summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/accessibility/braille/braille_console.c9
-rw-r--r--drivers/acpi/Kconfig18
-rw-r--r--drivers/acpi/ac.c1
-rw-r--r--drivers/acpi/acpi_pad.c1
-rw-r--r--drivers/acpi/acpi_platform.c24
-rw-r--r--drivers/acpi/acpi_processor.c24
-rw-r--r--drivers/acpi/acpica/acglobal.h7
-rw-r--r--drivers/acpi/acpica/aclocal.h4
-rw-r--r--drivers/acpi/acpica/acnamesp.h4
-rw-r--r--drivers/acpi/acpica/actables.h7
-rw-r--r--drivers/acpi/acpica/acutils.h4
-rw-r--r--drivers/acpi/acpica/evgpeinit.c11
-rw-r--r--drivers/acpi/acpica/exdump.c6
-rw-r--r--drivers/acpi/acpica/exoparg1.c48
-rw-r--r--drivers/acpi/acpica/hwesleep.c9
-rw-r--r--drivers/acpi/acpica/hwtimer.c13
-rw-r--r--drivers/acpi/acpica/nspredef.c16
-rw-r--r--drivers/acpi/acpica/nswalk.c26
-rw-r--r--drivers/acpi/acpica/nsxfeval.c16
-rw-r--r--drivers/acpi/acpica/nsxfname.c11
-rw-r--r--drivers/acpi/acpica/tbfadt.c4
-rw-r--r--drivers/acpi/acpica/tbxfroot.c12
-rw-r--r--drivers/acpi/acpica/uteval.c8
-rw-r--r--drivers/acpi/acpica/utglobal.c1
-rw-r--r--drivers/acpi/acpica/utosi.c77
-rw-r--r--drivers/acpi/acpica/utstring.c5
-rw-r--r--drivers/acpi/acpica/utxface.c29
-rw-r--r--drivers/acpi/battery.c23
-rw-r--r--drivers/acpi/bgrt.c27
-rw-r--r--drivers/acpi/blacklist.c30
-rw-r--r--drivers/acpi/bus.c142
-rw-r--r--drivers/acpi/button.c2
-rw-r--r--drivers/acpi/device_pm.c34
-rw-r--r--drivers/acpi/dock.c400
-rw-r--r--drivers/acpi/ec.c10
-rw-r--r--drivers/acpi/event.c106
-rw-r--r--drivers/acpi/fan.c4
-rw-r--r--drivers/acpi/glue.c220
-rw-r--r--drivers/acpi/internal.h3
-rw-r--r--drivers/acpi/numa.c2
-rw-r--r--drivers/acpi/osl.c86
-rw-r--r--drivers/acpi/pci_slot.c14
-rw-r--r--drivers/acpi/power.c6
-rw-r--r--drivers/acpi/proc.c8
-rw-r--r--drivers/acpi/processor_core.c2
-rw-r--r--drivers/acpi/processor_driver.c8
-rw-r--r--drivers/acpi/processor_perflib.c22
-rw-r--r--drivers/acpi/processor_thermal.c12
-rw-r--r--drivers/acpi/resource.c4
-rw-r--r--drivers/acpi/sbs.c15
-rw-r--r--drivers/acpi/scan.c272
-rw-r--r--drivers/acpi/sleep.c48
-rw-r--r--drivers/acpi/thermal.c49
-rw-r--r--drivers/acpi/utils.c70
-rw-r--r--drivers/acpi/video.c326
-rw-r--r--drivers/acpi/video_detect.c34
-rw-r--r--drivers/ata/Kconfig11
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c9
-rw-r--r--drivers/ata/ahci_imx.c236
-rw-r--r--drivers/ata/ata_piix.c2
-rw-r--r--drivers/ata/libata-acpi.c4
-rw-r--r--drivers/ata/libata-pmp.c12
-rw-r--r--drivers/ata/libata-scsi.c6
-rw-r--r--drivers/ata/pata_imx.c1
-rw-r--r--drivers/ata/sata_fsl.c5
-rw-r--r--drivers/ata/sata_highbank.c4
-rw-r--r--drivers/ata/sata_inic162x.c14
-rw-r--r--drivers/base/base.h10
-rw-r--r--drivers/base/bus.c60
-rw-r--r--drivers/base/class.c4
-rw-r--r--drivers/base/core.c150
-rw-r--r--drivers/base/cpu.c8
-rw-r--r--drivers/base/dma-contiguous.c4
-rw-r--r--drivers/base/driver.c31
-rw-r--r--drivers/base/firmware_class.c24
-rw-r--r--drivers/base/memory.c268
-rw-r--r--drivers/base/platform.c14
-rw-r--r--drivers/base/power/main.c77
-rw-r--r--drivers/base/power/opp.c1
-rw-r--r--drivers/base/power/sysfs.c2
-rw-r--r--drivers/base/regmap/internal.h14
-rw-r--r--drivers/base/regmap/regcache-rbtree.c183
-rw-r--r--drivers/base/regmap/regcache.c78
-rw-r--r--drivers/base/regmap/regmap-debugfs.c6
-rw-r--r--drivers/base/regmap/regmap-irq.c25
-rw-r--r--drivers/base/regmap/regmap.c26
-rw-r--r--drivers/base/topology.c20
-rw-r--r--drivers/block/Kconfig4
-rw-r--r--drivers/block/aoe/aoecmd.c17
-rw-r--r--drivers/block/drbd/drbd_actlog.c21
-rw-r--r--drivers/block/drbd/drbd_int.h15
-rw-r--r--drivers/block/drbd/drbd_main.c61
-rw-r--r--drivers/block/drbd/drbd_nl.c185
-rw-r--r--drivers/block/drbd/drbd_receiver.c12
-rw-r--r--drivers/block/drbd/drbd_state.c4
-rw-r--r--drivers/block/rbd.c14
-rw-r--r--drivers/block/rsxx/core.c359
-rw-r--r--drivers/block/rsxx/cregs.c14
-rw-r--r--drivers/block/rsxx/dev.c33
-rw-r--r--drivers/block/rsxx/dma.c185
-rw-r--r--drivers/block/rsxx/rsxx_priv.h10
-rw-r--r--drivers/block/xen-blkback/blkback.c872
-rw-r--r--drivers/block/xen-blkback/common.h147
-rw-r--r--drivers/block/xen-blkback/xenbus.c85
-rw-r--r--drivers/block/xen-blkfront.c532
-rw-r--r--drivers/bluetooth/ath3k.c46
-rw-r--r--drivers/bluetooth/btusb.c18
-rw-r--r--drivers/bus/arm-cci.c28
-rw-r--r--drivers/char/agp/parisc-agp.c6
-rw-r--r--drivers/char/bsr.c18
-rw-r--r--drivers/char/pcmcia/synclink_cs.c26
-rw-r--r--drivers/char/sonypi.c5
-rw-r--r--drivers/char/tile-srom.c28
-rw-r--r--drivers/char/virtio_console.c70
-rw-r--r--drivers/clk/samsung/clk-exynos4.c64
-rw-r--r--drivers/clk/zynq/clkc.c13
-rw-r--r--drivers/cpufreq/Kconfig.arm36
-rw-r--r--drivers/cpufreq/Makefile2
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c12
-rw-r--r--drivers/cpufreq/arm_big_little_dt.c40
-rw-r--r--drivers/cpufreq/at32ap-cpufreq.c1
-rw-r--r--drivers/cpufreq/blackfin-cpufreq.c1
-rw-r--r--drivers/cpufreq/cpufreq-cpu0.c34
-rw-r--r--drivers/cpufreq/cpufreq-nforce2.c1
-rw-r--r--drivers/cpufreq/cpufreq.c743
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c38
-rw-r--r--drivers/cpufreq/cpufreq_governor.c38
-rw-r--r--drivers/cpufreq/cpufreq_governor.h24
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c86
-rw-r--r--drivers/cpufreq/cpufreq_performance.c3
-rw-r--r--drivers/cpufreq/cpufreq_powersave.c3
-rw-r--r--drivers/cpufreq/cpufreq_stats.c31
-rw-r--r--drivers/cpufreq/cris-artpec3-cpufreq.c1
-rw-r--r--drivers/cpufreq/cris-etraxfs-cpufreq.c1
-rw-r--r--drivers/cpufreq/e_powersaver.c5
-rw-r--r--drivers/cpufreq/elanfreq.c1
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c3
-rw-r--r--drivers/cpufreq/exynos-cpufreq.h21
-rw-r--r--drivers/cpufreq/exynos5440-cpufreq.c3
-rw-r--r--drivers/cpufreq/freq_table.c4
-rw-r--r--drivers/cpufreq/gx-suspmod.c5
-rw-r--r--drivers/cpufreq/highbank-cpufreq.c18
-rw-r--r--drivers/cpufreq/ia64-acpi-cpufreq.c5
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c21
-rw-r--r--drivers/cpufreq/intel_pstate.c13
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c9
-rw-r--r--drivers/cpufreq/longhaul.c1
-rw-r--r--drivers/cpufreq/longrun.c1
-rw-r--r--drivers/cpufreq/loongson2_cpufreq.c12
-rw-r--r--drivers/cpufreq/maple-cpufreq.c24
-rw-r--r--drivers/cpufreq/mperf.c51
-rw-r--r--drivers/cpufreq/mperf.h9
-rw-r--r--drivers/cpufreq/p4-clockmod.c1
-rw-r--r--drivers/cpufreq/pasemi-cpufreq.c1
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c1
-rw-r--r--drivers/cpufreq/pmac32-cpufreq.c6
-rw-r--r--drivers/cpufreq/pmac64-cpufreq.c53
-rw-r--r--drivers/cpufreq/powernow-k6.c1
-rw-r--r--drivers/cpufreq/powernow-k7.c14
-rw-r--r--drivers/cpufreq/powernow-k8.c7
-rw-r--r--drivers/cpufreq/ppc-corenet-cpufreq.c1
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq.c1
-rw-r--r--drivers/cpufreq/pxa2xx-cpufreq.c4
-rw-r--r--drivers/cpufreq/pxa3xx-cpufreq.c6
-rw-r--r--drivers/cpufreq/s3c2416-cpufreq.c1
-rw-r--r--drivers/cpufreq/s3c24xx-cpufreq.c8
-rw-r--r--drivers/cpufreq/s3c64xx-cpufreq.c1
-rw-r--r--drivers/cpufreq/sc520_freq.c1
-rw-r--r--drivers/cpufreq/sh-cpufreq.c1
-rw-r--r--drivers/cpufreq/sparc-us2e-cpufreq.c6
-rw-r--r--drivers/cpufreq/sparc-us3-cpufreq.c6
-rw-r--r--drivers/cpufreq/spear-cpufreq.c4
-rw-r--r--drivers/cpufreq/speedstep-centrino.c1
-rw-r--r--drivers/cpufreq/speedstep-ich.c1
-rw-r--r--drivers/cpufreq/speedstep-smi.c1
-rw-r--r--drivers/cpufreq/tegra-cpufreq.c4
-rw-r--r--drivers/cpufreq/unicore2-cpufreq.c2
-rw-r--r--drivers/cpuidle/Kconfig20
-rw-r--r--drivers/cpuidle/Kconfig.arm29
-rw-r--r--drivers/cpuidle/Makefile9
-rw-r--r--drivers/cpuidle/coupled.c129
-rw-r--r--drivers/cpuidle/cpuidle-calxeda.c2
-rw-r--r--drivers/cpuidle/cpuidle-kirkwood.c5
-rw-r--r--drivers/cpuidle/cpuidle-ux500.c131
-rw-r--r--drivers/cpuidle/cpuidle.c94
-rw-r--r--drivers/cpuidle/governors/ladder.c12
-rw-r--r--drivers/cpuidle/governors/menu.c214
-rw-r--r--drivers/cpuidle/sysfs.c101
-rw-r--r--drivers/crypto/caam/caamhash.c2
-rw-r--r--drivers/devfreq/devfreq.c78
-rw-r--r--drivers/dma/Kconfig10
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/cppi41.c1059
-rw-r--r--drivers/dma/dmaengine.c26
-rw-r--r--drivers/dma/pch_dma.c1
-rw-r--r--drivers/dma/pl330.c93
-rw-r--r--drivers/dma/sh/shdma.c4
-rw-r--r--drivers/edac/edac_mc.c9
-rw-r--r--drivers/edac/edac_mc_sysfs.c28
-rw-r--r--drivers/edac/i5100_edac.c2
-rw-r--r--drivers/extcon/Kconfig4
-rw-r--r--drivers/extcon/Makefile2
-rw-r--r--drivers/extcon/extcon-adc-jack.c3
-rw-r--r--drivers/extcon/extcon-arizona.c25
-rw-r--r--drivers/extcon/extcon-class.c16
-rw-r--r--drivers/extcon/extcon-gpio.c2
-rw-r--r--drivers/extcon/extcon-palmas.c134
-rw-r--r--drivers/extcon/of_extcon.c64
-rw-r--r--drivers/firewire/core-cdev.c3
-rw-r--r--drivers/firewire/ohci.c10
-rw-r--r--drivers/firmware/dcdbas.c19
-rw-r--r--drivers/firmware/dmi_scan.c14
-rw-r--r--drivers/fmc/fmc-chardev.c9
-rw-r--r--drivers/fmc/fmc-write-eeprom.c4
-rw-r--r--drivers/gpio/gpio-msm-v1.c1
-rw-r--r--drivers/gpio/gpio-msm-v2.c2
-rw-r--r--drivers/gpu/drm/ast/ast_ttm.c1
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_ttm.c1
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c27
-rw-r--r--drivers/gpu/drm/drm_irq.c5
-rw-r--r--drivers/gpu/drm/exynos/exynos_ddc.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c19
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c13
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmiphy.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c1
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_sdvo.c3
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c22
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c13
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h4
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c18
-rw-r--r--drivers/gpu/drm/i915/i915_gem_dmabuf.c8
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h16
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c10
-rw-r--r--drivers/gpu/drm/i915/intel_display.c159
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c19
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c12
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c24
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c34
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c12
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c46
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_ttm.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/core/mm.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c8
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/falcon.c19
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nve0.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/xtensa.c8
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/falcon.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/mc.h7
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/vm.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/priv.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c12
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c22
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c14
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c34
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/base.c6
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/base.c27
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/crtc.c58
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c26
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c72
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c15
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c6
-rw-r--r--drivers/gpu/drm/nouveau/nv17_fence.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv40_pm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c46
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fence.c14
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c42
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c70
-rw-r--r--drivers/gpu/drm/qxl/qxl_draw.c263
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h76
-rw-r--r--drivers/gpu/drm/qxl/qxl_fb.c184
-rw-r--r--drivers/gpu/drm/qxl/qxl_fence.c10
-rw-r--r--drivers/gpu/drm/qxl/qxl_gem.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_image.c111
-rw-r--r--drivers/gpu/drm/qxl/qxl_ioctl.c319
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c70
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.h6
-rw-r--r--drivers/gpu/drm/qxl/qxl_release.c212
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c2
-rw-r--r--drivers/gpu/drm/radeon/atom.c5
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c43
-rw-r--r--drivers/gpu/drm/radeon/btc_dpm.c17
-rw-r--r--drivers/gpu/drm/radeon/cik.c18
-rw-r--r--drivers/gpu/drm/radeon/cypress_dpm.c17
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c6
-rw-r--r--drivers/gpu/drm/radeon/evergreen_hdmi.c26
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h3
-rw-r--r--drivers/gpu/drm/radeon/ni.c16
-rw-r--r--drivers/gpu/drm/radeon/ni_dpm.c24
-rw-r--r--drivers/gpu/drm/radeon/r600.c46
-rw-r--r--drivers/gpu/drm/radeon/r600_dpm.c4
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c37
-rw-r--r--drivers/gpu/drm/radeon/r600d.h3
-rw-r--r--drivers/gpu/drm/radeon/radeon.h6
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h4
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c159
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_gart.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_uvd.c101
-rw-r--r--drivers/gpu/drm/radeon/rv6xx_dpm.c63
-rw-r--r--drivers/gpu/drm/radeon/rv770.c19
-rw-r--r--drivers/gpu/drm/radeon/rv770_dpm.c33
-rw-r--r--drivers/gpu/drm/radeon/rv770_dpm.h1
-rw-r--r--drivers/gpu/drm/radeon/si.c33
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.c100
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c58
-rw-r--r--drivers/hid/hid-core.c10
-rw-r--r--drivers/hid/hid-hyperv.c1
-rw-r--r--drivers/hid/hid-logitech-dj.c45
-rw-r--r--drivers/hid/hid-logitech-dj.h1
-rw-r--r--drivers/hid/hid-roccat-arvo.c53
-rw-r--r--drivers/hid/hid-roccat-isku.c98
-rw-r--r--drivers/hid/hid-roccat-kone.c106
-rw-r--r--drivers/hid/hid-roccat-koneplus.c175
-rw-r--r--drivers/hid/hid-roccat-konepure.c67
-rw-r--r--drivers/hid/hid-roccat-kovaplus.c166
-rw-r--r--drivers/hid/hid-roccat-pyra.c158
-rw-r--r--drivers/hid/hid-roccat-savu.c58
-rw-r--r--drivers/hid/hid-sony.c3
-rw-r--r--drivers/hid/hidraw.c2
-rw-r--r--drivers/hv/channel_mgmt.c89
-rw-r--r--drivers/hv/connection.c5
-rw-r--r--drivers/hv/hv_balloon.c26
-rw-r--r--drivers/hv/hv_kvp.c26
-rw-r--r--drivers/hv/hv_snapshot.c18
-rw-r--r--drivers/hv/hv_util.c22
-rw-r--r--drivers/hv/vmbus_drv.c9
-rw-r--r--drivers/hwmon/Kconfig18
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/acpi_power_meter.c4
-rw-r--r--drivers/hwmon/ads1015.c27
-rw-r--r--drivers/hwmon/ads7828.c2
-rw-r--r--drivers/hwmon/adt7462.c8
-rw-r--r--drivers/hwmon/adt7470.c6
-rw-r--r--drivers/hwmon/coretemp.c14
-rw-r--r--drivers/hwmon/ds620.c2
-rw-r--r--drivers/hwmon/f71805f.c2
-rw-r--r--drivers/hwmon/f71882fg.c2
-rw-r--r--drivers/hwmon/f75375s.c3
-rw-r--r--drivers/hwmon/g762.c2
-rw-r--r--drivers/hwmon/gpio-fan.c2
-rw-r--r--drivers/hwmon/htu21.c199
-rw-r--r--drivers/hwmon/i5k_amb.c4
-rw-r--r--drivers/hwmon/ibmaem.c4
-rw-r--r--drivers/hwmon/ibmpex.c4
-rw-r--r--drivers/hwmon/ina2xx.c4
-rw-r--r--drivers/hwmon/it87.c6
-rw-r--r--drivers/hwmon/k10temp.c3
-rw-r--r--drivers/hwmon/lm87.c4
-rw-r--r--drivers/hwmon/max197.c2
-rw-r--r--drivers/hwmon/max6639.c2
-rw-r--r--drivers/hwmon/max6697.c4
-rw-r--r--drivers/hwmon/mcp3021.c7
-rw-r--r--drivers/hwmon/nct6775.c2531
-rw-r--r--drivers/hwmon/ntc_thermistor.c2
-rw-r--r--drivers/hwmon/pc87427.c4
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c2
-rw-r--r--drivers/hwmon/s3c-hwmon.c6
-rw-r--r--drivers/hwmon/sht15.c6
-rw-r--r--drivers/hwmon/smsc47m1.c4
-rw-r--r--drivers/hwmon/w83627ehf.c22
-rw-r--r--drivers/hwmon/w83627hf.c6
-rw-r--r--drivers/i2c/busses/i2c-kempld.c4
-rw-r--r--drivers/i2c/busses/i2c-mxs.c2
-rw-r--r--drivers/ide/ide-acpi.c5
-rw-r--r--drivers/iio/Kconfig8
-rw-r--r--drivers/iio/Makefile3
-rw-r--r--drivers/iio/accel/Kconfig32
-rw-r--r--drivers/iio/accel/Makefile5
-rw-r--r--drivers/iio/accel/bma180.c676
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c43
-rw-r--r--drivers/iio/accel/kxsd9.c17
-rw-r--r--drivers/iio/accel/st_accel.h11
-rw-r--r--drivers/iio/accel/st_accel_core.c28
-rw-r--r--drivers/iio/accel/st_accel_i2c.c17
-rw-r--r--drivers/iio/accel/st_accel_spi.c17
-rw-r--r--drivers/iio/adc/Kconfig61
-rw-r--r--drivers/iio/adc/Makefile3
-rw-r--r--drivers/iio/adc/ad7266.c16
-rw-r--r--drivers/iio/adc/ad7298.c24
-rw-r--r--drivers/iio/adc/ad7476.c26
-rw-r--r--drivers/iio/adc/ad7791.c19
-rw-r--r--drivers/iio/adc/ad7793.c23
-rw-r--r--drivers/iio/adc/ad7887.c23
-rw-r--r--drivers/iio/adc/ad7923.c20
-rw-r--r--drivers/iio/adc/at91_adc.c113
-rw-r--r--drivers/iio/adc/exynos_adc.c23
-rw-r--r--drivers/iio/adc/lp8788_adc.c7
-rw-r--r--drivers/iio/adc/max1363.c15
-rw-r--r--drivers/iio/adc/mcp320x.c18
-rw-r--r--drivers/iio/adc/nau7802.c581
-rw-r--r--drivers/iio/adc/ti-adc081c.c18
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c43
-rw-r--r--drivers/iio/adc/twl6030-gpadc.c1013
-rw-r--r--drivers/iio/adc/viperboard_adc.c9
-rw-r--r--drivers/iio/amplifiers/Kconfig2
-rw-r--r--drivers/iio/amplifiers/Makefile1
-rw-r--r--drivers/iio/amplifiers/ad8366.c13
-rw-r--r--drivers/iio/common/Makefile1
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c41
-rw-r--r--drivers/iio/dac/Kconfig44
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/ad5064.c21
-rw-r--r--drivers/iio/dac/ad5360.c15
-rw-r--r--drivers/iio/dac/ad5380.c18
-rw-r--r--drivers/iio/dac/ad5421.c19
-rw-r--r--drivers/iio/dac/ad5446.c19
-rw-r--r--drivers/iio/dac/ad5449.c15
-rw-r--r--drivers/iio/dac/ad5504.c31
-rw-r--r--drivers/iio/dac/ad5624r_spi.c22
-rw-r--r--drivers/iio/dac/ad5686.c17
-rw-r--r--drivers/iio/dac/ad5755.c14
-rw-r--r--drivers/iio/dac/ad5764.c20
-rw-r--r--drivers/iio/dac/ad5791.c35
-rw-r--r--drivers/iio/dac/ad7303.c31
-rw-r--r--drivers/iio/dac/max517.c17
-rw-r--r--drivers/iio/dac/mcp4725.c177
-rw-r--r--drivers/iio/frequency/Kconfig1
-rw-r--r--drivers/iio/frequency/Makefile1
-rw-r--r--drivers/iio/frequency/ad9523.c17
-rw-r--r--drivers/iio/frequency/adf4350.c31
-rw-r--r--drivers/iio/gyro/Kconfig18
-rw-r--r--drivers/iio/gyro/Makefile2
-rw-r--r--drivers/iio/gyro/adis16080.c21
-rw-r--r--drivers/iio/gyro/adis16130.c23
-rw-r--r--drivers/iio/gyro/adis16136.c10
-rw-r--r--drivers/iio/gyro/adis16260.c (renamed from drivers/staging/iio/gyro/adis16260_core.c)319
-rw-r--r--drivers/iio/gyro/adxrs450.c15
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c41
-rw-r--r--drivers/iio/gyro/itg3200_core.c15
-rw-r--r--drivers/iio/gyro/st_gyro.h11
-rw-r--r--drivers/iio/gyro/st_gyro_core.c14
-rw-r--r--drivers/iio/gyro/st_gyro_i2c.c18
-rw-r--r--drivers/iio/gyro/st_gyro_spi.c18
-rw-r--r--drivers/iio/iio_core_trigger.h7
-rw-r--r--drivers/iio/imu/Kconfig2
-rw-r--r--drivers/iio/imu/Makefile1
-rw-r--r--drivers/iio/imu/adis16400_core.c10
-rw-r--r--drivers/iio/imu/adis16480.c10
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c29
-rw-r--r--drivers/iio/industrialio-core.c51
-rw-r--r--drivers/iio/industrialio-trigger.c106
-rw-r--r--drivers/iio/light/Kconfig34
-rw-r--r--drivers/iio/light/Makefile4
-rw-r--r--drivers/iio/light/adjd_s311.c46
-rw-r--r--drivers/iio/light/apds9300.c512
-rw-r--r--drivers/iio/light/hid-sensor-als.c41
-rw-r--r--drivers/iio/light/lm3533-als.c7
-rw-r--r--drivers/iio/light/tsl2563.c25
-rw-r--r--drivers/iio/light/vcnl4000.c16
-rw-r--r--drivers/iio/magnetometer/Kconfig6
-rw-r--r--drivers/iio/magnetometer/Makefile1
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c43
-rw-r--r--drivers/iio/magnetometer/st_magn.h3
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c6
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c17
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c17
-rw-r--r--drivers/iio/pressure/Kconfig14
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/st_pressure.h11
-rw-r--r--drivers/iio/pressure/st_pressure_core.c21
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c17
-rw-r--r--drivers/iio/pressure/st_pressure_spi.c17
-rw-r--r--drivers/iio/temperature/Kconfig16
-rw-r--r--drivers/iio/temperature/Makefile5
-rw-r--r--drivers/iio/temperature/tmp006.c291
-rw-r--r--drivers/iio/trigger/Kconfig4
-rw-r--r--drivers/iio/trigger/Makefile1
-rw-r--r--drivers/infiniband/core/cma.c29
-rw-r--r--drivers/infiniband/core/mad.c8
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c1
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c2
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c10
-rw-r--r--drivers/infiniband/hw/mlx5/main.c11
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c4
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c3
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_ah.c1
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c5
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_sdma.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c76
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_netlink.c9
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c3
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c11
-rw-r--r--drivers/input/gameport/gameport.c12
-rw-r--r--drivers/input/joystick/xpad.c1
-rw-r--r--drivers/input/mouse/elantech.c44
-rw-r--r--drivers/input/mouse/elantech.h1
-rw-r--r--drivers/input/serio/Kconfig3
-rw-r--r--drivers/input/serio/serio.c21
-rw-r--r--drivers/input/tablet/wacom_wac.c10
-rw-r--r--drivers/irqchip/irq-sirfsoc.c18
-rw-r--r--drivers/isdn/mISDN/core.c64
-rw-r--r--drivers/isdn/mISDN/dsp_core.c4
-rw-r--r--drivers/leds/led-class.c38
-rw-r--r--drivers/macintosh/windfarm_rm31.c18
-rw-r--r--drivers/md/bcache/alloc.c46
-rw-r--r--drivers/md/bcache/bcache.h61
-rw-r--r--drivers/md/bcache/bset.c56
-rw-r--r--drivers/md/bcache/bset.h4
-rw-r--r--drivers/md/bcache/btree.c451
-rw-r--r--drivers/md/bcache/btree.h35
-rw-r--r--drivers/md/bcache/closure.c6
-rw-r--r--drivers/md/bcache/debug.c178
-rw-r--r--drivers/md/bcache/debug.h11
-rw-r--r--drivers/md/bcache/io.c68
-rw-r--r--drivers/md/bcache/journal.c25
-rw-r--r--drivers/md/bcache/movinggc.c24
-rw-r--r--drivers/md/bcache/request.c197
-rw-r--r--drivers/md/bcache/request.h2
-rw-r--r--drivers/md/bcache/super.c171
-rw-r--r--drivers/md/bcache/sysfs.c68
-rw-r--r--drivers/md/bcache/trace.c47
-rw-r--r--drivers/md/bcache/util.c17
-rw-r--r--drivers/md/bcache/util.h6
-rw-r--r--drivers/md/bcache/writeback.c133
-rw-r--r--drivers/md/bcache/writeback.h64
-rw-r--r--drivers/md/dm-cache-policy-mq.c16
-rw-r--r--drivers/md/dm-mpath.c16
-rw-r--r--drivers/md/raid10.c8
-rw-r--r--drivers/md/raid5.c15
-rw-r--r--drivers/md/raid5.h1
-rw-r--r--drivers/media/i2c/ml86v7667.c4
-rw-r--r--drivers/media/platform/coda.c2
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c79
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c46
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c2
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-core.c11
-rw-r--r--drivers/media/usb/usbtv/Kconfig2
-rw-r--r--drivers/media/usb/usbtv/usbtv.c51
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c30
-rw-r--r--drivers/mfd/db8500-prcmu.c4
-rw-r--r--drivers/misc/atmel-ssc.c19
-rw-r--r--drivers/misc/c2port/core.c83
-rw-r--r--drivers/misc/enclosure.c29
-rw-r--r--drivers/misc/hpilo.c4
-rw-r--r--drivers/misc/ics932s401.c4
-rw-r--r--drivers/misc/lkdtm.c63
-rw-r--r--drivers/misc/mei/amthif.c14
-rw-r--r--drivers/misc/mei/bus.c14
-rw-r--r--drivers/misc/mei/client.c15
-rw-r--r--drivers/misc/mei/client.h9
-rw-r--r--drivers/misc/mei/hbm.c2
-rw-r--r--drivers/misc/mei/hw-me.c23
-rw-r--r--drivers/misc/mei/init.c14
-rw-r--r--drivers/misc/mei/main.c22
-rw-r--r--drivers/misc/sram.c3
-rw-r--r--drivers/misc/ti-st/st_core.c2
-rw-r--r--drivers/misc/vmw_balloon.c2
-rw-r--r--drivers/misc/vmw_vmci/vmci_driver.c2
-rw-r--r--drivers/misc/vmw_vmci/vmci_driver.h7
-rw-r--r--drivers/misc/vmw_vmci/vmci_guest.c22
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.c315
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.h18
-rw-r--r--drivers/mmc/core/core.c2
-rw-r--r--drivers/mmc/host/dw_mmc.c2
-rw-r--r--drivers/mmc/host/pxamci.c4
-rw-r--r--drivers/mmc/host/sdhci.c4
-rw-r--r--drivers/net/arcnet/arcnet.c2
-rw-r--r--drivers/net/bonding/bond_main.c8
-rw-r--r--drivers/net/can/usb/esd_usb2.c10
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb.c2
-rw-r--r--drivers/net/can/usb/usb_8dev.c1
-rw-r--r--drivers/net/ethernet/allwinner/Kconfig26
-rw-r--r--drivers/net/ethernet/arc/emac_main.c2
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c.h3
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c40
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h15
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c11
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c53
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h5
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c99
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c121
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c95
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h3
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c19
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge.c107
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c3
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h6
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c6
-rw-r--r--drivers/net/ethernet/freescale/fec.h1
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c41
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h12
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c6
-rw-r--r--drivers/net/ethernet/jme.c2
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c31
-rw-r--r--drivers/net/ethernet/marvell/skge.c68
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cmd.c19
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eq.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/health.c29
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c69
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c52
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/uar.c1
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/Kconfig2
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic.h1
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h15
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c135
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c98
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c16
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c85
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c62
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c27
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c101
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c29
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c46
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c6
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c49
-rw-r--r--drivers/net/ethernet/realtek/r8169.c8
-rw-r--r--drivers/net/ethernet/sfc/filter.c6
-rw-r--r--drivers/net/ethernet/sis/sis900.c12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/ring_mode.c13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c111
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c20
-rw-r--r--drivers/net/ethernet/sun/niu.c2
-rw-r--r--drivers/net/ethernet/ti/cpsw.c2
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c3
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.c3
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.h1
-rw-r--r--drivers/net/ethernet/via/via-velocity.c4
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c1
-rw-r--r--drivers/net/hyperv/netvsc_drv.c2
-rw-r--r--drivers/net/irda/irtty-sir.c8
-rw-r--r--drivers/net/irda/via-ircc.c6
-rw-r--r--drivers/net/macvlan.c27
-rw-r--r--drivers/net/macvtap.c30
-rw-r--r--drivers/net/phy/mdio-sun4i.c14
-rw-r--r--drivers/net/phy/realtek.c4
-rw-r--r--drivers/net/tun.c6
-rw-r--r--drivers/net/usb/ax88179_178a.c17
-rw-r--r--drivers/net/usb/cdc_mbim.c4
-rw-r--r--drivers/net/usb/hso.c15
-rw-r--r--drivers/net/usb/r8152.c126
-rw-r--r--drivers/net/usb/r815x.c62
-rw-r--r--drivers/net/usb/smsc75xx.c12
-rw-r--r--drivers/net/usb/usbnet.c45
-rw-r--r--drivers/net/veth.c1
-rw-r--r--drivers/net/vxlan.c59
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c44
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c8
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c5
-rw-r--r--drivers/net/wireless/cw1200/sta.c7
-rw-r--r--drivers/net/wireless/cw1200/txrx.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c4
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c18
-rw-r--r--drivers/net/wireless/iwlegacy/common.c1
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c5
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/main.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c15
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c6
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c65
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c19
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c34
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c33
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c1
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c15
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c4
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c3
-rw-r--r--drivers/net/wireless/mwifiex/init.c10
-rw-r--r--drivers/net/wireless/mwifiex/join.c6
-rw-r--r--drivers/net/wireless/mwifiex/main.c13
-rw-r--r--drivers/net/wireless/mwifiex/main.h1
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c95
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h3
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c4
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c3
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c18
-rw-r--r--drivers/net/wireless/rtlwifi/Kconfig72
-rw-r--r--drivers/net/wireless/rtlwifi/Makefile10
-rw-r--r--drivers/net/wireless/rtlwifi/base.c19
-rw-r--r--drivers/net/wireless/rtlwifi/base.h2
-rw-r--r--drivers/net/wireless/rtlwifi/core.c1
-rw-r--r--drivers/net/wireless/rtlwifi/debug.c1
-rw-r--r--drivers/net/wireless/rtlwifi/efuse.c1
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c22
-rw-r--r--drivers/net/wireless/rtlwifi/ps.c16
-rw-r--r--drivers/net/wireless/rtlwifi/ps.h1
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c9
-rw-r--r--drivers/net/wireless/zd1201.c4
-rw-r--r--drivers/of/base.c121
-rw-r--r--drivers/of/fdt.c2
-rw-r--r--drivers/of/irq.c6
-rw-r--r--drivers/parisc/iosapic.c38
-rw-r--r--drivers/parport/Kconfig2
-rw-r--r--drivers/parport/parport_amiga.c1
-rw-r--r--drivers/pci/host/pci-mvebu.c27
-rw-r--r--drivers/pci/hotplug/Kconfig7
-rw-r--r--drivers/pci/hotplug/acpiphp.h55
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c18
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c1035
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c3
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c9
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c1
-rw-r--r--drivers/pci/hotplug/s390_pci_hpc.c63
-rw-r--r--drivers/pci/pci-acpi.c33
-rw-r--r--drivers/pci/pcie/Kconfig5
-rw-r--r--drivers/pci/setup-bus.c69
-rw-r--r--drivers/pinctrl/core.c1
-rw-r--r--drivers/pinctrl/pinctrl-single.c2
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.c66
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.h2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh73a0.c1
-rw-r--r--drivers/pinctrl/sirf/pinctrl-atlas6.c24
-rw-r--r--drivers/platform/olpc/olpc-ec.c2
-rw-r--r--drivers/platform/x86/asus-laptop.c1
-rw-r--r--drivers/platform/x86/eeepc-laptop.c1
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c4
-rw-r--r--drivers/platform/x86/hp-wmi.c16
-rw-r--r--drivers/platform/x86/panasonic-laptop.c3
-rw-r--r--drivers/platform/x86/sony-laptop.c12
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c40
-rw-r--r--drivers/platform/x86/wmi.c10
-rw-r--r--drivers/pnp/driver.c21
-rw-r--r--drivers/pnp/pnpacpi/core.c6
-rw-r--r--drivers/pps/pps.c2
-rw-r--r--drivers/pps/sysfs.c55
-rw-r--r--drivers/ptp/ptp_clock.c2
-rw-r--r--drivers/ptp/ptp_private.h2
-rw-r--r--drivers/ptp/ptp_sysfs.c51
-rw-r--r--drivers/rapidio/rio.c4
-rw-r--r--drivers/regulator/88pm800.c383
-rw-r--r--drivers/regulator/88pm8607.c2
-rw-r--r--drivers/regulator/Kconfig284
-rw-r--r--drivers/regulator/Makefile8
-rw-r--r--drivers/regulator/aat2870-regulator.c2
-rw-r--r--drivers/regulator/ab3100.c2
-rw-r--r--drivers/regulator/ad5398.c2
-rw-r--r--drivers/regulator/as3711-regulator.c163
-rw-r--r--drivers/regulator/core.c472
-rw-r--r--drivers/regulator/da903x.c47
-rw-r--r--drivers/regulator/da9052-regulator.c2
-rw-r--r--drivers/regulator/da9055-regulator.c2
-rw-r--r--drivers/regulator/da9063-regulator.c934
-rw-r--r--drivers/regulator/da9210-regulator.c196
-rw-r--r--drivers/regulator/da9210-regulator.h288
-rw-r--r--drivers/regulator/fan53555.c2
-rw-r--r--drivers/regulator/fixed.c2
-rw-r--r--drivers/regulator/gpio-regulator.c2
-rw-r--r--drivers/regulator/helpers.c447
-rw-r--r--drivers/regulator/isl6271a-regulator.c2
-rw-r--r--drivers/regulator/lp3971.c2
-rw-r--r--drivers/regulator/lp3972.c2
-rw-r--r--drivers/regulator/lp872x.c11
-rw-r--r--drivers/regulator/lp8755.c3
-rw-r--r--drivers/regulator/max1586.c2
-rw-r--r--drivers/regulator/max8649.c2
-rw-r--r--drivers/regulator/max8660.c108
-rw-r--r--drivers/regulator/max8925-regulator.c2
-rw-r--r--drivers/regulator/max8952.c2
-rw-r--r--drivers/regulator/max8973-regulator.c2
-rw-r--r--drivers/regulator/of_regulator.c12
-rw-r--r--drivers/regulator/palmas-regulator.c32
-rw-r--r--drivers/regulator/pcap-regulator.c2
-rw-r--r--drivers/regulator/pcf50633-regulator.c2
-rw-r--r--drivers/regulator/pfuze100-regulator.c445
-rw-r--r--drivers/regulator/s2mps11.c245
-rw-r--r--drivers/regulator/ti-abb-regulator.c10
-rw-r--r--drivers/regulator/tps51632-regulator.c2
-rw-r--r--drivers/regulator/tps62360-regulator.c2
-rw-r--r--drivers/regulator/tps65023-regulator.c2
-rw-r--r--drivers/regulator/tps65217-regulator.c182
-rw-r--r--drivers/regulator/tps6524x-regulator.c2
-rw-r--r--drivers/regulator/tps65912-regulator.c39
-rw-r--r--drivers/regulator/twl-regulator.c2
-rw-r--r--drivers/regulator/userspace-consumer.c2
-rw-r--r--drivers/regulator/virtual.c2
-rw-r--r--drivers/regulator/wm831x-dcdc.c8
-rw-r--r--drivers/regulator/wm831x-isink.c2
-rw-r--r--drivers/regulator/wm831x-ldo.c110
-rw-r--r--drivers/regulator/wm8350-regulator.c57
-rw-r--r--drivers/regulator/wm8400-regulator.c52
-rw-r--r--drivers/regulator/wm8994-regulator.c2
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c35
-rw-r--r--drivers/rtc/rtc-sysfs.c48
-rw-r--r--drivers/rtc/rtc-twl.c3
-rw-r--r--drivers/s390/block/dasd.c6
-rw-r--r--drivers/s390/block/dasd_devmap.c8
-rw-r--r--drivers/s390/block/dasd_eckd.c54
-rw-r--r--drivers/s390/block/dasd_erp.c14
-rw-r--r--drivers/s390/char/sclp_config.c2
-rw-r--r--drivers/s390/cio/airq.c174
-rw-r--r--drivers/s390/cio/ccwgroup.c2
-rw-r--r--drivers/s390/cio/cio.c46
-rw-r--r--drivers/s390/cio/cio.h3
-rw-r--r--drivers/s390/cio/cmf.c2
-rw-r--r--drivers/s390/cio/css.c4
-rw-r--r--drivers/s390/cio/css.h2
-rw-r--r--drivers/s390/cio/device.c2
-rw-r--r--drivers/s390/net/qeth_l3_sys.c2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c4
-rw-r--r--drivers/s390/scsi/zfcp_erp.c29
-rw-r--r--drivers/s390/scsi/zfcp_ext.h2
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c12
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c12
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c26
-rw-r--r--drivers/scsi/Kconfig2
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/bfa/bfad.c6
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_constants.h2
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_hsi.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c6
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_sysfs.c2
-rw-r--r--drivers/scsi/eata_pio.c2
-rw-r--r--drivers/scsi/esas2r/Kconfig5
-rw-r--r--drivers/scsi/esas2r/Makefile5
-rw-r--r--drivers/scsi/esas2r/atioctl.h1254
-rw-r--r--drivers/scsi/esas2r/atvda.h1319
-rw-r--r--drivers/scsi/esas2r/esas2r.h1441
-rw-r--r--drivers/scsi/esas2r/esas2r_disc.c1189
-rw-r--r--drivers/scsi/esas2r/esas2r_flash.c1512
-rw-r--r--drivers/scsi/esas2r/esas2r_init.c1773
-rw-r--r--drivers/scsi/esas2r/esas2r_int.c941
-rw-r--r--drivers/scsi/esas2r/esas2r_io.c880
-rw-r--r--drivers/scsi/esas2r/esas2r_ioctl.c2110
-rw-r--r--drivers/scsi/esas2r/esas2r_log.c254
-rw-r--r--drivers/scsi/esas2r/esas2r_log.h118
-rw-r--r--drivers/scsi/esas2r/esas2r_main.c2032
-rw-r--r--drivers/scsi/esas2r/esas2r_targdb.c306
-rw-r--r--drivers/scsi/esas2r/esas2r_vda.c521
-rw-r--r--drivers/scsi/fnic/fnic.h2
-rw-r--r--drivers/scsi/fnic/fnic_main.c22
-rw-r--r--drivers/scsi/hpsa.c8
-rw-r--r--drivers/scsi/hpsa.h2
-rw-r--r--drivers/scsi/ipr.c14
-rw-r--r--drivers/scsi/ipr.h7
-rw-r--r--drivers/scsi/isci/port_config.c2
-rw-r--r--drivers/scsi/isci/request.c2
-rw-r--r--drivers/scsi/isci/task.c9
-rw-r--r--drivers/scsi/libiscsi.c109
-rw-r--r--drivers/scsi/lpfc/lpfc.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c57
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h13
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c42
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c7
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c12
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c12
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c147
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h7
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c5
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c20
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h7
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h10
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h2
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h2
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_raid.h2
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_sas.h2
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h2
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_type.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c40
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h10
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c14
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_debug.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c82
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c7
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c41
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c1
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_transport.c5
-rw-r--r--drivers/scsi/mvsas/mv_sas.c11
-rw-r--r--drivers/scsi/mvsas/mv_sas.h1
-rw-r--r--drivers/scsi/osd/osd_uld.c13
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c4
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c5
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c4
-rw-r--r--drivers/scsi/qla2xxx/Makefile2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c81
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c43
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c58
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h39
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h74
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c97
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c86
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c28
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c91
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c297
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c164
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.h41
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c117
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.h10
-rw-r--r--drivers/scsi/qla2xxx/qla_nx2.c3716
-rw-r--r--drivers/scsi/qla2xxx/qla_nx2.h551
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c213
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c162
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c69
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h4
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c14
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.c12
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.h36
-rw-r--r--drivers/scsi/qla4xxx/ql4_attr.c90
-rw-r--r--drivers/scsi/qla4xxx/ql4_bsg.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.c13
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h29
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h10
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h10
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c6
-rw-r--r--drivers/scsi/qla4xxx/ql4_inline.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c65
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c171
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.c297
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c357
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h4
-rw-r--r--drivers/scsi/scsi.c3
-rw-r--r--drivers/scsi/scsi_debug.c14
-rw-r--r--drivers/scsi/scsi_error.c128
-rw-r--r--drivers/scsi/scsi_lib.c48
-rw-r--r--drivers/scsi/scsi_sysfs.c10
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c123
-rw-r--r--drivers/scsi/sd.c171
-rw-r--r--drivers/scsi/sg.c176
-rw-r--r--drivers/scsi/st.c27
-rw-r--r--drivers/scsi/storvsc_drv.c1
-rw-r--r--drivers/scsi/ufs/ufs.h155
-rw-r--r--drivers/scsi/ufs/ufshcd-pci.c99
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c57
-rw-r--r--drivers/scsi/ufs/ufshcd.c1170
-rw-r--r--drivers/scsi/ufs/ufshcd.h59
-rw-r--r--drivers/scsi/ufs/ufshci.h2
-rw-r--r--drivers/scsi/virtio_scsi.c2
-rw-r--r--drivers/spi/Kconfig63
-rw-r--r--drivers/spi/Makefile4
-rw-r--r--drivers/spi/spi-altera.c48
-rw-r--r--drivers/spi/spi-ath79.c2
-rw-r--r--drivers/spi/spi-atmel.c36
-rw-r--r--drivers/spi/spi-au1550.c2
-rw-r--r--drivers/spi/spi-bcm2835.c10
-rw-r--r--drivers/spi/spi-bcm63xx.c37
-rw-r--r--drivers/spi/spi-bfin-sport.c2
-rw-r--r--drivers/spi/spi-bfin-v3.c965
-rw-r--r--drivers/spi/spi-bfin5xx.c2
-rw-r--r--drivers/spi/spi-bitbang.c260
-rw-r--r--drivers/spi/spi-clps711x.c6
-rw-r--r--drivers/spi/spi-coldfire-qspi.c27
-rw-r--r--drivers/spi/spi-davinci.c6
-rw-r--r--drivers/spi/spi-efm32.c516
-rw-r--r--drivers/spi/spi-ep93xx.c355
-rw-r--r--drivers/spi/spi-fsl-dspi.c557
-rw-r--r--drivers/spi/spi-fsl-espi.c4
-rw-r--r--drivers/spi/spi-fsl-lib.c2
-rw-r--r--drivers/spi/spi-fsl-spi.c13
-rw-r--r--drivers/spi/spi-gpio.c4
-rw-r--r--drivers/spi/spi-imx.c76
-rw-r--r--drivers/spi/spi-mpc512x-psc.c50
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c2
-rw-r--r--drivers/spi/spi-mxs.c28
-rw-r--r--drivers/spi/spi-nuc900.c17
-rw-r--r--drivers/spi/spi-oc-tiny.c24
-rw-r--r--drivers/spi/spi-octeon.c49
-rw-r--r--drivers/spi/spi-omap-100k.c278
-rw-r--r--drivers/spi/spi-omap2-mcspi.c22
-rw-r--r--drivers/spi/spi-orion.c23
-rw-r--r--drivers/spi/spi-pl022.c28
-rw-r--r--drivers/spi/spi-pxa2xx.c21
-rw-r--r--drivers/spi/spi-rspi.c21
-rw-r--r--drivers/spi/spi-s3c24xx.c6
-rw-r--r--drivers/spi/spi-s3c64xx.c120
-rw-r--r--drivers/spi/spi-sh-hspi.c20
-rw-r--r--drivers/spi/spi-sh-msiof.c20
-rw-r--r--drivers/spi/spi-sh-sci.c2
-rw-r--r--drivers/spi/spi-sirf.c233
-rw-r--r--drivers/spi/spi-tegra114.c18
-rw-r--r--drivers/spi/spi-tegra20-sflash.c8
-rw-r--r--drivers/spi/spi-tegra20-slink.c8
-rw-r--r--drivers/spi/spi-ti-qspi.c574
-rw-r--r--drivers/spi/spi-ti-ssp.c2
-rw-r--r--drivers/spi/spi-tle62x0.c5
-rw-r--r--drivers/spi/spi-topcliff-pch.c2
-rw-r--r--drivers/spi/spi-txx9.c2
-rw-r--r--drivers/spi/spi-xilinx.c188
-rw-r--r--drivers/spi/spi.c137
-rw-r--r--drivers/staging/Kconfig14
-rw-r--r--drivers/staging/Makefile7
-rw-r--r--drivers/staging/android/binder.c32
-rw-r--r--drivers/staging/android/binder.h48
-rw-r--r--drivers/staging/android/logger.c4
-rw-r--r--drivers/staging/android/sw_sync.c2
-rw-r--r--drivers/staging/android/sync.c2
-rw-r--r--drivers/staging/android/timed_output.c27
-rw-r--r--drivers/staging/asus_oled/Kconfig6
-rw-r--r--drivers/staging/asus_oled/Makefile1
-rw-r--r--drivers/staging/asus_oled/README156
-rw-r--r--drivers/staging/asus_oled/TODO10
-rw-r--r--drivers/staging/asus_oled/asus_oled.c847
-rw-r--r--drivers/staging/asus_oled/linux.txt33
-rw-r--r--drivers/staging/asus_oled/linux_f.txt18
-rw-r--r--drivers/staging/asus_oled/linux_fr.txt33
-rw-r--r--drivers/staging/asus_oled/tux.txt33
-rw-r--r--drivers/staging/asus_oled/tux_r.txt33
-rw-r--r--drivers/staging/asus_oled/tux_r2.txt33
-rw-r--r--drivers/staging/asus_oled/zig.txt33
-rw-r--r--drivers/staging/bcm/Bcmchar.c4
-rw-r--r--drivers/staging/bcm/DDRInit.c54
-rw-r--r--drivers/staging/bcm/Ioctl.h2
-rw-r--r--drivers/staging/bcm/LeakyBucket.c262
-rw-r--r--drivers/staging/bcm/Misc.c2
-rw-r--r--drivers/staging/bcm/Qos.c538
-rw-r--r--drivers/staging/bcm/Version.h29
-rw-r--r--drivers/staging/bcm/headers.h3
-rw-r--r--drivers/staging/bcm/nvm.c2
-rw-r--r--drivers/staging/comedi/Kconfig44
-rw-r--r--drivers/staging/comedi/TODO2
-rw-r--r--drivers/staging/comedi/comedi_buf.c2
-rw-r--r--drivers/staging/comedi/comedi_fops.c72
-rw-r--r--drivers/staging/comedi/comedi_internal.h1
-rw-r--r--drivers/staging/comedi/comedidev.h23
-rw-r--r--drivers/staging/comedi/comedilib.h7
-rw-r--r--drivers/staging/comedi/drivers.c96
-rw-r--r--drivers/staging/comedi/drivers/8255.c45
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c4
-rw-r--r--drivers/staging/comedi/drivers/Makefile3
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c1068
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c2050
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c1037
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c5461
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c866
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c3582
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c845
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c2065
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c1044
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c3
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.h169
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_eeprom.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c1314
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_035.c1
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1500.c1
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1516.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1564.c1
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_16xx.c43
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1710.c99
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2032.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2200.c1
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3200.c1
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c40
-rw-r--r--drivers/staging/comedi/drivers/addi_watchdog.c1
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c4
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7x3x.c1
-rw-r--r--drivers/staging/comedi/drivers/adl_pci8164.c1
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c4
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c7
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c6
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c4
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c47
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1724.c11
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c4
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c5
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c6
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_common.c44
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_pci.c5
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c7
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c1
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c7
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c4
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci263.c1
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c36
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c4
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c29
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c4
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c5
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c4
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c367
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.c1
-rw-r--r--drivers/staging/comedi/drivers/comedi_parport.c5
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c4
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c1
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c4
-rw-r--r--drivers/staging/comedi/drivers/das08.c2
-rw-r--r--drivers/staging/comedi/drivers/das08_cs.c6
-rw-r--r--drivers/staging/comedi/drivers/das08_isa.c4
-rw-r--r--drivers/staging/comedi/drivers/das08_pci.c4
-rw-r--r--drivers/staging/comedi/drivers/das16.c1999
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c5
-rw-r--r--drivers/staging/comedi/drivers/das1800.c5
-rw-r--r--drivers/staging/comedi/drivers/das6402.c6
-rw-r--r--drivers/staging/comedi/drivers/das800.c5
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c41
-rw-r--r--drivers/staging/comedi/drivers/dt2801.c36
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c6
-rw-r--r--drivers/staging/comedi/drivers/dt2814.c5
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c5
-rw-r--r--drivers/staging/comedi/drivers/dt2817.c33
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c36
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c45
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c27
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c5
-rw-r--r--drivers/staging/comedi/drivers/fl512.c5
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c37
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c4
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c1015
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c4
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c1
-rw-r--r--drivers/staging/comedi/drivers/me4000.c127
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c54
-rw-r--r--drivers/staging/comedi/drivers/mite.c1
-rw-r--r--drivers/staging/comedi/drivers/mite.h1
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c5
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c6
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c4
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c5
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c4
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c30
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c7
-rw-r--r--drivers/staging/comedi/drivers/ni_at_ao.c61
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c28
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c28
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c1
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c283
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_cs.c5
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_isadma.c226
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_isadma.h57
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_pci.c5
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_regs.h75
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c61
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c1
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c33
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c1
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c3
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c1
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c5
-rw-r--r--drivers/staging/comedi/drivers/pcl724.c13
-rw-r--r--drivers/staging/comedi/drivers/pcl726.c6
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c3
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c6
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c5
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c5
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c52
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c1
-rw-r--r--drivers/staging/comedi/drivers/pcmda12.c4
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c86
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c39
-rw-r--r--drivers/staging/comedi/drivers/poc.c6
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c4
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c24
-rw-r--r--drivers/staging/comedi/drivers/rti800.c7
-rw-r--r--drivers/staging/comedi/drivers/rti802.c6
-rw-r--r--drivers/staging/comedi/drivers/s526.c50
-rw-r--r--drivers/staging/comedi/drivers/s626.c27
-rw-r--r--drivers/staging/comedi/drivers/s626.h2
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c5
-rw-r--r--drivers/staging/comedi/drivers/skel.c49
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c79
-rw-r--r--drivers/staging/comedi/drivers/unioxx5.c4
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c2485
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c3
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c317
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c3
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c60
-rw-r--r--drivers/staging/comedi/proc.c2
-rw-r--r--drivers/staging/comedi/range.c43
-rw-r--r--drivers/staging/crystalhd/crystalhd_cmds.c3
-rw-r--r--drivers/staging/crystalhd/crystalhd_hw.c7
-rw-r--r--drivers/staging/crystalhd/crystalhd_lnx.c3
-rw-r--r--drivers/staging/crystalhd/crystalhd_misc.h4
-rw-r--r--drivers/staging/cxt1e1/Makefile1
-rw-r--r--drivers/staging/cxt1e1/comet.c23
-rw-r--r--drivers/staging/cxt1e1/functions.c9
-rw-r--r--drivers/staging/cxt1e1/hwprobe.c8
-rw-r--r--drivers/staging/cxt1e1/linux.c52
-rw-r--r--drivers/staging/cxt1e1/musycc.c15
-rw-r--r--drivers/staging/cxt1e1/pmc93x6_eeprom.c15
-rw-r--r--drivers/staging/cxt1e1/pmcc4_drv.c11
-rw-r--r--drivers/staging/cxt1e1/sbeid.c7
-rw-r--r--drivers/staging/dgap/Kconfig6
-rw-r--r--drivers/staging/dgap/Makefile9
-rw-r--r--drivers/staging/dgap/dgap_conf.h290
-rw-r--r--drivers/staging/dgap/dgap_downld.h69
-rw-r--r--drivers/staging/dgap/dgap_driver.c1048
-rw-r--r--drivers/staging/dgap/dgap_driver.h618
-rw-r--r--drivers/staging/dgap/dgap_fep5.c1953
-rw-r--r--drivers/staging/dgap/dgap_fep5.h253
-rw-r--r--drivers/staging/dgap/dgap_kcompat.h93
-rw-r--r--drivers/staging/dgap/dgap_parse.c1371
-rw-r--r--drivers/staging/dgap/dgap_parse.h35
-rw-r--r--drivers/staging/dgap/dgap_pci.h92
-rw-r--r--drivers/staging/dgap/dgap_sysfs.c793
-rw-r--r--drivers/staging/dgap/dgap_sysfs.h48
-rw-r--r--drivers/staging/dgap/dgap_trace.c185
-rw-r--r--drivers/staging/dgap/dgap_trace.h36
-rw-r--r--drivers/staging/dgap/dgap_tty.c3597
-rw-r--r--drivers/staging/dgap/dgap_tty.h39
-rw-r--r--drivers/staging/dgap/dgap_types.h36
-rw-r--r--drivers/staging/dgap/digi.h376
-rw-r--r--drivers/staging/dgap/downld.c798
-rw-r--r--drivers/staging/dgnc/Kconfig6
-rw-r--r--drivers/staging/dgnc/Makefile7
-rw-r--r--drivers/staging/dgnc/TODO17
-rw-r--r--drivers/staging/dgnc/dgnc_cls.c1409
-rw-r--r--drivers/staging/dgnc/dgnc_cls.h90
-rw-r--r--drivers/staging/dgnc/dgnc_driver.c958
-rw-r--r--drivers/staging/dgnc/dgnc_driver.h563
-rw-r--r--drivers/staging/dgnc/dgnc_kcompat.h93
-rw-r--r--drivers/staging/dgnc/dgnc_mgmt.c305
-rw-r--r--drivers/staging/dgnc/dgnc_mgmt.h31
-rw-r--r--drivers/staging/dgnc/dgnc_neo.c1974
-rw-r--r--drivers/staging/dgnc/dgnc_neo.h157
-rw-r--r--drivers/staging/dgnc/dgnc_pci.h75
-rw-r--r--drivers/staging/dgnc/dgnc_sysfs.c756
-rw-r--r--drivers/staging/dgnc/dgnc_sysfs.h49
-rw-r--r--drivers/staging/dgnc/dgnc_trace.c184
-rw-r--r--drivers/staging/dgnc/dgnc_trace.h44
-rw-r--r--drivers/staging/dgnc/dgnc_tty.c3544
-rw-r--r--drivers/staging/dgnc/dgnc_tty.h42
-rw-r--r--drivers/staging/dgnc/dgnc_types.h36
-rw-r--r--drivers/staging/dgnc/digi.h416
-rw-r--r--drivers/staging/dgnc/dpacompat.h115
-rw-r--r--drivers/staging/dgrp/dgrp_driver.c14
-rw-r--r--drivers/staging/dgrp/dgrp_tty.c2
-rw-r--r--drivers/staging/dwc2/Kconfig1
-rw-r--r--drivers/staging/dwc2/core.c449
-rw-r--r--drivers/staging/dwc2/core.h221
-rw-r--r--drivers/staging/dwc2/core_intr.c4
-rw-r--r--drivers/staging/dwc2/hcd.c281
-rw-r--r--drivers/staging/dwc2/hcd.h45
-rw-r--r--drivers/staging/dwc2/hcd_ddma.c31
-rw-r--r--drivers/staging/dwc2/hcd_intr.c129
-rw-r--r--drivers/staging/dwc2/hcd_queue.c22
-rw-r--r--drivers/staging/dwc2/hw.h156
-rw-r--r--drivers/staging/dwc2/pci.c4
-rw-r--r--drivers/staging/et131x/README1
-rw-r--r--drivers/staging/frontier/alphatrack.c2
-rw-r--r--drivers/staging/frontier/tranzport.c10
-rw-r--r--drivers/staging/gdm724x/Kconfig15
-rw-r--r--drivers/staging/gdm724x/Makefile7
-rw-r--r--drivers/staging/gdm724x/TODO16
-rw-r--r--drivers/staging/gdm724x/gdm_endian.c67
-rw-r--r--drivers/staging/gdm724x/gdm_endian.h49
-rw-r--r--drivers/staging/gdm724x/gdm_lte.c877
-rw-r--r--drivers/staging/gdm724x/gdm_lte.h81
-rw-r--r--drivers/staging/gdm724x/gdm_mux.c690
-rw-r--r--drivers/staging/gdm724x/gdm_mux.h95
-rw-r--r--drivers/staging/gdm724x/gdm_tty.c343
-rw-r--r--drivers/staging/gdm724x/gdm_tty.h71
-rw-r--r--drivers/staging/gdm724x/gdm_usb.c1049
-rw-r--r--drivers/staging/gdm724x/gdm_usb.h109
-rw-r--r--drivers/staging/gdm724x/hci.h55
-rw-r--r--drivers/staging/gdm724x/hci_packet.h93
-rw-r--r--drivers/staging/gdm724x/netlink_k.c149
-rw-r--r--drivers/staging/gdm724x/netlink_k.h25
-rw-r--r--drivers/staging/gdm72xx/gdm_qos.c2
-rw-r--r--drivers/staging/iio/Documentation/device.txt4
-rw-r--r--drivers/staging/iio/accel/adis16201_core.c17
-rw-r--r--drivers/staging/iio/accel/adis16203_core.c16
-rw-r--r--drivers/staging/iio/accel/adis16204_core.c16
-rw-r--r--drivers/staging/iio/accel/adis16209_core.c16
-rw-r--r--drivers/staging/iio/accel/adis16220_core.c14
-rw-r--r--drivers/staging/iio/accel/adis16240_core.c16
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c15
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c15
-rw-r--r--drivers/staging/iio/adc/mxs-lradc.c45
-rw-r--r--drivers/staging/iio/adc/spear_adc.c30
-rw-r--r--drivers/staging/iio/addac/adt7316.c27
-rw-r--r--drivers/staging/iio/cdc/ad7150.c36
-rw-r--r--drivers/staging/iio/cdc/ad7152.c16
-rw-r--r--drivers/staging/iio/cdc/ad7746.c18
-rw-r--r--drivers/staging/iio/gyro/Kconfig12
-rw-r--r--drivers/staging/iio/gyro/Makefile3
-rw-r--r--drivers/staging/iio/gyro/adis16060_core.c17
-rw-r--r--drivers/staging/iio/gyro/adis16260.h98
-rw-r--r--drivers/staging/iio/gyro/adis16260_platform_data.h19
-rw-r--r--drivers/staging/iio/light/isl29018.c16
-rw-r--r--drivers/staging/iio/light/isl29028.c13
-rw-r--r--drivers/staging/iio/magnetometer/hmc5843.c71
-rw-r--r--drivers/staging/iio/meter/ade7753.c18
-rw-r--r--drivers/staging/iio/meter/ade7754.c19
-rw-r--r--drivers/staging/iio/meter/ade7758_core.c18
-rw-r--r--drivers/staging/iio/meter/ade7758_ring.c2
-rw-r--r--drivers/staging/iio/meter/ade7759.c18
-rw-r--r--drivers/staging/iio/meter/ade7854.c19
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c18
-rw-r--r--drivers/staging/imx-drm/Kconfig5
-rw-r--r--drivers/staging/imx-drm/TODO1
-rw-r--r--drivers/staging/imx-drm/imx-drm-core.c21
-rw-r--r--drivers/staging/imx-drm/imx-ldb.c3
-rw-r--r--drivers/staging/imx-drm/imx-tve.c25
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-common.c17
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dc.c5
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-di.c4
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dp.c13
-rw-r--r--drivers/staging/imx-drm/ipuv3-crtc.c1
-rw-r--r--drivers/staging/imx-drm/parallel-display.c1
-rw-r--r--drivers/staging/keucr/scsiglue.c13
-rw-r--r--drivers/staging/line6/driver.c9
-rw-r--r--drivers/staging/line6/driver.h3
-rw-r--r--drivers/staging/line6/pcm.c27
-rw-r--r--drivers/staging/line6/pod.c21
-rw-r--r--drivers/staging/lustre/Makefile2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/bitmap.h4
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/curproc.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs.h46
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h46
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h8
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h68
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h24
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_private.h7
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/kp30.h59
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h3
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/linux-cpu.h9
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h4
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/linux-prim.h158
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/linux-tcpip.h15
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h1
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/portals_compat25.h15
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/lucache.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/params_tree.h4
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-types.h6
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lnetst.h2
-rw-r--r--drivers/staging/lustre/include/linux/lnet/ptllnd.h4
-rw-r--r--drivers/staging/lustre/lnet/Makefile2
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c10
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h1
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c14
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c2
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c60
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c112
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c11
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.h3
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c62
-rw-r--r--drivers/staging/lustre/lnet/lnet/Makefile2
-rw-r--r--drivers/staging/lustre/lnet/lnet/acceptor.c62
-rw-r--r--drivers/staging/lustre/lnet/lnet/api-errno.c39
-rw-r--r--drivers/staging/lustre/lnet/lnet/api-ni.c7
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-eq.c14
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-msg.c13
-rw-r--r--drivers/staging/lustre/lnet/lnet/module.c9
-rw-r--r--drivers/staging/lustre/lnet/lnet/router_proc.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/brw_test.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/console.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/module.c4
-rw-r--r--drivers/staging/lustre/lnet/selftest/rpc.c6
-rw-r--r--drivers/staging/lustre/lnet/selftest/timer.c2
-rw-r--r--drivers/staging/lustre/lustre/Kconfig13
-rw-r--r--drivers/staging/lustre/lustre/Makefile4
-rw-r--r--drivers/staging/lustre/lustre/fid/Makefile2
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_handler.c661
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_internal.h36
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_lib.c14
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_request.c164
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_store.c259
-rw-r--r--drivers/staging/lustre/lustre/fid/lproc_fid.c28
-rw-r--r--drivers/staging/lustre/lustre/fld/Makefile2
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_cache.c45
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_handler.c447
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_index.c426
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_internal.h31
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_request.c90
-rw-r--r--drivers/staging/lustre/lustre/fld/lproc_fld.c217
-rw-r--r--drivers/staging/lustre/lustre/include/cl_object.h18
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lprocfs_status.h1
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_compat25.h103
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_fsfilt.h12
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_handles.h1
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_lib.h10
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_lite.h2
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_net.h1
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h2
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_quota.h1
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_user.h19
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lvfs.h8
-rw-r--r--drivers/staging/lustre/lustre/include/linux/obd.h5
-rw-r--r--drivers/staging/lustre/lustre/include/lprocfs_status.h73
-rw-r--r--drivers/staging/lustre/lustre/include/lu_object.h25
-rw-r--r--drivers/staging/lustre/lustre/include/lu_ref.h14
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_errno.h215
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_idl.h82
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_user.h12
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_cfg.h30
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_disk.h56
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm.h204
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm_flags.h460
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fid.h125
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fld.h45
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_idmap.h4
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_import.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_lib.h5
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_log.h32
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_mdc.h12
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_mdt.h84
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_net.h47
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_quota.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_sec.h2
-rw-r--r--drivers/staging/lustre/lustre/include/md_object.h7
-rw-r--r--drivers/staging/lustre/lustre/include/obd.h185
-rw-r--r--drivers/staging/lustre/lustre/include/obd_class.h392
-rw-r--r--drivers/staging/lustre/lustre/include/obd_lov.h10
-rw-r--r--drivers/staging/lustre/lustre/include/obd_support.h1
-rw-r--r--drivers/staging/lustre/lustre/lclient/glimpse.c19
-rw-r--r--drivers/staging/lustre/lustre/lclient/lcommon_cl.c43
-rw-r--r--drivers/staging/lustre/lustre/lclient/lcommon_misc.c8
-rw-r--r--drivers/staging/lustre/lustre/ldlm/interval_tree.c50
-rw-r--r--drivers/staging/lustre/lustre/ldlm/l_lock.c8
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_extent.c10
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_flock.c66
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_internal.h49
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lib.c79
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lock.c394
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c120
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_pool.c137
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_request.c181
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_resource.c95
-rw-r--r--drivers/staging/lustre/lustre/libcfs/Makefile2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/debug.c19
-rw-r--r--drivers/staging/lustre/lustre/libcfs/hash.c24
-rw-r--r--drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c15
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c3
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_lock.c3
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_mem.c3
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_string.c49
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c46
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c21
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c69
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-module.c31
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c21
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c5
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c16
-rw-r--r--drivers/staging/lustre/lustre/libcfs/module.c28
-rw-r--r--drivers/staging/lustre/lustre/libcfs/nidstrings.c14
-rw-r--r--drivers/staging/lustre/lustre/libcfs/tracefile.c13
-rw-r--r--drivers/staging/lustre/lustre/libcfs/upcall_cache.c22
-rw-r--r--drivers/staging/lustre/lustre/libcfs/watchdog.c516
-rw-r--r--drivers/staging/lustre/lustre/libcfs/workitem.c3
-rw-r--r--drivers/staging/lustre/lustre/llite/Makefile2
-rw-r--r--drivers/staging/lustre/lustre/llite/dcache.c80
-rw-r--r--drivers/staging/lustre/lustre/llite/dir.c251
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c454
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_capa.c26
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_close.c23
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h32
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c172
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_mmap.c67
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_nfs.c76
-rw-r--r--drivers/staging/lustre/lustre/llite/lloop.c15
-rw-r--r--drivers/staging/lustre/lustre/llite/lproc_llite.c38
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c97
-rw-r--r--drivers/staging/lustre/lustre/llite/remote_perm.c27
-rw-r--r--drivers/staging/lustre/lustre/llite/rw.c44
-rw-r--r--drivers/staging/lustre/lustre/llite/rw26.c35
-rw-r--r--drivers/staging/lustre/lustre/llite/statahead.c88
-rw-r--r--drivers/staging/lustre/lustre/llite/super25.c3
-rw-r--r--drivers/staging/lustre/lustre/llite/symlink.c16
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_dev.c5
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_io.c59
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_lock.c3
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_object.c8
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_page.c10
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr.c48
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_fld.c7
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_intent.c38
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_obd.c634
-rw-r--r--drivers/staging/lustre/lustre/lmv/lproc_lmv.c1
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_cl_internal.h13
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_dev.c33
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_ea.c23
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_io.c111
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_lock.c69
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_log.c16
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_merge.c10
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_obd.c300
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_object.c112
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_offset.c5
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pack.c82
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_page.c13
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pool.c40
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_request.c157
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_dev.c12
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_lock.c31
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_object.c14
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_page.c3
-rw-r--r--drivers/staging/lustre/lustre/lov/lproc_lov.c1
-rw-r--r--drivers/staging/lustre/lustre/lvfs/fsfilt.c5
-rw-r--r--drivers/staging/lustre/lustre/lvfs/fsfilt_ext3.c1
-rw-r--r--drivers/staging/lustre/lustre/lvfs/lvfs_linux.c15
-rw-r--r--drivers/staging/lustre/lustre/mdc/lproc_mdc.c10
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_lib.c29
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_locks.c151
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_reint.c46
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_request.c324
-rw-r--r--drivers/staging/lustre/lustre/mgc/libmgc.c19
-rw-r--r--drivers/staging/lustre/lustre/mgc/lproc_mgc.c1
-rw-r--r--drivers/staging/lustre/lustre/mgc/mgc_request.c169
-rw-r--r--drivers/staging/lustre/lustre/obdclass/Makefile2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/acl.c29
-rw-r--r--drivers/staging/lustre/lustre/obdclass/capa.c61
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_io.c152
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_lock.c144
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_object.c21
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_page.c108
-rw-r--r--drivers/staging/lustre/lustre/obdclass/class_obd.c35
-rw-r--r--drivers/staging/lustre/lustre/obdclass/dt_object.c28
-rw-r--r--drivers/staging/lustre/lustre/obdclass/genops.c79
-rw-r--r--drivers/staging/lustre/lustre/obdclass/idmap.c21
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-module.c48
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c10
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog.c124
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_cat.c92
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_ioctl.c79
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_lvfs.c99
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_obd.c37
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_osd.c121
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_swab.c28
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_test.c89
-rw-r--r--drivers/staging/lustre/lustre/obdclass/local_storage.c46
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_jobstats.c562
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_status.c61
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lu_object.c46
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lu_ucred.c8
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lustre_handles.c8
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lustre_peer.c3
-rw-r--r--drivers/staging/lustre/lustre/obdclass/md_attrs.c17
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_config.c148
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_mount.c134
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obdo.c16
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo.c47
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo_client.c248
-rw-r--r--drivers/staging/lustre/lustre/osc/lproc_osc.c3
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cache.c141
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cl_internal.h4
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_dev.c11
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_io.c28
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_lock.c146
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_object.c3
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_page.c28
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_quota.c31
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_request.c326
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/Makefile1
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/client.c161
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/connection.c24
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/errno.c380
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/events.c12
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_api.h2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c54
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c27
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c47
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c124
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c53
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_rawobj.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c12
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/lproc_gss.c6
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c219
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/import.c61
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/llog_client.c11
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/llog_net.c3
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/llog_server.c46
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c15
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/niobuf.c38
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/nrs.c105
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pack_generic.c34
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pinger.c82
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c11
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c37
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/recover.c23
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec.c123
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_config.c47
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_gc.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_plain.c90
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/service.c170
-rw-r--r--drivers/staging/nvec/nvec.c5
-rw-r--r--drivers/staging/octeon-usb/Kconfig2
-rw-r--r--drivers/staging/octeon-usb/cvmx-usb.c5339
-rw-r--r--drivers/staging/octeon-usb/cvmx-usb.h1157
-rw-r--r--drivers/staging/octeon-usb/cvmx-usbcx-defs.h23
-rw-r--r--drivers/staging/octeon-usb/cvmx-usbnx-defs.h2
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c33
-rw-r--r--drivers/staging/olpc_dcon/Kconfig11
-rw-r--r--drivers/staging/olpc_dcon/TODO11
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.c24
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.h27
-rw-r--r--drivers/staging/ozwpan/Makefile (renamed from drivers/staging/ozwpan/Kbuild)6
-rw-r--r--drivers/staging/ozwpan/ozcdev.c134
-rw-r--r--drivers/staging/ozwpan/ozconfig.h26
-rw-r--r--drivers/staging/ozwpan/ozdbg.h54
-rw-r--r--drivers/staging/ozwpan/ozeltbuf.c80
-rw-r--r--drivers/staging/ozwpan/ozhcd.c722
-rw-r--r--drivers/staging/ozwpan/ozhcd.h4
-rw-r--r--drivers/staging/ozwpan/ozmain.c18
-rw-r--r--drivers/staging/ozwpan/ozpd.c276
-rw-r--r--drivers/staging/ozwpan/ozpd.h21
-rw-r--r--drivers/staging/ozwpan/ozproto.c526
-rw-r--r--drivers/staging/ozwpan/ozproto.h32
-rw-r--r--drivers/staging/ozwpan/oztrace.c36
-rw-r--r--drivers/staging/ozwpan/oztrace.h35
-rw-r--r--drivers/staging/ozwpan/ozurbparanoia.c23
-rw-r--r--drivers/staging/ozwpan/ozurbparanoia.h4
-rw-r--r--drivers/staging/ozwpan/ozusbsvc.c76
-rw-r--r--drivers/staging/ozwpan/ozusbsvc1.c64
-rw-r--r--drivers/staging/quickstart/quickstart.c21
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211.h2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c2
-rw-r--r--drivers/staging/rtl8187se/r8180.h2
-rw-r--r--drivers/staging/rtl8187se/r8180_93cx6.h2
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c10
-rw-r--r--drivers/staging/rtl8187se/r8180_hw.h2
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225.h2
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225z2.c2
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.c2
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.h2
-rw-r--r--drivers/staging/rtl8188eu/Kconfig29
-rw-r--r--drivers/staging/rtl8188eu/Makefile70
-rw-r--r--drivers/staging/rtl8188eu/TODO15
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ap.c1988
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_br_ext.c1199
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_cmd.c2364
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_debug.c948
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c875
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c1640
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_io.c329
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ioctl_set.c1169
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_iol.c209
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_led.c1692
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c2442
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c8481
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mp.c997
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c1508
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_p2p.c2064
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_pwrctrl.c662
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c2299
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_rf.c89
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_security.c1779
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_sreset.c79
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_sta_mgt.c655
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c1689
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_xmit.c2447
-rw-r--r--drivers/staging/rtl8188eu/hal/Hal8188EFWImg_CE.c1761
-rw-r--r--drivers/staging/rtl8188eu/hal/Hal8188EPwrSeq.c86
-rw-r--r--drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c760
-rw-r--r--drivers/staging/rtl8188eu/hal/HalHWImg8188E_BB.c721
-rw-r--r--drivers/staging/rtl8188eu/hal/HalHWImg8188E_MAC.c231
-rw-r--r--drivers/staging/rtl8188eu/hal/HalHWImg8188E_RF.c269
-rw-r--r--drivers/staging/rtl8188eu/hal/HalPhyRf.c49
-rw-r--r--drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c1928
-rw-r--r--drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c132
-rw-r--r--drivers/staging/rtl8188eu/hal/hal_com.c381
-rw-r--r--drivers/staging/rtl8188eu/hal/hal_intf.c464
-rw-r--r--drivers/staging/rtl8188eu/hal/odm.c2171
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_HWConfig.c596
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_RTL8188E.c399
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c130
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_debug.c32
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_interface.c203
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c779
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_dm.c268
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c2378
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_mp.c860
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c1144
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c572
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c202
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_sreset.c80
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c91
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_led.c111
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c138
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c706
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c2346
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_ops_linux.c726
-rw-r--r--drivers/staging/rtl8188eu/include/Hal8188EFWImg_CE.h28
-rw-r--r--drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h276
-rw-r--r--drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h1094
-rw-r--r--drivers/staging/rtl8188eu/include/Hal8188EPwrSeq.h176
-rw-r--r--drivers/staging/rtl8188eu/include/Hal8188ERateAdaptive.h75
-rw-r--r--drivers/staging/rtl8188eu/include/Hal8188EReg.h46
-rw-r--r--drivers/staging/rtl8188eu/include/HalHWImg8188E_BB.h44
-rw-r--r--drivers/staging/rtl8188eu/include/HalHWImg8188E_FW.h34
-rw-r--r--drivers/staging/rtl8188eu/include/HalHWImg8188E_MAC.h30
-rw-r--r--drivers/staging/rtl8188eu/include/HalHWImg8188E_RF.h30
-rw-r--r--drivers/staging/rtl8188eu/include/HalPhyRf.h30
-rw-r--r--drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h63
-rw-r--r--drivers/staging/rtl8188eu/include/HalPwrSeqCmd.h128
-rw-r--r--drivers/staging/rtl8188eu/include/HalVerDef.h167
-rw-r--r--drivers/staging/rtl8188eu/include/basic_types.h184
-rw-r--r--drivers/staging/rtl8188eu/include/cmd_osdep.h32
-rw-r--r--drivers/staging/rtl8188eu/include/drv_types.h334
-rw-r--r--drivers/staging/rtl8188eu/include/drv_types_linux.h24
-rw-r--r--drivers/staging/rtl8188eu/include/ethernet.h42
-rw-r--r--drivers/staging/rtl8188eu/include/h2clbk.h35
-rw-r--r--drivers/staging/rtl8188eu/include/hal_com.h173
-rw-r--r--drivers/staging/rtl8188eu/include/hal_intf.h426
-rw-r--r--drivers/staging/rtl8188eu/include/ieee80211.h1274
-rw-r--r--drivers/staging/rtl8188eu/include/ieee80211_ext.h290
-rw-r--r--drivers/staging/rtl8188eu/include/if_ether.h111
-rw-r--r--drivers/staging/rtl8188eu/include/ioctl_cfg80211.h107
-rw-r--r--drivers/staging/rtl8188eu/include/ip.h126
-rw-r--r--drivers/staging/rtl8188eu/include/mlme_osdep.h35
-rw-r--r--drivers/staging/rtl8188eu/include/mp_custom_oid.h352
-rw-r--r--drivers/staging/rtl8188eu/include/nic_spec.h44
-rw-r--r--drivers/staging/rtl8188eu/include/odm.h1198
-rw-r--r--drivers/staging/rtl8188eu/include/odm_HWConfig.h132
-rw-r--r--drivers/staging/rtl8188eu/include/odm_RTL8188E.h56
-rw-r--r--drivers/staging/rtl8188eu/include/odm_RegConfig8188E.h43
-rw-r--r--drivers/staging/rtl8188eu/include/odm_RegDefine11AC.h54
-rw-r--r--drivers/staging/rtl8188eu/include/odm_RegDefine11N.h171
-rw-r--r--drivers/staging/rtl8188eu/include/odm_debug.h145
-rw-r--r--drivers/staging/rtl8188eu/include/odm_interface.h164
-rw-r--r--drivers/staging/rtl8188eu/include/odm_precomp.h104
-rw-r--r--drivers/staging/rtl8188eu/include/odm_reg.h119
-rw-r--r--drivers/staging/rtl8188eu/include/odm_types.h62
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_intf.h83
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_service.h547
-rw-r--r--drivers/staging/rtl8188eu/include/recv_osdep.h56
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_cmd.h122
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_dm.h62
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_hal.h487
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_led.h35
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_recv.h69
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_rf.h36
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_spec.h1439
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_sreset.h31
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_xmit.h178
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_android.h64
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ap.h65
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_br_ext.h66
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_cmd.h991
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_debug.h290
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_eeprom.h130
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_efuse.h150
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_event.h115
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ht.h44
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_io.h387
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ioctl.h124
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ioctl_rtl.h79
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ioctl_set.h50
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_iol.h84
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_led.h197
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme.h655
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme_ext.h877
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mp.h495
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mp_ioctl.h340
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h1084
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_p2p.h135
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_pwrctrl.h283
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_qos.h30
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_recv.h485
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_rf.h146
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_security.h383
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_sreset.h50
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_version.h1
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_xmit.h384
-rw-r--r--drivers/staging/rtl8188eu/include/sta_info.h384
-rw-r--r--drivers/staging/rtl8188eu/include/usb_hal.h26
-rw-r--r--drivers/staging/rtl8188eu/include/usb_ops.h115
-rw-r--r--drivers/staging/rtl8188eu/include/usb_ops_linux.h55
-rw-r--r--drivers/staging/rtl8188eu/include/usb_osintf.h45
-rw-r--r--drivers/staging/rtl8188eu/include/usb_vendor_req.h52
-rw-r--r--drivers/staging/rtl8188eu/include/wifi.h1127
-rw-r--r--drivers/staging/rtl8188eu/include/wlan_bssdef.h347
-rw-r--r--drivers/staging/rtl8188eu/include/xmit_osdep.h67
-rw-r--r--drivers/staging/rtl8188eu/os_dep/ioctl_linux.c8222
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c246
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c1251
-rw-r--r--drivers/staging/rtl8188eu/os_dep/osdep_service.c815
-rw-r--r--drivers/staging/rtl8188eu/os_dep/recv_linux.c261
-rw-r--r--drivers/staging/rtl8188eu/os_dep/rtw_android.c293
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_intf.c892
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c288
-rw-r--r--drivers/staging/rtl8188eu/os_dep/xmit_linux.c290
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.h2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c7
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.h8
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pci.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pci.h2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ps.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ps.h2
-rw-r--r--drivers/staging/rtl8192e/rtllib.h2
-rw-r--r--drivers/staging/rtl8192e/rtllib_debug.h2
-rw-r--r--drivers/staging/rtl8192e/rtllib_module.c3
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c6
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac_wx.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_tx.c2
-rw-r--r--drivers/staging/rtl8192u/authors2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_module.c3
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c2
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.c2
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.h2
-rw-r--r--drivers/staging/rtl8192u/r8180_pm.c2
-rw-r--r--drivers/staging/rtl8192u/r8180_pm.h2
-rw-r--r--drivers/staging/rtl8192u/r8190_rtl8256.h2
-rw-r--r--drivers/staging/rtl8192u/r8192U.h2
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c2
-rw-r--r--drivers/staging/rtl8192u/r8192U_hw.h2
-rw-r--r--drivers/staging/rtl8192u/r8192U_wx.c2
-rw-r--r--drivers/staging/rtl8192u/r8192U_wx.h2
-rw-r--r--drivers/staging/rtl8192u/r819xU_cmdpkt.c609
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c8
-rw-r--r--drivers/staging/silicom/bpctl_mod.c582
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/cmm.h2
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/proc.h2
-rw-r--r--drivers/staging/tidspbridge/pmgr/dbll.c7
-rw-r--r--drivers/staging/usbip/stub_dev.c6
-rw-r--r--drivers/staging/usbip/usbip_common.c11
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.c2
-rw-r--r--drivers/staging/usbip/userspace/src/usbip.c15
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_attach.c6
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_list.c6
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_network.c30
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_network.h5
-rw-r--r--drivers/staging/usbip/userspace/src/usbipd.c141
-rw-r--r--drivers/staging/usbip/vhci_sysfs.c4
-rw-r--r--drivers/staging/vt6655/device_main.c4
-rw-r--r--drivers/staging/vt6656/baseband.c80
-rw-r--r--drivers/staging/vt6656/baseband.h10
-rw-r--r--drivers/staging/vt6656/card.c78
-rw-r--r--drivers/staging/vt6656/desc.h224
-rw-r--r--drivers/staging/vt6656/device.h51
-rw-r--r--drivers/staging/vt6656/device_cfg.h14
-rw-r--r--drivers/staging/vt6656/dpc.c16
-rw-r--r--drivers/staging/vt6656/dpc.h4
-rw-r--r--drivers/staging/vt6656/main_usb.c23
-rw-r--r--drivers/staging/vt6656/rxtx.c1536
-rw-r--r--drivers/staging/vt6656/rxtx.h761
-rw-r--r--drivers/staging/vt6656/usbpipe.c12
-rw-r--r--drivers/staging/vt6656/usbpipe.h5
-rw-r--r--drivers/staging/vt6656/wmgr.c2
-rw-r--r--drivers/staging/winbond/mds.c56
-rw-r--r--drivers/staging/winbond/mds_f.h13
-rw-r--r--drivers/staging/winbond/phy_calibration.h1
-rw-r--r--drivers/staging/winbond/wb35reg.c36
-rw-r--r--drivers/staging/wlags49_h2/Makefile2
-rw-r--r--drivers/staging/wlags49_h2/wl_cs.c4
-rw-r--r--drivers/staging/wlags49_h2/wl_internal.h1
-rw-r--r--drivers/staging/wlags49_h2/wl_sysfs.c138
-rw-r--r--drivers/staging/wlags49_h2/wl_sysfs.h7
-rw-r--r--drivers/staging/wlags49_h25/Makefile3
-rw-r--r--drivers/staging/wlags49_h25/wl_sysfs.c2
-rw-r--r--drivers/staging/wlags49_h25/wl_sysfs.h2
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c12
-rw-r--r--drivers/staging/xgifb/vb_init.c36
-rw-r--r--drivers/staging/xgifb/vb_setmode.c333
-rw-r--r--drivers/staging/xgifb/vb_setmode.h11
-rw-r--r--drivers/staging/xillybus/Kconfig32
-rw-r--r--drivers/staging/xillybus/Makefile7
-rw-r--r--drivers/staging/xillybus/README403
-rw-r--r--drivers/staging/xillybus/TODO5
-rw-r--r--drivers/staging/xillybus/xillybus.h182
-rw-r--r--drivers/staging/xillybus/xillybus_core.c2345
-rw-r--r--drivers/staging/xillybus/xillybus_of.c212
-rw-r--r--drivers/staging/xillybus/xillybus_pcie.c262
-rw-r--r--drivers/staging/zcache/Kconfig59
-rw-r--r--drivers/staging/zcache/Makefile8
-rw-r--r--drivers/staging/zcache/TODO64
-rw-r--r--drivers/staging/zcache/debug.c107
-rw-r--r--drivers/staging/zcache/debug.h305
-rw-r--r--drivers/staging/zcache/ramster.h59
-rw-r--r--drivers/staging/zcache/ramster/debug.c68
-rw-r--r--drivers/staging/zcache/ramster/debug.h145
-rw-r--r--drivers/staging/zcache/ramster/heartbeat.c462
-rw-r--r--drivers/staging/zcache/ramster/heartbeat.h87
-rw-r--r--drivers/staging/zcache/ramster/masklog.c155
-rw-r--r--drivers/staging/zcache/ramster/masklog.h220
-rw-r--r--drivers/staging/zcache/ramster/nodemanager.c996
-rw-r--r--drivers/staging/zcache/ramster/nodemanager.h88
-rw-r--r--drivers/staging/zcache/ramster/r2net.c414
-rw-r--r--drivers/staging/zcache/ramster/ramster-howto.txt366
-rw-r--r--drivers/staging/zcache/ramster/ramster.c925
-rw-r--r--drivers/staging/zcache/ramster/ramster.h161
-rw-r--r--drivers/staging/zcache/ramster/ramster_nodemanager.h41
-rw-r--r--drivers/staging/zcache/ramster/tcp.c2248
-rw-r--r--drivers/staging/zcache/ramster/tcp.h159
-rw-r--r--drivers/staging/zcache/ramster/tcp_internal.h248
-rw-r--r--drivers/staging/zcache/tmem.c898
-rw-r--r--drivers/staging/zcache/tmem.h259
-rw-r--r--drivers/staging/zcache/zbud.c1066
-rw-r--r--drivers/staging/zcache/zbud.h33
-rw-r--r--drivers/staging/zcache/zcache-main.c1941
-rw-r--r--drivers/staging/zcache/zcache.h53
-rw-r--r--drivers/staging/zram/zram_drv.c101
-rw-r--r--drivers/staging/zram/zram_drv.h10
-rw-r--r--drivers/staging/zsmalloc/zsmalloc-main.c4
-rw-r--r--drivers/target/iscsi/iscsi_target.c17
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c9
-rw-r--r--drivers/target/target_core_spc.c9
-rw-r--r--drivers/target/target_core_transport.c11
-rw-r--r--drivers/thermal/x86_pkg_temp_thermal.c18
-rw-r--r--drivers/tty/amiserial.c2
-rw-r--r--drivers/tty/hvc/hvc_console.c11
-rw-r--r--drivers/tty/hvc/hvc_console.h3
-rw-r--r--drivers/tty/hvc/hvc_iucv.c64
-rw-r--r--drivers/tty/hvc/hvc_xen.c6
-rw-r--r--drivers/tty/hvc/hvsi_lib.c4
-rw-r--r--drivers/tty/n_gsm.c29
-rw-r--r--drivers/tty/n_tty.c1414
-rw-r--r--drivers/tty/pty.c18
-rw-r--r--drivers/tty/serial/8250/8250_core.c2
-rw-r--r--drivers/tty/serial/8250/8250_dw.c34
-rw-r--r--drivers/tty/serial/8250/8250_early.c3
-rw-r--r--drivers/tty/serial/8250/8250_em.c27
-rw-r--r--drivers/tty/serial/8250/8250_gsc.c3
-rw-r--r--drivers/tty/serial/8250/8250_pci.c15
-rw-r--r--drivers/tty/serial/8250/Kconfig2
-rw-r--r--drivers/tty/serial/Kconfig35
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/altera_jtaguart.c5
-rw-r--r--drivers/tty/serial/altera_uart.c4
-rw-r--r--drivers/tty/serial/amba-pl010.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c18
-rw-r--r--drivers/tty/serial/apbuart.c2
-rw-r--r--drivers/tty/serial/ar933x_uart.c111
-rw-r--r--drivers/tty/serial/arc_uart.c37
-rw-r--r--drivers/tty/serial/atmel_serial.c857
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c3
-rw-r--r--drivers/tty/serial/bfin_sport_uart.c14
-rw-r--r--drivers/tty/serial/bfin_uart.c21
-rw-r--r--drivers/tty/serial/clps711x.c11
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c28
-rw-r--r--drivers/tty/serial/efm32-uart.c29
-rw-r--r--drivers/tty/serial/fsl_lpuart.c7
-rw-r--r--drivers/tty/serial/icom.c103
-rw-r--r--drivers/tty/serial/ifx6x60.c2
-rw-r--r--drivers/tty/serial/imx.c520
-rw-r--r--drivers/tty/serial/ioc4_serial.c4
-rw-r--r--drivers/tty/serial/lantiq.c7
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c7
-rw-r--r--drivers/tty/serial/m32r_sio.c3
-rw-r--r--drivers/tty/serial/max3100.c2
-rw-r--r--drivers/tty/serial/max310x.c991
-rw-r--r--drivers/tty/serial/mcf.c5
-rw-r--r--drivers/tty/serial/mfd.c14
-rw-r--r--drivers/tty/serial/mpsc.c15
-rw-r--r--drivers/tty/serial/mrst_max3110.c4
-rw-r--r--drivers/tty/serial/msm_serial.c276
-rw-r--r--drivers/tty/serial/msm_serial.h19
-rw-r--r--drivers/tty/serial/msm_serial_hs.c2
-rw-r--r--drivers/tty/serial/mxs-auart.c54
-rw-r--r--drivers/tty/serial/netx-serial.c8
-rw-r--r--drivers/tty/serial/nwpserial.c3
-rw-r--r--drivers/tty/serial/omap-serial.c214
-rw-r--r--drivers/tty/serial/pch_uart.c84
-rw-r--r--drivers/tty/serial/pmac_zilog.c1
-rw-r--r--drivers/tty/serial/pnx8xxx_uart.c5
-rw-r--r--drivers/tty/serial/pxa.c33
-rw-r--r--drivers/tty/serial/rp2.c2
-rw-r--r--drivers/tty/serial/sa1100.c5
-rw-r--r--drivers/tty/serial/samsung.c9
-rw-r--r--drivers/tty/serial/samsung.h3
-rw-r--r--drivers/tty/serial/sc26xx.c2
-rw-r--r--drivers/tty/serial/sccnxp.c339
-rw-r--r--drivers/tty/serial/serial-tegra.c16
-rw-r--r--drivers/tty/serial/serial_core.c4
-rw-r--r--drivers/tty/serial/serial_txx9.c2
-rw-r--r--drivers/tty/serial/sh-sci.c4
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c1195
-rw-r--r--drivers/tty/serial/sirfsoc_uart.h501
-rw-r--r--drivers/tty/serial/st-asc.c932
-rw-r--r--drivers/tty/serial/timbuart.c4
-rw-r--r--drivers/tty/serial/vr41xx_siu.c2
-rw-r--r--drivers/tty/serial/vt8500_serial.c3
-rw-r--r--drivers/tty/synclink.c130
-rw-r--r--drivers/tty/synclinkmp.c2
-rw-r--r--drivers/tty/tty_buffer.c417
-rw-r--r--drivers/tty/tty_io.c33
-rw-r--r--drivers/tty/tty_ioctl.c90
-rw-r--r--drivers/tty/tty_ldisc.c461
-rw-r--r--drivers/tty/tty_port.c5
-rw-r--r--drivers/tty/vt/keyboard.c21
-rw-r--r--drivers/tty/vt/selection.c8
-rw-r--r--drivers/tty/vt/vt.c8
-rw-r--r--drivers/uio/Kconfig21
-rw-r--r--drivers/uio/Makefile2
-rw-r--r--drivers/uio/uio.c62
-rw-r--r--drivers/uio/uio_dmem_genirq.c2
-rw-r--r--drivers/uio/uio_mf624.c247
-rw-r--r--drivers/uio/uio_pdrv.c113
-rw-r--r--drivers/uio/uio_pdrv_genirq.c2
-rw-r--r--drivers/uio/uio_pruss.c3
-rw-r--r--drivers/usb/Kconfig17
-rw-r--r--drivers/usb/Makefile3
-rw-r--r--drivers/usb/atm/Makefile3
-rw-r--r--drivers/usb/atm/speedtch.c2
-rw-r--r--drivers/usb/atm/usbatm.c49
-rw-r--r--drivers/usb/atm/usbatm.h35
-rw-r--r--drivers/usb/c67x00/c67x00-drv.c4
-rw-r--r--drivers/usb/chipidea/Kconfig7
-rw-r--r--drivers/usb/chipidea/Makefile2
-rw-r--r--drivers/usb/chipidea/bits.h14
-rw-r--r--drivers/usb/chipidea/ci.h8
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c110
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.h17
-rw-r--r--drivers/usb/chipidea/ci_hdrc_msm.c1
-rw-r--r--drivers/usb/chipidea/core.c197
-rw-r--r--drivers/usb/chipidea/host.c31
-rw-r--r--drivers/usb/chipidea/host.h6
-rw-r--r--drivers/usb/chipidea/otg.c120
-rw-r--r--drivers/usb/chipidea/otg.h35
-rw-r--r--drivers/usb/chipidea/udc.c78
-rw-r--r--drivers/usb/chipidea/udc.h6
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c95
-rw-r--r--drivers/usb/class/cdc-acm.c2
-rw-r--r--drivers/usb/class/cdc-wdm.c13
-rw-r--r--drivers/usb/class/usbtmc.c70
-rw-r--r--drivers/usb/core/buffer.c5
-rw-r--r--drivers/usb/core/config.c3
-rw-r--r--drivers/usb/core/devio.c6
-rw-r--r--drivers/usb/core/driver.c46
-rw-r--r--drivers/usb/core/endpoint.c37
-rw-r--r--drivers/usb/core/file.c2
-rw-r--r--drivers/usb/core/hcd-pci.c2
-rw-r--r--drivers/usb/core/hcd.c227
-rw-r--r--drivers/usb/core/hub.c288
-rw-r--r--drivers/usb/core/hub.h3
-rw-r--r--drivers/usb/core/message.c62
-rw-r--r--drivers/usb/core/port.c20
-rw-r--r--drivers/usb/core/quirks.c6
-rw-r--r--drivers/usb/core/sysfs.c303
-rw-r--r--drivers/usb/core/urb.c43
-rw-r--r--drivers/usb/core/usb.c60
-rw-r--r--drivers/usb/dwc3/Kconfig35
-rw-r--r--drivers/usb/dwc3/Makefile13
-rw-r--r--drivers/usb/dwc3/core.c199
-rw-r--r--drivers/usb/dwc3/core.h57
-rw-r--r--drivers/usb/dwc3/debug.h34
-rw-r--r--drivers/usb/dwc3/debugfs.c34
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c22
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c167
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c54
-rw-r--r--drivers/usb/dwc3/ep0.c49
-rw-r--r--drivers/usb/dwc3/gadget.c258
-rw-r--r--drivers/usb/dwc3/gadget.h34
-rw-r--r--drivers/usb/dwc3/host.c34
-rw-r--r--drivers/usb/dwc3/io.h34
-rw-r--r--drivers/usb/dwc3/platform_data.h27
-rw-r--r--drivers/usb/gadget/Kconfig29
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/amd5536udc.c4
-rw-r--r--drivers/usb/gadget/at91_udc.c41
-rw-r--r--drivers/usb/gadget/at91_udc.h2
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c26
-rw-r--r--drivers/usb/gadget/bcm63xx_udc.c2
-rw-r--r--drivers/usb/gadget/composite.c8
-rw-r--r--drivers/usb/gadget/configfs.c4
-rw-r--r--drivers/usb/gadget/dummy_hcd.c8
-rw-r--r--drivers/usb/gadget/ether.c14
-rw-r--r--drivers/usb/gadget/f_acm.c1
-rw-r--r--drivers/usb/gadget/f_ecm.c7
-rw-r--r--drivers/usb/gadget/f_eem.c7
-rw-r--r--drivers/usb/gadget/f_fs.c2
-rw-r--r--drivers/usb/gadget/f_mass_storage.c18
-rw-r--r--drivers/usb/gadget/f_ncm.c7
-rw-r--r--drivers/usb/gadget/f_phonet.c9
-rw-r--r--drivers/usb/gadget/f_rndis.c7
-rw-r--r--drivers/usb/gadget/f_subset.c7
-rw-r--r--drivers/usb/gadget/f_uac1.c4
-rw-r--r--drivers/usb/gadget/fotg210-udc.c8
-rw-r--r--drivers/usb/gadget/fsl_mxc_udc.c4
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c6
-rw-r--r--drivers/usb/gadget/fusb300_udc.c2
-rw-r--r--drivers/usb/gadget/goku_udc.c2
-rw-r--r--drivers/usb/gadget/hid.c2
-rw-r--r--drivers/usb/gadget/imx_udc.c1544
-rw-r--r--drivers/usb/gadget/imx_udc.h351
-rw-r--r--drivers/usb/gadget/inode.c4
-rw-r--r--drivers/usb/gadget/m66592-udc.c4
-rw-r--r--drivers/usb/gadget/multi.c10
-rw-r--r--drivers/usb/gadget/mv_u3d_core.c16
-rw-r--r--drivers/usb/gadget/mv_udc_core.c4
-rw-r--r--drivers/usb/gadget/net2272.c4
-rw-r--r--drivers/usb/gadget/net2280.c18
-rw-r--r--drivers/usb/gadget/omap_udc.c2
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c2
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c2
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c2
-rw-r--r--drivers/usb/gadget/rndis.c4
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c14
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c4
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c2
-rw-r--r--drivers/usb/gadget/storage_common.c27
-rw-r--r--drivers/usb/gadget/u_uac1.c2
-rw-r--r--drivers/usb/gadget/udc-core.c32
-rw-r--r--drivers/usb/gadget/uvc_queue.c6
-rw-r--r--drivers/usb/host/Kconfig63
-rw-r--r--drivers/usb/host/Makefile5
-rw-r--r--drivers/usb/host/ehci-dbg.c9
-rw-r--r--drivers/usb/host/ehci-fsl.c18
-rw-r--r--drivers/usb/host/ehci-grlib.c13
-rw-r--r--drivers/usb/host/ehci-hcd.c33
-rw-r--r--drivers/usb/host/ehci-hub.c233
-rw-r--r--drivers/usb/host/ehci-mem.c1
-rw-r--r--drivers/usb/host/ehci-mv.c4
-rw-r--r--drivers/usb/host/ehci-mxc.c16
-rw-r--r--drivers/usb/host/ehci-octeon.c2
-rw-r--r--drivers/usb/host/ehci-omap.c14
-rw-r--r--drivers/usb/host/ehci-orion.c2
-rw-r--r--drivers/usb/host/ehci-pci.c42
-rw-r--r--drivers/usb/host/ehci-platform.c12
-rw-r--r--drivers/usb/host/ehci-pmcmsp.c2
-rw-r--r--drivers/usb/host/ehci-ppc-of.c13
-rw-r--r--drivers/usb/host/ehci-ps3.c2
-rw-r--r--drivers/usb/host/ehci-q.c119
-rw-r--r--drivers/usb/host/ehci-s5p.c12
-rw-r--r--drivers/usb/host/ehci-sched.c118
-rw-r--r--drivers/usb/host/ehci-sead3.c2
-rw-r--r--drivers/usb/host/ehci-sh.c4
-rw-r--r--drivers/usb/host/ehci-tegra.c95
-rw-r--r--drivers/usb/host/ehci-tilegx.c6
-rw-r--r--drivers/usb/host/ehci-timer.c34
-rw-r--r--drivers/usb/host/ehci-w90x900.c2
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c19
-rw-r--r--drivers/usb/host/ehci.h17
-rw-r--r--drivers/usb/host/fotg210-hcd.c6049
-rw-r--r--drivers/usb/host/fotg210.h750
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c4
-rw-r--r--drivers/usb/host/hwa-hc.c7
-rw-r--r--drivers/usb/host/imx21-hcd.c2
-rw-r--r--drivers/usb/host/isp116x-hcd.c2
-rw-r--r--drivers/usb/host/isp116x.h13
-rw-r--r--drivers/usb/host/isp1362-hcd.c85
-rw-r--r--drivers/usb/host/isp1362.h53
-rw-r--r--drivers/usb/host/isp1760-if.c2
-rw-r--r--drivers/usb/host/ohci-at91.c37
-rw-r--r--drivers/usb/host/ohci-da8xx.c8
-rw-r--r--drivers/usb/host/ohci-ep93xx.c137
-rw-r--r--drivers/usb/host/ohci-exynos.c2
-rw-r--r--drivers/usb/host/ohci-hcd.c2
-rw-r--r--drivers/usb/host/ohci-omap.c4
-rw-r--r--drivers/usb/host/ohci-omap3.c10
-rw-r--r--drivers/usb/host/ohci-pci.c9
-rw-r--r--drivers/usb/host/ohci-platform.c10
-rw-r--r--drivers/usb/host/ohci-ppc-of.c11
-rw-r--r--drivers/usb/host/ohci-pxa27x.c8
-rw-r--r--drivers/usb/host/ohci-s3c2410.c11
-rw-r--r--drivers/usb/host/ohci-tilegx.c4
-rw-r--r--drivers/usb/host/pci-quirks.c48
-rw-r--r--drivers/usb/host/pci-quirks.h4
-rw-r--r--drivers/usb/host/r8a66597-hcd.c6
-rw-r--r--drivers/usb/host/sl811-hcd.c109
-rw-r--r--drivers/usb/host/sl811.h21
-rw-r--r--drivers/usb/host/u132-hcd.c6
-rw-r--r--drivers/usb/host/xhci-dbg.c14
-rw-r--r--drivers/usb/host/xhci-ext-caps.h2
-rw-r--r--drivers/usb/host/xhci-hub.c228
-rw-r--r--drivers/usb/host/xhci-mem.c188
-rw-r--r--drivers/usb/host/xhci-pci.c29
-rw-r--r--drivers/usb/host/xhci-plat.c48
-rw-r--r--drivers/usb/host/xhci-ring.c115
-rw-r--r--drivers/usb/host/xhci-trace.c15
-rw-r--r--drivers/usb/host/xhci-trace.h151
-rw-r--r--drivers/usb/host/xhci.c396
-rw-r--r--drivers/usb/host/xhci.h18
-rw-r--r--drivers/usb/misc/Kconfig14
-rw-r--r--drivers/usb/misc/Makefile4
-rw-r--r--drivers/usb/misc/adutux.c202
-rw-r--r--drivers/usb/misc/ehset.c152
-rw-r--r--drivers/usb/misc/ldusb.c31
-rw-r--r--drivers/usb/misc/legousbtower.c124
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c1
-rw-r--r--drivers/usb/misc/usb3503.c284
-rw-r--r--drivers/usb/misc/usbtest.c9
-rw-r--r--drivers/usb/misc/uss720.c24
-rw-r--r--drivers/usb/musb/Kconfig9
-rw-r--r--drivers/usb/musb/Makefile4
-rw-r--r--drivers/usb/musb/am35x.c16
-rw-r--r--drivers/usb/musb/blackfin.c4
-rw-r--r--drivers/usb/musb/cppi_dma.c18
-rw-r--r--drivers/usb/musb/da8xx.c4
-rw-r--r--drivers/usb/musb/davinci.c4
-rw-r--r--drivers/usb/musb/musb_am335x.c55
-rw-r--r--drivers/usb/musb/musb_core.c31
-rw-r--r--drivers/usb/musb/musb_core.h8
-rw-r--r--drivers/usb/musb/musb_cppi41.c557
-rw-r--r--drivers/usb/musb/musb_dma.h21
-rw-r--r--drivers/usb/musb/musb_dsps.c395
-rw-r--r--drivers/usb/musb/musb_gadget.c102
-rw-r--r--drivers/usb/musb/musb_host.c2
-rw-r--r--drivers/usb/musb/musbhsdma.c17
-rw-r--r--drivers/usb/musb/omap2430.c15
-rw-r--r--drivers/usb/musb/tusb6010.c11
-rw-r--r--drivers/usb/musb/tusb6010_omap.c24
-rw-r--r--drivers/usb/musb/ux500.c2
-rw-r--r--drivers/usb/musb/ux500_dma.c25
-rw-r--r--drivers/usb/phy/Kconfig50
-rw-r--r--drivers/usb/phy/Makefile7
-rw-r--r--drivers/usb/phy/am35x-phy-control.h21
-rw-r--r--drivers/usb/phy/phy-am335x-control.c137
-rw-r--r--drivers/usb/phy/phy-am335x.c99
-rw-r--r--drivers/usb/phy/phy-fsl-usb.c12
-rw-r--r--drivers/usb/phy/phy-fsl-usb.h2
-rw-r--r--drivers/usb/phy/phy-fsm-usb.c2
-rw-r--r--drivers/usb/phy/phy-fsm-usb.h11
-rw-r--r--drivers/usb/phy/phy-generic.c (renamed from drivers/usb/phy/phy-nop.c)167
-rw-r--r--drivers/usb/phy/phy-generic.h20
-rw-r--r--drivers/usb/phy/phy-gpio-vbus-usb.c10
-rw-r--r--drivers/usb/phy/phy-isp1301-omap.c6
-rw-r--r--drivers/usb/phy/phy-msm-usb.c4
-rw-r--r--drivers/usb/phy/phy-mv-u3d-usb.c4
-rw-r--r--drivers/usb/phy/phy-mv-usb.c6
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c13
-rw-r--r--drivers/usb/phy/phy-omap-control.c3
-rw-r--r--drivers/usb/phy/phy-omap-usb2.c7
-rw-r--r--drivers/usb/phy/phy-omap-usb3.c87
-rw-r--r--drivers/usb/phy/phy-rcar-usb.c9
-rw-r--r--drivers/usb/phy/phy-samsung-usb2.c4
-rw-r--r--drivers/usb/phy/phy-samsung-usb3.c2
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c462
-rw-r--r--drivers/usb/phy/phy-twl4030-usb.c2
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c2
-rw-r--r--drivers/usb/renesas_usbhs/common.c6
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c10
-rw-r--r--drivers/usb/renesas_usbhs/mod_host.c6
-rw-r--r--drivers/usb/renesas_usbhs/pipe.h6
-rw-r--r--drivers/usb/serial/Kconfig77
-rw-r--r--drivers/usb/serial/Makefile8
-rw-r--r--drivers/usb/serial/bus.c19
-rw-r--r--drivers/usb/serial/console.c27
-rw-r--r--drivers/usb/serial/cp210x.c7
-rw-r--r--drivers/usb/serial/cypress_m8.c4
-rw-r--r--drivers/usb/serial/f81232.c3
-rw-r--r--drivers/usb/serial/flashloader.c39
-rw-r--r--drivers/usb/serial/ftdi_sio.c98
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h34
-rw-r--r--drivers/usb/serial/funsoft.c40
-rw-r--r--drivers/usb/serial/generic.c13
-rw-r--r--drivers/usb/serial/hp4x.c51
-rw-r--r--drivers/usb/serial/io_edgeport.c2
-rw-r--r--drivers/usb/serial/io_ti.c79
-rw-r--r--drivers/usb/serial/iuu_phoenix.c8
-rw-r--r--drivers/usb/serial/keyspan.c106
-rw-r--r--drivers/usb/serial/mos7720.c21
-rw-r--r--drivers/usb/serial/mos7840.c223
-rw-r--r--drivers/usb/serial/moto_modem.c48
-rw-r--r--drivers/usb/serial/option.c23
-rw-r--r--drivers/usb/serial/oti6858.c10
-rw-r--r--drivers/usb/serial/pl2303.c352
-rw-r--r--drivers/usb/serial/quatech2.c35
-rw-r--r--drivers/usb/serial/safe_serial.c51
-rw-r--r--drivers/usb/serial/siemens_mpi.c47
-rw-r--r--drivers/usb/serial/spcp8x5.c4
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c114
-rw-r--r--drivers/usb/serial/usb-serial-simple.c110
-rw-r--r--drivers/usb/serial/usb-serial.c14
-rw-r--r--drivers/usb/serial/usb_wwan.c20
-rw-r--r--drivers/usb/serial/vivopay-serial.c43
-rw-r--r--drivers/usb/serial/zio.c39
-rw-r--r--drivers/usb/storage/scsiglue.c16
-rw-r--r--drivers/usb/storage/unusual_devs.h7
-rw-r--r--drivers/usb/usb-common.c49
-rw-r--r--drivers/usb/usb-skeleton.c3
-rw-r--r--drivers/usb/wusbcore/rh.c28
-rw-r--r--drivers/usb/wusbcore/wa-hc.h15
-rw-r--r--drivers/usb/wusbcore/wa-rpipe.c21
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c148
-rw-r--r--drivers/uwb/drp-ie.c4
-rw-r--r--drivers/uwb/hwa-rc.c16
-rw-r--r--drivers/uwb/pal.c40
-rw-r--r--drivers/vfio/pci/vfio_pci.c23
-rw-r--r--drivers/vfio/vfio.c37
-rw-r--r--drivers/vhost/net.c37
-rw-r--r--drivers/vhost/scsi.c17
-rw-r--r--drivers/vhost/test.c6
-rw-r--r--drivers/vhost/vhost.h10
-rw-r--r--drivers/video/aty/atyfb_base.c4
-rw-r--r--drivers/video/backlight/backlight.c44
-rw-r--r--drivers/video/backlight/lcd.c26
-rw-r--r--drivers/video/backlight/max8925_bl.c41
-rw-r--r--drivers/video/hyperv_fb.c1
-rw-r--r--drivers/video/mxsfb.c26
-rw-r--r--drivers/video/nuc900fb.c3
-rw-r--r--drivers/video/omap2/displays-new/connector-analog-tv.c18
-rw-r--r--drivers/video/sgivwfb.c2
-rw-r--r--drivers/video/sh7760fb.c2
-rw-r--r--drivers/video/vga16fb.c1
-rw-r--r--drivers/video/xilinxfb.c4
-rw-r--r--drivers/vme/boards/vme_vmivme7805.c2
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.c10
-rw-r--r--drivers/vme/bridges/vme_tsi148.c4
-rw-r--r--drivers/w1/slaves/w1_ds2408.c174
-rw-r--r--drivers/w1/slaves/w1_ds2413.c72
-rw-r--r--drivers/w1/slaves/w1_ds2423.c27
-rw-r--r--drivers/w1/slaves/w1_ds2431.c43
-rw-r--r--drivers/w1/slaves/w1_ds2433.c47
-rw-r--r--drivers/w1/slaves/w1_ds2760.c35
-rw-r--r--drivers/w1/slaves/w1_ds2780.c36
-rw-r--r--drivers/w1/slaves/w1_ds2781.c36
-rw-r--r--drivers/w1/slaves/w1_ds28e04.c112
-rw-r--r--drivers/w1/slaves/w1_therm.c24
-rw-r--r--drivers/w1/w1.c164
-rw-r--r--drivers/w1/w1_family.h1
-rw-r--r--drivers/xen/Kconfig2
-rw-r--r--drivers/xen/Makefile5
-rw-r--r--drivers/xen/acpi.c41
-rw-r--r--drivers/xen/events.c13
-rw-r--r--drivers/xen/evtchn.c21
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c19
2380 files changed, 212442 insertions, 84500 deletions
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
index d21167bfc86..dc34a5b8bce 100644
--- a/drivers/accessibility/braille/braille_console.c
+++ b/drivers/accessibility/braille/braille_console.c
@@ -359,6 +359,9 @@ int braille_register_console(struct console *console, int index,
char *console_options, char *braille_options)
{
int ret;
+
+ if (!(console->flags & CON_BRL))
+ return 0;
if (!console_options)
/* Only support VisioBraille for now */
console_options = "57600o8";
@@ -374,15 +377,17 @@ int braille_register_console(struct console *console, int index,
braille_co = console;
register_keyboard_notifier(&keyboard_notifier_block);
register_vt_notifier(&vt_notifier_block);
- return 0;
+ return 1;
}
int braille_unregister_console(struct console *console)
{
if (braille_co != console)
return -EINVAL;
+ if (!(console->flags & CON_BRL))
+ return 0;
unregister_keyboard_notifier(&keyboard_notifier_block);
unregister_vt_notifier(&vt_notifier_block);
braille_co = NULL;
- return 0;
+ return 1;
}
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 100bd724f64..3278a210c43 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -91,24 +91,6 @@ config ACPI_EC_DEBUGFS
Thus this option is a debug option that helps to write ACPI drivers
and can be used to identify ACPI code or EC firmware bugs.
-config ACPI_PROC_EVENT
- bool "Deprecated /proc/acpi/event support"
- depends on PROC_FS
- default y
- help
- A user-space daemon, acpid, typically reads /proc/acpi/event
- and handles all ACPI-generated events.
-
- These events are now delivered to user-space either
- via the input layer or as netlink events.
-
- This build option enables the old code for legacy
- user-space implementation. After some time, this will
- be moved under CONFIG_ACPI_PROCFS, and then deleted.
-
- Say Y here to retain the old behaviour. Say N if your
- user-space is newer than kernel 2.6.23 (September 2007).
-
config ACPI_AC
tristate "AC Adapter"
depends on X86
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 4f4e741d34b..f37beaa3275 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -267,7 +267,6 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
msleep(ac_sleep_before_get_state_ms);
acpi_ac_get_state(ac);
- acpi_bus_generate_proc_event(device, event, (u32) ac->state);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
(u32) ac->state);
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 27bb6a91de5..6230637054c 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -452,7 +452,6 @@ static void acpi_pad_notify(acpi_handle handle, u32 event,
switch (event) {
case ACPI_PROCESSOR_AGGREGATOR_NOTIFY:
acpi_pad_handle_notify(handle);
- acpi_bus_generate_proc_event(device, event, 0);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event, 0);
break;
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index fafec5ddf17..1bde12708f9 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -52,7 +52,7 @@ int acpi_create_platform_device(struct acpi_device *adev,
struct platform_device_info pdevinfo;
struct resource_list_entry *rentry;
struct list_head resource_list;
- struct resource *resources;
+ struct resource *resources = NULL;
int count;
/* If the ACPI node already has a physical device attached, skip it. */
@@ -61,20 +61,22 @@ int acpi_create_platform_device(struct acpi_device *adev,
INIT_LIST_HEAD(&resource_list);
count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
- if (count <= 0)
+ if (count < 0) {
return 0;
+ } else if (count > 0) {
+ resources = kmalloc(count * sizeof(struct resource),
+ GFP_KERNEL);
+ if (!resources) {
+ dev_err(&adev->dev, "No memory for resources\n");
+ acpi_dev_free_resource_list(&resource_list);
+ return -ENOMEM;
+ }
+ count = 0;
+ list_for_each_entry(rentry, &resource_list, node)
+ resources[count++] = rentry->res;
- resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL);
- if (!resources) {
- dev_err(&adev->dev, "No memory for resources\n");
acpi_dev_free_resource_list(&resource_list);
- return -ENOMEM;
}
- count = 0;
- list_for_each_entry(rentry, &resource_list, node)
- resources[count++] = rentry->res;
-
- acpi_dev_free_resource_list(&resource_list);
memset(&pdevinfo, 0, sizeof(pdevinfo));
/*
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index fd6c51cc3ac..f29e06efa47 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -178,14 +178,17 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
return -ENODEV;
+ cpu_maps_update_begin();
+ cpu_hotplug_begin();
+
ret = acpi_map_lsapic(pr->handle, &pr->id);
if (ret)
- return ret;
+ goto out;
ret = arch_register_cpu(pr->id);
if (ret) {
acpi_unmap_lsapic(pr->id);
- return ret;
+ goto out;
}
/*
@@ -195,7 +198,11 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
*/
pr_info("CPU%d has been hot-added\n", pr->id);
pr->flags.need_hotplug_init = 1;
- return 0;
+
+out:
+ cpu_hotplug_done();
+ cpu_maps_update_done();
+ return ret;
}
#else
static inline int acpi_processor_hotadd_init(struct acpi_processor *pr)
@@ -451,13 +458,18 @@ static void acpi_processor_remove(struct acpi_device *device)
/* Clean up. */
per_cpu(processor_device_array, pr->id) = NULL;
per_cpu(processors, pr->id) = NULL;
- try_offline_node(cpu_to_node(pr->id));
+
+ cpu_maps_update_begin();
+ cpu_hotplug_begin();
/* Remove the CPU. */
- get_online_cpus();
arch_unregister_cpu(pr->id);
acpi_unmap_lsapic(pr->id);
- put_online_cpus();
+
+ cpu_hotplug_done();
+ cpu_maps_update_done();
+
+ try_offline_node(cpu_to_node(pr->id));
out:
free_cpumask_var(pr->throttling.shared_cpu_map);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index b8d38117a20..90e846f985f 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -138,6 +138,12 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE);
*/
u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_ssdt_table_load, FALSE);
+/*
+ * We keep track of the latest version of Windows that has been requested by
+ * the BIOS.
+ */
+u8 ACPI_INIT_GLOBAL(acpi_gbl_osi_data, 0);
+
/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
struct acpi_table_fadt acpi_gbl_FADT;
@@ -285,7 +291,6 @@ ACPI_EXTERN u8 acpi_gbl_debugger_configuration;
ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
ACPI_EXTERN u8 acpi_gbl_events_initialized;
-ACPI_EXTERN u8 acpi_gbl_osi_data;
ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces;
ACPI_EXTERN struct acpi_address_range
*acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX];
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index d4a4901637c..0ed00669cd2 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -942,6 +942,9 @@ struct acpi_interface_info {
#define ACPI_OSI_INVALID 0x01
#define ACPI_OSI_DYNAMIC 0x02
+#define ACPI_OSI_FEATURE 0x04
+#define ACPI_OSI_DEFAULT_INVALID 0x08
+#define ACPI_OSI_OPTIONAL_FEATURE (ACPI_OSI_FEATURE | ACPI_OSI_DEFAULT_INVALID | ACPI_OSI_INVALID)
struct acpi_port_info {
char *name;
@@ -1030,6 +1033,7 @@ struct acpi_external_list {
u8 type;
u8 flags;
u8 resolved;
+ u8 emitted;
};
/* Values for Flags field above */
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index b83dc32a5ae..40b04bd5579 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -104,8 +104,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
acpi_handle start_object,
u32 max_depth,
u32 flags,
- acpi_walk_callback pre_order_visit,
- acpi_walk_callback post_order_visit,
+ acpi_walk_callback descending_callback,
+ acpi_walk_callback ascending_callback,
void *context, void **return_value);
struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index 7755e915a00..c54f42c64fe 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -47,6 +47,13 @@
acpi_status acpi_allocate_root_table(u32 initial_table_count);
/*
+ * tbxfroot - Root pointer utilities
+ */
+acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
+
+u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length);
+
+/*
* tbfadt - FADT parse/convert/validate
*/
void acpi_tb_parse_fadt(u32 table_index);
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 3c76edea680..d5a62a6182b 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -470,6 +470,8 @@ acpi_status acpi_ut_install_interface(acpi_string interface_name);
acpi_status acpi_ut_remove_interface(acpi_string interface_name);
+acpi_status acpi_ut_update_interfaces(u8 action);
+
struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name);
acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
@@ -616,7 +618,7 @@ int acpi_ut_stricmp(char *string1, char *string2);
acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer);
-void acpi_ut_print_string(char *string, u8 max_length);
+void acpi_ut_print_string(char *string, u16 max_length);
void ut_convert_backslashes(char *pathname);
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 9037f17c960..7842700346a 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -125,7 +125,6 @@ acpi_status acpi_ev_gpe_initialize(void)
/* GPE block 0 exists (has both length and address > 0) */
register_count0 = (u16)(acpi_gbl_FADT.gpe0_block_length / 2);
-
gpe_number_max =
(register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
@@ -204,16 +203,6 @@ acpi_status acpi_ev_gpe_initialize(void)
goto cleanup;
}
- /* Check for Max GPE number out-of-range */
-
- if (gpe_number_max > ACPI_GPE_MAX) {
- ACPI_ERROR((AE_INFO,
- "Maximum GPE number from FADT is too large: 0x%X",
- gpe_number_max));
- status = AE_BAD_VALUE;
- goto cleanup;
- }
-
cleanup:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index c740f24e310..4d046faac48 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -338,6 +338,7 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
{
u8 *target;
char *name;
+ const char *reference_name;
u8 count;
if (!info) {
@@ -426,10 +427,9 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
case ACPI_EXD_REFERENCE:
+ reference_name = acpi_ut_get_reference_name(obj_desc);
acpi_ex_out_string("Class Name",
- ACPI_CAST_PTR(char,
- acpi_ut_get_reference_name
- (obj_desc)));
+ ACPI_CAST_PTR(char, reference_name));
acpi_ex_dump_reference_obj(obj_desc);
break;
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index 814b4a3d656..2cdd41d8ade 100644
--- a/drivers/acpi/acpica/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -962,10 +962,17 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
*/
return_desc =
*(operand[0]->reference.where);
- if (return_desc) {
- acpi_ut_add_reference
- (return_desc);
+ if (!return_desc) {
+ /*
+ * Element is NULL, do not allow the dereference.
+ * This provides compatibility with other ACPI
+ * implementations.
+ */
+ return_ACPI_STATUS
+ (AE_AML_UNINITIALIZED_ELEMENT);
}
+
+ acpi_ut_add_reference(return_desc);
break;
default:
@@ -990,11 +997,40 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
acpi_namespace_node
*)
return_desc);
- }
+ if (!return_desc) {
+ break;
+ }
- /* Add another reference to the object! */
+ /*
+ * June 2013:
+ * buffer_fields/field_units require additional resolution
+ */
+ switch (return_desc->common.type) {
+ case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
- acpi_ut_add_reference(return_desc);
+ status =
+ acpi_ex_read_data_from_field
+ (walk_state, return_desc,
+ &temp_desc);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ return_desc = temp_desc;
+ break;
+
+ default:
+
+ /* Add another reference to the object */
+
+ acpi_ut_add_reference
+ (return_desc);
+ break;
+ }
+ }
break;
default:
diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
index 5e5f76230f5..414076818d4 100644
--- a/drivers/acpi/acpica/hwesleep.c
+++ b/drivers/acpi/acpica/hwesleep.c
@@ -43,6 +43,7 @@
*/
#include <acpi/acpi.h>
+#include <linux/acpi.h>
#include "accommon.h"
#define _COMPONENT ACPI_HARDWARE
@@ -128,6 +129,14 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state)
ACPI_FLUSH_CPU_CACHE();
+ status = acpi_os_prepare_extended_sleep(sleep_state,
+ acpi_gbl_sleep_type_a,
+ acpi_gbl_sleep_type_b);
+ if (ACPI_SKIP(status))
+ return_ACPI_STATUS(AE_OK);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(status);
+
/*
* Set the SLP_TYP and SLP_EN bits.
*
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index 0c1a8bbd05d..2d7d22ebc78 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -100,8 +100,13 @@ acpi_status acpi_get_timer(u32 * ticks)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block);
+ /* ACPI 5.0A: PM Timer is optional */
+
+ if (!acpi_gbl_FADT.xpm_timer_block.address) {
+ return_ACPI_STATUS(AE_SUPPORT);
+ }
+ status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block);
return_ACPI_STATUS(status);
}
@@ -148,6 +153,12 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
+ /* ACPI 5.0A: PM Timer is optional */
+
+ if (!acpi_gbl_FADT.xpm_timer_block.address) {
+ return_ACPI_STATUS(AE_SUPPORT);
+ }
+
/*
* Compute Tick Delta:
* Handle (max one) timer rollovers on 24-bit versus 32-bit timers.
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 24b71a01bf9..098e7666cbc 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -151,6 +151,15 @@ acpi_ns_check_return_value(struct acpi_namespace_node *node,
}
/*
+ *
+ * 4) If there is no return value and it is optional, just return
+ * AE_OK (_WAK).
+ */
+ if (!(*return_object_ptr)) {
+ goto exit;
+ }
+
+ /*
* For returned Package objects, check the type of all sub-objects.
* Note: Package may have been newly created by call above.
*/
@@ -268,7 +277,12 @@ acpi_ns_check_object_type(struct acpi_evaluate_info *info,
acpi_ut_get_expected_return_types(type_buffer, expected_btypes);
- if (package_index == ACPI_NOT_PACKAGE_ELEMENT) {
+ if (!return_object) {
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
+ "Expected return object of type %s",
+ type_buffer));
+ } else if (package_index == ACPI_NOT_PACKAGE_ELEMENT) {
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
info->node_flags,
"Return type mismatch - found %s, expected %s",
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index e70911a9e44..e81f15ef659 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -156,9 +156,9 @@ struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
* max_depth - Depth to which search is to reach
* flags - Whether to unlock the NS before invoking
* the callback routine
- * pre_order_visit - Called during tree pre-order visit
+ * descending_callback - Called during tree descent
* when an object of "Type" is found
- * post_order_visit - Called during tree post-order visit
+ * ascending_callback - Called during tree ascent
* when an object of "Type" is found
* context - Passed to user function(s) above
* return_value - from the user_function if terminated
@@ -185,8 +185,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
acpi_handle start_node,
u32 max_depth,
u32 flags,
- acpi_walk_callback pre_order_visit,
- acpi_walk_callback post_order_visit,
+ acpi_walk_callback descending_callback,
+ acpi_walk_callback ascending_callback,
void *context, void **return_value)
{
acpi_status status;
@@ -255,22 +255,22 @@ acpi_ns_walk_namespace(acpi_object_type type,
}
/*
- * Invoke the user function, either pre-order or post-order
+ * Invoke the user function, either descending, ascending,
* or both.
*/
if (!node_previously_visited) {
- if (pre_order_visit) {
+ if (descending_callback) {
status =
- pre_order_visit(child_node, level,
- context,
- return_value);
+ descending_callback(child_node,
+ level, context,
+ return_value);
}
} else {
- if (post_order_visit) {
+ if (ascending_callback) {
status =
- post_order_visit(child_node, level,
- context,
- return_value);
+ ascending_callback(child_node,
+ level, context,
+ return_value);
}
}
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index f553cfdb71d..b38b4b07f86 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -533,9 +533,9 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info)
* PARAMETERS: type - acpi_object_type to search for
* start_object - Handle in namespace where search begins
* max_depth - Depth to which search is to reach
- * pre_order_visit - Called during tree pre-order visit
+ * descending_callback - Called during tree descent
* when an object of "Type" is found
- * post_order_visit - Called during tree post-order visit
+ * ascending_callback - Called during tree ascent
* when an object of "Type" is found
* context - Passed to user function(s) above
* return_value - Location where return value of
@@ -563,8 +563,8 @@ acpi_status
acpi_walk_namespace(acpi_object_type type,
acpi_handle start_object,
u32 max_depth,
- acpi_walk_callback pre_order_visit,
- acpi_walk_callback post_order_visit,
+ acpi_walk_callback descending_callback,
+ acpi_walk_callback ascending_callback,
void *context, void **return_value)
{
acpi_status status;
@@ -574,7 +574,7 @@ acpi_walk_namespace(acpi_object_type type,
/* Parameter validation */
if ((type > ACPI_TYPE_LOCAL_MAX) ||
- (!max_depth) || (!pre_order_visit && !post_order_visit)) {
+ (!max_depth) || (!descending_callback && !ascending_callback)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
@@ -606,9 +606,9 @@ acpi_walk_namespace(acpi_object_type type,
}
status = acpi_ns_walk_namespace(type, start_object, max_depth,
- ACPI_NS_WALK_UNLOCK, pre_order_visit,
- post_order_visit, context,
- return_value);
+ ACPI_NS_WALK_UNLOCK,
+ descending_callback, ascending_callback,
+ context, return_value);
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index f3a4d95899f..83c16443458 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -158,6 +158,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer)
{
acpi_status status;
struct acpi_namespace_node *node;
+ char *node_name;
/* Parameter validation */
@@ -202,7 +203,8 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer)
/* Just copy the ACPI name from the Node and zero terminate it */
- ACPI_MOVE_NAME(buffer->pointer, acpi_ut_get_node_name(node));
+ node_name = acpi_ut_get_node_name(node);
+ ACPI_MOVE_NAME(buffer->pointer, node_name);
((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0;
status = AE_OK;
@@ -379,9 +381,14 @@ acpi_get_object_info(acpi_handle handle,
* Get extra info for ACPI Device/Processor objects only:
* Run the _STA, _ADR and, sx_w, and _sx_d methods.
*
- * Note: none of these methods are required, so they may or may
+ * Notes: none of these methods are required, so they may or may
* not be present for this device. The Info->Valid bitfield is used
* to indicate which methods were found and run successfully.
+ *
+ * For _STA, if the method does not exist, then (as per the ACPI
+ * specification), the returned current_status flags will indicate
+ * that the device is present/functional/enabled. Otherwise, the
+ * current_status flags reflect the value returned from _STA.
*/
/* Execute the Device._STA method */
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 33b00d22300..9d99f218969 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -117,7 +117,7 @@ static struct acpi_fadt_info fadt_info_table[] = {
ACPI_FADT_OFFSET(pm_timer_block),
ACPI_FADT_OFFSET(pm_timer_length),
ACPI_PM_TIMER_WIDTH,
- ACPI_FADT_REQUIRED},
+ ACPI_FADT_SEPARATE_LENGTH}, /* ACPI 5.0A: Timer is optional */
{"Gpe0Block",
ACPI_FADT_OFFSET(xgpe0_block),
@@ -574,7 +574,7 @@ static void acpi_tb_validate_fadt(void)
if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
/*
- * Field is required (Pm1a_event, Pm1a_control, pm_timer).
+ * Field is required (Pm1a_event, Pm1a_control).
* Both the address and length must be non-zero.
*/
if (!address64->address || !length) {
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index 7c2ecfb7c2c..948c95e80d4 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -48,11 +48,6 @@
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbxfroot")
-/* Local prototypes */
-static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
-
-static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
-
/*******************************************************************************
*
* FUNCTION: acpi_tb_validate_rsdp
@@ -64,8 +59,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
* DESCRIPTION: Validate the RSDP (ptr)
*
******************************************************************************/
-
-static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
+acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
{
/*
@@ -74,7 +68,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
* Note: Sometimes there exists more than one RSDP in memory; the valid
* RSDP has a valid checksum, all others have an invalid checksum.
*/
- if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP,
+ if (ACPI_STRNCMP((char *)rsdp->signature, ACPI_SIG_RSDP,
sizeof(ACPI_SIG_RSDP) - 1) != 0) {
/* Nope, BAD Signature */
@@ -231,7 +225,7 @@ acpi_status acpi_find_root_pointer(acpi_size *table_address)
* DESCRIPTION: Search a block of memory for the RSDP signature
*
******************************************************************************/
-static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
+u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length)
{
acpi_status status;
u8 *mem_rover;
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index ee83adb97b1..4fd68971019 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -239,7 +239,8 @@ acpi_ut_evaluate_numeric_object(char *object_name,
* RETURN: Status
*
* DESCRIPTION: Executes _STA for selected device and stores results in
- * *Flags.
+ * *Flags. If _STA does not exist, then the device is assumed
+ * to be present/functional/enabled (as per the ACPI spec).
*
* NOTE: Internal function, no parameter validation
*
@@ -257,6 +258,11 @@ acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags)
ACPI_BTYPE_INTEGER, &obj_desc);
if (ACPI_FAILURE(status)) {
if (AE_NOT_FOUND == status) {
+ /*
+ * if _STA does not exist, then (as per the ACPI specification),
+ * the returned flags will indicate that the device is present,
+ * functional, and enabled.
+ */
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"_STA on %4.4s was not found, assuming device is present\n",
acpi_ut_get_node_name(device_node)));
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index f736448a860..d6f26bf8a06 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -336,7 +336,6 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_trace_dbg_layer = 0;
acpi_gbl_debugger_configuration = DEBUGGER_THREADING;
acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
- acpi_gbl_osi_data = 0;
acpi_gbl_osi_mutex = NULL;
acpi_gbl_reg_methods_executed = FALSE;
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
index 7e807725c63..8856bd37bc7 100644
--- a/drivers/acpi/acpica/utosi.c
+++ b/drivers/acpi/acpica/utosi.c
@@ -77,21 +77,20 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = {
/* Feature Group Strings */
- {"Extended Address Space Descriptor", NULL, 0, 0}
+ {"Extended Address Space Descriptor", NULL, ACPI_OSI_FEATURE, 0},
/*
* All "optional" feature group strings (features that are implemented
- * by the host) should be dynamically added by the host via
- * acpi_install_interface and should not be manually added here.
- *
- * Examples of optional feature group strings:
- *
- * "Module Device"
- * "Processor Device"
- * "3.0 Thermal Model"
- * "3.0 _SCP Extensions"
- * "Processor Aggregator Device"
+ * by the host) should be dynamically modified to VALID by the host via
+ * acpi_install_interface or acpi_update_interfaces. Such optional feature
+ * group strings are set as INVALID by default here.
*/
+
+ {"Module Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+ {"Processor Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+ {"3.0 Thermal Model", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+ {"3.0 _SCP Extensions", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+ {"Processor Aggregator Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}
};
/*******************************************************************************
@@ -158,11 +157,20 @@ acpi_status acpi_ut_interface_terminate(void)
while (next_interface) {
acpi_gbl_supported_interfaces = next_interface->next;
- /* Only interfaces added at runtime can be freed */
-
if (next_interface->flags & ACPI_OSI_DYNAMIC) {
+
+ /* Only interfaces added at runtime can be freed */
+
ACPI_FREE(next_interface->name);
ACPI_FREE(next_interface);
+ } else {
+ /* Interface is in static list. Reset it to invalid or valid. */
+
+ if (next_interface->flags & ACPI_OSI_DEFAULT_INVALID) {
+ next_interface->flags |= ACPI_OSI_INVALID;
+ } else {
+ next_interface->flags &= ~ACPI_OSI_INVALID;
+ }
}
next_interface = acpi_gbl_supported_interfaces;
@@ -278,6 +286,49 @@ acpi_status acpi_ut_remove_interface(acpi_string interface_name)
/*******************************************************************************
*
+ * FUNCTION: acpi_ut_update_interfaces
+ *
+ * PARAMETERS: action - Actions to be performed during the
+ * update
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor
+ * strings or/and feature group strings.
+ * Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_update_interfaces(u8 action)
+{
+ struct acpi_interface_info *next_interface;
+
+ next_interface = acpi_gbl_supported_interfaces;
+ while (next_interface) {
+ if (((next_interface->flags & ACPI_OSI_FEATURE) &&
+ (action & ACPI_FEATURE_STRINGS)) ||
+ (!(next_interface->flags & ACPI_OSI_FEATURE) &&
+ (action & ACPI_VENDOR_STRINGS))) {
+ if (action & ACPI_DISABLE_INTERFACES) {
+
+ /* Mark the interfaces as invalid */
+
+ next_interface->flags |= ACPI_OSI_INVALID;
+ } else {
+ /* Mark the interfaces as valid */
+
+ next_interface->flags &= ~ACPI_OSI_INVALID;
+ }
+ }
+
+ next_interface = next_interface->next;
+ }
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ut_get_interface
*
* PARAMETERS: interface_name - The interface to find
diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c
index c53759b76a3..cb1e9cc32d5 100644
--- a/drivers/acpi/acpica/utstring.c
+++ b/drivers/acpi/acpica/utstring.c
@@ -333,7 +333,8 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
* FUNCTION: acpi_ut_print_string
*
* PARAMETERS: string - Null terminated ASCII string
- * max_length - Maximum output length
+ * max_length - Maximum output length. Used to constrain the
+ * length of strings during debug output only.
*
* RETURN: None
*
@@ -342,7 +343,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
*
******************************************************************************/
-void acpi_ut_print_string(char *string, u8 max_length)
+void acpi_ut_print_string(char *string, u16 max_length)
{
u32 i;
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 6505774f223..03a211e6e26 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -389,6 +389,34 @@ ACPI_EXPORT_SYMBOL(acpi_install_interface_handler)
/*****************************************************************************
*
+ * FUNCTION: acpi_update_interfaces
+ *
+ * PARAMETERS: action - Actions to be performed during the
+ * update
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor
+ * string or/and feature group strings.
+ *
+ ****************************************************************************/
+acpi_status acpi_update_interfaces(u8 action)
+{
+ acpi_status status;
+
+ status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ status = acpi_ut_update_interfaces(action);
+
+ acpi_os_release_mutex(acpi_gbl_osi_mutex);
+ return (status);
+}
+
+/*****************************************************************************
+ *
* FUNCTION: acpi_check_address_range
*
* PARAMETERS: space_id - Address space ID
@@ -402,6 +430,7 @@ ACPI_EXPORT_SYMBOL(acpi_install_interface_handler)
* ASL operation region address ranges.
*
****************************************************************************/
+
u32
acpi_check_address_range(acpi_adr_space_type space_id,
acpi_physical_address address,
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 082b4dd252a..2c9958cd7a4 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -117,6 +117,7 @@ struct acpi_battery {
struct acpi_device *device;
struct notifier_block pm_nb;
unsigned long update_time;
+ int revision;
int rate_now;
int capacity_now;
int voltage_now;
@@ -359,6 +360,7 @@ static struct acpi_offsets info_offsets[] = {
};
static struct acpi_offsets extended_info_offsets[] = {
+ {offsetof(struct acpi_battery, revision), 0},
{offsetof(struct acpi_battery, power_unit), 0},
{offsetof(struct acpi_battery, design_capacity), 0},
{offsetof(struct acpi_battery, full_charge_capacity), 0},
@@ -525,18 +527,14 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
static int acpi_battery_set_alarm(struct acpi_battery *battery)
{
acpi_status status = 0;
- union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER };
- struct acpi_object_list arg_list = { 1, &arg0 };
if (!acpi_battery_present(battery) ||
!test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags))
return -ENODEV;
- arg0.integer.value = battery->alarm;
-
mutex_lock(&battery->lock);
- status = acpi_evaluate_object(battery->device->handle, "_BTP",
- &arg_list, NULL);
+ status = acpi_execute_simple_method(battery->device->handle, "_BTP",
+ battery->alarm);
mutex_unlock(&battery->lock);
if (ACPI_FAILURE(status))
@@ -548,12 +546,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery)
static int acpi_battery_init_alarm(struct acpi_battery *battery)
{
- acpi_status status = AE_OK;
- acpi_handle handle = NULL;
-
/* See if alarms are supported, and if so, set default */
- status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
- if (ACPI_FAILURE(status)) {
+ if (!acpi_has_method(battery->device->handle, "_BTP")) {
clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);
return 0;
}
@@ -1034,8 +1028,6 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
if (event == ACPI_BATTERY_NOTIFY_INFO)
acpi_battery_refresh(battery);
acpi_battery_update(battery);
- acpi_bus_generate_proc_event(device, event,
- acpi_battery_present(battery));
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
acpi_battery_present(battery));
@@ -1066,7 +1058,7 @@ static int acpi_battery_add(struct acpi_device *device)
{
int result = 0;
struct acpi_battery *battery = NULL;
- acpi_handle handle;
+
if (!device)
return -EINVAL;
battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
@@ -1078,8 +1070,7 @@ static int acpi_battery_add(struct acpi_device *device)
device->driver_data = battery;
mutex_init(&battery->lock);
mutex_init(&battery->sysfs_lock);
- if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle,
- "_BIX", &handle)))
+ if (acpi_has_method(battery->device->handle, "_BIX"))
set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
result = acpi_battery_update(battery);
if (result)
diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c
index be603995854..a83e3c62c5a 100644
--- a/drivers/acpi/bgrt.c
+++ b/drivers/acpi/bgrt.c
@@ -51,20 +51,14 @@ static ssize_t show_yoffset(struct device *dev,
}
static DEVICE_ATTR(yoffset, S_IRUGO, show_yoffset, NULL);
-static ssize_t show_image(struct file *file, struct kobject *kobj,
+static ssize_t image_read(struct file *file, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off, size_t count)
{
memcpy(buf, attr->private + off, count);
return count;
}
-static struct bin_attribute image_attr = {
- .attr = {
- .name = "image",
- .mode = S_IRUGO,
- },
- .read = show_image,
-};
+static BIN_ATTR_RO(image, 0); /* size gets filled in later */
static struct attribute *bgrt_attributes[] = {
&dev_attr_version.attr,
@@ -75,8 +69,14 @@ static struct attribute *bgrt_attributes[] = {
NULL,
};
+static struct bin_attribute *bgrt_bin_attributes[] = {
+ &bin_attr_image,
+ NULL,
+};
+
static struct attribute_group bgrt_attribute_group = {
.attrs = bgrt_attributes,
+ .bin_attrs = bgrt_bin_attributes,
};
static int __init bgrt_init(void)
@@ -86,9 +86,8 @@ static int __init bgrt_init(void)
if (!bgrt_image)
return -ENODEV;
- sysfs_bin_attr_init(&image_attr);
- image_attr.private = bgrt_image;
- image_attr.size = bgrt_image_size;
+ bin_attr_image.private = bgrt_image;
+ bin_attr_image.size = bgrt_image_size;
bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj);
if (!bgrt_kobj)
@@ -98,14 +97,8 @@ static int __init bgrt_init(void)
if (ret)
goto out_kobject;
- ret = sysfs_create_bin_file(bgrt_kobj, &image_attr);
- if (ret)
- goto out_group;
-
return 0;
-out_group:
- sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group);
out_kobject:
kobject_put(bgrt_kobj);
return ret;
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index cb9629638de..9515f18898b 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -192,6 +192,12 @@ static int __init dmi_disable_osi_win7(const struct dmi_system_id *d)
acpi_osi_setup("!Windows 2009");
return 0;
}
+static int __init dmi_disable_osi_win8(const struct dmi_system_id *d)
+{
+ printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
+ acpi_osi_setup("!Windows 2012");
+ return 0;
+}
static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
{
@@ -267,6 +273,30 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P305D"),
},
},
+ {
+ .callback = dmi_disable_osi_win8,
+ .ident = "ASUS Zenbook Prime UX31A",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "UX31A"),
+ },
+ },
+ {
+ .callback = dmi_disable_osi_win8,
+ .ident = "Dell Inspiron 15R SE",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"),
+ },
+ },
+ {
+ .callback = dmi_disable_osi_win8,
+ .ident = "Lenovo ThinkPad Edge E530",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "3259A2G"),
+ },
+ },
/*
* BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a5bb33bab44..b587ec8257b 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -89,27 +89,6 @@ static struct dmi_system_id dsdt_dmi_table[] __initdata = {
Device Management
-------------------------------------------------------------------------- */
-int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
-{
- acpi_status status;
-
- if (!device)
- return -EINVAL;
-
- /* TBD: Support fixed-feature devices */
-
- status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
- if (ACPI_FAILURE(status) || !*device) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
- handle));
- return -ENODEV;
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL(acpi_bus_get_device);
-
acpi_status acpi_bus_get_status_handle(acpi_handle handle,
unsigned long long *sta)
{
@@ -346,104 +325,6 @@ static void acpi_bus_osc_support(void)
}
/* --------------------------------------------------------------------------
- Event Management
- -------------------------------------------------------------------------- */
-
-#ifdef CONFIG_ACPI_PROC_EVENT
-static DEFINE_SPINLOCK(acpi_bus_event_lock);
-
-LIST_HEAD(acpi_bus_event_list);
-DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);
-
-extern int event_is_open;
-
-int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
-{
- struct acpi_bus_event *event;
- unsigned long flags;
-
- /* drop event on the floor if no one's listening */
- if (!event_is_open)
- return 0;
-
- event = kzalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
- if (!event)
- return -ENOMEM;
-
- strcpy(event->device_class, device_class);
- strcpy(event->bus_id, bus_id);
- event->type = type;
- event->data = data;
-
- spin_lock_irqsave(&acpi_bus_event_lock, flags);
- list_add_tail(&event->node, &acpi_bus_event_list);
- spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
-
- wake_up_interruptible(&acpi_bus_event_queue);
-
- return 0;
-
-}
-
-EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4);
-
-int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
-{
- if (!device)
- return -EINVAL;
- return acpi_bus_generate_proc_event4(device->pnp.device_class,
- device->pnp.bus_id, type, data);
-}
-
-EXPORT_SYMBOL(acpi_bus_generate_proc_event);
-
-int acpi_bus_receive_event(struct acpi_bus_event *event)
-{
- unsigned long flags;
- struct acpi_bus_event *entry = NULL;
-
- DECLARE_WAITQUEUE(wait, current);
-
-
- if (!event)
- return -EINVAL;
-
- if (list_empty(&acpi_bus_event_list)) {
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&acpi_bus_event_queue, &wait);
-
- if (list_empty(&acpi_bus_event_list))
- schedule();
-
- remove_wait_queue(&acpi_bus_event_queue, &wait);
- set_current_state(TASK_RUNNING);
-
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
-
- spin_lock_irqsave(&acpi_bus_event_lock, flags);
- if (!list_empty(&acpi_bus_event_list)) {
- entry = list_entry(acpi_bus_event_list.next,
- struct acpi_bus_event, node);
- list_del(&entry->node);
- }
- spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
-
- if (!entry)
- return -ENODEV;
-
- memcpy(event, entry, sizeof(struct acpi_bus_event));
-
- kfree(entry);
-
- return 0;
-}
-
-#endif /* CONFIG_ACPI_PROC_EVENT */
-
-/* --------------------------------------------------------------------------
Notification Handling
-------------------------------------------------------------------------- */
@@ -499,19 +380,6 @@ static void acpi_bus_check_scope(acpi_handle handle)
*/
}
-static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
-int register_acpi_bus_notifier(struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
-
-void unregister_acpi_bus_notifier(struct notifier_block *nb)
-{
- blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
-
/**
* acpi_bus_notify
* ---------------
@@ -525,9 +393,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
type, handle));
- blocking_notifier_call_chain(&acpi_bus_notify_list,
- type, (void *)handle);
-
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
@@ -593,8 +458,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
static int __init acpi_bus_init_irq(void)
{
acpi_status status;
- union acpi_object arg = { ACPI_TYPE_INTEGER };
- struct acpi_object_list arg_list = { 1, &arg };
char *message = NULL;
@@ -623,9 +486,7 @@ static int __init acpi_bus_init_irq(void)
printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);
- arg.integer.value = acpi_irq_model;
-
- status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
+ status = acpi_execute_simple_method(NULL, "\\_PIC", acpi_irq_model);
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
return -ENODEV;
@@ -715,7 +576,6 @@ static int __init acpi_bus_init(void)
{
int result;
acpi_status status;
- extern acpi_status acpi_os_initialize1(void);
acpi_os_initialize1();
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index d2e617b5b3f..a55773801c5 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -303,8 +303,6 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
pm_wakeup_event(&device->dev, 0);
}
-
- acpi_bus_generate_proc_event(device, event, ++button->pushed);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 4ab807dc851..59d3202f6b3 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -159,26 +159,29 @@ int acpi_device_set_power(struct acpi_device *device, int state)
int result = 0;
bool cut_power = false;
- if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
+ if (!device || !device->flags.power_manageable
+ || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
return -EINVAL;
/* Make sure this is a valid target state */
if (state == device->power.state) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n",
+ device->pnp.bus_id,
acpi_power_state_string(state)));
return 0;
}
if (!device->power.states[state].flags.valid) {
- printk(KERN_WARNING PREFIX "Device does not support %s\n",
- acpi_power_state_string(state));
+ dev_warn(&device->dev, "Power state %s not supported\n",
+ acpi_power_state_string(state));
return -ENODEV;
}
if (device->parent && (state < device->parent->power.state)) {
- printk(KERN_WARNING PREFIX
- "Cannot set device to a higher-powered"
- " state than parent\n");
+ dev_warn(&device->dev,
+ "Cannot transition to power state %s for parent in %s\n",
+ acpi_power_state_string(state),
+ acpi_power_state_string(device->parent->power.state));
return -ENODEV;
}
@@ -191,8 +194,8 @@ int acpi_device_set_power(struct acpi_device *device, int state)
if (state < device->power.state && state != ACPI_STATE_D0
&& device->power.state >= ACPI_STATE_D3_HOT) {
- printk(KERN_WARNING PREFIX
- "Cannot transition to non-D0 state from D3\n");
+ dev_warn(&device->dev,
+ "Cannot transition to non-D0 state from D3\n");
return -ENODEV;
}
@@ -219,10 +222,8 @@ int acpi_device_set_power(struct acpi_device *device, int state)
end:
if (result) {
- printk(KERN_WARNING PREFIX
- "Device [%s] failed to transition to %s\n",
- device->pnp.bus_id,
- acpi_power_state_string(state));
+ dev_warn(&device->dev, "Failed to change power state to %s\n",
+ acpi_power_state_string(state));
} else {
device->power.state = state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -244,13 +245,6 @@ int acpi_bus_set_power(acpi_handle handle, int state)
if (result)
return result;
- if (!device->flags.power_manageable) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Device [%s] is not power manageable\n",
- dev_name(&device->dev)));
- return -ENODEV;
- }
-
return acpi_device_set_power(device, state);
}
EXPORT_SYMBOL(acpi_bus_set_power);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 82656075338..05ea4be01a8 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -51,8 +51,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
" the driver to wait for userspace to write the undock sysfs file "
" before undocking");
-static struct atomic_notifier_head dock_notifier_list;
-
static const struct acpi_device_id dock_device_ids[] = {
{"LNXDOCK", 0},
{"", 0},
@@ -63,8 +61,6 @@ struct dock_station {
acpi_handle handle;
unsigned long last_dock_time;
u32 flags;
- spinlock_t dd_lock;
- struct mutex hp_lock;
struct list_head dependent_devices;
struct list_head sibling;
@@ -91,6 +87,12 @@ struct dock_dependent_device {
#define DOCK_EVENT 3
#define UNDOCK_EVENT 2
+enum dock_callback_type {
+ DOCK_CALL_HANDLER,
+ DOCK_CALL_FIXUP,
+ DOCK_CALL_UEVENT,
+};
+
/*****************************************************************************
* Dock Dependent device functions *
*****************************************************************************/
@@ -101,7 +103,7 @@ struct dock_dependent_device {
*
* Add the dependent device to the dock's dependent device list.
*/
-static int
+static int __init
add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
{
struct dock_dependent_device *dd;
@@ -112,14 +114,21 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
dd->handle = handle;
INIT_LIST_HEAD(&dd->list);
-
- spin_lock(&ds->dd_lock);
list_add_tail(&dd->list, &ds->dependent_devices);
- spin_unlock(&ds->dd_lock);
return 0;
}
+static void remove_dock_dependent_devices(struct dock_station *ds)
+{
+ struct dock_dependent_device *dd, *aux;
+
+ list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) {
+ list_del(&dd->list);
+ kfree(dd);
+ }
+}
+
/**
* dock_init_hotplug - Initialize a hotplug device on a docking station.
* @dd: Dock-dependent device.
@@ -135,19 +144,16 @@ static int dock_init_hotplug(struct dock_dependent_device *dd,
int ret = 0;
mutex_lock(&hotplug_lock);
-
- if (dd->hp_context) {
+ if (WARN_ON(dd->hp_context)) {
ret = -EEXIST;
} else {
dd->hp_refcount = 1;
dd->hp_ops = ops;
dd->hp_context = context;
dd->hp_release = release;
+ if (init)
+ init(context);
}
-
- if (!WARN_ON(ret) && init)
- init(context);
-
mutex_unlock(&hotplug_lock);
return ret;
}
@@ -162,27 +168,22 @@ static int dock_init_hotplug(struct dock_dependent_device *dd,
*/
static void dock_release_hotplug(struct dock_dependent_device *dd)
{
- void (*release)(void *) = NULL;
- void *context = NULL;
-
mutex_lock(&hotplug_lock);
-
if (dd->hp_context && !--dd->hp_refcount) {
+ void (*release)(void *) = dd->hp_release;
+ void *context = dd->hp_context;
+
dd->hp_ops = NULL;
- context = dd->hp_context;
dd->hp_context = NULL;
- release = dd->hp_release;
dd->hp_release = NULL;
+ if (release)
+ release(context);
}
-
- if (release && context)
- release(context);
-
mutex_unlock(&hotplug_lock);
}
static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
- bool uevent)
+ enum dock_callback_type cb_type)
{
acpi_notify_handler cb = NULL;
bool run = false;
@@ -192,8 +193,18 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
if (dd->hp_context) {
run = true;
dd->hp_refcount++;
- if (dd->hp_ops)
- cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler;
+ if (dd->hp_ops) {
+ switch (cb_type) {
+ case DOCK_CALL_FIXUP:
+ cb = dd->hp_ops->fixup;
+ break;
+ case DOCK_CALL_UEVENT:
+ cb = dd->hp_ops->uevent;
+ break;
+ default:
+ cb = dd->hp_ops->handler;
+ }
+ }
}
mutex_unlock(&hotplug_lock);
@@ -220,63 +231,17 @@ find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
{
struct dock_dependent_device *dd;
- spin_lock(&ds->dd_lock);
- list_for_each_entry(dd, &ds->dependent_devices, list) {
- if (handle == dd->handle) {
- spin_unlock(&ds->dd_lock);
+ list_for_each_entry(dd, &ds->dependent_devices, list)
+ if (handle == dd->handle)
return dd;
- }
- }
- spin_unlock(&ds->dd_lock);
+
return NULL;
}
/*****************************************************************************
* Dock functions *
*****************************************************************************/
-/**
- * is_dock - see if a device is a dock station
- * @handle: acpi handle of the device
- *
- * If an acpi object has a _DCK method, then it is by definition a dock
- * station, so return true.
- */
-static int is_dock(acpi_handle handle)
-{
- acpi_status status;
- acpi_handle tmp;
-
- status = acpi_get_handle(handle, "_DCK", &tmp);
- if (ACPI_FAILURE(status))
- return 0;
- return 1;
-}
-
-static int is_ejectable(acpi_handle handle)
-{
- acpi_status status;
- acpi_handle tmp;
-
- status = acpi_get_handle(handle, "_EJ0", &tmp);
- if (ACPI_FAILURE(status))
- return 0;
- return 1;
-}
-
-static int is_ata(acpi_handle handle)
-{
- acpi_handle tmp;
-
- if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
- return 1;
-
- return 0;
-}
-
-static int is_battery(acpi_handle handle)
+static int __init is_battery(acpi_handle handle)
{
struct acpi_device_info *info;
int ret = 1;
@@ -292,17 +257,13 @@ static int is_battery(acpi_handle handle)
return ret;
}
-static int is_ejectable_bay(acpi_handle handle)
+/* Check whether ACPI object is an ejectable battery or disk bay */
+static bool __init is_ejectable_bay(acpi_handle handle)
{
- acpi_handle phandle;
+ if (acpi_has_method(handle, "_EJ0") && is_battery(handle))
+ return true;
- if (!is_ejectable(handle))
- return 0;
- if (is_battery(handle) || is_ata(handle))
- return 1;
- if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
- return 1;
- return 0;
+ return acpi_bay_match(handle);
}
/**
@@ -320,7 +281,7 @@ int is_dock_device(acpi_handle handle)
if (!dock_station_count)
return 0;
- if (is_dock(handle))
+ if (acpi_dock_match(handle))
return 1;
list_for_each_entry(dock_station, &dock_stations, sibling)
@@ -359,10 +320,8 @@ static int dock_present(struct dock_station *ds)
* handle if one does not exist already. This should cause
* acpi to scan for drivers for the given devices, and call
* matching driver's add routine.
- *
- * Returns a pointer to the acpi_device corresponding to the handle.
*/
-static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
+static void dock_create_acpi_device(acpi_handle handle)
{
struct acpi_device *device;
int ret;
@@ -375,10 +334,7 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
ret = acpi_bus_scan(handle);
if (ret)
pr_debug("error adding bus, %x\n", -ret);
-
- acpi_bus_get_device(handle, &device);
}
- return device;
}
/**
@@ -397,9 +353,29 @@ static void dock_remove_acpi_device(acpi_handle handle)
}
/**
- * hotplug_dock_devices - insert or remove devices on the dock station
+ * hot_remove_dock_devices - Remove dock station devices.
+ * @ds: Dock station.
+ */
+static void hot_remove_dock_devices(struct dock_station *ds)
+{
+ struct dock_dependent_device *dd;
+
+ /*
+ * Walk the list in reverse order so that devices that have been added
+ * last are removed first (in case there are some indirect dependencies
+ * between them).
+ */
+ list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
+ dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false);
+
+ list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
+ dock_remove_acpi_device(dd->handle);
+}
+
+/**
+ * hotplug_dock_devices - Insert devices on a dock station.
* @ds: the dock station
- * @event: either bus check or eject request
+ * @event: either bus check or device check request
*
* Some devices on the dock station need to have drivers called
* to perform hotplug operations after a dock event has occurred.
@@ -410,27 +386,21 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
{
struct dock_dependent_device *dd;
- mutex_lock(&ds->hp_lock);
+ /* Call driver specific post-dock fixups. */
+ list_for_each_entry(dd, &ds->dependent_devices, list)
+ dock_hotplug_event(dd, event, DOCK_CALL_FIXUP);
- /*
- * First call driver specific hotplug functions
- */
+ /* Call driver specific hotplug functions. */
list_for_each_entry(dd, &ds->dependent_devices, list)
- dock_hotplug_event(dd, event, false);
+ dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
/*
- * Now make sure that an acpi_device is created for each
- * dependent device, or removed if this is an eject request.
- * This will cause acpi_drivers to be stopped/started if they
- * exist
+ * Now make sure that an acpi_device is created for each dependent
+ * device. That will cause scan handlers to be attached to device
+ * objects or acpi_drivers to be stopped/started if they are present.
*/
- list_for_each_entry(dd, &ds->dependent_devices, list) {
- if (event == ACPI_NOTIFY_EJECT_REQUEST)
- dock_remove_acpi_device(dd->handle);
- else
- dock_create_acpi_device(dd->handle);
- }
- mutex_unlock(&ds->hp_lock);
+ list_for_each_entry(dd, &ds->dependent_devices, list)
+ dock_create_acpi_device(dd->handle);
}
static void dock_event(struct dock_station *ds, u32 event, int num)
@@ -453,44 +423,13 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
list_for_each_entry(dd, &ds->dependent_devices, list)
- dock_hotplug_event(dd, event, true);
+ dock_hotplug_event(dd, event, DOCK_CALL_UEVENT);
if (num != DOCK_EVENT)
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
}
/**
- * eject_dock - respond to a dock eject request
- * @ds: the dock station
- *
- * This is called after _DCK is called, to execute the dock station's
- * _EJ0 method.
- */
-static void eject_dock(struct dock_station *ds)
-{
- struct acpi_object_list arg_list;
- union acpi_object arg;
- acpi_status status;
- acpi_handle tmp;
-
- /* all dock devices should have _EJ0, but check anyway */
- status = acpi_get_handle(ds->handle, "_EJ0", &tmp);
- if (ACPI_FAILURE(status)) {
- pr_debug("No _EJ0 support for dock device\n");
- return;
- }
-
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 1;
-
- status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL);
- if (ACPI_FAILURE(status))
- pr_debug("Failed to evaluate _EJ0!\n");
-}
-
-/**
* handle_dock - handle a dock event
* @ds: the dock station
* @dock: to dock, or undock - that is the question
@@ -550,27 +489,6 @@ static inline void complete_undock(struct dock_station *ds)
ds->flags &= ~(DOCK_UNDOCKING);
}
-static void dock_lock(struct dock_station *ds, int lock)
-{
- struct acpi_object_list arg_list;
- union acpi_object arg;
- acpi_status status;
-
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = !!lock;
- status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
- if (lock)
- acpi_handle_warn(ds->handle,
- "Locking device failed (0x%x)\n", status);
- else
- acpi_handle_warn(ds->handle,
- "Unlocking device failed (0x%x)\n", status);
- }
-}
-
/**
* dock_in_progress - see if we are in the middle of handling a dock event
* @ds: the dock station
@@ -588,37 +506,6 @@ static int dock_in_progress(struct dock_station *ds)
}
/**
- * register_dock_notifier - add yourself to the dock notifier list
- * @nb: the callers notifier block
- *
- * If a driver wishes to be notified about dock events, they can
- * use this function to put a notifier block on the dock notifier list.
- * this notifier call chain will be called after a dock event, but
- * before hotplugging any new devices.
- */
-int register_dock_notifier(struct notifier_block *nb)
-{
- if (!dock_station_count)
- return -ENODEV;
-
- return atomic_notifier_chain_register(&dock_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_dock_notifier);
-
-/**
- * unregister_dock_notifier - remove yourself from the dock notifier list
- * @nb: the callers notifier block
- */
-void unregister_dock_notifier(struct notifier_block *nb)
-{
- if (!dock_station_count)
- return;
-
- atomic_notifier_chain_unregister(&dock_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_dock_notifier);
-
-/**
* register_hotplug_dock_device - register a hotplug function
* @handle: the handle of the device
* @ops: handlers to call after docking
@@ -703,10 +590,10 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
*/
dock_event(ds, event, UNDOCK_EVENT);
- hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
+ hot_remove_dock_devices(ds);
undock(ds);
- dock_lock(ds, 0);
- eject_dock(ds);
+ acpi_evaluate_lck(ds->handle, 0);
+ acpi_evaluate_ej0(ds->handle);
if (dock_present(ds)) {
acpi_handle_err(ds->handle, "Unable to undock!\n");
return -EBUSY;
@@ -717,18 +604,17 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
/**
* dock_notify - act upon an acpi dock notification
- * @handle: the dock station handle
+ * @ds: dock station
* @event: the acpi event
- * @data: our driver data struct
*
* If we are notified to dock, then check to see if the dock is
* present and then dock. Notify all drivers of the dock event,
* and then hotplug and devices that may need hotplugging.
*/
-static void dock_notify(acpi_handle handle, u32 event, void *data)
+static void dock_notify(struct dock_station *ds, u32 event)
{
- struct dock_station *ds = data;
- struct acpi_device *tmp;
+ acpi_handle handle = ds->handle;
+ struct acpi_device *ad;
int surprise_removal = 0;
/*
@@ -751,8 +637,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
- if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
- &tmp)) {
+ if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) {
begin_dock(ds);
dock(ds);
if (!dock_present(ds)) {
@@ -760,12 +645,10 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
complete_dock(ds);
break;
}
- atomic_notifier_call_chain(&dock_notifier_list,
- event, NULL);
hotplug_dock_devices(ds, event);
complete_dock(ds);
dock_event(ds, event, DOCK_EVENT);
- dock_lock(ds, 1);
+ acpi_evaluate_lck(ds->handle, 1);
acpi_update_all_gpes();
break;
}
@@ -789,9 +672,8 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
}
struct dock_data {
- acpi_handle handle;
- unsigned long event;
struct dock_station *ds;
+ u32 event;
};
static void acpi_dock_deferred_cb(void *context)
@@ -799,52 +681,31 @@ static void acpi_dock_deferred_cb(void *context)
struct dock_data *data = context;
acpi_scan_lock_acquire();
- dock_notify(data->handle, data->event, data->ds);
+ dock_notify(data->ds, data->event);
acpi_scan_lock_release();
kfree(data);
}
-static int acpi_dock_notifier_call(struct notifier_block *this,
- unsigned long event, void *data)
+static void dock_notify_handler(acpi_handle handle, u32 event, void *data)
{
- struct dock_station *dock_station;
- acpi_handle handle = data;
+ struct dock_data *dd;
if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
&& event != ACPI_NOTIFY_EJECT_REQUEST)
- return 0;
-
- acpi_scan_lock_acquire();
-
- list_for_each_entry(dock_station, &dock_stations, sibling) {
- if (dock_station->handle == handle) {
- struct dock_data *dd;
- acpi_status status;
-
- dd = kmalloc(sizeof(*dd), GFP_KERNEL);
- if (!dd)
- break;
+ return;
- dd->handle = handle;
- dd->event = event;
- dd->ds = dock_station;
- status = acpi_os_hotplug_execute(acpi_dock_deferred_cb,
- dd);
- if (ACPI_FAILURE(status))
- kfree(dd);
+ dd = kmalloc(sizeof(*dd), GFP_KERNEL);
+ if (dd) {
+ acpi_status status;
- break;
- }
+ dd->ds = data;
+ dd->event = event;
+ status = acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
+ if (ACPI_FAILURE(status))
+ kfree(dd);
}
-
- acpi_scan_lock_release();
- return 0;
}
-static struct notifier_block dock_acpi_notifier = {
- .notifier_call = acpi_dock_notifier_call,
-};
-
/**
* find_dock_devices - find devices on the dock station
* @handle: the handle of the device we are examining
@@ -856,29 +717,16 @@ static struct notifier_block dock_acpi_notifier = {
* check to see if an object has an _EJD method. If it does, then it
* will see if it is dependent on the dock station.
*/
-static acpi_status
-find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
+static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
{
- acpi_status status;
- acpi_handle tmp, parent;
struct dock_station *ds = context;
+ acpi_handle ejd = NULL;
- status = acpi_bus_get_ejd(handle, &tmp);
- if (ACPI_FAILURE(status)) {
- /* try the parent device as well */
- status = acpi_get_parent(handle, &parent);
- if (ACPI_FAILURE(status))
- goto fdd_out;
- /* see if parent is dependent on dock */
- status = acpi_bus_get_ejd(parent, &tmp);
- if (ACPI_FAILURE(status))
- goto fdd_out;
- }
-
- if (tmp == ds->handle)
+ acpi_bus_get_ejd(handle, &ejd);
+ if (ejd == ds->handle)
add_dock_dependent_device(ds, handle);
-fdd_out:
return AE_OK;
}
@@ -988,13 +836,13 @@ static struct attribute_group dock_attribute_group = {
*/
static int __init dock_add(acpi_handle handle)
{
- int ret, id;
- struct dock_station ds, *dock_station;
+ struct dock_station *dock_station, ds = { NULL, };
struct platform_device *dd;
+ acpi_status status;
+ int ret;
- id = dock_station_count;
- memset(&ds, 0, sizeof(ds));
- dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds));
+ dd = platform_device_register_data(NULL, "dock", dock_station_count,
+ &ds, sizeof(ds));
if (IS_ERR(dd))
return PTR_ERR(dd);
@@ -1004,18 +852,15 @@ static int __init dock_add(acpi_handle handle)
dock_station->dock_device = dd;
dock_station->last_dock_time = jiffies - HZ;
- mutex_init(&dock_station->hp_lock);
- spin_lock_init(&dock_station->dd_lock);
INIT_LIST_HEAD(&dock_station->sibling);
- ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
INIT_LIST_HEAD(&dock_station->dependent_devices);
/* we want the dock device to send uevents */
dev_set_uevent_suppress(&dd->dev, 0);
- if (is_dock(handle))
+ if (acpi_dock_match(handle))
dock_station->flags |= DOCK_IS_DOCK;
- if (is_ata(handle))
+ if (acpi_ata_match(handle))
dock_station->flags |= DOCK_IS_ATA;
if (is_battery(handle))
dock_station->flags |= DOCK_IS_BAT;
@@ -1034,11 +879,19 @@ static int __init dock_add(acpi_handle handle)
if (ret)
goto err_rmgroup;
+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ dock_notify_handler, dock_station);
+ if (ACPI_FAILURE(status)) {
+ ret = -ENODEV;
+ goto err_rmgroup;
+ }
+
dock_station_count++;
list_add(&dock_station->sibling, &dock_stations);
return 0;
err_rmgroup:
+ remove_dock_dependent_devices(dock_station);
sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
err_unregister:
platform_device_unregister(dd);
@@ -1055,10 +908,10 @@ err_unregister:
*
* This is called by acpi_walk_namespace to look for dock stations and bays.
*/
-static __init acpi_status
+static acpi_status __init
find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
{
- if (is_dock(handle) || is_ejectable_bay(handle))
+ if (acpi_dock_match(handle) || is_ejectable_bay(handle))
dock_add(handle);
return AE_OK;
@@ -1078,7 +931,6 @@ void __init acpi_dock_init(void)
return;
}
- register_acpi_bus_notifier(&dock_acpi_notifier);
pr_info(PREFIX "%s: %d docks/bays found\n",
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 80403c1a89f..a06d9837470 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -948,7 +948,7 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
return 0;
}
-static struct dmi_system_id __initdata ec_dmi_table[] = {
+static struct dmi_system_id ec_dmi_table[] __initdata = {
{
ec_skip_dsdt_scan, "Compal JFL92", {
DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
@@ -987,6 +987,10 @@ static struct dmi_system_id __initdata ec_dmi_table[] = {
ec_skip_dsdt_scan, "HP Folio 13", {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13"),}, NULL},
+ {
+ ec_validate_ecdt, "ASUS hardware", {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
{},
};
@@ -1049,10 +1053,8 @@ int __init acpi_ec_ecdt_probe(void)
* which needs it, has fake EC._INI method, so use it as flag.
* Keep boot_ec struct as it will be needed soon.
*/
- acpi_handle dummy;
if (!dmi_name_in_vendors("ASUS") ||
- ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI",
- &dummy)))
+ !acpi_has_method(boot_ec->handle, "_INI"))
return -ENODEV;
}
install:
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 1442737cede..8247fcdde07 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -21,100 +21,6 @@
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("event");
-#ifdef CONFIG_ACPI_PROC_EVENT
-/* Global vars for handling event proc entry */
-static DEFINE_SPINLOCK(acpi_system_event_lock);
-int event_is_open = 0;
-extern struct list_head acpi_bus_event_list;
-extern wait_queue_head_t acpi_bus_event_queue;
-
-static int acpi_system_open_event(struct inode *inode, struct file *file)
-{
- spin_lock_irq(&acpi_system_event_lock);
-
- if (event_is_open)
- goto out_busy;
-
- event_is_open = 1;
-
- spin_unlock_irq(&acpi_system_event_lock);
- return 0;
-
- out_busy:
- spin_unlock_irq(&acpi_system_event_lock);
- return -EBUSY;
-}
-
-static ssize_t
-acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
- loff_t * ppos)
-{
- int result = 0;
- struct acpi_bus_event event;
- static char str[ACPI_MAX_STRING];
- static int chars_remaining = 0;
- static char *ptr;
-
- if (!chars_remaining) {
- memset(&event, 0, sizeof(struct acpi_bus_event));
-
- if ((file->f_flags & O_NONBLOCK)
- && (list_empty(&acpi_bus_event_list)))
- return -EAGAIN;
-
- result = acpi_bus_receive_event(&event);
- if (result)
- return result;
-
- chars_remaining = sprintf(str, "%s %s %08x %08x\n",
- event.device_class ? event.
- device_class : "<unknown>",
- event.bus_id ? event.
- bus_id : "<unknown>", event.type,
- event.data);
- ptr = str;
- }
-
- if (chars_remaining < count) {
- count = chars_remaining;
- }
-
- if (copy_to_user(buffer, ptr, count))
- return -EFAULT;
-
- *ppos += count;
- chars_remaining -= count;
- ptr += count;
-
- return count;
-}
-
-static int acpi_system_close_event(struct inode *inode, struct file *file)
-{
- spin_lock_irq(&acpi_system_event_lock);
- event_is_open = 0;
- spin_unlock_irq(&acpi_system_event_lock);
- return 0;
-}
-
-static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
-{
- poll_wait(file, &acpi_bus_event_queue, wait);
- if (!list_empty(&acpi_bus_event_list))
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-static const struct file_operations acpi_system_event_ops = {
- .owner = THIS_MODULE,
- .open = acpi_system_open_event,
- .read = acpi_system_read_event,
- .release = acpi_system_close_event,
- .poll = acpi_system_poll_event,
- .llseek = default_llseek,
-};
-#endif /* CONFIG_ACPI_PROC_EVENT */
-
/* ACPI notifier chain */
static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
@@ -280,9 +186,6 @@ static int acpi_event_genetlink_init(void)
static int __init acpi_event_init(void)
{
-#ifdef CONFIG_ACPI_PROC_EVENT
- struct proc_dir_entry *entry;
-#endif
int error = 0;
if (acpi_disabled)
@@ -293,15 +196,6 @@ static int __init acpi_event_init(void)
if (error)
printk(KERN_WARNING PREFIX
"Failed to create genetlink family for ACPI event\n");
-
-#ifdef CONFIG_ACPI_PROC_EVENT
- /* 'event' [R] */
- entry = proc_create("event", S_IRUSR, acpi_root_dir,
- &acpi_system_event_ops);
- if (!entry)
- return -ENODEV;
-#endif
-
return 0;
}
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 5b02a0aa540..41ade6570bc 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -93,7 +93,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
if (result)
return result;
- *state = (acpi_state == ACPI_STATE_D3 ? 0 :
+ *state = (acpi_state == ACPI_STATE_D3_COLD ? 0 :
(acpi_state == ACPI_STATE_D0 ? 1 : -1));
return 0;
}
@@ -108,7 +108,7 @@ fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
return -EINVAL;
result = acpi_bus_set_power(device->handle,
- state ? ACPI_STATE_D0 : ACPI_STATE_D3);
+ state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
return result;
}
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index f68095756fb..94672297e1b 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -31,6 +31,7 @@ static LIST_HEAD(bus_type_list);
static DECLARE_RWSEM(bus_type_sem);
#define PHYSICAL_NODE_STRING "physical_node"
+#define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10)
int register_acpi_bus_type(struct acpi_bus_type *type)
{
@@ -78,41 +79,117 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
return ret;
}
-static acpi_status do_acpi_find_child(acpi_handle handle, u32 lvl_not_used,
- void *addr_p, void **ret_p)
+static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
+ void *not_used, void **ret_p)
{
- unsigned long long addr, sta;
+ struct acpi_device *adev = NULL;
+
+ acpi_bus_get_device(handle, &adev);
+ if (adev) {
+ *ret_p = handle;
+ return AE_CTRL_TERMINATE;
+ }
+ return AE_OK;
+}
+
+static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge)
+{
+ unsigned long long sta;
+ acpi_status status;
+
+ status = acpi_bus_get_status_handle(handle, &sta);
+ if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
+ return false;
+
+ if (is_bridge) {
+ void *test = NULL;
+
+ /* Check if this object has at least one child device. */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ acpi_dev_present, NULL, NULL, &test);
+ return !!test;
+ }
+ return true;
+}
+
+struct find_child_context {
+ u64 addr;
+ bool is_bridge;
+ acpi_handle ret;
+ bool ret_checked;
+};
+
+static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
+ void *data, void **not_used)
+{
+ struct find_child_context *context = data;
+ unsigned long long addr;
acpi_status status;
status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
- if (ACPI_SUCCESS(status) && addr == *((u64 *)addr_p)) {
- *ret_p = handle;
- status = acpi_bus_get_status_handle(handle, &sta);
- if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_ENABLED))
+ if (ACPI_FAILURE(status) || addr != context->addr)
+ return AE_OK;
+
+ if (!context->ret) {
+ /* This is the first matching object. Save its handle. */
+ context->ret = handle;
+ return AE_OK;
+ }
+ /*
+ * There is more than one matching object with the same _ADR value.
+ * That really is unexpected, so we are kind of beyond the scope of the
+ * spec here. We have to choose which one to return, though.
+ *
+ * First, check if the previously found object is good enough and return
+ * its handle if so. Second, check the same for the object that we've
+ * just found.
+ */
+ if (!context->ret_checked) {
+ if (acpi_extra_checks_passed(context->ret, context->is_bridge))
return AE_CTRL_TERMINATE;
+ else
+ context->ret_checked = true;
+ }
+ if (acpi_extra_checks_passed(handle, context->is_bridge)) {
+ context->ret = handle;
+ return AE_CTRL_TERMINATE;
}
return AE_OK;
}
-acpi_handle acpi_get_child(acpi_handle parent, u64 address)
+acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge)
{
- void *ret = NULL;
-
- if (!parent)
- return NULL;
+ if (parent) {
+ struct find_child_context context = {
+ .addr = addr,
+ .is_bridge = is_bridge,
+ };
+
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, do_find_child,
+ NULL, &context, NULL);
+ return context.ret;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(acpi_find_child);
- acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, NULL,
- do_acpi_find_child, &address, &ret);
- return (acpi_handle)ret;
+static void acpi_physnode_link_name(char *buf, unsigned int node_id)
+{
+ if (node_id > 0)
+ snprintf(buf, PHYSICAL_NODE_NAME_SIZE,
+ PHYSICAL_NODE_STRING "%u", node_id);
+ else
+ strcpy(buf, PHYSICAL_NODE_STRING);
}
-EXPORT_SYMBOL(acpi_get_child);
int acpi_bind_one(struct device *dev, acpi_handle handle)
{
struct acpi_device *acpi_dev;
acpi_status status;
struct acpi_device_physical_node *physical_node, *pn;
- char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
+ char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
+ struct list_head *physnode_list;
+ unsigned int node_id;
int retval = -EINVAL;
if (ACPI_HANDLE(dev)) {
@@ -139,41 +216,53 @@ int acpi_bind_one(struct device *dev, acpi_handle handle)
mutex_lock(&acpi_dev->physical_node_lock);
- /* Sanity check. */
- list_for_each_entry(pn, &acpi_dev->physical_node_list, node)
+ /*
+ * Keep the list sorted by node_id so that the IDs of removed nodes can
+ * be recycled easily.
+ */
+ physnode_list = &acpi_dev->physical_node_list;
+ node_id = 0;
+ list_for_each_entry(pn, &acpi_dev->physical_node_list, node) {
+ /* Sanity check. */
if (pn->dev == dev) {
+ mutex_unlock(&acpi_dev->physical_node_lock);
+
dev_warn(dev, "Already associated with ACPI node\n");
- goto err_free;
- }
+ kfree(physical_node);
+ if (ACPI_HANDLE(dev) != handle)
+ goto err;
- /* allocate physical node id according to physical_node_id_bitmap */
- physical_node->node_id =
- find_first_zero_bit(acpi_dev->physical_node_id_bitmap,
- ACPI_MAX_PHYSICAL_NODE);
- if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) {
- retval = -ENOSPC;
- goto err_free;
+ put_device(dev);
+ return 0;
+ }
+ if (pn->node_id == node_id) {
+ physnode_list = &pn->node;
+ node_id++;
+ }
}
- set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap);
+ physical_node->node_id = node_id;
physical_node->dev = dev;
- list_add_tail(&physical_node->node, &acpi_dev->physical_node_list);
+ list_add(&physical_node->node, physnode_list);
acpi_dev->physical_node_count++;
- mutex_unlock(&acpi_dev->physical_node_lock);
-
if (!ACPI_HANDLE(dev))
ACPI_HANDLE_SET(dev, acpi_dev->handle);
- if (!physical_node->node_id)
- strcpy(physical_node_name, PHYSICAL_NODE_STRING);
- else
- sprintf(physical_node_name,
- "physical_node%d", physical_node->node_id);
+ acpi_physnode_link_name(physical_node_name, node_id);
retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
- physical_node_name);
+ physical_node_name);
+ if (retval)
+ dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n",
+ physical_node_name, retval);
+
retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
- "firmware_node");
+ "firmware_node");
+ if (retval)
+ dev_err(dev, "Failed to create link firmware_node (%d)\n",
+ retval);
+
+ mutex_unlock(&acpi_dev->physical_node_lock);
if (acpi_dev->wakeup.flags.valid)
device_set_wakeup_capable(dev, true);
@@ -184,11 +273,6 @@ int acpi_bind_one(struct device *dev, acpi_handle handle)
ACPI_HANDLE_SET(dev, NULL);
put_device(dev);
return retval;
-
- err_free:
- mutex_unlock(&acpi_dev->physical_node_lock);
- kfree(physical_node);
- goto err;
}
EXPORT_SYMBOL_GPL(acpi_bind_one);
@@ -197,49 +281,37 @@ int acpi_unbind_one(struct device *dev)
struct acpi_device_physical_node *entry;
struct acpi_device *acpi_dev;
acpi_status status;
- struct list_head *node, *next;
if (!ACPI_HANDLE(dev))
return 0;
status = acpi_bus_get_device(ACPI_HANDLE(dev), &acpi_dev);
- if (ACPI_FAILURE(status))
- goto err;
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "Oops, ACPI handle corrupt in %s()\n", __func__);
+ return -EINVAL;
+ }
mutex_lock(&acpi_dev->physical_node_lock);
- list_for_each_safe(node, next, &acpi_dev->physical_node_list) {
- char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
- entry = list_entry(node, struct acpi_device_physical_node,
- node);
- if (entry->dev != dev)
- continue;
+ list_for_each_entry(entry, &acpi_dev->physical_node_list, node)
+ if (entry->dev == dev) {
+ char physnode_name[PHYSICAL_NODE_NAME_SIZE];
- list_del(node);
- clear_bit(entry->node_id, acpi_dev->physical_node_id_bitmap);
+ list_del(&entry->node);
+ acpi_dev->physical_node_count--;
- acpi_dev->physical_node_count--;
+ acpi_physnode_link_name(physnode_name, entry->node_id);
+ sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);
+ sysfs_remove_link(&dev->kobj, "firmware_node");
+ ACPI_HANDLE_SET(dev, NULL);
+ /* acpi_bind_one() increase refcnt by one. */
+ put_device(dev);
+ kfree(entry);
+ break;
+ }
- if (!entry->node_id)
- strcpy(physical_node_name, PHYSICAL_NODE_STRING);
- else
- sprintf(physical_node_name,
- "physical_node%d", entry->node_id);
-
- sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name);
- sysfs_remove_link(&dev->kobj, "firmware_node");
- ACPI_HANDLE_SET(dev, NULL);
- /* acpi_bind_one increase refcnt by one */
- put_device(dev);
- kfree(entry);
- }
mutex_unlock(&acpi_dev->physical_node_lock);
-
return 0;
-
-err:
- dev_err(dev, "Oops, 'acpi_handle' corrupt\n");
- return -EINVAL;
}
EXPORT_SYMBOL_GPL(acpi_unbind_one);
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 227aca77ee1..20f423337e1 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -23,6 +23,7 @@
#define PREFIX "ACPI: "
+acpi_status acpi_os_initialize1(void);
int init_acpi_device_notify(void);
int acpi_scan_init(void);
#ifdef CONFIG_ACPI_PCI_SLOT
@@ -169,10 +170,8 @@ int acpi_create_platform_device(struct acpi_device *adev,
-------------------------------------------------------------------------- */
#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
bool acpi_video_backlight_quirks(void);
-bool acpi_video_verify_backlight_support(void);
#else
static inline bool acpi_video_backlight_quirks(void) { return false; }
-static inline bool acpi_video_verify_backlight_support(void) { return false; }
#endif
#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 33e609f6358..2e82e5d7693 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -159,7 +159,7 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header)
* distance than the others.
* Do some quick checks here and only use the SLIT if it passes.
*/
-static __init int slit_valid(struct acpi_table_slit *slit)
+static int __init slit_valid(struct acpi_table_slit *slit)
{
int i, j;
int d = slit->locality_count;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 6ab2c350552..e5f416c7f66 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -52,6 +52,7 @@
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/processor.h>
+#include "internal.h"
#define _COMPONENT ACPI_OS_SERVICES
ACPI_MODULE_NAME("osl");
@@ -79,6 +80,8 @@ extern char line_buf[80];
static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl,
u32 pm1b_ctrl);
+static int (*__acpi_os_prepare_extended_sleep)(u8 sleep_state, u32 val_a,
+ u32 val_b);
static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context;
@@ -140,7 +143,8 @@ static struct osi_linux {
unsigned int enable:1;
unsigned int dmi:1;
unsigned int cmdline:1;
-} osi_linux = {0, 0, 0};
+ unsigned int default_disabling:1;
+} osi_linux = {0, 0, 0, 0};
static u32 acpi_osi_handler(acpi_string interface, u32 supported)
{
@@ -563,10 +567,6 @@ static const char * const table_sigs[] = {
ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT,
ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL };
-/* Non-fatal errors: Affected tables/files are ignored */
-#define INVALID_TABLE(x, path, name) \
- { pr_err("ACPI OVERRIDE: " x " [%s%s]\n", path, name); continue; }
-
#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
/* Must not increase 10 or needs code modification below */
@@ -593,9 +593,11 @@ void __init acpi_initrd_override(void *data, size_t size)
data += offset;
size -= offset;
- if (file.size < sizeof(struct acpi_table_header))
- INVALID_TABLE("Table smaller than ACPI header",
- cpio_path, file.name);
+ if (file.size < sizeof(struct acpi_table_header)) {
+ pr_err("ACPI OVERRIDE: Table smaller than ACPI header [%s%s]\n",
+ cpio_path, file.name);
+ continue;
+ }
table = file.data;
@@ -603,15 +605,21 @@ void __init acpi_initrd_override(void *data, size_t size)
if (!memcmp(table->signature, table_sigs[sig], 4))
break;
- if (!table_sigs[sig])
- INVALID_TABLE("Unknown signature",
- cpio_path, file.name);
- if (file.size != table->length)
- INVALID_TABLE("File length does not match table length",
- cpio_path, file.name);
- if (acpi_table_checksum(file.data, table->length))
- INVALID_TABLE("Bad table checksum",
- cpio_path, file.name);
+ if (!table_sigs[sig]) {
+ pr_err("ACPI OVERRIDE: Unknown signature [%s%s]\n",
+ cpio_path, file.name);
+ continue;
+ }
+ if (file.size != table->length) {
+ pr_err("ACPI OVERRIDE: File length does not match table length [%s%s]\n",
+ cpio_path, file.name);
+ continue;
+ }
+ if (acpi_table_checksum(file.data, table->length)) {
+ pr_err("ACPI OVERRIDE: Bad table checksum [%s%s]\n",
+ cpio_path, file.name);
+ continue;
+ }
pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n",
table->signature, cpio_path, file.name, table->length);
@@ -1351,8 +1359,8 @@ struct osi_setup_entry {
bool enable;
};
-static struct osi_setup_entry __initdata
- osi_setup_entries[OSI_STRING_ENTRIES_MAX] = {
+static struct osi_setup_entry
+ osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = {
{"Module Device", true},
{"Processor Device", true},
{"3.0 _SCP Extensions", true},
@@ -1376,6 +1384,17 @@ void __init acpi_osi_setup(char *str)
if (*str == '!') {
str++;
+ if (*str == '\0') {
+ osi_linux.default_disabling = 1;
+ return;
+ } else if (*str == '*') {
+ acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS);
+ for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+ osi = &osi_setup_entries[i];
+ osi->enable = false;
+ }
+ return;
+ }
enable = false;
}
@@ -1441,6 +1460,13 @@ static void __init acpi_osi_setup_late(void)
int i;
acpi_status status;
+ if (osi_linux.default_disabling) {
+ status = acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS);
+
+ if (ACPI_SUCCESS(status))
+ printk(KERN_INFO PREFIX "Disabled all _OSI OS vendors\n");
+ }
+
for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
osi = &osi_setup_entries[i];
str = osi->string;
@@ -1779,6 +1805,28 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
__acpi_os_prepare_sleep = func;
}
+acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
+ u32 val_b)
+{
+ int rc = 0;
+ if (__acpi_os_prepare_extended_sleep)
+ rc = __acpi_os_prepare_extended_sleep(sleep_state,
+ val_a, val_b);
+ if (rc < 0)
+ return AE_ERROR;
+ else if (rc > 0)
+ return AE_CTRL_SKIP;
+
+ return AE_OK;
+}
+
+void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
+ u32 val_a, u32 val_b))
+{
+ __acpi_os_prepare_extended_sleep = func;
+}
+
+
void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
void (*func)(struct work_struct *work))
{
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index 033d1179bdb..d678a180ca2 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -159,12 +159,16 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
-void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle)
+void acpi_pci_slot_enumerate(struct pci_bus *bus)
{
- mutex_lock(&slot_list_lock);
- acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
- register_slot, NULL, bus, NULL);
- mutex_unlock(&slot_list_lock);
+ acpi_handle handle = ACPI_HANDLE(bus->bridge);
+
+ if (handle) {
+ mutex_lock(&slot_list_lock);
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ register_slot, NULL, bus, NULL);
+ mutex_unlock(&slot_list_lock);
+ }
}
void acpi_pci_slot_remove(struct pci_bus *bus)
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 5c28c894c0f..0dbe5cdf339 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -637,9 +637,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
}
/* Execute _PSW */
- arg_list.count = 1;
- in_arg[0].integer.value = enable;
- status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
+ status = acpi_execute_simple_method(dev->handle, "_PSW", enable);
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
printk(KERN_ERR PREFIX "_PSW execution failed\n");
dev->wakeup.flags.valid = 0;
@@ -786,7 +784,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
}
}
- *state = ACPI_STATE_D3;
+ *state = ACPI_STATE_D3_COLD;
return 0;
}
diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c
index aa1227a7e3f..04a13784dd2 100644
--- a/drivers/acpi/proc.c
+++ b/drivers/acpi/proc.c
@@ -311,6 +311,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
dev->pnp.bus_id,
(u32) dev->wakeup.sleep_state);
+ mutex_lock(&dev->physical_node_lock);
+
if (!dev->physical_node_count) {
seq_printf(seq, "%c%-8s\n",
dev->wakeup.flags.run_wake ? '*' : ' ',
@@ -338,6 +340,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
put_device(ldev);
}
}
+
+ mutex_unlock(&dev->physical_node_lock);
}
mutex_unlock(&acpi_device_lock);
return 0;
@@ -347,12 +351,16 @@ static void physical_device_enable_wakeup(struct acpi_device *adev)
{
struct acpi_device_physical_node *entry;
+ mutex_lock(&adev->physical_node_lock);
+
list_for_each_entry(entry,
&adev->physical_node_list, node)
if (entry->dev && device_can_wakeup(entry->dev)) {
bool enable = !device_may_wakeup(entry->dev);
device_set_wakeup_enable(entry->dev, enable);
}
+
+ mutex_unlock(&adev->physical_node_lock);
}
static ssize_t
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index a5e9f4a5b28..cf34d903f4f 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -28,7 +28,7 @@ static int __init set_no_mwait(const struct dmi_system_id *id)
return 0;
}
-static struct dmi_system_id __initdata processor_idle_dmi_table[] = {
+static struct dmi_system_id processor_idle_dmi_table[] __initdata = {
{
set_no_mwait, "Extensa 5220", {
DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 870eaf5fa54..e534ba66d5b 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -91,21 +91,17 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
acpi_processor_ppc_has_changed(pr, 1);
if (saved == pr->performance_platform_limit)
break;
- acpi_bus_generate_proc_event(device, event,
- pr->performance_platform_limit);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
pr->performance_platform_limit);
break;
case ACPI_PROCESSOR_NOTIFY_POWER:
acpi_processor_cst_has_changed(pr);
- acpi_bus_generate_proc_event(device, event, 0);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event, 0);
break;
case ACPI_PROCESSOR_NOTIFY_THROTTLING:
acpi_processor_tstate_has_changed(pr);
- acpi_bus_generate_proc_event(device, event, 0);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event, 0);
break;
@@ -179,7 +175,9 @@ static int __acpi_processor_start(struct acpi_device *device)
acpi_processor_load_module(pr);
#endif
acpi_processor_get_throttling_info(pr);
- acpi_processor_get_limit_info(pr);
+
+ if (pr->flags.throttling)
+ pr->flags.limit = 1;
if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
acpi_processor_power_init(pr);
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 1e9732d809b..51d7948611d 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -164,17 +164,12 @@ static void acpi_processor_ppc_ost(acpi_handle handle, int status)
{.type = ACPI_TYPE_INTEGER,},
};
struct acpi_object_list arg_list = {2, params};
- acpi_handle temp;
- params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE;
- params[1].integer.value = status;
-
- /* when there is no _OST , skip it */
- if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp)))
- return;
-
- acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
- return;
+ if (acpi_has_method(handle, "_OST")) {
+ params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE;
+ params[1].integer.value = status;
+ acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
+ }
}
int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
@@ -468,14 +463,11 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
int acpi_processor_get_performance_info(struct acpi_processor *pr)
{
int result = 0;
- acpi_status status = AE_OK;
- acpi_handle handle = NULL;
if (!pr || !pr->performance || !pr->handle)
return -EINVAL;
- status = acpi_get_handle(pr->handle, "_PCT", &handle);
- if (ACPI_FAILURE(status)) {
+ if (!acpi_has_method(pr->handle, "_PCT")) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"ACPI-based processor performance control unavailable\n"));
return -ENODEV;
@@ -501,7 +493,7 @@ int acpi_processor_get_performance_info(struct acpi_processor *pr)
*/
update_bios:
#ifdef CONFIG_X86
- if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){
+ if (acpi_has_method(pr->handle, "_PPC")) {
if(boot_cpu_has(X86_FEATURE_EST))
printk(KERN_WARNING FW_BUG "BIOS needs update for CPU "
"frequency support\n");
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index e8e652710e6..d1d2e7fb5b3 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -186,18 +186,6 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)
#endif
-int acpi_processor_get_limit_info(struct acpi_processor *pr)
-{
-
- if (!pr)
- return -EINVAL;
-
- if (pr->flags.throttling)
- pr->flags.limit = 1;
-
- return 0;
-}
-
/* thermal coolign device callbacks */
static int acpi_processor_max_state(struct acpi_processor *pr)
{
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 3322b47ab7c..b7201fc6f1e 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -505,14 +505,12 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
void *preproc_data)
{
struct res_proc_context c;
- acpi_handle not_used;
acpi_status status;
if (!adev || !adev->handle || !list_empty(list))
return -EINVAL;
- status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, &not_used);
- if (ACPI_FAILURE(status))
+ if (!acpi_has_method(adev->handle, METHOD_NAME__CRS))
return 0;
c.list = list;
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index b6241eeb113..aef7e1cd1e5 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -873,14 +873,9 @@ static void acpi_sbs_callback(void *context)
u8 saved_charger_state = sbs->charger_present;
u8 saved_battery_state;
acpi_ac_get_present(sbs);
- if (sbs->charger_present != saved_charger_state) {
-#ifdef CONFIG_ACPI_PROC_EVENT
- acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME,
- ACPI_SBS_NOTIFY_STATUS,
- sbs->charger_present);
-#endif
+ if (sbs->charger_present != saved_charger_state)
kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
- }
+
if (sbs->manager_present) {
for (id = 0; id < MAX_SBS_BAT; ++id) {
if (!(sbs->batteries_supported & (1 << id)))
@@ -890,12 +885,6 @@ static void acpi_sbs_callback(void *context)
acpi_battery_read(bat);
if (saved_battery_state == bat->present)
continue;
-#ifdef CONFIG_ACPI_PROC_EVENT
- acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS,
- bat->name,
- ACPI_SBS_NOTIFY_STATUS,
- bat->present);
-#endif
kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE);
}
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 8a46c924eff..61d090b6ce2 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -193,9 +193,6 @@ static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl,
static int acpi_scan_hot_remove(struct acpi_device *device)
{
acpi_handle handle = device->handle;
- acpi_handle not_used;
- struct acpi_object_list arg_list;
- union acpi_object arg;
struct device *errdev;
acpi_status status;
unsigned long long sta;
@@ -258,32 +255,15 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
put_device(&device->dev);
device = NULL;
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 0;
- acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
- }
-
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 1;
-
+ acpi_evaluate_lck(handle, 0);
/*
* TBD: _EJD support.
*/
- status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
- if (ACPI_FAILURE(status)) {
- if (status == AE_NOT_FOUND) {
- return -ENODEV;
- } else {
- acpi_handle_warn(handle, "Eject failed (0x%x)\n",
- status);
- return -EIO;
- }
- }
+ status = acpi_evaluate_ej0(handle);
+ if (status == AE_NOT_FOUND)
+ return -ENODEV;
+ else if (ACPI_FAILURE(status))
+ return -EIO;
/*
* Verify if eject was indeed successful. If not, log an error
@@ -307,6 +287,7 @@ static void acpi_bus_device_eject(void *context)
struct acpi_device *device = NULL;
struct acpi_scan_handler *handler;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+ int error;
mutex_lock(&acpi_scan_lock);
@@ -321,17 +302,13 @@ static void acpi_bus_device_eject(void *context)
}
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
- if (handler->hotplug.mode == AHM_CONTAINER) {
- device->flags.eject_pending = true;
+ if (handler->hotplug.mode == AHM_CONTAINER)
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- } else {
- int error;
- get_device(&device->dev);
- error = acpi_scan_hot_remove(device);
- if (error)
- goto err_out;
- }
+ get_device(&device->dev);
+ error = acpi_scan_hot_remove(device);
+ if (error)
+ goto err_out;
out:
mutex_unlock(&acpi_scan_lock);
@@ -516,7 +493,6 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
struct acpi_eject_event *ej_event;
acpi_object_type not_used;
acpi_status status;
- u32 ost_source;
int ret;
if (!count || buf[0] != '1')
@@ -530,43 +506,28 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
return -ENODEV;
- mutex_lock(&acpi_scan_lock);
-
- if (acpi_device->flags.eject_pending) {
- /* ACPI eject notification event. */
- ost_source = ACPI_NOTIFY_EJECT_REQUEST;
- acpi_device->flags.eject_pending = 0;
- } else {
- /* Eject initiated by user space. */
- ost_source = ACPI_OST_EC_OSPM_EJECT;
- }
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
if (!ej_event) {
ret = -ENOMEM;
goto err_out;
}
- acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+ acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
ej_event->device = acpi_device;
- ej_event->event = ost_source;
+ ej_event->event = ACPI_OST_EC_OSPM_EJECT;
get_device(&acpi_device->dev);
status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
- if (ACPI_FAILURE(status)) {
- put_device(&acpi_device->dev);
- kfree(ej_event);
- ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
- goto err_out;
- }
- ret = count;
+ if (ACPI_SUCCESS(status))
+ return count;
- out:
- mutex_unlock(&acpi_scan_lock);
- return ret;
+ put_device(&acpi_device->dev);
+ kfree(ej_event);
+ ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
err_out:
- acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+ acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
- goto out;
+ return ret;
}
static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
@@ -654,7 +615,6 @@ static int acpi_device_setup_files(struct acpi_device *dev)
{
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_status status;
- acpi_handle temp;
unsigned long long sun;
int result = 0;
@@ -680,8 +640,7 @@ static int acpi_device_setup_files(struct acpi_device *dev)
/*
* If device has _STR, 'description' file is created
*/
- status = acpi_get_handle(dev->handle, "_STR", &temp);
- if (ACPI_SUCCESS(status)) {
+ if (acpi_has_method(dev->handle, "_STR")) {
status = acpi_evaluate_object(dev->handle, "_STR",
NULL, &buffer);
if (ACPI_FAILURE(status))
@@ -711,8 +670,7 @@ static int acpi_device_setup_files(struct acpi_device *dev)
* If device has _EJ0, 'eject' file is created that is used to trigger
* hot-removal function from userland.
*/
- status = acpi_get_handle(dev->handle, "_EJ0", &temp);
- if (ACPI_SUCCESS(status)) {
+ if (acpi_has_method(dev->handle, "_EJ0")) {
result = device_create_file(&dev->dev, &dev_attr_eject);
if (result)
return result;
@@ -734,9 +692,6 @@ end:
static void acpi_device_remove_files(struct acpi_device *dev)
{
- acpi_status status;
- acpi_handle temp;
-
if (dev->flags.power_manageable) {
device_remove_file(&dev->dev, &dev_attr_power_state);
if (dev->power.flags.power_resources)
@@ -747,20 +702,17 @@ static void acpi_device_remove_files(struct acpi_device *dev)
/*
* If device has _STR, remove 'description' file
*/
- status = acpi_get_handle(dev->handle, "_STR", &temp);
- if (ACPI_SUCCESS(status)) {
+ if (acpi_has_method(dev->handle, "_STR")) {
kfree(dev->pnp.str_obj);
device_remove_file(&dev->dev, &dev_attr_description);
}
/*
* If device has _EJ0, remove 'eject' file.
*/
- status = acpi_get_handle(dev->handle, "_EJ0", &temp);
- if (ACPI_SUCCESS(status))
+ if (acpi_has_method(dev->handle, "_EJ0"))
device_remove_file(&dev->dev, &dev_attr_eject);
- status = acpi_get_handle(dev->handle, "_SUN", &temp);
- if (ACPI_SUCCESS(status))
+ if (acpi_has_method(dev->handle, "_SUN"))
device_remove_file(&dev->dev, &dev_attr_sun);
if (dev->pnp.unique_id)
@@ -999,6 +951,28 @@ struct bus_type acpi_bus_type = {
.uevent = acpi_device_uevent,
};
+static void acpi_bus_data_handler(acpi_handle handle, void *context)
+{
+ /* Intentionally empty. */
+}
+
+int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+{
+ acpi_status status;
+
+ if (!device)
+ return -EINVAL;
+
+ status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
+ if (ACPI_FAILURE(status) || !*device) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
+ handle));
+ return -ENODEV;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_device);
+
int acpi_device_add(struct acpi_device *device,
void (*release)(struct device *))
{
@@ -1210,14 +1184,6 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
}
EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
-void acpi_bus_data_handler(acpi_handle handle, void *context)
-{
-
- /* TBD */
-
- return;
-}
-
static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
struct acpi_device_wakeup *wakeup)
{
@@ -1336,13 +1302,10 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
{
- acpi_handle temp;
- acpi_status status = 0;
int err;
/* Presence of _PRW indicates wake capable */
- status = acpi_get_handle(device->handle, "_PRW", &temp);
- if (ACPI_FAILURE(status))
+ if (!acpi_has_method(device->handle, "_PRW"))
return;
err = acpi_bus_extract_wakeup_device_power_package(device->handle,
@@ -1372,7 +1335,6 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
struct acpi_device_power_state *ps = &device->power.states[state];
char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' };
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- acpi_handle handle;
acpi_status status;
INIT_LIST_HEAD(&ps->resources);
@@ -1395,8 +1357,7 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
/* Evaluate "_PSx" to see if we can do explicit sets */
pathname[2] = 'S';
- status = acpi_get_handle(device->handle, pathname, &handle);
- if (ACPI_SUCCESS(status))
+ if (acpi_has_method(device->handle, pathname))
ps->flags.explicit_set = 1;
/*
@@ -1415,28 +1376,21 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
static void acpi_bus_get_power_flags(struct acpi_device *device)
{
- acpi_status status;
- acpi_handle handle;
u32 i;
/* Presence of _PS0|_PR0 indicates 'power manageable' */
- status = acpi_get_handle(device->handle, "_PS0", &handle);
- if (ACPI_FAILURE(status)) {
- status = acpi_get_handle(device->handle, "_PR0", &handle);
- if (ACPI_FAILURE(status))
- return;
- }
+ if (!acpi_has_method(device->handle, "_PS0") &&
+ !acpi_has_method(device->handle, "_PR0"))
+ return;
device->flags.power_manageable = 1;
/*
* Power Management Flags
*/
- status = acpi_get_handle(device->handle, "_PSC", &handle);
- if (ACPI_SUCCESS(status))
+ if (acpi_has_method(device->handle, "_PSC"))
device->power.flags.explicit_get = 1;
- status = acpi_get_handle(device->handle, "_IRC", &handle);
- if (ACPI_SUCCESS(status))
+ if (acpi_has_method(device->handle, "_IRC"))
device->power.flags.inrush_current = 1;
/*
@@ -1450,8 +1404,8 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
/* Set defaults for D0 and D3 states (always valid) */
device->power.states[ACPI_STATE_D0].flags.valid = 1;
device->power.states[ACPI_STATE_D0].power = 100;
- device->power.states[ACPI_STATE_D3].flags.valid = 1;
- device->power.states[ACPI_STATE_D3].power = 0;
+ device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
+ device->power.states[ACPI_STATE_D3_COLD].power = 0;
/* Set D3cold's explicit_set flag if _PS3 exists. */
if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set)
@@ -1470,28 +1424,18 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
static void acpi_bus_get_flags(struct acpi_device *device)
{
- acpi_status status = AE_OK;
- acpi_handle temp = NULL;
-
/* Presence of _STA indicates 'dynamic_status' */
- status = acpi_get_handle(device->handle, "_STA", &temp);
- if (ACPI_SUCCESS(status))
+ if (acpi_has_method(device->handle, "_STA"))
device->flags.dynamic_status = 1;
/* Presence of _RMV indicates 'removable' */
- status = acpi_get_handle(device->handle, "_RMV", &temp);
- if (ACPI_SUCCESS(status))
+ if (acpi_has_method(device->handle, "_RMV"))
device->flags.removable = 1;
/* Presence of _EJD|_EJ0 indicates 'ejectable' */
- status = acpi_get_handle(device->handle, "_EJD", &temp);
- if (ACPI_SUCCESS(status))
+ if (acpi_has_method(device->handle, "_EJD") ||
+ acpi_has_method(device->handle, "_EJ0"))
device->flags.ejectable = 1;
- else {
- status = acpi_get_handle(device->handle, "_EJ0", &temp);
- if (ACPI_SUCCESS(status))
- device->flags.ejectable = 1;
- }
}
static void acpi_device_get_busid(struct acpi_device *device)
@@ -1533,46 +1477,45 @@ static void acpi_device_get_busid(struct acpi_device *device)
}
/*
+ * acpi_ata_match - see if an acpi object is an ATA device
+ *
+ * If an acpi object has one of the ACPI ATA methods defined,
+ * then we can safely call it an ATA device.
+ */
+bool acpi_ata_match(acpi_handle handle)
+{
+ return acpi_has_method(handle, "_GTF") ||
+ acpi_has_method(handle, "_GTM") ||
+ acpi_has_method(handle, "_STM") ||
+ acpi_has_method(handle, "_SDD");
+}
+
+/*
* acpi_bay_match - see if an acpi object is an ejectable driver bay
*
* If an acpi object is ejectable and has one of the ACPI ATA methods defined,
* then we can safely call it an ejectable drive bay
*/
-static int acpi_bay_match(acpi_handle handle)
+bool acpi_bay_match(acpi_handle handle)
{
- acpi_status status;
- acpi_handle tmp;
acpi_handle phandle;
- status = acpi_get_handle(handle, "_EJ0", &tmp);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
- return 0;
+ if (!acpi_has_method(handle, "_EJ0"))
+ return false;
+ if (acpi_ata_match(handle))
+ return true;
+ if (ACPI_FAILURE(acpi_get_parent(handle, &phandle)))
+ return false;
- if (acpi_get_parent(handle, &phandle))
- return -ENODEV;
-
- if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
- (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
- return 0;
-
- return -ENODEV;
+ return acpi_ata_match(phandle);
}
/*
* acpi_dock_match - see if an acpi object has a _DCK method
*/
-static int acpi_dock_match(acpi_handle handle)
+bool acpi_dock_match(acpi_handle handle)
{
- acpi_handle tmp;
- return acpi_get_handle(handle, "_DCK", &tmp);
+ return acpi_has_method(handle, "_DCK");
}
const char *acpi_device_hid(struct acpi_device *device)
@@ -1610,34 +1553,26 @@ static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id)
* lacks the SMBUS01 HID and the methods do not have the necessary "_"
* prefix. Work around this.
*/
-static int acpi_ibm_smbus_match(acpi_handle handle)
+static bool acpi_ibm_smbus_match(acpi_handle handle)
{
- acpi_handle h_dummy;
- struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
- int result;
+ char node_name[ACPI_PATH_SEGMENT_LENGTH];
+ struct acpi_buffer path = { sizeof(node_name), node_name };
if (!dmi_name_in_vendors("IBM"))
- return -ENODEV;
+ return false;
/* Look for SMBS object */
- result = acpi_get_name(handle, ACPI_SINGLE_NAME, &path);
- if (result)
- return result;
-
- if (strcmp("SMBS", path.pointer)) {
- result = -ENODEV;
- goto out;
- }
+ if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &path)) ||
+ strcmp("SMBS", path.pointer))
+ return false;
/* Does it have the necessary (but misnamed) methods? */
- result = -ENODEV;
- if (ACPI_SUCCESS(acpi_get_handle(handle, "SBI", &h_dummy)) &&
- ACPI_SUCCESS(acpi_get_handle(handle, "SBR", &h_dummy)) &&
- ACPI_SUCCESS(acpi_get_handle(handle, "SBW", &h_dummy)))
- result = 0;
-out:
- kfree(path.pointer);
- return result;
+ if (acpi_has_method(handle, "SBI") &&
+ acpi_has_method(handle, "SBR") &&
+ acpi_has_method(handle, "SBW"))
+ return true;
+
+ return false;
}
static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
@@ -1685,11 +1620,11 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
*/
if (acpi_is_video_device(handle))
acpi_add_id(pnp, ACPI_VIDEO_HID);
- else if (ACPI_SUCCESS(acpi_bay_match(handle)))
+ else if (acpi_bay_match(handle))
acpi_add_id(pnp, ACPI_BAY_HID);
- else if (ACPI_SUCCESS(acpi_dock_match(handle)))
+ else if (acpi_dock_match(handle))
acpi_add_id(pnp, ACPI_DOCK_HID);
- else if (!acpi_ibm_smbus_match(handle))
+ else if (acpi_ibm_smbus_match(handle))
acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) {
acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
@@ -1900,7 +1835,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
struct acpi_device *device = NULL;
int type;
unsigned long long sta;
- acpi_status status;
int result;
acpi_bus_get_device(handle, &device);
@@ -1921,10 +1855,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
struct acpi_device_wakeup wakeup;
- acpi_handle temp;
- status = acpi_get_handle(handle, "_PRW", &temp);
- if (ACPI_SUCCESS(status)) {
+ if (acpi_has_method(handle, "_PRW")) {
acpi_bus_extract_wakeup_device_power_package(handle,
&wakeup);
acpi_power_resources_list_free(&wakeup.resources);
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 187ab61889e..14df30580e1 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -31,12 +31,9 @@ static u8 sleep_states[ACPI_S_STATE_COUNT];
static void acpi_sleep_tts_switch(u32 acpi_state)
{
- union acpi_object in_arg = { ACPI_TYPE_INTEGER };
- struct acpi_object_list arg_list = { 1, &in_arg };
- acpi_status status = AE_OK;
+ acpi_status status;
- in_arg.integer.value = acpi_state;
- status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
+ status = acpi_execute_simple_method(NULL, "\\_TTS", acpi_state);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
/*
* OS can't evaluate the _TTS object correctly. Some warning
@@ -141,7 +138,7 @@ static int __init init_nvs_nosave(const struct dmi_system_id *d)
return 0;
}
-static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+static struct dmi_system_id acpisleep_dmi_table[] __initdata = {
{
.callback = init_old_suspend_ordering,
.ident = "Abit KN9 (nForce4 variant)",
@@ -423,10 +420,21 @@ static void acpi_pm_finish(void)
}
/**
- * acpi_pm_end - Finish up suspend sequence.
+ * acpi_pm_start - Start system PM transition.
+ */
+static void acpi_pm_start(u32 acpi_state)
+{
+ acpi_target_sleep_state = acpi_state;
+ acpi_sleep_tts_switch(acpi_target_sleep_state);
+ acpi_scan_lock_acquire();
+}
+
+/**
+ * acpi_pm_end - Finish up system PM transition.
*/
static void acpi_pm_end(void)
{
+ acpi_scan_lock_release();
/*
* This is necessary in case acpi_pm_finish() is not called during a
* failing transition to a sleep state.
@@ -454,21 +462,19 @@ static u32 acpi_suspend_states[] = {
static int acpi_suspend_begin(suspend_state_t pm_state)
{
u32 acpi_state = acpi_suspend_states[pm_state];
- int error = 0;
+ int error;
error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc();
if (error)
return error;
- if (sleep_states[acpi_state]) {
- acpi_target_sleep_state = acpi_state;
- acpi_sleep_tts_switch(acpi_target_sleep_state);
- } else {
- printk(KERN_ERR "ACPI does not support this state: %d\n",
- pm_state);
- error = -ENOSYS;
+ if (!sleep_states[acpi_state]) {
+ pr_err("ACPI does not support sleep state S%u\n", acpi_state);
+ return -ENOSYS;
}
- return error;
+
+ acpi_pm_start(acpi_state);
+ return 0;
}
/**
@@ -634,10 +640,8 @@ static int acpi_hibernation_begin(void)
int error;
error = nvs_nosave ? 0 : suspend_nvs_alloc();
- if (!error) {
- acpi_target_sleep_state = ACPI_STATE_S4;
- acpi_sleep_tts_switch(acpi_target_sleep_state);
- }
+ if (!error)
+ acpi_pm_start(ACPI_STATE_S4);
return error;
}
@@ -716,8 +720,10 @@ static int acpi_hibernation_begin_old(void)
if (!error) {
if (!nvs_nosave)
error = suspend_nvs_alloc();
- if (!error)
+ if (!error) {
acpi_target_sleep_state = ACPI_STATE_S4;
+ acpi_scan_lock_acquire();
+ }
}
return error;
}
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index a33821ca389..6a0329340b4 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -50,11 +50,6 @@
#define ACPI_THERMAL_CLASS "thermal_zone"
#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
-#define ACPI_THERMAL_FILE_STATE "state"
-#define ACPI_THERMAL_FILE_TEMPERATURE "temperature"
-#define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points"
-#define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode"
-#define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency"
#define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
#define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81
#define ACPI_THERMAL_NOTIFY_DEVICES 0x82
@@ -190,7 +185,6 @@ struct acpi_thermal {
struct thermal_zone_device *thermal_zone;
int tz_enabled;
int kelvin_offset;
- struct mutex lock;
};
/* --------------------------------------------------------------------------
@@ -239,26 +233,16 @@ static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
{
- acpi_status status = AE_OK;
- union acpi_object arg0 = { ACPI_TYPE_INTEGER };
- struct acpi_object_list arg_list = { 1, &arg0 };
- acpi_handle handle = NULL;
-
-
if (!tz)
return -EINVAL;
- status = acpi_get_handle(tz->device->handle, "_SCP", &handle);
- if (ACPI_FAILURE(status)) {
+ if (!acpi_has_method(tz->device->handle, "_SCP")) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
return -ENODEV;
- }
-
- arg0.integer.value = mode;
-
- status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
- if (ACPI_FAILURE(status))
+ } else if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle,
+ "_SCP", mode))) {
return -ENODEV;
+ }
return 0;
}
@@ -491,14 +475,14 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
break;
}
- if (flag & ACPI_TRIPS_DEVICES) {
- memset(&devices, 0, sizeof(struct acpi_handle_list));
+ if ((flag & ACPI_TRIPS_DEVICES)
+ && acpi_has_method(tz->device->handle, "_TZD")) {
+ memset(&devices, 0, sizeof(devices));
status = acpi_evaluate_reference(tz->device->handle, "_TZD",
NULL, &devices);
- if (memcmp(&tz->devices, &devices,
- sizeof(struct acpi_handle_list))) {
- memcpy(&tz->devices, &devices,
- sizeof(struct acpi_handle_list));
+ if (ACPI_SUCCESS(status)
+ && memcmp(&tz->devices, &devices, sizeof(devices))) {
+ tz->devices = devices;
ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
}
}
@@ -769,7 +753,6 @@ static int thermal_notify(struct thermal_zone_device *thermal, int trip,
else
return 0;
- acpi_bus_generate_proc_event(tz->device, type, 1);
acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
dev_name(&tz->device->dev), type, 1);
@@ -850,12 +833,13 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
if (ACPI_SUCCESS(status) && (dev == device)) {
if (bind)
result = thermal_zone_bind_cooling_device
- (thermal, -1, cdev,
- THERMAL_NO_LIMIT,
+ (thermal, THERMAL_TRIPS_NONE,
+ cdev, THERMAL_NO_LIMIT,
THERMAL_NO_LIMIT);
else
result = thermal_zone_unbind_cooling_device
- (thermal, -1, cdev);
+ (thermal, THERMAL_TRIPS_NONE,
+ cdev);
if (result)
goto failed;
}
@@ -980,14 +964,12 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event)
case ACPI_THERMAL_NOTIFY_THRESHOLDS:
acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
acpi_thermal_check(tz);
- acpi_bus_generate_proc_event(device, event, 0);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event, 0);
break;
case ACPI_THERMAL_NOTIFY_DEVICES:
acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
acpi_thermal_check(tz);
- acpi_bus_generate_proc_event(device, event, 0);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event, 0);
break;
@@ -1101,8 +1083,6 @@ static int acpi_thermal_add(struct acpi_device *device)
strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
device->driver_data = tz;
- mutex_init(&tz->lock);
-
result = acpi_thermal_get_info(tz);
if (result)
@@ -1135,7 +1115,6 @@ static int acpi_thermal_remove(struct acpi_device *device)
tz = acpi_driver_data(device);
acpi_thermal_unregister_thermal_zone(tz);
- mutex_destroy(&tz->lock);
kfree(tz);
return 0;
}
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 74437130431..552248b0005 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -495,3 +495,73 @@ acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...)
kfree(buffer.pointer);
}
EXPORT_SYMBOL(acpi_handle_printk);
+
+/**
+ * acpi_has_method: Check whether @handle has a method named @name
+ * @handle: ACPI device handle
+ * @name: name of object or method
+ *
+ * Check whether @handle has a method named @name.
+ */
+bool acpi_has_method(acpi_handle handle, char *name)
+{
+ acpi_handle tmp;
+
+ return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp));
+}
+EXPORT_SYMBOL(acpi_has_method);
+
+acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
+ u64 arg)
+{
+ union acpi_object obj = { .type = ACPI_TYPE_INTEGER };
+ struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, };
+
+ obj.integer.value = arg;
+
+ return acpi_evaluate_object(handle, method, &arg_list, NULL);
+}
+EXPORT_SYMBOL(acpi_execute_simple_method);
+
+/**
+ * acpi_evaluate_ej0: Evaluate _EJ0 method for hotplug operations
+ * @handle: ACPI device handle
+ *
+ * Evaluate device's _EJ0 method for hotplug operations.
+ */
+acpi_status acpi_evaluate_ej0(acpi_handle handle)
+{
+ acpi_status status;
+
+ status = acpi_execute_simple_method(handle, "_EJ0", 1);
+ if (status == AE_NOT_FOUND)
+ acpi_handle_warn(handle, "No _EJ0 support for device\n");
+ else if (ACPI_FAILURE(status))
+ acpi_handle_warn(handle, "Eject failed (0x%x)\n", status);
+
+ return status;
+}
+
+/**
+ * acpi_evaluate_lck: Evaluate _LCK method to lock/unlock device
+ * @handle: ACPI device handle
+ * @lock: lock device if non-zero, otherwise unlock device
+ *
+ * Evaluate device's _LCK method if present to lock/unlock device
+ */
+acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
+{
+ acpi_status status;
+
+ status = acpi_execute_simple_method(handle, "_LCK", !!lock);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ if (lock)
+ acpi_handle_warn(handle,
+ "Locking device failed (0x%x)\n", status);
+ else
+ acpi_handle_warn(handle,
+ "Unlocking device failed (0x%x)\n", status);
+ }
+
+ return status;
+}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 6dd237e79b4..aebcf6355df 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -1,5 +1,5 @@
/*
- * video.c - ACPI Video Driver ($Revision:$)
+ * video.c - ACPI Video Driver
*
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
@@ -88,7 +88,7 @@ module_param(allow_duplicates, bool, 0644);
static bool use_bios_initial_backlight = 1;
module_param(use_bios_initial_backlight, bool, 0644);
-static int register_count = 0;
+static int register_count;
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device);
static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
@@ -118,26 +118,26 @@ struct acpi_video_bus_flags {
};
struct acpi_video_bus_cap {
- u8 _DOS:1; /*Enable/Disable output switching */
- u8 _DOD:1; /*Enumerate all devices attached to display adapter */
- u8 _ROM:1; /*Get ROM Data */
- u8 _GPD:1; /*Get POST Device */
- u8 _SPD:1; /*Set POST Device */
- u8 _VPO:1; /*Video POST Options */
+ u8 _DOS:1; /* Enable/Disable output switching */
+ u8 _DOD:1; /* Enumerate all devices attached to display adapter */
+ u8 _ROM:1; /* Get ROM Data */
+ u8 _GPD:1; /* Get POST Device */
+ u8 _SPD:1; /* Set POST Device */
+ u8 _VPO:1; /* Video POST Options */
u8 reserved:2;
};
struct acpi_video_device_attrib {
u32 display_index:4; /* A zero-based instance of the Display */
- u32 display_port_attachment:4; /*This field differentiates the display type */
- u32 display_type:4; /*Describe the specific type in use */
- u32 vendor_specific:4; /*Chipset Vendor Specific */
- u32 bios_can_detect:1; /*BIOS can detect the device */
- u32 depend_on_vga:1; /*Non-VGA output device whose power is related to
+ u32 display_port_attachment:4; /* This field differentiates the display type */
+ u32 display_type:4; /* Describe the specific type in use */
+ u32 vendor_specific:4; /* Chipset Vendor Specific */
+ u32 bios_can_detect:1; /* BIOS can detect the device */
+ u32 depend_on_vga:1; /* Non-VGA output device whose power is related to
the VGA device. */
- u32 pipe_id:3; /*For VGA multiple-head devices. */
- u32 reserved:10; /*Must be 0 */
- u32 device_id_scheme:1; /*Device ID Scheme */
+ u32 pipe_id:3; /* For VGA multiple-head devices. */
+ u32 reserved:10; /* Must be 0 */
+ u32 device_id_scheme:1; /* Device ID Scheme */
};
struct acpi_video_enumerated_device {
@@ -174,19 +174,17 @@ struct acpi_video_device_flags {
};
struct acpi_video_device_cap {
- u8 _ADR:1; /*Return the unique ID */
- u8 _BCL:1; /*Query list of brightness control levels supported */
- u8 _BCM:1; /*Set the brightness level */
+ u8 _ADR:1; /* Return the unique ID */
+ u8 _BCL:1; /* Query list of brightness control levels supported */
+ u8 _BCM:1; /* Set the brightness level */
u8 _BQC:1; /* Get current brightness level */
u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */
- u8 _DDC:1; /*Return the EDID for this device */
+ u8 _DDC:1; /* Return the EDID for this device */
};
struct acpi_video_brightness_flags {
u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */
- u8 _BCL_reversed:1; /* _BCL package is in a reversed order*/
- u8 _BCL_use_index:1; /* levels in _BCL are index values */
- u8 _BCM_use_index:1; /* input of _BCM is an index value */
+ u8 _BCL_reversed:1; /* _BCL package is in a reversed order */
u8 _BQC_use_index:1; /* _BQC returns an index value */
};
@@ -231,21 +229,22 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
static int acpi_video_switch_brightness(struct acpi_video_device *device,
int event);
-/*backlight device sysfs support*/
+/* backlight device sysfs support */
static int acpi_video_get_brightness(struct backlight_device *bd)
{
unsigned long long cur_level;
int i;
- struct acpi_video_device *vd =
- (struct acpi_video_device *)bl_get_data(bd);
+ struct acpi_video_device *vd = bl_get_data(bd);
if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false))
return -EINVAL;
for (i = 2; i < vd->brightness->count; i++) {
if (vd->brightness->levels[i] == cur_level)
- /* The first two entries are special - see page 575
- of the ACPI spec 3.0 */
- return i-2;
+ /*
+ * The first two entries are special - see page 575
+ * of the ACPI spec 3.0
+ */
+ return i - 2;
}
return 0;
}
@@ -253,8 +252,7 @@ static int acpi_video_get_brightness(struct backlight_device *bd)
static int acpi_video_set_brightness(struct backlight_device *bd)
{
int request_level = bd->props.brightness + 2;
- struct acpi_video_device *vd =
- (struct acpi_video_device *)bl_get_data(bd);
+ struct acpi_video_device *vd = bl_get_data(bd);
return acpi_video_device_lcd_set_level(vd,
vd->brightness->levels[request_level]);
@@ -302,11 +300,11 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st
struct acpi_video_device *video = acpi_driver_data(device);
int level;
- if ( state >= video->brightness->count - 2)
+ if (state >= video->brightness->count - 2)
return -EINVAL;
state = video->brightness->count - state;
- level = video->brightness->levels[state -1];
+ level = video->brightness->levels[state - 1];
return acpi_video_device_lcd_set_level(video, level);
}
@@ -316,9 +314,11 @@ static const struct thermal_cooling_device_ops video_cooling_ops = {
.set_cur_state = video_set_cur_state,
};
-/* --------------------------------------------------------------------------
- Video Management
- -------------------------------------------------------------------------- */
+/*
+ * --------------------------------------------------------------------------
+ * Video Management
+ * --------------------------------------------------------------------------
+ */
static int
acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
@@ -345,7 +345,7 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
return 0;
- err:
+err:
kfree(buffer.pointer);
return status;
@@ -355,14 +355,10 @@ static int
acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
{
int status;
- union acpi_object arg0 = { ACPI_TYPE_INTEGER };
- struct acpi_object_list args = { 1, &arg0 };
int state;
- arg0.integer.value = level;
-
- status = acpi_evaluate_object(device->dev->handle, "_BCM",
- &args, NULL);
+ status = acpi_execute_simple_method(device->dev->handle,
+ "_BCM", level);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Evaluating _BCM failed"));
return -EIO;
@@ -546,7 +542,7 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
if (device->brightness->levels[i] == *level) {
device->brightness->curr = *level;
return 0;
- }
+ }
/*
* BQC returned an invalid level.
* Stop using it.
@@ -556,7 +552,8 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
buf));
device->cap._BQC = device->cap._BCQ = 0;
} else {
- /* Fixme:
+ /*
+ * Fixme:
* should we return an error or ignore this failure?
* dev->brightness->curr is a cached value which stores
* the correct current backlight level in most cases.
@@ -615,8 +612,8 @@ acpi_video_device_EDID(struct acpi_video_device *device,
/*
* Arg:
- * video : video bus device pointer
- * bios_flag :
+ * video : video bus device pointer
+ * bios_flag :
* 0. The system BIOS should NOT automatically switch(toggle)
* the active display output.
* 1. The system BIOS should automatically switch (toggle) the
@@ -628,9 +625,9 @@ acpi_video_device_EDID(struct acpi_video_device *device,
* lcd_flag :
* 0. The system BIOS should automatically control the brightness level
* of the LCD when the power changes from AC to DC
- * 1. The system BIOS should NOT automatically control the brightness
+ * 1. The system BIOS should NOT automatically control the brightness
* level of the LCD when the power changes from AC to DC.
- * Return Value:
+ * Return Value:
* -EINVAL wrong arg.
*/
@@ -638,18 +635,15 @@ static int
acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
{
acpi_status status;
- union acpi_object arg0 = { ACPI_TYPE_INTEGER };
- struct acpi_object_list args = { 1, &arg0 };
if (!video->cap._DOS)
return 0;
if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1)
return -EINVAL;
- arg0.integer.value = (lcd_flag << 2) | bios_flag;
- video->dos_setting = arg0.integer.value;
- status = acpi_evaluate_object(video->device->handle, "_DOS",
- &args, NULL);
+ video->dos_setting = (lcd_flag << 2) | bios_flag;
+ status = acpi_execute_simple_method(video->device->handle, "_DOS",
+ (lcd_flag << 2) | bios_flag);
if (ACPI_FAILURE(status))
return -EIO;
@@ -689,7 +683,7 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device,
* Some systems always report current brightness level as maximum
* through _BQC, we need to test another value for them.
*/
- test_level = current_level == max_level ? br->levels[2] : max_level;
+ test_level = current_level == max_level ? br->levels[3] : max_level;
result = acpi_video_device_lcd_set_level(device, test_level);
if (result)
@@ -717,8 +711,8 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device,
/*
- * Arg:
- * device : video output device (LCD, CRT, ..)
+ * Arg:
+ * device : video output device (LCD, CRT, ..)
*
* Return Value:
* Maximum brightness level
@@ -806,16 +800,6 @@ acpi_video_init_brightness(struct acpi_video_device *device)
br->count = count;
device->brightness = br;
- /* Check the input/output of _BQC/_BCL/_BCM */
- if ((max_level < 100) && (max_level <= (count - 2)))
- br->flags._BCL_use_index = 1;
-
- /*
- * _BCM is always consistent with _BCL,
- * at least for all the laptops we have ever seen.
- */
- br->flags._BCM_use_index = br->flags._BCL_use_index;
-
/* _BQC uses INDEX while _BCL uses VALUE in some laptops */
br->curr = level = max_level;
@@ -877,7 +861,7 @@ out:
* device : video output device (LCD, CRT, ..)
*
* Return Value:
- * None
+ * None
*
* Find out all required AML methods defined under the output
* device.
@@ -885,41 +869,34 @@ out:
static void acpi_video_device_find_cap(struct acpi_video_device *device)
{
- acpi_handle h_dummy1;
-
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
+ if (acpi_has_method(device->dev->handle, "_ADR"))
device->cap._ADR = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) {
+ if (acpi_has_method(device->dev->handle, "_BCL"))
device->cap._BCL = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
+ if (acpi_has_method(device->dev->handle, "_BCM"))
device->cap._BCM = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
+ if (acpi_has_method(device->dev->handle, "_BQC")) {
device->cap._BQC = 1;
- else if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCQ",
- &h_dummy1))) {
+ } else if (acpi_has_method(device->dev->handle, "_BCQ")) {
printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n");
device->cap._BCQ = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
+ if (acpi_has_method(device->dev->handle, "_DDC"))
device->cap._DDC = 1;
- }
- if (acpi_video_init_brightness(device))
- return;
-
- if (acpi_video_verify_backlight_support()) {
+ if (acpi_video_backlight_support()) {
struct backlight_properties props;
struct pci_dev *pdev;
acpi_handle acpi_parent;
struct device *parent = NULL;
int result;
- static int count = 0;
+ static int count;
char *name;
+ result = acpi_video_init_brightness(device);
+ if (result)
+ return;
name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
if (!name)
return;
@@ -979,46 +956,33 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (result)
printk(KERN_ERR PREFIX "Create sysfs link\n");
- } else {
- /* Remove the brightness object. */
- kfree(device->brightness->levels);
- kfree(device->brightness);
- device->brightness = NULL;
}
}
/*
- * Arg:
- * device : video output device (VGA)
+ * Arg:
+ * device : video output device (VGA)
*
* Return Value:
- * None
+ * None
*
* Find out all required AML methods defined under the video bus device.
*/
static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
{
- acpi_handle h_dummy1;
-
- if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
+ if (acpi_has_method(video->device->handle, "_DOS"))
video->cap._DOS = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) {
+ if (acpi_has_method(video->device->handle, "_DOD"))
video->cap._DOD = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) {
+ if (acpi_has_method(video->device->handle, "_ROM"))
video->cap._ROM = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) {
+ if (acpi_has_method(video->device->handle, "_GPD"))
video->cap._GPD = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) {
+ if (acpi_has_method(video->device->handle, "_SPD"))
video->cap._SPD = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) {
+ if (acpi_has_method(video->device->handle, "_VPO"))
video->cap._VPO = 1;
- }
}
/*
@@ -1039,7 +1003,8 @@ static int acpi_video_bus_check(struct acpi_video_bus *video)
return -ENODEV;
pci_dev_put(dev);
- /* Since there is no HID, CID and so on for VGA driver, we have
+ /*
+ * Since there is no HID, CID and so on for VGA driver, we have
* to check well known required nodes.
*/
@@ -1069,12 +1034,14 @@ static int acpi_video_bus_check(struct acpi_video_bus *video)
return status;
}
-/* --------------------------------------------------------------------------
- Driver Interface
- -------------------------------------------------------------------------- */
+/*
+ * --------------------------------------------------------------------------
+ * Driver Interface
+ * --------------------------------------------------------------------------
+ */
/* device interface */
-static struct acpi_video_device_attrib*
+static struct acpi_video_device_attrib *
acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
{
struct acpi_video_enumerated_device *ids;
@@ -1112,7 +1079,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
unsigned long long device_id;
int status, device_type;
struct acpi_video_device *data;
- struct acpi_video_device_attrib* attribute;
+ struct acpi_video_device_attrib *attribute;
status =
acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
@@ -1134,7 +1101,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
attribute = acpi_video_get_device_attr(video, device_id);
- if((attribute != NULL) && attribute->device_id_scheme) {
+ if (attribute && attribute->device_id_scheme) {
switch (attribute->display_type) {
case ACPI_VIDEO_DISPLAY_CRT:
data->flags.crt = 1;
@@ -1152,24 +1119,24 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
data->flags.unknown = 1;
break;
}
- if(attribute->bios_can_detect)
+ if (attribute->bios_can_detect)
data->flags.bios = 1;
} else {
/* Check for legacy IDs */
device_type = acpi_video_get_device_type(video, device_id);
/* Ignore bits 16 and 18-20 */
switch (device_type & 0xffe2ffff) {
- case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
- data->flags.crt = 1;
- break;
- case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
- data->flags.lcd = 1;
- break;
- case ACPI_VIDEO_DISPLAY_LEGACY_TV:
- data->flags.tvout = 1;
- break;
- default:
- data->flags.unknown = 1;
+ case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
+ data->flags.crt = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
+ data->flags.lcd = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_LEGACY_TV:
+ data->flags.tvout = 1;
+ break;
+ default:
+ data->flags.unknown = 1;
}
}
@@ -1192,12 +1159,12 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
/*
* Arg:
- * video : video bus device
+ * video : video bus device
*
* Return:
- * none
- *
- * Enumerate the video device list of the video bus,
+ * none
+ *
+ * Enumerate the video device list of the video bus,
* bind the ids with the corresponding video devices
* under the video bus.
*/
@@ -1216,13 +1183,13 @@ static void acpi_video_device_rebind(struct acpi_video_bus *video)
/*
* Arg:
- * video : video bus device
- * device : video output device under the video
- * bus
+ * video : video bus device
+ * device : video output device under the video
+ * bus
*
* Return:
- * none
- *
+ * none
+ *
* Bind the ids with the corresponding video devices
* under the video bus.
*/
@@ -1245,11 +1212,11 @@ acpi_video_device_bind(struct acpi_video_bus *video,
/*
* Arg:
- * video : video bus device
+ * video : video bus device
*
* Return:
- * < 0 : error
- *
+ * < 0 : error
+ *
* Call _DOD to enumerate all devices attached to display adapter
*
*/
@@ -1310,7 +1277,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
video->attached_array = active_list;
video->attached_count = count;
- out:
+out:
kfree(buffer.pointer);
return status;
}
@@ -1366,8 +1333,8 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
unsigned long long level_current, level_next;
int result = -EINVAL;
- /* no warning message if acpi_backlight=vendor or a quirk is used */
- if (!acpi_video_verify_backlight_support())
+ /* no warning message if acpi_backlight=vendor is used */
+ if (!acpi_video_backlight_support())
return 0;
if (!device->brightness)
@@ -1577,7 +1544,6 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
switch (event) {
case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch,
* most likely via hotkey. */
- acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_SWITCHVIDEOMODE;
break;
@@ -1585,20 +1551,16 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
* connector. */
acpi_video_device_enumerate(video);
acpi_video_device_rebind(video);
- acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_SWITCHVIDEOMODE;
break;
case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */
- acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_SWITCHVIDEOMODE;
break;
case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */
- acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_VIDEO_NEXT;
break;
case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */
- acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_VIDEO_PREV;
break;
@@ -1641,31 +1603,26 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
- acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_BRIGHTNESS_CYCLE;
break;
case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */
if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
- acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_BRIGHTNESSUP;
break;
case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */
if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
- acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_BRIGHTNESSDOWN;
break;
case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */
if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
- acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_BRIGHTNESS_ZERO;
break;
case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */
if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
- acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_DISPLAY_OFF;
break;
default:
@@ -1765,7 +1722,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
if (!strcmp(device->pnp.bus_id, "VID")) {
if (instance)
device->pnp.bus_id[3] = '0' + instance;
- instance ++;
+ instance++;
}
/* a hack to fix the duplicate name "VGA" problem on Pa 3553 */
if (!strcmp(device->pnp.bus_id, "VGA")) {
@@ -1875,46 +1832,6 @@ static int acpi_video_bus_remove(struct acpi_device *device)
return 0;
}
-static acpi_status video_unregister_backlight(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- struct acpi_device *acpi_dev;
- struct acpi_video_bus *video;
- struct acpi_video_device *dev, *next;
-
- if (acpi_bus_get_device(handle, &acpi_dev))
- return AE_OK;
-
- if (acpi_match_device_ids(acpi_dev, video_device_ids))
- return AE_OK;
-
- video = acpi_driver_data(acpi_dev);
- if (!video)
- return AE_OK;
-
- acpi_video_bus_stop_devices(video);
- mutex_lock(&video->device_list_lock);
- list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
- if (dev->backlight) {
- backlight_device_unregister(dev->backlight);
- dev->backlight = NULL;
- kfree(dev->brightness->levels);
- kfree(dev->brightness);
- }
- if (dev->cooling_dev) {
- sysfs_remove_link(&dev->dev->dev.kobj,
- "thermal_cooling");
- sysfs_remove_link(&dev->cooling_dev->device.kobj,
- "device");
- thermal_cooling_device_unregister(dev->cooling_dev);
- dev->cooling_dev = NULL;
- }
- }
- mutex_unlock(&video->device_list_lock);
- acpi_video_bus_start_devices(video);
- return AE_OK;
-}
-
static int __init is_i740(struct pci_dev *dev)
{
if (dev->device == 0x00D1)
@@ -1946,25 +1863,14 @@ static int __init intel_opregion_present(void)
return opregion;
}
-int __acpi_video_register(bool backlight_quirks)
+int acpi_video_register(void)
{
- bool no_backlight;
- int result;
-
- no_backlight = backlight_quirks ? acpi_video_backlight_quirks() : false;
-
+ int result = 0;
if (register_count) {
/*
- * If acpi_video_register() has been called already, don't try
- * to register acpi_video_bus, but unregister backlight devices
- * if no backlight support is requested.
+ * if the function of acpi_video_register is already called,
+ * don't register the acpi_vide_bus again and return no error.
*/
- if (no_backlight)
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- video_unregister_backlight,
- NULL, NULL, NULL);
-
return 0;
}
@@ -1980,7 +1886,7 @@ int __acpi_video_register(bool backlight_quirks)
return 0;
}
-EXPORT_SYMBOL(__acpi_video_register);
+EXPORT_SYMBOL(acpi_video_register);
void acpi_video_unregister(void)
{
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 826e52def08..940edbf2fe8 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -53,14 +53,13 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
void **retyurn_value)
{
long *cap = context;
- acpi_handle h_dummy;
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) &&
- ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) {
+ if (acpi_has_method(handle, "_BCM") &&
+ acpi_has_method(handle, "_BCL")) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
"support\n"));
*cap |= ACPI_VIDEO_BACKLIGHT;
- if (ACPI_FAILURE(acpi_get_handle(handle, "_BQC", &h_dummy)))
+ if (!acpi_has_method(handle, "_BQC"))
printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
"cannot determine initial brightness\n");
/* We have backlight support, no need to scan further */
@@ -79,22 +78,20 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
*/
long acpi_is_video_device(acpi_handle handle)
{
- acpi_handle h_dummy;
long video_caps = 0;
/* Is this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_DOD", &h_dummy)) ||
- ACPI_SUCCESS(acpi_get_handle(handle, "_DOS", &h_dummy)))
+ if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS"))
video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
/* Is this device able to retrieve a video ROM ? */
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_ROM", &h_dummy)))
+ if (acpi_has_method(handle, "_ROM"))
video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
/* Is this device able to configure which video head to be POSTed ? */
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_VPO", &h_dummy)) &&
- ACPI_SUCCESS(acpi_get_handle(handle, "_GPD", &h_dummy)) &&
- ACPI_SUCCESS(acpi_get_handle(handle, "_SPD", &h_dummy)))
+ if (acpi_has_method(handle, "_VPO") &&
+ acpi_has_method(handle, "_GPD") &&
+ acpi_has_method(handle, "_SPD"))
video_caps |= ACPI_VIDEO_DEVICE_POSTING;
/* Only check for backlight functionality if one of the above hit. */
@@ -238,12 +235,7 @@ static void acpi_video_caps_check(void)
bool acpi_video_backlight_quirks(void)
{
- if (acpi_gbl_osi_data >= ACPI_OSI_WIN_8) {
- acpi_video_caps_check();
- acpi_video_support |= ACPI_VIDEO_SKIP_BACKLIGHT;
- return true;
- }
- return false;
+ return acpi_gbl_osi_data >= ACPI_OSI_WIN_8;
}
EXPORT_SYMBOL(acpi_video_backlight_quirks);
@@ -291,14 +283,6 @@ int acpi_video_backlight_support(void)
}
EXPORT_SYMBOL(acpi_video_backlight_support);
-/* For the ACPI video driver use only. */
-bool acpi_video_verify_backlight_support(void)
-{
- return (acpi_video_support & ACPI_VIDEO_SKIP_BACKLIGHT) ?
- false : acpi_video_backlight_support();
-}
-EXPORT_SYMBOL(acpi_video_verify_backlight_support);
-
/*
* Use acpi_backlight=vendor/video to force that backlight switching
* is processed by vendor specific acpi drivers or video.ko driver.
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 80dc988f01e..4e737728aee 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -97,6 +97,15 @@ config SATA_AHCI_PLATFORM
If unsure, say N.
+config AHCI_IMX
+ tristate "Freescale i.MX AHCI SATA support"
+ depends on SATA_AHCI_PLATFORM && MFD_SYSCON
+ help
+ This option enables support for the Freescale i.MX SoC's
+ onboard AHCI SATA.
+
+ If unsure, say N.
+
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC
@@ -107,7 +116,7 @@ config SATA_FSL
If unsure, say N.
config SATA_INIC162X
- tristate "Initio 162x SATA support"
+ tristate "Initio 162x SATA support (Very Experimental)"
depends on PCI
help
This option enables support for Initio 162x Serial ATA.
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index c04d0fd038a..46518c62246 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
+obj-$(CONFIG_AHCI_IMX) += ahci_imx.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 5064f3ea20f..db4380d7003 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1146,11 +1146,18 @@ int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
return rc;
for (i = 0; i < host->n_ports; i++) {
+ const char* desc;
struct ahci_port_priv *pp = host->ports[i]->private_data;
+ /* pp is NULL for dummy ports */
+ if (pp)
+ desc = pp->irq_desc;
+ else
+ desc = dev_driver_string(host->dev);
+
rc = devm_request_threaded_irq(host->dev,
irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
- pp->irq_desc, host->ports[i]);
+ desc, host->ports[i]);
if (rc)
goto out_free_irqs;
}
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
new file mode 100644
index 00000000000..58debb0acc3
--- /dev/null
+++ b/drivers/ata/ahci_imx.c
@@ -0,0 +1,236 @@
+/*
+ * Freescale IMX AHCI SATA platform driver
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/ahci_platform.h>
+#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include "ahci.h"
+
+enum {
+ HOST_TIMER1MS = 0xe0, /* Timer 1-ms */
+};
+
+struct imx_ahci_priv {
+ struct platform_device *ahci_pdev;
+ struct clk *sata_ref_clk;
+ struct clk *ahb_clk;
+ struct regmap *gpr;
+};
+
+static int imx6q_sata_init(struct device *dev, void __iomem *mmio)
+{
+ int ret = 0;
+ unsigned int reg_val;
+ struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+
+ imxpriv->gpr =
+ syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+ if (IS_ERR(imxpriv->gpr)) {
+ dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n");
+ return PTR_ERR(imxpriv->gpr);
+ }
+
+ ret = clk_prepare_enable(imxpriv->sata_ref_clk);
+ if (ret < 0) {
+ dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret);
+ return ret;
+ }
+
+ /*
+ * set PHY Paremeters, two steps to configure the GPR13,
+ * one write for rest of parameters, mask of first write
+ * is 0x07fffffd, and the other one write for setting
+ * the mpll_clk_en.
+ */
+ regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK
+ | IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK
+ | IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK
+ | IMX6Q_GPR13_SATA_SPD_MODE_MASK
+ | IMX6Q_GPR13_SATA_MPLL_SS_EN
+ | IMX6Q_GPR13_SATA_TX_ATTEN_MASK
+ | IMX6Q_GPR13_SATA_TX_BOOST_MASK
+ | IMX6Q_GPR13_SATA_TX_LVL_MASK
+ | IMX6Q_GPR13_SATA_TX_EDGE_RATE
+ , IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB
+ | IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M
+ | IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F
+ | IMX6Q_GPR13_SATA_SPD_MODE_3P0G
+ | IMX6Q_GPR13_SATA_MPLL_SS_EN
+ | IMX6Q_GPR13_SATA_TX_ATTEN_9_16
+ | IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB
+ | IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
+ regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+ usleep_range(100, 200);
+
+ /*
+ * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
+ * and IP vendor specific register HOST_TIMER1MS.
+ * Configure CAP_SSS (support stagered spin up).
+ * Implement the port0.
+ * Get the ahb clock rate, and configure the TIMER1MS register.
+ */
+ reg_val = readl(mmio + HOST_CAP);
+ if (!(reg_val & HOST_CAP_SSS)) {
+ reg_val |= HOST_CAP_SSS;
+ writel(reg_val, mmio + HOST_CAP);
+ }
+ reg_val = readl(mmio + HOST_PORTS_IMPL);
+ if (!(reg_val & 0x1)) {
+ reg_val |= 0x1;
+ writel(reg_val, mmio + HOST_PORTS_IMPL);
+ }
+
+ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+ writel(reg_val, mmio + HOST_TIMER1MS);
+
+ return 0;
+}
+
+static void imx6q_sata_exit(struct device *dev)
+{
+ struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+
+ regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+ !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+ clk_disable_unprepare(imxpriv->sata_ref_clk);
+}
+
+static struct ahci_platform_data imx6q_sata_pdata = {
+ .init = imx6q_sata_init,
+ .exit = imx6q_sata_exit,
+};
+
+static const struct of_device_id imx_ahci_of_match[] = {
+ { .compatible = "fsl,imx6q-ahci", .data = &imx6q_sata_pdata},
+ {},
+};
+MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
+
+static int imx_ahci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *mem, *irq, res[2];
+ const struct of_device_id *of_id;
+ const struct ahci_platform_data *pdata = NULL;
+ struct imx_ahci_priv *imxpriv;
+ struct device *ahci_dev;
+ struct platform_device *ahci_pdev;
+ int ret;
+
+ imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
+ if (!imxpriv) {
+ dev_err(dev, "can't alloc ahci_host_priv\n");
+ return -ENOMEM;
+ }
+
+ ahci_pdev = platform_device_alloc("ahci", -1);
+ if (!ahci_pdev)
+ return -ENODEV;
+
+ ahci_dev = &ahci_pdev->dev;
+ ahci_dev->parent = dev;
+
+ imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
+ if (IS_ERR(imxpriv->ahb_clk)) {
+ dev_err(dev, "can't get ahb clock.\n");
+ ret = PTR_ERR(imxpriv->ahb_clk);
+ goto err_out;
+ }
+
+ imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
+ if (IS_ERR(imxpriv->sata_ref_clk)) {
+ dev_err(dev, "can't get sata_ref clock.\n");
+ ret = PTR_ERR(imxpriv->sata_ref_clk);
+ goto err_out;
+ }
+
+ imxpriv->ahci_pdev = ahci_pdev;
+ platform_set_drvdata(pdev, imxpriv);
+
+ of_id = of_match_device(imx_ahci_of_match, dev);
+ if (of_id) {
+ pdata = of_id->data;
+ } else {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!mem || !irq) {
+ dev_err(dev, "no mmio/irq resource\n");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ res[0] = *mem;
+ res[1] = *irq;
+
+ ahci_dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask;
+ ahci_dev->of_node = dev->of_node;
+
+ ret = platform_device_add_resources(ahci_pdev, res, 2);
+ if (ret)
+ goto err_out;
+
+ ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata));
+ if (ret)
+ goto err_out;
+
+ ret = platform_device_add(ahci_pdev);
+ if (ret) {
+err_out:
+ platform_device_put(ahci_pdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx_ahci_remove(struct platform_device *pdev)
+{
+ struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev);
+ struct platform_device *ahci_pdev = imxpriv->ahci_pdev;
+
+ platform_device_unregister(ahci_pdev);
+ return 0;
+}
+
+static struct platform_driver imx_ahci_driver = {
+ .probe = imx_ahci_probe,
+ .remove = imx_ahci_remove,
+ .driver = {
+ .name = "ahci-imx",
+ .owner = THIS_MODULE,
+ .of_match_table = imx_ahci_of_match,
+ },
+};
+module_platform_driver(imx_ahci_driver);
+
+MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver");
+MODULE_AUTHOR("Richard Zhu <Hong-Xing.Zhu@freescale.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ahci:imx");
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index b52a10c8eeb..513ad7ed0c9 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -330,7 +330,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* SATA Controller IDE (Wellsburg) */
{ 0x8086, 0x8d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
/* SATA Controller IDE (Wellsburg) */
- { 0x8086, 0x8d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ { 0x8086, 0x8d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
/* SATA Controller IDE (Wellsburg) */
{ 0x8086, 0x8d60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
/* SATA Controller IDE (Wellsburg) */
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index cf4e7020ada..da8170dfc90 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -947,11 +947,11 @@ static void pata_acpi_set_state(struct ata_port *ap, pm_message_t state)
continue;
acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ?
- ACPI_STATE_D0 : ACPI_STATE_D3);
+ ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
}
if (!(state.event & PM_EVENT_RESUME))
- acpi_bus_set_power(port_handle, ACPI_STATE_D3);
+ acpi_bus_set_power(port_handle, ACPI_STATE_D3_COLD);
}
/**
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index 1c41722bb7e..20fd337a573 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -289,24 +289,24 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info)
/* Disable sending Early R_OK.
* With "cached read" HDD testing and multiple ports busy on a SATA
- * host controller, 3726 PMP will very rarely drop a deferred
+ * host controller, 3x26 PMP will very rarely drop a deferred
* R_OK that was intended for the host. Symptom will be all
* 5 drives under test will timeout, get reset, and recover.
*/
- if (vendor == 0x1095 && devid == 0x3726) {
+ if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
u32 reg;
err_mask = sata_pmp_read(&ap->link, PMP_GSCR_SII_POL, &reg);
if (err_mask) {
rc = -EIO;
- reason = "failed to read Sil3726 Private Register";
+ reason = "failed to read Sil3x26 Private Register";
goto fail;
}
reg &= ~0x1;
err_mask = sata_pmp_write(&ap->link, PMP_GSCR_SII_POL, reg);
if (err_mask) {
rc = -EIO;
- reason = "failed to write Sil3726 Private Register";
+ reason = "failed to write Sil3x26 Private Register";
goto fail;
}
}
@@ -383,8 +383,8 @@ static void sata_pmp_quirks(struct ata_port *ap)
u16 devid = sata_pmp_gscr_devid(gscr);
struct ata_link *link;
- if (vendor == 0x1095 && devid == 0x3726) {
- /* sil3726 quirks */
+ if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
+ /* sil3x26 quirks */
ata_for_each_link(link, ap, EDGE) {
/* link reports offline after LPM */
link->flags |= ATA_LFLAG_NO_LPM;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 83c08907e04..b1e880a3c3d 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -206,8 +206,10 @@ static ssize_t ata_scsi_park_store(struct device *device,
unsigned long flags;
int rc;
- rc = strict_strtol(buf, 10, &input);
- if (rc || input < -2)
+ rc = kstrtol(buf, 10, &input);
+ if (rc)
+ return rc;
+ if (input < -2)
return -EINVAL;
if (input > ATA_TMOUT_MAX_PARK) {
rc = -EOVERFLOW;
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c
index 4ec7c04b3f8..26386f0b89a 100644
--- a/drivers/ata/pata_imx.c
+++ b/drivers/ata/pata_imx.c
@@ -237,6 +237,7 @@ static const struct of_device_id imx_pata_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, imx_pata_dt_ids);
static struct platform_driver pata_imx_driver = {
.probe = pata_imx_probe,
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 19720a0a4a6..851bd3f43ac 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -293,6 +293,7 @@ static void fsl_sata_set_irq_coalescing(struct ata_host *host,
{
struct sata_fsl_host_priv *host_priv = host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
+ unsigned long flags;
if (count > ICC_MAX_INT_COUNT_THRESHOLD)
count = ICC_MAX_INT_COUNT_THRESHOLD;
@@ -305,12 +306,12 @@ static void fsl_sata_set_irq_coalescing(struct ata_host *host,
(count > ICC_MIN_INT_COUNT_THRESHOLD))
ticks = ICC_SAFE_INT_TICKS;
- spin_lock(&host->lock);
+ spin_lock_irqsave(&host->lock, flags);
iowrite32((count << 24 | ticks), hcr_base + ICC);
intr_coalescing_count = count;
intr_coalescing_ticks = ticks;
- spin_unlock(&host->lock);
+ spin_unlock_irqrestore(&host->lock, flags);
DPRINTK("interrupt coalescing, count = 0x%x, ticks = %x\n",
intr_coalescing_count, intr_coalescing_ticks);
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index d047d92a456..e9a4f46d962 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -86,11 +86,11 @@ struct ecx_plat_data {
#define SGPIO_SIGNALS 3
#define ECX_ACTIVITY_BITS 0x300000
-#define ECX_ACTIVITY_SHIFT 2
+#define ECX_ACTIVITY_SHIFT 0
#define ECX_LOCATE_BITS 0x80000
#define ECX_LOCATE_SHIFT 1
#define ECX_FAULT_BITS 0x400000
-#define ECX_FAULT_SHIFT 0
+#define ECX_FAULT_SHIFT 2
static inline int sgpio_bit_shift(struct ecx_plat_data *pdata, u32 port,
u32 shift)
{
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index e4513174824..5c54d957370 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -6,6 +6,18 @@
*
* This file is released under GPL v2.
*
+ * **** WARNING ****
+ *
+ * This driver never worked properly and unfortunately data corruption is
+ * relatively common. There isn't anyone working on the driver and there's
+ * no support from the vendor. Do not use this driver in any production
+ * environment.
+ *
+ * http://thread.gmane.org/gmane.linux.debian.devel.bugs.rc/378525/focus=54491
+ * https://bugzilla.kernel.org/show_bug.cgi?id=60565
+ *
+ * *****************
+ *
* This controller is eccentric and easily locks up if something isn't
* right. Documentation is available at initio's website but it only
* documents registers (not programming model).
@@ -807,6 +819,8 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ata_print_version_once(&pdev->dev, DRV_VERSION);
+ dev_alert(&pdev->dev, "inic162x support is broken with common data corruption issues and will be disabled by default, contact linux-ide@vger.kernel.org if in production use\n");
+
/* alloc host */
host = ata_host_alloc_pinfo(&pdev->dev, ppi, NR_PORTS);
hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
diff --git a/drivers/base/base.h b/drivers/base/base.h
index b8bdfe61daa..2cbc6774f4c 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -119,6 +119,16 @@ static inline int driver_match_device(struct device_driver *drv,
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
+extern int driver_add_groups(struct device_driver *drv,
+ const struct attribute_group **groups);
+extern void driver_remove_groups(struct device_driver *drv,
+ const struct attribute_group **groups);
+
+extern int device_add_groups(struct device *dev,
+ const struct attribute_group **groups);
+extern void device_remove_groups(struct device *dev,
+ const struct attribute_group **groups);
+
extern char *make_class_name(const char *name, struct kobject *kobj);
extern int devres_release_all(struct device *dev);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index d414331b480..4c289ab9135 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include "base.h"
#include "power/power.h"
@@ -165,8 +166,8 @@ static const struct kset_uevent_ops bus_uevent_ops = {
static struct kset *bus_kset;
/* Manually detach a device from its associated driver. */
-static ssize_t driver_unbind(struct device_driver *drv,
- const char *buf, size_t count)
+static ssize_t unbind_store(struct device_driver *drv, const char *buf,
+ size_t count)
{
struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
@@ -185,15 +186,15 @@ static ssize_t driver_unbind(struct device_driver *drv,
bus_put(bus);
return err;
}
-static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
+static DRIVER_ATTR_WO(unbind);
/*
* Manually attach a device to a driver.
* Note: the driver must want to bind to the device,
* it is not possible to override the driver's id table.
*/
-static ssize_t driver_bind(struct device_driver *drv,
- const char *buf, size_t count)
+static ssize_t bind_store(struct device_driver *drv, const char *buf,
+ size_t count)
{
struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
@@ -221,7 +222,7 @@ static ssize_t driver_bind(struct device_driver *drv,
bus_put(bus);
return err;
}
-static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
+static DRIVER_ATTR_WO(bind);
static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
{
@@ -460,7 +461,7 @@ static int device_add_attrs(struct bus_type *bus, struct device *dev)
if (!bus->dev_attrs)
return 0;
- for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
+ for (i = 0; bus->dev_attrs[i].attr.name; i++) {
error = device_create_file(dev, &bus->dev_attrs[i]);
if (error) {
while (--i >= 0)
@@ -476,7 +477,7 @@ static void device_remove_attrs(struct bus_type *bus, struct device *dev)
int i;
if (bus->dev_attrs) {
- for (i = 0; attr_name(bus->dev_attrs[i]); i++)
+ for (i = 0; bus->dev_attrs[i].attr.name; i++)
device_remove_file(dev, &bus->dev_attrs[i]);
}
}
@@ -499,6 +500,9 @@ int bus_add_device(struct device *dev)
error = device_add_attrs(bus, dev);
if (error)
goto out_put;
+ error = device_add_groups(dev, bus->dev_groups);
+ if (error)
+ goto out_groups;
error = sysfs_create_link(&bus->p->devices_kset->kobj,
&dev->kobj, dev_name(dev));
if (error)
@@ -513,6 +517,8 @@ int bus_add_device(struct device *dev)
out_subsys:
sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
+out_groups:
+ device_remove_groups(dev, bus->dev_groups);
out_id:
device_remove_attrs(bus, dev);
out_put:
@@ -575,6 +581,7 @@ void bus_remove_device(struct device *dev)
sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
dev_name(dev));
device_remove_attrs(dev->bus, dev);
+ device_remove_groups(dev, dev->bus->dev_groups);
if (klist_node_attached(&dev->p->knode_bus))
klist_del(&dev->p->knode_bus);
@@ -590,7 +597,7 @@ static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv)
int i;
if (bus->drv_attrs) {
- for (i = 0; attr_name(bus->drv_attrs[i]); i++) {
+ for (i = 0; bus->drv_attrs[i].attr.name; i++) {
error = driver_create_file(drv, &bus->drv_attrs[i]);
if (error)
goto err;
@@ -610,7 +617,7 @@ static void driver_remove_attrs(struct bus_type *bus,
int i;
if (bus->drv_attrs) {
- for (i = 0; attr_name(bus->drv_attrs[i]); i++)
+ for (i = 0; bus->drv_attrs[i].attr.name; i++)
driver_remove_file(drv, &bus->drv_attrs[i]);
}
}
@@ -659,8 +666,8 @@ static void remove_probe_files(struct bus_type *bus)
bus_remove_file(bus, &bus_attr_drivers_probe);
}
-static ssize_t driver_uevent_store(struct device_driver *drv,
- const char *buf, size_t count)
+static ssize_t uevent_store(struct device_driver *drv, const char *buf,
+ size_t count)
{
enum kobject_action action;
@@ -668,7 +675,7 @@ static ssize_t driver_uevent_store(struct device_driver *drv,
kobject_uevent(&drv->p->kobj, action);
return count;
}
-static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
+static DRIVER_ATTR_WO(uevent);
/**
* bus_add_driver - Add a driver to the bus.
@@ -719,6 +726,10 @@ int bus_add_driver(struct device_driver *drv)
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__func__, drv->name);
}
+ error = driver_add_groups(drv, bus->drv_groups);
+ if (error)
+ printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
+ __func__, drv->name);
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
@@ -756,6 +767,7 @@ void bus_remove_driver(struct device_driver *drv)
if (!drv->suppress_bind_attrs)
remove_bind_files(drv);
driver_remove_attrs(drv->bus, drv);
+ driver_remove_groups(drv, drv->bus->drv_groups);
driver_remove_file(drv, &driver_attr_uevent);
klist_remove(&drv->p->knode_bus);
pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name);
@@ -846,7 +858,7 @@ static int bus_add_attrs(struct bus_type *bus)
int i;
if (bus->bus_attrs) {
- for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
+ for (i = 0; bus->bus_attrs[i].attr.name; i++) {
error = bus_create_file(bus, &bus->bus_attrs[i]);
if (error)
goto err;
@@ -865,11 +877,23 @@ static void bus_remove_attrs(struct bus_type *bus)
int i;
if (bus->bus_attrs) {
- for (i = 0; attr_name(bus->bus_attrs[i]); i++)
+ for (i = 0; bus->bus_attrs[i].attr.name; i++)
bus_remove_file(bus, &bus->bus_attrs[i]);
}
}
+static int bus_add_groups(struct bus_type *bus,
+ const struct attribute_group **groups)
+{
+ return sysfs_create_groups(&bus->p->subsys.kobj, groups);
+}
+
+static void bus_remove_groups(struct bus_type *bus,
+ const struct attribute_group **groups)
+{
+ sysfs_remove_groups(&bus->p->subsys.kobj, groups);
+}
+
static void klist_devices_get(struct klist_node *n)
{
struct device_private *dev_prv = to_device_private_bus(n);
@@ -962,10 +986,15 @@ int bus_register(struct bus_type *bus)
retval = bus_add_attrs(bus);
if (retval)
goto bus_attrs_fail;
+ retval = bus_add_groups(bus, bus->bus_groups);
+ if (retval)
+ goto bus_groups_fail;
pr_debug("bus: '%s': registered\n", bus->name);
return 0;
+bus_groups_fail:
+ bus_remove_attrs(bus);
bus_attrs_fail:
remove_probe_files(bus);
bus_probe_files_fail:
@@ -996,6 +1025,7 @@ void bus_unregister(struct bus_type *bus)
if (bus->dev_root)
device_unregister(bus->dev_root);
bus_remove_attrs(bus);
+ bus_remove_groups(bus, bus->bus_groups);
remove_probe_files(bus);
kset_unregister(bus->p->drivers_kset);
kset_unregister(bus->p->devices_kset);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 3ce84547132..8b7818b8005 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -135,7 +135,7 @@ static int add_class_attrs(struct class *cls)
int error = 0;
if (cls->class_attrs) {
- for (i = 0; attr_name(cls->class_attrs[i]); i++) {
+ for (i = 0; cls->class_attrs[i].attr.name; i++) {
error = class_create_file(cls, &cls->class_attrs[i]);
if (error)
goto error;
@@ -154,7 +154,7 @@ static void remove_class_attrs(struct class *cls)
int i;
if (cls->class_attrs) {
- for (i = 0; attr_name(cls->class_attrs[i]); i++)
+ for (i = 0; cls->class_attrs[i].attr.name; i++)
class_remove_file(cls, &cls->class_attrs[i]);
}
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 8856d74545d..c7cfadcf675 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -26,6 +26,7 @@
#include <linux/async.h>
#include <linux/pm_runtime.h>
#include <linux/netdevice.h>
+#include <linux/sysfs.h>
#include "base.h"
#include "power/power.h"
@@ -36,9 +37,9 @@ long sysfs_deprecated = 1;
#else
long sysfs_deprecated = 0;
#endif
-static __init int sysfs_deprecated_setup(char *arg)
+static int __init sysfs_deprecated_setup(char *arg)
{
- return strict_strtol(arg, 10, &sysfs_deprecated);
+ return kstrtol(arg, 10, &sysfs_deprecated);
}
early_param("sysfs.deprecated", sysfs_deprecated_setup);
#endif
@@ -49,6 +50,28 @@ static struct kobject *dev_kobj;
struct kobject *sysfs_dev_char_kobj;
struct kobject *sysfs_dev_block_kobj;
+static DEFINE_MUTEX(device_hotplug_lock);
+
+void lock_device_hotplug(void)
+{
+ mutex_lock(&device_hotplug_lock);
+}
+
+void unlock_device_hotplug(void)
+{
+ mutex_unlock(&device_hotplug_lock);
+}
+
+int lock_device_hotplug_sysfs(void)
+{
+ if (mutex_trylock(&device_hotplug_lock))
+ return 0;
+
+ /* Avoid busy looping (5 ms of sleep should do). */
+ msleep(5);
+ return restart_syscall();
+}
+
#ifdef CONFIG_BLOCK
static inline int device_is_not_partition(struct device *dev)
{
@@ -345,7 +368,7 @@ static const struct kset_uevent_ops device_uevent_ops = {
.uevent = dev_uevent,
};
-static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
+static ssize_t uevent_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct kobject *top_kobj;
@@ -388,7 +411,7 @@ out:
return count;
}
-static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
+static ssize_t uevent_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
enum kobject_action action;
@@ -399,22 +422,20 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
dev_err(dev, "uevent: unknown action-string\n");
return count;
}
+static DEVICE_ATTR_RW(uevent);
-static struct device_attribute uevent_attr =
- __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
-
-static ssize_t show_online(struct device *dev, struct device_attribute *attr,
+static ssize_t online_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
bool val;
- lock_device_hotplug();
+ device_lock(dev);
val = !dev->offline;
- unlock_device_hotplug();
+ device_unlock(dev);
return sprintf(buf, "%u\n", val);
}
-static ssize_t store_online(struct device *dev, struct device_attribute *attr,
+static ssize_t online_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
bool val;
@@ -424,14 +445,15 @@ static ssize_t store_online(struct device *dev, struct device_attribute *attr,
if (ret < 0)
return ret;
- lock_device_hotplug();
+ ret = lock_device_hotplug_sysfs();
+ if (ret)
+ return ret;
+
ret = val ? device_online(dev) : device_offline(dev);
unlock_device_hotplug();
return ret < 0 ? ret : count;
}
-
-static struct device_attribute online_attr =
- __ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online);
+static DEVICE_ATTR_RW(online);
static int device_add_attributes(struct device *dev,
struct device_attribute *attrs)
@@ -440,7 +462,7 @@ static int device_add_attributes(struct device *dev,
int i;
if (attrs) {
- for (i = 0; attr_name(attrs[i]); i++) {
+ for (i = 0; attrs[i].attr.name; i++) {
error = device_create_file(dev, &attrs[i]);
if (error)
break;
@@ -458,7 +480,7 @@ static void device_remove_attributes(struct device *dev,
int i;
if (attrs)
- for (i = 0; attr_name(attrs[i]); i++)
+ for (i = 0; attrs[i].attr.name; i++)
device_remove_file(dev, &attrs[i]);
}
@@ -469,7 +491,7 @@ static int device_add_bin_attributes(struct device *dev,
int i;
if (attrs) {
- for (i = 0; attr_name(attrs[i]); i++) {
+ for (i = 0; attrs[i].attr.name; i++) {
error = device_create_bin_file(dev, &attrs[i]);
if (error)
break;
@@ -487,38 +509,19 @@ static void device_remove_bin_attributes(struct device *dev,
int i;
if (attrs)
- for (i = 0; attr_name(attrs[i]); i++)
+ for (i = 0; attrs[i].attr.name; i++)
device_remove_bin_file(dev, &attrs[i]);
}
-static int device_add_groups(struct device *dev,
- const struct attribute_group **groups)
+int device_add_groups(struct device *dev, const struct attribute_group **groups)
{
- int error = 0;
- int i;
-
- if (groups) {
- for (i = 0; groups[i]; i++) {
- error = sysfs_create_group(&dev->kobj, groups[i]);
- if (error) {
- while (--i >= 0)
- sysfs_remove_group(&dev->kobj,
- groups[i]);
- break;
- }
- }
- }
- return error;
+ return sysfs_create_groups(&dev->kobj, groups);
}
-static void device_remove_groups(struct device *dev,
- const struct attribute_group **groups)
+void device_remove_groups(struct device *dev,
+ const struct attribute_group **groups)
{
- int i;
-
- if (groups)
- for (i = 0; groups[i]; i++)
- sysfs_remove_group(&dev->kobj, groups[i]);
+ sysfs_remove_groups(&dev->kobj, groups);
}
static int device_add_attrs(struct device *dev)
@@ -550,7 +553,7 @@ static int device_add_attrs(struct device *dev)
goto err_remove_type_groups;
if (device_supports_offline(dev) && !dev->offline_disabled) {
- error = device_create_file(dev, &online_attr);
+ error = device_create_file(dev, &dev_attr_online);
if (error)
goto err_remove_type_groups;
}
@@ -578,7 +581,7 @@ static void device_remove_attrs(struct device *dev)
struct class *class = dev->class;
const struct device_type *type = dev->type;
- device_remove_file(dev, &online_attr);
+ device_remove_file(dev, &dev_attr_online);
device_remove_groups(dev, dev->groups);
if (type)
@@ -591,15 +594,12 @@ static void device_remove_attrs(struct device *dev)
}
}
-
-static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
+static ssize_t dev_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return print_dev_t(buf, dev->devt);
}
-
-static struct device_attribute devt_attr =
- __ATTR(dev, S_IRUGO, show_dev, NULL);
+static DEVICE_ATTR_RO(dev);
/* /sys/devices/ */
struct kset *devices_kset;
@@ -626,6 +626,7 @@ int device_create_file(struct device *dev,
return error;
}
+EXPORT_SYMBOL_GPL(device_create_file);
/**
* device_remove_file - remove sysfs attribute file.
@@ -638,6 +639,7 @@ void device_remove_file(struct device *dev,
if (dev)
sysfs_remove_file(&dev->kobj, &attr->attr);
}
+EXPORT_SYMBOL_GPL(device_remove_file);
/**
* device_create_bin_file - create sysfs binary attribute file for device.
@@ -748,6 +750,7 @@ void device_initialize(struct device *dev)
device_pm_init(dev);
set_dev_node(dev, -1);
}
+EXPORT_SYMBOL_GPL(device_initialize);
struct kobject *virtual_device_parent(struct device *dev)
{
@@ -1100,12 +1103,12 @@ int device_add(struct device *dev)
if (platform_notify)
platform_notify(dev);
- error = device_create_file(dev, &uevent_attr);
+ error = device_create_file(dev, &dev_attr_uevent);
if (error)
goto attrError;
if (MAJOR(dev->devt)) {
- error = device_create_file(dev, &devt_attr);
+ error = device_create_file(dev, &dev_attr_dev);
if (error)
goto ueventattrError;
@@ -1172,9 +1175,9 @@ done:
device_remove_sys_dev_entry(dev);
devtattrError:
if (MAJOR(dev->devt))
- device_remove_file(dev, &devt_attr);
+ device_remove_file(dev, &dev_attr_dev);
ueventattrError:
- device_remove_file(dev, &uevent_attr);
+ device_remove_file(dev, &dev_attr_uevent);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
@@ -1187,6 +1190,7 @@ name_error:
dev->p = NULL;
goto done;
}
+EXPORT_SYMBOL_GPL(device_add);
/**
* device_register - register a device with the system.
@@ -1211,6 +1215,7 @@ int device_register(struct device *dev)
device_initialize(dev);
return device_add(dev);
}
+EXPORT_SYMBOL_GPL(device_register);
/**
* get_device - increment reference count for device.
@@ -1224,6 +1229,7 @@ struct device *get_device(struct device *dev)
{
return dev ? kobj_to_dev(kobject_get(&dev->kobj)) : NULL;
}
+EXPORT_SYMBOL_GPL(get_device);
/**
* put_device - decrement reference count.
@@ -1235,6 +1241,7 @@ void put_device(struct device *dev)
if (dev)
kobject_put(&dev->kobj);
}
+EXPORT_SYMBOL_GPL(put_device);
/**
* device_del - delete device from system.
@@ -1266,7 +1273,7 @@ void device_del(struct device *dev)
if (MAJOR(dev->devt)) {
devtmpfs_delete_node(dev);
device_remove_sys_dev_entry(dev);
- device_remove_file(dev, &devt_attr);
+ device_remove_file(dev, &dev_attr_dev);
}
if (dev->class) {
device_remove_class_symlinks(dev);
@@ -1281,7 +1288,7 @@ void device_del(struct device *dev)
klist_del(&dev->knode_class);
mutex_unlock(&dev->class->p->mutex);
}
- device_remove_file(dev, &uevent_attr);
+ device_remove_file(dev, &dev_attr_uevent);
device_remove_attrs(dev);
bus_remove_device(dev);
device_pm_remove(dev);
@@ -1297,6 +1304,7 @@ void device_del(struct device *dev)
kobject_del(&dev->kobj);
put_device(parent);
}
+EXPORT_SYMBOL_GPL(device_del);
/**
* device_unregister - unregister device from system.
@@ -1315,6 +1323,7 @@ void device_unregister(struct device *dev)
device_del(dev);
put_device(dev);
}
+EXPORT_SYMBOL_GPL(device_unregister);
static struct device *next_device(struct klist_iter *i)
{
@@ -1403,6 +1412,7 @@ int device_for_each_child(struct device *parent, void *data,
klist_iter_exit(&i);
return error;
}
+EXPORT_SYMBOL_GPL(device_for_each_child);
/**
* device_find_child - device iterator for locating a particular device.
@@ -1437,6 +1447,7 @@ struct device *device_find_child(struct device *parent, void *data,
klist_iter_exit(&i);
return child;
}
+EXPORT_SYMBOL_GPL(device_find_child);
int __init devices_init(void)
{
@@ -1464,33 +1475,6 @@ int __init devices_init(void)
return -ENOMEM;
}
-EXPORT_SYMBOL_GPL(device_for_each_child);
-EXPORT_SYMBOL_GPL(device_find_child);
-
-EXPORT_SYMBOL_GPL(device_initialize);
-EXPORT_SYMBOL_GPL(device_add);
-EXPORT_SYMBOL_GPL(device_register);
-
-EXPORT_SYMBOL_GPL(device_del);
-EXPORT_SYMBOL_GPL(device_unregister);
-EXPORT_SYMBOL_GPL(get_device);
-EXPORT_SYMBOL_GPL(put_device);
-
-EXPORT_SYMBOL_GPL(device_create_file);
-EXPORT_SYMBOL_GPL(device_remove_file);
-
-static DEFINE_MUTEX(device_hotplug_lock);
-
-void lock_device_hotplug(void)
-{
- mutex_lock(&device_hotplug_lock);
-}
-
-void unlock_device_hotplug(void)
-{
- mutex_unlock(&device_hotplug_lock);
-}
-
static int device_check_offline(struct device *dev, void *not_used)
{
int ret;
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 4c358bc44c7..848ebbd2571 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/percpu.h>
#include <linux/acpi.h>
+#include <linux/of.h>
#include "base.h"
@@ -43,11 +44,14 @@ static int __ref cpu_subsys_online(struct device *dev)
struct cpu *cpu = container_of(dev, struct cpu, dev);
int cpuid = dev->id;
int from_nid, to_nid;
- int ret;
+ int ret = -ENODEV;
cpu_hotplug_driver_lock();
from_nid = cpu_to_node(cpuid);
+ if (from_nid == NUMA_NO_NODE)
+ goto out;
+
ret = cpu_up(cpuid);
/*
* When hot adding memory to memoryless node and enabling a cpu
@@ -57,6 +61,7 @@ static int __ref cpu_subsys_online(struct device *dev)
if (from_nid != to_nid)
change_cpu_under_node(cpu, from_nid, to_nid);
+ out:
cpu_hotplug_driver_unlock();
return ret;
}
@@ -289,6 +294,7 @@ int register_cpu(struct cpu *cpu, int num)
cpu->dev.release = cpu_device_release;
cpu->dev.offline_disabled = !cpu->hotpluggable;
cpu->dev.offline = !cpu_online(num);
+ cpu->dev.of_node = of_get_cpu_node(num, NULL);
#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
cpu->dev.bus->uevent = arch_cpu_uevent;
#endif
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 0ca54421ce9..6c9cdaa9200 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -134,7 +134,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
static DEFINE_MUTEX(cma_mutex);
-static __init int cma_activate_area(unsigned long base_pfn, unsigned long count)
+static int __init cma_activate_area(unsigned long base_pfn, unsigned long count)
{
unsigned long pfn = base_pfn;
unsigned i = count >> pageblock_order;
@@ -156,7 +156,7 @@ static __init int cma_activate_area(unsigned long base_pfn, unsigned long count)
return 0;
}
-static __init struct cma *cma_create_area(unsigned long base_pfn,
+static struct cma * __init cma_create_area(unsigned long base_pfn,
unsigned long count)
{
int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 974e301a1ef..9e29943e56c 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -15,6 +15,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/sysfs.h>
#include "base.h"
static struct device *next_device(struct klist_iter *i)
@@ -123,34 +124,16 @@ void driver_remove_file(struct device_driver *drv,
}
EXPORT_SYMBOL_GPL(driver_remove_file);
-static int driver_add_groups(struct device_driver *drv,
- const struct attribute_group **groups)
+int driver_add_groups(struct device_driver *drv,
+ const struct attribute_group **groups)
{
- int error = 0;
- int i;
-
- if (groups) {
- for (i = 0; groups[i]; i++) {
- error = sysfs_create_group(&drv->p->kobj, groups[i]);
- if (error) {
- while (--i >= 0)
- sysfs_remove_group(&drv->p->kobj,
- groups[i]);
- break;
- }
- }
- }
- return error;
+ return sysfs_create_groups(&drv->p->kobj, groups);
}
-static void driver_remove_groups(struct device_driver *drv,
- const struct attribute_group **groups)
+void driver_remove_groups(struct device_driver *drv,
+ const struct attribute_group **groups)
{
- int i;
-
- if (groups)
- for (i = 0; groups[i]; i++)
- sysfs_remove_group(&drv->p->kobj, groups[i]);
+ sysfs_remove_groups(&drv->p->kobj, groups);
}
/**
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index a439602ea91..10a4467c63f 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -486,9 +486,8 @@ static struct notifier_block fw_shutdown_nb = {
.notifier_call = fw_shutdown_notify,
};
-static ssize_t firmware_timeout_show(struct class *class,
- struct class_attribute *attr,
- char *buf)
+static ssize_t timeout_show(struct class *class, struct class_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%d\n", loading_timeout);
}
@@ -506,9 +505,8 @@ static ssize_t firmware_timeout_show(struct class *class,
*
* Note: zero means 'wait forever'.
**/
-static ssize_t firmware_timeout_store(struct class *class,
- struct class_attribute *attr,
- const char *buf, size_t count)
+static ssize_t timeout_store(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t count)
{
loading_timeout = simple_strtol(buf, NULL, 10);
if (loading_timeout < 0)
@@ -518,8 +516,7 @@ static ssize_t firmware_timeout_store(struct class *class,
}
static struct class_attribute firmware_class_attrs[] = {
- __ATTR(timeout, S_IWUSR | S_IRUGO,
- firmware_timeout_show, firmware_timeout_store),
+ __ATTR_RW(timeout),
__ATTR_NULL
};
@@ -868,8 +865,15 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
goto err_del_dev;
}
+ mutex_lock(&fw_lock);
+ list_add(&buf->pending_list, &pending_fw_head);
+ mutex_unlock(&fw_lock);
+
retval = device_create_file(f_dev, &dev_attr_loading);
if (retval) {
+ mutex_lock(&fw_lock);
+ list_del_init(&buf->pending_list);
+ mutex_unlock(&fw_lock);
dev_err(f_dev, "%s: device_create_file failed\n", __func__);
goto err_del_bin_attr;
}
@@ -884,10 +888,6 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
}
- mutex_lock(&fw_lock);
- list_add(&buf->pending_list, &pending_fw_head);
- mutex_unlock(&fw_lock);
-
wait_for_completion(&buf->completion);
cancel_delayed_work_sync(&fw_priv->timeout_work);
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 2b7813ec6d0..9e59f6535c4 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -16,7 +16,6 @@
#include <linux/capability.h>
#include <linux/device.h>
#include <linux/memory.h>
-#include <linux/kobject.h>
#include <linux/memory_hotplug.h>
#include <linux/mm.h>
#include <linux/mutex.h>
@@ -30,6 +29,8 @@ static DEFINE_MUTEX(mem_sysfs_mutex);
#define MEMORY_CLASS_NAME "memory"
+#define to_memory_block(dev) container_of(dev, struct memory_block, dev)
+
static int sections_per_block;
static inline int base_memory_block_id(int section_nr)
@@ -77,7 +78,7 @@ EXPORT_SYMBOL(unregister_memory_isolate_notifier);
static void memory_block_release(struct device *dev)
{
- struct memory_block *mem = container_of(dev, struct memory_block, dev);
+ struct memory_block *mem = to_memory_block(dev);
kfree(mem);
}
@@ -110,8 +111,7 @@ static unsigned long get_memory_block_size(void)
static ssize_t show_mem_start_phys_index(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct memory_block *mem =
- container_of(dev, struct memory_block, dev);
+ struct memory_block *mem = to_memory_block(dev);
unsigned long phys_index;
phys_index = mem->start_section_nr / sections_per_block;
@@ -121,8 +121,7 @@ static ssize_t show_mem_start_phys_index(struct device *dev,
static ssize_t show_mem_end_phys_index(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct memory_block *mem =
- container_of(dev, struct memory_block, dev);
+ struct memory_block *mem = to_memory_block(dev);
unsigned long phys_index;
phys_index = mem->end_section_nr / sections_per_block;
@@ -137,10 +136,11 @@ static ssize_t show_mem_removable(struct device *dev,
{
unsigned long i, pfn;
int ret = 1;
- struct memory_block *mem =
- container_of(dev, struct memory_block, dev);
+ struct memory_block *mem = to_memory_block(dev);
for (i = 0; i < sections_per_block; i++) {
+ if (!present_section_nr(mem->start_section_nr + i))
+ continue;
pfn = section_nr_to_pfn(mem->start_section_nr + i);
ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
}
@@ -154,8 +154,7 @@ static ssize_t show_mem_removable(struct device *dev,
static ssize_t show_mem_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct memory_block *mem =
- container_of(dev, struct memory_block, dev);
+ struct memory_block *mem = to_memory_block(dev);
ssize_t len = 0;
/*
@@ -261,9 +260,8 @@ memory_block_action(unsigned long phys_index, unsigned long action, int online_t
return ret;
}
-static int __memory_block_change_state(struct memory_block *mem,
- unsigned long to_state, unsigned long from_state_req,
- int online_type)
+static int memory_block_change_state(struct memory_block *mem,
+ unsigned long to_state, unsigned long from_state_req)
{
int ret = 0;
@@ -273,105 +271,91 @@ static int __memory_block_change_state(struct memory_block *mem,
if (to_state == MEM_OFFLINE)
mem->state = MEM_GOING_OFFLINE;
- ret = memory_block_action(mem->start_section_nr, to_state, online_type);
+ ret = memory_block_action(mem->start_section_nr, to_state,
+ mem->online_type);
+
mem->state = ret ? from_state_req : to_state;
+
return ret;
}
+/* The device lock serializes operations on memory_subsys_[online|offline] */
static int memory_subsys_online(struct device *dev)
{
- struct memory_block *mem = container_of(dev, struct memory_block, dev);
+ struct memory_block *mem = to_memory_block(dev);
int ret;
- mutex_lock(&mem->state_mutex);
+ if (mem->state == MEM_ONLINE)
+ return 0;
- ret = mem->state == MEM_ONLINE ? 0 :
- __memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE,
- ONLINE_KEEP);
-
- mutex_unlock(&mem->state_mutex);
- return ret;
-}
-
-static int memory_subsys_offline(struct device *dev)
-{
- struct memory_block *mem = container_of(dev, struct memory_block, dev);
- int ret;
+ /*
+ * If we are called from store_mem_state(), online_type will be
+ * set >= 0 Otherwise we were called from the device online
+ * attribute and need to set the online_type.
+ */
+ if (mem->online_type < 0)
+ mem->online_type = ONLINE_KEEP;
- mutex_lock(&mem->state_mutex);
+ ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
- ret = mem->state == MEM_OFFLINE ? 0 :
- __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1);
+ /* clear online_type */
+ mem->online_type = -1;
- mutex_unlock(&mem->state_mutex);
return ret;
}
-static int __memory_block_change_state_uevent(struct memory_block *mem,
- unsigned long to_state, unsigned long from_state_req,
- int online_type)
-{
- int ret = __memory_block_change_state(mem, to_state, from_state_req,
- online_type);
- if (!ret) {
- switch (mem->state) {
- case MEM_OFFLINE:
- kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE);
- break;
- case MEM_ONLINE:
- kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE);
- break;
- default:
- break;
- }
- }
- return ret;
-}
-
-static int memory_block_change_state(struct memory_block *mem,
- unsigned long to_state, unsigned long from_state_req,
- int online_type)
+static int memory_subsys_offline(struct device *dev)
{
- int ret;
+ struct memory_block *mem = to_memory_block(dev);
- mutex_lock(&mem->state_mutex);
- ret = __memory_block_change_state_uevent(mem, to_state, from_state_req,
- online_type);
- mutex_unlock(&mem->state_mutex);
+ if (mem->state == MEM_OFFLINE)
+ return 0;
- return ret;
+ return memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
}
+
static ssize_t
store_mem_state(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct memory_block *mem;
- bool offline;
- int ret = -EINVAL;
-
- mem = container_of(dev, struct memory_block, dev);
-
- lock_device_hotplug();
-
- if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) {
- offline = false;
- ret = memory_block_change_state(mem, MEM_ONLINE,
- MEM_OFFLINE, ONLINE_KERNEL);
- } else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) {
- offline = false;
- ret = memory_block_change_state(mem, MEM_ONLINE,
- MEM_OFFLINE, ONLINE_MOVABLE);
- } else if (!strncmp(buf, "online", min_t(int, count, 6))) {
- offline = false;
- ret = memory_block_change_state(mem, MEM_ONLINE,
- MEM_OFFLINE, ONLINE_KEEP);
- } else if(!strncmp(buf, "offline", min_t(int, count, 7))) {
- offline = true;
- ret = memory_block_change_state(mem, MEM_OFFLINE,
- MEM_ONLINE, -1);
+ struct memory_block *mem = to_memory_block(dev);
+ int ret, online_type;
+
+ ret = lock_device_hotplug_sysfs();
+ if (ret)
+ return ret;
+
+ if (!strncmp(buf, "online_kernel", min_t(int, count, 13)))
+ online_type = ONLINE_KERNEL;
+ else if (!strncmp(buf, "online_movable", min_t(int, count, 14)))
+ online_type = ONLINE_MOVABLE;
+ else if (!strncmp(buf, "online", min_t(int, count, 6)))
+ online_type = ONLINE_KEEP;
+ else if (!strncmp(buf, "offline", min_t(int, count, 7)))
+ online_type = -1;
+ else
+ return -EINVAL;
+
+ switch (online_type) {
+ case ONLINE_KERNEL:
+ case ONLINE_MOVABLE:
+ case ONLINE_KEEP:
+ /*
+ * mem->online_type is not protected so there can be a
+ * race here. However, when racing online, the first
+ * will succeed and the second will just return as the
+ * block will already be online. The online type
+ * could be either one, but that is expected.
+ */
+ mem->online_type = online_type;
+ ret = device_online(&mem->dev);
+ break;
+ case -1:
+ ret = device_offline(&mem->dev);
+ break;
+ default:
+ ret = -EINVAL; /* should never happen */
}
- if (!ret)
- dev->offline = offline;
unlock_device_hotplug();
@@ -392,8 +376,7 @@ store_mem_state(struct device *dev,
static ssize_t show_phys_device(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct memory_block *mem =
- container_of(dev, struct memory_block, dev);
+ struct memory_block *mem = to_memory_block(dev);
return sprintf(buf, "%d\n", mem->phys_device);
}
@@ -469,7 +452,7 @@ store_soft_offline_page(struct device *dev,
u64 pfn;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (strict_strtoull(buf, 0, &pfn) < 0)
+ if (kstrtoull(buf, 0, &pfn) < 0)
return -EINVAL;
pfn >>= PAGE_SHIFT;
if (!pfn_valid(pfn))
@@ -488,7 +471,7 @@ store_hard_offline_page(struct device *dev,
u64 pfn;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (strict_strtoull(buf, 0, &pfn) < 0)
+ if (kstrtoull(buf, 0, &pfn) < 0)
return -EINVAL;
pfn >>= PAGE_SHIFT;
ret = memory_failure(pfn, 0, 0);
@@ -525,7 +508,7 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section,
put_device(&hint->dev);
if (!dev)
return NULL;
- return container_of(dev, struct memory_block, dev);
+ return to_memory_block(dev);
}
/*
@@ -565,16 +548,13 @@ static const struct attribute_group *memory_memblk_attr_groups[] = {
static
int register_memory(struct memory_block *memory)
{
- int error;
-
memory->dev.bus = &memory_subsys;
memory->dev.id = memory->start_section_nr / sections_per_block;
memory->dev.release = memory_block_release;
memory->dev.groups = memory_memblk_attr_groups;
memory->dev.offline = memory->state == MEM_OFFLINE;
- error = device_register(&memory->dev);
- return error;
+ return device_register(&memory->dev);
}
static int init_memory_block(struct memory_block **memory,
@@ -595,7 +575,6 @@ static int init_memory_block(struct memory_block **memory,
mem->end_section_nr = mem->start_section_nr + sections_per_block - 1;
mem->state = state;
mem->section_count++;
- mutex_init(&mem->state_mutex);
start_pfn = section_nr_to_pfn(mem->start_section_nr);
mem->phys_device = arch_get_memory_phys_device(start_pfn);
@@ -605,55 +584,57 @@ static int init_memory_block(struct memory_block **memory,
return ret;
}
-static int add_memory_section(int nid, struct mem_section *section,
- struct memory_block **mem_p,
- unsigned long state, enum mem_add_context context)
+static int add_memory_block(int base_section_nr)
{
- struct memory_block *mem = NULL;
- int scn_nr = __section_nr(section);
- int ret = 0;
-
- mutex_lock(&mem_sysfs_mutex);
-
- if (context == BOOT) {
- /* same memory block ? */
- if (mem_p && *mem_p)
- if (scn_nr >= (*mem_p)->start_section_nr &&
- scn_nr <= (*mem_p)->end_section_nr) {
- mem = *mem_p;
- kobject_get(&mem->dev.kobj);
- }
- } else
- mem = find_memory_block(section);
-
- if (mem) {
- mem->section_count++;
- kobject_put(&mem->dev.kobj);
- } else {
- ret = init_memory_block(&mem, section, state);
- /* store memory_block pointer for next loop */
- if (!ret && context == BOOT)
- if (mem_p)
- *mem_p = mem;
- }
+ struct memory_block *mem;
+ int i, ret, section_count = 0, section_nr;
- if (!ret) {
- if (context == HOTPLUG &&
- mem->section_count == sections_per_block)
- ret = register_mem_sect_under_node(mem, nid);
+ for (i = base_section_nr;
+ (i < base_section_nr + sections_per_block) && i < NR_MEM_SECTIONS;
+ i++) {
+ if (!present_section_nr(i))
+ continue;
+ if (section_count == 0)
+ section_nr = i;
+ section_count++;
}
- mutex_unlock(&mem_sysfs_mutex);
- return ret;
+ if (section_count == 0)
+ return 0;
+ ret = init_memory_block(&mem, __nr_to_section(section_nr), MEM_ONLINE);
+ if (ret)
+ return ret;
+ mem->section_count = section_count;
+ return 0;
}
+
/*
* need an interface for the VM to add new memory regions,
* but without onlining it.
*/
int register_new_memory(int nid, struct mem_section *section)
{
- return add_memory_section(nid, section, NULL, MEM_OFFLINE, HOTPLUG);
+ int ret = 0;
+ struct memory_block *mem;
+
+ mutex_lock(&mem_sysfs_mutex);
+
+ mem = find_memory_block(section);
+ if (mem) {
+ mem->section_count++;
+ put_device(&mem->dev);
+ } else {
+ ret = init_memory_block(&mem, section, MEM_OFFLINE);
+ if (ret)
+ goto out;
+ }
+
+ if (mem->section_count == sections_per_block)
+ ret = register_mem_sect_under_node(mem, nid);
+out:
+ mutex_unlock(&mem_sysfs_mutex);
+ return ret;
}
#ifdef CONFIG_MEMORY_HOTREMOVE
@@ -663,7 +644,7 @@ unregister_memory(struct memory_block *memory)
BUG_ON(memory->dev.bus != &memory_subsys);
/* drop the ref. we got in remove_memory_block() */
- kobject_put(&memory->dev.kobj);
+ put_device(&memory->dev);
device_unregister(&memory->dev);
}
@@ -680,7 +661,7 @@ static int remove_memory_block(unsigned long node_id,
if (mem->section_count == 0)
unregister_memory(mem);
else
- kobject_put(&mem->dev.kobj);
+ put_device(&mem->dev);
mutex_unlock(&mem_sysfs_mutex);
return 0;
@@ -733,7 +714,6 @@ int __init memory_dev_init(void)
int ret;
int err;
unsigned long block_sz;
- struct memory_block *mem = NULL;
ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);
if (ret)
@@ -746,17 +726,13 @@ int __init memory_dev_init(void)
* Create entries for memory sections that were found
* during boot and have been initialized
*/
- for (i = 0; i < NR_MEM_SECTIONS; i++) {
- if (!present_section_nr(i))
- continue;
- /* don't need to reuse memory_block if only one per block */
- err = add_memory_section(0, __nr_to_section(i),
- (sections_per_block == 1) ? NULL : &mem,
- MEM_ONLINE,
- BOOT);
+ mutex_lock(&mem_sysfs_mutex);
+ for (i = 0; i < NR_MEM_SECTIONS; i += sections_per_block) {
+ err = add_memory_block(i);
if (!ret)
ret = err;
}
+ mutex_unlock(&mem_sysfs_mutex);
out:
if (ret)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 3c3197a8de4..4f8bef3eb5a 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -672,11 +672,13 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
+static DEVICE_ATTR_RO(modalias);
-static struct device_attribute platform_dev_attrs[] = {
- __ATTR_RO(modalias),
- __ATTR_NULL,
+static struct attribute *platform_dev_attrs[] = {
+ &dev_attr_modalias.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(platform_dev);
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{
@@ -893,7 +895,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = {
struct bus_type platform_bus_type = {
.name = "platform",
- .dev_attrs = platform_dev_attrs,
+ .dev_groups = platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
@@ -1054,7 +1056,7 @@ void __init early_platform_driver_register_all(char *class_str)
* @epdrv: early platform driver structure
* @id: id to match against
*/
-static __init struct platform_device *
+static struct platform_device * __init
early_platform_match(struct early_platform_driver *epdrv, int id)
{
struct platform_device *pd;
@@ -1072,7 +1074,7 @@ early_platform_match(struct early_platform_driver *epdrv, int id)
* @epdrv: early platform driver structure
* @id: return true if id or above exists
*/
-static __init int early_platform_left(struct early_platform_driver *epdrv,
+static int __init early_platform_left(struct early_platform_driver *epdrv,
int id)
{
struct platform_device *pd;
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 5a9b6569dd7..9f098a82cf0 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -28,6 +28,7 @@
#include <linux/sched.h>
#include <linux/async.h>
#include <linux/suspend.h>
+#include <trace/events/power.h>
#include <linux/cpuidle.h>
#include "../base.h"
#include "power.h"
@@ -56,6 +57,30 @@ static pm_message_t pm_transition;
static int async_error;
+static char *pm_verb(int event)
+{
+ switch (event) {
+ case PM_EVENT_SUSPEND:
+ return "suspend";
+ case PM_EVENT_RESUME:
+ return "resume";
+ case PM_EVENT_FREEZE:
+ return "freeze";
+ case PM_EVENT_QUIESCE:
+ return "quiesce";
+ case PM_EVENT_HIBERNATE:
+ return "hibernate";
+ case PM_EVENT_THAW:
+ return "thaw";
+ case PM_EVENT_RESTORE:
+ return "restore";
+ case PM_EVENT_RECOVER:
+ return "recover";
+ default:
+ return "(unknown PM event)";
+ }
+}
+
/**
* device_pm_sleep_init - Initialize system suspend-related device fields.
* @dev: Device object being initialized.
@@ -172,16 +197,21 @@ static ktime_t initcall_debug_start(struct device *dev)
}
static void initcall_debug_report(struct device *dev, ktime_t calltime,
- int error)
+ int error, pm_message_t state, char *info)
{
- ktime_t delta, rettime;
+ ktime_t rettime;
+ s64 nsecs;
+
+ rettime = ktime_get();
+ nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime));
if (pm_print_times_enabled) {
- rettime = ktime_get();
- delta = ktime_sub(rettime, calltime);
pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
- error, (unsigned long long)ktime_to_ns(delta) >> 10);
+ error, (unsigned long long)nsecs >> 10);
}
+
+ trace_device_pm_report_time(dev, info, nsecs, pm_verb(state.event),
+ error);
}
/**
@@ -309,30 +339,6 @@ static pm_callback_t pm_noirq_op(const struct dev_pm_ops *ops, pm_message_t stat
return NULL;
}
-static char *pm_verb(int event)
-{
- switch (event) {
- case PM_EVENT_SUSPEND:
- return "suspend";
- case PM_EVENT_RESUME:
- return "resume";
- case PM_EVENT_FREEZE:
- return "freeze";
- case PM_EVENT_QUIESCE:
- return "quiesce";
- case PM_EVENT_HIBERNATE:
- return "hibernate";
- case PM_EVENT_THAW:
- return "thaw";
- case PM_EVENT_RESTORE:
- return "restore";
- case PM_EVENT_RECOVER:
- return "recover";
- default:
- return "(unknown PM event)";
- }
-}
-
static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info)
{
dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event),
@@ -379,7 +385,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev,
error = cb(dev);
suspend_report_result(cb, error);
- initcall_debug_report(dev, calltime, error);
+ initcall_debug_report(dev, calltime, error, state, info);
return error;
}
@@ -1027,7 +1033,8 @@ EXPORT_SYMBOL_GPL(dpm_suspend_end);
* @cb: Suspend callback to execute.
*/
static int legacy_suspend(struct device *dev, pm_message_t state,
- int (*cb)(struct device *dev, pm_message_t state))
+ int (*cb)(struct device *dev, pm_message_t state),
+ char *info)
{
int error;
ktime_t calltime;
@@ -1037,7 +1044,7 @@ static int legacy_suspend(struct device *dev, pm_message_t state,
error = cb(dev, state);
suspend_report_result(cb, error);
- initcall_debug_report(dev, calltime, error);
+ initcall_debug_report(dev, calltime, error, state, info);
return error;
}
@@ -1097,7 +1104,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
goto Run;
} else if (dev->class->suspend) {
pm_dev_dbg(dev, state, "legacy class ");
- error = legacy_suspend(dev, state, dev->class->suspend);
+ error = legacy_suspend(dev, state, dev->class->suspend,
+ "legacy class ");
goto End;
}
}
@@ -1108,7 +1116,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
callback = pm_op(dev->bus->pm, state);
} else if (dev->bus->suspend) {
pm_dev_dbg(dev, state, "legacy bus ");
- error = legacy_suspend(dev, state, dev->bus->suspend);
+ error = legacy_suspend(dev, state, dev->bus->suspend,
+ "legacy bus ");
goto End;
}
}
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index c8ec186303d..ef89897c604 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -460,6 +460,7 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ADD, new_opp);
return 0;
}
+EXPORT_SYMBOL_GPL(opp_add);
/**
* opp_set_availability() - helper to set the availability of an opp
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index a53ebd26570..03e089ade5c 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -206,7 +206,7 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev,
if (!dev->power.use_autosuspend)
return -EIO;
- if (strict_strtol(buf, 10, &delay) != 0 || delay != (int) delay)
+ if (kstrtol(buf, 10, &delay) != 0 || delay != (int) delay)
return -EINVAL;
device_lock(dev);
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 29c83160ca2..57f777835d9 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -128,9 +128,6 @@ struct regmap {
void *cache;
u32 cache_dirty;
- unsigned long *cache_present;
- unsigned int cache_present_nbits;
-
struct reg_default *patch;
int patch_regs;
@@ -203,6 +200,7 @@ int regcache_write(struct regmap *map,
unsigned int reg, unsigned int value);
int regcache_sync(struct regmap *map);
int regcache_sync_block(struct regmap *map, void *block,
+ unsigned long *cache_present,
unsigned int block_base, unsigned int start,
unsigned int end);
@@ -218,16 +216,6 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
unsigned int val);
int regcache_lookup_reg(struct regmap *map, unsigned int reg);
-int regcache_set_reg_present(struct regmap *map, unsigned int reg);
-
-static inline bool regcache_reg_present(struct regmap *map, unsigned int reg)
-{
- if (!map->cache_present)
- return true;
- if (reg > map->cache_present_nbits)
- return false;
- return map->cache_present[BIT_WORD(reg)] & BIT_MASK(reg);
-}
int _regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len, bool async);
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 5c1435c4e21..930cad4e5df 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -29,6 +29,8 @@ struct regcache_rbtree_node {
unsigned int base_reg;
/* block of adjacent registers */
void *block;
+ /* Which registers are present */
+ long *cache_present;
/* number of registers available in the block */
unsigned int blklen;
} __attribute__ ((packed));
@@ -57,6 +59,7 @@ static void regcache_rbtree_set_register(struct regmap *map,
struct regcache_rbtree_node *rbnode,
unsigned int idx, unsigned int val)
{
+ set_bit(idx, rbnode->cache_present);
regcache_set_val(map, rbnode->block, idx, val);
}
@@ -146,13 +149,13 @@ static int rbtree_show(struct seq_file *s, void *ignored)
map->lock(map->lock_arg);
mem_size = sizeof(*rbtree_ctx);
- mem_size += BITS_TO_LONGS(map->cache_present_nbits) * sizeof(long);
for (node = rb_first(&rbtree_ctx->root); node != NULL;
node = rb_next(node)) {
n = container_of(node, struct regcache_rbtree_node, node);
mem_size += sizeof(*n);
mem_size += (n->blklen * map->cache_word_size);
+ mem_size += BITS_TO_LONGS(n->blklen) * sizeof(long);
regcache_rbtree_get_base_top_reg(map, n, &base, &top);
this_registers = ((top - base) / map->reg_stride) + 1;
@@ -245,6 +248,7 @@ static int regcache_rbtree_exit(struct regmap *map)
rbtree_node = rb_entry(next, struct regcache_rbtree_node, node);
next = rb_next(&rbtree_node->node);
rb_erase(&rbtree_node->node, &rbtree_ctx->root);
+ kfree(rbtree_node->cache_present);
kfree(rbtree_node->block);
kfree(rbtree_node);
}
@@ -265,7 +269,7 @@ static int regcache_rbtree_read(struct regmap *map,
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
- if (!regcache_reg_present(map, reg))
+ if (!test_bit(reg_tmp, rbnode->cache_present))
return -ENOENT;
*value = regcache_rbtree_get_register(map, rbnode, reg_tmp);
} else {
@@ -278,27 +282,45 @@ static int regcache_rbtree_read(struct regmap *map,
static int regcache_rbtree_insert_to_block(struct regmap *map,
struct regcache_rbtree_node *rbnode,
- unsigned int pos, unsigned int reg,
+ unsigned int base_reg,
+ unsigned int top_reg,
+ unsigned int reg,
unsigned int value)
{
+ unsigned int blklen;
+ unsigned int pos, offset;
+ unsigned long *present;
u8 *blk;
+ blklen = (top_reg - base_reg) / map->reg_stride + 1;
+ pos = (reg - base_reg) / map->reg_stride;
+ offset = (rbnode->base_reg - base_reg) / map->reg_stride;
+
blk = krealloc(rbnode->block,
- (rbnode->blklen + 1) * map->cache_word_size,
+ blklen * map->cache_word_size,
GFP_KERNEL);
if (!blk)
return -ENOMEM;
+ present = krealloc(rbnode->cache_present,
+ BITS_TO_LONGS(blklen) * sizeof(*present), GFP_KERNEL);
+ if (!present) {
+ kfree(blk);
+ return -ENOMEM;
+ }
+
/* insert the register value in the correct place in the rbnode block */
- memmove(blk + (pos + 1) * map->cache_word_size,
- blk + pos * map->cache_word_size,
- (rbnode->blklen - pos) * map->cache_word_size);
+ if (pos == 0) {
+ memmove(blk + offset * map->cache_word_size,
+ blk, rbnode->blklen * map->cache_word_size);
+ bitmap_shift_right(present, present, offset, blklen);
+ }
/* update the rbnode block, its size and the base register */
rbnode->block = blk;
- rbnode->blklen++;
- if (!pos)
- rbnode->base_reg = reg;
+ rbnode->blklen = blklen;
+ rbnode->base_reg = base_reg;
+ rbnode->cache_present = present;
regcache_rbtree_set_register(map, rbnode, pos, value);
return 0;
@@ -325,25 +347,34 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
if (i != map->rd_table->n_yes_ranges) {
range = &map->rd_table->yes_ranges[i];
- rbnode->blklen = range->range_max - range->range_min
- + 1;
+ rbnode->blklen = (range->range_max - range->range_min) /
+ map->reg_stride + 1;
rbnode->base_reg = range->range_min;
}
}
if (!rbnode->blklen) {
- rbnode->blklen = sizeof(*rbnode);
+ rbnode->blklen = 1;
rbnode->base_reg = reg;
}
rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
GFP_KERNEL);
- if (!rbnode->block) {
- kfree(rbnode);
- return NULL;
- }
+ if (!rbnode->block)
+ goto err_free;
+
+ rbnode->cache_present = kzalloc(BITS_TO_LONGS(rbnode->blklen) *
+ sizeof(*rbnode->cache_present), GFP_KERNEL);
+ if (!rbnode->cache_present)
+ goto err_free_block;
return rbnode;
+
+err_free_block:
+ kfree(rbnode->block);
+err_free:
+ kfree(rbnode);
+ return NULL;
}
static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
@@ -353,15 +384,9 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
struct regcache_rbtree_node *rbnode, *rbnode_tmp;
struct rb_node *node;
unsigned int reg_tmp;
- unsigned int pos;
- int i;
int ret;
rbtree_ctx = map->cache;
- /* update the reg_present bitmap, make space if necessary */
- ret = regcache_set_reg_present(map, reg);
- if (ret < 0)
- return ret;
/* if we can't locate it in the cached rbnode we'll have
* to traverse the rbtree looking for it.
@@ -371,30 +396,43 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
regcache_rbtree_set_register(map, rbnode, reg_tmp, value);
} else {
+ unsigned int base_reg, top_reg;
+ unsigned int new_base_reg, new_top_reg;
+ unsigned int min, max;
+ unsigned int max_dist;
+
+ max_dist = map->reg_stride * sizeof(*rbnode_tmp) /
+ map->cache_word_size;
+ if (reg < max_dist)
+ min = 0;
+ else
+ min = reg - max_dist;
+ max = reg + max_dist;
+
/* look for an adjacent register to the one we are about to add */
for (node = rb_first(&rbtree_ctx->root); node;
node = rb_next(node)) {
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
node);
- for (i = 0; i < rbnode_tmp->blklen; i++) {
- reg_tmp = rbnode_tmp->base_reg +
- (i * map->reg_stride);
- if (abs(reg_tmp - reg) != map->reg_stride)
- continue;
- /* decide where in the block to place our register */
- if (reg_tmp + map->reg_stride == reg)
- pos = i + 1;
- else
- pos = i;
- ret = regcache_rbtree_insert_to_block(map,
- rbnode_tmp,
- pos, reg,
- value);
- if (ret)
- return ret;
- rbtree_ctx->cached_rbnode = rbnode_tmp;
- return 0;
+
+ regcache_rbtree_get_base_top_reg(map, rbnode_tmp,
+ &base_reg, &top_reg);
+
+ if (base_reg <= max && top_reg >= min) {
+ new_base_reg = min(reg, base_reg);
+ new_top_reg = max(reg, top_reg);
+ } else {
+ continue;
}
+
+ ret = regcache_rbtree_insert_to_block(map, rbnode_tmp,
+ new_base_reg,
+ new_top_reg, reg,
+ value);
+ if (ret)
+ return ret;
+ rbtree_ctx->cached_rbnode = rbnode_tmp;
+ return 0;
}
/* We did not manage to find a place to insert it in
@@ -418,30 +456,34 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
struct regcache_rbtree_ctx *rbtree_ctx;
struct rb_node *node;
struct regcache_rbtree_node *rbnode;
+ unsigned int base_reg, top_reg;
+ unsigned int start, end;
int ret;
- int base, end;
rbtree_ctx = map->cache;
for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
rbnode = rb_entry(node, struct regcache_rbtree_node, node);
- if (rbnode->base_reg > max)
+ regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
+ &top_reg);
+ if (base_reg > max)
break;
- if (rbnode->base_reg + rbnode->blklen < min)
+ if (top_reg < min)
continue;
- if (min > rbnode->base_reg)
- base = min - rbnode->base_reg;
+ if (min > base_reg)
+ start = (min - base_reg) / map->reg_stride;
else
- base = 0;
+ start = 0;
- if (max < rbnode->base_reg + rbnode->blklen)
- end = max - rbnode->base_reg + 1;
+ if (max < top_reg)
+ end = (max - base_reg) / map->reg_stride + 1;
else
end = rbnode->blklen;
- ret = regcache_sync_block(map, rbnode->block, rbnode->base_reg,
- base, end);
+ ret = regcache_sync_block(map, rbnode->block,
+ rbnode->cache_present,
+ rbnode->base_reg, start, end);
if (ret != 0)
return ret;
}
@@ -449,6 +491,42 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
return regmap_async_complete(map);
}
+static int regcache_rbtree_drop(struct regmap *map, unsigned int min,
+ unsigned int max)
+{
+ struct regcache_rbtree_ctx *rbtree_ctx;
+ struct regcache_rbtree_node *rbnode;
+ struct rb_node *node;
+ unsigned int base_reg, top_reg;
+ unsigned int start, end;
+
+ rbtree_ctx = map->cache;
+ for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
+ rbnode = rb_entry(node, struct regcache_rbtree_node, node);
+
+ regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
+ &top_reg);
+ if (base_reg > max)
+ break;
+ if (top_reg < min)
+ continue;
+
+ if (min > base_reg)
+ start = (min - base_reg) / map->reg_stride;
+ else
+ start = 0;
+
+ if (max < top_reg)
+ end = (max - base_reg) / map->reg_stride + 1;
+ else
+ end = rbnode->blklen;
+
+ bitmap_clear(rbnode->cache_present, start, end - start);
+ }
+
+ return 0;
+}
+
struct regcache_ops regcache_rbtree_ops = {
.type = REGCACHE_RBTREE,
.name = "rbtree",
@@ -456,5 +534,6 @@ struct regcache_ops regcache_rbtree_ops = {
.exit = regcache_rbtree_exit,
.read = regcache_rbtree_read,
.write = regcache_rbtree_write,
- .sync = regcache_rbtree_sync
+ .sync = regcache_rbtree_sync,
+ .drop = regcache_rbtree_drop,
};
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index e6910269653..d6c2d691b6e 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -121,8 +121,6 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
map->reg_defaults_raw = config->reg_defaults_raw;
map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8);
map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw;
- map->cache_present = NULL;
- map->cache_present_nbits = 0;
map->cache = NULL;
map->cache_ops = cache_types[i];
@@ -181,7 +179,6 @@ void regcache_exit(struct regmap *map)
BUG_ON(!map->cache_ops);
- kfree(map->cache_present);
kfree(map->reg_defaults);
if (map->cache_free)
kfree(map->reg_defaults_raw);
@@ -241,9 +238,6 @@ int regcache_write(struct regmap *map,
BUG_ON(!map->cache_ops);
- if (!regmap_writeable(map, reg))
- return -EIO;
-
if (!regmap_volatile(map, reg))
return map->cache_ops->write(map, reg, value);
@@ -410,22 +404,16 @@ EXPORT_SYMBOL_GPL(regcache_sync_region);
int regcache_drop_region(struct regmap *map, unsigned int min,
unsigned int max)
{
- unsigned int reg;
int ret = 0;
- if (!map->cache_present && !(map->cache_ops && map->cache_ops->drop))
+ if (!map->cache_ops || !map->cache_ops->drop)
return -EINVAL;
map->lock(map->lock_arg);
trace_regcache_drop_region(map->dev, min, max);
- if (map->cache_present)
- for (reg = min; reg < max + 1; reg++)
- clear_bit(reg, map->cache_present);
-
- if (map->cache_ops && map->cache_ops->drop)
- ret = map->cache_ops->drop(map, min, max);
+ ret = map->cache_ops->drop(map, min, max);
map->unlock(map->lock_arg);
@@ -493,42 +481,6 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);
-int regcache_set_reg_present(struct regmap *map, unsigned int reg)
-{
- unsigned long *cache_present;
- unsigned int cache_present_size;
- unsigned int nregs;
- int i;
-
- nregs = reg + 1;
- cache_present_size = BITS_TO_LONGS(nregs);
- cache_present_size *= sizeof(long);
-
- if (!map->cache_present) {
- cache_present = kmalloc(cache_present_size, GFP_KERNEL);
- if (!cache_present)
- return -ENOMEM;
- bitmap_zero(cache_present, nregs);
- map->cache_present = cache_present;
- map->cache_present_nbits = nregs;
- }
-
- if (nregs > map->cache_present_nbits) {
- cache_present = krealloc(map->cache_present,
- cache_present_size, GFP_KERNEL);
- if (!cache_present)
- return -ENOMEM;
- for (i = 0; i < nregs; i++)
- if (i >= map->cache_present_nbits)
- clear_bit(i, cache_present);
- map->cache_present = cache_present;
- map->cache_present_nbits = nregs;
- }
-
- set_bit(reg, map->cache_present);
- return 0;
-}
-
bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
unsigned int val)
{
@@ -620,7 +572,16 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg)
return -ENOENT;
}
+static bool regcache_reg_present(unsigned long *cache_present, unsigned int idx)
+{
+ if (!cache_present)
+ return true;
+
+ return test_bit(idx, cache_present);
+}
+
static int regcache_sync_block_single(struct regmap *map, void *block,
+ unsigned long *cache_present,
unsigned int block_base,
unsigned int start, unsigned int end)
{
@@ -630,7 +591,7 @@ static int regcache_sync_block_single(struct regmap *map, void *block,
for (i = start; i < end; i++) {
regtmp = block_base + (i * map->reg_stride);
- if (!regcache_reg_present(map, regtmp))
+ if (!regcache_reg_present(cache_present, i))
continue;
val = regcache_get_val(map, block, i);
@@ -681,6 +642,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
}
static int regcache_sync_block_raw(struct regmap *map, void *block,
+ unsigned long *cache_present,
unsigned int block_base, unsigned int start,
unsigned int end)
{
@@ -693,7 +655,7 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
for (i = start; i < end; i++) {
regtmp = block_base + (i * map->reg_stride);
- if (!regcache_reg_present(map, regtmp)) {
+ if (!regcache_reg_present(cache_present, i)) {
ret = regcache_sync_block_raw_flush(map, &data,
base, regtmp);
if (ret != 0)
@@ -719,17 +681,19 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
}
}
- return regcache_sync_block_raw_flush(map, &data, base, regtmp);
+ return regcache_sync_block_raw_flush(map, &data, base, regtmp +
+ map->reg_stride);
}
int regcache_sync_block(struct regmap *map, void *block,
+ unsigned long *cache_present,
unsigned int block_base, unsigned int start,
unsigned int end)
{
if (regmap_can_raw_write(map))
- return regcache_sync_block_raw(map, block, block_base,
- start, end);
+ return regcache_sync_block_raw(map, block, cache_present,
+ block_base, start, end);
else
- return regcache_sync_block_single(map, block, block_base,
- start, end);
+ return regcache_sync_block_single(map, block, cache_present,
+ block_base, start, end);
}
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 53495753fbd..de11ecaf383 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -85,8 +85,8 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
unsigned int reg_offset;
/* Suppress the cache if we're using a subrange */
- if (from)
- return from;
+ if (base)
+ return base;
/*
* If we don't have a cache build one so we don't have to do a
@@ -281,7 +281,7 @@ static ssize_t regmap_map_write_file(struct file *file,
reg = simple_strtoul(start, &start, 16);
while (*start == ' ')
start++;
- if (strict_strtoul(start, 16, &value))
+ if (kstrtoul(start, 16, &value))
return -EINVAL;
/* Userspace has been fiddling around behind the kernel's back */
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 1643e889baf..d10456ffd81 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -418,6 +418,31 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
reg, ret);
goto err_alloc;
}
+
+ if (!chip->init_ack_masked)
+ continue;
+
+ /* Ack masked but set interrupts */
+ reg = chip->status_base +
+ (i * map->reg_stride * d->irq_reg_stride);
+ ret = regmap_read(map, reg, &d->status_buf[i]);
+ if (ret != 0) {
+ dev_err(map->dev, "Failed to read IRQ status: %d\n",
+ ret);
+ goto err_alloc;
+ }
+
+ if (d->status_buf[i] && chip->ack_base) {
+ reg = chip->ack_base +
+ (i * map->reg_stride * d->irq_reg_stride);
+ ret = regmap_write(map, reg,
+ d->status_buf[i] & d->mask_buf[i]);
+ if (ret != 0) {
+ dev_err(map->dev, "Failed to ack 0x%x: %d\n",
+ reg, ret);
+ goto err_alloc;
+ }
+ }
}
/* Wake is disabled by default */
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index e0d0c7d8a5c..7d689a15c50 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -303,6 +303,7 @@ static void regmap_unlock_mutex(void *__map)
}
static void regmap_lock_spinlock(void *__map)
+__acquires(&map->spinlock)
{
struct regmap *map = __map;
unsigned long flags;
@@ -312,6 +313,7 @@ static void regmap_lock_spinlock(void *__map)
}
static void regmap_unlock_spinlock(void *__map)
+__releases(&map->spinlock)
{
struct regmap *map = __map;
spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);
@@ -687,6 +689,10 @@ skip_format_initialization:
unsigned win_max = win_min +
config->ranges[j].window_len - 1;
+ /* Allow data window inside its own virtual range */
+ if (j == i)
+ continue;
+
if (range_cfg->range_min <= sel_reg &&
sel_reg <= range_cfg->range_max) {
dev_err(map->dev,
@@ -1261,6 +1267,9 @@ int _regmap_write(struct regmap *map, unsigned int reg,
int ret;
void *context = _regmap_map_get_context(map);
+ if (!regmap_writeable(map, reg))
+ return -EIO;
+
if (!map->cache_bypass && !map->defer_caching) {
ret = regcache_write(map, reg, val);
if (ret != 0)
@@ -1888,13 +1897,10 @@ EXPORT_SYMBOL_GPL(regmap_async_complete);
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
int num_regs)
{
+ struct reg_default *p;
int i, ret;
bool bypass;
- /* If needed the implementation can be extended to support this */
- if (map->patch)
- return -EBUSY;
-
map->lock(map->lock_arg);
bypass = map->cache_bypass;
@@ -1911,11 +1917,13 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
}
}
- map->patch = kcalloc(num_regs, sizeof(struct reg_default), GFP_KERNEL);
- if (map->patch != NULL) {
- memcpy(map->patch, regs,
- num_regs * sizeof(struct reg_default));
- map->patch_regs = num_regs;
+ p = krealloc(map->patch,
+ sizeof(struct reg_default) * (map->patch_regs + num_regs),
+ GFP_KERNEL);
+ if (p) {
+ memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs));
+ map->patch = p;
+ map->patch_regs += num_regs;
} else {
ret = -ENOMEM;
}
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 2f5919ed91a..94ffee378f1 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -62,25 +62,6 @@ static ssize_t show_cpumap(int type, const struct cpumask *mask, char *buf)
}
#endif
-#ifdef arch_provides_topology_pointers
-#define define_siblings_show_map(name) \
-static ssize_t show_##name(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- unsigned int cpu = dev->id; \
- return show_cpumap(0, topology_##name(cpu), buf); \
-}
-
-#define define_siblings_show_list(name) \
-static ssize_t show_##name##_list(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- unsigned int cpu = dev->id; \
- return show_cpumap(1, topology_##name(cpu), buf); \
-}
-
-#else
#define define_siblings_show_map(name) \
static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
@@ -95,7 +76,6 @@ static ssize_t show_##name##_list(struct device *dev, \
{ \
return show_cpumap(1, topology_##name(dev->id), buf); \
}
-#endif
#define define_siblings_show_func(name) \
define_siblings_show_map(name); define_siblings_show_list(name)
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index b81ddfea1da..e07a5fd58ad 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -532,11 +532,11 @@ config BLK_DEV_RBD
If unsure, say N.
config BLK_DEV_RSXX
- tristate "IBM FlashSystem 70/80 PCIe SSD Device Driver"
+ tristate "IBM Flash Adapter 900GB Full Height PCIe Device Driver"
depends on PCI
help
Device driver for IBM's high speed PCIe SSD
- storage devices: FlashSystem-70 and FlashSystem-80.
+ storage device: Flash Adapter 900GB Full Height.
To compile this driver as a module, choose M here: the
module will be called rsxx.
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 99cb944a002..4d45dba7fb8 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -906,16 +906,10 @@ bio_pageinc(struct bio *bio)
int i;
bio_for_each_segment(bv, bio, i) {
- page = bv->bv_page;
/* Non-zero page count for non-head members of
- * compound pages is no longer allowed by the kernel,
- * but this has never been seen here.
+ * compound pages is no longer allowed by the kernel.
*/
- if (unlikely(PageCompound(page)))
- if (compound_trans_head(page) != page) {
- pr_crit("page tail used for block I/O\n");
- BUG();
- }
+ page = compound_trans_head(bv->bv_page);
atomic_inc(&page->_count);
}
}
@@ -924,10 +918,13 @@ static void
bio_pagedec(struct bio *bio)
{
struct bio_vec *bv;
+ struct page *page;
int i;
- bio_for_each_segment(bv, bio, i)
- atomic_dec(&bv->bv_page->_count);
+ bio_for_each_segment(bv, bio, i) {
+ page = compound_trans_head(bv->bv_page);
+ atomic_dec(&page->_count);
+ }
}
static void
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
index 6608076dc39..28c73ca320a 100644
--- a/drivers/block/drbd/drbd_actlog.c
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -659,6 +659,27 @@ void drbd_al_shrink(struct drbd_conf *mdev)
wake_up(&mdev->al_wait);
}
+int drbd_initialize_al(struct drbd_conf *mdev, void *buffer)
+{
+ struct al_transaction_on_disk *al = buffer;
+ struct drbd_md *md = &mdev->ldev->md;
+ sector_t al_base = md->md_offset + md->al_offset;
+ int al_size_4k = md->al_stripes * md->al_stripe_size_4k;
+ int i;
+
+ memset(al, 0, 4096);
+ al->magic = cpu_to_be32(DRBD_AL_MAGIC);
+ al->transaction_type = cpu_to_be16(AL_TR_INITIALIZED);
+ al->crc32c = cpu_to_be32(crc32c(0, al, 4096));
+
+ for (i = 0; i < al_size_4k; i++) {
+ int err = drbd_md_sync_page_io(mdev, mdev->ldev, al_base + i * 8, WRITE);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
static int w_update_odbm(struct drbd_work *w, int unused)
{
struct update_odbm_work *udw = container_of(w, struct update_odbm_work, w);
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index f943aacfdad..2d7f608d181 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -832,6 +832,7 @@ struct drbd_tconn { /* is a resource from the config file */
unsigned susp_nod:1; /* IO suspended because no data */
unsigned susp_fen:1; /* IO suspended because fence peer handler runs */
struct mutex cstate_mutex; /* Protects graceful disconnects */
+ unsigned int connect_cnt; /* Inc each time a connection is established */
unsigned long flags;
struct net_conf *net_conf; /* content protected by rcu */
@@ -1132,6 +1133,7 @@ extern void drbd_mdev_cleanup(struct drbd_conf *mdev);
void drbd_print_uuids(struct drbd_conf *mdev, const char *text);
extern void conn_md_sync(struct drbd_tconn *tconn);
+extern void drbd_md_write(struct drbd_conf *mdev, void *buffer);
extern void drbd_md_sync(struct drbd_conf *mdev);
extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev);
extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
@@ -1466,8 +1468,16 @@ extern void drbd_suspend_io(struct drbd_conf *mdev);
extern void drbd_resume_io(struct drbd_conf *mdev);
extern char *ppsize(char *buf, unsigned long long size);
extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, sector_t, int);
-enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = 2 };
-extern enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local);
+enum determine_dev_size {
+ DS_ERROR_SHRINK = -3,
+ DS_ERROR_SPACE_MD = -2,
+ DS_ERROR = -1,
+ DS_UNCHANGED = 0,
+ DS_SHRUNK = 1,
+ DS_GREW = 2
+};
+extern enum determine_dev_size
+drbd_determine_dev_size(struct drbd_conf *, enum dds_flags, struct resize_parms *) __must_hold(local);
extern void resync_after_online_grow(struct drbd_conf *);
extern void drbd_reconsider_max_bio_size(struct drbd_conf *mdev);
extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev,
@@ -1633,6 +1643,7 @@ extern int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector,
#define drbd_set_out_of_sync(mdev, sector, size) \
__drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__)
extern void drbd_al_shrink(struct drbd_conf *mdev);
+extern int drbd_initialize_al(struct drbd_conf *, void *);
/* drbd_nl.c */
/* state info broadcast */
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index a5dca6affcb..55635edf563 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2762,8 +2762,6 @@ int __init drbd_init(void)
/*
* allocate all necessary structs
*/
- err = -ENOMEM;
-
init_waitqueue_head(&drbd_pp_wait);
drbd_proc = NULL; /* play safe for drbd_cleanup */
@@ -2773,6 +2771,7 @@ int __init drbd_init(void)
if (err)
goto fail;
+ err = -ENOMEM;
drbd_proc = proc_create_data("drbd", S_IFREG | S_IRUGO , NULL, &drbd_proc_fops, NULL);
if (!drbd_proc) {
printk(KERN_ERR "drbd: unable to register proc file\n");
@@ -2803,7 +2802,6 @@ int __init drbd_init(void)
fail:
drbd_cleanup();
if (err == -ENOMEM)
- /* currently always the case */
printk(KERN_ERR "drbd: ran out of memory\n");
else
printk(KERN_ERR "drbd: initialization failure\n");
@@ -2881,34 +2879,14 @@ struct meta_data_on_disk {
u8 reserved_u8[4096 - (7*8 + 10*4)];
} __packed;
-/**
- * drbd_md_sync() - Writes the meta data super block if the MD_DIRTY flag bit is set
- * @mdev: DRBD device.
- */
-void drbd_md_sync(struct drbd_conf *mdev)
+
+
+void drbd_md_write(struct drbd_conf *mdev, void *b)
{
- struct meta_data_on_disk *buffer;
+ struct meta_data_on_disk *buffer = b;
sector_t sector;
int i;
- /* Don't accidentally change the DRBD meta data layout. */
- BUILD_BUG_ON(UI_SIZE != 4);
- BUILD_BUG_ON(sizeof(struct meta_data_on_disk) != 4096);
-
- del_timer(&mdev->md_sync_timer);
- /* timer may be rearmed by drbd_md_mark_dirty() now. */
- if (!test_and_clear_bit(MD_DIRTY, &mdev->flags))
- return;
-
- /* We use here D_FAILED and not D_ATTACHING because we try to write
- * metadata even if we detach due to a disk failure! */
- if (!get_ldev_if_state(mdev, D_FAILED))
- return;
-
- buffer = drbd_md_get_buffer(mdev);
- if (!buffer)
- goto out;
-
memset(buffer, 0, sizeof(*buffer));
buffer->la_size_sect = cpu_to_be64(drbd_get_capacity(mdev->this_bdev));
@@ -2937,6 +2915,35 @@ void drbd_md_sync(struct drbd_conf *mdev)
dev_err(DEV, "meta data update failed!\n");
drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
}
+}
+
+/**
+ * drbd_md_sync() - Writes the meta data super block if the MD_DIRTY flag bit is set
+ * @mdev: DRBD device.
+ */
+void drbd_md_sync(struct drbd_conf *mdev)
+{
+ struct meta_data_on_disk *buffer;
+
+ /* Don't accidentally change the DRBD meta data layout. */
+ BUILD_BUG_ON(UI_SIZE != 4);
+ BUILD_BUG_ON(sizeof(struct meta_data_on_disk) != 4096);
+
+ del_timer(&mdev->md_sync_timer);
+ /* timer may be rearmed by drbd_md_mark_dirty() now. */
+ if (!test_and_clear_bit(MD_DIRTY, &mdev->flags))
+ return;
+
+ /* We use here D_FAILED and not D_ATTACHING because we try to write
+ * metadata even if we detach due to a disk failure! */
+ if (!get_ldev_if_state(mdev, D_FAILED))
+ return;
+
+ buffer = drbd_md_get_buffer(mdev);
+ if (!buffer)
+ goto out;
+
+ drbd_md_write(mdev, buffer);
/* Update mdev->ldev->md.la_size_sect,
* since we updated it on metadata. */
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 9e3f441e7e8..8cc1e640f48 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -417,6 +417,7 @@ static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn)
bool conn_try_outdate_peer(struct drbd_tconn *tconn)
{
+ unsigned int connect_cnt;
union drbd_state mask = { };
union drbd_state val = { };
enum drbd_fencing_p fp;
@@ -428,6 +429,10 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
return false;
}
+ spin_lock_irq(&tconn->req_lock);
+ connect_cnt = tconn->connect_cnt;
+ spin_unlock_irq(&tconn->req_lock);
+
fp = highest_fencing_policy(tconn);
switch (fp) {
case FP_NOT_AVAIL:
@@ -492,8 +497,14 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
here, because we might were able to re-establish the connection in the
meantime. */
spin_lock_irq(&tconn->req_lock);
- if (tconn->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &tconn->flags))
- _conn_request_state(tconn, mask, val, CS_VERBOSE);
+ if (tconn->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &tconn->flags)) {
+ if (tconn->connect_cnt != connect_cnt)
+ /* In case the connection was established and droped
+ while the fence-peer handler was running, ignore it */
+ conn_info(tconn, "Ignoring fence-peer exit code\n");
+ else
+ _conn_request_state(tconn, mask, val, CS_VERBOSE);
+ }
spin_unlock_irq(&tconn->req_lock);
return conn_highest_pdsk(tconn) <= D_OUTDATED;
@@ -816,15 +827,20 @@ void drbd_resume_io(struct drbd_conf *mdev)
* Returns 0 on success, negative return values indicate errors.
* You should call drbd_md_sync() after calling this function.
*/
-enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags) __must_hold(local)
+enum determine_dev_size
+drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct resize_parms *rs) __must_hold(local)
{
sector_t prev_first_sect, prev_size; /* previous meta location */
sector_t la_size_sect, u_size;
+ struct drbd_md *md = &mdev->ldev->md;
+ u32 prev_al_stripe_size_4k;
+ u32 prev_al_stripes;
sector_t size;
char ppb[10];
+ void *buffer;
int md_moved, la_size_changed;
- enum determine_dev_size rv = unchanged;
+ enum determine_dev_size rv = DS_UNCHANGED;
/* race:
* application request passes inc_ap_bio,
@@ -836,6 +852,11 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
* still lock the act_log to not trigger ASSERTs there.
*/
drbd_suspend_io(mdev);
+ buffer = drbd_md_get_buffer(mdev); /* Lock meta-data IO */
+ if (!buffer) {
+ drbd_resume_io(mdev);
+ return DS_ERROR;
+ }
/* no wait necessary anymore, actually we could assert that */
wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
@@ -844,7 +865,17 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
prev_size = mdev->ldev->md.md_size_sect;
la_size_sect = mdev->ldev->md.la_size_sect;
- /* TODO: should only be some assert here, not (re)init... */
+ if (rs) {
+ /* rs is non NULL if we should change the AL layout only */
+
+ prev_al_stripes = md->al_stripes;
+ prev_al_stripe_size_4k = md->al_stripe_size_4k;
+
+ md->al_stripes = rs->al_stripes;
+ md->al_stripe_size_4k = rs->al_stripe_size / 4;
+ md->al_size_4k = (u64)rs->al_stripes * rs->al_stripe_size / 4;
+ }
+
drbd_md_set_sector_offsets(mdev, mdev->ldev);
rcu_read_lock();
@@ -852,6 +883,21 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
rcu_read_unlock();
size = drbd_new_dev_size(mdev, mdev->ldev, u_size, flags & DDSF_FORCED);
+ if (size < la_size_sect) {
+ if (rs && u_size == 0) {
+ /* Remove "rs &&" later. This check should always be active, but
+ right now the receiver expects the permissive behavior */
+ dev_warn(DEV, "Implicit shrink not allowed. "
+ "Use --size=%llus for explicit shrink.\n",
+ (unsigned long long)size);
+ rv = DS_ERROR_SHRINK;
+ }
+ if (u_size > size)
+ rv = DS_ERROR_SPACE_MD;
+ if (rv != DS_UNCHANGED)
+ goto err_out;
+ }
+
if (drbd_get_capacity(mdev->this_bdev) != size ||
drbd_bm_capacity(mdev) != size) {
int err;
@@ -867,7 +913,7 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
"Leaving size unchanged at size = %lu KB\n",
(unsigned long)size);
}
- rv = dev_size_error;
+ rv = DS_ERROR;
}
/* racy, see comments above. */
drbd_set_my_capacity(mdev, size);
@@ -875,38 +921,57 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds
dev_info(DEV, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
(unsigned long long)size>>1);
}
- if (rv == dev_size_error)
- goto out;
+ if (rv <= DS_ERROR)
+ goto err_out;
la_size_changed = (la_size_sect != mdev->ldev->md.la_size_sect);
md_moved = prev_first_sect != drbd_md_first_sector(mdev->ldev)
|| prev_size != mdev->ldev->md.md_size_sect;
- if (la_size_changed || md_moved) {
- int err;
+ if (la_size_changed || md_moved || rs) {
+ u32 prev_flags;
drbd_al_shrink(mdev); /* All extents inactive. */
+
+ prev_flags = md->flags;
+ md->flags &= ~MDF_PRIMARY_IND;
+ drbd_md_write(mdev, buffer);
+
dev_info(DEV, "Writing the whole bitmap, %s\n",
la_size_changed && md_moved ? "size changed and md moved" :
la_size_changed ? "size changed" : "md moved");
/* next line implicitly does drbd_suspend_io()+drbd_resume_io() */
- err = drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write,
- "size changed", BM_LOCKED_MASK);
- if (err) {
- rv = dev_size_error;
- goto out;
- }
- drbd_md_mark_dirty(mdev);
+ drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write,
+ "size changed", BM_LOCKED_MASK);
+ drbd_initialize_al(mdev, buffer);
+
+ md->flags = prev_flags;
+ drbd_md_write(mdev, buffer);
+
+ if (rs)
+ dev_info(DEV, "Changed AL layout to al-stripes = %d, al-stripe-size-kB = %d\n",
+ md->al_stripes, md->al_stripe_size_4k * 4);
}
if (size > la_size_sect)
- rv = grew;
+ rv = DS_GREW;
if (size < la_size_sect)
- rv = shrunk;
-out:
+ rv = DS_SHRUNK;
+
+ if (0) {
+ err_out:
+ if (rs) {
+ md->al_stripes = prev_al_stripes;
+ md->al_stripe_size_4k = prev_al_stripe_size_4k;
+ md->al_size_4k = (u64)prev_al_stripes * prev_al_stripe_size_4k;
+
+ drbd_md_set_sector_offsets(mdev, mdev->ldev);
+ }
+ }
lc_unlock(mdev->act_log);
wake_up(&mdev->al_wait);
+ drbd_md_put_buffer(mdev);
drbd_resume_io(mdev);
return rv;
@@ -1607,11 +1672,11 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
!drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
set_bit(USE_DEGR_WFC_T, &mdev->flags);
- dd = drbd_determine_dev_size(mdev, 0);
- if (dd == dev_size_error) {
+ dd = drbd_determine_dev_size(mdev, 0, NULL);
+ if (dd <= DS_ERROR) {
retcode = ERR_NOMEM_BITMAP;
goto force_diskless_dec;
- } else if (dd == grew)
+ } else if (dd == DS_GREW)
set_bit(RESYNC_AFTER_NEG, &mdev->flags);
if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC) ||
@@ -2305,6 +2370,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
struct drbd_conf *mdev;
enum drbd_ret_code retcode;
enum determine_dev_size dd;
+ bool change_al_layout = false;
enum dds_flags ddsf;
sector_t u_size;
int err;
@@ -2315,31 +2381,33 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto fail;
+ mdev = adm_ctx.mdev;
+ if (!get_ldev(mdev)) {
+ retcode = ERR_NO_DISK;
+ goto fail;
+ }
+
memset(&rs, 0, sizeof(struct resize_parms));
+ rs.al_stripes = mdev->ldev->md.al_stripes;
+ rs.al_stripe_size = mdev->ldev->md.al_stripe_size_4k * 4;
if (info->attrs[DRBD_NLA_RESIZE_PARMS]) {
err = resize_parms_from_attrs(&rs, info);
if (err) {
retcode = ERR_MANDATORY_TAG;
drbd_msg_put_info(from_attrs_err_to_txt(err));
- goto fail;
+ goto fail_ldev;
}
}
- mdev = adm_ctx.mdev;
if (mdev->state.conn > C_CONNECTED) {
retcode = ERR_RESIZE_RESYNC;
- goto fail;
+ goto fail_ldev;
}
if (mdev->state.role == R_SECONDARY &&
mdev->state.peer == R_SECONDARY) {
retcode = ERR_NO_PRIMARY;
- goto fail;
- }
-
- if (!get_ldev(mdev)) {
- retcode = ERR_NO_DISK;
- goto fail;
+ goto fail_ldev;
}
if (rs.no_resync && mdev->tconn->agreed_pro_version < 93) {
@@ -2358,6 +2426,28 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
}
}
+ if (mdev->ldev->md.al_stripes != rs.al_stripes ||
+ mdev->ldev->md.al_stripe_size_4k != rs.al_stripe_size / 4) {
+ u32 al_size_k = rs.al_stripes * rs.al_stripe_size;
+
+ if (al_size_k > (16 * 1024 * 1024)) {
+ retcode = ERR_MD_LAYOUT_TOO_BIG;
+ goto fail_ldev;
+ }
+
+ if (al_size_k < MD_32kB_SECT/2) {
+ retcode = ERR_MD_LAYOUT_TOO_SMALL;
+ goto fail_ldev;
+ }
+
+ if (mdev->state.conn != C_CONNECTED) {
+ retcode = ERR_MD_LAYOUT_CONNECTED;
+ goto fail_ldev;
+ }
+
+ change_al_layout = true;
+ }
+
if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev))
mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
@@ -2373,16 +2463,22 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
}
ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0);
- dd = drbd_determine_dev_size(mdev, ddsf);
+ dd = drbd_determine_dev_size(mdev, ddsf, change_al_layout ? &rs : NULL);
drbd_md_sync(mdev);
put_ldev(mdev);
- if (dd == dev_size_error) {
+ if (dd == DS_ERROR) {
retcode = ERR_NOMEM_BITMAP;
goto fail;
+ } else if (dd == DS_ERROR_SPACE_MD) {
+ retcode = ERR_MD_LAYOUT_NO_FIT;
+ goto fail;
+ } else if (dd == DS_ERROR_SHRINK) {
+ retcode = ERR_IMPLICIT_SHRINK;
+ goto fail;
}
if (mdev->state.conn == C_CONNECTED) {
- if (dd == grew)
+ if (dd == DS_GREW)
set_bit(RESIZE_PENDING, &mdev->flags);
drbd_send_uuids(mdev);
@@ -2658,7 +2754,6 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
const struct sib_info *sib)
{
struct state_info *si = NULL; /* for sizeof(si->member); */
- struct net_conf *nc;
struct nlattr *nla;
int got_ldev;
int err = 0;
@@ -2688,13 +2783,19 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
goto nla_put_failure;
rcu_read_lock();
- if (got_ldev)
- if (disk_conf_to_skb(skb, rcu_dereference(mdev->ldev->disk_conf), exclude_sensitive))
- goto nla_put_failure;
+ if (got_ldev) {
+ struct disk_conf *disk_conf;
- nc = rcu_dereference(mdev->tconn->net_conf);
- if (nc)
- err = net_conf_to_skb(skb, nc, exclude_sensitive);
+ disk_conf = rcu_dereference(mdev->ldev->disk_conf);
+ err = disk_conf_to_skb(skb, disk_conf, exclude_sensitive);
+ }
+ if (!err) {
+ struct net_conf *nc;
+
+ nc = rcu_dereference(mdev->tconn->net_conf);
+ if (nc)
+ err = net_conf_to_skb(skb, nc, exclude_sensitive);
+ }
rcu_read_unlock();
if (err)
goto nla_put_failure;
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 4222affff48..cc29cd3bf78 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -1039,6 +1039,8 @@ randomize:
rcu_read_lock();
idr_for_each_entry(&tconn->volumes, mdev, vnr) {
kref_get(&mdev->kref);
+ rcu_read_unlock();
+
/* Prevent a race between resync-handshake and
* being promoted to Primary.
*
@@ -1049,8 +1051,6 @@ randomize:
mutex_lock(mdev->state_mutex);
mutex_unlock(mdev->state_mutex);
- rcu_read_unlock();
-
if (discard_my_data)
set_bit(DISCARD_MY_DATA, &mdev->flags);
else
@@ -3545,7 +3545,7 @@ static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi)
{
struct drbd_conf *mdev;
struct p_sizes *p = pi->data;
- enum determine_dev_size dd = unchanged;
+ enum determine_dev_size dd = DS_UNCHANGED;
sector_t p_size, p_usize, my_usize;
int ldsc = 0; /* local disk size changed */
enum dds_flags ddsf;
@@ -3617,9 +3617,9 @@ static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi)
ddsf = be16_to_cpu(p->dds_flags);
if (get_ldev(mdev)) {
- dd = drbd_determine_dev_size(mdev, ddsf);
+ dd = drbd_determine_dev_size(mdev, ddsf, NULL);
put_ldev(mdev);
- if (dd == dev_size_error)
+ if (dd == DS_ERROR)
return -EIO;
drbd_md_sync(mdev);
} else {
@@ -3647,7 +3647,7 @@ static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi)
drbd_send_sizes(mdev, 0, ddsf);
}
if (test_and_clear_bit(RESIZE_PENDING, &mdev->flags) ||
- (dd == grew && mdev->state.conn == C_CONNECTED)) {
+ (dd == DS_GREW && mdev->state.conn == C_CONNECTED)) {
if (mdev->state.pdsk >= D_INCONSISTENT &&
mdev->state.disk >= D_INCONSISTENT) {
if (ddsf & DDSF_NO_RESYNC)
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index 90c5be2b1d3..216d47b7e88 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -1115,8 +1115,10 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
drbd_thread_restart_nowait(&mdev->tconn->receiver);
/* Resume AL writing if we get a connection */
- if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED)
+ if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) {
drbd_resume_al(mdev);
+ mdev->tconn->connect_cnt++;
+ }
/* remember last attach time so request_timer_fn() won't
* kill newly established sessions while we are still trying to thaw
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 4ad2ad9a5bb..191cd177fef 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -397,15 +397,19 @@ static ssize_t rbd_remove(struct bus_type *bus, const char *buf,
static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping);
static void rbd_spec_put(struct rbd_spec *spec);
-static struct bus_attribute rbd_bus_attrs[] = {
- __ATTR(add, S_IWUSR, NULL, rbd_add),
- __ATTR(remove, S_IWUSR, NULL, rbd_remove),
- __ATTR_NULL
+static BUS_ATTR(add, S_IWUSR, NULL, rbd_add);
+static BUS_ATTR(remove, S_IWUSR, NULL, rbd_remove);
+
+static struct attribute *rbd_bus_attrs[] = {
+ &bus_attr_add.attr,
+ &bus_attr_remove.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(rbd_bus);
static struct bus_type rbd_bus_type = {
.name = "rbd",
- .bus_attrs = rbd_bus_attrs,
+ .bus_groups = rbd_bus_groups,
};
static void rbd_root_dev_release(struct device *dev)
diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c
index 5af21f2db29..6e85e21445e 100644
--- a/drivers/block/rsxx/core.c
+++ b/drivers/block/rsxx/core.c
@@ -31,6 +31,8 @@
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <linux/genhd.h>
#include <linux/idr.h>
@@ -39,8 +41,9 @@
#include "rsxx_cfg.h"
#define NO_LEGACY 0
+#define SYNC_START_TIMEOUT (10 * 60) /* 10 minutes */
-MODULE_DESCRIPTION("IBM FlashSystem 70/80 PCIe SSD Device Driver");
+MODULE_DESCRIPTION("IBM Flash Adapter 900GB Full Height Device Driver");
MODULE_AUTHOR("Joshua Morris/Philip Kelleher, IBM");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
@@ -49,9 +52,282 @@ static unsigned int force_legacy = NO_LEGACY;
module_param(force_legacy, uint, 0444);
MODULE_PARM_DESC(force_legacy, "Force the use of legacy type PCI interrupts");
+static unsigned int sync_start = 1;
+module_param(sync_start, uint, 0444);
+MODULE_PARM_DESC(sync_start, "On by Default: Driver load will not complete "
+ "until the card startup has completed.");
+
static DEFINE_IDA(rsxx_disk_ida);
static DEFINE_SPINLOCK(rsxx_ida_lock);
+/* --------------------Debugfs Setup ------------------- */
+
+struct rsxx_cram {
+ u32 f_pos;
+ u32 offset;
+ void *i_private;
+};
+
+static int rsxx_attr_pci_regs_show(struct seq_file *m, void *p)
+{
+ struct rsxx_cardinfo *card = m->private;
+
+ seq_printf(m, "HWID 0x%08x\n",
+ ioread32(card->regmap + HWID));
+ seq_printf(m, "SCRATCH 0x%08x\n",
+ ioread32(card->regmap + SCRATCH));
+ seq_printf(m, "IER 0x%08x\n",
+ ioread32(card->regmap + IER));
+ seq_printf(m, "IPR 0x%08x\n",
+ ioread32(card->regmap + IPR));
+ seq_printf(m, "CREG_CMD 0x%08x\n",
+ ioread32(card->regmap + CREG_CMD));
+ seq_printf(m, "CREG_ADD 0x%08x\n",
+ ioread32(card->regmap + CREG_ADD));
+ seq_printf(m, "CREG_CNT 0x%08x\n",
+ ioread32(card->regmap + CREG_CNT));
+ seq_printf(m, "CREG_STAT 0x%08x\n",
+ ioread32(card->regmap + CREG_STAT));
+ seq_printf(m, "CREG_DATA0 0x%08x\n",
+ ioread32(card->regmap + CREG_DATA0));
+ seq_printf(m, "CREG_DATA1 0x%08x\n",
+ ioread32(card->regmap + CREG_DATA1));
+ seq_printf(m, "CREG_DATA2 0x%08x\n",
+ ioread32(card->regmap + CREG_DATA2));
+ seq_printf(m, "CREG_DATA3 0x%08x\n",
+ ioread32(card->regmap + CREG_DATA3));
+ seq_printf(m, "CREG_DATA4 0x%08x\n",
+ ioread32(card->regmap + CREG_DATA4));
+ seq_printf(m, "CREG_DATA5 0x%08x\n",
+ ioread32(card->regmap + CREG_DATA5));
+ seq_printf(m, "CREG_DATA6 0x%08x\n",
+ ioread32(card->regmap + CREG_DATA6));
+ seq_printf(m, "CREG_DATA7 0x%08x\n",
+ ioread32(card->regmap + CREG_DATA7));
+ seq_printf(m, "INTR_COAL 0x%08x\n",
+ ioread32(card->regmap + INTR_COAL));
+ seq_printf(m, "HW_ERROR 0x%08x\n",
+ ioread32(card->regmap + HW_ERROR));
+ seq_printf(m, "DEBUG0 0x%08x\n",
+ ioread32(card->regmap + PCI_DEBUG0));
+ seq_printf(m, "DEBUG1 0x%08x\n",
+ ioread32(card->regmap + PCI_DEBUG1));
+ seq_printf(m, "DEBUG2 0x%08x\n",
+ ioread32(card->regmap + PCI_DEBUG2));
+ seq_printf(m, "DEBUG3 0x%08x\n",
+ ioread32(card->regmap + PCI_DEBUG3));
+ seq_printf(m, "DEBUG4 0x%08x\n",
+ ioread32(card->regmap + PCI_DEBUG4));
+ seq_printf(m, "DEBUG5 0x%08x\n",
+ ioread32(card->regmap + PCI_DEBUG5));
+ seq_printf(m, "DEBUG6 0x%08x\n",
+ ioread32(card->regmap + PCI_DEBUG6));
+ seq_printf(m, "DEBUG7 0x%08x\n",
+ ioread32(card->regmap + PCI_DEBUG7));
+ seq_printf(m, "RECONFIG 0x%08x\n",
+ ioread32(card->regmap + PCI_RECONFIG));
+
+ return 0;
+}
+
+static int rsxx_attr_stats_show(struct seq_file *m, void *p)
+{
+ struct rsxx_cardinfo *card = m->private;
+ int i;
+
+ for (i = 0; i < card->n_targets; i++) {
+ seq_printf(m, "Ctrl %d CRC Errors = %d\n",
+ i, card->ctrl[i].stats.crc_errors);
+ seq_printf(m, "Ctrl %d Hard Errors = %d\n",
+ i, card->ctrl[i].stats.hard_errors);
+ seq_printf(m, "Ctrl %d Soft Errors = %d\n",
+ i, card->ctrl[i].stats.soft_errors);
+ seq_printf(m, "Ctrl %d Writes Issued = %d\n",
+ i, card->ctrl[i].stats.writes_issued);
+ seq_printf(m, "Ctrl %d Writes Failed = %d\n",
+ i, card->ctrl[i].stats.writes_failed);
+ seq_printf(m, "Ctrl %d Reads Issued = %d\n",
+ i, card->ctrl[i].stats.reads_issued);
+ seq_printf(m, "Ctrl %d Reads Failed = %d\n",
+ i, card->ctrl[i].stats.reads_failed);
+ seq_printf(m, "Ctrl %d Reads Retried = %d\n",
+ i, card->ctrl[i].stats.reads_retried);
+ seq_printf(m, "Ctrl %d Discards Issued = %d\n",
+ i, card->ctrl[i].stats.discards_issued);
+ seq_printf(m, "Ctrl %d Discards Failed = %d\n",
+ i, card->ctrl[i].stats.discards_failed);
+ seq_printf(m, "Ctrl %d DMA SW Errors = %d\n",
+ i, card->ctrl[i].stats.dma_sw_err);
+ seq_printf(m, "Ctrl %d DMA HW Faults = %d\n",
+ i, card->ctrl[i].stats.dma_hw_fault);
+ seq_printf(m, "Ctrl %d DMAs Cancelled = %d\n",
+ i, card->ctrl[i].stats.dma_cancelled);
+ seq_printf(m, "Ctrl %d SW Queue Depth = %d\n",
+ i, card->ctrl[i].stats.sw_q_depth);
+ seq_printf(m, "Ctrl %d HW Queue Depth = %d\n",
+ i, atomic_read(&card->ctrl[i].stats.hw_q_depth));
+ }
+
+ return 0;
+}
+
+static int rsxx_attr_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, rsxx_attr_stats_show, inode->i_private);
+}
+
+static int rsxx_attr_pci_regs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, rsxx_attr_pci_regs_show, inode->i_private);
+}
+
+static ssize_t rsxx_cram_read(struct file *fp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct rsxx_cram *info = fp->private_data;
+ struct rsxx_cardinfo *card = info->i_private;
+ char *buf;
+ int st;
+
+ buf = kzalloc(sizeof(*buf) * cnt, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ info->f_pos = (u32)*ppos + info->offset;
+
+ st = rsxx_creg_read(card, CREG_ADD_CRAM + info->f_pos, cnt, buf, 1);
+ if (st)
+ return st;
+
+ st = copy_to_user(ubuf, buf, cnt);
+ if (st)
+ return st;
+
+ info->offset += cnt;
+
+ kfree(buf);
+
+ return cnt;
+}
+
+static ssize_t rsxx_cram_write(struct file *fp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct rsxx_cram *info = fp->private_data;
+ struct rsxx_cardinfo *card = info->i_private;
+ char *buf;
+ int st;
+
+ buf = kzalloc(sizeof(*buf) * cnt, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ st = copy_from_user(buf, ubuf, cnt);
+ if (st)
+ return st;
+
+ info->f_pos = (u32)*ppos + info->offset;
+
+ st = rsxx_creg_write(card, CREG_ADD_CRAM + info->f_pos, cnt, buf, 1);
+ if (st)
+ return st;
+
+ info->offset += cnt;
+
+ kfree(buf);
+
+ return cnt;
+}
+
+static int rsxx_cram_open(struct inode *inode, struct file *file)
+{
+ struct rsxx_cram *info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->i_private = inode->i_private;
+ info->f_pos = file->f_pos;
+ file->private_data = info;
+
+ return 0;
+}
+
+static int rsxx_cram_release(struct inode *inode, struct file *file)
+{
+ struct rsxx_cram *info = file->private_data;
+
+ if (!info)
+ return 0;
+
+ kfree(info);
+ file->private_data = NULL;
+
+ return 0;
+}
+
+static const struct file_operations debugfs_cram_fops = {
+ .owner = THIS_MODULE,
+ .open = rsxx_cram_open,
+ .read = rsxx_cram_read,
+ .write = rsxx_cram_write,
+ .release = rsxx_cram_release,
+};
+
+static const struct file_operations debugfs_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = rsxx_attr_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations debugfs_pci_regs_fops = {
+ .owner = THIS_MODULE,
+ .open = rsxx_attr_pci_regs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void rsxx_debugfs_dev_new(struct rsxx_cardinfo *card)
+{
+ struct dentry *debugfs_stats;
+ struct dentry *debugfs_pci_regs;
+ struct dentry *debugfs_cram;
+
+ card->debugfs_dir = debugfs_create_dir(card->gendisk->disk_name, NULL);
+ if (IS_ERR_OR_NULL(card->debugfs_dir))
+ goto failed_debugfs_dir;
+
+ debugfs_stats = debugfs_create_file("stats", S_IRUGO,
+ card->debugfs_dir, card,
+ &debugfs_stats_fops);
+ if (IS_ERR_OR_NULL(debugfs_stats))
+ goto failed_debugfs_stats;
+
+ debugfs_pci_regs = debugfs_create_file("pci_regs", S_IRUGO,
+ card->debugfs_dir, card,
+ &debugfs_pci_regs_fops);
+ if (IS_ERR_OR_NULL(debugfs_pci_regs))
+ goto failed_debugfs_pci_regs;
+
+ debugfs_cram = debugfs_create_file("cram", S_IRUGO | S_IWUSR,
+ card->debugfs_dir, card,
+ &debugfs_cram_fops);
+ if (IS_ERR_OR_NULL(debugfs_cram))
+ goto failed_debugfs_cram;
+
+ return;
+failed_debugfs_cram:
+ debugfs_remove(debugfs_pci_regs);
+failed_debugfs_pci_regs:
+ debugfs_remove(debugfs_stats);
+failed_debugfs_stats:
+ debugfs_remove(card->debugfs_dir);
+failed_debugfs_dir:
+ card->debugfs_dir = NULL;
+}
+
/*----------------- Interrupt Control & Handling -------------------*/
static void rsxx_mask_interrupts(struct rsxx_cardinfo *card)
@@ -163,12 +439,13 @@ static irqreturn_t rsxx_isr(int irq, void *pdata)
}
if (isr & CR_INTR_CREG) {
- schedule_work(&card->creg_ctrl.done_work);
+ queue_work(card->creg_ctrl.creg_wq,
+ &card->creg_ctrl.done_work);
handled++;
}
if (isr & CR_INTR_EVENT) {
- schedule_work(&card->event_work);
+ queue_work(card->event_wq, &card->event_work);
rsxx_disable_ier_and_isr(card, CR_INTR_EVENT);
handled++;
}
@@ -329,7 +606,7 @@ static int rsxx_eeh_frozen(struct pci_dev *dev)
int i;
int st;
- dev_warn(&dev->dev, "IBM FlashSystem PCI: preparing for slot reset.\n");
+ dev_warn(&dev->dev, "IBM Flash Adapter PCI: preparing for slot reset.\n");
card->eeh_state = 1;
rsxx_mask_interrupts(card);
@@ -367,15 +644,26 @@ static void rsxx_eeh_failure(struct pci_dev *dev)
{
struct rsxx_cardinfo *card = pci_get_drvdata(dev);
int i;
+ int cnt = 0;
- dev_err(&dev->dev, "IBM FlashSystem PCI: disabling failed card.\n");
+ dev_err(&dev->dev, "IBM Flash Adapter PCI: disabling failed card.\n");
card->eeh_state = 1;
+ card->halt = 1;
- for (i = 0; i < card->n_targets; i++)
- del_timer_sync(&card->ctrl[i].activity_timer);
+ for (i = 0; i < card->n_targets; i++) {
+ spin_lock_bh(&card->ctrl[i].queue_lock);
+ cnt = rsxx_cleanup_dma_queue(&card->ctrl[i],
+ &card->ctrl[i].queue);
+ spin_unlock_bh(&card->ctrl[i].queue_lock);
+
+ cnt += rsxx_dma_cancel(&card->ctrl[i]);
- rsxx_eeh_cancel_dmas(card);
+ if (cnt)
+ dev_info(CARD_TO_DEV(card),
+ "Freed %d queued DMAs on channel %d\n",
+ cnt, card->ctrl[i].id);
+ }
}
static int rsxx_eeh_fifo_flush_poll(struct rsxx_cardinfo *card)
@@ -432,7 +720,7 @@ static pci_ers_result_t rsxx_slot_reset(struct pci_dev *dev)
int st;
dev_warn(&dev->dev,
- "IBM FlashSystem PCI: recovering from slot reset.\n");
+ "IBM Flash Adapter PCI: recovering from slot reset.\n");
st = pci_enable_device(dev);
if (st)
@@ -485,7 +773,7 @@ static pci_ers_result_t rsxx_slot_reset(struct pci_dev *dev)
&card->ctrl[i].issue_dma_work);
}
- dev_info(&dev->dev, "IBM FlashSystem PCI: recovery complete.\n");
+ dev_info(&dev->dev, "IBM Flash Adapter PCI: recovery complete.\n");
return PCI_ERS_RESULT_RECOVERED;
@@ -528,6 +816,7 @@ static int rsxx_pci_probe(struct pci_dev *dev,
{
struct rsxx_cardinfo *card;
int st;
+ unsigned int sync_timeout;
dev_info(&dev->dev, "PCI-Flash SSD discovered\n");
@@ -610,7 +899,11 @@ static int rsxx_pci_probe(struct pci_dev *dev,
}
/************* Setup Processor Command Interface *************/
- rsxx_creg_setup(card);
+ st = rsxx_creg_setup(card);
+ if (st) {
+ dev_err(CARD_TO_DEV(card), "Failed to setup creg interface.\n");
+ goto failed_creg_setup;
+ }
spin_lock_irq(&card->irq_lock);
rsxx_enable_ier_and_isr(card, CR_INTR_CREG);
@@ -650,6 +943,12 @@ static int rsxx_pci_probe(struct pci_dev *dev,
}
/************* Setup Card Event Handler *************/
+ card->event_wq = create_singlethread_workqueue(DRIVER_NAME"_event");
+ if (!card->event_wq) {
+ dev_err(CARD_TO_DEV(card), "Failed card event setup.\n");
+ goto failed_event_handler;
+ }
+
INIT_WORK(&card->event_work, card_event_handler);
st = rsxx_setup_dev(card);
@@ -676,6 +975,33 @@ static int rsxx_pci_probe(struct pci_dev *dev,
if (st)
dev_crit(CARD_TO_DEV(card),
"Failed issuing card startup\n");
+ if (sync_start) {
+ sync_timeout = SYNC_START_TIMEOUT;
+
+ dev_info(CARD_TO_DEV(card),
+ "Waiting for card to startup\n");
+
+ do {
+ ssleep(1);
+ sync_timeout--;
+
+ rsxx_get_card_state(card, &card->state);
+ } while (sync_timeout &&
+ (card->state == CARD_STATE_STARTING));
+
+ if (card->state == CARD_STATE_STARTING) {
+ dev_warn(CARD_TO_DEV(card),
+ "Card startup timed out\n");
+ card->size8 = 0;
+ } else {
+ dev_info(CARD_TO_DEV(card),
+ "card state: %s\n",
+ rsxx_card_state_to_str(card->state));
+ st = rsxx_get_card_size8(card, &card->size8);
+ if (st)
+ card->size8 = 0;
+ }
+ }
} else if (card->state == CARD_STATE_GOOD ||
card->state == CARD_STATE_RD_ONLY_FAULT) {
st = rsxx_get_card_size8(card, &card->size8);
@@ -685,12 +1011,21 @@ static int rsxx_pci_probe(struct pci_dev *dev,
rsxx_attach_dev(card);
+ /************* Setup Debugfs *************/
+ rsxx_debugfs_dev_new(card);
+
return 0;
failed_create_dev:
+ destroy_workqueue(card->event_wq);
+ card->event_wq = NULL;
+failed_event_handler:
rsxx_dma_destroy(card);
failed_dma_setup:
failed_compatiblity_check:
+ destroy_workqueue(card->creg_ctrl.creg_wq);
+ card->creg_ctrl.creg_wq = NULL;
+failed_creg_setup:
spin_lock_irq(&card->irq_lock);
rsxx_disable_ier_and_isr(card, CR_INTR_ALL);
spin_unlock_irq(&card->irq_lock);
@@ -756,6 +1091,8 @@ static void rsxx_pci_remove(struct pci_dev *dev)
/* Prevent work_structs from re-queuing themselves. */
card->halt = 1;
+ debugfs_remove_recursive(card->debugfs_dir);
+
free_irq(dev->irq, card);
if (!force_legacy)
diff --git a/drivers/block/rsxx/cregs.c b/drivers/block/rsxx/cregs.c
index 4b5c020a0a6..926dce9c452 100644
--- a/drivers/block/rsxx/cregs.c
+++ b/drivers/block/rsxx/cregs.c
@@ -431,6 +431,15 @@ static int __issue_creg_rw(struct rsxx_cardinfo *card,
*hw_stat = completion.creg_status;
if (completion.st) {
+ /*
+ * This read is needed to verify that there has not been any
+ * extreme errors that might have occurred, i.e. EEH. The
+ * function iowrite32 will not detect EEH errors, so it is
+ * necessary that we recover if such an error is the reason
+ * for the timeout. This is a dummy read.
+ */
+ ioread32(card->regmap + SCRATCH);
+
dev_warn(CARD_TO_DEV(card),
"creg command failed(%d x%08x)\n",
completion.st, addr);
@@ -727,6 +736,11 @@ int rsxx_creg_setup(struct rsxx_cardinfo *card)
{
card->creg_ctrl.active_cmd = NULL;
+ card->creg_ctrl.creg_wq =
+ create_singlethread_workqueue(DRIVER_NAME"_creg");
+ if (!card->creg_ctrl.creg_wq)
+ return -ENOMEM;
+
INIT_WORK(&card->creg_ctrl.done_work, creg_cmd_done);
mutex_init(&card->creg_ctrl.reset_lock);
INIT_LIST_HEAD(&card->creg_ctrl.queue);
diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c
index 4346d17d294..d7af441880b 100644
--- a/drivers/block/rsxx/dev.c
+++ b/drivers/block/rsxx/dev.c
@@ -155,7 +155,8 @@ static void bio_dma_done_cb(struct rsxx_cardinfo *card,
atomic_set(&meta->error, 1);
if (atomic_dec_and_test(&meta->pending_dmas)) {
- disk_stats_complete(card, meta->bio, meta->start_time);
+ if (!card->eeh_state && card->gendisk)
+ disk_stats_complete(card, meta->bio, meta->start_time);
bio_endio(meta->bio, atomic_read(&meta->error) ? -EIO : 0);
kmem_cache_free(bio_meta_pool, meta);
@@ -170,6 +171,12 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio)
might_sleep();
+ if (!card)
+ goto req_err;
+
+ if (bio->bi_sector + (bio->bi_size >> 9) > get_capacity(card->gendisk))
+ goto req_err;
+
if (unlikely(card->halt)) {
st = -EFAULT;
goto req_err;
@@ -196,7 +203,8 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio)
atomic_set(&bio_meta->pending_dmas, 0);
bio_meta->start_time = jiffies;
- disk_stats_start(card, bio);
+ if (!unlikely(card->halt))
+ disk_stats_start(card, bio);
dev_dbg(CARD_TO_DEV(card), "BIO[%c]: meta: %p addr8: x%llx size: %d\n",
bio_data_dir(bio) ? 'W' : 'R', bio_meta,
@@ -225,24 +233,6 @@ static bool rsxx_discard_supported(struct rsxx_cardinfo *card)
return (pci_rev >= RSXX_DISCARD_SUPPORT);
}
-static unsigned short rsxx_get_logical_block_size(
- struct rsxx_cardinfo *card)
-{
- u32 capabilities = 0;
- int st;
-
- st = rsxx_get_card_capabilities(card, &capabilities);
- if (st)
- dev_warn(CARD_TO_DEV(card),
- "Failed reading card capabilities register\n");
-
- /* Earlier firmware did not have support for 512 byte accesses */
- if (capabilities & CARD_CAP_SUBPAGE_WRITES)
- return 512;
- else
- return RSXX_HW_BLK_SIZE;
-}
-
int rsxx_attach_dev(struct rsxx_cardinfo *card)
{
mutex_lock(&card->dev_lock);
@@ -305,7 +295,7 @@ int rsxx_setup_dev(struct rsxx_cardinfo *card)
return -ENOMEM;
}
- blk_size = rsxx_get_logical_block_size(card);
+ blk_size = card->config.data.block_size;
blk_queue_make_request(card->queue, rsxx_make_request);
blk_queue_bounce_limit(card->queue, BLK_BOUNCE_ANY);
@@ -347,6 +337,7 @@ void rsxx_destroy_dev(struct rsxx_cardinfo *card)
card->gendisk = NULL;
blk_cleanup_queue(card->queue);
+ card->queue->queuedata = NULL;
unregister_blkdev(card->major, DRIVER_NAME);
}
diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c
index 0607513cfb4..bed32f16b08 100644
--- a/drivers/block/rsxx/dma.c
+++ b/drivers/block/rsxx/dma.c
@@ -245,6 +245,22 @@ static void rsxx_complete_dma(struct rsxx_dma_ctrl *ctrl,
kmem_cache_free(rsxx_dma_pool, dma);
}
+int rsxx_cleanup_dma_queue(struct rsxx_dma_ctrl *ctrl,
+ struct list_head *q)
+{
+ struct rsxx_dma *dma;
+ struct rsxx_dma *tmp;
+ int cnt = 0;
+
+ list_for_each_entry_safe(dma, tmp, q, list) {
+ list_del(&dma->list);
+ rsxx_complete_dma(ctrl, dma, DMA_CANCELLED);
+ cnt++;
+ }
+
+ return cnt;
+}
+
static void rsxx_requeue_dma(struct rsxx_dma_ctrl *ctrl,
struct rsxx_dma *dma)
{
@@ -252,9 +268,10 @@ static void rsxx_requeue_dma(struct rsxx_dma_ctrl *ctrl,
* Requeued DMAs go to the front of the queue so they are issued
* first.
*/
- spin_lock(&ctrl->queue_lock);
+ spin_lock_bh(&ctrl->queue_lock);
+ ctrl->stats.sw_q_depth++;
list_add(&dma->list, &ctrl->queue);
- spin_unlock(&ctrl->queue_lock);
+ spin_unlock_bh(&ctrl->queue_lock);
}
static void rsxx_handle_dma_error(struct rsxx_dma_ctrl *ctrl,
@@ -329,6 +346,7 @@ static void rsxx_handle_dma_error(struct rsxx_dma_ctrl *ctrl,
static void dma_engine_stalled(unsigned long data)
{
struct rsxx_dma_ctrl *ctrl = (struct rsxx_dma_ctrl *)data;
+ int cnt;
if (atomic_read(&ctrl->stats.hw_q_depth) == 0 ||
unlikely(ctrl->card->eeh_state))
@@ -349,18 +367,28 @@ static void dma_engine_stalled(unsigned long data)
"DMA channel %d has stalled, faulting interface.\n",
ctrl->id);
ctrl->card->dma_fault = 1;
+
+ /* Clean up the DMA queue */
+ spin_lock(&ctrl->queue_lock);
+ cnt = rsxx_cleanup_dma_queue(ctrl, &ctrl->queue);
+ spin_unlock(&ctrl->queue_lock);
+
+ cnt += rsxx_dma_cancel(ctrl);
+
+ if (cnt)
+ dev_info(CARD_TO_DEV(ctrl->card),
+ "Freed %d queued DMAs on channel %d\n",
+ cnt, ctrl->id);
}
}
-static void rsxx_issue_dmas(struct work_struct *work)
+static void rsxx_issue_dmas(struct rsxx_dma_ctrl *ctrl)
{
- struct rsxx_dma_ctrl *ctrl;
struct rsxx_dma *dma;
int tag;
int cmds_pending = 0;
struct hw_cmd *hw_cmd_buf;
- ctrl = container_of(work, struct rsxx_dma_ctrl, issue_dma_work);
hw_cmd_buf = ctrl->cmd.buf;
if (unlikely(ctrl->card->halt) ||
@@ -368,22 +396,22 @@ static void rsxx_issue_dmas(struct work_struct *work)
return;
while (1) {
- spin_lock(&ctrl->queue_lock);
+ spin_lock_bh(&ctrl->queue_lock);
if (list_empty(&ctrl->queue)) {
- spin_unlock(&ctrl->queue_lock);
+ spin_unlock_bh(&ctrl->queue_lock);
break;
}
- spin_unlock(&ctrl->queue_lock);
+ spin_unlock_bh(&ctrl->queue_lock);
tag = pop_tracker(ctrl->trackers);
if (tag == -1)
break;
- spin_lock(&ctrl->queue_lock);
+ spin_lock_bh(&ctrl->queue_lock);
dma = list_entry(ctrl->queue.next, struct rsxx_dma, list);
list_del(&dma->list);
ctrl->stats.sw_q_depth--;
- spin_unlock(&ctrl->queue_lock);
+ spin_unlock_bh(&ctrl->queue_lock);
/*
* This will catch any DMAs that slipped in right before the
@@ -440,9 +468,8 @@ static void rsxx_issue_dmas(struct work_struct *work)
}
}
-static void rsxx_dma_done(struct work_struct *work)
+static void rsxx_dma_done(struct rsxx_dma_ctrl *ctrl)
{
- struct rsxx_dma_ctrl *ctrl;
struct rsxx_dma *dma;
unsigned long flags;
u16 count;
@@ -450,7 +477,6 @@ static void rsxx_dma_done(struct work_struct *work)
u8 tag;
struct hw_status *hw_st_buf;
- ctrl = container_of(work, struct rsxx_dma_ctrl, dma_done_work);
hw_st_buf = ctrl->status.buf;
if (unlikely(ctrl->card->halt) ||
@@ -520,33 +546,32 @@ static void rsxx_dma_done(struct work_struct *work)
rsxx_enable_ier(ctrl->card, CR_INTR_DMA(ctrl->id));
spin_unlock_irqrestore(&ctrl->card->irq_lock, flags);
- spin_lock(&ctrl->queue_lock);
+ spin_lock_bh(&ctrl->queue_lock);
if (ctrl->stats.sw_q_depth)
queue_work(ctrl->issue_wq, &ctrl->issue_dma_work);
- spin_unlock(&ctrl->queue_lock);
+ spin_unlock_bh(&ctrl->queue_lock);
}
-static int rsxx_cleanup_dma_queue(struct rsxx_cardinfo *card,
- struct list_head *q)
+static void rsxx_schedule_issue(struct work_struct *work)
{
- struct rsxx_dma *dma;
- struct rsxx_dma *tmp;
- int cnt = 0;
+ struct rsxx_dma_ctrl *ctrl;
- list_for_each_entry_safe(dma, tmp, q, list) {
- list_del(&dma->list);
+ ctrl = container_of(work, struct rsxx_dma_ctrl, issue_dma_work);
- if (dma->dma_addr)
- pci_unmap_page(card->dev, dma->dma_addr,
- get_dma_size(dma),
- (dma->cmd == HW_CMD_BLK_WRITE) ?
- PCI_DMA_TODEVICE :
- PCI_DMA_FROMDEVICE);
- kmem_cache_free(rsxx_dma_pool, dma);
- cnt++;
- }
+ mutex_lock(&ctrl->work_lock);
+ rsxx_issue_dmas(ctrl);
+ mutex_unlock(&ctrl->work_lock);
+}
- return cnt;
+static void rsxx_schedule_done(struct work_struct *work)
+{
+ struct rsxx_dma_ctrl *ctrl;
+
+ ctrl = container_of(work, struct rsxx_dma_ctrl, dma_done_work);
+
+ mutex_lock(&ctrl->work_lock);
+ rsxx_dma_done(ctrl);
+ mutex_unlock(&ctrl->work_lock);
}
static int rsxx_queue_discard(struct rsxx_cardinfo *card,
@@ -698,10 +723,10 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
for (i = 0; i < card->n_targets; i++) {
if (!list_empty(&dma_list[i])) {
- spin_lock(&card->ctrl[i].queue_lock);
+ spin_lock_bh(&card->ctrl[i].queue_lock);
card->ctrl[i].stats.sw_q_depth += dma_cnt[i];
list_splice_tail(&dma_list[i], &card->ctrl[i].queue);
- spin_unlock(&card->ctrl[i].queue_lock);
+ spin_unlock_bh(&card->ctrl[i].queue_lock);
queue_work(card->ctrl[i].issue_wq,
&card->ctrl[i].issue_dma_work);
@@ -711,8 +736,11 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
return 0;
bvec_err:
- for (i = 0; i < card->n_targets; i++)
- rsxx_cleanup_dma_queue(card, &dma_list[i]);
+ for (i = 0; i < card->n_targets; i++) {
+ spin_lock_bh(&card->ctrl[i].queue_lock);
+ rsxx_cleanup_dma_queue(&card->ctrl[i], &dma_list[i]);
+ spin_unlock_bh(&card->ctrl[i].queue_lock);
+ }
return st;
}
@@ -780,6 +808,7 @@ static int rsxx_dma_ctrl_init(struct pci_dev *dev,
spin_lock_init(&ctrl->trackers->lock);
spin_lock_init(&ctrl->queue_lock);
+ mutex_init(&ctrl->work_lock);
INIT_LIST_HEAD(&ctrl->queue);
setup_timer(&ctrl->activity_timer, dma_engine_stalled,
@@ -793,8 +822,8 @@ static int rsxx_dma_ctrl_init(struct pci_dev *dev,
if (!ctrl->done_wq)
return -ENOMEM;
- INIT_WORK(&ctrl->issue_dma_work, rsxx_issue_dmas);
- INIT_WORK(&ctrl->dma_done_work, rsxx_dma_done);
+ INIT_WORK(&ctrl->issue_dma_work, rsxx_schedule_issue);
+ INIT_WORK(&ctrl->dma_done_work, rsxx_schedule_done);
st = rsxx_hw_buffers_init(dev, ctrl);
if (st)
@@ -918,13 +947,30 @@ failed_dma_setup:
return st;
}
+int rsxx_dma_cancel(struct rsxx_dma_ctrl *ctrl)
+{
+ struct rsxx_dma *dma;
+ int i;
+ int cnt = 0;
+
+ /* Clean up issued DMAs */
+ for (i = 0; i < RSXX_MAX_OUTSTANDING_CMDS; i++) {
+ dma = get_tracker_dma(ctrl->trackers, i);
+ if (dma) {
+ atomic_dec(&ctrl->stats.hw_q_depth);
+ rsxx_complete_dma(ctrl, dma, DMA_CANCELLED);
+ push_tracker(ctrl->trackers, i);
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
void rsxx_dma_destroy(struct rsxx_cardinfo *card)
{
struct rsxx_dma_ctrl *ctrl;
- struct rsxx_dma *dma;
- int i, j;
- int cnt = 0;
+ int i;
for (i = 0; i < card->n_targets; i++) {
ctrl = &card->ctrl[i];
@@ -943,33 +989,11 @@ void rsxx_dma_destroy(struct rsxx_cardinfo *card)
del_timer_sync(&ctrl->activity_timer);
/* Clean up the DMA queue */
- spin_lock(&ctrl->queue_lock);
- cnt = rsxx_cleanup_dma_queue(card, &ctrl->queue);
- spin_unlock(&ctrl->queue_lock);
-
- if (cnt)
- dev_info(CARD_TO_DEV(card),
- "Freed %d queued DMAs on channel %d\n",
- cnt, i);
-
- /* Clean up issued DMAs */
- for (j = 0; j < RSXX_MAX_OUTSTANDING_CMDS; j++) {
- dma = get_tracker_dma(ctrl->trackers, j);
- if (dma) {
- pci_unmap_page(card->dev, dma->dma_addr,
- get_dma_size(dma),
- (dma->cmd == HW_CMD_BLK_WRITE) ?
- PCI_DMA_TODEVICE :
- PCI_DMA_FROMDEVICE);
- kmem_cache_free(rsxx_dma_pool, dma);
- cnt++;
- }
- }
+ spin_lock_bh(&ctrl->queue_lock);
+ rsxx_cleanup_dma_queue(ctrl, &ctrl->queue);
+ spin_unlock_bh(&ctrl->queue_lock);
- if (cnt)
- dev_info(CARD_TO_DEV(card),
- "Freed %d pending DMAs on channel %d\n",
- cnt, i);
+ rsxx_dma_cancel(ctrl);
vfree(ctrl->trackers);
@@ -1013,7 +1037,7 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card)
cnt++;
}
- spin_lock(&card->ctrl[i].queue_lock);
+ spin_lock_bh(&card->ctrl[i].queue_lock);
list_splice(&issued_dmas[i], &card->ctrl[i].queue);
atomic_sub(cnt, &card->ctrl[i].stats.hw_q_depth);
@@ -1028,7 +1052,7 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card)
PCI_DMA_TODEVICE :
PCI_DMA_FROMDEVICE);
}
- spin_unlock(&card->ctrl[i].queue_lock);
+ spin_unlock_bh(&card->ctrl[i].queue_lock);
}
kfree(issued_dmas);
@@ -1036,30 +1060,13 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card)
return 0;
}
-void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card)
-{
- struct rsxx_dma *dma;
- struct rsxx_dma *tmp;
- int i;
-
- for (i = 0; i < card->n_targets; i++) {
- spin_lock(&card->ctrl[i].queue_lock);
- list_for_each_entry_safe(dma, tmp, &card->ctrl[i].queue, list) {
- list_del(&dma->list);
-
- rsxx_complete_dma(&card->ctrl[i], dma, DMA_CANCELLED);
- }
- spin_unlock(&card->ctrl[i].queue_lock);
- }
-}
-
int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card)
{
struct rsxx_dma *dma;
int i;
for (i = 0; i < card->n_targets; i++) {
- spin_lock(&card->ctrl[i].queue_lock);
+ spin_lock_bh(&card->ctrl[i].queue_lock);
list_for_each_entry(dma, &card->ctrl[i].queue, list) {
dma->dma_addr = pci_map_page(card->dev, dma->page,
dma->pg_off, get_dma_size(dma),
@@ -1067,12 +1074,12 @@ int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card)
PCI_DMA_TODEVICE :
PCI_DMA_FROMDEVICE);
if (!dma->dma_addr) {
- spin_unlock(&card->ctrl[i].queue_lock);
+ spin_unlock_bh(&card->ctrl[i].queue_lock);
kmem_cache_free(rsxx_dma_pool, dma);
return -ENOMEM;
}
}
- spin_unlock(&card->ctrl[i].queue_lock);
+ spin_unlock_bh(&card->ctrl[i].queue_lock);
}
return 0;
diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h
index 382e8bf5c03..5ad5055a410 100644
--- a/drivers/block/rsxx/rsxx_priv.h
+++ b/drivers/block/rsxx/rsxx_priv.h
@@ -39,6 +39,7 @@
#include <linux/vmalloc.h>
#include <linux/timer.h>
#include <linux/ioctl.h>
+#include <linux/delay.h>
#include "rsxx.h"
#include "rsxx_cfg.h"
@@ -114,6 +115,7 @@ struct rsxx_dma_ctrl {
struct timer_list activity_timer;
struct dma_tracker_list *trackers;
struct rsxx_dma_stats stats;
+ struct mutex work_lock;
};
struct rsxx_cardinfo {
@@ -134,6 +136,7 @@ struct rsxx_cardinfo {
spinlock_t lock;
bool active;
struct creg_cmd *active_cmd;
+ struct workqueue_struct *creg_wq;
struct work_struct done_work;
struct list_head queue;
unsigned int q_depth;
@@ -154,6 +157,7 @@ struct rsxx_cardinfo {
int buf_len;
} log;
+ struct workqueue_struct *event_wq;
struct work_struct event_work;
unsigned int state;
u64 size8;
@@ -181,6 +185,8 @@ struct rsxx_cardinfo {
int n_targets;
struct rsxx_dma_ctrl *ctrl;
+
+ struct dentry *debugfs_dir;
};
enum rsxx_pci_regmap {
@@ -283,6 +289,7 @@ enum rsxx_creg_addr {
CREG_ADD_CAPABILITIES = 0x80001050,
CREG_ADD_LOG = 0x80002000,
CREG_ADD_NUM_TARGETS = 0x80003000,
+ CREG_ADD_CRAM = 0xA0000000,
CREG_ADD_CONFIG = 0xB0000000,
};
@@ -372,6 +379,8 @@ typedef void (*rsxx_dma_cb)(struct rsxx_cardinfo *card,
int rsxx_dma_setup(struct rsxx_cardinfo *card);
void rsxx_dma_destroy(struct rsxx_cardinfo *card);
int rsxx_dma_init(void);
+int rsxx_cleanup_dma_queue(struct rsxx_dma_ctrl *ctrl, struct list_head *q);
+int rsxx_dma_cancel(struct rsxx_dma_ctrl *ctrl);
void rsxx_dma_cleanup(void);
void rsxx_dma_queue_reset(struct rsxx_cardinfo *card);
int rsxx_dma_configure(struct rsxx_cardinfo *card);
@@ -382,7 +391,6 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
void *cb_data);
int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl);
int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card);
-void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card);
int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card);
/***** cregs.c *****/
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index dd5b2fed97e..bf4b9d282c0 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -50,110 +50,118 @@
#include "common.h"
/*
- * These are rather arbitrary. They are fairly large because adjacent requests
- * pulled from a communication ring are quite likely to end up being part of
- * the same scatter/gather request at the disc.
+ * Maximum number of unused free pages to keep in the internal buffer.
+ * Setting this to a value too low will reduce memory used in each backend,
+ * but can have a performance penalty.
*
- * ** TRY INCREASING 'xen_blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW **
- *
- * This will increase the chances of being able to write whole tracks.
- * 64 should be enough to keep us competitive with Linux.
+ * A sane value is xen_blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST, but can
+ * be set to a lower value that might degrade performance on some intensive
+ * IO workloads.
*/
-static int xen_blkif_reqs = 64;
-module_param_named(reqs, xen_blkif_reqs, int, 0);
-MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate");
-/* Run-time switchable: /sys/module/blkback/parameters/ */
-static unsigned int log_stats;
-module_param(log_stats, int, 0644);
+static int xen_blkif_max_buffer_pages = 1024;
+module_param_named(max_buffer_pages, xen_blkif_max_buffer_pages, int, 0644);
+MODULE_PARM_DESC(max_buffer_pages,
+"Maximum number of free pages to keep in each block backend buffer");
/*
- * Each outstanding request that we've passed to the lower device layers has a
- * 'pending_req' allocated to it. Each buffer_head that completes decrements
- * the pendcnt towards zero. When it hits zero, the specified domain has a
- * response queued for it, with the saved 'id' passed back.
+ * Maximum number of grants to map persistently in blkback. For maximum
+ * performance this should be the total numbers of grants that can be used
+ * to fill the ring, but since this might become too high, specially with
+ * the use of indirect descriptors, we set it to a value that provides good
+ * performance without using too much memory.
+ *
+ * When the list of persistent grants is full we clean it up using a LRU
+ * algorithm.
*/
-struct pending_req {
- struct xen_blkif *blkif;
- u64 id;
- int nr_pages;
- atomic_t pendcnt;
- unsigned short operation;
- int status;
- struct list_head free_list;
- DECLARE_BITMAP(unmap_seg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-};
-#define BLKBACK_INVALID_HANDLE (~0)
+static int xen_blkif_max_pgrants = 1056;
+module_param_named(max_persistent_grants, xen_blkif_max_pgrants, int, 0644);
+MODULE_PARM_DESC(max_persistent_grants,
+ "Maximum number of grants to map persistently");
-struct xen_blkbk {
- struct pending_req *pending_reqs;
- /* List of all 'pending_req' available */
- struct list_head pending_free;
- /* And its spinlock. */
- spinlock_t pending_free_lock;
- wait_queue_head_t pending_free_wq;
- /* The list of all pages that are available. */
- struct page **pending_pages;
- /* And the grant handles that are available. */
- grant_handle_t *pending_grant_handles;
-};
-
-static struct xen_blkbk *blkbk;
+/*
+ * The LRU mechanism to clean the lists of persistent grants needs to
+ * be executed periodically. The time interval between consecutive executions
+ * of the purge mechanism is set in ms.
+ */
+#define LRU_INTERVAL 100
/*
- * Maximum number of grant pages that can be mapped in blkback.
- * BLKIF_MAX_SEGMENTS_PER_REQUEST * RING_SIZE is the maximum number of
- * pages that blkback will persistently map.
- * Currently, this is:
- * RING_SIZE = 32 (for all known ring types)
- * BLKIF_MAX_SEGMENTS_PER_REQUEST = 11
- * sizeof(struct persistent_gnt) = 48
- * So the maximum memory used to store the grants is:
- * 32 * 11 * 48 = 16896 bytes
+ * When the persistent grants list is full we will remove unused grants
+ * from the list. The percent number of grants to be removed at each LRU
+ * execution.
*/
-static inline unsigned int max_mapped_grant_pages(enum blkif_protocol protocol)
+#define LRU_PERCENT_CLEAN 5
+
+/* Run-time switchable: /sys/module/blkback/parameters/ */
+static unsigned int log_stats;
+module_param(log_stats, int, 0644);
+
+#define BLKBACK_INVALID_HANDLE (~0)
+
+/* Number of free pages to remove on each call to free_xenballooned_pages */
+#define NUM_BATCH_FREE_PAGES 10
+
+static inline int get_free_page(struct xen_blkif *blkif, struct page **page)
{
- switch (protocol) {
- case BLKIF_PROTOCOL_NATIVE:
- return __CONST_RING_SIZE(blkif, PAGE_SIZE) *
- BLKIF_MAX_SEGMENTS_PER_REQUEST;
- case BLKIF_PROTOCOL_X86_32:
- return __CONST_RING_SIZE(blkif_x86_32, PAGE_SIZE) *
- BLKIF_MAX_SEGMENTS_PER_REQUEST;
- case BLKIF_PROTOCOL_X86_64:
- return __CONST_RING_SIZE(blkif_x86_64, PAGE_SIZE) *
- BLKIF_MAX_SEGMENTS_PER_REQUEST;
- default:
- BUG();
+ unsigned long flags;
+
+ spin_lock_irqsave(&blkif->free_pages_lock, flags);
+ if (list_empty(&blkif->free_pages)) {
+ BUG_ON(blkif->free_pages_num != 0);
+ spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
+ return alloc_xenballooned_pages(1, page, false);
}
+ BUG_ON(blkif->free_pages_num == 0);
+ page[0] = list_first_entry(&blkif->free_pages, struct page, lru);
+ list_del(&page[0]->lru);
+ blkif->free_pages_num--;
+ spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
+
return 0;
}
-
-/*
- * Little helpful macro to figure out the index and virtual address of the
- * pending_pages[..]. For each 'pending_req' we have have up to
- * BLKIF_MAX_SEGMENTS_PER_REQUEST (11) pages. The seg would be from 0 through
- * 10 and would index in the pending_pages[..].
- */
-static inline int vaddr_pagenr(struct pending_req *req, int seg)
+static inline void put_free_pages(struct xen_blkif *blkif, struct page **page,
+ int num)
{
- return (req - blkbk->pending_reqs) *
- BLKIF_MAX_SEGMENTS_PER_REQUEST + seg;
-}
+ unsigned long flags;
+ int i;
-#define pending_page(req, seg) pending_pages[vaddr_pagenr(req, seg)]
+ spin_lock_irqsave(&blkif->free_pages_lock, flags);
+ for (i = 0; i < num; i++)
+ list_add(&page[i]->lru, &blkif->free_pages);
+ blkif->free_pages_num += num;
+ spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
+}
-static inline unsigned long vaddr(struct pending_req *req, int seg)
+static inline void shrink_free_pagepool(struct xen_blkif *blkif, int num)
{
- unsigned long pfn = page_to_pfn(blkbk->pending_page(req, seg));
- return (unsigned long)pfn_to_kaddr(pfn);
-}
+ /* Remove requested pages in batches of NUM_BATCH_FREE_PAGES */
+ struct page *page[NUM_BATCH_FREE_PAGES];
+ unsigned int num_pages = 0;
+ unsigned long flags;
-#define pending_handle(_req, _seg) \
- (blkbk->pending_grant_handles[vaddr_pagenr(_req, _seg)])
+ spin_lock_irqsave(&blkif->free_pages_lock, flags);
+ while (blkif->free_pages_num > num) {
+ BUG_ON(list_empty(&blkif->free_pages));
+ page[num_pages] = list_first_entry(&blkif->free_pages,
+ struct page, lru);
+ list_del(&page[num_pages]->lru);
+ blkif->free_pages_num--;
+ if (++num_pages == NUM_BATCH_FREE_PAGES) {
+ spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
+ free_xenballooned_pages(num_pages, page);
+ spin_lock_irqsave(&blkif->free_pages_lock, flags);
+ num_pages = 0;
+ }
+ }
+ spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
+ if (num_pages != 0)
+ free_xenballooned_pages(num_pages, page);
+}
+#define vaddr(page) ((unsigned long)pfn_to_kaddr(page_to_pfn(page)))
static int do_block_io_op(struct xen_blkif *blkif);
static int dispatch_rw_block_io(struct xen_blkif *blkif,
@@ -170,13 +178,29 @@ static void make_response(struct xen_blkif *blkif, u64 id,
(n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL)
-static void add_persistent_gnt(struct rb_root *root,
+/*
+ * We don't need locking around the persistent grant helpers
+ * because blkback uses a single-thread for each backed, so we
+ * can be sure that this functions will never be called recursively.
+ *
+ * The only exception to that is put_persistent_grant, that can be called
+ * from interrupt context (by xen_blkbk_unmap), so we have to use atomic
+ * bit operations to modify the flags of a persistent grant and to count
+ * the number of used grants.
+ */
+static int add_persistent_gnt(struct xen_blkif *blkif,
struct persistent_gnt *persistent_gnt)
{
- struct rb_node **new = &(root->rb_node), *parent = NULL;
+ struct rb_node **new = NULL, *parent = NULL;
struct persistent_gnt *this;
+ if (blkif->persistent_gnt_c >= xen_blkif_max_pgrants) {
+ if (!blkif->vbd.overflow_max_grants)
+ blkif->vbd.overflow_max_grants = 1;
+ return -EBUSY;
+ }
/* Figure out where to put new node */
+ new = &blkif->persistent_gnts.rb_node;
while (*new) {
this = container_of(*new, struct persistent_gnt, node);
@@ -186,22 +210,28 @@ static void add_persistent_gnt(struct rb_root *root,
else if (persistent_gnt->gnt > this->gnt)
new = &((*new)->rb_right);
else {
- pr_alert(DRV_PFX " trying to add a gref that's already in the tree\n");
- BUG();
+ pr_alert_ratelimited(DRV_PFX " trying to add a gref that's already in the tree\n");
+ return -EINVAL;
}
}
+ bitmap_zero(persistent_gnt->flags, PERSISTENT_GNT_FLAGS_SIZE);
+ set_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags);
/* Add new node and rebalance tree. */
rb_link_node(&(persistent_gnt->node), parent, new);
- rb_insert_color(&(persistent_gnt->node), root);
+ rb_insert_color(&(persistent_gnt->node), &blkif->persistent_gnts);
+ blkif->persistent_gnt_c++;
+ atomic_inc(&blkif->persistent_gnt_in_use);
+ return 0;
}
-static struct persistent_gnt *get_persistent_gnt(struct rb_root *root,
+static struct persistent_gnt *get_persistent_gnt(struct xen_blkif *blkif,
grant_ref_t gref)
{
struct persistent_gnt *data;
- struct rb_node *node = root->rb_node;
+ struct rb_node *node = NULL;
+ node = blkif->persistent_gnts.rb_node;
while (node) {
data = container_of(node, struct persistent_gnt, node);
@@ -209,13 +239,31 @@ static struct persistent_gnt *get_persistent_gnt(struct rb_root *root,
node = node->rb_left;
else if (gref > data->gnt)
node = node->rb_right;
- else
+ else {
+ if(test_bit(PERSISTENT_GNT_ACTIVE, data->flags)) {
+ pr_alert_ratelimited(DRV_PFX " requesting a grant already in use\n");
+ return NULL;
+ }
+ set_bit(PERSISTENT_GNT_ACTIVE, data->flags);
+ atomic_inc(&blkif->persistent_gnt_in_use);
return data;
+ }
}
return NULL;
}
-static void free_persistent_gnts(struct rb_root *root, unsigned int num)
+static void put_persistent_gnt(struct xen_blkif *blkif,
+ struct persistent_gnt *persistent_gnt)
+{
+ if(!test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags))
+ pr_alert_ratelimited(DRV_PFX " freeing a grant already unused");
+ set_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags);
+ clear_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags);
+ atomic_dec(&blkif->persistent_gnt_in_use);
+}
+
+static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
+ unsigned int num)
{
struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
@@ -240,7 +288,7 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num)
ret = gnttab_unmap_refs(unmap, NULL, pages,
segs_to_unmap);
BUG_ON(ret);
- free_xenballooned_pages(segs_to_unmap, pages);
+ put_free_pages(blkif, pages, segs_to_unmap);
segs_to_unmap = 0;
}
@@ -251,21 +299,148 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num)
BUG_ON(num != 0);
}
+static void unmap_purged_grants(struct work_struct *work)
+{
+ struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ struct persistent_gnt *persistent_gnt;
+ int ret, segs_to_unmap = 0;
+ struct xen_blkif *blkif = container_of(work, typeof(*blkif), persistent_purge_work);
+
+ while(!list_empty(&blkif->persistent_purge_list)) {
+ persistent_gnt = list_first_entry(&blkif->persistent_purge_list,
+ struct persistent_gnt,
+ remove_node);
+ list_del(&persistent_gnt->remove_node);
+
+ gnttab_set_unmap_op(&unmap[segs_to_unmap],
+ vaddr(persistent_gnt->page),
+ GNTMAP_host_map,
+ persistent_gnt->handle);
+
+ pages[segs_to_unmap] = persistent_gnt->page;
+
+ if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+ ret = gnttab_unmap_refs(unmap, NULL, pages,
+ segs_to_unmap);
+ BUG_ON(ret);
+ put_free_pages(blkif, pages, segs_to_unmap);
+ segs_to_unmap = 0;
+ }
+ kfree(persistent_gnt);
+ }
+ if (segs_to_unmap > 0) {
+ ret = gnttab_unmap_refs(unmap, NULL, pages, segs_to_unmap);
+ BUG_ON(ret);
+ put_free_pages(blkif, pages, segs_to_unmap);
+ }
+}
+
+static void purge_persistent_gnt(struct xen_blkif *blkif)
+{
+ struct persistent_gnt *persistent_gnt;
+ struct rb_node *n;
+ unsigned int num_clean, total;
+ bool scan_used = false, clean_used = false;
+ struct rb_root *root;
+
+ if (blkif->persistent_gnt_c < xen_blkif_max_pgrants ||
+ (blkif->persistent_gnt_c == xen_blkif_max_pgrants &&
+ !blkif->vbd.overflow_max_grants)) {
+ return;
+ }
+
+ if (work_pending(&blkif->persistent_purge_work)) {
+ pr_alert_ratelimited(DRV_PFX "Scheduled work from previous purge is still pending, cannot purge list\n");
+ return;
+ }
+
+ num_clean = (xen_blkif_max_pgrants / 100) * LRU_PERCENT_CLEAN;
+ num_clean = blkif->persistent_gnt_c - xen_blkif_max_pgrants + num_clean;
+ num_clean = min(blkif->persistent_gnt_c, num_clean);
+ if ((num_clean == 0) ||
+ (num_clean > (blkif->persistent_gnt_c - atomic_read(&blkif->persistent_gnt_in_use))))
+ return;
+
+ /*
+ * At this point, we can assure that there will be no calls
+ * to get_persistent_grant (because we are executing this code from
+ * xen_blkif_schedule), there can only be calls to put_persistent_gnt,
+ * which means that the number of currently used grants will go down,
+ * but never up, so we will always be able to remove the requested
+ * number of grants.
+ */
+
+ total = num_clean;
+
+ pr_debug(DRV_PFX "Going to purge %u persistent grants\n", num_clean);
+
+ INIT_LIST_HEAD(&blkif->persistent_purge_list);
+ root = &blkif->persistent_gnts;
+purge_list:
+ foreach_grant_safe(persistent_gnt, n, root, node) {
+ BUG_ON(persistent_gnt->handle ==
+ BLKBACK_INVALID_HANDLE);
+
+ if (clean_used) {
+ clear_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags);
+ continue;
+ }
+
+ if (test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags))
+ continue;
+ if (!scan_used &&
+ (test_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags)))
+ continue;
+
+ rb_erase(&persistent_gnt->node, root);
+ list_add(&persistent_gnt->remove_node,
+ &blkif->persistent_purge_list);
+ if (--num_clean == 0)
+ goto finished;
+ }
+ /*
+ * If we get here it means we also need to start cleaning
+ * grants that were used since last purge in order to cope
+ * with the requested num
+ */
+ if (!scan_used && !clean_used) {
+ pr_debug(DRV_PFX "Still missing %u purged frames\n", num_clean);
+ scan_used = true;
+ goto purge_list;
+ }
+finished:
+ if (!clean_used) {
+ pr_debug(DRV_PFX "Finished scanning for grants to clean, removing used flag\n");
+ clean_used = true;
+ goto purge_list;
+ }
+
+ blkif->persistent_gnt_c -= (total - num_clean);
+ blkif->vbd.overflow_max_grants = 0;
+
+ /* We can defer this work */
+ INIT_WORK(&blkif->persistent_purge_work, unmap_purged_grants);
+ schedule_work(&blkif->persistent_purge_work);
+ pr_debug(DRV_PFX "Purged %u/%u\n", (total - num_clean), total);
+ return;
+}
+
/*
* Retrieve from the 'pending_reqs' a free pending_req structure to be used.
*/
-static struct pending_req *alloc_req(void)
+static struct pending_req *alloc_req(struct xen_blkif *blkif)
{
struct pending_req *req = NULL;
unsigned long flags;
- spin_lock_irqsave(&blkbk->pending_free_lock, flags);
- if (!list_empty(&blkbk->pending_free)) {
- req = list_entry(blkbk->pending_free.next, struct pending_req,
+ spin_lock_irqsave(&blkif->pending_free_lock, flags);
+ if (!list_empty(&blkif->pending_free)) {
+ req = list_entry(blkif->pending_free.next, struct pending_req,
free_list);
list_del(&req->free_list);
}
- spin_unlock_irqrestore(&blkbk->pending_free_lock, flags);
+ spin_unlock_irqrestore(&blkif->pending_free_lock, flags);
return req;
}
@@ -273,17 +448,17 @@ static struct pending_req *alloc_req(void)
* Return the 'pending_req' structure back to the freepool. We also
* wake up the thread if it was waiting for a free page.
*/
-static void free_req(struct pending_req *req)
+static void free_req(struct xen_blkif *blkif, struct pending_req *req)
{
unsigned long flags;
int was_empty;
- spin_lock_irqsave(&blkbk->pending_free_lock, flags);
- was_empty = list_empty(&blkbk->pending_free);
- list_add(&req->free_list, &blkbk->pending_free);
- spin_unlock_irqrestore(&blkbk->pending_free_lock, flags);
+ spin_lock_irqsave(&blkif->pending_free_lock, flags);
+ was_empty = list_empty(&blkif->pending_free);
+ list_add(&req->free_list, &blkif->pending_free);
+ spin_unlock_irqrestore(&blkif->pending_free_lock, flags);
if (was_empty)
- wake_up(&blkbk->pending_free_wq);
+ wake_up(&blkif->pending_free_wq);
}
/*
@@ -382,10 +557,12 @@ irqreturn_t xen_blkif_be_int(int irq, void *dev_id)
static void print_stats(struct xen_blkif *blkif)
{
pr_info("xen-blkback (%s): oo %3llu | rd %4llu | wr %4llu | f %4llu"
- " | ds %4llu\n",
+ " | ds %4llu | pg: %4u/%4d\n",
current->comm, blkif->st_oo_req,
blkif->st_rd_req, blkif->st_wr_req,
- blkif->st_f_req, blkif->st_ds_req);
+ blkif->st_f_req, blkif->st_ds_req,
+ blkif->persistent_gnt_c,
+ xen_blkif_max_pgrants);
blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
blkif->st_rd_req = 0;
blkif->st_wr_req = 0;
@@ -397,6 +574,8 @@ int xen_blkif_schedule(void *arg)
{
struct xen_blkif *blkif = arg;
struct xen_vbd *vbd = &blkif->vbd;
+ unsigned long timeout;
+ int ret;
xen_blkif_get(blkif);
@@ -406,27 +585,52 @@ int xen_blkif_schedule(void *arg)
if (unlikely(vbd->size != vbd_sz(vbd)))
xen_vbd_resize(blkif);
- wait_event_interruptible(
+ timeout = msecs_to_jiffies(LRU_INTERVAL);
+
+ timeout = wait_event_interruptible_timeout(
blkif->wq,
- blkif->waiting_reqs || kthread_should_stop());
- wait_event_interruptible(
- blkbk->pending_free_wq,
- !list_empty(&blkbk->pending_free) ||
- kthread_should_stop());
+ blkif->waiting_reqs || kthread_should_stop(),
+ timeout);
+ if (timeout == 0)
+ goto purge_gnt_list;
+ timeout = wait_event_interruptible_timeout(
+ blkif->pending_free_wq,
+ !list_empty(&blkif->pending_free) ||
+ kthread_should_stop(),
+ timeout);
+ if (timeout == 0)
+ goto purge_gnt_list;
blkif->waiting_reqs = 0;
smp_mb(); /* clear flag *before* checking for work */
- if (do_block_io_op(blkif))
+ ret = do_block_io_op(blkif);
+ if (ret > 0)
blkif->waiting_reqs = 1;
+ if (ret == -EACCES)
+ wait_event_interruptible(blkif->shutdown_wq,
+ kthread_should_stop());
+
+purge_gnt_list:
+ if (blkif->vbd.feature_gnt_persistent &&
+ time_after(jiffies, blkif->next_lru)) {
+ purge_persistent_gnt(blkif);
+ blkif->next_lru = jiffies + msecs_to_jiffies(LRU_INTERVAL);
+ }
+
+ /* Shrink if we have more than xen_blkif_max_buffer_pages */
+ shrink_free_pagepool(blkif, xen_blkif_max_buffer_pages);
if (log_stats && time_after(jiffies, blkif->st_print))
print_stats(blkif);
}
+ /* Since we are shutting down remove all pages from the buffer */
+ shrink_free_pagepool(blkif, 0 /* All */);
+
/* Free all persistent grant pages */
if (!RB_EMPTY_ROOT(&blkif->persistent_gnts))
- free_persistent_gnts(&blkif->persistent_gnts,
+ free_persistent_gnts(blkif, &blkif->persistent_gnts,
blkif->persistent_gnt_c);
BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts));
@@ -441,148 +645,98 @@ int xen_blkif_schedule(void *arg)
return 0;
}
-struct seg_buf {
- unsigned int offset;
- unsigned int nsec;
-};
/*
* Unmap the grant references, and also remove the M2P over-rides
* used in the 'pending_req'.
*/
-static void xen_blkbk_unmap(struct pending_req *req)
+static void xen_blkbk_unmap(struct xen_blkif *blkif,
+ struct grant_page *pages[],
+ int num)
{
struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ struct page *unmap_pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
unsigned int i, invcount = 0;
- grant_handle_t handle;
int ret;
- for (i = 0; i < req->nr_pages; i++) {
- if (!test_bit(i, req->unmap_seg))
+ for (i = 0; i < num; i++) {
+ if (pages[i]->persistent_gnt != NULL) {
+ put_persistent_gnt(blkif, pages[i]->persistent_gnt);
continue;
- handle = pending_handle(req, i);
- if (handle == BLKBACK_INVALID_HANDLE)
+ }
+ if (pages[i]->handle == BLKBACK_INVALID_HANDLE)
continue;
- gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i),
- GNTMAP_host_map, handle);
- pending_handle(req, i) = BLKBACK_INVALID_HANDLE;
- pages[invcount] = virt_to_page(vaddr(req, i));
- invcount++;
+ unmap_pages[invcount] = pages[i]->page;
+ gnttab_set_unmap_op(&unmap[invcount], vaddr(pages[i]->page),
+ GNTMAP_host_map, pages[i]->handle);
+ pages[i]->handle = BLKBACK_INVALID_HANDLE;
+ if (++invcount == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+ ret = gnttab_unmap_refs(unmap, NULL, unmap_pages,
+ invcount);
+ BUG_ON(ret);
+ put_free_pages(blkif, unmap_pages, invcount);
+ invcount = 0;
+ }
+ }
+ if (invcount) {
+ ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, invcount);
+ BUG_ON(ret);
+ put_free_pages(blkif, unmap_pages, invcount);
}
-
- ret = gnttab_unmap_refs(unmap, NULL, pages, invcount);
- BUG_ON(ret);
}
-static int xen_blkbk_map(struct blkif_request *req,
- struct pending_req *pending_req,
- struct seg_buf seg[],
- struct page *pages[])
+static int xen_blkbk_map(struct xen_blkif *blkif,
+ struct grant_page *pages[],
+ int num, bool ro)
{
struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- struct persistent_gnt *persistent_gnts[BLKIF_MAX_SEGMENTS_PER_REQUEST];
struct page *pages_to_gnt[BLKIF_MAX_SEGMENTS_PER_REQUEST];
struct persistent_gnt *persistent_gnt = NULL;
- struct xen_blkif *blkif = pending_req->blkif;
phys_addr_t addr = 0;
- int i, j;
- bool new_map;
- int nseg = req->u.rw.nr_segments;
+ int i, seg_idx, new_map_idx;
int segs_to_map = 0;
int ret = 0;
+ int last_map = 0, map_until = 0;
int use_persistent_gnts;
use_persistent_gnts = (blkif->vbd.feature_gnt_persistent);
- BUG_ON(blkif->persistent_gnt_c >
- max_mapped_grant_pages(pending_req->blkif->blk_protocol));
-
/*
* Fill out preq.nr_sects with proper amount of sectors, and setup
* assign map[..] with the PFN of the page in our domain with the
* corresponding grant reference for each page.
*/
- for (i = 0; i < nseg; i++) {
+again:
+ for (i = map_until; i < num; i++) {
uint32_t flags;
if (use_persistent_gnts)
persistent_gnt = get_persistent_gnt(
- &blkif->persistent_gnts,
- req->u.rw.seg[i].gref);
+ blkif,
+ pages[i]->gref);
if (persistent_gnt) {
/*
* We are using persistent grants and
* the grant is already mapped
*/
- new_map = false;
- } else if (use_persistent_gnts &&
- blkif->persistent_gnt_c <
- max_mapped_grant_pages(blkif->blk_protocol)) {
- /*
- * We are using persistent grants, the grant is
- * not mapped but we have room for it
- */
- new_map = true;
- persistent_gnt = kmalloc(
- sizeof(struct persistent_gnt),
- GFP_KERNEL);
- if (!persistent_gnt)
- return -ENOMEM;
- if (alloc_xenballooned_pages(1, &persistent_gnt->page,
- false)) {
- kfree(persistent_gnt);
- return -ENOMEM;
- }
- persistent_gnt->gnt = req->u.rw.seg[i].gref;
- persistent_gnt->handle = BLKBACK_INVALID_HANDLE;
-
- pages_to_gnt[segs_to_map] =
- persistent_gnt->page;
- addr = (unsigned long) pfn_to_kaddr(
- page_to_pfn(persistent_gnt->page));
-
- add_persistent_gnt(&blkif->persistent_gnts,
- persistent_gnt);
- blkif->persistent_gnt_c++;
- pr_debug(DRV_PFX " grant %u added to the tree of persistent grants, using %u/%u\n",
- persistent_gnt->gnt, blkif->persistent_gnt_c,
- max_mapped_grant_pages(blkif->blk_protocol));
+ pages[i]->page = persistent_gnt->page;
+ pages[i]->persistent_gnt = persistent_gnt;
} else {
- /*
- * We are either using persistent grants and
- * hit the maximum limit of grants mapped,
- * or we are not using persistent grants.
- */
- if (use_persistent_gnts &&
- !blkif->vbd.overflow_max_grants) {
- blkif->vbd.overflow_max_grants = 1;
- pr_alert(DRV_PFX " domain %u, device %#x is using maximum number of persistent grants\n",
- blkif->domid, blkif->vbd.handle);
- }
- new_map = true;
- pages[i] = blkbk->pending_page(pending_req, i);
- addr = vaddr(pending_req, i);
- pages_to_gnt[segs_to_map] =
- blkbk->pending_page(pending_req, i);
- }
-
- if (persistent_gnt) {
- pages[i] = persistent_gnt->page;
- persistent_gnts[i] = persistent_gnt;
- } else {
- persistent_gnts[i] = NULL;
- }
-
- if (new_map) {
+ if (get_free_page(blkif, &pages[i]->page))
+ goto out_of_memory;
+ addr = vaddr(pages[i]->page);
+ pages_to_gnt[segs_to_map] = pages[i]->page;
+ pages[i]->persistent_gnt = NULL;
flags = GNTMAP_host_map;
- if (!persistent_gnt &&
- (pending_req->operation != BLKIF_OP_READ))
+ if (!use_persistent_gnts && ro)
flags |= GNTMAP_readonly;
gnttab_set_map_op(&map[segs_to_map++], addr,
- flags, req->u.rw.seg[i].gref,
+ flags, pages[i]->gref,
blkif->domid);
}
+ map_until = i + 1;
+ if (segs_to_map == BLKIF_MAX_SEGMENTS_PER_REQUEST)
+ break;
}
if (segs_to_map) {
@@ -595,49 +749,133 @@ static int xen_blkbk_map(struct blkif_request *req,
* so that when we access vaddr(pending_req,i) it has the contents of
* the page from the other domain.
*/
- bitmap_zero(pending_req->unmap_seg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
- for (i = 0, j = 0; i < nseg; i++) {
- if (!persistent_gnts[i] ||
- persistent_gnts[i]->handle == BLKBACK_INVALID_HANDLE) {
+ for (seg_idx = last_map, new_map_idx = 0; seg_idx < map_until; seg_idx++) {
+ if (!pages[seg_idx]->persistent_gnt) {
/* This is a newly mapped grant */
- BUG_ON(j >= segs_to_map);
- if (unlikely(map[j].status != 0)) {
+ BUG_ON(new_map_idx >= segs_to_map);
+ if (unlikely(map[new_map_idx].status != 0)) {
pr_debug(DRV_PFX "invalid buffer -- could not remap it\n");
- map[j].handle = BLKBACK_INVALID_HANDLE;
+ pages[seg_idx]->handle = BLKBACK_INVALID_HANDLE;
ret |= 1;
- if (persistent_gnts[i]) {
- rb_erase(&persistent_gnts[i]->node,
- &blkif->persistent_gnts);
- blkif->persistent_gnt_c--;
- kfree(persistent_gnts[i]);
- persistent_gnts[i] = NULL;
- }
+ goto next;
}
+ pages[seg_idx]->handle = map[new_map_idx].handle;
+ } else {
+ continue;
}
- if (persistent_gnts[i]) {
- if (persistent_gnts[i]->handle ==
- BLKBACK_INVALID_HANDLE) {
+ if (use_persistent_gnts &&
+ blkif->persistent_gnt_c < xen_blkif_max_pgrants) {
+ /*
+ * We are using persistent grants, the grant is
+ * not mapped but we might have room for it.
+ */
+ persistent_gnt = kmalloc(sizeof(struct persistent_gnt),
+ GFP_KERNEL);
+ if (!persistent_gnt) {
/*
- * If this is a new persistent grant
- * save the handler
+ * If we don't have enough memory to
+ * allocate the persistent_gnt struct
+ * map this grant non-persistenly
*/
- persistent_gnts[i]->handle = map[j++].handle;
+ goto next;
}
- pending_handle(pending_req, i) =
- persistent_gnts[i]->handle;
+ persistent_gnt->gnt = map[new_map_idx].ref;
+ persistent_gnt->handle = map[new_map_idx].handle;
+ persistent_gnt->page = pages[seg_idx]->page;
+ if (add_persistent_gnt(blkif,
+ persistent_gnt)) {
+ kfree(persistent_gnt);
+ persistent_gnt = NULL;
+ goto next;
+ }
+ pages[seg_idx]->persistent_gnt = persistent_gnt;
+ pr_debug(DRV_PFX " grant %u added to the tree of persistent grants, using %u/%u\n",
+ persistent_gnt->gnt, blkif->persistent_gnt_c,
+ xen_blkif_max_pgrants);
+ goto next;
+ }
+ if (use_persistent_gnts && !blkif->vbd.overflow_max_grants) {
+ blkif->vbd.overflow_max_grants = 1;
+ pr_debug(DRV_PFX " domain %u, device %#x is using maximum number of persistent grants\n",
+ blkif->domid, blkif->vbd.handle);
+ }
+ /*
+ * We could not map this grant persistently, so use it as
+ * a non-persistent grant.
+ */
+next:
+ new_map_idx++;
+ }
+ segs_to_map = 0;
+ last_map = map_until;
+ if (map_until != num)
+ goto again;
- if (ret)
- continue;
- } else {
- pending_handle(pending_req, i) = map[j++].handle;
- bitmap_set(pending_req->unmap_seg, i, 1);
+ return ret;
+
+out_of_memory:
+ pr_alert(DRV_PFX "%s: out of memory\n", __func__);
+ put_free_pages(blkif, pages_to_gnt, segs_to_map);
+ return -ENOMEM;
+}
+
+static int xen_blkbk_map_seg(struct pending_req *pending_req)
+{
+ int rc;
+
+ rc = xen_blkbk_map(pending_req->blkif, pending_req->segments,
+ pending_req->nr_pages,
+ (pending_req->operation != BLKIF_OP_READ));
+
+ return rc;
+}
- if (ret)
- continue;
+static int xen_blkbk_parse_indirect(struct blkif_request *req,
+ struct pending_req *pending_req,
+ struct seg_buf seg[],
+ struct phys_req *preq)
+{
+ struct grant_page **pages = pending_req->indirect_pages;
+ struct xen_blkif *blkif = pending_req->blkif;
+ int indirect_grefs, rc, n, nseg, i;
+ struct blkif_request_segment_aligned *segments = NULL;
+
+ nseg = pending_req->nr_pages;
+ indirect_grefs = INDIRECT_PAGES(nseg);
+ BUG_ON(indirect_grefs > BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST);
+
+ for (i = 0; i < indirect_grefs; i++)
+ pages[i]->gref = req->u.indirect.indirect_grefs[i];
+
+ rc = xen_blkbk_map(blkif, pages, indirect_grefs, true);
+ if (rc)
+ goto unmap;
+
+ for (n = 0, i = 0; n < nseg; n++) {
+ if ((n % SEGS_PER_INDIRECT_FRAME) == 0) {
+ /* Map indirect segments */
+ if (segments)
+ kunmap_atomic(segments);
+ segments = kmap_atomic(pages[n/SEGS_PER_INDIRECT_FRAME]->page);
+ }
+ i = n % SEGS_PER_INDIRECT_FRAME;
+ pending_req->segments[n]->gref = segments[i].gref;
+ seg[n].nsec = segments[i].last_sect -
+ segments[i].first_sect + 1;
+ seg[n].offset = (segments[i].first_sect << 9);
+ if ((segments[i].last_sect >= (PAGE_SIZE >> 9)) ||
+ (segments[i].last_sect < segments[i].first_sect)) {
+ rc = -EINVAL;
+ goto unmap;
}
- seg[i].offset = (req->u.rw.seg[i].first_sect << 9);
+ preq->nr_sects += seg[n].nsec;
}
- return ret;
+
+unmap:
+ if (segments)
+ kunmap_atomic(segments);
+ xen_blkbk_unmap(blkif, pages, indirect_grefs);
+ return rc;
}
static int dispatch_discard_io(struct xen_blkif *blkif,
@@ -647,7 +885,18 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
int status = BLKIF_RSP_OKAY;
struct block_device *bdev = blkif->vbd.bdev;
unsigned long secure;
+ struct phys_req preq;
+
+ preq.sector_number = req->u.discard.sector_number;
+ preq.nr_sects = req->u.discard.nr_sectors;
+ err = xen_vbd_translate(&preq, blkif, WRITE);
+ if (err) {
+ pr_warn(DRV_PFX "access denied: DISCARD [%llu->%llu] on dev=%04x\n",
+ preq.sector_number,
+ preq.sector_number + preq.nr_sects, blkif->vbd.pdevice);
+ goto fail_response;
+ }
blkif->st_ds_req++;
xen_blkif_get(blkif);
@@ -658,7 +907,7 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
err = blkdev_issue_discard(bdev, req->u.discard.sector_number,
req->u.discard.nr_sectors,
GFP_KERNEL, secure);
-
+fail_response:
if (err == -EOPNOTSUPP) {
pr_debug(DRV_PFX "discard op failed, not supported\n");
status = BLKIF_RSP_EOPNOTSUPP;
@@ -674,7 +923,7 @@ static int dispatch_other_io(struct xen_blkif *blkif,
struct blkif_request *req,
struct pending_req *pending_req)
{
- free_req(pending_req);
+ free_req(blkif, pending_req);
make_response(blkif, req->u.other.id, req->operation,
BLKIF_RSP_EOPNOTSUPP);
return -EIO;
@@ -726,7 +975,9 @@ static void __end_block_io_op(struct pending_req *pending_req, int error)
* the proper response on the ring.
*/
if (atomic_dec_and_test(&pending_req->pendcnt)) {
- xen_blkbk_unmap(pending_req);
+ xen_blkbk_unmap(pending_req->blkif,
+ pending_req->segments,
+ pending_req->nr_pages);
make_response(pending_req->blkif, pending_req->id,
pending_req->operation, pending_req->status);
xen_blkif_put(pending_req->blkif);
@@ -734,7 +985,7 @@ static void __end_block_io_op(struct pending_req *pending_req, int error)
if (atomic_read(&pending_req->blkif->drain))
complete(&pending_req->blkif->drain_complete);
}
- free_req(pending_req);
+ free_req(pending_req->blkif, pending_req);
}
}
@@ -767,6 +1018,12 @@ __do_block_io_op(struct xen_blkif *blkif)
rp = blk_rings->common.sring->req_prod;
rmb(); /* Ensure we see queued requests up to 'rp'. */
+ if (RING_REQUEST_PROD_OVERFLOW(&blk_rings->common, rp)) {
+ rc = blk_rings->common.rsp_prod_pvt;
+ pr_warn(DRV_PFX "Frontend provided bogus ring requests (%d - %d = %d). Halting ring processing on dev=%04x\n",
+ rp, rc, rp - rc, blkif->vbd.pdevice);
+ return -EACCES;
+ }
while (rc != rp) {
if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
@@ -777,7 +1034,7 @@ __do_block_io_op(struct xen_blkif *blkif)
break;
}
- pending_req = alloc_req();
+ pending_req = alloc_req(blkif);
if (NULL == pending_req) {
blkif->st_oo_req++;
more_to_do = 1;
@@ -807,11 +1064,12 @@ __do_block_io_op(struct xen_blkif *blkif)
case BLKIF_OP_WRITE:
case BLKIF_OP_WRITE_BARRIER:
case BLKIF_OP_FLUSH_DISKCACHE:
+ case BLKIF_OP_INDIRECT:
if (dispatch_rw_block_io(blkif, &req, pending_req))
goto done;
break;
case BLKIF_OP_DISCARD:
- free_req(pending_req);
+ free_req(blkif, pending_req);
if (dispatch_discard_io(blkif, &req))
goto done;
break;
@@ -853,17 +1111,28 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
struct pending_req *pending_req)
{
struct phys_req preq;
- struct seg_buf seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ struct seg_buf *seg = pending_req->seg;
unsigned int nseg;
struct bio *bio = NULL;
- struct bio *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ struct bio **biolist = pending_req->biolist;
int i, nbio = 0;
int operation;
struct blk_plug plug;
bool drain = false;
- struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ struct grant_page **pages = pending_req->segments;
+ unsigned short req_operation;
+
+ req_operation = req->operation == BLKIF_OP_INDIRECT ?
+ req->u.indirect.indirect_op : req->operation;
+ if ((req->operation == BLKIF_OP_INDIRECT) &&
+ (req_operation != BLKIF_OP_READ) &&
+ (req_operation != BLKIF_OP_WRITE)) {
+ pr_debug(DRV_PFX "Invalid indirect operation (%u)\n",
+ req_operation);
+ goto fail_response;
+ }
- switch (req->operation) {
+ switch (req_operation) {
case BLKIF_OP_READ:
blkif->st_rd_req++;
operation = READ;
@@ -885,33 +1154,47 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
}
/* Check that the number of segments is sane. */
- nseg = req->u.rw.nr_segments;
+ nseg = req->operation == BLKIF_OP_INDIRECT ?
+ req->u.indirect.nr_segments : req->u.rw.nr_segments;
if (unlikely(nseg == 0 && operation != WRITE_FLUSH) ||
- unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
+ unlikely((req->operation != BLKIF_OP_INDIRECT) &&
+ (nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) ||
+ unlikely((req->operation == BLKIF_OP_INDIRECT) &&
+ (nseg > MAX_INDIRECT_SEGMENTS))) {
pr_debug(DRV_PFX "Bad number of segments in request (%d)\n",
nseg);
/* Haven't submitted any bio's yet. */
goto fail_response;
}
- preq.sector_number = req->u.rw.sector_number;
preq.nr_sects = 0;
pending_req->blkif = blkif;
pending_req->id = req->u.rw.id;
- pending_req->operation = req->operation;
+ pending_req->operation = req_operation;
pending_req->status = BLKIF_RSP_OKAY;
pending_req->nr_pages = nseg;
- for (i = 0; i < nseg; i++) {
- seg[i].nsec = req->u.rw.seg[i].last_sect -
- req->u.rw.seg[i].first_sect + 1;
- if ((req->u.rw.seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
- (req->u.rw.seg[i].last_sect < req->u.rw.seg[i].first_sect))
+ if (req->operation != BLKIF_OP_INDIRECT) {
+ preq.dev = req->u.rw.handle;
+ preq.sector_number = req->u.rw.sector_number;
+ for (i = 0; i < nseg; i++) {
+ pages[i]->gref = req->u.rw.seg[i].gref;
+ seg[i].nsec = req->u.rw.seg[i].last_sect -
+ req->u.rw.seg[i].first_sect + 1;
+ seg[i].offset = (req->u.rw.seg[i].first_sect << 9);
+ if ((req->u.rw.seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
+ (req->u.rw.seg[i].last_sect <
+ req->u.rw.seg[i].first_sect))
+ goto fail_response;
+ preq.nr_sects += seg[i].nsec;
+ }
+ } else {
+ preq.dev = req->u.indirect.handle;
+ preq.sector_number = req->u.indirect.sector_number;
+ if (xen_blkbk_parse_indirect(req, pending_req, seg, &preq))
goto fail_response;
- preq.nr_sects += seg[i].nsec;
-
}
if (xen_vbd_translate(&preq, blkif, operation) != 0) {
@@ -948,7 +1231,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
* the hypercall to unmap the grants - that is all done in
* xen_blkbk_unmap.
*/
- if (xen_blkbk_map(req, pending_req, seg, pages))
+ if (xen_blkbk_map_seg(pending_req))
goto fail_flush;
/*
@@ -960,11 +1243,12 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
for (i = 0; i < nseg; i++) {
while ((bio == NULL) ||
(bio_add_page(bio,
- pages[i],
+ pages[i]->page,
seg[i].nsec << 9,
seg[i].offset) == 0)) {
- bio = bio_alloc(GFP_KERNEL, nseg-i);
+ int nr_iovecs = min_t(int, (nseg-i), BIO_MAX_PAGES);
+ bio = bio_alloc(GFP_KERNEL, nr_iovecs);
if (unlikely(bio == NULL))
goto fail_put_bio;
@@ -1009,11 +1293,12 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
return 0;
fail_flush:
- xen_blkbk_unmap(pending_req);
+ xen_blkbk_unmap(blkif, pending_req->segments,
+ pending_req->nr_pages);
fail_response:
/* Haven't submitted any bio's yet. */
- make_response(blkif, req->u.rw.id, req->operation, BLKIF_RSP_ERROR);
- free_req(pending_req);
+ make_response(blkif, req->u.rw.id, req_operation, BLKIF_RSP_ERROR);
+ free_req(blkif, pending_req);
msleep(1); /* back off a bit */
return -EIO;
@@ -1070,73 +1355,20 @@ static void make_response(struct xen_blkif *blkif, u64 id,
static int __init xen_blkif_init(void)
{
- int i, mmap_pages;
int rc = 0;
if (!xen_domain())
return -ENODEV;
- blkbk = kzalloc(sizeof(struct xen_blkbk), GFP_KERNEL);
- if (!blkbk) {
- pr_alert(DRV_PFX "%s: out of memory!\n", __func__);
- return -ENOMEM;
- }
-
- mmap_pages = xen_blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
-
- blkbk->pending_reqs = kzalloc(sizeof(blkbk->pending_reqs[0]) *
- xen_blkif_reqs, GFP_KERNEL);
- blkbk->pending_grant_handles = kmalloc(sizeof(blkbk->pending_grant_handles[0]) *
- mmap_pages, GFP_KERNEL);
- blkbk->pending_pages = kzalloc(sizeof(blkbk->pending_pages[0]) *
- mmap_pages, GFP_KERNEL);
-
- if (!blkbk->pending_reqs || !blkbk->pending_grant_handles ||
- !blkbk->pending_pages) {
- rc = -ENOMEM;
- goto out_of_memory;
- }
-
- for (i = 0; i < mmap_pages; i++) {
- blkbk->pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
- blkbk->pending_pages[i] = alloc_page(GFP_KERNEL);
- if (blkbk->pending_pages[i] == NULL) {
- rc = -ENOMEM;
- goto out_of_memory;
- }
- }
rc = xen_blkif_interface_init();
if (rc)
goto failed_init;
- INIT_LIST_HEAD(&blkbk->pending_free);
- spin_lock_init(&blkbk->pending_free_lock);
- init_waitqueue_head(&blkbk->pending_free_wq);
-
- for (i = 0; i < xen_blkif_reqs; i++)
- list_add_tail(&blkbk->pending_reqs[i].free_list,
- &blkbk->pending_free);
-
rc = xen_blkif_xenbus_init();
if (rc)
goto failed_init;
- return 0;
-
- out_of_memory:
- pr_alert(DRV_PFX "%s: out of memory\n", __func__);
failed_init:
- kfree(blkbk->pending_reqs);
- kfree(blkbk->pending_grant_handles);
- if (blkbk->pending_pages) {
- for (i = 0; i < mmap_pages; i++) {
- if (blkbk->pending_pages[i])
- __free_page(blkbk->pending_pages[i]);
- }
- kfree(blkbk->pending_pages);
- }
- kfree(blkbk);
- blkbk = NULL;
return rc;
}
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
index 60103e2517b..8d8807563d9 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -50,6 +50,19 @@
__func__, __LINE__, ##args)
+/*
+ * This is the maximum number of segments that would be allowed in indirect
+ * requests. This value will also be passed to the frontend.
+ */
+#define MAX_INDIRECT_SEGMENTS 256
+
+#define SEGS_PER_INDIRECT_FRAME \
+ (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned))
+#define MAX_INDIRECT_PAGES \
+ ((MAX_INDIRECT_SEGMENTS + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
+#define INDIRECT_PAGES(_segs) \
+ ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
+
/* Not a real protocol. Used to generate ring structs which contain
* the elements common to all protocols only. This way we get a
* compiler-checkable way to use common struct elements, so we can
@@ -83,12 +96,31 @@ struct blkif_x86_32_request_other {
uint64_t id; /* private guest value, echoed in resp */
} __attribute__((__packed__));
+struct blkif_x86_32_request_indirect {
+ uint8_t indirect_op;
+ uint16_t nr_segments;
+ uint64_t id;
+ blkif_sector_t sector_number;
+ blkif_vdev_t handle;
+ uint16_t _pad1;
+ grant_ref_t indirect_grefs[BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST];
+ /*
+ * The maximum number of indirect segments (and pages) that will
+ * be used is determined by MAX_INDIRECT_SEGMENTS, this value
+ * is also exported to the guest (via xenstore
+ * feature-max-indirect-segments entry), so the frontend knows how
+ * many indirect segments the backend supports.
+ */
+ uint64_t _pad2; /* make it 64 byte aligned */
+} __attribute__((__packed__));
+
struct blkif_x86_32_request {
uint8_t operation; /* BLKIF_OP_??? */
union {
struct blkif_x86_32_request_rw rw;
struct blkif_x86_32_request_discard discard;
struct blkif_x86_32_request_other other;
+ struct blkif_x86_32_request_indirect indirect;
} u;
} __attribute__((__packed__));
@@ -127,12 +159,32 @@ struct blkif_x86_64_request_other {
uint64_t id; /* private guest value, echoed in resp */
} __attribute__((__packed__));
+struct blkif_x86_64_request_indirect {
+ uint8_t indirect_op;
+ uint16_t nr_segments;
+ uint32_t _pad1; /* offsetof(blkif_..,u.indirect.id)==8 */
+ uint64_t id;
+ blkif_sector_t sector_number;
+ blkif_vdev_t handle;
+ uint16_t _pad2;
+ grant_ref_t indirect_grefs[BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST];
+ /*
+ * The maximum number of indirect segments (and pages) that will
+ * be used is determined by MAX_INDIRECT_SEGMENTS, this value
+ * is also exported to the guest (via xenstore
+ * feature-max-indirect-segments entry), so the frontend knows how
+ * many indirect segments the backend supports.
+ */
+ uint32_t _pad3; /* make it 64 byte aligned */
+} __attribute__((__packed__));
+
struct blkif_x86_64_request {
uint8_t operation; /* BLKIF_OP_??? */
union {
struct blkif_x86_64_request_rw rw;
struct blkif_x86_64_request_discard discard;
struct blkif_x86_64_request_other other;
+ struct blkif_x86_64_request_indirect indirect;
} u;
} __attribute__((__packed__));
@@ -182,12 +234,26 @@ struct xen_vbd {
struct backend_info;
+/* Number of available flags */
+#define PERSISTENT_GNT_FLAGS_SIZE 2
+/* This persistent grant is currently in use */
+#define PERSISTENT_GNT_ACTIVE 0
+/*
+ * This persistent grant has been used, this flag is set when we remove the
+ * PERSISTENT_GNT_ACTIVE, to know that this grant has been used recently.
+ */
+#define PERSISTENT_GNT_WAS_ACTIVE 1
+
+/* Number of requests that we can fit in a ring */
+#define XEN_BLKIF_REQS 32
struct persistent_gnt {
struct page *page;
grant_ref_t gnt;
grant_handle_t handle;
+ DECLARE_BITMAP(flags, PERSISTENT_GNT_FLAGS_SIZE);
struct rb_node node;
+ struct list_head remove_node;
};
struct xen_blkif {
@@ -219,6 +285,23 @@ struct xen_blkif {
/* tree to store persistent grants */
struct rb_root persistent_gnts;
unsigned int persistent_gnt_c;
+ atomic_t persistent_gnt_in_use;
+ unsigned long next_lru;
+
+ /* used by the kworker that offload work from the persistent purge */
+ struct list_head persistent_purge_list;
+ struct work_struct persistent_purge_work;
+
+ /* buffer of free pages to map grant refs */
+ spinlock_t free_pages_lock;
+ int free_pages_num;
+ struct list_head free_pages;
+
+ /* List of all 'pending_req' available */
+ struct list_head pending_free;
+ /* And its spinlock. */
+ spinlock_t pending_free_lock;
+ wait_queue_head_t pending_free_wq;
/* statistics */
unsigned long st_print;
@@ -231,6 +314,41 @@ struct xen_blkif {
unsigned long long st_wr_sect;
wait_queue_head_t waiting_to_free;
+ /* Thread shutdown wait queue. */
+ wait_queue_head_t shutdown_wq;
+};
+
+struct seg_buf {
+ unsigned long offset;
+ unsigned int nsec;
+};
+
+struct grant_page {
+ struct page *page;
+ struct persistent_gnt *persistent_gnt;
+ grant_handle_t handle;
+ grant_ref_t gref;
+};
+
+/*
+ * Each outstanding request that we've passed to the lower device layers has a
+ * 'pending_req' allocated to it. Each buffer_head that completes decrements
+ * the pendcnt towards zero. When it hits zero, the specified domain has a
+ * response queued for it, with the saved 'id' passed back.
+ */
+struct pending_req {
+ struct xen_blkif *blkif;
+ u64 id;
+ int nr_pages;
+ atomic_t pendcnt;
+ unsigned short operation;
+ int status;
+ struct list_head free_list;
+ struct grant_page *segments[MAX_INDIRECT_SEGMENTS];
+ /* Indirect descriptors */
+ struct grant_page *indirect_pages[MAX_INDIRECT_PAGES];
+ struct seg_buf seg[MAX_INDIRECT_SEGMENTS];
+ struct bio *biolist[MAX_INDIRECT_SEGMENTS];
};
@@ -257,6 +375,7 @@ int xen_blkif_xenbus_init(void);
irqreturn_t xen_blkif_be_int(int irq, void *dev_id);
int xen_blkif_schedule(void *arg);
+int xen_blkif_purge_persistent(void *arg);
int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
struct backend_info *be, int state);
@@ -268,7 +387,7 @@ struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be);
static inline void blkif_get_x86_32_req(struct blkif_request *dst,
struct blkif_x86_32_request *src)
{
- int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+ int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j;
dst->operation = src->operation;
switch (src->operation) {
case BLKIF_OP_READ:
@@ -291,6 +410,18 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
dst->u.discard.sector_number = src->u.discard.sector_number;
dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
break;
+ case BLKIF_OP_INDIRECT:
+ dst->u.indirect.indirect_op = src->u.indirect.indirect_op;
+ dst->u.indirect.nr_segments = src->u.indirect.nr_segments;
+ dst->u.indirect.handle = src->u.indirect.handle;
+ dst->u.indirect.id = src->u.indirect.id;
+ dst->u.indirect.sector_number = src->u.indirect.sector_number;
+ barrier();
+ j = min(MAX_INDIRECT_PAGES, INDIRECT_PAGES(dst->u.indirect.nr_segments));
+ for (i = 0; i < j; i++)
+ dst->u.indirect.indirect_grefs[i] =
+ src->u.indirect.indirect_grefs[i];
+ break;
default:
/*
* Don't know how to translate this op. Only get the
@@ -304,7 +435,7 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
static inline void blkif_get_x86_64_req(struct blkif_request *dst,
struct blkif_x86_64_request *src)
{
- int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+ int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j;
dst->operation = src->operation;
switch (src->operation) {
case BLKIF_OP_READ:
@@ -327,6 +458,18 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
dst->u.discard.sector_number = src->u.discard.sector_number;
dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
break;
+ case BLKIF_OP_INDIRECT:
+ dst->u.indirect.indirect_op = src->u.indirect.indirect_op;
+ dst->u.indirect.nr_segments = src->u.indirect.nr_segments;
+ dst->u.indirect.handle = src->u.indirect.handle;
+ dst->u.indirect.id = src->u.indirect.id;
+ dst->u.indirect.sector_number = src->u.indirect.sector_number;
+ barrier();
+ j = min(MAX_INDIRECT_PAGES, INDIRECT_PAGES(dst->u.indirect.nr_segments));
+ for (i = 0; i < j; i++)
+ dst->u.indirect.indirect_grefs[i] =
+ src->u.indirect.indirect_grefs[i];
+ break;
default:
/*
* Don't know how to translate this op. Only get the
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index 04608a6502d..fe5c3cd10c3 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -98,12 +98,17 @@ static void xen_update_blkif_status(struct xen_blkif *blkif)
err = PTR_ERR(blkif->xenblkd);
blkif->xenblkd = NULL;
xenbus_dev_error(blkif->be->dev, err, "start xenblkd");
+ return;
}
}
static struct xen_blkif *xen_blkif_alloc(domid_t domid)
{
struct xen_blkif *blkif;
+ struct pending_req *req, *n;
+ int i, j;
+
+ BUILD_BUG_ON(MAX_INDIRECT_PAGES > BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST);
blkif = kmem_cache_zalloc(xen_blkif_cachep, GFP_KERNEL);
if (!blkif)
@@ -118,8 +123,57 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
blkif->st_print = jiffies;
init_waitqueue_head(&blkif->waiting_to_free);
blkif->persistent_gnts.rb_node = NULL;
+ spin_lock_init(&blkif->free_pages_lock);
+ INIT_LIST_HEAD(&blkif->free_pages);
+ blkif->free_pages_num = 0;
+ atomic_set(&blkif->persistent_gnt_in_use, 0);
+
+ INIT_LIST_HEAD(&blkif->pending_free);
+
+ for (i = 0; i < XEN_BLKIF_REQS; i++) {
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ goto fail;
+ list_add_tail(&req->free_list,
+ &blkif->pending_free);
+ for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++) {
+ req->segments[j] = kzalloc(sizeof(*req->segments[0]),
+ GFP_KERNEL);
+ if (!req->segments[j])
+ goto fail;
+ }
+ for (j = 0; j < MAX_INDIRECT_PAGES; j++) {
+ req->indirect_pages[j] = kzalloc(sizeof(*req->indirect_pages[0]),
+ GFP_KERNEL);
+ if (!req->indirect_pages[j])
+ goto fail;
+ }
+ }
+ spin_lock_init(&blkif->pending_free_lock);
+ init_waitqueue_head(&blkif->pending_free_wq);
+ init_waitqueue_head(&blkif->shutdown_wq);
return blkif;
+
+fail:
+ list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) {
+ list_del(&req->free_list);
+ for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++) {
+ if (!req->segments[j])
+ break;
+ kfree(req->segments[j]);
+ }
+ for (j = 0; j < MAX_INDIRECT_PAGES; j++) {
+ if (!req->indirect_pages[j])
+ break;
+ kfree(req->indirect_pages[j]);
+ }
+ kfree(req);
+ }
+
+ kmem_cache_free(xen_blkif_cachep, blkif);
+
+ return ERR_PTR(-ENOMEM);
}
static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page,
@@ -178,6 +232,7 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif)
{
if (blkif->xenblkd) {
kthread_stop(blkif->xenblkd);
+ wake_up(&blkif->shutdown_wq);
blkif->xenblkd = NULL;
}
@@ -198,8 +253,28 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif)
static void xen_blkif_free(struct xen_blkif *blkif)
{
+ struct pending_req *req, *n;
+ int i = 0, j;
+
if (!atomic_dec_and_test(&blkif->refcnt))
BUG();
+
+ /* Check that there is no request in use */
+ list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) {
+ list_del(&req->free_list);
+
+ for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++)
+ kfree(req->segments[j]);
+
+ for (j = 0; j < MAX_INDIRECT_PAGES; j++)
+ kfree(req->indirect_pages[j]);
+
+ kfree(req);
+ i++;
+ }
+
+ WARN_ON(i != XEN_BLKIF_REQS);
+
kmem_cache_free(xen_blkif_cachep, blkif);
}
@@ -678,6 +753,11 @@ again:
dev->nodename);
goto abort;
}
+ err = xenbus_printf(xbt, dev->nodename, "feature-max-indirect-segments", "%u",
+ MAX_INDIRECT_SEGMENTS);
+ if (err)
+ dev_warn(&dev->dev, "writing %s/feature-max-indirect-segments (%d)",
+ dev->nodename, err);
err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
(unsigned long long)vbd_sz(&be->blkif->vbd));
@@ -704,6 +784,11 @@ again:
dev->nodename);
goto abort;
}
+ err = xenbus_printf(xbt, dev->nodename, "physical-sector-size", "%u",
+ bdev_physical_block_size(be->blkif->vbd.bdev));
+ if (err)
+ xenbus_dev_error(dev, err, "writing %s/physical-sector-size",
+ dev->nodename);
err = xenbus_transaction_end(xbt, 0);
if (err == -EAGAIN)
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index d89ef86220f..a4660bbee8a 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -74,12 +74,30 @@ struct grant {
struct blk_shadow {
struct blkif_request req;
struct request *request;
- struct grant *grants_used[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ struct grant **grants_used;
+ struct grant **indirect_grants;
+ struct scatterlist *sg;
+};
+
+struct split_bio {
+ struct bio *bio;
+ atomic_t pending;
+ int err;
};
static DEFINE_MUTEX(blkfront_mutex);
static const struct block_device_operations xlvbd_block_fops;
+/*
+ * Maximum number of segments in indirect requests, the actual value used by
+ * the frontend driver is the minimum of this value and the value provided
+ * by the backend driver.
+ */
+
+static unsigned int xen_blkif_max_segments = 32;
+module_param_named(max, xen_blkif_max_segments, int, S_IRUGO);
+MODULE_PARM_DESC(max, "Maximum amount of segments in indirect requests (default is 32)");
+
#define BLK_RING_SIZE __CONST_RING_SIZE(blkif, PAGE_SIZE)
/*
@@ -98,7 +116,6 @@ struct blkfront_info
enum blkif_state connected;
int ring_ref;
struct blkif_front_ring ring;
- struct scatterlist sg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
unsigned int evtchn, irq;
struct request_queue *rq;
struct work_struct work;
@@ -114,6 +131,7 @@ struct blkfront_info
unsigned int discard_granularity;
unsigned int discard_alignment;
unsigned int feature_persistent:1;
+ unsigned int max_indirect_segments;
int is_ready;
};
@@ -142,6 +160,13 @@ static DEFINE_SPINLOCK(minor_lock);
#define DEV_NAME "xvd" /* name in /dev */
+#define SEGS_PER_INDIRECT_FRAME \
+ (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned))
+#define INDIRECT_GREFS(_segs) \
+ ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
+
+static int blkfront_setup_indirect(struct blkfront_info *info);
+
static int get_id_from_freelist(struct blkfront_info *info)
{
unsigned long free = info->shadow_free;
@@ -358,7 +383,8 @@ static int blkif_queue_request(struct request *req)
struct blkif_request *ring_req;
unsigned long id;
unsigned int fsect, lsect;
- int i, ref;
+ int i, ref, n;
+ struct blkif_request_segment_aligned *segments = NULL;
/*
* Used to store if we are able to queue the request by just using
@@ -369,21 +395,27 @@ static int blkif_queue_request(struct request *req)
grant_ref_t gref_head;
struct grant *gnt_list_entry = NULL;
struct scatterlist *sg;
+ int nseg, max_grefs;
if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
return 1;
- /* Check if we have enought grants to allocate a requests */
- if (info->persistent_gnts_c < BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+ max_grefs = info->max_indirect_segments ?
+ info->max_indirect_segments +
+ INDIRECT_GREFS(info->max_indirect_segments) :
+ BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+ /* Check if we have enough grants to allocate a requests */
+ if (info->persistent_gnts_c < max_grefs) {
new_persistent_gnts = 1;
if (gnttab_alloc_grant_references(
- BLKIF_MAX_SEGMENTS_PER_REQUEST - info->persistent_gnts_c,
+ max_grefs - info->persistent_gnts_c,
&gref_head) < 0) {
gnttab_request_free_callback(
&info->callback,
blkif_restart_queue_callback,
info,
- BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ max_grefs);
return 1;
}
} else
@@ -394,42 +426,67 @@ static int blkif_queue_request(struct request *req)
id = get_id_from_freelist(info);
info->shadow[id].request = req;
- ring_req->u.rw.id = id;
- ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
- ring_req->u.rw.handle = info->handle;
-
- ring_req->operation = rq_data_dir(req) ?
- BLKIF_OP_WRITE : BLKIF_OP_READ;
-
- if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
- /*
- * Ideally we can do an unordered flush-to-disk. In case the
- * backend onlysupports barriers, use that. A barrier request
- * a superset of FUA, so we can implement it the same
- * way. (It's also a FLUSH+FUA, since it is
- * guaranteed ordered WRT previous writes.)
- */
- ring_req->operation = info->flush_op;
- }
-
if (unlikely(req->cmd_flags & (REQ_DISCARD | REQ_SECURE))) {
- /* id, sector_number and handle are set above. */
ring_req->operation = BLKIF_OP_DISCARD;
ring_req->u.discard.nr_sectors = blk_rq_sectors(req);
+ ring_req->u.discard.id = id;
+ ring_req->u.discard.sector_number = (blkif_sector_t)blk_rq_pos(req);
if ((req->cmd_flags & REQ_SECURE) && info->feature_secdiscard)
ring_req->u.discard.flag = BLKIF_DISCARD_SECURE;
else
ring_req->u.discard.flag = 0;
} else {
- ring_req->u.rw.nr_segments = blk_rq_map_sg(req->q, req,
- info->sg);
- BUG_ON(ring_req->u.rw.nr_segments >
- BLKIF_MAX_SEGMENTS_PER_REQUEST);
-
- for_each_sg(info->sg, sg, ring_req->u.rw.nr_segments, i) {
+ BUG_ON(info->max_indirect_segments == 0 &&
+ req->nr_phys_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ BUG_ON(info->max_indirect_segments &&
+ req->nr_phys_segments > info->max_indirect_segments);
+ nseg = blk_rq_map_sg(req->q, req, info->shadow[id].sg);
+ ring_req->u.rw.id = id;
+ if (nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+ /*
+ * The indirect operation can only be a BLKIF_OP_READ or
+ * BLKIF_OP_WRITE
+ */
+ BUG_ON(req->cmd_flags & (REQ_FLUSH | REQ_FUA));
+ ring_req->operation = BLKIF_OP_INDIRECT;
+ ring_req->u.indirect.indirect_op = rq_data_dir(req) ?
+ BLKIF_OP_WRITE : BLKIF_OP_READ;
+ ring_req->u.indirect.sector_number = (blkif_sector_t)blk_rq_pos(req);
+ ring_req->u.indirect.handle = info->handle;
+ ring_req->u.indirect.nr_segments = nseg;
+ } else {
+ ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
+ ring_req->u.rw.handle = info->handle;
+ ring_req->operation = rq_data_dir(req) ?
+ BLKIF_OP_WRITE : BLKIF_OP_READ;
+ if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
+ /*
+ * Ideally we can do an unordered flush-to-disk. In case the
+ * backend onlysupports barriers, use that. A barrier request
+ * a superset of FUA, so we can implement it the same
+ * way. (It's also a FLUSH+FUA, since it is
+ * guaranteed ordered WRT previous writes.)
+ */
+ ring_req->operation = info->flush_op;
+ }
+ ring_req->u.rw.nr_segments = nseg;
+ }
+ for_each_sg(info->shadow[id].sg, sg, nseg, i) {
fsect = sg->offset >> 9;
lsect = fsect + (sg->length >> 9) - 1;
+ if ((ring_req->operation == BLKIF_OP_INDIRECT) &&
+ (i % SEGS_PER_INDIRECT_FRAME == 0)) {
+ if (segments)
+ kunmap_atomic(segments);
+
+ n = i / SEGS_PER_INDIRECT_FRAME;
+ gnt_list_entry = get_grant(&gref_head, info);
+ info->shadow[id].indirect_grants[n] = gnt_list_entry;
+ segments = kmap_atomic(pfn_to_page(gnt_list_entry->pfn));
+ ring_req->u.indirect.indirect_grefs[n] = gnt_list_entry->gref;
+ }
+
gnt_list_entry = get_grant(&gref_head, info);
ref = gnt_list_entry->gref;
@@ -441,8 +498,7 @@ static int blkif_queue_request(struct request *req)
BUG_ON(sg->offset + sg->length > PAGE_SIZE);
- shared_data = kmap_atomic(
- pfn_to_page(gnt_list_entry->pfn));
+ shared_data = kmap_atomic(pfn_to_page(gnt_list_entry->pfn));
bvec_data = kmap_atomic(sg_page(sg));
/*
@@ -461,13 +517,23 @@ static int blkif_queue_request(struct request *req)
kunmap_atomic(bvec_data);
kunmap_atomic(shared_data);
}
-
- ring_req->u.rw.seg[i] =
- (struct blkif_request_segment) {
- .gref = ref,
- .first_sect = fsect,
- .last_sect = lsect };
+ if (ring_req->operation != BLKIF_OP_INDIRECT) {
+ ring_req->u.rw.seg[i] =
+ (struct blkif_request_segment) {
+ .gref = ref,
+ .first_sect = fsect,
+ .last_sect = lsect };
+ } else {
+ n = i % SEGS_PER_INDIRECT_FRAME;
+ segments[n] =
+ (struct blkif_request_segment_aligned) {
+ .gref = ref,
+ .first_sect = fsect,
+ .last_sect = lsect };
+ }
}
+ if (segments)
+ kunmap_atomic(segments);
}
info->ring.req_prod_pvt++;
@@ -542,7 +608,9 @@ wait:
flush_requests(info);
}
-static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
+static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size,
+ unsigned int physical_sector_size,
+ unsigned int segments)
{
struct request_queue *rq;
struct blkfront_info *info = gd->private_data;
@@ -564,14 +632,15 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
/* Hard sector size and max sectors impersonate the equiv. hardware. */
blk_queue_logical_block_size(rq, sector_size);
- blk_queue_max_hw_sectors(rq, 512);
+ blk_queue_physical_block_size(rq, physical_sector_size);
+ blk_queue_max_hw_sectors(rq, (segments * PAGE_SIZE) / 512);
/* Each segment in a request is up to an aligned page in size. */
blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
blk_queue_max_segment_size(rq, PAGE_SIZE);
/* Ensure a merged request will fit in a single I/O ring slot. */
- blk_queue_max_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ blk_queue_max_segments(rq, segments);
/* Make sure buffer addresses are sector-aligned. */
blk_queue_dma_alignment(rq, 511);
@@ -588,13 +657,16 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
static void xlvbd_flush(struct blkfront_info *info)
{
blk_queue_flush(info->rq, info->feature_flush);
- printk(KERN_INFO "blkfront: %s: %s: %s %s\n",
+ printk(KERN_INFO "blkfront: %s: %s: %s %s %s %s %s\n",
info->gd->disk_name,
info->flush_op == BLKIF_OP_WRITE_BARRIER ?
"barrier" : (info->flush_op == BLKIF_OP_FLUSH_DISKCACHE ?
"flush diskcache" : "barrier or flush"),
- info->feature_flush ? "enabled" : "disabled",
- info->feature_persistent ? "using persistent grants" : "");
+ info->feature_flush ? "enabled;" : "disabled;",
+ "persistent grants:",
+ info->feature_persistent ? "enabled;" : "disabled;",
+ "indirect descriptors:",
+ info->max_indirect_segments ? "enabled;" : "disabled;");
}
static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset)
@@ -667,7 +739,8 @@ static char *encode_disk_name(char *ptr, unsigned int n)
static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
struct blkfront_info *info,
- u16 vdisk_info, u16 sector_size)
+ u16 vdisk_info, u16 sector_size,
+ unsigned int physical_sector_size)
{
struct gendisk *gd;
int nr_minors = 1;
@@ -734,7 +807,9 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
gd->driverfs_dev = &(info->xbdev->dev);
set_capacity(gd, capacity);
- if (xlvbd_init_blk_queue(gd, sector_size)) {
+ if (xlvbd_init_blk_queue(gd, sector_size, physical_sector_size,
+ info->max_indirect_segments ? :
+ BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
del_gendisk(gd);
goto release;
}
@@ -818,6 +893,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)
{
struct grant *persistent_gnt;
struct grant *n;
+ int i, j, segs;
/* Prevent new requests being issued until we fix things up. */
spin_lock_irq(&info->io_lock);
@@ -843,6 +919,47 @@ static void blkif_free(struct blkfront_info *info, int suspend)
}
BUG_ON(info->persistent_gnts_c != 0);
+ for (i = 0; i < BLK_RING_SIZE; i++) {
+ /*
+ * Clear persistent grants present in requests already
+ * on the shared ring
+ */
+ if (!info->shadow[i].request)
+ goto free_shadow;
+
+ segs = info->shadow[i].req.operation == BLKIF_OP_INDIRECT ?
+ info->shadow[i].req.u.indirect.nr_segments :
+ info->shadow[i].req.u.rw.nr_segments;
+ for (j = 0; j < segs; j++) {
+ persistent_gnt = info->shadow[i].grants_used[j];
+ gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL);
+ __free_page(pfn_to_page(persistent_gnt->pfn));
+ kfree(persistent_gnt);
+ }
+
+ if (info->shadow[i].req.operation != BLKIF_OP_INDIRECT)
+ /*
+ * If this is not an indirect operation don't try to
+ * free indirect segments
+ */
+ goto free_shadow;
+
+ for (j = 0; j < INDIRECT_GREFS(segs); j++) {
+ persistent_gnt = info->shadow[i].indirect_grants[j];
+ gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL);
+ __free_page(pfn_to_page(persistent_gnt->pfn));
+ kfree(persistent_gnt);
+ }
+
+free_shadow:
+ kfree(info->shadow[i].grants_used);
+ info->shadow[i].grants_used = NULL;
+ kfree(info->shadow[i].indirect_grants);
+ info->shadow[i].indirect_grants = NULL;
+ kfree(info->shadow[i].sg);
+ info->shadow[i].sg = NULL;
+ }
+
/* No more gnttab callback work. */
gnttab_cancel_free_callback(&info->callback);
spin_unlock_irq(&info->io_lock);
@@ -867,12 +984,13 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
struct blkif_response *bret)
{
int i = 0;
- struct bio_vec *bvec;
- struct req_iterator iter;
- unsigned long flags;
+ struct scatterlist *sg;
char *bvec_data;
void *shared_data;
- unsigned int offset = 0;
+ int nseg;
+
+ nseg = s->req.operation == BLKIF_OP_INDIRECT ?
+ s->req.u.indirect.nr_segments : s->req.u.rw.nr_segments;
if (bret->operation == BLKIF_OP_READ) {
/*
@@ -881,26 +999,29 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
* than PAGE_SIZE, we have to keep track of the current offset,
* to be sure we are copying the data from the right shared page.
*/
- rq_for_each_segment(bvec, s->request, iter) {
- BUG_ON((bvec->bv_offset + bvec->bv_len) > PAGE_SIZE);
- if (bvec->bv_offset < offset)
- i++;
- BUG_ON(i >= s->req.u.rw.nr_segments);
+ for_each_sg(s->sg, sg, nseg, i) {
+ BUG_ON(sg->offset + sg->length > PAGE_SIZE);
shared_data = kmap_atomic(
pfn_to_page(s->grants_used[i]->pfn));
- bvec_data = bvec_kmap_irq(bvec, &flags);
- memcpy(bvec_data, shared_data + bvec->bv_offset,
- bvec->bv_len);
- bvec_kunmap_irq(bvec_data, &flags);
+ bvec_data = kmap_atomic(sg_page(sg));
+ memcpy(bvec_data + sg->offset,
+ shared_data + sg->offset,
+ sg->length);
+ kunmap_atomic(bvec_data);
kunmap_atomic(shared_data);
- offset = bvec->bv_offset + bvec->bv_len;
}
}
/* Add the persistent grant into the list of free grants */
- for (i = 0; i < s->req.u.rw.nr_segments; i++) {
+ for (i = 0; i < nseg; i++) {
list_add(&s->grants_used[i]->node, &info->persistent_gnts);
info->persistent_gnts_c++;
}
+ if (s->req.operation == BLKIF_OP_INDIRECT) {
+ for (i = 0; i < INDIRECT_GREFS(nseg); i++) {
+ list_add(&s->indirect_grants[i]->node, &info->persistent_gnts);
+ info->persistent_gnts_c++;
+ }
+ }
}
static irqreturn_t blkif_interrupt(int irq, void *dev_id)
@@ -1034,14 +1155,6 @@ static int setup_blkring(struct xenbus_device *dev,
SHARED_RING_INIT(sring);
FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
- sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-
- /* Allocate memory for grants */
- err = fill_grant_buffer(info, BLK_RING_SIZE *
- BLKIF_MAX_SEGMENTS_PER_REQUEST);
- if (err)
- goto fail;
-
err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
if (err < 0) {
free_page((unsigned long)sring);
@@ -1223,13 +1336,84 @@ static int blkfront_probe(struct xenbus_device *dev,
return 0;
}
+/*
+ * This is a clone of md_trim_bio, used to split a bio into smaller ones
+ */
+static void trim_bio(struct bio *bio, int offset, int size)
+{
+ /* 'bio' is a cloned bio which we need to trim to match
+ * the given offset and size.
+ * This requires adjusting bi_sector, bi_size, and bi_io_vec
+ */
+ int i;
+ struct bio_vec *bvec;
+ int sofar = 0;
+
+ size <<= 9;
+ if (offset == 0 && size == bio->bi_size)
+ return;
+
+ bio->bi_sector += offset;
+ bio->bi_size = size;
+ offset <<= 9;
+ clear_bit(BIO_SEG_VALID, &bio->bi_flags);
+
+ while (bio->bi_idx < bio->bi_vcnt &&
+ bio->bi_io_vec[bio->bi_idx].bv_len <= offset) {
+ /* remove this whole bio_vec */
+ offset -= bio->bi_io_vec[bio->bi_idx].bv_len;
+ bio->bi_idx++;
+ }
+ if (bio->bi_idx < bio->bi_vcnt) {
+ bio->bi_io_vec[bio->bi_idx].bv_offset += offset;
+ bio->bi_io_vec[bio->bi_idx].bv_len -= offset;
+ }
+ /* avoid any complications with bi_idx being non-zero*/
+ if (bio->bi_idx) {
+ memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx,
+ (bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec));
+ bio->bi_vcnt -= bio->bi_idx;
+ bio->bi_idx = 0;
+ }
+ /* Make sure vcnt and last bv are not too big */
+ bio_for_each_segment(bvec, bio, i) {
+ if (sofar + bvec->bv_len > size)
+ bvec->bv_len = size - sofar;
+ if (bvec->bv_len == 0) {
+ bio->bi_vcnt = i;
+ break;
+ }
+ sofar += bvec->bv_len;
+ }
+}
+
+static void split_bio_end(struct bio *bio, int error)
+{
+ struct split_bio *split_bio = bio->bi_private;
+
+ if (error)
+ split_bio->err = error;
+
+ if (atomic_dec_and_test(&split_bio->pending)) {
+ split_bio->bio->bi_phys_segments = 0;
+ bio_endio(split_bio->bio, split_bio->err);
+ kfree(split_bio);
+ }
+ bio_put(bio);
+}
static int blkif_recover(struct blkfront_info *info)
{
int i;
- struct blkif_request *req;
+ struct request *req, *n;
struct blk_shadow *copy;
- int j;
+ int rc;
+ struct bio *bio, *cloned_bio;
+ struct bio_list bio_list, merge_bio;
+ unsigned int segs, offset;
+ int pending, size;
+ struct split_bio *split_bio;
+ struct list_head requests;
/* Stage 1: Make a safe copy of the shadow state. */
copy = kmemdup(info->shadow, sizeof(info->shadow),
@@ -1244,36 +1428,64 @@ static int blkif_recover(struct blkfront_info *info)
info->shadow_free = info->ring.req_prod_pvt;
info->shadow[BLK_RING_SIZE-1].req.u.rw.id = 0x0fffffff;
- /* Stage 3: Find pending requests and requeue them. */
+ rc = blkfront_setup_indirect(info);
+ if (rc) {
+ kfree(copy);
+ return rc;
+ }
+
+ segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST;
+ blk_queue_max_segments(info->rq, segs);
+ bio_list_init(&bio_list);
+ INIT_LIST_HEAD(&requests);
for (i = 0; i < BLK_RING_SIZE; i++) {
/* Not in use? */
if (!copy[i].request)
continue;
- /* Grab a request slot and copy shadow state into it. */
- req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
- *req = copy[i].req;
-
- /* We get a new request id, and must reset the shadow state. */
- req->u.rw.id = get_id_from_freelist(info);
- memcpy(&info->shadow[req->u.rw.id], &copy[i], sizeof(copy[i]));
-
- if (req->operation != BLKIF_OP_DISCARD) {
- /* Rewrite any grant references invalidated by susp/resume. */
- for (j = 0; j < req->u.rw.nr_segments; j++)
- gnttab_grant_foreign_access_ref(
- req->u.rw.seg[j].gref,
- info->xbdev->otherend_id,
- pfn_to_mfn(copy[i].grants_used[j]->pfn),
- 0);
+ /*
+ * Get the bios in the request so we can re-queue them.
+ */
+ if (copy[i].request->cmd_flags &
+ (REQ_FLUSH | REQ_FUA | REQ_DISCARD | REQ_SECURE)) {
+ /*
+ * Flush operations don't contain bios, so
+ * we need to requeue the whole request
+ */
+ list_add(&copy[i].request->queuelist, &requests);
+ continue;
}
- info->shadow[req->u.rw.id].req = *req;
-
- info->ring.req_prod_pvt++;
+ merge_bio.head = copy[i].request->bio;
+ merge_bio.tail = copy[i].request->biotail;
+ bio_list_merge(&bio_list, &merge_bio);
+ copy[i].request->bio = NULL;
+ blk_put_request(copy[i].request);
}
kfree(copy);
+ /*
+ * Empty the queue, this is important because we might have
+ * requests in the queue with more segments than what we
+ * can handle now.
+ */
+ spin_lock_irq(&info->io_lock);
+ while ((req = blk_fetch_request(info->rq)) != NULL) {
+ if (req->cmd_flags &
+ (REQ_FLUSH | REQ_FUA | REQ_DISCARD | REQ_SECURE)) {
+ list_add(&req->queuelist, &requests);
+ continue;
+ }
+ merge_bio.head = req->bio;
+ merge_bio.tail = req->biotail;
+ bio_list_merge(&bio_list, &merge_bio);
+ req->bio = NULL;
+ if (req->cmd_flags & (REQ_FLUSH | REQ_FUA))
+ pr_alert("diskcache flush request found!\n");
+ __blk_put_request(info->rq, req);
+ }
+ spin_unlock_irq(&info->io_lock);
+
xenbus_switch_state(info->xbdev, XenbusStateConnected);
spin_lock_irq(&info->io_lock);
@@ -1281,14 +1493,50 @@ static int blkif_recover(struct blkfront_info *info)
/* Now safe for us to use the shared ring */
info->connected = BLKIF_STATE_CONNECTED;
- /* Send off requeued requests */
- flush_requests(info);
-
/* Kick any other new requests queued since we resumed */
kick_pending_request_queues(info);
+ list_for_each_entry_safe(req, n, &requests, queuelist) {
+ /* Requeue pending requests (flush or discard) */
+ list_del_init(&req->queuelist);
+ BUG_ON(req->nr_phys_segments > segs);
+ blk_requeue_request(info->rq, req);
+ }
spin_unlock_irq(&info->io_lock);
+ while ((bio = bio_list_pop(&bio_list)) != NULL) {
+ /* Traverse the list of pending bios and re-queue them */
+ if (bio_segments(bio) > segs) {
+ /*
+ * This bio has more segments than what we can
+ * handle, we have to split it.
+ */
+ pending = (bio_segments(bio) + segs - 1) / segs;
+ split_bio = kzalloc(sizeof(*split_bio), GFP_NOIO);
+ BUG_ON(split_bio == NULL);
+ atomic_set(&split_bio->pending, pending);
+ split_bio->bio = bio;
+ for (i = 0; i < pending; i++) {
+ offset = (i * segs * PAGE_SIZE) >> 9;
+ size = min((unsigned int)(segs * PAGE_SIZE) >> 9,
+ (unsigned int)(bio->bi_size >> 9) - offset);
+ cloned_bio = bio_clone(bio, GFP_NOIO);
+ BUG_ON(cloned_bio == NULL);
+ trim_bio(cloned_bio, offset, size);
+ cloned_bio->bi_private = split_bio;
+ cloned_bio->bi_end_io = split_bio_end;
+ submit_bio(cloned_bio->bi_rw, cloned_bio);
+ }
+ /*
+ * Now we have to wait for all those smaller bios to
+ * end, so we can also end the "parent" bio.
+ */
+ continue;
+ }
+ /* We don't need to split this bio */
+ submit_bio(bio->bi_rw, bio);
+ }
+
return 0;
}
@@ -1308,8 +1556,12 @@ static int blkfront_resume(struct xenbus_device *dev)
blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
err = talk_to_blkback(dev, info);
- if (info->connected == BLKIF_STATE_SUSPENDED && !err)
- err = blkif_recover(info);
+
+ /*
+ * We have to wait for the backend to switch to
+ * connected state, since we want to read which
+ * features it supports.
+ */
return err;
}
@@ -1387,6 +1639,60 @@ static void blkfront_setup_discard(struct blkfront_info *info)
kfree(type);
}
+static int blkfront_setup_indirect(struct blkfront_info *info)
+{
+ unsigned int indirect_segments, segs;
+ int err, i;
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-max-indirect-segments", "%u", &indirect_segments,
+ NULL);
+ if (err) {
+ info->max_indirect_segments = 0;
+ segs = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+ } else {
+ info->max_indirect_segments = min(indirect_segments,
+ xen_blkif_max_segments);
+ segs = info->max_indirect_segments;
+ }
+
+ err = fill_grant_buffer(info, (segs + INDIRECT_GREFS(segs)) * BLK_RING_SIZE);
+ if (err)
+ goto out_of_memory;
+
+ for (i = 0; i < BLK_RING_SIZE; i++) {
+ info->shadow[i].grants_used = kzalloc(
+ sizeof(info->shadow[i].grants_used[0]) * segs,
+ GFP_NOIO);
+ info->shadow[i].sg = kzalloc(sizeof(info->shadow[i].sg[0]) * segs, GFP_NOIO);
+ if (info->max_indirect_segments)
+ info->shadow[i].indirect_grants = kzalloc(
+ sizeof(info->shadow[i].indirect_grants[0]) *
+ INDIRECT_GREFS(segs),
+ GFP_NOIO);
+ if ((info->shadow[i].grants_used == NULL) ||
+ (info->shadow[i].sg == NULL) ||
+ (info->max_indirect_segments &&
+ (info->shadow[i].indirect_grants == NULL)))
+ goto out_of_memory;
+ sg_init_table(info->shadow[i].sg, segs);
+ }
+
+
+ return 0;
+
+out_of_memory:
+ for (i = 0; i < BLK_RING_SIZE; i++) {
+ kfree(info->shadow[i].grants_used);
+ info->shadow[i].grants_used = NULL;
+ kfree(info->shadow[i].sg);
+ info->shadow[i].sg = NULL;
+ kfree(info->shadow[i].indirect_grants);
+ info->shadow[i].indirect_grants = NULL;
+ }
+ return -ENOMEM;
+}
+
/*
* Invoked when the backend is finally 'ready' (and has told produced
* the details about the physical device - #sectors, size, etc).
@@ -1395,6 +1701,7 @@ static void blkfront_connect(struct blkfront_info *info)
{
unsigned long long sectors;
unsigned long sector_size;
+ unsigned int physical_sector_size;
unsigned int binfo;
int err;
int barrier, flush, discard, persistent;
@@ -1414,8 +1721,15 @@ static void blkfront_connect(struct blkfront_info *info)
set_capacity(info->gd, sectors);
revalidate_disk(info->gd);
- /* fall through */
+ return;
case BLKIF_STATE_SUSPENDED:
+ /*
+ * If we are recovering from suspension, we need to wait
+ * for the backend to announce it's features before
+ * reconnecting, at least we need to know if the backend
+ * supports indirect descriptors, and how many.
+ */
+ blkif_recover(info);
return;
default:
@@ -1437,6 +1751,16 @@ static void blkfront_connect(struct blkfront_info *info)
return;
}
+ /*
+ * physcial-sector-size is a newer field, so old backends may not
+ * provide this. Assume physical sector size to be the same as
+ * sector_size in that case.
+ */
+ err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+ "physical-sector-size", "%u", &physical_sector_size);
+ if (err != 1)
+ physical_sector_size = sector_size;
+
info->feature_flush = 0;
info->flush_op = 0;
@@ -1483,7 +1807,15 @@ static void blkfront_connect(struct blkfront_info *info)
else
info->feature_persistent = persistent;
- err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
+ err = blkfront_setup_indirect(info);
+ if (err) {
+ xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s",
+ info->xbdev->otherend);
+ return;
+ }
+
+ err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size,
+ physical_sector_size);
if (err) {
xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
info->xbdev->otherend);
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 11f467c00d0..a12b923bbac 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -91,6 +91,10 @@ static struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x0489, 0xe04e) },
{ USB_DEVICE(0x0489, 0xe056) },
{ USB_DEVICE(0x0489, 0xe04d) },
+ { USB_DEVICE(0x04c5, 0x1330) },
+ { USB_DEVICE(0x13d3, 0x3402) },
+ { USB_DEVICE(0x0cf3, 0x3121) },
+ { USB_DEVICE(0x0cf3, 0xe003) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
@@ -128,6 +132,10 @@ static struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
@@ -193,24 +201,44 @@ error:
static int ath3k_get_state(struct usb_device *udev, unsigned char *state)
{
- int pipe = 0;
+ int ret, pipe = 0;
+ char *buf;
+
+ buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
pipe = usb_rcvctrlpipe(udev, 0);
- return usb_control_msg(udev, pipe, ATH3K_GETSTATE,
- USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
- state, 0x01, USB_CTRL_SET_TIMEOUT);
+ ret = usb_control_msg(udev, pipe, ATH3K_GETSTATE,
+ USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+ buf, sizeof(*buf), USB_CTRL_SET_TIMEOUT);
+
+ *state = *buf;
+ kfree(buf);
+
+ return ret;
}
static int ath3k_get_version(struct usb_device *udev,
struct ath3k_version *version)
{
- int pipe = 0;
+ int ret, pipe = 0;
+ struct ath3k_version *buf;
+ const int size = sizeof(*buf);
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
pipe = usb_rcvctrlpipe(udev, 0);
- return usb_control_msg(udev, pipe, ATH3K_GETVERSION,
- USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version,
- sizeof(struct ath3k_version),
- USB_CTRL_SET_TIMEOUT);
+ ret = usb_control_msg(udev, pipe, ATH3K_GETVERSION,
+ USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+ buf, size, USB_CTRL_SET_TIMEOUT);
+
+ memcpy(version, buf, size);
+ kfree(buf);
+
+ return ret;
}
static int ath3k_load_fwfile(struct usb_device *udev,
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index de4cf4daa2f..8e16f0af635 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -154,6 +154,10 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -1095,7 +1099,7 @@ static int btusb_setup_intel_patching(struct hci_dev *hdev,
if (IS_ERR(skb)) {
BT_ERR("%s sending Intel patch command (0x%4.4x) failed (%ld)",
hdev->name, cmd->opcode, PTR_ERR(skb));
- return -PTR_ERR(skb);
+ return PTR_ERR(skb);
}
/* It ensures that the returned event matches the event data read from
@@ -1147,7 +1151,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
if (IS_ERR(skb)) {
BT_ERR("%s sending initial HCI reset command failed (%ld)",
hdev->name, PTR_ERR(skb));
- return -PTR_ERR(skb);
+ return PTR_ERR(skb);
}
kfree_skb(skb);
@@ -1161,7 +1165,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
if (IS_ERR(skb)) {
BT_ERR("%s reading Intel fw version command failed (%ld)",
hdev->name, PTR_ERR(skb));
- return -PTR_ERR(skb);
+ return PTR_ERR(skb);
}
if (skb->len != sizeof(*ver)) {
@@ -1219,7 +1223,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
BT_ERR("%s entering Intel manufacturer mode failed (%ld)",
hdev->name, PTR_ERR(skb));
release_firmware(fw);
- return -PTR_ERR(skb);
+ return PTR_ERR(skb);
}
if (skb->data[0]) {
@@ -1276,7 +1280,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
if (IS_ERR(skb)) {
BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
hdev->name, PTR_ERR(skb));
- return -PTR_ERR(skb);
+ return PTR_ERR(skb);
}
kfree_skb(skb);
@@ -1292,7 +1296,7 @@ exit_mfg_disable:
if (IS_ERR(skb)) {
BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
hdev->name, PTR_ERR(skb));
- return -PTR_ERR(skb);
+ return PTR_ERR(skb);
}
kfree_skb(skb);
@@ -1310,7 +1314,7 @@ exit_mfg_deactivate:
if (IS_ERR(skb)) {
BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
hdev->name, PTR_ERR(skb));
- return -PTR_ERR(skb);
+ return PTR_ERR(skb);
}
kfree_skb(skb);
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 733288967d4..20092669977 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -122,17 +122,8 @@ EXPORT_SYMBOL_GPL(cci_ace_get_port);
static void __init cci_ace_init_ports(void)
{
- int port, ac, cpu;
- u64 hwid;
- const u32 *cell;
- struct device_node *cpun, *cpus;
-
- cpus = of_find_node_by_path("/cpus");
- if (WARN(!cpus, "Missing cpus node, bailing out\n"))
- return;
-
- if (WARN_ON(of_property_read_u32(cpus, "#address-cells", &ac)))
- ac = of_n_addr_cells(cpus);
+ int port, cpu;
+ struct device_node *cpun;
/*
* Port index look-up speeds up the function disabling ports by CPU,
@@ -141,18 +132,13 @@ static void __init cci_ace_init_ports(void)
* The stashed index array is initialized for all possible CPUs
* at probe time.
*/
- for_each_child_of_node(cpus, cpun) {
- if (of_node_cmp(cpun->type, "cpu"))
- continue;
- cell = of_get_property(cpun, "reg", NULL);
- if (WARN(!cell, "%s: missing reg property\n", cpun->full_name))
- continue;
-
- hwid = of_read_number(cell, ac);
- cpu = get_logical_index(hwid & MPIDR_HWID_BITMASK);
+ for_each_possible_cpu(cpu) {
+ /* too early to use cpu->of_node */
+ cpun = of_get_cpu_node(cpu, NULL);
- if (cpu < 0 || !cpu_possible(cpu))
+ if (WARN(!cpun, "Missing cpu device node\n"))
continue;
+
port = __cci_ace_get_port(cpun, ACE_PORT);
if (port < 0)
continue;
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index bf5d2477cb7..15f2e7025b7 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -129,7 +129,8 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
off_t j, io_pg_start;
int io_pg_count;
- if (type != 0 || mem->type != 0) {
+ if (type != mem->type ||
+ agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
return -EINVAL;
}
@@ -175,7 +176,8 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
struct _parisc_agp_info *info = &parisc_agp_info;
int i, io_pg_start, io_pg_count;
- if (type != 0 || mem->type != 0) {
+ if (type != mem->type ||
+ agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
return -EINVAL;
}
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 97467053a01..0671e45daa5 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -95,6 +95,7 @@ bsr_size_show(struct device *dev, struct device_attribute *attr, char *buf)
struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", bsr_dev->bsr_bytes);
}
+static DEVICE_ATTR_RO(bsr_size);
static ssize_t
bsr_stride_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -102,20 +103,23 @@ bsr_stride_show(struct device *dev, struct device_attribute *attr, char *buf)
struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", bsr_dev->bsr_stride);
}
+static DEVICE_ATTR_RO(bsr_stride);
static ssize_t
-bsr_len_show(struct device *dev, struct device_attribute *attr, char *buf)
+bsr_length_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
return sprintf(buf, "%llu\n", bsr_dev->bsr_len);
}
+static DEVICE_ATTR_RO(bsr_length);
-static struct device_attribute bsr_dev_attrs[] = {
- __ATTR(bsr_size, S_IRUGO, bsr_size_show, NULL),
- __ATTR(bsr_stride, S_IRUGO, bsr_stride_show, NULL),
- __ATTR(bsr_length, S_IRUGO, bsr_len_show, NULL),
- __ATTR_NULL
+static struct attribute *bsr_dev_attrs[] = {
+ &dev_attr_bsr_size.attr,
+ &dev_attr_bsr_stride.attr,
+ &dev_attr_bsr_length.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(bsr_dev);
static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
{
@@ -308,7 +312,7 @@ static int __init bsr_init(void)
ret = PTR_ERR(bsr_class);
goto out_err_1;
}
- bsr_class->dev_attrs = bsr_dev_attrs;
+ bsr_class->dev_groups = bsr_dev_groups;
ret = alloc_chrdev_region(&bsr_dev, 0, BSR_MAX_DEVS, "bsr");
bsr_major = MAJOR(bsr_dev);
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 5c5cc00ebb0..d39cca659a3 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1182,14 +1182,14 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
}
count++;
- if (gis & (BIT1 + BIT0)) {
+ if (gis & (BIT1 | BIT0)) {
isr = read_reg16(info, CHB + ISR);
if (isr & IRQ_DCD)
dcd_change(info, tty);
if (isr & IRQ_CTS)
cts_change(info, tty);
}
- if (gis & (BIT3 + BIT2))
+ if (gis & (BIT3 | BIT2))
{
isr = read_reg16(info, CHA + ISR);
if (isr & IRQ_TIMER) {
@@ -1210,7 +1210,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
if (isr & IRQ_RXTIME) {
issue_command(info, CHA, CMD_RXFIFO_READ);
}
- if (isr & (IRQ_RXEOM + IRQ_RXFIFO)) {
+ if (isr & (IRQ_RXEOM | IRQ_RXFIFO)) {
if (info->params.mode == MGSL_MODE_HDLC)
rx_ready_hdlc(info, isr & IRQ_RXEOM);
else
@@ -3031,11 +3031,11 @@ static void loopback_enable(MGSLPC_INFO *info)
unsigned char val;
/* CCR1:02..00 CM[2..0] Clock Mode = 111 (clock mode 7) */
- val = read_reg(info, CHA + CCR1) | (BIT2 + BIT1 + BIT0);
+ val = read_reg(info, CHA + CCR1) | (BIT2 | BIT1 | BIT0);
write_reg(info, CHA + CCR1, val);
/* CCR2:04 SSEL Clock source select, 1=submode b */
- val = read_reg(info, CHA + CCR2) | (BIT4 + BIT5);
+ val = read_reg(info, CHA + CCR2) | (BIT4 | BIT5);
write_reg(info, CHA + CCR2, val);
/* set LinkSpeed if available, otherwise default to 2Mbps */
@@ -3125,10 +3125,10 @@ static void hdlc_mode(MGSLPC_INFO *info)
val |= BIT4;
break; // FM0
case HDLC_ENCODING_BIPHASE_MARK:
- val |= BIT4 + BIT2;
+ val |= BIT4 | BIT2;
break; // FM1
case HDLC_ENCODING_BIPHASE_LEVEL:
- val |= BIT4 + BIT3;
+ val |= BIT4 | BIT3;
break; // Manchester
}
write_reg(info, CHA + CCR0, val);
@@ -3185,7 +3185,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
*/
val = 0x00;
if (info->params.crc_type == HDLC_CRC_NONE)
- val |= BIT2 + BIT1;
+ val |= BIT2 | BIT1;
if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE)
val |= BIT5;
switch (info->params.preamble_length)
@@ -3197,7 +3197,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
val |= BIT6;
break;
case HDLC_PREAMBLE_LENGTH_64BITS:
- val |= BIT7 + BIT6;
+ val |= BIT7 | BIT6;
break;
}
write_reg(info, CHA + CCR3, val);
@@ -3264,8 +3264,8 @@ static void hdlc_mode(MGSLPC_INFO *info)
clear_reg_bits(info, CHA + PVR, BIT3);
irq_enable(info, CHA,
- IRQ_RXEOM + IRQ_RXFIFO + IRQ_ALLSENT +
- IRQ_UNDERRUN + IRQ_TXFIFO);
+ IRQ_RXEOM | IRQ_RXFIFO | IRQ_ALLSENT |
+ IRQ_UNDERRUN | IRQ_TXFIFO);
issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
wait_command_complete(info, CHA);
read_reg16(info, CHA + ISR); /* clear pending IRQs */
@@ -3582,8 +3582,8 @@ static void async_mode(MGSLPC_INFO *info)
} else
clear_reg_bits(info, CHA + PVR, BIT3);
irq_enable(info, CHA,
- IRQ_RXEOM + IRQ_RXFIFO + IRQ_BREAK_ON + IRQ_RXTIME +
- IRQ_ALLSENT + IRQ_TXFIFO);
+ IRQ_RXEOM | IRQ_RXFIFO | IRQ_BREAK_ON | IRQ_RXTIME |
+ IRQ_ALLSENT | IRQ_TXFIFO);
issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
wait_command_complete(info, CHA);
read_reg16(info, CHA + ISR); /* clear pending IRQs */
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index bf2349dbbf7..7cc1fe2241f 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -876,11 +876,6 @@ found:
if (useinput)
sonypi_report_input_event(event);
-#ifdef CONFIG_ACPI
- if (sonypi_acpi_device)
- acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event);
-#endif
-
kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event,
sizeof(event), &sonypi_device.fifo_lock);
kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c
index 7faeb1cde97..ae82933883b 100644
--- a/drivers/char/tile-srom.c
+++ b/drivers/char/tile-srom.c
@@ -279,33 +279,37 @@ loff_t srom_llseek(struct file *file, loff_t offset, int origin)
return fixed_size_llseek(file, offset, origin, srom->total_size);
}
-static ssize_t total_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t total_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct srom_dev *srom = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", srom->total_size);
}
+static DEVICE_ATTR_RO(total_size);
-static ssize_t sector_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t sector_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct srom_dev *srom = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", srom->sector_size);
}
+static DEVICE_ATTR_RO(sector_size);
-static ssize_t page_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t page_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct srom_dev *srom = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", srom->page_size);
}
+static DEVICE_ATTR_RO(page_size);
-static struct device_attribute srom_dev_attrs[] = {
- __ATTR(total_size, S_IRUGO, total_show, NULL),
- __ATTR(sector_size, S_IRUGO, sector_show, NULL),
- __ATTR(page_size, S_IRUGO, page_show, NULL),
- __ATTR_NULL
+static struct attribute *srom_dev_attrs[] = {
+ &dev_attr_total_size.attr,
+ &dev_attr_sector_size.attr,
+ &dev_attr_page_size.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(srom_dev);
static char *srom_devnode(struct device *dev, umode_t *mode)
{
@@ -418,7 +422,7 @@ static int srom_init(void)
result = PTR_ERR(srom_class);
goto fail_cdev;
}
- srom_class->dev_attrs = srom_dev_attrs;
+ srom_class->dev_groups = srom_dev_groups;
srom_class->devnode = srom_devnode;
/* Do per-partition initialization */
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 1b456fe9b87..fc45567ad3a 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -272,9 +272,12 @@ static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
unsigned long flags;
spin_lock_irqsave(&portdev->ports_lock, flags);
- list_for_each_entry(port, &portdev->ports, list)
- if (port->cdev->dev == dev)
+ list_for_each_entry(port, &portdev->ports, list) {
+ if (port->cdev->dev == dev) {
+ kref_get(&port->kref);
goto out;
+ }
+ }
port = NULL;
out:
spin_unlock_irqrestore(&portdev->ports_lock, flags);
@@ -746,6 +749,10 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
port = filp->private_data;
+ /* Port is hot-unplugged. */
+ if (!port->guest_connected)
+ return -ENODEV;
+
if (!port_has_data(port)) {
/*
* If nothing's connected on the host just return 0 in
@@ -762,7 +769,7 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
if (ret < 0)
return ret;
}
- /* Port got hot-unplugged. */
+ /* Port got hot-unplugged while we were waiting above. */
if (!port->guest_connected)
return -ENODEV;
/*
@@ -932,13 +939,25 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
if (is_rproc_serial(port->out_vq->vdev))
return -EINVAL;
+ /*
+ * pipe->nrbufs == 0 means there are no data to transfer,
+ * so this returns just 0 for no data.
+ */
+ pipe_lock(pipe);
+ if (!pipe->nrbufs) {
+ ret = 0;
+ goto error_out;
+ }
+
ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK);
if (ret < 0)
- return ret;
+ goto error_out;
buf = alloc_buf(port->out_vq, 0, pipe->nrbufs);
- if (!buf)
- return -ENOMEM;
+ if (!buf) {
+ ret = -ENOMEM;
+ goto error_out;
+ }
sgl.n = 0;
sgl.len = 0;
@@ -946,12 +965,17 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
sgl.sg = buf->sg;
sg_init_table(sgl.sg, sgl.size);
ret = __splice_from_pipe(pipe, &sd, pipe_to_sg);
+ pipe_unlock(pipe);
if (likely(ret > 0))
ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true);
if (unlikely(ret <= 0))
free_buf(buf, true);
return ret;
+
+error_out:
+ pipe_unlock(pipe);
+ return ret;
}
static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
@@ -1019,14 +1043,14 @@ static int port_fops_open(struct inode *inode, struct file *filp)
struct port *port;
int ret;
+ /* We get the port with a kref here */
port = find_port_by_devt(cdev->dev);
+ if (!port) {
+ /* Port was unplugged before we could proceed */
+ return -ENXIO;
+ }
filp->private_data = port;
- /* Prevent against a port getting hot-unplugged at the same time */
- spin_lock_irq(&port->portdev->ports_lock);
- kref_get(&port->kref);
- spin_unlock_irq(&port->portdev->ports_lock);
-
/*
* Don't allow opening of console port devices -- that's done
* via /dev/hvc
@@ -1498,14 +1522,6 @@ static void remove_port(struct kref *kref)
port = container_of(kref, struct port, kref);
- sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
- device_destroy(pdrvdata.class, port->dev->devt);
- cdev_del(port->cdev);
-
- kfree(port->name);
-
- debugfs_remove(port->debugfs_file);
-
kfree(port);
}
@@ -1539,12 +1555,14 @@ static void unplug_port(struct port *port)
spin_unlock_irq(&port->portdev->ports_lock);
if (port->guest_connected) {
+ /* Let the app know the port is going down. */
+ send_sigio_to_port(port);
+
+ /* Do this after sigio is actually sent */
port->guest_connected = false;
port->host_connected = false;
- wake_up_interruptible(&port->waitqueue);
- /* Let the app know the port is going down. */
- send_sigio_to_port(port);
+ wake_up_interruptible(&port->waitqueue);
}
if (is_console_port(port)) {
@@ -1563,6 +1581,14 @@ static void unplug_port(struct port *port)
*/
port->portdev = NULL;
+ sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+ device_destroy(pdrvdata.class, port->dev->devt);
+ cdev_del(port->cdev);
+
+ kfree(port->name);
+
+ debugfs_remove(port->debugfs_file);
+
/*
* Locks around here are not necessary - a port can't be
* opened after we removed the port struct from ports_list
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index 1bdb882c845..4e5739773c3 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -581,11 +581,15 @@ struct samsung_div_clock exynos4x12_div_clks[] __initdata = {
DIV(none, "div_spi1_isp", "mout_spi1_isp", E4X12_DIV_ISP, 16, 4),
DIV(none, "div_spi1_isp_pre", "div_spi1_isp", E4X12_DIV_ISP, 20, 8),
DIV(none, "div_uart_isp", "mout_uart_isp", E4X12_DIV_ISP, 28, 4),
- DIV(div_isp0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3),
- DIV(div_isp1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3),
+ DIV_F(div_isp0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3,
+ CLK_GET_RATE_NOCACHE, 0),
+ DIV_F(div_isp1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3,
+ CLK_GET_RATE_NOCACHE, 0),
DIV(none, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3),
- DIV(div_mcuisp0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1, 4, 3),
- DIV(div_mcuisp1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, 8, 3),
+ DIV_F(div_mcuisp0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1,
+ 4, 3, CLK_GET_RATE_NOCACHE, 0),
+ DIV_F(div_mcuisp1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
+ 8, 3, CLK_GET_RATE_NOCACHE, 0),
DIV(sclk_fimg2d, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4),
};
@@ -863,57 +867,57 @@ struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
GATE_DA(i2s0, "samsung-i2s.0", "i2s0", "aclk100",
E4X12_GATE_IP_MAUDIO, 3, 0, 0, "iis"),
GATE(fimc_isp, "isp", "aclk200", E4X12_GATE_ISP0, 0,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(fimc_drc, "drc", "aclk200", E4X12_GATE_ISP0, 1,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(fimc_fd, "fd", "aclk200", E4X12_GATE_ISP0, 2,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(fimc_lite0, "lite0", "aclk200", E4X12_GATE_ISP0, 3,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(fimc_lite1, "lite1", "aclk200", E4X12_GATE_ISP0, 4,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(mcuisp, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(gicisp, "gicisp", "aclk200", E4X12_GATE_ISP0, 7,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(smmu_isp, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(smmu_drc, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(smmu_fd, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(smmu_lite0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(smmu_lite1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(ppmuispmx, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(ppmuispx, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(mcuctl_isp, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(mpwm_isp, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(i2c0_isp, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(i2c1_isp, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(mtcadc_isp, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(pwm_isp, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(wdt_isp, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(uart_isp, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(asyncaxim, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(smmu_ispcx, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(spi0_isp, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(spi1_isp, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13,
- CLK_IGNORE_UNUSED, 0),
+ CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
GATE(g2d, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0),
};
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index 5c205b60a82..089d3e30e22 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -71,6 +71,7 @@ static DEFINE_SPINLOCK(armpll_lock);
static DEFINE_SPINLOCK(ddrpll_lock);
static DEFINE_SPINLOCK(iopll_lock);
static DEFINE_SPINLOCK(armclk_lock);
+static DEFINE_SPINLOCK(swdtclk_lock);
static DEFINE_SPINLOCK(ddrclk_lock);
static DEFINE_SPINLOCK(dciclk_lock);
static DEFINE_SPINLOCK(gem0clk_lock);
@@ -293,7 +294,7 @@ static void __init zynq_clk_setup(struct device_node *np)
}
clks[swdt] = clk_register_mux(NULL, clk_output_name[swdt],
swdt_ext_clk_mux_parents, 2, CLK_SET_RATE_PARENT,
- SLCR_SWDT_CLK_SEL, 0, 1, 0, &gem0clk_lock);
+ SLCR_SWDT_CLK_SEL, 0, 1, 0, &swdtclk_lock);
/* DDR clocks */
clk = clk_register_divider(NULL, "ddr2x_div", "ddrpll", 0,
@@ -364,8 +365,9 @@ static void __init zynq_clk_setup(struct device_node *np)
CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 20, 6,
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
&gem0clk_lock);
- clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2, 0,
- SLCR_GEM0_CLK_CTRL, 6, 1, 0, &gem0clk_lock);
+ clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2,
+ CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 6, 1, 0,
+ &gem0clk_lock);
clks[gem0] = clk_register_gate(NULL, clk_output_name[gem0],
"gem0_emio_mux", CLK_SET_RATE_PARENT,
SLCR_GEM0_CLK_CTRL, 0, 0, &gem0clk_lock);
@@ -386,8 +388,9 @@ static void __init zynq_clk_setup(struct device_node *np)
CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 20, 6,
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
&gem1clk_lock);
- clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2, 0,
- SLCR_GEM1_CLK_CTRL, 6, 1, 0, &gem1clk_lock);
+ clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2,
+ CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 6, 1, 0,
+ &gem1clk_lock);
clks[gem1] = clk_register_gate(NULL, clk_output_name[gem1],
"gem1_emio_mux", CLK_SET_RATE_PARENT,
SLCR_GEM1_CLK_CTRL, 0, 0, &gem1clk_lock);
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index de4d5d93c3f..0fa204b244b 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -17,37 +17,47 @@ config ARM_DT_BL_CPUFREQ
big.LITTLE platform. This gets frequency tables from DT.
config ARM_EXYNOS_CPUFREQ
- bool "SAMSUNG EXYNOS SoCs"
- depends on ARCH_EXYNOS
+ bool
select CPU_FREQ_TABLE
- default y
- help
- This adds the CPUFreq driver common part for Samsung
- EXYNOS SoCs.
-
- If in doubt, say N.
config ARM_EXYNOS4210_CPUFREQ
- def_bool CPU_EXYNOS4210
+ bool "SAMSUNG EXYNOS4210"
+ depends on CPU_EXYNOS4210
+ default y
+ select ARM_EXYNOS_CPUFREQ
help
This adds the CPUFreq driver for Samsung EXYNOS4210
SoC (S5PV310 or S5PC210).
+ If in doubt, say N.
+
config ARM_EXYNOS4X12_CPUFREQ
- def_bool (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+ bool "SAMSUNG EXYNOS4x12"
+ depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+ default y
+ select ARM_EXYNOS_CPUFREQ
help
This adds the CPUFreq driver for Samsung EXYNOS4X12
SoC (EXYNOS4212 or EXYNOS4412).
+ If in doubt, say N.
+
config ARM_EXYNOS5250_CPUFREQ
- def_bool SOC_EXYNOS5250
+ bool "SAMSUNG EXYNOS5250"
+ depends on SOC_EXYNOS5250
+ default y
+ select ARM_EXYNOS_CPUFREQ
help
This adds the CPUFreq driver for Samsung EXYNOS5250
SoC.
+ If in doubt, say N.
+
config ARM_EXYNOS5440_CPUFREQ
- def_bool SOC_EXYNOS5440
+ bool "SAMSUNG EXYNOS5440"
+ depends on SOC_EXYNOS5440
depends on HAVE_CLK && PM_OPP && OF
+ default y
select CPU_FREQ_TABLE
help
This adds the CPUFreq driver for Samsung EXYNOS5440
@@ -55,6 +65,8 @@ config ARM_EXYNOS5440_CPUFREQ
different than previous exynos controllers so not using
the common exynos framework.
+ If in doubt, say N.
+
config ARM_HIGHBANK_CPUFREQ
tristate "Calxeda Highbank-based"
depends on ARCH_HIGHBANK
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index d345b5a7aa7..ad5866c2ada 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -23,7 +23,7 @@ obj-$(CONFIG_GENERIC_CPUFREQ_CPU0) += cpufreq-cpu0.o
# powernow-k8 can load then. ACPI is preferred to all other hardware-specific drivers.
# speedstep-* is preferred over p4-clockmod.
-obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o
+obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o
obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o
obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 39264020b88..a1260b4549d 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -45,7 +45,6 @@
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/cpufeature.h>
-#include "mperf.h"
MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
MODULE_DESCRIPTION("ACPI Processor P-States Driver");
@@ -198,7 +197,7 @@ static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
return sprintf(buf, "%u\n", boost_enabled);
}
-static struct freq_attr cpb = __ATTR(cpb, 0644, show_cpb, store_cpb);
+cpufreq_freq_attr_rw(cpb);
#endif
static int check_est_cpu(unsigned int cpuid)
@@ -710,7 +709,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
return blacklisted;
#endif
- data = kzalloc(sizeof(struct acpi_cpufreq_data), GFP_KERNEL);
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -800,7 +799,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
goto err_unreg;
}
- data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) *
+ data->freq_table = kmalloc(sizeof(*data->freq_table) *
(perf->state_count+1), GFP_KERNEL);
if (!data->freq_table) {
result = -ENOMEM;
@@ -861,10 +860,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
/* notify BIOS that we exist */
acpi_processor_notify_smm(THIS_MODULE);
- /* Check for APERF/MPERF support in hardware */
- if (boot_cpu_has(X86_FEATURE_APERFMPERF))
- acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf;
-
pr_debug("CPU%u - ACPI performance management activated.\n", cpu);
for (i = 0; i < perf->state_count; i++)
pr_debug(" %cP%d: %d MHz, %d mW, %d uS\n",
@@ -941,7 +936,6 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.exit = acpi_cpufreq_cpu_exit,
.resume = acpi_cpufreq_resume,
.name = "acpi-cpufreq",
- .owner = THIS_MODULE,
.attr = acpi_cpufreq_attr,
};
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
index fd9e3ea6a48..480c0bd0468 100644
--- a/drivers/cpufreq/arm_big_little_dt.c
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -19,12 +19,11 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/module.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/opp.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -34,27 +33,13 @@
/* get cpu node with valid operating-points */
static struct device_node *get_cpu_node_with_valid_op(int cpu)
{
- struct device_node *np = NULL, *parent;
- int count = 0;
+ struct device_node *np = of_cpu_device_node_get(cpu);
- parent = of_find_node_by_path("/cpus");
- if (!parent) {
- pr_err("failed to find OF /cpus\n");
- return NULL;
+ if (!of_get_property(np, "operating-points", NULL)) {
+ of_node_put(np);
+ np = NULL;
}
- for_each_child_of_node(parent, np) {
- if (count++ != cpu)
- continue;
- if (!of_get_property(np, "operating-points", NULL)) {
- of_node_put(np);
- np = NULL;
- }
-
- break;
- }
-
- of_node_put(parent);
return np;
}
@@ -63,11 +48,12 @@ static int dt_init_opp_table(struct device *cpu_dev)
struct device_node *np;
int ret;
- np = get_cpu_node_with_valid_op(cpu_dev->id);
- if (!np)
- return -ENODATA;
+ np = of_node_get(cpu_dev->of_node);
+ if (!np) {
+ pr_err("failed to find cpu%d node\n", cpu_dev->id);
+ return -ENOENT;
+ }
- cpu_dev->of_node = np;
ret = of_init_opp_table(cpu_dev);
of_node_put(np);
@@ -79,9 +65,11 @@ static int dt_get_transition_latency(struct device *cpu_dev)
struct device_node *np;
u32 transition_latency = CPUFREQ_ETERNAL;
- np = get_cpu_node_with_valid_op(cpu_dev->id);
- if (!np)
+ np = of_node_get(cpu_dev->of_node);
+ if (!np) {
+ pr_info("Failed to find cpu node. Use CPUFREQ_ETERNAL transition latency\n");
return CPUFREQ_ETERNAL;
+ }
of_property_read_u32(np, "clock-latency", &transition_latency);
of_node_put(np);
diff --git a/drivers/cpufreq/at32ap-cpufreq.c b/drivers/cpufreq/at32ap-cpufreq.c
index 654488723cb..e0c38d93899 100644
--- a/drivers/cpufreq/at32ap-cpufreq.c
+++ b/drivers/cpufreq/at32ap-cpufreq.c
@@ -108,7 +108,6 @@ static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy)
static struct cpufreq_driver at32_driver = {
.name = "at32ap",
- .owner = THIS_MODULE,
.init = at32_cpufreq_driver_init,
.verify = at32_verify_speed,
.target = at32_set_target,
diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c
index 9cdbbd278a8..ef05978a723 100644
--- a/drivers/cpufreq/blackfin-cpufreq.c
+++ b/drivers/cpufreq/blackfin-cpufreq.c
@@ -225,7 +225,6 @@ static struct cpufreq_driver bfin_driver = {
.get = bfin_getfreq_khz,
.init = __bfin_cpu_init,
.name = "bfin cpufreq",
- .owner = THIS_MODULE,
.attr = bfin_freq_attr,
};
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index ad1fde27766..cbfffa91ebd 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -69,7 +69,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
- if (cpu_reg) {
+ if (!IS_ERR(cpu_reg)) {
rcu_read_lock();
opp = opp_find_freq_ceil(cpu_dev, &freq_Hz);
if (IS_ERR(opp)) {
@@ -90,7 +90,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
freqs.new / 1000, volt ? volt / 1000 : -1);
/* scaling up? scale voltage before frequency */
- if (cpu_reg && freqs.new > freqs.old) {
+ if (!IS_ERR(cpu_reg) && freqs.new > freqs.old) {
ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
if (ret) {
pr_err("failed to scale voltage up: %d\n", ret);
@@ -102,14 +102,14 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
ret = clk_set_rate(cpu_clk, freq_exact);
if (ret) {
pr_err("failed to set clock rate: %d\n", ret);
- if (cpu_reg)
+ if (!IS_ERR(cpu_reg))
regulator_set_voltage_tol(cpu_reg, volt_old, tol);
freqs.new = freqs.old;
goto post_notify;
}
/* scaling down? scale voltage after frequency */
- if (cpu_reg && freqs.new < freqs.old) {
+ if (!IS_ERR(cpu_reg) && freqs.new < freqs.old) {
ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
if (ret) {
pr_err("failed to scale voltage down: %d\n", ret);
@@ -174,30 +174,18 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
static int cpu0_cpufreq_probe(struct platform_device *pdev)
{
- struct device_node *np, *parent;
+ struct device_node *np;
int ret;
- parent = of_find_node_by_path("/cpus");
- if (!parent) {
- pr_err("failed to find OF /cpus\n");
- return -ENOENT;
- }
-
- for_each_child_of_node(parent, np) {
- if (of_get_property(np, "operating-points", NULL))
- break;
- }
+ cpu_dev = &pdev->dev;
+ np = of_node_get(cpu_dev->of_node);
if (!np) {
pr_err("failed to find cpu0 node\n");
- ret = -ENOENT;
- goto out_put_parent;
+ return -ENOENT;
}
- cpu_dev = &pdev->dev;
- cpu_dev->of_node = np;
-
- cpu_reg = devm_regulator_get(cpu_dev, "cpu0");
+ cpu_reg = devm_regulator_get_optional(cpu_dev, "cpu0");
if (IS_ERR(cpu_reg)) {
/*
* If cpu0 regulator supply node is present, but regulator is
@@ -210,7 +198,6 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
}
pr_warn("failed to get cpu0 regulator: %ld\n",
PTR_ERR(cpu_reg));
- cpu_reg = NULL;
}
cpu_clk = devm_clk_get(cpu_dev, NULL);
@@ -269,15 +256,12 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
}
of_node_put(np);
- of_node_put(parent);
return 0;
out_free_table:
opp_free_cpufreq_table(cpu_dev, &freq_table);
out_put_node:
of_node_put(np);
-out_put_parent:
- of_node_put(parent);
return ret;
}
diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c
index af1542d4144..b83d45f6857 100644
--- a/drivers/cpufreq/cpufreq-nforce2.c
+++ b/drivers/cpufreq/cpufreq-nforce2.c
@@ -379,7 +379,6 @@ static struct cpufreq_driver nforce2_driver = {
.get = nforce2_get,
.init = nforce2_cpu_init,
.exit = nforce2_cpu_exit,
- .owner = THIS_MODULE,
};
#ifdef MODULE
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index a4ad7339588..5c75e3147a6 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -17,24 +17,17 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <asm/cputime.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/notifier.h>
+#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/tick.h>
#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/cpu.h>
-#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/slab.h>
#include <linux/syscore_ops.h>
-
+#include <linux/tick.h>
#include <trace/events/power.h>
/**
@@ -44,8 +37,10 @@
*/
static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
+static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback);
static DEFINE_RWLOCK(cpufreq_driver_lock);
static DEFINE_MUTEX(cpufreq_governor_lock);
+static LIST_HEAD(cpufreq_policy_list);
#ifdef CONFIG_HOTPLUG_CPU
/* This one keeps track of the previously set governor of a removed CPU */
@@ -69,15 +64,14 @@ static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
* - Lock should not be held across
* __cpufreq_governor(data, CPUFREQ_GOV_STOP);
*/
-static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
#define lock_policy_rwsem(mode, cpu) \
static int lock_policy_rwsem_##mode(int cpu) \
{ \
- int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \
- BUG_ON(policy_cpu == -1); \
- down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \
+ struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); \
+ BUG_ON(!policy); \
+ down_##mode(&per_cpu(cpu_policy_rwsem, policy->cpu)); \
\
return 0; \
}
@@ -88,14 +82,20 @@ lock_policy_rwsem(write, cpu);
#define unlock_policy_rwsem(mode, cpu) \
static void unlock_policy_rwsem_##mode(int cpu) \
{ \
- int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \
- BUG_ON(policy_cpu == -1); \
- up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \
+ struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); \
+ BUG_ON(!policy); \
+ up_##mode(&per_cpu(cpu_policy_rwsem, policy->cpu)); \
}
unlock_policy_rwsem(read, cpu);
unlock_policy_rwsem(write, cpu);
+/*
+ * rwsem to guarantee that cpufreq driver module doesn't unload during critical
+ * sections
+ */
+static DECLARE_RWSEM(cpufreq_rwsem);
+
/* internal prototypes */
static int __cpufreq_governor(struct cpufreq_policy *policy,
unsigned int event);
@@ -183,78 +183,46 @@ u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
}
EXPORT_SYMBOL_GPL(get_cpu_idle_time);
-static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
+struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
{
- struct cpufreq_policy *data;
+ struct cpufreq_policy *policy = NULL;
unsigned long flags;
- if (cpu >= nr_cpu_ids)
- goto err_out;
+ if (cpufreq_disabled() || (cpu >= nr_cpu_ids))
+ return NULL;
+
+ if (!down_read_trylock(&cpufreq_rwsem))
+ return NULL;
/* get the cpufreq driver */
read_lock_irqsave(&cpufreq_driver_lock, flags);
- if (!cpufreq_driver)
- goto err_out_unlock;
-
- if (!try_module_get(cpufreq_driver->owner))
- goto err_out_unlock;
-
- /* get the CPU */
- data = per_cpu(cpufreq_cpu_data, cpu);
-
- if (!data)
- goto err_out_put_module;
-
- if (!sysfs && !kobject_get(&data->kobj))
- goto err_out_put_module;
+ if (cpufreq_driver) {
+ /* get the CPU */
+ policy = per_cpu(cpufreq_cpu_data, cpu);
+ if (policy)
+ kobject_get(&policy->kobj);
+ }
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
- return data;
-err_out_put_module:
- module_put(cpufreq_driver->owner);
-err_out_unlock:
- read_unlock_irqrestore(&cpufreq_driver_lock, flags);
-err_out:
- return NULL;
-}
-
-struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
-{
- if (cpufreq_disabled())
- return NULL;
+ if (!policy)
+ up_read(&cpufreq_rwsem);
- return __cpufreq_cpu_get(cpu, false);
+ return policy;
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
-static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu)
-{
- return __cpufreq_cpu_get(cpu, true);
-}
-
-static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs)
-{
- if (!sysfs)
- kobject_put(&data->kobj);
- module_put(cpufreq_driver->owner);
-}
-
-void cpufreq_cpu_put(struct cpufreq_policy *data)
+void cpufreq_cpu_put(struct cpufreq_policy *policy)
{
if (cpufreq_disabled())
return;
- __cpufreq_cpu_put(data, false);
+ kobject_put(&policy->kobj);
+ up_read(&cpufreq_rwsem);
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
-static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data)
-{
- __cpufreq_cpu_put(data, true);
-}
-
/*********************************************************************
* EXTERNALLY AFFECTING FREQUENCY CHANGES *
*********************************************************************/
@@ -459,8 +427,8 @@ show_one(scaling_min_freq, min);
show_one(scaling_max_freq, max);
show_one(scaling_cur_freq, cur);
-static int __cpufreq_set_policy(struct cpufreq_policy *data,
- struct cpufreq_policy *policy);
+static int __cpufreq_set_policy(struct cpufreq_policy *policy,
+ struct cpufreq_policy *new_policy);
/**
* cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access
@@ -699,12 +667,12 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
struct cpufreq_policy *policy = to_policy(kobj);
struct freq_attr *fattr = to_attr(attr);
ssize_t ret = -EINVAL;
- policy = cpufreq_cpu_get_sysfs(policy->cpu);
- if (!policy)
- goto no_policy;
+
+ if (!down_read_trylock(&cpufreq_rwsem))
+ goto exit;
if (lock_policy_rwsem_read(policy->cpu) < 0)
- goto fail;
+ goto up_read;
if (fattr->show)
ret = fattr->show(policy, buf);
@@ -712,9 +680,10 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
ret = -EIO;
unlock_policy_rwsem_read(policy->cpu);
-fail:
- cpufreq_cpu_put_sysfs(policy);
-no_policy:
+
+up_read:
+ up_read(&cpufreq_rwsem);
+exit:
return ret;
}
@@ -724,12 +693,12 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
struct cpufreq_policy *policy = to_policy(kobj);
struct freq_attr *fattr = to_attr(attr);
ssize_t ret = -EINVAL;
- policy = cpufreq_cpu_get_sysfs(policy->cpu);
- if (!policy)
- goto no_policy;
+
+ if (!down_read_trylock(&cpufreq_rwsem))
+ goto exit;
if (lock_policy_rwsem_write(policy->cpu) < 0)
- goto fail;
+ goto up_read;
if (fattr->store)
ret = fattr->store(policy, buf, count);
@@ -737,9 +706,10 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
ret = -EIO;
unlock_policy_rwsem_write(policy->cpu);
-fail:
- cpufreq_cpu_put_sysfs(policy);
-no_policy:
+
+up_read:
+ up_read(&cpufreq_rwsem);
+exit:
return ret;
}
@@ -805,41 +775,32 @@ void cpufreq_sysfs_remove_file(const struct attribute *attr)
EXPORT_SYMBOL(cpufreq_sysfs_remove_file);
/* symlink affected CPUs */
-static int cpufreq_add_dev_symlink(unsigned int cpu,
- struct cpufreq_policy *policy)
+static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy)
{
unsigned int j;
int ret = 0;
for_each_cpu(j, policy->cpus) {
- struct cpufreq_policy *managed_policy;
struct device *cpu_dev;
- if (j == cpu)
+ if (j == policy->cpu)
continue;
- pr_debug("CPU %u already managed, adding link\n", j);
- managed_policy = cpufreq_cpu_get(cpu);
+ pr_debug("Adding link for CPU: %u\n", j);
cpu_dev = get_cpu_device(j);
ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
"cpufreq");
- if (ret) {
- cpufreq_cpu_put(managed_policy);
- return ret;
- }
+ if (ret)
+ break;
}
return ret;
}
-static int cpufreq_add_dev_interface(unsigned int cpu,
- struct cpufreq_policy *policy,
+static int cpufreq_add_dev_interface(struct cpufreq_policy *policy,
struct device *dev)
{
- struct cpufreq_policy new_policy;
struct freq_attr **drv_attr;
- unsigned long flags;
int ret = 0;
- unsigned int j;
/* prepare interface data */
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
@@ -871,18 +832,24 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
goto err_out_kobj_put;
}
- write_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_cpu(j, policy->cpus) {
- per_cpu(cpufreq_cpu_data, j) = policy;
- per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
- }
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
- ret = cpufreq_add_dev_symlink(cpu, policy);
+ ret = cpufreq_add_dev_symlink(policy);
if (ret)
goto err_out_kobj_put;
- memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
+ return ret;
+
+err_out_kobj_put:
+ kobject_put(&policy->kobj);
+ wait_for_completion(&policy->kobj_unregister);
+ return ret;
+}
+
+static void cpufreq_init_policy(struct cpufreq_policy *policy)
+{
+ struct cpufreq_policy new_policy;
+ int ret = 0;
+
+ memcpy(&new_policy, policy, sizeof(*policy));
/* assure that the starting sequence is run in __cpufreq_set_policy */
policy->governor = NULL;
@@ -896,72 +863,106 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
}
- return ret;
-
-err_out_kobj_put:
- kobject_put(&policy->kobj);
- wait_for_completion(&policy->kobj_unregister);
- return ret;
}
#ifdef CONFIG_HOTPLUG_CPU
-static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
- struct device *dev)
+static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
+ unsigned int cpu, struct device *dev,
+ bool frozen)
{
- struct cpufreq_policy *policy;
int ret = 0, has_target = !!cpufreq_driver->target;
unsigned long flags;
- policy = cpufreq_cpu_get(sibling);
- WARN_ON(!policy);
-
- if (has_target)
- __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ if (has_target) {
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ if (ret) {
+ pr_err("%s: Failed to stop governor\n", __func__);
+ return ret;
+ }
+ }
- lock_policy_rwsem_write(sibling);
+ lock_policy_rwsem_write(policy->cpu);
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpumask_set_cpu(cpu, policy->cpus);
- per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu;
per_cpu(cpufreq_cpu_data, cpu) = policy;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- unlock_policy_rwsem_write(sibling);
+ unlock_policy_rwsem_write(policy->cpu);
if (has_target) {
- __cpufreq_governor(policy, CPUFREQ_GOV_START);
- __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
+ (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
+ pr_err("%s: Failed to start governor\n", __func__);
+ return ret;
+ }
}
- ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
- if (ret) {
- cpufreq_cpu_put(policy);
- return ret;
- }
+ /* Don't touch sysfs links during light-weight init */
+ if (!frozen)
+ ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
- return 0;
+ return ret;
}
#endif
-/**
- * cpufreq_add_dev - add a CPU device
- *
- * Adds the cpufreq interface for a CPU device.
- *
- * The Oracle says: try running cpufreq registration/unregistration concurrently
- * with with cpu hotplugging and all hell will break loose. Tried to clean this
- * mess up, but more thorough testing is needed. - Mathieu
- */
-static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
+static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
+{
+ struct cpufreq_policy *policy;
+ unsigned long flags;
+
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+
+ policy = per_cpu(cpufreq_cpu_data_fallback, cpu);
+
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ return policy;
+}
+
+static struct cpufreq_policy *cpufreq_policy_alloc(void)
+{
+ struct cpufreq_policy *policy;
+
+ policy = kzalloc(sizeof(*policy), GFP_KERNEL);
+ if (!policy)
+ return NULL;
+
+ if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
+ goto err_free_policy;
+
+ if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
+ goto err_free_cpumask;
+
+ INIT_LIST_HEAD(&policy->policy_list);
+ return policy;
+
+err_free_cpumask:
+ free_cpumask_var(policy->cpus);
+err_free_policy:
+ kfree(policy);
+
+ return NULL;
+}
+
+static void cpufreq_policy_free(struct cpufreq_policy *policy)
+{
+ free_cpumask_var(policy->related_cpus);
+ free_cpumask_var(policy->cpus);
+ kfree(policy);
+}
+
+static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
+ bool frozen)
{
unsigned int j, cpu = dev->id;
int ret = -ENOMEM;
struct cpufreq_policy *policy;
unsigned long flags;
#ifdef CONFIG_HOTPLUG_CPU
+ struct cpufreq_policy *tpolicy;
struct cpufreq_governor *gov;
- int sibling;
#endif
if (cpu_is_offline(cpu))
@@ -977,43 +978,38 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
cpufreq_cpu_put(policy);
return 0;
}
+#endif
+
+ if (!down_read_trylock(&cpufreq_rwsem))
+ return 0;
#ifdef CONFIG_HOTPLUG_CPU
/* Check if this cpu was hot-unplugged earlier and has siblings */
read_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_online_cpu(sibling) {
- struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
- if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
+ list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) {
+ if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) {
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
- return cpufreq_add_policy_cpu(cpu, sibling, dev);
+ ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev, frozen);
+ up_read(&cpufreq_rwsem);
+ return ret;
}
}
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
-#endif
- if (!try_module_get(cpufreq_driver->owner)) {
- ret = -EINVAL;
- goto module_out;
- }
+ if (frozen)
+ /* Restore the saved policy when doing light-weight init */
+ policy = cpufreq_policy_restore(cpu);
+ else
+ policy = cpufreq_policy_alloc();
- policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!policy)
goto nomem_out;
- if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
- goto err_free_policy;
-
- if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
- goto err_free_cpumask;
-
policy->cpu = cpu;
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
cpumask_copy(policy->cpus, cpumask_of(cpu));
- /* Initially set CPU itself as the policy_cpu */
- per_cpu(cpufreq_policy_cpu, cpu) = cpu;
-
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
@@ -1050,12 +1046,26 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
}
#endif
- ret = cpufreq_add_dev_interface(cpu, policy, dev);
- if (ret)
- goto err_out_unregister;
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ for_each_cpu(j, policy->cpus)
+ per_cpu(cpufreq_cpu_data, j) = policy;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ if (!frozen) {
+ ret = cpufreq_add_dev_interface(policy, dev);
+ if (ret)
+ goto err_out_unregister;
+ }
+
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ list_add(&policy->policy_list, &cpufreq_policy_list);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ cpufreq_init_policy(policy);
kobject_uevent(&policy->kobj, KOBJ_ADD);
- module_put(cpufreq_driver->owner);
+ up_read(&cpufreq_rwsem);
+
pr_debug("initialization complete\n");
return 0;
@@ -1066,32 +1076,33 @@ err_out_unregister:
per_cpu(cpufreq_cpu_data, j) = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- kobject_put(&policy->kobj);
- wait_for_completion(&policy->kobj_unregister);
-
err_set_policy_cpu:
- per_cpu(cpufreq_policy_cpu, cpu) = -1;
- free_cpumask_var(policy->related_cpus);
-err_free_cpumask:
- free_cpumask_var(policy->cpus);
-err_free_policy:
- kfree(policy);
+ cpufreq_policy_free(policy);
nomem_out:
- module_put(cpufreq_driver->owner);
-module_out:
+ up_read(&cpufreq_rwsem);
+
return ret;
}
-static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
+/**
+ * cpufreq_add_dev - add a CPU device
+ *
+ * Adds the cpufreq interface for a CPU device.
+ *
+ * The Oracle says: try running cpufreq registration/unregistration concurrently
+ * with with cpu hotplugging and all hell will break loose. Tried to clean this
+ * mess up, but more thorough testing is needed. - Mathieu
+ */
+static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
- int j;
+ return __cpufreq_add_dev(dev, sif, false);
+}
+static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
+{
policy->last_cpu = policy->cpu;
policy->cpu = cpu;
- for_each_cpu(j, policy->cpus)
- per_cpu(cpufreq_policy_cpu, j) = cpu;
-
#ifdef CONFIG_CPU_FREQ_TABLE
cpufreq_frequency_table_update_policy_cpu(policy);
#endif
@@ -1099,6 +1110,37 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
CPUFREQ_UPDATE_POLICY_CPU, policy);
}
+static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
+ unsigned int old_cpu, bool frozen)
+{
+ struct device *cpu_dev;
+ int ret;
+
+ /* first sibling now owns the new sysfs dir */
+ cpu_dev = get_cpu_device(cpumask_first(policy->cpus));
+
+ /* Don't touch sysfs files during light-weight tear-down */
+ if (frozen)
+ return cpu_dev->id;
+
+ sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
+ ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
+ if (ret) {
+ pr_err("%s: Failed to move kobj: %d", __func__, ret);
+
+ WARN_ON(lock_policy_rwsem_write(old_cpu));
+ cpumask_set_cpu(old_cpu, policy->cpus);
+ unlock_policy_rwsem_write(old_cpu);
+
+ ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
+ "cpufreq");
+
+ return -EINVAL;
+ }
+
+ return cpu_dev->id;
+}
+
/**
* __cpufreq_remove_dev - remove a CPU device
*
@@ -1107,110 +1149,126 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
* This routine frees the rwsem before returning.
*/
static int __cpufreq_remove_dev(struct device *dev,
- struct subsys_interface *sif)
+ struct subsys_interface *sif, bool frozen)
{
- unsigned int cpu = dev->id, ret, cpus;
+ unsigned int cpu = dev->id, cpus;
+ int new_cpu, ret;
unsigned long flags;
- struct cpufreq_policy *data;
+ struct cpufreq_policy *policy;
struct kobject *kobj;
struct completion *cmp;
- struct device *cpu_dev;
pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
write_lock_irqsave(&cpufreq_driver_lock, flags);
- data = per_cpu(cpufreq_cpu_data, cpu);
- per_cpu(cpufreq_cpu_data, cpu) = NULL;
+ policy = per_cpu(cpufreq_cpu_data, cpu);
+
+ /* Save the policy somewhere when doing a light-weight tear-down */
+ if (frozen)
+ per_cpu(cpufreq_cpu_data_fallback, cpu) = policy;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- if (!data) {
+ if (!policy) {
pr_debug("%s: No cpu_data found\n", __func__);
return -EINVAL;
}
- if (cpufreq_driver->target)
- __cpufreq_governor(data, CPUFREQ_GOV_STOP);
+ if (cpufreq_driver->target) {
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ if (ret) {
+ pr_err("%s: Failed to stop governor\n", __func__);
+ return ret;
+ }
+ }
#ifdef CONFIG_HOTPLUG_CPU
if (!cpufreq_driver->setpolicy)
strncpy(per_cpu(cpufreq_cpu_governor, cpu),
- data->governor->name, CPUFREQ_NAME_LEN);
+ policy->governor->name, CPUFREQ_NAME_LEN);
#endif
WARN_ON(lock_policy_rwsem_write(cpu));
- cpus = cpumask_weight(data->cpus);
+ cpus = cpumask_weight(policy->cpus);
if (cpus > 1)
- cpumask_clear_cpu(cpu, data->cpus);
+ cpumask_clear_cpu(cpu, policy->cpus);
unlock_policy_rwsem_write(cpu);
- if (cpu != data->cpu) {
+ if (cpu != policy->cpu && !frozen) {
sysfs_remove_link(&dev->kobj, "cpufreq");
} else if (cpus > 1) {
- /* first sibling now owns the new sysfs dir */
- cpu_dev = get_cpu_device(cpumask_first(data->cpus));
- sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
- ret = kobject_move(&data->kobj, &cpu_dev->kobj);
- if (ret) {
- pr_err("%s: Failed to move kobj: %d", __func__, ret);
+ new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen);
+ if (new_cpu >= 0) {
WARN_ON(lock_policy_rwsem_write(cpu));
- cpumask_set_cpu(cpu, data->cpus);
-
- write_lock_irqsave(&cpufreq_driver_lock, flags);
- per_cpu(cpufreq_cpu_data, cpu) = data;
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
+ update_policy_cpu(policy, new_cpu);
unlock_policy_rwsem_write(cpu);
- ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj,
- "cpufreq");
- return -EINVAL;
+ if (!frozen) {
+ pr_debug("%s: policy Kobject moved to cpu: %d "
+ "from: %d\n",__func__, new_cpu, cpu);
+ }
}
-
- WARN_ON(lock_policy_rwsem_write(cpu));
- update_policy_cpu(data, cpu_dev->id);
- unlock_policy_rwsem_write(cpu);
- pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
- __func__, cpu_dev->id, cpu);
}
- if ((cpus == 1) && (cpufreq_driver->target))
- __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
-
- pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
- cpufreq_cpu_put(data);
-
/* If cpu is last user of policy, free policy */
if (cpus == 1) {
- lock_policy_rwsem_read(cpu);
- kobj = &data->kobj;
- cmp = &data->kobj_unregister;
- unlock_policy_rwsem_read(cpu);
- kobject_put(kobj);
-
- /* we need to make sure that the underlying kobj is actually
- * not referenced anymore by anybody before we proceed with
- * unloading.
- */
- pr_debug("waiting for dropping of refcount\n");
- wait_for_completion(cmp);
- pr_debug("wait complete\n");
+ if (cpufreq_driver->target) {
+ ret = __cpufreq_governor(policy,
+ CPUFREQ_GOV_POLICY_EXIT);
+ if (ret) {
+ pr_err("%s: Failed to exit governor\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ if (!frozen) {
+ lock_policy_rwsem_read(cpu);
+ kobj = &policy->kobj;
+ cmp = &policy->kobj_unregister;
+ unlock_policy_rwsem_read(cpu);
+ kobject_put(kobj);
+
+ /*
+ * We need to make sure that the underlying kobj is
+ * actually not referenced anymore by anybody before we
+ * proceed with unloading.
+ */
+ pr_debug("waiting for dropping of refcount\n");
+ wait_for_completion(cmp);
+ pr_debug("wait complete\n");
+ }
+ /*
+ * Perform the ->exit() even during light-weight tear-down,
+ * since this is a core component, and is essential for the
+ * subsequent light-weight ->init() to succeed.
+ */
if (cpufreq_driver->exit)
- cpufreq_driver->exit(data);
+ cpufreq_driver->exit(policy);
- free_cpumask_var(data->related_cpus);
- free_cpumask_var(data->cpus);
- kfree(data);
- } else if (cpufreq_driver->target) {
- __cpufreq_governor(data, CPUFREQ_GOV_START);
- __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+ /* Remove policy from list of active policies */
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ list_del(&policy->policy_list);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ if (!frozen)
+ cpufreq_policy_free(policy);
+ } else {
+ if (cpufreq_driver->target) {
+ if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
+ (ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
+ pr_err("%s: Failed to start governor\n",
+ __func__);
+ return ret;
+ }
+ }
}
- per_cpu(cpufreq_policy_cpu, cpu) = -1;
+ per_cpu(cpufreq_cpu_data, cpu) = NULL;
return 0;
}
@@ -1222,7 +1280,7 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
if (cpu_is_offline(cpu))
return 0;
- retval = __cpufreq_remove_dev(dev, sif);
+ retval = __cpufreq_remove_dev(dev, sif, false);
return retval;
}
@@ -1343,10 +1401,9 @@ static unsigned int __cpufreq_get(unsigned int cpu)
unsigned int cpufreq_get(unsigned int cpu)
{
unsigned int ret_freq = 0;
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- if (!policy)
- goto out;
+ if (!down_read_trylock(&cpufreq_rwsem))
+ return 0;
if (unlikely(lock_policy_rwsem_read(cpu)))
goto out_policy;
@@ -1356,8 +1413,8 @@ unsigned int cpufreq_get(unsigned int cpu)
unlock_policy_rwsem_read(cpu);
out_policy:
- cpufreq_cpu_put(policy);
-out:
+ up_read(&cpufreq_rwsem);
+
return ret_freq;
}
EXPORT_SYMBOL(cpufreq_get);
@@ -1380,23 +1437,23 @@ static int cpufreq_bp_suspend(void)
int ret = 0;
int cpu = smp_processor_id();
- struct cpufreq_policy *cpu_policy;
+ struct cpufreq_policy *policy;
pr_debug("suspending cpu %u\n", cpu);
/* If there's no policy for the boot CPU, we have nothing to do. */
- cpu_policy = cpufreq_cpu_get(cpu);
- if (!cpu_policy)
+ policy = cpufreq_cpu_get(cpu);
+ if (!policy)
return 0;
if (cpufreq_driver->suspend) {
- ret = cpufreq_driver->suspend(cpu_policy);
+ ret = cpufreq_driver->suspend(policy);
if (ret)
printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
- "step on CPU %u\n", cpu_policy->cpu);
+ "step on CPU %u\n", policy->cpu);
}
- cpufreq_cpu_put(cpu_policy);
+ cpufreq_cpu_put(policy);
return ret;
}
@@ -1418,28 +1475,28 @@ static void cpufreq_bp_resume(void)
int ret = 0;
int cpu = smp_processor_id();
- struct cpufreq_policy *cpu_policy;
+ struct cpufreq_policy *policy;
pr_debug("resuming cpu %u\n", cpu);
/* If there's no policy for the boot CPU, we have nothing to do. */
- cpu_policy = cpufreq_cpu_get(cpu);
- if (!cpu_policy)
+ policy = cpufreq_cpu_get(cpu);
+ if (!policy)
return;
if (cpufreq_driver->resume) {
- ret = cpufreq_driver->resume(cpu_policy);
+ ret = cpufreq_driver->resume(policy);
if (ret) {
printk(KERN_ERR "cpufreq: resume failed in ->resume "
- "step on CPU %u\n", cpu_policy->cpu);
+ "step on CPU %u\n", policy->cpu);
goto fail;
}
}
- schedule_work(&cpu_policy->update);
+ schedule_work(&policy->update);
fail:
- cpufreq_cpu_put(cpu_policy);
+ cpufreq_cpu_put(policy);
}
static struct syscore_ops cpufreq_syscore_ops = {
@@ -1593,18 +1650,6 @@ fail:
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
-int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
-{
- if (cpufreq_disabled())
- return 0;
-
- if (!cpufreq_driver->getavg)
- return 0;
-
- return cpufreq_driver->getavg(policy, cpu);
-}
-EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg);
-
/*
* when "event" is CPUFREQ_GOV_LIMITS
*/
@@ -1639,8 +1684,9 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
}
}
- if (!try_module_get(policy->governor->owner))
- return -EINVAL;
+ if (event == CPUFREQ_GOV_POLICY_INIT)
+ if (!try_module_get(policy->governor->owner))
+ return -EINVAL;
pr_debug("__cpufreq_governor for CPU %u, event %u\n",
policy->cpu, event);
@@ -1676,11 +1722,8 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
mutex_unlock(&cpufreq_governor_lock);
}
- /* we keep one module reference alive for
- each CPU governed by this CPU */
- if ((event != CPUFREQ_GOV_START) || ret)
- module_put(policy->governor->owner);
- if ((event == CPUFREQ_GOV_STOP) && !ret)
+ if (((event == CPUFREQ_GOV_POLICY_INIT) && ret) ||
+ ((event == CPUFREQ_GOV_POLICY_EXIT) && !ret))
module_put(policy->governor->owner);
return ret;
@@ -1760,7 +1803,7 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
if (!cpu_policy)
return -EINVAL;
- memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy));
+ memcpy(policy, cpu_policy, sizeof(*policy));
cpufreq_cpu_put(cpu_policy);
return 0;
@@ -1771,95 +1814,94 @@ EXPORT_SYMBOL(cpufreq_get_policy);
* data : current policy.
* policy : policy to be set.
*/
-static int __cpufreq_set_policy(struct cpufreq_policy *data,
- struct cpufreq_policy *policy)
+static int __cpufreq_set_policy(struct cpufreq_policy *policy,
+ struct cpufreq_policy *new_policy)
{
int ret = 0, failed = 1;
- pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
- policy->min, policy->max);
+ pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu,
+ new_policy->min, new_policy->max);
- memcpy(&policy->cpuinfo, &data->cpuinfo,
- sizeof(struct cpufreq_cpuinfo));
+ memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
- if (policy->min > data->max || policy->max < data->min) {
+ if (new_policy->min > policy->max || new_policy->max < policy->min) {
ret = -EINVAL;
goto error_out;
}
/* verify the cpu speed can be set within this limit */
- ret = cpufreq_driver->verify(policy);
+ ret = cpufreq_driver->verify(new_policy);
if (ret)
goto error_out;
/* adjust if necessary - all reasons */
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
- CPUFREQ_ADJUST, policy);
+ CPUFREQ_ADJUST, new_policy);
/* adjust if necessary - hardware incompatibility*/
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
- CPUFREQ_INCOMPATIBLE, policy);
+ CPUFREQ_INCOMPATIBLE, new_policy);
/*
* verify the cpu speed can be set within this limit, which might be
* different to the first one
*/
- ret = cpufreq_driver->verify(policy);
+ ret = cpufreq_driver->verify(new_policy);
if (ret)
goto error_out;
/* notification of the new policy */
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
- CPUFREQ_NOTIFY, policy);
+ CPUFREQ_NOTIFY, new_policy);
- data->min = policy->min;
- data->max = policy->max;
+ policy->min = new_policy->min;
+ policy->max = new_policy->max;
pr_debug("new min and max freqs are %u - %u kHz\n",
- data->min, data->max);
+ policy->min, policy->max);
if (cpufreq_driver->setpolicy) {
- data->policy = policy->policy;
+ policy->policy = new_policy->policy;
pr_debug("setting range\n");
- ret = cpufreq_driver->setpolicy(policy);
+ ret = cpufreq_driver->setpolicy(new_policy);
} else {
- if (policy->governor != data->governor) {
+ if (new_policy->governor != policy->governor) {
/* save old, working values */
- struct cpufreq_governor *old_gov = data->governor;
+ struct cpufreq_governor *old_gov = policy->governor;
pr_debug("governor switch\n");
/* end old governor */
- if (data->governor) {
- __cpufreq_governor(data, CPUFREQ_GOV_STOP);
- unlock_policy_rwsem_write(policy->cpu);
- __cpufreq_governor(data,
+ if (policy->governor) {
+ __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ unlock_policy_rwsem_write(new_policy->cpu);
+ __cpufreq_governor(policy,
CPUFREQ_GOV_POLICY_EXIT);
- lock_policy_rwsem_write(policy->cpu);
+ lock_policy_rwsem_write(new_policy->cpu);
}
/* start new governor */
- data->governor = policy->governor;
- if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) {
- if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) {
+ policy->governor = new_policy->governor;
+ if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
+ if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) {
failed = 0;
} else {
- unlock_policy_rwsem_write(policy->cpu);
- __cpufreq_governor(data,
+ unlock_policy_rwsem_write(new_policy->cpu);
+ __cpufreq_governor(policy,
CPUFREQ_GOV_POLICY_EXIT);
- lock_policy_rwsem_write(policy->cpu);
+ lock_policy_rwsem_write(new_policy->cpu);
}
}
if (failed) {
/* new governor failed, so re-start old one */
pr_debug("starting governor %s failed\n",
- data->governor->name);
+ policy->governor->name);
if (old_gov) {
- data->governor = old_gov;
- __cpufreq_governor(data,
+ policy->governor = old_gov;
+ __cpufreq_governor(policy,
CPUFREQ_GOV_POLICY_INIT);
- __cpufreq_governor(data,
+ __cpufreq_governor(policy,
CPUFREQ_GOV_START);
}
ret = -EINVAL;
@@ -1868,7 +1910,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
/* might be a policy change, too, so fall through */
}
pr_debug("governor: change or update limits\n");
- __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
}
error_out:
@@ -1884,11 +1926,11 @@ error_out:
*/
int cpufreq_update_policy(unsigned int cpu)
{
- struct cpufreq_policy *data = cpufreq_cpu_get(cpu);
- struct cpufreq_policy policy;
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ struct cpufreq_policy new_policy;
int ret;
- if (!data) {
+ if (!policy) {
ret = -ENODEV;
goto no_policy;
}
@@ -1899,34 +1941,34 @@ int cpufreq_update_policy(unsigned int cpu)
}
pr_debug("updating policy for CPU %u\n", cpu);
- memcpy(&policy, data, sizeof(struct cpufreq_policy));
- policy.min = data->user_policy.min;
- policy.max = data->user_policy.max;
- policy.policy = data->user_policy.policy;
- policy.governor = data->user_policy.governor;
+ memcpy(&new_policy, policy, sizeof(*policy));
+ new_policy.min = policy->user_policy.min;
+ new_policy.max = policy->user_policy.max;
+ new_policy.policy = policy->user_policy.policy;
+ new_policy.governor = policy->user_policy.governor;
/*
* BIOS might change freq behind our back
* -> ask driver for current freq and notify governors about a change
*/
if (cpufreq_driver->get) {
- policy.cur = cpufreq_driver->get(cpu);
- if (!data->cur) {
+ new_policy.cur = cpufreq_driver->get(cpu);
+ if (!policy->cur) {
pr_debug("Driver did not initialize current freq");
- data->cur = policy.cur;
+ policy->cur = new_policy.cur;
} else {
- if (data->cur != policy.cur && cpufreq_driver->target)
- cpufreq_out_of_sync(cpu, data->cur,
- policy.cur);
+ if (policy->cur != new_policy.cur && cpufreq_driver->target)
+ cpufreq_out_of_sync(cpu, policy->cur,
+ new_policy.cur);
}
}
- ret = __cpufreq_set_policy(data, &policy);
+ ret = __cpufreq_set_policy(policy, &new_policy);
unlock_policy_rwsem_write(cpu);
fail:
- cpufreq_cpu_put(data);
+ cpufreq_cpu_put(policy);
no_policy:
return ret;
}
@@ -1937,21 +1979,26 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
{
unsigned int cpu = (unsigned long)hcpu;
struct device *dev;
+ bool frozen = false;
dev = get_cpu_device(cpu);
if (dev) {
- switch (action) {
+
+ if (action & CPU_TASKS_FROZEN)
+ frozen = true;
+
+ switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- cpufreq_add_dev(dev, NULL);
+ __cpufreq_add_dev(dev, NULL, frozen);
+ cpufreq_update_policy(cpu);
break;
+
case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
- __cpufreq_remove_dev(dev, NULL);
+ __cpufreq_remove_dev(dev, NULL, frozen);
break;
+
case CPU_DOWN_FAILED:
- case CPU_DOWN_FAILED_FROZEN:
- cpufreq_add_dev(dev, NULL);
+ __cpufreq_add_dev(dev, NULL, frozen);
break;
}
}
@@ -2058,9 +2105,13 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
subsys_interface_unregister(&cpufreq_interface);
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
+ down_write(&cpufreq_rwsem);
write_lock_irqsave(&cpufreq_driver_lock, flags);
+
cpufreq_driver = NULL;
+
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ up_write(&cpufreq_rwsem);
return 0;
}
@@ -2073,10 +2124,8 @@ static int __init cpufreq_core_init(void)
if (cpufreq_disabled())
return -ENODEV;
- for_each_possible_cpu(cpu) {
- per_cpu(cpufreq_policy_cpu, cpu) = -1;
+ for_each_possible_cpu(cpu)
init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
- }
cpufreq_global_kobject = kobject_create();
BUG_ON(!cpufreq_global_kobject);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 0ceb2eff5a7..f62d822048e 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -11,19 +11,7 @@
* published by the Free Software Foundation.
*/
-#include <linux/cpufreq.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/notifier.h>
-#include <linux/percpu-defs.h>
#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
#include "cpufreq_governor.h"
/* Conservative governor macros */
@@ -79,8 +67,6 @@ static void cs_check_cpu(int cpu, unsigned int load)
return;
dbs_info->requested_freq += get_freq_target(cs_tuners, policy);
- if (dbs_info->requested_freq > policy->max)
- dbs_info->requested_freq = policy->max;
__cpufreq_driver_target(policy, dbs_info->requested_freq,
CPUFREQ_RELATION_H);
@@ -101,8 +87,6 @@ static void cs_check_cpu(int cpu, unsigned int load)
return;
dbs_info->requested_freq -= get_freq_target(cs_tuners, policy);
- if (dbs_info->requested_freq < policy->min)
- dbs_info->requested_freq = policy->min;
__cpufreq_driver_target(policy, dbs_info->requested_freq,
CPUFREQ_RELATION_L);
@@ -221,8 +205,8 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
return count;
}
-static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
- size_t count)
+static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
+ const char *buf, size_t count)
{
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input, j;
@@ -235,10 +219,10 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
if (input > 1)
input = 1;
- if (input == cs_tuners->ignore_nice) /* nothing to do */
+ if (input == cs_tuners->ignore_nice_load) /* nothing to do */
return count;
- cs_tuners->ignore_nice = input;
+ cs_tuners->ignore_nice_load = input;
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) {
@@ -246,7 +230,7 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
dbs_info = &per_cpu(cs_cpu_dbs_info, j);
dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
&dbs_info->cdbs.prev_cpu_wall, 0);
- if (cs_tuners->ignore_nice)
+ if (cs_tuners->ignore_nice_load)
dbs_info->cdbs.prev_cpu_nice =
kcpustat_cpu(j).cpustat[CPUTIME_NICE];
}
@@ -279,7 +263,7 @@ show_store_one(cs, sampling_rate);
show_store_one(cs, sampling_down_factor);
show_store_one(cs, up_threshold);
show_store_one(cs, down_threshold);
-show_store_one(cs, ignore_nice);
+show_store_one(cs, ignore_nice_load);
show_store_one(cs, freq_step);
declare_show_sampling_rate_min(cs);
@@ -287,7 +271,7 @@ gov_sys_pol_attr_rw(sampling_rate);
gov_sys_pol_attr_rw(sampling_down_factor);
gov_sys_pol_attr_rw(up_threshold);
gov_sys_pol_attr_rw(down_threshold);
-gov_sys_pol_attr_rw(ignore_nice);
+gov_sys_pol_attr_rw(ignore_nice_load);
gov_sys_pol_attr_rw(freq_step);
gov_sys_pol_attr_ro(sampling_rate_min);
@@ -297,7 +281,7 @@ static struct attribute *dbs_attributes_gov_sys[] = {
&sampling_down_factor_gov_sys.attr,
&up_threshold_gov_sys.attr,
&down_threshold_gov_sys.attr,
- &ignore_nice_gov_sys.attr,
+ &ignore_nice_load_gov_sys.attr,
&freq_step_gov_sys.attr,
NULL
};
@@ -313,7 +297,7 @@ static struct attribute *dbs_attributes_gov_pol[] = {
&sampling_down_factor_gov_pol.attr,
&up_threshold_gov_pol.attr,
&down_threshold_gov_pol.attr,
- &ignore_nice_gov_pol.attr,
+ &ignore_nice_load_gov_pol.attr,
&freq_step_gov_pol.attr,
NULL
};
@@ -329,7 +313,7 @@ static int cs_init(struct dbs_data *dbs_data)
{
struct cs_dbs_tuners *tuners;
- tuners = kzalloc(sizeof(struct cs_dbs_tuners), GFP_KERNEL);
+ tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);
if (!tuners) {
pr_err("%s: kzalloc failed\n", __func__);
return -ENOMEM;
@@ -338,7 +322,7 @@ static int cs_init(struct dbs_data *dbs_data)
tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;
tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
- tuners->ignore_nice = 0;
+ tuners->ignore_nice_load = 0;
tuners->freq_step = DEF_FREQUENCY_STEP;
dbs_data->tuners = tuners;
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 7b839a8db2a..0806c31e576 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -16,15 +16,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <asm/cputime.h>
-#include <linux/cpufreq.h>
-#include <linux/cpumask.h>
#include <linux/export.h>
#include <linux/kernel_stat.h>
-#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/workqueue.h>
#include "cpufreq_governor.h"
@@ -47,13 +41,13 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
unsigned int j;
if (dbs_data->cdata->governor == GOV_ONDEMAND)
- ignore_nice = od_tuners->ignore_nice;
+ ignore_nice = od_tuners->ignore_nice_load;
else
- ignore_nice = cs_tuners->ignore_nice;
+ ignore_nice = cs_tuners->ignore_nice_load;
policy = cdbs->cur_policy;
- /* Get Absolute Load (in terms of freq for ondemand gov) */
+ /* Get Absolute Load */
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_common_info *j_cdbs;
u64 cur_wall_time, cur_idle_time;
@@ -104,14 +98,6 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
load = 100 * (wall_time - idle_time) / wall_time;
- if (dbs_data->cdata->governor == GOV_ONDEMAND) {
- int freq_avg = __cpufreq_driver_getavg(policy, j);
- if (freq_avg <= 0)
- freq_avg = policy->cur;
-
- load *= freq_avg;
- }
-
if (load > max_load)
max_load = load;
}
@@ -133,8 +119,18 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
{
int i;
+ if (!policy->governor_enabled)
+ return;
+
if (!all_cpus) {
- __gov_queue_work(smp_processor_id(), dbs_data, delay);
+ /*
+ * Use raw_smp_processor_id() to avoid preemptible warnings.
+ * We know that this is only called with all_cpus == false from
+ * works that have been queued with *_work_on() functions and
+ * those works are canceled during CPU_DOWN_PREPARE so they
+ * can't possibly run on any other CPU.
+ */
+ __gov_queue_work(raw_smp_processor_id(), dbs_data, delay);
} else {
for_each_cpu(i, policy->cpus)
__gov_queue_work(i, dbs_data, delay);
@@ -244,7 +240,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
policy->governor_data = dbs_data;
- /* policy latency is in nS. Convert it to uS first */
+ /* policy latency is in ns. Convert it to us first */
latency = policy->cpuinfo.transition_latency / 1000;
if (latency == 0)
latency = 1;
@@ -298,12 +294,12 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
cs_tuners = dbs_data->tuners;
cs_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
sampling_rate = cs_tuners->sampling_rate;
- ignore_nice = cs_tuners->ignore_nice;
+ ignore_nice = cs_tuners->ignore_nice_load;
} else {
od_tuners = dbs_data->tuners;
od_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
sampling_rate = od_tuners->sampling_rate;
- ignore_nice = od_tuners->ignore_nice;
+ ignore_nice = od_tuners->ignore_nice_load;
od_ops = dbs_data->cdata->gov_ops;
io_busy = od_tuners->io_is_busy;
}
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index 6663ec3b305..88cd39f7b0e 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -18,19 +18,18 @@
#define _CPUFREQ_GOVERNOR_H
#include <linux/cpufreq.h>
-#include <linux/kobject.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/workqueue.h>
-#include <linux/sysfs.h>
/*
* The polling frequency depends on the capability of the processor. Default
* polling frequency is 1000 times the transition latency of the processor. The
- * governor will work on any processor with transition latency <= 10mS, using
+ * governor will work on any processor with transition latency <= 10ms, using
* appropriate sampling rate.
*
- * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
- * this governor will not work. All times here are in uS.
+ * For CPUs with transition latency > 10ms (mostly drivers with CPUFREQ_ETERNAL)
+ * this governor will not work. All times here are in us (micro seconds).
*/
#define MIN_SAMPLING_RATE_RATIO (2)
#define LATENCY_MULTIPLIER (1000)
@@ -163,19 +162,18 @@ struct cs_cpu_dbs_info_s {
unsigned int enable:1;
};
-/* Per policy Governers sysfs tunables */
+/* Per policy Governors sysfs tunables */
struct od_dbs_tuners {
- unsigned int ignore_nice;
+ unsigned int ignore_nice_load;
unsigned int sampling_rate;
unsigned int sampling_down_factor;
unsigned int up_threshold;
- unsigned int adj_up_threshold;
unsigned int powersave_bias;
unsigned int io_is_busy;
};
struct cs_dbs_tuners {
- unsigned int ignore_nice;
+ unsigned int ignore_nice_load;
unsigned int sampling_rate;
unsigned int sampling_down_factor;
unsigned int up_threshold;
@@ -183,7 +181,7 @@ struct cs_dbs_tuners {
unsigned int freq_step;
};
-/* Common Governer data across policies */
+/* Common Governor data across policies */
struct dbs_data;
struct common_dbs_data {
/* Common across governors */
@@ -207,7 +205,7 @@ struct common_dbs_data {
void *gov_ops;
};
-/* Governer Per policy data */
+/* Governor Per policy data */
struct dbs_data {
struct common_dbs_data *cdata;
unsigned int min_sampling_rate;
@@ -223,7 +221,7 @@ struct od_ops {
void (*powersave_bias_init_cpu)(int cpu);
unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy,
unsigned int freq_next, unsigned int relation);
- void (*freq_increase)(struct cpufreq_policy *p, unsigned int freq);
+ void (*freq_increase)(struct cpufreq_policy *policy, unsigned int freq);
};
struct cs_ops {
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 93eb5cbcc1f..32f26f6e17c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -12,28 +12,16 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/cpufreq.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
+#include <linux/cpu.h>
#include <linux/percpu-defs.h>
#include <linux/slab.h>
-#include <linux/sysfs.h>
#include <linux/tick.h>
-#include <linux/types.h>
-#include <linux/cpu.h>
-
#include "cpufreq_governor.h"
/* On-demand governor macros */
-#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10)
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (100000)
-#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3)
#define MICRO_FREQUENCY_UP_THRESHOLD (95)
#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000)
#define MIN_FREQUENCY_UP_THRESHOLD (11)
@@ -144,31 +132,27 @@ static void ondemand_powersave_bias_init(void)
}
}
-static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
+static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq)
{
- struct dbs_data *dbs_data = p->governor_data;
+ struct dbs_data *dbs_data = policy->governor_data;
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
if (od_tuners->powersave_bias)
- freq = od_ops.powersave_bias_target(p, freq,
+ freq = od_ops.powersave_bias_target(policy, freq,
CPUFREQ_RELATION_H);
- else if (p->cur == p->max)
+ else if (policy->cur == policy->max)
return;
- __cpufreq_driver_target(p, freq, od_tuners->powersave_bias ?
+ __cpufreq_driver_target(policy, freq, od_tuners->powersave_bias ?
CPUFREQ_RELATION_L : CPUFREQ_RELATION_H);
}
/*
* Every sampling_rate, we check, if current idle time is less than 20%
- * (default), then we try to increase frequency. Every sampling_rate, we look
- * for the lowest frequency which can sustain the load while keeping idle time
- * over 30%. If such a frequency exist, we try to decrease to this frequency.
- *
- * Any frequency increase takes it to the maximum frequency. Frequency reduction
- * happens at minimum steps of 5% (default) of current frequency
+ * (default), then we try to increase frequency. Else, we adjust the frequency
+ * proportional to load.
*/
-static void od_check_cpu(int cpu, unsigned int load_freq)
+static void od_check_cpu(int cpu, unsigned int load)
{
struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
@@ -178,36 +162,21 @@ static void od_check_cpu(int cpu, unsigned int load_freq)
dbs_info->freq_lo = 0;
/* Check for frequency increase */
- if (load_freq > od_tuners->up_threshold * policy->cur) {
+ if (load > od_tuners->up_threshold) {
/* If switching to max speed, apply sampling_down_factor */
if (policy->cur < policy->max)
dbs_info->rate_mult =
od_tuners->sampling_down_factor;
dbs_freq_increase(policy, policy->max);
return;
- }
-
- /* Check for frequency decrease */
- /* if we cannot reduce the frequency anymore, break out early */
- if (policy->cur == policy->min)
- return;
-
- /*
- * The optimal frequency is the frequency that is the lowest that can
- * support the current CPU usage without triggering the up policy. To be
- * safe, we focus 10 points under the threshold.
- */
- if (load_freq < od_tuners->adj_up_threshold
- * policy->cur) {
+ } else {
+ /* Calculate the next frequency proportional to load */
unsigned int freq_next;
- freq_next = load_freq / od_tuners->adj_up_threshold;
+ freq_next = load * policy->cpuinfo.max_freq / 100;
/* No longer fully busy, reset rate_mult */
dbs_info->rate_mult = 1;
- if (freq_next < policy->min)
- freq_next = policy->min;
-
if (!od_tuners->powersave_bias) {
__cpufreq_driver_target(policy, freq_next,
CPUFREQ_RELATION_L);
@@ -374,9 +343,6 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
input < MIN_FREQUENCY_UP_THRESHOLD) {
return -EINVAL;
}
- /* Calculate the new adj_up_threshold */
- od_tuners->adj_up_threshold += input;
- od_tuners->adj_up_threshold -= od_tuners->up_threshold;
od_tuners->up_threshold = input;
return count;
@@ -403,8 +369,8 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
return count;
}
-static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
- size_t count)
+static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
+ const char *buf, size_t count)
{
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
unsigned int input;
@@ -419,10 +385,10 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
if (input > 1)
input = 1;
- if (input == od_tuners->ignore_nice) { /* nothing to do */
+ if (input == od_tuners->ignore_nice_load) { /* nothing to do */
return count;
}
- od_tuners->ignore_nice = input;
+ od_tuners->ignore_nice_load = input;
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) {
@@ -430,7 +396,7 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
dbs_info = &per_cpu(od_cpu_dbs_info, j);
dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
&dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy);
- if (od_tuners->ignore_nice)
+ if (od_tuners->ignore_nice_load)
dbs_info->cdbs.prev_cpu_nice =
kcpustat_cpu(j).cpustat[CPUTIME_NICE];
@@ -461,7 +427,7 @@ show_store_one(od, sampling_rate);
show_store_one(od, io_is_busy);
show_store_one(od, up_threshold);
show_store_one(od, sampling_down_factor);
-show_store_one(od, ignore_nice);
+show_store_one(od, ignore_nice_load);
show_store_one(od, powersave_bias);
declare_show_sampling_rate_min(od);
@@ -469,7 +435,7 @@ gov_sys_pol_attr_rw(sampling_rate);
gov_sys_pol_attr_rw(io_is_busy);
gov_sys_pol_attr_rw(up_threshold);
gov_sys_pol_attr_rw(sampling_down_factor);
-gov_sys_pol_attr_rw(ignore_nice);
+gov_sys_pol_attr_rw(ignore_nice_load);
gov_sys_pol_attr_rw(powersave_bias);
gov_sys_pol_attr_ro(sampling_rate_min);
@@ -478,7 +444,7 @@ static struct attribute *dbs_attributes_gov_sys[] = {
&sampling_rate_gov_sys.attr,
&up_threshold_gov_sys.attr,
&sampling_down_factor_gov_sys.attr,
- &ignore_nice_gov_sys.attr,
+ &ignore_nice_load_gov_sys.attr,
&powersave_bias_gov_sys.attr,
&io_is_busy_gov_sys.attr,
NULL
@@ -494,7 +460,7 @@ static struct attribute *dbs_attributes_gov_pol[] = {
&sampling_rate_gov_pol.attr,
&up_threshold_gov_pol.attr,
&sampling_down_factor_gov_pol.attr,
- &ignore_nice_gov_pol.attr,
+ &ignore_nice_load_gov_pol.attr,
&powersave_bias_gov_pol.attr,
&io_is_busy_gov_pol.attr,
NULL
@@ -513,7 +479,7 @@ static int od_init(struct dbs_data *dbs_data)
u64 idle_time;
int cpu;
- tuners = kzalloc(sizeof(struct od_dbs_tuners), GFP_KERNEL);
+ tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);
if (!tuners) {
pr_err("%s: kzalloc failed\n", __func__);
return -ENOMEM;
@@ -525,8 +491,6 @@ static int od_init(struct dbs_data *dbs_data)
if (idle_time != -1ULL) {
/* Idle micro accounting is supported. Use finer thresholds */
tuners->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
- tuners->adj_up_threshold = MICRO_FREQUENCY_UP_THRESHOLD -
- MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
/*
* In nohz/micro accounting case we set the minimum frequency
* not depending on HZ, but fixed (very low). The deferred
@@ -535,8 +499,6 @@ static int od_init(struct dbs_data *dbs_data)
dbs_data->min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
} else {
tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
- tuners->adj_up_threshold = DEF_FREQUENCY_UP_THRESHOLD -
- DEF_FREQUENCY_DOWN_DIFFERENTIAL;
/* For correct statistics, we need 10 ticks for each measure */
dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
@@ -544,7 +506,7 @@ static int od_init(struct dbs_data *dbs_data)
}
tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
- tuners->ignore_nice = 0;
+ tuners->ignore_nice_load = 0;
tuners->powersave_bias = default_powersave_bias;
tuners->io_is_busy = should_io_be_busy();
diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c
index 9fef7d6e4e6..cf117deb39b 100644
--- a/drivers/cpufreq/cpufreq_performance.c
+++ b/drivers/cpufreq/cpufreq_performance.c
@@ -12,10 +12,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/cpufreq.h>
#include <linux/init.h>
+#include <linux/module.h>
static int cpufreq_governor_performance(struct cpufreq_policy *policy,
unsigned int event)
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index 32109a14f5d..e3b874c235e 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -12,10 +12,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/cpufreq.h>
#include <linux/init.h>
+#include <linux/module.h>
static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
unsigned int event)
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index d37568c5ca9..04452f026ed 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -9,17 +9,10 @@
* published by the Free Software Foundation.
*/
-#include <linux/kernel.h>
-#include <linux/slab.h>
#include <linux/cpu.h>
-#include <linux/sysfs.h>
#include <linux/cpufreq.h>
#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/percpu.h>
-#include <linux/kobject.h>
-#include <linux/spinlock.h>
-#include <linux/notifier.h>
+#include <linux/slab.h>
#include <asm/cputime.h>
static spinlock_t cpufreq_stats_lock;
@@ -200,22 +193,22 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
{
unsigned int i, j, count = 0, ret = 0;
struct cpufreq_stats *stat;
- struct cpufreq_policy *data;
+ struct cpufreq_policy *current_policy;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
if (per_cpu(cpufreq_stats_table, cpu))
return -EBUSY;
- stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
+ stat = kzalloc(sizeof(*stat), GFP_KERNEL);
if ((stat) == NULL)
return -ENOMEM;
- data = cpufreq_cpu_get(cpu);
- if (data == NULL) {
+ current_policy = cpufreq_cpu_get(cpu);
+ if (current_policy == NULL) {
ret = -EINVAL;
goto error_get_fail;
}
- ret = sysfs_create_group(&data->kobj, &stats_attr_group);
+ ret = sysfs_create_group(&current_policy->kobj, &stats_attr_group);
if (ret)
goto error_out;
@@ -258,10 +251,10 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
stat->last_time = get_jiffies_64();
stat->last_index = freq_table_get_index(stat, policy->cur);
spin_unlock(&cpufreq_stats_lock);
- cpufreq_cpu_put(data);
+ cpufreq_cpu_put(current_policy);
return 0;
error_out:
- cpufreq_cpu_put(data);
+ cpufreq_cpu_put(current_policy);
error_get_fail:
kfree(stat);
per_cpu(cpufreq_stats_table, cpu) = NULL;
@@ -348,16 +341,10 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
unsigned int cpu = (unsigned long)hcpu;
switch (action) {
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- cpufreq_update_policy(cpu);
- break;
case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
cpufreq_stats_free_sysfs(cpu);
break;
case CPU_DEAD:
- case CPU_DEAD_FROZEN:
cpufreq_stats_free_table(cpu);
break;
}
@@ -390,8 +377,6 @@ static int __init cpufreq_stats_init(void)
return ret;
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
- for_each_online_cpu(cpu)
- cpufreq_update_policy(cpu);
ret = cpufreq_register_notifier(&notifier_trans_block,
CPUFREQ_TRANSITION_NOTIFIER);
diff --git a/drivers/cpufreq/cris-artpec3-cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c
index ee142c49057..cb8276dd19c 100644
--- a/drivers/cpufreq/cris-artpec3-cpufreq.c
+++ b/drivers/cpufreq/cris-artpec3-cpufreq.c
@@ -111,7 +111,6 @@ static struct cpufreq_driver cris_freq_driver = {
.init = cris_freq_cpu_init,
.exit = cris_freq_cpu_exit,
.name = "cris_freq",
- .owner = THIS_MODULE,
.attr = cris_freq_attr,
};
diff --git a/drivers/cpufreq/cris-etraxfs-cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c
index 12952235d5d..72328f77dc5 100644
--- a/drivers/cpufreq/cris-etraxfs-cpufreq.c
+++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c
@@ -108,7 +108,6 @@ static struct cpufreq_driver cris_freq_driver = {
.init = cris_freq_cpu_init,
.exit = cris_freq_cpu_exit,
.name = "cris_freq",
- .owner = THIS_MODULE,
.attr = cris_freq_attr,
};
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c
index a60efaeb4cf..09f64cc8301 100644
--- a/drivers/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
@@ -54,7 +54,7 @@ static struct acpi_processor_performance *eps_acpi_cpu_perf;
/* Minimum necessary to get acpi_processor_get_bios_limit() working */
static int eps_acpi_init(void)
{
- eps_acpi_cpu_perf = kzalloc(sizeof(struct acpi_processor_performance),
+ eps_acpi_cpu_perf = kzalloc(sizeof(*eps_acpi_cpu_perf),
GFP_KERNEL);
if (!eps_acpi_cpu_perf)
return -ENOMEM;
@@ -366,7 +366,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
states = 2;
/* Allocate private data and frequency table for current cpu */
- centaur = kzalloc(sizeof(struct eps_cpu_data)
+ centaur = kzalloc(sizeof(*centaur)
+ (states + 1) * sizeof(struct cpufreq_frequency_table),
GFP_KERNEL);
if (!centaur)
@@ -436,7 +436,6 @@ static struct cpufreq_driver eps_driver = {
.exit = eps_cpu_exit,
.get = eps_get,
.name = "e_powersaver",
- .owner = THIS_MODULE,
.attr = eps_attr,
};
diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c
index 658d860344b..823a400d98f 100644
--- a/drivers/cpufreq/elanfreq.c
+++ b/drivers/cpufreq/elanfreq.c
@@ -274,7 +274,6 @@ static struct cpufreq_driver elanfreq_driver = {
.init = elanfreq_cpu_init,
.exit = elanfreq_cpu_exit,
.name = "elanfreq",
- .owner = THIS_MODULE,
.attr = elanfreq_attr,
};
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 0d32f02ef4d..0fac34439e3 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -289,7 +289,7 @@ static int __init exynos_cpufreq_init(void)
{
int ret = -EINVAL;
- exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL);
+ exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
if (!exynos_info)
return -ENOMEM;
@@ -332,7 +332,6 @@ err_cpufreq:
regulator_put(arm_regulator);
err_vdd_arm:
kfree(exynos_info);
- pr_debug("%s: failed initialization\n", __func__);
return -EINVAL;
}
late_initcall(exynos_cpufreq_init);
diff --git a/drivers/cpufreq/exynos-cpufreq.h b/drivers/cpufreq/exynos-cpufreq.h
index 92b852ee5dd..7f25cee8cec 100644
--- a/drivers/cpufreq/exynos-cpufreq.h
+++ b/drivers/cpufreq/exynos-cpufreq.h
@@ -43,6 +43,27 @@ struct exynos_dvfs_info {
bool (*need_apll_change)(unsigned int, unsigned int);
};
+#ifdef CONFIG_ARM_EXYNOS4210_CPUFREQ
extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
+#else
+static inline int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+#ifdef CONFIG_ARM_EXYNOS4X12_CPUFREQ
extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
+#else
+static inline int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+#ifdef CONFIG_ARM_EXYNOS5250_CPUFREQ
extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
+#else
+static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
+{
+ return -EOPNOTSUPP;
+}
+#endif
diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c
index 0c74018eda4..d514c152fd1 100644
--- a/drivers/cpufreq/exynos5440-cpufreq.c
+++ b/drivers/cpufreq/exynos5440-cpufreq.c
@@ -238,6 +238,9 @@ static int exynos_target(struct cpufreq_policy *policy,
freqs.old = dvfs_info->cur_frequency;
freqs.new = freq_table[index].frequency;
+ if (freqs.old == freqs.new)
+ goto out;
+
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* Set the target frequency in all C0_3_PSTATE register */
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index f0d87412cc9..f111454a7ae 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -11,10 +11,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
#include <linux/cpufreq.h>
+#include <linux/module.h>
/*********************************************************************
* FREQUENCY TABLE HELPERS *
diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c
index 3dfc99b9ca8..70442c7b5e7 100644
--- a/drivers/cpufreq/gx-suspmod.c
+++ b/drivers/cpufreq/gx-suspmod.c
@@ -183,7 +183,7 @@ static void gx_write_byte(int reg, int value)
* gx_detect_chipset:
*
**/
-static __init struct pci_dev *gx_detect_chipset(void)
+static struct pci_dev * __init gx_detect_chipset(void)
{
struct pci_dev *gx_pci = NULL;
@@ -446,7 +446,6 @@ static struct cpufreq_driver gx_suspmod_driver = {
.target = cpufreq_gx_target,
.init = cpufreq_gx_cpu_init,
.name = "gx-suspmod",
- .owner = THIS_MODULE,
};
static int __init cpufreq_gx_init(void)
@@ -466,7 +465,7 @@ static int __init cpufreq_gx_init(void)
pr_debug("geode suspend modulation available.\n");
- params = kzalloc(sizeof(struct gxfreq_params), GFP_KERNEL);
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
if (params == NULL)
return -ENOMEM;
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
index b61b5a3fad6..794123fcf3e 100644
--- a/drivers/cpufreq/highbank-cpufreq.c
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -69,23 +69,17 @@ static int hb_cpufreq_driver_init(void)
if (!of_machine_is_compatible("calxeda,highbank"))
return -ENODEV;
- for_each_child_of_node(of_find_node_by_path("/cpus"), np)
- if (of_get_property(np, "operating-points", NULL))
- break;
-
- if (!np) {
- pr_err("failed to find highbank cpufreq node\n");
- return -ENOENT;
- }
-
cpu_dev = get_cpu_device(0);
if (!cpu_dev) {
pr_err("failed to get highbank cpufreq device\n");
- ret = -ENODEV;
- goto out_put_node;
+ return -ENODEV;
}
- cpu_dev->of_node = np;
+ np = of_node_get(cpu_dev->of_node);
+ if (!np) {
+ pr_err("failed to find highbank cpufreq node\n");
+ return -ENOENT;
+ }
cpu_clk = clk_get(cpu_dev, NULL);
if (IS_ERR(cpu_clk)) {
diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c
index 573c14ea802..3e14f031717 100644
--- a/drivers/cpufreq/ia64-acpi-cpufreq.c
+++ b/drivers/cpufreq/ia64-acpi-cpufreq.c
@@ -274,7 +274,7 @@ acpi_cpufreq_cpu_init (
pr_debug("acpi_cpufreq_cpu_init\n");
- data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return (-ENOMEM);
@@ -304,7 +304,7 @@ acpi_cpufreq_cpu_init (
}
/* alloc freq_table */
- data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) *
+ data->freq_table = kmalloc(sizeof(*data->freq_table) *
(data->acpi_data.state_count + 1),
GFP_KERNEL);
if (!data->freq_table) {
@@ -409,7 +409,6 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.init = acpi_cpufreq_cpu_init,
.exit = acpi_cpufreq_cpu_exit,
.name = "acpi-cpufreq",
- .owner = THIS_MODULE,
.attr = acpi_cpufreq_attr,
};
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index e37cdaedbb5..3e396543aea 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -117,28 +117,11 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
* - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
* - Disable pll2_pfd2_396m_clk
*/
- clk_prepare_enable(pll2_pfd2_396m_clk);
clk_set_parent(step_clk, pll2_pfd2_396m_clk);
clk_set_parent(pll1_sw_clk, step_clk);
if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
clk_set_rate(pll1_sys_clk, freqs.new * 1000);
- /*
- * If we are leaving 396 MHz set-point, we need to enable
- * pll1_sys_clk and disable pll2_pfd2_396m_clk to keep
- * their use count correct.
- */
- if (freqs.old * 1000 <= clk_get_rate(pll2_pfd2_396m_clk)) {
- clk_prepare_enable(pll1_sys_clk);
- clk_disable_unprepare(pll2_pfd2_396m_clk);
- }
clk_set_parent(pll1_sw_clk, pll1_sys_clk);
- clk_disable_unprepare(pll2_pfd2_396m_clk);
- } else {
- /*
- * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
- * to provide the frequency.
- */
- clk_disable_unprepare(pll1_sys_clk);
}
/* Ensure the arm clock divider is what we expect */
@@ -221,14 +204,12 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
cpu_dev = &pdev->dev;
- np = of_find_node_by_path("/cpus/cpu@0");
+ np = of_node_get(cpu_dev->of_node);
if (!np) {
dev_err(cpu_dev, "failed to find cpu0 node\n");
return -ENOENT;
}
- cpu_dev->of_node = np;
-
arm_clk = devm_clk_get(cpu_dev, "arm");
pll1_sys_clk = devm_clk_get(cpu_dev, "pll1_sys");
pll1_sw_clk = devm_clk_get(cpu_dev, "pll1_sw");
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index b012d7600e1..6efd96c196b 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -103,10 +103,10 @@ struct pstate_adjust_policy {
static struct pstate_adjust_policy default_policy = {
.sample_rate_ms = 10,
.deadband = 0,
- .setpoint = 109,
- .p_gain_pct = 17,
+ .setpoint = 97,
+ .p_gain_pct = 20,
.d_gain_pct = 0,
- .i_gain_pct = 4,
+ .i_gain_pct = 0,
};
struct perf_limits {
@@ -468,12 +468,12 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
static inline int intel_pstate_get_scaled_busy(struct cpudata *cpu)
{
int32_t busy_scaled;
- int32_t core_busy, turbo_pstate, current_pstate;
+ int32_t core_busy, max_pstate, current_pstate;
core_busy = int_tofp(cpu->samples[cpu->sample_ptr].core_pct_busy);
- turbo_pstate = int_tofp(cpu->pstate.turbo_pstate);
+ max_pstate = int_tofp(cpu->pstate.max_pstate);
current_pstate = int_tofp(cpu->pstate.current_pstate);
- busy_scaled = mul_fp(core_busy, div_fp(turbo_pstate, current_pstate));
+ busy_scaled = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
return fp_toint(busy_scaled);
}
@@ -665,7 +665,6 @@ static struct cpufreq_driver intel_pstate_driver = {
.init = intel_pstate_cpu_init,
.exit = intel_pstate_cpu_exit,
.name = "intel_pstate",
- .owner = THIS_MODULE,
};
static int __initdata no_load;
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index c233ea61736..ba10658a939 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -14,7 +14,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/cpufreq.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <asm/proc-fns.h>
@@ -158,7 +158,6 @@ static struct cpufreq_driver kirkwood_cpufreq_driver = {
.init = kirkwood_cpufreq_cpu_init,
.exit = kirkwood_cpufreq_cpu_exit,
.name = "kirkwood-cpufreq",
- .owner = THIS_MODULE,
.attr = kirkwood_cpufreq_attr,
};
@@ -175,9 +174,11 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev)
if (IS_ERR(priv.base))
return PTR_ERR(priv.base);
- np = of_find_node_by_path("/cpus/cpu@0");
- if (!np)
+ np = of_cpu_device_node_get(0);
+ if (!np) {
+ dev_err(&pdev->dev, "failed to get cpu device node\n");
return -ENODEV;
+ }
priv.cpu_clk = of_clk_get_by_name(np, "cpu_clk");
if (IS_ERR(priv.cpu_clk)) {
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index 8c49261df57..4ada1cccb05 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -948,7 +948,6 @@ static struct cpufreq_driver longhaul_driver = {
.init = longhaul_cpu_init,
.exit = longhaul_cpu_exit,
.name = "longhaul",
- .owner = THIS_MODULE,
.attr = longhaul_attr,
};
diff --git a/drivers/cpufreq/longrun.c b/drivers/cpufreq/longrun.c
index 0fe041d1f77..5aa031612d5 100644
--- a/drivers/cpufreq/longrun.c
+++ b/drivers/cpufreq/longrun.c
@@ -286,7 +286,6 @@ static struct cpufreq_driver longrun_driver = {
.get = longrun_get,
.init = longrun_cpu_init,
.name = "longrun",
- .owner = THIS_MODULE,
};
static const struct x86_cpu_id longrun_ids[] = {
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index bb838b98507..7bc3c44d34e 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -118,11 +118,6 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
clk_put(cpuclk);
return -EINVAL;
}
- ret = clk_set_rate(cpuclk, rate);
- if (ret) {
- clk_put(cpuclk);
- return ret;
- }
/* clock table init */
for (i = 2;
@@ -130,6 +125,12 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
i++)
loongson2_clockmod_table[i].frequency = (rate * i) / 8;
+ ret = clk_set_rate(cpuclk, rate);
+ if (ret) {
+ clk_put(cpuclk);
+ return ret;
+ }
+
policy->cur = loongson2_cpufreq_get(policy->cpu);
cpufreq_frequency_table_get_attr(&loongson2_clockmod_table[0],
@@ -157,7 +158,6 @@ static struct freq_attr *loongson2_table_attr[] = {
};
static struct cpufreq_driver loongson2_cpufreq_driver = {
- .owner = THIS_MODULE,
.name = "loongson2",
.init = loongson2_cpufreq_cpu_init,
.verify = loongson2_cpufreq_verify,
diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c
index cdd62915efa..6168d77b296 100644
--- a/drivers/cpufreq/maple-cpufreq.c
+++ b/drivers/cpufreq/maple-cpufreq.c
@@ -24,7 +24,7 @@
#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/time.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
#define DBG(fmt...) pr_debug(fmt)
@@ -190,7 +190,6 @@ static int maple_cpufreq_cpu_init(struct cpufreq_policy *policy)
static struct cpufreq_driver maple_cpufreq_driver = {
.name = "maple",
- .owner = THIS_MODULE,
.flags = CPUFREQ_CONST_LOOPS,
.init = maple_cpufreq_cpu_init,
.verify = maple_cpufreq_verify,
@@ -201,7 +200,6 @@ static struct cpufreq_driver maple_cpufreq_driver = {
static int __init maple_cpufreq_init(void)
{
- struct device_node *cpus;
struct device_node *cpunode;
unsigned int psize;
unsigned long max_freq;
@@ -217,24 +215,11 @@ static int __init maple_cpufreq_init(void)
!of_machine_is_compatible("Momentum,Apache"))
return 0;
- cpus = of_find_node_by_path("/cpus");
- if (cpus == NULL) {
- DBG("No /cpus node !\n");
- return -ENODEV;
- }
-
/* Get first CPU node */
- for (cpunode = NULL;
- (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
- const u32 *reg = of_get_property(cpunode, "reg", NULL);
- if (reg == NULL || (*reg) != 0)
- continue;
- if (!strcmp(cpunode->type, "cpu"))
- break;
- }
+ cpunode = of_cpu_device_node_get(0);
if (cpunode == NULL) {
printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n");
- goto bail_cpus;
+ goto bail_noprops;
}
/* Check 970FX for now */
@@ -290,14 +275,11 @@ static int __init maple_cpufreq_init(void)
rc = cpufreq_register_driver(&maple_cpufreq_driver);
of_node_put(cpunode);
- of_node_put(cpus);
return rc;
bail_noprops:
of_node_put(cpunode);
-bail_cpus:
- of_node_put(cpus);
return rc;
}
diff --git a/drivers/cpufreq/mperf.c b/drivers/cpufreq/mperf.c
deleted file mode 100644
index 911e193018a..00000000000
--- a/drivers/cpufreq/mperf.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/smp.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <linux/slab.h>
-
-#include "mperf.h"
-
-static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf);
-
-/* Called via smp_call_function_single(), on the target CPU */
-static void read_measured_perf_ctrs(void *_cur)
-{
- struct aperfmperf *am = _cur;
-
- get_aperfmperf(am);
-}
-
-/*
- * Return the measured active (C0) frequency on this CPU since last call
- * to this function.
- * Input: cpu number
- * Return: Average CPU frequency in terms of max frequency (zero on error)
- *
- * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance
- * over a period of time, while CPU is in C0 state.
- * IA32_MPERF counts at the rate of max advertised frequency
- * IA32_APERF counts at the rate of actual CPU frequency
- * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and
- * no meaning should be associated with absolute values of these MSRs.
- */
-unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy,
- unsigned int cpu)
-{
- struct aperfmperf perf;
- unsigned long ratio;
- unsigned int retval;
-
- if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1))
- return 0;
-
- ratio = calc_aperfmperf_ratio(&per_cpu(acfreq_old_perf, cpu), &perf);
- per_cpu(acfreq_old_perf, cpu) = perf;
-
- retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT;
-
- return retval;
-}
-EXPORT_SYMBOL_GPL(cpufreq_get_measured_perf);
-MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/mperf.h b/drivers/cpufreq/mperf.h
deleted file mode 100644
index 5dbf2950dc2..00000000000
--- a/drivers/cpufreq/mperf.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * (c) 2010 Advanced Micro Devices, Inc.
- * Your use of this code is subject to the terms and conditions of the
- * GNU general public license version 2. See "COPYING" or
- * http://www.gnu.org/licenses/gpl.html
- */
-
-unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy,
- unsigned int cpu);
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index 9ee78170ff8..2f0a2a65c37 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -279,7 +279,6 @@ static struct cpufreq_driver p4clockmod_driver = {
.exit = cpufreq_p4_cpu_exit,
.get = cpufreq_p4_get,
.name = "p4-clockmod",
- .owner = THIS_MODULE,
.attr = p4clockmod_attr,
};
diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c
index b704da40406..534e43a60d1 100644
--- a/drivers/cpufreq/pasemi-cpufreq.c
+++ b/drivers/cpufreq/pasemi-cpufreq.c
@@ -297,7 +297,6 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy,
static struct cpufreq_driver pas_cpufreq_driver = {
.name = "pas-cpufreq",
- .owner = THIS_MODULE,
.flags = CPUFREQ_CONST_LOOPS,
.init = pas_cpufreq_cpu_init,
.exit = pas_cpufreq_cpu_exit,
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 1581fcc4cf4..d81c4e5ea0a 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -587,7 +587,6 @@ static struct cpufreq_driver pcc_cpufreq_driver = {
.init = pcc_cpufreq_cpu_init,
.exit = pcc_cpufreq_cpu_exit,
.name = "pcc-cpufreq",
- .owner = THIS_MODULE,
};
static int __init pcc_cpufreq_init(void)
diff --git a/drivers/cpufreq/pmac32-cpufreq.c b/drivers/cpufreq/pmac32-cpufreq.c
index 3104fad8248..a096cd3fa23 100644
--- a/drivers/cpufreq/pmac32-cpufreq.c
+++ b/drivers/cpufreq/pmac32-cpufreq.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/hardirq.h>
+#include <linux/of_device.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/irq.h>
@@ -477,7 +478,6 @@ static struct cpufreq_driver pmac_cpufreq_driver = {
.flags = CPUFREQ_PM_NO_WARN,
.attr = pmac_cpu_freqs_attr,
.name = "powermac",
- .owner = THIS_MODULE,
};
@@ -649,8 +649,8 @@ static int __init pmac_cpufreq_setup(void)
if (strstr(cmd_line, "nocpufreq"))
return 0;
- /* Assume only one CPU */
- cpunode = of_find_node_by_type(NULL, "cpu");
+ /* Get first CPU node */
+ cpunode = of_cpu_device_node_get(0);
if (!cpunode)
goto out;
diff --git a/drivers/cpufreq/pmac64-cpufreq.c b/drivers/cpufreq/pmac64-cpufreq.c
index 7ba423431cf..3a51ad7e47c 100644
--- a/drivers/cpufreq/pmac64-cpufreq.c
+++ b/drivers/cpufreq/pmac64-cpufreq.c
@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/mutex.h>
+#include <linux/of_device.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/irq.h>
@@ -371,7 +372,6 @@ static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
static struct cpufreq_driver g5_cpufreq_driver = {
.name = "powermac",
- .owner = THIS_MODULE,
.flags = CPUFREQ_CONST_LOOPS,
.init = g5_cpufreq_cpu_init,
.verify = g5_cpufreq_verify,
@@ -383,9 +383,8 @@ static struct cpufreq_driver g5_cpufreq_driver = {
#ifdef CONFIG_PMAC_SMU
-static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
+static int __init g5_neo2_cpufreq_init(struct device_node *cpunode)
{
- struct device_node *cpunode;
unsigned int psize, ssize;
unsigned long max_freq;
char *freq_method, *volt_method;
@@ -405,20 +404,6 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
else
return -ENODEV;
- /* Get first CPU node */
- for (cpunode = NULL;
- (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
- const u32 *reg = of_get_property(cpunode, "reg", NULL);
- if (reg == NULL || (*reg) != 0)
- continue;
- if (!strcmp(cpunode->type, "cpu"))
- break;
- }
- if (cpunode == NULL) {
- printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n");
- return -ENODEV;
- }
-
/* Check 970FX for now */
valp = of_get_property(cpunode, "cpu-version", NULL);
if (!valp) {
@@ -447,9 +432,8 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
if (!shdr)
goto bail_noprops;
g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
- ssize = (shdr->len * sizeof(u32)) -
- sizeof(struct smu_sdbp_header);
- g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
+ ssize = (shdr->len * sizeof(u32)) - sizeof(*shdr);
+ g5_fvt_count = ssize / sizeof(*g5_fvt_table);
g5_fvt_cur = 0;
/* Sanity checking */
@@ -537,9 +521,9 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
#endif /* CONFIG_PMAC_SMU */
-static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
+static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
{
- struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
+ struct device_node *cpuid = NULL, *hwclock = NULL;
const u8 *eeprom = NULL;
const u32 *valp;
u64 max_freq, min_freq, ih, il;
@@ -548,17 +532,6 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
DBG("cpufreq: Initializing for PowerMac7,2, PowerMac7,3 and"
" RackMac3,1...\n");
- /* Get first CPU node */
- for (cpunode = NULL;
- (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
- if (!strcmp(cpunode->type, "cpu"))
- break;
- }
- if (cpunode == NULL) {
- printk(KERN_ERR "cpufreq: Can't find any CPU node\n");
- return -ENODEV;
- }
-
/* Lookup the cpuid eeprom node */
cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
if (cpuid != NULL)
@@ -718,25 +691,25 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
static int __init g5_cpufreq_init(void)
{
- struct device_node *cpus;
+ struct device_node *cpunode;
int rc = 0;
- cpus = of_find_node_by_path("/cpus");
- if (cpus == NULL) {
- DBG("No /cpus node !\n");
+ /* Get first CPU node */
+ cpunode = of_cpu_device_node_get(0);
+ if (cpunode == NULL) {
+ pr_err("cpufreq: Can't find any CPU node\n");
return -ENODEV;
}
if (of_machine_is_compatible("PowerMac7,2") ||
of_machine_is_compatible("PowerMac7,3") ||
of_machine_is_compatible("RackMac3,1"))
- rc = g5_pm72_cpufreq_init(cpus);
+ rc = g5_pm72_cpufreq_init(cpunode);
#ifdef CONFIG_PMAC_SMU
else
- rc = g5_neo2_cpufreq_init(cpus);
+ rc = g5_neo2_cpufreq_init(cpunode);
#endif /* CONFIG_PMAC_SMU */
- of_node_put(cpus);
return rc;
}
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index ea8e10382ec..85f1c8c25dd 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -207,7 +207,6 @@ static struct cpufreq_driver powernow_k6_driver = {
.exit = powernow_k6_cpu_exit,
.get = powernow_k6_get,
.name = "powernow-k6",
- .owner = THIS_MODULE,
.attr = powernow_k6_attr,
};
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index 95587087793..14ce480be8a 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -177,7 +177,7 @@ static int get_ranges(unsigned char *pst)
unsigned int speed;
u8 fid, vid;
- powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) *
+ powernow_table = kzalloc((sizeof(*powernow_table) *
(number_scales + 1)), GFP_KERNEL);
if (!powernow_table)
return -ENOMEM;
@@ -309,8 +309,7 @@ static int powernow_acpi_init(void)
goto err0;
}
- acpi_processor_perf = kzalloc(sizeof(struct acpi_processor_performance),
- GFP_KERNEL);
+ acpi_processor_perf = kzalloc(sizeof(*acpi_processor_perf), GFP_KERNEL);
if (!acpi_processor_perf) {
retval = -ENOMEM;
goto err0;
@@ -346,7 +345,7 @@ static int powernow_acpi_init(void)
goto err2;
}
- powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) *
+ powernow_table = kzalloc((sizeof(*powernow_table) *
(number_scales + 1)), GFP_KERNEL);
if (!powernow_table) {
retval = -ENOMEM;
@@ -497,7 +496,7 @@ static int powernow_decode_bios(int maxfid, int startvid)
"relevant to this CPU).\n",
psb->numpst);
- p += sizeof(struct psb_s);
+ p += sizeof(*psb);
pst = (struct pst_s *) p;
@@ -510,12 +509,12 @@ static int powernow_decode_bios(int maxfid, int startvid)
(maxfid == pst->maxfid) &&
(startvid == pst->startvid)) {
print_pst_entry(pst, j);
- p = (char *)pst + sizeof(struct pst_s);
+ p = (char *)pst + sizeof(*pst);
ret = get_ranges(p);
return ret;
} else {
unsigned int k;
- p = (char *)pst + sizeof(struct pst_s);
+ p = (char *)pst + sizeof(*pst);
for (k = 0; k < number_scales; k++)
p += 2;
}
@@ -717,7 +716,6 @@ static struct cpufreq_driver powernow_driver = {
.init = powernow_cpu_init,
.exit = powernow_cpu_exit,
.name = "powernow-k7",
- .owner = THIS_MODULE,
.attr = powernow_table_attr,
};
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index c39d189217c..2344a9ed17f 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -623,7 +623,7 @@ static int fill_powernow_table(struct powernow_k8_data *data,
if (check_pst_table(data, pst, maxvid))
return -EINVAL;
- powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
+ powernow_table = kmalloc((sizeof(*powernow_table)
* (data->numps + 1)), GFP_KERNEL);
if (!powernow_table) {
printk(KERN_ERR PFX "powernow_table memory alloc failure\n");
@@ -793,7 +793,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
}
/* fill in data->powernow_table */
- powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
+ powernow_table = kmalloc((sizeof(*powernow_table)
* (data->acpi_data.state_count + 1)), GFP_KERNEL);
if (!powernow_table) {
pr_debug("powernow_table memory alloc failure\n");
@@ -1106,7 +1106,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
if (rc)
return -ENODEV;
- data = kzalloc(sizeof(struct powernow_k8_data), GFP_KERNEL);
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
printk(KERN_ERR PFX "unable to alloc powernow_k8_data");
return -ENOMEM;
@@ -1240,7 +1240,6 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
.exit = powernowk8_cpu_exit,
.get = powernowk8_get,
.name = "powernow-k8",
- .owner = THIS_MODULE,
.attr = powernow_k8_attr,
};
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
index 3cae4529f95..60e81d524ea 100644
--- a/drivers/cpufreq/ppc-corenet-cpufreq.c
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -300,7 +300,6 @@ static struct freq_attr *corenet_cpufreq_attr[] = {
static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
.name = "ppc_cpufreq",
- .owner = THIS_MODULE,
.flags = CPUFREQ_CONST_LOOPS,
.init = corenet_cpufreq_cpu_init,
.exit = __exit_p(corenet_cpufreq_cpu_exit),
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c
index 5936f8d6f2c..2e448f0bbdc 100644
--- a/drivers/cpufreq/ppc_cbe_cpufreq.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -181,7 +181,6 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
.init = cbe_cpufreq_cpu_init,
.exit = cbe_cpufreq_cpu_exit,
.name = "cbe-cpufreq",
- .owner = THIS_MODULE,
.flags = CPUFREQ_CONST_LOOPS,
};
diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c
index fb3981ac829..8749eaf1879 100644
--- a/drivers/cpufreq/pxa2xx-cpufreq.c
+++ b/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -191,7 +191,7 @@ static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq)
return ret;
}
-static __init void pxa_cpufreq_init_voltages(void)
+static void __init pxa_cpufreq_init_voltages(void)
{
vcc_core = regulator_get(NULL, "vcc_core");
if (IS_ERR(vcc_core)) {
@@ -207,7 +207,7 @@ static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq)
return 0;
}
-static __init void pxa_cpufreq_init_voltages(void) { }
+static void __init pxa_cpufreq_init_voltages(void) { }
#endif
static void find_freq_tables(struct cpufreq_frequency_table **freq_table,
diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c
index 9c92ef032a9..d26306fb00d 100644
--- a/drivers/cpufreq/pxa3xx-cpufreq.c
+++ b/drivers/cpufreq/pxa3xx-cpufreq.c
@@ -213,10 +213,12 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)
policy->cur = policy->min = policy->max;
if (cpu_is_pxa300() || cpu_is_pxa310())
- ret = setup_freqs_table(policy, ARRAY_AND_SIZE(pxa300_freqs));
+ ret = setup_freqs_table(policy, pxa300_freqs,
+ ARRAY_SIZE(pxa300_freqs));
if (cpu_is_pxa320())
- ret = setup_freqs_table(policy, ARRAY_AND_SIZE(pxa320_freqs));
+ ret = setup_freqs_table(policy, pxa320_freqs,
+ ARRAY_SIZE(pxa320_freqs));
if (ret) {
pr_err("failed to setup frequency table\n");
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c
index ce5b9fca9c1..22dcb81ef9d 100644
--- a/drivers/cpufreq/s3c2416-cpufreq.c
+++ b/drivers/cpufreq/s3c2416-cpufreq.c
@@ -524,7 +524,6 @@ static struct freq_attr *s3c2416_cpufreq_attr[] = {
};
static struct cpufreq_driver s3c2416_cpufreq_driver = {
- .owner = THIS_MODULE,
.flags = 0,
.verify = s3c2416_cpufreq_verify_speed,
.target = s3c2416_cpufreq_set_target,
diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c
index 87781eb20d6..b0f343fcb7e 100644
--- a/drivers/cpufreq/s3c24xx-cpufreq.c
+++ b/drivers/cpufreq/s3c24xx-cpufreq.c
@@ -392,7 +392,7 @@ static int s3c_cpufreq_init(struct cpufreq_policy *policy)
return 0;
}
-static __init int s3c_cpufreq_initclks(void)
+static int __init s3c_cpufreq_initclks(void)
{
_clk_mpll = s3c_cpufreq_clk_get(NULL, "mpll");
_clk_xtal = s3c_cpufreq_clk_get(NULL, "xtal");
@@ -522,7 +522,7 @@ int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
/* Copy the board information so that each board can make this
* initdata. */
- ours = kzalloc(sizeof(struct s3c_cpufreq_board), GFP_KERNEL);
+ ours = kzalloc(sizeof(*ours), GFP_KERNEL);
if (ours == NULL) {
printk(KERN_ERR "%s: no memory\n", __func__);
return -ENOMEM;
@@ -615,7 +615,7 @@ static int s3c_cpufreq_build_freq(void)
size = cpu_cur.info->calc_freqtable(&cpu_cur, NULL, 0);
size++;
- ftab = kmalloc(sizeof(struct cpufreq_frequency_table) * size, GFP_KERNEL);
+ ftab = kmalloc(sizeof(*ftab) * size, GFP_KERNEL);
if (!ftab) {
printk(KERN_ERR "%s: no memory for tables\n", __func__);
return -ENOMEM;
@@ -691,7 +691,7 @@ int __init s3c_plltab_register(struct cpufreq_frequency_table *plls,
struct cpufreq_frequency_table *vals;
unsigned int size;
- size = sizeof(struct cpufreq_frequency_table) * (plls_no + 1);
+ size = sizeof(*vals) * (plls_no + 1);
vals = kmalloc(size, GFP_KERNEL);
if (vals) {
diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index 13bb4bae64e..8a72b0c555f 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -263,7 +263,6 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
}
static struct cpufreq_driver s3c64xx_cpufreq_driver = {
- .owner = THIS_MODULE,
.flags = 0,
.verify = s3c64xx_cpufreq_verify_speed,
.target = s3c64xx_cpufreq_set_target,
diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c
index 77a210975fc..d6f6c6f4efa 100644
--- a/drivers/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -147,7 +147,6 @@ static struct cpufreq_driver sc520_freq_driver = {
.init = sc520_freq_cpu_init,
.exit = sc520_freq_cpu_exit,
.name = "sc520_freq",
- .owner = THIS_MODULE,
.attr = sc520_freq_attr,
};
diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c
index 73adb64651e..ffc6d24b0cf 100644
--- a/drivers/cpufreq/sh-cpufreq.c
+++ b/drivers/cpufreq/sh-cpufreq.c
@@ -160,7 +160,6 @@ static struct freq_attr *sh_freq_attr[] = {
};
static struct cpufreq_driver sh_cpufreq_driver = {
- .owner = THIS_MODULE,
.name = "sh",
.get = sh_cpufreq_get,
.target = sh_cpufreq_target,
diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c
index 93061a40877..cf5bc2ca16f 100644
--- a/drivers/cpufreq/sparc-us2e-cpufreq.c
+++ b/drivers/cpufreq/sparc-us2e-cpufreq.c
@@ -351,12 +351,11 @@ static int __init us2e_freq_init(void)
struct cpufreq_driver *driver;
ret = -ENOMEM;
- driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL);
+ driver = kzalloc(sizeof(*driver), GFP_KERNEL);
if (!driver)
goto err_out;
- us2e_freq_table = kzalloc(
- (NR_CPUS * sizeof(struct us2e_freq_percpu_info)),
+ us2e_freq_table = kzalloc((NR_CPUS * sizeof(*us2e_freq_table)),
GFP_KERNEL);
if (!us2e_freq_table)
goto err_out;
@@ -366,7 +365,6 @@ static int __init us2e_freq_init(void)
driver->target = us2e_freq_target;
driver->get = us2e_freq_get;
driver->exit = us2e_freq_cpu_exit;
- driver->owner = THIS_MODULE,
strcpy(driver->name, "UltraSPARC-IIe");
cpufreq_us2e_driver = driver;
diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c
index 880ee293d61..ac76b489979 100644
--- a/drivers/cpufreq/sparc-us3-cpufreq.c
+++ b/drivers/cpufreq/sparc-us3-cpufreq.c
@@ -212,12 +212,11 @@ static int __init us3_freq_init(void)
struct cpufreq_driver *driver;
ret = -ENOMEM;
- driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL);
+ driver = kzalloc(sizeof(*driver), GFP_KERNEL);
if (!driver)
goto err_out;
- us3_freq_table = kzalloc(
- (NR_CPUS * sizeof(struct us3_freq_percpu_info)),
+ us3_freq_table = kzalloc((NR_CPUS * sizeof(*us3_freq_table)),
GFP_KERNEL);
if (!us3_freq_table)
goto err_out;
@@ -227,7 +226,6 @@ static int __init us3_freq_init(void)
driver->target = us3_freq_target;
driver->get = us3_freq_get;
driver->exit = us3_freq_cpu_exit;
- driver->owner = THIS_MODULE,
strcpy(driver->name, "UltraSPARC-III");
cpufreq_us3_driver = driver;
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index c3efa7f2a90..19e364fa595 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -18,7 +18,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -223,7 +223,7 @@ static int spear_cpufreq_driver_init(void)
const __be32 *val;
int cnt, i, ret;
- np = of_find_node_by_path("/cpus/cpu@0");
+ np = of_cpu_device_node_get(0);
if (!np) {
pr_err("No cpu node found");
return -ENODEV;
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 0915e712fbd..f897d510584 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -575,7 +575,6 @@ static struct cpufreq_driver centrino_driver = {
.target = centrino_target,
.get = get_cur_freq,
.attr = centrino_attr,
- .owner = THIS_MODULE,
};
/*
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c
index e2e5aa97145..5355abb69af 100644
--- a/drivers/cpufreq/speedstep-ich.c
+++ b/drivers/cpufreq/speedstep-ich.c
@@ -378,7 +378,6 @@ static struct cpufreq_driver speedstep_driver = {
.init = speedstep_cpu_init,
.exit = speedstep_cpu_exit,
.get = speedstep_get,
- .owner = THIS_MODULE,
.attr = speedstep_attr,
};
diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c
index f5a6b70ee6c..abfba4f731e 100644
--- a/drivers/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -375,7 +375,6 @@ static struct cpufreq_driver speedstep_driver = {
.exit = speedstep_cpu_exit,
.get = speedstep_get,
.resume = speedstep_resume,
- .owner = THIS_MODULE,
.attr = speedstep_attr,
};
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c
index cd66b85d927..a7b876fdc1d 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -255,7 +255,7 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
static int __init tegra_cpufreq_init(void)
{
- cpu_clk = clk_get_sys(NULL, "cpu");
+ cpu_clk = clk_get_sys(NULL, "cclk");
if (IS_ERR(cpu_clk))
return PTR_ERR(cpu_clk);
@@ -263,7 +263,7 @@ static int __init tegra_cpufreq_init(void)
if (IS_ERR(pll_x_clk))
return PTR_ERR(pll_x_clk);
- pll_p_clk = clk_get_sys(NULL, "pll_p_cclk");
+ pll_p_clk = clk_get_sys(NULL, "pll_p");
if (IS_ERR(pll_p_clk))
return PTR_ERR(pll_p_clk);
diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c
index 12fc904d7da..b225f04d8ae 100644
--- a/drivers/cpufreq/unicore2-cpufreq.c
+++ b/drivers/cpufreq/unicore2-cpufreq.c
@@ -24,7 +24,7 @@ static struct cpufreq_driver ucv2_driver;
/* make sure that only the "userspace" governor is run
* -- anything else wouldn't make sense on this platform, anyway.
*/
-int ucv2_verify_speed(struct cpufreq_policy *policy)
+static int ucv2_verify_speed(struct cpufreq_policy *policy)
{
if (policy->cpu)
return -EINVAL;
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 0e2cd5cab4d..b3fb81d7cf0 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -1,5 +1,6 @@
+menu "CPU Idle"
-menuconfig CPU_IDLE
+config CPU_IDLE
bool "CPU idle PM support"
default y if ACPI || PPC_PSERIES
select CPU_IDLE_GOV_LADDER if (!NO_HZ && !NO_HZ_IDLE)
@@ -29,20 +30,13 @@ config CPU_IDLE_GOV_MENU
bool "Menu governor (for tickless system)"
default y
-config CPU_IDLE_CALXEDA
- bool "CPU Idle Driver for Calxeda processors"
- depends on ARCH_HIGHBANK
- select ARM_CPU_SUSPEND
- help
- Select this to enable cpuidle on Calxeda processors.
-
-config CPU_IDLE_ZYNQ
- bool "CPU Idle Driver for Xilinx Zynq processors"
- depends on ARCH_ZYNQ
- help
- Select this to enable cpuidle on Xilinx Zynq processors.
+menu "ARM CPU Idle Drivers"
+depends on ARM
+source "drivers/cpuidle/Kconfig.arm"
+endmenu
endif
config ARCH_NEEDS_CPU_IDLE_COUPLED
def_bool n
+endmenu
diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
new file mode 100644
index 00000000000..b3302193c15
--- /dev/null
+++ b/drivers/cpuidle/Kconfig.arm
@@ -0,0 +1,29 @@
+#
+# ARM CPU Idle drivers
+#
+
+config ARM_HIGHBANK_CPUIDLE
+ bool "CPU Idle Driver for Calxeda processors"
+ depends on ARCH_HIGHBANK
+ select ARM_CPU_SUSPEND
+ help
+ Select this to enable cpuidle on Calxeda processors.
+
+config ARM_KIRKWOOD_CPUIDLE
+ bool "CPU Idle Driver for Marvell Kirkwood SoCs"
+ depends on ARCH_KIRKWOOD
+ help
+ This adds the CPU Idle driver for Marvell Kirkwood SoCs.
+
+config ARM_ZYNQ_CPUIDLE
+ bool "CPU Idle Driver for Xilinx Zynq processors"
+ depends on ARCH_ZYNQ
+ help
+ Select this to enable cpuidle on Xilinx Zynq processors.
+
+config ARM_U8500_CPUIDLE
+ bool "Cpu Idle Driver for the ST-E u8500 processors"
+ depends on ARCH_U8500
+ help
+ Select this to enable cpuidle for ST-E u8500 processors
+
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 8767a7b3eb9..0b9d200c7e4 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -5,6 +5,9 @@
obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
-obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
-obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
-obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o
+##################################################################################
+# ARM SoC drivers
+obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE) += cpuidle-calxeda.o
+obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o
+obj-$(CONFIG_ARM_ZYNQ_CPUIDLE) += cpuidle-zynq.o
+obj-$(CONFIG_ARM_U8500_CPUIDLE) += cpuidle-ux500.o
diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c
index 2a297f86dba..f8a86364c6b 100644
--- a/drivers/cpuidle/coupled.c
+++ b/drivers/cpuidle/coupled.c
@@ -106,6 +106,7 @@ struct cpuidle_coupled {
cpumask_t coupled_cpus;
int requested_state[NR_CPUS];
atomic_t ready_waiting_counts;
+ atomic_t abort_barrier;
int online_count;
int refcnt;
int prevent;
@@ -122,12 +123,19 @@ static DEFINE_MUTEX(cpuidle_coupled_lock);
static DEFINE_PER_CPU(struct call_single_data, cpuidle_coupled_poke_cb);
/*
- * The cpuidle_coupled_poked_mask mask is used to avoid calling
+ * The cpuidle_coupled_poke_pending mask is used to avoid calling
* __smp_call_function_single with the per cpu call_single_data struct already
* in use. This prevents a deadlock where two cpus are waiting for each others
* call_single_data struct to be available
*/
-static cpumask_t cpuidle_coupled_poked_mask;
+static cpumask_t cpuidle_coupled_poke_pending;
+
+/*
+ * The cpuidle_coupled_poked mask is used to ensure that each cpu has been poked
+ * once to minimize entering the ready loop with a poke pending, which would
+ * require aborting and retrying.
+ */
+static cpumask_t cpuidle_coupled_poked;
/**
* cpuidle_coupled_parallel_barrier - synchronize all online coupled cpus
@@ -291,10 +299,11 @@ static inline int cpuidle_coupled_get_state(struct cpuidle_device *dev,
return state;
}
-static void cpuidle_coupled_poked(void *info)
+static void cpuidle_coupled_handle_poke(void *info)
{
int cpu = (unsigned long)info;
- cpumask_clear_cpu(cpu, &cpuidle_coupled_poked_mask);
+ cpumask_set_cpu(cpu, &cpuidle_coupled_poked);
+ cpumask_clear_cpu(cpu, &cpuidle_coupled_poke_pending);
}
/**
@@ -313,7 +322,7 @@ static void cpuidle_coupled_poke(int cpu)
{
struct call_single_data *csd = &per_cpu(cpuidle_coupled_poke_cb, cpu);
- if (!cpumask_test_and_set_cpu(cpu, &cpuidle_coupled_poked_mask))
+ if (!cpumask_test_and_set_cpu(cpu, &cpuidle_coupled_poke_pending))
__smp_call_function_single(cpu, csd, 0);
}
@@ -340,30 +349,19 @@ static void cpuidle_coupled_poke_others(int this_cpu,
* @coupled: the struct coupled that contains the current cpu
* @next_state: the index in drv->states of the requested state for this cpu
*
- * Updates the requested idle state for the specified cpuidle device,
- * poking all coupled cpus out of idle if necessary to let them see the new
- * state.
+ * Updates the requested idle state for the specified cpuidle device.
+ * Returns the number of waiting cpus.
*/
-static void cpuidle_coupled_set_waiting(int cpu,
+static int cpuidle_coupled_set_waiting(int cpu,
struct cpuidle_coupled *coupled, int next_state)
{
- int w;
-
coupled->requested_state[cpu] = next_state;
/*
- * If this is the last cpu to enter the waiting state, poke
- * all the other cpus out of their waiting state so they can
- * enter a deeper state. This can race with one of the cpus
- * exiting the waiting state due to an interrupt and
- * decrementing waiting_count, see comment below.
- *
* The atomic_inc_return provides a write barrier to order the write
* to requested_state with the later write that increments ready_count.
*/
- w = atomic_inc_return(&coupled->ready_waiting_counts) & WAITING_MASK;
- if (w == coupled->online_count)
- cpuidle_coupled_poke_others(cpu, coupled);
+ return atomic_inc_return(&coupled->ready_waiting_counts) & WAITING_MASK;
}
/**
@@ -410,19 +408,33 @@ static void cpuidle_coupled_set_done(int cpu, struct cpuidle_coupled *coupled)
* been processed and the poke bit has been cleared.
*
* Other interrupts may also be processed while interrupts are enabled, so
- * need_resched() must be tested after turning interrupts off again to make sure
+ * need_resched() must be tested after this function returns to make sure
* the interrupt didn't schedule work that should take the cpu out of idle.
*
- * Returns 0 if need_resched was false, -EINTR if need_resched was true.
+ * Returns 0 if no poke was pending, 1 if a poke was cleared.
*/
static int cpuidle_coupled_clear_pokes(int cpu)
{
+ if (!cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending))
+ return 0;
+
local_irq_enable();
- while (cpumask_test_cpu(cpu, &cpuidle_coupled_poked_mask))
+ while (cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending))
cpu_relax();
local_irq_disable();
- return need_resched() ? -EINTR : 0;
+ return 1;
+}
+
+static bool cpuidle_coupled_any_pokes_pending(struct cpuidle_coupled *coupled)
+{
+ cpumask_t cpus;
+ int ret;
+
+ cpumask_and(&cpus, cpu_online_mask, &coupled->coupled_cpus);
+ ret = cpumask_and(&cpus, &cpuidle_coupled_poke_pending, &cpus);
+
+ return ret;
}
/**
@@ -449,31 +461,56 @@ int cpuidle_enter_state_coupled(struct cpuidle_device *dev,
{
int entered_state = -1;
struct cpuidle_coupled *coupled = dev->coupled;
+ int w;
if (!coupled)
return -EINVAL;
while (coupled->prevent) {
- if (cpuidle_coupled_clear_pokes(dev->cpu)) {
+ cpuidle_coupled_clear_pokes(dev->cpu);
+ if (need_resched()) {
local_irq_enable();
return entered_state;
}
entered_state = cpuidle_enter_state(dev, drv,
dev->safe_state_index);
+ local_irq_disable();
}
/* Read barrier ensures online_count is read after prevent is cleared */
smp_rmb();
- cpuidle_coupled_set_waiting(dev->cpu, coupled, next_state);
+reset:
+ cpumask_clear_cpu(dev->cpu, &cpuidle_coupled_poked);
+
+ w = cpuidle_coupled_set_waiting(dev->cpu, coupled, next_state);
+ /*
+ * If this is the last cpu to enter the waiting state, poke
+ * all the other cpus out of their waiting state so they can
+ * enter a deeper state. This can race with one of the cpus
+ * exiting the waiting state due to an interrupt and
+ * decrementing waiting_count, see comment below.
+ */
+ if (w == coupled->online_count) {
+ cpumask_set_cpu(dev->cpu, &cpuidle_coupled_poked);
+ cpuidle_coupled_poke_others(dev->cpu, coupled);
+ }
retry:
/*
* Wait for all coupled cpus to be idle, using the deepest state
- * allowed for a single cpu.
+ * allowed for a single cpu. If this was not the poking cpu, wait
+ * for at least one poke before leaving to avoid a race where
+ * two cpus could arrive at the waiting loop at the same time,
+ * but the first of the two to arrive could skip the loop without
+ * processing the pokes from the last to arrive.
*/
- while (!cpuidle_coupled_cpus_waiting(coupled)) {
- if (cpuidle_coupled_clear_pokes(dev->cpu)) {
+ while (!cpuidle_coupled_cpus_waiting(coupled) ||
+ !cpumask_test_cpu(dev->cpu, &cpuidle_coupled_poked)) {
+ if (cpuidle_coupled_clear_pokes(dev->cpu))
+ continue;
+
+ if (need_resched()) {
cpuidle_coupled_set_not_waiting(dev->cpu, coupled);
goto out;
}
@@ -485,14 +522,22 @@ retry:
entered_state = cpuidle_enter_state(dev, drv,
dev->safe_state_index);
+ local_irq_disable();
}
- if (cpuidle_coupled_clear_pokes(dev->cpu)) {
+ cpuidle_coupled_clear_pokes(dev->cpu);
+ if (need_resched()) {
cpuidle_coupled_set_not_waiting(dev->cpu, coupled);
goto out;
}
/*
+ * Make sure final poke status for this cpu is visible before setting
+ * cpu as ready.
+ */
+ smp_wmb();
+
+ /*
* All coupled cpus are probably idle. There is a small chance that
* one of the other cpus just became active. Increment the ready count,
* and spin until all coupled cpus have incremented the counter. Once a
@@ -511,6 +556,28 @@ retry:
cpu_relax();
}
+ /*
+ * Make sure read of all cpus ready is done before reading pending pokes
+ */
+ smp_rmb();
+
+ /*
+ * There is a small chance that a cpu left and reentered idle after this
+ * cpu saw that all cpus were waiting. The cpu that reentered idle will
+ * have sent this cpu a poke, which will still be pending after the
+ * ready loop. The pending interrupt may be lost by the interrupt
+ * controller when entering the deep idle state. It's not possible to
+ * clear a pending interrupt without turning interrupts on and handling
+ * it, and it's too late to turn on interrupts here, so reset the
+ * coupled idle state of all cpus and retry.
+ */
+ if (cpuidle_coupled_any_pokes_pending(coupled)) {
+ cpuidle_coupled_set_done(dev->cpu, coupled);
+ /* Wait for all cpus to see the pending pokes */
+ cpuidle_coupled_parallel_barrier(dev, &coupled->abort_barrier);
+ goto reset;
+ }
+
/* all cpus have acked the coupled state */
next_state = cpuidle_coupled_get_state(dev, coupled);
@@ -596,7 +663,7 @@ have_coupled:
coupled->refcnt++;
csd = &per_cpu(cpuidle_coupled_poke_cb, dev->cpu);
- csd->func = cpuidle_coupled_poked;
+ csd->func = cpuidle_coupled_handle_poke;
csd->info = (void *)(unsigned long)dev->cpu;
return 0;
diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c
index 0e6e408c0a6..34605847957 100644
--- a/drivers/cpuidle/cpuidle-calxeda.c
+++ b/drivers/cpuidle/cpuidle-calxeda.c
@@ -35,7 +35,7 @@
#include <asm/cp15.h>
extern void highbank_set_cpu_jump(int cpu, void *jump_addr);
-extern void *scu_base_addr;
+extern void __iomem *scu_base_addr;
static noinline void calxeda_idle_restore(void)
{
diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c
index 521b0a7fdd8..41ba843251b 100644
--- a/drivers/cpuidle/cpuidle-kirkwood.c
+++ b/drivers/cpuidle/cpuidle-kirkwood.c
@@ -60,9 +60,6 @@ static int kirkwood_cpuidle_probe(struct platform_device *pdev)
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL)
- return -EINVAL;
-
ddr_operation_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(ddr_operation_base))
return PTR_ERR(ddr_operation_base);
@@ -70,7 +67,7 @@ static int kirkwood_cpuidle_probe(struct platform_device *pdev)
return cpuidle_register(&kirkwood_idle_driver, NULL);
}
-int kirkwood_cpuidle_remove(struct platform_device *pdev)
+static int kirkwood_cpuidle_remove(struct platform_device *pdev)
{
cpuidle_unregister(&kirkwood_idle_driver);
return 0;
diff --git a/drivers/cpuidle/cpuidle-ux500.c b/drivers/cpuidle/cpuidle-ux500.c
new file mode 100644
index 00000000000..e0564652af3
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-ux500.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012 Linaro : Daniel Lezcano <daniel.lezcano@linaro.org> (IBM)
+ *
+ * Based on the work of Rickard Andersson <rickard.andersson@stericsson.com>
+ * and Jonas Aaberg <jonas.aberg@stericsson.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/cpuidle.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+#include <linux/smp.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_data/arm-ux500-pm.h>
+#include <linux/platform_device.h>
+
+#include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+
+static atomic_t master = ATOMIC_INIT(0);
+static DEFINE_SPINLOCK(master_lock);
+
+static inline int ux500_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ int this_cpu = smp_processor_id();
+ bool recouple = false;
+
+ if (atomic_inc_return(&master) == num_online_cpus()) {
+
+ /* With this lock, we prevent the other cpu to exit and enter
+ * this function again and become the master */
+ if (!spin_trylock(&master_lock))
+ goto wfi;
+
+ /* decouple the gic from the A9 cores */
+ if (prcmu_gic_decouple()) {
+ spin_unlock(&master_lock);
+ goto out;
+ }
+
+ /* If an error occur, we will have to recouple the gic
+ * manually */
+ recouple = true;
+
+ /* At this state, as the gic is decoupled, if the other
+ * cpu is in WFI, we have the guarantee it won't be wake
+ * up, so we can safely go to retention */
+ if (!prcmu_is_cpu_in_wfi(this_cpu ? 0 : 1))
+ goto out;
+
+ /* The prcmu will be in charge of watching the interrupts
+ * and wake up the cpus */
+ if (prcmu_copy_gic_settings())
+ goto out;
+
+ /* Check in the meantime an interrupt did
+ * not occur on the gic ... */
+ if (prcmu_gic_pending_irq())
+ goto out;
+
+ /* ... and the prcmu */
+ if (prcmu_pending_irq())
+ goto out;
+
+ /* Go to the retention state, the prcmu will wait for the
+ * cpu to go WFI and this is what happens after exiting this
+ * 'master' critical section */
+ if (prcmu_set_power_state(PRCMU_AP_IDLE, true, true))
+ goto out;
+
+ /* When we switch to retention, the prcmu is in charge
+ * of recoupling the gic automatically */
+ recouple = false;
+
+ spin_unlock(&master_lock);
+ }
+wfi:
+ cpu_do_idle();
+out:
+ atomic_dec(&master);
+
+ if (recouple) {
+ prcmu_gic_recouple();
+ spin_unlock(&master_lock);
+ }
+
+ return index;
+}
+
+static struct cpuidle_driver ux500_idle_driver = {
+ .name = "ux500_idle",
+ .owner = THIS_MODULE,
+ .states = {
+ ARM_CPUIDLE_WFI_STATE,
+ {
+ .enter = ux500_enter_idle,
+ .exit_latency = 70,
+ .target_residency = 260,
+ .flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_TIMER_STOP,
+ .name = "ApIdle",
+ .desc = "ARM Retention",
+ },
+ },
+ .safe_state_index = 0,
+ .state_count = 2,
+};
+
+static int __init dbx500_cpuidle_probe(struct platform_device *pdev)
+{
+ /* Configure wake up reasons */
+ prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
+ PRCMU_WAKEUP(ABB));
+
+ return cpuidle_register(&ux500_idle_driver, NULL);
+}
+
+static struct platform_driver dbx500_cpuidle_plat_driver = {
+ .driver = {
+ .name = "cpuidle-dbx500",
+ .owner = THIS_MODULE,
+ },
+ .probe = dbx500_cpuidle_probe,
+};
+
+module_platform_driver(dbx500_cpuidle_plat_driver);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index fdc432f1802..d75040ddd2b 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -42,8 +42,6 @@ void disable_cpuidle(void)
off = 1;
}
-static int __cpuidle_register_device(struct cpuidle_device *dev);
-
/**
* cpuidle_play_dead - cpu off-lining
*
@@ -278,7 +276,7 @@ static void poll_idle_init(struct cpuidle_driver *drv) {}
*/
int cpuidle_enable_device(struct cpuidle_device *dev)
{
- int ret, i;
+ int ret;
struct cpuidle_driver *drv;
if (!dev)
@@ -292,15 +290,12 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
if (!drv || !cpuidle_curr_governor)
return -EIO;
+ if (!dev->registered)
+ return -EINVAL;
+
if (!dev->state_count)
dev->state_count = drv->state_count;
- if (dev->registered == 0) {
- ret = __cpuidle_register_device(dev);
- if (ret)
- return ret;
- }
-
poll_idle_init(drv);
ret = cpuidle_add_device_sysfs(dev);
@@ -311,12 +306,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
(ret = cpuidle_curr_governor->enable(drv, dev)))
goto fail_sysfs;
- for (i = 0; i < dev->state_count; i++) {
- dev->states_usage[i].usage = 0;
- dev->states_usage[i].time = 0;
- }
- dev->last_residency = 0;
-
smp_wmb();
dev->enabled = 1;
@@ -360,6 +349,23 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
EXPORT_SYMBOL_GPL(cpuidle_disable_device);
+static void __cpuidle_unregister_device(struct cpuidle_device *dev)
+{
+ struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
+
+ list_del(&dev->device_list);
+ per_cpu(cpuidle_devices, dev->cpu) = NULL;
+ module_put(drv->owner);
+}
+
+static int __cpuidle_device_init(struct cpuidle_device *dev)
+{
+ memset(dev->states_usage, 0, sizeof(dev->states_usage));
+ dev->last_residency = 0;
+
+ return 0;
+}
+
/**
* __cpuidle_register_device - internal register function called before register
* and enable routines
@@ -377,24 +383,15 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
per_cpu(cpuidle_devices, dev->cpu) = dev;
list_add(&dev->device_list, &cpuidle_detected_devices);
- ret = cpuidle_add_sysfs(dev);
- if (ret)
- goto err_sysfs;
ret = cpuidle_coupled_register_device(dev);
- if (ret)
- goto err_coupled;
+ if (ret) {
+ __cpuidle_unregister_device(dev);
+ return ret;
+ }
dev->registered = 1;
return 0;
-
-err_coupled:
- cpuidle_remove_sysfs(dev);
-err_sysfs:
- list_del(&dev->device_list);
- per_cpu(cpuidle_devices, dev->cpu) = NULL;
- module_put(drv->owner);
- return ret;
}
/**
@@ -403,25 +400,44 @@ err_sysfs:
*/
int cpuidle_register_device(struct cpuidle_device *dev)
{
- int ret;
+ int ret = -EBUSY;
if (!dev)
return -EINVAL;
mutex_lock(&cpuidle_lock);
- if ((ret = __cpuidle_register_device(dev))) {
- mutex_unlock(&cpuidle_lock);
- return ret;
- }
+ if (dev->registered)
+ goto out_unlock;
+
+ ret = __cpuidle_device_init(dev);
+ if (ret)
+ goto out_unlock;
+
+ ret = __cpuidle_register_device(dev);
+ if (ret)
+ goto out_unlock;
+
+ ret = cpuidle_add_sysfs(dev);
+ if (ret)
+ goto out_unregister;
+
+ ret = cpuidle_enable_device(dev);
+ if (ret)
+ goto out_sysfs;
- cpuidle_enable_device(dev);
cpuidle_install_idle_handler();
+out_unlock:
mutex_unlock(&cpuidle_lock);
- return 0;
+ return ret;
+out_sysfs:
+ cpuidle_remove_sysfs(dev);
+out_unregister:
+ __cpuidle_unregister_device(dev);
+ goto out_unlock;
}
EXPORT_SYMBOL_GPL(cpuidle_register_device);
@@ -432,8 +448,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device);
*/
void cpuidle_unregister_device(struct cpuidle_device *dev)
{
- struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
-
if (dev->registered == 0)
return;
@@ -442,14 +456,12 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
cpuidle_disable_device(dev);
cpuidle_remove_sysfs(dev);
- list_del(&dev->device_list);
- per_cpu(cpuidle_devices, dev->cpu) = NULL;
+
+ __cpuidle_unregister_device(dev);
cpuidle_coupled_unregister_device(dev);
cpuidle_resume_and_unlock();
-
- module_put(drv->owner);
}
EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 9b784051ec1..9f08e8cce1a 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -192,14 +192,4 @@ static int __init init_ladder(void)
return cpuidle_register_governor(&ladder_governor);
}
-/**
- * exit_ladder - exits the governor
- */
-static void __exit exit_ladder(void)
-{
- cpuidle_unregister_governor(&ladder_governor);
-}
-
-MODULE_LICENSE("GPL");
-module_init(init_ladder);
-module_exit(exit_ladder);
+postcore_initcall(init_ladder);
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index fe343a06b7d..cf7f2f0e4ef 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -21,6 +21,15 @@
#include <linux/math64.h>
#include <linux/module.h>
+/*
+ * Please note when changing the tuning values:
+ * If (MAX_INTERESTING-1) * RESOLUTION > UINT_MAX, the result of
+ * a scaling operation multiplication may overflow on 32 bit platforms.
+ * In that case, #define RESOLUTION as ULL to get 64 bit result:
+ * #define RESOLUTION 1024ULL
+ *
+ * The default values do not overflow.
+ */
#define BUCKETS 12
#define INTERVALS 8
#define RESOLUTION 1024
@@ -28,13 +37,6 @@
#define MAX_INTERESTING 50000
#define STDDEV_THRESH 400
-/* 60 * 60 > STDDEV_THRESH * INTERVALS = 400 * 8 */
-#define MAX_DEVIATION 60
-
-static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer);
-static DEFINE_PER_CPU(int, hrtimer_status);
-/* menu hrtimer mode */
-enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL};
/*
* Concepts and ideas behind the menu governor
@@ -116,23 +118,16 @@ enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL};
*
*/
-/*
- * The C-state residency is so long that is is worthwhile to exit
- * from the shallow C-state and re-enter into a deeper C-state.
- */
-static unsigned int perfect_cstate_ms __read_mostly = 30;
-module_param(perfect_cstate_ms, uint, 0000);
-
struct menu_device {
int last_state_idx;
int needs_update;
unsigned int expected_us;
- u64 predicted_us;
+ unsigned int predicted_us;
unsigned int exit_us;
unsigned int bucket;
- u64 correction_factor[BUCKETS];
- u32 intervals[INTERVALS];
+ unsigned int correction_factor[BUCKETS];
+ unsigned int intervals[INTERVALS];
int interval_ptr;
};
@@ -205,59 +200,28 @@ static u64 div_round64(u64 dividend, u32 divisor)
return div_u64(dividend + (divisor / 2), divisor);
}
-/* Cancel the hrtimer if it is not triggered yet */
-void menu_hrtimer_cancel(void)
-{
- int cpu = smp_processor_id();
- struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
-
- /* The timer is still not time out*/
- if (per_cpu(hrtimer_status, cpu)) {
- hrtimer_cancel(hrtmr);
- per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
- }
-}
-EXPORT_SYMBOL_GPL(menu_hrtimer_cancel);
-
-/* Call back for hrtimer is triggered */
-static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer)
-{
- int cpu = smp_processor_id();
- struct menu_device *data = &per_cpu(menu_devices, cpu);
-
- /* In general case, the expected residency is much larger than
- * deepest C-state target residency, but prediction logic still
- * predicts a small predicted residency, so the prediction
- * history is totally broken if the timer is triggered.
- * So reset the correction factor.
- */
- if (per_cpu(hrtimer_status, cpu) == MENU_HRTIMER_GENERAL)
- data->correction_factor[data->bucket] = RESOLUTION * DECAY;
-
- per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
-
- return HRTIMER_NORESTART;
-}
-
/*
* Try detecting repeating patterns by keeping track of the last 8
* intervals, and checking if the standard deviation of that set
* of points is below a threshold. If it is... then use the
* average of these 8 points as the estimated value.
*/
-static u32 get_typical_interval(struct menu_device *data)
+static void get_typical_interval(struct menu_device *data)
{
- int i = 0, divisor = 0;
- uint64_t max = 0, avg = 0, stddev = 0;
- int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */
- unsigned int ret = 0;
+ int i, divisor;
+ unsigned int max, thresh;
+ uint64_t avg, stddev;
+
+ thresh = UINT_MAX; /* Discard outliers above this value */
again:
- /* first calculate average and standard deviation of the past */
- max = avg = divisor = stddev = 0;
+ /* First calculate the average of past intervals */
+ max = 0;
+ avg = 0;
+ divisor = 0;
for (i = 0; i < INTERVALS; i++) {
- int64_t value = data->intervals[i];
+ unsigned int value = data->intervals[i];
if (value <= thresh) {
avg += value;
divisor++;
@@ -267,15 +231,38 @@ again:
}
do_div(avg, divisor);
+ /* Then try to determine standard deviation */
+ stddev = 0;
for (i = 0; i < INTERVALS; i++) {
- int64_t value = data->intervals[i];
+ unsigned int value = data->intervals[i];
if (value <= thresh) {
int64_t diff = value - avg;
stddev += diff * diff;
}
}
do_div(stddev, divisor);
- stddev = int_sqrt(stddev);
+ /*
+ * The typical interval is obtained when standard deviation is small
+ * or standard deviation is small compared to the average interval.
+ *
+ * int_sqrt() formal parameter type is unsigned long. When the
+ * greatest difference to an outlier exceeds ~65 ms * sqrt(divisor)
+ * the resulting squared standard deviation exceeds the input domain
+ * of int_sqrt on platforms where unsigned long is 32 bits in size.
+ * In such case reject the candidate average.
+ *
+ * Use this result only if there is no timer to wake us up sooner.
+ */
+ if (likely(stddev <= ULONG_MAX)) {
+ stddev = int_sqrt(stddev);
+ if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
+ || stddev <= 20) {
+ if (data->expected_us > avg)
+ data->predicted_us = avg;
+ return;
+ }
+ }
+
/*
* If we have outliers to the upside in our distribution, discard
* those by setting the threshold to exclude these outliers, then
@@ -284,23 +271,12 @@ again:
*
* This can deal with workloads that have long pauses interspersed
* with sporadic activity with a bunch of short pauses.
- *
- * The typical interval is obtained when standard deviation is small
- * or standard deviation is small compared to the average interval.
*/
- if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
- || stddev <= 20) {
- data->predicted_us = avg;
- ret = 1;
- return ret;
-
- } else if ((divisor * 4) > INTERVALS * 3) {
- /* Exclude the max interval */
- thresh = max - 1;
- goto again;
- }
+ if ((divisor * 4) <= INTERVALS * 3)
+ return;
- return ret;
+ thresh = max - 1;
+ goto again;
}
/**
@@ -315,9 +291,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
int i;
int multiplier;
struct timespec t;
- int repeat = 0, low_predicted = 0;
- int cpu = smp_processor_id();
- struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
if (data->needs_update) {
menu_update(drv, dev);
@@ -348,11 +321,16 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
if (data->correction_factor[data->bucket] == 0)
data->correction_factor[data->bucket] = RESOLUTION * DECAY;
- /* Make sure to round up for half microseconds */
- data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
+ /*
+ * Force the result of multiplication to be 64 bits even if both
+ * operands are 32 bits.
+ * Make sure to round up for half microseconds.
+ */
+ data->predicted_us = div_round64((uint64_t)data->expected_us *
+ data->correction_factor[data->bucket],
RESOLUTION * DECAY);
- repeat = get_typical_interval(data);
+ get_typical_interval(data);
/*
* We want to default to C1 (hlt), not to busy polling
@@ -373,10 +351,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
if (s->disabled || su->disable)
continue;
- if (s->target_residency > data->predicted_us) {
- low_predicted = 1;
+ if (s->target_residency > data->predicted_us)
continue;
- }
if (s->exit_latency > latency_req)
continue;
if (s->exit_latency * multiplier > data->predicted_us)
@@ -386,44 +362,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
data->exit_us = s->exit_latency;
}
- /* not deepest C-state chosen for low predicted residency */
- if (low_predicted) {
- unsigned int timer_us = 0;
- unsigned int perfect_us = 0;
-
- /*
- * Set a timer to detect whether this sleep is much
- * longer than repeat mode predicted. If the timer
- * triggers, the code will evaluate whether to put
- * the CPU into a deeper C-state.
- * The timer is cancelled on CPU wakeup.
- */
- timer_us = 2 * (data->predicted_us + MAX_DEVIATION);
-
- perfect_us = perfect_cstate_ms * 1000;
-
- if (repeat && (4 * timer_us < data->expected_us)) {
- RCU_NONIDLE(hrtimer_start(hrtmr,
- ns_to_ktime(1000 * timer_us),
- HRTIMER_MODE_REL_PINNED));
- /* In repeat case, menu hrtimer is started */
- per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT;
- } else if (perfect_us < data->expected_us) {
- /*
- * The next timer is long. This could be because
- * we did not make a useful prediction.
- * In that case, it makes sense to re-enter
- * into a deeper C-state after some time.
- */
- RCU_NONIDLE(hrtimer_start(hrtmr,
- ns_to_ktime(1000 * timer_us),
- HRTIMER_MODE_REL_PINNED));
- /* In general case, menu hrtimer is started */
- per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_GENERAL;
- }
-
- }
-
return data->last_state_idx;
}
@@ -455,7 +393,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
unsigned int last_idle_us = cpuidle_get_last_residency(dev);
struct cpuidle_state *target = &drv->states[last_idx];
unsigned int measured_us;
- u64 new_factor;
+ unsigned int new_factor;
/*
* Ugh, this idle state doesn't support residency measurements, so we
@@ -476,10 +414,9 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
measured_us -= data->exit_us;
- /* update our correction ratio */
-
- new_factor = data->correction_factor[data->bucket]
- * (DECAY - 1) / DECAY;
+ /* Update our correction ratio */
+ new_factor = data->correction_factor[data->bucket];
+ new_factor -= new_factor / DECAY;
if (data->expected_us > 0 && measured_us < MAX_INTERESTING)
new_factor += RESOLUTION * measured_us / data->expected_us;
@@ -492,9 +429,11 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
/*
* We don't want 0 as factor; we always want at least
- * a tiny bit of estimated time.
+ * a tiny bit of estimated time. Fortunately, due to rounding,
+ * new_factor will stay nonzero regardless of measured_us values
+ * and the compiler can eliminate this test as long as DECAY > 1.
*/
- if (new_factor == 0)
+ if (DECAY == 1 && unlikely(new_factor == 0))
new_factor = 1;
data->correction_factor[data->bucket] = new_factor;
@@ -514,9 +453,6 @@ static int menu_enable_device(struct cpuidle_driver *drv,
struct cpuidle_device *dev)
{
struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
- struct hrtimer *t = &per_cpu(menu_hrtimer, dev->cpu);
- hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- t->function = menu_hrtimer_notify;
memset(data, 0, sizeof(struct menu_device));
@@ -540,14 +476,4 @@ static int __init init_menu(void)
return cpuidle_register_governor(&menu_governor);
}
-/**
- * exit_menu - exits the governor
- */
-static void __exit exit_menu(void)
-{
- cpuidle_unregister_governor(&menu_governor);
-}
-
-MODULE_LICENSE("GPL");
-module_init(init_menu);
-module_exit(exit_menu);
+postcore_initcall(init_menu);
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 428754af623..8739cc05228 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -11,8 +11,10 @@
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/cpu.h>
+#include <linux/completion.h>
#include <linux/capability.h>
#include <linux/device.h>
+#include <linux/kobject.h>
#include "cpuidle.h"
@@ -33,7 +35,8 @@ static ssize_t show_available_governors(struct device *dev,
mutex_lock(&cpuidle_lock);
list_for_each_entry(tmp, &cpuidle_governors, governor_list) {
- if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - CPUIDLE_NAME_LEN - 2))
+ if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) -
+ CPUIDLE_NAME_LEN - 2))
goto out;
i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name);
}
@@ -166,13 +169,28 @@ struct cpuidle_attr {
#define define_one_rw(_name, show, store) \
static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store)
-#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj)
#define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
-static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf)
+
+struct cpuidle_device_kobj {
+ struct cpuidle_device *dev;
+ struct completion kobj_unregister;
+ struct kobject kobj;
+};
+
+static inline struct cpuidle_device *to_cpuidle_device(struct kobject *kobj)
+{
+ struct cpuidle_device_kobj *kdev =
+ container_of(kobj, struct cpuidle_device_kobj, kobj);
+
+ return kdev->dev;
+}
+
+static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
{
int ret = -EIO;
- struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
- struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
+ struct cpuidle_device *dev = to_cpuidle_device(kobj);
+ struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);
if (cattr->show) {
mutex_lock(&cpuidle_lock);
@@ -182,12 +200,12 @@ static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char
return ret;
}
-static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr,
- const char * buf, size_t count)
+static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
{
int ret = -EIO;
- struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
- struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
+ struct cpuidle_device *dev = to_cpuidle_device(kobj);
+ struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);
if (cattr->store) {
mutex_lock(&cpuidle_lock);
@@ -204,9 +222,10 @@ static const struct sysfs_ops cpuidle_sysfs_ops = {
static void cpuidle_sysfs_release(struct kobject *kobj)
{
- struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
+ struct cpuidle_device_kobj *kdev =
+ container_of(kobj, struct cpuidle_device_kobj, kobj);
- complete(&dev->kobj_unregister);
+ complete(&kdev->kobj_unregister);
}
static struct kobj_type ktype_cpuidle = {
@@ -237,8 +256,8 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \
#define define_store_state_ull_function(_name) \
static ssize_t store_state_##_name(struct cpuidle_state *state, \
- struct cpuidle_state_usage *state_usage, \
- const char *buf, size_t size) \
+ struct cpuidle_state_usage *state_usage, \
+ const char *buf, size_t size) \
{ \
unsigned long long value; \
int err; \
@@ -256,14 +275,16 @@ static ssize_t store_state_##_name(struct cpuidle_state *state, \
#define define_show_state_ull_function(_name) \
static ssize_t show_state_##_name(struct cpuidle_state *state, \
- struct cpuidle_state_usage *state_usage, char *buf) \
+ struct cpuidle_state_usage *state_usage, \
+ char *buf) \
{ \
return sprintf(buf, "%llu\n", state_usage->_name);\
}
#define define_show_state_str_function(_name) \
static ssize_t show_state_##_name(struct cpuidle_state *state, \
- struct cpuidle_state_usage *state_usage, char *buf) \
+ struct cpuidle_state_usage *state_usage, \
+ char *buf) \
{ \
if (state->_name[0] == '\0')\
return sprintf(buf, "<null>\n");\
@@ -309,8 +330,9 @@ struct cpuidle_state_kobj {
#define kobj_to_state(k) (kobj_to_state_obj(k)->state)
#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
#define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
-static ssize_t cpuidle_state_show(struct kobject * kobj,
- struct attribute * attr ,char * buf)
+
+static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr,
+ char * buf)
{
int ret = -EIO;
struct cpuidle_state *state = kobj_to_state(kobj);
@@ -323,8 +345,8 @@ static ssize_t cpuidle_state_show(struct kobject * kobj,
return ret;
}
-static ssize_t cpuidle_state_store(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t size)
+static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t size)
{
int ret = -EIO;
struct cpuidle_state *state = kobj_to_state(kobj);
@@ -371,6 +393,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
{
int i, ret = -ENOMEM;
struct cpuidle_state_kobj *kobj;
+ struct cpuidle_device_kobj *kdev = device->kobj_dev;
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);
/* state statistics */
@@ -383,7 +406,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
init_completion(&kobj->kobj_unregister);
ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
- &device->kobj, "state%d", i);
+ &kdev->kobj, "state%d", i);
if (ret) {
kfree(kobj);
goto error_state;
@@ -449,8 +472,8 @@ static void cpuidle_driver_sysfs_release(struct kobject *kobj)
complete(&driver_kobj->kobj_unregister);
}
-static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute * attr,
- char * buf)
+static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
{
int ret = -EIO;
struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
@@ -500,6 +523,7 @@ static struct kobj_type ktype_driver_cpuidle = {
static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
{
struct cpuidle_driver_kobj *kdrv;
+ struct cpuidle_device_kobj *kdev = dev->kobj_dev;
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
int ret;
@@ -511,7 +535,7 @@ static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
init_completion(&kdrv->kobj_unregister);
ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,
- &dev->kobj, "driver");
+ &kdev->kobj, "driver");
if (ret) {
kfree(kdrv);
return ret;
@@ -580,16 +604,28 @@ void cpuidle_remove_device_sysfs(struct cpuidle_device *device)
*/
int cpuidle_add_sysfs(struct cpuidle_device *dev)
{
+ struct cpuidle_device_kobj *kdev;
struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);
int error;
- init_completion(&dev->kobj_unregister);
+ kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
+ if (!kdev)
+ return -ENOMEM;
+ kdev->dev = dev;
+ dev->kobj_dev = kdev;
- error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
- "cpuidle");
- if (!error)
- kobject_uevent(&dev->kobj, KOBJ_ADD);
- return error;
+ init_completion(&kdev->kobj_unregister);
+
+ error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
+ "cpuidle");
+ if (error) {
+ kfree(kdev);
+ return error;
+ }
+
+ kobject_uevent(&kdev->kobj, KOBJ_ADD);
+
+ return 0;
}
/**
@@ -598,6 +634,9 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev)
*/
void cpuidle_remove_sysfs(struct cpuidle_device *dev)
{
- kobject_put(&dev->kobj);
- wait_for_completion(&dev->kobj_unregister);
+ struct cpuidle_device_kobj *kdev = dev->kobj_dev;
+
+ kobject_put(&kdev->kobj);
+ wait_for_completion(&kdev->kobj_unregister);
+ kfree(kdev);
}
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 5996521a1ca..84573b4d6f9 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -429,7 +429,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in,
dma_addr_t src_dma, dst_dma;
int ret = 0;
- desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA);
+ desc = kmalloc(CAAM_CMD_SZ * 8 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA);
if (!desc) {
dev_err(jrdev, "unable to allocate key input memory\n");
return -ENOMEM;
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index e94e619fe05..c99c00d35d3 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -703,7 +703,7 @@ err_out:
}
EXPORT_SYMBOL(devfreq_remove_governor);
-static ssize_t show_governor(struct device *dev,
+static ssize_t governor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
if (!to_devfreq(dev)->governor)
@@ -712,7 +712,7 @@ static ssize_t show_governor(struct device *dev,
return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);
}
-static ssize_t store_governor(struct device *dev, struct device_attribute *attr,
+static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct devfreq *df = to_devfreq(dev);
@@ -754,9 +754,11 @@ out:
ret = count;
return ret;
}
-static ssize_t show_available_governors(struct device *d,
- struct device_attribute *attr,
- char *buf)
+static DEVICE_ATTR_RW(governor);
+
+static ssize_t available_governors_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
struct devfreq_governor *tmp_governor;
ssize_t count = 0;
@@ -775,9 +777,10 @@ static ssize_t show_available_governors(struct device *d,
return count;
}
+static DEVICE_ATTR_RO(available_governors);
-static ssize_t show_freq(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
unsigned long freq;
struct devfreq *devfreq = to_devfreq(dev);
@@ -788,20 +791,22 @@ static ssize_t show_freq(struct device *dev,
return sprintf(buf, "%lu\n", devfreq->previous_freq);
}
+static DEVICE_ATTR_RO(cur_freq);
-static ssize_t show_target_freq(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t target_freq_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq);
}
+static DEVICE_ATTR_RO(target_freq);
-static ssize_t show_polling_interval(struct device *dev,
+static ssize_t polling_interval_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", to_devfreq(dev)->profile->polling_ms);
}
-static ssize_t store_polling_interval(struct device *dev,
+static ssize_t polling_interval_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -821,8 +826,9 @@ static ssize_t store_polling_interval(struct device *dev,
return ret;
}
+static DEVICE_ATTR_RW(polling_interval);
-static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr,
+static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct devfreq *df = to_devfreq(dev);
@@ -849,13 +855,13 @@ unlock:
return ret;
}
-static ssize_t show_min_freq(struct device *dev, struct device_attribute *attr,
+static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%lu\n", to_devfreq(dev)->min_freq);
}
-static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr,
+static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct devfreq *df = to_devfreq(dev);
@@ -881,16 +887,18 @@ unlock:
mutex_unlock(&df->lock);
return ret;
}
+static DEVICE_ATTR_RW(min_freq);
-static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr,
+static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq);
}
+static DEVICE_ATTR_RW(max_freq);
-static ssize_t show_available_freqs(struct device *d,
- struct device_attribute *attr,
- char *buf)
+static ssize_t available_frequencies_show(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
struct devfreq *df = to_devfreq(d);
struct device *dev = df->dev.parent;
@@ -918,9 +926,10 @@ static ssize_t show_available_freqs(struct device *d,
return count;
}
+static DEVICE_ATTR_RO(available_frequencies);
-static ssize_t show_trans_table(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t trans_stat_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct devfreq *devfreq = to_devfreq(dev);
ssize_t len;
@@ -959,20 +968,21 @@ static ssize_t show_trans_table(struct device *dev, struct device_attribute *att
devfreq->total_trans);
return len;
}
-
-static struct device_attribute devfreq_attrs[] = {
- __ATTR(governor, S_IRUGO | S_IWUSR, show_governor, store_governor),
- __ATTR(available_governors, S_IRUGO, show_available_governors, NULL),
- __ATTR(cur_freq, S_IRUGO, show_freq, NULL),
- __ATTR(available_frequencies, S_IRUGO, show_available_freqs, NULL),
- __ATTR(target_freq, S_IRUGO, show_target_freq, NULL),
- __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval,
- store_polling_interval),
- __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq),
- __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq),
- __ATTR(trans_stat, S_IRUGO, show_trans_table, NULL),
- { },
+static DEVICE_ATTR_RO(trans_stat);
+
+static struct attribute *devfreq_attrs[] = {
+ &dev_attr_governor.attr,
+ &dev_attr_available_governors.attr,
+ &dev_attr_cur_freq.attr,
+ &dev_attr_available_frequencies.attr,
+ &dev_attr_target_freq.attr,
+ &dev_attr_polling_interval.attr,
+ &dev_attr_min_freq.attr,
+ &dev_attr_max_freq.attr,
+ &dev_attr_trans_stat.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(devfreq);
static int __init devfreq_init(void)
{
@@ -988,7 +998,7 @@ static int __init devfreq_init(void)
pr_err("%s: couldn't create workqueue\n", __FILE__);
return PTR_ERR(devfreq_wq);
}
- devfreq_class->dev_attrs = devfreq_attrs;
+ devfreq_class->dev_groups = devfreq_groups;
return 0;
}
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 6825957c97f..daa4da281e5 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -194,7 +194,7 @@ config SIRF_DMA
Enable support for the CSR SiRFprimaII DMA engine.
config TI_EDMA
- tristate "TI EDMA support"
+ bool "TI EDMA support"
depends on ARCH_DAVINCI || ARCH_OMAP
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
@@ -287,6 +287,14 @@ config DMA_OMAP
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
+config TI_CPPI41
+ tristate "AM33xx CPPI41 DMA support"
+ depends on ARCH_OMAP
+ select DMA_ENGINE
+ help
+ The Communications Port Programming Interface (CPPI) 4.1 DMA engine
+ is currently used by the USB driver on AM335x platforms.
+
config MMP_PDMA
bool "MMP PDMA support"
depends on (ARCH_MMP || ARCH_PXA)
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 5e0f2ef8561..6d62ec30c4b 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -39,3 +39,4 @@ obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
obj-$(CONFIG_DMA_OMAP) += omap-dma.o
obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
+obj-$(CONFIG_TI_CPPI41) += cppi41.o
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
new file mode 100644
index 00000000000..7c82b92f9b1
--- /dev/null
+++ b/drivers/dma/cppi41.c
@@ -0,0 +1,1059 @@
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/of_dma.h>
+#include <linux/of_irq.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include "dmaengine.h"
+
+#define DESC_TYPE 27
+#define DESC_TYPE_HOST 0x10
+#define DESC_TYPE_TEARD 0x13
+
+#define TD_DESC_IS_RX (1 << 16)
+#define TD_DESC_DMA_NUM 10
+
+#define DESC_LENGTH_BITS_NUM 21
+
+#define DESC_TYPE_USB (5 << 26)
+#define DESC_PD_COMPLETE (1 << 31)
+
+/* DMA engine */
+#define DMA_TDFDQ 4
+#define DMA_TXGCR(x) (0x800 + (x) * 0x20)
+#define DMA_RXGCR(x) (0x808 + (x) * 0x20)
+#define RXHPCRA0 4
+
+#define GCR_CHAN_ENABLE (1 << 31)
+#define GCR_TEARDOWN (1 << 30)
+#define GCR_STARV_RETRY (1 << 24)
+#define GCR_DESC_TYPE_HOST (1 << 14)
+
+/* DMA scheduler */
+#define DMA_SCHED_CTRL 0
+#define DMA_SCHED_CTRL_EN (1 << 31)
+#define DMA_SCHED_WORD(x) ((x) * 4 + 0x800)
+
+#define SCHED_ENTRY0_CHAN(x) ((x) << 0)
+#define SCHED_ENTRY0_IS_RX (1 << 7)
+
+#define SCHED_ENTRY1_CHAN(x) ((x) << 8)
+#define SCHED_ENTRY1_IS_RX (1 << 15)
+
+#define SCHED_ENTRY2_CHAN(x) ((x) << 16)
+#define SCHED_ENTRY2_IS_RX (1 << 23)
+
+#define SCHED_ENTRY3_CHAN(x) ((x) << 24)
+#define SCHED_ENTRY3_IS_RX (1 << 31)
+
+/* Queue manager */
+/* 4 KiB of memory for descriptors, 2 for each endpoint */
+#define ALLOC_DECS_NUM 128
+#define DESCS_AREAS 1
+#define TOTAL_DESCS_NUM (ALLOC_DECS_NUM * DESCS_AREAS)
+#define QMGR_SCRATCH_SIZE (TOTAL_DESCS_NUM * 4)
+
+#define QMGR_LRAM0_BASE 0x80
+#define QMGR_LRAM_SIZE 0x84
+#define QMGR_LRAM1_BASE 0x88
+#define QMGR_MEMBASE(x) (0x1000 + (x) * 0x10)
+#define QMGR_MEMCTRL(x) (0x1004 + (x) * 0x10)
+#define QMGR_MEMCTRL_IDX_SH 16
+#define QMGR_MEMCTRL_DESC_SH 8
+
+#define QMGR_NUM_PEND 5
+#define QMGR_PEND(x) (0x90 + (x) * 4)
+
+#define QMGR_PENDING_SLOT_Q(x) (x / 32)
+#define QMGR_PENDING_BIT_Q(x) (x % 32)
+
+#define QMGR_QUEUE_A(n) (0x2000 + (n) * 0x10)
+#define QMGR_QUEUE_B(n) (0x2004 + (n) * 0x10)
+#define QMGR_QUEUE_C(n) (0x2008 + (n) * 0x10)
+#define QMGR_QUEUE_D(n) (0x200c + (n) * 0x10)
+
+/* Glue layer specific */
+/* USBSS / USB AM335x */
+#define USBSS_IRQ_STATUS 0x28
+#define USBSS_IRQ_ENABLER 0x2c
+#define USBSS_IRQ_CLEARR 0x30
+
+#define USBSS_IRQ_PD_COMP (1 << 2)
+
+struct cppi41_channel {
+ struct dma_chan chan;
+ struct dma_async_tx_descriptor txd;
+ struct cppi41_dd *cdd;
+ struct cppi41_desc *desc;
+ dma_addr_t desc_phys;
+ void __iomem *gcr_reg;
+ int is_tx;
+ u32 residue;
+
+ unsigned int q_num;
+ unsigned int q_comp_num;
+ unsigned int port_num;
+
+ unsigned td_retry;
+ unsigned td_queued:1;
+ unsigned td_seen:1;
+ unsigned td_desc_seen:1;
+};
+
+struct cppi41_desc {
+ u32 pd0;
+ u32 pd1;
+ u32 pd2;
+ u32 pd3;
+ u32 pd4;
+ u32 pd5;
+ u32 pd6;
+ u32 pd7;
+} __aligned(32);
+
+struct chan_queues {
+ u16 submit;
+ u16 complete;
+};
+
+struct cppi41_dd {
+ struct dma_device ddev;
+
+ void *qmgr_scratch;
+ dma_addr_t scratch_phys;
+
+ struct cppi41_desc *cd;
+ dma_addr_t descs_phys;
+ u32 first_td_desc;
+ struct cppi41_channel *chan_busy[ALLOC_DECS_NUM];
+
+ void __iomem *usbss_mem;
+ void __iomem *ctrl_mem;
+ void __iomem *sched_mem;
+ void __iomem *qmgr_mem;
+ unsigned int irq;
+ const struct chan_queues *queues_rx;
+ const struct chan_queues *queues_tx;
+ struct chan_queues td_queue;
+};
+
+#define FIST_COMPLETION_QUEUE 93
+static struct chan_queues usb_queues_tx[] = {
+ /* USB0 ENDP 1 */
+ [ 0] = { .submit = 32, .complete = 93},
+ [ 1] = { .submit = 34, .complete = 94},
+ [ 2] = { .submit = 36, .complete = 95},
+ [ 3] = { .submit = 38, .complete = 96},
+ [ 4] = { .submit = 40, .complete = 97},
+ [ 5] = { .submit = 42, .complete = 98},
+ [ 6] = { .submit = 44, .complete = 99},
+ [ 7] = { .submit = 46, .complete = 100},
+ [ 8] = { .submit = 48, .complete = 101},
+ [ 9] = { .submit = 50, .complete = 102},
+ [10] = { .submit = 52, .complete = 103},
+ [11] = { .submit = 54, .complete = 104},
+ [12] = { .submit = 56, .complete = 105},
+ [13] = { .submit = 58, .complete = 106},
+ [14] = { .submit = 60, .complete = 107},
+
+ /* USB1 ENDP1 */
+ [15] = { .submit = 62, .complete = 125},
+ [16] = { .submit = 64, .complete = 126},
+ [17] = { .submit = 66, .complete = 127},
+ [18] = { .submit = 68, .complete = 128},
+ [19] = { .submit = 70, .complete = 129},
+ [20] = { .submit = 72, .complete = 130},
+ [21] = { .submit = 74, .complete = 131},
+ [22] = { .submit = 76, .complete = 132},
+ [23] = { .submit = 78, .complete = 133},
+ [24] = { .submit = 80, .complete = 134},
+ [25] = { .submit = 82, .complete = 135},
+ [26] = { .submit = 84, .complete = 136},
+ [27] = { .submit = 86, .complete = 137},
+ [28] = { .submit = 88, .complete = 138},
+ [29] = { .submit = 90, .complete = 139},
+};
+
+static const struct chan_queues usb_queues_rx[] = {
+ /* USB0 ENDP 1 */
+ [ 0] = { .submit = 1, .complete = 109},
+ [ 1] = { .submit = 2, .complete = 110},
+ [ 2] = { .submit = 3, .complete = 111},
+ [ 3] = { .submit = 4, .complete = 112},
+ [ 4] = { .submit = 5, .complete = 113},
+ [ 5] = { .submit = 6, .complete = 114},
+ [ 6] = { .submit = 7, .complete = 115},
+ [ 7] = { .submit = 8, .complete = 116},
+ [ 8] = { .submit = 9, .complete = 117},
+ [ 9] = { .submit = 10, .complete = 118},
+ [10] = { .submit = 11, .complete = 119},
+ [11] = { .submit = 12, .complete = 120},
+ [12] = { .submit = 13, .complete = 121},
+ [13] = { .submit = 14, .complete = 122},
+ [14] = { .submit = 15, .complete = 123},
+
+ /* USB1 ENDP 1 */
+ [15] = { .submit = 16, .complete = 141},
+ [16] = { .submit = 17, .complete = 142},
+ [17] = { .submit = 18, .complete = 143},
+ [18] = { .submit = 19, .complete = 144},
+ [19] = { .submit = 20, .complete = 145},
+ [20] = { .submit = 21, .complete = 146},
+ [21] = { .submit = 22, .complete = 147},
+ [22] = { .submit = 23, .complete = 148},
+ [23] = { .submit = 24, .complete = 149},
+ [24] = { .submit = 25, .complete = 150},
+ [25] = { .submit = 26, .complete = 151},
+ [26] = { .submit = 27, .complete = 152},
+ [27] = { .submit = 28, .complete = 153},
+ [28] = { .submit = 29, .complete = 154},
+ [29] = { .submit = 30, .complete = 155},
+};
+
+struct cppi_glue_infos {
+ irqreturn_t (*isr)(int irq, void *data);
+ const struct chan_queues *queues_rx;
+ const struct chan_queues *queues_tx;
+ struct chan_queues td_queue;
+};
+
+static struct cppi41_channel *to_cpp41_chan(struct dma_chan *c)
+{
+ return container_of(c, struct cppi41_channel, chan);
+}
+
+static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc)
+{
+ struct cppi41_channel *c;
+ u32 descs_size;
+ u32 desc_num;
+
+ descs_size = sizeof(struct cppi41_desc) * ALLOC_DECS_NUM;
+
+ if (!((desc >= cdd->descs_phys) &&
+ (desc < (cdd->descs_phys + descs_size)))) {
+ return NULL;
+ }
+
+ desc_num = (desc - cdd->descs_phys) / sizeof(struct cppi41_desc);
+ BUG_ON(desc_num >= ALLOC_DECS_NUM);
+ c = cdd->chan_busy[desc_num];
+ cdd->chan_busy[desc_num] = NULL;
+ return c;
+}
+
+static void cppi_writel(u32 val, void *__iomem *mem)
+{
+ __raw_writel(val, mem);
+}
+
+static u32 cppi_readl(void *__iomem *mem)
+{
+ return __raw_readl(mem);
+}
+
+static u32 pd_trans_len(u32 val)
+{
+ return val & ((1 << (DESC_LENGTH_BITS_NUM + 1)) - 1);
+}
+
+static irqreturn_t cppi41_irq(int irq, void *data)
+{
+ struct cppi41_dd *cdd = data;
+ struct cppi41_channel *c;
+ u32 status;
+ int i;
+
+ status = cppi_readl(cdd->usbss_mem + USBSS_IRQ_STATUS);
+ if (!(status & USBSS_IRQ_PD_COMP))
+ return IRQ_NONE;
+ cppi_writel(status, cdd->usbss_mem + USBSS_IRQ_STATUS);
+
+ for (i = QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE); i < QMGR_NUM_PEND;
+ i++) {
+ u32 val;
+ u32 q_num;
+
+ val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i));
+ if (i == QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE) && val) {
+ u32 mask;
+ /* set corresponding bit for completetion Q 93 */
+ mask = 1 << QMGR_PENDING_BIT_Q(FIST_COMPLETION_QUEUE);
+ /* not set all bits for queues less than Q 93 */
+ mask--;
+ /* now invert and keep only Q 93+ set */
+ val &= ~mask;
+ }
+
+ if (val)
+ __iormb();
+
+ while (val) {
+ u32 desc;
+
+ q_num = __fls(val);
+ val &= ~(1 << q_num);
+ q_num += 32 * i;
+ desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(q_num));
+ desc &= ~0x1f;
+ c = desc_to_chan(cdd, desc);
+ if (WARN_ON(!c)) {
+ pr_err("%s() q %d desc %08x\n", __func__,
+ q_num, desc);
+ continue;
+ }
+ c->residue = pd_trans_len(c->desc->pd6) -
+ pd_trans_len(c->desc->pd0);
+
+ dma_cookie_complete(&c->txd);
+ c->txd.callback(c->txd.callback_param);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static dma_cookie_t cppi41_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ dma_cookie_t cookie;
+
+ cookie = dma_cookie_assign(tx);
+
+ return cookie;
+}
+
+static int cppi41_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+
+ dma_cookie_init(chan);
+ dma_async_tx_descriptor_init(&c->txd, chan);
+ c->txd.tx_submit = cppi41_tx_submit;
+
+ if (!c->is_tx)
+ cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0);
+
+ return 0;
+}
+
+static void cppi41_dma_free_chan_resources(struct dma_chan *chan)
+{
+}
+
+static enum dma_status cppi41_dma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+ enum dma_status ret;
+
+ /* lock */
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (txstate && ret == DMA_SUCCESS)
+ txstate->residue = c->residue;
+ /* unlock */
+
+ return ret;
+}
+
+static void push_desc_queue(struct cppi41_channel *c)
+{
+ struct cppi41_dd *cdd = c->cdd;
+ u32 desc_num;
+ u32 desc_phys;
+ u32 reg;
+
+ desc_phys = lower_32_bits(c->desc_phys);
+ desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
+ WARN_ON(cdd->chan_busy[desc_num]);
+ cdd->chan_busy[desc_num] = c;
+
+ reg = (sizeof(struct cppi41_desc) - 24) / 4;
+ reg |= desc_phys;
+ cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
+}
+
+static void cppi41_dma_issue_pending(struct dma_chan *chan)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+ u32 reg;
+
+ c->residue = 0;
+
+ reg = GCR_CHAN_ENABLE;
+ if (!c->is_tx) {
+ reg |= GCR_STARV_RETRY;
+ reg |= GCR_DESC_TYPE_HOST;
+ reg |= c->q_comp_num;
+ }
+
+ cppi_writel(reg, c->gcr_reg);
+
+ /*
+ * We don't use writel() but __raw_writel() so we have to make sure
+ * that the DMA descriptor in coherent memory made to the main memory
+ * before starting the dma engine.
+ */
+ __iowmb();
+ push_desc_queue(c);
+}
+
+static u32 get_host_pd0(u32 length)
+{
+ u32 reg;
+
+ reg = DESC_TYPE_HOST << DESC_TYPE;
+ reg |= length;
+
+ return reg;
+}
+
+static u32 get_host_pd1(struct cppi41_channel *c)
+{
+ u32 reg;
+
+ reg = 0;
+
+ return reg;
+}
+
+static u32 get_host_pd2(struct cppi41_channel *c)
+{
+ u32 reg;
+
+ reg = DESC_TYPE_USB;
+ reg |= c->q_comp_num;
+
+ return reg;
+}
+
+static u32 get_host_pd3(u32 length)
+{
+ u32 reg;
+
+ /* PD3 = packet size */
+ reg = length;
+
+ return reg;
+}
+
+static u32 get_host_pd6(u32 length)
+{
+ u32 reg;
+
+ /* PD6 buffer size */
+ reg = DESC_PD_COMPLETE;
+ reg |= length;
+
+ return reg;
+}
+
+static u32 get_host_pd4_or_7(u32 addr)
+{
+ u32 reg;
+
+ reg = addr;
+
+ return reg;
+}
+
+static u32 get_host_pd5(void)
+{
+ u32 reg;
+
+ reg = 0;
+
+ return reg;
+}
+
+static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl, unsigned sg_len,
+ enum dma_transfer_direction dir, unsigned long tx_flags, void *context)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+ struct cppi41_desc *d;
+ struct scatterlist *sg;
+ unsigned int i;
+ unsigned int num;
+
+ num = 0;
+ d = c->desc;
+ for_each_sg(sgl, sg, sg_len, i) {
+ u32 addr;
+ u32 len;
+
+ /* We need to use more than one desc once musb supports sg */
+ BUG_ON(num > 0);
+ addr = lower_32_bits(sg_dma_address(sg));
+ len = sg_dma_len(sg);
+
+ d->pd0 = get_host_pd0(len);
+ d->pd1 = get_host_pd1(c);
+ d->pd2 = get_host_pd2(c);
+ d->pd3 = get_host_pd3(len);
+ d->pd4 = get_host_pd4_or_7(addr);
+ d->pd5 = get_host_pd5();
+ d->pd6 = get_host_pd6(len);
+ d->pd7 = get_host_pd4_or_7(addr);
+
+ d++;
+ }
+
+ return &c->txd;
+}
+
+static int cpp41_cfg_chan(struct cppi41_channel *c,
+ struct dma_slave_config *cfg)
+{
+ return 0;
+}
+
+static void cppi41_compute_td_desc(struct cppi41_desc *d)
+{
+ d->pd0 = DESC_TYPE_TEARD << DESC_TYPE;
+}
+
+static u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num)
+{
+ u32 desc;
+
+ desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(queue_num));
+ desc &= ~0x1f;
+ return desc;
+}
+
+static int cppi41_tear_down_chan(struct cppi41_channel *c)
+{
+ struct cppi41_dd *cdd = c->cdd;
+ struct cppi41_desc *td;
+ u32 reg;
+ u32 desc_phys;
+ u32 td_desc_phys;
+
+ td = cdd->cd;
+ td += cdd->first_td_desc;
+
+ td_desc_phys = cdd->descs_phys;
+ td_desc_phys += cdd->first_td_desc * sizeof(struct cppi41_desc);
+
+ if (!c->td_queued) {
+ cppi41_compute_td_desc(td);
+ __iowmb();
+
+ reg = (sizeof(struct cppi41_desc) - 24) / 4;
+ reg |= td_desc_phys;
+ cppi_writel(reg, cdd->qmgr_mem +
+ QMGR_QUEUE_D(cdd->td_queue.submit));
+
+ reg = GCR_CHAN_ENABLE;
+ if (!c->is_tx) {
+ reg |= GCR_STARV_RETRY;
+ reg |= GCR_DESC_TYPE_HOST;
+ reg |= c->q_comp_num;
+ }
+ reg |= GCR_TEARDOWN;
+ cppi_writel(reg, c->gcr_reg);
+ c->td_queued = 1;
+ c->td_retry = 100;
+ }
+
+ if (!c->td_seen) {
+ unsigned td_comp_queue;
+
+ if (c->is_tx)
+ td_comp_queue = cdd->td_queue.complete;
+ else
+ td_comp_queue = c->q_comp_num;
+
+ desc_phys = cppi41_pop_desc(cdd, td_comp_queue);
+ if (desc_phys) {
+ __iormb();
+
+ if (desc_phys == td_desc_phys) {
+ u32 pd0;
+ pd0 = td->pd0;
+ WARN_ON((pd0 >> DESC_TYPE) != DESC_TYPE_TEARD);
+ WARN_ON(!c->is_tx && !(pd0 & TD_DESC_IS_RX));
+ WARN_ON((pd0 & 0x1f) != c->port_num);
+ } else {
+ WARN_ON_ONCE(1);
+ }
+ c->td_seen = 1;
+ }
+ }
+ if (!c->td_desc_seen) {
+ desc_phys = cppi41_pop_desc(cdd, c->q_comp_num);
+ if (desc_phys) {
+ __iormb();
+ WARN_ON(c->desc_phys != desc_phys);
+ c->td_desc_seen = 1;
+ }
+ }
+ c->td_retry--;
+ /*
+ * If the TX descriptor / channel is in use, the caller needs to poke
+ * his TD bit multiple times. After that he hardware releases the
+ * transfer descriptor followed by TD descriptor. Waiting seems not to
+ * cause any difference.
+ * RX seems to be thrown out right away. However once the TearDown
+ * descriptor gets through we are done. If we have seens the transfer
+ * descriptor before the TD we fetch it from enqueue, it has to be
+ * there waiting for us.
+ */
+ if (!c->td_seen && c->td_retry)
+ return -EAGAIN;
+
+ WARN_ON(!c->td_retry);
+ if (!c->td_desc_seen) {
+ desc_phys = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
+ WARN_ON(!desc_phys);
+ }
+
+ c->td_queued = 0;
+ c->td_seen = 0;
+ c->td_desc_seen = 0;
+ cppi_writel(0, c->gcr_reg);
+ return 0;
+}
+
+static int cppi41_stop_chan(struct dma_chan *chan)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+ struct cppi41_dd *cdd = c->cdd;
+ u32 desc_num;
+ u32 desc_phys;
+ int ret;
+
+ ret = cppi41_tear_down_chan(c);
+ if (ret)
+ return ret;
+
+ desc_phys = lower_32_bits(c->desc_phys);
+ desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
+ WARN_ON(!cdd->chan_busy[desc_num]);
+ cdd->chan_busy[desc_num] = NULL;
+
+ return 0;
+}
+
+static int cppi41_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct cppi41_channel *c = to_cpp41_chan(chan);
+ int ret;
+
+ switch (cmd) {
+ case DMA_SLAVE_CONFIG:
+ ret = cpp41_cfg_chan(c, (struct dma_slave_config *) arg);
+ break;
+
+ case DMA_TERMINATE_ALL:
+ ret = cppi41_stop_chan(chan);
+ break;
+
+ default:
+ ret = -ENXIO;
+ break;
+ }
+ return ret;
+}
+
+static void cleanup_chans(struct cppi41_dd *cdd)
+{
+ while (!list_empty(&cdd->ddev.channels)) {
+ struct cppi41_channel *cchan;
+
+ cchan = list_first_entry(&cdd->ddev.channels,
+ struct cppi41_channel, chan.device_node);
+ list_del(&cchan->chan.device_node);
+ kfree(cchan);
+ }
+}
+
+static int cppi41_add_chans(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+ struct cppi41_channel *cchan;
+ int i;
+ int ret;
+ u32 n_chans;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "#dma-channels",
+ &n_chans);
+ if (ret)
+ return ret;
+ /*
+ * The channels can only be used as TX or as RX. So we add twice
+ * that much dma channels because USB can only do RX or TX.
+ */
+ n_chans *= 2;
+
+ for (i = 0; i < n_chans; i++) {
+ cchan = kzalloc(sizeof(*cchan), GFP_KERNEL);
+ if (!cchan)
+ goto err;
+
+ cchan->cdd = cdd;
+ if (i & 1) {
+ cchan->gcr_reg = cdd->ctrl_mem + DMA_TXGCR(i >> 1);
+ cchan->is_tx = 1;
+ } else {
+ cchan->gcr_reg = cdd->ctrl_mem + DMA_RXGCR(i >> 1);
+ cchan->is_tx = 0;
+ }
+ cchan->port_num = i >> 1;
+ cchan->desc = &cdd->cd[i];
+ cchan->desc_phys = cdd->descs_phys;
+ cchan->desc_phys += i * sizeof(struct cppi41_desc);
+ cchan->chan.device = &cdd->ddev;
+ list_add_tail(&cchan->chan.device_node, &cdd->ddev.channels);
+ }
+ cdd->first_td_desc = n_chans;
+
+ return 0;
+err:
+ cleanup_chans(cdd);
+ return -ENOMEM;
+}
+
+static void purge_descs(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+ unsigned int mem_decs;
+ int i;
+
+ mem_decs = ALLOC_DECS_NUM * sizeof(struct cppi41_desc);
+
+ for (i = 0; i < DESCS_AREAS; i++) {
+
+ cppi_writel(0, cdd->qmgr_mem + QMGR_MEMBASE(i));
+ cppi_writel(0, cdd->qmgr_mem + QMGR_MEMCTRL(i));
+
+ dma_free_coherent(&pdev->dev, mem_decs, cdd->cd,
+ cdd->descs_phys);
+ }
+}
+
+static void disable_sched(struct cppi41_dd *cdd)
+{
+ cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
+}
+
+static void deinit_cpii41(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+ disable_sched(cdd);
+
+ purge_descs(pdev, cdd);
+
+ cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+ cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+ dma_free_coherent(&pdev->dev, QMGR_SCRATCH_SIZE, cdd->qmgr_scratch,
+ cdd->scratch_phys);
+}
+
+static int init_descs(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+ unsigned int desc_size;
+ unsigned int mem_decs;
+ int i;
+ u32 reg;
+ u32 idx;
+
+ BUILD_BUG_ON(sizeof(struct cppi41_desc) &
+ (sizeof(struct cppi41_desc) - 1));
+ BUILD_BUG_ON(sizeof(struct cppi41_desc) < 32);
+ BUILD_BUG_ON(ALLOC_DECS_NUM < 32);
+
+ desc_size = sizeof(struct cppi41_desc);
+ mem_decs = ALLOC_DECS_NUM * desc_size;
+
+ idx = 0;
+ for (i = 0; i < DESCS_AREAS; i++) {
+
+ reg = idx << QMGR_MEMCTRL_IDX_SH;
+ reg |= (ilog2(desc_size) - 5) << QMGR_MEMCTRL_DESC_SH;
+ reg |= ilog2(ALLOC_DECS_NUM) - 5;
+
+ BUILD_BUG_ON(DESCS_AREAS != 1);
+ cdd->cd = dma_alloc_coherent(&pdev->dev, mem_decs,
+ &cdd->descs_phys, GFP_KERNEL);
+ if (!cdd->cd)
+ return -ENOMEM;
+
+ cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i));
+ cppi_writel(reg, cdd->qmgr_mem + QMGR_MEMCTRL(i));
+
+ idx += ALLOC_DECS_NUM;
+ }
+ return 0;
+}
+
+static void init_sched(struct cppi41_dd *cdd)
+{
+ unsigned ch;
+ unsigned word;
+ u32 reg;
+
+ word = 0;
+ cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
+ for (ch = 0; ch < 15 * 2; ch += 2) {
+
+ reg = SCHED_ENTRY0_CHAN(ch);
+ reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX;
+
+ reg |= SCHED_ENTRY2_CHAN(ch + 1);
+ reg |= SCHED_ENTRY3_CHAN(ch + 1) | SCHED_ENTRY3_IS_RX;
+ cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word));
+ word++;
+ }
+ reg = 15 * 2 * 2 - 1;
+ reg |= DMA_SCHED_CTRL_EN;
+ cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL);
+}
+
+static int init_cppi41(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+ int ret;
+
+ BUILD_BUG_ON(QMGR_SCRATCH_SIZE > ((1 << 14) - 1));
+ cdd->qmgr_scratch = dma_alloc_coherent(&pdev->dev, QMGR_SCRATCH_SIZE,
+ &cdd->scratch_phys, GFP_KERNEL);
+ if (!cdd->qmgr_scratch)
+ return -ENOMEM;
+
+ cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+ cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE);
+ cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE);
+
+ ret = init_descs(pdev, cdd);
+ if (ret)
+ goto err_td;
+
+ cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ);
+ init_sched(cdd);
+ return 0;
+err_td:
+ deinit_cpii41(pdev, cdd);
+ return ret;
+}
+
+static struct platform_driver cpp41_dma_driver;
+/*
+ * The param format is:
+ * X Y
+ * X: Port
+ * Y: 0 = RX else TX
+ */
+#define INFO_PORT 0
+#define INFO_IS_TX 1
+
+static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param)
+{
+ struct cppi41_channel *cchan;
+ struct cppi41_dd *cdd;
+ const struct chan_queues *queues;
+ u32 *num = param;
+
+ if (chan->device->dev->driver != &cpp41_dma_driver.driver)
+ return false;
+
+ cchan = to_cpp41_chan(chan);
+
+ if (cchan->port_num != num[INFO_PORT])
+ return false;
+
+ if (cchan->is_tx && !num[INFO_IS_TX])
+ return false;
+ cdd = cchan->cdd;
+ if (cchan->is_tx)
+ queues = cdd->queues_tx;
+ else
+ queues = cdd->queues_rx;
+
+ BUILD_BUG_ON(ARRAY_SIZE(usb_queues_rx) != ARRAY_SIZE(usb_queues_tx));
+ if (WARN_ON(cchan->port_num > ARRAY_SIZE(usb_queues_rx)))
+ return false;
+
+ cchan->q_num = queues[cchan->port_num].submit;
+ cchan->q_comp_num = queues[cchan->port_num].complete;
+ return true;
+}
+
+static struct of_dma_filter_info cpp41_dma_info = {
+ .filter_fn = cpp41_dma_filter_fn,
+};
+
+static struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ int count = dma_spec->args_count;
+ struct of_dma_filter_info *info = ofdma->of_dma_data;
+
+ if (!info || !info->filter_fn)
+ return NULL;
+
+ if (count != 2)
+ return NULL;
+
+ return dma_request_channel(info->dma_cap, info->filter_fn,
+ &dma_spec->args[0]);
+}
+
+static const struct cppi_glue_infos usb_infos = {
+ .isr = cppi41_irq,
+ .queues_rx = usb_queues_rx,
+ .queues_tx = usb_queues_tx,
+ .td_queue = { .submit = 31, .complete = 0 },
+};
+
+static const struct of_device_id cppi41_dma_ids[] = {
+ { .compatible = "ti,am3359-cppi41", .data = &usb_infos},
+ {},
+};
+MODULE_DEVICE_TABLE(of, cppi41_dma_ids);
+
+static const struct cppi_glue_infos *get_glue_info(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id;
+
+ of_id = of_match_node(cppi41_dma_ids, pdev->dev.of_node);
+ if (!of_id)
+ return NULL;
+ return of_id->data;
+}
+
+static int cppi41_dma_probe(struct platform_device *pdev)
+{
+ struct cppi41_dd *cdd;
+ const struct cppi_glue_infos *glue_info;
+ int irq;
+ int ret;
+
+ glue_info = get_glue_info(pdev);
+ if (!glue_info)
+ return -EINVAL;
+
+ cdd = kzalloc(sizeof(*cdd), GFP_KERNEL);
+ if (!cdd)
+ return -ENOMEM;
+
+ dma_cap_set(DMA_SLAVE, cdd->ddev.cap_mask);
+ cdd->ddev.device_alloc_chan_resources = cppi41_dma_alloc_chan_resources;
+ cdd->ddev.device_free_chan_resources = cppi41_dma_free_chan_resources;
+ cdd->ddev.device_tx_status = cppi41_dma_tx_status;
+ cdd->ddev.device_issue_pending = cppi41_dma_issue_pending;
+ cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg;
+ cdd->ddev.device_control = cppi41_dma_control;
+ cdd->ddev.dev = &pdev->dev;
+ INIT_LIST_HEAD(&cdd->ddev.channels);
+ cpp41_dma_info.dma_cap = cdd->ddev.cap_mask;
+
+ cdd->usbss_mem = of_iomap(pdev->dev.of_node, 0);
+ cdd->ctrl_mem = of_iomap(pdev->dev.of_node, 1);
+ cdd->sched_mem = of_iomap(pdev->dev.of_node, 2);
+ cdd->qmgr_mem = of_iomap(pdev->dev.of_node, 3);
+
+ if (!cdd->usbss_mem || !cdd->ctrl_mem || !cdd->sched_mem ||
+ !cdd->qmgr_mem) {
+ ret = -ENXIO;
+ goto err_remap;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret)
+ goto err_get_sync;
+
+ cdd->queues_rx = glue_info->queues_rx;
+ cdd->queues_tx = glue_info->queues_tx;
+ cdd->td_queue = glue_info->td_queue;
+
+ ret = init_cppi41(pdev, cdd);
+ if (ret)
+ goto err_init_cppi;
+
+ ret = cppi41_add_chans(pdev, cdd);
+ if (ret)
+ goto err_chans;
+
+ irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ if (!irq)
+ goto err_irq;
+
+ cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER);
+
+ ret = request_irq(irq, glue_info->isr, IRQF_SHARED,
+ dev_name(&pdev->dev), cdd);
+ if (ret)
+ goto err_irq;
+ cdd->irq = irq;
+
+ ret = dma_async_device_register(&cdd->ddev);
+ if (ret)
+ goto err_dma_reg;
+
+ ret = of_dma_controller_register(pdev->dev.of_node,
+ cppi41_dma_xlate, &cpp41_dma_info);
+ if (ret)
+ goto err_of;
+
+ platform_set_drvdata(pdev, cdd);
+ return 0;
+err_of:
+ dma_async_device_unregister(&cdd->ddev);
+err_dma_reg:
+ free_irq(irq, cdd);
+err_irq:
+ cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR);
+ cleanup_chans(cdd);
+err_chans:
+ deinit_cpii41(pdev, cdd);
+err_init_cppi:
+ pm_runtime_put(&pdev->dev);
+err_get_sync:
+ pm_runtime_disable(&pdev->dev);
+ iounmap(cdd->usbss_mem);
+ iounmap(cdd->ctrl_mem);
+ iounmap(cdd->sched_mem);
+ iounmap(cdd->qmgr_mem);
+err_remap:
+ kfree(cdd);
+ return ret;
+}
+
+static int cppi41_dma_remove(struct platform_device *pdev)
+{
+ struct cppi41_dd *cdd = platform_get_drvdata(pdev);
+
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(&cdd->ddev);
+
+ cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR);
+ free_irq(cdd->irq, cdd);
+ cleanup_chans(cdd);
+ deinit_cpii41(pdev, cdd);
+ iounmap(cdd->usbss_mem);
+ iounmap(cdd->ctrl_mem);
+ iounmap(cdd->sched_mem);
+ iounmap(cdd->qmgr_mem);
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ kfree(cdd);
+ return 0;
+}
+
+static struct platform_driver cpp41_dma_driver = {
+ .probe = cppi41_dma_probe,
+ .remove = cppi41_dma_remove,
+ .driver = {
+ .name = "cppi41-dma-engine",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(cppi41_dma_ids),
+ },
+};
+
+module_platform_driver(cpp41_dma_driver);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 9e56745f87b..99af4db5948 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -87,7 +87,8 @@ static struct dma_chan *dev_to_dma_chan(struct device *dev)
return chan_dev->chan;
}
-static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t memcpy_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct dma_chan *chan;
unsigned long count = 0;
@@ -106,9 +107,10 @@ static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *at
return err;
}
+static DEVICE_ATTR_RO(memcpy_count);
-static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t bytes_transferred_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct dma_chan *chan;
unsigned long count = 0;
@@ -127,8 +129,10 @@ static ssize_t show_bytes_transferred(struct device *dev, struct device_attribut
return err;
}
+static DEVICE_ATTR_RO(bytes_transferred);
-static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t in_use_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct dma_chan *chan;
int err;
@@ -143,13 +147,15 @@ static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, ch
return err;
}
+static DEVICE_ATTR_RO(in_use);
-static struct device_attribute dma_attrs[] = {
- __ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL),
- __ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL),
- __ATTR(in_use, S_IRUGO, show_in_use, NULL),
- __ATTR_NULL
+static struct attribute *dma_dev_attrs[] = {
+ &dev_attr_memcpy_count.attr,
+ &dev_attr_bytes_transferred.attr,
+ &dev_attr_in_use.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(dma_dev);
static void chan_dev_release(struct device *dev)
{
@@ -167,7 +173,7 @@ static void chan_dev_release(struct device *dev)
static struct class dma_devclass = {
.name = "dma",
- .dev_attrs = dma_attrs,
+ .dev_groups = dma_dev_groups,
.dev_release = chan_dev_release,
};
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index ce3dc3e9688..0bbdea5059f 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -867,6 +867,7 @@ static int pch_dma_probe(struct pci_dev *pdev,
if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
dev_err(&pdev->dev, "Cannot find proper base address\n");
+ err = -ENODEV;
goto err_disable_pdev;
}
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 593827b3fdd..fa645d82500 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -2505,6 +2505,10 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
/* Assign cookies to all nodes */
while (!list_empty(&last->node)) {
desc = list_entry(last->node.next, struct dma_pl330_desc, node);
+ if (pch->cyclic) {
+ desc->txd.callback = last->txd.callback;
+ desc->txd.callback_param = last->txd.callback_param;
+ }
dma_cookie_assign(&desc->txd);
@@ -2688,45 +2692,82 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
size_t period_len, enum dma_transfer_direction direction,
unsigned long flags, void *context)
{
- struct dma_pl330_desc *desc;
+ struct dma_pl330_desc *desc = NULL, *first = NULL;
struct dma_pl330_chan *pch = to_pchan(chan);
+ struct dma_pl330_dmac *pdmac = pch->dmac;
+ unsigned int i;
dma_addr_t dst;
dma_addr_t src;
- desc = pl330_get_desc(pch);
- if (!desc) {
- dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
- __func__, __LINE__);
+ if (len % period_len != 0)
return NULL;
- }
- switch (direction) {
- case DMA_MEM_TO_DEV:
- desc->rqcfg.src_inc = 1;
- desc->rqcfg.dst_inc = 0;
- desc->req.rqtype = MEMTODEV;
- src = dma_addr;
- dst = pch->fifo_addr;
- break;
- case DMA_DEV_TO_MEM:
- desc->rqcfg.src_inc = 0;
- desc->rqcfg.dst_inc = 1;
- desc->req.rqtype = DEVTOMEM;
- src = pch->fifo_addr;
- dst = dma_addr;
- break;
- default:
+ if (!is_slave_direction(direction)) {
dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
__func__, __LINE__);
return NULL;
}
- desc->rqcfg.brst_size = pch->burst_sz;
- desc->rqcfg.brst_len = 1;
+ for (i = 0; i < len / period_len; i++) {
+ desc = pl330_get_desc(pch);
+ if (!desc) {
+ dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+ __func__, __LINE__);
- pch->cyclic = true;
+ if (!first)
+ return NULL;
+
+ spin_lock_irqsave(&pdmac->pool_lock, flags);
+
+ while (!list_empty(&first->node)) {
+ desc = list_entry(first->node.next,
+ struct dma_pl330_desc, node);
+ list_move_tail(&desc->node, &pdmac->desc_pool);
+ }
+
+ list_move_tail(&first->node, &pdmac->desc_pool);
- fill_px(&desc->px, dst, src, period_len);
+ spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+
+ return NULL;
+ }
+
+ switch (direction) {
+ case DMA_MEM_TO_DEV:
+ desc->rqcfg.src_inc = 1;
+ desc->rqcfg.dst_inc = 0;
+ desc->req.rqtype = MEMTODEV;
+ src = dma_addr;
+ dst = pch->fifo_addr;
+ break;
+ case DMA_DEV_TO_MEM:
+ desc->rqcfg.src_inc = 0;
+ desc->rqcfg.dst_inc = 1;
+ desc->req.rqtype = DEVTOMEM;
+ src = pch->fifo_addr;
+ dst = dma_addr;
+ break;
+ default:
+ break;
+ }
+
+ desc->rqcfg.brst_size = pch->burst_sz;
+ desc->rqcfg.brst_len = 1;
+ fill_px(&desc->px, dst, src, period_len);
+
+ if (!first)
+ first = desc;
+ else
+ list_add_tail(&desc->node, &first->node);
+
+ dma_addr += period_len;
+ }
+
+ if (!desc)
+ return NULL;
+
+ pch->cyclic = true;
+ desc->txd.flags = flags;
return &desc->txd;
}
diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c
index b67f45f5c27..5039fbc8825 100644
--- a/drivers/dma/sh/shdma.c
+++ b/drivers/dma/sh/shdma.c
@@ -400,8 +400,8 @@ static size_t sh_dmae_get_partial(struct shdma_chan *schan,
shdma_chan);
struct sh_dmae_desc *sh_desc = container_of(sdesc,
struct sh_dmae_desc, shdma_desc);
- return (sh_desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) <<
- sh_chan->xmit_shift;
+ return sh_desc->hw.tcr -
+ (sh_dmae_readl(sh_chan, TCR) << sh_chan->xmit_shift);
}
/* Called from error IRQ or NMI */
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 27e86d93826..89e109022d7 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -48,6 +48,8 @@ static LIST_HEAD(mc_devices);
*/
static void const *edac_mc_owner;
+static struct bus_type mc_bus[EDAC_MAX_MCS];
+
unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
unsigned len)
{
@@ -723,6 +725,11 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
int ret = -EINVAL;
edac_dbg(0, "\n");
+ if (mci->mc_idx >= EDAC_MAX_MCS) {
+ pr_warn_once("Too many memory controllers: %d\n", mci->mc_idx);
+ return -ENODEV;
+ }
+
#ifdef CONFIG_EDAC_DEBUG
if (edac_debug_level >= 3)
edac_mc_dump_mci(mci);
@@ -762,6 +769,8 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
/* set load time so that error rate can be tracked */
mci->start_time = jiffies;
+ mci->bus = &mc_bus[mci->mc_idx];
+
if (edac_create_sysfs_mci_device(mci)) {
edac_mc_printk(mci, KERN_WARNING,
"failed to create sysfs device\n");
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index ef15a7e613b..e7c32c4f783 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -370,7 +370,7 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
return -ENODEV;
csrow->dev.type = &csrow_attr_type;
- csrow->dev.bus = &mci->bus;
+ csrow->dev.bus = mci->bus;
device_initialize(&csrow->dev);
csrow->dev.parent = &mci->dev;
csrow->mci = mci;
@@ -605,7 +605,7 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
dimm->mci = mci;
dimm->dev.type = &dimm_attr_type;
- dimm->dev.bus = &mci->bus;
+ dimm->dev.bus = mci->bus;
device_initialize(&dimm->dev);
dimm->dev.parent = &mci->dev;
@@ -975,11 +975,13 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
* The memory controller needs its own bus, in order to avoid
* namespace conflicts at /sys/bus/edac.
*/
- mci->bus.name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
- if (!mci->bus.name)
+ mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
+ if (!mci->bus->name)
return -ENOMEM;
- edac_dbg(0, "creating bus %s\n", mci->bus.name);
- err = bus_register(&mci->bus);
+
+ edac_dbg(0, "creating bus %s\n", mci->bus->name);
+
+ err = bus_register(mci->bus);
if (err < 0)
return err;
@@ -988,7 +990,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
device_initialize(&mci->dev);
mci->dev.parent = mci_pdev;
- mci->dev.bus = &mci->bus;
+ mci->dev.bus = mci->bus;
dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
dev_set_drvdata(&mci->dev, mci);
pm_runtime_forbid(&mci->dev);
@@ -997,8 +999,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
err = device_add(&mci->dev);
if (err < 0) {
edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
- bus_unregister(&mci->bus);
- kfree(mci->bus.name);
+ bus_unregister(mci->bus);
+ kfree(mci->bus->name);
return err;
}
@@ -1064,8 +1066,8 @@ fail:
}
fail2:
device_unregister(&mci->dev);
- bus_unregister(&mci->bus);
- kfree(mci->bus.name);
+ bus_unregister(mci->bus);
+ kfree(mci->bus->name);
return err;
}
@@ -1098,8 +1100,8 @@ void edac_unregister_sysfs(struct mem_ctl_info *mci)
{
edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
device_unregister(&mci->dev);
- bus_unregister(&mci->bus);
- kfree(mci->bus.name);
+ bus_unregister(mci->bus);
+ kfree(mci->bus->name);
}
static void mc_attr_release(struct device *dev)
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index 1b635178cc4..157b934e8ce 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -974,7 +974,7 @@ static int i5100_setup_debugfs(struct mem_ctl_info *mci)
if (!i5100_debugfs)
return -ENODEV;
- priv->debugfs = debugfs_create_dir(mci->bus.name, i5100_debugfs);
+ priv->debugfs = debugfs_create_dir(mci->bus->name, i5100_debugfs);
if (!priv->debugfs)
return -ENOMEM;
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 63f454e2057..f1d54a3985b 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -14,6 +14,10 @@ if EXTCON
comment "Extcon Device Drivers"
+config OF_EXTCON
+ def_tristate y
+ depends on OF
+
config EXTCON_GPIO
tristate "GPIO extcon support"
depends on GPIOLIB
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 540e2c3a443..759fdae46f9 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -2,6 +2,8 @@
# Makefile for external connector class (extcon) devices
#
+obj-$(CONFIG_OF_EXTCON) += of_extcon.o
+
obj-$(CONFIG_EXTCON) += extcon-class.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index d0233cd18ff..5985807e52c 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -87,7 +87,8 @@ static irqreturn_t adc_jack_irq_thread(int irq, void *_data)
{
struct adc_jack_data *data = _data;
- schedule_delayed_work(&data->handler, data->handling_delay);
+ queue_delayed_work(system_power_efficient_wq,
+ &data->handler, data->handling_delay);
return IRQ_HANDLED;
}
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 7a1b4a7791b..e55713083c7 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -890,8 +890,9 @@ static void arizona_micd_detect(struct work_struct *work)
handled:
if (info->detecting)
- schedule_delayed_work(&info->micd_timeout_work,
- msecs_to_jiffies(info->micd_timeout));
+ queue_delayed_work(system_power_efficient_wq,
+ &info->micd_timeout_work,
+ msecs_to_jiffies(info->micd_timeout));
pm_runtime_mark_last_busy(info->dev);
mutex_unlock(&info->lock);
@@ -912,8 +913,9 @@ static irqreturn_t arizona_micdet(int irq, void *data)
mutex_unlock(&info->lock);
if (debounce)
- schedule_delayed_work(&info->micd_detect_work,
- msecs_to_jiffies(debounce));
+ queue_delayed_work(system_power_efficient_wq,
+ &info->micd_detect_work,
+ msecs_to_jiffies(debounce));
else
arizona_micd_detect(&info->micd_detect_work.work);
@@ -967,12 +969,14 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
if (val == info->last_jackdet) {
dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
if (cancelled_hp)
- schedule_delayed_work(&info->hpdet_work,
- msecs_to_jiffies(HPDET_DEBOUNCE));
+ queue_delayed_work(system_power_efficient_wq,
+ &info->hpdet_work,
+ msecs_to_jiffies(HPDET_DEBOUNCE));
if (cancelled_mic)
- schedule_delayed_work(&info->micd_timeout_work,
- msecs_to_jiffies(info->micd_timeout));
+ queue_delayed_work(system_power_efficient_wq,
+ &info->micd_timeout_work,
+ msecs_to_jiffies(info->micd_timeout));
goto out;
}
@@ -994,8 +998,9 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
arizona_start_mic(info);
} else {
- schedule_delayed_work(&info->hpdet_work,
- msecs_to_jiffies(HPDET_DEBOUNCE));
+ queue_delayed_work(system_power_efficient_wq,
+ &info->hpdet_work,
+ msecs_to_jiffies(HPDET_DEBOUNCE));
}
regmap_update_bits(arizona->regmap,
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
index 18ccadef43f..148382faded 100644
--- a/drivers/extcon/extcon-class.c
+++ b/drivers/extcon/extcon-class.c
@@ -148,6 +148,7 @@ static ssize_t state_store(struct device *dev, struct device_attribute *attr,
return count;
}
+static DEVICE_ATTR_RW(state);
static ssize_t name_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -163,6 +164,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%s\n", dev_name(edev->dev));
}
+static DEVICE_ATTR_RO(name);
static ssize_t cable_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -527,11 +529,12 @@ int extcon_unregister_notifier(struct extcon_dev *edev,
}
EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
-static struct device_attribute extcon_attrs[] = {
- __ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store),
- __ATTR_RO(name),
- __ATTR_NULL,
+static struct attribute *extcon_attrs[] = {
+ &dev_attr_state.attr,
+ &dev_attr_name.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(extcon);
static int create_extcon_class(void)
{
@@ -539,7 +542,7 @@ static int create_extcon_class(void)
extcon_class = class_create(THIS_MODULE, "extcon");
if (IS_ERR(extcon_class))
return PTR_ERR(extcon_class);
- extcon_class->dev_attrs = extcon_attrs;
+ extcon_class->dev_groups = extcon_groups;
#if defined(CONFIG_ANDROID)
switch_class = class_compat_register("switch");
@@ -602,7 +605,8 @@ int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
edev->dev->class = extcon_class;
edev->dev->release = extcon_dev_release;
- dev_set_name(edev->dev, "%s", edev->name ? edev->name : dev_name(dev));
+ edev->name = edev->name ? edev->name : dev_name(dev);
+ dev_set_name(edev->dev, "%s", edev->name);
if (edev->max_supported) {
char buf[10];
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index 02bec32adde..f874c30ddbf 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -56,7 +56,7 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{
struct gpio_extcon_data *extcon_data = dev_id;
- schedule_delayed_work(&extcon_data->work,
+ queue_delayed_work(system_power_efficient_wq, &extcon_data->work,
extcon_data->debounce_jiffies);
return IRQ_HANDLED;
}
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index b752a0ad7b6..89fdd05c5fd 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -57,6 +57,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) {
palmas_usb->linkstat = PALMAS_USB_STATE_VBUS;
extcon_set_cable_state(&palmas_usb->edev, "USB", true);
+ dev_info(palmas_usb->dev, "USB cable is attached\n");
} else {
dev_dbg(palmas_usb->dev,
"Spurious connect event detected\n");
@@ -65,6 +66,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) {
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
extcon_set_cable_state(&palmas_usb->edev, "USB", false);
+ dev_info(palmas_usb->dev, "USB cable is detached\n");
} else {
dev_dbg(palmas_usb->dev,
"Spurious disconnect event detected\n");
@@ -84,28 +86,23 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
if (set & PALMAS_USB_ID_INT_SRC_ID_GND) {
palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
- PALMAS_USB_ID_INT_EN_HI_SET,
- PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
- palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
- PALMAS_USB_ID_INT_EN_HI_CLR,
- PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
- palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_LATCH_CLR,
PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
palmas_usb->linkstat = PALMAS_USB_STATE_ID;
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
+ dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
} else if (set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) {
palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
- PALMAS_USB_ID_INT_EN_HI_SET,
- PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
- palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
- PALMAS_USB_ID_INT_EN_HI_CLR,
- PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
- palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_LATCH_CLR,
PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
+ dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
+ } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) &&
+ (!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) {
+ palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
+ extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
+ dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
}
return IRQ_HANDLED;
@@ -122,13 +119,17 @@ static void palmas_enable_irq(struct palmas_usb *palmas_usb)
palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_EN_HI_SET,
- PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
+ PALMAS_USB_ID_INT_EN_HI_SET_ID_GND |
+ PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
- palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
+ if (palmas_usb->enable_vbus_detection)
+ palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
/* cold plug for host mode needs this delay */
- msleep(30);
- palmas_id_irq_handler(palmas_usb->id_irq, palmas_usb);
+ if (palmas_usb->enable_id_detection) {
+ msleep(30);
+ palmas_id_irq_handler(palmas_usb->id_irq, palmas_usb);
+ }
}
static int palmas_usb_probe(struct platform_device *pdev)
@@ -139,21 +140,25 @@ static int palmas_usb_probe(struct platform_device *pdev)
struct palmas_usb *palmas_usb;
int status;
- if (node && !pdata) {
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-
- if (!pdata)
- return -ENOMEM;
-
- pdata->wakeup = of_property_read_bool(node, "ti,wakeup");
- } else if (!pdata) {
- return -EINVAL;
- }
-
palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL);
if (!palmas_usb)
return -ENOMEM;
+ if (node && !pdata) {
+ palmas_usb->wakeup = of_property_read_bool(node, "ti,wakeup");
+ palmas_usb->enable_id_detection = of_property_read_bool(node,
+ "ti,enable-id-detection");
+ palmas_usb->enable_vbus_detection = of_property_read_bool(node,
+ "ti,enable-vbus-detection");
+ } else {
+ palmas_usb->wakeup = true;
+ palmas_usb->enable_id_detection = true;
+ palmas_usb->enable_vbus_detection = true;
+
+ if (pdata)
+ palmas_usb->wakeup = pdata->wakeup;
+ }
+
palmas->usb = palmas_usb;
palmas_usb->palmas = palmas;
@@ -168,11 +173,10 @@ static int palmas_usb_probe(struct platform_device *pdev)
palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data,
PALMAS_VBUS_IRQ);
- palmas_usb_wakeup(palmas, pdata->wakeup);
+ palmas_usb_wakeup(palmas, palmas_usb->wakeup);
platform_set_drvdata(pdev, palmas_usb);
- palmas_usb->edev.name = "palmas-usb";
palmas_usb->edev.supported_cable = palmas_extcon_cable;
palmas_usb->edev.mutually_exclusive = mutually_exclusive;
@@ -182,28 +186,36 @@ static int palmas_usb_probe(struct platform_device *pdev)
return status;
}
- status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq,
- NULL, palmas_id_irq_handler,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "palmas_usb_id", palmas_usb);
- if (status < 0) {
- dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+ if (palmas_usb->enable_id_detection) {
+ status = devm_request_threaded_irq(palmas_usb->dev,
+ palmas_usb->id_irq,
+ NULL, palmas_id_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ "palmas_usb_id", palmas_usb);
+ if (status < 0) {
+ dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
palmas_usb->id_irq, status);
- goto fail_extcon;
+ goto fail_extcon;
+ }
}
- status = devm_request_threaded_irq(palmas_usb->dev,
- palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "palmas_usb_vbus", palmas_usb);
- if (status < 0) {
- dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+ if (palmas_usb->enable_vbus_detection) {
+ status = devm_request_threaded_irq(palmas_usb->dev,
+ palmas_usb->vbus_irq, NULL,
+ palmas_vbus_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ "palmas_usb_vbus", palmas_usb);
+ if (status < 0) {
+ dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
palmas_usb->vbus_irq, status);
- goto fail_extcon;
+ goto fail_extcon;
+ }
}
palmas_enable_irq(palmas_usb);
-
+ device_set_wakeup_capable(&pdev->dev, true);
return 0;
fail_extcon:
@@ -221,6 +233,39 @@ static int palmas_usb_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int palmas_usb_suspend(struct device *dev)
+{
+ struct palmas_usb *palmas_usb = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev)) {
+ if (palmas_usb->enable_vbus_detection)
+ enable_irq_wake(palmas_usb->vbus_irq);
+ if (palmas_usb->enable_id_detection)
+ enable_irq_wake(palmas_usb->id_irq);
+ }
+ return 0;
+}
+
+static int palmas_usb_resume(struct device *dev)
+{
+ struct palmas_usb *palmas_usb = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev)) {
+ if (palmas_usb->enable_vbus_detection)
+ disable_irq_wake(palmas_usb->vbus_irq);
+ if (palmas_usb->enable_id_detection)
+ disable_irq_wake(palmas_usb->id_irq);
+ }
+ return 0;
+};
+#endif
+
+static const struct dev_pm_ops palmas_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(palmas_usb_suspend,
+ palmas_usb_resume)
+};
+
static struct of_device_id of_palmas_match_tbl[] = {
{ .compatible = "ti,palmas-usb", },
{ .compatible = "ti,twl6035-usb", },
@@ -234,6 +279,7 @@ static struct platform_driver palmas_usb_driver = {
.name = "palmas-usb",
.of_match_table = of_palmas_match_tbl,
.owner = THIS_MODULE,
+ .pm = &palmas_pm_ops,
},
};
diff --git a/drivers/extcon/of_extcon.c b/drivers/extcon/of_extcon.c
new file mode 100644
index 00000000000..72173ecbb31
--- /dev/null
+++ b/drivers/extcon/of_extcon.c
@@ -0,0 +1,64 @@
+/*
+ * OF helpers for External connector (extcon) framework
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ * Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/extcon/of_extcon.h>
+
+/*
+ * of_extcon_get_extcon_dev - Get the name of extcon device from devicetree
+ * @dev - instance to the given device
+ * @index - index into list of extcon_dev
+ *
+ * return the instance of extcon device
+ */
+struct extcon_dev *of_extcon_get_extcon_dev(struct device *dev, int index)
+{
+ struct device_node *node;
+ struct extcon_dev *edev;
+ struct platform_device *extcon_parent_dev;
+
+ if (!dev->of_node) {
+ dev_dbg(dev, "device does not have a device node entry\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ node = of_parse_phandle(dev->of_node, "extcon", index);
+ if (!node) {
+ dev_dbg(dev, "failed to get phandle in %s node\n",
+ dev->of_node->full_name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ extcon_parent_dev = of_find_device_by_node(node);
+ if (!extcon_parent_dev) {
+ dev_dbg(dev, "unable to find device by node\n");
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ edev = extcon_get_extcon_dev(dev_name(&extcon_parent_dev->dev));
+ if (!edev) {
+ dev_dbg(dev, "unable to get extcon device : %s\n",
+ dev_name(&extcon_parent_dev->dev));
+ return ERR_PTR(-ENODEV);
+ }
+
+ return edev;
+}
+EXPORT_SYMBOL_GPL(of_extcon_get_extcon_dev);
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 7ef316fdc4d..ac1b43a0428 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -54,6 +54,7 @@
#define FW_CDEV_KERNEL_VERSION 5
#define FW_CDEV_VERSION_EVENT_REQUEST2 4
#define FW_CDEV_VERSION_ALLOCATE_REGION_END 4
+#define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW 5
struct client {
u32 version;
@@ -1005,6 +1006,8 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
a->channel, a->speed, a->header_size, cb, client);
if (IS_ERR(context))
return PTR_ERR(context);
+ if (client->version < FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW)
+ context->drop_overflow_headers = true;
/* We only support one context at this time. */
spin_lock_irq(&client->lock);
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 9e1db6490b9..afb701ec90c 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -2749,8 +2749,11 @@ static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr)
{
u32 *ctx_hdr;
- if (ctx->header_length + ctx->base.header_size > PAGE_SIZE)
+ if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) {
+ if (ctx->base.drop_overflow_headers)
+ return;
flush_iso_completions(ctx);
+ }
ctx_hdr = ctx->header + ctx->header_length;
ctx->last_timestamp = (u16)le32_to_cpu((__force __le32)dma_hdr[0]);
@@ -2910,8 +2913,11 @@ static int handle_it_packet(struct context *context,
sync_it_packet_for_cpu(context, d);
- if (ctx->header_length + 4 > PAGE_SIZE)
+ if (ctx->header_length + 4 > PAGE_SIZE) {
+ if (ctx->base.drop_overflow_headers)
+ return 1;
flush_iso_completions(ctx);
+ }
ctx_hdr = ctx->header + ctx->header_length;
ctx->last_timestamp = le16_to_cpu(last->res_count);
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 8e77c02edb2..ff080ee2019 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -535,11 +535,12 @@ static struct attribute *dcdbas_dev_attrs[] = {
static struct attribute_group dcdbas_attr_group = {
.attrs = dcdbas_dev_attrs,
+ .bin_attrs = dcdbas_bin_attrs,
};
static int dcdbas_probe(struct platform_device *dev)
{
- int i, error;
+ int error;
host_control_action = HC_ACTION_NONE;
host_control_smi_type = HC_SMITYPE_NONE;
@@ -555,18 +556,6 @@ static int dcdbas_probe(struct platform_device *dev)
if (error)
return error;
- for (i = 0; dcdbas_bin_attrs[i]; i++) {
- error = sysfs_create_bin_file(&dev->dev.kobj,
- dcdbas_bin_attrs[i]);
- if (error) {
- while (--i >= 0)
- sysfs_remove_bin_file(&dev->dev.kobj,
- dcdbas_bin_attrs[i]);
- sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group);
- return error;
- }
- }
-
register_reboot_notifier(&dcdbas_reboot_nb);
dev_info(&dev->dev, "%s (version %s)\n",
@@ -577,11 +566,7 @@ static int dcdbas_probe(struct platform_device *dev)
static int dcdbas_remove(struct platform_device *dev)
{
- int i;
-
unregister_reboot_notifier(&dcdbas_reboot_nb);
- for (i = 0; dcdbas_bin_attrs[i]; i++)
- sysfs_remove_bin_file(&dev->dev.kobj, dcdbas_bin_attrs[i]);
sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group);
return 0;
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index eb760a218da..232fa8fce26 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -419,6 +419,13 @@ static void __init dmi_format_ids(char *buf, size_t len)
dmi_get_system_info(DMI_BIOS_DATE));
}
+/*
+ * Check for DMI/SMBIOS headers in the system firmware image. Any
+ * SMBIOS header must start 16 bytes before the DMI header, so take a
+ * 32 byte buffer and check for DMI at offset 16 and SMBIOS at offset
+ * 0. If the DMI header is present, set dmi_ver accordingly (SMBIOS
+ * takes precedence) and return 0. Otherwise return 1.
+ */
static int __init dmi_present(const u8 *buf)
{
int smbios_ver;
@@ -506,6 +513,13 @@ void __init dmi_scan_machine(void)
if (p == NULL)
goto error;
+ /*
+ * Iterate over all possible DMI header addresses q.
+ * Maintain the 32 bytes around q in buf. On the
+ * first iteration, substitute zero for the
+ * out-of-range bytes so there is no chance of falsely
+ * detecting an SMBIOS header.
+ */
memset(buf, 0, 16);
for (q = p; q < p + 0x10000; q += 16) {
memcpy_fromio(buf + 16, q, 16);
diff --git a/drivers/fmc/fmc-chardev.c b/drivers/fmc/fmc-chardev.c
index cc031db2d2a..ace6ef24d15 100644
--- a/drivers/fmc/fmc-chardev.c
+++ b/drivers/fmc/fmc-chardev.c
@@ -143,18 +143,17 @@ static int fc_probe(struct fmc_device *fmc)
fc->misc.fops = &fc_fops;
fc->misc.name = kstrdup(dev_name(&fmc->dev), GFP_KERNEL);
- spin_lock(&fc_lock);
ret = misc_register(&fc->misc);
if (ret < 0)
- goto err_unlock;
+ goto out;
+ spin_lock(&fc_lock);
list_add(&fc->list, &fc_devices);
spin_unlock(&fc_lock);
dev_info(&fc->fmc->dev, "Created misc device \"%s\"\n",
fc->misc.name);
return 0;
-err_unlock:
- spin_unlock(&fc_lock);
+out:
kfree(fc->misc.name);
kfree(fc);
return ret;
@@ -174,10 +173,10 @@ static int fc_remove(struct fmc_device *fmc)
spin_lock(&fc_lock);
list_del(&fc->list);
+ spin_unlock(&fc_lock);
misc_deregister(&fc->misc);
kfree(fc->misc.name);
kfree(fc);
- spin_unlock(&fc_lock);
return 0;
}
diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c
index 2cc680dd604..ee5b4790413 100644
--- a/drivers/fmc/fmc-write-eeprom.c
+++ b/drivers/fmc/fmc-write-eeprom.c
@@ -103,7 +103,7 @@ static int fwe_run(struct fmc_device *fmc, const struct firmware *fw, char *s)
* difficult to know in advance when probing the first card if others
* are there.
*/
-int fwe_probe(struct fmc_device *fmc)
+static int fwe_probe(struct fmc_device *fmc)
{
int err, index = 0;
const struct firmware *fw;
@@ -144,7 +144,7 @@ int fwe_probe(struct fmc_device *fmc)
return 0;
}
-int fwe_remove(struct fmc_device *fmc)
+static int fwe_remove(struct fmc_device *fmc)
{
return 0;
}
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
index e3ceaacde45..73b73969d36 100644
--- a/drivers/gpio/gpio-msm-v1.c
+++ b/drivers/gpio/gpio-msm-v1.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/err.h>
#include <mach/msm_gpiomux.h>
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index f4491a497cc..c2fa77086eb 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -378,7 +378,7 @@ static int msm_gpio_probe(struct platform_device *pdev)
int ret, ngpio;
struct resource *res;
- if (!of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio)) {
+ if (of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio)) {
dev_err(&pdev->dev, "%s: ngpio property missing\n", __func__);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c
index 98d670825a1..6e8887fe6c1 100644
--- a/drivers/gpu/drm/ast/ast_ttm.c
+++ b/drivers/gpu/drm/ast/ast_ttm.c
@@ -323,6 +323,7 @@ int ast_bo_create(struct drm_device *dev, int size, int align,
astbo->gem.driver_private = NULL;
astbo->bo.bdev = &ast->ttm.bdev;
+ astbo->bo.bdev->dev_mapping = dev->dev_mapping;
ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c
index 0047012045c..69fd8f1ac8d 100644
--- a/drivers/gpu/drm/cirrus/cirrus_ttm.c
+++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c
@@ -328,6 +328,7 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align,
cirrusbo->gem.driver_private = NULL;
cirrusbo->bo.bdev = &cirrus->ttm.bdev;
+ cirrusbo->bo.bdev->dev_mapping = dev->dev_mapping;
cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 738a4294d82..6a647493ca7 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -677,6 +677,11 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
/* don't break so fail path works correct */
fail = 1;
break;
+
+ if (connector->dpms != DRM_MODE_DPMS_ON) {
+ DRM_DEBUG_KMS("connector dpms not on, full mode switch\n");
+ mode_changed = true;
+ }
}
}
@@ -754,6 +759,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
ret = -EINVAL;
goto fail;
}
+ DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+ for (i = 0; i < set->num_connectors; i++) {
+ DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+ drm_get_connector_name(set->connectors[i]));
+ set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
+ }
}
drm_helper_disable_unused_functions(dev);
} else if (fb_changed) {
@@ -771,22 +782,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
}
}
- /*
- * crtc set_config helpers implicit set the crtc and all connected
- * encoders to DPMS on for a full mode set. But for just an fb update it
- * doesn't do that. To not confuse userspace, do an explicit DPMS_ON
- * unconditionally. This will also ensure driver internal dpms state is
- * consistent again.
- */
- if (set->crtc->enabled) {
- DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
- for (i = 0; i < set->num_connectors; i++) {
- DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
- drm_get_connector_name(set->connectors[i]));
- set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
- }
- }
-
kfree(save_connectors);
kfree(save_encoders);
kfree(save_crtcs);
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 8bcce7866d3..f92da0a32f0 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -708,7 +708,10 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
/* Subtract time delta from raw timestamp to get final
* vblank_time timestamp for end of vblank.
*/
- etime = ktime_sub_ns(etime, delta_ns);
+ if (delta_ns < 0)
+ etime = ktime_add_ns(etime, -delta_ns);
+ else
+ etime = ktime_sub_ns(etime, delta_ns);
*vblank_time = ktime_to_timeval(etime);
DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c
index 95c75edef01..30ef41bcd7b 100644
--- a/drivers/gpu/drm/exynos/exynos_ddc.c
+++ b/drivers/gpu/drm/exynos/exynos_ddc.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
-#include <linux/module.h>
#include "exynos_drm_drv.h"
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 61b094f689a..6e047bd53e2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -12,7 +12,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 3e106beca5b..1c263dac3c1 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -14,7 +14,6 @@
#include <drm/drmP.h>
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/of_device.h>
@@ -130,7 +129,6 @@ static const struct of_device_id fimd_driver_dt_match[] = {
.data = &exynos5_fimd_driver_data },
{},
};
-MODULE_DEVICE_TABLE(of, fimd_driver_dt_match);
#endif
static inline struct fimd_driver_data *drm_fimd_get_driver_data(
@@ -1082,7 +1080,6 @@ static struct platform_device_id fimd_driver_ids[] = {
},
{},
};
-MODULE_DEVICE_TABLE(platform, fimd_driver_ids);
static const struct dev_pm_ops fimd_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 42a5a546607..eddea494148 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -8,7 +8,6 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/interrupt.h>
@@ -806,9 +805,20 @@ static void g2d_dma_start(struct g2d_data *g2d,
struct g2d_cmdlist_node *node =
list_first_entry(&runqueue_node->run_cmdlist,
struct g2d_cmdlist_node, list);
+ int ret;
+
+ ret = pm_runtime_get_sync(g2d->dev);
+ if (ret < 0) {
+ dev_warn(g2d->dev, "failed pm power on.\n");
+ return;
+ }
- pm_runtime_get_sync(g2d->dev);
- clk_enable(g2d->gate_clk);
+ ret = clk_prepare_enable(g2d->gate_clk);
+ if (ret < 0) {
+ dev_warn(g2d->dev, "failed to enable clock.\n");
+ pm_runtime_put_sync(g2d->dev);
+ return;
+ }
writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR);
writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND);
@@ -861,7 +871,7 @@ static void g2d_runqueue_worker(struct work_struct *work)
runqueue_work);
mutex_lock(&g2d->runqueue_mutex);
- clk_disable(g2d->gate_clk);
+ clk_disable_unprepare(g2d->gate_clk);
pm_runtime_put_sync(g2d->dev);
complete(&g2d->runqueue_node->complete);
@@ -1521,7 +1531,6 @@ static const struct of_device_id exynos_g2d_match[] = {
{ .compatible = "samsung,exynos5250-g2d" },
{},
};
-MODULE_DEVICE_TABLE(of, exynos_g2d_match);
#endif
struct platform_driver g2d_driver = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 472e3b25e7f..90b8a1a5344 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -12,7 +12,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index aaa550d622f..8d3bc01d683 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/wait.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index b1ef8e7ff9c..d2b6ab4def9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -12,7 +12,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/clk.h>
@@ -342,10 +341,10 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
*/
ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock,
prop_list->ipp_id);
- if (!ippdrv) {
+ if (IS_ERR(ippdrv)) {
DRM_ERROR("not found ipp%d driver.\n",
prop_list->ipp_id);
- return -EINVAL;
+ return PTR_ERR(ippdrv);
}
prop_list = ippdrv->prop_list;
@@ -970,9 +969,9 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
/* find command node */
c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
qbuf->prop_id);
- if (!c_node) {
+ if (IS_ERR(c_node)) {
DRM_ERROR("failed to get command node.\n");
- return -EFAULT;
+ return PTR_ERR(c_node);
}
/* buffer control */
@@ -1106,9 +1105,9 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
cmd_ctrl->prop_id);
- if (!c_node) {
+ if (IS_ERR(c_node)) {
DRM_ERROR("invalid command node list.\n");
- return -EINVAL;
+ return PTR_ERR(c_node);
}
if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index 427640aa514..49669aa24c4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -10,7 +10,6 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 41cc74d83e4..c57c56519ad 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -13,7 +13,6 @@
#include <drm/drmP.h>
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
#include <drm/exynos_drm.h>
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 62ef5971ac3..2f5c6942c96 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -24,7 +24,6 @@
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/i2c.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
index ef04255076c..6e320ae9afe 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
-#include <linux/module.h>
#include "exynos_drm_drv.h"
#include "exynos_hdmi.h"
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 42ffb71c63b..c9a137caea4 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -23,7 +23,6 @@
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/i2c.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 19e36603b23..3bc8414533c 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -500,7 +500,8 @@ static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo,
&status))
goto log_fail;
- while (status == SDVO_CMD_STATUS_PENDING && retry--) {
+ while ((status == SDVO_CMD_STATUS_PENDING ||
+ status == SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED) && retry--) {
udelay(15);
if (!psb_intel_sdvo_read_byte(psb_intel_sdvo,
SDVO_I2C_CMD_STATUS,
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index cf188ab7051..f4669802a0f 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1495,6 +1495,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv->dev = dev;
dev_priv->info = info;
+ spin_lock_init(&dev_priv->irq_lock);
+ spin_lock_init(&dev_priv->gpu_error.lock);
+ spin_lock_init(&dev_priv->rps.lock);
+ spin_lock_init(&dev_priv->gt_lock);
+ spin_lock_init(&dev_priv->backlight.lock);
+ mutex_init(&dev_priv->dpio_lock);
+ mutex_init(&dev_priv->rps.hw_lock);
+ mutex_init(&dev_priv->modeset_restore_lock);
+
i915_dump_device_info(dev_priv);
if (i915_get_bridge_dev(dev)) {
@@ -1585,6 +1594,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
intel_detect_pch(dev);
intel_irq_init(dev);
+ intel_pm_init(dev);
+ intel_gt_sanitize(dev);
intel_gt_init(dev);
/* Try to make sure MCHBAR is enabled before poking at it */
@@ -1610,15 +1621,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (!IS_I945G(dev) && !IS_I945GM(dev))
pci_enable_msi(dev->pdev);
- spin_lock_init(&dev_priv->irq_lock);
- spin_lock_init(&dev_priv->gpu_error.lock);
- spin_lock_init(&dev_priv->rps.lock);
- spin_lock_init(&dev_priv->backlight.lock);
- mutex_init(&dev_priv->dpio_lock);
-
- mutex_init(&dev_priv->rps.hw_lock);
- mutex_init(&dev_priv->modeset_restore_lock);
-
dev_priv->num_plane = 1;
if (IS_VALLEYVIEW(dev))
dev_priv->num_plane = 2;
@@ -1648,7 +1650,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (INTEL_INFO(dev)->num_pipes) {
/* Must be done after probing outputs */
intel_opregion_init(dev);
- acpi_video_register_with_quirks();
+ acpi_video_register();
}
if (IS_GEN5(dev))
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index f4af1ca0fb6..45b3c030f48 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -706,7 +706,7 @@ static int i915_drm_thaw(struct drm_device *dev)
{
int error = 0;
- intel_gt_reset(dev);
+ intel_gt_sanitize(dev);
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
mutex_lock(&dev->struct_mutex);
@@ -732,7 +732,7 @@ int i915_resume(struct drm_device *dev)
pci_set_master(dev->pdev);
- intel_gt_reset(dev);
+ intel_gt_sanitize(dev);
/*
* Platforms with opregion should have sane BIOS, older ones (gen3 and
@@ -1253,21 +1253,21 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
#define __i915_read(x, y) \
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
+ unsigned long irqflags; \
u##x val = 0; \
+ spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
if (IS_GEN5(dev_priv->dev)) \
ilk_dummy_write(dev_priv); \
if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
- unsigned long irqflags; \
- spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
if (dev_priv->forcewake_count == 0) \
dev_priv->gt.force_wake_get(dev_priv); \
val = read##y(dev_priv->regs + reg); \
if (dev_priv->forcewake_count == 0) \
dev_priv->gt.force_wake_put(dev_priv); \
- spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
} else { \
val = read##y(dev_priv->regs + reg); \
} \
+ spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
trace_i915_reg_rw(false, reg, val, sizeof(val)); \
return val; \
}
@@ -1280,8 +1280,10 @@ __i915_read(64, q)
#define __i915_write(x, y) \
void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
+ unsigned long irqflags; \
u32 __fifo_ret = 0; \
trace_i915_reg_rw(true, reg, val, sizeof(val)); \
+ spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
} \
@@ -1293,6 +1295,7 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
gen6_gt_check_fifodbg(dev_priv); \
} \
hsw_unclaimed_reg_check(dev_priv, reg); \
+ spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
}
__i915_write(8, b)
__i915_write(16, w)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a416645bcd2..1929bffc1c7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -555,6 +555,7 @@ enum intel_sbi_destination {
#define QUIRK_PIPEA_FORCE (1<<0)
#define QUIRK_LVDS_SSC_DISABLE (1<<1)
#define QUIRK_INVERT_BRIGHTNESS (1<<2)
+#define QUIRK_NO_PCH_PWM_ENABLE (1<<3)
struct intel_fbdev;
struct intel_fbc_work;
@@ -1581,9 +1582,10 @@ void i915_hangcheck_elapsed(unsigned long data);
void i915_handle_error(struct drm_device *dev, bool wedged);
extern void intel_irq_init(struct drm_device *dev);
+extern void intel_pm_init(struct drm_device *dev);
extern void intel_hpd_init(struct drm_device *dev);
extern void intel_gt_init(struct drm_device *dev);
-extern void intel_gt_reset(struct drm_device *dev);
+extern void intel_gt_sanitize(struct drm_device *dev);
void i915_error_state_free(struct kref *error_ref);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 97afd2639fb..d9e2208cfe9 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2258,7 +2258,17 @@ void i915_gem_restore_fences(struct drm_device *dev)
for (i = 0; i < dev_priv->num_fence_regs; i++) {
struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
- i915_gem_write_fence(dev, i, reg->obj);
+
+ /*
+ * Commit delayed tiling changes if we have an object still
+ * attached to the fence, otherwise just clear the fence.
+ */
+ if (reg->obj) {
+ i915_gem_object_update_fence(reg->obj, reg,
+ reg->obj->tiling_mode);
+ } else {
+ i915_gem_write_fence(dev, i, NULL);
+ }
}
}
@@ -2795,6 +2805,10 @@ static void i915_gem_write_fence(struct drm_device *dev, int reg,
if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj))
mb();
+ WARN(obj && (!obj->stride || !obj->tiling_mode),
+ "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
+ obj->stride, obj->tiling_mode);
+
switch (INTEL_INFO(dev)->gen) {
case 7:
case 6:
@@ -2836,6 +2850,7 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
fence->obj = NULL;
list_del_init(&fence->lru_list);
}
+ obj->fence_dirty = false;
}
static int
@@ -2965,7 +2980,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
return 0;
i915_gem_object_update_fence(obj, reg, enable);
- obj->fence_dirty = false;
return 0;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
index dc53a527126..9e657833080 100644
--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
@@ -85,9 +85,17 @@ static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
struct sg_table *sg,
enum dma_data_direction dir)
{
+ struct drm_i915_gem_object *obj = attachment->dmabuf->priv;
+
+ mutex_lock(&obj->base.dev->struct_mutex);
+
dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
sg_free_table(sg);
kfree(sg);
+
+ i915_gem_object_unpin_pages(obj);
+
+ mutex_unlock(&obj->base.dev->struct_mutex);
}
static void i915_gem_dmabuf_release(struct dma_buf *dma_buf)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index f2326fc60ac..342f1f33616 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -752,6 +752,8 @@
will not assert AGPBUSY# and will only
be delivered when out of C3. */
#define INSTPM_FORCE_ORDERING (1<<7) /* GEN6+ */
+#define INSTPM_TLB_INVALIDATE (1<<9)
+#define INSTPM_SYNC_FLUSH (1<<5)
#define ACTHD 0x020c8
#define FW_BLC 0x020d8
#define FW_BLC2 0x020dc
@@ -1856,10 +1858,16 @@
#define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2)
#define PORT_HOTPLUG_STAT (dev_priv->info->display_mmio_offset + 0x61114)
-/* HDMI/DP bits are gen4+ */
-#define PORTB_HOTPLUG_LIVE_STATUS (1 << 29)
+/*
+ * HDMI/DP bits are gen4+
+ *
+ * WARNING: Bspec for hpd status bits on gen4 seems to be completely confused.
+ * Please check the detailed lore in the commit message for for experimental
+ * evidence.
+ */
+#define PORTD_HOTPLUG_LIVE_STATUS (1 << 29)
#define PORTC_HOTPLUG_LIVE_STATUS (1 << 28)
-#define PORTD_HOTPLUG_LIVE_STATUS (1 << 27)
+#define PORTB_HOTPLUG_LIVE_STATUS (1 << 27)
#define PORTD_HOTPLUG_INT_STATUS (3 << 21)
#define PORTC_HOTPLUG_INT_STATUS (3 << 19)
#define PORTB_HOTPLUG_INT_STATUS (3 << 17)
@@ -4432,7 +4440,7 @@
#define EDP_LINK_TRAIN_600MV_0DB_IVB (0x30 <<22)
#define EDP_LINK_TRAIN_600MV_3_5DB_IVB (0x36 <<22)
#define EDP_LINK_TRAIN_800MV_0DB_IVB (0x38 <<22)
-#define EDP_LINK_TRAIN_800MV_3_5DB_IVB (0x33 <<22)
+#define EDP_LINK_TRAIN_800MV_3_5DB_IVB (0x3e <<22)
/* legacy values */
#define EDP_LINK_TRAIN_500MV_0DB_IVB (0x00 <<22)
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 324211ac9c5..b042ee5c407 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -301,7 +301,7 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder,
struct intel_digital_port *intel_dig_port =
enc_to_dig_port(encoder);
- intel_dp->DP = intel_dig_port->port_reversal |
+ intel_dp->DP = intel_dig_port->saved_port_bits |
DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW;
intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
@@ -1109,7 +1109,8 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
* enabling the port.
*/
I915_WRITE(DDI_BUF_CTL(port),
- intel_dig_port->port_reversal | DDI_BUF_CTL_ENABLE);
+ intel_dig_port->saved_port_bits |
+ DDI_BUF_CTL_ENABLE);
} else if (type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -1347,8 +1348,9 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
intel_encoder->get_config = intel_ddi_get_config;
intel_dig_port->port = port;
- intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) &
- DDI_BUF_PORT_REVERSAL;
+ intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
+ (DDI_BUF_PORT_REVERSAL |
+ DDI_A_4_LANES);
intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);
intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 85f3eb74d2b..be79f477a38 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4913,22 +4913,19 @@ static void i9xx_get_pfit_config(struct intel_crtc *crtc,
uint32_t tmp;
tmp = I915_READ(PFIT_CONTROL);
+ if (!(tmp & PFIT_ENABLE))
+ return;
+ /* Check whether the pfit is attached to our pipe. */
if (INTEL_INFO(dev)->gen < 4) {
if (crtc->pipe != PIPE_B)
return;
-
- /* gen2/3 store dither state in pfit control, needs to match */
- pipe_config->gmch_pfit.control = tmp & PANEL_8TO6_DITHER_ENABLE;
} else {
if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT))
return;
}
- if (!(tmp & PFIT_ENABLE))
- return;
-
- pipe_config->gmch_pfit.control = I915_READ(PFIT_CONTROL);
+ pipe_config->gmch_pfit.control = tmp;
pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS);
if (INTEL_INFO(dev)->gen < 5)
pipe_config->gmch_pfit.lvds_border_bits =
@@ -8272,9 +8269,11 @@ check_crtc_state(struct drm_device *dev)
list_for_each_entry(encoder, &dev->mode_config.encoder_list,
base.head) {
+ enum pipe pipe;
if (encoder->base.crtc != &crtc->base)
continue;
- if (encoder->get_config)
+ if (encoder->get_config &&
+ encoder->get_hw_state(encoder, &pipe))
encoder->get_config(encoder, &pipe_config);
}
@@ -8317,6 +8316,8 @@ check_shared_dpll_state(struct drm_device *dev)
pll->active, pll->refcount);
WARN(pll->active && !pll->on,
"pll in active use but not on in sw tracking\n");
+ WARN(pll->on && !pll->active,
+ "pll in on but not on in use in sw tracking\n");
WARN(pll->on != active,
"pll on state mismatch (expected %i, found %i)\n",
pll->on, active);
@@ -8541,15 +8542,20 @@ static void intel_set_config_restore_state(struct drm_device *dev,
}
static bool
-is_crtc_connector_off(struct drm_crtc *crtc, struct drm_connector *connectors,
- int num_connectors)
+is_crtc_connector_off(struct drm_mode_set *set)
{
int i;
- for (i = 0; i < num_connectors; i++)
- if (connectors[i].encoder &&
- connectors[i].encoder->crtc == crtc &&
- connectors[i].dpms != DRM_MODE_DPMS_ON)
+ if (set->num_connectors == 0)
+ return false;
+
+ if (WARN_ON(set->connectors == NULL))
+ return false;
+
+ for (i = 0; i < set->num_connectors; i++)
+ if (set->connectors[i]->encoder &&
+ set->connectors[i]->encoder->crtc == set->crtc &&
+ set->connectors[i]->dpms != DRM_MODE_DPMS_ON)
return true;
return false;
@@ -8562,10 +8568,8 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
/* We should be able to check here if the fb has the same properties
* and then just flip_or_move it */
- if (set->connectors != NULL &&
- is_crtc_connector_off(set->crtc, *set->connectors,
- set->num_connectors)) {
- config->mode_changed = true;
+ if (is_crtc_connector_off(set)) {
+ config->mode_changed = true;
} else if (set->crtc->fb != set->fb) {
/* If we have no fb then treat it as a full mode set */
if (set->crtc->fb == NULL) {
@@ -9398,6 +9402,17 @@ static void quirk_invert_brightness(struct drm_device *dev)
DRM_INFO("applying inverted panel brightness quirk\n");
}
+/*
+ * Some machines (Dell XPS13) suffer broken backlight controls if
+ * BLM_PCH_PWM_ENABLE is set.
+ */
+static void quirk_no_pcm_pwm_enable(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ dev_priv->quirks |= QUIRK_NO_PCH_PWM_ENABLE;
+ DRM_INFO("applying no-PCH_PWM_ENABLE quirk\n");
+}
+
struct intel_quirk {
int device;
int subsystem_vendor;
@@ -9467,6 +9482,11 @@ static struct intel_quirk intel_quirks[] = {
/* Acer Aspire 4736Z */
{ 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
+
+ /* Dell XPS13 HD Sandy Bridge */
+ { 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable },
+ /* Dell XPS13 HD and XPS13 FHD Ivy Bridge */
+ { 0x0166, 0x1028, 0x058b, quirk_no_pcm_pwm_enable },
};
static void intel_init_quirks(struct drm_device *dev)
@@ -9817,8 +9837,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
}
pll->refcount = pll->active;
- DRM_DEBUG_KMS("%s hw state readout: refcount %i\n",
- pll->name, pll->refcount);
+ DRM_DEBUG_KMS("%s hw state readout: refcount %i, on %i\n",
+ pll->name, pll->refcount, pll->on);
}
list_for_each_entry(encoder, &dev->mode_config.encoder_list,
@@ -9869,6 +9889,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
struct drm_plane *plane;
struct intel_crtc *crtc;
struct intel_encoder *encoder;
+ int i;
intel_modeset_readout_hw_state(dev);
@@ -9884,6 +9905,18 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]");
}
+ for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
+
+ if (!pll->on || pll->active)
+ continue;
+
+ DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", pll->name);
+
+ pll->disable(dev_priv, pll);
+ pll->on = false;
+ }
+
if (force_restore) {
/*
* We need to use raw interfaces for restoring state to avoid
@@ -10009,6 +10042,8 @@ struct intel_display_error_state {
u32 power_well_driver;
+ int num_transcoders;
+
struct intel_cursor_error_state {
u32 control;
u32 position;
@@ -10017,16 +10052,7 @@ struct intel_display_error_state {
} cursor[I915_MAX_PIPES];
struct intel_pipe_error_state {
- enum transcoder cpu_transcoder;
- u32 conf;
u32 source;
-
- u32 htotal;
- u32 hblank;
- u32 hsync;
- u32 vtotal;
- u32 vblank;
- u32 vsync;
} pipe[I915_MAX_PIPES];
struct intel_plane_error_state {
@@ -10038,6 +10064,19 @@ struct intel_display_error_state {
u32 surface;
u32 tile_offset;
} plane[I915_MAX_PIPES];
+
+ struct intel_transcoder_error_state {
+ enum transcoder cpu_transcoder;
+
+ u32 conf;
+
+ u32 htotal;
+ u32 hblank;
+ u32 hsync;
+ u32 vtotal;
+ u32 vblank;
+ u32 vsync;
+ } transcoder[4];
};
struct intel_display_error_state *
@@ -10045,9 +10084,17 @@ intel_display_capture_error_state(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_display_error_state *error;
- enum transcoder cpu_transcoder;
+ int transcoders[] = {
+ TRANSCODER_A,
+ TRANSCODER_B,
+ TRANSCODER_C,
+ TRANSCODER_EDP,
+ };
int i;
+ if (INTEL_INFO(dev)->num_pipes == 0)
+ return NULL;
+
error = kmalloc(sizeof(*error), GFP_ATOMIC);
if (error == NULL)
return NULL;
@@ -10056,9 +10103,6 @@ intel_display_capture_error_state(struct drm_device *dev)
error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER);
for_each_pipe(i) {
- cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i);
- error->pipe[i].cpu_transcoder = cpu_transcoder;
-
if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) {
error->cursor[i].control = I915_READ(CURCNTR(i));
error->cursor[i].position = I915_READ(CURPOS(i));
@@ -10082,14 +10126,25 @@ intel_display_capture_error_state(struct drm_device *dev)
error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i));
}
- error->pipe[i].conf = I915_READ(PIPECONF(cpu_transcoder));
error->pipe[i].source = I915_READ(PIPESRC(i));
- error->pipe[i].htotal = I915_READ(HTOTAL(cpu_transcoder));
- error->pipe[i].hblank = I915_READ(HBLANK(cpu_transcoder));
- error->pipe[i].hsync = I915_READ(HSYNC(cpu_transcoder));
- error->pipe[i].vtotal = I915_READ(VTOTAL(cpu_transcoder));
- error->pipe[i].vblank = I915_READ(VBLANK(cpu_transcoder));
- error->pipe[i].vsync = I915_READ(VSYNC(cpu_transcoder));
+ }
+
+ error->num_transcoders = INTEL_INFO(dev)->num_pipes;
+ if (HAS_DDI(dev_priv->dev))
+ error->num_transcoders++; /* Account for eDP. */
+
+ for (i = 0; i < error->num_transcoders; i++) {
+ enum transcoder cpu_transcoder = transcoders[i];
+
+ error->transcoder[i].cpu_transcoder = cpu_transcoder;
+
+ error->transcoder[i].conf = I915_READ(PIPECONF(cpu_transcoder));
+ error->transcoder[i].htotal = I915_READ(HTOTAL(cpu_transcoder));
+ error->transcoder[i].hblank = I915_READ(HBLANK(cpu_transcoder));
+ error->transcoder[i].hsync = I915_READ(HSYNC(cpu_transcoder));
+ error->transcoder[i].vtotal = I915_READ(VTOTAL(cpu_transcoder));
+ error->transcoder[i].vblank = I915_READ(VBLANK(cpu_transcoder));
+ error->transcoder[i].vsync = I915_READ(VSYNC(cpu_transcoder));
}
/* In the code above we read the registers without checking if the power
@@ -10111,22 +10166,16 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
{
int i;
+ if (!error)
+ return;
+
err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes);
if (HAS_POWER_WELL(dev))
err_printf(m, "PWR_WELL_CTL2: %08x\n",
error->power_well_driver);
for_each_pipe(i) {
err_printf(m, "Pipe [%d]:\n", i);
- err_printf(m, " CPU transcoder: %c\n",
- transcoder_name(error->pipe[i].cpu_transcoder));
- err_printf(m, " CONF: %08x\n", error->pipe[i].conf);
err_printf(m, " SRC: %08x\n", error->pipe[i].source);
- err_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal);
- err_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank);
- err_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync);
- err_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal);
- err_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank);
- err_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync);
err_printf(m, "Plane [%d]:\n", i);
err_printf(m, " CNTR: %08x\n", error->plane[i].control);
@@ -10147,5 +10196,17 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
err_printf(m, " POS: %08x\n", error->cursor[i].position);
err_printf(m, " BASE: %08x\n", error->cursor[i].base);
}
+
+ for (i = 0; i < error->num_transcoders; i++) {
+ err_printf(m, " CPU transcoder: %c\n",
+ transcoder_name(error->transcoder[i].cpu_transcoder));
+ err_printf(m, " CONF: %08x\n", error->transcoder[i].conf);
+ err_printf(m, " HTOTAL: %08x\n", error->transcoder[i].htotal);
+ err_printf(m, " HBLANK: %08x\n", error->transcoder[i].hblank);
+ err_printf(m, " HSYNC: %08x\n", error->transcoder[i].hsync);
+ err_printf(m, " VTOTAL: %08x\n", error->transcoder[i].vtotal);
+ err_printf(m, " VBLANK: %08x\n", error->transcoder[i].vblank);
+ err_printf(m, " VSYNC: %08x\n", error->transcoder[i].vsync);
+ }
}
#endif
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index c8c9b6f4823..b7d6e09456c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -504,7 +504,7 @@ struct intel_dp {
struct intel_digital_port {
struct intel_encoder base;
enum port port;
- u32 port_reversal;
+ u32 saved_port_bits;
struct intel_dp dp;
struct intel_hdmi hdmi;
};
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 98df2a0c85b..2fd3fd5b943 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -785,10 +785,22 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
}
}
+static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
+{
+ struct drm_device *dev = intel_hdmi_to_dev(hdmi);
+
+ if (IS_G4X(dev))
+ return 165000;
+ else if (IS_HASWELL(dev))
+ return 300000;
+ else
+ return 225000;
+}
+
static int intel_hdmi_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- if (mode->clock > 165000)
+ if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector)))
return MODE_CLOCK_HIGH;
if (mode->clock < 20000)
return MODE_CLOCK_LOW;
@@ -806,6 +818,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
struct drm_device *dev = encoder->base.dev;
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
int clock_12bpc = pipe_config->requested_mode.clock * 3 / 2;
+ int portclock_limit = hdmi_portclock_limit(intel_hdmi);
int desired_bpp;
if (intel_hdmi->color_range_auto) {
@@ -829,7 +842,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
* outputs. We also need to check that the higher clock still fits
* within limits.
*/
- if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= 225000
+ if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= portclock_limit
&& HAS_PCH_SPLIT(dev)) {
DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
desired_bpp = 12*3;
@@ -846,7 +859,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
pipe_config->pipe_bpp = desired_bpp;
}
- if (adjusted_mode->clock > 225000) {
+ if (adjusted_mode->clock > portclock_limit) {
DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n");
return false;
}
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 021e8daa022..61348eae2f0 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -109,6 +109,13 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
flags |= DRM_MODE_FLAG_PVSYNC;
pipe_config->adjusted_mode.flags |= flags;
+
+ /* gen2/3 store dither state in pfit control, needs to match */
+ if (INTEL_INFO(dev)->gen < 4) {
+ tmp = I915_READ(PFIT_CONTROL);
+
+ pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE;
+ }
}
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
@@ -290,14 +297,11 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
intel_pch_panel_fitting(intel_crtc, pipe_config,
intel_connector->panel.fitting_mode);
- return true;
} else {
intel_gmch_panel_fitting(intel_crtc, pipe_config,
intel_connector->panel.fitting_mode);
- }
- drm_mode_set_crtcinfo(adjusted_mode, 0);
- pipe_config->timings_set = true;
+ }
/*
* XXX: It would be nice to support lower refresh rates on the
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 80bea1d3209..5950888ae1d 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -194,6 +194,9 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
adjusted_mode->vdisplay == mode->vdisplay)
goto out;
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
+ pipe_config->timings_set = true;
+
switch (fitting_mode) {
case DRM_MODE_SCALE_CENTER:
/*
@@ -494,8 +497,11 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
goto out;
}
- /* scale to hardware */
- level = level * freq / max;
+ /* scale to hardware, but be careful to not overflow */
+ if (freq < max)
+ level = level * freq / max;
+ else
+ level = freq / max * level;
dev_priv->backlight.level = level;
if (dev_priv->backlight.device)
@@ -512,6 +518,17 @@ void intel_panel_disable_backlight(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long flags;
+ /*
+ * Do not disable backlight on the vgaswitcheroo path. When switching
+ * away from i915, the other client may depend on i915 to handle the
+ * backlight. This will leave the backlight on unnecessarily when
+ * another client is not activated.
+ */
+ if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) {
+ DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n");
+ return;
+ }
+
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
dev_priv->backlight.enabled = false;
@@ -580,7 +597,8 @@ void intel_panel_enable_backlight(struct drm_device *dev,
POSTING_READ(reg);
I915_WRITE(reg, tmp | BLM_PWM_ENABLE);
- if (HAS_PCH_SPLIT(dev)) {
+ if (HAS_PCH_SPLIT(dev) &&
+ !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) {
tmp = I915_READ(BLC_PWM_PCH_CTL1);
tmp |= BLM_PCH_PWM_ENABLE;
tmp &= ~BLM_PCH_OVERRIDE_ENABLE;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index d10e6735771..b0e4a0bd131 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -5063,8 +5063,26 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable)
}
} else {
if (enable_requested) {
+ unsigned long irqflags;
+ enum pipe p;
+
I915_WRITE(HSW_PWR_WELL_DRIVER, 0);
+ POSTING_READ(HSW_PWR_WELL_DRIVER);
DRM_DEBUG_KMS("Requesting to disable the power well\n");
+
+ /*
+ * After this, the registers on the pipes that are part
+ * of the power well will become zero, so we have to
+ * adjust our counters according to that.
+ *
+ * FIXME: Should we do this in general in
+ * drm_vblank_post_modeset?
+ */
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ for_each_pipe(p)
+ if (p != PIPE_A)
+ dev->last_vblank[p] = 0;
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
}
}
@@ -5476,7 +5494,7 @@ static void vlv_force_wake_put(struct drm_i915_private *dev_priv)
gen6_gt_check_fifodbg(dev_priv);
}
-void intel_gt_reset(struct drm_device *dev)
+void intel_gt_sanitize(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5487,16 +5505,16 @@ void intel_gt_reset(struct drm_device *dev)
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
__gen6_gt_force_wake_mt_reset(dev_priv);
}
+
+ /* BIOS often leaves RC6 enabled, but disable it for hw init */
+ if (INTEL_INFO(dev)->gen >= 6)
+ intel_disable_gt_powersave(dev);
}
void intel_gt_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- spin_lock_init(&dev_priv->gt_lock);
-
- intel_gt_reset(dev);
-
if (IS_VALLEYVIEW(dev)) {
dev_priv->gt.force_wake_get = vlv_force_wake_get;
dev_priv->gt.force_wake_put = vlv_force_wake_put;
@@ -5536,6 +5554,12 @@ void intel_gt_init(struct drm_device *dev)
dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get;
dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put;
}
+}
+
+void intel_pm_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
intel_gen6_powersave_work);
}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 664118d8c1d..079ef0129e7 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -968,6 +968,18 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
POSTING_READ(mmio);
+
+ /* Flush the TLB for this page */
+ if (INTEL_INFO(dev)->gen >= 6) {
+ u32 reg = RING_INSTPM(ring->mmio_base);
+ I915_WRITE(reg,
+ _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE |
+ INSTPM_SYNC_FLUSH));
+ if (wait_for((I915_READ(reg) & INSTPM_SYNC_FLUSH) == 0,
+ 1000))
+ DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n",
+ ring->name);
+ }
}
static int
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 251784aa222..503a414cbda 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -29,6 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->fb;
int i;
if (!crtc->enabled)
@@ -36,6 +37,28 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
WREG8(DAC_INDEX + MGA1064_INDEX, 0);
+ if (fb && fb->bits_per_pixel == 16) {
+ int inc = (fb->depth == 15) ? 8 : 4;
+ u8 r, b;
+ for (i = 0; i < MGAG200_LUT_SIZE; i += inc) {
+ if (fb->depth == 16) {
+ if (i > (MGAG200_LUT_SIZE >> 1)) {
+ r = b = 0;
+ } else {
+ r = mga_crtc->lut_r[i << 1];
+ b = mga_crtc->lut_b[i << 1];
+ }
+ } else {
+ r = mga_crtc->lut_r[i];
+ b = mga_crtc->lut_b[i];
+ }
+ /* VGA registers */
+ WREG8(DAC_INDEX + MGA1064_COL_PAL, r);
+ WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]);
+ WREG8(DAC_INDEX + MGA1064_COL_PAL, b);
+ }
+ return;
+ }
for (i = 0; i < MGAG200_LUT_SIZE; i++) {
/* VGA registers */
WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_r[i]);
@@ -877,7 +900,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
if (crtc->fb->bits_per_pixel == 24)
- pitch = pitch >> (4 - bppshift);
+ pitch = (pitch * 3) >> (4 - bppshift);
else
pitch = pitch >> (4 - bppshift);
@@ -1251,6 +1274,24 @@ static void mga_crtc_destroy(struct drm_crtc *crtc)
kfree(mga_crtc);
}
+static void mga_crtc_disable(struct drm_crtc *crtc)
+{
+ int ret;
+ DRM_DEBUG_KMS("\n");
+ mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+ if (crtc->fb) {
+ struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb);
+ struct drm_gem_object *obj = mga_fb->obj;
+ struct mgag200_bo *bo = gem_to_mga_bo(obj);
+ ret = mgag200_bo_reserve(bo, false);
+ if (ret)
+ return;
+ mgag200_bo_push_sysram(bo);
+ mgag200_bo_unreserve(bo);
+ }
+ crtc->fb = NULL;
+}
+
/* These provide the minimum set of functions required to handle a CRTC */
static const struct drm_crtc_funcs mga_crtc_funcs = {
.cursor_set = mga_crtc_cursor_set,
@@ -1261,6 +1302,7 @@ static const struct drm_crtc_funcs mga_crtc_funcs = {
};
static const struct drm_crtc_helper_funcs mga_helper_funcs = {
+ .disable = mga_crtc_disable,
.dpms = mga_crtc_dpms,
.mode_fixup = mga_crtc_mode_fixup,
.mode_set = mga_crtc_mode_set,
@@ -1581,6 +1623,8 @@ static struct drm_connector *mga_vga_init(struct drm_device *dev)
drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs);
+ drm_sysfs_connector_add(connector);
+
mga_connector->i2c = mgag200_i2c_create(dev);
if (!mga_connector->i2c)
DRM_ERROR("failed to add ddc bus\n");
diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c
index 3acb2b044c7..d70e4a92773 100644
--- a/drivers/gpu/drm/mgag200/mgag200_ttm.c
+++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c
@@ -323,6 +323,7 @@ int mgag200_bo_create(struct drm_device *dev, int size, int align,
mgabo->gem.driver_private = NULL;
mgabo->bo.bdev = &mdev->ttm.bdev;
+ mgabo->bo.bdev->dev_mapping = dev->dev_mapping;
mgag200_ttm_placement(mgabo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
@@ -353,6 +354,7 @@ int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr)
bo->pin_count++;
if (gpu_addr)
*gpu_addr = mgag200_bo_gpu_offset(bo);
+ return 0;
}
mgag200_ttm_placement(bo, pl_flag);
diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c
index d8291724dbd..7a4e0891c5f 100644
--- a/drivers/gpu/drm/nouveau/core/core/mm.c
+++ b/drivers/gpu/drm/nouveau/core/core/mm.c
@@ -98,6 +98,8 @@ nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
u32 splitoff;
u32 s, e;
+ BUG_ON(!type);
+
list_for_each_entry(this, &mm->free, fl_entry) {
e = this->offset + this->length;
s = this->offset;
@@ -162,6 +164,8 @@ nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
struct nouveau_mm_node *prev, *this, *next;
u32 mask = align - 1;
+ BUG_ON(!type);
+
list_for_each_entry_reverse(this, &mm->free, fl_entry) {
u32 e = this->offset + this->length;
u32 s = this->offset;
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
index 262c9f5f5f6..ce860de43e6 100644
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
@@ -90,6 +90,7 @@ nvc0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
nv_subdev(priv)->unit = 0x00008000;
+ nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nvc0_bsp_cclass;
nv_engine(priv)->sclass = nvc0_bsp_sclass;
return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
index c46882c8398..ba6aeca0285 100644
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
@@ -90,6 +90,7 @@ nve0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
nv_subdev(priv)->unit = 0x00008000;
+ nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nve0_bsp_cclass;
nv_engine(priv)->sclass = nve0_bsp_sclass;
return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
index 373dbcc523b..a19e7d79b84 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
@@ -36,6 +36,8 @@ nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
if (data && data[0]) {
for (i = 0; i < size; i++)
nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[i]);
+ for (; i < 0x60; i++)
+ nv_wr32(priv, 0x61c440 + soff, (i << 8));
nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
} else
if (data) {
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
index dc57e24fc1d..717639386ce 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
@@ -41,6 +41,8 @@ nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
if (data && data[0]) {
for (i = 0; i < size; i++)
nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[i]);
+ for (; i < 0x60; i++)
+ nv_wr32(priv, 0x10ec00 + soff, (i << 8));
nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
} else
if (data) {
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
index ab1e918469a..526b7524289 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
@@ -47,14 +47,8 @@ int
nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
{
struct nv50_disp_priv *priv = (void *)object->engine;
- struct nouveau_bios *bios = nouveau_bios(priv);
- const u16 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
const u8 head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
- const u8 link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR);
- const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
- struct dcb_output outp;
- u8 ver, hdr;
u32 data;
int ret = -EINVAL;
@@ -62,8 +56,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
return -EINVAL;
data = *(u32 *)args;
- if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
- return -ENODEV;
switch (mthd & ~0x3f) {
case NV50_DISP_SOR_PWR:
diff --git a/drivers/gpu/drm/nouveau/core/engine/falcon.c b/drivers/gpu/drm/nouveau/core/engine/falcon.c
index 3c7a31f7590..e03fc8e4dc1 100644
--- a/drivers/gpu/drm/nouveau/core/engine/falcon.c
+++ b/drivers/gpu/drm/nouveau/core/engine/falcon.c
@@ -23,6 +23,25 @@
#include <engine/falcon.h>
#include <subdev/timer.h>
+void
+nouveau_falcon_intr(struct nouveau_subdev *subdev)
+{
+ struct nouveau_falcon *falcon = (void *)subdev;
+ u32 dispatch = nv_ro32(falcon, 0x01c);
+ u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
+
+ if (intr & 0x00000010) {
+ nv_debug(falcon, "ucode halted\n");
+ nv_wo32(falcon, 0x004, 0x00000010);
+ intr &= ~0x00000010;
+ }
+
+ if (intr) {
+ nv_error(falcon, "unhandled intr 0x%08x\n", intr);
+ nv_wo32(falcon, 0x004, intr);
+ }
+}
+
u32
_nouveau_falcon_rd32(struct nouveau_object *object, u64 addr)
{
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
index 49ecbb859b2..c1900430130 100644
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
@@ -265,8 +265,8 @@ nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int
nv31_mpeg_init(struct nouveau_object *object)
{
- struct nouveau_engine *engine = nv_engine(object->engine);
- struct nv31_mpeg_priv *priv = (void *)engine;
+ struct nouveau_engine *engine = nv_engine(object);
+ struct nv31_mpeg_priv *priv = (void *)object;
struct nouveau_fb *pfb = nouveau_fb(object);
int ret, i;
@@ -284,7 +284,10 @@ nv31_mpeg_init(struct nouveau_object *object)
/* PMPEG init */
nv_wr32(priv, 0x00b32c, 0x00000000);
nv_wr32(priv, 0x00b314, 0x00000100);
- nv_wr32(priv, 0x00b220, nv44_graph_class(priv) ? 0x00000044 : 0x00000031);
+ if (nv_device(priv)->chipset >= 0x40 && nv44_graph_class(priv))
+ nv_wr32(priv, 0x00b220, 0x00000044);
+ else
+ nv_wr32(priv, 0x00b220, 0x00000031);
nv_wr32(priv, 0x00b300, 0x02001ec1);
nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
index f7c581ad199..dd6196072e9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
@@ -61,6 +61,7 @@ nv40_mpeg_context_ctor(struct nouveau_object *parent,
if (ret)
return ret;
+ nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
index 98072c1ff36..73719aaa62d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
@@ -90,6 +90,7 @@ nvc0_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
nv_subdev(priv)->unit = 0x00000002;
+ nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nvc0_ppp_cclass;
nv_engine(priv)->sclass = nvc0_ppp_sclass;
return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
index 1879229b60e..ac1f62aace7 100644
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
@@ -90,6 +90,7 @@ nvc0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
nv_subdev(priv)->unit = 0x00020000;
+ nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nvc0_vp_cclass;
nv_engine(priv)->sclass = nvc0_vp_sclass;
return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
index d28ecbf7bc4..d4c3108479c 100644
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
@@ -90,6 +90,7 @@ nve0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
nv_subdev(priv)->unit = 0x00020000;
+ nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nve0_vp_cclass;
nv_engine(priv)->sclass = nve0_vp_sclass;
return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/xtensa.c b/drivers/gpu/drm/nouveau/core/engine/xtensa.c
index 0639bc59d0a..5f6ede7c489 100644
--- a/drivers/gpu/drm/nouveau/core/engine/xtensa.c
+++ b/drivers/gpu/drm/nouveau/core/engine/xtensa.c
@@ -118,7 +118,13 @@ _nouveau_xtensa_init(struct nouveau_object *object)
return ret;
}
- ret = nouveau_gpuobj_new(object, NULL, fw->size, 0x1000, 0,
+ if (fw->size > 0x40000) {
+ nv_warn(xtensa, "firmware %s too large\n", name);
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ ret = nouveau_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
&xtensa->gpu_fw);
if (ret) {
release_firmware(fw);
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/falcon.h b/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
index 1edec386ab3..181aa7da524 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
@@ -72,6 +72,8 @@ int nouveau_falcon_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, u32, bool, const char *,
const char *, int, void **);
+void nouveau_falcon_intr(struct nouveau_subdev *subdev);
+
#define _nouveau_falcon_dtor _nouveau_engine_dtor
int _nouveau_falcon_init(struct nouveau_object *);
int _nouveau_falcon_fini(struct nouveau_object *, bool);
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
index d5502267c30..9d2cd200625 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
@@ -20,8 +20,8 @@ nouveau_mc(void *obj)
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC];
}
-#define nouveau_mc_create(p,e,o,d) \
- nouveau_mc_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nouveau_mc_create(p,e,o,m,d) \
+ nouveau_mc_create_((p), (e), (o), (m), sizeof(**d), (void **)d)
#define nouveau_mc_destroy(p) ({ \
struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc)); \
})
@@ -33,7 +33,8 @@ nouveau_mc(void *obj)
})
int nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
+ struct nouveau_oclass *, const struct nouveau_mc_intr *,
+ int, void **);
void _nouveau_mc_dtor(struct nouveau_object *);
int _nouveau_mc_init(struct nouveau_object *);
int _nouveau_mc_fini(struct nouveau_object *, bool);
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
index f2e87b10566..fcf57fa309b 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
@@ -55,7 +55,7 @@ struct nouveau_vma {
struct nouveau_vm {
struct nouveau_vmmgr *vmm;
struct nouveau_mm mm;
- int refcount;
+ struct kref refcount;
struct list_head pgd_list;
atomic_t engref[NVDEV_SUBDEV_NR];
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
index 6c974dd83e8..db9d6ddde52 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
@@ -81,7 +81,7 @@ void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
+void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *);
extern int nv50_fb_memtype[0x80];
#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
index 19e3a9a63a0..ab7ef0ac9e3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
@@ -40,15 +40,15 @@ nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
switch (pfb914 & 0x00000003) {
- case 0x00000000: pfb->ram->type = NV_MEM_TYPE_DDR1; break;
- case 0x00000001: pfb->ram->type = NV_MEM_TYPE_DDR2; break;
- case 0x00000002: pfb->ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000000: ram->type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000001: ram->type = NV_MEM_TYPE_DDR2; break;
+ case 0x00000002: ram->type = NV_MEM_TYPE_GDDR3; break;
case 0x00000003: break;
}
- pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- pfb->ram->tags = nv_rd32(pfb, 0x100320);
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
index 7192aa6e557..63a6aab8602 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
@@ -38,8 +38,8 @@ nv4e_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram->type = NV_MEM_TYPE_STOLEN;
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->type = NV_MEM_TYPE_STOLEN;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
index af5aa7ee8ad..903baff77fd 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
@@ -27,17 +27,10 @@
#include "priv.h"
void
-nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+__nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem)
{
struct nouveau_mm_node *this;
- struct nouveau_mem *mem;
- mem = *pmem;
- *pmem = NULL;
- if (unlikely(mem == NULL))
- return;
-
- mutex_lock(&pfb->base.mutex);
while (!list_empty(&mem->regions)) {
this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
@@ -46,6 +39,19 @@ nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
}
nouveau_mm_free(&pfb->tags, &mem->tag);
+}
+
+void
+nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+ struct nouveau_mem *mem = *pmem;
+
+ *pmem = NULL;
+ if (unlikely(mem == NULL))
+ return;
+
+ mutex_lock(&pfb->base.mutex);
+ __nv50_ram_put(pfb, mem);
mutex_unlock(&pfb->base.mutex);
kfree(mem);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
index 9c3634acbb9..cf97c4de4a6 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
@@ -33,11 +33,19 @@ void
nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
{
struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+ struct nouveau_mem *mem = *pmem;
- if ((*pmem)->tag)
- ltcg->tags_free(ltcg, &(*pmem)->tag);
+ *pmem = NULL;
+ if (unlikely(mem == NULL))
+ return;
- nv50_ram_put(pfb, pmem);
+ mutex_lock(&pfb->base.mutex);
+ if (mem->tag)
+ ltcg->tags_free(ltcg, &mem->tag);
+ __nv50_ram_put(pfb, mem);
+ mutex_unlock(&pfb->base.mutex);
+
+ kfree(mem);
}
int
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
index bf489dcf46e..c4c1d415e7f 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
@@ -103,7 +103,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
int i;
intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
- if (nv_device(priv)->chipset >= 0x90)
+ if (nv_device(priv)->chipset > 0x92)
intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);
hi = (intr0 & 0x0000ffff) | (intr1 << 16);
@@ -115,7 +115,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
}
nv_wr32(priv, 0xe054, intr0);
- if (nv_device(priv)->chipset >= 0x90)
+ if (nv_device(priv)->chipset > 0x92)
nv_wr32(priv, 0xe074, intr1);
}
@@ -146,7 +146,7 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int ret;
ret = nouveau_gpio_create(parent, engine, oclass,
- nv_device(parent)->chipset >= 0x90 ? 32 : 16,
+ nv_device(parent)->chipset > 0x92 ? 32 : 16,
&priv);
*pobject = nv_object(priv);
if (ret)
@@ -182,7 +182,7 @@ nv50_gpio_init(struct nouveau_object *object)
/* disable, and ack any pending gpio interrupts */
nv_wr32(priv, 0xe050, 0x00000000);
nv_wr32(priv, 0xe054, 0xffffffff);
- if (nv_device(priv)->chipset >= 0x90) {
+ if (nv_device(priv)->chipset > 0x92) {
nv_wr32(priv, 0xe070, 0x00000000);
nv_wr32(priv, 0xe074, 0xffffffff);
}
@@ -195,7 +195,7 @@ nv50_gpio_fini(struct nouveau_object *object, bool suspend)
{
struct nv50_gpio_priv *priv = (void *)object;
nv_wr32(priv, 0xe050, 0x00000000);
- if (nv_device(priv)->chipset >= 0x90)
+ if (nv_device(priv)->chipset > 0x92)
nv_wr32(priv, 0xe070, 0x00000000);
return nouveau_gpio_fini(&priv->base, suspend);
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
index bcca883018f..cce65cc5651 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
@@ -30,8 +30,9 @@ struct nvc0_ltcg_priv {
struct nouveau_ltcg base;
u32 part_nr;
u32 subp_nr;
- struct nouveau_mm tags;
u32 num_tags;
+ u32 tag_base;
+ struct nouveau_mm tags;
struct nouveau_mm_node *tag_ram;
};
@@ -117,10 +118,6 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv)
u32 tag_size, tag_margin, tag_align;
int ret;
- nv_wr32(priv, 0x17e8d8, priv->part_nr);
- if (nv_device(pfb)->card_type >= NV_E0)
- nv_wr32(priv, 0x17e000, priv->part_nr);
-
/* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
priv->num_tags = (pfb->ram->size >> 17) / 4;
if (priv->num_tags > (1 << 17))
@@ -142,7 +139,7 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv)
tag_size += tag_align;
tag_size = (tag_size + 0xfff) >> 12; /* round up */
- ret = nouveau_mm_tail(&pfb->vram, 0, tag_size, tag_size, 1,
+ ret = nouveau_mm_tail(&pfb->vram, 1, tag_size, tag_size, 1,
&priv->tag_ram);
if (ret) {
priv->num_tags = 0;
@@ -152,7 +149,7 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv)
tag_base += tag_align - 1;
ret = do_div(tag_base, tag_align);
- nv_wr32(priv, 0x17e8d4, tag_base);
+ priv->tag_base = tag_base;
}
ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1);
@@ -182,8 +179,6 @@ nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
}
priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28;
- nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
-
ret = nvc0_ltcg_init_tag_ram(pfb, priv);
if (ret)
return ret;
@@ -209,13 +204,32 @@ nvc0_ltcg_dtor(struct nouveau_object *object)
nouveau_ltcg_destroy(ltcg);
}
+static int
+nvc0_ltcg_init(struct nouveau_object *object)
+{
+ struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
+ struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
+ int ret;
+
+ ret = nouveau_ltcg_init(ltcg);
+ if (ret)
+ return ret;
+
+ nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
+ nv_wr32(priv, 0x17e8d8, priv->part_nr);
+ if (nv_device(ltcg)->card_type >= NV_E0)
+ nv_wr32(priv, 0x17e000, priv->part_nr);
+ nv_wr32(priv, 0x17e8d4, priv->tag_base);
+ return 0;
+}
+
struct nouveau_oclass
nvc0_ltcg_oclass = {
.handle = NV_SUBDEV(LTCG, 0xc0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_ltcg_ctor,
.dtor = nvc0_ltcg_dtor,
- .init = _nouveau_ltcg_init,
+ .init = nvc0_ltcg_init,
.fini = _nouveau_ltcg_fini,
},
};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
index 1c0330b8c9a..ec9cd6f10f9 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
@@ -80,7 +80,9 @@ _nouveau_mc_dtor(struct nouveau_object *object)
int
nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int length, void **pobject)
+ struct nouveau_oclass *oclass,
+ const struct nouveau_mc_intr *intr_map,
+ int length, void **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nouveau_mc *pmc;
@@ -92,6 +94,8 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ pmc->intr_map = intr_map;
+
ret = request_irq(device->pdev->irq, nouveau_mc_intr,
IRQF_SHARED, "nouveau", pmc);
if (ret < 0)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
index 8c769715227..64aa4edb0d9 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
@@ -50,12 +50,11 @@ nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv04_mc_priv *priv;
int ret;
- ret = nouveau_mc_create(parent, engine, oclass, &priv);
+ ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
- priv->base.intr_map = nv04_mc_intr;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
index 51919371810..d9891782bf2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
@@ -36,12 +36,11 @@ nv44_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv44_mc_priv *priv;
int ret;
- ret = nouveau_mc_create(parent, engine, oclass, &priv);
+ ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
- priv->base.intr_map = nv04_mc_intr;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
index 0cb322a5e72..2b1afe225db 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
@@ -41,7 +41,7 @@ nv50_mc_intr[] = {
{ 0x04000000, NVDEV_ENGINE_DISP },
{ 0x10000000, NVDEV_SUBDEV_BUS },
{ 0x80000000, NVDEV_ENGINE_SW },
- { 0x0000d101, NVDEV_SUBDEV_FB },
+ { 0x0002d101, NVDEV_SUBDEV_FB },
{},
};
@@ -53,12 +53,11 @@ nv50_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv50_mc_priv *priv;
int ret;
- ret = nouveau_mc_create(parent, engine, oclass, &priv);
+ ret = nouveau_mc_create(parent, engine, oclass, nv50_mc_intr, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
- priv->base.intr_map = nv50_mc_intr;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
index e82fd21b504..0d57b4d3e00 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
@@ -54,12 +54,11 @@ nv98_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv98_mc_priv *priv;
int ret;
- ret = nouveau_mc_create(parent, engine, oclass, &priv);
+ ret = nouveau_mc_create(parent, engine, oclass, nv98_mc_intr, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
- priv->base.intr_map = nv98_mc_intr;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
index c5da3babbc6..104175c5a2d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
@@ -57,12 +57,11 @@ nvc0_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nvc0_mc_priv *priv;
int ret;
- ret = nouveau_mc_create(parent, engine, oclass, &priv);
+ ret = nouveau_mc_create(parent, engine, oclass, nvc0_mc_intr, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
- priv->base.intr_map = nvc0_mc_intr;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
index 67fcb6c852a..ef3133e7575 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
@@ -361,7 +361,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
INIT_LIST_HEAD(&vm->pgd_list);
vm->vmm = vmm;
- vm->refcount = 1;
+ kref_init(&vm->refcount);
vm->fpde = offset >> (vmm->pgt_bits + 12);
vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
@@ -441,8 +441,9 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
}
static void
-nouveau_vm_del(struct nouveau_vm *vm)
+nouveau_vm_del(struct kref *kref)
{
+ struct nouveau_vm *vm = container_of(kref, typeof(*vm), refcount);
struct nouveau_vm_pgd *vpgd, *tmp;
list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
@@ -458,27 +459,19 @@ int
nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
struct nouveau_gpuobj *pgd)
{
- struct nouveau_vm *vm;
- int ret;
-
- vm = ref;
- if (vm) {
- ret = nouveau_vm_link(vm, pgd);
+ if (ref) {
+ int ret = nouveau_vm_link(ref, pgd);
if (ret)
return ret;
- vm->refcount++;
+ kref_get(&ref->refcount);
}
- vm = *ptr;
- *ptr = ref;
-
- if (vm) {
- nouveau_vm_unlink(vm, pgd);
-
- if (--vm->refcount == 0)
- nouveau_vm_del(vm);
+ if (*ptr) {
+ nouveau_vm_unlink(*ptr, pgd);
+ kref_put(&(*ptr)->refcount, nouveau_vm_del);
}
+ *ptr = ref;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 0782bd2f1e0..6a13ffb53bd 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -606,6 +606,24 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
regp->ramdac_a34 = 0x1;
}
+static int
+nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
+{
+ struct nv04_display *disp = nv04_display(crtc->dev);
+ struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ int ret;
+
+ ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
+ if (ret == 0) {
+ if (disp->image[nv_crtc->index])
+ nouveau_bo_unpin(disp->image[nv_crtc->index]);
+ nouveau_bo_ref(nvfb->nvbo, &disp->image[nv_crtc->index]);
+ }
+
+ return ret;
+}
+
/**
* Sets up registers for the given mode/adjusted_mode pair.
*
@@ -622,10 +640,15 @@ nv_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_device *dev = crtc->dev;
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct nouveau_drm *drm = nouveau_drm(dev);
+ int ret;
NV_DEBUG(drm, "CTRC mode on CRTC %d:\n", nv_crtc->index);
drm_mode_debug_printmodeline(adjusted_mode);
+ ret = nv_crtc_swap_fbs(crtc, old_fb);
+ if (ret)
+ return ret;
+
/* unlock must come after turning off FP_TG_CONTROL in output_prepare */
nv_lock_vga_crtc_shadow(dev, nv_crtc->index, -1);
@@ -722,6 +745,7 @@ static void nv_crtc_commit(struct drm_crtc *crtc)
static void nv_crtc_destroy(struct drm_crtc *crtc)
{
+ struct nv04_display *disp = nv04_display(crtc->dev);
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
if (!nv_crtc)
@@ -729,6 +753,10 @@ static void nv_crtc_destroy(struct drm_crtc *crtc)
drm_crtc_cleanup(crtc);
+ if (disp->image[nv_crtc->index])
+ nouveau_bo_unpin(disp->image[nv_crtc->index]);
+ nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]);
+
nouveau_bo_unmap(nv_crtc->cursor.nvbo);
nouveau_bo_unpin(nv_crtc->cursor.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
@@ -754,6 +782,16 @@ nv_crtc_gamma_load(struct drm_crtc *crtc)
}
static void
+nv_crtc_disable(struct drm_crtc *crtc)
+{
+ struct nv04_display *disp = nv04_display(crtc->dev);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ if (disp->image[nv_crtc->index])
+ nouveau_bo_unpin(disp->image[nv_crtc->index]);
+ nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]);
+}
+
+static void
nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
uint32_t size)
{
@@ -791,7 +829,6 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *drm_fb;
struct nouveau_framebuffer *fb;
int arb_burst, arb_lwm;
- int ret;
NV_DEBUG(drm, "index %d\n", nv_crtc->index);
@@ -801,10 +838,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
return 0;
}
-
/* If atomic, we want to switch to the fb we were passed, so
- * now we update pointers to do that. (We don't pin; just
- * assume we're already pinned and update the base address.)
+ * now we update pointers to do that.
*/
if (atomic) {
drm_fb = passed_fb;
@@ -812,17 +847,6 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
} else {
drm_fb = crtc->fb;
fb = nouveau_framebuffer(crtc->fb);
- /* If not atomic, we can go ahead and pin, and unpin the
- * old fb we were passed.
- */
- ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
- if (ret)
- return ret;
-
- if (passed_fb) {
- struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
- nouveau_bo_unpin(ofb->nvbo);
- }
}
nv_crtc->fb.offset = fb->nvbo->bo.offset;
@@ -877,6 +901,9 @@ static int
nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
+ int ret = nv_crtc_swap_fbs(crtc, old_fb);
+ if (ret)
+ return ret;
return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
}
@@ -1027,6 +1054,7 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = {
.mode_set_base = nv04_crtc_mode_set_base,
.mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
.load_lut = nv_crtc_gamma_load,
+ .disable = nv_crtc_disable,
};
int
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h
index a0a031dad13..9928187f0a7 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h
@@ -81,6 +81,7 @@ struct nv04_display {
uint32_t saved_vga_font[4][16384];
uint32_t dac_users[4];
struct nouveau_object *core;
+ struct nouveau_bo *image[2];
};
static inline struct nv04_display *
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 4b1afb13138..af20fba3a1a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -148,6 +148,7 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
if (unlikely(nvbo->gem))
DRM_ERROR("bo %p still attached to GEM object\n", bo);
+ WARN_ON(nvbo->pin_refcnt > 0);
nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
kfree(nvbo);
}
@@ -197,6 +198,17 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
size_t acc_size;
int ret;
int type = ttm_bo_type_device;
+ int lpg_shift = 12;
+ int max_size;
+
+ if (drm->client.base.vm)
+ lpg_shift = drm->client.base.vm->vmm->lpg_shift;
+ max_size = INT_MAX & ~((1 << lpg_shift) - 1);
+
+ if (size <= 0 || size > max_size) {
+ nv_warn(drm, "skipped size %x\n", (u32)size);
+ return -EINVAL;
+ }
if (sg)
type = ttm_bo_type_sg;
@@ -340,13 +352,15 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
{
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
struct ttm_buffer_object *bo = &nvbo->bo;
- int ret;
+ int ret, ref;
ret = ttm_bo_reserve(bo, false, false, false, 0);
if (ret)
return ret;
- if (--nvbo->pin_refcnt)
+ ref = --nvbo->pin_refcnt;
+ WARN_ON_ONCE(ref < 0);
+ if (ref)
goto out;
nouveau_bo_placement_set(nvbo, bo->mem.placement, 0);
@@ -578,7 +592,7 @@ nve0_bo_move_init(struct nouveau_channel *chan, u32 handle)
int ret = RING_SPACE(chan, 2);
if (ret == 0) {
BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1);
- OUT_RING (chan, handle);
+ OUT_RING (chan, handle & 0x0000ffff);
FIRE_RING (chan);
}
return ret;
@@ -973,7 +987,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
struct ttm_mem_reg *old_mem = &bo->mem;
int ret;
- mutex_lock(&chan->cli->mutex);
+ mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING);
/* create temporary vmas for the transfer and attach them to the
* old nouveau_mem node, these will get cleaned up after ttm has
@@ -1014,7 +1028,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
struct ttm_mem_reg *, struct ttm_mem_reg *);
int (*init)(struct nouveau_channel *, u32 handle);
} _methods[] = {
- { "COPY", 0, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
+ { "COPY", 4, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
{ "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init },
{ "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init },
{ "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init },
@@ -1034,7 +1048,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
struct nouveau_channel *chan;
u32 handle = (mthd->engine << 16) | mthd->oclass;
- if (mthd->init == nve0_bo_move_init)
+ if (mthd->engine)
chan = drm->cechan;
else
chan = drm->channel;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 708b2d1c003..a03e75deaca 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -138,7 +138,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
{
struct nouveau_framebuffer *nouveau_fb;
struct drm_gem_object *gem;
- int ret;
+ int ret = -ENOMEM;
gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
if (!gem)
@@ -146,15 +146,19 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
if (!nouveau_fb)
- return ERR_PTR(-ENOMEM);
+ goto err_unref;
ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
- if (ret) {
- drm_gem_object_unreference(gem);
- return ERR_PTR(ret);
- }
+ if (ret)
+ goto err;
return &nouveau_fb->base;
+
+err:
+ kfree(nouveau_fb);
+err_unref:
+ drm_gem_object_unreference(gem);
+ return ERR_PTR(ret);
}
static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
@@ -524,9 +528,12 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct nouveau_page_flip_state *s;
struct nouveau_channel *chan = NULL;
struct nouveau_fence *fence;
- struct list_head res;
- struct ttm_validate_buffer res_val[2];
+ struct ttm_validate_buffer resv[2] = {
+ { .bo = &old_bo->bo },
+ { .bo = &new_bo->bo },
+ };
struct ww_acquire_ctx ticket;
+ LIST_HEAD(res);
int ret;
if (!drm->channel)
@@ -545,27 +552,19 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
chan = drm->channel;
spin_unlock(&old_bo->bo.bdev->fence_lock);
- mutex_lock(&chan->cli->mutex);
-
if (new_bo != old_bo) {
ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
- if (likely(!ret)) {
- res_val[0].bo = &old_bo->bo;
- res_val[1].bo = &new_bo->bo;
- INIT_LIST_HEAD(&res);
- list_add_tail(&res_val[0].head, &res);
- list_add_tail(&res_val[1].head, &res);
- ret = ttm_eu_reserve_buffers(&ticket, &res);
- if (ret)
- nouveau_bo_unpin(new_bo);
- }
- } else
- ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
+ if (ret)
+ goto fail_free;
- if (ret) {
- mutex_unlock(&chan->cli->mutex);
- goto fail_free;
+ list_add(&resv[1].head, &res);
}
+ list_add(&resv[0].head, &res);
+
+ mutex_lock(&chan->cli->mutex);
+ ret = ttm_eu_reserve_buffers(&ticket, &res);
+ if (ret)
+ goto fail_unpin;
/* Initialize a page flip struct */
*s = (struct nouveau_page_flip_state)
@@ -576,10 +575,11 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
/* Emit a page flip */
if (nv_device(drm->device)->card_type >= NV_50) {
ret = nv50_display_flip_next(crtc, fb, chan, 0);
- if (ret) {
- mutex_unlock(&chan->cli->mutex);
+ if (ret)
goto fail_unreserve;
- }
+ } else {
+ struct nv04_display *dispnv04 = nv04_display(dev);
+ nouveau_bo_ref(new_bo, &dispnv04->image[nouveau_crtc(crtc)->index]);
}
ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
@@ -590,22 +590,18 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
/* Update the crtc struct and cleanup */
crtc->fb = fb;
- if (old_bo != new_bo) {
- ttm_eu_fence_buffer_objects(&ticket, &res, fence);
+ ttm_eu_fence_buffer_objects(&ticket, &res, fence);
+ if (old_bo != new_bo)
nouveau_bo_unpin(old_bo);
- } else {
- nouveau_bo_fence(new_bo, fence);
- ttm_bo_unreserve(&new_bo->bo);
- }
nouveau_fence_unref(&fence);
return 0;
fail_unreserve:
- if (old_bo != new_bo) {
- ttm_eu_backoff_reservation(&ticket, &res);
+ ttm_eu_backoff_reservation(&ticket, &res);
+fail_unpin:
+ mutex_unlock(&chan->cli->mutex);
+ if (old_bo != new_bo)
nouveau_bo_unpin(new_bo);
- } else
- ttm_bo_unreserve(&new_bo->bo);
fail_free:
kfree(s);
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 218a4b522fe..61972668fd0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -192,6 +192,18 @@ nouveau_accel_init(struct nouveau_drm *drm)
arg0 = NVE0_CHANNEL_IND_ENGINE_GR;
arg1 = 1;
+ } else
+ if (device->chipset >= 0xa3 &&
+ device->chipset != 0xaa &&
+ device->chipset != 0xac) {
+ ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE,
+ NVDRM_CHAN + 1, NvDmaFB, NvDmaTT,
+ &drm->cechan);
+ if (ret)
+ NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
+
+ arg0 = NvDmaFB;
+ arg1 = NvDmaTT;
} else {
arg0 = NvDmaFB;
arg1 = NvDmaTT;
@@ -284,8 +296,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
return 0;
}
-static struct lock_class_key drm_client_lock_class_key;
-
static int
nouveau_drm_load(struct drm_device *dev, unsigned long flags)
{
@@ -297,7 +307,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
if (ret)
return ret;
- lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key);
dev->dev_private = drm;
drm->dev = dev;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 9352010030e..8f6d63d7edd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -385,6 +385,7 @@ out_unlock:
mutex_unlock(&dev->struct_mutex);
if (chan)
nouveau_bo_vma_del(nvbo, &fbcon->nouveau_fb.vma);
+ nouveau_bo_unmap(nvbo);
out_unpin:
nouveau_bo_unpin(nvbo);
out_unref:
@@ -397,7 +398,8 @@ void
nouveau_fbcon_output_poll_changed(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- drm_fb_helper_hotplug_event(&drm->fbcon->helper);
+ if (drm->fbcon)
+ drm_fb_helper_hotplug_event(&drm->fbcon->helper);
}
static int
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 1680d9187ba..be3149932c2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -143,7 +143,7 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
int ret;
fence->channel = chan;
- fence->timeout = jiffies + (3 * DRM_HZ);
+ fence->timeout = jiffies + (15 * DRM_HZ);
fence->sequence = ++fctx->sequence;
ret = fctx->emit(fence);
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index e72d09c068a..830cb7bad92 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -50,12 +50,6 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
return;
nvbo->gem = NULL;
- /* Lockdep hates you for doing reserve with gem object lock held */
- if (WARN_ON_ONCE(nvbo->pin_refcnt)) {
- nvbo->pin_refcnt = 1;
- nouveau_bo_unpin(nvbo);
- }
-
if (gem->import_attach)
drm_prime_gem_destroy(gem, nvbo->bo.sg);
diff --git a/drivers/gpu/drm/nouveau/nv17_fence.c b/drivers/gpu/drm/nouveau/nv17_fence.c
index 8e47a9bae8c..22aa9963ea6 100644
--- a/drivers/gpu/drm/nouveau/nv17_fence.c
+++ b/drivers/gpu/drm/nouveau/nv17_fence.c
@@ -76,7 +76,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
struct ttm_mem_reg *mem = &priv->bo->bo.mem;
struct nouveau_object *object;
u32 start = mem->start * PAGE_SIZE;
- u32 limit = mem->start + mem->size - 1;
+ u32 limit = start + mem->size - 1;
int ret = 0;
fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c
index 3af5bcd0b20..625f80d53dc 100644
--- a/drivers/gpu/drm/nouveau/nv40_pm.c
+++ b/drivers/gpu/drm/nouveau/nv40_pm.c
@@ -131,7 +131,7 @@ nv40_calc_pll(struct drm_device *dev, u32 reg, struct nvbios_pll *pll,
if (clk < pll->vco1.max_freq)
pll->vco2.max_freq = 0;
- pclk->pll_calc(pclk, pll, clk, &coef);
+ ret = pclk->pll_calc(pclk, pll, clk, &coef);
if (ret == 0)
return -ERANGE;
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 54dc6355b0c..8b40a36c1b5 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -355,6 +355,7 @@ struct nv50_oimm {
struct nv50_head {
struct nouveau_crtc base;
+ struct nouveau_bo *image;
struct nv50_curs curs;
struct nv50_sync sync;
struct nv50_ovly ovly;
@@ -517,9 +518,10 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
{
struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ struct nv50_head *head = nv50_head(crtc);
struct nv50_sync *sync = nv50_sync(crtc);
- int head = nv_crtc->index, ret;
u32 *push;
+ int ret;
swap_interval <<= 4;
if (swap_interval == 0)
@@ -537,7 +539,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
return ret;
BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
- OUT_RING (chan, NvEvoSema0 + head);
+ OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
OUT_RING (chan, sync->addr ^ 0x10);
BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
OUT_RING (chan, sync->data + 1);
@@ -546,7 +548,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
OUT_RING (chan, sync->data);
} else
if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) {
- u64 addr = nv84_fence_crtc(chan, head) + sync->addr;
+ u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
ret = RING_SPACE(chan, 12);
if (ret)
return ret;
@@ -565,7 +567,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
} else
if (chan) {
- u64 addr = nv84_fence_crtc(chan, head) + sync->addr;
+ u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
ret = RING_SPACE(chan, 10);
if (ret)
return ret;
@@ -630,6 +632,8 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
evo_mthd(push, 0x0080, 1);
evo_data(push, 0x00000000);
evo_kick(push, sync);
+
+ nouveau_bo_ref(nv_fb->nvbo, &head->image);
return 0;
}
@@ -1038,18 +1042,17 @@ static int
nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
{
struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
+ struct nv50_head *head = nv50_head(crtc);
int ret;
ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
- if (ret)
- return ret;
-
- if (old_fb) {
- nvfb = nouveau_framebuffer(old_fb);
- nouveau_bo_unpin(nvfb->nvbo);
+ if (ret == 0) {
+ if (head->image)
+ nouveau_bo_unpin(head->image);
+ nouveau_bo_ref(nvfb->nvbo, &head->image);
}
- return 0;
+ return ret;
}
static int
@@ -1198,6 +1201,15 @@ nv50_crtc_lut_load(struct drm_crtc *crtc)
}
}
+static void
+nv50_crtc_disable(struct drm_crtc *crtc)
+{
+ struct nv50_head *head = nv50_head(crtc);
+ if (head->image)
+ nouveau_bo_unpin(head->image);
+ nouveau_bo_ref(NULL, &head->image);
+}
+
static int
nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
uint32_t handle, uint32_t width, uint32_t height)
@@ -1271,18 +1283,29 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct nv50_disp *disp = nv50_disp(crtc->dev);
struct nv50_head *head = nv50_head(crtc);
+
nv50_dmac_destroy(disp->core, &head->ovly.base);
nv50_pioc_destroy(disp->core, &head->oimm.base);
nv50_dmac_destroy(disp->core, &head->sync.base);
nv50_pioc_destroy(disp->core, &head->curs.base);
+
+ /*XXX: this shouldn't be necessary, but the core doesn't call
+ * disconnect() during the cleanup paths
+ */
+ if (head->image)
+ nouveau_bo_unpin(head->image);
+ nouveau_bo_ref(NULL, &head->image);
+
nouveau_bo_unmap(nv_crtc->cursor.nvbo);
if (nv_crtc->cursor.nvbo)
nouveau_bo_unpin(nv_crtc->cursor.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
+
nouveau_bo_unmap(nv_crtc->lut.nvbo);
if (nv_crtc->lut.nvbo)
nouveau_bo_unpin(nv_crtc->lut.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
+
drm_crtc_cleanup(crtc);
kfree(crtc);
}
@@ -1296,6 +1319,7 @@ static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
.mode_set_base = nv50_crtc_mode_set_base,
.mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
.load_lut = nv50_crtc_lut_load,
+ .disable = nv50_crtc_disable,
};
static const struct drm_crtc_funcs nv50_crtc_func = {
diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c
index f9701e567db..0ee36384003 100644
--- a/drivers/gpu/drm/nouveau/nv50_fence.c
+++ b/drivers/gpu/drm/nouveau/nv50_fence.c
@@ -39,6 +39,8 @@ nv50_fence_context_new(struct nouveau_channel *chan)
struct nv10_fence_chan *fctx;
struct ttm_mem_reg *mem = &priv->bo->bo.mem;
struct nouveau_object *object;
+ u32 start = mem->start * PAGE_SIZE;
+ u32 limit = start + mem->size - 1;
int ret, i;
fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
@@ -51,26 +53,28 @@ nv50_fence_context_new(struct nouveau_channel *chan)
fctx->base.sync = nv17_fence_sync;
ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
- NvSema, 0x0002,
+ NvSema, 0x003d,
&(struct nv_dma_class) {
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
- .start = mem->start * PAGE_SIZE,
- .limit = mem->size - 1,
+ .start = start,
+ .limit = limit,
}, sizeof(struct nv_dma_class),
&object);
/* dma objects for display sync channel semaphore blocks */
for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
+ u32 start = bo->bo.mem.start * PAGE_SIZE;
+ u32 limit = start + bo->bo.mem.size - 1;
ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
NvEvoSema0 + i, 0x003d,
&(struct nv_dma_class) {
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
- .start = bo->bo.offset,
- .limit = bo->bo.offset + 0xfff,
+ .start = start,
+ .limit = limit,
}, sizeof(struct nv_dma_class),
&object);
}
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index 93c2f2cceb5..eb89653a7a1 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -179,9 +179,10 @@ qxl_push_command_ring_release(struct qxl_device *qdev, struct qxl_release *relea
uint32_t type, bool interruptible)
{
struct qxl_command cmd;
+ struct qxl_bo_list *entry = list_first_entry(&release->bos, struct qxl_bo_list, tv.head);
cmd.type = type;
- cmd.data = qxl_bo_physical_address(qdev, release->bos[0], release->release_offset);
+ cmd.data = qxl_bo_physical_address(qdev, to_qxl_bo(entry->tv.bo), release->release_offset);
return qxl_ring_push(qdev->command_ring, &cmd, interruptible);
}
@@ -191,9 +192,10 @@ qxl_push_cursor_ring_release(struct qxl_device *qdev, struct qxl_release *releas
uint32_t type, bool interruptible)
{
struct qxl_command cmd;
+ struct qxl_bo_list *entry = list_first_entry(&release->bos, struct qxl_bo_list, tv.head);
cmd.type = type;
- cmd.data = qxl_bo_physical_address(qdev, release->bos[0], release->release_offset);
+ cmd.data = qxl_bo_physical_address(qdev, to_qxl_bo(entry->tv.bo), release->release_offset);
return qxl_ring_push(qdev->cursor_ring, &cmd, interruptible);
}
@@ -214,7 +216,6 @@ int qxl_garbage_collect(struct qxl_device *qdev)
struct qxl_release *release;
uint64_t id, next_id;
int i = 0;
- int ret;
union qxl_release_info *info;
while (qxl_ring_pop(qdev->release_ring, &id)) {
@@ -224,17 +225,10 @@ int qxl_garbage_collect(struct qxl_device *qdev)
if (release == NULL)
break;
- ret = qxl_release_reserve(qdev, release, false);
- if (ret) {
- qxl_io_log(qdev, "failed to reserve release on garbage collect %lld\n", id);
- DRM_ERROR("failed to reserve release %lld\n", id);
- }
-
info = qxl_release_map(qdev, release);
next_id = info->next;
qxl_release_unmap(qdev, release, info);
- qxl_release_unreserve(qdev, release);
QXL_INFO(qdev, "popped %lld, next %lld\n", id,
next_id);
@@ -259,27 +253,29 @@ int qxl_garbage_collect(struct qxl_device *qdev)
return i;
}
-int qxl_alloc_bo_reserved(struct qxl_device *qdev, unsigned long size,
+int qxl_alloc_bo_reserved(struct qxl_device *qdev,
+ struct qxl_release *release,
+ unsigned long size,
struct qxl_bo **_bo)
{
struct qxl_bo *bo;
int ret;
ret = qxl_bo_create(qdev, size, false /* not kernel - device */,
- QXL_GEM_DOMAIN_VRAM, NULL, &bo);
+ false, QXL_GEM_DOMAIN_VRAM, NULL, &bo);
if (ret) {
DRM_ERROR("failed to allocate VRAM BO\n");
return ret;
}
- ret = qxl_bo_reserve(bo, false);
- if (unlikely(ret != 0))
+ ret = qxl_release_list_add(release, bo);
+ if (ret)
goto out_unref;
*_bo = bo;
return 0;
out_unref:
qxl_bo_unref(&bo);
- return 0;
+ return ret;
}
static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port, bool intr)
@@ -503,6 +499,10 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev,
if (ret)
return ret;
+ ret = qxl_release_reserve_list(release, true);
+ if (ret)
+ return ret;
+
cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release);
cmd->type = QXL_SURFACE_CMD_CREATE;
cmd->u.surface_create.format = surf->surf.format;
@@ -524,14 +524,11 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev,
surf->surf_create = release;
- /* no need to add a release to the fence for this bo,
+ /* no need to add a release to the fence for this surface bo,
since it is only released when we ask to destroy the surface
and it would never signal otherwise */
- qxl_fence_releaseable(qdev, release);
-
qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
-
- qxl_release_unreserve(qdev, release);
+ qxl_release_fence_buffer_objects(release);
surf->hw_surf_alloc = true;
spin_lock(&qdev->surf_id_idr_lock);
@@ -573,12 +570,9 @@ int qxl_hw_surface_dealloc(struct qxl_device *qdev,
cmd->surface_id = id;
qxl_release_unmap(qdev, release, &cmd->release_info);
- qxl_fence_releaseable(qdev, release);
-
qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
- qxl_release_unreserve(qdev, release);
-
+ qxl_release_fence_buffer_objects(release);
return 0;
}
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index f76f5dd7bfc..835caba026d 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -179,7 +179,7 @@ static void qxl_crtc_destroy(struct drm_crtc *crtc)
kfree(qxl_crtc);
}
-static void
+static int
qxl_hide_cursor(struct qxl_device *qdev)
{
struct qxl_release *release;
@@ -188,14 +188,22 @@ qxl_hide_cursor(struct qxl_device *qdev)
ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), QXL_RELEASE_CURSOR_CMD,
&release, NULL);
+ if (ret)
+ return ret;
+
+ ret = qxl_release_reserve_list(release, true);
+ if (ret) {
+ qxl_release_free(qdev, release);
+ return ret;
+ }
cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
cmd->type = QXL_CURSOR_HIDE;
qxl_release_unmap(qdev, release, &cmd->release_info);
- qxl_fence_releaseable(qdev, release);
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
- qxl_release_unreserve(qdev, release);
+ qxl_release_fence_buffer_objects(release);
+ return 0;
}
static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
@@ -216,10 +224,8 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
int size = 64*64*4;
int ret = 0;
- if (!handle) {
- qxl_hide_cursor(qdev);
- return 0;
- }
+ if (!handle)
+ return qxl_hide_cursor(qdev);
obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
if (!obj) {
@@ -234,8 +240,9 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
goto out_unref;
ret = qxl_bo_pin(user_bo, QXL_GEM_DOMAIN_CPU, NULL);
+ qxl_bo_unreserve(user_bo);
if (ret)
- goto out_unreserve;
+ goto out_unref;
ret = qxl_bo_kmap(user_bo, &user_ptr);
if (ret)
@@ -246,14 +253,20 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
&release, NULL);
if (ret)
goto out_kunmap;
- ret = qxl_alloc_bo_reserved(qdev, sizeof(struct qxl_cursor) + size,
- &cursor_bo);
+
+ ret = qxl_alloc_bo_reserved(qdev, release, sizeof(struct qxl_cursor) + size,
+ &cursor_bo);
if (ret)
goto out_free_release;
- ret = qxl_bo_kmap(cursor_bo, (void **)&cursor);
+
+ ret = qxl_release_reserve_list(release, false);
if (ret)
goto out_free_bo;
+ ret = qxl_bo_kmap(cursor_bo, (void **)&cursor);
+ if (ret)
+ goto out_backoff;
+
cursor->header.unique = 0;
cursor->header.type = SPICE_CURSOR_TYPE_ALPHA;
cursor->header.width = 64;
@@ -269,11 +282,7 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
qxl_bo_kunmap(cursor_bo);
- /* finish with the userspace bo */
qxl_bo_kunmap(user_bo);
- qxl_bo_unpin(user_bo);
- qxl_bo_unreserve(user_bo);
- drm_gem_object_unreference_unlocked(obj);
cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
cmd->type = QXL_CURSOR_SET;
@@ -281,30 +290,35 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
cmd->u.set.position.y = qcrtc->cur_y;
cmd->u.set.shape = qxl_bo_physical_address(qdev, cursor_bo, 0);
- qxl_release_add_res(qdev, release, cursor_bo);
cmd->u.set.visible = 1;
qxl_release_unmap(qdev, release, &cmd->release_info);
- qxl_fence_releaseable(qdev, release);
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
- qxl_release_unreserve(qdev, release);
+ qxl_release_fence_buffer_objects(release);
+
+ /* finish with the userspace bo */
+ ret = qxl_bo_reserve(user_bo, false);
+ if (!ret) {
+ qxl_bo_unpin(user_bo);
+ qxl_bo_unreserve(user_bo);
+ }
+ drm_gem_object_unreference_unlocked(obj);
- qxl_bo_unreserve(cursor_bo);
qxl_bo_unref(&cursor_bo);
return ret;
+
+out_backoff:
+ qxl_release_backoff_reserve_list(release);
out_free_bo:
qxl_bo_unref(&cursor_bo);
out_free_release:
- qxl_release_unreserve(qdev, release);
qxl_release_free(qdev, release);
out_kunmap:
qxl_bo_kunmap(user_bo);
out_unpin:
qxl_bo_unpin(user_bo);
-out_unreserve:
- qxl_bo_unreserve(user_bo);
out_unref:
drm_gem_object_unreference_unlocked(obj);
return ret;
@@ -322,6 +336,14 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc,
ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), QXL_RELEASE_CURSOR_CMD,
&release, NULL);
+ if (ret)
+ return ret;
+
+ ret = qxl_release_reserve_list(release, true);
+ if (ret) {
+ qxl_release_free(qdev, release);
+ return ret;
+ }
qcrtc->cur_x = x;
qcrtc->cur_y = y;
@@ -332,9 +354,9 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc,
cmd->u.position.y = qcrtc->cur_y;
qxl_release_unmap(qdev, release, &cmd->release_info);
- qxl_fence_releaseable(qdev, release);
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
- qxl_release_unreserve(qdev, release);
+ qxl_release_fence_buffer_objects(release);
+
return 0;
}
diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c
index 3c8c3dbf937..56e1d633875 100644
--- a/drivers/gpu/drm/qxl/qxl_draw.c
+++ b/drivers/gpu/drm/qxl/qxl_draw.c
@@ -23,25 +23,29 @@
#include "qxl_drv.h"
#include "qxl_object.h"
+static int alloc_clips(struct qxl_device *qdev,
+ struct qxl_release *release,
+ unsigned num_clips,
+ struct qxl_bo **clips_bo)
+{
+ int size = sizeof(struct qxl_clip_rects) + sizeof(struct qxl_rect) * num_clips;
+
+ return qxl_alloc_bo_reserved(qdev, release, size, clips_bo);
+}
+
/* returns a pointer to the already allocated qxl_rect array inside
* the qxl_clip_rects. This is *not* the same as the memory allocated
* on the device, it is offset to qxl_clip_rects.chunk.data */
static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
struct qxl_drawable *drawable,
unsigned num_clips,
- struct qxl_bo **clips_bo,
- struct qxl_release *release)
+ struct qxl_bo *clips_bo)
{
struct qxl_clip_rects *dev_clips;
int ret;
- int size = sizeof(*dev_clips) + sizeof(struct qxl_rect) * num_clips;
- ret = qxl_alloc_bo_reserved(qdev, size, clips_bo);
- if (ret)
- return NULL;
- ret = qxl_bo_kmap(*clips_bo, (void **)&dev_clips);
+ ret = qxl_bo_kmap(clips_bo, (void **)&dev_clips);
if (ret) {
- qxl_bo_unref(clips_bo);
return NULL;
}
dev_clips->num_rects = num_clips;
@@ -52,20 +56,34 @@ static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
}
static int
+alloc_drawable(struct qxl_device *qdev, struct qxl_release **release)
+{
+ int ret;
+ ret = qxl_alloc_release_reserved(qdev, sizeof(struct qxl_drawable),
+ QXL_RELEASE_DRAWABLE, release,
+ NULL);
+ return ret;
+}
+
+static void
+free_drawable(struct qxl_device *qdev, struct qxl_release *release)
+{
+ qxl_release_free(qdev, release);
+}
+
+/* release needs to be reserved at this point */
+static int
make_drawable(struct qxl_device *qdev, int surface, uint8_t type,
const struct qxl_rect *rect,
- struct qxl_release **release)
+ struct qxl_release *release)
{
struct qxl_drawable *drawable;
- int i, ret;
+ int i;
- ret = qxl_alloc_release_reserved(qdev, sizeof(*drawable),
- QXL_RELEASE_DRAWABLE, release,
- NULL);
- if (ret)
- return ret;
+ drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
+ if (!drawable)
+ return -ENOMEM;
- drawable = (struct qxl_drawable *)qxl_release_map(qdev, *release);
drawable->type = type;
drawable->surface_id = surface; /* Only primary for now */
@@ -91,14 +109,23 @@ make_drawable(struct qxl_device *qdev, int surface, uint8_t type,
drawable->bbox = *rect;
drawable->mm_time = qdev->rom->mm_clock;
- qxl_release_unmap(qdev, *release, &drawable->release_info);
+ qxl_release_unmap(qdev, release, &drawable->release_info);
return 0;
}
-static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,
+static int alloc_palette_object(struct qxl_device *qdev,
+ struct qxl_release *release,
+ struct qxl_bo **palette_bo)
+{
+ return qxl_alloc_bo_reserved(qdev, release,
+ sizeof(struct qxl_palette) + sizeof(uint32_t) * 2,
+ palette_bo);
+}
+
+static int qxl_palette_create_1bit(struct qxl_bo *palette_bo,
+ struct qxl_release *release,
const struct qxl_fb_image *qxl_fb_image)
{
- struct qxl_device *qdev = qxl_fb_image->qdev;
const struct fb_image *fb_image = &qxl_fb_image->fb_image;
uint32_t visual = qxl_fb_image->visual;
const uint32_t *pseudo_palette = qxl_fb_image->pseudo_palette;
@@ -108,12 +135,7 @@ static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,
static uint64_t unique; /* we make no attempt to actually set this
* correctly globaly, since that would require
* tracking all of our palettes. */
-
- ret = qxl_alloc_bo_reserved(qdev,
- sizeof(struct qxl_palette) + sizeof(uint32_t) * 2,
- palette_bo);
-
- ret = qxl_bo_kmap(*palette_bo, (void **)&pal);
+ ret = qxl_bo_kmap(palette_bo, (void **)&pal);
pal->num_ents = 2;
pal->unique = unique++;
if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) {
@@ -126,7 +148,7 @@ static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,
}
pal->ents[0] = bgcolor;
pal->ents[1] = fgcolor;
- qxl_bo_kunmap(*palette_bo);
+ qxl_bo_kunmap(palette_bo);
return 0;
}
@@ -144,44 +166,63 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
const char *src = fb_image->data;
int depth = fb_image->depth;
struct qxl_release *release;
- struct qxl_bo *image_bo;
struct qxl_image *image;
int ret;
-
+ struct qxl_drm_image *dimage;
+ struct qxl_bo *palette_bo = NULL;
if (stride == 0)
stride = depth * width / 8;
+ ret = alloc_drawable(qdev, &release);
+ if (ret)
+ return;
+
+ ret = qxl_image_alloc_objects(qdev, release,
+ &dimage,
+ height, stride);
+ if (ret)
+ goto out_free_drawable;
+
+ if (depth == 1) {
+ ret = alloc_palette_object(qdev, release, &palette_bo);
+ if (ret)
+ goto out_free_image;
+ }
+
+ /* do a reservation run over all the objects we just allocated */
+ ret = qxl_release_reserve_list(release, true);
+ if (ret)
+ goto out_free_palette;
+
rect.left = x;
rect.right = x + width;
rect.top = y;
rect.bottom = y + height;
- ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, &release);
- if (ret)
- return;
+ ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, release);
+ if (ret) {
+ qxl_release_backoff_reserve_list(release);
+ goto out_free_palette;
+ }
- ret = qxl_image_create(qdev, release, &image_bo,
- (const uint8_t *)src, 0, 0,
- width, height, depth, stride);
+ ret = qxl_image_init(qdev, release, dimage,
+ (const uint8_t *)src, 0, 0,
+ width, height, depth, stride);
if (ret) {
- qxl_release_unreserve(qdev, release);
+ qxl_release_backoff_reserve_list(release);
qxl_release_free(qdev, release);
return;
}
if (depth == 1) {
- struct qxl_bo *palette_bo;
void *ptr;
- ret = qxl_palette_create_1bit(&palette_bo, qxl_fb_image);
- qxl_release_add_res(qdev, release, palette_bo);
+ ret = qxl_palette_create_1bit(palette_bo, release, qxl_fb_image);
- ptr = qxl_bo_kmap_atomic_page(qdev, image_bo, 0);
+ ptr = qxl_bo_kmap_atomic_page(qdev, dimage->bo, 0);
image = ptr;
image->u.bitmap.palette =
qxl_bo_physical_address(qdev, palette_bo, 0);
- qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
- qxl_bo_unreserve(palette_bo);
- qxl_bo_unref(&palette_bo);
+ qxl_bo_kunmap_atomic_page(qdev, dimage->bo, ptr);
}
drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
@@ -199,16 +240,20 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
drawable->u.copy.mask.bitmap = 0;
drawable->u.copy.src_bitmap =
- qxl_bo_physical_address(qdev, image_bo, 0);
+ qxl_bo_physical_address(qdev, dimage->bo, 0);
qxl_release_unmap(qdev, release, &drawable->release_info);
- qxl_release_add_res(qdev, release, image_bo);
- qxl_bo_unreserve(image_bo);
- qxl_bo_unref(&image_bo);
-
- qxl_fence_releaseable(qdev, release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
- qxl_release_unreserve(qdev, release);
+ qxl_release_fence_buffer_objects(release);
+
+out_free_palette:
+ if (palette_bo)
+ qxl_bo_unref(&palette_bo);
+out_free_image:
+ qxl_image_free_objects(qdev, dimage);
+out_free_drawable:
+ if (ret)
+ free_drawable(qdev, release);
}
/* push a draw command using the given clipping rectangles as
@@ -243,10 +288,14 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
int depth = qxl_fb->base.bits_per_pixel;
uint8_t *surface_base;
struct qxl_release *release;
- struct qxl_bo *image_bo;
struct qxl_bo *clips_bo;
+ struct qxl_drm_image *dimage;
int ret;
+ ret = alloc_drawable(qdev, &release);
+ if (ret)
+ return;
+
left = clips->x1;
right = clips->x2;
top = clips->y1;
@@ -263,36 +312,52 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
width = right - left;
height = bottom - top;
+
+ ret = alloc_clips(qdev, release, num_clips, &clips_bo);
+ if (ret)
+ goto out_free_drawable;
+
+ ret = qxl_image_alloc_objects(qdev, release,
+ &dimage,
+ height, stride);
+ if (ret)
+ goto out_free_clips;
+
+ /* do a reservation run over all the objects we just allocated */
+ ret = qxl_release_reserve_list(release, true);
+ if (ret)
+ goto out_free_image;
+
drawable_rect.left = left;
drawable_rect.right = right;
drawable_rect.top = top;
drawable_rect.bottom = bottom;
+
ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &drawable_rect,
- &release);
+ release);
if (ret)
- return;
+ goto out_release_backoff;
ret = qxl_bo_kmap(bo, (void **)&surface_base);
if (ret)
- goto out_unref;
+ goto out_release_backoff;
- ret = qxl_image_create(qdev, release, &image_bo, surface_base,
- left, top, width, height, depth, stride);
+
+ ret = qxl_image_init(qdev, release, dimage, surface_base,
+ left, top, width, height, depth, stride);
qxl_bo_kunmap(bo);
if (ret)
- goto out_unref;
+ goto out_release_backoff;
+
+ rects = drawable_set_clipping(qdev, drawable, num_clips, clips_bo);
+ if (!rects)
+ goto out_release_backoff;
- rects = drawable_set_clipping(qdev, drawable, num_clips, &clips_bo, release);
- if (!rects) {
- qxl_bo_unref(&image_bo);
- goto out_unref;
- }
drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
drawable->clip.data = qxl_bo_physical_address(qdev,
clips_bo, 0);
- qxl_release_add_res(qdev, release, clips_bo);
drawable->u.copy.src_area.top = 0;
drawable->u.copy.src_area.bottom = height;
@@ -306,11 +371,9 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
drawable->u.copy.mask.pos.y = 0;
drawable->u.copy.mask.bitmap = 0;
- drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, image_bo, 0);
+ drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, dimage->bo, 0);
qxl_release_unmap(qdev, release, &drawable->release_info);
- qxl_release_add_res(qdev, release, image_bo);
- qxl_bo_unreserve(image_bo);
- qxl_bo_unref(&image_bo);
+
clips_ptr = clips;
for (i = 0; i < num_clips; i++, clips_ptr += inc) {
rects[i].left = clips_ptr->x1;
@@ -319,17 +382,22 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
rects[i].bottom = clips_ptr->y2;
}
qxl_bo_kunmap(clips_bo);
- qxl_bo_unreserve(clips_bo);
- qxl_bo_unref(&clips_bo);
- qxl_fence_releaseable(qdev, release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
- qxl_release_unreserve(qdev, release);
- return;
+ qxl_release_fence_buffer_objects(release);
+
+out_release_backoff:
+ if (ret)
+ qxl_release_backoff_reserve_list(release);
+out_free_image:
+ qxl_image_free_objects(qdev, dimage);
+out_free_clips:
+ qxl_bo_unref(&clips_bo);
+out_free_drawable:
+ /* only free drawable on error */
+ if (ret)
+ free_drawable(qdev, release);
-out_unref:
- qxl_release_unreserve(qdev, release);
- qxl_release_free(qdev, release);
}
void qxl_draw_copyarea(struct qxl_device *qdev,
@@ -342,22 +410,36 @@ void qxl_draw_copyarea(struct qxl_device *qdev,
struct qxl_release *release;
int ret;
+ ret = alloc_drawable(qdev, &release);
+ if (ret)
+ return;
+
+ /* do a reservation run over all the objects we just allocated */
+ ret = qxl_release_reserve_list(release, true);
+ if (ret)
+ goto out_free_release;
+
rect.left = dx;
rect.top = dy;
rect.right = dx + width;
rect.bottom = dy + height;
- ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, &release);
- if (ret)
- return;
+ ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, release);
+ if (ret) {
+ qxl_release_backoff_reserve_list(release);
+ goto out_free_release;
+ }
drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
drawable->u.copy_bits.src_pos.x = sx;
drawable->u.copy_bits.src_pos.y = sy;
-
qxl_release_unmap(qdev, release, &drawable->release_info);
- qxl_fence_releaseable(qdev, release);
+
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
- qxl_release_unreserve(qdev, release);
+ qxl_release_fence_buffer_objects(release);
+
+out_free_release:
+ if (ret)
+ free_drawable(qdev, release);
}
void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
@@ -370,10 +452,21 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
struct qxl_release *release;
int ret;
- ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, &release);
+ ret = alloc_drawable(qdev, &release);
if (ret)
return;
+ /* do a reservation run over all the objects we just allocated */
+ ret = qxl_release_reserve_list(release, true);
+ if (ret)
+ goto out_free_release;
+
+ ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, release);
+ if (ret) {
+ qxl_release_backoff_reserve_list(release);
+ goto out_free_release;
+ }
+
drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID;
drawable->u.fill.brush.u.color = color;
@@ -384,7 +477,11 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
drawable->u.fill.mask.bitmap = 0;
qxl_release_unmap(qdev, release, &drawable->release_info);
- qxl_fence_releaseable(qdev, release);
+
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
- qxl_release_unreserve(qdev, release);
+ qxl_release_fence_buffer_objects(release);
+
+out_free_release:
+ if (ret)
+ free_drawable(qdev, release);
}
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index aacb791464a..7e96f4f1173 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -42,6 +42,9 @@
#include <ttm/ttm_placement.h>
#include <ttm/ttm_module.h>
+/* just for ttm_validate_buffer */
+#include <ttm/ttm_execbuf_util.h>
+
#include <drm/qxl_drm.h>
#include "qxl_dev.h"
@@ -118,9 +121,9 @@ struct qxl_bo {
uint32_t surface_id;
struct qxl_fence fence; /* per bo fence - list of releases */
struct qxl_release *surf_create;
- atomic_t reserve_count;
};
#define gem_to_qxl_bo(gobj) container_of((gobj), struct qxl_bo, gem_base)
+#define to_qxl_bo(tobj) container_of((tobj), struct qxl_bo, tbo)
struct qxl_gem {
struct mutex mutex;
@@ -128,12 +131,7 @@ struct qxl_gem {
};
struct qxl_bo_list {
- struct list_head lhead;
- struct qxl_bo *bo;
-};
-
-struct qxl_reloc_list {
- struct list_head bos;
+ struct ttm_validate_buffer tv;
};
struct qxl_crtc {
@@ -195,10 +193,20 @@ enum {
struct qxl_release {
int id;
int type;
- int bo_count;
uint32_t release_offset;
uint32_t surface_release_id;
- struct qxl_bo *bos[QXL_MAX_RES];
+ struct ww_acquire_ctx ticket;
+ struct list_head bos;
+};
+
+struct qxl_drm_chunk {
+ struct list_head head;
+ struct qxl_bo *bo;
+};
+
+struct qxl_drm_image {
+ struct qxl_bo *bo;
+ struct list_head chunk_list;
};
struct qxl_fb_image {
@@ -314,6 +322,7 @@ struct qxl_device {
struct workqueue_struct *gc_queue;
struct work_struct gc_work;
+ struct work_struct fb_work;
};
/* forward declaration for QXL_INFO_IO */
@@ -433,12 +442,19 @@ int qxl_mmap(struct file *filp, struct vm_area_struct *vma);
/* qxl image */
-int qxl_image_create(struct qxl_device *qdev,
- struct qxl_release *release,
- struct qxl_bo **image_bo,
- const uint8_t *data,
- int x, int y, int width, int height,
- int depth, int stride);
+int qxl_image_init(struct qxl_device *qdev,
+ struct qxl_release *release,
+ struct qxl_drm_image *dimage,
+ const uint8_t *data,
+ int x, int y, int width, int height,
+ int depth, int stride);
+int
+qxl_image_alloc_objects(struct qxl_device *qdev,
+ struct qxl_release *release,
+ struct qxl_drm_image **image_ptr,
+ int height, int stride);
+void qxl_image_free_objects(struct qxl_device *qdev, struct qxl_drm_image *dimage);
+
void qxl_update_screen(struct qxl_device *qxl);
/* qxl io operations (qxl_cmd.c) */
@@ -459,20 +475,15 @@ int qxl_ring_push(struct qxl_ring *ring, const void *new_elt, bool interruptible
void qxl_io_flush_release(struct qxl_device *qdev);
void qxl_io_flush_surfaces(struct qxl_device *qdev);
-int qxl_release_reserve(struct qxl_device *qdev,
- struct qxl_release *release, bool no_wait);
-void qxl_release_unreserve(struct qxl_device *qdev,
- struct qxl_release *release);
union qxl_release_info *qxl_release_map(struct qxl_device *qdev,
struct qxl_release *release);
void qxl_release_unmap(struct qxl_device *qdev,
struct qxl_release *release,
union qxl_release_info *info);
-/*
- * qxl_bo_add_resource.
- *
- */
-void qxl_bo_add_resource(struct qxl_bo *main_bo, struct qxl_bo *resource);
+int qxl_release_list_add(struct qxl_release *release, struct qxl_bo *bo);
+int qxl_release_reserve_list(struct qxl_release *release, bool no_intr);
+void qxl_release_backoff_reserve_list(struct qxl_release *release);
+void qxl_release_fence_buffer_objects(struct qxl_release *release);
int qxl_alloc_surface_release_reserved(struct qxl_device *qdev,
enum qxl_surface_cmd_type surface_cmd_type,
@@ -481,15 +492,16 @@ int qxl_alloc_surface_release_reserved(struct qxl_device *qdev,
int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
int type, struct qxl_release **release,
struct qxl_bo **rbo);
-int qxl_fence_releaseable(struct qxl_device *qdev,
- struct qxl_release *release);
+
int
qxl_push_command_ring_release(struct qxl_device *qdev, struct qxl_release *release,
uint32_t type, bool interruptible);
int
qxl_push_cursor_ring_release(struct qxl_device *qdev, struct qxl_release *release,
uint32_t type, bool interruptible);
-int qxl_alloc_bo_reserved(struct qxl_device *qdev, unsigned long size,
+int qxl_alloc_bo_reserved(struct qxl_device *qdev,
+ struct qxl_release *release,
+ unsigned long size,
struct qxl_bo **_bo);
/* qxl drawing commands */
@@ -510,15 +522,9 @@ void qxl_draw_copyarea(struct qxl_device *qdev,
u32 sx, u32 sy,
u32 dx, u32 dy);
-uint64_t
-qxl_release_alloc(struct qxl_device *qdev, int type,
- struct qxl_release **ret);
-
void qxl_release_free(struct qxl_device *qdev,
struct qxl_release *release);
-void qxl_release_add_res(struct qxl_device *qdev,
- struct qxl_release *release,
- struct qxl_bo *bo);
+
/* used by qxl_debugfs_release */
struct qxl_release *qxl_release_from_id_locked(struct qxl_device *qdev,
uint64_t id);
@@ -561,7 +567,7 @@ void qxl_surface_evict(struct qxl_device *qdev, struct qxl_bo *surf, bool freein
int qxl_update_surface(struct qxl_device *qdev, struct qxl_bo *surf);
/* qxl_fence.c */
-int qxl_fence_add_release(struct qxl_fence *qfence, uint32_t rel_id);
+void qxl_fence_add_release_locked(struct qxl_fence *qfence, uint32_t rel_id);
int qxl_fence_remove_release(struct qxl_fence *qfence, uint32_t rel_id);
int qxl_fence_init(struct qxl_device *qdev, struct qxl_fence *qfence);
void qxl_fence_fini(struct qxl_fence *qfence);
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
index 76f39d88d68..88722f23343 100644
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
@@ -37,12 +37,29 @@
#define QXL_DIRTY_DELAY (HZ / 30)
+#define QXL_FB_OP_FILLRECT 1
+#define QXL_FB_OP_COPYAREA 2
+#define QXL_FB_OP_IMAGEBLIT 3
+
+struct qxl_fb_op {
+ struct list_head head;
+ int op_type;
+ union {
+ struct fb_fillrect fr;
+ struct fb_copyarea ca;
+ struct fb_image ib;
+ } op;
+ void *img_data;
+};
+
struct qxl_fbdev {
struct drm_fb_helper helper;
struct qxl_framebuffer qfb;
struct list_head fbdev_list;
struct qxl_device *qdev;
+ spinlock_t delayed_ops_lock;
+ struct list_head delayed_ops;
void *shadow;
int size;
@@ -164,8 +181,69 @@ static struct fb_deferred_io qxl_defio = {
.deferred_io = qxl_deferred_io,
};
-static void qxl_fb_fillrect(struct fb_info *info,
- const struct fb_fillrect *fb_rect)
+static void qxl_fb_delayed_fillrect(struct qxl_fbdev *qfbdev,
+ const struct fb_fillrect *fb_rect)
+{
+ struct qxl_fb_op *op;
+ unsigned long flags;
+
+ op = kmalloc(sizeof(struct qxl_fb_op), GFP_ATOMIC | __GFP_NOWARN);
+ if (!op)
+ return;
+
+ op->op.fr = *fb_rect;
+ op->img_data = NULL;
+ op->op_type = QXL_FB_OP_FILLRECT;
+
+ spin_lock_irqsave(&qfbdev->delayed_ops_lock, flags);
+ list_add_tail(&op->head, &qfbdev->delayed_ops);
+ spin_unlock_irqrestore(&qfbdev->delayed_ops_lock, flags);
+}
+
+static void qxl_fb_delayed_copyarea(struct qxl_fbdev *qfbdev,
+ const struct fb_copyarea *fb_copy)
+{
+ struct qxl_fb_op *op;
+ unsigned long flags;
+
+ op = kmalloc(sizeof(struct qxl_fb_op), GFP_ATOMIC | __GFP_NOWARN);
+ if (!op)
+ return;
+
+ op->op.ca = *fb_copy;
+ op->img_data = NULL;
+ op->op_type = QXL_FB_OP_COPYAREA;
+
+ spin_lock_irqsave(&qfbdev->delayed_ops_lock, flags);
+ list_add_tail(&op->head, &qfbdev->delayed_ops);
+ spin_unlock_irqrestore(&qfbdev->delayed_ops_lock, flags);
+}
+
+static void qxl_fb_delayed_imageblit(struct qxl_fbdev *qfbdev,
+ const struct fb_image *fb_image)
+{
+ struct qxl_fb_op *op;
+ unsigned long flags;
+ uint32_t size = fb_image->width * fb_image->height * (fb_image->depth >= 8 ? fb_image->depth / 8 : 1);
+
+ op = kmalloc(sizeof(struct qxl_fb_op) + size, GFP_ATOMIC | __GFP_NOWARN);
+ if (!op)
+ return;
+
+ op->op.ib = *fb_image;
+ op->img_data = (void *)(op + 1);
+ op->op_type = QXL_FB_OP_IMAGEBLIT;
+
+ memcpy(op->img_data, fb_image->data, size);
+
+ op->op.ib.data = op->img_data;
+ spin_lock_irqsave(&qfbdev->delayed_ops_lock, flags);
+ list_add_tail(&op->head, &qfbdev->delayed_ops);
+ spin_unlock_irqrestore(&qfbdev->delayed_ops_lock, flags);
+}
+
+static void qxl_fb_fillrect_internal(struct fb_info *info,
+ const struct fb_fillrect *fb_rect)
{
struct qxl_fbdev *qfbdev = info->par;
struct qxl_device *qdev = qfbdev->qdev;
@@ -203,17 +281,28 @@ static void qxl_fb_fillrect(struct fb_info *info,
qxl_draw_fill_rec.rect = rect;
qxl_draw_fill_rec.color = color;
qxl_draw_fill_rec.rop = rop;
+
+ qxl_draw_fill(&qxl_draw_fill_rec);
+}
+
+static void qxl_fb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *fb_rect)
+{
+ struct qxl_fbdev *qfbdev = info->par;
+ struct qxl_device *qdev = qfbdev->qdev;
+
if (!drm_can_sleep()) {
- qxl_io_log(qdev,
- "%s: TODO use RCU, mysterious locks with spin_lock\n",
- __func__);
+ qxl_fb_delayed_fillrect(qfbdev, fb_rect);
+ schedule_work(&qdev->fb_work);
return;
}
- qxl_draw_fill(&qxl_draw_fill_rec);
+ /* make sure any previous work is done */
+ flush_work(&qdev->fb_work);
+ qxl_fb_fillrect_internal(info, fb_rect);
}
-static void qxl_fb_copyarea(struct fb_info *info,
- const struct fb_copyarea *region)
+static void qxl_fb_copyarea_internal(struct fb_info *info,
+ const struct fb_copyarea *region)
{
struct qxl_fbdev *qfbdev = info->par;
@@ -223,37 +312,89 @@ static void qxl_fb_copyarea(struct fb_info *info,
region->dx, region->dy);
}
+static void qxl_fb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *region)
+{
+ struct qxl_fbdev *qfbdev = info->par;
+ struct qxl_device *qdev = qfbdev->qdev;
+
+ if (!drm_can_sleep()) {
+ qxl_fb_delayed_copyarea(qfbdev, region);
+ schedule_work(&qdev->fb_work);
+ return;
+ }
+ /* make sure any previous work is done */
+ flush_work(&qdev->fb_work);
+ qxl_fb_copyarea_internal(info, region);
+}
+
static void qxl_fb_imageblit_safe(struct qxl_fb_image *qxl_fb_image)
{
qxl_draw_opaque_fb(qxl_fb_image, 0);
}
+static void qxl_fb_imageblit_internal(struct fb_info *info,
+ const struct fb_image *image)
+{
+ struct qxl_fbdev *qfbdev = info->par;
+ struct qxl_fb_image qxl_fb_image;
+
+ /* ensure proper order rendering operations - TODO: must do this
+ * for everything. */
+ qxl_fb_image_init(&qxl_fb_image, qfbdev->qdev, info, image);
+ qxl_fb_imageblit_safe(&qxl_fb_image);
+}
+
static void qxl_fb_imageblit(struct fb_info *info,
const struct fb_image *image)
{
struct qxl_fbdev *qfbdev = info->par;
struct qxl_device *qdev = qfbdev->qdev;
- struct qxl_fb_image qxl_fb_image;
if (!drm_can_sleep()) {
- /* we cannot do any ttm_bo allocation since that will fail on
- * ioremap_wc..__get_vm_area_node, so queue the work item
- * instead This can happen from printk inside an interrupt
- * context, i.e.: smp_apic_timer_interrupt..check_cpu_stall */
- qxl_io_log(qdev,
- "%s: TODO use RCU, mysterious locks with spin_lock\n",
- __func__);
+ qxl_fb_delayed_imageblit(qfbdev, image);
+ schedule_work(&qdev->fb_work);
return;
}
+ /* make sure any previous work is done */
+ flush_work(&qdev->fb_work);
+ qxl_fb_imageblit_internal(info, image);
+}
- /* ensure proper order of rendering operations - TODO: must do this
- * for everything. */
- qxl_fb_image_init(&qxl_fb_image, qfbdev->qdev, info, image);
- qxl_fb_imageblit_safe(&qxl_fb_image);
+static void qxl_fb_work(struct work_struct *work)
+{
+ struct qxl_device *qdev = container_of(work, struct qxl_device, fb_work);
+ unsigned long flags;
+ struct qxl_fb_op *entry, *tmp;
+ struct qxl_fbdev *qfbdev = qdev->mode_info.qfbdev;
+
+ /* since the irq context just adds entries to the end of the
+ list dropping the lock should be fine, as entry isn't modified
+ in the operation code */
+ spin_lock_irqsave(&qfbdev->delayed_ops_lock, flags);
+ list_for_each_entry_safe(entry, tmp, &qfbdev->delayed_ops, head) {
+ spin_unlock_irqrestore(&qfbdev->delayed_ops_lock, flags);
+ switch (entry->op_type) {
+ case QXL_FB_OP_FILLRECT:
+ qxl_fb_fillrect_internal(qfbdev->helper.fbdev, &entry->op.fr);
+ break;
+ case QXL_FB_OP_COPYAREA:
+ qxl_fb_copyarea_internal(qfbdev->helper.fbdev, &entry->op.ca);
+ break;
+ case QXL_FB_OP_IMAGEBLIT:
+ qxl_fb_imageblit_internal(qfbdev->helper.fbdev, &entry->op.ib);
+ break;
+ }
+ spin_lock_irqsave(&qfbdev->delayed_ops_lock, flags);
+ list_del(&entry->head);
+ kfree(entry);
+ }
+ spin_unlock_irqrestore(&qfbdev->delayed_ops_lock, flags);
}
int qxl_fb_init(struct qxl_device *qdev)
{
+ INIT_WORK(&qdev->fb_work, qxl_fb_work);
return 0;
}
@@ -536,7 +677,8 @@ int qxl_fbdev_init(struct qxl_device *qdev)
qfbdev->qdev = qdev;
qdev->mode_info.qfbdev = qfbdev;
qfbdev->helper.funcs = &qxl_fb_helper_funcs;
-
+ spin_lock_init(&qfbdev->delayed_ops_lock);
+ INIT_LIST_HEAD(&qfbdev->delayed_ops);
ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper,
qxl_num_crtc /* num_crtc - QXL supports just 1 */,
QXLFB_CONN_LIMIT);
diff --git a/drivers/gpu/drm/qxl/qxl_fence.c b/drivers/gpu/drm/qxl/qxl_fence.c
index 63c6715ad38..ae59e91cfb9 100644
--- a/drivers/gpu/drm/qxl/qxl_fence.c
+++ b/drivers/gpu/drm/qxl/qxl_fence.c
@@ -49,17 +49,11 @@
For some reason every so often qxl hw fails to release, things go wrong.
*/
-
-
-int qxl_fence_add_release(struct qxl_fence *qfence, uint32_t rel_id)
+/* must be called with the fence lock held */
+void qxl_fence_add_release_locked(struct qxl_fence *qfence, uint32_t rel_id)
{
- struct qxl_bo *bo = container_of(qfence, struct qxl_bo, fence);
-
- spin_lock(&bo->tbo.bdev->fence_lock);
radix_tree_insert(&qfence->tree, rel_id, qfence);
qfence->num_active_releases++;
- spin_unlock(&bo->tbo.bdev->fence_lock);
- return 0;
}
int qxl_fence_remove_release(struct qxl_fence *qfence, uint32_t rel_id)
diff --git a/drivers/gpu/drm/qxl/qxl_gem.c b/drivers/gpu/drm/qxl/qxl_gem.c
index a235693aabb..25e1777fb0a 100644
--- a/drivers/gpu/drm/qxl/qxl_gem.c
+++ b/drivers/gpu/drm/qxl/qxl_gem.c
@@ -55,7 +55,7 @@ int qxl_gem_object_create(struct qxl_device *qdev, int size,
/* At least align on page size */
if (alignment < PAGE_SIZE)
alignment = PAGE_SIZE;
- r = qxl_bo_create(qdev, size, kernel, initial_domain, surf, &qbo);
+ r = qxl_bo_create(qdev, size, kernel, false, initial_domain, surf, &qbo);
if (r) {
if (r != -ERESTARTSYS)
DRM_ERROR(
diff --git a/drivers/gpu/drm/qxl/qxl_image.c b/drivers/gpu/drm/qxl/qxl_image.c
index cf856206996..7fbcc35e8ad 100644
--- a/drivers/gpu/drm/qxl/qxl_image.c
+++ b/drivers/gpu/drm/qxl/qxl_image.c
@@ -30,31 +30,100 @@
#include "qxl_object.h"
static int
-qxl_image_create_helper(struct qxl_device *qdev,
+qxl_allocate_chunk(struct qxl_device *qdev,
+ struct qxl_release *release,
+ struct qxl_drm_image *image,
+ unsigned int chunk_size)
+{
+ struct qxl_drm_chunk *chunk;
+ int ret;
+
+ chunk = kmalloc(sizeof(struct qxl_drm_chunk), GFP_KERNEL);
+ if (!chunk)
+ return -ENOMEM;
+
+ ret = qxl_alloc_bo_reserved(qdev, release, chunk_size, &chunk->bo);
+ if (ret) {
+ kfree(chunk);
+ return ret;
+ }
+
+ list_add_tail(&chunk->head, &image->chunk_list);
+ return 0;
+}
+
+int
+qxl_image_alloc_objects(struct qxl_device *qdev,
struct qxl_release *release,
- struct qxl_bo **image_bo,
- const uint8_t *data,
- int width, int height,
- int depth, unsigned int hash,
- int stride)
+ struct qxl_drm_image **image_ptr,
+ int height, int stride)
+{
+ struct qxl_drm_image *image;
+ int ret;
+
+ image = kmalloc(sizeof(struct qxl_drm_image), GFP_KERNEL);
+ if (!image)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&image->chunk_list);
+
+ ret = qxl_alloc_bo_reserved(qdev, release, sizeof(struct qxl_image), &image->bo);
+ if (ret) {
+ kfree(image);
+ return ret;
+ }
+
+ ret = qxl_allocate_chunk(qdev, release, image, sizeof(struct qxl_data_chunk) + stride * height);
+ if (ret) {
+ qxl_bo_unref(&image->bo);
+ kfree(image);
+ return ret;
+ }
+ *image_ptr = image;
+ return 0;
+}
+
+void qxl_image_free_objects(struct qxl_device *qdev, struct qxl_drm_image *dimage)
{
+ struct qxl_drm_chunk *chunk, *tmp;
+
+ list_for_each_entry_safe(chunk, tmp, &dimage->chunk_list, head) {
+ qxl_bo_unref(&chunk->bo);
+ kfree(chunk);
+ }
+
+ qxl_bo_unref(&dimage->bo);
+ kfree(dimage);
+}
+
+static int
+qxl_image_init_helper(struct qxl_device *qdev,
+ struct qxl_release *release,
+ struct qxl_drm_image *dimage,
+ const uint8_t *data,
+ int width, int height,
+ int depth, unsigned int hash,
+ int stride)
+{
+ struct qxl_drm_chunk *drv_chunk;
struct qxl_image *image;
struct qxl_data_chunk *chunk;
int i;
int chunk_stride;
int linesize = width * depth / 8;
- struct qxl_bo *chunk_bo;
- int ret;
+ struct qxl_bo *chunk_bo, *image_bo;
void *ptr;
/* Chunk */
/* FIXME: Check integer overflow */
/* TODO: variable number of chunks */
+
+ drv_chunk = list_first_entry(&dimage->chunk_list, struct qxl_drm_chunk, head);
+
+ chunk_bo = drv_chunk->bo;
chunk_stride = stride; /* TODO: should use linesize, but it renders
wrong (check the bitmaps are sent correctly
first) */
- ret = qxl_alloc_bo_reserved(qdev, sizeof(*chunk) + height * chunk_stride,
- &chunk_bo);
-
+
ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, 0);
chunk = ptr;
chunk->data_size = height * chunk_stride;
@@ -102,7 +171,6 @@ qxl_image_create_helper(struct qxl_device *qdev,
while (remain > 0) {
page_base = out_offset & PAGE_MASK;
page_offset = offset_in_page(out_offset);
-
size = min((int)(PAGE_SIZE - page_offset), remain);
ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, page_base);
@@ -116,14 +184,10 @@ qxl_image_create_helper(struct qxl_device *qdev,
}
}
}
-
-
qxl_bo_kunmap(chunk_bo);
- /* Image */
- ret = qxl_alloc_bo_reserved(qdev, sizeof(*image), image_bo);
-
- ptr = qxl_bo_kmap_atomic_page(qdev, *image_bo, 0);
+ image_bo = dimage->bo;
+ ptr = qxl_bo_kmap_atomic_page(qdev, image_bo, 0);
image = ptr;
image->descriptor.id = 0;
@@ -154,23 +218,20 @@ qxl_image_create_helper(struct qxl_device *qdev,
image->u.bitmap.stride = chunk_stride;
image->u.bitmap.palette = 0;
image->u.bitmap.data = qxl_bo_physical_address(qdev, chunk_bo, 0);
- qxl_release_add_res(qdev, release, chunk_bo);
- qxl_bo_unreserve(chunk_bo);
- qxl_bo_unref(&chunk_bo);
- qxl_bo_kunmap_atomic_page(qdev, *image_bo, ptr);
+ qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
return 0;
}
-int qxl_image_create(struct qxl_device *qdev,
+int qxl_image_init(struct qxl_device *qdev,
struct qxl_release *release,
- struct qxl_bo **image_bo,
+ struct qxl_drm_image *dimage,
const uint8_t *data,
int x, int y, int width, int height,
int depth, int stride)
{
data += y * stride + x * (depth / 8);
- return qxl_image_create_helper(qdev, release, image_bo, data,
+ return qxl_image_init_helper(qdev, release, dimage, data,
width, height, depth, 0, stride);
}
diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c
index 27f45e49250..6de33563d6f 100644
--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -68,55 +68,60 @@ static int qxl_map_ioctl(struct drm_device *dev, void *data,
&qxl_map->offset);
}
+struct qxl_reloc_info {
+ int type;
+ struct qxl_bo *dst_bo;
+ uint32_t dst_offset;
+ struct qxl_bo *src_bo;
+ int src_offset;
+};
+
/*
* dst must be validated, i.e. whole bo on vram/surfacesram (right now all bo's
* are on vram).
* *(dst + dst_off) = qxl_bo_physical_address(src, src_off)
*/
static void
-apply_reloc(struct qxl_device *qdev, struct qxl_bo *dst, uint64_t dst_off,
- struct qxl_bo *src, uint64_t src_off)
+apply_reloc(struct qxl_device *qdev, struct qxl_reloc_info *info)
{
void *reloc_page;
-
- reloc_page = qxl_bo_kmap_atomic_page(qdev, dst, dst_off & PAGE_MASK);
- *(uint64_t *)(reloc_page + (dst_off & ~PAGE_MASK)) = qxl_bo_physical_address(qdev,
- src, src_off);
- qxl_bo_kunmap_atomic_page(qdev, dst, reloc_page);
+ reloc_page = qxl_bo_kmap_atomic_page(qdev, info->dst_bo, info->dst_offset & PAGE_MASK);
+ *(uint64_t *)(reloc_page + (info->dst_offset & ~PAGE_MASK)) = qxl_bo_physical_address(qdev,
+ info->src_bo,
+ info->src_offset);
+ qxl_bo_kunmap_atomic_page(qdev, info->dst_bo, reloc_page);
}
static void
-apply_surf_reloc(struct qxl_device *qdev, struct qxl_bo *dst, uint64_t dst_off,
- struct qxl_bo *src)
+apply_surf_reloc(struct qxl_device *qdev, struct qxl_reloc_info *info)
{
uint32_t id = 0;
void *reloc_page;
- if (src && !src->is_primary)
- id = src->surface_id;
+ if (info->src_bo && !info->src_bo->is_primary)
+ id = info->src_bo->surface_id;
- reloc_page = qxl_bo_kmap_atomic_page(qdev, dst, dst_off & PAGE_MASK);
- *(uint32_t *)(reloc_page + (dst_off & ~PAGE_MASK)) = id;
- qxl_bo_kunmap_atomic_page(qdev, dst, reloc_page);
+ reloc_page = qxl_bo_kmap_atomic_page(qdev, info->dst_bo, info->dst_offset & PAGE_MASK);
+ *(uint32_t *)(reloc_page + (info->dst_offset & ~PAGE_MASK)) = id;
+ qxl_bo_kunmap_atomic_page(qdev, info->dst_bo, reloc_page);
}
/* return holding the reference to this object */
static struct qxl_bo *qxlhw_handle_to_bo(struct qxl_device *qdev,
struct drm_file *file_priv, uint64_t handle,
- struct qxl_reloc_list *reloc_list)
+ struct qxl_release *release)
{
struct drm_gem_object *gobj;
struct qxl_bo *qobj;
int ret;
gobj = drm_gem_object_lookup(qdev->ddev, file_priv, handle);
- if (!gobj) {
- DRM_ERROR("bad bo handle %lld\n", handle);
+ if (!gobj)
return NULL;
- }
+
qobj = gem_to_qxl_bo(gobj);
- ret = qxl_bo_list_add(reloc_list, qobj);
+ ret = qxl_release_list_add(release, qobj);
if (ret)
return NULL;
@@ -129,151 +134,177 @@ static struct qxl_bo *qxlhw_handle_to_bo(struct qxl_device *qdev,
* However, the command as passed from user space must *not* contain the initial
* QXLReleaseInfo struct (first XXX bytes)
*/
-static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+static int qxl_process_single_command(struct qxl_device *qdev,
+ struct drm_qxl_command *cmd,
+ struct drm_file *file_priv)
{
- struct qxl_device *qdev = dev->dev_private;
- struct drm_qxl_execbuffer *execbuffer = data;
- struct drm_qxl_command user_cmd;
- int cmd_num;
- struct qxl_bo *reloc_src_bo;
- struct qxl_bo *reloc_dst_bo;
- struct drm_qxl_reloc reloc;
+ struct qxl_reloc_info *reloc_info;
+ int release_type;
+ struct qxl_release *release;
+ struct qxl_bo *cmd_bo;
void *fb_cmd;
- int i, ret;
- struct qxl_reloc_list reloc_list;
+ int i, j, ret, num_relocs;
int unwritten;
- uint32_t reloc_dst_offset;
- INIT_LIST_HEAD(&reloc_list.bos);
- for (cmd_num = 0; cmd_num < execbuffer->commands_num; ++cmd_num) {
- struct qxl_release *release;
- struct qxl_bo *cmd_bo;
- int release_type;
- struct drm_qxl_command *commands =
- (struct drm_qxl_command *)(uintptr_t)execbuffer->commands;
+ switch (cmd->type) {
+ case QXL_CMD_DRAW:
+ release_type = QXL_RELEASE_DRAWABLE;
+ break;
+ case QXL_CMD_SURFACE:
+ case QXL_CMD_CURSOR:
+ default:
+ DRM_DEBUG("Only draw commands in execbuffers\n");
+ return -EINVAL;
+ break;
+ }
- if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num],
- sizeof(user_cmd)))
- return -EFAULT;
- switch (user_cmd.type) {
- case QXL_CMD_DRAW:
- release_type = QXL_RELEASE_DRAWABLE;
- break;
- case QXL_CMD_SURFACE:
- case QXL_CMD_CURSOR:
- default:
- DRM_DEBUG("Only draw commands in execbuffers\n");
- return -EINVAL;
- break;
- }
+ if (cmd->command_size > PAGE_SIZE - sizeof(union qxl_release_info))
+ return -EINVAL;
- if (user_cmd.command_size > PAGE_SIZE - sizeof(union qxl_release_info))
- return -EINVAL;
+ if (!access_ok(VERIFY_READ,
+ (void *)(unsigned long)cmd->command,
+ cmd->command_size))
+ return -EFAULT;
- if (!access_ok(VERIFY_READ,
- (void *)(unsigned long)user_cmd.command,
- user_cmd.command_size))
- return -EFAULT;
+ reloc_info = kmalloc(sizeof(struct qxl_reloc_info) * cmd->relocs_num, GFP_KERNEL);
+ if (!reloc_info)
+ return -ENOMEM;
- ret = qxl_alloc_release_reserved(qdev,
- sizeof(union qxl_release_info) +
- user_cmd.command_size,
- release_type,
- &release,
- &cmd_bo);
- if (ret)
- return ret;
+ ret = qxl_alloc_release_reserved(qdev,
+ sizeof(union qxl_release_info) +
+ cmd->command_size,
+ release_type,
+ &release,
+ &cmd_bo);
+ if (ret)
+ goto out_free_reloc;
- /* TODO copy slow path code from i915 */
- fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE));
- unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)user_cmd.command, user_cmd.command_size);
+ /* TODO copy slow path code from i915 */
+ fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE));
+ unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)cmd->command, cmd->command_size);
- {
- struct qxl_drawable *draw = fb_cmd;
+ {
+ struct qxl_drawable *draw = fb_cmd;
+ draw->mm_time = qdev->rom->mm_clock;
+ }
- draw->mm_time = qdev->rom->mm_clock;
- }
- qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd);
- if (unwritten) {
- DRM_ERROR("got unwritten %d\n", unwritten);
- qxl_release_unreserve(qdev, release);
- qxl_release_free(qdev, release);
- return -EFAULT;
+ qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd);
+ if (unwritten) {
+ DRM_ERROR("got unwritten %d\n", unwritten);
+ ret = -EFAULT;
+ goto out_free_release;
+ }
+
+ /* fill out reloc info structs */
+ num_relocs = 0;
+ for (i = 0; i < cmd->relocs_num; ++i) {
+ struct drm_qxl_reloc reloc;
+
+ if (DRM_COPY_FROM_USER(&reloc,
+ &((struct drm_qxl_reloc *)(uintptr_t)cmd->relocs)[i],
+ sizeof(reloc))) {
+ ret = -EFAULT;
+ goto out_free_bos;
}
- for (i = 0 ; i < user_cmd.relocs_num; ++i) {
- if (DRM_COPY_FROM_USER(&reloc,
- &((struct drm_qxl_reloc *)(uintptr_t)user_cmd.relocs)[i],
- sizeof(reloc))) {
- qxl_bo_list_unreserve(&reloc_list, true);
- qxl_release_unreserve(qdev, release);
- qxl_release_free(qdev, release);
- return -EFAULT;
- }
+ /* add the bos to the list of bos to validate -
+ need to validate first then process relocs? */
+ if (reloc.reloc_type != QXL_RELOC_TYPE_BO && reloc.reloc_type != QXL_RELOC_TYPE_SURF) {
+ DRM_DEBUG("unknown reloc type %d\n", reloc_info[i].type);
- /* add the bos to the list of bos to validate -
- need to validate first then process relocs? */
- if (reloc.dst_handle) {
- reloc_dst_bo = qxlhw_handle_to_bo(qdev, file_priv,
- reloc.dst_handle, &reloc_list);
- if (!reloc_dst_bo) {
- qxl_bo_list_unreserve(&reloc_list, true);
- qxl_release_unreserve(qdev, release);
- qxl_release_free(qdev, release);
- return -EINVAL;
- }
- reloc_dst_offset = 0;
- } else {
- reloc_dst_bo = cmd_bo;
- reloc_dst_offset = release->release_offset;
+ ret = -EINVAL;
+ goto out_free_bos;
+ }
+ reloc_info[i].type = reloc.reloc_type;
+
+ if (reloc.dst_handle) {
+ reloc_info[i].dst_bo = qxlhw_handle_to_bo(qdev, file_priv,
+ reloc.dst_handle, release);
+ if (!reloc_info[i].dst_bo) {
+ ret = -EINVAL;
+ reloc_info[i].src_bo = NULL;
+ goto out_free_bos;
}
-
- /* reserve and validate the reloc dst bo */
- if (reloc.reloc_type == QXL_RELOC_TYPE_BO || reloc.src_handle > 0) {
- reloc_src_bo =
- qxlhw_handle_to_bo(qdev, file_priv,
- reloc.src_handle, &reloc_list);
- if (!reloc_src_bo) {
- if (reloc_dst_bo != cmd_bo)
- drm_gem_object_unreference_unlocked(&reloc_dst_bo->gem_base);
- qxl_bo_list_unreserve(&reloc_list, true);
- qxl_release_unreserve(qdev, release);
- qxl_release_free(qdev, release);
- return -EINVAL;
- }
- } else
- reloc_src_bo = NULL;
- if (reloc.reloc_type == QXL_RELOC_TYPE_BO) {
- apply_reloc(qdev, reloc_dst_bo, reloc_dst_offset + reloc.dst_offset,
- reloc_src_bo, reloc.src_offset);
- } else if (reloc.reloc_type == QXL_RELOC_TYPE_SURF) {
- apply_surf_reloc(qdev, reloc_dst_bo, reloc_dst_offset + reloc.dst_offset, reloc_src_bo);
- } else {
- DRM_ERROR("unknown reloc type %d\n", reloc.reloc_type);
- return -EINVAL;
+ reloc_info[i].dst_offset = reloc.dst_offset;
+ } else {
+ reloc_info[i].dst_bo = cmd_bo;
+ reloc_info[i].dst_offset = reloc.dst_offset + release->release_offset;
+ }
+ num_relocs++;
+
+ /* reserve and validate the reloc dst bo */
+ if (reloc.reloc_type == QXL_RELOC_TYPE_BO || reloc.src_handle > 0) {
+ reloc_info[i].src_bo =
+ qxlhw_handle_to_bo(qdev, file_priv,
+ reloc.src_handle, release);
+ if (!reloc_info[i].src_bo) {
+ if (reloc_info[i].dst_bo != cmd_bo)
+ drm_gem_object_unreference_unlocked(&reloc_info[i].dst_bo->gem_base);
+ ret = -EINVAL;
+ goto out_free_bos;
}
+ reloc_info[i].src_offset = reloc.src_offset;
+ } else {
+ reloc_info[i].src_bo = NULL;
+ reloc_info[i].src_offset = 0;
+ }
+ }
- if (reloc_src_bo && reloc_src_bo != cmd_bo) {
- qxl_release_add_res(qdev, release, reloc_src_bo);
- drm_gem_object_unreference_unlocked(&reloc_src_bo->gem_base);
- }
+ /* validate all buffers */
+ ret = qxl_release_reserve_list(release, false);
+ if (ret)
+ goto out_free_bos;
- if (reloc_dst_bo != cmd_bo)
- drm_gem_object_unreference_unlocked(&reloc_dst_bo->gem_base);
- }
- qxl_fence_releaseable(qdev, release);
+ for (i = 0; i < cmd->relocs_num; ++i) {
+ if (reloc_info[i].type == QXL_RELOC_TYPE_BO)
+ apply_reloc(qdev, &reloc_info[i]);
+ else if (reloc_info[i].type == QXL_RELOC_TYPE_SURF)
+ apply_surf_reloc(qdev, &reloc_info[i]);
+ }
- ret = qxl_push_command_ring_release(qdev, release, user_cmd.type, true);
- if (ret == -ERESTARTSYS) {
- qxl_release_unreserve(qdev, release);
- qxl_release_free(qdev, release);
- qxl_bo_list_unreserve(&reloc_list, true);
+ ret = qxl_push_command_ring_release(qdev, release, cmd->type, true);
+ if (ret)
+ qxl_release_backoff_reserve_list(release);
+ else
+ qxl_release_fence_buffer_objects(release);
+
+out_free_bos:
+ for (j = 0; j < num_relocs; j++) {
+ if (reloc_info[j].dst_bo != cmd_bo)
+ drm_gem_object_unreference_unlocked(&reloc_info[j].dst_bo->gem_base);
+ if (reloc_info[j].src_bo && reloc_info[j].src_bo != cmd_bo)
+ drm_gem_object_unreference_unlocked(&reloc_info[j].src_bo->gem_base);
+ }
+out_free_release:
+ if (ret)
+ qxl_release_free(qdev, release);
+out_free_reloc:
+ kfree(reloc_info);
+ return ret;
+}
+
+static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct qxl_device *qdev = dev->dev_private;
+ struct drm_qxl_execbuffer *execbuffer = data;
+ struct drm_qxl_command user_cmd;
+ int cmd_num;
+ int ret;
+
+ for (cmd_num = 0; cmd_num < execbuffer->commands_num; ++cmd_num) {
+
+ struct drm_qxl_command *commands =
+ (struct drm_qxl_command *)(uintptr_t)execbuffer->commands;
+
+ if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num],
+ sizeof(user_cmd)))
+ return -EFAULT;
+
+ ret = qxl_process_single_command(qdev, &user_cmd, file_priv);
+ if (ret)
return ret;
- }
- qxl_release_unreserve(qdev, release);
}
- qxl_bo_list_unreserve(&reloc_list, 0);
return 0;
}
@@ -305,7 +336,7 @@ static int qxl_update_area_ioctl(struct drm_device *dev, void *data,
goto out;
if (!qobj->pin_count) {
- qxl_ttm_placement_from_domain(qobj, qobj->type);
+ qxl_ttm_placement_from_domain(qobj, qobj->type, false);
ret = ttm_bo_validate(&qobj->tbo, &qobj->placement,
true, false);
if (unlikely(ret))
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index 1191fe7788c..aa161cddd87 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -51,20 +51,21 @@ bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo)
return false;
}
-void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain)
+void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
{
u32 c = 0;
+ u32 pflag = pinned ? TTM_PL_FLAG_NO_EVICT : 0;
qbo->placement.fpfn = 0;
qbo->placement.lpfn = 0;
qbo->placement.placement = qbo->placements;
qbo->placement.busy_placement = qbo->placements;
if (domain == QXL_GEM_DOMAIN_VRAM)
- qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM;
+ qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag;
if (domain == QXL_GEM_DOMAIN_SURFACE)
- qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0;
+ qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0 | pflag;
if (domain == QXL_GEM_DOMAIN_CPU)
- qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+ qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM | pflag;
if (!c)
qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
qbo->placement.num_placement = c;
@@ -73,7 +74,7 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain)
int qxl_bo_create(struct qxl_device *qdev,
- unsigned long size, bool kernel, u32 domain,
+ unsigned long size, bool kernel, bool pinned, u32 domain,
struct qxl_surface *surf,
struct qxl_bo **bo_ptr)
{
@@ -99,15 +100,15 @@ int qxl_bo_create(struct qxl_device *qdev,
}
bo->gem_base.driver_private = NULL;
bo->type = domain;
- bo->pin_count = 0;
+ bo->pin_count = pinned ? 1 : 0;
bo->surface_id = 0;
qxl_fence_init(qdev, &bo->fence);
INIT_LIST_HEAD(&bo->list);
- atomic_set(&bo->reserve_count, 0);
+
if (surf)
bo->surf = *surf;
- qxl_ttm_placement_from_domain(bo, domain);
+ qxl_ttm_placement_from_domain(bo, domain, pinned);
r = ttm_bo_init(&qdev->mman.bdev, &bo->tbo, size, type,
&bo->placement, 0, !kernel, NULL, size,
@@ -228,7 +229,7 @@ struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo)
int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr)
{
struct qxl_device *qdev = (struct qxl_device *)bo->gem_base.dev->dev_private;
- int r, i;
+ int r;
if (bo->pin_count) {
bo->pin_count++;
@@ -236,9 +237,7 @@ int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr)
*gpu_addr = qxl_bo_gpu_offset(bo);
return 0;
}
- qxl_ttm_placement_from_domain(bo, domain);
- for (i = 0; i < bo->placement.num_placement; i++)
- bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+ qxl_ttm_placement_from_domain(bo, domain, true);
r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
if (likely(r == 0)) {
bo->pin_count = 1;
@@ -317,53 +316,6 @@ int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo)
return 0;
}
-void qxl_bo_list_unreserve(struct qxl_reloc_list *reloc_list, bool failed)
-{
- struct qxl_bo_list *entry, *sf;
-
- list_for_each_entry_safe(entry, sf, &reloc_list->bos, lhead) {
- qxl_bo_unreserve(entry->bo);
- list_del(&entry->lhead);
- kfree(entry);
- }
-}
-
-int qxl_bo_list_add(struct qxl_reloc_list *reloc_list, struct qxl_bo *bo)
-{
- struct qxl_bo_list *entry;
- int ret;
-
- list_for_each_entry(entry, &reloc_list->bos, lhead) {
- if (entry->bo == bo)
- return 0;
- }
-
- entry = kmalloc(sizeof(struct qxl_bo_list), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- entry->bo = bo;
- list_add(&entry->lhead, &reloc_list->bos);
-
- ret = qxl_bo_reserve(bo, false);
- if (ret)
- return ret;
-
- if (!bo->pin_count) {
- qxl_ttm_placement_from_domain(bo, bo->type);
- ret = ttm_bo_validate(&bo->tbo, &bo->placement,
- true, false);
- if (ret)
- return ret;
- }
-
- /* allocate a surface for reserved + validated buffers */
- ret = qxl_bo_check_id(bo->gem_base.dev->dev_private, bo);
- if (ret)
- return ret;
- return 0;
-}
-
int qxl_surf_evict(struct qxl_device *qdev)
{
return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0);
diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h
index ee7ad79ce78..8cb6167038e 100644
--- a/drivers/gpu/drm/qxl/qxl_object.h
+++ b/drivers/gpu/drm/qxl/qxl_object.h
@@ -88,7 +88,7 @@ static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type,
extern int qxl_bo_create(struct qxl_device *qdev,
unsigned long size,
- bool kernel, u32 domain,
+ bool kernel, bool pinned, u32 domain,
struct qxl_surface *surf,
struct qxl_bo **bo_ptr);
extern int qxl_bo_kmap(struct qxl_bo *bo, void **ptr);
@@ -99,9 +99,7 @@ extern struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo);
extern void qxl_bo_unref(struct qxl_bo **bo);
extern int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr);
extern int qxl_bo_unpin(struct qxl_bo *bo);
-extern void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain);
+extern void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned);
extern bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo);
-extern int qxl_bo_list_add(struct qxl_reloc_list *reloc_list, struct qxl_bo *bo);
-extern void qxl_bo_list_unreserve(struct qxl_reloc_list *reloc_list, bool failed);
#endif
diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c
index b443d6751d5..b61449e52cd 100644
--- a/drivers/gpu/drm/qxl/qxl_release.c
+++ b/drivers/gpu/drm/qxl/qxl_release.c
@@ -38,7 +38,8 @@
static const int release_size_per_bo[] = { RELEASE_SIZE, SURFACE_RELEASE_SIZE, RELEASE_SIZE };
static const int releases_per_bo[] = { RELEASES_PER_BO, SURFACE_RELEASES_PER_BO, RELEASES_PER_BO };
-uint64_t
+
+static uint64_t
qxl_release_alloc(struct qxl_device *qdev, int type,
struct qxl_release **ret)
{
@@ -53,9 +54,9 @@ qxl_release_alloc(struct qxl_device *qdev, int type,
return 0;
}
release->type = type;
- release->bo_count = 0;
release->release_offset = 0;
release->surface_release_id = 0;
+ INIT_LIST_HEAD(&release->bos);
idr_preload(GFP_KERNEL);
spin_lock(&qdev->release_idr_lock);
@@ -77,20 +78,20 @@ void
qxl_release_free(struct qxl_device *qdev,
struct qxl_release *release)
{
- int i;
-
- QXL_INFO(qdev, "release %d, type %d, %d bos\n", release->id,
- release->type, release->bo_count);
+ struct qxl_bo_list *entry, *tmp;
+ QXL_INFO(qdev, "release %d, type %d\n", release->id,
+ release->type);
if (release->surface_release_id)
qxl_surface_id_dealloc(qdev, release->surface_release_id);
- for (i = 0 ; i < release->bo_count; ++i) {
+ list_for_each_entry_safe(entry, tmp, &release->bos, tv.head) {
+ struct qxl_bo *bo = to_qxl_bo(entry->tv.bo);
QXL_INFO(qdev, "release %llx\n",
- release->bos[i]->tbo.addr_space_offset
+ entry->tv.bo->addr_space_offset
- DRM_FILE_OFFSET);
- qxl_fence_remove_release(&release->bos[i]->fence, release->id);
- qxl_bo_unref(&release->bos[i]);
+ qxl_fence_remove_release(&bo->fence, release->id);
+ qxl_bo_unref(&bo);
}
spin_lock(&qdev->release_idr_lock);
idr_remove(&qdev->release_idr, release->id);
@@ -98,83 +99,117 @@ qxl_release_free(struct qxl_device *qdev,
kfree(release);
}
-void
-qxl_release_add_res(struct qxl_device *qdev, struct qxl_release *release,
- struct qxl_bo *bo)
-{
- int i;
- for (i = 0; i < release->bo_count; i++)
- if (release->bos[i] == bo)
- return;
-
- if (release->bo_count >= QXL_MAX_RES) {
- DRM_ERROR("exceeded max resource on a qxl_release item\n");
- return;
- }
- release->bos[release->bo_count++] = qxl_bo_ref(bo);
-}
-
static int qxl_release_bo_alloc(struct qxl_device *qdev,
struct qxl_bo **bo)
{
int ret;
- ret = qxl_bo_create(qdev, PAGE_SIZE, false, QXL_GEM_DOMAIN_VRAM, NULL,
+ /* pin releases bo's they are too messy to evict */
+ ret = qxl_bo_create(qdev, PAGE_SIZE, false, true,
+ QXL_GEM_DOMAIN_VRAM, NULL,
bo);
return ret;
}
-int qxl_release_reserve(struct qxl_device *qdev,
- struct qxl_release *release, bool no_wait)
+int qxl_release_list_add(struct qxl_release *release, struct qxl_bo *bo)
+{
+ struct qxl_bo_list *entry;
+
+ list_for_each_entry(entry, &release->bos, tv.head) {
+ if (entry->tv.bo == &bo->tbo)
+ return 0;
+ }
+
+ entry = kmalloc(sizeof(struct qxl_bo_list), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ qxl_bo_ref(bo);
+ entry->tv.bo = &bo->tbo;
+ list_add_tail(&entry->tv.head, &release->bos);
+ return 0;
+}
+
+static int qxl_release_validate_bo(struct qxl_bo *bo)
{
int ret;
- if (atomic_inc_return(&release->bos[0]->reserve_count) == 1) {
- ret = qxl_bo_reserve(release->bos[0], no_wait);
+
+ if (!bo->pin_count) {
+ qxl_ttm_placement_from_domain(bo, bo->type, false);
+ ret = ttm_bo_validate(&bo->tbo, &bo->placement,
+ true, false);
if (ret)
return ret;
}
+
+ /* allocate a surface for reserved + validated buffers */
+ ret = qxl_bo_check_id(bo->gem_base.dev->dev_private, bo);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+int qxl_release_reserve_list(struct qxl_release *release, bool no_intr)
+{
+ int ret;
+ struct qxl_bo_list *entry;
+
+ /* if only one object on the release its the release itself
+ since these objects are pinned no need to reserve */
+ if (list_is_singular(&release->bos))
+ return 0;
+
+ ret = ttm_eu_reserve_buffers(&release->ticket, &release->bos);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(entry, &release->bos, tv.head) {
+ struct qxl_bo *bo = to_qxl_bo(entry->tv.bo);
+
+ ret = qxl_release_validate_bo(bo);
+ if (ret) {
+ ttm_eu_backoff_reservation(&release->ticket, &release->bos);
+ return ret;
+ }
+ }
return 0;
}
-void qxl_release_unreserve(struct qxl_device *qdev,
- struct qxl_release *release)
+void qxl_release_backoff_reserve_list(struct qxl_release *release)
{
- if (atomic_dec_and_test(&release->bos[0]->reserve_count))
- qxl_bo_unreserve(release->bos[0]);
+ /* if only one object on the release its the release itself
+ since these objects are pinned no need to reserve */
+ if (list_is_singular(&release->bos))
+ return;
+
+ ttm_eu_backoff_reservation(&release->ticket, &release->bos);
}
+
int qxl_alloc_surface_release_reserved(struct qxl_device *qdev,
enum qxl_surface_cmd_type surface_cmd_type,
struct qxl_release *create_rel,
struct qxl_release **release)
{
- int ret;
-
if (surface_cmd_type == QXL_SURFACE_CMD_DESTROY && create_rel) {
int idr_ret;
+ struct qxl_bo_list *entry = list_first_entry(&create_rel->bos, struct qxl_bo_list, tv.head);
struct qxl_bo *bo;
union qxl_release_info *info;
/* stash the release after the create command */
idr_ret = qxl_release_alloc(qdev, QXL_RELEASE_SURFACE_CMD, release);
- bo = qxl_bo_ref(create_rel->bos[0]);
+ bo = qxl_bo_ref(to_qxl_bo(entry->tv.bo));
(*release)->release_offset = create_rel->release_offset + 64;
- qxl_release_add_res(qdev, *release, bo);
+ qxl_release_list_add(*release, bo);
- ret = qxl_release_reserve(qdev, *release, false);
- if (ret) {
- DRM_ERROR("release reserve failed\n");
- goto out_unref;
- }
info = qxl_release_map(qdev, *release);
info->id = idr_ret;
qxl_release_unmap(qdev, *release, info);
-
-out_unref:
qxl_bo_unref(&bo);
- return ret;
+ return 0;
}
return qxl_alloc_release_reserved(qdev, sizeof(struct qxl_surface_cmd),
@@ -187,7 +222,7 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
{
struct qxl_bo *bo;
int idr_ret;
- int ret;
+ int ret = 0;
union qxl_release_info *info;
int cur_idx;
@@ -216,11 +251,6 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
mutex_unlock(&qdev->release_mutex);
return ret;
}
-
- /* pin releases bo's they are too messy to evict */
- ret = qxl_bo_reserve(qdev->current_release_bo[cur_idx], false);
- qxl_bo_pin(qdev->current_release_bo[cur_idx], QXL_GEM_DOMAIN_VRAM, NULL);
- qxl_bo_unreserve(qdev->current_release_bo[cur_idx]);
}
bo = qxl_bo_ref(qdev->current_release_bo[cur_idx]);
@@ -231,36 +261,18 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
if (rbo)
*rbo = bo;
- qxl_release_add_res(qdev, *release, bo);
-
- ret = qxl_release_reserve(qdev, *release, false);
mutex_unlock(&qdev->release_mutex);
- if (ret)
- goto out_unref;
+
+ qxl_release_list_add(*release, bo);
info = qxl_release_map(qdev, *release);
info->id = idr_ret;
qxl_release_unmap(qdev, *release, info);
-out_unref:
qxl_bo_unref(&bo);
return ret;
}
-int qxl_fence_releaseable(struct qxl_device *qdev,
- struct qxl_release *release)
-{
- int i, ret;
- for (i = 0; i < release->bo_count; i++) {
- if (!release->bos[i]->tbo.sync_obj)
- release->bos[i]->tbo.sync_obj = &release->bos[i]->fence;
- ret = qxl_fence_add_release(&release->bos[i]->fence, release->id);
- if (ret)
- return ret;
- }
- return 0;
-}
-
struct qxl_release *qxl_release_from_id_locked(struct qxl_device *qdev,
uint64_t id)
{
@@ -273,10 +285,7 @@ struct qxl_release *qxl_release_from_id_locked(struct qxl_device *qdev,
DRM_ERROR("failed to find id in release_idr\n");
return NULL;
}
- if (release->bo_count < 1) {
- DRM_ERROR("read a released resource with 0 bos\n");
- return NULL;
- }
+
return release;
}
@@ -285,9 +294,12 @@ union qxl_release_info *qxl_release_map(struct qxl_device *qdev,
{
void *ptr;
union qxl_release_info *info;
- struct qxl_bo *bo = release->bos[0];
+ struct qxl_bo_list *entry = list_first_entry(&release->bos, struct qxl_bo_list, tv.head);
+ struct qxl_bo *bo = to_qxl_bo(entry->tv.bo);
ptr = qxl_bo_kmap_atomic_page(qdev, bo, release->release_offset & PAGE_SIZE);
+ if (!ptr)
+ return NULL;
info = ptr + (release->release_offset & ~PAGE_SIZE);
return info;
}
@@ -296,9 +308,51 @@ void qxl_release_unmap(struct qxl_device *qdev,
struct qxl_release *release,
union qxl_release_info *info)
{
- struct qxl_bo *bo = release->bos[0];
+ struct qxl_bo_list *entry = list_first_entry(&release->bos, struct qxl_bo_list, tv.head);
+ struct qxl_bo *bo = to_qxl_bo(entry->tv.bo);
void *ptr;
ptr = ((void *)info) - (release->release_offset & ~PAGE_SIZE);
qxl_bo_kunmap_atomic_page(qdev, bo, ptr);
}
+
+void qxl_release_fence_buffer_objects(struct qxl_release *release)
+{
+ struct ttm_validate_buffer *entry;
+ struct ttm_buffer_object *bo;
+ struct ttm_bo_global *glob;
+ struct ttm_bo_device *bdev;
+ struct ttm_bo_driver *driver;
+ struct qxl_bo *qbo;
+
+ /* if only one object on the release its the release itself
+ since these objects are pinned no need to reserve */
+ if (list_is_singular(&release->bos))
+ return;
+
+ bo = list_first_entry(&release->bos, struct ttm_validate_buffer, head)->bo;
+ bdev = bo->bdev;
+ driver = bdev->driver;
+ glob = bo->glob;
+
+ spin_lock(&glob->lru_lock);
+ spin_lock(&bdev->fence_lock);
+
+ list_for_each_entry(entry, &release->bos, head) {
+ bo = entry->bo;
+ qbo = to_qxl_bo(bo);
+
+ if (!entry->bo->sync_obj)
+ entry->bo->sync_obj = &qbo->fence;
+
+ qxl_fence_add_release_locked(&qbo->fence, release->id);
+
+ ttm_bo_add_to_lru(bo);
+ ww_mutex_unlock(&bo->resv->lock);
+ entry->reserved = false;
+ }
+ spin_unlock(&bdev->fence_lock);
+ spin_unlock(&glob->lru_lock);
+ ww_acquire_fini(&release->ticket);
+}
+
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c
index 489cb8cece4..1dfd84cda2a 100644
--- a/drivers/gpu/drm/qxl/qxl_ttm.c
+++ b/drivers/gpu/drm/qxl/qxl_ttm.c
@@ -206,7 +206,7 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo,
return;
}
qbo = container_of(bo, struct qxl_bo, tbo);
- qxl_ttm_placement_from_domain(qbo, QXL_GEM_DOMAIN_CPU);
+ qxl_ttm_placement_from_domain(qbo, QXL_GEM_DOMAIN_CPU, false);
*placement = qbo->placement;
}
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index fb441a790f3..15da7ef344a 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -1222,12 +1222,17 @@ int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
int r;
mutex_lock(&ctx->mutex);
+ /* reset data block */
+ ctx->data_block = 0;
/* reset reg block */
ctx->reg_block = 0;
/* reset fb window */
ctx->fb_base = 0;
/* reset io mode */
ctx->io_mode = ATOM_IO_MM;
+ /* reset divmul */
+ ctx->divmul[0] = 0;
+ ctx->divmul[1] = 0;
r = atom_execute_table_locked(ctx, index, params);
mutex_unlock(&ctx->mutex);
return r;
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 064023bed48..32501f6ec99 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -44,6 +44,41 @@ static char *pre_emph_names[] = {
};
/***** radeon AUX functions *****/
+
+/* Atom needs data in little endian format
+ * so swap as appropriate when copying data to
+ * or from atom. Note that atom operates on
+ * dw units.
+ */
+static void radeon_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
+{
+#ifdef __BIG_ENDIAN
+ u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */
+ u32 *dst32, *src32;
+ int i;
+
+ memcpy(src_tmp, src, num_bytes);
+ src32 = (u32 *)src_tmp;
+ dst32 = (u32 *)dst_tmp;
+ if (to_le) {
+ for (i = 0; i < ((num_bytes + 3) / 4); i++)
+ dst32[i] = cpu_to_le32(src32[i]);
+ memcpy(dst, dst_tmp, num_bytes);
+ } else {
+ u8 dws = num_bytes & ~3;
+ for (i = 0; i < ((num_bytes + 3) / 4); i++)
+ dst32[i] = le32_to_cpu(src32[i]);
+ memcpy(dst, dst_tmp, dws);
+ if (num_bytes % 4) {
+ for (i = 0; i < (num_bytes % 4); i++)
+ dst[dws+i] = dst_tmp[dws+i];
+ }
+ }
+#else
+ memcpy(dst, src, num_bytes);
+#endif
+}
+
union aux_channel_transaction {
PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
@@ -65,10 +100,10 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);
- memcpy(base, send, send_bytes);
+ radeon_copy_swap(base, send, send_bytes, true);
- args.v1.lpAuxRequest = 0 + 4;
- args.v1.lpDataOut = 16 + 4;
+ args.v1.lpAuxRequest = cpu_to_le16((u16)(0 + 4));
+ args.v1.lpDataOut = cpu_to_le16((u16)(16 + 4));
args.v1.ucDataOutLen = 0;
args.v1.ucChannelID = chan->rec.i2c_id;
args.v1.ucDelay = delay / 10;
@@ -102,7 +137,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
recv_bytes = recv_size;
if (recv && recv_size)
- memcpy(recv, base + 16, recv_bytes);
+ radeon_copy_swap(recv, base + 16, recv_bytes, false);
return recv_bytes;
}
diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 0bfd55e0882..9953e1fbc46 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -2548,9 +2548,6 @@ int btc_dpm_init(struct radeon_device *rdev)
{
struct rv7xx_power_info *pi;
struct evergreen_power_info *eg_pi;
- int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
- u16 data_offset, size;
- u8 frev, crev;
struct atom_clock_dividers dividers;
int ret;
@@ -2633,16 +2630,7 @@ int btc_dpm_init(struct radeon_device *rdev)
eg_pi->vddci_control =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0);
- if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
- &frev, &crev, &data_offset)) {
- pi->sclk_ss = true;
- pi->mclk_ss = true;
- pi->dynamic_ss = true;
- } else {
- pi->sclk_ss = false;
- pi->mclk_ss = false;
- pi->dynamic_ss = true;
- }
+ rv770_get_engine_memory_ss(rdev);
pi->asi = RV770_ASI_DFLT;
pi->pasi = CYPRESS_HASI_DFLT;
@@ -2659,8 +2647,7 @@ int btc_dpm_init(struct radeon_device *rdev)
pi->dynamic_pcie_gen2 = true;
- if (pi->gfx_clock_gating &&
- (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
pi->thermal_protection = true;
else
pi->thermal_protection = false;
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 6dacec4e209..8928bd109c1 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -2587,9 +2587,11 @@ u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
if (rdev->wb.enabled) {
rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
} else {
+ mutex_lock(&rdev->srbm_mutex);
cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
rptr = RREG32(CP_HQD_PQ_RPTR);
cik_srbm_select(rdev, 0, 0, 0, 0);
+ mutex_unlock(&rdev->srbm_mutex);
}
rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
@@ -2604,9 +2606,11 @@ u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
if (rdev->wb.enabled) {
wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]);
} else {
+ mutex_lock(&rdev->srbm_mutex);
cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
wptr = RREG32(CP_HQD_PQ_WPTR);
cik_srbm_select(rdev, 0, 0, 0, 0);
+ mutex_unlock(&rdev->srbm_mutex);
}
wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
@@ -2897,6 +2901,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
WREG32(CP_CPF_DEBUG, tmp);
/* init the pipes */
+ mutex_lock(&rdev->srbm_mutex);
for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) {
int me = (i < 4) ? 1 : 2;
int pipe = (i < 4) ? i : (i - 4);
@@ -2919,6 +2924,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
WREG32(CP_HPD_EOP_CONTROL, tmp);
}
cik_srbm_select(rdev, 0, 0, 0, 0);
+ mutex_unlock(&rdev->srbm_mutex);
/* init the queues. Just two for now. */
for (i = 0; i < 2; i++) {
@@ -2972,6 +2978,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
mqd->static_thread_mgmt23[0] = 0xffffffff;
mqd->static_thread_mgmt23[1] = 0xffffffff;
+ mutex_lock(&rdev->srbm_mutex);
cik_srbm_select(rdev, rdev->ring[idx].me,
rdev->ring[idx].pipe,
rdev->ring[idx].queue, 0);
@@ -3099,6 +3106,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
WREG32(CP_HQD_ACTIVE, mqd->queue_state.cp_hqd_active);
cik_srbm_select(rdev, 0, 0, 0, 0);
+ mutex_unlock(&rdev->srbm_mutex);
radeon_bo_kunmap(rdev->ring[idx].mqd_obj);
radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
@@ -4320,6 +4328,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
/* XXX SH_MEM regs */
/* where to put LDS, scratch, GPUVM in FSA64 space */
+ mutex_lock(&rdev->srbm_mutex);
for (i = 0; i < 16; i++) {
cik_srbm_select(rdev, 0, 0, 0, i);
/* CP and shaders */
@@ -4335,6 +4344,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
/* XXX SDMA RLC - todo */
}
cik_srbm_select(rdev, 0, 0, 0, 0);
+ mutex_unlock(&rdev->srbm_mutex);
cik_pcie_gart_tlb_flush(rdev);
DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
@@ -5954,6 +5964,8 @@ static int cik_startup(struct radeon_device *rdev)
struct radeon_ring *ring;
int r;
+ cik_mc_program(rdev);
+
if (rdev->flags & RADEON_IS_IGP) {
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
!rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
@@ -5985,7 +5997,6 @@ static int cik_startup(struct radeon_device *rdev)
if (r)
return r;
- cik_mc_program(rdev);
r = cik_pcie_gart_enable(rdev);
if (r)
return r;
@@ -6194,7 +6205,7 @@ int cik_suspend(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev);
cik_cp_enable(rdev, false);
cik_sdma_enable(rdev, false);
- r600_uvd_rbc_stop(rdev);
+ r600_uvd_stop(rdev);
radeon_uvd_suspend(rdev);
cik_irq_suspend(rdev);
radeon_wb_disable(rdev);
@@ -6358,6 +6369,7 @@ void cik_fini(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
+ r600_uvd_stop(rdev);
radeon_uvd_fini(rdev);
cik_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
@@ -6978,7 +6990,7 @@ int cik_uvd_resume(struct radeon_device *rdev)
/* programm the VCPU memory controller bits 0-27 */
addr = rdev->uvd.gpu_addr >> 3;
- size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3;
+ size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3;
WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
WREG32(UVD_VCPU_CACHE_SIZE0, size);
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
index 9bcdd174780..7e5d0b570a3 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.c
+++ b/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -2038,9 +2038,6 @@ int cypress_dpm_init(struct radeon_device *rdev)
{
struct rv7xx_power_info *pi;
struct evergreen_power_info *eg_pi;
- int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
- uint16_t data_offset, size;
- uint8_t frev, crev;
struct atom_clock_dividers dividers;
int ret;
@@ -2092,16 +2089,7 @@ int cypress_dpm_init(struct radeon_device *rdev)
eg_pi->vddci_control =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0);
- if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
- &frev, &crev, &data_offset)) {
- pi->sclk_ss = true;
- pi->mclk_ss = true;
- pi->dynamic_ss = true;
- } else {
- pi->sclk_ss = false;
- pi->mclk_ss = false;
- pi->dynamic_ss = true;
- }
+ rv770_get_engine_memory_ss(rdev);
pi->asi = RV770_ASI_DFLT;
pi->pasi = CYPRESS_HASI_DFLT;
@@ -2122,8 +2110,7 @@ int cypress_dpm_init(struct radeon_device *rdev)
pi->dynamic_pcie_gen2 = true;
- if (pi->gfx_clock_gating &&
- (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
pi->thermal_protection = true;
else
pi->thermal_protection = false;
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 038dcac7670..d5b49e33315 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -5106,6 +5106,8 @@ static int evergreen_startup(struct radeon_device *rdev)
/* enable aspm */
evergreen_program_aspm(rdev);
+ evergreen_mc_program(rdev);
+
if (ASIC_IS_DCE5(rdev)) {
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
r = ni_init_microcode(rdev);
@@ -5133,7 +5135,6 @@ static int evergreen_startup(struct radeon_device *rdev)
if (r)
return r;
- evergreen_mc_program(rdev);
if (rdev->flags & RADEON_IS_AGP) {
evergreen_agp_enable(rdev);
} else {
@@ -5291,10 +5292,10 @@ int evergreen_resume(struct radeon_device *rdev)
int evergreen_suspend(struct radeon_device *rdev)
{
r600_audio_fini(rdev);
+ r600_uvd_stop(rdev);
radeon_uvd_suspend(rdev);
r700_cp_stop(rdev);
r600_dma_stop(rdev);
- r600_uvd_rbc_stop(rdev);
evergreen_irq_suspend(rdev);
radeon_wb_disable(rdev);
evergreen_pcie_gart_disable(rdev);
@@ -5429,6 +5430,7 @@ void evergreen_fini(struct radeon_device *rdev)
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
evergreen_pcie_gart_fini(rdev);
+ r600_uvd_stop(rdev);
radeon_uvd_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index b0d3fb34141..b0e280058b9 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -148,18 +148,40 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
u32 base_rate = 24000;
+ u32 max_ratio = clock / base_rate;
+ u32 dto_phase;
+ u32 dto_modulo = clock;
+ u32 wallclock_ratio;
+ u32 dto_cntl;
if (!dig || !dig->afmt)
return;
+ if (max_ratio >= 8) {
+ dto_phase = 192 * 1000;
+ wallclock_ratio = 3;
+ } else if (max_ratio >= 4) {
+ dto_phase = 96 * 1000;
+ wallclock_ratio = 2;
+ } else if (max_ratio >= 2) {
+ dto_phase = 48 * 1000;
+ wallclock_ratio = 1;
+ } else {
+ dto_phase = 24 * 1000;
+ wallclock_ratio = 0;
+ }
+ dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+ dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+ WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
+
/* XXX two dtos; generally use dto0 for hdmi */
/* Express [24MHz / target pixel clock] as an exact rational
* number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
* is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
*/
- WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
- WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
+ WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
+ WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
}
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index a7baf67aef6..0d582ac1dc3 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -497,6 +497,9 @@
#define DCCG_AUDIO_DTO0_MODULE 0x05b4
#define DCCG_AUDIO_DTO0_LOAD 0x05b8
#define DCCG_AUDIO_DTO0_CNTL 0x05bc
+# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO(x) (((x) & 7) << 0)
+# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK 7
+# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_SHIFT 0
#define DCCG_AUDIO_DTO1_PHASE 0x05c0
#define DCCG_AUDIO_DTO1_MODULE 0x05c4
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 56bd4f3be4f..ccb4f8b5485 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -794,9 +794,13 @@ int ni_init_microcode(struct radeon_device *rdev)
if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAYMAN)) {
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev);
- if (err)
- goto out;
- if (rdev->smc_fw->size != smc_req_size) {
+ if (err) {
+ printk(KERN_ERR
+ "smc: error loading firmware \"%s\"\n",
+ fw_name);
+ release_firmware(rdev->smc_fw);
+ rdev->smc_fw = NULL;
+ } else if (rdev->smc_fw->size != smc_req_size) {
printk(KERN_ERR
"ni_mc: Bogus length %zu in firmware \"%s\"\n",
rdev->mc_fw->size, fw_name);
@@ -2079,6 +2083,8 @@ static int cayman_startup(struct radeon_device *rdev)
/* enable aspm */
evergreen_program_aspm(rdev);
+ evergreen_mc_program(rdev);
+
if (rdev->flags & RADEON_IS_IGP) {
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
r = ni_init_microcode(rdev);
@@ -2107,7 +2113,6 @@ static int cayman_startup(struct radeon_device *rdev)
if (r)
return r;
- evergreen_mc_program(rdev);
r = cayman_pcie_gart_enable(rdev);
if (r)
return r;
@@ -2286,7 +2291,7 @@ int cayman_suspend(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev);
cayman_cp_enable(rdev, false);
cayman_dma_stop(rdev);
- r600_uvd_rbc_stop(rdev);
+ r600_uvd_stop(rdev);
radeon_uvd_suspend(rdev);
evergreen_irq_suspend(rdev);
radeon_wb_disable(rdev);
@@ -2418,6 +2423,7 @@ void cayman_fini(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
+ r600_uvd_stop(rdev);
radeon_uvd_fini(rdev);
cayman_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index 559cf24d51a..f0f5f748938 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -1054,10 +1054,6 @@ static int ni_restrict_performance_levels_before_switch(struct radeon_device *rd
int ni_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level)
{
- struct radeon_ps *rps = rdev->pm.dpm.current_ps;
- struct ni_ps *ps = ni_get_ps(rps);
- u32 levels;
-
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
return -EINVAL;
@@ -1068,8 +1064,7 @@ int ni_dpm_force_performance_level(struct radeon_device *rdev,
if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
return -EINVAL;
- levels = ps->performance_level_count - 1;
- if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+ if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK)
return -EINVAL;
} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
@@ -4072,9 +4067,6 @@ int ni_dpm_init(struct radeon_device *rdev)
struct rv7xx_power_info *pi;
struct evergreen_power_info *eg_pi;
struct ni_power_info *ni_pi;
- int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
- u16 data_offset, size;
- u8 frev, crev;
struct atom_clock_dividers dividers;
int ret;
@@ -4167,16 +4159,7 @@ int ni_dpm_init(struct radeon_device *rdev)
eg_pi->vddci_control =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0);
- if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
- &frev, &crev, &data_offset)) {
- pi->sclk_ss = true;
- pi->mclk_ss = true;
- pi->dynamic_ss = true;
- } else {
- pi->sclk_ss = false;
- pi->mclk_ss = false;
- pi->dynamic_ss = true;
- }
+ rv770_get_engine_memory_ss(rdev);
pi->asi = RV770_ASI_DFLT;
pi->pasi = CYPRESS_HASI_DFLT;
@@ -4193,8 +4176,7 @@ int ni_dpm_init(struct radeon_device *rdev)
pi->dynamic_pcie_gen2 = true;
- if (pi->gfx_clock_gating &&
- (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
pi->thermal_protection = true;
else
pi->thermal_protection = false;
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 393880a0941..e66e7207735 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -2299,9 +2299,13 @@ int r600_init_microcode(struct radeon_device *rdev)
if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_HEMLOCK)) {
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", smc_chip_name);
err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev);
- if (err)
- goto out;
- if (rdev->smc_fw->size != smc_req_size) {
+ if (err) {
+ printk(KERN_ERR
+ "smc: error loading firmware \"%s\"\n",
+ fw_name);
+ release_firmware(rdev->smc_fw);
+ rdev->smc_fw = NULL;
+ } else if (rdev->smc_fw->size != smc_req_size) {
printk(KERN_ERR
"smc: Bogus length %zu in firmware \"%s\"\n",
rdev->smc_fw->size, fw_name);
@@ -2697,12 +2701,29 @@ int r600_uvd_rbc_start(struct radeon_device *rdev)
return 0;
}
-void r600_uvd_rbc_stop(struct radeon_device *rdev)
+void r600_uvd_stop(struct radeon_device *rdev)
{
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
/* force RBC into idle state */
WREG32(UVD_RBC_RB_CNTL, 0x11010101);
+
+ /* Stall UMC and register bus before resetting VCPU */
+ WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
+ WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
+ mdelay(1);
+
+ /* put VCPU into reset */
+ WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
+ mdelay(5);
+
+ /* disable VCPU clock */
+ WREG32(UVD_VCPU_CNTL, 0x0);
+
+ /* Unstall UMC and register bus */
+ WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
+ WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
+
ring->ready = false;
}
@@ -2722,6 +2743,11 @@ int r600_uvd_init(struct radeon_device *rdev)
/* disable interupt */
WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1));
+ /* Stall UMC and register bus before resetting VCPU */
+ WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
+ WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
+ mdelay(1);
+
/* put LMI, VCPU, RBC etc... into reset */
WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET |
LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET |
@@ -2751,10 +2777,6 @@ int r600_uvd_init(struct radeon_device *rdev)
WREG32(UVD_MPC_SET_ALU, 0);
WREG32(UVD_MPC_SET_MUX, 0x88);
- /* Stall UMC */
- WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
- WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
-
/* take all subblocks out of reset, except VCPU */
WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
mdelay(5);
@@ -3166,7 +3188,7 @@ int r600_copy_cpdma(struct radeon_device *rdev,
size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
- r = radeon_ring_lock(rdev, ring, num_loops * 6 + 21);
+ r = radeon_ring_lock(rdev, ring, num_loops * 6 + 24);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
radeon_semaphore_free(rdev, &sem, NULL);
@@ -3181,6 +3203,9 @@ int r600_copy_cpdma(struct radeon_device *rdev,
radeon_semaphore_free(rdev, &sem, NULL);
}
+ radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+ radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
+ radeon_ring_write(ring, WAIT_3D_IDLE_bit);
for (i = 0; i < num_loops; i++) {
cur_size_in_bytes = size_in_bytes;
if (cur_size_in_bytes > 0x1fffff)
@@ -3309,6 +3334,8 @@ static int r600_startup(struct radeon_device *rdev)
/* enable pcie gen2 link */
r600_pcie_gen2_enable(rdev);
+ r600_mc_program(rdev);
+
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
r = r600_init_microcode(rdev);
if (r) {
@@ -3321,7 +3348,6 @@ static int r600_startup(struct radeon_device *rdev)
if (r)
return r;
- r600_mc_program(rdev);
if (rdev->flags & RADEON_IS_AGP) {
r600_agp_enable(rdev);
} else {
diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c
index b88f54b134a..e5c860f4ccb 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.c
+++ b/drivers/gpu/drm/radeon/r600_dpm.c
@@ -278,9 +278,9 @@ bool r600_dynamicpm_enabled(struct radeon_device *rdev)
void r600_enable_sclk_control(struct radeon_device *rdev, bool enable)
{
if (enable)
- WREG32_P(GENERAL_PWRMGT, 0, ~SCLK_PWRMGT_OFF);
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
else
- WREG32_P(GENERAL_PWRMGT, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+ WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
}
void r600_enable_mclk_control(struct radeon_device *rdev, bool enable)
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index f48240bb8c5..f264df5470f 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -226,10 +226,29 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
u32 base_rate = 24000;
+ u32 max_ratio = clock / base_rate;
+ u32 dto_phase;
+ u32 dto_modulo = clock;
+ u32 wallclock_ratio;
+ u32 dto_cntl;
if (!dig || !dig->afmt)
return;
+ if (max_ratio >= 8) {
+ dto_phase = 192 * 1000;
+ wallclock_ratio = 3;
+ } else if (max_ratio >= 4) {
+ dto_phase = 96 * 1000;
+ wallclock_ratio = 2;
+ } else if (max_ratio >= 2) {
+ dto_phase = 48 * 1000;
+ wallclock_ratio = 1;
+ } else {
+ dto_phase = 24 * 1000;
+ wallclock_ratio = 0;
+ }
+
/* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT.
* doesn't matter which one you use. Just use the first one.
*/
@@ -242,9 +261,21 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
/* according to the reg specs, this should DCE3.2 only, but in
* practice it seems to cover DCE3.0 as well.
*/
- WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
- WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
- WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
+ if (dig->dig_encoder == 0) {
+ dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+ dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+ WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
+ WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
+ WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
+ WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
+ } else {
+ dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+ dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+ WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl);
+ WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase);
+ WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo);
+ WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
+ }
} else {
/* according to the reg specs, this should be DCE2.0 and DCE3.0 */
WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate / 10) |
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 8e3fe815eda..7c780839a7f 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -933,6 +933,9 @@
#define DCCG_AUDIO_DTO0_LOAD 0x051c
# define DTO_LOAD (1 << 31)
#define DCCG_AUDIO_DTO0_CNTL 0x0520
+# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO(x) (((x) & 7) << 0)
+# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK 7
+# define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_SHIFT 0
#define DCCG_AUDIO_DTO1_PHASE 0x0524
#define DCCG_AUDIO_DTO1_MODULE 0x0528
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 2f08219c39b..9f19259667d 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1468,7 +1468,6 @@ struct radeon_uvd {
void *cpu_addr;
uint64_t gpu_addr;
void *saved_bo;
- unsigned fw_size;
atomic_t handles[RADEON_MAX_UVD_HANDLES];
struct drm_file *filp[RADEON_MAX_UVD_HANDLES];
struct delayed_work idle_work;
@@ -2066,6 +2065,7 @@ struct radeon_device {
const struct firmware *mec_fw; /* CIK MEC firmware */
const struct firmware *sdma_fw; /* CIK SDMA firmware */
const struct firmware *smc_fw; /* SMC firmware */
+ const struct firmware *uvd_fw; /* UVD firmware */
struct r600_blit r600_blit;
struct r600_vram_scratch vram_scratch;
int msi_enabled; /* msi enabled */
@@ -2095,6 +2095,8 @@ struct radeon_device {
/* ACPI interface */
struct radeon_atif atif;
struct radeon_atcs atcs;
+ /* srbm instance registers */
+ struct mutex srbm_mutex;
};
int radeon_device_init(struct radeon_device *rdev,
@@ -2161,7 +2163,7 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
WREG32(reg, tmp_); \
} while (0)
#define WREG32_AND(reg, and) WREG32_P(reg, 0, and)
-#define WREG32_OR(reg, or) WREG32_P(reg, or, ~or)
+#define WREG32_OR(reg, or) WREG32_P(reg, or, ~(or))
#define WREG32_PLL_P(reg, val, mask) \
do { \
uint32_t tmp_ = RREG32_PLL(reg); \
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 78bec1a58ed..f8f8b3113dd 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1161,6 +1161,7 @@ static struct radeon_asic rv6xx_asic = {
.get_mclk = &rv6xx_dpm_get_mclk,
.print_power_state = &rv6xx_dpm_print_power_state,
.debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level,
+ .force_performance_level = &rv6xx_dpm_force_performance_level,
},
.pflip = {
.pre_page_flip = &rs600_pre_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index ca189570990..3d61d5aac18 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -421,6 +421,8 @@ void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
struct radeon_ps *ps);
void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
struct seq_file *m);
+int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level);
/* rs780 dpm */
int rs780_dpm_init(struct radeon_device *rdev);
int rs780_dpm_enable(struct radeon_device *rdev);
@@ -439,7 +441,7 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
/* uvd */
int r600_uvd_init(struct radeon_device *rdev);
int r600_uvd_rbc_start(struct radeon_device *rdev);
-void r600_uvd_rbc_stop(struct radeon_device *rdev);
+void r600_uvd_stop(struct radeon_device *rdev);
int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
void r600_uvd_fence_emit(struct radeon_device *rdev,
struct radeon_fence *fence);
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index e3f3e884178..4ccd61f60eb 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -2782,7 +2782,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
dividers->enable_dithen = (args.v3.ucCntlFlag &
ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
- dividers->fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
+ dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);
dividers->ref_div = args.v3.ucRefDiv;
dividers->vco_mode = (args.v3.ucCntlFlag &
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 78edadc9e86..68ce3605601 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -147,7 +147,7 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
enum radeon_combios_table_offset table)
{
struct radeon_device *rdev = dev->dev_private;
- int rev;
+ int rev, size;
uint16_t offset = 0, check_offset;
if (!rdev->bios)
@@ -156,174 +156,106 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
switch (table) {
/* absolute offset tables */
case COMBIOS_ASIC_INIT_1_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0xc);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0xc;
break;
case COMBIOS_BIOS_SUPPORT_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x14);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x14;
break;
case COMBIOS_DAC_PROGRAMMING_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x2a);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x2a;
break;
case COMBIOS_MAX_COLOR_DEPTH_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x2c);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x2c;
break;
case COMBIOS_CRTC_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x2e);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x2e;
break;
case COMBIOS_PLL_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x30);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x30;
break;
case COMBIOS_TV_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x32);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x32;
break;
case COMBIOS_DFP_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x34);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x34;
break;
case COMBIOS_HW_CONFIG_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x36);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x36;
break;
case COMBIOS_MULTIMEDIA_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x38);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x38;
break;
case COMBIOS_TV_STD_PATCH_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x3e);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x3e;
break;
case COMBIOS_LCD_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x40);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x40;
break;
case COMBIOS_MOBILE_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x42);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x42;
break;
case COMBIOS_PLL_INIT_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x46);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x46;
break;
case COMBIOS_MEM_CONFIG_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x48);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x48;
break;
case COMBIOS_SAVE_MASK_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x4a);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x4a;
break;
case COMBIOS_HARDCODED_EDID_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x4c);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x4c;
break;
case COMBIOS_ASIC_INIT_2_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x4e);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x4e;
break;
case COMBIOS_CONNECTOR_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x50);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x50;
break;
case COMBIOS_DYN_CLK_1_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x52);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x52;
break;
case COMBIOS_RESERVED_MEM_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x54);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x54;
break;
case COMBIOS_EXT_TMDS_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x58);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x58;
break;
case COMBIOS_MEM_CLK_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x5a);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x5a;
break;
case COMBIOS_EXT_DAC_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x5c);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x5c;
break;
case COMBIOS_MISC_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x5e);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x5e;
break;
case COMBIOS_CRT_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x60);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x60;
break;
case COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x62);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x62;
break;
case COMBIOS_COMPONENT_VIDEO_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x64);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x64;
break;
case COMBIOS_FAN_SPEED_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x66);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x66;
break;
case COMBIOS_OVERDRIVE_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x68);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x68;
break;
case COMBIOS_OEM_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x6a);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x6a;
break;
case COMBIOS_DYN_CLK_2_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x6c);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x6c;
break;
case COMBIOS_POWER_CONNECTOR_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x6e);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x6e;
break;
case COMBIOS_I2C_INFO_TABLE:
- check_offset = RBIOS16(rdev->bios_header_start + 0x70);
- if (check_offset)
- offset = check_offset;
+ check_offset = 0x70;
break;
/* relative offset tables */
case COMBIOS_ASIC_INIT_3_TABLE: /* offset from misc info */
@@ -439,11 +371,16 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
}
break;
default:
+ check_offset = 0;
break;
}
- return offset;
+ size = RBIOS8(rdev->bios_header_start + 0x6);
+ /* check absolute offset tables */
+ if (table < COMBIOS_ASIC_INIT_3_TABLE && check_offset && check_offset < size)
+ offset = RBIOS16(rdev->bios_header_start + check_offset);
+ return offset;
}
bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
@@ -965,16 +902,22 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
dac = RBIOS8(dac_info + 0x3) & 0xf;
p_dac->ps2_pdac_adj = (bg << 8) | (dac);
}
- /* if the values are all zeros, use the table */
- if (p_dac->ps2_pdac_adj)
+ /* if the values are zeros, use the table */
+ if ((dac == 0) || (bg == 0))
+ found = 0;
+ else
found = 1;
}
/* quirks */
+ /* Radeon 7000 (RV100) */
+ if (((dev->pdev->device == 0x5159) &&
+ (dev->pdev->subsystem_vendor == 0x174B) &&
+ (dev->pdev->subsystem_device == 0x7c28)) ||
/* Radeon 9100 (R200) */
- if ((dev->pdev->device == 0x514D) &&
+ ((dev->pdev->device == 0x514D) &&
(dev->pdev->subsystem_vendor == 0x174B) &&
- (dev->pdev->subsystem_device == 0x7149)) {
+ (dev->pdev->subsystem_device == 0x7149))) {
/* vbios value is bad, use the default */
found = 0;
}
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 82335e38ec4..63398ae1dbf 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1163,6 +1163,7 @@ int radeon_device_init(struct radeon_device *rdev,
mutex_init(&rdev->gem.mutex);
mutex_init(&rdev->pm.mutex);
mutex_init(&rdev->gpu_clock_mutex);
+ mutex_init(&rdev->srbm_mutex);
init_rwsem(&rdev->pm.mclk_lock);
init_rwsem(&rdev->exclusive_lock);
init_waitqueue_head(&rdev->irq.vblank_queue);
@@ -1519,6 +1520,7 @@ int radeon_gpu_reset(struct radeon_device *rdev)
radeon_save_bios_scratch_regs(rdev);
/* block TTM */
resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
+ radeon_pm_suspend(rdev);
radeon_suspend(rdev);
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
@@ -1564,6 +1566,7 @@ retry:
}
}
+ radeon_pm_resume(rdev);
drm_helper_resume_force_mode(rdev->ddev);
ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 7ddb0efe240..ddb8f8e04eb 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -782,7 +782,7 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring)
} else {
/* put fence directly behind firmware */
- index = ALIGN(rdev->uvd.fw_size, 8);
+ index = ALIGN(rdev->uvd_fw->size, 8);
rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index;
rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index;
}
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index d9d31a38327..b990b1a2bd5 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -207,7 +207,6 @@ void radeon_gart_table_vram_free(struct radeon_device *rdev)
if (rdev->gart.robj == NULL) {
return;
}
- radeon_gart_table_vram_unpin(rdev);
radeon_bo_unref(&rdev->gart.robj);
}
@@ -466,7 +465,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev)
size += rdev->vm_manager.max_pfn * 8;
size *= 2;
r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager,
- RADEON_VM_PTB_ALIGN(size),
+ RADEON_GPU_PAGE_ALIGN(size),
RADEON_VM_PTB_ALIGN_SIZE,
RADEON_GEM_DOMAIN_VRAM);
if (r) {
@@ -621,7 +620,7 @@ int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm)
}
retry:
- pd_size = RADEON_VM_PTB_ALIGN(radeon_vm_directory_size(rdev));
+ pd_size = radeon_vm_directory_size(rdev);
r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
&vm->page_directory, pd_size,
RADEON_VM_PTB_ALIGN_SIZE, false);
@@ -953,8 +952,8 @@ static int radeon_vm_update_pdes(struct radeon_device *rdev,
retry:
r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
&vm->page_tables[pt_idx],
- RADEON_VM_PTB_ALIGN(RADEON_VM_PTE_COUNT * 8),
- RADEON_VM_PTB_ALIGN_SIZE, false);
+ RADEON_VM_PTE_COUNT * 8,
+ RADEON_GPU_PAGE_SIZE, false);
if (r == -ENOMEM) {
r = radeon_vm_evict(rdev, vm);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index f374c467aac..c557850cd34 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1176,7 +1176,14 @@ int radeon_pm_init(struct radeon_device *rdev)
case CHIP_VERDE:
case CHIP_OLAND:
case CHIP_HAINAN:
- if (radeon_dpm == 1)
+ /* DPM requires the RLC, RV770+ dGPU requires SMC */
+ if (!rdev->rlc_fw)
+ rdev->pm.pm_method = PM_METHOD_PROFILE;
+ else if ((rdev->family >= CHIP_RV770) &&
+ (!(rdev->flags & RADEON_IS_IGP)) &&
+ (!rdev->smc_fw))
+ rdev->pm.pm_method = PM_METHOD_PROFILE;
+ else if (radeon_dpm == 1)
rdev->pm.pm_method = PM_METHOD_DPM;
else
rdev->pm.pm_method = PM_METHOD_PROFILE;
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index 414fd145d20..b79f4f5cdd6 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -56,7 +56,6 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work);
int radeon_uvd_init(struct radeon_device *rdev)
{
- const struct firmware *fw;
unsigned long bo_size;
const char *fw_name;
int i, r;
@@ -105,14 +104,14 @@ int radeon_uvd_init(struct radeon_device *rdev)
return -EINVAL;
}
- r = request_firmware(&fw, fw_name, rdev->dev);
+ r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev);
if (r) {
dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n",
fw_name);
return r;
}
- bo_size = RADEON_GPU_PAGE_ALIGN(fw->size + 8) +
+ bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) +
RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE;
r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo);
@@ -145,12 +144,6 @@ int radeon_uvd_init(struct radeon_device *rdev)
radeon_bo_unreserve(rdev->uvd.vcpu_bo);
- rdev->uvd.fw_size = fw->size;
- memset(rdev->uvd.cpu_addr, 0, bo_size);
- memcpy(rdev->uvd.cpu_addr, fw->data, fw->size);
-
- release_firmware(fw);
-
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
atomic_set(&rdev->uvd.handles[i], 0);
rdev->uvd.filp[i] = NULL;
@@ -174,33 +167,60 @@ void radeon_uvd_fini(struct radeon_device *rdev)
}
radeon_bo_unref(&rdev->uvd.vcpu_bo);
+
+ release_firmware(rdev->uvd_fw);
}
int radeon_uvd_suspend(struct radeon_device *rdev)
{
unsigned size;
+ void *ptr;
+ int i;
if (rdev->uvd.vcpu_bo == NULL)
return 0;
+ for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i)
+ if (atomic_read(&rdev->uvd.handles[i]))
+ break;
+
+ if (i == RADEON_MAX_UVD_HANDLES)
+ return 0;
+
size = radeon_bo_size(rdev->uvd.vcpu_bo);
+ size -= rdev->uvd_fw->size;
+
+ ptr = rdev->uvd.cpu_addr;
+ ptr += rdev->uvd_fw->size;
+
rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL);
- memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size);
+ memcpy(rdev->uvd.saved_bo, ptr, size);
return 0;
}
int radeon_uvd_resume(struct radeon_device *rdev)
{
+ unsigned size;
+ void *ptr;
+
if (rdev->uvd.vcpu_bo == NULL)
return -EINVAL;
+ memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size);
+
+ size = radeon_bo_size(rdev->uvd.vcpu_bo);
+ size -= rdev->uvd_fw->size;
+
+ ptr = rdev->uvd.cpu_addr;
+ ptr += rdev->uvd_fw->size;
+
if (rdev->uvd.saved_bo != NULL) {
- unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo);
- memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size);
+ memcpy(ptr, rdev->uvd.saved_bo, size);
kfree(rdev->uvd.saved_bo);
rdev->uvd.saved_bo = NULL;
- }
+ } else
+ memset(ptr, 0, size);
return 0;
}
@@ -215,8 +235,8 @@ void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp)
{
int i, r;
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
- if (rdev->uvd.filp[i] == filp) {
- uint32_t handle = atomic_read(&rdev->uvd.handles[i]);
+ uint32_t handle = atomic_read(&rdev->uvd.handles[i]);
+ if (handle != 0 && rdev->uvd.filp[i] == filp) {
struct radeon_fence *fence;
r = radeon_uvd_get_destroy_msg(rdev,
@@ -336,9 +356,19 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
return -EINVAL;
}
+ if (bo->tbo.sync_obj) {
+ r = radeon_fence_wait(bo->tbo.sync_obj, false);
+ if (r) {
+ DRM_ERROR("Failed waiting for UVD message (%d)!\n", r);
+ return r;
+ }
+ }
+
r = radeon_bo_kmap(bo, &ptr);
- if (r)
+ if (r) {
+ DRM_ERROR("Failed mapping the UVD message (%d)!\n", r);
return r;
+ }
msg = ptr + offset;
@@ -364,8 +394,14 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
radeon_bo_kunmap(bo);
return 0;
} else {
- /* it's a create msg, no special handling needed */
radeon_bo_kunmap(bo);
+
+ if (msg_type != 0) {
+ DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
+ return -EINVAL;
+ }
+
+ /* it's a create msg, no special handling needed */
}
/* create or decode, validate the handle */
@@ -388,7 +424,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
int data0, int data1,
- unsigned buf_sizes[])
+ unsigned buf_sizes[], bool *has_msg_cmd)
{
struct radeon_cs_chunk *relocs_chunk;
struct radeon_cs_reloc *reloc;
@@ -417,7 +453,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
if (cmd < 0x4) {
if ((end - start) < buf_sizes[cmd]) {
- DRM_ERROR("buffer to small (%d / %d)!\n",
+ DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
(unsigned)(end - start), buf_sizes[cmd]);
return -EINVAL;
}
@@ -442,9 +478,17 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
}
if (cmd == 0) {
+ if (*has_msg_cmd) {
+ DRM_ERROR("More than one message in a UVD-IB!\n");
+ return -EINVAL;
+ }
+ *has_msg_cmd = true;
r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes);
if (r)
return r;
+ } else if (!*has_msg_cmd) {
+ DRM_ERROR("Message needed before other commands are send!\n");
+ return -EINVAL;
}
return 0;
@@ -453,7 +497,8 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt,
int *data0, int *data1,
- unsigned buf_sizes[])
+ unsigned buf_sizes[],
+ bool *has_msg_cmd)
{
int i, r;
@@ -467,7 +512,8 @@ static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
*data1 = p->idx;
break;
case UVD_GPCOM_VCPU_CMD:
- r = radeon_uvd_cs_reloc(p, *data0, *data1, buf_sizes);
+ r = radeon_uvd_cs_reloc(p, *data0, *data1,
+ buf_sizes, has_msg_cmd);
if (r)
return r;
break;
@@ -488,6 +534,9 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
struct radeon_cs_packet pkt;
int r, data0 = 0, data1 = 0;
+ /* does the IB has a msg command */
+ bool has_msg_cmd = false;
+
/* minimum buffer sizes */
unsigned buf_sizes[] = {
[0x00000000] = 2048,
@@ -514,8 +563,8 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
return r;
switch (pkt.type) {
case RADEON_PACKET_TYPE0:
- r = radeon_uvd_cs_reg(p, &pkt, &data0,
- &data1, buf_sizes);
+ r = radeon_uvd_cs_reg(p, &pkt, &data0, &data1,
+ buf_sizes, &has_msg_cmd);
if (r)
return r;
break;
@@ -527,6 +576,12 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
return -EINVAL;
}
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
+
+ if (!has_msg_cmd) {
+ DRM_ERROR("UVD-IBs need a msg command!\n");
+ return -EINVAL;
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c
index 65e33f38734..bdd888b4db2 100644
--- a/drivers/gpu/drm/radeon/rv6xx_dpm.c
+++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c
@@ -819,7 +819,7 @@ static void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev)
POWERMODE1(calculate_memory_refresh_rate(rdev,
pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
POWERMODE2(calculate_memory_refresh_rate(rdev,
- pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
+ pi->hw.sclks[R600_POWER_LEVEL_HIGH])) |
POWERMODE3(calculate_memory_refresh_rate(rdev,
pi->hw.sclks[R600_POWER_LEVEL_HIGH])));
WREG32(ARB_RFSH_RATE, arb_refresh_rate);
@@ -1182,10 +1182,10 @@ static void rv6xx_program_display_gap(struct radeon_device *rdev)
u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
- if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) {
+ if (rdev->pm.dpm.new_active_crtcs & 1) {
tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
- } else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) {
+ } else if (rdev->pm.dpm.new_active_crtcs & 2) {
tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
} else {
@@ -1670,6 +1670,8 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
int ret;
+ pi->restricted_levels = 0;
+
rv6xx_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
rv6xx_clear_vc(rdev);
@@ -1756,6 +1758,8 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
rv6xx_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+ rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
+
return 0;
}
@@ -1940,9 +1944,7 @@ static int rv6xx_parse_power_table(struct radeon_device *rdev)
int rv6xx_dpm_init(struct radeon_device *rdev)
{
- int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
- uint16_t data_offset, size;
- uint8_t frev, crev;
+ struct radeon_atom_ss ss;
struct atom_clock_dividers dividers;
struct rv6xx_power_info *pi;
int ret;
@@ -1985,16 +1987,18 @@ int rv6xx_dpm_init(struct radeon_device *rdev)
pi->gfx_clock_gating = true;
- if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
- &frev, &crev, &data_offset)) {
- pi->sclk_ss = true;
- pi->mclk_ss = true;
+ pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_ENGINE_SS, 0);
+ pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_MEMORY_SS, 0);
+
+ /* Disable sclk ss, causes hangs on a lot of systems */
+ pi->sclk_ss = false;
+
+ if (pi->sclk_ss || pi->mclk_ss)
pi->dynamic_ss = true;
- } else {
- pi->sclk_ss = false;
- pi->mclk_ss = false;
+ else
pi->dynamic_ss = false;
- }
pi->dynamic_pcie_gen2 = true;
@@ -2085,3 +2089,34 @@ u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low)
else
return requested_state->high.mclk;
}
+
+int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+ pi->restricted_levels = 3;
+ } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+ pi->restricted_levels = 2;
+ } else {
+ pi->restricted_levels = 0;
+ }
+
+ rv6xx_clear_vc(rdev);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+ r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
+ r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+ rv6xx_enable_medium(rdev);
+ rv6xx_enable_high(rdev);
+ if (pi->restricted_levels == 3)
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false);
+ rv6xx_program_vc(rdev);
+ rv6xx_program_at(rdev);
+
+ rdev->pm.dpm.forced_level = level;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 30ea14e8854..f5e92cfcc14 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -744,10 +744,10 @@ static void rv770_init_golden_registers(struct radeon_device *rdev)
(const u32)ARRAY_SIZE(r7xx_golden_dyn_gpr_registers));
radeon_program_register_sequence(rdev,
rv730_golden_registers,
- (const u32)ARRAY_SIZE(rv770_golden_registers));
+ (const u32)ARRAY_SIZE(rv730_golden_registers));
radeon_program_register_sequence(rdev,
rv730_mgcg_init,
- (const u32)ARRAY_SIZE(rv770_mgcg_init));
+ (const u32)ARRAY_SIZE(rv730_mgcg_init));
break;
case CHIP_RV710:
radeon_program_register_sequence(rdev,
@@ -758,18 +758,18 @@ static void rv770_init_golden_registers(struct radeon_device *rdev)
(const u32)ARRAY_SIZE(r7xx_golden_dyn_gpr_registers));
radeon_program_register_sequence(rdev,
rv710_golden_registers,
- (const u32)ARRAY_SIZE(rv770_golden_registers));
+ (const u32)ARRAY_SIZE(rv710_golden_registers));
radeon_program_register_sequence(rdev,
rv710_mgcg_init,
- (const u32)ARRAY_SIZE(rv770_mgcg_init));
+ (const u32)ARRAY_SIZE(rv710_mgcg_init));
break;
case CHIP_RV740:
radeon_program_register_sequence(rdev,
rv740_golden_registers,
- (const u32)ARRAY_SIZE(rv770_golden_registers));
+ (const u32)ARRAY_SIZE(rv740_golden_registers));
radeon_program_register_sequence(rdev,
rv740_mgcg_init,
- (const u32)ARRAY_SIZE(rv770_mgcg_init));
+ (const u32)ARRAY_SIZE(rv740_mgcg_init));
break;
default:
break;
@@ -813,7 +813,7 @@ int rv770_uvd_resume(struct radeon_device *rdev)
/* programm the VCPU memory controller bits 0-27 */
addr = rdev->uvd.gpu_addr >> 3;
- size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3;
+ size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3;
WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
WREG32(UVD_VCPU_CACHE_SIZE0, size);
@@ -1829,6 +1829,8 @@ static int rv770_startup(struct radeon_device *rdev)
/* enable pcie gen2 link */
rv770_pcie_gen2_enable(rdev);
+ rv770_mc_program(rdev);
+
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
r = r600_init_microcode(rdev);
if (r) {
@@ -1841,7 +1843,6 @@ static int rv770_startup(struct radeon_device *rdev)
if (r)
return r;
- rv770_mc_program(rdev);
if (rdev->flags & RADEON_IS_AGP) {
rv770_agp_enable(rdev);
} else {
@@ -1983,6 +1984,7 @@ int rv770_resume(struct radeon_device *rdev)
int rv770_suspend(struct radeon_device *rdev)
{
r600_audio_fini(rdev);
+ r600_uvd_stop(rdev);
radeon_uvd_suspend(rdev);
r700_cp_stop(rdev);
r600_dma_stop(rdev);
@@ -2098,6 +2100,7 @@ void rv770_fini(struct radeon_device *rdev)
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
rv770_pcie_gart_fini(rdev);
+ r600_uvd_stop(rdev);
radeon_uvd_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 2d347925f77..094c67a29d0 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -2319,12 +2319,25 @@ int rv7xx_parse_power_table(struct radeon_device *rdev)
return 0;
}
+void rv770_get_engine_memory_ss(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct radeon_atom_ss ss;
+
+ pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_ENGINE_SS, 0);
+ pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_MEMORY_SS, 0);
+
+ if (pi->sclk_ss || pi->mclk_ss)
+ pi->dynamic_ss = true;
+ else
+ pi->dynamic_ss = false;
+}
+
int rv770_dpm_init(struct radeon_device *rdev)
{
struct rv7xx_power_info *pi;
- int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
- uint16_t data_offset, size;
- uint8_t frev, crev;
struct atom_clock_dividers dividers;
int ret;
@@ -2369,16 +2382,7 @@ int rv770_dpm_init(struct radeon_device *rdev)
pi->mvdd_control =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0);
- if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
- &frev, &crev, &data_offset)) {
- pi->sclk_ss = true;
- pi->mclk_ss = true;
- pi->dynamic_ss = true;
- } else {
- pi->sclk_ss = false;
- pi->mclk_ss = false;
- pi->dynamic_ss = false;
- }
+ rv770_get_engine_memory_ss(rdev);
pi->asi = RV770_ASI_DFLT;
pi->pasi = RV770_HASI_DFLT;
@@ -2393,8 +2397,7 @@ int rv770_dpm_init(struct radeon_device *rdev)
pi->dynamic_pcie_gen2 = true;
- if (pi->gfx_clock_gating &&
- (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
pi->thermal_protection = true;
else
pi->thermal_protection = false;
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h
index 96b1b2a62a8..9244effc6b5 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.h
+++ b/drivers/gpu/drm/radeon/rv770_dpm.h
@@ -275,6 +275,7 @@ void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
struct radeon_ps *new_ps,
struct radeon_ps *old_ps);
+void rv770_get_engine_memory_ss(struct radeon_device *rdev);
/* smc */
int rv770_read_smc_soft_register(struct radeon_device *rdev,
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index d325280e2f9..daa8d2df8ec 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -1663,9 +1663,13 @@ static int si_init_microcode(struct radeon_device *rdev)
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev);
- if (err)
- goto out;
- if (rdev->smc_fw->size != smc_req_size) {
+ if (err) {
+ printk(KERN_ERR
+ "smc: error loading firmware \"%s\"\n",
+ fw_name);
+ release_firmware(rdev->smc_fw);
+ rdev->smc_fw = NULL;
+ } else if (rdev->smc_fw->size != smc_req_size) {
printk(KERN_ERR
"si_smc: Bogus length %zu in firmware \"%s\"\n",
rdev->smc_fw->size, fw_name);
@@ -5215,14 +5219,12 @@ static void si_enable_mc_ls(struct radeon_device *rdev,
static void si_init_cg(struct radeon_device *rdev)
{
- bool has_uvd = true;
-
si_enable_mgcg(rdev, true);
- si_enable_cgcg(rdev, true);
+ si_enable_cgcg(rdev, false);
/* disable MC LS on Tahiti */
if (rdev->family == CHIP_TAHITI)
si_enable_mc_ls(rdev, false);
- if (has_uvd) {
+ if (rdev->has_uvd) {
si_enable_uvd_mgcg(rdev, true);
si_init_uvd_internal_cg(rdev);
}
@@ -5230,9 +5232,7 @@ static void si_init_cg(struct radeon_device *rdev)
static void si_fini_cg(struct radeon_device *rdev)
{
- bool has_uvd = true;
-
- if (has_uvd)
+ if (rdev->has_uvd)
si_enable_uvd_mgcg(rdev, false);
si_enable_cgcg(rdev, false);
si_enable_mgcg(rdev, false);
@@ -5241,11 +5241,11 @@ static void si_fini_cg(struct radeon_device *rdev)
static void si_init_pg(struct radeon_device *rdev)
{
bool has_pg = false;
-
+#if 0
/* only cape verde supports PG */
if (rdev->family == CHIP_VERDE)
has_pg = true;
-
+#endif
if (has_pg) {
si_init_ao_cu_mask(rdev);
si_init_dma_pg(rdev);
@@ -6422,6 +6422,8 @@ static int si_startup(struct radeon_device *rdev)
/* enable aspm */
si_program_aspm(rdev);
+ si_mc_program(rdev);
+
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
!rdev->rlc_fw || !rdev->mc_fw) {
r = si_init_microcode(rdev);
@@ -6441,7 +6443,6 @@ static int si_startup(struct radeon_device *rdev)
if (r)
return r;
- si_mc_program(rdev);
r = si_pcie_gart_enable(rdev);
if (r)
return r;
@@ -6625,7 +6626,7 @@ int si_suspend(struct radeon_device *rdev)
si_cp_enable(rdev, false);
cayman_dma_stop(rdev);
if (rdev->has_uvd) {
- r600_uvd_rbc_stop(rdev);
+ r600_uvd_stop(rdev);
radeon_uvd_suspend(rdev);
}
si_irq_suspend(rdev);
@@ -6767,8 +6768,10 @@ void si_fini(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
- if (rdev->has_uvd)
+ if (rdev->has_uvd) {
+ r600_uvd_stop(rdev);
radeon_uvd_fini(rdev);
+ }
si_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index 73aaa2e4c31..88699e3cd86 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -37,8 +37,6 @@
#define SMC_RAM_END 0x20000
-#define DDR3_DRAM_ROWS 0x2000
-
#define SCLK_MIN_DEEPSLEEP_FREQ 1350
static const struct si_cac_config_reg cac_weights_tahiti[] =
@@ -1767,8 +1765,9 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe
{
s64 kt, kv, leakage_w, i_leakage, vddc;
s64 temperature, t_slope, t_intercept, av, bv, t_ref;
+ s64 tmp;
- i_leakage = drm_int2fixp(ileakage / 100);
+ i_leakage = div64_s64(drm_int2fixp(ileakage), 100);
vddc = div64_s64(drm_int2fixp(v), 1000);
temperature = div64_s64(drm_int2fixp(t), 1000);
@@ -1778,8 +1777,9 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe
bv = div64_s64(drm_int2fixp(coeff->bv), 100000000);
t_ref = drm_int2fixp(coeff->t_ref);
- kt = drm_fixp_div(drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, temperature)),
- drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, t_ref)));
+ tmp = drm_fixp_mul(t_slope, vddc) + t_intercept;
+ kt = drm_fixp_exp(drm_fixp_mul(tmp, temperature));
+ kt = drm_fixp_div(kt, drm_fixp_exp(drm_fixp_mul(tmp, t_ref)));
kv = drm_fixp_mul(av, drm_fixp_exp(drm_fixp_mul(bv, vddc)));
leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);
@@ -1931,6 +1931,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)
si_pi->cac_override = cac_override_pitcairn;
si_pi->powertune_data = &powertune_data_pitcairn;
si_pi->dte_data = dte_data_pitcairn;
+ break;
}
} else if (rdev->family == CHIP_VERDE) {
si_pi->lcac_config = lcac_cape_verde;
@@ -1941,6 +1942,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)
case 0x683B:
case 0x683F:
case 0x6829:
+ case 0x6835:
si_pi->cac_weights = cac_weights_cape_verde_pro;
si_pi->dte_data = dte_data_cape_verde;
break;
@@ -2901,7 +2903,8 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
{
struct ni_ps *ps = ni_get_ps(rps);
struct radeon_clock_and_voltage_limits *max_limits;
- bool disable_mclk_switching;
+ bool disable_mclk_switching = false;
+ bool disable_sclk_switching = false;
u32 mclk, sclk;
u16 vddc, vddci;
int i;
@@ -2909,8 +2912,11 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
ni_dpm_vblank_too_short(rdev))
disable_mclk_switching = true;
- else
- disable_mclk_switching = false;
+
+ if (rps->vclk || rps->dclk) {
+ disable_mclk_switching = true;
+ disable_sclk_switching = true;
+ }
if (rdev->pm.dpm.ac_power)
max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
@@ -2938,27 +2944,43 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
if (disable_mclk_switching) {
mclk = ps->performance_levels[ps->performance_level_count - 1].mclk;
- sclk = ps->performance_levels[0].sclk;
- vddc = ps->performance_levels[0].vddc;
vddci = ps->performance_levels[ps->performance_level_count - 1].vddci;
} else {
- sclk = ps->performance_levels[0].sclk;
mclk = ps->performance_levels[0].mclk;
- vddc = ps->performance_levels[0].vddc;
vddci = ps->performance_levels[0].vddci;
}
+ if (disable_sclk_switching) {
+ sclk = ps->performance_levels[ps->performance_level_count - 1].sclk;
+ vddc = ps->performance_levels[ps->performance_level_count - 1].vddc;
+ } else {
+ sclk = ps->performance_levels[0].sclk;
+ vddc = ps->performance_levels[0].vddc;
+ }
+
/* adjusted low state */
ps->performance_levels[0].sclk = sclk;
ps->performance_levels[0].mclk = mclk;
ps->performance_levels[0].vddc = vddc;
ps->performance_levels[0].vddci = vddci;
- for (i = 1; i < ps->performance_level_count; i++) {
- if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk)
- ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk;
- if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc)
- ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;
+ if (disable_sclk_switching) {
+ sclk = ps->performance_levels[0].sclk;
+ for (i = 1; i < ps->performance_level_count; i++) {
+ if (sclk < ps->performance_levels[i].sclk)
+ sclk = ps->performance_levels[i].sclk;
+ }
+ for (i = 0; i < ps->performance_level_count; i++) {
+ ps->performance_levels[i].sclk = sclk;
+ ps->performance_levels[i].vddc = vddc;
+ }
+ } else {
+ for (i = 1; i < ps->performance_level_count; i++) {
+ if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk)
+ ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk;
+ if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc)
+ ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;
+ }
}
if (disable_mclk_switching) {
@@ -3237,10 +3259,10 @@ int si_dpm_force_performance_level(struct radeon_device *rdev,
{
struct radeon_ps *rps = rdev->pm.dpm.current_ps;
struct ni_ps *ps = ni_get_ps(rps);
- u32 levels;
+ u32 levels = ps->performance_level_count;
if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
- if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+ if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
return -EINVAL;
if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK)
@@ -3249,14 +3271,13 @@ int si_dpm_force_performance_level(struct radeon_device *rdev,
if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
return -EINVAL;
- levels = ps->performance_level_count - 1;
- if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+ if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK)
return -EINVAL;
} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
return -EINVAL;
- if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+ if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
return -EINVAL;
}
@@ -3620,8 +3641,12 @@ static void si_enable_display_gap(struct radeon_device *rdev)
{
u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+ tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+ tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
+ DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE));
+
tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
- tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+ tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) |
DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
WREG32(CG_DISPLAY_GAP_CNTL, tmp);
}
@@ -4036,16 +4061,15 @@ static int si_force_switch_to_arb_f0(struct radeon_device *rdev)
static u32 si_calculate_memory_refresh_rate(struct radeon_device *rdev,
u32 engine_clock)
{
- struct rv7xx_power_info *pi = rv770_get_pi(rdev);
u32 dram_rows;
u32 dram_refresh_rate;
u32 mc_arb_rfsh_rate;
u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
- if (pi->mem_gddr5)
- dram_rows = 1 << (tmp + 10);
+ if (tmp >= 4)
+ dram_rows = 16384;
else
- dram_rows = DDR3_DRAM_ROWS;
+ dram_rows = 1 << (tmp + 10);
dram_refresh_rate = 1 << ((RREG32(MC_SEQ_MISC0) & 0x3) + 3);
mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
@@ -6013,16 +6037,11 @@ int si_dpm_set_power_state(struct radeon_device *rdev)
return ret;
}
-#if 0
- /* XXX */
ret = si_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
if (ret) {
DRM_ERROR("si_dpm_force_performance_level failed\n");
return ret;
}
-#else
- rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
-#endif
return 0;
}
@@ -6254,9 +6273,6 @@ int si_dpm_init(struct radeon_device *rdev)
struct evergreen_power_info *eg_pi;
struct ni_power_info *ni_pi;
struct si_power_info *si_pi;
- int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
- u16 data_offset, size;
- u8 frev, crev;
struct atom_clock_dividers dividers;
int ret;
u32 mask;
@@ -6347,16 +6363,7 @@ int si_dpm_init(struct radeon_device *rdev)
si_pi->vddc_phase_shed_control =
radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, VOLTAGE_OBJ_PHASE_LUT);
- if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
- &frev, &crev, &data_offset)) {
- pi->sclk_ss = true;
- pi->mclk_ss = true;
- pi->dynamic_ss = true;
- } else {
- pi->sclk_ss = false;
- pi->mclk_ss = false;
- pi->dynamic_ss = true;
- }
+ rv770_get_engine_memory_ss(rdev);
pi->asi = RV770_ASI_DFLT;
pi->pasi = CYPRESS_HASI_DFLT;
@@ -6367,8 +6374,7 @@ int si_dpm_init(struct radeon_device *rdev)
eg_pi->sclk_deep_sleep = true;
si_pi->sclk_deep_sleep_above_low = false;
- if (pi->gfx_clock_gating &&
- (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
pi->thermal_protection = true;
else
pi->thermal_protection = false;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
index 3751730764a..1a0bf07fe54 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
@@ -29,7 +29,9 @@
#include <drm/drmP.h>
#include <drm/ttm/ttm_bo_driver.h>
-#define VMW_PPN_SIZE sizeof(unsigned long)
+#define VMW_PPN_SIZE (sizeof(unsigned long))
+/* A future safe maximum remap size. */
+#define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE)
static int vmw_gmr2_bind(struct vmw_private *dev_priv,
struct page *pages[],
@@ -38,43 +40,61 @@ static int vmw_gmr2_bind(struct vmw_private *dev_priv,
{
SVGAFifoCmdDefineGMR2 define_cmd;
SVGAFifoCmdRemapGMR2 remap_cmd;
- uint32_t define_size = sizeof(define_cmd) + 4;
- uint32_t remap_size = VMW_PPN_SIZE * num_pages + sizeof(remap_cmd) + 4;
uint32_t *cmd;
uint32_t *cmd_orig;
+ uint32_t define_size = sizeof(define_cmd) + sizeof(*cmd);
+ uint32_t remap_num = num_pages / VMW_PPN_PER_REMAP + ((num_pages % VMW_PPN_PER_REMAP) > 0);
+ uint32_t remap_size = VMW_PPN_SIZE * num_pages + (sizeof(remap_cmd) + sizeof(*cmd)) * remap_num;
+ uint32_t remap_pos = 0;
+ uint32_t cmd_size = define_size + remap_size;
uint32_t i;
- cmd_orig = cmd = vmw_fifo_reserve(dev_priv, define_size + remap_size);
+ cmd_orig = cmd = vmw_fifo_reserve(dev_priv, cmd_size);
if (unlikely(cmd == NULL))
return -ENOMEM;
define_cmd.gmrId = gmr_id;
define_cmd.numPages = num_pages;
+ *cmd++ = SVGA_CMD_DEFINE_GMR2;
+ memcpy(cmd, &define_cmd, sizeof(define_cmd));
+ cmd += sizeof(define_cmd) / sizeof(*cmd);
+
+ /*
+ * Need to split the command if there are too many
+ * pages that goes into the gmr.
+ */
+
remap_cmd.gmrId = gmr_id;
remap_cmd.flags = (VMW_PPN_SIZE > sizeof(*cmd)) ?
SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32;
- remap_cmd.offsetPages = 0;
- remap_cmd.numPages = num_pages;
- *cmd++ = SVGA_CMD_DEFINE_GMR2;
- memcpy(cmd, &define_cmd, sizeof(define_cmd));
- cmd += sizeof(define_cmd) / sizeof(uint32);
+ while (num_pages > 0) {
+ unsigned long nr = min(num_pages, (unsigned long)VMW_PPN_PER_REMAP);
+
+ remap_cmd.offsetPages = remap_pos;
+ remap_cmd.numPages = nr;
- *cmd++ = SVGA_CMD_REMAP_GMR2;
- memcpy(cmd, &remap_cmd, sizeof(remap_cmd));
- cmd += sizeof(remap_cmd) / sizeof(uint32);
+ *cmd++ = SVGA_CMD_REMAP_GMR2;
+ memcpy(cmd, &remap_cmd, sizeof(remap_cmd));
+ cmd += sizeof(remap_cmd) / sizeof(*cmd);
- for (i = 0; i < num_pages; ++i) {
- if (VMW_PPN_SIZE <= 4)
- *cmd = page_to_pfn(*pages++);
- else
- *((uint64_t *)cmd) = page_to_pfn(*pages++);
+ for (i = 0; i < nr; ++i) {
+ if (VMW_PPN_SIZE <= 4)
+ *cmd = page_to_pfn(*pages++);
+ else
+ *((uint64_t *)cmd) = page_to_pfn(*pages++);
- cmd += VMW_PPN_SIZE / sizeof(*cmd);
+ cmd += VMW_PPN_SIZE / sizeof(*cmd);
+ }
+
+ num_pages -= nr;
+ remap_pos += nr;
}
- vmw_fifo_commit(dev_priv, define_size + remap_size);
+ BUG_ON(cmd != cmd_orig + cmd_size / sizeof(*cmd));
+
+ vmw_fifo_commit(dev_priv, cmd_size);
return 0;
}
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 36668d1aca8..b8f1c77f2f7 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1917,11 +1917,13 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
+static DEVICE_ATTR_RO(modalias);
-static struct device_attribute hid_dev_attrs[] = {
- __ATTR_RO(modalias),
- __ATTR_NULL,
+static struct attribute *hid_dev_attrs[] = {
+ &dev_attr_modalias.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(hid_dev);
static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
{
@@ -1949,7 +1951,7 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
static struct bus_type hid_bus_type = {
.name = "hid",
- .dev_attrs = hid_dev_attrs,
+ .dev_groups = hid_dev_groups,
.match = hid_bus_match,
.probe = hid_device_probe,
.remove = hid_device_remove,
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 713217380b4..8fae6d1414c 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -590,6 +590,5 @@ static void __exit mousevsc_exit(void)
}
MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
module_init(mousevsc_init);
module_exit(mousevsc_exit);
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 5207591a598..cd33084c786 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -192,6 +192,7 @@ static struct hid_ll_driver logi_dj_ll_driver;
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
size_t count,
unsigned char report_type);
+static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
struct dj_report *dj_report)
@@ -232,6 +233,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
SPFUNCTION_DEVICE_LIST_EMPTY) {
dbg_hid("%s: device list is empty\n", __func__);
+ djrcv_dev->querying_devices = false;
return;
}
@@ -242,6 +244,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
return;
}
+ if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
+ /* The device is already known. No need to reallocate it. */
+ dbg_hid("%s: device is already known\n", __func__);
+ return;
+ }
+
dj_hiddev = hid_allocate_device();
if (IS_ERR(dj_hiddev)) {
dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
@@ -305,6 +313,7 @@ static void delayedwork_callback(struct work_struct *work)
struct dj_report dj_report;
unsigned long flags;
int count;
+ int retval;
dbg_hid("%s\n", __func__);
@@ -337,6 +346,25 @@ static void delayedwork_callback(struct work_struct *work)
logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
break;
default:
+ /* A normal report (i. e. not belonging to a pair/unpair notification)
+ * arriving here, means that the report arrived but we did not have a
+ * paired dj_device associated to the report's device_index, this
+ * means that the original "device paired" notification corresponding
+ * to this dj_device never arrived to this driver. The reason is that
+ * hid-core discards all packets coming from a device while probe() is
+ * executing. */
+ if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
+ /* ok, we don't know the device, just re-ask the
+ * receiver for the list of connected devices. */
+ retval = logi_dj_recv_query_paired_devices(djrcv_dev);
+ if (!retval) {
+ /* everything went fine, so just leave */
+ break;
+ }
+ dev_err(&djrcv_dev->hdev->dev,
+ "%s:logi_dj_recv_query_paired_devices "
+ "error:%d\n", __func__, retval);
+ }
dbg_hid("%s: unexpected report type\n", __func__);
}
}
@@ -367,6 +395,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
if (!djdev) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index);
+ kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+
+ if (schedule_work(&djrcv_dev->work) == 0) {
+ dbg_hid("%s: did not schedule the work item, was already "
+ "queued\n", __func__);
+ }
return;
}
@@ -397,6 +431,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
if (dj_device == NULL) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index);
+ kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+
+ if (schedule_work(&djrcv_dev->work) == 0) {
+ dbg_hid("%s: did not schedule the work item, was already "
+ "queued\n", __func__);
+ }
return;
}
@@ -444,6 +484,10 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
struct dj_report *dj_report;
int retval;
+ /* no need to protect djrcv_dev->querying_devices */
+ if (djrcv_dev->querying_devices)
+ return 0;
+
dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
if (!dj_report)
return -ENOMEM;
@@ -455,6 +499,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
return retval;
}
+
static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
unsigned timeout)
{
diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h
index fd28a5e0ca3..4a4000340ce 100644
--- a/drivers/hid/hid-logitech-dj.h
+++ b/drivers/hid/hid-logitech-dj.h
@@ -101,6 +101,7 @@ struct dj_receiver_dev {
struct work_struct work;
struct kfifo notif_fifo;
spinlock_t lock;
+ bool querying_devices;
};
struct dj_device {
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c
index 327f9b8ed1f..eed7f52084c 100644
--- a/drivers/hid/hid-roccat-arvo.c
+++ b/drivers/hid/hid-roccat-arvo.c
@@ -75,6 +75,8 @@ static ssize_t arvo_sysfs_set_mode_key(struct device *dev,
return size;
}
+static DEVICE_ATTR(mode_key, 0660,
+ arvo_sysfs_show_mode_key, arvo_sysfs_set_mode_key);
static ssize_t arvo_sysfs_show_key_mask(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -123,6 +125,8 @@ static ssize_t arvo_sysfs_set_key_mask(struct device *dev,
return size;
}
+static DEVICE_ATTR(key_mask, 0660,
+ arvo_sysfs_show_key_mask, arvo_sysfs_set_key_mask);
/* retval is 1-5 on success, < 0 on error */
static int arvo_get_actual_profile(struct usb_device *usb_dev)
@@ -179,6 +183,9 @@ static ssize_t arvo_sysfs_set_actual_profile(struct device *dev,
mutex_unlock(&arvo->arvo_lock);
return retval;
}
+static DEVICE_ATTR(actual_profile, 0660,
+ arvo_sysfs_show_actual_profile,
+ arvo_sysfs_set_actual_profile);
static ssize_t arvo_sysfs_write(struct file *fp,
struct kobject *kobj, void const *buf,
@@ -230,6 +237,8 @@ static ssize_t arvo_sysfs_write_button(struct file *fp,
return arvo_sysfs_write(fp, kobj, buf, off, count,
sizeof(struct arvo_button), ARVO_COMMAND_BUTTON);
}
+static BIN_ATTR(button, 0220, NULL, arvo_sysfs_write_button,
+ sizeof(struct arvo_button));
static ssize_t arvo_sysfs_read_info(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
@@ -238,31 +247,30 @@ static ssize_t arvo_sysfs_read_info(struct file *fp,
return arvo_sysfs_read(fp, kobj, buf, off, count,
sizeof(struct arvo_info), ARVO_COMMAND_INFO);
}
+static BIN_ATTR(info, 0440, arvo_sysfs_read_info, NULL,
+ sizeof(struct arvo_info));
+
+static struct attribute *arvo_attrs[] = {
+ &dev_attr_mode_key.attr,
+ &dev_attr_key_mask.attr,
+ &dev_attr_actual_profile.attr,
+ NULL,
+};
+static struct bin_attribute *arvo_bin_attributes[] = {
+ &bin_attr_button,
+ &bin_attr_info,
+ NULL,
+};
-static struct device_attribute arvo_attributes[] = {
- __ATTR(mode_key, 0660,
- arvo_sysfs_show_mode_key, arvo_sysfs_set_mode_key),
- __ATTR(key_mask, 0660,
- arvo_sysfs_show_key_mask, arvo_sysfs_set_key_mask),
- __ATTR(actual_profile, 0660,
- arvo_sysfs_show_actual_profile,
- arvo_sysfs_set_actual_profile),
- __ATTR_NULL
+static const struct attribute_group arvo_group = {
+ .attrs = arvo_attrs,
+ .bin_attrs = arvo_bin_attributes,
};
-static struct bin_attribute arvo_bin_attributes[] = {
- {
- .attr = { .name = "button", .mode = 0220 },
- .size = sizeof(struct arvo_button),
- .write = arvo_sysfs_write_button
- },
- {
- .attr = { .name = "info", .mode = 0440 },
- .size = sizeof(struct arvo_info),
- .read = arvo_sysfs_read_info
- },
- __ATTR_NULL
+static const struct attribute_group *arvo_groups[] = {
+ &arvo_group,
+ NULL,
};
static int arvo_init_arvo_device_struct(struct usb_device *usb_dev,
@@ -430,8 +438,7 @@ static int __init arvo_init(void)
arvo_class = class_create(THIS_MODULE, "arvo");
if (IS_ERR(arvo_class))
return PTR_ERR(arvo_class);
- arvo_class->dev_attrs = arvo_attributes;
- arvo_class->dev_bin_attrs = arvo_bin_attributes;
+ arvo_class->dev_groups = arvo_groups;
retval = hid_register_driver(&arvo_driver);
if (retval)
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c
index 8023751d525..b7a4e10e112 100644
--- a/drivers/hid/hid-roccat-isku.c
+++ b/drivers/hid/hid-roccat-isku.c
@@ -109,12 +109,12 @@ static ssize_t isku_sysfs_set_actual_profile(struct device *dev,
return size;
}
+static DEVICE_ATTR(actual_profile, 0660, isku_sysfs_show_actual_profile,
+ isku_sysfs_set_actual_profile);
-static struct device_attribute isku_attributes[] = {
- __ATTR(actual_profile, 0660,
- isku_sysfs_show_actual_profile,
- isku_sysfs_set_actual_profile),
- __ATTR_NULL
+static struct attribute *isku_attrs[] = {
+ &dev_attr_actual_profile.attr,
+ NULL,
};
static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj,
@@ -184,7 +184,8 @@ ISKU_SYSFS_R(thingy, THINGY) \
ISKU_SYSFS_W(thingy, THINGY)
#define ISKU_BIN_ATTR_RW(thingy, THINGY) \
-{ \
+ISKU_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = ISKU_SIZE_ ## THINGY, \
.read = isku_sysfs_read_ ## thingy, \
@@ -192,52 +193,64 @@ ISKU_SYSFS_W(thingy, THINGY)
}
#define ISKU_BIN_ATTR_R(thingy, THINGY) \
-{ \
+ISKU_SYSFS_R(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = ISKU_SIZE_ ## THINGY, \
.read = isku_sysfs_read_ ## thingy, \
}
#define ISKU_BIN_ATTR_W(thingy, THINGY) \
-{ \
+ISKU_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = ISKU_SIZE_ ## THINGY, \
.write = isku_sysfs_write_ ## thingy \
}
-ISKU_SYSFS_RW(macro, MACRO)
-ISKU_SYSFS_RW(keys_function, KEYS_FUNCTION)
-ISKU_SYSFS_RW(keys_easyzone, KEYS_EASYZONE)
-ISKU_SYSFS_RW(keys_media, KEYS_MEDIA)
-ISKU_SYSFS_RW(keys_thumbster, KEYS_THUMBSTER)
-ISKU_SYSFS_RW(keys_macro, KEYS_MACRO)
-ISKU_SYSFS_RW(keys_capslock, KEYS_CAPSLOCK)
-ISKU_SYSFS_RW(light, LIGHT)
-ISKU_SYSFS_RW(key_mask, KEY_MASK)
-ISKU_SYSFS_RW(last_set, LAST_SET)
-ISKU_SYSFS_W(talk, TALK)
-ISKU_SYSFS_W(talkfx, TALKFX)
-ISKU_SYSFS_R(info, INFO)
-ISKU_SYSFS_W(control, CONTROL)
-ISKU_SYSFS_W(reset, RESET)
-
-static struct bin_attribute isku_bin_attributes[] = {
- ISKU_BIN_ATTR_RW(macro, MACRO),
- ISKU_BIN_ATTR_RW(keys_function, KEYS_FUNCTION),
- ISKU_BIN_ATTR_RW(keys_easyzone, KEYS_EASYZONE),
- ISKU_BIN_ATTR_RW(keys_media, KEYS_MEDIA),
- ISKU_BIN_ATTR_RW(keys_thumbster, KEYS_THUMBSTER),
- ISKU_BIN_ATTR_RW(keys_macro, KEYS_MACRO),
- ISKU_BIN_ATTR_RW(keys_capslock, KEYS_CAPSLOCK),
- ISKU_BIN_ATTR_RW(light, LIGHT),
- ISKU_BIN_ATTR_RW(key_mask, KEY_MASK),
- ISKU_BIN_ATTR_RW(last_set, LAST_SET),
- ISKU_BIN_ATTR_W(talk, TALK),
- ISKU_BIN_ATTR_W(talkfx, TALKFX),
- ISKU_BIN_ATTR_R(info, INFO),
- ISKU_BIN_ATTR_W(control, CONTROL),
- ISKU_BIN_ATTR_W(reset, RESET),
- __ATTR_NULL
+ISKU_BIN_ATTR_RW(macro, MACRO);
+ISKU_BIN_ATTR_RW(keys_function, KEYS_FUNCTION);
+ISKU_BIN_ATTR_RW(keys_easyzone, KEYS_EASYZONE);
+ISKU_BIN_ATTR_RW(keys_media, KEYS_MEDIA);
+ISKU_BIN_ATTR_RW(keys_thumbster, KEYS_THUMBSTER);
+ISKU_BIN_ATTR_RW(keys_macro, KEYS_MACRO);
+ISKU_BIN_ATTR_RW(keys_capslock, KEYS_CAPSLOCK);
+ISKU_BIN_ATTR_RW(light, LIGHT);
+ISKU_BIN_ATTR_RW(key_mask, KEY_MASK);
+ISKU_BIN_ATTR_RW(last_set, LAST_SET);
+ISKU_BIN_ATTR_W(talk, TALK);
+ISKU_BIN_ATTR_W(talkfx, TALKFX);
+ISKU_BIN_ATTR_W(control, CONTROL);
+ISKU_BIN_ATTR_W(reset, RESET);
+ISKU_BIN_ATTR_R(info, INFO);
+
+static struct bin_attribute *isku_bin_attributes[] = {
+ &bin_attr_macro,
+ &bin_attr_keys_function,
+ &bin_attr_keys_easyzone,
+ &bin_attr_keys_media,
+ &bin_attr_keys_thumbster,
+ &bin_attr_keys_macro,
+ &bin_attr_keys_capslock,
+ &bin_attr_light,
+ &bin_attr_key_mask,
+ &bin_attr_last_set,
+ &bin_attr_talk,
+ &bin_attr_talkfx,
+ &bin_attr_control,
+ &bin_attr_reset,
+ &bin_attr_info,
+ NULL,
+};
+
+static const struct attribute_group isku_group = {
+ .attrs = isku_attrs,
+ .bin_attrs = isku_bin_attributes,
+};
+
+static const struct attribute_group *isku_groups[] = {
+ &isku_group,
+ NULL,
};
static int isku_init_isku_device_struct(struct usb_device *usb_dev,
@@ -427,8 +440,7 @@ static int __init isku_init(void)
isku_class = class_create(THIS_MODULE, "isku");
if (IS_ERR(isku_class))
return PTR_ERR(isku_class);
- isku_class->dev_attrs = isku_attributes;
- isku_class->dev_bin_attrs = isku_bin_attributes;
+ isku_class->dev_groups = isku_groups;
retval = hid_register_driver(&isku_driver);
if (retval)
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 7fae070788f..6e614a85f17 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -324,6 +324,8 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
return sizeof(struct kone_settings);
}
+static BIN_ATTR(settings, 0660, kone_sysfs_read_settings,
+ kone_sysfs_write_settings, sizeof(struct kone_settings));
static ssize_t kone_sysfs_read_profilex(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr,
@@ -378,6 +380,19 @@ static ssize_t kone_sysfs_write_profilex(struct file *fp,
return sizeof(struct kone_profile);
}
+#define PROFILE_ATTR(number) \
+static struct bin_attribute bin_attr_profile##number = { \
+ .attr = { .name = "profile##number", .mode = 0660 }, \
+ .size = sizeof(struct kone_profile), \
+ .read = kone_sysfs_read_profilex, \
+ .write = kone_sysfs_write_profilex, \
+ .private = &profile_numbers[number-1], \
+};
+PROFILE_ATTR(1);
+PROFILE_ATTR(2);
+PROFILE_ATTR(3);
+PROFILE_ATTR(4);
+PROFILE_ATTR(5);
static ssize_t kone_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -386,6 +401,7 @@ static ssize_t kone_sysfs_show_actual_profile(struct device *dev,
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile);
}
+static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL);
static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -394,6 +410,7 @@ static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi);
}
+static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL);
/* weight is read each time, since we don't get informed when it's changed */
static ssize_t kone_sysfs_show_weight(struct device *dev,
@@ -416,6 +433,7 @@ static ssize_t kone_sysfs_show_weight(struct device *dev,
return retval;
return snprintf(buf, PAGE_SIZE, "%d\n", weight);
}
+static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL);
static ssize_t kone_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -424,6 +442,8 @@ static ssize_t kone_sysfs_show_firmware_version(struct device *dev,
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version);
}
+static DEVICE_ATTR(firmware_version, 0440, kone_sysfs_show_firmware_version,
+ NULL);
static ssize_t kone_sysfs_show_tcu(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -524,6 +544,7 @@ exit_unlock:
mutex_unlock(&kone->kone_lock);
return retval;
}
+static DEVICE_ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu);
static ssize_t kone_sysfs_show_startup_profile(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -570,15 +591,17 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
mutex_unlock(&kone->kone_lock);
return size;
}
+static DEVICE_ATTR(startup_profile, 0660, kone_sysfs_show_startup_profile,
+ kone_sysfs_set_startup_profile);
-static struct device_attribute kone_attributes[] = {
+static struct attribute *kone_attrs[] = {
/*
* Read actual dpi settings.
* Returns raw value for further processing. Refer to enum
* kone_polling_rates to get real value.
*/
- __ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL),
- __ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL),
+ &dev_attr_actual_dpi.attr,
+ &dev_attr_actual_profile.attr,
/*
* The mouse can be equipped with one of four supplied weights from 5
@@ -587,7 +610,7 @@ static struct device_attribute kone_attributes[] = {
* by software. Refer to enum kone_weights to get corresponding real
* weight.
*/
- __ATTR(weight, 0440, kone_sysfs_show_weight, NULL),
+ &dev_attr_weight.attr,
/*
* Prints firmware version stored in mouse as integer.
@@ -595,66 +618,38 @@ static struct device_attribute kone_attributes[] = {
* to get the real version number the decimal point has to be shifted 2
* positions to the left. E.g. a value of 138 means 1.38.
*/
- __ATTR(firmware_version, 0440,
- kone_sysfs_show_firmware_version, NULL),
+ &dev_attr_firmware_version.attr,
/*
* Prints state of Tracking Control Unit as number where 0 = off and
* 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and
* activates the tcu
*/
- __ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu),
+ &dev_attr_tcu.attr,
/* Prints and takes the number of the profile the mouse starts with */
- __ATTR(startup_profile, 0660,
- kone_sysfs_show_startup_profile,
- kone_sysfs_set_startup_profile),
- __ATTR_NULL
+ &dev_attr_startup_profile.attr,
+ NULL,
+};
+
+static struct bin_attribute *kone_bin_attributes[] = {
+ &bin_attr_settings,
+ &bin_attr_profile1,
+ &bin_attr_profile2,
+ &bin_attr_profile3,
+ &bin_attr_profile4,
+ &bin_attr_profile5,
+ NULL,
+};
+
+static const struct attribute_group kone_group = {
+ .attrs = kone_attrs,
+ .bin_attrs = kone_bin_attributes,
};
-static struct bin_attribute kone_bin_attributes[] = {
- {
- .attr = { .name = "settings", .mode = 0660 },
- .size = sizeof(struct kone_settings),
- .read = kone_sysfs_read_settings,
- .write = kone_sysfs_write_settings
- },
- {
- .attr = { .name = "profile1", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profilex,
- .write = kone_sysfs_write_profilex,
- .private = &profile_numbers[0]
- },
- {
- .attr = { .name = "profile2", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profilex,
- .write = kone_sysfs_write_profilex,
- .private = &profile_numbers[1]
- },
- {
- .attr = { .name = "profile3", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profilex,
- .write = kone_sysfs_write_profilex,
- .private = &profile_numbers[2]
- },
- {
- .attr = { .name = "profile4", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profilex,
- .write = kone_sysfs_write_profilex,
- .private = &profile_numbers[3]
- },
- {
- .attr = { .name = "profile5", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profilex,
- .write = kone_sysfs_write_profilex,
- .private = &profile_numbers[4]
- },
- __ATTR_NULL
+static const struct attribute_group *kone_groups[] = {
+ &kone_group,
+ NULL,
};
static int kone_init_kone_device_struct(struct usb_device *usb_dev,
@@ -891,8 +886,7 @@ static int __init kone_init(void)
kone_class = class_create(THIS_MODULE, "kone");
if (IS_ERR(kone_class))
return PTR_ERR(kone_class);
- kone_class->dev_attrs = kone_attributes;
- kone_class->dev_bin_attrs = kone_bin_attributes;
+ kone_class->dev_groups = kone_groups;
retval = hid_register_driver(&kone_driver);
if (retval)
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
index 6a48fa3c7da..db4d8b6a254 100644
--- a/drivers/hid/hid-roccat-koneplus.c
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -156,7 +156,8 @@ KONEPLUS_SYSFS_W(thingy, THINGY) \
KONEPLUS_SYSFS_R(thingy, THINGY)
#define KONEPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \
-{ \
+KONEPLUS_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = KONEPLUS_SIZE_ ## THINGY, \
.read = koneplus_sysfs_read_ ## thingy, \
@@ -164,28 +165,29 @@ KONEPLUS_SYSFS_R(thingy, THINGY)
}
#define KONEPLUS_BIN_ATTRIBUTE_R(thingy, THINGY) \
-{ \
+KONEPLUS_SYSFS_R(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = KONEPLUS_SIZE_ ## THINGY, \
.read = koneplus_sysfs_read_ ## thingy, \
}
#define KONEPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
-{ \
+KONEPLUS_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = KONEPLUS_SIZE_ ## THINGY, \
.write = koneplus_sysfs_write_ ## thingy \
}
-
-KONEPLUS_SYSFS_W(control, CONTROL)
-KONEPLUS_SYSFS_RW(info, INFO)
-KONEPLUS_SYSFS_W(talk, TALK)
-KONEPLUS_SYSFS_W(macro, MACRO)
-KONEPLUS_SYSFS_RW(sensor, SENSOR)
-KONEPLUS_SYSFS_RW(tcu, TCU)
-KONEPLUS_SYSFS_R(tcu_image, TCU_IMAGE)
-KONEPLUS_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
-KONEPLUS_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
+KONEPLUS_BIN_ATTRIBUTE_W(control, CONTROL);
+KONEPLUS_BIN_ATTRIBUTE_W(talk, TALK);
+KONEPLUS_BIN_ATTRIBUTE_W(macro, MACRO);
+KONEPLUS_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE);
+KONEPLUS_BIN_ATTRIBUTE_RW(info, INFO);
+KONEPLUS_BIN_ATTRIBUTE_RW(sensor, SENSOR);
+KONEPLUS_BIN_ATTRIBUTE_RW(tcu, TCU);
+KONEPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
+KONEPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
@@ -225,6 +227,25 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
KONEPLUS_COMMAND_PROFILE_BUTTONS);
}
+#define PROFILE_ATTR(number) \
+static struct bin_attribute bin_attr_profile##number##_settings = { \
+ .attr = { .name = "profile##number##_settings", .mode = 0440 }, \
+ .size = KONEPLUS_SIZE_PROFILE_SETTINGS, \
+ .read = koneplus_sysfs_read_profilex_settings, \
+ .private = &profile_numbers[number-1], \
+}; \
+static struct bin_attribute bin_attr_profile##number##_buttons = { \
+ .attr = { .name = "profile##number##_buttons", .mode = 0440 }, \
+ .size = KONEPLUS_SIZE_PROFILE_BUTTONS, \
+ .read = koneplus_sysfs_read_profilex_buttons, \
+ .private = &profile_numbers[number-1], \
+};
+PROFILE_ATTR(1);
+PROFILE_ATTR(2);
+PROFILE_ATTR(3);
+PROFILE_ATTR(4);
+PROFILE_ATTR(5);
+
static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -274,6 +295,12 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
return size;
}
+static DEVICE_ATTR(actual_profile, 0660,
+ koneplus_sysfs_show_actual_profile,
+ koneplus_sysfs_set_actual_profile);
+static DEVICE_ATTR(startup_profile, 0660,
+ koneplus_sysfs_show_actual_profile,
+ koneplus_sysfs_set_actual_profile);
static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -293,90 +320,47 @@ static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
}
+static DEVICE_ATTR(firmware_version, 0440,
+ koneplus_sysfs_show_firmware_version, NULL);
+
+static struct attribute *koneplus_attrs[] = {
+ &dev_attr_actual_profile.attr,
+ &dev_attr_startup_profile.attr,
+ &dev_attr_firmware_version.attr,
+ NULL,
+};
+
+static struct bin_attribute *koneplus_bin_attributes[] = {
+ &bin_attr_control,
+ &bin_attr_talk,
+ &bin_attr_macro,
+ &bin_attr_tcu_image,
+ &bin_attr_info,
+ &bin_attr_sensor,
+ &bin_attr_tcu,
+ &bin_attr_profile_settings,
+ &bin_attr_profile_buttons,
+ &bin_attr_profile1_settings,
+ &bin_attr_profile2_settings,
+ &bin_attr_profile3_settings,
+ &bin_attr_profile4_settings,
+ &bin_attr_profile5_settings,
+ &bin_attr_profile1_buttons,
+ &bin_attr_profile2_buttons,
+ &bin_attr_profile3_buttons,
+ &bin_attr_profile4_buttons,
+ &bin_attr_profile5_buttons,
+ NULL,
+};
-static struct device_attribute koneplus_attributes[] = {
- __ATTR(actual_profile, 0660,
- koneplus_sysfs_show_actual_profile,
- koneplus_sysfs_set_actual_profile),
- __ATTR(startup_profile, 0660,
- koneplus_sysfs_show_actual_profile,
- koneplus_sysfs_set_actual_profile),
- __ATTR(firmware_version, 0440,
- koneplus_sysfs_show_firmware_version, NULL),
- __ATTR_NULL
+static const struct attribute_group koneplus_group = {
+ .attrs = koneplus_attrs,
+ .bin_attrs = koneplus_bin_attributes,
};
-static struct bin_attribute koneplus_bin_attributes[] = {
- KONEPLUS_BIN_ATTRIBUTE_W(control, CONTROL),
- KONEPLUS_BIN_ATTRIBUTE_RW(info, INFO),
- KONEPLUS_BIN_ATTRIBUTE_W(talk, TALK),
- KONEPLUS_BIN_ATTRIBUTE_W(macro, MACRO),
- KONEPLUS_BIN_ATTRIBUTE_RW(sensor, SENSOR),
- KONEPLUS_BIN_ATTRIBUTE_RW(tcu, TCU),
- KONEPLUS_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE),
- KONEPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
- KONEPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
- {
- .attr = { .name = "profile1_settings", .mode = 0440 },
- .size = KONEPLUS_SIZE_PROFILE_SETTINGS,
- .read = koneplus_sysfs_read_profilex_settings,
- .private = &profile_numbers[0]
- },
- {
- .attr = { .name = "profile2_settings", .mode = 0440 },
- .size = KONEPLUS_SIZE_PROFILE_SETTINGS,
- .read = koneplus_sysfs_read_profilex_settings,
- .private = &profile_numbers[1]
- },
- {
- .attr = { .name = "profile3_settings", .mode = 0440 },
- .size = KONEPLUS_SIZE_PROFILE_SETTINGS,
- .read = koneplus_sysfs_read_profilex_settings,
- .private = &profile_numbers[2]
- },
- {
- .attr = { .name = "profile4_settings", .mode = 0440 },
- .size = KONEPLUS_SIZE_PROFILE_SETTINGS,
- .read = koneplus_sysfs_read_profilex_settings,
- .private = &profile_numbers[3]
- },
- {
- .attr = { .name = "profile5_settings", .mode = 0440 },
- .size = KONEPLUS_SIZE_PROFILE_SETTINGS,
- .read = koneplus_sysfs_read_profilex_settings,
- .private = &profile_numbers[4]
- },
- {
- .attr = { .name = "profile1_buttons", .mode = 0440 },
- .size = KONEPLUS_SIZE_PROFILE_BUTTONS,
- .read = koneplus_sysfs_read_profilex_buttons,
- .private = &profile_numbers[0]
- },
- {
- .attr = { .name = "profile2_buttons", .mode = 0440 },
- .size = KONEPLUS_SIZE_PROFILE_BUTTONS,
- .read = koneplus_sysfs_read_profilex_buttons,
- .private = &profile_numbers[1]
- },
- {
- .attr = { .name = "profile3_buttons", .mode = 0440 },
- .size = KONEPLUS_SIZE_PROFILE_BUTTONS,
- .read = koneplus_sysfs_read_profilex_buttons,
- .private = &profile_numbers[2]
- },
- {
- .attr = { .name = "profile4_buttons", .mode = 0440 },
- .size = KONEPLUS_SIZE_PROFILE_BUTTONS,
- .read = koneplus_sysfs_read_profilex_buttons,
- .private = &profile_numbers[3]
- },
- {
- .attr = { .name = "profile5_buttons", .mode = 0440 },
- .size = KONEPLUS_SIZE_PROFILE_BUTTONS,
- .read = koneplus_sysfs_read_profilex_buttons,
- .private = &profile_numbers[4]
- },
- __ATTR_NULL
+static const struct attribute_group *koneplus_groups[] = {
+ &koneplus_group,
+ NULL,
};
static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
@@ -572,8 +556,7 @@ static int __init koneplus_init(void)
koneplus_class = class_create(THIS_MODULE, "koneplus");
if (IS_ERR(koneplus_class))
return PTR_ERR(koneplus_class);
- koneplus_class->dev_attrs = koneplus_attributes;
- koneplus_class->dev_bin_attrs = koneplus_bin_attributes;
+ koneplus_class->dev_groups = koneplus_groups;
retval = hid_register_driver(&koneplus_driver);
if (retval)
diff --git a/drivers/hid/hid-roccat-konepure.c b/drivers/hid/hid-roccat-konepure.c
index c79d0b06c14..fa02b1f4497 100644
--- a/drivers/hid/hid-roccat-konepure.c
+++ b/drivers/hid/hid-roccat-konepure.c
@@ -94,7 +94,8 @@ KONEPURE_SYSFS_W(thingy, THINGY) \
KONEPURE_SYSFS_R(thingy, THINGY)
#define KONEPURE_BIN_ATTRIBUTE_RW(thingy, THINGY) \
-{ \
+KONEPURE_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = KONEPURE_SIZE_ ## THINGY, \
.read = konepure_sysfs_read_ ## thingy, \
@@ -102,44 +103,56 @@ KONEPURE_SYSFS_R(thingy, THINGY)
}
#define KONEPURE_BIN_ATTRIBUTE_R(thingy, THINGY) \
-{ \
+KONEPURE_SYSFS_R(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = KONEPURE_SIZE_ ## THINGY, \
.read = konepure_sysfs_read_ ## thingy, \
}
#define KONEPURE_BIN_ATTRIBUTE_W(thingy, THINGY) \
-{ \
+KONEPURE_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = KONEPURE_SIZE_ ## THINGY, \
.write = konepure_sysfs_write_ ## thingy \
}
-KONEPURE_SYSFS_RW(actual_profile, ACTUAL_PROFILE)
-KONEPURE_SYSFS_W(control, CONTROL)
-KONEPURE_SYSFS_RW(info, INFO)
-KONEPURE_SYSFS_W(talk, TALK)
-KONEPURE_SYSFS_W(macro, MACRO)
-KONEPURE_SYSFS_RW(sensor, SENSOR)
-KONEPURE_SYSFS_RW(tcu, TCU)
-KONEPURE_SYSFS_R(tcu_image, TCU_IMAGE)
-KONEPURE_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
-KONEPURE_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
-
-static struct bin_attribute konepure_bin_attributes[] = {
- KONEPURE_BIN_ATTRIBUTE_RW(actual_profile, ACTUAL_PROFILE),
- KONEPURE_BIN_ATTRIBUTE_W(control, CONTROL),
- KONEPURE_BIN_ATTRIBUTE_RW(info, INFO),
- KONEPURE_BIN_ATTRIBUTE_W(talk, TALK),
- KONEPURE_BIN_ATTRIBUTE_W(macro, MACRO),
- KONEPURE_BIN_ATTRIBUTE_RW(sensor, SENSOR),
- KONEPURE_BIN_ATTRIBUTE_RW(tcu, TCU),
- KONEPURE_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE),
- KONEPURE_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
- KONEPURE_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
- __ATTR_NULL
+KONEPURE_BIN_ATTRIBUTE_RW(actual_profile, ACTUAL_PROFILE);
+KONEPURE_BIN_ATTRIBUTE_RW(info, INFO);
+KONEPURE_BIN_ATTRIBUTE_RW(sensor, SENSOR);
+KONEPURE_BIN_ATTRIBUTE_RW(tcu, TCU);
+KONEPURE_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
+KONEPURE_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
+KONEPURE_BIN_ATTRIBUTE_W(control, CONTROL);
+KONEPURE_BIN_ATTRIBUTE_W(talk, TALK);
+KONEPURE_BIN_ATTRIBUTE_W(macro, MACRO);
+KONEPURE_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE);
+
+static struct bin_attribute *konepure_bin_attributes[] = {
+ &bin_attr_actual_profile,
+ &bin_attr_info,
+ &bin_attr_sensor,
+ &bin_attr_tcu,
+ &bin_attr_profile_settings,
+ &bin_attr_profile_buttons,
+ &bin_attr_control,
+ &bin_attr_talk,
+ &bin_attr_macro,
+ &bin_attr_tcu_image,
+ NULL,
+};
+
+static const struct attribute_group konepure_group = {
+ .bin_attrs = konepure_bin_attributes,
+};
+
+static const struct attribute_group *konepure_groups[] = {
+ &konepure_group,
+ NULL,
};
+
static int konepure_init_konepure_device_struct(struct usb_device *usb_dev,
struct konepure_device *konepure)
{
@@ -282,7 +295,7 @@ static int __init konepure_init(void)
konepure_class = class_create(THIS_MODULE, "konepure");
if (IS_ERR(konepure_class))
return PTR_ERR(konepure_class);
- konepure_class->dev_bin_attrs = konepure_bin_attributes;
+ konepure_class->dev_groups = konepure_groups;
retval = hid_register_driver(&konepure_driver);
if (retval)
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
index b8b37789b86..8a0f2993411 100644
--- a/drivers/hid/hid-roccat-kovaplus.c
+++ b/drivers/hid/hid-roccat-kovaplus.c
@@ -197,31 +197,25 @@ KOVAPLUS_SYSFS_W(thingy, THINGY) \
KOVAPLUS_SYSFS_R(thingy, THINGY)
#define KOVAPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \
-{ \
+KOVAPLUS_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = KOVAPLUS_SIZE_ ## THINGY, \
.read = kovaplus_sysfs_read_ ## thingy, \
.write = kovaplus_sysfs_write_ ## thingy \
}
-#define KOVAPLUS_BIN_ATTRIBUTE_R(thingy, THINGY) \
-{ \
- .attr = { .name = #thingy, .mode = 0440 }, \
- .size = KOVAPLUS_SIZE_ ## THINGY, \
- .read = kovaplus_sysfs_read_ ## thingy, \
-}
-
#define KOVAPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
-{ \
+KOVAPLUS_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = KOVAPLUS_SIZE_ ## THINGY, \
.write = kovaplus_sysfs_write_ ## thingy \
}
-
-KOVAPLUS_SYSFS_W(control, CONTROL)
-KOVAPLUS_SYSFS_RW(info, INFO)
-KOVAPLUS_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
-KOVAPLUS_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
+KOVAPLUS_BIN_ATTRIBUTE_W(control, CONTROL);
+KOVAPLUS_BIN_ATTRIBUTE_RW(info, INFO);
+KOVAPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
+KOVAPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
@@ -261,6 +255,25 @@ static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
KOVAPLUS_COMMAND_PROFILE_BUTTONS);
}
+#define PROFILE_ATTR(number) \
+static struct bin_attribute bin_attr_profile##number##_settings = { \
+ .attr = { .name = "profile##number##_settings", .mode = 0440 }, \
+ .size = KOVAPLUS_SIZE_PROFILE_SETTINGS, \
+ .read = kovaplus_sysfs_read_profilex_settings, \
+ .private = &profile_numbers[number-1], \
+}; \
+static struct bin_attribute bin_attr_profile##number##_buttons = { \
+ .attr = { .name = "profile##number##_buttons", .mode = 0440 }, \
+ .size = KOVAPLUS_SIZE_PROFILE_BUTTONS, \
+ .read = kovaplus_sysfs_read_profilex_buttons, \
+ .private = &profile_numbers[number-1], \
+};
+PROFILE_ATTR(1);
+PROFILE_ATTR(2);
+PROFILE_ATTR(3);
+PROFILE_ATTR(4);
+PROFILE_ATTR(5);
+
static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -310,6 +323,9 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
return size;
}
+static DEVICE_ATTR(actual_profile, 0660,
+ kovaplus_sysfs_show_actual_profile,
+ kovaplus_sysfs_set_actual_profile);
static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -318,6 +334,7 @@ static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev,
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_cpi);
}
+static DEVICE_ATTR(actual_cpi, 0440, kovaplus_sysfs_show_actual_cpi, NULL);
static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -326,6 +343,8 @@ static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev,
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_x_sensitivity);
}
+static DEVICE_ATTR(actual_sensitivity_x, 0440,
+ kovaplus_sysfs_show_actual_sensitivity_x, NULL);
static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -334,6 +353,8 @@ static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev,
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_y_sensitivity);
}
+static DEVICE_ATTR(actual_sensitivity_y, 0440,
+ kovaplus_sysfs_show_actual_sensitivity_y, NULL);
static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -353,88 +374,44 @@ static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
}
+static DEVICE_ATTR(firmware_version, 0440,
+ kovaplus_sysfs_show_firmware_version, NULL);
+
+static struct attribute *kovaplus_attrs[] = {
+ &dev_attr_actual_cpi.attr,
+ &dev_attr_firmware_version.attr,
+ &dev_attr_actual_profile.attr,
+ &dev_attr_actual_sensitivity_x.attr,
+ &dev_attr_actual_sensitivity_y.attr,
+ NULL,
+};
+
+static struct bin_attribute *kovaplus_bin_attributes[] = {
+ &bin_attr_control,
+ &bin_attr_info,
+ &bin_attr_profile_settings,
+ &bin_attr_profile_buttons,
+ &bin_attr_profile1_settings,
+ &bin_attr_profile2_settings,
+ &bin_attr_profile3_settings,
+ &bin_attr_profile4_settings,
+ &bin_attr_profile5_settings,
+ &bin_attr_profile1_buttons,
+ &bin_attr_profile2_buttons,
+ &bin_attr_profile3_buttons,
+ &bin_attr_profile4_buttons,
+ &bin_attr_profile5_buttons,
+ NULL,
+};
-static struct device_attribute kovaplus_attributes[] = {
- __ATTR(actual_cpi, 0440,
- kovaplus_sysfs_show_actual_cpi, NULL),
- __ATTR(firmware_version, 0440,
- kovaplus_sysfs_show_firmware_version, NULL),
- __ATTR(actual_profile, 0660,
- kovaplus_sysfs_show_actual_profile,
- kovaplus_sysfs_set_actual_profile),
- __ATTR(actual_sensitivity_x, 0440,
- kovaplus_sysfs_show_actual_sensitivity_x, NULL),
- __ATTR(actual_sensitivity_y, 0440,
- kovaplus_sysfs_show_actual_sensitivity_y, NULL),
- __ATTR_NULL
+static const struct attribute_group kovaplus_group = {
+ .attrs = kovaplus_attrs,
+ .bin_attrs = kovaplus_bin_attributes,
};
-static struct bin_attribute kovaplus_bin_attributes[] = {
- KOVAPLUS_BIN_ATTRIBUTE_W(control, CONTROL),
- KOVAPLUS_BIN_ATTRIBUTE_RW(info, INFO),
- KOVAPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
- KOVAPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
- {
- .attr = { .name = "profile1_settings", .mode = 0440 },
- .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
- .read = kovaplus_sysfs_read_profilex_settings,
- .private = &profile_numbers[0]
- },
- {
- .attr = { .name = "profile2_settings", .mode = 0440 },
- .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
- .read = kovaplus_sysfs_read_profilex_settings,
- .private = &profile_numbers[1]
- },
- {
- .attr = { .name = "profile3_settings", .mode = 0440 },
- .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
- .read = kovaplus_sysfs_read_profilex_settings,
- .private = &profile_numbers[2]
- },
- {
- .attr = { .name = "profile4_settings", .mode = 0440 },
- .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
- .read = kovaplus_sysfs_read_profilex_settings,
- .private = &profile_numbers[3]
- },
- {
- .attr = { .name = "profile5_settings", .mode = 0440 },
- .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
- .read = kovaplus_sysfs_read_profilex_settings,
- .private = &profile_numbers[4]
- },
- {
- .attr = { .name = "profile1_buttons", .mode = 0440 },
- .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
- .read = kovaplus_sysfs_read_profilex_buttons,
- .private = &profile_numbers[0]
- },
- {
- .attr = { .name = "profile2_buttons", .mode = 0440 },
- .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
- .read = kovaplus_sysfs_read_profilex_buttons,
- .private = &profile_numbers[1]
- },
- {
- .attr = { .name = "profile3_buttons", .mode = 0440 },
- .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
- .read = kovaplus_sysfs_read_profilex_buttons,
- .private = &profile_numbers[2]
- },
- {
- .attr = { .name = "profile4_buttons", .mode = 0440 },
- .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
- .read = kovaplus_sysfs_read_profilex_buttons,
- .private = &profile_numbers[3]
- },
- {
- .attr = { .name = "profile5_buttons", .mode = 0440 },
- .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
- .read = kovaplus_sysfs_read_profilex_buttons,
- .private = &profile_numbers[4]
- },
- __ATTR_NULL
+static const struct attribute_group *kovaplus_groups[] = {
+ &kovaplus_group,
+ NULL,
};
static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
@@ -662,8 +639,7 @@ static int __init kovaplus_init(void)
kovaplus_class = class_create(THIS_MODULE, "kovaplus");
if (IS_ERR(kovaplus_class))
return PTR_ERR(kovaplus_class);
- kovaplus_class->dev_attrs = kovaplus_attributes;
- kovaplus_class->dev_bin_attrs = kovaplus_bin_attributes;
+ kovaplus_class->dev_groups = kovaplus_groups;
retval = hid_register_driver(&kovaplus_driver);
if (retval)
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index d4f1e3bee59..5a6dbbeee79 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -156,7 +156,8 @@ PYRA_SYSFS_W(thingy, THINGY) \
PYRA_SYSFS_R(thingy, THINGY)
#define PYRA_BIN_ATTRIBUTE_RW(thingy, THINGY) \
-{ \
+PYRA_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = PYRA_SIZE_ ## THINGY, \
.read = pyra_sysfs_read_ ## thingy, \
@@ -164,24 +165,25 @@ PYRA_SYSFS_R(thingy, THINGY)
}
#define PYRA_BIN_ATTRIBUTE_R(thingy, THINGY) \
-{ \
+PYRA_SYSFS_R(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = PYRA_SIZE_ ## THINGY, \
.read = pyra_sysfs_read_ ## thingy, \
}
#define PYRA_BIN_ATTRIBUTE_W(thingy, THINGY) \
-{ \
+PYRA_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = PYRA_SIZE_ ## THINGY, \
.write = pyra_sysfs_write_ ## thingy \
}
-PYRA_SYSFS_W(control, CONTROL)
-PYRA_SYSFS_RW(info, INFO)
-PYRA_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
-PYRA_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
-PYRA_SYSFS_R(settings, SETTINGS)
+PYRA_BIN_ATTRIBUTE_W(control, CONTROL);
+PYRA_BIN_ATTRIBUTE_RW(info, INFO);
+PYRA_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
+PYRA_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
@@ -221,6 +223,25 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
PYRA_COMMAND_PROFILE_BUTTONS);
}
+#define PROFILE_ATTR(number) \
+static struct bin_attribute bin_attr_profile##number##_settings = { \
+ .attr = { .name = "profile##number##_settings", .mode = 0440 }, \
+ .size = PYRA_SIZE_PROFILE_SETTINGS, \
+ .read = pyra_sysfs_read_profilex_settings, \
+ .private = &profile_numbers[number-1], \
+}; \
+static struct bin_attribute bin_attr_profile##number##_buttons = { \
+ .attr = { .name = "profile##number##_buttons", .mode = 0440 }, \
+ .size = PYRA_SIZE_PROFILE_BUTTONS, \
+ .read = pyra_sysfs_read_profilex_buttons, \
+ .private = &profile_numbers[number-1], \
+};
+PROFILE_ATTR(1);
+PROFILE_ATTR(2);
+PROFILE_ATTR(3);
+PROFILE_ATTR(4);
+PROFILE_ATTR(5);
+
static ssize_t pyra_sysfs_write_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
@@ -258,6 +279,11 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
return PYRA_SIZE_SETTINGS;
}
+PYRA_SYSFS_R(settings, SETTINGS);
+static struct bin_attribute bin_attr_settings =
+ __BIN_ATTR(settings, (S_IWUSR | S_IRUGO),
+ pyra_sysfs_read_settings, pyra_sysfs_write_settings,
+ PYRA_SIZE_SETTINGS);
static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -266,6 +292,7 @@ static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev,
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi);
}
+static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL);
static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -282,6 +309,8 @@ static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", settings.startup_profile);
}
+static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
+static DEVICE_ATTR(startup_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -301,84 +330,44 @@ static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
}
+static DEVICE_ATTR(firmware_version, 0440, pyra_sysfs_show_firmware_version,
+ NULL);
+
+static struct attribute *pyra_attrs[] = {
+ &dev_attr_actual_cpi.attr,
+ &dev_attr_actual_profile.attr,
+ &dev_attr_firmware_version.attr,
+ &dev_attr_startup_profile.attr,
+ NULL,
+};
+
+static struct bin_attribute *pyra_bin_attributes[] = {
+ &bin_attr_control,
+ &bin_attr_info,
+ &bin_attr_profile_settings,
+ &bin_attr_profile_buttons,
+ &bin_attr_settings,
+ &bin_attr_profile1_settings,
+ &bin_attr_profile2_settings,
+ &bin_attr_profile3_settings,
+ &bin_attr_profile4_settings,
+ &bin_attr_profile5_settings,
+ &bin_attr_profile1_buttons,
+ &bin_attr_profile2_buttons,
+ &bin_attr_profile3_buttons,
+ &bin_attr_profile4_buttons,
+ &bin_attr_profile5_buttons,
+ NULL,
+};
-static struct device_attribute pyra_attributes[] = {
- __ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL),
- __ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL),
- __ATTR(firmware_version, 0440,
- pyra_sysfs_show_firmware_version, NULL),
- __ATTR(startup_profile, 0440,
- pyra_sysfs_show_actual_profile, NULL),
- __ATTR_NULL
+static const struct attribute_group pyra_group = {
+ .attrs = pyra_attrs,
+ .bin_attrs = pyra_bin_attributes,
};
-static struct bin_attribute pyra_bin_attributes[] = {
- PYRA_BIN_ATTRIBUTE_W(control, CONTROL),
- PYRA_BIN_ATTRIBUTE_RW(info, INFO),
- PYRA_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
- PYRA_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
- PYRA_BIN_ATTRIBUTE_RW(settings, SETTINGS),
- {
- .attr = { .name = "profile1_settings", .mode = 0440 },
- .size = PYRA_SIZE_PROFILE_SETTINGS,
- .read = pyra_sysfs_read_profilex_settings,
- .private = &profile_numbers[0]
- },
- {
- .attr = { .name = "profile2_settings", .mode = 0440 },
- .size = PYRA_SIZE_PROFILE_SETTINGS,
- .read = pyra_sysfs_read_profilex_settings,
- .private = &profile_numbers[1]
- },
- {
- .attr = { .name = "profile3_settings", .mode = 0440 },
- .size = PYRA_SIZE_PROFILE_SETTINGS,
- .read = pyra_sysfs_read_profilex_settings,
- .private = &profile_numbers[2]
- },
- {
- .attr = { .name = "profile4_settings", .mode = 0440 },
- .size = PYRA_SIZE_PROFILE_SETTINGS,
- .read = pyra_sysfs_read_profilex_settings,
- .private = &profile_numbers[3]
- },
- {
- .attr = { .name = "profile5_settings", .mode = 0440 },
- .size = PYRA_SIZE_PROFILE_SETTINGS,
- .read = pyra_sysfs_read_profilex_settings,
- .private = &profile_numbers[4]
- },
- {
- .attr = { .name = "profile1_buttons", .mode = 0440 },
- .size = PYRA_SIZE_PROFILE_BUTTONS,
- .read = pyra_sysfs_read_profilex_buttons,
- .private = &profile_numbers[0]
- },
- {
- .attr = { .name = "profile2_buttons", .mode = 0440 },
- .size = PYRA_SIZE_PROFILE_BUTTONS,
- .read = pyra_sysfs_read_profilex_buttons,
- .private = &profile_numbers[1]
- },
- {
- .attr = { .name = "profile3_buttons", .mode = 0440 },
- .size = PYRA_SIZE_PROFILE_BUTTONS,
- .read = pyra_sysfs_read_profilex_buttons,
- .private = &profile_numbers[2]
- },
- {
- .attr = { .name = "profile4_buttons", .mode = 0440 },
- .size = PYRA_SIZE_PROFILE_BUTTONS,
- .read = pyra_sysfs_read_profilex_buttons,
- .private = &profile_numbers[3]
- },
- {
- .attr = { .name = "profile5_buttons", .mode = 0440 },
- .size = PYRA_SIZE_PROFILE_BUTTONS,
- .read = pyra_sysfs_read_profilex_buttons,
- .private = &profile_numbers[4]
- },
- __ATTR_NULL
+static const struct attribute_group *pyra_groups[] = {
+ &pyra_group,
+ NULL,
};
static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
@@ -600,8 +589,7 @@ static int __init pyra_init(void)
pyra_class = class_create(THIS_MODULE, "pyra");
if (IS_ERR(pyra_class))
return PTR_ERR(pyra_class);
- pyra_class->dev_attrs = pyra_attributes;
- pyra_class->dev_bin_attrs = pyra_bin_attributes;
+ pyra_class->dev_groups = pyra_groups;
retval = hid_register_driver(&pyra_driver);
if (retval)
diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c
index 31747a29c09..0332267199d 100644
--- a/drivers/hid/hid-roccat-savu.c
+++ b/drivers/hid/hid-roccat-savu.c
@@ -94,44 +94,48 @@ SAVU_SYSFS_W(thingy, THINGY) \
SAVU_SYSFS_R(thingy, THINGY)
#define SAVU_BIN_ATTRIBUTE_RW(thingy, THINGY) \
-{ \
+SAVU_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = SAVU_SIZE_ ## THINGY, \
.read = savu_sysfs_read_ ## thingy, \
.write = savu_sysfs_write_ ## thingy \
}
-#define SAVU_BIN_ATTRIBUTE_R(thingy, THINGY) \
-{ \
- .attr = { .name = #thingy, .mode = 0440 }, \
- .size = SAVU_SIZE_ ## THINGY, \
- .read = savu_sysfs_read_ ## thingy, \
-}
-
#define SAVU_BIN_ATTRIBUTE_W(thingy, THINGY) \
-{ \
+SAVU_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = SAVU_SIZE_ ## THINGY, \
.write = savu_sysfs_write_ ## thingy \
}
-SAVU_SYSFS_W(control, CONTROL)
-SAVU_SYSFS_RW(profile, PROFILE)
-SAVU_SYSFS_RW(general, GENERAL)
-SAVU_SYSFS_RW(buttons, BUTTONS)
-SAVU_SYSFS_RW(macro, MACRO)
-SAVU_SYSFS_RW(info, INFO)
-SAVU_SYSFS_RW(sensor, SENSOR)
-
-static struct bin_attribute savu_bin_attributes[] = {
- SAVU_BIN_ATTRIBUTE_W(control, CONTROL),
- SAVU_BIN_ATTRIBUTE_RW(profile, PROFILE),
- SAVU_BIN_ATTRIBUTE_RW(general, GENERAL),
- SAVU_BIN_ATTRIBUTE_RW(buttons, BUTTONS),
- SAVU_BIN_ATTRIBUTE_RW(macro, MACRO),
- SAVU_BIN_ATTRIBUTE_RW(info, INFO),
- SAVU_BIN_ATTRIBUTE_RW(sensor, SENSOR),
- __ATTR_NULL
+SAVU_BIN_ATTRIBUTE_W(control, CONTROL);
+SAVU_BIN_ATTRIBUTE_RW(profile, PROFILE);
+SAVU_BIN_ATTRIBUTE_RW(general, GENERAL);
+SAVU_BIN_ATTRIBUTE_RW(buttons, BUTTONS);
+SAVU_BIN_ATTRIBUTE_RW(macro, MACRO);
+SAVU_BIN_ATTRIBUTE_RW(info, INFO);
+SAVU_BIN_ATTRIBUTE_RW(sensor, SENSOR);
+
+static struct bin_attribute *savu_bin_attributes[] = {
+ &bin_attr_control,
+ &bin_attr_profile,
+ &bin_attr_general,
+ &bin_attr_buttons,
+ &bin_attr_macro,
+ &bin_attr_info,
+ &bin_attr_sensor,
+ NULL,
+};
+
+static const struct attribute_group savu_group = {
+ .bin_attrs = savu_bin_attributes,
+};
+
+static const struct attribute_group *savu_groups[] = {
+ &savu_group,
+ NULL,
};
static int savu_init_savu_device_struct(struct usb_device *usb_dev,
@@ -294,7 +298,7 @@ static int __init savu_init(void)
savu_class = class_create(THIS_MODULE, "savu");
if (IS_ERR(savu_class))
return PTR_ERR(savu_class);
- savu_class->dev_bin_attrs = savu_bin_attributes;
+ savu_class->dev_groups = savu_groups;
retval = hid_register_driver(&savu_driver);
if (retval)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index ecbc74923d0..87fbe2924cf 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -369,7 +369,8 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
if (sc->quirks & PS3REMOTE)
return ps3remote_mapping(hdev, hi, field, usage, bit, max);
- return -1;
+ /* Let hid-core decide for the others */
+ return 0;
}
/*
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index a7451632ceb..6f1feb2c2e9 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -518,7 +518,6 @@ int hidraw_connect(struct hid_device *hid)
goto out;
}
- mutex_unlock(&minors_lock);
init_waitqueue_head(&dev->wait);
INIT_LIST_HEAD(&dev->list);
@@ -528,6 +527,7 @@ int hidraw_connect(struct hid_device *hid)
dev->exist = 1;
hid->hidraw = dev;
+ mutex_unlock(&minors_lock);
out:
return result;
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 0df75908200..bbff5f200be 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -48,30 +48,39 @@ struct vmbus_channel_message_table_entry {
* @negop is of type &struct icmsg_negotiate.
* Set up and fill in default negotiate response message.
*
- * The max_fw_version specifies the maximum framework version that
- * we can support and max _srv_version specifies the maximum service
- * version we can support. A special value MAX_SRV_VER can be
- * specified to indicate that we can handle the maximum version
- * exposed by the host.
+ * The fw_version specifies the framework version that
+ * we can support and srv_version specifies the service
+ * version we can support.
*
* Mainly used by Hyper-V drivers.
*/
-void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
+bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
struct icmsg_negotiate *negop, u8 *buf,
- int max_fw_version, int max_srv_version)
+ int fw_version, int srv_version)
{
- int icframe_vercnt;
- int icmsg_vercnt;
+ int icframe_major, icframe_minor;
+ int icmsg_major, icmsg_minor;
+ int fw_major, fw_minor;
+ int srv_major, srv_minor;
int i;
+ bool found_match = false;
icmsghdrp->icmsgsize = 0x10;
+ fw_major = (fw_version >> 16);
+ fw_minor = (fw_version & 0xFFFF);
+
+ srv_major = (srv_version >> 16);
+ srv_minor = (srv_version & 0xFFFF);
negop = (struct icmsg_negotiate *)&buf[
sizeof(struct vmbuspipe_hdr) +
sizeof(struct icmsg_hdr)];
- icframe_vercnt = negop->icframe_vercnt;
- icmsg_vercnt = negop->icmsg_vercnt;
+ icframe_major = negop->icframe_vercnt;
+ icframe_minor = 0;
+
+ icmsg_major = negop->icmsg_vercnt;
+ icmsg_minor = 0;
/*
* Select the framework version number we will
@@ -79,26 +88,48 @@ void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
*/
for (i = 0; i < negop->icframe_vercnt; i++) {
- if (negop->icversion_data[i].major <= max_fw_version)
- icframe_vercnt = negop->icversion_data[i].major;
+ if ((negop->icversion_data[i].major == fw_major) &&
+ (negop->icversion_data[i].minor == fw_minor)) {
+ icframe_major = negop->icversion_data[i].major;
+ icframe_minor = negop->icversion_data[i].minor;
+ found_match = true;
+ }
}
+ if (!found_match)
+ goto fw_error;
+
+ found_match = false;
+
for (i = negop->icframe_vercnt;
(i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
- if (negop->icversion_data[i].major <= max_srv_version)
- icmsg_vercnt = negop->icversion_data[i].major;
+ if ((negop->icversion_data[i].major == srv_major) &&
+ (negop->icversion_data[i].minor == srv_minor)) {
+ icmsg_major = negop->icversion_data[i].major;
+ icmsg_minor = negop->icversion_data[i].minor;
+ found_match = true;
+ }
}
/*
- * Respond with the maximum framework and service
+ * Respond with the framework and service
* version numbers we can support.
*/
- negop->icframe_vercnt = 1;
- negop->icmsg_vercnt = 1;
- negop->icversion_data[0].major = icframe_vercnt;
- negop->icversion_data[0].minor = 0;
- negop->icversion_data[1].major = icmsg_vercnt;
- negop->icversion_data[1].minor = 0;
+
+fw_error:
+ if (!found_match) {
+ negop->icframe_vercnt = 0;
+ negop->icmsg_vercnt = 0;
+ } else {
+ negop->icframe_vercnt = 1;
+ negop->icmsg_vercnt = 1;
+ }
+
+ negop->icversion_data[0].major = icframe_major;
+ negop->icversion_data[0].minor = icframe_minor;
+ negop->icversion_data[1].major = icmsg_major;
+ negop->icversion_data[1].minor = icmsg_minor;
+ return found_match;
}
EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
@@ -262,6 +293,13 @@ static void vmbus_process_offer(struct work_struct *work)
}
/*
+ * This state is used to indicate a successful open
+ * so that when we do close the channel normally, we
+ * can cleanup properly
+ */
+ newchannel->state = CHANNEL_OPEN_STATE;
+
+ /*
* Start the process of binding this offer to the driver
* We need to set the DeviceObject field before calling
* vmbus_child_dev_add()
@@ -287,13 +325,6 @@ static void vmbus_process_offer(struct work_struct *work)
kfree(newchannel->device_obj);
free_channel(newchannel);
- } else {
- /*
- * This state is used to indicate a successful open
- * so that when we do close the channel normally, we
- * can cleanup properly
- */
- newchannel->state = CHANNEL_OPEN_STATE;
}
}
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index ec3b8cdf1e0..8f4743ab5fb 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -195,7 +195,10 @@ int vmbus_connect(void)
do {
ret = vmbus_negotiate_version(msginfo, version);
- if (ret == 0)
+ if (ret)
+ goto cleanup;
+
+ if (vmbus_connection.conn_state == CONNECTED)
break;
version = vmbus_get_next_version(version);
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 4c605c70ebf..7e17a5495e0 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -562,7 +562,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
struct hv_hotadd_state *has)
{
int ret = 0;
- int i, nid, t;
+ int i, nid;
unsigned long start_pfn;
unsigned long processed_pfn;
unsigned long total_pfn = pfn_count;
@@ -607,14 +607,11 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
/*
* Wait for the memory block to be onlined.
+ * Since the hot add has succeeded, it is ok to
+ * proceed even if the pages in the hot added region
+ * have not been "onlined" within the allowed time.
*/
- t = wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
- if (t == 0) {
- pr_info("hot_add memory timedout\n");
- has->ha_end_pfn -= HA_CHUNK;
- has->covered_end_pfn -= processed_pfn;
- break;
- }
+ wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
}
@@ -828,7 +825,6 @@ static void hot_add_req(struct work_struct *dummy)
memset(&resp, 0, sizeof(struct dm_hot_add_response));
resp.hdr.type = DM_MEM_HOT_ADD_RESPONSE;
resp.hdr.size = sizeof(struct dm_hot_add_response);
- resp.hdr.trans_id = atomic_inc_return(&trans_id);
#ifdef CONFIG_MEMORY_HOTPLUG
pg_start = dm->ha_wrk.ha_page_range.finfo.start_page;
@@ -890,6 +886,7 @@ static void hot_add_req(struct work_struct *dummy)
pr_info("Memory hot add failed\n");
dm->state = DM_INITIALIZED;
+ resp.hdr.trans_id = atomic_inc_return(&trans_id);
vmbus_sendpacket(dm->dev->channel, &resp,
sizeof(struct dm_hot_add_response),
(unsigned long)NULL,
@@ -978,6 +975,14 @@ static void post_status(struct hv_dynmem_device *dm)
dm->num_pages_ballooned +
compute_balloon_floor();
+ /*
+ * If our transaction ID is no longer current, just don't
+ * send the status. This can happen if we were interrupted
+ * after we picked our transaction ID.
+ */
+ if (status.hdr.trans_id != atomic_read(&trans_id))
+ return;
+
vmbus_sendpacket(dm->dev->channel, &status,
sizeof(struct dm_status),
(unsigned long)NULL,
@@ -1076,7 +1081,6 @@ static void balloon_up(struct work_struct *dummy)
bl_resp = (struct dm_balloon_response *)send_buffer;
memset(send_buffer, 0, PAGE_SIZE);
bl_resp->hdr.type = DM_BALLOON_RESPONSE;
- bl_resp->hdr.trans_id = atomic_inc_return(&trans_id);
bl_resp->hdr.size = sizeof(struct dm_balloon_response);
bl_resp->more_pages = 1;
@@ -1104,6 +1108,7 @@ static void balloon_up(struct work_struct *dummy)
*/
do {
+ bl_resp->hdr.trans_id = atomic_inc_return(&trans_id);
ret = vmbus_sendpacket(dm_device.dev->channel,
bl_resp,
bl_resp->hdr.size,
@@ -1521,5 +1526,4 @@ static int __init init_balloon_drv(void)
module_init(init_balloon_drv);
MODULE_DESCRIPTION("Hyper-V Balloon");
-MODULE_VERSION(HV_DRV_VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index ed50e9e83c6..28b03325b87 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -29,6 +29,16 @@
#include <linux/hyperv.h>
+/*
+ * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7)
+ */
+#define WIN7_SRV_MAJOR 3
+#define WIN7_SRV_MINOR 0
+#define WIN7_SRV_MAJOR_MINOR (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR)
+
+#define WIN8_SRV_MAJOR 4
+#define WIN8_SRV_MINOR 0
+#define WIN8_SRV_MAJOR_MINOR (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
/*
* Global state maintained for transaction that is being processed.
@@ -76,7 +86,9 @@ static u8 *recv_buffer;
/*
* Register the kernel component with the user-level daemon.
* As part of this registration, pass the LIC version number.
+ * This number has no meaning, it satisfies the registration protocol.
*/
+#define HV_DRV_VERSION "3.1"
static void
kvp_register(int reg_value)
@@ -593,8 +605,19 @@ void hv_kvp_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ /*
+ * We start with win8 version and if the host cannot
+ * support that we use the previous version.
+ */
+ if (vmbus_prep_negotiate_resp(icmsghdrp, negop,
+ recv_buffer, UTIL_FW_MAJOR_MINOR,
+ WIN8_SRV_MAJOR_MINOR))
+ goto done;
+
vmbus_prep_negotiate_resp(icmsghdrp, negop,
- recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
+ recv_buffer, UTIL_FW_MAJOR_MINOR,
+ WIN7_SRV_MAJOR_MINOR);
+
} else {
kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
sizeof(struct vmbuspipe_hdr) +
@@ -626,6 +649,7 @@ void hv_kvp_onchannelcallback(void *context)
return;
}
+done:
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 8ad5653ce44..e4572f3f283 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -24,6 +24,10 @@
#include <linux/workqueue.h>
#include <linux/hyperv.h>
+#define VSS_MAJOR 5
+#define VSS_MINOR 0
+#define VSS_MAJOR_MINOR (VSS_MAJOR << 16 | VSS_MINOR)
+
/*
@@ -186,18 +190,8 @@ void hv_vss_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, negop,
- recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
- /*
- * We currently negotiate the highest number the
- * host has presented. If this version is not
- * atleast 5.0, reject.
- */
- negop = (struct icmsg_negotiate *)&recv_buffer[
- sizeof(struct vmbuspipe_hdr) +
- sizeof(struct icmsg_hdr)];
-
- if (negop->icversion_data[1].major < 5)
- negop->icframe_vercnt = 0;
+ recv_buffer, UTIL_FW_MAJOR_MINOR,
+ VSS_MAJOR_MINOR);
} else {
vss_msg = (struct hv_vss_msg *)&recv_buffer[
sizeof(struct vmbuspipe_hdr) +
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 2f561c5dfe2..cb82233541b 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -28,6 +28,18 @@
#include <linux/reboot.h>
#include <linux/hyperv.h>
+#define SHUTDOWN_MAJOR 3
+#define SHUTDOWN_MINOR 0
+#define SHUTDOWN_MAJOR_MINOR (SHUTDOWN_MAJOR << 16 | SHUTDOWN_MINOR)
+
+#define TIMESYNCH_MAJOR 3
+#define TIMESYNCH_MINOR 0
+#define TIMESYNCH_MAJOR_MINOR (TIMESYNCH_MAJOR << 16 | TIMESYNCH_MINOR)
+
+#define HEARTBEAT_MAJOR 3
+#define HEARTBEAT_MINOR 0
+#define HEARTBEAT_MAJOR_MINOR (HEARTBEAT_MAJOR << 16 | HEARTBEAT_MINOR)
+
static void shutdown_onchannelcallback(void *context);
static struct hv_util_service util_shutdown = {
.util_cb = shutdown_onchannelcallback,
@@ -87,7 +99,8 @@ static void shutdown_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, negop,
- shut_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
+ shut_txf_buf, UTIL_FW_MAJOR_MINOR,
+ SHUTDOWN_MAJOR_MINOR);
} else {
shutdown_msg =
(struct shutdown_msg_data *)&shut_txf_buf[
@@ -213,7 +226,8 @@ static void timesync_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf,
- MAX_SRV_VER, MAX_SRV_VER);
+ UTIL_FW_MAJOR_MINOR,
+ TIMESYNCH_MAJOR_MINOR);
} else {
timedatap = (struct ictimesync_data *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr) +
@@ -253,7 +267,8 @@ static void heartbeat_onchannelcallback(void *context)
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
vmbus_prep_negotiate_resp(icmsghdrp, NULL,
- hbeat_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
+ hbeat_txf_buf, UTIL_FW_MAJOR_MINOR,
+ HEARTBEAT_MAJOR_MINOR);
} else {
heartbeat_msg =
(struct heartbeat_msg_data *)&hbeat_txf_buf[
@@ -380,5 +395,4 @@ module_init(init_hyperv_utils);
module_exit(exit_hyperv_utils);
MODULE_DESCRIPTION("Hyper-V Utilities");
-MODULE_VERSION(HV_DRV_VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index a2464bf07c4..f9fe46f52cf 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -690,7 +690,7 @@ int vmbus_device_register(struct hv_device *child_device_obj)
if (ret)
pr_err("Unable to register child device\n");
else
- pr_info("child device %s registered\n",
+ pr_debug("child device %s registered\n",
dev_name(&child_device_obj->device));
return ret;
@@ -702,14 +702,14 @@ int vmbus_device_register(struct hv_device *child_device_obj)
*/
void vmbus_device_unregister(struct hv_device *device_obj)
{
+ pr_debug("child device %s unregistered\n",
+ dev_name(&device_obj->device));
+
/*
* Kick off the process of unregistering the device.
* This will call vmbus_remove() and eventually vmbus_device_release()
*/
device_unregister(&device_obj->device);
-
- pr_info("child device %s unregistered\n",
- dev_name(&device_obj->device));
}
@@ -816,7 +816,6 @@ static void __exit vmbus_exit(void)
MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
subsys_initcall(hv_acpi_init);
module_exit(vmbus_exit);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index e989f7fd645..b3ab9d43bb3 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -296,8 +296,8 @@ config SENSORS_K10TEMP
If you say yes here you get support for the temperature
sensor(s) inside your CPU. Supported are later revisions of
the AMD Family 10h and all revisions of the AMD Family 11h,
- 12h (Llano), 14h (Brazos) and 15h (Bulldozer/Trinity)
- microarchitectures.
+ 12h (Llano), 14h (Brazos), 15h (Bulldozer/Trinity) and
+ 16h (Kabini) microarchitectures.
This driver can also be built as a module. If so, the module
will be called k10temp.
@@ -511,6 +511,16 @@ config SENSORS_HIH6130
This driver can also be built as a module. If so, the module
will be called hih6130.
+config SENSORS_HTU21
+ tristate "Measurement Specialties HTU21D humidity/temperature sensors"
+ depends on I2C
+ help
+ If you say yes here you get support for the Measurement Specialties
+ HTU21D humidity and temperature sensors.
+
+ This driver can also be built as a module. If so, the module
+ will be called htu21.
+
config SENSORS_CORETEMP
tristate "Intel Core/Core2/Atom temperature sensor"
depends on X86
@@ -1202,8 +1212,8 @@ config SENSORS_ADS1015
tristate "Texas Instruments ADS1015"
depends on I2C
help
- If you say yes here you get support for Texas Instruments ADS1015
- 12-bit 4-input ADC device.
+ If you say yes here you get support for Texas Instruments
+ ADS1015/ADS1115 12/16-bit 4-input ADC device.
This driver can also be built as a module. If so, the module
will be called ads1015.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4f0fb5235f4..ec7cde06eb5 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o
+obj-$(CONFIG_SENSORS_HTU21) += htu21.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 6351aba8819..a9e3d0152c0 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -2,7 +2,7 @@
* A hwmon driver for ACPI 4.0 power meters
* Copyright (C) 2009 IBM
*
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -1001,7 +1001,7 @@ static void __exit acpi_power_meter_exit(void)
acpi_bus_unregister_driver(&acpi_power_meter_driver);
}
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
MODULE_DESCRIPTION("ACPI 4.0 power meter driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
index 2798246ad81..7f9dc2f86b6 100644
--- a/drivers/hwmon/ads1015.c
+++ b/drivers/hwmon/ads1015.c
@@ -46,17 +46,28 @@ static const unsigned int fullscale_table[8] = {
6144, 4096, 2048, 1024, 512, 256, 256, 256 };
/* Data rates in samples per second */
-static const unsigned int data_rate_table[8] = {
- 128, 250, 490, 920, 1600, 2400, 3300, 3300 };
+static const unsigned int data_rate_table_1015[8] = {
+ 128, 250, 490, 920, 1600, 2400, 3300, 3300
+};
+
+static const unsigned int data_rate_table_1115[8] = {
+ 8, 16, 32, 64, 128, 250, 475, 860
+};
#define ADS1015_DEFAULT_CHANNELS 0xff
#define ADS1015_DEFAULT_PGA 2
#define ADS1015_DEFAULT_DATA_RATE 4
+enum ads1015_chips {
+ ads1015,
+ ads1115,
+};
+
struct ads1015_data {
struct device *hwmon_dev;
struct mutex update_lock; /* mutex protect updates */
struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
+ enum ads1015_chips id;
};
static int ads1015_read_adc(struct i2c_client *client, unsigned int channel)
@@ -66,6 +77,8 @@ static int ads1015_read_adc(struct i2c_client *client, unsigned int channel)
unsigned int pga = data->channel_data[channel].pga;
unsigned int data_rate = data->channel_data[channel].data_rate;
unsigned int conversion_time_ms;
+ const unsigned int * const rate_table = data->id == ads1115 ?
+ data_rate_table_1115 : data_rate_table_1015;
int res;
mutex_lock(&data->update_lock);
@@ -75,7 +88,7 @@ static int ads1015_read_adc(struct i2c_client *client, unsigned int channel)
if (res < 0)
goto err_unlock;
config = res;
- conversion_time_ms = DIV_ROUND_UP(1000, data_rate_table[data_rate]);
+ conversion_time_ms = DIV_ROUND_UP(1000, rate_table[data_rate]);
/* setup and start single conversion */
config &= 0x001f;
@@ -113,8 +126,9 @@ static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel,
struct ads1015_data *data = i2c_get_clientdata(client);
unsigned int pga = data->channel_data[channel].pga;
int fullscale = fullscale_table[pga];
+ const unsigned mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
- return DIV_ROUND_CLOSEST(reg * fullscale, 0x7ff0);
+ return DIV_ROUND_CLOSEST(reg * fullscale, mask);
}
/* sysfs callback function */
@@ -257,7 +271,7 @@ static int ads1015_probe(struct i2c_client *client,
GFP_KERNEL);
if (!data)
return -ENOMEM;
-
+ data->id = id->driver_data;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
@@ -286,7 +300,8 @@ exit_remove:
}
static const struct i2c_device_id ads1015_id[] = {
- { "ads1015", 0 },
+ { "ads1015", ads1015},
+ { "ads1115", ads1115},
{ }
};
MODULE_DEVICE_TABLE(i2c, ads1015_id);
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index ba962ac4b81..7092c78f814 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -145,7 +145,7 @@ static int ads7828_remove(struct i2c_client *client)
static int ads7828_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct ads7828_platform_data *pdata = client->dev.platform_data;
+ struct ads7828_platform_data *pdata = dev_get_platdata(&client->dev);
struct ads7828_data *data;
int err;
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
index 69481d3a3d2..addb5a4d506 100644
--- a/drivers/hwmon/adt7462.c
+++ b/drivers/hwmon/adt7462.c
@@ -2,7 +2,7 @@
* A hwmon driver for the Analog Devices ADT7462
* Copyright (C) 2008 IBM
*
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -333,7 +333,7 @@ static int ADT7462_REG_VOLT_MAX(struct adt7462_data *data, int which)
return 0x4C;
break;
}
- return -ENODEV;
+ return 0;
}
static int ADT7462_REG_VOLT_MIN(struct adt7462_data *data, int which)
@@ -392,7 +392,7 @@ static int ADT7462_REG_VOLT_MIN(struct adt7462_data *data, int which)
return 0x77;
break;
}
- return -ENODEV;
+ return 0;
}
static int ADT7462_REG_VOLT(struct adt7462_data *data, int which)
@@ -1970,6 +1970,6 @@ static int adt7462_remove(struct i2c_client *client)
module_i2c_driver(adt7462_driver);
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
MODULE_DESCRIPTION("ADT7462 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 0f34bca9f5e..0f4dea5ccf1 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -2,7 +2,7 @@
* A hwmon driver for the Analog Devices ADT7470
* Copyright (C) 2007 IBM
*
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -215,7 +215,7 @@ static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg,
u16 value)
{
return i2c_smbus_write_byte_data(client, reg, value & 0xFF)
- && i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
+ || i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
}
static void adt7470_init_client(struct i2c_client *client)
@@ -1314,6 +1314,6 @@ static int adt7470_remove(struct i2c_client *client)
module_i2c_driver(adt7470_driver);
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
MODULE_DESCRIPTION("ADT7470 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 2e5e2dc47ea..78be6617684 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -316,6 +316,18 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
return tjmax;
}
+static bool cpu_has_tjmax(struct cpuinfo_x86 *c)
+{
+ u8 model = c->x86_model;
+
+ return model > 0xe &&
+ model != 0x1c &&
+ model != 0x26 &&
+ model != 0x27 &&
+ model != 0x35 &&
+ model != 0x36;
+}
+
static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
{
int err;
@@ -328,7 +340,7 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
*/
err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
if (err) {
- if (c->x86_model > 0xe && c->x86_model != 0x1c)
+ if (cpu_has_tjmax(c))
dev_warn(dev, "Unable to read TjMax from CPU %u\n", id);
} else {
val = (eax >> 16) & 0xff;
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
index f1d6b422cf0..0918b913658 100644
--- a/drivers/hwmon/ds620.c
+++ b/drivers/hwmon/ds620.c
@@ -77,7 +77,7 @@ struct ds620_data {
static void ds620_init_client(struct i2c_client *client)
{
- struct ds620_platform_data *ds620_info = client->dev.platform_data;
+ struct ds620_platform_data *ds620_info = dev_get_platdata(&client->dev);
u16 conf, new_conf;
new_conf = conf =
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 0c9f3da242b..15b7f5281de 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -1375,7 +1375,7 @@ static void f71805f_init_device(struct f71805f_data *data)
static int f71805f_probe(struct platform_device *pdev)
{
- struct f71805f_sio_data *sio_data = pdev->dev.platform_data;
+ struct f71805f_sio_data *sio_data = dev_get_platdata(&pdev->dev);
struct f71805f_data *data;
struct resource *res;
int i, err;
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index cfb02dd91aa..31b221eeee6 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -2267,7 +2267,7 @@ static int f71882fg_create_fan_sysfs_files(
static int f71882fg_probe(struct platform_device *pdev)
{
struct f71882fg_data *data;
- struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
+ struct f71882fg_sio_data *sio_data = dev_get_platdata(&pdev->dev);
int nr_fans = f71882fg_nr_fans[sio_data->type];
int nr_temps = f71882fg_nr_temps[sio_data->type];
int err, i;
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index 9e300e567f1..a837b94977f 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -832,7 +832,8 @@ static int f75375_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct f75375_data *data;
- struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data;
+ struct f75375s_platform_data *f75375s_pdata =
+ dev_get_platdata(&client->dev);
int err;
if (!i2c_check_functionality(client->adapter,
diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c
index 73adf01b0ef..b4b8b5bef71 100644
--- a/drivers/hwmon/g762.c
+++ b/drivers/hwmon/g762.c
@@ -717,7 +717,7 @@ static void g762_of_clock_disable(struct i2c_client *client) { }
static int g762_pdata_prop_import(struct i2c_client *client)
{
- struct g762_platform_data *pdata = client->dev.platform_data;
+ struct g762_platform_data *pdata = dev_get_platdata(&client->dev);
int ret;
if (!pdata)
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 3104149795c..b7d6a5704eb 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -495,7 +495,7 @@ static int gpio_fan_probe(struct platform_device *pdev)
{
int err;
struct gpio_fan_data *fan_data;
- struct gpio_fan_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_fan_platform_data *pdata = dev_get_platdata(&pdev->dev);
#ifdef CONFIG_OF_GPIO
if (!pdata) {
diff --git a/drivers/hwmon/htu21.c b/drivers/hwmon/htu21.c
new file mode 100644
index 00000000000..839086e0e95
--- /dev/null
+++ b/drivers/hwmon/htu21.c
@@ -0,0 +1,199 @@
+/*
+ * Measurement Specialties HTU21D humidity and temperature sensor driver
+ *
+ * Copyright (C) 2013 William Markezana <william.markezana@meas-spec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+
+/* HTU21 Commands */
+#define HTU21_T_MEASUREMENT_HM 0xE3
+#define HTU21_RH_MEASUREMENT_HM 0xE5
+
+struct htu21 {
+ struct device *hwmon_dev;
+ struct mutex lock;
+ bool valid;
+ unsigned long last_update;
+ int temperature;
+ int humidity;
+};
+
+static inline int htu21_temp_ticks_to_millicelsius(int ticks)
+{
+ ticks &= ~0x0003; /* clear status bits */
+ /*
+ * Formula T = -46.85 + 175.72 * ST / 2^16 from datasheet p14,
+ * optimized for integer fixed point (3 digits) arithmetic
+ */
+ return ((21965 * ticks) >> 13) - 46850;
+}
+
+static inline int htu21_rh_ticks_to_per_cent_mille(int ticks)
+{
+ ticks &= ~0x0003; /* clear status bits */
+ /*
+ * Formula RH = -6 + 125 * SRH / 2^16 from datasheet p14,
+ * optimized for integer fixed point (3 digits) arithmetic
+ */
+ return ((15625 * ticks) >> 13) - 6000;
+}
+
+static int htu21_update_measurements(struct i2c_client *client)
+{
+ int ret = 0;
+ struct htu21 *htu21 = i2c_get_clientdata(client);
+
+ mutex_lock(&htu21->lock);
+
+ if (time_after(jiffies, htu21->last_update + HZ / 2) ||
+ !htu21->valid) {
+ ret = i2c_smbus_read_word_swapped(client,
+ HTU21_T_MEASUREMENT_HM);
+ if (ret < 0)
+ goto out;
+ htu21->temperature = htu21_temp_ticks_to_millicelsius(ret);
+ ret = i2c_smbus_read_word_swapped(client,
+ HTU21_RH_MEASUREMENT_HM);
+ if (ret < 0)
+ goto out;
+ htu21->humidity = htu21_rh_ticks_to_per_cent_mille(ret);
+ htu21->last_update = jiffies;
+ htu21->valid = true;
+ }
+out:
+ mutex_unlock(&htu21->lock);
+
+ return ret >= 0 ? 0 : ret;
+}
+
+static ssize_t htu21_show_temperature(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct htu21 *htu21 = i2c_get_clientdata(client);
+ int ret = htu21_update_measurements(client);
+ if (ret < 0)
+ return ret;
+ return sprintf(buf, "%d\n", htu21->temperature);
+}
+
+static ssize_t htu21_show_humidity(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct htu21 *htu21 = i2c_get_clientdata(client);
+ int ret = htu21_update_measurements(client);
+ if (ret < 0)
+ return ret;
+ return sprintf(buf, "%d\n", htu21->humidity);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+ htu21_show_temperature, NULL, 0);
+static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
+ htu21_show_humidity, NULL, 0);
+
+static struct attribute *htu21_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_humidity1_input.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group htu21_group = {
+ .attrs = htu21_attributes,
+};
+
+static int htu21_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct htu21 *htu21;
+ int err;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ dev_err(&client->dev,
+ "adapter does not support SMBus word transactions\n");
+ return -ENODEV;
+ }
+
+ htu21 = devm_kzalloc(&client->dev, sizeof(*htu21), GFP_KERNEL);
+ if (!htu21)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, htu21);
+
+ mutex_init(&htu21->lock);
+
+ err = sysfs_create_group(&client->dev.kobj, &htu21_group);
+ if (err) {
+ dev_dbg(&client->dev, "could not create sysfs files\n");
+ return err;
+ }
+ htu21->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(htu21->hwmon_dev)) {
+ dev_dbg(&client->dev, "unable to register hwmon device\n");
+ err = PTR_ERR(htu21->hwmon_dev);
+ goto error;
+ }
+
+ dev_info(&client->dev, "initialized\n");
+
+ return 0;
+
+error:
+ sysfs_remove_group(&client->dev.kobj, &htu21_group);
+ return err;
+}
+
+static int htu21_remove(struct i2c_client *client)
+{
+ struct htu21 *htu21 = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(htu21->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &htu21_group);
+
+ return 0;
+}
+
+static const struct i2c_device_id htu21_id[] = {
+ { "htu21", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, htu21_id);
+
+static struct i2c_driver htu21_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "htu21",
+ },
+ .probe = htu21_probe,
+ .remove = htu21_remove,
+ .id_table = htu21_id,
+};
+
+module_i2c_driver(htu21_driver);
+
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_DESCRIPTION("MEAS HTU21D humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index de058c278aa..6c0080a3b90 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -3,7 +3,7 @@
* temperature sensors
* Copyright (C) 2007 IBM
*
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -609,7 +609,7 @@ static void __exit i5k_amb_exit(void)
platform_driver_unregister(&i5k_amb_driver);
}
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
MODULE_DESCRIPTION("Intel 5000 chipset FB-DIMM AMB temperature sensor");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
index 1429f6e177f..e2b56a2b756 100644
--- a/drivers/hwmon/ibmaem.c
+++ b/drivers/hwmon/ibmaem.c
@@ -3,7 +3,7 @@
* temperature/power/energy sensors and capping functionality.
* Copyright (C) 2008 IBM
*
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -1103,7 +1103,7 @@ static void __exit aem_exit(void)
aem_delete(p1);
}
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
MODULE_DESCRIPTION("IBM AEM power/temp/energy sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
index 74b365ea01c..20ab0fb8539 100644
--- a/drivers/hwmon/ibmpex.c
+++ b/drivers/hwmon/ibmpex.c
@@ -2,7 +2,7 @@
* A hwmon driver for the IBM PowerExecutive temperature/power sensors
* Copyright (C) 2007 IBM
*
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -606,7 +606,7 @@ static void __exit ibmpex_exit(void)
ibmpex_bmc_delete(p);
}
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index d917a2d8c30..18c062360ca 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -232,9 +232,9 @@ static int ina2xx_probe(struct i2c_client *client,
if (!data)
return -ENOMEM;
- if (client->dev.platform_data) {
+ if (dev_get_platdata(&client->dev)) {
pdata =
- (struct ina2xx_platform_data *)client->dev.platform_data;
+ (struct ina2xx_platform_data *)dev_get_platdata(&client->dev);
shunt = pdata->shunt_uohms;
} else if (!of_property_read_u32(client->dev.of_node,
"shunt-resistor", &val)) {
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 72b21d5b1c6..29ffa27c60b 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -1962,7 +1962,7 @@ exit:
static void it87_remove_files(struct device *dev)
{
struct it87_data *data = platform_get_drvdata(pdev);
- struct it87_sio_data *sio_data = dev->platform_data;
+ struct it87_sio_data *sio_data = dev_get_platdata(dev);
int i;
sysfs_remove_group(&dev->kobj, &it87_group);
@@ -2014,7 +2014,7 @@ static int it87_probe(struct platform_device *pdev)
struct it87_data *data;
struct resource *res;
struct device *dev = &pdev->dev;
- struct it87_sio_data *sio_data = dev->platform_data;
+ struct it87_sio_data *sio_data = dev_get_platdata(dev);
int err = 0, i;
int enable_pwm_interface;
int fan_beep_need_rw;
@@ -2316,7 +2316,7 @@ static int it87_check_pwm(struct device *dev)
/* Called when we have found a new IT87. */
static void it87_init_device(struct platform_device *pdev)
{
- struct it87_sio_data *sio_data = pdev->dev.platform_data;
+ struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
struct it87_data *data = platform_get_drvdata(pdev);
int tmp, i;
u8 mask;
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index e3b037c73a7..e633856370c 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -1,5 +1,5 @@
/*
- * k10temp.c - AMD Family 10h/11h/12h/14h/15h processor hardware monitoring
+ * k10temp.c - AMD Family 10h/11h/12h/14h/15h/16h processor hardware monitoring
*
* Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
*
@@ -211,6 +211,7 @@ static DEFINE_PCI_DEVICE_TABLE(k10temp_id_table) = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
{}
};
MODULE_DEVICE_TABLE(pci, k10temp_id_table);
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 16e45d70215..333092ce246 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -855,8 +855,8 @@ static void lm87_init_client(struct i2c_client *client)
{
struct lm87_data *data = i2c_get_clientdata(client);
- if (client->dev.platform_data) {
- data->channel = *(u8 *)client->dev.platform_data;
+ if (dev_get_platdata(&client->dev)) {
+ data->channel = *(u8 *)dev_get_platdata(&client->dev);
lm87_write_value(client,
LM87_REG_CHANNEL_MODE, data->channel);
} else {
diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c
index b5ebb9198c7..96dccaf919d 100644
--- a/drivers/hwmon/max197.c
+++ b/drivers/hwmon/max197.c
@@ -261,7 +261,7 @@ static int max197_probe(struct platform_device *pdev)
{
int ch, ret;
struct max197_data *data;
- struct max197_platform_data *pdata = pdev->dev.platform_data;
+ struct max197_platform_data *pdata = dev_get_platdata(&pdev->dev);
enum max197_chips chip = platform_get_device_id(pdev)->driver_data;
if (pdata == NULL) {
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index 3e7b4269f5b..066e587a18a 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -428,7 +428,7 @@ static int max6639_init_client(struct i2c_client *client)
{
struct max6639_data *data = i2c_get_clientdata(client);
struct max6639_platform_data *max6639_info =
- client->dev.platform_data;
+ dev_get_platdata(&client->dev);
int i;
int rpm_range = 1; /* default: 4000 RPM */
int err;
diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c
index 328fb0353c1..a41b5f3fc50 100644
--- a/drivers/hwmon/max6697.c
+++ b/drivers/hwmon/max6697.c
@@ -605,12 +605,12 @@ static int max6697_init_chip(struct i2c_client *client)
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY,
- pdata->ideality_mask >> 1);
+ pdata->ideality_value);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(client,
MAX6581_REG_IDEALITY_SELECT,
- pdata->ideality_value);
+ pdata->ideality_mask >> 1);
if (ret < 0)
return ret;
}
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c
index eedb32292d6..d219c06a857 100644
--- a/drivers/hwmon/mcp3021.c
+++ b/drivers/hwmon/mcp3021.c
@@ -143,12 +143,13 @@ static int mcp3021_probe(struct i2c_client *client,
break;
}
- if (client->dev.platform_data) {
- data->vdd = *(u32 *)client->dev.platform_data;
+ if (dev_get_platdata(&client->dev)) {
+ data->vdd = *(u32 *)dev_get_platdata(&client->dev);
if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN)
return -EINVAL;
- } else
+ } else {
data->vdd = MCP3021_VDD_REF;
+ }
err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
if (err)
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
index 99cec182542..6eb03ce2cff 100644
--- a/drivers/hwmon/nct6775.c
+++ b/drivers/hwmon/nct6775.c
@@ -33,9 +33,11 @@
* Supports the following chips:
*
* Chip #vin #fan #pwm #temp chip IDs man ID
+ * nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
* nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
* nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
* nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
+ * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
*
* #temp lists the number of monitored temperature sources (first value) plus
* the number of directly connectable temperature sensors (second value).
@@ -59,13 +61,15 @@
#define USE_ALTERNATE
-enum kinds { nct6775, nct6776, nct6779 };
+enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791 };
/* used to set data->name = nct6775_device_names[data->sio_kind] */
static const char * const nct6775_device_names[] = {
+ "nct6106",
"nct6775",
"nct6776",
"nct6779",
+ "nct6791",
};
static unsigned short force_id;
@@ -91,9 +95,11 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
#define SIO_REG_ENABLE 0x30 /* Logical device enable */
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
+#define SIO_NCT6106_ID 0xc450
#define SIO_NCT6775_ID 0xb470
#define SIO_NCT6776_ID 0xc330
#define SIO_NCT6779_ID 0xc560
+#define SIO_NCT6791_ID 0xc800
#define SIO_ID_MASK 0xFFF0
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
@@ -167,7 +173,10 @@ superio_exit(int ioreg)
#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
-#define NUM_REG_ALARM 4 /* Max number of alarm registers */
+#define NUM_REG_ALARM 7 /* Max number of alarm registers */
+#define NUM_REG_BEEP 5 /* Max number of beep registers */
+
+#define NUM_FAN 6
/* Common and NCT6775 specific data */
@@ -185,6 +194,7 @@ static const u16 NCT6775_REG_IN[] = {
#define NCT6775_REG_VBAT 0x5D
#define NCT6775_REG_DIODE 0x5E
+#define NCT6775_DIODE_MASK 0x02
#define NCT6775_REG_FANDIV1 0x506
#define NCT6775_REG_FANDIV2 0x507
@@ -193,7 +203,7 @@ static const u16 NCT6775_REG_IN[] = {
static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
-/* 0..15 voltages, 16..23 fans, 24..31 temperatures */
+/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
static const s8 NCT6775_ALARM_BITS[] = {
0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
@@ -208,6 +218,23 @@ static const s8 NCT6775_ALARM_BITS[] = {
#define TEMP_ALARM_BASE 24
#define INTRUSION_ALARM_BASE 30
+static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
+
+/*
+ * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
+ * 30..31 intrusion
+ */
+static const s8 NCT6775_BEEP_BITS[] = {
+ 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
+ 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
+ 21, /* global beep enable */
+ 6, 7, 11, 28, -1, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
+ 12, -1 }; /* intrusion0, intrusion1 */
+
+#define BEEP_ENABLE_BASE 15
+
static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
@@ -217,27 +244,32 @@ static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
/* Advanced Fan control, some values are common for all fans */
-static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301, 0x801, 0x901 };
-static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302, 0x802, 0x902 };
+static const u16 NCT6775_REG_TARGET[] = {
+ 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
+static const u16 NCT6775_REG_FAN_MODE[] = {
+ 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
- 0x103, 0x203, 0x303, 0x803, 0x903 };
+ 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
- 0x104, 0x204, 0x304, 0x804, 0x904 };
+ 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
- 0x105, 0x205, 0x305, 0x805, 0x905 };
-static const u16 NCT6775_REG_FAN_START_OUTPUT[]
- = { 0x106, 0x206, 0x306, 0x806, 0x906 };
+ 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
+ 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
- 0x107, 0x207, 0x307, 0x807, 0x907 };
-static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309, 0x809, 0x909 };
-static const u16 NCT6775_REG_PWM_READ[] = { 0x01, 0x03, 0x11, 0x13, 0x15 };
+ 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
+static const u16 NCT6775_REG_PWM[] = {
+ 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
+static const u16 NCT6775_REG_PWM_READ[] = {
+ 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
+static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
static const u16 NCT6775_REG_TEMP[] = {
0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
@@ -253,25 +285,25 @@ static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
static const u16 NCT6775_REG_TEMP_SEL[] = {
- 0x100, 0x200, 0x300, 0x800, 0x900 };
+ 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
- 0x139, 0x239, 0x339, 0x839, 0x939 };
+ 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
- 0x13a, 0x23a, 0x33a, 0x83a, 0x93a };
+ 0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
- 0x13b, 0x23b, 0x33b, 0x83b, 0x93b };
+ 0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
- 0x13c, 0x23c, 0x33c, 0x83c, 0x93c };
+ 0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
- 0x13d, 0x23d, 0x33d, 0x83d, 0x93d };
+ 0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
static const u16 NCT6775_REG_AUTO_TEMP[] = {
- 0x121, 0x221, 0x321, 0x821, 0x921 };
+ 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
static const u16 NCT6775_REG_AUTO_PWM[] = {
- 0x127, 0x227, 0x327, 0x827, 0x927 };
+ 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
@@ -279,9 +311,9 @@ static const u16 NCT6775_REG_AUTO_PWM[] = {
static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
- 0x135, 0x235, 0x335, 0x835, 0x935 };
+ 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
- 0x138, 0x238, 0x338, 0x838, 0x938 };
+ 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
static const char *const nct6775_temp_label[] = {
"",
@@ -325,17 +357,28 @@ static const s8 NCT6776_ALARM_BITS[] = {
4, 5, 13, -1, -1, -1, /* temp1..temp6 */
12, 9 }; /* intrusion0, intrusion1 */
+static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
+
+static const s8 NCT6776_BEEP_BITS[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
+ 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
+ 24, /* global beep enable */
+ 25, 26, 27, 28, 29, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
+ 30, 31 }; /* intrusion0, intrusion1 */
+
static const u16 NCT6776_REG_TOLERANCE_H[] = {
- 0x10c, 0x20c, 0x30c, 0x80c, 0x90c };
+ 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
-static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0 };
-static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0 };
+static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
+static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
- 0x13e, 0x23e, 0x33e, 0x83e, 0x93e };
+ 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
@@ -390,14 +433,25 @@ static const s8 NCT6779_ALARM_BITS[] = {
4, 5, 13, -1, -1, -1, /* temp1..temp6 */
12, 9 }; /* intrusion0, intrusion1 */
-static const u16 NCT6779_REG_FAN[] = { 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8 };
+static const s8 NCT6779_BEEP_BITS[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
+ 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
+ 24, /* global beep enable */
+ 25, 26, 27, 28, 29, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
+ 30, 31 }; /* intrusion0, intrusion1 */
+
+static const u16 NCT6779_REG_FAN[] = {
+ 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
static const u16 NCT6779_REG_FAN_PULSES[] = {
- 0x644, 0x645, 0x646, 0x647, 0x648 };
+ 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
- 0x136, 0x236, 0x336, 0x836, 0x936 };
+ 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
+#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
static const u16 NCT6779_REG_CRITICAL_PWM[] = {
- 0x137, 0x237, 0x337, 0x837, 0x937 };
+ 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
@@ -449,6 +503,122 @@ static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1]
static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
+/* NCT6791 specific data */
+
+#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
+
+static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
+ 0x459, 0x45A, 0x45B, 0x568, 0x45D };
+
+static const s8 NCT6791_ALARM_BITS[] = {
+ 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
+ 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
+ -1, /* unused */
+ 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
+ -1, -1, /* unused */
+ 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
+ 12, 9 }; /* intrusion0, intrusion1 */
+
+
+/* NCT6102D/NCT6106D specific data */
+
+#define NCT6106_REG_VBAT 0x318
+#define NCT6106_REG_DIODE 0x319
+#define NCT6106_DIODE_MASK 0x01
+
+static const u16 NCT6106_REG_IN_MAX[] = {
+ 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
+static const u16 NCT6106_REG_IN_MIN[] = {
+ 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
+static const u16 NCT6106_REG_IN[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
+
+static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
+static const u16 NCT6106_REG_TEMP_HYST[] = {
+ 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
+static const u16 NCT6106_REG_TEMP_OVER[] = {
+ 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
+static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
+ 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
+static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
+ 0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
+static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
+static const u16 NCT6106_REG_TEMP_CONFIG[] = {
+ 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
+
+static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
+static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
+static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
+static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
+
+static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
+static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
+static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
+static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
+static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
+static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
+static const u16 NCT6106_REG_TEMP_SOURCE[] = {
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
+
+static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
+static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
+ 0x11b, 0x12b, 0x13b };
+
+static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
+#define NCT6106_CRITICAL_PWM_ENABLE_MASK 0x10
+static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
+
+static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
+static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
+static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
+static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
+static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
+static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
+
+static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
+
+static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
+static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
+static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
+static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
+
+static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
+static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
+
+static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
+ 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
+
+static const s8 NCT6106_ALARM_BITS[] = {
+ 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
+ 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
+ -1, /* unused */
+ 32, 33, 34, -1, -1, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
+ 48, -1 /* intrusion0, intrusion1 */
+};
+
+static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
+ 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
+
+static const s8 NCT6106_BEEP_BITS[] = {
+ 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
+ 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
+ 32, /* global beep enable */
+ 24, 25, 26, 27, 28, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
+ 34, -1 /* intrusion0, intrusion1 */
+};
+
+static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
+ = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
+
+static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
+ = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
+
static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
{
if (mode == 0 && pwm == 255)
@@ -550,13 +720,18 @@ static inline u8 in_to_reg(u32 val, u8 nr)
struct nct6775_data {
int addr; /* IO base of hw monitor block */
+ int sioreg; /* SIO register address */
enum kinds kind;
const char *name;
struct device *hwmon_dev;
+ struct attribute_group *group_in;
+ struct attribute_group *group_fan;
+ struct attribute_group *group_temp;
+ struct attribute_group *group_pwm;
- u16 reg_temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
- * 3=temp_crit
+ u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+ * 3=temp_crit, 4=temp_lcrit
*/
u8 temp_src[NUM_TEMP];
u16 reg_temp_config[NUM_TEMP];
@@ -566,8 +741,10 @@ struct nct6775_data {
u16 REG_CONFIG;
u16 REG_VBAT;
u16 REG_DIODE;
+ u8 DIODE_MASK;
const s8 *ALARM_BITS;
+ const s8 *BEEP_BITS;
const u16 *REG_VIN;
const u16 *REG_IN_MINMAX[2];
@@ -577,6 +754,7 @@ struct nct6775_data {
const u16 *REG_FAN_MODE;
const u16 *REG_FAN_MIN;
const u16 *REG_FAN_PULSES;
+ const u16 *FAN_PULSE_SHIFT;
const u16 *REG_FAN_TIME[3];
const u16 *REG_TOLERANCE_H;
@@ -590,6 +768,10 @@ struct nct6775_data {
*/
const u16 *REG_PWM_READ;
+ const u16 *REG_CRITICAL_PWM_ENABLE;
+ u8 CRITICAL_PWM_ENABLE_MASK;
+ const u16 *REG_CRITICAL_PWM;
+
const u16 *REG_AUTO_TEMP;
const u16 *REG_AUTO_PWM;
@@ -604,6 +786,7 @@ struct nct6775_data {
const u16 *REG_TEMP_OFFSET;
const u16 *REG_ALARM;
+ const u16 *REG_BEEP;
unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
@@ -616,26 +799,30 @@ struct nct6775_data {
u8 bank; /* current register bank */
u8 in_num; /* number of in inputs we have */
u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
- unsigned int rpm[5];
- u16 fan_min[5];
- u8 fan_pulses[5];
- u8 fan_div[5];
+ unsigned int rpm[NUM_FAN];
+ u16 fan_min[NUM_FAN];
+ u8 fan_pulses[NUM_FAN];
+ u8 fan_div[NUM_FAN];
u8 has_pwm;
u8 has_fan; /* some fan inputs can be disabled */
u8 has_fan_min; /* some fans don't have min register */
bool has_fan_div;
- u8 num_temp_alarms; /* 2 or 3 */
+ u8 num_temp_alarms; /* 2, 3, or 6 */
+ u8 num_temp_beeps; /* 2, 3, or 6 */
u8 temp_fixed_num; /* 3 or 6 */
u8 temp_type[NUM_TEMP_FIXED];
s8 temp_offset[NUM_TEMP_FIXED];
- s16 temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
- * 3=temp_crit */
+ s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+ * 3=temp_crit, 4=temp_lcrit */
u64 alarms;
+ u64 beeps;
u8 pwm_num; /* number of pwm */
- u8 pwm_mode[5]; /* 1->DC variable voltage, 0->PWM variable duty cycle */
- enum pwm_enable pwm_enable[5];
+ u8 pwm_mode[NUM_FAN]; /* 1->DC variable voltage,
+ * 0->PWM variable duty cycle
+ */
+ enum pwm_enable pwm_enable[NUM_FAN];
/* 0->off
* 1->manual
* 2->thermal cruise mode (also called SmartFan I)
@@ -643,35 +830,37 @@ struct nct6775_data {
* 4->SmartFan III
* 5->enhanced variable thermal cruise (SmartFan IV)
*/
- u8 pwm[7][5]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
- * [3]=pwm_max, [4]=pwm_step,
- * [5]=weight_duty_step, [6]=weight_duty_base
- */
+ u8 pwm[7][NUM_FAN]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
+ * [3]=pwm_max, [4]=pwm_step,
+ * [5]=weight_duty_step, [6]=weight_duty_base
+ */
- u8 target_temp[5];
+ u8 target_temp[NUM_FAN];
u8 target_temp_mask;
- u32 target_speed[5];
- u32 target_speed_tolerance[5];
+ u32 target_speed[NUM_FAN];
+ u32 target_speed_tolerance[NUM_FAN];
u8 speed_tolerance_limit;
- u8 temp_tolerance[2][5];
+ u8 temp_tolerance[2][NUM_FAN];
u8 tolerance_mask;
- u8 fan_time[3][5]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
+ u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
/* Automatic fan speed control registers */
int auto_pwm_num;
- u8 auto_pwm[5][7];
- u8 auto_temp[5][7];
- u8 pwm_temp_sel[5];
- u8 pwm_weight_temp_sel[5];
- u8 weight_temp[3][5]; /* 0->temp_step, 1->temp_step_tol,
- * 2->temp_base
- */
+ u8 auto_pwm[NUM_FAN][7];
+ u8 auto_temp[NUM_FAN][7];
+ u8 pwm_temp_sel[NUM_FAN];
+ u8 pwm_weight_temp_sel[NUM_FAN];
+ u8 weight_temp[3][NUM_FAN]; /* 0->temp_step, 1->temp_step_tol,
+ * 2->temp_base
+ */
u8 vid;
u8 vrm;
+ bool have_vid;
+
u16 have_temp;
u16 have_temp_fixed;
u16 have_in;
@@ -688,9 +877,145 @@ struct nct6775_sio_data {
enum kinds kind;
};
+struct sensor_device_template {
+ struct device_attribute dev_attr;
+ union {
+ struct {
+ u8 nr;
+ u8 index;
+ } s;
+ int index;
+ } u;
+ bool s2; /* true if both index and nr are used */
+};
+
+struct sensor_device_attr_u {
+ union {
+ struct sensor_device_attribute a1;
+ struct sensor_device_attribute_2 a2;
+ } u;
+ char name[32];
+};
+
+#define __TEMPLATE_ATTR(_template, _mode, _show, _store) { \
+ .attr = {.name = _template, .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+}
+
+#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index) \
+ { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
+ .u.index = _index, \
+ .s2 = false }
+
+#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
+ _nr, _index) \
+ { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
+ .u.s.index = _index, \
+ .u.s.nr = _nr, \
+ .s2 = true }
+
+#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index) \
+static struct sensor_device_template sensor_dev_template_##_name \
+ = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, \
+ _index)
+
+#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store, \
+ _nr, _index) \
+static struct sensor_device_template sensor_dev_template_##_name \
+ = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store, \
+ _nr, _index)
+
+struct sensor_template_group {
+ struct sensor_device_template **templates;
+ umode_t (*is_visible)(struct kobject *, struct attribute *, int);
+ int base;
+};
+
+static struct attribute_group *
+nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+ int repeat)
+{
+ struct attribute_group *group;
+ struct sensor_device_attr_u *su;
+ struct sensor_device_attribute *a;
+ struct sensor_device_attribute_2 *a2;
+ struct attribute **attrs;
+ struct sensor_device_template **t;
+ int err, i, j, count;
+
+ if (repeat <= 0)
+ return ERR_PTR(-EINVAL);
+
+ t = tg->templates;
+ for (count = 0; *t; t++, count++)
+ ;
+
+ if (count == 0)
+ return ERR_PTR(-EINVAL);
+
+ group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
+ if (group == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
+ GFP_KERNEL);
+ if (attrs == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
+ GFP_KERNEL);
+ if (su == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ group->attrs = attrs;
+ group->is_visible = tg->is_visible;
+
+ for (i = 0; i < repeat; i++) {
+ t = tg->templates;
+ for (j = 0; *t != NULL; j++) {
+ snprintf(su->name, sizeof(su->name),
+ (*t)->dev_attr.attr.name, tg->base + i);
+ if ((*t)->s2) {
+ a2 = &su->u.a2;
+ a2->dev_attr.attr.name = su->name;
+ a2->nr = (*t)->u.s.nr + i;
+ a2->index = (*t)->u.s.index;
+ a2->dev_attr.attr.mode =
+ (*t)->dev_attr.attr.mode;
+ a2->dev_attr.show = (*t)->dev_attr.show;
+ a2->dev_attr.store = (*t)->dev_attr.store;
+ *attrs = &a2->dev_attr.attr;
+ } else {
+ a = &su->u.a1;
+ a->dev_attr.attr.name = su->name;
+ a->index = (*t)->u.index + i;
+ a->dev_attr.attr.mode =
+ (*t)->dev_attr.attr.mode;
+ a->dev_attr.show = (*t)->dev_attr.show;
+ a->dev_attr.store = (*t)->dev_attr.store;
+ *attrs = &a->dev_attr.attr;
+ }
+ attrs++;
+ su++;
+ t++;
+ }
+ }
+
+ err = sysfs_create_group(&dev->kobj, group);
+ if (err)
+ return ERR_PTR(-ENOMEM);
+
+ return group;
+}
+
static bool is_word_sized(struct nct6775_data *data, u16 reg)
{
switch (data->kind) {
+ case nct6106:
+ return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
+ reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
+ reg == 0x111 || reg == 0x121 || reg == 0x131;
case nct6775:
return (((reg & 0xff00) == 0x100 ||
(reg & 0xff00) == 0x200) &&
@@ -714,8 +1039,9 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
reg == 0x73 || reg == 0x75 || reg == 0x77;
case nct6779:
+ case nct6791:
return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
- ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x09) ||
+ ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
reg == 0x402 ||
reg == 0x63a || reg == 0x63c || reg == 0x63e ||
reg == 0x640 || reg == 0x642 ||
@@ -1056,15 +1382,17 @@ static void nct6775_update_pwm_limits(struct device *dev)
case nct6776:
data->auto_pwm[i][data->auto_pwm_num] = 0xff;
break;
+ case nct6106:
case nct6779:
+ case nct6791:
reg = nct6775_read_value(data,
- NCT6779_REG_CRITICAL_PWM_ENABLE[i]);
- if (reg & 1)
- data->auto_pwm[i][data->auto_pwm_num] =
- nct6775_read_value(data,
- NCT6779_REG_CRITICAL_PWM[i]);
+ data->REG_CRITICAL_PWM_ENABLE[i]);
+ if (reg & data->CRITICAL_PWM_ENABLE_MASK)
+ reg = nct6775_read_value(data,
+ data->REG_CRITICAL_PWM[i]);
else
- data->auto_pwm[i][data->auto_pwm_num] = 0xff;
+ reg = 0xff;
+ data->auto_pwm[i][data->auto_pwm_num] = reg;
break;
}
}
@@ -1110,7 +1438,8 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
data->fan_min[i] = nct6775_read_value(data,
data->REG_FAN_MIN[i]);
data->fan_pulses[i] =
- nct6775_read_value(data, data->REG_FAN_PULSES[i]);
+ (nct6775_read_value(data, data->REG_FAN_PULSES[i])
+ >> data->FAN_PULSE_SHIFT[i]) & 0x03;
nct6775_select_fan_div(dev, data, i, reg);
}
@@ -1143,6 +1472,15 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
data->alarms |= ((u64)alarm) << (i << 3);
}
+ data->beeps = 0;
+ for (i = 0; i < NUM_REG_BEEP; i++) {
+ u8 beep;
+ if (!data->REG_BEEP[i])
+ continue;
+ beep = nct6775_read_value(data, data->REG_BEEP[i]);
+ data->beeps |= ((u64)beep) << (i << 3);
+ }
+
data->last_updated = jiffies;
data->valid = true;
}
@@ -1230,224 +1568,138 @@ show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%u\n", alarm);
}
-static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in_reg, NULL, 0, 0);
-static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in_reg, NULL, 1, 0);
-static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in_reg, NULL, 2, 0);
-static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in_reg, NULL, 3, 0);
-static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in_reg, NULL, 4, 0);
-static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in_reg, NULL, 5, 0);
-static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in_reg, NULL, 6, 0);
-static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in_reg, NULL, 7, 0);
-static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in_reg, NULL, 8, 0);
-static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in_reg, NULL, 9, 0);
-static SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in_reg, NULL, 10, 0);
-static SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in_reg, NULL, 11, 0);
-static SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in_reg, NULL, 12, 0);
-static SENSOR_DEVICE_ATTR_2(in13_input, S_IRUGO, show_in_reg, NULL, 13, 0);
-static SENSOR_DEVICE_ATTR_2(in14_input, S_IRUGO, show_in_reg, NULL, 14, 0);
-
-static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
-static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
-static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
-static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
-static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
-static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
-static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
-static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
-static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9);
-static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10);
-static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 11);
-static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 12);
-static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 13);
-static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 14);
-
-static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 0, 1);
-static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 1, 1);
-static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 2, 1);
-static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 3, 1);
-static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 4, 1);
-static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 5, 1);
-static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 6, 1);
-static SENSOR_DEVICE_ATTR_2(in7_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 7, 1);
-static SENSOR_DEVICE_ATTR_2(in8_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 8, 1);
-static SENSOR_DEVICE_ATTR_2(in9_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 9, 1);
-static SENSOR_DEVICE_ATTR_2(in10_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 10, 1);
-static SENSOR_DEVICE_ATTR_2(in11_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 11, 1);
-static SENSOR_DEVICE_ATTR_2(in12_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 12, 1);
-static SENSOR_DEVICE_ATTR_2(in13_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 13, 1);
-static SENSOR_DEVICE_ATTR_2(in14_min, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 14, 1);
-
-static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 0, 2);
-static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 1, 2);
-static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 2, 2);
-static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 3, 2);
-static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 4, 2);
-static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 5, 2);
-static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 6, 2);
-static SENSOR_DEVICE_ATTR_2(in7_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 7, 2);
-static SENSOR_DEVICE_ATTR_2(in8_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 8, 2);
-static SENSOR_DEVICE_ATTR_2(in9_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 9, 2);
-static SENSOR_DEVICE_ATTR_2(in10_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 10, 2);
-static SENSOR_DEVICE_ATTR_2(in11_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 11, 2);
-static SENSOR_DEVICE_ATTR_2(in12_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 12, 2);
-static SENSOR_DEVICE_ATTR_2(in13_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 13, 2);
-static SENSOR_DEVICE_ATTR_2(in14_max, S_IWUSR | S_IRUGO, show_in_reg,
- store_in_reg, 14, 2);
-
-static struct attribute *nct6775_attributes_in[15][5] = {
- {
- &sensor_dev_attr_in0_input.dev_attr.attr,
- &sensor_dev_attr_in0_min.dev_attr.attr,
- &sensor_dev_attr_in0_max.dev_attr.attr,
- &sensor_dev_attr_in0_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in1_input.dev_attr.attr,
- &sensor_dev_attr_in1_min.dev_attr.attr,
- &sensor_dev_attr_in1_max.dev_attr.attr,
- &sensor_dev_attr_in1_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in2_input.dev_attr.attr,
- &sensor_dev_attr_in2_min.dev_attr.attr,
- &sensor_dev_attr_in2_max.dev_attr.attr,
- &sensor_dev_attr_in2_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in3_input.dev_attr.attr,
- &sensor_dev_attr_in3_min.dev_attr.attr,
- &sensor_dev_attr_in3_max.dev_attr.attr,
- &sensor_dev_attr_in3_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in4_input.dev_attr.attr,
- &sensor_dev_attr_in4_min.dev_attr.attr,
- &sensor_dev_attr_in4_max.dev_attr.attr,
- &sensor_dev_attr_in4_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in5_input.dev_attr.attr,
- &sensor_dev_attr_in5_min.dev_attr.attr,
- &sensor_dev_attr_in5_max.dev_attr.attr,
- &sensor_dev_attr_in5_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in6_input.dev_attr.attr,
- &sensor_dev_attr_in6_min.dev_attr.attr,
- &sensor_dev_attr_in6_max.dev_attr.attr,
- &sensor_dev_attr_in6_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in7_input.dev_attr.attr,
- &sensor_dev_attr_in7_min.dev_attr.attr,
- &sensor_dev_attr_in7_max.dev_attr.attr,
- &sensor_dev_attr_in7_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in8_input.dev_attr.attr,
- &sensor_dev_attr_in8_min.dev_attr.attr,
- &sensor_dev_attr_in8_max.dev_attr.attr,
- &sensor_dev_attr_in8_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in9_input.dev_attr.attr,
- &sensor_dev_attr_in9_min.dev_attr.attr,
- &sensor_dev_attr_in9_max.dev_attr.attr,
- &sensor_dev_attr_in9_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in10_input.dev_attr.attr,
- &sensor_dev_attr_in10_min.dev_attr.attr,
- &sensor_dev_attr_in10_max.dev_attr.attr,
- &sensor_dev_attr_in10_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in11_input.dev_attr.attr,
- &sensor_dev_attr_in11_min.dev_attr.attr,
- &sensor_dev_attr_in11_max.dev_attr.attr,
- &sensor_dev_attr_in11_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in12_input.dev_attr.attr,
- &sensor_dev_attr_in12_min.dev_attr.attr,
- &sensor_dev_attr_in12_max.dev_attr.attr,
- &sensor_dev_attr_in12_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in13_input.dev_attr.attr,
- &sensor_dev_attr_in13_min.dev_attr.attr,
- &sensor_dev_attr_in13_max.dev_attr.attr,
- &sensor_dev_attr_in13_alarm.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_in14_input.dev_attr.attr,
- &sensor_dev_attr_in14_min.dev_attr.attr,
- &sensor_dev_attr_in14_max.dev_attr.attr,
- &sensor_dev_attr_in14_alarm.dev_attr.attr,
- NULL
- },
+static ssize_t
+show_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct nct6775_data *data = nct6775_update_device(dev);
+ int nr = data->BEEP_BITS[sattr->index];
+
+ return sprintf(buf, "%u\n",
+ (unsigned int)((data->beeps >> nr) & 0x01));
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ int nr = data->BEEP_BITS[sattr->index];
+ int regindex = nr >> 3;
+ unsigned long val;
+
+ int err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+ if (val > 1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->beeps |= (1ULL << nr);
+ else
+ data->beeps &= ~(1ULL << nr);
+ nct6775_write_value(data, data->REG_BEEP[regindex],
+ (data->beeps >> (regindex << 3)) & 0xff);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct nct6775_data *data = nct6775_update_device(dev);
+ unsigned int beep = 0;
+ int nr;
+
+ /*
+ * For temperatures, there is no fixed mapping from registers to beep
+ * enable bits. Beep enable bits are determined by the temperature
+ * source mapping.
+ */
+ nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
+ if (nr >= 0) {
+ int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
+ beep = (data->beeps >> bit) & 0x01;
+ }
+ return sprintf(buf, "%u\n", beep);
+}
+
+static ssize_t
+store_temp_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ int nr, bit, regindex;
+ unsigned long val;
+
+ int err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+ if (val > 1)
+ return -EINVAL;
+
+ nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
+ if (nr < 0)
+ return -ENODEV;
+
+ bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
+ regindex = bit >> 3;
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->beeps |= (1ULL << bit);
+ else
+ data->beeps &= ~(1ULL << bit);
+ nct6775_write_value(data, data->REG_BEEP[regindex],
+ (data->beeps >> (regindex << 3)) & 0xff);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static umode_t nct6775_in_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ int in = index / 5; /* voltage index */
+
+ if (!(data->have_in & (1 << in)))
+ return 0;
+
+ return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
+SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
+SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
+ 0);
+SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 0, 1);
+SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 0, 2);
+
+/*
+ * nct6775_in_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_in_template[] = {
+ &sensor_dev_template_in_input,
+ &sensor_dev_template_in_alarm,
+ &sensor_dev_template_in_beep,
+ &sensor_dev_template_in_min,
+ &sensor_dev_template_in_max,
+ NULL
};
-static const struct attribute_group nct6775_group_in[15] = {
- { .attrs = nct6775_attributes_in[0] },
- { .attrs = nct6775_attributes_in[1] },
- { .attrs = nct6775_attributes_in[2] },
- { .attrs = nct6775_attributes_in[3] },
- { .attrs = nct6775_attributes_in[4] },
- { .attrs = nct6775_attributes_in[5] },
- { .attrs = nct6775_attributes_in[6] },
- { .attrs = nct6775_attributes_in[7] },
- { .attrs = nct6775_attributes_in[8] },
- { .attrs = nct6775_attributes_in[9] },
- { .attrs = nct6775_attributes_in[10] },
- { .attrs = nct6775_attributes_in[11] },
- { .attrs = nct6775_attributes_in[12] },
- { .attrs = nct6775_attributes_in[13] },
- { .attrs = nct6775_attributes_in[14] },
+static struct sensor_template_group nct6775_in_template_group = {
+ .templates = nct6775_attributes_in_template,
+ .is_visible = nct6775_in_is_visible,
};
static ssize_t
@@ -1592,6 +1844,7 @@ store_fan_pulses(struct device *dev, struct device_attribute *attr,
int nr = sattr->index;
unsigned long val;
int err;
+ u8 reg;
err = kstrtoul(buf, 10, &val);
if (err < 0)
@@ -1602,60 +1855,68 @@ store_fan_pulses(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
data->fan_pulses[nr] = val & 3;
- nct6775_write_value(data, data->REG_FAN_PULSES[nr], val & 3);
+ reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
+ reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
+ reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
+ nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
mutex_unlock(&data->update_lock);
return count;
}
-static struct sensor_device_attribute sda_fan_input[] = {
- SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
- SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
- SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
- SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
- SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
-};
+static umode_t nct6775_fan_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ int fan = index / 6; /* fan index */
+ int nr = index % 6; /* attribute index */
-static struct sensor_device_attribute sda_fan_alarm[] = {
- SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE),
- SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 1),
- SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 2),
- SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 3),
- SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 4),
-};
+ if (!(data->has_fan & (1 << fan)))
+ return 0;
-static struct sensor_device_attribute sda_fan_min[] = {
- SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
- store_fan_min, 0),
- SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
- store_fan_min, 1),
- SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
- store_fan_min, 2),
- SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
- store_fan_min, 3),
- SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
- store_fan_min, 4),
-};
+ if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
+ return 0;
+ if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
+ return 0;
+ if (nr == 4 && !(data->has_fan_min & (1 << fan)))
+ return 0;
+ if (nr == 5 && data->kind != nct6775)
+ return 0;
+
+ return attr->mode;
+}
-static struct sensor_device_attribute sda_fan_pulses[] = {
- SENSOR_ATTR(fan1_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
- store_fan_pulses, 0),
- SENSOR_ATTR(fan2_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
- store_fan_pulses, 1),
- SENSOR_ATTR(fan3_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
- store_fan_pulses, 2),
- SENSOR_ATTR(fan4_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
- store_fan_pulses, 3),
- SENSOR_ATTR(fan5_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
- store_fan_pulses, 4),
+SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
+SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
+ FAN_ALARM_BASE);
+SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
+ store_beep, FAN_ALARM_BASE);
+SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
+ store_fan_pulses, 0);
+SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
+ store_fan_min, 0);
+SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
+
+/*
+ * nct6775_fan_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_fan_template[] = {
+ &sensor_dev_template_fan_input,
+ &sensor_dev_template_fan_alarm, /* 1 */
+ &sensor_dev_template_fan_beep, /* 2 */
+ &sensor_dev_template_fan_pulses,
+ &sensor_dev_template_fan_min, /* 4 */
+ &sensor_dev_template_fan_div, /* 5 */
+ NULL
};
-static struct sensor_device_attribute sda_fan_div[] = {
- SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
- SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
- SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
- SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
- SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
+static struct sensor_template_group nct6775_fan_template_group = {
+ .templates = nct6775_attributes_fan_template,
+ .is_visible = nct6775_fan_is_visible,
+ .base = 1,
};
static ssize_t
@@ -1752,7 +2013,7 @@ store_temp_type(struct device *dev, struct device_attribute *attr,
int nr = sattr->index;
unsigned long val;
int err;
- u8 vbat, diode, bit;
+ u8 vbat, diode, vbit, dbit;
err = kstrtoul(buf, 10, &val);
if (err < 0)
@@ -1764,16 +2025,17 @@ store_temp_type(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
data->temp_type[nr] = val;
- vbat = nct6775_read_value(data, data->REG_VBAT) & ~(0x02 << nr);
- diode = nct6775_read_value(data, data->REG_DIODE) & ~(0x02 << nr);
- bit = 0x02 << nr;
+ vbit = 0x02 << nr;
+ dbit = data->DIODE_MASK << nr;
+ vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
+ diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
switch (val) {
case 1: /* CPU diode (diode, current mode) */
- vbat |= bit;
- diode |= bit;
+ vbat |= vbit;
+ diode |= dbit;
break;
case 3: /* diode, voltage mode */
- vbat |= bit;
+ vbat |= dbit;
break;
case 4: /* thermistor */
break;
@@ -1785,142 +2047,83 @@ store_temp_type(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute_2 sda_temp_input[] = {
- SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
- SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0),
- SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0),
- SENSOR_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0),
- SENSOR_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0),
- SENSOR_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0),
- SENSOR_ATTR_2(temp7_input, S_IRUGO, show_temp, NULL, 6, 0),
- SENSOR_ATTR_2(temp8_input, S_IRUGO, show_temp, NULL, 7, 0),
- SENSOR_ATTR_2(temp9_input, S_IRUGO, show_temp, NULL, 8, 0),
- SENSOR_ATTR_2(temp10_input, S_IRUGO, show_temp, NULL, 9, 0),
-};
+static umode_t nct6775_temp_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ int temp = index / 10; /* temp index */
+ int nr = index % 10; /* attribute index */
-static struct sensor_device_attribute sda_temp_label[] = {
- SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
- SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
- SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
- SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
- SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
- SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
- SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
- SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
- SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
- SENSOR_ATTR(temp10_label, S_IRUGO, show_temp_label, NULL, 9),
-};
+ if (!(data->have_temp & (1 << temp)))
+ return 0;
-static struct sensor_device_attribute_2 sda_temp_max[] = {
- SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 0, 1),
- SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 1, 1),
- SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 2, 1),
- SENSOR_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 3, 1),
- SENSOR_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 4, 1),
- SENSOR_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 5, 1),
- SENSOR_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 6, 1),
- SENSOR_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 7, 1),
- SENSOR_ATTR_2(temp9_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 8, 1),
- SENSOR_ATTR_2(temp10_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 9, 1),
-};
+ if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
+ return 0; /* alarm */
-static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
- SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 0, 2),
- SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 1, 2),
- SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 2, 2),
- SENSOR_ATTR_2(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 3, 2),
- SENSOR_ATTR_2(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 4, 2),
- SENSOR_ATTR_2(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 5, 2),
- SENSOR_ATTR_2(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 6, 2),
- SENSOR_ATTR_2(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 7, 2),
- SENSOR_ATTR_2(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 8, 2),
- SENSOR_ATTR_2(temp10_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 9, 2),
-};
+ if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
+ return 0; /* beep */
-static struct sensor_device_attribute_2 sda_temp_crit[] = {
- SENSOR_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 0, 3),
- SENSOR_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 1, 3),
- SENSOR_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 2, 3),
- SENSOR_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 3, 3),
- SENSOR_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 4, 3),
- SENSOR_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 5, 3),
- SENSOR_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 6, 3),
- SENSOR_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 7, 3),
- SENSOR_ATTR_2(temp9_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 8, 3),
- SENSOR_ATTR_2(temp10_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
- 9, 3),
-};
+ if (nr == 4 && !data->reg_temp[1][temp]) /* max */
+ return 0;
-static struct sensor_device_attribute sda_temp_offset[] = {
- SENSOR_ATTR(temp1_offset, S_IRUGO | S_IWUSR, show_temp_offset,
- store_temp_offset, 0),
- SENSOR_ATTR(temp2_offset, S_IRUGO | S_IWUSR, show_temp_offset,
- store_temp_offset, 1),
- SENSOR_ATTR(temp3_offset, S_IRUGO | S_IWUSR, show_temp_offset,
- store_temp_offset, 2),
- SENSOR_ATTR(temp4_offset, S_IRUGO | S_IWUSR, show_temp_offset,
- store_temp_offset, 3),
- SENSOR_ATTR(temp5_offset, S_IRUGO | S_IWUSR, show_temp_offset,
- store_temp_offset, 4),
- SENSOR_ATTR(temp6_offset, S_IRUGO | S_IWUSR, show_temp_offset,
- store_temp_offset, 5),
-};
+ if (nr == 5 && !data->reg_temp[2][temp]) /* max_hyst */
+ return 0;
+
+ if (nr == 6 && !data->reg_temp[3][temp]) /* crit */
+ return 0;
+
+ if (nr == 7 && !data->reg_temp[4][temp]) /* lcrit */
+ return 0;
+
+ /* offset and type only apply to fixed sensors */
+ if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
+ return 0;
-static struct sensor_device_attribute sda_temp_type[] = {
- SENSOR_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
- store_temp_type, 0),
- SENSOR_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
- store_temp_type, 1),
- SENSOR_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
- store_temp_type, 2),
- SENSOR_ATTR(temp4_type, S_IRUGO | S_IWUSR, show_temp_type,
- store_temp_type, 3),
- SENSOR_ATTR(temp5_type, S_IRUGO | S_IWUSR, show_temp_type,
- store_temp_type, 4),
- SENSOR_ATTR(temp6_type, S_IRUGO | S_IWUSR, show_temp_type,
- store_temp_type, 5),
+ return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
+SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
+SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0, 1);
+SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
+ show_temp, store_temp, 0, 2);
+SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0, 3);
+SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0, 4);
+SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
+ show_temp_offset, store_temp_offset, 0);
+SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
+ store_temp_type, 0);
+SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
+SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
+ store_temp_beep, 0);
+
+/*
+ * nct6775_temp_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_temp_template[] = {
+ &sensor_dev_template_temp_input,
+ &sensor_dev_template_temp_label,
+ &sensor_dev_template_temp_alarm, /* 2 */
+ &sensor_dev_template_temp_beep, /* 3 */
+ &sensor_dev_template_temp_max, /* 4 */
+ &sensor_dev_template_temp_max_hyst, /* 5 */
+ &sensor_dev_template_temp_crit, /* 6 */
+ &sensor_dev_template_temp_lcrit, /* 7 */
+ &sensor_dev_template_temp_offset, /* 8 */
+ &sensor_dev_template_temp_type, /* 9 */
+ NULL
};
-static struct sensor_device_attribute sda_temp_alarm[] = {
- SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
- SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
- SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
- SENSOR_ATTR(temp4_alarm, S_IRUGO, show_temp_alarm, NULL, 3),
- SENSOR_ATTR(temp5_alarm, S_IRUGO, show_temp_alarm, NULL, 4),
- SENSOR_ATTR(temp6_alarm, S_IRUGO, show_temp_alarm, NULL, 5),
- SENSOR_ATTR(temp7_alarm, S_IRUGO, show_temp_alarm, NULL, 6),
- SENSOR_ATTR(temp8_alarm, S_IRUGO, show_temp_alarm, NULL, 7),
- SENSOR_ATTR(temp9_alarm, S_IRUGO, show_temp_alarm, NULL, 8),
- SENSOR_ATTR(temp10_alarm, S_IRUGO, show_temp_alarm, NULL, 9),
+static struct sensor_template_group nct6775_temp_template_group = {
+ .templates = nct6775_attributes_temp_template,
+ .is_visible = nct6775_temp_is_visible,
+ .base = 1,
};
static ssize_t
@@ -2422,77 +2625,19 @@ store_speed_tolerance(struct device *dev, struct device_attribute *attr,
return count;
}
-static SENSOR_DEVICE_ATTR_2(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 0);
-
-static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
- store_pwm_mode, 0);
-static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
- store_pwm_mode, 1);
-static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
- store_pwm_mode, 2);
-static SENSOR_DEVICE_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
- store_pwm_mode, 3);
-static SENSOR_DEVICE_ATTR(pwm5_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
- store_pwm_mode, 4);
-
-static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
- store_pwm_enable, 0);
-static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
- store_pwm_enable, 1);
-static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
- store_pwm_enable, 2);
-static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
- store_pwm_enable, 3);
-static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
- store_pwm_enable, 4);
-
-static SENSOR_DEVICE_ATTR(pwm1_temp_sel, S_IWUSR | S_IRUGO,
- show_pwm_temp_sel, store_pwm_temp_sel, 0);
-static SENSOR_DEVICE_ATTR(pwm2_temp_sel, S_IWUSR | S_IRUGO,
- show_pwm_temp_sel, store_pwm_temp_sel, 1);
-static SENSOR_DEVICE_ATTR(pwm3_temp_sel, S_IWUSR | S_IRUGO,
- show_pwm_temp_sel, store_pwm_temp_sel, 2);
-static SENSOR_DEVICE_ATTR(pwm4_temp_sel, S_IWUSR | S_IRUGO,
- show_pwm_temp_sel, store_pwm_temp_sel, 3);
-static SENSOR_DEVICE_ATTR(pwm5_temp_sel, S_IWUSR | S_IRUGO,
- show_pwm_temp_sel, store_pwm_temp_sel, 4);
-
-static SENSOR_DEVICE_ATTR(pwm1_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
- store_target_temp, 0);
-static SENSOR_DEVICE_ATTR(pwm2_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
- store_target_temp, 1);
-static SENSOR_DEVICE_ATTR(pwm3_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
- store_target_temp, 2);
-static SENSOR_DEVICE_ATTR(pwm4_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
- store_target_temp, 3);
-static SENSOR_DEVICE_ATTR(pwm5_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
- store_target_temp, 4);
-
-static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, show_target_speed,
- store_target_speed, 0);
-static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO, show_target_speed,
- store_target_speed, 1);
-static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO, show_target_speed,
- store_target_speed, 2);
-static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO, show_target_speed,
- store_target_speed, 3);
-static SENSOR_DEVICE_ATTR(fan5_target, S_IWUSR | S_IRUGO, show_target_speed,
- store_target_speed, 4);
-
-static SENSOR_DEVICE_ATTR(fan1_tolerance, S_IWUSR | S_IRUGO,
- show_speed_tolerance, store_speed_tolerance, 0);
-static SENSOR_DEVICE_ATTR(fan2_tolerance, S_IWUSR | S_IRUGO,
- show_speed_tolerance, store_speed_tolerance, 1);
-static SENSOR_DEVICE_ATTR(fan3_tolerance, S_IWUSR | S_IRUGO,
- show_speed_tolerance, store_speed_tolerance, 2);
-static SENSOR_DEVICE_ATTR(fan4_tolerance, S_IWUSR | S_IRUGO,
- show_speed_tolerance, store_speed_tolerance, 3);
-static SENSOR_DEVICE_ATTR(fan5_tolerance, S_IWUSR | S_IRUGO,
- show_speed_tolerance, store_speed_tolerance, 4);
+SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
+SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 0);
+SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 0);
+SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
+ show_pwm_temp_sel, store_pwm_temp_sel, 0);
+SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
+ show_target_temp, store_target_temp, 0);
+SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
+ show_target_speed, store_target_speed, 0);
+SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
+ show_speed_tolerance, store_speed_tolerance, 0);
/* Smart Fan registers */
@@ -2531,79 +2676,18 @@ store_weight_temp(struct device *dev, struct device_attribute *attr,
return count;
}
-static SENSOR_DEVICE_ATTR(pwm1_weight_temp_sel, S_IWUSR | S_IRUGO,
- show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
- 0);
-static SENSOR_DEVICE_ATTR(pwm2_weight_temp_sel, S_IWUSR | S_IRUGO,
- show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
- 1);
-static SENSOR_DEVICE_ATTR(pwm3_weight_temp_sel, S_IWUSR | S_IRUGO,
- show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
- 2);
-static SENSOR_DEVICE_ATTR(pwm4_weight_temp_sel, S_IWUSR | S_IRUGO,
- show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
- 3);
-static SENSOR_DEVICE_ATTR(pwm5_weight_temp_sel, S_IWUSR | S_IRUGO,
- show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
- 4);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 4, 0);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_tol, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_tol, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_tol, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_tol, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_tol, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 4, 1);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_base, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 0, 2);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_base, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 1, 2);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_base, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 2, 2);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_base, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 3, 2);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_base, S_IWUSR | S_IRUGO,
- show_weight_temp, store_weight_temp, 4, 2);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_duty_step, S_IWUSR | S_IRUGO,
- show_pwm, store_pwm, 0, 5);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_duty_step, S_IWUSR | S_IRUGO,
- show_pwm, store_pwm, 1, 5);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_duty_step, S_IWUSR | S_IRUGO,
- show_pwm, store_pwm, 2, 5);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_duty_step, S_IWUSR | S_IRUGO,
- show_pwm, store_pwm, 3, 5);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_duty_step, S_IWUSR | S_IRUGO,
- show_pwm, store_pwm, 4, 5);
-
-/* duty_base is not supported on all chips */
-static struct sensor_device_attribute_2 sda_weight_duty_base[] = {
- SENSOR_ATTR_2(pwm1_weight_duty_base, S_IWUSR | S_IRUGO,
- show_pwm, store_pwm, 0, 6),
- SENSOR_ATTR_2(pwm2_weight_duty_base, S_IWUSR | S_IRUGO,
- show_pwm, store_pwm, 1, 6),
- SENSOR_ATTR_2(pwm3_weight_duty_base, S_IWUSR | S_IRUGO,
- show_pwm, store_pwm, 2, 6),
- SENSOR_ATTR_2(pwm4_weight_duty_base, S_IWUSR | S_IRUGO,
- show_pwm, store_pwm, 3, 6),
- SENSOR_ATTR_2(pwm5_weight_duty_base, S_IWUSR | S_IRUGO,
- show_pwm, store_pwm, 4, 6),
-};
+SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
+ show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
+ S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
+ S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
+ S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
+SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
+ S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
+SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
+ S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
static ssize_t
show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
@@ -2651,227 +2735,6 @@ show_name(struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-static SENSOR_DEVICE_ATTR_2(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
- store_fan_time, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
- store_fan_time, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
- store_fan_time, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
- store_fan_time, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
- store_fan_time, 4, 0);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
- store_fan_time, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
- store_fan_time, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
- store_fan_time, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
- store_fan_time, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
- store_fan_time, 4, 1);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_step_down_time, S_IWUSR | S_IRUGO,
- show_fan_time, store_fan_time, 0, 2);
-static SENSOR_DEVICE_ATTR_2(pwm2_step_down_time, S_IWUSR | S_IRUGO,
- show_fan_time, store_fan_time, 1, 2);
-static SENSOR_DEVICE_ATTR_2(pwm3_step_down_time, S_IWUSR | S_IRUGO,
- show_fan_time, store_fan_time, 2, 2);
-static SENSOR_DEVICE_ATTR_2(pwm4_step_down_time, S_IWUSR | S_IRUGO,
- show_fan_time, store_fan_time, 3, 2);
-static SENSOR_DEVICE_ATTR_2(pwm5_step_down_time, S_IWUSR | S_IRUGO,
- show_fan_time, store_fan_time, 4, 2);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_start, S_IWUSR | S_IRUGO, show_pwm,
- store_pwm, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_start, S_IWUSR | S_IRUGO, show_pwm,
- store_pwm, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_start, S_IWUSR | S_IRUGO, show_pwm,
- store_pwm, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_start, S_IWUSR | S_IRUGO, show_pwm,
- store_pwm, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_start, S_IWUSR | S_IRUGO, show_pwm,
- store_pwm, 4, 1);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_floor, S_IWUSR | S_IRUGO, show_pwm,
- store_pwm, 0, 2);
-static SENSOR_DEVICE_ATTR_2(pwm2_floor, S_IWUSR | S_IRUGO, show_pwm,
- store_pwm, 1, 2);
-static SENSOR_DEVICE_ATTR_2(pwm3_floor, S_IWUSR | S_IRUGO, show_pwm,
- store_pwm, 2, 2);
-static SENSOR_DEVICE_ATTR_2(pwm4_floor, S_IWUSR | S_IRUGO, show_pwm,
- store_pwm, 3, 2);
-static SENSOR_DEVICE_ATTR_2(pwm5_floor, S_IWUSR | S_IRUGO, show_pwm,
- store_pwm, 4, 2);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_temp_tolerance, S_IWUSR | S_IRUGO,
- show_temp_tolerance, store_temp_tolerance, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2_temp_tolerance, S_IWUSR | S_IRUGO,
- show_temp_tolerance, store_temp_tolerance, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3_temp_tolerance, S_IWUSR | S_IRUGO,
- show_temp_tolerance, store_temp_tolerance, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4_temp_tolerance, S_IWUSR | S_IRUGO,
- show_temp_tolerance, store_temp_tolerance, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5_temp_tolerance, S_IWUSR | S_IRUGO,
- show_temp_tolerance, store_temp_tolerance, 4, 0);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_crit_temp_tolerance, S_IWUSR | S_IRUGO,
- show_temp_tolerance, store_temp_tolerance, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_crit_temp_tolerance, S_IWUSR | S_IRUGO,
- show_temp_tolerance, store_temp_tolerance, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_crit_temp_tolerance, S_IWUSR | S_IRUGO,
- show_temp_tolerance, store_temp_tolerance, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_crit_temp_tolerance, S_IWUSR | S_IRUGO,
- show_temp_tolerance, store_temp_tolerance, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_crit_temp_tolerance, S_IWUSR | S_IRUGO,
- show_temp_tolerance, store_temp_tolerance, 4, 1);
-
-/* pwm_max is not supported on all chips */
-static struct sensor_device_attribute_2 sda_pwm_max[] = {
- SENSOR_ATTR_2(pwm1_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
- 0, 3),
- SENSOR_ATTR_2(pwm2_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
- 1, 3),
- SENSOR_ATTR_2(pwm3_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
- 2, 3),
- SENSOR_ATTR_2(pwm4_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
- 3, 3),
- SENSOR_ATTR_2(pwm5_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
- 4, 3),
-};
-
-/* pwm_step is not supported on all chips */
-static struct sensor_device_attribute_2 sda_pwm_step[] = {
- SENSOR_ATTR_2(pwm1_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 4),
- SENSOR_ATTR_2(pwm2_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 4),
- SENSOR_ATTR_2(pwm3_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 4),
- SENSOR_ATTR_2(pwm4_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 4),
- SENSOR_ATTR_2(pwm5_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 4),
-};
-
-static struct attribute *nct6775_attributes_pwm[5][20] = {
- {
- &sensor_dev_attr_pwm1.dev_attr.attr,
- &sensor_dev_attr_pwm1_mode.dev_attr.attr,
- &sensor_dev_attr_pwm1_enable.dev_attr.attr,
- &sensor_dev_attr_pwm1_temp_sel.dev_attr.attr,
- &sensor_dev_attr_pwm1_temp_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm1_crit_temp_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm1_target_temp.dev_attr.attr,
- &sensor_dev_attr_fan1_target.dev_attr.attr,
- &sensor_dev_attr_fan1_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm1_stop_time.dev_attr.attr,
- &sensor_dev_attr_pwm1_step_up_time.dev_attr.attr,
- &sensor_dev_attr_pwm1_step_down_time.dev_attr.attr,
- &sensor_dev_attr_pwm1_start.dev_attr.attr,
- &sensor_dev_attr_pwm1_floor.dev_attr.attr,
- &sensor_dev_attr_pwm1_weight_temp_sel.dev_attr.attr,
- &sensor_dev_attr_pwm1_weight_temp_step.dev_attr.attr,
- &sensor_dev_attr_pwm1_weight_temp_step_tol.dev_attr.attr,
- &sensor_dev_attr_pwm1_weight_temp_step_base.dev_attr.attr,
- &sensor_dev_attr_pwm1_weight_duty_step.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_pwm2.dev_attr.attr,
- &sensor_dev_attr_pwm2_mode.dev_attr.attr,
- &sensor_dev_attr_pwm2_enable.dev_attr.attr,
- &sensor_dev_attr_pwm2_temp_sel.dev_attr.attr,
- &sensor_dev_attr_pwm2_temp_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm2_crit_temp_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm2_target_temp.dev_attr.attr,
- &sensor_dev_attr_fan2_target.dev_attr.attr,
- &sensor_dev_attr_fan2_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm2_stop_time.dev_attr.attr,
- &sensor_dev_attr_pwm2_step_up_time.dev_attr.attr,
- &sensor_dev_attr_pwm2_step_down_time.dev_attr.attr,
- &sensor_dev_attr_pwm2_start.dev_attr.attr,
- &sensor_dev_attr_pwm2_floor.dev_attr.attr,
- &sensor_dev_attr_pwm2_weight_temp_sel.dev_attr.attr,
- &sensor_dev_attr_pwm2_weight_temp_step.dev_attr.attr,
- &sensor_dev_attr_pwm2_weight_temp_step_tol.dev_attr.attr,
- &sensor_dev_attr_pwm2_weight_temp_step_base.dev_attr.attr,
- &sensor_dev_attr_pwm2_weight_duty_step.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_pwm3.dev_attr.attr,
- &sensor_dev_attr_pwm3_mode.dev_attr.attr,
- &sensor_dev_attr_pwm3_enable.dev_attr.attr,
- &sensor_dev_attr_pwm3_temp_sel.dev_attr.attr,
- &sensor_dev_attr_pwm3_temp_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm3_crit_temp_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm3_target_temp.dev_attr.attr,
- &sensor_dev_attr_fan3_target.dev_attr.attr,
- &sensor_dev_attr_fan3_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm3_stop_time.dev_attr.attr,
- &sensor_dev_attr_pwm3_step_up_time.dev_attr.attr,
- &sensor_dev_attr_pwm3_step_down_time.dev_attr.attr,
- &sensor_dev_attr_pwm3_start.dev_attr.attr,
- &sensor_dev_attr_pwm3_floor.dev_attr.attr,
- &sensor_dev_attr_pwm3_weight_temp_sel.dev_attr.attr,
- &sensor_dev_attr_pwm3_weight_temp_step.dev_attr.attr,
- &sensor_dev_attr_pwm3_weight_temp_step_tol.dev_attr.attr,
- &sensor_dev_attr_pwm3_weight_temp_step_base.dev_attr.attr,
- &sensor_dev_attr_pwm3_weight_duty_step.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_pwm4.dev_attr.attr,
- &sensor_dev_attr_pwm4_mode.dev_attr.attr,
- &sensor_dev_attr_pwm4_enable.dev_attr.attr,
- &sensor_dev_attr_pwm4_temp_sel.dev_attr.attr,
- &sensor_dev_attr_pwm4_temp_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm4_crit_temp_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm4_target_temp.dev_attr.attr,
- &sensor_dev_attr_fan4_target.dev_attr.attr,
- &sensor_dev_attr_fan4_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm4_stop_time.dev_attr.attr,
- &sensor_dev_attr_pwm4_step_up_time.dev_attr.attr,
- &sensor_dev_attr_pwm4_step_down_time.dev_attr.attr,
- &sensor_dev_attr_pwm4_start.dev_attr.attr,
- &sensor_dev_attr_pwm4_floor.dev_attr.attr,
- &sensor_dev_attr_pwm4_weight_temp_sel.dev_attr.attr,
- &sensor_dev_attr_pwm4_weight_temp_step.dev_attr.attr,
- &sensor_dev_attr_pwm4_weight_temp_step_tol.dev_attr.attr,
- &sensor_dev_attr_pwm4_weight_temp_step_base.dev_attr.attr,
- &sensor_dev_attr_pwm4_weight_duty_step.dev_attr.attr,
- NULL
- },
- {
- &sensor_dev_attr_pwm5.dev_attr.attr,
- &sensor_dev_attr_pwm5_mode.dev_attr.attr,
- &sensor_dev_attr_pwm5_enable.dev_attr.attr,
- &sensor_dev_attr_pwm5_temp_sel.dev_attr.attr,
- &sensor_dev_attr_pwm5_temp_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm5_crit_temp_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm5_target_temp.dev_attr.attr,
- &sensor_dev_attr_fan5_target.dev_attr.attr,
- &sensor_dev_attr_fan5_tolerance.dev_attr.attr,
- &sensor_dev_attr_pwm5_stop_time.dev_attr.attr,
- &sensor_dev_attr_pwm5_step_up_time.dev_attr.attr,
- &sensor_dev_attr_pwm5_step_down_time.dev_attr.attr,
- &sensor_dev_attr_pwm5_start.dev_attr.attr,
- &sensor_dev_attr_pwm5_floor.dev_attr.attr,
- &sensor_dev_attr_pwm5_weight_temp_sel.dev_attr.attr,
- &sensor_dev_attr_pwm5_weight_temp_step.dev_attr.attr,
- &sensor_dev_attr_pwm5_weight_temp_step_tol.dev_attr.attr,
- &sensor_dev_attr_pwm5_weight_temp_step_base.dev_attr.attr,
- &sensor_dev_attr_pwm5_weight_duty_step.dev_attr.attr,
- NULL
- },
-};
-
-static const struct attribute_group nct6775_group_pwm[5] = {
- { .attrs = nct6775_attributes_pwm[0] },
- { .attrs = nct6775_attributes_pwm[1] },
- { .attrs = nct6775_attributes_pwm[2] },
- { .attrs = nct6775_attributes_pwm[3] },
- { .attrs = nct6775_attributes_pwm[4] },
-};
-
static ssize_t
show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -2927,17 +2790,19 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
break;
case nct6776:
break; /* always enabled, nothing to do */
+ case nct6106:
case nct6779:
- nct6775_write_value(data, NCT6779_REG_CRITICAL_PWM[nr],
+ case nct6791:
+ nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
val);
reg = nct6775_read_value(data,
- NCT6779_REG_CRITICAL_PWM_ENABLE[nr]);
+ data->REG_CRITICAL_PWM_ENABLE[nr]);
if (val == 255)
- reg &= ~0x01;
+ reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
else
- reg |= 0x01;
+ reg |= data->CRITICAL_PWM_ENABLE_MASK;
nct6775_write_value(data,
- NCT6779_REG_CRITICAL_PWM_ENABLE[nr],
+ data->REG_CRITICAL_PWM_ENABLE[nr],
reg);
break;
}
@@ -2992,155 +2857,140 @@ store_auto_temp(struct device *dev, struct device_attribute *attr,
return count;
}
+static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ int pwm = index / 36; /* pwm index */
+ int nr = index % 36; /* attribute index */
+
+ if (!(data->has_pwm & (1 << pwm)))
+ return 0;
+
+ if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
+ return 0;
+ if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
+ return 0;
+ if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
+ return 0;
+
+ if (nr >= 22 && nr <= 35) { /* auto point */
+ int api = (nr - 22) / 2; /* auto point index */
+
+ if (api > data->auto_pwm_num)
+ return 0;
+ }
+ return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
+ show_fan_time, store_fan_time, 0, 0);
+SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
+ show_fan_time, store_fan_time, 0, 1);
+SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
+ show_fan_time, store_fan_time, 0, 2);
+SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 0, 1);
+SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 0, 2);
+SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 0, 0);
+SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
+ S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
+ 0, 1);
+
+SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+ 0, 3);
+
+SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 0, 4);
+
+SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
+ S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
+SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
+ S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
+
+SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
+ S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
+SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
+ S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
+
+SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
+ S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
+SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
+ S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
+
+SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
+ S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
+SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
+ S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
+
+SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
+ S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
+SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
+ S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
+
+SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
+ S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
+SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
+ S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
+
+SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
+ S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
+SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
+ S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
+
/*
- * The number of auto-point trip points is chip dependent.
- * Need to check support while generating/removing attribute files.
+ * nct6775_pwm_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
*/
-static struct sensor_device_attribute_2 sda_auto_pwm_arrays[] = {
- SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 0, 0),
- SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 0, 0),
- SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 0, 1),
- SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 0, 1),
- SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 0, 2),
- SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 0, 2),
- SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 0, 3),
- SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 0, 3),
- SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 0, 4),
- SENSOR_ATTR_2(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 0, 4),
- SENSOR_ATTR_2(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 0, 5),
- SENSOR_ATTR_2(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 0, 5),
- SENSOR_ATTR_2(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 0, 6),
- SENSOR_ATTR_2(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 0, 6),
-
- SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 1, 0),
- SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 1, 0),
- SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 1, 1),
- SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 1, 1),
- SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 1, 2),
- SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 1, 2),
- SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 1, 3),
- SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 1, 3),
- SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 1, 4),
- SENSOR_ATTR_2(pwm2_auto_point5_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 1, 4),
- SENSOR_ATTR_2(pwm2_auto_point6_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 1, 5),
- SENSOR_ATTR_2(pwm2_auto_point6_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 1, 5),
- SENSOR_ATTR_2(pwm2_auto_point7_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 1, 6),
- SENSOR_ATTR_2(pwm2_auto_point7_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 1, 6),
-
- SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 2, 0),
- SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 2, 0),
- SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 2, 1),
- SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 2, 1),
- SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 2, 2),
- SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 2, 2),
- SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 2, 3),
- SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 2, 3),
- SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 2, 4),
- SENSOR_ATTR_2(pwm3_auto_point5_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 2, 4),
- SENSOR_ATTR_2(pwm3_auto_point6_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 2, 5),
- SENSOR_ATTR_2(pwm3_auto_point6_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 2, 5),
- SENSOR_ATTR_2(pwm3_auto_point7_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 2, 6),
- SENSOR_ATTR_2(pwm3_auto_point7_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 2, 6),
-
- SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 3, 0),
- SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 3, 0),
- SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 3, 1),
- SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 3, 1),
- SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 3, 2),
- SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 3, 2),
- SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 3, 3),
- SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 3, 3),
- SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 3, 4),
- SENSOR_ATTR_2(pwm4_auto_point5_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 3, 4),
- SENSOR_ATTR_2(pwm4_auto_point6_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 3, 5),
- SENSOR_ATTR_2(pwm4_auto_point6_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 3, 5),
- SENSOR_ATTR_2(pwm4_auto_point7_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 3, 6),
- SENSOR_ATTR_2(pwm4_auto_point7_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 3, 6),
-
- SENSOR_ATTR_2(pwm5_auto_point1_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 4, 0),
- SENSOR_ATTR_2(pwm5_auto_point1_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 4, 0),
- SENSOR_ATTR_2(pwm5_auto_point2_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 4, 1),
- SENSOR_ATTR_2(pwm5_auto_point2_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 4, 1),
- SENSOR_ATTR_2(pwm5_auto_point3_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 4, 2),
- SENSOR_ATTR_2(pwm5_auto_point3_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 4, 2),
- SENSOR_ATTR_2(pwm5_auto_point4_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 4, 3),
- SENSOR_ATTR_2(pwm5_auto_point4_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 4, 3),
- SENSOR_ATTR_2(pwm5_auto_point5_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 4, 4),
- SENSOR_ATTR_2(pwm5_auto_point5_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 4, 4),
- SENSOR_ATTR_2(pwm5_auto_point6_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 4, 5),
- SENSOR_ATTR_2(pwm5_auto_point6_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 4, 5),
- SENSOR_ATTR_2(pwm5_auto_point7_pwm, S_IWUSR | S_IRUGO,
- show_auto_pwm, store_auto_pwm, 4, 6),
- SENSOR_ATTR_2(pwm5_auto_point7_temp, S_IWUSR | S_IRUGO,
- show_auto_temp, store_auto_temp, 4, 6),
+static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
+ &sensor_dev_template_pwm,
+ &sensor_dev_template_pwm_mode,
+ &sensor_dev_template_pwm_enable,
+ &sensor_dev_template_pwm_temp_sel,
+ &sensor_dev_template_pwm_temp_tolerance,
+ &sensor_dev_template_pwm_crit_temp_tolerance,
+ &sensor_dev_template_pwm_target_temp,
+ &sensor_dev_template_fan_target,
+ &sensor_dev_template_fan_tolerance,
+ &sensor_dev_template_pwm_stop_time,
+ &sensor_dev_template_pwm_step_up_time,
+ &sensor_dev_template_pwm_step_down_time,
+ &sensor_dev_template_pwm_start,
+ &sensor_dev_template_pwm_floor,
+ &sensor_dev_template_pwm_weight_temp_sel,
+ &sensor_dev_template_pwm_weight_temp_step,
+ &sensor_dev_template_pwm_weight_temp_step_tol,
+ &sensor_dev_template_pwm_weight_temp_step_base,
+ &sensor_dev_template_pwm_weight_duty_step,
+ &sensor_dev_template_pwm_max, /* 19 */
+ &sensor_dev_template_pwm_step, /* 20 */
+ &sensor_dev_template_pwm_weight_duty_base, /* 21 */
+ &sensor_dev_template_pwm_auto_point1_pwm, /* 22 */
+ &sensor_dev_template_pwm_auto_point1_temp,
+ &sensor_dev_template_pwm_auto_point2_pwm,
+ &sensor_dev_template_pwm_auto_point2_temp,
+ &sensor_dev_template_pwm_auto_point3_pwm,
+ &sensor_dev_template_pwm_auto_point3_temp,
+ &sensor_dev_template_pwm_auto_point4_pwm,
+ &sensor_dev_template_pwm_auto_point4_temp,
+ &sensor_dev_template_pwm_auto_point5_pwm,
+ &sensor_dev_template_pwm_auto_point5_temp,
+ &sensor_dev_template_pwm_auto_point6_pwm,
+ &sensor_dev_template_pwm_auto_point6_temp,
+ &sensor_dev_template_pwm_auto_point7_pwm,
+ &sensor_dev_template_pwm_auto_point7_temp, /* 35 */
+
+ NULL
+};
+
+static struct sensor_template_group nct6775_pwm_template_group = {
+ .templates = nct6775_attributes_pwm_template,
+ .is_visible = nct6775_pwm_is_visible,
+ .base = 1,
};
static ssize_t
@@ -3159,7 +3009,6 @@ clear_caseopen(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct nct6775_data *data = dev_get_drvdata(dev);
- struct nct6775_sio_data *sio_data = dev->platform_data;
int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
unsigned long val;
u8 reg;
@@ -3175,19 +3024,19 @@ clear_caseopen(struct device *dev, struct device_attribute *attr,
* The CR registers are the same for all chips, and not all chips
* support clearing the caseopen status through "regular" registers.
*/
- ret = superio_enter(sio_data->sioreg);
+ ret = superio_enter(data->sioreg);
if (ret) {
count = ret;
goto error;
}
- superio_select(sio_data->sioreg, NCT6775_LD_ACPI);
- reg = superio_inb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
+ superio_select(data->sioreg, NCT6775_LD_ACPI);
+ reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
- superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+ superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
- superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
- superio_exit(sio_data->sioreg);
+ superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+ superio_exit(data->sioreg);
data->valid = false; /* Force cache refresh */
error:
@@ -3195,71 +3044,79 @@ error:
return count;
}
-static struct sensor_device_attribute sda_caseopen[] = {
- SENSOR_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
- clear_caseopen, INTRUSION_ALARM_BASE),
- SENSOR_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
- clear_caseopen, INTRUSION_ALARM_BASE + 1),
-};
-
-/*
- * Driver and device management
- */
-
-static void nct6775_device_remove_files(struct device *dev)
+static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
+ clear_caseopen, INTRUSION_ALARM_BASE);
+static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
+ clear_caseopen, INTRUSION_ALARM_BASE + 1);
+static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
+ store_beep, INTRUSION_ALARM_BASE);
+static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
+ store_beep, INTRUSION_ALARM_BASE + 1);
+static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
+ store_beep, BEEP_ENABLE_BASE);
+
+static umode_t nct6775_other_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
{
- /*
- * some entries in the following arrays may not have been used in
- * device_create_file(), but device_remove_file() will ignore them
- */
- int i;
+ struct device *dev = container_of(kobj, struct device, kobj);
struct nct6775_data *data = dev_get_drvdata(dev);
- for (i = 0; i < data->pwm_num; i++)
- sysfs_remove_group(&dev->kobj, &nct6775_group_pwm[i]);
+ if (index == 1 && !data->have_vid)
+ return 0;
- for (i = 0; i < ARRAY_SIZE(sda_pwm_max); i++)
- device_remove_file(dev, &sda_pwm_max[i].dev_attr);
+ if (index == 2 || index == 3) {
+ if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 2] < 0)
+ return 0;
+ }
+
+ if (index == 4 || index == 5) {
+ if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 4] < 0)
+ return 0;
+ }
- for (i = 0; i < ARRAY_SIZE(sda_pwm_step); i++)
- device_remove_file(dev, &sda_pwm_step[i].dev_attr);
+ return attr->mode;
+}
- for (i = 0; i < ARRAY_SIZE(sda_weight_duty_base); i++)
- device_remove_file(dev, &sda_weight_duty_base[i].dev_attr);
+/*
+ * nct6775_other_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct attribute *nct6775_attributes_other[] = {
+ &dev_attr_name.attr,
+ &dev_attr_cpu0_vid.attr, /* 1 */
+ &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 2 */
+ &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 3 */
+ &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 4 */
+ &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 5 */
+ &sensor_dev_attr_beep_enable.dev_attr.attr, /* 6 */
+
+ NULL
+};
- for (i = 0; i < ARRAY_SIZE(sda_auto_pwm_arrays); i++)
- device_remove_file(dev, &sda_auto_pwm_arrays[i].dev_attr);
+static const struct attribute_group nct6775_group_other = {
+ .attrs = nct6775_attributes_other,
+ .is_visible = nct6775_other_is_visible,
+};
- for (i = 0; i < data->in_num; i++)
- sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]);
+/*
+ * Driver and device management
+ */
- for (i = 0; i < 5; i++) {
- device_remove_file(dev, &sda_fan_input[i].dev_attr);
- device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
- device_remove_file(dev, &sda_fan_div[i].dev_attr);
- device_remove_file(dev, &sda_fan_min[i].dev_attr);
- device_remove_file(dev, &sda_fan_pulses[i].dev_attr);
- }
- for (i = 0; i < NUM_TEMP; i++) {
- if (!(data->have_temp & (1 << i)))
- continue;
- device_remove_file(dev, &sda_temp_input[i].dev_attr);
- device_remove_file(dev, &sda_temp_label[i].dev_attr);
- device_remove_file(dev, &sda_temp_max[i].dev_attr);
- device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
- device_remove_file(dev, &sda_temp_crit[i].dev_attr);
- device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
- if (!(data->have_temp_fixed & (1 << i)))
- continue;
- device_remove_file(dev, &sda_temp_type[i].dev_attr);
- device_remove_file(dev, &sda_temp_offset[i].dev_attr);
- }
+static void nct6775_device_remove_files(struct device *dev)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
- device_remove_file(dev, &sda_caseopen[0].dev_attr);
- device_remove_file(dev, &sda_caseopen[1].dev_attr);
+ if (data->group_pwm)
+ sysfs_remove_group(&dev->kobj, data->group_pwm);
+ if (data->group_in)
+ sysfs_remove_group(&dev->kobj, data->group_in);
+ if (data->group_fan)
+ sysfs_remove_group(&dev->kobj, data->group_fan);
+ if (data->group_temp)
+ sysfs_remove_group(&dev->kobj, data->group_temp);
- device_remove_file(dev, &dev_attr_name);
- device_remove_file(dev, &dev_attr_cpu0_vid);
+ sysfs_remove_group(&dev->kobj, &nct6775_group_other);
}
/* Get the monitoring functions started */
@@ -3297,68 +3154,78 @@ static inline void nct6775_init_device(struct nct6775_data *data)
for (i = 0; i < data->temp_fixed_num; i++) {
if (!(data->have_temp_fixed & (1 << i)))
continue;
- if ((tmp & (0x02 << i))) /* diode */
- data->temp_type[i] = 3 - ((diode >> i) & 0x02);
+ if ((tmp & (data->DIODE_MASK << i))) /* diode */
+ data->temp_type[i]
+ = 3 - ((diode >> i) & data->DIODE_MASK);
else /* thermistor */
data->temp_type[i] = 4;
}
}
-static int
-nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data,
- struct nct6775_data *data)
+static void
+nct6775_check_fan_inputs(struct nct6775_data *data)
{
+ bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
+ bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
+ int sioreg = data->sioreg;
int regval;
- bool fan3pin, fan3min, fan4pin, fan4min, fan5pin;
- bool pwm3pin, pwm4pin, pwm5pin;
- int ret;
-
- ret = superio_enter(sio_data->sioreg);
- if (ret)
- return ret;
/* fan4 and fan5 share some pins with the GPIO and serial flash */
if (data->kind == nct6775) {
- regval = superio_inb(sio_data->sioreg, 0x2c);
+ regval = superio_inb(sioreg, 0x2c);
fan3pin = regval & (1 << 6);
- fan3min = fan3pin;
pwm3pin = regval & (1 << 7);
/* On NCT6775, fan4 shares pins with the fdc interface */
- fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
- fan4min = 0;
- fan5pin = 0;
- pwm4pin = 0;
- pwm5pin = 0;
+ fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
+ fan4min = false;
+ fan5pin = false;
+ fan6pin = false;
+ pwm4pin = false;
+ pwm5pin = false;
+ pwm6pin = false;
} else if (data->kind == nct6776) {
- bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80;
+ bool gpok = superio_inb(sioreg, 0x27) & 0x80;
- superio_select(sio_data->sioreg, NCT6775_LD_HWM);
- regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE);
+ superio_select(sioreg, NCT6775_LD_HWM);
+ regval = superio_inb(sioreg, SIO_REG_ENABLE);
if (regval & 0x80)
fan3pin = gpok;
else
- fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+ fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
if (regval & 0x40)
fan4pin = gpok;
else
- fan4pin = superio_inb(sio_data->sioreg, 0x1C) & 0x01;
+ fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
if (regval & 0x20)
fan5pin = gpok;
else
- fan5pin = superio_inb(sio_data->sioreg, 0x1C) & 0x02;
+ fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
fan4min = fan4pin;
- fan3min = fan3pin;
+ fan6pin = false;
pwm3pin = fan3pin;
- pwm4pin = 0;
- pwm5pin = 0;
- } else { /* NCT6779D */
- regval = superio_inb(sio_data->sioreg, 0x1c);
+ pwm4pin = false;
+ pwm5pin = false;
+ pwm6pin = false;
+ } else if (data->kind == nct6106) {
+ regval = superio_inb(sioreg, 0x24);
+ fan3pin = !(regval & 0x80);
+ pwm3pin = regval & 0x08;
+
+ fan4pin = false;
+ fan4min = false;
+ fan5pin = false;
+ fan6pin = false;
+ pwm4pin = false;
+ pwm5pin = false;
+ pwm6pin = false;
+ } else { /* NCT6779D or NCT6791D */
+ regval = superio_inb(sioreg, 0x1c);
fan3pin = !(regval & (1 << 5));
fan4pin = !(regval & (1 << 6));
@@ -3368,22 +3235,25 @@ nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data,
pwm4pin = !(regval & (1 << 1));
pwm5pin = !(regval & (1 << 2));
- fan3min = fan3pin;
fan4min = fan4pin;
- }
-
- superio_exit(sio_data->sioreg);
- data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
- data->has_fan |= fan3pin << 2;
- data->has_fan_min |= fan3min << 2;
-
- data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
- data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
-
- data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | (pwm5pin << 4);
+ if (data->kind == nct6791) {
+ regval = superio_inb(sioreg, 0x2d);
+ fan6pin = (regval & (1 << 1));
+ pwm6pin = (regval & (1 << 0));
+ } else { /* NCT6779D */
+ fan6pin = false;
+ pwm6pin = false;
+ }
+ }
- return 0;
+ /* fan 1 and 2 (0x03) are always present */
+ data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
+ (fan5pin << 4) | (fan6pin << 5);
+ data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
+ (fan5pin << 4);
+ data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
+ (pwm5pin << 4) | (pwm6pin << 5);
}
static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
@@ -3415,16 +3285,17 @@ static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
static int nct6775_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct nct6775_sio_data *sio_data = dev->platform_data;
+ struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
struct nct6775_data *data;
struct resource *res;
int i, s, err = 0;
int src, mask, available;
const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
const u16 *reg_temp_alternate, *reg_temp_crit;
+ const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
int num_reg_temp;
- bool have_vid = false;
u8 cr2a;
+ struct attribute_group *group;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
@@ -3437,6 +3308,7 @@ static int nct6775_probe(struct platform_device *pdev)
return -ENOMEM;
data->kind = sio_data->kind;
+ data->sioreg = sio_data->sioreg;
data->addr = res->start;
mutex_init(&data->update_lock);
data->name = nct6775_device_names[data->kind];
@@ -3444,6 +3316,75 @@ static int nct6775_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
switch (data->kind) {
+ case nct6106:
+ data->in_num = 9;
+ data->pwm_num = 3;
+ data->auto_pwm_num = 4;
+ data->temp_fixed_num = 3;
+ data->num_temp_alarms = 6;
+ data->num_temp_beeps = 6;
+
+ data->fan_from_reg = fan_from_reg13;
+ data->fan_from_reg_min = fan_from_reg13;
+
+ data->temp_label = nct6776_temp_label;
+ data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
+
+ data->REG_VBAT = NCT6106_REG_VBAT;
+ data->REG_DIODE = NCT6106_REG_DIODE;
+ data->DIODE_MASK = NCT6106_DIODE_MASK;
+ data->REG_VIN = NCT6106_REG_IN;
+ data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
+ data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
+ data->REG_TARGET = NCT6106_REG_TARGET;
+ data->REG_FAN = NCT6106_REG_FAN;
+ data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
+ data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
+ data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
+ data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
+ data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
+ data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
+ data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
+ data->REG_PWM[0] = NCT6106_REG_PWM;
+ data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
+ data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
+ data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
+ data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
+ data->REG_PWM_READ = NCT6106_REG_PWM_READ;
+ data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
+ data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
+ data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
+ data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
+ data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
+ data->REG_CRITICAL_TEMP_TOLERANCE
+ = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
+ data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
+ data->CRITICAL_PWM_ENABLE_MASK
+ = NCT6106_CRITICAL_PWM_ENABLE_MASK;
+ data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
+ data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
+ data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
+ data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
+ data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
+ data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
+ data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
+ data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
+ data->REG_ALARM = NCT6106_REG_ALARM;
+ data->ALARM_BITS = NCT6106_ALARM_BITS;
+ data->REG_BEEP = NCT6106_REG_BEEP;
+ data->BEEP_BITS = NCT6106_BEEP_BITS;
+
+ reg_temp = NCT6106_REG_TEMP;
+ num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
+ reg_temp_over = NCT6106_REG_TEMP_OVER;
+ reg_temp_hyst = NCT6106_REG_TEMP_HYST;
+ reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+ reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
+ reg_temp_crit = NCT6106_REG_TEMP_CRIT;
+ reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
+ reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
+
+ break;
case nct6775:
data->in_num = 9;
data->pwm_num = 3;
@@ -3451,8 +3392,10 @@ static int nct6775_probe(struct platform_device *pdev)
data->has_fan_div = true;
data->temp_fixed_num = 3;
data->num_temp_alarms = 3;
+ data->num_temp_beeps = 3;
data->ALARM_BITS = NCT6775_ALARM_BITS;
+ data->BEEP_BITS = NCT6775_BEEP_BITS;
data->fan_from_reg = fan_from_reg16;
data->fan_from_reg_min = fan_from_reg8;
@@ -3466,6 +3409,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT;
data->REG_DIODE = NCT6775_REG_DIODE;
+ data->DIODE_MASK = NCT6775_DIODE_MASK;
data->REG_VIN = NCT6775_REG_IN;
data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3474,6 +3418,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
+ data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
@@ -3499,6 +3444,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
data->REG_ALARM = NCT6775_REG_ALARM;
+ data->REG_BEEP = NCT6775_REG_BEEP;
reg_temp = NCT6775_REG_TEMP;
num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
@@ -3516,8 +3462,10 @@ static int nct6775_probe(struct platform_device *pdev)
data->has_fan_div = false;
data->temp_fixed_num = 3;
data->num_temp_alarms = 3;
+ data->num_temp_beeps = 6;
data->ALARM_BITS = NCT6776_ALARM_BITS;
+ data->BEEP_BITS = NCT6776_BEEP_BITS;
data->fan_from_reg = fan_from_reg13;
data->fan_from_reg_min = fan_from_reg13;
@@ -3531,6 +3479,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT;
data->REG_DIODE = NCT6775_REG_DIODE;
+ data->DIODE_MASK = NCT6775_DIODE_MASK;
data->REG_VIN = NCT6775_REG_IN;
data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3539,6 +3488,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
+ data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
@@ -3564,6 +3514,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
data->REG_ALARM = NCT6775_REG_ALARM;
+ data->REG_BEEP = NCT6776_REG_BEEP;
reg_temp = NCT6775_REG_TEMP;
num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
@@ -3581,8 +3532,10 @@ static int nct6775_probe(struct platform_device *pdev)
data->has_fan_div = false;
data->temp_fixed_num = 6;
data->num_temp_alarms = 2;
+ data->num_temp_beeps = 2;
data->ALARM_BITS = NCT6779_ALARM_BITS;
+ data->BEEP_BITS = NCT6779_BEEP_BITS;
data->fan_from_reg = fan_from_reg13;
data->fan_from_reg_min = fan_from_reg13;
@@ -3596,6 +3549,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT;
data->REG_DIODE = NCT6775_REG_DIODE;
+ data->DIODE_MASK = NCT6775_DIODE_MASK;
data->REG_VIN = NCT6779_REG_IN;
data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3604,6 +3558,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+ data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
@@ -3621,6 +3576,10 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
data->REG_CRITICAL_TEMP_TOLERANCE
= NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+ data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
+ data->CRITICAL_PWM_ENABLE_MASK
+ = NCT6779_CRITICAL_PWM_ENABLE_MASK;
+ data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
@@ -3629,6 +3588,81 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
data->REG_ALARM = NCT6779_REG_ALARM;
+ data->REG_BEEP = NCT6776_REG_BEEP;
+
+ reg_temp = NCT6779_REG_TEMP;
+ num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
+ reg_temp_over = NCT6779_REG_TEMP_OVER;
+ reg_temp_hyst = NCT6779_REG_TEMP_HYST;
+ reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+ reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
+ reg_temp_crit = NCT6779_REG_TEMP_CRIT;
+
+ break;
+ case nct6791:
+ data->in_num = 15;
+ data->pwm_num = 6;
+ data->auto_pwm_num = 4;
+ data->has_fan_div = false;
+ data->temp_fixed_num = 6;
+ data->num_temp_alarms = 2;
+ data->num_temp_beeps = 2;
+
+ data->ALARM_BITS = NCT6791_ALARM_BITS;
+ data->BEEP_BITS = NCT6779_BEEP_BITS;
+
+ data->fan_from_reg = fan_from_reg13;
+ data->fan_from_reg_min = fan_from_reg13;
+ data->target_temp_mask = 0xff;
+ data->tolerance_mask = 0x07;
+ data->speed_tolerance_limit = 63;
+
+ data->temp_label = nct6779_temp_label;
+ data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
+
+ data->REG_CONFIG = NCT6775_REG_CONFIG;
+ data->REG_VBAT = NCT6775_REG_VBAT;
+ data->REG_DIODE = NCT6775_REG_DIODE;
+ data->DIODE_MASK = NCT6775_DIODE_MASK;
+ data->REG_VIN = NCT6779_REG_IN;
+ data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+ data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+ data->REG_TARGET = NCT6775_REG_TARGET;
+ data->REG_FAN = NCT6779_REG_FAN;
+ data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+ data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+ data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+ data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
+ data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+ data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+ data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+ data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+ data->REG_PWM[0] = NCT6775_REG_PWM;
+ data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+ data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+ data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+ data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+ data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+ data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+ data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+ data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+ data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+ data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+ data->REG_CRITICAL_TEMP_TOLERANCE
+ = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+ data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
+ data->CRITICAL_PWM_ENABLE_MASK
+ = NCT6779_CRITICAL_PWM_ENABLE_MASK;
+ data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
+ data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
+ data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+ data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+ data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+ data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+ data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+ data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+ data->REG_ALARM = NCT6791_REG_ALARM;
+ data->REG_BEEP = NCT6776_REG_BEEP;
reg_temp = NCT6779_REG_TEMP;
num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
@@ -3700,6 +3734,13 @@ static int nct6775_probe(struct platform_device *pdev)
data->reg_temp[0][src - 1] = reg_temp[i];
data->reg_temp[1][src - 1] = reg_temp_over[i];
data->reg_temp[2][src - 1] = reg_temp_hyst[i];
+ if (reg_temp_crit_h && reg_temp_crit_h[i])
+ data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
+ else if (reg_temp_crit[src - 1])
+ data->reg_temp[3][src - 1]
+ = reg_temp_crit[src - 1];
+ if (reg_temp_crit_l && reg_temp_crit_l[i])
+ data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
data->reg_temp_config[src - 1] = reg_temp_config[i];
data->temp_src[src - 1] = src;
continue;
@@ -3714,8 +3755,12 @@ static int nct6775_probe(struct platform_device *pdev)
data->reg_temp[1][s] = reg_temp_over[i];
data->reg_temp[2][s] = reg_temp_hyst[i];
data->reg_temp_config[s] = reg_temp_config[i];
- if (reg_temp_crit[src - 1])
+ if (reg_temp_crit_h && reg_temp_crit_h[i])
+ data->reg_temp[3][s] = reg_temp_crit_h[i];
+ else if (reg_temp_crit[src - 1])
data->reg_temp[3][s] = reg_temp_crit[src - 1];
+ if (reg_temp_crit_l && reg_temp_crit_l[i])
+ data->reg_temp[4][s] = reg_temp_crit_l[i];
data->temp_src[s] = src;
s++;
@@ -3767,12 +3812,14 @@ static int nct6775_probe(struct platform_device *pdev)
cr2a = superio_inb(sio_data->sioreg, 0x2a);
switch (data->kind) {
case nct6775:
- have_vid = (cr2a & 0x40);
+ data->have_vid = (cr2a & 0x40);
break;
case nct6776:
- have_vid = (cr2a & 0x60) == 0x40;
+ data->have_vid = (cr2a & 0x60) == 0x40;
break;
+ case nct6106:
case nct6779:
+ case nct6791:
break;
}
@@ -3780,7 +3827,7 @@ static int nct6775_probe(struct platform_device *pdev)
* Read VID value
* We can get the VID input values directly at logical device D 0xe3.
*/
- if (have_vid) {
+ if (data->have_vid) {
superio_select(sio_data->sioreg, NCT6775_LD_VID);
data->vid = superio_inb(sio_data->sioreg, 0xe3);
data->vrm = vid_which_vrm();
@@ -3793,6 +3840,9 @@ static int nct6775_probe(struct platform_device *pdev)
tmp = superio_inb(sio_data->sioreg,
NCT6775_REG_CR_FAN_DEBOUNCE);
switch (data->kind) {
+ case nct6106:
+ tmp |= 0xe0;
+ break;
case nct6775:
tmp |= 0x1e;
break;
@@ -3800,6 +3850,9 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6779:
tmp |= 0x3e;
break;
+ case nct6791:
+ tmp |= 0x7e;
+ break;
}
superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
tmp);
@@ -3807,157 +3860,47 @@ static int nct6775_probe(struct platform_device *pdev)
data->name);
}
- superio_exit(sio_data->sioreg);
-
- if (have_vid) {
- err = device_create_file(dev, &dev_attr_cpu0_vid);
- if (err)
- return err;
- }
+ nct6775_check_fan_inputs(data);
- err = nct6775_check_fan_inputs(sio_data, data);
- if (err)
- goto exit_remove;
+ superio_exit(sio_data->sioreg);
/* Read fan clock dividers immediately */
nct6775_init_fan_common(dev, data);
/* Register sysfs hooks */
- for (i = 0; i < data->pwm_num; i++) {
- if (!(data->has_pwm & (1 << i)))
- continue;
-
- err = sysfs_create_group(&dev->kobj, &nct6775_group_pwm[i]);
- if (err)
- goto exit_remove;
-
- if (data->REG_PWM[3]) {
- err = device_create_file(dev,
- &sda_pwm_max[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- if (data->REG_PWM[4]) {
- err = device_create_file(dev,
- &sda_pwm_step[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- if (data->REG_PWM[6]) {
- err = device_create_file(dev,
- &sda_weight_duty_base[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- }
- for (i = 0; i < ARRAY_SIZE(sda_auto_pwm_arrays); i++) {
- struct sensor_device_attribute_2 *attr =
- &sda_auto_pwm_arrays[i];
-
- if (!(data->has_pwm & (1 << attr->nr)))
- continue;
- if (attr->index > data->auto_pwm_num)
- continue;
- err = device_create_file(dev, &attr->dev_attr);
- if (err)
- goto exit_remove;
- }
-
- for (i = 0; i < data->in_num; i++) {
- if (!(data->have_in & (1 << i)))
- continue;
- err = sysfs_create_group(&dev->kobj, &nct6775_group_in[i]);
- if (err)
- goto exit_remove;
+ group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
+ data->pwm_num);
+ if (IS_ERR(group)) {
+ err = PTR_ERR(group);
+ goto exit_remove;
}
+ data->group_pwm = group;
- for (i = 0; i < 5; i++) {
- if (data->has_fan & (1 << i)) {
- err = device_create_file(dev,
- &sda_fan_input[i].dev_attr);
- if (err)
- goto exit_remove;
- if (data->ALARM_BITS[FAN_ALARM_BASE + i] >= 0) {
- err = device_create_file(dev,
- &sda_fan_alarm[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- if (data->kind != nct6776 &&
- data->kind != nct6779) {
- err = device_create_file(dev,
- &sda_fan_div[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- if (data->has_fan_min & (1 << i)) {
- err = device_create_file(dev,
- &sda_fan_min[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- err = device_create_file(dev,
- &sda_fan_pulses[i].dev_attr);
- if (err)
- goto exit_remove;
- }
+ group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
+ fls(data->have_in));
+ if (IS_ERR(group)) {
+ err = PTR_ERR(group);
+ goto exit_remove;
}
+ data->group_in = group;
- for (i = 0; i < NUM_TEMP; i++) {
- if (!(data->have_temp & (1 << i)))
- continue;
- err = device_create_file(dev, &sda_temp_input[i].dev_attr);
- if (err)
- goto exit_remove;
- if (data->temp_label) {
- err = device_create_file(dev,
- &sda_temp_label[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- if (data->reg_temp[1][i]) {
- err = device_create_file(dev,
- &sda_temp_max[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- if (data->reg_temp[2][i]) {
- err = device_create_file(dev,
- &sda_temp_max_hyst[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- if (data->reg_temp[3][i]) {
- err = device_create_file(dev,
- &sda_temp_crit[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- if (find_temp_source(data, i, data->num_temp_alarms) >= 0) {
- err = device_create_file(dev,
- &sda_temp_alarm[i].dev_attr);
- if (err)
- goto exit_remove;
- }
- if (!(data->have_temp_fixed & (1 << i)))
- continue;
- err = device_create_file(dev, &sda_temp_type[i].dev_attr);
- if (err)
- goto exit_remove;
- err = device_create_file(dev, &sda_temp_offset[i].dev_attr);
- if (err)
- goto exit_remove;
+ group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
+ fls(data->has_fan));
+ if (IS_ERR(group)) {
+ err = PTR_ERR(group);
+ goto exit_remove;
}
+ data->group_fan = group;
- for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) {
- if (data->ALARM_BITS[INTRUSION_ALARM_BASE + i] < 0)
- continue;
- err = device_create_file(dev, &sda_caseopen[i].dev_attr);
- if (err)
- goto exit_remove;
+ group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
+ fls(data->have_temp));
+ if (IS_ERR(group)) {
+ err = PTR_ERR(group);
+ goto exit_remove;
}
+ data->group_temp = group;
- err = device_create_file(dev, &dev_attr_name);
+ err = sysfs_create_group(&dev->kobj, &nct6775_group_other);
if (err)
goto exit_remove;
@@ -3988,11 +3931,10 @@ static int nct6775_remove(struct platform_device *pdev)
static int nct6775_suspend(struct device *dev)
{
struct nct6775_data *data = nct6775_update_device(dev);
- struct nct6775_sio_data *sio_data = dev->platform_data;
mutex_lock(&data->update_lock);
data->vbat = nct6775_read_value(data, data->REG_VBAT);
- if (sio_data->kind == nct6775) {
+ if (data->kind == nct6775) {
data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
}
@@ -4004,7 +3946,6 @@ static int nct6775_suspend(struct device *dev)
static int nct6775_resume(struct device *dev)
{
struct nct6775_data *data = dev_get_drvdata(dev);
- struct nct6775_sio_data *sio_data = dev->platform_data;
int i, j;
mutex_lock(&data->update_lock);
@@ -4041,7 +3982,7 @@ static int nct6775_resume(struct device *dev)
/* Restore other settings */
nct6775_write_value(data, data->REG_VBAT, data->vbat);
- if (sio_data->kind == nct6775) {
+ if (data->kind == nct6775) {
nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
}
@@ -4056,6 +3997,8 @@ static int nct6775_resume(struct device *dev)
static const struct dev_pm_ops nct6775_dev_pm_ops = {
.suspend = nct6775_suspend,
.resume = nct6775_resume,
+ .freeze = nct6775_suspend,
+ .restore = nct6775_resume,
};
#define NCT6775_DEV_PM_OPS (&nct6775_dev_pm_ops)
@@ -4074,17 +4017,19 @@ static struct platform_driver nct6775_driver = {
};
static const char * const nct6775_sio_names[] __initconst = {
+ "NCT6106D",
"NCT6775F",
"NCT6776D/F",
"NCT6779D",
+ "NCT6791D",
};
/* nct6775_find() looks for a '627 in the Super-I/O config space */
-static int __init nct6775_find(int sioaddr, unsigned short *addr,
- struct nct6775_sio_data *sio_data)
+static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
{
u16 val;
int err;
+ int addr;
err = superio_enter(sioaddr);
if (err)
@@ -4096,6 +4041,9 @@ static int __init nct6775_find(int sioaddr, unsigned short *addr,
val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
| superio_inb(sioaddr, SIO_REG_DEVID + 1);
switch (val & SIO_ID_MASK) {
+ case SIO_NCT6106_ID:
+ sio_data->kind = nct6106;
+ break;
case SIO_NCT6775_ID:
sio_data->kind = nct6775;
break;
@@ -4105,6 +4053,9 @@ static int __init nct6775_find(int sioaddr, unsigned short *addr,
case SIO_NCT6779_ID:
sio_data->kind = nct6779;
break;
+ case SIO_NCT6791_ID:
+ sio_data->kind = nct6791;
+ break;
default:
if (val != 0xffff)
pr_debug("unsupported chip ID: 0x%04x\n", val);
@@ -4116,8 +4067,8 @@ static int __init nct6775_find(int sioaddr, unsigned short *addr,
superio_select(sioaddr, NCT6775_LD_HWM);
val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
| superio_inb(sioaddr, SIO_REG_ADDR + 1);
- *addr = val & IOREGION_ALIGNMENT;
- if (*addr == 0) {
+ addr = val & IOREGION_ALIGNMENT;
+ if (addr == 0) {
pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
superio_exit(sioaddr);
return -ENODEV;
@@ -4129,13 +4080,22 @@ static int __init nct6775_find(int sioaddr, unsigned short *addr,
pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
}
+ if (sio_data->kind == nct6791) {
+ val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
+ if (val & 0x10) {
+ pr_info("Enabling hardware monitor logical device mappings.\n");
+ superio_outb(sioaddr,
+ NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
+ val & ~0x10);
+ }
+ }
superio_exit(sioaddr);
- pr_info("Found %s or compatible chip at %#x\n",
- nct6775_sio_names[sio_data->kind], *addr);
+ pr_info("Found %s or compatible chip at %#x:%#x\n",
+ nct6775_sio_names[sio_data->kind], sioaddr, addr);
sio_data->sioreg = sioaddr;
- return 0;
+ return addr;
}
/*
@@ -4144,14 +4104,20 @@ static int __init nct6775_find(int sioaddr, unsigned short *addr,
* track of the nct6775 driver. But since we platform_device_alloc(), we
* must keep track of the device
*/
-static struct platform_device *pdev;
+static struct platform_device *pdev[2];
static int __init sensors_nct6775_init(void)
{
- int err;
- unsigned short address;
+ int i, err;
+ bool found = false;
+ int address;
struct resource res;
struct nct6775_sio_data sio_data;
+ int sioaddr[2] = { 0x2e, 0x4e };
+
+ err = platform_driver_register(&nct6775_driver);
+ if (err)
+ return err;
/*
* initialize sio_data->kind and sio_data->sioreg.
@@ -4160,64 +4126,71 @@ static int __init sensors_nct6775_init(void)
* driver will probe 0x2e and 0x4e and auto-detect the presence of a
* nct6775 hardware monitor, and call probe()
*/
- if (nct6775_find(0x2e, &address, &sio_data) &&
- nct6775_find(0x4e, &address, &sio_data))
- return -ENODEV;
-
- err = platform_driver_register(&nct6775_driver);
- if (err)
- goto exit;
+ for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+ address = nct6775_find(sioaddr[i], &sio_data);
+ if (address <= 0)
+ continue;
- pdev = platform_device_alloc(DRVNAME, address);
- if (!pdev) {
- err = -ENOMEM;
- pr_err("Device allocation failed\n");
- goto exit_unregister;
- }
+ found = true;
- err = platform_device_add_data(pdev, &sio_data,
- sizeof(struct nct6775_sio_data));
- if (err) {
- pr_err("Platform data allocation failed\n");
- goto exit_device_put;
- }
+ pdev[i] = platform_device_alloc(DRVNAME, address);
+ if (!pdev[i]) {
+ err = -ENOMEM;
+ goto exit_device_put;
+ }
- memset(&res, 0, sizeof(res));
- res.name = DRVNAME;
- res.start = address + IOREGION_OFFSET;
- res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
- res.flags = IORESOURCE_IO;
+ err = platform_device_add_data(pdev[i], &sio_data,
+ sizeof(struct nct6775_sio_data));
+ if (err)
+ goto exit_device_put;
+
+ memset(&res, 0, sizeof(res));
+ res.name = DRVNAME;
+ res.start = address + IOREGION_OFFSET;
+ res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+ res.flags = IORESOURCE_IO;
+
+ err = acpi_check_resource_conflict(&res);
+ if (err) {
+ platform_device_put(pdev[i]);
+ pdev[i] = NULL;
+ continue;
+ }
- err = acpi_check_resource_conflict(&res);
- if (err)
- goto exit_device_put;
+ err = platform_device_add_resources(pdev[i], &res, 1);
+ if (err)
+ goto exit_device_put;
- err = platform_device_add_resources(pdev, &res, 1);
- if (err) {
- pr_err("Device resource addition failed (%d)\n", err);
- goto exit_device_put;
+ /* platform_device_add calls probe() */
+ err = platform_device_add(pdev[i]);
+ if (err)
+ goto exit_device_put;
}
-
- /* platform_device_add calls probe() */
- err = platform_device_add(pdev);
- if (err) {
- pr_err("Device addition failed (%d)\n", err);
- goto exit_device_put;
+ if (!found) {
+ err = -ENODEV;
+ goto exit_unregister;
}
return 0;
exit_device_put:
- platform_device_put(pdev);
+ for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+ if (pdev[i])
+ platform_device_put(pdev[i]);
+ }
exit_unregister:
platform_driver_unregister(&nct6775_driver);
-exit:
return err;
}
static void __exit sensors_nct6775_exit(void)
{
- platform_device_unregister(pdev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+ if (pdev[i])
+ platform_device_unregister(pdev[i]);
+ }
platform_driver_unregister(&nct6775_driver);
}
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index 830a842d796..8c23203915a 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -424,7 +424,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
if (IS_ERR(pdata))
return PTR_ERR(pdata);
else if (pdata == NULL)
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n");
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index ea606860d2b..6e6ea4437bb 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -983,7 +983,7 @@ static int pc87427_request_regions(struct platform_device *pdev,
static void pc87427_init_device(struct device *dev)
{
- struct pc87427_sio_data *sio_data = dev->platform_data;
+ struct pc87427_sio_data *sio_data = dev_get_platdata(dev);
struct pc87427_data *data = dev_get_drvdata(dev);
int i;
u8 reg;
@@ -1075,7 +1075,7 @@ static void pc87427_remove_files(struct device *dev)
static int pc87427_probe(struct platform_device *pdev)
{
- struct pc87427_sio_data *sio_data = pdev->dev.platform_data;
+ struct pc87427_sio_data *sio_data = dev_get_platdata(&pdev->dev);
struct pc87427_data *data;
int i, err, res_count;
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 9add60920ac..9319fcf142d 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -1726,7 +1726,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
struct pmbus_driver_info *info)
{
struct device *dev = &client->dev;
- const struct pmbus_platform_data *pdata = dev->platform_data;
+ const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
struct pmbus_data *data;
int ret;
diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c
index a9f7e804f1e..73bd64e8c30 100644
--- a/drivers/hwmon/s3c-hwmon.c
+++ b/drivers/hwmon/s3c-hwmon.c
@@ -165,7 +165,7 @@ static ssize_t s3c_hwmon_ch_show(struct device *dev,
{
struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
struct s3c_hwmon *hwmon = platform_get_drvdata(to_platform_device(dev));
- struct s3c_hwmon_pdata *pdata = dev->platform_data;
+ struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev);
struct s3c_hwmon_chcfg *cfg;
int ret;
@@ -194,7 +194,7 @@ static ssize_t s3c_hwmon_label_show(struct device *dev,
char *buf)
{
struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
- struct s3c_hwmon_pdata *pdata = dev->platform_data;
+ struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev);
struct s3c_hwmon_chcfg *cfg;
cfg = pdata->in[sen_attr->index];
@@ -274,7 +274,7 @@ static void s3c_hwmon_remove_attr(struct device *dev,
*/
static int s3c_hwmon_probe(struct platform_device *dev)
{
- struct s3c_hwmon_pdata *pdata = dev->dev.platform_data;
+ struct s3c_hwmon_pdata *pdata = dev_get_platdata(&dev->dev);
struct s3c_hwmon *hwmon;
int ret = 0;
int i;
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index 2507f902fb7..97cd45a8432 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -940,11 +940,11 @@ static int sht15_probe(struct platform_device *pdev)
data->dev = &pdev->dev;
init_waitqueue_head(&data->wait_queue);
- if (pdev->dev.platform_data == NULL) {
+ if (dev_get_platdata(&pdev->dev) == NULL) {
dev_err(&pdev->dev, "no platform data supplied\n");
return -EINVAL;
}
- data->pdata = pdev->dev.platform_data;
+ data->pdata = dev_get_platdata(&pdev->dev);
data->supply_uv = data->pdata->supply_mv * 1000;
if (data->pdata->checksum)
data->checksumming = true;
@@ -957,7 +957,7 @@ static int sht15_probe(struct platform_device *pdev)
* If a regulator is available,
* query what the supply voltage actually is!
*/
- data->reg = devm_regulator_get(data->dev, "vcc");
+ data->reg = devm_regulator_get_optional(data->dev, "vcc");
if (!IS_ERR(data->reg)) {
int voltage;
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 6d8255ccf07..05cb814539c 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -668,7 +668,7 @@ static void smsc47m1_remove_files(struct device *dev)
static int __init smsc47m1_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct smsc47m1_sio_data *sio_data = dev->platform_data;
+ struct smsc47m1_sio_data *sio_data = dev_get_platdata(dev);
struct smsc47m1_data *data;
struct resource *res;
int err;
@@ -940,7 +940,7 @@ exit_device:
static void __exit sm_smsc47m1_exit(void)
{
platform_driver_unregister(&smsc47m1_driver);
- smsc47m1_restore(pdev->dev.platform_data);
+ smsc47m1_restore(dev_get_platdata(&pdev->dev));
platform_device_unregister(pdev);
}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 004801e6fbb..23ff210513d 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -673,7 +673,7 @@ static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
static void w83627ehf_write_fan_div_common(struct device *dev,
struct w83627ehf_data *data, int nr)
{
- struct w83627ehf_sio_data *sio_data = dev->platform_data;
+ struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
if (sio_data->kind == nct6776)
; /* no dividers, do nothing */
@@ -724,7 +724,7 @@ static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
static void w83627ehf_update_fan_div_common(struct device *dev,
struct w83627ehf_data *data)
{
- struct w83627ehf_sio_data *sio_data = dev->platform_data;
+ struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
if (sio_data->kind == nct6776)
; /* no dividers, do nothing */
@@ -781,7 +781,7 @@ static void w83627ehf_update_pwm(struct w83627ehf_data *data)
static void w83627ehf_update_pwm_common(struct device *dev,
struct w83627ehf_data *data)
{
- struct w83627ehf_sio_data *sio_data = dev->platform_data;
+ struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
if (sio_data->kind == nct6775 || sio_data->kind == nct6776)
nct6775_update_pwm(data);
@@ -792,7 +792,7 @@ static void w83627ehf_update_pwm_common(struct device *dev,
static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
{
struct w83627ehf_data *data = dev_get_drvdata(dev);
- struct w83627ehf_sio_data *sio_data = dev->platform_data;
+ struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
int i;
@@ -1392,7 +1392,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
{
struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- struct w83627ehf_sio_data *sio_data = dev->platform_data;
+ struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
int nr = sensor_attr->index;
unsigned long val;
int err;
@@ -1448,7 +1448,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct w83627ehf_data *data = dev_get_drvdata(dev);
- struct w83627ehf_sio_data *sio_data = dev->platform_data;
+ struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
unsigned long val;
@@ -1527,7 +1527,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct w83627ehf_data *data = dev_get_drvdata(dev);
- struct w83627ehf_sio_data *sio_data = dev->platform_data;
+ struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u16 reg;
@@ -2065,7 +2065,7 @@ w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data,
static int w83627ehf_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct w83627ehf_sio_data *sio_data = dev->platform_data;
+ struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
struct w83627ehf_data *data;
struct resource *res;
u8 en_vrm10;
@@ -2618,7 +2618,7 @@ static int w83627ehf_remove(struct platform_device *pdev)
static int w83627ehf_suspend(struct device *dev)
{
struct w83627ehf_data *data = w83627ehf_update_device(dev);
- struct w83627ehf_sio_data *sio_data = dev->platform_data;
+ struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
mutex_lock(&data->update_lock);
data->vbat = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
@@ -2634,7 +2634,7 @@ static int w83627ehf_suspend(struct device *dev)
static int w83627ehf_resume(struct device *dev)
{
struct w83627ehf_data *data = dev_get_drvdata(dev);
- struct w83627ehf_sio_data *sio_data = dev->platform_data;
+ struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
int i;
mutex_lock(&data->update_lock);
@@ -2694,6 +2694,8 @@ static int w83627ehf_resume(struct device *dev)
static const struct dev_pm_ops w83627ehf_dev_pm_ops = {
.suspend = w83627ehf_suspend,
.resume = w83627ehf_resume,
+ .freeze = w83627ehf_suspend,
+ .restore = w83627ehf_resume,
};
#define W83627EHF_DEV_PM_OPS (&w83627ehf_dev_pm_ops)
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 3b9ef2d2345..cb9cd326ecb 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -1415,7 +1415,7 @@ static const struct attribute_group w83627hf_group_opt = {
static int w83627hf_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct w83627hf_sio_data *sio_data = dev->platform_data;
+ struct w83627hf_sio_data *sio_data = dev_get_platdata(dev);
struct w83627hf_data *data;
struct resource *res;
int err, i;
@@ -1636,7 +1636,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
static int w83627thf_read_gpio5(struct platform_device *pdev)
{
- struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
+ struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev);
int res = 0xff, sel;
superio_enter(sio_data);
@@ -1669,7 +1669,7 @@ exit:
static int w83687thf_read_vid(struct platform_device *pdev)
{
- struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
+ struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev);
int res = 0xff;
superio_enter(sio_data);
diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c
index ccec916bc3e..af8f65fb1c0 100644
--- a/drivers/i2c/busses/i2c-kempld.c
+++ b/drivers/i2c/busses/i2c-kempld.c
@@ -246,9 +246,9 @@ static void kempld_i2c_device_init(struct kempld_i2c_data *i2c)
bus_frequency = KEMPLD_I2C_FREQ_MAX;
if (pld->info.spec_major == 1)
- prescale = pld->pld_clock / bus_frequency * 5 - 1000;
+ prescale = pld->pld_clock / (bus_frequency * 5) - 1000;
else
- prescale = pld->pld_clock / bus_frequency * 4 - 3000;
+ prescale = pld->pld_clock / (bus_frequency * 4) - 3000;
if (prescale < 0)
prescale = 0;
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index df8ff5aea5b..e2e9a0dade9 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -493,7 +493,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
* based on this empirical measurement and a lot of previous frobbing.
*/
i2c->cmd_err = 0;
- if (msg->len < 8) {
+ if (0) { /* disable PIO mode until a proper fix is made */
ret = mxs_i2c_pio_setup_xfer(adap, msg, flags);
if (ret)
mxs_i2c_reset(i2c);
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index f1a6796b165..140c8ef5052 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -520,11 +520,12 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
ide_port_for_each_present_dev(i, drive, hwif) {
if (drive->acpidata->obj_handle)
acpi_bus_set_power(drive->acpidata->obj_handle,
- on ? ACPI_STATE_D0 : ACPI_STATE_D3);
+ on ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
}
if (!on)
- acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
+ acpi_bus_set_power(hwif->acpidata->obj_handle,
+ ACPI_STATE_D3_COLD);
}
/**
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 9af763a90d9..cbea3271c1b 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -23,15 +23,14 @@ if IIO_BUFFER
config IIO_BUFFER_CB
boolean "IIO callback buffer used for push in-kernel interfaces"
help
- Should be selected by any drivers that do-inkernel push
+ Should be selected by any drivers that do in-kernel push
usage. That is, those where the data is pushed to the consumer.
config IIO_KFIFO_BUF
select IIO_TRIGGER
tristate "Industrial I/O buffering based on kfifo"
help
- A simple fifo based on kfifo. Use this if you want a fifo
- rather than a ring buffer. Note that this currently provides
+ A simple fifo based on kfifo. Note that this currently provides
no buffer events so it is up to userspace to work out how
often to read from the buffer.
@@ -49,7 +48,7 @@ config IIO_TRIGGER
help
Provides IIO core support for triggers. Currently these
are used to initialize capture of samples to push into
- ring buffers. The triggers are effectively a 'capture
+ buffers. The triggers are effectively a 'capture
data now' interrupt.
config IIO_CONSUMERS_PER_TRIGGER
@@ -74,5 +73,6 @@ if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
endif #IIO_TRIGGER
source "drivers/iio/pressure/Kconfig"
+source "drivers/iio/temperature/Kconfig"
endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 7a3866c2d2a..bcf7e9e3b05 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -21,5 +21,6 @@ obj-y += frequency/
obj-y += imu/
obj-y += light/
obj-y += magnetometer/
-obj-y += trigger/
obj-y += pressure/
+obj-y += temperature/
+obj-y += trigger/
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 719d83fe51d..e23e5085065 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -1,8 +1,22 @@
#
# Accelerometer drivers
#
+# When adding new entries keep the list in alphabetical order
+
menu "Accelerometers"
+config BMA180
+ tristate "Bosch BMA180 3-Axis Accelerometer Driver"
+ depends on I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say Y here if you want to build a driver for the Bosch BMA180
+ triaxial acceleration sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bma180.
+
config HID_SENSOR_ACCEL_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
@@ -14,13 +28,6 @@ config HID_SENSOR_ACCEL_3D
Say yes here to build support for the HID SENSOR
accelerometers 3D.
-config KXSD9
- tristate "Kionix KXSD9 Accelerometer Driver"
- depends on SPI
- help
- Say yes here to build support for the Kionix KXSD9 accelerometer.
- Currently this only supports the device via an SPI interface.
-
config IIO_ST_ACCEL_3AXIS
tristate "STMicroelectronics accelerometers 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
@@ -33,8 +40,8 @@ config IIO_ST_ACCEL_3AXIS
LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
LIS331DLH, LSM303DL, LSM303DLM, LSM330.
- This driver can also be built as a module. If so, will be created
- these modules:
+ This driver can also be built as a module. If so, these modules
+ will be created:
- st_accel (core functions for the driver [it is mandatory]);
- st_accel_i2c (necessary for the I2C devices [optional*]);
- st_accel_spi (necessary for the SPI devices [optional*]);
@@ -51,4 +58,11 @@ config IIO_ST_ACCEL_SPI_3AXIS
depends on IIO_ST_ACCEL_3AXIS
depends on IIO_ST_SENSORS_SPI
+config KXSD9
+ tristate "Kionix KXSD9 Accelerometer Driver"
+ depends on SPI
+ help
+ Say yes here to build support for the Kionix KXSD9 accelerometer.
+ Currently this only supports the device via an SPI interface.
+
endmenu
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 87d8fa26489..c48d15f2561 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -2,7 +2,10 @@
# Makefile for industrial I/O accelerometer drivers
#
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_BMA180) += bma180.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
+obj-$(CONFIG_KXSD9) += kxsd9.o
obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
st_accel-y := st_accel_core.o
@@ -10,5 +13,3 @@ st_accel-$(CONFIG_IIO_BUFFER) += st_accel_buffer.o
obj-$(CONFIG_IIO_ST_ACCEL_I2C_3AXIS) += st_accel_i2c.o
obj-$(CONFIG_IIO_ST_ACCEL_SPI_3AXIS) += st_accel_spi.o
-
-obj-$(CONFIG_KXSD9) += kxsd9.o
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
new file mode 100644
index 00000000000..12e32e6b410
--- /dev/null
+++ b/drivers/iio/accel/bma180.c
@@ -0,0 +1,676 @@
+/*
+ * bma180.c - IIO driver for Bosch BMA180 triaxial acceleration sensor
+ *
+ * Copyright 2013 Oleksandr Kravchenko <x0199363@ti.com>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define BMA180_DRV_NAME "bma180"
+#define BMA180_IRQ_NAME "bma180_event"
+
+/* Register set */
+#define BMA180_CHIP_ID 0x00 /* Need to distinguish BMA180 from other */
+#define BMA180_ACC_X_LSB 0x02 /* First of 6 registers of accel data */
+#define BMA180_CTRL_REG0 0x0d
+#define BMA180_RESET 0x10
+#define BMA180_BW_TCS 0x20
+#define BMA180_CTRL_REG3 0x21
+#define BMA180_TCO_Z 0x30
+#define BMA180_OFFSET_LSB1 0x35
+
+/* BMA180_CTRL_REG0 bits */
+#define BMA180_DIS_WAKE_UP BIT(0) /* Disable wake up mode */
+#define BMA180_SLEEP BIT(1) /* 1 - chip will sleep */
+#define BMA180_EE_W BIT(4) /* Unlock writing to addr from 0x20 */
+#define BMA180_RESET_INT BIT(6) /* Reset pending interrupts */
+
+/* BMA180_CTRL_REG3 bits */
+#define BMA180_NEW_DATA_INT BIT(1) /* Intr every new accel data is ready */
+
+/* BMA180_OFFSET_LSB1 skipping mode bit */
+#define BMA180_SMP_SKIP BIT(0)
+
+/* Bit masks for registers bit fields */
+#define BMA180_RANGE 0x0e /* Range of measured accel values*/
+#define BMA180_BW 0xf0 /* Accel bandwidth */
+#define BMA180_MODE_CONFIG 0x03 /* Config operation modes */
+
+/* We have to write this value in reset register to do soft reset */
+#define BMA180_RESET_VAL 0xb6
+
+#define BMA_180_ID_REG_VAL 0x03
+
+/* Chip power modes */
+#define BMA180_LOW_NOISE 0x00
+#define BMA180_LOW_POWER 0x03
+
+#define BMA180_LOW_NOISE_STR "low_noise"
+#define BMA180_LOW_POWER_STR "low_power"
+
+/* Defaults values */
+#define BMA180_DEF_PMODE 0
+#define BMA180_DEF_BW 20
+#define BMA180_DEF_SCALE 250
+
+/* Available values for sysfs */
+#define BMA180_FLP_FREQ_AVAILABLE \
+ "10 20 40 75 150 300"
+#define BMA180_SCALE_AVAILABLE \
+ "0.000130 0.000190 0.000250 0.000380 0.000500 0.000990 0.001980"
+
+struct bma180_data {
+ struct i2c_client *client;
+ struct iio_trigger *trig;
+ struct mutex mutex;
+ int sleep_state;
+ int scale;
+ int bw;
+ int pmode;
+ char *buff;
+};
+
+enum bma180_axis {
+ AXIS_X,
+ AXIS_Y,
+ AXIS_Z,
+};
+
+static int bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */
+static int scale_table[] = { 130, 190, 250, 380, 500, 990, 1980 };
+
+static int bma180_get_acc_reg(struct bma180_data *data, enum bma180_axis axis)
+{
+ u8 reg = BMA180_ACC_X_LSB + axis * 2;
+ int ret;
+
+ if (data->sleep_state)
+ return -EBUSY;
+
+ ret = i2c_smbus_read_word_data(data->client, reg);
+ if (ret < 0)
+ dev_err(&data->client->dev,
+ "failed to read accel_%c registers\n", 'x' + axis);
+
+ return ret;
+}
+
+static int bma180_set_bits(struct bma180_data *data, u8 reg, u8 mask, u8 val)
+{
+ int ret = i2c_smbus_read_byte_data(data->client, reg);
+ u8 reg_val = (ret & ~mask) | (val << (ffs(mask) - 1));
+
+ if (ret < 0)
+ return ret;
+
+ return i2c_smbus_write_byte_data(data->client, reg, reg_val);
+}
+
+static int bma180_reset_intr(struct bma180_data *data)
+{
+ int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_RESET_INT, 1);
+
+ if (ret)
+ dev_err(&data->client->dev, "failed to reset interrupt\n");
+
+ return ret;
+}
+
+static int bma180_set_new_data_intr_state(struct bma180_data *data, int state)
+{
+ u8 reg_val = state ? BMA180_NEW_DATA_INT : 0x00;
+ int ret = i2c_smbus_write_byte_data(data->client, BMA180_CTRL_REG3,
+ reg_val);
+
+ if (ret)
+ goto err;
+ ret = bma180_reset_intr(data);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ dev_err(&data->client->dev,
+ "failed to set new data interrupt state %d\n", state);
+ return ret;
+}
+
+static int bma180_set_sleep_state(struct bma180_data *data, int state)
+{
+ int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_SLEEP, state);
+
+ if (ret) {
+ dev_err(&data->client->dev,
+ "failed to set sleep state %d\n", state);
+ return ret;
+ }
+ data->sleep_state = state;
+
+ return 0;
+}
+
+static int bma180_set_ee_writing_state(struct bma180_data *data, int state)
+{
+ int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_EE_W, state);
+
+ if (ret)
+ dev_err(&data->client->dev,
+ "failed to set ee writing state %d\n", state);
+
+ return ret;
+}
+
+static int bma180_set_bw(struct bma180_data *data, int val)
+{
+ int ret, i;
+
+ if (data->sleep_state)
+ return -EBUSY;
+
+ for (i = 0; i < ARRAY_SIZE(bw_table); ++i) {
+ if (bw_table[i] == val) {
+ ret = bma180_set_bits(data,
+ BMA180_BW_TCS, BMA180_BW, i);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "failed to set bandwidth\n");
+ return ret;
+ }
+ data->bw = val;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int bma180_set_scale(struct bma180_data *data, int val)
+{
+ int ret, i;
+
+ if (data->sleep_state)
+ return -EBUSY;
+
+ for (i = 0; i < ARRAY_SIZE(scale_table); ++i)
+ if (scale_table[i] == val) {
+ ret = bma180_set_bits(data,
+ BMA180_OFFSET_LSB1, BMA180_RANGE, i);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "failed to set scale\n");
+ return ret;
+ }
+ data->scale = val;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int bma180_set_pmode(struct bma180_data *data, int mode)
+{
+ u8 reg_val = mode ? BMA180_LOW_POWER : BMA180_LOW_NOISE;
+ int ret = bma180_set_bits(data, BMA180_TCO_Z, BMA180_MODE_CONFIG,
+ reg_val);
+
+ if (ret) {
+ dev_err(&data->client->dev, "failed to set power mode\n");
+ return ret;
+ }
+ data->pmode = mode;
+
+ return 0;
+}
+
+static int bma180_soft_reset(struct bma180_data *data)
+{
+ int ret = i2c_smbus_write_byte_data(data->client,
+ BMA180_RESET, BMA180_RESET_VAL);
+
+ if (ret)
+ dev_err(&data->client->dev, "failed to reset the chip\n");
+
+ return ret;
+}
+
+static int bma180_chip_init(struct bma180_data *data)
+{
+ /* Try to read chip_id register. It must return 0x03. */
+ int ret = i2c_smbus_read_byte_data(data->client, BMA180_CHIP_ID);
+
+ if (ret < 0)
+ goto err;
+ if (ret != BMA_180_ID_REG_VAL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ ret = bma180_soft_reset(data);
+ if (ret)
+ goto err;
+ /*
+ * No serial transaction should occur within minimum 10 us
+ * after soft_reset command
+ */
+ msleep(20);
+
+ ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_DIS_WAKE_UP, 1);
+ if (ret)
+ goto err;
+ ret = bma180_set_ee_writing_state(data, 1);
+ if (ret)
+ goto err;
+ ret = bma180_set_new_data_intr_state(data, 0);
+ if (ret)
+ goto err;
+ ret = bma180_set_bits(data, BMA180_OFFSET_LSB1, BMA180_SMP_SKIP, 1);
+ if (ret)
+ goto err;
+ ret = bma180_set_pmode(data, BMA180_DEF_PMODE);
+ if (ret)
+ goto err;
+ ret = bma180_set_bw(data, BMA180_DEF_BW);
+ if (ret)
+ goto err;
+ ret = bma180_set_scale(data, BMA180_DEF_SCALE);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ dev_err(&data->client->dev, "failed to init the chip\n");
+ return ret;
+}
+
+static void bma180_chip_disable(struct bma180_data *data)
+{
+ if (bma180_set_new_data_intr_state(data, 0))
+ goto err;
+ if (bma180_set_ee_writing_state(data, 0))
+ goto err;
+ if (bma180_set_sleep_state(data, 1))
+ goto err;
+
+ return;
+
+err:
+ dev_err(&data->client->dev, "failed to disable the chip\n");
+}
+
+static IIO_CONST_ATTR(in_accel_filter_low_pass_3db_frequency_available,
+ BMA180_FLP_FREQ_AVAILABLE);
+static IIO_CONST_ATTR(in_accel_scale_available, BMA180_SCALE_AVAILABLE);
+
+static struct attribute *bma180_attributes[] = {
+ &iio_const_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr,
+ &iio_const_attr_in_accel_scale_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group bma180_attrs_group = {
+ .attrs = bma180_attributes,
+};
+
+static int bma180_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2,
+ long mask)
+{
+ struct bma180_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&data->mutex);
+ if (iio_buffer_enabled(indio_dev))
+ ret = -EBUSY;
+ else
+ ret = bma180_get_acc_reg(data, chan->scan_index);
+ mutex_unlock(&data->mutex);
+ if (ret < 0)
+ return ret;
+ *val = (s16)ret >> chan->scan_type.shift;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ *val = data->bw;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = data->scale;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bma180_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+ struct bma180_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (val)
+ return -EINVAL;
+ mutex_lock(&data->mutex);
+ ret = bma180_set_scale(data, val2);
+ mutex_unlock(&data->mutex);
+ return ret;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ mutex_lock(&data->mutex);
+ ret = bma180_set_bw(data, val);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bma180_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct bma180_data *data = iio_priv(indio_dev);
+
+ if (data->buff)
+ devm_kfree(&indio_dev->dev, data->buff);
+ data->buff = devm_kzalloc(&indio_dev->dev,
+ indio_dev->scan_bytes, GFP_KERNEL);
+ if (!data->buff)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static const struct iio_info bma180_info = {
+ .attrs = &bma180_attrs_group,
+ .read_raw = bma180_read_raw,
+ .write_raw = bma180_write_raw,
+ .update_scan_mode = bma180_update_scan_mode,
+ .driver_module = THIS_MODULE,
+};
+
+static const char * const bma180_power_modes[] = {
+ BMA180_LOW_NOISE_STR,
+ BMA180_LOW_POWER_STR,
+};
+
+static int bma180_get_power_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct bma180_data *data = iio_priv(indio_dev);
+
+ return data->pmode;
+}
+
+static int bma180_set_power_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, unsigned int mode)
+{
+ struct bma180_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = bma180_set_pmode(data, mode);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct iio_enum bma180_power_mode_enum = {
+ .items = bma180_power_modes,
+ .num_items = ARRAY_SIZE(bma180_power_modes),
+ .get = bma180_get_power_mode,
+ .set = bma180_set_power_mode,
+};
+
+static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
+ IIO_ENUM("power_mode", true, &bma180_power_mode_enum),
+ IIO_ENUM_AVAILABLE("power_mode", &bma180_power_mode_enum),
+ { },
+};
+
+#define BMA180_CHANNEL(_index) { \
+ .type = IIO_ACCEL, \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = (_index), \
+ .scan_type = IIO_ST('s', 14, 16, 2), \
+ .ext_info = bma180_ext_info, \
+}
+
+static const struct iio_chan_spec bma180_channels[] = {
+ BMA180_CHANNEL(AXIS_X),
+ BMA180_CHANNEL(AXIS_Y),
+ BMA180_CHANNEL(AXIS_Z),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static irqreturn_t bma180_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct bma180_data *data = iio_priv(indio_dev);
+ int bit, ret, i = 0;
+
+ mutex_lock(&data->mutex);
+ if (indio_dev->scan_timestamp) {
+ ret = indio_dev->scan_bytes / sizeof(s64) - 1;
+ ((s64 *)data->buff)[ret] = iio_get_time_ns();
+ }
+
+ for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+ indio_dev->masklength) {
+ ret = bma180_get_acc_reg(data, bit);
+ if (ret < 0) {
+ mutex_unlock(&data->mutex);
+ goto err;
+ }
+ ((s16 *)data->buff)[i++] = ret;
+ }
+ mutex_unlock(&data->mutex);
+
+ iio_push_to_buffers(indio_dev, (u8 *)data->buff);
+err:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int bma180_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct bma180_data *data = iio_priv(indio_dev);
+
+ return bma180_set_new_data_intr_state(data, state);
+}
+
+static int bma180_trig_try_reen(struct iio_trigger *trig)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct bma180_data *data = iio_priv(indio_dev);
+
+ return bma180_reset_intr(data);
+}
+
+static const struct iio_trigger_ops bma180_trigger_ops = {
+ .set_trigger_state = bma180_data_rdy_trigger_set_state,
+ .try_reenable = bma180_trig_try_reen,
+ .owner = THIS_MODULE,
+};
+
+static int bma180_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct bma180_data *data;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ ret = bma180_chip_init(data);
+ if (ret < 0)
+ goto err_chip_disable;
+
+ mutex_init(&data->mutex);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->channels = bma180_channels;
+ indio_dev->num_channels = ARRAY_SIZE(bma180_channels);
+ indio_dev->name = BMA180_DRV_NAME;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &bma180_info;
+
+ trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, indio_dev->id);
+ if (!trig) {
+ ret = -ENOMEM;
+ goto err_chip_disable;
+ }
+
+ ret = devm_request_irq(&client->dev, client->irq,
+ iio_trigger_generic_data_rdy_poll,
+ IRQF_TRIGGER_RISING, BMA180_IRQ_NAME, trig);
+ if (ret) {
+ dev_err(&client->dev, "unable to request IRQ\n");
+ goto err_trigger_free;
+ }
+
+ trig->dev.parent = &client->dev;
+ trig->ops = &bma180_trigger_ops;
+ iio_trigger_set_drvdata(trig, indio_dev);
+ data->trig = trig;
+ indio_dev->trig = trig;
+
+ ret = iio_trigger_register(trig);
+ if (ret)
+ goto err_trigger_free;
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ bma180_trigger_handler, NULL);
+ if (ret < 0) {
+ dev_err(&client->dev, "unable to setup iio triggered buffer\n");
+ goto err_trigger_unregister;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "unable to register iio device\n");
+ goto err_buffer_cleanup;
+ }
+
+ return 0;
+
+err_buffer_cleanup:
+ iio_triggered_buffer_cleanup(indio_dev);
+err_trigger_unregister:
+ iio_trigger_unregister(trig);
+err_trigger_free:
+ iio_trigger_free(trig);
+err_chip_disable:
+ bma180_chip_disable(data);
+
+ return ret;
+}
+
+static int bma180_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct bma180_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ iio_trigger_unregister(data->trig);
+ iio_trigger_free(data->trig);
+
+ mutex_lock(&data->mutex);
+ bma180_chip_disable(data);
+ mutex_unlock(&data->mutex);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bma180_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct bma180_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = bma180_set_sleep_state(data, 1);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int bma180_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct bma180_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = bma180_set_sleep_state(data, 0);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
+#define BMA180_PM_OPS (&bma180_pm_ops)
+#else
+#define BMA180_PM_OPS NULL
+#endif
+
+static struct i2c_device_id bma180_id[] = {
+ { BMA180_DRV_NAME, 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, bma180_id);
+
+static struct i2c_driver bma180_driver = {
+ .driver = {
+ .name = BMA180_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = BMA180_PM_OPS,
+ },
+ .probe = bma180_probe,
+ .remove = bma180_remove,
+ .id_table = bma180_id,
+};
+
+module_i2c_driver(bma180_driver);
+
+MODULE_AUTHOR("Kravchenko Oleksandr <x0199363@ti.com>");
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("Bosch BMA180 triaxial acceleration sensor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index bbcbd7101f3..46d22f3fb1a 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -30,10 +30,6 @@
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
-/*Format: HID-SENSOR-usage_id_in_hex*/
-/*Usage ID from spec for Accelerometer-3D: 0x200073*/
-#define DRIVER_NAME "HID-SENSOR-200073"
-
enum accel_3d_channel {
CHANNEL_SCAN_INDEX_X,
CHANNEL_SCAN_INDEX_Y,
@@ -179,18 +175,10 @@ static int accel_3d_write_raw(struct iio_dev *indio_dev,
return ret;
}
-static int accel_3d_write_raw_get_fmt(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- long mask)
-{
- return IIO_VAL_INT_PLUS_MICRO;
-}
-
static const struct iio_info accel_3d_info = {
.driver_module = THIS_MODULE,
.read_raw = &accel_3d_read_raw,
.write_raw = &accel_3d_write_raw,
- .write_raw_get_fmt = &accel_3d_write_raw_get_fmt,
};
/* Function to push data to buffer */
@@ -286,11 +274,11 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
- indio_dev = iio_device_alloc(sizeof(struct accel_3d_state));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&pdev->dev,
+ sizeof(struct accel_3d_state));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
platform_set_drvdata(pdev, indio_dev);
accel_state = iio_priv(indio_dev);
@@ -302,15 +290,14 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
&accel_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
- goto error_free_dev;
+ return ret;
}
channels = kmemdup(accel_3d_channels, sizeof(accel_3d_channels),
GFP_KERNEL);
if (!channels) {
- ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
- goto error_free_dev;
+ return -ENOMEM;
}
ret = accel_3d_parse_report(pdev, hsdev, channels,
@@ -367,9 +354,6 @@ error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
error_free_dev_mem:
kfree(indio_dev->channels);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -384,14 +368,23 @@ static int hid_accel_3d_remove(struct platform_device *pdev)
hid_sensor_remove_trigger(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
kfree(indio_dev->channels);
- iio_device_free(indio_dev);
return 0;
}
+static struct platform_device_id hid_accel_3d_ids[] = {
+ {
+ /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+ .name = "HID-SENSOR-200073",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_accel_3d_ids);
+
static struct platform_driver hid_accel_3d_platform_driver = {
+ .id_table = hid_accel_3d_ids,
.driver = {
- .name = DRIVER_NAME,
+ .name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
.probe = hid_accel_3d_probe,
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index 7229645bf1d..709c13259f1 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -224,11 +224,10 @@ static int kxsd9_probe(struct spi_device *spi)
struct kxsd9_state *st;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
@@ -247,20 +246,14 @@ static int kxsd9_probe(struct spi_device *spi)
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_dev;
+ return ret;
return 0;
-
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
- return ret;
}
static int kxsd9_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index 37949b94377..c3877630b2e 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -25,7 +25,16 @@
#define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel"
#define LSM330_ACCEL_DEV_NAME "lsm330_accel"
-int st_accel_common_probe(struct iio_dev *indio_dev);
+/**
+* struct st_sensors_platform_data - default accel platform data
+* @drdy_int_pin: default accel DRDY is available on INT1 pin.
+*/
+static const struct st_sensors_platform_data default_accel_pdata = {
+ .drdy_int_pin = 1,
+};
+
+int st_accel_common_probe(struct iio_dev *indio_dev,
+ struct st_sensors_platform_data *pdata);
void st_accel_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index 4aec121261d..1458343f6f3 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -65,7 +65,8 @@
#define ST_ACCEL_1_BDU_ADDR 0x23
#define ST_ACCEL_1_BDU_MASK 0x80
#define ST_ACCEL_1_DRDY_IRQ_ADDR 0x22
-#define ST_ACCEL_1_DRDY_IRQ_MASK 0x10
+#define ST_ACCEL_1_DRDY_IRQ_INT1_MASK 0x10
+#define ST_ACCEL_1_DRDY_IRQ_INT2_MASK 0x08
#define ST_ACCEL_1_MULTIREAD_BIT true
/* CUSTOM VALUES FOR SENSOR 2 */
@@ -89,7 +90,8 @@
#define ST_ACCEL_2_BDU_ADDR 0x23
#define ST_ACCEL_2_BDU_MASK 0x80
#define ST_ACCEL_2_DRDY_IRQ_ADDR 0x22
-#define ST_ACCEL_2_DRDY_IRQ_MASK 0x02
+#define ST_ACCEL_2_DRDY_IRQ_INT1_MASK 0x02
+#define ST_ACCEL_2_DRDY_IRQ_INT2_MASK 0x10
#define ST_ACCEL_2_MULTIREAD_BIT true
/* CUSTOM VALUES FOR SENSOR 3 */
@@ -121,7 +123,8 @@
#define ST_ACCEL_3_BDU_ADDR 0x20
#define ST_ACCEL_3_BDU_MASK 0x08
#define ST_ACCEL_3_DRDY_IRQ_ADDR 0x23
-#define ST_ACCEL_3_DRDY_IRQ_MASK 0x80
+#define ST_ACCEL_3_DRDY_IRQ_INT1_MASK 0x80
+#define ST_ACCEL_3_DRDY_IRQ_INT2_MASK 0x00
#define ST_ACCEL_3_IG1_EN_ADDR 0x23
#define ST_ACCEL_3_IG1_EN_MASK 0x08
#define ST_ACCEL_3_MULTIREAD_BIT false
@@ -224,7 +227,8 @@ static const struct st_sensors st_accel_sensors[] = {
},
.drdy_irq = {
.addr = ST_ACCEL_1_DRDY_IRQ_ADDR,
- .mask = ST_ACCEL_1_DRDY_IRQ_MASK,
+ .mask_int1 = ST_ACCEL_1_DRDY_IRQ_INT1_MASK,
+ .mask_int2 = ST_ACCEL_1_DRDY_IRQ_INT2_MASK,
},
.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
.bootime = 2,
@@ -285,7 +289,8 @@ static const struct st_sensors st_accel_sensors[] = {
},
.drdy_irq = {
.addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
- .mask = ST_ACCEL_2_DRDY_IRQ_MASK,
+ .mask_int1 = ST_ACCEL_2_DRDY_IRQ_INT1_MASK,
+ .mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK,
},
.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
.bootime = 2,
@@ -358,7 +363,8 @@ static const struct st_sensors st_accel_sensors[] = {
},
.drdy_irq = {
.addr = ST_ACCEL_3_DRDY_IRQ_ADDR,
- .mask = ST_ACCEL_3_DRDY_IRQ_MASK,
+ .mask_int1 = ST_ACCEL_3_DRDY_IRQ_INT1_MASK,
+ .mask_int2 = ST_ACCEL_3_DRDY_IRQ_INT2_MASK,
.ig1 = {
.en_addr = ST_ACCEL_3_IG1_EN_ADDR,
.en_mask = ST_ACCEL_3_IG1_EN_MASK,
@@ -443,7 +449,8 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
#define ST_ACCEL_TRIGGER_OPS NULL
#endif
-int st_accel_common_probe(struct iio_dev *indio_dev)
+int st_accel_common_probe(struct iio_dev *indio_dev,
+ struct st_sensors_platform_data *plat_data)
{
int err;
struct st_sensor_data *adata = iio_priv(indio_dev);
@@ -465,7 +472,11 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
&adata->sensor->fs.fs_avl[0];
adata->odr = adata->sensor->odr.odr_avl[0].hz;
- err = st_sensors_init_sensor(indio_dev);
+ if (!plat_data)
+ plat_data =
+ (struct st_sensors_platform_data *)&default_accel_pdata;
+
+ err = st_sensors_init_sensor(indio_dev, plat_data);
if (err < 0)
goto st_accel_common_probe_error;
@@ -506,7 +517,6 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
st_sensors_deallocate_trigger(indio_dev);
st_accel_deallocate_ring(indio_dev);
}
- iio_device_free(indio_dev);
}
EXPORT_SYMBOL(st_accel_common_remove);
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index ffc9d097e48..d7bedbdfc81 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -25,27 +25,20 @@ static int st_accel_i2c_probe(struct i2c_client *client,
struct st_sensor_data *adata;
int err;
- indio_dev = iio_device_alloc(sizeof(*adata));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto iio_device_alloc_error;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata));
+ if (!indio_dev)
+ return -ENOMEM;
adata = iio_priv(indio_dev);
adata->dev = &client->dev;
st_sensors_i2c_configure(indio_dev, client, adata);
- err = st_accel_common_probe(indio_dev);
+ err = st_accel_common_probe(indio_dev, client->dev.platform_data);
if (err < 0)
- goto st_accel_common_probe_error;
+ return err;
return 0;
-
-st_accel_common_probe_error:
- iio_device_free(indio_dev);
-iio_device_alloc_error:
- return err;
}
static int st_accel_i2c_remove(struct i2c_client *client)
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index 22b35bfea7d..195639646e3 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -24,27 +24,20 @@ static int st_accel_spi_probe(struct spi_device *spi)
struct st_sensor_data *adata;
int err;
- indio_dev = iio_device_alloc(sizeof(*adata));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto iio_device_alloc_error;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adata));
+ if (!indio_dev)
+ return -ENOMEM;
adata = iio_priv(indio_dev);
adata->dev = &spi->dev;
st_sensors_spi_configure(indio_dev, spi, adata);
- err = st_accel_common_probe(indio_dev);
+ err = st_accel_common_probe(indio_dev, spi->dev.platform_data);
if (err < 0)
- goto st_accel_common_probe_error;
+ return err;
return 0;
-
-st_accel_common_probe_error:
- iio_device_free(indio_dev);
-iio_device_alloc_error:
- return err;
}
static int st_accel_spi_remove(struct spi_device *spi)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 93129ec4b64..09371cbc9dc 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1,6 +1,8 @@
#
# ADC drivers
#
+# When adding new entries keep the list in alphabetical order
+
menu "Analog to digital converters"
config AD_SIGMA_DELTA
@@ -30,17 +32,20 @@ config AD7298
To compile this driver as a module, choose M here: the
module will be called ad7298.
-config AD7923
- tristate "Analog Devices AD7923 and similar ADCs driver"
+config AD7476
+ tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
- Say yes here to build support for Analog Devices
- AD7904, AD7914, AD7923, AD7924 4 Channel ADCs.
+ Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
+ AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
+ AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
+
+ If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
- module will be called ad7923.
+ module will be called ad7476.
config AD7791
tristate "Analog Devices AD7791 ADC driver"
@@ -66,33 +71,30 @@ config AD7793
To compile this driver as a module, choose M here: the
module will be called AD7793.
-config AD7476
- tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
+config AD7887
+ tristate "Analog Devices AD7887 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
- Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
- AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
- AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
-
+ Say yes here to build support for Analog Devices
+ AD7887 SPI analog to digital converter (ADC).
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
- module will be called ad7476.
+ module will be called ad7887.
-config AD7887
- tristate "Analog Devices AD7887 ADC driver"
+config AD7923
+ tristate "Analog Devices AD7923 and similar ADCs driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices
- AD7887 SPI analog to digital converter (ADC).
- If unsure, say N (but it's safe to say "Y").
+ AD7904, AD7914, AD7923, AD7924 4 Channel ADCs.
To compile this driver as a module, choose M here: the
- module will be called ad7887.
+ module will be called ad7923.
config AT91_ADC
tristate "Atmel AT91 ADC"
@@ -143,6 +145,15 @@ config MCP320X
This driver can also be built as a module. If so, the module will be
called mcp320x.
+config NAU7802
+ tristate "Nuvoton NAU7802 ADC driver"
+ depends on I2C
+ help
+ Say yes here to build support for Nuvoton NAU7802 ADC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called nau7802.
+
config TI_ADC081C
tristate "Texas Instruments ADC081C021/027"
depends on I2C
@@ -154,12 +165,26 @@ config TI_ADC081C
called ti-adc081c.
config TI_AM335X_ADC
- tristate "TI's ADC driver"
+ tristate "TI's AM335X ADC driver"
depends on MFD_TI_AM335X_TSCADC
help
Say yes here to build support for Texas Instruments ADC
driver which is also a MFD client.
+config TWL6030_GPADC
+ tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
+ depends on TWL4030_CORE
+ default n
+ help
+ Say yes here if you want support for the TWL6030/TWL6032 General
+ Purpose A/D Converter. This will add support for battery type
+ detection, battery voltage and temperature measurement, die
+ temperature measurement, system supply voltage, audio accessory,
+ USB ID detection.
+
+ This driver can also be built as a module. If so, the module will be
+ called twl6030-gpadc.
+
config VIPERBOARD_ADC
tristate "Viperboard ADC support"
depends on MFD_VIPERBOARD && USB
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 8f475d31fe4..33656ef7d1f 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -2,6 +2,7 @@
# Makefile for IIO ADC drivers
#
+# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7298) += ad7298.o
@@ -15,6 +16,8 @@ obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
+obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
+obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index c2744a75c3b..371731df163 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -399,17 +399,17 @@ static int ad7266_probe(struct spi_device *spi)
unsigned int i;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = regulator_get(&spi->dev, "vref");
+ st->reg = devm_regulator_get(&spi->dev, "vref");
if (!IS_ERR_OR_NULL(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
@@ -489,11 +489,6 @@ error_free_gpios:
error_disable_reg:
if (!IS_ERR_OR_NULL(st->reg))
regulator_disable(st->reg);
-error_put_reg:
- if (!IS_ERR_OR_NULL(st->reg))
- regulator_put(st->reg);
-
- iio_device_free(indio_dev);
return ret;
}
@@ -507,11 +502,8 @@ static int ad7266_remove(struct spi_device *spi)
iio_triggered_buffer_cleanup(indio_dev);
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
- if (!IS_ERR_OR_NULL(st->reg)) {
+ if (!IS_ERR_OR_NULL(st->reg))
regulator_disable(st->reg);
- regulator_put(st->reg);
- }
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
index 03b77189dbf..85d1481c312 100644
--- a/drivers/iio/adc/ad7298.c
+++ b/drivers/iio/adc/ad7298.c
@@ -296,9 +296,10 @@ static int ad7298_probe(struct spi_device *spi)
{
struct ad7298_platform_data *pdata = spi->dev.platform_data;
struct ad7298_state *st;
- struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
+ struct iio_dev *indio_dev;
int ret;
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -308,14 +309,13 @@ static int ad7298_probe(struct spi_device *spi)
st->ext_ref = AD7298_EXTREF;
if (st->ext_ref) {
- st->reg = regulator_get(&spi->dev, "vref");
- if (IS_ERR(st->reg)) {
- ret = PTR_ERR(st->reg);
- goto error_free;
- }
+ st->reg = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
+
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
}
spi_set_drvdata(spi, indio_dev);
@@ -361,11 +361,6 @@ error_cleanup_ring:
error_disable_reg:
if (st->ext_ref)
regulator_disable(st->reg);
-error_put_reg:
- if (st->ext_ref)
- regulator_put(st->reg);
-error_free:
- iio_device_free(indio_dev);
return ret;
}
@@ -377,11 +372,8 @@ static int ad7298_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
- if (st->ext_ref) {
+ if (st->ext_ref)
regulator_disable(st->reg);
- regulator_put(st->reg);
- }
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 2e98bef4af6..6d2b1d8d1a1 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -213,24 +213,21 @@ static int ad7476_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
st = iio_priv(indio_dev);
st->chip_info =
&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
- st->reg = regulator_get(&spi->dev, "vcc");
- if (IS_ERR(st->reg)) {
- ret = PTR_ERR(st->reg);
- goto error_free_dev;
- }
+ st->reg = devm_regulator_get(&spi->dev, "vcc");
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
spi_set_drvdata(spi, indio_dev);
@@ -268,12 +265,7 @@ error_ring_unregister:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
-error_put_reg:
- regulator_put(st->reg);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -285,8 +277,6 @@ static int ad7476_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg);
- regulator_put(st->reg);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c
index 5e8d1da6887..c20203577d2 100644
--- a/drivers/iio/adc/ad7791.c
+++ b/drivers/iio/adc/ad7791.c
@@ -361,21 +361,19 @@ static int ad7791_probe(struct spi_device *spi)
return -ENXIO;
}
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = regulator_get(&spi->dev, "refin");
- if (IS_ERR(st->reg)) {
- ret = PTR_ERR(st->reg);
- goto err_iio_free;
- }
+ st->reg = devm_regulator_get(&spi->dev, "refin");
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
st->info = &ad7791_chip_infos[spi_get_device_id(spi)->driver_data];
ad_sd_init(&st->sd, indio_dev, spi, &ad7791_sigma_delta_info);
@@ -410,10 +408,6 @@ error_remove_trigger:
ad_sd_cleanup_buffer_and_trigger(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
-error_put_reg:
- regulator_put(st->reg);
-err_iio_free:
- iio_device_free(indio_dev);
return ret;
}
@@ -427,9 +421,6 @@ static int ad7791_remove(struct spi_device *spi)
ad_sd_cleanup_buffer_and_trigger(indio_dev);
regulator_disable(st->reg);
- regulator_put(st->reg);
-
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c
index 334e31ff7a4..4dddeabdfbb 100644
--- a/drivers/iio/adc/ad7793.c
+++ b/drivers/iio/adc/ad7793.c
@@ -757,7 +757,7 @@ static int ad7793_probe(struct spi_device *spi)
return -ENODEV;
}
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -766,15 +766,13 @@ static int ad7793_probe(struct spi_device *spi)
ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info);
if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
- st->reg = regulator_get(&spi->dev, "refin");
- if (IS_ERR(st->reg)) {
- ret = PTR_ERR(st->reg);
- goto error_device_free;
- }
+ st->reg = devm_regulator_get(&spi->dev, "refin");
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
vref_mv = regulator_get_voltage(st->reg);
if (vref_mv < 0) {
@@ -818,11 +816,6 @@ error_remove_trigger:
error_disable_reg:
if (pdata->refsel != AD7793_REFSEL_INTERNAL)
regulator_disable(st->reg);
-error_put_reg:
- if (pdata->refsel != AD7793_REFSEL_INTERNAL)
- regulator_put(st->reg);
-error_device_free:
- iio_device_free(indio_dev);
return ret;
}
@@ -836,12 +829,8 @@ static int ad7793_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
ad_sd_cleanup_buffer_and_trigger(indio_dev);
- if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
+ if (pdata->refsel != AD7793_REFSEL_INTERNAL)
regulator_disable(st->reg);
- regulator_put(st->reg);
- }
-
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c
index dd15a5b0f70..9dd077b7875 100644
--- a/drivers/iio/adc/ad7887.c
+++ b/drivers/iio/adc/ad7887.c
@@ -237,25 +237,24 @@ static int ad7887_probe(struct spi_device *spi)
{
struct ad7887_platform_data *pdata = spi->dev.platform_data;
struct ad7887_state *st;
- struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
+ struct iio_dev *indio_dev;
uint8_t mode;
int ret;
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
if (!pdata || !pdata->use_onchip_ref) {
- st->reg = regulator_get(&spi->dev, "vref");
- if (IS_ERR(st->reg)) {
- ret = PTR_ERR(st->reg);
- goto error_free;
- }
+ st->reg = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
}
st->chip_info =
@@ -331,11 +330,6 @@ error_unregister_ring:
error_disable_reg:
if (st->reg)
regulator_disable(st->reg);
-error_put_reg:
- if (st->reg)
- regulator_put(st->reg);
-error_free:
- iio_device_free(indio_dev);
return ret;
}
@@ -347,11 +341,8 @@ static int ad7887_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
- if (st->reg) {
+ if (st->reg)
regulator_disable(st->reg);
- regulator_put(st->reg);
- }
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c
index 97fa0d3dc4a..4108dbb28c3 100644
--- a/drivers/iio/adc/ad7923.c
+++ b/drivers/iio/adc/ad7923.c
@@ -275,10 +275,11 @@ static const struct iio_info ad7923_info = {
static int ad7923_probe(struct spi_device *spi)
{
struct ad7923_state *st;
- struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
+ struct iio_dev *indio_dev;
const struct ad7923_chip_info *info;
int ret;
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -311,14 +312,13 @@ static int ad7923_probe(struct spi_device *spi)
spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
- st->reg = regulator_get(&spi->dev, "refin");
- if (IS_ERR(st->reg)) {
- ret = PTR_ERR(st->reg);
- goto error_free;
- }
+ st->reg = devm_regulator_get(&spi->dev, "refin");
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
+
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7923_trigger_handler, NULL);
@@ -335,10 +335,6 @@ error_cleanup_ring:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
-error_put_reg:
- regulator_put(st->reg);
-error_free:
- iio_device_free(indio_dev);
return ret;
}
@@ -351,8 +347,6 @@ static int ad7923_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg);
- regulator_put(st->reg);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index b6db6a0e09c..84be63bdf03 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -39,6 +39,10 @@
#define at91_adc_writel(st, reg, val) \
(writel_relaxed(val, st->reg_base + reg))
+struct at91_adc_caps {
+ struct at91_adc_reg_desc registers;
+};
+
struct at91_adc_state {
struct clk *adc_clk;
u16 *buffer;
@@ -62,6 +66,7 @@ struct at91_adc_state {
u32 res; /* resolution used for convertions */
bool low_res; /* the resolution corresponds to the lowest one */
wait_queue_head_t wq_data_avail;
+ struct at91_adc_caps *caps;
};
static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -429,6 +434,8 @@ ret:
return ret;
}
+static const struct of_device_id at91_adc_dt_ids[];
+
static int at91_adc_probe_dt(struct at91_adc_state *st,
struct platform_device *pdev)
{
@@ -441,6 +448,9 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
if (!node)
return -EINVAL;
+ st->caps = (struct at91_adc_caps *)
+ of_match_device(at91_adc_dt_ids, &pdev->dev)->data;
+
st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
@@ -481,43 +491,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
if (ret)
goto error_ret;
- st->registers = devm_kzalloc(&idev->dev,
- sizeof(struct at91_adc_reg_desc),
- GFP_KERNEL);
- if (!st->registers) {
- dev_err(&idev->dev, "Could not allocate register memory.\n");
- ret = -ENOMEM;
- goto error_ret;
- }
-
- if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
- dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
- ret = -EINVAL;
- goto error_ret;
- }
- st->registers->channel_base = prop;
-
- if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
- dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
- ret = -EINVAL;
- goto error_ret;
- }
- st->registers->drdy_mask = prop;
-
- if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
- dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
- ret = -EINVAL;
- goto error_ret;
- }
- st->registers->status_register = prop;
-
- if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
- dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
- ret = -EINVAL;
- goto error_ret;
- }
- st->registers->trigger_register = prop;
-
+ st->registers = &st->caps->registers;
st->trigger_number = of_get_child_count(node);
st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
sizeof(struct at91_adc_trigger),
@@ -589,11 +563,9 @@ static int at91_adc_probe(struct platform_device *pdev)
struct resource *res;
u32 reg;
- idev = iio_device_alloc(sizeof(struct at91_adc_state));
- if (idev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ idev = devm_iio_device_alloc(&pdev->dev, sizeof(struct at91_adc_state));
+ if (!idev)
+ return -ENOMEM;
st = iio_priv(idev);
@@ -604,8 +576,7 @@ static int at91_adc_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "No platform data available.\n");
- ret = -EINVAL;
- goto error_free_device;
+ return -EINVAL;
}
platform_set_drvdata(pdev, idev);
@@ -618,16 +589,14 @@ static int at91_adc_probe(struct platform_device *pdev)
st->irq = platform_get_irq(pdev, 0);
if (st->irq < 0) {
dev_err(&pdev->dev, "No IRQ ID is designated\n");
- ret = -ENODEV;
- goto error_free_device;
+ return -ENODEV;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
st->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(st->reg_base)) {
- ret = PTR_ERR(st->reg_base);
- goto error_free_device;
+ return PTR_ERR(st->reg_base);
}
/*
@@ -642,7 +611,7 @@ static int at91_adc_probe(struct platform_device *pdev)
idev);
if (ret) {
dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
- goto error_free_device;
+ return ret;
}
st->clk = devm_clk_get(&pdev->dev, "adc_clk");
@@ -703,8 +672,8 @@ static int at91_adc_probe(struct platform_device *pdev)
shtim = round_up((st->sample_hold_time * adc_clk /
1000000) - 1, 1);
- reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
- reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
+ reg = AT91_ADC_PRESCAL_(prsc) & st->registers->mr_prescal_mask;
+ reg |= AT91_ADC_STARTUP_(ticks) & st->registers->mr_startup_mask;
if (st->low_res)
reg |= AT91_ADC_LOWRES;
if (st->sleep_mode)
@@ -752,9 +721,6 @@ error_disable_clk:
clk_disable_unprepare(st->clk);
error_free_irq:
free_irq(st->irq, idev);
-error_free_device:
- iio_device_free(idev);
-error_ret:
return ret;
}
@@ -769,14 +735,49 @@ static int at91_adc_remove(struct platform_device *pdev)
clk_disable_unprepare(st->adc_clk);
clk_disable_unprepare(st->clk);
free_irq(st->irq, idev);
- iio_device_free(idev);
return 0;
}
#ifdef CONFIG_OF
+static struct at91_adc_caps at91sam9260_caps = {
+ .registers = {
+ .channel_base = AT91_ADC_CHR(0),
+ .drdy_mask = AT91_ADC_DRDY,
+ .status_register = AT91_ADC_SR,
+ .trigger_register = AT91_ADC_TRGR_9260,
+ .mr_prescal_mask = AT91_ADC_PRESCAL_9260,
+ .mr_startup_mask = AT91_ADC_STARTUP_9260,
+ },
+};
+
+static struct at91_adc_caps at91sam9g45_caps = {
+ .registers = {
+ .channel_base = AT91_ADC_CHR(0),
+ .drdy_mask = AT91_ADC_DRDY,
+ .status_register = AT91_ADC_SR,
+ .trigger_register = AT91_ADC_TRGR_9G45,
+ .mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
+ .mr_startup_mask = AT91_ADC_STARTUP_9G45,
+ },
+};
+
+static struct at91_adc_caps at91sam9x5_caps = {
+ .registers = {
+ .channel_base = AT91_ADC_CDR0_9X5,
+ .drdy_mask = AT91_ADC_SR_DRDY_9X5,
+ .status_register = AT91_ADC_SR_9X5,
+ .trigger_register = AT91_ADC_TRGR_9X5,
+ /* prescal mask is same as 9G45 */
+ .mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
+ .mr_startup_mask = AT91_ADC_STARTUP_9X5,
+ },
+};
+
static const struct of_device_id at91_adc_dt_ids[] = {
- { .compatible = "atmel,at91sam9260-adc" },
+ { .compatible = "atmel,at91sam9260-adc", .data = &at91sam9260_caps },
+ { .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps },
+ { .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps },
{},
};
MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 9809fc9a35d..d25b262193a 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -33,6 +33,7 @@
#include <linux/of_irq.h>
#include <linux/regulator/consumer.h>
#include <linux/of_platform.h>
+#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
@@ -261,7 +262,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (!np)
return ret;
- indio_dev = iio_device_alloc(sizeof(struct exynos_adc));
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc));
if (!indio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
@@ -271,23 +272,18 @@ static int exynos_adc_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
- if (IS_ERR(info->regs)) {
- ret = PTR_ERR(info->regs);
- goto err_iio;
- }
+ if (IS_ERR(info->regs))
+ return PTR_ERR(info->regs);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
info->enable_reg = devm_ioremap_resource(&pdev->dev, mem);
- if (IS_ERR(info->enable_reg)) {
- ret = PTR_ERR(info->enable_reg);
- goto err_iio;
- }
+ if (IS_ERR(info->enable_reg))
+ return PTR_ERR(info->enable_reg);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
- ret = irq;
- goto err_iio;
+ return irq;
}
info->irq = irq;
@@ -299,7 +295,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
info->irq);
- goto err_iio;
+ return ret;
}
writel(1, info->enable_reg);
@@ -365,8 +361,6 @@ err_iio_dev:
iio_device_unregister(indio_dev);
err_irq:
free_irq(info->irq, info);
-err_iio:
- iio_device_free(indio_dev);
return ret;
}
@@ -382,7 +376,6 @@ static int exynos_adc_remove(struct platform_device *pdev)
writel(0, info->enable_reg);
iio_device_unregister(indio_dev);
free_irq(info->irq, info);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c
index 62bc39e9c94..5c8c91595f4 100644
--- a/drivers/iio/adc/lp8788_adc.c
+++ b/drivers/iio/adc/lp8788_adc.c
@@ -194,7 +194,7 @@ static int lp8788_adc_probe(struct platform_device *pdev)
struct lp8788_adc *adc;
int ret;
- indio_dev = iio_device_alloc(sizeof(*adc));
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
@@ -205,7 +205,7 @@ static int lp8788_adc_probe(struct platform_device *pdev)
indio_dev->dev.of_node = pdev->dev.of_node;
ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc);
if (ret)
- goto err_iio_map;
+ return ret;
mutex_init(&adc->lock);
@@ -226,8 +226,6 @@ static int lp8788_adc_probe(struct platform_device *pdev)
err_iio_device:
iio_map_array_unregister(indio_dev);
-err_iio_map:
- iio_device_free(indio_dev);
return ret;
}
@@ -237,7 +235,6 @@ static int lp8788_adc_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
iio_map_array_unregister(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index f148d00b83f..4fb35d1d749 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -1498,16 +1498,15 @@ static int max1363_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
struct regulator *vref;
- indio_dev = iio_device_alloc(sizeof(struct max1363_state));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_out;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev,
+ sizeof(struct max1363_state));
+ if (!indio_dev)
+ return -ENOMEM;
indio_dev->dev.of_node = client->dev.of_node;
ret = iio_map_array_register(indio_dev, client->dev.platform_data);
if (ret < 0)
- goto error_free_device;
+ return ret;
st = iio_priv(indio_dev);
@@ -1590,9 +1589,6 @@ error_disable_reg:
regulator_disable(st->reg);
error_unregister_map:
iio_map_array_unregister(indio_dev);
-error_free_device:
- iio_device_free(indio_dev);
-error_out:
return ret;
}
@@ -1607,7 +1603,6 @@ static int max1363_remove(struct i2c_client *client)
regulator_disable(st->vref);
regulator_disable(st->reg);
iio_map_array_unregister(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
index ebc015922a7..28a086e4877 100644
--- a/drivers/iio/adc/mcp320x.c
+++ b/drivers/iio/adc/mcp320x.c
@@ -169,7 +169,7 @@ static int mcp320x_probe(struct spi_device *spi)
const struct mcp3208_chip_info *chip_info;
int ret;
- indio_dev = iio_device_alloc(sizeof(*adc));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
@@ -193,15 +193,13 @@ static int mcp320x_probe(struct spi_device *spi)
spi_message_init_with_transfers(&adc->msg, adc->transfer,
ARRAY_SIZE(adc->transfer));
- adc->reg = regulator_get(&spi->dev, "vref");
- if (IS_ERR(adc->reg)) {
- ret = PTR_ERR(adc->reg);
- goto iio_free;
- }
+ adc->reg = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(adc->reg))
+ return PTR_ERR(adc->reg);
ret = regulator_enable(adc->reg);
if (ret < 0)
- goto reg_free;
+ return ret;
mutex_init(&adc->lock);
@@ -213,10 +211,6 @@ static int mcp320x_probe(struct spi_device *spi)
reg_disable:
regulator_disable(adc->reg);
-reg_free:
- regulator_put(adc->reg);
-iio_free:
- iio_device_free(indio_dev);
return ret;
}
@@ -228,8 +222,6 @@ static int mcp320x_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
regulator_disable(adc->reg);
- regulator_put(adc->reg);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c
new file mode 100644
index 00000000000..bdf03468f3b
--- /dev/null
+++ b/drivers/iio/adc/nau7802.c
@@ -0,0 +1,581 @@
+/*
+ * Driver for the Nuvoton NAU7802 ADC
+ *
+ * Copyright 2013 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/log2.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define NAU7802_REG_PUCTRL 0x00
+#define NAU7802_PUCTRL_RR(x) (x << 0)
+#define NAU7802_PUCTRL_RR_BIT NAU7802_PUCTRL_RR(1)
+#define NAU7802_PUCTRL_PUD(x) (x << 1)
+#define NAU7802_PUCTRL_PUD_BIT NAU7802_PUCTRL_PUD(1)
+#define NAU7802_PUCTRL_PUA(x) (x << 2)
+#define NAU7802_PUCTRL_PUA_BIT NAU7802_PUCTRL_PUA(1)
+#define NAU7802_PUCTRL_PUR(x) (x << 3)
+#define NAU7802_PUCTRL_PUR_BIT NAU7802_PUCTRL_PUR(1)
+#define NAU7802_PUCTRL_CS(x) (x << 4)
+#define NAU7802_PUCTRL_CS_BIT NAU7802_PUCTRL_CS(1)
+#define NAU7802_PUCTRL_CR(x) (x << 5)
+#define NAU7802_PUCTRL_CR_BIT NAU7802_PUCTRL_CR(1)
+#define NAU7802_PUCTRL_AVDDS(x) (x << 7)
+#define NAU7802_PUCTRL_AVDDS_BIT NAU7802_PUCTRL_AVDDS(1)
+#define NAU7802_REG_CTRL1 0x01
+#define NAU7802_CTRL1_VLDO(x) (x << 3)
+#define NAU7802_CTRL1_GAINS(x) (x)
+#define NAU7802_CTRL1_GAINS_BITS 0x07
+#define NAU7802_REG_CTRL2 0x02
+#define NAU7802_CTRL2_CHS(x) (x << 7)
+#define NAU7802_CTRL2_CRS(x) (x << 4)
+#define NAU7802_SAMP_FREQ_320 0x07
+#define NAU7802_CTRL2_CHS_BIT NAU7802_CTRL2_CHS(1)
+#define NAU7802_REG_ADC_B2 0x12
+#define NAU7802_REG_ADC_B1 0x13
+#define NAU7802_REG_ADC_B0 0x14
+#define NAU7802_REG_ADC_CTRL 0x15
+
+#define NAU7802_MIN_CONVERSIONS 6
+
+struct nau7802_state {
+ struct i2c_client *client;
+ s32 last_value;
+ struct mutex lock;
+ struct mutex data_lock;
+ u32 vref_mv;
+ u32 conversion_count;
+ u32 min_conversions;
+ u8 sample_rate;
+ u32 scale_avail[8];
+ struct completion value_ok;
+};
+
+#define NAU7802_CHANNEL(chan) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (chan), \
+ .scan_index = (chan), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) \
+}
+
+static const struct iio_chan_spec nau7802_chan_array[] = {
+ NAU7802_CHANNEL(0),
+ NAU7802_CHANNEL(1),
+};
+
+static const u16 nau7802_sample_freq_avail[] = {10, 20, 40, 80,
+ 10, 10, 10, 320};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 40 80 320");
+
+static struct attribute *nau7802_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group nau7802_attribute_group = {
+ .attrs = nau7802_attributes,
+};
+
+static int nau7802_set_gain(struct nau7802_state *st, int gain)
+{
+ int ret;
+
+ mutex_lock(&st->lock);
+ st->conversion_count = 0;
+
+ ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL1);
+ if (ret < 0)
+ goto nau7802_sysfs_set_gain_out;
+ ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL1,
+ (ret & (~NAU7802_CTRL1_GAINS_BITS)) |
+ gain);
+
+nau7802_sysfs_set_gain_out:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int nau7802_read_conversion(struct nau7802_state *st)
+{
+ int data;
+
+ mutex_lock(&st->data_lock);
+ data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B2);
+ if (data < 0)
+ goto nau7802_read_conversion_out;
+ st->last_value = data << 16;
+
+ data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B1);
+ if (data < 0)
+ goto nau7802_read_conversion_out;
+ st->last_value |= data << 8;
+
+ data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B0);
+ if (data < 0)
+ goto nau7802_read_conversion_out;
+ st->last_value |= data;
+
+ st->last_value = sign_extend32(st->last_value, 23);
+
+nau7802_read_conversion_out:
+ mutex_unlock(&st->data_lock);
+
+ return data;
+}
+
+/*
+ * Conversions are synchronised on the rising edge of NAU7802_PUCTRL_CS_BIT
+ */
+static int nau7802_sync(struct nau7802_state *st)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
+ if (ret < 0)
+ return ret;
+ ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
+ ret | NAU7802_PUCTRL_CS_BIT);
+
+ return ret;
+}
+
+static irqreturn_t nau7802_eoc_trigger(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct nau7802_state *st = iio_priv(indio_dev);
+ int status;
+
+ status = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
+ if (status < 0)
+ return IRQ_HANDLED;
+
+ if (!(status & NAU7802_PUCTRL_CR_BIT))
+ return IRQ_NONE;
+
+ if (nau7802_read_conversion(st) < 0)
+ return IRQ_HANDLED;
+
+ /*
+ * Because there is actually only one ADC for both channels, we have to
+ * wait for enough conversions to happen before getting a significant
+ * value when changing channels and the values are far apart.
+ */
+ if (st->conversion_count < NAU7802_MIN_CONVERSIONS)
+ st->conversion_count++;
+ if (st->conversion_count >= NAU7802_MIN_CONVERSIONS)
+ complete_all(&st->value_ok);
+
+ return IRQ_HANDLED;
+}
+
+static int nau7802_read_irq(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ struct nau7802_state *st = iio_priv(indio_dev);
+ int ret;
+
+ INIT_COMPLETION(st->value_ok);
+ enable_irq(st->client->irq);
+
+ nau7802_sync(st);
+
+ /* read registers to ensure we flush everything */
+ ret = nau7802_read_conversion(st);
+ if (ret < 0)
+ goto read_chan_info_failure;
+
+ /* Wait for a conversion to finish */
+ ret = wait_for_completion_interruptible_timeout(&st->value_ok,
+ msecs_to_jiffies(1000));
+ if (ret == 0)
+ ret = -ETIMEDOUT;
+
+ if (ret < 0)
+ goto read_chan_info_failure;
+
+ disable_irq(st->client->irq);
+
+ *val = st->last_value;
+
+ return IIO_VAL_INT;
+
+read_chan_info_failure:
+ disable_irq(st->client->irq);
+
+ return ret;
+}
+
+static int nau7802_read_poll(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ struct nau7802_state *st = iio_priv(indio_dev);
+ int ret;
+
+ nau7802_sync(st);
+
+ /* read registers to ensure we flush everything */
+ ret = nau7802_read_conversion(st);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Because there is actually only one ADC for both channels, we have to
+ * wait for enough conversions to happen before getting a significant
+ * value when changing channels and the values are far appart.
+ */
+ do {
+ ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
+ if (ret < 0)
+ return ret;
+
+ while (!(ret & NAU7802_PUCTRL_CR_BIT)) {
+ if (st->sample_rate != NAU7802_SAMP_FREQ_320)
+ msleep(20);
+ else
+ mdelay(4);
+ ret = i2c_smbus_read_byte_data(st->client,
+ NAU7802_REG_PUCTRL);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = nau7802_read_conversion(st);
+ if (ret < 0)
+ return ret;
+ if (st->conversion_count < NAU7802_MIN_CONVERSIONS)
+ st->conversion_count++;
+ } while (st->conversion_count < NAU7802_MIN_CONVERSIONS);
+
+ *val = st->last_value;
+
+ return IIO_VAL_INT;
+}
+
+static int nau7802_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct nau7802_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&st->lock);
+ /*
+ * Select the channel to use
+ * - Channel 1 is value 0 in the CHS register
+ * - Channel 2 is value 1 in the CHS register
+ */
+ ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL2);
+ if (ret < 0) {
+ mutex_unlock(&st->lock);
+ return ret;
+ }
+
+ if (((ret & NAU7802_CTRL2_CHS_BIT) && !chan->channel) ||
+ (!(ret & NAU7802_CTRL2_CHS_BIT) &&
+ chan->channel)) {
+ st->conversion_count = 0;
+ ret = i2c_smbus_write_byte_data(st->client,
+ NAU7802_REG_CTRL2,
+ NAU7802_CTRL2_CHS(chan->channel) |
+ NAU7802_CTRL2_CRS(st->sample_rate));
+
+ if (ret < 0) {
+ mutex_unlock(&st->lock);
+ return ret;
+ }
+ }
+
+ if (st->client->irq)
+ ret = nau7802_read_irq(indio_dev, chan, val);
+ else
+ ret = nau7802_read_poll(indio_dev, chan, val);
+
+ mutex_unlock(&st->lock);
+ return ret;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * We have 24 bits of signed data, that means 23 bits of data
+ * plus the sign bit
+ */
+ *val = st->vref_mv;
+ *val2 = 23 + (ret & NAU7802_CTRL1_GAINS_BITS);
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = nau7802_sample_freq_avail[st->sample_rate];
+ *val2 = 0;
+ return IIO_VAL_INT;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int nau7802_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct nau7802_state *st = iio_priv(indio_dev);
+ int i, ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
+ if (val2 == st->scale_avail[i])
+ return nau7802_set_gain(st, i);
+
+ break;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ for (i = 0; i < ARRAY_SIZE(nau7802_sample_freq_avail); i++)
+ if (val == nau7802_sample_freq_avail[i]) {
+ mutex_lock(&st->lock);
+ st->sample_rate = i;
+ st->conversion_count = 0;
+ ret = i2c_smbus_write_byte_data(st->client,
+ NAU7802_REG_CTRL2,
+ NAU7802_CTRL2_CRS(st->sample_rate));
+ mutex_unlock(&st->lock);
+ return ret;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int nau7802_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ return IIO_VAL_INT_PLUS_NANO;
+}
+
+static const struct iio_info nau7802_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &nau7802_read_raw,
+ .write_raw = &nau7802_write_raw,
+ .write_raw_get_fmt = nau7802_write_raw_get_fmt,
+ .attrs = &nau7802_attribute_group,
+};
+
+static int nau7802_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct nau7802_state *st;
+ struct device_node *np = client->dev.of_node;
+ int i, ret;
+ u8 data;
+ u32 tmp = 0;
+
+ if (!client->dev.of_node) {
+ dev_err(&client->dev, "No device tree node available.\n");
+ return -EINVAL;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ i2c_set_clientdata(client, indio_dev);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = dev_name(&client->dev);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &nau7802_info;
+
+ st->client = client;
+
+ /* Reset the device */
+ ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
+ NAU7802_PUCTRL_RR_BIT);
+ if (ret < 0)
+ return ret;
+
+ /* Enter normal operation mode */
+ ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
+ NAU7802_PUCTRL_PUD_BIT);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * After about 200 usecs, the device should be ready and then
+ * the Power Up bit will be set to 1. If not, wait for it.
+ */
+ udelay(210);
+ ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
+ if (ret < 0)
+ return ret;
+ if (!(ret & NAU7802_PUCTRL_PUR_BIT))
+ return ret;
+
+ of_property_read_u32(np, "nuvoton,vldo", &tmp);
+ st->vref_mv = tmp;
+
+ data = NAU7802_PUCTRL_PUD_BIT | NAU7802_PUCTRL_PUA_BIT |
+ NAU7802_PUCTRL_CS_BIT;
+ if (tmp >= 2400)
+ data |= NAU7802_PUCTRL_AVDDS_BIT;
+
+ ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL, data);
+ if (ret < 0)
+ return ret;
+ ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_ADC_CTRL, 0x30);
+ if (ret < 0)
+ return ret;
+
+ if (tmp >= 2400) {
+ data = NAU7802_CTRL1_VLDO((4500 - tmp) / 300);
+ ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL1,
+ data);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Populate available ADC input ranges */
+ for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
+ st->scale_avail[i] = (((u64)st->vref_mv) * 1000000000ULL)
+ >> (23 + i);
+
+ init_completion(&st->value_ok);
+
+ /*
+ * The ADC fires continuously and we can't do anything about
+ * it. So we need to have the IRQ disabled by default, and we
+ * will enable them back when we will need them..
+ */
+ if (client->irq) {
+ ret = request_threaded_irq(client->irq,
+ NULL,
+ nau7802_eoc_trigger,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ client->dev.driver->name,
+ indio_dev);
+ if (ret) {
+ /*
+ * What may happen here is that our IRQ controller is
+ * not able to get level interrupt but this is required
+ * by this ADC as when going over 40 sample per second,
+ * the interrupt line may stay high between conversions.
+ * So, we continue no matter what but we switch to
+ * polling mode.
+ */
+ dev_info(&client->dev,
+ "Failed to allocate IRQ, using polling mode\n");
+ client->irq = 0;
+ } else
+ disable_irq(client->irq);
+ }
+
+ if (!client->irq) {
+ /*
+ * We are polling, use the fastest sample rate by
+ * default
+ */
+ st->sample_rate = NAU7802_SAMP_FREQ_320;
+ ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL2,
+ NAU7802_CTRL2_CRS(st->sample_rate));
+ if (ret)
+ goto error_free_irq;
+ }
+
+ /* Setup the ADC channels available on the board */
+ indio_dev->num_channels = ARRAY_SIZE(nau7802_chan_array);
+ indio_dev->channels = nau7802_chan_array;
+
+ mutex_init(&st->lock);
+ mutex_init(&st->data_lock);
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "Couldn't register the device.\n");
+ goto error_device_register;
+ }
+
+ return 0;
+
+error_device_register:
+ mutex_destroy(&st->lock);
+ mutex_destroy(&st->data_lock);
+error_free_irq:
+ if (client->irq)
+ free_irq(client->irq, indio_dev);
+
+ return ret;
+}
+
+static int nau7802_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct nau7802_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ mutex_destroy(&st->lock);
+ mutex_destroy(&st->data_lock);
+ if (client->irq)
+ free_irq(client->irq, indio_dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id nau7802_i2c_id[] = {
+ { "nau7802", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
+
+static const struct of_device_id nau7802_dt_ids[] = {
+ { .compatible = "nuvoton,nau7802" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, nau7802_dt_ids);
+
+static struct i2c_driver nau7802_driver = {
+ .probe = nau7802_probe,
+ .remove = nau7802_remove,
+ .id_table = nau7802_i2c_id,
+ .driver = {
+ .name = "nau7802",
+ .of_match_table = of_match_ptr(nau7802_dt_ids),
+ },
+};
+
+module_i2c_driver(nau7802_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Nuvoton NAU7802 ADC Driver");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index 2826faae706..ee5f72bffe5 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -74,22 +74,20 @@ static int adc081c_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
- iio = iio_device_alloc(sizeof(*adc));
+ iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));
if (!iio)
return -ENOMEM;
adc = iio_priv(iio);
adc->i2c = client;
- adc->ref = regulator_get(&client->dev, "vref");
- if (IS_ERR(adc->ref)) {
- err = PTR_ERR(adc->ref);
- goto iio_free;
- }
+ adc->ref = devm_regulator_get(&client->dev, "vref");
+ if (IS_ERR(adc->ref))
+ return PTR_ERR(adc->ref);
err = regulator_enable(adc->ref);
if (err < 0)
- goto regulator_put;
+ return err;
iio->dev.parent = &client->dev;
iio->name = dev_name(&client->dev);
@@ -109,10 +107,6 @@ static int adc081c_probe(struct i2c_client *client,
regulator_disable:
regulator_disable(adc->ref);
-regulator_put:
- regulator_put(adc->ref);
-iio_free:
- iio_device_free(iio);
return err;
}
@@ -124,8 +118,6 @@ static int adc081c_remove(struct i2c_client *client)
iio_device_unregister(iio);
regulator_disable(adc->ref);
- regulator_put(adc->ref);
- iio_device_free(iio);
return 0;
}
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index 0ad208a69c2..a952538a1a8 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -60,7 +60,6 @@ static void tiadc_step_config(struct tiadc_device *adc_dev)
{
unsigned int stepconfig;
int i, steps;
- u32 step_en;
/*
* There are 16 configurable steps and 8 analog input
@@ -86,8 +85,7 @@ static void tiadc_step_config(struct tiadc_device *adc_dev)
adc_dev->channel_step[i] = steps;
steps++;
}
- step_en = get_adc_step_mask(adc_dev);
- am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en);
+
}
static const char * const chan_name_ain[] = {
@@ -142,10 +140,22 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
- int i;
- unsigned int fifo1count, read;
+ int i, map_val;
+ unsigned int fifo1count, read, stepid;
u32 step = UINT_MAX;
bool found = false;
+ u32 step_en;
+ unsigned long timeout = jiffies + usecs_to_jiffies
+ (IDLE_TIMEOUT * adc_dev->channels);
+ step_en = get_adc_step_mask(adc_dev);
+ am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en);
+
+ /* Wait for ADC sequencer to complete sampling */
+ while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) {
+ if (time_after(jiffies, timeout))
+ return -EAGAIN;
+ }
+ map_val = chan->channel + TOTAL_CHANNELS;
/*
* When the sub-system is first enabled,
@@ -170,12 +180,16 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
for (i = 0; i < fifo1count; i++) {
read = tiadc_readl(adc_dev, REG_FIFO1);
- if (read >> 16 == step) {
- *val = read & 0xfff;
+ stepid = read & FIFOREAD_CHNLID_MASK;
+ stepid = stepid >> 0x10;
+
+ if (stepid == map_val) {
+ read = read & FIFOREAD_DATA_MASK;
found = true;
+ *val = read;
}
}
- am335x_tsc_se_update(adc_dev->mfd_tscadc);
+
if (found == false)
return -EBUSY;
return IIO_VAL_INT;
@@ -202,11 +216,11 @@ static int tiadc_probe(struct platform_device *pdev)
return -EINVAL;
}
- indio_dev = iio_device_alloc(sizeof(struct tiadc_device));
+ indio_dev = devm_iio_device_alloc(&pdev->dev,
+ sizeof(struct tiadc_device));
if (indio_dev == NULL) {
dev_err(&pdev->dev, "failed to allocate iio device\n");
- err = -ENOMEM;
- goto err_ret;
+ return -ENOMEM;
}
adc_dev = iio_priv(indio_dev);
@@ -227,7 +241,7 @@ static int tiadc_probe(struct platform_device *pdev)
err = tiadc_channel_init(indio_dev, adc_dev->channels);
if (err < 0)
- goto err_free_device;
+ return err;
err = iio_device_register(indio_dev);
if (err)
@@ -239,9 +253,6 @@ static int tiadc_probe(struct platform_device *pdev)
err_free_channels:
tiadc_channels_remove(indio_dev);
-err_free_device:
- iio_device_free(indio_dev);
-err_ret:
return err;
}
@@ -257,8 +268,6 @@ static int tiadc_remove(struct platform_device *pdev)
step_en = get_adc_step_mask(adc_dev);
am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en);
- iio_device_free(indio_dev);
-
return 0;
}
diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c
new file mode 100644
index 00000000000..0ea96c058c0
--- /dev/null
+++ b/drivers/iio/adc/twl6030-gpadc.c
@@ -0,0 +1,1013 @@
+/*
+ * TWL6030 GPADC module driver
+ *
+ * Copyright (C) 2009-2013 Texas Instruments Inc.
+ * Nishant Kamat <nskamat@ti.com>
+ * Balaji T K <balajitk@ti.com>
+ * Graeme Gregory <gg@slimlogic.co.uk>
+ * Girish S Ghongdemath <girishsg@ti.com>
+ * Ambresh K <ambresh@ti.com>
+ * Oleksandr Kozaruk <oleksandr.kozaruk@ti.com
+ *
+ * Based on twl4030-madc.c
+ * Copyright (C) 2008 Nokia Corporation
+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/i2c/twl.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define DRIVER_NAME "twl6030_gpadc"
+
+/*
+ * twl6030 per TRM has 17 channels, and twl6032 has 19 channels
+ * 2 test network channels are not used,
+ * 2 die temperature channels are not used either, as it is not
+ * defined how to convert ADC value to temperature
+ */
+#define TWL6030_GPADC_USED_CHANNELS 13
+#define TWL6030_GPADC_MAX_CHANNELS 15
+#define TWL6032_GPADC_USED_CHANNELS 15
+#define TWL6032_GPADC_MAX_CHANNELS 19
+#define TWL6030_GPADC_NUM_TRIM_REGS 16
+
+#define TWL6030_GPADC_CTRL_P1 0x05
+
+#define TWL6032_GPADC_GPSELECT_ISB 0x07
+#define TWL6032_GPADC_CTRL_P1 0x08
+
+#define TWL6032_GPADC_GPCH0_LSB 0x0d
+#define TWL6032_GPADC_GPCH0_MSB 0x0e
+
+#define TWL6030_GPADC_CTRL_P1_SP1 BIT(3)
+
+#define TWL6030_GPADC_GPCH0_LSB (0x29)
+
+#define TWL6030_GPADC_RT_SW1_EOC_MASK BIT(5)
+
+#define TWL6030_GPADC_TRIM1 0xCD
+
+#define TWL6030_REG_TOGGLE1 0x90
+#define TWL6030_GPADCS BIT(1)
+#define TWL6030_GPADCR BIT(0)
+
+/**
+ * struct twl6030_chnl_calib - channel calibration
+ * @gain: slope coefficient for ideal curve
+ * @gain_error: gain error
+ * @offset_error: offset of the real curve
+ */
+struct twl6030_chnl_calib {
+ s32 gain;
+ s32 gain_error;
+ s32 offset_error;
+};
+
+/**
+ * struct twl6030_ideal_code - GPADC calibration parameters
+ * GPADC is calibrated in two points: close to the beginning and
+ * to the and of the measurable input range
+ *
+ * @channel: channel number
+ * @code1: ideal code for the input at the beginning
+ * @code2: ideal code for at the end of the range
+ * @volt1: voltage input at the beginning(low voltage)
+ * @volt2: voltage input at the end(high voltage)
+ */
+struct twl6030_ideal_code {
+ int channel;
+ u16 code1;
+ u16 code2;
+ u16 volt1;
+ u16 volt2;
+};
+
+struct twl6030_gpadc_data;
+
+/**
+ * struct twl6030_gpadc_platform_data - platform specific data
+ * @nchannels: number of GPADC channels
+ * @iio_channels: iio channels
+ * @twl6030_ideal: pointer to calibration parameters
+ * @start_conversion: pointer to ADC start conversion function
+ * @channel_to_reg pointer to ADC function to convert channel to
+ * register address for reading conversion result
+ * @calibrate: pointer to calibration function
+ */
+struct twl6030_gpadc_platform_data {
+ const int nchannels;
+ const struct iio_chan_spec *iio_channels;
+ const struct twl6030_ideal_code *ideal;
+ int (*start_conversion)(int channel);
+ u8 (*channel_to_reg)(int channel);
+ int (*calibrate)(struct twl6030_gpadc_data *gpadc);
+};
+
+/**
+ * struct twl6030_gpadc_data - GPADC data
+ * @dev: device pointer
+ * @lock: mutual exclusion lock for the structure
+ * @irq_complete: completion to signal end of conversion
+ * @twl6030_cal_tbl: pointer to calibration data for each
+ * channel with gain error and offset
+ * @pdata: pointer to device specific data
+ */
+struct twl6030_gpadc_data {
+ struct device *dev;
+ struct mutex lock;
+ struct completion irq_complete;
+ struct twl6030_chnl_calib *twl6030_cal_tbl;
+ const struct twl6030_gpadc_platform_data *pdata;
+};
+
+/*
+ * channels 11, 12, 13, 15 and 16 have no calibration data
+ * calibration offset is same for channels 1, 3, 4, 5
+ *
+ * The data is taken from GPADC_TRIM registers description.
+ * GPADC_TRIM registers keep difference between the code measured
+ * at volt1 and volt2 input voltages and corresponding code1 and code2
+ */
+static const struct twl6030_ideal_code
+ twl6030_ideal[TWL6030_GPADC_USED_CHANNELS] = {
+ [0] = { /* ch 0, external, battery type, resistor value */
+ .channel = 0,
+ .code1 = 116,
+ .code2 = 745,
+ .volt1 = 141,
+ .volt2 = 910,
+ },
+ [1] = { /* ch 1, external, battery temperature, NTC resistor value */
+ .channel = 1,
+ .code1 = 82,
+ .code2 = 900,
+ .volt1 = 100,
+ .volt2 = 1100,
+ },
+ [2] = { /* ch 2, external, audio accessory/general purpose */
+ .channel = 2,
+ .code1 = 55,
+ .code2 = 818,
+ .volt1 = 101,
+ .volt2 = 1499,
+ },
+ [3] = { /* ch 3, external, general purpose */
+ .channel = 3,
+ .code1 = 82,
+ .code2 = 900,
+ .volt1 = 100,
+ .volt2 = 1100,
+ },
+ [4] = { /* ch 4, external, temperature measurement/general purpose */
+ .channel = 4,
+ .code1 = 82,
+ .code2 = 900,
+ .volt1 = 100,
+ .volt2 = 1100,
+ },
+ [5] = { /* ch 5, external, general purpose */
+ .channel = 5,
+ .code1 = 82,
+ .code2 = 900,
+ .volt1 = 100,
+ .volt2 = 1100,
+ },
+ [6] = { /* ch 6, external, general purpose */
+ .channel = 6,
+ .code1 = 82,
+ .code2 = 900,
+ .volt1 = 100,
+ .volt2 = 1100,
+ },
+ [7] = { /* ch 7, internal, main battery */
+ .channel = 7,
+ .code1 = 614,
+ .code2 = 941,
+ .volt1 = 3001,
+ .volt2 = 4599,
+ },
+ [8] = { /* ch 8, internal, backup battery */
+ .channel = 8,
+ .code1 = 82,
+ .code2 = 688,
+ .volt1 = 501,
+ .volt2 = 4203,
+ },
+ [9] = { /* ch 9, internal, external charger input */
+ .channel = 9,
+ .code1 = 182,
+ .code2 = 818,
+ .volt1 = 2001,
+ .volt2 = 8996,
+ },
+ [10] = { /* ch 10, internal, VBUS */
+ .channel = 10,
+ .code1 = 149,
+ .code2 = 818,
+ .volt1 = 1001,
+ .volt2 = 5497,
+ },
+ [11] = { /* ch 11, internal, VBUS charging current */
+ .channel = 11,
+ },
+ /* ch 12, internal, Die temperature */
+ /* ch 13, internal, Die temperature */
+ [12] = { /* ch 14, internal, USB ID line */
+ .channel = 14,
+ .code1 = 48,
+ .code2 = 714,
+ .volt1 = 323,
+ .volt2 = 4800,
+ },
+};
+
+static const struct twl6030_ideal_code
+ twl6032_ideal[TWL6032_GPADC_USED_CHANNELS] = {
+ [0] = { /* ch 0, external, battery type, resistor value */
+ .channel = 0,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 440,
+ .volt2 = 1000,
+ },
+ [1] = { /* ch 1, external, battery temperature, NTC resistor value */
+ .channel = 1,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 440,
+ .volt2 = 1000,
+ },
+ [2] = { /* ch 2, external, audio accessory/general purpose */
+ .channel = 2,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 660,
+ .volt2 = 1500,
+ },
+ [3] = { /* ch 3, external, temperature with external diode/general
+ purpose */
+ .channel = 3,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 440,
+ .volt2 = 1000,
+ },
+ [4] = { /* ch 4, external, temperature measurement/general purpose */
+ .channel = 4,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 440,
+ .volt2 = 1000,
+ },
+ [5] = { /* ch 5, external, general purpose */
+ .channel = 5,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 440,
+ .volt2 = 1000,
+ },
+ [6] = { /* ch 6, external, general purpose */
+ .channel = 6,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 440,
+ .volt2 = 1000,
+ },
+ [7] = { /* ch7, internal, system supply */
+ .channel = 7,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 2200,
+ .volt2 = 5000,
+ },
+ [8] = { /* ch8, internal, backup battery */
+ .channel = 8,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 2200,
+ .volt2 = 5000,
+ },
+ [9] = { /* ch 9, internal, external charger input */
+ .channel = 9,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 3960,
+ .volt2 = 9000,
+ },
+ [10] = { /* ch10, internal, VBUS */
+ .channel = 10,
+ .code1 = 150,
+ .code2 = 751,
+ .volt1 = 1000,
+ .volt2 = 5000,
+ },
+ [11] = { /* ch 11, internal, VBUS DC-DC output current */
+ .channel = 11,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 660,
+ .volt2 = 1500,
+ },
+ /* ch 12, internal, Die temperature */
+ /* ch 13, internal, Die temperature */
+ [12] = { /* ch 14, internal, USB ID line */
+ .channel = 14,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 2420,
+ .volt2 = 5500,
+ },
+ /* ch 15, internal, test network */
+ /* ch 16, internal, test network */
+ [13] = { /* ch 17, internal, battery charging current */
+ .channel = 17,
+ },
+ [14] = { /* ch 18, internal, battery voltage */
+ .channel = 18,
+ .code1 = 1441,
+ .code2 = 3276,
+ .volt1 = 2200,
+ .volt2 = 5000,
+ },
+};
+
+static inline int twl6030_gpadc_write(u8 reg, u8 val)
+{
+ return twl_i2c_write_u8(TWL6030_MODULE_GPADC, val, reg);
+}
+
+static inline int twl6030_gpadc_read(u8 reg, u8 *val)
+{
+
+ return twl_i2c_read(TWL6030_MODULE_GPADC, val, reg, 2);
+}
+
+static int twl6030_gpadc_enable_irq(u8 mask)
+{
+ int ret;
+
+ ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_LINE_B);
+ if (ret < 0)
+ return ret;
+
+ ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_STS_B);
+
+ return ret;
+}
+
+static void twl6030_gpadc_disable_irq(u8 mask)
+{
+ twl6030_interrupt_mask(mask, REG_INT_MSK_LINE_B);
+ twl6030_interrupt_mask(mask, REG_INT_MSK_STS_B);
+}
+
+static irqreturn_t twl6030_gpadc_irq_handler(int irq, void *indio_dev)
+{
+ struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev);
+
+ complete(&gpadc->irq_complete);
+
+ return IRQ_HANDLED;
+}
+
+static int twl6030_start_conversion(int channel)
+{
+ return twl6030_gpadc_write(TWL6030_GPADC_CTRL_P1,
+ TWL6030_GPADC_CTRL_P1_SP1);
+}
+
+static int twl6032_start_conversion(int channel)
+{
+ int ret;
+
+ ret = twl6030_gpadc_write(TWL6032_GPADC_GPSELECT_ISB, channel);
+ if (ret)
+ return ret;
+
+ return twl6030_gpadc_write(TWL6032_GPADC_CTRL_P1,
+ TWL6030_GPADC_CTRL_P1_SP1);
+}
+
+static u8 twl6030_channel_to_reg(int channel)
+{
+ return TWL6030_GPADC_GPCH0_LSB + 2 * channel;
+}
+
+static u8 twl6032_channel_to_reg(int channel)
+{
+ /*
+ * for any prior chosen channel, when the conversion is ready
+ * the result is avalable in GPCH0_LSB, GPCH0_MSB.
+ */
+
+ return TWL6032_GPADC_GPCH0_LSB;
+}
+
+static int twl6030_gpadc_lookup(const struct twl6030_ideal_code *ideal,
+ int channel, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ if (ideal[i].channel == channel)
+ break;
+
+ return i;
+}
+
+static int twl6030_channel_calibrated(const struct twl6030_gpadc_platform_data
+ *pdata, int channel)
+{
+ const struct twl6030_ideal_code *ideal = pdata->ideal;
+ int i;
+
+ i = twl6030_gpadc_lookup(ideal, channel, pdata->nchannels);
+ /* not calibrated channels have 0 in all structure members */
+ return pdata->ideal[i].code2;
+}
+
+static int twl6030_gpadc_make_correction(struct twl6030_gpadc_data *gpadc,
+ int channel, int raw_code)
+{
+ const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal;
+ int corrected_code;
+ int i;
+
+ i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels);
+ corrected_code = ((raw_code * 1000) -
+ gpadc->twl6030_cal_tbl[i].offset_error) /
+ gpadc->twl6030_cal_tbl[i].gain_error;
+
+ return corrected_code;
+}
+
+static int twl6030_gpadc_get_raw(struct twl6030_gpadc_data *gpadc,
+ int channel, int *res)
+{
+ u8 reg = gpadc->pdata->channel_to_reg(channel);
+ __le16 val;
+ int raw_code;
+ int ret;
+
+ ret = twl6030_gpadc_read(reg, (u8 *)&val);
+ if (ret) {
+ dev_dbg(gpadc->dev, "unable to read register 0x%X\n", reg);
+ return ret;
+ }
+
+ raw_code = le16_to_cpu(val);
+ dev_dbg(gpadc->dev, "GPADC raw code: %d", raw_code);
+
+ if (twl6030_channel_calibrated(gpadc->pdata, channel))
+ *res = twl6030_gpadc_make_correction(gpadc, channel, raw_code);
+ else
+ *res = raw_code;
+
+ return ret;
+}
+
+static int twl6030_gpadc_get_processed(struct twl6030_gpadc_data *gpadc,
+ int channel, int *val)
+{
+ const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal;
+ int corrected_code;
+ int channel_value;
+ int i;
+ int ret;
+
+ ret = twl6030_gpadc_get_raw(gpadc, channel, &corrected_code);
+ if (ret)
+ return ret;
+
+ i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels);
+ channel_value = corrected_code *
+ gpadc->twl6030_cal_tbl[i].gain;
+
+ /* Shift back into mV range */
+ channel_value /= 1000;
+
+ dev_dbg(gpadc->dev, "GPADC corrected code: %d", corrected_code);
+ dev_dbg(gpadc->dev, "GPADC value: %d", channel_value);
+
+ *val = channel_value;
+
+ return ret;
+}
+
+static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev);
+ int ret;
+ long timeout;
+
+ mutex_lock(&gpadc->lock);
+
+ ret = gpadc->pdata->start_conversion(chan->channel);
+ if (ret) {
+ dev_err(gpadc->dev, "failed to start conversion\n");
+ goto err;
+ }
+ /* wait for conversion to complete */
+ timeout = wait_for_completion_interruptible_timeout(
+ &gpadc->irq_complete, msecs_to_jiffies(5000));
+ if (timeout == 0) {
+ ret = -ETIMEDOUT;
+ goto err;
+ } else if (timeout < 0) {
+ ret = -EINTR;
+ goto err;
+ }
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = twl6030_gpadc_get_raw(gpadc, chan->channel, val);
+ ret = ret ? -EIO : IIO_VAL_INT;
+ break;
+
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = twl6030_gpadc_get_processed(gpadc, chan->channel, val);
+ ret = ret ? -EIO : IIO_VAL_INT;
+ break;
+
+ default:
+ break;
+ }
+err:
+ mutex_unlock(&gpadc->lock);
+
+ return ret;
+}
+
+/*
+ * The GPADC channels are calibrated using a two point calibration method.
+ * The channels measured with two known values: volt1 and volt2, and
+ * ideal corresponding output codes are known: code1, code2.
+ * The difference(d1, d2) between ideal and measured codes stored in trim
+ * registers.
+ * The goal is to find offset and gain of the real curve for each calibrated
+ * channel.
+ * gain: k = 1 + ((d2 - d1) / (x2 - x1))
+ * offset: b = d1 + (k - 1) * x1
+ */
+static void twl6030_calibrate_channel(struct twl6030_gpadc_data *gpadc,
+ int channel, int d1, int d2)
+{
+ int b, k, gain, x1, x2, i;
+ const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal;
+
+ i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels);
+
+ /* Gain */
+ gain = ((ideal[i].volt2 - ideal[i].volt1) * 1000) /
+ (ideal[i].code2 - ideal[i].code1);
+
+ x1 = ideal[i].code1;
+ x2 = ideal[i].code2;
+
+ /* k - real curve gain */
+ k = 1000 + (((d2 - d1) * 1000) / (x2 - x1));
+
+ /* b - offset of the real curve gain */
+ b = (d1 * 1000) - (k - 1000) * x1;
+
+ gpadc->twl6030_cal_tbl[i].gain = gain;
+ gpadc->twl6030_cal_tbl[i].gain_error = k;
+ gpadc->twl6030_cal_tbl[i].offset_error = b;
+
+ dev_dbg(gpadc->dev, "GPADC d1 for Chn: %d = %d\n", channel, d1);
+ dev_dbg(gpadc->dev, "GPADC d2 for Chn: %d = %d\n", channel, d2);
+ dev_dbg(gpadc->dev, "GPADC x1 for Chn: %d = %d\n", channel, x1);
+ dev_dbg(gpadc->dev, "GPADC x2 for Chn: %d = %d\n", channel, x2);
+ dev_dbg(gpadc->dev, "GPADC Gain for Chn: %d = %d\n", channel, gain);
+ dev_dbg(gpadc->dev, "GPADC k for Chn: %d = %d\n", channel, k);
+ dev_dbg(gpadc->dev, "GPADC b for Chn: %d = %d\n", channel, b);
+}
+
+static inline int twl6030_gpadc_get_trim_offset(s8 d)
+{
+ /*
+ * XXX NOTE!
+ * bit 0 - sign, bit 7 - reserved, 6..1 - trim value
+ * though, the documentation states that trim value
+ * is absolute value, the correct conversion results are
+ * obtained if the value is interpreted as 2's complement.
+ */
+ __u32 temp = ((d & 0x7f) >> 1) | ((d & 1) << 6);
+
+ return sign_extend32(temp, 6);
+}
+
+static int twl6030_calibration(struct twl6030_gpadc_data *gpadc)
+{
+ int ret;
+ int chn;
+ u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS];
+ s8 d1, d2;
+
+ /*
+ * for calibration two measurements have been performed at
+ * factory, for some channels, during the production test and
+ * have been stored in registers. This two stored values are
+ * used to correct the measurements. The values represent
+ * offsets for the given input from the output on ideal curve.
+ */
+ ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs,
+ TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS);
+ if (ret < 0) {
+ dev_err(gpadc->dev, "calibration failed\n");
+ return ret;
+ }
+
+ for (chn = 0; chn < TWL6030_GPADC_MAX_CHANNELS; chn++) {
+
+ switch (chn) {
+ case 0:
+ d1 = trim_regs[0];
+ d2 = trim_regs[1];
+ break;
+ case 1:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ d1 = trim_regs[4];
+ d2 = trim_regs[5];
+ break;
+ case 2:
+ d1 = trim_regs[12];
+ d2 = trim_regs[13];
+ break;
+ case 7:
+ d1 = trim_regs[6];
+ d2 = trim_regs[7];
+ break;
+ case 8:
+ d1 = trim_regs[2];
+ d2 = trim_regs[3];
+ break;
+ case 9:
+ d1 = trim_regs[8];
+ d2 = trim_regs[9];
+ break;
+ case 10:
+ d1 = trim_regs[10];
+ d2 = trim_regs[11];
+ break;
+ case 14:
+ d1 = trim_regs[14];
+ d2 = trim_regs[15];
+ break;
+ default:
+ continue;
+ }
+
+ d1 = twl6030_gpadc_get_trim_offset(d1);
+ d2 = twl6030_gpadc_get_trim_offset(d2);
+
+ twl6030_calibrate_channel(gpadc, chn, d1, d2);
+ }
+
+ return 0;
+}
+
+static int twl6032_get_trim_value(u8 *trim_regs, unsigned int reg0,
+ unsigned int reg1, unsigned int mask0, unsigned int mask1,
+ unsigned int shift0)
+{
+ int val;
+
+ val = (trim_regs[reg0] & mask0) << shift0;
+ val |= (trim_regs[reg1] & mask1) >> 1;
+ if (trim_regs[reg1] & 0x01)
+ val = -val;
+
+ return val;
+}
+
+static int twl6032_calibration(struct twl6030_gpadc_data *gpadc)
+{
+ int chn, d1 = 0, d2 = 0, temp;
+ u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS];
+ int ret;
+
+ ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs,
+ TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS);
+ if (ret < 0) {
+ dev_err(gpadc->dev, "calibration failed\n");
+ return ret;
+ }
+
+ /*
+ * Loop to calculate the value needed for returning voltages from
+ * GPADC not values.
+ *
+ * gain is calculated to 3 decimal places fixed point.
+ */
+ for (chn = 0; chn < TWL6032_GPADC_MAX_CHANNELS; chn++) {
+
+ switch (chn) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 11:
+ case 14:
+ d1 = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
+ 0x06, 2);
+ d2 = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f,
+ 0x06, 2);
+ break;
+ case 8:
+ temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
+ 0x06, 2);
+ d1 = temp + twl6032_get_trim_value(trim_regs, 7, 6,
+ 0x18, 0x1E, 1);
+
+ temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3F,
+ 0x06, 2);
+ d2 = temp + twl6032_get_trim_value(trim_regs, 9, 7,
+ 0x1F, 0x06, 2);
+ break;
+ case 9:
+ temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
+ 0x06, 2);
+ d1 = temp + twl6032_get_trim_value(trim_regs, 13, 11,
+ 0x18, 0x1E, 1);
+
+ temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f,
+ 0x06, 2);
+ d2 = temp + twl6032_get_trim_value(trim_regs, 15, 13,
+ 0x1F, 0x06, 1);
+ break;
+ case 10:
+ d1 = twl6032_get_trim_value(trim_regs, 10, 8, 0x0f,
+ 0x0E, 3);
+ d2 = twl6032_get_trim_value(trim_regs, 14, 12, 0x0f,
+ 0x0E, 3);
+ break;
+ case 7:
+ case 18:
+ temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
+ 0x06, 2);
+
+ d1 = (trim_regs[4] & 0x7E) >> 1;
+ if (trim_regs[4] & 0x01)
+ d1 = -d1;
+ d1 += temp;
+
+ temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f,
+ 0x06, 2);
+
+ d2 = (trim_regs[5] & 0xFE) >> 1;
+ if (trim_regs[5] & 0x01)
+ d2 = -d2;
+
+ d2 += temp;
+ break;
+ default:
+ /* No data for other channels */
+ continue;
+ }
+
+ twl6030_calibrate_channel(gpadc, chn, d1, d2);
+ }
+
+ return 0;
+}
+
+#define TWL6030_GPADC_CHAN(chn, _type, chan_info) { \
+ .type = _type, \
+ .channel = chn, \
+ .info_mask_separate = BIT(chan_info), \
+ .indexed = 1, \
+}
+
+static const struct iio_chan_spec twl6030_gpadc_iio_channels[] = {
+ TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW),
+ TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW),
+ TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+ TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+};
+
+static const struct iio_chan_spec twl6032_gpadc_iio_channels[] = {
+ TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW),
+ TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW),
+ TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+ TWL6030_GPADC_CHAN(17, IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+ TWL6030_GPADC_CHAN(18, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+};
+
+static const struct iio_info twl6030_gpadc_iio_info = {
+ .read_raw = &twl6030_gpadc_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static const struct twl6030_gpadc_platform_data twl6030_pdata = {
+ .iio_channels = twl6030_gpadc_iio_channels,
+ .nchannels = TWL6030_GPADC_USED_CHANNELS,
+ .ideal = twl6030_ideal,
+ .start_conversion = twl6030_start_conversion,
+ .channel_to_reg = twl6030_channel_to_reg,
+ .calibrate = twl6030_calibration,
+};
+
+static const struct twl6030_gpadc_platform_data twl6032_pdata = {
+ .iio_channels = twl6032_gpadc_iio_channels,
+ .nchannels = TWL6032_GPADC_USED_CHANNELS,
+ .ideal = twl6032_ideal,
+ .start_conversion = twl6032_start_conversion,
+ .channel_to_reg = twl6032_channel_to_reg,
+ .calibrate = twl6032_calibration,
+};
+
+static const struct of_device_id of_twl6030_match_tbl[] = {
+ {
+ .compatible = "ti,twl6030-gpadc",
+ .data = &twl6030_pdata,
+ },
+ {
+ .compatible = "ti,twl6032-gpadc",
+ .data = &twl6032_pdata,
+ },
+ { /* end */ }
+};
+
+static int twl6030_gpadc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct twl6030_gpadc_data *gpadc;
+ const struct twl6030_gpadc_platform_data *pdata;
+ const struct of_device_id *match;
+ struct iio_dev *indio_dev;
+ int irq;
+ int ret;
+
+ match = of_match_device(of_match_ptr(of_twl6030_match_tbl), dev);
+ if (!match)
+ return -EINVAL;
+
+ pdata = match->data;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ gpadc = iio_priv(indio_dev);
+
+ gpadc->twl6030_cal_tbl = devm_kzalloc(dev,
+ sizeof(*gpadc->twl6030_cal_tbl) *
+ pdata->nchannels, GFP_KERNEL);
+ if (!gpadc->twl6030_cal_tbl)
+ return -ENOMEM;
+
+ gpadc->dev = dev;
+ gpadc->pdata = pdata;
+
+ platform_set_drvdata(pdev, indio_dev);
+ mutex_init(&gpadc->lock);
+ init_completion(&gpadc->irq_complete);
+
+ ret = pdata->calibrate(gpadc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to read calibration registers\n");
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ return irq;
+ }
+
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ twl6030_gpadc_irq_handler,
+ IRQF_ONESHOT, "twl6030_gpadc", indio_dev);
+
+ ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to enable GPADC interrupt\n");
+ return ret;
+ }
+
+ ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
+ TWL6030_REG_TOGGLE1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to enable GPADC module\n");
+ return ret;
+ }
+
+ indio_dev->name = DRIVER_NAME;
+ indio_dev->dev.parent = dev;
+ indio_dev->info = &twl6030_gpadc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = pdata->iio_channels;
+ indio_dev->num_channels = pdata->nchannels;
+
+ ret = iio_device_register(indio_dev);
+
+ return ret;
+}
+
+static int twl6030_gpadc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+ twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
+ iio_device_unregister(indio_dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int twl6030_gpadc_suspend(struct device *pdev)
+{
+ int ret;
+
+ ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCR,
+ TWL6030_REG_TOGGLE1);
+ if (ret)
+ dev_err(pdev, "error reseting GPADC (%d)!\n", ret);
+
+ return 0;
+};
+
+static int twl6030_gpadc_resume(struct device *pdev)
+{
+ int ret;
+
+ ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
+ TWL6030_REG_TOGGLE1);
+ if (ret)
+ dev_err(pdev, "error setting GPADC (%d)!\n", ret);
+
+ return 0;
+};
+#endif
+
+static SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend,
+ twl6030_gpadc_resume);
+
+static struct platform_driver twl6030_gpadc_driver = {
+ .probe = twl6030_gpadc_probe,
+ .remove = twl6030_gpadc_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &twl6030_gpadc_pm_ops,
+ .of_match_table = of_twl6030_match_tbl,
+ },
+};
+
+module_platform_driver(twl6030_gpadc_driver);
+
+MODULE_ALIAS("platform: " DRIVER_NAME);
+MODULE_AUTHOR("Balaji T K <balajitk@ti.com>");
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_AUTHOR("Oleksandr Kozaruk <oleksandr.kozaruk@ti.com");
+MODULE_DESCRIPTION("twl6030 ADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c
index 56ac481c73c..09727a71e9f 100644
--- a/drivers/iio/adc/viperboard_adc.c
+++ b/drivers/iio/adc/viperboard_adc.c
@@ -124,7 +124,7 @@ static int vprbrd_adc_probe(struct platform_device *pdev)
int ret;
/* registering iio */
- indio_dev = iio_device_alloc(sizeof(*adc));
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
if (!indio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
@@ -142,16 +142,12 @@ static int vprbrd_adc_probe(struct platform_device *pdev)
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "could not register iio (adc)");
- goto error;
+ return ret;
}
platform_set_drvdata(pdev, indio_dev);
return 0;
-
-error:
- iio_device_free(indio_dev);
- return ret;
}
static int vprbrd_adc_remove(struct platform_device *pdev)
@@ -159,7 +155,6 @@ static int vprbrd_adc_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_device_unregister(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/amplifiers/Kconfig b/drivers/iio/amplifiers/Kconfig
index 05d707ed7d4..e9c5f2cd925 100644
--- a/drivers/iio/amplifiers/Kconfig
+++ b/drivers/iio/amplifiers/Kconfig
@@ -1,6 +1,8 @@
#
# Gain Amplifiers, etc.
#
+# When adding new entries keep the list in alphabetical order
+
menu "Amplifiers"
config AD8366
diff --git a/drivers/iio/amplifiers/Makefile b/drivers/iio/amplifiers/Makefile
index a6ca366908e..8da4b787898 100644
--- a/drivers/iio/amplifiers/Makefile
+++ b/drivers/iio/amplifiers/Makefile
@@ -2,4 +2,5 @@
# Makefile iio/amplifiers
#
+# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD8366) += ad8366.o
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
index d354554b51b..d0a79a4bce1 100644
--- a/drivers/iio/amplifiers/ad8366.c
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -139,17 +139,17 @@ static int ad8366_probe(struct spi_device *spi)
struct ad8366_state *st;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = regulator_get(&spi->dev, "vcc");
+ st->reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
}
spi_set_drvdata(spi, indio_dev);
@@ -173,11 +173,6 @@ static int ad8366_probe(struct spi_device *spi)
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
-error_put_reg:
- if (!IS_ERR(st->reg))
- regulator_put(st->reg);
-
- iio_device_free(indio_dev);
return ret;
}
@@ -195,8 +190,6 @@ static int ad8366_remove(struct spi_device *spi)
regulator_put(reg);
}
- iio_device_free(indio_dev);
-
return 0;
}
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
index c2352beb5d9..3112df0060e 100644
--- a/drivers/iio/common/Makefile
+++ b/drivers/iio/common/Makefile
@@ -6,5 +6,6 @@
# instead of duplicating in each module.
#
+# When adding new entries keep the list in alphabetical order
obj-y += hid-sensors/
obj-y += st_sensors/
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 865b1781df6..965ee22d3ac 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -22,7 +22,7 @@
static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
{
- return ((s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8);
+ return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
}
static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
@@ -118,7 +118,7 @@ st_sensors_match_odr_error:
}
static int st_sensors_set_fullscale(struct iio_dev *indio_dev,
- unsigned int fs)
+ unsigned int fs)
{
int err, i = 0;
struct st_sensor_data *sdata = iio_priv(indio_dev);
@@ -198,13 +198,39 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
}
EXPORT_SYMBOL(st_sensors_set_axis_enable);
-int st_sensors_init_sensor(struct iio_dev *indio_dev)
+int st_sensors_init_sensor(struct iio_dev *indio_dev,
+ struct st_sensors_platform_data *pdata)
{
int err;
struct st_sensor_data *sdata = iio_priv(indio_dev);
mutex_init(&sdata->tb.buf_lock);
+ switch (pdata->drdy_int_pin) {
+ case 1:
+ if (sdata->sensor->drdy_irq.mask_int1 == 0) {
+ dev_err(&indio_dev->dev,
+ "DRDY on INT1 not available.\n");
+ err = -EINVAL;
+ goto init_error;
+ }
+ sdata->drdy_int_pin = 1;
+ break;
+ case 2:
+ if (sdata->sensor->drdy_irq.mask_int2 == 0) {
+ dev_err(&indio_dev->dev,
+ "DRDY on INT2 not available.\n");
+ err = -EINVAL;
+ goto init_error;
+ }
+ sdata->drdy_int_pin = 2;
+ break;
+ default:
+ dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n");
+ err = -EINVAL;
+ goto init_error;
+ }
+
err = st_sensors_set_enable(indio_dev, false);
if (err < 0)
goto init_error;
@@ -234,6 +260,7 @@ EXPORT_SYMBOL(st_sensors_init_sensor);
int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
{
int err;
+ u8 drdy_mask;
struct st_sensor_data *sdata = iio_priv(indio_dev);
/* Enable/Disable the interrupt generator 1. */
@@ -245,10 +272,14 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
goto st_accel_set_dataready_irq_error;
}
+ if (sdata->drdy_int_pin == 1)
+ drdy_mask = sdata->sensor->drdy_irq.mask_int1;
+ else
+ drdy_mask = sdata->sensor->drdy_irq.mask_int2;
+
/* Enable/Disable the interrupt generator for data ready. */
err = st_sensors_write_data_with_mask(indio_dev,
- sdata->sensor->drdy_irq.addr,
- sdata->sensor->drdy_irq.mask, (int)enable);
+ sdata->sensor->drdy_irq.addr, drdy_mask, (int)enable);
st_accel_set_dataready_irq_error:
return err;
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index c9c33ce32d3..3c6a78a75b7 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -1,6 +1,8 @@
#
# DAC drivers
#
+# When adding new entries keep the list in alphabetical order
+
menu "Digital to analog converters"
config AD5064
@@ -15,7 +17,7 @@ config AD5064
module will be called ad5064.
config AD5360
- tristate "Analog Devices Analog Devices AD5360/61/62/63/70/71/73 DAC driver"
+ tristate "Analog Devices AD5360/61/62/63/70/71/73 DAC driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5360, AD5361,
@@ -48,13 +50,6 @@ config AD5421
To compile this driver as module choose M here: the module will be called
ad5421.
-config AD5624R_SPI
- tristate "Analog Devices AD5624/44/64R DAC spi driver"
- depends on SPI
- help
- Say yes here to build support for Analog Devices AD5624R, AD5644R and
- AD5664R converters (DAC). This driver uses the common SPI interface.
-
config AD5446
tristate "Analog Devices AD5446 and similar single channel DACs driver"
depends on (SPI_MASTER && I2C!=m) || I2C
@@ -68,7 +63,7 @@ config AD5446
module will be called ad5446.
config AD5449
- tristate "Analog Device AD5449 and similar DACs driver"
+ tristate "Analog Devices AD5449 and similar DACs driver"
depends on SPI_MASTER
help
Say yes here to build support for Analog Devices AD5415, AD5426, AD5429,
@@ -87,6 +82,24 @@ config AD5504
To compile this driver as a module, choose M here: the
module will be called ad5504.
+config AD5624R_SPI
+ tristate "Analog Devices AD5624/44/64R DAC spi driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices AD5624R, AD5644R and
+ AD5664R converters (DAC). This driver uses the common SPI interface.
+
+config AD5686
+ tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices AD5686R, AD5685R,
+ AD5684R, AD5791 Voltage Output Digital to
+ Analog Converter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad5686.
+
config AD5755
tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver"
depends on SPI_MASTER
@@ -119,19 +132,8 @@ config AD5791
To compile this driver as a module, choose M here: the
module will be called ad5791.
-config AD5686
- tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
- depends on SPI
- help
- Say yes here to build support for Analog Devices AD5686R, AD5685R,
- AD5684R, AD5791 Voltage Output Digital to
- Analog Converter.
-
- To compile this driver as a module, choose M here: the
- module will be called ad5686.
-
config AD7303
- tristate "Analog Devices Analog Devices AD7303 DAC driver"
+ tristate "Analog Devices AD7303 DAC driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD7303 Digital to Analog
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index c8d7ab6bff0..bb84ad64463 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -2,6 +2,7 @@
# Makefile for industrial I/O DAC drivers
#
+# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD5360) += ad5360.o
obj-$(CONFIG_AD5380) += ad5380.o
obj-$(CONFIG_AD5421) += ad5421.o
diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c
index aa26d50ab63..a3a52be4852 100644
--- a/drivers/iio/dac/ad5064.c
+++ b/drivers/iio/dac/ad5064.c
@@ -442,7 +442,7 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type,
unsigned int i;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -456,23 +456,23 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type,
for (i = 0; i < ad5064_num_vref(st); ++i)
st->vref_reg[i].supply = ad5064_vref_name(st, i);
- ret = regulator_bulk_get(dev, ad5064_num_vref(st),
+ ret = devm_regulator_bulk_get(dev, ad5064_num_vref(st),
st->vref_reg);
if (ret) {
if (!st->chip_info->internal_vref)
- goto error_free;
+ return ret;
st->use_internal_vref = true;
ret = ad5064_write(st, AD5064_CMD_CONFIG, 0,
AD5064_CONFIG_INT_VREF_ENABLE, 0);
if (ret) {
dev_err(dev, "Failed to enable internal vref: %d\n",
ret);
- goto error_free;
+ return ret;
}
} else {
ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
if (ret)
- goto error_free_reg;
+ return ret;
}
indio_dev->dev.parent = dev;
@@ -498,11 +498,6 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type,
error_disable_reg:
if (!st->use_internal_vref)
regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
-error_free_reg:
- if (!st->use_internal_vref)
- regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
-error_free:
- iio_device_free(indio_dev);
return ret;
}
@@ -514,12 +509,8 @@ static int ad5064_remove(struct device *dev)
iio_device_unregister(indio_dev);
- if (!st->use_internal_vref) {
+ if (!st->use_internal_vref)
regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
- regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
- }
-
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c
index 80923af424f..d2da71ece74 100644
--- a/drivers/iio/dac/ad5360.c
+++ b/drivers/iio/dac/ad5360.c
@@ -459,7 +459,7 @@ static int ad5360_probe(struct spi_device *spi)
unsigned int i;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
@@ -480,13 +480,13 @@ static int ad5360_probe(struct spi_device *spi)
ret = ad5360_alloc_channels(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to allocate channel spec: %d\n", ret);
- goto error_free;
+ return ret;
}
for (i = 0; i < st->chip_info->num_vrefs; ++i)
st->vref_reg[i].supply = ad5360_vref_name[i];
- ret = regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs,
+ ret = devm_regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs,
st->vref_reg);
if (ret) {
dev_err(&spi->dev, "Failed to request vref regulators: %d\n", ret);
@@ -496,7 +496,7 @@ static int ad5360_probe(struct spi_device *spi)
ret = regulator_bulk_enable(st->chip_info->num_vrefs, st->vref_reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", ret);
- goto error_free_reg;
+ goto error_free_channels;
}
ret = iio_device_register(indio_dev);
@@ -509,12 +509,8 @@ static int ad5360_probe(struct spi_device *spi)
error_disable_reg:
regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
-error_free_reg:
- regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
error_free_channels:
kfree(indio_dev->channels);
-error_free:
- iio_device_free(indio_dev);
return ret;
}
@@ -529,9 +525,6 @@ static int ad5360_remove(struct spi_device *spi)
kfree(indio_dev->channels);
regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
- regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
-
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c
index bf2db02215c..1c44ae3920e 100644
--- a/drivers/iio/dac/ad5380.c
+++ b/drivers/iio/dac/ad5380.c
@@ -369,11 +369,10 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap,
unsigned int ctrl = 0;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL) {
dev_err(dev, "Failed to allocate iio device\n");
- ret = -ENOMEM;
- goto error_out;
+ return -ENOMEM;
}
st = iio_priv(indio_dev);
@@ -391,13 +390,13 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap,
ret = ad5380_alloc_channels(indio_dev);
if (ret) {
dev_err(dev, "Failed to allocate channel spec: %d\n", ret);
- goto error_free;
+ return ret;
}
if (st->chip_info->int_vref == 2500000)
ctrl |= AD5380_CTRL_INT_VREF_2V5;
- st->vref_reg = regulator_get(dev, "vref");
+ st->vref_reg = devm_regulator_get(dev, "vref");
if (!IS_ERR(st->vref_reg)) {
ret = regulator_enable(st->vref_reg);
if (ret) {
@@ -434,13 +433,7 @@ error_disable_reg:
if (!IS_ERR(st->vref_reg))
regulator_disable(st->vref_reg);
error_free_reg:
- if (!IS_ERR(st->vref_reg))
- regulator_put(st->vref_reg);
-
kfree(indio_dev->channels);
-error_free:
- iio_device_free(indio_dev);
-error_out:
return ret;
}
@@ -456,11 +449,8 @@ static int ad5380_remove(struct device *dev)
if (!IS_ERR(st->vref_reg)) {
regulator_disable(st->vref_reg);
- regulator_put(st->vref_reg);
}
- iio_device_free(indio_dev);
-
return 0;
}
diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c
index 98f24407c3c..1f78b14abb7 100644
--- a/drivers/iio/dac/ad5421.c
+++ b/drivers/iio/dac/ad5421.c
@@ -451,7 +451,7 @@ static int ad5421_probe(struct spi_device *spi)
struct ad5421_state *st;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
@@ -484,31 +484,23 @@ static int ad5421_probe(struct spi_device *spi)
ad5421_update_ctrl(indio_dev, 0, 0);
if (spi->irq) {
- ret = request_threaded_irq(spi->irq,
+ ret = devm_request_threaded_irq(&spi->dev, spi->irq,
NULL,
ad5421_fault_handler,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"ad5421 fault",
indio_dev);
if (ret)
- goto error_free;
+ return ret;
}
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
- goto error_free_irq;
+ return ret;
}
return 0;
-
-error_free_irq:
- if (spi->irq)
- free_irq(spi->irq, indio_dev);
-error_free:
- iio_device_free(indio_dev);
-
- return ret;
}
static int ad5421_remove(struct spi_device *spi)
@@ -516,9 +508,6 @@ static int ad5421_remove(struct spi_device *spi)
struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
- if (spi->irq)
- free_irq(spi->irq, indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
index cae8f6056ac..96e9ed4c2d0 100644
--- a/drivers/iio/dac/ad5446.c
+++ b/drivers/iio/dac/ad5446.c
@@ -220,11 +220,11 @@ static int ad5446_probe(struct device *dev, const char *name,
struct regulator *reg;
int ret, voltage_uv = 0;
- reg = regulator_get(dev, "vcc");
+ reg = devm_regulator_get(dev, "vcc");
if (!IS_ERR(reg)) {
ret = regulator_enable(reg);
if (ret)
- goto error_put_reg;
+ return ret;
ret = regulator_get_voltage(reg);
if (ret < 0)
@@ -233,7 +233,7 @@ static int ad5446_probe(struct device *dev, const char *name,
voltage_uv = ret;
}
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
@@ -264,19 +264,13 @@ static int ad5446_probe(struct device *dev, const char *name,
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_device;
+ goto error_disable_reg;
return 0;
-error_free_device:
- iio_device_free(indio_dev);
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
-error_put_reg:
- if (!IS_ERR(reg))
- regulator_put(reg);
-
return ret;
}
@@ -286,11 +280,8 @@ static int ad5446_remove(struct device *dev)
struct ad5446_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
- if (!IS_ERR(st->reg)) {
+ if (!IS_ERR(st->reg))
regulator_disable(st->reg);
- regulator_put(st->reg);
- }
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c
index ba1c914b039..fff7d0762c0 100644
--- a/drivers/iio/dac/ad5449.c
+++ b/drivers/iio/dac/ad5449.c
@@ -275,7 +275,7 @@ static int ad5449_spi_probe(struct spi_device *spi)
unsigned int i;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -288,14 +288,14 @@ static int ad5449_spi_probe(struct spi_device *spi)
for (i = 0; i < st->chip_info->num_channels; ++i)
st->vref_reg[i].supply = ad5449_vref_name(st, i);
- ret = regulator_bulk_get(&spi->dev, st->chip_info->num_channels,
+ ret = devm_regulator_bulk_get(&spi->dev, st->chip_info->num_channels,
st->vref_reg);
if (ret)
- goto error_free;
+ return ret;
ret = regulator_bulk_enable(st->chip_info->num_channels, st->vref_reg);
if (ret)
- goto error_free_reg;
+ return ret;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = id->name;
@@ -325,10 +325,6 @@ static int ad5449_spi_probe(struct spi_device *spi)
error_disable_reg:
regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg);
-error_free_reg:
- regulator_bulk_free(st->chip_info->num_channels, st->vref_reg);
-error_free:
- iio_device_free(indio_dev);
return ret;
}
@@ -341,9 +337,6 @@ static int ad5449_spi_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg);
- regulator_bulk_free(st->chip_info->num_channels, st->vref_reg);
-
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index 139206e84cb..caffb16bc05 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -281,16 +281,14 @@ static int ad5504_probe(struct spi_device *spi)
struct regulator *reg;
int ret, voltage_uv = 0;
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
- reg = regulator_get(&spi->dev, "vcc");
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+ reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(reg)) {
ret = regulator_enable(reg);
if (ret)
- goto error_put_reg;
+ return ret;
ret = regulator_get_voltage(reg);
if (ret < 0)
@@ -321,7 +319,7 @@ static int ad5504_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
if (spi->irq) {
- ret = request_threaded_irq(spi->irq,
+ ret = devm_request_threaded_irq(&spi->dev, spi->irq,
NULL,
&ad5504_event_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
@@ -333,22 +331,14 @@ static int ad5504_probe(struct spi_device *spi)
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_irq;
+ goto error_disable_reg;
return 0;
-error_free_irq:
- if (spi->irq)
- free_irq(spi->irq, indio_dev);
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
-error_put_reg:
- if (!IS_ERR(reg))
- regulator_put(reg);
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -358,14 +348,9 @@ static int ad5504_remove(struct spi_device *spi)
struct ad5504_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
- if (spi->irq)
- free_irq(spi->irq, indio_dev);
- if (!IS_ERR(st->reg)) {
+ if (!IS_ERR(st->reg))
regulator_disable(st->reg);
- regulator_put(st->reg);
- }
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c
index bb298aaff32..714af757cd5 100644
--- a/drivers/iio/dac/ad5624r_spi.c
+++ b/drivers/iio/dac/ad5624r_spi.c
@@ -226,17 +226,15 @@ static int ad5624r_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = regulator_get(&spi->dev, "vcc");
+ st->reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
@@ -277,11 +275,6 @@ static int ad5624r_probe(struct spi_device *spi)
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
-error_put_reg:
- if (!IS_ERR(st->reg))
- regulator_put(st->reg);
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -292,11 +285,8 @@ static int ad5624r_remove(struct spi_device *spi)
struct ad5624r_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
- if (!IS_ERR(st->reg)) {
+ if (!IS_ERR(st->reg))
regulator_disable(st->reg);
- regulator_put(st->reg);
- }
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 06439b1af9b..57825ead7db 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -314,18 +314,18 @@ static int ad5686_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret, regdone = 0, voltage_uv = 0;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
- st->reg = regulator_get(&spi->dev, "vcc");
+ st->reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
@@ -369,12 +369,6 @@ static int ad5686_probe(struct spi_device *spi)
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
-error_put_reg:
- if (!IS_ERR(st->reg))
- regulator_put(st->reg);
-
- iio_device_free(indio_dev);
-
return ret;
}
@@ -384,11 +378,8 @@ static int ad5686_remove(struct spi_device *spi)
struct ad5686_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
- if (!IS_ERR(st->reg)) {
+ if (!IS_ERR(st->reg))
regulator_disable(st->reg);
- regulator_put(st->reg);
- }
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c
index 12bb315e55f..36a4361aece 100644
--- a/drivers/iio/dac/ad5755.c
+++ b/drivers/iio/dac/ad5755.c
@@ -565,7 +565,7 @@ static int ad5755_probe(struct spi_device *spi)
struct ad5755_state *st;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
@@ -589,24 +589,19 @@ static int ad5755_probe(struct spi_device *spi)
ret = ad5755_init_channels(indio_dev, pdata);
if (ret)
- goto error_free;
+ return ret;
ret = ad5755_setup_pdata(indio_dev, pdata);
if (ret)
- goto error_free;
+ return ret;
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
- goto error_free;
+ return ret;
}
return 0;
-
-error_free:
- iio_device_free(indio_dev);
-
- return ret;
}
static int ad5755_remove(struct spi_device *spi)
@@ -614,7 +609,6 @@ static int ad5755_remove(struct spi_device *spi)
struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c
index 7a53f7d70da..df7e028d9db 100644
--- a/drivers/iio/dac/ad5764.c
+++ b/drivers/iio/dac/ad5764.c
@@ -275,7 +275,7 @@ static int ad5764_probe(struct spi_device *spi)
struct ad5764_state *st;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
@@ -298,12 +298,12 @@ static int ad5764_probe(struct spi_device *spi)
st->vref_reg[0].supply = "vrefAB";
st->vref_reg[1].supply = "vrefCD";
- ret = regulator_bulk_get(&st->spi->dev,
+ ret = devm_regulator_bulk_get(&st->spi->dev,
ARRAY_SIZE(st->vref_reg), st->vref_reg);
if (ret) {
dev_err(&spi->dev, "Failed to request vref regulators: %d\n",
ret);
- goto error_free;
+ return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(st->vref_reg),
@@ -311,7 +311,7 @@ static int ad5764_probe(struct spi_device *spi)
if (ret) {
dev_err(&spi->dev, "Failed to enable vref regulators: %d\n",
ret);
- goto error_free_reg;
+ return ret;
}
}
@@ -326,12 +326,6 @@ static int ad5764_probe(struct spi_device *spi)
error_disable_reg:
if (st->chip_info->int_vref == 0)
regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
-error_free_reg:
- if (st->chip_info->int_vref == 0)
- regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
-error_free:
- iio_device_free(indio_dev);
-
return ret;
}
@@ -342,12 +336,8 @@ static int ad5764_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
- if (st->chip_info->int_vref == 0) {
+ if (st->chip_info->int_vref == 0)
regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
- regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
- }
-
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
index 97c1e5d780d..ce745896330 100644
--- a/drivers/iio/dac/ad5791.c
+++ b/drivers/iio/dac/ad5791.c
@@ -349,17 +349,15 @@ static int ad5791_probe(struct spi_device *spi)
struct ad5791_state *st;
int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg_vdd = regulator_get(&spi->dev, "vdd");
+ st->reg_vdd = devm_regulator_get(&spi->dev, "vdd");
if (!IS_ERR(st->reg_vdd)) {
ret = regulator_enable(st->reg_vdd);
if (ret)
- goto error_put_reg_pos;
+ return ret;
ret = regulator_get_voltage(st->reg_vdd);
if (ret < 0)
@@ -368,11 +366,11 @@ static int ad5791_probe(struct spi_device *spi)
pos_voltage_uv = ret;
}
- st->reg_vss = regulator_get(&spi->dev, "vss");
+ st->reg_vss = devm_regulator_get(&spi->dev, "vss");
if (!IS_ERR(st->reg_vss)) {
ret = regulator_enable(st->reg_vss);
if (ret)
- goto error_put_reg_neg;
+ goto error_disable_reg_pos;
ret = regulator_get_voltage(st->reg_vss);
if (ret < 0)
@@ -428,19 +426,9 @@ static int ad5791_probe(struct spi_device *spi)
error_disable_reg_neg:
if (!IS_ERR(st->reg_vss))
regulator_disable(st->reg_vss);
-error_put_reg_neg:
- if (!IS_ERR(st->reg_vss))
- regulator_put(st->reg_vss);
-
error_disable_reg_pos:
if (!IS_ERR(st->reg_vdd))
regulator_disable(st->reg_vdd);
-error_put_reg_pos:
- if (!IS_ERR(st->reg_vdd))
- regulator_put(st->reg_vdd);
- iio_device_free(indio_dev);
-error_ret:
-
return ret;
}
@@ -450,16 +438,11 @@ static int ad5791_remove(struct spi_device *spi)
struct ad5791_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
- if (!IS_ERR(st->reg_vdd)) {
+ if (!IS_ERR(st->reg_vdd))
regulator_disable(st->reg_vdd);
- regulator_put(st->reg_vdd);
- }
- if (!IS_ERR(st->reg_vss)) {
+ if (!IS_ERR(st->reg_vss))
regulator_disable(st->reg_vss);
- regulator_put(st->reg_vss);
- }
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c
index d546f50f925..ed2d276477b 100644
--- a/drivers/iio/dac/ad7303.c
+++ b/drivers/iio/dac/ad7303.c
@@ -203,7 +203,7 @@ static int ad7303_probe(struct spi_device *spi)
bool ext_ref;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -212,15 +212,13 @@ static int ad7303_probe(struct spi_device *spi)
st->spi = spi;
- st->vdd_reg = regulator_get(&spi->dev, "Vdd");
- if (IS_ERR(st->vdd_reg)) {
- ret = PTR_ERR(st->vdd_reg);
- goto err_free;
- }
+ st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd");
+ if (IS_ERR(st->vdd_reg))
+ return PTR_ERR(st->vdd_reg);
ret = regulator_enable(st->vdd_reg);
if (ret)
- goto err_put_vdd_reg;
+ return ret;
if (spi->dev.of_node) {
ext_ref = of_property_read_bool(spi->dev.of_node,
@@ -234,7 +232,7 @@ static int ad7303_probe(struct spi_device *spi)
}
if (ext_ref) {
- st->vref_reg = regulator_get(&spi->dev, "REF");
+ st->vref_reg = devm_regulator_get(&spi->dev, "REF");
if (IS_ERR(st->vref_reg)) {
ret = PTR_ERR(st->vref_reg);
goto err_disable_vdd_reg;
@@ -242,7 +240,7 @@ static int ad7303_probe(struct spi_device *spi)
ret = regulator_enable(st->vref_reg);
if (ret)
- goto err_put_vref_reg;
+ goto err_disable_vdd_reg;
st->config |= AD7303_CFG_EXTERNAL_VREF;
}
@@ -263,16 +261,8 @@ static int ad7303_probe(struct spi_device *spi)
err_disable_vref_reg:
if (st->vref_reg)
regulator_disable(st->vref_reg);
-err_put_vref_reg:
- if (st->vref_reg)
- regulator_put(st->vref_reg);
err_disable_vdd_reg:
regulator_disable(st->vdd_reg);
-err_put_vdd_reg:
- regulator_put(st->vdd_reg);
-err_free:
- iio_device_free(indio_dev);
-
return ret;
}
@@ -283,14 +273,9 @@ static int ad7303_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
- if (st->vref_reg) {
+ if (st->vref_reg)
regulator_disable(st->vref_reg);
- regulator_put(st->vref_reg);
- }
regulator_disable(st->vdd_reg);
- regulator_put(st->vdd_reg);
-
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
index ebfaa415624..83adcbf1a20 100644
--- a/drivers/iio/dac/max517.c
+++ b/drivers/iio/dac/max517.c
@@ -164,11 +164,9 @@ static int max517_probe(struct i2c_client *client,
struct max517_platform_data *platform_data = client->dev.platform_data;
int err;
- indio_dev = iio_device_alloc(sizeof(*data));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto exit;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
@@ -198,23 +196,16 @@ static int max517_probe(struct i2c_client *client,
err = iio_device_register(indio_dev);
if (err)
- goto exit_free_device;
+ return err;
dev_info(&client->dev, "DAC registered\n");
return 0;
-
-exit_free_device:
- iio_device_free(indio_dev);
-exit:
- return err;
}
static int max517_remove(struct i2c_client *client)
{
iio_device_unregister(i2c_get_clientdata(client));
- iio_device_free(i2c_get_clientdata(client));
-
return 0;
}
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
index a612ec766d9..1f4a48e6a82 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -12,14 +12,13 @@
* driver for the Microchip I2C 12-bit digital-to-analog converter (DAC)
* (7-bit I2C slave address 0x60, the three LSBs can be configured in
* hardware)
- *
- * writing the DAC value to EEPROM is not supported
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/err.h>
+#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -32,15 +31,19 @@ struct mcp4725_data {
struct i2c_client *client;
u16 vref_mv;
u16 dac_value;
+ bool powerdown;
+ unsigned powerdown_mode;
};
-#ifdef CONFIG_PM_SLEEP
static int mcp4725_suspend(struct device *dev)
{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct mcp4725_data *data = iio_priv(indio_dev);
u8 outbuf[2];
- outbuf[0] = 0x3 << 4; /* power-down bits, 500 kOhm resistor */
+ outbuf[0] = (data->powerdown_mode + 1) << 4;
outbuf[1] = 0;
+ data->powerdown = true;
return i2c_master_send(to_i2c_client(dev), outbuf, 2);
}
@@ -54,16 +57,150 @@ static int mcp4725_resume(struct device *dev)
/* restore previous DAC value */
outbuf[0] = (data->dac_value >> 8) & 0xf;
outbuf[1] = data->dac_value & 0xff;
+ data->powerdown = false;
return i2c_master_send(to_i2c_client(dev), outbuf, 2);
}
+#ifdef CONFIG_PM_SLEEP
static SIMPLE_DEV_PM_OPS(mcp4725_pm_ops, mcp4725_suspend, mcp4725_resume);
#define MCP4725_PM_OPS (&mcp4725_pm_ops)
#else
#define MCP4725_PM_OPS NULL
#endif
+static ssize_t mcp4725_store_eeprom(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct mcp4725_data *data = iio_priv(indio_dev);
+ int tries = 20;
+ u8 inoutbuf[3];
+ bool state;
+ int ret;
+
+ ret = strtobool(buf, &state);
+ if (ret < 0)
+ return ret;
+
+ if (!state)
+ return 0;
+
+ inoutbuf[0] = 0x60; /* write EEPROM */
+ inoutbuf[1] = data->dac_value >> 4;
+ inoutbuf[2] = (data->dac_value & 0xf) << 4;
+
+ ret = i2c_master_send(data->client, inoutbuf, 3);
+ if (ret < 0)
+ return ret;
+ else if (ret != 3)
+ return -EIO;
+
+ /* wait for write complete, takes up to 50ms */
+ while (tries--) {
+ msleep(20);
+ ret = i2c_master_recv(data->client, inoutbuf, 3);
+ if (ret < 0)
+ return ret;
+ else if (ret != 3)
+ return -EIO;
+
+ if (inoutbuf[0] & 0x80)
+ break;
+ }
+
+ if (tries < 0) {
+ dev_err(&data->client->dev,
+ "mcp4725_store_eeprom() failed, incomplete\n");
+ return -EIO;
+ }
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(store_eeprom, S_IWUSR, NULL, mcp4725_store_eeprom, 0);
+
+static struct attribute *mcp4725_attributes[] = {
+ &iio_dev_attr_store_eeprom.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group mcp4725_attribute_group = {
+ .attrs = mcp4725_attributes,
+};
+
+static const char * const mcp4725_powerdown_modes[] = {
+ "1kohm_to_gnd",
+ "100kohm_to_gnd",
+ "500kohm_to_gnd"
+};
+
+static int mcp4725_get_powerdown_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct mcp4725_data *data = iio_priv(indio_dev);
+
+ return data->powerdown_mode;
+}
+
+static int mcp4725_set_powerdown_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, unsigned mode)
+{
+ struct mcp4725_data *data = iio_priv(indio_dev);
+
+ data->powerdown_mode = mode;
+
+ return 0;
+}
+
+static ssize_t mcp4725_read_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+ struct mcp4725_data *data = iio_priv(indio_dev);
+
+ return sprintf(buf, "%d\n", data->powerdown);
+}
+
+static ssize_t mcp4725_write_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private, const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct mcp4725_data *data = iio_priv(indio_dev);
+ bool state;
+ int ret;
+
+ ret = strtobool(buf, &state);
+ if (ret)
+ return ret;
+
+ if (state)
+ ret = mcp4725_suspend(&data->client->dev);
+ else
+ ret = mcp4725_resume(&data->client->dev);
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+
+static const struct iio_enum mcp4725_powerdown_mode_enum = {
+ .items = mcp4725_powerdown_modes,
+ .num_items = ARRAY_SIZE(mcp4725_powerdown_modes),
+ .get = mcp4725_get_powerdown_mode,
+ .set = mcp4725_set_powerdown_mode,
+};
+
+static const struct iio_chan_spec_ext_info mcp4725_ext_info[] = {
+ {
+ .name = "powerdown",
+ .read = mcp4725_read_powerdown,
+ .write = mcp4725_write_powerdown,
+ },
+ IIO_ENUM("powerdown_mode", false, &mcp4725_powerdown_mode_enum),
+ IIO_ENUM_AVAILABLE("powerdown_mode", &mcp4725_powerdown_mode_enum),
+ { },
+};
+
static const struct iio_chan_spec mcp4725_channel = {
.type = IIO_VOLTAGE,
.indexed = 1,
@@ -72,6 +209,7 @@ static const struct iio_chan_spec mcp4725_channel = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.scan_type = IIO_ST('u', 12, 16, 0),
+ .ext_info = mcp4725_ext_info,
};
static int mcp4725_set_value(struct iio_dev *indio_dev, int val)
@@ -138,6 +276,7 @@ static int mcp4725_write_raw(struct iio_dev *indio_dev,
static const struct iio_info mcp4725_info = {
.read_raw = mcp4725_read_raw,
.write_raw = mcp4725_write_raw,
+ .attrs = &mcp4725_attribute_group,
.driver_module = THIS_MODULE,
};
@@ -148,19 +287,17 @@ static int mcp4725_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
struct mcp4725_platform_data *platform_data = client->dev.platform_data;
u8 inbuf[3];
+ u8 pd;
int err;
if (!platform_data || !platform_data->vref_mv) {
dev_err(&client->dev, "invalid platform data");
- err = -EINVAL;
- goto exit;
+ return -EINVAL;
}
- indio_dev = iio_device_alloc(sizeof(*data));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto exit;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (indio_dev == NULL)
+ return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
@@ -177,31 +314,25 @@ static int mcp4725_probe(struct i2c_client *client,
err = i2c_master_recv(client, inbuf, 3);
if (err < 0) {
dev_err(&client->dev, "failed to read DAC value");
- goto exit_free_device;
+ return err;
}
+ pd = (inbuf[0] >> 1) & 0x3;
+ data->powerdown = pd > 0 ? true : false;
+ data->powerdown_mode = pd ? pd-1 : 2; /* 500kohm_to_gnd */
data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4);
err = iio_device_register(indio_dev);
if (err)
- goto exit_free_device;
+ return err;
dev_info(&client->dev, "MCP4725 DAC registered\n");
return 0;
-
-exit_free_device:
- iio_device_free(indio_dev);
-exit:
- return err;
}
static int mcp4725_remove(struct i2c_client *client)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
- iio_device_unregister(indio_dev);
- iio_device_free(indio_dev);
-
+ iio_device_unregister(i2c_get_clientdata(client));
return 0;
}
diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig
index 6aaa33ef454..dc5e0b72882 100644
--- a/drivers/iio/frequency/Kconfig
+++ b/drivers/iio/frequency/Kconfig
@@ -4,6 +4,7 @@
# Clock Distribution device drivers
# Phase-Locked Loop (PLL) frequency synthesizers
#
+# When adding new entries keep the list in alphabetical order
menu "Frequency Synthesizers DDS/PLL"
diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile
index 00d26e5d1dc..2bca03f3e2e 100644
--- a/drivers/iio/frequency/Makefile
+++ b/drivers/iio/frequency/Makefile
@@ -2,5 +2,6 @@
# Makefile iio/frequency
#
+# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD9523) += ad9523.o
obj-$(CONFIG_ADF4350) += adf4350.o
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 92276deeb02..7c5245d9f99 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -961,17 +961,17 @@ static int ad9523_probe(struct spi_device *spi)
return -EINVAL;
}
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = regulator_get(&spi->dev, "vcc");
+ st->reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ return ret;
}
spi_set_drvdata(spi, indio_dev);
@@ -1001,11 +1001,6 @@ static int ad9523_probe(struct spi_device *spi)
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
-error_put_reg:
- if (!IS_ERR(st->reg))
- regulator_put(st->reg);
-
- iio_device_free(indio_dev);
return ret;
}
@@ -1017,12 +1012,8 @@ static int ad9523_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
- if (!IS_ERR(st->reg)) {
+ if (!IS_ERR(st->reg))
regulator_disable(st->reg);
- regulator_put(st->reg);
- }
-
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index a4157cdb314..a7b30be86ae 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -515,7 +515,7 @@ static int adf4350_probe(struct spi_device *spi)
}
if (!pdata->clkin) {
- clk = clk_get(&spi->dev, "clkin");
+ clk = devm_clk_get(&spi->dev, "clkin");
if (IS_ERR(clk))
return -EPROBE_DEFER;
@@ -524,17 +524,17 @@ static int adf4350_probe(struct spi_device *spi)
return ret;
}
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = regulator_get(&spi->dev, "vcc");
+ st->reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ goto error_disable_clk;
}
spi_set_drvdata(spi, indio_dev);
@@ -564,7 +564,8 @@ static int adf4350_probe(struct spi_device *spi)
memset(st->regs_hw, 0xFF, sizeof(st->regs_hw));
if (gpio_is_valid(pdata->gpio_lock_detect)) {
- ret = gpio_request(pdata->gpio_lock_detect, indio_dev->name);
+ ret = devm_gpio_request(&spi->dev, pdata->gpio_lock_detect,
+ indio_dev->name);
if (ret) {
dev_err(&spi->dev, "fail to request lock detect GPIO-%d",
pdata->gpio_lock_detect);
@@ -576,29 +577,21 @@ static int adf4350_probe(struct spi_device *spi)
if (pdata->power_up_frequency) {
ret = adf4350_set_freq(st, pdata->power_up_frequency);
if (ret)
- goto error_free_gpio;
+ goto error_disable_reg;
}
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_gpio;
+ goto error_disable_reg;
return 0;
-error_free_gpio:
- if (gpio_is_valid(pdata->gpio_lock_detect))
- gpio_free(pdata->gpio_lock_detect);
-
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
-error_put_reg:
- if (!IS_ERR(st->reg))
- regulator_put(st->reg);
-
+error_disable_clk:
if (clk)
clk_disable_unprepare(clk);
- iio_device_free(indio_dev);
return ret;
}
@@ -619,14 +612,8 @@ static int adf4350_remove(struct spi_device *spi)
if (!IS_ERR(reg)) {
regulator_disable(reg);
- regulator_put(reg);
}
- if (gpio_is_valid(st->pdata->gpio_lock_detect))
- gpio_free(st->pdata->gpio_lock_detect);
-
- iio_device_free(indio_dev);
-
return 0;
}
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
index 8498e9dcda6..41c64a43bca 100644
--- a/drivers/iio/gyro/Kconfig
+++ b/drivers/iio/gyro/Kconfig
@@ -1,6 +1,8 @@
#
# IIO Digital Gyroscope Sensor drivers configuration
#
+# When adding new entries keep the list in alphabetical order
+
menu "Digital gyroscope sensors"
config ADIS16080
@@ -26,6 +28,18 @@ config ADIS16136
Say yes here to build support for the Analog Devices ADIS16133, ADIS16135,
ADIS16136 gyroscope devices.
+config ADIS16260
+ tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver"
+ depends on SPI
+ select IIO_ADIS_LIB
+ select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
+ help
+ Say yes here to build support for Analog Devices ADIS16260 ADIS16265
+ ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors.
+
+ This driver can also be built as a module. If so, the module
+ will be called adis16260.
+
config ADXRS450
tristate "Analog Devices ADXRS450/3 Digital Output Gyroscope SPI driver"
depends on SPI
@@ -58,8 +72,8 @@ config IIO_ST_GYRO_3AXIS
Say yes here to build support for STMicroelectronics gyroscopes:
L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330.
- This driver can also be built as a module. If so, will be created
- these modules:
+ This driver can also be built as a module. If so, these modules
+ will be created:
- st_gyro (core functions for the driver [it is mandatory]);
- st_gyro_i2c (necessary for the I2C devices [optional*]);
- st_gyro_spi (necessary for the SPI devices [optional*]);
diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
index e9dc034aa18..2f2752a4ea8 100644
--- a/drivers/iio/gyro/Makefile
+++ b/drivers/iio/gyro/Makefile
@@ -2,9 +2,11 @@
# Makefile for industrial I/O gyroscope sensor drivers
#
+# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ADIS16080) += adis16080.o
obj-$(CONFIG_ADIS16130) += adis16130.o
obj-$(CONFIG_ADIS16136) += adis16136.o
+obj-$(CONFIG_ADIS16260) += adis16260.o
obj-$(CONFIG_ADXRS450) += adxrs450.o
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c
index e1bb5f994a5..e9ec022ae22 100644
--- a/drivers/iio/gyro/adis16080.c
+++ b/drivers/iio/gyro/adis16080.c
@@ -192,16 +192,13 @@ static const struct adis16080_chip_info adis16080_chip_info[] = {
static int adis16080_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
- int ret;
struct adis16080_state *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
@@ -217,22 +214,12 @@ static int adis16080_probe(struct spi_device *spi)
indio_dev->info = &adis16080_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_free_dev;
- return 0;
-
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
- return ret;
+ return iio_device_register(indio_dev);
}
static int adis16080_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_device_free(spi_get_drvdata(spi));
-
return 0;
}
diff --git a/drivers/iio/gyro/adis16130.c b/drivers/iio/gyro/adis16130.c
index 129acdf801a..ac66fc18404 100644
--- a/drivers/iio/gyro/adis16130.c
+++ b/drivers/iio/gyro/adis16130.c
@@ -148,16 +148,13 @@ static const struct iio_info adis16130_info = {
static int adis16130_probe(struct spi_device *spi)
{
- int ret;
struct adis16130_state *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
@@ -170,24 +167,12 @@ static int adis16130_probe(struct spi_device *spi)
indio_dev->info = &adis16130_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_free_dev;
-
- return 0;
-
-error_free_dev:
- iio_device_free(indio_dev);
-
-error_ret:
- return ret;
+ return iio_device_register(indio_dev);
}
static int adis16130_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_device_free(spi_get_drvdata(spi));
-
return 0;
}
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
index 058e6d5c955..591bd555e1f 100644
--- a/drivers/iio/gyro/adis16136.c
+++ b/drivers/iio/gyro/adis16136.c
@@ -497,7 +497,7 @@ static int adis16136_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret;
- indio_dev = iio_device_alloc(sizeof(*adis16136));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136));
if (indio_dev == NULL)
return -ENOMEM;
@@ -515,11 +515,11 @@ static int adis16136_probe(struct spi_device *spi)
ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis16136_initial_setup(indio_dev);
if (ret)
@@ -537,8 +537,6 @@ error_stop_device:
adis16136_stop_device(indio_dev);
error_cleanup_buffer:
adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
return ret;
}
@@ -552,8 +550,6 @@ static int adis16136_remove(struct spi_device *spi)
adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
- iio_device_free(indio_dev);
-
return 0;
}
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/iio/gyro/adis16260.c
index 620d63fd099..06541162fc0 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/iio/gyro/adis16260.c
@@ -7,54 +7,119 @@
*/
#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-#include <linux/slab.h>
#include <linux/sysfs.h>
-#include <linux/list.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/imu/adis.h>
+
+#define ADIS16260_STARTUP_DELAY 220 /* ms */
+
+#define ADIS16260_FLASH_CNT 0x00 /* Flash memory write count */
+#define ADIS16260_SUPPLY_OUT 0x02 /* Power supply measurement */
+#define ADIS16260_GYRO_OUT 0x04 /* X-axis gyroscope output */
+#define ADIS16260_AUX_ADC 0x0A /* analog input channel measurement */
+#define ADIS16260_TEMP_OUT 0x0C /* internal temperature measurement */
+#define ADIS16260_ANGL_OUT 0x0E /* angle displacement */
+#define ADIS16260_GYRO_OFF 0x14 /* Calibration, offset/bias adjustment */
+#define ADIS16260_GYRO_SCALE 0x16 /* Calibration, scale adjustment */
+#define ADIS16260_ALM_MAG1 0x20 /* Alarm 1 magnitude/polarity setting */
+#define ADIS16260_ALM_MAG2 0x22 /* Alarm 2 magnitude/polarity setting */
+#define ADIS16260_ALM_SMPL1 0x24 /* Alarm 1 dynamic rate of change setting */
+#define ADIS16260_ALM_SMPL2 0x26 /* Alarm 2 dynamic rate of change setting */
+#define ADIS16260_ALM_CTRL 0x28 /* Alarm control */
+#define ADIS16260_AUX_DAC 0x30 /* Auxiliary DAC data */
+#define ADIS16260_GPIO_CTRL 0x32 /* Control, digital I/O line */
+#define ADIS16260_MSC_CTRL 0x34 /* Control, data ready, self-test settings */
+#define ADIS16260_SMPL_PRD 0x36 /* Control, internal sample rate */
+#define ADIS16260_SENS_AVG 0x38 /* Control, dynamic range, filtering */
+#define ADIS16260_SLP_CNT 0x3A /* Control, sleep mode initiation */
+#define ADIS16260_DIAG_STAT 0x3C /* Diagnostic, error flags */
+#define ADIS16260_GLOB_CMD 0x3E /* Control, global commands */
+#define ADIS16260_LOT_ID1 0x52 /* Lot Identification Code 1 */
+#define ADIS16260_LOT_ID2 0x54 /* Lot Identification Code 2 */
+#define ADIS16260_PROD_ID 0x56 /* Product identifier;
+ * convert to decimal = 16,265/16,260 */
+#define ADIS16260_SERIAL_NUM 0x58 /* Serial number */
+
+#define ADIS16260_ERROR_ACTIVE (1<<14)
+#define ADIS16260_NEW_DATA (1<<15)
+
+/* MSC_CTRL */
+#define ADIS16260_MSC_CTRL_MEM_TEST (1<<11)
+/* Internal self-test enable */
+#define ADIS16260_MSC_CTRL_INT_SELF_TEST (1<<10)
+#define ADIS16260_MSC_CTRL_NEG_SELF_TEST (1<<9)
+#define ADIS16260_MSC_CTRL_POS_SELF_TEST (1<<8)
+#define ADIS16260_MSC_CTRL_DATA_RDY_EN (1<<2)
+#define ADIS16260_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1)
+#define ADIS16260_MSC_CTRL_DATA_RDY_DIO2 (1<<0)
+
+/* SMPL_PRD */
+/* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */
+#define ADIS16260_SMPL_PRD_TIME_BASE (1<<7)
+#define ADIS16260_SMPL_PRD_DIV_MASK 0x7F
+
+/* SLP_CNT */
+#define ADIS16260_SLP_CNT_POWER_OFF 0x80
+
+/* DIAG_STAT */
+#define ADIS16260_DIAG_STAT_ALARM2 (1<<9)
+#define ADIS16260_DIAG_STAT_ALARM1 (1<<8)
+#define ADIS16260_DIAG_STAT_FLASH_CHK_BIT 6
+#define ADIS16260_DIAG_STAT_SELF_TEST_BIT 5
+#define ADIS16260_DIAG_STAT_OVERFLOW_BIT 4
+#define ADIS16260_DIAG_STAT_SPI_FAIL_BIT 3
+#define ADIS16260_DIAG_STAT_FLASH_UPT_BIT 2
+#define ADIS16260_DIAG_STAT_POWER_HIGH_BIT 1
+#define ADIS16260_DIAG_STAT_POWER_LOW_BIT 0
+
+/* GLOB_CMD */
+#define ADIS16260_GLOB_CMD_SW_RESET (1<<7)
+#define ADIS16260_GLOB_CMD_FLASH_UPD (1<<3)
+#define ADIS16260_GLOB_CMD_DAC_LATCH (1<<2)
+#define ADIS16260_GLOB_CMD_FAC_CALIB (1<<1)
+#define ADIS16260_GLOB_CMD_AUTO_NULL (1<<0)
+
+#define ADIS16260_SPI_SLOW (u32)(300 * 1000)
+#define ADIS16260_SPI_BURST (u32)(1000 * 1000)
+#define ADIS16260_SPI_FAST (u32)(2000 * 1000)
+
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
-#include "adis16260.h"
-
-static ssize_t adis16260_read_frequency_available(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct adis16260_state *st = iio_priv(indio_dev);
- if (spi_get_device_id(st->adis.spi)->driver_data)
- return sprintf(buf, "%s\n", "0.129 ~ 256");
- else
- return sprintf(buf, "%s\n", "256 2048");
-}
+#define ADIS16260_SCAN_GYRO 0
+#define ADIS16260_SCAN_SUPPLY 1
+#define ADIS16260_SCAN_AUX_ADC 2
+#define ADIS16260_SCAN_TEMP 3
+#define ADIS16260_SCAN_ANGL 4
static ssize_t adis16260_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct adis16260_state *st = iio_priv(indio_dev);
+ struct adis *adis = iio_priv(indio_dev);
int ret, len = 0;
u16 t;
int sps;
- ret = adis_read_reg_16(&st->adis, ADIS16260_SMPL_PRD, &t);
+ ret = adis_read_reg_16(adis, ADIS16260_SMPL_PRD, &t);
if (ret)
return ret;
- if (spi_get_device_id(st->adis.spi)->driver_data) /* If an adis16251 */
- sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 8 : 256;
+ if (spi_get_device_id(adis->spi)->driver_data) /* If an adis16251 */
+ sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 8 : 256;
else
- sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048;
+ sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048;
sps /= (t & ADIS16260_SMPL_PRD_DIV_MASK) + 1;
- len = sprintf(buf, "%d SPS\n", sps);
+ len = sprintf(buf, "%d\n", sps);
return len;
}
@@ -64,36 +129,31 @@ static ssize_t adis16260_write_frequency(struct device *dev,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct adis16260_state *st = iio_priv(indio_dev);
- long val;
+ struct adis *adis = iio_priv(indio_dev);
+ unsigned int val;
int ret;
u8 t;
- ret = strict_strtol(buf, 10, &val);
+ ret = kstrtouint(buf, 10, &val);
if (ret)
return ret;
- if (val == 0)
- return -EINVAL;
mutex_lock(&indio_dev->mlock);
- if (spi_get_device_id(st->adis.spi)->driver_data) {
- t = (256 / val);
- if (t > 0)
- t--;
- t &= ADIS16260_SMPL_PRD_DIV_MASK;
- } else {
- t = (2048 / val);
- if (t > 0)
- t--;
- t &= ADIS16260_SMPL_PRD_DIV_MASK;
- }
- if ((t & ADIS16260_SMPL_PRD_DIV_MASK) >= 0x0A)
- st->adis.spi->max_speed_hz = ADIS16260_SPI_SLOW;
+ if (spi_get_device_id(adis->spi)->driver_data)
+ t = 256 / val;
+ else
+ t = 2048 / val;
+
+ if (t > ADIS16260_SMPL_PRD_DIV_MASK)
+ t = ADIS16260_SMPL_PRD_DIV_MASK;
+ else if (t > 0)
+ t--;
+
+ if (t >= 0x0A)
+ adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
else
- st->adis.spi->max_speed_hz = ADIS16260_SPI_FAST;
- ret = adis_write_reg_8(&st->adis,
- ADIS16260_SMPL_PRD,
- t);
+ adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
+ ret = adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
mutex_unlock(&indio_dev->mlock);
@@ -103,11 +163,11 @@ static ssize_t adis16260_write_frequency(struct device *dev,
/* Power down the device */
static int adis16260_stop_device(struct iio_dev *indio_dev)
{
- struct adis16260_state *st = iio_priv(indio_dev);
+ struct adis *adis = iio_priv(indio_dev);
int ret;
u16 val = ADIS16260_SLP_CNT_POWER_OFF;
- ret = adis_write_reg_16(&st->adis, ADIS16260_SLP_CNT, val);
+ ret = adis_write_reg_16(adis, ADIS16260_SLP_CNT, val);
if (ret)
dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
@@ -118,24 +178,16 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
adis16260_read_frequency,
adis16260_write_frequency);
-static IIO_DEVICE_ATTR(sampling_frequency_available,
- S_IRUGO, adis16260_read_frequency_available, NULL, 0);
-
-#define ADIS16260_GYRO_CHANNEL_SET(axis, mod) \
-struct iio_chan_spec adis16260_channels_##axis[] = { \
- ADIS_GYRO_CHAN(mod, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, \
- BIT(IIO_CHAN_INFO_CALIBBIAS) | \
- BIT(IIO_CHAN_INFO_CALIBSCALE), 14), \
- ADIS_INCLI_CHAN(mod, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, 14), \
- ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, 12), \
- ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, 12), \
- ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, 12), \
- IIO_CHAN_SOFT_TIMESTAMP(5), \
-}
-
-static const ADIS16260_GYRO_CHANNEL_SET(x, X);
-static const ADIS16260_GYRO_CHANNEL_SET(y, Y);
-static const ADIS16260_GYRO_CHANNEL_SET(z, Z);
+static const struct iio_chan_spec adis16260_channels[] = {
+ ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE), 14),
+ ADIS_INCLI_CHAN(X, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, 14),
+ ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, 12),
+ ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, 12),
+ ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(5),
+};
static const u8 adis16260_addresses[][2] = {
[ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE },
@@ -146,9 +198,8 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
int *val, int *val2,
long mask)
{
- struct adis16260_state *st = iio_priv(indio_dev);
+ struct adis *adis = iio_priv(indio_dev);
int ret;
- int bits;
u8 addr;
s16 val16;
@@ -160,7 +211,7 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_ANGL_VEL:
*val = 0;
- if (spi_get_device_id(st->adis.spi)->driver_data) {
+ if (spi_get_device_id(adis->spi)->driver_data) {
/* 0.01832 degree / sec */
*val2 = IIO_DEGREE_TO_RAD(18320);
} else {
@@ -168,6 +219,10 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
*val2 = IIO_DEGREE_TO_RAD(73260);
}
return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_INCLI:
+ *val = 0;
+ *val2 = IIO_DEGREE_TO_RAD(36630);
+ return IIO_VAL_INT_PLUS_MICRO;
case IIO_VOLTAGE:
if (chan->channel == 0) {
*val = 1;
@@ -189,42 +244,20 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
*val = 250000 / 1453; /* 25 C = 0x00 */
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
- switch (chan->type) {
- case IIO_ANGL_VEL:
- bits = 12;
- break;
- default:
- return -EINVAL;
- }
- mutex_lock(&indio_dev->mlock);
addr = adis16260_addresses[chan->scan_index][0];
- ret = adis_read_reg_16(&st->adis, addr, &val16);
- if (ret) {
- mutex_unlock(&indio_dev->mlock);
+ ret = adis_read_reg_16(adis, addr, &val16);
+ if (ret)
return ret;
- }
- val16 &= (1 << bits) - 1;
- val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
- *val = val16;
- mutex_unlock(&indio_dev->mlock);
+
+ *val = sign_extend32(val16, 11);
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBSCALE:
- switch (chan->type) {
- case IIO_ANGL_VEL:
- bits = 12;
- break;
- default:
- return -EINVAL;
- }
- mutex_lock(&indio_dev->mlock);
addr = adis16260_addresses[chan->scan_index][1];
- ret = adis_read_reg_16(&st->adis, addr, &val16);
- if (ret) {
- mutex_unlock(&indio_dev->mlock);
+ ret = adis_read_reg_16(adis, addr, &val16);
+ if (ret)
return ret;
- }
- *val = (1 << bits) - 1;
- mutex_unlock(&indio_dev->mlock);
+
+ *val = val16;
return IIO_VAL_INT;
}
return -EINVAL;
@@ -236,26 +269,28 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
int val2,
long mask)
{
- struct adis16260_state *st = iio_priv(indio_dev);
- int bits = 12;
- s16 val16;
+ struct adis *adis = iio_priv(indio_dev);
u8 addr;
+
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
- val16 = val & ((1 << bits) - 1);
+ if (val < -2048 || val >= 2048)
+ return -EINVAL;
+
addr = adis16260_addresses[chan->scan_index][0];
- return adis_write_reg_16(&st->adis, addr, val16);
+ return adis_write_reg_16(adis, addr, val);
case IIO_CHAN_INFO_CALIBSCALE:
- val16 = val & ((1 << bits) - 1);
+ if (val < 0 || val >= 4096)
+ return -EINVAL;
+
addr = adis16260_addresses[chan->scan_index][1];
- return adis_write_reg_16(&st->adis, addr, val16);
+ return adis_write_reg_16(adis, addr, val);
}
return -EINVAL;
}
static struct attribute *adis16260_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
- &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
@@ -303,71 +338,35 @@ static const struct adis_data adis16260_data = {
static int adis16260_probe(struct spi_device *spi)
{
- int ret;
- struct adis16260_platform_data *pd = spi->dev.platform_data;
- struct adis16260_state *st;
struct iio_dev *indio_dev;
+ struct adis *adis;
+ int ret;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
- st = iio_priv(indio_dev);
- if (pd)
- st->negate = pd->negate;
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis));
+ if (!indio_dev)
+ return -ENOMEM;
+ adis = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16260_info;
- indio_dev->num_channels
- = ARRAY_SIZE(adis16260_channels_x);
- if (pd && pd->direction)
- switch (pd->direction) {
- case 'x':
- indio_dev->channels = adis16260_channels_x;
- break;
- case 'y':
- indio_dev->channels = adis16260_channels_y;
- break;
- case 'z':
- indio_dev->channels = adis16260_channels_z;
- break;
- default:
- return -EINVAL;
- }
- else
- indio_dev->channels = adis16260_channels_x;
- indio_dev->num_channels = ARRAY_SIZE(adis16260_channels_x);
+ indio_dev->channels = adis16260_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adis16260_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = adis_init(&st->adis, indio_dev, spi, &adis16260_data);
+ ret = adis_init(adis, indio_dev, spi, &adis16260_data);
if (ret)
- goto error_free_dev;
+ return ret;
- ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
+ ret = adis_setup_buffer_and_trigger(adis, indio_dev, NULL);
if (ret)
- goto error_free_dev;
-
- if (indio_dev->buffer) {
- /* Set default scan mode */
- iio_scan_mask_set(indio_dev, indio_dev->buffer,
- ADIS16260_SCAN_SUPPLY);
- iio_scan_mask_set(indio_dev, indio_dev->buffer,
- ADIS16260_SCAN_GYRO);
- iio_scan_mask_set(indio_dev, indio_dev->buffer,
- ADIS16260_SCAN_AUX_ADC);
- iio_scan_mask_set(indio_dev, indio_dev->buffer,
- ADIS16260_SCAN_TEMP);
- iio_scan_mask_set(indio_dev, indio_dev->buffer,
- ADIS16260_SCAN_ANGL);
- }
+ return ret;
/* Get the device into a sane initial state */
- ret = adis_initial_startup(&st->adis);
+ ret = adis_initial_startup(adis);
if (ret)
goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev);
@@ -377,22 +376,18 @@ static int adis16260_probe(struct spi_device *spi)
return 0;
error_cleanup_buffer_trigger:
- adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
+ adis_cleanup_buffer_and_trigger(adis, indio_dev);
return ret;
}
static int adis16260_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct adis16260_state *st = iio_priv(indio_dev);
+ struct adis *adis = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16260_stop_device(indio_dev);
- adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
- iio_device_free(indio_dev);
+ adis_cleanup_buffer_and_trigger(adis, indio_dev);
return 0;
}
diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c
index 8bd72b490b7..6dab2995f0f 100644
--- a/drivers/iio/gyro/adxrs450.c
+++ b/drivers/iio/gyro/adxrs450.c
@@ -426,11 +426,9 @@ static int adxrs450_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
@@ -447,7 +445,7 @@ static int adxrs450_probe(struct spi_device *spi)
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_dev;
+ return ret;
/* Get the device into a sane initial state */
ret = adxrs450_initial_setup(indio_dev);
@@ -456,17 +454,12 @@ static int adxrs450_probe(struct spi_device *spi)
return 0;
error_initial:
iio_device_unregister(indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-
-error_ret:
return ret;
}
static int adxrs450_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index bc943dd47da..c688d974d3e 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -30,10 +30,6 @@
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
-/*Format: HID-SENSOR-usage_id_in_hex*/
-/*Usage ID from spec for Gyro-3D: 0x200076*/
-#define DRIVER_NAME "HID-SENSOR-200076"
-
enum gyro_3d_channel {
CHANNEL_SCAN_INDEX_X,
CHANNEL_SCAN_INDEX_Y,
@@ -179,18 +175,10 @@ static int gyro_3d_write_raw(struct iio_dev *indio_dev,
return ret;
}
-static int gyro_3d_write_raw_get_fmt(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- long mask)
-{
- return IIO_VAL_INT_PLUS_MICRO;
-}
-
static const struct iio_info gyro_3d_info = {
.driver_module = THIS_MODULE,
.read_raw = &gyro_3d_read_raw,
.write_raw = &gyro_3d_write_raw,
- .write_raw_get_fmt = &gyro_3d_write_raw_get_fmt,
};
/* Function to push data to buffer */
@@ -286,11 +274,9 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
- indio_dev = iio_device_alloc(sizeof(struct gyro_3d_state));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*gyro_state));
+ if (!indio_dev)
+ return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
gyro_state = iio_priv(indio_dev);
@@ -302,15 +288,14 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
&gyro_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
- goto error_free_dev;
+ return ret;
}
channels = kmemdup(gyro_3d_channels, sizeof(gyro_3d_channels),
GFP_KERNEL);
if (!channels) {
- ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
- goto error_free_dev;
+ return -ENOMEM;
}
ret = gyro_3d_parse_report(pdev, hsdev, channels,
@@ -367,9 +352,6 @@ error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
error_free_dev_mem:
kfree(indio_dev->channels);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -384,14 +366,23 @@ static int hid_gyro_3d_remove(struct platform_device *pdev)
hid_sensor_remove_trigger(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
kfree(indio_dev->channels);
- iio_device_free(indio_dev);
return 0;
}
+static struct platform_device_id hid_gyro_3d_ids[] = {
+ {
+ /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+ .name = "HID-SENSOR-200076",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_gyro_3d_ids);
+
static struct platform_driver hid_gyro_3d_platform_driver = {
+ .id_table = hid_gyro_3d_ids,
.driver = {
- .name = DRIVER_NAME,
+ .name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
.probe = hid_gyro_3d_probe,
diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c
index d66605d2629..4d3f3b92b36 100644
--- a/drivers/iio/gyro/itg3200_core.c
+++ b/drivers/iio/gyro/itg3200_core.c
@@ -309,11 +309,9 @@ static int itg3200_probe(struct i2c_client *client,
dev_dbg(&client->dev, "probe I2C dev with IRQ %i", client->irq);
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
@@ -330,7 +328,7 @@ static int itg3200_probe(struct i2c_client *client,
ret = itg3200_buffer_configure(indio_dev);
if (ret)
- goto error_free_dev;
+ return ret;
if (client->irq) {
ret = itg3200_probe_trigger(indio_dev);
@@ -353,9 +351,6 @@ error_remove_trigger:
itg3200_remove_trigger(indio_dev);
error_unconfigure_buffer:
itg3200_buffer_unconfigure(indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -370,8 +365,6 @@ static int itg3200_remove(struct i2c_client *client)
itg3200_buffer_unconfigure(indio_dev);
- iio_device_free(indio_dev);
-
return 0;
}
diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h
index 3ad9907bb15..f8f2bf84a5a 100644
--- a/drivers/iio/gyro/st_gyro.h
+++ b/drivers/iio/gyro/st_gyro.h
@@ -23,7 +23,16 @@
#define L3G4IS_GYRO_DEV_NAME "l3g4is_ui"
#define LSM330_GYRO_DEV_NAME "lsm330_gyro"
-int st_gyro_common_probe(struct iio_dev *indio_dev);
+/**
+ * struct st_sensors_platform_data - gyro platform data
+ * @drdy_int_pin: DRDY on gyros is available only on INT2 pin.
+ */
+static const struct st_sensors_platform_data gyro_pdata = {
+ .drdy_int_pin = 2,
+};
+
+int st_gyro_common_probe(struct iio_dev *indio_dev,
+ struct st_sensors_platform_data *pdata);
void st_gyro_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
index f9ed3488c31..e13c2b0bf3d 100644
--- a/drivers/iio/gyro/st_gyro_core.c
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -60,7 +60,7 @@
#define ST_GYRO_1_BDU_ADDR 0x23
#define ST_GYRO_1_BDU_MASK 0x80
#define ST_GYRO_1_DRDY_IRQ_ADDR 0x22
-#define ST_GYRO_1_DRDY_IRQ_MASK 0x08
+#define ST_GYRO_1_DRDY_IRQ_INT2_MASK 0x08
#define ST_GYRO_1_MULTIREAD_BIT true
/* CUSTOM VALUES FOR SENSOR 2 */
@@ -84,7 +84,7 @@
#define ST_GYRO_2_BDU_ADDR 0x23
#define ST_GYRO_2_BDU_MASK 0x80
#define ST_GYRO_2_DRDY_IRQ_ADDR 0x22
-#define ST_GYRO_2_DRDY_IRQ_MASK 0x08
+#define ST_GYRO_2_DRDY_IRQ_INT2_MASK 0x08
#define ST_GYRO_2_MULTIREAD_BIT true
static const struct iio_chan_spec st_gyro_16bit_channels[] = {
@@ -158,7 +158,7 @@ static const struct st_sensors st_gyro_sensors[] = {
},
.drdy_irq = {
.addr = ST_GYRO_1_DRDY_IRQ_ADDR,
- .mask = ST_GYRO_1_DRDY_IRQ_MASK,
+ .mask_int2 = ST_GYRO_1_DRDY_IRQ_INT2_MASK,
},
.multi_read_bit = ST_GYRO_1_MULTIREAD_BIT,
.bootime = 2,
@@ -221,7 +221,7 @@ static const struct st_sensors st_gyro_sensors[] = {
},
.drdy_irq = {
.addr = ST_GYRO_2_DRDY_IRQ_ADDR,
- .mask = ST_GYRO_2_DRDY_IRQ_MASK,
+ .mask_int2 = ST_GYRO_2_DRDY_IRQ_INT2_MASK,
},
.multi_read_bit = ST_GYRO_2_MULTIREAD_BIT,
.bootime = 2,
@@ -302,7 +302,8 @@ static const struct iio_trigger_ops st_gyro_trigger_ops = {
#define ST_GYRO_TRIGGER_OPS NULL
#endif
-int st_gyro_common_probe(struct iio_dev *indio_dev)
+int st_gyro_common_probe(struct iio_dev *indio_dev,
+ struct st_sensors_platform_data *pdata)
{
int err;
struct st_sensor_data *gdata = iio_priv(indio_dev);
@@ -324,7 +325,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
&gdata->sensor->fs.fs_avl[0];
gdata->odr = gdata->sensor->odr.odr_avl[0].hz;
- err = st_sensors_init_sensor(indio_dev);
+ err = st_sensors_init_sensor(indio_dev, pdata);
if (err < 0)
goto st_gyro_common_probe_error;
@@ -365,7 +366,6 @@ void st_gyro_common_remove(struct iio_dev *indio_dev)
st_sensors_deallocate_trigger(indio_dev);
st_gyro_deallocate_ring(indio_dev);
}
- iio_device_free(indio_dev);
}
EXPORT_SYMBOL(st_gyro_common_remove);
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
index 8a310500573..16b8b8d70bf 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -25,27 +25,21 @@ static int st_gyro_i2c_probe(struct i2c_client *client,
struct st_sensor_data *gdata;
int err;
- indio_dev = iio_device_alloc(sizeof(*gdata));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto iio_device_alloc_error;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*gdata));
+ if (!indio_dev)
+ return -ENOMEM;
gdata = iio_priv(indio_dev);
gdata->dev = &client->dev;
st_sensors_i2c_configure(indio_dev, client, gdata);
- err = st_gyro_common_probe(indio_dev);
+ err = st_gyro_common_probe(indio_dev,
+ (struct st_sensors_platform_data *)&gyro_pdata);
if (err < 0)
- goto st_gyro_common_probe_error;
+ return err;
return 0;
-
-st_gyro_common_probe_error:
- iio_device_free(indio_dev);
-iio_device_alloc_error:
- return err;
}
static int st_gyro_i2c_remove(struct i2c_client *client)
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
index f3540390eb2..94763e25caf 100644
--- a/drivers/iio/gyro/st_gyro_spi.c
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -24,27 +24,21 @@ static int st_gyro_spi_probe(struct spi_device *spi)
struct st_sensor_data *gdata;
int err;
- indio_dev = iio_device_alloc(sizeof(*gdata));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto iio_device_alloc_error;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*gdata));
+ if (!indio_dev)
+ return -ENOMEM;
gdata = iio_priv(indio_dev);
gdata->dev = &spi->dev;
st_sensors_spi_configure(indio_dev, spi, gdata);
- err = st_gyro_common_probe(indio_dev);
+ err = st_gyro_common_probe(indio_dev,
+ (struct st_sensors_platform_data *)&gyro_pdata);
if (err < 0)
- goto st_gyro_common_probe_error;
+ return err;
return 0;
-
-st_gyro_common_probe_error:
- iio_device_free(indio_dev);
-iio_device_alloc_error:
- return err;
}
static int st_gyro_spi_remove(struct spi_device *spi)
diff --git a/drivers/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h
index 6f7c56fcbe7..1fdb1e4ea4a 100644
--- a/drivers/iio/iio_core_trigger.h
+++ b/drivers/iio/iio_core_trigger.h
@@ -30,7 +30,7 @@ void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev);
static int iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
{
return 0;
-};
+}
/**
* iio_device_unregister_trigger_consumer() - reverse the registration process
@@ -38,9 +38,6 @@ static int iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
**/
static void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
{
-};
+}
#endif /* CONFIG_TRIGGER_CONSUMER */
-
-
-
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 4f40a10cb74..663e88a1a3c 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -1,6 +1,8 @@
#
# IIO imu drivers configuration
#
+# When adding new entries keep the list in alphabetical order
+
menu "Inertial measurement units"
config ADIS16400
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index f2f56ceaed2..114d2c17cbe 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -2,6 +2,7 @@
# Makefile for Inertial Measurement Units
#
+# When adding new entries keep the list in alphabetical order
adis16400-y := adis16400_core.o
adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o
obj-$(CONFIG_ADIS16400) += adis16400.o
diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c
index f60591f0b92..3fb7757a102 100644
--- a/drivers/iio/imu/adis16400_core.c
+++ b/drivers/iio/imu/adis16400_core.c
@@ -871,7 +871,7 @@ static int adis16400_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -893,12 +893,12 @@ static int adis16400_probe(struct spi_device *spi)
ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev,
adis16400_trigger_handler);
if (ret)
- goto error_free_dev;
+ return ret;
/* Get the device into a sane initial state */
ret = adis16400_initial_setup(indio_dev);
@@ -913,8 +913,6 @@ static int adis16400_probe(struct spi_device *spi)
error_cleanup_buffer:
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
return ret;
}
@@ -928,8 +926,6 @@ static int adis16400_remove(struct spi_device *spi)
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
- iio_device_free(indio_dev);
-
return 0;
}
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index b7db3837629..dd4206cac62 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -839,7 +839,7 @@ static int adis16480_probe(struct spi_device *spi)
struct adis16480 *st;
int ret;
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -857,11 +857,11 @@ static int adis16480_probe(struct spi_device *spi)
ret = adis_init(&st->adis, indio_dev, spi, &adis16480_data);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis16480_initial_setup(indio_dev);
if (ret)
@@ -879,8 +879,6 @@ error_stop_device:
adis16480_stop_device(indio_dev);
error_cleanup_buffer:
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
return ret;
}
@@ -894,8 +892,6 @@ static int adis16480_remove(struct spi_device *spi)
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
- iio_device_free(indio_dev);
-
return 0;
}
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index fe4c61e219f..df7f1e1157a 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/kfifo.h>
#include <linux/spinlock.h>
+#include <linux/iio/iio.h>
#include "inv_mpu_iio.h"
/*
@@ -663,16 +664,13 @@ static int inv_mpu_probe(struct i2c_client *client,
int result;
if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_I2C_BLOCK |
- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
- result = -ENOSYS;
- goto out_no_free;
- }
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- result = -ENOMEM;
- goto out_no_free;
- }
+ I2C_FUNC_SMBUS_I2C_BLOCK))
+ return -ENOSYS;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
st = iio_priv(indio_dev);
st->client = client;
st->plat_data = *(struct inv_mpu6050_platform_data
@@ -680,13 +678,13 @@ static int inv_mpu_probe(struct i2c_client *client,
/* power is turned on inside check chip type*/
result = inv_check_and_setup_chip(st, id);
if (result)
- goto out_free;
+ return result;
result = inv_mpu6050_init_config(indio_dev);
if (result) {
dev_err(&client->dev,
"Could not initialize device.\n");
- goto out_free;
+ return result;
}
i2c_set_clientdata(client, indio_dev);
@@ -705,7 +703,7 @@ static int inv_mpu_probe(struct i2c_client *client,
if (result) {
dev_err(&st->client->dev, "configure buffer fail %d\n",
result);
- goto out_free;
+ return result;
}
result = inv_mpu6050_probe_trigger(indio_dev);
if (result) {
@@ -727,10 +725,6 @@ out_remove_trigger:
inv_mpu6050_remove_trigger(st);
out_unreg_ring:
iio_triggered_buffer_cleanup(indio_dev);
-out_free:
- iio_device_free(indio_dev);
-out_no_free:
-
return result;
}
@@ -742,7 +736,6 @@ static int inv_mpu_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
inv_mpu6050_remove_trigger(st);
iio_triggered_buffer_cleanup(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index e145931ef1b..97f0297b120 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -383,14 +383,14 @@ static ssize_t iio_read_channel_info(struct device *dev,
scale_db = true;
case IIO_VAL_INT_PLUS_MICRO:
if (val2 < 0)
- return sprintf(buf, "-%d.%06u%s\n", val, -val2,
+ return sprintf(buf, "-%ld.%06u%s\n", abs(val), -val2,
scale_db ? " dB" : "");
else
return sprintf(buf, "%d.%06u%s\n", val, val2,
scale_db ? " dB" : "");
case IIO_VAL_INT_PLUS_NANO:
if (val2 < 0)
- return sprintf(buf, "-%d.%09u\n", val, -val2);
+ return sprintf(buf, "-%ld.%09u\n", abs(val), -val2);
else
return sprintf(buf, "%d.%09u\n", val, val2);
case IIO_VAL_FRACTIONAL:
@@ -912,6 +912,53 @@ void iio_device_free(struct iio_dev *dev)
}
EXPORT_SYMBOL(iio_device_free);
+static void devm_iio_device_release(struct device *dev, void *res)
+{
+ iio_device_free(*(struct iio_dev **)res);
+}
+
+static int devm_iio_device_match(struct device *dev, void *res, void *data)
+{
+ struct iio_dev **r = res;
+ if (!r || !*r) {
+ WARN_ON(!r || !*r);
+ return 0;
+ }
+ return *r == data;
+}
+
+struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv)
+{
+ struct iio_dev **ptr, *iio_dev;
+
+ ptr = devres_alloc(devm_iio_device_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ /* use raw alloc_dr for kmalloc caller tracing */
+ iio_dev = iio_device_alloc(sizeof_priv);
+ if (iio_dev) {
+ *ptr = iio_dev;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return iio_dev;
+}
+EXPORT_SYMBOL_GPL(devm_iio_device_alloc);
+
+void devm_iio_device_free(struct device *dev, struct iio_dev *iio_dev)
+{
+ int rc;
+
+ rc = devres_release(dev, devm_iio_device_release,
+ devm_iio_device_match, iio_dev);
+ WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_iio_device_free);
+
/**
* iio_chrdev_open() - chrdev file open for buffer access and ioctls
**/
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index ea8a4146620..bf5e70a32d3 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -127,12 +127,17 @@ static struct iio_trigger *iio_trigger_find_by_name(const char *name,
void iio_trigger_poll(struct iio_trigger *trig, s64 time)
{
int i;
- if (!trig->use_count)
- for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++)
- if (trig->subirqs[i].enabled) {
- trig->use_count++;
+
+ if (!atomic_read(&trig->use_count)) {
+ atomic_set(&trig->use_count, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+
+ for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
+ if (trig->subirqs[i].enabled)
generic_handle_irq(trig->subirq_base + i);
- }
+ else
+ iio_trigger_notify_done(trig);
+ }
+ }
}
EXPORT_SYMBOL(iio_trigger_poll);
@@ -146,19 +151,24 @@ EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll);
void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time)
{
int i;
- if (!trig->use_count)
- for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++)
- if (trig->subirqs[i].enabled) {
- trig->use_count++;
+
+ if (!atomic_read(&trig->use_count)) {
+ atomic_set(&trig->use_count, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+
+ for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
+ if (trig->subirqs[i].enabled)
handle_nested_irq(trig->subirq_base + i);
- }
+ else
+ iio_trigger_notify_done(trig);
+ }
+ }
}
EXPORT_SYMBOL(iio_trigger_poll_chained);
void iio_trigger_notify_done(struct iio_trigger *trig)
{
- trig->use_count--;
- if (trig->use_count == 0 && trig->ops && trig->ops->try_reenable)
+ if (atomic_dec_and_test(&trig->use_count) && trig->ops &&
+ trig->ops->try_reenable)
if (trig->ops->try_reenable(trig))
/* Missed an interrupt so launch new poll now */
iio_trigger_poll(trig, 0);
@@ -414,9 +424,8 @@ static void iio_trig_subirqunmask(struct irq_data *d)
trig->subirqs[d->irq - trig->subirq_base].enabled = true;
}
-struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
+static struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs)
{
- va_list vargs;
struct iio_trigger *trig;
trig = kzalloc(sizeof *trig, GFP_KERNEL);
if (trig) {
@@ -434,9 +443,8 @@ struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
kfree(trig);
return NULL;
}
- va_start(vargs, fmt);
+
trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
- va_end(vargs);
if (trig->name == NULL) {
irq_free_descs(trig->subirq_base,
CONFIG_IIO_CONSUMERS_PER_TRIGGER);
@@ -457,6 +465,19 @@ struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
}
get_device(&trig->dev);
}
+
+ return trig;
+}
+
+struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
+{
+ struct iio_trigger *trig;
+ va_list vargs;
+
+ va_start(vargs, fmt);
+ trig = viio_trigger_alloc(fmt, vargs);
+ va_end(vargs);
+
return trig;
}
EXPORT_SYMBOL(iio_trigger_alloc);
@@ -468,6 +489,59 @@ void iio_trigger_free(struct iio_trigger *trig)
}
EXPORT_SYMBOL(iio_trigger_free);
+static void devm_iio_trigger_release(struct device *dev, void *res)
+{
+ iio_trigger_free(*(struct iio_trigger **)res);
+}
+
+static int devm_iio_trigger_match(struct device *dev, void *res, void *data)
+{
+ struct iio_trigger **r = res;
+
+ if (!r || !*r) {
+ WARN_ON(!r || !*r);
+ return 0;
+ }
+
+ return *r == data;
+}
+
+struct iio_trigger *devm_iio_trigger_alloc(struct device *dev,
+ const char *fmt, ...)
+{
+ struct iio_trigger **ptr, *trig;
+ va_list vargs;
+
+ ptr = devres_alloc(devm_iio_trigger_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ /* use raw alloc_dr for kmalloc caller tracing */
+ va_start(vargs, fmt);
+ trig = viio_trigger_alloc(fmt, vargs);
+ va_end(vargs);
+ if (trig) {
+ *ptr = trig;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return trig;
+}
+EXPORT_SYMBOL_GPL(devm_iio_trigger_alloc);
+
+void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig)
+{
+ int rc;
+
+ rc = devres_release(dev, devm_iio_trigger_release,
+ devm_iio_trigger_match, iio_trig);
+ WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_iio_trigger_free);
+
void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
{
indio_dev->groups[indio_dev->groupcounter++] =
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 5ef1a396e0c..bf9fa0d7aff 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -1,6 +1,8 @@
#
# Light sensors
#
+# When adding new entries keep the list in alphabetical order
+
menu "Light sensors"
config ADJD_S311
@@ -15,6 +17,27 @@ config ADJD_S311
This driver can also be built as a module. If so, the module
will be called adjd_s311.
+config APDS9300
+ tristate "APDS9300 ambient light sensor"
+ depends on I2C
+ help
+ Say Y here if you want to build a driver for the Avago APDS9300
+ ambient light sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called apds9300.
+
+config HID_SENSOR_ALS
+ depends on HID_SENSOR_HUB
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select HID_SENSOR_IIO_COMMON
+ select HID_SENSOR_IIO_TRIGGER
+ tristate "HID ALS"
+ help
+ Say yes here to build support for the HID SENSOR
+ Ambient light sensor.
+
config SENSORS_LM3533
tristate "LM3533 ambient light sensor"
depends on MFD_LM3533
@@ -52,15 +75,4 @@ config VCNL4000
To compile this driver as a module, choose M here: the
module will be called vcnl4000.
-config HID_SENSOR_ALS
- depends on HID_SENSOR_HUB
- select IIO_BUFFER
- select IIO_TRIGGERED_BUFFER
- select HID_SENSOR_IIO_COMMON
- select HID_SENSOR_IIO_TRIGGER
- tristate "HID ALS"
- help
- Say yes here to build support for the HID SENSOR
- Ambient light sensor.
-
endmenu
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 040d9c75f8e..354ee9ab237 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -2,8 +2,10 @@
# Makefile for IIO Light sensors
#
+# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ADJD_S311) += adjd_s311.o
+obj-$(CONFIG_APDS9300) += apds9300.o
+obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
-obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 5f4749e60b0..23cff798598 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -37,22 +37,14 @@
#define ADJD_S311_CAP_GREEN 0x07
#define ADJD_S311_CAP_BLUE 0x08
#define ADJD_S311_CAP_CLEAR 0x09
-#define ADJD_S311_INT_RED_LO 0x0a
-#define ADJD_S311_INT_RED_HI 0x0b
-#define ADJD_S311_INT_GREEN_LO 0x0c
-#define ADJD_S311_INT_GREEN_HI 0x0d
-#define ADJD_S311_INT_BLUE_LO 0x0e
-#define ADJD_S311_INT_BLUE_HI 0x0f
-#define ADJD_S311_INT_CLEAR_LO 0x10
-#define ADJD_S311_INT_CLEAR_HI 0x11
-#define ADJD_S311_DATA_RED_LO 0x40
-#define ADJD_S311_DATA_RED_HI 0x41
-#define ADJD_S311_DATA_GREEN_LO 0x42
-#define ADJD_S311_DATA_GREEN_HI 0x43
-#define ADJD_S311_DATA_BLUE_LO 0x44
-#define ADJD_S311_DATA_BLUE_HI 0x45
-#define ADJD_S311_DATA_CLEAR_LO 0x46
-#define ADJD_S311_DATA_CLEAR_HI 0x47
+#define ADJD_S311_INT_RED 0x0a
+#define ADJD_S311_INT_GREEN 0x0c
+#define ADJD_S311_INT_BLUE 0x0e
+#define ADJD_S311_INT_CLEAR 0x10
+#define ADJD_S311_DATA_RED 0x40
+#define ADJD_S311_DATA_GREEN 0x42
+#define ADJD_S311_DATA_BLUE 0x44
+#define ADJD_S311_DATA_CLEAR 0x46
#define ADJD_S311_OFFSET_RED 0x48
#define ADJD_S311_OFFSET_GREEN 0x49
#define ADJD_S311_OFFSET_BLUE 0x4a
@@ -73,8 +65,8 @@ enum adjd_s311_channel_idx {
IDX_RED, IDX_GREEN, IDX_BLUE, IDX_CLEAR
};
-#define ADJD_S311_DATA_REG(chan) (ADJD_S311_DATA_RED_LO + (chan) * 2)
-#define ADJD_S311_INT_REG(chan) (ADJD_S311_INT_RED_LO + (chan) * 2)
+#define ADJD_S311_DATA_REG(chan) (ADJD_S311_DATA_RED + (chan) * 2)
+#define ADJD_S311_INT_REG(chan) (ADJD_S311_INT_RED + (chan) * 2)
#define ADJD_S311_CAP_REG(chan) (ADJD_S311_CAP_RED + (chan))
static int adjd_s311_req_data(struct iio_dev *indio_dev)
@@ -232,7 +224,8 @@ static int adjd_s311_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = adjd_s311_read_data(indio_dev, chan->address, val);
+ ret = adjd_s311_read_data(indio_dev,
+ ADJD_S311_DATA_REG(chan->address), val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
@@ -293,11 +286,10 @@ static int adjd_s311_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int err;
- indio_dev = iio_device_alloc(sizeof(*data));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto exit;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
@@ -312,7 +304,7 @@ static int adjd_s311_probe(struct i2c_client *client,
err = iio_triggered_buffer_setup(indio_dev, NULL,
adjd_s311_trigger_handler, NULL);
if (err < 0)
- goto exit_free_device;
+ return err;
err = iio_device_register(indio_dev);
if (err)
@@ -324,9 +316,6 @@ static int adjd_s311_probe(struct i2c_client *client,
exit_unreg_buffer:
iio_triggered_buffer_cleanup(indio_dev);
-exit_free_device:
- iio_device_free(indio_dev);
-exit:
return err;
}
@@ -338,7 +327,6 @@ static int adjd_s311_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
kfree(data->buffer);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c
new file mode 100644
index 00000000000..66a58bda6dc
--- /dev/null
+++ b/drivers/iio/light/apds9300.c
@@ -0,0 +1,512 @@
+/*
+ * apds9300.c - IIO driver for Avago APDS9300 ambient light sensor
+ *
+ * Copyright 2013 Oleksandr Kravchenko <o.v.kravchenko@globallogic.com>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+
+#define APDS9300_DRV_NAME "apds9300"
+#define APDS9300_IRQ_NAME "apds9300_event"
+
+/* Command register bits */
+#define APDS9300_CMD BIT(7) /* Select command register. Must write as 1 */
+#define APDS9300_WORD BIT(5) /* I2C write/read: if 1 word, if 0 byte */
+#define APDS9300_CLEAR BIT(6) /* Interrupt clear. Clears pending interrupt */
+
+/* Register set */
+#define APDS9300_CONTROL 0x00 /* Control of basic functions */
+#define APDS9300_THRESHLOWLOW 0x02 /* Low byte of low interrupt threshold */
+#define APDS9300_THRESHHIGHLOW 0x04 /* Low byte of high interrupt threshold */
+#define APDS9300_INTERRUPT 0x06 /* Interrupt control */
+#define APDS9300_DATA0LOW 0x0c /* Low byte of ADC channel 0 */
+#define APDS9300_DATA1LOW 0x0e /* Low byte of ADC channel 1 */
+
+/* Power on/off value for APDS9300_CONTROL register */
+#define APDS9300_POWER_ON 0x03
+#define APDS9300_POWER_OFF 0x00
+
+/* Interrupts */
+#define APDS9300_INTR_ENABLE 0x10
+/* Interrupt Persist Function: Any value outside of threshold range */
+#define APDS9300_THRESH_INTR 0x01
+
+#define APDS9300_THRESH_MAX 0xffff /* Max threshold value */
+
+struct apds9300_data {
+ struct i2c_client *client;
+ struct mutex mutex;
+ int power_state;
+ int thresh_low;
+ int thresh_hi;
+ int intr_en;
+};
+
+/* Lux calculation */
+
+/* Calculated values 1000 * (CH1/CH0)^1.4 for CH1/CH0 from 0 to 0.52 */
+static const u16 apds9300_lux_ratio[] = {
+ 0, 2, 4, 7, 11, 15, 19, 24, 29, 34, 40, 45, 51, 57, 64, 70, 77, 84, 91,
+ 98, 105, 112, 120, 128, 136, 144, 152, 160, 168, 177, 185, 194, 203,
+ 212, 221, 230, 239, 249, 258, 268, 277, 287, 297, 307, 317, 327, 337,
+ 347, 358, 368, 379, 390, 400,
+};
+
+static unsigned long apds9300_calculate_lux(u16 ch0, u16 ch1)
+{
+ unsigned long lux, tmp;
+
+ /* avoid division by zero */
+ if (ch0 == 0)
+ return 0;
+
+ tmp = DIV_ROUND_UP(ch1 * 100, ch0);
+ if (tmp <= 52) {
+ lux = 3150 * ch0 - (unsigned long)DIV_ROUND_UP_ULL(ch0
+ * apds9300_lux_ratio[tmp] * 5930ull, 1000);
+ } else if (tmp <= 65) {
+ lux = 2290 * ch0 - 2910 * ch1;
+ } else if (tmp <= 80) {
+ lux = 1570 * ch0 - 1800 * ch1;
+ } else if (tmp <= 130) {
+ lux = 338 * ch0 - 260 * ch1;
+ } else {
+ lux = 0;
+ }
+
+ return lux / 100000;
+}
+
+static int apds9300_get_adc_val(struct apds9300_data *data, int adc_number)
+{
+ int ret;
+ u8 flags = APDS9300_CMD | APDS9300_WORD;
+
+ if (!data->power_state)
+ return -EBUSY;
+
+ /* Select ADC0 or ADC1 data register */
+ flags |= adc_number ? APDS9300_DATA1LOW : APDS9300_DATA0LOW;
+
+ ret = i2c_smbus_read_word_data(data->client, flags);
+ if (ret < 0)
+ dev_err(&data->client->dev,
+ "failed to read ADC%d value\n", adc_number);
+
+ return ret;
+}
+
+static int apds9300_set_thresh_low(struct apds9300_data *data, int value)
+{
+ int ret;
+
+ if (!data->power_state)
+ return -EBUSY;
+
+ if (value > APDS9300_THRESH_MAX)
+ return -EINVAL;
+
+ ret = i2c_smbus_write_word_data(data->client, APDS9300_THRESHLOWLOW
+ | APDS9300_CMD | APDS9300_WORD, value);
+ if (ret) {
+ dev_err(&data->client->dev, "failed to set thresh_low\n");
+ return ret;
+ }
+ data->thresh_low = value;
+
+ return 0;
+}
+
+static int apds9300_set_thresh_hi(struct apds9300_data *data, int value)
+{
+ int ret;
+
+ if (!data->power_state)
+ return -EBUSY;
+
+ if (value > APDS9300_THRESH_MAX)
+ return -EINVAL;
+
+ ret = i2c_smbus_write_word_data(data->client, APDS9300_THRESHHIGHLOW
+ | APDS9300_CMD | APDS9300_WORD, value);
+ if (ret) {
+ dev_err(&data->client->dev, "failed to set thresh_hi\n");
+ return ret;
+ }
+ data->thresh_hi = value;
+
+ return 0;
+}
+
+static int apds9300_set_intr_state(struct apds9300_data *data, int state)
+{
+ int ret;
+ u8 cmd;
+
+ if (!data->power_state)
+ return -EBUSY;
+
+ cmd = state ? APDS9300_INTR_ENABLE | APDS9300_THRESH_INTR : 0x00;
+ ret = i2c_smbus_write_byte_data(data->client,
+ APDS9300_INTERRUPT | APDS9300_CMD, cmd);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "failed to set interrupt state %d\n", state);
+ return ret;
+ }
+ data->intr_en = state;
+
+ return 0;
+}
+
+static int apds9300_set_power_state(struct apds9300_data *data, int state)
+{
+ int ret;
+ u8 cmd;
+
+ cmd = state ? APDS9300_POWER_ON : APDS9300_POWER_OFF;
+ ret = i2c_smbus_write_byte_data(data->client,
+ APDS9300_CONTROL | APDS9300_CMD, cmd);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "failed to set power state %d\n", state);
+ return ret;
+ }
+ data->power_state = state;
+
+ return 0;
+}
+
+static void apds9300_clear_intr(struct apds9300_data *data)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte(data->client, APDS9300_CLEAR | APDS9300_CMD);
+ if (ret < 0)
+ dev_err(&data->client->dev, "failed to clear interrupt\n");
+}
+
+static int apds9300_chip_init(struct apds9300_data *data)
+{
+ int ret;
+
+ /* Need to set power off to ensure that the chip is off */
+ ret = apds9300_set_power_state(data, 0);
+ if (ret < 0)
+ goto err;
+ /*
+ * Probe the chip. To do so we try to power up the device and then to
+ * read back the 0x03 code
+ */
+ ret = apds9300_set_power_state(data, 1);
+ if (ret < 0)
+ goto err;
+ ret = i2c_smbus_read_byte_data(data->client,
+ APDS9300_CONTROL | APDS9300_CMD);
+ if (ret != APDS9300_POWER_ON) {
+ ret = -ENODEV;
+ goto err;
+ }
+ /*
+ * Disable interrupt to ensure thai it is doesn't enable
+ * i.e. after device soft reset
+ */
+ ret = apds9300_set_intr_state(data, 0);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dev_err(&data->client->dev, "failed to init the chip\n");
+ return ret;
+}
+
+static int apds9300_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2,
+ long mask)
+{
+ int ch0, ch1, ret = -EINVAL;
+ struct apds9300_data *data = iio_priv(indio_dev);
+
+ mutex_lock(&data->mutex);
+ switch (chan->type) {
+ case IIO_LIGHT:
+ ch0 = apds9300_get_adc_val(data, 0);
+ if (ch0 < 0) {
+ ret = ch0;
+ break;
+ }
+ ch1 = apds9300_get_adc_val(data, 1);
+ if (ch1 < 0) {
+ ret = ch1;
+ break;
+ }
+ *val = apds9300_calculate_lux(ch0, ch1);
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_INTENSITY:
+ ret = apds9300_get_adc_val(data, chan->channel);
+ if (ret < 0)
+ break;
+ *val = ret;
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int apds9300_read_thresh(struct iio_dev *indio_dev, u64 event_code,
+ int *val)
+{
+ struct apds9300_data *data = iio_priv(indio_dev);
+
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_RISING:
+ *val = data->thresh_hi;
+ break;
+ case IIO_EV_DIR_FALLING:
+ *val = data->thresh_low;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int apds9300_write_thresh(struct iio_dev *indio_dev, u64 event_code,
+ int val)
+{
+ struct apds9300_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_RISING)
+ ret = apds9300_set_thresh_hi(data, val);
+ else
+ ret = apds9300_set_thresh_low(data, val);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int apds9300_read_interrupt_config(struct iio_dev *indio_dev,
+ u64 event_code)
+{
+ struct apds9300_data *data = iio_priv(indio_dev);
+
+ return data->intr_en;
+}
+
+static int apds9300_write_interrupt_config(struct iio_dev *indio_dev,
+ u64 event_code, int state)
+{
+ struct apds9300_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = apds9300_set_intr_state(data, state);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct iio_info apds9300_info_no_irq = {
+ .driver_module = THIS_MODULE,
+ .read_raw = apds9300_read_raw,
+};
+
+static const struct iio_info apds9300_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = apds9300_read_raw,
+ .read_event_value = apds9300_read_thresh,
+ .write_event_value = apds9300_write_thresh,
+ .read_event_config = apds9300_read_interrupt_config,
+ .write_event_config = apds9300_write_interrupt_config,
+};
+
+static const struct iio_chan_spec apds9300_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .channel = 0,
+ .indexed = true,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ }, {
+ .type = IIO_INTENSITY,
+ .channel = 0,
+ .channel2 = IIO_MOD_LIGHT_BOTH,
+ .indexed = true,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING) |
+ IIO_EV_BIT(IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING)),
+ }, {
+ .type = IIO_INTENSITY,
+ .channel = 1,
+ .channel2 = IIO_MOD_LIGHT_IR,
+ .indexed = true,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ },
+};
+
+static irqreturn_t apds9300_interrupt_handler(int irq, void *private)
+{
+ struct iio_dev *dev_info = private;
+ struct apds9300_data *data = iio_priv(dev_info);
+
+ iio_push_event(dev_info,
+ IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ iio_get_time_ns());
+
+ apds9300_clear_intr(data);
+
+ return IRQ_HANDLED;
+}
+
+static int apds9300_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct apds9300_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ ret = apds9300_chip_init(data);
+ if (ret < 0)
+ goto err;
+
+ mutex_init(&data->mutex);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->channels = apds9300_channels;
+ indio_dev->num_channels = ARRAY_SIZE(apds9300_channels);
+ indio_dev->name = APDS9300_DRV_NAME;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ if (client->irq)
+ indio_dev->info = &apds9300_info;
+ else
+ indio_dev->info = &apds9300_info_no_irq;
+
+ if (client->irq) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, apds9300_interrupt_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ APDS9300_IRQ_NAME, indio_dev);
+ if (ret) {
+ dev_err(&client->dev, "irq request error %d\n", -ret);
+ goto err;
+ }
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ /* Ensure that power off in case of error */
+ apds9300_set_power_state(data, 0);
+ return ret;
+}
+
+static int apds9300_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct apds9300_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ /* Ensure that power off and interrupts are disabled */
+ apds9300_set_intr_state(data, 0);
+ apds9300_set_power_state(data, 0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int apds9300_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct apds9300_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = apds9300_set_power_state(data, 0);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int apds9300_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct apds9300_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = apds9300_set_power_state(data, 1);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend, apds9300_resume);
+#define APDS9300_PM_OPS (&apds9300_pm_ops)
+#else
+#define APDS9300_PM_OPS NULL
+#endif
+
+static struct i2c_device_id apds9300_id[] = {
+ { APDS9300_DRV_NAME, 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, apds9300_id);
+
+static struct i2c_driver apds9300_driver = {
+ .driver = {
+ .name = APDS9300_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = APDS9300_PM_OPS,
+ },
+ .probe = apds9300_probe,
+ .remove = apds9300_remove,
+ .id_table = apds9300_id,
+};
+
+module_i2c_driver(apds9300_driver);
+
+MODULE_AUTHOR("Kravchenko Oleksandr <o.v.kravchenko@globallogic.com>");
+MODULE_AUTHOR("GlobalLogic inc.");
+MODULE_DESCRIPTION("APDS9300 ambient light photo sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index cdc2cad0f01..e59d00c3139 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -30,10 +30,6 @@
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
-/*Format: HID-SENSOR-usage_id_in_hex*/
-/*Usage ID from spec for Ambiant-Light: 0x200041*/
-#define DRIVER_NAME "HID-SENSOR-200041"
-
#define CHANNEL_SCAN_INDEX_ILLUM 0
struct als_state {
@@ -158,18 +154,10 @@ static int als_write_raw(struct iio_dev *indio_dev,
return ret;
}
-static int als_write_raw_get_fmt(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- long mask)
-{
- return IIO_VAL_INT_PLUS_MICRO;
-}
-
static const struct iio_info als_info = {
.driver_module = THIS_MODULE,
.read_raw = &als_read_raw,
.write_raw = &als_write_raw,
- .write_raw_get_fmt = &als_write_raw_get_fmt,
};
/* Function to push data to buffer */
@@ -253,11 +241,9 @@ static int hid_als_probe(struct platform_device *pdev)
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
- indio_dev = iio_device_alloc(sizeof(struct als_state));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct als_state));
+ if (!indio_dev)
+ return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
als_state = iio_priv(indio_dev);
@@ -268,14 +254,13 @@ static int hid_als_probe(struct platform_device *pdev)
&als_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
- goto error_free_dev;
+ return ret;
}
channels = kmemdup(als_channels, sizeof(als_channels), GFP_KERNEL);
if (!channels) {
- ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
- goto error_free_dev;
+ return -ENOMEM;
}
ret = als_parse_report(pdev, hsdev, channels,
@@ -333,9 +318,6 @@ error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
error_free_dev_mem:
kfree(indio_dev->channels);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -350,14 +332,23 @@ static int hid_als_remove(struct platform_device *pdev)
hid_sensor_remove_trigger(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
kfree(indio_dev->channels);
- iio_device_free(indio_dev);
return 0;
}
+static struct platform_device_id hid_als_ids[] = {
+ {
+ /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+ .name = "HID-SENSOR-200041",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_als_ids);
+
static struct platform_driver hid_als_platform_driver = {
+ .id_table = hid_als_ids,
.driver = {
- .name = DRIVER_NAME,
+ .name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
.probe = hid_als_probe,
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index 5fa31a4ef82..c1aadc6b865 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -847,7 +847,7 @@ static int lm3533_als_probe(struct platform_device *pdev)
return -EINVAL;
}
- indio_dev = iio_device_alloc(sizeof(*als));
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*als));
if (!indio_dev)
return -ENOMEM;
@@ -870,7 +870,7 @@ static int lm3533_als_probe(struct platform_device *pdev)
if (als->irq) {
ret = lm3533_als_setup_irq(als, indio_dev);
if (ret)
- goto err_free_dev;
+ return ret;
}
ret = lm3533_als_setup(als, pdata);
@@ -894,8 +894,6 @@ err_disable:
err_free_irq:
if (als->irq)
free_irq(als->irq, indio_dev);
-err_free_dev:
- iio_device_free(indio_dev);
return ret;
}
@@ -910,7 +908,6 @@ static int lm3533_als_remove(struct platform_device *pdev)
lm3533_als_disable(als);
if (als->irq)
free_irq(als->irq, indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index 1f529f36f13..ebb962c5c32 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -702,7 +702,7 @@ static int tsl2563_probe(struct i2c_client *client,
int err = 0;
u8 id = 0;
- indio_dev = iio_device_alloc(sizeof(*chip));
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
if (!indio_dev)
return -ENOMEM;
@@ -714,13 +714,13 @@ static int tsl2563_probe(struct i2c_client *client,
err = tsl2563_detect(chip);
if (err) {
dev_err(&client->dev, "detect error %d\n", -err);
- goto fail1;
+ return err;
}
err = tsl2563_read_id(chip, &id);
if (err) {
dev_err(&client->dev, "read id error %d\n", -err);
- goto fail1;
+ return err;
}
mutex_init(&chip->lock);
@@ -751,7 +751,7 @@ static int tsl2563_probe(struct i2c_client *client,
indio_dev->info = &tsl2563_info_no_irq;
if (client->irq) {
- err = request_threaded_irq(client->irq,
+ err = devm_request_threaded_irq(&client->dev, client->irq,
NULL,
&tsl2563_event_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@@ -759,14 +759,14 @@ static int tsl2563_probe(struct i2c_client *client,
indio_dev);
if (err) {
dev_err(&client->dev, "irq request error %d\n", -err);
- goto fail1;
+ return err;
}
}
err = tsl2563_configure(chip);
if (err) {
dev_err(&client->dev, "configure error %d\n", -err);
- goto fail2;
+ return err;
}
INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work);
@@ -777,19 +777,14 @@ static int tsl2563_probe(struct i2c_client *client,
err = iio_device_register(indio_dev);
if (err) {
dev_err(&client->dev, "iio registration error %d\n", -err);
- goto fail3;
+ goto fail;
}
return 0;
-fail3:
+fail:
cancel_delayed_work(&chip->poweroff_work);
flush_scheduled_work();
-fail2:
- if (client->irq)
- free_irq(client->irq, indio_dev);
-fail1:
- iio_device_free(indio_dev);
return err;
}
@@ -807,10 +802,6 @@ static int tsl2563_remove(struct i2c_client *client)
chip->intr);
flush_scheduled_work();
tsl2563_set_power(chip, 0);
- if (client->irq)
- free_irq(client->irq, indio_dev);
-
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index 1014943d949..2bb304215b1 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -157,7 +157,7 @@ static int vcnl4000_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int ret;
- indio_dev = iio_device_alloc(sizeof(*data));
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
@@ -167,7 +167,7 @@ static int vcnl4000_probe(struct i2c_client *client,
ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
if (ret < 0)
- goto error_free_dev;
+ return ret;
dev_info(&client->dev, "VCNL4000 Ambient light/proximity sensor, Prod %02x, Rev: %02x\n",
ret >> 4, ret & 0xf);
@@ -181,22 +181,14 @@ static int vcnl4000_probe(struct i2c_client *client,
ret = iio_device_register(indio_dev);
if (ret < 0)
- goto error_free_dev;
+ return ret;
return 0;
-
-error_free_dev:
- iio_device_free(indio_dev);
- return ret;
}
static int vcnl4000_remove(struct i2c_client *client)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
- iio_device_unregister(indio_dev);
- iio_device_free(indio_dev);
-
+ iio_device_unregister(i2c_get_clientdata(client));
return 0;
}
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index c332b0ae4a3..4fa923f37b9 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -1,6 +1,8 @@
#
# Magnetometer sensors
#
+# When adding new entries keep the list in alphabetical order
+
menu "Magnetometer sensors"
config AK8975
@@ -36,8 +38,8 @@ config IIO_ST_MAGN_3AXIS
Say yes here to build support for STMicroelectronics magnetometers:
LSM303DLHC, LSM303DLM, LIS3MDL.
- This driver can also be built as a module. If so, will be created
- these modules:
+ This driver can also be built as a module. If so, these modules
+ will be created:
- st_magn (core functions for the driver [it is mandatory]);
- st_magn_i2c (necessary for the I2C devices [optional*]);
- st_magn_spi (necessary for the SPI devices [optional*]);
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index 7f328e37fba..f91b1b68d39 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -2,6 +2,7 @@
# Makefile for industrial I/O Magnetometer sensor drivers
#
+# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AK8975) += ak8975.o
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index 99f4e494513..a98460b15e4 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -30,10 +30,6 @@
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
-/*Format: HID-SENSOR-usage_id_in_hex*/
-/*Usage ID from spec for Magnetometer-3D: 0x200083*/
-#define DRIVER_NAME "HID-SENSOR-200083"
-
enum magn_3d_channel {
CHANNEL_SCAN_INDEX_X,
CHANNEL_SCAN_INDEX_Y,
@@ -180,18 +176,10 @@ static int magn_3d_write_raw(struct iio_dev *indio_dev,
return ret;
}
-static int magn_3d_write_raw_get_fmt(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- long mask)
-{
- return IIO_VAL_INT_PLUS_MICRO;
-}
-
static const struct iio_info magn_3d_info = {
.driver_module = THIS_MODULE,
.read_raw = &magn_3d_read_raw,
.write_raw = &magn_3d_write_raw,
- .write_raw_get_fmt = &magn_3d_write_raw_get_fmt,
};
/* Function to push data to buffer */
@@ -287,11 +275,11 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
- indio_dev = iio_device_alloc(sizeof(struct magn_3d_state));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&pdev->dev,
+ sizeof(struct magn_3d_state));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
platform_set_drvdata(pdev, indio_dev);
magn_state = iio_priv(indio_dev);
@@ -303,15 +291,14 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
&magn_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
- goto error_free_dev;
+ return ret;
}
channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels),
GFP_KERNEL);
if (!channels) {
- ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
- goto error_free_dev;
+ return -ENOMEM;
}
ret = magn_3d_parse_report(pdev, hsdev, channels,
@@ -368,9 +355,6 @@ error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev);
error_free_dev_mem:
kfree(indio_dev->channels);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -385,14 +369,23 @@ static int hid_magn_3d_remove(struct platform_device *pdev)
hid_sensor_remove_trigger(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
kfree(indio_dev->channels);
- iio_device_free(indio_dev);
return 0;
}
+static struct platform_device_id hid_magn_3d_ids[] = {
+ {
+ /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+ .name = "HID-SENSOR-200083",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_magn_3d_ids);
+
static struct platform_driver hid_magn_3d_platform_driver = {
+ .id_table = hid_magn_3d_ids,
.driver = {
- .name = DRIVER_NAME,
+ .name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
.probe = hid_magn_3d_probe,
diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h
index 7e81d00ef0c..694e33e0fb7 100644
--- a/drivers/iio/magnetometer/st_magn.h
+++ b/drivers/iio/magnetometer/st_magn.h
@@ -18,7 +18,8 @@
#define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn"
#define LIS3MDL_MAGN_DEV_NAME "lis3mdl"
-int st_magn_common_probe(struct iio_dev *indio_dev);
+int st_magn_common_probe(struct iio_dev *indio_dev,
+ struct st_sensors_platform_data *pdata);
void st_magn_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index ebfe8f11a0c..e8d2849cc81 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -345,7 +345,8 @@ static const struct iio_info magn_info = {
.write_raw = &st_magn_write_raw,
};
-int st_magn_common_probe(struct iio_dev *indio_dev)
+int st_magn_common_probe(struct iio_dev *indio_dev,
+ struct st_sensors_platform_data *pdata)
{
int err;
struct st_sensor_data *mdata = iio_priv(indio_dev);
@@ -367,7 +368,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
&mdata->sensor->fs.fs_avl[0];
mdata->odr = mdata->sensor->odr.odr_avl[0].hz;
- err = st_sensors_init_sensor(indio_dev);
+ err = st_sensors_init_sensor(indio_dev, pdata);
if (err < 0)
goto st_magn_common_probe_error;
@@ -406,7 +407,6 @@ void st_magn_common_remove(struct iio_dev *indio_dev)
st_sensors_deallocate_trigger(indio_dev);
st_magn_deallocate_ring(indio_dev);
}
- iio_device_free(indio_dev);
}
EXPORT_SYMBOL(st_magn_common_remove);
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index e6adc4a8642..892e0feeb5c 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -25,27 +25,20 @@ static int st_magn_i2c_probe(struct i2c_client *client,
struct st_sensor_data *mdata;
int err;
- indio_dev = iio_device_alloc(sizeof(*mdata));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto iio_device_alloc_error;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mdata));
+ if (!indio_dev)
+ return -ENOMEM;
mdata = iio_priv(indio_dev);
mdata->dev = &client->dev;
st_sensors_i2c_configure(indio_dev, client, mdata);
- err = st_magn_common_probe(indio_dev);
+ err = st_magn_common_probe(indio_dev, NULL);
if (err < 0)
- goto st_magn_common_probe_error;
+ return err;
return 0;
-
-st_magn_common_probe_error:
- iio_device_free(indio_dev);
-iio_device_alloc_error:
- return err;
}
static int st_magn_i2c_remove(struct i2c_client *client)
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index 51adb797cb7..a6143ea51df 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -24,27 +24,20 @@ static int st_magn_spi_probe(struct spi_device *spi)
struct st_sensor_data *mdata;
int err;
- indio_dev = iio_device_alloc(sizeof(*mdata));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto iio_device_alloc_error;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*mdata));
+ if (!indio_dev)
+ return -ENOMEM;
mdata = iio_priv(indio_dev);
mdata->dev = &spi->dev;
st_sensors_spi_configure(indio_dev, spi, mdata);
- err = st_magn_common_probe(indio_dev);
+ err = st_magn_common_probe(indio_dev, NULL);
if (err < 0)
- goto st_magn_common_probe_error;
+ return err;
return 0;
-
-st_magn_common_probe_error:
- iio_device_free(indio_dev);
-iio_device_alloc_error:
- return err;
}
static int st_magn_spi_remove(struct spi_device *spi)
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 9427f01e149..26fdc0bdb99 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -1,21 +1,23 @@
#
# Pressure drivers
#
-menu "Pressure Sensors"
+# When adding new entries keep the list in alphabetical order
+
+menu "Pressure sensors"
config IIO_ST_PRESS
- tristate "STMicroelectronics pressures Driver"
+ tristate "STMicroelectronics pressure sensor Driver"
depends on (I2C || SPI_MASTER) && SYSFS
select IIO_ST_SENSORS_CORE
select IIO_ST_PRESS_I2C if (I2C)
select IIO_ST_PRESS_SPI if (SPI_MASTER)
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
- Say yes here to build support for STMicroelectronics pressures:
- LPS331AP.
+ Say yes here to build support for STMicroelectronics pressure
+ sensors: LPS331AP.
- This driver can also be built as a module. If so, will be created
- these modules:
+ This driver can also be built as a module. If so, these modules
+ will be created:
- st_pressure (core functions for the driver [it is mandatory]);
- st_pressure_i2c (necessary for the I2C devices [optional*]);
- st_pressure_spi (necessary for the SPI devices [optional*]);
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index d4bb33e5c84..be71464c275 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -2,6 +2,7 @@
# Makefile for industrial I/O pressure drivers
#
+# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
st_pressure-y := st_pressure_core.o
st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h
index 414e45ac9b9..b0b630688da 100644
--- a/drivers/iio/pressure/st_pressure.h
+++ b/drivers/iio/pressure/st_pressure.h
@@ -16,7 +16,16 @@
#define LPS331AP_PRESS_DEV_NAME "lps331ap"
-int st_press_common_probe(struct iio_dev *indio_dev);
+/**
+ * struct st_sensors_platform_data - default press platform data
+ * @drdy_int_pin: default press DRDY is available on INT1 pin.
+ */
+static const struct st_sensors_platform_data default_press_pdata = {
+ .drdy_int_pin = 1,
+};
+
+int st_press_common_probe(struct iio_dev *indio_dev,
+ struct st_sensors_platform_data *pdata);
void st_press_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index 3ffbc56917b..ceebd3c2789 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -31,6 +31,9 @@
#define ST_PRESS_LSB_PER_MBAR 4096UL
#define ST_PRESS_KPASCAL_NANO_SCALE (100000000UL / \
ST_PRESS_LSB_PER_MBAR)
+#define ST_PRESS_LSB_PER_CELSIUS 480UL
+#define ST_PRESS_CELSIUS_NANO_SCALE (1000000000UL / \
+ ST_PRESS_LSB_PER_CELSIUS)
#define ST_PRESS_NUMBER_DATA_CHANNELS 1
/* DEFAULT VALUE FOR SENSORS */
@@ -53,12 +56,13 @@
#define ST_PRESS_1_FS_ADDR 0x23
#define ST_PRESS_1_FS_MASK 0x30
#define ST_PRESS_1_FS_AVL_1260_VAL 0x00
-#define ST_PRESS_1_FS_AVL_TEMP_GAIN 2083000
#define ST_PRESS_1_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE
+#define ST_PRESS_1_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE
#define ST_PRESS_1_BDU_ADDR 0x20
#define ST_PRESS_1_BDU_MASK 0x04
#define ST_PRESS_1_DRDY_IRQ_ADDR 0x22
-#define ST_PRESS_1_DRDY_IRQ_MASK 0x04
+#define ST_PRESS_1_DRDY_IRQ_INT1_MASK 0x04
+#define ST_PRESS_1_DRDY_IRQ_INT2_MASK 0x20
#define ST_PRESS_1_MULTIREAD_BIT true
#define ST_PRESS_1_TEMP_OFFSET 42500
@@ -116,7 +120,8 @@ static const struct st_sensors st_press_sensors[] = {
},
.drdy_irq = {
.addr = ST_PRESS_1_DRDY_IRQ_ADDR,
- .mask = ST_PRESS_1_DRDY_IRQ_MASK,
+ .mask_int1 = ST_PRESS_1_DRDY_IRQ_INT1_MASK,
+ .mask_int2 = ST_PRESS_1_DRDY_IRQ_INT2_MASK,
},
.multi_read_bit = ST_PRESS_1_MULTIREAD_BIT,
.bootime = 2,
@@ -202,7 +207,8 @@ static const struct iio_trigger_ops st_press_trigger_ops = {
#define ST_PRESS_TRIGGER_OPS NULL
#endif
-int st_press_common_probe(struct iio_dev *indio_dev)
+int st_press_common_probe(struct iio_dev *indio_dev,
+ struct st_sensors_platform_data *plat_data)
{
int err;
struct st_sensor_data *pdata = iio_priv(indio_dev);
@@ -224,7 +230,11 @@ int st_press_common_probe(struct iio_dev *indio_dev)
&pdata->sensor->fs.fs_avl[0];
pdata->odr = pdata->sensor->odr.odr_avl[0].hz;
- err = st_sensors_init_sensor(indio_dev);
+ if (!plat_data)
+ plat_data =
+ (struct st_sensors_platform_data *)&default_press_pdata;
+
+ err = st_sensors_init_sensor(indio_dev, plat_data);
if (err < 0)
goto st_press_common_probe_error;
@@ -265,7 +275,6 @@ void st_press_common_remove(struct iio_dev *indio_dev)
st_sensors_deallocate_trigger(indio_dev);
st_press_deallocate_ring(indio_dev);
}
- iio_device_free(indio_dev);
}
EXPORT_SYMBOL(st_press_common_remove);
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 7cebcc73bfb..08aac5e6251 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -25,27 +25,20 @@ static int st_press_i2c_probe(struct i2c_client *client,
struct st_sensor_data *pdata;
int err;
- indio_dev = iio_device_alloc(sizeof(*pdata));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto iio_device_alloc_error;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*pdata));
+ if (!indio_dev)
+ return -ENOMEM;
pdata = iio_priv(indio_dev);
pdata->dev = &client->dev;
st_sensors_i2c_configure(indio_dev, client, pdata);
- err = st_press_common_probe(indio_dev);
+ err = st_press_common_probe(indio_dev, client->dev.platform_data);
if (err < 0)
- goto st_press_common_probe_error;
+ return err;
return 0;
-
-st_press_common_probe_error:
- iio_device_free(indio_dev);
-iio_device_alloc_error:
- return err;
}
static int st_press_i2c_remove(struct i2c_client *client)
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index 17a14907940..399a29b6017 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -24,27 +24,20 @@ static int st_press_spi_probe(struct spi_device *spi)
struct st_sensor_data *pdata;
int err;
- indio_dev = iio_device_alloc(sizeof(*pdata));
- if (indio_dev == NULL) {
- err = -ENOMEM;
- goto iio_device_alloc_error;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*pdata));
+ if (indio_dev == NULL)
+ return -ENOMEM;
pdata = iio_priv(indio_dev);
pdata->dev = &spi->dev;
st_sensors_spi_configure(indio_dev, spi, pdata);
- err = st_press_common_probe(indio_dev);
+ err = st_press_common_probe(indio_dev, spi->dev.platform_data);
if (err < 0)
- goto st_press_common_probe_error;
+ return err;
return 0;
-
-st_press_common_probe_error:
- iio_device_free(indio_dev);
-iio_device_alloc_error:
- return err;
}
static int st_press_spi_remove(struct spi_device *spi)
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
new file mode 100644
index 00000000000..372f8fb3085
--- /dev/null
+++ b/drivers/iio/temperature/Kconfig
@@ -0,0 +1,16 @@
+#
+# Temperature sensor drivers
+#
+menu "Temperature sensors"
+
+config TMP006
+ tristate "TMP006 infrared thermopile sensor"
+ depends on I2C
+ help
+ If you say yes here you get support for the Texas Instruments
+ TMP006 infrared thermopile sensor.
+
+ This driver can also be built as a module. If so, the module will
+ be called tmp006.
+
+endmenu
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
new file mode 100644
index 00000000000..24d7b602db3
--- /dev/null
+++ b/drivers/iio/temperature/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for industrial I/O temperature drivers
+#
+
+obj-$(CONFIG_TMP006) += tmp006.o
diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c
new file mode 100644
index 00000000000..64ccde3f1f7
--- /dev/null
+++ b/drivers/iio/temperature/tmp006.c
@@ -0,0 +1,291 @@
+/*
+ * tmp006.c - Support for TI TMP006 IR thermopile sensor
+ *
+ * Copyright (c) 2013 Peter Meerwald <pmeerw@pmeerw.net>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Driver for the Texas Instruments I2C 16-bit IR thermopile sensor
+ *
+ * (7-bit I2C slave address 0x40, changeable via ADR pins)
+ *
+ * TODO: data ready irq
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define TMP006_VOBJECT 0x00
+#define TMP006_TAMBIENT 0x01
+#define TMP006_CONFIG 0x02
+#define TMP006_MANUFACTURER_ID 0xfe
+#define TMP006_DEVICE_ID 0xff
+
+#define TMP006_TAMBIENT_SHIFT 2
+
+#define TMP006_CONFIG_RESET BIT(15)
+#define TMP006_CONFIG_DRDY_EN BIT(8)
+#define TMP006_CONFIG_DRDY BIT(7)
+
+#define TMP006_CONFIG_MOD_MASK 0x7000
+
+#define TMP006_CONFIG_CR_MASK 0x0e00
+#define TMP006_CONFIG_CR_SHIFT 9
+
+#define MANUFACTURER_MAGIC 0x5449
+#define DEVICE_MAGIC 0x0067
+
+struct tmp006_data {
+ struct i2c_client *client;
+ u16 config;
+};
+
+static int tmp006_read_measurement(struct tmp006_data *data, u8 reg)
+{
+ s32 ret;
+ int tries = 50;
+
+ while (tries-- > 0) {
+ ret = i2c_smbus_read_word_swapped(data->client,
+ TMP006_CONFIG);
+ if (ret < 0)
+ return ret;
+ if (ret & TMP006_CONFIG_DRDY)
+ break;
+ msleep(100);
+ }
+
+ if (tries < 0)
+ return -EIO;
+
+ return i2c_smbus_read_word_swapped(data->client, reg);
+}
+
+static int tmp006_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ struct tmp006_data *data = iio_priv(indio_dev);
+ s32 ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (channel->type == IIO_VOLTAGE) {
+ /* LSB is 156.25 nV */
+ ret = tmp006_read_measurement(data, TMP006_VOBJECT);
+ if (ret < 0)
+ return ret;
+ *val = sign_extend32(ret, 15);
+ } else if (channel->type == IIO_TEMP) {
+ /* LSB is 0.03125 degrees Celsius */
+ ret = tmp006_read_measurement(data, TMP006_TAMBIENT);
+ if (ret < 0)
+ return ret;
+ *val = sign_extend32(ret, 15) >> TMP006_TAMBIENT_SHIFT;
+ } else {
+ break;
+ }
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ if (channel->type == IIO_VOLTAGE) {
+ *val = 0;
+ *val2 = 156250;
+ } else if (channel->type == IIO_TEMP) {
+ *val = 31;
+ *val2 = 250000;
+ } else {
+ break;
+ }
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const char * const tmp006_freqs[] = { "4", "2", "1", "0.5", "0.25" };
+
+static ssize_t tmp006_show_freq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tmp006_data *data = iio_priv(dev_to_iio_dev(dev));
+ int cr = (data->config & TMP006_CONFIG_CR_MASK)
+ >> TMP006_CONFIG_CR_SHIFT;
+ return sprintf(buf, "%s\n", tmp006_freqs[cr]);
+}
+
+static ssize_t tmp006_store_freq(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tmp006_data *data = iio_priv(indio_dev);
+ int i;
+ bool found = false;
+
+ for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++)
+ if (sysfs_streq(buf, tmp006_freqs[i])) {
+ found = true;
+ break;
+ }
+ if (!found)
+ return -EINVAL;
+
+ data->config &= ~TMP006_CONFIG_CR_MASK;
+ data->config |= i << TMP006_CONFIG_CR_SHIFT;
+
+ return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
+ data->config);
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR,
+ tmp006_show_freq, tmp006_store_freq);
+
+static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25");
+
+static struct attribute *tmp006_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group tmp006_attribute_group = {
+ .attrs = tmp006_attributes,
+};
+
+static const struct iio_chan_spec tmp006_channels[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ }
+};
+
+static const struct iio_info tmp006_info = {
+ .read_raw = tmp006_read_raw,
+ .attrs = &tmp006_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static bool tmp006_check_identification(struct i2c_client *client)
+{
+ int mid, did;
+
+ mid = i2c_smbus_read_word_swapped(client, TMP006_MANUFACTURER_ID);
+ if (mid < 0)
+ return false;
+
+ did = i2c_smbus_read_word_swapped(client, TMP006_DEVICE_ID);
+ if (did < 0)
+ return false;
+
+ return mid == MANUFACTURER_MAGIC && did == DEVICE_MAGIC;
+}
+
+static int tmp006_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct tmp006_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ if (!tmp006_check_identification(client)) {
+ dev_err(&client->dev, "no TMP006 sensor\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = dev_name(&client->dev);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &tmp006_info;
+
+ indio_dev->channels = tmp006_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tmp006_channels);
+
+ ret = i2c_smbus_read_word_swapped(data->client, TMP006_CONFIG);
+ if (ret < 0)
+ return ret;
+ data->config = ret;
+
+ return iio_device_register(indio_dev);
+}
+
+static int tmp006_powerdown(struct tmp006_data *data)
+{
+ return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
+ data->config & ~TMP006_CONFIG_MOD_MASK);
+}
+
+static int tmp006_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ iio_device_unregister(indio_dev);
+ tmp006_powerdown(iio_priv(indio_dev));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tmp006_suspend(struct device *dev)
+{
+ return tmp006_powerdown(iio_priv(dev_to_iio_dev(dev)));
+}
+
+static int tmp006_resume(struct device *dev)
+{
+ struct tmp006_data *data = iio_priv(dev_to_iio_dev(dev));
+ return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
+ data->config | TMP006_CONFIG_MOD_MASK);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume);
+
+static const struct i2c_device_id tmp006_id[] = {
+ { "tmp006", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tmp006_id);
+
+static struct i2c_driver tmp006_driver = {
+ .driver = {
+ .name = "tmp006",
+ .pm = &tmp006_pm_ops,
+ .owner = THIS_MODULE,
+ },
+ .probe = tmp006_probe,
+ .remove = tmp006_remove,
+ .id_table = tmp006_id,
+};
+module_i2c_driver(tmp006_driver);
+
+MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
+MODULE_DESCRIPTION("TI TMP006 IR thermopile sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
index 360fd508b08..79996123a71 100644
--- a/drivers/iio/trigger/Kconfig
+++ b/drivers/iio/trigger/Kconfig
@@ -1,6 +1,8 @@
#
# Industrial I/O standalone triggers
#
+# When adding new entries keep the list in alphabetical order
+
menu "Triggers - standalone"
config IIO_INTERRUPT_TRIGGER
@@ -17,7 +19,7 @@ config IIO_SYSFS_TRIGGER
depends on SYSFS
select IRQ_WORK
help
- Provides support for using SYSFS entry as IIO triggers.
+ Provides support for using SYSFS entries as IIO triggers.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
index ce319a51b6a..0694daecaf2 100644
--- a/drivers/iio/trigger/Makefile
+++ b/drivers/iio/trigger/Makefile
@@ -2,5 +2,6 @@
# Makefile for triggers not associated with iio-devices
#
+# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index f1c279fabe6..7c0f9535fb7 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -423,7 +423,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
struct sockaddr_ib *addr;
union ib_gid gid, sgid, *dgid;
u16 pkey, index;
- u8 port, p;
+ u8 p;
int i;
cma_dev = NULL;
@@ -443,7 +443,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
if (!memcmp(&gid, dgid, sizeof(gid))) {
cma_dev = cur_dev;
sgid = gid;
- port = p;
+ id_priv->id.port_num = p;
goto found;
}
@@ -451,7 +451,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
dgid->global.subnet_prefix)) {
cma_dev = cur_dev;
sgid = gid;
- port = p;
+ id_priv->id.port_num = p;
}
}
}
@@ -462,7 +462,6 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
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);
@@ -880,7 +879,8 @@ static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id
{
struct cma_hdr *hdr;
- if (listen_id->route.addr.src_addr.ss_family == AF_IB) {
+ if ((listen_id->route.addr.src_addr.ss_family == AF_IB) &&
+ (ib_event->event == IB_CM_REQ_RECEIVED)) {
cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path);
return 0;
}
@@ -2677,29 +2677,32 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
{
struct ib_cm_sidr_req_param req;
struct ib_cm_id *id;
+ void *private_data;
int offset, ret;
+ memset(&req, 0, sizeof req);
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;
if (req.private_data_len) {
- req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
- if (!req.private_data)
+ private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+ if (!private_data)
return -ENOMEM;
} else {
- req.private_data = NULL;
+ private_data = NULL;
}
if (conn_param->private_data && conn_param->private_data_len)
- memcpy((void *) req.private_data + offset,
- conn_param->private_data, conn_param->private_data_len);
+ memcpy(private_data + offset, conn_param->private_data,
+ conn_param->private_data_len);
- if (req.private_data) {
- ret = cma_format_hdr((void *) req.private_data, id_priv);
+ if (private_data) {
+ ret = cma_format_hdr(private_data, id_priv);
if (ret)
goto out;
+ req.private_data = private_data;
}
id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler,
@@ -2721,7 +2724,7 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
id_priv->cm_id.ib = NULL;
}
out:
- kfree(req.private_data);
+ kfree(private_data);
return ret;
}
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index dc3fd1e8af0..4c837e66516 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -2663,6 +2663,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
int ret, i;
struct ib_qp_attr *attr;
struct ib_qp *qp;
+ u16 pkey_index;
attr = kmalloc(sizeof *attr, GFP_KERNEL);
if (!attr) {
@@ -2670,6 +2671,11 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
return -ENOMEM;
}
+ ret = ib_find_pkey(port_priv->device, port_priv->port_num,
+ IB_DEFAULT_PKEY_FULL, &pkey_index);
+ if (ret)
+ pkey_index = 0;
+
for (i = 0; i < IB_MAD_QPS_CORE; i++) {
qp = port_priv->qp_info[i].qp;
if (!qp)
@@ -2680,7 +2686,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
* one is needed for the Reset to Init transition
*/
attr->qp_state = IB_QPS_INIT;
- attr->pkey_index = 0;
+ attr->pkey_index = pkey_index;
attr->qkey = (qp->qp_num == 0) ? 0 : IB_QP1_QKEY;
ret = ib_modify_qp(qp, attr, IB_QP_STATE |
IB_QP_PKEY_INDEX | IB_QP_QKEY);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index e87f2201b22..d2283837d45 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -226,6 +226,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
mm->len = PAGE_ALIGN(((1UL << uresp.size_log2) + 1) *
sizeof(struct t3_cqe));
uresp.memsize = mm->len;
+ uresp.reserved = 0;
resplen = sizeof uresp;
}
if (ib_copy_to_udata(udata, &uresp, resplen)) {
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 232040447e8..a4975e1654a 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -1657,6 +1657,8 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
if (mm5) {
uresp.ma_sync_key = ucontext->key;
ucontext->key += PAGE_SIZE;
+ } else {
+ uresp.ma_sync_key = 0;
}
uresp.sq_key = ucontext->key;
ucontext->key += PAGE_SIZE;
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 4d599cedbb0..f2a3f48107e 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -1511,8 +1511,14 @@ static int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx,
memset(&attr, 0, sizeof attr);
attr.qp_state = IB_QPS_INIT;
- attr.pkey_index =
- to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0];
+ ret = 0;
+ if (create_tun)
+ ret = find_slave_port_pkey_ix(to_mdev(ctx->ib_dev), ctx->slave,
+ ctx->port, IB_DEFAULT_PKEY_FULL,
+ &attr.pkey_index);
+ if (ret || !create_tun)
+ attr.pkey_index =
+ to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0];
attr.qkey = IB_QP1_QKEY;
attr.port_num = ctx->port;
ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT);
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 8000fff4d44..3f831de9a4d 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -619,7 +619,8 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
resp.tot_uuars = req.total_num_uuars;
resp.num_ports = dev->mdev.caps.num_ports;
- err = ib_copy_to_udata(udata, &resp, sizeof(resp));
+ err = ib_copy_to_udata(udata, &resp,
+ sizeof(resp) - sizeof(resp.reserved));
if (err)
goto out_uars;
@@ -1426,7 +1427,8 @@ static int init_one(struct pci_dev *pdev,
if (err)
goto err_eqs;
- if (ib_register_device(&dev->ib_dev, NULL))
+ err = ib_register_device(&dev->ib_dev, NULL);
+ if (err)
goto err_rsrc;
err = create_umr_res(dev);
@@ -1434,8 +1436,9 @@ static int init_one(struct pci_dev *pdev,
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]))
+ err = device_create_file(&dev->ib_dev.dev,
+ mlx5_class_attributes[i]);
+ if (err)
goto err_umrc;
}
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index 16ac54c9819..045f8cdbd30 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -199,7 +199,7 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
static int sq_overhead(enum ib_qp_type qp_type)
{
- int size;
+ int size = 0;
switch (qp_type) {
case IB_QPT_XRC_INI:
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 418004c93fe..90200245c5e 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -3570,10 +3570,10 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
nes_debug(NES_DBG_AEQ, "aeid = 0x%04X, qp-cq id = %d, aeqe = %p,"
- " Tcp state = %d, iWARP state = %d\n",
+ " Tcp state = %s, iWARP state = %s\n",
async_event_id,
le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
- tcp_state, iwarp_state);
+ nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
if (aeq_info & NES_AEQE_QP) {
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 8f67fe2e91e..5b53ca5a228 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1384,6 +1384,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
if (ibpd->uobject) {
uresp.mmap_sq_db_index = nesqp->mmap_sq_db_index;
+ uresp.mmap_rq_db_index = 0;
uresp.actual_sq_size = sq_size;
uresp.actual_rq_size = rq_size;
uresp.qp_id = nesqp->hwqp.qp_id;
@@ -1767,7 +1768,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
resp.cq_id = nescq->hw_cq.cq_number;
resp.cq_size = nescq->hw_cq.cq_size;
resp.mmap_db_index = 0;
- if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
+ if (ib_copy_to_udata(udata, &resp, sizeof resp - sizeof resp.reserved)) {
nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
kfree(nescq);
return ERR_PTR(-EFAULT);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
index a877a8ed790..f4c587c68f6 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
@@ -29,7 +29,6 @@
#include <net/netevent.h>
#include <rdma/ib_addr.h>
-#include <rdma/ib_cache.h>
#include "ocrdma.h"
#include "ocrdma_verbs.h"
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index dcfbab177fa..f36630e4b6b 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -242,6 +242,7 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev,
memset(ctx->ah_tbl.va, 0, map_len);
ctx->ah_tbl.len = map_len;
+ memset(&resp, 0, sizeof(resp));
resp.ah_tbl_len = ctx->ah_tbl.len;
resp.ah_tbl_page = ctx->ah_tbl.pa;
@@ -253,7 +254,6 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev,
resp.wqe_size = dev->attr.wqe_size;
resp.rqe_size = dev->attr.rqe_size;
resp.dpp_wqe_size = dev->attr.wqe_size;
- resp.rsvd = 0;
memcpy(resp.fw_ver, dev->attr.fw_ver, sizeof(resp.fw_ver));
status = ib_copy_to_udata(udata, &resp, sizeof(resp));
@@ -338,6 +338,7 @@ static int ocrdma_copy_pd_uresp(struct ocrdma_pd *pd,
struct ocrdma_alloc_pd_uresp rsp;
struct ocrdma_ucontext *uctx = get_ocrdma_ucontext(ib_ctx);
+ memset(&rsp, 0, sizeof(rsp));
rsp.id = pd->id;
rsp.dpp_enabled = pd->dpp_enabled;
db_page_addr = pd->dev->nic_info.unmapped_db +
@@ -692,6 +693,7 @@ static int ocrdma_copy_cq_uresp(struct ocrdma_cq *cq, struct ib_udata *udata,
struct ocrdma_ucontext *uctx;
struct ocrdma_create_cq_uresp uresp;
+ memset(&uresp, 0, sizeof(uresp));
uresp.cq_id = cq->id;
uresp.page_size = cq->len;
uresp.num_pages = 1;
@@ -1460,6 +1462,7 @@ static int ocrdma_copy_srq_uresp(struct ocrdma_srq *srq, struct ib_udata *udata)
int status;
struct ocrdma_create_srq_uresp uresp;
+ memset(&uresp, 0, sizeof(uresp));
uresp.rq_dbid = srq->rq.dbid;
uresp.num_rq_pages = 1;
uresp.rq_page_addr[0] = srq->rq.pa;
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 21e8b09d4bf..016e7429adf 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -1596,6 +1596,8 @@ static void sdma_7322_p_errors(struct qib_pportdata *ppd, u64 errs)
struct qib_devdata *dd = ppd->dd;
errs &= QIB_E_P_SDMAERRS;
+ err_decode(ppd->cpspec->sdmamsgbuf, sizeof(ppd->cpspec->sdmamsgbuf),
+ errs, qib_7322p_error_msgs);
if (errs & QIB_E_P_SDMAUNEXPDATA)
qib_dev_err(dd, "IB%u:%u SDmaUnexpData\n", dd->unit,
diff --git a/drivers/infiniband/hw/qib/qib_sdma.c b/drivers/infiniband/hw/qib/qib_sdma.c
index 32162d35537..9b5322d8cd5 100644
--- a/drivers/infiniband/hw/qib/qib_sdma.c
+++ b/drivers/infiniband/hw/qib/qib_sdma.c
@@ -717,7 +717,7 @@ void dump_sdma_state(struct qib_pportdata *ppd)
struct qib_sdma_txreq *txp, *txpnext;
__le64 *descqp;
u64 desc[2];
- dma_addr_t addr;
+ u64 addr;
u16 gen, dwlen, dwoffset;
u16 head, tail, cnt;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 2cfa76f5d99..196b1d13cbc 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -932,12 +932,47 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
return 0;
}
+/*
+ * Takes whatever value which is in pkey index 0 and updates priv->pkey
+ * returns 0 if the pkey value was changed.
+ */
+static inline int update_parent_pkey(struct ipoib_dev_priv *priv)
+{
+ int result;
+ u16 prev_pkey;
+
+ prev_pkey = priv->pkey;
+ result = ib_query_pkey(priv->ca, priv->port, 0, &priv->pkey);
+ if (result) {
+ ipoib_warn(priv, "ib_query_pkey port %d failed (ret = %d)\n",
+ priv->port, result);
+ return result;
+ }
+
+ priv->pkey |= 0x8000;
+
+ if (prev_pkey != priv->pkey) {
+ ipoib_dbg(priv, "pkey changed from 0x%x to 0x%x\n",
+ prev_pkey, priv->pkey);
+ /*
+ * Update the pkey in the broadcast address, while making sure to set
+ * the full membership bit, so that we join the right broadcast group.
+ */
+ priv->dev->broadcast[8] = priv->pkey >> 8;
+ priv->dev->broadcast[9] = priv->pkey & 0xff;
+ return 0;
+ }
+
+ return 1;
+}
+
static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
enum ipoib_flush_level level)
{
struct ipoib_dev_priv *cpriv;
struct net_device *dev = priv->dev;
u16 new_index;
+ int result;
mutex_lock(&priv->vlan_mutex);
@@ -951,6 +986,10 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
mutex_unlock(&priv->vlan_mutex);
if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) {
+ /* for non-child devices must check/update the pkey value here */
+ if (level == IPOIB_FLUSH_HEAVY &&
+ !test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags))
+ update_parent_pkey(priv);
ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n");
return;
}
@@ -961,21 +1000,32 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
}
if (level == IPOIB_FLUSH_HEAVY) {
- if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
- clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
- ipoib_ib_dev_down(dev, 0);
- ipoib_ib_dev_stop(dev, 0);
- if (ipoib_pkey_dev_delay_open(dev))
+ /* child devices chase their origin pkey value, while non-child
+ * (parent) devices should always takes what present in pkey index 0
+ */
+ if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
+ if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
+ clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
+ ipoib_ib_dev_down(dev, 0);
+ ipoib_ib_dev_stop(dev, 0);
+ if (ipoib_pkey_dev_delay_open(dev))
+ return;
+ }
+ /* restart QP only if P_Key index is changed */
+ if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
+ new_index == priv->pkey_index) {
+ ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
return;
+ }
+ priv->pkey_index = new_index;
+ } else {
+ result = update_parent_pkey(priv);
+ /* restart QP only if P_Key value changed */
+ if (result) {
+ ipoib_dbg(priv, "Not flushing - P_Key value not changed.\n");
+ return;
+ }
}
-
- /* restart QP only if P_Key index is changed */
- if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
- new_index == priv->pkey_index) {
- ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
- return;
- }
- priv->pkey_index = new_index;
}
if (level == IPOIB_FLUSH_LIGHT) {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index b6e049a3c7a..c6f71a88c55 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1461,7 +1461,7 @@ static ssize_t create_child(struct device *dev,
if (sscanf(buf, "%i", &pkey) != 1)
return -EINVAL;
- if (pkey < 0 || pkey > 0xffff)
+ if (pkey <= 0 || pkey > 0xffff || pkey == 0x8000)
return -EINVAL;
/*
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
index 74685936c94..f81abe16cf0 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
@@ -119,6 +119,15 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
} else
child_pkey = nla_get_u16(data[IFLA_IPOIB_PKEY]);
+ if (child_pkey == 0 || child_pkey == 0x8000)
+ return -EINVAL;
+
+ /*
+ * Set the full membership bit, so that we join the right
+ * broadcast group, etc.
+ */
+ child_pkey |= 0x8000;
+
err = __ipoib_vlan_add(ppriv, netdev_priv(dev), child_pkey, IPOIB_RTNL_CHILD);
if (!err && data)
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 2e84ef859c5..1ec78bd8fa1 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -672,6 +672,7 @@ static umode_t iser_attr_is_visible(int param_type, int param)
case ISCSI_PARAM_TGT_RESET_TMO:
case ISCSI_PARAM_IFACE_NAME:
case ISCSI_PARAM_INITIATOR_NAME:
+ case ISCSI_PARAM_DISCOVERY_SESS:
return S_IRUGO;
default:
return 0;
@@ -701,7 +702,7 @@ static struct scsi_host_template iscsi_iser_sht = {
static struct iscsi_transport iscsi_iser_transport = {
.owner = THIS_MODULE,
.name = "iser",
- .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T,
+ .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_TEXT_NEGO,
/* session management */
.create_session = iscsi_iser_session_create,
.destroy_session = iscsi_iser_session_destroy,
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index b6d81a86c97..b31fa1d954a 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -234,6 +234,7 @@ void iser_free_rx_descriptors(struct iser_conn *ib_conn)
static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req)
{
struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iscsi_session *session = conn->session;
iser_dbg("req op %x flags %x\n", req->opcode, req->flags);
/* check if this is the last login - going to full feature phase */
@@ -248,7 +249,13 @@ static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req)
WARN_ON(iser_conn->ib_conn->post_recv_buf_count != 1);
WARN_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
- iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX);
+ if (session->discovery_sess) {
+ iser_info("Discovery session, re-using login RX buffer\n");
+ return 0;
+ } else
+ iser_info("Normal session, posting batch of RX %d buffers\n",
+ ISER_MIN_POSTED_RX);
+
/* Initial post receive buffers */
if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX))
return -ENOMEM;
@@ -425,6 +432,8 @@ int iser_send_control(struct iscsi_conn *conn,
}
if (task == conn->login_task) {
+ iser_dbg("op %x dsl %lx, posting login rx buffer\n",
+ task->hdr->opcode, data_seg_len);
err = iser_post_recvl(iser_conn->ib_conn);
if (err)
goto send_control_error;
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index da739d9d190..922a7fea2ce 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -639,16 +639,18 @@ EXPORT_SYMBOL(gameport_unregister_port);
* Gameport driver operations
*/
-static ssize_t gameport_driver_show_description(struct device_driver *drv, char *buf)
+static ssize_t description_show(struct device_driver *drv, char *buf)
{
struct gameport_driver *driver = to_gameport_driver(drv);
return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
}
+static DRIVER_ATTR_RO(description);
-static struct driver_attribute gameport_driver_attrs[] = {
- __ATTR(description, S_IRUGO, gameport_driver_show_description, NULL),
- __ATTR_NULL
+static struct attribute *gameport_driver_attrs[] = {
+ &driver_attr_description.attr,
+ NULL
};
+ATTRIBUTE_GROUPS(gameport_driver);
static int gameport_driver_probe(struct device *dev)
{
@@ -749,7 +751,7 @@ static int gameport_bus_match(struct device *dev, struct device_driver *drv)
static struct bus_type gameport_bus = {
.name = "gameport",
.dev_attrs = gameport_device_attrs,
- .drv_attrs = gameport_driver_attrs,
+ .drv_groups = gameport_driver_groups,
.match = gameport_bus_match,
.probe = gameport_driver_probe,
.remove = gameport_driver_remove,
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index fa061d46527..75e3b102ce4 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -167,6 +167,7 @@ static const struct xpad_device {
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
{ 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
+ { 0x1689, 0xfd01, "Razer Onza Classic Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 },
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 57b2637e153..8551dcaf24d 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -672,6 +672,7 @@ static int elantech_packet_check_v2(struct psmouse *psmouse)
*/
static int elantech_packet_check_v3(struct psmouse *psmouse)
{
+ struct elantech_data *etd = psmouse->private;
const u8 debounce_packet[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff };
unsigned char *packet = psmouse->packet;
@@ -682,19 +683,48 @@ static int elantech_packet_check_v3(struct psmouse *psmouse)
if (!memcmp(packet, debounce_packet, sizeof(debounce_packet)))
return PACKET_DEBOUNCE;
- if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02)
- return PACKET_V3_HEAD;
+ /*
+ * If the hardware flag 'crc_enabled' is set the packets have
+ * different signatures.
+ */
+ if (etd->crc_enabled) {
+ if ((packet[3] & 0x09) == 0x08)
+ return PACKET_V3_HEAD;
+
+ if ((packet[3] & 0x09) == 0x09)
+ return PACKET_V3_TAIL;
+ } else {
+ if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02)
+ return PACKET_V3_HEAD;
- if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c)
- return PACKET_V3_TAIL;
+ if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c)
+ return PACKET_V3_TAIL;
+ }
return PACKET_UNKNOWN;
}
static int elantech_packet_check_v4(struct psmouse *psmouse)
{
+ struct elantech_data *etd = psmouse->private;
unsigned char *packet = psmouse->packet;
unsigned char packet_type = packet[3] & 0x03;
+ bool sanity_check;
+
+ /*
+ * Sanity check based on the constant bits of a packet.
+ * The constant bits change depending on the value of
+ * the hardware flag 'crc_enabled' but are the same for
+ * every packet, regardless of the type.
+ */
+ if (etd->crc_enabled)
+ sanity_check = ((packet[3] & 0x08) == 0x00);
+ else
+ sanity_check = ((packet[0] & 0x0c) == 0x04 &&
+ (packet[3] & 0x1c) == 0x10);
+
+ if (!sanity_check)
+ return PACKET_UNKNOWN;
switch (packet_type) {
case 0:
@@ -1313,6 +1343,12 @@ static int elantech_set_properties(struct elantech_data *etd)
etd->reports_pressure = true;
}
+ /*
+ * The signatures of v3 and v4 packets change depending on the
+ * value of this hardware flag.
+ */
+ etd->crc_enabled = ((etd->fw_version & 0x4000) == 0x4000);
+
return 0;
}
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index 46db3be45ac..036a04abaef 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -129,6 +129,7 @@ struct elantech_data {
bool paritycheck;
bool jumpy_cursor;
bool reports_pressure;
+ bool crc_enabled;
unsigned char hw_version;
unsigned int fw_version;
unsigned int single_finger_reports;
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 94c17c28d26..1e691a3a79c 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -22,7 +22,8 @@ config SERIO_I8042
tristate "i8042 PC Keyboard controller" if EXPERT || !X86
default y
depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \
- (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN && !S390
+ (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN && !S390 && \
+ !ARC
help
i8042 is the chip over which the standard AT keyboard and PS/2
mouse are connected to the computer. If you use these devices,
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 25fc5971f42..2b56855c2c7 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -732,19 +732,20 @@ EXPORT_SYMBOL(serio_unregister_child_port);
* Serio driver operations
*/
-static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf)
+static ssize_t description_show(struct device_driver *drv, char *buf)
{
struct serio_driver *driver = to_serio_driver(drv);
return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
}
+static DRIVER_ATTR_RO(description);
-static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf)
+static ssize_t bind_mode_show(struct device_driver *drv, char *buf)
{
struct serio_driver *serio_drv = to_serio_driver(drv);
return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto");
}
-static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count)
+static ssize_t bind_mode_store(struct device_driver *drv, const char *buf, size_t count)
{
struct serio_driver *serio_drv = to_serio_driver(drv);
int retval;
@@ -760,14 +761,14 @@ static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char
return retval;
}
+static DRIVER_ATTR_RW(bind_mode);
-
-static struct driver_attribute serio_driver_attrs[] = {
- __ATTR(description, S_IRUGO, serio_driver_show_description, NULL),
- __ATTR(bind_mode, S_IWUSR | S_IRUGO,
- serio_driver_show_bind_mode, serio_driver_set_bind_mode),
- __ATTR_NULL
+static struct attribute *serio_driver_attrs[] = {
+ &driver_attr_description.attr,
+ &driver_attr_bind_mode.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(serio_driver);
static int serio_driver_probe(struct device *dev)
{
@@ -996,7 +997,7 @@ EXPORT_SYMBOL(serio_interrupt);
static struct bus_type serio_bus = {
.name = "serio",
.dev_attrs = serio_device_attrs,
- .drv_attrs = serio_driver_attrs,
+ .drv_groups = serio_driver_groups,
.match = serio_bus_match,
.uevent = serio_uevent,
.probe = serio_driver_probe,
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 384fbcd0cee..f3e91f0b57a 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -2112,7 +2112,7 @@ static const struct wacom_features wacom_features_0xDA =
{ "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
-static struct wacom_features wacom_features_0xDB =
+static const struct wacom_features wacom_features_0xDB =
{ "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
@@ -2127,6 +2127,12 @@ static const struct wacom_features wacom_features_0xDF =
{ "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN, 21648, 13700, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 16 };
+static const struct wacom_features wacom_features_0x300 =
+ { "Wacom Bamboo One S", WACOM_PKGLEN_BBPEN, 14720, 9225, 1023,
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x301 =
+ { "Wacom Bamboo One M", WACOM_PKGLEN_BBPEN, 21648, 13530, 1023,
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x6004 =
{ "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2253,6 +2259,8 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x100) },
{ USB_DEVICE_WACOM(0x101) },
{ USB_DEVICE_WACOM(0x10D) },
+ { USB_DEVICE_WACOM(0x300) },
+ { USB_DEVICE_WACOM(0x301) },
{ USB_DEVICE_WACOM(0x304) },
{ USB_DEVICE_WACOM(0x4001) },
{ USB_DEVICE_WACOM(0x47) },
diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c
index 69ea44ebcf6..4851afae38d 100644
--- a/drivers/irqchip/irq-sirfsoc.c
+++ b/drivers/irqchip/irq-sirfsoc.c
@@ -23,7 +23,7 @@
#define SIRFSOC_INT_RISC_LEVEL1 0x0024
#define SIRFSOC_INIT_IRQ_ID 0x0038
-#define SIRFSOC_NUM_IRQS 128
+#define SIRFSOC_NUM_IRQS 64
static struct irq_domain *sirfsoc_irqdomain;
@@ -32,15 +32,18 @@ sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
+ int ret;
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
- gc = irq_alloc_generic_chip("SIRFINTC", 1, irq_start, base, handle_level_irq);
- ct = gc->chip_types;
+ ret = irq_alloc_domain_generic_chips(sirfsoc_irqdomain, num, 1, "irq_sirfsoc",
+ handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+ gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, irq_start);
+ gc->reg_base = base;
+ ct = gc->chip_types;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->regs.mask = SIRFSOC_INT_RISC_MASK0;
-
- irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, 0);
}
static asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
@@ -60,9 +63,8 @@ static int __init sirfsoc_irq_init(struct device_node *np, struct device_node *p
if (!base)
panic("unable to map intc cpu registers\n");
- /* using legacy because irqchip_generic does not work with linear */
- sirfsoc_irqdomain = irq_domain_add_legacy(np, SIRFSOC_NUM_IRQS, 0, 0,
- &irq_domain_simple_ops, base);
+ sirfsoc_irqdomain = irq_domain_add_linear(np, SIRFSOC_NUM_IRQS,
+ &irq_generic_chip_ops, base);
sirfsoc_alloc_gc(base, 0, 32);
sirfsoc_alloc_gc(base + 4, 32, SIRFSOC_NUM_IRQS - 32);
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
index da30c5cb960..faf505462a4 100644
--- a/drivers/isdn/mISDN/core.c
+++ b/drivers/isdn/mISDN/core.c
@@ -37,8 +37,8 @@ static void mISDN_dev_release(struct device *dev)
/* nothing to do: the device is part of its parent's data structure */
}
-static ssize_t _show_id(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mISDNdevice *mdev = dev_to_mISDN(dev);
@@ -46,9 +46,10 @@ static ssize_t _show_id(struct device *dev,
return -ENODEV;
return sprintf(buf, "%d\n", mdev->id);
}
+static DEVICE_ATTR_RO(id);
-static ssize_t _show_nrbchan(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t nrbchan_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mISDNdevice *mdev = dev_to_mISDN(dev);
@@ -56,9 +57,10 @@ static ssize_t _show_nrbchan(struct device *dev,
return -ENODEV;
return sprintf(buf, "%d\n", mdev->nrbchan);
}
+static DEVICE_ATTR_RO(nrbchan);
-static ssize_t _show_d_protocols(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t d_protocols_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mISDNdevice *mdev = dev_to_mISDN(dev);
@@ -66,9 +68,10 @@ static ssize_t _show_d_protocols(struct device *dev,
return -ENODEV;
return sprintf(buf, "%d\n", mdev->Dprotocols);
}
+static DEVICE_ATTR_RO(d_protocols);
-static ssize_t _show_b_protocols(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t b_protocols_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mISDNdevice *mdev = dev_to_mISDN(dev);
@@ -76,9 +79,10 @@ static ssize_t _show_b_protocols(struct device *dev,
return -ENODEV;
return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols());
}
+static DEVICE_ATTR_RO(b_protocols);
-static ssize_t _show_protocol(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t protocol_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mISDNdevice *mdev = dev_to_mISDN(dev);
@@ -86,17 +90,19 @@ static ssize_t _show_protocol(struct device *dev,
return -ENODEV;
return sprintf(buf, "%d\n", mdev->D.protocol);
}
+static DEVICE_ATTR_RO(protocol);
-static ssize_t _show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
strcpy(buf, dev_name(dev));
return strlen(buf);
}
+static DEVICE_ATTR_RO(name);
#if 0 /* hangs */
-static ssize_t _set_name(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t name_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
int err = 0;
char *out = kmalloc(count + 1, GFP_KERNEL);
@@ -113,10 +119,11 @@ static ssize_t _set_name(struct device *dev, struct device_attribute *attr,
return (err < 0) ? err : count;
}
+static DEVICE_ATTR_RW(name);
#endif
-static ssize_t _show_channelmap(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t channelmap_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mISDNdevice *mdev = dev_to_mISDN(dev);
char *bp = buf;
@@ -127,18 +134,19 @@ static ssize_t _show_channelmap(struct device *dev,
return bp - buf;
}
-
-static struct device_attribute mISDN_dev_attrs[] = {
- __ATTR(id, S_IRUGO, _show_id, NULL),
- __ATTR(d_protocols, S_IRUGO, _show_d_protocols, NULL),
- __ATTR(b_protocols, S_IRUGO, _show_b_protocols, NULL),
- __ATTR(protocol, S_IRUGO, _show_protocol, NULL),
- __ATTR(channelmap, S_IRUGO, _show_channelmap, NULL),
- __ATTR(nrbchan, S_IRUGO, _show_nrbchan, NULL),
- __ATTR(name, S_IRUGO, _show_name, NULL),
-/* __ATTR(name, S_IRUGO | S_IWUSR, _show_name, _set_name), */
- {}
+static DEVICE_ATTR_RO(channelmap);
+
+static struct attribute *mISDN_attrs[] = {
+ &dev_attr_id.attr,
+ &dev_attr_d_protocols.attr,
+ &dev_attr_b_protocols.attr,
+ &dev_attr_protocol.attr,
+ &dev_attr_channelmap.attr,
+ &dev_attr_nrbchan.attr,
+ &dev_attr_name.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(mISDN);
static int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env)
{
@@ -162,7 +170,7 @@ static struct class mISDN_class = {
.name = "mISDN",
.owner = THIS_MODULE,
.dev_uevent = mISDN_uevent,
- .dev_attrs = mISDN_dev_attrs,
+ .dev_groups = mISDN_groups,
.dev_release = mISDN_dev_release,
.class_release = mISDN_class_release,
};
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c
index 22b720ec80c..77025f5cb57 100644
--- a/drivers/isdn/mISDN/dsp_core.c
+++ b/drivers/isdn/mISDN/dsp_core.c
@@ -288,8 +288,10 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb)
u8 *data;
int len;
- if (skb->len < sizeof(int))
+ if (skb->len < sizeof(int)) {
printk(KERN_ERR "%s: PH_CONTROL message too short\n", __func__);
+ return -EINVAL;
+ }
cont = *((int *)skb->data);
len = skb->len - sizeof(int);
data = skb->data + sizeof(int);
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 4336e37a97f..f37d63cf726 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -29,7 +29,7 @@ static void led_update_brightness(struct led_classdev *led_cdev)
led_cdev->brightness = led_cdev->brightness_get(led_cdev);
}
-static ssize_t led_brightness_show(struct device *dev,
+static ssize_t brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -40,7 +40,7 @@ static ssize_t led_brightness_show(struct device *dev,
return sprintf(buf, "%u\n", led_cdev->brightness);
}
-static ssize_t led_brightness_store(struct device *dev,
+static ssize_t brightness_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -57,6 +57,7 @@ static ssize_t led_brightness_store(struct device *dev,
return size;
}
+static DEVICE_ATTR_RW(brightness);
static ssize_t led_max_brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -65,14 +66,35 @@ static ssize_t led_max_brightness_show(struct device *dev,
return sprintf(buf, "%u\n", led_cdev->max_brightness);
}
+static DEVICE_ATTR(max_brightness, 0444, led_max_brightness_show, NULL);
-static struct device_attribute led_class_attrs[] = {
- __ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
- __ATTR(max_brightness, 0444, led_max_brightness_show, NULL),
#ifdef CONFIG_LEDS_TRIGGERS
- __ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
+static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
+static struct attribute *led_trigger_attrs[] = {
+ &dev_attr_trigger.attr,
+ NULL,
+};
+static const struct attribute_group led_trigger_group = {
+ .attrs = led_trigger_attrs,
+};
+#endif
+
+static struct attribute *led_class_attrs[] = {
+ &dev_attr_brightness.attr,
+ &dev_attr_max_brightness.attr,
+ NULL,
+};
+
+static const struct attribute_group led_group = {
+ .attrs = led_class_attrs,
+};
+
+static const struct attribute_group *led_groups[] = {
+ &led_group,
+#ifdef CONFIG_LEDS_TRIGGERS
+ &led_trigger_group,
#endif
- __ATTR_NULL,
+ NULL,
};
static void led_timer_function(unsigned long data)
@@ -258,7 +280,7 @@ static int __init leds_init(void)
if (IS_ERR(leds_class))
return PTR_ERR(leds_class);
leds_class->pm = &leds_class_dev_pm_ops;
- leds_class->dev_attrs = led_class_attrs;
+ leds_class->dev_groups = led_groups;
return 0;
}
diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c
index 0b9a79b2f48..82fc86a90c1 100644
--- a/drivers/macintosh/windfarm_rm31.c
+++ b/drivers/macintosh/windfarm_rm31.c
@@ -439,15 +439,15 @@ static void backside_setup_pid(void)
/* Slots fan */
static const struct wf_pid_param slots_param = {
- .interval = 5,
- .history_len = 2,
- .gd = 30 << 20,
- .gp = 5 << 20,
- .gr = 0,
- .itarget = 40 << 16,
- .additive = 1,
- .min = 300,
- .max = 4000,
+ .interval = 1,
+ .history_len = 20,
+ .gd = 0,
+ .gp = 0,
+ .gr = 0x00100000,
+ .itarget = 3200000,
+ .additive = 0,
+ .min = 20,
+ .max = 100,
};
static void slots_fan_tick(void)
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index 048f2947e08..e45f5575fd4 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -63,7 +63,10 @@
#include "bcache.h"
#include "btree.h"
+#include <linux/freezer.h>
+#include <linux/kthread.h>
#include <linux/random.h>
+#include <trace/events/bcache.h>
#define MAX_IN_FLIGHT_DISCARDS 8U
@@ -151,7 +154,7 @@ static void discard_finish(struct work_struct *w)
mutex_unlock(&ca->set->bucket_lock);
closure_wake_up(&ca->set->bucket_wait);
- wake_up(&ca->set->alloc_wait);
+ wake_up_process(ca->alloc_thread);
closure_put(&ca->set->cl);
}
@@ -350,38 +353,30 @@ static void invalidate_buckets(struct cache *ca)
break;
}
- pr_debug("free %zu/%zu free_inc %zu/%zu unused %zu/%zu",
- fifo_used(&ca->free), ca->free.size,
- fifo_used(&ca->free_inc), ca->free_inc.size,
- fifo_used(&ca->unused), ca->unused.size);
+ trace_bcache_alloc_invalidate(ca);
}
#define allocator_wait(ca, cond) \
do { \
- DEFINE_WAIT(__wait); \
- \
while (1) { \
- prepare_to_wait(&ca->set->alloc_wait, \
- &__wait, TASK_INTERRUPTIBLE); \
+ set_current_state(TASK_INTERRUPTIBLE); \
if (cond) \
break; \
\
mutex_unlock(&(ca)->set->bucket_lock); \
- if (test_bit(CACHE_SET_STOPPING_2, &ca->set->flags)) { \
- finish_wait(&ca->set->alloc_wait, &__wait); \
- closure_return(cl); \
- } \
+ if (kthread_should_stop()) \
+ return 0; \
\
+ try_to_freeze(); \
schedule(); \
mutex_lock(&(ca)->set->bucket_lock); \
} \
- \
- finish_wait(&ca->set->alloc_wait, &__wait); \
+ __set_current_state(TASK_RUNNING); \
} while (0)
-void bch_allocator_thread(struct closure *cl)
+static int bch_allocator_thread(void *arg)
{
- struct cache *ca = container_of(cl, struct cache, alloc);
+ struct cache *ca = arg;
mutex_lock(&ca->set->bucket_lock);
@@ -442,7 +437,7 @@ long bch_bucket_alloc(struct cache *ca, unsigned watermark, struct closure *cl)
{
long r = -1;
again:
- wake_up(&ca->set->alloc_wait);
+ wake_up_process(ca->alloc_thread);
if (fifo_used(&ca->free) > ca->watermark[watermark] &&
fifo_pop(&ca->free, r)) {
@@ -476,9 +471,7 @@ again:
return r;
}
- pr_debug("alloc failure: blocked %i free %zu free_inc %zu unused %zu",
- atomic_read(&ca->set->prio_blocked), fifo_used(&ca->free),
- fifo_used(&ca->free_inc), fifo_used(&ca->unused));
+ trace_bcache_alloc_fail(ca);
if (cl) {
closure_wait(&ca->set->bucket_wait, cl);
@@ -552,6 +545,17 @@ int bch_bucket_alloc_set(struct cache_set *c, unsigned watermark,
/* Init */
+int bch_cache_allocator_start(struct cache *ca)
+{
+ struct task_struct *k = kthread_run(bch_allocator_thread,
+ ca, "bcache_allocator");
+ if (IS_ERR(k))
+ return PTR_ERR(k);
+
+ ca->alloc_thread = k;
+ return 0;
+}
+
void bch_cache_allocator_exit(struct cache *ca)
{
struct discard *d;
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index d3e15b42a4a..b39f6f0b45f 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -178,7 +178,6 @@
#define pr_fmt(fmt) "bcache: %s() " fmt "\n", __func__
#include <linux/bio.h>
-#include <linux/blktrace_api.h>
#include <linux/kobject.h>
#include <linux/list.h>
#include <linux/mutex.h>
@@ -388,8 +387,6 @@ struct keybuf_key {
typedef bool (keybuf_pred_fn)(struct keybuf *, struct bkey *);
struct keybuf {
- keybuf_pred_fn *key_predicate;
-
struct bkey last_scanned;
spinlock_t lock;
@@ -437,9 +434,12 @@ struct bcache_device {
/* If nonzero, we're detaching/unregistering from cache set */
atomic_t detaching;
+ int flush_done;
+
+ uint64_t nr_stripes;
+ unsigned stripe_size_bits;
+ atomic_t *stripe_sectors_dirty;
- atomic_long_t sectors_dirty;
- unsigned long sectors_dirty_gc;
unsigned long sectors_dirty_last;
long sectors_dirty_derivative;
@@ -531,6 +531,7 @@ struct cached_dev {
unsigned sequential_merge:1;
unsigned verify:1;
+ unsigned partial_stripes_expensive:1;
unsigned writeback_metadata:1;
unsigned writeback_running:1;
unsigned char writeback_percent;
@@ -565,8 +566,7 @@ struct cache {
unsigned watermark[WATERMARK_MAX];
- struct closure alloc;
- struct workqueue_struct *alloc_workqueue;
+ struct task_struct *alloc_thread;
struct closure prio;
struct prio_set *disk_buckets;
@@ -664,13 +664,9 @@ struct gc_stat {
* CACHE_SET_STOPPING always gets set first when we're closing down a cache set;
* we'll continue to run normally for awhile with CACHE_SET_STOPPING set (i.e.
* flushing dirty data).
- *
- * CACHE_SET_STOPPING_2 gets set at the last phase, when it's time to shut down
- * the allocation thread.
*/
#define CACHE_SET_UNREGISTERING 0
#define CACHE_SET_STOPPING 1
-#define CACHE_SET_STOPPING_2 2
struct cache_set {
struct closure cl;
@@ -703,9 +699,6 @@ struct cache_set {
/* For the btree cache */
struct shrinker shrink;
- /* For the allocator itself */
- wait_queue_head_t alloc_wait;
-
/* For the btree cache and anything allocation related */
struct mutex bucket_lock;
@@ -823,10 +816,9 @@ struct cache_set {
/*
* A btree node on disk could have too many bsets for an iterator to fit
- * on the stack - this is a single element mempool for btree_read_work()
+ * on the stack - have to dynamically allocate them
*/
- struct mutex fill_lock;
- struct btree_iter *fill_iter;
+ mempool_t *fill_iter;
/*
* btree_sort() is a merge sort and requires temporary space - single
@@ -834,6 +826,7 @@ struct cache_set {
*/
struct mutex sort_lock;
struct bset *sort;
+ unsigned sort_crit_factor;
/* List of buckets we're currently writing data to */
struct list_head data_buckets;
@@ -906,8 +899,6 @@ static inline unsigned local_clock_us(void)
return local_clock() >> 10;
}
-#define MAX_BSETS 4U
-
#define BTREE_PRIO USHRT_MAX
#define INITIAL_PRIO 32768
@@ -1112,23 +1103,6 @@ static inline void __bkey_put(struct cache_set *c, struct bkey *k)
atomic_dec_bug(&PTR_BUCKET(c, k, i)->pin);
}
-/* Blktrace macros */
-
-#define blktrace_msg(c, fmt, ...) \
-do { \
- struct request_queue *q = bdev_get_queue(c->bdev); \
- if (q) \
- blk_add_trace_msg(q, fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define blktrace_msg_all(s, fmt, ...) \
-do { \
- struct cache *_c; \
- unsigned i; \
- for_each_cache(_c, (s), i) \
- blktrace_msg(_c, fmt, ##__VA_ARGS__); \
-} while (0)
-
static inline void cached_dev_put(struct cached_dev *dc)
{
if (atomic_dec_and_test(&dc->count))
@@ -1173,10 +1147,16 @@ static inline uint8_t bucket_disk_gen(struct bucket *b)
static struct kobj_attribute ksysfs_##n = \
__ATTR(n, S_IWUSR|S_IRUSR, show, store)
-/* Forward declarations */
+static inline void wake_up_allocators(struct cache_set *c)
+{
+ struct cache *ca;
+ unsigned i;
+
+ for_each_cache(ca, c, i)
+ wake_up_process(ca->alloc_thread);
+}
-void bch_writeback_queue(struct cached_dev *);
-void bch_writeback_add(struct cached_dev *, unsigned);
+/* Forward declarations */
void bch_count_io_errors(struct cache *, int, const char *);
void bch_bbio_count_io_errors(struct cache_set *, struct bio *,
@@ -1193,7 +1173,6 @@ void bch_submit_bbio(struct bio *, struct cache_set *, struct bkey *, unsigned);
uint8_t bch_inc_gen(struct cache *, struct bucket *);
void bch_rescale_priorities(struct cache_set *, int);
bool bch_bucket_add_unused(struct cache *, struct bucket *);
-void bch_allocator_thread(struct closure *);
long bch_bucket_alloc(struct cache *, unsigned, struct closure *);
void bch_bucket_free(struct cache_set *, struct bkey *);
@@ -1241,9 +1220,9 @@ void bch_cache_set_stop(struct cache_set *);
struct cache_set *bch_cache_set_alloc(struct cache_sb *);
void bch_btree_cache_free(struct cache_set *);
int bch_btree_cache_alloc(struct cache_set *);
-void bch_cached_dev_writeback_init(struct cached_dev *);
void bch_moving_init_cache_set(struct cache_set *);
+int bch_cache_allocator_start(struct cache *ca);
void bch_cache_allocator_exit(struct cache *ca);
int bch_cache_allocator_init(struct cache *ca);
diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c
index 1d27d3af325..8010eed06a5 100644
--- a/drivers/md/bcache/bset.c
+++ b/drivers/md/bcache/bset.c
@@ -78,6 +78,7 @@ struct bkey *bch_keylist_pop(struct keylist *l)
bool __bch_ptr_invalid(struct cache_set *c, int level, const struct bkey *k)
{
unsigned i;
+ char buf[80];
if (level && (!KEY_PTRS(k) || !KEY_SIZE(k) || KEY_DIRTY(k)))
goto bad;
@@ -102,7 +103,8 @@ bool __bch_ptr_invalid(struct cache_set *c, int level, const struct bkey *k)
return false;
bad:
- cache_bug(c, "spotted bad key %s: %s", pkey(k), bch_ptr_status(c, k));
+ bch_bkey_to_text(buf, sizeof(buf), k);
+ cache_bug(c, "spotted bad key %s: %s", buf, bch_ptr_status(c, k));
return true;
}
@@ -162,10 +164,16 @@ bool bch_ptr_bad(struct btree *b, const struct bkey *k)
#ifdef CONFIG_BCACHE_EDEBUG
bug:
mutex_unlock(&b->c->bucket_lock);
- btree_bug(b,
+
+ {
+ char buf[80];
+
+ bch_bkey_to_text(buf, sizeof(buf), k);
+ btree_bug(b,
"inconsistent pointer %s: bucket %zu pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
- pkey(k), PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin),
- g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
+ buf, PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin),
+ g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
+ }
return true;
#endif
}
@@ -1084,33 +1092,39 @@ void bch_btree_sort_into(struct btree *b, struct btree *new)
new->sets->size = 0;
}
+#define SORT_CRIT (4096 / sizeof(uint64_t))
+
void bch_btree_sort_lazy(struct btree *b)
{
- if (b->nsets) {
- unsigned i, j, keys = 0, total;
+ unsigned crit = SORT_CRIT;
+ int i;
- for (i = 0; i <= b->nsets; i++)
- keys += b->sets[i].data->keys;
-
- total = keys;
+ /* Don't sort if nothing to do */
+ if (!b->nsets)
+ goto out;
- for (j = 0; j < b->nsets; j++) {
- if (keys * 2 < total ||
- keys < 1000) {
- bch_btree_sort_partial(b, j);
- return;
- }
+ /* If not a leaf node, always sort */
+ if (b->level) {
+ bch_btree_sort(b);
+ return;
+ }
- keys -= b->sets[j].data->keys;
- }
+ for (i = b->nsets - 1; i >= 0; --i) {
+ crit *= b->c->sort_crit_factor;
- /* Must sort if b->nsets == 3 or we'll overflow */
- if (b->nsets >= (MAX_BSETS - 1) - b->level) {
- bch_btree_sort(b);
+ if (b->sets[i].data->keys < crit) {
+ bch_btree_sort_partial(b, i);
return;
}
}
+ /* Sort if we'd overflow */
+ if (b->nsets + 1 == MAX_BSETS) {
+ bch_btree_sort(b);
+ return;
+ }
+
+out:
bset_build_written_tree(b);
}
diff --git a/drivers/md/bcache/bset.h b/drivers/md/bcache/bset.h
index 57a9cff4154..ae115a253d7 100644
--- a/drivers/md/bcache/bset.h
+++ b/drivers/md/bcache/bset.h
@@ -1,6 +1,8 @@
#ifndef _BCACHE_BSET_H
#define _BCACHE_BSET_H
+#include <linux/slab.h>
+
/*
* BKEYS:
*
@@ -142,6 +144,8 @@
/* Btree key comparison/iteration */
+#define MAX_BSETS 4U
+
struct btree_iter {
size_t size, used;
struct btree_iter_set {
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 7a5658f04e6..ee372884c40 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -24,6 +24,7 @@
#include "btree.h"
#include "debug.h"
#include "request.h"
+#include "writeback.h"
#include <linux/slab.h>
#include <linux/bitops.h>
@@ -134,44 +135,17 @@ static uint64_t btree_csum_set(struct btree *b, struct bset *i)
return crc ^ 0xffffffffffffffffULL;
}
-static void btree_bio_endio(struct bio *bio, int error)
+static void bch_btree_node_read_done(struct btree *b)
{
- struct closure *cl = bio->bi_private;
- struct btree *b = container_of(cl, struct btree, io.cl);
-
- if (error)
- set_btree_node_io_error(b);
-
- bch_bbio_count_io_errors(b->c, bio, error, (bio->bi_rw & WRITE)
- ? "writing btree" : "reading btree");
- closure_put(cl);
-}
-
-static void btree_bio_init(struct btree *b)
-{
- BUG_ON(b->bio);
- b->bio = bch_bbio_alloc(b->c);
-
- b->bio->bi_end_io = btree_bio_endio;
- b->bio->bi_private = &b->io.cl;
-}
-
-void bch_btree_read_done(struct closure *cl)
-{
- struct btree *b = container_of(cl, struct btree, io.cl);
- struct bset *i = b->sets[0].data;
- struct btree_iter *iter = b->c->fill_iter;
const char *err = "bad btree header";
- BUG_ON(b->nsets || b->written);
-
- bch_bbio_free(b->bio, b->c);
- b->bio = NULL;
+ struct bset *i = b->sets[0].data;
+ struct btree_iter *iter;
- mutex_lock(&b->c->fill_lock);
+ iter = mempool_alloc(b->c->fill_iter, GFP_NOWAIT);
+ iter->size = b->c->sb.bucket_size / b->c->sb.block_size;
iter->used = 0;
- if (btree_node_io_error(b) ||
- !i->seq)
+ if (!i->seq)
goto err;
for (;
@@ -228,17 +202,8 @@ void bch_btree_read_done(struct closure *cl)
if (b->written < btree_blocks(b))
bch_bset_init_next(b);
out:
-
- mutex_unlock(&b->c->fill_lock);
-
- spin_lock(&b->c->btree_read_time_lock);
- bch_time_stats_update(&b->c->btree_read_time, b->io_start_time);
- spin_unlock(&b->c->btree_read_time_lock);
-
- smp_wmb(); /* read_done is our write lock */
- set_btree_node_read_done(b);
-
- closure_return(cl);
+ mempool_free(iter, b->c->fill_iter);
+ return;
err:
set_btree_node_io_error(b);
bch_cache_set_error(b->c, "%s at bucket %zu, block %zu, %u keys",
@@ -247,48 +212,69 @@ err:
goto out;
}
-void bch_btree_read(struct btree *b)
+static void btree_node_read_endio(struct bio *bio, int error)
+{
+ struct closure *cl = bio->bi_private;
+ closure_put(cl);
+}
+
+void bch_btree_node_read(struct btree *b)
{
- BUG_ON(b->nsets || b->written);
+ uint64_t start_time = local_clock();
+ struct closure cl;
+ struct bio *bio;
+
+ trace_bcache_btree_read(b);
+
+ closure_init_stack(&cl);
+
+ bio = bch_bbio_alloc(b->c);
+ bio->bi_rw = REQ_META|READ_SYNC;
+ bio->bi_size = KEY_SIZE(&b->key) << 9;
+ bio->bi_end_io = btree_node_read_endio;
+ bio->bi_private = &cl;
+
+ bch_bio_map(bio, b->sets[0].data);
+
+ bch_submit_bbio(bio, b->c, &b->key, 0);
+ closure_sync(&cl);
- if (!closure_trylock(&b->io.cl, &b->c->cl))
- BUG();
+ if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+ set_btree_node_io_error(b);
- b->io_start_time = local_clock();
+ bch_bbio_free(bio, b->c);
- btree_bio_init(b);
- b->bio->bi_rw = REQ_META|READ_SYNC;
- b->bio->bi_size = KEY_SIZE(&b->key) << 9;
+ if (btree_node_io_error(b))
+ goto err;
- bch_bio_map(b->bio, b->sets[0].data);
+ bch_btree_node_read_done(b);
- pr_debug("%s", pbtree(b));
- trace_bcache_btree_read(b->bio);
- bch_submit_bbio(b->bio, b->c, &b->key, 0);
+ spin_lock(&b->c->btree_read_time_lock);
+ bch_time_stats_update(&b->c->btree_read_time, start_time);
+ spin_unlock(&b->c->btree_read_time_lock);
- continue_at(&b->io.cl, bch_btree_read_done, system_wq);
+ return;
+err:
+ bch_cache_set_error(b->c, "io error reading bucket %lu",
+ PTR_BUCKET_NR(b->c, &b->key, 0));
}
static void btree_complete_write(struct btree *b, struct btree_write *w)
{
if (w->prio_blocked &&
!atomic_sub_return(w->prio_blocked, &b->c->prio_blocked))
- wake_up(&b->c->alloc_wait);
+ wake_up_allocators(b->c);
if (w->journal) {
atomic_dec_bug(w->journal);
__closure_wake_up(&b->c->journal.wait);
}
- if (w->owner)
- closure_put(w->owner);
-
w->prio_blocked = 0;
w->journal = NULL;
- w->owner = NULL;
}
-static void __btree_write_done(struct closure *cl)
+static void __btree_node_write_done(struct closure *cl)
{
struct btree *b = container_of(cl, struct btree, io.cl);
struct btree_write *w = btree_prev_write(b);
@@ -304,7 +290,7 @@ static void __btree_write_done(struct closure *cl)
closure_return(cl);
}
-static void btree_write_done(struct closure *cl)
+static void btree_node_write_done(struct closure *cl)
{
struct btree *b = container_of(cl, struct btree, io.cl);
struct bio_vec *bv;
@@ -313,10 +299,22 @@ static void btree_write_done(struct closure *cl)
__bio_for_each_segment(bv, b->bio, n, 0)
__free_page(bv->bv_page);
- __btree_write_done(cl);
+ __btree_node_write_done(cl);
}
-static void do_btree_write(struct btree *b)
+static void btree_node_write_endio(struct bio *bio, int error)
+{
+ struct closure *cl = bio->bi_private;
+ struct btree *b = container_of(cl, struct btree, io.cl);
+
+ if (error)
+ set_btree_node_io_error(b);
+
+ bch_bbio_count_io_errors(b->c, bio, error, "writing btree");
+ closure_put(cl);
+}
+
+static void do_btree_node_write(struct btree *b)
{
struct closure *cl = &b->io.cl;
struct bset *i = b->sets[b->nsets].data;
@@ -325,15 +323,34 @@ static void do_btree_write(struct btree *b)
i->version = BCACHE_BSET_VERSION;
i->csum = btree_csum_set(b, i);
- btree_bio_init(b);
- b->bio->bi_rw = REQ_META|WRITE_SYNC;
- b->bio->bi_size = set_blocks(i, b->c) * block_bytes(b->c);
+ BUG_ON(b->bio);
+ b->bio = bch_bbio_alloc(b->c);
+
+ b->bio->bi_end_io = btree_node_write_endio;
+ b->bio->bi_private = &b->io.cl;
+ b->bio->bi_rw = REQ_META|WRITE_SYNC|REQ_FUA;
+ b->bio->bi_size = set_blocks(i, b->c) * block_bytes(b->c);
bch_bio_map(b->bio, i);
+ /*
+ * If we're appending to a leaf node, we don't technically need FUA -
+ * this write just needs to be persisted before the next journal write,
+ * which will be marked FLUSH|FUA.
+ *
+ * Similarly if we're writing a new btree root - the pointer is going to
+ * be in the next journal entry.
+ *
+ * But if we're writing a new btree node (that isn't a root) or
+ * appending to a non leaf btree node, we need either FUA or a flush
+ * when we write the parent with the new pointer. FUA is cheaper than a
+ * flush, and writes appending to leaf nodes aren't blocking anything so
+ * just make all btree node writes FUA to keep things sane.
+ */
+
bkey_copy(&k.key, &b->key);
SET_PTR_OFFSET(&k.key, 0, PTR_OFFSET(&k.key, 0) + bset_offset(b, i));
- if (!bch_bio_alloc_pages(b->bio, GFP_NOIO)) {
+ if (!bio_alloc_pages(b->bio, GFP_NOIO)) {
int j;
struct bio_vec *bv;
void *base = (void *) ((unsigned long) i & ~(PAGE_SIZE - 1));
@@ -342,40 +359,41 @@ static void do_btree_write(struct btree *b)
memcpy(page_address(bv->bv_page),
base + j * PAGE_SIZE, PAGE_SIZE);
- trace_bcache_btree_write(b->bio);
bch_submit_bbio(b->bio, b->c, &k.key, 0);
- continue_at(cl, btree_write_done, NULL);
+ continue_at(cl, btree_node_write_done, NULL);
} else {
b->bio->bi_vcnt = 0;
bch_bio_map(b->bio, i);
- trace_bcache_btree_write(b->bio);
bch_submit_bbio(b->bio, b->c, &k.key, 0);
closure_sync(cl);
- __btree_write_done(cl);
+ __btree_node_write_done(cl);
}
}
-static void __btree_write(struct btree *b)
+void bch_btree_node_write(struct btree *b, struct closure *parent)
{
struct bset *i = b->sets[b->nsets].data;
+ trace_bcache_btree_write(b);
+
BUG_ON(current->bio_list);
+ BUG_ON(b->written >= btree_blocks(b));
+ BUG_ON(b->written && !i->keys);
+ BUG_ON(b->sets->data->seq != i->seq);
+ bch_check_key_order(b, i);
- closure_lock(&b->io, &b->c->cl);
cancel_delayed_work(&b->work);
+ /* If caller isn't waiting for write, parent refcount is cache set */
+ closure_lock(&b->io, parent ?: &b->c->cl);
+
clear_bit(BTREE_NODE_dirty, &b->flags);
change_bit(BTREE_NODE_write_idx, &b->flags);
- bch_check_key_order(b, i);
- BUG_ON(b->written && !i->keys);
-
- do_btree_write(b);
-
- pr_debug("%s block %i keys %i", pbtree(b), b->written, i->keys);
+ do_btree_node_write(b);
b->written += set_blocks(i, b->c);
atomic_long_add(set_blocks(i, b->c) * b->c->sb.block_size,
@@ -387,37 +405,31 @@ static void __btree_write(struct btree *b)
bch_bset_init_next(b);
}
-static void btree_write_work(struct work_struct *w)
+static void btree_node_write_work(struct work_struct *w)
{
struct btree *b = container_of(to_delayed_work(w), struct btree, work);
- down_write(&b->lock);
+ rw_lock(true, b, b->level);
if (btree_node_dirty(b))
- __btree_write(b);
- up_write(&b->lock);
+ bch_btree_node_write(b, NULL);
+ rw_unlock(true, b);
}
-void bch_btree_write(struct btree *b, bool now, struct btree_op *op)
+static void bch_btree_leaf_dirty(struct btree *b, struct btree_op *op)
{
struct bset *i = b->sets[b->nsets].data;
struct btree_write *w = btree_current_write(b);
- BUG_ON(b->written &&
- (b->written >= btree_blocks(b) ||
- i->seq != b->sets[0].data->seq ||
- !i->keys));
+ BUG_ON(!b->written);
+ BUG_ON(!i->keys);
- if (!btree_node_dirty(b)) {
- set_btree_node_dirty(b);
- queue_delayed_work(btree_io_wq, &b->work,
- msecs_to_jiffies(30000));
- }
+ if (!btree_node_dirty(b))
+ queue_delayed_work(btree_io_wq, &b->work, 30 * HZ);
- w->prio_blocked += b->prio_blocked;
- b->prio_blocked = 0;
+ set_btree_node_dirty(b);
- if (op && op->journal && !b->level) {
+ if (op && op->journal) {
if (w->journal &&
journal_pin_cmp(b->c, w, op)) {
atomic_dec_bug(w->journal);
@@ -430,23 +442,10 @@ void bch_btree_write(struct btree *b, bool now, struct btree_op *op)
}
}
- if (current->bio_list)
- return;
-
/* Force write if set is too big */
- if (now ||
- b->level ||
- set_bytes(i) > PAGE_SIZE - 48) {
- if (op && now) {
- /* Must wait on multiple writes */
- BUG_ON(w->owner);
- w->owner = &op->cl;
- closure_get(&op->cl);
- }
-
- __btree_write(b);
- }
- BUG_ON(!b->written);
+ if (set_bytes(i) > PAGE_SIZE - 48 &&
+ !current->bio_list)
+ bch_btree_node_write(b, NULL);
}
/*
@@ -559,7 +558,7 @@ static struct btree *mca_bucket_alloc(struct cache_set *c,
init_rwsem(&b->lock);
lockdep_set_novalidate_class(&b->lock);
INIT_LIST_HEAD(&b->list);
- INIT_DELAYED_WORK(&b->work, btree_write_work);
+ INIT_DELAYED_WORK(&b->work, btree_node_write_work);
b->c = c;
closure_init_unlocked(&b->io);
@@ -582,7 +581,7 @@ static int mca_reap(struct btree *b, struct closure *cl, unsigned min_order)
BUG_ON(btree_node_dirty(b) && !b->sets[0].data);
if (cl && btree_node_dirty(b))
- bch_btree_write(b, true, NULL);
+ bch_btree_node_write(b, NULL);
if (cl)
closure_wait_event_async(&b->io.wait, cl,
@@ -623,6 +622,13 @@ static int bch_mca_shrink(struct shrinker *shrink, struct shrink_control *sc)
else if (!mutex_trylock(&c->bucket_lock))
return -1;
+ /*
+ * It's _really_ critical that we don't free too many btree nodes - we
+ * have to always leave ourselves a reserve. The reserve is how we
+ * guarantee that allocating memory for a new btree node can always
+ * succeed, so that inserting keys into the btree can always succeed and
+ * IO can always make forward progress:
+ */
nr /= c->btree_pages;
nr = min_t(unsigned long, nr, mca_can_free(c));
@@ -766,6 +772,8 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k,
int ret = -ENOMEM;
struct btree *i;
+ trace_bcache_btree_cache_cannibalize(c);
+
if (!cl)
return ERR_PTR(-ENOMEM);
@@ -784,7 +792,6 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k,
return ERR_PTR(-EAGAIN);
}
- /* XXX: tracepoint */
c->try_harder = cl;
c->try_harder_start = local_clock();
retry:
@@ -905,6 +912,9 @@ retry:
b = mca_find(c, k);
if (!b) {
+ if (current->bio_list)
+ return ERR_PTR(-EAGAIN);
+
mutex_lock(&c->bucket_lock);
b = mca_alloc(c, k, level, &op->cl);
mutex_unlock(&c->bucket_lock);
@@ -914,7 +924,7 @@ retry:
if (IS_ERR(b))
return b;
- bch_btree_read(b);
+ bch_btree_node_read(b);
if (!write)
downgrade_write(&b->lock);
@@ -937,15 +947,12 @@ retry:
for (; i <= b->nsets; i++)
prefetch(b->sets[i].data);
- if (!closure_wait_event(&b->io.wait, &op->cl,
- btree_node_read_done(b))) {
- rw_unlock(write, b);
- b = ERR_PTR(-EAGAIN);
- } else if (btree_node_io_error(b)) {
+ if (btree_node_io_error(b)) {
rw_unlock(write, b);
- b = ERR_PTR(-EIO);
- } else
- BUG_ON(!b->written);
+ return ERR_PTR(-EIO);
+ }
+
+ BUG_ON(!b->written);
return b;
}
@@ -959,7 +966,7 @@ static void btree_node_prefetch(struct cache_set *c, struct bkey *k, int level)
mutex_unlock(&c->bucket_lock);
if (!IS_ERR_OR_NULL(b)) {
- bch_btree_read(b);
+ bch_btree_node_read(b);
rw_unlock(true, b);
}
}
@@ -970,24 +977,19 @@ static void btree_node_free(struct btree *b, struct btree_op *op)
{
unsigned i;
+ trace_bcache_btree_node_free(b);
+
/*
* The BUG_ON() in btree_node_get() implies that we must have a write
* lock on parent to free or even invalidate a node
*/
BUG_ON(op->lock <= b->level);
BUG_ON(b == b->c->root);
- pr_debug("bucket %s", pbtree(b));
if (btree_node_dirty(b))
btree_complete_write(b, btree_current_write(b));
clear_bit(BTREE_NODE_dirty, &b->flags);
- if (b->prio_blocked &&
- !atomic_sub_return(b->prio_blocked, &b->c->prio_blocked))
- wake_up(&b->c->alloc_wait);
-
- b->prio_blocked = 0;
-
cancel_delayed_work(&b->work);
mutex_lock(&b->c->bucket_lock);
@@ -1028,17 +1030,20 @@ retry:
goto retry;
}
- set_btree_node_read_done(b);
b->accessed = 1;
bch_bset_init_next(b);
mutex_unlock(&c->bucket_lock);
+
+ trace_bcache_btree_node_alloc(b);
return b;
err_free:
bch_bucket_free(c, &k.key);
__bkey_put(c, &k.key);
err:
mutex_unlock(&c->bucket_lock);
+
+ trace_bcache_btree_node_alloc_fail(b);
return b;
}
@@ -1137,11 +1142,8 @@ static int btree_gc_mark_node(struct btree *b, unsigned *keys,
gc->nkeys++;
gc->data += KEY_SIZE(k);
- if (KEY_DIRTY(k)) {
+ if (KEY_DIRTY(k))
gc->dirty += KEY_SIZE(k);
- if (d)
- d->sectors_dirty_gc += KEY_SIZE(k);
- }
}
for (t = b->sets; t <= &b->sets[b->nsets]; t++)
@@ -1166,14 +1168,11 @@ static struct btree *btree_gc_alloc(struct btree *b, struct bkey *k,
if (!IS_ERR_OR_NULL(n)) {
swap(b, n);
+ __bkey_put(b->c, &b->key);
memcpy(k->ptr, b->key.ptr,
sizeof(uint64_t) * KEY_PTRS(&b->key));
- __bkey_put(b->c, &b->key);
- atomic_inc(&b->c->prio_blocked);
- b->prio_blocked++;
-
btree_node_free(n, op);
up_write(&n->lock);
}
@@ -1278,7 +1277,7 @@ static void btree_gc_coalesce(struct btree *b, struct btree_op *op,
btree_node_free(r->b, op);
up_write(&r->b->lock);
- pr_debug("coalesced %u nodes", nodes);
+ trace_bcache_btree_gc_coalesce(nodes);
gc->nodes--;
nodes--;
@@ -1293,14 +1292,9 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
void write(struct btree *r)
{
if (!r->written)
- bch_btree_write(r, true, op);
- else if (btree_node_dirty(r)) {
- BUG_ON(btree_current_write(r)->owner);
- btree_current_write(r)->owner = writes;
- closure_get(writes);
-
- bch_btree_write(r, true, NULL);
- }
+ bch_btree_node_write(r, &op->cl);
+ else if (btree_node_dirty(r))
+ bch_btree_node_write(r, writes);
up_write(&r->lock);
}
@@ -1386,9 +1380,7 @@ static int bch_btree_gc_root(struct btree *b, struct btree_op *op,
ret = btree_gc_recurse(b, op, writes, gc);
if (!b->written || btree_node_dirty(b)) {
- atomic_inc(&b->c->prio_blocked);
- b->prio_blocked++;
- bch_btree_write(b, true, n ? op : NULL);
+ bch_btree_node_write(b, n ? &op->cl : NULL);
}
if (!IS_ERR_OR_NULL(n)) {
@@ -1405,7 +1397,6 @@ static void btree_gc_start(struct cache_set *c)
{
struct cache *ca;
struct bucket *b;
- struct bcache_device **d;
unsigned i;
if (!c->gc_mark_valid)
@@ -1419,16 +1410,12 @@ static void btree_gc_start(struct cache_set *c)
for_each_cache(ca, c, i)
for_each_bucket(b, ca) {
b->gc_gen = b->gen;
- if (!atomic_read(&b->pin))
+ if (!atomic_read(&b->pin)) {
SET_GC_MARK(b, GC_MARK_RECLAIMABLE);
+ SET_GC_SECTORS_USED(b, 0);
+ }
}
- for (d = c->devices;
- d < c->devices + c->nr_uuids;
- d++)
- if (*d)
- (*d)->sectors_dirty_gc = 0;
-
mutex_unlock(&c->bucket_lock);
}
@@ -1437,7 +1424,6 @@ size_t bch_btree_gc_finish(struct cache_set *c)
size_t available = 0;
struct bucket *b;
struct cache *ca;
- struct bcache_device **d;
unsigned i;
mutex_lock(&c->bucket_lock);
@@ -1480,22 +1466,6 @@ size_t bch_btree_gc_finish(struct cache_set *c)
}
}
- for (d = c->devices;
- d < c->devices + c->nr_uuids;
- d++)
- if (*d) {
- unsigned long last =
- atomic_long_read(&((*d)->sectors_dirty));
- long difference = (*d)->sectors_dirty_gc - last;
-
- pr_debug("sectors dirty off by %li", difference);
-
- (*d)->sectors_dirty_last += difference;
-
- atomic_long_set(&((*d)->sectors_dirty),
- (*d)->sectors_dirty_gc);
- }
-
mutex_unlock(&c->bucket_lock);
return available;
}
@@ -1508,10 +1478,9 @@ static void bch_btree_gc(struct closure *cl)
struct gc_stat stats;
struct closure writes;
struct btree_op op;
-
uint64_t start_time = local_clock();
- trace_bcache_gc_start(c->sb.set_uuid);
- blktrace_msg_all(c, "Starting gc");
+
+ trace_bcache_gc_start(c);
memset(&stats, 0, sizeof(struct gc_stat));
closure_init_stack(&writes);
@@ -1520,14 +1489,14 @@ static void bch_btree_gc(struct closure *cl)
btree_gc_start(c);
+ atomic_inc(&c->prio_blocked);
+
ret = btree_root(gc_root, c, &op, &writes, &stats);
closure_sync(&op.cl);
closure_sync(&writes);
if (ret) {
- blktrace_msg_all(c, "Stopped gc");
pr_warn("gc failed!");
-
continue_at(cl, bch_btree_gc, bch_gc_wq);
}
@@ -1537,6 +1506,9 @@ static void bch_btree_gc(struct closure *cl)
available = bch_btree_gc_finish(c);
+ atomic_dec(&c->prio_blocked);
+ wake_up_allocators(c);
+
bch_time_stats_update(&c->btree_gc_time, start_time);
stats.key_bytes *= sizeof(uint64_t);
@@ -1544,10 +1516,8 @@ static void bch_btree_gc(struct closure *cl)
stats.data <<= 9;
stats.in_use = (c->nbuckets - available) * 100 / c->nbuckets;
memcpy(&c->gc_stats, &stats, sizeof(struct gc_stat));
- blktrace_msg_all(c, "Finished gc");
- trace_bcache_gc_end(c->sb.set_uuid);
- wake_up(&c->alloc_wait);
+ trace_bcache_gc_end(c);
continue_at(cl, bch_moving_gc, bch_gc_wq);
}
@@ -1654,14 +1624,14 @@ static bool fix_overlapping_extents(struct btree *b,
struct btree_iter *iter,
struct btree_op *op)
{
- void subtract_dirty(struct bkey *k, int sectors)
+ void subtract_dirty(struct bkey *k, uint64_t offset, int sectors)
{
- struct bcache_device *d = b->c->devices[KEY_INODE(k)];
-
- if (KEY_DIRTY(k) && d)
- atomic_long_sub(sectors, &d->sectors_dirty);
+ if (KEY_DIRTY(k))
+ bcache_dev_sectors_dirty_add(b->c, KEY_INODE(k),
+ offset, -sectors);
}
+ uint64_t old_offset;
unsigned old_size, sectors_found = 0;
while (1) {
@@ -1673,6 +1643,7 @@ static bool fix_overlapping_extents(struct btree *b,
if (bkey_cmp(k, &START_KEY(insert)) <= 0)
continue;
+ old_offset = KEY_START(k);
old_size = KEY_SIZE(k);
/*
@@ -1728,7 +1699,7 @@ static bool fix_overlapping_extents(struct btree *b,
struct bkey *top;
- subtract_dirty(k, KEY_SIZE(insert));
+ subtract_dirty(k, KEY_START(insert), KEY_SIZE(insert));
if (bkey_written(b, k)) {
/*
@@ -1775,7 +1746,7 @@ static bool fix_overlapping_extents(struct btree *b,
}
}
- subtract_dirty(k, old_size - KEY_SIZE(k));
+ subtract_dirty(k, old_offset, old_size - KEY_SIZE(k));
}
check_failed:
@@ -1798,7 +1769,7 @@ static bool btree_insert_key(struct btree *b, struct btree_op *op,
{
struct bset *i = b->sets[b->nsets].data;
struct bkey *m, *prev;
- const char *status = "insert";
+ unsigned status = BTREE_INSERT_STATUS_INSERT;
BUG_ON(bkey_cmp(k, &b->key) > 0);
BUG_ON(b->level && !KEY_PTRS(k));
@@ -1831,17 +1802,17 @@ static bool btree_insert_key(struct btree *b, struct btree_op *op,
goto insert;
/* prev is in the tree, if we merge we're done */
- status = "back merging";
+ status = BTREE_INSERT_STATUS_BACK_MERGE;
if (prev &&
bch_bkey_try_merge(b, prev, k))
goto merged;
- status = "overwrote front";
+ status = BTREE_INSERT_STATUS_OVERWROTE;
if (m != end(i) &&
KEY_PTRS(m) == KEY_PTRS(k) && !KEY_SIZE(m))
goto copy;
- status = "front merge";
+ status = BTREE_INSERT_STATUS_FRONT_MERGE;
if (m != end(i) &&
bch_bkey_try_merge(b, k, m))
goto copy;
@@ -1851,21 +1822,21 @@ static bool btree_insert_key(struct btree *b, struct btree_op *op,
insert: shift_keys(b, m, k);
copy: bkey_copy(m, k);
merged:
- bch_check_keys(b, "%s for %s at %s: %s", status,
- op_type(op), pbtree(b), pkey(k));
- bch_check_key_order_msg(b, i, "%s for %s at %s: %s", status,
- op_type(op), pbtree(b), pkey(k));
+ if (KEY_DIRTY(k))
+ bcache_dev_sectors_dirty_add(b->c, KEY_INODE(k),
+ KEY_START(k), KEY_SIZE(k));
+
+ bch_check_keys(b, "%u for %s", status, op_type(op));
if (b->level && !KEY_OFFSET(k))
- b->prio_blocked++;
+ btree_current_write(b)->prio_blocked++;
- pr_debug("%s for %s at %s: %s", status,
- op_type(op), pbtree(b), pkey(k));
+ trace_bcache_btree_insert_key(b, k, op->type, status);
return true;
}
-bool bch_btree_insert_keys(struct btree *b, struct btree_op *op)
+static bool bch_btree_insert_keys(struct btree *b, struct btree_op *op)
{
bool ret = false;
struct bkey *k;
@@ -1896,7 +1867,7 @@ bool bch_btree_insert_check_key(struct btree *b, struct btree_op *op,
should_split(b))
goto out;
- op->replace = KEY(op->inode, bio_end(bio), bio_sectors(bio));
+ op->replace = KEY(op->inode, bio_end_sector(bio), bio_sectors(bio));
SET_KEY_PTRS(&op->replace, 1);
get_random_bytes(&op->replace.ptr[0], sizeof(uint64_t));
@@ -1907,7 +1878,6 @@ bool bch_btree_insert_check_key(struct btree *b, struct btree_op *op,
BUG_ON(op->type != BTREE_INSERT);
BUG_ON(!btree_insert_key(b, op, &tmp.k));
- bch_btree_write(b, false, NULL);
ret = true;
out:
downgrade_write(&b->lock);
@@ -1929,12 +1899,11 @@ static int btree_split(struct btree *b, struct btree_op *op)
split = set_blocks(n1->sets[0].data, n1->c) > (btree_blocks(b) * 4) / 5;
- pr_debug("%ssplitting at %s keys %i", split ? "" : "not ",
- pbtree(b), n1->sets[0].data->keys);
-
if (split) {
unsigned keys = 0;
+ trace_bcache_btree_node_split(b, n1->sets[0].data->keys);
+
n2 = bch_btree_node_alloc(b->c, b->level, &op->cl);
if (IS_ERR(n2))
goto err_free1;
@@ -1967,18 +1936,21 @@ static int btree_split(struct btree *b, struct btree_op *op)
bkey_copy_key(&n2->key, &b->key);
bch_keylist_add(&op->keys, &n2->key);
- bch_btree_write(n2, true, op);
+ bch_btree_node_write(n2, &op->cl);
rw_unlock(true, n2);
- } else
+ } else {
+ trace_bcache_btree_node_compact(b, n1->sets[0].data->keys);
+
bch_btree_insert_keys(n1, op);
+ }
bch_keylist_add(&op->keys, &n1->key);
- bch_btree_write(n1, true, op);
+ bch_btree_node_write(n1, &op->cl);
if (n3) {
bkey_copy_key(&n3->key, &MAX_KEY);
bch_btree_insert_keys(n3, op);
- bch_btree_write(n3, true, op);
+ bch_btree_node_write(n3, &op->cl);
closure_sync(&op->cl);
bch_btree_set_root(n3);
@@ -2082,8 +2054,12 @@ static int bch_btree_insert_recurse(struct btree *b, struct btree_op *op,
BUG_ON(write_block(b) != b->sets[b->nsets].data);
- if (bch_btree_insert_keys(b, op))
- bch_btree_write(b, false, op);
+ if (bch_btree_insert_keys(b, op)) {
+ if (!b->level)
+ bch_btree_leaf_dirty(b, op);
+ else
+ bch_btree_node_write(b, &op->cl);
+ }
}
return 0;
@@ -2140,6 +2116,11 @@ int bch_btree_insert(struct btree_op *op, struct cache_set *c)
void bch_btree_set_root(struct btree *b)
{
unsigned i;
+ struct closure cl;
+
+ closure_init_stack(&cl);
+
+ trace_bcache_btree_set_root(b);
BUG_ON(!b->written);
@@ -2153,8 +2134,8 @@ void bch_btree_set_root(struct btree *b)
b->c->root = b;
__bkey_put(b->c, &b->key);
- bch_journal_meta(b->c, NULL);
- pr_debug("%s for %pf", pbtree(b), __builtin_return_address(0));
+ bch_journal_meta(b->c, &cl);
+ closure_sync(&cl);
}
/* Cache lookup */
@@ -2215,9 +2196,6 @@ static int submit_partial_cache_hit(struct btree *b, struct btree_op *op,
KEY_OFFSET(k) - bio->bi_sector);
n = bch_bio_split(bio, sectors, GFP_NOIO, s->d->bio_split);
- if (!n)
- return -EAGAIN;
-
if (n == bio)
op->lookup_done = true;
@@ -2240,7 +2218,6 @@ static int submit_partial_cache_hit(struct btree *b, struct btree_op *op,
n->bi_end_io = bch_cache_read_endio;
n->bi_private = &s->cl;
- trace_bcache_cache_hit(n);
__bch_submit_bbio(n, b->c);
}
@@ -2257,9 +2234,6 @@ int bch_btree_search_recurse(struct btree *b, struct btree_op *op)
struct btree_iter iter;
bch_btree_iter_init(b, &iter, &KEY(op->inode, bio->bi_sector, 0));
- pr_debug("at %s searching for %u:%llu", pbtree(b), op->inode,
- (uint64_t) bio->bi_sector);
-
do {
k = bch_btree_iter_next_filter(&iter, b, bch_ptr_bad);
if (!k) {
@@ -2303,7 +2277,8 @@ static inline int keybuf_nonoverlapping_cmp(struct keybuf_key *l,
}
static int bch_btree_refill_keybuf(struct btree *b, struct btree_op *op,
- struct keybuf *buf, struct bkey *end)
+ struct keybuf *buf, struct bkey *end,
+ keybuf_pred_fn *pred)
{
struct btree_iter iter;
bch_btree_iter_init(b, &iter, &buf->last_scanned);
@@ -2322,11 +2297,9 @@ static int bch_btree_refill_keybuf(struct btree *b, struct btree_op *op,
if (bkey_cmp(&buf->last_scanned, end) >= 0)
break;
- if (buf->key_predicate(buf, k)) {
+ if (pred(buf, k)) {
struct keybuf_key *w;
- pr_debug("%s", pkey(k));
-
spin_lock(&buf->lock);
w = array_alloc(&buf->freelist);
@@ -2343,7 +2316,7 @@ static int bch_btree_refill_keybuf(struct btree *b, struct btree_op *op,
if (!k)
break;
- btree(refill_keybuf, k, b, op, buf, end);
+ btree(refill_keybuf, k, b, op, buf, end, pred);
/*
* Might get an error here, but can't really do anything
* and it'll get logged elsewhere. Just read what we
@@ -2361,7 +2334,7 @@ static int bch_btree_refill_keybuf(struct btree *b, struct btree_op *op,
}
void bch_refill_keybuf(struct cache_set *c, struct keybuf *buf,
- struct bkey *end)
+ struct bkey *end, keybuf_pred_fn *pred)
{
struct bkey start = buf->last_scanned;
struct btree_op op;
@@ -2369,7 +2342,7 @@ void bch_refill_keybuf(struct cache_set *c, struct keybuf *buf,
cond_resched();
- btree_root(refill_keybuf, c, &op, buf, end);
+ btree_root(refill_keybuf, c, &op, buf, end, pred);
closure_sync(&op.cl);
pr_debug("found %s keys from %llu:%llu to %llu:%llu",
@@ -2455,7 +2428,8 @@ struct keybuf_key *bch_keybuf_next(struct keybuf *buf)
struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *c,
struct keybuf *buf,
- struct bkey *end)
+ struct bkey *end,
+ keybuf_pred_fn *pred)
{
struct keybuf_key *ret;
@@ -2469,15 +2443,14 @@ struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *c,
break;
}
- bch_refill_keybuf(c, buf, end);
+ bch_refill_keybuf(c, buf, end, pred);
}
return ret;
}
-void bch_keybuf_init(struct keybuf *buf, keybuf_pred_fn *fn)
+void bch_keybuf_init(struct keybuf *buf)
{
- buf->key_predicate = fn;
buf->last_scanned = MAX_KEY;
buf->keys = RB_ROOT;
diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h
index af4a7092a28..3333d372363 100644
--- a/drivers/md/bcache/btree.h
+++ b/drivers/md/bcache/btree.h
@@ -102,7 +102,6 @@
#include "debug.h"
struct btree_write {
- struct closure *owner;
atomic_t *journal;
/* If btree_split() frees a btree node, it writes a new pointer to that
@@ -142,16 +141,12 @@ struct btree {
*/
struct bset_tree sets[MAX_BSETS];
- /* Used to refcount bio splits, also protects b->bio */
+ /* For outstanding btree writes, used as a lock - protects write_idx */
struct closure_with_waitlist io;
- /* Gets transferred to w->prio_blocked - see the comment there */
- int prio_blocked;
-
struct list_head list;
struct delayed_work work;
- uint64_t io_start_time;
struct btree_write writes[2];
struct bio *bio;
};
@@ -164,13 +159,11 @@ static inline void set_btree_node_ ## flag(struct btree *b) \
{ set_bit(BTREE_NODE_ ## flag, &b->flags); } \
enum btree_flags {
- BTREE_NODE_read_done,
BTREE_NODE_io_error,
BTREE_NODE_dirty,
BTREE_NODE_write_idx,
};
-BTREE_FLAG(read_done);
BTREE_FLAG(io_error);
BTREE_FLAG(dirty);
BTREE_FLAG(write_idx);
@@ -278,6 +271,13 @@ struct btree_op {
BKEY_PADDED(replace);
};
+enum {
+ BTREE_INSERT_STATUS_INSERT,
+ BTREE_INSERT_STATUS_BACK_MERGE,
+ BTREE_INSERT_STATUS_OVERWROTE,
+ BTREE_INSERT_STATUS_FRONT_MERGE,
+};
+
void bch_btree_op_init_stack(struct btree_op *);
static inline void rw_lock(bool w, struct btree *b, int level)
@@ -293,9 +293,7 @@ static inline void rw_unlock(bool w, struct btree *b)
#ifdef CONFIG_BCACHE_EDEBUG
unsigned i;
- if (w &&
- b->key.ptr[0] &&
- btree_node_read_done(b))
+ if (w && b->key.ptr[0])
for (i = 0; i <= b->nsets; i++)
bch_check_key_order(b, b->sets[i].data);
#endif
@@ -370,9 +368,8 @@ static inline bool should_split(struct btree *b)
> btree_blocks(b));
}
-void bch_btree_read_done(struct closure *);
-void bch_btree_read(struct btree *);
-void bch_btree_write(struct btree *b, bool now, struct btree_op *op);
+void bch_btree_node_read(struct btree *);
+void bch_btree_node_write(struct btree *, struct closure *);
void bch_cannibalize_unlock(struct cache_set *, struct closure *);
void bch_btree_set_root(struct btree *);
@@ -380,7 +377,6 @@ struct btree *bch_btree_node_alloc(struct cache_set *, int, struct closure *);
struct btree *bch_btree_node_get(struct cache_set *, struct bkey *,
int, struct btree_op *);
-bool bch_btree_insert_keys(struct btree *, struct btree_op *);
bool bch_btree_insert_check_key(struct btree *, struct btree_op *,
struct bio *);
int bch_btree_insert(struct btree_op *, struct cache_set *);
@@ -393,13 +389,14 @@ void bch_moving_gc(struct closure *);
int bch_btree_check(struct cache_set *, struct btree_op *);
uint8_t __bch_btree_mark_key(struct cache_set *, int, struct bkey *);
-void bch_keybuf_init(struct keybuf *, keybuf_pred_fn *);
-void bch_refill_keybuf(struct cache_set *, struct keybuf *, struct bkey *);
+void bch_keybuf_init(struct keybuf *);
+void bch_refill_keybuf(struct cache_set *, struct keybuf *, struct bkey *,
+ keybuf_pred_fn *);
bool bch_keybuf_check_overlapping(struct keybuf *, struct bkey *,
struct bkey *);
void bch_keybuf_del(struct keybuf *, struct keybuf_key *);
struct keybuf_key *bch_keybuf_next(struct keybuf *);
-struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *,
- struct keybuf *, struct bkey *);
+struct keybuf_key *bch_keybuf_next_rescan(struct cache_set *, struct keybuf *,
+ struct bkey *, keybuf_pred_fn *);
#endif
diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c
index bd05a9a8c7c..9aba2017f0d 100644
--- a/drivers/md/bcache/closure.c
+++ b/drivers/md/bcache/closure.c
@@ -66,16 +66,18 @@ static inline void closure_put_after_sub(struct closure *cl, int flags)
} else {
struct closure *parent = cl->parent;
struct closure_waitlist *wait = closure_waitlist(cl);
+ closure_fn *destructor = cl->fn;
closure_debug_destroy(cl);
+ smp_mb();
atomic_set(&cl->remaining, -1);
if (wait)
closure_wake_up(wait);
- if (cl->fn)
- cl->fn(cl);
+ if (destructor)
+ destructor(cl);
if (parent)
closure_put(parent);
diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c
index 89fd5204924..88e6411eab4 100644
--- a/drivers/md/bcache/debug.c
+++ b/drivers/md/bcache/debug.c
@@ -47,11 +47,10 @@ const char *bch_ptr_status(struct cache_set *c, const struct bkey *k)
return "";
}
-struct keyprint_hack bch_pkey(const struct bkey *k)
+int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k)
{
unsigned i = 0;
- struct keyprint_hack r;
- char *out = r.s, *end = r.s + KEYHACK_SIZE;
+ char *out = buf, *end = buf + size;
#define p(...) (out += scnprintf(out, end - out, __VA_ARGS__))
@@ -75,16 +74,14 @@ struct keyprint_hack bch_pkey(const struct bkey *k)
if (KEY_CSUM(k))
p(" cs%llu %llx", KEY_CSUM(k), k->ptr[1]);
#undef p
- return r;
+ return out - buf;
}
-struct keyprint_hack bch_pbtree(const struct btree *b)
+int bch_btree_to_text(char *buf, size_t size, const struct btree *b)
{
- struct keyprint_hack r;
-
- snprintf(r.s, 40, "%zu level %i/%i", PTR_BUCKET_NR(b->c, &b->key, 0),
- b->level, b->c->root ? b->c->root->level : -1);
- return r;
+ return scnprintf(buf, size, "%zu level %i/%i",
+ PTR_BUCKET_NR(b->c, &b->key, 0),
+ b->level, b->c->root ? b->c->root->level : -1);
}
#if defined(CONFIG_BCACHE_DEBUG) || defined(CONFIG_BCACHE_EDEBUG)
@@ -100,10 +97,12 @@ static void dump_bset(struct btree *b, struct bset *i)
{
struct bkey *k;
unsigned j;
+ char buf[80];
for (k = i->start; k < end(i); k = bkey_next(k)) {
+ bch_bkey_to_text(buf, sizeof(buf), k);
printk(KERN_ERR "block %zu key %zi/%u: %s", index(i, b),
- (uint64_t *) k - i->d, i->keys, pkey(k));
+ (uint64_t *) k - i->d, i->keys, buf);
for (j = 0; j < KEY_PTRS(k); j++) {
size_t n = PTR_BUCKET_NR(b->c, k, j);
@@ -144,7 +143,7 @@ void bch_btree_verify(struct btree *b, struct bset *new)
v->written = 0;
v->level = b->level;
- bch_btree_read(v);
+ bch_btree_node_read(v);
closure_wait_event(&v->io.wait, &cl,
atomic_read(&b->io.cl.remaining) == -1);
@@ -200,7 +199,7 @@ void bch_data_verify(struct search *s)
if (!check)
return;
- if (bch_bio_alloc_pages(check, GFP_NOIO))
+ if (bio_alloc_pages(check, GFP_NOIO))
goto out_put;
check->bi_rw = READ_SYNC;
@@ -252,6 +251,7 @@ static void vdump_bucket_and_panic(struct btree *b, const char *fmt,
va_list args)
{
unsigned i;
+ char buf[80];
console_lock();
@@ -262,7 +262,8 @@ static void vdump_bucket_and_panic(struct btree *b, const char *fmt,
console_unlock();
- panic("at %s\n", pbtree(b));
+ bch_btree_to_text(buf, sizeof(buf), b);
+ panic("at %s\n", buf);
}
void bch_check_key_order_msg(struct btree *b, struct bset *i,
@@ -337,6 +338,7 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf,
{
struct dump_iterator *i = file->private_data;
ssize_t ret = 0;
+ char kbuf[80];
while (size) {
struct keybuf_key *w;
@@ -355,11 +357,12 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf,
if (i->bytes)
break;
- w = bch_keybuf_next_rescan(i->c, &i->keys, &MAX_KEY);
+ w = bch_keybuf_next_rescan(i->c, &i->keys, &MAX_KEY, dump_pred);
if (!w)
break;
- i->bytes = snprintf(i->buf, PAGE_SIZE, "%s\n", pkey(&w->key));
+ bch_bkey_to_text(kbuf, sizeof(kbuf), &w->key);
+ i->bytes = snprintf(i->buf, PAGE_SIZE, "%s\n", kbuf);
bch_keybuf_del(&i->keys, w);
}
@@ -377,7 +380,7 @@ static int bch_dump_open(struct inode *inode, struct file *file)
file->private_data = i;
i->c = c;
- bch_keybuf_init(&i->keys, dump_pred);
+ bch_keybuf_init(&i->keys);
i->keys.last_scanned = KEY(0, 0, 0);
return 0;
@@ -409,142 +412,6 @@ void bch_debug_init_cache_set(struct cache_set *c)
#endif
-/* Fuzz tester has rotted: */
-#if 0
-
-static ssize_t btree_fuzz(struct kobject *k, struct kobj_attribute *a,
- const char *buffer, size_t size)
-{
- void dump(struct btree *b)
- {
- struct bset *i;
-
- for (i = b->sets[0].data;
- index(i, b) < btree_blocks(b) &&
- i->seq == b->sets[0].data->seq;
- i = ((void *) i) + set_blocks(i, b->c) * block_bytes(b->c))
- dump_bset(b, i);
- }
-
- struct cache_sb *sb;
- struct cache_set *c;
- struct btree *all[3], *b, *fill, *orig;
- int j;
-
- struct btree_op op;
- bch_btree_op_init_stack(&op);
-
- sb = kzalloc(sizeof(struct cache_sb), GFP_KERNEL);
- if (!sb)
- return -ENOMEM;
-
- sb->bucket_size = 128;
- sb->block_size = 4;
-
- c = bch_cache_set_alloc(sb);
- if (!c)
- return -ENOMEM;
-
- for (j = 0; j < 3; j++) {
- BUG_ON(list_empty(&c->btree_cache));
- all[j] = list_first_entry(&c->btree_cache, struct btree, list);
- list_del_init(&all[j]->list);
-
- all[j]->key = KEY(0, 0, c->sb.bucket_size);
- bkey_copy_key(&all[j]->key, &MAX_KEY);
- }
-
- b = all[0];
- fill = all[1];
- orig = all[2];
-
- while (1) {
- for (j = 0; j < 3; j++)
- all[j]->written = all[j]->nsets = 0;
-
- bch_bset_init_next(b);
-
- while (1) {
- struct bset *i = write_block(b);
- struct bkey *k = op.keys.top;
- unsigned rand;
-
- bkey_init(k);
- rand = get_random_int();
-
- op.type = rand & 1
- ? BTREE_INSERT
- : BTREE_REPLACE;
- rand >>= 1;
-
- SET_KEY_SIZE(k, bucket_remainder(c, rand));
- rand >>= c->bucket_bits;
- rand &= 1024 * 512 - 1;
- rand += c->sb.bucket_size;
- SET_KEY_OFFSET(k, rand);
-#if 0
- SET_KEY_PTRS(k, 1);
-#endif
- bch_keylist_push(&op.keys);
- bch_btree_insert_keys(b, &op);
-
- if (should_split(b) ||
- set_blocks(i, b->c) !=
- __set_blocks(i, i->keys + 15, b->c)) {
- i->csum = csum_set(i);
-
- memcpy(write_block(fill),
- i, set_bytes(i));
-
- b->written += set_blocks(i, b->c);
- fill->written = b->written;
- if (b->written == btree_blocks(b))
- break;
-
- bch_btree_sort_lazy(b);
- bch_bset_init_next(b);
- }
- }
-
- memcpy(orig->sets[0].data,
- fill->sets[0].data,
- btree_bytes(c));
-
- bch_btree_sort(b);
- fill->written = 0;
- bch_btree_read_done(&fill->io.cl);
-
- if (b->sets[0].data->keys != fill->sets[0].data->keys ||
- memcmp(b->sets[0].data->start,
- fill->sets[0].data->start,
- b->sets[0].data->keys * sizeof(uint64_t))) {
- struct bset *i = b->sets[0].data;
- struct bkey *k, *l;
-
- for (k = i->start,
- l = fill->sets[0].data->start;
- k < end(i);
- k = bkey_next(k), l = bkey_next(l))
- if (bkey_cmp(k, l) ||
- KEY_SIZE(k) != KEY_SIZE(l))
- pr_err("key %zi differs: %s != %s",
- (uint64_t *) k - i->d,
- pkey(k), pkey(l));
-
- for (j = 0; j < 3; j++) {
- pr_err("**** Set %i ****", j);
- dump(all[j]);
- }
- panic("\n");
- }
-
- pr_info("fuzz complete: %i keys", b->sets[0].data->keys);
- }
-}
-
-kobj_attribute_write(fuzz, btree_fuzz);
-#endif
-
void bch_debug_exit(void)
{
if (!IS_ERR_OR_NULL(debug))
@@ -554,11 +421,6 @@ void bch_debug_exit(void)
int __init bch_debug_init(struct kobject *kobj)
{
int ret = 0;
-#if 0
- ret = sysfs_create_file(kobj, &ksysfs_fuzz.attr);
- if (ret)
- return ret;
-#endif
debug = debugfs_create_dir("bcache", NULL);
return ret;
diff --git a/drivers/md/bcache/debug.h b/drivers/md/bcache/debug.h
index f9378a21814..1c39b5a2489 100644
--- a/drivers/md/bcache/debug.h
+++ b/drivers/md/bcache/debug.h
@@ -3,15 +3,8 @@
/* Btree/bkey debug printing */
-#define KEYHACK_SIZE 80
-struct keyprint_hack {
- char s[KEYHACK_SIZE];
-};
-
-struct keyprint_hack bch_pkey(const struct bkey *k);
-struct keyprint_hack bch_pbtree(const struct btree *b);
-#define pkey(k) (&bch_pkey(k).s[0])
-#define pbtree(b) (&bch_pbtree(b).s[0])
+int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k);
+int bch_btree_to_text(char *buf, size_t size, const struct btree *b);
#ifdef CONFIG_BCACHE_EDEBUG
diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c
index 48efd4dea64..9056632995b 100644
--- a/drivers/md/bcache/io.c
+++ b/drivers/md/bcache/io.c
@@ -9,6 +9,8 @@
#include "bset.h"
#include "debug.h"
+#include <linux/blkdev.h>
+
static void bch_bi_idx_hack_endio(struct bio *bio, int error)
{
struct bio *p = bio->bi_private;
@@ -66,13 +68,6 @@ static void bch_generic_make_request_hack(struct bio *bio)
* The newly allocated bio will point to @bio's bi_io_vec, if the split was on a
* bvec boundry; it is the caller's responsibility to ensure that @bio is not
* freed before the split.
- *
- * If bch_bio_split() is running under generic_make_request(), it's not safe to
- * allocate more than one bio from the same bio set. Therefore, if it is running
- * under generic_make_request() it masks out __GFP_WAIT when doing the
- * allocation. The caller must check for failure if there's any possibility of
- * it being called from under generic_make_request(); it is then the caller's
- * responsibility to retry from a safe context (by e.g. punting to workqueue).
*/
struct bio *bch_bio_split(struct bio *bio, int sectors,
gfp_t gfp, struct bio_set *bs)
@@ -83,20 +78,13 @@ struct bio *bch_bio_split(struct bio *bio, int sectors,
BUG_ON(sectors <= 0);
- /*
- * If we're being called from underneath generic_make_request() and we
- * already allocated any bios from this bio set, we risk deadlock if we
- * use the mempool. So instead, we possibly fail and let the caller punt
- * to workqueue or somesuch and retry in a safe context.
- */
- if (current->bio_list)
- gfp &= ~__GFP_WAIT;
-
if (sectors >= bio_sectors(bio))
return bio;
if (bio->bi_rw & REQ_DISCARD) {
ret = bio_alloc_bioset(gfp, 1, bs);
+ if (!ret)
+ return NULL;
idx = 0;
goto out;
}
@@ -160,17 +148,18 @@ static unsigned bch_bio_max_sectors(struct bio *bio)
struct request_queue *q = bdev_get_queue(bio->bi_bdev);
unsigned max_segments = min_t(unsigned, BIO_MAX_PAGES,
queue_max_segments(q));
- struct bio_vec *bv, *end = bio_iovec(bio) +
- min_t(int, bio_segments(bio), max_segments);
if (bio->bi_rw & REQ_DISCARD)
return min(ret, q->limits.max_discard_sectors);
if (bio_segments(bio) > max_segments ||
q->merge_bvec_fn) {
+ struct bio_vec *bv;
+ int i, seg = 0;
+
ret = 0;
- for (bv = bio_iovec(bio); bv < end; bv++) {
+ bio_for_each_segment(bv, bio, i) {
struct bvec_merge_data bvm = {
.bi_bdev = bio->bi_bdev,
.bi_sector = bio->bi_sector,
@@ -178,10 +167,14 @@ static unsigned bch_bio_max_sectors(struct bio *bio)
.bi_rw = bio->bi_rw,
};
+ if (seg == max_segments)
+ break;
+
if (q->merge_bvec_fn &&
q->merge_bvec_fn(q, &bvm, bv) < (int) bv->bv_len)
break;
+ seg++;
ret += bv->bv_len >> 9;
}
}
@@ -218,30 +211,10 @@ static void bch_bio_submit_split_endio(struct bio *bio, int error)
closure_put(cl);
}
-static void __bch_bio_submit_split(struct closure *cl)
-{
- struct bio_split_hook *s = container_of(cl, struct bio_split_hook, cl);
- struct bio *bio = s->bio, *n;
-
- do {
- n = bch_bio_split(bio, bch_bio_max_sectors(bio),
- GFP_NOIO, s->p->bio_split);
- if (!n)
- continue_at(cl, __bch_bio_submit_split, system_wq);
-
- n->bi_end_io = bch_bio_submit_split_endio;
- n->bi_private = cl;
-
- closure_get(cl);
- bch_generic_make_request_hack(n);
- } while (n != bio);
-
- continue_at(cl, bch_bio_submit_split_done, NULL);
-}
-
void bch_generic_make_request(struct bio *bio, struct bio_split_pool *p)
{
struct bio_split_hook *s;
+ struct bio *n;
if (!bio_has_data(bio) && !(bio->bi_rw & REQ_DISCARD))
goto submit;
@@ -250,6 +223,7 @@ void bch_generic_make_request(struct bio *bio, struct bio_split_pool *p)
goto submit;
s = mempool_alloc(p->bio_split_hook, GFP_NOIO);
+ closure_init(&s->cl, NULL);
s->bio = bio;
s->p = p;
@@ -257,8 +231,18 @@ void bch_generic_make_request(struct bio *bio, struct bio_split_pool *p)
s->bi_private = bio->bi_private;
bio_get(bio);
- closure_call(&s->cl, __bch_bio_submit_split, NULL, NULL);
- return;
+ do {
+ n = bch_bio_split(bio, bch_bio_max_sectors(bio),
+ GFP_NOIO, s->p->bio_split);
+
+ n->bi_end_io = bch_bio_submit_split_endio;
+ n->bi_private = &s->cl;
+
+ closure_get(&s->cl);
+ bch_generic_make_request_hack(n);
+ } while (n != bio);
+
+ continue_at(&s->cl, bch_bio_submit_split_done, NULL);
submit:
bch_generic_make_request_hack(bio);
}
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index 8c8dfdcd9d4..ba95ab84b2b 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -9,6 +9,8 @@
#include "debug.h"
#include "request.h"
+#include <trace/events/bcache.h>
+
/*
* Journal replay/recovery:
*
@@ -182,9 +184,14 @@ bsearch:
pr_debug("starting binary search, l %u r %u", l, r);
while (l + 1 < r) {
+ seq = list_entry(list->prev, struct journal_replay,
+ list)->j.seq;
+
m = (l + r) >> 1;
+ read_bucket(m);
- if (read_bucket(m))
+ if (seq != list_entry(list->prev, struct journal_replay,
+ list)->j.seq)
l = m;
else
r = m;
@@ -300,7 +307,8 @@ int bch_journal_replay(struct cache_set *s, struct list_head *list,
for (k = i->j.start;
k < end(&i->j);
k = bkey_next(k)) {
- pr_debug("%s", pkey(k));
+ trace_bcache_journal_replay_key(k);
+
bkey_copy(op->keys.top, k);
bch_keylist_push(&op->keys);
@@ -384,7 +392,7 @@ out:
return;
found:
if (btree_node_dirty(best))
- bch_btree_write(best, true, NULL);
+ bch_btree_node_write(best, NULL);
rw_unlock(true, best);
}
@@ -617,7 +625,7 @@ static void journal_write_unlocked(struct closure *cl)
bio_reset(bio);
bio->bi_sector = PTR_OFFSET(k, i);
bio->bi_bdev = ca->bdev;
- bio->bi_rw = REQ_WRITE|REQ_SYNC|REQ_META|REQ_FLUSH;
+ bio->bi_rw = REQ_WRITE|REQ_SYNC|REQ_META|REQ_FLUSH|REQ_FUA;
bio->bi_size = sectors << 9;
bio->bi_end_io = journal_write_endio;
@@ -712,7 +720,8 @@ void bch_journal(struct closure *cl)
spin_lock(&c->journal.lock);
if (journal_full(&c->journal)) {
- /* XXX: tracepoint */
+ trace_bcache_journal_full(c);
+
closure_wait(&c->journal.wait, cl);
journal_reclaim(c);
@@ -728,13 +737,15 @@ void bch_journal(struct closure *cl)
if (b * c->sb.block_size > PAGE_SECTORS << JSET_BITS ||
b > c->journal.blocks_free) {
- /* XXX: If we were inserting so many keys that they won't fit in
+ trace_bcache_journal_entry_full(c);
+
+ /*
+ * XXX: If we were inserting so many keys that they won't fit in
* an _empty_ journal write, we'll deadlock. For now, handle
* this in bch_keylist_realloc() - but something to think about.
*/
BUG_ON(!w->data->keys);
- /* XXX: tracepoint */
BUG_ON(!closure_wait(&w->wait, cl));
closure_flush(&c->journal.io);
diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c
index 8589512c972..1a3b4f4786c 100644
--- a/drivers/md/bcache/movinggc.c
+++ b/drivers/md/bcache/movinggc.c
@@ -9,6 +9,8 @@
#include "debug.h"
#include "request.h"
+#include <trace/events/bcache.h>
+
struct moving_io {
struct keybuf_key *w;
struct search s;
@@ -44,14 +46,14 @@ static void write_moving_finish(struct closure *cl)
{
struct moving_io *io = container_of(cl, struct moving_io, s.cl);
struct bio *bio = &io->bio.bio;
- struct bio_vec *bv = bio_iovec_idx(bio, bio->bi_vcnt);
+ struct bio_vec *bv;
+ int i;
- while (bv-- != bio->bi_io_vec)
+ bio_for_each_segment_all(bv, bio, i)
__free_page(bv->bv_page);
- pr_debug("%s %s", io->s.op.insert_collision
- ? "collision moving" : "moved",
- pkey(&io->w->key));
+ if (io->s.op.insert_collision)
+ trace_bcache_gc_copy_collision(&io->w->key);
bch_keybuf_del(&io->s.op.c->moving_gc_keys, io->w);
@@ -94,8 +96,6 @@ static void write_moving(struct closure *cl)
struct moving_io *io = container_of(s, struct moving_io, s);
if (!s->error) {
- trace_bcache_write_moving(&io->bio.bio);
-
moving_init(io);
io->bio.bio.bi_sector = KEY_START(&io->w->key);
@@ -122,7 +122,6 @@ static void read_moving_submit(struct closure *cl)
struct moving_io *io = container_of(s, struct moving_io, s);
struct bio *bio = &io->bio.bio;
- trace_bcache_read_moving(bio);
bch_submit_bbio(bio, s->op.c, &io->w->key, 0);
continue_at(cl, write_moving, bch_gc_wq);
@@ -138,7 +137,8 @@ static void read_moving(struct closure *cl)
/* XXX: if we error, background writeback could stall indefinitely */
while (!test_bit(CACHE_SET_STOPPING, &c->flags)) {
- w = bch_keybuf_next_rescan(c, &c->moving_gc_keys, &MAX_KEY);
+ w = bch_keybuf_next_rescan(c, &c->moving_gc_keys,
+ &MAX_KEY, moving_pred);
if (!w)
break;
@@ -159,10 +159,10 @@ static void read_moving(struct closure *cl)
bio->bi_rw = READ;
bio->bi_end_io = read_moving_endio;
- if (bch_bio_alloc_pages(bio, GFP_KERNEL))
+ if (bio_alloc_pages(bio, GFP_KERNEL))
goto err;
- pr_debug("%s", pkey(&w->key));
+ trace_bcache_gc_copy(&w->key);
closure_call(&io->s.cl, read_moving_submit, NULL, &c->gc.cl);
@@ -250,5 +250,5 @@ void bch_moving_gc(struct closure *cl)
void bch_moving_init_cache_set(struct cache_set *c)
{
- bch_keybuf_init(&c->moving_gc_keys, moving_pred);
+ bch_keybuf_init(&c->moving_gc_keys);
}
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index e5ff12e52d5..786a1a4f74d 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -10,6 +10,7 @@
#include "btree.h"
#include "debug.h"
#include "request.h"
+#include "writeback.h"
#include <linux/cgroup.h>
#include <linux/module.h>
@@ -21,8 +22,6 @@
#define CUTOFF_CACHE_ADD 95
#define CUTOFF_CACHE_READA 90
-#define CUTOFF_WRITEBACK 50
-#define CUTOFF_WRITEBACK_SYNC 75
struct kmem_cache *bch_search_cache;
@@ -489,6 +488,12 @@ static void bch_insert_data_loop(struct closure *cl)
bch_queue_gc(op->c);
}
+ /*
+ * Journal writes are marked REQ_FLUSH; if the original write was a
+ * flush, it'll wait on the journal write.
+ */
+ bio->bi_rw &= ~(REQ_FLUSH|REQ_FUA);
+
do {
unsigned i;
struct bkey *k;
@@ -510,10 +515,6 @@ static void bch_insert_data_loop(struct closure *cl)
goto err;
n = bch_bio_split(bio, KEY_SIZE(k), GFP_NOIO, split);
- if (!n) {
- __bkey_put(op->c, k);
- continue_at(cl, bch_insert_data_loop, bcache_wq);
- }
n->bi_end_io = bch_insert_data_endio;
n->bi_private = cl;
@@ -530,10 +531,9 @@ static void bch_insert_data_loop(struct closure *cl)
if (KEY_CSUM(k))
bio_csum(n, k);
- pr_debug("%s", pkey(k));
+ trace_bcache_cache_insert(k);
bch_keylist_push(&op->keys);
- trace_bcache_cache_insert(n, n->bi_sector, n->bi_bdev);
n->bi_rw |= REQ_WRITE;
bch_submit_bbio(n, op->c, k, 0);
} while (n != bio);
@@ -716,7 +716,7 @@ static struct search *search_alloc(struct bio *bio, struct bcache_device *d)
s->task = current;
s->orig_bio = bio;
s->write = (bio->bi_rw & REQ_WRITE) != 0;
- s->op.flush_journal = (bio->bi_rw & REQ_FLUSH) != 0;
+ s->op.flush_journal = (bio->bi_rw & (REQ_FLUSH|REQ_FUA)) != 0;
s->op.skip = (bio->bi_rw & REQ_DISCARD) != 0;
s->recoverable = 1;
s->start_time = jiffies;
@@ -784,11 +784,8 @@ static void request_read_error(struct closure *cl)
int i;
if (s->recoverable) {
- /* The cache read failed, but we can retry from the backing
- * device.
- */
- pr_debug("recovering at sector %llu",
- (uint64_t) s->orig_bio->bi_sector);
+ /* Retry from the backing device: */
+ trace_bcache_read_retry(s->orig_bio);
s->error = 0;
bv = s->bio.bio.bi_io_vec;
@@ -806,7 +803,6 @@ static void request_read_error(struct closure *cl)
/* XXX: invalidate cache */
- trace_bcache_read_retry(&s->bio.bio);
closure_bio_submit(&s->bio.bio, &s->cl, s->d);
}
@@ -827,53 +823,13 @@ static void request_read_done(struct closure *cl)
*/
if (s->op.cache_bio) {
- struct bio_vec *src, *dst;
- unsigned src_offset, dst_offset, bytes;
- void *dst_ptr;
-
bio_reset(s->op.cache_bio);
s->op.cache_bio->bi_sector = s->cache_miss->bi_sector;
s->op.cache_bio->bi_bdev = s->cache_miss->bi_bdev;
s->op.cache_bio->bi_size = s->cache_bio_sectors << 9;
bch_bio_map(s->op.cache_bio, NULL);
- src = bio_iovec(s->op.cache_bio);
- dst = bio_iovec(s->cache_miss);
- src_offset = src->bv_offset;
- dst_offset = dst->bv_offset;
- dst_ptr = kmap(dst->bv_page);
-
- while (1) {
- if (dst_offset == dst->bv_offset + dst->bv_len) {
- kunmap(dst->bv_page);
- dst++;
- if (dst == bio_iovec_idx(s->cache_miss,
- s->cache_miss->bi_vcnt))
- break;
-
- dst_offset = dst->bv_offset;
- dst_ptr = kmap(dst->bv_page);
- }
-
- if (src_offset == src->bv_offset + src->bv_len) {
- src++;
- if (src == bio_iovec_idx(s->op.cache_bio,
- s->op.cache_bio->bi_vcnt))
- BUG();
-
- src_offset = src->bv_offset;
- }
-
- bytes = min(dst->bv_offset + dst->bv_len - dst_offset,
- src->bv_offset + src->bv_len - src_offset);
-
- memcpy(dst_ptr + dst_offset,
- page_address(src->bv_page) + src_offset,
- bytes);
-
- src_offset += bytes;
- dst_offset += bytes;
- }
+ bio_copy_data(s->cache_miss, s->op.cache_bio);
bio_put(s->cache_miss);
s->cache_miss = NULL;
@@ -899,6 +855,7 @@ static void request_read_done_bh(struct closure *cl)
struct cached_dev *dc = container_of(s->d, struct cached_dev, disk);
bch_mark_cache_accounting(s, !s->cache_miss, s->op.skip);
+ trace_bcache_read(s->orig_bio, !s->cache_miss, s->op.skip);
if (s->error)
continue_at_nobarrier(cl, request_read_error, bcache_wq);
@@ -917,9 +874,6 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
struct bio *miss;
miss = bch_bio_split(bio, sectors, GFP_NOIO, s->d->bio_split);
- if (!miss)
- return -EAGAIN;
-
if (miss == bio)
s->op.lookup_done = true;
@@ -938,8 +892,9 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
reada = min(dc->readahead >> 9,
sectors - bio_sectors(miss));
- if (bio_end(miss) + reada > bdev_sectors(miss->bi_bdev))
- reada = bdev_sectors(miss->bi_bdev) - bio_end(miss);
+ if (bio_end_sector(miss) + reada > bdev_sectors(miss->bi_bdev))
+ reada = bdev_sectors(miss->bi_bdev) -
+ bio_end_sector(miss);
}
s->cache_bio_sectors = bio_sectors(miss) + reada;
@@ -963,13 +918,12 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
goto out_put;
bch_bio_map(s->op.cache_bio, NULL);
- if (bch_bio_alloc_pages(s->op.cache_bio, __GFP_NOWARN|GFP_NOIO))
+ if (bio_alloc_pages(s->op.cache_bio, __GFP_NOWARN|GFP_NOIO))
goto out_put;
s->cache_miss = miss;
bio_get(s->op.cache_bio);
- trace_bcache_cache_miss(s->orig_bio);
closure_bio_submit(s->op.cache_bio, &s->cl, s->d);
return ret;
@@ -1002,24 +956,13 @@ static void cached_dev_write_complete(struct closure *cl)
cached_dev_bio_complete(cl);
}
-static bool should_writeback(struct cached_dev *dc, struct bio *bio)
-{
- unsigned threshold = (bio->bi_rw & REQ_SYNC)
- ? CUTOFF_WRITEBACK_SYNC
- : CUTOFF_WRITEBACK;
-
- return !atomic_read(&dc->disk.detaching) &&
- cache_mode(dc, bio) == CACHE_MODE_WRITEBACK &&
- dc->disk.c->gc_stats.in_use < threshold;
-}
-
static void request_write(struct cached_dev *dc, struct search *s)
{
struct closure *cl = &s->cl;
struct bio *bio = &s->bio.bio;
struct bkey start, end;
start = KEY(dc->disk.id, bio->bi_sector, 0);
- end = KEY(dc->disk.id, bio_end(bio), 0);
+ end = KEY(dc->disk.id, bio_end_sector(bio), 0);
bch_keybuf_check_overlapping(&s->op.c->moving_gc_keys, &start, &end);
@@ -1034,22 +977,37 @@ static void request_write(struct cached_dev *dc, struct search *s)
if (bio->bi_rw & REQ_DISCARD)
goto skip;
+ if (should_writeback(dc, s->orig_bio,
+ cache_mode(dc, bio),
+ s->op.skip)) {
+ s->op.skip = false;
+ s->writeback = true;
+ }
+
if (s->op.skip)
goto skip;
- if (should_writeback(dc, s->orig_bio))
- s->writeback = true;
+ trace_bcache_write(s->orig_bio, s->writeback, s->op.skip);
if (!s->writeback) {
s->op.cache_bio = bio_clone_bioset(bio, GFP_NOIO,
dc->disk.bio_split);
- trace_bcache_writethrough(s->orig_bio);
closure_bio_submit(bio, cl, s->d);
} else {
- s->op.cache_bio = bio;
- trace_bcache_writeback(s->orig_bio);
- bch_writeback_add(dc, bio_sectors(bio));
+ bch_writeback_add(dc);
+
+ if (s->op.flush_journal) {
+ /* Also need to send a flush to the backing device */
+ s->op.cache_bio = bio_clone_bioset(bio, GFP_NOIO,
+ dc->disk.bio_split);
+
+ bio->bi_size = 0;
+ bio->bi_vcnt = 0;
+ closure_bio_submit(bio, cl, s->d);
+ } else {
+ s->op.cache_bio = bio;
+ }
}
out:
closure_call(&s->op.cl, bch_insert_data, NULL, cl);
@@ -1058,7 +1016,6 @@ skip:
s->op.skip = true;
s->op.cache_bio = s->orig_bio;
bio_get(s->op.cache_bio);
- trace_bcache_write_skip(s->orig_bio);
if ((bio->bi_rw & REQ_DISCARD) &&
!blk_queue_discard(bdev_get_queue(dc->bdev)))
@@ -1088,9 +1045,10 @@ static void request_nodata(struct cached_dev *dc, struct search *s)
/* Cached devices - read & write stuff */
-int bch_get_congested(struct cache_set *c)
+unsigned bch_get_congested(struct cache_set *c)
{
int i;
+ long rand;
if (!c->congested_read_threshold_us &&
!c->congested_write_threshold_us)
@@ -1106,7 +1064,13 @@ int bch_get_congested(struct cache_set *c)
i += CONGESTED_MAX;
- return i <= 0 ? 1 : fract_exp_two(i, 6);
+ if (i > 0)
+ i = fract_exp_two(i, 6);
+
+ rand = get_random_int();
+ i -= bitmap_weight(&rand, BITS_PER_LONG);
+
+ return i > 0 ? i : 1;
}
static void add_sequential(struct task_struct *t)
@@ -1126,10 +1090,8 @@ static void check_should_skip(struct cached_dev *dc, struct search *s)
{
struct cache_set *c = s->op.c;
struct bio *bio = &s->bio.bio;
-
- long rand;
- int cutoff = bch_get_congested(c);
unsigned mode = cache_mode(dc, bio);
+ unsigned sectors, congested = bch_get_congested(c);
if (atomic_read(&dc->disk.detaching) ||
c->gc_stats.in_use > CUTOFF_CACHE_ADD ||
@@ -1147,17 +1109,14 @@ static void check_should_skip(struct cached_dev *dc, struct search *s)
goto skip;
}
- if (!cutoff) {
- cutoff = dc->sequential_cutoff >> 9;
+ if (!congested && !dc->sequential_cutoff)
+ goto rescale;
- if (!cutoff)
- goto rescale;
-
- if (mode == CACHE_MODE_WRITEBACK &&
- (bio->bi_rw & REQ_WRITE) &&
- (bio->bi_rw & REQ_SYNC))
- goto rescale;
- }
+ if (!congested &&
+ mode == CACHE_MODE_WRITEBACK &&
+ (bio->bi_rw & REQ_WRITE) &&
+ (bio->bi_rw & REQ_SYNC))
+ goto rescale;
if (dc->sequential_merge) {
struct io *i;
@@ -1177,7 +1136,7 @@ found:
if (i->sequential + bio->bi_size > i->sequential)
i->sequential += bio->bi_size;
- i->last = bio_end(bio);
+ i->last = bio_end_sector(bio);
i->jiffies = jiffies + msecs_to_jiffies(5000);
s->task->sequential_io = i->sequential;
@@ -1192,12 +1151,19 @@ found:
add_sequential(s->task);
}
- rand = get_random_int();
- cutoff -= bitmap_weight(&rand, BITS_PER_LONG);
+ sectors = max(s->task->sequential_io,
+ s->task->sequential_io_avg) >> 9;
- if (cutoff <= (int) (max(s->task->sequential_io,
- s->task->sequential_io_avg) >> 9))
+ if (dc->sequential_cutoff &&
+ sectors >= dc->sequential_cutoff >> 9) {
+ trace_bcache_bypass_sequential(s->orig_bio);
goto skip;
+ }
+
+ if (congested && sectors >= congested) {
+ trace_bcache_bypass_congested(s->orig_bio);
+ goto skip;
+ }
rescale:
bch_rescale_priorities(c, bio_sectors(bio));
@@ -1288,30 +1254,25 @@ void bch_cached_dev_request_init(struct cached_dev *dc)
static int flash_dev_cache_miss(struct btree *b, struct search *s,
struct bio *bio, unsigned sectors)
{
+ struct bio_vec *bv;
+ int i;
+
/* Zero fill bio */
- while (bio->bi_idx != bio->bi_vcnt) {
- struct bio_vec *bv = bio_iovec(bio);
+ bio_for_each_segment(bv, bio, i) {
unsigned j = min(bv->bv_len >> 9, sectors);
void *p = kmap(bv->bv_page);
memset(p + bv->bv_offset, 0, j << 9);
kunmap(bv->bv_page);
- bv->bv_len -= j << 9;
- bv->bv_offset += j << 9;
-
- if (bv->bv_len)
- return 0;
-
- bio->bi_sector += j;
- bio->bi_size -= j << 9;
-
- bio->bi_idx++;
- sectors -= j;
+ sectors -= j;
}
- s->op.lookup_done = true;
+ bio_advance(bio, min(sectors << 9, bio->bi_size));
+
+ if (!bio->bi_size)
+ s->op.lookup_done = true;
return 0;
}
@@ -1338,8 +1299,8 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio)
closure_call(&s->op.cl, btree_read_async, NULL, cl);
} else if (bio_has_data(bio) || s->op.skip) {
bch_keybuf_check_overlapping(&s->op.c->moving_gc_keys,
- &KEY(d->id, bio->bi_sector, 0),
- &KEY(d->id, bio_end(bio), 0));
+ &KEY(d->id, bio->bi_sector, 0),
+ &KEY(d->id, bio_end_sector(bio), 0));
s->writeback = true;
s->op.cache_bio = bio;
diff --git a/drivers/md/bcache/request.h b/drivers/md/bcache/request.h
index 254d9ab5707..57dc4784f4f 100644
--- a/drivers/md/bcache/request.h
+++ b/drivers/md/bcache/request.h
@@ -30,7 +30,7 @@ struct search {
};
void bch_cache_read_endio(struct bio *, int);
-int bch_get_congested(struct cache_set *);
+unsigned bch_get_congested(struct cache_set *);
void bch_insert_data(struct closure *cl);
void bch_btree_insert_async(struct closure *);
void bch_cache_read_endio(struct bio *, int);
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index f88e2b653a3..547c4c57b05 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -10,10 +10,13 @@
#include "btree.h"
#include "debug.h"
#include "request.h"
+#include "writeback.h"
+#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/debugfs.h>
#include <linux/genhd.h>
+#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/reboot.h>
@@ -342,6 +345,7 @@ static void uuid_io(struct cache_set *c, unsigned long rw,
struct closure *cl = &c->uuid_write.cl;
struct uuid_entry *u;
unsigned i;
+ char buf[80];
BUG_ON(!parent);
closure_lock(&c->uuid_write, parent);
@@ -362,8 +366,8 @@ static void uuid_io(struct cache_set *c, unsigned long rw,
break;
}
- pr_debug("%s UUIDs at %s", rw & REQ_WRITE ? "wrote" : "read",
- pkey(&c->uuid_bucket));
+ bch_bkey_to_text(buf, sizeof(buf), k);
+ pr_debug("%s UUIDs at %s", rw & REQ_WRITE ? "wrote" : "read", buf);
for (u = c->uuids; u < c->uuids + c->nr_uuids; u++)
if (!bch_is_zero(u->uuid, 16))
@@ -543,7 +547,6 @@ void bch_prio_write(struct cache *ca)
pr_debug("free %zu, free_inc %zu, unused %zu", fifo_used(&ca->free),
fifo_used(&ca->free_inc), fifo_used(&ca->unused));
- blktrace_msg(ca, "Starting priorities: " buckets_free(ca));
for (i = prio_buckets(ca) - 1; i >= 0; --i) {
long bucket;
@@ -704,7 +707,8 @@ static void bcache_device_detach(struct bcache_device *d)
atomic_set(&d->detaching, 0);
}
- bcache_device_unlink(d);
+ if (!d->flush_done)
+ bcache_device_unlink(d);
d->c->devices[d->id] = NULL;
closure_put(&d->c->caching);
@@ -743,13 +747,35 @@ static void bcache_device_free(struct bcache_device *d)
mempool_destroy(d->unaligned_bvec);
if (d->bio_split)
bioset_free(d->bio_split);
+ if (is_vmalloc_addr(d->stripe_sectors_dirty))
+ vfree(d->stripe_sectors_dirty);
+ else
+ kfree(d->stripe_sectors_dirty);
closure_debug_destroy(&d->cl);
}
-static int bcache_device_init(struct bcache_device *d, unsigned block_size)
+static int bcache_device_init(struct bcache_device *d, unsigned block_size,
+ sector_t sectors)
{
struct request_queue *q;
+ size_t n;
+
+ if (!d->stripe_size_bits)
+ d->stripe_size_bits = 31;
+
+ d->nr_stripes = round_up(sectors, 1 << d->stripe_size_bits) >>
+ d->stripe_size_bits;
+
+ if (!d->nr_stripes || d->nr_stripes > SIZE_MAX / sizeof(atomic_t))
+ return -ENOMEM;
+
+ n = d->nr_stripes * sizeof(atomic_t);
+ d->stripe_sectors_dirty = n < PAGE_SIZE << 6
+ ? kzalloc(n, GFP_KERNEL)
+ : vzalloc(n);
+ if (!d->stripe_sectors_dirty)
+ return -ENOMEM;
if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
!(d->unaligned_bvec = mempool_create_kmalloc_pool(1,
@@ -759,6 +785,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size)
!(q = blk_alloc_queue(GFP_KERNEL)))
return -ENOMEM;
+ set_capacity(d->disk, sectors);
snprintf(d->disk->disk_name, DISK_NAME_LEN, "bcache%i", bcache_minor);
d->disk->major = bcache_major;
@@ -781,6 +808,8 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size)
set_bit(QUEUE_FLAG_NONROT, &d->disk->queue->queue_flags);
set_bit(QUEUE_FLAG_DISCARD, &d->disk->queue->queue_flags);
+ blk_queue_flush(q, REQ_FLUSH|REQ_FUA);
+
return 0;
}
@@ -800,6 +829,17 @@ static void calc_cached_dev_sectors(struct cache_set *c)
void bch_cached_dev_run(struct cached_dev *dc)
{
struct bcache_device *d = &dc->disk;
+ char buf[SB_LABEL_SIZE + 1];
+ char *env[] = {
+ "DRIVER=bcache",
+ kasprintf(GFP_KERNEL, "CACHED_UUID=%pU", dc->sb.uuid),
+ NULL,
+ NULL,
+ };
+
+ memcpy(buf, dc->sb.label, SB_LABEL_SIZE);
+ buf[SB_LABEL_SIZE] = '\0';
+ env[2] = kasprintf(GFP_KERNEL, "CACHED_LABEL=%s", buf);
if (atomic_xchg(&dc->running, 1))
return;
@@ -816,10 +856,12 @@ void bch_cached_dev_run(struct cached_dev *dc)
add_disk(d->disk);
bd_link_disk_holder(dc->bdev, dc->disk.disk);
-#if 0
- char *env[] = { "SYMLINK=label" , NULL };
+ /* won't show up in the uevent file, use udevadm monitor -e instead
+ * only class / kset properties are persistent */
kobject_uevent_env(&disk_to_dev(d->disk)->kobj, KOBJ_CHANGE, env);
-#endif
+ kfree(env[1]);
+ kfree(env[2]);
+
if (sysfs_create_link(&d->kobj, &disk_to_dev(d->disk)->kobj, "dev") ||
sysfs_create_link(&disk_to_dev(d->disk)->kobj, &d->kobj, "bcache"))
pr_debug("error creating sysfs link");
@@ -960,6 +1002,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
atomic_set(&dc->count, 1);
if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) {
+ bch_sectors_dirty_init(dc);
atomic_set(&dc->has_dirty, 1);
atomic_inc(&dc->count);
bch_writeback_queue(dc);
@@ -1014,6 +1057,14 @@ static void cached_dev_flush(struct closure *cl)
struct cached_dev *dc = container_of(cl, struct cached_dev, disk.cl);
struct bcache_device *d = &dc->disk;
+ mutex_lock(&bch_register_lock);
+ d->flush_done = 1;
+
+ if (d->c)
+ bcache_device_unlink(d);
+
+ mutex_unlock(&bch_register_lock);
+
bch_cache_accounting_destroy(&dc->accounting);
kobject_del(&d->kobj);
@@ -1045,7 +1096,8 @@ static int cached_dev_init(struct cached_dev *dc, unsigned block_size)
hlist_add_head(&io->hash, dc->io_hash + RECENT_IO);
}
- ret = bcache_device_init(&dc->disk, block_size);
+ ret = bcache_device_init(&dc->disk, block_size,
+ dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
if (ret)
return ret;
@@ -1144,11 +1196,10 @@ static int flash_dev_run(struct cache_set *c, struct uuid_entry *u)
kobject_init(&d->kobj, &bch_flash_dev_ktype);
- if (bcache_device_init(d, block_bytes(c)))
+ if (bcache_device_init(d, block_bytes(c), u->sectors))
goto err;
bcache_device_attach(d, c, u - c->uuids);
- set_capacity(d->disk, u->sectors);
bch_flash_dev_request_init(d);
add_disk(d->disk);
@@ -1255,9 +1306,10 @@ static void cache_set_free(struct closure *cl)
free_pages((unsigned long) c->uuids, ilog2(bucket_pages(c)));
free_pages((unsigned long) c->sort, ilog2(bucket_pages(c)));
- kfree(c->fill_iter);
if (c->bio_split)
bioset_free(c->bio_split);
+ if (c->fill_iter)
+ mempool_destroy(c->fill_iter);
if (c->bio_meta)
mempool_destroy(c->bio_meta);
if (c->search)
@@ -1278,11 +1330,9 @@ static void cache_set_free(struct closure *cl)
static void cache_set_flush(struct closure *cl)
{
struct cache_set *c = container_of(cl, struct cache_set, caching);
+ struct cache *ca;
struct btree *b;
-
- /* Shut down allocator threads */
- set_bit(CACHE_SET_STOPPING_2, &c->flags);
- wake_up(&c->alloc_wait);
+ unsigned i;
bch_cache_accounting_destroy(&c->accounting);
@@ -1295,7 +1345,11 @@ static void cache_set_flush(struct closure *cl)
/* Should skip this if we're unregistering because of an error */
list_for_each_entry(b, &c->btree_cache, list)
if (btree_node_dirty(b))
- bch_btree_write(b, true, NULL);
+ bch_btree_node_write(b, NULL);
+
+ for_each_cache(ca, c, i)
+ if (ca->alloc_thread)
+ kthread_stop(ca->alloc_thread);
closure_return(cl);
}
@@ -1303,18 +1357,22 @@ static void cache_set_flush(struct closure *cl)
static void __cache_set_unregister(struct closure *cl)
{
struct cache_set *c = container_of(cl, struct cache_set, caching);
- struct cached_dev *dc, *t;
+ struct cached_dev *dc;
size_t i;
mutex_lock(&bch_register_lock);
- if (test_bit(CACHE_SET_UNREGISTERING, &c->flags))
- list_for_each_entry_safe(dc, t, &c->cached_devs, list)
- bch_cached_dev_detach(dc);
-
for (i = 0; i < c->nr_uuids; i++)
- if (c->devices[i] && UUID_FLASH_ONLY(&c->uuids[i]))
- bcache_device_stop(c->devices[i]);
+ if (c->devices[i]) {
+ if (!UUID_FLASH_ONLY(&c->uuids[i]) &&
+ test_bit(CACHE_SET_UNREGISTERING, &c->flags)) {
+ dc = container_of(c->devices[i],
+ struct cached_dev, disk);
+ bch_cached_dev_detach(dc);
+ } else {
+ bcache_device_stop(c->devices[i]);
+ }
+ }
mutex_unlock(&bch_register_lock);
@@ -1373,9 +1431,9 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
c->btree_pages = max_t(int, c->btree_pages / 4,
BTREE_MAX_PAGES);
- init_waitqueue_head(&c->alloc_wait);
+ c->sort_crit_factor = int_sqrt(c->btree_pages);
+
mutex_init(&c->bucket_lock);
- mutex_init(&c->fill_lock);
mutex_init(&c->sort_lock);
spin_lock_init(&c->sort_time_lock);
closure_init_unlocked(&c->sb_write);
@@ -1401,8 +1459,8 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
!(c->bio_meta = mempool_create_kmalloc_pool(2,
sizeof(struct bbio) + sizeof(struct bio_vec) *
bucket_pages(c))) ||
+ !(c->fill_iter = mempool_create_kmalloc_pool(1, iter_size)) ||
!(c->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
- !(c->fill_iter = kmalloc(iter_size, GFP_KERNEL)) ||
!(c->sort = alloc_bucket_pages(GFP_KERNEL, c)) ||
!(c->uuids = alloc_bucket_pages(GFP_KERNEL, c)) ||
bch_journal_alloc(c) ||
@@ -1410,8 +1468,6 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
bch_open_buckets_alloc(c))
goto err;
- c->fill_iter->size = sb->bucket_size / sb->block_size;
-
c->congested_read_threshold_us = 2000;
c->congested_write_threshold_us = 20000;
c->error_limit = 8 << IO_ERROR_SHIFT;
@@ -1496,9 +1552,10 @@ static void run_cache_set(struct cache_set *c)
*/
bch_journal_next(&c->journal);
+ err = "error starting allocator thread";
for_each_cache(ca, c, i)
- closure_call(&ca->alloc, bch_allocator_thread,
- system_wq, &c->cl);
+ if (bch_cache_allocator_start(ca))
+ goto err;
/*
* First place it's safe to allocate: btree_check() and
@@ -1531,17 +1588,16 @@ static void run_cache_set(struct cache_set *c)
bch_btree_gc_finish(c);
+ err = "error starting allocator thread";
for_each_cache(ca, c, i)
- closure_call(&ca->alloc, bch_allocator_thread,
- ca->alloc_workqueue, &c->cl);
+ if (bch_cache_allocator_start(ca))
+ goto err;
mutex_lock(&c->bucket_lock);
for_each_cache(ca, c, i)
bch_prio_write(ca);
mutex_unlock(&c->bucket_lock);
- wake_up(&c->alloc_wait);
-
err = "cannot allocate new UUID bucket";
if (__uuid_write(c))
goto err_unlock_gc;
@@ -1552,7 +1608,7 @@ static void run_cache_set(struct cache_set *c)
goto err_unlock_gc;
bkey_copy_key(&c->root->key, &MAX_KEY);
- bch_btree_write(c->root, true, &op);
+ bch_btree_node_write(c->root, &op.cl);
bch_btree_set_root(c->root);
rw_unlock(true, c->root);
@@ -1673,9 +1729,6 @@ void bch_cache_release(struct kobject *kobj)
bio_split_pool_free(&ca->bio_split_hook);
- if (ca->alloc_workqueue)
- destroy_workqueue(ca->alloc_workqueue);
-
free_pages((unsigned long) ca->disk_buckets, ilog2(bucket_pages(ca)));
kfree(ca->prio_buckets);
vfree(ca->buckets);
@@ -1723,7 +1776,6 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
!(ca->prio_buckets = kzalloc(sizeof(uint64_t) * prio_buckets(ca) *
2, GFP_KERNEL)) ||
!(ca->disk_buckets = alloc_bucket_pages(GFP_KERNEL, ca)) ||
- !(ca->alloc_workqueue = alloc_workqueue("bch_allocator", 0, 1)) ||
bio_split_pool_init(&ca->bio_split_hook))
return -ENOMEM;
@@ -1786,6 +1838,36 @@ static ssize_t register_bcache(struct kobject *, struct kobj_attribute *,
kobj_attribute_write(register, register_bcache);
kobj_attribute_write(register_quiet, register_bcache);
+static bool bch_is_open_backing(struct block_device *bdev) {
+ struct cache_set *c, *tc;
+ struct cached_dev *dc, *t;
+
+ list_for_each_entry_safe(c, tc, &bch_cache_sets, list)
+ list_for_each_entry_safe(dc, t, &c->cached_devs, list)
+ if (dc->bdev == bdev)
+ return true;
+ list_for_each_entry_safe(dc, t, &uncached_devices, list)
+ if (dc->bdev == bdev)
+ return true;
+ return false;
+}
+
+static bool bch_is_open_cache(struct block_device *bdev) {
+ struct cache_set *c, *tc;
+ struct cache *ca;
+ unsigned i;
+
+ list_for_each_entry_safe(c, tc, &bch_cache_sets, list)
+ for_each_cache(ca, c, i)
+ if (ca->bdev == bdev)
+ return true;
+ return false;
+}
+
+static bool bch_is_open(struct block_device *bdev) {
+ return bch_is_open_cache(bdev) || bch_is_open_backing(bdev);
+}
+
static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
const char *buffer, size_t size)
{
@@ -1810,8 +1892,13 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
FMODE_READ|FMODE_WRITE|FMODE_EXCL,
sb);
if (IS_ERR(bdev)) {
- if (bdev == ERR_PTR(-EBUSY))
- err = "device busy";
+ if (bdev == ERR_PTR(-EBUSY)) {
+ bdev = lookup_bdev(strim(path));
+ if (!IS_ERR(bdev) && bch_is_open(bdev))
+ err = "device already registered";
+ else
+ err = "device busy";
+ }
goto err;
}
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index 4d9cca47e4c..12a2c2846f9 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -9,7 +9,9 @@
#include "sysfs.h"
#include "btree.h"
#include "request.h"
+#include "writeback.h"
+#include <linux/blkdev.h>
#include <linux/sort.h>
static const char * const cache_replacement_policies[] = {
@@ -79,6 +81,9 @@ rw_attribute(writeback_rate_p_term_inverse);
rw_attribute(writeback_rate_d_smooth);
read_attribute(writeback_rate_debug);
+read_attribute(stripe_size);
+read_attribute(partial_stripes_expensive);
+
rw_attribute(synchronous);
rw_attribute(journal_delay_ms);
rw_attribute(discard);
@@ -127,7 +132,7 @@ SHOW(__bch_cached_dev)
char derivative[20];
char target[20];
bch_hprint(dirty,
- atomic_long_read(&dc->disk.sectors_dirty) << 9);
+ bcache_dev_sectors_dirty(&dc->disk) << 9);
bch_hprint(derivative, dc->writeback_rate_derivative << 9);
bch_hprint(target, dc->writeback_rate_target << 9);
@@ -143,7 +148,10 @@ SHOW(__bch_cached_dev)
}
sysfs_hprint(dirty_data,
- atomic_long_read(&dc->disk.sectors_dirty) << 9);
+ bcache_dev_sectors_dirty(&dc->disk) << 9);
+
+ sysfs_hprint(stripe_size, (1 << dc->disk.stripe_size_bits) << 9);
+ var_printf(partial_stripes_expensive, "%u");
var_printf(sequential_merge, "%i");
var_hprint(sequential_cutoff);
@@ -170,6 +178,7 @@ STORE(__cached_dev)
disk.kobj);
unsigned v = size;
struct cache_set *c;
+ struct kobj_uevent_env *env;
#define d_strtoul(var) sysfs_strtoul(var, dc->var)
#define d_strtoi_h(var) sysfs_hatoi(var, dc->var)
@@ -214,6 +223,7 @@ STORE(__cached_dev)
}
if (attr == &sysfs_label) {
+ /* note: endlines are preserved */
memcpy(dc->sb.label, buf, SB_LABEL_SIZE);
bch_write_bdev_super(dc, NULL);
if (dc->disk.c) {
@@ -221,6 +231,15 @@ STORE(__cached_dev)
buf, SB_LABEL_SIZE);
bch_uuid_write(dc->disk.c);
}
+ env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+ if (!env)
+ return -ENOMEM;
+ add_uevent_var(env, "DRIVER=bcache");
+ add_uevent_var(env, "CACHED_UUID=%pU", dc->sb.uuid),
+ add_uevent_var(env, "CACHED_LABEL=%s", buf);
+ kobject_uevent_env(
+ &disk_to_dev(dc->disk.disk)->kobj, KOBJ_CHANGE, env->envp);
+ kfree(env);
}
if (attr == &sysfs_attach) {
@@ -284,6 +303,8 @@ static struct attribute *bch_cached_dev_files[] = {
&sysfs_writeback_rate_d_smooth,
&sysfs_writeback_rate_debug,
&sysfs_dirty_data,
+ &sysfs_stripe_size,
+ &sysfs_partial_stripes_expensive,
&sysfs_sequential_cutoff,
&sysfs_sequential_merge,
&sysfs_clear_stats,
@@ -665,12 +686,10 @@ SHOW(__bch_cache)
int cmp(const void *l, const void *r)
{ return *((uint16_t *) r) - *((uint16_t *) l); }
- /* Number of quantiles we compute */
- const unsigned nq = 31;
-
size_t n = ca->sb.nbuckets, i, unused, btree;
uint64_t sum = 0;
- uint16_t q[nq], *p, *cached;
+ /* Compute 31 quantiles */
+ uint16_t q[31], *p, *cached;
ssize_t ret;
cached = p = vmalloc(ca->sb.nbuckets * sizeof(uint16_t));
@@ -703,26 +722,29 @@ SHOW(__bch_cache)
if (n)
do_div(sum, n);
- for (i = 0; i < nq; i++)
- q[i] = INITIAL_PRIO - cached[n * (i + 1) / (nq + 1)];
+ for (i = 0; i < ARRAY_SIZE(q); i++)
+ q[i] = INITIAL_PRIO - cached[n * (i + 1) /
+ (ARRAY_SIZE(q) + 1)];
vfree(p);
- ret = snprintf(buf, PAGE_SIZE,
- "Unused: %zu%%\n"
- "Metadata: %zu%%\n"
- "Average: %llu\n"
- "Sectors per Q: %zu\n"
- "Quantiles: [",
- unused * 100 / (size_t) ca->sb.nbuckets,
- btree * 100 / (size_t) ca->sb.nbuckets, sum,
- n * ca->sb.bucket_size / (nq + 1));
-
- for (i = 0; i < nq && ret < (ssize_t) PAGE_SIZE; i++)
- ret += snprintf(buf + ret, PAGE_SIZE - ret,
- i < nq - 1 ? "%u " : "%u]\n", q[i]);
-
- buf[PAGE_SIZE - 1] = '\0';
+ ret = scnprintf(buf, PAGE_SIZE,
+ "Unused: %zu%%\n"
+ "Metadata: %zu%%\n"
+ "Average: %llu\n"
+ "Sectors per Q: %zu\n"
+ "Quantiles: [",
+ unused * 100 / (size_t) ca->sb.nbuckets,
+ btree * 100 / (size_t) ca->sb.nbuckets, sum,
+ n * ca->sb.bucket_size / (ARRAY_SIZE(q) + 1));
+
+ for (i = 0; i < ARRAY_SIZE(q); i++)
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "%u ", q[i]);
+ ret--;
+
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "]\n");
+
return ret;
}
diff --git a/drivers/md/bcache/trace.c b/drivers/md/bcache/trace.c
index 983f9bb411b..f7b6c197f90 100644
--- a/drivers/md/bcache/trace.c
+++ b/drivers/md/bcache/trace.c
@@ -2,6 +2,7 @@
#include "btree.h"
#include "request.h"
+#include <linux/blktrace_api.h>
#include <linux/module.h>
#define CREATE_TRACE_POINTS
@@ -9,18 +10,44 @@
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_request_start);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_request_end);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_passthrough);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_cache_hit);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_cache_miss);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_bypass_sequential);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_bypass_congested);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_read);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_write);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_read_retry);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_writethrough);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_writeback);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_write_skip);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_cache_insert);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_journal_replay_key);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_journal_write);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_journal_full);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_journal_entry_full);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_cache_cannibalize);
+
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_read);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_write);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_write_dirty);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_read_dirty);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_journal_write);
-EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_cache_insert);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_alloc);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_alloc_fail);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_free);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_gc_coalesce);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_gc_start);
EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_gc_end);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_gc_copy);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_gc_copy_collision);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_insert_key);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_split);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_node_compact);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_btree_set_root);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_alloc_invalidate);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_alloc_fail);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_writeback);
+EXPORT_TRACEPOINT_SYMBOL_GPL(bcache_writeback_collision);
diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c
index da3a99e85b1..98eb81159a2 100644
--- a/drivers/md/bcache/util.c
+++ b/drivers/md/bcache/util.c
@@ -228,23 +228,6 @@ start: bv->bv_len = min_t(size_t, PAGE_SIZE - bv->bv_offset,
}
}
-int bch_bio_alloc_pages(struct bio *bio, gfp_t gfp)
-{
- int i;
- struct bio_vec *bv;
-
- bio_for_each_segment(bv, bio, i) {
- bv->bv_page = alloc_page(gfp);
- if (!bv->bv_page) {
- while (bv-- != bio->bi_io_vec + bio->bi_idx)
- __free_page(bv->bv_page);
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-
/*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group (Any
* use permitted, subject to terms of PostgreSQL license; see.)
diff --git a/drivers/md/bcache/util.h b/drivers/md/bcache/util.h
index 577393e38c3..1ae2a73ad85 100644
--- a/drivers/md/bcache/util.h
+++ b/drivers/md/bcache/util.h
@@ -15,8 +15,6 @@
struct closure;
-#include <trace/events/bcache.h>
-
#ifdef CONFIG_BCACHE_EDEBUG
#define atomic_dec_bug(v) BUG_ON(atomic_dec_return(v) < 0)
@@ -566,12 +564,8 @@ static inline unsigned fract_exp_two(unsigned x, unsigned fract_bits)
return x;
}
-#define bio_end(bio) ((bio)->bi_sector + bio_sectors(bio))
-
void bch_bio_map(struct bio *bio, void *base);
-int bch_bio_alloc_pages(struct bio *bio, gfp_t gfp);
-
static inline sector_t bdev_sectors(struct block_device *bdev)
{
return bdev->bd_inode->i_size >> 9;
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
index 2714ed3991d..22cbff55162 100644
--- a/drivers/md/bcache/writeback.c
+++ b/drivers/md/bcache/writeback.c
@@ -9,6 +9,9 @@
#include "bcache.h"
#include "btree.h"
#include "debug.h"
+#include "writeback.h"
+
+#include <trace/events/bcache.h>
static struct workqueue_struct *dirty_wq;
@@ -36,7 +39,7 @@ static void __update_writeback_rate(struct cached_dev *dc)
int change = 0;
int64_t error;
- int64_t dirty = atomic_long_read(&dc->disk.sectors_dirty);
+ int64_t dirty = bcache_dev_sectors_dirty(&dc->disk);
int64_t derivative = dirty - dc->disk.sectors_dirty_last;
dc->disk.sectors_dirty_last = dirty;
@@ -105,6 +108,31 @@ static bool dirty_pred(struct keybuf *buf, struct bkey *k)
return KEY_DIRTY(k);
}
+static bool dirty_full_stripe_pred(struct keybuf *buf, struct bkey *k)
+{
+ uint64_t stripe;
+ unsigned nr_sectors = KEY_SIZE(k);
+ struct cached_dev *dc = container_of(buf, struct cached_dev,
+ writeback_keys);
+ unsigned stripe_size = 1 << dc->disk.stripe_size_bits;
+
+ if (!KEY_DIRTY(k))
+ return false;
+
+ stripe = KEY_START(k) >> dc->disk.stripe_size_bits;
+ while (1) {
+ if (atomic_read(dc->disk.stripe_sectors_dirty + stripe) !=
+ stripe_size)
+ return false;
+
+ if (nr_sectors <= stripe_size)
+ return true;
+
+ nr_sectors -= stripe_size;
+ stripe++;
+ }
+}
+
static void dirty_init(struct keybuf_key *w)
{
struct dirty_io *io = w->private;
@@ -149,7 +177,22 @@ static void refill_dirty(struct closure *cl)
searched_from_start = true;
}
- bch_refill_keybuf(dc->disk.c, buf, &end);
+ if (dc->partial_stripes_expensive) {
+ uint64_t i;
+
+ for (i = 0; i < dc->disk.nr_stripes; i++)
+ if (atomic_read(dc->disk.stripe_sectors_dirty + i) ==
+ 1 << dc->disk.stripe_size_bits)
+ goto full_stripes;
+
+ goto normal_refill;
+full_stripes:
+ bch_refill_keybuf(dc->disk.c, buf, &end,
+ dirty_full_stripe_pred);
+ } else {
+normal_refill:
+ bch_refill_keybuf(dc->disk.c, buf, &end, dirty_pred);
+ }
if (bkey_cmp(&buf->last_scanned, &end) >= 0 && searched_from_start) {
/* Searched the entire btree - delay awhile */
@@ -181,10 +224,8 @@ void bch_writeback_queue(struct cached_dev *dc)
}
}
-void bch_writeback_add(struct cached_dev *dc, unsigned sectors)
+void bch_writeback_add(struct cached_dev *dc)
{
- atomic_long_add(sectors, &dc->disk.sectors_dirty);
-
if (!atomic_read(&dc->has_dirty) &&
!atomic_xchg(&dc->has_dirty, 1)) {
atomic_inc(&dc->count);
@@ -203,6 +244,34 @@ void bch_writeback_add(struct cached_dev *dc, unsigned sectors)
}
}
+void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode,
+ uint64_t offset, int nr_sectors)
+{
+ struct bcache_device *d = c->devices[inode];
+ unsigned stripe_size, stripe_offset;
+ uint64_t stripe;
+
+ if (!d)
+ return;
+
+ stripe_size = 1 << d->stripe_size_bits;
+ stripe = offset >> d->stripe_size_bits;
+ stripe_offset = offset & (stripe_size - 1);
+
+ while (nr_sectors) {
+ int s = min_t(unsigned, abs(nr_sectors),
+ stripe_size - stripe_offset);
+
+ if (nr_sectors < 0)
+ s = -s;
+
+ atomic_add(s, d->stripe_sectors_dirty + stripe);
+ nr_sectors -= s;
+ stripe_offset = 0;
+ stripe++;
+ }
+}
+
/* Background writeback - IO loop */
static void dirty_io_destructor(struct closure *cl)
@@ -216,9 +285,10 @@ static void write_dirty_finish(struct closure *cl)
struct dirty_io *io = container_of(cl, struct dirty_io, cl);
struct keybuf_key *w = io->bio.bi_private;
struct cached_dev *dc = io->dc;
- struct bio_vec *bv = bio_iovec_idx(&io->bio, io->bio.bi_vcnt);
+ struct bio_vec *bv;
+ int i;
- while (bv-- != io->bio.bi_io_vec)
+ bio_for_each_segment_all(bv, &io->bio, i)
__free_page(bv->bv_page);
/* This is kind of a dumb way of signalling errors. */
@@ -236,10 +306,12 @@ static void write_dirty_finish(struct closure *cl)
for (i = 0; i < KEY_PTRS(&w->key); i++)
atomic_inc(&PTR_BUCKET(dc->disk.c, &w->key, i)->pin);
- pr_debug("clearing %s", pkey(&w->key));
bch_btree_insert(&op, dc->disk.c);
closure_sync(&op.cl);
+ if (op.insert_collision)
+ trace_bcache_writeback_collision(&w->key);
+
atomic_long_inc(op.insert_collision
? &dc->disk.c->writeback_keys_failed
: &dc->disk.c->writeback_keys_done);
@@ -275,7 +347,6 @@ static void write_dirty(struct closure *cl)
io->bio.bi_bdev = io->dc->bdev;
io->bio.bi_end_io = dirty_endio;
- trace_bcache_write_dirty(&io->bio);
closure_bio_submit(&io->bio, cl, &io->dc->disk);
continue_at(cl, write_dirty_finish, dirty_wq);
@@ -296,7 +367,6 @@ static void read_dirty_submit(struct closure *cl)
{
struct dirty_io *io = container_of(cl, struct dirty_io, cl);
- trace_bcache_read_dirty(&io->bio);
closure_bio_submit(&io->bio, cl, &io->dc->disk);
continue_at(cl, write_dirty, dirty_wq);
@@ -349,10 +419,10 @@ static void read_dirty(struct closure *cl)
io->bio.bi_rw = READ;
io->bio.bi_end_io = read_dirty_endio;
- if (bch_bio_alloc_pages(&io->bio, GFP_KERNEL))
+ if (bio_alloc_pages(&io->bio, GFP_KERNEL))
goto err_free;
- pr_debug("%s", pkey(&w->key));
+ trace_bcache_writeback(&w->key);
closure_call(&io->cl, read_dirty_submit, NULL, &dc->disk.cl);
@@ -375,12 +445,49 @@ err:
refill_dirty(cl);
}
+/* Init */
+
+static int bch_btree_sectors_dirty_init(struct btree *b, struct btree_op *op,
+ struct cached_dev *dc)
+{
+ struct bkey *k;
+ struct btree_iter iter;
+
+ bch_btree_iter_init(b, &iter, &KEY(dc->disk.id, 0, 0));
+ while ((k = bch_btree_iter_next_filter(&iter, b, bch_ptr_bad)))
+ if (!b->level) {
+ if (KEY_INODE(k) > dc->disk.id)
+ break;
+
+ if (KEY_DIRTY(k))
+ bcache_dev_sectors_dirty_add(b->c, dc->disk.id,
+ KEY_START(k),
+ KEY_SIZE(k));
+ } else {
+ btree(sectors_dirty_init, k, b, op, dc);
+ if (KEY_INODE(k) > dc->disk.id)
+ break;
+
+ cond_resched();
+ }
+
+ return 0;
+}
+
+void bch_sectors_dirty_init(struct cached_dev *dc)
+{
+ struct btree_op op;
+
+ bch_btree_op_init_stack(&op);
+ btree_root(sectors_dirty_init, dc->disk.c, &op, dc);
+}
+
void bch_cached_dev_writeback_init(struct cached_dev *dc)
{
closure_init_unlocked(&dc->writeback);
init_rwsem(&dc->writeback_lock);
- bch_keybuf_init(&dc->writeback_keys, dirty_pred);
+ bch_keybuf_init(&dc->writeback_keys);
dc->writeback_metadata = true;
dc->writeback_running = true;
diff --git a/drivers/md/bcache/writeback.h b/drivers/md/bcache/writeback.h
new file mode 100644
index 00000000000..c91f61bb95b
--- /dev/null
+++ b/drivers/md/bcache/writeback.h
@@ -0,0 +1,64 @@
+#ifndef _BCACHE_WRITEBACK_H
+#define _BCACHE_WRITEBACK_H
+
+#define CUTOFF_WRITEBACK 40
+#define CUTOFF_WRITEBACK_SYNC 70
+
+static inline uint64_t bcache_dev_sectors_dirty(struct bcache_device *d)
+{
+ uint64_t i, ret = 0;
+
+ for (i = 0; i < d->nr_stripes; i++)
+ ret += atomic_read(d->stripe_sectors_dirty + i);
+
+ return ret;
+}
+
+static inline bool bcache_dev_stripe_dirty(struct bcache_device *d,
+ uint64_t offset,
+ unsigned nr_sectors)
+{
+ uint64_t stripe = offset >> d->stripe_size_bits;
+
+ while (1) {
+ if (atomic_read(d->stripe_sectors_dirty + stripe))
+ return true;
+
+ if (nr_sectors <= 1 << d->stripe_size_bits)
+ return false;
+
+ nr_sectors -= 1 << d->stripe_size_bits;
+ stripe++;
+ }
+}
+
+static inline bool should_writeback(struct cached_dev *dc, struct bio *bio,
+ unsigned cache_mode, bool would_skip)
+{
+ unsigned in_use = dc->disk.c->gc_stats.in_use;
+
+ if (cache_mode != CACHE_MODE_WRITEBACK ||
+ atomic_read(&dc->disk.detaching) ||
+ in_use > CUTOFF_WRITEBACK_SYNC)
+ return false;
+
+ if (dc->partial_stripes_expensive &&
+ bcache_dev_stripe_dirty(&dc->disk, bio->bi_sector,
+ bio_sectors(bio)))
+ return true;
+
+ if (would_skip)
+ return false;
+
+ return bio->bi_rw & REQ_SYNC ||
+ in_use <= CUTOFF_WRITEBACK;
+}
+
+void bcache_dev_sectors_dirty_add(struct cache_set *, unsigned, uint64_t, int);
+void bch_writeback_queue(struct cached_dev *);
+void bch_writeback_add(struct cached_dev *);
+
+void bch_sectors_dirty_init(struct cached_dev *dc);
+void bch_cached_dev_writeback_init(struct cached_dev *);
+
+#endif
diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c
index dc112a7137f..4296155090b 100644
--- a/drivers/md/dm-cache-policy-mq.c
+++ b/drivers/md/dm-cache-policy-mq.c
@@ -959,23 +959,21 @@ out:
return r;
}
-static void remove_mapping(struct mq_policy *mq, dm_oblock_t oblock)
+static void mq_remove_mapping(struct dm_cache_policy *p, dm_oblock_t oblock)
{
- struct entry *e = hash_lookup(mq, oblock);
+ struct mq_policy *mq = to_mq_policy(p);
+ struct entry *e;
+
+ mutex_lock(&mq->lock);
+
+ e = hash_lookup(mq, oblock);
BUG_ON(!e || !e->in_cache);
del(mq, e);
e->in_cache = false;
push(mq, e);
-}
-static void mq_remove_mapping(struct dm_cache_policy *p, dm_oblock_t oblock)
-{
- struct mq_policy *mq = to_mq_policy(p);
-
- mutex_lock(&mq->lock);
- remove_mapping(mq, oblock);
mutex_unlock(&mq->lock);
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 5adede17ddf..b759a127f9c 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1261,6 +1261,20 @@ static void activate_path(struct work_struct *work)
pg_init_done, pgpath);
}
+static int noretry_error(int error)
+{
+ switch (error) {
+ case -EOPNOTSUPP:
+ case -EREMOTEIO:
+ case -EILSEQ:
+ case -ENODATA:
+ return 1;
+ }
+
+ /* Anything else could be a path failure, so should be retried */
+ return 0;
+}
+
/*
* end_io handling
*/
@@ -1284,7 +1298,7 @@ static int do_end_io(struct multipath *m, struct request *clone,
if (!error && !clone->errors)
return 0; /* I/O complete */
- if (error == -EOPNOTSUPP || error == -EREMOTEIO || error == -EILSEQ)
+ if (noretry_error(error))
return error;
if (mpio->pgpath)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 957a719e8c2..df7b0a06b0e 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2290,12 +2290,18 @@ static void recovery_request_write(struct mddev *mddev, struct r10bio *r10_bio)
d = r10_bio->devs[1].devnum;
wbio = r10_bio->devs[1].bio;
wbio2 = r10_bio->devs[1].repl_bio;
+ /* Need to test wbio2->bi_end_io before we call
+ * generic_make_request as if the former is NULL,
+ * the latter is free to free wbio2.
+ */
+ if (wbio2 && !wbio2->bi_end_io)
+ wbio2 = NULL;
if (wbio->bi_end_io) {
atomic_inc(&conf->mirrors[d].rdev->nr_pending);
md_sync_acct(conf->mirrors[d].rdev->bdev, bio_sectors(wbio));
generic_make_request(wbio);
}
- if (wbio2 && wbio2->bi_end_io) {
+ if (wbio2) {
atomic_inc(&conf->mirrors[d].replacement->nr_pending);
md_sync_acct(conf->mirrors[d].replacement->bdev,
bio_sectors(wbio2));
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 2bf094a587c..78ea44336e7 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3462,6 +3462,7 @@ static void handle_stripe(struct stripe_head *sh)
test_and_clear_bit(STRIPE_SYNC_REQUESTED, &sh->state)) {
set_bit(STRIPE_SYNCING, &sh->state);
clear_bit(STRIPE_INSYNC, &sh->state);
+ clear_bit(STRIPE_REPLACED, &sh->state);
}
spin_unlock(&sh->stripe_lock);
}
@@ -3607,19 +3608,23 @@ static void handle_stripe(struct stripe_head *sh)
handle_parity_checks5(conf, sh, &s, disks);
}
- if (s.replacing && s.locked == 0
- && !test_bit(STRIPE_INSYNC, &sh->state)) {
+ if ((s.replacing || s.syncing) && s.locked == 0
+ && !test_bit(STRIPE_COMPUTE_RUN, &sh->state)
+ && !test_bit(STRIPE_REPLACED, &sh->state)) {
/* Write out to replacement devices where possible */
for (i = 0; i < conf->raid_disks; i++)
- if (test_bit(R5_UPTODATE, &sh->dev[i].flags) &&
- test_bit(R5_NeedReplace, &sh->dev[i].flags)) {
+ if (test_bit(R5_NeedReplace, &sh->dev[i].flags)) {
+ WARN_ON(!test_bit(R5_UPTODATE, &sh->dev[i].flags));
set_bit(R5_WantReplace, &sh->dev[i].flags);
set_bit(R5_LOCKED, &sh->dev[i].flags);
s.locked++;
}
- set_bit(STRIPE_INSYNC, &sh->state);
+ if (s.replacing)
+ set_bit(STRIPE_INSYNC, &sh->state);
+ set_bit(STRIPE_REPLACED, &sh->state);
}
if ((s.syncing || s.replacing) && s.locked == 0 &&
+ !test_bit(STRIPE_COMPUTE_RUN, &sh->state) &&
test_bit(STRIPE_INSYNC, &sh->state)) {
md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
clear_bit(STRIPE_SYNCING, &sh->state);
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index b0b663b119a..70c49329ca9 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -306,6 +306,7 @@ enum {
STRIPE_SYNC_REQUESTED,
STRIPE_SYNCING,
STRIPE_INSYNC,
+ STRIPE_REPLACED,
STRIPE_PREREAD_ACTIVE,
STRIPE_DELAYED,
STRIPE_DEGRADED,
diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c
index efdc873e58d..a9857022f71 100644
--- a/drivers/media/i2c/ml86v7667.c
+++ b/drivers/media/i2c/ml86v7667.c
@@ -117,7 +117,7 @@ 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;
+ int ret = -EINVAL;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -157,7 +157,7 @@ static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl)
break;
}
- return 0;
+ return ret;
}
static int ml86v7667_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
index df4ada880e4..bd9405df1bd 100644
--- a/drivers/media/platform/coda.c
+++ b/drivers/media/platform/coda.c
@@ -1987,7 +1987,7 @@ MODULE_DEVICE_TABLE(platform, coda_platform_ids);
#ifdef CONFIG_OF
static const struct of_device_id coda_dt_ids[] = {
- { .compatible = "fsl,imx27-vpu", .data = &coda_platform_ids[CODA_IMX27] },
+ { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
{ .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
{ /* sentinel */ }
};
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index 553d87e5cea..fd6289d60cd 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -784,6 +784,7 @@ static int g2d_probe(struct platform_device *pdev)
}
*vfd = g2d_videodev;
vfd->lock = &dev->mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 5296385153d..4f6dd42c9ad 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -344,7 +344,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
pix_mp->num_planes = 2;
/* Set pixelformat to the format in which MFC
outputs the decoded frame */
- pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT;
+ pix_mp->pixelformat = ctx->dst_fmt->fourcc;
pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
@@ -382,10 +382,16 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
mfc_err("Unsupported format for source.\n");
return -EINVAL;
}
- if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
- mfc_err("Not supported format.\n");
+ if (fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
+ mfc_err("Unknown codec\n");
return -EINVAL;
}
+ if (!IS_MFCV6(dev)) {
+ if (fmt->fourcc == V4L2_PIX_FMT_VP8) {
+ mfc_err("Not supported format.\n");
+ return -EINVAL;
+ }
+ }
} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
fmt = find_format(f, MFC_FMT_RAW);
if (!fmt) {
@@ -411,7 +417,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
struct s5p_mfc_dev *dev = video_drvdata(file);
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
int ret = 0;
- struct s5p_mfc_fmt *fmt;
struct v4l2_pix_format_mplane *pix_mp;
mfc_debug_enter();
@@ -425,54 +430,32 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
goto out;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- fmt = find_format(f, MFC_FMT_RAW);
- if (!fmt) {
- mfc_err("Unsupported format for source.\n");
- return -EINVAL;
- }
- if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) {
- mfc_err("Not supported format.\n");
- return -EINVAL;
- } else if (IS_MFCV6(dev) &&
- (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
- mfc_err("Not supported format.\n");
- return -EINVAL;
- }
- ctx->dst_fmt = fmt;
- mfc_debug_leave();
- return ret;
- } else if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_err("Wrong type error for S_FMT : %d", f->type);
- return -EINVAL;
- }
- fmt = find_format(f, MFC_FMT_DEC);
- if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) {
- mfc_err("Unknown codec\n");
- ret = -EINVAL;
+ /* dst_fmt is validated by call to vidioc_try_fmt */
+ ctx->dst_fmt = find_format(f, MFC_FMT_RAW);
+ ret = 0;
goto out;
- }
- if (fmt->type != MFC_FMT_DEC) {
- mfc_err("Wrong format selected, you should choose "
- "format for decoding\n");
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ /* src_fmt is validated by call to vidioc_try_fmt */
+ ctx->src_fmt = find_format(f, MFC_FMT_DEC);
+ ctx->codec_mode = ctx->src_fmt->codec_mode;
+ mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
+ pix_mp->height = 0;
+ pix_mp->width = 0;
+ if (pix_mp->plane_fmt[0].sizeimage)
+ ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
+ else
+ pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
+ DEF_CPB_SIZE;
+ pix_mp->plane_fmt[0].bytesperline = 0;
+ ctx->state = MFCINST_INIT;
+ ret = 0;
+ goto out;
+ } else {
+ mfc_err("Wrong type error for S_FMT : %d", f->type);
ret = -EINVAL;
goto out;
}
- if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
- mfc_err("Not supported format.\n");
- return -EINVAL;
- }
- ctx->src_fmt = fmt;
- ctx->codec_mode = fmt->codec_mode;
- mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
- pix_mp->height = 0;
- pix_mp->width = 0;
- if (pix_mp->plane_fmt[0].sizeimage)
- ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
- else
- pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
- DEF_CPB_SIZE;
- pix_mp->plane_fmt[0].bytesperline = 0;
- ctx->state = MFCINST_INIT;
+
out:
mfc_debug_leave();
return ret;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 2549967b2f8..59e56f4c8ce 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -906,6 +906,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
struct s5p_mfc_fmt *fmt;
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
@@ -930,6 +931,18 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
return -EINVAL;
}
+ if (!IS_MFCV6(dev)) {
+ if (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
+ mfc_err("Not supported format.\n");
+ return -EINVAL;
+ }
+ } else if (IS_MFCV6(dev)) {
+ if (fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
+ mfc_err("Not supported format.\n");
+ return -EINVAL;
+ }
+ }
+
if (fmt->num_planes != pix_fmt_mp->num_planes) {
mfc_err("failed to try output format\n");
return -EINVAL;
@@ -947,7 +960,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
struct s5p_mfc_dev *dev = video_drvdata(file);
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- struct s5p_mfc_fmt *fmt;
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
int ret = 0;
@@ -960,13 +972,9 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
goto out;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- fmt = find_format(f, MFC_FMT_ENC);
- if (!fmt) {
- mfc_err("failed to set capture format\n");
- return -EINVAL;
- }
+ /* dst_fmt is validated by call to vidioc_try_fmt */
+ ctx->dst_fmt = find_format(f, MFC_FMT_ENC);
ctx->state = MFCINST_INIT;
- ctx->dst_fmt = fmt;
ctx->codec_mode = ctx->dst_fmt->codec_mode;
ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
pix_fmt_mp->plane_fmt[0].bytesperline = 0;
@@ -987,28 +995,8 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
}
mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- fmt = find_format(f, MFC_FMT_RAW);
- if (!fmt) {
- mfc_err("failed to set output format\n");
- return -EINVAL;
- }
-
- if (!IS_MFCV6(dev) &&
- (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)) {
- mfc_err("Not supported format.\n");
- return -EINVAL;
- } else if (IS_MFCV6(dev) &&
- (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
- mfc_err("Not supported format.\n");
- return -EINVAL;
- }
-
- if (fmt->num_planes != pix_fmt_mp->num_planes) {
- mfc_err("failed to set output format\n");
- ret = -EINVAL;
- goto out;
- }
- ctx->src_fmt = fmt;
+ /* src_fmt is validated by call to vidioc_try_fmt */
+ ctx->src_fmt = find_format(f, MFC_FMT_RAW);
ctx->img_width = pix_fmt_mp->width;
ctx->img_height = pix_fmt_mp->height;
mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode);
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 4851cc2e4a4..c4ff9739a7a 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -726,7 +726,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
*eedata = data;
*eedata_len = len;
- dev_config = (void *)eedata;
+ dev_config = (void *)*eedata;
switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) {
case 0:
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index cb694055ba7..6e5070774dc 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -303,6 +303,11 @@ static int hdpvr_probe(struct usb_interface *interface,
dev->workqueue = 0;
+ /* init video transfer queues first of all */
+ /* to prevent oops in hdpvr_delete() on error paths */
+ INIT_LIST_HEAD(&dev->free_buff_list);
+ INIT_LIST_HEAD(&dev->rec_buff_list);
+
/* register v4l2_device early so it can be used for printks */
if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
dev_err(&interface->dev, "v4l2_device_register failed\n");
@@ -325,10 +330,6 @@ static int hdpvr_probe(struct usb_interface *interface,
if (!dev->workqueue)
goto error;
- /* init video transfer queues */
- INIT_LIST_HEAD(&dev->free_buff_list);
- INIT_LIST_HEAD(&dev->rec_buff_list);
-
dev->options = hdpvr_default_options;
if (default_video_input < HDPVR_VIDEO_INPUTS)
@@ -405,7 +406,7 @@ static int hdpvr_probe(struct usb_interface *interface,
video_nr[atomic_inc_return(&dev_nr)]);
if (retval < 0) {
v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
- goto error;
+ goto reg_fail;
}
/* let the user know what node this device is now attached to */
diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig
index 8864436464b..7c5b86006ee 100644
--- a/drivers/media/usb/usbtv/Kconfig
+++ b/drivers/media/usb/usbtv/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_USBTV
tristate "USBTV007 video capture support"
- depends on VIDEO_DEV
+ depends on VIDEO_V4L2
select VIDEOBUF2_VMALLOC
---help---
diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv.c
index bf43f874685..91650173941 100644
--- a/drivers/media/usb/usbtv/usbtv.c
+++ b/drivers/media/usb/usbtv/usbtv.c
@@ -57,7 +57,7 @@
#define USBTV_CHUNK_SIZE 256
#define USBTV_CHUNK 240
#define USBTV_CHUNKS (USBTV_WIDTH * USBTV_HEIGHT \
- / 2 / USBTV_CHUNK)
+ / 4 / USBTV_CHUNK)
/* Chunk header. */
#define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \
@@ -89,6 +89,7 @@ struct usbtv {
/* Number of currently processed frame, useful find
* out when a new one begins. */
u32 frame_id;
+ int chunks_done;
int iso_size;
unsigned int sequence;
@@ -202,6 +203,26 @@ static int usbtv_setup_capture(struct usbtv *usbtv)
return 0;
}
+/* Copy data from chunk into a frame buffer, deinterlacing the data
+ * into every second line. Unfortunately, they don't align nicely into
+ * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels.
+ * Therefore, we break down the chunk into two halves before copyting,
+ * so that we can interleave a line if needed. */
+static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd)
+{
+ int half;
+
+ for (half = 0; half < 2; half++) {
+ int part_no = chunk_no * 2 + half;
+ int line = part_no / 3;
+ int part_index = (line * 2 + !odd) * 3 + (part_no % 3);
+
+ u32 *dst = &frame[part_index * USBTV_CHUNK/2];
+ memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src));
+ src += USBTV_CHUNK/2;
+ }
+}
+
/* Called for each 256-byte image chunk.
* First word identifies the chunk, followed by 240 words of image
* data and padding. */
@@ -218,17 +239,17 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
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)
+ if (chunk_no == 0) {
usbtv->frame_id = frame_id;
+ usbtv->chunks_done = 0;
+ }
+
+ if (usbtv->frame_id != frame_id)
+ return;
spin_lock_irqsave(&usbtv->buflock, flags);
if (list_empty(&usbtv->bufs)) {
@@ -241,19 +262,23 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
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]));
+ /* Copy the chunk data. */
+ usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd);
+ usbtv->chunks_done++;
/* Last chunk in a frame, signalling an end */
- if (usbtv->frame_id && chunk_no == USBTV_CHUNKS-1) {
+ if (odd && chunk_no == USBTV_CHUNKS-1) {
int size = vb2_plane_size(&buf->vb, 0);
+ enum vb2_buffer_state state = usbtv->chunks_done ==
+ USBTV_CHUNKS ?
+ VB2_BUF_STATE_DONE :
+ VB2_BUF_STATE_ERROR;
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);
+ vb2_buffer_done(&buf->vb, state);
list_del(&buf->list);
}
@@ -518,7 +543,7 @@ static int usbtv_queue_setup(struct vb2_queue *vq,
if (*nbuffers < 2)
*nbuffers = 2;
*nplanes = 1;
- sizes[0] = USBTV_CHUNK * USBTV_CHUNKS * sizeof(u32);
+ sizes[0] = USBTV_WIDTH * USBTV_HEIGHT / 2 * sizeof(u32);
return 0;
}
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index c8859d6ff6a..b0f49b014bc 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -38,24 +38,25 @@
* sysfs stuff
*/
-static ssize_t show_index(struct device *cd,
- struct device_attribute *attr, char *buf)
+static ssize_t index_show(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vdev = to_video_device(cd);
return sprintf(buf, "%i\n", vdev->index);
}
+static DEVICE_ATTR_RO(index);
-static ssize_t show_debug(struct device *cd,
- struct device_attribute *attr, char *buf)
+static ssize_t debug_show(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vdev = to_video_device(cd);
return sprintf(buf, "%i\n", vdev->debug);
}
-static ssize_t set_debug(struct device *cd, struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t debug_store(struct device *cd, struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct video_device *vdev = to_video_device(cd);
int res = 0;
@@ -68,21 +69,24 @@ static ssize_t set_debug(struct device *cd, struct device_attribute *attr,
vdev->debug = value;
return len;
}
+static DEVICE_ATTR_RW(debug);
-static ssize_t show_name(struct device *cd,
+static ssize_t name_show(struct device *cd,
struct device_attribute *attr, char *buf)
{
struct video_device *vdev = to_video_device(cd);
return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name);
}
+static DEVICE_ATTR_RO(name);
-static struct device_attribute video_device_attrs[] = {
- __ATTR(name, S_IRUGO, show_name, NULL),
- __ATTR(debug, 0644, show_debug, set_debug),
- __ATTR(index, S_IRUGO, show_index, NULL),
- __ATTR_NULL
+static struct attribute *video_device_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_debug.attr,
+ &dev_attr_index.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(video_device);
/*
* Active devices
@@ -217,7 +221,7 @@ static void v4l2_device_release(struct device *cd)
static struct class video_class = {
.name = VIDEO_NAME,
- .dev_attrs = video_device_attrs,
+ .dev_groups = video_device_groups,
};
struct video_device *video_devdata(struct file *file)
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 3c157faee64..0d68eb1a5ec 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -3094,6 +3094,10 @@ static struct mfd_cell db8500_prcmu_devs[] = {
.pdata_size = sizeof(db8500_cpufreq_table),
},
{
+ .name = "cpuidle-dbx500",
+ .of_compatible = "stericsson,cpuidle-dbx500",
+ },
+ {
.name = "db8500-thermal",
.num_resources = ARRAY_SIZE(db8500_thsens_resources),
.resources = db8500_thsens_resources,
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index f7b90661e32..5be808406ed 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/pinctrl/consumer.h>
/* Serialize access to ssc_list and user count */
static DEFINE_SPINLOCK(user_lock);
@@ -66,14 +65,19 @@ EXPORT_SYMBOL(ssc_request);
void ssc_free(struct ssc_device *ssc)
{
+ bool disable_clk = true;
+
spin_lock(&user_lock);
- if (ssc->user) {
+ if (ssc->user)
ssc->user--;
- clk_disable_unprepare(ssc->clk);
- } else {
+ else {
+ disable_clk = false;
dev_dbg(&ssc->pdev->dev, "device already free\n");
}
spin_unlock(&user_lock);
+
+ if (disable_clk)
+ clk_disable_unprepare(ssc->clk);
}
EXPORT_SYMBOL(ssc_free);
@@ -132,13 +136,6 @@ static int ssc_probe(struct platform_device *pdev)
struct resource *regs;
struct ssc_device *ssc;
const struct atmel_ssc_platform_data *plat_dat;
- struct pinctrl *pinctrl;
-
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- dev_err(&pdev->dev, "Failed to request pinctrl\n");
- return PTR_ERR(pinctrl);
- }
ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL);
if (!ssc) {
diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c
index f32550a74bd..464419b3644 100644
--- a/drivers/misc/c2port/core.c
+++ b/drivers/misc/c2port/core.c
@@ -311,6 +311,7 @@ static ssize_t c2port_show_name(struct device *dev,
return sprintf(buf, "%s\n", c2dev->name);
}
+static DEVICE_ATTR(name, 0444, c2port_show_name, NULL);
static ssize_t c2port_show_flash_blocks_num(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -320,6 +321,7 @@ static ssize_t c2port_show_flash_blocks_num(struct device *dev,
return sprintf(buf, "%d\n", ops->blocks_num);
}
+static DEVICE_ATTR(flash_blocks_num, 0444, c2port_show_flash_blocks_num, NULL);
static ssize_t c2port_show_flash_block_size(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -329,6 +331,7 @@ static ssize_t c2port_show_flash_block_size(struct device *dev,
return sprintf(buf, "%d\n", ops->block_size);
}
+static DEVICE_ATTR(flash_block_size, 0444, c2port_show_flash_block_size, NULL);
static ssize_t c2port_show_flash_size(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -338,18 +341,18 @@ static ssize_t c2port_show_flash_size(struct device *dev,
return sprintf(buf, "%d\n", ops->blocks_num * ops->block_size);
}
+static DEVICE_ATTR(flash_size, 0444, c2port_show_flash_size, NULL);
-static ssize_t c2port_show_access(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t access_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct c2port_device *c2dev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", c2dev->access);
}
-static ssize_t c2port_store_access(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t access_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct c2port_device *c2dev = dev_get_drvdata(dev);
struct c2port_ops *ops = c2dev->ops;
@@ -375,6 +378,7 @@ static ssize_t c2port_store_access(struct device *dev,
return count;
}
+static DEVICE_ATTR_RW(access);
static ssize_t c2port_store_reset(struct device *dev,
struct device_attribute *attr,
@@ -395,6 +399,7 @@ static ssize_t c2port_store_reset(struct device *dev,
return count;
}
+static DEVICE_ATTR(reset, 0200, NULL, c2port_store_reset);
static ssize_t __c2port_show_dev_id(struct c2port_device *dev, char *buf)
{
@@ -431,6 +436,7 @@ static ssize_t c2port_show_dev_id(struct device *dev,
return ret;
}
+static DEVICE_ATTR(dev_id, 0444, c2port_show_dev_id, NULL);
static ssize_t __c2port_show_rev_id(struct c2port_device *dev, char *buf)
{
@@ -467,6 +473,7 @@ static ssize_t c2port_show_rev_id(struct device *dev,
return ret;
}
+static DEVICE_ATTR(rev_id, 0444, c2port_show_rev_id, NULL);
static ssize_t c2port_show_flash_access(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -536,6 +543,8 @@ static ssize_t c2port_store_flash_access(struct device *dev,
return count;
}
+static DEVICE_ATTR(flash_access, 0644, c2port_show_flash_access,
+ c2port_store_flash_access);
static ssize_t __c2port_write_flash_erase(struct c2port_device *dev)
{
@@ -616,6 +625,7 @@ static ssize_t c2port_store_flash_erase(struct device *dev,
return count;
}
+static DEVICE_ATTR(flash_erase, 0200, NULL, c2port_store_flash_erase);
static ssize_t __c2port_read_flash_data(struct c2port_device *dev,
char *buffer, loff_t offset, size_t count)
@@ -846,35 +856,40 @@ static ssize_t c2port_write_flash_data(struct file *filp, struct kobject *kobj,
return ret;
}
+/* size is computed at run-time */
+static BIN_ATTR(flash_data, 0644, c2port_read_flash_data,
+ c2port_write_flash_data, 0);
/*
* Class attributes
*/
+static struct attribute *c2port_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_flash_blocks_num.attr,
+ &dev_attr_flash_block_size.attr,
+ &dev_attr_flash_size.attr,
+ &dev_attr_access.attr,
+ &dev_attr_reset.attr,
+ &dev_attr_dev_id.attr,
+ &dev_attr_rev_id.attr,
+ &dev_attr_flash_access.attr,
+ &dev_attr_flash_erase.attr,
+ NULL,
+};
-static struct device_attribute c2port_attrs[] = {
- __ATTR(name, 0444, c2port_show_name, NULL),
- __ATTR(flash_blocks_num, 0444, c2port_show_flash_blocks_num, NULL),
- __ATTR(flash_block_size, 0444, c2port_show_flash_block_size, NULL),
- __ATTR(flash_size, 0444, c2port_show_flash_size, NULL),
- __ATTR(access, 0644, c2port_show_access, c2port_store_access),
- __ATTR(reset, 0200, NULL, c2port_store_reset),
- __ATTR(dev_id, 0444, c2port_show_dev_id, NULL),
- __ATTR(rev_id, 0444, c2port_show_rev_id, NULL),
-
- __ATTR(flash_access, 0644, c2port_show_flash_access,
- c2port_store_flash_access),
- __ATTR(flash_erase, 0200, NULL, c2port_store_flash_erase),
- __ATTR_NULL,
+static struct bin_attribute *c2port_bin_attrs[] = {
+ &bin_attr_flash_data,
+ NULL,
};
-static struct bin_attribute c2port_bin_attrs = {
- .attr = {
- .name = "flash_data",
- .mode = 0644
- },
- .read = c2port_read_flash_data,
- .write = c2port_write_flash_data,
- /* .size is computed at run-time */
+static const struct attribute_group c2port_group = {
+ .attrs = c2port_attrs,
+ .bin_attrs = c2port_bin_attrs,
+};
+
+static const struct attribute_group *c2port_groups[] = {
+ &c2port_group,
+ NULL,
};
/*
@@ -907,6 +922,8 @@ struct c2port_device *c2port_device_register(char *name,
goto error_idr_alloc;
c2dev->id = ret;
+ bin_attr_flash_data.size = ops->blocks_num * ops->block_size;
+
c2dev->dev = device_create(c2port_class, NULL, 0, c2dev,
"c2port%d", c2dev->id);
if (unlikely(IS_ERR(c2dev->dev))) {
@@ -919,12 +936,6 @@ struct c2port_device *c2port_device_register(char *name,
c2dev->ops = ops;
mutex_init(&c2dev->mutex);
- /* Create binary file */
- c2port_bin_attrs.size = ops->blocks_num * ops->block_size;
- ret = device_create_bin_file(c2dev->dev, &c2port_bin_attrs);
- if (unlikely(ret))
- goto error_device_create_bin_file;
-
/* By default C2 port access is off */
c2dev->access = c2dev->flash_access = 0;
ops->access(c2dev, 0);
@@ -937,9 +948,6 @@ struct c2port_device *c2port_device_register(char *name,
return c2dev;
-error_device_create_bin_file:
- device_destroy(c2port_class, 0);
-
error_device_create:
spin_lock_irq(&c2port_idr_lock);
idr_remove(&c2port_idr, c2dev->id);
@@ -959,7 +967,6 @@ void c2port_device_unregister(struct c2port_device *c2dev)
dev_info(c2dev->dev, "C2 port %s removed\n", c2dev->name);
- device_remove_bin_file(c2dev->dev, &c2port_bin_attrs);
spin_lock_irq(&c2port_idr_lock);
idr_remove(&c2port_idr, c2dev->id);
spin_unlock_irq(&c2port_idr_lock);
@@ -984,7 +991,7 @@ static int __init c2port_init(void)
printk(KERN_ERR "c2port: failed to allocate class\n");
return PTR_ERR(c2port_class);
}
- c2port_class->dev_attrs = c2port_attrs;
+ c2port_class->dev_groups = c2port_groups;
return 0;
}
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 00e5fcac8fd..0e8df41aaf1 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -239,7 +239,7 @@ static void enclosure_component_release(struct device *dev)
put_device(dev->parent);
}
-static const struct attribute_group *enclosure_groups[];
+static const struct attribute_group *enclosure_component_groups[];
/**
* enclosure_component_register - add a particular component to an enclosure
@@ -282,7 +282,7 @@ enclosure_component_register(struct enclosure_device *edev,
dev_set_name(cdev, "%u", number);
cdev->release = enclosure_component_release;
- cdev->groups = enclosure_groups;
+ cdev->groups = enclosure_component_groups;
err = device_register(cdev);
if (err) {
@@ -365,25 +365,26 @@ EXPORT_SYMBOL_GPL(enclosure_remove_device);
* sysfs pieces below
*/
-static ssize_t enclosure_show_components(struct device *cdev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t components_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
{
struct enclosure_device *edev = to_enclosure_device(cdev);
return snprintf(buf, 40, "%d\n", edev->components);
}
+static DEVICE_ATTR_RO(components);
-static struct device_attribute enclosure_attrs[] = {
- __ATTR(components, S_IRUGO, enclosure_show_components, NULL),
- __ATTR_NULL
+static struct attribute *enclosure_class_attrs[] = {
+ &dev_attr_components.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(enclosure_class);
static struct class enclosure_class = {
.name = "enclosure",
.owner = THIS_MODULE,
.dev_release = enclosure_release,
- .dev_attrs = enclosure_attrs,
+ .dev_groups = enclosure_class_groups,
};
static const char *const enclosure_status [] = {
@@ -536,15 +537,7 @@ static struct attribute *enclosure_component_attrs[] = {
&dev_attr_type.attr,
NULL
};
-
-static struct attribute_group enclosure_group = {
- .attrs = enclosure_component_attrs,
-};
-
-static const struct attribute_group *enclosure_groups[] = {
- &enclosure_group,
- NULL
-};
+ATTRIBUTE_GROUPS(enclosure_component);
static int __init enclosure_init(void)
{
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index 621c7a37339..b83e3ca12a4 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -759,7 +759,7 @@ static int ilo_probe(struct pci_dev *pdev,
/* Ignore subsystem_device = 0x1979 (set by BIOS) */
if (pdev->subsystem_device == 0x1979)
- goto out;
+ return 0;
if (max_ccb > MAX_CCB)
max_ccb = MAX_CCB;
@@ -899,7 +899,7 @@ static void __exit ilo_exit(void)
class_destroy(ilo_class);
}
-MODULE_VERSION("1.4");
+MODULE_VERSION("1.4.1");
MODULE_ALIAS(ILO_NAME);
MODULE_DESCRIPTION(ILO_NAME);
MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
diff --git a/drivers/misc/ics932s401.c b/drivers/misc/ics932s401.c
index 00295367c06..28f51e01fd2 100644
--- a/drivers/misc/ics932s401.c
+++ b/drivers/misc/ics932s401.c
@@ -2,7 +2,7 @@
* A driver for the Integrated Circuits ICS932S401
* Copyright (C) 2008 IBM
*
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -482,7 +482,7 @@ static int ics932s401_remove(struct i2c_client *client)
module_i2c_driver(ics932s401_driver);
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
MODULE_DESCRIPTION("ICS932S401 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 08aad69c8da..2fc0586ce3b 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -43,6 +43,7 @@
#include <linux/slab.h>
#include <scsi/scsi_cmnd.h>
#include <linux/debugfs.h>
+#include <linux/vmalloc.h>
#ifdef CONFIG_IDE
#include <linux/ide.h>
@@ -50,6 +51,7 @@
#define DEFAULT_COUNT 10
#define REC_NUM_DEFAULT 10
+#define EXEC_SIZE 64
enum cname {
CN_INVALID,
@@ -68,6 +70,7 @@ enum ctype {
CT_NONE,
CT_PANIC,
CT_BUG,
+ CT_WARNING,
CT_EXCEPTION,
CT_LOOP,
CT_OVERFLOW,
@@ -77,7 +80,12 @@ enum ctype {
CT_WRITE_AFTER_FREE,
CT_SOFTLOCKUP,
CT_HARDLOCKUP,
+ CT_SPINLOCKUP,
CT_HUNG_TASK,
+ CT_EXEC_DATA,
+ CT_EXEC_STACK,
+ CT_EXEC_KMALLOC,
+ CT_EXEC_VMALLOC,
};
static char* cp_name[] = {
@@ -95,6 +103,7 @@ static char* cp_name[] = {
static char* cp_type[] = {
"PANIC",
"BUG",
+ "WARNING",
"EXCEPTION",
"LOOP",
"OVERFLOW",
@@ -104,7 +113,12 @@ static char* cp_type[] = {
"WRITE_AFTER_FREE",
"SOFTLOCKUP",
"HARDLOCKUP",
+ "SPINLOCKUP",
"HUNG_TASK",
+ "EXEC_DATA",
+ "EXEC_STACK",
+ "EXEC_KMALLOC",
+ "EXEC_VMALLOC",
};
static struct jprobe lkdtm;
@@ -121,6 +135,9 @@ static enum cname cpoint = CN_INVALID;
static enum ctype cptype = CT_NONE;
static int count = DEFAULT_COUNT;
static DEFINE_SPINLOCK(count_lock);
+static DEFINE_SPINLOCK(lock_me_up);
+
+static u8 data_area[EXEC_SIZE];
module_param(recur_count, int, 0644);
MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\
@@ -275,6 +292,19 @@ static int recursive_loop(int a)
return recursive_loop(a);
}
+static void do_nothing(void)
+{
+ return;
+}
+
+static void execute_location(void *dst)
+{
+ void (*func)(void) = dst;
+
+ memcpy(dst, do_nothing, EXEC_SIZE);
+ func();
+}
+
static void lkdtm_do_action(enum ctype which)
{
switch (which) {
@@ -284,6 +314,9 @@ static void lkdtm_do_action(enum ctype which)
case CT_BUG:
BUG();
break;
+ case CT_WARNING:
+ WARN_ON(1);
+ break;
case CT_EXCEPTION:
*((int *) 0) = 0;
break;
@@ -295,10 +328,10 @@ static void lkdtm_do_action(enum ctype which)
(void) recursive_loop(0);
break;
case CT_CORRUPT_STACK: {
- volatile u32 data[8];
- volatile u32 *p = data;
+ /* Make sure the compiler creates and uses an 8 char array. */
+ volatile char data[8];
- p[12] = 0x12345678;
+ memset((void *)data, 0, 64);
break;
}
case CT_UNALIGNED_LOAD_STORE_WRITE: {
@@ -340,10 +373,34 @@ static void lkdtm_do_action(enum ctype which)
for (;;)
cpu_relax();
break;
+ case CT_SPINLOCKUP:
+ /* Must be called twice to trigger. */
+ spin_lock(&lock_me_up);
+ break;
case CT_HUNG_TASK:
set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
break;
+ case CT_EXEC_DATA:
+ execute_location(data_area);
+ break;
+ case CT_EXEC_STACK: {
+ u8 stack_area[EXEC_SIZE];
+ execute_location(stack_area);
+ break;
+ }
+ case CT_EXEC_KMALLOC: {
+ u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL);
+ execute_location(kmalloc_area);
+ kfree(kmalloc_area);
+ break;
+ }
+ case CT_EXEC_VMALLOC: {
+ u32 *vmalloc_area = vmalloc(EXEC_SIZE);
+ execute_location(vmalloc_area);
+ vfree(vmalloc_area);
+ break;
+ }
case CT_NONE:
default:
break;
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 749452f8e2f..d0fdc134068 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -418,15 +418,23 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
struct file *file, poll_table *wait)
{
unsigned int mask = 0;
- mutex_unlock(&dev->device_lock);
+
poll_wait(file, &dev->iamthif_cl.wait, wait);
+
mutex_lock(&dev->device_lock);
- if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
- dev->iamthif_file_object == file) {
+ if (!mei_cl_is_connected(&dev->iamthif_cl)) {
+
+ mask = POLLERR;
+
+ } else if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
+ dev->iamthif_file_object == file) {
+
mask |= (POLLIN | POLLRDNORM);
dev_dbg(&dev->pdev->dev, "run next amthif cb\n");
mei_amthif_run_next_cmd(dev);
}
+ mutex_unlock(&dev->device_lock);
+
return mask;
}
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 9ecd49a7be1..6d0282c08a0 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -47,7 +47,7 @@ static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
id = driver->id_table;
while (id->name[0]) {
- if (!strcmp(dev_name(dev), id->name))
+ if (!strncmp(dev_name(dev), id->name, sizeof(id->name)))
return 1;
id++;
@@ -71,7 +71,7 @@ static int mei_cl_device_probe(struct device *dev)
dev_dbg(dev, "Device probe\n");
- strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE);
+ strncpy(id.name, dev_name(dev), sizeof(id.name));
return driver->probe(device, &id);
}
@@ -108,11 +108,13 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
+static DEVICE_ATTR_RO(modalias);
-static struct device_attribute mei_cl_dev_attrs[] = {
- __ATTR_RO(modalias),
- __ATTR_NULL,
+static struct attribute *mei_cl_dev_attrs[] = {
+ &dev_attr_modalias.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(mei_cl_dev);
static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
{
@@ -124,7 +126,7 @@ static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
static struct bus_type mei_cl_bus_type = {
.name = "mei",
- .dev_attrs = mei_cl_dev_attrs,
+ .dev_groups = mei_cl_dev_groups,
.match = mei_cl_device_match,
.probe = mei_cl_device_probe,
.remove = mei_cl_device_remove,
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 21d3f5aa835..e0684b4d9a0 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -635,10 +635,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
dev = cl->dev;
- if (cl->state != MEI_FILE_CONNECTED)
- return -ENODEV;
-
- if (dev->dev_state != MEI_DEV_ENABLED)
+ if (!mei_cl_is_connected(cl))
return -ENODEV;
if (cl->read_cb) {
@@ -892,18 +889,22 @@ void mei_cl_all_disconnect(struct mei_device *dev)
/**
- * mei_cl_all_read_wakeup - wake up all readings so they can be interrupted
+ * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
*
* @dev - mei device
*/
-void mei_cl_all_read_wakeup(struct mei_device *dev)
+void mei_cl_all_wakeup(struct mei_device *dev)
{
struct mei_cl *cl, *next;
list_for_each_entry_safe(cl, next, &dev->file_list, link) {
if (waitqueue_active(&cl->rx_wait)) {
- dev_dbg(&dev->pdev->dev, "Waking up client!\n");
+ dev_dbg(&dev->pdev->dev, "Waking up reading client!\n");
wake_up_interruptible(&cl->rx_wait);
}
+ if (waitqueue_active(&cl->tx_wait)) {
+ dev_dbg(&dev->pdev->dev, "Waking up writing client!\n");
+ wake_up_interruptible(&cl->tx_wait);
+ }
}
}
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 26b157d8bad..9eb031e9207 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -84,6 +84,13 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
/*
* MEI input output function prototype
*/
+static inline bool mei_cl_is_connected(struct mei_cl *cl)
+{
+ return (cl->dev &&
+ cl->dev->dev_state == MEI_DEV_ENABLED &&
+ cl->state == MEI_FILE_CONNECTED);
+}
+
bool mei_cl_is_other_connecting(struct mei_cl *cl);
int mei_cl_disconnect(struct mei_cl *cl);
int mei_cl_connect(struct mei_cl *cl, struct file *file);
@@ -99,7 +106,7 @@ void mei_host_client_init(struct work_struct *work);
void mei_cl_all_disconnect(struct mei_device *dev);
-void mei_cl_all_read_wakeup(struct mei_device *dev);
+void mei_cl_all_wakeup(struct mei_device *dev);
void mei_cl_all_write_clear(struct mei_device *dev);
#endif /* _MEI_CLIENT_H_ */
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index f9296abcf02..6127ab64bb3 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -167,7 +167,7 @@ int mei_hbm_start_req(struct mei_device *dev)
dev->hbm_state = MEI_HBM_IDLE;
if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
- dev_err(&dev->pdev->dev, "version message writet failed\n");
+ dev_err(&dev->pdev->dev, "version message write failed\n");
dev->dev_state = MEI_DEV_RESETTING;
mei_reset(dev, 1);
return -ENODEV;
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index e4f8dec4dc3..3412adcdaeb 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -176,21 +176,18 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
- dev_dbg(&dev->pdev->dev, "before reset HCSR = 0x%08x.\n", hcsr);
-
- hcsr |= (H_RST | H_IG);
+ hcsr |= H_RST | H_IG | H_IS;
if (intr_enable)
hcsr |= H_IE;
else
- hcsr |= ~H_IE;
+ hcsr &= ~H_IE;
- mei_hcsr_set(hw, hcsr);
+ mei_me_reg_write(hw, H_CSR, hcsr);
if (dev->dev_state == MEI_DEV_POWER_DOWN)
mei_me_hw_reset_release(dev);
- dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", mei_hcsr_read(hw));
return 0;
}
@@ -239,14 +236,18 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
if (mei_me_hw_is_ready(dev))
return 0;
+ dev->recvd_hw_ready = false;
mutex_unlock(&dev->device_lock);
err = wait_event_interruptible_timeout(dev->wait_hw_ready,
- dev->recvd_hw_ready, MEI_INTEROP_TIMEOUT);
+ dev->recvd_hw_ready,
+ mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
mutex_lock(&dev->device_lock);
if (!err && !dev->recvd_hw_ready) {
+ if (!err)
+ err = -ETIMEDOUT;
dev_err(&dev->pdev->dev,
- "wait hw ready failed. status = 0x%x\n", err);
- return -ETIMEDOUT;
+ "wait hw ready failed. status = %d\n", err);
+ return err;
}
dev->recvd_hw_ready = false;
@@ -483,7 +484,9 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
/* check if ME wants a reset */
if (!mei_hw_is_ready(dev) &&
dev->dev_state != MEI_DEV_RESETTING &&
- dev->dev_state != MEI_DEV_INITIALIZING) {
+ dev->dev_state != MEI_DEV_INITIALIZING &&
+ dev->dev_state != MEI_DEV_POWER_DOWN &&
+ dev->dev_state != MEI_DEV_POWER_UP) {
dev_dbg(&dev->pdev->dev, "FW not ready.\n");
mei_reset(dev, 1);
mutex_unlock(&dev->device_lock);
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index ed1d75203af..92c73118b13 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -148,13 +148,20 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
dev->hbm_state = MEI_HBM_IDLE;
- if (dev->dev_state != MEI_DEV_INITIALIZING) {
+ if (dev->dev_state != MEI_DEV_INITIALIZING &&
+ dev->dev_state != MEI_DEV_POWER_UP) {
if (dev->dev_state != MEI_DEV_DISABLED &&
dev->dev_state != MEI_DEV_POWER_DOWN)
dev->dev_state = MEI_DEV_RESETTING;
+ /* remove all waiting requests */
+ mei_cl_all_write_clear(dev);
+
mei_cl_all_disconnect(dev);
+ /* wake up all readings so they can be interrupted */
+ mei_cl_all_wakeup(dev);
+
/* remove entry if already in list */
dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
mei_cl_unlink(&dev->wd_cl);
@@ -195,11 +202,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
mei_hbm_start_req(dev);
- /* wake up all readings so they can be interrupted */
- mei_cl_all_read_wakeup(dev);
-
- /* remove all waiting requests */
- mei_cl_all_write_clear(dev);
}
EXPORT_SYMBOL_GPL(mei_reset);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 5e11b5b9b65..173ff095be0 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -625,24 +625,32 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
unsigned int mask = 0;
if (WARN_ON(!cl || !cl->dev))
- return mask;
+ return POLLERR;
dev = cl->dev;
mutex_lock(&dev->device_lock);
- if (dev->dev_state != MEI_DEV_ENABLED)
- goto out;
-
-
- if (cl == &dev->iamthif_cl) {
- mask = mei_amthif_poll(dev, file, wait);
+ if (!mei_cl_is_connected(cl)) {
+ mask = POLLERR;
goto out;
}
mutex_unlock(&dev->device_lock);
+
+
+ if (cl == &dev->iamthif_cl)
+ return mei_amthif_poll(dev, file, wait);
+
poll_wait(file, &cl->tx_wait, wait);
+
mutex_lock(&dev->device_lock);
+
+ if (!mei_cl_is_connected(cl)) {
+ mask = POLLERR;
+ goto out;
+ }
+
if (MEI_WRITE_COMPLETE == cl->writing_state)
mask |= (POLLIN | POLLRDNORM);
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index d87cc91bc01..afe66571ce0 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -68,7 +68,8 @@ static int sram_probe(struct platform_device *pdev)
ret = gen_pool_add_virt(sram->pool, (unsigned long)virt_base,
res->start, size, -1);
if (ret < 0) {
- gen_pool_destroy(sram->pool);
+ if (sram->clk)
+ clk_disable_unprepare(sram->clk);
return ret;
}
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 0a142801635..8d64b681dd9 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -562,7 +562,9 @@ long st_register(struct st_proto_s *new_proto)
if ((st_gdata->protos_registered != ST_EMPTY) &&
(test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
pr_err(" KIM failure complete callback ");
+ spin_lock_irqsave(&st_gdata->lock, flags);
st_reg_complete(st_gdata, err);
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
clear_bit(ST_REG_PENDING, &st_gdata->st_state);
}
return -EINVAL;
diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c
index cb56e270da1..2421835d5da 100644
--- a/drivers/misc/vmw_balloon.c
+++ b/drivers/misc/vmw_balloon.c
@@ -133,7 +133,7 @@ MODULE_LICENSE("GPL");
#define VMWARE_BALLOON_CMD(cmd, data, result) \
({ \
unsigned long __stat, __dummy1, __dummy2; \
- __asm__ __volatile__ ("inl (%%dx)" : \
+ __asm__ __volatile__ ("inl %%dx" : \
"=a"(__stat), \
"=c"(__dummy1), \
"=d"(__dummy2), \
diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c
index 7b3fce2da6c..3dee7ae123e 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.c
+++ b/drivers/misc/vmw_vmci/vmci_driver.c
@@ -113,5 +113,5 @@ module_exit(vmci_drv_exit);
MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface.");
-MODULE_VERSION("1.0.0.0-k");
+MODULE_VERSION("1.1.0.0-k");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/vmw_vmci/vmci_driver.h b/drivers/misc/vmw_vmci/vmci_driver.h
index f69156a1f30..cee9e977d31 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.h
+++ b/drivers/misc/vmw_vmci/vmci_driver.h
@@ -35,6 +35,13 @@ struct vmci_obj {
enum vmci_obj_type type;
};
+/*
+ * Needed by other components of this module. It's okay to have one global
+ * instance of this because there can only ever be one VMCI device. Our
+ * virtual hardware enforces this.
+ */
+extern struct pci_dev *vmci_pdev;
+
u32 vmci_get_context_id(void);
int vmci_send_datagram(struct vmci_datagram *dg);
diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c
index 60c01999f48..b3a2b763ecf 100644
--- a/drivers/misc/vmw_vmci/vmci_guest.c
+++ b/drivers/misc/vmw_vmci/vmci_guest.c
@@ -65,9 +65,11 @@ struct vmci_guest_device {
void *data_buffer;
void *notification_bitmap;
+ dma_addr_t notification_base;
};
/* vmci_dev singleton device and supporting data*/
+struct pci_dev *vmci_pdev;
static struct vmci_guest_device *vmci_dev_g;
static DEFINE_SPINLOCK(vmci_dev_spinlock);
@@ -528,7 +530,9 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
* well.
*/
if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
- vmci_dev->notification_bitmap = vmalloc(PAGE_SIZE);
+ vmci_dev->notification_bitmap = dma_alloc_coherent(
+ &pdev->dev, PAGE_SIZE, &vmci_dev->notification_base,
+ GFP_KERNEL);
if (!vmci_dev->notification_bitmap) {
dev_warn(&pdev->dev,
"Unable to allocate notification bitmap\n");
@@ -546,6 +550,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
/* Set up global device so that we can start sending datagrams */
spin_lock_irq(&vmci_dev_spinlock);
vmci_dev_g = vmci_dev;
+ vmci_pdev = pdev;
spin_unlock_irq(&vmci_dev_spinlock);
/*
@@ -553,9 +558,8 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
* used.
*/
if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
- struct page *page =
- vmalloc_to_page(vmci_dev->notification_bitmap);
- unsigned long bitmap_ppn = page_to_pfn(page);
+ unsigned long bitmap_ppn =
+ vmci_dev->notification_base >> PAGE_SHIFT;
if (!vmci_dbell_register_notification_bitmap(bitmap_ppn)) {
dev_warn(&pdev->dev,
"VMCI device unable to register notification bitmap with PPN 0x%x\n",
@@ -665,11 +669,14 @@ err_remove_bitmap:
if (vmci_dev->notification_bitmap) {
iowrite32(VMCI_CONTROL_RESET,
vmci_dev->iobase + VMCI_CONTROL_ADDR);
- vfree(vmci_dev->notification_bitmap);
+ dma_free_coherent(&pdev->dev, PAGE_SIZE,
+ vmci_dev->notification_bitmap,
+ vmci_dev->notification_base);
}
err_remove_vmci_dev_g:
spin_lock_irq(&vmci_dev_spinlock);
+ vmci_pdev = NULL;
vmci_dev_g = NULL;
spin_unlock_irq(&vmci_dev_spinlock);
@@ -699,6 +706,7 @@ static void vmci_guest_remove_device(struct pci_dev *pdev)
spin_lock_irq(&vmci_dev_spinlock);
vmci_dev_g = NULL;
+ vmci_pdev = NULL;
spin_unlock_irq(&vmci_dev_spinlock);
dev_dbg(&pdev->dev, "Resetting vmci device\n");
@@ -727,7 +735,9 @@ static void vmci_guest_remove_device(struct pci_dev *pdev)
* device, so we can safely free it here.
*/
- vfree(vmci_dev->notification_bitmap);
+ dma_free_coherent(&pdev->dev, PAGE_SIZE,
+ vmci_dev->notification_bitmap,
+ vmci_dev->notification_base);
}
vfree(vmci_dev->data_buffer);
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index 8ff2e5ee8fb..a0515a6d6eb 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pagemap.h>
+#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uio.h>
@@ -146,14 +147,20 @@ typedef int vmci_memcpy_from_queue_func(void *dest, size_t dest_offset,
/* The Kernel specific component of the struct vmci_queue structure. */
struct vmci_queue_kern_if {
- struct page **page;
- struct page **header_page;
- void *va;
struct mutex __mutex; /* Protects the queue. */
struct mutex *mutex; /* Shared by producer and consumer queues. */
- bool host;
- size_t num_pages;
- bool mapped;
+ size_t num_pages; /* Number of pages incl. header. */
+ bool host; /* Host or guest? */
+ union {
+ struct {
+ dma_addr_t *pas;
+ void **vas;
+ } g; /* Used by the guest. */
+ struct {
+ struct page **page;
+ struct page **header_page;
+ } h; /* Used by the host. */
+ } u;
};
/*
@@ -265,76 +272,65 @@ static void qp_free_queue(void *q, u64 size)
struct vmci_queue *queue = q;
if (queue) {
- u64 i = DIV_ROUND_UP(size, PAGE_SIZE);
+ u64 i;
- if (queue->kernel_if->mapped) {
- vunmap(queue->kernel_if->va);
- queue->kernel_if->va = NULL;
+ /* Given size does not include header, so add in a page here. */
+ for (i = 0; i < DIV_ROUND_UP(size, PAGE_SIZE) + 1; i++) {
+ dma_free_coherent(&vmci_pdev->dev, PAGE_SIZE,
+ queue->kernel_if->u.g.vas[i],
+ queue->kernel_if->u.g.pas[i]);
}
- while (i)
- __free_page(queue->kernel_if->page[--i]);
-
- vfree(queue->q_header);
+ vfree(queue);
}
}
/*
- * Allocates kernel VA space of specified size, plus space for the
- * queue structure/kernel interface and the queue header. Allocates
- * physical pages for the queue data pages.
- *
- * PAGE m: struct vmci_queue_header (struct vmci_queue->q_header)
- * PAGE m+1: struct vmci_queue
- * PAGE m+1+q: struct vmci_queue_kern_if (struct vmci_queue->kernel_if)
- * PAGE n-size: Data pages (struct vmci_queue->kernel_if->page[])
+ * Allocates kernel queue pages of specified size with IOMMU mappings,
+ * plus space for the queue structure/kernel interface and the queue
+ * header.
*/
static void *qp_alloc_queue(u64 size, u32 flags)
{
u64 i;
struct vmci_queue *queue;
- struct vmci_queue_header *q_header;
- const u64 num_data_pages = DIV_ROUND_UP(size, PAGE_SIZE);
- const uint queue_size =
- PAGE_SIZE +
- sizeof(*queue) + sizeof(*(queue->kernel_if)) +
- num_data_pages * sizeof(*(queue->kernel_if->page));
-
- q_header = vmalloc(queue_size);
- if (!q_header)
+ const size_t num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
+ const size_t pas_size = num_pages * sizeof(*queue->kernel_if->u.g.pas);
+ const size_t vas_size = num_pages * sizeof(*queue->kernel_if->u.g.vas);
+ const size_t queue_size =
+ sizeof(*queue) + sizeof(*queue->kernel_if) +
+ pas_size + vas_size;
+
+ queue = vmalloc(queue_size);
+ if (!queue)
return NULL;
- queue = (void *)q_header + PAGE_SIZE;
- queue->q_header = q_header;
+ queue->q_header = NULL;
queue->saved_header = NULL;
queue->kernel_if = (struct vmci_queue_kern_if *)(queue + 1);
- queue->kernel_if->header_page = NULL; /* Unused in guest. */
- queue->kernel_if->page = (struct page **)(queue->kernel_if + 1);
+ queue->kernel_if->mutex = NULL;
+ queue->kernel_if->num_pages = num_pages;
+ queue->kernel_if->u.g.pas = (dma_addr_t *)(queue->kernel_if + 1);
+ queue->kernel_if->u.g.vas =
+ (void **)((u8 *)queue->kernel_if->u.g.pas + pas_size);
queue->kernel_if->host = false;
- queue->kernel_if->va = NULL;
- queue->kernel_if->mapped = false;
-
- for (i = 0; i < num_data_pages; i++) {
- queue->kernel_if->page[i] = alloc_pages(GFP_KERNEL, 0);
- if (!queue->kernel_if->page[i])
- goto fail;
- }
- if (vmci_qp_pinned(flags)) {
- queue->kernel_if->va =
- vmap(queue->kernel_if->page, num_data_pages, VM_MAP,
- PAGE_KERNEL);
- if (!queue->kernel_if->va)
- goto fail;
-
- queue->kernel_if->mapped = true;
+ for (i = 0; i < num_pages; i++) {
+ queue->kernel_if->u.g.vas[i] =
+ dma_alloc_coherent(&vmci_pdev->dev, PAGE_SIZE,
+ &queue->kernel_if->u.g.pas[i],
+ GFP_KERNEL);
+ if (!queue->kernel_if->u.g.vas[i]) {
+ /* Size excl. the header. */
+ qp_free_queue(queue, i * PAGE_SIZE);
+ return NULL;
+ }
}
- return (void *)queue;
+ /* Queue header is the first page. */
+ queue->q_header = queue->kernel_if->u.g.vas[0];
- fail:
- qp_free_queue(queue, i * PAGE_SIZE);
- return NULL;
+ return queue;
}
/*
@@ -353,17 +349,18 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue,
size_t bytes_copied = 0;
while (bytes_copied < size) {
- u64 page_index = (queue_offset + bytes_copied) / PAGE_SIZE;
- size_t page_offset =
+ const u64 page_index =
+ (queue_offset + bytes_copied) / PAGE_SIZE;
+ const size_t page_offset =
(queue_offset + bytes_copied) & (PAGE_SIZE - 1);
void *va;
size_t to_copy;
- if (!kernel_if->mapped)
- va = kmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ va = kmap(kernel_if->u.h.page[page_index]);
else
- va = (void *)((u8 *)kernel_if->va +
- (page_index * PAGE_SIZE));
+ va = kernel_if->u.g.vas[page_index + 1];
+ /* Skip header. */
if (size - bytes_copied > PAGE_SIZE - page_offset)
/* Enough payload to fill up from this page. */
@@ -379,7 +376,8 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue,
err = memcpy_fromiovec((u8 *)va + page_offset,
iov, to_copy);
if (err != 0) {
- kunmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ kunmap(kernel_if->u.h.page[page_index]);
return VMCI_ERROR_INVALID_ARGS;
}
} else {
@@ -388,8 +386,8 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue,
}
bytes_copied += to_copy;
- if (!kernel_if->mapped)
- kunmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ kunmap(kernel_if->u.h.page[page_index]);
}
return VMCI_SUCCESS;
@@ -411,17 +409,18 @@ static int __qp_memcpy_from_queue(void *dest,
size_t bytes_copied = 0;
while (bytes_copied < size) {
- u64 page_index = (queue_offset + bytes_copied) / PAGE_SIZE;
- size_t page_offset =
+ const u64 page_index =
+ (queue_offset + bytes_copied) / PAGE_SIZE;
+ const size_t page_offset =
(queue_offset + bytes_copied) & (PAGE_SIZE - 1);
void *va;
size_t to_copy;
- if (!kernel_if->mapped)
- va = kmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ va = kmap(kernel_if->u.h.page[page_index]);
else
- va = (void *)((u8 *)kernel_if->va +
- (page_index * PAGE_SIZE));
+ va = kernel_if->u.g.vas[page_index + 1];
+ /* Skip header. */
if (size - bytes_copied > PAGE_SIZE - page_offset)
/* Enough payload to fill up this page. */
@@ -437,7 +436,8 @@ static int __qp_memcpy_from_queue(void *dest,
err = memcpy_toiovec(iov, (u8 *)va + page_offset,
to_copy);
if (err != 0) {
- kunmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ kunmap(kernel_if->u.h.page[page_index]);
return VMCI_ERROR_INVALID_ARGS;
}
} else {
@@ -446,8 +446,8 @@ static int __qp_memcpy_from_queue(void *dest,
}
bytes_copied += to_copy;
- if (!kernel_if->mapped)
- kunmap(kernel_if->page[page_index]);
+ if (kernel_if->host)
+ kunmap(kernel_if->u.h.page[page_index]);
}
return VMCI_SUCCESS;
@@ -489,12 +489,11 @@ static int qp_alloc_ppn_set(void *prod_q,
return VMCI_ERROR_NO_MEM;
}
- produce_ppns[0] = page_to_pfn(vmalloc_to_page(produce_q->q_header));
- for (i = 1; i < num_produce_pages; i++) {
+ for (i = 0; i < num_produce_pages; i++) {
unsigned long pfn;
produce_ppns[i] =
- page_to_pfn(produce_q->kernel_if->page[i - 1]);
+ produce_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT;
pfn = produce_ppns[i];
/* Fail allocation if PFN isn't supported by hypervisor. */
@@ -503,12 +502,11 @@ static int qp_alloc_ppn_set(void *prod_q,
goto ppn_error;
}
- consume_ppns[0] = page_to_pfn(vmalloc_to_page(consume_q->q_header));
- for (i = 1; i < num_consume_pages; i++) {
+ for (i = 0; i < num_consume_pages; i++) {
unsigned long pfn;
consume_ppns[i] =
- page_to_pfn(consume_q->kernel_if->page[i - 1]);
+ consume_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT;
pfn = consume_ppns[i];
/* Fail allocation if PFN isn't supported by hypervisor. */
@@ -619,23 +617,20 @@ static struct vmci_queue *qp_host_alloc_queue(u64 size)
const size_t num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
const size_t queue_size = sizeof(*queue) + sizeof(*(queue->kernel_if));
const size_t queue_page_size =
- num_pages * sizeof(*queue->kernel_if->page);
+ num_pages * sizeof(*queue->kernel_if->u.h.page);
queue = kzalloc(queue_size + queue_page_size, GFP_KERNEL);
if (queue) {
queue->q_header = NULL;
queue->saved_header = NULL;
- queue->kernel_if =
- (struct vmci_queue_kern_if *)((u8 *)queue +
- sizeof(*queue));
+ queue->kernel_if = (struct vmci_queue_kern_if *)(queue + 1);
queue->kernel_if->host = true;
queue->kernel_if->mutex = NULL;
queue->kernel_if->num_pages = num_pages;
- queue->kernel_if->header_page =
+ queue->kernel_if->u.h.header_page =
(struct page **)((u8 *)queue + queue_size);
- queue->kernel_if->page = &queue->kernel_if->header_page[1];
- queue->kernel_if->va = NULL;
- queue->kernel_if->mapped = false;
+ queue->kernel_if->u.h.page =
+ &queue->kernel_if->u.h.header_page[1];
}
return queue;
@@ -742,11 +737,12 @@ static int qp_host_get_user_memory(u64 produce_uva,
current->mm,
(uintptr_t) produce_uva,
produce_q->kernel_if->num_pages,
- 1, 0, produce_q->kernel_if->header_page, NULL);
+ 1, 0,
+ produce_q->kernel_if->u.h.header_page, NULL);
if (retval < produce_q->kernel_if->num_pages) {
pr_warn("get_user_pages(produce) failed (retval=%d)", retval);
- qp_release_pages(produce_q->kernel_if->header_page, retval,
- false);
+ qp_release_pages(produce_q->kernel_if->u.h.header_page,
+ retval, false);
err = VMCI_ERROR_NO_MEM;
goto out;
}
@@ -755,12 +751,13 @@ static int qp_host_get_user_memory(u64 produce_uva,
current->mm,
(uintptr_t) consume_uva,
consume_q->kernel_if->num_pages,
- 1, 0, consume_q->kernel_if->header_page, NULL);
+ 1, 0,
+ consume_q->kernel_if->u.h.header_page, NULL);
if (retval < consume_q->kernel_if->num_pages) {
pr_warn("get_user_pages(consume) failed (retval=%d)", retval);
- qp_release_pages(consume_q->kernel_if->header_page, retval,
- false);
- qp_release_pages(produce_q->kernel_if->header_page,
+ qp_release_pages(consume_q->kernel_if->u.h.header_page,
+ retval, false);
+ qp_release_pages(produce_q->kernel_if->u.h.header_page,
produce_q->kernel_if->num_pages, false);
err = VMCI_ERROR_NO_MEM;
}
@@ -803,15 +800,15 @@ static int qp_host_register_user_memory(struct vmci_qp_page_store *page_store,
static void qp_host_unregister_user_memory(struct vmci_queue *produce_q,
struct vmci_queue *consume_q)
{
- qp_release_pages(produce_q->kernel_if->header_page,
+ qp_release_pages(produce_q->kernel_if->u.h.header_page,
produce_q->kernel_if->num_pages, true);
- memset(produce_q->kernel_if->header_page, 0,
- sizeof(*produce_q->kernel_if->header_page) *
+ memset(produce_q->kernel_if->u.h.header_page, 0,
+ sizeof(*produce_q->kernel_if->u.h.header_page) *
produce_q->kernel_if->num_pages);
- qp_release_pages(consume_q->kernel_if->header_page,
+ qp_release_pages(consume_q->kernel_if->u.h.header_page,
consume_q->kernel_if->num_pages, true);
- memset(consume_q->kernel_if->header_page, 0,
- sizeof(*consume_q->kernel_if->header_page) *
+ memset(consume_q->kernel_if->u.h.header_page, 0,
+ sizeof(*consume_q->kernel_if->u.h.header_page) *
consume_q->kernel_if->num_pages);
}
@@ -834,12 +831,12 @@ static int qp_host_map_queues(struct vmci_queue *produce_q,
if (produce_q->q_header != consume_q->q_header)
return VMCI_ERROR_QUEUEPAIR_MISMATCH;
- if (produce_q->kernel_if->header_page == NULL ||
- *produce_q->kernel_if->header_page == NULL)
+ if (produce_q->kernel_if->u.h.header_page == NULL ||
+ *produce_q->kernel_if->u.h.header_page == NULL)
return VMCI_ERROR_UNAVAILABLE;
- headers[0] = *produce_q->kernel_if->header_page;
- headers[1] = *consume_q->kernel_if->header_page;
+ headers[0] = *produce_q->kernel_if->u.h.header_page;
+ headers[1] = *consume_q->kernel_if->u.h.header_page;
produce_q->q_header = vmap(headers, 2, VM_MAP, PAGE_KERNEL);
if (produce_q->q_header != NULL) {
@@ -1720,21 +1717,6 @@ static int qp_broker_attach(struct qp_broker_entry *entry,
if (result < VMCI_SUCCESS)
return result;
- /*
- * Preemptively load in the headers if non-blocking to
- * prevent blocking later.
- */
- if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
- result = qp_host_map_queues(entry->produce_q,
- entry->consume_q);
- if (result < VMCI_SUCCESS) {
- qp_host_unregister_user_memory(
- entry->produce_q,
- entry->consume_q);
- return result;
- }
- }
-
entry->state = VMCIQPB_ATTACHED_MEM;
} else {
entry->state = VMCIQPB_ATTACHED_NO_MEM;
@@ -1749,24 +1731,6 @@ static int qp_broker_attach(struct qp_broker_entry *entry,
return VMCI_ERROR_UNAVAILABLE;
} else {
- /*
- * For non-blocking queue pairs, we cannot rely on
- * enqueue/dequeue to map in the pages on the
- * host-side, since it may block, so we make an
- * attempt here.
- */
-
- if (flags & VMCI_QPFLAG_NONBLOCK) {
- result =
- qp_host_map_queues(entry->produce_q,
- entry->consume_q);
- if (result < VMCI_SUCCESS)
- return result;
-
- entry->qp.flags |= flags &
- (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED);
- }
-
/* The host side has successfully attached to a queue pair. */
entry->state = VMCIQPB_ATTACHED_MEM;
}
@@ -2543,24 +2507,19 @@ void vmci_qp_guest_endpoints_exit(void)
* Since non-blocking isn't yet implemented on the host personality we
* have no reason to acquire a spin lock. So to avoid the use of an
* unnecessary lock only acquire the mutex if we can block.
- * Note: It is assumed that QPFLAG_PINNED implies QPFLAG_NONBLOCK. Therefore
- * we can use the same locking function for access to both the queue
- * and the queue headers as it is the same logic. Assert this behvior.
*/
static void qp_lock(const struct vmci_qp *qpair)
{
- if (vmci_can_block(qpair->flags))
- qp_acquire_queue_mutex(qpair->produce_q);
+ qp_acquire_queue_mutex(qpair->produce_q);
}
/*
* Helper routine that unlocks the queue pair after calling
- * qp_lock. Respects non-blocking and pinning flags.
+ * qp_lock.
*/
static void qp_unlock(const struct vmci_qp *qpair)
{
- if (vmci_can_block(qpair->flags))
- qp_release_queue_mutex(qpair->produce_q);
+ qp_release_queue_mutex(qpair->produce_q);
}
/*
@@ -2568,17 +2527,12 @@ static void qp_unlock(const struct vmci_qp *qpair)
* currently not mapped, it will be attempted to do so.
*/
static int qp_map_queue_headers(struct vmci_queue *produce_q,
- struct vmci_queue *consume_q,
- bool can_block)
+ struct vmci_queue *consume_q)
{
int result;
if (NULL == produce_q->q_header || NULL == consume_q->q_header) {
- if (can_block)
- result = qp_host_map_queues(produce_q, consume_q);
- else
- result = VMCI_ERROR_QUEUEPAIR_NOT_READY;
-
+ result = qp_host_map_queues(produce_q, consume_q);
if (result < VMCI_SUCCESS)
return (produce_q->saved_header &&
consume_q->saved_header) ?
@@ -2601,8 +2555,7 @@ static int qp_get_queue_headers(const struct vmci_qp *qpair,
{
int result;
- result = qp_map_queue_headers(qpair->produce_q, qpair->consume_q,
- vmci_can_block(qpair->flags));
+ result = qp_map_queue_headers(qpair->produce_q, qpair->consume_q);
if (result == VMCI_SUCCESS) {
*produce_q_header = qpair->produce_q->q_header;
*consume_q_header = qpair->consume_q->q_header;
@@ -2645,9 +2598,6 @@ static bool qp_wait_for_ready_queue(struct vmci_qp *qpair)
{
unsigned int generation;
- if (qpair->flags & VMCI_QPFLAG_NONBLOCK)
- return false;
-
qpair->blocked++;
generation = qpair->generation;
qp_unlock(qpair);
@@ -2674,15 +2624,14 @@ static ssize_t qp_enqueue_locked(struct vmci_queue *produce_q,
const u64 produce_q_size,
const void *buf,
size_t buf_size,
- vmci_memcpy_to_queue_func memcpy_to_queue,
- bool can_block)
+ vmci_memcpy_to_queue_func memcpy_to_queue)
{
s64 free_space;
u64 tail;
size_t written;
ssize_t result;
- result = qp_map_queue_headers(produce_q, consume_q, can_block);
+ result = qp_map_queue_headers(produce_q, consume_q);
if (unlikely(result != VMCI_SUCCESS))
return result;
@@ -2737,15 +2686,14 @@ static ssize_t qp_dequeue_locked(struct vmci_queue *produce_q,
void *buf,
size_t buf_size,
vmci_memcpy_from_queue_func memcpy_from_queue,
- bool update_consumer,
- bool can_block)
+ bool update_consumer)
{
s64 buf_ready;
u64 head;
size_t read;
ssize_t result;
- result = qp_map_queue_headers(produce_q, consume_q, can_block);
+ result = qp_map_queue_headers(produce_q, consume_q);
if (unlikely(result != VMCI_SUCCESS))
return result;
@@ -2842,32 +2790,11 @@ int vmci_qpair_alloc(struct vmci_qp **qpair,
route = vmci_guest_code_active() ?
VMCI_ROUTE_AS_GUEST : VMCI_ROUTE_AS_HOST;
- /* If NONBLOCK or PINNED is set, we better be the guest personality. */
- if ((!vmci_can_block(flags) || vmci_qp_pinned(flags)) &&
- VMCI_ROUTE_AS_GUEST != route) {
- pr_devel("Not guest personality w/ NONBLOCK OR PINNED set");
+ if (flags & (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED)) {
+ pr_devel("NONBLOCK OR PINNED set");
return VMCI_ERROR_INVALID_ARGS;
}
- /*
- * Limit the size of pinned QPs and check sanity.
- *
- * Pinned pages implies non-blocking mode. Mutexes aren't acquired
- * when the NONBLOCK flag is set in qpair code; and also should not be
- * acquired when the PINNED flagged is set. Since pinning pages
- * implies we want speed, it makes no sense not to have NONBLOCK
- * set if PINNED is set. Hence enforce this implication.
- */
- if (vmci_qp_pinned(flags)) {
- if (vmci_can_block(flags)) {
- pr_err("Attempted to enable pinning w/o non-blocking");
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (produce_qsize + consume_qsize > VMCI_MAX_PINNED_QP_MEMORY)
- return VMCI_ERROR_NO_RESOURCES;
- }
-
my_qpair = kzalloc(sizeof(*my_qpair), GFP_KERNEL);
if (!my_qpair)
return VMCI_ERROR_NO_MEM;
@@ -3195,8 +3122,7 @@ ssize_t vmci_qpair_enqueue(struct vmci_qp *qpair,
qpair->consume_q,
qpair->produce_q_size,
buf, buf_size,
- qp_memcpy_to_queue,
- vmci_can_block(qpair->flags));
+ qp_memcpy_to_queue);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
@@ -3237,8 +3163,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_qp *qpair,
qpair->consume_q,
qpair->consume_q_size,
buf, buf_size,
- qp_memcpy_from_queue, true,
- vmci_can_block(qpair->flags));
+ qp_memcpy_from_queue, true);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
@@ -3280,8 +3205,7 @@ ssize_t vmci_qpair_peek(struct vmci_qp *qpair,
qpair->consume_q,
qpair->consume_q_size,
buf, buf_size,
- qp_memcpy_from_queue, false,
- vmci_can_block(qpair->flags));
+ qp_memcpy_from_queue, false);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
@@ -3323,8 +3247,7 @@ ssize_t vmci_qpair_enquev(struct vmci_qp *qpair,
qpair->consume_q,
qpair->produce_q_size,
iov, iov_size,
- qp_memcpy_to_queue_iov,
- vmci_can_block(qpair->flags));
+ qp_memcpy_to_queue_iov);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
@@ -3367,7 +3290,7 @@ ssize_t vmci_qpair_dequev(struct vmci_qp *qpair,
qpair->consume_q_size,
iov, iov_size,
qp_memcpy_from_queue_iov,
- true, vmci_can_block(qpair->flags));
+ true);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
@@ -3411,7 +3334,7 @@ ssize_t vmci_qpair_peekv(struct vmci_qp *qpair,
qpair->consume_q_size,
iov, iov_size,
qp_memcpy_from_queue_iov,
- false, vmci_can_block(qpair->flags));
+ false);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
!qp_wait_for_ready_queue(qpair))
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.h b/drivers/misc/vmw_vmci/vmci_queue_pair.h
index 58c6959f6b6..ed177f04ef2 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.h
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.h
@@ -146,24 +146,6 @@ VMCI_QP_PAGESTORE_IS_WELLFORMED(struct vmci_qp_page_store *page_store)
return page_store->len >= 2;
}
-/*
- * Helper function to check if the non-blocking flag
- * is set for a given queue pair.
- */
-static inline bool vmci_can_block(u32 flags)
-{
- return !(flags & VMCI_QPFLAG_NONBLOCK);
-}
-
-/*
- * Helper function to check if the queue pair is pinned
- * into memory.
- */
-static inline bool vmci_qp_pinned(u32 flags)
-{
- return flags & VMCI_QPFLAG_PINNED;
-}
-
void vmci_qp_broker_exit(void);
int vmci_qp_broker_alloc(struct vmci_handle handle, u32 peer,
u32 flags, u32 priv_flags,
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 49a5bca418b..5d088551196 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1313,7 +1313,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
supply = devm_regulator_get(dev, "vmmc");
mmc->supply.vmmc = supply;
- mmc->supply.vqmmc = devm_regulator_get(dev, "vqmmc");
+ mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc");
if (IS_ERR(supply))
return PTR_ERR(supply);
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index ee5f1676f14..542407363dd 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2231,7 +2231,7 @@ int dw_mci_probe(struct dw_mci *host)
}
}
- host->vmmc = devm_regulator_get(host->dev, "vmmc");
+ host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
if (IS_ERR(host->vmmc)) {
ret = PTR_ERR(host->vmmc);
if (ret == -EPROBE_DEFER)
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 847b1996ce8..1956a3df7cf 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -83,7 +83,7 @@ struct pxamci_host {
static inline void pxamci_init_ocr(struct pxamci_host *host)
{
#ifdef CONFIG_REGULATOR
- host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
+ host->vcc = regulator_get_optional(mmc_dev(host->mmc), "vmmc");
if (IS_ERR(host->vcc))
host->vcc = NULL;
@@ -128,7 +128,7 @@ static inline int pxamci_set_power(struct pxamci_host *host,
!!on ^ host->pdata->gpio_power_invert);
}
if (!host->vcc && host->pdata && host->pdata->setpower)
- host->pdata->setpower(mmc_dev(host->mmc), vdd);
+ return host->pdata->setpower(mmc_dev(host->mmc), vdd);
return 0;
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index a78bd4f3aec..dd2c083c434 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2966,7 +2966,7 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->caps |= MMC_CAP_NEEDS_POLL;
/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
- host->vqmmc = regulator_get(mmc_dev(mmc), "vqmmc");
+ host->vqmmc = regulator_get_optional(mmc_dev(mmc), "vqmmc");
if (IS_ERR_OR_NULL(host->vqmmc)) {
if (PTR_ERR(host->vqmmc) < 0) {
pr_info("%s: no vqmmc regulator found\n",
@@ -3042,7 +3042,7 @@ int sdhci_add_host(struct sdhci_host *host)
ocr_avail = 0;
- host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
+ host->vmmc = regulator_get_optional(mmc_dev(mmc), "vmmc");
if (IS_ERR_OR_NULL(host->vmmc)) {
if (PTR_ERR(host->vmmc) < 0) {
pr_info("%s: no vmmc regulator found\n",
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index a746ba272f0..a956053608f 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -1007,7 +1007,7 @@ static void arcnet_rx(struct net_device *dev, int bufnum)
soft = &pkt.soft.rfc1201;
- lp->hw.copy_from_card(dev, bufnum, 0, &pkt, sizeof(ARC_HDR_SIZE));
+ lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE);
if (pkt.hard.offset[0]) {
ofs = pkt.hard.offset[0];
length = 256 - ofs;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 07f257d44a1..e48cb339c0c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3714,11 +3714,17 @@ static int bond_neigh_init(struct neighbour *n)
* The bonding ndo_neigh_setup is called at init time beofre any
* slave exists. So we must declare proxy setup function which will
* be used at run time to resolve the actual slave neigh param setup.
+ *
+ * It's also called by master devices (such as vlans) to setup their
+ * underlying devices. In that case - do nothing, we're already set up from
+ * our init.
*/
static int bond_neigh_setup(struct net_device *dev,
struct neigh_parms *parms)
{
- parms->neigh_setup = bond_neigh_init;
+ /* modify only our neigh_parms */
+ if (parms->dev == dev)
+ parms->neigh_setup = bond_neigh_init;
return 0;
}
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
index 6aa7b3266c8..ac6177d3bef 100644
--- a/drivers/net/can/usb/esd_usb2.c
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -412,10 +412,20 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
switch (msg->msg.hdr.cmd) {
case CMD_CAN_RX:
+ if (msg->msg.rx.net >= dev->net_count) {
+ dev_err(dev->udev->dev.parent, "format error\n");
+ break;
+ }
+
esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
break;
case CMD_CAN_TX:
+ if (msg->msg.txdone.net >= dev->net_count) {
+ dev_err(dev->udev->dev.parent, "format error\n");
+ break;
+ }
+
esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
msg);
break;
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 25723d8ee20..925ab8ec932 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -649,7 +649,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
if ((mc->ptr + rec_len) > mc->end)
goto decode_failed;
- memcpy(cf->data, mc->ptr, rec_len);
+ memcpy(cf->data, mc->ptr, cf->can_dlc);
mc->ptr += rec_len;
}
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
index cbd388eea68..8becd3d838b 100644
--- a/drivers/net/can/usb/usb_8dev.c
+++ b/drivers/net/can/usb/usb_8dev.c
@@ -779,6 +779,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)
usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf,
urb->transfer_dma);
+ usb_free_urb(urb);
break;
}
diff --git a/drivers/net/ethernet/allwinner/Kconfig b/drivers/net/ethernet/allwinner/Kconfig
index 53ad213e865..d8d95d4cd45 100644
--- a/drivers/net/ethernet/allwinner/Kconfig
+++ b/drivers/net/ethernet/allwinner/Kconfig
@@ -3,19 +3,20 @@
#
config NET_VENDOR_ALLWINNER
- bool "Allwinner devices"
- default y
- depends on ARCH_SUNXI
- ---help---
- If you have a network (Ethernet) card belonging to this
- class, say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ bool "Allwinner devices"
+ default y
- Note that the answer to this question doesn't directly
- affect the kernel: saying N will just cause the configurator
- to skip all the questions about Allwinner cards. If you say Y,
- you will be asked for your specific card in the following
- questions.
+ depends on ARCH_SUNXI
+ ---help---
+ If you have a network (Ethernet) card belonging to this
+ class, say Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly
+ affect the kernel: saying N will just cause the configurator
+ to skip all the questions about Allwinner cards. If you say Y,
+ you will be asked for your specific card in the following
+ questions.
if NET_VENDOR_ALLWINNER
@@ -26,6 +27,7 @@ config SUN4I_EMAC
select CRC32
select MII
select PHYLIB
+ select MDIO_SUN4I
---help---
Support for Allwinner A10 EMAC ethernet driver.
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index f1b121ee552..55d79cb53a7 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -199,7 +199,7 @@ static int arc_emac_rx(struct net_device *ndev, int budget)
struct arc_emac_priv *priv = netdev_priv(ndev);
unsigned int work_done;
- for (work_done = 0; work_done <= budget; work_done++) {
+ for (work_done = 0; work_done < budget; work_done++) {
unsigned int *last_rx_bd = &priv->last_rx_bd;
struct net_device_stats *stats = &priv->stats;
struct buffer_state *rx_buff = &priv->rx_buff[*last_rx_bd];
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h
index b2bf324631d..0f0556526ba 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h
@@ -520,6 +520,9 @@ struct atl1c_adapter {
struct net_device *netdev;
struct pci_dev *pdev;
struct napi_struct napi;
+ struct page *rx_page;
+ unsigned int rx_page_offset;
+ unsigned int rx_frag_size;
struct atl1c_hw hw;
struct atl1c_hw_stats hw_stats;
struct mii_if_info mii; /* MII interface info */
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 786a8748329..a36a760ada2 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -481,10 +481,15 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
struct net_device *dev)
{
+ unsigned int head_size;
int mtu = dev->mtu;
adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ?
roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE;
+
+ head_size = SKB_DATA_ALIGN(adapter->rx_buffer_len + NET_SKB_PAD) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ adapter->rx_frag_size = roundup_pow_of_two(head_size);
}
static netdev_features_t atl1c_fix_features(struct net_device *netdev,
@@ -952,6 +957,10 @@ static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
kfree(adapter->tpd_ring[0].buffer_info);
adapter->tpd_ring[0].buffer_info = NULL;
}
+ if (adapter->rx_page) {
+ put_page(adapter->rx_page);
+ adapter->rx_page = NULL;
+ }
}
/**
@@ -1639,6 +1648,35 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
skb_checksum_none_assert(skb);
}
+static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter)
+{
+ struct sk_buff *skb;
+ struct page *page;
+
+ if (adapter->rx_frag_size > PAGE_SIZE)
+ return netdev_alloc_skb(adapter->netdev,
+ adapter->rx_buffer_len);
+
+ page = adapter->rx_page;
+ if (!page) {
+ adapter->rx_page = page = alloc_page(GFP_ATOMIC);
+ if (unlikely(!page))
+ return NULL;
+ adapter->rx_page_offset = 0;
+ }
+
+ skb = build_skb(page_address(page) + adapter->rx_page_offset,
+ adapter->rx_frag_size);
+ if (likely(skb)) {
+ adapter->rx_page_offset += adapter->rx_frag_size;
+ if (adapter->rx_page_offset >= PAGE_SIZE)
+ adapter->rx_page = NULL;
+ else
+ get_page(page);
+ }
+ return skb;
+}
+
static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
{
struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
@@ -1660,7 +1698,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
while (next_info->flags & ATL1C_BUFFER_FREE) {
rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
- skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len);
+ skb = atl1c_alloc_skb(adapter);
if (unlikely(!skb)) {
if (netif_msg_rx_err(adapter))
dev_warn(&pdev->dev, "alloc rx buffer failed\n");
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index dedbd76c033..00b88cbfde2 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -486,7 +486,7 @@ struct bnx2x_fastpath {
struct napi_struct napi;
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
unsigned int state;
#define BNX2X_FP_STATE_IDLE 0
#define BNX2X_FP_STATE_NAPI (1 << 0) /* NAPI owns this FP */
@@ -498,7 +498,7 @@ struct bnx2x_fastpath {
#define BNX2X_FP_USER_PEND (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_POLL_YIELD)
/* protect state */
spinlock_t lock;
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
union host_hc_status_block status_blk;
/* chip independent shortcuts into sb structure */
@@ -572,7 +572,7 @@ struct bnx2x_fastpath {
#define bnx2x_fp_stats(bp, fp) (&((bp)->fp_stats[(fp)->index]))
#define bnx2x_fp_qstats(bp, fp) (&((bp)->fp_stats[(fp)->index].eth_q_stats))
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
static inline void bnx2x_fp_init_lock(struct bnx2x_fastpath *fp)
{
spin_lock_init(&fp->lock);
@@ -680,7 +680,7 @@ static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp)
{
return false;
}
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
/* Use 2500 as a mini-jumbo MTU for FCoE */
#define BNX2X_FCOE_MINI_JUMBO_MTU 2500
@@ -1333,6 +1333,8 @@ enum {
BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
BNX2X_SP_RTNL_HYPERVISOR_VLAN,
+ BNX2X_SP_RTNL_TX_STOP,
+ BNX2X_SP_RTNL_TX_RESUME,
};
struct bnx2x_prev_path_list {
@@ -1502,6 +1504,7 @@ struct bnx2x {
#define BC_SUPPORTS_DCBX_MSG_NON_PMF (1 << 21)
#define IS_VF_FLAG (1 << 22)
#define INTERRUPTS_ENABLED_FLAG (1 << 23)
+#define BC_SUPPORTS_RMMOD_CMD (1 << 24)
#define BP_NOMCP(bp) ((bp)->flags & NO_MCP_FLAG)
@@ -1830,6 +1833,8 @@ struct bnx2x {
int fp_array_size;
u32 dump_preset_idx;
+ bool stats_started;
+ struct semaphore stats_sema;
};
/* Tx queues may be less or equal to Rx queues */
@@ -2451,4 +2456,6 @@ enum bnx2x_pci_bus_speed {
BNX2X_PCI_LINK_SPEED_5000 = 5000,
BNX2X_PCI_LINK_SPEED_8000 = 8000
};
+
+void bnx2x_set_local_cmng(struct bnx2x *bp);
#endif /* bnx2x.h */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index ee350bde181..0cc26110868 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -53,6 +53,7 @@ static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
struct bnx2x_fp_stats *to_fp_stats = &bp->fp_stats[to];
int old_max_eth_txqs, new_max_eth_txqs;
int old_txdata_index = 0, new_txdata_index = 0;
+ struct bnx2x_agg_info *old_tpa_info = to_fp->tpa_info;
/* Copy the NAPI object as it has been already initialized */
from_fp->napi = to_fp->napi;
@@ -61,6 +62,11 @@ static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
memcpy(to_fp, from_fp, sizeof(*to_fp));
to_fp->index = to;
+ /* Retain the tpa_info of the original `to' version as we don't want
+ * 2 FPs to contain the same tpa_info pointer.
+ */
+ to_fp->tpa_info = old_tpa_info;
+
/* move sp_objs contents as well, as their indices match fp ones */
memcpy(to_sp_objs, from_sp_objs, sizeof(*to_sp_objs));
@@ -2956,8 +2962,9 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
if (IS_PF(bp)) {
if (CNIC_LOADED(bp))
bnx2x_free_mem_cnic(bp);
- bnx2x_free_mem(bp);
}
+ bnx2x_free_mem(bp);
+
bp->state = BNX2X_STATE_CLOSED;
bp->cnic_loaded = false;
@@ -3117,7 +3124,7 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
return work_done;
}
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
/* must be called with local_bh_disable()d */
int bnx2x_low_latency_recv(struct napi_struct *napi)
{
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index 0c94df47e0e..fcf2761d882 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -30,10 +30,8 @@
#include "bnx2x_dcb.h"
/* forward declarations of dcbx related functions */
-static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp);
static void bnx2x_pfc_set_pfc(struct bnx2x *bp);
static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp);
-static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp);
static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
u32 *set_configuration_ets_pg,
u32 *pri_pg_tbl);
@@ -425,30 +423,52 @@ static void bnx2x_pfc_set_pfc(struct bnx2x *bp)
bnx2x_pfc_clear(bp);
}
-static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
+int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
{
struct bnx2x_func_state_params func_params = {NULL};
+ int rc;
func_params.f_obj = &bp->func_obj;
func_params.cmd = BNX2X_F_CMD_TX_STOP;
+ __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
+ __set_bit(RAMROD_RETRY, &func_params.ramrod_flags);
+
DP(BNX2X_MSG_DCB, "STOP TRAFFIC\n");
- return bnx2x_func_state_change(bp, &func_params);
+
+ rc = bnx2x_func_state_change(bp, &func_params);
+ if (rc) {
+ BNX2X_ERR("Unable to hold traffic for HW configuration\n");
+ bnx2x_panic();
+ }
+
+ return rc;
}
-static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
+int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
{
struct bnx2x_func_state_params func_params = {NULL};
struct bnx2x_func_tx_start_params *tx_params =
&func_params.params.tx_start;
+ int rc;
func_params.f_obj = &bp->func_obj;
func_params.cmd = BNX2X_F_CMD_TX_START;
+ __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
+ __set_bit(RAMROD_RETRY, &func_params.ramrod_flags);
+
bnx2x_dcbx_fw_struct(bp, tx_params);
DP(BNX2X_MSG_DCB, "START TRAFFIC\n");
- return bnx2x_func_state_change(bp, &func_params);
+
+ rc = bnx2x_func_state_change(bp, &func_params);
+ if (rc) {
+ BNX2X_ERR("Unable to resume traffic after HW configuration\n");
+ bnx2x_panic();
+ }
+
+ return rc;
}
static void bnx2x_dcbx_2cos_limit_update_ets_config(struct bnx2x *bp)
@@ -744,7 +764,9 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
if (IS_MF(bp))
bnx2x_link_sync_notify(bp);
- bnx2x_dcbx_stop_hw_tx(bp);
+ set_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state);
+
+ schedule_delayed_work(&bp->sp_rtnl_task, 0);
return;
}
@@ -753,7 +775,13 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
bnx2x_pfc_set_pfc(bp);
bnx2x_dcbx_update_ets_params(bp);
- bnx2x_dcbx_resume_hw_tx(bp);
+
+ /* ets may affect cmng configuration: reinit it in hw */
+ bnx2x_set_local_cmng(bp);
+
+ set_bit(BNX2X_SP_RTNL_TX_RESUME, &bp->sp_rtnl_state);
+
+ schedule_delayed_work(&bp->sp_rtnl_task, 0);
return;
case BNX2X_DCBX_STATE_TX_RELEASED:
@@ -2363,21 +2391,24 @@ static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid,
case DCB_FEATCFG_ATTR_PG:
if (bp->dcbx_local_feat.ets.enabled)
*flags |= DCB_FEATCFG_ENABLE;
- if (bp->dcbx_error & DCBX_LOCAL_ETS_ERROR)
+ if (bp->dcbx_error & (DCBX_LOCAL_ETS_ERROR |
+ DCBX_REMOTE_MIB_ERROR))
*flags |= DCB_FEATCFG_ERROR;
break;
case DCB_FEATCFG_ATTR_PFC:
if (bp->dcbx_local_feat.pfc.enabled)
*flags |= DCB_FEATCFG_ENABLE;
if (bp->dcbx_error & (DCBX_LOCAL_PFC_ERROR |
- DCBX_LOCAL_PFC_MISMATCH))
+ DCBX_LOCAL_PFC_MISMATCH |
+ DCBX_REMOTE_MIB_ERROR))
*flags |= DCB_FEATCFG_ERROR;
break;
case DCB_FEATCFG_ATTR_APP:
if (bp->dcbx_local_feat.app.enabled)
*flags |= DCB_FEATCFG_ENABLE;
if (bp->dcbx_error & (DCBX_LOCAL_APP_ERROR |
- DCBX_LOCAL_APP_MISMATCH))
+ DCBX_LOCAL_APP_MISMATCH |
+ DCBX_REMOTE_MIB_ERROR))
*flags |= DCB_FEATCFG_ERROR;
break;
default:
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
index 125bd1b6586..804b8f64463 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
@@ -199,4 +199,7 @@ extern const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops;
int bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall);
#endif /* BCM_DCBNL */
+int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp);
+int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp);
+
#endif /* BNX2X_DCB_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index 5018e52ae2a..32767f6aa33 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -1300,6 +1300,9 @@ struct drv_func_mb {
#define DRV_MSG_CODE_EEE_RESULTS_ACK 0xda000000
+ #define DRV_MSG_CODE_RMMOD 0xdb000000
+ #define REQ_BC_VER_4_RMMOD_CMD 0x0007080f
+
#define DRV_MSG_CODE_SET_MF_BW 0xe0000000
#define REQ_BC_VER_4_SET_MF_BW 0x00060202
#define DRV_MSG_CODE_SET_MF_BW_ACK 0xe1000000
@@ -1372,6 +1375,8 @@ struct drv_func_mb {
#define FW_MSG_CODE_EEE_RESULS_ACK 0xda100000
+ #define FW_MSG_CODE_RMMOD_ACK 0xdb100000
+
#define FW_MSG_CODE_SET_MF_BW_SENT 0xe0000000
#define FW_MSG_CODE_SET_MF_BW_DONE 0xe1000000
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index c51d2f82a93..815f2dea633 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -2261,6 +2261,23 @@ static void bnx2x_set_requested_fc(struct bnx2x *bp)
bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH;
}
+static void bnx2x_init_dropless_fc(struct bnx2x *bp)
+{
+ u32 pause_enabled = 0;
+
+ if (!CHIP_IS_E1(bp) && bp->dropless_fc && bp->link_vars.link_up) {
+ if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
+ pause_enabled = 1;
+
+ REG_WR(bp, BAR_USTRORM_INTMEM +
+ USTORM_ETH_PAUSE_ENABLED_OFFSET(BP_PORT(bp)),
+ pause_enabled);
+ }
+
+ DP(NETIF_MSG_IFUP | NETIF_MSG_LINK, "dropless_fc is %s\n",
+ pause_enabled ? "enabled" : "disabled");
+}
+
int bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
{
int rc, cfx_idx = bnx2x_get_link_cfg_idx(bp);
@@ -2294,6 +2311,8 @@ int bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
bnx2x_release_phy_lock(bp);
+ bnx2x_init_dropless_fc(bp);
+
bnx2x_calc_fc_adv(bp);
if (bp->link_vars.link_up) {
@@ -2315,6 +2334,8 @@ void bnx2x_link_set(struct bnx2x *bp)
bnx2x_phy_init(&bp->link_params, &bp->link_vars);
bnx2x_release_phy_lock(bp);
+ bnx2x_init_dropless_fc(bp);
+
bnx2x_calc_fc_adv(bp);
} else
BNX2X_ERR("Bootcode is missing - can not set link\n");
@@ -2476,7 +2497,7 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
input.port_rate = bp->link_vars.line_speed;
- if (cmng_type == CMNG_FNS_MINMAX) {
+ if (cmng_type == CMNG_FNS_MINMAX && input.port_rate) {
int vn;
/* read mf conf from shmem */
@@ -2533,6 +2554,21 @@ static void storm_memset_cmng(struct bnx2x *bp,
}
}
+/* init cmng mode in HW according to local configuration */
+void bnx2x_set_local_cmng(struct bnx2x *bp)
+{
+ int cmng_fns = bnx2x_get_cmng_fns_mode(bp);
+
+ if (cmng_fns != CMNG_FNS_NONE) {
+ bnx2x_cmng_fns_init(bp, false, cmng_fns);
+ storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
+ } else {
+ /* rate shaping and fairness are disabled */
+ DP(NETIF_MSG_IFUP,
+ "single function mode without fairness\n");
+ }
+}
+
/* This function is called upon link interrupt */
static void bnx2x_link_attn(struct bnx2x *bp)
{
@@ -2541,20 +2577,9 @@ static void bnx2x_link_attn(struct bnx2x *bp)
bnx2x_link_update(&bp->link_params, &bp->link_vars);
- if (bp->link_vars.link_up) {
-
- /* dropless flow control */
- if (!CHIP_IS_E1(bp) && bp->dropless_fc) {
- int port = BP_PORT(bp);
- u32 pause_enabled = 0;
+ bnx2x_init_dropless_fc(bp);
- if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
- pause_enabled = 1;
-
- REG_WR(bp, BAR_USTRORM_INTMEM +
- USTORM_ETH_PAUSE_ENABLED_OFFSET(port),
- pause_enabled);
- }
+ if (bp->link_vars.link_up) {
if (bp->link_vars.mac_type != MAC_TYPE_EMAC) {
struct host_port_stats *pstats;
@@ -2568,17 +2593,8 @@ static void bnx2x_link_attn(struct bnx2x *bp)
bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
}
- if (bp->link_vars.link_up && bp->link_vars.line_speed) {
- int cmng_fns = bnx2x_get_cmng_fns_mode(bp);
-
- if (cmng_fns != CMNG_FNS_NONE) {
- bnx2x_cmng_fns_init(bp, false, cmng_fns);
- storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
- } else
- /* rate shaping and fairness are disabled */
- DP(NETIF_MSG_IFUP,
- "single function mode without fairness\n");
- }
+ if (bp->link_vars.link_up && bp->link_vars.line_speed)
+ bnx2x_set_local_cmng(bp);
__bnx2x_link_report(bp);
@@ -7839,12 +7855,15 @@ void bnx2x_free_mem(struct bnx2x *bp)
{
int i;
- BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
- sizeof(struct host_sp_status_block));
-
BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+ if (IS_VF(bp))
+ return;
+
+ BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
+ sizeof(struct host_sp_status_block));
+
BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping,
sizeof(struct bnx2x_slowpath));
@@ -9639,6 +9658,12 @@ sp_rtnl_not_reset:
&bp->sp_rtnl_state))
bnx2x_pf_set_vfs_vlan(bp);
+ if (test_and_clear_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state))
+ bnx2x_dcbx_stop_hw_tx(bp);
+
+ if (test_and_clear_bit(BNX2X_SP_RTNL_TX_RESUME, &bp->sp_rtnl_state))
+ bnx2x_dcbx_resume_hw_tx(bp);
+
/* work which needs rtnl lock not-taken (as it takes the lock itself and
* can be called from other contexts as well)
*/
@@ -10348,6 +10373,10 @@ static void bnx2x_get_common_hwinfo(struct bnx2x *bp)
bp->flags |= (val >= REQ_BC_VER_4_DCBX_ADMIN_MSG_NON_PMF) ?
BC_SUPPORTS_DCBX_MSG_NON_PMF : 0;
+
+ bp->flags |= (val >= REQ_BC_VER_4_RMMOD_CMD) ?
+ BC_SUPPORTS_RMMOD_CMD : 0;
+
boot_mode = SHMEM_RD(bp,
dev_info.port_feature_config[BP_PORT(bp)].mba_config) &
PORT_FEATURE_MBA_BOOT_AGENT_TYPE_MASK;
@@ -11123,6 +11152,9 @@ static bool bnx2x_get_dropless_info(struct bnx2x *bp)
int tmp;
u32 cfg;
+ if (IS_VF(bp))
+ return 0;
+
if (IS_MF(bp) && !CHIP_IS_E1x(bp)) {
/* Take function: tmp = func */
tmp = BP_ABS_FUNC(bp);
@@ -11510,6 +11542,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
mutex_init(&bp->port.phy_mutex);
mutex_init(&bp->fw_mb_mutex);
spin_lock_init(&bp->stats_lock);
+ sema_init(&bp->stats_sema, 1);
INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
@@ -12012,7 +12045,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn,
#endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
.ndo_busy_poll = bnx2x_low_latency_recv,
#endif
};
@@ -12803,13 +12836,17 @@ static void __bnx2x_remove(struct pci_dev *pdev,
bnx2x_dcbnl_update_applist(bp, true);
#endif
+ if (IS_PF(bp) &&
+ !BP_NOMCP(bp) &&
+ (bp->flags & BC_SUPPORTS_RMMOD_CMD))
+ bnx2x_fw_command(bp, DRV_MSG_CODE_RMMOD, 0);
+
/* Close the interface - either directly or implicitly */
if (remove_netdev) {
unregister_netdev(dev);
} else {
rtnl_lock();
- if (netif_running(dev))
- bnx2x_close(dev);
+ dev_close(dev);
rtnl_unlock();
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 95861efb505..e8706e19f96 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -522,23 +522,6 @@ static int bnx2x_vfop_set_user_req(struct bnx2x *bp,
return 0;
}
-static int
-bnx2x_vfop_config_vlan0(struct bnx2x *bp,
- struct bnx2x_vlan_mac_ramrod_params *vlan_mac,
- bool add)
-{
- int rc;
-
- vlan_mac->user_req.cmd = add ? BNX2X_VLAN_MAC_ADD :
- BNX2X_VLAN_MAC_DEL;
- vlan_mac->user_req.u.vlan.vlan = 0;
-
- rc = bnx2x_config_vlan_mac(bp, vlan_mac);
- if (rc == -EEXIST)
- rc = 0;
- return rc;
-}
-
static int bnx2x_vfop_config_list(struct bnx2x *bp,
struct bnx2x_vfop_filters *filters,
struct bnx2x_vlan_mac_ramrod_params *vlan_mac)
@@ -643,30 +626,14 @@ static void bnx2x_vfop_vlan_mac(struct bnx2x *bp, struct bnx2x_virtf *vf)
case BNX2X_VFOP_VLAN_CONFIG_LIST:
/* next state */
- vfop->state = BNX2X_VFOP_VLAN_CONFIG_LIST_0;
-
- /* remove vlan0 - could be no-op */
- vfop->rc = bnx2x_vfop_config_vlan0(bp, vlan_mac, false);
- if (vfop->rc)
- goto op_err;
+ vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
- /* Do vlan list config. if this operation fails we try to
- * restore vlan0 to keep the queue is working order
- */
+ /* do list config */
vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
if (!vfop->rc) {
set_bit(RAMROD_CONT, &vlan_mac->ramrod_flags);
vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
}
- bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT); /* fall-through */
-
- case BNX2X_VFOP_VLAN_CONFIG_LIST_0:
- /* next state */
- vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
-
- if (list_empty(&obj->head))
- /* add vlan0 */
- vfop->rc = bnx2x_vfop_config_vlan0(bp, vlan_mac, true);
bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
default:
@@ -1747,11 +1714,8 @@ void bnx2x_iov_init_dq(struct bnx2x *bp)
void bnx2x_iov_init_dmae(struct bnx2x *bp)
{
- DP(BNX2X_MSG_IOV, "SRIOV is %s\n", IS_SRIOV(bp) ? "ON" : "OFF");
- if (!IS_SRIOV(bp))
- return;
-
- REG_WR(bp, DMAE_REG_BACKWARD_COMP_EN, 0);
+ if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV))
+ REG_WR(bp, DMAE_REG_BACKWARD_COMP_EN, 0);
}
static int bnx2x_vf_bus(struct bnx2x *bp, int vfid)
@@ -2822,6 +2786,18 @@ int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf, dma_addr_t *sb_map)
return 0;
}
+struct set_vf_state_cookie {
+ struct bnx2x_virtf *vf;
+ u8 state;
+};
+
+void bnx2x_set_vf_state(void *cookie)
+{
+ struct set_vf_state_cookie *p = (struct set_vf_state_cookie *)cookie;
+
+ p->vf->state = p->state;
+}
+
/* VFOP close (teardown the queues, delete mcasts and close HW) */
static void bnx2x_vfop_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
@@ -2872,7 +2848,19 @@ static void bnx2x_vfop_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
op_err:
BNX2X_ERR("VF[%d] CLOSE error: rc %d\n", vf->abs_vfid, vfop->rc);
op_done:
- vf->state = VF_ACQUIRED;
+
+ /* need to make sure there are no outstanding stats ramrods which may
+ * cause the device to access the VF's stats buffer which it will free
+ * as soon as we return from the close flow.
+ */
+ {
+ struct set_vf_state_cookie cookie;
+
+ cookie.vf = vf;
+ cookie.state = VF_ACQUIRED;
+ bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie);
+ }
+
DP(BNX2X_MSG_IOV, "set state to acquired\n");
bnx2x_vfop_end(bp, vf, vfop);
}
@@ -3084,8 +3072,9 @@ void bnx2x_disable_sriov(struct bnx2x *bp)
pci_disable_sriov(bp->pdev);
}
-static int bnx2x_vf_ndo_sanity(struct bnx2x *bp, int vfidx,
- struct bnx2x_virtf *vf)
+static int bnx2x_vf_ndo_prep(struct bnx2x *bp, int vfidx,
+ struct bnx2x_virtf **vf,
+ struct pf_vf_bulletin_content **bulletin)
{
if (bp->state != BNX2X_STATE_OPEN) {
BNX2X_ERR("vf ndo called though PF is down\n");
@@ -3103,12 +3092,22 @@ static int bnx2x_vf_ndo_sanity(struct bnx2x *bp, int vfidx,
return -EINVAL;
}
- if (!vf) {
+ /* init members */
+ *vf = BP_VF(bp, vfidx);
+ *bulletin = BP_VF_BULLETIN(bp, vfidx);
+
+ if (!*vf) {
BNX2X_ERR("vf ndo called but vf was null. vfidx was %d\n",
vfidx);
return -EINVAL;
}
+ if (!*bulletin) {
+ BNX2X_ERR("vf ndo called but Bulletin Board struct is null. vfidx was %d\n",
+ vfidx);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -3116,17 +3115,19 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
struct ifla_vf_info *ivi)
{
struct bnx2x *bp = netdev_priv(dev);
- struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
- struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
- struct bnx2x_vlan_mac_obj *vlan_obj = &bnx2x_vfq(vf, 0, vlan_obj);
- struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+ struct bnx2x_virtf *vf = NULL;
+ struct pf_vf_bulletin_content *bulletin = NULL;
+ struct bnx2x_vlan_mac_obj *mac_obj;
+ struct bnx2x_vlan_mac_obj *vlan_obj;
int rc;
- /* sanity */
- rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+ /* sanity and init */
+ rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
if (rc)
return rc;
- if (!mac_obj || !vlan_obj || !bulletin) {
+ mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
+ vlan_obj = &bnx2x_vfq(vf, 0, vlan_obj);
+ if (!mac_obj || !vlan_obj) {
BNX2X_ERR("VF partially initialized\n");
return -EINVAL;
}
@@ -3183,11 +3184,11 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
{
struct bnx2x *bp = netdev_priv(dev);
int rc, q_logical_state;
- struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
- struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+ struct bnx2x_virtf *vf = NULL;
+ struct pf_vf_bulletin_content *bulletin = NULL;
- /* sanity */
- rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+ /* sanity and init */
+ rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
if (rc)
return rc;
if (!is_valid_ether_addr(mac)) {
@@ -3249,11 +3250,11 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
{
struct bnx2x *bp = netdev_priv(dev);
int rc, q_logical_state;
- struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
- struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+ struct bnx2x_virtf *vf = NULL;
+ struct pf_vf_bulletin_content *bulletin = NULL;
- /* sanity */
- rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+ /* sanity and init */
+ rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
if (rc)
return rc;
@@ -3463,7 +3464,7 @@ int bnx2x_vf_pci_alloc(struct bnx2x *bp)
alloc_mem_err:
BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
sizeof(struct bnx2x_vf_mbx_msg));
- BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+ BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->pf2vf_bulletin_mapping,
sizeof(union pf_vf_bulletin));
return -ENOMEM;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 98366abd02b..86436c77af0 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -221,7 +221,8 @@ static int bnx2x_stats_comp(struct bnx2x *bp)
* Statistics service functions
*/
-static void bnx2x_stats_pmf_update(struct bnx2x *bp)
+/* should be called under stats_sema */
+static void __bnx2x_stats_pmf_update(struct bnx2x *bp)
{
struct dmae_command *dmae;
u32 opcode;
@@ -518,29 +519,47 @@ static void bnx2x_func_stats_init(struct bnx2x *bp)
*stats_comp = 0;
}
-static void bnx2x_stats_start(struct bnx2x *bp)
+/* should be called under stats_sema */
+static void __bnx2x_stats_start(struct bnx2x *bp)
{
- /* vfs travel through here as part of the statistics FSM, but no action
- * is required
- */
- if (IS_VF(bp))
- return;
+ if (IS_PF(bp)) {
+ if (bp->port.pmf)
+ bnx2x_port_stats_init(bp);
- if (bp->port.pmf)
- bnx2x_port_stats_init(bp);
+ else if (bp->func_stx)
+ bnx2x_func_stats_init(bp);
- else if (bp->func_stx)
- bnx2x_func_stats_init(bp);
+ bnx2x_hw_stats_post(bp);
+ bnx2x_storm_stats_post(bp);
+ }
- bnx2x_hw_stats_post(bp);
- bnx2x_storm_stats_post(bp);
+ bp->stats_started = true;
+}
+
+static void bnx2x_stats_start(struct bnx2x *bp)
+{
+ if (down_timeout(&bp->stats_sema, HZ/10))
+ BNX2X_ERR("Unable to acquire stats lock\n");
+ __bnx2x_stats_start(bp);
+ up(&bp->stats_sema);
}
static void bnx2x_stats_pmf_start(struct bnx2x *bp)
{
+ if (down_timeout(&bp->stats_sema, HZ/10))
+ BNX2X_ERR("Unable to acquire stats lock\n");
bnx2x_stats_comp(bp);
- bnx2x_stats_pmf_update(bp);
- bnx2x_stats_start(bp);
+ __bnx2x_stats_pmf_update(bp);
+ __bnx2x_stats_start(bp);
+ up(&bp->stats_sema);
+}
+
+static void bnx2x_stats_pmf_update(struct bnx2x *bp)
+{
+ if (down_timeout(&bp->stats_sema, HZ/10))
+ BNX2X_ERR("Unable to acquire stats lock\n");
+ __bnx2x_stats_pmf_update(bp);
+ up(&bp->stats_sema);
}
static void bnx2x_stats_restart(struct bnx2x *bp)
@@ -550,8 +569,11 @@ static void bnx2x_stats_restart(struct bnx2x *bp)
*/
if (IS_VF(bp))
return;
+ if (down_timeout(&bp->stats_sema, HZ/10))
+ BNX2X_ERR("Unable to acquire stats lock\n");
bnx2x_stats_comp(bp);
- bnx2x_stats_start(bp);
+ __bnx2x_stats_start(bp);
+ up(&bp->stats_sema);
}
static void bnx2x_bmac_stats_update(struct bnx2x *bp)
@@ -888,9 +910,7 @@ static int bnx2x_storm_stats_validate_counters(struct bnx2x *bp)
/* Make sure we use the value of the counter
* used for sending the last stats ramrod.
*/
- spin_lock_bh(&bp->stats_lock);
cur_stats_counter = bp->stats_counter - 1;
- spin_unlock_bh(&bp->stats_lock);
/* are storm stats valid? */
if (le16_to_cpu(counters->xstats_counter) != cur_stats_counter) {
@@ -1227,12 +1247,18 @@ static void bnx2x_stats_update(struct bnx2x *bp)
{
u32 *stats_comp = bnx2x_sp(bp, stats_comp);
- if (bnx2x_edebug_stats_stopped(bp))
+ /* we run update from timer context, so give up
+ * if somebody is in the middle of transition
+ */
+ if (down_trylock(&bp->stats_sema))
return;
+ if (bnx2x_edebug_stats_stopped(bp) || !bp->stats_started)
+ goto out;
+
if (IS_PF(bp)) {
if (*stats_comp != DMAE_COMP_VAL)
- return;
+ goto out;
if (bp->port.pmf)
bnx2x_hw_stats_update(bp);
@@ -1242,7 +1268,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
BNX2X_ERR("storm stats were not updated for 3 times\n");
bnx2x_panic();
}
- return;
+ goto out;
}
} else {
/* vf doesn't collect HW statistics, and doesn't get completions
@@ -1256,7 +1282,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
/* vf is done */
if (IS_VF(bp))
- return;
+ goto out;
if (netif_msg_timer(bp)) {
struct bnx2x_eth_stats *estats = &bp->eth_stats;
@@ -1267,6 +1293,9 @@ static void bnx2x_stats_update(struct bnx2x *bp)
bnx2x_hw_stats_post(bp);
bnx2x_storm_stats_post(bp);
+
+out:
+ up(&bp->stats_sema);
}
static void bnx2x_port_stats_stop(struct bnx2x *bp)
@@ -1332,6 +1361,11 @@ static void bnx2x_stats_stop(struct bnx2x *bp)
{
int update = 0;
+ if (down_timeout(&bp->stats_sema, HZ/10))
+ BNX2X_ERR("Unable to acquire stats lock\n");
+
+ bp->stats_started = false;
+
bnx2x_stats_comp(bp);
if (bp->port.pmf)
@@ -1348,6 +1382,8 @@ static void bnx2x_stats_stop(struct bnx2x *bp)
bnx2x_hw_stats_post(bp);
bnx2x_stats_comp(bp);
}
+
+ up(&bp->stats_sema);
}
static void bnx2x_stats_do_nothing(struct bnx2x *bp)
@@ -1376,15 +1412,17 @@ static const struct {
void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
{
enum bnx2x_stats_state state;
+ void (*action)(struct bnx2x *bp);
if (unlikely(bp->panic))
return;
spin_lock_bh(&bp->stats_lock);
state = bp->stats_state;
bp->stats_state = bnx2x_stats_stm[state][event].next_state;
+ action = bnx2x_stats_stm[state][event].action;
spin_unlock_bh(&bp->stats_lock);
- bnx2x_stats_stm[state][event].action(bp);
+ action(bp);
if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
@@ -1955,3 +1993,14 @@ void bnx2x_afex_collect_stats(struct bnx2x *bp, void *void_afex_stats,
estats->mac_discard);
}
}
+
+void bnx2x_stats_safe_exec(struct bnx2x *bp,
+ void (func_to_exec)(void *cookie),
+ void *cookie){
+ if (down_timeout(&bp->stats_sema, HZ/10))
+ BNX2X_ERR("Unable to acquire stats lock\n");
+ bnx2x_stats_comp(bp);
+ func_to_exec(cookie);
+ __bnx2x_stats_start(bp);
+ up(&bp->stats_sema);
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
index 853824d258e..f35845006cd 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
@@ -539,6 +539,9 @@ struct bnx2x;
void bnx2x_memset_stats(struct bnx2x *bp);
void bnx2x_stats_init(struct bnx2x *bp);
void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
+void bnx2x_stats_safe_exec(struct bnx2x *bp,
+ void (func_to_exec)(void *cookie),
+ void *cookie);
/**
* bnx2x_save_statistics - save statistics when unloading.
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index d964f302ac9..0da2214ef1b 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -17625,7 +17625,8 @@ err_out_free_res:
pci_release_regions(pdev);
err_out_disable_pdev:
- pci_disable_device(pdev);
+ if (pci_is_enabled(pdev))
+ pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
return err;
}
@@ -17773,7 +17774,8 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
rtnl_lock();
- if (!netif_running(netdev))
+ /* We probably don't have netdev yet */
+ if (!netdev || !netif_running(netdev))
goto done;
tg3_phy_stop(tp);
@@ -17794,8 +17796,10 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
done:
if (state == pci_channel_io_perm_failure) {
- tg3_napi_enable(tp);
- dev_close(netdev);
+ if (netdev) {
+ tg3_napi_enable(tp);
+ dev_close(netdev);
+ }
err = PCI_ERS_RESULT_DISCONNECT;
} else {
pci_disable_device(pdev);
@@ -17825,7 +17829,8 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev)
rtnl_lock();
if (pci_enable_device(pdev)) {
- netdev_err(netdev, "Cannot re-enable PCI device after reset.\n");
+ dev_err(&pdev->dev,
+ "Cannot re-enable PCI device after reset.\n");
goto done;
}
@@ -17833,7 +17838,7 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev)
pci_restore_state(pdev);
pci_save_state(pdev);
- if (!netif_running(netdev)) {
+ if (!netdev || !netif_running(netdev)) {
rc = PCI_ERS_RESULT_RECOVERED;
goto done;
}
@@ -17845,7 +17850,7 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev)
rc = PCI_ERS_RESULT_RECOVERED;
done:
- if (rc != PCI_ERS_RESULT_RECOVERED && netif_running(netdev)) {
+ if (rc != PCI_ERS_RESULT_RECOVERED && netdev && netif_running(netdev)) {
tg3_napi_enable(tp);
dev_close(netdev);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index 687ec4a8bb4..9c89dc8fe10 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -455,11 +455,6 @@ static int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q,
q->pg_chunk.offset = 0;
mapping = pci_map_page(adapter->pdev, q->pg_chunk.page,
0, q->alloc_size, PCI_DMA_FROMDEVICE);
- if (unlikely(pci_dma_mapping_error(adapter->pdev, mapping))) {
- __free_pages(q->pg_chunk.page, order);
- q->pg_chunk.page = NULL;
- return -EIO;
- }
q->pg_chunk.mapping = mapping;
}
sd->pg_chunk = q->pg_chunk;
@@ -954,75 +949,40 @@ static inline unsigned int calc_tx_descs(const struct sk_buff *skb)
return flits_to_desc(flits);
}
-
-/* map_skb - map a packet main body and its page fragments
- * @pdev: the PCI device
- * @skb: the packet
- * @addr: placeholder to save the mapped addresses
- *
- * map the main body of an sk_buff and its page fragments, if any.
- */
-static int map_skb(struct pci_dev *pdev, const struct sk_buff *skb,
- dma_addr_t *addr)
-{
- const skb_frag_t *fp, *end;
- const struct skb_shared_info *si;
-
- *addr = pci_map_single(pdev, skb->data, skb_headlen(skb),
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(pdev, *addr))
- goto out_err;
-
- si = skb_shinfo(skb);
- end = &si->frags[si->nr_frags];
-
- for (fp = si->frags; fp < end; fp++) {
- *++addr = skb_frag_dma_map(&pdev->dev, fp, 0, skb_frag_size(fp),
- DMA_TO_DEVICE);
- if (pci_dma_mapping_error(pdev, *addr))
- goto unwind;
- }
- return 0;
-
-unwind:
- while (fp-- > si->frags)
- dma_unmap_page(&pdev->dev, *--addr, skb_frag_size(fp),
- DMA_TO_DEVICE);
-
- pci_unmap_single(pdev, addr[-1], skb_headlen(skb), PCI_DMA_TODEVICE);
-out_err:
- return -ENOMEM;
-}
-
/**
- * write_sgl - populate a scatter/gather list for a packet
+ * make_sgl - populate a scatter/gather list for a packet
* @skb: the packet
* @sgp: the SGL to populate
* @start: start address of skb main body data to include in the SGL
* @len: length of skb main body data to include in the SGL
- * @addr: the list of the mapped addresses
+ * @pdev: the PCI device
*
- * Copies the scatter/gather list for the buffers that make up a packet
+ * Generates a scatter/gather list for the buffers that make up a packet
* and returns the SGL size in 8-byte words. The caller must size the SGL
* appropriately.
*/
-static inline unsigned int write_sgl(const struct sk_buff *skb,
+static inline unsigned int make_sgl(const struct sk_buff *skb,
struct sg_ent *sgp, unsigned char *start,
- unsigned int len, const dma_addr_t *addr)
+ unsigned int len, struct pci_dev *pdev)
{
- unsigned int i, j = 0, k = 0, nfrags;
+ dma_addr_t mapping;
+ unsigned int i, j = 0, nfrags;
if (len) {
+ mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE);
sgp->len[0] = cpu_to_be32(len);
- sgp->addr[j++] = cpu_to_be64(addr[k++]);
+ sgp->addr[0] = cpu_to_be64(mapping);
+ j = 1;
}
nfrags = skb_shinfo(skb)->nr_frags;
for (i = 0; i < nfrags; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ mapping = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
sgp->len[j] = cpu_to_be32(skb_frag_size(frag));
- sgp->addr[j] = cpu_to_be64(addr[k++]);
+ sgp->addr[j] = cpu_to_be64(mapping);
j ^= 1;
if (j == 0)
++sgp;
@@ -1178,7 +1138,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
const struct port_info *pi,
unsigned int pidx, unsigned int gen,
struct sge_txq *q, unsigned int ndesc,
- unsigned int compl, const dma_addr_t *addr)
+ unsigned int compl)
{
unsigned int flits, sgl_flits, cntrl, tso_info;
struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
@@ -1236,7 +1196,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
}
sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
- sgl_flits = write_sgl(skb, sgp, skb->data, skb_headlen(skb), addr);
+ sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev);
write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen,
htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl),
@@ -1267,7 +1227,6 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
struct netdev_queue *txq;
struct sge_qset *qs;
struct sge_txq *q;
- dma_addr_t addr[MAX_SKB_FRAGS + 1];
/*
* The chip min packet length is 9 octets but play safe and reject
@@ -1296,11 +1255,6 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
- if (unlikely(map_skb(adap->pdev, skb, addr) < 0)) {
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
q->in_use += ndesc;
if (unlikely(credits - ndesc < q->stop_thres)) {
t3_stop_tx_queue(txq, qs, q);
@@ -1358,7 +1312,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
if (likely(!skb_shared(skb)))
skb_orphan(skb);
- write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl, addr);
+ write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl);
check_ring_tx_db(adap, q);
return NETDEV_TX_OK;
}
@@ -1623,8 +1577,7 @@ static void setup_deferred_unmapping(struct sk_buff *skb, struct pci_dev *pdev,
*/
static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
struct sge_txq *q, unsigned int pidx,
- unsigned int gen, unsigned int ndesc,
- const dma_addr_t *addr)
+ unsigned int gen, unsigned int ndesc)
{
unsigned int sgl_flits, flits;
struct work_request_hdr *from;
@@ -1645,9 +1598,9 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
flits = skb_transport_offset(skb) / 8;
sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
- sgl_flits = write_sgl(skb, sgp, skb_transport_header(skb),
- skb_tail_pointer(skb) -
- skb_transport_header(skb), addr);
+ sgl_flits = make_sgl(skb, sgp, skb_transport_header(skb),
+ skb->tail - skb->transport_header,
+ adap->pdev);
if (need_skb_unmap()) {
setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits);
skb->destructor = deferred_unmap_destructor;
@@ -1705,11 +1658,6 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
goto again;
}
- if (map_skb(adap->pdev, skb, (dma_addr_t *)skb->head)) {
- spin_unlock(&q->lock);
- return NET_XMIT_SUCCESS;
- }
-
gen = q->gen;
q->in_use += ndesc;
pidx = q->pidx;
@@ -1720,7 +1668,7 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
}
spin_unlock(&q->lock);
- write_ofld_wr(adap, skb, q, pidx, gen, ndesc, (dma_addr_t *)skb->head);
+ write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
check_ring_tx_db(adap, q);
return NET_XMIT_SUCCESS;
}
@@ -1738,7 +1686,6 @@ static void restart_offloadq(unsigned long data)
struct sge_txq *q = &qs->txq[TXQ_OFLD];
const struct port_info *pi = netdev_priv(qs->netdev);
struct adapter *adap = pi->adapter;
- unsigned int written = 0;
spin_lock(&q->lock);
again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
@@ -1758,14 +1705,10 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
break;
}
- if (map_skb(adap->pdev, skb, (dma_addr_t *)skb->head))
- break;
-
gen = q->gen;
q->in_use += ndesc;
pidx = q->pidx;
q->pidx += ndesc;
- written += ndesc;
if (q->pidx >= q->size) {
q->pidx -= q->size;
q->gen ^= 1;
@@ -1773,8 +1716,7 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
__skb_unlink(skb, &q->sendq);
spin_unlock(&q->lock);
- write_ofld_wr(adap, skb, q, pidx, gen, ndesc,
- (dma_addr_t *)skb->head);
+ write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
spin_lock(&q->lock);
}
spin_unlock(&q->lock);
@@ -1784,9 +1726,8 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
set_bit(TXQ_LAST_PKT_DB, &q->flags);
#endif
wmb();
- if (likely(written))
- t3_write_reg(adap, A_SG_KDOORBELL,
- F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
}
/**
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 6e6e0a117ee..8ec5d74ad44 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -3048,6 +3048,9 @@ int be_cmd_get_func_config(struct be_adapter *adapter)
adapter->max_event_queues = le16_to_cpu(desc->eq_count);
adapter->if_cap_flags = le32_to_cpu(desc->cap_flags);
+
+ /* Clear flags that driver is not interested in */
+ adapter->if_cap_flags &= BE_IF_CAP_FLAGS_WANT;
}
err:
mutex_unlock(&adapter->mbox_lock);
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 5228d88c5a0..1b3b9e88641 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -563,6 +563,12 @@ enum be_if_flags {
BE_IF_FLAGS_MULTICAST = 0x1000
};
+#define BE_IF_CAP_FLAGS_WANT (BE_IF_FLAGS_RSS | BE_IF_FLAGS_PROMISCUOUS |\
+ BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_VLAN_PROMISCUOUS |\
+ BE_IF_FLAGS_VLAN | BE_IF_FLAGS_MCAST_PROMISCUOUS |\
+ BE_IF_FLAGS_PASS_L3L4_ERRORS | BE_IF_FLAGS_MULTICAST |\
+ BE_IF_FLAGS_UNTAGGED)
+
/* An RX interface is an object with one or more MAC addresses and
* filtering capabilities. */
struct be_cmd_req_if_create {
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 181edb52245..3d91a5ec61a 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -2563,8 +2563,8 @@ static int be_close(struct net_device *netdev)
/* Wait for all pending tx completions to arrive so that
* all tx skbs are freed.
*/
- be_tx_compl_clean(adapter);
netif_tx_disable(netdev);
+ be_tx_compl_clean(adapter);
be_rx_qs_destroy(adapter);
@@ -4373,6 +4373,10 @@ static int be_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
+ status = be_fw_wait_ready(adapter);
+ if (status)
+ return status;
+
/* tell fw we're ready to fire cmds */
status = be_cmd_fw_init(adapter);
if (status)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 2b0a0ea4f8e..ae236009f1a 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -259,6 +259,7 @@ struct bufdesc_ex {
struct fec_enet_delayed_work {
struct delayed_work delay_work;
bool timeout;
+ bool trig_tx;
};
/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index d3ad5ea711d..c610a2716be 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -93,6 +93,20 @@ static void set_multicast_list(struct net_device *ndev);
#define FEC_QUIRK_HAS_CSUM (1 << 5)
/* Controller has hardware vlan support */
#define FEC_QUIRK_HAS_VLAN (1 << 6)
+/* ENET IP errata ERR006358
+ *
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
+ * detected as not set during a prior frame transmission, then the
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
+ * detected as not set during a prior frame transmission, then the
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
+ * frames not being transmitted until there is a 0-to-1 transition on
+ * ENET_TDAR[TDAR].
+ */
+#define FEC_QUIRK_ERR006358 (1 << 7)
static struct platform_device_id fec_devtype[] = {
{
@@ -112,7 +126,7 @@ static struct platform_device_id fec_devtype[] = {
.name = "imx6q-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
- FEC_QUIRK_HAS_VLAN,
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358,
}, {
.name = "mvf600-fec",
.driver_data = FEC_QUIRK_ENET_MAC,
@@ -275,16 +289,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);
- struct bufdesc *bdp;
+ struct bufdesc *bdp, *bdp_pre;
void *bufaddr;
unsigned short status;
unsigned int index;
- if (!fep->link) {
- /* Link is down or auto-negotiation is in progress. */
- return NETDEV_TX_BUSY;
- }
-
/* Fill in a Tx ring entry */
bdp = fep->cur_tx;
@@ -370,6 +379,15 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
ebdp->cbd_esc |= BD_ENET_TX_PINS;
}
}
+
+ bdp_pre = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
+ if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
+ !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
+ fep->delay_work.trig_tx = true;
+ schedule_delayed_work(&(fep->delay_work.delay_work),
+ msecs_to_jiffies(1));
+ }
+
/* If this was the last BD in the ring, start at the beginning again. */
if (status & BD_ENET_TX_WRAP)
bdp = fep->tx_bd_base;
@@ -689,6 +707,11 @@ static void fec_enet_work(struct work_struct *work)
fec_restart(fep->netdev, fep->full_duplex);
netif_wake_queue(fep->netdev);
}
+
+ if (fep->delay_work.trig_tx) {
+ fep->delay_work.trig_tx = false;
+ writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+ }
}
static void
@@ -948,8 +971,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
htons(ETH_P_8021Q),
vlan_tag);
- if (!skb_defer_rx_timestamp(skb))
- napi_gro_receive(&fep->napi, skb);
+ napi_gro_receive(&fep->napi, skb);
}
bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
@@ -2279,4 +2301,5 @@ static struct platform_driver fec_driver = {
module_platform_driver(fec_driver);
+MODULE_ALIAS("platform:"DRIVER_NAME);
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 6a0c1b66ce5..c1d72c03cb5 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -3739,9 +3739,8 @@ static void igb_set_rx_mode(struct net_device *netdev)
rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE);
if (netdev->flags & IFF_PROMISC) {
- u32 mrqc = rd32(E1000_MRQC);
/* retain VLAN HW filtering if in VT mode */
- if (mrqc & E1000_MRQC_ENABLE_VMDQ)
+ if (adapter->vfs_allocated_count)
rctl |= E1000_RCTL_VFE;
rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 7be725cdfea..a6494e5daff 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -54,7 +54,7 @@
#include <net/busy_poll.h>
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
#define LL_EXTENDED_STATS
#endif
/* common prefix used by pr_<> macros */
@@ -366,7 +366,7 @@ struct ixgbe_q_vector {
struct rcu_head rcu; /* to avoid race with update stats on free */
char name[IFNAMSIZ + 9];
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
unsigned int state;
#define IXGBE_QV_STATE_IDLE 0
#define IXGBE_QV_STATE_NAPI 1 /* NAPI owns this QV */
@@ -377,12 +377,12 @@ struct ixgbe_q_vector {
#define IXGBE_QV_YIELD (IXGBE_QV_STATE_NAPI_YIELD | IXGBE_QV_STATE_POLL_YIELD)
#define IXGBE_QV_USER_PEND (IXGBE_QV_STATE_POLL | IXGBE_QV_STATE_POLL_YIELD)
spinlock_t lock;
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
/* for dynamic allocation of rings associated with this q_vector */
struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp;
};
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
{
@@ -462,7 +462,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
WARN_ON(!(q_vector->state & IXGBE_QV_LOCKED));
return q_vector->state & IXGBE_QV_USER_PEND;
}
-#else /* CONFIG_NET_LL_RX_POLL */
+#else /* CONFIG_NET_RX_BUSY_POLL */
static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
{
}
@@ -491,7 +491,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
{
return false;
}
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
#ifdef CONFIG_IXGBE_HWMON
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
index ac780770863..7a77f37a7cb 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
@@ -108,9 +108,8 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
/* Enable arbiter */
reg &= ~IXGBE_DPMCS_ARBDIS;
- /* Enable DFP and Recycle mode */
- reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM);
reg |= IXGBE_DPMCS_TSOEF;
+
/* Configure Max TSO packet size 34KB including payload and headers */
reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index bad8f14b194..be4b1fb3d0d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1998,7 +1998,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
return total_rx_packets;
}
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
/* must be called with local_bh_disable()d */
static int ixgbe_low_latency_recv(struct napi_struct *napi)
{
@@ -2030,7 +2030,7 @@ static int ixgbe_low_latency_recv(struct napi_struct *napi)
return found;
}
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
/**
* ixgbe_configure_msix - Configure MSI-X hardware
@@ -7227,7 +7227,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ixgbe_netpoll,
#endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
.ndo_busy_poll = ixgbe_low_latency_recv,
#endif
#ifdef IXGBE_FCOE
diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index 7fbe6abf605..23de82a9da8 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -3069,7 +3069,7 @@ jme_init_one(struct pci_dev *pdev,
jwrite32(jme, JME_APMC, apmc);
}
- NETIF_NAPI_SET(netdev, &jme->napi, jme_poll, jme->rx_ring_size >> 2)
+ NETIF_NAPI_SET(netdev, &jme->napi, jme_poll, NAPI_POLL_WEIGHT)
spin_lock_init(&jme->phy_lock);
spin_lock_init(&jme->macaddr_lock);
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 712779fb12b..b017818bcca 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -88,6 +88,8 @@
#define MVNETA_TX_IN_PRGRS BIT(1)
#define MVNETA_TX_FIFO_EMPTY BIT(8)
#define MVNETA_RX_MIN_FRAME_SIZE 0x247c
+#define MVNETA_SGMII_SERDES_CFG 0x24A0
+#define MVNETA_SGMII_SERDES_PROTO 0x0cc7
#define MVNETA_TYPE_PRIO 0x24bc
#define MVNETA_FORCE_UNI BIT(21)
#define MVNETA_TXQ_CMD_1 0x24e4
@@ -655,6 +657,8 @@ static void mvneta_port_sgmii_config(struct mvneta_port *pp)
val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
val |= MVNETA_GMAC2_PSC_ENABLE;
mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
+
+ mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
}
/* Start the Ethernet port RX and TX activity */
@@ -2728,28 +2732,24 @@ static int mvneta_probe(struct platform_device *pdev)
pp = netdev_priv(dev);
- pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
- init_timer(&pp->tx_done_timer);
- clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
-
pp->weight = MVNETA_RX_POLL_WEIGHT;
pp->phy_node = phy_node;
pp->phy_interface = phy_mode;
- pp->base = of_iomap(dn, 0);
- if (pp->base == NULL) {
- err = -ENOMEM;
- goto err_free_irq;
- }
-
pp->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pp->clk)) {
err = PTR_ERR(pp->clk);
- goto err_unmap;
+ goto err_free_irq;
}
clk_prepare_enable(pp->clk);
+ pp->base = of_iomap(dn, 0);
+ if (pp->base == NULL) {
+ err = -ENOMEM;
+ goto err_clk;
+ }
+
dt_mac_addr = of_get_mac_address(dn);
if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) {
mac_from = "device tree";
@@ -2766,6 +2766,9 @@ static int mvneta_probe(struct platform_device *pdev)
}
pp->tx_done_timer.data = (unsigned long)dev;
+ pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
+ init_timer(&pp->tx_done_timer);
+ clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
pp->tx_ring_size = MVNETA_MAX_TXD;
pp->rx_ring_size = MVNETA_MAX_RXD;
@@ -2776,7 +2779,7 @@ static int mvneta_probe(struct platform_device *pdev)
err = mvneta_init(pp, phy_addr);
if (err < 0) {
dev_err(&pdev->dev, "can't init eth hal\n");
- goto err_clk;
+ goto err_unmap;
}
mvneta_port_power_up(pp, phy_mode);
@@ -2806,10 +2809,10 @@ static int mvneta_probe(struct platform_device *pdev)
err_deinit:
mvneta_deinit(pp);
-err_clk:
- clk_disable_unprepare(pp->clk);
err_unmap:
iounmap(pp->base);
+err_clk:
+ clk_disable_unprepare(pp->clk);
err_free_irq:
irq_dispose_mapping(dev->irq);
err_free_netdev:
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index c896079728e..ef94a591f9e 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -931,17 +931,20 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base)
}
/* Allocate and setup a new buffer for receiving */
-static void skge_rx_setup(struct skge_port *skge, struct skge_element *e,
- struct sk_buff *skb, unsigned int bufsize)
+static int skge_rx_setup(struct skge_port *skge, struct skge_element *e,
+ struct sk_buff *skb, unsigned int bufsize)
{
struct skge_rx_desc *rd = e->desc;
- u64 map;
+ dma_addr_t map;
map = pci_map_single(skge->hw->pdev, skb->data, bufsize,
PCI_DMA_FROMDEVICE);
- rd->dma_lo = map;
- rd->dma_hi = map >> 32;
+ if (pci_dma_mapping_error(skge->hw->pdev, map))
+ return -1;
+
+ rd->dma_lo = lower_32_bits(map);
+ rd->dma_hi = upper_32_bits(map);
e->skb = skb;
rd->csum1_start = ETH_HLEN;
rd->csum2_start = ETH_HLEN;
@@ -953,6 +956,7 @@ static void skge_rx_setup(struct skge_port *skge, struct skge_element *e,
rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize;
dma_unmap_addr_set(e, mapaddr, map);
dma_unmap_len_set(e, maplen, bufsize);
+ return 0;
}
/* Resume receiving using existing skb,
@@ -1014,7 +1018,10 @@ static int skge_rx_fill(struct net_device *dev)
return -ENOMEM;
skb_reserve(skb, NET_IP_ALIGN);
- skge_rx_setup(skge, e, skb, skge->rx_buf_size);
+ if (skge_rx_setup(skge, e, skb, skge->rx_buf_size) < 0) {
+ dev_kfree_skb(skb);
+ return -EIO;
+ }
} while ((e = e->next) != ring->start);
ring->to_clean = ring->start;
@@ -2544,7 +2551,7 @@ static int skge_up(struct net_device *dev)
BUG_ON(skge->dma & 7);
- if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) {
+ if (upper_32_bits(skge->dma) != upper_32_bits(skge->dma + skge->mem_size)) {
dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n");
err = -EINVAL;
goto free_pci_mem;
@@ -2729,7 +2736,7 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
struct skge_tx_desc *td;
int i;
u32 control, len;
- u64 map;
+ dma_addr_t map;
if (skb_padto(skb, ETH_ZLEN))
return NETDEV_TX_OK;
@@ -2743,11 +2750,14 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
e->skb = skb;
len = skb_headlen(skb);
map = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(hw->pdev, map))
+ goto mapping_error;
+
dma_unmap_addr_set(e, mapaddr, map);
dma_unmap_len_set(e, maplen, len);
- td->dma_lo = map;
- td->dma_hi = map >> 32;
+ td->dma_lo = lower_32_bits(map);
+ td->dma_hi = upper_32_bits(map);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
const int offset = skb_checksum_start_offset(skb);
@@ -2778,14 +2788,16 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
map = skb_frag_dma_map(&hw->pdev->dev, frag, 0,
skb_frag_size(frag), DMA_TO_DEVICE);
+ if (dma_mapping_error(&hw->pdev->dev, map))
+ goto mapping_unwind;
e = e->next;
e->skb = skb;
tf = e->desc;
BUG_ON(tf->control & BMU_OWN);
- tf->dma_lo = map;
- tf->dma_hi = (u64) map >> 32;
+ tf->dma_lo = lower_32_bits(map);
+ tf->dma_hi = upper_32_bits(map);
dma_unmap_addr_set(e, mapaddr, map);
dma_unmap_len_set(e, maplen, skb_frag_size(frag));
@@ -2815,6 +2827,26 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
}
return NETDEV_TX_OK;
+
+mapping_unwind:
+ e = skge->tx_ring.to_use;
+ pci_unmap_single(hw->pdev,
+ dma_unmap_addr(e, mapaddr),
+ dma_unmap_len(e, maplen),
+ PCI_DMA_TODEVICE);
+ while (i-- > 0) {
+ e = e->next;
+ pci_unmap_page(hw->pdev,
+ dma_unmap_addr(e, mapaddr),
+ dma_unmap_len(e, maplen),
+ PCI_DMA_TODEVICE);
+ }
+
+mapping_error:
+ if (net_ratelimit())
+ dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name);
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
}
@@ -3045,11 +3077,13 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
pci_dma_sync_single_for_cpu(skge->hw->pdev,
dma_unmap_addr(e, mapaddr),
- len, PCI_DMA_FROMDEVICE);
+ dma_unmap_len(e, maplen),
+ PCI_DMA_FROMDEVICE);
skb_copy_from_linear_data(e->skb, skb->data, len);
pci_dma_sync_single_for_device(skge->hw->pdev,
dma_unmap_addr(e, mapaddr),
- len, PCI_DMA_FROMDEVICE);
+ dma_unmap_len(e, maplen),
+ PCI_DMA_FROMDEVICE);
skge_rx_reuse(e, skge->rx_buf_size);
} else {
struct sk_buff *nskb;
@@ -3058,13 +3092,17 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
if (!nskb)
goto resubmit;
+ if (skge_rx_setup(skge, e, nskb, skge->rx_buf_size) < 0) {
+ dev_kfree_skb(nskb);
+ goto resubmit;
+ }
+
pci_unmap_single(skge->hw->pdev,
dma_unmap_addr(e, mapaddr),
dma_unmap_len(e, maplen),
PCI_DMA_FROMDEVICE);
skb = e->skb;
prefetch(skb->data);
- skge_rx_setup(skge, e, nskb, skge->rx_buf_size);
}
skb_put(skb, len);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 727874f575c..a28cd801a23 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -223,7 +223,7 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
case ETH_SS_STATS:
return (priv->stats_bitmap ? bit_count : NUM_ALL_STATS) +
(priv->tx_ring_num * 2) +
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
(priv->rx_ring_num * 5);
#else
(priv->rx_ring_num * 2);
@@ -276,7 +276,7 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
for (i = 0; i < priv->rx_ring_num; i++) {
data[index++] = priv->rx_ring[i].packets;
data[index++] = priv->rx_ring[i].bytes;
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
data[index++] = priv->rx_ring[i].yields;
data[index++] = priv->rx_ring[i].misses;
data[index++] = priv->rx_ring[i].cleaned;
@@ -344,7 +344,7 @@ static void mlx4_en_get_strings(struct net_device *dev,
"rx%d_packets", i);
sprintf(data + (index++) * ETH_GSTRING_LEN,
"rx%d_bytes", i);
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
sprintf(data + (index++) * ETH_GSTRING_LEN,
"rx%d_napi_yield", i);
sprintf(data + (index++) * ETH_GSTRING_LEN,
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 5eac871399d..fa37b7a6121 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -68,7 +68,7 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up)
return 0;
}
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
/* must be called with local_bh_disable()d */
static int mlx4_en_low_latency_recv(struct napi_struct *napi)
{
@@ -94,7 +94,7 @@ static int mlx4_en_low_latency_recv(struct napi_struct *napi)
return done;
}
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
#ifdef CONFIG_RFS_ACCEL
@@ -2140,7 +2140,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
#ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = mlx4_en_filter_rfs,
#endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
.ndo_busy_poll = mlx4_en_low_latency_recv,
#endif
};
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 8873d6802c8..6fc6dabc78d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -845,16 +845,7 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
MLX4_CMD_NATIVE);
if (!err && dev->caps.function != slave) {
- /* if config MAC in DB use it */
- if (priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac)
- def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
- else {
- /* set slave default_mac address */
- MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET);
- def_mac += slave << 8;
- priv->mfunc.master.vf_admin[slave].vport[vhcr->in_modifier].mac = def_mac;
- }
-
+ def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET);
/* get port type - currently only eth is enabled */
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index e85af922dcd..36be3208786 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -371,7 +371,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev->caps.sqp_demux = (mlx4_is_master(dev)) ? MLX4_MAX_NUM_SLAVES : 0;
- if (!enable_64b_cqe_eqe) {
+ if (!enable_64b_cqe_eqe && !mlx4_is_slave(dev)) {
if (dev_cap->flags &
(MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) {
mlx4_warn(dev, "64B EQEs/CQEs supported by the device but not enabled\n");
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 35fb60e2320..5e0aa569306 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -292,7 +292,7 @@ struct mlx4_en_rx_ring {
void *rx_info;
unsigned long bytes;
unsigned long packets;
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
unsigned long yields;
unsigned long misses;
unsigned long cleaned;
@@ -318,7 +318,7 @@ struct mlx4_en_cq {
struct mlx4_cqe *buf;
#define MLX4_EN_OPCODE_ERROR 0x1e
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
unsigned int state;
#define MLX4_EN_CQ_STATE_IDLE 0
#define MLX4_EN_CQ_STATE_NAPI 1 /* NAPI owns this CQ */
@@ -329,7 +329,7 @@ struct mlx4_en_cq {
#define CQ_YIELD (MLX4_EN_CQ_STATE_NAPI_YIELD | MLX4_EN_CQ_STATE_POLL_YIELD)
#define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD)
spinlock_t poll_lock; /* protects from LLS/napi conflicts */
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
};
struct mlx4_en_port_profile {
@@ -580,7 +580,7 @@ struct mlx4_mac_entry {
struct rcu_head rcu;
};
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq)
{
spin_lock_init(&cq->poll_lock);
@@ -687,7 +687,7 @@ static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
{
return false;
}
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
#define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index 205753a04cf..5472cbd3402 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -46,7 +46,7 @@
#include "mlx5_core.h"
enum {
- CMD_IF_REV = 3,
+ CMD_IF_REV = 5,
};
enum {
@@ -282,6 +282,12 @@ const char *mlx5_command_str(int command)
case MLX5_CMD_OP_TEARDOWN_HCA:
return "TEARDOWN_HCA";
+ case MLX5_CMD_OP_ENABLE_HCA:
+ return "MLX5_CMD_OP_ENABLE_HCA";
+
+ case MLX5_CMD_OP_DISABLE_HCA:
+ return "MLX5_CMD_OP_DISABLE_HCA";
+
case MLX5_CMD_OP_QUERY_PAGES:
return "QUERY_PAGES";
@@ -1113,7 +1119,13 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
for (i = 0; i < (1 << cmd->log_sz); i++) {
if (test_bit(i, &vector)) {
+ struct semaphore *sem;
+
ent = cmd->ent_arr[i];
+ if (ent->page_queue)
+ sem = &cmd->pages_sem;
+ else
+ sem = &cmd->sem;
ktime_get_ts(&ent->ts2);
memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
dump_command(dev, ent, 0);
@@ -1136,10 +1148,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
} else {
complete(&ent->done);
}
- if (ent->page_queue)
- up(&cmd->pages_sem);
- else
- up(&cmd->sem);
+ up(sem);
}
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index c02cbcfd0fb..443cc4d7b02 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -268,7 +268,7 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
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);
+ s32 npages = be32_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);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index 72a5222447f..f012658b6a9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -113,7 +113,7 @@ int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev,
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_qp_mcg = be32_to_cpu(out->hca_cap.max_qp_mcg) & 0xffffff;
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;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
index 748f10a155c..3e6670c4a7c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -55,33 +55,9 @@ enum {
};
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;
@@ -98,11 +74,8 @@ static void health_care(struct work_struct *work)
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");
+ /* nothing yet */
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);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 12242de2b0e..b47739b0b5f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -249,6 +249,44 @@ static int set_hca_ctrl(struct mlx5_core_dev *dev)
return err;
}
+static int mlx5_core_enable_hca(struct mlx5_core_dev *dev)
+{
+ int err;
+ struct mlx5_enable_hca_mbox_in in;
+ struct mlx5_enable_hca_mbox_out out;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ENABLE_HCA);
+ 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 0;
+}
+
+static int mlx5_core_disable_hca(struct mlx5_core_dev *dev)
+{
+ int err;
+ struct mlx5_disable_hca_mbox_in in;
+ struct mlx5_disable_hca_mbox_out out;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DISABLE_HCA);
+ 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 0;
+}
+
int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
{
struct mlx5_priv *priv = &dev->priv;
@@ -304,28 +342,41 @@ int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
}
mlx5_pagealloc_init(dev);
+
+ err = mlx5_core_enable_hca(dev);
+ if (err) {
+ dev_err(&pdev->dev, "enable hca failed\n");
+ goto err_pagealloc_cleanup;
+ }
+
+ err = mlx5_satisfy_startup_pages(dev, 1);
+ if (err) {
+ dev_err(&pdev->dev, "failed to allocate boot pages\n");
+ goto err_disable_hca;
+ }
+
err = set_hca_ctrl(dev);
if (err) {
dev_err(&pdev->dev, "set_hca_ctrl failed\n");
- goto err_pagealloc_cleanup;
+ goto reclaim_boot_pages;
}
err = handle_hca_cap(dev);
if (err) {
dev_err(&pdev->dev, "handle_hca_cap failed\n");
- goto err_pagealloc_cleanup;
+ goto reclaim_boot_pages;
}
- err = mlx5_satisfy_startup_pages(dev);
+ err = mlx5_satisfy_startup_pages(dev, 0);
if (err) {
- dev_err(&pdev->dev, "failed to allocate startup pages\n");
- goto err_pagealloc_cleanup;
+ dev_err(&pdev->dev, "failed to allocate init pages\n");
+ goto reclaim_boot_pages;
}
err = mlx5_pagealloc_start(dev);
if (err) {
dev_err(&pdev->dev, "mlx5_pagealloc_start failed\n");
- goto err_reclaim_pages;
+ goto reclaim_boot_pages;
}
err = mlx5_cmd_init_hca(dev);
@@ -396,9 +447,12 @@ err_stop_poll:
err_pagealloc_stop:
mlx5_pagealloc_stop(dev);
-err_reclaim_pages:
+reclaim_boot_pages:
mlx5_reclaim_startup_pages(dev);
+err_disable_hca:
+ mlx5_core_disable_hca(dev);
+
err_pagealloc_cleanup:
mlx5_pagealloc_cleanup(dev);
mlx5_cmd_cleanup(dev);
@@ -434,6 +488,7 @@ void mlx5_dev_cleanup(struct mlx5_core_dev *dev)
mlx5_cmd_teardown_hca(dev);
mlx5_pagealloc_stop(dev);
mlx5_reclaim_startup_pages(dev);
+ mlx5_core_disable_hca(dev);
mlx5_pagealloc_cleanup(dev);
mlx5_cmd_cleanup(dev);
iounmap(dev->iseg);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
index f0bf46339b2..3a2408d4482 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
@@ -43,10 +43,16 @@ enum {
MLX5_PAGES_TAKE = 2
};
+enum {
+ MLX5_BOOT_PAGES = 1,
+ MLX5_INIT_PAGES = 2,
+ MLX5_POST_INIT_PAGES = 3
+};
+
struct mlx5_pages_req {
struct mlx5_core_dev *dev;
u32 func_id;
- s16 npages;
+ s32 npages;
struct work_struct work;
};
@@ -64,27 +70,23 @@ struct mlx5_query_pages_inbox {
struct mlx5_query_pages_outbox {
struct mlx5_outbox_hdr hdr;
- u8 reserved[2];
+ __be16 rsvd;
__be16 func_id;
- __be16 init_pages;
- __be16 num_pages;
+ __be32 num_pages;
};
struct mlx5_manage_pages_inbox {
struct mlx5_inbox_hdr hdr;
- __be16 rsvd0;
+ __be16 rsvd;
__be16 func_id;
- __be16 rsvd1;
- __be16 num_entries;
- u8 rsvd2[16];
+ __be32 num_entries;
__be64 pas[0];
};
struct mlx5_manage_pages_outbox {
struct mlx5_outbox_hdr hdr;
- u8 rsvd0[2];
- __be16 num_entries;
- u8 rsvd1[20];
+ __be32 num_entries;
+ u8 rsvd[4];
__be64 pas[0];
};
@@ -146,7 +148,7 @@ static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr)
}
static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
- s16 *pages, s16 *init_pages)
+ s32 *npages, int boot)
{
struct mlx5_query_pages_inbox in;
struct mlx5_query_pages_outbox out;
@@ -155,6 +157,8 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
memset(&in, 0, sizeof(in));
memset(&out, 0, sizeof(out));
in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_PAGES);
+ in.hdr.opmod = boot ? cpu_to_be16(MLX5_BOOT_PAGES) : cpu_to_be16(MLX5_INIT_PAGES);
+
err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
if (err)
return err;
@@ -162,10 +166,7 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
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);
+ *npages = be32_to_cpu(out.num_pages);
*func_id = be16_to_cpu(out.func_id);
return err;
@@ -219,7 +220,7 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
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);
+ in->num_entries = cpu_to_be32(npages);
err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
mlx5_core_dbg(dev, "err %d\n", err);
if (err) {
@@ -287,7 +288,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
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);
+ in.num_entries = cpu_to_be32(npages);
mlx5_core_dbg(dev, "npages %d, outlen %d\n", npages, outlen);
err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
if (err) {
@@ -301,7 +302,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
goto out_free;
}
- num_claimed = be16_to_cpu(out->num_entries);
+ num_claimed = be32_to_cpu(out->num_entries);
if (nclaimed)
*nclaimed = num_claimed;
@@ -340,7 +341,7 @@ static void pages_work_handler(struct work_struct *work)
}
void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
- s16 npages)
+ s32 npages)
{
struct mlx5_pages_req *req;
@@ -357,19 +358,20 @@ void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
queue_work(dev->priv.pg_wq, &req->work);
}
-int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev)
+int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot)
{
- s16 uninitialized_var(init_pages);
u16 uninitialized_var(func_id);
+ s32 uninitialized_var(npages);
int err;
- err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages);
+ err = mlx5_cmd_query_pages(dev, &func_id, &npages, boot);
if (err)
return err;
- mlx5_core_dbg(dev, "requested %d init pages for func_id 0x%x\n", init_pages, func_id);
+ mlx5_core_dbg(dev, "requested %d %s pages for func_id 0x%x\n",
+ npages, boot ? "boot" : "init", func_id);
- return give_pages(dev, func_id, init_pages, 0);
+ return give_pages(dev, func_id, npages, 0);
}
static int optimal_reclaimed_pages(void)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c
index 71d4a393720..68f5d9c77c7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/uar.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c
@@ -164,6 +164,7 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
uuari->uars[i].map = ioremap(addr, PAGE_SIZE);
if (!uuari->uars[i].map) {
mlx5_cmd_free_uar(dev, uuari->uars[i].index);
+ err = -ENOMEM;
goto out_count;
}
mlx5_core_dbg(dev, "allocated uar index 0x%x, mmaped at %p\n",
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
index cb22341a14a..a588ffde970 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
@@ -4,7 +4,7 @@
config PCH_GBE
tristate "OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE"
- depends on PCI
+ depends on PCI && (X86 || COMPILE_TEST)
select MII
select PTP_1588_CLOCK_PCH
---help---
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
index 3fe09ab2d7c..32675e16021 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
@@ -1171,7 +1171,6 @@ typedef struct {
#define NETXEN_DB_MAPSIZE_BYTES 0x1000
-#define NETXEN_NETDEV_WEIGHT 128
#define NETXEN_ADAPTER_UP_MAGIC 777
#define NETXEN_NIC_PEG_TUNE 0
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index c401b0b4353..ec4cf7fd412 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -197,7 +197,7 @@ netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev)
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
netif_napi_add(netdev, &sds_ring->napi,
- netxen_nic_poll, NETXEN_NETDEV_WEIGHT);
+ netxen_nic_poll, NAPI_POLL_WEIGHT);
}
return 0;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index b00cf5665ea..221645e9f18 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1400,8 +1400,8 @@ void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64);
#define ADDR_IN_RANGE(addr, low, high) \
(((addr) < (high)) && ((addr) >= (low)))
-#define QLCRD32(adapter, off) \
- (adapter->ahw->hw_ops->read_reg)(adapter, off)
+#define QLCRD32(adapter, off, err) \
+ (adapter->ahw->hw_ops->read_reg)(adapter, off, err)
#define QLCWR32(adapter, off, val) \
adapter->ahw->hw_ops->write_reg(adapter, off, val)
@@ -1604,7 +1604,7 @@ struct qlcnic_nic_template {
struct qlcnic_hardware_ops {
void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
void (*write_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
- int (*read_reg) (struct qlcnic_adapter *, ulong);
+ int (*read_reg) (struct qlcnic_adapter *, ulong, int *);
int (*write_reg) (struct qlcnic_adapter *, ulong, u32);
void (*get_ocm_win) (struct qlcnic_hardware_context *);
int (*get_mac_address) (struct qlcnic_adapter *, u8 *);
@@ -1662,12 +1662,6 @@ static inline void qlcnic_write_crb(struct qlcnic_adapter *adapter, char *buf,
adapter->ahw->hw_ops->write_crb(adapter, buf, offset, size);
}
-static inline int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter,
- ulong off)
-{
- return adapter->ahw->hw_ops->read_reg(adapter, off);
-}
-
static inline int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter,
ulong off, u32 data)
{
@@ -1869,7 +1863,8 @@ static inline void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter)
{
- adapter->ahw->hw_ops->set_mac_filter_count(adapter);
+ if (adapter->ahw->hw_ops->set_mac_filter_count)
+ adapter->ahw->hw_ops->set_mac_filter_count(adapter);
}
static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index 0913c623a67..9d4bb7f8390 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -228,17 +228,17 @@ static int __qlcnic_set_win_base(struct qlcnic_adapter *adapter, u32 addr)
return 0;
}
-int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr)
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,
+ int *err)
{
- int ret;
struct qlcnic_hardware_context *ahw = adapter->ahw;
- ret = __qlcnic_set_win_base(adapter, (u32) addr);
- if (!ret) {
+ *err = __qlcnic_set_win_base(adapter, (u32) addr);
+ if (!*err) {
return QLCRDX(ahw, QLCNIC_WILDCARD);
} else {
dev_err(&adapter->pdev->dev,
- "%s failed, addr = 0x%x\n", __func__, (int)addr);
+ "%s failed, addr = 0x%lx\n", __func__, addr);
return -EIO;
}
}
@@ -561,7 +561,7 @@ void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *adapter)
void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
loff_t offset, size_t size)
{
- int ret;
+ int ret = 0;
u32 data;
if (qlcnic_api_lock(adapter)) {
@@ -571,7 +571,7 @@ void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
return;
}
- ret = qlcnic_83xx_rd_reg_indirect(adapter, (u32) offset);
+ data = QLCRD32(adapter, (u32) offset, &ret);
qlcnic_api_unlock(adapter);
if (ret == -EIO) {
@@ -580,7 +580,6 @@ void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
__func__, (u32)offset);
return;
}
- data = ret;
memcpy(buf, &data, size);
}
@@ -2075,18 +2074,25 @@ void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter)
static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
u32 data[])
{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
u8 link_status, duplex;
/* link speed */
link_status = LSB(data[3]) & 1;
- adapter->ahw->link_speed = MSW(data[2]);
- adapter->ahw->link_autoneg = MSB(MSW(data[3]));
- adapter->ahw->module_type = MSB(LSW(data[3]));
- duplex = LSB(MSW(data[3]));
- if (duplex)
- adapter->ahw->link_duplex = DUPLEX_FULL;
- else
- adapter->ahw->link_duplex = DUPLEX_HALF;
- adapter->ahw->has_link_events = 1;
+ if (link_status) {
+ ahw->link_speed = MSW(data[2]);
+ duplex = LSB(MSW(data[3]));
+ if (duplex)
+ ahw->link_duplex = DUPLEX_FULL;
+ else
+ ahw->link_duplex = DUPLEX_HALF;
+ } else {
+ ahw->link_speed = SPEED_UNKNOWN;
+ ahw->link_duplex = DUPLEX_UNKNOWN;
+ }
+
+ ahw->link_autoneg = MSB(MSW(data[3]));
+ ahw->module_type = MSB(LSW(data[3]));
+ ahw->has_link_events = 1;
qlcnic_advert_link_change(adapter, link_status);
}
@@ -2384,9 +2390,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
u32 flash_addr, u8 *p_data,
int count)
{
- int i, ret;
- u32 word, range, flash_offset, addr = flash_addr;
+ u32 word, range, flash_offset, addr = flash_addr, ret;
ulong indirect_add, direct_window;
+ int i, err = 0;
flash_offset = addr & (QLCNIC_FLASH_SECTOR_SIZE - 1);
if (addr & 0x3) {
@@ -2404,10 +2410,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
/* Multi sector read */
for (i = 0; i < count; i++) {
indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
- ret = qlcnic_83xx_rd_reg_indirect(adapter,
- indirect_add);
- if (ret == -EIO)
- return -EIO;
+ ret = QLCRD32(adapter, indirect_add, &err);
+ if (err == -EIO)
+ return err;
word = ret;
*(u32 *)p_data = word;
@@ -2428,10 +2433,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
/* Single sector read */
for (i = 0; i < count; i++) {
indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
- ret = qlcnic_83xx_rd_reg_indirect(adapter,
- indirect_add);
- if (ret == -EIO)
- return -EIO;
+ ret = QLCRD32(adapter, indirect_add, &err);
+ if (err == -EIO)
+ return err;
word = ret;
*(u32 *)p_data = word;
@@ -2447,10 +2451,13 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
{
u32 status;
int retries = QLC_83XX_FLASH_READ_RETRY_COUNT;
+ int err = 0;
do {
- status = qlcnic_83xx_rd_reg_indirect(adapter,
- QLC_83XX_FLASH_STATUS);
+ status = QLCRD32(adapter, QLC_83XX_FLASH_STATUS, &err);
+ if (err == -EIO)
+ return err;
+
if ((status & QLC_83XX_FLASH_STATUS_READY) ==
QLC_83XX_FLASH_STATUS_READY)
break;
@@ -2502,7 +2509,8 @@ int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *adapter)
int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)
{
- int ret, mfg_id;
+ int ret, err = 0;
+ u32 mfg_id;
if (qlcnic_83xx_lock_flash(adapter))
return -EIO;
@@ -2517,9 +2525,11 @@ int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)
return -EIO;
}
- mfg_id = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
- if (mfg_id == -EIO)
- return -EIO;
+ mfg_id = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err);
+ if (err == -EIO) {
+ qlcnic_83xx_unlock_flash(adapter);
+ return err;
+ }
adapter->flash_mfg_id = (mfg_id & 0xFF);
qlcnic_83xx_unlock_flash(adapter);
@@ -2636,7 +2646,7 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
u32 *p_data, int count)
{
u32 temp;
- int ret = -EIO;
+ int ret = -EIO, err = 0;
if ((count < QLC_83XX_FLASH_WRITE_MIN) ||
(count > QLC_83XX_FLASH_WRITE_MAX)) {
@@ -2645,8 +2655,10 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
return -EIO;
}
- temp = qlcnic_83xx_rd_reg_indirect(adapter,
- QLC_83XX_FLASH_SPI_CONTROL);
+ temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err);
+ if (err == -EIO)
+ return err;
+
qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL,
(temp | QLC_83XX_FLASH_SPI_CTRL));
qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
@@ -2695,13 +2707,18 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
return -EIO;
}
- ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_SPI_STATUS);
+ ret = QLCRD32(adapter, QLC_83XX_FLASH_SPI_STATUS, &err);
+ if (err == -EIO)
+ return err;
+
if ((ret & QLC_83XX_FLASH_SPI_CTRL) == QLC_83XX_FLASH_SPI_CTRL) {
dev_err(&adapter->pdev->dev, "%s: failed at %d\n",
__func__, __LINE__);
/* Operation failed, clear error bit */
- temp = qlcnic_83xx_rd_reg_indirect(adapter,
- QLC_83XX_FLASH_SPI_CONTROL);
+ temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err);
+ if (err == -EIO)
+ return err;
+
qlcnic_83xx_wrt_reg_indirect(adapter,
QLC_83XX_FLASH_SPI_CONTROL,
(temp | QLC_83XX_FLASH_SPI_CTRL));
@@ -2823,6 +2840,7 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
{
int i, j, ret = 0;
u32 temp;
+ int err = 0;
/* Check alignment */
if (addr & 0xF)
@@ -2855,8 +2873,12 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
QLCNIC_TA_WRITE_START);
for (j = 0; j < MAX_CTL_CHECK; j++) {
- temp = qlcnic_83xx_rd_reg_indirect(adapter,
- QLCNIC_MS_CTRL);
+ temp = QLCRD32(adapter, QLCNIC_MS_CTRL, &err);
+ if (err == -EIO) {
+ mutex_unlock(&adapter->ahw->mem_lock);
+ return err;
+ }
+
if ((temp & TA_CTL_BUSY) == 0)
break;
}
@@ -2878,9 +2900,9 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
u8 *p_data, int count)
{
- int i, ret;
- u32 word, addr = flash_addr;
+ u32 word, addr = flash_addr, ret;
ulong indirect_addr;
+ int i, err = 0;
if (qlcnic_83xx_lock_flash(adapter) != 0)
return -EIO;
@@ -2900,10 +2922,10 @@ int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
}
indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr);
- ret = qlcnic_83xx_rd_reg_indirect(adapter,
- indirect_addr);
- if (ret == -EIO)
- return -EIO;
+ ret = QLCRD32(adapter, indirect_addr, &err);
+ if (err == -EIO)
+ return err;
+
word = ret;
*(u32 *)p_data = word;
p_data = p_data + 4;
@@ -3014,8 +3036,8 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
}
if (ahw->port_type == QLCNIC_XGBE) {
- ecmd->supported = SUPPORTED_1000baseT_Full;
- ecmd->advertising = ADVERTISED_1000baseT_Full;
+ ecmd->supported = SUPPORTED_10000baseT_Full;
+ ecmd->advertising = ADVERTISED_10000baseT_Full;
} else {
ecmd->supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
@@ -3244,6 +3266,11 @@ int qlcnic_83xx_interrupt_test(struct net_device *netdev)
u8 val;
int ret, max_sds_rings = adapter->max_sds_rings;
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+ netdev_info(netdev, "Device is resetting\n");
+ return -EBUSY;
+ }
+
if (qlcnic_get_diag_lock(adapter)) {
netdev_info(netdev, "Device in diagnostics mode\n");
return -EBUSY;
@@ -3369,7 +3396,8 @@ int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter,
static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
{
- int ret;
+ int ret, err = 0;
+ u32 temp;
qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
QLC_83XX_FLASH_OEM_READ_SIG);
@@ -3379,8 +3407,11 @@ static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
if (ret)
return -EIO;
- ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
- return ret & 0xFF;
+ temp = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err);
+ if (err == -EIO)
+ return err;
+
+ return temp & 0xFF;
}
int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index 2548d1403d7..272f56a2e14 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -508,7 +508,7 @@ void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *);
void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *);
void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
-int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong);
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong, int *);
int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32);
void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *, int, u64 []);
int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index f41dfab1e9a..345d987aede 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -629,7 +629,8 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
return -EIO;
}
- qlcnic_set_drv_version(adapter);
+ if (adapter->portnum == 0)
+ qlcnic_set_drv_version(adapter);
qlcnic_83xx_idc_attach_driver(adapter);
return 0;
@@ -1303,8 +1304,11 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
{
int i, j;
u32 val = 0, val1 = 0, reg = 0;
+ int err = 0;
- val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG);
+ val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG, &err);
+ if (err == -EIO)
+ return;
dev_info(&adapter->pdev->dev, "SRE-Shim Ctrl:0x%x\n", val);
for (j = 0; j < 2; j++) {
@@ -1318,7 +1322,9 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
reg = QLC_83XX_PORT1_THRESHOLD;
}
for (i = 0; i < 8; i++) {
- val = QLCRD32(adapter, reg + (i * 0x4));
+ val = QLCRD32(adapter, reg + (i * 0x4), &err);
+ if (err == -EIO)
+ return;
dev_info(&adapter->pdev->dev, "0x%x ", val);
}
dev_info(&adapter->pdev->dev, "\n");
@@ -1335,8 +1341,10 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
reg = QLC_83XX_PORT1_TC_MC_REG;
}
for (i = 0; i < 4; i++) {
- val = QLCRD32(adapter, reg + (i * 0x4));
- dev_info(&adapter->pdev->dev, "0x%x ", val);
+ val = QLCRD32(adapter, reg + (i * 0x4), &err);
+ if (err == -EIO)
+ return;
+ dev_info(&adapter->pdev->dev, "0x%x ", val);
}
dev_info(&adapter->pdev->dev, "\n");
}
@@ -1352,17 +1360,25 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
reg = QLC_83XX_PORT1_TC_STATS;
}
for (i = 7; i >= 0; i--) {
- val = QLCRD32(adapter, reg);
+ val = QLCRD32(adapter, reg, &err);
+ if (err == -EIO)
+ return;
val &= ~(0x7 << 29); /* Reset bits 29 to 31 */
QLCWR32(adapter, reg, (val | (i << 29)));
- val = QLCRD32(adapter, reg);
+ val = QLCRD32(adapter, reg, &err);
+ if (err == -EIO)
+ return;
dev_info(&adapter->pdev->dev, "0x%x ", val);
}
dev_info(&adapter->pdev->dev, "\n");
}
- val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD);
- val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD);
+ val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, &err);
+ if (err == -EIO)
+ return;
+ val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, &err);
+ if (err == -EIO)
+ return;
dev_info(&adapter->pdev->dev,
"IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
val, val1);
@@ -1425,7 +1441,7 @@ static void qlcnic_83xx_take_eport_out_of_reset(struct qlcnic_adapter *adapter)
static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
{
u32 heartbeat, peg_status;
- int retries, ret = -EIO;
+ int retries, ret = -EIO, err = 0;
retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
p_dev->heartbeat = QLC_SHARED_REG_RD32(p_dev,
@@ -1453,11 +1469,11 @@ static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
"PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
"PEG_NET_4_PC: 0x%x\n", peg_status,
QLC_SHARED_REG_RD32(p_dev, QLCNIC_PEG_HALT_STATUS2),
- QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0),
- QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1),
- QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2),
- QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3),
- QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4));
+ QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0, &err),
+ QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1, &err),
+ QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2, &err),
+ QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3, &err),
+ QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4, &err));
if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
dev_err(&p_dev->pdev->dev,
@@ -1501,18 +1517,22 @@ int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)
static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr,
int duration, u32 mask, u32 status)
{
+ int timeout_error, err = 0;
u32 value;
- int timeout_error;
u8 retries;
- value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+ value = QLCRD32(p_dev, addr, &err);
+ if (err == -EIO)
+ return err;
retries = duration / 10;
do {
if ((value & mask) != status) {
timeout_error = 1;
msleep(duration / 10);
- value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+ value = QLCRD32(p_dev, addr, &err);
+ if (err == -EIO)
+ return err;
} else {
timeout_error = 0;
break;
@@ -1606,9 +1626,12 @@ int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev,
u32 raddr, u32 waddr)
{
- int value;
+ int err = 0;
+ u32 value;
- value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+ value = QLCRD32(p_dev, raddr, &err);
+ if (err == -EIO)
+ return;
qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
}
@@ -1617,12 +1640,16 @@ static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev,
u32 raddr, u32 waddr,
struct qlc_83xx_rmw *p_rmw_hdr)
{
- int value;
+ int err = 0;
+ u32 value;
- if (p_rmw_hdr->index_a)
+ if (p_rmw_hdr->index_a) {
value = p_dev->ahw->reset.array[p_rmw_hdr->index_a];
- else
- value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+ } else {
+ value = QLCRD32(p_dev, raddr, &err);
+ if (err == -EIO)
+ return;
+ }
value &= p_rmw_hdr->mask;
value <<= p_rmw_hdr->shl;
@@ -1675,7 +1702,7 @@ static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
long delay;
struct qlc_83xx_entry *entry;
struct qlc_83xx_poll *poll;
- int i;
+ int i, err = 0;
unsigned long arg1, arg2;
poll = (struct qlc_83xx_poll *)((char *)p_hdr +
@@ -1699,10 +1726,12 @@ static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
arg1, delay,
poll->mask,
poll->status)){
- qlcnic_83xx_rd_reg_indirect(p_dev,
- arg1);
- qlcnic_83xx_rd_reg_indirect(p_dev,
- arg2);
+ QLCRD32(p_dev, arg1, &err);
+ if (err == -EIO)
+ return;
+ QLCRD32(p_dev, arg2, &err);
+ if (err == -EIO)
+ return;
}
}
}
@@ -1768,7 +1797,7 @@ static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
struct qlc_83xx_entry_hdr *p_hdr)
{
long delay;
- int index, i, j;
+ int index, i, j, err;
struct qlc_83xx_quad_entry *entry;
struct qlc_83xx_poll *poll;
unsigned long addr;
@@ -1788,7 +1817,10 @@ static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
poll->mask, poll->status)){
index = p_dev->ahw->reset.array_index;
addr = entry->dr_addr;
- j = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+ j = QLCRD32(p_dev, addr, &err);
+ if (err == -EIO)
+ return;
+
p_dev->ahw->reset.array[index++] = j;
if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES)
@@ -2123,6 +2155,8 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
qlcnic_83xx_clear_function_resources(adapter);
+ INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
+
/* register for NIC IDC AEN Events */
qlcnic_83xx_register_nic_idc_func(adapter, 1);
@@ -2140,8 +2174,6 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
if (adapter->nic_ops->init_driver(adapter))
return -EIO;
- INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
-
/* Periodically monitor device status */
qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index 0581a484ceb..d09389b3347 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -104,7 +104,7 @@ static u32
qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
{
u32 rsp;
- int timeout = 0;
+ int timeout = 0, err = 0;
do {
/* give atleast 1ms for firmware to respond */
@@ -113,7 +113,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT)
return QLCNIC_CDRP_RSP_TIMEOUT;
- rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET);
+ rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET, &err);
} while (!QLCNIC_CDRP_IS_RSP(rsp));
return rsp;
@@ -122,7 +122,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
struct qlcnic_cmd_args *cmd)
{
- int i;
+ int i, err = 0;
u32 rsp;
u32 signature;
struct pci_dev *pdev = adapter->pdev;
@@ -148,7 +148,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
dev_err(&pdev->dev, "card response timeout.\n");
cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
} else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
- cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1));
+ cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1), &err);
switch (cmd->rsp.arg[0]) {
case QLCNIC_RCODE_INVALID_ARGS:
fmt = "CDRP invalid args: [%d]\n";
@@ -175,7 +175,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS;
for (i = 1; i < cmd->rsp.num; i++)
- cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i));
+ cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i), &err);
/* Release semaphore */
qlcnic_api_unlock(adapter);
@@ -210,10 +210,10 @@ int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter, u32 fw_cmd)
if (err) {
dev_info(&adapter->pdev->dev,
"Failed to set driver version in firmware\n");
- return -EIO;
+ err = -EIO;
}
-
- return 0;
+ qlcnic_free_mbx_args(&cmd);
+ return err;
}
int
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 700a46324d0..7aac23ab31d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -150,6 +150,7 @@ static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
"Link_Test_on_offline",
"Interrupt_Test_offline",
"Internal_Loopback_offline",
+ "External_Loopback_offline",
"EEPROM_Test_offline"
};
@@ -266,7 +267,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
u32 speed, reg;
- int check_sfp_module = 0;
+ int check_sfp_module = 0, err = 0;
u16 pcifn = ahw->pci_func;
/* read which mode */
@@ -289,7 +290,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
} else if (adapter->ahw->port_type == QLCNIC_XGBE) {
u32 val = 0;
- val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
+ val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err);
if (val == QLCNIC_PORT_MODE_802_3_AP) {
ecmd->supported = SUPPORTED_1000baseT_Full;
@@ -300,9 +301,13 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
}
if (netif_running(adapter->netdev) && ahw->has_link_events) {
- reg = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
- speed = P3P_LINK_SPEED_VAL(pcifn, reg);
- ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
+ if (ahw->linkup) {
+ reg = QLCRD32(adapter,
+ P3P_LINK_SPEED_REG(pcifn), &err);
+ speed = P3P_LINK_SPEED_VAL(pcifn, reg);
+ ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
+ }
+
ethtool_cmd_speed_set(ecmd, ahw->link_speed);
ecmd->autoneg = ahw->link_autoneg;
ecmd->duplex = ahw->link_duplex;
@@ -463,13 +468,14 @@ static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter,
u32 *regs_buff)
{
- int i, j = 0;
+ int i, j = 0, err = 0;
for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]);
j = 0;
while (ext_diag_registers[j] != -1)
- regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++]);
+ regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++],
+ &err);
return i;
}
@@ -519,13 +525,16 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
static u32 qlcnic_test_link(struct net_device *dev)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
+ int err = 0;
u32 val;
if (qlcnic_83xx_check(adapter)) {
val = qlcnic_83xx_test_link(adapter);
return (val & 1) ? 0 : 1;
}
- val = QLCRD32(adapter, CRB_XG_STATE_P3P);
+ val = QLCRD32(adapter, CRB_XG_STATE_P3P, &err);
+ if (err == -EIO)
+ return err;
val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
return (val == XG_LINK_UP_P3P) ? 0 : 1;
}
@@ -658,6 +667,7 @@ qlcnic_get_pauseparam(struct net_device *netdev,
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int port = adapter->ahw->physical_port;
+ int err = 0;
__u32 val;
if (qlcnic_83xx_check(adapter)) {
@@ -668,9 +678,13 @@ qlcnic_get_pauseparam(struct net_device *netdev,
if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
return;
/* get flow control settings */
- val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+ val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
+ if (err == -EIO)
+ return;
pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
- val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+ val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
+ if (err == -EIO)
+ return;
switch (port) {
case 0:
pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
@@ -690,7 +704,9 @@ qlcnic_get_pauseparam(struct net_device *netdev,
if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
return;
pause->rx_pause = 1;
- val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+ val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
+ if (err == -EIO)
+ return;
if (port == 0)
pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
else
@@ -707,6 +723,7 @@ qlcnic_set_pauseparam(struct net_device *netdev,
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int port = adapter->ahw->physical_port;
+ int err = 0;
__u32 val;
if (qlcnic_83xx_check(adapter))
@@ -717,7 +734,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
return -EIO;
/* set flow control */
- val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+ val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
+ if (err == -EIO)
+ return err;
if (pause->rx_pause)
qlcnic_gb_rx_flowctl(val);
@@ -728,7 +747,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
val);
QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
/* set autoneg */
- val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+ val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
+ if (err == -EIO)
+ return err;
switch (port) {
case 0:
if (pause->tx_pause)
@@ -764,7 +785,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
return -EIO;
- val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+ val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
+ if (err == -EIO)
+ return err;
if (port == 0) {
if (pause->tx_pause)
qlcnic_xg_unset_xg0_mask(val);
@@ -788,11 +811,14 @@ static int qlcnic_reg_test(struct net_device *dev)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 data_read;
+ int err = 0;
if (qlcnic_83xx_check(adapter))
return qlcnic_83xx_reg_test(adapter);
- data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
+ data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0), &err);
+ if (err == -EIO)
+ return err;
if ((data_read & 0xffff) != adapter->pdev->vendor)
return 1;
@@ -1026,8 +1052,15 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
if (data[3])
eth_test->flags |= ETH_TEST_FL_FAILED;
- data[4] = qlcnic_eeprom_test(dev);
- if (data[4])
+ if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
+ data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
+ if (data[4])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+ eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
+ }
+
+ data[5] = qlcnic_eeprom_test(dev);
+ if (data[5])
eth_test->flags |= ETH_TEST_FL_FAILED;
}
}
@@ -1257,17 +1290,20 @@ qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 wol_cfg;
+ int err = 0;
if (qlcnic_83xx_check(adapter))
return;
wol->supported = 0;
wol->wolopts = 0;
- wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
+ if (err == -EIO)
+ return;
if (wol_cfg & (1UL << adapter->portnum))
wol->supported |= WAKE_MAGIC;
- wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
if (wol_cfg & (1UL << adapter->portnum))
wol->wolopts |= WAKE_MAGIC;
}
@@ -1277,17 +1313,22 @@ qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 wol_cfg;
+ int err = 0;
if (qlcnic_83xx_check(adapter))
return -EOPNOTSUPP;
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
- wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
+ if (err == -EIO)
+ return err;
if (!(wol_cfg & (1 << adapter->portnum)))
return -EOPNOTSUPP;
- wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
+ if (err == -EIO)
+ return err;
if (wol->wolopts & WAKE_MAGIC)
wol_cfg |= 1UL << adapter->portnum;
else
@@ -1540,7 +1581,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
return 0;
case QLCNIC_SET_QUIESCENT:
case QLCNIC_RESET_QUIESCENT:
- state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
netdev_info(netdev, "Device in FAILED state\n");
return 0;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 5b5d2edf125..4d5f59b2d15 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -317,16 +317,20 @@ static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data)
int
qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
{
- int done = 0, timeout = 0;
+ int timeout = 0;
+ int err = 0;
+ u32 done = 0;
while (!done) {
- done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)));
+ done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)),
+ &err);
if (done == 1)
break;
if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
dev_err(&adapter->pdev->dev,
"Failed to acquire sem=%d lock; holdby=%d\n",
- sem, id_reg ? QLCRD32(adapter, id_reg) : -1);
+ sem,
+ id_reg ? QLCRD32(adapter, id_reg, &err) : -1);
return -EIO;
}
msleep(1);
@@ -341,19 +345,22 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
void
qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem)
{
- QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)));
+ int err = 0;
+
+ QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)), &err);
}
int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
{
+ int err = 0;
u32 data;
if (qlcnic_82xx_check(adapter))
qlcnic_read_window_reg(addr, adapter->ahw->pci_base0, &data);
else {
- data = qlcnic_83xx_rd_reg_indirect(adapter, addr);
- if (data == -EIO)
- return -EIO;
+ data = QLCRD32(adapter, addr, &err);
+ if (err == -EIO)
+ return err;
}
return data;
}
@@ -516,20 +523,18 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
if (netdev->flags & IFF_PROMISC) {
if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
mode = VPORT_MISS_MODE_ACCEPT_ALL;
- } else if (netdev->flags & IFF_ALLMULTI) {
- if (netdev_mc_count(netdev) > ahw->max_mc_count) {
- mode = VPORT_MISS_MODE_ACCEPT_MULTI;
- } else if (!netdev_mc_empty(netdev) &&
- !qlcnic_sriov_vf_check(adapter)) {
- netdev_for_each_mc_addr(ha, netdev)
- qlcnic_nic_add_mac(adapter, ha->addr,
- vlan);
- }
- if (mode != VPORT_MISS_MODE_ACCEPT_MULTI &&
- qlcnic_sriov_vf_check(adapter))
- qlcnic_vf_add_mc_list(netdev, vlan);
+ } else if ((netdev->flags & IFF_ALLMULTI) ||
+ (netdev_mc_count(netdev) > ahw->max_mc_count)) {
+ mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+ } else if (!netdev_mc_empty(netdev) &&
+ !qlcnic_sriov_vf_check(adapter)) {
+ netdev_for_each_mc_addr(ha, netdev)
+ qlcnic_nic_add_mac(adapter, ha->addr, vlan);
}
+ if (qlcnic_sriov_vf_check(adapter))
+ qlcnic_vf_add_mc_list(netdev, vlan);
+
/* configure unicast MAC address, if there is not sufficient space
* to store all the unicast addresses then enable promiscuous mode
*/
@@ -1161,7 +1166,8 @@ int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off,
return -EIO;
}
-int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off,
+ int *err)
{
unsigned long flags;
int rv;
@@ -1417,7 +1423,7 @@ int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
{
- int offset, board_type, magic;
+ int offset, board_type, magic, err = 0;
struct pci_dev *pdev = adapter->pdev;
offset = QLCNIC_FW_MAGIC_OFFSET;
@@ -1437,7 +1443,9 @@ int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
adapter->ahw->board_type = board_type;
if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) {
- u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I);
+ u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I, &err);
+ if (err == -EIO)
+ return err;
if ((gpio & 0x8000) == 0)
board_type = QLCNIC_BRDTYPE_P3P_10G_TP;
}
@@ -1477,10 +1485,13 @@ int
qlcnic_wol_supported(struct qlcnic_adapter *adapter)
{
u32 wol_cfg;
+ int err = 0;
- wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
if (wol_cfg & (1UL << adapter->portnum)) {
- wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+ wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
+ if (err == -EIO)
+ return err;
if (wol_cfg & (1 << adapter->portnum))
return 1;
}
@@ -1541,6 +1552,7 @@ void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
loff_t offset, size_t size)
{
+ int err = 0;
u32 data;
u64 qmdata;
@@ -1548,7 +1560,7 @@ void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
memcpy(buf, &qmdata, size);
} else {
- data = QLCRD32(adapter, offset);
+ data = QLCRD32(adapter, offset, &err);
memcpy(buf, &data, size);
}
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index 2c22504f57a..4a71b28effc 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -154,7 +154,7 @@ struct qlcnic_hardware_context;
struct qlcnic_adapter;
int qlcnic_82xx_start_firmware(struct qlcnic_adapter *);
-int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong);
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong, int *);
int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int);
int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index d28336fc65a..974d62607e1 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -142,7 +142,7 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter)
buffrag->length, PCI_DMA_TODEVICE);
buffrag->dma = 0ULL;
}
- for (j = 0; j < cmd_buf->frag_count; j++) {
+ for (j = 1; j < cmd_buf->frag_count; j++) {
buffrag++;
if (buffrag->dma) {
pci_unmap_page(adapter->pdev, buffrag->dma,
@@ -286,10 +286,11 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
{
long timeout = 0;
long done = 0;
+ int err = 0;
cond_resched();
while (done == 0) {
- done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS);
+ done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS, &err);
done &= 2;
if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) {
dev_err(&adapter->pdev->dev,
@@ -304,6 +305,8 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
static int do_rom_fast_read(struct qlcnic_adapter *adapter,
u32 addr, u32 *valp)
{
+ int err = 0;
+
QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr);
QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3);
@@ -317,7 +320,9 @@ static int do_rom_fast_read(struct qlcnic_adapter *adapter,
udelay(10);
QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
- *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA);
+ *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA, &err);
+ if (err == -EIO)
+ return err;
return 0;
}
@@ -369,11 +374,11 @@ int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp)
int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
{
- int addr, val;
+ int addr, err = 0;
int i, n, init_delay;
struct crb_addr_pair *buf;
unsigned offset;
- u32 off;
+ u32 off, val;
struct pci_dev *pdev = adapter->pdev;
QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, 0);
@@ -402,7 +407,9 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
QLCWR32(adapter, QLCNIC_CRB_NIU + 0xb0000, 0x00);
/* halt sre */
- val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000);
+ val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000, &err);
+ if (err == -EIO)
+ return err;
QLCWR32(adapter, QLCNIC_CRB_SRE + 0x1000, val & (~(0x1)));
/* halt epg */
@@ -719,10 +726,12 @@ qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter)
static int
qlcnic_has_mn(struct qlcnic_adapter *adapter)
{
- u32 capability;
- capability = 0;
+ u32 capability = 0;
+ int err = 0;
- capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY);
+ capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY, &err);
+ if (err == -EIO)
+ return err;
if (capability & QLCNIC_PEG_TUNE_MN_PRESENT)
return 1;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index d3f8797efcc..6946d354f44 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -161,36 +161,68 @@ static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data)
return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0;
}
+static void qlcnic_delete_rx_list_mac(struct qlcnic_adapter *adapter,
+ struct qlcnic_filter *fil,
+ void *addr, u16 vlan_id)
+{
+ int ret;
+ u8 op;
+
+ op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
+ ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op);
+ if (ret)
+ return;
+
+ op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
+ ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op);
+ if (!ret) {
+ hlist_del(&fil->fnode);
+ adapter->rx_fhash.fnum--;
+ }
+}
+
+static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head,
+ void *addr, u16 vlan_id)
+{
+ struct qlcnic_filter *tmp_fil = NULL;
+ struct hlist_node *n;
+
+ hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
+ if (!memcmp(tmp_fil->faddr, addr, ETH_ALEN) &&
+ tmp_fil->vlan_id == vlan_id)
+ return tmp_fil;
+ }
+
+ return NULL;
+}
+
void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
int loopback_pkt, u16 vlan_id)
{
struct ethhdr *phdr = (struct ethhdr *)(skb->data);
struct qlcnic_filter *fil, *tmp_fil;
- struct hlist_node *n;
struct hlist_head *head;
unsigned long time;
u64 src_addr = 0;
- u8 hindex, found = 0, op;
+ u8 hindex, op;
int ret;
memcpy(&src_addr, phdr->h_source, ETH_ALEN);
+ hindex = qlcnic_mac_hash(src_addr) &
+ (adapter->fhash.fbucket_size - 1);
if (loopback_pkt) {
if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax)
return;
- hindex = qlcnic_mac_hash(src_addr) &
- (adapter->fhash.fbucket_size - 1);
head = &(adapter->rx_fhash.fhead[hindex]);
- hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
- if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
- tmp_fil->vlan_id == vlan_id) {
- time = tmp_fil->ftime;
- if (jiffies > (QLCNIC_READD_AGE * HZ + time))
- tmp_fil->ftime = jiffies;
- return;
- }
+ tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
+ if (tmp_fil) {
+ time = tmp_fil->ftime;
+ if (time_after(jiffies, QLCNIC_READD_AGE * HZ + time))
+ tmp_fil->ftime = jiffies;
+ return;
}
fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
@@ -205,36 +237,37 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
adapter->rx_fhash.fnum++;
spin_unlock(&adapter->rx_mac_learn_lock);
} else {
- hindex = qlcnic_mac_hash(src_addr) &
- (adapter->fhash.fbucket_size - 1);
- head = &(adapter->rx_fhash.fhead[hindex]);
- spin_lock(&adapter->rx_mac_learn_lock);
- hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
- if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
- tmp_fil->vlan_id == vlan_id) {
- found = 1;
- break;
- }
- }
+ head = &adapter->fhash.fhead[hindex];
- if (!found) {
- spin_unlock(&adapter->rx_mac_learn_lock);
- return;
- }
+ spin_lock(&adapter->mac_learn_lock);
- op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
- ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr,
- vlan_id, op);
- if (!ret) {
+ tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
+ if (tmp_fil) {
op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
ret = qlcnic_sre_macaddr_change(adapter,
(u8 *)&src_addr,
vlan_id, op);
if (!ret) {
- hlist_del(&(tmp_fil->fnode));
- adapter->rx_fhash.fnum--;
+ hlist_del(&tmp_fil->fnode);
+ adapter->fhash.fnum--;
}
+
+ spin_unlock(&adapter->mac_learn_lock);
+
+ return;
}
+
+ spin_unlock(&adapter->mac_learn_lock);
+
+ head = &adapter->rx_fhash.fhead[hindex];
+
+ spin_lock(&adapter->rx_mac_learn_lock);
+
+ tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
+ if (tmp_fil)
+ qlcnic_delete_rx_list_mac(adapter, tmp_fil, &src_addr,
+ vlan_id);
+
spin_unlock(&adapter->rx_mac_learn_lock);
}
}
@@ -262,7 +295,7 @@ void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
- memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
+ memcpy(mac_req->mac_addr, uaddr, ETH_ALEN);
vlan_req = (struct qlcnic_vlan_req *)&req->words[1];
vlan_req->vlan_id = cpu_to_le16(vlan_id);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 4528f8ec333..bc05d016c85 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -977,8 +977,8 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
static int
qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
{
- int err;
struct qlcnic_info nic_info;
+ int err = 0;
memset(&nic_info, 0, sizeof(struct qlcnic_info));
err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func);
@@ -993,7 +993,9 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
u32 temp;
- temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+ temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2, &err);
+ if (err == -EIO)
+ return err;
adapter->ahw->extra_capability[0] = temp;
}
adapter->ahw->max_mac_filters = nic_info.max_mac_filters;
@@ -1383,6 +1385,8 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
if (qlcnic_82xx_check(adapter))
handler = qlcnic_tmp_intr;
+ else
+ handler = qlcnic_83xx_tmp_intr;
if (!QLCNIC_IS_MSI_FAMILY(adapter))
flags |= IRQF_SHARED;
@@ -1531,12 +1535,12 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
if (netdev->features & NETIF_F_LRO)
qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
+ set_bit(__QLCNIC_DEV_UP, &adapter->state);
qlcnic_napi_enable(adapter);
qlcnic_linkevent_request(adapter, 1);
adapter->ahw->reset_context = 0;
- set_bit(__QLCNIC_DEV_UP, &adapter->state);
return 0;
}
@@ -2139,7 +2143,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (qlcnic_83xx_check(adapter) && !qlcnic_use_msi_x &&
!!qlcnic_use_msi)
dev_warn(&pdev->dev,
- "83xx adapter do not support MSI interrupts\n");
+ "Device does not support MSI interrupts\n");
err = qlcnic_setup_intr(adapter, 0);
if (err) {
@@ -2161,7 +2165,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_out_disable_mbx_intr;
- qlcnic_set_drv_version(adapter);
+ if (adapter->portnum == 0)
+ qlcnic_set_drv_version(adapter);
pci_set_drvdata(pdev, adapter);
@@ -3081,7 +3086,8 @@ done:
adapter->fw_fail_cnt = 0;
adapter->flags &= ~QLCNIC_FW_HANG;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
- qlcnic_set_drv_version(adapter);
+ if (adapter->portnum == 0)
+ qlcnic_set_drv_version(adapter);
if (!qlcnic_clr_drv_state(adapter))
qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
@@ -3093,6 +3099,7 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
{
u32 state = 0, heartbeat;
u32 peg_status;
+ int err = 0;
if (qlcnic_check_temp(adapter))
goto detach;
@@ -3139,11 +3146,11 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
"PEG_NET_4_PC: 0x%x\n",
peg_status,
QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS2),
- QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c),
- QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c),
- QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c),
- QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c),
- QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c));
+ QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c, &err),
+ QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c, &err),
+ QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c, &err),
+ QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c, &err),
+ QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, &err));
if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
dev_err(&adapter->pdev->dev,
"Firmware aborted with error code 0x00006700. "
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
index ab8a6744d40..79e54efe07b 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -1084,7 +1084,7 @@ flash_temp:
tmpl_hdr = ahw->fw_dump.tmpl_hdr;
tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
- if ((tmpl_hdr->version & 0xffffff) >= 0x20001)
+ if ((tmpl_hdr->version & 0xfffff) >= 0x20001)
ahw->fw_dump.use_pex_dma = true;
else
ahw->fw_dump.use_pex_dma = false;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 62380ce8990..5d40045b3ce 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -562,7 +562,7 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
INIT_LIST_HEAD(&adapter->vf_mc_list);
if (!qlcnic_use_msi_x && !!qlcnic_use_msi)
dev_warn(&adapter->pdev->dev,
- "83xx adapter do not support MSI interrupts\n");
+ "Device does not support MSI interrupts\n");
err = qlcnic_setup_intr(adapter, 1);
if (err) {
@@ -762,6 +762,7 @@ static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type)
memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
mbx->req.arg[0] = (type | (mbx->req.num << 16) |
(3 << 29));
+ mbx->rsp.arg[0] = (type & 0xffff) | mbx->rsp.num << 16;
return 0;
}
}
@@ -813,6 +814,7 @@ static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans,
cmd->req.num = trans->req_pay_size / 4;
cmd->rsp.num = trans->rsp_pay_size / 4;
hdr = trans->rsp_hdr;
+ cmd->op_type = trans->req_hdr->op_type;
}
trans->trans_id = seq;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index ee0c1d30796..eb49cd65378 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -635,12 +635,12 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
struct qlcnic_cmd_args *cmd)
{
struct qlcnic_vf_info *vf = trans->vf;
- struct qlcnic_adapter *adapter = vf->adapter;
- int err;
+ struct qlcnic_vport *vp = vf->vp;
+ struct qlcnic_adapter *adapter;
u16 func = vf->pci_func;
+ int err;
- cmd->rsp.arg[0] = trans->req_hdr->cmd_op;
- cmd->rsp.arg[0] |= (1 << 16);
+ adapter = vf->adapter;
if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) {
err = qlcnic_sriov_pf_config_vport(adapter, 1, func);
@@ -650,6 +650,8 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
qlcnic_sriov_pf_config_vport(adapter, 0, func);
}
} else {
+ if (vp->vlan_mode == QLC_GUEST_VLAN_MODE)
+ vp->vlan = 0;
err = qlcnic_sriov_pf_config_vport(adapter, 0, func);
}
@@ -1183,7 +1185,7 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,
u8 cmd_op, mode = vp->vlan_mode;
cmd_op = trans->req_hdr->cmd_op;
- cmd->rsp.arg[0] = (cmd_op & 0xffff) | 14 << 16 | 1 << 25;
+ cmd->rsp.arg[0] |= 1 << 25;
switch (mode) {
case QLC_GUEST_VLAN_MODE:
@@ -1561,6 +1563,7 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
struct qlcnic_vf_info *vf)
{
struct net_device *dev = vf->adapter->netdev;
+ struct qlcnic_vport *vp = vf->vp;
if (!test_and_clear_bit(QLC_BC_VF_STATE, &vf->state)) {
clear_bit(QLC_BC_VF_FLR, &vf->state);
@@ -1573,6 +1576,9 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
return;
}
+ if (vp->vlan_mode == QLC_GUEST_VLAN_MODE)
+ vp->vlan = 0;
+
qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr);
netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func);
}
@@ -1621,13 +1627,15 @@ int qlcnic_sriov_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
- int i, num_vfs = sriov->num_vfs;
+ int i, num_vfs;
struct qlcnic_vf_info *vf_info;
u8 *curr_mac;
if (!qlcnic_sriov_pf_check(adapter))
return -EOPNOTSUPP;
+ num_vfs = sriov->num_vfs;
+
if (!is_valid_ether_addr(mac) || vf >= num_vfs)
return -EINVAL;
@@ -1741,6 +1749,7 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,
switch (vlan) {
case 4095:
+ vp->vlan = 0;
vp->vlan_mode = QLC_GUEST_VLAN_MODE;
break;
case 0:
@@ -1759,6 +1768,29 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,
return 0;
}
+static inline __u32 qlcnic_sriov_get_vf_vlan(struct qlcnic_adapter *adapter,
+ struct qlcnic_vport *vp, int vf)
+{
+ __u32 vlan = 0;
+
+ switch (vp->vlan_mode) {
+ case QLC_PVID_MODE:
+ vlan = vp->vlan;
+ break;
+ case QLC_GUEST_VLAN_MODE:
+ vlan = MAX_VLAN_ID;
+ break;
+ case QLC_NO_VLAN_MODE:
+ vlan = 0;
+ break;
+ default:
+ netdev_info(adapter->netdev, "Invalid VLAN mode = %d for VF %d\n",
+ vp->vlan_mode, vf);
+ }
+
+ return vlan;
+}
+
int qlcnic_sriov_get_vf_config(struct net_device *netdev,
int vf, struct ifla_vf_info *ivi)
{
@@ -1774,7 +1806,7 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev,
vp = sriov->vf_info[vf].vp;
memcpy(&ivi->mac, vp->mac, ETH_ALEN);
- ivi->vlan = vp->vlan;
+ ivi->vlan = qlcnic_sriov_get_vf_vlan(adapter, vp, vf);
ivi->qos = vp->qos;
ivi->spoofchk = vp->spoofchk;
if (vp->max_tx_bw == MAX_BW)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
index 10ed82b3bac..660c3f5b223 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -170,9 +170,9 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter,
if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) {
err = qlcnic_get_beacon_state(adapter, &h_beacon_state);
- if (!err) {
- dev_info(&adapter->pdev->dev,
- "Failed to get current beacon state\n");
+ if (err) {
+ netdev_err(adapter->netdev,
+ "Failed to get current beacon state\n");
} else {
if (h_beacon_state == QLCNIC_BEACON_DISABLE)
ahw->beacon_state = 0;
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index e6acb9fa576..d2e591955bd 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -478,7 +478,7 @@ rx_status_loop:
while (1) {
u32 status, len;
- dma_addr_t mapping;
+ dma_addr_t mapping, new_mapping;
struct sk_buff *skb, *new_skb;
struct cp_desc *desc;
const unsigned buflen = cp->rx_buf_sz;
@@ -520,6 +520,14 @@ rx_status_loop:
goto rx_next;
}
+ new_mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
+ PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&cp->pdev->dev, new_mapping)) {
+ dev->stats.rx_dropped++;
+ kfree_skb(new_skb);
+ goto rx_next;
+ }
+
dma_unmap_single(&cp->pdev->dev, mapping,
buflen, PCI_DMA_FROMDEVICE);
@@ -531,12 +539,11 @@ rx_status_loop:
skb_put(skb, len);
- mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
- PCI_DMA_FROMDEVICE);
cp->rx_skb[rx_tail] = new_skb;
cp_rx_skb(cp, skb, desc);
rx++;
+ mapping = new_mapping;
rx_next:
cp->rx_ring[rx_tail].opts2 = 0;
@@ -716,6 +723,22 @@ static inline u32 cp_tx_vlan_tag(struct sk_buff *skb)
TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
}
+static void unwind_tx_frag_mapping(struct cp_private *cp, struct sk_buff *skb,
+ int first, int entry_last)
+{
+ int frag, index;
+ struct cp_desc *txd;
+ skb_frag_t *this_frag;
+ for (frag = 0; frag+first < entry_last; frag++) {
+ index = first+frag;
+ cp->tx_skb[index] = NULL;
+ txd = &cp->tx_ring[index];
+ this_frag = &skb_shinfo(skb)->frags[frag];
+ dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
+ skb_frag_size(this_frag), PCI_DMA_TODEVICE);
+ }
+}
+
static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
struct net_device *dev)
{
@@ -749,6 +772,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
len = skb->len;
mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
+ if (dma_mapping_error(&cp->pdev->dev, mapping))
+ goto out_dma_error;
+
txd->opts2 = opts2;
txd->addr = cpu_to_le64(mapping);
wmb();
@@ -786,6 +812,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
first_len = skb_headlen(skb);
first_mapping = dma_map_single(&cp->pdev->dev, skb->data,
first_len, PCI_DMA_TODEVICE);
+ if (dma_mapping_error(&cp->pdev->dev, first_mapping))
+ goto out_dma_error;
+
cp->tx_skb[entry] = skb;
entry = NEXT_TX(entry);
@@ -799,6 +828,11 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
mapping = dma_map_single(&cp->pdev->dev,
skb_frag_address(this_frag),
len, PCI_DMA_TODEVICE);
+ if (dma_mapping_error(&cp->pdev->dev, mapping)) {
+ unwind_tx_frag_mapping(cp, skb, first_entry, entry);
+ goto out_dma_error;
+ }
+
eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
ctrl = eor | len | DescOwn;
@@ -859,11 +893,16 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
+out_unlock:
spin_unlock_irqrestore(&cp->lock, intr_flags);
cpw8(TxPoll, NormalTxPoll);
return NETDEV_TX_OK;
+out_dma_error:
+ kfree_skb(skb);
+ cp->dev->stats.tx_dropped++;
+ goto out_unlock;
}
/* Set or clear the multicast filter for this adaptor.
@@ -1054,6 +1093,10 @@ static int cp_refill_rx(struct cp_private *cp)
mapping = dma_map_single(&cp->pdev->dev, skb->data,
cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&cp->pdev->dev, mapping)) {
+ kfree_skb(skb);
+ goto err_out;
+ }
cp->rx_skb[i] = skb;
cp->rx_ring[i].opts2 = 0;
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 4106a743ca7..85e5c97191d 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -3689,7 +3689,7 @@ static void rtl_phy_work(struct rtl8169_private *tp)
if (tp->link_ok(ioaddr))
return;
- netif_warn(tp, link, tp->dev, "PHY reset until link up\n");
+ netif_dbg(tp, link, tp->dev, "PHY reset until link up\n");
tp->phy_reset_enable(tp);
@@ -6468,6 +6468,8 @@ static int rtl8169_close(struct net_device *dev)
rtl8169_down(dev);
rtl_unlock_work(tp);
+ cancel_work_sync(&tp->wk.work);
+
free_irq(pdev->irq, dev);
dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
@@ -6793,8 +6795,6 @@ static void rtl_remove_one(struct pci_dev *pdev)
rtl8168_driver_stop(tp);
}
- cancel_work_sync(&tp->wk.work);
-
netif_napi_del(&tp->napi);
unregister_netdev(dev);
@@ -7088,7 +7088,7 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
RTL_W8(Cfg9346, Cfg9346_Unlock);
RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
- RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
+ RTL_W8(Config5, RTL_R8(Config5) & (BWF | MWF | UWF | LanWake | PMEStatus));
if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
tp->features |= RTL_FEATURE_WOL;
if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c
index b74a60ab9ac..30d744235d2 100644
--- a/drivers/net/ethernet/sfc/filter.c
+++ b/drivers/net/ethernet/sfc/filter.c
@@ -675,7 +675,7 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
BUILD_BUG_ON(EFX_FILTER_INDEX_UC_DEF != 0);
BUILD_BUG_ON(EFX_FILTER_INDEX_MC_DEF !=
EFX_FILTER_MC_DEF - EFX_FILTER_UC_DEF);
- rep_index = spec->type - EFX_FILTER_INDEX_UC_DEF;
+ rep_index = spec->type - EFX_FILTER_UC_DEF;
ins_index = rep_index;
spin_lock_bh(&state->lock);
@@ -1209,7 +1209,9 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb,
EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + 4 * ip->ihl + 4);
ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl);
- efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, 0, rxq_index);
+ efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT,
+ efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0,
+ rxq_index);
rc = efx_filter_set_ipv4_full(&spec, ip->protocol,
ip->daddr, ports[1], ip->saddr, ports[0]);
if (rc)
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index eb4aea3fe79..f5d7ad75e47 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -1318,7 +1318,7 @@ static void sis900_timer(unsigned long data)
if (duplex){
sis900_set_mode(sis_priv, speed, duplex);
sis630_set_eq(net_dev, sis_priv->chipset_rev);
- netif_start_queue(net_dev);
+ netif_carrier_on(net_dev);
}
sis_priv->timer.expires = jiffies + HZ;
@@ -1336,10 +1336,8 @@ static void sis900_timer(unsigned long data)
status = sis900_default_phy(net_dev);
mii_phy = sis_priv->mii;
- if (status & MII_STAT_LINK){
+ if (status & MII_STAT_LINK)
sis900_check_mode(net_dev, mii_phy);
- netif_carrier_on(net_dev);
- }
} else {
/* Link ON -> OFF */
if (!(status & MII_STAT_LINK)){
@@ -1612,12 +1610,6 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
unsigned int index_cur_tx, index_dirty_tx;
unsigned int count_dirty_tx;
- /* Don't transmit data before the complete of auto-negotiation */
- if(!sis_priv->autong_complete){
- netif_stop_queue(net_dev);
- return NETDEV_TX_BUSY;
- }
-
spin_lock_irqsave(&sis_priv->lock, flags);
/* Calculate the next Tx descriptor entry. */
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index c9d942a5c33..1ef9d8a555a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -33,10 +33,15 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
struct stmmac_priv *priv = (struct stmmac_priv *)p;
unsigned int txsize = priv->dma_tx_size;
unsigned int entry = priv->cur_tx % txsize;
- struct dma_desc *desc = priv->dma_tx + entry;
+ struct dma_desc *desc;
unsigned int nopaged_len = skb_headlen(skb);
unsigned int bmax, len;
+ if (priv->extend_desc)
+ desc = (struct dma_desc *)(priv->dma_etx + entry);
+ else
+ desc = priv->dma_tx + entry;
+
if (priv->plat->enh_desc)
bmax = BUF_SIZE_8KiB;
else
@@ -54,7 +59,11 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
STMMAC_RING_MODE);
wmb();
entry = (++priv->cur_tx) % txsize;
- desc = priv->dma_tx + entry;
+
+ if (priv->extend_desc)
+ desc = (struct dma_desc *)(priv->dma_etx + entry);
+ else
+ desc = priv->dma_tx + entry;
desc->des2 = dma_map_single(priv->device, skb->data + bmax,
len, DMA_TO_DEVICE);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index f2ccb36e868..0a9bb9d30c3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -939,15 +939,20 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN,
GFP_KERNEL);
- if (unlikely(skb == NULL)) {
+ if (!skb) {
pr_err("%s: Rx init fails; skb is NULL\n", __func__);
- return 1;
+ return -ENOMEM;
}
skb_reserve(skb, NET_IP_ALIGN);
priv->rx_skbuff[i] = skb;
priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
priv->dma_buf_sz,
DMA_FROM_DEVICE);
+ if (dma_mapping_error(priv->device, priv->rx_skbuff_dma[i])) {
+ pr_err("%s: DMA mapping error\n", __func__);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
p->des2 = priv->rx_skbuff_dma[i];
@@ -958,6 +963,16 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
return 0;
}
+static void stmmac_free_rx_buffers(struct stmmac_priv *priv, int i)
+{
+ if (priv->rx_skbuff[i]) {
+ dma_unmap_single(priv->device, priv->rx_skbuff_dma[i],
+ priv->dma_buf_sz, DMA_FROM_DEVICE);
+ dev_kfree_skb_any(priv->rx_skbuff[i]);
+ }
+ priv->rx_skbuff[i] = NULL;
+}
+
/**
* init_dma_desc_rings - init the RX/TX descriptor rings
* @dev: net device structure
@@ -965,13 +980,14 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
* and allocates the socket buffers. It suppors the chained and ring
* modes.
*/
-static void init_dma_desc_rings(struct net_device *dev)
+static int init_dma_desc_rings(struct net_device *dev)
{
int i;
struct stmmac_priv *priv = netdev_priv(dev);
unsigned int txsize = priv->dma_tx_size;
unsigned int rxsize = priv->dma_rx_size;
unsigned int bfsize = 0;
+ int ret = -ENOMEM;
/* Set the max buffer size according to the DESC mode
* and the MTU. Note that RING mode allows 16KiB bsize.
@@ -992,34 +1008,60 @@ static void init_dma_desc_rings(struct net_device *dev)
dma_extended_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
+ if (!priv->dma_erx)
+ goto err_dma;
+
priv->dma_etx = dma_alloc_coherent(priv->device, txsize *
sizeof(struct
dma_extended_desc),
&priv->dma_tx_phy,
GFP_KERNEL);
- if ((!priv->dma_erx) || (!priv->dma_etx))
- return;
+ if (!priv->dma_etx) {
+ dma_free_coherent(priv->device, priv->dma_rx_size *
+ sizeof(struct dma_extended_desc),
+ priv->dma_erx, priv->dma_rx_phy);
+ goto err_dma;
+ }
} else {
priv->dma_rx = dma_alloc_coherent(priv->device, rxsize *
sizeof(struct dma_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
+ if (!priv->dma_rx)
+ goto err_dma;
+
priv->dma_tx = dma_alloc_coherent(priv->device, txsize *
sizeof(struct dma_desc),
&priv->dma_tx_phy,
GFP_KERNEL);
- if ((!priv->dma_rx) || (!priv->dma_tx))
- return;
+ if (!priv->dma_tx) {
+ dma_free_coherent(priv->device, priv->dma_rx_size *
+ sizeof(struct dma_desc),
+ priv->dma_rx, priv->dma_rx_phy);
+ goto err_dma;
+ }
}
priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t),
GFP_KERNEL);
+ if (!priv->rx_skbuff_dma)
+ goto err_rx_skbuff_dma;
+
priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *),
GFP_KERNEL);
+ if (!priv->rx_skbuff)
+ goto err_rx_skbuff;
+
priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t),
GFP_KERNEL);
+ if (!priv->tx_skbuff_dma)
+ goto err_tx_skbuff_dma;
+
priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
GFP_KERNEL);
+ if (!priv->tx_skbuff)
+ goto err_tx_skbuff;
+
if (netif_msg_probe(priv)) {
pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__,
(u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy);
@@ -1034,8 +1076,9 @@ static void init_dma_desc_rings(struct net_device *dev)
else
p = priv->dma_rx + i;
- if (stmmac_init_rx_buffers(priv, p, i))
- break;
+ ret = stmmac_init_rx_buffers(priv, p, i);
+ if (ret)
+ goto err_init_rx_buffers;
if (netif_msg_probe(priv))
pr_debug("[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
@@ -1081,20 +1124,44 @@ static void init_dma_desc_rings(struct net_device *dev)
if (netif_msg_hw(priv))
stmmac_display_rings(priv);
+
+ return 0;
+err_init_rx_buffers:
+ while (--i >= 0)
+ stmmac_free_rx_buffers(priv, i);
+ kfree(priv->tx_skbuff);
+err_tx_skbuff:
+ kfree(priv->tx_skbuff_dma);
+err_tx_skbuff_dma:
+ kfree(priv->rx_skbuff);
+err_rx_skbuff:
+ kfree(priv->rx_skbuff_dma);
+err_rx_skbuff_dma:
+ if (priv->extend_desc) {
+ dma_free_coherent(priv->device, priv->dma_tx_size *
+ sizeof(struct dma_extended_desc),
+ priv->dma_etx, priv->dma_tx_phy);
+ dma_free_coherent(priv->device, priv->dma_rx_size *
+ sizeof(struct dma_extended_desc),
+ priv->dma_erx, priv->dma_rx_phy);
+ } else {
+ dma_free_coherent(priv->device,
+ priv->dma_tx_size * sizeof(struct dma_desc),
+ priv->dma_tx, priv->dma_tx_phy);
+ dma_free_coherent(priv->device,
+ priv->dma_rx_size * sizeof(struct dma_desc),
+ priv->dma_rx, priv->dma_rx_phy);
+ }
+err_dma:
+ return ret;
}
static void dma_free_rx_skbufs(struct stmmac_priv *priv)
{
int i;
- for (i = 0; i < priv->dma_rx_size; i++) {
- if (priv->rx_skbuff[i]) {
- dma_unmap_single(priv->device, priv->rx_skbuff_dma[i],
- priv->dma_buf_sz, DMA_FROM_DEVICE);
- dev_kfree_skb_any(priv->rx_skbuff[i]);
- }
- priv->rx_skbuff[i] = NULL;
- }
+ for (i = 0; i < priv->dma_rx_size; i++)
+ stmmac_free_rx_buffers(priv, i);
}
static void dma_free_tx_skbufs(struct stmmac_priv *priv)
@@ -1560,12 +1627,17 @@ static int stmmac_open(struct net_device *dev)
priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
- init_dma_desc_rings(dev);
+
+ ret = init_dma_desc_rings(dev);
+ if (ret < 0) {
+ pr_err("%s: DMA descriptors initialization failed\n", __func__);
+ goto dma_desc_error;
+ }
/* DMA initialization and SW reset */
ret = stmmac_init_dma_engine(priv);
if (ret < 0) {
- pr_err("%s: DMA initialization failed\n", __func__);
+ pr_err("%s: DMA engine initialization failed\n", __func__);
goto init_error;
}
@@ -1672,6 +1744,7 @@ wolirq_error:
init_error:
free_dma_desc_resources(priv);
+dma_desc_error:
if (priv->phydev)
phy_disconnect(priv->phydev);
phy_error:
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 03de76c7a17..1c83a44c547 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -71,14 +71,18 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
plat->force_sf_dma_mode = 1;
}
- dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), GFP_KERNEL);
- if (!dma_cfg)
- return -ENOMEM;
-
- plat->dma_cfg = dma_cfg;
- of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
- dma_cfg->fixed_burst = of_property_read_bool(np, "snps,fixed-burst");
- dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst");
+ if (of_find_property(np, "snps,pbl", NULL)) {
+ dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
+ GFP_KERNEL);
+ if (!dma_cfg)
+ return -ENOMEM;
+ plat->dma_cfg = dma_cfg;
+ of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
+ dma_cfg->fixed_burst =
+ of_property_read_bool(np, "snps,fixed-burst");
+ dma_cfg->mixed_burst =
+ of_property_read_bool(np, "snps,mixed-burst");
+ }
return 0;
}
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index fa322409bff..52b2adf63cb 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -9478,7 +9478,7 @@ static struct niu_parent *niu_new_parent(struct niu *np,
if (IS_ERR(plat_dev))
return NULL;
- for (i = 0; attr_name(niu_parent_attributes[i]); i++) {
+ for (i = 0; niu_parent_attributes[i].attr.name; i++) {
int err = device_create_file(&plat_dev->dev,
&niu_parent_attributes[i]);
if (err)
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 05a1674e204..22a7a433621 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1867,7 +1867,7 @@ static int cpsw_probe(struct platform_device *pdev)
while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
for (i = res->start; i <= res->end; i++) {
- if (request_irq(i, cpsw_interrupt, IRQF_DISABLED,
+ if (request_irq(i, cpsw_interrupt, 0,
dev_name(&pdev->dev), priv)) {
dev_err(priv->dev, "error attaching irq\n");
goto clean_ale_ret;
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index 07b176bcf92..1a222bce4bd 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -1568,8 +1568,7 @@ static int emac_dev_open(struct net_device *ndev)
while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
for (i = res->start; i <= res->end; i++) {
if (devm_request_irq(&priv->pdev->dev, i, emac_irq,
- IRQF_DISABLED,
- ndev->name, ndev))
+ 0, ndev->name, ndev))
goto rollback;
}
k++;
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
index ad32af67e61..9c805e0c0ca 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -1466,8 +1466,7 @@ static void gelic_ether_setup_netdev_ops(struct net_device *netdev,
{
netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
/* NAPI */
- netif_napi_add(netdev, napi,
- gelic_net_poll, GELIC_NET_NAPI_WEIGHT);
+ netif_napi_add(netdev, napi, gelic_net_poll, NAPI_POLL_WEIGHT);
netdev->ethtool_ops = &gelic_ether_ethtool_ops;
netdev->netdev_ops = &gelic_netdevice_ops;
}
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
index a93df6ac190..309abb472aa 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.h
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
@@ -37,7 +37,6 @@
#define GELIC_NET_RXBUF_ALIGN 128
#define GELIC_CARD_RX_CSUM_DEFAULT 1 /* hw chksum */
#define GELIC_NET_WATCHDOG_TIMEOUT 5*HZ
-#define GELIC_NET_NAPI_WEIGHT (GELIC_NET_RX_DESCRIPTORS)
#define GELIC_NET_BROADCAST_ADDR 0xffffffffffffL
#define GELIC_NET_MC_COUNT_MAX 32 /* multicast address list */
diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index 1d6dc41f755..d01cacf8a7c 100644
--- a/drivers/net/ethernet/via/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -2100,7 +2100,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
}
- netif_rx(skb);
+ netif_receive_skb(skb);
stats->rx_bytes += pkt_len;
stats->rx_packets++;
@@ -2884,6 +2884,7 @@ out:
return ret;
err_iounmap:
+ netif_napi_del(&vptr->napi);
iounmap(regs);
err_free_dev:
free_netdev(netdev);
@@ -2904,6 +2905,7 @@ static int velocity_remove(struct device *dev)
struct velocity_info *vptr = netdev_priv(netdev);
unregister_netdev(netdev);
+ netif_napi_del(&vptr->napi);
iounmap(vptr->mac_regs);
free_netdev(netdev);
velocity_nics--;
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
index e90e1f46121..64b4639f43b 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
@@ -175,6 +175,7 @@ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np)
printk(KERN_WARNING "Setting MDIO clock divisor to "
"default %d\n", DEFAULT_CLOCK_DIVISOR);
clk_div = DEFAULT_CLOCK_DIVISOR;
+ of_node_put(np1);
goto issue;
}
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 23a0fff0df5..524f713f601 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -306,7 +306,6 @@ static void netvsc_get_drvinfo(struct net_device *net,
struct ethtool_drvinfo *info)
{
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
- strlcpy(info->version, HV_DRV_VERSION, sizeof(info->version));
strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
}
@@ -529,7 +528,6 @@ static int __init netvsc_drv_init(void)
}
MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V network driver");
module_init(netvsc_drv_init);
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index a4126719783..177441afeb9 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -123,14 +123,14 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
tty = priv->tty;
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
old_termios = tty->termios;
cflag = tty->termios.c_cflag;
tty_encode_baud_rate(tty, speed, speed);
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
priv->io.speed = speed;
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
return 0;
}
@@ -280,7 +280,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
struct ktermios old_termios;
int cflag;
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
old_termios = tty->termios;
cflag = tty->termios.c_cflag;
@@ -292,7 +292,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
tty->termios.c_cflag = cflag;
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
}
/*****************************************************************/
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 51f2bc37610..2dcc60fb37f 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -210,8 +210,7 @@ static int via_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
pci_write_config_byte(pcidev,0x42,(bTmp | 0xf0));
pci_write_config_byte(pcidev,0x5a,0xc0);
WriteLPCReg(0x28, 0x70 );
- if (via_ircc_open(pcidev, &info, 0x3076) == 0)
- rc=0;
+ rc = via_ircc_open(pcidev, &info, 0x3076);
} else
rc = -ENODEV; //IR not turn on
} else { //Not VT1211
@@ -249,8 +248,7 @@ static int via_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
info.irq=FirIRQ;
info.dma=FirDRQ1;
info.dma2=FirDRQ0;
- if (via_ircc_open(pcidev, &info, 0x3096) == 0)
- rc=0;
+ rc = via_ircc_open(pcidev, &info, 0x3096);
} else
rc = -ENODEV; //IR not turn on !!!!!
}//Not VT1211
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 18373b6ae37..16b43bf544b 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -337,8 +337,11 @@ static int macvlan_open(struct net_device *dev)
int err;
if (vlan->port->passthru) {
- if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
- dev_set_promiscuity(lowerdev, 1);
+ if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) {
+ err = dev_set_promiscuity(lowerdev, 1);
+ if (err < 0)
+ goto out;
+ }
goto hash_add;
}
@@ -736,6 +739,10 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
return -EADDRNOTAVAIL;
}
+ if (data && data[IFLA_MACVLAN_FLAGS] &&
+ nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~MACVLAN_FLAG_NOPROMISC)
+ return -EINVAL;
+
if (data && data[IFLA_MACVLAN_MODE]) {
switch (nla_get_u32(data[IFLA_MACVLAN_MODE])) {
case MACVLAN_MODE_PRIVATE:
@@ -863,6 +870,18 @@ static int macvlan_changelink(struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct macvlan_dev *vlan = netdev_priv(dev);
+ enum macvlan_mode mode;
+ bool set_mode = false;
+
+ /* Validate mode, but don't set yet: setting flags may fail. */
+ if (data && data[IFLA_MACVLAN_MODE]) {
+ set_mode = true;
+ mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
+ /* Passthrough mode can't be set or cleared dynamically */
+ if ((mode == MACVLAN_MODE_PASSTHRU) !=
+ (vlan->mode == MACVLAN_MODE_PASSTHRU))
+ return -EINVAL;
+ }
if (data && data[IFLA_MACVLAN_FLAGS]) {
__u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
@@ -879,8 +898,8 @@ static int macvlan_changelink(struct net_device *dev,
}
vlan->flags = flags;
}
- if (data && data[IFLA_MACVLAN_MODE])
- vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
+ if (set_mode)
+ vlan->mode = mode;
return 0;
}
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index a98fb0ed6ae..ea53abb2098 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -68,6 +68,8 @@ static const struct proto_ops macvtap_socket_ops;
#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
NETIF_F_TSO6 | NETIF_F_UFO)
#define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO)
+#define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG)
+
/*
* RCU usage:
* The macvtap_queue and the macvlan_dev are loosely coupled, the
@@ -278,7 +280,8 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb)
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct macvtap_queue *q = macvtap_get_queue(dev, skb);
- netdev_features_t features;
+ netdev_features_t features = TAP_FEATURES;
+
if (!q)
goto drop;
@@ -287,9 +290,11 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb)
skb->dev = dev;
/* Apply the forward feature mask so that we perform segmentation
- * according to users wishes.
+ * according to users wishes. This only works if VNET_HDR is
+ * enabled.
*/
- features = netif_skb_features(skb) & vlan->tap_features;
+ if (q->flags & IFF_VNET_HDR)
+ features |= vlan->tap_features;
if (netif_needs_gso(skb, features)) {
struct sk_buff *segs = __skb_gso_segment(skb, features, false);
@@ -818,10 +823,13 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
}
- if (vlan)
+ if (vlan) {
+ local_bh_disable();
macvlan_start_xmit(skb, vlan->dev);
- else
+ local_bh_enable();
+ } else {
kfree_skb(skb);
+ }
rcu_read_unlock();
return total_len;
@@ -912,8 +920,11 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
done:
rcu_read_lock();
vlan = rcu_dereference(q->vlan);
- if (vlan)
+ if (vlan) {
+ preempt_disable();
macvlan_count_rx(vlan, copied - vnet_hdr_len, ret == 0, 0);
+ preempt_enable();
+ }
rcu_read_unlock();
return ret ? ret : copied;
@@ -1058,8 +1069,7 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg)
/* tap_features are the same as features on tun/tap and
* reflect user expectations.
*/
- vlan->tap_features = vlan->dev->features &
- (feature_mask | ~TUN_OFFLOADS);
+ vlan->tap_features = feature_mask;
vlan->set_features = features;
netdev_update_features(vlan->dev);
@@ -1155,10 +1165,6 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
TUN_F_TSO_ECN | TUN_F_UFO))
return -EINVAL;
- /* TODO: only accept frames with the features that
- got enabled for forwarded frames */
- if (!(q->flags & IFF_VNET_HDR))
- return -EINVAL;
rtnl_lock();
ret = set_offload(q, arg);
rtnl_unlock();
diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c
index 61d3f4ebf52..7f25e49ae37 100644
--- a/drivers/net/phy/mdio-sun4i.c
+++ b/drivers/net/phy/mdio-sun4i.c
@@ -40,7 +40,7 @@ struct sun4i_mdio_data {
static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{
struct sun4i_mdio_data *data = bus->priv;
- unsigned long start_jiffies;
+ unsigned long timeout_jiffies;
int value;
/* issue the phy address and reg */
@@ -49,10 +49,9 @@ static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
writel(0x1, data->membase + EMAC_MAC_MCMD_REG);
/* Wait read complete */
- start_jiffies = jiffies;
+ timeout_jiffies = jiffies + MDIO_TIMEOUT;
while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) {
- if (time_after(start_jiffies,
- start_jiffies + MDIO_TIMEOUT))
+ if (time_is_before_jiffies(timeout_jiffies))
return -ETIMEDOUT;
msleep(1);
}
@@ -69,7 +68,7 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
u16 value)
{
struct sun4i_mdio_data *data = bus->priv;
- unsigned long start_jiffies;
+ unsigned long timeout_jiffies;
/* issue the phy address and reg */
writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG);
@@ -77,10 +76,9 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
writel(0x1, data->membase + EMAC_MAC_MCMD_REG);
/* Wait read complete */
- start_jiffies = jiffies;
+ timeout_jiffies = jiffies + MDIO_TIMEOUT;
while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) {
- if (time_after(start_jiffies,
- start_jiffies + MDIO_TIMEOUT))
+ if (time_is_before_jiffies(timeout_jiffies))
return -ETIMEDOUT;
msleep(1);
}
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 8e7af835434..138de837977 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -23,7 +23,7 @@
#define RTL821x_INER_INIT 0x6400
#define RTL821x_INSR 0x13
-#define RTL8211E_INER_LINK_STAT 0x10
+#define RTL8211E_INER_LINK_STATUS 0x400
MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
@@ -57,7 +57,7 @@ static int rtl8211e_config_intr(struct phy_device *phydev)
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
err = phy_write(phydev, RTL821x_INER,
- RTL8211E_INER_LINK_STAT);
+ RTL8211E_INER_LINK_STATUS);
else
err = phy_write(phydev, RTL821x_INER, 0);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index db690a37226..71af122edf2 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1074,8 +1074,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
u32 rxhash;
if (!(tun->flags & TUN_NO_PI)) {
- if ((len -= sizeof(pi)) > total_len)
+ if (len < sizeof(pi))
return -EINVAL;
+ len -= sizeof(pi);
if (memcpy_fromiovecend((void *)&pi, iv, 0, sizeof(pi)))
return -EFAULT;
@@ -1083,8 +1084,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
}
if (tun->flags & TUN_VNET_HDR) {
- if ((len -= tun->vnet_hdr_sz) > total_len)
+ if (len < tun->vnet_hdr_sz)
return -EINVAL;
+ len -= tun->vnet_hdr_sz;
if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso)))
return -EFAULT;
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 1e3c302d94f..4233c05a3e3 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -1028,11 +1028,19 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
dev->mii.phy_id = 0x03;
dev->mii.supports_gmii = 1;
+ if (usb_device_no_sg_constraint(dev->udev))
+ dev->can_dma_sg = 1;
+
dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+ NETIF_F_RXCSUM;
dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+ NETIF_F_RXCSUM;
+
+ if (dev->can_dma_sg) {
+ dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
+ dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
+ }
/* Enable checksum offload */
*tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
@@ -1173,7 +1181,6 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
if (((skb->len + 8) % frame_size) == 0)
tx_hdr2 |= 0x80008000; /* Enable padding */
- skb_linearize(skb);
headroom = skb_headroom(skb);
tailroom = skb_tailroom(skb);
@@ -1317,10 +1324,10 @@ static int ax88179_reset(struct usbnet *dev)
1, 1, tmp);
dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+ NETIF_F_RXCSUM;
dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+ NETIF_F_RXCSUM;
/* Enable checksum offload */
*tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index 872819851ae..25ba7eca9a1 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -400,6 +400,10 @@ static const struct usb_device_id mbim_devs[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68a2, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
.driver_info = (unsigned long)&cdc_mbim_info_zlp,
},
+ /* HP hs2434 Mobile Broadband Module needs ZLPs */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x3f0, 0x4b1d, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&cdc_mbim_info_zlp,
+ },
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
.driver_info = (unsigned long)&cdc_mbim_info,
},
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index cba1d46e672..86292e6aaf4 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2816,13 +2816,16 @@ exit:
static int hso_get_config_data(struct usb_interface *interface)
{
struct usb_device *usbdev = interface_to_usbdev(interface);
- u8 config_data[17];
+ u8 *config_data = kmalloc(17, GFP_KERNEL);
u32 if_num = interface->altsetting->desc.bInterfaceNumber;
s32 result;
+ if (!config_data)
+ return -ENOMEM;
if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
0x86, 0xC0, 0, 0, config_data, 17,
USB_CTRL_SET_TIMEOUT) != 0x11) {
+ kfree(config_data);
return -EIO;
}
@@ -2873,6 +2876,7 @@ static int hso_get_config_data(struct usb_interface *interface)
if (config_data[16] & 0x1)
result |= HSO_INFO_CRC_BUG;
+ kfree(config_data);
return result;
}
@@ -2886,6 +2890,11 @@ static int hso_probe(struct usb_interface *interface,
struct hso_shared_int *shared_int;
struct hso_device *tmp_dev = NULL;
+ if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
+ dev_err(&interface->dev, "Not our interface\n");
+ return -ENODEV;
+ }
+
if_num = interface->altsetting->desc.bInterfaceNumber;
/* Get the interface/port specification from either driver_info or from
@@ -2895,10 +2904,6 @@ static int hso_probe(struct usb_interface *interface,
else
port_spec = hso_get_config_data(interface);
- if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
- dev_err(&interface->dev, "Not our interface\n");
- return -ENODEV;
- }
/* Check if we need to switch to alt interfaces prior to port
* configuration */
if (interface->num_altsetting > 1)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index ee13f9eb740..11c51f27536 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -344,17 +344,41 @@ static const int multicast_filter_limit = 32;
static
int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
{
- return usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
+ int ret;
+ void *tmp;
+
+ tmp = kmalloc(size, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
- value, index, data, size, 500);
+ value, index, tmp, size, 500);
+
+ memcpy(data, tmp, size);
+ kfree(tmp);
+
+ return ret;
}
static
int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
{
- return usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
+ int ret;
+ void *tmp;
+
+ tmp = kmalloc(size, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ memcpy(tmp, data, size);
+
+ ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
- value, index, data, size, 500);
+ value, index, tmp, size, 500);
+
+ kfree(tmp);
+ return ret;
}
static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
@@ -490,37 +514,31 @@ int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
static u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index)
{
- u32 data;
+ __le32 data;
- if (type == MCU_TYPE_PLA)
- pla_ocp_read(tp, index, sizeof(data), &data);
- else
- usb_ocp_read(tp, index, sizeof(data), &data);
+ generic_ocp_read(tp, index, sizeof(data), &data, type);
return __le32_to_cpu(data);
}
static void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data)
{
- if (type == MCU_TYPE_PLA)
- pla_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data);
- else
- usb_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data);
+ __le32 tmp = __cpu_to_le32(data);
+
+ generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type);
}
static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
{
u32 data;
+ __le32 tmp;
u8 shift = index & 2;
index &= ~3;
- if (type == MCU_TYPE_PLA)
- pla_ocp_read(tp, index, sizeof(data), &data);
- else
- usb_ocp_read(tp, index, sizeof(data), &data);
+ generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
- data = __le32_to_cpu(data);
+ data = __le32_to_cpu(tmp);
data >>= (shift * 8);
data &= 0xffff;
@@ -529,7 +547,8 @@ static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
{
- u32 tmp, mask = 0xffff;
+ u32 mask = 0xffff;
+ __le32 tmp;
u16 byen = BYTE_EN_WORD;
u8 shift = index & 2;
@@ -542,34 +561,25 @@ static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
index &= ~3;
}
- if (type == MCU_TYPE_PLA)
- pla_ocp_read(tp, index, sizeof(tmp), &tmp);
- else
- usb_ocp_read(tp, index, sizeof(tmp), &tmp);
+ generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
- tmp = __le32_to_cpu(tmp) & ~mask;
- tmp |= data;
- tmp = __cpu_to_le32(tmp);
+ data |= __le32_to_cpu(tmp) & ~mask;
+ tmp = __cpu_to_le32(data);
- if (type == MCU_TYPE_PLA)
- pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
- else
- usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
+ generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
}
static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
{
u32 data;
+ __le32 tmp;
u8 shift = index & 3;
index &= ~3;
- if (type == MCU_TYPE_PLA)
- pla_ocp_read(tp, index, sizeof(data), &data);
- else
- usb_ocp_read(tp, index, sizeof(data), &data);
+ generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
- data = __le32_to_cpu(data);
+ data = __le32_to_cpu(tmp);
data >>= (shift * 8);
data &= 0xff;
@@ -578,7 +588,8 @@ static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
{
- u32 tmp, mask = 0xff;
+ u32 mask = 0xff;
+ __le32 tmp;
u16 byen = BYTE_EN_BYTE;
u8 shift = index & 3;
@@ -591,19 +602,12 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
index &= ~3;
}
- if (type == MCU_TYPE_PLA)
- pla_ocp_read(tp, index, sizeof(tmp), &tmp);
- else
- usb_ocp_read(tp, index, sizeof(tmp), &tmp);
+ generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
- tmp = __le32_to_cpu(tmp) & ~mask;
- tmp |= data;
- tmp = __cpu_to_le32(tmp);
+ data |= __le32_to_cpu(tmp) & ~mask;
+ tmp = __cpu_to_le32(data);
- if (type == MCU_TYPE_PLA)
- pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
- else
- usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
+ generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
}
static void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
@@ -685,21 +689,14 @@ static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
static inline void set_ethernet_addr(struct r8152 *tp)
{
struct net_device *dev = tp->netdev;
- u8 *node_id;
-
- node_id = kmalloc(sizeof(u8) * 8, GFP_KERNEL);
- if (!node_id) {
- netif_err(tp, probe, dev, "out of memory");
- return;
- }
+ u8 node_id[8] = {0};
- if (pla_ocp_read(tp, PLA_IDR, sizeof(u8) * 8, node_id) < 0)
+ if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0)
netif_notice(tp, probe, dev, "inet addr fail\n");
else {
memcpy(dev->dev_addr, node_id, dev->addr_len);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
}
- kfree(node_id);
}
static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
@@ -882,15 +879,10 @@ static void rtl8152_set_rx_mode(struct net_device *netdev)
static void _rtl8152_set_rx_mode(struct net_device *netdev)
{
struct r8152 *tp = netdev_priv(netdev);
- u32 tmp, *mc_filter; /* Multicast hash filter */
+ u32 mc_filter[2]; /* Multicast hash filter */
+ __le32 tmp[2];
u32 ocp_data;
- mc_filter = kmalloc(sizeof(u32) * 2, GFP_KERNEL);
- if (!mc_filter) {
- netif_err(tp, link, netdev, "out of memory");
- return;
- }
-
clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
netif_stop_queue(netdev);
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
@@ -918,14 +910,12 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
}
}
- tmp = mc_filter[0];
- mc_filter[0] = __cpu_to_le32(swab32(mc_filter[1]));
- mc_filter[1] = __cpu_to_le32(swab32(tmp));
+ tmp[0] = __cpu_to_le32(swab32(mc_filter[1]));
+ tmp[1] = __cpu_to_le32(swab32(mc_filter[0]));
- pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(u32) * 2, mc_filter);
+ pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp);
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
netif_wake_queue(netdev);
- kfree(mc_filter);
}
static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c
index 85239226971..2df2f4fb42a 100644
--- a/drivers/net/usb/r815x.c
+++ b/drivers/net/usb/r815x.c
@@ -24,34 +24,43 @@
static int pla_read_word(struct usb_device *udev, u16 index)
{
- int data, ret;
+ int ret;
u8 shift = index & 2;
- __le32 ocp_data;
+ __le32 *tmp;
+
+ tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
index &= ~3;
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
- index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
- 500);
+ index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
if (ret < 0)
- return ret;
+ goto out2;
- data = __le32_to_cpu(ocp_data);
- data >>= (shift * 8);
- data &= 0xffff;
+ ret = __le32_to_cpu(*tmp);
+ ret >>= (shift * 8);
+ ret &= 0xffff;
- return data;
+out2:
+ kfree(tmp);
+ return ret;
}
static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
{
- __le32 ocp_data;
+ __le32 *tmp;
u32 mask = 0xffff;
u16 byen = BYTE_EN_WORD;
u8 shift = index & 2;
int ret;
+ tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
data &= mask;
if (shift) {
@@ -63,19 +72,20 @@ static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
- index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
- 500);
+ index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
if (ret < 0)
- return ret;
+ goto out3;
- data |= __le32_to_cpu(ocp_data) & ~mask;
- ocp_data = __cpu_to_le32(data);
+ data |= __le32_to_cpu(*tmp) & ~mask;
+ *tmp = __cpu_to_le32(data);
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
- index, MCU_TYPE_PLA | byen, &ocp_data,
- sizeof(ocp_data), 500);
+ index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp),
+ 500);
+out3:
+ kfree(tmp);
return ret;
}
@@ -116,11 +126,18 @@ out1:
static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
{
struct usbnet *dev = netdev_priv(netdev);
+ int ret;
if (phy_id != R815x_PHY_ID)
return -EINVAL;
- return ocp_reg_read(dev, BASE_MII + reg * 2);
+ if (usb_autopm_get_interface(dev->intf) < 0)
+ return -ENODEV;
+
+ ret = ocp_reg_read(dev, BASE_MII + reg * 2);
+
+ usb_autopm_put_interface(dev->intf);
+ return ret;
}
static
@@ -131,7 +148,12 @@ void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
if (phy_id != R815x_PHY_ID)
return;
+ if (usb_autopm_get_interface(dev->intf) < 0)
+ return;
+
ocp_reg_write(dev, BASE_MII + reg * 2, val);
+
+ usb_autopm_put_interface(dev->intf);
}
static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -150,7 +172,7 @@ static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
dev->mii.phy_id = R815x_PHY_ID;
dev->mii.supports_gmii = 1;
- return 0;
+ return status;
}
static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -169,7 +191,7 @@ static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
dev->mii.phy_id = R815x_PHY_ID;
dev->mii.supports_gmii = 0;
- return 0;
+ return status;
}
static const struct driver_info r8152_info = {
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 75409748c77..66ebbacf066 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -45,7 +45,6 @@
#define EEPROM_MAC_OFFSET (0x01)
#define DEFAULT_TX_CSUM_ENABLE (true)
#define DEFAULT_RX_CSUM_ENABLE (true)
-#define DEFAULT_TSO_ENABLE (true)
#define SMSC75XX_INTERNAL_PHY_ID (1)
#define SMSC75XX_TX_OVERHEAD (8)
#define MAX_RX_FIFO_SIZE (20 * 1024)
@@ -1410,17 +1409,14 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write);
- if (DEFAULT_TX_CSUM_ENABLE) {
+ if (DEFAULT_TX_CSUM_ENABLE)
dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
- if (DEFAULT_TSO_ENABLE)
- dev->net->features |= NETIF_F_SG |
- NETIF_F_TSO | NETIF_F_TSO6;
- }
+
if (DEFAULT_RX_CSUM_ENABLE)
dev->net->features |= NETIF_F_RXCSUM;
dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM;
+ NETIF_F_RXCSUM;
ret = smsc75xx_wait_ready(dev, 0);
if (ret < 0) {
@@ -2200,8 +2196,6 @@ static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev,
{
u32 tx_cmd_a, tx_cmd_b;
- skb_linearize(skb);
-
if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) {
struct sk_buff *skb2 =
skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags);
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 06ee82f557d..27a00b00603 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1197,6 +1197,37 @@ EXPORT_SYMBOL_GPL(usbnet_tx_timeout);
/*-------------------------------------------------------------------------*/
+static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
+{
+ unsigned num_sgs, total_len = 0;
+ int i, s = 0;
+
+ num_sgs = skb_shinfo(skb)->nr_frags + 1;
+ if (num_sgs == 1)
+ return 0;
+
+ urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), GFP_ATOMIC);
+ if (!urb->sg)
+ return -ENOMEM;
+
+ urb->num_sgs = num_sgs;
+ sg_init_table(urb->sg, urb->num_sgs);
+
+ sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb));
+ total_len += skb_headlen(skb);
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ struct skb_frag_struct *f = &skb_shinfo(skb)->frags[i];
+
+ total_len += skb_frag_size(f);
+ sg_set_page(&urb->sg[i + s], f->page.p, f->size,
+ f->page_offset);
+ }
+ urb->transfer_buffer_length = total_len;
+
+ return 1;
+}
+
netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
struct net_device *net)
{
@@ -1223,7 +1254,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
goto drop;
}
}
- length = skb->len;
if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) {
netif_dbg(dev, tx_err, dev->net, "no urb\n");
@@ -1233,10 +1263,14 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
entry = (struct skb_data *) skb->cb;
entry->urb = urb;
entry->dev = dev;
- entry->length = length;
usb_fill_bulk_urb (urb, dev->udev, dev->out,
skb->data, skb->len, tx_complete, skb);
+ if (dev->can_dma_sg) {
+ if (build_dma_sg(skb, urb) < 0)
+ goto drop;
+ }
+ entry->length = length = urb->transfer_buffer_length;
/* don't assume the hardware handles USB_ZERO_PACKET
* NOTE: strictly conforming cdc-ether devices should expect
@@ -1305,7 +1339,10 @@ drop:
not_drop:
if (skb)
dev_kfree_skb_any (skb);
- usb_free_urb (urb);
+ if (urb) {
+ kfree(urb->sg);
+ usb_free_urb(urb);
+ }
} else
netif_dbg(dev, tx_queued, dev->net,
"> tx, len %d, type 0x%x\n", length, skb->protocol);
@@ -1356,6 +1393,7 @@ static void usbnet_bh (unsigned long param)
rx_process (dev, skb);
continue;
case tx_done:
+ kfree(entry->urb->sg);
case rx_cleanup:
usb_free_urb (entry->urb);
dev_kfree_skb (skb);
@@ -1689,6 +1727,7 @@ int usbnet_resume (struct usb_interface *intf)
retval = usb_submit_urb(res, GFP_ATOMIC);
if (retval < 0) {
dev_kfree_skb_any(skb);
+ kfree(res->sg);
usb_free_urb(res);
usb_autopm_put_interface_async(dev->intf);
} else {
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index da866523cf2..eee1f19ef1e 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -269,6 +269,7 @@ static void veth_setup(struct net_device *dev)
dev->ethtool_ops = &veth_ethtool_ops;
dev->features |= NETIF_F_LLTX;
dev->features |= VETH_FEATURES;
+ dev->vlan_features = dev->features;
dev->destructor = veth_dev_free;
dev->hw_features = VETH_FEATURES;
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index a5ba8dd7e6b..767f7af3bd4 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -136,7 +136,8 @@ struct vxlan_dev {
u32 flags; /* VXLAN_F_* below */
struct work_struct sock_work;
- struct work_struct igmp_work;
+ struct work_struct igmp_join;
+ struct work_struct igmp_leave;
unsigned long age_interval;
struct timer_list age_timer;
@@ -736,7 +737,6 @@ static bool vxlan_snoop(struct net_device *dev,
return false;
}
-
/* See if multicast group is already in use by other ID */
static bool vxlan_group_used(struct vxlan_net *vn, __be32 remote_ip)
{
@@ -770,12 +770,13 @@ static void vxlan_sock_release(struct vxlan_net *vn, struct vxlan_sock *vs)
queue_work(vxlan_wq, &vs->del_work);
}
-/* Callback to update multicast group membership.
- * Scheduled when vxlan goes up/down.
+/* Callback to update multicast group membership when first VNI on
+ * multicast asddress is brought up
+ * Done as workqueue because ip_mc_join_group acquires RTNL.
*/
-static void vxlan_igmp_work(struct work_struct *work)
+static void vxlan_igmp_join(struct work_struct *work)
{
- struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_work);
+ struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_join);
struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id);
struct vxlan_sock *vs = vxlan->vn_sock;
struct sock *sk = vs->sock->sk;
@@ -785,10 +786,27 @@ static void vxlan_igmp_work(struct work_struct *work)
};
lock_sock(sk);
- if (vxlan_group_used(vn, vxlan->default_dst.remote_ip))
- ip_mc_join_group(sk, &mreq);
- else
- ip_mc_leave_group(sk, &mreq);
+ ip_mc_join_group(sk, &mreq);
+ release_sock(sk);
+
+ vxlan_sock_release(vn, vs);
+ dev_put(vxlan->dev);
+}
+
+/* Inverse of vxlan_igmp_join when last VNI is brought down */
+static void vxlan_igmp_leave(struct work_struct *work)
+{
+ struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_leave);
+ struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id);
+ struct vxlan_sock *vs = vxlan->vn_sock;
+ struct sock *sk = vs->sock->sk;
+ struct ip_mreqn mreq = {
+ .imr_multiaddr.s_addr = vxlan->default_dst.remote_ip,
+ .imr_ifindex = vxlan->default_dst.remote_ifindex,
+ };
+
+ lock_sock(sk);
+ ip_mc_leave_group(sk, &mreq);
release_sock(sk);
vxlan_sock_release(vn, vs);
@@ -1359,6 +1377,7 @@ static void vxlan_uninit(struct net_device *dev)
/* Start ageing timer and join group when device is brought up */
static int vxlan_open(struct net_device *dev)
{
+ struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_sock *vs = vxlan->vn_sock;
@@ -1366,10 +1385,11 @@ static int vxlan_open(struct net_device *dev)
if (!vs)
return -ENOTCONN;
- if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) {
+ if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) &&
+ vxlan_group_used(vn, vxlan->default_dst.remote_ip)) {
vxlan_sock_hold(vs);
dev_hold(dev);
- queue_work(vxlan_wq, &vxlan->igmp_work);
+ queue_work(vxlan_wq, &vxlan->igmp_join);
}
if (vxlan->age_interval)
@@ -1400,13 +1420,15 @@ static void vxlan_flush(struct vxlan_dev *vxlan)
/* Cleanup timer and forwarding table on shutdown */
static int vxlan_stop(struct net_device *dev)
{
+ struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_sock *vs = vxlan->vn_sock;
- if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) {
+ if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) &&
+ ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) {
vxlan_sock_hold(vs);
dev_hold(dev);
- queue_work(vxlan_wq, &vxlan->igmp_work);
+ queue_work(vxlan_wq, &vxlan->igmp_leave);
}
del_timer_sync(&vxlan->age_timer);
@@ -1471,7 +1493,8 @@ static void vxlan_setup(struct net_device *dev)
INIT_LIST_HEAD(&vxlan->next);
spin_lock_init(&vxlan->hash_lock);
- INIT_WORK(&vxlan->igmp_work, vxlan_igmp_work);
+ INIT_WORK(&vxlan->igmp_join, vxlan_igmp_join);
+ INIT_WORK(&vxlan->igmp_leave, vxlan_igmp_leave);
INIT_WORK(&vxlan->sock_work, vxlan_sock_work);
init_timer_deferrable(&vxlan->age_timer);
@@ -1770,8 +1793,6 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head)
struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
struct vxlan_dev *vxlan = netdev_priv(dev);
- flush_workqueue(vxlan_wq);
-
spin_lock(&vn->sock_lock);
hlist_del_rcu(&vxlan->hlist);
spin_unlock(&vn->sock_lock);
@@ -1878,10 +1899,12 @@ static __net_exit void vxlan_exit_net(struct net *net)
{
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
struct vxlan_dev *vxlan;
+ LIST_HEAD(list);
rtnl_lock();
list_for_each_entry(vxlan, &vn->vxlan_list, next)
- dev_close(vxlan->dev);
+ unregister_netdevice_queue(vxlan->dev, &list);
+ unregister_netdevice_many(&list);
rtnl_unlock();
}
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index cde58fe9625..82e8088ca9b 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -1,6 +1,6 @@
config ATH10K
tristate "Atheros 802.11ac wireless cards support"
- depends on MAC80211
+ depends on MAC80211 && HAS_DMA
select ATH_COMMON
---help---
This module adds support for wireless adapters based on
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 81b686c6a37..40825d43322 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -325,7 +325,7 @@ ath5k_prepare_multicast(struct ieee80211_hw *hw,
struct netdev_hw_addr *ha;
mfilt[0] = 0;
- mfilt[1] = 1;
+ mfilt[1] = 0;
netdev_hw_addr_list_for_each(ha, mc_list) {
/* calculate XOR of eight 6-bit values */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index d1acfe98918..1576d58291d 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -610,7 +610,15 @@ static void ar5008_hw_override_ini(struct ath_hw *ah,
REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
if (AR_SREV_9280_20_OR_LATER(ah)) {
- val = REG_READ(ah, AR_PCU_MISC_MODE2);
+ /*
+ * For AR9280 and above, there is a new feature that allows
+ * Multicast search based on both MAC Address and Key ID.
+ * By default, this feature is enabled. But since the driver
+ * is not using this feature, we switch it off; otherwise
+ * multicast search based on MAC addr only will fail.
+ */
+ val = REG_READ(ah, AR_PCU_MISC_MODE2) &
+ (~AR_ADHOC_MCAST_KEYID_ENABLE);
if (!AR_SREV_9271(ah))
val &= ~AR_PCU_MISC_MODE2_HWWAR1;
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 9e582e14da7..5205a3625e8 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -1082,7 +1082,7 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev)
struct device *dev = &hif_dev->udev->dev;
struct device *parent = dev->parent;
- complete(&hif_dev->fw_done);
+ complete_all(&hif_dev->fw_done);
if (parent)
device_lock(parent);
@@ -1131,7 +1131,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
release_firmware(fw);
hif_dev->flags |= HIF_USB_READY;
- complete(&hif_dev->fw_done);
+ complete_all(&hif_dev->fw_done);
return;
@@ -1295,7 +1295,9 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
usb_set_intfdata(interface, NULL);
- if (!unplugged && (hif_dev->flags & HIF_USB_START))
+ /* If firmware was loaded we should drop it
+ * go back to first stage bootloader. */
+ if (!unplugged && (hif_dev->flags & HIF_USB_READY))
ath9k_hif_usb_reboot(udev);
kfree(hif_dev);
@@ -1316,7 +1318,10 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface,
if (!(hif_dev->flags & HIF_USB_START))
ath9k_htc_suspend(hif_dev->htc_handle);
- ath9k_hif_usb_dealloc_urbs(hif_dev);
+ wait_for_completion(&hif_dev->fw_done);
+
+ if (hif_dev->flags & HIF_USB_READY)
+ ath9k_hif_usb_dealloc_urbs(hif_dev);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 71a183ffc77..c3676bf1d6c 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -861,6 +861,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
if (error != 0)
goto err_rx;
+ ath9k_hw_disable(priv->ah);
#ifdef CONFIG_MAC80211_LEDS
/* must be initialized before ieee80211_register_hw */
priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index e602c951970..c028df76b56 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -448,6 +448,7 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
struct ieee80211_conf *cur_conf = &priv->hw->conf;
bool txok;
int slot;
+ int hdrlen, padsize;
slot = strip_drv_header(priv, skb);
if (slot < 0) {
@@ -504,6 +505,15 @@ send_mac80211:
ath9k_htc_tx_clear_slot(priv, slot);
+ /* Remove padding before handing frame back to mac80211 */
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+
+ padsize = hdrlen & 3;
+ if (padsize && skb->len > hdrlen + padsize) {
+ memmove(skb->data + padsize, skb->data, hdrlen);
+ skb_pull(skb, padsize);
+ }
+
/* Send status to mac80211 */
ieee80211_tx_status(priv->hw, skb);
}
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 16f8b201642..026a2a067b4 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -802,7 +802,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_RC_TABLE;
+ IEEE80211_HW_SUPPORTS_RC_TABLE |
+ IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1737a3e3368..cb5a65553ac 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -173,8 +173,7 @@ static void ath_restart_work(struct ath_softc *sc)
{
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
- if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) ||
- AR_SREV_9550(sc->sc_ah))
+ if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah))
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index c59ae43b9b3..92799273262 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -146,6 +146,28 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
ARRAY_SIZE(bf->rates));
}
+static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+ struct sk_buff *skb)
+{
+ int q;
+
+ q = skb_get_queue_mapping(skb);
+ if (txq == sc->tx.uapsdq)
+ txq = sc->tx.txq_map[q];
+
+ if (txq != sc->tx.txq_map[q])
+ return;
+
+ if (WARN_ON(--txq->pending_frames < 0))
+ txq->pending_frames = 0;
+
+ if (txq->stopped &&
+ txq->pending_frames < sc->tx.txq_max_pending[q]) {
+ ieee80211_wake_queue(sc->hw, q);
+ txq->stopped = false;
+ }
+}
+
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = tid->ac->txq;
@@ -167,6 +189,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
if (!bf) {
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
if (!bf) {
+ ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
continue;
}
@@ -811,6 +834,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
if (!bf) {
__skb_unlink(skb, &tid->buf_q);
+ ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
continue;
}
@@ -1824,6 +1848,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq,
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
if (!bf) {
+ ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
return;
}
@@ -2090,6 +2115,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
if (!bf) {
+ ath_txq_skb_done(sc, txq, skb);
if (txctl->paprd)
dev_kfree_skb_any(skb);
else
@@ -2189,7 +2215,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
- int q, padpos, padsize;
+ int padpos, padsize;
unsigned long flags;
ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
@@ -2225,21 +2251,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
__skb_queue_tail(&txq->complete_q, skb);
-
- q = skb_get_queue_mapping(skb);
- if (txq == sc->tx.uapsdq)
- txq = sc->tx.txq_map[q];
-
- if (txq == sc->tx.txq_map[q]) {
- if (WARN_ON(--txq->pending_frames < 0))
- txq->pending_frames = 0;
-
- if (txq->stopped &&
- txq->pending_frames < sc->tx.txq_max_pending[q]) {
- ieee80211_wake_queue(sc->hw, q);
- txq->stopped = false;
- }
- }
+ ath_txq_skb_done(sc, txq, skb);
}
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 4a33c6e39ca..349fa22a921 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1860,7 +1860,8 @@ void *carl9170_alloc(size_t priv_size)
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
IEEE80211_HW_SUPPORTS_RC_TABLE |
- IEEE80211_HW_SIGNAL_DBM;
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
if (!modparam_noht) {
/*
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index e8308ec3097..ab636767fbd 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -145,7 +145,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
le16_to_cpu(hdr.type), hdr.flags);
if (len <= MAX_MBOXITEM_SIZE) {
int n = 0;
- unsigned char printbuf[16 * 3 + 2];
+ char printbuf[16 * 3 + 2];
unsigned char databuf[MAX_MBOXITEM_SIZE];
void __iomem *src = wmi_buffer(wil, d.addr) +
sizeof(struct wil6210_mbox_hdr);
@@ -416,7 +416,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
seq_printf(s, " SKB = %p\n", skb);
if (skb) {
- unsigned char printbuf[16 * 3 + 2];
+ char printbuf[16 * 3 + 2];
int i = 0;
int len = le16_to_cpu(d->dma.length);
void *p = skb->data;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index 8e8975562ec..80099016d21 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -242,7 +242,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
{
unsigned long flags;
- if (!ifp)
+ if (!ifp || !ifp->ndev)
return;
brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index f0d9f7f6c83..29b1f24c2d0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -1744,13 +1744,14 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
ulong flags;
int fifo = BRCMF_FWS_FIFO_BCMC;
bool multicast = is_multicast_ether_addr(eh->h_dest);
+ bool pae = eh->h_proto == htons(ETH_P_PAE);
/* determine the priority */
if (!skb->priority)
skb->priority = cfg80211_classify8021d(skb);
drvr->tx_multicast += !!multicast;
- if (ntohs(eh->h_proto) == ETH_P_PAE)
+ if (pae)
atomic_inc(&ifp->pend_8021x_cnt);
if (!brcmf_fws_fc_active(fws)) {
@@ -1781,6 +1782,11 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
brcmf_fws_schedule_deq(fws);
} else {
brcmf_err("drop skb: no hanger slot\n");
+ if (pae) {
+ atomic_dec(&ifp->pend_8021x_cnt);
+ if (waitqueue_active(&ifp->pend_8021x_wait))
+ wake_up(&ifp->pend_8021x_wait);
+ }
brcmu_pkt_buf_free_skb(skb);
}
brcmf_fws_unlock(drvr, flags);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 277b37ae712..7fa71f73cfe 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -1093,8 +1093,11 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
err = brcmf_fil_cmd_data_set(vif->ifp,
BRCMF_C_DISASSOC, NULL, 0);
- if (err)
+ if (err) {
brcmf_err("WLC_DISASSOC failed (%d)\n", err);
+ cfg80211_disconnected(vif->wdev.netdev, 0,
+ NULL, 0, GFP_KERNEL);
+ }
clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
}
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c
index 7365674366f..010b252be58 100644
--- a/drivers/net/wireless/cw1200/sta.c
+++ b/drivers/net/wireless/cw1200/sta.c
@@ -1406,11 +1406,8 @@ static void cw1200_do_unjoin(struct cw1200_common *priv)
if (!priv->join_status)
goto done;
- if (priv->join_status > CW1200_JOIN_STATUS_IBSS) {
- wiphy_err(priv->hw->wiphy, "Unexpected: join status: %d\n",
- priv->join_status);
- BUG_ON(1);
- }
+ if (priv->join_status == CW1200_JOIN_STATUS_AP)
+ goto done;
cancel_work_sync(&priv->update_filtering_work);
cancel_work_sync(&priv->set_beacon_wakeup_period_work);
diff --git a/drivers/net/wireless/cw1200/txrx.c b/drivers/net/wireless/cw1200/txrx.c
index 5862c373d71..e824d4d4a18 100644
--- a/drivers/net/wireless/cw1200/txrx.c
+++ b/drivers/net/wireless/cw1200/txrx.c
@@ -1165,7 +1165,7 @@ void cw1200_rx_cb(struct cw1200_common *priv,
if (cw1200_handle_action_rx(priv, skb))
return;
} else if (ieee80211_is_beacon(frame->frame_control) &&
- !arg->status &&
+ !arg->status && priv->vif &&
!memcmp(ieee80211_get_SA(frame), priv->vif->bss_conf.bssid,
ETH_ALEN)) {
const u8 *tim_ie;
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index ac074731335..e5090309824 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -523,9 +523,9 @@ static int prism2_ioctl_giwaplist(struct net_device *dev,
data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1);
- memcpy(extra, &addr, sizeof(struct sockaddr) * data->length);
+ memcpy(extra, addr, sizeof(struct sockaddr) * data->length);
data->flags = 1; /* has quality information */
- memcpy(extra + sizeof(struct sockaddr) * data->length, &qual,
+ memcpy(extra + sizeof(struct sockaddr) * data->length, qual,
sizeof(struct iw_quality) * data->length);
kfree(addr);
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index b9b2bb51e60..7acf5ee2358 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -4460,13 +4460,13 @@ il4965_irq_tasklet(struct il_priv *il)
* is killed. Hence update the killswitch state here. The
* rfkill handler will care about restarting if needed.
*/
- if (!test_bit(S_ALIVE, &il->status)) {
- if (hw_rf_kill)
- set_bit(S_RFKILL, &il->status);
- else
- clear_bit(S_RFKILL, &il->status);
- wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rf_kill);
+ if (hw_rf_kill) {
+ set_bit(S_RFKILL, &il->status);
+ } else {
+ clear_bit(S_RFKILL, &il->status);
+ il_force_reset(il, true);
}
+ wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rf_kill);
handled |= CSR_INT_BIT_RF_KILL;
}
@@ -5334,6 +5334,9 @@ il4965_alive_start(struct il_priv *il)
il->active_rate = RATES_MASK;
+ il_power_update_mode(il, true);
+ D_INFO("Updated power mode\n");
+
if (il_is_associated(il)) {
struct il_rxon_cmd *active_rxon =
(struct il_rxon_cmd *)&il->active;
@@ -5364,9 +5367,6 @@ il4965_alive_start(struct il_priv *il)
D_INFO("ALIVE processing complete.\n");
wake_up(&il->wait_command_queue);
- il_power_update_mode(il, true);
- D_INFO("Updated power mode\n");
-
return;
restart:
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c
index 3195aad440d..b03e22ef546 100644
--- a/drivers/net/wireless/iwlegacy/common.c
+++ b/drivers/net/wireless/iwlegacy/common.c
@@ -4660,6 +4660,7 @@ il_force_reset(struct il_priv *il, bool external)
return 0;
}
+EXPORT_SYMBOL(il_force_reset);
int
il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 822f1a00efb..319387263e1 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -1068,7 +1068,10 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+ if (!test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+ return;
+
+ if (ctx->vif)
ieee80211_chswitch_done(ctx->vif, is_success);
}
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index 3952ddf2ddb..1531a4fc096 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -758,7 +758,7 @@ int iwl_alive_start(struct iwl_priv *priv)
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
if (ret)
return ret;
- } else {
+ } else if (priv->lib->bt_params) {
/*
* default is 2-wire BT coexexistence support
*/
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 7e5e5c2f9f8..83da884cf30 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -134,7 +134,7 @@ struct wowlan_key_data {
struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
struct iwl_wowlan_tkip_params_cmd *tkip;
bool error, use_rsc_tsc, use_tkip;
- int gtk_key_idx;
+ int wep_key_idx;
};
static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
@@ -188,8 +188,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
wkc.wep_key.key_offset = 0;
} else {
/* others start at 1 */
- data->gtk_key_idx++;
- wkc.wep_key.key_offset = data->gtk_key_idx;
+ data->wep_key_idx++;
+ wkc.wep_key.key_offset = data->wep_key_idx;
}
ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC,
@@ -316,8 +316,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
mvm->ptk_ivlen = key->iv_len;
mvm->ptk_icvlen = key->icv_len;
} else {
- data->gtk_key_idx++;
- key->hw_key_idx = data->gtk_key_idx;
+ /*
+ * firmware only supports TSC/RSC for a single key,
+ * so if there are multiple keep overwriting them
+ * with new ones -- this relies on mac80211 doing
+ * list_add_tail().
+ */
+ key->hw_key_idx = 1;
mvm->gtk_ivlen = key->iv_len;
mvm->gtk_icvlen = key->icv_len;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index e56ed2a8488..c24a744910a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -988,7 +988,11 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
char buf[100];
- if (!dbgfs_dir)
+ /*
+ * Check if debugfs directory already exist before creating it.
+ * This may happen when, for example, resetting hw or suspend-resume
+ */
+ if (!dbgfs_dir || mvmvif->dbgfs_dir)
return;
mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index b60d1415172..365095a0c3b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -69,7 +69,6 @@
/* Scan Commands, Responses, Notifications */
/* Masks for iwl_scan_channel.type flags */
-#define SCAN_CHANNEL_TYPE_PASSIVE 0
#define SCAN_CHANNEL_TYPE_ACTIVE BIT(0)
#define SCAN_CHANNEL_NARROW_BAND BIT(22)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index e08683b2053..f19baf0dea6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -257,7 +257,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if (ret)
return ret;
- return ieee80211_register_hw(mvm->hw);
+ ret = ieee80211_register_hw(mvm->hw);
+ if (ret)
+ iwl_mvm_leds_exit(mvm);
+
+ return ret;
}
static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
@@ -385,6 +389,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
ieee80211_wake_queues(mvm->hw);
mvm->vif_count = 0;
+ mvm->rx_ba_sessions = 0;
}
static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
@@ -507,6 +512,27 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
goto out_unlock;
/*
+ * TODO: remove this temporary code.
+ * Currently MVM FW supports power management only on single MAC.
+ * If new interface added, disable PM on existing interface.
+ * P2P device is a special case, since it is handled by FW similary to
+ * scan. If P2P deviced is added, PM remains enabled on existing
+ * interface.
+ * Note: the method below does not count the new interface being added
+ * at this moment.
+ */
+ if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
+ mvm->vif_count++;
+ if (mvm->vif_count > 1) {
+ IWL_DEBUG_MAC80211(mvm,
+ "Disable power on existing interfaces\n");
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_pm_disable_iterator, mvm);
+ }
+
+ /*
* The AP binding flow can be done only after the beacon
* template is configured (which happens only in the mac80211
* start_ap() flow), and adding the broadcast station can happen
@@ -529,27 +555,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
goto out_unlock;
}
- /*
- * TODO: remove this temporary code.
- * Currently MVM FW supports power management only on single MAC.
- * If new interface added, disable PM on existing interface.
- * P2P device is a special case, since it is handled by FW similary to
- * scan. If P2P deviced is added, PM remains enabled on existing
- * interface.
- * Note: the method below does not count the new interface being added
- * at this moment.
- */
- if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
- mvm->vif_count++;
- if (mvm->vif_count > 1) {
- IWL_DEBUG_MAC80211(mvm,
- "Disable power on existing interfaces\n");
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_pm_disable_iterator, mvm);
- }
-
ret = iwl_mvm_mac_ctxt_add(mvm, vif);
if (ret)
goto out_release;
@@ -1006,6 +1011,21 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
if (old_state == IEEE80211_STA_NOTEXIST &&
new_state == IEEE80211_STA_NONE) {
+ /*
+ * Firmware bug - it'll crash if the beacon interval is less
+ * than 16. We can't avoid connecting at all, so refuse the
+ * station state change, this will cause mac80211 to abandon
+ * attempts to connect to this AP, and eventually wpa_s will
+ * blacklist the AP...
+ */
+ if (vif->type == NL80211_IFTYPE_STATION &&
+ vif->bss_conf.beacon_int < 16) {
+ IWL_ERR(mvm,
+ "AP %pM beacon interval is %d, refusing due to firmware bug!\n",
+ sta->addr, vif->bss_conf.beacon_int);
+ ret = -EINVAL;
+ goto out_unlock;
+ }
ret = iwl_mvm_add_sta(mvm, vif, sta);
} else if (old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_AUTH) {
@@ -1038,6 +1058,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
} else {
ret = -EIO;
}
+ out_unlock:
mutex_unlock(&mvm->mutex);
return ret;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index d40d7db185d..420e82d379d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -419,6 +419,7 @@ struct iwl_mvm {
struct work_struct sta_drained_wk;
unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
atomic_t pending_frames[IWL_MVM_STATION_COUNT];
+ u8 rx_ba_sessions;
/* configured by mac80211 */
u32 rts_threshold;
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 2157b0f8ced..acdff6b67e0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -137,8 +137,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
{
int fw_idx, req_idx;
- fw_idx = 0;
- for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) {
+ for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx > 0;
+ req_idx--, fw_idx++) {
cmd->direct_scan[fw_idx].id = WLAN_EID_SSID;
cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len;
memcpy(cmd->direct_scan[fw_idx].ssid,
@@ -153,7 +153,9 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
* just to notify that this scan is active and not passive.
* In order to notify the FW of the number of SSIDs we wish to scan (including
* the zero-length one), we need to set the corresponding bits in chan->type,
- * one for each SSID, and set the active bit (first).
+ * one for each SSID, and set the active bit (first). The first SSID is already
+ * included in the probe template, so we need to set only req->n_ssids - 1 bits
+ * in addition to the first bit.
*/
static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
{
@@ -176,19 +178,12 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
(cmd->data + le16_to_cpu(cmd->tx_cmd.len));
int i;
- __le32 chan_type_value;
-
- if (req->n_ssids > 0)
- chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1);
- else
- chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE;
for (i = 0; i < cmd->channel_count; i++) {
chan->channel = cpu_to_le16(req->channels[i]->hw_value);
+ chan->type = cpu_to_le32(BIT(req->n_ssids) - 1);
if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
- chan->type = SCAN_CHANNEL_TYPE_PASSIVE;
- else
- chan->type = chan_type_value;
+ chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
chan->active_dwell = cpu_to_le16(active_dwell);
chan->passive_dwell = cpu_to_le16(passive_dwell);
chan->iteration_count = cpu_to_le16(1);
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 62fe5209093..563f559b902 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -608,6 +608,8 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
return ret;
}
+#define IWL_MAX_RX_BA_SESSIONS 16
+
int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int tid, u16 ssn, bool start)
{
@@ -618,11 +620,20 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lockdep_assert_held(&mvm->mutex);
+ if (start && mvm->rx_ba_sessions >= IWL_MAX_RX_BA_SESSIONS) {
+ IWL_WARN(mvm, "Not enough RX BA SESSIONS\n");
+ return -ENOSPC;
+ }
+
cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
cmd.sta_id = mvm_sta->sta_id;
cmd.add_modify = STA_MODE_MODIFY;
- cmd.add_immediate_ba_tid = (u8) tid;
- cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+ if (start) {
+ cmd.add_immediate_ba_tid = (u8) tid;
+ cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+ } else {
+ cmd.remove_immediate_ba_tid = (u8) tid;
+ }
cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID :
STA_MODIFY_REMOVE_BA_TID;
@@ -648,6 +659,14 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
break;
}
+ if (!ret) {
+ if (start)
+ mvm->rx_ba_sessions++;
+ else if (mvm->rx_ba_sessions > 0)
+ /* check that restart flow didn't zero the counter */
+ mvm->rx_ba_sessions--;
+ }
+
return ret;
}
@@ -896,6 +915,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
u16 txq_id;
+ enum iwl_mvm_agg_state old_state;
/*
* First set the agg state to OFF to avoid calling
@@ -905,13 +925,17 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
txq_id = tid_data->txq_id;
IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n",
mvmsta->sta_id, tid, txq_id, tid_data->state);
+ old_state = tid_data->state;
tid_data->state = IWL_AGG_OFF;
spin_unlock_bh(&mvmsta->lock);
- if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
- IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+ if (old_state >= IWL_AGG_ON) {
+ if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
+ IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+
+ iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+ }
- iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
mvm->queue_to_mac80211[tid_data->txq_id] =
IWL_INVALID_MAC80211_QUEUE;
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index ad9bbca9921..7fd6fbfbc1b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -138,6 +138,20 @@ static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
schedule_work(&mvm->roc_done_wk);
}
+static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ const char *errmsg)
+{
+ if (vif->type != NL80211_IFTYPE_STATION)
+ return false;
+ if (vif->bss_conf.assoc && vif->bss_conf.dtim_period)
+ return false;
+ if (errmsg)
+ IWL_ERR(mvm, "%s\n", errmsg);
+ ieee80211_connection_loss(vif);
+ return true;
+}
+
/*
* Handles a FW notification for an event that is known to the driver.
*
@@ -163,8 +177,13 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
* P2P Device discoveribility, while there are other higher priority
* events in the system).
*/
- WARN_ONCE(!le32_to_cpu(notif->status),
- "Failed to schedule time event\n");
+ if (WARN_ONCE(!le32_to_cpu(notif->status),
+ "Failed to schedule time event\n")) {
+ if (iwl_mvm_te_check_disconnect(mvm, te_data->vif, NULL)) {
+ iwl_mvm_te_clear_data(mvm, te_data);
+ return;
+ }
+ }
if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) {
IWL_DEBUG_TE(mvm,
@@ -180,14 +199,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
* By now, we should have finished association
* and know the dtim period.
*/
- if (te_data->vif->type == NL80211_IFTYPE_STATION &&
- (!te_data->vif->bss_conf.assoc ||
- !te_data->vif->bss_conf.dtim_period)) {
- IWL_ERR(mvm,
- "No assocation and the time event is over already...\n");
- ieee80211_connection_loss(te_data->vif);
- }
-
+ iwl_mvm_te_check_disconnect(mvm, te_data->vif,
+ "No assocation and the time event is over already...");
iwl_mvm_te_clear_data(mvm, te_data);
} else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) {
te_data->running = true;
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index 81f3ea5b09a..ff13458efc2 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -130,6 +130,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
{IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
{IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
+ {IWL_PCI_DEVICE(0x423C, 0x1326, iwl5150_abg_cfg)}, /* Half Mini Card */
{IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
{IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 826c15602c4..390e2f058af 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -670,6 +670,11 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
return err;
}
+ /* Reset the entire device */
+ iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ usleep_range(10, 15);
+
iwl_pcie_apm_init(trans);
/* From now on, the op_mode will be kept updated about RF kill state */
@@ -1497,16 +1502,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
spin_lock_init(&trans_pcie->reg_lock);
init_waitqueue_head(&trans_pcie->ucode_write_waitq);
- /* W/A - seems to solve weird behavior. We need to remove this if we
- * don't want to stay in L1 all the time. This wastes a lot of power */
- pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
- PCIE_LINK_STATE_CLKPM);
-
if (pci_enable_device(pdev)) {
err = -ENODEV;
goto out_no_pci;
}
+ /* W/A - seems to solve weird behavior. We need to remove this if we
+ * don't want to stay in L1 all the time. This wastes a lot of power */
+ pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+ PCIE_LINK_STATE_CLKPM);
+
pci_set_master(pdev);
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index ef5fa890a28..89459db4c53 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1716,9 +1716,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
int ret;
- if (priv->bss_mode != NL80211_IFTYPE_STATION) {
+ if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) {
wiphy_err(wiphy,
- "%s: reject infra assoc request in non-STA mode\n",
+ "%s: reject infra assoc request in non-STA role\n",
dev->name);
return -EINVAL;
}
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index 988552dece7..5178c4630d8 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -415,7 +415,8 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
u32 k = 0;
struct mwifiex_adapter *adapter = priv->adapter;
- if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+ if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+ priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
switch (adapter->config_bands) {
case BAND_B:
dev_dbg(adapter->dev, "info: infra band=%d "
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index caaf4bd56b3..2cf8b964e96 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -693,7 +693,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
if (!ret) {
dev_notice(adapter->dev,
"WLAN FW already running! Skip FW dnld\n");
- goto done;
+ return 0;
}
poll_num = MAX_FIRMWARE_POLL_TRIES;
@@ -719,14 +719,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
poll_fw:
/* Check if the firmware is downloaded successfully or not */
ret = adapter->if_ops.check_fw_status(adapter, poll_num);
- if (ret) {
+ if (ret)
dev_err(adapter->dev, "FW failed to be active in time\n");
- return -1;
- }
-done:
- /* re-enable host interrupt for mwifiex after fw dnld is successful */
- if (adapter->if_ops.enable_int)
- adapter->if_ops.enable_int(adapter);
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 1c8a771e8e8..12e778159ec 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -1291,8 +1291,10 @@ int mwifiex_associate(struct mwifiex_private *priv,
{
u8 current_bssid[ETH_ALEN];
- /* Return error if the adapter or table entry is not marked as infra */
- if ((priv->bss_mode != NL80211_IFTYPE_STATION) ||
+ /* Return error if the adapter is not STA role or table entry
+ * is not marked as infra.
+ */
+ if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) ||
(bss_desc->bss_mode != NL80211_IFTYPE_STATION))
return -1;
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index e15ab72fb03..1753431de36 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -427,6 +427,10 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
"Cal data request_firmware() failed\n");
}
+ /* enable host interrupt after fw dnld is successful */
+ if (adapter->if_ops.enable_int)
+ adapter->if_ops.enable_int(adapter);
+
adapter->init_wait_q_woken = false;
ret = mwifiex_init_fw(adapter);
if (ret == -1) {
@@ -478,6 +482,8 @@ err_add_intf:
mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
rtnl_unlock();
err_init_fw:
+ if (adapter->if_ops.disable_int)
+ adapter->if_ops.disable_int(adapter);
pr_debug("info: %s: unregister device\n", __func__);
adapter->if_ops.unregister_dev(adapter);
done:
@@ -855,7 +861,7 @@ mwifiex_add_card(void *card, struct semaphore *sem,
INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
/* Register the device. Fill up the private data structure with relevant
- information from the card and request for the required IRQ. */
+ information from the card. */
if (adapter->if_ops.register_dev(adapter)) {
pr_err("%s: failed to register mwifiex device\n", __func__);
goto err_registerdev;
@@ -919,6 +925,11 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
if (!adapter)
goto exit_remove;
+ /* We can no longer handle interrupts once we start doing the teardown
+ * below. */
+ if (adapter->if_ops.disable_int)
+ adapter->if_ops.disable_int(adapter);
+
adapter->surprise_removed = true;
/* Stop data */
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 3da73d36acd..253e0bd38e2 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -601,6 +601,7 @@ struct mwifiex_if_ops {
int (*register_dev) (struct mwifiex_adapter *);
void (*unregister_dev) (struct mwifiex_adapter *);
int (*enable_int) (struct mwifiex_adapter *);
+ void (*disable_int) (struct mwifiex_adapter *);
int (*process_int_status) (struct mwifiex_adapter *);
int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *,
struct mwifiex_tx_param *);
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 5ee5ed02ecc..09185c96324 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -51,6 +51,7 @@ static struct mwifiex_if_ops sdio_ops;
static struct semaphore add_remove_card_sem;
static int mwifiex_sdio_resume(struct device *dev);
+static void mwifiex_sdio_interrupt(struct sdio_func *func);
/*
* SDIO probe.
@@ -296,6 +297,15 @@ static struct sdio_driver mwifiex_sdio = {
}
};
+/* Write data into SDIO card register. Caller claims SDIO device. */
+static int
+mwifiex_write_reg_locked(struct sdio_func *func, u32 reg, u8 data)
+{
+ int ret = -1;
+ sdio_writeb(func, data, reg, &ret);
+ return ret;
+}
+
/*
* This function writes data into SDIO card register.
*/
@@ -303,10 +313,10 @@ static int
mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u8 data)
{
struct sdio_mmc_card *card = adapter->card;
- int ret = -1;
+ int ret;
sdio_claim_host(card->func);
- sdio_writeb(card->func, data, reg, &ret);
+ ret = mwifiex_write_reg_locked(card->func, reg, data);
sdio_release_host(card->func);
return ret;
@@ -685,23 +695,15 @@ mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
* The host interrupt mask is read, the disable bit is reset and
* written back to the card host interrupt mask register.
*/
-static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
+static void mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
{
- u8 host_int_mask, host_int_disable = HOST_INT_DISABLE;
-
- /* Read back the host_int_mask register */
- if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask))
- return -1;
-
- /* Update with the mask and write back to the register */
- host_int_mask &= ~host_int_disable;
-
- if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) {
- dev_err(adapter->dev, "disable host interrupt failed\n");
- return -1;
- }
+ struct sdio_mmc_card *card = adapter->card;
+ struct sdio_func *func = card->func;
- return 0;
+ sdio_claim_host(func);
+ mwifiex_write_reg_locked(func, HOST_INT_MASK_REG, 0);
+ sdio_release_irq(func);
+ sdio_release_host(func);
}
/*
@@ -713,14 +715,29 @@ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
{
struct sdio_mmc_card *card = adapter->card;
+ struct sdio_func *func = card->func;
+ int ret;
+
+ sdio_claim_host(func);
+
+ /* Request the SDIO IRQ */
+ ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
+ if (ret) {
+ dev_err(adapter->dev, "claim irq failed: ret=%d\n", ret);
+ goto out;
+ }
/* Simply write the mask to the register */
- if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG,
- card->reg->host_int_enable)) {
+ ret = mwifiex_write_reg_locked(func, HOST_INT_MASK_REG,
+ card->reg->host_int_enable);
+ if (ret) {
dev_err(adapter->dev, "enable host interrupt failed\n");
- return -1;
+ sdio_release_irq(func);
}
- return 0;
+
+out:
+ sdio_release_host(func);
+ return ret;
}
/*
@@ -997,9 +1014,6 @@ mwifiex_sdio_interrupt(struct sdio_func *func)
}
adapter = card->adapter;
- if (adapter->surprise_removed)
- return;
-
if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
adapter->ps_state = PS_STATE_AWAKE;
@@ -1625,8 +1639,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
/* Allocate buffer and copy payload */
blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
buf_block_len = (pkt_len + blk_size - 1) / blk_size;
- *(u16 *) &payload[0] = (u16) pkt_len;
- *(u16 *) &payload[2] = type;
+ *(__le16 *)&payload[0] = cpu_to_le16((u16)pkt_len);
+ *(__le16 *)&payload[2] = cpu_to_le16(type);
/*
* This is SDIO specific header
@@ -1728,9 +1742,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
struct sdio_mmc_card *card = adapter->card;
if (adapter->card) {
- /* Release the SDIO IRQ */
sdio_claim_host(card->func);
- sdio_release_irq(card->func);
sdio_disable_func(card->func);
sdio_release_host(card->func);
sdio_set_drvdata(card->func, NULL);
@@ -1744,7 +1756,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
*/
static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
{
- int ret = 0;
+ int ret;
struct sdio_mmc_card *card = adapter->card;
struct sdio_func *func = card->func;
@@ -1753,22 +1765,14 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
sdio_claim_host(func);
- /* Request the SDIO IRQ */
- ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
- if (ret) {
- pr_err("claim irq failed: ret=%d\n", ret);
- goto disable_func;
- }
-
/* Set block size */
ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE);
+ sdio_release_host(func);
if (ret) {
pr_err("cannot set SDIO block size\n");
- ret = -1;
- goto release_irq;
+ return ret;
}
- sdio_release_host(func);
sdio_set_drvdata(func, card);
adapter->dev = &func->dev;
@@ -1776,15 +1780,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
strcpy(adapter->fw_name, card->firmware);
return 0;
-
-release_irq:
- sdio_release_irq(func);
-disable_func:
- sdio_disable_func(func);
- sdio_release_host(func);
- adapter->card = NULL;
-
- return -1;
}
/*
@@ -1813,9 +1808,6 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
*/
mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg);
- /* Disable host interrupt mask register for SDIO */
- mwifiex_sdio_disable_host_int(adapter);
-
/* Get SDIO ioport */
mwifiex_init_sdio_ioport(adapter);
@@ -1957,6 +1949,7 @@ static struct mwifiex_if_ops sdio_ops = {
.register_dev = mwifiex_register_dev,
.unregister_dev = mwifiex_unregister_dev,
.enable_int = mwifiex_sdio_enable_host_int,
+ .disable_int = mwifiex_sdio_disable_host_int,
.process_int_status = mwifiex_process_int_status,
.host_to_card = mwifiex_sdio_host_to_card,
.wakeup = mwifiex_pm_wakeup_card,
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
index 6d51dfdd825..532ae0ac4df 100644
--- a/drivers/net/wireless/mwifiex/sdio.h
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -92,9 +92,6 @@
/* Host Control Registers : Download host interrupt mask */
#define DN_LD_HOST_INT_MASK (0x2U)
-/* Disable Host interrupt mask */
-#define HOST_INT_DISABLE 0xff
-
/* Host Control Registers : Host interrupt status */
#define HOST_INTSTATUS_REG 0x03
/* Host Control Registers : Upload host interrupt status */
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 206c3e03807..8af97abf710 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -257,10 +257,10 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
goto done;
}
- if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+ if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+ priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
u8 config_bands;
- /* Infra mode */
ret = mwifiex_deauthenticate(priv, NULL);
if (ret)
goto done;
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 9b915d3a44b..3e60a31582f 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -1,6 +1,6 @@
menuconfig RT2X00
tristate "Ralink driver support"
- depends on MAC80211
+ depends on MAC80211 && HAS_DMA
---help---
This will enable the support for the Ralink drivers,
developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 1f80ea5e29d..1b41c8eda12 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -6133,7 +6133,8 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+ IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
/*
* Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 6c0a91ff963..aa95c6cf354 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -936,13 +936,8 @@ void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index)
spin_unlock_irqrestore(&queue->index_lock, irqflags);
}
-void rt2x00queue_pause_queue(struct data_queue *queue)
+void rt2x00queue_pause_queue_nocheck(struct data_queue *queue)
{
- if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
- !test_bit(QUEUE_STARTED, &queue->flags) ||
- test_and_set_bit(QUEUE_PAUSED, &queue->flags))
- return;
-
switch (queue->qid) {
case QID_AC_VO:
case QID_AC_VI:
@@ -958,6 +953,15 @@ void rt2x00queue_pause_queue(struct data_queue *queue)
break;
}
}
+void rt2x00queue_pause_queue(struct data_queue *queue)
+{
+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+ !test_bit(QUEUE_STARTED, &queue->flags) ||
+ test_and_set_bit(QUEUE_PAUSED, &queue->flags))
+ return;
+
+ rt2x00queue_pause_queue_nocheck(queue);
+}
EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue);
void rt2x00queue_unpause_queue(struct data_queue *queue)
@@ -1019,7 +1023,7 @@ void rt2x00queue_stop_queue(struct data_queue *queue)
return;
}
- rt2x00queue_pause_queue(queue);
+ rt2x00queue_pause_queue_nocheck(queue);
queue->rt2x00dev->ops->lib->stop_queue(queue);
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index 7253de3d8c6..c2ffce7a907 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -1,27 +1,20 @@
-config RTLWIFI
- tristate "Realtek wireless card support"
- depends on MAC80211
- select FW_LOADER
- ---help---
- This is common code for RTL8192CE/RTL8192CU/RTL8192SE/RTL8723AE
- drivers. This module does nothing by itself - the various front-end
- drivers need to be enabled to support any desired devices.
-
- If you choose to build as a module, it'll be called rtlwifi.
-
-config RTLWIFI_DEBUG
- bool "Debugging output for rtlwifi driver family"
- depends on RTLWIFI
+menuconfig RTL_CARDS
+ tristate "Realtek rtlwifi family of devices"
+ depends on MAC80211 && (PCI || USB)
default y
---help---
- To use the module option that sets the dynamic-debugging level for,
- the front-end driver, this parameter must be "Y". For memory-limited
- systems, choose "N". If in doubt, choose "Y".
+ This option will enable support for the Realtek mac80211-based
+ wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de,
+ rtl8723eu, and rtl8188eu share some common code.
+
+if RTL_CARDS
config RTL8192CE
tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter"
- depends on RTLWIFI && PCI
+ depends on PCI
select RTL8192C_COMMON
+ select RTLWIFI
+ select RTLWIFI_PCI
---help---
This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe
wireless network adapters.
@@ -30,7 +23,9 @@ config RTL8192CE
config RTL8192SE
tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter"
- depends on RTLWIFI && PCI
+ depends on PCI
+ select RTLWIFI
+ select RTLWIFI_PCI
---help---
This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe
wireless network adapters.
@@ -39,7 +34,9 @@ config RTL8192SE
config RTL8192DE
tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter"
- depends on RTLWIFI && PCI
+ depends on PCI
+ select RTLWIFI
+ select RTLWIFI_PCI
---help---
This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe
wireless network adapters.
@@ -48,7 +45,9 @@ config RTL8192DE
config RTL8723AE
tristate "Realtek RTL8723AE PCIe Wireless Network Adapter"
- depends on RTLWIFI && PCI
+ depends on PCI
+ select RTLWIFI
+ select RTLWIFI_PCI
---help---
This is the driver for Realtek RTL8723AE 802.11n PCIe
wireless network adapters.
@@ -57,7 +56,9 @@ config RTL8723AE
config RTL8188EE
tristate "Realtek RTL8188EE Wireless Network Adapter"
- depends on RTLWIFI && PCI
+ depends on PCI
+ select RTLWIFI
+ select RTLWIFI_PCI
---help---
This is the driver for Realtek RTL8188EE 802.11n PCIe
wireless network adapters.
@@ -66,7 +67,9 @@ config RTL8188EE
config RTL8192CU
tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
- depends on RTLWIFI && USB
+ depends on USB
+ select RTLWIFI
+ select RTLWIFI_USB
select RTL8192C_COMMON
---help---
This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB
@@ -74,7 +77,28 @@ config RTL8192CU
If you choose to build it as a module, it will be called rtl8192cu
+config RTLWIFI
+ tristate
+ select FW_LOADER
+
+config RTLWIFI_PCI
+ tristate
+
+config RTLWIFI_USB
+ tristate
+
+config RTLWIFI_DEBUG
+ bool "Debugging output for rtlwifi driver family"
+ depends on RTLWIFI
+ default y
+ ---help---
+ To use the module option that sets the dynamic-debugging level for,
+ the front-end driver, this parameter must be "Y". For memory-limited
+ systems, choose "N". If in doubt, choose "Y".
+
config RTL8192C_COMMON
tristate
depends on RTL8192CE || RTL8192CU
- default m
+ default y
+
+endif
diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile
index ff02b874f8d..d56f023a4b9 100644
--- a/drivers/net/wireless/rtlwifi/Makefile
+++ b/drivers/net/wireless/rtlwifi/Makefile
@@ -12,13 +12,11 @@ rtlwifi-objs := \
rtl8192c_common-objs += \
-ifneq ($(CONFIG_PCI),)
-rtlwifi-objs += pci.o
-endif
+obj-$(CONFIG_RTLWIFI_PCI) += rtl_pci.o
+rtl_pci-objs := pci.o
-ifneq ($(CONFIG_USB),)
-rtlwifi-objs += usb.o
-endif
+obj-$(CONFIG_RTLWIFI_USB) += rtl_usb.o
+rtl_usb-objs := usb.o
obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c/
obj-$(CONFIG_RTL8192CE) += rtl8192ce/
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 9d558ac77b0..7651f5acc14 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -172,6 +172,7 @@ u8 rtl_tid_to_ac(u8 tid)
{
return tid_to_ac[tid];
}
+EXPORT_SYMBOL_GPL(rtl_tid_to_ac);
static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
struct ieee80211_sta_ht_cap *ht_cap)
@@ -406,6 +407,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
cancel_delayed_work(&rtlpriv->works.fwevt_wq);
}
+EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work);
void rtl_init_rfkill(struct ieee80211_hw *hw)
{
@@ -439,6 +441,7 @@ void rtl_deinit_rfkill(struct ieee80211_hw *hw)
{
wiphy_rfkill_stop_polling(hw->wiphy);
}
+EXPORT_SYMBOL_GPL(rtl_deinit_rfkill);
int rtl_init_core(struct ieee80211_hw *hw)
{
@@ -489,10 +492,12 @@ int rtl_init_core(struct ieee80211_hw *hw)
return 0;
}
+EXPORT_SYMBOL_GPL(rtl_init_core);
void rtl_deinit_core(struct ieee80211_hw *hw)
{
}
+EXPORT_SYMBOL_GPL(rtl_deinit_core);
void rtl_init_rx_config(struct ieee80211_hw *hw)
{
@@ -501,6 +506,7 @@ void rtl_init_rx_config(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
}
+EXPORT_SYMBOL_GPL(rtl_init_rx_config);
/*********************************************************
*
@@ -879,6 +885,7 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
return true;
}
+EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc);
void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info,
@@ -1052,6 +1059,7 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
return true;
}
+EXPORT_SYMBOL_GPL(rtl_action_proc);
/*should call before software enc*/
u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
@@ -1125,6 +1133,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
return false;
}
+EXPORT_SYMBOL_GPL(rtl_is_special_data);
/*********************************************************
*
@@ -1300,6 +1309,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
rtlpriv->link_info.bcn_rx_inperiod++;
}
+EXPORT_SYMBOL_GPL(rtl_beacon_statistic);
void rtl_watchdog_wq_callback(void *data)
{
@@ -1793,6 +1803,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
mac->vendor = vendor;
}
+EXPORT_SYMBOL_GPL(rtl_recognize_peer);
/*********************************************************
*
@@ -1849,6 +1860,7 @@ struct attribute_group rtl_attribute_group = {
.name = "rtlsysfs",
.attrs = rtl_sysfs_entries,
};
+EXPORT_SYMBOL_GPL(rtl_attribute_group);
MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
@@ -1856,7 +1868,8 @@ MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
-struct rtl_global_var global_var = {};
+struct rtl_global_var rtl_global_var = {};
+EXPORT_SYMBOL_GPL(rtl_global_var);
static int __init rtl_core_module_init(void)
{
@@ -1864,8 +1877,8 @@ static int __init rtl_core_module_init(void)
pr_err("Unable to register rtl_rc, use default RC !!\n");
/* init some global vars */
- INIT_LIST_HEAD(&global_var.glb_priv_list);
- spin_lock_init(&global_var.glb_list_lock);
+ INIT_LIST_HEAD(&rtl_global_var.glb_priv_list);
+ spin_lock_init(&rtl_global_var.glb_list_lock);
return 0;
}
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
index 8576bc34b03..0e5fe0902da 100644
--- a/drivers/net/wireless/rtlwifi/base.h
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -147,7 +147,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
u8 rtl_tid_to_ac(u8 tid);
extern struct attribute_group rtl_attribute_group;
void rtl_easy_concurrent_retrytimer_callback(unsigned long data);
-extern struct rtl_global_var global_var;
+extern struct rtl_global_var rtl_global_var;
int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
bool isht, u8 desc_rate, bool first_ampdu);
bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index ee84844be00..733b7ce7f0e 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -1330,3 +1330,4 @@ const struct ieee80211_ops rtl_ops = {
.rfkill_poll = rtl_op_rfkill_poll,
.flush = rtl_op_flush,
};
+EXPORT_SYMBOL_GPL(rtl_ops);
diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c
index 7d52d3d7769..76e2086e137 100644
--- a/drivers/net/wireless/rtlwifi/debug.c
+++ b/drivers/net/wireless/rtlwifi/debug.c
@@ -51,3 +51,4 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
/*Init Debug flag enable condition */
}
+EXPORT_SYMBOL_GPL(rtl_dbgp_flag_init);
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c
index 9e3894178e7..838a1ed3f19 100644
--- a/drivers/net/wireless/rtlwifi/efuse.c
+++ b/drivers/net/wireless/rtlwifi/efuse.c
@@ -229,6 +229,7 @@ void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
*pbuf = (u8) (value32 & 0xff);
}
+EXPORT_SYMBOL_GPL(read_efuse_byte);
void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
{
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index c97e9d32733..703f839af6c 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -35,6 +35,13 @@
#include "efuse.h"
#include <linux/export.h>
#include <linux/kmemleak.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCI basic driver for rtlwifi");
static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
PCI_VENDOR_ID_INTEL,
@@ -1008,19 +1015,6 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
return;
}
-static void rtl_lps_change_work_callback(struct work_struct *work)
-{
- struct rtl_works *rtlworks =
- container_of(work, struct rtl_works, lps_change_work);
- struct ieee80211_hw *hw = rtlworks->hw;
- struct rtl_priv *rtlpriv = rtl_priv(hw);
-
- if (rtlpriv->enter_ps)
- rtl_lps_enter(hw);
- else
- rtl_lps_leave(hw);
-}
-
static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
{
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -1899,7 +1893,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
rtlpriv->rtlhal.interface = INTF_PCI;
rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
rtlpriv->intf_ops = &rtl_pci_ops;
- rtlpriv->glb_var = &global_var;
+ rtlpriv->glb_var = &rtl_global_var;
/*
*init dbgp flags before all
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index 884bceae38a..298b615964e 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -269,6 +269,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw)
spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags);
}
+EXPORT_SYMBOL_GPL(rtl_ips_nic_on);
/*for FW LPS*/
@@ -518,6 +519,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
"u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed);
}
}
+EXPORT_SYMBOL_GPL(rtl_swlps_beacon);
void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
{
@@ -611,6 +613,19 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40));
}
+void rtl_lps_change_work_callback(struct work_struct *work)
+{
+ struct rtl_works *rtlworks =
+ container_of(work, struct rtl_works, lps_change_work);
+ struct ieee80211_hw *hw = rtlworks->hw;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->enter_ps)
+ rtl_lps_enter(hw);
+ else
+ rtl_lps_leave(hw);
+}
+EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback);
void rtl_swlps_wq_callback(void *data)
{
@@ -922,3 +937,4 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
else
rtl_p2p_noa_ie(hw, data, len - FCS_LEN);
}
+EXPORT_SYMBOL_GPL(rtl_p2p_info);
diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h
index 4d682b753f5..88bd76ea88f 100644
--- a/drivers/net/wireless/rtlwifi/ps.h
+++ b/drivers/net/wireless/rtlwifi/ps.h
@@ -49,5 +49,6 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw);
void rtl_swlps_rf_sleep(struct ieee80211_hw *hw);
void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len);
+void rtl_lps_change_work_callback(struct work_struct *work);
#endif
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index a3532e07787..e56778cac9b 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -32,6 +32,13 @@
#include "ps.h"
#include "rtl8192c/fw_common.h"
#include <linux/export.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("USB basic driver for rtlwifi");
#define REALTEK_USB_VENQT_READ 0xC0
#define REALTEK_USB_VENQT_WRITE 0x40
@@ -1070,6 +1077,8 @@ int rtl_usb_probe(struct usb_interface *intf,
spin_lock_init(&rtlpriv->locks.usb_lock);
INIT_WORK(&rtlpriv->works.fill_h2c_cmd,
rtl_fill_h2c_cmd_work_callback);
+ INIT_WORK(&rtlpriv->works.lps_change_work,
+ rtl_lps_change_work_callback);
rtlpriv->usb_data_index = 0;
init_completion(&rtlpriv->firmware_loading_complete);
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 4941f201d6c..b8ba1f925e7 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -98,10 +98,12 @@ static int zd1201_fw_upload(struct usb_device *dev, int apfw)
goto exit;
err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4,
- USB_DIR_IN | 0x40, 0,0, &ret, sizeof(ret), ZD1201_FW_TIMEOUT);
+ USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT);
if (err < 0)
goto exit;
+ memcpy(&ret, buf, sizeof(ret));
+
if (ret & 0x80) {
err = -EIO;
goto exit;
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 5c5427918eb..e486e416d5a 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -18,6 +18,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/ctype.h>
+#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/spinlock.h>
@@ -32,6 +33,7 @@ struct device_node *of_allnodes;
EXPORT_SYMBOL(of_allnodes);
struct device_node *of_chosen;
struct device_node *of_aliases;
+static struct device_node *of_stdout;
DEFINE_MUTEX(of_aliases_mutex);
@@ -230,6 +232,100 @@ const void *of_get_property(const struct device_node *np, const char *name,
}
EXPORT_SYMBOL(of_get_property);
+/*
+ * arch_match_cpu_phys_id - Match the given logical CPU and physical id
+ *
+ * @cpu: logical cpu index of a core/thread
+ * @phys_id: physical identifier of a core/thread
+ *
+ * CPU logical to physical index mapping is architecture specific.
+ * However this __weak function provides a default match of physical
+ * id to logical cpu index. phys_id provided here is usually values read
+ * from the device tree which must match the hardware internal registers.
+ *
+ * Returns true if the physical identifier and the logical cpu index
+ * correspond to the same core/thread, false otherwise.
+ */
+bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id)
+{
+ return (u32)phys_id == cpu;
+}
+
+/**
+ * Checks if the given "prop_name" property holds the physical id of the
+ * core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not
+ * NULL, local thread number within the core is returned in it.
+ */
+static bool __of_find_n_match_cpu_property(struct device_node *cpun,
+ const char *prop_name, int cpu, unsigned int *thread)
+{
+ const __be32 *cell;
+ int ac, prop_len, tid;
+ u64 hwid;
+
+ ac = of_n_addr_cells(cpun);
+ cell = of_get_property(cpun, prop_name, &prop_len);
+ if (!cell)
+ return false;
+ prop_len /= sizeof(*cell);
+ for (tid = 0; tid < prop_len; tid++) {
+ hwid = of_read_number(cell, ac);
+ if (arch_match_cpu_phys_id(cpu, hwid)) {
+ if (thread)
+ *thread = tid;
+ return true;
+ }
+ cell += ac;
+ }
+ return false;
+}
+
+/**
+ * of_get_cpu_node - Get device node associated with the given logical CPU
+ *
+ * @cpu: CPU number(logical index) for which device node is required
+ * @thread: if not NULL, local thread number within the physical core is
+ * returned
+ *
+ * The main purpose of this function is to retrieve the device node for the
+ * given logical CPU index. It should be used to initialize the of_node in
+ * cpu device. Once of_node in cpu device is populated, all the further
+ * references can use that instead.
+ *
+ * CPU logical to physical index mapping is architecture specific and is built
+ * before booting secondary cores. This function uses arch_match_cpu_phys_id
+ * which can be overridden by architecture specific implementation.
+ *
+ * Returns a node pointer for the logical cpu if found, else NULL.
+ */
+struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
+{
+ struct device_node *cpun, *cpus;
+
+ cpus = of_find_node_by_path("/cpus");
+ if (!cpus) {
+ pr_warn("Missing cpus node, bailing out\n");
+ return NULL;
+ }
+
+ for_each_child_of_node(cpus, cpun) {
+ if (of_node_cmp(cpun->type, "cpu"))
+ continue;
+ /* Check for non-standard "ibm,ppc-interrupt-server#s" property
+ * for thread ids on PowerPC. If it doesn't exist fallback to
+ * standard "reg" property.
+ */
+ if (IS_ENABLED(CONFIG_PPC) &&
+ __of_find_n_match_cpu_property(cpun,
+ "ibm,ppc-interrupt-server#s", cpu, thread))
+ return cpun;
+ if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread))
+ return cpun;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_get_cpu_node);
+
/** Checks if the given "compat" string matches one of the strings in
* the device's "compatible" property
*/
@@ -1595,6 +1691,15 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
of_chosen = of_find_node_by_path("/chosen");
if (of_chosen == NULL)
of_chosen = of_find_node_by_path("/chosen@0");
+
+ if (of_chosen) {
+ const char *name;
+
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+ if (name)
+ of_stdout = of_find_node_by_path(name);
+ }
+
of_aliases = of_find_node_by_path("/aliases");
if (!of_aliases)
return;
@@ -1703,3 +1808,19 @@ const char *of_prop_next_string(struct property *prop, const char *cur)
return curv;
}
EXPORT_SYMBOL_GPL(of_prop_next_string);
+
+/**
+ * of_device_is_stdout_path - check if a device node matches the
+ * linux,stdout-path property
+ *
+ * Check if this device node matches the linux,stdout-path property
+ * in the chosen node. return true if yes, false otherwise.
+ */
+int of_device_is_stdout_path(struct device_node *dn)
+{
+ if (!of_stdout)
+ return false;
+
+ return of_stdout == dn;
+}
+EXPORT_SYMBOL_GPL(of_device_is_stdout_path);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 6bb7cf2de55..b10ba00cc3e 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -392,6 +392,8 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
mem = (unsigned long)
dt_alloc(size + 4, __alignof__(struct device_node));
+ memset((void *)mem, 0, size);
+
((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
pr_debug(" unflattening %lx...\n", mem);
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index a3c1c5aae6a..1264923ade0 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -345,6 +345,7 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
if (r && irq) {
const char *name = NULL;
+ memset(r, 0, sizeof(*r));
/*
* Get optional "interrupts-names" property to add a name
* to the resource.
@@ -482,8 +483,9 @@ void __init of_irq_init(const struct of_device_id *matches)
}
/* Get the next pending parent that might have children */
- desc = list_first_entry(&intc_parent_list, typeof(*desc), list);
- if (list_empty(&intc_parent_list) || !desc) {
+ desc = list_first_entry_or_null(&intc_parent_list,
+ typeof(*desc), list);
+ if (!desc) {
pr_err("of_irq_init: children remain, but no parents\n");
break;
}
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index e79e006eb9a..9ee04b4b68b 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -811,18 +811,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
return pcidev->irq;
}
-static struct iosapic_info *first_isi = NULL;
+static struct iosapic_info *iosapic_list;
#ifdef CONFIG_64BIT
-int iosapic_serial_irq(int num)
+int iosapic_serial_irq(struct parisc_device *dev)
{
- struct iosapic_info *isi = first_isi;
- struct irt_entry *irte = NULL; /* only used if PAT PDC */
+ struct iosapic_info *isi;
+ struct irt_entry *irte;
struct vector_info *vi;
- int isi_line; /* line used by device */
+ int cnt;
+ int intin;
+
+ intin = (dev->mod_info >> 24) & 15;
/* lookup IRT entry for isi/slot/pin set */
- irte = &irt_cell[num];
+ for (cnt = 0; cnt < irt_num_entry; cnt++) {
+ irte = &irt_cell[cnt];
+ if (COMPARE_IRTE_ADDR(irte, dev->mod0) &&
+ irte->dest_iosapic_intin == intin)
+ break;
+ }
+ if (cnt >= irt_num_entry)
+ return 0; /* no irq found, force polling */
DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n",
irte,
@@ -834,11 +844,17 @@ int iosapic_serial_irq(int num)
irte->src_seg_id,
irte->dest_iosapic_intin,
(u32) irte->dest_iosapic_addr);
- isi_line = irte->dest_iosapic_intin;
+
+ /* search for iosapic */
+ for (isi = iosapic_list; isi; isi = isi->isi_next)
+ if (isi->isi_hpa == dev->mod0)
+ break;
+ if (!isi)
+ return 0; /* no iosapic found, force polling */
/* get vector info for this input line */
- vi = isi->isi_vector + isi_line;
- DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", isi_line, vi);
+ vi = isi->isi_vector + intin;
+ DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", iosapic_intin, vi);
/* If this IRQ line has already been setup, skip it */
if (vi->irte)
@@ -941,8 +957,8 @@ void *iosapic_register(unsigned long hpa)
vip->irqline = (unsigned char) cnt;
vip->iosapic = isi;
}
- if (!first_isi)
- first_isi = isi;
+ isi->isi_next = iosapic_list;
+ iosapic_list = isi;
return isi;
}
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index dc82ef096f3..70694ce38be 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -37,7 +37,7 @@ config PARPORT_PC
tristate "PC-style hardware"
depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && !S390 && \
(!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && \
- !XTENSA && !CRIS
+ !XTENSA && !CRIS && !H8300
---help---
You should say Y here if you have a PC-style parallel port. All
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index 09503b8d12e..26ecdea84fb 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -232,7 +232,6 @@ static int __exit amiga_parallel_remove(struct platform_device *pdev)
if (port->irq != PARPORT_IRQ_NONE)
free_irq(IRQ_AMIGA_CIAA_FLG, port);
parport_put_port(port);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index 8fc2a8241fa..ce1543a584a 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -86,10 +86,6 @@ struct mvebu_sw_pci_bridge {
u16 secondary_status;
u16 membase;
u16 memlimit;
- u16 prefmembase;
- u16 prefmemlimit;
- u32 prefbaseupper;
- u32 preflimitupper;
u16 iobaseupper;
u16 iolimitupper;
u8 cappointer;
@@ -419,15 +415,7 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
break;
case PCI_PREF_MEMORY_BASE:
- *value = (bridge->prefmemlimit << 16 | bridge->prefmembase);
- break;
-
- case PCI_PREF_BASE_UPPER32:
- *value = bridge->prefbaseupper;
- break;
-
- case PCI_PREF_LIMIT_UPPER32:
- *value = bridge->preflimitupper;
+ *value = 0;
break;
case PCI_IO_BASE_UPPER16:
@@ -501,19 +489,6 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
mvebu_pcie_handle_membase_change(port);
break;
- case PCI_PREF_MEMORY_BASE:
- bridge->prefmembase = value & 0xffff;
- bridge->prefmemlimit = value >> 16;
- break;
-
- case PCI_PREF_BASE_UPPER32:
- bridge->prefbaseupper = value;
- break;
-
- case PCI_PREF_LIMIT_UPPER32:
- bridge->preflimitupper = value;
- break;
-
case PCI_IO_BASE_UPPER16:
bridge->iobaseupper = value & 0xffff;
bridge->iolimitupper = value >> 16;
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index bb7ebb22db0..0a648af8953 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -3,16 +3,13 @@
#
menuconfig HOTPLUG_PCI
- tristate "Support for PCI Hotplug"
+ bool "Support for PCI Hotplug"
depends on PCI && SYSFS
---help---
Say Y here if you have a motherboard with a PCI Hotplug controller.
This allows you to add and remove PCI cards while the machine is
powered up and running.
- To compile this driver as a module, choose M here: the
- module will be called pci_hotplug.
-
When in doubt, say N.
if HOTPLUG_PCI
@@ -149,7 +146,7 @@ config HOTPLUG_PCI_SGI
When in doubt, say N.
config HOTPLUG_PCI_S390
- tristate "System z PCI Hotplug Support"
+ bool "System z PCI Hotplug Support"
depends on S390 && 64BIT
help
Say Y here if you want to use the System z PCI Hotplug
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 6fdd49c6f0b..f4e02892466 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -49,6 +49,7 @@
#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+struct acpiphp_context;
struct acpiphp_bridge;
struct acpiphp_slot;
@@ -59,6 +60,7 @@ struct slot {
struct hotplug_slot *hotplug_slot;
struct acpiphp_slot *acpi_slot;
struct hotplug_slot_info info;
+ unsigned int sun; /* ACPI _SUN (Slot User Number) value */
};
static inline const char *slot_name(struct slot *slot)
@@ -75,15 +77,11 @@ struct acpiphp_bridge {
struct list_head list;
struct list_head slots;
struct kref ref;
- acpi_handle handle;
- /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
- struct acpiphp_func *func;
+ struct acpiphp_context *context;
int nr_slots;
- u32 flags;
-
/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
struct pci_bus *pci_bus;
@@ -99,15 +97,13 @@ struct acpiphp_bridge {
*/
struct acpiphp_slot {
struct list_head node;
- struct acpiphp_bridge *bridge; /* parent */
+ struct pci_bus *bus;
struct list_head funcs; /* one slot may have different
objects (i.e. for each function) */
struct slot *slot;
struct mutex crit_sect;
u8 device; /* pci device# */
-
- unsigned long long sun; /* ACPI _SUN (slot unique number) */
u32 flags; /* see below */
};
@@ -119,16 +115,32 @@ struct acpiphp_slot {
* typically 8 objects per slot (i.e. for each PCI function)
*/
struct acpiphp_func {
- struct acpiphp_slot *slot; /* parent */
+ struct acpiphp_bridge *parent;
+ struct acpiphp_slot *slot;
struct list_head sibling;
- struct notifier_block nb;
- acpi_handle handle;
u8 function; /* pci function# */
u32 flags; /* see below */
};
+struct acpiphp_context {
+ acpi_handle handle;
+ struct acpiphp_func func;
+ struct acpiphp_bridge *bridge;
+ unsigned int refcount;
+};
+
+static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
+{
+ return container_of(func, struct acpiphp_context, func);
+}
+
+static inline acpi_handle func_to_handle(struct acpiphp_func *func)
+{
+ return func_to_context(func)->handle;
+}
+
/*
* struct acpiphp_attention_info - device specific attention registration
*
@@ -142,45 +154,32 @@ struct acpiphp_attention_info
struct module *owner;
};
-/* PCI bus bridge HID */
-#define ACPI_PCI_HOST_HID "PNP0A03"
-
/* ACPI _STA method value (ignore bit 4; battery present) */
#define ACPI_STA_ALL (0x0000000f)
-/* bridge flags */
-#define BRIDGE_HAS_EJ0 (0x00000001)
-
/* slot flags */
-#define SLOT_POWEREDON (0x00000001)
-#define SLOT_ENABLED (0x00000002)
-#define SLOT_MULTIFUNCTION (0x00000004)
+#define SLOT_ENABLED (0x00000001)
/* function flags */
#define FUNC_HAS_STA (0x00000001)
#define FUNC_HAS_EJ0 (0x00000002)
-#define FUNC_HAS_PS0 (0x00000010)
-#define FUNC_HAS_PS1 (0x00000020)
-#define FUNC_HAS_PS2 (0x00000040)
-#define FUNC_HAS_PS3 (0x00000080)
-#define FUNC_HAS_DCK (0x00000100)
+#define FUNC_HAS_DCK (0x00000004)
/* function prototypes */
/* acpiphp_core.c */
int acpiphp_register_attention(struct acpiphp_attention_info*info);
int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
-int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot, unsigned int sun);
void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
/* acpiphp_glue.c */
typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
int acpiphp_enable_slot(struct acpiphp_slot *slot);
-int acpiphp_disable_slot(struct acpiphp_slot *slot);
-int acpiphp_eject_slot(struct acpiphp_slot *slot);
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
u8 acpiphp_get_power_status(struct acpiphp_slot *slot);
u8 acpiphp_get_attention_status(struct acpiphp_slot *slot);
u8 acpiphp_get_latch_status(struct acpiphp_slot *slot);
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index ca8127950fc..bf2203ef130 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -155,15 +155,11 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
static int disable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
- int retval;
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
/* disable the specified slot */
- retval = acpiphp_disable_slot(slot->acpi_slot);
- if (!retval)
- retval = acpiphp_eject_slot(slot->acpi_slot);
- return retval;
+ return acpiphp_disable_and_eject_slot(slot->acpi_slot);
}
@@ -290,7 +286,8 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
}
/* callback routine to initialize 'struct slot' for each slot */
-int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
+ unsigned int sun)
{
struct slot *slot;
int retval = -ENOMEM;
@@ -317,12 +314,11 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
acpiphp_slot->slot = slot;
- snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun);
+ slot->sun = sun;
+ snprintf(name, SLOT_NAME_SIZE, "%u", sun);
- retval = pci_hp_register(slot->hotplug_slot,
- acpiphp_slot->bridge->pci_bus,
- acpiphp_slot->device,
- name);
+ retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus,
+ acpiphp_slot->device, name);
if (retval == -EBUSY)
goto error_hpslot;
if (retval) {
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 52dee9d31e1..f6488adf3af 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -46,6 +46,7 @@
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/pci-acpi.h>
+#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/acpi.h>
@@ -55,28 +56,82 @@
static LIST_HEAD(bridge_list);
static DEFINE_MUTEX(bridge_mutex);
+static DEFINE_MUTEX(acpiphp_context_lock);
#define MY_NAME "acpiphp_glue"
-static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
+static void handle_hotplug_event(acpi_handle handle, u32 type, void *data);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(struct pci_bus *bus);
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context);
-static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
+static void hotplug_event(acpi_handle handle, u32 type, void *data);
static void free_bridge(struct kref *kref);
-/* callback routine to check for the existence of a pci dock device */
-static acpi_status
-is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
+static void acpiphp_context_handler(acpi_handle handle, void *context)
{
- int *count = (int *)context;
+ /* Intentionally empty. */
+}
- if (is_dock_device(handle)) {
- (*count)++;
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
+/**
+ * acpiphp_init_context - Create hotplug context and grab a reference to it.
+ * @handle: ACPI object handle to create the context for.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
+{
+ struct acpiphp_context *context;
+ acpi_status status;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return NULL;
+
+ context->handle = handle;
+ context->refcount = 1;
+ status = acpi_attach_data(handle, acpiphp_context_handler, context);
+ if (ACPI_FAILURE(status)) {
+ kfree(context);
+ return NULL;
}
+ return context;
+}
+
+/**
+ * acpiphp_get_context - Get hotplug context and grab a reference to it.
+ * @handle: ACPI object handle to get the context for.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static struct acpiphp_context *acpiphp_get_context(acpi_handle handle)
+{
+ struct acpiphp_context *context = NULL;
+ acpi_status status;
+ void *data;
+
+ status = acpi_get_data(handle, acpiphp_context_handler, &data);
+ if (ACPI_SUCCESS(status)) {
+ context = data;
+ context->refcount++;
+ }
+ return context;
+}
+
+/**
+ * acpiphp_put_context - Drop a reference to ACPI hotplug context.
+ * @handle: ACPI object handle to put the context for.
+ *
+ * The context object is removed if there are no more references to it.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static void acpiphp_put_context(struct acpiphp_context *context)
+{
+ if (--context->refcount)
+ return;
+
+ WARN_ON(context->bridge);
+ acpi_detach_data(context->handle, acpiphp_context_handler);
+ kfree(context);
}
static inline void get_bridge(struct acpiphp_bridge *bridge)
@@ -91,25 +146,36 @@ static inline void put_bridge(struct acpiphp_bridge *bridge)
static void free_bridge(struct kref *kref)
{
+ struct acpiphp_context *context;
struct acpiphp_bridge *bridge;
struct acpiphp_slot *slot, *next;
struct acpiphp_func *func, *tmp;
+ mutex_lock(&acpiphp_context_lock);
+
bridge = container_of(kref, struct acpiphp_bridge, ref);
list_for_each_entry_safe(slot, next, &bridge->slots, node) {
- list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
- kfree(func);
- }
+ list_for_each_entry_safe(func, tmp, &slot->funcs, sibling)
+ acpiphp_put_context(func_to_context(func));
+
kfree(slot);
}
- /* Release reference acquired by acpiphp_bridge_handle_to_function() */
- if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)
- put_bridge(bridge->func->slot->bridge);
+ context = bridge->context;
+ /* Root bridges will not have hotplug context. */
+ if (context) {
+ /* Release the reference taken by acpiphp_enumerate_slots(). */
+ put_bridge(context->func.parent);
+ context->bridge = NULL;
+ acpiphp_put_context(context);
+ }
+
put_device(&bridge->pci_bus->dev);
pci_dev_put(bridge->pci_dev);
kfree(bridge);
+
+ mutex_unlock(&acpiphp_context_lock);
}
/*
@@ -119,15 +185,14 @@ static void free_bridge(struct kref *kref)
* TBD - figure out a way to only call fixups for
* systems that require them.
*/
-static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
- void *v)
+static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
{
- struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb);
- struct pci_bus *bus = func->slot->bridge->pci_bus;
+ struct acpiphp_context *context = data;
+ struct pci_bus *bus = context->func.slot->bus;
u32 buses;
if (!bus->self)
- return NOTIFY_OK;
+ return;
/* fixup bad _DCK function that rewrites
* secondary bridge on slot
@@ -143,12 +208,12 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
| ((unsigned int)(bus->busn_res.end) << 16);
pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
}
- return NOTIFY_OK;
}
static const struct acpi_dock_ops acpiphp_dock_ops = {
- .handler = hotplug_event_func,
+ .fixup = post_dock_fixups,
+ .handler = hotplug_event,
};
/* Check whether the PCI device is managed by native PCIe hotplug driver */
@@ -182,129 +247,118 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
static void acpiphp_dock_init(void *data)
{
- struct acpiphp_func *func = data;
+ struct acpiphp_context *context = data;
- get_bridge(func->slot->bridge);
+ get_bridge(context->func.parent);
}
static void acpiphp_dock_release(void *data)
{
- struct acpiphp_func *func = data;
+ struct acpiphp_context *context = data;
- put_bridge(func->slot->bridge);
+ put_bridge(context->func.parent);
}
/* callback routine to register each ACPI PCI slot object */
-static acpi_status
-register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
+ void **rv)
{
- struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
+ struct acpiphp_bridge *bridge = data;
+ struct acpiphp_context *context;
struct acpiphp_slot *slot;
struct acpiphp_func *newfunc;
- acpi_handle tmp;
acpi_status status = AE_OK;
- unsigned long long adr, sun;
- int device, function, retval, found = 0;
+ unsigned long long adr;
+ int device, function;
struct pci_bus *pbus = bridge->pci_bus;
- struct pci_dev *pdev;
+ struct pci_dev *pdev = bridge->pci_dev;
u32 val;
- if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
+ if (pdev && device_is_managed_by_native_pciehp(pdev))
return AE_OK;
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
if (ACPI_FAILURE(status)) {
- warn("can't evaluate _ADR (%#x)\n", status);
+ acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status);
return AE_OK;
}
device = (adr >> 16) & 0xffff;
function = adr & 0xffff;
- pdev = bridge->pci_dev;
- if (pdev && device_is_managed_by_native_pciehp(pdev))
- return AE_OK;
-
- newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
- if (!newfunc)
- return AE_NO_MEMORY;
-
- newfunc->handle = handle;
+ mutex_lock(&acpiphp_context_lock);
+ context = acpiphp_init_context(handle);
+ if (!context) {
+ mutex_unlock(&acpiphp_context_lock);
+ acpi_handle_err(handle, "No hotplug context\n");
+ return AE_NOT_EXIST;
+ }
+ newfunc = &context->func;
newfunc->function = function;
+ newfunc->parent = bridge;
+ mutex_unlock(&acpiphp_context_lock);
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
+ if (acpi_has_method(handle, "_EJ0"))
newfunc->flags = FUNC_HAS_EJ0;
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
+ if (acpi_has_method(handle, "_STA"))
newfunc->flags |= FUNC_HAS_STA;
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp)))
- newfunc->flags |= FUNC_HAS_PS0;
-
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
- newfunc->flags |= FUNC_HAS_PS3;
-
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
+ if (acpi_has_method(handle, "_DCK"))
newfunc->flags |= FUNC_HAS_DCK;
- status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
- if (ACPI_FAILURE(status)) {
- /*
- * use the count of the number of slots we've found
- * for the number of the slot
- */
- sun = bridge->nr_slots+1;
- }
-
/* search for objects that share the same slot */
list_for_each_entry(slot, &bridge->slots, node)
- if (slot->device == device) {
- if (slot->sun != sun)
- warn("sibling found, but _SUN doesn't match!\n");
- found = 1;
- break;
- }
+ if (slot->device == device)
+ goto slot_found;
- if (!found) {
- slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
- if (!slot) {
- kfree(newfunc);
- return AE_NO_MEMORY;
- }
+ slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
+ if (!slot) {
+ status = AE_NO_MEMORY;
+ goto err;
+ }
- slot->bridge = bridge;
- slot->device = device;
- slot->sun = sun;
- INIT_LIST_HEAD(&slot->funcs);
- mutex_init(&slot->crit_sect);
+ slot->bus = bridge->pci_bus;
+ slot->device = device;
+ INIT_LIST_HEAD(&slot->funcs);
+ mutex_init(&slot->crit_sect);
+
+ list_add_tail(&slot->node, &bridge->slots);
+
+ /* Register slots for ejectable funtions only. */
+ if (acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) {
+ unsigned long long sun;
+ int retval;
- mutex_lock(&bridge_mutex);
- list_add_tail(&slot->node, &bridge->slots);
- mutex_unlock(&bridge_mutex);
bridge->nr_slots++;
+ status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
+ if (ACPI_FAILURE(status))
+ sun = bridge->nr_slots;
dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
- slot->sun, pci_domain_nr(pbus), pbus->number, device);
- retval = acpiphp_register_hotplug_slot(slot);
+ sun, pci_domain_nr(pbus), pbus->number, device);
+
+ retval = acpiphp_register_hotplug_slot(slot, sun);
if (retval) {
+ slot->slot = NULL;
+ bridge->nr_slots--;
if (retval == -EBUSY)
warn("Slot %llu already registered by another "
- "hotplug driver\n", slot->sun);
+ "hotplug driver\n", sun);
else
warn("acpiphp_register_hotplug_slot failed "
"(err code = 0x%x)\n", retval);
- goto err_exit;
}
+ /* Even if the slot registration fails, we can still use it. */
}
+ slot_found:
newfunc->slot = slot;
- mutex_lock(&bridge_mutex);
list_add_tail(&newfunc->sibling, &slot->funcs);
- mutex_unlock(&bridge_mutex);
if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
&val, 60*1000))
- slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+ slot->flags |= SLOT_ENABLED;
if (is_dock_device(handle)) {
/* we don't want to call this device's _EJ0
@@ -313,136 +367,46 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
*/
newfunc->flags &= ~FUNC_HAS_EJ0;
if (register_hotplug_dock_device(handle,
- &acpiphp_dock_ops, newfunc,
+ &acpiphp_dock_ops, context,
acpiphp_dock_init, acpiphp_dock_release))
dbg("failed to register dock device\n");
-
- /* we need to be notified when dock events happen
- * outside of the hotplug operation, since we may
- * need to do fixups before we can hotplug.
- */
- newfunc->nb.notifier_call = post_dock_fixups;
- if (register_dock_notifier(&newfunc->nb))
- dbg("failed to register a dock notifier");
}
/* install notify handler */
if (!(newfunc->flags & FUNC_HAS_DCK)) {
- status = acpi_install_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_func,
- newfunc);
-
+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event,
+ context);
if (ACPI_FAILURE(status))
- err("failed to register interrupt notify handler\n");
- } else
- status = AE_OK;
-
- return status;
-
- err_exit:
- bridge->nr_slots--;
- mutex_lock(&bridge_mutex);
- list_del(&slot->node);
- mutex_unlock(&bridge_mutex);
- kfree(slot);
- kfree(newfunc);
-
- return AE_OK;
-}
-
-
-/* see if it's worth looking at this bridge */
-static int detect_ejectable_slots(acpi_handle handle)
-{
- int found = acpi_pci_detect_ejectable(handle);
- if (!found) {
- acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
- is_pci_dock_device, NULL, (void *)&found, NULL);
- }
- return found;
-}
-
-/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */
-static void init_bridge_misc(struct acpiphp_bridge *bridge)
-{
- acpi_status status;
-
- /* must be added to the list prior to calling register_slot */
- mutex_lock(&bridge_mutex);
- list_add(&bridge->list, &bridge_list);
- mutex_unlock(&bridge_mutex);
-
- /* register all slot objects under this bridge */
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
- register_slot, NULL, bridge, NULL);
- if (ACPI_FAILURE(status)) {
- mutex_lock(&bridge_mutex);
- list_del(&bridge->list);
- mutex_unlock(&bridge_mutex);
- return;
+ acpi_handle_err(handle,
+ "failed to install notify handler\n");
}
- /* install notify handler for P2P bridges */
- if (!pci_is_root_bus(bridge->pci_bus)) {
- if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
- status = acpi_remove_notify_handler(bridge->func->handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_func);
- if (ACPI_FAILURE(status))
- err("failed to remove notify handler\n");
- }
- status = acpi_install_notify_handler(bridge->handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_bridge,
- bridge);
-
- if (ACPI_FAILURE(status)) {
- err("failed to register interrupt notify handler\n");
- }
- }
-}
-
-
-/* find acpiphp_func from acpiphp_bridge */
-static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
-{
- struct acpiphp_bridge *bridge;
- struct acpiphp_slot *slot;
- struct acpiphp_func *func = NULL;
-
- mutex_lock(&bridge_mutex);
- list_for_each_entry(bridge, &bridge_list, list) {
- list_for_each_entry(slot, &bridge->slots, node) {
- list_for_each_entry(func, &slot->funcs, sibling) {
- if (func->handle == handle) {
- get_bridge(func->slot->bridge);
- mutex_unlock(&bridge_mutex);
- return func;
- }
- }
- }
- }
- mutex_unlock(&bridge_mutex);
+ return AE_OK;
- return NULL;
+ err:
+ mutex_lock(&acpiphp_context_lock);
+ acpiphp_put_context(context);
+ mutex_unlock(&acpiphp_context_lock);
+ return status;
}
-
static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
{
- struct acpiphp_bridge *bridge;
-
- mutex_lock(&bridge_mutex);
- list_for_each_entry(bridge, &bridge_list, list)
- if (bridge->handle == handle) {
+ struct acpiphp_context *context;
+ struct acpiphp_bridge *bridge = NULL;
+
+ mutex_lock(&acpiphp_context_lock);
+ context = acpiphp_get_context(handle);
+ if (context) {
+ bridge = context->bridge;
+ if (bridge)
get_bridge(bridge);
- mutex_unlock(&bridge_mutex);
- return bridge;
- }
- mutex_unlock(&bridge_mutex);
- return NULL;
+ acpiphp_put_context(context);
+ }
+ mutex_unlock(&acpiphp_context_lock);
+ return bridge;
}
static void cleanup_bridge(struct acpiphp_bridge *bridge)
@@ -450,40 +414,24 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
struct acpiphp_slot *slot;
struct acpiphp_func *func;
acpi_status status;
- acpi_handle handle = bridge->handle;
-
- if (!pci_is_root_bus(bridge->pci_bus)) {
- status = acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_bridge);
- if (ACPI_FAILURE(status))
- err("failed to remove notify handler\n");
- }
-
- if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
- status = acpi_install_notify_handler(bridge->func->handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_func,
- bridge->func);
- if (ACPI_FAILURE(status))
- err("failed to install interrupt notify handler\n");
- }
list_for_each_entry(slot, &bridge->slots, node) {
list_for_each_entry(func, &slot->funcs, sibling) {
- if (is_dock_device(func->handle)) {
- unregister_hotplug_dock_device(func->handle);
- unregister_dock_notifier(&func->nb);
- }
+ acpi_handle handle = func_to_handle(func);
+
+ if (is_dock_device(handle))
+ unregister_hotplug_dock_device(handle);
+
if (!(func->flags & FUNC_HAS_DCK)) {
- status = acpi_remove_notify_handler(func->handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_func);
+ status = acpi_remove_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event);
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
}
}
- acpiphp_unregister_hotplug_slot(slot);
+ if (slot->slot)
+ acpiphp_unregister_hotplug_slot(slot);
}
mutex_lock(&bridge_mutex);
@@ -491,71 +439,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
mutex_unlock(&bridge_mutex);
}
-static int power_on_slot(struct acpiphp_slot *slot)
-{
- acpi_status status;
- struct acpiphp_func *func;
- int retval = 0;
-
- /* if already enabled, just skip */
- if (slot->flags & SLOT_POWEREDON)
- goto err_exit;
-
- list_for_each_entry(func, &slot->funcs, sibling) {
- if (func->flags & FUNC_HAS_PS0) {
- dbg("%s: executing _PS0\n", __func__);
- status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
- if (ACPI_FAILURE(status)) {
- warn("%s: _PS0 failed\n", __func__);
- retval = -1;
- goto err_exit;
- } else
- break;
- }
- }
-
- /* TBD: evaluate _STA to check if the slot is enabled */
-
- slot->flags |= SLOT_POWEREDON;
-
- err_exit:
- return retval;
-}
-
-
-static int power_off_slot(struct acpiphp_slot *slot)
-{
- acpi_status status;
- struct acpiphp_func *func;
-
- int retval = 0;
-
- /* if already disabled, just skip */
- if ((slot->flags & SLOT_POWEREDON) == 0)
- goto err_exit;
-
- list_for_each_entry(func, &slot->funcs, sibling) {
- if (func->flags & FUNC_HAS_PS3) {
- status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
- if (ACPI_FAILURE(status)) {
- warn("%s: _PS3 failed\n", __func__);
- retval = -1;
- goto err_exit;
- } else
- break;
- }
- }
-
- /* TBD: evaluate _STA to check if the slot is disabled */
-
- slot->flags &= (~SLOT_POWEREDON);
-
- err_exit:
- return retval;
-}
-
-
-
/**
* acpiphp_max_busnr - return the highest reserved bus number under the given bus.
* @bus: bus to start search with
@@ -583,52 +466,32 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
return max;
}
-
/**
- * acpiphp_bus_add - add a new bus to acpi subsystem
- * @func: acpiphp_func of the bridge
+ * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree.
+ * @handle: ACPI device object handle to start from.
*/
-static int acpiphp_bus_add(struct acpiphp_func *func)
+static void acpiphp_bus_trim(acpi_handle handle)
{
- struct acpi_device *device;
- int ret_val;
-
- if (!acpi_bus_get_device(func->handle, &device)) {
- dbg("bus exists... trim\n");
- /* this shouldn't be in here, so remove
- * the bus then re-add it...
- */
- acpi_bus_trim(device);
- }
-
- ret_val = acpi_bus_scan(func->handle);
- if (!ret_val)
- ret_val = acpi_bus_get_device(func->handle, &device);
-
- if (ret_val)
- dbg("error adding bus, %x\n", -ret_val);
+ struct acpi_device *adev = NULL;
- return ret_val;
+ acpi_bus_get_device(handle, &adev);
+ if (adev)
+ acpi_bus_trim(adev);
}
-
/**
- * acpiphp_bus_trim - trim a bus from acpi subsystem
- * @handle: handle to acpi namespace
+ * acpiphp_bus_add - Scan ACPI namespace subtree.
+ * @handle: ACPI object handle to start the scan from.
*/
-static int acpiphp_bus_trim(acpi_handle handle)
+static void acpiphp_bus_add(acpi_handle handle)
{
- struct acpi_device *device;
- int retval;
-
- retval = acpi_bus_get_device(handle, &device);
- if (retval) {
- dbg("acpi_device not found\n");
- return retval;
- }
+ struct acpi_device *adev = NULL;
- acpi_bus_trim(device);
- return 0;
+ acpiphp_bus_trim(handle);
+ acpi_bus_scan(handle);
+ acpi_bus_get_device(handle, &adev);
+ if (adev)
+ acpi_device_set_power(adev, ACPI_STATE_D0);
}
static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
@@ -645,7 +508,8 @@ static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = 1;
/* _REG is optional, we don't care about if there is failure */
- acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL);
+ acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list,
+ NULL);
}
}
@@ -653,59 +517,44 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
{
struct acpiphp_func *func;
- if (!dev->subordinate)
- return;
-
/* quirk, or pcie could set it already */
if (dev->is_hotplug_bridge)
return;
- if (PCI_SLOT(dev->devfn) != slot->device)
- return;
-
list_for_each_entry(func, &slot->funcs, sibling) {
if (PCI_FUNC(dev->devfn) == func->function) {
- /* check if this bridge has ejectable slots */
- if ((detect_ejectable_slots(func->handle) > 0))
- dev->is_hotplug_bridge = 1;
+ dev->is_hotplug_bridge = 1;
break;
}
}
}
/**
- * enable_device - enable, configure a slot
+ * enable_slot - enable, configure a slot
* @slot: slot to be enabled
*
* This function should be called per *physical slot*,
* not per each slot object in ACPI namespace.
*/
-static int __ref enable_device(struct acpiphp_slot *slot)
+static void __ref enable_slot(struct acpiphp_slot *slot)
{
struct pci_dev *dev;
- struct pci_bus *bus = slot->bridge->pci_bus;
+ struct pci_bus *bus = slot->bus;
struct acpiphp_func *func;
- int num, max, pass;
+ int max, pass;
LIST_HEAD(add_list);
- if (slot->flags & SLOT_ENABLED)
- goto err_exit;
-
list_for_each_entry(func, &slot->funcs, sibling)
- acpiphp_bus_add(func);
+ acpiphp_bus_add(func_to_handle(func));
- num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
- if (num == 0) {
- /* Maybe only part of funcs are added. */
- dbg("No new device found\n");
- goto err_exit;
- }
+ pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
max = acpiphp_max_busnr(bus);
for (pass = 0; pass < 2; pass++) {
list_for_each_entry(dev, &bus->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != slot->device)
continue;
+
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
max = pci_scan_bridge(bus, dev, max, pass);
@@ -743,16 +592,12 @@ static int __ref enable_device(struct acpiphp_slot *slot)
continue;
}
}
-
-
- err_exit:
- return 0;
}
/* return first device in slot, acquiring a reference on it */
static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
{
- struct pci_bus *bus = slot->bridge->pci_bus;
+ struct pci_bus *bus = slot->bus;
struct pci_dev *dev;
struct pci_dev *ret = NULL;
@@ -768,16 +613,16 @@ static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
}
/**
- * disable_device - disable a slot
+ * disable_slot - disable a slot
* @slot: ACPI PHP slot
*/
-static int disable_device(struct acpiphp_slot *slot)
+static void disable_slot(struct acpiphp_slot *slot)
{
struct acpiphp_func *func;
struct pci_dev *pdev;
/*
- * enable_device() enumerates all functions in this device via
+ * enable_slot() enumerates all functions in this device via
* pci_scan_slot(), whether they have associated ACPI hotplug
* methods (_EJ0, etc.) or not. Therefore, we remove all functions
* here.
@@ -787,13 +632,10 @@ static int disable_device(struct acpiphp_slot *slot)
pci_dev_put(pdev);
}
- list_for_each_entry(func, &slot->funcs, sibling) {
- acpiphp_bus_trim(func->handle);
- }
+ list_for_each_entry(func, &slot->funcs, sibling)
+ acpiphp_bus_trim(func_to_handle(func));
slot->flags &= (~SLOT_ENABLED);
-
- return 0;
}
@@ -811,18 +653,21 @@ static int disable_device(struct acpiphp_slot *slot)
*/
static unsigned int get_slot_status(struct acpiphp_slot *slot)
{
- acpi_status status;
unsigned long long sta = 0;
- u32 dvid;
struct acpiphp_func *func;
list_for_each_entry(func, &slot->funcs, sibling) {
if (func->flags & FUNC_HAS_STA) {
- status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
+ acpi_status status;
+
+ status = acpi_evaluate_integer(func_to_handle(func),
+ "_STA", NULL, &sta);
if (ACPI_SUCCESS(status) && sta)
break;
} else {
- pci_bus_read_config_dword(slot->bridge->pci_bus,
+ u32 dvid;
+
+ pci_bus_read_config_dword(slot->bus,
PCI_DEVFN(slot->device,
func->function),
PCI_VENDOR_ID, &dvid);
@@ -837,34 +682,42 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
}
/**
- * acpiphp_eject_slot - physically eject the slot
- * @slot: ACPI PHP slot
+ * trim_stale_devices - remove PCI devices that are not responding.
+ * @dev: PCI device to start walking the hierarchy from.
*/
-int acpiphp_eject_slot(struct acpiphp_slot *slot)
+static void trim_stale_devices(struct pci_dev *dev)
{
- acpi_status status;
- struct acpiphp_func *func;
- struct acpi_object_list arg_list;
- union acpi_object arg;
+ acpi_handle handle = ACPI_HANDLE(&dev->dev);
+ struct pci_bus *bus = dev->subordinate;
+ bool alive = false;
- list_for_each_entry(func, &slot->funcs, sibling) {
- /* We don't want to call _EJ0 on non-existing functions. */
- if ((func->flags & FUNC_HAS_EJ0)) {
- /* _EJ0 method take one argument */
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 1;
-
- status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
- if (ACPI_FAILURE(status)) {
- warn("%s: _EJ0 failed\n", __func__);
- return -1;
- } else
- break;
- }
+ if (handle) {
+ acpi_status status;
+ unsigned long long sta;
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL;
+ }
+ if (!alive) {
+ u32 v;
+
+ /* Check if the device responds. */
+ alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0);
+ }
+ if (!alive) {
+ pci_stop_and_remove_bus_device(dev);
+ if (handle)
+ acpiphp_bus_trim(handle);
+ } else if (bus) {
+ struct pci_dev *child, *tmp;
+
+ /* The device is a bridge. so check the bus below it. */
+ pm_runtime_get_sync(&dev->dev);
+ list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
+ trim_stale_devices(child);
+
+ pm_runtime_put(&dev->dev);
}
- return 0;
}
/**
@@ -874,43 +727,30 @@ int acpiphp_eject_slot(struct acpiphp_slot *slot)
* Iterate over all slots under this bridge and make sure that if a
* card is present they are enabled, and if not they are disabled.
*/
-static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
+static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
{
struct acpiphp_slot *slot;
- int retval = 0;
- int enabled, disabled;
-
- enabled = disabled = 0;
list_for_each_entry(slot, &bridge->slots, node) {
- unsigned int status = get_slot_status(slot);
- if (slot->flags & SLOT_ENABLED) {
- if (status == ACPI_STA_ALL)
- continue;
- retval = acpiphp_disable_slot(slot);
- if (retval) {
- err("Error occurred in disabling\n");
- goto err_exit;
- } else {
- acpiphp_eject_slot(slot);
- }
- disabled++;
+ struct pci_bus *bus = slot->bus;
+ struct pci_dev *dev, *tmp;
+
+ mutex_lock(&slot->crit_sect);
+ /* wake up all functions */
+ if (get_slot_status(slot) == ACPI_STA_ALL) {
+ /* remove stale devices if any */
+ list_for_each_entry_safe(dev, tmp, &bus->devices,
+ bus_list)
+ if (PCI_SLOT(dev->devfn) == slot->device)
+ trim_stale_devices(dev);
+
+ /* configure all functions */
+ enable_slot(slot);
} else {
- if (status != ACPI_STA_ALL)
- continue;
- retval = acpiphp_enable_slot(slot);
- if (retval) {
- err("Error occurred in enabling\n");
- goto err_exit;
- }
- enabled++;
+ disable_slot(slot);
}
+ mutex_unlock(&slot->crit_sect);
}
-
- dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled);
-
- err_exit:
- return retval;
}
static void acpiphp_set_hpp_values(struct pci_bus *bus)
@@ -949,25 +789,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
* ACPI event handlers
*/
-static acpi_status
-check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- struct acpiphp_bridge *bridge;
- char objname[64];
- struct acpi_buffer buffer = { .length = sizeof(objname),
- .pointer = objname };
-
- bridge = acpiphp_handle_to_bridge(handle);
- if (bridge) {
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- dbg("%s: re-enumerating slots under %s\n",
- __func__, objname);
- acpiphp_check_bridge(bridge);
- put_bridge(bridge);
- }
- return AE_OK ;
-}
-
void acpiphp_check_host_bridge(acpi_handle handle)
{
struct acpiphp_bridge *bridge;
@@ -977,27 +798,23 @@ void acpiphp_check_host_bridge(acpi_handle handle)
acpiphp_check_bridge(bridge);
put_bridge(bridge);
}
-
- acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
- ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
}
-static void _handle_hotplug_event_bridge(struct work_struct *work)
+static void hotplug_event(acpi_handle handle, u32 type, void *data)
{
+ struct acpiphp_context *context = data;
+ struct acpiphp_func *func = &context->func;
struct acpiphp_bridge *bridge;
char objname[64];
struct acpi_buffer buffer = { .length = sizeof(objname),
.pointer = objname };
- struct acpi_hp_work *hp_work;
- acpi_handle handle;
- u32 type;
- hp_work = container_of(work, struct acpi_hp_work, work);
- handle = hp_work->handle;
- type = hp_work->type;
- bridge = (struct acpiphp_bridge *)hp_work->context;
+ mutex_lock(&acpiphp_context_lock);
+ bridge = context->bridge;
+ if (bridge)
+ get_bridge(bridge);
- acpi_scan_lock_acquire();
+ mutex_unlock(&acpiphp_context_lock);
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
@@ -1006,188 +823,129 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
/* bus re-enumerate */
dbg("%s: Bus check notify on %s\n", __func__, objname);
dbg("%s: re-enumerating slots under %s\n", __func__, objname);
- acpiphp_check_bridge(bridge);
- acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
- ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
+ if (bridge) {
+ acpiphp_check_bridge(bridge);
+ } else {
+ struct acpiphp_slot *slot = func->slot;
+
+ mutex_lock(&slot->crit_sect);
+ enable_slot(slot);
+ mutex_unlock(&slot->crit_sect);
+ }
break;
case ACPI_NOTIFY_DEVICE_CHECK:
/* device check */
dbg("%s: Device check notify on %s\n", __func__, objname);
- acpiphp_check_bridge(bridge);
- break;
+ if (bridge)
+ acpiphp_check_bridge(bridge);
+ else
+ acpiphp_check_bridge(func->parent);
- case ACPI_NOTIFY_DEVICE_WAKE:
- /* wake event */
- dbg("%s: Device wake notify on %s\n", __func__, objname);
break;
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
dbg("%s: Device eject notify on %s\n", __func__, objname);
- if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
- struct acpiphp_slot *slot;
- slot = bridge->func->slot;
- if (!acpiphp_disable_slot(slot))
- acpiphp_eject_slot(slot);
- }
+ acpiphp_disable_and_eject_slot(func->slot);
break;
+ }
- case ACPI_NOTIFY_FREQUENCY_MISMATCH:
- printk(KERN_ERR "Device %s cannot be configured due"
- " to a frequency mismatch\n", objname);
- break;
+ if (bridge)
+ put_bridge(bridge);
+}
- case ACPI_NOTIFY_BUS_MODE_MISMATCH:
- printk(KERN_ERR "Device %s cannot be configured due"
- " to a bus mode mismatch\n", objname);
- break;
+static void hotplug_event_work(struct work_struct *work)
+{
+ struct acpiphp_context *context;
+ struct acpi_hp_work *hp_work;
- case ACPI_NOTIFY_POWER_FAULT:
- printk(KERN_ERR "Device %s has suffered a power fault\n",
- objname);
- break;
+ hp_work = container_of(work, struct acpi_hp_work, work);
+ context = hp_work->context;
+ acpi_scan_lock_acquire();
- default:
- warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
- break;
- }
+ hotplug_event(hp_work->handle, hp_work->type, context);
acpi_scan_lock_release();
- kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
- put_bridge(bridge);
+ kfree(hp_work); /* allocated in handle_hotplug_event() */
+ put_bridge(context->func.parent);
}
/**
- * handle_hotplug_event_bridge - handle ACPI event on bridges
+ * handle_hotplug_event - handle ACPI hotplug event
* @handle: Notify()'ed acpi_handle
* @type: Notify code
- * @context: pointer to acpiphp_bridge structure
+ * @data: pointer to acpiphp_context structure
*
- * Handles ACPI event notification on {host,p2p} bridges.
+ * Handles ACPI event notification on slots.
*/
-static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
- void *context)
+static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
{
- struct acpiphp_bridge *bridge = context;
-
- /*
- * Currently the code adds all hotplug events to the kacpid_wq
- * queue when it should add hotplug events to the kacpi_hotplug_wq.
- * The proper way to fix this is to reorganize the code so that
- * drivers (dock, etc.) do not call acpi_os_execute(), etc.
- * For now just re-add this work to the kacpi_hotplug_wq so we
- * don't deadlock on hotplug actions.
- */
- get_bridge(bridge);
- alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
-}
-
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context)
-{
- struct acpiphp_func *func = context;
- char objname[64];
- struct acpi_buffer buffer = { .length = sizeof(objname),
- .pointer = objname };
-
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ struct acpiphp_context *context;
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
- /* bus re-enumerate */
- dbg("%s: Bus check notify on %s\n", __func__, objname);
- acpiphp_enable_slot(func->slot);
- break;
-
case ACPI_NOTIFY_DEVICE_CHECK:
- /* device check : re-enumerate from parent bus */
- dbg("%s: Device check notify on %s\n", __func__, objname);
- acpiphp_check_bridge(func->slot->bridge);
- break;
-
- case ACPI_NOTIFY_DEVICE_WAKE:
- /* wake event */
- dbg("%s: Device wake notify on %s\n", __func__, objname);
- break;
-
case ACPI_NOTIFY_EJECT_REQUEST:
- /* request device eject */
- dbg("%s: Device eject notify on %s\n", __func__, objname);
- if (!(acpiphp_disable_slot(func->slot)))
- acpiphp_eject_slot(func->slot);
break;
- default:
- warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
- break;
- }
-}
-
-static void _handle_hotplug_event_func(struct work_struct *work)
-{
- struct acpi_hp_work *hp_work;
- struct acpiphp_func *func;
+ case ACPI_NOTIFY_DEVICE_WAKE:
+ return;
- hp_work = container_of(work, struct acpi_hp_work, work);
- func = hp_work->context;
- acpi_scan_lock_acquire();
+ case ACPI_NOTIFY_FREQUENCY_MISMATCH:
+ acpi_handle_err(handle, "Device cannot be configured due "
+ "to a frequency mismatch\n");
+ return;
- hotplug_event_func(hp_work->handle, hp_work->type, func);
+ case ACPI_NOTIFY_BUS_MODE_MISMATCH:
+ acpi_handle_err(handle, "Device cannot be configured due "
+ "to a bus mode mismatch\n");
+ return;
- acpi_scan_lock_release();
- kfree(hp_work); /* allocated in handle_hotplug_event_func */
- put_bridge(func->slot->bridge);
-}
+ case ACPI_NOTIFY_POWER_FAULT:
+ acpi_handle_err(handle, "Device has suffered a power fault\n");
+ return;
-/**
- * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
- * @handle: Notify()'ed acpi_handle
- * @type: Notify code
- * @context: pointer to acpiphp_func structure
- *
- * Handles ACPI event notification on slots.
- */
-static void handle_hotplug_event_func(acpi_handle handle, u32 type,
- void *context)
-{
- struct acpiphp_func *func = context;
+ default:
+ acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
+ return;
+ }
- /*
- * Currently the code adds all hotplug events to the kacpid_wq
- * queue when it should add hotplug events to the kacpi_hotplug_wq.
- * The proper way to fix this is to reorganize the code so that
- * drivers (dock, etc.) do not call acpi_os_execute(), etc.
- * For now just re-add this work to the kacpi_hotplug_wq so we
- * don't deadlock on hotplug actions.
- */
- get_bridge(func->slot->bridge);
- alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
+ mutex_lock(&acpiphp_context_lock);
+ context = acpiphp_get_context(handle);
+ if (context) {
+ get_bridge(context->func.parent);
+ acpiphp_put_context(context);
+ alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
+ }
+ mutex_unlock(&acpiphp_context_lock);
}
/*
* Create hotplug slots for the PCI bus.
* It should always return 0 to avoid skipping following notifiers.
*/
-void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle)
+void acpiphp_enumerate_slots(struct pci_bus *bus)
{
- acpi_handle dummy_handle;
struct acpiphp_bridge *bridge;
+ acpi_handle handle;
+ acpi_status status;
if (acpiphp_disabled)
return;
- if (detect_ejectable_slots(handle) <= 0)
+ handle = ACPI_HANDLE(bus->bridge);
+ if (!handle)
return;
bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
- if (bridge == NULL) {
- err("out of memory\n");
+ if (!bridge) {
+ acpi_handle_err(handle, "No memory for bridge object\n");
return;
}
INIT_LIST_HEAD(&bridge->slots);
kref_init(&bridge->ref);
- bridge->handle = handle;
bridge->pci_dev = pci_dev_get(bus->self);
bridge->pci_bus = bus;
@@ -1198,31 +956,62 @@ void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle)
*/
get_device(&bus->dev);
- if (!pci_is_root_bus(bridge->pci_bus) &&
- ACPI_SUCCESS(acpi_get_handle(bridge->handle,
- "_EJ0", &dummy_handle))) {
- dbg("found ejectable p2p bridge\n");
- bridge->flags |= BRIDGE_HAS_EJ0;
- bridge->func = acpiphp_bridge_handle_to_function(handle);
+ if (!pci_is_root_bus(bridge->pci_bus)) {
+ struct acpiphp_context *context;
+
+ /*
+ * This bridge should have been registered as a hotplug function
+ * under its parent, so the context has to be there. If not, we
+ * are in deep goo.
+ */
+ mutex_lock(&acpiphp_context_lock);
+ context = acpiphp_get_context(handle);
+ if (WARN_ON(!context)) {
+ mutex_unlock(&acpiphp_context_lock);
+ put_device(&bus->dev);
+ kfree(bridge);
+ return;
+ }
+ bridge->context = context;
+ context->bridge = bridge;
+ /* Get a reference to the parent bridge. */
+ get_bridge(context->func.parent);
+ mutex_unlock(&acpiphp_context_lock);
}
- init_bridge_misc(bridge);
+ /* must be added to the list prior to calling register_slot */
+ mutex_lock(&bridge_mutex);
+ list_add(&bridge->list, &bridge_list);
+ mutex_unlock(&bridge_mutex);
+
+ /* register all slot objects under this bridge */
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ register_slot, NULL, bridge, NULL);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(handle, "failed to register slots\n");
+ cleanup_bridge(bridge);
+ put_bridge(bridge);
+ }
}
/* Destroy hotplug slots associated with the PCI bus */
void acpiphp_remove_slots(struct pci_bus *bus)
{
- struct acpiphp_bridge *bridge, *tmp;
+ struct acpiphp_bridge *bridge;
if (acpiphp_disabled)
return;
- list_for_each_entry_safe(bridge, tmp, &bridge_list, list)
+ mutex_lock(&bridge_mutex);
+ list_for_each_entry(bridge, &bridge_list, list)
if (bridge->pci_bus == bus) {
+ mutex_unlock(&bridge_mutex);
cleanup_bridge(bridge);
put_bridge(bridge);
- break;
+ return;
}
+
+ mutex_unlock(&bridge_mutex);
}
/**
@@ -1231,51 +1020,39 @@ void acpiphp_remove_slots(struct pci_bus *bus)
*/
int acpiphp_enable_slot(struct acpiphp_slot *slot)
{
- int retval;
-
mutex_lock(&slot->crit_sect);
+ /* configure all functions */
+ if (!(slot->flags & SLOT_ENABLED))
+ enable_slot(slot);
- /* wake up all functions */
- retval = power_on_slot(slot);
- if (retval)
- goto err_exit;
-
- if (get_slot_status(slot) == ACPI_STA_ALL) {
- /* configure all functions */
- retval = enable_device(slot);
- if (retval)
- power_off_slot(slot);
- } else {
- dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__);
- power_off_slot(slot);
- }
-
- err_exit:
mutex_unlock(&slot->crit_sect);
- return retval;
+ return 0;
}
/**
- * acpiphp_disable_slot - power off slot
+ * acpiphp_disable_and_eject_slot - power off and eject slot
* @slot: ACPI PHP slot
*/
-int acpiphp_disable_slot(struct acpiphp_slot *slot)
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
{
+ struct acpiphp_func *func;
int retval = 0;
mutex_lock(&slot->crit_sect);
/* unconfigure all functions */
- retval = disable_device(slot);
- if (retval)
- goto err_exit;
+ disable_slot(slot);
+
+ list_for_each_entry(func, &slot->funcs, sibling)
+ if (func->flags & FUNC_HAS_EJ0) {
+ acpi_handle handle = func_to_handle(func);
- /* power off all functions */
- retval = power_off_slot(slot);
- if (retval)
- goto err_exit;
+ if (ACPI_FAILURE(acpi_evaluate_ej0(handle)))
+ acpi_handle_err(handle, "_EJ0 failed\n");
+
+ break;
+ }
- err_exit:
mutex_unlock(&slot->crit_sect);
return retval;
}
@@ -1287,7 +1064,7 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
*/
u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
{
- return (slot->flags & SLOT_POWEREDON);
+ return (slot->flags & SLOT_ENABLED);
}
@@ -1297,11 +1074,7 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
*/
u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
{
- unsigned int sta;
-
- sta = get_slot_status(slot);
-
- return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1;
+ return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI);
}
@@ -1311,9 +1084,5 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
*/
u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
{
- unsigned int sta;
-
- sta = get_slot_status(slot);
-
- return (sta == 0) ? 0 : 1;
+ return !!get_slot_status(slot);
}
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index c35e8ad6db0..2f5786c8522 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -66,7 +66,7 @@ do { \
#define IBM_HARDWARE_ID1 "IBM37D0"
#define IBM_HARDWARE_ID2 "IBM37D4"
-#define hpslot_to_sun(A) (((struct slot *)((A)->private))->acpi_slot->sun)
+#define hpslot_to_sun(A) (((struct slot *)((A)->private))->sun)
/* union apci_descriptor - allows access to the
* various device descriptors that are embedded in the
@@ -270,7 +270,6 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context)
if (subevent == 0x80) {
dbg("%s: generationg bus event\n", __func__);
- acpi_bus_generate_proc_event(note->device, note->event, detail);
acpi_bus_generate_netlink_event(note->device->pnp.device_class,
dev_name(&note->device->dev),
note->event, detail);
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index aac7a40e4a4..0e0d0f7f63f 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -92,7 +92,14 @@ int pciehp_unconfigure_device(struct slot *p_slot)
if (ret)
presence = 0;
- list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
+ /*
+ * Stopping an SR-IOV PF device removes all the associated VFs,
+ * which will update the bus->devices list and confuse the
+ * iterator. Therefore, iterate in reverse so we remove the VFs
+ * first, then the PF. We do the same in pci_stop_bus_device().
+ */
+ list_for_each_entry_safe_reverse(dev, temp, &parent->devices,
+ bus_list) {
pci_dev_get(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl);
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index b29e20b7862..bb7af78e4ee 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -388,7 +388,6 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
/* Remove the EADS bridge device itself */
BUG_ON(!bus->self);
pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
- eeh_remove_bus_device(bus->self, true);
pci_stop_and_remove_bus_device(bus->self);
return 0;
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c
index ea3fa90d020..66e505ca24e 100644
--- a/drivers/pci/hotplug/s390_pci_hpc.c
+++ b/drivers/pci/hotplug/s390_pci_hpc.c
@@ -79,8 +79,6 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
if (rc)
goto out_deconfigure;
- slot->zdev->state = ZPCI_FN_STATE_ONLINE;
-
pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN);
pci_bus_add_devices(slot->zdev->bus);
@@ -148,7 +146,7 @@ static struct hotplug_slot_ops s390_hotplug_slot_ops = {
.get_adapter_status = get_adapter_status,
};
-static int init_pci_slot(struct zpci_dev *zdev)
+int zpci_init_slot(struct zpci_dev *zdev)
{
struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *info;
@@ -202,7 +200,7 @@ error:
return -ENOMEM;
}
-static void exit_pci_slot(struct zpci_dev *zdev)
+void zpci_exit_slot(struct zpci_dev *zdev)
{
struct list_head *tmp, *n;
struct slot *slot;
@@ -215,60 +213,3 @@ static void exit_pci_slot(struct zpci_dev *zdev)
pci_hp_deregister(slot->hotplug_slot);
}
}
-
-static struct pci_hp_callback_ops hp_ops = {
- .create_slot = init_pci_slot,
- .remove_slot = exit_pci_slot,
-};
-
-static void __init init_pci_slots(void)
-{
- struct zpci_dev *zdev;
-
- /*
- * Create a structure for each slot, and register that slot
- * with the pci_hotplug subsystem.
- */
- mutex_lock(&zpci_list_lock);
- list_for_each_entry(zdev, &zpci_list, entry) {
- init_pci_slot(zdev);
- }
- mutex_unlock(&zpci_list_lock);
-}
-
-static void __exit exit_pci_slots(void)
-{
- struct list_head *tmp, *n;
- struct slot *slot;
-
- /*
- * Unregister all of our slots with the pci_hotplug subsystem.
- * Memory will be freed in release_slot() callback after slot's
- * lifespan is finished.
- */
- list_for_each_safe(tmp, n, &s390_hotplug_slot_list) {
- slot = list_entry(tmp, struct slot, slot_list);
- list_del(&slot->slot_list);
- pci_hp_deregister(slot->hotplug_slot);
- }
-}
-
-static int __init pci_hotplug_s390_init(void)
-{
- if (!s390_pci_probe)
- return -EOPNOTSUPP;
-
- zpci_register_hp_ops(&hp_ops);
- init_pci_slots();
-
- return 0;
-}
-
-static void __exit pci_hotplug_s390_exit(void)
-{
- exit_pci_slots();
- zpci_deregister_hp_ops();
-}
-
-module_init(pci_hotplug_s390_init);
-module_exit(pci_hotplug_s390_exit);
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index dbdc5f7e2b2..7c29ee4ed0a 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -210,7 +210,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
}
if (!error)
- dev_info(&dev->dev, "power state changed by ACPI to %s\n",
+ dev_dbg(&dev->dev, "power state changed by ACPI to %s\n",
acpi_power_state_string(state_conv[state]));
return error;
@@ -290,24 +290,16 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {
void acpi_pci_add_bus(struct pci_bus *bus)
{
- acpi_handle handle = NULL;
-
- if (bus->bridge)
- handle = ACPI_HANDLE(bus->bridge);
- if (acpi_pci_disabled || handle == NULL)
+ if (acpi_pci_disabled || !bus->bridge)
return;
- acpi_pci_slot_enumerate(bus, handle);
- acpiphp_enumerate_slots(bus, handle);
+ acpi_pci_slot_enumerate(bus);
+ acpiphp_enumerate_slots(bus);
}
void acpi_pci_remove_bus(struct pci_bus *bus)
{
- /*
- * bus->bridge->acpi_node.handle has already been reset to NULL
- * when acpi_pci_remove_bus() is called, so don't check ACPI handle.
- */
- if (acpi_pci_disabled)
+ if (acpi_pci_disabled || !bus->bridge)
return;
acpiphp_remove_slots(bus);
@@ -317,13 +309,20 @@ void acpi_pci_remove_bus(struct pci_bus *bus)
/* ACPI bus type */
static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
{
- struct pci_dev * pci_dev;
- u64 addr;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ bool is_bridge;
+ u64 addr;
- pci_dev = to_pci_dev(dev);
+ /*
+ * pci_is_bridge() is not suitable here, because pci_dev->subordinate
+ * is set only after acpi_pci_find_device() has been called for the
+ * given device.
+ */
+ is_bridge = pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE
+ || pci_dev->hdr_type == PCI_HEADER_TYPE_CARDBUS;
/* Please ref to ACPI spec for the syntax of _ADR */
addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
- *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr);
+ *handle = acpi_find_child(ACPI_HANDLE(dev->parent), addr, is_bridge);
if (!*handle)
return -ENODEV;
return 0;
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index a82e70a4103..7958e59d607 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -14,15 +14,12 @@ config PCIEPORTBUS
# Include service Kconfig here
#
config HOTPLUG_PCI_PCIE
- tristate "PCI Express Hotplug driver"
+ bool "PCI Express Hotplug driver"
depends on HOTPLUG_PCI && PCIEPORTBUS
help
Say Y here if you have a motherboard that supports PCI Express Native
Hotplug
- To compile this driver as a module, choose M here: the
- module will be called pciehp.
-
When in doubt, say N.
source "drivers/pci/pcie/aer/Kconfig"
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 9be359594b0..bc26d7990cc 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -300,6 +300,47 @@ static void assign_requested_resources_sorted(struct list_head *head,
}
}
+static unsigned long pci_fail_res_type_mask(struct list_head *fail_head)
+{
+ struct pci_dev_resource *fail_res;
+ unsigned long mask = 0;
+
+ /* check failed type */
+ list_for_each_entry(fail_res, fail_head, list)
+ mask |= fail_res->flags;
+
+ /*
+ * one pref failed resource will set IORESOURCE_MEM,
+ * as we can allocate pref in non-pref range.
+ * Will release all assigned non-pref sibling resources
+ * according to that bit.
+ */
+ return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH);
+}
+
+static bool pci_need_to_release(unsigned long mask, struct resource *res)
+{
+ if (res->flags & IORESOURCE_IO)
+ return !!(mask & IORESOURCE_IO);
+
+ /* check pref at first */
+ if (res->flags & IORESOURCE_PREFETCH) {
+ if (mask & IORESOURCE_PREFETCH)
+ return true;
+ /* count pref if its parent is non-pref */
+ else if ((mask & IORESOURCE_MEM) &&
+ !(res->parent->flags & IORESOURCE_PREFETCH))
+ return true;
+ else
+ return false;
+ }
+
+ if (res->flags & IORESOURCE_MEM)
+ return !!(mask & IORESOURCE_MEM);
+
+ return false; /* should not get here */
+}
+
static void __assign_resources_sorted(struct list_head *head,
struct list_head *realloc_head,
struct list_head *fail_head)
@@ -312,11 +353,24 @@ static void __assign_resources_sorted(struct list_head *head,
* if could do that, could get out early.
* if could not do that, we still try to assign requested at first,
* then try to reassign add_size for some resources.
+ *
+ * Separate three resource type checking if we need to release
+ * assigned resource after requested + add_size try.
+ * 1. if there is io port assign fail, will release assigned
+ * io port.
+ * 2. if there is pref mmio assign fail, release assigned
+ * pref mmio.
+ * if assigned pref mmio's parent is non-pref mmio and there
+ * is non-pref mmio assign fail, will release that assigned
+ * pref mmio.
+ * 3. if there is non-pref mmio assign fail or pref mmio
+ * assigned fail, will release assigned non-pref mmio.
*/
LIST_HEAD(save_head);
LIST_HEAD(local_fail_head);
struct pci_dev_resource *save_res;
- struct pci_dev_resource *dev_res;
+ struct pci_dev_resource *dev_res, *tmp_res;
+ unsigned long fail_type;
/* Check if optional add_size is there */
if (!realloc_head || list_empty(realloc_head))
@@ -348,6 +402,19 @@ static void __assign_resources_sorted(struct list_head *head,
return;
}
+ /* check failed type */
+ fail_type = pci_fail_res_type_mask(&local_fail_head);
+ /* remove not need to be released assigned res from head list etc */
+ list_for_each_entry_safe(dev_res, tmp_res, head, list)
+ if (dev_res->res->parent &&
+ !pci_need_to_release(fail_type, dev_res->res)) {
+ /* remove it from realloc_head list */
+ remove_from_list(realloc_head, dev_res->res);
+ remove_from_list(&save_head, dev_res->res);
+ list_del(&dev_res->list);
+ kfree(dev_res);
+ }
+
free_list(&local_fail_head);
/* Release assigned resource */
list_for_each_entry(dev_res, head, list)
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 5b272bfd261..2a00239661b 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -1193,6 +1193,7 @@ void pinctrl_unregister_map(struct pinctrl_map const *map)
list_for_each_entry(maps_node, &pinctrl_maps, node) {
if (maps_node->maps == map) {
list_del(&maps_node->node);
+ kfree(maps_node);
mutex_unlock(&pinctrl_maps_mutex);
return;
}
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 6866548fab3..7323cca440b 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -1483,6 +1483,7 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
return ret;
}
+#ifdef CONFIG_PM
static int pinctrl_single_suspend(struct platform_device *pdev,
pm_message_t state)
{
@@ -1505,6 +1506,7 @@ static int pinctrl_single_resume(struct platform_device *pdev)
return pinctrl_force_default(pcs->pctl);
}
+#endif
static int pcs_probe(struct platform_device *pdev)
{
diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
index c47fd1e5450..94716c77980 100644
--- a/drivers/pinctrl/pinctrl-sunxi.c
+++ b/drivers/pinctrl/pinctrl-sunxi.c
@@ -278,6 +278,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
{
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct sunxi_pinctrl_group *g = &pctl->groups[group];
+ unsigned long flags;
u32 val, mask;
u16 strength;
u8 dlevel;
@@ -295,22 +296,35 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
* 3: 40mA
*/
dlevel = strength / 10 - 1;
+
+ spin_lock_irqsave(&pctl->lock, flags);
+
val = readl(pctl->membase + sunxi_dlevel_reg(g->pin));
mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin);
writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin),
pctl->membase + sunxi_dlevel_reg(g->pin));
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
break;
case PIN_CONFIG_BIAS_PULL_UP:
+ spin_lock_irqsave(&pctl->lock, flags);
+
val = readl(pctl->membase + sunxi_pull_reg(g->pin));
mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin),
pctl->membase + sunxi_pull_reg(g->pin));
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
+ spin_lock_irqsave(&pctl->lock, flags);
+
val = readl(pctl->membase + sunxi_pull_reg(g->pin));
mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin),
pctl->membase + sunxi_pull_reg(g->pin));
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
break;
default:
break;
@@ -360,11 +374,17 @@ static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
u8 config)
{
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ unsigned long flags;
+ u32 val, mask;
+
+ spin_lock_irqsave(&pctl->lock, flags);
- u32 val = readl(pctl->membase + sunxi_mux_reg(pin));
- u32 mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
+ val = readl(pctl->membase + sunxi_mux_reg(pin));
+ mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
writel((val & ~mask) | config << sunxi_mux_offset(pin),
pctl->membase + sunxi_mux_reg(pin));
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
}
static int sunxi_pmx_enable(struct pinctrl_dev *pctldev,
@@ -464,8 +484,21 @@ static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
u32 reg = sunxi_data_reg(offset);
u8 index = sunxi_data_offset(offset);
+ unsigned long flags;
+ u32 regval;
+
+ spin_lock_irqsave(&pctl->lock, flags);
+
+ regval = readl(pctl->membase + reg);
- writel((value & DATA_PINS_MASK) << index, pctl->membase + reg);
+ if (value)
+ regval |= BIT(index);
+ else
+ regval &= ~(BIT(index));
+
+ writel(regval, pctl->membase + reg);
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
}
static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
@@ -526,6 +559,8 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
u32 reg = sunxi_irq_cfg_reg(d->hwirq);
u8 index = sunxi_irq_cfg_offset(d->hwirq);
+ unsigned long flags;
+ u32 regval;
u8 mode;
switch (type) {
@@ -548,7 +583,13 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
return -EINVAL;
}
- writel((mode & IRQ_CFG_IRQ_MASK) << index, pctl->membase + reg);
+ spin_lock_irqsave(&pctl->lock, flags);
+
+ regval = readl(pctl->membase + reg);
+ regval &= ~IRQ_CFG_IRQ_MASK;
+ writel(regval | (mode << index), pctl->membase + reg);
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
return 0;
}
@@ -560,14 +601,19 @@ static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d)
u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq);
u32 status_reg = sunxi_irq_status_reg(d->hwirq);
u8 status_idx = sunxi_irq_status_offset(d->hwirq);
+ unsigned long flags;
u32 val;
+ spin_lock_irqsave(&pctl->lock, flags);
+
/* Mask the IRQ */
val = readl(pctl->membase + ctrl_reg);
writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg);
/* Clear the IRQ */
writel(1 << status_idx, pctl->membase + status_reg);
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
}
static void sunxi_pinctrl_irq_mask(struct irq_data *d)
@@ -575,11 +621,16 @@ static void sunxi_pinctrl_irq_mask(struct irq_data *d)
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
+ unsigned long flags;
u32 val;
+ spin_lock_irqsave(&pctl->lock, flags);
+
/* Mask the IRQ */
val = readl(pctl->membase + reg);
writel(val & ~(1 << idx), pctl->membase + reg);
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
}
static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
@@ -588,6 +639,7 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
struct sunxi_desc_function *func;
u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
+ unsigned long flags;
u32 val;
func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
@@ -597,9 +649,13 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
/* Change muxing to INT mode */
sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
+ spin_lock_irqsave(&pctl->lock, flags);
+
/* Unmask the IRQ */
val = readl(pctl->membase + reg);
writel(val | (1 << idx), pctl->membase + reg);
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
}
static struct irq_chip sunxi_pinctrl_irq_chip = {
@@ -752,6 +808,8 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, pctl);
+ spin_lock_init(&pctl->lock);
+
pctl->membase = of_iomap(node, 0);
if (!pctl->membase)
return -ENOMEM;
diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h
index d68047d8f69..01c494f8a14 100644
--- a/drivers/pinctrl/pinctrl-sunxi.h
+++ b/drivers/pinctrl/pinctrl-sunxi.h
@@ -14,6 +14,7 @@
#define __PINCTRL_SUNXI_H
#include <linux/kernel.h>
+#include <linux/spinlock.h>
#define PA_BASE 0
#define PB_BASE 32
@@ -407,6 +408,7 @@ struct sunxi_pinctrl {
unsigned ngroups;
int irq;
int irq_array[SUNXI_IRQ_NUMBER];
+ spinlock_t lock;
struct pinctrl_dev *pctl_dev;
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
index 7956df58d75..31f7d0e04aa 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
@@ -3785,6 +3785,7 @@ static const struct regulator_desc sh73a0_vccq_mc0_desc = {
static struct regulator_consumer_supply sh73a0_vccq_mc0_consumers[] = {
REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
+ REGULATOR_SUPPLY("vqmmc", "ee100000.sdhi"),
};
static const struct regulator_init_data sh73a0_vccq_mc0_init_data = {
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas6.c b/drivers/pinctrl/sirf/pinctrl-atlas6.c
index 1fa39a44417..867c9681763 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas6.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas6.c
@@ -496,7 +496,7 @@ static const unsigned sdmmc5_pins[] = { 24, 25, 26 };
static const struct sirfsoc_muxmask usp0_muxmask[] = {
{
.group = 1,
- .mask = BIT(19) | BIT(20) | BIT(21) | BIT(22),
+ .mask = BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23),
},
};
@@ -507,8 +507,21 @@ static const struct sirfsoc_padmux usp0_padmux = {
.funcval = 0,
};
-static const unsigned usp0_pins[] = { 51, 52, 53, 54 };
+static const unsigned usp0_pins[] = { 51, 52, 53, 54, 55 };
+static const struct sirfsoc_muxmask usp0_uart_nostreamctrl_muxmask[] = {
+ {
+ .group = 1,
+ .mask = BIT(20) | BIT(21),
+ },
+};
+
+static const struct sirfsoc_padmux usp0_uart_nostreamctrl_padmux = {
+ .muxmask_counts = ARRAY_SIZE(usp0_uart_nostreamctrl_muxmask),
+ .muxmask = usp0_uart_nostreamctrl_muxmask,
+};
+
+static const unsigned usp0_uart_nostreamctrl_pins[] = { 52, 53 };
static const struct sirfsoc_muxmask usp1_muxmask[] = {
{
.group = 0,
@@ -822,6 +835,8 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
SIRFSOC_PIN_GROUP("uart2grp", uart2_pins),
SIRFSOC_PIN_GROUP("uart2_nostreamctrlgrp", uart2_nostreamctrl_pins),
SIRFSOC_PIN_GROUP("usp0grp", usp0_pins),
+ SIRFSOC_PIN_GROUP("usp0_uart_nostreamctrl_grp",
+ usp0_uart_nostreamctrl_pins),
SIRFSOC_PIN_GROUP("usp1grp", usp1_pins),
SIRFSOC_PIN_GROUP("i2c0grp", i2c0_pins),
SIRFSOC_PIN_GROUP("i2c1grp", i2c1_pins),
@@ -862,6 +877,8 @@ static const char * const uart0grp[] = { "uart0grp" };
static const char * const uart1grp[] = { "uart1grp" };
static const char * const uart2grp[] = { "uart2grp" };
static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" };
+static const char * const usp0_uart_nostreamctrl_grp[] = {
+ "usp0_uart_nostreamctrl_grp" };
static const char * const usp0grp[] = { "usp0grp" };
static const char * const usp1grp[] = { "usp1grp" };
static const char * const i2c0grp[] = { "i2c0grp" };
@@ -904,6 +921,9 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = {
SIRFSOC_PMX_FUNCTION("uart2", uart2grp, uart2_padmux),
SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux),
SIRFSOC_PMX_FUNCTION("usp0", usp0grp, usp0_padmux),
+ SIRFSOC_PMX_FUNCTION("usp0_uart_nostreamctrl",
+ usp0_uart_nostreamctrl_grp,
+ usp0_uart_nostreamctrl_padmux),
SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux),
SIRFSOC_PMX_FUNCTION("i2c0", i2c0grp, i2c0_padmux),
SIRFSOC_PMX_FUNCTION("i2c1", i2c1grp, i2c1_padmux),
diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c
index 0f9f8596b30..f9119525f55 100644
--- a/drivers/platform/olpc/olpc-ec.c
+++ b/drivers/platform/olpc/olpc-ec.c
@@ -330,7 +330,7 @@ static int __init olpc_ec_init_module(void)
return platform_driver_register(&olpc_ec_plat_driver);
}
-module_init(olpc_ec_init_module);
+arch_initcall(olpc_ec_init_module);
MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 8e268da6fdb..0e9c169b42f 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -1543,7 +1543,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
/* TODO Find a better way to handle events count. */
count = asus->event_count[event % 128]++;
- acpi_bus_generate_proc_event(asus->device, event, count);
acpi_bus_generate_netlink_event(asus->device->pnp.device_class,
dev_name(&asus->device->dev), event,
count);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 5d26e70bed6..a6afd4108be 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1269,7 +1269,6 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
if (event > ACPI_MAX_SYS_NOTIFY)
return;
count = eeepc->event_count[event % 128]++;
- acpi_bus_generate_proc_event(device, event, count);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
count);
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 1c9386e7c58..52b8a97efde 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -773,8 +773,6 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event)
else
set_lcd_level(newb);
}
- acpi_bus_generate_proc_event(fujitsu->dev,
- ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0);
keycode = KEY_BRIGHTNESSUP;
} else if (oldb > newb) {
if (disable_brightness_adjust != 1) {
@@ -783,8 +781,6 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event)
else
set_lcd_level(newb);
}
- acpi_bus_generate_proc_event(fujitsu->dev,
- ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0);
keycode = KEY_BRIGHTNESSDOWN;
}
break;
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 97bb05edcb5..d6970f47ae7 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -53,7 +53,6 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
#define HPWMI_ALS_QUERY 0x3
#define HPWMI_HARDWARE_QUERY 0x4
#define HPWMI_WIRELESS_QUERY 0x5
-#define HPWMI_BIOS_QUERY 0x9
#define HPWMI_HOTKEY_QUERY 0xc
#define HPWMI_WIRELESS2_QUERY 0x1b
#define HPWMI_POSTCODEERROR_QUERY 0x2a
@@ -293,19 +292,6 @@ static int hp_wmi_tablet_state(void)
return (state & 0x4) ? 1 : 0;
}
-static int hp_wmi_enable_hotkeys(void)
-{
- int ret;
- int query = 0x6e;
-
- ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query),
- 0);
-
- if (ret)
- return -EINVAL;
- return 0;
-}
-
static int hp_wmi_set_block(void *data, bool blocked)
{
enum hp_wmi_radio r = (enum hp_wmi_radio) data;
@@ -1009,8 +995,6 @@ static int __init hp_wmi_init(void)
err = hp_wmi_input_setup();
if (err)
return err;
-
- hp_wmi_enable_hotkeys();
}
if (bios_capable) {
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 4add9a31bf6..984253da365 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -464,9 +464,6 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
"error getting hotkey status\n"));
return;
}
-
- acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
-
if (!sparse_keymap_report_event(hotk_input_dev,
result & 0xf, result & 0x80, false))
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 2ac045f27f1..d3fd52036fd 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1275,9 +1275,6 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
ev_type = HOTKEY;
sony_laptop_report_input_event(real_ev);
}
-
- acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev);
-
acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class,
dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev);
}
@@ -2440,7 +2437,10 @@ static ssize_t sony_nc_gfx_switch_status_show(struct device *dev,
if (pos < 0)
return pos;
- return snprintf(buffer, PAGE_SIZE, "%s\n", pos ? "speed" : "stamina");
+ return snprintf(buffer, PAGE_SIZE, "%s\n",
+ pos == SPEED ? "speed" :
+ pos == STAMINA ? "stamina" :
+ pos == AUTO ? "auto" : "unknown");
}
static int sony_nc_gfx_switch_setup(struct platform_device *pd,
@@ -4243,7 +4243,6 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
found:
sony_laptop_report_input_event(device_event);
- acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
sonypi_compat_report_event(device_event);
return IRQ_HANDLED;
}
@@ -4320,7 +4319,8 @@ static int sony_pic_add(struct acpi_device *device)
goto err_free_resources;
}
- if (sonypi_compat_init())
+ result = sonypi_compat_init();
+ if (result)
goto err_remove_input;
/* request io port */
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 54d31c0a984..be67e5e28d1 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -2022,8 +2022,6 @@ static u32 hotkey_driver_mask; /* events needed by the driver */
static u32 hotkey_user_mask; /* events visible to userspace */
static u32 hotkey_acpi_mask; /* events enabled in firmware */
-static unsigned int hotkey_report_mode;
-
static u16 *hotkey_keycode_map;
static struct attribute_set *hotkey_dev_attributes;
@@ -2282,10 +2280,6 @@ static struct tp_acpi_drv_struct ibm_hotkey_acpidriver;
static void tpacpi_hotkey_send_key(unsigned int scancode)
{
tpacpi_input_send_key_masked(scancode);
- if (hotkey_report_mode < 2) {
- acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device,
- 0x80, TP_HKEY_EV_HOTKEY_BASE + scancode);
- }
}
static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m)
@@ -2882,18 +2876,6 @@ static void hotkey_tablet_mode_notify_change(void)
"hotkey_tablet_mode");
}
-/* sysfs hotkey report_mode -------------------------------------------- */
-static ssize_t hotkey_report_mode_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n",
- (hotkey_report_mode != 0) ? hotkey_report_mode : 1);
-}
-
-static struct device_attribute dev_attr_hotkey_report_mode =
- __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
-
/* sysfs wakeup reason (pollable) -------------------------------------- */
static ssize_t hotkey_wakeup_reason_show(struct device *dev,
struct device_attribute *attr,
@@ -2935,7 +2917,6 @@ static struct attribute *hotkey_attributes[] __initdata = {
&dev_attr_hotkey_enable.attr,
&dev_attr_hotkey_bios_enabled.attr,
&dev_attr_hotkey_bios_mask.attr,
- &dev_attr_hotkey_report_mode.attr,
&dev_attr_hotkey_wakeup_reason.attr,
&dev_attr_hotkey_wakeup_hotunplug_complete.attr,
&dev_attr_hotkey_mask.attr,
@@ -3439,11 +3420,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
"initial masks: user=0x%08x, fw=0x%08x, poll=0x%08x\n",
hotkey_user_mask, hotkey_acpi_mask, hotkey_source_mask);
- dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
- "legacy ibm/hotkey event reporting over procfs %s\n",
- (hotkey_report_mode < 2) ?
- "enabled" : "disabled");
-
tpacpi_inputdev->open = &hotkey_inputdev_open;
tpacpi_inputdev->close = &hotkey_inputdev_close;
@@ -3737,13 +3713,6 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
"event happened to %s\n", TPACPI_MAIL);
}
- /* Legacy events */
- if (!ignore_acpi_ev &&
- (send_acpi_ev || hotkey_report_mode < 2)) {
- acpi_bus_generate_proc_event(ibm->acpi->device,
- event, hkey);
- }
-
/* netlink events */
if (!ignore_acpi_ev && send_acpi_ev) {
acpi_bus_generate_netlink_event(
@@ -8840,11 +8809,6 @@ module_param(brightness_enable, uint, 0444);
MODULE_PARM_DESC(brightness_enable,
"Enables backlight control when 1, disables when 0");
-module_param(hotkey_report_mode, uint, 0444);
-MODULE_PARM_DESC(hotkey_report_mode,
- "used for backwards compatibility with userspace, "
- "see documentation");
-
#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
module_param_named(volume_mode, volume_mode, uint, 0444);
MODULE_PARM_DESC(volume_mode,
@@ -8975,10 +8939,6 @@ static int __init thinkpad_acpi_module_init(void)
tpacpi_lifecycle = TPACPI_LIFE_INIT;
- /* Parameter checking */
- if (hotkey_report_mode > 2)
- return -EINVAL;
-
/* Driver-level probe */
ret = get_thinkpad_model_data(&thinkpad_id);
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index b13344c5980..6e02c953d88 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -693,11 +693,13 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "wmi:%s\n", guid_string);
}
+static DEVICE_ATTR_RO(modalias);
-static struct device_attribute wmi_dev_attrs[] = {
- __ATTR_RO(modalias),
- __ATTR_NULL
+static struct attribute *wmi_attrs[] = {
+ &dev_attr_modalias.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(wmi);
static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{
@@ -732,7 +734,7 @@ static struct class wmi_class = {
.name = "wmi",
.dev_release = wmi_dev_free,
.dev_uevent = wmi_dev_uevent,
- .dev_attrs = wmi_dev_attrs,
+ .dev_groups = wmi_groups,
};
static int wmi_create_device(const struct guid_block *gblock,
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index 00e94032531..12adb43a069 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -154,7 +154,7 @@ static int pnp_bus_match(struct device *dev, struct device_driver *drv)
return 1;
}
-static int pnp_bus_suspend(struct device *dev, pm_message_t state)
+static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
{
struct pnp_dev *pnp_dev = to_pnp_dev(dev);
struct pnp_driver *pnp_drv = pnp_dev->driver;
@@ -180,6 +180,16 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state)
return 0;
}
+static int pnp_bus_suspend(struct device *dev)
+{
+ return __pnp_bus_suspend(dev, PMSG_SUSPEND);
+}
+
+static int pnp_bus_freeze(struct device *dev)
+{
+ return __pnp_bus_suspend(dev, PMSG_FREEZE);
+}
+
static int pnp_bus_resume(struct device *dev)
{
struct pnp_dev *pnp_dev = to_pnp_dev(dev);
@@ -210,14 +220,19 @@ static int pnp_bus_resume(struct device *dev)
return 0;
}
+static const struct dev_pm_ops pnp_bus_dev_pm_ops = {
+ .suspend = pnp_bus_suspend,
+ .freeze = pnp_bus_freeze,
+ .resume = pnp_bus_resume,
+};
+
struct bus_type pnp_bus_type = {
.name = "pnp",
.match = pnp_bus_match,
.probe = pnp_device_probe,
.remove = pnp_device_remove,
.shutdown = pnp_device_shutdown,
- .suspend = pnp_bus_suspend,
- .resume = pnp_bus_resume,
+ .pm = &pnp_bus_dev_pm_ops,
.dev_attrs = pnp_interface_attrs,
};
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 55cd459a390..34049b0b4c7 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -131,7 +131,7 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
/* acpi_unregister_gsi(pnp_irq(dev, 0)); */
ret = 0;
if (acpi_bus_power_manageable(handle))
- acpi_bus_set_power(handle, ACPI_STATE_D3);
+ acpi_bus_set_power(handle, ACPI_STATE_D3_COLD);
/* continue even if acpi_bus_set_power() fails */
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DIS", NULL, NULL)))
ret = -ENODEV;
@@ -174,10 +174,10 @@ static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
if (acpi_bus_power_manageable(handle)) {
int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL,
- ACPI_STATE_D3);
+ ACPI_STATE_D3_COLD);
if (power_state < 0)
power_state = (state.event == PM_EVENT_ON) ?
- ACPI_STATE_D0 : ACPI_STATE_D3;
+ ACPI_STATE_D0 : ACPI_STATE_D3_COLD;
/*
* acpi_bus_set_power() often fails (keyboard port can't be
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 7173e3ad475..2f07cd61566 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -406,7 +406,7 @@ static int __init pps_init(void)
pr_err("failed to allocate class\n");
return PTR_ERR(pps_class);
}
- pps_class->dev_attrs = pps_attrs;
+ pps_class->dev_groups = pps_groups;
err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");
if (err < 0) {
diff --git a/drivers/pps/sysfs.c b/drivers/pps/sysfs.c
index ef0978c71ee..aefb75d6709 100644
--- a/drivers/pps/sysfs.c
+++ b/drivers/pps/sysfs.c
@@ -29,8 +29,8 @@
* Attribute functions
*/
-static ssize_t pps_show_assert(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t assert_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pps_device *pps = dev_get_drvdata(dev);
@@ -41,9 +41,10 @@ static ssize_t pps_show_assert(struct device *dev,
(long long) pps->assert_tu.sec, pps->assert_tu.nsec,
pps->assert_sequence);
}
+static DEVICE_ATTR_RO(assert);
-static ssize_t pps_show_clear(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t clear_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pps_device *pps = dev_get_drvdata(dev);
@@ -54,45 +55,59 @@ static ssize_t pps_show_clear(struct device *dev,
(long long) pps->clear_tu.sec, pps->clear_tu.nsec,
pps->clear_sequence);
}
+static DEVICE_ATTR_RO(clear);
-static ssize_t pps_show_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pps_device *pps = dev_get_drvdata(dev);
return sprintf(buf, "%4x\n", pps->info.mode);
}
+static DEVICE_ATTR_RO(mode);
-static ssize_t pps_show_echo(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t echo_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pps_device *pps = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", !!pps->info.echo);
}
+static DEVICE_ATTR_RO(echo);
-static ssize_t pps_show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pps_device *pps = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", pps->info.name);
}
+static DEVICE_ATTR_RO(name);
-static ssize_t pps_show_path(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t path_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pps_device *pps = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", pps->info.path);
}
+static DEVICE_ATTR_RO(path);
+
+static struct attribute *pps_attrs[] = {
+ &dev_attr_assert.attr,
+ &dev_attr_clear.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_echo.attr,
+ &dev_attr_name.attr,
+ &dev_attr_path.attr,
+ NULL,
+};
+
+static const struct attribute_group pps_group = {
+ .attrs = pps_attrs,
+};
-struct device_attribute pps_attrs[] = {
- __ATTR(assert, S_IRUGO, pps_show_assert, NULL),
- __ATTR(clear, S_IRUGO, pps_show_clear, NULL),
- __ATTR(mode, S_IRUGO, pps_show_mode, NULL),
- __ATTR(echo, S_IRUGO, pps_show_echo, NULL),
- __ATTR(name, S_IRUGO, pps_show_name, NULL),
- __ATTR(path, S_IRUGO, pps_show_path, NULL),
- __ATTR_NULL,
+const struct attribute_group *pps_groups[] = {
+ &pps_group,
+ NULL,
};
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 4a8c388364c..a8319b26664 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -330,7 +330,7 @@ static int __init ptp_init(void)
goto no_region;
}
- ptp_class->dev_attrs = ptp_dev_attrs;
+ ptp_class->dev_groups = ptp_groups;
pr_info("PTP clock support registered\n");
return 0;
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
index 69d32070cc6..df03f2e30ad 100644
--- a/drivers/ptp/ptp_private.h
+++ b/drivers/ptp/ptp_private.h
@@ -84,7 +84,7 @@ uint ptp_poll(struct posix_clock *pc,
* see ptp_sysfs.c
*/
-extern struct device_attribute ptp_dev_attrs[];
+extern const struct attribute_group *ptp_groups[];
int ptp_cleanup_sysfs(struct ptp_clock *ptp);
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
index 2f93926ac97..13ec5311746 100644
--- a/drivers/ptp/ptp_sysfs.c
+++ b/drivers/ptp/ptp_sysfs.c
@@ -27,36 +27,43 @@ static ssize_t clock_name_show(struct device *dev,
struct ptp_clock *ptp = dev_get_drvdata(dev);
return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name);
}
+static DEVICE_ATTR(clock_name, 0444, clock_name_show, NULL);
-#define PTP_SHOW_INT(name) \
-static ssize_t name##_show(struct device *dev, \
+#define PTP_SHOW_INT(name, var) \
+static ssize_t var##_show(struct device *dev, \
struct device_attribute *attr, char *page) \
{ \
struct ptp_clock *ptp = dev_get_drvdata(dev); \
- return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->name); \
-}
-
-PTP_SHOW_INT(max_adj);
-PTP_SHOW_INT(n_alarm);
-PTP_SHOW_INT(n_ext_ts);
-PTP_SHOW_INT(n_per_out);
-PTP_SHOW_INT(pps);
+ return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->var); \
+} \
+static DEVICE_ATTR(name, 0444, var##_show, NULL);
+
+PTP_SHOW_INT(max_adjustment, max_adj);
+PTP_SHOW_INT(n_alarms, n_alarm);
+PTP_SHOW_INT(n_external_timestamps, n_ext_ts);
+PTP_SHOW_INT(n_periodic_outputs, n_per_out);
+PTP_SHOW_INT(pps_available, pps);
+
+static struct attribute *ptp_attrs[] = {
+ &dev_attr_clock_name.attr,
+ &dev_attr_max_adjustment.attr,
+ &dev_attr_n_alarms.attr,
+ &dev_attr_n_external_timestamps.attr,
+ &dev_attr_n_periodic_outputs.attr,
+ &dev_attr_pps_available.attr,
+ NULL,
+};
-#define PTP_RO_ATTR(_var, _name) { \
- .attr = { .name = __stringify(_name), .mode = 0444 }, \
- .show = _var##_show, \
-}
+static const struct attribute_group ptp_group = {
+ .attrs = ptp_attrs,
+};
-struct device_attribute ptp_dev_attrs[] = {
- PTP_RO_ATTR(clock_name, clock_name),
- PTP_RO_ATTR(max_adj, max_adjustment),
- PTP_RO_ATTR(n_alarm, n_alarms),
- PTP_RO_ATTR(n_ext_ts, n_external_timestamps),
- PTP_RO_ATTR(n_per_out, n_periodic_outputs),
- PTP_RO_ATTR(pps, pps_available),
- __ATTR_NULL,
+const struct attribute_group *ptp_groups[] = {
+ &ptp_group,
+ NULL,
};
+
static ssize_t extts_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index f4f30af2df6..2e8a20cac58 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -1715,11 +1715,13 @@ int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops)
(mport_id == RIO_MPORT_ANY && port->nscan == scan_ops))
port->nscan = NULL;
- list_for_each_entry(scan, &rio_scans, node)
+ list_for_each_entry(scan, &rio_scans, node) {
if (scan->mport_id == mport_id) {
list_del(&scan->node);
kfree(scan);
+ break;
}
+ }
mutex_unlock(&rio_mport_list_lock);
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c
new file mode 100644
index 00000000000..3459f60dcfd
--- /dev/null
+++ b/drivers/regulator/88pm800.c
@@ -0,0 +1,383 @@
+/*
+ * Regulators driver for Marvell 88PM800
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ * Joseph(Yossi) Hanin <yhanin@marvell.com>
+ * Yi Zhang <yizhang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/88pm80x.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
+
+/* LDO1 with DVC[0..3] */
+#define PM800_LDO1_VOUT (0x08) /* VOUT1 */
+#define PM800_LDO1_VOUT_2 (0x09)
+#define PM800_LDO1_VOUT_3 (0x0A)
+#define PM800_LDO2_VOUT (0x0B)
+#define PM800_LDO3_VOUT (0x0C)
+#define PM800_LDO4_VOUT (0x0D)
+#define PM800_LDO5_VOUT (0x0E)
+#define PM800_LDO6_VOUT (0x0F)
+#define PM800_LDO7_VOUT (0x10)
+#define PM800_LDO8_VOUT (0x11)
+#define PM800_LDO9_VOUT (0x12)
+#define PM800_LDO10_VOUT (0x13)
+#define PM800_LDO11_VOUT (0x14)
+#define PM800_LDO12_VOUT (0x15)
+#define PM800_LDO13_VOUT (0x16)
+#define PM800_LDO14_VOUT (0x17)
+#define PM800_LDO15_VOUT (0x18)
+#define PM800_LDO16_VOUT (0x19)
+#define PM800_LDO17_VOUT (0x1A)
+#define PM800_LDO18_VOUT (0x1B)
+#define PM800_LDO19_VOUT (0x1C)
+
+/* BUCK1 with DVC[0..3] */
+#define PM800_BUCK1 (0x3C)
+#define PM800_BUCK1_1 (0x3D)
+#define PM800_BUCK1_2 (0x3E)
+#define PM800_BUCK1_3 (0x3F)
+#define PM800_BUCK2 (0x40)
+#define PM800_BUCK3 (0x41)
+#define PM800_BUCK3 (0x41)
+#define PM800_BUCK4 (0x42)
+#define PM800_BUCK4_1 (0x43)
+#define PM800_BUCK4_2 (0x44)
+#define PM800_BUCK4_3 (0x45)
+#define PM800_BUCK5 (0x46)
+
+#define PM800_BUCK_ENA (0x50)
+#define PM800_LDO_ENA1_1 (0x51)
+#define PM800_LDO_ENA1_2 (0x52)
+#define PM800_LDO_ENA1_3 (0x53)
+
+#define PM800_LDO_ENA2_1 (0x56)
+#define PM800_LDO_ENA2_2 (0x57)
+#define PM800_LDO_ENA2_3 (0x58)
+
+#define PM800_BUCK1_MISC1 (0x78)
+#define PM800_BUCK3_MISC1 (0x7E)
+#define PM800_BUCK4_MISC1 (0x81)
+#define PM800_BUCK5_MISC1 (0x84)
+
+struct pm800_regulator_info {
+ struct regulator_desc desc;
+ int max_ua;
+};
+
+struct pm800_regulators {
+ struct regulator_dev *regulators[PM800_ID_RG_MAX];
+ struct pm80x_chip *chip;
+ struct regmap *map;
+};
+
+/*
+ * vreg - the buck regs string.
+ * ereg - the string for the enable register.
+ * ebit - the bit number in the enable register.
+ * amax - the current
+ * Buck has 2 kinds of voltage steps. It is easy to find voltage by ranges,
+ * not the constant voltage table.
+ * n_volt - Number of available selectors
+ */
+#define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges, n_volt) \
+{ \
+ .desc = { \
+ .name = #vreg, \
+ .ops = &pm800_volt_range_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = PM800_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = n_volt, \
+ .linear_ranges = volt_ranges, \
+ .n_linear_ranges = ARRAY_SIZE(volt_ranges), \
+ .vsel_reg = PM800_##vreg, \
+ .vsel_mask = 0x7f, \
+ .enable_reg = PM800_##ereg, \
+ .enable_mask = 1 << (ebit), \
+ }, \
+ .max_ua = (amax), \
+}
+
+/*
+ * vreg - the LDO regs string
+ * ereg - the string for the enable register.
+ * ebit - the bit number in the enable register.
+ * amax - the current
+ * volt_table - the LDO voltage table
+ * For all the LDOes, there are too many ranges. Using volt_table will be
+ * simpler and faster.
+ */
+#define PM800_LDO(vreg, ereg, ebit, amax, ldo_volt_table) \
+{ \
+ .desc = { \
+ .name = #vreg, \
+ .ops = &pm800_volt_table_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = PM800_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(ldo_volt_table), \
+ .vsel_reg = PM800_##vreg##_VOUT, \
+ .vsel_mask = 0x1f, \
+ .enable_reg = PM800_##ereg, \
+ .enable_mask = 1 << (ebit), \
+ .volt_table = ldo_volt_table, \
+ }, \
+ .max_ua = (amax), \
+}
+
+/* Ranges are sorted in ascending order. */
+static const struct regulator_linear_range buck1_volt_range[] = {
+ { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f,
+ .uV_step = 12500 },
+ { .min_uV = 1600000, .max_uV = 1800000, .min_sel = 0x50,
+ .max_sel = 0x54, .uV_step = 50000 },
+};
+
+/* BUCK 2~5 have same ranges. */
+static const struct regulator_linear_range buck2_5_volt_range[] = {
+ { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f,
+ .uV_step = 12500 },
+ { .min_uV = 1600000, .max_uV = 3300000, .min_sel = 0x50,
+ .max_sel = 0x72, .uV_step = 50000 },
+};
+
+static const unsigned int ldo1_volt_table[] = {
+ 600000, 650000, 700000, 750000, 800000, 850000, 900000, 950000,
+ 1000000, 1050000, 1100000, 1150000, 1200000, 1300000, 1400000, 1500000,
+};
+
+static const unsigned int ldo2_volt_table[] = {
+ 1700000, 1800000, 1900000, 2000000, 2100000, 2500000, 2700000, 2800000,
+};
+
+/* LDO 3~17 have same voltage table. */
+static const unsigned int ldo3_17_volt_table[] = {
+ 1200000, 1250000, 1700000, 1800000, 1850000, 1900000, 2500000, 2600000,
+ 2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
+};
+
+/* LDO 18~19 have same voltage table. */
+static const unsigned int ldo18_19_volt_table[] = {
+ 1700000, 1800000, 1900000, 2500000, 2800000, 2900000, 3100000, 3300000,
+};
+
+static int pm800_get_current_limit(struct regulator_dev *rdev)
+{
+ struct pm800_regulator_info *info = rdev_get_drvdata(rdev);
+
+ return info->max_ua;
+}
+
+static struct regulator_ops pm800_volt_range_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_current_limit = pm800_get_current_limit,
+};
+
+static struct regulator_ops pm800_volt_table_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_iterate,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_current_limit = pm800_get_current_limit,
+};
+
+/* The array is indexed by id(PM800_ID_XXX) */
+static struct pm800_regulator_info pm800_regulator_info[] = {
+ PM800_BUCK(BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range, 0x55),
+ PM800_BUCK(BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range, 0x73),
+ PM800_BUCK(BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range, 0x73),
+ PM800_BUCK(BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range, 0x73),
+ PM800_BUCK(BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range, 0x73),
+
+ PM800_LDO(LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table),
+ PM800_LDO(LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table),
+ PM800_LDO(LDO3, LDO_ENA1_1, 2, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO4, LDO_ENA1_1, 3, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO5, LDO_ENA1_1, 4, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO6, LDO_ENA1_1, 5, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO7, LDO_ENA1_1, 6, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO8, LDO_ENA1_1, 7, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO9, LDO_ENA1_2, 0, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO10, LDO_ENA1_2, 1, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO11, LDO_ENA1_2, 2, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO12, LDO_ENA1_2, 3, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO13, LDO_ENA1_2, 4, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO14, LDO_ENA1_2, 5, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO15, LDO_ENA1_2, 6, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO16, LDO_ENA1_2, 7, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO17, LDO_ENA1_3, 0, 300000, ldo3_17_volt_table),
+ PM800_LDO(LDO18, LDO_ENA1_3, 1, 200000, ldo18_19_volt_table),
+ PM800_LDO(LDO19, LDO_ENA1_3, 2, 200000, ldo18_19_volt_table),
+};
+
+#define PM800_REGULATOR_OF_MATCH(_name, _id) \
+ [PM800_ID_##_id] = { \
+ .name = #_name, \
+ .driver_data = &pm800_regulator_info[PM800_ID_##_id], \
+ }
+
+static struct of_regulator_match pm800_regulator_matches[] = {
+ PM800_REGULATOR_OF_MATCH(buck1, BUCK1),
+ PM800_REGULATOR_OF_MATCH(buck2, BUCK2),
+ PM800_REGULATOR_OF_MATCH(buck3, BUCK3),
+ PM800_REGULATOR_OF_MATCH(buck4, BUCK4),
+ PM800_REGULATOR_OF_MATCH(buck5, BUCK5),
+ PM800_REGULATOR_OF_MATCH(ldo1, LDO1),
+ PM800_REGULATOR_OF_MATCH(ldo2, LDO2),
+ PM800_REGULATOR_OF_MATCH(ldo3, LDO3),
+ PM800_REGULATOR_OF_MATCH(ldo4, LDO4),
+ PM800_REGULATOR_OF_MATCH(ldo5, LDO5),
+ PM800_REGULATOR_OF_MATCH(ldo6, LDO6),
+ PM800_REGULATOR_OF_MATCH(ldo7, LDO7),
+ PM800_REGULATOR_OF_MATCH(ldo8, LDO8),
+ PM800_REGULATOR_OF_MATCH(ldo9, LDO9),
+ PM800_REGULATOR_OF_MATCH(ldo10, LDO10),
+ PM800_REGULATOR_OF_MATCH(ldo11, LDO11),
+ PM800_REGULATOR_OF_MATCH(ldo12, LDO12),
+ PM800_REGULATOR_OF_MATCH(ldo13, LDO13),
+ PM800_REGULATOR_OF_MATCH(ldo14, LDO14),
+ PM800_REGULATOR_OF_MATCH(ldo15, LDO15),
+ PM800_REGULATOR_OF_MATCH(ldo16, LDO16),
+ PM800_REGULATOR_OF_MATCH(ldo17, LDO17),
+ PM800_REGULATOR_OF_MATCH(ldo18, LDO18),
+ PM800_REGULATOR_OF_MATCH(ldo19, LDO19),
+};
+
+static int pm800_regulator_dt_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int ret;
+
+ ret = of_regulator_match(&pdev->dev, np,
+ pm800_regulator_matches,
+ ARRAY_SIZE(pm800_regulator_matches));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int pm800_regulator_probe(struct platform_device *pdev)
+{
+ struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm80x_platform_data *pdata = dev_get_platdata(pdev->dev.parent);
+ struct pm800_regulators *pm800_data;
+ struct pm800_regulator_info *info;
+ struct regulator_config config = { };
+ struct regulator_init_data *init_data;
+ int i, ret;
+
+ if (!pdata || pdata->num_regulators == 0) {
+ if (IS_ENABLED(CONFIG_OF)) {
+ ret = pm800_regulator_dt_init(pdev);
+ if (ret)
+ return ret;
+ } else {
+ return -ENODEV;
+ }
+ } else if (pdata->num_regulators) {
+ unsigned int count = 0;
+
+ /* Check whether num_regulator is valid. */
+ for (i = 0; i < ARRAY_SIZE(pdata->regulators); i++) {
+ if (pdata->regulators[i])
+ count++;
+ }
+ if (count != pdata->num_regulators)
+ return -EINVAL;
+ } else {
+ return -EINVAL;
+ }
+
+ pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data),
+ GFP_KERNEL);
+ if (!pm800_data) {
+ dev_err(&pdev->dev, "Failed to allocate pm800_regualtors");
+ return -ENOMEM;
+ }
+
+ pm800_data->map = chip->subchip->regmap_power;
+ pm800_data->chip = chip;
+
+ platform_set_drvdata(pdev, pm800_data);
+
+ for (i = 0; i < PM800_ID_RG_MAX; i++) {
+ if (!pdata || pdata->num_regulators == 0)
+ init_data = pm800_regulator_matches[i].init_data;
+ else
+ init_data = pdata->regulators[i];
+ if (!init_data)
+ continue;
+ info = pm800_regulator_matches[i].driver_data;
+ config.dev = &pdev->dev;
+ config.init_data = init_data;
+ config.driver_data = info;
+ config.regmap = pm800_data->map;
+ config.of_node = pm800_regulator_matches[i].of_node;
+
+ pm800_data->regulators[i] =
+ regulator_register(&info->desc, &config);
+ if (IS_ERR(pm800_data->regulators[i])) {
+ ret = PTR_ERR(pm800_data->regulators[i]);
+ dev_err(&pdev->dev, "Failed to register %s\n",
+ info->desc.name);
+
+ while (--i >= 0)
+ regulator_unregister(pm800_data->regulators[i]);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int pm800_regulator_remove(struct platform_device *pdev)
+{
+ struct pm800_regulators *pm800_data = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < PM800_ID_RG_MAX; i++)
+ regulator_unregister(pm800_data->regulators[i]);
+
+ return 0;
+}
+
+static struct platform_driver pm800_regulator_driver = {
+ .driver = {
+ .name = "88pm80x-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm800_regulator_probe,
+ .remove = pm800_regulator_remove,
+};
+
+module_platform_driver(pm800_regulator_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Joseph(Yossi) Hanin <yhanin@marvell.com>");
+MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM800 PMIC");
+MODULE_ALIAS("platform:88pm800-regulator");
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 8a7cb1f4304..70230974468 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -346,7 +346,7 @@ static int pm8607_regulator_probe(struct platform_device *pdev)
{
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct pm8607_regulator_info *info = NULL;
- struct regulator_init_data *pdata = pdev->dev.platform_data;
+ struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev);
struct regulator_config config = { };
struct resource *res;
int i;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index f1e6ad98eeb..dfe58096b37 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -64,15 +64,21 @@ config REGULATOR_USERSPACE_CONSUMER
If unsure, say no.
-config REGULATOR_GPIO
- tristate "GPIO regulator support"
- depends on GPIOLIB
+config REGULATOR_88PM800
+ tristate "Marvell 88PM800 Power regulators"
+ depends on MFD_88PM800
help
- This driver provides support for regulators that can be
- controlled via gpios.
- It is capable of supporting current and voltage regulators
- and the platform has to provide a mapping of GPIO-states
- to target volts/amps.
+ This driver supports Marvell 88PM800 voltage regulator chips.
+ It delivers digitally programmable output,
+ the voltage is programmed via I2C interface.
+ It's suitable to support PXA988 chips to control VCC_MAIN and
+ various voltages.
+
+config REGULATOR_88PM8607
+ tristate "Marvell 88PM8607 Power regulators"
+ depends on MFD_88PM860X=y
+ help
+ This driver supports 88PM8607 voltage regulator chips.
config REGULATOR_AD5398
tristate "Analog Devices AD5398/AD5821 regulators"
@@ -81,6 +87,14 @@ config REGULATOR_AD5398
This driver supports AD5398 and AD5821 current regulator chips.
If building into module, its name is ad5398.ko.
+config REGULATOR_ANATOP
+ tristate "Freescale i.MX on-chip ANATOP LDO regulators"
+ depends on MFD_SYSCON
+ help
+ Say y here to support Freescale i.MX on-chip ANATOP LDOs
+ regulators. It is recommended that this option be
+ enabled on i.MX6 platform.
+
config REGULATOR_AAT2870
tristate "AnalogicTech AAT2870 Regulators"
depends on MFD_AAT2870_CORE
@@ -88,6 +102,22 @@ config REGULATOR_AAT2870
If you have a AnalogicTech AAT2870 say Y to enable the
regulator driver.
+config REGULATOR_AB3100
+ tristate "ST-Ericsson AB3100 Regulator functions"
+ depends on AB3100_CORE
+ default y if AB3100_CORE
+ help
+ These regulators correspond to functionality in the
+ AB3100 analog baseband dealing with power regulators
+ for the system.
+
+config REGULATOR_AB8500
+ bool "ST-Ericsson AB8500 Power Regulators"
+ depends on AB8500_CORE
+ help
+ This driver supports the regulators found on the ST-Ericsson mixed
+ signal AB8500 PMIC
+
config REGULATOR_ARIZONA
tristate "Wolfson Arizona class devices"
depends on MFD_ARIZONA
@@ -96,6 +126,13 @@ config REGULATOR_ARIZONA
Support for the regulators found on Wolfson Arizona class
devices.
+config REGULATOR_AS3711
+ tristate "AS3711 PMIC"
+ depends on MFD_AS3711
+ help
+ This driver provides support for the voltage regulators on the
+ AS3711 PMIC
+
config REGULATOR_DA903X
tristate "Dialog Semiconductor DA9030/DA9034 regulators"
depends on PMIC_DA903X
@@ -120,6 +157,37 @@ config REGULATOR_DA9055
This driver can also be built as a module. If so, the module
will be called da9055-regulator.
+config REGULATOR_DA9063
+ tristate "Dialog Semiconductor DA9063 regulators"
+ depends on MFD_DA9063
+ help
+ Say y here to support the BUCKs and LDOs regulators found on
+ DA9063 PMICs.
+
+ This driver can also be built as a module. If so, the module
+ will be called da9063-regulator.
+
+config REGULATOR_DA9210
+ tristate "Dialog Semiconductor DA9210 regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say y here to support for the Dialog Semiconductor DA9210.
+ The DA9210 is a multi-phase synchronous step down
+ converter 12A DC-DC Buck controlled through an I2C
+ interface.
+
+config REGULATOR_DBX500_PRCMU
+ bool
+
+config REGULATOR_DB8500_PRCMU
+ bool "ST-Ericsson DB8500 Voltage Domain Regulators"
+ depends on MFD_DB8500_PRCMU
+ select REGULATOR_DBX500_PRCMU
+ help
+ This driver supports the voltage domain regulators controlled by the
+ DB8500 PRCMU
+
config REGULATOR_FAN53555
tristate "Fairchild FAN53555 Regulator"
depends on I2C
@@ -131,44 +199,57 @@ config REGULATOR_FAN53555
input voltage supply of 2.5V to 5.5V. The output voltage is
programmed through an I2C interface.
-config REGULATOR_ANATOP
- tristate "Freescale i.MX on-chip ANATOP LDO regulators"
- depends on MFD_SYSCON
+config REGULATOR_GPIO
+ tristate "GPIO regulator support"
+ depends on GPIOLIB
help
- Say y here to support Freescale i.MX on-chip ANATOP LDOs
- regulators. It is recommended that this option be
- enabled on i.MX6 platform.
+ This driver provides support for regulators that can be
+ controlled via gpios.
+ It is capable of supporting current and voltage regulators
+ and the platform has to provide a mapping of GPIO-states
+ to target volts/amps.
-config REGULATOR_MC13XXX_CORE
- tristate
+config REGULATOR_ISL6271A
+ tristate "Intersil ISL6271A Power regulator"
+ depends on I2C
+ help
+ This driver supports ISL6271A voltage regulator chip.
-config REGULATOR_MC13783
- tristate "Freescale MC13783 regulator driver"
- depends on MFD_MC13783
- select REGULATOR_MC13XXX_CORE
+config REGULATOR_LP3971
+ tristate "National Semiconductors LP3971 PMIC regulator driver"
+ depends on I2C
help
- Say y here to support the regulators found on the Freescale MC13783
- PMIC.
+ Say Y here to support the voltage regulators and convertors
+ on National Semiconductors LP3971 PMIC
-config REGULATOR_MC13892
- tristate "Freescale MC13892 regulator driver"
- depends on MFD_MC13XXX
- select REGULATOR_MC13XXX_CORE
+config REGULATOR_LP3972
+ tristate "National Semiconductors LP3972 PMIC regulator driver"
+ depends on I2C
help
- Say y here to support the regulators found on the Freescale MC13892
- PMIC.
+ Say Y here to support the voltage regulators and convertors
+ on National Semiconductors LP3972 PMIC
-config REGULATOR_ISL6271A
- tristate "Intersil ISL6271A Power regulator"
+config REGULATOR_LP872X
+ tristate "TI/National Semiconductor LP8720/LP8725 voltage regulators"
depends on I2C
+ select REGMAP_I2C
help
- This driver supports ISL6271A voltage regulator chip.
+ This driver supports LP8720/LP8725 PMIC
-config REGULATOR_88PM8607
- bool "Marvell 88PM8607 Power regulators"
- depends on MFD_88PM860X=y
+config REGULATOR_LP8755
+ tristate "TI LP8755 High Performance PMU driver"
+ depends on I2C
+ select REGMAP_I2C
help
- This driver supports 88PM8607 voltage regulator chips.
+ This driver supports LP8755 High Performance PMU driver. This
+ chip contains six step-down DC/DC converters which can support
+ 9 mode multiphase configuration.
+
+config REGULATOR_LP8788
+ tristate "TI LP8788 Power Regulators"
+ depends on MFD_LP8788
+ help
+ This driver supports LP8788 voltage regulator chip.
config REGULATOR_MAX1586
tristate "Maxim 1586/1587 voltage regulator"
@@ -259,48 +340,43 @@ config REGULATOR_MAX77693
and one current regulator 'CHARGER'. This is suitable for
Exynos-4x12 chips.
-config REGULATOR_PCAP
- tristate "Motorola PCAP2 regulator driver"
- depends on EZX_PCAP
- help
- This driver provides support for the voltage regulators of the
- PCAP2 PMIC.
+config REGULATOR_MC13XXX_CORE
+ tristate
-config REGULATOR_LP3971
- tristate "National Semiconductors LP3971 PMIC regulator driver"
- depends on I2C
+config REGULATOR_MC13783
+ tristate "Freescale MC13783 regulator driver"
+ depends on MFD_MC13783
+ select REGULATOR_MC13XXX_CORE
help
- Say Y here to support the voltage regulators and convertors
- on National Semiconductors LP3971 PMIC
+ Say y here to support the regulators found on the Freescale MC13783
+ PMIC.
-config REGULATOR_LP3972
- tristate "National Semiconductors LP3972 PMIC regulator driver"
- depends on I2C
+config REGULATOR_MC13892
+ tristate "Freescale MC13892 regulator driver"
+ depends on MFD_MC13XXX
+ select REGULATOR_MC13XXX_CORE
help
- Say Y here to support the voltage regulators and convertors
- on National Semiconductors LP3972 PMIC
+ Say y here to support the regulators found on the Freescale MC13892
+ PMIC.
-config REGULATOR_LP872X
- bool "TI/National Semiconductor LP8720/LP8725 voltage regulators"
- depends on I2C=y
- select REGMAP_I2C
+config REGULATOR_PALMAS
+ tristate "TI Palmas PMIC Regulators"
+ depends on MFD_PALMAS
help
- This driver supports LP8720/LP8725 PMIC
+ If you wish to control the regulators on the Palmas series of
+ chips say Y here. This will enable support for all the software
+ controllable SMPS/LDO regulators.
-config REGULATOR_LP8755
- tristate "TI LP8755 High Performance PMU driver"
- depends on I2C
- select REGMAP_I2C
- help
- This driver supports LP8755 High Performance PMU driver. This
- chip contains six step-down DC/DC converters which can support
- 9 mode multiphase configuration.
+ The regulators available on Palmas series chips vary depending
+ on the muxing. This is handled automatically in the driver by
+ reading the mux info from OTP.
-config REGULATOR_LP8788
- bool "TI LP8788 Power Regulators"
- depends on MFD_LP8788
+config REGULATOR_PCAP
+ tristate "Motorola PCAP2 regulator driver"
+ depends on EZX_PCAP
help
- This driver supports LP8788 voltage regulator chip.
+ This driver provides support for the voltage regulators of the
+ PCAP2 PMIC.
config REGULATOR_PCF50633
tristate "NXP PCF50633 regulator driver"
@@ -309,6 +385,14 @@ config REGULATOR_PCF50633
Say Y here to support the voltage regulators and convertors
on PCF50633
+config REGULATOR_PFUZE100
+ tristate "Support regulators on Freescale PFUZE100 PMIC"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say y here to support the regulators found on the Freescale PFUZE100
+ PMIC.
+
config REGULATOR_RC5T583
tristate "RICOH RC5T583 Power regulators"
depends on MFD_RC5T583
@@ -335,44 +419,15 @@ config REGULATOR_S5M8767
via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
supports DVS mode with 8bits of output voltage control.
-config REGULATOR_AB3100
- tristate "ST-Ericsson AB3100 Regulator functions"
- depends on AB3100_CORE
- default y if AB3100_CORE
- help
- These regulators correspond to functionality in the
- AB3100 analog baseband dealing with power regulators
- for the system.
-
-config REGULATOR_AB8500
- bool "ST-Ericsson AB8500 Power Regulators"
- depends on AB8500_CORE
- help
- This driver supports the regulators found on the ST-Ericsson mixed
- signal AB8500 PMIC
-
-config REGULATOR_DBX500_PRCMU
- bool
-
-config REGULATOR_DB8500_PRCMU
- bool "ST-Ericsson DB8500 Voltage Domain Regulators"
- depends on MFD_DB8500_PRCMU
- select REGULATOR_DBX500_PRCMU
- help
- This driver supports the voltage domain regulators controlled by the
- DB8500 PRCMU
-
-config REGULATOR_PALMAS
- tristate "TI Palmas PMIC Regulators"
- depends on MFD_PALMAS
+config REGULATOR_TI_ABB
+ tristate "TI Adaptive Body Bias on-chip LDO"
+ depends on ARCH_OMAP
help
- If you wish to control the regulators on the Palmas series of
- chips say Y here. This will enable support for all the software
- controllable SMPS/LDO regulators.
-
- The regulators available on Palmas series chips vary depending
- on the muxing. This is handled automatically in the driver by
- reading the mux info from OTP.
+ Select this option to support Texas Instruments' on-chip Adaptive Body
+ Bias (ABB) LDO regulators. It is recommended that this option be
+ enabled on required TI SoC. Certain Operating Performance Points
+ on TI SoCs may be unstable without enabling this as it provides
+ device specific optimized bias to allow/optimize functionality.
config REGULATOR_TPS51632
tristate "TI TPS51632 Power Regulator"
@@ -475,22 +530,12 @@ config REGULATOR_TPS80031
output to control regulators.
config REGULATOR_TWL4030
- bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
+ tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
depends on TWL4030_CORE
help
This driver supports the voltage regulators provided by
this family of companion chips.
-config REGULATOR_TI_ABB
- bool "TI Adaptive Body Bias on-chip LDO"
- depends on ARCH_OMAP
- help
- Select this option to support Texas Instruments' on-chip Adaptive Body
- Bias (ABB) LDO regulators. It is recommended that this option be
- enabled on required TI SoC. Certain Operating Performance Points
- on TI SoCs may be unstable without enabling this as it provides
- device specific optimized bias to allow/optimize functionality.
-
config REGULATOR_VEXPRESS
tristate "Versatile Express regulators"
depends on VEXPRESS_CONFIG
@@ -526,12 +571,5 @@ config REGULATOR_WM8994
This driver provides support for the voltage regulators on the
WM8994 CODEC.
-config REGULATOR_AS3711
- tristate "AS3711 PMIC"
- depends on MFD_AS3711
- help
- This driver provides support for the voltage regulators on the
- AS3711 PMIC
-
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ba4a3cf3afe..185cce24602 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -3,12 +3,13 @@
#
-obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o
+obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o
obj-$(CONFIG_OF) += of_regulator.o
obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
+obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
@@ -20,6 +21,8 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o
+obj-$(CONFIG_REGULATOR_DA9063) += da9063-regulator.o
+obj-$(CONFIG_REGULATOR_DA9210) += da9210-regulator.o
obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
@@ -46,12 +49,14 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
+obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
@@ -64,7 +69,6 @@ obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
-obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c
index 8b5876356db..881159dfcb5 100644
--- a/drivers/regulator/aat2870-regulator.c
+++ b/drivers/regulator/aat2870-regulator.c
@@ -174,7 +174,7 @@ static int aat2870_regulator_probe(struct platform_device *pdev)
config.dev = &pdev->dev;
config.driver_data = ri;
- config.init_data = pdev->dev.platform_data;
+ config.init_data = dev_get_platdata(&pdev->dev);
rdev = regulator_register(&ri->desc, &config);
if (IS_ERR(rdev)) {
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 3be9e46594a..7d5eaa874b2 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -660,7 +660,7 @@ ab3100_regulator_of_probe(struct platform_device *pdev, struct device_node *np)
static int ab3100_regulators_probe(struct platform_device *pdev)
{
- struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
+ struct ab3100_platform_data *plfdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
int err = 0;
u8 data;
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
index 6b981b5faa7..b2b203cb6b2 100644
--- a/drivers/regulator/ad5398.c
+++ b/drivers/regulator/ad5398.c
@@ -214,7 +214,7 @@ MODULE_DEVICE_TABLE(i2c, ad5398_id);
static int ad5398_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct regulator_init_data *init_data = client->dev.platform_data;
+ struct regulator_init_data *init_data = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct ad5398_chip_info *chip;
const struct ad5398_current_data_format *df =
diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index 3da6bd6950c..8406cd745da 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -30,102 +30,6 @@ struct as3711_regulator {
struct regulator_dev *rdev;
};
-static int as3711_list_voltage_sd(struct regulator_dev *rdev,
- unsigned int selector)
-{
- if (selector >= rdev->desc->n_voltages)
- return -EINVAL;
-
- if (!selector)
- return 0;
- if (selector < 0x41)
- return 600000 + selector * 12500;
- if (selector < 0x71)
- return 1400000 + (selector - 0x40) * 25000;
- return 2600000 + (selector - 0x70) * 50000;
-}
-
-static int as3711_list_voltage_aldo(struct regulator_dev *rdev,
- unsigned int selector)
-{
- if (selector >= rdev->desc->n_voltages)
- return -EINVAL;
-
- if (selector < 0x10)
- return 1200000 + selector * 50000;
- return 1800000 + (selector - 0x10) * 100000;
-}
-
-static int as3711_list_voltage_dldo(struct regulator_dev *rdev,
- unsigned int selector)
-{
- if (selector >= rdev->desc->n_voltages ||
- (selector > 0x10 && selector < 0x20))
- return -EINVAL;
-
- if (selector < 0x11)
- return 900000 + selector * 50000;
- return 1750000 + (selector - 0x20) * 50000;
-}
-
-static int as3711_bound_check(struct regulator_dev *rdev,
- int *min_uV, int *max_uV)
-{
- struct as3711_regulator *reg = rdev_get_drvdata(rdev);
- struct as3711_regulator_info *info = reg->reg_info;
-
- dev_dbg(&rdev->dev, "%s(), %d, %d, %d\n", __func__,
- *min_uV, rdev->desc->min_uV, info->max_uV);
-
- if (*max_uV < *min_uV ||
- *min_uV > info->max_uV || rdev->desc->min_uV > *max_uV)
- return -EINVAL;
-
- if (rdev->desc->n_voltages == 1)
- return 0;
-
- if (*max_uV > info->max_uV)
- *max_uV = info->max_uV;
-
- if (*min_uV < rdev->desc->min_uV)
- *min_uV = rdev->desc->min_uV;
-
- return *min_uV;
-}
-
-static int as3711_sel_check(int min, int max, int bottom, int step)
-{
- int sel, voltage;
-
- /* Round up min, when dividing: keeps us within the range */
- sel = DIV_ROUND_UP(min - bottom, step);
- voltage = sel * step + bottom;
- pr_debug("%s(): select %d..%d in %d+N*%d: %d\n", __func__,
- min, max, bottom, step, sel);
- if (voltage > max)
- return -EINVAL;
-
- return sel;
-}
-
-static int as3711_map_voltage_sd(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- int ret;
-
- ret = as3711_bound_check(rdev, &min_uV, &max_uV);
- if (ret <= 0)
- return ret;
-
- if (min_uV <= 1400000)
- return as3711_sel_check(min_uV, max_uV, 600000, 12500);
-
- if (min_uV <= 2600000)
- return as3711_sel_check(min_uV, max_uV, 1400000, 25000) + 0x40;
-
- return as3711_sel_check(min_uV, max_uV, 2600000, 50000) + 0x70;
-}
-
/*
* The regulator API supports 4 modes of operataion: FAST, NORMAL, IDLE and
* STANDBY. We map them in the following way to AS3711 SD1-4 DCDC modes:
@@ -180,44 +84,14 @@ static unsigned int as3711_get_mode_sd(struct regulator_dev *rdev)
return -EINVAL;
}
-static int as3711_map_voltage_aldo(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- int ret;
-
- ret = as3711_bound_check(rdev, &min_uV, &max_uV);
- if (ret <= 0)
- return ret;
-
- if (min_uV <= 1800000)
- return as3711_sel_check(min_uV, max_uV, 1200000, 50000);
-
- return as3711_sel_check(min_uV, max_uV, 1800000, 100000) + 0x10;
-}
-
-static int as3711_map_voltage_dldo(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- int ret;
-
- ret = as3711_bound_check(rdev, &min_uV, &max_uV);
- if (ret <= 0)
- return ret;
-
- if (min_uV <= 1700000)
- return as3711_sel_check(min_uV, max_uV, 900000, 50000);
-
- return as3711_sel_check(min_uV, max_uV, 1750000, 50000) + 0x20;
-}
-
static struct regulator_ops as3711_sd_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .list_voltage = as3711_list_voltage_sd,
- .map_voltage = as3711_map_voltage_sd,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
.get_mode = as3711_get_mode_sd,
.set_mode = as3711_set_mode_sd,
};
@@ -228,8 +102,8 @@ static struct regulator_ops as3711_aldo_ops = {
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .list_voltage = as3711_list_voltage_aldo,
- .map_voltage = as3711_map_voltage_aldo,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
};
static struct regulator_ops as3711_dldo_ops = {
@@ -238,8 +112,31 @@ static struct regulator_ops as3711_dldo_ops = {
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .list_voltage = as3711_list_voltage_dldo,
- .map_voltage = as3711_map_voltage_dldo,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+};
+
+static const struct regulator_linear_range as3711_sd_ranges[] = {
+ { .min_uV = 612500, .max_uV = 1400000,
+ .min_sel = 0x1, .max_sel = 0x40, .uV_step = 12500 },
+ { .min_uV = 1425000, .max_uV = 2600000,
+ .min_sel = 0x41, .max_sel = 0x70, .uV_step = 25000 },
+ { .min_uV = 2650000, .max_uV = 3350000,
+ .min_sel = 0x71, .max_sel = 0x7f, .uV_step = 50000 },
+};
+
+static const struct regulator_linear_range as3711_aldo_ranges[] = {
+ { .min_uV = 1200000, .max_uV = 1950000,
+ .min_sel = 0, .max_sel = 0xf, .uV_step = 50000 },
+ { .min_uV = 1800000, .max_uV = 3300000,
+ .min_sel = 0x10, .max_sel = 0x1f, .uV_step = 100000 },
+};
+
+static const struct regulator_linear_range as3711_dldo_ranges[] = {
+ { .min_uV = 900000, .max_uV = 1700000,
+ .min_sel = 0, .max_sel = 0x10, .uV_step = 50000 },
+ { .min_uV = 1750000, .max_uV = 3300000,
+ .min_sel = 0x20, .max_sel = 0x3f, .uV_step = 50000 },
};
#define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx) \
@@ -256,6 +153,8 @@ static struct regulator_ops as3711_dldo_ops = {
.enable_reg = AS3711_ ## _en_reg, \
.enable_mask = BIT(_en_bit), \
.min_uV = _min_uV, \
+ .linear_ranges = as3711_ ## _sfx ## _ranges, \
+ .n_linear_ranges = ARRAY_SIZE(as3711_ ## _sfx ## _ranges), \
}, \
.max_uV = _max_uV, \
}
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 288c75abc19..a01b8b3b70c 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -323,13 +323,14 @@ static ssize_t regulator_uA_show(struct device *dev,
}
static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL);
-static ssize_t regulator_name_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", rdev_get_name(rdev));
}
+static DEVICE_ATTR_RO(name);
static ssize_t regulator_print_opmode(char *buf, int mode)
{
@@ -489,15 +490,16 @@ static ssize_t regulator_total_uA_show(struct device *dev,
}
static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL);
-static ssize_t regulator_num_users_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t num_users_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", rdev->use_count);
}
+static DEVICE_ATTR_RO(num_users);
-static ssize_t regulator_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
@@ -509,6 +511,7 @@ static ssize_t regulator_type_show(struct device *dev,
}
return sprintf(buf, "unknown\n");
}
+static DEVICE_ATTR_RO(type);
static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -632,12 +635,13 @@ static DEVICE_ATTR(bypass, 0444,
* These are the only attributes are present for all regulators.
* Other attributes are a function of regulator functionality.
*/
-static struct device_attribute regulator_dev_attrs[] = {
- __ATTR(name, 0444, regulator_name_show, NULL),
- __ATTR(num_users, 0444, regulator_num_users_show, NULL),
- __ATTR(type, 0444, regulator_type_show, NULL),
- __ATTR_NULL,
+static struct attribute *regulator_dev_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_num_users.attr,
+ &dev_attr_type.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(regulator_dev);
static void regulator_dev_release(struct device *dev)
{
@@ -648,7 +652,7 @@ static void regulator_dev_release(struct device *dev)
static struct class regulator_class = {
.name = "regulator",
.dev_release = regulator_dev_release,
- .dev_attrs = regulator_dev_attrs,
+ .dev_groups = regulator_dev_groups,
};
/* Calculate the new optimum regulator operating mode based on the new total
@@ -984,7 +988,8 @@ static int set_machine_constraints(struct regulator_dev *rdev,
}
}
- if (rdev->constraints->ramp_delay && ops->set_ramp_delay) {
+ if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable)
+ && ops->set_ramp_delay) {
ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
if (ret < 0) {
rdev_err(rdev, "failed to set ramp_delay\n");
@@ -1238,7 +1243,7 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
/* Internal regulator request function */
static struct regulator *_regulator_get(struct device *dev, const char *id,
- int exclusive)
+ bool exclusive)
{
struct regulator_dev *rdev;
struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
@@ -1344,7 +1349,7 @@ out:
*/
struct regulator *regulator_get(struct device *dev, const char *id)
{
- return _regulator_get(dev, id, 0);
+ return _regulator_get(dev, id, false);
}
EXPORT_SYMBOL_GPL(regulator_get);
@@ -1405,10 +1410,69 @@ EXPORT_SYMBOL_GPL(devm_regulator_get);
*/
struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
{
- return _regulator_get(dev, id, 1);
+ return _regulator_get(dev, id, true);
}
EXPORT_SYMBOL_GPL(regulator_get_exclusive);
+/**
+ * regulator_get_optional - obtain optional access to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno. Other consumers will be
+ * unable to obtain this reference is held and the use count for the
+ * regulator will be initialised to reflect the current state of the
+ * regulator.
+ *
+ * This is intended for use by consumers for devices which can have
+ * some supplies unconnected in normal use, such as some MMC devices.
+ * It can allow the regulator core to provide stub supplies for other
+ * supplies requested using normal regulator_get() calls without
+ * disrupting the operation of drivers that can handle absent
+ * supplies.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged. It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
+ */
+struct regulator *regulator_get_optional(struct device *dev, const char *id)
+{
+ return _regulator_get(dev, id, 0);
+}
+EXPORT_SYMBOL_GPL(regulator_get_optional);
+
+/**
+ * devm_regulator_get_optional - Resource managed regulator_get_optional()
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Managed regulator_get_optional(). Regulators returned from this
+ * function are automatically regulator_put() on driver detach. See
+ * regulator_get_optional() for more information.
+ */
+struct regulator *devm_regulator_get_optional(struct device *dev,
+ const char *id)
+{
+ struct regulator **ptr, *regulator;
+
+ ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ regulator = regulator_get_optional(dev, id);
+ if (!IS_ERR(regulator)) {
+ *ptr = regulator;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return regulator;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_get_optional);
+
/* Locks held by regulator_put() */
static void _regulator_put(struct regulator *regulator)
{
@@ -1435,6 +1499,36 @@ static void _regulator_put(struct regulator *regulator)
}
/**
+ * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive()
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Managed regulator_get_exclusive(). Regulators returned from this function
+ * are automatically regulator_put() on driver detach. See regulator_get() for
+ * more information.
+ */
+struct regulator *devm_regulator_get_exclusive(struct device *dev,
+ const char *id)
+{
+ struct regulator **ptr, *regulator;
+
+ ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ regulator = _regulator_get(dev, id, 1);
+ if (!IS_ERR(regulator)) {
+ *ptr = regulator;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return regulator;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_get_exclusive);
+
+/**
* regulator_put - "free" the regulator source
* @regulator: regulator source
*
@@ -1890,8 +1984,9 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
rdev->deferred_disables++;
mutex_unlock(&rdev->mutex);
- ret = schedule_delayed_work(&rdev->disable_work,
- msecs_to_jiffies(ms));
+ ret = queue_delayed_work(system_power_efficient_wq,
+ &rdev->disable_work,
+ msecs_to_jiffies(ms));
if (ret < 0)
return ret;
else
@@ -1899,77 +1994,6 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
}
EXPORT_SYMBOL_GPL(regulator_disable_deferred);
-/**
- * regulator_is_enabled_regmap - standard is_enabled() for regmap users
- *
- * @rdev: regulator to operate on
- *
- * Regulators that use regmap for their register I/O can set the
- * enable_reg and enable_mask fields in their descriptor and then use
- * this as their is_enabled operation, saving some code.
- */
-int regulator_is_enabled_regmap(struct regulator_dev *rdev)
-{
- unsigned int val;
- int ret;
-
- ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
- if (ret != 0)
- return ret;
-
- if (rdev->desc->enable_is_inverted)
- return (val & rdev->desc->enable_mask) == 0;
- else
- return (val & rdev->desc->enable_mask) != 0;
-}
-EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
-
-/**
- * regulator_enable_regmap - standard enable() for regmap users
- *
- * @rdev: regulator to operate on
- *
- * Regulators that use regmap for their register I/O can set the
- * enable_reg and enable_mask fields in their descriptor and then use
- * this as their enable() operation, saving some code.
- */
-int regulator_enable_regmap(struct regulator_dev *rdev)
-{
- unsigned int val;
-
- if (rdev->desc->enable_is_inverted)
- val = 0;
- else
- val = rdev->desc->enable_mask;
-
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask, val);
-}
-EXPORT_SYMBOL_GPL(regulator_enable_regmap);
-
-/**
- * regulator_disable_regmap - standard disable() for regmap users
- *
- * @rdev: regulator to operate on
- *
- * Regulators that use regmap for their register I/O can set the
- * enable_reg and enable_mask fields in their descriptor and then use
- * this as their disable() operation, saving some code.
- */
-int regulator_disable_regmap(struct regulator_dev *rdev)
-{
- unsigned int val;
-
- if (rdev->desc->enable_is_inverted)
- val = rdev->desc->enable_mask;
- else
- val = 0;
-
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask, val);
-}
-EXPORT_SYMBOL_GPL(regulator_disable_regmap);
-
static int _regulator_is_enabled(struct regulator_dev *rdev)
{
/* A GPIO control always takes precedence */
@@ -2055,55 +2079,6 @@ int regulator_count_voltages(struct regulator *regulator)
EXPORT_SYMBOL_GPL(regulator_count_voltages);
/**
- * regulator_list_voltage_linear - List voltages with simple calculation
- *
- * @rdev: Regulator device
- * @selector: Selector to convert into a voltage
- *
- * Regulators with a simple linear mapping between voltages and
- * selectors can set min_uV and uV_step in the regulator descriptor
- * and then use this function as their list_voltage() operation,
- */
-int regulator_list_voltage_linear(struct regulator_dev *rdev,
- unsigned int selector)
-{
- if (selector >= rdev->desc->n_voltages)
- return -EINVAL;
- if (selector < rdev->desc->linear_min_sel)
- return 0;
-
- selector -= rdev->desc->linear_min_sel;
-
- return rdev->desc->min_uV + (rdev->desc->uV_step * selector);
-}
-EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
-
-/**
- * regulator_list_voltage_table - List voltages with table based mapping
- *
- * @rdev: Regulator device
- * @selector: Selector to convert into a voltage
- *
- * Regulators with table based mapping between voltages and
- * selectors can set volt_table in the regulator descriptor
- * and then use this function as their list_voltage() operation.
- */
-int regulator_list_voltage_table(struct regulator_dev *rdev,
- unsigned int selector)
-{
- if (!rdev->desc->volt_table) {
- BUG_ON(!rdev->desc->volt_table);
- return -EINVAL;
- }
-
- if (selector >= rdev->desc->n_voltages)
- return -EINVAL;
-
- return rdev->desc->volt_table[selector];
-}
-EXPORT_SYMBOL_GPL(regulator_list_voltage_table);
-
-/**
* regulator_list_voltage - enumerate supported voltages
* @regulator: regulator source
* @selector: identify voltage to list
@@ -2197,177 +2172,6 @@ int regulator_is_supported_voltage(struct regulator *regulator,
}
EXPORT_SYMBOL_GPL(regulator_is_supported_voltage);
-/**
- * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users
- *
- * @rdev: regulator to operate on
- *
- * Regulators that use regmap for their register I/O can set the
- * vsel_reg and vsel_mask fields in their descriptor and then use this
- * as their get_voltage_vsel operation, saving some code.
- */
-int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev)
-{
- unsigned int val;
- int ret;
-
- ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
- if (ret != 0)
- return ret;
-
- val &= rdev->desc->vsel_mask;
- val >>= ffs(rdev->desc->vsel_mask) - 1;
-
- return val;
-}
-EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap);
-
-/**
- * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users
- *
- * @rdev: regulator to operate on
- * @sel: Selector to set
- *
- * Regulators that use regmap for their register I/O can set the
- * vsel_reg and vsel_mask fields in their descriptor and then use this
- * as their set_voltage_vsel operation, saving some code.
- */
-int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
-{
- int ret;
-
- sel <<= ffs(rdev->desc->vsel_mask) - 1;
-
- ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
- rdev->desc->vsel_mask, sel);
- if (ret)
- return ret;
-
- if (rdev->desc->apply_bit)
- ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
- rdev->desc->apply_bit,
- rdev->desc->apply_bit);
- return ret;
-}
-EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
-
-/**
- * regulator_map_voltage_iterate - map_voltage() based on list_voltage()
- *
- * @rdev: Regulator to operate on
- * @min_uV: Lower bound for voltage
- * @max_uV: Upper bound for voltage
- *
- * Drivers implementing set_voltage_sel() and list_voltage() can use
- * this as their map_voltage() operation. It will find a suitable
- * voltage by calling list_voltage() until it gets something in bounds
- * for the requested voltages.
- */
-int regulator_map_voltage_iterate(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- int best_val = INT_MAX;
- int selector = 0;
- int i, ret;
-
- /* Find the smallest voltage that falls within the specified
- * range.
- */
- for (i = 0; i < rdev->desc->n_voltages; i++) {
- ret = rdev->desc->ops->list_voltage(rdev, i);
- if (ret < 0)
- continue;
-
- if (ret < best_val && ret >= min_uV && ret <= max_uV) {
- best_val = ret;
- selector = i;
- }
- }
-
- if (best_val != INT_MAX)
- return selector;
- else
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate);
-
-/**
- * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list
- *
- * @rdev: Regulator to operate on
- * @min_uV: Lower bound for voltage
- * @max_uV: Upper bound for voltage
- *
- * Drivers that have ascendant voltage list can use this as their
- * map_voltage() operation.
- */
-int regulator_map_voltage_ascend(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- int i, ret;
-
- for (i = 0; i < rdev->desc->n_voltages; i++) {
- ret = rdev->desc->ops->list_voltage(rdev, i);
- if (ret < 0)
- continue;
-
- if (ret > max_uV)
- break;
-
- if (ret >= min_uV && ret <= max_uV)
- return i;
- }
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend);
-
-/**
- * regulator_map_voltage_linear - map_voltage() for simple linear mappings
- *
- * @rdev: Regulator to operate on
- * @min_uV: Lower bound for voltage
- * @max_uV: Upper bound for voltage
- *
- * Drivers providing min_uV and uV_step in their regulator_desc can
- * use this as their map_voltage() operation.
- */
-int regulator_map_voltage_linear(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- int ret, voltage;
-
- /* Allow uV_step to be 0 for fixed voltage */
- if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) {
- if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV)
- return 0;
- else
- return -EINVAL;
- }
-
- if (!rdev->desc->uV_step) {
- BUG_ON(!rdev->desc->uV_step);
- return -EINVAL;
- }
-
- if (min_uV < rdev->desc->min_uV)
- min_uV = rdev->desc->min_uV;
-
- ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step);
- if (ret < 0)
- return ret;
-
- ret += rdev->desc->linear_min_sel;
-
- /* Map back into a voltage to verify we're still in bounds */
- voltage = rdev->desc->ops->list_voltage(rdev, ret);
- if (voltage < min_uV || voltage > max_uV)
- return -EINVAL;
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(regulator_map_voltage_linear);
-
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
@@ -2438,8 +2242,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
}
/* Call set_voltage_time_sel if successfully obtained old_selector */
- if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
- old_selector != selector && rdev->desc->ops->set_voltage_time_sel) {
+ if (ret == 0 && !rdev->constraints->ramp_disable && old_selector >= 0
+ && old_selector != selector) {
delay = rdev->desc->ops->set_voltage_time_sel(rdev,
old_selector, selector);
@@ -2971,47 +2775,6 @@ out:
EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
/**
- * regulator_set_bypass_regmap - Default set_bypass() using regmap
- *
- * @rdev: device to operate on.
- * @enable: state to set.
- */
-int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
-{
- unsigned int val;
-
- if (enable)
- val = rdev->desc->bypass_mask;
- else
- val = 0;
-
- return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
- rdev->desc->bypass_mask, val);
-}
-EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap);
-
-/**
- * regulator_get_bypass_regmap - Default get_bypass() using regmap
- *
- * @rdev: device to operate on.
- * @enable: current state.
- */
-int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
-{
- unsigned int val;
- int ret;
-
- ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val);
- if (ret != 0)
- return ret;
-
- *enable = val & rdev->desc->bypass_mask;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
-
-/**
* regulator_allow_bypass - allow the regulator to go into bypass mode
*
* @regulator: Regulator to configure
@@ -3740,8 +3503,11 @@ void regulator_unregister(struct regulator_dev *rdev)
if (rdev == NULL)
return;
- if (rdev->supply)
+ if (rdev->supply) {
+ while (rdev->use_count--)
+ regulator_disable(rdev->supply);
regulator_put(rdev->supply);
+ }
mutex_lock(&regulator_list_mutex);
debugfs_remove_recursive(rdev->debugfs);
flush_work(&rdev->disable_work.work);
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index 2afa5730f32..f06854cf8cf 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -252,39 +252,12 @@ static int da9034_set_dvc_voltage_sel(struct regulator_dev *rdev,
return ret;
}
-static int da9034_map_ldo12_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
- int sel;
-
- if (check_range(info, min_uV, max_uV)) {
- pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
- return -EINVAL;
- }
-
- sel = DIV_ROUND_UP(min_uV - info->desc.min_uV, info->desc.uV_step);
- sel = (sel >= 20) ? sel - 12 : ((sel > 7) ? 8 : sel);
-
- return sel;
-}
-
-static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
- int volt;
-
- if (selector >= 8)
- volt = 2700000 + rdev->desc->uV_step * (selector - 8);
- else
- volt = rdev->desc->min_uV + rdev->desc->uV_step * selector;
-
- if (volt > info->max_uV)
- return -EINVAL;
-
- return volt;
-}
+static const struct regulator_linear_range da9034_ldo12_ranges[] = {
+ { .min_uV = 1700000, .max_uV = 2050000, .min_sel = 0, .max_sel = 7,
+ .uV_step = 50000 },
+ { .min_uV = 2700000, .max_uV = 3050000, .min_sel = 8, .max_sel = 15,
+ .uV_step = 50000 },
+};
static struct regulator_ops da903x_regulator_ldo_ops = {
.set_voltage_sel = da903x_set_voltage_sel,
@@ -332,8 +305,8 @@ static struct regulator_ops da9034_regulator_dvc_ops = {
static struct regulator_ops da9034_regulator_ldo12_ops = {
.set_voltage_sel = da903x_set_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
- .list_voltage = da9034_list_ldo12_voltage,
- .map_voltage = da9034_map_ldo12_voltage,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
.enable = da903x_enable,
.disable = da903x_disable,
.is_enabled = da903x_is_enabled,
@@ -476,6 +449,8 @@ static int da903x_regulator_probe(struct platform_device *pdev)
if (ri->desc.id == DA9034_ID_LDO12) {
ri->desc.ops = &da9034_regulator_ldo12_ops;
ri->desc.n_voltages = 16;
+ ri->desc.linear_ranges = da9034_ldo12_ranges;
+ ri->desc.n_linear_ranges = ARRAY_SIZE(da9034_ldo12_ranges);
}
if (ri->desc.id == DA9030_ID_LDO14)
@@ -485,7 +460,7 @@ static int da903x_regulator_probe(struct platform_device *pdev)
ri->desc.ops = &da9030_regulator_ldo1_15_ops;
config.dev = &pdev->dev;
- config.init_data = pdev->dev.platform_data;
+ config.init_data = dev_get_platdata(&pdev->dev);
config.driver_data = ri;
rdev = regulator_register(&ri->desc, &config);
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 96b569abb46..1e4d483f616 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -349,7 +349,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
return -ENOMEM;
da9052 = dev_get_drvdata(pdev->dev.parent);
- pdata = da9052->dev->platform_data;
+ pdata = dev_get_platdata(da9052->dev);
regulator->da9052 = da9052;
regulator->info = find_regulator_info(regulator->da9052->chip_id,
diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c
index 30221099d09..77b53e5a231 100644
--- a/drivers/regulator/da9055-regulator.c
+++ b/drivers/regulator/da9055-regulator.c
@@ -535,7 +535,7 @@ static int da9055_regulator_probe(struct platform_device *pdev)
struct regulator_config config = { };
struct da9055_regulator *regulator;
struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
- struct da9055_pdata *pdata = da9055->dev->platform_data;
+ struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
int ret, irq;
if (pdata == NULL || pdata->regulators[pdev->id] == NULL)
diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c
new file mode 100644
index 00000000000..1a781639077
--- /dev/null
+++ b/drivers/regulator/da9063-regulator.c
@@ -0,0 +1,934 @@
+/*
+ * Regulator driver for DA9063 PMIC series
+ *
+ * Copyright 2012 Dialog Semiconductors Ltd.
+ * Copyright 2013 Philipp Zabel, Pengutronix
+ *
+ * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.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.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/da9063/core.h>
+#include <linux/mfd/da9063/pdata.h>
+#include <linux/mfd/da9063/registers.h>
+
+
+/* Definition for registering regmap bit fields using a mask */
+#define BFIELD(_reg, _mask) \
+ REG_FIELD(_reg, __builtin_ffs((int)_mask) - 1, \
+ sizeof(unsigned int) * 8 - __builtin_clz((_mask)) - 1)
+
+/* Regulator capabilities and registers description */
+struct da9063_regulator_info {
+ struct regulator_desc desc;
+
+ /* Current limiting */
+ unsigned n_current_limits;
+ const int *current_limits;
+
+ /* DA9063 main register fields */
+ struct reg_field mode; /* buck mode of operation */
+ struct reg_field suspend;
+ struct reg_field sleep;
+ struct reg_field suspend_sleep;
+ unsigned int suspend_vsel_reg;
+ struct reg_field ilimit;
+
+ /* DA9063 event detection bit */
+ struct reg_field oc_event;
+};
+
+/* Macros for LDO */
+#define DA9063_LDO(chip, regl_name, min_mV, step_mV, max_mV) \
+ .desc.id = chip##_ID_##regl_name, \
+ .desc.name = __stringify(chip##_##regl_name), \
+ .desc.ops = &da9063_ldo_ops, \
+ .desc.min_uV = (min_mV) * 1000, \
+ .desc.uV_step = (step_mV) * 1000, \
+ .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1), \
+ .desc.enable_reg = DA9063_REG_##regl_name##_CONT, \
+ .desc.enable_mask = DA9063_LDO_EN, \
+ .desc.vsel_reg = DA9063_REG_V##regl_name##_A, \
+ .desc.vsel_mask = DA9063_V##regl_name##_MASK, \
+ .desc.linear_min_sel = DA9063_V##regl_name##_BIAS, \
+ .sleep = BFIELD(DA9063_REG_V##regl_name##_A, DA9063_LDO_SL), \
+ .suspend_sleep = BFIELD(DA9063_REG_V##regl_name##_B, DA9063_LDO_SL), \
+ .suspend_vsel_reg = DA9063_REG_V##regl_name##_B
+
+/* Macros for voltage DC/DC converters (BUCKs) */
+#define DA9063_BUCK(chip, regl_name, min_mV, step_mV, max_mV, limits_array) \
+ .desc.id = chip##_ID_##regl_name, \
+ .desc.name = __stringify(chip##_##regl_name), \
+ .desc.ops = &da9063_buck_ops, \
+ .desc.min_uV = (min_mV) * 1000, \
+ .desc.uV_step = (step_mV) * 1000, \
+ .desc.n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \
+ .current_limits = limits_array, \
+ .n_current_limits = ARRAY_SIZE(limits_array)
+
+#define DA9063_BUCK_COMMON_FIELDS(regl_name) \
+ .desc.enable_reg = DA9063_REG_##regl_name##_CONT, \
+ .desc.enable_mask = DA9063_BUCK_EN, \
+ .desc.vsel_reg = DA9063_REG_V##regl_name##_A, \
+ .desc.vsel_mask = DA9063_VBUCK_MASK, \
+ .desc.linear_min_sel = DA9063_VBUCK_BIAS, \
+ .sleep = BFIELD(DA9063_REG_V##regl_name##_A, DA9063_BUCK_SL), \
+ .suspend_sleep = BFIELD(DA9063_REG_V##regl_name##_B, DA9063_BUCK_SL), \
+ .suspend_vsel_reg = DA9063_REG_V##regl_name##_B, \
+ .mode = BFIELD(DA9063_REG_##regl_name##_CFG, DA9063_BUCK_MODE_MASK)
+
+/* Defines asignment of regulators info table to chip model */
+struct da9063_dev_model {
+ const struct da9063_regulator_info *regulator_info;
+ unsigned n_regulators;
+ unsigned dev_model;
+};
+
+/* Single regulator settings */
+struct da9063_regulator {
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ struct da9063 *hw;
+ const struct da9063_regulator_info *info;
+
+ struct regmap_field *mode;
+ struct regmap_field *suspend;
+ struct regmap_field *sleep;
+ struct regmap_field *suspend_sleep;
+ struct regmap_field *ilimit;
+};
+
+/* Encapsulates all information for the regulators driver */
+struct da9063_regulators {
+ int irq_ldo_lim;
+ int irq_uvov;
+
+ unsigned n_regulators;
+ /* Array size to be defined during init. Keep at end. */
+ struct da9063_regulator regulator[0];
+};
+
+/* BUCK modes for DA9063 */
+enum {
+ BUCK_MODE_MANUAL, /* 0 */
+ BUCK_MODE_SLEEP, /* 1 */
+ BUCK_MODE_SYNC, /* 2 */
+ BUCK_MODE_AUTO /* 3 */
+};
+
+/* Regulator operations */
+
+/* Current limits array (in uA) for BCORE1, BCORE2, BPRO.
+ Entry indexes corresponds to register values. */
+static const int da9063_buck_a_limits[] = {
+ 500000, 600000, 700000, 800000, 900000, 1000000, 1100000, 1200000,
+ 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000
+};
+
+/* Current limits array (in uA) for BMEM, BIO, BPERI.
+ Entry indexes corresponds to register values. */
+static const int da9063_buck_b_limits[] = {
+ 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, 2200000,
+ 2300000, 2400000, 2500000, 2600000, 2700000, 2800000, 2900000, 3000000
+};
+
+/* Current limits array (in uA) for merged BCORE1 and BCORE2.
+ Entry indexes corresponds to register values. */
+static const int da9063_bcores_merged_limits[] = {
+ 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2200000, 2400000,
+ 2600000, 2800000, 3000000, 3200000, 3400000, 3600000, 3800000, 4000000
+};
+
+/* Current limits array (in uA) for merged BMEM and BIO.
+ Entry indexes corresponds to register values. */
+static const int da9063_bmem_bio_merged_limits[] = {
+ 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000,
+ 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000
+};
+
+static int da9063_set_current_limit(struct regulator_dev *rdev,
+ int min_uA, int max_uA)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+ const struct da9063_regulator_info *rinfo = regl->info;
+ int n, tval;
+
+ for (n = 0; n < rinfo->n_current_limits; n++) {
+ tval = rinfo->current_limits[n];
+ if (tval >= min_uA && tval <= max_uA)
+ return regmap_field_write(regl->ilimit, n);
+ }
+
+ return -EINVAL;
+}
+
+static int da9063_get_current_limit(struct regulator_dev *rdev)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+ const struct da9063_regulator_info *rinfo = regl->info;
+ unsigned int sel;
+ int ret;
+
+ ret = regmap_field_read(regl->ilimit, &sel);
+ if (ret < 0)
+ return ret;
+
+ if (sel >= rinfo->n_current_limits)
+ sel = rinfo->n_current_limits - 1;
+
+ return rinfo->current_limits[sel];
+}
+
+static int da9063_buck_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+ unsigned val;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = BUCK_MODE_SYNC;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = BUCK_MODE_AUTO;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ val = BUCK_MODE_SLEEP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_field_write(regl->mode, val);
+}
+
+/*
+ * Bucks use single mode register field for normal operation
+ * and suspend state.
+ * There are 3 modes to map to: FAST, NORMAL, and STANDBY.
+ */
+
+static unsigned da9063_buck_get_mode(struct regulator_dev *rdev)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+ struct regmap_field *field;
+ unsigned int val, mode = 0;
+ int ret;
+
+ ret = regmap_field_read(regl->mode, &val);
+ if (ret < 0)
+ return ret;
+
+ switch (val) {
+ default:
+ case BUCK_MODE_MANUAL:
+ mode = REGULATOR_MODE_FAST | REGULATOR_MODE_STANDBY;
+ /* Sleep flag bit decides the mode */
+ break;
+ case BUCK_MODE_SLEEP:
+ return REGULATOR_MODE_STANDBY;
+ case BUCK_MODE_SYNC:
+ return REGULATOR_MODE_FAST;
+ case BUCK_MODE_AUTO:
+ return REGULATOR_MODE_NORMAL;
+ }
+
+ /* Detect current regulator state */
+ ret = regmap_field_read(regl->suspend, &val);
+ if (ret < 0)
+ return 0;
+
+ /* Read regulator mode from proper register, depending on state */
+ if (val)
+ field = regl->suspend_sleep;
+ else
+ field = regl->sleep;
+
+ ret = regmap_field_read(field, &val);
+ if (ret < 0)
+ return 0;
+
+ if (val)
+ mode &= REGULATOR_MODE_STANDBY;
+ else
+ mode &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST;
+
+ return mode;
+}
+
+/*
+ * LDOs use sleep flags - one for normal and one for suspend state.
+ * There are 2 modes to map to: NORMAL and STANDBY (sleep) for each state.
+ */
+
+static int da9063_ldo_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+ unsigned val;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ val = 0;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ val = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_field_write(regl->sleep, val);
+}
+
+static unsigned da9063_ldo_get_mode(struct regulator_dev *rdev)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+ struct regmap_field *field;
+ int ret, val;
+
+ /* Detect current regulator state */
+ ret = regmap_field_read(regl->suspend, &val);
+ if (ret < 0)
+ return 0;
+
+ /* Read regulator mode from proper register, depending on state */
+ if (val)
+ field = regl->suspend_sleep;
+ else
+ field = regl->sleep;
+
+ ret = regmap_field_read(field, &val);
+ if (ret < 0)
+ return 0;
+
+ if (val)
+ return REGULATOR_MODE_STANDBY;
+ else
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int da9063_buck_get_status(struct regulator_dev *rdev)
+{
+ int ret = regulator_is_enabled_regmap(rdev);
+
+ if (ret == 0) {
+ ret = REGULATOR_STATUS_OFF;
+ } else if (ret > 0) {
+ ret = da9063_buck_get_mode(rdev);
+ if (ret > 0)
+ ret = regulator_mode_to_status(ret);
+ else if (ret == 0)
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int da9063_ldo_get_status(struct regulator_dev *rdev)
+{
+ int ret = regulator_is_enabled_regmap(rdev);
+
+ if (ret == 0) {
+ ret = REGULATOR_STATUS_OFF;
+ } else if (ret > 0) {
+ ret = da9063_ldo_get_mode(rdev);
+ if (ret > 0)
+ ret = regulator_mode_to_status(ret);
+ else if (ret == 0)
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int da9063_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+ const struct da9063_regulator_info *rinfo = regl->info;
+ int ret, sel;
+
+ sel = regulator_map_voltage_linear(rdev, uV, uV);
+ if (sel < 0)
+ return -EINVAL;
+
+ sel <<= ffs(rdev->desc->vsel_mask) - 1;
+
+ ret = regmap_update_bits(regl->hw->regmap, rinfo->suspend_vsel_reg,
+ rdev->desc->vsel_mask, sel);
+
+ return ret;
+}
+
+static int da9063_suspend_enable(struct regulator_dev *rdev)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+
+ return regmap_field_write(regl->suspend, 1);
+}
+
+static int da9063_suspend_disable(struct regulator_dev *rdev)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+
+ return regmap_field_write(regl->suspend, 0);
+}
+
+static int da9063_buck_set_suspend_mode(struct regulator_dev *rdev, unsigned mode)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+ int val;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = BUCK_MODE_SYNC;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = BUCK_MODE_AUTO;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ val = BUCK_MODE_SLEEP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_field_write(regl->mode, val);
+}
+
+static int da9063_ldo_set_suspend_mode(struct regulator_dev *rdev, unsigned mode)
+{
+ struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+ unsigned val;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ val = 0;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ val = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_field_write(regl->suspend_sleep, val);
+}
+
+static struct regulator_ops da9063_buck_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_current_limit = da9063_set_current_limit,
+ .get_current_limit = da9063_get_current_limit,
+ .set_mode = da9063_buck_set_mode,
+ .get_mode = da9063_buck_get_mode,
+ .get_status = da9063_buck_get_status,
+ .set_suspend_voltage = da9063_set_suspend_voltage,
+ .set_suspend_enable = da9063_suspend_enable,
+ .set_suspend_disable = da9063_suspend_disable,
+ .set_suspend_mode = da9063_buck_set_suspend_mode,
+};
+
+static struct regulator_ops da9063_ldo_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_mode = da9063_ldo_set_mode,
+ .get_mode = da9063_ldo_get_mode,
+ .get_status = da9063_ldo_get_status,
+ .set_suspend_voltage = da9063_set_suspend_voltage,
+ .set_suspend_enable = da9063_suspend_enable,
+ .set_suspend_disable = da9063_suspend_disable,
+ .set_suspend_mode = da9063_ldo_set_suspend_mode,
+};
+
+/* Info of regulators for DA9063 */
+static const struct da9063_regulator_info da9063_regulator_info[] = {
+ {
+ DA9063_BUCK(DA9063, BCORE1, 300, 10, 1570,
+ da9063_buck_a_limits),
+ DA9063_BUCK_COMMON_FIELDS(BCORE1),
+ .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE1_SEL),
+ .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_C,
+ DA9063_BCORE1_ILIM_MASK),
+ },
+ {
+ DA9063_BUCK(DA9063, BCORE2, 300, 10, 1570,
+ da9063_buck_a_limits),
+ DA9063_BUCK_COMMON_FIELDS(BCORE2),
+ .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE2_SEL),
+ .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_C,
+ DA9063_BCORE2_ILIM_MASK),
+ },
+ {
+ DA9063_BUCK(DA9063, BPRO, 530, 10, 1800,
+ da9063_buck_a_limits),
+ DA9063_BUCK_COMMON_FIELDS(BPRO),
+ .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBPRO_SEL),
+ .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_B,
+ DA9063_BPRO_ILIM_MASK),
+ },
+ {
+ DA9063_BUCK(DA9063, BMEM, 800, 20, 3340,
+ da9063_buck_b_limits),
+ DA9063_BUCK_COMMON_FIELDS(BMEM),
+ .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBMEM_SEL),
+ .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_A,
+ DA9063_BMEM_ILIM_MASK),
+ },
+ {
+ DA9063_BUCK(DA9063, BIO, 800, 20, 3340,
+ da9063_buck_b_limits),
+ DA9063_BUCK_COMMON_FIELDS(BIO),
+ .suspend = BFIELD(DA9063_REG_DVC_2, DA9063_VBIO_SEL),
+ .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_A,
+ DA9063_BIO_ILIM_MASK),
+ },
+ {
+ DA9063_BUCK(DA9063, BPERI, 800, 20, 3340,
+ da9063_buck_b_limits),
+ DA9063_BUCK_COMMON_FIELDS(BPERI),
+ .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBPERI_SEL),
+ .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_B,
+ DA9063_BPERI_ILIM_MASK),
+ },
+ {
+ DA9063_BUCK(DA9063, BCORES_MERGED, 300, 10, 1570,
+ da9063_bcores_merged_limits),
+ /* BCORES_MERGED uses the same register fields as BCORE1 */
+ DA9063_BUCK_COMMON_FIELDS(BCORE1),
+ .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE1_SEL),
+ .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_C,
+ DA9063_BCORE1_ILIM_MASK),
+ },
+ {
+ DA9063_BUCK(DA9063, BMEM_BIO_MERGED, 800, 20, 3340,
+ da9063_bmem_bio_merged_limits),
+ /* BMEM_BIO_MERGED uses the same register fields as BMEM */
+ DA9063_BUCK_COMMON_FIELDS(BMEM),
+ .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBMEM_SEL),
+ .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_A,
+ DA9063_BMEM_ILIM_MASK),
+ },
+ {
+ DA9063_LDO(DA9063, LDO1, 600, 20, 1860),
+ .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO1_SEL),
+ },
+ {
+ DA9063_LDO(DA9063, LDO2, 600, 20, 1860),
+ .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO2_SEL),
+ },
+ {
+ DA9063_LDO(DA9063, LDO3, 900, 20, 3440),
+ .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO3_SEL),
+ .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO3_LIM),
+ },
+ {
+ DA9063_LDO(DA9063, LDO4, 900, 20, 3440),
+ .suspend = BFIELD(DA9063_REG_DVC_2, DA9063_VLDO4_SEL),
+ .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO4_LIM),
+ },
+ {
+ DA9063_LDO(DA9063, LDO5, 900, 50, 3600),
+ .suspend = BFIELD(DA9063_REG_LDO5_CONT, DA9063_VLDO5_SEL),
+ },
+ {
+ DA9063_LDO(DA9063, LDO6, 900, 50, 3600),
+ .suspend = BFIELD(DA9063_REG_LDO6_CONT, DA9063_VLDO6_SEL),
+ },
+ {
+ DA9063_LDO(DA9063, LDO7, 900, 50, 3600),
+ .suspend = BFIELD(DA9063_REG_LDO7_CONT, DA9063_VLDO7_SEL),
+ .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO7_LIM),
+ },
+ {
+ DA9063_LDO(DA9063, LDO8, 900, 50, 3600),
+ .suspend = BFIELD(DA9063_REG_LDO8_CONT, DA9063_VLDO8_SEL),
+ .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO8_LIM),
+ },
+ {
+ DA9063_LDO(DA9063, LDO9, 950, 50, 3600),
+ .suspend = BFIELD(DA9063_REG_LDO9_CONT, DA9063_VLDO9_SEL),
+ },
+ {
+ DA9063_LDO(DA9063, LDO10, 900, 50, 3600),
+ .suspend = BFIELD(DA9063_REG_LDO10_CONT, DA9063_VLDO10_SEL),
+ },
+ {
+ DA9063_LDO(DA9063, LDO11, 900, 50, 3600),
+ .suspend = BFIELD(DA9063_REG_LDO11_CONT, DA9063_VLDO11_SEL),
+ .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO11_LIM),
+ },
+};
+
+/* Link chip model with regulators info table */
+static struct da9063_dev_model regulators_models[] = {
+ {
+ .regulator_info = da9063_regulator_info,
+ .n_regulators = ARRAY_SIZE(da9063_regulator_info),
+ .dev_model = PMIC_DA9063,
+ },
+ { }
+};
+
+/* Regulator interrupt handlers */
+static irqreturn_t da9063_ldo_lim_event(int irq, void *data)
+{
+ struct da9063_regulators *regulators = data;
+ struct da9063 *hw = regulators->regulator[0].hw;
+ struct da9063_regulator *regl;
+ int bits, i , ret;
+
+ ret = regmap_read(hw->regmap, DA9063_REG_STATUS_D, &bits);
+ if (ret < 0)
+ return IRQ_NONE;
+
+ for (i = regulators->n_regulators - 1; i >= 0; i--) {
+ regl = &regulators->regulator[i];
+ if (regl->info->oc_event.reg != DA9063_REG_STATUS_D)
+ continue;
+
+ if (BIT(regl->info->oc_event.lsb) & bits)
+ regulator_notifier_call_chain(regl->rdev,
+ REGULATOR_EVENT_OVER_CURRENT, NULL);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Probing and Initialisation functions
+ */
+static const struct regulator_init_data *da9063_get_regulator_initdata(
+ const struct da9063_regulators_pdata *regl_pdata, int id)
+{
+ int i;
+
+ for (i = 0; i < regl_pdata->n_regulators; i++) {
+ if (id == regl_pdata->regulator_data[i].id)
+ return regl_pdata->regulator_data[i].initdata;
+ }
+
+ return NULL;
+}
+
+#ifdef CONFIG_OF
+static struct of_regulator_match da9063_matches[] = {
+ [DA9063_ID_BCORE1] = { .name = "bcore1" },
+ [DA9063_ID_BCORE2] = { .name = "bcore2" },
+ [DA9063_ID_BPRO] = { .name = "bpro", },
+ [DA9063_ID_BMEM] = { .name = "bmem", },
+ [DA9063_ID_BIO] = { .name = "bio", },
+ [DA9063_ID_BPERI] = { .name = "bperi", },
+ [DA9063_ID_BCORES_MERGED] = { .name = "bcores-merged" },
+ [DA9063_ID_BMEM_BIO_MERGED] = { .name = "bmem-bio-merged", },
+ [DA9063_ID_LDO1] = { .name = "ldo1", },
+ [DA9063_ID_LDO2] = { .name = "ldo2", },
+ [DA9063_ID_LDO3] = { .name = "ldo3", },
+ [DA9063_ID_LDO4] = { .name = "ldo4", },
+ [DA9063_ID_LDO5] = { .name = "ldo5", },
+ [DA9063_ID_LDO6] = { .name = "ldo6", },
+ [DA9063_ID_LDO7] = { .name = "ldo7", },
+ [DA9063_ID_LDO8] = { .name = "ldo8", },
+ [DA9063_ID_LDO9] = { .name = "ldo9", },
+ [DA9063_ID_LDO10] = { .name = "ldo10", },
+ [DA9063_ID_LDO11] = { .name = "ldo11", },
+};
+
+static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
+ struct platform_device *pdev,
+ struct of_regulator_match **da9063_reg_matches)
+{
+ struct da9063_regulators_pdata *pdata;
+ struct da9063_regulator_data *rdata;
+ struct device_node *node;
+ int i, n, num;
+
+ node = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+ if (!node) {
+ dev_err(&pdev->dev, "Regulators device node not found\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ num = of_regulator_match(&pdev->dev, node, da9063_matches,
+ ARRAY_SIZE(da9063_matches));
+ if (num < 0) {
+ dev_err(&pdev->dev, "Failed to match regulators\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->regulator_data = devm_kzalloc(&pdev->dev,
+ num * sizeof(*pdata->regulator_data),
+ GFP_KERNEL);
+ if (!pdata->regulator_data)
+ return ERR_PTR(-ENOMEM);
+ pdata->n_regulators = num;
+
+ n = 0;
+ for (i = 0; i < ARRAY_SIZE(da9063_matches); i++) {
+ if (!da9063_matches[i].init_data)
+ continue;
+
+ rdata = &pdata->regulator_data[n];
+ rdata->id = i;
+ rdata->initdata = da9063_matches[i].init_data;
+
+ n++;
+ };
+
+ *da9063_reg_matches = da9063_matches;
+ return pdata;
+}
+#else
+static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
+ struct platform_device *pdev,
+ struct of_regulator_match **da9063_reg_matches)
+{
+ da9063_reg_matches = NULL;
+ return PTR_ERR(-ENODEV);
+}
+#endif
+
+static int da9063_regulator_probe(struct platform_device *pdev)
+{
+ struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
+ struct da9063_pdata *da9063_pdata = dev_get_platdata(da9063->dev);
+ struct of_regulator_match *da9063_reg_matches;
+ struct da9063_regulators_pdata *regl_pdata;
+ const struct da9063_dev_model *model;
+ struct da9063_regulators *regulators;
+ struct da9063_regulator *regl;
+ struct regulator_config config;
+ bool bcores_merged, bmem_bio_merged;
+ int id, irq, n, n_regulators, ret, val;
+ size_t size;
+
+ regl_pdata = da9063_pdata ? da9063_pdata->regulators_pdata : NULL;
+
+ if (!regl_pdata)
+ regl_pdata = da9063_parse_regulators_dt(pdev,
+ &da9063_reg_matches);
+
+ if (IS_ERR(regl_pdata) || regl_pdata->n_regulators == 0) {
+ dev_err(&pdev->dev,
+ "No regulators defined for the platform\n");
+ return PTR_ERR(regl_pdata);
+ }
+
+ /* Find regulators set for particular device model */
+ for (model = regulators_models; model->regulator_info; model++) {
+ if (model->dev_model == da9063->model)
+ break;
+ }
+ if (!model->regulator_info) {
+ dev_err(&pdev->dev, "Chip model not recognised (%u)\n",
+ da9063->model);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(da9063->regmap, DA9063_REG_CONFIG_H, &val);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Error while reading BUCKs configuration\n");
+ return -EIO;
+ }
+ bcores_merged = val & DA9063_BCORE_MERGE;
+ bmem_bio_merged = val & DA9063_BUCK_MERGE;
+
+ n_regulators = model->n_regulators;
+ if (bcores_merged)
+ n_regulators -= 2; /* remove BCORE1, BCORE2 */
+ else
+ n_regulators--; /* remove BCORES_MERGED */
+ if (bmem_bio_merged)
+ n_regulators -= 2; /* remove BMEM, BIO */
+ else
+ n_regulators--; /* remove BMEM_BIO_MERGED */
+
+ /* Allocate memory required by usable regulators */
+ size = sizeof(struct da9063_regulators) +
+ n_regulators * sizeof(struct da9063_regulator);
+ regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ if (!regulators) {
+ dev_err(&pdev->dev, "No memory for regulators\n");
+ return -ENOMEM;
+ }
+
+ regulators->n_regulators = n_regulators;
+ platform_set_drvdata(pdev, regulators);
+
+ /* Register all regulators declared in platform information */
+ n = 0;
+ id = 0;
+ while (n < regulators->n_regulators) {
+ /* Skip regulator IDs depending on merge mode configuration */
+ switch (id) {
+ case DA9063_ID_BCORE1:
+ case DA9063_ID_BCORE2:
+ if (bcores_merged) {
+ id++;
+ continue;
+ }
+ break;
+ case DA9063_ID_BMEM:
+ case DA9063_ID_BIO:
+ if (bmem_bio_merged) {
+ id++;
+ continue;
+ }
+ break;
+ case DA9063_ID_BCORES_MERGED:
+ if (!bcores_merged) {
+ id++;
+ continue;
+ }
+ break;
+ case DA9063_ID_BMEM_BIO_MERGED:
+ if (!bmem_bio_merged) {
+ id++;
+ continue;
+ }
+ break;
+ }
+
+ /* Initialise regulator structure */
+ regl = &regulators->regulator[n];
+ regl->hw = da9063;
+ regl->info = &model->regulator_info[id];
+ regl->desc = regl->info->desc;
+ regl->desc.type = REGULATOR_VOLTAGE;
+ regl->desc.owner = THIS_MODULE;
+
+ if (regl->info->mode.reg)
+ regl->mode = devm_regmap_field_alloc(&pdev->dev,
+ da9063->regmap, regl->info->mode);
+ if (regl->info->suspend.reg)
+ regl->suspend = devm_regmap_field_alloc(&pdev->dev,
+ da9063->regmap, regl->info->suspend);
+ if (regl->info->sleep.reg)
+ regl->sleep = devm_regmap_field_alloc(&pdev->dev,
+ da9063->regmap, regl->info->sleep);
+ if (regl->info->suspend_sleep.reg)
+ regl->suspend_sleep = devm_regmap_field_alloc(&pdev->dev,
+ da9063->regmap, regl->info->suspend_sleep);
+ if (regl->info->ilimit.reg)
+ regl->ilimit = devm_regmap_field_alloc(&pdev->dev,
+ da9063->regmap, regl->info->ilimit);
+
+ /* Register regulator */
+ memset(&config, 0, sizeof(config));
+ config.dev = &pdev->dev;
+ config.init_data = da9063_get_regulator_initdata(regl_pdata, id);
+ config.driver_data = regl;
+ if (da9063_reg_matches)
+ config.of_node = da9063_reg_matches[id].of_node;
+ config.regmap = da9063->regmap;
+ regl->rdev = regulator_register(&regl->desc, &config);
+ if (IS_ERR(regl->rdev)) {
+ dev_err(&pdev->dev,
+ "Failed to register %s regulator\n",
+ regl->desc.name);
+ ret = PTR_ERR(regl->rdev);
+ goto err;
+ }
+ id++;
+ n++;
+ }
+
+ /* LDOs overcurrent event support */
+ irq = platform_get_irq_byname(pdev, "LDO_LIM");
+ if (irq < 0) {
+ ret = irq;
+ dev_err(&pdev->dev, "Failed to get IRQ.\n");
+ goto err;
+ }
+
+ regulators->irq_ldo_lim = regmap_irq_get_virq(da9063->regmap_irq, irq);
+ if (regulators->irq_ldo_lim >= 0) {
+ ret = request_threaded_irq(regulators->irq_ldo_lim,
+ NULL, da9063_ldo_lim_event,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "LDO_LIM", regulators);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request LDO_LIM IRQ.\n");
+ regulators->irq_ldo_lim = -ENXIO;
+ }
+ }
+
+ return 0;
+
+err:
+ /* Wind back regulators registeration */
+ while (--n >= 0)
+ regulator_unregister(regulators->regulator[n].rdev);
+
+ return ret;
+}
+
+static int da9063_regulator_remove(struct platform_device *pdev)
+{
+ struct da9063_regulators *regulators = platform_get_drvdata(pdev);
+ struct da9063_regulator *regl;
+
+ free_irq(regulators->irq_ldo_lim, regulators);
+ free_irq(regulators->irq_uvov, regulators);
+
+ for (regl = &regulators->regulator[regulators->n_regulators - 1];
+ regl >= &regulators->regulator[0]; regl--)
+ regulator_unregister(regl->rdev);
+
+ return 0;
+}
+
+static struct platform_driver da9063_regulator_driver = {
+ .driver = {
+ .name = DA9063_DRVNAME_REGULATORS,
+ .owner = THIS_MODULE,
+ },
+ .probe = da9063_regulator_probe,
+ .remove = da9063_regulator_remove,
+};
+
+static int __init da9063_regulator_init(void)
+{
+ return platform_driver_register(&da9063_regulator_driver);
+}
+subsys_initcall(da9063_regulator_init);
+
+static void __exit da9063_regulator_cleanup(void)
+{
+ platform_driver_unregister(&da9063_regulator_driver);
+}
+module_exit(da9063_regulator_cleanup);
+
+
+/* Module information */
+MODULE_AUTHOR("Krystian Garbaciak <krystian.garbaciak@diasemi.com>");
+MODULE_DESCRIPTION("DA9063 regulators driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("paltform:" DA9063_DRVNAME_REGULATORS);
diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c
new file mode 100644
index 00000000000..f0fe54b3897
--- /dev/null
+++ b/drivers/regulator/da9210-regulator.c
@@ -0,0 +1,196 @@
+/*
+ * da9210-regulator.c - Regulator device driver for DA9210
+ * Copyright (C) 2013 Dialog Semiconductor Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regmap.h>
+
+#include "da9210-regulator.h"
+
+struct da9210 {
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+};
+
+static const struct regmap_config da9210_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA,
+ int max_uA);
+static int da9210_get_current_limit(struct regulator_dev *rdev);
+
+static struct regulator_ops da9210_buck_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_current_limit = da9210_set_current_limit,
+ .get_current_limit = da9210_get_current_limit,
+};
+
+/* Default limits measured in millivolts and milliamps */
+#define DA9210_MIN_MV 300
+#define DA9210_MAX_MV 1570
+#define DA9210_STEP_MV 10
+
+/* Current limits for buck (uA) indices corresponds with register values */
+static const int da9210_buck_limits[] = {
+ 1600000, 1800000, 2000000, 2200000, 2400000, 2600000, 2800000, 3000000,
+ 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 4600000
+};
+
+static const struct regulator_desc da9210_reg = {
+ .name = "DA9210",
+ .id = 0,
+ .ops = &da9210_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = ((DA9210_MAX_MV - DA9210_MIN_MV) / DA9210_STEP_MV) + 1,
+ .min_uV = (DA9210_MIN_MV * 1000),
+ .uV_step = (DA9210_STEP_MV * 1000),
+ .vsel_reg = DA9210_REG_VBUCK_A,
+ .vsel_mask = DA9210_VBUCK_MASK,
+ .enable_reg = DA9210_REG_BUCK_CONT,
+ .enable_mask = DA9210_BUCK_EN,
+ .owner = THIS_MODULE,
+};
+
+static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA,
+ int max_uA)
+{
+ struct da9210 *chip = rdev_get_drvdata(rdev);
+ unsigned int sel;
+ int i;
+
+ /* search for closest to maximum */
+ for (i = ARRAY_SIZE(da9210_buck_limits)-1; i >= 0; i--) {
+ if (min_uA <= da9210_buck_limits[i] &&
+ max_uA >= da9210_buck_limits[i]) {
+ sel = i;
+ sel = sel << DA9210_BUCK_ILIM_SHIFT;
+ return regmap_update_bits(chip->regmap,
+ DA9210_REG_BUCK_ILIM,
+ DA9210_BUCK_ILIM_MASK, sel);
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int da9210_get_current_limit(struct regulator_dev *rdev)
+{
+ struct da9210 *chip = rdev_get_drvdata(rdev);
+ unsigned int data;
+ unsigned int sel;
+ int ret;
+
+ ret = regmap_read(chip->regmap, DA9210_REG_BUCK_ILIM, &data);
+ if (ret < 0)
+ return ret;
+
+ /* select one of 16 values: 0000 (1600mA) to 1111 (4600mA) */
+ sel = (data & DA9210_BUCK_ILIM_MASK) >> DA9210_BUCK_ILIM_SHIFT;
+
+ return da9210_buck_limits[sel];
+}
+
+/*
+ * I2C driver interface functions
+ */
+static int da9210_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct da9210 *chip;
+ struct da9210_pdata *pdata = i2c->dev.platform_data;
+ struct regulator_dev *rdev = NULL;
+ struct regulator_config config = { };
+ int error;
+
+ chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL);
+ if (NULL == chip) {
+ dev_err(&i2c->dev,
+ "Cannot kzalloc memory for regulator structure\n");
+ return -ENOMEM;
+ }
+
+ chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ error = PTR_ERR(chip->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ error);
+ return error;
+ }
+
+ config.dev = &i2c->dev;
+ if (pdata)
+ config.init_data = &pdata->da9210_constraints;
+ config.driver_data = chip;
+ config.regmap = chip->regmap;
+
+ rdev = regulator_register(&da9210_reg, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&i2c->dev, "Failed to register DA9210 regulator\n");
+ return PTR_ERR(rdev);
+ }
+
+ chip->rdev = rdev;
+
+ i2c_set_clientdata(i2c, chip);
+
+ return 0;
+}
+
+static int da9210_i2c_remove(struct i2c_client *i2c)
+{
+ struct da9210 *chip = i2c_get_clientdata(i2c);
+ regulator_unregister(chip->rdev);
+ return 0;
+}
+
+static const struct i2c_device_id da9210_i2c_id[] = {
+ {"da9210", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, da9210_i2c_id);
+
+static struct i2c_driver da9210_regulator_driver = {
+ .driver = {
+ .name = "da9210",
+ .owner = THIS_MODULE,
+ },
+ .probe = da9210_i2c_probe,
+ .remove = da9210_i2c_remove,
+ .id_table = da9210_i2c_id,
+};
+
+module_i2c_driver(da9210_regulator_driver);
+
+MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
+MODULE_DESCRIPTION("Regulator device driver for Dialog DA9210");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/da9210-regulator.h b/drivers/regulator/da9210-regulator.h
new file mode 100644
index 00000000000..749c550808b
--- /dev/null
+++ b/drivers/regulator/da9210-regulator.h
@@ -0,0 +1,288 @@
+
+/*
+ * da9210-regulator.h - Regulator definitions for DA9210
+ * Copyright (C) 2013 Dialog Semiconductor Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __DA9210_REGISTERS_H__
+#define __DA9210_REGISTERS_H__
+
+struct da9210_pdata {
+ struct regulator_init_data da9210_constraints;
+};
+
+/* Page selection */
+#define DA9210_REG_PAGE_CON 0x00
+
+/* System Control and Event Registers */
+#define DA9210_REG_STATUS_A 0x50
+#define DA9210_REG_STATUS_B 0x51
+#define DA9210_REG_EVENT_A 0x52
+#define DA9210_REG_EVENT_B 0x53
+#define DA9210_REG_MASK_A 0x54
+#define DA9210_REG_MASK_B 0x55
+#define DA9210_REG_CONTROL_A 0x56
+
+/* GPIO Control Registers */
+#define DA9210_REG_GPIO_0_1 0x58
+#define DA9210_REG_GPIO_2_3 0x59
+#define DA9210_REG_GPIO_4_5 0x5A
+#define DA9210_REG_GPIO_6 0x5B
+
+/* Regulator Registers */
+#define DA9210_REG_BUCK_CONT 0x5D
+#define DA9210_REG_BUCK_ILIM 0xD0
+#define DA9210_REG_BUCK_CONF1 0xD1
+#define DA9210_REG_BUCK_CONF2 0xD2
+#define DA9210_REG_VBACK_AUTO 0xD4
+#define DA9210_REG_VBACK_BASE 0xD5
+#define DA9210_REG_VBACK_MAX_DVC_IF 0xD6
+#define DA9210_REG_VBACK_DVC 0xD7
+#define DA9210_REG_VBUCK_A 0xD8
+#define DA9210_REG_VBUCK_B 0xD9
+
+/* I2C Interface Settings */
+#define DA9210_REG_INTERFACE 0x105
+
+/* OTP */
+#define DA9210_REG_OPT_COUNT 0x140
+#define DA9210_REG_OPT_ADDR 0x141
+#define DA9210_REG_OPT_DATA 0x142
+
+/* Customer Trim and Configuration */
+#define DA9210_REG_CONFIG_A 0x143
+#define DA9210_REG_CONFIG_B 0x144
+#define DA9210_REG_CONFIG_C 0x145
+#define DA9210_REG_CONFIG_D 0x146
+#define DA9210_REG_CONFIG_E 0x147
+
+
+/*
+ * Registers bits
+ */
+/* DA9210_REG_PAGE_CON (addr=0x00) */
+#define DA9210_PEG_PAGE_SHIFT 0
+#define DA9210_REG_PAGE_MASK 0x0F
+/* On I2C registers 0x00 - 0xFF */
+#define DA9210_REG_PAGE0 0
+/* On I2C registers 0x100 - 0x1FF */
+#define DA9210_REG_PAGE2 2
+#define DA9210_PAGE_WRITE_MODE 0x00
+#define DA9210_REPEAT_WRITE_MODE 0x40
+#define DA9210_PAGE_REVERT 0x80
+
+/* DA9210_REG_STATUS_A (addr=0x50) */
+#define DA9210_GPI0 0x01
+#define DA9210_GPI1 0x02
+#define DA9210_GPI2 0x04
+#define DA9210_GPI3 0x08
+#define DA9210_GPI4 0x10
+#define DA9210_GPI5 0x20
+#define DA9210_GPI6 0x40
+
+/* DA9210_REG_EVENT_A (addr=0x52) */
+#define DA9210_E_GPI0 0x01
+#define DA9210_E_GPI1 0x02
+#define DA9210_E_GPI2 0x04
+#define DA9210_E_GPI3 0x08
+#define DA9210_E_GPI4 0x10
+#define DA9210_E_GPI5 0x20
+#define DA9210_E_GPI6 0x40
+
+/* DA9210_REG_EVENT_B (addr=0x53) */
+#define DA9210_E_OVCURR 0x01
+#define DA9210_E_NPWRGOOD 0x02
+#define DA9210_E_TEMP_WARN 0x04
+#define DA9210_E_TEMP_CRIT 0x08
+#define DA9210_E_VMAX 0x10
+
+/* DA9210_REG_MASK_A (addr=0x54) */
+#define DA9210_M_GPI0 0x01
+#define DA9210_M_GPI1 0x02
+#define DA9210_M_GPI2 0x04
+#define DA9210_M_GPI3 0x08
+#define DA9210_M_GPI4 0x10
+#define DA9210_M_GPI5 0x20
+#define DA9210_M_GPI6 0x40
+
+/* DA9210_REG_MASK_B (addr=0x55) */
+#define DA9210_M_OVCURR 0x01
+#define DA9210_M_NPWRGOOD 0x02
+#define DA9210_M_TEMP_WARN 0x04
+#define DA9210_M_TEMP_CRIT 0x08
+#define DA9210_M_VMAX 0x10
+
+/* DA9210_REG_CONTROL_A (addr=0x56) */
+#define DA9210_DEBOUNCING_SHIFT 0
+#define DA9210_DEBOUNCING_MASK 0x07
+#define DA9210_SLEW_RATE_SHIFT 3
+#define DA9210_SLEW_RATE_MASK 0x18
+#define DA9210_V_LOCK 0x20
+
+/* DA9210_REG_GPIO_0_1 (addr=0x58) */
+#define DA9210_GPIO0_PIN_SHIFT 0
+#define DA9210_GPIO0_PIN_MASK 0x03
+#define DA9210_GPIO0_PIN_GPI 0x00
+#define DA9210_GPIO0_PIN_GPO_OD 0x02
+#define DA9210_GPIO0_PIN_GPO 0x03
+#define DA9210_GPIO0_TYPE 0x04
+#define DA9210_GPIO0_TYPE_GPI 0x00
+#define DA9210_GPIO0_TYPE_GPO 0x04
+#define DA9210_GPIO0_MODE 0x08
+#define DA9210_GPIO1_PIN_SHIFT 4
+#define DA9210_GPIO1_PIN_MASK 0x30
+#define DA9210_GPIO1_PIN_GPI 0x00
+#define DA9210_GPIO1_PIN_VERROR 0x10
+#define DA9210_GPIO1_PIN_GPO_OD 0x20
+#define DA9210_GPIO1_PIN_GPO 0x30
+#define DA9210_GPIO1_TYPE_SHIFT 0x40
+#define DA9210_GPIO1_TYPE_GPI 0x00
+#define DA9210_GPIO1_TYPE_GPO 0x40
+#define DA9210_GPIO1_MODE 0x80
+
+/* DA9210_REG_GPIO_2_3 (addr=0x59) */
+#define DA9210_GPIO2_PIN_SHIFT 0
+#define DA9210_GPIO2_PIN_MASK 0x03
+#define DA9210_GPIO2_PIN_GPI 0x00
+#define DA9210_GPIO5_PIN_BUCK_CLK 0x10
+#define DA9210_GPIO2_PIN_GPO_OD 0x02
+#define DA9210_GPIO2_PIN_GPO 0x03
+#define DA9210_GPIO2_TYPE 0x04
+#define DA9210_GPIO2_TYPE_GPI 0x00
+#define DA9210_GPIO2_TYPE_GPO 0x04
+#define DA9210_GPIO2_MODE 0x08
+#define DA9210_GPIO3_PIN_SHIFT 4
+#define DA9210_GPIO3_PIN_MASK 0x30
+#define DA9210_GPIO3_PIN_GPI 0x00
+#define DA9210_GPIO3_PIN_IERROR 0x10
+#define DA9210_GPIO3_PIN_GPO_OD 0x20
+#define DA9210_GPIO3_PIN_GPO 0x30
+#define DA9210_GPIO3_TYPE_SHIFT 0x40
+#define DA9210_GPIO3_TYPE_GPI 0x00
+#define DA9210_GPIO3_TYPE_GPO 0x40
+#define DA9210_GPIO3_MODE 0x80
+
+/* DA9210_REG_GPIO_4_5 (addr=0x5A) */
+#define DA9210_GPIO4_PIN_SHIFT 0
+#define DA9210_GPIO4_PIN_MASK 0x03
+#define DA9210_GPIO4_PIN_GPI 0x00
+#define DA9210_GPIO4_PIN_GPO_OD 0x02
+#define DA9210_GPIO4_PIN_GPO 0x03
+#define DA9210_GPIO4_TYPE 0x04
+#define DA9210_GPIO4_TYPE_GPI 0x00
+#define DA9210_GPIO4_TYPE_GPO 0x04
+#define DA9210_GPIO4_MODE 0x08
+#define DA9210_GPIO5_PIN_SHIFT 4
+#define DA9210_GPIO5_PIN_MASK 0x30
+#define DA9210_GPIO5_PIN_GPI 0x00
+#define DA9210_GPIO5_PIN_INTERFACE 0x01
+#define DA9210_GPIO5_PIN_GPO_OD 0x20
+#define DA9210_GPIO5_PIN_GPO 0x30
+#define DA9210_GPIO5_TYPE_SHIFT 0x40
+#define DA9210_GPIO5_TYPE_GPI 0x00
+#define DA9210_GPIO5_TYPE_GPO 0x40
+#define DA9210_GPIO5_MODE 0x80
+
+/* DA9210_REG_GPIO_6 (addr=0x5B) */
+#define DA9210_GPIO6_PIN_SHIFT 0
+#define DA9210_GPIO6_PIN_MASK 0x03
+#define DA9210_GPIO6_PIN_GPI 0x00
+#define DA9210_GPIO6_PIN_INTERFACE 0x01
+#define DA9210_GPIO6_PIN_GPO_OD 0x02
+#define DA9210_GPIO6_PIN_GPO 0x03
+#define DA9210_GPIO6_TYPE 0x04
+#define DA9210_GPIO6_TYPE_GPI 0x00
+#define DA9210_GPIO6_TYPE_GPO 0x04
+#define DA9210_GPIO6_MODE 0x08
+
+/* DA9210_REG_BUCK_CONT (addr=0x5D) */
+#define DA9210_BUCK_EN 0x01
+#define DA9210_BUCK_GPI_SHIFT 1
+#define DA9210_BUCK_GPI_MASK 0x06
+#define DA9210_BUCK_GPI_OFF 0x00
+#define DA9210_BUCK_GPI_GPIO0 0x02
+#define DA9210_BUCK_GPI_GPIO3 0x04
+#define DA9210_BUCK_GPI_GPIO4 0x06
+#define DA9210_BUCK_PD_DIS 0x08
+#define DA9210_VBUCK_SEL 0x10
+#define DA9210_VBUCK_SEL_A 0x00
+#define DA9210_VBUCK_SEL_B 0x10
+#define DA9210_VBUCK_GPI_SHIFT 5
+#define DA9210_VBUCK_GPI_MASK 0x60
+#define DA9210_VBUCK_GPI_OFF 0x00
+#define DA9210_VBUCK_GPI_GPIO0 0x20
+#define DA9210_VBUCK_GPI_GPIO3 0x40
+#define DA9210_VBUCK_GPI_GPIO4 0x60
+#define DA9210_DVC_CTRL_EN 0x80
+
+/* DA9210_REG_BUCK_ILIM (addr=0xD0) */
+#define DA9210_BUCK_ILIM_SHIFT 0
+#define DA9210_BUCK_ILIM_MASK 0x0F
+#define DA9210_BUCK_IALARM 0x10
+
+/* DA9210_REG_BUCK_CONF1 (addr=0xD1) */
+#define DA9210_BUCK_MODE_SHIFT 0
+#define DA9210_BUCK_MODE_MASK 0x03
+#define DA9210_BUCK_MODE_MANUAL 0x00
+#define DA9210_BUCK_MODE_SLEEP 0x01
+#define DA9210_BUCK_MODE_SYNC 0x02
+#define DA9210_BUCK_MODE_AUTO 0x03
+#define DA9210_STARTUP_CTRL_SHIFT 2
+#define DA9210_STARTUP_CTRL_MASK 0x1C
+#define DA9210_PWR_DOWN_CTRL_SHIFT 5
+#define DA9210_PWR_DOWN_CTRL_MASK 0xE0
+
+/* DA9210_REG_BUCK_CONF2 (addr=0xD2) */
+#define DA9210_PHASE_SEL_SHIFT 0
+#define DA9210_PHASE_SEL_MASK 0x03
+#define DA9210_FREQ_SEL 0x40
+
+/* DA9210_REG_BUCK_AUTO (addr=0xD4) */
+#define DA9210_VBUCK_AUTO_SHIFT 0
+#define DA9210_VBUCK_AUTO_MASK 0x7F
+
+/* DA9210_REG_BUCK_BASE (addr=0xD5) */
+#define DA9210_VBUCK_BASE_SHIFT 0
+#define DA9210_VBUCK_BASE_MASK 0x7F
+
+/* DA9210_REG_VBUCK_MAX_DVC_IF (addr=0xD6) */
+#define DA9210_VBUCK_MAX_SHIFT 0
+#define DA9210_VBUCK_MAX_MASK 0x7F
+#define DA9210_DVC_STEP_SIZE 0x80
+#define DA9210_DVC_STEP_SIZE_10MV 0x00
+#define DA9210_DVC_STEP_SIZE_20MV 0x80
+
+/* DA9210_REG_VBUCK_DVC (addr=0xD7) */
+#define DA9210_VBUCK_DVC_SHIFT 0
+#define DA9210_VBUCK_DVC_MASK 0x7F
+
+/* DA9210_REG_VBUCK_A/B (addr=0xD8/0xD9) */
+#define DA9210_VBUCK_SHIFT 0
+#define DA9210_VBUCK_MASK 0x7F
+#define DA9210_VBUCK_BIAS 0
+#define DA9210_BUCK_SL 0x80
+
+/* DA9210_REG_INTERFACE (addr=0x105) */
+#define DA9210_IF_BASE_ADDR_SHIFT 4
+#define DA9210_IF_BASE_ADDR_MASK 0xF0
+
+/* DA9210_REG_CONFIG_E (addr=0x147) */
+#define DA9210_STAND_ALONE 0x01
+
+#endif /* __DA9210_REGISTERS_H__ */
+
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index f0e1ae52bb0..a32b44272a0 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -237,7 +237,7 @@ static int fan53555_regulator_probe(struct i2c_client *client,
unsigned int val;
int ret;
- pdata = client->dev.platform_data;
+ pdata = dev_get_platdata(&client->dev);
if (!pdata || !pdata->regulator) {
dev_err(&client->dev, "Platform data not found!\n");
return -ENODEV;
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index e5c03b534fa..7610920014d 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -146,7 +146,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
if (IS_ERR(config))
return PTR_ERR(config);
} else {
- config = pdev->dev.platform_data;
+ config = dev_get_platdata(&pdev->dev);
}
if (!config)
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index 9d39eb4aafa..98a98ffa7fe 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -219,7 +219,7 @@ static struct regulator_ops gpio_regulator_current_ops = {
static int gpio_regulator_probe(struct platform_device *pdev)
{
- struct gpio_regulator_config *config = pdev->dev.platform_data;
+ struct gpio_regulator_config *config = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct gpio_regulator_data *drvdata;
struct regulator_config cfg = { };
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
new file mode 100644
index 00000000000..6e30df14714
--- /dev/null
+++ b/drivers/regulator/helpers.c
@@ -0,0 +1,447 @@
+/*
+ * helpers.c -- Voltage/Current Regulator framework helper functions.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ * Copyright 2008 SlimLogic Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/module.h>
+
+/**
+ * regulator_is_enabled_regmap - standard is_enabled() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their is_enabled operation, saving some code.
+ */
+int regulator_is_enabled_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+ if (ret != 0)
+ return ret;
+
+ if (rdev->desc->enable_is_inverted)
+ return (val & rdev->desc->enable_mask) == 0;
+ else
+ return (val & rdev->desc->enable_mask) != 0;
+}
+EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
+
+/**
+ * regulator_enable_regmap - standard enable() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their enable() operation, saving some code.
+ */
+int regulator_enable_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+
+ if (rdev->desc->enable_is_inverted)
+ val = 0;
+ else
+ val = rdev->desc->enable_mask;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_enable_regmap);
+
+/**
+ * regulator_disable_regmap - standard disable() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their disable() operation, saving some code.
+ */
+int regulator_disable_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+
+ if (rdev->desc->enable_is_inverted)
+ val = rdev->desc->enable_mask;
+ else
+ val = 0;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_disable_regmap);
+
+/**
+ * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * vsel_reg and vsel_mask fields in their descriptor and then use this
+ * as their get_voltage_vsel operation, saving some code.
+ */
+int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+ if (ret != 0)
+ return ret;
+
+ val &= rdev->desc->vsel_mask;
+ val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap);
+
+/**
+ * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users
+ *
+ * @rdev: regulator to operate on
+ * @sel: Selector to set
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * vsel_reg and vsel_mask fields in their descriptor and then use this
+ * as their set_voltage_vsel operation, saving some code.
+ */
+int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
+{
+ int ret;
+
+ sel <<= ffs(rdev->desc->vsel_mask) - 1;
+
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+ rdev->desc->vsel_mask, sel);
+ if (ret)
+ return ret;
+
+ if (rdev->desc->apply_bit)
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+ rdev->desc->apply_bit,
+ rdev->desc->apply_bit);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
+
+/**
+ * regulator_map_voltage_iterate - map_voltage() based on list_voltage()
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers implementing set_voltage_sel() and list_voltage() can use
+ * this as their map_voltage() operation. It will find a suitable
+ * voltage by calling list_voltage() until it gets something in bounds
+ * for the requested voltages.
+ */
+int regulator_map_voltage_iterate(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int best_val = INT_MAX;
+ int selector = 0;
+ int i, ret;
+
+ /* Find the smallest voltage that falls within the specified
+ * range.
+ */
+ for (i = 0; i < rdev->desc->n_voltages; i++) {
+ ret = rdev->desc->ops->list_voltage(rdev, i);
+ if (ret < 0)
+ continue;
+
+ if (ret < best_val && ret >= min_uV && ret <= max_uV) {
+ best_val = ret;
+ selector = i;
+ }
+ }
+
+ if (best_val != INT_MAX)
+ return selector;
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate);
+
+/**
+ * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers that have ascendant voltage list can use this as their
+ * map_voltage() operation.
+ */
+int regulator_map_voltage_ascend(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int i, ret;
+
+ for (i = 0; i < rdev->desc->n_voltages; i++) {
+ ret = rdev->desc->ops->list_voltage(rdev, i);
+ if (ret < 0)
+ continue;
+
+ if (ret > max_uV)
+ break;
+
+ if (ret >= min_uV && ret <= max_uV)
+ return i;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend);
+
+/**
+ * regulator_map_voltage_linear - map_voltage() for simple linear mappings
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing min_uV and uV_step in their regulator_desc can
+ * use this as their map_voltage() operation.
+ */
+int regulator_map_voltage_linear(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int ret, voltage;
+
+ /* Allow uV_step to be 0 for fixed voltage */
+ if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) {
+ if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV)
+ return 0;
+ else
+ return -EINVAL;
+ }
+
+ if (!rdev->desc->uV_step) {
+ BUG_ON(!rdev->desc->uV_step);
+ return -EINVAL;
+ }
+
+ if (min_uV < rdev->desc->min_uV)
+ min_uV = rdev->desc->min_uV;
+
+ ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step);
+ if (ret < 0)
+ return ret;
+
+ ret += rdev->desc->linear_min_sel;
+
+ /* Map back into a voltage to verify we're still in bounds */
+ voltage = rdev->desc->ops->list_voltage(rdev, ret);
+ if (voltage < min_uV || voltage > max_uV)
+ return -EINVAL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear);
+
+/**
+ * regulator_map_voltage_linear - map_voltage() for multiple linear ranges
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing linear_ranges in their descriptor can use this as
+ * their map_voltage() callback.
+ */
+int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ const struct regulator_linear_range *range;
+ int ret = -EINVAL;
+ int voltage, i;
+
+ if (!rdev->desc->n_linear_ranges) {
+ BUG_ON(!rdev->desc->n_linear_ranges);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+ range = &rdev->desc->linear_ranges[i];
+
+ if (!(min_uV <= range->max_uV && max_uV >= range->min_uV))
+ continue;
+
+ if (min_uV <= range->min_uV)
+ min_uV = range->min_uV;
+
+ /* range->uV_step == 0 means fixed voltage range */
+ if (range->uV_step == 0) {
+ ret = 0;
+ } else {
+ ret = DIV_ROUND_UP(min_uV - range->min_uV,
+ range->uV_step);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret += range->min_sel;
+
+ break;
+ }
+
+ if (i == rdev->desc->n_linear_ranges)
+ return -EINVAL;
+
+ /* Map back into a voltage to verify we're still in bounds */
+ voltage = rdev->desc->ops->list_voltage(rdev, ret);
+ if (voltage < min_uV || voltage > max_uV)
+ return -EINVAL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
+
+/**
+ * regulator_list_voltage_linear - List voltages with simple calculation
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a simple linear mapping between voltages and
+ * selectors can set min_uV and uV_step in the regulator descriptor
+ * and then use this function as their list_voltage() operation,
+ */
+int regulator_list_voltage_linear(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ if (selector >= rdev->desc->n_voltages)
+ return -EINVAL;
+ if (selector < rdev->desc->linear_min_sel)
+ return 0;
+
+ selector -= rdev->desc->linear_min_sel;
+
+ return rdev->desc->min_uV + (rdev->desc->uV_step * selector);
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
+
+/**
+ * regulator_list_voltage_linear_range - List voltages for linear ranges
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a series of simple linear mappings between voltages
+ * and selectors can set linear_ranges in the regulator descriptor and
+ * then use this function as their list_voltage() operation,
+ */
+int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ const struct regulator_linear_range *range;
+ int i;
+
+ if (!rdev->desc->n_linear_ranges) {
+ BUG_ON(!rdev->desc->n_linear_ranges);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+ range = &rdev->desc->linear_ranges[i];
+
+ if (!(selector >= range->min_sel &&
+ selector <= range->max_sel))
+ continue;
+
+ selector -= range->min_sel;
+
+ return range->min_uV + (range->uV_step * selector);
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_linear_range);
+
+/**
+ * regulator_list_voltage_table - List voltages with table based mapping
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with table based mapping between voltages and
+ * selectors can set volt_table in the regulator descriptor
+ * and then use this function as their list_voltage() operation.
+ */
+int regulator_list_voltage_table(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ if (!rdev->desc->volt_table) {
+ BUG_ON(!rdev->desc->volt_table);
+ return -EINVAL;
+ }
+
+ if (selector >= rdev->desc->n_voltages)
+ return -EINVAL;
+
+ return rdev->desc->volt_table[selector];
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_table);
+
+/**
+ * regulator_set_bypass_regmap - Default set_bypass() using regmap
+ *
+ * @rdev: device to operate on.
+ * @enable: state to set.
+ */
+int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
+{
+ unsigned int val;
+
+ if (enable)
+ val = rdev->desc->bypass_mask;
+ else
+ val = 0;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
+ rdev->desc->bypass_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap);
+
+/**
+ * regulator_get_bypass_regmap - Default get_bypass() using regmap
+ *
+ * @rdev: device to operate on.
+ * @enable: current state.
+ */
+int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val);
+ if (ret != 0)
+ return ret;
+
+ *enable = val & rdev->desc->bypass_mask;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c
index b99c49b9aff..88c1a3acf56 100644
--- a/drivers/regulator/isl6271a-regulator.c
+++ b/drivers/regulator/isl6271a-regulator.c
@@ -110,7 +110,7 @@ static int isl6271a_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct regulator_config config = { };
- struct regulator_init_data *init_data = i2c->dev.platform_data;
+ struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
struct isl_pmic *pmic;
int err, i;
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 3809b438160..5a4604ee5ea 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -425,7 +425,7 @@ static int lp3971_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct lp3971 *lp3971;
- struct lp3971_platform_data *pdata = i2c->dev.platform_data;
+ struct lp3971_platform_data *pdata = dev_get_platdata(&i2c->dev);
int ret;
u16 val;
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index 573024039ca..093e6f44ff8 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -519,7 +519,7 @@ static int lp3972_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct lp3972 *lp3972;
- struct lp3972_platform_data *pdata = i2c->dev.platform_data;
+ struct lp3972_platform_data *pdata = dev_get_platdata(&i2c->dev);
int ret;
u16 val;
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index b16336bcd4d..2b84b727a3c 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -373,7 +373,7 @@ static int lp8725_buck_set_current_limit(struct regulator_dev *rdev,
return -EINVAL;
}
- for (i = ARRAY_SIZE(lp8725_buck_uA) - 1 ; i >= 0; i--) {
+ for (i = ARRAY_SIZE(lp8725_buck_uA) - 1; i >= 0; i--) {
if (lp8725_buck_uA[i] >= min_uA &&
lp8725_buck_uA[i] <= max_uA)
return lp872x_update_bits(lp, addr,
@@ -787,7 +787,7 @@ static int lp872x_regulator_register(struct lp872x *lp)
struct regulator_dev *rdev;
int i, ret;
- for (i = 0 ; i < lp->num_regulators ; i++) {
+ for (i = 0; i < lp->num_regulators; i++) {
desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] :
&lp8725_regulator_desc[i];
@@ -820,7 +820,7 @@ static void lp872x_regulator_unregister(struct lp872x *lp)
struct regulator_dev *rdev;
int i;
- for (i = 0 ; i < lp->num_regulators ; i++) {
+ for (i = 0; i < lp->num_regulators; i++) {
rdev = *(lp->regulators + i);
regulator_unregister(rdev);
}
@@ -907,7 +907,8 @@ static struct lp872x_platform_data
goto out;
for (i = 0; i < num_matches; i++) {
- pdata->regulator_data[i].id = (int)match[i].driver_data;
+ pdata->regulator_data[i].id =
+ (enum lp872x_regulator_id)match[i].driver_data;
pdata->regulator_data[i].init_data = match[i].init_data;
/* Operation mode configuration for buck/buck1/buck2 */
@@ -961,7 +962,7 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
}
lp->dev = &cl->dev;
- lp->pdata = cl->dev.platform_data;
+ lp->pdata = dev_get_platdata(&cl->dev);
lp->chipid = id->driver_data;
lp->num_regulators = num_regulators;
i2c_set_clientdata(cl, lp);
diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c
index d9e38b4c2ad..785a25e9a43 100644
--- a/drivers/regulator/lp8755.c
+++ b/drivers/regulator/lp8755.c
@@ -228,6 +228,7 @@ err_i2c:
}
static struct regulator_ops lp8755_buck_ops = {
+ .map_voltage = regulator_map_voltage_linear,
.list_voltage = regulator_list_voltage_linear,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -449,7 +450,7 @@ static int lp8755_probe(struct i2c_client *client,
{
int ret, icnt;
struct lp8755_chip *pchip;
- struct lp8755_platform_data *pdata = client->dev.platform_data;
+ struct lp8755_platform_data *pdata = dev_get_platdata(&client->dev);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "i2c functionality check fail.\n");
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 54af6101581..3a599ee0a45 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -163,7 +163,7 @@ static int max1586_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
struct regulator_dev **rdev;
- struct max1586_platform_data *pdata = client->dev.platform_data;
+ struct max1586_platform_data *pdata = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct max1586_data *max1586;
int i, id, ret = -ENOMEM;
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index db6c9be10f3..19c6f08eafd 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -152,7 +152,7 @@ static struct regmap_config max8649_regmap_config = {
static int max8649_regulator_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct max8649_platform_data *pdata = client->dev.platform_data;
+ struct max8649_platform_data *pdata = dev_get_platdata(&client->dev);
struct max8649_regulator_info *info = NULL;
struct regulator_config config = { };
unsigned int val;
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index d428ef9a626..144bcacd734 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -44,6 +44,9 @@
#include <linux/regulator/driver.h>
#include <linux/slab.h>
#include <linux/regulator/max8660.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/of_regulator.h>
#define MAX8660_DCDC_MIN_UV 725000
#define MAX8660_DCDC_MAX_UV 1800000
@@ -305,21 +308,105 @@ static const struct regulator_desc max8660_reg[] = {
},
};
+enum {
+ MAX8660 = 0,
+ MAX8661 = 1,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id max8660_dt_ids[] = {
+ { .compatible = "maxim,max8660", .data = (void *) MAX8660 },
+ { .compatible = "maxim,max8661", .data = (void *) MAX8661 },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max8660_dt_ids);
+
+static int max8660_pdata_from_dt(struct device *dev,
+ struct device_node **of_node,
+ struct max8660_platform_data *pdata)
+{
+ int matched, i;
+ struct device_node *np;
+ struct max8660_subdev_data *sub;
+ struct of_regulator_match rmatch[ARRAY_SIZE(max8660_reg)];
+
+ np = of_find_node_by_name(dev->of_node, "regulators");
+ if (!np) {
+ dev_err(dev, "missing 'regulators' subnode in DT\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(rmatch); i++)
+ rmatch[i].name = max8660_reg[i].name;
+
+ matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch));
+ if (matched <= 0)
+ return matched;
+
+ pdata->subdevs = devm_kzalloc(dev, sizeof(struct max8660_subdev_data) *
+ matched, GFP_KERNEL);
+ if (!pdata->subdevs)
+ return -ENOMEM;
+
+ pdata->num_subdevs = matched;
+ sub = pdata->subdevs;
+
+ for (i = 0; i < matched; i++) {
+ sub->id = i;
+ sub->name = rmatch[i].name;
+ sub->platform_data = rmatch[i].init_data;
+ of_node[i] = rmatch[i].of_node;
+ sub++;
+ }
+
+ return 0;
+}
+#else
+static inline int max8660_pdata_from_dt(struct device *dev,
+ struct device_node **of_node,
+ struct max8660_platform_data *pdata)
+{
+ return 0;
+}
+#endif
+
static int max8660_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
struct regulator_dev **rdev;
- struct max8660_platform_data *pdata = client->dev.platform_data;
+ struct device *dev = &client->dev;
+ struct max8660_platform_data *pdata = dev_get_platdata(dev);
struct regulator_config config = { };
struct max8660 *max8660;
int boot_on, i, id, ret = -EINVAL;
+ struct device_node *of_node[MAX8660_V_END];
+ unsigned long type;
+
+ if (dev->of_node && !pdata) {
+ const struct of_device_id *id;
+ struct max8660_platform_data pdata_of;
+
+ id = of_match_device(of_match_ptr(max8660_dt_ids), dev);
+ if (!id)
+ return -ENODEV;
+
+ ret = max8660_pdata_from_dt(dev, of_node, &pdata_of);
+ if (ret < 0)
+ return ret;
+
+ pdata = &pdata_of;
+ type = (unsigned long) id->data;
+ } else {
+ type = i2c_id->driver_data;
+ memset(of_node, 0, sizeof(of_node));
+ }
if (pdata->num_subdevs > MAX8660_V_END) {
- dev_err(&client->dev, "Too many regulators found!\n");
+ dev_err(dev, "Too many regulators found!\n");
return -EINVAL;
}
- max8660 = devm_kzalloc(&client->dev, sizeof(struct max8660) +
+ max8660 = devm_kzalloc(dev, sizeof(struct max8660) +
sizeof(struct regulator_dev *) * MAX8660_V_END,
GFP_KERNEL);
if (!max8660)
@@ -376,8 +463,8 @@ static int max8660_probe(struct i2c_client *client,
break;
case MAX8660_V7:
- if (!strcmp(i2c_id->name, "max8661")) {
- dev_err(&client->dev, "Regulator not on this chip!\n");
+ if (type == MAX8661) {
+ dev_err(dev, "Regulator not on this chip!\n");
goto err_out;
}
@@ -386,7 +473,7 @@ static int max8660_probe(struct i2c_client *client,
break;
default:
- dev_err(&client->dev, "invalid regulator %s\n",
+ dev_err(dev, "invalid regulator %s\n",
pdata->subdevs[i].name);
goto err_out;
}
@@ -397,14 +484,15 @@ static int max8660_probe(struct i2c_client *client,
id = pdata->subdevs[i].id;
- config.dev = &client->dev;
+ config.dev = dev;
config.init_data = pdata->subdevs[i].platform_data;
+ config.of_node = of_node[i];
config.driver_data = max8660;
rdev[i] = regulator_register(&max8660_reg[id], &config);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
- dev_err(&client->dev, "failed to register %s\n",
+ dev_err(dev, "failed to register %s\n",
max8660_reg[id].name);
goto err_unregister;
}
@@ -431,8 +519,8 @@ static int max8660_remove(struct i2c_client *client)
}
static const struct i2c_device_id max8660_id[] = {
- { "max8660", 0 },
- { "max8661", 0 },
+ { .name = "max8660", .driver_data = MAX8660 },
+ { .name = "max8661", .driver_data = MAX8661 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max8660_id);
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index e6d54a546d3..d80b5fa758a 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -277,7 +277,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
static int max8925_regulator_probe(struct platform_device *pdev)
{
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
- struct regulator_init_data *pdata = pdev->dev.platform_data;
+ struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev);
struct regulator_config config = { };
struct max8925_regulator_info *ri;
struct resource *res;
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index 5259c2fea90..788e5ae2af1 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -196,7 +196,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct max8952_platform_data *pdata = client->dev.platform_data;
+ struct max8952_platform_data *pdata = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct max8952_data *max8952;
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
index 0c5195a842e..5b77ab7762e 100644
--- a/drivers/regulator/max8973-regulator.c
+++ b/drivers/regulator/max8973-regulator.c
@@ -371,7 +371,7 @@ static int max8973_probe(struct i2c_client *client,
struct max8973_chip *max;
int ret;
- pdata = client->dev.platform_data;
+ pdata = dev_get_platdata(&client->dev);
if (!pdata && !client->dev.of_node) {
dev_err(&client->dev, "No Platform data");
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index f3c8f8f9dc3..7827384680d 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -21,6 +21,7 @@ static void of_get_regulation_constraints(struct device_node *np,
{
const __be32 *min_uV, *max_uV, *uV_offset;
const __be32 *min_uA, *max_uA, *ramp_delay;
+ struct property *prop;
struct regulation_constraints *constraints = &(*init_data)->constraints;
constraints->name = of_get_property(np, "regulator-name", NULL);
@@ -64,9 +65,14 @@ static void of_get_regulation_constraints(struct device_node *np,
if (of_property_read_bool(np, "regulator-allow-bypass"))
constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
- ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL);
- if (ramp_delay)
- constraints->ramp_delay = be32_to_cpu(*ramp_delay);
+ prop = of_find_property(np, "regulator-ramp-delay", NULL);
+ if (prop && prop->value) {
+ ramp_delay = prop->value;
+ if (*ramp_delay)
+ constraints->ramp_delay = be32_to_cpu(*ramp_delay);
+ else
+ constraints->ramp_disable = true;
+ }
}
/**
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index d0c87856dd2..488dfe7ce9a 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -97,11 +97,16 @@ static const struct regs_info palmas_regs_info[] = {
.ctrl_addr = PALMAS_SMPS9_CTRL,
},
{
- .name = "SMPS10",
+ .name = "SMPS10_OUT2",
.sname = "smps10-in",
.ctrl_addr = PALMAS_SMPS10_CTRL,
},
{
+ .name = "SMPS10_OUT1",
+ .sname = "smps10-out2",
+ .ctrl_addr = PALMAS_SMPS10_CTRL,
+ },
+ {
.name = "LDO1",
.sname = "ldo1-in",
.vsel_addr = PALMAS_LDO1_VOLTAGE,
@@ -487,6 +492,8 @@ static struct regulator_ops palmas_ops_smps10 = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
+ .set_bypass = regulator_set_bypass_regmap,
+ .get_bypass = regulator_get_bypass_regmap,
};
static int palmas_is_enabled_ldo(struct regulator_dev *dev)
@@ -538,7 +545,8 @@ static int palmas_smps_init(struct palmas *palmas, int id,
return ret;
switch (id) {
- case PALMAS_REG_SMPS10:
+ case PALMAS_REG_SMPS10_OUT1:
+ case PALMAS_REG_SMPS10_OUT2:
reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
if (reg_init->mode_sleep)
reg |= reg_init->mode_sleep <<
@@ -681,7 +689,8 @@ static struct of_regulator_match palmas_matches[] = {
{ .name = "smps7", },
{ .name = "smps8", },
{ .name = "smps9", },
- { .name = "smps10", },
+ { .name = "smps10_out2", },
+ { .name = "smps10_out1", },
{ .name = "ldo1", },
{ .name = "ldo2", },
{ .name = "ldo3", },
@@ -765,7 +774,7 @@ static void palmas_dt_to_pdata(struct device *dev,
static int palmas_regulators_probe(struct platform_device *pdev)
{
struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
- struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data;
+ struct palmas_pmic_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *node = pdev->dev.of_node;
struct regulator_dev *rdev;
struct regulator_config config = { };
@@ -838,7 +847,8 @@ static int palmas_regulators_probe(struct platform_device *pdev)
continue;
ramp_delay_support = true;
break;
- case PALMAS_REG_SMPS10:
+ case PALMAS_REG_SMPS10_OUT1:
+ case PALMAS_REG_SMPS10_OUT2:
if (!PALMAS_PMIC_HAS(palmas, SMPS10_BOOST))
continue;
}
@@ -872,7 +882,8 @@ static int palmas_regulators_probe(struct platform_device *pdev)
pmic->desc[id].id = id;
switch (id) {
- case PALMAS_REG_SMPS10:
+ case PALMAS_REG_SMPS10_OUT1:
+ case PALMAS_REG_SMPS10_OUT2:
pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES;
pmic->desc[id].ops = &palmas_ops_smps10;
pmic->desc[id].vsel_reg =
@@ -882,7 +893,14 @@ static int palmas_regulators_probe(struct platform_device *pdev)
pmic->desc[id].enable_reg =
PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
PALMAS_SMPS10_CTRL);
- pmic->desc[id].enable_mask = SMPS10_BOOST_EN;
+ if (id == PALMAS_REG_SMPS10_OUT1)
+ pmic->desc[id].enable_mask = SMPS10_SWITCH_EN;
+ else
+ pmic->desc[id].enable_mask = SMPS10_BOOST_EN;
+ pmic->desc[id].bypass_reg =
+ PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
+ PALMAS_SMPS10_CTRL);
+ pmic->desc[id].bypass_mask = SMPS10_BYPASS_EN;
pmic->desc[id].min_uV = 3750000;
pmic->desc[id].uV_step = 1250000;
break;
diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c
index 1a73a297fe7..b49eaeedea8 100644
--- a/drivers/regulator/pcap-regulator.c
+++ b/drivers/regulator/pcap-regulator.c
@@ -243,7 +243,7 @@ static int pcap_regulator_probe(struct platform_device *pdev)
struct regulator_config config = { };
config.dev = &pdev->dev;
- config.init_data = pdev->dev.platform_data;
+ config.init_data = dev_get_platdata(&pdev->dev);
config.driver_data = pcap;
rdev = regulator_register(&pcap_regulators[pdev->id], &config);
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
index 54df9f7cb50..0f3576d48ab 100644
--- a/drivers/regulator/pcf50633-regulator.c
+++ b/drivers/regulator/pcf50633-regulator.c
@@ -86,7 +86,7 @@ static int pcf50633_regulator_probe(struct platform_device *pdev)
pcf = dev_to_pcf50633(pdev->dev.parent);
config.dev = &pdev->dev;
- config.init_data = pdev->dev.platform_data;
+ config.init_data = dev_get_platdata(&pdev->dev);
config.driver_data = pcf;
config.regmap = pcf->regmap;
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
new file mode 100644
index 00000000000..ba67b2c4e2e
--- /dev/null
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/pfuze100.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+#define PFUZE_NUMREGS 128
+#define PFUZE100_VOL_OFFSET 0
+#define PFUZE100_STANDBY_OFFSET 1
+#define PFUZE100_MODE_OFFSET 3
+#define PFUZE100_CONF_OFFSET 4
+
+#define PFUZE100_DEVICEID 0x0
+#define PFUZE100_REVID 0x3
+#define PFUZE100_FABID 0x3
+
+#define PFUZE100_SW1ABVOL 0x20
+#define PFUZE100_SW1CVOL 0x2e
+#define PFUZE100_SW2VOL 0x35
+#define PFUZE100_SW3AVOL 0x3c
+#define PFUZE100_SW3BVOL 0x43
+#define PFUZE100_SW4VOL 0x4a
+#define PFUZE100_SWBSTCON1 0x66
+#define PFUZE100_VREFDDRCON 0x6a
+#define PFUZE100_VSNVSVOL 0x6b
+#define PFUZE100_VGEN1VOL 0x6c
+#define PFUZE100_VGEN2VOL 0x6d
+#define PFUZE100_VGEN3VOL 0x6e
+#define PFUZE100_VGEN4VOL 0x6f
+#define PFUZE100_VGEN5VOL 0x70
+#define PFUZE100_VGEN6VOL 0x71
+
+struct pfuze_regulator {
+ struct regulator_desc desc;
+ unsigned char stby_reg;
+ unsigned char stby_mask;
+};
+
+struct pfuze_chip {
+ struct regmap *regmap;
+ struct device *dev;
+ struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
+ struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
+};
+
+static const int pfuze100_swbst[] = {
+ 5000000, 5050000, 5100000, 5150000,
+};
+
+static const int pfuze100_vsnvs[] = {
+ 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000,
+};
+
+static const struct i2c_device_id pfuze_device_id[] = {
+ {.name = "pfuze100"},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
+
+static const struct of_device_id pfuze_dt_ids[] = {
+ { .compatible = "fsl,pfuze100" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
+
+static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev);
+ int id = rdev->desc->id;
+ unsigned int ramp_bits;
+ int ret;
+
+ if (id < PFUZE100_SWBST) {
+ ramp_delay = 12500 / ramp_delay;
+ ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3);
+ ret = regmap_update_bits(pfuze100->regmap,
+ rdev->desc->vsel_reg + 4,
+ 0xc0, ramp_bits << 6);
+ if (ret < 0)
+ dev_err(pfuze100->dev, "ramp failed, err %d\n", ret);
+ } else
+ ret = -EACCES;
+
+ return ret;
+}
+
+static struct regulator_ops pfuze100_ldo_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops pfuze100_fixed_regulator_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops pfuze100_sw_regulator_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = pfuze100_set_ramp_delay,
+};
+
+static struct regulator_ops pfuze100_swb_regulator_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+
+};
+
+#define PFUZE100_FIXED_REG(_name, base, voltage) \
+ [PFUZE100_ ## _name] = { \
+ .desc = { \
+ .name = #_name, \
+ .n_voltages = 1, \
+ .ops = &pfuze100_fixed_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = PFUZE100_ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (voltage), \
+ .enable_reg = (base), \
+ .enable_mask = 0x10, \
+ }, \
+ }
+
+#define PFUZE100_SW_REG(_name, base, min, max, step) \
+ [PFUZE100_ ## _name] = { \
+ .desc = { \
+ .name = #_name,\
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pfuze100_sw_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = PFUZE100_ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \
+ .vsel_mask = 0x3f, \
+ }, \
+ .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \
+ .stby_mask = 0x3f, \
+ }
+
+#define PFUZE100_SWB_REG(_name, base, mask, voltages) \
+ [PFUZE100_ ## _name] = { \
+ .desc = { \
+ .name = #_name, \
+ .n_voltages = ARRAY_SIZE(voltages), \
+ .ops = &pfuze100_swb_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = PFUZE100_ ## _name, \
+ .owner = THIS_MODULE, \
+ .volt_table = voltages, \
+ .vsel_reg = (base), \
+ .vsel_mask = (mask), \
+ }, \
+ }
+
+#define PFUZE100_VGEN_REG(_name, base, min, max, step) \
+ [PFUZE100_ ## _name] = { \
+ .desc = { \
+ .name = #_name, \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pfuze100_ldo_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = PFUZE100_ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .vsel_reg = (base), \
+ .vsel_mask = 0xf, \
+ .enable_reg = (base), \
+ .enable_mask = 0x10, \
+ }, \
+ .stby_reg = (base), \
+ .stby_mask = 0x20, \
+ }
+
+static struct pfuze_regulator pfuze100_regulators[] = {
+ PFUZE100_SW_REG(SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
+ PFUZE100_SW_REG(SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000),
+ PFUZE100_SW_REG(SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
+ PFUZE100_SW_REG(SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000),
+ PFUZE100_SWB_REG(SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
+ PFUZE100_SWB_REG(VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+ PFUZE100_FIXED_REG(VREFDDR, PFUZE100_VREFDDRCON, 750000),
+ PFUZE100_VGEN_REG(VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
+ PFUZE100_VGEN_REG(VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+ PFUZE100_VGEN_REG(VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+};
+
+#ifdef CONFIG_OF
+static struct of_regulator_match pfuze100_matches[] = {
+ { .name = "sw1ab", },
+ { .name = "sw1c", },
+ { .name = "sw2", },
+ { .name = "sw3a", },
+ { .name = "sw3b", },
+ { .name = "sw4", },
+ { .name = "swbst", },
+ { .name = "vsnvs", },
+ { .name = "vrefddr", },
+ { .name = "vgen1", },
+ { .name = "vgen2", },
+ { .name = "vgen3", },
+ { .name = "vgen4", },
+ { .name = "vgen5", },
+ { .name = "vgen6", },
+};
+
+static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
+{
+ struct device *dev = chip->dev;
+ struct device_node *np, *parent;
+ int ret;
+
+ np = of_node_get(dev->parent->of_node);
+ if (!np)
+ return 0;
+
+ parent = of_find_node_by_name(np, "regulators");
+ if (!parent) {
+ dev_err(dev, "regulators node not found\n");
+ return -EINVAL;
+ }
+
+ ret = of_regulator_match(dev, parent, pfuze100_matches,
+ ARRAY_SIZE(pfuze100_matches));
+
+ of_node_put(parent);
+ if (ret < 0) {
+ dev_err(dev, "Error parsing regulator init data: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline struct regulator_init_data *match_init_data(int index)
+{
+ return pfuze100_matches[index].init_data;
+}
+
+static inline struct device_node *match_of_node(int index)
+{
+ return pfuze100_matches[index].of_node;
+}
+#else
+static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
+{
+ return 0;
+}
+
+static inline struct regulator_init_data *match_init_data(int index)
+{
+ return NULL;
+}
+
+static inline struct device_node *match_of_node(int index)
+{
+ return NULL;
+}
+#endif
+
+static int pfuze_identify(struct pfuze_chip *pfuze_chip)
+{
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(pfuze_chip->regmap, PFUZE100_DEVICEID, &value);
+ if (ret)
+ return ret;
+
+ if (value & 0x0f) {
+ dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(pfuze_chip->regmap, PFUZE100_REVID, &value);
+ if (ret)
+ return ret;
+ dev_info(pfuze_chip->dev,
+ "Full lay: %x, Metal lay: %x\n",
+ (value & 0xf0) >> 4, value & 0x0f);
+
+ ret = regmap_read(pfuze_chip->regmap, PFUZE100_FABID, &value);
+ if (ret)
+ return ret;
+ dev_info(pfuze_chip->dev, "FAB: %x, FIN: %x\n",
+ (value & 0xc) >> 2, value & 0x3);
+
+ return 0;
+}
+
+static const struct regmap_config pfuze_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PFUZE_NUMREGS - 1,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int pfuze100_regulator_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pfuze_chip *pfuze_chip;
+ struct pfuze_regulator_platform_data *pdata =
+ dev_get_platdata(&client->dev);
+ struct regulator_config config = { };
+ int i, ret;
+
+ pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip),
+ GFP_KERNEL);
+ if (!pfuze_chip)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, pfuze_chip);
+
+ memcpy(pfuze_chip->regulator_descs, pfuze100_regulators,
+ sizeof(pfuze_chip->regulator_descs));
+
+ pfuze_chip->dev = &client->dev;
+
+ pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config);
+ if (IS_ERR(pfuze_chip->regmap)) {
+ ret = PTR_ERR(pfuze_chip->regmap);
+ dev_err(&client->dev,
+ "regmap allocation failed with err %d\n", ret);
+ return ret;
+ }
+
+ ret = pfuze_identify(pfuze_chip);
+ if (ret) {
+ dev_err(&client->dev, "unrecognized pfuze chip ID!\n");
+ return ret;
+ }
+
+ ret = pfuze_parse_regulators_dt(pfuze_chip);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) {
+ struct regulator_init_data *init_data;
+ struct regulator_desc *desc;
+ int val;
+
+ desc = &pfuze_chip->regulator_descs[i].desc;
+
+ if (pdata)
+ init_data = pdata->init_data[i];
+ else
+ init_data = match_init_data(i);
+
+ /* SW2~SW4 high bit check and modify the voltage value table */
+ if (i > PFUZE100_SW1C && i < PFUZE100_SWBST) {
+ regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
+ if (val & 0x40) {
+ desc->min_uV = 800000;
+ desc->uV_step = 50000;
+ desc->n_voltages = 51;
+ }
+ }
+
+ config.dev = &client->dev;
+ config.init_data = init_data;
+ config.driver_data = pfuze_chip;
+ config.of_node = match_of_node(i);
+
+ pfuze_chip->regulators[i] = regulator_register(desc, &config);
+ if (IS_ERR(pfuze_chip->regulators[i])) {
+ dev_err(&client->dev, "register regulator%s failed\n",
+ pfuze100_regulators[i].desc.name);
+ ret = PTR_ERR(pfuze_chip->regulators[i]);
+ while (--i >= 0)
+ regulator_unregister(pfuze_chip->regulators[i]);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int pfuze100_regulator_remove(struct i2c_client *client)
+{
+ int i;
+ struct pfuze_chip *pfuze_chip = i2c_get_clientdata(client);
+
+ for (i = 0; i < PFUZE100_MAX_REGULATOR; i++)
+ regulator_unregister(pfuze_chip->regulators[i]);
+
+ return 0;
+}
+
+static struct i2c_driver pfuze_driver = {
+ .id_table = pfuze_device_id,
+ .driver = {
+ .name = "pfuze100-regulator",
+ .owner = THIS_MODULE,
+ .of_match_table = pfuze_dt_ids,
+ },
+ .probe = pfuze100_regulator_probe,
+ .remove = pfuze100_regulator_remove,
+};
+module_i2c_driver(pfuze_driver);
+
+MODULE_AUTHOR("Robin Gong <b38343@freescale.com>");
+MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:pfuze100-regulator");
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index 2f62564ca93..5eba2ff8c0e 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -16,12 +16,17 @@
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/s2mps11.h>
+#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators)
+
struct s2mps11_info {
struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX];
@@ -31,11 +36,6 @@ struct s2mps11_info {
int ramp_delay16;
int ramp_delay7810;
int ramp_delay9;
-
- bool buck6_ramp;
- bool buck2_ramp;
- bool buck3_ramp;
- bool buck4_ramp;
};
static int get_ramp_delay(int ramp_delay)
@@ -50,9 +50,171 @@ static int get_ramp_delay(int ramp_delay)
break;
cnt++;
}
+
+ if (cnt > 3)
+ cnt = 3;
+
return cnt;
}
+static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector,
+ unsigned int new_selector)
+{
+ struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+ unsigned int ramp_delay = 0;
+ int old_volt, new_volt;
+
+ switch (rdev->desc->id) {
+ case S2MPS11_BUCK2:
+ ramp_delay = s2mps11->ramp_delay2;
+ break;
+ case S2MPS11_BUCK3:
+ ramp_delay = s2mps11->ramp_delay34;
+ break;
+ case S2MPS11_BUCK4:
+ ramp_delay = s2mps11->ramp_delay34;
+ break;
+ case S2MPS11_BUCK5:
+ ramp_delay = s2mps11->ramp_delay5;
+ break;
+ case S2MPS11_BUCK6:
+ case S2MPS11_BUCK1:
+ ramp_delay = s2mps11->ramp_delay16;
+ break;
+ case S2MPS11_BUCK7:
+ case S2MPS11_BUCK8:
+ case S2MPS11_BUCK10:
+ ramp_delay = s2mps11->ramp_delay7810;
+ break;
+ case S2MPS11_BUCK9:
+ ramp_delay = s2mps11->ramp_delay9;
+ }
+
+ if (ramp_delay == 0)
+ ramp_delay = rdev->desc->ramp_delay;
+
+ old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector);
+ new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector);
+
+ return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+}
+
+static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+ unsigned int ramp_val, ramp_shift, ramp_reg = S2MPS11_REG_RAMP_BUCK;
+ unsigned int ramp_enable = 1, enable_shift = 0;
+ int ret;
+
+ switch (rdev->desc->id) {
+ case S2MPS11_BUCK1:
+ if (ramp_delay > s2mps11->ramp_delay16)
+ s2mps11->ramp_delay16 = ramp_delay;
+ else
+ ramp_delay = s2mps11->ramp_delay16;
+
+ ramp_shift = S2MPS11_BUCK16_RAMP_SHIFT;
+ break;
+ case S2MPS11_BUCK2:
+ enable_shift = S2MPS11_BUCK2_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ s2mps11->ramp_delay2 = ramp_delay;
+ ramp_shift = S2MPS11_BUCK2_RAMP_SHIFT;
+ ramp_reg = S2MPS11_REG_RAMP;
+ break;
+ case S2MPS11_BUCK3:
+ enable_shift = S2MPS11_BUCK3_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ if (ramp_delay > s2mps11->ramp_delay34)
+ s2mps11->ramp_delay34 = ramp_delay;
+ else
+ ramp_delay = s2mps11->ramp_delay34;
+
+ ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT;
+ ramp_reg = S2MPS11_REG_RAMP;
+ break;
+ case S2MPS11_BUCK4:
+ enable_shift = S2MPS11_BUCK4_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ if (ramp_delay > s2mps11->ramp_delay34)
+ s2mps11->ramp_delay34 = ramp_delay;
+ else
+ ramp_delay = s2mps11->ramp_delay34;
+
+ ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT;
+ ramp_reg = S2MPS11_REG_RAMP;
+ break;
+ case S2MPS11_BUCK5:
+ s2mps11->ramp_delay5 = ramp_delay;
+ ramp_shift = S2MPS11_BUCK5_RAMP_SHIFT;
+ break;
+ case S2MPS11_BUCK6:
+ enable_shift = S2MPS11_BUCK6_RAMP_EN_SHIFT;
+ if (!ramp_delay) {
+ ramp_enable = 0;
+ break;
+ }
+
+ if (ramp_delay > s2mps11->ramp_delay16)
+ s2mps11->ramp_delay16 = ramp_delay;
+ else
+ ramp_delay = s2mps11->ramp_delay16;
+
+ ramp_shift = S2MPS11_BUCK16_RAMP_SHIFT;
+ break;
+ case S2MPS11_BUCK7:
+ case S2MPS11_BUCK8:
+ case S2MPS11_BUCK10:
+ if (ramp_delay > s2mps11->ramp_delay7810)
+ s2mps11->ramp_delay7810 = ramp_delay;
+ else
+ ramp_delay = s2mps11->ramp_delay7810;
+
+ ramp_shift = S2MPS11_BUCK7810_RAMP_SHIFT;
+ break;
+ case S2MPS11_BUCK9:
+ s2mps11->ramp_delay9 = ramp_delay;
+ ramp_shift = S2MPS11_BUCK9_RAMP_SHIFT;
+ break;
+ default:
+ return 0;
+ }
+
+ if (!ramp_enable)
+ goto ramp_disable;
+
+ if (enable_shift) {
+ ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP,
+ 1 << enable_shift, 1 << enable_shift);
+ if (ret) {
+ dev_err(&rdev->dev, "failed to enable ramp rate\n");
+ return ret;
+ }
+ }
+
+ ramp_val = get_ramp_delay(ramp_delay);
+
+ return regmap_update_bits(rdev->regmap, ramp_reg, 0x3 << ramp_shift,
+ ramp_val << ramp_shift);
+
+ramp_disable:
+ return regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP,
+ 1 << enable_shift, 0);
+}
+
static struct regulator_ops s2mps11_ldo_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
@@ -72,7 +234,8 @@ static struct regulator_ops s2mps11_buck_ops = {
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_voltage_time_sel = s2mps11_regulator_set_voltage_time_sel,
+ .set_ramp_delay = s2mps11_set_ramp_delay,
};
#define regulator_desc_ldo1(num) { \
@@ -239,59 +402,51 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX];
+ struct device_node *reg_np = NULL;
struct regulator_config config = { };
struct s2mps11_info *s2mps11;
int i, ret;
- unsigned char ramp_enable, ramp_reg = 0;
-
- if (!pdata) {
- dev_err(pdev->dev.parent, "Platform data not supplied\n");
- return -ENODEV;
- }
s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
GFP_KERNEL);
if (!s2mps11)
return -ENOMEM;
- platform_set_drvdata(pdev, s2mps11);
+ if (!iodev->dev->of_node) {
+ if (pdata) {
+ goto common_reg;
+ } else {
+ dev_err(pdev->dev.parent,
+ "Platform data or DT node not supplied\n");
+ return -ENODEV;
+ }
+ }
- s2mps11->ramp_delay2 = pdata->buck2_ramp_delay;
- s2mps11->ramp_delay34 = pdata->buck34_ramp_delay;
- s2mps11->ramp_delay5 = pdata->buck5_ramp_delay;
- s2mps11->ramp_delay16 = pdata->buck16_ramp_delay;
- s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay;
- s2mps11->ramp_delay9 = pdata->buck9_ramp_delay;
-
- s2mps11->buck6_ramp = pdata->buck6_ramp_enable;
- s2mps11->buck2_ramp = pdata->buck2_ramp_enable;
- s2mps11->buck3_ramp = pdata->buck3_ramp_enable;
- s2mps11->buck4_ramp = pdata->buck4_ramp_enable;
-
- ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) |
- (s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ;
-
- if (ramp_enable) {
- if (s2mps11->buck2_ramp)
- ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) << 6;
- if (s2mps11->buck3_ramp || s2mps11->buck4_ramp)
- ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) << 4;
- sec_reg_write(iodev, S2MPS11_REG_RAMP, ramp_reg | ramp_enable);
+ for (i = 0; i < S2MPS11_REGULATOR_CNT; i++)
+ rdata[i].name = regulators[i].name;
+
+ reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators");
+ if (!reg_np) {
+ dev_err(&pdev->dev, "could not find regulators sub-node\n");
+ return -EINVAL;
}
- ramp_reg &= 0x00;
- ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) << 6;
- ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) << 4;
- ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) << 2;
- ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9);
- sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg);
+ of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX);
- for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
+common_reg:
+ platform_set_drvdata(pdev, s2mps11);
- config.dev = &pdev->dev;
- config.regmap = iodev->regmap;
- config.init_data = pdata->regulators[i].initdata;
- config.driver_data = s2mps11;
+ config.dev = &pdev->dev;
+ config.regmap = iodev->regmap;
+ config.driver_data = s2mps11;
+ for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
+ if (!reg_np) {
+ config.init_data = pdata->regulators[i].initdata;
+ } else {
+ config.init_data = rdata[i].init_data;
+ config.of_node = rdata[i].of_node;
+ }
s2mps11->rdev[i] = regulator_register(&regulators[i], &config);
if (IS_ERR(s2mps11->rdev[i])) {
diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c
index 3753ed05e71..d8e3e1262bc 100644
--- a/drivers/regulator/ti-abb-regulator.c
+++ b/drivers/regulator/ti-abb-regulator.c
@@ -717,11 +717,6 @@ static int ti_abb_probe(struct platform_device *pdev)
/* Map ABB resources */
pname = "base-address";
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
- if (!res) {
- dev_err(dev, "Missing '%s' IO resource\n", pname);
- ret = -ENODEV;
- goto err;
- }
abb->base = devm_ioremap_resource(dev, res);
if (IS_ERR(abb->base)) {
ret = PTR_ERR(abb->base);
@@ -770,11 +765,6 @@ static int ti_abb_probe(struct platform_device *pdev)
pname = "ldo-address";
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
- if (!res) {
- dev_dbg(dev, "Missing '%s' IO resource\n", pname);
- ret = -ENODEV;
- goto skip_opt;
- }
abb->ldo_base = devm_ioremap_resource(dev, res);
if (IS_ERR(abb->ldo_base)) {
ret = PTR_ERR(abb->ldo_base);
diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c
index 6e67be75ea1..9392a7ca3d2 100644
--- a/drivers/regulator/tps51632-regulator.c
+++ b/drivers/regulator/tps51632-regulator.c
@@ -275,7 +275,7 @@ static int tps51632_probe(struct i2c_client *client,
}
}
- pdata = client->dev.platform_data;
+ pdata = dev_get_platdata(&client->dev);
if (!pdata && client->dev.of_node)
pdata = of_get_tps51632_platform_data(&client->dev);
if (!pdata) {
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c
index a490d5b749b..0b7ebb1ebf8 100644
--- a/drivers/regulator/tps62360-regulator.c
+++ b/drivers/regulator/tps62360-regulator.c
@@ -350,7 +350,7 @@ static int tps62360_probe(struct i2c_client *client,
int i;
int chip_id;
- pdata = client->dev.platform_data;
+ pdata = dev_get_platdata(&client->dev);
if (client->dev.of_node) {
const struct of_device_id *match;
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index 9d053e23e9e..a15263d4bdf 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -218,7 +218,7 @@ static int tps_65023_probe(struct i2c_client *client,
* init_data points to array of regulator_init structures
* coming from the board-evm file.
*/
- init_data = client->dev.platform_data;
+ init_data = dev_get_platdata(&client->dev);
if (!init_data)
return -EIO;
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index 2df4616621f..90861d68a0b 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -27,7 +27,7 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65217.h>
-#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t) \
+#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t, _lr, _nlr) \
{ \
.name = _name, \
.id = _id, \
@@ -40,17 +40,10 @@
.enable_reg = TPS65217_REG_ENABLE, \
.enable_mask = _em, \
.volt_table = _t, \
+ .linear_ranges = _lr, \
+ .n_linear_ranges = _nlr, \
} \
-#define TPS65217_INFO(_nm, _min, _max, _f1, _f2) \
- { \
- .name = _nm, \
- .min_uV = _min, \
- .max_uV = _max, \
- .vsel_to_uv = _f1, \
- .uv_to_vsel = _f2, \
- }
-
static const unsigned int LDO1_VSEL_table[] = {
1000000, 1100000, 1200000, 1250000,
1300000, 1350000, 1400000, 1500000,
@@ -58,88 +51,26 @@ static const unsigned int LDO1_VSEL_table[] = {
2800000, 3000000, 3100000, 3300000,
};
-static int tps65217_vsel_to_uv1(unsigned int vsel)
-{
- int uV = 0;
-
- if (vsel > 63)
- return -EINVAL;
-
- if (vsel <= 24)
- uV = vsel * 25000 + 900000;
- else if (vsel <= 52)
- uV = (vsel - 24) * 50000 + 1500000;
- else if (vsel < 56)
- uV = (vsel - 52) * 100000 + 2900000;
- else
- uV = 3300000;
-
- return uV;
-}
-
-static int tps65217_uv_to_vsel1(int uV, unsigned int *vsel)
-{
- if (uV < 0 || uV > 3300000)
- return -EINVAL;
-
- if (uV <= 1500000)
- *vsel = DIV_ROUND_UP(uV - 900000, 25000);
- else if (uV <= 2900000)
- *vsel = 24 + DIV_ROUND_UP(uV - 1500000, 50000);
- else if (uV < 3300000)
- *vsel = 52 + DIV_ROUND_UP(uV - 2900000, 100000);
- else
- *vsel = 56;
-
- return 0;
-}
-
-static int tps65217_vsel_to_uv2(unsigned int vsel)
-{
- int uV = 0;
-
- if (vsel > 31)
- return -EINVAL;
-
- if (vsel <= 8)
- uV = vsel * 50000 + 1500000;
- else if (vsel <= 13)
- uV = (vsel - 8) * 100000 + 1900000;
- else
- uV = (vsel - 13) * 50000 + 2400000;
-
- return uV;
-}
-
-static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel)
-{
- if (uV < 0 || uV > 3300000)
- return -EINVAL;
-
- if (uV <= 1900000)
- *vsel = DIV_ROUND_UP(uV - 1500000, 50000);
- else if (uV <= 2400000)
- *vsel = 8 + DIV_ROUND_UP(uV - 1900000, 100000);
- else
- *vsel = 13 + DIV_ROUND_UP(uV - 2400000, 50000);
-
- return 0;
-}
+static const struct regulator_linear_range tps65217_uv1_ranges[] = {
+ { .min_uV = 900000, .max_uV = 1500000, .min_sel = 0, .max_sel = 24,
+ .uV_step = 25000 },
+ { .min_uV = 1550000, .max_uV = 1800000, .min_sel = 25, .max_sel = 30,
+ .uV_step = 50000 },
+ { .min_uV = 1850000, .max_uV = 2900000, .min_sel = 31, .max_sel = 52,
+ .uV_step = 50000 },
+ { .min_uV = 3000000, .max_uV = 3200000, .min_sel = 53, .max_sel = 55,
+ .uV_step = 100000 },
+ { .min_uV = 3300000, .max_uV = 3300000, .min_sel = 56, .max_sel = 62,
+ .uV_step = 0 },
+};
-static struct tps_info tps65217_pmic_regs[] = {
- TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1,
- tps65217_uv_to_vsel1),
- TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1,
- tps65217_uv_to_vsel1),
- TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1,
- tps65217_uv_to_vsel1),
- TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL),
- TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1,
- tps65217_uv_to_vsel1),
- TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2,
- tps65217_uv_to_vsel2),
- TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2,
- tps65217_uv_to_vsel2),
+static const struct regulator_linear_range tps65217_uv2_ranges[] = {
+ { .min_uV = 1500000, .max_uV = 1900000, .min_sel = 0, .max_sel = 8,
+ .uV_step = 50000 },
+ { .min_uV = 2000000, .max_uV = 2400000, .min_sel = 9, .max_sel = 13,
+ .uV_step = 100000 },
+ { .min_uV = 2450000, .max_uV = 3300000, .min_sel = 14, .max_sel = 31,
+ .uV_step = 50000 },
};
static int tps65217_pmic_enable(struct regulator_dev *dev)
@@ -192,49 +123,6 @@ static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev,
return ret;
}
-static int tps65217_pmic_map_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
-{
-
- struct tps65217 *tps = rdev_get_drvdata(dev);
- unsigned int sel, rid = rdev_get_id(dev);
- int ret;
-
- /* LDO1 uses regulator_map_voltage_iterate() */
- if (rid == TPS65217_LDO_1)
- return -EINVAL;
-
- if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
- return -EINVAL;
-
- if (min_uV < tps->info[rid]->min_uV)
- min_uV = tps->info[rid]->min_uV;
-
- if (max_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV)
- return -EINVAL;
-
- ret = tps->info[rid]->uv_to_vsel(min_uV, &sel);
- if (ret)
- return ret;
-
- return sel;
-}
-
-static int tps65217_pmic_list_voltage(struct regulator_dev *dev,
- unsigned selector)
-{
- struct tps65217 *tps = rdev_get_drvdata(dev);
- unsigned int rid = rdev_get_id(dev);
-
- if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
- return -EINVAL;
-
- if (selector >= dev->desc->n_voltages)
- return -EINVAL;
-
- return tps->info[rid]->vsel_to_uv(selector);
-}
-
/* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */
static struct regulator_ops tps65217_pmic_ops = {
.is_enabled = regulator_is_enabled_regmap,
@@ -242,8 +130,8 @@ static struct regulator_ops tps65217_pmic_ops = {
.disable = tps65217_pmic_disable,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = tps65217_pmic_set_voltage_sel,
- .list_voltage = tps65217_pmic_list_voltage,
- .map_voltage = tps65217_pmic_map_voltage,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
};
/* Operations permitted on LDO1 */
@@ -259,27 +147,33 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = {
static const struct regulator_desc regulators[] = {
TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64,
TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK,
- TPS65217_ENABLE_DC1_EN, NULL),
+ TPS65217_ENABLE_DC1_EN, NULL, tps65217_uv1_ranges,
+ 2), /* DCDC1 voltage range: 900000 ~ 1800000 */
TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64,
TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK,
- TPS65217_ENABLE_DC2_EN, NULL),
+ TPS65217_ENABLE_DC2_EN, NULL, tps65217_uv1_ranges,
+ ARRAY_SIZE(tps65217_uv1_ranges)),
TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64,
TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK,
- TPS65217_ENABLE_DC3_EN, NULL),
+ TPS65217_ENABLE_DC3_EN, NULL, tps65217_uv1_ranges,
+ 1), /* DCDC3 voltage range: 900000 ~ 1500000 */
TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16,
TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK,
- TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table),
+ TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table, NULL, 0),
TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64,
TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK,
- TPS65217_ENABLE_LDO2_EN, NULL),
+ TPS65217_ENABLE_LDO2_EN, NULL, tps65217_uv1_ranges,
+ ARRAY_SIZE(tps65217_uv1_ranges)),
TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32,
TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK,
TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
- NULL),
+ NULL, tps65217_uv2_ranges,
+ ARRAY_SIZE(tps65217_uv2_ranges)),
TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32,
TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK,
TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
- NULL),
+ NULL, tps65217_uv2_ranges,
+ ARRAY_SIZE(tps65217_uv2_ranges)),
};
#ifdef CONFIG_OF
@@ -368,8 +262,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
continue;
/* Register the regulators */
- tps->info[i] = &tps65217_pmic_regs[i];
-
config.dev = tps->dev;
config.init_data = reg_data;
config.driver_data = tps;
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 1094393155e..62e8d28beab 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -601,7 +601,7 @@ static int pmic_probe(struct spi_device *spi)
struct regulator_config config = { };
int ret = 0, i;
- init_data = dev->platform_data;
+ init_data = dev_get_platdata(dev);
if (!init_data) {
dev_err(dev, "could not find regulator platform data\n");
return -EINVAL;
diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c
index 17e994e47dc..281e52ac64b 100644
--- a/drivers/regulator/tps65912-regulator.c
+++ b/drivers/regulator/tps65912-regulator.c
@@ -118,6 +118,15 @@ struct tps65912_reg {
int eco_reg;
};
+static const struct regulator_linear_range tps65912_ldo_ranges[] = {
+ { .min_uV = 800000, .max_uV = 1600000, .min_sel = 0, .max_sel = 32,
+ .uV_step = 25000 },
+ { .min_uV = 1650000, .max_uV = 3000000, .min_sel = 33, .max_sel = 60,
+ .uV_step = 50000 },
+ { .min_uV = 3100000, .max_uV = 3300000, .min_sel = 61, .max_sel = 63,
+ .uV_step = 100000 },
+};
+
static int tps65912_get_range(struct tps65912_reg *pmic, int id)
{
struct tps65912 *mfd = pmic->mfd;
@@ -184,20 +193,6 @@ static unsigned long tps65912_vsel_to_uv_range3(u8 vsel)
return uv;
}
-static unsigned long tps65912_vsel_to_uv_ldo(u8 vsel)
-{
- unsigned long uv = 0;
-
- if (vsel <= 32)
- uv = ((vsel * 25000) + 800000);
- else if (vsel > 32 && vsel <= 60)
- uv = (((vsel - 32) * 50000) + 1600000);
- else if (vsel > 60)
- uv = (((vsel - 60) * 100000) + 3000000);
-
- return uv;
-}
-
static int tps65912_get_ctrl_register(int id)
{
if (id >= TPS65912_REG_DCDC1 && id <= TPS65912_REG_LDO4)
@@ -376,9 +371,6 @@ static int tps65912_list_voltage(struct regulator_dev *dev, unsigned selector)
struct tps65912_reg *pmic = rdev_get_drvdata(dev);
int range, voltage = 0, id = rdev_get_id(dev);
- if (id >= TPS65912_REG_LDO1 && id <= TPS65912_REG_LDO10)
- return tps65912_vsel_to_uv_ldo(selector);
-
if (id > TPS65912_REG_DCDC4)
return -EINVAL;
@@ -456,7 +448,8 @@ static struct regulator_ops tps65912_ops_ldo = {
.disable = tps65912_reg_disable,
.get_voltage_sel = tps65912_get_voltage_sel,
.set_voltage_sel = tps65912_set_voltage_sel,
- .list_voltage = tps65912_list_voltage,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
};
static int tps65912_probe(struct platform_device *pdev)
@@ -495,8 +488,14 @@ static int tps65912_probe(struct platform_device *pdev)
pmic->desc[i].name = info->name;
pmic->desc[i].id = i;
pmic->desc[i].n_voltages = 64;
- pmic->desc[i].ops = (i > TPS65912_REG_DCDC4 ?
- &tps65912_ops_ldo : &tps65912_ops_dcdc);
+ if (i > TPS65912_REG_DCDC4) {
+ pmic->desc[i].ops = &tps65912_ops_ldo;
+ pmic->desc[i].linear_ranges = tps65912_ldo_ranges;
+ pmic->desc[i].n_linear_ranges =
+ ARRAY_SIZE(tps65912_ldo_ranges);
+ } else {
+ pmic->desc[i].ops = &tps65912_ops_dcdc;
+ }
pmic->desc[i].type = REGULATOR_VOLTAGE;
pmic->desc[i].owner = THIS_MODULE;
range = tps65912_get_range(pmic, i);
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 93bc4f456da..78aae4cbb00 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -1108,7 +1108,7 @@ static int twlreg_probe(struct platform_device *pdev)
drvdata = NULL;
} else {
id = pdev->id;
- initdata = pdev->dev.platform_data;
+ initdata = dev_get_platdata(&pdev->dev);
for (i = 0, template = NULL; i < ARRAY_SIZE(twl_of_match); i++) {
template = twl_of_match[i].data;
if (template && template->desc.id == id)
diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c
index a7c8deb5f28..765acc11c9c 100644
--- a/drivers/regulator/userspace-consumer.c
+++ b/drivers/regulator/userspace-consumer.c
@@ -111,7 +111,7 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
struct userspace_consumer_data *drvdata;
int ret;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata)
return -EINVAL;
diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c
index a9d4284ea00..f53e78b9a84 100644
--- a/drivers/regulator/virtual.c
+++ b/drivers/regulator/virtual.c
@@ -287,7 +287,7 @@ static const struct attribute_group regulator_virtual_attr_group = {
static int regulator_virtual_probe(struct platform_device *pdev)
{
- char *reg_id = pdev->dev.platform_data;
+ char *reg_id = dev_get_platdata(&pdev->dev);
struct virtual_consumer_data *drvdata;
int ret;
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 46938cf162a..11861cb861d 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -451,7 +451,7 @@ static void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
static int wm831x_buckv_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
- struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
struct regulator_config config = { };
int id;
struct wm831x_dcdc *dcdc;
@@ -624,7 +624,7 @@ static struct regulator_ops wm831x_buckp_ops = {
static int wm831x_buckp_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
- struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
struct regulator_config config = { };
int id;
struct wm831x_dcdc *dcdc;
@@ -770,7 +770,7 @@ static struct regulator_ops wm831x_boostp_ops = {
static int wm831x_boostp_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
- struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
struct regulator_config config = { };
int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
struct wm831x_dcdc *dcdc;
@@ -880,7 +880,7 @@ static struct regulator_ops wm831x_epe_ops = {
static int wm831x_epe_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
- struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
struct regulator_config config = { };
int id = pdev->id % ARRAY_SIZE(pdata->epe);
struct wm831x_dcdc *dcdc;
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c
index 16ebdf94d0a..4eb373de1fa 100644
--- a/drivers/regulator/wm831x-isink.c
+++ b/drivers/regulator/wm831x-isink.c
@@ -151,7 +151,7 @@ static irqreturn_t wm831x_isink_irq(int irq, void *data)
static int wm831x_isink_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
- struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
struct wm831x_isink *isink;
int id = pdev->id % ARRAY_SIZE(pdata->isink);
struct regulator_config config = { };
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 9ff883f8087..1432b26ef2e 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -62,41 +62,12 @@ static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data)
* General purpose LDOs
*/
-#define WM831X_GP_LDO_SELECTOR_LOW 0xe
-#define WM831X_GP_LDO_MAX_SELECTOR 0x1f
-
-static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev,
- unsigned int selector)
-{
- /* 0.9-1.6V in 50mV steps */
- if (selector <= WM831X_GP_LDO_SELECTOR_LOW)
- return 900000 + (selector * 50000);
- /* 1.7-3.3V in 100mV steps */
- if (selector <= WM831X_GP_LDO_MAX_SELECTOR)
- return 1600000 + ((selector - WM831X_GP_LDO_SELECTOR_LOW)
- * 100000);
- return -EINVAL;
-}
-
-static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- int volt, vsel;
-
- if (min_uV < 900000)
- vsel = 0;
- else if (min_uV < 1700000)
- vsel = ((min_uV - 900000) / 50000);
- else
- vsel = ((min_uV - 1700000) / 100000)
- + WM831X_GP_LDO_SELECTOR_LOW + 1;
-
- volt = wm831x_gp_ldo_list_voltage(rdev, vsel);
- if (volt < min_uV || volt > max_uV)
- return -EINVAL;
-
- return vsel;
-}
+static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = {
+ { .min_uV = 900000, .max_uV = 1650000, .min_sel = 0, .max_sel = 14,
+ .uV_step = 50000 },
+ { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31,
+ .uV_step = 100000 },
+};
static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
int uV)
@@ -105,7 +76,7 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
struct wm831x *wm831x = ldo->wm831x;
int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
- sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV);
+ sel = regulator_map_voltage_linear_range(rdev, uV, uV);
if (sel < 0)
return sel;
@@ -230,8 +201,8 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
static struct regulator_ops wm831x_gp_ldo_ops = {
- .list_voltage = wm831x_gp_ldo_list_voltage,
- .map_voltage = wm831x_gp_ldo_map_voltage,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
@@ -250,7 +221,7 @@ static struct regulator_ops wm831x_gp_ldo_ops = {
static int wm831x_gp_ldo_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
- struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
struct regulator_config config = { };
int id;
struct wm831x_ldo *ldo;
@@ -290,7 +261,7 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev)
ldo->desc.id = id;
ldo->desc.type = REGULATOR_VOLTAGE;
- ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1;
+ ldo->desc.n_voltages = 32;
ldo->desc.ops = &wm831x_gp_ldo_ops;
ldo->desc.owner = THIS_MODULE;
ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
@@ -299,6 +270,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev)
ldo->desc.enable_mask = 1 << id;
ldo->desc.bypass_reg = ldo->base;
ldo->desc.bypass_mask = WM831X_LDO1_SWI;
+ ldo->desc.linear_ranges = wm831x_gp_ldo_ranges;
+ ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_gp_ldo_ranges);
config.dev = pdev->dev.parent;
if (pdata)
@@ -358,43 +331,12 @@ static struct platform_driver wm831x_gp_ldo_driver = {
* Analogue LDOs
*/
-
-#define WM831X_ALDO_SELECTOR_LOW 0xc
-#define WM831X_ALDO_MAX_SELECTOR 0x1f
-
-static int wm831x_aldo_list_voltage(struct regulator_dev *rdev,
- unsigned int selector)
-{
- /* 1-1.6V in 50mV steps */
- if (selector <= WM831X_ALDO_SELECTOR_LOW)
- return 1000000 + (selector * 50000);
- /* 1.7-3.5V in 100mV steps */
- if (selector <= WM831X_ALDO_MAX_SELECTOR)
- return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW)
- * 100000);
- return -EINVAL;
-}
-
-static int wm831x_aldo_map_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- int volt, vsel;
-
- if (min_uV < 1000000)
- vsel = 0;
- else if (min_uV < 1700000)
- vsel = ((min_uV - 1000000) / 50000);
- else
- vsel = ((min_uV - 1700000) / 100000)
- + WM831X_ALDO_SELECTOR_LOW + 1;
-
- volt = wm831x_aldo_list_voltage(rdev, vsel);
- if (volt < min_uV || volt > max_uV)
- return -EINVAL;
-
- return vsel;
-
-}
+static const struct regulator_linear_range wm831x_aldo_ranges[] = {
+ { .min_uV = 1000000, .max_uV = 1650000, .min_sel = 0, .max_sel = 12,
+ .uV_step = 50000 },
+ { .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31,
+ .uV_step = 100000 },
+};
static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
int uV)
@@ -403,7 +345,7 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
struct wm831x *wm831x = ldo->wm831x;
int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
- sel = wm831x_aldo_map_voltage(rdev, uV, uV);
+ sel = regulator_map_voltage_linear_range(rdev, uV, uV);
if (sel < 0)
return sel;
@@ -486,8 +428,8 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev)
}
static struct regulator_ops wm831x_aldo_ops = {
- .list_voltage = wm831x_aldo_list_voltage,
- .map_voltage = wm831x_aldo_map_voltage,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
@@ -505,7 +447,7 @@ static struct regulator_ops wm831x_aldo_ops = {
static int wm831x_aldo_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
- struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
struct regulator_config config = { };
int id;
struct wm831x_ldo *ldo;
@@ -545,7 +487,9 @@ static int wm831x_aldo_probe(struct platform_device *pdev)
ldo->desc.id = id;
ldo->desc.type = REGULATOR_VOLTAGE;
- ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1;
+ ldo->desc.n_voltages = 32;
+ ldo->desc.linear_ranges = wm831x_aldo_ranges;
+ ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_aldo_ranges);
ldo->desc.ops = &wm831x_aldo_ops;
ldo->desc.owner = THIS_MODULE;
ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
@@ -661,7 +605,7 @@ static struct regulator_ops wm831x_alive_ldo_ops = {
static int wm831x_alive_ldo_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
- struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
struct regulator_config config = { };
int id;
struct wm831x_ldo *ldo;
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 7f0fa22ef2a..835b5f0f344 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -542,41 +542,12 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
return 0;
}
-static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
-{
- if (selector > WM8350_LDO1_VSEL_MASK)
- return -EINVAL;
-
- if (selector < 16)
- return (selector * 50000) + 900000;
- else
- return ((selector - 16) * 100000) + 1800000;
-}
-
-static int wm8350_ldo_map_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV)
-{
- int volt, sel;
- int min_mV = min_uV / 1000;
- int max_mV = max_uV / 1000;
-
- if (min_mV < 900 || min_mV > 3300)
- return -EINVAL;
- if (max_mV < 900 || max_mV > 3300)
- return -EINVAL;
-
- if (min_mV < 1800) /* step size is 50mV < 1800mV */
- sel = DIV_ROUND_UP(min_uV - 900, 50);
- else /* step size is 100mV > 1800mV */
- sel = DIV_ROUND_UP(min_uV - 1800, 100) + 16;
-
- volt = wm8350_ldo_list_voltage(rdev, sel);
- if (volt < min_uV || volt > max_uV)
- return -EINVAL;
-
- return sel;
-}
+static const struct regulator_linear_range wm8350_ldo_ranges[] = {
+ { .min_uV = 900000, .max_uV = 1750000, .min_sel = 0, .max_sel = 15,
+ .uV_step = 50000 },
+ { .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31,
+ .uV_step = 100000 },
+};
static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
@@ -603,7 +574,7 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
return -EINVAL;
}
- sel = wm8350_ldo_map_voltage(rdev, uV, uV);
+ sel = regulator_map_voltage_linear_range(rdev, uV, uV);
if (sel < 0)
return -EINVAL;
@@ -998,10 +969,10 @@ static struct regulator_ops wm8350_dcdc2_5_ops = {
};
static struct regulator_ops wm8350_ldo_ops = {
- .map_voltage = wm8350_ldo_map_voltage,
+ .map_voltage = regulator_map_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .list_voltage = wm8350_ldo_list_voltage,
+ .list_voltage = regulator_list_voltage_linear_range,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
@@ -1108,6 +1079,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.irq = WM8350_IRQ_UV_LDO1,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO1_VSEL_MASK + 1,
+ .linear_ranges = wm8350_ldo_ranges,
+ .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
.vsel_reg = WM8350_LDO1_CONTROL,
.vsel_mask = WM8350_LDO1_VSEL_MASK,
.enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1121,6 +1094,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.irq = WM8350_IRQ_UV_LDO2,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO2_VSEL_MASK + 1,
+ .linear_ranges = wm8350_ldo_ranges,
+ .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
.vsel_reg = WM8350_LDO2_CONTROL,
.vsel_mask = WM8350_LDO2_VSEL_MASK,
.enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1134,6 +1109,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.irq = WM8350_IRQ_UV_LDO3,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO3_VSEL_MASK + 1,
+ .linear_ranges = wm8350_ldo_ranges,
+ .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
.vsel_reg = WM8350_LDO3_CONTROL,
.vsel_mask = WM8350_LDO3_VSEL_MASK,
.enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1147,6 +1124,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.irq = WM8350_IRQ_UV_LDO4,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO4_VSEL_MASK + 1,
+ .linear_ranges = wm8350_ldo_ranges,
+ .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
.vsel_reg = WM8350_LDO4_CONTROL,
.vsel_mask = WM8350_LDO4_VSEL_MASK,
.enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1222,7 +1201,7 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
}
config.dev = &pdev->dev;
- config.init_data = pdev->dev.platform_data;
+ config.init_data = dev_get_platdata(&pdev->dev);
config.driver_data = dev_get_drvdata(&pdev->dev);
config.regmap = wm8350->regmap;
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index a09f03ee550..58f51bec13f 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -19,47 +19,21 @@
#include <linux/regulator/driver.h>
#include <linux/mfd/wm8400-private.h>
-static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
- unsigned selector)
-{
- if (selector > WM8400_LDO1_VSEL_MASK)
- return -EINVAL;
-
- if (selector < 15)
- return 900000 + (selector * 50000);
- else
- return 1700000 + ((selector - 15) * 100000);
-}
-
-static int wm8400_ldo_map_voltage(struct regulator_dev *dev,
- int min_uV, int max_uV)
-{
- u16 val;
- int volt;
-
- if (min_uV < 900000 || min_uV > 3300000)
- return -EINVAL;
-
- if (min_uV < 1700000) /* Steps of 50mV from 900mV; */
- val = DIV_ROUND_UP(min_uV - 900000, 50000);
- else /* Steps of 100mV from 1700mV */
- val = DIV_ROUND_UP(min_uV - 1700000, 100000) + 15;
-
- volt = wm8400_ldo_list_voltage(dev, val);
- if (volt < min_uV || volt > max_uV)
- return -EINVAL;
-
- return val;
-}
+static const struct regulator_linear_range wm8400_ldo_ranges[] = {
+ { .min_uV = 900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14,
+ .uV_step = 50000 },
+ { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31,
+ .uV_step = 100000 },
+};
static struct regulator_ops wm8400_ldo_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .list_voltage = wm8400_ldo_list_voltage,
+ .list_voltage = regulator_list_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .map_voltage = wm8400_ldo_map_voltage,
+ .map_voltage = regulator_map_voltage_linear_range,
};
static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
@@ -155,6 +129,8 @@ static struct regulator_desc regulators[] = {
.enable_reg = WM8400_LDO1_CONTROL,
.enable_mask = WM8400_LDO1_ENA,
.n_voltages = WM8400_LDO1_VSEL_MASK + 1,
+ .linear_ranges = wm8400_ldo_ranges,
+ .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
.vsel_reg = WM8400_LDO1_CONTROL,
.vsel_mask = WM8400_LDO1_VSEL_MASK,
.type = REGULATOR_VOLTAGE,
@@ -167,6 +143,8 @@ static struct regulator_desc regulators[] = {
.enable_reg = WM8400_LDO2_CONTROL,
.enable_mask = WM8400_LDO2_ENA,
.n_voltages = WM8400_LDO2_VSEL_MASK + 1,
+ .linear_ranges = wm8400_ldo_ranges,
+ .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
.type = REGULATOR_VOLTAGE,
.vsel_reg = WM8400_LDO2_CONTROL,
.vsel_mask = WM8400_LDO2_VSEL_MASK,
@@ -179,6 +157,8 @@ static struct regulator_desc regulators[] = {
.enable_reg = WM8400_LDO3_CONTROL,
.enable_mask = WM8400_LDO3_ENA,
.n_voltages = WM8400_LDO3_VSEL_MASK + 1,
+ .linear_ranges = wm8400_ldo_ranges,
+ .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
.vsel_reg = WM8400_LDO3_CONTROL,
.vsel_mask = WM8400_LDO3_VSEL_MASK,
.type = REGULATOR_VOLTAGE,
@@ -191,6 +171,8 @@ static struct regulator_desc regulators[] = {
.enable_reg = WM8400_LDO4_CONTROL,
.enable_mask = WM8400_LDO4_ENA,
.n_voltages = WM8400_LDO4_VSEL_MASK + 1,
+ .linear_ranges = wm8400_ldo_ranges,
+ .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
.vsel_reg = WM8400_LDO4_CONTROL,
.vsel_mask = WM8400_LDO4_VSEL_MASK,
.type = REGULATOR_VOLTAGE,
@@ -233,7 +215,7 @@ static int wm8400_regulator_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
config.dev = &pdev->dev;
- config.init_data = pdev->dev.platform_data;
+ config.init_data = dev_get_platdata(&pdev->dev);
config.driver_data = wm8400;
config.regmap = wm8400->regmap;
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 8f2a8a7a3f9..5ee2a208457 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -125,7 +125,7 @@ static const struct regulator_init_data wm8994_ldo_default[] = {
static int wm8994_ldo_probe(struct platform_device *pdev)
{
struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
- struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+ struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev);
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
struct regulator_config config = { };
struct wm8994_ldo *ldo;
diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c
index 767fee2ab34..26019531db1 100644
--- a/drivers/rtc/rtc-stmp3xxx.c
+++ b/drivers/rtc/rtc-stmp3xxx.c
@@ -23,6 +23,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/of_device.h>
@@ -119,24 +120,39 @@ static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev)
}
#endif /* CONFIG_STMP3XXX_RTC_WATCHDOG */
-static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data)
+static int stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data)
{
+ int timeout = 5000; /* 3ms according to i.MX28 Ref Manual */
/*
- * The datasheet doesn't say which way round the
- * NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0,
- * 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS
+ * The i.MX28 Applications Processor Reference Manual, Rev. 1, 2010
+ * states:
+ * | The order in which registers are updated is
+ * | Persistent 0, 1, 2, 3, 4, 5, Alarm, Seconds.
+ * | (This list is in bitfield order, from LSB to MSB, as they would
+ * | appear in the STALE_REGS and NEW_REGS bitfields of the HW_RTC_STAT
+ * | register. For example, the Seconds register corresponds to
+ * | STALE_REGS or NEW_REGS containing 0x80.)
*/
- while (readl(rtc_data->io + STMP3XXX_RTC_STAT) &
- (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT))
- cpu_relax();
+ do {
+ if (!(readl(rtc_data->io + STMP3XXX_RTC_STAT) &
+ (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)))
+ return 0;
+ udelay(1);
+ } while (--timeout > 0);
+ return (readl(rtc_data->io + STMP3XXX_RTC_STAT) &
+ (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)) ? -ETIME : 0;
}
/* Time read/write */
static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
{
+ int ret;
struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
- stmp3xxx_wait_time(rtc_data);
+ ret = stmp3xxx_wait_time(rtc_data);
+ if (ret)
+ return ret;
+
rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_SECONDS), rtc_tm);
return 0;
}
@@ -146,8 +162,7 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t)
struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS);
- stmp3xxx_wait_time(rtc_data);
- return 0;
+ return stmp3xxx_wait_time(rtc_data);
}
/* interrupt(s) handler */
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 4b26f8672b2..babd43bf3dd 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -25,15 +25,14 @@
*/
static ssize_t
-rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
- char *buf)
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
}
+static DEVICE_ATTR_RO(name);
static ssize_t
-rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
- char *buf)
+date_show(struct device *dev, struct device_attribute *attr, char *buf)
{
ssize_t retval;
struct rtc_time tm;
@@ -46,10 +45,10 @@ rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
return retval;
}
+static DEVICE_ATTR_RO(date);
static ssize_t
-rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
- char *buf)
+time_show(struct device *dev, struct device_attribute *attr, char *buf)
{
ssize_t retval;
struct rtc_time tm;
@@ -62,10 +61,10 @@ rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
return retval;
}
+static DEVICE_ATTR_RO(time);
static ssize_t
-rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
- char *buf)
+since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf)
{
ssize_t retval;
struct rtc_time tm;
@@ -79,16 +78,16 @@ rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
return retval;
}
+static DEVICE_ATTR_RO(since_epoch);
static ssize_t
-rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr,
- char *buf)
+max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
}
static ssize_t
-rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
+max_user_freq_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t n)
{
struct rtc_device *rtc = to_rtc_device(dev);
@@ -101,6 +100,7 @@ rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
return n;
}
+static DEVICE_ATTR_RW(max_user_freq);
/**
* rtc_sysfs_show_hctosys - indicate if the given RTC set the system time
@@ -109,8 +109,7 @@ rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
* boot or resume event.
*/
static ssize_t
-rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr,
- char *buf)
+hctosys_show(struct device *dev, struct device_attribute *attr, char *buf)
{
#ifdef CONFIG_RTC_HCTOSYS_DEVICE
if (rtc_hctosys_ret == 0 &&
@@ -121,17 +120,18 @@ rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr,
#endif
return sprintf(buf, "0\n");
}
-
-static struct device_attribute rtc_attrs[] = {
- __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
- __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
- __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
- __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
- __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,
- rtc_sysfs_set_max_user_freq),
- __ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),
- { },
+static DEVICE_ATTR_RO(hctosys);
+
+static struct attribute *rtc_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_date.attr,
+ &dev_attr_time.attr,
+ &dev_attr_since_epoch.attr,
+ &dev_attr_max_user_freq.attr,
+ &dev_attr_hctosys.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(rtc);
static ssize_t
rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
@@ -261,5 +261,5 @@ void rtc_sysfs_del_device(struct rtc_device *rtc)
void __init rtc_sysfs_init(struct class *rtc_class)
{
- rtc_class->dev_attrs = rtc_attrs;
+ rtc_class->dev_groups = rtc_groups;
}
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index 02faf3c4e0d..c2e80d7ca5e 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -524,6 +524,8 @@ static int twl_rtc_probe(struct platform_device *pdev)
if (ret < 0)
goto out1;
+ device_init_wakeup(&pdev->dev, 1);
+
rtc = rtc_device_register(pdev->name,
&pdev->dev, &twl_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
@@ -542,7 +544,6 @@ static int twl_rtc_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, rtc);
- device_init_wakeup(&pdev->dev, 1);
return 0;
out2:
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 17150a77898..451bf99582f 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2392,6 +2392,12 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
rc = cqr->intrc;
else
rc = -EIO;
+
+ /* kick tasklets */
+ dasd_schedule_device_bh(device);
+ if (device->block)
+ dasd_schedule_block_bh(device->block);
+
return rc;
}
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 58bc6eb49de..2ead7e78c45 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -930,7 +930,7 @@ dasd_use_raw_store(struct device *dev, struct device_attribute *attr,
if (IS_ERR(devmap))
return PTR_ERR(devmap);
- if ((strict_strtoul(buf, 10, &val) != 0) || val > 1)
+ if ((kstrtoul(buf, 10, &val) != 0) || val > 1)
return -EINVAL;
spin_lock(&dasd_devmap_lock);
@@ -1225,7 +1225,7 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr,
if (IS_ERR(device))
return -ENODEV;
- if ((strict_strtoul(buf, 10, &val) != 0) ||
+ if ((kstrtoul(buf, 10, &val) != 0) ||
(val > DASD_EXPIRES_MAX) || val == 0) {
dasd_put_device(device);
return -EINVAL;
@@ -1265,7 +1265,7 @@ dasd_retries_store(struct device *dev, struct device_attribute *attr,
if (IS_ERR(device))
return -ENODEV;
- if ((strict_strtoul(buf, 10, &val) != 0) ||
+ if ((kstrtoul(buf, 10, &val) != 0) ||
(val > DASD_RETRIES_MAX)) {
dasd_put_device(device);
return -EINVAL;
@@ -1307,7 +1307,7 @@ dasd_timeout_store(struct device *dev, struct device_attribute *attr,
if (IS_ERR(device) || !device->block)
return -ENODEV;
- if ((strict_strtoul(buf, 10, &val) != 0) ||
+ if ((kstrtoul(buf, 10, &val) != 0) ||
val > UINT_MAX / HZ) {
dasd_put_device(device);
return -EINVAL;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index e61a6deea3c..5adb2042e82 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -85,6 +85,8 @@ MODULE_DEVICE_TABLE(ccw, dasd_eckd_ids);
static struct ccw_driver dasd_eckd_driver; /* see below */
+static void *rawpadpage;
+
#define INIT_CQR_OK 0
#define INIT_CQR_UNFORMATTED 1
#define INIT_CQR_ERROR 2
@@ -3237,18 +3239,26 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
unsigned int seg_len, len_to_track_end;
unsigned int first_offs;
unsigned int cidaw, cplength, datasize;
- sector_t first_trk, last_trk;
+ sector_t first_trk, last_trk, sectors;
+ sector_t start_padding_sectors, end_sector_offset, end_padding_sectors;
unsigned int pfx_datasize;
/*
* raw track access needs to be mutiple of 64k and on 64k boundary
+ * For read requests we can fix an incorrect alignment by padding
+ * the request with dummy pages.
*/
- if ((blk_rq_pos(req) % DASD_RAW_SECTORS_PER_TRACK) != 0) {
- cqr = ERR_PTR(-EINVAL);
- goto out;
- }
- if (((blk_rq_pos(req) + blk_rq_sectors(req)) %
- DASD_RAW_SECTORS_PER_TRACK) != 0) {
+ start_padding_sectors = blk_rq_pos(req) % DASD_RAW_SECTORS_PER_TRACK;
+ end_sector_offset = (blk_rq_pos(req) + blk_rq_sectors(req)) %
+ DASD_RAW_SECTORS_PER_TRACK;
+ end_padding_sectors = (DASD_RAW_SECTORS_PER_TRACK - end_sector_offset) %
+ DASD_RAW_SECTORS_PER_TRACK;
+ basedev = block->base;
+ if ((start_padding_sectors || end_padding_sectors) &&
+ (rq_data_dir(req) == WRITE)) {
+ DBF_DEV_EVENT(DBF_ERR, basedev,
+ "raw write not track aligned (%lu,%lu) req %p",
+ start_padding_sectors, end_padding_sectors, req);
cqr = ERR_PTR(-EINVAL);
goto out;
}
@@ -3258,7 +3268,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
DASD_RAW_SECTORS_PER_TRACK;
trkcount = last_trk - first_trk + 1;
first_offs = 0;
- basedev = block->base;
if (rq_data_dir(req) == READ)
cmd = DASD_ECKD_CCW_READ_TRACK;
@@ -3307,12 +3316,26 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
}
idaws = (unsigned long *)(cqr->data + pfx_datasize);
-
len_to_track_end = 0;
-
+ if (start_padding_sectors) {
+ ccw[-1].flags |= CCW_FLAG_CC;
+ ccw->cmd_code = cmd;
+ /* maximum 3390 track size */
+ ccw->count = 57326;
+ /* 64k map to one track */
+ len_to_track_end = 65536 - start_padding_sectors * 512;
+ ccw->cda = (__u32)(addr_t)idaws;
+ ccw->flags |= CCW_FLAG_IDA;
+ ccw->flags |= CCW_FLAG_SLI;
+ ccw++;
+ for (sectors = 0; sectors < start_padding_sectors; sectors += 8)
+ idaws = idal_create_words(idaws, rawpadpage, PAGE_SIZE);
+ }
rq_for_each_segment(bv, req, iter) {
dst = page_address(bv->bv_page) + bv->bv_offset;
seg_len = bv->bv_len;
+ if (cmd == DASD_ECKD_CCW_READ_TRACK)
+ memset(dst, 0, seg_len);
if (!len_to_track_end) {
ccw[-1].flags |= CCW_FLAG_CC;
ccw->cmd_code = cmd;
@@ -3328,7 +3351,8 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
len_to_track_end -= seg_len;
idaws = idal_create_words(idaws, dst, seg_len);
}
-
+ for (sectors = 0; sectors < end_padding_sectors; sectors += 8)
+ idaws = idal_create_words(idaws, rawpadpage, PAGE_SIZE);
if (blk_noretry_request(req) ||
block->base->features & DASD_FEATURE_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
@@ -4479,12 +4503,19 @@ dasd_eckd_init(void)
kfree(dasd_reserve_req);
return -ENOMEM;
}
+ rawpadpage = (void *)__get_free_page(GFP_KERNEL);
+ if (!rawpadpage) {
+ kfree(path_verification_worker);
+ kfree(dasd_reserve_req);
+ return -ENOMEM;
+ }
ret = ccw_driver_register(&dasd_eckd_driver);
if (!ret)
wait_for_device_probe();
else {
kfree(path_verification_worker);
kfree(dasd_reserve_req);
+ free_page((unsigned long)rawpadpage);
}
return ret;
}
@@ -4495,6 +4526,7 @@ dasd_eckd_cleanup(void)
ccw_driver_unregister(&dasd_eckd_driver);
kfree(path_verification_worker);
kfree(dasd_reserve_req);
+ free_page((unsigned long)rawpadpage);
}
module_init(dasd_eckd_init);
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index 8d11f773a75..e1e88486b2b 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -124,10 +124,15 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr)
struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
{
int success;
+ unsigned long long startclk, stopclk;
+ struct dasd_device *startdev;
BUG_ON(cqr->refers == NULL || cqr->function == NULL);
success = cqr->status == DASD_CQR_DONE;
+ startclk = cqr->startclk;
+ stopclk = cqr->stopclk;
+ startdev = cqr->startdev;
/* free all ERPs - but NOT the original cqr */
while (cqr->refers != NULL) {
@@ -142,6 +147,9 @@ struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
}
/* set corresponding status to original cqr */
+ cqr->startclk = startclk;
+ cqr->stopclk = stopclk;
+ cqr->startdev = startdev;
if (success)
cqr->status = DASD_CQR_DONE;
else {
@@ -160,11 +168,13 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
device = cqr->startdev;
if (cqr->intrc == -ETIMEDOUT) {
- dev_err(&device->cdev->dev, "cqr %p timeout error", cqr);
+ dev_err(&device->cdev->dev,
+ "A timeout error occurred for cqr %p", cqr);
return;
}
if (cqr->intrc == -ENOLINK) {
- dev_err(&device->cdev->dev, "cqr %p transport error", cqr);
+ dev_err(&device->cdev->dev,
+ "A transport error occurred for cqr %p", cqr);
return;
}
/* dump sense data */
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index 444d36183a2..94415620747 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -32,7 +32,7 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
struct device *dev;
s390_adjust_jiffies();
- pr_warning("cpu capability changed.\n");
+ pr_info("CPU capability may have changed\n");
get_online_cpus();
for_each_online_cpu(cpu) {
dev = get_cpu_device(cpu);
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index 91edbd7ee80..d028fd800c9 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -81,15 +81,185 @@ void unregister_adapter_interrupt(struct airq_struct *airq)
}
EXPORT_SYMBOL(unregister_adapter_interrupt);
-void do_adapter_IO(u8 isc)
+static irqreturn_t do_airq_interrupt(int irq, void *dummy)
{
+ struct tpi_info *tpi_info;
struct airq_struct *airq;
struct hlist_head *head;
- head = &airq_lists[isc];
+ __this_cpu_write(s390_idle.nohz_delay, 1);
+ tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+ head = &airq_lists[tpi_info->isc];
rcu_read_lock();
hlist_for_each_entry_rcu(airq, head, list)
if ((*airq->lsi_ptr & airq->lsi_mask) != 0)
airq->handler(airq);
rcu_read_unlock();
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction airq_interrupt = {
+ .name = "AIO",
+ .handler = do_airq_interrupt,
+};
+
+void __init init_airq_interrupts(void)
+{
+ irq_set_chip_and_handler(THIN_INTERRUPT,
+ &dummy_irq_chip, handle_percpu_irq);
+ setup_irq(THIN_INTERRUPT, &airq_interrupt);
+}
+
+/**
+ * airq_iv_create - create an interrupt vector
+ * @bits: number of bits in the interrupt vector
+ * @flags: allocation flags
+ *
+ * Returns a pointer to an interrupt vector structure
+ */
+struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags)
+{
+ struct airq_iv *iv;
+ unsigned long size;
+
+ iv = kzalloc(sizeof(*iv), GFP_KERNEL);
+ if (!iv)
+ goto out;
+ iv->bits = bits;
+ size = BITS_TO_LONGS(bits) * sizeof(unsigned long);
+ iv->vector = kzalloc(size, GFP_KERNEL);
+ if (!iv->vector)
+ goto out_free;
+ if (flags & AIRQ_IV_ALLOC) {
+ iv->avail = kmalloc(size, GFP_KERNEL);
+ if (!iv->avail)
+ goto out_free;
+ memset(iv->avail, 0xff, size);
+ iv->end = 0;
+ } else
+ iv->end = bits;
+ if (flags & AIRQ_IV_BITLOCK) {
+ iv->bitlock = kzalloc(size, GFP_KERNEL);
+ if (!iv->bitlock)
+ goto out_free;
+ }
+ if (flags & AIRQ_IV_PTR) {
+ size = bits * sizeof(unsigned long);
+ iv->ptr = kzalloc(size, GFP_KERNEL);
+ if (!iv->ptr)
+ goto out_free;
+ }
+ if (flags & AIRQ_IV_DATA) {
+ size = bits * sizeof(unsigned int);
+ iv->data = kzalloc(size, GFP_KERNEL);
+ if (!iv->data)
+ goto out_free;
+ }
+ spin_lock_init(&iv->lock);
+ return iv;
+
+out_free:
+ kfree(iv->ptr);
+ kfree(iv->bitlock);
+ kfree(iv->avail);
+ kfree(iv->vector);
+ kfree(iv);
+out:
+ return NULL;
+}
+EXPORT_SYMBOL(airq_iv_create);
+
+/**
+ * airq_iv_release - release an interrupt vector
+ * @iv: pointer to interrupt vector structure
+ */
+void airq_iv_release(struct airq_iv *iv)
+{
+ kfree(iv->data);
+ kfree(iv->ptr);
+ kfree(iv->bitlock);
+ kfree(iv->vector);
+ kfree(iv->avail);
+ kfree(iv);
+}
+EXPORT_SYMBOL(airq_iv_release);
+
+/**
+ * airq_iv_alloc_bit - allocate an irq bit from an interrupt vector
+ * @iv: pointer to an interrupt vector structure
+ *
+ * Returns the bit number of the allocated irq, or -1UL if no bit
+ * is available or the AIRQ_IV_ALLOC flag has not been specified
+ */
+unsigned long airq_iv_alloc_bit(struct airq_iv *iv)
+{
+ const unsigned long be_to_le = BITS_PER_LONG - 1;
+ unsigned long bit;
+
+ if (!iv->avail)
+ return -1UL;
+ spin_lock(&iv->lock);
+ bit = find_first_bit_left(iv->avail, iv->bits);
+ if (bit < iv->bits) {
+ clear_bit(bit ^ be_to_le, iv->avail);
+ if (bit >= iv->end)
+ iv->end = bit + 1;
+ } else
+ bit = -1UL;
+ spin_unlock(&iv->lock);
+ return bit;
+
+}
+EXPORT_SYMBOL(airq_iv_alloc_bit);
+
+/**
+ * airq_iv_free_bit - free an irq bit of an interrupt vector
+ * @iv: pointer to interrupt vector structure
+ * @bit: number of the irq bit to free
+ */
+void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
+{
+ const unsigned long be_to_le = BITS_PER_LONG - 1;
+
+ if (!iv->avail)
+ return;
+ spin_lock(&iv->lock);
+ /* Clear (possibly left over) interrupt bit */
+ clear_bit(bit ^ be_to_le, iv->vector);
+ /* Make the bit position available again */
+ set_bit(bit ^ be_to_le, iv->avail);
+ if (bit == iv->end - 1) {
+ /* Find new end of bit-field */
+ while (--iv->end > 0)
+ if (!test_bit((iv->end - 1) ^ be_to_le, iv->avail))
+ break;
+ }
+ spin_unlock(&iv->lock);
+}
+EXPORT_SYMBOL(airq_iv_free_bit);
+
+/**
+ * airq_iv_scan - scan interrupt vector for non-zero bits
+ * @iv: pointer to interrupt vector structure
+ * @start: bit number to start the search
+ * @end: bit number to end the search
+ *
+ * Returns the bit number of the next non-zero interrupt bit, or
+ * -1UL if the scan completed without finding any more any non-zero bits.
+ */
+unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
+ unsigned long end)
+{
+ const unsigned long be_to_le = BITS_PER_LONG - 1;
+ unsigned long bit;
+
+ /* Find non-zero bit starting from 'ivs->next'. */
+ bit = find_next_bit_left(iv->vector, end, start);
+ if (bit >= end)
+ return -1UL;
+ /* Clear interrupt bit (find left uses big-endian bit numbers) */
+ clear_bit(bit ^ be_to_le, iv->vector);
+ return bit;
}
+EXPORT_SYMBOL(airq_iv_scan);
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 84846c2b96d..959135a0184 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -137,7 +137,7 @@ static ssize_t ccwgroup_online_store(struct device *dev,
if (!try_module_get(gdrv->driver.owner))
return -EINVAL;
- ret = strict_strtoul(buf, 0, &value);
+ ret = kstrtoul(buf, 0, &value);
if (ret)
goto out;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 4eeb4a6bf20..d7da67a31c7 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -561,37 +561,23 @@ out:
}
/*
- * do_IRQ() handles all normal I/O device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
- *
+ * do_cio_interrupt() handles all normal I/O device IRQ's
*/
-void __irq_entry do_IRQ(struct pt_regs *regs)
+static irqreturn_t do_cio_interrupt(int irq, void *dummy)
{
- struct tpi_info *tpi_info = (struct tpi_info *) &regs->int_code;
+ struct tpi_info *tpi_info;
struct subchannel *sch;
struct irb *irb;
- struct pt_regs *old_regs;
- old_regs = set_irq_regs(regs);
- irq_enter();
__this_cpu_write(s390_idle.nohz_delay, 1);
- if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
- /* Serve timer interrupts first. */
- clock_comparator_work();
-
- kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
+ tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
irb = (struct irb *) &S390_lowcore.irb;
- if (tpi_info->adapter_IO) {
- do_adapter_IO(tpi_info->isc);
- goto out;
- }
sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
if (!sch) {
/* Clear pending interrupt condition. */
inc_irq_stat(IRQIO_CIO);
tsch(tpi_info->schid, irb);
- goto out;
+ return IRQ_HANDLED;
}
spin_lock(sch->lock);
/* Store interrupt response block to lowcore. */
@@ -606,9 +592,23 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
} else
inc_irq_stat(IRQIO_CIO);
spin_unlock(sch->lock);
-out:
- irq_exit();
- set_irq_regs(old_regs);
+
+ return IRQ_HANDLED;
+}
+
+static struct irq_desc *irq_desc_io;
+
+static struct irqaction io_interrupt = {
+ .name = "IO",
+ .handler = do_cio_interrupt,
+};
+
+void __init init_cio_interrupts(void)
+{
+ irq_set_chip_and_handler(IO_INTERRUPT,
+ &dummy_irq_chip, handle_percpu_irq);
+ setup_irq(IO_INTERRUPT, &io_interrupt);
+ irq_desc_io = irq_to_desc(IO_INTERRUPT);
}
#ifdef CONFIG_CCW_CONSOLE
@@ -635,7 +635,7 @@ void cio_tsch(struct subchannel *sch)
local_bh_disable();
irq_enter();
}
- kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
+ kstat_incr_irqs_this_cpu(IO_INTERRUPT, irq_desc_io);
if (sch->driver && sch->driver->irq)
sch->driver->irq(sch);
else
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index d62f5e7f3cf..d42f67412bd 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -121,9 +121,6 @@ extern int cio_commit_config(struct subchannel *sch);
int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
int cio_tm_intrg(struct subchannel *sch);
-void do_adapter_IO(u8 isc);
-void do_IRQ(struct pt_regs *);
-
/* Use with care. */
#ifdef CONFIG_CCW_CONSOLE
extern struct subchannel *cio_probe_console(void);
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 4495e0627a4..23054f8fa9f 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1182,7 +1182,7 @@ static ssize_t cmb_enable_store(struct device *dev,
int ret;
unsigned long val;
- ret = strict_strtoul(buf, 16, &val);
+ ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 1ebe5d3ddeb..8c2cb87bccc 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -546,7 +546,9 @@ static int slow_eval_unknown_fn(struct subchannel_id schid, void *data)
case -ENOMEM:
case -EIO:
/* These should abort looping */
+ spin_lock_irq(&slow_subchannel_lock);
idset_sch_del_subseq(slow_subchannel_set, schid);
+ spin_unlock_irq(&slow_subchannel_lock);
break;
default:
rc = 0;
@@ -740,7 +742,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr,
int ret;
unsigned long val;
- ret = strict_strtoul(buf, 16, &val);
+ ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
mutex_lock(&css->mutex);
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index b1de6033523..29351321bad 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -130,8 +130,6 @@ struct channel_subsystem {
extern struct channel_subsystem *channel_subsystems[];
-void channel_subsystem_reinit(void);
-
/* Helper functions to build lists for the slow path. */
void css_schedule_eval(struct subchannel_id schid);
void css_schedule_eval_all(void);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 1ab5f6c36d9..e4a7ab2bb62 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -564,7 +564,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
ret = 0;
} else {
force = 0;
- ret = strict_strtoul(buf, 16, &i);
+ ret = kstrtoul(buf, 16, &i);
}
if (ret)
goto out;
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index d1c8025b0b0..adef5f5de11 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -208,7 +208,7 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
goto out;
}
- rc = strict_strtoul(buf, 16, &i);
+ rc = kstrtoul(buf, 16, &i);
if (rc) {
rc = -EINVAL;
goto out;
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 1b9e4aee914..8004b071a9f 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -104,11 +104,11 @@ static void __init zfcp_init_device_setup(char *devstr)
strncpy(busid, token, ZFCP_BUS_ID_SIZE);
token = strsep(&str, ",");
- if (!token || strict_strtoull(token, 0, (unsigned long long *) &wwpn))
+ if (!token || kstrtoull(token, 0, (unsigned long long *) &wwpn))
goto err_out;
token = strsep(&str, ",");
- if (!token || strict_strtoull(token, 0, (unsigned long long *) &lun))
+ if (!token || kstrtoull(token, 0, (unsigned long long *) &lun))
goto err_out;
kfree(str_saved);
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 1d4c8fe7275..c82fe65c412 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -102,10 +102,13 @@ static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
zfcp_erp_action_dismiss(&port->erp_action);
- else
- shost_for_each_device(sdev, port->adapter->scsi_host)
+ else {
+ spin_lock(port->adapter->scsi_host->host_lock);
+ __shost_for_each_device(sdev, port->adapter->scsi_host)
if (sdev_to_zfcp(sdev)->port == port)
zfcp_erp_action_dismiss_lun(sdev);
+ spin_unlock(port->adapter->scsi_host->host_lock);
+ }
}
static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
@@ -592,9 +595,11 @@ static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear,
{
struct scsi_device *sdev;
- shost_for_each_device(sdev, port->adapter->scsi_host)
+ spin_lock(port->adapter->scsi_host->host_lock);
+ __shost_for_each_device(sdev, port->adapter->scsi_host)
if (sdev_to_zfcp(sdev)->port == port)
_zfcp_erp_lun_reopen(sdev, clear, id, 0);
+ spin_unlock(port->adapter->scsi_host->host_lock);
}
static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
@@ -1434,8 +1439,10 @@ void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask)
atomic_set_mask(common_mask, &port->status);
read_unlock_irqrestore(&adapter->port_list_lock, flags);
- shost_for_each_device(sdev, adapter->scsi_host)
+ spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
+ __shost_for_each_device(sdev, adapter->scsi_host)
atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status);
+ spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
}
/**
@@ -1469,11 +1476,13 @@ void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask)
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
- shost_for_each_device(sdev, adapter->scsi_host) {
+ spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
+ __shost_for_each_device(sdev, adapter->scsi_host) {
atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status);
if (clear_counter)
atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
}
+ spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
}
/**
@@ -1487,16 +1496,19 @@ void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask)
{
struct scsi_device *sdev;
u32 common_mask = mask & ZFCP_COMMON_FLAGS;
+ unsigned long flags;
atomic_set_mask(mask, &port->status);
if (!common_mask)
return;
- shost_for_each_device(sdev, port->adapter->scsi_host)
+ spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
+ __shost_for_each_device(sdev, port->adapter->scsi_host)
if (sdev_to_zfcp(sdev)->port == port)
atomic_set_mask(common_mask,
&sdev_to_zfcp(sdev)->status);
+ spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
}
/**
@@ -1511,6 +1523,7 @@ void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask)
struct scsi_device *sdev;
u32 common_mask = mask & ZFCP_COMMON_FLAGS;
u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
+ unsigned long flags;
atomic_clear_mask(mask, &port->status);
@@ -1520,13 +1533,15 @@ void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask)
if (clear_counter)
atomic_set(&port->erp_counter, 0);
- shost_for_each_device(sdev, port->adapter->scsi_host)
+ spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
+ __shost_for_each_device(sdev, port->adapter->scsi_host)
if (sdev_to_zfcp(sdev)->port == port) {
atomic_clear_mask(common_mask,
&sdev_to_zfcp(sdev)->status);
if (clear_counter)
atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
}
+ spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
}
/**
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 83e3f1408c3..a9c570a09b8 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -126,8 +126,6 @@ extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
extern int zfcp_qdio_open(struct zfcp_qdio *);
extern void zfcp_qdio_close(struct zfcp_qdio *);
extern void zfcp_qdio_siosl(struct zfcp_adapter *);
-extern struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *,
- struct qdio_buffer *);
/* zfcp_scsi.c */
extern struct scsi_transport_template *zfcp_scsi_transport_template;
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 510e9b06c1a..0fe8d5d9511 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -770,7 +770,8 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
if (zfcp_qdio_sbal_get(qdio))
goto out;
- req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, 0,
+ req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS,
+ SBAL_SFLAGS0_TYPE_STATUS,
adapter->pool.status_read_req);
if (IS_ERR(req)) {
retval = PTR_ERR(req);
@@ -2387,12 +2388,3 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
break;
}
}
-
-struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *qdio,
- struct qdio_buffer *sbal)
-{
- struct qdio_buffer_element *sbale = &sbal->element[0];
- u64 req_id = (unsigned long) sbale->addr;
-
- return zfcp_reqlist_find(qdio->adapter->req_list, req_id);
-}
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 665e3cfaaf8..06025cdaa4a 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -16,9 +16,9 @@
#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
-static bool enable_multibuffer;
+static bool enable_multibuffer = 1;
module_param_named(datarouter, enable_multibuffer, bool, 0400);
-MODULE_PARM_DESC(datarouter, "Enable hardware data router support");
+MODULE_PARM_DESC(datarouter, "Enable hardware data router support (default on)");
static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
{
@@ -224,11 +224,9 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
{
- spin_lock_irq(&qdio->req_q_lock);
if (atomic_read(&qdio->req_q_free) ||
!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
return 1;
- spin_unlock_irq(&qdio->req_q_lock);
return 0;
}
@@ -246,9 +244,8 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
{
long ret;
- spin_unlock_irq(&qdio->req_q_lock);
- ret = wait_event_interruptible_timeout(qdio->req_q_wq,
- zfcp_qdio_sbal_check(qdio), 5 * HZ);
+ ret = wait_event_interruptible_lock_irq_timeout(qdio->req_q_wq,
+ zfcp_qdio_sbal_check(qdio), qdio->req_q_lock, 5 * HZ);
if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
return -EIO;
@@ -262,7 +259,6 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1");
}
- spin_lock_irq(&qdio->req_q_lock);
return -EIO;
}
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 3f01bbf0609..672b57219e1 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -27,6 +27,16 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \
static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \
zfcp_sysfs_##_feat##_##_name##_show, NULL);
+#define ZFCP_DEFINE_ATTR_CONST(_feat, _name, _format, _value) \
+static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \
+ struct device_attribute *at,\
+ char *buf) \
+{ \
+ return sprintf(buf, _format, _value); \
+} \
+static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \
+ zfcp_sysfs_##_feat##_##_name##_show, NULL);
+
#define ZFCP_DEFINE_A_ATTR(_name, _format, _value) \
static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \
struct device_attribute *at,\
@@ -75,6 +85,8 @@ ZFCP_DEFINE_ATTR(zfcp_unit, unit, in_recovery, "%d\n",
ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n",
(zfcp_unit_sdev_status(unit) &
ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0);
+ZFCP_DEFINE_ATTR_CONST(unit, access_shared, "%d\n", 0);
+ZFCP_DEFINE_ATTR_CONST(unit, access_readonly, "%d\n", 0);
static ssize_t zfcp_sysfs_port_failed_show(struct device *dev,
struct device_attribute *attr,
@@ -95,7 +107,7 @@ static ssize_t zfcp_sysfs_port_failed_store(struct device *dev,
struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
unsigned long val;
- if (strict_strtoul(buf, 0, &val) || val != 0)
+ if (kstrtoul(buf, 0, &val) || val != 0)
return -EINVAL;
zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_RUNNING);
@@ -134,7 +146,7 @@ static ssize_t zfcp_sysfs_unit_failed_store(struct device *dev,
unsigned long val;
struct scsi_device *sdev;
- if (strict_strtoul(buf, 0, &val) || val != 0)
+ if (kstrtoul(buf, 0, &val) || val != 0)
return -EINVAL;
sdev = zfcp_unit_sdev(unit);
@@ -184,7 +196,7 @@ static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev,
if (!adapter)
return -ENODEV;
- if (strict_strtoul(buf, 0, &val) || val != 0) {
+ if (kstrtoul(buf, 0, &val) || val != 0) {
retval = -EINVAL;
goto out;
}
@@ -236,7 +248,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
if (!adapter)
return -ENODEV;
- if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn))
+ if (kstrtoull(buf, 0, (unsigned long long *) &wwpn))
goto out;
port = zfcp_get_port_by_wwpn(adapter, wwpn);
@@ -297,7 +309,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
u64 fcp_lun;
int retval;
- if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
+ if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
return -EINVAL;
retval = zfcp_unit_add(port, fcp_lun);
@@ -315,7 +327,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
u64 fcp_lun;
- if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
+ if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
return -EINVAL;
if (zfcp_unit_remove(port, fcp_lun))
@@ -347,6 +359,8 @@ static struct attribute *zfcp_unit_attrs[] = {
&dev_attr_unit_in_recovery.attr,
&dev_attr_unit_status.attr,
&dev_attr_unit_access_denied.attr,
+ &dev_attr_unit_access_shared.attr,
+ &dev_attr_unit_access_readonly.attr,
NULL
};
static struct attribute_group zfcp_unit_attr_group = {
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 48b2918e0d6..fe25677a551 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -601,6 +601,7 @@ config SCSI_ARCMSR
To compile this driver as a module, choose M here: the
module will be called arcmsr (modprobe arcmsr).
+source "drivers/scsi/esas2r/Kconfig"
source "drivers/scsi/megaraid/Kconfig.megaraid"
source "drivers/scsi/mpt2sas/Kconfig"
source "drivers/scsi/mpt3sas/Kconfig"
@@ -1353,7 +1354,6 @@ config SCSI_LPFC
tristate "Emulex LightPulse Fibre Channel Support"
depends on PCI && SCSI
select SCSI_FC_ATTRS
- select GENERIC_CSUM
select CRC_T10DIF
help
This lpfc driver supports the Emulex LightPulse
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index b607ba4f563..149bb6bf184 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -141,6 +141,7 @@ obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/
obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/
obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
+obj-$(CONFIG_SCSI_ESAS2R) += esas2r/
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
obj-$(CONFIG_SCSI_VIRTIO) += virtio_scsi.o
obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 9611195d670..f8ca7becacc 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -63,9 +63,9 @@ int max_rport_logins = BFA_FCS_MAX_RPORT_LOGINS;
u32 bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size;
u32 *bfi_image_cb, *bfi_image_ct, *bfi_image_ct2;
-#define BFAD_FW_FILE_CB "cbfw-3.2.1.0.bin"
-#define BFAD_FW_FILE_CT "ctfw-3.2.1.0.bin"
-#define BFAD_FW_FILE_CT2 "ct2fw-3.2.1.0.bin"
+#define BFAD_FW_FILE_CB "cbfw-3.2.1.1.bin"
+#define BFAD_FW_FILE_CT "ctfw-3.2.1.1.bin"
+#define BFAD_FW_FILE_CT2 "ct2fw-3.2.1.1.bin"
static u32 *bfad_load_fwimg(struct pci_dev *pdev);
static void bfad_free_fwimg(void);
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
index 25093a04123..3d33767f2f2 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_constants.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
@@ -1,6 +1,6 @@
/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
*
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
*
* 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
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
index f2db5fe7bdc..37049e433c9 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
@@ -1,6 +1,6 @@
/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
*
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
*
* 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
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index f109e3b073c..6940f0930a8 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -1,6 +1,6 @@
/* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index a28b03e5a5f..af3e675d4d4 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1,6 +1,6 @@
/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index 50fef6963a8..b6f6f436777 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -1,6 +1,6 @@
/* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -18,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
static u32 adapter_count;
#define DRV_MODULE_NAME "bnx2i"
-#define DRV_MODULE_VERSION "2.7.2.2"
-#define DRV_MODULE_RELDATE "Apr 25, 2012"
+#define DRV_MODULE_VERSION "2.7.6.2"
+#define DRV_MODULE_RELDATE "Jun 06, 2013"
static char version[] =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 0056e47bd56..fabeb88602a 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1,7 +1,7 @@
/*
* bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c
index c61cf7a4365..a0a3d9fe61f 100644
--- a/drivers/scsi/bnx2i/bnx2i_sysfs.c
+++ b/drivers/scsi/bnx2i/bnx2i_sysfs.c
@@ -1,6 +1,6 @@
/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2004 - 2012 Broadcom Corporation
+ * Copyright (c) 2004 - 2013 Broadcom Corporation
*
* 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
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 356def44ce5..1663173cdb9 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -919,7 +919,7 @@ static int eata_pio_detect(struct scsi_host_template *tpnt)
find_pio_EISA(&gc);
find_pio_ISA(&gc);
- for (i = 0; i <= MAXIRQ; i++)
+ for (i = 0; i < MAXIRQ; i++)
if (reg_IRQ[i])
request_irq(i, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", NULL);
diff --git a/drivers/scsi/esas2r/Kconfig b/drivers/scsi/esas2r/Kconfig
new file mode 100644
index 00000000000..78fdbfd9b4b
--- /dev/null
+++ b/drivers/scsi/esas2r/Kconfig
@@ -0,0 +1,5 @@
+config SCSI_ESAS2R
+ tristate "ATTO Technology's ExpressSAS RAID adapter driver"
+ depends on PCI && SCSI
+ ---help---
+ This driver supports the ATTO ExpressSAS R6xx SAS/SATA RAID controllers.
diff --git a/drivers/scsi/esas2r/Makefile b/drivers/scsi/esas2r/Makefile
new file mode 100644
index 00000000000..c77160b8c8b
--- /dev/null
+++ b/drivers/scsi/esas2r/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_SCSI_ESAS2R) += esas2r.o
+
+esas2r-objs := esas2r_log.o esas2r_disc.o esas2r_flash.o esas2r_init.o \
+ esas2r_int.o esas2r_io.o esas2r_ioctl.o esas2r_targdb.o \
+ esas2r_vda.o esas2r_main.o
diff --git a/drivers/scsi/esas2r/atioctl.h b/drivers/scsi/esas2r/atioctl.h
new file mode 100644
index 00000000000..4aca3d52c85
--- /dev/null
+++ b/drivers/scsi/esas2r/atioctl.h
@@ -0,0 +1,1254 @@
+/* linux/drivers/scsi/esas2r/atioctl.h
+ * ATTO IOCTL Handling
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "atvda.h"
+
+#ifndef ATIOCTL_H
+#define ATIOCTL_H
+
+#define EXPRESS_IOCTL_SIGNATURE "Express"
+#define EXPRESS_IOCTL_SIGNATURE_SIZE 8
+
+/* structure definitions for IOCTls */
+
+struct __packed atto_express_ioctl_header {
+ u8 signature[EXPRESS_IOCTL_SIGNATURE_SIZE];
+ u8 return_code;
+
+#define IOCTL_SUCCESS 0
+#define IOCTL_ERR_INVCMD 101
+#define IOCTL_INIT_FAILED 102
+#define IOCTL_NOT_IMPLEMENTED 103
+#define IOCTL_BAD_CHANNEL 104
+#define IOCTL_TARGET_OVERRUN 105
+#define IOCTL_TARGET_NOT_ENABLED 106
+#define IOCTL_BAD_FLASH_IMGTYPE 107
+#define IOCTL_OUT_OF_RESOURCES 108
+#define IOCTL_GENERAL_ERROR 109
+#define IOCTL_INVALID_PARAM 110
+
+ u8 channel;
+ u8 retries;
+ u8 pad[5];
+};
+
+/*
+ * NOTE - if channel == 0xFF, the request is
+ * handled on the adapter it came in on.
+ */
+#define MAX_NODE_NAMES 256
+
+struct __packed atto_firmware_rw_request {
+ u8 function;
+ #define FUNC_FW_DOWNLOAD 0x09
+ #define FUNC_FW_UPLOAD 0x12
+
+ u8 img_type;
+ #define FW_IMG_FW 0x01
+ #define FW_IMG_BIOS 0x02
+ #define FW_IMG_NVR 0x03
+ #define FW_IMG_RAW 0x04
+ #define FW_IMG_FM_API 0x05
+ #define FW_IMG_FS_API 0x06
+
+ u8 pad[2];
+ u32 img_offset;
+ u32 img_size;
+ u8 image[0x80000];
+};
+
+struct __packed atto_param_rw_request {
+ u16 code;
+ char data_buffer[512];
+};
+
+#define MAX_CHANNEL 256
+
+struct __packed atto_channel_list {
+ u32 num_channels;
+ u8 channel[MAX_CHANNEL];
+};
+
+struct __packed atto_channel_info {
+ u8 major_rev;
+ u8 minor_rev;
+ u8 IRQ;
+ u8 revision_id;
+ u8 pci_bus;
+ u8 pci_dev_func;
+ u8 core_rev;
+ u8 host_no;
+ u16 device_id;
+ u16 vendor_id;
+ u16 ven_dev_id;
+ u8 pad[3];
+ u32 hbaapi_rev;
+};
+
+/*
+ * CSMI control codes
+ * class independent
+ */
+#define CSMI_CC_GET_DRVR_INFO 1
+#define CSMI_CC_GET_CNTLR_CFG 2
+#define CSMI_CC_GET_CNTLR_STS 3
+#define CSMI_CC_FW_DOWNLOAD 4
+
+/* RAID class */
+#define CSMI_CC_GET_RAID_INFO 10
+#define CSMI_CC_GET_RAID_CFG 11
+
+/* HBA class */
+#define CSMI_CC_GET_PHY_INFO 20
+#define CSMI_CC_SET_PHY_INFO 21
+#define CSMI_CC_GET_LINK_ERRORS 22
+#define CSMI_CC_SMP_PASSTHRU 23
+#define CSMI_CC_SSP_PASSTHRU 24
+#define CSMI_CC_STP_PASSTHRU 25
+#define CSMI_CC_GET_SATA_SIG 26
+#define CSMI_CC_GET_SCSI_ADDR 27
+#define CSMI_CC_GET_DEV_ADDR 28
+#define CSMI_CC_TASK_MGT 29
+#define CSMI_CC_GET_CONN_INFO 30
+
+/* PHY class */
+#define CSMI_CC_PHY_CTRL 60
+
+/*
+ * CSMI status codes
+ * class independent
+ */
+#define CSMI_STS_SUCCESS 0
+#define CSMI_STS_FAILED 1
+#define CSMI_STS_BAD_CTRL_CODE 2
+#define CSMI_STS_INV_PARAM 3
+#define CSMI_STS_WRITE_ATTEMPTED 4
+
+/* RAID class */
+#define CSMI_STS_INV_RAID_SET 1000
+
+/* HBA class */
+#define CSMI_STS_PHY_CHANGED CSMI_STS_SUCCESS
+#define CSMI_STS_PHY_UNCHANGEABLE 2000
+#define CSMI_STS_INV_LINK_RATE 2001
+#define CSMI_STS_INV_PHY 2002
+#define CSMI_STS_INV_PHY_FOR_PORT 2003
+#define CSMI_STS_PHY_UNSELECTABLE 2004
+#define CSMI_STS_SELECT_PHY_OR_PORT 2005
+#define CSMI_STS_INV_PORT 2006
+#define CSMI_STS_PORT_UNSELECTABLE 2007
+#define CSMI_STS_CONNECTION_FAILED 2008
+#define CSMI_STS_NO_SATA_DEV 2009
+#define CSMI_STS_NO_SATA_SIGNATURE 2010
+#define CSMI_STS_SCSI_EMULATION 2011
+#define CSMI_STS_NOT_AN_END_DEV 2012
+#define CSMI_STS_NO_SCSI_ADDR 2013
+#define CSMI_STS_NO_DEV_ADDR 2014
+
+/* CSMI class independent structures */
+struct atto_csmi_get_driver_info {
+ char name[81];
+ char description[81];
+ u16 major_rev;
+ u16 minor_rev;
+ u16 build_rev;
+ u16 release_rev;
+ u16 csmi_major_rev;
+ u16 csmi_minor_rev;
+ #define CSMI_MAJOR_REV_0_81 0
+ #define CSMI_MINOR_REV_0_81 81
+
+ #define CSMI_MAJOR_REV CSMI_MAJOR_REV_0_81
+ #define CSMI_MINOR_REV CSMI_MINOR_REV_0_81
+};
+
+struct atto_csmi_get_pci_bus_addr {
+ u8 bus_num;
+ u8 device_num;
+ u8 function_num;
+ u8 reserved;
+};
+
+struct atto_csmi_get_cntlr_cfg {
+ u32 base_io_addr;
+
+ struct {
+ u32 base_memaddr_lo;
+ u32 base_memaddr_hi;
+ };
+
+ u32 board_id;
+ u16 slot_num;
+ #define CSMI_SLOT_NUM_UNKNOWN 0xFFFF
+
+ u8 cntlr_class;
+ #define CSMI_CNTLR_CLASS_HBA 5
+
+ u8 io_bus_type;
+ #define CSMI_BUS_TYPE_PCI 3
+ #define CSMI_BUS_TYPE_PCMCIA 4
+
+ union {
+ struct atto_csmi_get_pci_bus_addr pci_addr;
+ u8 reserved[32];
+ };
+
+ char serial_num[81];
+ u16 major_rev;
+ u16 minor_rev;
+ u16 build_rev;
+ u16 release_rev;
+ u16 bios_major_rev;
+ u16 bios_minor_rev;
+ u16 bios_build_rev;
+ u16 bios_release_rev;
+ u32 cntlr_flags;
+ #define CSMI_CNTLRF_SAS_HBA 0x00000001
+ #define CSMI_CNTLRF_SAS_RAID 0x00000002
+ #define CSMI_CNTLRF_SATA_HBA 0x00000004
+ #define CSMI_CNTLRF_SATA_RAID 0x00000008
+ #define CSMI_CNTLRF_FWD_SUPPORT 0x00010000
+ #define CSMI_CNTLRF_FWD_ONLINE 0x00020000
+ #define CSMI_CNTLRF_FWD_SRESET 0x00040000
+ #define CSMI_CNTLRF_FWD_HRESET 0x00080000
+ #define CSMI_CNTLRF_FWD_RROM 0x00100000
+
+ u16 rrom_major_rev;
+ u16 rrom_minor_rev;
+ u16 rrom_build_rev;
+ u16 rrom_release_rev;
+ u16 rrom_biosmajor_rev;
+ u16 rrom_biosminor_rev;
+ u16 rrom_biosbuild_rev;
+ u16 rrom_biosrelease_rev;
+ u8 reserved2[7];
+};
+
+struct atto_csmi_get_cntlr_sts {
+ u32 status;
+ #define CSMI_CNTLR_STS_GOOD 1
+ #define CSMI_CNTLR_STS_FAILED 2
+ #define CSMI_CNTLR_STS_OFFLINE 3
+ #define CSMI_CNTLR_STS_POWEROFF 4
+
+ u32 offline_reason;
+ #define CSMI_OFFLINE_NO_REASON 0
+ #define CSMI_OFFLINE_INITIALIZING 1
+ #define CSMI_OFFLINE_BUS_DEGRADED 2
+ #define CSMI_OFFLINE_BUS_FAILURE 3
+
+ u8 reserved[28];
+};
+
+struct atto_csmi_fw_download {
+ u32 buffer_len;
+ u32 download_flags;
+ #define CSMI_FWDF_VALIDATE 0x00000001
+ #define CSMI_FWDF_SOFT_RESET 0x00000002
+ #define CSMI_FWDF_HARD_RESET 0x00000004
+
+ u8 reserved[32];
+ u16 status;
+ #define CSMI_FWD_STS_SUCCESS 0
+ #define CSMI_FWD_STS_FAILED 1
+ #define CSMI_FWD_STS_USING_RROM 2
+ #define CSMI_FWD_STS_REJECT 3
+ #define CSMI_FWD_STS_DOWNREV 4
+
+ u16 severity;
+ #define CSMI_FWD_SEV_INFO 0
+ #define CSMI_FWD_SEV_WARNING 1
+ #define CSMI_FWD_SEV_ERROR 2
+ #define CSMI_FWD_SEV_FATAL 3
+
+};
+
+/* CSMI RAID class structures */
+struct atto_csmi_get_raid_info {
+ u32 num_raid_sets;
+ u32 max_drivesper_set;
+ u8 reserved[92];
+};
+
+struct atto_csmi_raid_drives {
+ char model[40];
+ char firmware[8];
+ char serial_num[40];
+ u8 sas_addr[8];
+ u8 lun[8];
+ u8 drive_sts;
+ #define CSMI_DRV_STS_OK 0
+ #define CSMI_DRV_STS_REBUILDING 1
+ #define CSMI_DRV_STS_FAILED 2
+ #define CSMI_DRV_STS_DEGRADED 3
+
+ u8 drive_usage;
+ #define CSMI_DRV_USE_NOT_USED 0
+ #define CSMI_DRV_USE_MEMBER 1
+ #define CSMI_DRV_USE_SPARE 2
+
+ u8 reserved[30]; /* spec says 22 */
+};
+
+struct atto_csmi_get_raid_cfg {
+ u32 raid_set_index;
+ u32 capacity;
+ u32 stripe_size;
+ u8 raid_type;
+ u8 status;
+ u8 information;
+ u8 drive_cnt;
+ u8 reserved[20];
+
+ struct atto_csmi_raid_drives drives[1];
+};
+
+/* CSMI HBA class structures */
+struct atto_csmi_phy_entity {
+ u8 ident_frame[0x1C];
+ u8 port_id;
+ u8 neg_link_rate;
+ u8 min_link_rate;
+ u8 max_link_rate;
+ u8 phy_change_cnt;
+ u8 auto_discover;
+ #define CSMI_DISC_NOT_SUPPORTED 0x00
+ #define CSMI_DISC_NOT_STARTED 0x01
+ #define CSMI_DISC_IN_PROGRESS 0x02
+ #define CSMI_DISC_COMPLETE 0x03
+ #define CSMI_DISC_ERROR 0x04
+
+ u8 reserved[2];
+ u8 attach_ident_frame[0x1C];
+};
+
+struct atto_csmi_get_phy_info {
+ u8 number_of_phys;
+ u8 reserved[3];
+ struct atto_csmi_phy_entity
+ phy[32];
+};
+
+struct atto_csmi_set_phy_info {
+ u8 phy_id;
+ u8 neg_link_rate;
+ #define CSMI_NEG_RATE_NEGOTIATE 0x00
+ #define CSMI_NEG_RATE_PHY_DIS 0x01
+
+ u8 prog_minlink_rate;
+ u8 prog_maxlink_rate;
+ u8 signal_class;
+ #define CSMI_SIG_CLASS_UNKNOWN 0x00
+ #define CSMI_SIG_CLASS_DIRECT 0x01
+ #define CSMI_SIG_CLASS_SERVER 0x02
+ #define CSMI_SIG_CLASS_ENCLOSURE 0x03
+
+ u8 reserved[3];
+};
+
+struct atto_csmi_get_link_errors {
+ u8 phy_id;
+ u8 reset_cnts;
+ #define CSMI_RESET_CNTS_NO 0x00
+ #define CSMI_RESET_CNTS_YES 0x01
+
+ u8 reserved[2];
+ u32 inv_dw_cnt;
+ u32 disp_err_cnt;
+ u32 loss_ofdw_sync_cnt;
+ u32 phy_reseterr_cnt;
+
+ /*
+ * The following field has been added by ATTO for ease of
+ * implementation of additional statistics. Drivers must validate
+ * the length of the IOCTL payload prior to filling them in so CSMI
+ * complaint applications function correctly.
+ */
+
+ u32 crc_err_cnt;
+};
+
+struct atto_csmi_smp_passthru {
+ u8 phy_id;
+ u8 port_id;
+ u8 conn_rate;
+ u8 reserved;
+ u8 dest_sas_addr[8];
+ u32 req_len;
+ u8 smp_req[1020];
+ u8 conn_sts;
+ u8 reserved2[3];
+ u32 rsp_len;
+ u8 smp_rsp[1020];
+};
+
+struct atto_csmi_ssp_passthru_sts {
+ u8 conn_sts;
+ u8 reserved[3];
+ u8 data_present;
+ u8 status;
+ u16 rsp_length;
+ u8 rsp[256];
+ u32 data_bytes;
+};
+
+struct atto_csmi_ssp_passthru {
+ u8 phy_id;
+ u8 port_id;
+ u8 conn_rate;
+ u8 reserved;
+ u8 dest_sas_addr[8];
+ u8 lun[8];
+ u8 cdb_len;
+ u8 add_cdb_len;
+ u8 reserved2[2];
+ u8 cdb[16];
+ u32 flags;
+ #define CSMI_SSPF_DD_READ 0x00000001
+ #define CSMI_SSPF_DD_WRITE 0x00000002
+ #define CSMI_SSPF_DD_UNSPECIFIED 0x00000004
+ #define CSMI_SSPF_TA_SIMPLE 0x00000000
+ #define CSMI_SSPF_TA_HEAD_OF_Q 0x00000010
+ #define CSMI_SSPF_TA_ORDERED 0x00000020
+ #define CSMI_SSPF_TA_ACA 0x00000040
+
+ u8 add_cdb[24];
+ u32 data_len;
+
+ struct atto_csmi_ssp_passthru_sts sts;
+};
+
+struct atto_csmi_stp_passthru_sts {
+ u8 conn_sts;
+ u8 reserved[3];
+ u8 sts_fis[20];
+ u32 scr[16];
+ u32 data_bytes;
+};
+
+struct atto_csmi_stp_passthru {
+ u8 phy_id;
+ u8 port_id;
+ u8 conn_rate;
+ u8 reserved;
+ u8 dest_sas_addr[8];
+ u8 reserved2[4];
+ u8 command_fis[20];
+ u32 flags;
+ #define CSMI_STPF_DD_READ 0x00000001
+ #define CSMI_STPF_DD_WRITE 0x00000002
+ #define CSMI_STPF_DD_UNSPECIFIED 0x00000004
+ #define CSMI_STPF_PIO 0x00000010
+ #define CSMI_STPF_DMA 0x00000020
+ #define CSMI_STPF_PACKET 0x00000040
+ #define CSMI_STPF_DMA_QUEUED 0x00000080
+ #define CSMI_STPF_EXECUTE_DIAG 0x00000100
+ #define CSMI_STPF_RESET_DEVICE 0x00000200
+
+ u32 data_len;
+
+ struct atto_csmi_stp_passthru_sts sts;
+};
+
+struct atto_csmi_get_sata_sig {
+ u8 phy_id;
+ u8 reserved[3];
+ u8 reg_dth_fis[20];
+};
+
+struct atto_csmi_get_scsi_addr {
+ u8 sas_addr[8];
+ u8 sas_lun[8];
+ u8 host_index;
+ u8 path_id;
+ u8 target_id;
+ u8 lun;
+};
+
+struct atto_csmi_get_dev_addr {
+ u8 host_index;
+ u8 path_id;
+ u8 target_id;
+ u8 lun;
+ u8 sas_addr[8];
+ u8 sas_lun[8];
+};
+
+struct atto_csmi_task_mgmt {
+ u8 host_index;
+ u8 path_id;
+ u8 target_id;
+ u8 lun;
+ u32 flags;
+ #define CSMI_TMF_TASK_IU 0x00000001
+ #define CSMI_TMF_HARD_RST 0x00000002
+ #define CSMI_TMF_SUPPRESS_RSLT 0x00000004
+
+ u32 queue_tag;
+ u32 reserved;
+ u8 task_mgt_func;
+ u8 reserved2[7];
+ u32 information;
+ #define CSMI_TM_INFO_TEST 1
+ #define CSMI_TM_INFO_EXCEEDED 2
+ #define CSMI_TM_INFO_DEMAND 3
+ #define CSMI_TM_INFO_TRIGGER 4
+
+ struct atto_csmi_ssp_passthru_sts sts;
+
+};
+
+struct atto_csmi_get_conn_info {
+ u32 pinout;
+ #define CSMI_CON_UNKNOWN 0x00000001
+ #define CSMI_CON_SFF_8482 0x00000002
+ #define CSMI_CON_SFF_8470_LANE_1 0x00000100
+ #define CSMI_CON_SFF_8470_LANE_2 0x00000200
+ #define CSMI_CON_SFF_8470_LANE_3 0x00000400
+ #define CSMI_CON_SFF_8470_LANE_4 0x00000800
+ #define CSMI_CON_SFF_8484_LANE_1 0x00010000
+ #define CSMI_CON_SFF_8484_LANE_2 0x00020000
+ #define CSMI_CON_SFF_8484_LANE_3 0x00040000
+ #define CSMI_CON_SFF_8484_LANE_4 0x00080000
+
+ u8 connector[16];
+ u8 location;
+ #define CSMI_CON_INTERNAL 0x02
+ #define CSMI_CON_EXTERNAL 0x04
+ #define CSMI_CON_SWITCHABLE 0x08
+ #define CSMI_CON_AUTO 0x10
+
+ u8 reserved[15];
+};
+
+/* CSMI PHY class structures */
+struct atto_csmi_character {
+ u8 type_flags;
+ #define CSMI_CTF_POS_DISP 0x01
+ #define CSMI_CTF_NEG_DISP 0x02
+ #define CSMI_CTF_CTRL_CHAR 0x04
+
+ u8 value;
+};
+
+struct atto_csmi_pc_ctrl {
+ u8 type;
+ #define CSMI_PC_TYPE_UNDEFINED 0x00
+ #define CSMI_PC_TYPE_SATA 0x01
+ #define CSMI_PC_TYPE_SAS 0x02
+ u8 rate;
+ u8 reserved[6];
+ u32 vendor_unique[8];
+ u32 tx_flags;
+ #define CSMI_PC_TXF_PREEMP_DIS 0x00000001
+
+ signed char tx_amplitude;
+ signed char tx_preemphasis;
+ signed char tx_slew_rate;
+ signed char tx_reserved[13];
+ u8 tx_vendor_unique[64];
+ u32 rx_flags;
+ #define CSMI_PC_RXF_EQ_DIS 0x00000001
+
+ signed char rx_threshold;
+ signed char rx_equalization_gain;
+ signed char rx_reserved[14];
+ u8 rx_vendor_unique[64];
+ u32 pattern_flags;
+ #define CSMI_PC_PATF_FIXED 0x00000001
+ #define CSMI_PC_PATF_DIS_SCR 0x00000002
+ #define CSMI_PC_PATF_DIS_ALIGN 0x00000004
+ #define CSMI_PC_PATF_DIS_SSC 0x00000008
+
+ u8 fixed_pattern;
+ #define CSMI_PC_FP_CJPAT 0x00000001
+ #define CSMI_PC_FP_ALIGN 0x00000002
+
+ u8 user_pattern_len;
+ u8 pattern_reserved[6];
+
+ struct atto_csmi_character user_pattern_buffer[16];
+};
+
+struct atto_csmi_phy_ctrl {
+ u32 function;
+ #define CSMI_PC_FUNC_GET_SETUP 0x00000100
+
+ u8 phy_id;
+ u16 len_of_cntl;
+ u8 num_of_cntls;
+ u8 reserved[4];
+ u32 link_flags;
+ #define CSMI_PHY_ACTIVATE_CTRL 0x00000001
+ #define CSMI_PHY_UPD_SPINUP_RATE 0x00000002
+ #define CSMI_PHY_AUTO_COMWAKE 0x00000004
+
+ u8 spinup_rate;
+ u8 link_reserved[7];
+ u32 vendor_unique[8];
+
+ struct atto_csmi_pc_ctrl control[1];
+};
+
+union atto_ioctl_csmi {
+ struct atto_csmi_get_driver_info drvr_info;
+ struct atto_csmi_get_cntlr_cfg cntlr_cfg;
+ struct atto_csmi_get_cntlr_sts cntlr_sts;
+ struct atto_csmi_fw_download fw_dwnld;
+ struct atto_csmi_get_raid_info raid_info;
+ struct atto_csmi_get_raid_cfg raid_cfg;
+ struct atto_csmi_get_phy_info get_phy_info;
+ struct atto_csmi_set_phy_info set_phy_info;
+ struct atto_csmi_get_link_errors link_errs;
+ struct atto_csmi_smp_passthru smp_pass_thru;
+ struct atto_csmi_ssp_passthru ssp_pass_thru;
+ struct atto_csmi_stp_passthru stp_pass_thru;
+ struct atto_csmi_task_mgmt tsk_mgt;
+ struct atto_csmi_get_sata_sig sata_sig;
+ struct atto_csmi_get_scsi_addr scsi_addr;
+ struct atto_csmi_get_dev_addr dev_addr;
+ struct atto_csmi_get_conn_info conn_info[32];
+ struct atto_csmi_phy_ctrl phy_ctrl;
+};
+
+struct atto_csmi {
+ u32 control_code;
+ u32 status;
+ union atto_ioctl_csmi data;
+};
+
+struct atto_module_info {
+ void *adapter;
+ void *pci_dev;
+ void *scsi_host;
+ unsigned short host_no;
+ union {
+ struct {
+ u64 node_name;
+ u64 port_name;
+ };
+ u64 sas_addr;
+ };
+};
+
+#define ATTO_FUNC_GET_ADAP_INFO 0x00
+#define ATTO_VER_GET_ADAP_INFO0 0
+#define ATTO_VER_GET_ADAP_INFO ATTO_VER_GET_ADAP_INFO0
+
+struct __packed atto_hba_get_adapter_info {
+
+ struct {
+ u16 vendor_id;
+ u16 device_id;
+ u16 ss_vendor_id;
+ u16 ss_device_id;
+ u8 class_code[3];
+ u8 rev_id;
+ u8 bus_num;
+ u8 dev_num;
+ u8 func_num;
+ u8 link_width_max;
+ u8 link_width_curr;
+ #define ATTO_GAI_PCILW_UNKNOWN 0x00
+
+ u8 link_speed_max;
+ u8 link_speed_curr;
+ #define ATTO_GAI_PCILS_UNKNOWN 0x00
+ #define ATTO_GAI_PCILS_GEN1 0x01
+ #define ATTO_GAI_PCILS_GEN2 0x02
+ #define ATTO_GAI_PCILS_GEN3 0x03
+
+ u8 interrupt_mode;
+ #define ATTO_GAI_PCIIM_UNKNOWN 0x00
+ #define ATTO_GAI_PCIIM_LEGACY 0x01
+ #define ATTO_GAI_PCIIM_MSI 0x02
+ #define ATTO_GAI_PCIIM_MSIX 0x03
+
+ u8 msi_vector_cnt;
+ u8 reserved[19];
+ } pci;
+
+ u8 adap_type;
+ #define ATTO_GAI_AT_EPCIU320 0x00
+ #define ATTO_GAI_AT_ESASRAID 0x01
+ #define ATTO_GAI_AT_ESASRAID2 0x02
+ #define ATTO_GAI_AT_ESASHBA 0x03
+ #define ATTO_GAI_AT_ESASHBA2 0x04
+ #define ATTO_GAI_AT_CELERITY 0x05
+ #define ATTO_GAI_AT_CELERITY8 0x06
+ #define ATTO_GAI_AT_FASTFRAME 0x07
+ #define ATTO_GAI_AT_ESASHBA3 0x08
+ #define ATTO_GAI_AT_CELERITY16 0x09
+ #define ATTO_GAI_AT_TLSASHBA 0x0A
+ #define ATTO_GAI_AT_ESASHBA4 0x0B
+
+ u8 adap_flags;
+ #define ATTO_GAI_AF_DEGRADED 0x01
+ #define ATTO_GAI_AF_SPT_SUPP 0x02
+ #define ATTO_GAI_AF_DEVADDR_SUPP 0x04
+ #define ATTO_GAI_AF_PHYCTRL_SUPP 0x08
+ #define ATTO_GAI_AF_TEST_SUPP 0x10
+ #define ATTO_GAI_AF_DIAG_SUPP 0x20
+ #define ATTO_GAI_AF_VIRT_SES 0x40
+ #define ATTO_GAI_AF_CONN_CTRL 0x80
+
+ u8 num_ports;
+ u8 num_phys;
+ u8 drvr_rev_major;
+ u8 drvr_rev_minor;
+ u8 drvr_revsub_minor;
+ u8 drvr_rev_build;
+ char drvr_rev_ascii[16];
+ char drvr_name[32];
+ char firmware_rev[16];
+ char flash_rev[16];
+ char model_name_short[16];
+ char model_name[32];
+ u32 num_targets;
+ u32 num_targsper_bus;
+ u32 num_lunsper_targ;
+ u8 num_busses;
+ u8 num_connectors;
+ u8 adap_flags2;
+ #define ATTO_GAI_AF2_FCOE_SUPP 0x01
+ #define ATTO_GAI_AF2_NIC_SUPP 0x02
+ #define ATTO_GAI_AF2_LOCATE_SUPP 0x04
+ #define ATTO_GAI_AF2_ADAP_CTRL_SUPP 0x08
+ #define ATTO_GAI_AF2_DEV_INFO_SUPP 0x10
+ #define ATTO_GAI_AF2_NPIV_SUPP 0x20
+ #define ATTO_GAI_AF2_MP_SUPP 0x40
+
+ u8 num_temp_sensors;
+ u32 num_targets_backend;
+ u32 tunnel_flags;
+ #define ATTO_GAI_TF_MEM_RW 0x00000001
+ #define ATTO_GAI_TF_TRACE 0x00000002
+ #define ATTO_GAI_TF_SCSI_PASS_THRU 0x00000004
+ #define ATTO_GAI_TF_GET_DEV_ADDR 0x00000008
+ #define ATTO_GAI_TF_PHY_CTRL 0x00000010
+ #define ATTO_GAI_TF_CONN_CTRL 0x00000020
+ #define ATTO_GAI_TF_GET_DEV_INFO 0x00000040
+
+ u8 reserved3[0x138];
+};
+
+#define ATTO_FUNC_GET_ADAP_ADDR 0x01
+#define ATTO_VER_GET_ADAP_ADDR0 0
+#define ATTO_VER_GET_ADAP_ADDR ATTO_VER_GET_ADAP_ADDR0
+
+struct __packed atto_hba_get_adapter_address {
+
+ u8 addr_type;
+ #define ATTO_GAA_AT_PORT 0x00
+ #define ATTO_GAA_AT_NODE 0x01
+ #define ATTO_GAA_AT_CURR_MAC 0x02
+ #define ATTO_GAA_AT_PERM_MAC 0x03
+ #define ATTO_GAA_AT_VNIC 0x04
+
+ u8 port_id;
+ u16 addr_len;
+ u8 address[256];
+};
+
+#define ATTO_FUNC_MEM_RW 0x02
+#define ATTO_VER_MEM_RW0 0
+#define ATTO_VER_MEM_RW ATTO_VER_MEM_RW0
+
+struct __packed atto_hba_memory_read_write {
+ u8 mem_func;
+ u8 mem_type;
+ union {
+ u8 pci_index;
+ u8 i2c_dev;
+ };
+ u8 i2c_status;
+ u32 length;
+ u64 address;
+ u8 reserved[48];
+
+};
+
+#define ATTO_FUNC_TRACE 0x03
+#define ATTO_VER_TRACE0 0
+#define ATTO_VER_TRACE1 1
+#define ATTO_VER_TRACE ATTO_VER_TRACE1
+
+struct __packed atto_hba_trace {
+ u8 trace_func;
+ #define ATTO_TRC_TF_GET_INFO 0x00
+ #define ATTO_TRC_TF_ENABLE 0x01
+ #define ATTO_TRC_TF_DISABLE 0x02
+ #define ATTO_TRC_TF_SET_MASK 0x03
+ #define ATTO_TRC_TF_UPLOAD 0x04
+ #define ATTO_TRC_TF_RESET 0x05
+
+ u8 trace_type;
+ #define ATTO_TRC_TT_DRIVER 0x00
+ #define ATTO_TRC_TT_FWCOREDUMP 0x01
+
+ u8 reserved[2];
+ u32 current_offset;
+ u32 total_length;
+ u32 trace_mask;
+ u8 reserved2[48];
+};
+
+#define ATTO_FUNC_SCSI_PASS_THRU 0x04
+#define ATTO_VER_SCSI_PASS_THRU0 0
+#define ATTO_VER_SCSI_PASS_THRU ATTO_VER_SCSI_PASS_THRU0
+
+struct __packed atto_hba_scsi_pass_thru {
+ u8 cdb[32];
+ u8 cdb_length;
+ u8 req_status;
+ #define ATTO_SPT_RS_SUCCESS 0x00
+ #define ATTO_SPT_RS_FAILED 0x01
+ #define ATTO_SPT_RS_OVERRUN 0x02
+ #define ATTO_SPT_RS_UNDERRUN 0x03
+ #define ATTO_SPT_RS_NO_DEVICE 0x04
+ #define ATTO_SPT_RS_NO_LUN 0x05
+ #define ATTO_SPT_RS_TIMEOUT 0x06
+ #define ATTO_SPT_RS_BUS_RESET 0x07
+ #define ATTO_SPT_RS_ABORTED 0x08
+ #define ATTO_SPT_RS_BUSY 0x09
+ #define ATTO_SPT_RS_DEGRADED 0x0A
+
+ u8 scsi_status;
+ u8 sense_length;
+ u32 flags;
+ #define ATTO_SPTF_DATA_IN 0x00000001
+ #define ATTO_SPTF_DATA_OUT 0x00000002
+ #define ATTO_SPTF_SIMPLE_Q 0x00000004
+ #define ATTO_SPTF_HEAD_OF_Q 0x00000008
+ #define ATTO_SPTF_ORDERED_Q 0x00000010
+
+ u32 timeout;
+ u32 target_id;
+ u8 lun[8];
+ u32 residual_length;
+ u8 sense_data[0xFC];
+ u8 reserved[0x28];
+};
+
+#define ATTO_FUNC_GET_DEV_ADDR 0x05
+#define ATTO_VER_GET_DEV_ADDR0 0
+#define ATTO_VER_GET_DEV_ADDR ATTO_VER_GET_DEV_ADDR0
+
+struct __packed atto_hba_get_device_address {
+ u8 addr_type;
+ #define ATTO_GDA_AT_PORT 0x00
+ #define ATTO_GDA_AT_NODE 0x01
+ #define ATTO_GDA_AT_MAC 0x02
+ #define ATTO_GDA_AT_PORTID 0x03
+ #define ATTO_GDA_AT_UNIQUE 0x04
+
+ u8 reserved;
+ u16 addr_len;
+ u32 target_id;
+ u8 address[256];
+};
+
+/* The following functions are supported by firmware but do not have any
+ * associated driver structures
+ */
+#define ATTO_FUNC_PHY_CTRL 0x06
+#define ATTO_FUNC_CONN_CTRL 0x0C
+#define ATTO_FUNC_ADAP_CTRL 0x0E
+#define ATTO_VER_ADAP_CTRL0 0
+#define ATTO_VER_ADAP_CTRL ATTO_VER_ADAP_CTRL0
+
+struct __packed atto_hba_adap_ctrl {
+ u8 adap_func;
+ #define ATTO_AC_AF_HARD_RST 0x00
+ #define ATTO_AC_AF_GET_STATE 0x01
+ #define ATTO_AC_AF_GET_TEMP 0x02
+
+ u8 adap_state;
+ #define ATTO_AC_AS_UNKNOWN 0x00
+ #define ATTO_AC_AS_OK 0x01
+ #define ATTO_AC_AS_RST_SCHED 0x02
+ #define ATTO_AC_AS_RST_IN_PROG 0x03
+ #define ATTO_AC_AS_RST_DISC 0x04
+ #define ATTO_AC_AS_DEGRADED 0x05
+ #define ATTO_AC_AS_DISABLED 0x06
+ #define ATTO_AC_AS_TEMP 0x07
+
+ u8 reserved[2];
+
+ union {
+ struct {
+ u8 temp_sensor;
+ u8 temp_state;
+
+ #define ATTO_AC_TS_UNSUPP 0x00
+ #define ATTO_AC_TS_UNKNOWN 0x01
+ #define ATTO_AC_TS_INIT_FAILED 0x02
+ #define ATTO_AC_TS_NORMAL 0x03
+ #define ATTO_AC_TS_OUT_OF_RANGE 0x04
+ #define ATTO_AC_TS_FAULT 0x05
+
+ signed short temp_value;
+ signed short temp_lower_lim;
+ signed short temp_upper_lim;
+ char temp_desc[32];
+ u8 reserved2[20];
+ };
+ };
+};
+
+#define ATTO_FUNC_GET_DEV_INFO 0x0F
+#define ATTO_VER_GET_DEV_INFO0 0
+#define ATTO_VER_GET_DEV_INFO ATTO_VER_GET_DEV_INFO0
+
+struct __packed atto_hba_sas_device_info {
+
+ #define ATTO_SDI_MAX_PHYS_WIDE_PORT 16
+
+ u8 phy_id[ATTO_SDI_MAX_PHYS_WIDE_PORT]; /* IDs of parent exp/adapt */
+ #define ATTO_SDI_PHY_ID_INV ATTO_SAS_PHY_ID_INV
+ u32 exp_target_id;
+ u32 sas_port_mask;
+ u8 sas_level;
+ #define ATTO_SDI_SAS_LVL_INV 0xFF
+
+ u8 slot_num;
+ #define ATTO_SDI_SLOT_NUM_INV ATTO_SLOT_NUM_INV
+
+ u8 dev_type;
+ #define ATTO_SDI_DT_END_DEVICE 0
+ #define ATTO_SDI_DT_EXPANDER 1
+ #define ATTO_SDI_DT_PORT_MULT 2
+
+ u8 ini_flags;
+ u8 tgt_flags;
+ u8 link_rate; /* SMP_RATE_XXX */
+ u8 loc_flags;
+ #define ATTO_SDI_LF_DIRECT 0x01
+ #define ATTO_SDI_LF_EXPANDER 0x02
+ #define ATTO_SDI_LF_PORT_MULT 0x04
+ u8 pm_port;
+ u8 reserved[0x60];
+};
+
+union atto_hba_device_info {
+ struct atto_hba_sas_device_info sas_dev_info;
+};
+
+struct __packed atto_hba_get_device_info {
+ u32 target_id;
+ u8 info_type;
+ #define ATTO_GDI_IT_UNKNOWN 0x00
+ #define ATTO_GDI_IT_SAS 0x01
+ #define ATTO_GDI_IT_FC 0x02
+ #define ATTO_GDI_IT_FCOE 0x03
+
+ u8 reserved[11];
+ union atto_hba_device_info dev_info;
+};
+
+struct atto_ioctl {
+ u8 version;
+ u8 function; /* ATTO_FUNC_XXX */
+ u8 status;
+#define ATTO_STS_SUCCESS 0x00
+#define ATTO_STS_FAILED 0x01
+#define ATTO_STS_INV_VERSION 0x02
+#define ATTO_STS_OUT_OF_RSRC 0x03
+#define ATTO_STS_INV_FUNC 0x04
+#define ATTO_STS_UNSUPPORTED 0x05
+#define ATTO_STS_INV_ADAPTER 0x06
+#define ATTO_STS_INV_DRVR_VER 0x07
+#define ATTO_STS_INV_PARAM 0x08
+#define ATTO_STS_TIMEOUT 0x09
+#define ATTO_STS_NOT_APPL 0x0A
+#define ATTO_STS_DEGRADED 0x0B
+
+ u8 flags;
+ #define HBAF_TUNNEL 0x01
+
+ u32 data_length;
+ u8 reserved2[56];
+
+ union {
+ u8 byte[1];
+ struct atto_hba_get_adapter_info get_adap_info;
+ struct atto_hba_get_adapter_address get_adap_addr;
+ struct atto_hba_scsi_pass_thru scsi_pass_thru;
+ struct atto_hba_get_device_address get_dev_addr;
+ struct atto_hba_adap_ctrl adap_ctrl;
+ struct atto_hba_get_device_info get_dev_info;
+ struct atto_hba_trace trace;
+ } data;
+
+};
+
+struct __packed atto_ioctl_vda_scsi_cmd {
+
+ #define ATTO_VDA_SCSI_VER0 0
+ #define ATTO_VDA_SCSI_VER ATTO_VDA_SCSI_VER0
+
+ u8 cdb[16];
+ u32 flags;
+ u32 data_length;
+ u32 residual_length;
+ u16 target_id;
+ u8 sense_len;
+ u8 scsi_stat;
+ u8 reserved[8];
+ u8 sense_data[80];
+};
+
+struct __packed atto_ioctl_vda_flash_cmd {
+
+ #define ATTO_VDA_FLASH_VER0 0
+ #define ATTO_VDA_FLASH_VER ATTO_VDA_FLASH_VER0
+
+ u32 flash_addr;
+ u32 data_length;
+ u8 sub_func;
+ u8 reserved[15];
+
+ union {
+ struct {
+ u32 flash_size;
+ u32 page_size;
+ u8 prod_info[32];
+ } info;
+
+ struct {
+ char file_name[16]; /* 8.3 fname, NULL term, wc=* */
+ u32 file_size;
+ } file;
+ } data;
+
+};
+
+struct __packed atto_ioctl_vda_diag_cmd {
+
+ #define ATTO_VDA_DIAG_VER0 0
+ #define ATTO_VDA_DIAG_VER ATTO_VDA_DIAG_VER0
+
+ u64 local_addr;
+ u32 data_length;
+ u8 sub_func;
+ u8 flags;
+ u8 reserved[3];
+};
+
+struct __packed atto_ioctl_vda_cli_cmd {
+
+ #define ATTO_VDA_CLI_VER0 0
+ #define ATTO_VDA_CLI_VER ATTO_VDA_CLI_VER0
+
+ u32 cmd_rsp_len;
+};
+
+struct __packed atto_ioctl_vda_smp_cmd {
+
+ #define ATTO_VDA_SMP_VER0 0
+ #define ATTO_VDA_SMP_VER ATTO_VDA_SMP_VER0
+
+ u64 dest;
+ u32 cmd_rsp_len;
+};
+
+struct __packed atto_ioctl_vda_cfg_cmd {
+
+ #define ATTO_VDA_CFG_VER0 0
+ #define ATTO_VDA_CFG_VER ATTO_VDA_CFG_VER0
+
+ u32 data_length;
+ u8 cfg_func;
+ u8 reserved[11];
+
+ union {
+ u8 bytes[112];
+ struct atto_vda_cfg_init init;
+ } data;
+
+};
+
+struct __packed atto_ioctl_vda_mgt_cmd {
+
+ #define ATTO_VDA_MGT_VER0 0
+ #define ATTO_VDA_MGT_VER ATTO_VDA_MGT_VER0
+
+ u8 mgt_func;
+ u8 scan_generation;
+ u16 dev_index;
+ u32 data_length;
+ u8 reserved[8];
+ union {
+ u8 bytes[112];
+ struct atto_vda_devinfo dev_info;
+ struct atto_vda_grp_info grp_info;
+ struct atto_vdapart_info part_info;
+ struct atto_vda_dh_info dh_info;
+ struct atto_vda_metrics_info metrics_info;
+ struct atto_vda_schedule_info sched_info;
+ struct atto_vda_n_vcache_info nvcache_info;
+ struct atto_vda_buzzer_info buzzer_info;
+ struct atto_vda_adapter_info adapter_info;
+ struct atto_vda_temp_info temp_info;
+ struct atto_vda_fan_info fan_info;
+ } data;
+};
+
+struct __packed atto_ioctl_vda_gsv_cmd {
+
+ #define ATTO_VDA_GSV_VER0 0
+ #define ATTO_VDA_GSV_VER ATTO_VDA_GSV_VER0
+
+ u8 rsp_len;
+ u8 reserved[7];
+ u8 version_info[1];
+ #define ATTO_VDA_VER_UNSUPPORTED 0xFF
+
+};
+
+struct __packed atto_ioctl_vda {
+ u8 version;
+ u8 function; /* VDA_FUNC_XXXX */
+ u8 status; /* ATTO_STS_XXX */
+ u8 vda_status; /* RS_XXX (if status == ATTO_STS_SUCCESS) */
+ u32 data_length;
+ u8 reserved[8];
+
+ union {
+ struct atto_ioctl_vda_scsi_cmd scsi;
+ struct atto_ioctl_vda_flash_cmd flash;
+ struct atto_ioctl_vda_diag_cmd diag;
+ struct atto_ioctl_vda_cli_cmd cli;
+ struct atto_ioctl_vda_smp_cmd smp;
+ struct atto_ioctl_vda_cfg_cmd cfg;
+ struct atto_ioctl_vda_mgt_cmd mgt;
+ struct atto_ioctl_vda_gsv_cmd gsv;
+ u8 cmd_info[256];
+ } cmd;
+
+ union {
+ u8 data[1];
+ struct atto_vda_devinfo2 dev_info2;
+ } data;
+
+};
+
+struct __packed atto_ioctl_smp {
+ u8 version;
+ #define ATTO_SMP_VERSION0 0
+ #define ATTO_SMP_VERSION1 1
+ #define ATTO_SMP_VERSION2 2
+ #define ATTO_SMP_VERSION ATTO_SMP_VERSION2
+
+ u8 function;
+#define ATTO_SMP_FUNC_DISC_SMP 0x00
+#define ATTO_SMP_FUNC_DISC_TARG 0x01
+#define ATTO_SMP_FUNC_SEND_CMD 0x02
+#define ATTO_SMP_FUNC_DISC_TARG_DIRECT 0x03
+#define ATTO_SMP_FUNC_SEND_CMD_DIRECT 0x04
+#define ATTO_SMP_FUNC_DISC_SMP_DIRECT 0x05
+
+ u8 status; /* ATTO_STS_XXX */
+ u8 smp_status; /* if status == ATTO_STS_SUCCESS */
+ #define ATTO_SMP_STS_SUCCESS 0x00
+ #define ATTO_SMP_STS_FAILURE 0x01
+ #define ATTO_SMP_STS_RESCAN 0x02
+ #define ATTO_SMP_STS_NOT_FOUND 0x03
+
+ u16 target_id;
+ u8 phy_id;
+ u8 dev_index;
+ u64 smp_sas_addr;
+ u64 targ_sas_addr;
+ u32 req_length;
+ u32 rsp_length;
+ u8 flags;
+ #define ATTO_SMPF_ROOT_EXP 0x01 /* expander direct attached */
+
+ u8 reserved[31];
+
+ union {
+ u8 byte[1];
+ u32 dword[1];
+ } data;
+
+};
+
+struct __packed atto_express_ioctl {
+ struct atto_express_ioctl_header header;
+
+ union {
+ struct atto_firmware_rw_request fwrw;
+ struct atto_param_rw_request prw;
+ struct atto_channel_list chanlist;
+ struct atto_channel_info chaninfo;
+ struct atto_ioctl ioctl_hba;
+ struct atto_module_info modinfo;
+ struct atto_ioctl_vda ioctl_vda;
+ struct atto_ioctl_smp ioctl_smp;
+ struct atto_csmi csmi;
+
+ } data;
+};
+
+/* The struct associated with the code is listed after the definition */
+#define EXPRESS_IOCTL_MIN 0x4500
+#define EXPRESS_IOCTL_RW_FIRMWARE 0x4500 /* FIRMWARERW */
+#define EXPRESS_IOCTL_READ_PARAMS 0x4501 /* PARAMRW */
+#define EXPRESS_IOCTL_WRITE_PARAMS 0x4502 /* PARAMRW */
+#define EXPRESS_IOCTL_FC_API 0x4503 /* internal */
+#define EXPRESS_IOCTL_GET_CHANNELS 0x4504 /* CHANNELLIST */
+#define EXPRESS_IOCTL_CHAN_INFO 0x4505 /* CHANNELINFO */
+#define EXPRESS_IOCTL_DEFAULT_PARAMS 0x4506 /* PARAMRW */
+#define EXPRESS_ADDR_MEMORY 0x4507 /* MEMADDR */
+#define EXPRESS_RW_MEMORY 0x4508 /* MEMRW */
+#define EXPRESS_TSDK_DUMP 0x4509 /* TSDKDUMP */
+#define EXPRESS_IOCTL_SMP 0x450A /* IOCTL_SMP */
+#define EXPRESS_CSMI 0x450B /* CSMI */
+#define EXPRESS_IOCTL_HBA 0x450C /* IOCTL_HBA */
+#define EXPRESS_IOCTL_VDA 0x450D /* IOCTL_VDA */
+#define EXPRESS_IOCTL_GET_ID 0x450E /* GET_ID */
+#define EXPRESS_IOCTL_GET_MOD_INFO 0x450F /* MODULE_INFO */
+#define EXPRESS_IOCTL_MAX 0x450F
+
+#endif
diff --git a/drivers/scsi/esas2r/atvda.h b/drivers/scsi/esas2r/atvda.h
new file mode 100644
index 00000000000..5fc1f991d24
--- /dev/null
+++ b/drivers/scsi/esas2r/atvda.h
@@ -0,0 +1,1319 @@
+/* linux/drivers/scsi/esas2r/atvda.h
+ * ATTO VDA interface definitions
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+
+#ifndef ATVDA_H
+#define ATVDA_H
+
+struct __packed atto_dev_addr {
+ u64 dev_port;
+ u64 hba_port;
+ u8 lun;
+ u8 flags;
+ #define VDA_DEVADDRF_SATA 0x01
+ #define VDA_DEVADDRF_SSD 0x02
+ u8 link_speed; /* VDALINKSPEED_xxx */
+ u8 pad[1];
+};
+
+/* dev_addr2 was added for 64-bit alignment */
+
+struct __packed atto_dev_addr2 {
+ u64 dev_port;
+ u64 hba_port;
+ u8 lun;
+ u8 flags;
+ u8 link_speed;
+ u8 pad[5];
+};
+
+struct __packed atto_vda_sge {
+ u32 length;
+ u64 address;
+};
+
+
+/* VDA request function codes */
+
+#define VDA_FUNC_SCSI 0x00
+#define VDA_FUNC_FLASH 0x01
+#define VDA_FUNC_DIAG 0x02
+#define VDA_FUNC_AE 0x03
+#define VDA_FUNC_CLI 0x04
+#define VDA_FUNC_IOCTL 0x05
+#define VDA_FUNC_CFG 0x06
+#define VDA_FUNC_MGT 0x07
+#define VDA_FUNC_GSV 0x08
+
+
+/* VDA request status values. for host driver considerations, values for
+ * SCSI requests start at zero. other requests may use these values as well. */
+
+#define RS_SUCCESS 0x00 /*! successful completion */
+#define RS_INV_FUNC 0x01 /*! invalid command function */
+#define RS_BUSY 0x02 /*! insufficient resources */
+#define RS_SEL 0x03 /*! no target at target_id */
+#define RS_NO_LUN 0x04 /*! invalid LUN */
+#define RS_TIMEOUT 0x05 /*! request timeout */
+#define RS_OVERRUN 0x06 /*! data overrun */
+#define RS_UNDERRUN 0x07 /*! data underrun */
+#define RS_SCSI_ERROR 0x08 /*! SCSI error occurred */
+#define RS_ABORTED 0x0A /*! command aborted */
+#define RS_RESID_MISM 0x0B /*! residual length incorrect */
+#define RS_TM_FAILED 0x0C /*! task management failed */
+#define RS_RESET 0x0D /*! aborted due to bus reset */
+#define RS_ERR_DMA_SG 0x0E /*! error reading SG list */
+#define RS_ERR_DMA_DATA 0x0F /*! error transferring data */
+#define RS_UNSUPPORTED 0x10 /*! unsupported request */
+#define RS_SEL2 0x70 /*! internal generated RS_SEL */
+#define RS_VDA_BASE 0x80 /*! base of VDA-specific errors */
+#define RS_MGT_BASE 0x80 /*! base of VDA management errors */
+#define RS_SCAN_FAIL (RS_MGT_BASE + 0x00)
+#define RS_DEV_INVALID (RS_MGT_BASE + 0x01)
+#define RS_DEV_ASSIGNED (RS_MGT_BASE + 0x02)
+#define RS_DEV_REMOVE (RS_MGT_BASE + 0x03)
+#define RS_DEV_LOST (RS_MGT_BASE + 0x04)
+#define RS_SCAN_GEN (RS_MGT_BASE + 0x05)
+#define RS_GRP_INVALID (RS_MGT_BASE + 0x08)
+#define RS_GRP_EXISTS (RS_MGT_BASE + 0x09)
+#define RS_GRP_LIMIT (RS_MGT_BASE + 0x0A)
+#define RS_GRP_INTLV (RS_MGT_BASE + 0x0B)
+#define RS_GRP_SPAN (RS_MGT_BASE + 0x0C)
+#define RS_GRP_TYPE (RS_MGT_BASE + 0x0D)
+#define RS_GRP_MEMBERS (RS_MGT_BASE + 0x0E)
+#define RS_GRP_COMMIT (RS_MGT_BASE + 0x0F)
+#define RS_GRP_REBUILD (RS_MGT_BASE + 0x10)
+#define RS_GRP_REBUILD_TYPE (RS_MGT_BASE + 0x11)
+#define RS_GRP_BLOCK_SIZE (RS_MGT_BASE + 0x12)
+#define RS_CFG_SAVE (RS_MGT_BASE + 0x14)
+#define RS_PART_LAST (RS_MGT_BASE + 0x18)
+#define RS_ELEM_INVALID (RS_MGT_BASE + 0x19)
+#define RS_PART_MAPPED (RS_MGT_BASE + 0x1A)
+#define RS_PART_TARGET (RS_MGT_BASE + 0x1B)
+#define RS_PART_LUN (RS_MGT_BASE + 0x1C)
+#define RS_PART_DUP (RS_MGT_BASE + 0x1D)
+#define RS_PART_NOMAP (RS_MGT_BASE + 0x1E)
+#define RS_PART_MAX (RS_MGT_BASE + 0x1F)
+#define RS_PART_CAP (RS_MGT_BASE + 0x20)
+#define RS_PART_STATE (RS_MGT_BASE + 0x21)
+#define RS_TEST_IN_PROG (RS_MGT_BASE + 0x22)
+#define RS_METRICS_ERROR (RS_MGT_BASE + 0x23)
+#define RS_HS_ERROR (RS_MGT_BASE + 0x24)
+#define RS_NO_METRICS_TEST (RS_MGT_BASE + 0x25)
+#define RS_BAD_PARAM (RS_MGT_BASE + 0x26)
+#define RS_GRP_MEMBER_SIZE (RS_MGT_BASE + 0x27)
+#define RS_FLS_BASE 0xB0 /*! base of VDA errors */
+#define RS_FLS_ERR_AREA (RS_FLS_BASE + 0x00)
+#define RS_FLS_ERR_BUSY (RS_FLS_BASE + 0x01)
+#define RS_FLS_ERR_RANGE (RS_FLS_BASE + 0x02)
+#define RS_FLS_ERR_BEGIN (RS_FLS_BASE + 0x03)
+#define RS_FLS_ERR_CHECK (RS_FLS_BASE + 0x04)
+#define RS_FLS_ERR_FAIL (RS_FLS_BASE + 0x05)
+#define RS_FLS_ERR_RSRC (RS_FLS_BASE + 0x06)
+#define RS_FLS_ERR_NOFILE (RS_FLS_BASE + 0x07)
+#define RS_FLS_ERR_FSIZE (RS_FLS_BASE + 0x08)
+#define RS_CFG_BASE 0xC0 /*! base of VDA configuration errors */
+#define RS_CFG_ERR_BUSY (RS_CFG_BASE + 0)
+#define RS_CFG_ERR_SGE (RS_CFG_BASE + 1)
+#define RS_CFG_ERR_DATE (RS_CFG_BASE + 2)
+#define RS_CFG_ERR_TIME (RS_CFG_BASE + 3)
+#define RS_DEGRADED 0xFB /*! degraded mode */
+#define RS_CLI_INTERNAL 0xFC /*! VDA CLI internal error */
+#define RS_VDA_INTERNAL 0xFD /*! catch-all */
+#define RS_PENDING 0xFE /*! pending, not started */
+#define RS_STARTED 0xFF /*! started */
+
+
+/* flash request subfunctions. these are used in both the IOCTL and the
+ * driver-firmware interface (VDA_FUNC_FLASH). */
+
+#define VDA_FLASH_BEGINW 0x00
+#define VDA_FLASH_READ 0x01
+#define VDA_FLASH_WRITE 0x02
+#define VDA_FLASH_COMMIT 0x03
+#define VDA_FLASH_CANCEL 0x04
+#define VDA_FLASH_INFO 0x05
+#define VDA_FLASH_FREAD 0x06
+#define VDA_FLASH_FWRITE 0x07
+#define VDA_FLASH_FINFO 0x08
+
+
+/* IOCTL request subfunctions. these identify the payload type for
+ * VDA_FUNC_IOCTL.
+ */
+
+#define VDA_IOCTL_HBA 0x00
+#define VDA_IOCTL_CSMI 0x01
+#define VDA_IOCTL_SMP 0x02
+
+struct __packed atto_vda_devinfo {
+ struct atto_dev_addr dev_addr;
+ u8 vendor_id[8];
+ u8 product_id[16];
+ u8 revision[4];
+ u64 capacity;
+ u32 block_size;
+ u8 dev_type;
+
+ union {
+ u8 dev_status;
+ #define VDADEVSTAT_INVALID 0x00
+ #define VDADEVSTAT_CORRUPT VDADEVSTAT_INVALID
+ #define VDADEVSTAT_ASSIGNED 0x01
+ #define VDADEVSTAT_SPARE 0x02
+ #define VDADEVSTAT_UNAVAIL 0x03
+ #define VDADEVSTAT_PT_MAINT 0x04
+ #define VDADEVSTAT_LCLSPARE 0x05
+ #define VDADEVSTAT_UNUSEABLE 0x06
+ #define VDADEVSTAT_AVAIL 0xFF
+
+ u8 op_ctrl;
+ #define VDA_DEV_OP_CTRL_START 0x01
+ #define VDA_DEV_OP_CTRL_HALT 0x02
+ #define VDA_DEV_OP_CTRL_RESUME 0x03
+ #define VDA_DEV_OP_CTRL_CANCEL 0x04
+ };
+
+ u8 member_state;
+ #define VDAMBRSTATE_ONLINE 0x00
+ #define VDAMBRSTATE_DEGRADED 0x01
+ #define VDAMBRSTATE_UNAVAIL 0x02
+ #define VDAMBRSTATE_FAULTED 0x03
+ #define VDAMBRSTATE_MISREAD 0x04
+ #define VDAMBRSTATE_INCOMPAT 0x05
+
+ u8 operation;
+ #define VDAOP_NONE 0x00
+ #define VDAOP_REBUILD 0x01
+ #define VDAOP_ERASE 0x02
+ #define VDAOP_PATTERN 0x03
+ #define VDAOP_CONVERSION 0x04
+ #define VDAOP_FULL_INIT 0x05
+ #define VDAOP_QUICK_INIT 0x06
+ #define VDAOP_SECT_SCAN 0x07
+ #define VDAOP_SECT_SCAN_PARITY 0x08
+ #define VDAOP_SECT_SCAN_PARITY_FIX 0x09
+ #define VDAOP_RECOV_REBUILD 0x0A
+
+ u8 op_status;
+ #define VDAOPSTAT_OK 0x00
+ #define VDAOPSTAT_FAULTED 0x01
+ #define VDAOPSTAT_HALTED 0x02
+ #define VDAOPSTAT_INT 0x03
+
+ u8 progress; /* 0 - 100% */
+ u16 ses_dev_index;
+ #define VDASESDI_INVALID 0xFFFF
+
+ u8 serial_no[32];
+
+ union {
+ u16 target_id;
+ #define VDATGTID_INVALID 0xFFFF
+
+ u16 features_mask;
+ };
+
+ u16 lun;
+ u16 features;
+ #define VDADEVFEAT_ENC_SERV 0x0001
+ #define VDADEVFEAT_IDENT 0x0002
+ #define VDADEVFEAT_DH_SUPP 0x0004
+ #define VDADEVFEAT_PHYS_ID 0x0008
+
+ u8 ses_element_id;
+ u8 link_speed;
+ #define VDALINKSPEED_UNKNOWN 0x00
+ #define VDALINKSPEED_1GB 0x01
+ #define VDALINKSPEED_1_5GB 0x02
+ #define VDALINKSPEED_2GB 0x03
+ #define VDALINKSPEED_3GB 0x04
+ #define VDALINKSPEED_4GB 0x05
+ #define VDALINKSPEED_6GB 0x06
+ #define VDALINKSPEED_8GB 0x07
+
+ u16 phys_target_id;
+ u8 reserved[2];
+};
+
+
+/*! struct atto_vda_devinfo2 is a replacement for atto_vda_devinfo. it
+ * extends beyond the 0x70 bytes allowed in atto_vda_mgmt_req; therefore,
+ * the entire structure is DMaed between the firmware and host buffer and
+ * the data will always be in little endian format.
+ */
+
+struct __packed atto_vda_devinfo2 {
+ struct atto_dev_addr dev_addr;
+ u8 vendor_id[8];
+ u8 product_id[16];
+ u8 revision[4];
+ u64 capacity;
+ u32 block_size;
+ u8 dev_type;
+ u8 dev_status;
+ u8 member_state;
+ u8 operation;
+ u8 op_status;
+ u8 progress;
+ u16 ses_dev_index;
+ u8 serial_no[32];
+ union {
+ u16 target_id;
+ u16 features_mask;
+ };
+
+ u16 lun;
+ u16 features;
+ u8 ses_element_id;
+ u8 link_speed;
+ u16 phys_target_id;
+ u8 reserved[2];
+
+/* This is where fields specific to struct atto_vda_devinfo2 begin. Note
+ * that the structure version started at one so applications that unionize this
+ * structure with atto_vda_dev_info can differentiate them if desired.
+ */
+
+ u8 version;
+ #define VDADEVINFO_VERSION0 0x00
+ #define VDADEVINFO_VERSION1 0x01
+ #define VDADEVINFO_VERSION2 0x02
+ #define VDADEVINFO_VERSION3 0x03
+ #define VDADEVINFO_VERSION VDADEVINFO_VERSION3
+
+ u8 reserved2[3];
+
+ /* sector scanning fields */
+
+ u32 ss_curr_errors;
+ u64 ss_curr_scanned;
+ u32 ss_curr_recvrd;
+ u32 ss_scan_length;
+ u32 ss_total_errors;
+ u32 ss_total_recvrd;
+ u32 ss_num_scans;
+
+ /* grp_name was added in version 2 of this structure. */
+
+ char grp_name[15];
+ u8 reserved3[4];
+
+ /* dev_addr_list was added in version 3 of this structure. */
+
+ u8 num_dev_addr;
+ struct atto_dev_addr2 dev_addr_list[8];
+};
+
+
+struct __packed atto_vda_grp_info {
+ u8 grp_index;
+ #define VDA_MAX_RAID_GROUPS 32
+
+ char grp_name[15];
+ u64 capacity;
+ u32 block_size;
+ u32 interleave;
+ u8 type;
+ #define VDA_GRP_TYPE_RAID0 0
+ #define VDA_GRP_TYPE_RAID1 1
+ #define VDA_GRP_TYPE_RAID4 4
+ #define VDA_GRP_TYPE_RAID5 5
+ #define VDA_GRP_TYPE_RAID6 6
+ #define VDA_GRP_TYPE_RAID10 10
+ #define VDA_GRP_TYPE_RAID40 40
+ #define VDA_GRP_TYPE_RAID50 50
+ #define VDA_GRP_TYPE_RAID60 60
+ #define VDA_GRP_TYPE_DVRAID_HS 252
+ #define VDA_GRP_TYPE_DVRAID_NOHS 253
+ #define VDA_GRP_TYPE_JBOD 254
+ #define VDA_GRP_TYPE_SPARE 255
+
+ union {
+ u8 status;
+ #define VDA_GRP_STAT_INVALID 0x00
+ #define VDA_GRP_STAT_NEW 0x01
+ #define VDA_GRP_STAT_WAITING 0x02
+ #define VDA_GRP_STAT_ONLINE 0x03
+ #define VDA_GRP_STAT_DEGRADED 0x04
+ #define VDA_GRP_STAT_OFFLINE 0x05
+ #define VDA_GRP_STAT_DELETED 0x06
+ #define VDA_GRP_STAT_RECOV_BASIC 0x07
+ #define VDA_GRP_STAT_RECOV_EXTREME 0x08
+
+ u8 op_ctrl;
+ #define VDA_GRP_OP_CTRL_START 0x01
+ #define VDA_GRP_OP_CTRL_HALT 0x02
+ #define VDA_GRP_OP_CTRL_RESUME 0x03
+ #define VDA_GRP_OP_CTRL_CANCEL 0x04
+ };
+
+ u8 rebuild_state;
+ #define VDA_RBLD_NONE 0x00
+ #define VDA_RBLD_REBUILD 0x01
+ #define VDA_RBLD_ERASE 0x02
+ #define VDA_RBLD_PATTERN 0x03
+ #define VDA_RBLD_CONV 0x04
+ #define VDA_RBLD_FULL_INIT 0x05
+ #define VDA_RBLD_QUICK_INIT 0x06
+ #define VDA_RBLD_SECT_SCAN 0x07
+ #define VDA_RBLD_SECT_SCAN_PARITY 0x08
+ #define VDA_RBLD_SECT_SCAN_PARITY_FIX 0x09
+ #define VDA_RBLD_RECOV_REBUILD 0x0A
+ #define VDA_RBLD_RECOV_BASIC 0x0B
+ #define VDA_RBLD_RECOV_EXTREME 0x0C
+
+ u8 span_depth;
+ u8 progress;
+ u8 mirror_width;
+ u8 stripe_width;
+ u8 member_cnt;
+
+ union {
+ u16 members[32];
+ #define VDA_MEMBER_MISSING 0xFFFF
+ #define VDA_MEMBER_NEW 0xFFFE
+ u16 features_mask;
+ };
+
+ u16 features;
+ #define VDA_GRP_FEAT_HOTSWAP 0x0001
+ #define VDA_GRP_FEAT_SPDRD_MASK 0x0006
+ #define VDA_GRP_FEAT_SPDRD_DIS 0x0000
+ #define VDA_GRP_FEAT_SPDRD_ENB 0x0002
+ #define VDA_GRP_FEAT_SPDRD_AUTO 0x0004
+ #define VDA_GRP_FEAT_IDENT 0x0008
+ #define VDA_GRP_FEAT_RBLDPRI_MASK 0x0030
+ #define VDA_GRP_FEAT_RBLDPRI_LOW 0x0010
+ #define VDA_GRP_FEAT_RBLDPRI_SAME 0x0020
+ #define VDA_GRP_FEAT_RBLDPRI_HIGH 0x0030
+ #define VDA_GRP_FEAT_WRITE_CACHE 0x0040
+ #define VDA_GRP_FEAT_RBLD_RESUME 0x0080
+ #define VDA_GRP_FEAT_SECT_RESUME 0x0100
+ #define VDA_GRP_FEAT_INIT_RESUME 0x0200
+ #define VDA_GRP_FEAT_SSD 0x0400
+ #define VDA_GRP_FEAT_BOOT_DEV 0x0800
+
+ /*
+ * for backward compatibility, a prefetch value of zero means the
+ * setting is ignored/unsupported. therefore, the firmware supported
+ * 0-6 values are incremented to 1-7.
+ */
+
+ u8 prefetch;
+ u8 op_status;
+ #define VDAGRPOPSTAT_MASK 0x0F
+ #define VDAGRPOPSTAT_INVALID 0x00
+ #define VDAGRPOPSTAT_OK 0x01
+ #define VDAGRPOPSTAT_FAULTED 0x02
+ #define VDAGRPOPSTAT_HALTED 0x03
+ #define VDAGRPOPSTAT_INT 0x04
+ #define VDAGRPOPPROC_MASK 0xF0
+ #define VDAGRPOPPROC_STARTABLE 0x10
+ #define VDAGRPOPPROC_CANCELABLE 0x20
+ #define VDAGRPOPPROC_RESUMABLE 0x40
+ #define VDAGRPOPPROC_HALTABLE 0x80
+ u8 over_provision;
+ u8 reserved[3];
+
+};
+
+
+struct __packed atto_vdapart_info {
+ u8 part_no;
+ #define VDA_MAX_PARTITIONS 128
+
+ char grp_name[15];
+ u64 part_size;
+ u64 start_lba;
+ u32 block_size;
+ u16 target_id;
+ u8 LUN;
+ char serial_no[41];
+ u8 features;
+ #define VDAPI_FEAT_WRITE_CACHE 0x01
+
+ u8 reserved[7];
+};
+
+
+struct __packed atto_vda_dh_info {
+ u8 req_type;
+ #define VDADH_RQTYPE_CACHE 0x01
+ #define VDADH_RQTYPE_FETCH 0x02
+ #define VDADH_RQTYPE_SET_STAT 0x03
+ #define VDADH_RQTYPE_GET_STAT 0x04
+
+ u8 req_qual;
+ #define VDADH_RQQUAL_SMART 0x01
+ #define VDADH_RQQUAL_MEDDEF 0x02
+ #define VDADH_RQQUAL_INFOEXC 0x04
+
+ u8 num_smart_attribs;
+ u8 status;
+ #define VDADH_STAT_DISABLE 0x00
+ #define VDADH_STAT_ENABLE 0x01
+
+ u32 med_defect_cnt;
+ u32 info_exc_cnt;
+ u8 smart_status;
+ #define VDADH_SMARTSTAT_OK 0x00
+ #define VDADH_SMARTSTAT_ERR 0x01
+
+ u8 reserved[35];
+ struct atto_vda_sge sge[1];
+};
+
+
+struct __packed atto_vda_dh_smart {
+ u8 attrib_id;
+ u8 current_val;
+ u8 worst;
+ u8 threshold;
+ u8 raw_data[6];
+ u8 raw_attrib_status;
+ #define VDADHSM_RAWSTAT_PREFAIL_WARRANTY 0x01
+ #define VDADHSM_RAWSTAT_ONLINE_COLLECTION 0x02
+ #define VDADHSM_RAWSTAT_PERFORMANCE_ATTR 0x04
+ #define VDADHSM_RAWSTAT_ERROR_RATE_ATTR 0x08
+ #define VDADHSM_RAWSTAT_EVENT_COUNT_ATTR 0x10
+ #define VDADHSM_RAWSTAT_SELF_PRESERVING_ATTR 0x20
+
+ u8 calc_attrib_status;
+ #define VDADHSM_CALCSTAT_UNKNOWN 0x00
+ #define VDADHSM_CALCSTAT_GOOD 0x01
+ #define VDADHSM_CALCSTAT_PREFAIL 0x02
+ #define VDADHSM_CALCSTAT_OLDAGE 0x03
+
+ u8 reserved[4];
+};
+
+
+struct __packed atto_vda_metrics_info {
+ u8 data_version;
+ #define VDAMET_VERSION0 0x00
+ #define VDAMET_VERSION VDAMET_VERSION0
+
+ u8 metrics_action;
+ #define VDAMET_METACT_NONE 0x00
+ #define VDAMET_METACT_START 0x01
+ #define VDAMET_METACT_STOP 0x02
+ #define VDAMET_METACT_RETRIEVE 0x03
+ #define VDAMET_METACT_CLEAR 0x04
+
+ u8 test_action;
+ #define VDAMET_TSTACT_NONE 0x00
+ #define VDAMET_TSTACT_STRT_INIT 0x01
+ #define VDAMET_TSTACT_STRT_READ 0x02
+ #define VDAMET_TSTACT_STRT_VERIFY 0x03
+ #define VDAMET_TSTACT_STRT_INIT_VERIFY 0x04
+ #define VDAMET_TSTACT_STOP 0x05
+
+ u8 num_dev_indexes;
+ #define VDAMET_ALL_DEVICES 0xFF
+
+ u16 dev_indexes[32];
+ u8 reserved[12];
+ struct atto_vda_sge sge[1];
+};
+
+
+struct __packed atto_vda_metrics_data {
+ u16 dev_index;
+ u16 length;
+ #define VDAMD_LEN_LAST 0x8000
+ #define VDAMD_LEN_MASK 0x0FFF
+
+ u32 flags;
+ #define VDAMDF_RUN 0x00000007
+ #define VDAMDF_RUN_READ 0x00000001
+ #define VDAMDF_RUN_WRITE 0x00000002
+ #define VDAMDF_RUN_ALL 0x00000004
+ #define VDAMDF_READ 0x00000010
+ #define VDAMDF_WRITE 0x00000020
+ #define VDAMDF_ALL 0x00000040
+ #define VDAMDF_DRIVETEST 0x40000000
+ #define VDAMDF_NEW 0x80000000
+
+ u64 total_read_data;
+ u64 total_write_data;
+ u64 total_read_io;
+ u64 total_write_io;
+ u64 read_start_time;
+ u64 read_stop_time;
+ u64 write_start_time;
+ u64 write_stop_time;
+ u64 read_maxio_time;
+ u64 wpvdadmetricsdatarite_maxio_time;
+ u64 read_totalio_time;
+ u64 write_totalio_time;
+ u64 read_total_errs;
+ u64 write_total_errs;
+ u64 read_recvrd_errs;
+ u64 write_recvrd_errs;
+ u64 miscompares;
+};
+
+
+struct __packed atto_vda_schedule_info {
+ u8 schedule_type;
+ #define VDASI_SCHTYPE_ONETIME 0x01
+ #define VDASI_SCHTYPE_DAILY 0x02
+ #define VDASI_SCHTYPE_WEEKLY 0x03
+
+ u8 operation;
+ #define VDASI_OP_NONE 0x00
+ #define VDASI_OP_CREATE 0x01
+ #define VDASI_OP_CANCEL 0x02
+
+ u8 hour;
+ u8 minute;
+ u8 day;
+ #define VDASI_DAY_NONE 0x00
+
+ u8 progress;
+ #define VDASI_PROG_NONE 0xFF
+
+ u8 event_type;
+ #define VDASI_EVTTYPE_SECT_SCAN 0x01
+ #define VDASI_EVTTYPE_SECT_SCAN_PARITY 0x02
+ #define VDASI_EVTTYPE_SECT_SCAN_PARITY_FIX 0x03
+
+ u8 recurrences;
+ #define VDASI_RECUR_FOREVER 0x00
+
+ u32 id;
+ #define VDASI_ID_NONE 0x00
+
+ char grp_name[15];
+ u8 reserved[85];
+};
+
+
+struct __packed atto_vda_n_vcache_info {
+ u8 super_cap_status;
+ #define VDANVCI_SUPERCAP_NOT_PRESENT 0x00
+ #define VDANVCI_SUPERCAP_FULLY_CHARGED 0x01
+ #define VDANVCI_SUPERCAP_NOT_CHARGED 0x02
+
+ u8 nvcache_module_status;
+ #define VDANVCI_NVCACHEMODULE_NOT_PRESENT 0x00
+ #define VDANVCI_NVCACHEMODULE_PRESENT 0x01
+
+ u8 protection_mode;
+ #define VDANVCI_PROTMODE_HI_PROTECT 0x00
+ #define VDANVCI_PROTMODE_HI_PERFORM 0x01
+
+ u8 reserved[109];
+};
+
+
+struct __packed atto_vda_buzzer_info {
+ u8 status;
+ #define VDABUZZI_BUZZER_OFF 0x00
+ #define VDABUZZI_BUZZER_ON 0x01
+ #define VDABUZZI_BUZZER_LAST 0x02
+
+ u8 reserved[3];
+ u32 duration;
+ #define VDABUZZI_DURATION_INDEFINITE 0xffffffff
+
+ u8 reserved2[104];
+};
+
+
+struct __packed atto_vda_adapter_info {
+ u8 version;
+ #define VDAADAPINFO_VERSION0 0x00
+ #define VDAADAPINFO_VERSION VDAADAPINFO_VERSION0
+
+ u8 reserved;
+ signed short utc_offset;
+ u32 utc_time;
+ u32 features;
+ #define VDA_ADAP_FEAT_IDENT 0x0001
+ #define VDA_ADAP_FEAT_BUZZ_ERR 0x0002
+ #define VDA_ADAP_FEAT_UTC_TIME 0x0004
+
+ u32 valid_features;
+ char active_config[33];
+ u8 temp_count;
+ u8 fan_count;
+ u8 reserved3[61];
+};
+
+
+struct __packed atto_vda_temp_info {
+ u8 temp_index;
+ u8 max_op_temp;
+ u8 min_op_temp;
+ u8 op_temp_warn;
+ u8 temperature;
+ u8 type;
+ #define VDA_TEMP_TYPE_CPU 1
+
+ u8 reserved[106];
+};
+
+
+struct __packed atto_vda_fan_info {
+ u8 fan_index;
+ u8 status;
+ #define VDA_FAN_STAT_UNKNOWN 0
+ #define VDA_FAN_STAT_NORMAL 1
+ #define VDA_FAN_STAT_FAIL 2
+
+ u16 crit_pvdafaninfothreshold;
+ u16 warn_threshold;
+ u16 speed;
+ u8 reserved[104];
+};
+
+
+/* VDA management commands */
+
+#define VDAMGT_DEV_SCAN 0x00
+#define VDAMGT_DEV_INFO 0x01
+#define VDAMGT_DEV_CLEAN 0x02
+#define VDAMGT_DEV_IDENTIFY 0x03
+#define VDAMGT_DEV_IDENTSTOP 0x04
+#define VDAMGT_DEV_PT_INFO 0x05
+#define VDAMGT_DEV_FEATURES 0x06
+#define VDAMGT_DEV_PT_FEATURES 0x07
+#define VDAMGT_DEV_HEALTH_REQ 0x08
+#define VDAMGT_DEV_METRICS 0x09
+#define VDAMGT_DEV_INFO2 0x0A
+#define VDAMGT_DEV_OPERATION 0x0B
+#define VDAMGT_DEV_INFO2_BYADDR 0x0C
+#define VDAMGT_GRP_INFO 0x10
+#define VDAMGT_GRP_CREATE 0x11
+#define VDAMGT_GRP_DELETE 0x12
+#define VDAMGT_ADD_STORAGE 0x13
+#define VDAMGT_MEMBER_ADD 0x14
+#define VDAMGT_GRP_COMMIT 0x15
+#define VDAMGT_GRP_REBUILD 0x16
+#define VDAMGT_GRP_COMMIT_INIT 0x17
+#define VDAMGT_QUICK_RAID 0x18
+#define VDAMGT_GRP_FEATURES 0x19
+#define VDAMGT_GRP_COMMIT_INIT_AUTOMAP 0x1A
+#define VDAMGT_QUICK_RAID_INIT_AUTOMAP 0x1B
+#define VDAMGT_GRP_OPERATION 0x1C
+#define VDAMGT_CFG_SAVE 0x20
+#define VDAMGT_LAST_ERROR 0x21
+#define VDAMGT_ADAP_INFO 0x22
+#define VDAMGT_ADAP_FEATURES 0x23
+#define VDAMGT_TEMP_INFO 0x24
+#define VDAMGT_FAN_INFO 0x25
+#define VDAMGT_PART_INFO 0x30
+#define VDAMGT_PART_MAP 0x31
+#define VDAMGT_PART_UNMAP 0x32
+#define VDAMGT_PART_AUTOMAP 0x33
+#define VDAMGT_PART_SPLIT 0x34
+#define VDAMGT_PART_MERGE 0x35
+#define VDAMGT_SPARE_LIST 0x40
+#define VDAMGT_SPARE_ADD 0x41
+#define VDAMGT_SPARE_REMOVE 0x42
+#define VDAMGT_LOCAL_SPARE_ADD 0x43
+#define VDAMGT_SCHEDULE_EVENT 0x50
+#define VDAMGT_SCHEDULE_INFO 0x51
+#define VDAMGT_NVCACHE_INFO 0x60
+#define VDAMGT_NVCACHE_SET 0x61
+#define VDAMGT_BUZZER_INFO 0x70
+#define VDAMGT_BUZZER_SET 0x71
+
+
+struct __packed atto_vda_ae_hdr {
+ u8 bylength;
+ u8 byflags;
+ #define VDAAE_HDRF_EVENT_ACK 0x01
+
+ u8 byversion;
+ #define VDAAE_HDR_VER_0 0
+
+ u8 bytype;
+ #define VDAAE_HDR_TYPE_RAID 1
+ #define VDAAE_HDR_TYPE_LU 2
+ #define VDAAE_HDR_TYPE_DISK 3
+ #define VDAAE_HDR_TYPE_RESET 4
+ #define VDAAE_HDR_TYPE_LOG_INFO 5
+ #define VDAAE_HDR_TYPE_LOG_WARN 6
+ #define VDAAE_HDR_TYPE_LOG_CRIT 7
+ #define VDAAE_HDR_TYPE_LOG_FAIL 8
+ #define VDAAE_HDR_TYPE_NVC 9
+ #define VDAAE_HDR_TYPE_TLG_INFO 10
+ #define VDAAE_HDR_TYPE_TLG_WARN 11
+ #define VDAAE_HDR_TYPE_TLG_CRIT 12
+ #define VDAAE_HDR_TYPE_PWRMGT 13
+ #define VDAAE_HDR_TYPE_MUTE 14
+ #define VDAAE_HDR_TYPE_DEV 15
+};
+
+
+struct __packed atto_vda_ae_raid {
+ struct atto_vda_ae_hdr hdr;
+ u32 dwflags;
+ #define VDAAE_GROUP_STATE 0x00000001
+ #define VDAAE_RBLD_STATE 0x00000002
+ #define VDAAE_RBLD_PROG 0x00000004
+ #define VDAAE_MEMBER_CHG 0x00000008
+ #define VDAAE_PART_CHG 0x00000010
+ #define VDAAE_MEM_STATE_CHG 0x00000020
+
+ u8 bygroup_state;
+ #define VDAAE_RAID_INVALID 0
+ #define VDAAE_RAID_NEW 1
+ #define VDAAE_RAID_WAITING 2
+ #define VDAAE_RAID_ONLINE 3
+ #define VDAAE_RAID_DEGRADED 4
+ #define VDAAE_RAID_OFFLINE 5
+ #define VDAAE_RAID_DELETED 6
+ #define VDAAE_RAID_BASIC 7
+ #define VDAAE_RAID_EXTREME 8
+ #define VDAAE_RAID_UNKNOWN 9
+
+ u8 byrebuild_state;
+ #define VDAAE_RBLD_NONE 0
+ #define VDAAE_RBLD_REBUILD 1
+ #define VDAAE_RBLD_ERASE 2
+ #define VDAAE_RBLD_PATTERN 3
+ #define VDAAE_RBLD_CONV 4
+ #define VDAAE_RBLD_FULL_INIT 5
+ #define VDAAE_RBLD_QUICK_INIT 6
+ #define VDAAE_RBLD_SECT_SCAN 7
+ #define VDAAE_RBLD_SECT_SCAN_PARITY 8
+ #define VDAAE_RBLD_SECT_SCAN_PARITY_FIX 9
+ #define VDAAE_RBLD_RECOV_REBUILD 10
+ #define VDAAE_RBLD_UNKNOWN 11
+
+ u8 byrebuild_progress;
+ u8 op_status;
+ #define VDAAE_GRPOPSTAT_MASK 0x0F
+ #define VDAAE_GRPOPSTAT_INVALID 0x00
+ #define VDAAE_GRPOPSTAT_OK 0x01
+ #define VDAAE_GRPOPSTAT_FAULTED 0x02
+ #define VDAAE_GRPOPSTAT_HALTED 0x03
+ #define VDAAE_GRPOPSTAT_INT 0x04
+ #define VDAAE_GRPOPPROC_MASK 0xF0
+ #define VDAAE_GRPOPPROC_STARTABLE 0x10
+ #define VDAAE_GRPOPPROC_CANCELABLE 0x20
+ #define VDAAE_GRPOPPROC_RESUMABLE 0x40
+ #define VDAAE_GRPOPPROC_HALTABLE 0x80
+ char acname[15];
+ u8 byreserved;
+ u8 byreserved2[0x80 - 0x1C];
+};
+
+
+struct __packed atto_vda_ae_lu_tgt_lun {
+ u16 wtarget_id;
+ u8 bylun;
+ u8 byreserved;
+};
+
+
+struct __packed atto_vda_ae_lu_tgt_lun_raid {
+ u16 wtarget_id;
+ u8 bylun;
+ u8 byreserved;
+ u32 dwinterleave;
+ u32 dwblock_size;
+};
+
+
+struct __packed atto_vda_ae_lu {
+ struct atto_vda_ae_hdr hdr;
+ u32 dwevent;
+ #define VDAAE_LU_DISC 0x00000001
+ #define VDAAE_LU_LOST 0x00000002
+ #define VDAAE_LU_STATE 0x00000004
+ #define VDAAE_LU_PASSTHROUGH 0x10000000
+ #define VDAAE_LU_PHYS_ID 0x20000000
+
+ u8 bystate;
+ #define VDAAE_LU_UNDEFINED 0
+ #define VDAAE_LU_NOT_PRESENT 1
+ #define VDAAE_LU_OFFLINE 2
+ #define VDAAE_LU_ONLINE 3
+ #define VDAAE_LU_DEGRADED 4
+ #define VDAAE_LU_FACTORY_DISABLED 5
+ #define VDAAE_LU_DELETED 6
+ #define VDAAE_LU_BUSSCAN 7
+ #define VDAAE_LU_UNKNOWN 8
+
+ u8 byreserved;
+ u16 wphys_target_id;
+
+ union {
+ struct atto_vda_ae_lu_tgt_lun tgtlun;
+ struct atto_vda_ae_lu_tgt_lun_raid tgtlun_raid;
+ } id;
+};
+
+
+struct __packed atto_vda_ae_disk {
+ struct atto_vda_ae_hdr hdr;
+};
+
+
+#define VDAAE_LOG_STRSZ 64
+
+struct __packed atto_vda_ae_log {
+ struct atto_vda_ae_hdr hdr;
+ char aclog_ascii[VDAAE_LOG_STRSZ];
+};
+
+
+#define VDAAE_TLG_STRSZ 56
+
+struct __packed atto_vda_ae_timestamp_log {
+ struct atto_vda_ae_hdr hdr;
+ u32 dwtimestamp;
+ char aclog_ascii[VDAAE_TLG_STRSZ];
+};
+
+
+struct __packed atto_vda_ae_nvc {
+ struct atto_vda_ae_hdr hdr;
+};
+
+
+struct __packed atto_vda_ae_dev {
+ struct atto_vda_ae_hdr hdr;
+ struct atto_dev_addr devaddr;
+};
+
+
+union atto_vda_ae {
+ struct atto_vda_ae_hdr hdr;
+ struct atto_vda_ae_disk disk;
+ struct atto_vda_ae_lu lu;
+ struct atto_vda_ae_raid raid;
+ struct atto_vda_ae_log log;
+ struct atto_vda_ae_timestamp_log tslog;
+ struct atto_vda_ae_nvc nvcache;
+ struct atto_vda_ae_dev dev;
+};
+
+
+struct __packed atto_vda_date_and_time {
+ u8 flags;
+ #define VDA_DT_DAY_MASK 0x07
+ #define VDA_DT_DAY_NONE 0x00
+ #define VDA_DT_DAY_SUN 0x01
+ #define VDA_DT_DAY_MON 0x02
+ #define VDA_DT_DAY_TUE 0x03
+ #define VDA_DT_DAY_WED 0x04
+ #define VDA_DT_DAY_THU 0x05
+ #define VDA_DT_DAY_FRI 0x06
+ #define VDA_DT_DAY_SAT 0x07
+ #define VDA_DT_PM 0x40
+ #define VDA_DT_MILITARY 0x80
+
+ u8 seconds;
+ u8 minutes;
+ u8 hours;
+ u8 day;
+ u8 month;
+ u16 year;
+};
+
+#define SGE_LEN_LIMIT 0x003FFFFF /*! mask of segment length */
+#define SGE_LEN_MAX 0x003FF000 /*! maximum segment length */
+#define SGE_LAST 0x01000000 /*! last entry */
+#define SGE_ADDR_64 0x04000000 /*! 64-bit addressing flag */
+#define SGE_CHAIN 0x80000000 /*! chain descriptor flag */
+#define SGE_CHAIN_LEN 0x0000FFFF /*! mask of length in chain entries */
+#define SGE_CHAIN_SZ 0x00FF0000 /*! mask of size of chained buffer */
+
+
+struct __packed atto_vda_cfg_init {
+ struct atto_vda_date_and_time date_time;
+ u32 sgl_page_size;
+ u32 vda_version;
+ u32 fw_version;
+ u32 fw_build;
+ u32 fw_release;
+ u32 epoch_time;
+ u32 ioctl_tunnel;
+ #define VDA_ITF_MEM_RW 0x00000001
+ #define VDA_ITF_TRACE 0x00000002
+ #define VDA_ITF_SCSI_PASS_THRU 0x00000004
+ #define VDA_ITF_GET_DEV_ADDR 0x00000008
+ #define VDA_ITF_PHY_CTRL 0x00000010
+ #define VDA_ITF_CONN_CTRL 0x00000020
+ #define VDA_ITF_GET_DEV_INFO 0x00000040
+
+ u32 num_targets_backend;
+ u8 reserved[0x48];
+};
+
+
+/* configuration commands */
+
+#define VDA_CFG_INIT 0x00
+#define VDA_CFG_GET_INIT 0x01
+#define VDA_CFG_GET_INIT2 0x02
+
+
+/*! physical region descriptor (PRD) aka scatter/gather entry */
+
+struct __packed atto_physical_region_description {
+ u64 address;
+ u32 ctl_len;
+ #define PRD_LEN_LIMIT 0x003FFFFF
+ #define PRD_LEN_MAX 0x003FF000
+ #define PRD_NXT_PRD_CNT 0x0000007F
+ #define PRD_CHAIN 0x01000000
+ #define PRD_DATA 0x00000000
+ #define PRD_INT_SEL 0xF0000000
+ #define PRD_INT_SEL_F0 0x00000000
+ #define PRD_INT_SEL_F1 0x40000000
+ #define PRD_INT_SEL_F2 0x80000000
+ #define PRD_INT_SEL_F3 0xc0000000
+ #define PRD_INT_SEL_SRAM 0x10000000
+ #define PRD_INT_SEL_PBSR 0x20000000
+
+};
+
+/* Request types. NOTE that ALL requests have the same layout for the first
+ * few bytes.
+ */
+struct __packed atto_vda_req_header {
+ u32 length;
+ u8 function;
+ u8 variable1;
+ u8 chain_offset;
+ u8 sg_list_offset;
+ u32 handle;
+};
+
+
+#define FCP_CDB_SIZE 16
+
+struct __packed atto_vda_scsi_req {
+ u32 length;
+ u8 function; /* VDA_FUNC_SCSI */
+ u8 sense_len;
+ u8 chain_offset;
+ u8 sg_list_offset;
+ u32 handle;
+ u32 flags;
+ #define FCP_CMND_LUN_MASK 0x000000FF
+ #define FCP_CMND_TA_MASK 0x00000700
+ #define FCP_CMND_TA_SIMPL_Q 0x00000000
+ #define FCP_CMND_TA_HEAD_Q 0x00000100
+ #define FCP_CMND_TA_ORDRD_Q 0x00000200
+ #define FCP_CMND_TA_ACA 0x00000400
+ #define FCP_CMND_PRI_MASK 0x00007800
+ #define FCP_CMND_TM_MASK 0x00FF0000
+ #define FCP_CMND_ATS 0x00020000
+ #define FCP_CMND_CTS 0x00040000
+ #define FCP_CMND_LRS 0x00100000
+ #define FCP_CMND_TRS 0x00200000
+ #define FCP_CMND_CLA 0x00400000
+ #define FCP_CMND_TRM 0x00800000
+ #define FCP_CMND_DATA_DIR 0x03000000
+ #define FCP_CMND_WRD 0x01000000
+ #define FCP_CMND_RDD 0x02000000
+
+ u8 cdb[FCP_CDB_SIZE];
+ union {
+ struct __packed {
+ u64 ppsense_buf;
+ u16 target_id;
+ u8 iblk_cnt_prd;
+ u8 reserved;
+ };
+
+ struct atto_physical_region_description sense_buff_prd;
+ };
+
+ union {
+ struct atto_vda_sge sge[1];
+
+ u32 abort_handle;
+ u32 dwords[245];
+ struct atto_physical_region_description prd[1];
+ } u;
+};
+
+
+struct __packed atto_vda_flash_req {
+ u32 length;
+ u8 function; /* VDA_FUNC_FLASH */
+ u8 sub_func;
+ u8 chain_offset;
+ u8 sg_list_offset;
+ u32 handle;
+ u32 flash_addr;
+ u8 checksum;
+ u8 rsvd[3];
+
+ union {
+ struct {
+ char file_name[16]; /* 8.3 fname, NULL term, wc=* */
+ struct atto_vda_sge sge[1];
+ } file;
+
+ struct atto_vda_sge sge[1];
+ struct atto_physical_region_description prde[2];
+ } data;
+};
+
+
+struct __packed atto_vda_diag_req {
+ u32 length;
+ u8 function; /* VDA_FUNC_DIAG */
+ u8 sub_func;
+ #define VDA_DIAG_STATUS 0x00
+ #define VDA_DIAG_RESET 0x01
+ #define VDA_DIAG_PAUSE 0x02
+ #define VDA_DIAG_RESUME 0x03
+ #define VDA_DIAG_READ 0x04
+ #define VDA_DIAG_WRITE 0x05
+
+ u8 chain_offset;
+ u8 sg_list_offset;
+ u32 handle;
+ u32 rsvd;
+ u64 local_addr;
+ struct atto_vda_sge sge[1];
+};
+
+
+struct __packed atto_vda_ae_req {
+ u32 length;
+ u8 function; /* VDA_FUNC_AE */
+ u8 reserved1;
+ u8 chain_offset;
+ u8 sg_list_offset;
+ u32 handle;
+
+ union {
+ struct atto_vda_sge sge[1];
+ struct atto_physical_region_description prde[1];
+ };
+};
+
+
+struct __packed atto_vda_cli_req {
+ u32 length;
+ u8 function; /* VDA_FUNC_CLI */
+ u8 reserved1;
+ u8 chain_offset;
+ u8 sg_list_offset;
+ u32 handle;
+ u32 cmd_rsp_len;
+ struct atto_vda_sge sge[1];
+};
+
+
+struct __packed atto_vda_ioctl_req {
+ u32 length;
+ u8 function; /* VDA_FUNC_IOCTL */
+ u8 sub_func;
+ u8 chain_offset;
+ u8 sg_list_offset;
+ u32 handle;
+
+ union {
+ struct atto_vda_sge reserved_sge;
+ struct atto_physical_region_description reserved_prde;
+ };
+
+ union {
+ struct {
+ u32 ctrl_code;
+ u16 target_id;
+ u8 lun;
+ u8 reserved;
+ } csmi;
+ };
+
+ union {
+ struct atto_vda_sge sge[1];
+ struct atto_physical_region_description prde[1];
+ };
+};
+
+
+struct __packed atto_vda_cfg_req {
+ u32 length;
+ u8 function; /* VDA_FUNC_CFG */
+ u8 sub_func;
+ u8 rsvd1;
+ u8 sg_list_offset;
+ u32 handle;
+
+ union {
+ u8 bytes[116];
+ struct atto_vda_cfg_init init;
+ struct atto_vda_sge sge;
+ struct atto_physical_region_description prde;
+ } data;
+};
+
+
+struct __packed atto_vda_mgmt_req {
+ u32 length;
+ u8 function; /* VDA_FUNC_MGT */
+ u8 mgt_func;
+ u8 chain_offset;
+ u8 sg_list_offset;
+ u32 handle;
+ u8 scan_generation;
+ u8 payld_sglst_offset;
+ u16 dev_index;
+ u32 payld_length;
+ u32 pad;
+ union {
+ struct atto_vda_sge sge[2];
+ struct atto_physical_region_description prde[2];
+ };
+ struct atto_vda_sge payld_sge[1];
+};
+
+
+union atto_vda_req {
+ struct atto_vda_scsi_req scsi;
+ struct atto_vda_flash_req flash;
+ struct atto_vda_diag_req diag;
+ struct atto_vda_ae_req ae;
+ struct atto_vda_cli_req cli;
+ struct atto_vda_ioctl_req ioctl;
+ struct atto_vda_cfg_req cfg;
+ struct atto_vda_mgmt_req mgt;
+ u8 bytes[1024];
+};
+
+/* Outbound response structures */
+
+struct __packed atto_vda_scsi_rsp {
+ u8 scsi_stat;
+ u8 sense_len;
+ u8 rsvd[2];
+ u32 residual_length;
+};
+
+struct __packed atto_vda_flash_rsp {
+ u32 file_size;
+};
+
+struct __packed atto_vda_ae_rsp {
+ u32 length;
+};
+
+struct __packed atto_vda_cli_rsp {
+ u32 cmd_rsp_len;
+};
+
+struct __packed atto_vda_ioctl_rsp {
+ union {
+ struct {
+ u32 csmi_status;
+ u16 target_id;
+ u8 lun;
+ u8 reserved;
+ } csmi;
+ };
+};
+
+struct __packed atto_vda_cfg_rsp {
+ u16 vda_version;
+ u16 fw_release;
+ u32 fw_build;
+};
+
+struct __packed atto_vda_mgmt_rsp {
+ u32 length;
+ u16 dev_index;
+ u8 scan_generation;
+};
+
+union atto_vda_func_rsp {
+ struct atto_vda_scsi_rsp scsi_rsp;
+ struct atto_vda_flash_rsp flash_rsp;
+ struct atto_vda_ae_rsp ae_rsp;
+ struct atto_vda_cli_rsp cli_rsp;
+ struct atto_vda_ioctl_rsp ioctl_rsp;
+ struct atto_vda_cfg_rsp cfg_rsp;
+ struct atto_vda_mgmt_rsp mgt_rsp;
+ u32 dwords[2];
+};
+
+struct __packed atto_vda_ob_rsp {
+ u32 handle;
+ u8 req_stat;
+ u8 rsvd[3];
+
+ union atto_vda_func_rsp
+ func_rsp;
+};
+
+struct __packed atto_vda_ae_data {
+ u8 event_data[256];
+};
+
+struct __packed atto_vda_mgmt_data {
+ union {
+ u8 bytes[112];
+ struct atto_vda_devinfo dev_info;
+ struct atto_vda_grp_info grp_info;
+ struct atto_vdapart_info part_info;
+ struct atto_vda_dh_info dev_health_info;
+ struct atto_vda_metrics_info metrics_info;
+ struct atto_vda_schedule_info sched_info;
+ struct atto_vda_n_vcache_info nvcache_info;
+ struct atto_vda_buzzer_info buzzer_info;
+ } data;
+};
+
+union atto_vda_rsp_data {
+ struct atto_vda_ae_data ae_data;
+ struct atto_vda_mgmt_data mgt_data;
+ u8 sense_data[252];
+ #define SENSE_DATA_SZ 252;
+ u8 bytes[256];
+};
+
+#endif
diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h
new file mode 100644
index 00000000000..0838e265e0b
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r.h
@@ -0,0 +1,1441 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r.h
+ * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_tcq.h>
+
+#include "esas2r_log.h"
+#include "atioctl.h"
+#include "atvda.h"
+
+#ifndef ESAS2R_H
+#define ESAS2R_H
+
+/* Global Variables */
+extern struct esas2r_adapter *esas2r_adapters[];
+extern u8 *esas2r_buffered_ioctl;
+extern dma_addr_t esas2r_buffered_ioctl_addr;
+extern u32 esas2r_buffered_ioctl_size;
+extern struct pci_dev *esas2r_buffered_ioctl_pcid;
+#define SGL_PG_SZ_MIN 64
+#define SGL_PG_SZ_MAX 1024
+extern int sgl_page_size;
+#define NUM_SGL_MIN 8
+#define NUM_SGL_MAX 2048
+extern int num_sg_lists;
+#define NUM_REQ_MIN 4
+#define NUM_REQ_MAX 256
+extern int num_requests;
+#define NUM_AE_MIN 2
+#define NUM_AE_MAX 8
+extern int num_ae_requests;
+extern int cmd_per_lun;
+extern int can_queue;
+extern int esas2r_max_sectors;
+extern int sg_tablesize;
+extern int interrupt_mode;
+extern int num_io_requests;
+
+/* Macro defintions */
+#define ESAS2R_MAX_ID 255
+#define MAX_ADAPTERS 32
+#define ESAS2R_DRVR_NAME "esas2r"
+#define ESAS2R_LONGNAME "ATTO ExpressSAS 6GB RAID Adapter"
+#define ESAS2R_MAX_DEVICES 32
+#define ATTONODE_NAME "ATTONode"
+#define ESAS2R_MAJOR_REV 1
+#define ESAS2R_MINOR_REV 00
+#define ESAS2R_VERSION_STR DEFINED_NUM_TO_STR(ESAS2R_MAJOR_REV) "." \
+ DEFINED_NUM_TO_STR(ESAS2R_MINOR_REV)
+#define ESAS2R_COPYRIGHT_YEARS "2001-2013"
+#define ESAS2R_DEFAULT_SGL_PAGE_SIZE 384
+#define ESAS2R_DEFAULT_CMD_PER_LUN 64
+#define ESAS2R_DEFAULT_NUM_SG_LISTS 1024
+#define DEFINED_NUM_TO_STR(num) NUM_TO_STR(num)
+#define NUM_TO_STR(num) #num
+
+#define ESAS2R_SGL_ALIGN 16
+#define ESAS2R_LIST_ALIGN 16
+#define ESAS2R_LIST_EXTRA ESAS2R_NUM_EXTRA
+#define ESAS2R_DATA_BUF_LEN 256
+#define ESAS2R_DEFAULT_TMO 5000
+#define ESAS2R_DISC_BUF_LEN 512
+#define ESAS2R_FWCOREDUMP_SZ 0x80000
+#define ESAS2R_NUM_PHYS 8
+#define ESAS2R_TARG_ID_INV 0xFFFF
+#define ESAS2R_INT_STS_MASK MU_INTSTAT_MASK
+#define ESAS2R_INT_ENB_MASK MU_INTSTAT_MASK
+#define ESAS2R_INT_DIS_MASK 0
+#define ESAS2R_MAX_TARGETS 256
+#define ESAS2R_KOBJ_NAME_LEN 20
+
+/* u16 (WORD) component macros */
+#define LOBYTE(w) ((u8)(u16)(w))
+#define HIBYTE(w) ((u8)(((u16)(w)) >> 8))
+#define MAKEWORD(lo, hi) ((u16)((u8)(lo) | ((u16)(u8)(hi) << 8)))
+
+/* u32 (DWORD) component macros */
+#define LOWORD(d) ((u16)(u32)(d))
+#define HIWORD(d) ((u16)(((u32)(d)) >> 16))
+#define MAKEDWORD(lo, hi) ((u32)((u16)(lo) | ((u32)(u16)(hi) << 16)))
+
+/* macro to get the lowest nonzero bit of a value */
+#define LOBIT(x) ((x) & (0 - (x)))
+
+/* These functions are provided to access the chip's control registers.
+ * The register is specified by its byte offset from the register base
+ * for the adapter.
+ */
+#define esas2r_read_register_dword(a, reg) \
+ readl((void __iomem *)a->regs + (reg) + MW_REG_OFFSET_HWREG)
+
+#define esas2r_write_register_dword(a, reg, data) \
+ writel(data, (void __iomem *)(a->regs + (reg) + MW_REG_OFFSET_HWREG))
+
+#define esas2r_flush_register_dword(a, r) esas2r_read_register_dword(a, r)
+
+/* This function is provided to access the chip's data window. The
+ * register is specified by its byte offset from the window base
+ * for the adapter.
+ */
+#define esas2r_read_data_byte(a, reg) \
+ readb((void __iomem *)a->data_window + (reg))
+
+/* ATTO vendor and device Ids */
+#define ATTO_VENDOR_ID 0x117C
+#define ATTO_DID_INTEL_IOP348 0x002C
+#define ATTO_DID_MV_88RC9580 0x0049
+#define ATTO_DID_MV_88RC9580TS 0x0066
+#define ATTO_DID_MV_88RC9580TSE 0x0067
+#define ATTO_DID_MV_88RC9580TL 0x0068
+
+/* ATTO subsystem device Ids */
+#define ATTO_SSDID_TBT 0x4000
+#define ATTO_TSSC_3808 0x4066
+#define ATTO_TSSC_3808E 0x4067
+#define ATTO_TLSH_1068 0x4068
+#define ATTO_ESAS_R680 0x0049
+#define ATTO_ESAS_R608 0x004A
+#define ATTO_ESAS_R60F 0x004B
+#define ATTO_ESAS_R6F0 0x004C
+#define ATTO_ESAS_R644 0x004D
+#define ATTO_ESAS_R648 0x004E
+
+/*
+ * flash definitions & structures
+ * define the code types
+ */
+#define FBT_CPYR 0xAA00
+#define FBT_SETUP 0xAA02
+#define FBT_FLASH_VER 0xAA04
+
+/* offsets to various locations in flash */
+#define FLS_OFFSET_BOOT (u32)(0x00700000)
+#define FLS_OFFSET_NVR (u32)(0x007C0000)
+#define FLS_OFFSET_CPYR FLS_OFFSET_NVR
+#define FLS_LENGTH_BOOT (FLS_OFFSET_CPYR - FLS_OFFSET_BOOT)
+#define FLS_BLOCK_SIZE (u32)(0x00020000)
+#define FI_NVR_2KB 0x0800
+#define FI_NVR_8KB 0x2000
+#define FM_BUF_SZ 0x800
+
+/*
+ * marvell frey (88R9580) register definitions
+ * chip revision identifiers
+ */
+#define MVR_FREY_B2 0xB2
+
+/*
+ * memory window definitions. window 0 is the data window with definitions
+ * of MW_DATA_XXX. window 1 is the register window with definitions of
+ * MW_REG_XXX.
+ */
+#define MW_REG_WINDOW_SIZE (u32)(0x00040000)
+#define MW_REG_OFFSET_HWREG (u32)(0x00000000)
+#define MW_REG_OFFSET_PCI (u32)(0x00008000)
+#define MW_REG_PCI_HWREG_DELTA (MW_REG_OFFSET_PCI - MW_REG_OFFSET_HWREG)
+#define MW_DATA_WINDOW_SIZE (u32)(0x00020000)
+#define MW_DATA_ADDR_SER_FLASH (u32)(0xEC000000)
+#define MW_DATA_ADDR_SRAM (u32)(0xF4000000)
+#define MW_DATA_ADDR_PAR_FLASH (u32)(0xFC000000)
+
+/*
+ * the following registers are for the communication
+ * list interface (AKA message unit (MU))
+ */
+#define MU_IN_LIST_ADDR_LO (u32)(0x00004000)
+#define MU_IN_LIST_ADDR_HI (u32)(0x00004004)
+
+#define MU_IN_LIST_WRITE (u32)(0x00004018)
+ #define MU_ILW_TOGGLE (u32)(0x00004000)
+
+#define MU_IN_LIST_READ (u32)(0x0000401C)
+ #define MU_ILR_TOGGLE (u32)(0x00004000)
+ #define MU_ILIC_LIST (u32)(0x0000000F)
+ #define MU_ILIC_LIST_F0 (u32)(0x00000000)
+ #define MU_ILIC_DEST (u32)(0x00000F00)
+ #define MU_ILIC_DEST_DDR (u32)(0x00000200)
+#define MU_IN_LIST_IFC_CONFIG (u32)(0x00004028)
+
+#define MU_IN_LIST_CONFIG (u32)(0x0000402C)
+ #define MU_ILC_ENABLE (u32)(0x00000001)
+ #define MU_ILC_ENTRY_MASK (u32)(0x000000F0)
+ #define MU_ILC_ENTRY_4_DW (u32)(0x00000020)
+ #define MU_ILC_DYNAMIC_SRC (u32)(0x00008000)
+ #define MU_ILC_NUMBER_MASK (u32)(0x7FFF0000)
+ #define MU_ILC_NUMBER_SHIFT 16
+
+#define MU_OUT_LIST_ADDR_LO (u32)(0x00004050)
+#define MU_OUT_LIST_ADDR_HI (u32)(0x00004054)
+
+#define MU_OUT_LIST_COPY_PTR_LO (u32)(0x00004058)
+#define MU_OUT_LIST_COPY_PTR_HI (u32)(0x0000405C)
+
+#define MU_OUT_LIST_WRITE (u32)(0x00004068)
+ #define MU_OLW_TOGGLE (u32)(0x00004000)
+
+#define MU_OUT_LIST_COPY (u32)(0x0000406C)
+ #define MU_OLC_TOGGLE (u32)(0x00004000)
+ #define MU_OLC_WRT_PTR (u32)(0x00003FFF)
+
+#define MU_OUT_LIST_IFC_CONFIG (u32)(0x00004078)
+ #define MU_OLIC_LIST (u32)(0x0000000F)
+ #define MU_OLIC_LIST_F0 (u32)(0x00000000)
+ #define MU_OLIC_SOURCE (u32)(0x00000F00)
+ #define MU_OLIC_SOURCE_DDR (u32)(0x00000200)
+
+#define MU_OUT_LIST_CONFIG (u32)(0x0000407C)
+ #define MU_OLC_ENABLE (u32)(0x00000001)
+ #define MU_OLC_ENTRY_MASK (u32)(0x000000F0)
+ #define MU_OLC_ENTRY_4_DW (u32)(0x00000020)
+ #define MU_OLC_NUMBER_MASK (u32)(0x7FFF0000)
+ #define MU_OLC_NUMBER_SHIFT 16
+
+#define MU_OUT_LIST_INT_STAT (u32)(0x00004088)
+ #define MU_OLIS_INT (u32)(0x00000001)
+
+#define MU_OUT_LIST_INT_MASK (u32)(0x0000408C)
+ #define MU_OLIS_MASK (u32)(0x00000001)
+
+/*
+ * the maximum size of the communication lists is two greater than the
+ * maximum amount of VDA requests. the extra are to prevent queue overflow.
+ */
+#define ESAS2R_MAX_NUM_REQS 256
+#define ESAS2R_NUM_EXTRA 2
+#define ESAS2R_MAX_COMM_LIST_SIZE (ESAS2R_MAX_NUM_REQS + ESAS2R_NUM_EXTRA)
+
+/*
+ * the following registers are for the CPU interface
+ */
+#define MU_CTL_STATUS_IN (u32)(0x00010108)
+ #define MU_CTL_IN_FULL_RST (u32)(0x00000020)
+#define MU_CTL_STATUS_IN_B2 (u32)(0x00010130)
+ #define MU_CTL_IN_FULL_RST2 (u32)(0x80000000)
+#define MU_DOORBELL_IN (u32)(0x00010460)
+ #define DRBL_RESET_BUS (u32)(0x00000002)
+ #define DRBL_PAUSE_AE (u32)(0x00000004)
+ #define DRBL_RESUME_AE (u32)(0x00000008)
+ #define DRBL_MSG_IFC_DOWN (u32)(0x00000010)
+ #define DRBL_FLASH_REQ (u32)(0x00000020)
+ #define DRBL_FLASH_DONE (u32)(0x00000040)
+ #define DRBL_FORCE_INT (u32)(0x00000080)
+ #define DRBL_MSG_IFC_INIT (u32)(0x00000100)
+ #define DRBL_POWER_DOWN (u32)(0x00000200)
+ #define DRBL_DRV_VER_1 (u32)(0x00010000)
+ #define DRBL_DRV_VER DRBL_DRV_VER_1
+#define MU_DOORBELL_IN_ENB (u32)(0x00010464)
+#define MU_DOORBELL_OUT (u32)(0x00010480)
+ #define DRBL_PANIC_REASON_MASK (u32)(0x00F00000)
+ #define DRBL_UNUSED_HANDLER (u32)(0x00100000)
+ #define DRBL_UNDEF_INSTR (u32)(0x00200000)
+ #define DRBL_PREFETCH_ABORT (u32)(0x00300000)
+ #define DRBL_DATA_ABORT (u32)(0x00400000)
+ #define DRBL_JUMP_TO_ZERO (u32)(0x00500000)
+ #define DRBL_FW_RESET (u32)(0x00080000)
+ #define DRBL_FW_VER_MSK (u32)(0x00070000)
+ #define DRBL_FW_VER_0 (u32)(0x00000000)
+ #define DRBL_FW_VER_1 (u32)(0x00010000)
+ #define DRBL_FW_VER DRBL_FW_VER_1
+#define MU_DOORBELL_OUT_ENB (u32)(0x00010484)
+ #define DRBL_ENB_MASK (u32)(0x00F803FF)
+#define MU_INT_STATUS_OUT (u32)(0x00010200)
+ #define MU_INTSTAT_POST_OUT (u32)(0x00000010)
+ #define MU_INTSTAT_DRBL_IN (u32)(0x00000100)
+ #define MU_INTSTAT_DRBL (u32)(0x00001000)
+ #define MU_INTSTAT_MASK (u32)(0x00001010)
+#define MU_INT_MASK_OUT (u32)(0x0001020C)
+
+/* PCI express registers accessed via window 1 */
+#define MVR_PCI_WIN1_REMAP (u32)(0x00008438)
+ #define MVRPW1R_ENABLE (u32)(0x00000001)
+
+
+/* structures */
+
+/* inbound list dynamic source entry */
+struct esas2r_inbound_list_source_entry {
+ u64 address;
+ u32 length;
+ #define HWILSE_INTERFACE_F0 0x00000000
+ u32 reserved;
+};
+
+/* PCI data structure in expansion ROM images */
+struct __packed esas2r_boot_header {
+ char signature[4];
+ u16 vendor_id;
+ u16 device_id;
+ u16 VPD;
+ u16 struct_length;
+ u8 struct_revision;
+ u8 class_code[3];
+ u16 image_length;
+ u16 code_revision;
+ u8 code_type;
+ #define CODE_TYPE_PC 0
+ #define CODE_TYPE_OPEN 1
+ #define CODE_TYPE_EFI 3
+ u8 indicator;
+ #define INDICATOR_LAST 0x80
+ u8 reserved[2];
+};
+
+struct __packed esas2r_boot_image {
+ u16 signature;
+ u8 reserved[22];
+ u16 header_offset;
+ u16 pnp_offset;
+};
+
+struct __packed esas2r_pc_image {
+ u16 signature;
+ u8 length;
+ u8 entry_point[3];
+ u8 checksum;
+ u16 image_end;
+ u16 min_size;
+ u8 rom_flags;
+ u8 reserved[12];
+ u16 header_offset;
+ u16 pnp_offset;
+ struct esas2r_boot_header boot_image;
+};
+
+struct __packed esas2r_efi_image {
+ u16 signature;
+ u16 length;
+ u32 efi_signature;
+ #define EFI_ROM_SIG 0x00000EF1
+ u16 image_type;
+ #define EFI_IMAGE_APP 10
+ #define EFI_IMAGE_BSD 11
+ #define EFI_IMAGE_RTD 12
+ u16 machine_type;
+ #define EFI_MACHINE_IA32 0x014c
+ #define EFI_MACHINE_IA64 0x0200
+ #define EFI_MACHINE_X64 0x8664
+ #define EFI_MACHINE_EBC 0x0EBC
+ u16 compression;
+ #define EFI_UNCOMPRESSED 0x0000
+ #define EFI_COMPRESSED 0x0001
+ u8 reserved[8];
+ u16 efi_offset;
+ u16 header_offset;
+ u16 reserved2;
+ struct esas2r_boot_header boot_image;
+};
+
+struct esas2r_adapter;
+struct esas2r_sg_context;
+struct esas2r_request;
+
+typedef void (*RQCALLBK) (struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+typedef bool (*RQBUILDSGL) (struct esas2r_adapter *a,
+ struct esas2r_sg_context *sgc);
+
+struct esas2r_component_header {
+ u8 img_type;
+ #define CH_IT_FW 0x00
+ #define CH_IT_NVR 0x01
+ #define CH_IT_BIOS 0x02
+ #define CH_IT_MAC 0x03
+ #define CH_IT_CFG 0x04
+ #define CH_IT_EFI 0x05
+ u8 status;
+ #define CH_STAT_PENDING 0xff
+ #define CH_STAT_FAILED 0x00
+ #define CH_STAT_SUCCESS 0x01
+ #define CH_STAT_RETRY 0x02
+ #define CH_STAT_INVALID 0x03
+ u8 pad[2];
+ u32 version;
+ u32 length;
+ u32 image_offset;
+};
+
+#define FI_REL_VER_SZ 16
+
+struct esas2r_flash_img_v0 {
+ u8 fi_version;
+ #define FI_VERSION_0 00
+ u8 status;
+ u8 adap_typ;
+ u8 action;
+ u32 length;
+ u16 checksum;
+ u16 driver_error;
+ u16 flags;
+ u16 num_comps;
+ #define FI_NUM_COMPS_V0 5
+ u8 rel_version[FI_REL_VER_SZ];
+ struct esas2r_component_header cmp_hdr[FI_NUM_COMPS_V0];
+ u8 scratch_buf[FM_BUF_SZ];
+};
+
+struct esas2r_flash_img {
+ u8 fi_version;
+ #define FI_VERSION_1 01
+ u8 status;
+ #define FI_STAT_SUCCESS 0x00
+ #define FI_STAT_FAILED 0x01
+ #define FI_STAT_REBOOT 0x02
+ #define FI_STAT_ADAPTYP 0x03
+ #define FI_STAT_INVALID 0x04
+ #define FI_STAT_CHKSUM 0x05
+ #define FI_STAT_LENGTH 0x06
+ #define FI_STAT_UNKNOWN 0x07
+ #define FI_STAT_IMG_VER 0x08
+ #define FI_STAT_BUSY 0x09
+ #define FI_STAT_DUAL 0x0A
+ #define FI_STAT_MISSING 0x0B
+ #define FI_STAT_UNSUPP 0x0C
+ #define FI_STAT_ERASE 0x0D
+ #define FI_STAT_FLASH 0x0E
+ #define FI_STAT_DEGRADED 0x0F
+ u8 adap_typ;
+ #define FI_AT_UNKNWN 0xFF
+ #define FI_AT_SUN_LAKE 0x0B
+ #define FI_AT_MV_9580 0x0F
+ u8 action;
+ #define FI_ACT_DOWN 0x00
+ #define FI_ACT_UP 0x01
+ #define FI_ACT_UPSZ 0x02
+ #define FI_ACT_MAX 0x02
+ #define FI_ACT_DOWN1 0x80
+ u32 length;
+ u16 checksum;
+ u16 driver_error;
+ u16 flags;
+ #define FI_FLG_NVR_DEF 0x0001
+ u16 num_comps;
+ #define FI_NUM_COMPS_V1 6
+ u8 rel_version[FI_REL_VER_SZ];
+ struct esas2r_component_header cmp_hdr[FI_NUM_COMPS_V1];
+ u8 scratch_buf[FM_BUF_SZ];
+};
+
+/* definitions for flash script (FS) commands */
+struct esas2r_ioctlfs_command {
+ u8 command;
+ #define ESAS2R_FS_CMD_ERASE 0
+ #define ESAS2R_FS_CMD_READ 1
+ #define ESAS2R_FS_CMD_BEGINW 2
+ #define ESAS2R_FS_CMD_WRITE 3
+ #define ESAS2R_FS_CMD_COMMIT 4
+ #define ESAS2R_FS_CMD_CANCEL 5
+ u8 checksum;
+ u8 reserved[2];
+ u32 flash_addr;
+ u32 length;
+ u32 image_offset;
+};
+
+struct esas2r_ioctl_fs {
+ u8 version;
+ #define ESAS2R_FS_VER 0
+ u8 status;
+ u8 driver_error;
+ u8 adap_type;
+ #define ESAS2R_FS_AT_ESASRAID2 3
+ #define ESAS2R_FS_AT_TSSASRAID2 4
+ #define ESAS2R_FS_AT_TSSASRAID2E 5
+ #define ESAS2R_FS_AT_TLSASHBA 6
+ u8 driver_ver;
+ u8 reserved[11];
+ struct esas2r_ioctlfs_command command;
+ u8 data[1];
+};
+
+struct esas2r_sas_nvram {
+ u8 signature[4];
+ u8 version;
+ #define SASNVR_VERSION_0 0x00
+ #define SASNVR_VERSION SASNVR_VERSION_0
+ u8 checksum;
+ #define SASNVR_CKSUM_SEED 0x5A
+ u8 max_lun_for_target;
+ u8 pci_latency;
+ #define SASNVR_PCILAT_DIS 0x00
+ #define SASNVR_PCILAT_MIN 0x10
+ #define SASNVR_PCILAT_MAX 0xF8
+ u8 options1;
+ #define SASNVR1_BOOT_DRVR 0x01
+ #define SASNVR1_BOOT_SCAN 0x02
+ #define SASNVR1_DIS_PCI_MWI 0x04
+ #define SASNVR1_FORCE_ORD_Q 0x08
+ #define SASNVR1_CACHELINE_0 0x10
+ #define SASNVR1_DIS_DEVSORT 0x20
+ #define SASNVR1_PWR_MGT_EN 0x40
+ #define SASNVR1_WIDEPORT 0x80
+ u8 options2;
+ #define SASNVR2_SINGLE_BUS 0x01
+ #define SASNVR2_SLOT_BIND 0x02
+ #define SASNVR2_EXP_PROG 0x04
+ #define SASNVR2_CMDTHR_LUN 0x08
+ #define SASNVR2_HEARTBEAT 0x10
+ #define SASNVR2_INT_CONNECT 0x20
+ #define SASNVR2_SW_MUX_CTRL 0x40
+ #define SASNVR2_DISABLE_NCQ 0x80
+ u8 int_coalescing;
+ #define SASNVR_COAL_DIS 0x00
+ #define SASNVR_COAL_LOW 0x01
+ #define SASNVR_COAL_MED 0x02
+ #define SASNVR_COAL_HI 0x03
+ u8 cmd_throttle;
+ #define SASNVR_CMDTHR_NONE 0x00
+ u8 dev_wait_time;
+ u8 dev_wait_count;
+ u8 spin_up_delay;
+ #define SASNVR_SPINUP_MAX 0x14
+ u8 ssp_align_rate;
+ u8 sas_addr[8];
+ u8 phy_speed[16];
+ #define SASNVR_SPEED_AUTO 0x00
+ #define SASNVR_SPEED_1_5GB 0x01
+ #define SASNVR_SPEED_3GB 0x02
+ #define SASNVR_SPEED_6GB 0x03
+ #define SASNVR_SPEED_12GB 0x04
+ u8 phy_mux[16];
+ #define SASNVR_MUX_DISABLED 0x00
+ #define SASNVR_MUX_1_5GB 0x01
+ #define SASNVR_MUX_3GB 0x02
+ #define SASNVR_MUX_6GB 0x03
+ u8 phy_flags[16];
+ #define SASNVR_PHF_DISABLED 0x01
+ #define SASNVR_PHF_RD_ONLY 0x02
+ u8 sort_type;
+ #define SASNVR_SORT_SAS_ADDR 0x00
+ #define SASNVR_SORT_H308_CONN 0x01
+ #define SASNVR_SORT_PHY_ID 0x02
+ #define SASNVR_SORT_SLOT_ID 0x03
+ u8 dpm_reqcmd_lmt;
+ u8 dpm_stndby_time;
+ u8 dpm_active_time;
+ u8 phy_target_id[16];
+ #define SASNVR_PTI_DISABLED 0xFF
+ u8 virt_ses_mode;
+ #define SASNVR_VSMH_DISABLED 0x00
+ u8 read_write_mode;
+ #define SASNVR_RWM_DEFAULT 0x00
+ u8 link_down_to;
+ u8 reserved[0xA1];
+};
+
+typedef u32 (*PGETPHYSADDR) (struct esas2r_sg_context *sgc, u64 *addr);
+
+struct esas2r_sg_context {
+ struct esas2r_adapter *adapter;
+ struct esas2r_request *first_req;
+ u32 length;
+ u8 *cur_offset;
+ PGETPHYSADDR get_phys_addr;
+ union {
+ struct {
+ struct atto_vda_sge *curr;
+ struct atto_vda_sge *last;
+ struct atto_vda_sge *limit;
+ struct atto_vda_sge *chain;
+ } a64;
+ struct {
+ struct atto_physical_region_description *curr;
+ struct atto_physical_region_description *chain;
+ u32 sgl_max_cnt;
+ u32 sge_cnt;
+ } prd;
+ } sge;
+ struct scatterlist *cur_sgel;
+ u8 *exp_offset;
+ int num_sgel;
+ int sgel_count;
+};
+
+struct esas2r_target {
+ u8 flags;
+ #define TF_PASS_THRU 0x01
+ #define TF_USED 0x02
+ u8 new_target_state;
+ u8 target_state;
+ u8 buffered_target_state;
+#define TS_NOT_PRESENT 0x00
+#define TS_PRESENT 0x05
+#define TS_LUN_CHANGE 0x06
+#define TS_INVALID 0xFF
+ u32 block_size;
+ u32 inter_block;
+ u32 inter_byte;
+ u16 virt_targ_id;
+ u16 phys_targ_id;
+ u8 identifier_len;
+ u64 sas_addr;
+ u8 identifier[60];
+ struct atto_vda_ae_lu lu_event;
+};
+
+struct esas2r_request {
+ struct list_head comp_list;
+ struct list_head req_list;
+ union atto_vda_req *vrq;
+ struct esas2r_mem_desc *vrq_md;
+ union {
+ void *data_buf;
+ union atto_vda_rsp_data *vda_rsp_data;
+ };
+ u8 *sense_buf;
+ struct list_head sg_table_head;
+ struct esas2r_mem_desc *sg_table;
+ u32 timeout;
+ #define RQ_TIMEOUT_S1 0xFFFFFFFF
+ #define RQ_TIMEOUT_S2 0xFFFFFFFE
+ #define RQ_MAX_TIMEOUT 0xFFFFFFFD
+ u16 target_id;
+ u8 req_type;
+ #define RT_INI_REQ 0x01
+ #define RT_DISC_REQ 0x02
+ u8 sense_len;
+ union atto_vda_func_rsp func_rsp;
+ RQCALLBK comp_cb;
+ RQCALLBK interrupt_cb;
+ void *interrupt_cx;
+ u8 flags;
+ #define RF_1ST_IBLK_BASE 0x04
+ #define RF_FAILURE_OK 0x08
+ u8 req_stat;
+ u16 vda_req_sz;
+ #define RQ_SIZE_DEFAULT 0
+ u64 lba;
+ RQCALLBK aux_req_cb;
+ void *aux_req_cx;
+ u32 blk_len;
+ u32 max_blk_len;
+ union {
+ struct scsi_cmnd *cmd;
+ u8 *task_management_status_ptr;
+ };
+};
+
+struct esas2r_flash_context {
+ struct esas2r_flash_img *fi;
+ RQCALLBK interrupt_cb;
+ u8 *sgc_offset;
+ u8 *scratch;
+ u32 fi_hdr_len;
+ u8 task;
+ #define FMTSK_ERASE_BOOT 0
+ #define FMTSK_WRTBIOS 1
+ #define FMTSK_READBIOS 2
+ #define FMTSK_WRTMAC 3
+ #define FMTSK_READMAC 4
+ #define FMTSK_WRTEFI 5
+ #define FMTSK_READEFI 6
+ #define FMTSK_WRTCFG 7
+ #define FMTSK_READCFG 8
+ u8 func;
+ u16 num_comps;
+ u32 cmp_len;
+ u32 flsh_addr;
+ u32 curr_len;
+ u8 comp_typ;
+ struct esas2r_sg_context sgc;
+};
+
+struct esas2r_disc_context {
+ u8 disc_evt;
+ #define DCDE_DEV_CHANGE 0x01
+ #define DCDE_DEV_SCAN 0x02
+ u8 state;
+ #define DCS_DEV_RMV 0x00
+ #define DCS_DEV_ADD 0x01
+ #define DCS_BLOCK_DEV_SCAN 0x02
+ #define DCS_RAID_GRP_INFO 0x03
+ #define DCS_PART_INFO 0x04
+ #define DCS_PT_DEV_INFO 0x05
+ #define DCS_PT_DEV_ADDR 0x06
+ #define DCS_DISC_DONE 0xFF
+ u16 flags;
+ #define DCF_DEV_CHANGE 0x0001
+ #define DCF_DEV_SCAN 0x0002
+ #define DCF_POLLED 0x8000
+ u32 interleave;
+ u32 block_size;
+ u16 dev_ix;
+ u8 part_num;
+ u8 raid_grp_ix;
+ char raid_grp_name[16];
+ struct esas2r_target *curr_targ;
+ u16 curr_virt_id;
+ u16 curr_phys_id;
+ u8 scan_gen;
+ u8 dev_addr_type;
+ u64 sas_addr;
+};
+
+struct esas2r_mem_desc {
+ struct list_head next_desc;
+ void *virt_addr;
+ u64 phys_addr;
+ void *pad;
+ void *esas2r_data;
+ u32 esas2r_param;
+ u32 size;
+};
+
+enum fw_event_type {
+ fw_event_null,
+ fw_event_lun_change,
+ fw_event_present,
+ fw_event_not_present,
+ fw_event_vda_ae
+};
+
+struct esas2r_vda_ae {
+ u32 signature;
+#define ESAS2R_VDA_EVENT_SIG 0x4154544F
+ u8 bus_number;
+ u8 devfn;
+ u8 pad[2];
+ union atto_vda_ae vda_ae;
+};
+
+struct esas2r_fw_event_work {
+ struct list_head list;
+ struct delayed_work work;
+ struct esas2r_adapter *a;
+ enum fw_event_type type;
+ u8 data[sizeof(struct esas2r_vda_ae)];
+};
+
+enum state {
+ FW_INVALID_ST,
+ FW_STATUS_ST,
+ FW_COMMAND_ST
+};
+
+struct esas2r_firmware {
+ enum state state;
+ struct esas2r_flash_img header;
+ u8 *data;
+ u64 phys;
+ int orig_len;
+ void *header_buff;
+ u64 header_buff_phys;
+};
+
+struct esas2r_adapter {
+ struct esas2r_target targetdb[ESAS2R_MAX_TARGETS];
+ struct esas2r_target *targetdb_end;
+ unsigned char *regs;
+ unsigned char *data_window;
+ u32 volatile flags;
+ #define AF_PORT_CHANGE (u32)(0x00000001)
+ #define AF_CHPRST_NEEDED (u32)(0x00000004)
+ #define AF_CHPRST_PENDING (u32)(0x00000008)
+ #define AF_CHPRST_DETECTED (u32)(0x00000010)
+ #define AF_BUSRST_NEEDED (u32)(0x00000020)
+ #define AF_BUSRST_PENDING (u32)(0x00000040)
+ #define AF_BUSRST_DETECTED (u32)(0x00000080)
+ #define AF_DISABLED (u32)(0x00000100)
+ #define AF_FLASH_LOCK (u32)(0x00000200)
+ #define AF_OS_RESET (u32)(0x00002000)
+ #define AF_FLASHING (u32)(0x00004000)
+ #define AF_POWER_MGT (u32)(0x00008000)
+ #define AF_NVR_VALID (u32)(0x00010000)
+ #define AF_DEGRADED_MODE (u32)(0x00020000)
+ #define AF_DISC_PENDING (u32)(0x00040000)
+ #define AF_TASKLET_SCHEDULED (u32)(0x00080000)
+ #define AF_HEARTBEAT (u32)(0x00200000)
+ #define AF_HEARTBEAT_ENB (u32)(0x00400000)
+ #define AF_NOT_PRESENT (u32)(0x00800000)
+ #define AF_CHPRST_STARTED (u32)(0x01000000)
+ #define AF_FIRST_INIT (u32)(0x02000000)
+ #define AF_POWER_DOWN (u32)(0x04000000)
+ #define AF_DISC_IN_PROG (u32)(0x08000000)
+ #define AF_COMM_LIST_TOGGLE (u32)(0x10000000)
+ #define AF_LEGACY_SGE_MODE (u32)(0x20000000)
+ #define AF_DISC_POLLED (u32)(0x40000000)
+ u32 volatile flags2;
+ #define AF2_SERIAL_FLASH (u32)(0x00000001)
+ #define AF2_DEV_SCAN (u32)(0x00000002)
+ #define AF2_DEV_CNT_OK (u32)(0x00000004)
+ #define AF2_COREDUMP_AVAIL (u32)(0x00000008)
+ #define AF2_COREDUMP_SAVED (u32)(0x00000010)
+ #define AF2_VDA_POWER_DOWN (u32)(0x00000100)
+ #define AF2_THUNDERLINK (u32)(0x00000200)
+ #define AF2_THUNDERBOLT (u32)(0x00000400)
+ #define AF2_INIT_DONE (u32)(0x00000800)
+ #define AF2_INT_PENDING (u32)(0x00001000)
+ #define AF2_TIMER_TICK (u32)(0x00002000)
+ #define AF2_IRQ_CLAIMED (u32)(0x00004000)
+ #define AF2_MSI_ENABLED (u32)(0x00008000)
+ atomic_t disable_cnt;
+ atomic_t dis_ints_cnt;
+ u32 int_stat;
+ u32 int_mask;
+ u32 volatile *outbound_copy;
+ struct list_head avail_request;
+ spinlock_t request_lock;
+ spinlock_t sg_list_lock;
+ spinlock_t queue_lock;
+ spinlock_t mem_lock;
+ struct list_head free_sg_list_head;
+ struct esas2r_mem_desc *sg_list_mds;
+ struct list_head active_list;
+ struct list_head defer_list;
+ struct esas2r_request **req_table;
+ union {
+ u16 prev_dev_cnt;
+ u32 heartbeat_time;
+ #define ESAS2R_HEARTBEAT_TIME (3000)
+ };
+ u32 chip_uptime;
+ #define ESAS2R_CHP_UPTIME_MAX (60000)
+ #define ESAS2R_CHP_UPTIME_CNT (20000)
+ u64 uncached_phys;
+ u8 *uncached;
+ struct esas2r_sas_nvram *nvram;
+ struct esas2r_request general_req;
+ u8 init_msg;
+ #define ESAS2R_INIT_MSG_START 1
+ #define ESAS2R_INIT_MSG_INIT 2
+ #define ESAS2R_INIT_MSG_GET_INIT 3
+ #define ESAS2R_INIT_MSG_REINIT 4
+ u16 cmd_ref_no;
+ u32 fw_version;
+ u32 fw_build;
+ u32 chip_init_time;
+ #define ESAS2R_CHPRST_TIME (180000)
+ #define ESAS2R_CHPRST_WAIT_TIME (2000)
+ u32 last_tick_time;
+ u32 window_base;
+ RQBUILDSGL build_sgl;
+ struct esas2r_request *first_ae_req;
+ u32 list_size;
+ u32 last_write;
+ u32 last_read;
+ u16 max_vdareq_size;
+ u16 disc_wait_cnt;
+ struct esas2r_mem_desc inbound_list_md;
+ struct esas2r_mem_desc outbound_list_md;
+ struct esas2r_disc_context disc_ctx;
+ u8 *disc_buffer;
+ u32 disc_start_time;
+ u32 disc_wait_time;
+ u32 flash_ver;
+ char flash_rev[16];
+ char fw_rev[16];
+ char image_type[16];
+ struct esas2r_flash_context flash_context;
+ u32 num_targets_backend;
+ u32 ioctl_tunnel;
+ struct tasklet_struct tasklet;
+ struct pci_dev *pcid;
+ struct Scsi_Host *host;
+ unsigned int index;
+ char name[32];
+ struct timer_list timer;
+ struct esas2r_firmware firmware;
+ wait_queue_head_t nvram_waiter;
+ int nvram_command_done;
+ wait_queue_head_t fm_api_waiter;
+ int fm_api_command_done;
+ wait_queue_head_t vda_waiter;
+ int vda_command_done;
+ u8 *vda_buffer;
+ u64 ppvda_buffer;
+#define VDA_BUFFER_HEADER_SZ (offsetof(struct atto_ioctl_vda, data))
+#define VDA_MAX_BUFFER_SIZE (0x40000 + VDA_BUFFER_HEADER_SZ)
+ wait_queue_head_t fs_api_waiter;
+ int fs_api_command_done;
+ u64 ppfs_api_buffer;
+ u8 *fs_api_buffer;
+ u32 fs_api_buffer_size;
+ wait_queue_head_t buffered_ioctl_waiter;
+ int buffered_ioctl_done;
+ int uncached_size;
+ struct workqueue_struct *fw_event_q;
+ struct list_head fw_event_list;
+ spinlock_t fw_event_lock;
+ u8 fw_events_off; /* if '1', then ignore events */
+ char fw_event_q_name[ESAS2R_KOBJ_NAME_LEN];
+ /*
+ * intr_mode stores the interrupt mode currently being used by this
+ * adapter. it is based on the interrupt_mode module parameter, but
+ * can be changed based on the ability (or not) to utilize the
+ * mode requested by the parameter.
+ */
+ int intr_mode;
+#define INTR_MODE_LEGACY 0
+#define INTR_MODE_MSI 1
+#define INTR_MODE_MSIX 2
+ struct esas2r_sg_context fm_api_sgc;
+ u8 *save_offset;
+ struct list_head vrq_mds_head;
+ struct esas2r_mem_desc *vrq_mds;
+ int num_vrqs;
+ struct semaphore fm_api_semaphore;
+ struct semaphore fs_api_semaphore;
+ struct semaphore nvram_semaphore;
+ struct atto_ioctl *local_atto_ioctl;
+ u8 fw_coredump_buff[ESAS2R_FWCOREDUMP_SZ];
+ unsigned int sysfs_fw_created:1;
+ unsigned int sysfs_fs_created:1;
+ unsigned int sysfs_vda_created:1;
+ unsigned int sysfs_hw_created:1;
+ unsigned int sysfs_live_nvram_created:1;
+ unsigned int sysfs_default_nvram_created:1;
+};
+
+/*
+ * Function Declarations
+ * SCSI functions
+ */
+int esas2r_release(struct Scsi_Host *);
+const char *esas2r_info(struct Scsi_Host *);
+int esas2r_write_params(struct esas2r_adapter *a, struct esas2r_request *rq,
+ struct esas2r_sas_nvram *data);
+int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg);
+int esas2r_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
+u8 handle_hba_ioctl(struct esas2r_adapter *a,
+ struct atto_ioctl *ioctl_hba);
+int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd);
+int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh);
+int esas2r_slave_alloc(struct scsi_device *dev);
+int esas2r_slave_configure(struct scsi_device *dev);
+void esas2r_slave_destroy(struct scsi_device *dev);
+int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason);
+int esas2r_change_queue_type(struct scsi_device *dev, int type);
+long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg);
+
+/* SCSI error handler (eh) functions */
+int esas2r_eh_abort(struct scsi_cmnd *cmd);
+int esas2r_device_reset(struct scsi_cmnd *cmd);
+int esas2r_host_reset(struct scsi_cmnd *cmd);
+int esas2r_bus_reset(struct scsi_cmnd *cmd);
+int esas2r_target_reset(struct scsi_cmnd *cmd);
+
+/* Internal functions */
+int esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid,
+ int index);
+int esas2r_cleanup(struct Scsi_Host *host);
+int esas2r_read_fw(struct esas2r_adapter *a, char *buf, long off, int count);
+int esas2r_write_fw(struct esas2r_adapter *a, const char *buf, long off,
+ int count);
+int esas2r_read_vda(struct esas2r_adapter *a, char *buf, long off, int count);
+int esas2r_write_vda(struct esas2r_adapter *a, const char *buf, long off,
+ int count);
+int esas2r_read_fs(struct esas2r_adapter *a, char *buf, long off, int count);
+int esas2r_write_fs(struct esas2r_adapter *a, const char *buf, long off,
+ int count);
+void esas2r_adapter_tasklet(unsigned long context);
+irqreturn_t esas2r_interrupt(int irq, void *dev_id);
+irqreturn_t esas2r_msi_interrupt(int irq, void *dev_id);
+void esas2r_kickoff_timer(struct esas2r_adapter *a);
+int esas2r_suspend(struct pci_dev *pcid, pm_message_t state);
+int esas2r_resume(struct pci_dev *pcid);
+void esas2r_fw_event_off(struct esas2r_adapter *a);
+void esas2r_fw_event_on(struct esas2r_adapter *a);
+bool esas2r_nvram_write(struct esas2r_adapter *a, struct esas2r_request *rq,
+ struct esas2r_sas_nvram *nvram);
+void esas2r_nvram_get_defaults(struct esas2r_adapter *a,
+ struct esas2r_sas_nvram *nvram);
+void esas2r_complete_request_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+void esas2r_reset_detected(struct esas2r_adapter *a);
+void esas2r_target_state_changed(struct esas2r_adapter *ha, u16 targ_id,
+ u8 state);
+int esas2r_req_status_to_error(u8 req_stat);
+void esas2r_kill_adapter(int i);
+void esas2r_free_request(struct esas2r_adapter *a, struct esas2r_request *rq);
+struct esas2r_request *esas2r_alloc_request(struct esas2r_adapter *a);
+u32 esas2r_get_uncached_size(struct esas2r_adapter *a);
+bool esas2r_init_adapter_struct(struct esas2r_adapter *a,
+ void **uncached_area);
+bool esas2r_check_adapter(struct esas2r_adapter *a);
+bool esas2r_init_adapter_hw(struct esas2r_adapter *a, bool init_poll);
+void esas2r_start_request(struct esas2r_adapter *a, struct esas2r_request *rq);
+bool esas2r_send_task_mgmt(struct esas2r_adapter *a,
+ struct esas2r_request *rqaux, u8 task_mgt_func);
+void esas2r_do_tasklet_tasks(struct esas2r_adapter *a);
+void esas2r_adapter_interrupt(struct esas2r_adapter *a);
+void esas2r_do_deferred_processes(struct esas2r_adapter *a);
+void esas2r_reset_bus(struct esas2r_adapter *a);
+void esas2r_reset_adapter(struct esas2r_adapter *a);
+void esas2r_timer_tick(struct esas2r_adapter *a);
+const char *esas2r_get_model_name(struct esas2r_adapter *a);
+const char *esas2r_get_model_name_short(struct esas2r_adapter *a);
+u32 esas2r_stall_execution(struct esas2r_adapter *a, u32 start_time,
+ u32 *delay);
+void esas2r_build_flash_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ u8 sub_func,
+ u8 cksum,
+ u32 addr,
+ u32 length);
+void esas2r_build_mgt_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ u8 sub_func,
+ u8 scan_gen,
+ u16 dev_index,
+ u32 length,
+ void *data);
+void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq);
+void esas2r_build_cli_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ u32 length,
+ u32 cmd_rsp_len);
+void esas2r_build_ioctl_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ u32 length,
+ u8 sub_func);
+void esas2r_build_cfg_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ u8 sub_func,
+ u32 length,
+ void *data);
+void esas2r_power_down(struct esas2r_adapter *a);
+bool esas2r_power_up(struct esas2r_adapter *a, bool init_poll);
+void esas2r_wait_request(struct esas2r_adapter *a, struct esas2r_request *rq);
+u32 esas2r_map_data_window(struct esas2r_adapter *a, u32 addr_lo);
+bool esas2r_process_fs_ioctl(struct esas2r_adapter *a,
+ struct esas2r_ioctl_fs *fs,
+ struct esas2r_request *rq,
+ struct esas2r_sg_context *sgc);
+bool esas2r_read_flash_block(struct esas2r_adapter *a, void *to, u32 from,
+ u32 size);
+bool esas2r_read_mem_block(struct esas2r_adapter *a, void *to, u32 from,
+ u32 size);
+bool esas2r_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi,
+ struct esas2r_request *rq, struct esas2r_sg_context *sgc);
+void esas2r_force_interrupt(struct esas2r_adapter *a);
+void esas2r_local_start_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+void esas2r_process_adapter_reset(struct esas2r_adapter *a);
+void esas2r_complete_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+void esas2r_dummy_complete(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+void esas2r_ae_complete(struct esas2r_adapter *a, struct esas2r_request *rq);
+void esas2r_start_vda_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+bool esas2r_read_flash_rev(struct esas2r_adapter *a);
+bool esas2r_read_image_type(struct esas2r_adapter *a);
+bool esas2r_nvram_read_direct(struct esas2r_adapter *a);
+bool esas2r_nvram_validate(struct esas2r_adapter *a);
+void esas2r_nvram_set_defaults(struct esas2r_adapter *a);
+bool esas2r_print_flash_rev(struct esas2r_adapter *a);
+void esas2r_send_reset_ae(struct esas2r_adapter *a, bool pwr_mgt);
+bool esas2r_init_msgs(struct esas2r_adapter *a);
+bool esas2r_is_adapter_present(struct esas2r_adapter *a);
+void esas2r_nuxi_mgt_data(u8 function, void *data);
+void esas2r_nuxi_cfg_data(u8 function, void *data);
+void esas2r_nuxi_ae_data(union atto_vda_ae *ae);
+void esas2r_reset_chip(struct esas2r_adapter *a);
+void esas2r_log_request_failure(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+void esas2r_polled_interrupt(struct esas2r_adapter *a);
+bool esas2r_ioreq_aborted(struct esas2r_adapter *a, struct esas2r_request *rq,
+ u8 status);
+bool esas2r_build_sg_list_sge(struct esas2r_adapter *a,
+ struct esas2r_sg_context *sgc);
+bool esas2r_build_sg_list_prd(struct esas2r_adapter *a,
+ struct esas2r_sg_context *sgc);
+void esas2r_targ_db_initialize(struct esas2r_adapter *a);
+void esas2r_targ_db_remove_all(struct esas2r_adapter *a, bool notify);
+void esas2r_targ_db_report_changes(struct esas2r_adapter *a);
+struct esas2r_target *esas2r_targ_db_add_raid(struct esas2r_adapter *a,
+ struct esas2r_disc_context *dc);
+struct esas2r_target *esas2r_targ_db_add_pthru(struct esas2r_adapter *a,
+ struct esas2r_disc_context *dc,
+ u8 *ident,
+ u8 ident_len);
+void esas2r_targ_db_remove(struct esas2r_adapter *a, struct esas2r_target *t);
+struct esas2r_target *esas2r_targ_db_find_by_sas_addr(struct esas2r_adapter *a,
+ u64 *sas_addr);
+struct esas2r_target *esas2r_targ_db_find_by_ident(struct esas2r_adapter *a,
+ void *identifier,
+ u8 ident_len);
+u16 esas2r_targ_db_find_next_present(struct esas2r_adapter *a, u16 target_id);
+struct esas2r_target *esas2r_targ_db_find_by_virt_id(struct esas2r_adapter *a,
+ u16 virt_id);
+u16 esas2r_targ_db_get_tgt_cnt(struct esas2r_adapter *a);
+void esas2r_disc_initialize(struct esas2r_adapter *a);
+void esas2r_disc_start_waiting(struct esas2r_adapter *a);
+void esas2r_disc_check_for_work(struct esas2r_adapter *a);
+void esas2r_disc_check_complete(struct esas2r_adapter *a);
+void esas2r_disc_queue_event(struct esas2r_adapter *a, u8 disc_evt);
+bool esas2r_disc_start_port(struct esas2r_adapter *a);
+void esas2r_disc_local_start_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+bool esas2r_set_degraded_mode(struct esas2r_adapter *a, char *error_str);
+bool esas2r_process_vda_ioctl(struct esas2r_adapter *a,
+ struct atto_ioctl_vda *vi,
+ struct esas2r_request *rq,
+ struct esas2r_sg_context *sgc);
+void esas2r_queue_fw_event(struct esas2r_adapter *a,
+ enum fw_event_type type,
+ void *data,
+ int data_sz);
+
+/* Inline functions */
+static inline u32 esas2r_lock_set_flags(volatile u32 *flags, u32 bits)
+{
+ return test_and_set_bit(ilog2(bits), (volatile unsigned long *)flags);
+}
+
+static inline u32 esas2r_lock_clear_flags(volatile u32 *flags, u32 bits)
+{
+ return test_and_clear_bit(ilog2(bits),
+ (volatile unsigned long *)flags);
+}
+
+/* Allocate a chip scatter/gather list entry */
+static inline struct esas2r_mem_desc *esas2r_alloc_sgl(struct esas2r_adapter *a)
+{
+ unsigned long flags;
+ struct list_head *sgl;
+ struct esas2r_mem_desc *result = NULL;
+
+ spin_lock_irqsave(&a->sg_list_lock, flags);
+ if (likely(!list_empty(&a->free_sg_list_head))) {
+ sgl = a->free_sg_list_head.next;
+ result = list_entry(sgl, struct esas2r_mem_desc, next_desc);
+ list_del_init(sgl);
+ }
+ spin_unlock_irqrestore(&a->sg_list_lock, flags);
+
+ return result;
+}
+
+/* Initialize a scatter/gather context */
+static inline void esas2r_sgc_init(struct esas2r_sg_context *sgc,
+ struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ struct atto_vda_sge *first)
+{
+ sgc->adapter = a;
+ sgc->first_req = rq;
+
+ /*
+ * set the limit pointer such that an SGE pointer above this value
+ * would be the first one to overflow the SGL.
+ */
+ sgc->sge.a64.limit = (struct atto_vda_sge *)((u8 *)rq->vrq
+ + (sizeof(union
+ atto_vda_req) /
+ 8)
+ - sizeof(struct
+ atto_vda_sge));
+ if (first) {
+ sgc->sge.a64.last =
+ sgc->sge.a64.curr = first;
+ rq->vrq->scsi.sg_list_offset = (u8)
+ ((u8 *)first -
+ (u8 *)rq->vrq);
+ } else {
+ sgc->sge.a64.last =
+ sgc->sge.a64.curr = &rq->vrq->scsi.u.sge[0];
+ rq->vrq->scsi.sg_list_offset =
+ (u8)offsetof(struct atto_vda_scsi_req, u.sge);
+ }
+ sgc->sge.a64.chain = NULL;
+}
+
+static inline void esas2r_rq_init_request(struct esas2r_request *rq,
+ struct esas2r_adapter *a)
+{
+ union atto_vda_req *vrq = rq->vrq;
+ u32 handle;
+
+ INIT_LIST_HEAD(&rq->sg_table_head);
+ rq->data_buf = (void *)(vrq + 1);
+ rq->interrupt_cb = NULL;
+ rq->comp_cb = esas2r_complete_request_cb;
+ rq->flags = 0;
+ rq->timeout = 0;
+ rq->req_stat = RS_PENDING;
+ rq->req_type = RT_INI_REQ;
+
+ /* clear the outbound response */
+ rq->func_rsp.dwords[0] = 0;
+ rq->func_rsp.dwords[1] = 0;
+
+ /*
+ * clear the size of the VDA request. esas2r_build_sg_list() will
+ * only allow the size of the request to grow. there are some
+ * management requests that go through there twice and the second
+ * time through sets a smaller request size. if this is not modified
+ * at all we'll set it to the size of the entire VDA request.
+ */
+ rq->vda_req_sz = RQ_SIZE_DEFAULT;
+
+ /* req_table entry should be NULL at this point - if not, halt */
+
+ if (a->req_table[LOWORD(vrq->scsi.handle)])
+ esas2r_bugon();
+
+ /* fill in the table for this handle so we can get back to the
+ * request.
+ */
+ a->req_table[LOWORD(vrq->scsi.handle)] = rq;
+
+ /*
+ * add a reference number to the handle to make it unique (until it
+ * wraps of course) while preserving the upper word
+ */
+
+ handle = be32_to_cpu(vrq->scsi.handle) & 0xFFFF0000;
+ vrq->scsi.handle = cpu_to_be32(handle + a->cmd_ref_no++);
+
+ /*
+ * the following formats a SCSI request. the caller can override as
+ * necessary. clear_vda_request can be called to clear the VDA
+ * request for another type of request.
+ */
+ vrq->scsi.function = VDA_FUNC_SCSI;
+ vrq->scsi.sense_len = SENSE_DATA_SZ;
+
+ /* clear out sg_list_offset and chain_offset */
+ vrq->scsi.sg_list_offset = 0;
+ vrq->scsi.chain_offset = 0;
+ vrq->scsi.flags = 0;
+ vrq->scsi.reserved = 0;
+
+ /* set the sense buffer to be the data payload buffer */
+ vrq->scsi.ppsense_buf
+ = cpu_to_le64(rq->vrq_md->phys_addr +
+ sizeof(union atto_vda_req));
+}
+
+static inline void esas2r_rq_free_sg_lists(struct esas2r_request *rq,
+ struct esas2r_adapter *a)
+{
+ unsigned long flags;
+
+ if (list_empty(&rq->sg_table_head))
+ return;
+
+ spin_lock_irqsave(&a->sg_list_lock, flags);
+ list_splice_tail_init(&rq->sg_table_head, &a->free_sg_list_head);
+ spin_unlock_irqrestore(&a->sg_list_lock, flags);
+}
+
+static inline void esas2r_rq_destroy_request(struct esas2r_request *rq,
+ struct esas2r_adapter *a)
+
+{
+ esas2r_rq_free_sg_lists(rq, a);
+ a->req_table[LOWORD(rq->vrq->scsi.handle)] = NULL;
+ rq->data_buf = NULL;
+}
+
+static inline bool esas2r_is_tasklet_pending(struct esas2r_adapter *a)
+{
+ return (a->flags & (AF_BUSRST_NEEDED | AF_BUSRST_DETECTED
+ | AF_CHPRST_NEEDED | AF_CHPRST_DETECTED
+ | AF_PORT_CHANGE))
+ ? true : false;
+}
+
+/*
+ * Build the scatter/gather list for an I/O request according to the
+ * specifications placed in the esas2r_sg_context. The caller must initialize
+ * struct esas2r_sg_context prior to the initial call by calling
+ * esas2r_sgc_init()
+ */
+static inline bool esas2r_build_sg_list(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ struct esas2r_sg_context *sgc)
+{
+ if (unlikely(le32_to_cpu(rq->vrq->scsi.length) == 0))
+ return true;
+
+ return (*a->build_sgl)(a, sgc);
+}
+
+static inline void esas2r_disable_chip_interrupts(struct esas2r_adapter *a)
+{
+ if (atomic_inc_return(&a->dis_ints_cnt) == 1)
+ esas2r_write_register_dword(a, MU_INT_MASK_OUT,
+ ESAS2R_INT_DIS_MASK);
+}
+
+static inline void esas2r_enable_chip_interrupts(struct esas2r_adapter *a)
+{
+ if (atomic_dec_return(&a->dis_ints_cnt) == 0)
+ esas2r_write_register_dword(a, MU_INT_MASK_OUT,
+ ESAS2R_INT_ENB_MASK);
+}
+
+/* Schedule a TASKLET to perform non-interrupt tasks that may require delays
+ * or long completion times.
+ */
+static inline void esas2r_schedule_tasklet(struct esas2r_adapter *a)
+{
+ /* make sure we don't schedule twice */
+ if (!(esas2r_lock_set_flags(&a->flags, AF_TASKLET_SCHEDULED) &
+ ilog2(AF_TASKLET_SCHEDULED)))
+ tasklet_hi_schedule(&a->tasklet);
+}
+
+static inline void esas2r_enable_heartbeat(struct esas2r_adapter *a)
+{
+ if (!(a->flags & (AF_DEGRADED_MODE | AF_CHPRST_PENDING))
+ && (a->nvram->options2 & SASNVR2_HEARTBEAT))
+ esas2r_lock_set_flags(&a->flags, AF_HEARTBEAT_ENB);
+ else
+ esas2r_lock_clear_flags(&a->flags, AF_HEARTBEAT_ENB);
+}
+
+static inline void esas2r_disable_heartbeat(struct esas2r_adapter *a)
+{
+ esas2r_lock_clear_flags(&a->flags, AF_HEARTBEAT_ENB);
+ esas2r_lock_clear_flags(&a->flags, AF_HEARTBEAT);
+}
+
+/* Set the initial state for resetting the adapter on the next pass through
+ * esas2r_do_deferred.
+ */
+static inline void esas2r_local_reset_adapter(struct esas2r_adapter *a)
+{
+ esas2r_disable_heartbeat(a);
+
+ esas2r_lock_set_flags(&a->flags, AF_CHPRST_NEEDED);
+ esas2r_lock_set_flags(&a->flags, AF_CHPRST_PENDING);
+ esas2r_lock_set_flags(&a->flags, AF_DISC_PENDING);
+}
+
+/* See if an interrupt is pending on the adapter. */
+static inline bool esas2r_adapter_interrupt_pending(struct esas2r_adapter *a)
+{
+ u32 intstat;
+
+ if (a->int_mask == 0)
+ return false;
+
+ intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
+
+ if ((intstat & a->int_mask) == 0)
+ return false;
+
+ esas2r_disable_chip_interrupts(a);
+
+ a->int_stat = intstat;
+ a->int_mask = 0;
+
+ return true;
+}
+
+static inline u16 esas2r_targ_get_id(struct esas2r_target *t,
+ struct esas2r_adapter *a)
+{
+ return (u16)(uintptr_t)(t - a->targetdb);
+}
+
+/* Build and start an asynchronous event request */
+static inline void esas2r_start_ae_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ unsigned long flags;
+
+ esas2r_build_ae_req(a, rq);
+
+ spin_lock_irqsave(&a->queue_lock, flags);
+ esas2r_start_vda_request(a, rq);
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+}
+
+static inline void esas2r_comp_list_drain(struct esas2r_adapter *a,
+ struct list_head *comp_list)
+{
+ struct esas2r_request *rq;
+ struct list_head *element, *next;
+
+ list_for_each_safe(element, next, comp_list) {
+ rq = list_entry(element, struct esas2r_request, comp_list);
+ list_del_init(element);
+ esas2r_complete_request(a, rq);
+ }
+}
+
+/* sysfs handlers */
+extern struct bin_attribute bin_attr_fw;
+extern struct bin_attribute bin_attr_fs;
+extern struct bin_attribute bin_attr_vda;
+extern struct bin_attribute bin_attr_hw;
+extern struct bin_attribute bin_attr_live_nvram;
+extern struct bin_attribute bin_attr_default_nvram;
+
+#endif /* ESAS2R_H */
diff --git a/drivers/scsi/esas2r/esas2r_disc.c b/drivers/scsi/esas2r/esas2r_disc.c
new file mode 100644
index 00000000000..dec6c334ce3
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_disc.c
@@ -0,0 +1,1189 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r_disc.c
+ * esas2r device discovery routines
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "esas2r.h"
+
+/* Miscellaneous internal discovery routines */
+static void esas2r_disc_abort(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static bool esas2r_disc_continue(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static void esas2r_disc_fix_curr_requests(struct esas2r_adapter *a);
+static u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr);
+static bool esas2r_disc_start_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+
+/* Internal discovery routines that process the states */
+static bool esas2r_disc_block_dev_scan(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static void esas2r_disc_block_dev_scan_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static bool esas2r_disc_dev_add(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static bool esas2r_disc_dev_remove(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static bool esas2r_disc_part_info(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static void esas2r_disc_part_info_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static bool esas2r_disc_passthru_dev_info(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static void esas2r_disc_passthru_dev_info_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static bool esas2r_disc_passthru_dev_addr(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static void esas2r_disc_passthru_dev_addr_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static bool esas2r_disc_raid_grp_info(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+static void esas2r_disc_raid_grp_info_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+
+void esas2r_disc_initialize(struct esas2r_adapter *a)
+{
+ struct esas2r_sas_nvram *nvr = a->nvram;
+
+ esas2r_trace_enter();
+
+ esas2r_lock_clear_flags(&a->flags, AF_DISC_IN_PROG);
+ esas2r_lock_clear_flags(&a->flags2, AF2_DEV_SCAN);
+ esas2r_lock_clear_flags(&a->flags2, AF2_DEV_CNT_OK);
+
+ a->disc_start_time = jiffies_to_msecs(jiffies);
+ a->disc_wait_time = nvr->dev_wait_time * 1000;
+ a->disc_wait_cnt = nvr->dev_wait_count;
+
+ if (a->disc_wait_cnt > ESAS2R_MAX_TARGETS)
+ a->disc_wait_cnt = ESAS2R_MAX_TARGETS;
+
+ /*
+ * If we are doing chip reset or power management processing, always
+ * wait for devices. use the NVRAM device count if it is greater than
+ * previously discovered devices.
+ */
+
+ esas2r_hdebug("starting discovery...");
+
+ a->general_req.interrupt_cx = NULL;
+
+ if (a->flags & (AF_CHPRST_DETECTED | AF_POWER_MGT)) {
+ if (a->prev_dev_cnt == 0) {
+ /* Don't bother waiting if there is nothing to wait
+ * for.
+ */
+ a->disc_wait_time = 0;
+ } else {
+ /*
+ * Set the device wait count to what was previously
+ * found. We don't care if the user only configured
+ * a time because we know the exact count to wait for.
+ * There is no need to honor the user's wishes to
+ * always wait the full time.
+ */
+ a->disc_wait_cnt = a->prev_dev_cnt;
+
+ /*
+ * bump the minimum wait time to 15 seconds since the
+ * default is 3 (system boot or the boot driver usually
+ * buys us more time).
+ */
+ if (a->disc_wait_time < 15000)
+ a->disc_wait_time = 15000;
+ }
+ }
+
+ esas2r_trace("disc wait count: %d", a->disc_wait_cnt);
+ esas2r_trace("disc wait time: %d", a->disc_wait_time);
+
+ if (a->disc_wait_time == 0)
+ esas2r_disc_check_complete(a);
+
+ esas2r_trace_exit();
+}
+
+void esas2r_disc_start_waiting(struct esas2r_adapter *a)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&a->mem_lock, flags);
+
+ if (a->disc_ctx.disc_evt)
+ esas2r_disc_start_port(a);
+
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+}
+
+void esas2r_disc_check_for_work(struct esas2r_adapter *a)
+{
+ struct esas2r_request *rq = &a->general_req;
+
+ /* service any pending interrupts first */
+
+ esas2r_polled_interrupt(a);
+
+ /*
+ * now, interrupt processing may have queued up a discovery event. go
+ * see if we have one to start. we couldn't start it in the ISR since
+ * polled discovery would cause a deadlock.
+ */
+
+ esas2r_disc_start_waiting(a);
+
+ if (rq->interrupt_cx == NULL)
+ return;
+
+ if (rq->req_stat == RS_STARTED
+ && rq->timeout <= RQ_MAX_TIMEOUT) {
+ /* wait for the current discovery request to complete. */
+ esas2r_wait_request(a, rq);
+
+ if (rq->req_stat == RS_TIMEOUT) {
+ esas2r_disc_abort(a, rq);
+ esas2r_local_reset_adapter(a);
+ return;
+ }
+ }
+
+ if (rq->req_stat == RS_PENDING
+ || rq->req_stat == RS_STARTED)
+ return;
+
+ esas2r_disc_continue(a, rq);
+}
+
+void esas2r_disc_check_complete(struct esas2r_adapter *a)
+{
+ unsigned long flags;
+
+ esas2r_trace_enter();
+
+ /* check to see if we should be waiting for devices */
+ if (a->disc_wait_time) {
+ u32 currtime = jiffies_to_msecs(jiffies);
+ u32 time = currtime - a->disc_start_time;
+
+ /*
+ * Wait until the device wait time is exhausted or the device
+ * wait count is satisfied.
+ */
+ if (time < a->disc_wait_time
+ && (esas2r_targ_db_get_tgt_cnt(a) < a->disc_wait_cnt
+ || a->disc_wait_cnt == 0)) {
+ /* After three seconds of waiting, schedule a scan. */
+ if (time >= 3000
+ && !(esas2r_lock_set_flags(&a->flags2,
+ AF2_DEV_SCAN) &
+ ilog2(AF2_DEV_SCAN))) {
+ spin_lock_irqsave(&a->mem_lock, flags);
+ esas2r_disc_queue_event(a, DCDE_DEV_SCAN);
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+ }
+
+ esas2r_trace_exit();
+ return;
+ }
+
+ /*
+ * We are done waiting...we think. Adjust the wait time to
+ * consume events after the count is met.
+ */
+ if (!(esas2r_lock_set_flags(&a->flags2, AF2_DEV_CNT_OK)
+ & ilog2(AF2_DEV_CNT_OK)))
+ a->disc_wait_time = time + 3000;
+
+ /* If we haven't done a full scan yet, do it now. */
+ if (!(esas2r_lock_set_flags(&a->flags2,
+ AF2_DEV_SCAN) &
+ ilog2(AF2_DEV_SCAN))) {
+ spin_lock_irqsave(&a->mem_lock, flags);
+ esas2r_disc_queue_event(a, DCDE_DEV_SCAN);
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+
+ esas2r_trace_exit();
+ return;
+ }
+
+ /*
+ * Now, if there is still time left to consume events, continue
+ * waiting.
+ */
+ if (time < a->disc_wait_time) {
+ esas2r_trace_exit();
+ return;
+ }
+ } else {
+ if (!(esas2r_lock_set_flags(&a->flags2,
+ AF2_DEV_SCAN) &
+ ilog2(AF2_DEV_SCAN))) {
+ spin_lock_irqsave(&a->mem_lock, flags);
+ esas2r_disc_queue_event(a, DCDE_DEV_SCAN);
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+ }
+ }
+
+ /* We want to stop waiting for devices. */
+ a->disc_wait_time = 0;
+
+ if ((a->flags & AF_DISC_POLLED)
+ && (a->flags & AF_DISC_IN_PROG)) {
+ /*
+ * Polled discovery is still pending so continue the active
+ * discovery until it is done. At that point, we will stop
+ * polled discovery and transition to interrupt driven
+ * discovery.
+ */
+ } else {
+ /*
+ * Done waiting for devices. Note that we get here immediately
+ * after deferred waiting completes because that is interrupt
+ * driven; i.e. There is no transition.
+ */
+ esas2r_disc_fix_curr_requests(a);
+ esas2r_lock_clear_flags(&a->flags, AF_DISC_PENDING);
+
+ /*
+ * We have deferred target state changes until now because we
+ * don't want to report any removals (due to the first arrival)
+ * until the device wait time expires.
+ */
+ esas2r_lock_set_flags(&a->flags, AF_PORT_CHANGE);
+ }
+
+ esas2r_trace_exit();
+}
+
+void esas2r_disc_queue_event(struct esas2r_adapter *a, u8 disc_evt)
+{
+ struct esas2r_disc_context *dc = &a->disc_ctx;
+
+ esas2r_trace_enter();
+
+ esas2r_trace("disc_event: %d", disc_evt);
+
+ /* Initialize the discovery context */
+ dc->disc_evt |= disc_evt;
+
+ /*
+ * Don't start discovery before or during polled discovery. if we did,
+ * we would have a deadlock if we are in the ISR already.
+ */
+ if (!(a->flags & (AF_CHPRST_PENDING | AF_DISC_POLLED)))
+ esas2r_disc_start_port(a);
+
+ esas2r_trace_exit();
+}
+
+bool esas2r_disc_start_port(struct esas2r_adapter *a)
+{
+ struct esas2r_request *rq = &a->general_req;
+ struct esas2r_disc_context *dc = &a->disc_ctx;
+ bool ret;
+
+ esas2r_trace_enter();
+
+ if (a->flags & AF_DISC_IN_PROG) {
+ esas2r_trace_exit();
+
+ return false;
+ }
+
+ /* If there is a discovery waiting, process it. */
+ if (dc->disc_evt) {
+ if ((a->flags & AF_DISC_POLLED)
+ && a->disc_wait_time == 0) {
+ /*
+ * We are doing polled discovery, but we no longer want
+ * to wait for devices. Stop polled discovery and
+ * transition to interrupt driven discovery.
+ */
+
+ esas2r_trace_exit();
+
+ return false;
+ }
+ } else {
+ /* Discovery is complete. */
+
+ esas2r_hdebug("disc done");
+
+ esas2r_lock_set_flags(&a->flags, AF_PORT_CHANGE);
+
+ esas2r_trace_exit();
+
+ return false;
+ }
+
+ /* Handle the discovery context */
+ esas2r_trace("disc_evt: %d", dc->disc_evt);
+ esas2r_lock_set_flags(&a->flags, AF_DISC_IN_PROG);
+ dc->flags = 0;
+
+ if (a->flags & AF_DISC_POLLED)
+ dc->flags |= DCF_POLLED;
+
+ rq->interrupt_cx = dc;
+ rq->req_stat = RS_SUCCESS;
+
+ /* Decode the event code */
+ if (dc->disc_evt & DCDE_DEV_SCAN) {
+ dc->disc_evt &= ~DCDE_DEV_SCAN;
+
+ dc->flags |= DCF_DEV_SCAN;
+ dc->state = DCS_BLOCK_DEV_SCAN;
+ } else if (dc->disc_evt & DCDE_DEV_CHANGE) {
+ dc->disc_evt &= ~DCDE_DEV_CHANGE;
+
+ dc->flags |= DCF_DEV_CHANGE;
+ dc->state = DCS_DEV_RMV;
+ }
+
+ /* Continue interrupt driven discovery */
+ if (!(a->flags & AF_DISC_POLLED))
+ ret = esas2r_disc_continue(a, rq);
+ else
+ ret = true;
+
+ esas2r_trace_exit();
+
+ return ret;
+}
+
+static bool esas2r_disc_continue(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ bool rslt;
+
+ /* Device discovery/removal */
+ while (dc->flags & (DCF_DEV_CHANGE | DCF_DEV_SCAN)) {
+ rslt = false;
+
+ switch (dc->state) {
+ case DCS_DEV_RMV:
+
+ rslt = esas2r_disc_dev_remove(a, rq);
+ break;
+
+ case DCS_DEV_ADD:
+
+ rslt = esas2r_disc_dev_add(a, rq);
+ break;
+
+ case DCS_BLOCK_DEV_SCAN:
+
+ rslt = esas2r_disc_block_dev_scan(a, rq);
+ break;
+
+ case DCS_RAID_GRP_INFO:
+
+ rslt = esas2r_disc_raid_grp_info(a, rq);
+ break;
+
+ case DCS_PART_INFO:
+
+ rslt = esas2r_disc_part_info(a, rq);
+ break;
+
+ case DCS_PT_DEV_INFO:
+
+ rslt = esas2r_disc_passthru_dev_info(a, rq);
+ break;
+ case DCS_PT_DEV_ADDR:
+
+ rslt = esas2r_disc_passthru_dev_addr(a, rq);
+ break;
+ case DCS_DISC_DONE:
+
+ dc->flags &= ~(DCF_DEV_CHANGE | DCF_DEV_SCAN);
+ break;
+
+ default:
+
+ esas2r_bugon();
+ dc->state = DCS_DISC_DONE;
+ break;
+ }
+
+ if (rslt)
+ return true;
+ }
+
+ /* Discovery is done...for now. */
+ rq->interrupt_cx = NULL;
+
+ if (!(a->flags & AF_DISC_PENDING))
+ esas2r_disc_fix_curr_requests(a);
+
+ esas2r_lock_clear_flags(&a->flags, AF_DISC_IN_PROG);
+
+ /* Start the next discovery. */
+ return esas2r_disc_start_port(a);
+}
+
+static bool esas2r_disc_start_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ unsigned long flags;
+
+ /* Set the timeout to a minimum value. */
+ if (rq->timeout < ESAS2R_DEFAULT_TMO)
+ rq->timeout = ESAS2R_DEFAULT_TMO;
+
+ /*
+ * Override the request type to distinguish discovery requests. If we
+ * end up deferring the request, esas2r_disc_local_start_request()
+ * will be called to restart it.
+ */
+ rq->req_type = RT_DISC_REQ;
+
+ spin_lock_irqsave(&a->queue_lock, flags);
+
+ if (!(a->flags & (AF_CHPRST_PENDING | AF_FLASHING)))
+ esas2r_disc_local_start_request(a, rq);
+ else
+ list_add_tail(&rq->req_list, &a->defer_list);
+
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+
+ return true;
+}
+
+void esas2r_disc_local_start_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ esas2r_trace_enter();
+
+ list_add_tail(&rq->req_list, &a->active_list);
+
+ esas2r_start_vda_request(a, rq);
+
+ esas2r_trace_exit();
+
+ return;
+}
+
+static void esas2r_disc_abort(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+
+ esas2r_trace_enter();
+
+ /* abort the current discovery */
+
+ dc->state = DCS_DISC_DONE;
+
+ esas2r_trace_exit();
+}
+
+static bool esas2r_disc_block_dev_scan(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ bool rslt;
+
+ esas2r_trace_enter();
+
+ esas2r_rq_init_request(rq, a);
+
+ esas2r_build_mgt_req(a,
+ rq,
+ VDAMGT_DEV_SCAN,
+ 0,
+ 0,
+ 0,
+ NULL);
+
+ rq->comp_cb = esas2r_disc_block_dev_scan_cb;
+
+ rq->timeout = 30000;
+ rq->interrupt_cx = dc;
+
+ rslt = esas2r_disc_start_request(a, rq);
+
+ esas2r_trace_exit();
+
+ return rslt;
+}
+
+static void esas2r_disc_block_dev_scan_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ unsigned long flags;
+
+ esas2r_trace_enter();
+
+ spin_lock_irqsave(&a->mem_lock, flags);
+
+ if (rq->req_stat == RS_SUCCESS)
+ dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
+
+ dc->state = DCS_RAID_GRP_INFO;
+ dc->raid_grp_ix = 0;
+
+ esas2r_rq_destroy_request(rq, a);
+
+ /* continue discovery if it's interrupt driven */
+
+ if (!(dc->flags & DCF_POLLED))
+ esas2r_disc_continue(a, rq);
+
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+
+ esas2r_trace_exit();
+}
+
+static bool esas2r_disc_raid_grp_info(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ bool rslt;
+ struct atto_vda_grp_info *grpinfo;
+
+ esas2r_trace_enter();
+
+ esas2r_trace("raid_group_idx: %d", dc->raid_grp_ix);
+
+ if (dc->raid_grp_ix >= VDA_MAX_RAID_GROUPS) {
+ dc->state = DCS_DISC_DONE;
+
+ esas2r_trace_exit();
+
+ return false;
+ }
+
+ esas2r_rq_init_request(rq, a);
+
+ grpinfo = &rq->vda_rsp_data->mgt_data.data.grp_info;
+
+ memset(grpinfo, 0, sizeof(struct atto_vda_grp_info));
+
+ esas2r_build_mgt_req(a,
+ rq,
+ VDAMGT_GRP_INFO,
+ dc->scan_gen,
+ 0,
+ sizeof(struct atto_vda_grp_info),
+ NULL);
+
+ grpinfo->grp_index = dc->raid_grp_ix;
+
+ rq->comp_cb = esas2r_disc_raid_grp_info_cb;
+
+ rq->interrupt_cx = dc;
+
+ rslt = esas2r_disc_start_request(a, rq);
+
+ esas2r_trace_exit();
+
+ return rslt;
+}
+
+static void esas2r_disc_raid_grp_info_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ unsigned long flags;
+ struct atto_vda_grp_info *grpinfo;
+
+ esas2r_trace_enter();
+
+ spin_lock_irqsave(&a->mem_lock, flags);
+
+ if (rq->req_stat == RS_SCAN_GEN) {
+ dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
+ dc->raid_grp_ix = 0;
+ goto done;
+ }
+
+ if (rq->req_stat == RS_SUCCESS) {
+ grpinfo = &rq->vda_rsp_data->mgt_data.data.grp_info;
+
+ if (grpinfo->status != VDA_GRP_STAT_ONLINE
+ && grpinfo->status != VDA_GRP_STAT_DEGRADED) {
+ /* go to the next group. */
+
+ dc->raid_grp_ix++;
+ } else {
+ memcpy(&dc->raid_grp_name[0],
+ &grpinfo->grp_name[0],
+ sizeof(grpinfo->grp_name));
+
+ dc->interleave = le32_to_cpu(grpinfo->interleave);
+ dc->block_size = le32_to_cpu(grpinfo->block_size);
+
+ dc->state = DCS_PART_INFO;
+ dc->part_num = 0;
+ }
+ } else {
+ if (!(rq->req_stat == RS_GRP_INVALID)) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "A request for RAID group info failed - "
+ "returned with %x",
+ rq->req_stat);
+ }
+
+ dc->dev_ix = 0;
+ dc->state = DCS_PT_DEV_INFO;
+ }
+
+done:
+
+ esas2r_rq_destroy_request(rq, a);
+
+ /* continue discovery if it's interrupt driven */
+
+ if (!(dc->flags & DCF_POLLED))
+ esas2r_disc_continue(a, rq);
+
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+
+ esas2r_trace_exit();
+}
+
+static bool esas2r_disc_part_info(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ bool rslt;
+ struct atto_vdapart_info *partinfo;
+
+ esas2r_trace_enter();
+
+ esas2r_trace("part_num: %d", dc->part_num);
+
+ if (dc->part_num >= VDA_MAX_PARTITIONS) {
+ dc->state = DCS_RAID_GRP_INFO;
+ dc->raid_grp_ix++;
+
+ esas2r_trace_exit();
+
+ return false;
+ }
+
+ esas2r_rq_init_request(rq, a);
+
+ partinfo = &rq->vda_rsp_data->mgt_data.data.part_info;
+
+ memset(partinfo, 0, sizeof(struct atto_vdapart_info));
+
+ esas2r_build_mgt_req(a,
+ rq,
+ VDAMGT_PART_INFO,
+ dc->scan_gen,
+ 0,
+ sizeof(struct atto_vdapart_info),
+ NULL);
+
+ partinfo->part_no = dc->part_num;
+
+ memcpy(&partinfo->grp_name[0],
+ &dc->raid_grp_name[0],
+ sizeof(partinfo->grp_name));
+
+ rq->comp_cb = esas2r_disc_part_info_cb;
+
+ rq->interrupt_cx = dc;
+
+ rslt = esas2r_disc_start_request(a, rq);
+
+ esas2r_trace_exit();
+
+ return rslt;
+}
+
+static void esas2r_disc_part_info_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ unsigned long flags;
+ struct atto_vdapart_info *partinfo;
+
+ esas2r_trace_enter();
+
+ spin_lock_irqsave(&a->mem_lock, flags);
+
+ if (rq->req_stat == RS_SCAN_GEN) {
+ dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
+ dc->raid_grp_ix = 0;
+ dc->state = DCS_RAID_GRP_INFO;
+ } else if (rq->req_stat == RS_SUCCESS) {
+ partinfo = &rq->vda_rsp_data->mgt_data.data.part_info;
+
+ dc->part_num = partinfo->part_no;
+
+ dc->curr_virt_id = le16_to_cpu(partinfo->target_id);
+
+ esas2r_targ_db_add_raid(a, dc);
+
+ dc->part_num++;
+ } else {
+ if (!(rq->req_stat == RS_PART_LAST)) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "A request for RAID group partition info "
+ "failed - status:%d", rq->req_stat);
+ }
+
+ dc->state = DCS_RAID_GRP_INFO;
+ dc->raid_grp_ix++;
+ }
+
+ esas2r_rq_destroy_request(rq, a);
+
+ /* continue discovery if it's interrupt driven */
+
+ if (!(dc->flags & DCF_POLLED))
+ esas2r_disc_continue(a, rq);
+
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+
+ esas2r_trace_exit();
+}
+
+static bool esas2r_disc_passthru_dev_info(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ bool rslt;
+ struct atto_vda_devinfo *devinfo;
+
+ esas2r_trace_enter();
+
+ esas2r_trace("dev_ix: %d", dc->dev_ix);
+
+ esas2r_rq_init_request(rq, a);
+
+ devinfo = &rq->vda_rsp_data->mgt_data.data.dev_info;
+
+ memset(devinfo, 0, sizeof(struct atto_vda_devinfo));
+
+ esas2r_build_mgt_req(a,
+ rq,
+ VDAMGT_DEV_PT_INFO,
+ dc->scan_gen,
+ dc->dev_ix,
+ sizeof(struct atto_vda_devinfo),
+ NULL);
+
+ rq->comp_cb = esas2r_disc_passthru_dev_info_cb;
+
+ rq->interrupt_cx = dc;
+
+ rslt = esas2r_disc_start_request(a, rq);
+
+ esas2r_trace_exit();
+
+ return rslt;
+}
+
+static void esas2r_disc_passthru_dev_info_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ unsigned long flags;
+ struct atto_vda_devinfo *devinfo;
+
+ esas2r_trace_enter();
+
+ spin_lock_irqsave(&a->mem_lock, flags);
+
+ if (rq->req_stat == RS_SCAN_GEN) {
+ dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
+ dc->dev_ix = 0;
+ dc->state = DCS_PT_DEV_INFO;
+ } else if (rq->req_stat == RS_SUCCESS) {
+ devinfo = &rq->vda_rsp_data->mgt_data.data.dev_info;
+
+ dc->dev_ix = le16_to_cpu(rq->func_rsp.mgt_rsp.dev_index);
+
+ dc->curr_virt_id = le16_to_cpu(devinfo->target_id);
+
+ if (le16_to_cpu(devinfo->features) & VDADEVFEAT_PHYS_ID) {
+ dc->curr_phys_id =
+ le16_to_cpu(devinfo->phys_target_id);
+ dc->dev_addr_type = ATTO_GDA_AT_PORT;
+ dc->state = DCS_PT_DEV_ADDR;
+
+ esas2r_trace("curr_virt_id: %d", dc->curr_virt_id);
+ esas2r_trace("curr_phys_id: %d", dc->curr_phys_id);
+ } else {
+ dc->dev_ix++;
+ }
+ } else {
+ if (!(rq->req_stat == RS_DEV_INVALID)) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "A request for device information failed - "
+ "status:%d", rq->req_stat);
+ }
+
+ dc->state = DCS_DISC_DONE;
+ }
+
+ esas2r_rq_destroy_request(rq, a);
+
+ /* continue discovery if it's interrupt driven */
+
+ if (!(dc->flags & DCF_POLLED))
+ esas2r_disc_continue(a, rq);
+
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+
+ esas2r_trace_exit();
+}
+
+static bool esas2r_disc_passthru_dev_addr(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ bool rslt;
+ struct atto_ioctl *hi;
+ struct esas2r_sg_context sgc;
+
+ esas2r_trace_enter();
+
+ esas2r_rq_init_request(rq, a);
+
+ /* format the request. */
+
+ sgc.cur_offset = NULL;
+ sgc.get_phys_addr = (PGETPHYSADDR)esas2r_disc_get_phys_addr;
+ sgc.length = offsetof(struct atto_ioctl, data)
+ + sizeof(struct atto_hba_get_device_address);
+
+ esas2r_sgc_init(&sgc, a, rq, rq->vrq->ioctl.sge);
+
+ esas2r_build_ioctl_req(a, rq, sgc.length, VDA_IOCTL_HBA);
+
+ if (!esas2r_build_sg_list(a, rq, &sgc)) {
+ esas2r_rq_destroy_request(rq, a);
+
+ esas2r_trace_exit();
+
+ return false;
+ }
+
+ rq->comp_cb = esas2r_disc_passthru_dev_addr_cb;
+
+ rq->interrupt_cx = dc;
+
+ /* format the IOCTL data. */
+
+ hi = (struct atto_ioctl *)a->disc_buffer;
+
+ memset(a->disc_buffer, 0, ESAS2R_DISC_BUF_LEN);
+
+ hi->version = ATTO_VER_GET_DEV_ADDR0;
+ hi->function = ATTO_FUNC_GET_DEV_ADDR;
+ hi->flags = HBAF_TUNNEL;
+
+ hi->data.get_dev_addr.target_id = le32_to_cpu(dc->curr_phys_id);
+ hi->data.get_dev_addr.addr_type = dc->dev_addr_type;
+
+ /* start it up. */
+
+ rslt = esas2r_disc_start_request(a, rq);
+
+ esas2r_trace_exit();
+
+ return rslt;
+}
+
+static void esas2r_disc_passthru_dev_addr_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ struct esas2r_target *t = NULL;
+ unsigned long flags;
+ struct atto_ioctl *hi;
+ u16 addrlen;
+
+ esas2r_trace_enter();
+
+ spin_lock_irqsave(&a->mem_lock, flags);
+
+ hi = (struct atto_ioctl *)a->disc_buffer;
+
+ if (rq->req_stat == RS_SUCCESS
+ && hi->status == ATTO_STS_SUCCESS) {
+ addrlen = le16_to_cpu(hi->data.get_dev_addr.addr_len);
+
+ if (dc->dev_addr_type == ATTO_GDA_AT_PORT) {
+ if (addrlen == sizeof(u64))
+ memcpy(&dc->sas_addr,
+ &hi->data.get_dev_addr.address[0],
+ addrlen);
+ else
+ memset(&dc->sas_addr, 0, sizeof(dc->sas_addr));
+
+ /* Get the unique identifier. */
+ dc->dev_addr_type = ATTO_GDA_AT_UNIQUE;
+
+ goto next_dev_addr;
+ } else {
+ /* Add the pass through target. */
+ if (HIBYTE(addrlen) == 0) {
+ t = esas2r_targ_db_add_pthru(a,
+ dc,
+ &hi->data.
+ get_dev_addr.
+ address[0],
+ (u8)hi->data.
+ get_dev_addr.
+ addr_len);
+
+ if (t)
+ memcpy(&t->sas_addr, &dc->sas_addr,
+ sizeof(t->sas_addr));
+ } else {
+ /* getting the back end data failed */
+
+ esas2r_log(ESAS2R_LOG_WARN,
+ "an error occurred retrieving the "
+ "back end data (%s:%d)",
+ __func__,
+ __LINE__);
+ }
+ }
+ } else {
+ /* getting the back end data failed */
+
+ esas2r_log(ESAS2R_LOG_WARN,
+ "an error occurred retrieving the back end data - "
+ "rq->req_stat:%d hi->status:%d",
+ rq->req_stat, hi->status);
+ }
+
+ /* proceed to the next device. */
+
+ if (dc->flags & DCF_DEV_SCAN) {
+ dc->dev_ix++;
+ dc->state = DCS_PT_DEV_INFO;
+ } else if (dc->flags & DCF_DEV_CHANGE) {
+ dc->curr_targ++;
+ dc->state = DCS_DEV_ADD;
+ } else {
+ esas2r_bugon();
+ }
+
+next_dev_addr:
+ esas2r_rq_destroy_request(rq, a);
+
+ /* continue discovery if it's interrupt driven */
+
+ if (!(dc->flags & DCF_POLLED))
+ esas2r_disc_continue(a, rq);
+
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+
+ esas2r_trace_exit();
+}
+
+static u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr)
+{
+ struct esas2r_adapter *a = sgc->adapter;
+
+ if (sgc->length > ESAS2R_DISC_BUF_LEN)
+ esas2r_bugon();
+
+ *addr = a->uncached_phys
+ + (u64)((u8 *)a->disc_buffer - a->uncached);
+
+ return sgc->length;
+}
+
+static bool esas2r_disc_dev_remove(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ struct esas2r_target *t;
+ struct esas2r_target *t2;
+
+ esas2r_trace_enter();
+
+ /* process removals. */
+
+ for (t = a->targetdb; t < a->targetdb_end; t++) {
+ if (t->new_target_state != TS_NOT_PRESENT)
+ continue;
+
+ t->new_target_state = TS_INVALID;
+
+ /* remove the right target! */
+
+ t2 =
+ esas2r_targ_db_find_by_virt_id(a,
+ esas2r_targ_get_id(t,
+ a));
+
+ if (t2)
+ esas2r_targ_db_remove(a, t2);
+ }
+
+ /* removals complete. process arrivals. */
+
+ dc->state = DCS_DEV_ADD;
+ dc->curr_targ = a->targetdb;
+
+ esas2r_trace_exit();
+
+ return false;
+}
+
+static bool esas2r_disc_dev_add(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_disc_context *dc =
+ (struct esas2r_disc_context *)rq->interrupt_cx;
+ struct esas2r_target *t = dc->curr_targ;
+
+ if (t >= a->targetdb_end) {
+ /* done processing state changes. */
+
+ dc->state = DCS_DISC_DONE;
+ } else if (t->new_target_state == TS_PRESENT) {
+ struct atto_vda_ae_lu *luevt = &t->lu_event;
+
+ esas2r_trace_enter();
+
+ /* clear this now in case more events come in. */
+
+ t->new_target_state = TS_INVALID;
+
+ /* setup the discovery context for adding this device. */
+
+ dc->curr_virt_id = esas2r_targ_get_id(t, a);
+
+ if ((luevt->hdr.bylength >= offsetof(struct atto_vda_ae_lu, id)
+ + sizeof(struct atto_vda_ae_lu_tgt_lun_raid))
+ && !(luevt->dwevent & VDAAE_LU_PASSTHROUGH)) {
+ dc->block_size = luevt->id.tgtlun_raid.dwblock_size;
+ dc->interleave = luevt->id.tgtlun_raid.dwinterleave;
+ } else {
+ dc->block_size = 0;
+ dc->interleave = 0;
+ }
+
+ /* determine the device type being added. */
+
+ if (luevt->dwevent & VDAAE_LU_PASSTHROUGH) {
+ if (luevt->dwevent & VDAAE_LU_PHYS_ID) {
+ dc->state = DCS_PT_DEV_ADDR;
+ dc->dev_addr_type = ATTO_GDA_AT_PORT;
+ dc->curr_phys_id = luevt->wphys_target_id;
+ } else {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "luevt->dwevent does not have the "
+ "VDAAE_LU_PHYS_ID bit set (%s:%d)",
+ __func__, __LINE__);
+ }
+ } else {
+ dc->raid_grp_name[0] = 0;
+
+ esas2r_targ_db_add_raid(a, dc);
+ }
+
+ esas2r_trace("curr_virt_id: %d", dc->curr_virt_id);
+ esas2r_trace("curr_phys_id: %d", dc->curr_phys_id);
+ esas2r_trace("dwevent: %d", luevt->dwevent);
+
+ esas2r_trace_exit();
+ }
+
+ if (dc->state == DCS_DEV_ADD) {
+ /* go to the next device. */
+
+ dc->curr_targ++;
+ }
+
+ return false;
+}
+
+/*
+ * When discovery is done, find all requests on defer queue and
+ * test if they need to be modified. If a target is no longer present
+ * then complete the request with RS_SEL. Otherwise, update the
+ * target_id since after a hibernate it can be a different value.
+ * VDA does not make passthrough target IDs persistent.
+ */
+static void esas2r_disc_fix_curr_requests(struct esas2r_adapter *a)
+{
+ unsigned long flags;
+ struct esas2r_target *t;
+ struct esas2r_request *rq;
+ struct list_head *element;
+
+ /* update virt_targ_id in any outstanding esas2r_requests */
+
+ spin_lock_irqsave(&a->queue_lock, flags);
+
+ list_for_each(element, &a->defer_list) {
+ rq = list_entry(element, struct esas2r_request, req_list);
+ if (rq->vrq->scsi.function == VDA_FUNC_SCSI) {
+ t = a->targetdb + rq->target_id;
+
+ if (t->target_state == TS_PRESENT)
+ rq->vrq->scsi.target_id = le16_to_cpu(
+ t->virt_targ_id);
+ else
+ rq->req_stat = RS_SEL;
+ }
+
+ }
+
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+}
diff --git a/drivers/scsi/esas2r/esas2r_flash.c b/drivers/scsi/esas2r/esas2r_flash.c
new file mode 100644
index 00000000000..8582929b1fe
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_flash.c
@@ -0,0 +1,1512 @@
+
+/*
+ * linux/drivers/scsi/esas2r/esas2r_flash.c
+ * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+/* local macro defs */
+#define esas2r_nvramcalc_cksum(n) \
+ (esas2r_calc_byte_cksum((u8 *)(n), sizeof(struct esas2r_sas_nvram), \
+ SASNVR_CKSUM_SEED))
+#define esas2r_nvramcalc_xor_cksum(n) \
+ (esas2r_calc_byte_xor_cksum((u8 *)(n), \
+ sizeof(struct esas2r_sas_nvram), 0))
+
+#define ESAS2R_FS_DRVR_VER 2
+
+static struct esas2r_sas_nvram default_sas_nvram = {
+ { 'E', 'S', 'A', 'S' }, /* signature */
+ SASNVR_VERSION, /* version */
+ 0, /* checksum */
+ 31, /* max_lun_for_target */
+ SASNVR_PCILAT_MAX, /* pci_latency */
+ SASNVR1_BOOT_DRVR, /* options1 */
+ SASNVR2_HEARTBEAT | SASNVR2_SINGLE_BUS /* options2 */
+ | SASNVR2_SW_MUX_CTRL,
+ SASNVR_COAL_DIS, /* int_coalescing */
+ SASNVR_CMDTHR_NONE, /* cmd_throttle */
+ 3, /* dev_wait_time */
+ 1, /* dev_wait_count */
+ 0, /* spin_up_delay */
+ 0, /* ssp_align_rate */
+ { 0x50, 0x01, 0x08, 0x60, /* sas_addr */
+ 0x00, 0x00, 0x00, 0x00 },
+ { SASNVR_SPEED_AUTO }, /* phy_speed */
+ { SASNVR_MUX_DISABLED }, /* SAS multiplexing */
+ { 0 }, /* phy_flags */
+ SASNVR_SORT_SAS_ADDR, /* sort_type */
+ 3, /* dpm_reqcmd_lmt */
+ 3, /* dpm_stndby_time */
+ 0, /* dpm_active_time */
+ { 0 }, /* phy_target_id */
+ SASNVR_VSMH_DISABLED, /* virt_ses_mode */
+ SASNVR_RWM_DEFAULT, /* read_write_mode */
+ 0, /* link down timeout */
+ { 0 } /* reserved */
+};
+
+static u8 cmd_to_fls_func[] = {
+ 0xFF,
+ VDA_FLASH_READ,
+ VDA_FLASH_BEGINW,
+ VDA_FLASH_WRITE,
+ VDA_FLASH_COMMIT,
+ VDA_FLASH_CANCEL
+};
+
+static u8 esas2r_calc_byte_xor_cksum(u8 *addr, u32 len, u8 seed)
+{
+ u32 cksum = seed;
+ u8 *p = (u8 *)&cksum;
+
+ while (len) {
+ if (((uintptr_t)addr & 3) == 0)
+ break;
+
+ cksum = cksum ^ *addr;
+ addr++;
+ len--;
+ }
+ while (len >= sizeof(u32)) {
+ cksum = cksum ^ *(u32 *)addr;
+ addr += 4;
+ len -= 4;
+ }
+ while (len--) {
+ cksum = cksum ^ *addr;
+ addr++;
+ }
+ return p[0] ^ p[1] ^ p[2] ^ p[3];
+}
+
+static u8 esas2r_calc_byte_cksum(void *addr, u32 len, u8 seed)
+{
+ u8 *p = (u8 *)addr;
+ u8 cksum = seed;
+
+ while (len--)
+ cksum = cksum + p[len];
+ return cksum;
+}
+
+/* Interrupt callback to process FM API write requests. */
+static void esas2r_fmapi_callback(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct atto_vda_flash_req *vrq = &rq->vrq->flash;
+ struct esas2r_flash_context *fc =
+ (struct esas2r_flash_context *)rq->interrupt_cx;
+
+ if (rq->req_stat == RS_SUCCESS) {
+ /* Last request was successful. See what to do now. */
+ switch (vrq->sub_func) {
+ case VDA_FLASH_BEGINW:
+ if (fc->sgc.cur_offset == NULL)
+ goto commit;
+
+ vrq->sub_func = VDA_FLASH_WRITE;
+ rq->req_stat = RS_PENDING;
+ break;
+
+ case VDA_FLASH_WRITE:
+commit:
+ vrq->sub_func = VDA_FLASH_COMMIT;
+ rq->req_stat = RS_PENDING;
+ rq->interrupt_cb = fc->interrupt_cb;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (rq->req_stat != RS_PENDING)
+ /*
+ * All done. call the real callback to complete the FM API
+ * request. We should only get here if a BEGINW or WRITE
+ * operation failed.
+ */
+ (*fc->interrupt_cb)(a, rq);
+}
+
+/*
+ * Build a flash request based on the flash context. The request status
+ * is filled in on an error.
+ */
+static void build_flash_msg(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_flash_context *fc =
+ (struct esas2r_flash_context *)rq->interrupt_cx;
+ struct esas2r_sg_context *sgc = &fc->sgc;
+ u8 cksum = 0;
+
+ /* calculate the checksum */
+ if (fc->func == VDA_FLASH_BEGINW) {
+ if (sgc->cur_offset)
+ cksum = esas2r_calc_byte_xor_cksum(sgc->cur_offset,
+ sgc->length,
+ 0);
+ rq->interrupt_cb = esas2r_fmapi_callback;
+ } else {
+ rq->interrupt_cb = fc->interrupt_cb;
+ }
+ esas2r_build_flash_req(a,
+ rq,
+ fc->func,
+ cksum,
+ fc->flsh_addr,
+ sgc->length);
+
+ esas2r_rq_free_sg_lists(rq, a);
+
+ /*
+ * remember the length we asked for. we have to keep track of
+ * the current amount done so we know how much to compare when
+ * doing the verification phase.
+ */
+ fc->curr_len = fc->sgc.length;
+
+ if (sgc->cur_offset) {
+ /* setup the S/G context to build the S/G table */
+ esas2r_sgc_init(sgc, a, rq, &rq->vrq->flash.data.sge[0]);
+
+ if (!esas2r_build_sg_list(a, rq, sgc)) {
+ rq->req_stat = RS_BUSY;
+ return;
+ }
+ } else {
+ fc->sgc.length = 0;
+ }
+
+ /* update the flsh_addr to the next one to write to */
+ fc->flsh_addr += fc->curr_len;
+}
+
+/* determine the method to process the flash request */
+static bool load_image(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+ /*
+ * assume we have more to do. if we return with the status set to
+ * RS_PENDING, FM API tasks will continue.
+ */
+ rq->req_stat = RS_PENDING;
+ if (a->flags & AF_DEGRADED_MODE)
+ /* not suppported for now */;
+ else
+ build_flash_msg(a, rq);
+
+ return rq->req_stat == RS_PENDING;
+}
+
+/* boot image fixer uppers called before downloading the image. */
+static void fix_bios(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
+{
+ struct esas2r_component_header *ch = &fi->cmp_hdr[CH_IT_BIOS];
+ struct esas2r_pc_image *pi;
+ struct esas2r_boot_header *bh;
+
+ pi = (struct esas2r_pc_image *)((u8 *)fi + ch->image_offset);
+ bh =
+ (struct esas2r_boot_header *)((u8 *)pi +
+ le16_to_cpu(pi->header_offset));
+ bh->device_id = cpu_to_le16(a->pcid->device);
+
+ /* Recalculate the checksum in the PNP header if there */
+ if (pi->pnp_offset) {
+ u8 *pnp_header_bytes =
+ ((u8 *)pi + le16_to_cpu(pi->pnp_offset));
+
+ /* Identifier - dword that starts at byte 10 */
+ *((u32 *)&pnp_header_bytes[10]) =
+ cpu_to_le32(MAKEDWORD(a->pcid->subsystem_vendor,
+ a->pcid->subsystem_device));
+
+ /* Checksum - byte 9 */
+ pnp_header_bytes[9] -= esas2r_calc_byte_cksum(pnp_header_bytes,
+ 32, 0);
+ }
+
+ /* Recalculate the checksum needed by the PC */
+ pi->checksum = pi->checksum -
+ esas2r_calc_byte_cksum((u8 *)pi, ch->length, 0);
+}
+
+static void fix_efi(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
+{
+ struct esas2r_component_header *ch = &fi->cmp_hdr[CH_IT_EFI];
+ u32 len = ch->length;
+ u32 offset = ch->image_offset;
+ struct esas2r_efi_image *ei;
+ struct esas2r_boot_header *bh;
+
+ while (len) {
+ u32 thislen;
+
+ ei = (struct esas2r_efi_image *)((u8 *)fi + offset);
+ bh = (struct esas2r_boot_header *)((u8 *)ei +
+ le16_to_cpu(
+ ei->header_offset));
+ bh->device_id = cpu_to_le16(a->pcid->device);
+ thislen = (u32)le16_to_cpu(bh->image_length) * 512;
+
+ if (thislen > len)
+ break;
+
+ len -= thislen;
+ offset += thislen;
+ }
+}
+
+/* Complete a FM API request with the specified status. */
+static bool complete_fmapi_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq, u8 fi_stat)
+{
+ struct esas2r_flash_context *fc =
+ (struct esas2r_flash_context *)rq->interrupt_cx;
+ struct esas2r_flash_img *fi = fc->fi;
+
+ fi->status = fi_stat;
+ fi->driver_error = rq->req_stat;
+ rq->interrupt_cb = NULL;
+ rq->req_stat = RS_SUCCESS;
+
+ if (fi_stat != FI_STAT_IMG_VER)
+ memset(fc->scratch, 0, FM_BUF_SZ);
+
+ esas2r_enable_heartbeat(a);
+ esas2r_lock_clear_flags(&a->flags, AF_FLASH_LOCK);
+ return false;
+}
+
+/* Process each phase of the flash download process. */
+static void fw_download_proc(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_flash_context *fc =
+ (struct esas2r_flash_context *)rq->interrupt_cx;
+ struct esas2r_flash_img *fi = fc->fi;
+ struct esas2r_component_header *ch;
+ u32 len;
+ u8 *p, *q;
+
+ /* If the previous operation failed, just return. */
+ if (rq->req_stat != RS_SUCCESS)
+ goto error;
+
+ /*
+ * If an upload just completed and the compare length is non-zero,
+ * then we just read back part of the image we just wrote. verify the
+ * section and continue reading until the entire image is verified.
+ */
+ if (fc->func == VDA_FLASH_READ
+ && fc->cmp_len) {
+ ch = &fi->cmp_hdr[fc->comp_typ];
+
+ p = fc->scratch;
+ q = (u8 *)fi /* start of the whole gob */
+ + ch->image_offset /* start of the current image */
+ + ch->length /* end of the current image */
+ - fc->cmp_len; /* where we are now */
+
+ /*
+ * NOTE - curr_len is the exact count of bytes for the read
+ * even when the end is read and its not a full buffer
+ */
+ for (len = fc->curr_len; len; len--)
+ if (*p++ != *q++)
+ goto error;
+
+ fc->cmp_len -= fc->curr_len; /* # left to compare */
+
+ /* Update fc and determine the length for the next upload */
+ if (fc->cmp_len > FM_BUF_SZ)
+ fc->sgc.length = FM_BUF_SZ;
+ else
+ fc->sgc.length = fc->cmp_len;
+
+ fc->sgc.cur_offset = fc->sgc_offset +
+ ((u8 *)fc->scratch - (u8 *)fi);
+ }
+
+ /*
+ * This code uses a 'while' statement since the next component may
+ * have a length = zero. This can happen since some components are
+ * not required. At the end of this 'while' we set up the length
+ * for the next request and therefore sgc.length can be = 0.
+ */
+ while (fc->sgc.length == 0) {
+ ch = &fi->cmp_hdr[fc->comp_typ];
+
+ switch (fc->task) {
+ case FMTSK_ERASE_BOOT:
+ /* the BIOS image is written next */
+ ch = &fi->cmp_hdr[CH_IT_BIOS];
+ if (ch->length == 0)
+ goto no_bios;
+
+ fc->task = FMTSK_WRTBIOS;
+ fc->func = VDA_FLASH_BEGINW;
+ fc->comp_typ = CH_IT_BIOS;
+ fc->flsh_addr = FLS_OFFSET_BOOT;
+ fc->sgc.length = ch->length;
+ fc->sgc.cur_offset = fc->sgc_offset +
+ ch->image_offset;
+ break;
+
+ case FMTSK_WRTBIOS:
+ /*
+ * The BIOS image has been written - read it and
+ * verify it
+ */
+ fc->task = FMTSK_READBIOS;
+ fc->func = VDA_FLASH_READ;
+ fc->flsh_addr = FLS_OFFSET_BOOT;
+ fc->cmp_len = ch->length;
+ fc->sgc.length = FM_BUF_SZ;
+ fc->sgc.cur_offset = fc->sgc_offset
+ + ((u8 *)fc->scratch -
+ (u8 *)fi);
+ break;
+
+ case FMTSK_READBIOS:
+no_bios:
+ /*
+ * Mark the component header status for the image
+ * completed
+ */
+ ch->status = CH_STAT_SUCCESS;
+
+ /* The MAC image is written next */
+ ch = &fi->cmp_hdr[CH_IT_MAC];
+ if (ch->length == 0)
+ goto no_mac;
+
+ fc->task = FMTSK_WRTMAC;
+ fc->func = VDA_FLASH_BEGINW;
+ fc->comp_typ = CH_IT_MAC;
+ fc->flsh_addr = FLS_OFFSET_BOOT
+ + fi->cmp_hdr[CH_IT_BIOS].length;
+ fc->sgc.length = ch->length;
+ fc->sgc.cur_offset = fc->sgc_offset +
+ ch->image_offset;
+ break;
+
+ case FMTSK_WRTMAC:
+ /* The MAC image has been written - read and verify */
+ fc->task = FMTSK_READMAC;
+ fc->func = VDA_FLASH_READ;
+ fc->flsh_addr -= ch->length;
+ fc->cmp_len = ch->length;
+ fc->sgc.length = FM_BUF_SZ;
+ fc->sgc.cur_offset = fc->sgc_offset
+ + ((u8 *)fc->scratch -
+ (u8 *)fi);
+ break;
+
+ case FMTSK_READMAC:
+no_mac:
+ /*
+ * Mark the component header status for the image
+ * completed
+ */
+ ch->status = CH_STAT_SUCCESS;
+
+ /* The EFI image is written next */
+ ch = &fi->cmp_hdr[CH_IT_EFI];
+ if (ch->length == 0)
+ goto no_efi;
+
+ fc->task = FMTSK_WRTEFI;
+ fc->func = VDA_FLASH_BEGINW;
+ fc->comp_typ = CH_IT_EFI;
+ fc->flsh_addr = FLS_OFFSET_BOOT
+ + fi->cmp_hdr[CH_IT_BIOS].length
+ + fi->cmp_hdr[CH_IT_MAC].length;
+ fc->sgc.length = ch->length;
+ fc->sgc.cur_offset = fc->sgc_offset +
+ ch->image_offset;
+ break;
+
+ case FMTSK_WRTEFI:
+ /* The EFI image has been written - read and verify */
+ fc->task = FMTSK_READEFI;
+ fc->func = VDA_FLASH_READ;
+ fc->flsh_addr -= ch->length;
+ fc->cmp_len = ch->length;
+ fc->sgc.length = FM_BUF_SZ;
+ fc->sgc.cur_offset = fc->sgc_offset
+ + ((u8 *)fc->scratch -
+ (u8 *)fi);
+ break;
+
+ case FMTSK_READEFI:
+no_efi:
+ /*
+ * Mark the component header status for the image
+ * completed
+ */
+ ch->status = CH_STAT_SUCCESS;
+
+ /* The CFG image is written next */
+ ch = &fi->cmp_hdr[CH_IT_CFG];
+
+ if (ch->length == 0)
+ goto no_cfg;
+ fc->task = FMTSK_WRTCFG;
+ fc->func = VDA_FLASH_BEGINW;
+ fc->comp_typ = CH_IT_CFG;
+ fc->flsh_addr = FLS_OFFSET_CPYR - ch->length;
+ fc->sgc.length = ch->length;
+ fc->sgc.cur_offset = fc->sgc_offset +
+ ch->image_offset;
+ break;
+
+ case FMTSK_WRTCFG:
+ /* The CFG image has been written - read and verify */
+ fc->task = FMTSK_READCFG;
+ fc->func = VDA_FLASH_READ;
+ fc->flsh_addr = FLS_OFFSET_CPYR - ch->length;
+ fc->cmp_len = ch->length;
+ fc->sgc.length = FM_BUF_SZ;
+ fc->sgc.cur_offset = fc->sgc_offset
+ + ((u8 *)fc->scratch -
+ (u8 *)fi);
+ break;
+
+ case FMTSK_READCFG:
+no_cfg:
+ /*
+ * Mark the component header status for the image
+ * completed
+ */
+ ch->status = CH_STAT_SUCCESS;
+
+ /*
+ * The download is complete. If in degraded mode,
+ * attempt a chip reset.
+ */
+ if (a->flags & AF_DEGRADED_MODE)
+ esas2r_local_reset_adapter(a);
+
+ a->flash_ver = fi->cmp_hdr[CH_IT_BIOS].version;
+ esas2r_print_flash_rev(a);
+
+ /* Update the type of boot image on the card */
+ memcpy(a->image_type, fi->rel_version,
+ sizeof(fi->rel_version));
+ complete_fmapi_req(a, rq, FI_STAT_SUCCESS);
+ return;
+ }
+
+ /* If verifying, don't try reading more than what's there */
+ if (fc->func == VDA_FLASH_READ
+ && fc->sgc.length > fc->cmp_len)
+ fc->sgc.length = fc->cmp_len;
+ }
+
+ /* Build the request to perform the next action */
+ if (!load_image(a, rq)) {
+error:
+ if (fc->comp_typ < fi->num_comps) {
+ ch = &fi->cmp_hdr[fc->comp_typ];
+ ch->status = CH_STAT_FAILED;
+ }
+
+ complete_fmapi_req(a, rq, FI_STAT_FAILED);
+ }
+}
+
+/* Determine the flash image adaptyp for this adapter */
+static u8 get_fi_adap_type(struct esas2r_adapter *a)
+{
+ u8 type;
+
+ /* use the device ID to get the correct adap_typ for this HBA */
+ switch (a->pcid->device) {
+ case ATTO_DID_INTEL_IOP348:
+ type = FI_AT_SUN_LAKE;
+ break;
+
+ case ATTO_DID_MV_88RC9580:
+ case ATTO_DID_MV_88RC9580TS:
+ case ATTO_DID_MV_88RC9580TSE:
+ case ATTO_DID_MV_88RC9580TL:
+ type = FI_AT_MV_9580;
+ break;
+
+ default:
+ type = FI_AT_UNKNWN;
+ break;
+ }
+
+ return type;
+}
+
+/* Size of config + copyright + flash_ver images, 0 for failure. */
+static u32 chk_cfg(u8 *cfg, u32 length, u32 *flash_ver)
+{
+ u16 *pw = (u16 *)cfg - 1;
+ u32 sz = 0;
+ u32 len = length;
+
+ if (len == 0)
+ len = FM_BUF_SZ;
+
+ if (flash_ver)
+ *flash_ver = 0;
+
+ while (true) {
+ u16 type;
+ u16 size;
+
+ type = le16_to_cpu(*pw--);
+ size = le16_to_cpu(*pw--);
+
+ if (type != FBT_CPYR
+ && type != FBT_SETUP
+ && type != FBT_FLASH_VER)
+ break;
+
+ if (type == FBT_FLASH_VER
+ && flash_ver)
+ *flash_ver = le32_to_cpu(*(u32 *)(pw - 1));
+
+ sz += size + (2 * sizeof(u16));
+ pw -= size / sizeof(u16);
+
+ if (sz > len - (2 * sizeof(u16)))
+ break;
+ }
+
+ /* See if we are comparing the size to the specified length */
+ if (length && sz != length)
+ return 0;
+
+ return sz;
+}
+
+/* Verify that the boot image is valid */
+static u8 chk_boot(u8 *boot_img, u32 length)
+{
+ struct esas2r_boot_image *bi = (struct esas2r_boot_image *)boot_img;
+ u16 hdroffset = le16_to_cpu(bi->header_offset);
+ struct esas2r_boot_header *bh;
+
+ if (bi->signature != le16_to_cpu(0xaa55)
+ || (long)hdroffset >
+ (long)(65536L - sizeof(struct esas2r_boot_header))
+ || (hdroffset & 3)
+ || (hdroffset < sizeof(struct esas2r_boot_image))
+ || ((u32)hdroffset + sizeof(struct esas2r_boot_header) > length))
+ return 0xff;
+
+ bh = (struct esas2r_boot_header *)((char *)bi + hdroffset);
+
+ if (bh->signature[0] != 'P'
+ || bh->signature[1] != 'C'
+ || bh->signature[2] != 'I'
+ || bh->signature[3] != 'R'
+ || le16_to_cpu(bh->struct_length) <
+ (u16)sizeof(struct esas2r_boot_header)
+ || bh->class_code[2] != 0x01
+ || bh->class_code[1] != 0x04
+ || bh->class_code[0] != 0x00
+ || (bh->code_type != CODE_TYPE_PC
+ && bh->code_type != CODE_TYPE_OPEN
+ && bh->code_type != CODE_TYPE_EFI))
+ return 0xff;
+
+ return bh->code_type;
+}
+
+/* The sum of all the WORDS of the image */
+static u16 calc_fi_checksum(struct esas2r_flash_context *fc)
+{
+ struct esas2r_flash_img *fi = fc->fi;
+ u16 cksum;
+ u32 len;
+ u16 *pw;
+
+ for (len = (fi->length - fc->fi_hdr_len) / 2,
+ pw = (u16 *)((u8 *)fi + fc->fi_hdr_len),
+ cksum = 0;
+ len;
+ len--, pw++)
+ cksum = cksum + le16_to_cpu(*pw);
+
+ return cksum;
+}
+
+/*
+ * Verify the flash image structure. The following verifications will
+ * be performed:
+ * 1) verify the fi_version is correct
+ * 2) verify the checksum of the entire image.
+ * 3) validate the adap_typ, action and length fields.
+ * 4) valdiate each component header. check the img_type and
+ * length fields
+ * 5) valdiate each component image. validate signatures and
+ * local checksums
+ */
+static bool verify_fi(struct esas2r_adapter *a,
+ struct esas2r_flash_context *fc)
+{
+ struct esas2r_flash_img *fi = fc->fi;
+ u8 type;
+ bool imgerr;
+ u16 i;
+ u32 len;
+ struct esas2r_component_header *ch;
+
+ /* Verify the length - length must even since we do a word checksum */
+ len = fi->length;
+
+ if ((len & 1)
+ || len < fc->fi_hdr_len) {
+ fi->status = FI_STAT_LENGTH;
+ return false;
+ }
+
+ /* Get adapter type and verify type in flash image */
+ type = get_fi_adap_type(a);
+ if ((type == FI_AT_UNKNWN) || (fi->adap_typ != type)) {
+ fi->status = FI_STAT_ADAPTYP;
+ return false;
+ }
+
+ /*
+ * Loop through each component and verify the img_type and length
+ * fields. Keep a running count of the sizes sooze we can verify total
+ * size to additive size.
+ */
+ imgerr = false;
+
+ for (i = 0, len = 0, ch = fi->cmp_hdr;
+ i < fi->num_comps;
+ i++, ch++) {
+ bool cmperr = false;
+
+ /*
+ * Verify that the component header has the same index as the
+ * image type. The headers must be ordered correctly
+ */
+ if (i != ch->img_type) {
+ imgerr = true;
+ ch->status = CH_STAT_INVALID;
+ continue;
+ }
+
+ switch (ch->img_type) {
+ case CH_IT_BIOS:
+ type = CODE_TYPE_PC;
+ break;
+
+ case CH_IT_MAC:
+ type = CODE_TYPE_OPEN;
+ break;
+
+ case CH_IT_EFI:
+ type = CODE_TYPE_EFI;
+ break;
+ }
+
+ switch (ch->img_type) {
+ case CH_IT_FW:
+ case CH_IT_NVR:
+ break;
+
+ case CH_IT_BIOS:
+ case CH_IT_MAC:
+ case CH_IT_EFI:
+ if (ch->length & 0x1ff)
+ cmperr = true;
+
+ /* Test if component image is present */
+ if (ch->length == 0)
+ break;
+
+ /* Image is present - verify the image */
+ if (chk_boot((u8 *)fi + ch->image_offset, ch->length)
+ != type)
+ cmperr = true;
+
+ break;
+
+ case CH_IT_CFG:
+
+ /* Test if component image is present */
+ if (ch->length == 0) {
+ cmperr = true;
+ break;
+ }
+
+ /* Image is present - verify the image */
+ if (!chk_cfg((u8 *)fi + ch->image_offset + ch->length,
+ ch->length, NULL))
+ cmperr = true;
+
+ break;
+
+ default:
+
+ fi->status = FI_STAT_UNKNOWN;
+ return false;
+ }
+
+ if (cmperr) {
+ imgerr = true;
+ ch->status = CH_STAT_INVALID;
+ } else {
+ ch->status = CH_STAT_PENDING;
+ len += ch->length;
+ }
+ }
+
+ if (imgerr) {
+ fi->status = FI_STAT_MISSING;
+ return false;
+ }
+
+ /* Compare fi->length to the sum of ch->length fields */
+ if (len != fi->length - fc->fi_hdr_len) {
+ fi->status = FI_STAT_LENGTH;
+ return false;
+ }
+
+ /* Compute the checksum - it should come out zero */
+ if (fi->checksum != calc_fi_checksum(fc)) {
+ fi->status = FI_STAT_CHKSUM;
+ return false;
+ }
+
+ return true;
+}
+
+/* Fill in the FS IOCTL response data from a completed request. */
+static void esas2r_complete_fs_ioctl(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_ioctl_fs *fs =
+ (struct esas2r_ioctl_fs *)rq->interrupt_cx;
+
+ if (rq->vrq->flash.sub_func == VDA_FLASH_COMMIT)
+ esas2r_enable_heartbeat(a);
+
+ fs->driver_error = rq->req_stat;
+
+ if (fs->driver_error == RS_SUCCESS)
+ fs->status = ATTO_STS_SUCCESS;
+ else
+ fs->status = ATTO_STS_FAILED;
+}
+
+/* Prepare an FS IOCTL request to be sent to the firmware. */
+bool esas2r_process_fs_ioctl(struct esas2r_adapter *a,
+ struct esas2r_ioctl_fs *fs,
+ struct esas2r_request *rq,
+ struct esas2r_sg_context *sgc)
+{
+ u8 cmdcnt = (u8)ARRAY_SIZE(cmd_to_fls_func);
+ struct esas2r_ioctlfs_command *fsc = &fs->command;
+ u8 func = 0;
+ u32 datalen;
+
+ fs->status = ATTO_STS_FAILED;
+ fs->driver_error = RS_PENDING;
+
+ if (fs->version > ESAS2R_FS_VER) {
+ fs->status = ATTO_STS_INV_VERSION;
+ return false;
+ }
+
+ func = cmd_to_fls_func[fsc->command];
+ if (fsc->command >= cmdcnt || func == 0xFF) {
+ fs->status = ATTO_STS_INV_FUNC;
+ return false;
+ }
+
+ if (fsc->command != ESAS2R_FS_CMD_CANCEL) {
+ if ((a->pcid->device != ATTO_DID_MV_88RC9580
+ || fs->adap_type != ESAS2R_FS_AT_ESASRAID2)
+ && (a->pcid->device != ATTO_DID_MV_88RC9580TS
+ || fs->adap_type != ESAS2R_FS_AT_TSSASRAID2)
+ && (a->pcid->device != ATTO_DID_MV_88RC9580TSE
+ || fs->adap_type != ESAS2R_FS_AT_TSSASRAID2E)
+ && (a->pcid->device != ATTO_DID_MV_88RC9580TL
+ || fs->adap_type != ESAS2R_FS_AT_TLSASHBA)) {
+ fs->status = ATTO_STS_INV_ADAPTER;
+ return false;
+ }
+
+ if (fs->driver_ver > ESAS2R_FS_DRVR_VER) {
+ fs->status = ATTO_STS_INV_DRVR_VER;
+ return false;
+ }
+ }
+
+ if (a->flags & AF_DEGRADED_MODE) {
+ fs->status = ATTO_STS_DEGRADED;
+ return false;
+ }
+
+ rq->interrupt_cb = esas2r_complete_fs_ioctl;
+ rq->interrupt_cx = fs;
+ datalen = le32_to_cpu(fsc->length);
+ esas2r_build_flash_req(a,
+ rq,
+ func,
+ fsc->checksum,
+ le32_to_cpu(fsc->flash_addr),
+ datalen);
+
+ if (func == VDA_FLASH_WRITE
+ || func == VDA_FLASH_READ) {
+ if (datalen == 0) {
+ fs->status = ATTO_STS_INV_FUNC;
+ return false;
+ }
+
+ esas2r_sgc_init(sgc, a, rq, rq->vrq->flash.data.sge);
+ sgc->length = datalen;
+
+ if (!esas2r_build_sg_list(a, rq, sgc)) {
+ fs->status = ATTO_STS_OUT_OF_RSRC;
+ return false;
+ }
+ }
+
+ if (func == VDA_FLASH_COMMIT)
+ esas2r_disable_heartbeat(a);
+
+ esas2r_start_request(a, rq);
+
+ return true;
+}
+
+static bool esas2r_flash_access(struct esas2r_adapter *a, u32 function)
+{
+ u32 starttime;
+ u32 timeout;
+ u32 intstat;
+ u32 doorbell;
+
+ /* Disable chip interrupts awhile */
+ if (function == DRBL_FLASH_REQ)
+ esas2r_disable_chip_interrupts(a);
+
+ /* Issue the request to the firmware */
+ esas2r_write_register_dword(a, MU_DOORBELL_IN, function);
+
+ /* Now wait for the firmware to process it */
+ starttime = jiffies_to_msecs(jiffies);
+ timeout = a->flags &
+ (AF_CHPRST_PENDING | AF_DISC_PENDING) ? 40000 : 5000;
+
+ while (true) {
+ intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
+
+ if (intstat & MU_INTSTAT_DRBL) {
+ /* Got a doorbell interrupt. Check for the function */
+ doorbell =
+ esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+ esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+ doorbell);
+ if (doorbell & function)
+ break;
+ }
+
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ if ((jiffies_to_msecs(jiffies) - starttime) > timeout) {
+ /*
+ * Iimeout. If we were requesting flash access,
+ * indicate we are done so the firmware knows we gave
+ * up. If this was a REQ, we also need to re-enable
+ * chip interrupts.
+ */
+ if (function == DRBL_FLASH_REQ) {
+ esas2r_hdebug("flash access timeout");
+ esas2r_write_register_dword(a, MU_DOORBELL_IN,
+ DRBL_FLASH_DONE);
+ esas2r_enable_chip_interrupts(a);
+ } else {
+ esas2r_hdebug("flash release timeout");
+ }
+
+ return false;
+ }
+ }
+
+ /* if we're done, re-enable chip interrupts */
+ if (function == DRBL_FLASH_DONE)
+ esas2r_enable_chip_interrupts(a);
+
+ return true;
+}
+
+#define WINDOW_SIZE ((signed int)MW_DATA_WINDOW_SIZE)
+
+bool esas2r_read_flash_block(struct esas2r_adapter *a,
+ void *to,
+ u32 from,
+ u32 size)
+{
+ u8 *end = (u8 *)to;
+
+ /* Try to acquire access to the flash */
+ if (!esas2r_flash_access(a, DRBL_FLASH_REQ))
+ return false;
+
+ while (size) {
+ u32 len;
+ u32 offset;
+ u32 iatvr;
+
+ if (a->flags2 & AF2_SERIAL_FLASH)
+ iatvr = MW_DATA_ADDR_SER_FLASH + (from & -WINDOW_SIZE);
+ else
+ iatvr = MW_DATA_ADDR_PAR_FLASH + (from & -WINDOW_SIZE);
+
+ esas2r_map_data_window(a, iatvr);
+ offset = from & (WINDOW_SIZE - 1);
+ len = size;
+
+ if (len > WINDOW_SIZE - offset)
+ len = WINDOW_SIZE - offset;
+
+ from += len;
+ size -= len;
+
+ while (len--) {
+ *end++ = esas2r_read_data_byte(a, offset);
+ offset++;
+ }
+ }
+
+ /* Release flash access */
+ esas2r_flash_access(a, DRBL_FLASH_DONE);
+ return true;
+}
+
+bool esas2r_read_flash_rev(struct esas2r_adapter *a)
+{
+ u8 bytes[256];
+ u16 *pw;
+ u16 *pwstart;
+ u16 type;
+ u16 size;
+ u32 sz;
+
+ sz = sizeof(bytes);
+ pw = (u16 *)(bytes + sz);
+ pwstart = (u16 *)bytes + 2;
+
+ if (!esas2r_read_flash_block(a, bytes, FLS_OFFSET_CPYR - sz, sz))
+ goto invalid_rev;
+
+ while (pw >= pwstart) {
+ pw--;
+ type = le16_to_cpu(*pw);
+ pw--;
+ size = le16_to_cpu(*pw);
+ pw -= size / 2;
+
+ if (type == FBT_CPYR
+ || type == FBT_SETUP
+ || pw < pwstart)
+ continue;
+
+ if (type == FBT_FLASH_VER)
+ a->flash_ver = le32_to_cpu(*(u32 *)pw);
+
+ break;
+ }
+
+invalid_rev:
+ return esas2r_print_flash_rev(a);
+}
+
+bool esas2r_print_flash_rev(struct esas2r_adapter *a)
+{
+ u16 year = LOWORD(a->flash_ver);
+ u8 day = LOBYTE(HIWORD(a->flash_ver));
+ u8 month = HIBYTE(HIWORD(a->flash_ver));
+
+ if (day == 0
+ || month == 0
+ || day > 31
+ || month > 12
+ || year < 2006
+ || year > 9999) {
+ strcpy(a->flash_rev, "not found");
+ a->flash_ver = 0;
+ return false;
+ }
+
+ sprintf(a->flash_rev, "%02d/%02d/%04d", month, day, year);
+ esas2r_hdebug("flash version: %s", a->flash_rev);
+ return true;
+}
+
+/*
+ * Find the type of boot image type that is currently in the flash.
+ * The chip only has a 64 KB PCI-e expansion ROM
+ * size so only one image can be flashed at a time.
+ */
+bool esas2r_read_image_type(struct esas2r_adapter *a)
+{
+ u8 bytes[256];
+ struct esas2r_boot_image *bi;
+ struct esas2r_boot_header *bh;
+ u32 sz;
+ u32 len;
+ u32 offset;
+
+ /* Start at the base of the boot images and look for a valid image */
+ sz = sizeof(bytes);
+ len = FLS_LENGTH_BOOT;
+ offset = 0;
+
+ while (true) {
+ if (!esas2r_read_flash_block(a, bytes, FLS_OFFSET_BOOT +
+ offset,
+ sz))
+ goto invalid_rev;
+
+ bi = (struct esas2r_boot_image *)bytes;
+ bh = (struct esas2r_boot_header *)((u8 *)bi +
+ le16_to_cpu(
+ bi->header_offset));
+ if (bi->signature != cpu_to_le16(0xAA55))
+ goto invalid_rev;
+
+ if (bh->code_type == CODE_TYPE_PC) {
+ strcpy(a->image_type, "BIOS");
+
+ return true;
+ } else if (bh->code_type == CODE_TYPE_EFI) {
+ struct esas2r_efi_image *ei;
+
+ /*
+ * So we have an EFI image. There are several types
+ * so see which architecture we have.
+ */
+ ei = (struct esas2r_efi_image *)bytes;
+
+ switch (le16_to_cpu(ei->machine_type)) {
+ case EFI_MACHINE_IA32:
+ strcpy(a->image_type, "EFI 32-bit");
+ return true;
+
+ case EFI_MACHINE_IA64:
+ strcpy(a->image_type, "EFI itanium");
+ return true;
+
+ case EFI_MACHINE_X64:
+ strcpy(a->image_type, "EFI 64-bit");
+ return true;
+
+ case EFI_MACHINE_EBC:
+ strcpy(a->image_type, "EFI EBC");
+ return true;
+
+ default:
+ goto invalid_rev;
+ }
+ } else {
+ u32 thislen;
+
+ /* jump to the next image */
+ thislen = (u32)le16_to_cpu(bh->image_length) * 512;
+ if (thislen == 0
+ || thislen + offset > len
+ || bh->indicator == INDICATOR_LAST)
+ break;
+
+ offset += thislen;
+ }
+ }
+
+invalid_rev:
+ strcpy(a->image_type, "no boot images");
+ return false;
+}
+
+/*
+ * Read and validate current NVRAM parameters by accessing
+ * physical NVRAM directly. if currently stored parameters are
+ * invalid, use the defaults.
+ */
+bool esas2r_nvram_read_direct(struct esas2r_adapter *a)
+{
+ bool result;
+
+ if (down_interruptible(&a->nvram_semaphore))
+ return false;
+
+ if (!esas2r_read_flash_block(a, a->nvram, FLS_OFFSET_NVR,
+ sizeof(struct esas2r_sas_nvram))) {
+ esas2r_hdebug("NVRAM read failed, using defaults");
+ return false;
+ }
+
+ result = esas2r_nvram_validate(a);
+
+ up(&a->nvram_semaphore);
+
+ return result;
+}
+
+/* Interrupt callback to process NVRAM completions. */
+static void esas2r_nvram_callback(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct atto_vda_flash_req *vrq = &rq->vrq->flash;
+
+ if (rq->req_stat == RS_SUCCESS) {
+ /* last request was successful. see what to do now. */
+
+ switch (vrq->sub_func) {
+ case VDA_FLASH_BEGINW:
+ vrq->sub_func = VDA_FLASH_WRITE;
+ rq->req_stat = RS_PENDING;
+ break;
+
+ case VDA_FLASH_WRITE:
+ vrq->sub_func = VDA_FLASH_COMMIT;
+ rq->req_stat = RS_PENDING;
+ break;
+
+ case VDA_FLASH_READ:
+ esas2r_nvram_validate(a);
+ break;
+
+ case VDA_FLASH_COMMIT:
+ default:
+ break;
+ }
+ }
+
+ if (rq->req_stat != RS_PENDING) {
+ /* update the NVRAM state */
+ if (rq->req_stat == RS_SUCCESS)
+ esas2r_lock_set_flags(&a->flags, AF_NVR_VALID);
+ else
+ esas2r_lock_clear_flags(&a->flags, AF_NVR_VALID);
+
+ esas2r_enable_heartbeat(a);
+
+ up(&a->nvram_semaphore);
+ }
+}
+
+/*
+ * Write the contents of nvram to the adapter's physical NVRAM.
+ * The cached copy of the NVRAM is also updated.
+ */
+bool esas2r_nvram_write(struct esas2r_adapter *a, struct esas2r_request *rq,
+ struct esas2r_sas_nvram *nvram)
+{
+ struct esas2r_sas_nvram *n = nvram;
+ u8 sas_address_bytes[8];
+ u32 *sas_address_dwords = (u32 *)&sas_address_bytes[0];
+ struct atto_vda_flash_req *vrq = &rq->vrq->flash;
+
+ if (a->flags & AF_DEGRADED_MODE)
+ return false;
+
+ if (down_interruptible(&a->nvram_semaphore))
+ return false;
+
+ if (n == NULL)
+ n = a->nvram;
+
+ /* check the validity of the settings */
+ if (n->version > SASNVR_VERSION) {
+ up(&a->nvram_semaphore);
+ return false;
+ }
+
+ memcpy(&sas_address_bytes[0], n->sas_addr, 8);
+
+ if (sas_address_bytes[0] != 0x50
+ || sas_address_bytes[1] != 0x01
+ || sas_address_bytes[2] != 0x08
+ || (sas_address_bytes[3] & 0xF0) != 0x60
+ || ((sas_address_bytes[3] & 0x0F) | sas_address_dwords[1]) == 0) {
+ up(&a->nvram_semaphore);
+ return false;
+ }
+
+ if (n->spin_up_delay > SASNVR_SPINUP_MAX)
+ n->spin_up_delay = SASNVR_SPINUP_MAX;
+
+ n->version = SASNVR_VERSION;
+ n->checksum = n->checksum - esas2r_nvramcalc_cksum(n);
+ memcpy(a->nvram, n, sizeof(struct esas2r_sas_nvram));
+
+ /* write the NVRAM */
+ n = a->nvram;
+ esas2r_disable_heartbeat(a);
+
+ esas2r_build_flash_req(a,
+ rq,
+ VDA_FLASH_BEGINW,
+ esas2r_nvramcalc_xor_cksum(n),
+ FLS_OFFSET_NVR,
+ sizeof(struct esas2r_sas_nvram));
+
+ if (a->flags & AF_LEGACY_SGE_MODE) {
+
+ vrq->data.sge[0].length =
+ cpu_to_le32(SGE_LAST |
+ sizeof(struct esas2r_sas_nvram));
+ vrq->data.sge[0].address = cpu_to_le64(
+ a->uncached_phys + (u64)((u8 *)n - a->uncached));
+ } else {
+ vrq->data.prde[0].ctl_len =
+ cpu_to_le32(sizeof(struct esas2r_sas_nvram));
+ vrq->data.prde[0].address = cpu_to_le64(
+ a->uncached_phys
+ + (u64)((u8 *)n - a->uncached));
+ }
+ rq->interrupt_cb = esas2r_nvram_callback;
+ esas2r_start_request(a, rq);
+ return true;
+}
+
+/* Validate the cached NVRAM. if the NVRAM is invalid, load the defaults. */
+bool esas2r_nvram_validate(struct esas2r_adapter *a)
+{
+ struct esas2r_sas_nvram *n = a->nvram;
+ bool rslt = false;
+
+ if (n->signature[0] != 'E'
+ || n->signature[1] != 'S'
+ || n->signature[2] != 'A'
+ || n->signature[3] != 'S') {
+ esas2r_hdebug("invalid NVRAM signature");
+ } else if (esas2r_nvramcalc_cksum(n)) {
+ esas2r_hdebug("invalid NVRAM checksum");
+ } else if (n->version > SASNVR_VERSION) {
+ esas2r_hdebug("invalid NVRAM version");
+ } else {
+ esas2r_lock_set_flags(&a->flags, AF_NVR_VALID);
+ rslt = true;
+ }
+
+ if (rslt == false) {
+ esas2r_hdebug("using defaults");
+ esas2r_nvram_set_defaults(a);
+ }
+
+ return rslt;
+}
+
+/*
+ * Set the cached NVRAM to defaults. note that this function sets the default
+ * NVRAM when it has been determined that the physical NVRAM is invalid.
+ * In this case, the SAS address is fabricated.
+ */
+void esas2r_nvram_set_defaults(struct esas2r_adapter *a)
+{
+ struct esas2r_sas_nvram *n = a->nvram;
+ u32 time = jiffies_to_msecs(jiffies);
+
+ esas2r_lock_clear_flags(&a->flags, AF_NVR_VALID);
+ memcpy(n, &default_sas_nvram, sizeof(struct esas2r_sas_nvram));
+ n->sas_addr[3] |= 0x0F;
+ n->sas_addr[4] = HIBYTE(LOWORD(time));
+ n->sas_addr[5] = LOBYTE(LOWORD(time));
+ n->sas_addr[6] = a->pcid->bus->number;
+ n->sas_addr[7] = a->pcid->devfn;
+}
+
+void esas2r_nvram_get_defaults(struct esas2r_adapter *a,
+ struct esas2r_sas_nvram *nvram)
+{
+ u8 sas_addr[8];
+
+ /*
+ * in case we are copying the defaults into the adapter, copy the SAS
+ * address out first.
+ */
+ memcpy(&sas_addr[0], a->nvram->sas_addr, 8);
+ memcpy(nvram, &default_sas_nvram, sizeof(struct esas2r_sas_nvram));
+ memcpy(&nvram->sas_addr[0], &sas_addr[0], 8);
+}
+
+bool esas2r_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi,
+ struct esas2r_request *rq, struct esas2r_sg_context *sgc)
+{
+ struct esas2r_flash_context *fc = &a->flash_context;
+ u8 j;
+ struct esas2r_component_header *ch;
+
+ if (esas2r_lock_set_flags(&a->flags, AF_FLASH_LOCK) & AF_FLASH_LOCK) {
+ /* flag was already set */
+ fi->status = FI_STAT_BUSY;
+ return false;
+ }
+
+ memcpy(&fc->sgc, sgc, sizeof(struct esas2r_sg_context));
+ sgc = &fc->sgc;
+ fc->fi = fi;
+ fc->sgc_offset = sgc->cur_offset;
+ rq->req_stat = RS_SUCCESS;
+ rq->interrupt_cx = fc;
+
+ switch (fi->fi_version) {
+ case FI_VERSION_1:
+ fc->scratch = ((struct esas2r_flash_img *)fi)->scratch_buf;
+ fc->num_comps = FI_NUM_COMPS_V1;
+ fc->fi_hdr_len = sizeof(struct esas2r_flash_img);
+ break;
+
+ default:
+ return complete_fmapi_req(a, rq, FI_STAT_IMG_VER);
+ }
+
+ if (a->flags & AF_DEGRADED_MODE)
+ return complete_fmapi_req(a, rq, FI_STAT_DEGRADED);
+
+ switch (fi->action) {
+ case FI_ACT_DOWN: /* Download the components */
+ /* Verify the format of the flash image */
+ if (!verify_fi(a, fc))
+ return complete_fmapi_req(a, rq, fi->status);
+
+ /* Adjust the BIOS fields that are dependent on the HBA */
+ ch = &fi->cmp_hdr[CH_IT_BIOS];
+
+ if (ch->length)
+ fix_bios(a, fi);
+
+ /* Adjust the EFI fields that are dependent on the HBA */
+ ch = &fi->cmp_hdr[CH_IT_EFI];
+
+ if (ch->length)
+ fix_efi(a, fi);
+
+ /*
+ * Since the image was just modified, compute the checksum on
+ * the modified image. First update the CRC for the composite
+ * expansion ROM image.
+ */
+ fi->checksum = calc_fi_checksum(fc);
+
+ /* Disable the heartbeat */
+ esas2r_disable_heartbeat(a);
+
+ /* Now start up the download sequence */
+ fc->task = FMTSK_ERASE_BOOT;
+ fc->func = VDA_FLASH_BEGINW;
+ fc->comp_typ = CH_IT_CFG;
+ fc->flsh_addr = FLS_OFFSET_BOOT;
+ fc->sgc.length = FLS_LENGTH_BOOT;
+ fc->sgc.cur_offset = NULL;
+
+ /* Setup the callback address */
+ fc->interrupt_cb = fw_download_proc;
+ break;
+
+ case FI_ACT_UPSZ: /* Get upload sizes */
+ fi->adap_typ = get_fi_adap_type(a);
+ fi->flags = 0;
+ fi->num_comps = fc->num_comps;
+ fi->length = fc->fi_hdr_len;
+
+ /* Report the type of boot image in the rel_version string */
+ memcpy(fi->rel_version, a->image_type,
+ sizeof(fi->rel_version));
+
+ /* Build the component headers */
+ for (j = 0, ch = fi->cmp_hdr;
+ j < fi->num_comps;
+ j++, ch++) {
+ ch->img_type = j;
+ ch->status = CH_STAT_PENDING;
+ ch->length = 0;
+ ch->version = 0xffffffff;
+ ch->image_offset = 0;
+ ch->pad[0] = 0;
+ ch->pad[1] = 0;
+ }
+
+ if (a->flash_ver != 0) {
+ fi->cmp_hdr[CH_IT_BIOS].version =
+ fi->cmp_hdr[CH_IT_MAC].version =
+ fi->cmp_hdr[CH_IT_EFI].version =
+ fi->cmp_hdr[CH_IT_CFG].version
+ = a->flash_ver;
+
+ fi->cmp_hdr[CH_IT_BIOS].status =
+ fi->cmp_hdr[CH_IT_MAC].status =
+ fi->cmp_hdr[CH_IT_EFI].status =
+ fi->cmp_hdr[CH_IT_CFG].status =
+ CH_STAT_SUCCESS;
+
+ return complete_fmapi_req(a, rq, FI_STAT_SUCCESS);
+ }
+
+ /* fall through */
+
+ case FI_ACT_UP: /* Upload the components */
+ default:
+ return complete_fmapi_req(a, rq, FI_STAT_INVALID);
+ }
+
+ /*
+ * If we make it here, fc has been setup to do the first task. Call
+ * load_image to format the request, start it, and get out. The
+ * interrupt code will call the callback when the first message is
+ * complete.
+ */
+ if (!load_image(a, rq))
+ return complete_fmapi_req(a, rq, FI_STAT_FAILED);
+
+ esas2r_start_request(a, rq);
+
+ return true;
+}
diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c
new file mode 100644
index 00000000000..3a798e7d5c5
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_init.c
@@ -0,0 +1,1773 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r_init.c
+ * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.com)mpt3sas/mpt3sas_trigger_diag.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+static bool esas2r_initmem_alloc(struct esas2r_adapter *a,
+ struct esas2r_mem_desc *mem_desc,
+ u32 align)
+{
+ mem_desc->esas2r_param = mem_desc->size + align;
+ mem_desc->virt_addr = NULL;
+ mem_desc->phys_addr = 0;
+ mem_desc->esas2r_data = dma_alloc_coherent(&a->pcid->dev,
+ (size_t)mem_desc->
+ esas2r_param,
+ (dma_addr_t *)&mem_desc->
+ phys_addr,
+ GFP_KERNEL);
+
+ if (mem_desc->esas2r_data == NULL) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "failed to allocate %lu bytes of consistent memory!",
+ (long
+ unsigned
+ int)mem_desc->esas2r_param);
+ return false;
+ }
+
+ mem_desc->virt_addr = PTR_ALIGN(mem_desc->esas2r_data, align);
+ mem_desc->phys_addr = ALIGN(mem_desc->phys_addr, align);
+ memset(mem_desc->virt_addr, 0, mem_desc->size);
+ return true;
+}
+
+static void esas2r_initmem_free(struct esas2r_adapter *a,
+ struct esas2r_mem_desc *mem_desc)
+{
+ if (mem_desc->virt_addr == NULL)
+ return;
+
+ /*
+ * Careful! phys_addr and virt_addr may have been adjusted from the
+ * original allocation in order to return the desired alignment. That
+ * means we have to use the original address (in esas2r_data) and size
+ * (esas2r_param) and calculate the original physical address based on
+ * the difference between the requested and actual allocation size.
+ */
+ if (mem_desc->phys_addr) {
+ int unalign = ((u8 *)mem_desc->virt_addr) -
+ ((u8 *)mem_desc->esas2r_data);
+
+ dma_free_coherent(&a->pcid->dev,
+ (size_t)mem_desc->esas2r_param,
+ mem_desc->esas2r_data,
+ (dma_addr_t)(mem_desc->phys_addr - unalign));
+ } else {
+ kfree(mem_desc->esas2r_data);
+ }
+
+ mem_desc->virt_addr = NULL;
+}
+
+static bool alloc_vda_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_mem_desc *memdesc = kzalloc(
+ sizeof(struct esas2r_mem_desc), GFP_KERNEL);
+
+ if (memdesc == NULL) {
+ esas2r_hdebug("could not alloc mem for vda request memdesc\n");
+ return false;
+ }
+
+ memdesc->size = sizeof(union atto_vda_req) +
+ ESAS2R_DATA_BUF_LEN;
+
+ if (!esas2r_initmem_alloc(a, memdesc, 256)) {
+ esas2r_hdebug("could not alloc mem for vda request\n");
+ kfree(memdesc);
+ return false;
+ }
+
+ a->num_vrqs++;
+ list_add(&memdesc->next_desc, &a->vrq_mds_head);
+
+ rq->vrq_md = memdesc;
+ rq->vrq = (union atto_vda_req *)memdesc->virt_addr;
+ rq->vrq->scsi.handle = a->num_vrqs;
+
+ return true;
+}
+
+static void esas2r_unmap_regions(struct esas2r_adapter *a)
+{
+ if (a->regs)
+ iounmap((void __iomem *)a->regs);
+
+ a->regs = NULL;
+
+ pci_release_region(a->pcid, 2);
+
+ if (a->data_window)
+ iounmap((void __iomem *)a->data_window);
+
+ a->data_window = NULL;
+
+ pci_release_region(a->pcid, 0);
+}
+
+static int esas2r_map_regions(struct esas2r_adapter *a)
+{
+ int error;
+
+ a->regs = NULL;
+ a->data_window = NULL;
+
+ error = pci_request_region(a->pcid, 2, a->name);
+ if (error != 0) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "pci_request_region(2) failed, error %d",
+ error);
+
+ return error;
+ }
+
+ a->regs = (void __force *)ioremap(pci_resource_start(a->pcid, 2),
+ pci_resource_len(a->pcid, 2));
+ if (a->regs == NULL) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "ioremap failed for regs mem region\n");
+ pci_release_region(a->pcid, 2);
+ return -EFAULT;
+ }
+
+ error = pci_request_region(a->pcid, 0, a->name);
+ if (error != 0) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "pci_request_region(2) failed, error %d",
+ error);
+ esas2r_unmap_regions(a);
+ return error;
+ }
+
+ a->data_window = (void __force *)ioremap(pci_resource_start(a->pcid,
+ 0),
+ pci_resource_len(a->pcid, 0));
+ if (a->data_window == NULL) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "ioremap failed for data_window mem region\n");
+ esas2r_unmap_regions(a);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void esas2r_setup_interrupts(struct esas2r_adapter *a, int intr_mode)
+{
+ int i;
+
+ /* Set up interrupt mode based on the requested value */
+ switch (intr_mode) {
+ case INTR_MODE_LEGACY:
+use_legacy_interrupts:
+ a->intr_mode = INTR_MODE_LEGACY;
+ break;
+
+ case INTR_MODE_MSI:
+ i = pci_enable_msi(a->pcid);
+ if (i != 0) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "failed to enable MSI for adapter %d, "
+ "falling back to legacy interrupts "
+ "(err=%d)", a->index,
+ i);
+ goto use_legacy_interrupts;
+ }
+ a->intr_mode = INTR_MODE_MSI;
+ esas2r_lock_set_flags(&a->flags2, AF2_MSI_ENABLED);
+ break;
+
+
+ default:
+ esas2r_log(ESAS2R_LOG_WARN,
+ "unknown interrupt_mode %d requested, "
+ "falling back to legacy interrupt",
+ interrupt_mode);
+ goto use_legacy_interrupts;
+ }
+}
+
+static void esas2r_claim_interrupts(struct esas2r_adapter *a)
+{
+ unsigned long flags = IRQF_DISABLED;
+
+ if (a->intr_mode == INTR_MODE_LEGACY)
+ flags |= IRQF_SHARED;
+
+ esas2r_log(ESAS2R_LOG_INFO,
+ "esas2r_claim_interrupts irq=%d (%p, %s, %x)",
+ a->pcid->irq, a, a->name, flags);
+
+ if (request_irq(a->pcid->irq,
+ (a->intr_mode ==
+ INTR_MODE_LEGACY) ? esas2r_interrupt :
+ esas2r_msi_interrupt,
+ flags,
+ a->name,
+ a)) {
+ esas2r_log(ESAS2R_LOG_CRIT, "unable to request IRQ %02X",
+ a->pcid->irq);
+ return;
+ }
+
+ esas2r_lock_set_flags(&a->flags2, AF2_IRQ_CLAIMED);
+ esas2r_log(ESAS2R_LOG_INFO,
+ "claimed IRQ %d flags: 0x%lx",
+ a->pcid->irq, flags);
+}
+
+int esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid,
+ int index)
+{
+ struct esas2r_adapter *a;
+ u64 bus_addr = 0;
+ int i;
+ void *next_uncached;
+ struct esas2r_request *first_request, *last_request;
+
+ if (index >= MAX_ADAPTERS) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "tried to init invalid adapter index %u!",
+ index);
+ return 0;
+ }
+
+ if (esas2r_adapters[index]) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "tried to init existing adapter index %u!",
+ index);
+ return 0;
+ }
+
+ a = (struct esas2r_adapter *)host->hostdata;
+ memset(a, 0, sizeof(struct esas2r_adapter));
+ a->pcid = pcid;
+ a->host = host;
+
+ if (sizeof(dma_addr_t) > 4) {
+ const uint64_t required_mask = dma_get_required_mask
+ (&pcid->dev);
+ if (required_mask > DMA_BIT_MASK(32)
+ && !pci_set_dma_mask(pcid, DMA_BIT_MASK(64))
+ && !pci_set_consistent_dma_mask(pcid,
+ DMA_BIT_MASK(64))) {
+ esas2r_log_dev(ESAS2R_LOG_INFO,
+ &(a->pcid->dev),
+ "64-bit PCI addressing enabled\n");
+ } else if (!pci_set_dma_mask(pcid, DMA_BIT_MASK(32))
+ && !pci_set_consistent_dma_mask(pcid,
+ DMA_BIT_MASK(32))) {
+ esas2r_log_dev(ESAS2R_LOG_INFO,
+ &(a->pcid->dev),
+ "32-bit PCI addressing enabled\n");
+ } else {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "failed to set DMA mask");
+ esas2r_kill_adapter(index);
+ return 0;
+ }
+ } else {
+ if (!pci_set_dma_mask(pcid, DMA_BIT_MASK(32))
+ && !pci_set_consistent_dma_mask(pcid,
+ DMA_BIT_MASK(32))) {
+ esas2r_log_dev(ESAS2R_LOG_INFO,
+ &(a->pcid->dev),
+ "32-bit PCI addressing enabled\n");
+ } else {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "failed to set DMA mask");
+ esas2r_kill_adapter(index);
+ return 0;
+ }
+ }
+ esas2r_adapters[index] = a;
+ sprintf(a->name, ESAS2R_DRVR_NAME "_%02d", index);
+ esas2r_debug("new adapter %p, name %s", a, a->name);
+ spin_lock_init(&a->request_lock);
+ spin_lock_init(&a->fw_event_lock);
+ sema_init(&a->fm_api_semaphore, 1);
+ sema_init(&a->fs_api_semaphore, 1);
+ sema_init(&a->nvram_semaphore, 1);
+
+ esas2r_fw_event_off(a);
+ snprintf(a->fw_event_q_name, ESAS2R_KOBJ_NAME_LEN, "esas2r/%d",
+ a->index);
+ a->fw_event_q = create_singlethread_workqueue(a->fw_event_q_name);
+
+ init_waitqueue_head(&a->buffered_ioctl_waiter);
+ init_waitqueue_head(&a->nvram_waiter);
+ init_waitqueue_head(&a->fm_api_waiter);
+ init_waitqueue_head(&a->fs_api_waiter);
+ init_waitqueue_head(&a->vda_waiter);
+
+ INIT_LIST_HEAD(&a->general_req.req_list);
+ INIT_LIST_HEAD(&a->active_list);
+ INIT_LIST_HEAD(&a->defer_list);
+ INIT_LIST_HEAD(&a->free_sg_list_head);
+ INIT_LIST_HEAD(&a->avail_request);
+ INIT_LIST_HEAD(&a->vrq_mds_head);
+ INIT_LIST_HEAD(&a->fw_event_list);
+
+ first_request = (struct esas2r_request *)((u8 *)(a + 1));
+
+ for (last_request = first_request, i = 1; i < num_requests;
+ last_request++, i++) {
+ INIT_LIST_HEAD(&last_request->req_list);
+ list_add_tail(&last_request->comp_list, &a->avail_request);
+ if (!alloc_vda_req(a, last_request)) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "failed to allocate a VDA request!");
+ esas2r_kill_adapter(index);
+ return 0;
+ }
+ }
+
+ esas2r_debug("requests: %p to %p (%d, %d)", first_request,
+ last_request,
+ sizeof(*first_request),
+ num_requests);
+
+ if (esas2r_map_regions(a) != 0) {
+ esas2r_log(ESAS2R_LOG_CRIT, "could not map PCI regions!");
+ esas2r_kill_adapter(index);
+ return 0;
+ }
+
+ a->index = index;
+
+ /* interrupts will be disabled until we are done with init */
+ atomic_inc(&a->dis_ints_cnt);
+ atomic_inc(&a->disable_cnt);
+ a->flags |= AF_CHPRST_PENDING
+ | AF_DISC_PENDING
+ | AF_FIRST_INIT
+ | AF_LEGACY_SGE_MODE;
+
+ a->init_msg = ESAS2R_INIT_MSG_START;
+ a->max_vdareq_size = 128;
+ a->build_sgl = esas2r_build_sg_list_sge;
+
+ esas2r_setup_interrupts(a, interrupt_mode);
+
+ a->uncached_size = esas2r_get_uncached_size(a);
+ a->uncached = dma_alloc_coherent(&pcid->dev,
+ (size_t)a->uncached_size,
+ (dma_addr_t *)&bus_addr,
+ GFP_KERNEL);
+ if (a->uncached == NULL) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "failed to allocate %d bytes of consistent memory!",
+ a->uncached_size);
+ esas2r_kill_adapter(index);
+ return 0;
+ }
+
+ a->uncached_phys = bus_addr;
+
+ esas2r_debug("%d bytes uncached memory allocated @ %p (%x:%x)",
+ a->uncached_size,
+ a->uncached,
+ upper_32_bits(bus_addr),
+ lower_32_bits(bus_addr));
+ memset(a->uncached, 0, a->uncached_size);
+ next_uncached = a->uncached;
+
+ if (!esas2r_init_adapter_struct(a,
+ &next_uncached)) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "failed to initialize adapter structure (2)!");
+ esas2r_kill_adapter(index);
+ return 0;
+ }
+
+ tasklet_init(&a->tasklet,
+ esas2r_adapter_tasklet,
+ (unsigned long)a);
+
+ /*
+ * Disable chip interrupts to prevent spurious interrupts
+ * until we claim the IRQ.
+ */
+ esas2r_disable_chip_interrupts(a);
+ esas2r_check_adapter(a);
+
+ if (!esas2r_init_adapter_hw(a, true))
+ esas2r_log(ESAS2R_LOG_CRIT, "failed to initialize hardware!");
+ else
+ esas2r_debug("esas2r_init_adapter ok");
+
+ esas2r_claim_interrupts(a);
+
+ if (a->flags2 & AF2_IRQ_CLAIMED)
+ esas2r_enable_chip_interrupts(a);
+
+ esas2r_lock_set_flags(&a->flags2, AF2_INIT_DONE);
+ if (!(a->flags & AF_DEGRADED_MODE))
+ esas2r_kickoff_timer(a);
+ esas2r_debug("esas2r_init_adapter done for %p (%d)",
+ a, a->disable_cnt);
+
+ return 1;
+}
+
+static void esas2r_adapter_power_down(struct esas2r_adapter *a,
+ int power_management)
+{
+ struct esas2r_mem_desc *memdesc, *next;
+
+ if ((a->flags2 & AF2_INIT_DONE)
+ && (!(a->flags & AF_DEGRADED_MODE))) {
+ if (!power_management) {
+ del_timer_sync(&a->timer);
+ tasklet_kill(&a->tasklet);
+ }
+ esas2r_power_down(a);
+
+ /*
+ * There are versions of firmware that do not handle the sync
+ * cache command correctly. Stall here to ensure that the
+ * cache is lazily flushed.
+ */
+ mdelay(500);
+ esas2r_debug("chip halted");
+ }
+
+ /* Remove sysfs binary files */
+ if (a->sysfs_fw_created) {
+ sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_fw);
+ a->sysfs_fw_created = 0;
+ }
+
+ if (a->sysfs_fs_created) {
+ sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_fs);
+ a->sysfs_fs_created = 0;
+ }
+
+ if (a->sysfs_vda_created) {
+ sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_vda);
+ a->sysfs_vda_created = 0;
+ }
+
+ if (a->sysfs_hw_created) {
+ sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_hw);
+ a->sysfs_hw_created = 0;
+ }
+
+ if (a->sysfs_live_nvram_created) {
+ sysfs_remove_bin_file(&a->host->shost_dev.kobj,
+ &bin_attr_live_nvram);
+ a->sysfs_live_nvram_created = 0;
+ }
+
+ if (a->sysfs_default_nvram_created) {
+ sysfs_remove_bin_file(&a->host->shost_dev.kobj,
+ &bin_attr_default_nvram);
+ a->sysfs_default_nvram_created = 0;
+ }
+
+ /* Clean up interrupts */
+ if (a->flags2 & AF2_IRQ_CLAIMED) {
+ esas2r_log_dev(ESAS2R_LOG_INFO,
+ &(a->pcid->dev),
+ "free_irq(%d) called", a->pcid->irq);
+
+ free_irq(a->pcid->irq, a);
+ esas2r_debug("IRQ released");
+ esas2r_lock_clear_flags(&a->flags2, AF2_IRQ_CLAIMED);
+ }
+
+ if (a->flags2 & AF2_MSI_ENABLED) {
+ pci_disable_msi(a->pcid);
+ esas2r_lock_clear_flags(&a->flags2, AF2_MSI_ENABLED);
+ esas2r_debug("MSI disabled");
+ }
+
+ if (a->inbound_list_md.virt_addr)
+ esas2r_initmem_free(a, &a->inbound_list_md);
+
+ if (a->outbound_list_md.virt_addr)
+ esas2r_initmem_free(a, &a->outbound_list_md);
+
+ list_for_each_entry_safe(memdesc, next, &a->free_sg_list_head,
+ next_desc) {
+ esas2r_initmem_free(a, memdesc);
+ }
+
+ /* Following frees everything allocated via alloc_vda_req */
+ list_for_each_entry_safe(memdesc, next, &a->vrq_mds_head, next_desc) {
+ esas2r_initmem_free(a, memdesc);
+ list_del(&memdesc->next_desc);
+ kfree(memdesc);
+ }
+
+ kfree(a->first_ae_req);
+ a->first_ae_req = NULL;
+
+ kfree(a->sg_list_mds);
+ a->sg_list_mds = NULL;
+
+ kfree(a->req_table);
+ a->req_table = NULL;
+
+ if (a->regs) {
+ esas2r_unmap_regions(a);
+ a->regs = NULL;
+ a->data_window = NULL;
+ esas2r_debug("regions unmapped");
+ }
+}
+
+/* Release/free allocated resources for specified adapters. */
+void esas2r_kill_adapter(int i)
+{
+ struct esas2r_adapter *a = esas2r_adapters[i];
+
+ if (a) {
+ unsigned long flags;
+ struct workqueue_struct *wq;
+ esas2r_debug("killing adapter %p [%d] ", a, i);
+ esas2r_fw_event_off(a);
+ esas2r_adapter_power_down(a, 0);
+ if (esas2r_buffered_ioctl &&
+ (a->pcid == esas2r_buffered_ioctl_pcid)) {
+ dma_free_coherent(&a->pcid->dev,
+ (size_t)esas2r_buffered_ioctl_size,
+ esas2r_buffered_ioctl,
+ esas2r_buffered_ioctl_addr);
+ esas2r_buffered_ioctl = NULL;
+ }
+
+ if (a->vda_buffer) {
+ dma_free_coherent(&a->pcid->dev,
+ (size_t)VDA_MAX_BUFFER_SIZE,
+ a->vda_buffer,
+ (dma_addr_t)a->ppvda_buffer);
+ a->vda_buffer = NULL;
+ }
+ if (a->fs_api_buffer) {
+ dma_free_coherent(&a->pcid->dev,
+ (size_t)a->fs_api_buffer_size,
+ a->fs_api_buffer,
+ (dma_addr_t)a->ppfs_api_buffer);
+ a->fs_api_buffer = NULL;
+ }
+
+ kfree(a->local_atto_ioctl);
+ a->local_atto_ioctl = NULL;
+
+ spin_lock_irqsave(&a->fw_event_lock, flags);
+ wq = a->fw_event_q;
+ a->fw_event_q = NULL;
+ spin_unlock_irqrestore(&a->fw_event_lock, flags);
+ if (wq)
+ destroy_workqueue(wq);
+
+ if (a->uncached) {
+ dma_free_coherent(&a->pcid->dev,
+ (size_t)a->uncached_size,
+ a->uncached,
+ (dma_addr_t)a->uncached_phys);
+ a->uncached = NULL;
+ esas2r_debug("uncached area freed");
+ }
+
+ esas2r_log_dev(ESAS2R_LOG_INFO,
+ &(a->pcid->dev),
+ "pci_disable_device() called. msix_enabled: %d "
+ "msi_enabled: %d irq: %d pin: %d",
+ a->pcid->msix_enabled,
+ a->pcid->msi_enabled,
+ a->pcid->irq,
+ a->pcid->pin);
+
+ esas2r_log_dev(ESAS2R_LOG_INFO,
+ &(a->pcid->dev),
+ "before pci_disable_device() enable_cnt: %d",
+ a->pcid->enable_cnt.counter);
+
+ pci_disable_device(a->pcid);
+ esas2r_log_dev(ESAS2R_LOG_INFO,
+ &(a->pcid->dev),
+ "after pci_disable_device() enable_cnt: %d",
+ a->pcid->enable_cnt.counter);
+
+ esas2r_log_dev(ESAS2R_LOG_INFO,
+ &(a->pcid->dev),
+ "pci_set_drv_data(%p, NULL) called",
+ a->pcid);
+
+ pci_set_drvdata(a->pcid, NULL);
+ esas2r_adapters[i] = NULL;
+
+ if (a->flags2 & AF2_INIT_DONE) {
+ esas2r_lock_clear_flags(&a->flags2,
+ AF2_INIT_DONE);
+
+ esas2r_lock_set_flags(&a->flags,
+ AF_DEGRADED_MODE);
+
+ esas2r_log_dev(ESAS2R_LOG_INFO,
+ &(a->host->shost_gendev),
+ "scsi_remove_host() called");
+
+ scsi_remove_host(a->host);
+
+ esas2r_log_dev(ESAS2R_LOG_INFO,
+ &(a->host->shost_gendev),
+ "scsi_host_put() called");
+
+ scsi_host_put(a->host);
+ }
+ }
+}
+
+int esas2r_cleanup(struct Scsi_Host *host)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata;
+ int index;
+
+ if (host == NULL) {
+ int i;
+
+ esas2r_debug("esas2r_cleanup everything");
+ for (i = 0; i < MAX_ADAPTERS; i++)
+ esas2r_kill_adapter(i);
+ return -1;
+ }
+
+ esas2r_debug("esas2r_cleanup called for host %p", host);
+ index = a->index;
+ esas2r_kill_adapter(index);
+ return index;
+}
+
+int esas2r_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ u32 device_state;
+ struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata;
+
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "suspending adapter()");
+ if (!a)
+ return -ENODEV;
+
+ esas2r_adapter_power_down(a, 1);
+ device_state = pci_choose_state(pdev, state);
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+ "pci_save_state() called");
+ pci_save_state(pdev);
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+ "pci_disable_device() called");
+ pci_disable_device(pdev);
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+ "pci_set_power_state() called");
+ pci_set_power_state(pdev, device_state);
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "esas2r_suspend(): 0");
+ return 0;
+}
+
+int esas2r_resume(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata;
+ int rez;
+
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "resuming adapter()");
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+ "pci_set_power_state(PCI_D0) "
+ "called");
+ pci_set_power_state(pdev, PCI_D0);
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+ "pci_enable_wake(PCI_D0, 0) "
+ "called");
+ pci_enable_wake(pdev, PCI_D0, 0);
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+ "pci_restore_state() called");
+ pci_restore_state(pdev);
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+ "pci_enable_device() called");
+ rez = pci_enable_device(pdev);
+ pci_set_master(pdev);
+
+ if (!a) {
+ rez = -ENODEV;
+ goto error_exit;
+ }
+
+ if (esas2r_map_regions(a) != 0) {
+ esas2r_log(ESAS2R_LOG_CRIT, "could not re-map PCI regions!");
+ rez = -ENOMEM;
+ goto error_exit;
+ }
+
+ /* Set up interupt mode */
+ esas2r_setup_interrupts(a, a->intr_mode);
+
+ /*
+ * Disable chip interrupts to prevent spurious interrupts until we
+ * claim the IRQ.
+ */
+ esas2r_disable_chip_interrupts(a);
+ if (!esas2r_power_up(a, true)) {
+ esas2r_debug("yikes, esas2r_power_up failed");
+ rez = -ENOMEM;
+ goto error_exit;
+ }
+
+ esas2r_claim_interrupts(a);
+
+ if (a->flags2 & AF2_IRQ_CLAIMED) {
+ /*
+ * Now that system interrupt(s) are claimed, we can enable
+ * chip interrupts.
+ */
+ esas2r_enable_chip_interrupts(a);
+ esas2r_kickoff_timer(a);
+ } else {
+ esas2r_debug("yikes, unable to claim IRQ");
+ esas2r_log(ESAS2R_LOG_CRIT, "could not re-claim IRQ!");
+ rez = -ENOMEM;
+ goto error_exit;
+ }
+
+error_exit:
+ esas2r_log_dev(ESAS2R_LOG_CRIT, &(pdev->dev), "esas2r_resume(): %d",
+ rez);
+ return rez;
+}
+
+bool esas2r_set_degraded_mode(struct esas2r_adapter *a, char *error_str)
+{
+ esas2r_lock_set_flags(&a->flags, AF_DEGRADED_MODE);
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "setting adapter to degraded mode: %s\n", error_str);
+ return false;
+}
+
+u32 esas2r_get_uncached_size(struct esas2r_adapter *a)
+{
+ return sizeof(struct esas2r_sas_nvram)
+ + ALIGN(ESAS2R_DISC_BUF_LEN, 8)
+ + ALIGN(sizeof(u32), 8) /* outbound list copy pointer */
+ + 8
+ + (num_sg_lists * (u16)sgl_page_size)
+ + ALIGN((num_requests + num_ae_requests + 1 +
+ ESAS2R_LIST_EXTRA) *
+ sizeof(struct esas2r_inbound_list_source_entry),
+ 8)
+ + ALIGN((num_requests + num_ae_requests + 1 +
+ ESAS2R_LIST_EXTRA) *
+ sizeof(struct atto_vda_ob_rsp), 8)
+ + 256; /* VDA request and buffer align */
+}
+
+static void esas2r_init_pci_cfg_space(struct esas2r_adapter *a)
+{
+ int pcie_cap_reg;
+
+ pcie_cap_reg = pci_find_capability(a->pcid, PCI_CAP_ID_EXP);
+ if (0xffff && pcie_cap_reg) {
+ u16 devcontrol;
+
+ pci_read_config_word(a->pcid, pcie_cap_reg + PCI_EXP_DEVCTL,
+ &devcontrol);
+
+ if ((devcontrol & PCI_EXP_DEVCTL_READRQ) > 0x2000) {
+ esas2r_log(ESAS2R_LOG_INFO,
+ "max read request size > 512B");
+
+ devcontrol &= ~PCI_EXP_DEVCTL_READRQ;
+ devcontrol |= 0x2000;
+ pci_write_config_word(a->pcid,
+ pcie_cap_reg + PCI_EXP_DEVCTL,
+ devcontrol);
+ }
+ }
+}
+
+/*
+ * Determine the organization of the uncached data area and
+ * finish initializing the adapter structure
+ */
+bool esas2r_init_adapter_struct(struct esas2r_adapter *a,
+ void **uncached_area)
+{
+ u32 i;
+ u8 *high;
+ struct esas2r_inbound_list_source_entry *element;
+ struct esas2r_request *rq;
+ struct esas2r_mem_desc *sgl;
+
+ spin_lock_init(&a->sg_list_lock);
+ spin_lock_init(&a->mem_lock);
+ spin_lock_init(&a->queue_lock);
+
+ a->targetdb_end = &a->targetdb[ESAS2R_MAX_TARGETS];
+
+ if (!alloc_vda_req(a, &a->general_req)) {
+ esas2r_hdebug(
+ "failed to allocate a VDA request for the general req!");
+ return false;
+ }
+
+ /* allocate requests for asynchronous events */
+ a->first_ae_req =
+ kzalloc(num_ae_requests * sizeof(struct esas2r_request),
+ GFP_KERNEL);
+
+ if (a->first_ae_req == NULL) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "failed to allocate memory for asynchronous events");
+ return false;
+ }
+
+ /* allocate the S/G list memory descriptors */
+ a->sg_list_mds = kzalloc(
+ num_sg_lists * sizeof(struct esas2r_mem_desc), GFP_KERNEL);
+
+ if (a->sg_list_mds == NULL) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "failed to allocate memory for s/g list descriptors");
+ return false;
+ }
+
+ /* allocate the request table */
+ a->req_table =
+ kzalloc((num_requests + num_ae_requests +
+ 1) * sizeof(struct esas2r_request *), GFP_KERNEL);
+
+ if (a->req_table == NULL) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "failed to allocate memory for the request table");
+ return false;
+ }
+
+ /* initialize PCI configuration space */
+ esas2r_init_pci_cfg_space(a);
+
+ /*
+ * the thunder_stream boards all have a serial flash part that has a
+ * different base address on the AHB bus.
+ */
+ if ((a->pcid->subsystem_vendor == ATTO_VENDOR_ID)
+ && (a->pcid->subsystem_device & ATTO_SSDID_TBT))
+ a->flags2 |= AF2_THUNDERBOLT;
+
+ if (a->flags2 & AF2_THUNDERBOLT)
+ a->flags2 |= AF2_SERIAL_FLASH;
+
+ if (a->pcid->subsystem_device == ATTO_TLSH_1068)
+ a->flags2 |= AF2_THUNDERLINK;
+
+ /* Uncached Area */
+ high = (u8 *)*uncached_area;
+
+ /* initialize the scatter/gather table pages */
+
+ for (i = 0, sgl = a->sg_list_mds; i < num_sg_lists; i++, sgl++) {
+ sgl->size = sgl_page_size;
+
+ list_add_tail(&sgl->next_desc, &a->free_sg_list_head);
+
+ if (!esas2r_initmem_alloc(a, sgl, ESAS2R_SGL_ALIGN)) {
+ /* Allow the driver to load if the minimum count met. */
+ if (i < NUM_SGL_MIN)
+ return false;
+ break;
+ }
+ }
+
+ /* compute the size of the lists */
+ a->list_size = num_requests + ESAS2R_LIST_EXTRA;
+
+ /* allocate the inbound list */
+ a->inbound_list_md.size = a->list_size *
+ sizeof(struct
+ esas2r_inbound_list_source_entry);
+
+ if (!esas2r_initmem_alloc(a, &a->inbound_list_md, ESAS2R_LIST_ALIGN)) {
+ esas2r_hdebug("failed to allocate IB list");
+ return false;
+ }
+
+ /* allocate the outbound list */
+ a->outbound_list_md.size = a->list_size *
+ sizeof(struct atto_vda_ob_rsp);
+
+ if (!esas2r_initmem_alloc(a, &a->outbound_list_md,
+ ESAS2R_LIST_ALIGN)) {
+ esas2r_hdebug("failed to allocate IB list");
+ return false;
+ }
+
+ /* allocate the NVRAM structure */
+ a->nvram = (struct esas2r_sas_nvram *)high;
+ high += sizeof(struct esas2r_sas_nvram);
+
+ /* allocate the discovery buffer */
+ a->disc_buffer = high;
+ high += ESAS2R_DISC_BUF_LEN;
+ high = PTR_ALIGN(high, 8);
+
+ /* allocate the outbound list copy pointer */
+ a->outbound_copy = (u32 volatile *)high;
+ high += sizeof(u32);
+
+ if (!(a->flags & AF_NVR_VALID))
+ esas2r_nvram_set_defaults(a);
+
+ /* update the caller's uncached memory area pointer */
+ *uncached_area = (void *)high;
+
+ /* initialize the allocated memory */
+ if (a->flags & AF_FIRST_INIT) {
+ memset(a->req_table, 0,
+ (num_requests + num_ae_requests +
+ 1) * sizeof(struct esas2r_request *));
+
+ esas2r_targ_db_initialize(a);
+
+ /* prime parts of the inbound list */
+ element =
+ (struct esas2r_inbound_list_source_entry *)a->
+ inbound_list_md.
+ virt_addr;
+
+ for (i = 0; i < a->list_size; i++) {
+ element->address = 0;
+ element->reserved = 0;
+ element->length = cpu_to_le32(HWILSE_INTERFACE_F0
+ | (sizeof(union
+ atto_vda_req)
+ /
+ sizeof(u32)));
+ element++;
+ }
+
+ /* init the AE requests */
+ for (rq = a->first_ae_req, i = 0; i < num_ae_requests; rq++,
+ i++) {
+ INIT_LIST_HEAD(&rq->req_list);
+ if (!alloc_vda_req(a, rq)) {
+ esas2r_hdebug(
+ "failed to allocate a VDA request!");
+ return false;
+ }
+
+ esas2r_rq_init_request(rq, a);
+
+ /* override the completion function */
+ rq->comp_cb = esas2r_ae_complete;
+ }
+ }
+
+ return true;
+}
+
+/* This code will verify that the chip is operational. */
+bool esas2r_check_adapter(struct esas2r_adapter *a)
+{
+ u32 starttime;
+ u32 doorbell;
+ u64 ppaddr;
+ u32 dw;
+
+ /*
+ * if the chip reset detected flag is set, we can bypass a bunch of
+ * stuff.
+ */
+ if (a->flags & AF_CHPRST_DETECTED)
+ goto skip_chip_reset;
+
+ /*
+ * BEFORE WE DO ANYTHING, disable the chip interrupts! the boot driver
+ * may have left them enabled or we may be recovering from a fault.
+ */
+ esas2r_write_register_dword(a, MU_INT_MASK_OUT, ESAS2R_INT_DIS_MASK);
+ esas2r_flush_register_dword(a, MU_INT_MASK_OUT);
+
+ /*
+ * wait for the firmware to become ready by forcing an interrupt and
+ * waiting for a response.
+ */
+ starttime = jiffies_to_msecs(jiffies);
+
+ while (true) {
+ esas2r_force_interrupt(a);
+ doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+ if (doorbell == 0xFFFFFFFF) {
+ /*
+ * Give the firmware up to two seconds to enable
+ * register access after a reset.
+ */
+ if ((jiffies_to_msecs(jiffies) - starttime) > 2000)
+ return esas2r_set_degraded_mode(a,
+ "unable to access registers");
+ } else if (doorbell & DRBL_FORCE_INT) {
+ u32 ver = (doorbell & DRBL_FW_VER_MSK);
+
+ /*
+ * This driver supports version 0 and version 1 of
+ * the API
+ */
+ esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+ doorbell);
+
+ if (ver == DRBL_FW_VER_0) {
+ esas2r_lock_set_flags(&a->flags,
+ AF_LEGACY_SGE_MODE);
+
+ a->max_vdareq_size = 128;
+ a->build_sgl = esas2r_build_sg_list_sge;
+ } else if (ver == DRBL_FW_VER_1) {
+ esas2r_lock_clear_flags(&a->flags,
+ AF_LEGACY_SGE_MODE);
+
+ a->max_vdareq_size = 1024;
+ a->build_sgl = esas2r_build_sg_list_prd;
+ } else {
+ return esas2r_set_degraded_mode(a,
+ "unknown firmware version");
+ }
+ break;
+ }
+
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ if ((jiffies_to_msecs(jiffies) - starttime) > 180000) {
+ esas2r_hdebug("FW ready TMO");
+ esas2r_bugon();
+
+ return esas2r_set_degraded_mode(a,
+ "firmware start has timed out");
+ }
+ }
+
+ /* purge any asynchronous events since we will repost them later */
+ esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_MSG_IFC_DOWN);
+ starttime = jiffies_to_msecs(jiffies);
+
+ while (true) {
+ doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+ if (doorbell & DRBL_MSG_IFC_DOWN) {
+ esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+ doorbell);
+ break;
+ }
+
+ schedule_timeout_interruptible(msecs_to_jiffies(50));
+
+ if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
+ esas2r_hdebug("timeout waiting for interface down");
+ break;
+ }
+ }
+skip_chip_reset:
+ /*
+ * first things first, before we go changing any of these registers
+ * disable the communication lists.
+ */
+ dw = esas2r_read_register_dword(a, MU_IN_LIST_CONFIG);
+ dw &= ~MU_ILC_ENABLE;
+ esas2r_write_register_dword(a, MU_IN_LIST_CONFIG, dw);
+ dw = esas2r_read_register_dword(a, MU_OUT_LIST_CONFIG);
+ dw &= ~MU_OLC_ENABLE;
+ esas2r_write_register_dword(a, MU_OUT_LIST_CONFIG, dw);
+
+ /* configure the communication list addresses */
+ ppaddr = a->inbound_list_md.phys_addr;
+ esas2r_write_register_dword(a, MU_IN_LIST_ADDR_LO,
+ lower_32_bits(ppaddr));
+ esas2r_write_register_dword(a, MU_IN_LIST_ADDR_HI,
+ upper_32_bits(ppaddr));
+ ppaddr = a->outbound_list_md.phys_addr;
+ esas2r_write_register_dword(a, MU_OUT_LIST_ADDR_LO,
+ lower_32_bits(ppaddr));
+ esas2r_write_register_dword(a, MU_OUT_LIST_ADDR_HI,
+ upper_32_bits(ppaddr));
+ ppaddr = a->uncached_phys +
+ ((u8 *)a->outbound_copy - a->uncached);
+ esas2r_write_register_dword(a, MU_OUT_LIST_COPY_PTR_LO,
+ lower_32_bits(ppaddr));
+ esas2r_write_register_dword(a, MU_OUT_LIST_COPY_PTR_HI,
+ upper_32_bits(ppaddr));
+
+ /* reset the read and write pointers */
+ *a->outbound_copy =
+ a->last_write =
+ a->last_read = a->list_size - 1;
+ esas2r_lock_set_flags(&a->flags, AF_COMM_LIST_TOGGLE);
+ esas2r_write_register_dword(a, MU_IN_LIST_WRITE, MU_ILW_TOGGLE |
+ a->last_write);
+ esas2r_write_register_dword(a, MU_OUT_LIST_COPY, MU_OLC_TOGGLE |
+ a->last_write);
+ esas2r_write_register_dword(a, MU_IN_LIST_READ, MU_ILR_TOGGLE |
+ a->last_write);
+ esas2r_write_register_dword(a, MU_OUT_LIST_WRITE,
+ MU_OLW_TOGGLE | a->last_write);
+
+ /* configure the interface select fields */
+ dw = esas2r_read_register_dword(a, MU_IN_LIST_IFC_CONFIG);
+ dw &= ~(MU_ILIC_LIST | MU_ILIC_DEST);
+ esas2r_write_register_dword(a, MU_IN_LIST_IFC_CONFIG,
+ (dw | MU_ILIC_LIST_F0 | MU_ILIC_DEST_DDR));
+ dw = esas2r_read_register_dword(a, MU_OUT_LIST_IFC_CONFIG);
+ dw &= ~(MU_OLIC_LIST | MU_OLIC_SOURCE);
+ esas2r_write_register_dword(a, MU_OUT_LIST_IFC_CONFIG,
+ (dw | MU_OLIC_LIST_F0 |
+ MU_OLIC_SOURCE_DDR));
+
+ /* finish configuring the communication lists */
+ dw = esas2r_read_register_dword(a, MU_IN_LIST_CONFIG);
+ dw &= ~(MU_ILC_ENTRY_MASK | MU_ILC_NUMBER_MASK);
+ dw |= MU_ILC_ENTRY_4_DW | MU_ILC_DYNAMIC_SRC
+ | (a->list_size << MU_ILC_NUMBER_SHIFT);
+ esas2r_write_register_dword(a, MU_IN_LIST_CONFIG, dw);
+ dw = esas2r_read_register_dword(a, MU_OUT_LIST_CONFIG);
+ dw &= ~(MU_OLC_ENTRY_MASK | MU_OLC_NUMBER_MASK);
+ dw |= MU_OLC_ENTRY_4_DW | (a->list_size << MU_OLC_NUMBER_SHIFT);
+ esas2r_write_register_dword(a, MU_OUT_LIST_CONFIG, dw);
+
+ /*
+ * notify the firmware that we're done setting up the communication
+ * list registers. wait here until the firmware is done configuring
+ * its lists. it will signal that it is done by enabling the lists.
+ */
+ esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_MSG_IFC_INIT);
+ starttime = jiffies_to_msecs(jiffies);
+
+ while (true) {
+ doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+ if (doorbell & DRBL_MSG_IFC_INIT) {
+ esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+ doorbell);
+ break;
+ }
+
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
+ esas2r_hdebug(
+ "timeout waiting for communication list init");
+ esas2r_bugon();
+ return esas2r_set_degraded_mode(a,
+ "timeout waiting for communication list init");
+ }
+ }
+
+ /*
+ * flag whether the firmware supports the power down doorbell. we
+ * determine this by reading the inbound doorbell enable mask.
+ */
+ doorbell = esas2r_read_register_dword(a, MU_DOORBELL_IN_ENB);
+ if (doorbell & DRBL_POWER_DOWN)
+ esas2r_lock_set_flags(&a->flags2, AF2_VDA_POWER_DOWN);
+ else
+ esas2r_lock_clear_flags(&a->flags2, AF2_VDA_POWER_DOWN);
+
+ /*
+ * enable assertion of outbound queue and doorbell interrupts in the
+ * main interrupt cause register.
+ */
+ esas2r_write_register_dword(a, MU_OUT_LIST_INT_MASK, MU_OLIS_MASK);
+ esas2r_write_register_dword(a, MU_DOORBELL_OUT_ENB, DRBL_ENB_MASK);
+ return true;
+}
+
+/* Process the initialization message just completed and format the next one. */
+static bool esas2r_format_init_msg(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ u32 msg = a->init_msg;
+ struct atto_vda_cfg_init *ci;
+
+ a->init_msg = 0;
+
+ switch (msg) {
+ case ESAS2R_INIT_MSG_START:
+ case ESAS2R_INIT_MSG_REINIT:
+ {
+ struct timeval now;
+ do_gettimeofday(&now);
+ esas2r_hdebug("CFG init");
+ esas2r_build_cfg_req(a,
+ rq,
+ VDA_CFG_INIT,
+ 0,
+ NULL);
+ ci = (struct atto_vda_cfg_init *)&rq->vrq->cfg.data.init;
+ ci->sgl_page_size = sgl_page_size;
+ ci->epoch_time = now.tv_sec;
+ rq->flags |= RF_FAILURE_OK;
+ a->init_msg = ESAS2R_INIT_MSG_INIT;
+ break;
+ }
+
+ case ESAS2R_INIT_MSG_INIT:
+ if (rq->req_stat == RS_SUCCESS) {
+ u32 major;
+ u32 minor;
+
+ a->fw_version = le16_to_cpu(
+ rq->func_rsp.cfg_rsp.vda_version);
+ a->fw_build = rq->func_rsp.cfg_rsp.fw_build;
+ major = LOBYTE(rq->func_rsp.cfg_rsp.fw_release);
+ minor = HIBYTE(rq->func_rsp.cfg_rsp.fw_release);
+ a->fw_version += (major << 16) + (minor << 24);
+ } else {
+ esas2r_hdebug("FAILED");
+ }
+
+ /*
+ * the 2.71 and earlier releases of R6xx firmware did not error
+ * unsupported config requests correctly.
+ */
+
+ if ((a->flags2 & AF2_THUNDERBOLT)
+ || (be32_to_cpu(a->fw_version) >
+ be32_to_cpu(0x47020052))) {
+ esas2r_hdebug("CFG get init");
+ esas2r_build_cfg_req(a,
+ rq,
+ VDA_CFG_GET_INIT2,
+ sizeof(struct atto_vda_cfg_init),
+ NULL);
+
+ rq->vrq->cfg.sg_list_offset = offsetof(
+ struct atto_vda_cfg_req,
+ data.sge);
+ rq->vrq->cfg.data.prde.ctl_len =
+ cpu_to_le32(sizeof(struct atto_vda_cfg_init));
+ rq->vrq->cfg.data.prde.address = cpu_to_le64(
+ rq->vrq_md->phys_addr +
+ sizeof(union atto_vda_req));
+ rq->flags |= RF_FAILURE_OK;
+ a->init_msg = ESAS2R_INIT_MSG_GET_INIT;
+ break;
+ }
+
+ case ESAS2R_INIT_MSG_GET_INIT:
+ if (msg == ESAS2R_INIT_MSG_GET_INIT) {
+ ci = (struct atto_vda_cfg_init *)rq->data_buf;
+ if (rq->req_stat == RS_SUCCESS) {
+ a->num_targets_backend =
+ le32_to_cpu(ci->num_targets_backend);
+ a->ioctl_tunnel =
+ le32_to_cpu(ci->ioctl_tunnel);
+ } else {
+ esas2r_hdebug("FAILED");
+ }
+ }
+ /* fall through */
+
+ default:
+ rq->req_stat = RS_SUCCESS;
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Perform initialization messages via the request queue. Messages are
+ * performed with interrupts disabled.
+ */
+bool esas2r_init_msgs(struct esas2r_adapter *a)
+{
+ bool success = true;
+ struct esas2r_request *rq = &a->general_req;
+
+ esas2r_rq_init_request(rq, a);
+ rq->comp_cb = esas2r_dummy_complete;
+
+ if (a->init_msg == 0)
+ a->init_msg = ESAS2R_INIT_MSG_REINIT;
+
+ while (a->init_msg) {
+ if (esas2r_format_init_msg(a, rq)) {
+ unsigned long flags;
+ while (true) {
+ spin_lock_irqsave(&a->queue_lock, flags);
+ esas2r_start_vda_request(a, rq);
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+ esas2r_wait_request(a, rq);
+ if (rq->req_stat != RS_PENDING)
+ break;
+ }
+ }
+
+ if (rq->req_stat == RS_SUCCESS
+ || ((rq->flags & RF_FAILURE_OK)
+ && rq->req_stat != RS_TIMEOUT))
+ continue;
+
+ esas2r_log(ESAS2R_LOG_CRIT, "init message %x failed (%x, %x)",
+ a->init_msg, rq->req_stat, rq->flags);
+ a->init_msg = ESAS2R_INIT_MSG_START;
+ success = false;
+ break;
+ }
+
+ esas2r_rq_destroy_request(rq, a);
+ return success;
+}
+
+/* Initialize the adapter chip */
+bool esas2r_init_adapter_hw(struct esas2r_adapter *a, bool init_poll)
+{
+ bool rslt = false;
+ struct esas2r_request *rq;
+ u32 i;
+
+ if (a->flags & AF_DEGRADED_MODE)
+ goto exit;
+
+ if (!(a->flags & AF_NVR_VALID)) {
+ if (!esas2r_nvram_read_direct(a))
+ esas2r_log(ESAS2R_LOG_WARN,
+ "invalid/missing NVRAM parameters");
+ }
+
+ if (!esas2r_init_msgs(a)) {
+ esas2r_set_degraded_mode(a, "init messages failed");
+ goto exit;
+ }
+
+ /* The firmware is ready. */
+ esas2r_lock_clear_flags(&a->flags, AF_DEGRADED_MODE);
+ esas2r_lock_clear_flags(&a->flags, AF_CHPRST_PENDING);
+
+ /* Post all the async event requests */
+ for (i = 0, rq = a->first_ae_req; i < num_ae_requests; i++, rq++)
+ esas2r_start_ae_request(a, rq);
+
+ if (!a->flash_rev[0])
+ esas2r_read_flash_rev(a);
+
+ if (!a->image_type[0])
+ esas2r_read_image_type(a);
+
+ if (a->fw_version == 0)
+ a->fw_rev[0] = 0;
+ else
+ sprintf(a->fw_rev, "%1d.%02d",
+ (int)LOBYTE(HIWORD(a->fw_version)),
+ (int)HIBYTE(HIWORD(a->fw_version)));
+
+ esas2r_hdebug("firmware revision: %s", a->fw_rev);
+
+ if ((a->flags & AF_CHPRST_DETECTED)
+ && (a->flags & AF_FIRST_INIT)) {
+ esas2r_enable_chip_interrupts(a);
+ return true;
+ }
+
+ /* initialize discovery */
+ esas2r_disc_initialize(a);
+
+ /*
+ * wait for the device wait time to expire here if requested. this is
+ * usually requested during initial driver load and possibly when
+ * resuming from a low power state. deferred device waiting will use
+ * interrupts. chip reset recovery always defers device waiting to
+ * avoid being in a TASKLET too long.
+ */
+ if (init_poll) {
+ u32 currtime = a->disc_start_time;
+ u32 nexttick = 100;
+ u32 deltatime;
+
+ /*
+ * Block Tasklets from getting scheduled and indicate this is
+ * polled discovery.
+ */
+ esas2r_lock_set_flags(&a->flags, AF_TASKLET_SCHEDULED);
+ esas2r_lock_set_flags(&a->flags, AF_DISC_POLLED);
+
+ /*
+ * Temporarily bring the disable count to zero to enable
+ * deferred processing. Note that the count is already zero
+ * after the first initialization.
+ */
+ if (a->flags & AF_FIRST_INIT)
+ atomic_dec(&a->disable_cnt);
+
+ while (a->flags & AF_DISC_PENDING) {
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ /*
+ * Determine the need for a timer tick based on the
+ * delta time between this and the last iteration of
+ * this loop. We don't use the absolute time because
+ * then we would have to worry about when nexttick
+ * wraps and currtime hasn't yet.
+ */
+ deltatime = jiffies_to_msecs(jiffies) - currtime;
+ currtime += deltatime;
+
+ /*
+ * Process any waiting discovery as long as the chip is
+ * up. If a chip reset happens during initial polling,
+ * we have to make sure the timer tick processes the
+ * doorbell indicating the firmware is ready.
+ */
+ if (!(a->flags & AF_CHPRST_PENDING))
+ esas2r_disc_check_for_work(a);
+
+ /* Simulate a timer tick. */
+ if (nexttick <= deltatime) {
+
+ /* Time for a timer tick */
+ nexttick += 100;
+ esas2r_timer_tick(a);
+ }
+
+ if (nexttick > deltatime)
+ nexttick -= deltatime;
+
+ /* Do any deferred processing */
+ if (esas2r_is_tasklet_pending(a))
+ esas2r_do_tasklet_tasks(a);
+
+ }
+
+ if (a->flags & AF_FIRST_INIT)
+ atomic_inc(&a->disable_cnt);
+
+ esas2r_lock_clear_flags(&a->flags, AF_DISC_POLLED);
+ esas2r_lock_clear_flags(&a->flags, AF_TASKLET_SCHEDULED);
+ }
+
+
+ esas2r_targ_db_report_changes(a);
+
+ /*
+ * For cases where (a) the initialization messages processing may
+ * handle an interrupt for a port event and a discovery is waiting, but
+ * we are not waiting for devices, or (b) the device wait time has been
+ * exhausted but there is still discovery pending, start any leftover
+ * discovery in interrupt driven mode.
+ */
+ esas2r_disc_start_waiting(a);
+
+ /* Enable chip interrupts */
+ a->int_mask = ESAS2R_INT_STS_MASK;
+ esas2r_enable_chip_interrupts(a);
+ esas2r_enable_heartbeat(a);
+ rslt = true;
+
+exit:
+ /*
+ * Regardless of whether initialization was successful, certain things
+ * need to get done before we exit.
+ */
+
+ if ((a->flags & AF_CHPRST_DETECTED)
+ && (a->flags & AF_FIRST_INIT)) {
+ /*
+ * Reinitialization was performed during the first
+ * initialization. Only clear the chip reset flag so the
+ * original device polling is not cancelled.
+ */
+ if (!rslt)
+ esas2r_lock_clear_flags(&a->flags, AF_CHPRST_PENDING);
+ } else {
+ /* First initialization or a subsequent re-init is complete. */
+ if (!rslt) {
+ esas2r_lock_clear_flags(&a->flags, AF_CHPRST_PENDING);
+ esas2r_lock_clear_flags(&a->flags, AF_DISC_PENDING);
+ }
+
+
+ /* Enable deferred processing after the first initialization. */
+ if (a->flags & AF_FIRST_INIT) {
+ esas2r_lock_clear_flags(&a->flags, AF_FIRST_INIT);
+
+ if (atomic_dec_return(&a->disable_cnt) == 0)
+ esas2r_do_deferred_processes(a);
+ }
+ }
+
+ return rslt;
+}
+
+void esas2r_reset_adapter(struct esas2r_adapter *a)
+{
+ esas2r_lock_set_flags(&a->flags, AF_OS_RESET);
+ esas2r_local_reset_adapter(a);
+ esas2r_schedule_tasklet(a);
+}
+
+void esas2r_reset_chip(struct esas2r_adapter *a)
+{
+ if (!esas2r_is_adapter_present(a))
+ return;
+
+ /*
+ * Before we reset the chip, save off the VDA core dump. The VDA core
+ * dump is located in the upper 512KB of the onchip SRAM. Make sure
+ * to not overwrite a previous crash that was saved.
+ */
+ if ((a->flags2 & AF2_COREDUMP_AVAIL)
+ && !(a->flags2 & AF2_COREDUMP_SAVED)
+ && a->fw_coredump_buff) {
+ esas2r_read_mem_block(a,
+ a->fw_coredump_buff,
+ MW_DATA_ADDR_SRAM + 0x80000,
+ ESAS2R_FWCOREDUMP_SZ);
+
+ esas2r_lock_set_flags(&a->flags2, AF2_COREDUMP_SAVED);
+ }
+
+ esas2r_lock_clear_flags(&a->flags2, AF2_COREDUMP_AVAIL);
+
+ /* Reset the chip */
+ if (a->pcid->revision == MVR_FREY_B2)
+ esas2r_write_register_dword(a, MU_CTL_STATUS_IN_B2,
+ MU_CTL_IN_FULL_RST2);
+ else
+ esas2r_write_register_dword(a, MU_CTL_STATUS_IN,
+ MU_CTL_IN_FULL_RST);
+
+
+ /* Stall a little while to let the reset condition clear */
+ mdelay(10);
+}
+
+static void esas2r_power_down_notify_firmware(struct esas2r_adapter *a)
+{
+ u32 starttime;
+ u32 doorbell;
+
+ esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_POWER_DOWN);
+ starttime = jiffies_to_msecs(jiffies);
+
+ while (true) {
+ doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+ if (doorbell & DRBL_POWER_DOWN) {
+ esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+ doorbell);
+ break;
+ }
+
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ if ((jiffies_to_msecs(jiffies) - starttime) > 30000) {
+ esas2r_hdebug("Timeout waiting for power down");
+ break;
+ }
+ }
+}
+
+/*
+ * Perform power management processing including managing device states, adapter
+ * states, interrupts, and I/O.
+ */
+void esas2r_power_down(struct esas2r_adapter *a)
+{
+ esas2r_lock_set_flags(&a->flags, AF_POWER_MGT);
+ esas2r_lock_set_flags(&a->flags, AF_POWER_DOWN);
+
+ if (!(a->flags & AF_DEGRADED_MODE)) {
+ u32 starttime;
+ u32 doorbell;
+
+ /*
+ * We are currently running OK and will be reinitializing later.
+ * increment the disable count to coordinate with
+ * esas2r_init_adapter. We don't have to do this in degraded
+ * mode since we never enabled interrupts in the first place.
+ */
+ esas2r_disable_chip_interrupts(a);
+ esas2r_disable_heartbeat(a);
+
+ /* wait for any VDA activity to clear before continuing */
+ esas2r_write_register_dword(a, MU_DOORBELL_IN,
+ DRBL_MSG_IFC_DOWN);
+ starttime = jiffies_to_msecs(jiffies);
+
+ while (true) {
+ doorbell =
+ esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+ if (doorbell & DRBL_MSG_IFC_DOWN) {
+ esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+ doorbell);
+ break;
+ }
+
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
+ esas2r_hdebug(
+ "timeout waiting for interface down");
+ break;
+ }
+ }
+
+ /*
+ * For versions of firmware that support it tell them the driver
+ * is powering down.
+ */
+ if (a->flags2 & AF2_VDA_POWER_DOWN)
+ esas2r_power_down_notify_firmware(a);
+ }
+
+ /* Suspend I/O processing. */
+ esas2r_lock_set_flags(&a->flags, AF_OS_RESET);
+ esas2r_lock_set_flags(&a->flags, AF_DISC_PENDING);
+ esas2r_lock_set_flags(&a->flags, AF_CHPRST_PENDING);
+
+ esas2r_process_adapter_reset(a);
+
+ /* Remove devices now that I/O is cleaned up. */
+ a->prev_dev_cnt = esas2r_targ_db_get_tgt_cnt(a);
+ esas2r_targ_db_remove_all(a, false);
+}
+
+/*
+ * Perform power management processing including managing device states, adapter
+ * states, interrupts, and I/O.
+ */
+bool esas2r_power_up(struct esas2r_adapter *a, bool init_poll)
+{
+ bool ret;
+
+ esas2r_lock_clear_flags(&a->flags, AF_POWER_DOWN);
+ esas2r_init_pci_cfg_space(a);
+ esas2r_lock_set_flags(&a->flags, AF_FIRST_INIT);
+ atomic_inc(&a->disable_cnt);
+
+ /* reinitialize the adapter */
+ ret = esas2r_check_adapter(a);
+ if (!esas2r_init_adapter_hw(a, init_poll))
+ ret = false;
+
+ /* send the reset asynchronous event */
+ esas2r_send_reset_ae(a, true);
+
+ /* clear this flag after initialization. */
+ esas2r_lock_clear_flags(&a->flags, AF_POWER_MGT);
+ return ret;
+}
+
+bool esas2r_is_adapter_present(struct esas2r_adapter *a)
+{
+ if (a->flags & AF_NOT_PRESENT)
+ return false;
+
+ if (esas2r_read_register_dword(a, MU_DOORBELL_OUT) == 0xFFFFFFFF) {
+ esas2r_lock_set_flags(&a->flags, AF_NOT_PRESENT);
+
+ return false;
+ }
+ return true;
+}
+
+const char *esas2r_get_model_name(struct esas2r_adapter *a)
+{
+ switch (a->pcid->subsystem_device) {
+ case ATTO_ESAS_R680:
+ return "ATTO ExpressSAS R680";
+
+ case ATTO_ESAS_R608:
+ return "ATTO ExpressSAS R608";
+
+ case ATTO_ESAS_R60F:
+ return "ATTO ExpressSAS R60F";
+
+ case ATTO_ESAS_R6F0:
+ return "ATTO ExpressSAS R6F0";
+
+ case ATTO_ESAS_R644:
+ return "ATTO ExpressSAS R644";
+
+ case ATTO_ESAS_R648:
+ return "ATTO ExpressSAS R648";
+
+ case ATTO_TSSC_3808:
+ return "ATTO ThunderStream SC 3808D";
+
+ case ATTO_TSSC_3808E:
+ return "ATTO ThunderStream SC 3808E";
+
+ case ATTO_TLSH_1068:
+ return "ATTO ThunderLink SH 1068";
+ }
+
+ return "ATTO SAS Controller";
+}
+
+const char *esas2r_get_model_name_short(struct esas2r_adapter *a)
+{
+ switch (a->pcid->subsystem_device) {
+ case ATTO_ESAS_R680:
+ return "R680";
+
+ case ATTO_ESAS_R608:
+ return "R608";
+
+ case ATTO_ESAS_R60F:
+ return "R60F";
+
+ case ATTO_ESAS_R6F0:
+ return "R6F0";
+
+ case ATTO_ESAS_R644:
+ return "R644";
+
+ case ATTO_ESAS_R648:
+ return "R648";
+
+ case ATTO_TSSC_3808:
+ return "SC 3808D";
+
+ case ATTO_TSSC_3808E:
+ return "SC 3808E";
+
+ case ATTO_TLSH_1068:
+ return "SH 1068";
+ }
+
+ return "unknown";
+}
diff --git a/drivers/scsi/esas2r/esas2r_int.c b/drivers/scsi/esas2r/esas2r_int.c
new file mode 100644
index 00000000000..c2d4ff57c5c
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_int.c
@@ -0,0 +1,941 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r_int.c
+ * esas2r interrupt handling
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "esas2r.h"
+
+/* Local function prototypes */
+static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell);
+static void esas2r_get_outbound_responses(struct esas2r_adapter *a);
+static void esas2r_process_bus_reset(struct esas2r_adapter *a);
+
+/*
+ * Poll the adapter for interrupts and service them.
+ * This function handles both legacy interrupts and MSI.
+ */
+void esas2r_polled_interrupt(struct esas2r_adapter *a)
+{
+ u32 intstat;
+ u32 doorbell;
+
+ esas2r_disable_chip_interrupts(a);
+
+ intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
+
+ if (intstat & MU_INTSTAT_POST_OUT) {
+ /* clear the interrupt */
+
+ esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
+ MU_OLIS_INT);
+ esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
+
+ esas2r_get_outbound_responses(a);
+ }
+
+ if (intstat & MU_INTSTAT_DRBL) {
+ doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+ if (doorbell != 0)
+ esas2r_doorbell_interrupt(a, doorbell);
+ }
+
+ esas2r_enable_chip_interrupts(a);
+
+ if (atomic_read(&a->disable_cnt) == 0)
+ esas2r_do_deferred_processes(a);
+}
+
+/*
+ * Legacy and MSI interrupt handlers. Note that the legacy interrupt handler
+ * schedules a TASKLET to process events, whereas the MSI handler just
+ * processes interrupt events directly.
+ */
+irqreturn_t esas2r_interrupt(int irq, void *dev_id)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)dev_id;
+
+ if (!esas2r_adapter_interrupt_pending(a))
+ return IRQ_NONE;
+
+ esas2r_lock_set_flags(&a->flags2, AF2_INT_PENDING);
+ esas2r_schedule_tasklet(a);
+
+ return IRQ_HANDLED;
+}
+
+void esas2r_adapter_interrupt(struct esas2r_adapter *a)
+{
+ u32 doorbell;
+
+ if (likely(a->int_stat & MU_INTSTAT_POST_OUT)) {
+ /* clear the interrupt */
+ esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
+ MU_OLIS_INT);
+ esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
+ esas2r_get_outbound_responses(a);
+ }
+
+ if (unlikely(a->int_stat & MU_INTSTAT_DRBL)) {
+ doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+ if (doorbell != 0)
+ esas2r_doorbell_interrupt(a, doorbell);
+ }
+
+ a->int_mask = ESAS2R_INT_STS_MASK;
+
+ esas2r_enable_chip_interrupts(a);
+
+ if (likely(atomic_read(&a->disable_cnt) == 0))
+ esas2r_do_deferred_processes(a);
+}
+
+irqreturn_t esas2r_msi_interrupt(int irq, void *dev_id)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)dev_id;
+ u32 intstat;
+ u32 doorbell;
+
+ intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
+
+ if (likely(intstat & MU_INTSTAT_POST_OUT)) {
+ /* clear the interrupt */
+
+ esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
+ MU_OLIS_INT);
+ esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
+
+ esas2r_get_outbound_responses(a);
+ }
+
+ if (unlikely(intstat & MU_INTSTAT_DRBL)) {
+ doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+ if (doorbell != 0)
+ esas2r_doorbell_interrupt(a, doorbell);
+ }
+
+ /*
+ * Work around a chip bug and force a new MSI to be sent if one is
+ * still pending.
+ */
+ esas2r_disable_chip_interrupts(a);
+ esas2r_enable_chip_interrupts(a);
+
+ if (likely(atomic_read(&a->disable_cnt) == 0))
+ esas2r_do_deferred_processes(a);
+
+ esas2r_do_tasklet_tasks(a);
+
+ return 1;
+}
+
+
+
+static void esas2r_handle_outbound_rsp_err(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ struct atto_vda_ob_rsp *rsp)
+{
+
+ /*
+ * For I/O requests, only copy the response if an error
+ * occurred and setup a callback to do error processing.
+ */
+ if (unlikely(rq->req_stat != RS_SUCCESS)) {
+ memcpy(&rq->func_rsp, &rsp->func_rsp, sizeof(rsp->func_rsp));
+
+ if (rq->req_stat == RS_ABORTED) {
+ if (rq->timeout > RQ_MAX_TIMEOUT)
+ rq->req_stat = RS_TIMEOUT;
+ } else if (rq->req_stat == RS_SCSI_ERROR) {
+ u8 scsistatus = rq->func_rsp.scsi_rsp.scsi_stat;
+
+ esas2r_trace("scsistatus: %x", scsistatus);
+
+ /* Any of these are a good result. */
+ if (scsistatus == SAM_STAT_GOOD || scsistatus ==
+ SAM_STAT_CONDITION_MET || scsistatus ==
+ SAM_STAT_INTERMEDIATE || scsistatus ==
+ SAM_STAT_INTERMEDIATE_CONDITION_MET) {
+ rq->req_stat = RS_SUCCESS;
+ rq->func_rsp.scsi_rsp.scsi_stat =
+ SAM_STAT_GOOD;
+ }
+ }
+ }
+}
+
+static void esas2r_get_outbound_responses(struct esas2r_adapter *a)
+{
+ struct atto_vda_ob_rsp *rsp;
+ u32 rspput_ptr;
+ u32 rspget_ptr;
+ struct esas2r_request *rq;
+ u32 handle;
+ unsigned long flags;
+
+ LIST_HEAD(comp_list);
+
+ esas2r_trace_enter();
+
+ spin_lock_irqsave(&a->queue_lock, flags);
+
+ /* Get the outbound limit and pointers */
+ rspput_ptr = le32_to_cpu(*a->outbound_copy) & MU_OLC_WRT_PTR;
+ rspget_ptr = a->last_read;
+
+ esas2r_trace("rspput_ptr: %x, rspget_ptr: %x", rspput_ptr, rspget_ptr);
+
+ /* If we don't have anything to process, get out */
+ if (unlikely(rspget_ptr == rspput_ptr)) {
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+ esas2r_trace_exit();
+ return;
+ }
+
+ /* Make sure the firmware is healthy */
+ if (unlikely(rspput_ptr >= a->list_size)) {
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+ esas2r_bugon();
+ esas2r_local_reset_adapter(a);
+ esas2r_trace_exit();
+ return;
+ }
+
+ do {
+ rspget_ptr++;
+
+ if (rspget_ptr >= a->list_size)
+ rspget_ptr = 0;
+
+ rsp = (struct atto_vda_ob_rsp *)a->outbound_list_md.virt_addr
+ + rspget_ptr;
+
+ handle = rsp->handle;
+
+ /* Verify the handle range */
+ if (unlikely(LOWORD(handle) == 0
+ || LOWORD(handle) > num_requests +
+ num_ae_requests + 1)) {
+ esas2r_bugon();
+ continue;
+ }
+
+ /* Get the request for this handle */
+ rq = a->req_table[LOWORD(handle)];
+
+ if (unlikely(rq == NULL || rq->vrq->scsi.handle != handle)) {
+ esas2r_bugon();
+ continue;
+ }
+
+ list_del(&rq->req_list);
+
+ /* Get the completion status */
+ rq->req_stat = rsp->req_stat;
+
+ esas2r_trace("handle: %x", handle);
+ esas2r_trace("rq: %p", rq);
+ esas2r_trace("req_status: %x", rq->req_stat);
+
+ if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)) {
+ esas2r_handle_outbound_rsp_err(a, rq, rsp);
+ } else {
+ /*
+ * Copy the outbound completion struct for non-I/O
+ * requests.
+ */
+ memcpy(&rq->func_rsp, &rsp->func_rsp,
+ sizeof(rsp->func_rsp));
+ }
+
+ /* Queue the request for completion. */
+ list_add_tail(&rq->comp_list, &comp_list);
+
+ } while (rspget_ptr != rspput_ptr);
+
+ a->last_read = rspget_ptr;
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+
+ esas2r_comp_list_drain(a, &comp_list);
+ esas2r_trace_exit();
+}
+
+/*
+ * Perform all deferred processes for the adapter. Deferred
+ * processes can only be done while the current interrupt
+ * disable_cnt for the adapter is zero.
+ */
+void esas2r_do_deferred_processes(struct esas2r_adapter *a)
+{
+ int startreqs = 2;
+ struct esas2r_request *rq;
+ unsigned long flags;
+
+ /*
+ * startreqs is used to control starting requests
+ * that are on the deferred queue
+ * = 0 - do not start any requests
+ * = 1 - can start discovery requests
+ * = 2 - can start any request
+ */
+
+ if (a->flags & (AF_CHPRST_PENDING | AF_FLASHING))
+ startreqs = 0;
+ else if (a->flags & AF_DISC_PENDING)
+ startreqs = 1;
+
+ atomic_inc(&a->disable_cnt);
+
+ /* Clear off the completed list to be processed later. */
+
+ if (esas2r_is_tasklet_pending(a)) {
+ esas2r_schedule_tasklet(a);
+
+ startreqs = 0;
+ }
+
+ /*
+ * If we can start requests then traverse the defer queue
+ * looking for requests to start or complete
+ */
+ if (startreqs && !list_empty(&a->defer_list)) {
+ LIST_HEAD(comp_list);
+ struct list_head *element, *next;
+
+ spin_lock_irqsave(&a->queue_lock, flags);
+
+ list_for_each_safe(element, next, &a->defer_list) {
+ rq = list_entry(element, struct esas2r_request,
+ req_list);
+
+ if (rq->req_stat != RS_PENDING) {
+ list_del(element);
+ list_add_tail(&rq->comp_list, &comp_list);
+ }
+ /*
+ * Process discovery and OS requests separately. We
+ * can't hold up discovery requests when discovery is
+ * pending. In general, there may be different sets of
+ * conditions for starting different types of requests.
+ */
+ else if (rq->req_type == RT_DISC_REQ) {
+ list_del(element);
+ esas2r_disc_local_start_request(a, rq);
+ } else if (startreqs == 2) {
+ list_del(element);
+ esas2r_local_start_request(a, rq);
+
+ /*
+ * Flashing could have been set by last local
+ * start
+ */
+ if (a->flags & AF_FLASHING)
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+ esas2r_comp_list_drain(a, &comp_list);
+ }
+
+ atomic_dec(&a->disable_cnt);
+}
+
+/*
+ * Process an adapter reset (or one that is about to happen)
+ * by making sure all outstanding requests are completed that
+ * haven't been already.
+ */
+void esas2r_process_adapter_reset(struct esas2r_adapter *a)
+{
+ struct esas2r_request *rq = &a->general_req;
+ unsigned long flags;
+ struct esas2r_disc_context *dc;
+
+ LIST_HEAD(comp_list);
+ struct list_head *element;
+
+ esas2r_trace_enter();
+
+ spin_lock_irqsave(&a->queue_lock, flags);
+
+ /* abort the active discovery, if any. */
+
+ if (rq->interrupt_cx) {
+ dc = (struct esas2r_disc_context *)rq->interrupt_cx;
+
+ dc->disc_evt = 0;
+
+ esas2r_lock_clear_flags(&a->flags, AF_DISC_IN_PROG);
+ }
+
+ /*
+ * just clear the interrupt callback for now. it will be dequeued if
+ * and when we find it on the active queue and we don't want the
+ * callback called. also set the dummy completion callback in case we
+ * were doing an I/O request.
+ */
+
+ rq->interrupt_cx = NULL;
+ rq->interrupt_cb = NULL;
+
+ rq->comp_cb = esas2r_dummy_complete;
+
+ /* Reset the read and write pointers */
+
+ *a->outbound_copy =
+ a->last_write =
+ a->last_read = a->list_size - 1;
+
+ esas2r_lock_set_flags(&a->flags, AF_COMM_LIST_TOGGLE);
+
+ /* Kill all the requests on the active list */
+ list_for_each(element, &a->defer_list) {
+ rq = list_entry(element, struct esas2r_request, req_list);
+
+ if (rq->req_stat == RS_STARTED)
+ if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
+ list_add_tail(&rq->comp_list, &comp_list);
+ }
+
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+ esas2r_comp_list_drain(a, &comp_list);
+ esas2r_process_bus_reset(a);
+ esas2r_trace_exit();
+}
+
+static void esas2r_process_bus_reset(struct esas2r_adapter *a)
+{
+ struct esas2r_request *rq;
+ struct list_head *element;
+ unsigned long flags;
+
+ LIST_HEAD(comp_list);
+
+ esas2r_trace_enter();
+
+ esas2r_hdebug("reset detected");
+
+ spin_lock_irqsave(&a->queue_lock, flags);
+
+ /* kill all the requests on the deferred queue */
+ list_for_each(element, &a->defer_list) {
+ rq = list_entry(element, struct esas2r_request, req_list);
+ if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
+ list_add_tail(&rq->comp_list, &comp_list);
+ }
+
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+
+ esas2r_comp_list_drain(a, &comp_list);
+
+ if (atomic_read(&a->disable_cnt) == 0)
+ esas2r_do_deferred_processes(a);
+
+ esas2r_lock_clear_flags(&a->flags, AF_OS_RESET);
+
+ esas2r_trace_exit();
+}
+
+static void esas2r_chip_rst_needed_during_tasklet(struct esas2r_adapter *a)
+{
+
+ esas2r_lock_clear_flags(&a->flags, AF_CHPRST_NEEDED);
+ esas2r_lock_clear_flags(&a->flags, AF_BUSRST_NEEDED);
+ esas2r_lock_clear_flags(&a->flags, AF_BUSRST_DETECTED);
+ esas2r_lock_clear_flags(&a->flags, AF_BUSRST_PENDING);
+ /*
+ * Make sure we don't get attempt more than 3 resets
+ * when the uptime between resets does not exceed one
+ * minute. This will stop any situation where there is
+ * really something wrong with the hardware. The way
+ * this works is that we start with uptime ticks at 0.
+ * Each time we do a reset, we add 20 seconds worth to
+ * the count. Each time a timer tick occurs, as long
+ * as a chip reset is not pending, we decrement the
+ * tick count. If the uptime ticks ever gets to 60
+ * seconds worth, we disable the adapter from that
+ * point forward. Three strikes, you're out.
+ */
+ if (!esas2r_is_adapter_present(a) || (a->chip_uptime >=
+ ESAS2R_CHP_UPTIME_MAX)) {
+ esas2r_hdebug("*** adapter disabled ***");
+
+ /*
+ * Ok, some kind of hard failure. Make sure we
+ * exit this loop with chip interrupts
+ * permanently disabled so we don't lock up the
+ * entire system. Also flag degraded mode to
+ * prevent the heartbeat from trying to recover.
+ */
+
+ esas2r_lock_set_flags(&a->flags, AF_DEGRADED_MODE);
+ esas2r_lock_set_flags(&a->flags, AF_DISABLED);
+ esas2r_lock_clear_flags(&a->flags, AF_CHPRST_PENDING);
+ esas2r_lock_clear_flags(&a->flags, AF_DISC_PENDING);
+
+ esas2r_disable_chip_interrupts(a);
+ a->int_mask = 0;
+ esas2r_process_adapter_reset(a);
+
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "Adapter disabled because of hardware failure");
+ } else {
+ u32 flags =
+ esas2r_lock_set_flags(&a->flags, AF_CHPRST_STARTED);
+
+ if (!(flags & AF_CHPRST_STARTED))
+ /*
+ * Only disable interrupts if this is
+ * the first reset attempt.
+ */
+ esas2r_disable_chip_interrupts(a);
+
+ if ((a->flags & AF_POWER_MGT) && !(a->flags & AF_FIRST_INIT) &&
+ !(flags & AF_CHPRST_STARTED)) {
+ /*
+ * Don't reset the chip on the first
+ * deferred power up attempt.
+ */
+ } else {
+ esas2r_hdebug("*** resetting chip ***");
+ esas2r_reset_chip(a);
+ }
+
+ /* Kick off the reinitialization */
+ a->chip_uptime += ESAS2R_CHP_UPTIME_CNT;
+ a->chip_init_time = jiffies_to_msecs(jiffies);
+ if (!(a->flags & AF_POWER_MGT)) {
+ esas2r_process_adapter_reset(a);
+
+ if (!(flags & AF_CHPRST_STARTED)) {
+ /* Remove devices now that I/O is cleaned up. */
+ a->prev_dev_cnt =
+ esas2r_targ_db_get_tgt_cnt(a);
+ esas2r_targ_db_remove_all(a, false);
+ }
+ }
+
+ a->int_mask = 0;
+ }
+}
+
+static void esas2r_handle_chip_rst_during_tasklet(struct esas2r_adapter *a)
+{
+ while (a->flags & AF_CHPRST_DETECTED) {
+ /*
+ * Balance the enable in esas2r_initadapter_hw.
+ * Esas2r_power_down already took care of it for power
+ * management.
+ */
+ if (!(a->flags & AF_DEGRADED_MODE) && !(a->flags &
+ AF_POWER_MGT))
+ esas2r_disable_chip_interrupts(a);
+
+ /* Reinitialize the chip. */
+ esas2r_check_adapter(a);
+ esas2r_init_adapter_hw(a, 0);
+
+ if (a->flags & AF_CHPRST_NEEDED)
+ break;
+
+ if (a->flags & AF_POWER_MGT) {
+ /* Recovery from power management. */
+ if (a->flags & AF_FIRST_INIT) {
+ /* Chip reset during normal power up */
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "The firmware was reset during a normal power-up sequence");
+ } else {
+ /* Deferred power up complete. */
+ esas2r_lock_clear_flags(&a->flags,
+ AF_POWER_MGT);
+ esas2r_send_reset_ae(a, true);
+ }
+ } else {
+ /* Recovery from online chip reset. */
+ if (a->flags & AF_FIRST_INIT) {
+ /* Chip reset during driver load */
+ } else {
+ /* Chip reset after driver load */
+ esas2r_send_reset_ae(a, false);
+ }
+
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "Recovering from a chip reset while the chip was online");
+ }
+
+ esas2r_lock_clear_flags(&a->flags, AF_CHPRST_STARTED);
+ esas2r_enable_chip_interrupts(a);
+
+ /*
+ * Clear this flag last! this indicates that the chip has been
+ * reset already during initialization.
+ */
+ esas2r_lock_clear_flags(&a->flags, AF_CHPRST_DETECTED);
+ }
+}
+
+
+/* Perform deferred tasks when chip interrupts are disabled */
+void esas2r_do_tasklet_tasks(struct esas2r_adapter *a)
+{
+ if (a->flags & (AF_CHPRST_NEEDED | AF_CHPRST_DETECTED)) {
+ if (a->flags & AF_CHPRST_NEEDED)
+ esas2r_chip_rst_needed_during_tasklet(a);
+
+ esas2r_handle_chip_rst_during_tasklet(a);
+ }
+
+ if (a->flags & AF_BUSRST_NEEDED) {
+ esas2r_hdebug("hard resetting bus");
+
+ esas2r_lock_clear_flags(&a->flags, AF_BUSRST_NEEDED);
+
+ if (a->flags & AF_FLASHING)
+ esas2r_lock_set_flags(&a->flags, AF_BUSRST_DETECTED);
+ else
+ esas2r_write_register_dword(a, MU_DOORBELL_IN,
+ DRBL_RESET_BUS);
+ }
+
+ if (a->flags & AF_BUSRST_DETECTED) {
+ esas2r_process_bus_reset(a);
+
+ esas2r_log_dev(ESAS2R_LOG_WARN,
+ &(a->host->shost_gendev),
+ "scsi_report_bus_reset() called");
+
+ scsi_report_bus_reset(a->host, 0);
+
+ esas2r_lock_clear_flags(&a->flags, AF_BUSRST_DETECTED);
+ esas2r_lock_clear_flags(&a->flags, AF_BUSRST_PENDING);
+
+ esas2r_log(ESAS2R_LOG_WARN, "Bus reset complete");
+ }
+
+ if (a->flags & AF_PORT_CHANGE) {
+ esas2r_lock_clear_flags(&a->flags, AF_PORT_CHANGE);
+
+ esas2r_targ_db_report_changes(a);
+ }
+
+ if (atomic_read(&a->disable_cnt) == 0)
+ esas2r_do_deferred_processes(a);
+}
+
+static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell)
+{
+ if (!(doorbell & DRBL_FORCE_INT)) {
+ esas2r_trace_enter();
+ esas2r_trace("doorbell: %x", doorbell);
+ }
+
+ /* First clear the doorbell bits */
+ esas2r_write_register_dword(a, MU_DOORBELL_OUT, doorbell);
+
+ if (doorbell & DRBL_RESET_BUS)
+ esas2r_lock_set_flags(&a->flags, AF_BUSRST_DETECTED);
+
+ if (doorbell & DRBL_FORCE_INT)
+ esas2r_lock_clear_flags(&a->flags, AF_HEARTBEAT);
+
+ if (doorbell & DRBL_PANIC_REASON_MASK) {
+ esas2r_hdebug("*** Firmware Panic ***");
+ esas2r_log(ESAS2R_LOG_CRIT, "The firmware has panicked");
+ }
+
+ if (doorbell & DRBL_FW_RESET) {
+ esas2r_lock_set_flags(&a->flags2, AF2_COREDUMP_AVAIL);
+ esas2r_local_reset_adapter(a);
+ }
+
+ if (!(doorbell & DRBL_FORCE_INT))
+ esas2r_trace_exit();
+}
+
+void esas2r_force_interrupt(struct esas2r_adapter *a)
+{
+ esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_FORCE_INT |
+ DRBL_DRV_VER);
+}
+
+
+static void esas2r_lun_event(struct esas2r_adapter *a, union atto_vda_ae *ae,
+ u16 target, u32 length)
+{
+ struct esas2r_target *t = a->targetdb + target;
+ u32 cplen = length;
+ unsigned long flags;
+
+ if (cplen > sizeof(t->lu_event))
+ cplen = sizeof(t->lu_event);
+
+ esas2r_trace("ae->lu.dwevent: %x", ae->lu.dwevent);
+ esas2r_trace("ae->lu.bystate: %x", ae->lu.bystate);
+
+ spin_lock_irqsave(&a->mem_lock, flags);
+
+ t->new_target_state = TS_INVALID;
+
+ if (ae->lu.dwevent & VDAAE_LU_LOST) {
+ t->new_target_state = TS_NOT_PRESENT;
+ } else {
+ switch (ae->lu.bystate) {
+ case VDAAE_LU_NOT_PRESENT:
+ case VDAAE_LU_OFFLINE:
+ case VDAAE_LU_DELETED:
+ case VDAAE_LU_FACTORY_DISABLED:
+ t->new_target_state = TS_NOT_PRESENT;
+ break;
+
+ case VDAAE_LU_ONLINE:
+ case VDAAE_LU_DEGRADED:
+ t->new_target_state = TS_PRESENT;
+ break;
+ }
+ }
+
+ if (t->new_target_state != TS_INVALID) {
+ memcpy(&t->lu_event, &ae->lu, cplen);
+
+ esas2r_disc_queue_event(a, DCDE_DEV_CHANGE);
+ }
+
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+}
+
+
+
+void esas2r_ae_complete(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+ union atto_vda_ae *ae =
+ (union atto_vda_ae *)rq->vda_rsp_data->ae_data.event_data;
+ u32 length = le32_to_cpu(rq->func_rsp.ae_rsp.length);
+ union atto_vda_ae *last =
+ (union atto_vda_ae *)(rq->vda_rsp_data->ae_data.event_data
+ + length);
+
+ esas2r_trace_enter();
+ esas2r_trace("length: %d", length);
+
+ if (length > sizeof(struct atto_vda_ae_data)
+ || (length & 3) != 0
+ || length == 0) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "The AE request response length (%p) is too long: %d",
+ rq, length);
+
+ esas2r_hdebug("aereq->length (0x%x) too long", length);
+ esas2r_bugon();
+
+ last = ae;
+ }
+
+ while (ae < last) {
+ u16 target;
+
+ esas2r_trace("ae: %p", ae);
+ esas2r_trace("ae->hdr: %p", &(ae->hdr));
+
+ length = ae->hdr.bylength;
+
+ if (length > (u32)((u8 *)last - (u8 *)ae)
+ || (length & 3) != 0
+ || length == 0) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "the async event length is invalid (%p): %d",
+ ae, length);
+
+ esas2r_hdebug("ae->hdr.length (0x%x) invalid", length);
+ esas2r_bugon();
+
+ break;
+ }
+
+ esas2r_nuxi_ae_data(ae);
+
+ esas2r_queue_fw_event(a, fw_event_vda_ae, ae,
+ sizeof(union atto_vda_ae));
+
+ switch (ae->hdr.bytype) {
+ case VDAAE_HDR_TYPE_RAID:
+
+ if (ae->raid.dwflags & (VDAAE_GROUP_STATE
+ | VDAAE_RBLD_STATE
+ | VDAAE_MEMBER_CHG
+ | VDAAE_PART_CHG)) {
+ esas2r_log(ESAS2R_LOG_INFO,
+ "RAID event received - name:%s rebuild_state:%d group_state:%d",
+ ae->raid.acname,
+ ae->raid.byrebuild_state,
+ ae->raid.bygroup_state);
+ }
+
+ break;
+
+ case VDAAE_HDR_TYPE_LU:
+ esas2r_log(ESAS2R_LOG_INFO,
+ "LUN event received: event:%d target_id:%d LUN:%d state:%d",
+ ae->lu.dwevent,
+ ae->lu.id.tgtlun.wtarget_id,
+ ae->lu.id.tgtlun.bylun,
+ ae->lu.bystate);
+
+ target = ae->lu.id.tgtlun.wtarget_id;
+
+ if (target < ESAS2R_MAX_TARGETS)
+ esas2r_lun_event(a, ae, target, length);
+
+ break;
+
+ case VDAAE_HDR_TYPE_DISK:
+ esas2r_log(ESAS2R_LOG_INFO, "Disk event received");
+ break;
+
+ default:
+
+ /* Silently ignore the rest and let the apps deal with
+ * them.
+ */
+
+ break;
+ }
+
+ ae = (union atto_vda_ae *)((u8 *)ae + length);
+ }
+
+ /* Now requeue it. */
+ esas2r_start_ae_request(a, rq);
+ esas2r_trace_exit();
+}
+
+/* Send an asynchronous event for a chip reset or power management. */
+void esas2r_send_reset_ae(struct esas2r_adapter *a, bool pwr_mgt)
+{
+ struct atto_vda_ae_hdr ae;
+
+ if (pwr_mgt)
+ ae.bytype = VDAAE_HDR_TYPE_PWRMGT;
+ else
+ ae.bytype = VDAAE_HDR_TYPE_RESET;
+
+ ae.byversion = VDAAE_HDR_VER_0;
+ ae.byflags = 0;
+ ae.bylength = (u8)sizeof(struct atto_vda_ae_hdr);
+
+ if (pwr_mgt)
+ esas2r_hdebug("*** sending power management AE ***");
+ else
+ esas2r_hdebug("*** sending reset AE ***");
+
+ esas2r_queue_fw_event(a, fw_event_vda_ae, &ae,
+ sizeof(union atto_vda_ae));
+}
+
+void esas2r_dummy_complete(struct esas2r_adapter *a, struct esas2r_request *rq)
+{}
+
+static void esas2r_check_req_rsp_sense(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ u8 snslen, snslen2;
+
+ snslen = snslen2 = rq->func_rsp.scsi_rsp.sense_len;
+
+ if (snslen > rq->sense_len)
+ snslen = rq->sense_len;
+
+ if (snslen) {
+ if (rq->sense_buf)
+ memcpy(rq->sense_buf, rq->data_buf, snslen);
+ else
+ rq->sense_buf = (u8 *)rq->data_buf;
+
+ /* See about possible sense data */
+ if (snslen2 > 0x0c) {
+ u8 *s = (u8 *)rq->data_buf;
+
+ esas2r_trace_enter();
+
+ /* Report LUNS data has changed */
+ if (s[0x0c] == 0x3f && s[0x0d] == 0x0E) {
+ esas2r_trace("rq->target_id: %d",
+ rq->target_id);
+ esas2r_target_state_changed(a, rq->target_id,
+ TS_LUN_CHANGE);
+ }
+
+ esas2r_trace("add_sense_key=%x", s[0x0c]);
+ esas2r_trace("add_sense_qual=%x", s[0x0d]);
+ esas2r_trace_exit();
+ }
+ }
+
+ rq->sense_len = snslen;
+}
+
+
+void esas2r_complete_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ if (rq->vrq->scsi.function == VDA_FUNC_FLASH
+ && rq->vrq->flash.sub_func == VDA_FLASH_COMMIT)
+ esas2r_lock_clear_flags(&a->flags, AF_FLASHING);
+
+ /* See if we setup a callback to do special processing */
+
+ if (rq->interrupt_cb) {
+ (*rq->interrupt_cb)(a, rq);
+
+ if (rq->req_stat == RS_PENDING) {
+ esas2r_start_request(a, rq);
+ return;
+ }
+ }
+
+ if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)
+ && unlikely(rq->req_stat != RS_SUCCESS)) {
+ esas2r_check_req_rsp_sense(a, rq);
+ esas2r_log_request_failure(a, rq);
+ }
+
+ (*rq->comp_cb)(a, rq);
+}
diff --git a/drivers/scsi/esas2r/esas2r_io.c b/drivers/scsi/esas2r/esas2r_io.c
new file mode 100644
index 00000000000..324e2626a08
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_io.c
@@ -0,0 +1,880 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r_io.c
+ * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.com)mpt3sas/mpt3sas_trigger_diag.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+void esas2r_start_request(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+ struct esas2r_target *t = NULL;
+ struct esas2r_request *startrq = rq;
+ unsigned long flags;
+
+ if (unlikely(a->flags & (AF_DEGRADED_MODE | AF_POWER_DOWN))) {
+ if (rq->vrq->scsi.function == VDA_FUNC_SCSI)
+ rq->req_stat = RS_SEL2;
+ else
+ rq->req_stat = RS_DEGRADED;
+ } else if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)) {
+ t = a->targetdb + rq->target_id;
+
+ if (unlikely(t >= a->targetdb_end
+ || !(t->flags & TF_USED))) {
+ rq->req_stat = RS_SEL;
+ } else {
+ /* copy in the target ID. */
+ rq->vrq->scsi.target_id = cpu_to_le16(t->virt_targ_id);
+
+ /*
+ * Test if we want to report RS_SEL for missing target.
+ * Note that if AF_DISC_PENDING is set than this will
+ * go on the defer queue.
+ */
+ if (unlikely(t->target_state != TS_PRESENT
+ && !(a->flags & AF_DISC_PENDING)))
+ rq->req_stat = RS_SEL;
+ }
+ }
+
+ if (unlikely(rq->req_stat != RS_PENDING)) {
+ esas2r_complete_request(a, rq);
+ return;
+ }
+
+ esas2r_trace("rq=%p", rq);
+ esas2r_trace("rq->vrq->scsi.handle=%x", rq->vrq->scsi.handle);
+
+ if (rq->vrq->scsi.function == VDA_FUNC_SCSI) {
+ esas2r_trace("rq->target_id=%d", rq->target_id);
+ esas2r_trace("rq->vrq->scsi.flags=%x", rq->vrq->scsi.flags);
+ }
+
+ spin_lock_irqsave(&a->queue_lock, flags);
+
+ if (likely(list_empty(&a->defer_list) &&
+ !(a->flags &
+ (AF_CHPRST_PENDING | AF_FLASHING | AF_DISC_PENDING))))
+ esas2r_local_start_request(a, startrq);
+ else
+ list_add_tail(&startrq->req_list, &a->defer_list);
+
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+}
+
+/*
+ * Starts the specified request. all requests have RS_PENDING set when this
+ * routine is called. The caller is usually esas2r_start_request, but
+ * esas2r_do_deferred_processes will start request that are deferred.
+ *
+ * The caller must ensure that requests can be started.
+ *
+ * esas2r_start_request will defer a request if there are already requests
+ * waiting or there is a chip reset pending. once the reset condition clears,
+ * esas2r_do_deferred_processes will call this function to start the request.
+ *
+ * When a request is started, it is placed on the active list and queued to
+ * the controller.
+ */
+void esas2r_local_start_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ esas2r_trace_enter();
+ esas2r_trace("rq=%p", rq);
+ esas2r_trace("rq->vrq:%p", rq->vrq);
+ esas2r_trace("rq->vrq_md->phys_addr:%x", rq->vrq_md->phys_addr);
+
+ if (unlikely(rq->vrq->scsi.function == VDA_FUNC_FLASH
+ && rq->vrq->flash.sub_func == VDA_FLASH_COMMIT))
+ esas2r_lock_set_flags(&a->flags, AF_FLASHING);
+
+ list_add_tail(&rq->req_list, &a->active_list);
+ esas2r_start_vda_request(a, rq);
+ esas2r_trace_exit();
+ return;
+}
+
+void esas2r_start_vda_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct esas2r_inbound_list_source_entry *element;
+ u32 dw;
+
+ rq->req_stat = RS_STARTED;
+ /*
+ * Calculate the inbound list entry location and the current state of
+ * toggle bit.
+ */
+ a->last_write++;
+ if (a->last_write >= a->list_size) {
+ a->last_write = 0;
+ /* update the toggle bit */
+ if (a->flags & AF_COMM_LIST_TOGGLE)
+ esas2r_lock_clear_flags(&a->flags,
+ AF_COMM_LIST_TOGGLE);
+ else
+ esas2r_lock_set_flags(&a->flags, AF_COMM_LIST_TOGGLE);
+ }
+
+ element =
+ (struct esas2r_inbound_list_source_entry *)a->inbound_list_md.
+ virt_addr
+ + a->last_write;
+
+ /* Set the VDA request size if it was never modified */
+ if (rq->vda_req_sz == RQ_SIZE_DEFAULT)
+ rq->vda_req_sz = (u16)(a->max_vdareq_size / sizeof(u32));
+
+ element->address = cpu_to_le64(rq->vrq_md->phys_addr);
+ element->length = cpu_to_le32(rq->vda_req_sz);
+
+ /* Update the write pointer */
+ dw = a->last_write;
+
+ if (a->flags & AF_COMM_LIST_TOGGLE)
+ dw |= MU_ILW_TOGGLE;
+
+ esas2r_trace("rq->vrq->scsi.handle:%x", rq->vrq->scsi.handle);
+ esas2r_trace("dw:%x", dw);
+ esas2r_trace("rq->vda_req_sz:%x", rq->vda_req_sz);
+ esas2r_write_register_dword(a, MU_IN_LIST_WRITE, dw);
+}
+
+/*
+ * Build the scatter/gather list for an I/O request according to the
+ * specifications placed in the s/g context. The caller must initialize
+ * context prior to the initial call by calling esas2r_sgc_init().
+ */
+bool esas2r_build_sg_list_sge(struct esas2r_adapter *a,
+ struct esas2r_sg_context *sgc)
+{
+ struct esas2r_request *rq = sgc->first_req;
+ union atto_vda_req *vrq = rq->vrq;
+
+ while (sgc->length) {
+ u32 rem = 0;
+ u64 addr;
+ u32 len;
+
+ len = (*sgc->get_phys_addr)(sgc, &addr);
+
+ if (unlikely(len == 0))
+ return false;
+
+ /* if current length is more than what's left, stop there */
+ if (unlikely(len > sgc->length))
+ len = sgc->length;
+
+another_entry:
+ /* limit to a round number less than the maximum length */
+ if (len > SGE_LEN_MAX) {
+ /*
+ * Save the remainder of the split. Whenever we limit
+ * an entry we come back around to build entries out
+ * of the leftover. We do this to prevent multiple
+ * calls to the get_phys_addr() function for an SGE
+ * that is too large.
+ */
+ rem = len - SGE_LEN_MAX;
+ len = SGE_LEN_MAX;
+ }
+
+ /* See if we need to allocate a new SGL */
+ if (unlikely(sgc->sge.a64.curr > sgc->sge.a64.limit)) {
+ u8 sgelen;
+ struct esas2r_mem_desc *sgl;
+
+ /*
+ * If no SGls are available, return failure. The
+ * caller can call us later with the current context
+ * to pick up here.
+ */
+ sgl = esas2r_alloc_sgl(a);
+
+ if (unlikely(sgl == NULL))
+ return false;
+
+ /* Calculate the length of the last SGE filled in */
+ sgelen = (u8)((u8 *)sgc->sge.a64.curr
+ - (u8 *)sgc->sge.a64.last);
+
+ /*
+ * Copy the last SGE filled in to the first entry of
+ * the new SGL to make room for the chain entry.
+ */
+ memcpy(sgl->virt_addr, sgc->sge.a64.last, sgelen);
+
+ /* Figure out the new curr pointer in the new segment */
+ sgc->sge.a64.curr =
+ (struct atto_vda_sge *)((u8 *)sgl->virt_addr +
+ sgelen);
+
+ /* Set the limit pointer and build the chain entry */
+ sgc->sge.a64.limit =
+ (struct atto_vda_sge *)((u8 *)sgl->virt_addr
+ + sgl_page_size
+ - sizeof(struct
+ atto_vda_sge));
+ sgc->sge.a64.last->length = cpu_to_le32(
+ SGE_CHAIN | SGE_ADDR_64);
+ sgc->sge.a64.last->address =
+ cpu_to_le64(sgl->phys_addr);
+
+ /*
+ * Now, if there was a previous chain entry, then
+ * update it to contain the length of this segment
+ * and size of this chain. otherwise this is the
+ * first SGL, so set the chain_offset in the request.
+ */
+ if (sgc->sge.a64.chain) {
+ sgc->sge.a64.chain->length |=
+ cpu_to_le32(
+ ((u8 *)(sgc->sge.a64.
+ last + 1)
+ - (u8 *)rq->sg_table->
+ virt_addr)
+ + sizeof(struct atto_vda_sge) *
+ LOBIT(SGE_CHAIN_SZ));
+ } else {
+ vrq->scsi.chain_offset = (u8)
+ ((u8 *)sgc->
+ sge.a64.last -
+ (u8 *)vrq);
+
+ /*
+ * This is the first SGL, so set the
+ * chain_offset and the VDA request size in
+ * the request.
+ */
+ rq->vda_req_sz =
+ (vrq->scsi.chain_offset +
+ sizeof(struct atto_vda_sge) +
+ 3)
+ / sizeof(u32);
+ }
+
+ /*
+ * Remember this so when we get a new SGL filled in we
+ * can update the length of this chain entry.
+ */
+ sgc->sge.a64.chain = sgc->sge.a64.last;
+
+ /* Now link the new SGL onto the primary request. */
+ list_add(&sgl->next_desc, &rq->sg_table_head);
+ }
+
+ /* Update last one filled in */
+ sgc->sge.a64.last = sgc->sge.a64.curr;
+
+ /* Build the new SGE and update the S/G context */
+ sgc->sge.a64.curr->length = cpu_to_le32(SGE_ADDR_64 | len);
+ sgc->sge.a64.curr->address = cpu_to_le32(addr);
+ sgc->sge.a64.curr++;
+ sgc->cur_offset += len;
+ sgc->length -= len;
+
+ /*
+ * Check if we previously split an entry. If so we have to
+ * pick up where we left off.
+ */
+ if (rem) {
+ addr += len;
+ len = rem;
+ rem = 0;
+ goto another_entry;
+ }
+ }
+
+ /* Mark the end of the SGL */
+ sgc->sge.a64.last->length |= cpu_to_le32(SGE_LAST);
+
+ /*
+ * If there was a previous chain entry, update the length to indicate
+ * the length of this last segment.
+ */
+ if (sgc->sge.a64.chain) {
+ sgc->sge.a64.chain->length |= cpu_to_le32(
+ ((u8 *)(sgc->sge.a64.curr) -
+ (u8 *)rq->sg_table->virt_addr));
+ } else {
+ u16 reqsize;
+
+ /*
+ * The entire VDA request was not used so lets
+ * set the size of the VDA request to be DMA'd
+ */
+ reqsize =
+ ((u16)((u8 *)sgc->sge.a64.last - (u8 *)vrq)
+ + sizeof(struct atto_vda_sge) + 3) / sizeof(u32);
+
+ /*
+ * Only update the request size if it is bigger than what is
+ * already there. We can come in here twice for some management
+ * commands.
+ */
+ if (reqsize > rq->vda_req_sz)
+ rq->vda_req_sz = reqsize;
+ }
+ return true;
+}
+
+
+/*
+ * Create PRD list for each I-block consumed by the command. This routine
+ * determines how much data is required from each I-block being consumed
+ * by the command. The first and last I-blocks can be partials and all of
+ * the I-blocks in between are for a full I-block of data.
+ *
+ * The interleave size is used to determine the number of bytes in the 1st
+ * I-block and the remaining I-blocks are what remeains.
+ */
+static bool esas2r_build_prd_iblk(struct esas2r_adapter *a,
+ struct esas2r_sg_context *sgc)
+{
+ struct esas2r_request *rq = sgc->first_req;
+ u64 addr;
+ u32 len;
+ struct esas2r_mem_desc *sgl;
+ u32 numchain = 1;
+ u32 rem = 0;
+
+ while (sgc->length) {
+ /* Get the next address/length pair */
+
+ len = (*sgc->get_phys_addr)(sgc, &addr);
+
+ if (unlikely(len == 0))
+ return false;
+
+ /* If current length is more than what's left, stop there */
+
+ if (unlikely(len > sgc->length))
+ len = sgc->length;
+
+another_entry:
+ /* Limit to a round number less than the maximum length */
+
+ if (len > PRD_LEN_MAX) {
+ /*
+ * Save the remainder of the split. whenever we limit
+ * an entry we come back around to build entries out
+ * of the leftover. We do this to prevent multiple
+ * calls to the get_phys_addr() function for an SGE
+ * that is too large.
+ */
+ rem = len - PRD_LEN_MAX;
+ len = PRD_LEN_MAX;
+ }
+
+ /* See if we need to allocate a new SGL */
+ if (sgc->sge.prd.sge_cnt == 0) {
+ if (len == sgc->length) {
+ /*
+ * We only have 1 PRD entry left.
+ * It can be placed where the chain
+ * entry would have gone
+ */
+
+ /* Build the simple SGE */
+ sgc->sge.prd.curr->ctl_len = cpu_to_le32(
+ PRD_DATA | len);
+ sgc->sge.prd.curr->address = cpu_to_le64(addr);
+
+ /* Adjust length related fields */
+ sgc->cur_offset += len;
+ sgc->length -= len;
+
+ /* We use the reserved chain entry for data */
+ numchain = 0;
+
+ break;
+ }
+
+ if (sgc->sge.prd.chain) {
+ /*
+ * Fill # of entries of current SGL in previous
+ * chain the length of this current SGL may not
+ * full.
+ */
+
+ sgc->sge.prd.chain->ctl_len |= cpu_to_le32(
+ sgc->sge.prd.sgl_max_cnt);
+ }
+
+ /*
+ * If no SGls are available, return failure. The
+ * caller can call us later with the current context
+ * to pick up here.
+ */
+
+ sgl = esas2r_alloc_sgl(a);
+
+ if (unlikely(sgl == NULL))
+ return false;
+
+ /*
+ * Link the new SGL onto the chain
+ * They are in reverse order
+ */
+ list_add(&sgl->next_desc, &rq->sg_table_head);
+
+ /*
+ * An SGL was just filled in and we are starting
+ * a new SGL. Prime the chain of the ending SGL with
+ * info that points to the new SGL. The length gets
+ * filled in when the new SGL is filled or ended
+ */
+
+ sgc->sge.prd.chain = sgc->sge.prd.curr;
+
+ sgc->sge.prd.chain->ctl_len = cpu_to_le32(PRD_CHAIN);
+ sgc->sge.prd.chain->address =
+ cpu_to_le64(sgl->phys_addr);
+
+ /*
+ * Start a new segment.
+ * Take one away and save for chain SGE
+ */
+
+ sgc->sge.prd.curr =
+ (struct atto_physical_region_description *)sgl
+ ->
+ virt_addr;
+ sgc->sge.prd.sge_cnt = sgc->sge.prd.sgl_max_cnt - 1;
+ }
+
+ sgc->sge.prd.sge_cnt--;
+ /* Build the simple SGE */
+ sgc->sge.prd.curr->ctl_len = cpu_to_le32(PRD_DATA | len);
+ sgc->sge.prd.curr->address = cpu_to_le64(addr);
+
+ /* Used another element. Point to the next one */
+
+ sgc->sge.prd.curr++;
+
+ /* Adjust length related fields */
+
+ sgc->cur_offset += len;
+ sgc->length -= len;
+
+ /*
+ * Check if we previously split an entry. If so we have to
+ * pick up where we left off.
+ */
+
+ if (rem) {
+ addr += len;
+ len = rem;
+ rem = 0;
+ goto another_entry;
+ }
+ }
+
+ if (!list_empty(&rq->sg_table_head)) {
+ if (sgc->sge.prd.chain) {
+ sgc->sge.prd.chain->ctl_len |=
+ cpu_to_le32(sgc->sge.prd.sgl_max_cnt
+ - sgc->sge.prd.sge_cnt
+ - numchain);
+ }
+ }
+
+ return true;
+}
+
+bool esas2r_build_sg_list_prd(struct esas2r_adapter *a,
+ struct esas2r_sg_context *sgc)
+{
+ struct esas2r_request *rq = sgc->first_req;
+ u32 len = sgc->length;
+ struct esas2r_target *t = a->targetdb + rq->target_id;
+ u8 is_i_o = 0;
+ u16 reqsize;
+ struct atto_physical_region_description *curr_iblk_chn;
+ u8 *cdb = (u8 *)&rq->vrq->scsi.cdb[0];
+
+ /*
+ * extract LBA from command so we can determine
+ * the I-Block boundary
+ */
+
+ if (rq->vrq->scsi.function == VDA_FUNC_SCSI
+ && t->target_state == TS_PRESENT
+ && !(t->flags & TF_PASS_THRU)) {
+ u32 lbalo = 0;
+
+ switch (rq->vrq->scsi.cdb[0]) {
+ case READ_16:
+ case WRITE_16:
+ {
+ lbalo =
+ MAKEDWORD(MAKEWORD(cdb[9],
+ cdb[8]),
+ MAKEWORD(cdb[7],
+ cdb[6]));
+ is_i_o = 1;
+ break;
+ }
+
+ case READ_12:
+ case WRITE_12:
+ case READ_10:
+ case WRITE_10:
+ {
+ lbalo =
+ MAKEDWORD(MAKEWORD(cdb[5],
+ cdb[4]),
+ MAKEWORD(cdb[3],
+ cdb[2]));
+ is_i_o = 1;
+ break;
+ }
+
+ case READ_6:
+ case WRITE_6:
+ {
+ lbalo =
+ MAKEDWORD(MAKEWORD(cdb[3],
+ cdb[2]),
+ MAKEWORD(cdb[1] & 0x1F,
+ 0));
+ is_i_o = 1;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (is_i_o) {
+ u32 startlba;
+
+ rq->vrq->scsi.iblk_cnt_prd = 0;
+
+ /* Determine size of 1st I-block PRD list */
+ startlba = t->inter_block - (lbalo & (t->inter_block -
+ 1));
+ sgc->length = startlba * t->block_size;
+
+ /* Chk if the 1st iblk chain starts at base of Iblock */
+ if ((lbalo & (t->inter_block - 1)) == 0)
+ rq->flags |= RF_1ST_IBLK_BASE;
+
+ if (sgc->length > len)
+ sgc->length = len;
+ } else {
+ sgc->length = len;
+ }
+ } else {
+ sgc->length = len;
+ }
+
+ /* get our starting chain address */
+
+ curr_iblk_chn =
+ (struct atto_physical_region_description *)sgc->sge.a64.curr;
+
+ sgc->sge.prd.sgl_max_cnt = sgl_page_size /
+ sizeof(struct
+ atto_physical_region_description);
+
+ /* create all of the I-block PRD lists */
+
+ while (len) {
+ sgc->sge.prd.sge_cnt = 0;
+ sgc->sge.prd.chain = NULL;
+ sgc->sge.prd.curr = curr_iblk_chn;
+
+ /* increment to next I-Block */
+
+ len -= sgc->length;
+
+ /* go build the next I-Block PRD list */
+
+ if (unlikely(!esas2r_build_prd_iblk(a, sgc)))
+ return false;
+
+ curr_iblk_chn++;
+
+ if (is_i_o) {
+ rq->vrq->scsi.iblk_cnt_prd++;
+
+ if (len > t->inter_byte)
+ sgc->length = t->inter_byte;
+ else
+ sgc->length = len;
+ }
+ }
+
+ /* figure out the size used of the VDA request */
+
+ reqsize = ((u16)((u8 *)curr_iblk_chn - (u8 *)rq->vrq))
+ / sizeof(u32);
+
+ /*
+ * only update the request size if it is bigger than what is
+ * already there. we can come in here twice for some management
+ * commands.
+ */
+
+ if (reqsize > rq->vda_req_sz)
+ rq->vda_req_sz = reqsize;
+
+ return true;
+}
+
+static void esas2r_handle_pending_reset(struct esas2r_adapter *a, u32 currtime)
+{
+ u32 delta = currtime - a->chip_init_time;
+
+ if (delta <= ESAS2R_CHPRST_WAIT_TIME) {
+ /* Wait before accessing registers */
+ } else if (delta >= ESAS2R_CHPRST_TIME) {
+ /*
+ * The last reset failed so try again. Reset
+ * processing will give up after three tries.
+ */
+ esas2r_local_reset_adapter(a);
+ } else {
+ /* We can now see if the firmware is ready */
+ u32 doorbell;
+
+ doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+ if (doorbell == 0xFFFFFFFF || !(doorbell & DRBL_FORCE_INT)) {
+ esas2r_force_interrupt(a);
+ } else {
+ u32 ver = (doorbell & DRBL_FW_VER_MSK);
+
+ /* Driver supports API version 0 and 1 */
+ esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+ doorbell);
+ if (ver == DRBL_FW_VER_0) {
+ esas2r_lock_set_flags(&a->flags,
+ AF_CHPRST_DETECTED);
+ esas2r_lock_set_flags(&a->flags,
+ AF_LEGACY_SGE_MODE);
+
+ a->max_vdareq_size = 128;
+ a->build_sgl = esas2r_build_sg_list_sge;
+ } else if (ver == DRBL_FW_VER_1) {
+ esas2r_lock_set_flags(&a->flags,
+ AF_CHPRST_DETECTED);
+ esas2r_lock_clear_flags(&a->flags,
+ AF_LEGACY_SGE_MODE);
+
+ a->max_vdareq_size = 1024;
+ a->build_sgl = esas2r_build_sg_list_prd;
+ } else {
+ esas2r_local_reset_adapter(a);
+ }
+ }
+ }
+}
+
+
+/* This function must be called once per timer tick */
+void esas2r_timer_tick(struct esas2r_adapter *a)
+{
+ u32 currtime = jiffies_to_msecs(jiffies);
+ u32 deltatime = currtime - a->last_tick_time;
+
+ a->last_tick_time = currtime;
+
+ /* count down the uptime */
+ if (a->chip_uptime
+ && !(a->flags & (AF_CHPRST_PENDING | AF_DISC_PENDING))) {
+ if (deltatime >= a->chip_uptime)
+ a->chip_uptime = 0;
+ else
+ a->chip_uptime -= deltatime;
+ }
+
+ if (a->flags & AF_CHPRST_PENDING) {
+ if (!(a->flags & AF_CHPRST_NEEDED)
+ && !(a->flags & AF_CHPRST_DETECTED))
+ esas2r_handle_pending_reset(a, currtime);
+ } else {
+ if (a->flags & AF_DISC_PENDING)
+ esas2r_disc_check_complete(a);
+
+ if (a->flags & AF_HEARTBEAT_ENB) {
+ if (a->flags & AF_HEARTBEAT) {
+ if ((currtime - a->heartbeat_time) >=
+ ESAS2R_HEARTBEAT_TIME) {
+ esas2r_lock_clear_flags(&a->flags,
+ AF_HEARTBEAT);
+ esas2r_hdebug("heartbeat failed");
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "heartbeat failed");
+ esas2r_bugon();
+ esas2r_local_reset_adapter(a);
+ }
+ } else {
+ esas2r_lock_set_flags(&a->flags, AF_HEARTBEAT);
+ a->heartbeat_time = currtime;
+ esas2r_force_interrupt(a);
+ }
+ }
+ }
+
+ if (atomic_read(&a->disable_cnt) == 0)
+ esas2r_do_deferred_processes(a);
+}
+
+/*
+ * Send the specified task management function to the target and LUN
+ * specified in rqaux. in addition, immediately abort any commands that
+ * are queued but not sent to the device according to the rules specified
+ * by the task management function.
+ */
+bool esas2r_send_task_mgmt(struct esas2r_adapter *a,
+ struct esas2r_request *rqaux, u8 task_mgt_func)
+{
+ u16 targetid = rqaux->target_id;
+ u8 lun = (u8)le32_to_cpu(rqaux->vrq->scsi.flags);
+ bool ret = false;
+ struct esas2r_request *rq;
+ struct list_head *next, *element;
+ unsigned long flags;
+
+ LIST_HEAD(comp_list);
+
+ esas2r_trace_enter();
+ esas2r_trace("rqaux:%p", rqaux);
+ esas2r_trace("task_mgt_func:%x", task_mgt_func);
+ spin_lock_irqsave(&a->queue_lock, flags);
+
+ /* search the defer queue looking for requests for the device */
+ list_for_each_safe(element, next, &a->defer_list) {
+ rq = list_entry(element, struct esas2r_request, req_list);
+
+ if (rq->vrq->scsi.function == VDA_FUNC_SCSI
+ && rq->target_id == targetid
+ && (((u8)le32_to_cpu(rq->vrq->scsi.flags)) == lun
+ || task_mgt_func == 0x20)) { /* target reset */
+ /* Found a request affected by the task management */
+ if (rq->req_stat == RS_PENDING) {
+ /*
+ * The request is pending or waiting. We can
+ * safelycomplete the request now.
+ */
+ if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
+ list_add_tail(&rq->comp_list,
+ &comp_list);
+ }
+ }
+ }
+
+ /* Send the task management request to the firmware */
+ rqaux->sense_len = 0;
+ rqaux->vrq->scsi.length = 0;
+ rqaux->target_id = targetid;
+ rqaux->vrq->scsi.flags |= cpu_to_le32(lun);
+ memset(rqaux->vrq->scsi.cdb, 0, sizeof(rqaux->vrq->scsi.cdb));
+ rqaux->vrq->scsi.flags |=
+ cpu_to_le16(task_mgt_func * LOBIT(FCP_CMND_TM_MASK));
+
+ if (a->flags & AF_FLASHING) {
+ /* Assume success. if there are active requests, return busy */
+ rqaux->req_stat = RS_SUCCESS;
+
+ list_for_each_safe(element, next, &a->active_list) {
+ rq = list_entry(element, struct esas2r_request,
+ req_list);
+ if (rq->vrq->scsi.function == VDA_FUNC_SCSI
+ && rq->target_id == targetid
+ && (((u8)le32_to_cpu(rq->vrq->scsi.flags)) == lun
+ || task_mgt_func == 0x20)) /* target reset */
+ rqaux->req_stat = RS_BUSY;
+ }
+
+ ret = true;
+ }
+
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+
+ if (!(a->flags & AF_FLASHING))
+ esas2r_start_request(a, rqaux);
+
+ esas2r_comp_list_drain(a, &comp_list);
+
+ if (atomic_read(&a->disable_cnt) == 0)
+ esas2r_do_deferred_processes(a);
+
+ esas2r_trace_exit();
+
+ return ret;
+}
+
+void esas2r_reset_bus(struct esas2r_adapter *a)
+{
+ esas2r_log(ESAS2R_LOG_INFO, "performing a bus reset");
+
+ if (!(a->flags & AF_DEGRADED_MODE)
+ && !(a->flags & (AF_CHPRST_PENDING | AF_DISC_PENDING))) {
+ esas2r_lock_set_flags(&a->flags, AF_BUSRST_NEEDED);
+ esas2r_lock_set_flags(&a->flags, AF_BUSRST_PENDING);
+ esas2r_lock_set_flags(&a->flags, AF_OS_RESET);
+
+ esas2r_schedule_tasklet(a);
+ }
+}
+
+bool esas2r_ioreq_aborted(struct esas2r_adapter *a, struct esas2r_request *rq,
+ u8 status)
+{
+ esas2r_trace_enter();
+ esas2r_trace("rq:%p", rq);
+ list_del_init(&rq->req_list);
+ if (rq->timeout > RQ_MAX_TIMEOUT) {
+ /*
+ * The request timed out, but we could not abort it because a
+ * chip reset occurred. Return busy status.
+ */
+ rq->req_stat = RS_BUSY;
+ esas2r_trace_exit();
+ return true;
+ }
+
+ rq->req_stat = status;
+ esas2r_trace_exit();
+ return true;
+}
diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c b/drivers/scsi/esas2r/esas2r_ioctl.c
new file mode 100644
index 00000000000..f3d0cb88597
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_ioctl.c
@@ -0,0 +1,2110 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r_ioctl.c
+ * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+/*
+ * Buffered ioctl handlers. A buffered ioctl is one which requires that we
+ * allocate a DMA-able memory area to communicate with the firmware. In
+ * order to prevent continually allocating and freeing consistent memory,
+ * we will allocate a global buffer the first time we need it and re-use
+ * it for subsequent ioctl calls that require it.
+ */
+
+u8 *esas2r_buffered_ioctl;
+dma_addr_t esas2r_buffered_ioctl_addr;
+u32 esas2r_buffered_ioctl_size;
+struct pci_dev *esas2r_buffered_ioctl_pcid;
+
+static DEFINE_SEMAPHORE(buffered_ioctl_semaphore);
+typedef int (*BUFFERED_IOCTL_CALLBACK)(struct esas2r_adapter *,
+ struct esas2r_request *,
+ struct esas2r_sg_context *,
+ void *);
+typedef void (*BUFFERED_IOCTL_DONE_CALLBACK)(struct esas2r_adapter *,
+ struct esas2r_request *, void *);
+
+struct esas2r_buffered_ioctl {
+ struct esas2r_adapter *a;
+ void *ioctl;
+ u32 length;
+ u32 control_code;
+ u32 offset;
+ BUFFERED_IOCTL_CALLBACK
+ callback;
+ void *context;
+ BUFFERED_IOCTL_DONE_CALLBACK
+ done_callback;
+ void *done_context;
+
+};
+
+static void complete_fm_api_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ a->fm_api_command_done = 1;
+ wake_up_interruptible(&a->fm_api_waiter);
+}
+
+/* Callbacks for building scatter/gather lists for FM API requests */
+static u32 get_physaddr_fm_api(struct esas2r_sg_context *sgc, u64 *addr)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)sgc->adapter;
+ int offset = sgc->cur_offset - a->save_offset;
+
+ (*addr) = a->firmware.phys + offset;
+ return a->firmware.orig_len - offset;
+}
+
+static u32 get_physaddr_fm_api_header(struct esas2r_sg_context *sgc, u64 *addr)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)sgc->adapter;
+ int offset = sgc->cur_offset - a->save_offset;
+
+ (*addr) = a->firmware.header_buff_phys + offset;
+ return sizeof(struct esas2r_flash_img) - offset;
+}
+
+/* Handle EXPRESS_IOCTL_RW_FIRMWARE ioctl with img_type = FW_IMG_FM_API. */
+static void do_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
+{
+ struct esas2r_request *rq;
+
+ if (down_interruptible(&a->fm_api_semaphore)) {
+ fi->status = FI_STAT_BUSY;
+ return;
+ }
+
+ rq = esas2r_alloc_request(a);
+ if (rq == NULL) {
+ up(&a->fm_api_semaphore);
+ fi->status = FI_STAT_BUSY;
+ return;
+ }
+
+ if (fi == &a->firmware.header) {
+ a->firmware.header_buff = dma_alloc_coherent(&a->pcid->dev,
+ (size_t)sizeof(
+ struct
+ esas2r_flash_img),
+ (dma_addr_t *)&a->
+ firmware.
+ header_buff_phys,
+ GFP_KERNEL);
+
+ if (a->firmware.header_buff == NULL) {
+ esas2r_debug("failed to allocate header buffer!");
+ fi->status = FI_STAT_BUSY;
+ return;
+ }
+
+ memcpy(a->firmware.header_buff, fi,
+ sizeof(struct esas2r_flash_img));
+ a->save_offset = a->firmware.header_buff;
+ a->fm_api_sgc.get_phys_addr =
+ (PGETPHYSADDR)get_physaddr_fm_api_header;
+ } else {
+ a->save_offset = (u8 *)fi;
+ a->fm_api_sgc.get_phys_addr =
+ (PGETPHYSADDR)get_physaddr_fm_api;
+ }
+
+ rq->comp_cb = complete_fm_api_req;
+ a->fm_api_command_done = 0;
+ a->fm_api_sgc.cur_offset = a->save_offset;
+
+ if (!esas2r_fm_api(a, (struct esas2r_flash_img *)a->save_offset, rq,
+ &a->fm_api_sgc))
+ goto all_done;
+
+ /* Now wait around for it to complete. */
+ while (!a->fm_api_command_done)
+ wait_event_interruptible(a->fm_api_waiter,
+ a->fm_api_command_done);
+all_done:
+ if (fi == &a->firmware.header) {
+ memcpy(fi, a->firmware.header_buff,
+ sizeof(struct esas2r_flash_img));
+
+ dma_free_coherent(&a->pcid->dev,
+ (size_t)sizeof(struct esas2r_flash_img),
+ a->firmware.header_buff,
+ (dma_addr_t)a->firmware.header_buff_phys);
+ }
+
+ up(&a->fm_api_semaphore);
+ esas2r_free_request(a, (struct esas2r_request *)rq);
+ return;
+
+}
+
+static void complete_nvr_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ a->nvram_command_done = 1;
+ wake_up_interruptible(&a->nvram_waiter);
+}
+
+/* Callback for building scatter/gather lists for buffered ioctls */
+static u32 get_physaddr_buffered_ioctl(struct esas2r_sg_context *sgc,
+ u64 *addr)
+{
+ int offset = (u8 *)sgc->cur_offset - esas2r_buffered_ioctl;
+
+ (*addr) = esas2r_buffered_ioctl_addr + offset;
+ return esas2r_buffered_ioctl_size - offset;
+}
+
+static void complete_buffered_ioctl_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ a->buffered_ioctl_done = 1;
+ wake_up_interruptible(&a->buffered_ioctl_waiter);
+}
+
+static u8 handle_buffered_ioctl(struct esas2r_buffered_ioctl *bi)
+{
+ struct esas2r_adapter *a = bi->a;
+ struct esas2r_request *rq;
+ struct esas2r_sg_context sgc;
+ u8 result = IOCTL_SUCCESS;
+
+ if (down_interruptible(&buffered_ioctl_semaphore))
+ return IOCTL_OUT_OF_RESOURCES;
+
+ /* allocate a buffer or use the existing buffer. */
+ if (esas2r_buffered_ioctl) {
+ if (esas2r_buffered_ioctl_size < bi->length) {
+ /* free the too-small buffer and get a new one */
+ dma_free_coherent(&a->pcid->dev,
+ (size_t)esas2r_buffered_ioctl_size,
+ esas2r_buffered_ioctl,
+ esas2r_buffered_ioctl_addr);
+
+ goto allocate_buffer;
+ }
+ } else {
+allocate_buffer:
+ esas2r_buffered_ioctl_size = bi->length;
+ esas2r_buffered_ioctl_pcid = a->pcid;
+ esas2r_buffered_ioctl = dma_alloc_coherent(&a->pcid->dev,
+ (size_t)
+ esas2r_buffered_ioctl_size,
+ &
+ esas2r_buffered_ioctl_addr,
+ GFP_KERNEL);
+ }
+
+ if (!esas2r_buffered_ioctl) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "could not allocate %d bytes of consistent memory "
+ "for a buffered ioctl!",
+ bi->length);
+
+ esas2r_debug("buffered ioctl alloc failure");
+ result = IOCTL_OUT_OF_RESOURCES;
+ goto exit_cleanly;
+ }
+
+ memcpy(esas2r_buffered_ioctl, bi->ioctl, bi->length);
+
+ rq = esas2r_alloc_request(a);
+ if (rq == NULL) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "could not allocate an internal request");
+
+ result = IOCTL_OUT_OF_RESOURCES;
+ esas2r_debug("buffered ioctl - no requests");
+ goto exit_cleanly;
+ }
+
+ a->buffered_ioctl_done = 0;
+ rq->comp_cb = complete_buffered_ioctl_req;
+ sgc.cur_offset = esas2r_buffered_ioctl + bi->offset;
+ sgc.get_phys_addr = (PGETPHYSADDR)get_physaddr_buffered_ioctl;
+ sgc.length = esas2r_buffered_ioctl_size;
+
+ if (!(*bi->callback)(a, rq, &sgc, bi->context)) {
+ /* completed immediately, no need to wait */
+ a->buffered_ioctl_done = 0;
+ goto free_andexit_cleanly;
+ }
+
+ /* now wait around for it to complete. */
+ while (!a->buffered_ioctl_done)
+ wait_event_interruptible(a->buffered_ioctl_waiter,
+ a->buffered_ioctl_done);
+
+free_andexit_cleanly:
+ if (result == IOCTL_SUCCESS && bi->done_callback)
+ (*bi->done_callback)(a, rq, bi->done_context);
+
+ esas2r_free_request(a, rq);
+
+exit_cleanly:
+ if (result == IOCTL_SUCCESS)
+ memcpy(bi->ioctl, esas2r_buffered_ioctl, bi->length);
+
+ up(&buffered_ioctl_semaphore);
+ return result;
+}
+
+/* SMP ioctl support */
+static int smp_ioctl_callback(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ struct esas2r_sg_context *sgc, void *context)
+{
+ struct atto_ioctl_smp *si =
+ (struct atto_ioctl_smp *)esas2r_buffered_ioctl;
+
+ esas2r_sgc_init(sgc, a, rq, rq->vrq->ioctl.sge);
+ esas2r_build_ioctl_req(a, rq, sgc->length, VDA_IOCTL_SMP);
+
+ if (!esas2r_build_sg_list(a, rq, sgc)) {
+ si->status = ATTO_STS_OUT_OF_RSRC;
+ return false;
+ }
+
+ esas2r_start_request(a, rq);
+ return true;
+}
+
+static u8 handle_smp_ioctl(struct esas2r_adapter *a, struct atto_ioctl_smp *si)
+{
+ struct esas2r_buffered_ioctl bi;
+
+ memset(&bi, 0, sizeof(bi));
+
+ bi.a = a;
+ bi.ioctl = si;
+ bi.length = sizeof(struct atto_ioctl_smp)
+ + le32_to_cpu(si->req_length)
+ + le32_to_cpu(si->rsp_length);
+ bi.offset = 0;
+ bi.callback = smp_ioctl_callback;
+ return handle_buffered_ioctl(&bi);
+}
+
+
+/* CSMI ioctl support */
+static void esas2r_csmi_ioctl_tunnel_comp_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ rq->target_id = le16_to_cpu(rq->func_rsp.ioctl_rsp.csmi.target_id);
+ rq->vrq->scsi.flags |= cpu_to_le32(rq->func_rsp.ioctl_rsp.csmi.lun);
+
+ /* Now call the original completion callback. */
+ (*rq->aux_req_cb)(a, rq);
+}
+
+/* Tunnel a CSMI IOCTL to the back end driver for processing. */
+static bool csmi_ioctl_tunnel(struct esas2r_adapter *a,
+ union atto_ioctl_csmi *ci,
+ struct esas2r_request *rq,
+ struct esas2r_sg_context *sgc,
+ u32 ctrl_code,
+ u16 target_id)
+{
+ struct atto_vda_ioctl_req *ioctl = &rq->vrq->ioctl;
+
+ if (a->flags & AF_DEGRADED_MODE)
+ return false;
+
+ esas2r_sgc_init(sgc, a, rq, rq->vrq->ioctl.sge);
+ esas2r_build_ioctl_req(a, rq, sgc->length, VDA_IOCTL_CSMI);
+ ioctl->csmi.ctrl_code = cpu_to_le32(ctrl_code);
+ ioctl->csmi.target_id = cpu_to_le16(target_id);
+ ioctl->csmi.lun = (u8)le32_to_cpu(rq->vrq->scsi.flags);
+
+ /*
+ * Always usurp the completion callback since the interrupt callback
+ * mechanism may be used.
+ */
+ rq->aux_req_cx = ci;
+ rq->aux_req_cb = rq->comp_cb;
+ rq->comp_cb = esas2r_csmi_ioctl_tunnel_comp_cb;
+
+ if (!esas2r_build_sg_list(a, rq, sgc))
+ return false;
+
+ esas2r_start_request(a, rq);
+ return true;
+}
+
+static bool check_lun(struct scsi_lun lun)
+{
+ bool result;
+
+ result = ((lun.scsi_lun[7] == 0) &&
+ (lun.scsi_lun[6] == 0) &&
+ (lun.scsi_lun[5] == 0) &&
+ (lun.scsi_lun[4] == 0) &&
+ (lun.scsi_lun[3] == 0) &&
+ (lun.scsi_lun[2] == 0) &&
+/* Byte 1 is intentionally skipped */
+ (lun.scsi_lun[0] == 0));
+
+ return result;
+}
+
+static int csmi_ioctl_callback(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ struct esas2r_sg_context *sgc, void *context)
+{
+ struct atto_csmi *ci = (struct atto_csmi *)context;
+ union atto_ioctl_csmi *ioctl_csmi =
+ (union atto_ioctl_csmi *)esas2r_buffered_ioctl;
+ u8 path = 0;
+ u8 tid = 0;
+ u8 lun = 0;
+ u32 sts = CSMI_STS_SUCCESS;
+ struct esas2r_target *t;
+ unsigned long flags;
+
+ if (ci->control_code == CSMI_CC_GET_DEV_ADDR) {
+ struct atto_csmi_get_dev_addr *gda = &ci->data.dev_addr;
+
+ path = gda->path_id;
+ tid = gda->target_id;
+ lun = gda->lun;
+ } else if (ci->control_code == CSMI_CC_TASK_MGT) {
+ struct atto_csmi_task_mgmt *tm = &ci->data.tsk_mgt;
+
+ path = tm->path_id;
+ tid = tm->target_id;
+ lun = tm->lun;
+ }
+
+ if (path > 0 || tid > ESAS2R_MAX_ID) {
+ rq->func_rsp.ioctl_rsp.csmi.csmi_status = cpu_to_le32(
+ CSMI_STS_INV_PARAM);
+ return false;
+ }
+
+ rq->target_id = tid;
+ rq->vrq->scsi.flags |= cpu_to_le32(lun);
+
+ switch (ci->control_code) {
+ case CSMI_CC_GET_DRVR_INFO:
+ {
+ struct atto_csmi_get_driver_info *gdi = &ioctl_csmi->drvr_info;
+
+ strcpy(gdi->description, esas2r_get_model_name(a));
+ gdi->csmi_major_rev = CSMI_MAJOR_REV;
+ gdi->csmi_minor_rev = CSMI_MINOR_REV;
+ break;
+ }
+
+ case CSMI_CC_GET_CNTLR_CFG:
+ {
+ struct atto_csmi_get_cntlr_cfg *gcc = &ioctl_csmi->cntlr_cfg;
+
+ gcc->base_io_addr = 0;
+ pci_read_config_dword(a->pcid, PCI_BASE_ADDRESS_2,
+ &gcc->base_memaddr_lo);
+ pci_read_config_dword(a->pcid, PCI_BASE_ADDRESS_3,
+ &gcc->base_memaddr_hi);
+ gcc->board_id = MAKEDWORD(a->pcid->subsystem_device,
+ a->pcid->subsystem_vendor);
+ gcc->slot_num = CSMI_SLOT_NUM_UNKNOWN;
+ gcc->cntlr_class = CSMI_CNTLR_CLASS_HBA;
+ gcc->io_bus_type = CSMI_BUS_TYPE_PCI;
+ gcc->pci_addr.bus_num = a->pcid->bus->number;
+ gcc->pci_addr.device_num = PCI_SLOT(a->pcid->devfn);
+ gcc->pci_addr.function_num = PCI_FUNC(a->pcid->devfn);
+
+ memset(gcc->serial_num, 0, sizeof(gcc->serial_num));
+
+ gcc->major_rev = LOBYTE(LOWORD(a->fw_version));
+ gcc->minor_rev = HIBYTE(LOWORD(a->fw_version));
+ gcc->build_rev = LOBYTE(HIWORD(a->fw_version));
+ gcc->release_rev = HIBYTE(HIWORD(a->fw_version));
+ gcc->bios_major_rev = HIBYTE(HIWORD(a->flash_ver));
+ gcc->bios_minor_rev = LOBYTE(HIWORD(a->flash_ver));
+ gcc->bios_build_rev = LOWORD(a->flash_ver);
+
+ if (a->flags2 & AF2_THUNDERLINK)
+ gcc->cntlr_flags = CSMI_CNTLRF_SAS_HBA
+ | CSMI_CNTLRF_SATA_HBA;
+ else
+ gcc->cntlr_flags = CSMI_CNTLRF_SAS_RAID
+ | CSMI_CNTLRF_SATA_RAID;
+
+ gcc->rrom_major_rev = 0;
+ gcc->rrom_minor_rev = 0;
+ gcc->rrom_build_rev = 0;
+ gcc->rrom_release_rev = 0;
+ gcc->rrom_biosmajor_rev = 0;
+ gcc->rrom_biosminor_rev = 0;
+ gcc->rrom_biosbuild_rev = 0;
+ gcc->rrom_biosrelease_rev = 0;
+ break;
+ }
+
+ case CSMI_CC_GET_CNTLR_STS:
+ {
+ struct atto_csmi_get_cntlr_sts *gcs = &ioctl_csmi->cntlr_sts;
+
+ if (a->flags & AF_DEGRADED_MODE)
+ gcs->status = CSMI_CNTLR_STS_FAILED;
+ else
+ gcs->status = CSMI_CNTLR_STS_GOOD;
+
+ gcs->offline_reason = CSMI_OFFLINE_NO_REASON;
+ break;
+ }
+
+ case CSMI_CC_FW_DOWNLOAD:
+ case CSMI_CC_GET_RAID_INFO:
+ case CSMI_CC_GET_RAID_CFG:
+
+ sts = CSMI_STS_BAD_CTRL_CODE;
+ break;
+
+ case CSMI_CC_SMP_PASSTHRU:
+ case CSMI_CC_SSP_PASSTHRU:
+ case CSMI_CC_STP_PASSTHRU:
+ case CSMI_CC_GET_PHY_INFO:
+ case CSMI_CC_SET_PHY_INFO:
+ case CSMI_CC_GET_LINK_ERRORS:
+ case CSMI_CC_GET_SATA_SIG:
+ case CSMI_CC_GET_CONN_INFO:
+ case CSMI_CC_PHY_CTRL:
+
+ if (!csmi_ioctl_tunnel(a, ioctl_csmi, rq, sgc,
+ ci->control_code,
+ ESAS2R_TARG_ID_INV)) {
+ sts = CSMI_STS_FAILED;
+ break;
+ }
+
+ return true;
+
+ case CSMI_CC_GET_SCSI_ADDR:
+ {
+ struct atto_csmi_get_scsi_addr *gsa = &ioctl_csmi->scsi_addr;
+
+ struct scsi_lun lun;
+
+ memcpy(&lun, gsa->sas_lun, sizeof(struct scsi_lun));
+
+ if (!check_lun(lun)) {
+ sts = CSMI_STS_NO_SCSI_ADDR;
+ break;
+ }
+
+ /* make sure the device is present */
+ spin_lock_irqsave(&a->mem_lock, flags);
+ t = esas2r_targ_db_find_by_sas_addr(a, (u64 *)gsa->sas_addr);
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+
+ if (t == NULL) {
+ sts = CSMI_STS_NO_SCSI_ADDR;
+ break;
+ }
+
+ gsa->host_index = 0xFF;
+ gsa->lun = gsa->sas_lun[1];
+ rq->target_id = esas2r_targ_get_id(t, a);
+ break;
+ }
+
+ case CSMI_CC_GET_DEV_ADDR:
+ {
+ struct atto_csmi_get_dev_addr *gda = &ioctl_csmi->dev_addr;
+
+ /* make sure the target is present */
+ t = a->targetdb + rq->target_id;
+
+ if (t >= a->targetdb_end
+ || t->target_state != TS_PRESENT
+ || t->sas_addr == 0) {
+ sts = CSMI_STS_NO_DEV_ADDR;
+ break;
+ }
+
+ /* fill in the result */
+ *(u64 *)gda->sas_addr = t->sas_addr;
+ memset(gda->sas_lun, 0, sizeof(gda->sas_lun));
+ gda->sas_lun[1] = (u8)le32_to_cpu(rq->vrq->scsi.flags);
+ break;
+ }
+
+ case CSMI_CC_TASK_MGT:
+
+ /* make sure the target is present */
+ t = a->targetdb + rq->target_id;
+
+ if (t >= a->targetdb_end
+ || t->target_state != TS_PRESENT
+ || !(t->flags & TF_PASS_THRU)) {
+ sts = CSMI_STS_NO_DEV_ADDR;
+ break;
+ }
+
+ if (!csmi_ioctl_tunnel(a, ioctl_csmi, rq, sgc,
+ ci->control_code,
+ t->phys_targ_id)) {
+ sts = CSMI_STS_FAILED;
+ break;
+ }
+
+ return true;
+
+ default:
+
+ sts = CSMI_STS_BAD_CTRL_CODE;
+ break;
+ }
+
+ rq->func_rsp.ioctl_rsp.csmi.csmi_status = cpu_to_le32(sts);
+
+ return false;
+}
+
+
+static void csmi_ioctl_done_callback(struct esas2r_adapter *a,
+ struct esas2r_request *rq, void *context)
+{
+ struct atto_csmi *ci = (struct atto_csmi *)context;
+ union atto_ioctl_csmi *ioctl_csmi =
+ (union atto_ioctl_csmi *)esas2r_buffered_ioctl;
+
+ switch (ci->control_code) {
+ case CSMI_CC_GET_DRVR_INFO:
+ {
+ struct atto_csmi_get_driver_info *gdi =
+ &ioctl_csmi->drvr_info;
+
+ strcpy(gdi->name, ESAS2R_VERSION_STR);
+
+ gdi->major_rev = ESAS2R_MAJOR_REV;
+ gdi->minor_rev = ESAS2R_MINOR_REV;
+ gdi->build_rev = 0;
+ gdi->release_rev = 0;
+ break;
+ }
+
+ case CSMI_CC_GET_SCSI_ADDR:
+ {
+ struct atto_csmi_get_scsi_addr *gsa = &ioctl_csmi->scsi_addr;
+
+ if (le32_to_cpu(rq->func_rsp.ioctl_rsp.csmi.csmi_status) ==
+ CSMI_STS_SUCCESS) {
+ gsa->target_id = rq->target_id;
+ gsa->path_id = 0;
+ }
+
+ break;
+ }
+ }
+
+ ci->status = le32_to_cpu(rq->func_rsp.ioctl_rsp.csmi.csmi_status);
+}
+
+
+static u8 handle_csmi_ioctl(struct esas2r_adapter *a, struct atto_csmi *ci)
+{
+ struct esas2r_buffered_ioctl bi;
+
+ memset(&bi, 0, sizeof(bi));
+
+ bi.a = a;
+ bi.ioctl = &ci->data;
+ bi.length = sizeof(union atto_ioctl_csmi);
+ bi.offset = 0;
+ bi.callback = csmi_ioctl_callback;
+ bi.context = ci;
+ bi.done_callback = csmi_ioctl_done_callback;
+ bi.done_context = ci;
+
+ return handle_buffered_ioctl(&bi);
+}
+
+/* ATTO HBA ioctl support */
+
+/* Tunnel an ATTO HBA IOCTL to the back end driver for processing. */
+static bool hba_ioctl_tunnel(struct esas2r_adapter *a,
+ struct atto_ioctl *hi,
+ struct esas2r_request *rq,
+ struct esas2r_sg_context *sgc)
+{
+ esas2r_sgc_init(sgc, a, rq, rq->vrq->ioctl.sge);
+
+ esas2r_build_ioctl_req(a, rq, sgc->length, VDA_IOCTL_HBA);
+
+ if (!esas2r_build_sg_list(a, rq, sgc)) {
+ hi->status = ATTO_STS_OUT_OF_RSRC;
+
+ return false;
+ }
+
+ esas2r_start_request(a, rq);
+
+ return true;
+}
+
+static void scsi_passthru_comp_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct atto_ioctl *hi = (struct atto_ioctl *)rq->aux_req_cx;
+ struct atto_hba_scsi_pass_thru *spt = &hi->data.scsi_pass_thru;
+ u8 sts = ATTO_SPT_RS_FAILED;
+
+ spt->scsi_status = rq->func_rsp.scsi_rsp.scsi_stat;
+ spt->sense_length = rq->sense_len;
+ spt->residual_length =
+ le32_to_cpu(rq->func_rsp.scsi_rsp.residual_length);
+
+ switch (rq->req_stat) {
+ case RS_SUCCESS:
+ case RS_SCSI_ERROR:
+ sts = ATTO_SPT_RS_SUCCESS;
+ break;
+ case RS_UNDERRUN:
+ sts = ATTO_SPT_RS_UNDERRUN;
+ break;
+ case RS_OVERRUN:
+ sts = ATTO_SPT_RS_OVERRUN;
+ break;
+ case RS_SEL:
+ case RS_SEL2:
+ sts = ATTO_SPT_RS_NO_DEVICE;
+ break;
+ case RS_NO_LUN:
+ sts = ATTO_SPT_RS_NO_LUN;
+ break;
+ case RS_TIMEOUT:
+ sts = ATTO_SPT_RS_TIMEOUT;
+ break;
+ case RS_DEGRADED:
+ sts = ATTO_SPT_RS_DEGRADED;
+ break;
+ case RS_BUSY:
+ sts = ATTO_SPT_RS_BUSY;
+ break;
+ case RS_ABORTED:
+ sts = ATTO_SPT_RS_ABORTED;
+ break;
+ case RS_RESET:
+ sts = ATTO_SPT_RS_BUS_RESET;
+ break;
+ }
+
+ spt->req_status = sts;
+
+ /* Update the target ID to the next one present. */
+ spt->target_id =
+ esas2r_targ_db_find_next_present(a, (u16)spt->target_id);
+
+ /* Done, call the completion callback. */
+ (*rq->aux_req_cb)(a, rq);
+}
+
+static int hba_ioctl_callback(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ struct esas2r_sg_context *sgc,
+ void *context)
+{
+ struct atto_ioctl *hi = (struct atto_ioctl *)esas2r_buffered_ioctl;
+
+ hi->status = ATTO_STS_SUCCESS;
+
+ switch (hi->function) {
+ case ATTO_FUNC_GET_ADAP_INFO:
+ {
+ u8 *class_code = (u8 *)&a->pcid->class;
+
+ struct atto_hba_get_adapter_info *gai =
+ &hi->data.get_adap_info;
+ int pcie_cap_reg;
+
+ if (hi->flags & HBAF_TUNNEL) {
+ hi->status = ATTO_STS_UNSUPPORTED;
+ break;
+ }
+
+ if (hi->version > ATTO_VER_GET_ADAP_INFO0) {
+ hi->status = ATTO_STS_INV_VERSION;
+ hi->version = ATTO_VER_GET_ADAP_INFO0;
+ break;
+ }
+
+ memset(gai, 0, sizeof(*gai));
+
+ gai->pci.vendor_id = a->pcid->vendor;
+ gai->pci.device_id = a->pcid->device;
+ gai->pci.ss_vendor_id = a->pcid->subsystem_vendor;
+ gai->pci.ss_device_id = a->pcid->subsystem_device;
+ gai->pci.class_code[0] = class_code[0];
+ gai->pci.class_code[1] = class_code[1];
+ gai->pci.class_code[2] = class_code[2];
+ gai->pci.rev_id = a->pcid->revision;
+ gai->pci.bus_num = a->pcid->bus->number;
+ gai->pci.dev_num = PCI_SLOT(a->pcid->devfn);
+ gai->pci.func_num = PCI_FUNC(a->pcid->devfn);
+
+ pcie_cap_reg = pci_find_capability(a->pcid, PCI_CAP_ID_EXP);
+ if (pcie_cap_reg) {
+ u16 stat;
+ u32 caps;
+
+ pci_read_config_word(a->pcid,
+ pcie_cap_reg + PCI_EXP_LNKSTA,
+ &stat);
+ pci_read_config_dword(a->pcid,
+ pcie_cap_reg + PCI_EXP_LNKCAP,
+ &caps);
+
+ gai->pci.link_speed_curr =
+ (u8)(stat & PCI_EXP_LNKSTA_CLS);
+ gai->pci.link_speed_max =
+ (u8)(caps & PCI_EXP_LNKCAP_SLS);
+ gai->pci.link_width_curr =
+ (u8)((stat & PCI_EXP_LNKSTA_NLW)
+ >> PCI_EXP_LNKSTA_NLW_SHIFT);
+ gai->pci.link_width_max =
+ (u8)((caps & PCI_EXP_LNKCAP_MLW)
+ >> 4);
+ }
+
+ gai->pci.msi_vector_cnt = 1;
+
+ if (a->pcid->msix_enabled)
+ gai->pci.interrupt_mode = ATTO_GAI_PCIIM_MSIX;
+ else if (a->pcid->msi_enabled)
+ gai->pci.interrupt_mode = ATTO_GAI_PCIIM_MSI;
+ else
+ gai->pci.interrupt_mode = ATTO_GAI_PCIIM_LEGACY;
+
+ gai->adap_type = ATTO_GAI_AT_ESASRAID2;
+
+ if (a->flags2 & AF2_THUNDERLINK)
+ gai->adap_type = ATTO_GAI_AT_TLSASHBA;
+
+ if (a->flags & AF_DEGRADED_MODE)
+ gai->adap_flags |= ATTO_GAI_AF_DEGRADED;
+
+ gai->adap_flags |= ATTO_GAI_AF_SPT_SUPP |
+ ATTO_GAI_AF_DEVADDR_SUPP;
+
+ if (a->pcid->subsystem_device == ATTO_ESAS_R60F
+ || a->pcid->subsystem_device == ATTO_ESAS_R608
+ || a->pcid->subsystem_device == ATTO_ESAS_R644
+ || a->pcid->subsystem_device == ATTO_TSSC_3808E)
+ gai->adap_flags |= ATTO_GAI_AF_VIRT_SES;
+
+ gai->num_ports = ESAS2R_NUM_PHYS;
+ gai->num_phys = ESAS2R_NUM_PHYS;
+
+ strcpy(gai->firmware_rev, a->fw_rev);
+ strcpy(gai->flash_rev, a->flash_rev);
+ strcpy(gai->model_name_short, esas2r_get_model_name_short(a));
+ strcpy(gai->model_name, esas2r_get_model_name(a));
+
+ gai->num_targets = ESAS2R_MAX_TARGETS;
+
+ gai->num_busses = 1;
+ gai->num_targsper_bus = gai->num_targets;
+ gai->num_lunsper_targ = 256;
+
+ if (a->pcid->subsystem_device == ATTO_ESAS_R6F0
+ || a->pcid->subsystem_device == ATTO_ESAS_R60F)
+ gai->num_connectors = 4;
+ else
+ gai->num_connectors = 2;
+
+ gai->adap_flags2 |= ATTO_GAI_AF2_ADAP_CTRL_SUPP;
+
+ gai->num_targets_backend = a->num_targets_backend;
+
+ gai->tunnel_flags = a->ioctl_tunnel
+ & (ATTO_GAI_TF_MEM_RW
+ | ATTO_GAI_TF_TRACE
+ | ATTO_GAI_TF_SCSI_PASS_THRU
+ | ATTO_GAI_TF_GET_DEV_ADDR
+ | ATTO_GAI_TF_PHY_CTRL
+ | ATTO_GAI_TF_CONN_CTRL
+ | ATTO_GAI_TF_GET_DEV_INFO);
+ break;
+ }
+
+ case ATTO_FUNC_GET_ADAP_ADDR:
+ {
+ struct atto_hba_get_adapter_address *gaa =
+ &hi->data.get_adap_addr;
+
+ if (hi->flags & HBAF_TUNNEL) {
+ hi->status = ATTO_STS_UNSUPPORTED;
+ break;
+ }
+
+ if (hi->version > ATTO_VER_GET_ADAP_ADDR0) {
+ hi->status = ATTO_STS_INV_VERSION;
+ hi->version = ATTO_VER_GET_ADAP_ADDR0;
+ } else if (gaa->addr_type == ATTO_GAA_AT_PORT
+ || gaa->addr_type == ATTO_GAA_AT_NODE) {
+ if (gaa->addr_type == ATTO_GAA_AT_PORT
+ && gaa->port_id >= ESAS2R_NUM_PHYS) {
+ hi->status = ATTO_STS_NOT_APPL;
+ } else {
+ memcpy((u64 *)gaa->address,
+ &a->nvram->sas_addr[0], sizeof(u64));
+ gaa->addr_len = sizeof(u64);
+ }
+ } else {
+ hi->status = ATTO_STS_INV_PARAM;
+ }
+
+ break;
+ }
+
+ case ATTO_FUNC_MEM_RW:
+ {
+ if (hi->flags & HBAF_TUNNEL) {
+ if (hba_ioctl_tunnel(a, hi, rq, sgc))
+ return true;
+
+ break;
+ }
+
+ hi->status = ATTO_STS_UNSUPPORTED;
+
+ break;
+ }
+
+ case ATTO_FUNC_TRACE:
+ {
+ struct atto_hba_trace *trc = &hi->data.trace;
+
+ if (hi->flags & HBAF_TUNNEL) {
+ if (hba_ioctl_tunnel(a, hi, rq, sgc))
+ return true;
+
+ break;
+ }
+
+ if (hi->version > ATTO_VER_TRACE1) {
+ hi->status = ATTO_STS_INV_VERSION;
+ hi->version = ATTO_VER_TRACE1;
+ break;
+ }
+
+ if (trc->trace_type == ATTO_TRC_TT_FWCOREDUMP
+ && hi->version >= ATTO_VER_TRACE1) {
+ if (trc->trace_func == ATTO_TRC_TF_UPLOAD) {
+ u32 len = hi->data_length;
+ u32 offset = trc->current_offset;
+ u32 total_len = ESAS2R_FWCOREDUMP_SZ;
+
+ /* Size is zero if a core dump isn't present */
+ if (!(a->flags2 & AF2_COREDUMP_SAVED))
+ total_len = 0;
+
+ if (len > total_len)
+ len = total_len;
+
+ if (offset >= total_len
+ || offset + len > total_len
+ || len == 0) {
+ hi->status = ATTO_STS_INV_PARAM;
+ break;
+ }
+
+ memcpy(trc + 1,
+ a->fw_coredump_buff + offset,
+ len);
+
+ hi->data_length = len;
+ } else if (trc->trace_func == ATTO_TRC_TF_RESET) {
+ memset(a->fw_coredump_buff, 0,
+ ESAS2R_FWCOREDUMP_SZ);
+
+ esas2r_lock_clear_flags(&a->flags2,
+ AF2_COREDUMP_SAVED);
+ } else if (trc->trace_func != ATTO_TRC_TF_GET_INFO) {
+ hi->status = ATTO_STS_UNSUPPORTED;
+ break;
+ }
+
+ /* Always return all the info we can. */
+ trc->trace_mask = 0;
+ trc->current_offset = 0;
+ trc->total_length = ESAS2R_FWCOREDUMP_SZ;
+
+ /* Return zero length buffer if core dump not present */
+ if (!(a->flags2 & AF2_COREDUMP_SAVED))
+ trc->total_length = 0;
+ } else {
+ hi->status = ATTO_STS_UNSUPPORTED;
+ }
+
+ break;
+ }
+
+ case ATTO_FUNC_SCSI_PASS_THRU:
+ {
+ struct atto_hba_scsi_pass_thru *spt = &hi->data.scsi_pass_thru;
+ struct scsi_lun lun;
+
+ memcpy(&lun, spt->lun, sizeof(struct scsi_lun));
+
+ if (hi->flags & HBAF_TUNNEL) {
+ if (hba_ioctl_tunnel(a, hi, rq, sgc))
+ return true;
+
+ break;
+ }
+
+ if (hi->version > ATTO_VER_SCSI_PASS_THRU0) {
+ hi->status = ATTO_STS_INV_VERSION;
+ hi->version = ATTO_VER_SCSI_PASS_THRU0;
+ break;
+ }
+
+ if (spt->target_id >= ESAS2R_MAX_TARGETS || !check_lun(lun)) {
+ hi->status = ATTO_STS_INV_PARAM;
+ break;
+ }
+
+ esas2r_sgc_init(sgc, a, rq, NULL);
+
+ sgc->length = hi->data_length;
+ sgc->cur_offset += offsetof(struct atto_ioctl, data.byte)
+ + sizeof(struct atto_hba_scsi_pass_thru);
+
+ /* Finish request initialization */
+ rq->target_id = (u16)spt->target_id;
+ rq->vrq->scsi.flags |= cpu_to_le32(spt->lun[1]);
+ memcpy(rq->vrq->scsi.cdb, spt->cdb, 16);
+ rq->vrq->scsi.length = cpu_to_le32(hi->data_length);
+ rq->sense_len = spt->sense_length;
+ rq->sense_buf = (u8 *)spt->sense_data;
+ /* NOTE: we ignore spt->timeout */
+
+ /*
+ * always usurp the completion callback since the interrupt
+ * callback mechanism may be used.
+ */
+
+ rq->aux_req_cx = hi;
+ rq->aux_req_cb = rq->comp_cb;
+ rq->comp_cb = scsi_passthru_comp_cb;
+
+ if (spt->flags & ATTO_SPTF_DATA_IN) {
+ rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_RDD);
+ } else if (spt->flags & ATTO_SPTF_DATA_OUT) {
+ rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_WRD);
+ } else {
+ if (sgc->length) {
+ hi->status = ATTO_STS_INV_PARAM;
+ break;
+ }
+ }
+
+ if (spt->flags & ATTO_SPTF_ORDERED_Q)
+ rq->vrq->scsi.flags |=
+ cpu_to_le32(FCP_CMND_TA_ORDRD_Q);
+ else if (spt->flags & ATTO_SPTF_HEAD_OF_Q)
+ rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_TA_HEAD_Q);
+
+ if (!esas2r_build_sg_list(a, rq, sgc)) {
+ hi->status = ATTO_STS_OUT_OF_RSRC;
+ break;
+ }
+
+ esas2r_start_request(a, rq);
+
+ return true;
+ }
+
+ case ATTO_FUNC_GET_DEV_ADDR:
+ {
+ struct atto_hba_get_device_address *gda =
+ &hi->data.get_dev_addr;
+ struct esas2r_target *t;
+
+ if (hi->flags & HBAF_TUNNEL) {
+ if (hba_ioctl_tunnel(a, hi, rq, sgc))
+ return true;
+
+ break;
+ }
+
+ if (hi->version > ATTO_VER_GET_DEV_ADDR0) {
+ hi->status = ATTO_STS_INV_VERSION;
+ hi->version = ATTO_VER_GET_DEV_ADDR0;
+ break;
+ }
+
+ if (gda->target_id >= ESAS2R_MAX_TARGETS) {
+ hi->status = ATTO_STS_INV_PARAM;
+ break;
+ }
+
+ t = a->targetdb + (u16)gda->target_id;
+
+ if (t->target_state != TS_PRESENT) {
+ hi->status = ATTO_STS_FAILED;
+ } else if (gda->addr_type == ATTO_GDA_AT_PORT) {
+ if (t->sas_addr == 0) {
+ hi->status = ATTO_STS_UNSUPPORTED;
+ } else {
+ *(u64 *)gda->address = t->sas_addr;
+
+ gda->addr_len = sizeof(u64);
+ }
+ } else if (gda->addr_type == ATTO_GDA_AT_NODE) {
+ hi->status = ATTO_STS_NOT_APPL;
+ } else {
+ hi->status = ATTO_STS_INV_PARAM;
+ }
+
+ /* update the target ID to the next one present. */
+
+ gda->target_id =
+ esas2r_targ_db_find_next_present(a,
+ (u16)gda->target_id);
+ break;
+ }
+
+ case ATTO_FUNC_PHY_CTRL:
+ case ATTO_FUNC_CONN_CTRL:
+ {
+ if (hba_ioctl_tunnel(a, hi, rq, sgc))
+ return true;
+
+ break;
+ }
+
+ case ATTO_FUNC_ADAP_CTRL:
+ {
+ struct atto_hba_adap_ctrl *ac = &hi->data.adap_ctrl;
+
+ if (hi->flags & HBAF_TUNNEL) {
+ hi->status = ATTO_STS_UNSUPPORTED;
+ break;
+ }
+
+ if (hi->version > ATTO_VER_ADAP_CTRL0) {
+ hi->status = ATTO_STS_INV_VERSION;
+ hi->version = ATTO_VER_ADAP_CTRL0;
+ break;
+ }
+
+ if (ac->adap_func == ATTO_AC_AF_HARD_RST) {
+ esas2r_reset_adapter(a);
+ } else if (ac->adap_func != ATTO_AC_AF_GET_STATE) {
+ hi->status = ATTO_STS_UNSUPPORTED;
+ break;
+ }
+
+ if (a->flags & AF_CHPRST_NEEDED)
+ ac->adap_state = ATTO_AC_AS_RST_SCHED;
+ else if (a->flags & AF_CHPRST_PENDING)
+ ac->adap_state = ATTO_AC_AS_RST_IN_PROG;
+ else if (a->flags & AF_DISC_PENDING)
+ ac->adap_state = ATTO_AC_AS_RST_DISC;
+ else if (a->flags & AF_DISABLED)
+ ac->adap_state = ATTO_AC_AS_DISABLED;
+ else if (a->flags & AF_DEGRADED_MODE)
+ ac->adap_state = ATTO_AC_AS_DEGRADED;
+ else
+ ac->adap_state = ATTO_AC_AS_OK;
+
+ break;
+ }
+
+ case ATTO_FUNC_GET_DEV_INFO:
+ {
+ struct atto_hba_get_device_info *gdi = &hi->data.get_dev_info;
+ struct esas2r_target *t;
+
+ if (hi->flags & HBAF_TUNNEL) {
+ if (hba_ioctl_tunnel(a, hi, rq, sgc))
+ return true;
+
+ break;
+ }
+
+ if (hi->version > ATTO_VER_GET_DEV_INFO0) {
+ hi->status = ATTO_STS_INV_VERSION;
+ hi->version = ATTO_VER_GET_DEV_INFO0;
+ break;
+ }
+
+ if (gdi->target_id >= ESAS2R_MAX_TARGETS) {
+ hi->status = ATTO_STS_INV_PARAM;
+ break;
+ }
+
+ t = a->targetdb + (u16)gdi->target_id;
+
+ /* update the target ID to the next one present. */
+
+ gdi->target_id =
+ esas2r_targ_db_find_next_present(a,
+ (u16)gdi->target_id);
+
+ if (t->target_state != TS_PRESENT) {
+ hi->status = ATTO_STS_FAILED;
+ break;
+ }
+
+ hi->status = ATTO_STS_UNSUPPORTED;
+ break;
+ }
+
+ default:
+
+ hi->status = ATTO_STS_INV_FUNC;
+ break;
+ }
+
+ return false;
+}
+
+static void hba_ioctl_done_callback(struct esas2r_adapter *a,
+ struct esas2r_request *rq, void *context)
+{
+ struct atto_ioctl *ioctl_hba =
+ (struct atto_ioctl *)esas2r_buffered_ioctl;
+
+ esas2r_debug("hba_ioctl_done_callback %d", a->index);
+
+ if (ioctl_hba->function == ATTO_FUNC_GET_ADAP_INFO) {
+ struct atto_hba_get_adapter_info *gai =
+ &ioctl_hba->data.get_adap_info;
+
+ esas2r_debug("ATTO_FUNC_GET_ADAP_INFO");
+
+ gai->drvr_rev_major = ESAS2R_MAJOR_REV;
+ gai->drvr_rev_minor = ESAS2R_MINOR_REV;
+
+ strcpy(gai->drvr_rev_ascii, ESAS2R_VERSION_STR);
+ strcpy(gai->drvr_name, ESAS2R_DRVR_NAME);
+
+ gai->num_busses = 1;
+ gai->num_targsper_bus = ESAS2R_MAX_ID + 1;
+ gai->num_lunsper_targ = 1;
+ }
+}
+
+u8 handle_hba_ioctl(struct esas2r_adapter *a,
+ struct atto_ioctl *ioctl_hba)
+{
+ struct esas2r_buffered_ioctl bi;
+
+ memset(&bi, 0, sizeof(bi));
+
+ bi.a = a;
+ bi.ioctl = ioctl_hba;
+ bi.length = sizeof(struct atto_ioctl) + ioctl_hba->data_length;
+ bi.callback = hba_ioctl_callback;
+ bi.context = NULL;
+ bi.done_callback = hba_ioctl_done_callback;
+ bi.done_context = NULL;
+ bi.offset = 0;
+
+ return handle_buffered_ioctl(&bi);
+}
+
+
+int esas2r_write_params(struct esas2r_adapter *a, struct esas2r_request *rq,
+ struct esas2r_sas_nvram *data)
+{
+ int result = 0;
+
+ a->nvram_command_done = 0;
+ rq->comp_cb = complete_nvr_req;
+
+ if (esas2r_nvram_write(a, rq, data)) {
+ /* now wait around for it to complete. */
+ while (!a->nvram_command_done)
+ wait_event_interruptible(a->nvram_waiter,
+ a->nvram_command_done);
+ ;
+
+ /* done, check the status. */
+ if (rq->req_stat == RS_SUCCESS)
+ result = 1;
+ }
+ return result;
+}
+
+
+/* This function only cares about ATTO-specific ioctls (atto_express_ioctl) */
+int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg)
+{
+ struct atto_express_ioctl *ioctl = NULL;
+ struct esas2r_adapter *a;
+ struct esas2r_request *rq;
+ u16 code;
+ int err;
+
+ esas2r_log(ESAS2R_LOG_DEBG, "ioctl (%p, %x, %p)", hostdata, cmd, arg);
+
+ if ((arg == NULL)
+ || (cmd < EXPRESS_IOCTL_MIN)
+ || (cmd > EXPRESS_IOCTL_MAX))
+ return -ENOTSUPP;
+
+ if (!access_ok(VERIFY_WRITE, arg, sizeof(struct atto_express_ioctl))) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "ioctl_handler access_ok failed for cmd %d, "
+ "address %p", cmd,
+ arg);
+ return -EFAULT;
+ }
+
+ /* allocate a kernel memory buffer for the IOCTL data */
+ ioctl = kzalloc(sizeof(struct atto_express_ioctl), GFP_KERNEL);
+ if (ioctl == NULL) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "ioctl_handler kzalloc failed for %d bytes",
+ sizeof(struct atto_express_ioctl));
+ return -ENOMEM;
+ }
+
+ err = __copy_from_user(ioctl, arg, sizeof(struct atto_express_ioctl));
+ if (err != 0) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "copy_from_user didn't copy everything (err %d, cmd %d)",
+ err,
+ cmd);
+ kfree(ioctl);
+
+ return -EFAULT;
+ }
+
+ /* verify the signature */
+
+ if (memcmp(ioctl->header.signature,
+ EXPRESS_IOCTL_SIGNATURE,
+ EXPRESS_IOCTL_SIGNATURE_SIZE) != 0) {
+ esas2r_log(ESAS2R_LOG_WARN, "invalid signature");
+ kfree(ioctl);
+
+ return -ENOTSUPP;
+ }
+
+ /* assume success */
+
+ ioctl->header.return_code = IOCTL_SUCCESS;
+ err = 0;
+
+ /*
+ * handle EXPRESS_IOCTL_GET_CHANNELS
+ * without paying attention to channel
+ */
+
+ if (cmd == EXPRESS_IOCTL_GET_CHANNELS) {
+ int i = 0, k = 0;
+
+ ioctl->data.chanlist.num_channels = 0;
+
+ while (i < MAX_ADAPTERS) {
+ if (esas2r_adapters[i]) {
+ ioctl->data.chanlist.num_channels++;
+ ioctl->data.chanlist.channel[k] = i;
+ k++;
+ }
+ i++;
+ }
+
+ goto ioctl_done;
+ }
+
+ /* get the channel */
+
+ if (ioctl->header.channel == 0xFF) {
+ a = (struct esas2r_adapter *)hostdata;
+ } else {
+ a = esas2r_adapters[ioctl->header.channel];
+ if (ioctl->header.channel >= MAX_ADAPTERS || (a == NULL)) {
+ ioctl->header.return_code = IOCTL_BAD_CHANNEL;
+ esas2r_log(ESAS2R_LOG_WARN, "bad channel value");
+ kfree(ioctl);
+
+ return -ENOTSUPP;
+ }
+ }
+
+ switch (cmd) {
+ case EXPRESS_IOCTL_RW_FIRMWARE:
+
+ if (ioctl->data.fwrw.img_type == FW_IMG_FM_API) {
+ err = esas2r_write_fw(a,
+ (char *)ioctl->data.fwrw.image,
+ 0,
+ sizeof(struct
+ atto_express_ioctl));
+
+ if (err >= 0) {
+ err = esas2r_read_fw(a,
+ (char *)ioctl->data.fwrw.
+ image,
+ 0,
+ sizeof(struct
+ atto_express_ioctl));
+ }
+ } else if (ioctl->data.fwrw.img_type == FW_IMG_FS_API) {
+ err = esas2r_write_fs(a,
+ (char *)ioctl->data.fwrw.image,
+ 0,
+ sizeof(struct
+ atto_express_ioctl));
+
+ if (err >= 0) {
+ err = esas2r_read_fs(a,
+ (char *)ioctl->data.fwrw.
+ image,
+ 0,
+ sizeof(struct
+ atto_express_ioctl));
+ }
+ } else {
+ ioctl->header.return_code = IOCTL_BAD_FLASH_IMGTYPE;
+ }
+
+ break;
+
+ case EXPRESS_IOCTL_READ_PARAMS:
+
+ memcpy(ioctl->data.prw.data_buffer, a->nvram,
+ sizeof(struct esas2r_sas_nvram));
+ ioctl->data.prw.code = 1;
+ break;
+
+ case EXPRESS_IOCTL_WRITE_PARAMS:
+
+ rq = esas2r_alloc_request(a);
+ if (rq == NULL) {
+ up(&a->nvram_semaphore);
+ ioctl->data.prw.code = 0;
+ break;
+ }
+
+ code = esas2r_write_params(a, rq,
+ (struct esas2r_sas_nvram *)ioctl->data.prw.data_buffer);
+ ioctl->data.prw.code = code;
+
+ esas2r_free_request(a, rq);
+
+ break;
+
+ case EXPRESS_IOCTL_DEFAULT_PARAMS:
+
+ esas2r_nvram_get_defaults(a,
+ (struct esas2r_sas_nvram *)ioctl->data.prw.data_buffer);
+ ioctl->data.prw.code = 1;
+ break;
+
+ case EXPRESS_IOCTL_CHAN_INFO:
+
+ ioctl->data.chaninfo.major_rev = ESAS2R_MAJOR_REV;
+ ioctl->data.chaninfo.minor_rev = ESAS2R_MINOR_REV;
+ ioctl->data.chaninfo.IRQ = a->pcid->irq;
+ ioctl->data.chaninfo.device_id = a->pcid->device;
+ ioctl->data.chaninfo.vendor_id = a->pcid->vendor;
+ ioctl->data.chaninfo.ven_dev_id = a->pcid->subsystem_device;
+ ioctl->data.chaninfo.revision_id = a->pcid->revision;
+ ioctl->data.chaninfo.pci_bus = a->pcid->bus->number;
+ ioctl->data.chaninfo.pci_dev_func = a->pcid->devfn;
+ ioctl->data.chaninfo.core_rev = 0;
+ ioctl->data.chaninfo.host_no = a->host->host_no;
+ ioctl->data.chaninfo.hbaapi_rev = 0;
+ break;
+
+ case EXPRESS_IOCTL_SMP:
+ ioctl->header.return_code = handle_smp_ioctl(a,
+ &ioctl->data.
+ ioctl_smp);
+ break;
+
+ case EXPRESS_CSMI:
+ ioctl->header.return_code =
+ handle_csmi_ioctl(a, &ioctl->data.csmi);
+ break;
+
+ case EXPRESS_IOCTL_HBA:
+ ioctl->header.return_code = handle_hba_ioctl(a,
+ &ioctl->data.
+ ioctl_hba);
+ break;
+
+ case EXPRESS_IOCTL_VDA:
+ err = esas2r_write_vda(a,
+ (char *)&ioctl->data.ioctl_vda,
+ 0,
+ sizeof(struct atto_ioctl_vda) +
+ ioctl->data.ioctl_vda.data_length);
+
+ if (err >= 0) {
+ err = esas2r_read_vda(a,
+ (char *)&ioctl->data.ioctl_vda,
+ 0,
+ sizeof(struct atto_ioctl_vda) +
+ ioctl->data.ioctl_vda.data_length);
+ }
+
+
+
+
+ break;
+
+ case EXPRESS_IOCTL_GET_MOD_INFO:
+
+ ioctl->data.modinfo.adapter = a;
+ ioctl->data.modinfo.pci_dev = a->pcid;
+ ioctl->data.modinfo.scsi_host = a->host;
+ ioctl->data.modinfo.host_no = a->host->host_no;
+
+ break;
+
+ default:
+ esas2r_debug("esas2r_ioctl invalid cmd %p!", cmd);
+ ioctl->header.return_code = IOCTL_ERR_INVCMD;
+ }
+
+ioctl_done:
+
+ if (err < 0) {
+ esas2r_log(ESAS2R_LOG_WARN, "err %d on ioctl cmd %d", err,
+ cmd);
+
+ switch (err) {
+ case -ENOMEM:
+ case -EBUSY:
+ ioctl->header.return_code = IOCTL_OUT_OF_RESOURCES;
+ break;
+
+ case -ENOSYS:
+ case -EINVAL:
+ ioctl->header.return_code = IOCTL_INVALID_PARAM;
+ break;
+ }
+
+ ioctl->header.return_code = IOCTL_GENERAL_ERROR;
+ }
+
+ /* Always copy the buffer back, if only to pick up the status */
+ err = __copy_to_user(arg, ioctl, sizeof(struct atto_express_ioctl));
+ if (err != 0) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "ioctl_handler copy_to_user didn't copy "
+ "everything (err %d, cmd %d)", err,
+ cmd);
+ kfree(ioctl);
+
+ return -EFAULT;
+ }
+
+ kfree(ioctl);
+
+ return 0;
+}
+
+int esas2r_ioctl(struct scsi_device *sd, int cmd, void __user *arg)
+{
+ return esas2r_ioctl_handler(sd->host->hostdata, cmd, arg);
+}
+
+static void free_fw_buffers(struct esas2r_adapter *a)
+{
+ if (a->firmware.data) {
+ dma_free_coherent(&a->pcid->dev,
+ (size_t)a->firmware.orig_len,
+ a->firmware.data,
+ (dma_addr_t)a->firmware.phys);
+
+ a->firmware.data = NULL;
+ }
+}
+
+static int allocate_fw_buffers(struct esas2r_adapter *a, u32 length)
+{
+ free_fw_buffers(a);
+
+ a->firmware.orig_len = length;
+
+ a->firmware.data = (u8 *)dma_alloc_coherent(&a->pcid->dev,
+ (size_t)length,
+ (dma_addr_t *)&a->firmware.
+ phys,
+ GFP_KERNEL);
+
+ if (!a->firmware.data) {
+ esas2r_debug("buffer alloc failed!");
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Handle a call to read firmware. */
+int esas2r_read_fw(struct esas2r_adapter *a, char *buf, long off, int count)
+{
+ esas2r_trace_enter();
+ /* if the cached header is a status, simply copy it over and return. */
+ if (a->firmware.state == FW_STATUS_ST) {
+ int size = min_t(int, count, sizeof(a->firmware.header));
+ esas2r_trace_exit();
+ memcpy(buf, &a->firmware.header, size);
+ esas2r_debug("esas2r_read_fw: STATUS size %d", size);
+ return size;
+ }
+
+ /*
+ * if the cached header is a command, do it if at
+ * offset 0, otherwise copy the pieces.
+ */
+
+ if (a->firmware.state == FW_COMMAND_ST) {
+ u32 length = a->firmware.header.length;
+ esas2r_trace_exit();
+
+ esas2r_debug("esas2r_read_fw: COMMAND length %d off %d",
+ length,
+ off);
+
+ if (off == 0) {
+ if (a->firmware.header.action == FI_ACT_UP) {
+ if (!allocate_fw_buffers(a, length))
+ return -ENOMEM;
+
+
+ /* copy header over */
+
+ memcpy(a->firmware.data,
+ &a->firmware.header,
+ sizeof(a->firmware.header));
+
+ do_fm_api(a,
+ (struct esas2r_flash_img *)a->firmware.data);
+ } else if (a->firmware.header.action == FI_ACT_UPSZ) {
+ int size =
+ min((int)count,
+ (int)sizeof(a->firmware.header));
+ do_fm_api(a, &a->firmware.header);
+ memcpy(buf, &a->firmware.header, size);
+ esas2r_debug("FI_ACT_UPSZ size %d", size);
+ return size;
+ } else {
+ esas2r_debug("invalid action %d",
+ a->firmware.header.action);
+ return -ENOSYS;
+ }
+ }
+
+ if (count + off > length)
+ count = length - off;
+
+ if (count < 0)
+ return 0;
+
+ if (!a->firmware.data) {
+ esas2r_debug(
+ "read: nonzero offset but no buffer available!");
+ return -ENOMEM;
+ }
+
+ esas2r_debug("esas2r_read_fw: off %d count %d length %d ", off,
+ count,
+ length);
+
+ memcpy(buf, &a->firmware.data[off], count);
+
+ /* when done, release the buffer */
+
+ if (length <= off + count) {
+ esas2r_debug("esas2r_read_fw: freeing buffer!");
+
+ free_fw_buffers(a);
+ }
+
+ return count;
+ }
+
+ esas2r_trace_exit();
+ esas2r_debug("esas2r_read_fw: invalid firmware state %d",
+ a->firmware.state);
+
+ return -EINVAL;
+}
+
+/* Handle a call to write firmware. */
+int esas2r_write_fw(struct esas2r_adapter *a, const char *buf, long off,
+ int count)
+{
+ u32 length;
+
+ if (off == 0) {
+ struct esas2r_flash_img *header =
+ (struct esas2r_flash_img *)buf;
+
+ /* assume version 0 flash image */
+
+ int min_size = sizeof(struct esas2r_flash_img_v0);
+
+ a->firmware.state = FW_INVALID_ST;
+
+ /* validate the version field first */
+
+ if (count < 4
+ || header->fi_version > FI_VERSION_1) {
+ esas2r_debug(
+ "esas2r_write_fw: short header or invalid version");
+ return -EINVAL;
+ }
+
+ /* See if its a version 1 flash image */
+
+ if (header->fi_version == FI_VERSION_1)
+ min_size = sizeof(struct esas2r_flash_img);
+
+ /* If this is the start, the header must be full and valid. */
+ if (count < min_size) {
+ esas2r_debug("esas2r_write_fw: short header, aborting");
+ return -EINVAL;
+ }
+
+ /* Make sure the size is reasonable. */
+ length = header->length;
+
+ if (length > 1024 * 1024) {
+ esas2r_debug(
+ "esas2r_write_fw: hosed, length %d fi_version %d",
+ length, header->fi_version);
+ return -EINVAL;
+ }
+
+ /*
+ * If this is a write command, allocate memory because
+ * we have to cache everything. otherwise, just cache
+ * the header, because the read op will do the command.
+ */
+
+ if (header->action == FI_ACT_DOWN) {
+ if (!allocate_fw_buffers(a, length))
+ return -ENOMEM;
+
+ /*
+ * Store the command, so there is context on subsequent
+ * calls.
+ */
+ memcpy(&a->firmware.header,
+ buf,
+ sizeof(*header));
+ } else if (header->action == FI_ACT_UP
+ || header->action == FI_ACT_UPSZ) {
+ /* Save the command, result will be picked up on read */
+ memcpy(&a->firmware.header,
+ buf,
+ sizeof(*header));
+
+ a->firmware.state = FW_COMMAND_ST;
+
+ esas2r_debug(
+ "esas2r_write_fw: COMMAND, count %d, action %d ",
+ count, header->action);
+
+ /*
+ * Pretend we took the whole buffer,
+ * so we don't get bothered again.
+ */
+
+ return count;
+ } else {
+ esas2r_debug("esas2r_write_fw: invalid action %d ",
+ a->firmware.header.action);
+ return -ENOSYS;
+ }
+ } else {
+ length = a->firmware.header.length;
+ }
+
+ /*
+ * We only get here on a download command, regardless of offset.
+ * the chunks written by the system need to be cached, and when
+ * the final one arrives, issue the fmapi command.
+ */
+
+ if (off + count > length)
+ count = length - off;
+
+ if (count > 0) {
+ esas2r_debug("esas2r_write_fw: off %d count %d length %d", off,
+ count,
+ length);
+
+ /*
+ * On a full upload, the system tries sending the whole buffer.
+ * there's nothing to do with it, so just drop it here, before
+ * trying to copy over into unallocated memory!
+ */
+ if (a->firmware.header.action == FI_ACT_UP)
+ return count;
+
+ if (!a->firmware.data) {
+ esas2r_debug(
+ "write: nonzero offset but no buffer available!");
+ return -ENOMEM;
+ }
+
+ memcpy(&a->firmware.data[off], buf, count);
+
+ if (length == off + count) {
+ do_fm_api(a,
+ (struct esas2r_flash_img *)a->firmware.data);
+
+ /*
+ * Now copy the header result to be picked up by the
+ * next read
+ */
+ memcpy(&a->firmware.header,
+ a->firmware.data,
+ sizeof(a->firmware.header));
+
+ a->firmware.state = FW_STATUS_ST;
+
+ esas2r_debug("write completed");
+
+ /*
+ * Since the system has the data buffered, the only way
+ * this can leak is if a root user writes a program
+ * that writes a shorter buffer than it claims, and the
+ * copyin fails.
+ */
+ free_fw_buffers(a);
+ }
+ }
+
+ return count;
+}
+
+/* Callback for the completion of a VDA request. */
+static void vda_complete_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ a->vda_command_done = 1;
+ wake_up_interruptible(&a->vda_waiter);
+}
+
+/* Scatter/gather callback for VDA requests */
+static u32 get_physaddr_vda(struct esas2r_sg_context *sgc, u64 *addr)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)sgc->adapter;
+ int offset = (u8 *)sgc->cur_offset - (u8 *)a->vda_buffer;
+
+ (*addr) = a->ppvda_buffer + offset;
+ return VDA_MAX_BUFFER_SIZE - offset;
+}
+
+/* Handle a call to read a VDA command. */
+int esas2r_read_vda(struct esas2r_adapter *a, char *buf, long off, int count)
+{
+ if (!a->vda_buffer)
+ return -ENOMEM;
+
+ if (off == 0) {
+ struct esas2r_request *rq;
+ struct atto_ioctl_vda *vi =
+ (struct atto_ioctl_vda *)a->vda_buffer;
+ struct esas2r_sg_context sgc;
+ bool wait_for_completion;
+
+ /*
+ * Presumeably, someone has already written to the vda_buffer,
+ * and now they are reading the node the response, so now we
+ * will actually issue the request to the chip and reply.
+ */
+
+ /* allocate a request */
+ rq = esas2r_alloc_request(a);
+ if (rq == NULL) {
+ esas2r_debug("esas2r_read_vda: out of requestss");
+ return -EBUSY;
+ }
+
+ rq->comp_cb = vda_complete_req;
+
+ sgc.first_req = rq;
+ sgc.adapter = a;
+ sgc.cur_offset = a->vda_buffer + VDA_BUFFER_HEADER_SZ;
+ sgc.get_phys_addr = (PGETPHYSADDR)get_physaddr_vda;
+
+ a->vda_command_done = 0;
+
+ wait_for_completion =
+ esas2r_process_vda_ioctl(a, vi, rq, &sgc);
+
+ if (wait_for_completion) {
+ /* now wait around for it to complete. */
+
+ while (!a->vda_command_done)
+ wait_event_interruptible(a->vda_waiter,
+ a->vda_command_done);
+ }
+
+ esas2r_free_request(a, (struct esas2r_request *)rq);
+ }
+
+ if (off > VDA_MAX_BUFFER_SIZE)
+ return 0;
+
+ if (count + off > VDA_MAX_BUFFER_SIZE)
+ count = VDA_MAX_BUFFER_SIZE - off;
+
+ if (count < 0)
+ return 0;
+
+ memcpy(buf, a->vda_buffer + off, count);
+
+ return count;
+}
+
+/* Handle a call to write a VDA command. */
+int esas2r_write_vda(struct esas2r_adapter *a, const char *buf, long off,
+ int count)
+{
+ /*
+ * allocate memory for it, if not already done. once allocated,
+ * we will keep it around until the driver is unloaded.
+ */
+
+ if (!a->vda_buffer) {
+ dma_addr_t dma_addr;
+ a->vda_buffer = (u8 *)dma_alloc_coherent(&a->pcid->dev,
+ (size_t)
+ VDA_MAX_BUFFER_SIZE,
+ &dma_addr,
+ GFP_KERNEL);
+
+ a->ppvda_buffer = dma_addr;
+ }
+
+ if (!a->vda_buffer)
+ return -ENOMEM;
+
+ if (off > VDA_MAX_BUFFER_SIZE)
+ return 0;
+
+ if (count + off > VDA_MAX_BUFFER_SIZE)
+ count = VDA_MAX_BUFFER_SIZE - off;
+
+ if (count < 1)
+ return 0;
+
+ memcpy(a->vda_buffer + off, buf, count);
+
+ return count;
+}
+
+/* Callback for the completion of an FS_API request.*/
+static void fs_api_complete_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ a->fs_api_command_done = 1;
+
+ wake_up_interruptible(&a->fs_api_waiter);
+}
+
+/* Scatter/gather callback for VDA requests */
+static u32 get_physaddr_fs_api(struct esas2r_sg_context *sgc, u64 *addr)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)sgc->adapter;
+ struct esas2r_ioctl_fs *fs =
+ (struct esas2r_ioctl_fs *)a->fs_api_buffer;
+ u32 offset = (u8 *)sgc->cur_offset - (u8 *)fs;
+
+ (*addr) = a->ppfs_api_buffer + offset;
+
+ return a->fs_api_buffer_size - offset;
+}
+
+/* Handle a call to read firmware via FS_API. */
+int esas2r_read_fs(struct esas2r_adapter *a, char *buf, long off, int count)
+{
+ if (!a->fs_api_buffer)
+ return -ENOMEM;
+
+ if (off == 0) {
+ struct esas2r_request *rq;
+ struct esas2r_sg_context sgc;
+ struct esas2r_ioctl_fs *fs =
+ (struct esas2r_ioctl_fs *)a->fs_api_buffer;
+
+ /* If another flash request is already in progress, return. */
+ if (down_interruptible(&a->fs_api_semaphore)) {
+busy:
+ fs->status = ATTO_STS_OUT_OF_RSRC;
+ return -EBUSY;
+ }
+
+ /*
+ * Presumeably, someone has already written to the
+ * fs_api_buffer, and now they are reading the node the
+ * response, so now we will actually issue the request to the
+ * chip and reply. Allocate a request
+ */
+
+ rq = esas2r_alloc_request(a);
+ if (rq == NULL) {
+ esas2r_debug("esas2r_read_fs: out of requests");
+ up(&a->fs_api_semaphore);
+ goto busy;
+ }
+
+ rq->comp_cb = fs_api_complete_req;
+
+ /* Set up the SGCONTEXT for to build the s/g table */
+
+ sgc.cur_offset = fs->data;
+ sgc.get_phys_addr = (PGETPHYSADDR)get_physaddr_fs_api;
+
+ a->fs_api_command_done = 0;
+
+ if (!esas2r_process_fs_ioctl(a, fs, rq, &sgc)) {
+ if (fs->status == ATTO_STS_OUT_OF_RSRC)
+ count = -EBUSY;
+
+ goto dont_wait;
+ }
+
+ /* Now wait around for it to complete. */
+
+ while (!a->fs_api_command_done)
+ wait_event_interruptible(a->fs_api_waiter,
+ a->fs_api_command_done);
+ ;
+dont_wait:
+ /* Free the request and keep going */
+ up(&a->fs_api_semaphore);
+ esas2r_free_request(a, (struct esas2r_request *)rq);
+
+ /* Pick up possible error code from above */
+ if (count < 0)
+ return count;
+ }
+
+ if (off > a->fs_api_buffer_size)
+ return 0;
+
+ if (count + off > a->fs_api_buffer_size)
+ count = a->fs_api_buffer_size - off;
+
+ if (count < 0)
+ return 0;
+
+ memcpy(buf, a->fs_api_buffer + off, count);
+
+ return count;
+}
+
+/* Handle a call to write firmware via FS_API. */
+int esas2r_write_fs(struct esas2r_adapter *a, const char *buf, long off,
+ int count)
+{
+ if (off == 0) {
+ struct esas2r_ioctl_fs *fs = (struct esas2r_ioctl_fs *)buf;
+ u32 length = fs->command.length + offsetof(
+ struct esas2r_ioctl_fs,
+ data);
+
+ /*
+ * Special case, for BEGIN commands, the length field
+ * is lying to us, so just get enough for the header.
+ */
+
+ if (fs->command.command == ESAS2R_FS_CMD_BEGINW)
+ length = offsetof(struct esas2r_ioctl_fs, data);
+
+ /*
+ * Beginning a command. We assume we'll get at least
+ * enough in the first write so we can look at the
+ * header and see how much we need to alloc.
+ */
+
+ if (count < offsetof(struct esas2r_ioctl_fs, data))
+ return -EINVAL;
+
+ /* Allocate a buffer or use the existing buffer. */
+ if (a->fs_api_buffer) {
+ if (a->fs_api_buffer_size < length) {
+ /* Free too-small buffer and get a new one */
+ dma_free_coherent(&a->pcid->dev,
+ (size_t)a->fs_api_buffer_size,
+ a->fs_api_buffer,
+ (dma_addr_t)a->ppfs_api_buffer);
+
+ goto re_allocate_buffer;
+ }
+ } else {
+re_allocate_buffer:
+ a->fs_api_buffer_size = length;
+
+ a->fs_api_buffer = (u8 *)dma_alloc_coherent(
+ &a->pcid->dev,
+ (size_t)a->fs_api_buffer_size,
+ (dma_addr_t *)&a->ppfs_api_buffer,
+ GFP_KERNEL);
+ }
+ }
+
+ if (!a->fs_api_buffer)
+ return -ENOMEM;
+
+ if (off > a->fs_api_buffer_size)
+ return 0;
+
+ if (count + off > a->fs_api_buffer_size)
+ count = a->fs_api_buffer_size - off;
+
+ if (count < 1)
+ return 0;
+
+ memcpy(a->fs_api_buffer + off, buf, count);
+
+ return count;
+}
diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c
new file mode 100644
index 00000000000..9bf285df58d
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_log.c
@@ -0,0 +1,254 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r_log.c
+ * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+/*
+ * this module within the driver is tasked with providing logging functionality.
+ * the event_log_level module parameter controls the level of messages that are
+ * written to the system log. the default level of messages that are written
+ * are critical and warning messages. if other types of messages are desired,
+ * one simply needs to load the module with the correct value for the
+ * event_log_level module parameter. for example:
+ *
+ * insmod <module> event_log_level=1
+ *
+ * will load the module and only critical events will be written by this module
+ * to the system log. if critical, warning, and information-level messages are
+ * desired, the correct value for the event_log_level module parameter
+ * would be as follows:
+ *
+ * insmod <module> event_log_level=3
+ */
+
+#define EVENT_LOG_BUFF_SIZE 1024
+
+static long event_log_level = ESAS2R_LOG_DFLT;
+
+module_param(event_log_level, long, S_IRUGO | S_IRUSR);
+MODULE_PARM_DESC(event_log_level,
+ "Specifies the level of events to report to the system log. Critical and warning level events are logged by default.");
+
+/* A shared buffer to use for formatting messages. */
+static char event_buffer[EVENT_LOG_BUFF_SIZE];
+
+/* A lock to protect the shared buffer used for formatting messages. */
+static DEFINE_SPINLOCK(event_buffer_lock);
+
+/**
+ * translates an esas2r-defined logging event level to a kernel logging level.
+ *
+ * @param [in] level the esas2r-defined logging event level to translate
+ *
+ * @return the corresponding kernel logging level.
+ */
+static const char *translate_esas2r_event_level_to_kernel(const long level)
+{
+ switch (level) {
+ case ESAS2R_LOG_CRIT:
+ return KERN_CRIT;
+
+ case ESAS2R_LOG_WARN:
+ return KERN_WARNING;
+
+ case ESAS2R_LOG_INFO:
+ return KERN_INFO;
+
+ case ESAS2R_LOG_DEBG:
+ case ESAS2R_LOG_TRCE:
+ default:
+ return KERN_DEBUG;
+ }
+}
+
+/**
+ * the master logging function. this function will format the message as
+ * outlined by the formatting string, the input device information and the
+ * substitution arguments and output the resulting string to the system log.
+ *
+ * @param [in] level the event log level of the message
+ * @param [in] dev the device information
+ * @param [in] format the formatting string for the message
+ * @param [in] args the substition arguments to the formatting string
+ *
+ * @return 0 on success, or -1 if an error occurred.
+ */
+static int esas2r_log_master(const long level,
+ const struct device *dev,
+ const char *format,
+ va_list args)
+{
+ if (level <= event_log_level) {
+ unsigned long flags = 0;
+ int retval = 0;
+ char *buffer = event_buffer;
+ size_t buflen = EVENT_LOG_BUFF_SIZE;
+ const char *fmt_nodev = "%s%s: ";
+ const char *fmt_dev = "%s%s [%s, %s, %s]";
+ const char *slevel =
+ translate_esas2r_event_level_to_kernel(level);
+
+ spin_lock_irqsave(&event_buffer_lock, flags);
+
+ if (buffer == NULL) {
+ spin_unlock_irqrestore(&event_buffer_lock, flags);
+ return -1;
+ }
+
+ memset(buffer, 0, buflen);
+
+ /*
+ * format the level onto the beginning of the string and do
+ * some pointer arithmetic to move the pointer to the point
+ * where the actual message can be inserted.
+ */
+
+ if (dev == NULL) {
+ snprintf(buffer, buflen, fmt_nodev, slevel,
+ ESAS2R_DRVR_NAME);
+ } else {
+ snprintf(buffer, buflen, fmt_dev, slevel,
+ ESAS2R_DRVR_NAME,
+ (dev->driver ? dev->driver->name : "unknown"),
+ (dev->bus ? dev->bus->name : "unknown"),
+ dev_name(dev));
+ }
+
+ buffer += strlen(event_buffer);
+ buflen -= strlen(event_buffer);
+
+ retval = vsnprintf(buffer, buflen, format, args);
+ if (retval < 0) {
+ spin_unlock_irqrestore(&event_buffer_lock, flags);
+ return -1;
+ }
+
+ /*
+ * Put a line break at the end of the formatted string so that
+ * we don't wind up with run-on messages. only append if there
+ * is enough space in the buffer.
+ */
+ if (strlen(event_buffer) < buflen)
+ strcat(buffer, "\n");
+
+ printk(event_buffer);
+
+ spin_unlock_irqrestore(&event_buffer_lock, flags);
+ }
+
+ return 0;
+}
+
+/**
+ * formats and logs a message to the system log.
+ *
+ * @param [in] level the event level of the message
+ * @param [in] format the formating string for the message
+ * @param [in] ... the substitution arguments to the formatting string
+ *
+ * @return 0 on success, or -1 if an error occurred.
+ */
+int esas2r_log(const long level, const char *format, ...)
+{
+ int retval = 0;
+ va_list args;
+
+ va_start(args, format);
+
+ retval = esas2r_log_master(level, NULL, format, args);
+
+ va_end(args);
+
+ return retval;
+}
+
+/**
+ * formats and logs a message to the system log. this message will include
+ * device information.
+ *
+ * @param [in] level the event level of the message
+ * @param [in] dev the device information
+ * @param [in] format the formatting string for the message
+ * @param [in] ... the substitution arguments to the formatting string
+ *
+ * @return 0 on success, or -1 if an error occurred.
+ */
+int esas2r_log_dev(const long level,
+ const struct device *dev,
+ const char *format,
+ ...)
+{
+ int retval = 0;
+ va_list args;
+
+ va_start(args, format);
+
+ retval = esas2r_log_master(level, dev, format, args);
+
+ va_end(args);
+
+ return retval;
+}
+
+/**
+ * formats and logs a message to the system log. this message will include
+ * device information.
+ *
+ * @param [in] level the event level of the message
+ * @param [in] buf
+ * @param [in] len
+ *
+ * @return 0 on success, or -1 if an error occurred.
+ */
+int esas2r_log_hexdump(const long level,
+ const void *buf,
+ size_t len)
+{
+ if (level <= event_log_level) {
+ print_hex_dump(translate_esas2r_event_level_to_kernel(level),
+ "", DUMP_PREFIX_OFFSET, 16, 1, buf,
+ len, true);
+ }
+
+ return 1;
+}
diff --git a/drivers/scsi/esas2r/esas2r_log.h b/drivers/scsi/esas2r/esas2r_log.h
new file mode 100644
index 00000000000..7b6397bb5b9
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_log.h
@@ -0,0 +1,118 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r_log.h
+ * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#ifndef __esas2r_log_h__
+#define __esas2r_log_h__
+
+struct device;
+
+enum {
+ ESAS2R_LOG_NONE = 0, /* no events logged */
+ ESAS2R_LOG_CRIT = 1, /* critical events */
+ ESAS2R_LOG_WARN = 2, /* warning events */
+ ESAS2R_LOG_INFO = 3, /* info events */
+ ESAS2R_LOG_DEBG = 4, /* debugging events */
+ ESAS2R_LOG_TRCE = 5, /* tracing events */
+
+#ifdef ESAS2R_TRACE
+ ESAS2R_LOG_DFLT = ESAS2R_LOG_TRCE
+#else
+ ESAS2R_LOG_DFLT = ESAS2R_LOG_WARN
+#endif
+};
+
+int esas2r_log(const long level, const char *format, ...);
+int esas2r_log_dev(const long level,
+ const struct device *dev,
+ const char *format,
+ ...);
+int esas2r_log_hexdump(const long level,
+ const void *buf,
+ size_t len);
+
+/*
+ * the following macros are provided specifically for debugging and tracing
+ * messages. esas2r_debug() is provided for generic non-hardware layer
+ * debugging and tracing events. esas2r_hdebug is provided specifically for
+ * hardware layer debugging and tracing events.
+ */
+
+#ifdef ESAS2R_DEBUG
+#define esas2r_debug(f, args ...) esas2r_log(ESAS2R_LOG_DEBG, f, ## args)
+#define esas2r_hdebug(f, args ...) esas2r_log(ESAS2R_LOG_DEBG, f, ## args)
+#else
+#define esas2r_debug(f, args ...)
+#define esas2r_hdebug(f, args ...)
+#endif /* ESAS2R_DEBUG */
+
+/*
+ * the following macros are provided in order to trace the driver and catch
+ * some more serious bugs. be warned, enabling these macros may *severely*
+ * impact performance.
+ */
+
+#ifdef ESAS2R_TRACE
+#define esas2r_bugon() \
+ do { \
+ esas2r_log(ESAS2R_LOG_TRCE, "esas2r_bugon() called in %s:%d" \
+ " - dumping stack and stopping kernel", __func__, \
+ __LINE__); \
+ dump_stack(); \
+ BUG(); \
+ } while (0)
+
+#define esas2r_trace_enter() esas2r_log(ESAS2R_LOG_TRCE, "entered %s (%s:%d)", \
+ __func__, __FILE__, __LINE__)
+#define esas2r_trace_exit() esas2r_log(ESAS2R_LOG_TRCE, "exited %s (%s:%d)", \
+ __func__, __FILE__, __LINE__)
+#define esas2r_trace(f, args ...) esas2r_log(ESAS2R_LOG_TRCE, "(%s:%s:%d): " \
+ f, __func__, __FILE__, __LINE__, \
+ ## args)
+#else
+#define esas2r_bugon()
+#define esas2r_trace_enter()
+#define esas2r_trace_exit()
+#define esas2r_trace(f, args ...)
+#endif /* ESAS2R_TRACE */
+
+#endif /* __esas2r_log_h__ */
diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c
new file mode 100644
index 00000000000..4abf1272e1e
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_main.c
@@ -0,0 +1,2032 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r_main.c
+ * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+MODULE_DESCRIPTION(ESAS2R_DRVR_NAME ": " ESAS2R_LONGNAME " driver");
+MODULE_AUTHOR("ATTO Technology, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ESAS2R_VERSION_STR);
+
+/* global definitions */
+
+static int found_adapters;
+struct esas2r_adapter *esas2r_adapters[MAX_ADAPTERS];
+
+#define ESAS2R_VDA_EVENT_PORT1 54414
+#define ESAS2R_VDA_EVENT_PORT2 54415
+#define ESAS2R_VDA_EVENT_SOCK_COUNT 2
+
+static struct esas2r_adapter *esas2r_adapter_from_kobj(struct kobject *kobj)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct Scsi_Host *host = class_to_shost(dev);
+
+ return (struct esas2r_adapter *)host->hostdata;
+}
+
+static ssize_t read_fw(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+ return esas2r_read_fw(a, buf, off, count);
+}
+
+static ssize_t write_fw(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+ return esas2r_write_fw(a, buf, off, count);
+}
+
+static ssize_t read_fs(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+ return esas2r_read_fs(a, buf, off, count);
+}
+
+static ssize_t write_fs(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+ int length = min(sizeof(struct esas2r_ioctl_fs), count);
+ int result = 0;
+
+ result = esas2r_write_fs(a, buf, off, count);
+
+ if (result < 0)
+ result = 0;
+
+ return length;
+}
+
+static ssize_t read_vda(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+ return esas2r_read_vda(a, buf, off, count);
+}
+
+static ssize_t write_vda(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+ return esas2r_write_vda(a, buf, off, count);
+}
+
+static ssize_t read_live_nvram(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+ int length = min_t(size_t, sizeof(struct esas2r_sas_nvram), PAGE_SIZE);
+
+ memcpy(buf, a->nvram, length);
+ return length;
+}
+
+static ssize_t write_live_nvram(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+ struct esas2r_request *rq;
+ int result = -EFAULT;
+
+ rq = esas2r_alloc_request(a);
+ if (rq == NULL)
+ return -ENOMEM;
+
+ if (esas2r_write_params(a, rq, (struct esas2r_sas_nvram *)buf))
+ result = count;
+
+ esas2r_free_request(a, rq);
+
+ return result;
+}
+
+static ssize_t read_default_nvram(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+ esas2r_nvram_get_defaults(a, (struct esas2r_sas_nvram *)buf);
+
+ return sizeof(struct esas2r_sas_nvram);
+}
+
+static ssize_t read_hw(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+ int length = min_t(size_t, sizeof(struct atto_ioctl), PAGE_SIZE);
+
+ if (!a->local_atto_ioctl)
+ return -ENOMEM;
+
+ if (handle_hba_ioctl(a, a->local_atto_ioctl) != IOCTL_SUCCESS)
+ return -ENOMEM;
+
+ memcpy(buf, a->local_atto_ioctl, length);
+
+ return length;
+}
+
+static ssize_t write_hw(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+ int length = min(sizeof(struct atto_ioctl), count);
+
+ if (!a->local_atto_ioctl) {
+ a->local_atto_ioctl = kzalloc(sizeof(struct atto_ioctl),
+ GFP_KERNEL);
+ if (a->local_atto_ioctl == NULL) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "write_hw kzalloc failed for %d bytes",
+ sizeof(struct atto_ioctl));
+ return -ENOMEM;
+ }
+ }
+
+ memset(a->local_atto_ioctl, 0, sizeof(struct atto_ioctl));
+ memcpy(a->local_atto_ioctl, buf, length);
+
+ return length;
+}
+
+#define ESAS2R_RW_BIN_ATTR(_name) \
+ struct bin_attribute bin_attr_ ## _name = { \
+ .attr = \
+ { .name = __stringify(_name), .mode = S_IRUSR | S_IWUSR }, \
+ .size = 0, \
+ .read = read_ ## _name, \
+ .write = write_ ## _name }
+
+ESAS2R_RW_BIN_ATTR(fw);
+ESAS2R_RW_BIN_ATTR(fs);
+ESAS2R_RW_BIN_ATTR(vda);
+ESAS2R_RW_BIN_ATTR(hw);
+ESAS2R_RW_BIN_ATTR(live_nvram);
+
+struct bin_attribute bin_attr_default_nvram = {
+ .attr = { .name = "default_nvram", .mode = S_IRUGO },
+ .size = 0,
+ .read = read_default_nvram,
+ .write = NULL
+};
+
+static struct scsi_host_template driver_template = {
+ .module = THIS_MODULE,
+ .show_info = esas2r_show_info,
+ .name = ESAS2R_LONGNAME,
+ .release = esas2r_release,
+ .info = esas2r_info,
+ .ioctl = esas2r_ioctl,
+ .queuecommand = esas2r_queuecommand,
+ .eh_abort_handler = esas2r_eh_abort,
+ .eh_device_reset_handler = esas2r_device_reset,
+ .eh_bus_reset_handler = esas2r_bus_reset,
+ .eh_host_reset_handler = esas2r_host_reset,
+ .eh_target_reset_handler = esas2r_target_reset,
+ .can_queue = 128,
+ .this_id = -1,
+ .sg_tablesize = SCSI_MAX_SG_SEGMENTS,
+ .cmd_per_lun =
+ ESAS2R_DEFAULT_CMD_PER_LUN,
+ .present = 0,
+ .unchecked_isa_dma = 0,
+ .use_clustering = ENABLE_CLUSTERING,
+ .emulated = 0,
+ .proc_name = ESAS2R_DRVR_NAME,
+ .slave_configure = esas2r_slave_configure,
+ .slave_alloc = esas2r_slave_alloc,
+ .slave_destroy = esas2r_slave_destroy,
+ .change_queue_depth = esas2r_change_queue_depth,
+ .change_queue_type = esas2r_change_queue_type,
+ .max_sectors = 0xFFFF,
+};
+
+int sgl_page_size = 512;
+module_param(sgl_page_size, int, 0);
+MODULE_PARM_DESC(sgl_page_size,
+ "Scatter/gather list (SGL) page size in number of S/G "
+ "entries. If your application is doing a lot of very large "
+ "transfers, you may want to increase the SGL page size. "
+ "Default 512.");
+
+int num_sg_lists = 1024;
+module_param(num_sg_lists, int, 0);
+MODULE_PARM_DESC(num_sg_lists,
+ "Number of scatter/gather lists. Default 1024.");
+
+int sg_tablesize = SCSI_MAX_SG_SEGMENTS;
+module_param(sg_tablesize, int, 0);
+MODULE_PARM_DESC(sg_tablesize,
+ "Maximum number of entries in a scatter/gather table.");
+
+int num_requests = 256;
+module_param(num_requests, int, 0);
+MODULE_PARM_DESC(num_requests,
+ "Number of requests. Default 256.");
+
+int num_ae_requests = 4;
+module_param(num_ae_requests, int, 0);
+MODULE_PARM_DESC(num_ae_requests,
+ "Number of VDA asynchromous event requests. Default 4.");
+
+int cmd_per_lun = ESAS2R_DEFAULT_CMD_PER_LUN;
+module_param(cmd_per_lun, int, 0);
+MODULE_PARM_DESC(cmd_per_lun,
+ "Maximum number of commands per LUN. Default "
+ DEFINED_NUM_TO_STR(ESAS2R_DEFAULT_CMD_PER_LUN) ".");
+
+int can_queue = 128;
+module_param(can_queue, int, 0);
+MODULE_PARM_DESC(can_queue,
+ "Maximum number of commands per adapter. Default 128.");
+
+int esas2r_max_sectors = 0xFFFF;
+module_param(esas2r_max_sectors, int, 0);
+MODULE_PARM_DESC(esas2r_max_sectors,
+ "Maximum number of disk sectors in a single data transfer. "
+ "Default 65535 (largest possible setting).");
+
+int interrupt_mode = 1;
+module_param(interrupt_mode, int, 0);
+MODULE_PARM_DESC(interrupt_mode,
+ "Defines the interrupt mode to use. 0 for legacy"
+ ", 1 for MSI. Default is MSI (1).");
+
+static struct pci_device_id
+ esas2r_pci_table[] = {
+ { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x0049,
+ 0,
+ 0, 0 },
+ { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x004A,
+ 0,
+ 0, 0 },
+ { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x004B,
+ 0,
+ 0, 0 },
+ { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x004C,
+ 0,
+ 0, 0 },
+ { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x004D,
+ 0,
+ 0, 0 },
+ { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x004E,
+ 0,
+ 0, 0 },
+ { 0, 0, 0, 0,
+ 0,
+ 0, 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, esas2r_pci_table);
+
+static int
+esas2r_probe(struct pci_dev *pcid, const struct pci_device_id *id);
+
+static void
+esas2r_remove(struct pci_dev *pcid);
+
+static struct pci_driver
+ esas2r_pci_driver = {
+ .name = ESAS2R_DRVR_NAME,
+ .id_table = esas2r_pci_table,
+ .probe = esas2r_probe,
+ .remove = esas2r_remove,
+ .suspend = esas2r_suspend,
+ .resume = esas2r_resume,
+};
+
+static int esas2r_probe(struct pci_dev *pcid,
+ const struct pci_device_id *id)
+{
+ struct Scsi_Host *host = NULL;
+ struct esas2r_adapter *a;
+ int err;
+
+ size_t host_alloc_size = sizeof(struct esas2r_adapter)
+ + ((num_requests) +
+ 1) * sizeof(struct esas2r_request);
+
+ esas2r_log_dev(ESAS2R_LOG_DEBG, &(pcid->dev),
+ "esas2r_probe() 0x%02x 0x%02x 0x%02x 0x%02x",
+ pcid->vendor,
+ pcid->device,
+ pcid->subsystem_vendor,
+ pcid->subsystem_device);
+
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pcid->dev),
+ "before pci_enable_device() "
+ "enable_cnt: %d",
+ pcid->enable_cnt.counter);
+
+ err = pci_enable_device(pcid);
+ if (err != 0) {
+ esas2r_log_dev(ESAS2R_LOG_CRIT, &(pcid->dev),
+ "pci_enable_device() FAIL (%d)",
+ err);
+ return -ENODEV;
+ }
+
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pcid->dev),
+ "pci_enable_device() OK");
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pcid->dev),
+ "after pci_device_enable() enable_cnt: %d",
+ pcid->enable_cnt.counter);
+
+ host = scsi_host_alloc(&driver_template, host_alloc_size);
+ if (host == NULL) {
+ esas2r_log(ESAS2R_LOG_CRIT, "scsi_host_alloc() FAIL");
+ return -ENODEV;
+ }
+
+ memset(host->hostdata, 0, host_alloc_size);
+
+ a = (struct esas2r_adapter *)host->hostdata;
+
+ esas2r_log(ESAS2R_LOG_INFO, "scsi_host_alloc() OK host: %p", host);
+
+ /* override max LUN and max target id */
+
+ host->max_id = ESAS2R_MAX_ID + 1;
+ host->max_lun = 255;
+
+ /* we can handle 16-byte CDbs */
+
+ host->max_cmd_len = 16;
+
+ host->can_queue = can_queue;
+ host->cmd_per_lun = cmd_per_lun;
+ host->this_id = host->max_id + 1;
+ host->max_channel = 0;
+ host->unique_id = found_adapters;
+ host->sg_tablesize = sg_tablesize;
+ host->max_sectors = esas2r_max_sectors;
+
+ /* set to bus master for BIOses that don't do it for us */
+
+ esas2r_log(ESAS2R_LOG_INFO, "pci_set_master() called");
+
+ pci_set_master(pcid);
+
+ if (!esas2r_init_adapter(host, pcid, found_adapters)) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "unable to initialize device at PCI bus %x:%x",
+ pcid->bus->number,
+ pcid->devfn);
+
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(host->shost_gendev),
+ "scsi_host_put() called");
+
+ scsi_host_put(host);
+
+ return 0;
+
+ }
+
+ esas2r_log(ESAS2R_LOG_INFO, "pci_set_drvdata(%p, %p) called", pcid,
+ host->hostdata);
+
+ pci_set_drvdata(pcid, host);
+
+ esas2r_log(ESAS2R_LOG_INFO, "scsi_add_host() called");
+
+ err = scsi_add_host(host, &pcid->dev);
+
+ if (err) {
+ esas2r_log(ESAS2R_LOG_CRIT, "scsi_add_host returned %d", err);
+ esas2r_log_dev(ESAS2R_LOG_CRIT, &(host->shost_gendev),
+ "scsi_add_host() FAIL");
+
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(host->shost_gendev),
+ "scsi_host_put() called");
+
+ scsi_host_put(host);
+
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(host->shost_gendev),
+ "pci_set_drvdata(%p, NULL) called",
+ pcid);
+
+ pci_set_drvdata(pcid, NULL);
+
+ return -ENODEV;
+ }
+
+
+ esas2r_fw_event_on(a);
+
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(host->shost_gendev),
+ "scsi_scan_host() called");
+
+ scsi_scan_host(host);
+
+ /* Add sysfs binary files */
+ if (sysfs_create_bin_file(&host->shost_dev.kobj, &bin_attr_fw))
+ esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+ "Failed to create sysfs binary file: fw");
+ else
+ a->sysfs_fw_created = 1;
+
+ if (sysfs_create_bin_file(&host->shost_dev.kobj, &bin_attr_fs))
+ esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+ "Failed to create sysfs binary file: fs");
+ else
+ a->sysfs_fs_created = 1;
+
+ if (sysfs_create_bin_file(&host->shost_dev.kobj, &bin_attr_vda))
+ esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+ "Failed to create sysfs binary file: vda");
+ else
+ a->sysfs_vda_created = 1;
+
+ if (sysfs_create_bin_file(&host->shost_dev.kobj, &bin_attr_hw))
+ esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+ "Failed to create sysfs binary file: hw");
+ else
+ a->sysfs_hw_created = 1;
+
+ if (sysfs_create_bin_file(&host->shost_dev.kobj, &bin_attr_live_nvram))
+ esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+ "Failed to create sysfs binary file: live_nvram");
+ else
+ a->sysfs_live_nvram_created = 1;
+
+ if (sysfs_create_bin_file(&host->shost_dev.kobj,
+ &bin_attr_default_nvram))
+ esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+ "Failed to create sysfs binary file: default_nvram");
+ else
+ a->sysfs_default_nvram_created = 1;
+
+ found_adapters++;
+
+ return 0;
+}
+
+static void esas2r_remove(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host;
+ int index;
+
+ if (pdev == NULL) {
+ esas2r_log(ESAS2R_LOG_WARN, "esas2r_remove pdev==NULL");
+ return;
+ }
+
+ host = pci_get_drvdata(pdev);
+
+ if (host == NULL) {
+ /*
+ * this can happen if pci_set_drvdata was already called
+ * to clear the host pointer. if this is the case, we
+ * are okay; this channel has already been cleaned up.
+ */
+
+ return;
+ }
+
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+ "esas2r_remove(%p) called; "
+ "host:%p", pdev,
+ host);
+
+ index = esas2r_cleanup(host);
+
+ if (index < 0)
+ esas2r_log_dev(ESAS2R_LOG_WARN, &(pdev->dev),
+ "unknown host in %s",
+ __func__);
+
+ found_adapters--;
+
+ /* if this was the last adapter, clean up the rest of the driver */
+
+ if (found_adapters == 0)
+ esas2r_cleanup(NULL);
+}
+
+static int __init esas2r_init(void)
+{
+ int i;
+
+ esas2r_log(ESAS2R_LOG_INFO, "%s called", __func__);
+
+ /* verify valid parameters */
+
+ if (can_queue < 1) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "warning: can_queue must be at least 1, value "
+ "forced.");
+ can_queue = 1;
+ } else if (can_queue > 2048) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "warning: can_queue must be no larger than 2048, "
+ "value forced.");
+ can_queue = 2048;
+ }
+
+ if (cmd_per_lun < 1) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "warning: cmd_per_lun must be at least 1, value "
+ "forced.");
+ cmd_per_lun = 1;
+ } else if (cmd_per_lun > 2048) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "warning: cmd_per_lun must be no larger than "
+ "2048, value forced.");
+ cmd_per_lun = 2048;
+ }
+
+ if (sg_tablesize < 32) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "warning: sg_tablesize must be at least 32, "
+ "value forced.");
+ sg_tablesize = 32;
+ }
+
+ if (esas2r_max_sectors < 1) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "warning: esas2r_max_sectors must be at least "
+ "1, value forced.");
+ esas2r_max_sectors = 1;
+ } else if (esas2r_max_sectors > 0xffff) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "warning: esas2r_max_sectors must be no larger "
+ "than 0xffff, value forced.");
+ esas2r_max_sectors = 0xffff;
+ }
+
+ sgl_page_size &= ~(ESAS2R_SGL_ALIGN - 1);
+
+ if (sgl_page_size < SGL_PG_SZ_MIN)
+ sgl_page_size = SGL_PG_SZ_MIN;
+ else if (sgl_page_size > SGL_PG_SZ_MAX)
+ sgl_page_size = SGL_PG_SZ_MAX;
+
+ if (num_sg_lists < NUM_SGL_MIN)
+ num_sg_lists = NUM_SGL_MIN;
+ else if (num_sg_lists > NUM_SGL_MAX)
+ num_sg_lists = NUM_SGL_MAX;
+
+ if (num_requests < NUM_REQ_MIN)
+ num_requests = NUM_REQ_MIN;
+ else if (num_requests > NUM_REQ_MAX)
+ num_requests = NUM_REQ_MAX;
+
+ if (num_ae_requests < NUM_AE_MIN)
+ num_ae_requests = NUM_AE_MIN;
+ else if (num_ae_requests > NUM_AE_MAX)
+ num_ae_requests = NUM_AE_MAX;
+
+ /* set up other globals */
+
+ for (i = 0; i < MAX_ADAPTERS; i++)
+ esas2r_adapters[i] = NULL;
+
+ /* initialize */
+
+ driver_template.module = THIS_MODULE;
+
+ if (pci_register_driver(&esas2r_pci_driver) != 0)
+ esas2r_log(ESAS2R_LOG_CRIT, "pci_register_driver FAILED");
+ else
+ esas2r_log(ESAS2R_LOG_INFO, "pci_register_driver() OK");
+
+ if (!found_adapters) {
+ pci_unregister_driver(&esas2r_pci_driver);
+ esas2r_cleanup(NULL);
+
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "driver will not be loaded because no ATTO "
+ "%s devices were found",
+ ESAS2R_DRVR_NAME);
+ return -1;
+ } else {
+ esas2r_log(ESAS2R_LOG_INFO, "found %d adapters",
+ found_adapters);
+ }
+
+ return 0;
+}
+
+/* Handle ioctl calls to "/proc/scsi/esas2r/ATTOnode" */
+static const struct file_operations esas2r_proc_fops = {
+ .compat_ioctl = esas2r_proc_ioctl,
+ .unlocked_ioctl = esas2r_proc_ioctl,
+};
+
+static struct Scsi_Host *esas2r_proc_host;
+static int esas2r_proc_major;
+
+long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+ return esas2r_ioctl_handler(esas2r_proc_host->hostdata,
+ (int)cmd, (void __user *)arg);
+}
+
+static void __exit esas2r_exit(void)
+{
+ esas2r_log(ESAS2R_LOG_INFO, "%s called", __func__);
+
+ if (esas2r_proc_major > 0) {
+ esas2r_log(ESAS2R_LOG_INFO, "unregister proc");
+
+ remove_proc_entry(ATTONODE_NAME,
+ esas2r_proc_host->hostt->proc_dir);
+ unregister_chrdev(esas2r_proc_major, ESAS2R_DRVR_NAME);
+
+ esas2r_proc_major = 0;
+ }
+
+ esas2r_log(ESAS2R_LOG_INFO, "pci_unregister_driver() called");
+
+ pci_unregister_driver(&esas2r_pci_driver);
+}
+
+int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)sh->hostdata;
+
+ struct esas2r_target *t;
+ int dev_count = 0;
+
+ esas2r_log(ESAS2R_LOG_DEBG, "esas2r_show_info (%p,%d)", m, sh->host_no);
+
+ seq_printf(m, ESAS2R_LONGNAME "\n"
+ "Driver version: "ESAS2R_VERSION_STR "\n"
+ "Flash version: %s\n"
+ "Firmware version: %s\n"
+ "Copyright "ESAS2R_COPYRIGHT_YEARS "\n"
+ "http://www.attotech.com\n"
+ "\n",
+ a->flash_rev,
+ a->fw_rev[0] ? a->fw_rev : "(none)");
+
+
+ seq_printf(m, "Adapter information:\n"
+ "--------------------\n"
+ "Model: %s\n"
+ "SAS address: %02X%02X%02X%02X:%02X%02X%02X%02X\n",
+ esas2r_get_model_name(a),
+ a->nvram->sas_addr[0],
+ a->nvram->sas_addr[1],
+ a->nvram->sas_addr[2],
+ a->nvram->sas_addr[3],
+ a->nvram->sas_addr[4],
+ a->nvram->sas_addr[5],
+ a->nvram->sas_addr[6],
+ a->nvram->sas_addr[7]);
+
+ seq_puts(m, "\n"
+ "Discovered devices:\n"
+ "\n"
+ " # Target ID\n"
+ "---------------\n");
+
+ for (t = a->targetdb; t < a->targetdb_end; t++)
+ if (t->buffered_target_state == TS_PRESENT) {
+ seq_printf(m, " %3d %3d\n",
+ ++dev_count,
+ (u16)(uintptr_t)(t - a->targetdb));
+ }
+
+ if (dev_count == 0)
+ seq_puts(m, "none\n");
+
+ seq_puts(m, "\n");
+ return 0;
+
+}
+
+int esas2r_release(struct Scsi_Host *sh)
+{
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(sh->shost_gendev),
+ "esas2r_release() called");
+
+ esas2r_cleanup(sh);
+ if (sh->irq)
+ free_irq(sh->irq, NULL);
+ scsi_unregister(sh);
+ return 0;
+}
+
+const char *esas2r_info(struct Scsi_Host *sh)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)sh->hostdata;
+ static char esas2r_info_str[512];
+
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(sh->shost_gendev),
+ "esas2r_info() called");
+
+ /*
+ * if we haven't done so already, register as a char driver
+ * and stick a node under "/proc/scsi/esas2r/ATTOnode"
+ */
+
+ if (esas2r_proc_major <= 0) {
+ esas2r_proc_host = sh;
+
+ esas2r_proc_major = register_chrdev(0, ESAS2R_DRVR_NAME,
+ &esas2r_proc_fops);
+
+ esas2r_log_dev(ESAS2R_LOG_DEBG, &(sh->shost_gendev),
+ "register_chrdev (major %d)",
+ esas2r_proc_major);
+
+ if (esas2r_proc_major > 0) {
+ struct proc_dir_entry *pde;
+
+ pde = proc_create(ATTONODE_NAME, 0,
+ sh->hostt->proc_dir,
+ &esas2r_proc_fops);
+
+ if (!pde) {
+ esas2r_log_dev(ESAS2R_LOG_WARN,
+ &(sh->shost_gendev),
+ "failed to create_proc_entry");
+ esas2r_proc_major = -1;
+ }
+ }
+ }
+
+ sprintf(esas2r_info_str,
+ ESAS2R_LONGNAME " (bus 0x%02X, device 0x%02X, IRQ 0x%02X)"
+ " driver version: "ESAS2R_VERSION_STR " firmware version: "
+ "%s\n",
+ a->pcid->bus->number, a->pcid->devfn, a->pcid->irq,
+ a->fw_rev[0] ? a->fw_rev : "(none)");
+
+ return esas2r_info_str;
+}
+
+/* Callback for building a request scatter/gather list */
+static u32 get_physaddr_from_sgc(struct esas2r_sg_context *sgc, u64 *addr)
+{
+ u32 len;
+
+ if (likely(sgc->cur_offset == sgc->exp_offset)) {
+ /*
+ * the normal case: caller used all bytes from previous call, so
+ * expected offset is the same as the current offset.
+ */
+
+ if (sgc->sgel_count < sgc->num_sgel) {
+ /* retrieve next segment, except for first time */
+ if (sgc->exp_offset > (u8 *)0) {
+ /* advance current segment */
+ sgc->cur_sgel = sg_next(sgc->cur_sgel);
+ ++(sgc->sgel_count);
+ }
+
+
+ len = sg_dma_len(sgc->cur_sgel);
+ (*addr) = sg_dma_address(sgc->cur_sgel);
+
+ /* save the total # bytes returned to caller so far */
+ sgc->exp_offset += len;
+
+ } else {
+ len = 0;
+ }
+ } else if (sgc->cur_offset < sgc->exp_offset) {
+ /*
+ * caller did not use all bytes from previous call. need to
+ * compute the address based on current segment.
+ */
+
+ len = sg_dma_len(sgc->cur_sgel);
+ (*addr) = sg_dma_address(sgc->cur_sgel);
+
+ sgc->exp_offset -= len;
+
+ /* calculate PA based on prev segment address and offsets */
+ *addr = *addr +
+ (sgc->cur_offset - sgc->exp_offset);
+
+ sgc->exp_offset += len;
+
+ /* re-calculate length based on offset */
+ len = lower_32_bits(
+ sgc->exp_offset - sgc->cur_offset);
+ } else { /* if ( sgc->cur_offset > sgc->exp_offset ) */
+ /*
+ * we don't expect the caller to skip ahead.
+ * cur_offset will never exceed the len we return
+ */
+ len = 0;
+ }
+
+ return len;
+}
+
+int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+{
+ struct esas2r_adapter *a =
+ (struct esas2r_adapter *)cmd->device->host->hostdata;
+ struct esas2r_request *rq;
+ struct esas2r_sg_context sgc;
+ unsigned bufflen;
+
+ /* Assume success, if it fails we will fix the result later. */
+ cmd->result = DID_OK << 16;
+
+ if (unlikely(a->flags & AF_DEGRADED_MODE)) {
+ cmd->result = DID_NO_CONNECT << 16;
+ cmd->scsi_done(cmd);
+ return 0;
+ }
+
+ rq = esas2r_alloc_request(a);
+ if (unlikely(rq == NULL)) {
+ esas2r_debug("esas2r_alloc_request failed");
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ rq->cmd = cmd;
+ bufflen = scsi_bufflen(cmd);
+
+ if (likely(bufflen != 0)) {
+ if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_WRD);
+ else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_RDD);
+ }
+
+ memcpy(rq->vrq->scsi.cdb, cmd->cmnd, cmd->cmd_len);
+ rq->vrq->scsi.length = cpu_to_le32(bufflen);
+ rq->target_id = cmd->device->id;
+ rq->vrq->scsi.flags |= cpu_to_le32(cmd->device->lun);
+ rq->sense_buf = cmd->sense_buffer;
+ rq->sense_len = SCSI_SENSE_BUFFERSIZE;
+
+ esas2r_sgc_init(&sgc, a, rq, NULL);
+
+ sgc.length = bufflen;
+ sgc.cur_offset = NULL;
+
+ sgc.cur_sgel = scsi_sglist(cmd);
+ sgc.exp_offset = NULL;
+ sgc.num_sgel = scsi_dma_map(cmd);
+ sgc.sgel_count = 0;
+
+ if (unlikely(sgc.num_sgel < 0)) {
+ esas2r_free_request(a, rq);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ sgc.get_phys_addr = (PGETPHYSADDR)get_physaddr_from_sgc;
+
+ if (unlikely(!esas2r_build_sg_list(a, rq, &sgc))) {
+ scsi_dma_unmap(cmd);
+ esas2r_free_request(a, rq);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ esas2r_debug("start request %p to %d:%d\n", rq, (int)cmd->device->id,
+ (int)cmd->device->lun);
+
+ esas2r_start_request(a, rq);
+
+ return 0;
+}
+
+static void complete_task_management_request(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ (*rq->task_management_status_ptr) = rq->req_stat;
+ esas2r_free_request(a, rq);
+}
+
+/**
+ * Searches the specified queue for the specified queue for the command
+ * to abort.
+ *
+ * @param [in] a
+ * @param [in] abort_request
+ * @param [in] cmd
+ * t
+ * @return 0 on failure, 1 if command was not found, 2 if command was found
+ */
+static int esas2r_check_active_queue(struct esas2r_adapter *a,
+ struct esas2r_request **abort_request,
+ struct scsi_cmnd *cmd,
+ struct list_head *queue)
+{
+ bool found = false;
+ struct esas2r_request *ar = *abort_request;
+ struct esas2r_request *rq;
+ struct list_head *element, *next;
+
+ list_for_each_safe(element, next, queue) {
+
+ rq = list_entry(element, struct esas2r_request, req_list);
+
+ if (rq->cmd == cmd) {
+
+ /* Found the request. See what to do with it. */
+ if (queue == &a->active_list) {
+ /*
+ * We are searching the active queue, which
+ * means that we need to send an abort request
+ * to the firmware.
+ */
+ ar = esas2r_alloc_request(a);
+ if (ar == NULL) {
+ esas2r_log_dev(ESAS2R_LOG_WARN,
+ &(a->host->shost_gendev),
+ "unable to allocate an abort request for cmd %p",
+ cmd);
+ return 0; /* Failure */
+ }
+
+ /*
+ * Task management request must be formatted
+ * with a lock held.
+ */
+ ar->sense_len = 0;
+ ar->vrq->scsi.length = 0;
+ ar->target_id = rq->target_id;
+ ar->vrq->scsi.flags |= cpu_to_le32(
+ (u8)le32_to_cpu(rq->vrq->scsi.flags));
+
+ memset(ar->vrq->scsi.cdb, 0,
+ sizeof(ar->vrq->scsi.cdb));
+
+ ar->vrq->scsi.flags |= cpu_to_le32(
+ FCP_CMND_TRM);
+ ar->vrq->scsi.u.abort_handle =
+ rq->vrq->scsi.handle;
+ } else {
+ /*
+ * The request is pending but not active on
+ * the firmware. Just free it now and we'll
+ * report the successful abort below.
+ */
+ list_del_init(&rq->req_list);
+ esas2r_free_request(a, rq);
+ }
+
+ found = true;
+ break;
+ }
+
+ }
+
+ if (!found)
+ return 1; /* Not found */
+
+ return 2; /* found */
+
+
+}
+
+int esas2r_eh_abort(struct scsi_cmnd *cmd)
+{
+ struct esas2r_adapter *a =
+ (struct esas2r_adapter *)cmd->device->host->hostdata;
+ struct esas2r_request *abort_request = NULL;
+ unsigned long flags;
+ struct list_head *queue;
+ int result;
+
+ esas2r_log(ESAS2R_LOG_INFO, "eh_abort (%p)", cmd);
+
+ if (a->flags & AF_DEGRADED_MODE) {
+ cmd->result = DID_ABORT << 16;
+
+ scsi_set_resid(cmd, 0);
+
+ cmd->scsi_done(cmd);
+
+ return 0;
+ }
+
+ spin_lock_irqsave(&a->queue_lock, flags);
+
+ /*
+ * Run through the defer and active queues looking for the request
+ * to abort.
+ */
+
+ queue = &a->defer_list;
+
+check_active_queue:
+
+ result = esas2r_check_active_queue(a, &abort_request, cmd, queue);
+
+ if (!result) {
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+ return FAILED;
+ } else if (result == 2 && (queue == &a->defer_list)) {
+ queue = &a->active_list;
+ goto check_active_queue;
+ }
+
+ spin_unlock_irqrestore(&a->queue_lock, flags);
+
+ if (abort_request) {
+ u8 task_management_status = RS_PENDING;
+
+ /*
+ * the request is already active, so we need to tell
+ * the firmware to abort it and wait for the response.
+ */
+
+ abort_request->comp_cb = complete_task_management_request;
+ abort_request->task_management_status_ptr =
+ &task_management_status;
+
+ esas2r_start_request(a, abort_request);
+
+ if (atomic_read(&a->disable_cnt) == 0)
+ esas2r_do_deferred_processes(a);
+
+ while (task_management_status == RS_PENDING)
+ msleep(10);
+
+ /*
+ * Once we get here, the original request will have been
+ * completed by the firmware and the abort request will have
+ * been cleaned up. we're done!
+ */
+
+ return SUCCESS;
+ }
+
+ /*
+ * If we get here, either we found the inactive request and
+ * freed it, or we didn't find it at all. Either way, success!
+ */
+
+ cmd->result = DID_ABORT << 16;
+
+ scsi_set_resid(cmd, 0);
+
+ cmd->scsi_done(cmd);
+
+ return SUCCESS;
+}
+
+static int esas2r_host_bus_reset(struct scsi_cmnd *cmd, bool host_reset)
+{
+ struct esas2r_adapter *a =
+ (struct esas2r_adapter *)cmd->device->host->hostdata;
+
+ if (a->flags & AF_DEGRADED_MODE)
+ return FAILED;
+
+ if (host_reset)
+ esas2r_reset_adapter(a);
+ else
+ esas2r_reset_bus(a);
+
+ /* above call sets the AF_OS_RESET flag. wait for it to clear. */
+
+ while (a->flags & AF_OS_RESET) {
+ msleep(10);
+
+ if (a->flags & AF_DEGRADED_MODE)
+ return FAILED;
+ }
+
+ if (a->flags & AF_DEGRADED_MODE)
+ return FAILED;
+
+ return SUCCESS;
+}
+
+int esas2r_host_reset(struct scsi_cmnd *cmd)
+{
+ esas2r_log(ESAS2R_LOG_INFO, "host_reset (%p)", cmd);
+
+ return esas2r_host_bus_reset(cmd, true);
+}
+
+int esas2r_bus_reset(struct scsi_cmnd *cmd)
+{
+ esas2r_log(ESAS2R_LOG_INFO, "bus_reset (%p)", cmd);
+
+ return esas2r_host_bus_reset(cmd, false);
+}
+
+static int esas2r_dev_targ_reset(struct scsi_cmnd *cmd, bool target_reset)
+{
+ struct esas2r_adapter *a =
+ (struct esas2r_adapter *)cmd->device->host->hostdata;
+ struct esas2r_request *rq;
+ u8 task_management_status = RS_PENDING;
+ bool completed;
+
+ if (a->flags & AF_DEGRADED_MODE)
+ return FAILED;
+
+retry:
+ rq = esas2r_alloc_request(a);
+ if (rq == NULL) {
+ if (target_reset) {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "unable to allocate a request for a "
+ "target reset (%d)!",
+ cmd->device->id);
+ } else {
+ esas2r_log(ESAS2R_LOG_CRIT,
+ "unable to allocate a request for a "
+ "device reset (%d:%d)!",
+ cmd->device->id,
+ cmd->device->lun);
+ }
+
+
+ return FAILED;
+ }
+
+ rq->target_id = cmd->device->id;
+ rq->vrq->scsi.flags |= cpu_to_le32(cmd->device->lun);
+ rq->req_stat = RS_PENDING;
+
+ rq->comp_cb = complete_task_management_request;
+ rq->task_management_status_ptr = &task_management_status;
+
+ if (target_reset) {
+ esas2r_debug("issuing target reset (%p) to id %d", rq,
+ cmd->device->id);
+ completed = esas2r_send_task_mgmt(a, rq, 0x20);
+ } else {
+ esas2r_debug("issuing device reset (%p) to id %d lun %d", rq,
+ cmd->device->id, cmd->device->lun);
+ completed = esas2r_send_task_mgmt(a, rq, 0x10);
+ }
+
+ if (completed) {
+ /* Task management cmd completed right away, need to free it. */
+
+ esas2r_free_request(a, rq);
+ } else {
+ /*
+ * Wait for firmware to complete the request. Completion
+ * callback will free it.
+ */
+ while (task_management_status == RS_PENDING)
+ msleep(10);
+ }
+
+ if (a->flags & AF_DEGRADED_MODE)
+ return FAILED;
+
+ if (task_management_status == RS_BUSY) {
+ /*
+ * Busy, probably because we are flashing. Wait a bit and
+ * try again.
+ */
+ msleep(100);
+ goto retry;
+ }
+
+ return SUCCESS;
+}
+
+int esas2r_device_reset(struct scsi_cmnd *cmd)
+{
+ esas2r_log(ESAS2R_LOG_INFO, "device_reset (%p)", cmd);
+
+ return esas2r_dev_targ_reset(cmd, false);
+
+}
+
+int esas2r_target_reset(struct scsi_cmnd *cmd)
+{
+ esas2r_log(ESAS2R_LOG_INFO, "target_reset (%p)", cmd);
+
+ return esas2r_dev_targ_reset(cmd, true);
+}
+
+int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason)
+{
+ esas2r_log(ESAS2R_LOG_INFO, "change_queue_depth %p, %d", dev, depth);
+
+ scsi_adjust_queue_depth(dev, scsi_get_tag_type(dev), depth);
+
+ return dev->queue_depth;
+}
+
+int esas2r_change_queue_type(struct scsi_device *dev, int type)
+{
+ esas2r_log(ESAS2R_LOG_INFO, "change_queue_type %p, %d", dev, type);
+
+ if (dev->tagged_supported) {
+ scsi_set_tag_type(dev, type);
+
+ if (type)
+ scsi_activate_tcq(dev, dev->queue_depth);
+ else
+ scsi_deactivate_tcq(dev, dev->queue_depth);
+ } else {
+ type = 0;
+ }
+
+ return type;
+}
+
+int esas2r_slave_alloc(struct scsi_device *dev)
+{
+ return 0;
+}
+
+int esas2r_slave_configure(struct scsi_device *dev)
+{
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev),
+ "esas2r_slave_configure()");
+
+ if (dev->tagged_supported) {
+ scsi_set_tag_type(dev, MSG_SIMPLE_TAG);
+ scsi_activate_tcq(dev, cmd_per_lun);
+ } else {
+ scsi_set_tag_type(dev, 0);
+ scsi_deactivate_tcq(dev, cmd_per_lun);
+ }
+
+ return 0;
+}
+
+void esas2r_slave_destroy(struct scsi_device *dev)
+{
+ esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev),
+ "esas2r_slave_destroy()");
+}
+
+void esas2r_log_request_failure(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ u8 reqstatus = rq->req_stat;
+
+ if (reqstatus == RS_SUCCESS)
+ return;
+
+ if (rq->vrq->scsi.function == VDA_FUNC_SCSI) {
+ if (reqstatus == RS_SCSI_ERROR) {
+ if (rq->func_rsp.scsi_rsp.sense_len >= 13) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "request failure - SCSI error %x ASC:%x ASCQ:%x CDB:%x",
+ rq->sense_buf[2], rq->sense_buf[12],
+ rq->sense_buf[13],
+ rq->vrq->scsi.cdb[0]);
+ } else {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "request failure - SCSI error CDB:%x\n",
+ rq->vrq->scsi.cdb[0]);
+ }
+ } else if ((rq->vrq->scsi.cdb[0] != INQUIRY
+ && rq->vrq->scsi.cdb[0] != REPORT_LUNS)
+ || (reqstatus != RS_SEL
+ && reqstatus != RS_SEL2)) {
+ if ((reqstatus == RS_UNDERRUN) &&
+ (rq->vrq->scsi.cdb[0] == INQUIRY)) {
+ /* Don't log inquiry underruns */
+ } else {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "request failure - cdb:%x reqstatus:%d target:%d",
+ rq->vrq->scsi.cdb[0], reqstatus,
+ rq->target_id);
+ }
+ }
+ }
+}
+
+void esas2r_wait_request(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+ u32 starttime;
+ u32 timeout;
+
+ starttime = jiffies_to_msecs(jiffies);
+ timeout = rq->timeout ? rq->timeout : 5000;
+
+ while (true) {
+ esas2r_polled_interrupt(a);
+
+ if (rq->req_stat != RS_STARTED)
+ break;
+
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+ if ((jiffies_to_msecs(jiffies) - starttime) > timeout) {
+ esas2r_hdebug("request TMO");
+ esas2r_bugon();
+
+ rq->req_stat = RS_TIMEOUT;
+
+ esas2r_local_reset_adapter(a);
+ return;
+ }
+ }
+}
+
+u32 esas2r_map_data_window(struct esas2r_adapter *a, u32 addr_lo)
+{
+ u32 offset = addr_lo & (MW_DATA_WINDOW_SIZE - 1);
+ u32 base = addr_lo & -(signed int)MW_DATA_WINDOW_SIZE;
+
+ if (a->window_base != base) {
+ esas2r_write_register_dword(a, MVR_PCI_WIN1_REMAP,
+ base | MVRPW1R_ENABLE);
+ esas2r_flush_register_dword(a, MVR_PCI_WIN1_REMAP);
+ a->window_base = base;
+ }
+
+ return offset;
+}
+
+/* Read a block of data from chip memory */
+bool esas2r_read_mem_block(struct esas2r_adapter *a,
+ void *to,
+ u32 from,
+ u32 size)
+{
+ u8 *end = (u8 *)to;
+
+ while (size) {
+ u32 len;
+ u32 offset;
+ u32 iatvr;
+
+ iatvr = (from & -(signed int)MW_DATA_WINDOW_SIZE);
+
+ esas2r_map_data_window(a, iatvr);
+
+ offset = from & (MW_DATA_WINDOW_SIZE - 1);
+ len = size;
+
+ if (len > MW_DATA_WINDOW_SIZE - offset)
+ len = MW_DATA_WINDOW_SIZE - offset;
+
+ from += len;
+ size -= len;
+
+ while (len--) {
+ *end++ = esas2r_read_data_byte(a, offset);
+ offset++;
+ }
+ }
+
+ return true;
+}
+
+void esas2r_nuxi_mgt_data(u8 function, void *data)
+{
+ struct atto_vda_grp_info *g;
+ struct atto_vda_devinfo *d;
+ struct atto_vdapart_info *p;
+ struct atto_vda_dh_info *h;
+ struct atto_vda_metrics_info *m;
+ struct atto_vda_schedule_info *s;
+ struct atto_vda_buzzer_info *b;
+ u8 i;
+
+ switch (function) {
+ case VDAMGT_BUZZER_INFO:
+ case VDAMGT_BUZZER_SET:
+
+ b = (struct atto_vda_buzzer_info *)data;
+
+ b->duration = le32_to_cpu(b->duration);
+ break;
+
+ case VDAMGT_SCHEDULE_INFO:
+ case VDAMGT_SCHEDULE_EVENT:
+
+ s = (struct atto_vda_schedule_info *)data;
+
+ s->id = le32_to_cpu(s->id);
+
+ break;
+
+ case VDAMGT_DEV_INFO:
+ case VDAMGT_DEV_CLEAN:
+ case VDAMGT_DEV_PT_INFO:
+ case VDAMGT_DEV_FEATURES:
+ case VDAMGT_DEV_PT_FEATURES:
+ case VDAMGT_DEV_OPERATION:
+
+ d = (struct atto_vda_devinfo *)data;
+
+ d->capacity = le64_to_cpu(d->capacity);
+ d->block_size = le32_to_cpu(d->block_size);
+ d->ses_dev_index = le16_to_cpu(d->ses_dev_index);
+ d->target_id = le16_to_cpu(d->target_id);
+ d->lun = le16_to_cpu(d->lun);
+ d->features = le16_to_cpu(d->features);
+ break;
+
+ case VDAMGT_GRP_INFO:
+ case VDAMGT_GRP_CREATE:
+ case VDAMGT_GRP_DELETE:
+ case VDAMGT_ADD_STORAGE:
+ case VDAMGT_MEMBER_ADD:
+ case VDAMGT_GRP_COMMIT:
+ case VDAMGT_GRP_REBUILD:
+ case VDAMGT_GRP_COMMIT_INIT:
+ case VDAMGT_QUICK_RAID:
+ case VDAMGT_GRP_FEATURES:
+ case VDAMGT_GRP_COMMIT_INIT_AUTOMAP:
+ case VDAMGT_QUICK_RAID_INIT_AUTOMAP:
+ case VDAMGT_SPARE_LIST:
+ case VDAMGT_SPARE_ADD:
+ case VDAMGT_SPARE_REMOVE:
+ case VDAMGT_LOCAL_SPARE_ADD:
+ case VDAMGT_GRP_OPERATION:
+
+ g = (struct atto_vda_grp_info *)data;
+
+ g->capacity = le64_to_cpu(g->capacity);
+ g->block_size = le32_to_cpu(g->block_size);
+ g->interleave = le32_to_cpu(g->interleave);
+ g->features = le16_to_cpu(g->features);
+
+ for (i = 0; i < 32; i++)
+ g->members[i] = le16_to_cpu(g->members[i]);
+
+ break;
+
+ case VDAMGT_PART_INFO:
+ case VDAMGT_PART_MAP:
+ case VDAMGT_PART_UNMAP:
+ case VDAMGT_PART_AUTOMAP:
+ case VDAMGT_PART_SPLIT:
+ case VDAMGT_PART_MERGE:
+
+ p = (struct atto_vdapart_info *)data;
+
+ p->part_size = le64_to_cpu(p->part_size);
+ p->start_lba = le32_to_cpu(p->start_lba);
+ p->block_size = le32_to_cpu(p->block_size);
+ p->target_id = le16_to_cpu(p->target_id);
+ break;
+
+ case VDAMGT_DEV_HEALTH_REQ:
+
+ h = (struct atto_vda_dh_info *)data;
+
+ h->med_defect_cnt = le32_to_cpu(h->med_defect_cnt);
+ h->info_exc_cnt = le32_to_cpu(h->info_exc_cnt);
+ break;
+
+ case VDAMGT_DEV_METRICS:
+
+ m = (struct atto_vda_metrics_info *)data;
+
+ for (i = 0; i < 32; i++)
+ m->dev_indexes[i] = le16_to_cpu(m->dev_indexes[i]);
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+void esas2r_nuxi_cfg_data(u8 function, void *data)
+{
+ struct atto_vda_cfg_init *ci;
+
+ switch (function) {
+ case VDA_CFG_INIT:
+ case VDA_CFG_GET_INIT:
+ case VDA_CFG_GET_INIT2:
+
+ ci = (struct atto_vda_cfg_init *)data;
+
+ ci->date_time.year = le16_to_cpu(ci->date_time.year);
+ ci->sgl_page_size = le32_to_cpu(ci->sgl_page_size);
+ ci->vda_version = le32_to_cpu(ci->vda_version);
+ ci->epoch_time = le32_to_cpu(ci->epoch_time);
+ ci->ioctl_tunnel = le32_to_cpu(ci->ioctl_tunnel);
+ ci->num_targets_backend = le32_to_cpu(ci->num_targets_backend);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void esas2r_nuxi_ae_data(union atto_vda_ae *ae)
+{
+ struct atto_vda_ae_raid *r = &ae->raid;
+ struct atto_vda_ae_lu *l = &ae->lu;
+
+ switch (ae->hdr.bytype) {
+ case VDAAE_HDR_TYPE_RAID:
+
+ r->dwflags = le32_to_cpu(r->dwflags);
+ break;
+
+ case VDAAE_HDR_TYPE_LU:
+
+ l->dwevent = le32_to_cpu(l->dwevent);
+ l->wphys_target_id = le16_to_cpu(l->wphys_target_id);
+ l->id.tgtlun.wtarget_id = le16_to_cpu(l->id.tgtlun.wtarget_id);
+
+ if (l->hdr.bylength >= offsetof(struct atto_vda_ae_lu, id)
+ + sizeof(struct atto_vda_ae_lu_tgt_lun_raid)) {
+ l->id.tgtlun_raid.dwinterleave
+ = le32_to_cpu(l->id.tgtlun_raid.dwinterleave);
+ l->id.tgtlun_raid.dwblock_size
+ = le32_to_cpu(l->id.tgtlun_raid.dwblock_size);
+ }
+
+ break;
+
+ case VDAAE_HDR_TYPE_DISK:
+ default:
+ break;
+ }
+}
+
+void esas2r_free_request(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+ unsigned long flags;
+
+ esas2r_rq_destroy_request(rq, a);
+ spin_lock_irqsave(&a->request_lock, flags);
+ list_add(&rq->comp_list, &a->avail_request);
+ spin_unlock_irqrestore(&a->request_lock, flags);
+}
+
+struct esas2r_request *esas2r_alloc_request(struct esas2r_adapter *a)
+{
+ struct esas2r_request *rq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&a->request_lock, flags);
+
+ if (unlikely(list_empty(&a->avail_request))) {
+ spin_unlock_irqrestore(&a->request_lock, flags);
+ return NULL;
+ }
+
+ rq = list_first_entry(&a->avail_request, struct esas2r_request,
+ comp_list);
+ list_del(&rq->comp_list);
+ spin_unlock_irqrestore(&a->request_lock, flags);
+ esas2r_rq_init_request(rq, a);
+
+ return rq;
+
+}
+
+void esas2r_complete_request_cb(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ esas2r_debug("completing request %p\n", rq);
+
+ scsi_dma_unmap(rq->cmd);
+
+ if (unlikely(rq->req_stat != RS_SUCCESS)) {
+ esas2r_debug("[%x STATUS %x:%x (%x)]", rq->target_id,
+ rq->req_stat,
+ rq->func_rsp.scsi_rsp.scsi_stat,
+ rq->cmd);
+
+ rq->cmd->result =
+ ((esas2r_req_status_to_error(rq->req_stat) << 16)
+ | (rq->func_rsp.scsi_rsp.scsi_stat & STATUS_MASK));
+
+ if (rq->req_stat == RS_UNDERRUN)
+ scsi_set_resid(rq->cmd,
+ le32_to_cpu(rq->func_rsp.scsi_rsp.
+ residual_length));
+ else
+ scsi_set_resid(rq->cmd, 0);
+ }
+
+ rq->cmd->scsi_done(rq->cmd);
+
+ esas2r_free_request(a, rq);
+}
+
+/* Run tasklet to handle stuff outside of interrupt context. */
+void esas2r_adapter_tasklet(unsigned long context)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)context;
+
+ if (unlikely(a->flags2 & AF2_TIMER_TICK)) {
+ esas2r_lock_clear_flags(&a->flags2, AF2_TIMER_TICK);
+ esas2r_timer_tick(a);
+ }
+
+ if (likely(a->flags2 & AF2_INT_PENDING)) {
+ esas2r_lock_clear_flags(&a->flags2, AF2_INT_PENDING);
+ esas2r_adapter_interrupt(a);
+ }
+
+ if (esas2r_is_tasklet_pending(a))
+ esas2r_do_tasklet_tasks(a);
+
+ if (esas2r_is_tasklet_pending(a)
+ || (a->flags2 & AF2_INT_PENDING)
+ || (a->flags2 & AF2_TIMER_TICK)) {
+ esas2r_lock_clear_flags(&a->flags, AF_TASKLET_SCHEDULED);
+ esas2r_schedule_tasklet(a);
+ } else {
+ esas2r_lock_clear_flags(&a->flags, AF_TASKLET_SCHEDULED);
+ }
+}
+
+static void esas2r_timer_callback(unsigned long context);
+
+void esas2r_kickoff_timer(struct esas2r_adapter *a)
+{
+ init_timer(&a->timer);
+
+ a->timer.function = esas2r_timer_callback;
+ a->timer.data = (unsigned long)a;
+ a->timer.expires = jiffies +
+ msecs_to_jiffies(100);
+
+ add_timer(&a->timer);
+}
+
+static void esas2r_timer_callback(unsigned long context)
+{
+ struct esas2r_adapter *a = (struct esas2r_adapter *)context;
+
+ esas2r_lock_set_flags(&a->flags2, AF2_TIMER_TICK);
+
+ esas2r_schedule_tasklet(a);
+
+ esas2r_kickoff_timer(a);
+}
+
+/*
+ * Firmware events need to be handled outside of interrupt context
+ * so we schedule a delayed_work to handle them.
+ */
+
+static void
+esas2r_free_fw_event(struct esas2r_fw_event_work *fw_event)
+{
+ unsigned long flags;
+ struct esas2r_adapter *a = fw_event->a;
+
+ spin_lock_irqsave(&a->fw_event_lock, flags);
+ list_del(&fw_event->list);
+ kfree(fw_event);
+ spin_unlock_irqrestore(&a->fw_event_lock, flags);
+}
+
+void
+esas2r_fw_event_off(struct esas2r_adapter *a)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&a->fw_event_lock, flags);
+ a->fw_events_off = 1;
+ spin_unlock_irqrestore(&a->fw_event_lock, flags);
+}
+
+void
+esas2r_fw_event_on(struct esas2r_adapter *a)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&a->fw_event_lock, flags);
+ a->fw_events_off = 0;
+ spin_unlock_irqrestore(&a->fw_event_lock, flags);
+}
+
+static void esas2r_add_device(struct esas2r_adapter *a, u16 target_id)
+{
+ int ret;
+ struct scsi_device *scsi_dev;
+
+ scsi_dev = scsi_device_lookup(a->host, 0, target_id, 0);
+
+ if (scsi_dev) {
+ esas2r_log_dev(
+ ESAS2R_LOG_WARN,
+ &(scsi_dev->
+ sdev_gendev),
+ "scsi device already exists at id %d", target_id);
+
+ scsi_device_put(scsi_dev);
+ } else {
+ esas2r_log_dev(
+ ESAS2R_LOG_INFO,
+ &(a->host->
+ shost_gendev),
+ "scsi_add_device() called for 0:%d:0",
+ target_id);
+
+ ret = scsi_add_device(a->host, 0, target_id, 0);
+ if (ret) {
+ esas2r_log_dev(
+ ESAS2R_LOG_CRIT,
+ &(a->host->
+ shost_gendev),
+ "scsi_add_device failed with %d for id %d",
+ ret, target_id);
+ }
+ }
+}
+
+static void esas2r_remove_device(struct esas2r_adapter *a, u16 target_id)
+{
+ struct scsi_device *scsi_dev;
+
+ scsi_dev = scsi_device_lookup(a->host, 0, target_id, 0);
+
+ if (scsi_dev) {
+ scsi_device_set_state(scsi_dev, SDEV_OFFLINE);
+
+ esas2r_log_dev(
+ ESAS2R_LOG_INFO,
+ &(scsi_dev->
+ sdev_gendev),
+ "scsi_remove_device() called for 0:%d:0",
+ target_id);
+
+ scsi_remove_device(scsi_dev);
+
+ esas2r_log_dev(
+ ESAS2R_LOG_INFO,
+ &(scsi_dev->
+ sdev_gendev),
+ "scsi_device_put() called");
+
+ scsi_device_put(scsi_dev);
+ } else {
+ esas2r_log_dev(
+ ESAS2R_LOG_WARN,
+ &(a->host->shost_gendev),
+ "no target found at id %d",
+ target_id);
+ }
+}
+
+/*
+ * Sends a firmware asynchronous event to anyone who happens to be
+ * listening on the defined ATTO VDA event ports.
+ */
+static void esas2r_send_ae_event(struct esas2r_fw_event_work *fw_event)
+{
+ struct esas2r_vda_ae *ae = (struct esas2r_vda_ae *)fw_event->data;
+ char *type;
+
+ switch (ae->vda_ae.hdr.bytype) {
+ case VDAAE_HDR_TYPE_RAID:
+ type = "RAID group state change";
+ break;
+
+ case VDAAE_HDR_TYPE_LU:
+ type = "Mapped destination LU change";
+ break;
+
+ case VDAAE_HDR_TYPE_DISK:
+ type = "Physical disk inventory change";
+ break;
+
+ case VDAAE_HDR_TYPE_RESET:
+ type = "Firmware reset";
+ break;
+
+ case VDAAE_HDR_TYPE_LOG_INFO:
+ type = "Event Log message (INFO level)";
+ break;
+
+ case VDAAE_HDR_TYPE_LOG_WARN:
+ type = "Event Log message (WARN level)";
+ break;
+
+ case VDAAE_HDR_TYPE_LOG_CRIT:
+ type = "Event Log message (CRIT level)";
+ break;
+
+ case VDAAE_HDR_TYPE_LOG_FAIL:
+ type = "Event Log message (FAIL level)";
+ break;
+
+ case VDAAE_HDR_TYPE_NVC:
+ type = "NVCache change";
+ break;
+
+ case VDAAE_HDR_TYPE_TLG_INFO:
+ type = "Time stamped log message (INFO level)";
+ break;
+
+ case VDAAE_HDR_TYPE_TLG_WARN:
+ type = "Time stamped log message (WARN level)";
+ break;
+
+ case VDAAE_HDR_TYPE_TLG_CRIT:
+ type = "Time stamped log message (CRIT level)";
+ break;
+
+ case VDAAE_HDR_TYPE_PWRMGT:
+ type = "Power management";
+ break;
+
+ case VDAAE_HDR_TYPE_MUTE:
+ type = "Mute button pressed";
+ break;
+
+ case VDAAE_HDR_TYPE_DEV:
+ type = "Device attribute change";
+ break;
+
+ default:
+ type = "Unknown";
+ break;
+ }
+
+ esas2r_log(ESAS2R_LOG_WARN,
+ "An async event of type \"%s\" was received from the firmware. The event contents are:",
+ type);
+ esas2r_log_hexdump(ESAS2R_LOG_WARN, &ae->vda_ae,
+ ae->vda_ae.hdr.bylength);
+
+}
+
+static void
+esas2r_firmware_event_work(struct work_struct *work)
+{
+ struct esas2r_fw_event_work *fw_event =
+ container_of(work, struct esas2r_fw_event_work, work.work);
+
+ struct esas2r_adapter *a = fw_event->a;
+
+ u16 target_id = *(u16 *)&fw_event->data[0];
+
+ if (a->fw_events_off)
+ goto done;
+
+ switch (fw_event->type) {
+ case fw_event_null:
+ break; /* do nothing */
+
+ case fw_event_lun_change:
+ esas2r_remove_device(a, target_id);
+ esas2r_add_device(a, target_id);
+ break;
+
+ case fw_event_present:
+ esas2r_add_device(a, target_id);
+ break;
+
+ case fw_event_not_present:
+ esas2r_remove_device(a, target_id);
+ break;
+
+ case fw_event_vda_ae:
+ esas2r_send_ae_event(fw_event);
+ break;
+ }
+
+done:
+ esas2r_free_fw_event(fw_event);
+}
+
+void esas2r_queue_fw_event(struct esas2r_adapter *a,
+ enum fw_event_type type,
+ void *data,
+ int data_sz)
+{
+ struct esas2r_fw_event_work *fw_event;
+ unsigned long flags;
+
+ fw_event = kzalloc(sizeof(struct esas2r_fw_event_work), GFP_ATOMIC);
+ if (!fw_event) {
+ esas2r_log(ESAS2R_LOG_WARN,
+ "esas2r_queue_fw_event failed to alloc");
+ return;
+ }
+
+ if (type == fw_event_vda_ae) {
+ struct esas2r_vda_ae *ae =
+ (struct esas2r_vda_ae *)fw_event->data;
+
+ ae->signature = ESAS2R_VDA_EVENT_SIG;
+ ae->bus_number = a->pcid->bus->number;
+ ae->devfn = a->pcid->devfn;
+ memcpy(&ae->vda_ae, data, sizeof(ae->vda_ae));
+ } else {
+ memcpy(fw_event->data, data, data_sz);
+ }
+
+ fw_event->type = type;
+ fw_event->a = a;
+
+ spin_lock_irqsave(&a->fw_event_lock, flags);
+ list_add_tail(&fw_event->list, &a->fw_event_list);
+ INIT_DELAYED_WORK(&fw_event->work, esas2r_firmware_event_work);
+ queue_delayed_work_on(
+ smp_processor_id(), a->fw_event_q, &fw_event->work,
+ msecs_to_jiffies(1));
+ spin_unlock_irqrestore(&a->fw_event_lock, flags);
+}
+
+void esas2r_target_state_changed(struct esas2r_adapter *a, u16 targ_id,
+ u8 state)
+{
+ if (state == TS_LUN_CHANGE)
+ esas2r_queue_fw_event(a, fw_event_lun_change, &targ_id,
+ sizeof(targ_id));
+ else if (state == TS_PRESENT)
+ esas2r_queue_fw_event(a, fw_event_present, &targ_id,
+ sizeof(targ_id));
+ else if (state == TS_NOT_PRESENT)
+ esas2r_queue_fw_event(a, fw_event_not_present, &targ_id,
+ sizeof(targ_id));
+}
+
+/* Translate status to a Linux SCSI mid-layer error code */
+int esas2r_req_status_to_error(u8 req_stat)
+{
+ switch (req_stat) {
+ case RS_OVERRUN:
+ case RS_UNDERRUN:
+ case RS_SUCCESS:
+ /*
+ * NOTE: SCSI mid-layer wants a good status for a SCSI error, because
+ * it will check the scsi_stat value in the completion anyway.
+ */
+ case RS_SCSI_ERROR:
+ return DID_OK;
+
+ case RS_SEL:
+ case RS_SEL2:
+ return DID_NO_CONNECT;
+
+ case RS_RESET:
+ return DID_RESET;
+
+ case RS_ABORTED:
+ return DID_ABORT;
+
+ case RS_BUSY:
+ return DID_BUS_BUSY;
+ }
+
+ /* everything else is just an error. */
+
+ return DID_ERROR;
+}
+
+module_init(esas2r_init);
+module_exit(esas2r_exit);
diff --git a/drivers/scsi/esas2r/esas2r_targdb.c b/drivers/scsi/esas2r/esas2r_targdb.c
new file mode 100644
index 00000000000..e540a2fa3d1
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_targdb.c
@@ -0,0 +1,306 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r_targdb.c
+ * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+void esas2r_targ_db_initialize(struct esas2r_adapter *a)
+{
+ struct esas2r_target *t;
+
+ for (t = a->targetdb; t < a->targetdb_end; t++) {
+ memset(t, 0, sizeof(struct esas2r_target));
+
+ t->target_state = TS_NOT_PRESENT;
+ t->buffered_target_state = TS_NOT_PRESENT;
+ t->new_target_state = TS_INVALID;
+ }
+}
+
+void esas2r_targ_db_remove_all(struct esas2r_adapter *a, bool notify)
+{
+ struct esas2r_target *t;
+ unsigned long flags;
+
+ for (t = a->targetdb; t < a->targetdb_end; t++) {
+ if (t->target_state != TS_PRESENT)
+ continue;
+
+ spin_lock_irqsave(&a->mem_lock, flags);
+ esas2r_targ_db_remove(a, t);
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+
+ if (notify) {
+ esas2r_trace("remove id:%d", esas2r_targ_get_id(t,
+ a));
+ esas2r_target_state_changed(a, esas2r_targ_get_id(t,
+ a),
+ TS_NOT_PRESENT);
+ }
+ }
+}
+
+void esas2r_targ_db_report_changes(struct esas2r_adapter *a)
+{
+ struct esas2r_target *t;
+ unsigned long flags;
+
+ esas2r_trace_enter();
+
+ if (a->flags & AF_DISC_PENDING) {
+ esas2r_trace_exit();
+ return;
+ }
+
+ for (t = a->targetdb; t < a->targetdb_end; t++) {
+ u8 state = TS_INVALID;
+
+ spin_lock_irqsave(&a->mem_lock, flags);
+ if (t->buffered_target_state != t->target_state)
+ state = t->buffered_target_state = t->target_state;
+
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+ if (state != TS_INVALID) {
+ esas2r_trace("targ_db_report_changes:%d",
+ esas2r_targ_get_id(
+ t,
+ a));
+ esas2r_trace("state:%d", state);
+
+ esas2r_target_state_changed(a,
+ esas2r_targ_get_id(t,
+ a),
+ state);
+ }
+ }
+
+ esas2r_trace_exit();
+}
+
+struct esas2r_target *esas2r_targ_db_add_raid(struct esas2r_adapter *a,
+ struct esas2r_disc_context *
+ dc)
+{
+ struct esas2r_target *t;
+
+ esas2r_trace_enter();
+
+ if (dc->curr_virt_id >= ESAS2R_MAX_TARGETS) {
+ esas2r_bugon();
+ esas2r_trace_exit();
+ return NULL;
+ }
+
+ t = a->targetdb + dc->curr_virt_id;
+
+ if (t->target_state == TS_PRESENT) {
+ esas2r_trace_exit();
+ return NULL;
+ }
+
+ esas2r_hdebug("add RAID %s, T:%d", dc->raid_grp_name,
+ esas2r_targ_get_id(
+ t,
+ a));
+
+ if (dc->interleave == 0
+ || dc->block_size == 0) {
+ /* these are invalid values, don't create the target entry. */
+
+ esas2r_hdebug("invalid RAID group dimensions");
+
+ esas2r_trace_exit();
+
+ return NULL;
+ }
+
+ t->block_size = dc->block_size;
+ t->inter_byte = dc->interleave;
+ t->inter_block = dc->interleave / dc->block_size;
+ t->virt_targ_id = dc->curr_virt_id;
+ t->phys_targ_id = ESAS2R_TARG_ID_INV;
+
+ t->flags &= ~TF_PASS_THRU;
+ t->flags |= TF_USED;
+
+ t->identifier_len = 0;
+
+ t->target_state = TS_PRESENT;
+
+ return t;
+}
+
+struct esas2r_target *esas2r_targ_db_add_pthru(struct esas2r_adapter *a,
+ struct esas2r_disc_context *dc,
+ u8 *ident,
+ u8 ident_len)
+{
+ struct esas2r_target *t;
+
+ esas2r_trace_enter();
+
+ if (dc->curr_virt_id >= ESAS2R_MAX_TARGETS) {
+ esas2r_bugon();
+ esas2r_trace_exit();
+ return NULL;
+ }
+
+ /* see if we found this device before. */
+
+ t = esas2r_targ_db_find_by_ident(a, ident, ident_len);
+
+ if (t == NULL) {
+ t = a->targetdb + dc->curr_virt_id;
+
+ if (ident_len > sizeof(t->identifier)
+ || t->target_state == TS_PRESENT) {
+ esas2r_trace_exit();
+ return NULL;
+ }
+ }
+
+ esas2r_hdebug("add PT; T:%d, V:%d, P:%d", esas2r_targ_get_id(t, a),
+ dc->curr_virt_id,
+ dc->curr_phys_id);
+
+ t->block_size = 0;
+ t->inter_byte = 0;
+ t->inter_block = 0;
+ t->virt_targ_id = dc->curr_virt_id;
+ t->phys_targ_id = dc->curr_phys_id;
+ t->identifier_len = ident_len;
+
+ memcpy(t->identifier, ident, ident_len);
+
+ t->flags |= TF_PASS_THRU | TF_USED;
+
+ t->target_state = TS_PRESENT;
+
+ return t;
+}
+
+void esas2r_targ_db_remove(struct esas2r_adapter *a, struct esas2r_target *t)
+{
+ esas2r_trace_enter();
+
+ t->target_state = TS_NOT_PRESENT;
+
+ esas2r_trace("remove id:%d", esas2r_targ_get_id(t, a));
+
+ esas2r_trace_exit();
+}
+
+struct esas2r_target *esas2r_targ_db_find_by_sas_addr(struct esas2r_adapter *a,
+ u64 *sas_addr)
+{
+ struct esas2r_target *t;
+
+ for (t = a->targetdb; t < a->targetdb_end; t++)
+ if (t->sas_addr == *sas_addr)
+ return t;
+
+ return NULL;
+}
+
+struct esas2r_target *esas2r_targ_db_find_by_ident(struct esas2r_adapter *a,
+ void *identifier,
+ u8 ident_len)
+{
+ struct esas2r_target *t;
+
+ for (t = a->targetdb; t < a->targetdb_end; t++) {
+ if (ident_len == t->identifier_len
+ && memcmp(&t->identifier[0], identifier,
+ ident_len) == 0)
+ return t;
+ }
+
+ return NULL;
+}
+
+u16 esas2r_targ_db_find_next_present(struct esas2r_adapter *a, u16 target_id)
+{
+ u16 id = target_id + 1;
+
+ while (id < ESAS2R_MAX_TARGETS) {
+ struct esas2r_target *t = a->targetdb + id;
+
+ if (t->target_state == TS_PRESENT)
+ break;
+
+ id++;
+ }
+
+ return id;
+}
+
+struct esas2r_target *esas2r_targ_db_find_by_virt_id(struct esas2r_adapter *a,
+ u16 virt_id)
+{
+ struct esas2r_target *t;
+
+ for (t = a->targetdb; t < a->targetdb_end; t++) {
+ if (t->target_state != TS_PRESENT)
+ continue;
+
+ if (t->virt_targ_id == virt_id)
+ return t;
+ }
+
+ return NULL;
+}
+
+u16 esas2r_targ_db_get_tgt_cnt(struct esas2r_adapter *a)
+{
+ u16 devcnt = 0;
+ struct esas2r_target *t;
+ unsigned long flags;
+
+ spin_lock_irqsave(&a->mem_lock, flags);
+ for (t = a->targetdb; t < a->targetdb_end; t++)
+ if (t->target_state == TS_PRESENT)
+ devcnt++;
+
+ spin_unlock_irqrestore(&a->mem_lock, flags);
+
+ return devcnt;
+}
diff --git a/drivers/scsi/esas2r/esas2r_vda.c b/drivers/scsi/esas2r/esas2r_vda.c
new file mode 100644
index 00000000000..f8ec6d63684
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_vda.c
@@ -0,0 +1,521 @@
+/*
+ * linux/drivers/scsi/esas2r/esas2r_vda.c
+ * esas2r driver VDA firmware interface functions
+ *
+ * Copyright (c) 2001-2013 ATTO Technology, Inc.
+ * (mailto:linuxdrivers@attotech.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "esas2r.h"
+
+static u8 esas2r_vdaioctl_versions[] = {
+ ATTO_VDA_VER_UNSUPPORTED,
+ ATTO_VDA_FLASH_VER,
+ ATTO_VDA_VER_UNSUPPORTED,
+ ATTO_VDA_VER_UNSUPPORTED,
+ ATTO_VDA_CLI_VER,
+ ATTO_VDA_VER_UNSUPPORTED,
+ ATTO_VDA_CFG_VER,
+ ATTO_VDA_MGT_VER,
+ ATTO_VDA_GSV_VER
+};
+
+static void clear_vda_request(struct esas2r_request *rq);
+
+static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
+ struct esas2r_request *rq);
+
+/* Prepare a VDA IOCTL request to be sent to the firmware. */
+bool esas2r_process_vda_ioctl(struct esas2r_adapter *a,
+ struct atto_ioctl_vda *vi,
+ struct esas2r_request *rq,
+ struct esas2r_sg_context *sgc)
+{
+ u32 datalen = 0;
+ struct atto_vda_sge *firstsg = NULL;
+ u8 vercnt = (u8)ARRAY_SIZE(esas2r_vdaioctl_versions);
+
+ vi->status = ATTO_STS_SUCCESS;
+ vi->vda_status = RS_PENDING;
+
+ if (vi->function >= vercnt) {
+ vi->status = ATTO_STS_INV_FUNC;
+ return false;
+ }
+
+ if (vi->version > esas2r_vdaioctl_versions[vi->function]) {
+ vi->status = ATTO_STS_INV_VERSION;
+ return false;
+ }
+
+ if (a->flags & AF_DEGRADED_MODE) {
+ vi->status = ATTO_STS_DEGRADED;
+ return false;
+ }
+
+ if (vi->function != VDA_FUNC_SCSI)
+ clear_vda_request(rq);
+
+ rq->vrq->scsi.function = vi->function;
+ rq->interrupt_cb = esas2r_complete_vda_ioctl;
+ rq->interrupt_cx = vi;
+
+ switch (vi->function) {
+ case VDA_FUNC_FLASH:
+
+ if (vi->cmd.flash.sub_func != VDA_FLASH_FREAD
+ && vi->cmd.flash.sub_func != VDA_FLASH_FWRITE
+ && vi->cmd.flash.sub_func != VDA_FLASH_FINFO) {
+ vi->status = ATTO_STS_INV_FUNC;
+ return false;
+ }
+
+ if (vi->cmd.flash.sub_func != VDA_FLASH_FINFO)
+ datalen = vi->data_length;
+
+ rq->vrq->flash.length = cpu_to_le32(datalen);
+ rq->vrq->flash.sub_func = vi->cmd.flash.sub_func;
+
+ memcpy(rq->vrq->flash.data.file.file_name,
+ vi->cmd.flash.data.file.file_name,
+ sizeof(vi->cmd.flash.data.file.file_name));
+
+ firstsg = rq->vrq->flash.data.file.sge;
+ break;
+
+ case VDA_FUNC_CLI:
+
+ datalen = vi->data_length;
+
+ rq->vrq->cli.cmd_rsp_len =
+ cpu_to_le32(vi->cmd.cli.cmd_rsp_len);
+ rq->vrq->cli.length = cpu_to_le32(datalen);
+
+ firstsg = rq->vrq->cli.sge;
+ break;
+
+ case VDA_FUNC_MGT:
+ {
+ u8 *cmdcurr_offset = sgc->cur_offset
+ - offsetof(struct atto_ioctl_vda, data)
+ + offsetof(struct atto_ioctl_vda, cmd)
+ + offsetof(struct atto_ioctl_vda_mgt_cmd,
+ data);
+ /*
+ * build the data payload SGL here first since
+ * esas2r_sgc_init() will modify the S/G list offset for the
+ * management SGL (which is built below where the data SGL is
+ * usually built).
+ */
+
+ if (vi->data_length) {
+ u32 payldlen = 0;
+
+ if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_HEALTH_REQ
+ || vi->cmd.mgt.mgt_func == VDAMGT_DEV_METRICS) {
+ rq->vrq->mgt.payld_sglst_offset =
+ (u8)offsetof(struct atto_vda_mgmt_req,
+ payld_sge);
+
+ payldlen = vi->data_length;
+ datalen = vi->cmd.mgt.data_length;
+ } else if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_INFO2
+ || vi->cmd.mgt.mgt_func ==
+ VDAMGT_DEV_INFO2_BYADDR) {
+ datalen = vi->data_length;
+ cmdcurr_offset = sgc->cur_offset;
+ } else {
+ vi->status = ATTO_STS_INV_PARAM;
+ return false;
+ }
+
+ /* Setup the length so building the payload SGL works */
+ rq->vrq->mgt.length = cpu_to_le32(datalen);
+
+ if (payldlen) {
+ rq->vrq->mgt.payld_length =
+ cpu_to_le32(payldlen);
+
+ esas2r_sgc_init(sgc, a, rq,
+ rq->vrq->mgt.payld_sge);
+ sgc->length = payldlen;
+
+ if (!esas2r_build_sg_list(a, rq, sgc)) {
+ vi->status = ATTO_STS_OUT_OF_RSRC;
+ return false;
+ }
+ }
+ } else {
+ datalen = vi->cmd.mgt.data_length;
+
+ rq->vrq->mgt.length = cpu_to_le32(datalen);
+ }
+
+ /*
+ * Now that the payload SGL is built, if any, setup to build
+ * the management SGL.
+ */
+ firstsg = rq->vrq->mgt.sge;
+ sgc->cur_offset = cmdcurr_offset;
+
+ /* Finish initializing the management request. */
+ rq->vrq->mgt.mgt_func = vi->cmd.mgt.mgt_func;
+ rq->vrq->mgt.scan_generation = vi->cmd.mgt.scan_generation;
+ rq->vrq->mgt.dev_index =
+ cpu_to_le32(vi->cmd.mgt.dev_index);
+
+ esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
+ break;
+ }
+
+ case VDA_FUNC_CFG:
+
+ if (vi->data_length
+ || vi->cmd.cfg.data_length == 0) {
+ vi->status = ATTO_STS_INV_PARAM;
+ return false;
+ }
+
+ if (vi->cmd.cfg.cfg_func == VDA_CFG_INIT) {
+ vi->status = ATTO_STS_INV_FUNC;
+ return false;
+ }
+
+ rq->vrq->cfg.sub_func = vi->cmd.cfg.cfg_func;
+ rq->vrq->cfg.length = cpu_to_le32(vi->cmd.cfg.data_length);
+
+ if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
+ memcpy(&rq->vrq->cfg.data,
+ &vi->cmd.cfg.data,
+ vi->cmd.cfg.data_length);
+
+ esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
+ &rq->vrq->cfg.data);
+ } else {
+ vi->status = ATTO_STS_INV_FUNC;
+
+ return false;
+ }
+
+ break;
+
+ case VDA_FUNC_GSV:
+
+ vi->cmd.gsv.rsp_len = vercnt;
+
+ memcpy(vi->cmd.gsv.version_info, esas2r_vdaioctl_versions,
+ vercnt);
+
+ vi->vda_status = RS_SUCCESS;
+ break;
+
+ default:
+
+ vi->status = ATTO_STS_INV_FUNC;
+ return false;
+ }
+
+ if (datalen) {
+ esas2r_sgc_init(sgc, a, rq, firstsg);
+ sgc->length = datalen;
+
+ if (!esas2r_build_sg_list(a, rq, sgc)) {
+ vi->status = ATTO_STS_OUT_OF_RSRC;
+ return false;
+ }
+ }
+
+ esas2r_start_request(a, rq);
+
+ return true;
+}
+
+static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
+ struct esas2r_request *rq)
+{
+ struct atto_ioctl_vda *vi = (struct atto_ioctl_vda *)rq->interrupt_cx;
+
+ vi->vda_status = rq->req_stat;
+
+ switch (vi->function) {
+ case VDA_FUNC_FLASH:
+
+ if (vi->cmd.flash.sub_func == VDA_FLASH_FINFO
+ || vi->cmd.flash.sub_func == VDA_FLASH_FREAD)
+ vi->cmd.flash.data.file.file_size =
+ le32_to_cpu(rq->func_rsp.flash_rsp.file_size);
+
+ break;
+
+ case VDA_FUNC_MGT:
+
+ vi->cmd.mgt.scan_generation =
+ rq->func_rsp.mgt_rsp.scan_generation;
+ vi->cmd.mgt.dev_index = le16_to_cpu(
+ rq->func_rsp.mgt_rsp.dev_index);
+
+ if (vi->data_length == 0)
+ vi->cmd.mgt.data_length =
+ le32_to_cpu(rq->func_rsp.mgt_rsp.length);
+
+ esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
+ break;
+
+ case VDA_FUNC_CFG:
+
+ if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
+ struct atto_ioctl_vda_cfg_cmd *cfg = &vi->cmd.cfg;
+ struct atto_vda_cfg_rsp *rsp = &rq->func_rsp.cfg_rsp;
+
+ cfg->data_length =
+ cpu_to_le32(sizeof(struct atto_vda_cfg_init));
+ cfg->data.init.vda_version =
+ le32_to_cpu(rsp->vda_version);
+ cfg->data.init.fw_build = rsp->fw_build;
+
+ sprintf((char *)&cfg->data.init.fw_release,
+ "%1d.%02d",
+ (int)LOBYTE(le16_to_cpu(rsp->fw_release)),
+ (int)HIBYTE(le16_to_cpu(rsp->fw_release)));
+
+ if (LOWORD(LOBYTE(cfg->data.init.fw_build)) == 'A')
+ cfg->data.init.fw_version =
+ cfg->data.init.fw_build;
+ else
+ cfg->data.init.fw_version =
+ cfg->data.init.fw_release;
+ } else {
+ esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
+ &vi->cmd.cfg.data);
+ }
+
+ break;
+
+ case VDA_FUNC_CLI:
+
+ vi->cmd.cli.cmd_rsp_len =
+ le32_to_cpu(rq->func_rsp.cli_rsp.cmd_rsp_len);
+ break;
+
+ default:
+
+ break;
+ }
+}
+
+/* Build a flash VDA request. */
+void esas2r_build_flash_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ u8 sub_func,
+ u8 cksum,
+ u32 addr,
+ u32 length)
+{
+ struct atto_vda_flash_req *vrq = &rq->vrq->flash;
+
+ clear_vda_request(rq);
+
+ rq->vrq->scsi.function = VDA_FUNC_FLASH;
+
+ if (sub_func == VDA_FLASH_BEGINW
+ || sub_func == VDA_FLASH_WRITE
+ || sub_func == VDA_FLASH_READ)
+ vrq->sg_list_offset = (u8)offsetof(struct atto_vda_flash_req,
+ data.sge);
+
+ vrq->length = cpu_to_le32(length);
+ vrq->flash_addr = cpu_to_le32(addr);
+ vrq->checksum = cksum;
+ vrq->sub_func = sub_func;
+}
+
+/* Build a VDA management request. */
+void esas2r_build_mgt_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ u8 sub_func,
+ u8 scan_gen,
+ u16 dev_index,
+ u32 length,
+ void *data)
+{
+ struct atto_vda_mgmt_req *vrq = &rq->vrq->mgt;
+
+ clear_vda_request(rq);
+
+ rq->vrq->scsi.function = VDA_FUNC_MGT;
+
+ vrq->mgt_func = sub_func;
+ vrq->scan_generation = scan_gen;
+ vrq->dev_index = cpu_to_le16(dev_index);
+ vrq->length = cpu_to_le32(length);
+
+ if (vrq->length) {
+ if (a->flags & AF_LEGACY_SGE_MODE) {
+ vrq->sg_list_offset = (u8)offsetof(
+ struct atto_vda_mgmt_req, sge);
+
+ vrq->sge[0].length = cpu_to_le32(SGE_LAST | length);
+ vrq->sge[0].address = cpu_to_le64(
+ rq->vrq_md->phys_addr +
+ sizeof(union atto_vda_req));
+ } else {
+ vrq->sg_list_offset = (u8)offsetof(
+ struct atto_vda_mgmt_req, prde);
+
+ vrq->prde[0].ctl_len = cpu_to_le32(length);
+ vrq->prde[0].address = cpu_to_le64(
+ rq->vrq_md->phys_addr +
+ sizeof(union atto_vda_req));
+ }
+ }
+
+ if (data) {
+ esas2r_nuxi_mgt_data(sub_func, data);
+
+ memcpy(&rq->vda_rsp_data->mgt_data.data.bytes[0], data,
+ length);
+ }
+}
+
+/* Build a VDA asyncronous event (AE) request. */
+void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+ struct atto_vda_ae_req *vrq = &rq->vrq->ae;
+
+ clear_vda_request(rq);
+
+ rq->vrq->scsi.function = VDA_FUNC_AE;
+
+ vrq->length = cpu_to_le32(sizeof(struct atto_vda_ae_data));
+
+ if (a->flags & AF_LEGACY_SGE_MODE) {
+ vrq->sg_list_offset =
+ (u8)offsetof(struct atto_vda_ae_req, sge);
+ vrq->sge[0].length = cpu_to_le32(SGE_LAST | vrq->length);
+ vrq->sge[0].address = cpu_to_le64(
+ rq->vrq_md->phys_addr +
+ sizeof(union atto_vda_req));
+ } else {
+ vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ae_req,
+ prde);
+ vrq->prde[0].ctl_len = cpu_to_le32(vrq->length);
+ vrq->prde[0].address = cpu_to_le64(
+ rq->vrq_md->phys_addr +
+ sizeof(union atto_vda_req));
+ }
+}
+
+/* Build a VDA CLI request. */
+void esas2r_build_cli_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ u32 length,
+ u32 cmd_rsp_len)
+{
+ struct atto_vda_cli_req *vrq = &rq->vrq->cli;
+
+ clear_vda_request(rq);
+
+ rq->vrq->scsi.function = VDA_FUNC_CLI;
+
+ vrq->length = cpu_to_le32(length);
+ vrq->cmd_rsp_len = cpu_to_le32(cmd_rsp_len);
+ vrq->sg_list_offset = (u8)offsetof(struct atto_vda_cli_req, sge);
+}
+
+/* Build a VDA IOCTL request. */
+void esas2r_build_ioctl_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ u32 length,
+ u8 sub_func)
+{
+ struct atto_vda_ioctl_req *vrq = &rq->vrq->ioctl;
+
+ clear_vda_request(rq);
+
+ rq->vrq->scsi.function = VDA_FUNC_IOCTL;
+
+ vrq->length = cpu_to_le32(length);
+ vrq->sub_func = sub_func;
+ vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ioctl_req, sge);
+}
+
+/* Build a VDA configuration request. */
+void esas2r_build_cfg_req(struct esas2r_adapter *a,
+ struct esas2r_request *rq,
+ u8 sub_func,
+ u32 length,
+ void *data)
+{
+ struct atto_vda_cfg_req *vrq = &rq->vrq->cfg;
+
+ clear_vda_request(rq);
+
+ rq->vrq->scsi.function = VDA_FUNC_CFG;
+
+ vrq->sub_func = sub_func;
+ vrq->length = cpu_to_le32(length);
+
+ if (data) {
+ esas2r_nuxi_cfg_data(sub_func, data);
+
+ memcpy(&vrq->data, data, length);
+ }
+}
+
+static void clear_vda_request(struct esas2r_request *rq)
+{
+ u32 handle = rq->vrq->scsi.handle;
+
+ memset(rq->vrq, 0, sizeof(*rq->vrq));
+
+ rq->vrq->scsi.handle = handle;
+
+ rq->req_stat = RS_PENDING;
+
+ /* since the data buffer is separate clear that too */
+
+ memset(rq->data_buf, 0, ESAS2R_DATA_BUF_LEN);
+
+ /*
+ * Setup next and prev pointer in case the request is not going through
+ * esas2r_start_request().
+ */
+
+ INIT_LIST_HEAD(&rq->req_list);
+}
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h
index b6d1f92ed33..c18c68150e9 100644
--- a/drivers/scsi/fnic/fnic.h
+++ b/drivers/scsi/fnic/fnic.h
@@ -38,7 +38,7 @@
#define DRV_NAME "fnic"
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
-#define DRV_VERSION "1.5.0.22"
+#define DRV_VERSION "1.5.0.23"
#define PFX DRV_NAME ": "
#define DFX DRV_NAME "%d: "
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index 5f09d1814d2..42e15ee6e1b 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -642,19 +642,6 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&fnic->fip_frame_work, fnic_handle_fip_frame);
INIT_WORK(&fnic->event_work, fnic_handle_event);
skb_queue_head_init(&fnic->fip_frame_queue);
- spin_lock_irqsave(&fnic_list_lock, flags);
- if (!fnic_fip_queue) {
- fnic_fip_queue =
- create_singlethread_workqueue("fnic_fip_q");
- if (!fnic_fip_queue) {
- spin_unlock_irqrestore(&fnic_list_lock, flags);
- printk(KERN_ERR PFX "fnic FIP work queue "
- "create failed\n");
- err = -ENOMEM;
- goto err_out_free_max_pool;
- }
- }
- spin_unlock_irqrestore(&fnic_list_lock, flags);
INIT_LIST_HEAD(&fnic->evlist);
INIT_LIST_HEAD(&fnic->vlans);
} else {
@@ -960,6 +947,13 @@ static int __init fnic_init_module(void)
spin_lock_init(&fnic_list_lock);
INIT_LIST_HEAD(&fnic_list);
+ fnic_fip_queue = create_singlethread_workqueue("fnic_fip_q");
+ if (!fnic_fip_queue) {
+ printk(KERN_ERR PFX "fnic FIP work queue create failed\n");
+ err = -ENOMEM;
+ goto err_create_fip_workq;
+ }
+
fnic_fc_transport = fc_attach_transport(&fnic_fc_functions);
if (!fnic_fc_transport) {
printk(KERN_ERR PFX "fc_attach_transport error\n");
@@ -978,6 +972,8 @@ static int __init fnic_init_module(void)
err_pci_register:
fc_release_transport(fnic_fc_transport);
err_fc_transport:
+ destroy_workqueue(fnic_fip_queue);
+err_create_fip_workq:
destroy_workqueue(fnic_event_queue);
err_create_fnic_workq:
kmem_cache_destroy(fnic_io_req_cache);
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 7f4f790a3d7..b766f5aea58 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -583,7 +583,7 @@ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
if (likely(h->msix_vector))
c->Header.ReplyQueue =
- smp_processor_id() % h->nreply_queues;
+ raw_smp_processor_id() % h->nreply_queues;
}
}
@@ -1205,8 +1205,8 @@ static void complete_scsi_command(struct CommandList *cp)
scsi_set_resid(cmd, ei->ResidualCnt);
if (ei->CommandStatus == 0) {
- cmd->scsi_done(cmd);
cmd_free(h, cp);
+ cmd->scsi_done(cmd);
return;
}
@@ -1379,8 +1379,8 @@ static void complete_scsi_command(struct CommandList *cp)
dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
cp, ei->CommandStatus);
}
- cmd->scsi_done(cmd);
cmd_free(h, cp);
+ cmd->scsi_done(cmd);
}
static void hpsa_pci_unmap(struct pci_dev *pdev,
@@ -2721,7 +2721,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
} while (test_and_set_bit
(i & (BITS_PER_LONG - 1),
h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
- h->nr_allocs++;
spin_unlock_irqrestore(&h->lock, flags);
c = h->cmd_pool + i;
@@ -2793,7 +2792,6 @@ static void cmd_free(struct ctlr_info *h, struct CommandList *c)
spin_lock_irqsave(&h->lock, flags);
clear_bit(i & (BITS_PER_LONG - 1),
h->cmd_pool_bits + (i / BITS_PER_LONG));
- h->nr_frees++;
spin_unlock_irqrestore(&h->lock, flags);
}
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 981647989bf..bc85e7244f4 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -98,8 +98,6 @@ struct ctlr_info {
struct ErrorInfo *errinfo_pool;
dma_addr_t errinfo_pool_dhandle;
unsigned long *cmd_pool_bits;
- int nr_allocs;
- int nr_frees;
int scan_finished;
spinlock_t scan_lock;
wait_queue_head_t scan_wait_queue;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 6601e03520c..36ac1c34ce9 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -9990,6 +9990,20 @@ static struct pci_device_id ipr_pci_table[] = {
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D7, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D8, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D9, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EB, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EC, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57ED, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EE, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EF, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57F0, 0, 0, 0 },
{ }
};
MODULE_DEVICE_TABLE(pci, ipr_pci_table);
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 07a85ce4178..cad1483f05d 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -100,6 +100,13 @@
#define IPR_SUBS_DEV_ID_57D6 0x03FC
#define IPR_SUBS_DEV_ID_57D7 0x03FF
#define IPR_SUBS_DEV_ID_57D8 0x03FE
+#define IPR_SUBS_DEV_ID_57D9 0x046D
+#define IPR_SUBS_DEV_ID_57EB 0x0474
+#define IPR_SUBS_DEV_ID_57EC 0x0475
+#define IPR_SUBS_DEV_ID_57ED 0x0499
+#define IPR_SUBS_DEV_ID_57EE 0x049A
+#define IPR_SUBS_DEV_ID_57EF 0x049B
+#define IPR_SUBS_DEV_ID_57F0 0x049C
#define IPR_NAME "ipr"
/*
diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c
index cd962da4a57..85c77f6b802 100644
--- a/drivers/scsi/isci/port_config.c
+++ b/drivers/scsi/isci/port_config.c
@@ -311,9 +311,9 @@ sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost,
&ihost->phys[phy_index]);
assigned_phy_mask |= (1 << phy_index);
+ phy_index++;
}
- phy_index++;
}
return sci_port_configuration_agent_validate_ports(ihost, port_agent);
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 7b082157eb7..99d2930b18c 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -185,7 +185,7 @@ static void sci_io_request_build_ssp_command_iu(struct isci_request *ireq)
cmd_iu->_r_c = 0;
sci_swab32_cpy(&cmd_iu->cdb, task->ssp_task.cmd->cmnd,
- task->ssp_task.cmd->cmd_len / sizeof(u32));
+ (task->ssp_task.cmd->cmd_len+3) / sizeof(u32));
}
static void sci_task_request_build_ssp_task_iu(struct isci_request *ireq)
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 9bb020ac089..0d30ca849e8 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -491,6 +491,7 @@ int isci_task_abort_task(struct sas_task *task)
struct isci_tmf tmf;
int ret = TMF_RESP_FUNC_FAILED;
unsigned long flags;
+ int target_done_already = 0;
/* Get the isci_request reference from the task. Note that
* this check does not depend on the pending request list
@@ -505,9 +506,11 @@ int isci_task_abort_task(struct sas_task *task)
/* If task is already done, the request isn't valid */
if (!(task->task_state_flags & SAS_TASK_STATE_DONE) &&
(task->task_state_flags & SAS_TASK_AT_INITIATOR) &&
- old_request)
+ old_request) {
idev = isci_get_device(task->dev->lldd_dev);
-
+ target_done_already = test_bit(IREQ_COMPLETE_IN_TARGET,
+ &old_request->flags);
+ }
spin_unlock(&task->task_state_lock);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
@@ -561,7 +564,7 @@ int isci_task_abort_task(struct sas_task *task)
if (task->task_proto == SAS_PROTOCOL_SMP ||
sas_protocol_ata(task->task_proto) ||
- test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags) ||
+ target_done_already ||
test_bit(IDEV_GONE, &idev->flags)) {
spin_unlock_irqrestore(&ihost->scic_lock, flags);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index ae69dfcc783..e3995612ea7 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2812,6 +2812,8 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
kfree(session->boot_nic);
kfree(session->boot_target);
kfree(session->ifacename);
+ kfree(session->portal_type);
+ kfree(session->discovery_parent_type);
iscsi_destroy_session(cls_session);
iscsi_host_dec_session_cnt(shost);
@@ -3168,6 +3170,7 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_session *session = conn->session;
+ int val;
switch(param) {
case ISCSI_PARAM_FAST_ABORT:
@@ -3257,6 +3260,15 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
return iscsi_switch_str_param(&session->boot_nic, buf);
case ISCSI_PARAM_BOOT_TARGET:
return iscsi_switch_str_param(&session->boot_target, buf);
+ case ISCSI_PARAM_PORTAL_TYPE:
+ return iscsi_switch_str_param(&session->portal_type, buf);
+ case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
+ return iscsi_switch_str_param(&session->discovery_parent_type,
+ buf);
+ case ISCSI_PARAM_DISCOVERY_SESS:
+ sscanf(buf, "%d", &val);
+ session->discovery_sess = !!val;
+ break;
default:
return -ENOSYS;
}
@@ -3305,6 +3317,9 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
case ISCSI_PARAM_DATASEQ_INORDER_EN:
len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
break;
+ case ISCSI_PARAM_DEF_TASKMGMT_TMO:
+ len = sprintf(buf, "%d\n", session->def_taskmgmt_tmo);
+ break;
case ISCSI_PARAM_ERL:
len = sprintf(buf, "%d\n", session->erl);
break;
@@ -3344,6 +3359,52 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
case ISCSI_PARAM_BOOT_TARGET:
len = sprintf(buf, "%s\n", session->boot_target);
break;
+ case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
+ len = sprintf(buf, "%u\n", session->auto_snd_tgt_disable);
+ break;
+ case ISCSI_PARAM_DISCOVERY_SESS:
+ len = sprintf(buf, "%u\n", session->discovery_sess);
+ break;
+ case ISCSI_PARAM_PORTAL_TYPE:
+ len = sprintf(buf, "%s\n", session->portal_type);
+ break;
+ case ISCSI_PARAM_CHAP_AUTH_EN:
+ len = sprintf(buf, "%u\n", session->chap_auth_en);
+ break;
+ case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
+ len = sprintf(buf, "%u\n", session->discovery_logout_en);
+ break;
+ case ISCSI_PARAM_BIDI_CHAP_EN:
+ len = sprintf(buf, "%u\n", session->bidi_chap_en);
+ break;
+ case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
+ len = sprintf(buf, "%u\n", session->discovery_auth_optional);
+ break;
+ case ISCSI_PARAM_DEF_TIME2WAIT:
+ len = sprintf(buf, "%d\n", session->time2wait);
+ break;
+ case ISCSI_PARAM_DEF_TIME2RETAIN:
+ len = sprintf(buf, "%d\n", session->time2retain);
+ break;
+ case ISCSI_PARAM_TSID:
+ len = sprintf(buf, "%u\n", session->tsid);
+ break;
+ case ISCSI_PARAM_ISID:
+ len = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
+ session->isid[0], session->isid[1],
+ session->isid[2], session->isid[3],
+ session->isid[4], session->isid[5]);
+ break;
+ case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
+ len = sprintf(buf, "%u\n", session->discovery_parent_idx);
+ break;
+ case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
+ if (session->discovery_parent_type)
+ len = sprintf(buf, "%s\n",
+ session->discovery_parent_type);
+ else
+ len = sprintf(buf, "\n");
+ break;
default:
return -ENOSYS;
}
@@ -3433,6 +3494,54 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
case ISCSI_PARAM_PERSISTENT_ADDRESS:
len = sprintf(buf, "%s\n", conn->persistent_address);
break;
+ case ISCSI_PARAM_STATSN:
+ len = sprintf(buf, "%u\n", conn->statsn);
+ break;
+ case ISCSI_PARAM_MAX_SEGMENT_SIZE:
+ len = sprintf(buf, "%u\n", conn->max_segment_size);
+ break;
+ case ISCSI_PARAM_KEEPALIVE_TMO:
+ len = sprintf(buf, "%u\n", conn->keepalive_tmo);
+ break;
+ case ISCSI_PARAM_LOCAL_PORT:
+ len = sprintf(buf, "%u\n", conn->local_port);
+ break;
+ case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
+ len = sprintf(buf, "%u\n", conn->tcp_timestamp_stat);
+ break;
+ case ISCSI_PARAM_TCP_NAGLE_DISABLE:
+ len = sprintf(buf, "%u\n", conn->tcp_nagle_disable);
+ break;
+ case ISCSI_PARAM_TCP_WSF_DISABLE:
+ len = sprintf(buf, "%u\n", conn->tcp_wsf_disable);
+ break;
+ case ISCSI_PARAM_TCP_TIMER_SCALE:
+ len = sprintf(buf, "%u\n", conn->tcp_timer_scale);
+ break;
+ case ISCSI_PARAM_TCP_TIMESTAMP_EN:
+ len = sprintf(buf, "%u\n", conn->tcp_timestamp_en);
+ break;
+ case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
+ len = sprintf(buf, "%u\n", conn->fragment_disable);
+ break;
+ case ISCSI_PARAM_IPV4_TOS:
+ len = sprintf(buf, "%u\n", conn->ipv4_tos);
+ break;
+ case ISCSI_PARAM_IPV6_TC:
+ len = sprintf(buf, "%u\n", conn->ipv6_traffic_class);
+ break;
+ case ISCSI_PARAM_IPV6_FLOW_LABEL:
+ len = sprintf(buf, "%u\n", conn->ipv6_flow_label);
+ break;
+ case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
+ len = sprintf(buf, "%u\n", conn->is_fw_assigned_ipv6);
+ break;
+ case ISCSI_PARAM_TCP_XMIT_WSF:
+ len = sprintf(buf, "%u\n", conn->tcp_xmit_wsf);
+ break;
+ case ISCSI_PARAM_TCP_RECV_WSF:
+ len = sprintf(buf, "%u\n", conn->tcp_recv_wsf);
+ break;
default:
return -ENOSYS;
}
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 93f222d6671..df43bfe6d57 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -421,6 +421,7 @@ struct lpfc_vport {
uint32_t cfg_enable_da_id;
uint32_t cfg_max_scsicmpl_time;
uint32_t cfg_tgt_queue_depth;
+ uint32_t cfg_first_burst_size;
uint32_t dev_loss_tmo_changed;
@@ -710,8 +711,6 @@ struct lpfc_hba {
uint32_t cfg_use_msi;
uint32_t cfg_fcp_imax;
uint32_t cfg_fcp_cpu_map;
- uint32_t cfg_fcp_wq_count;
- uint32_t cfg_fcp_eq_count;
uint32_t cfg_fcp_io_channel;
uint32_t cfg_total_seg_cnt;
uint32_t cfg_sg_seg_cnt;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 5cb08ae3e8c..22f42f866f7 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -674,9 +674,6 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
int i;
int rc;
- if (phba->pport->fc_flag & FC_OFFLINE_MODE)
- return 0;
-
init_completion(&online_compl);
rc = lpfc_workq_post_event(phba, &status, &online_compl,
LPFC_EVT_OFFLINE_PREP);
@@ -744,14 +741,15 @@ lpfc_selective_reset(struct lpfc_hba *phba)
int status = 0;
int rc;
- if ((!phba->cfg_enable_hba_reset) ||
- (phba->pport->fc_flag & FC_OFFLINE_MODE))
+ if (!phba->cfg_enable_hba_reset)
return -EACCES;
- status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
+ if (!(phba->pport->fc_flag & FC_OFFLINE_MODE)) {
+ status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
- if (status != 0)
- return status;
+ if (status != 0)
+ return status;
+ }
init_completion(&online_compl);
rc = lpfc_workq_post_event(phba, &status, &online_compl,
@@ -2591,9 +2589,12 @@ LPFC_VPORT_ATTR_R(enable_da_id, 1, 0, 1,
/*
# lun_queue_depth: This parameter is used to limit the number of outstanding
-# commands per FCP LUN. Value range is [1,128]. Default value is 30.
+# commands per FCP LUN. Value range is [1,512]. Default value is 30.
+# If this parameter value is greater than 1/8th the maximum number of exchanges
+# supported by the HBA port, then the lun queue depth will be reduced to
+# 1/8th the maximum number of exchanges.
*/
-LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128,
+LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512,
"Max number of FCP commands we can queue to a specific LUN");
/*
@@ -2601,7 +2602,7 @@ LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128,
# commands per target port. Value range is [10,65535]. Default value is 65535.
*/
LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535,
- "Max number of FCP commands we can queue to a specific target port");
+ "Max number of FCP commands we can queue to a specific target port");
/*
# hba_queue_depth: This parameter is used to limit the number of outstanding
@@ -3949,6 +3950,14 @@ LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1,
"Use ADISC on rediscovery to authenticate FCP devices");
/*
+# lpfc_first_burst_size: First burst size to use on the NPorts
+# that support first burst.
+# Value range is [0,65536]. Default value is 0.
+*/
+LPFC_VPORT_ATTR_RW(first_burst_size, 0, 0, 65536,
+ "First burst size for Targets that support first burst");
+
+/*
# lpfc_max_scsicmpl_time: Use scsi command completion time to control I/O queue
# depth. Default value is 0. When the value of this parameter is zero the
# SCSI command completion time is not used for controlling I/O queue depth. When
@@ -4112,25 +4121,6 @@ LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or "
"MSI-X (2), if possible");
/*
-# lpfc_fcp_wq_count: Set the number of fast-path FCP work queues
-# This parameter is ignored and will eventually be depricated
-#
-# Value range is [1,7]. Default value is 4.
-*/
-LPFC_ATTR_R(fcp_wq_count, LPFC_FCP_IO_CHAN_DEF, LPFC_FCP_IO_CHAN_MIN,
- LPFC_FCP_IO_CHAN_MAX,
- "Set the number of fast-path FCP work queues, if possible");
-
-/*
-# lpfc_fcp_eq_count: Set the number of FCP EQ/CQ/WQ IO channels
-#
-# Value range is [1,7]. Default value is 4.
-*/
-LPFC_ATTR_R(fcp_eq_count, LPFC_FCP_IO_CHAN_DEF, LPFC_FCP_IO_CHAN_MIN,
- LPFC_FCP_IO_CHAN_MAX,
- "Set the number of fast-path FCP event queues, if possible");
-
-/*
# lpfc_fcp_io_channel: Set the number of FCP EQ/CQ/WQ IO channels
#
# Value range is [1,7]. Default value is 4.
@@ -4276,6 +4266,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_devloss_tmo,
&dev_attr_lpfc_fcp_class,
&dev_attr_lpfc_use_adisc,
+ &dev_attr_lpfc_first_burst_size,
&dev_attr_lpfc_ack0,
&dev_attr_lpfc_topology,
&dev_attr_lpfc_scan_down,
@@ -4307,8 +4298,6 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_use_msi,
&dev_attr_lpfc_fcp_imax,
&dev_attr_lpfc_fcp_cpu_map,
- &dev_attr_lpfc_fcp_wq_count,
- &dev_attr_lpfc_fcp_eq_count,
&dev_attr_lpfc_fcp_io_channel,
&dev_attr_lpfc_enable_bg,
&dev_attr_lpfc_soft_wwnn,
@@ -4352,6 +4341,7 @@ struct device_attribute *lpfc_vport_attrs[] = {
&dev_attr_lpfc_restrict_login,
&dev_attr_lpfc_fcp_class,
&dev_attr_lpfc_use_adisc,
+ &dev_attr_lpfc_first_burst_size,
&dev_attr_lpfc_fdmi_on,
&dev_attr_lpfc_max_luns,
&dev_attr_nport_evt_cnt,
@@ -5290,8 +5280,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
- lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count);
- lpfc_fcp_eq_count_init(phba, lpfc_fcp_eq_count);
lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel);
lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
@@ -5331,6 +5319,7 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
lpfc_restrict_login_init(vport, lpfc_restrict_login);
lpfc_fcp_class_init(vport, lpfc_fcp_class);
lpfc_use_adisc_init(vport, lpfc_use_adisc);
+ lpfc_first_burst_size_init(vport, lpfc_first_burst_size);
lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time);
lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 6630520d295..bc270639c1c 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -2498,7 +2498,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
struct lpfc_sli_ct_request *ctreq = NULL;
int ret_val = 0;
int time_left;
- int iocb_stat = 0;
+ int iocb_stat = IOCB_SUCCESS;
unsigned long flags;
*txxri = 0;
@@ -2574,6 +2574,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
cmdiocbq->vport = phba->pport;
+ cmdiocbq->iocb_cmpl = NULL;
iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
rspiocbq,
@@ -2963,7 +2964,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
uint8_t *ptr = NULL, *rx_databuf = NULL;
int rc = 0;
int time_left;
- int iocb_stat;
+ int iocb_stat = IOCB_SUCCESS;
unsigned long flags;
void *dataout = NULL;
uint32_t total_mem;
@@ -3149,6 +3150,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
}
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
cmdiocbq->vport = phba->pport;
+ cmdiocbq->iocb_cmpl = NULL;
iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
rspiocbq, (phba->fc_ratov * 2) +
LPFC_DRVR_TIMEOUT);
@@ -3209,7 +3211,7 @@ err_loopback_test_exit:
lpfc_bsg_event_unref(evt); /* delete */
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- if (cmdiocbq != NULL)
+ if ((cmdiocbq != NULL) && (iocb_stat != IOCB_TIMEDOUT))
lpfc_sli_release_iocbq(phba, cmdiocbq);
if (rspiocbq != NULL)
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 68391177432..02e8cd923d0 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -895,7 +895,7 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (irsp->ulpStatus) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
- "0268 NS cmd %x Error (%d %d)\n",
+ "0268 NS cmd x%x Error (x%x x%x)\n",
cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]);
if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index af49fb03dbb..e409ba5f728 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2008 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2013 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -154,6 +154,7 @@ struct lpfc_node_rrq {
#define NLP_NODEV_REMOVE 0x08000000 /* Defer removal till discovery ends */
#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */
#define NLP_SC_REQ 0x20000000 /* Target requires authentication */
+#define NLP_FIRSTBURST 0x40000000 /* Target supports FirstBurst */
#define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */
/* ndlp usage management macros */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 6b8ee7449f1..110445f0c58 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -2122,6 +2122,8 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
}
npr->estabImagePair = 1;
npr->readXferRdyDis = 1;
+ if (vport->cfg_first_burst_size)
+ npr->writeXferRdyDis = 1;
/* For FCP support */
npr->prliType = PRLI_FCP_TYPE;
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 4ec3d7c044c..086c3f28caa 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -234,6 +234,9 @@ struct ulp_bde64 {
uint32_t addrHigh;
};
+/* Maximun size of immediate data that can fit into a 128 byte WQE */
+#define LPFC_MAX_BDE_IMM_SIZE 64
+
struct lpfc_sli4_flags {
uint32_t word0;
#define lpfc_idx_rsrc_rdy_SHIFT 0
@@ -2585,6 +2588,9 @@ struct lpfc_sli4_parameters {
#define cfg_mqv_WORD word6
uint32_t word7;
uint32_t word8;
+#define cfg_wqsize_SHIFT 8
+#define cfg_wqsize_MASK 0x0000000f
+#define cfg_wqsize_WORD word8
#define cfg_wqv_SHIFT 14
#define cfg_wqv_MASK 0x00000003
#define cfg_wqv_WORD word8
@@ -3622,6 +3628,13 @@ union lpfc_wqe {
struct gen_req64_wqe gen_req;
};
+union lpfc_wqe128 {
+ uint32_t words[32];
+ struct lpfc_wqe_generic generic;
+ struct xmit_seq64_wqe xmit_sequence;
+ struct gen_req64_wqe gen_req;
+};
+
#define LPFC_GROUP_OJECT_MAGIC_NUM 0xfeaa0001
#define LPFC_FILE_TYPE_GROUP 0xf7
#define LPFC_FILE_ID_GROUP 0xa2
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index e0b20fad850..501147c4a14 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -472,10 +472,22 @@ lpfc_config_port_post(struct lpfc_hba *phba)
lpfc_sli_read_link_ste(phba);
/* Reset the DFT_HBA_Q_DEPTH to the max xri */
- if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1))
- phba->cfg_hba_queue_depth =
- (mb->un.varRdConfig.max_xri + 1) -
- lpfc_sli4_get_els_iocb_cnt(phba);
+ i = (mb->un.varRdConfig.max_xri + 1);
+ if (phba->cfg_hba_queue_depth > i) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "3359 HBA queue depth changed from %d to %d\n",
+ phba->cfg_hba_queue_depth, i);
+ phba->cfg_hba_queue_depth = i;
+ }
+
+ /* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */
+ i = (mb->un.varRdConfig.max_xri >> 3);
+ if (phba->pport->cfg_lun_queue_depth > i) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "3360 LUN queue depth changed from %d to %d\n",
+ phba->pport->cfg_lun_queue_depth, i);
+ phba->pport->cfg_lun_queue_depth = i;
+ }
phba->lmt = mb->un.varRdConfig.lmt;
@@ -4901,9 +4913,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
lpfc_get_cfgparam(phba);
phba->max_vpi = LPFC_MAX_VPI;
- /* Eventually cfg_fcp_eq_count / cfg_fcp_wq_count will be depricated */
- phba->cfg_fcp_io_channel = phba->cfg_fcp_eq_count;
-
/* This will be set to correct value after the read_config mbox */
phba->max_vports = 0;
@@ -6664,12 +6673,14 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
goto read_cfg_out;
/* Reset the DFT_HBA_Q_DEPTH to the max xri */
- if (phba->cfg_hba_queue_depth >
- (phba->sli4_hba.max_cfg_param.max_xri -
- lpfc_sli4_get_els_iocb_cnt(phba)))
- phba->cfg_hba_queue_depth =
- phba->sli4_hba.max_cfg_param.max_xri -
- lpfc_sli4_get_els_iocb_cnt(phba);
+ length = phba->sli4_hba.max_cfg_param.max_xri -
+ lpfc_sli4_get_els_iocb_cnt(phba);
+ if (phba->cfg_hba_queue_depth > length) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "3361 HBA queue depth changed from %d to %d\n",
+ phba->cfg_hba_queue_depth, length);
+ phba->cfg_hba_queue_depth = length;
+ }
if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
LPFC_SLI_INTF_IF_TYPE_2)
@@ -6859,11 +6870,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq;
}
- /* Eventually cfg_fcp_eq_count / cfg_fcp_wq_count will be depricated */
-
/* The actual number of FCP event queues adopted */
- phba->cfg_fcp_eq_count = cfg_fcp_io_channel;
- phba->cfg_fcp_wq_count = cfg_fcp_io_channel;
phba->cfg_fcp_io_channel = cfg_fcp_io_channel;
/* Get EQ depth from module parameter, fake the default for now */
@@ -9154,6 +9161,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters);
sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters);
sli4_params->rqv = bf_get(cfg_rqv, mbx_sli4_parameters);
+ sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters);
sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt,
mbx_sli4_parameters);
sli4_params->sgl_pp_align = bf_get(cfg_sgl_pp_align,
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index b1c510f6b8f..1f292e29d56 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -178,7 +178,8 @@ lpfc_dump_wakeup_param(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
mb->mbxOwner = OWN_HOST;
mb->un.varDmp.cv = 1;
mb->un.varDmp.type = DMP_NV_PARAMS;
- mb->un.varDmp.entry_index = 0;
+ if (phba->sli_rev < LPFC_SLI_REV4)
+ mb->un.varDmp.entry_index = 0;
mb->un.varDmp.region_id = WAKE_UP_PARMS_REGION_ID;
mb->un.varDmp.word_cnt = WAKE_UP_PARMS_WORD_SIZE;
mb->un.varDmp.co = 0;
@@ -361,7 +362,7 @@ lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
/* NEW_FEATURE
* SLI-2, Coalescing Response Feature.
*/
- if (phba->cfg_cr_delay) {
+ if (phba->cfg_cr_delay && (phba->sli_rev < LPFC_SLI_REV4)) {
mb->un.varCfgLnk.cr = 1;
mb->un.varCfgLnk.ci = 1;
mb->un.varCfgLnk.cr_delay = phba->cfg_cr_delay;
@@ -377,7 +378,7 @@ lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
mb->un.varCfgLnk.crtov = phba->fc_crtov;
mb->un.varCfgLnk.citov = phba->fc_citov;
- if (phba->cfg_ack0)
+ if (phba->cfg_ack0 && (phba->sli_rev < LPFC_SLI_REV4))
mb->un.varCfgLnk.ack0_enable = 1;
mb->mbxCommand = MBX_CONFIG_LINK;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 6aaf39a1f1c..abc361259d6 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -690,11 +690,15 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
+ ndlp->nlp_flag &= ~NLP_FIRSTBURST;
if (npr->prliType == PRLI_FCP_TYPE) {
if (npr->initiatorFunc)
ndlp->nlp_type |= NLP_FCP_INITIATOR;
- if (npr->targetFunc)
+ if (npr->targetFunc) {
ndlp->nlp_type |= NLP_FCP_TARGET;
+ if (npr->writeXferRdyDis)
+ ndlp->nlp_flag |= NLP_FIRSTBURST;
+ }
if (npr->Retry)
ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
}
@@ -1676,12 +1680,16 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Check out PRLI rsp */
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
+ ndlp->nlp_flag &= ~NLP_FIRSTBURST;
if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
(npr->prliType == PRLI_FCP_TYPE)) {
if (npr->initiatorFunc)
ndlp->nlp_type |= NLP_FCP_INITIATOR;
- if (npr->targetFunc)
+ if (npr->targetFunc) {
ndlp->nlp_type |= NLP_FCP_TARGET;
+ if (npr->writeXferRdyDis)
+ ndlp->nlp_flag |= NLP_FIRSTBURST;
+ }
if (npr->Retry)
ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 243de1d324b..1242b6c4308 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -4386,11 +4386,11 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
if (scsi_sg_count(scsi_cmnd)) {
if (datadir == DMA_TO_DEVICE) {
iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
- if (sli4)
- iocb_cmd->ulpPU = PARM_READ_CHECK;
- else {
- iocb_cmd->un.fcpi.fcpi_parm = 0;
- iocb_cmd->ulpPU = 0;
+ iocb_cmd->ulpPU = PARM_READ_CHECK;
+ if (vport->cfg_first_burst_size &&
+ (pnode->nlp_flag & NLP_FIRSTBURST)) {
+ piocbq->iocb.un.fcpi.fcpi_XRdy =
+ vport->cfg_first_burst_size;
}
fcp_cmnd->fcpCntl3 = WRITE_DATA;
phba->fc4OutputRequests++;
@@ -5022,6 +5022,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
lpfc_release_scsi_buf(phba, lpfc_cmd);
return FAILED;
}
+ iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
"0702 Issue %s to TGT %d LUN %d "
@@ -5034,7 +5035,6 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
iocbq, iocbqrsp, lpfc_cmd->timeout);
if (status != IOCB_SUCCESS) {
if (status == IOCB_TIMEDOUT) {
- iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
ret = TIMEOUT_ERROR;
} else
ret = FAILED;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 43440ca16f4..0392e114531 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -6163,6 +6163,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
kfree(vpd);
goto out_free_mbox;
}
+
mqe = &mboxq->u.mqe;
phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev);
if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev))
@@ -6249,6 +6250,16 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow,
phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow);
+ /* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */
+ rc = (phba->sli4_hba.max_cfg_param.max_xri >> 3);
+ if (phba->pport->cfg_lun_queue_depth > rc) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "3362 LUN queue depth changed from %d to %d\n",
+ phba->pport->cfg_lun_queue_depth, rc);
+ phba->pport->cfg_lun_queue_depth = rc;
+ }
+
+
/*
* Discover the port's supported feature set and match it against the
* hosts requests.
@@ -9889,6 +9900,24 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
struct lpfc_scsi_buf *lpfc_cmd;
spin_lock_irqsave(&phba->hbalock, iflags);
+ if (cmdiocbq->iocb_flag & LPFC_IO_WAKE_TMO) {
+
+ /*
+ * A time out has occurred for the iocb. If a time out
+ * completion handler has been supplied, call it. Otherwise,
+ * just free the iocbq.
+ */
+
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ cmdiocbq->iocb_cmpl = cmdiocbq->wait_iocb_cmpl;
+ cmdiocbq->wait_iocb_cmpl = NULL;
+ if (cmdiocbq->iocb_cmpl)
+ (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, NULL);
+ else
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
+ return;
+ }
+
cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
if (cmdiocbq->context2 && rspiocbq)
memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
@@ -9944,10 +9973,16 @@ lpfc_chk_iocb_flg(struct lpfc_hba *phba,
* @timeout: Timeout in number of seconds.
*
* This function issues the iocb to firmware and waits for the
- * iocb to complete. If the iocb command is not
- * completed within timeout seconds, it returns IOCB_TIMEDOUT.
- * Caller should not free the iocb resources if this function
- * returns IOCB_TIMEDOUT.
+ * iocb to complete. The iocb_cmpl field of the shall be used
+ * to handle iocbs which time out. If the field is NULL, the
+ * function shall free the iocbq structure. If more clean up is
+ * needed, the caller is expected to provide a completion function
+ * that will provide the needed clean up. If the iocb command is
+ * not completed within timeout seconds, the function will either
+ * free the iocbq structure (if iocb_cmpl == NULL) or execute the
+ * completion function set in the iocb_cmpl field and then return
+ * a status of IOCB_TIMEDOUT. The caller should not free the iocb
+ * resources if this function returns IOCB_TIMEDOUT.
* The function waits for the iocb completion using an
* non-interruptible wait.
* This function will sleep while waiting for iocb completion.
@@ -9980,6 +10015,9 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
int txq_cnt = 0;
int txcmplq_cnt = 0;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ unsigned long iflags;
+ bool iocb_completed = true;
+
/*
* If the caller has provided a response iocbq buffer, then context2
* is NULL or its an error.
@@ -9990,9 +10028,10 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
piocb->context2 = prspiocbq;
}
+ piocb->wait_iocb_cmpl = piocb->iocb_cmpl;
piocb->iocb_cmpl = lpfc_sli_wake_iocb_wait;
piocb->context_un.wait_queue = &done_q;
- piocb->iocb_flag &= ~LPFC_IO_WAKE;
+ piocb->iocb_flag &= ~(LPFC_IO_WAKE | LPFC_IO_WAKE_TMO);
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
if (lpfc_readl(phba->HCregaddr, &creg_val))
@@ -10009,8 +10048,19 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
timeleft = wait_event_timeout(done_q,
lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE),
timeout_req);
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ if (!(piocb->iocb_flag & LPFC_IO_WAKE)) {
- if (piocb->iocb_flag & LPFC_IO_WAKE) {
+ /*
+ * IOCB timed out. Inform the wake iocb wait
+ * completion function and set local status
+ */
+
+ iocb_completed = false;
+ piocb->iocb_flag |= LPFC_IO_WAKE_TMO;
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (iocb_completed) {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"0331 IOCB wake signaled\n");
} else if (timeleft == 0) {
@@ -10122,7 +10172,6 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
*/
if (pmboxq->mbox_flag & LPFC_MBX_WAKE) {
retval = MBX_SUCCESS;
- lpfc_sli4_swap_str(phba, pmboxq);
} else {
retval = MBX_TIMEOUT;
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -12820,10 +12869,44 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
wq->page_count);
bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request,
cq->queue_id);
+
+ /* wqv is the earliest version supported, NOT the latest */
bf_set(lpfc_mbox_hdr_version, &shdr->request,
phba->sli4_hba.pc_sli4_params.wqv);
- if (phba->sli4_hba.pc_sli4_params.wqv == LPFC_Q_CREATE_VERSION_1) {
+ switch (phba->sli4_hba.pc_sli4_params.wqv) {
+ case LPFC_Q_CREATE_VERSION_0:
+ switch (wq->entry_size) {
+ default:
+ case 64:
+ /* Nothing to do, version 0 ONLY supports 64 byte */
+ page = wq_create->u.request.page;
+ break;
+ case 128:
+ if (!(phba->sli4_hba.pc_sli4_params.wqsize &
+ LPFC_WQ_SZ128_SUPPORT)) {
+ status = -ERANGE;
+ goto out;
+ }
+ /* If we get here the HBA MUST also support V1 and
+ * we MUST use it
+ */
+ bf_set(lpfc_mbox_hdr_version, &shdr->request,
+ LPFC_Q_CREATE_VERSION_1);
+
+ bf_set(lpfc_mbx_wq_create_wqe_count,
+ &wq_create->u.request_1, wq->entry_count);
+ bf_set(lpfc_mbx_wq_create_wqe_size,
+ &wq_create->u.request_1,
+ LPFC_WQ_WQE_SIZE_128);
+ bf_set(lpfc_mbx_wq_create_page_size,
+ &wq_create->u.request_1,
+ (PAGE_SIZE/SLI4_PAGE_SIZE));
+ page = wq_create->u.request_1.page;
+ break;
+ }
+ break;
+ case LPFC_Q_CREATE_VERSION_1:
bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1,
wq->entry_count);
switch (wq->entry_size) {
@@ -12834,6 +12917,11 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
LPFC_WQ_WQE_SIZE_64);
break;
case 128:
+ if (!(phba->sli4_hba.pc_sli4_params.wqsize &
+ LPFC_WQ_SZ128_SUPPORT)) {
+ status = -ERANGE;
+ goto out;
+ }
bf_set(lpfc_mbx_wq_create_wqe_size,
&wq_create->u.request_1,
LPFC_WQ_WQE_SIZE_128);
@@ -12842,9 +12930,12 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1,
(PAGE_SIZE/SLI4_PAGE_SIZE));
page = wq_create->u.request_1.page;
- } else {
- page = wq_create->u.request.page;
+ break;
+ default:
+ status = -ERANGE;
+ goto out;
}
+
list_for_each_entry(dmabuf, &wq->page_list, list) {
memset(dmabuf->virt, 0, hw_page_size);
page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys);
@@ -14665,14 +14756,20 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
first_iocbq->iocb.unsli3.rcvsli3.vpi =
vport->phba->vpi_ids[vport->vpi];
/* put the first buffer into the first IOCBq */
+ tot_len = bf_get(lpfc_rcqe_length,
+ &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+
first_iocbq->context2 = &seq_dmabuf->dbuf;
first_iocbq->context3 = NULL;
first_iocbq->iocb.ulpBdeCount = 1;
- first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
+ if (tot_len > LPFC_DATA_BUF_SIZE)
+ first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
+ else
+ first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = tot_len;
+
first_iocbq->iocb.un.rcvels.remoteID = sid;
- tot_len = bf_get(lpfc_rcqe_length,
- &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+
first_iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
}
iocbq = first_iocbq;
@@ -14688,14 +14785,17 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
if (!iocbq->context3) {
iocbq->context3 = d_buf;
iocbq->iocb.ulpBdeCount++;
- pbde = (struct ulp_bde64 *)
- &iocbq->iocb.unsli3.sli3Words[4];
- pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE;
-
/* We need to get the size out of the right CQE */
hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
len = bf_get(lpfc_rcqe_length,
&hbq_buf->cq_event.cqe.rcqe_cmpl);
+ pbde = (struct ulp_bde64 *)
+ &iocbq->iocb.unsli3.sli3Words[4];
+ if (len > LPFC_DATA_BUF_SIZE)
+ pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE;
+ else
+ pbde->tus.f.bdeSize = len;
+
iocbq->iocb.unsli3.rcvsli3.acc_len += len;
tot_len += len;
} else {
@@ -14710,16 +14810,19 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
lpfc_in_buf_free(vport->phba, d_buf);
continue;
}
+ /* We need to get the size out of the right CQE */
+ hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+ len = bf_get(lpfc_rcqe_length,
+ &hbq_buf->cq_event.cqe.rcqe_cmpl);
iocbq->context2 = d_buf;
iocbq->context3 = NULL;
iocbq->iocb.ulpBdeCount = 1;
- iocbq->iocb.un.cont64[0].tus.f.bdeSize =
+ if (len > LPFC_DATA_BUF_SIZE)
+ iocbq->iocb.un.cont64[0].tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
+ else
+ iocbq->iocb.un.cont64[0].tus.f.bdeSize = len;
- /* We need to get the size out of the right CQE */
- hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
- len = bf_get(lpfc_rcqe_length,
- &hbq_buf->cq_event.cqe.rcqe_cmpl);
tot_len += len;
iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 9d2e0c6fe33..97617996206 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2007 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2013 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -60,7 +60,8 @@ struct lpfc_iocbq {
uint8_t retry; /* retry counter for IOCB cmd - if needed */
uint16_t iocb_flag;
#define LPFC_IO_LIBDFC 1 /* libdfc iocb */
-#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */
+#define LPFC_IO_WAKE 2 /* Synchronous I/O completed */
+#define LPFC_IO_WAKE_TMO LPFC_IO_WAKE /* Synchronous I/O timed out */
#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */
#define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */
@@ -93,6 +94,8 @@ struct lpfc_iocbq {
void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *);
+ void (*wait_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
+ struct lpfc_iocbq *);
void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *);
};
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index d710b87a441..5bcc38223ac 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -117,6 +117,7 @@ union sli4_qe {
struct lpfc_rcqe_complete *rcqe_complete;
struct lpfc_mqe *mqe;
union lpfc_wqe *wqe;
+ union lpfc_wqe128 *wqe128;
struct lpfc_rqe *rqe;
};
@@ -325,12 +326,14 @@ struct lpfc_bmbx {
#define LPFC_EQE_SIZE_16B 16
#define LPFC_CQE_SIZE 16
#define LPFC_WQE_SIZE 64
+#define LPFC_WQE128_SIZE 128
#define LPFC_MQE_SIZE 256
#define LPFC_RQE_SIZE 8
#define LPFC_EQE_DEF_COUNT 1024
#define LPFC_CQE_DEF_COUNT 1024
#define LPFC_WQE_DEF_COUNT 256
+#define LPFC_WQE128_DEF_COUNT 128
#define LPFC_MQE_DEF_COUNT 16
#define LPFC_RQE_DEF_COUNT 512
@@ -416,6 +419,9 @@ struct lpfc_pc_sli4_params {
uint8_t mqv;
uint8_t wqv;
uint8_t rqv;
+ uint8_t wqsize;
+#define LPFC_WQ_SZ64_SUPPORT 1
+#define LPFC_WQ_SZ128_SUPPORT 2
};
struct lpfc_iov {
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index c6c32eebf3d..21859d2006c 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.40"
+#define LPFC_DRIVER_VERSION "8.3.41"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index e28e431564b..a87ee33f4f2 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2008 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2013 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -387,6 +387,9 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
/* Create binary sysfs attribute for vport */
lpfc_alloc_sysfs_attr(vport);
+ /* Set the DFT_LUN_Q_DEPTH accordingly */
+ vport->cfg_lun_queue_depth = phba->pport->cfg_lun_queue_depth;
+
*(struct lpfc_vport **)fc_vport->dd_data = vport;
vport->fc_vport = fc_vport;
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 0177295599e..1f0ca68409d 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -3547,11 +3547,21 @@ static int megasas_init_fw(struct megasas_instance *instance)
break;
}
- /*
- * We expect the FW state to be READY
- */
- if (megasas_transition_to_ready(instance, 0))
- goto fail_ready_state;
+ if (megasas_transition_to_ready(instance, 0)) {
+ atomic_set(&instance->fw_reset_no_pci_access, 1);
+ instance->instancet->adp_reset
+ (instance, instance->reg_set);
+ atomic_set(&instance->fw_reset_no_pci_access, 0);
+ dev_info(&instance->pdev->dev,
+ "megasas: FW restarted successfully from %s!\n",
+ __func__);
+
+ /*waitting for about 30 second before retry*/
+ ssleep(30);
+
+ if (megasas_transition_to_ready(instance, 0))
+ goto fail_ready_state;
+ }
/*
* MSI-X host index 0 is common for all adapter.
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index 31b5b15a472..7b14a015c90 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/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.27
+ * mpi2.h Version: 02.00.28
*
* Version History
* ---------------
@@ -77,6 +77,7 @@
* 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.
* --------------------------------------------------------------------------
*/
@@ -102,7 +103,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x1B)
+#define MPI2_HEADER_VERSION_UNIT (0x1C)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index 737fa8cfb54..88cb7f828bb 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/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.23
*
* Version History
* ---------------
@@ -149,6 +149,8 @@
* 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT.
* Added UEFIVersion field to BIOS Page 1 and defined new
* BiosOptions bits.
+ * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER.
+ * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID.
* --------------------------------------------------------------------------
*/
@@ -698,6 +700,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)
@@ -1224,6 +1227,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)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
index 963761fb846..9d284dae655 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt2sas/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/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index e93f8f53adf..d159c5f24aa 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_ioc.h
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
index 255b0ca219a..0d202a2c6db 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_raid.h
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
index fdffde1ebc0..50b39ccd526 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2010 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_sas.h
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
index 67c387f10e5..11b2ac4e7c6 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2012 LSI Corporation.
+ * Copyright (c) 2000-2013 LSI Corporation.
*
*
* Name: mpi2_tool.h
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/drivers/scsi/mpt2sas/mpi/mpi2_type.h
index cfde017bf16..0b128b68a5e 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_type.h
+++ b/drivers/scsi/mpt2sas/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/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index ccd6d5a97ec..3901edc3581 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -3,7 +3,7 @@
* for access to MPT (Message Passing Technology) firmware.
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2012 LSI Corporation
+ * Copyright (C) 2007-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -768,10 +768,9 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
* @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
+ * Returns void.
*/
-static u8
+static void
_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
{
Mpi2EventNotificationReply_t *mpi_reply;
@@ -780,9 +779,9 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (!mpi_reply)
- return 1;
+ return;
if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
- return 1;
+ return;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
_base_display_event_data(ioc, mpi_reply);
#endif
@@ -812,7 +811,7 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
/* ctl callback handler */
mpt2sas_ctl_event_callback(ioc, msix_index, reply);
- return 1;
+ return;
}
/**
@@ -1409,8 +1408,6 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
int i;
u8 try_msix = 0;
- INIT_LIST_HEAD(&ioc->reply_queue_list);
-
if (msix_disable == -1 || msix_disable == 0)
try_msix = 1;
@@ -1489,6 +1486,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
if (pci_enable_device_mem(pdev)) {
printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: "
"failed\n", ioc->name);
+ ioc->bars = 0;
return -ENODEV;
}
@@ -1497,6 +1495,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
MPT2SAS_DRIVER_NAME)) {
printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: "
"failed\n", ioc->name);
+ ioc->bars = 0;
r = -ENODEV;
goto out_fail;
}
@@ -4229,18 +4228,25 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
- _base_mask_interrupts(ioc);
- ioc->shost_recovery = 1;
- _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
- ioc->shost_recovery = 0;
+ if (ioc->chip_phys && ioc->chip) {
+ _base_mask_interrupts(ioc);
+ ioc->shost_recovery = 1;
+ _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+ ioc->shost_recovery = 0;
+ }
+
_base_free_irq(ioc);
_base_disable_msix(ioc);
- if (ioc->chip_phys)
+
+ if (ioc->chip_phys && ioc->chip)
iounmap(ioc->chip);
ioc->chip_phys = 0;
- pci_release_selected_regions(ioc->pdev, ioc->bars);
- pci_disable_pcie_error_reporting(pdev);
- pci_disable_device(pdev);
+
+ if (pci_is_enabled(pdev)) {
+ pci_release_selected_regions(ioc->pdev, ioc->bars);
+ pci_disable_pcie_error_reporting(pdev);
+ pci_disable_device(pdev);
+ }
return;
}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 6fbd0841777..1f2ac3a2862 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -3,7 +3,7 @@
* for access to MPT (Message Passing Technology) firmware.
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.h
- * Copyright (C) 2007-2012 LSI Corporation
+ * Copyright (C) 2007-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -69,8 +69,8 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "15.100.00.00"
-#define MPT2SAS_MAJOR_VERSION 15
+#define MPT2SAS_DRIVER_VERSION "16.100.00.00"
+#define MPT2SAS_MAJOR_VERSION 16
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 00
#define MPT2SAS_RELEASE_VERSION 00
@@ -1061,7 +1061,7 @@ void mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc);
/* scsih shared API */
-u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
u32 reply);
int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
uint channel, uint id, uint lun, u8 type, u16 smid_task,
@@ -1144,7 +1144,7 @@ void mpt2sas_ctl_exit(void);
u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply);
void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
-u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
u32 reply);
void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventNotificationReply_t *mpi_reply);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
index 863778071a9..0c47425c73f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_config.c
@@ -2,7 +2,7 @@
* This module provides common API for accessing firmware configuration pages
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2012 LSI Corporation
+ * Copyright (C) 2007-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index eec052c2670..b7f887c9b0b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -3,7 +3,7 @@
* controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
- * Copyright (C) 2007-2012 LSI Corporation
+ * Copyright (C) 2007-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -397,18 +397,22 @@ mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
* This function merely adds a new work task into ioc->firmware_event_thread.
* The tasks are worked from _firmware_event_work in user context.
*
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
+ * Returns void.
*/
-u8
+void
mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
u32 reply)
{
Mpi2EventNotificationReply_t *mpi_reply;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+ if (unlikely(!mpi_reply)) {
+ printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return;
+ }
mpt2sas_ctl_add_to_event_log(ioc, mpi_reply);
- return 1;
+ return;
}
/**
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
index b5eb0d1b8ea..8b2ac1869dc 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
@@ -3,7 +3,7 @@
* controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
- * Copyright (C) 2007-2012 LSI Corporation
+ * Copyright (C) 2007-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h
index 69cc7d0c112..a9021cbd662 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_debug.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h
@@ -2,7 +2,7 @@
* Logging Support for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
- * Copyright (C) 2007-2012 LSI Corporation
+ * Copyright (C) 2007-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 51004768d0f..7f0af4fcc00 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -2,7 +2,7 @@
* Scsi Host Layer for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
- * Copyright (C) 2007-2012 LSI Corporation
+ * Copyright (C) 2007-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -628,11 +628,12 @@ _scsih_sas_device_add(struct MPT2SAS_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) {
mpt2sas_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);
+ }
}
}
@@ -1402,6 +1403,7 @@ _scsih_slave_alloc(struct scsi_device *sdev)
struct MPT2SAS_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);
@@ -1430,6 +1432,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 = mpt2sas_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;
}
@@ -6753,7 +6768,7 @@ _scsih_search_responding_sas_devices(struct MPT2SAS_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);
@@ -6862,7 +6877,7 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_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);
@@ -6887,7 +6902,7 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_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);
@@ -6967,7 +6982,7 @@ _scsih_search_responding_expanders(struct MPT2SAS_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);
@@ -7109,8 +7124,6 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_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) {
printk(MPT2SAS_INFO_FMT "\tbreak from expander scan: "
"ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -7153,8 +7166,6 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_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) {
printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan:"
"ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -7219,8 +7230,6 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_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) {
printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: "
"ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -7278,8 +7287,6 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_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) {
printk(MPT2SAS_INFO_FMT "\tbreak from end device scan:"
" ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -7471,10 +7478,9 @@ _firmware_event_work(struct work_struct *work)
* This function merely adds a new work task into ioc->firmware_event_thread.
* The tasks are worked from _firmware_event_work in user context.
*
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
+ * Returns void.
*/
-u8
+void
mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
u32 reply)
{
@@ -7485,14 +7491,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
/* events turned off due to host reset or driver unloading */
if (ioc->remove_host || ioc->pci_error_recovery)
- return 1;
+ return;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (unlikely(!mpi_reply)) {
printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
- return 1;
+ return;
}
event = le16_to_cpu(mpi_reply->Event);
@@ -7507,11 +7513,11 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
if (baen_data->Primitive !=
MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
- return 1;
+ return;
if (ioc->broadcast_aen_busy) {
ioc->broadcast_aen_pending++;
- return 1;
+ return;
} else
ioc->broadcast_aen_busy = 1;
break;
@@ -7587,14 +7593,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
break;
default: /* ignore the rest */
- return 1;
+ return;
}
fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
if (!fw_event) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
- return 1;
+ return;
}
sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
fw_event->event_data = kzalloc(sz, GFP_ATOMIC);
@@ -7602,7 +7608,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
kfree(fw_event);
- return 1;
+ return;
}
memcpy(fw_event->event_data, mpi_reply->EventData,
@@ -7612,7 +7618,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
fw_event->VP_ID = mpi_reply->VP_ID;
fw_event->event = event;
_scsih_fw_event_add(ioc, fw_event);
- return 1;
+ return;
}
/* shost template */
@@ -7711,10 +7717,6 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
if (!ioc->ir_firmware)
return;
- /* are there any volumes ? */
- if (list_empty(&ioc->raid_device_list))
- return;
-
mutex_lock(&ioc->scsih_cmds.mutex);
if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
@@ -7929,10 +7931,12 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
sas_device->sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device);
} else if (!sas_device->starget) {
- if (!ioc->is_driver_loading)
- mpt2sas_transport_port_remove(ioc, sas_address,
+ if (!ioc->is_driver_loading) {
+ mpt2sas_transport_port_remove(ioc,
+ sas_address,
sas_address_parent);
- _scsih_sas_device_remove(ioc, sas_device);
+ _scsih_sas_device_remove(ioc, sas_device);
+ }
}
}
}
@@ -7985,14 +7989,14 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
kfree(sas_device);
continue;
} else if (!sas_device->starget) {
- if (!ioc->is_driver_loading)
+ if (!ioc->is_driver_loading) {
mpt2sas_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);
list_move_tail(&sas_device->list, &ioc->sas_device_list);
@@ -8175,6 +8179,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
INIT_LIST_HEAD(&ioc->delayed_tr_list);
INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
+ INIT_LIST_HEAD(&ioc->reply_queue_list);
/* init shost parameters */
shost->max_cmd_len = 32;
@@ -8280,6 +8285,7 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state)
mpt2sas_base_stop_watchdog(ioc);
scsi_block_requests(shost);
+ _scsih_ir_shutdown(ioc);
device_state = pci_choose_state(pdev, state);
printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
"operating state [D%d]\n", ioc->name, pdev,
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 193e7ae90c3..9d26637308b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -2,7 +2,7 @@
* SAS Transport Layer for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
- * Copyright (C) 2007-2012 LSI Corporation
+ * Copyright (C) 2007-2013 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -1006,9 +1006,12 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
&mpt2sas_phy->remote_identify);
_transport_add_phy_to_an_existing_port(ioc, sas_node,
mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address);
- } else
+ } else {
memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
sas_identify));
+ _transport_del_phy_from_an_existing_port(ioc, sas_node,
+ mpt2sas_phy);
+ }
if (mpt2sas_phy->phy)
mpt2sas_phy->phy->negotiated_linkrate =
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 5dc280c7532..fa785062e97 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -82,6 +82,10 @@ static int msix_disable = -1;
module_param(msix_disable, int, 0);
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
+static int max_msix_vectors = 8;
+module_param(max_msix_vectors, int, 0);
+MODULE_PARM_DESC(max_msix_vectors,
+ " max msix vectors - (default=8)");
static int mpt3sas_fwfault_debug;
MODULE_PARM_DESC(mpt3sas_fwfault_debug,
@@ -1709,8 +1713,6 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
int i;
u8 try_msix = 0;
- INIT_LIST_HEAD(&ioc->reply_queue_list);
-
if (msix_disable == -1 || msix_disable == 0)
try_msix = 1;
@@ -1723,6 +1725,16 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
ioc->reply_queue_count = min_t(int, ioc->cpu_count,
ioc->msix_vector_count);
+ printk(MPT3SAS_FMT "MSI-X vectors supported: %d, no of cores"
+ ": %d, max_msix_vectors: %d\n", ioc->name, ioc->msix_vector_count,
+ ioc->cpu_count, max_msix_vectors);
+
+ if (max_msix_vectors > 0) {
+ ioc->reply_queue_count = min_t(int, max_msix_vectors,
+ ioc->reply_queue_count);
+ ioc->msix_vector_count = ioc->reply_queue_count;
+ }
+
entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry),
GFP_KERNEL);
if (!entries) {
@@ -1790,6 +1802,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
if (pci_enable_device_mem(pdev)) {
pr_warn(MPT3SAS_FMT "pci_enable_device_mem: failed\n",
ioc->name);
+ ioc->bars = 0;
return -ENODEV;
}
@@ -1798,6 +1811,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
MPT3SAS_DRIVER_NAME)) {
pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n",
ioc->name);
+ ioc->bars = 0;
r = -ENODEV;
goto out_fail;
}
@@ -4393,18 +4407,25 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
__func__));
- _base_mask_interrupts(ioc);
- ioc->shost_recovery = 1;
- _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
- ioc->shost_recovery = 0;
+ if (ioc->chip_phys && ioc->chip) {
+ _base_mask_interrupts(ioc);
+ ioc->shost_recovery = 1;
+ _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+ ioc->shost_recovery = 0;
+ }
+
_base_free_irq(ioc);
_base_disable_msix(ioc);
- if (ioc->chip_phys)
+
+ if (ioc->chip_phys && ioc->chip)
iounmap(ioc->chip);
ioc->chip_phys = 0;
- pci_release_selected_regions(ioc->pdev, ioc->bars);
- pci_disable_pcie_error_reporting(pdev);
- pci_disable_device(pdev);
+
+ if (pci_is_enabled(pdev)) {
+ pci_release_selected_regions(ioc->pdev, ioc->bars);
+ pci_disable_pcie_error_reporting(pdev);
+ pci_disable_device(pdev);
+ }
return;
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 8cbe8fd21fc..a961fe11b52 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -7779,6 +7779,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
INIT_LIST_HEAD(&ioc->delayed_tr_list);
INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
+ INIT_LIST_HEAD(&ioc->reply_queue_list);
/* init shost parameters */
shost->max_cmd_len = 32;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index dcadd56860f..e771a88c6a7 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -1003,9 +1003,12 @@ mpt3sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc,
&mpt3sas_phy->remote_identify);
_transport_add_phy_to_an_existing_port(ioc, sas_node,
mpt3sas_phy, mpt3sas_phy->remote_identify.sas_address);
- } else
+ } else {
memset(&mpt3sas_phy->remote_identify, 0 , sizeof(struct
sas_identify));
+ _transport_del_phy_from_an_existing_port(ioc, sas_node,
+ mpt3sas_phy);
+ }
if (mpt3sas_phy->phy)
mpt3sas_phy->phy->negotiated_linkrate =
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index f14665a6293..6b1b4e91e53 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -1857,11 +1857,16 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
goto out;
}
- /* error info record present */
- if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
+ /*
+ * error info record present; slot->response is 32 bit aligned but may
+ * not be 64 bit aligned, so check for zero in two 32 bit reads
+ */
+ if (unlikely((rx_desc & RXQ_ERR)
+ && (*((u32 *)slot->response)
+ || *(((u32 *)slot->response) + 1)))) {
mv_dprintk("port %d slot %d rx_desc %X has error info"
"%016llX.\n", slot->port->sas_port.id, slot_idx,
- rx_desc, (u64)(*(u64 *)slot->response));
+ rx_desc, get_unaligned_le64(slot->response));
tstat->stat = mvs_slot_err(mvi, task, slot_idx);
tstat->resp = SAS_TASK_COMPLETE;
goto out;
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index 60e2fb7f2dc..d6b19dc80be 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -39,6 +39,7 @@
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <asm/unaligned.h>
#include <scsi/libsas.h>
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index 9d86947d67f..e1d9a4c4c4b 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -107,6 +107,7 @@ static ssize_t osdname_show(struct device *dev, struct device_attribute *attr,
class_dev);
return sprintf(buf, "%s\n", ould->odi.osdname);
}
+static DEVICE_ATTR_RO(osdname);
static ssize_t systemid_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -117,17 +118,19 @@ static ssize_t systemid_show(struct device *dev, struct device_attribute *attr,
memcpy(buf, ould->odi.systemid, ould->odi.systemid_len);
return ould->odi.systemid_len;
}
+static DEVICE_ATTR_RO(systemid);
-static struct device_attribute osd_uld_attrs[] = {
- __ATTR(osdname, S_IRUGO, osdname_show, NULL),
- __ATTR(systemid, S_IRUGO, systemid_show, NULL),
- __ATTR_NULL,
+static struct attribute *osd_uld_attrs[] = {
+ &dev_attr_osdname.attr,
+ &dev_attr_systemid.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(osd_uld);
static struct class osd_uld_class = {
.owner = THIS_MODULE,
.name = "scsi_osd",
- .dev_attrs = osd_uld_attrs,
+ .dev_groups = osd_uld_groups,
};
/*
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 5456f5c7359..4a219575219 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -221,7 +221,7 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_interrupt = 0x01;
for (i = 0; i < PM8001_MAX_INB_NUM; i++) {
pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt =
- PM8001_MPI_QUEUE | (64 << 16) | (0x00<<30);
+ PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x00<<30);
pm8001_ha->inbnd_q_tbl[i].upper_base_addr =
pm8001_ha->memoryMap.region[IB + i].phys_addr_hi;
pm8001_ha->inbnd_q_tbl[i].lower_base_addr =
@@ -247,7 +247,7 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
}
for (i = 0; i < PM8001_MAX_OUTB_NUM; i++) {
pm8001_ha->outbnd_q_tbl[i].element_size_cnt =
- PM8001_MPI_QUEUE | (64 << 16) | (0x01<<30);
+ PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x01<<30);
pm8001_ha->outbnd_q_tbl[i].upper_base_addr =
pm8001_ha->memoryMap.region[OB + i].phys_addr_hi;
pm8001_ha->outbnd_q_tbl[i].lower_base_addr =
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 3861aa1f452..f7c189606b8 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -424,7 +424,8 @@ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha)
PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
"base addr %llx virt_addr=%llx len=%d\n",
(u64)pm8001_ha->io_mem[logicalBar].membase,
- (u64)pm8001_ha->io_mem[logicalBar].memvirtaddr,
+ (u64)(unsigned long)
+ pm8001_ha->io_mem[logicalBar].memvirtaddr,
pm8001_ha->io_mem[logicalBar].memsize));
} else {
pm8001_ha->io_mem[logicalBar].membase = 0;
@@ -734,7 +735,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
pdev = pm8001_ha->pdev;
#ifdef PM8001_USE_MSIX
- if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
+ if (pdev->msix_cap)
return pm8001_setup_msix(pm8001_ha);
else {
PM8001_INIT_DBG(pm8001_ha,
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 7f77210f5cf..9f91030211e 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -275,7 +275,7 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
for (i = 0; i < PM8001_MAX_SPCV_INB_NUM; i++) {
pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt =
- PM8001_MPI_QUEUE | (64 << 16) | (0x00<<30);
+ PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x00<<30);
pm8001_ha->inbnd_q_tbl[i].upper_base_addr =
pm8001_ha->memoryMap.region[IB + i].phys_addr_hi;
pm8001_ha->inbnd_q_tbl[i].lower_base_addr =
@@ -301,7 +301,7 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
}
for (i = 0; i < PM8001_MAX_SPCV_OUTB_NUM; i++) {
pm8001_ha->outbnd_q_tbl[i].element_size_cnt =
- PM8001_MPI_QUEUE | (64 << 16) | (0x01<<30);
+ PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x01<<30);
pm8001_ha->outbnd_q_tbl[i].upper_base_addr =
pm8001_ha->memoryMap.region[OB + i].phys_addr_hi;
pm8001_ha->outbnd_q_tbl[i].lower_base_addr =
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index c37b244cf8a..ff0fc7c7812 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,6 +1,6 @@
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \
- qla_nx.o qla_mr.o qla_target.o
+ qla_nx.o qla_mr.o qla_nx2.o qla_target.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
obj-$(CONFIG_TCM_QLA2XXX) += tcm_qla2xxx.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index d7a99ae7f39..5f174b83f56 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -29,7 +29,7 @@ qla2x00_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj,
if (!(ha->fw_dump_reading || ha->mctp_dump_reading))
return 0;
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
if (off < ha->md_template_size) {
rval = memory_read_from_buffer(buf, count,
&off, ha->md_tmplt_hdr, ha->md_template_size);
@@ -71,7 +71,7 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
ql_log(ql_log_info, vha, 0x705d,
"Firmware dump cleared on (%ld).\n", vha->host_no);
- if (IS_QLA82XX(vha->hw)) {
+ if (IS_P3P_TYPE(ha)) {
qla82xx_md_free(vha);
qla82xx_md_prep(vha);
}
@@ -95,11 +95,15 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
qla82xx_idc_lock(ha);
qla82xx_set_reset_owner(vha);
qla82xx_idc_unlock(ha);
+ } else if (IS_QLA8044(ha)) {
+ qla8044_idc_lock(ha);
+ qla82xx_set_reset_owner(vha);
+ qla8044_idc_unlock(ha);
} else
qla2x00_system_error(vha);
break;
case 4:
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
if (ha->md_tmplt_hdr)
ql_dbg(ql_dbg_user, vha, 0x705b,
"MiniDump supported with this firmware.\n");
@@ -109,7 +113,7 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
}
break;
case 5:
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
break;
case 6:
@@ -586,7 +590,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
int type;
uint32_t idc_control;
-
+ uint8_t *tmp_data = NULL;
if (off != 0)
return -EINVAL;
@@ -597,14 +601,23 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
"Issuing ISP reset.\n");
scsi_block_requests(vha->host);
- set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
if (IS_QLA82XX(ha)) {
ha->flags.isp82xx_no_md_cap = 1;
qla82xx_idc_lock(ha);
qla82xx_set_reset_owner(vha);
qla82xx_idc_unlock(ha);
+ } else if (IS_QLA8044(ha)) {
+ qla8044_idc_lock(ha);
+ idc_control = qla8044_rd_reg(ha,
+ QLA8044_IDC_DRV_CTRL);
+ qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL,
+ (idc_control | GRACEFUL_RESET_BIT1));
+ qla82xx_set_reset_owner(vha);
+ qla8044_idc_unlock(ha);
+ } else {
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
}
- qla2xxx_wake_dpc(vha);
qla2x00_wait_for_chip_reset(vha);
scsi_unblock_requests(vha->host);
break;
@@ -640,7 +653,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
break;
}
case 0x2025e:
- if (!IS_QLA82XX(ha) || vha != base_vha) {
+ if (!IS_P3P_TYPE(ha) || vha != base_vha) {
ql_log(ql_log_info, vha, 0x7071,
"FCoE ctx reset no supported.\n");
return -EPERM;
@@ -674,7 +687,19 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
__qla83xx_set_idc_control(vha, idc_control);
qla83xx_idc_unlock(vha, 0);
break;
-
+ case 0x20261:
+ ql_dbg(ql_dbg_user, vha, 0x70e0,
+ "Updating cache versions without reset ");
+
+ tmp_data = vmalloc(256);
+ if (!tmp_data) {
+ ql_log(ql_log_warn, vha, 0x70e1,
+ "Unable to allocate memory for VPD information update.\n");
+ return -ENOMEM;
+ }
+ ha->isp_ops->get_flash_version(vha, tmp_data);
+ vfree(tmp_data);
+ break;
}
return count;
}
@@ -1212,7 +1237,7 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
+ if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
return snprintf(buf, PAGE_SIZE, "\n");
return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
@@ -1265,10 +1290,7 @@ qla2x00_vn_port_mac_address_show(struct device *dev,
if (!IS_CNA_CAPABLE(vha->hw))
return snprintf(buf, PAGE_SIZE, "\n");
- return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
- vha->fcoe_vn_port_mac[5], vha->fcoe_vn_port_mac[4],
- vha->fcoe_vn_port_mac[3], vha->fcoe_vn_port_mac[2],
- vha->fcoe_vn_port_mac[1], vha->fcoe_vn_port_mac[0]);
+ return snprintf(buf, PAGE_SIZE, "%pMR\n", vha->fcoe_vn_port_mac);
}
static ssize_t
@@ -1287,12 +1309,6 @@ qla2x00_thermal_temp_show(struct device *dev,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
uint16_t temp = 0;
- if (!vha->hw->thermal_support) {
- ql_log(ql_log_warn, vha, 0x70db,
- "Thermal not supported by this card.\n");
- goto done;
- }
-
if (qla2x00_reset_active(vha)) {
ql_log(ql_log_warn, vha, 0x70dc, "ISP reset active.\n");
goto done;
@@ -1725,11 +1741,21 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
pfc_host_stat->lip_count = stats->lip_cnt;
pfc_host_stat->tx_frames = stats->tx_frames;
pfc_host_stat->rx_frames = stats->rx_frames;
- pfc_host_stat->dumped_frames = stats->dumped_frames;
+ pfc_host_stat->dumped_frames = stats->discarded_frames;
pfc_host_stat->nos_count = stats->nos_rcvd;
+ pfc_host_stat->error_frames =
+ stats->dropped_frames + stats->discarded_frames;
+ pfc_host_stat->rx_words = vha->qla_stats.input_bytes;
+ pfc_host_stat->tx_words = vha->qla_stats.output_bytes;
}
+ pfc_host_stat->fcp_control_requests = vha->qla_stats.control_requests;
+ pfc_host_stat->fcp_input_requests = vha->qla_stats.input_requests;
+ pfc_host_stat->fcp_output_requests = vha->qla_stats.output_requests;
pfc_host_stat->fcp_input_megabytes = vha->qla_stats.input_bytes >> 20;
pfc_host_stat->fcp_output_megabytes = vha->qla_stats.output_bytes >> 20;
+ pfc_host_stat->seconds_since_last_reset =
+ get_jiffies_64() - vha->qla_stats.jiffies_at_last_reset;
+ do_div(pfc_host_stat->seconds_since_last_reset, HZ);
done_free:
dma_pool_free(ha->s_dma_pool, stats, stats_dma);
@@ -1738,6 +1764,16 @@ done:
}
static void
+qla2x00_reset_host_stats(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *vha = shost_priv(shost);
+
+ memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
+
+ vha->qla_stats.jiffies_at_last_reset = get_jiffies_64();
+}
+
+static void
qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
{
scsi_qla_host_t *vha = shost_priv(shost);
@@ -2043,6 +2079,7 @@ struct fc_function_template qla2xxx_transport_functions = {
.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
.terminate_rport_io = qla2x00_terminate_rport_io,
.get_fc_host_stats = qla2x00_get_fc_host_stats,
+ .reset_fc_host_stats = qla2x00_reset_host_stats,
.vport_create = qla24xx_vport_create,
.vport_disable = qla24xx_vport_disable,
@@ -2089,6 +2126,8 @@ struct fc_function_template qla2xxx_transport_vport_functions = {
.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
.terminate_rport_io = qla2x00_terminate_rport_io,
.get_fc_host_stats = qla2x00_get_fc_host_stats,
+ .reset_fc_host_stats = qla2x00_reset_host_stats,
+
.bsg_request = qla24xx_bsg_request,
.bsg_timeout = qla24xx_bsg_timeout,
};
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 417eaad50ae..b989add77ec 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -125,7 +125,7 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
uint32_t len;
uint32_t oper;
- if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA82XX(ha))) {
+ if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_P3P_TYPE(ha))) {
ret = -EINVAL;
goto exit_fcp_prio_cfg;
}
@@ -559,7 +559,7 @@ qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
uint16_t new_config[4];
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
+ if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
goto done_reset_internal;
memset(new_config, 0 , sizeof(new_config));
@@ -627,9 +627,10 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
{
int ret = 0;
int rval = 0;
+ unsigned long rem_tmo = 0, current_tmo = 0;
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
+ if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
goto done_set_internal;
if (mode == INTERNAL_LOOPBACK)
@@ -652,8 +653,19 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
}
/* Wait for DCBX complete event */
- if (!wait_for_completion_timeout(&ha->dcbx_comp,
- (DCBX_COMP_TIMEOUT * HZ))) {
+ current_tmo = DCBX_COMP_TIMEOUT * HZ;
+ while (1) {
+ rem_tmo = wait_for_completion_timeout(&ha->dcbx_comp,
+ current_tmo);
+ if (!ha->idc_extend_tmo || rem_tmo) {
+ ha->idc_extend_tmo = 0;
+ break;
+ }
+ current_tmo = ha->idc_extend_tmo * HZ;
+ ha->idc_extend_tmo = 0;
+ }
+
+ if (!rem_tmo) {
ql_dbg(ql_dbg_user, vha, 0x7022,
"DCBX completion not received.\n");
ret = qla81xx_reset_loopback_mode(vha, new_config, 0, 0);
@@ -678,6 +690,7 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
}
ha->notify_dcbx_comp = 0;
+ ha->idc_extend_tmo = 0;
done_set_internal:
return rval;
@@ -773,7 +786,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
if (atomic_read(&vha->loop_state) == LOOP_READY &&
(ha->current_topology == ISP_CFG_F ||
- ((IS_QLA81XX(ha) || IS_QLA8031(ha)) &&
+ ((IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) &&
le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
&& req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
elreq.options == EXTERNAL_LOOPBACK) {
@@ -783,7 +796,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
command_sent = INT_DEF_LB_ECHO_CMD;
rval = qla2x00_echo_test(vha, &elreq, response);
} else {
- if (IS_QLA81XX(ha) || IS_QLA8031(ha)) {
+ if (IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) {
memset(config, 0, sizeof(config));
memset(new_config, 0, sizeof(new_config));
@@ -806,7 +819,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
"elreq.options=%04x\n", elreq.options);
if (elreq.options == EXTERNAL_LOOPBACK)
- if (IS_QLA8031(ha))
+ if (IS_QLA8031(ha) || IS_QLA8044(ha))
rval = qla81xx_set_loopback_mode(vha,
config, new_config, elreq.options);
else
@@ -1266,6 +1279,7 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
int rval = 0;
struct qla_port_param *port_param = NULL;
fc_port_t *fcport = NULL;
+ int found = 0;
uint16_t mb[MAILBOX_REGISTER_COUNT];
uint8_t *rsp_ptr = NULL;
@@ -1288,10 +1302,12 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn,
fcport->port_name, sizeof(fcport->port_name)))
continue;
+
+ found = 1;
break;
}
- if (!fcport) {
+ if (!found) {
ql_log(ql_log_warn, vha, 0x7049,
"Failed to find port.\n");
return -EINVAL;
@@ -1318,12 +1334,9 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
if (rval) {
ql_log(ql_log_warn, vha, 0x704c,
- "iIDMA cmd failed for %02x%02x%02x%02x%02x%02x%02x%02x -- "
- "%04x %x %04x %04x.\n", fcport->port_name[0],
- fcport->port_name[1], fcport->port_name[2],
- fcport->port_name[3], fcport->port_name[4],
- fcport->port_name[5], fcport->port_name[6],
- fcport->port_name[7], rval, fcport->fp_speed, mb[0], mb[1]);
+ "iIDMA cmd failed for %8phN -- "
+ "%04x %x %04x %04x.\n", fcport->port_name,
+ rval, fcport->fp_speed, mb[0], mb[1]);
rval = (DID_ERROR << 16);
} else {
if (!port_param->mode) {
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index df132fec6d8..2ef497ebadc 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,9 +11,12 @@
* ----------------------------------------------------------------------
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
- * | Module Init and Probe | 0x014f | 0x4b,0xba,0xfa |
- * | Mailbox commands | 0x117a | 0x111a-0x111b |
+ * | Module Init and Probe | 0x0159 | 0x4b,0xba,0xfa |
+ * | Mailbox commands | 0x1181 | 0x111a-0x111b |
* | | | 0x1155-0x1158 |
+ * | | | 0x1018-0x1019 |
+ * | | | 0x1115-0x1116 |
+ * | | | 0x10ca |
* | Device Discovery | 0x2095 | 0x2020-0x2022, |
* | | | 0x2011-0x2012, |
* | | | 0x2016 |
@@ -24,11 +27,12 @@
* | | | 0x3036,0x3038 |
* | | | 0x303a |
* | DPC Thread | 0x4022 | 0x4002,0x4013 |
- * | Async Events | 0x5081 | 0x502b-0x502f |
+ * | Async Events | 0x5087 | 0x502b-0x502f |
* | | | 0x5047,0x5052 |
- * | | | 0x5040,0x5075 |
- * | Timer Routines | 0x6011 | |
- * | User Space Interactions | 0x70dd | 0x7018,0x702e, |
+ * | | | 0x5084,0x5075 |
+ * | | | 0x503d,0x5044 |
+ * | Timer Routines | 0x6012 | |
+ * | User Space Interactions | 0x70e1 | 0x7018,0x702e, |
* | | | 0x7020,0x7024, |
* | | | 0x7039,0x7045, |
* | | | 0x7073-0x7075, |
@@ -36,17 +40,28 @@
* | | | 0x70a5,0x70a6, |
* | | | 0x70a8,0x70ab, |
* | | | 0x70ad-0x70ae, |
- * | | | 0x70d1-0x70da, |
+ * | | | 0x70d1-0x70db, |
* | | | 0x7047,0x703b |
- * | Task Management | 0x803c | 0x8025-0x8026 |
+ * | | | 0x70de-0x70df, |
+ * | Task Management | 0x803d | 0x8025-0x8026 |
* | | | 0x800b,0x8039 |
* | AER/EEH | 0x9011 | |
* | Virtual Port | 0xa007 | |
- * | ISP82XX Specific | 0xb086 | 0xb002,0xb024 |
+ * | ISP82XX Specific | 0xb14c | 0xb002,0xb024 |
+ * | | | 0xb09e,0xb0ae |
+ * | | | 0xb0e0-0xb0ef |
+ * | | | 0xb085,0xb0dc |
+ * | | | 0xb107,0xb108 |
+ * | | | 0xb111,0xb11e |
+ * | | | 0xb12c,0xb12d |
+ * | | | 0xb13a,0xb142 |
+ * | | | 0xb13c-0xb140 |
+ * | | | 0xb149 |
* | MultiQ | 0xc00c | |
* | Misc | 0xd010 | |
- * | Target Mode | 0xe070 | |
- * | Target Mode Management | 0xf072 | |
+ * | Target Mode | 0xe070 | 0xe021 |
+ * | Target Mode Management | 0xf072 | 0xf002-0xf003 |
+ * | | | 0xf046-0xf049 |
* | Target Mode Task Management | 0x1000b | |
* ----------------------------------------------------------------------
*/
@@ -519,7 +534,7 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
uint32_t cnt, que_idx;
uint8_t que_cnt;
struct qla2xxx_mq_chain *mq = ptr;
- struct device_reg_25xxmq __iomem *reg;
+ device_reg_t __iomem *reg;
if (!ha->mqenable || IS_QLA83XX(ha))
return ptr;
@@ -533,13 +548,16 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
ha->max_req_queues : ha->max_rsp_queues;
mq->count = htonl(que_cnt);
for (cnt = 0; cnt < que_cnt; cnt++) {
- reg = (struct device_reg_25xxmq __iomem *)
- (ha->mqiobase + cnt * QLA_QUE_PAGE);
+ reg = ISP_QUE_REG(ha, cnt);
que_idx = cnt * 4;
- mq->qregs[que_idx] = htonl(RD_REG_DWORD(&reg->req_q_in));
- mq->qregs[que_idx+1] = htonl(RD_REG_DWORD(&reg->req_q_out));
- mq->qregs[que_idx+2] = htonl(RD_REG_DWORD(&reg->rsp_q_in));
- mq->qregs[que_idx+3] = htonl(RD_REG_DWORD(&reg->rsp_q_out));
+ mq->qregs[que_idx] =
+ htonl(RD_REG_DWORD(&reg->isp25mq.req_q_in));
+ mq->qregs[que_idx+1] =
+ htonl(RD_REG_DWORD(&reg->isp25mq.req_q_out));
+ mq->qregs[que_idx+2] =
+ htonl(RD_REG_DWORD(&reg->isp25mq.rsp_q_in));
+ mq->qregs[que_idx+3] =
+ htonl(RD_REG_DWORD(&reg->isp25mq.rsp_q_out));
}
return ptr + sizeof(struct qla2xxx_mq_chain);
@@ -941,7 +959,7 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
uint32_t *last_chain = NULL;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
return;
risc_address = ext_mem_cnt = 0;
@@ -2530,7 +2548,7 @@ ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id)
if (!ql_mask_match(level))
return;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
mbx_reg = &reg82->mailbox_in[0];
else if (IS_FWI2_CAPABLE(ha))
mbx_reg = &reg24->mailbox0;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 95ca32a71e7..93db74ef346 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -35,6 +35,7 @@
#include "qla_bsg.h"
#include "qla_nx.h"
+#include "qla_nx2.h"
#define QLA2XXX_DRIVER_NAME "qla2xxx"
#define QLA2XXX_APIDEV "ql2xapidev"
#define QLA2XXX_MANUFACTURER "QLogic Corporation"
@@ -642,6 +643,7 @@ struct device_reg_fx00 {
uint32_t initval6; /* C8 */
uint32_t initval7; /* CC */
uint32_t fwheartbeat; /* D0 */
+ uint32_t pseudoaen; /* D4 */
};
@@ -805,6 +807,7 @@ struct mbx_cmd_32 {
#define MBA_MIRROR_LUN_CHANGE 0x8402 /* Mirror LUN State Change
Notification */
#define MBA_FW_POLL_STATE 0x8600 /* Firmware in poll diagnostic state */
+#define MBA_FW_RESET_FCT 0x8502 /* Firmware reset factory defaults */
/* 83XX FCoE specific */
#define MBA_IDC_AEN 0x8200 /* FCoE: NIC Core state change AEN */
@@ -997,6 +1000,7 @@ struct mbx_cmd_32 {
#define MBX_1 BIT_1
#define MBX_0 BIT_0
+#define RNID_TYPE_SET_VERSION 0x9
#define RNID_TYPE_ASIC_TEMP 0xC
/*
@@ -1233,8 +1237,9 @@ struct link_statistics {
uint32_t unused1[0x1a];
uint32_t tx_frames;
uint32_t rx_frames;
- uint32_t dumped_frames;
- uint32_t unused2[2];
+ uint32_t discarded_frames;
+ uint32_t dropped_frames;
+ uint32_t unused2[1];
uint32_t nos_rcvd;
};
@@ -2656,6 +2661,11 @@ struct qla_statistics {
uint32_t total_isp_aborts;
uint64_t input_bytes;
uint64_t output_bytes;
+ uint64_t input_requests;
+ uint64_t output_requests;
+ uint32_t control_requests;
+
+ uint64_t jiffies_at_last_reset;
};
struct bidi_statistics {
@@ -2670,9 +2680,8 @@ struct bidi_statistics {
#define QLA_MAX_QUEUES 256
#define ISP_QUE_REG(ha, id) \
((ha->mqenable || IS_QLA83XX(ha)) ? \
- ((device_reg_t __iomem *)(ha->mqiobase) +\
- (QLA_QUE_PAGE * id)) :\
- ((device_reg_t __iomem *)(ha->iobase)))
+ ((void __iomem *)ha->mqiobase + (QLA_QUE_PAGE * id)) :\
+ ((void __iomem *)ha->iobase))
#define QLA_REQ_QUE_ID(tag) \
((tag < QLA_MAX_QUEUES && tag > 0) ? tag : 0)
#define QLA_DEFAULT_QUE_QOS 5
@@ -2935,7 +2944,8 @@ struct qla_hw_data {
#define DT_ISP2031 BIT_15
#define DT_ISP8031 BIT_16
#define DT_ISPFX00 BIT_17
-#define DT_ISP_LAST (DT_ISPFX00 << 1)
+#define DT_ISP8044 BIT_18
+#define DT_ISP_LAST (DT_ISP8044 << 1)
#define DT_T10_PI BIT_25
#define DT_IIDMA BIT_26
@@ -2961,6 +2971,7 @@ struct qla_hw_data {
#define IS_QLA8001(ha) (DT_MASK(ha) & DT_ISP8001)
#define IS_QLA81XX(ha) (IS_QLA8001(ha))
#define IS_QLA82XX(ha) (DT_MASK(ha) & DT_ISP8021)
+#define IS_QLA8044(ha) (DT_MASK(ha) & DT_ISP8044)
#define IS_QLA2031(ha) (DT_MASK(ha) & DT_ISP2031)
#define IS_QLA8031(ha) (DT_MASK(ha) & DT_ISP8031)
#define IS_QLAFX00(ha) (DT_MASK(ha) & DT_ISPFX00)
@@ -2975,10 +2986,12 @@ struct qla_hw_data {
#define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
IS_QLA84XX(ha))
#define IS_CNA_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA82XX(ha) || \
- IS_QLA8031(ha))
+ IS_QLA8031(ha) || IS_QLA8044(ha))
+#define IS_P3P_TYPE(ha) (IS_QLA82XX(ha) || IS_QLA8044(ha))
#define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \
IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
- IS_QLA82XX(ha) || IS_QLA83XX(ha))
+ IS_QLA82XX(ha) || IS_QLA83XX(ha) || \
+ IS_QLA8044(ha))
#define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
#define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
IS_QLA83XX(ha)) && (ha)->flags.msix_enabled)
@@ -3187,10 +3200,12 @@ struct qla_hw_data {
uint32_t nvram_data_off;
uint32_t fdt_wrt_disable;
+ uint32_t fdt_wrt_enable;
uint32_t fdt_erase_cmd;
uint32_t fdt_block_size;
uint32_t fdt_unprotect_sec_cmd;
uint32_t fdt_protect_sec_cmd;
+ uint32_t fdt_wrt_sts_reg_cmd;
uint32_t flt_region_flt;
uint32_t flt_region_fdt;
@@ -3277,6 +3292,7 @@ struct qla_hw_data {
/* QLA83XX IDC specific fields */
uint32_t idc_audit_ts;
+ uint32_t idc_extend_tmo;
/* DPC low-priority workqueue */
struct workqueue_struct *dpc_lp_wq;
@@ -3296,9 +3312,6 @@ struct qla_hw_data {
struct mr_data_fx00 mr;
struct qlt_hw_data tgt;
- uint16_t thermal_support;
-#define THERMAL_SUPPORT_I2C BIT_0
-#define THERMAL_SUPPORT_ISP BIT_1
};
/*
@@ -3364,6 +3377,7 @@ typedef struct scsi_qla_host {
#define PORT_UPDATE_NEEDED 24
#define FX00_RESET_RECOVERY 25
#define FX00_TARGET_SCAN 26
+#define FX00_CRITEMP_RECOVERY 27
uint32_t device_flags;
#define SWITCH_FOUND BIT_0
@@ -3402,7 +3416,7 @@ typedef struct scsi_qla_host {
uint16_t fcoe_fcf_idx;
uint8_t fcoe_vn_port_mac[6];
- uint32_t vp_abort_cnt;
+ uint32_t vp_abort_cnt;
struct fc_vport *fc_vport; /* holds fc_vport * for each vport */
uint16_t vp_idx; /* vport ID */
@@ -3435,6 +3449,7 @@ typedef struct scsi_qla_host {
struct bidi_statistics bidi_stats;
atomic_t vref_count;
+ struct qla8044_reset_template reset_tmplt;
} scsi_qla_host_t;
#define SET_VP_IDX 1
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 1ac2b0e3a0e..610d3aa905a 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1387,6 +1387,8 @@ struct qla_flt_header {
#define FLT_REG_GOLD_FW 0x2f
#define FLT_REG_FCP_PRIO_0 0x87
#define FLT_REG_FCP_PRIO_1 0x88
+#define FLT_REG_CNA_FW 0x97
+#define FLT_REG_BOOT_CODE_8044 0xA2
#define FLT_REG_FCOE_FW 0xA4
#define FLT_REG_FCOE_NVRAM_0 0xAA
#define FLT_REG_FCOE_NVRAM_1 0xAC
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 2d98232a08e..4446bf5fe29 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -357,6 +357,12 @@ extern int
qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *);
extern int
+qla82xx_set_driver_version(scsi_qla_host_t *, char *);
+
+extern int
+qla25xx_set_driver_version(scsi_qla_host_t *, char *);
+
+extern int
qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *,
uint16_t, uint16_t, uint16_t, uint16_t);
@@ -435,19 +441,19 @@ qla2x00_process_completed_request(struct scsi_qla_host *, struct req_que *,
*/
extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
- uint32_t, uint32_t);
+ uint32_t, uint32_t);
extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
+ uint32_t);
extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
+ uint32_t);
extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
+ uint32_t);
extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
+ uint32_t);
extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
+ uint32_t);
extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
+ uint32_t);
extern int qla2x00_is_a_vp_did(scsi_qla_host_t *, uint32_t);
extern int qla2x00_beacon_on(struct scsi_qla_host *);
@@ -463,21 +469,25 @@ extern int qla83xx_wr_reg(scsi_qla_host_t *, uint32_t, uint32_t);
extern int qla83xx_rd_reg(scsi_qla_host_t *, uint32_t, uint32_t *);
extern int qla83xx_restart_nic_firmware(scsi_qla_host_t *);
extern int qla83xx_access_control(scsi_qla_host_t *, uint16_t, uint32_t,
- uint32_t, uint16_t *);
+ uint32_t, uint16_t *);
extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *,
- uint32_t, uint32_t);
+ uint32_t, uint32_t);
extern int qla2x00_write_optrom_data(struct scsi_qla_host *, uint8_t *,
- uint32_t, uint32_t);
+ uint32_t, uint32_t);
extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
- uint32_t, uint32_t);
+ uint32_t, uint32_t);
extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
- uint32_t, uint32_t);
+ uint32_t, uint32_t);
extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
- uint32_t, uint32_t);
+ uint32_t, uint32_t);
+extern uint8_t *qla8044_read_optrom_data(struct scsi_qla_host *,
+ uint8_t *, uint32_t, uint32_t);
+extern void qla8044_watchdog(struct scsi_qla_host *vha);
extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *);
extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
+extern int qla82xx_get_flash_version(scsi_qla_host_t *, void *);
extern int qla2xxx_get_flash_info(scsi_qla_host_t *);
extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
@@ -498,7 +508,7 @@ extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);
extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t);
extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t,
- uint8_t *, uint32_t);
+ uint8_t *, uint32_t);
extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int);
/*
@@ -584,6 +594,7 @@ extern int qlafx00_start_scsi(srb_t *);
extern int qlafx00_abort_isp(scsi_qla_host_t *);
extern int qlafx00_iospace_config(struct qla_hw_data *);
extern int qlafx00_init_firmware(scsi_qla_host_t *, uint16_t);
+extern int qlafx00_driver_shutdown(scsi_qla_host_t *, int);
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 *);
@@ -601,6 +612,7 @@ extern void qlafx00_abort_iocb(srb_t *, struct abort_iocb_entry_fx00 *);
extern void qlafx00_fxdisc_iocb(srb_t *, struct fxdisc_entry_fx00 *);
extern void qlafx00_timer_routine(scsi_qla_host_t *);
extern int qlafx00_rescan_isp(scsi_qla_host_t *);
+extern int qlafx00_loop_reset(scsi_qla_host_t *vha);
/* qla82xx related functions */
@@ -619,9 +631,9 @@ extern int qla82xx_start_firmware(scsi_qla_host_t *);
/* Firmware and flash related functions */
extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *);
extern uint8_t *qla82xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
- uint32_t, uint32_t);
+ uint32_t, uint32_t);
extern int qla82xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
- uint32_t, uint32_t);
+ uint32_t, uint32_t);
/* Mailbox related functions */
extern int qla82xx_abort_isp(scsi_qla_host_t *);
@@ -662,7 +674,7 @@ extern void qla8xxx_dev_failed_handler(scsi_qla_host_t *);
extern void qla82xx_clear_qsnt_ready(scsi_qla_host_t *);
extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *,
- size_t, char *);
+ size_t, char *);
extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *);
extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *);
extern void qla82xx_start_iocbs(scsi_qla_host_t *);
@@ -674,6 +686,8 @@ extern int qla81xx_get_led_config(scsi_qla_host_t *, uint16_t *);
extern int qla82xx_mbx_beacon_ctl(scsi_qla_host_t *, int);
extern char *qdev_state(uint32_t);
extern void qla82xx_clear_pending_mbx(scsi_qla_host_t *);
+extern int qla82xx_read_temperature(scsi_qla_host_t *);
+extern int qla8044_read_temperature(scsi_qla_host_t *);
/* BSG related functions */
extern int qla24xx_bsg_request(struct fc_bsg_job *);
@@ -695,5 +709,31 @@ extern void qla82xx_md_free(scsi_qla_host_t *);
extern int qla82xx_md_collect(scsi_qla_host_t *);
extern void qla82xx_md_prep(scsi_qla_host_t *);
extern void qla82xx_set_reset_owner(scsi_qla_host_t *);
+extern int qla82xx_validate_template_chksum(scsi_qla_host_t *vha);
+
+/* Function declarations for ISP8044 */
+extern int qla8044_idc_lock(struct qla_hw_data *ha);
+extern void qla8044_idc_unlock(struct qla_hw_data *ha);
+extern uint32_t qla8044_rd_reg(struct qla_hw_data *ha, ulong addr);
+extern void qla8044_wr_reg(struct qla_hw_data *ha, ulong addr, uint32_t val);
+extern void qla8044_read_reset_template(struct scsi_qla_host *ha);
+extern void qla8044_set_idc_dontreset(struct scsi_qla_host *ha);
+extern int qla8044_rd_direct(struct scsi_qla_host *vha, const uint32_t crb_reg);
+extern void qla8044_wr_direct(struct scsi_qla_host *vha,
+ const uint32_t crb_reg, const uint32_t value);
+extern inline void qla8044_set_qsnt_ready(struct scsi_qla_host *vha);
+extern inline void qla8044_need_reset_handler(struct scsi_qla_host *vha);
+extern int qla8044_device_state_handler(struct scsi_qla_host *vha);
+extern void qla8044_clear_qsnt_ready(struct scsi_qla_host *vha);
+extern void qla8044_clear_drv_active(struct scsi_qla_host *vha);
+void qla8044_get_minidump(struct scsi_qla_host *vha);
+int qla8044_collect_md_data(struct scsi_qla_host *vha);
+extern int qla8044_md_get_template(scsi_qla_host_t *);
+extern int qla8044_write_optrom_data(struct scsi_qla_host *, uint8_t *,
+ uint32_t, uint32_t);
+extern irqreturn_t qla8044_intr_handler(int, void *);
+extern void qla82xx_mbx_completion(scsi_qla_host_t *, uint16_t);
+extern int qla8044_abort_isp(scsi_qla_host_t *);
+extern int qla8044_check_fw_alive(struct scsi_qla_host *);
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 0926451980e..cd47f1b32d9 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -49,6 +49,8 @@ qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size)
ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;
+ vha->qla_stats.control_requests++;
+
return (ms_pkt);
}
@@ -87,6 +89,8 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size)
ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
ct_pkt->vp_index = vha->vp_idx;
+ vha->qla_stats.control_requests++;
+
return (ct_pkt);
}
@@ -226,17 +230,9 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
fcport->d_id.b.domain = 0xf0;
ql_dbg(ql_dbg_disc, vha, 0x2063,
- "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
- "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+ "GA_NXT entry - nn %8phN pn %8phN "
"port_id=%02x%02x%02x.\n",
- fcport->node_name[0], fcport->node_name[1],
- fcport->node_name[2], fcport->node_name[3],
- fcport->node_name[4], fcport->node_name[5],
- fcport->node_name[6], fcport->node_name[7],
- fcport->port_name[0], fcport->port_name[1],
- fcport->port_name[2], fcport->port_name[3],
- fcport->port_name[4], fcport->port_name[5],
- fcport->port_name[6], fcport->port_name[7],
+ fcport->node_name, fcport->port_name,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
}
@@ -447,17 +443,9 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
ct_rsp->rsp.gnn_id.node_name, WWN_SIZE);
ql_dbg(ql_dbg_disc, vha, 0x2058,
- "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02X%02x "
- "pn %02x%02x%02x%02x%02x%02x%02X%02x "
+ "GID_PT entry - nn %8phN pn %8phN "
"portid=%02x%02x%02x.\n",
- list[i].node_name[0], list[i].node_name[1],
- list[i].node_name[2], list[i].node_name[3],
- list[i].node_name[4], list[i].node_name[5],
- list[i].node_name[6], list[i].node_name[7],
- list[i].port_name[0], list[i].port_name[1],
- list[i].port_name[2], list[i].port_name[3],
- list[i].port_name[4], list[i].port_name[5],
- list[i].port_name[6], list[i].port_name[7],
+ list[i].node_name, list[i].port_name,
list[i].d_id.b.domain, list[i].d_id.b.area,
list[i].d_id.b.al_pa);
}
@@ -739,6 +727,8 @@ qla2x00_prep_sns_cmd(scsi_qla_host_t *vha, uint16_t cmd, uint16_t scmd_len,
wc = (data_size - 16) / 4; /* Size in 32bit words. */
sns_cmd->p.cmd.size = cpu_to_le16(wc);
+ vha->qla_stats.control_requests++;
+
return (sns_cmd);
}
@@ -796,17 +786,9 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
fcport->d_id.b.domain = 0xf0;
ql_dbg(ql_dbg_disc, vha, 0x2061,
- "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
- "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+ "GA_NXT entry - nn %8phN pn %8phN "
"port_id=%02x%02x%02x.\n",
- fcport->node_name[0], fcport->node_name[1],
- fcport->node_name[2], fcport->node_name[3],
- fcport->node_name[4], fcport->node_name[5],
- fcport->node_name[6], fcport->node_name[7],
- fcport->port_name[0], fcport->port_name[1],
- fcport->port_name[2], fcport->port_name[3],
- fcport->port_name[4], fcport->port_name[5],
- fcport->port_name[6], fcport->port_name[7],
+ fcport->node_name, fcport->port_name,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
}
@@ -991,17 +973,9 @@ qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
WWN_SIZE);
ql_dbg(ql_dbg_disc, vha, 0x206e,
- "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
- "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+ "GID_PT entry - nn %8phN pn %8phN "
"port_id=%02x%02x%02x.\n",
- list[i].node_name[0], list[i].node_name[1],
- list[i].node_name[2], list[i].node_name[3],
- list[i].node_name[4], list[i].node_name[5],
- list[i].node_name[6], list[i].node_name[7],
- list[i].port_name[0], list[i].port_name[1],
- list[i].port_name[2], list[i].port_name[3],
- list[i].port_name[4], list[i].port_name[5],
- list[i].port_name[6], list[i].port_name[7],
+ list[i].node_name, list[i].port_name,
list[i].d_id.b.domain, list[i].d_id.b.area,
list[i].d_id.b.al_pa);
}
@@ -1321,11 +1295,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
size += 4 + WWN_SIZE;
ql_dbg(ql_dbg_disc, vha, 0x2025,
- "NodeName = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
- eiter->a.node_name[0], eiter->a.node_name[1],
- eiter->a.node_name[2], eiter->a.node_name[3],
- eiter->a.node_name[4], eiter->a.node_name[5],
- eiter->a.node_name[6], eiter->a.node_name[7]);
+ "NodeName = %8phN.\n", eiter->a.node_name);
/* Manufacturer. */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1428,16 +1398,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
qla2x00_update_ms_fdmi_iocb(vha, size + 16);
ql_dbg(ql_dbg_disc, vha, 0x202e,
- "RHBA identifier = "
- "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n",
- ct_req->req.rhba.hba_identifier[0],
- ct_req->req.rhba.hba_identifier[1],
- ct_req->req.rhba.hba_identifier[2],
- ct_req->req.rhba.hba_identifier[3],
- ct_req->req.rhba.hba_identifier[4],
- ct_req->req.rhba.hba_identifier[5],
- ct_req->req.rhba.hba_identifier[6],
- ct_req->req.rhba.hba_identifier[7], size);
+ "RHBA identifier = %8phN size=%d.\n",
+ ct_req->req.rhba.hba_identifier, size);
ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2076,
entries, size);
@@ -1494,11 +1456,7 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha)
memcpy(ct_req->req.dhba.port_name, vha->port_name, WWN_SIZE);
ql_dbg(ql_dbg_disc, vha, 0x2036,
- "DHBA portname = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
- ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1],
- ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3],
- ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5],
- ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]);
+ "DHBA portname = %8phN.\n", ct_req->req.dhba.port_name);
/* Execute MS IOCB */
rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
@@ -1678,12 +1636,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
qla2x00_update_ms_fdmi_iocb(vha, size + 16);
ql_dbg(ql_dbg_disc, vha, 0x203e,
- "RPA portname= %02x%02x%02x%02x%02X%02x%02x%02x size=%d.\n",
- ct_req->req.rpa.port_name[0], ct_req->req.rpa.port_name[1],
- ct_req->req.rpa.port_name[2], ct_req->req.rpa.port_name[3],
- ct_req->req.rpa.port_name[4], ct_req->req.rpa.port_name[5],
- ct_req->req.rpa.port_name[6], ct_req->req.rpa.port_name[7],
- size);
+ "RPA portname= %8phN size=%d.\n", ct_req->req.rpa.port_name, size);
ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2079,
entries, size);
@@ -1940,16 +1893,8 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
ql_dbg(ql_dbg_disc, vha, 0x205b,
"GPSC ext entry - fpn "
- "%02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
- "speed=%04x.\n",
- list[i].fabric_port_name[0],
- list[i].fabric_port_name[1],
- list[i].fabric_port_name[2],
- list[i].fabric_port_name[3],
- list[i].fabric_port_name[4],
- list[i].fabric_port_name[5],
- list[i].fabric_port_name[6],
- list[i].fabric_port_name[7],
+ "%8phN speeds=%04x speed=%04x.\n",
+ list[i].fabric_port_name,
be16_to_cpu(ct_rsp->rsp.gpsc.speeds),
be16_to_cpu(ct_rsp->rsp.gpsc.speed));
}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index f2216ed2ad8..03f715e7591 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -524,7 +524,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
vha->flags.reset_active = 0;
ha->flags.pci_channel_io_perm_failure = 0;
ha->flags.eeh_busy = 0;
- ha->thermal_support = THERMAL_SUPPORT_I2C|THERMAL_SUPPORT_ISP;
+ vha->qla_stats.jiffies_at_last_reset = get_jiffies_64();
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
atomic_set(&vha->loop_state, LOOP_DOWN);
vha->device_flags = DFLG_NO_CABLE;
@@ -552,7 +552,18 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
if (rval) {
ql_log(ql_log_fatal, vha, 0x004f,
"Unable to validate FLASH data.\n");
- return (rval);
+ return rval;
+ }
+
+ if (IS_QLA8044(ha)) {
+ qla8044_read_reset_template(vha);
+
+ /* NOTE: If ql2xdontresethba==1, set IDC_CTRL DONTRESET_BIT0.
+ * If DONRESET_BIT0 is set, drivers should not set dev_state
+ * to NEED_RESET. But if NEED_RESET is set, drivers should
+ * should honor the reset. */
+ if (ql2xdontresethba == 1)
+ qla8044_set_idc_dontreset(vha);
}
ha->isp_ops->get_flash_version(vha, req->ring);
@@ -564,12 +575,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
if (ha->flags.disable_serdes) {
/* Mask HBA via NVRAM settings? */
ql_log(ql_log_info, vha, 0x0077,
- "Masking HBA WWPN "
- "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
- vha->port_name[0], vha->port_name[1],
- vha->port_name[2], vha->port_name[3],
- vha->port_name[4], vha->port_name[5],
- vha->port_name[6], vha->port_name[7]);
+ "Masking HBA WWPN %8phN (via NVRAM).\n", vha->port_name);
return QLA_FUNCTION_FAILED;
}
@@ -620,6 +626,11 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
qla24xx_read_fcp_prio_cfg(vha);
+ if (IS_P3P_TYPE(ha))
+ qla82xx_set_driver_version(vha, QLA2XXX_VERSION);
+ else
+ qla25xx_set_driver_version(vha, QLA2XXX_VERSION);
+
return (rval);
}
@@ -1332,7 +1343,7 @@ qla24xx_chip_diag(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
return QLA_SUCCESS;
ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
@@ -1615,7 +1626,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
unsigned long flags;
uint16_t fw_major_version;
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
rval = ha->isp_ops->load_risc(vha, &srisc_address);
if (rval == QLA_SUCCESS) {
qla2x00_stop_firmware(vha);
@@ -1651,7 +1662,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
if (rval == QLA_SUCCESS) {
enable_82xx_npiv:
fw_major_version = ha->fw_major_version;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
qla82xx_check_md_needed(vha);
else
rval = qla2x00_get_fw_version(vha);
@@ -1681,7 +1692,7 @@ enable_82xx_npiv:
goto failed;
if (!fw_major_version && ql2xallocfwdump
- && !IS_QLA82XX(ha))
+ && !(IS_P3P_TYPE(ha)))
qla2x00_alloc_fw_dump(vha);
}
} else {
@@ -1849,7 +1860,7 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
int rval;
struct qla_hw_data *ha = vha->hw;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
return;
/* Update Serial Link options. */
@@ -3061,22 +3072,13 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
mb);
if (rval != QLA_SUCCESS) {
ql_dbg(ql_dbg_disc, vha, 0x2004,
- "Unable to adjust iIDMA "
- "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x "
- "%04x.\n", fcport->port_name[0], fcport->port_name[1],
- fcport->port_name[2], fcport->port_name[3],
- fcport->port_name[4], fcport->port_name[5],
- fcport->port_name[6], fcport->port_name[7], rval,
- fcport->fp_speed, mb[0], mb[1]);
+ "Unable to adjust iIDMA %8phN -- %04x %x %04x %04x.\n",
+ fcport->port_name, rval, fcport->fp_speed, mb[0], mb[1]);
} else {
ql_dbg(ql_dbg_disc, vha, 0x2005,
- "iIDMA adjusted to %s GB/s "
- "on %02x%02x%02x%02x%02x%02x%02x%02x.\n",
+ "iIDMA adjusted to %s GB/s on %8phN.\n",
qla2x00_get_link_speed_str(ha, fcport->fp_speed),
- fcport->port_name[0], fcport->port_name[1],
- fcport->port_name[2], fcport->port_name[3],
- fcport->port_name[4], fcport->port_name[5],
- fcport->port_name[6], fcport->port_name[7]);
+ fcport->port_name);
}
}
@@ -4007,10 +4009,18 @@ qla83xx_reset_ownership(scsi_qla_host_t *vha)
uint32_t class_type_mask = 0x3;
uint16_t fcoe_other_function = 0xffff, i;
- qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
-
- qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO1, &dev_part_info1);
- qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO2, &dev_part_info2);
+ if (IS_QLA8044(ha)) {
+ drv_presence = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_ACTIVE_INDEX);
+ dev_part_info1 = qla8044_rd_direct(vha,
+ QLA8044_CRB_DEV_PART_INFO_INDEX);
+ dev_part_info2 = qla8044_rd_direct(vha,
+ QLA8044_CRB_DEV_PART_INFO2);
+ } else {
+ qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
+ qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO1, &dev_part_info1);
+ qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO2, &dev_part_info2);
+ }
for (i = 0; i < 8; i++) {
class_type = ((dev_part_info1 >> (i * 4)) & class_type_mask);
if ((class_type == QLA83XX_CLASS_TYPE_FCOE) &&
@@ -4347,7 +4357,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
/* For ISP82XX, driver waits for completion of the commands.
* online flag should be set.
*/
- if (!IS_QLA82XX(ha))
+ if (!(IS_P3P_TYPE(ha)))
vha->flags.online = 0;
ha->flags.chip_reset_done = 0;
clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -4360,7 +4370,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
* Driver waits for the completion of the commands.
* the interrupts need to be enabled.
*/
- if (!IS_QLA82XX(ha))
+ if (!(IS_P3P_TYPE(ha)))
ha->isp_ops->reset_chip(vha);
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
@@ -4403,7 +4413,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
if (!ha->flags.eeh_busy) {
/* Make sure for ISP 82XX IO DMA is complete */
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
qla82xx_chip_reset_cleanup(vha);
ql_log(ql_log_info, vha, 0x00b4,
"Done chip reset cleanup.\n");
@@ -4723,7 +4733,7 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
return;
vha->flags.online = 0;
@@ -4789,8 +4799,6 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
}
ha->nvram_size = sizeof(struct nvram_24xx);
ha->vpd_size = FA_NVRAM_VPD_SIZE;
- if (IS_QLA82XX(ha))
- ha->vpd_size = FA_VPD_SIZE_82XX;
/* Get VPD data into cache */
ha->vpd = ha->nvram + VPD_OFFSET;
@@ -5552,6 +5560,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
/* Determine NVRAM starting address. */
ha->nvram_size = sizeof(struct nvram_81xx);
ha->vpd_size = FA_NVRAM_VPD_SIZE;
+ if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
+ ha->vpd_size = FA_VPD_SIZE_82XX;
/* Get VPD data into cache */
ha->vpd = ha->nvram + VPD_OFFSET;
@@ -5734,7 +5744,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
/* Link Down Timeout = 0:
*
- * When Port Down timer expires we will start returning
+ * When Port Down timer expires we will start returning
* I/O's to OS with "DID_NO_CONNECT".
*
* Link Down Timeout != 0:
@@ -6061,7 +6071,7 @@ qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
if (priority < 0)
return QLA_FUNCTION_FAILED;
- if (IS_QLA82XX(vha->hw)) {
+ if (IS_P3P_TYPE(vha->hw)) {
fcport->fcp_prio = priority & 0xf;
return QLA_SUCCESS;
}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 28c38b4929c..957088b0461 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -59,7 +59,7 @@ qla2x00_poll(struct rsp_que *rsp)
unsigned long flags;
struct qla_hw_data *ha = rsp->hw;
local_irq_save(flags);
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
qla82xx_poll(0, rsp);
else
ha->isp_ops->intr_handler(0, rsp);
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 42ef481db94..46b9307e8be 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -32,9 +32,11 @@ qla2x00_get_cmd_direction(srb_t *sp)
if (cmd->sc_data_direction == DMA_TO_DEVICE) {
cflags = CF_WRITE;
vha->qla_stats.output_bytes += scsi_bufflen(cmd);
+ vha->qla_stats.output_requests++;
} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
cflags = CF_READ;
vha->qla_stats.input_bytes += scsi_bufflen(cmd);
+ vha->qla_stats.input_requests++;
}
return (cflags);
}
@@ -419,6 +421,8 @@ qla2x00_start_scsi(srb_t *sp)
__constant_cpu_to_le16(CF_SIMPLE_TAG);
break;
}
+ } else {
+ cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);
}
/* Load SCSI command packet. */
@@ -472,7 +476,7 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
struct qla_hw_data *ha = vha->hw;
device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
qla82xx_start_iocbs(vha);
} else {
/* Adjust ring index. */
@@ -640,10 +644,12 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
cmd_pkt->control_flags =
__constant_cpu_to_le16(CF_WRITE_DATA);
vha->qla_stats.output_bytes += scsi_bufflen(cmd);
+ vha->qla_stats.output_requests++;
} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
cmd_pkt->control_flags =
__constant_cpu_to_le16(CF_READ_DATA);
vha->qla_stats.input_bytes += scsi_bufflen(cmd);
+ vha->qla_stats.input_requests++;
}
cur_seg = scsi_sglist(cmd);
@@ -756,10 +762,12 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
cmd_pkt->task_mgmt_flags =
__constant_cpu_to_le16(TMF_WRITE_DATA);
vha->qla_stats.output_bytes += scsi_bufflen(cmd);
+ vha->qla_stats.output_requests++;
} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
cmd_pkt->task_mgmt_flags =
__constant_cpu_to_le16(TMF_READ_DATA);
vha->qla_stats.input_bytes += scsi_bufflen(cmd);
+ vha->qla_stats.input_requests++;
}
/* One DSD is available in the Command Type 3 IOCB */
@@ -1307,11 +1315,11 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
fcp_cmnd->task_attribute = TSK_ORDERED;
break;
default:
- fcp_cmnd->task_attribute = 0;
+ fcp_cmnd->task_attribute = TSK_SIMPLE;
break;
}
} else {
- fcp_cmnd->task_attribute = 0;
+ fcp_cmnd->task_attribute = TSK_SIMPLE;
}
cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
@@ -1525,7 +1533,12 @@ qla24xx_start_scsi(srb_t *sp)
case ORDERED_QUEUE_TAG:
cmd_pkt->task = TSK_ORDERED;
break;
+ default:
+ cmd_pkt->task = TSK_SIMPLE;
+ break;
}
+ } else {
+ cmd_pkt->task = TSK_SIMPLE;
}
/* Load SCSI command packet. */
@@ -1837,7 +1850,7 @@ skip_cmd_array:
if (req->cnt < req_cnt) {
if (ha->mqenable || IS_QLA83XX(ha))
cnt = RD_REG_DWORD(&reg->isp25mq.req_q_out);
- else if (IS_QLA82XX(ha))
+ else if (IS_P3P_TYPE(ha))
cnt = RD_REG_DWORD(&reg->isp82.req_q_out);
else if (IS_FWI2_CAPABLE(ha))
cnt = RD_REG_DWORD(&reg->isp24.req_q_out);
@@ -2049,6 +2062,8 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
(bsg_job->reply_payload.sg_list)));
els_iocb->rx_len = cpu_to_le32(sg_dma_len
(bsg_job->reply_payload.sg_list));
+
+ sp->fcport->vha->qla_stats.control_requests++;
}
static void
@@ -2126,6 +2141,8 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb)
avail_dsds--;
}
ct_iocb->entry_count = entry_count;
+
+ sp->fcport->vha->qla_stats.control_requests++;
}
static void
@@ -2678,6 +2695,9 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
vha->bidi_stats.transfer_bytes += req_data_len;
vha->bidi_stats.io_count++;
+ vha->qla_stats.output_bytes += req_data_len;
+ vha->qla_stats.output_requests++;
+
/* Only one dsd is available for bidirectional IOCB, remaining dsds
* are bundled in continuation iocb
*/
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 2d8e7b81235..df1b30ba938 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -282,25 +282,38 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
"%04x %04x %04x %04x %04x %04x %04x.\n",
event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
mb[4], mb[5], mb[6]);
- if ((aen == MBA_IDC_COMPLETE && mb[1] >> 15)) {
- vha->hw->flags.idc_compl_status = 1;
- if (vha->hw->notify_dcbx_comp)
- complete(&vha->hw->dcbx_comp);
- }
-
- /* Acknowledgement needed? [Notify && non-zero timeout]. */
- timeout = (descr >> 8) & 0xf;
- if (aen != MBA_IDC_NOTIFY || !timeout)
- return;
+ switch (aen) {
+ /* Handle IDC Error completion case. */
+ case MBA_IDC_COMPLETE:
+ if (mb[1] >> 15) {
+ vha->hw->flags.idc_compl_status = 1;
+ if (vha->hw->notify_dcbx_comp)
+ complete(&vha->hw->dcbx_comp);
+ }
+ break;
- ql_dbg(ql_dbg_async, vha, 0x5022,
- "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
- vha->host_no, event[aen & 0xff], timeout);
+ case MBA_IDC_NOTIFY:
+ /* Acknowledgement needed? [Notify && non-zero timeout]. */
+ timeout = (descr >> 8) & 0xf;
+ ql_dbg(ql_dbg_async, vha, 0x5022,
+ "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
+ vha->host_no, event[aen & 0xff], timeout);
- rval = qla2x00_post_idc_ack_work(vha, mb);
- if (rval != QLA_SUCCESS)
- ql_log(ql_log_warn, vha, 0x5023,
- "IDC failed to post ACK.\n");
+ if (!timeout)
+ return;
+ rval = qla2x00_post_idc_ack_work(vha, mb);
+ if (rval != QLA_SUCCESS)
+ ql_log(ql_log_warn, vha, 0x5023,
+ "IDC failed to post ACK.\n");
+ break;
+ case MBA_IDC_TIME_EXT:
+ vha->hw->idc_extend_tmo = descr;
+ ql_dbg(ql_dbg_async, vha, 0x5087,
+ "%lu Inter-Driver Communication %s -- "
+ "Extend timeout by=%d.\n",
+ vha->host_no, event[aen & 0xff], vha->hw->idc_extend_tmo);
+ break;
+ }
}
#define LS_UNKNOWN 2
@@ -691,7 +704,8 @@ skip_rio:
case MBA_LOOP_DOWN: /* Loop Down Event */
mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
? RD_REG_WORD(&reg24->mailbox4) : 0;
- mbx = IS_QLA82XX(ha) ? RD_REG_WORD(&reg82->mailbox_out[4]) : mbx;
+ mbx = (IS_P3P_TYPE(ha)) ? RD_REG_WORD(&reg82->mailbox_out[4])
+ : mbx;
ql_dbg(ql_dbg_async, vha, 0x500b,
"LOOP DOWN detected (%x %x %x %x).\n",
mb[1], mb[2], mb[3], mbx);
@@ -740,7 +754,7 @@ skip_rio:
if (IS_QLA2100(ha))
break;
- if (IS_QLA81XX(ha) || IS_QLA82XX(ha) || IS_QLA8031(ha)) {
+ if (IS_CNA_CAPABLE(ha)) {
ql_dbg(ql_dbg_async, vha, 0x500d,
"DCBX Completed -- %04x %04x %04x.\n",
mb[1], mb[2], mb[3]);
@@ -1002,7 +1016,7 @@ skip_rio:
mb[1], mb[2], mb[3]);
break;
case MBA_IDC_NOTIFY:
- if (IS_QLA8031(vha->hw)) {
+ if (IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
mb[4] = RD_REG_WORD(&reg24->mailbox4);
if (((mb[2] & 0x7fff) == MBC_PORT_RESET ||
(mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) &&
@@ -1022,7 +1036,8 @@ skip_rio:
complete(&ha->lb_portup_comp);
/* Fallthru */
case MBA_IDC_TIME_EXT:
- if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw))
+ if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) ||
+ IS_QLA8044(ha))
qla81xx_idc_event(vha, mb[0], mb[1]);
break;
@@ -1063,7 +1078,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
ql_log(ql_log_warn, vha, 0x3014,
"Invalid SCSI command index (%x).\n", index);
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
else
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -1080,7 +1095,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
} else {
ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
else
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -1100,7 +1115,7 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
if (index >= req->num_outstanding_cmds) {
ql_log(ql_log_warn, vha, 0x5031,
"Invalid command index (%x).\n", index);
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
else
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -1805,6 +1820,9 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
if (scsi_status == 0) {
bsg_job->reply->reply_payload_rcv_len =
bsg_job->reply_payload.payload_len;
+ vha->qla_stats.input_bytes +=
+ bsg_job->reply->reply_payload_rcv_len;
+ vha->qla_stats.input_requests++;
rval = EXT_STATUS_OK;
}
goto done;
@@ -1949,7 +1967,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
ql_dbg(ql_dbg_io, vha, 0x3017,
"Invalid status handle (0x%x).\n", sts->handle);
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
else
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -2176,8 +2194,10 @@ check_scsi_status:
}
ql_dbg(ql_dbg_io, fcport->vha, 0x3021,
- "Port down status: port-state=0x%x.\n",
- atomic_read(&fcport->state));
+ "Port to be marked lost on fcport=%02x%02x%02x, current "
+ "port state= %s.\n", fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa,
+ port_state_str[atomic_read(&fcport->state)]);
if (atomic_read(&fcport->state) == FCS_ONLINE)
qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
@@ -2212,16 +2232,13 @@ check_scsi_status:
out:
if (logit)
ql_dbg(ql_dbg_io, fcport->vha, 0x3022,
- "FCP command status: 0x%x-0x%x (0x%x) "
- "nexus=%ld:%d:%d portid=%02x%02x%02x oxid=0x%x "
- "cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x "
+ "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%d "
+ "portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x "
"rsp_info=0x%x resid=0x%x fw_resid=0x%x.\n",
comp_status, scsi_status, res, vha->host_no,
cp->device->id, cp->device->lun, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
- cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3],
- cp->cmnd[4], cp->cmnd[5], cp->cmnd[6], cp->cmnd[7],
- cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp), rsp_info_len,
+ cp->cmnd, scsi_bufflen(cp), rsp_info_len,
resid_len, fw_resid_len);
if (!res)
@@ -2324,7 +2341,7 @@ fatal:
ql_log(ql_log_warn, vha, 0x5030,
"Error entry - invalid handle/queue.\n");
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
else
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -2452,7 +2469,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
}
/* Adjust ring index */
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
WRT_REG_DWORD(&reg->rsp_q_out[0], rsp->ring_index);
} else
@@ -2865,7 +2882,7 @@ msix_failed:
ret = request_irq(qentry->vector,
qla83xx_msix_entries[i].handler,
0, qla83xx_msix_entries[i].name, rsp);
- } else if (IS_QLA82XX(ha)) {
+ } else if (IS_P3P_TYPE(ha)) {
ret = request_irq(qentry->vector,
qla82xx_msix_entries[i].handler,
0, qla82xx_msix_entries[i].name, rsp);
@@ -2950,7 +2967,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
skip_msix:
if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
- !IS_QLA8001(ha) && !IS_QLA82XX(ha) && !IS_QLAFX00(ha))
+ !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha))
goto skip_msi;
ret = pci_enable_msi(ha->pdev);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 7257c3c4f2d..a9aae500e79 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -75,7 +75,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
return QLA_FUNCTION_TIMEOUT;
}
- if (IS_QLA82XX(ha) && ha->flags.isp82xx_fw_hung) {
+ if (IS_P3P_TYPE(ha) && ha->flags.isp82xx_fw_hung) {
/* Setting Link-Down error */
mcp->mb[0] = MBS_LINK_DOWN_ERROR;
ql_log(ql_log_warn, vha, 0x1004,
@@ -106,9 +106,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Load mailbox registers. */
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
optr = (uint16_t __iomem *)&reg->isp82.mailbox_in[0];
- else if (IS_FWI2_CAPABLE(ha) && !IS_QLA82XX(ha))
+ else if (IS_FWI2_CAPABLE(ha) && !(IS_P3P_TYPE(ha)))
optr = (uint16_t __iomem *)&reg->isp24.mailbox0;
else
optr = (uint16_t __iomem *)MAILBOX_REG(ha, &reg->isp, 0);
@@ -117,33 +117,25 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
command = mcp->mb[0];
mboxes = mcp->out_mb;
+ ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1111,
+ "Mailbox registers (OUT):\n");
for (cnt = 0; cnt < ha->mbx_count; cnt++) {
if (IS_QLA2200(ha) && cnt == 8)
optr =
(uint16_t __iomem *)MAILBOX_REG(ha, &reg->isp, 8);
- if (mboxes & BIT_0)
+ if (mboxes & BIT_0) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1112,
+ "mbox[%d]<-0x%04x\n", cnt, *iptr);
WRT_REG_WORD(optr, *iptr);
+ }
mboxes >>= 1;
optr++;
iptr++;
}
- ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1111,
- "Loaded MBX registers (displayed in bytes) =.\n");
- ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1112,
- (uint8_t *)mcp->mb, 16);
- ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1113,
- ".\n");
- ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1114,
- ((uint8_t *)mcp->mb + 0x10), 16);
- ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1115,
- ".\n");
- ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1116,
- ((uint8_t *)mcp->mb + 0x20), 8);
ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1117,
"I/O Address = %p.\n", optr);
- ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x100e);
/* Issue set host interrupt command to send cmd out. */
ha->flags.mbox_int = 0;
@@ -159,7 +151,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) {
set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
if (RD_REG_DWORD(&reg->isp82.hint) &
HINT_MBX_INT_PENDING) {
spin_unlock_irqrestore(&ha->hardware_lock,
@@ -189,7 +181,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
ql_dbg(ql_dbg_mbx, vha, 0x1011,
"Cmd=%x Polling Mode.\n", command);
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
if (RD_REG_DWORD(&reg->isp82.hint) &
HINT_MBX_INT_PENDING) {
spin_unlock_irqrestore(&ha->hardware_lock,
@@ -236,7 +228,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
ha->flags.mbox_int = 0;
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
- if ((IS_QLA82XX(ha) && ha->flags.isp82xx_fw_hung)) {
+ if (IS_P3P_TYPE(ha) && ha->flags.isp82xx_fw_hung) {
ha->flags.mbox_busy = 0;
/* Setting Link-Down error */
mcp->mb[0] = MBS_LINK_DOWN_ERROR;
@@ -254,9 +246,15 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
iptr2 = mcp->mb;
iptr = (uint16_t *)&ha->mailbox_out[0];
mboxes = mcp->in_mb;
+
+ ql_dbg(ql_dbg_mbx, vha, 0x1113,
+ "Mailbox registers (IN):\n");
for (cnt = 0; cnt < ha->mbx_count; cnt++) {
- if (mboxes & BIT_0)
+ if (mboxes & BIT_0) {
*iptr2 = *iptr;
+ ql_dbg(ql_dbg_mbx, vha, 0x1114,
+ "mbox[%d]->0x%04x\n", cnt, *iptr2);
+ }
mboxes >>= 1;
iptr2++;
@@ -537,7 +535,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
mcp->mb[0] = MBC_GET_FIRMWARE_VERSION;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
- if (IS_QLA81XX(vha->hw) || IS_QLA8031(ha))
+ if (IS_QLA81XX(vha->hw) || IS_QLA8031(ha) || IS_QLA8044(ha))
mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8;
if (IS_FWI2_CAPABLE(ha))
mcp->in_mb |= MBX_17|MBX_16|MBX_15;
@@ -556,7 +554,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
ha->fw_memory_size = 0x1FFFF; /* Defaults to 128KB. */
else
ha->fw_memory_size = (mcp->mb[5] << 16) | mcp->mb[4];
- if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw)) {
+ if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
ha->mpi_version[0] = mcp->mb[10] & 0xff;
ha->mpi_version[1] = mcp->mb[11] >> 8;
ha->mpi_version[2] = mcp->mb[11] & 0xff;
@@ -1201,7 +1199,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x104c,
"Entered %s.\n", __func__);
- if (IS_QLA82XX(ha) && ql2xdbwr)
+ if (IS_P3P_TYPE(ha) && ql2xdbwr)
qla82xx_wr_32(ha, ha->nxdb_wr_ptr,
(0x04 | (ha->portnum << 5) | (0 << 8) | (0 << 16)));
@@ -1667,7 +1665,11 @@ qla24xx_link_initialize(scsi_qla_host_t *vha)
return QLA_FUNCTION_FAILED;
mcp->mb[0] = MBC_LINK_INITIALIZATION;
- mcp->mb[1] = BIT_6|BIT_4;
+ mcp->mb[1] = BIT_4;
+ if (vha->hw->operating_mode == LOOP)
+ mcp->mb[1] |= BIT_6;
+ else
+ mcp->mb[1] |= BIT_5;
mcp->mb[2] = 0;
mcp->mb[3] = 0;
mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -3574,7 +3576,6 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
unsigned long flags;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- struct device_reg_25xxmq __iomem *reg;
struct qla_hw_data *ha = vha->hw;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d3,
@@ -3595,9 +3596,6 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
if (IS_QLA83XX(ha))
mcp->mb[15] = 0;
- reg = (struct device_reg_25xxmq __iomem *)((ha->mqiobase) +
- QLA_QUE_PAGE * req->id);
-
mcp->mb[4] = req->id;
/* que in ptr index */
mcp->mb[8] = 0;
@@ -3619,12 +3617,10 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
spin_lock_irqsave(&ha->hardware_lock, flags);
if (!(req->options & BIT_0)) {
- WRT_REG_DWORD(&reg->req_q_in, 0);
+ WRT_REG_DWORD(req->req_q_in, 0);
if (!IS_QLA83XX(ha))
- WRT_REG_DWORD(&reg->req_q_out, 0);
+ WRT_REG_DWORD(req->req_q_out, 0);
}
- req->req_q_in = &reg->req_q_in;
- req->req_q_out = &reg->req_q_out;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
rval = qla2x00_mailbox_command(vha, mcp);
@@ -3646,7 +3642,6 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
unsigned long flags;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- struct device_reg_25xxmq __iomem *reg;
struct qla_hw_data *ha = vha->hw;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d6,
@@ -3664,9 +3659,6 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
if (IS_QLA83XX(ha))
mcp->mb[15] = 0;
- reg = (struct device_reg_25xxmq __iomem *)((ha->mqiobase) +
- QLA_QUE_PAGE * rsp->id);
-
mcp->mb[4] = rsp->id;
/* que in ptr index */
mcp->mb[8] = 0;
@@ -3690,9 +3682,9 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
spin_lock_irqsave(&ha->hardware_lock, flags);
if (!(rsp->options & BIT_0)) {
- WRT_REG_DWORD(&reg->rsp_q_out, 0);
+ WRT_REG_DWORD(rsp->rsp_q_out, 0);
if (!IS_QLA83XX(ha))
- WRT_REG_DWORD(&reg->rsp_q_in, 0);
+ WRT_REG_DWORD(rsp->rsp_q_in, 0);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -3872,6 +3864,112 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
return rval;
}
+int
+qla82xx_set_driver_version(scsi_qla_host_t *vha, char *version)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ int i;
+ int len;
+ uint16_t *str;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_P3P_TYPE(ha))
+ return QLA_FUNCTION_FAILED;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x117b,
+ "Entered %s.\n", __func__);
+
+ str = (void *)version;
+ len = strlen(version);
+
+ mcp->mb[0] = MBC_SET_RNID_PARAMS;
+ mcp->mb[1] = RNID_TYPE_SET_VERSION << 8;
+ mcp->out_mb = MBX_1|MBX_0;
+ for (i = 4; i < 16 && len; i++, str++, len -= 2) {
+ mcp->mb[i] = cpu_to_le16p(str);
+ mcp->out_mb |= 1<<i;
+ }
+ for (; i < 16; i++) {
+ mcp->mb[i] = 0;
+ mcp->out_mb |= 1<<i;
+ }
+ mcp->in_mb = MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x117c,
+ "Failed=%x mb[0]=%x,%x.\n", rval, mcp->mb[0], mcp->mb[1]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x117d,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+int
+qla25xx_set_driver_version(scsi_qla_host_t *vha, char *version)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ int len;
+ uint16_t dwlen;
+ uint8_t *str;
+ dma_addr_t str_dma;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_FWI2_CAPABLE(ha) || IS_QLA24XX_TYPE(ha) || IS_QLA81XX(ha) ||
+ IS_P3P_TYPE(ha))
+ return QLA_FUNCTION_FAILED;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x117e,
+ "Entered %s.\n", __func__);
+
+ str = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &str_dma);
+ if (!str) {
+ ql_log(ql_log_warn, vha, 0x117f,
+ "Failed to allocate driver version param.\n");
+ return QLA_MEMORY_ALLOC_FAILED;
+ }
+
+ memcpy(str, "\x7\x3\x11\x0", 4);
+ dwlen = str[0];
+ len = dwlen * 4 - 4;
+ memset(str + 4, 0, len);
+ if (len > strlen(version))
+ len = strlen(version);
+ memcpy(str + 4, version, len);
+
+ mcp->mb[0] = MBC_SET_RNID_PARAMS;
+ mcp->mb[1] = RNID_TYPE_SET_VERSION << 8 | dwlen;
+ mcp->mb[2] = MSW(LSD(str_dma));
+ mcp->mb[3] = LSW(LSD(str_dma));
+ mcp->mb[6] = MSW(MSD(str_dma));
+ mcp->mb[7] = LSW(MSD(str_dma));
+ mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1180,
+ "Failed=%x mb[0]=%x,%x.\n", rval, mcp->mb[0], mcp->mb[1]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1181,
+ "Done %s.\n", __func__);
+ }
+
+ dma_pool_free(ha->s_dma_pool, str, str_dma);
+
+ return rval;
+}
+
static int
qla2x00_read_asic_temperature(scsi_qla_host_t *vha, uint16_t *temp)
{
@@ -4407,7 +4505,7 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1109,
"Entered %s.\n", __func__);
- if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
+ if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA8044(ha))
return QLA_FUNCTION_FAILED;
mcp->mb[0] = MBC_GET_PORT_CONFIG;
mcp->out_mb = MBX_0;
@@ -4512,40 +4610,43 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp)
struct qla_hw_data *ha = vha->hw;
uint8_t byte;
- ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ca,
- "Entered %s.\n", __func__);
-
- if (ha->thermal_support & THERMAL_SUPPORT_I2C) {
- rval = qla2x00_read_sfp(vha, 0, &byte,
- 0x98, 0x1, 1, BIT_13|BIT_12|BIT_0);
- *temp = byte;
- if (rval == QLA_SUCCESS)
- goto done;
-
- ql_log(ql_log_warn, vha, 0x10c9,
- "Thermal not supported through I2C bus, trying alternate "
- "method (ISP access).\n");
- ha->thermal_support &= ~THERMAL_SUPPORT_I2C;
+ if (!IS_FWI2_CAPABLE(ha) || IS_QLA24XX_TYPE(ha) || IS_QLA81XX(ha)) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1150,
+ "Thermal not supported by this card.\n");
+ return rval;
}
- if (ha->thermal_support & THERMAL_SUPPORT_ISP) {
- rval = qla2x00_read_asic_temperature(vha, temp);
- if (rval == QLA_SUCCESS)
- goto done;
-
- ql_log(ql_log_warn, vha, 0x1019,
- "Thermal not supported through ISP.\n");
- ha->thermal_support &= ~THERMAL_SUPPORT_ISP;
+ if (IS_QLA25XX(ha)) {
+ if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
+ ha->pdev->subsystem_device == 0x0175) {
+ rval = qla2x00_read_sfp(vha, 0, &byte,
+ 0x98, 0x1, 1, BIT_13|BIT_0);
+ *temp = byte;
+ return rval;
+ }
+ if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
+ ha->pdev->subsystem_device == 0x338e) {
+ rval = qla2x00_read_sfp(vha, 0, &byte,
+ 0x98, 0x1, 1, BIT_15|BIT_14|BIT_0);
+ *temp = byte;
+ return rval;
+ }
+ ql_dbg(ql_dbg_mbx, vha, 0x10c9,
+ "Thermal not supported by this card.\n");
+ return rval;
}
- ql_log(ql_log_warn, vha, 0x1150,
- "Thermal not supported by this card "
- "(ignoring further requests).\n");
- return rval;
+ if (IS_QLA82XX(ha)) {
+ *temp = qla82xx_read_temperature(vha);
+ rval = QLA_SUCCESS;
+ return rval;
+ } else if (IS_QLA8044(ha)) {
+ *temp = qla8044_read_temperature(vha);
+ rval = QLA_SUCCESS;
+ return rval;
+ }
-done:
- ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1018,
- "Done %s.\n", __func__);
+ rval = qla2x00_read_asic_temperature(vha, temp);
return rval;
}
@@ -4595,7 +4696,7 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x100d,
"Entered %s.\n", __func__);
- if (!IS_QLA82XX(ha))
+ if (!IS_P3P_TYPE(ha))
return QLA_FUNCTION_FAILED;
memset(mcp, 0, sizeof(mbx_cmd_t));
@@ -4713,6 +4814,60 @@ qla82xx_md_get_template(scsi_qla_host_t *vha)
}
int
+qla8044_md_get_template(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ int rval = QLA_FUNCTION_FAILED;
+ int offset = 0, size = MINIDUMP_SIZE_36K;
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xb11f,
+ "Entered %s.\n", __func__);
+
+ ha->md_tmplt_hdr = dma_alloc_coherent(&ha->pdev->dev,
+ ha->md_template_size, &ha->md_tmplt_hdr_dma, GFP_KERNEL);
+ if (!ha->md_tmplt_hdr) {
+ ql_log(ql_log_warn, vha, 0xb11b,
+ "Unable to allocate memory for Minidump template.\n");
+ return rval;
+ }
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ while (offset < ha->md_template_size) {
+ mcp->mb[0] = LSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE);
+ mcp->mb[1] = MSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE);
+ mcp->mb[2] = LSW(RQST_TMPLT);
+ mcp->mb[3] = MSW(RQST_TMPLT);
+ mcp->mb[4] = LSW(LSD(ha->md_tmplt_hdr_dma + offset));
+ mcp->mb[5] = MSW(LSD(ha->md_tmplt_hdr_dma + offset));
+ mcp->mb[6] = LSW(MSD(ha->md_tmplt_hdr_dma + offset));
+ mcp->mb[7] = MSW(MSD(ha->md_tmplt_hdr_dma + offset));
+ mcp->mb[8] = LSW(size);
+ mcp->mb[9] = MSW(size);
+ mcp->mb[10] = offset & 0x0000FFFF;
+ mcp->mb[11] = offset & 0xFFFF0000;
+ mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->out_mb = MBX_11|MBX_10|MBX_9|MBX_8|
+ MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0xb11c,
+ "mailbox command FAILED=0x%x, subcode=%x.\n",
+ ((mcp->mb[1] << 16) | mcp->mb[0]),
+ ((mcp->mb[3] << 16) | mcp->mb[2]));
+ return rval;
+ } else
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xb11d,
+ "Done %s.\n", __func__);
+ offset = offset + size;
+ }
+ return rval;
+}
+
+int
qla81xx_set_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg)
{
int rval;
@@ -4808,7 +4963,7 @@ qla82xx_mbx_beacon_ctl(scsi_qla_host_t *vha, int enable)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA82XX(ha))
+ if (!IS_P3P_TYPE(ha))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1127,
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index f868a9f98af..a72df701fb3 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -699,6 +699,8 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
req->cnt = req->length;
req->id = que_id;
reg = ISP_QUE_REG(ha, que_id);
+ req->req_q_in = &reg->isp25mq.req_q_in;
+ req->req_q_out = &reg->isp25mq.req_q_out;
req->max_q_depth = ha->req_q_map[0]->max_q_depth;
mutex_unlock(&ha->vport_lock);
ql_dbg(ql_dbg_multiq, base_vha, 0xc004,
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index d7993797f46..2482975d72b 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -294,7 +294,7 @@ premature_exit:
* Context:
* Kernel context.
*/
-static int
+int
qlafx00_driver_shutdown(scsi_qla_host_t *vha, int tmo)
{
int rval;
@@ -776,6 +776,29 @@ qlafx00_lun_reset(fc_port_t *fcport, unsigned int l, int tag)
}
int
+qlafx00_loop_reset(scsi_qla_host_t *vha)
+{
+ int ret;
+ struct fc_port *fcport;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (ql2xtargetreset) {
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (fcport->port_type != FCT_TARGET)
+ continue;
+
+ ret = ha->isp_ops->target_reset(fcport, 0, 0);
+ if (ret != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_taskm, vha, 0x803d,
+ "Bus Reset failed: Reset=%d "
+ "d_id=%x.\n", ret, fcport->d_id.b24);
+ }
+ }
+ }
+ return QLA_SUCCESS;
+}
+
+int
qlafx00_iospace_config(struct qla_hw_data *ha)
{
if (pci_request_selected_regions(ha->pdev, ha->bars,
@@ -918,12 +941,23 @@ qlafx00_init_fw_ready(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
uint32_t aenmbx, aenmbx7 = 0;
+ uint32_t pseudo_aen;
uint32_t state[5];
bool done = false;
/* 30 seconds wait - Adjust if required */
wait_time = 30;
+ pseudo_aen = RD_REG_DWORD(&reg->pseudoaen);
+ if (pseudo_aen == 1) {
+ aenmbx7 = RD_REG_DWORD(&reg->initval7);
+ ha->mbx_intr_code = MSW(aenmbx7);
+ ha->rqstq_intr_code = LSW(aenmbx7);
+ rval = qlafx00_driver_shutdown(vha, 10);
+ if (rval != QLA_SUCCESS)
+ qlafx00_soft_reset(vha);
+ }
+
/* wait time before firmware ready */
wtime = jiffies + (wait_time * HZ);
do {
@@ -1349,21 +1383,22 @@ qlafx00_configure_devices(scsi_qla_host_t *vha)
}
static void
-qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha)
+qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha, bool critemp)
{
struct qla_hw_data *ha = vha->hw;
fc_port_t *fcport;
vha->flags.online = 0;
- ha->flags.chip_reset_done = 0;
ha->mr.fw_hbt_en = 0;
- clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
- vha->qla_stats.total_isp_aborts++;
-
- ql_log(ql_log_info, vha, 0x013f,
- "Performing ISP error recovery - ha = %p.\n", ha);
- ha->isp_ops->reset_chip(vha);
+ if (!critemp) {
+ ha->flags.chip_reset_done = 0;
+ clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ vha->qla_stats.total_isp_aborts++;
+ ql_log(ql_log_info, vha, 0x013f,
+ "Performing ISP error recovery - ha = %p.\n", ha);
+ ha->isp_ops->reset_chip(vha);
+ }
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -1383,12 +1418,19 @@ qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha)
}
if (!ha->flags.eeh_busy) {
- /* Requeue all commands in outstanding command list. */
- qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+ if (critemp) {
+ qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
+ } else {
+ /* Requeue all commands in outstanding command list. */
+ qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+ }
}
qla2x00_free_irqs(vha);
- set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
+ if (critemp)
+ set_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags);
+ else
+ set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
/* Clear the Interrupts */
QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
@@ -1475,6 +1517,7 @@ qlafx00_timer_routine(scsi_qla_host_t *vha)
uint32_t fw_heart_beat;
uint32_t aenmbx0;
struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+ uint32_t tempc;
/* Check firmware health */
if (ha->mr.fw_hbt_cnt)
@@ -1539,10 +1582,36 @@ qlafx00_timer_routine(scsi_qla_host_t *vha)
} else if ((aenmbx0 & 0xFF00) == MBA_FW_POLL_STATE) {
ha->mr.fw_reset_timer_tick =
QLAFX00_MAX_RESET_INTERVAL;
+ } else if (aenmbx0 == MBA_FW_RESET_FCT) {
+ ha->mr.fw_reset_timer_tick =
+ QLAFX00_MAX_RESET_INTERVAL;
}
ha->mr.old_aenmbx0_state = aenmbx0;
ha->mr.fw_reset_timer_tick--;
}
+ if (test_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags)) {
+ /*
+ * Critical temperature recovery to be
+ * performed in timer routine
+ */
+ if (ha->mr.fw_critemp_timer_tick == 0) {
+ tempc = QLAFX00_GET_TEMPERATURE(ha);
+ ql_dbg(ql_dbg_timer, vha, 0x6012,
+ "ISPFx00(%s): Critical temp timer, "
+ "current SOC temperature: %d\n",
+ __func__, tempc);
+ if (tempc < ha->mr.critical_temperature) {
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ clear_bit(FX00_CRITEMP_RECOVERY,
+ &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ }
+ ha->mr.fw_critemp_timer_tick =
+ QLAFX00_CRITEMP_INTERVAL;
+ } else {
+ ha->mr.fw_critemp_timer_tick--;
+ }
+ }
}
/*
@@ -1570,7 +1639,7 @@ qlafx00_reset_initialize(scsi_qla_host_t *vha)
if (vha->flags.online) {
scsi_block_requests(vha->host);
- qlafx00_abort_isp_cleanup(vha);
+ qlafx00_abort_isp_cleanup(vha, false);
}
ql_log(ql_log_info, vha, 0x0143,
@@ -1602,7 +1671,15 @@ qlafx00_abort_isp(scsi_qla_host_t *vha)
}
scsi_block_requests(vha->host);
- qlafx00_abort_isp_cleanup(vha);
+ qlafx00_abort_isp_cleanup(vha, false);
+ } else {
+ scsi_block_requests(vha->host);
+ clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ vha->qla_stats.total_isp_aborts++;
+ ha->isp_ops->reset_chip(vha);
+ set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
+ /* Clear the Interrupts */
+ QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
}
ql_log(ql_log_info, vha, 0x0145,
@@ -1688,6 +1765,15 @@ qlafx00_process_aen(struct scsi_qla_host *vha, struct qla_work_evt *evt)
aen_code = FCH_EVT_LINKDOWN;
aen_data = 0;
break;
+ case QLAFX00_MBA_TEMP_CRIT: /* Critical temperature event */
+ ql_log(ql_log_info, vha, 0x5082,
+ "Process critical temperature event "
+ "aenmb[0]: %x\n",
+ evt->u.aenfx.evtcode);
+ scsi_block_requests(vha->host);
+ qlafx00_abort_isp_cleanup(vha, true);
+ scsi_unblock_requests(vha->host);
+ break;
}
fc_host_post_event(vha->host, fc_get_event_number(),
@@ -1879,6 +1965,11 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
sizeof(vha->hw->mr.uboot_version));
memcpy(&vha->hw->mr.fru_serial_num, pinfo->fru_serial_num,
sizeof(vha->hw->mr.fru_serial_num));
+ vha->hw->mr.critical_temperature =
+ (pinfo->nominal_temp_value) ?
+ pinfo->nominal_temp_value : QLAFX00_CRITEMP_THRSHLD;
+ ha->mr.extended_io_enabled = (pinfo->enabled_capabilities &
+ QLAFX00_EXTENDED_IO_EN_MASK) != 0;
} else if (fx_type == FXDISC_GET_PORT_INFO) {
struct port_info_data *pinfo =
(struct port_info_data *) fdisc->u.fxiocb.rsp_addr;
@@ -2021,6 +2112,7 @@ qlafx00_initialize_adapter(scsi_qla_host_t *vha)
{
int rval;
struct qla_hw_data *ha = vha->hw;
+ uint32_t tempc;
/* Clear adapter flags. */
vha->flags.online = 0;
@@ -2028,7 +2120,6 @@ qlafx00_initialize_adapter(scsi_qla_host_t *vha)
vha->flags.reset_active = 0;
ha->flags.pci_channel_io_perm_failure = 0;
ha->flags.eeh_busy = 0;
- ha->thermal_support = 0;
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
atomic_set(&vha->loop_state, LOOP_DOWN);
vha->device_flags = DFLG_NO_CABLE;
@@ -2072,6 +2163,11 @@ qlafx00_initialize_adapter(scsi_qla_host_t *vha)
rval = qla2x00_init_rings(vha);
ha->flags.chip_reset_done = 1;
+ tempc = QLAFX00_GET_TEMPERATURE(ha);
+ ql_dbg(ql_dbg_init, vha, 0x0152,
+ "ISPFx00(%s): Critical temp timer, current SOC temperature: 0x%x\n",
+ __func__, tempc);
+
return rval;
}
@@ -2526,16 +2622,13 @@ check_scsi_status:
if (logit)
ql_dbg(ql_dbg_io, fcport->vha, 0x3058,
- "FCP command status: 0x%x-0x%x (0x%x) "
- "nexus=%ld:%d:%d tgt_id: 0x%x lscsi_status: 0x%x"
- "cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x "
- "rsp_info=0x%x resid=0x%x fw_resid=0x%x "
- "sense_len=0x%x, par_sense_len=0x%x, rsp_info_len=0x%x\n",
+ "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%d "
+ "tgt_id: 0x%x lscsi_status: 0x%x cdb=%10phN len=0x%x "
+ "rsp_info=0x%x resid=0x%x fw_resid=0x%x sense_len=0x%x, "
+ "par_sense_len=0x%x, rsp_info_len=0x%x\n",
comp_status, scsi_status, res, vha->host_no,
cp->device->id, cp->device->lun, fcport->tgt_id,
- lscsi_status, cp->cmnd[0], cp->cmnd[1], cp->cmnd[2],
- cp->cmnd[3], cp->cmnd[4], cp->cmnd[5], cp->cmnd[6],
- cp->cmnd[7], cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp),
+ lscsi_status, cp->cmnd, scsi_bufflen(cp),
rsp_info_len, resid_len, fw_resid_len, sense_len,
par_sense_len, rsp_info_len);
@@ -2720,9 +2813,6 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
struct sts_entry_fx00 *pkt;
response_t *lptr;
- if (!vha->flags.online)
- return;
-
while (RD_REG_DWORD((void __iomem *)&(rsp->ring_ptr->signature)) !=
RESPONSE_PROCESSED) {
lptr = rsp->ring_ptr;
@@ -2824,6 +2914,28 @@ qlafx00_async_event(scsi_qla_host_t *vha)
ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3]);
data_size = 4;
break;
+
+ case QLAFX00_MBA_TEMP_OVER: /* Over temperature event */
+ ql_log(ql_log_info, vha, 0x5085,
+ "Asynchronous over temperature event received "
+ "aenmb[0]: %x\n",
+ ha->aenmb[0]);
+ break;
+
+ case QLAFX00_MBA_TEMP_NORM: /* Normal temperature event */
+ ql_log(ql_log_info, vha, 0x5086,
+ "Asynchronous normal temperature event received "
+ "aenmb[0]: %x\n",
+ ha->aenmb[0]);
+ break;
+
+ case QLAFX00_MBA_TEMP_CRIT: /* Critical temperature event */
+ ql_log(ql_log_info, vha, 0x5083,
+ "Asynchronous critical temperature event received "
+ "aenmb[0]: %x\n",
+ ha->aenmb[0]);
+ break;
+
default:
ha->aenmb[1] = RD_REG_WORD(&reg->aenmailbox1);
ha->aenmb[2] = RD_REG_WORD(&reg->aenmailbox2);
diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h
index 1a092af0e2c..79a93c52bae 100644
--- a/drivers/scsi/qla2xxx/qla_mr.h
+++ b/drivers/scsi/qla2xxx/qla_mr.h
@@ -329,11 +329,13 @@ struct config_info_data {
uint64_t adapter_id;
uint32_t cluster_key_len;
- uint8_t cluster_key[10];
+ uint8_t cluster_key[16];
uint64_t cluster_master_id;
uint64_t cluster_slave_id;
uint8_t cluster_flags;
+ uint32_t enabled_capabilities;
+ uint32_t nominal_temp_value;
} __packed;
#define FXDISC_GET_CONFIG_INFO 0x01
@@ -342,10 +344,11 @@ struct config_info_data {
#define FXDISC_GET_TGT_NODE_LIST 0x81
#define FXDISC_REG_HOST_INFO 0x99
-#define QLAFX00_HBA_ICNTRL_REG 0x21B08
+#define QLAFX00_HBA_ICNTRL_REG 0x20B08
#define QLAFX00_ICR_ENB_MASK 0x80000000
#define QLAFX00_ICR_DIS_MASK 0x7fffffff
#define QLAFX00_HST_RST_REG 0x18264
+#define QLAFX00_SOC_TEMP_REG 0x184C4
#define QLAFX00_HST_TO_HBA_REG 0x20A04
#define QLAFX00_HBA_TO_HOST_REG 0x21B70
#define QLAFX00_HST_INT_STS_BITS 0x7
@@ -361,6 +364,9 @@ struct config_info_data {
#define QLAFX00_INTR_ALL_CMPLT 0x7
#define QLAFX00_MBA_SYSTEM_ERR 0x8002
+#define QLAFX00_MBA_TEMP_OVER 0x8005
+#define QLAFX00_MBA_TEMP_NORM 0x8006
+#define QLAFX00_MBA_TEMP_CRIT 0x8007
#define QLAFX00_MBA_LINK_UP 0x8011
#define QLAFX00_MBA_LINK_DOWN 0x8012
#define QLAFX00_MBA_PORT_UPDATE 0x8014
@@ -434,9 +440,11 @@ struct qla_mt_iocb_rqst_fx00 {
__le32 dataword_extra;
- __le32 req_len;
+ __le16 req_len;
+ __le16 reserved_2;
- __le32 rsp_len;
+ __le16 rsp_len;
+ __le16 reserved_3;
};
struct qla_mt_iocb_rsp_fx00 {
@@ -499,12 +507,37 @@ struct mr_data_fx00 {
uint32_t old_fw_hbt_cnt;
uint16_t fw_reset_timer_tick;
uint8_t fw_reset_timer_exp;
+ uint16_t fw_critemp_timer_tick;
uint32_t old_aenmbx0_state;
+ uint32_t critical_temperature;
+ bool extended_io_enabled;
};
+#define QLAFX00_EXTENDED_IO_EN_MASK 0x20
+
+/*
+ * SoC Junction Temperature is stored in
+ * bits 9:1 of SoC Junction Temperature Register
+ * in a firmware specific format format.
+ * To get the temperature in Celsius degrees
+ * the value from this bitfiled should be converted
+ * using this formula:
+ * Temperature (degrees C) = ((3,153,000 - (10,000 * X)) / 13,825)
+ * where X is the bit field value
+ * this macro reads the register, extracts the bitfield value,
+ * performs the calcualtions and returns temperature in Celsius
+ */
+#define QLAFX00_GET_TEMPERATURE(ha) ((3153000 - (10000 * \
+ ((QLAFX00_RD_REG(ha, QLAFX00_SOC_TEMP_REG) & 0x3FE) >> 1))) / 13825)
+
+
#define QLAFX00_LOOP_DOWN_TIME 615 /* 600 */
#define QLAFX00_HEARTBEAT_INTERVAL 6 /* number of seconds */
#define QLAFX00_HEARTBEAT_MISS_CNT 3 /* number of miss */
#define QLAFX00_RESET_INTERVAL 120 /* number of seconds */
#define QLAFX00_MAX_RESET_INTERVAL 600 /* number of seconds */
+#define QLAFX00_CRITEMP_INTERVAL 60 /* number of seconds */
+
+#define QLAFX00_CRITEMP_THRSHLD 80 /* Celsius degrees */
+
#endif
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index cce0cd0d7ec..11ce53dcbe7 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -848,7 +848,6 @@ qla82xx_rom_lock(struct qla_hw_data *ha)
{
int done = 0, timeout = 0;
uint32_t lock_owner = 0;
- scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
while (!done) {
/* acquire semaphore2 from PCI HW block */
@@ -857,9 +856,6 @@ qla82xx_rom_lock(struct qla_hw_data *ha)
break;
if (timeout >= qla82xx_rom_lock_timeout) {
lock_owner = qla82xx_rd_32(ha, QLA82XX_ROM_LOCK_ID);
- ql_dbg(ql_dbg_p3p, vha, 0xb085,
- "Failed to acquire rom lock, acquired by %d.\n",
- lock_owner);
return -1;
}
timeout++;
@@ -1666,8 +1662,14 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
}
/* Mapping of IO base pointer */
- ha->iobase = (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase +
- 0xbc000 + (ha->pdev->devfn << 11));
+ if (IS_QLA8044(ha)) {
+ ha->iobase =
+ (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase);
+ } else if (IS_QLA82XX(ha)) {
+ ha->iobase =
+ (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase +
+ 0xbc000 + (ha->pdev->devfn << 11));
+ }
if (!ql2xdbwr) {
ha->nxdb_wr_ptr =
@@ -1967,7 +1969,7 @@ static struct qla82xx_legacy_intr_set legacy_intr[] = \
* @ha: SCSI driver HA context
* @mb0: Mailbox0 register
*/
-static void
+void
qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
{
uint16_t cnt;
@@ -2075,13 +2077,6 @@ qla82xx_intr_handler(int irq, void *dev_id)
WRT_REG_DWORD(&reg->host_int, 0);
}
-#ifdef QL_DEBUG_LEVEL_17
- if (!irq && ha->flags.eeh_busy)
- ql_log(ql_log_warn, vha, 0x503d,
- "isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n",
- status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
-#endif
-
qla2x00_handle_mbx_completion(ha, status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -2147,13 +2142,6 @@ qla82xx_msix_default(int irq, void *dev_id)
WRT_REG_DWORD(&reg->host_int, 0);
} while (0);
-#ifdef QL_DEBUG_LEVEL_17
- if (!irq && ha->flags.eeh_busy)
- ql_log(ql_log_warn, vha, 0x5044,
- "isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n",
- status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
-#endif
-
qla2x00_handle_mbx_completion(ha, status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -2247,7 +2235,10 @@ qla82xx_enable_intrs(struct qla_hw_data *ha)
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
qla82xx_mbx_intr_enable(vha);
spin_lock_irq(&ha->hardware_lock);
- qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
+ if (IS_QLA8044(ha))
+ qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 0);
+ else
+ qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
spin_unlock_irq(&ha->hardware_lock);
ha->interrupts_on = 1;
}
@@ -2258,7 +2249,10 @@ qla82xx_disable_intrs(struct qla_hw_data *ha)
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
qla82xx_mbx_intr_disable(vha);
spin_lock_irq(&ha->hardware_lock);
- qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
+ if (IS_QLA8044(ha))
+ qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 1);
+ else
+ qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
spin_unlock_irq(&ha->hardware_lock);
ha->interrupts_on = 0;
}
@@ -3008,6 +3002,9 @@ qla8xxx_dev_failed_handler(scsi_qla_host_t *vha)
if (IS_QLA82XX(ha)) {
qla82xx_clear_drv_active(ha);
qla82xx_idc_unlock(ha);
+ } else if (IS_QLA8044(ha)) {
+ qla8044_clear_drv_active(vha);
+ qla8044_idc_unlock(ha);
}
/* Set DEV_FAILED flag to disable timer */
@@ -3134,7 +3131,7 @@ qla82xx_check_md_needed(scsi_qla_host_t *vha)
if (fw_major_version != ha->fw_major_version ||
fw_minor_version != ha->fw_minor_version ||
fw_subminor_version != ha->fw_subminor_version) {
- ql_log(ql_log_info, vha, 0xb02d,
+ ql_dbg(ql_dbg_p3p, vha, 0xb02d,
"Firmware version differs "
"Previous version: %d:%d:%d - "
"New version: %d:%d:%d\n",
@@ -3330,6 +3327,14 @@ static int qla82xx_check_temp(scsi_qla_host_t *vha)
return 0;
}
+int qla82xx_read_temperature(scsi_qla_host_t *vha)
+{
+ uint32_t temp;
+
+ temp = qla82xx_rd_32(vha->hw, CRB_TEMP_STATE);
+ return qla82xx_get_temp_val(temp);
+}
+
void qla82xx_clear_pending_mbx(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
@@ -3423,8 +3428,18 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
int qla82xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
{
- int rval;
- rval = qla82xx_device_state_handler(vha);
+ int rval = -1;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (IS_QLA82XX(ha))
+ rval = qla82xx_device_state_handler(vha);
+ else if (IS_QLA8044(ha)) {
+ qla8044_idc_lock(ha);
+ /* Decide the reset ownership */
+ qla83xx_reset_ownership(vha);
+ qla8044_idc_unlock(ha);
+ rval = qla8044_device_state_handler(vha);
+ }
return rval;
}
@@ -3432,17 +3447,25 @@ void
qla82xx_set_reset_owner(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
- uint32_t dev_state;
+ uint32_t dev_state = 0;
+
+ if (IS_QLA82XX(ha))
+ dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+ else if (IS_QLA8044(ha))
+ dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
- dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
if (dev_state == QLA8XXX_DEV_READY) {
ql_log(ql_log_info, vha, 0xb02f,
"HW State: NEED RESET\n");
- qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
- QLA8XXX_DEV_NEED_RESET);
- ha->flags.nic_core_reset_owner = 1;
- ql_dbg(ql_dbg_p3p, vha, 0xb030,
- "reset_owner is 0x%x\n", ha->portnum);
+ if (IS_QLA82XX(ha)) {
+ qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+ QLA8XXX_DEV_NEED_RESET);
+ ha->flags.nic_core_reset_owner = 1;
+ ql_dbg(ql_dbg_p3p, vha, 0xb030,
+ "reset_owner is 0x%x\n", ha->portnum);
+ } else if (IS_QLA8044(ha))
+ qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+ QLA8XXX_DEV_NEED_RESET);
} else
ql_log(ql_log_info, vha, 0xb031,
"Device state is 0x%x = %s.\n",
@@ -3463,7 +3486,7 @@ qla82xx_set_reset_owner(scsi_qla_host_t *vha)
int
qla82xx_abort_isp(scsi_qla_host_t *vha)
{
- int rval;
+ int rval = -1;
struct qla_hw_data *ha = vha->hw;
if (vha->device_flags & DFLG_DEV_FAILED) {
@@ -3477,7 +3500,15 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
qla82xx_set_reset_owner(vha);
qla82xx_idc_unlock(ha);
- rval = qla82xx_device_state_handler(vha);
+ if (IS_QLA82XX(ha))
+ rval = qla82xx_device_state_handler(vha);
+ else if (IS_QLA8044(ha)) {
+ qla8044_idc_lock(ha);
+ /* Decide the reset ownership */
+ qla83xx_reset_ownership(vha);
+ qla8044_idc_unlock(ha);
+ rval = qla8044_device_state_handler(vha);
+ }
qla82xx_idc_lock(ha);
qla82xx_clear_rst_ready(ha);
@@ -3597,7 +3628,7 @@ int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha)
void
qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
{
- int i;
+ int i, fw_state = 0;
unsigned long flags;
struct qla_hw_data *ha = vha->hw;
@@ -3608,7 +3639,11 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
if (!ha->flags.isp82xx_fw_hung) {
for (i = 0; i < 2; i++) {
msleep(1000);
- if (qla82xx_check_fw_alive(vha)) {
+ if (IS_QLA82XX(ha))
+ fw_state = qla82xx_check_fw_alive(vha);
+ else if (IS_QLA8044(ha))
+ fw_state = qla8044_check_fw_alive(vha);
+ if (fw_state) {
ha->flags.isp82xx_fw_hung = 1;
qla82xx_clear_pending_mbx(vha);
break;
@@ -4072,7 +4107,7 @@ qla82xx_minidump_process_rdmem(scsi_qla_host_t *vha,
return QLA_SUCCESS;
}
-static int
+int
qla82xx_validate_template_chksum(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
@@ -4384,7 +4419,11 @@ qla82xx_md_prep(scsi_qla_host_t *vha)
ha->md_template_size / 1024);
/* Get Minidump template */
- rval = qla82xx_md_get_template(vha);
+ if (IS_QLA8044(ha))
+ rval = qla8044_md_get_template(vha);
+ else
+ rval = qla82xx_md_get_template(vha);
+
if (rval == QLA_SUCCESS) {
ql_dbg(ql_dbg_p3p, vha, 0xb04b,
"MiniDump Template obtained\n");
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
index d268e8406fd..1bb93dbbccb 100644
--- a/drivers/scsi/qla2xxx/qla_nx.h
+++ b/drivers/scsi/qla2xxx/qla_nx.h
@@ -589,6 +589,7 @@
* The PCI VendorID and DeviceID for our board.
*/
#define PCI_DEVICE_ID_QLOGIC_ISP8021 0x8021
+#define PCI_DEVICE_ID_QLOGIC_ISP8044 0x8044
#define QLA82XX_MSIX_TBL_SPACE 8192
#define QLA82XX_PCI_REG_MSIX_TBL 0x44
@@ -954,6 +955,11 @@ struct ct6_dsd {
#define QLA82XX_CNTRL 98
#define QLA82XX_TLHDR 99
#define QLA82XX_RDEND 255
+#define QLA8044_POLLRD 35
+#define QLA8044_RDMUX2 36
+#define QLA8044_L1DTG 8
+#define QLA8044_L1ITG 9
+#define QLA8044_POLLRDMWR 37
/*
* Opcodes for Control Entries.
@@ -1191,4 +1197,8 @@ enum {
QLA82XX_TEMP_WARN, /* Sound alert, temperature getting high */
QLA82XX_TEMP_PANIC /* Fatal error, hardware has shut down. */
};
+
+#define LEG_INTR_PTR_OFFSET 0x38C0
+#define LEG_INTR_TRIG_OFFSET 0x38C4
+#define LEG_INTR_MASK_OFFSET 0x38C8
#endif
diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c
new file mode 100644
index 00000000000..8164cc9e728
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_nx2.c
@@ -0,0 +1,3716 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+
+#include <linux/vmalloc.h>
+
+#include "qla_def.h"
+#include "qla_gbl.h"
+
+#include <linux/delay.h>
+
+/* 8044 Flash Read/Write functions */
+uint32_t
+qla8044_rd_reg(struct qla_hw_data *ha, ulong addr)
+{
+ return readl((void __iomem *) (ha->nx_pcibase + addr));
+}
+
+void
+qla8044_wr_reg(struct qla_hw_data *ha, ulong addr, uint32_t val)
+{
+ writel(val, (void __iomem *)((ha)->nx_pcibase + addr));
+}
+
+int
+qla8044_rd_direct(struct scsi_qla_host *vha,
+ const uint32_t crb_reg)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (crb_reg < CRB_REG_INDEX_MAX)
+ return qla8044_rd_reg(ha, qla8044_reg_tbl[crb_reg]);
+ else
+ return QLA_FUNCTION_FAILED;
+}
+
+void
+qla8044_wr_direct(struct scsi_qla_host *vha,
+ const uint32_t crb_reg,
+ const uint32_t value)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (crb_reg < CRB_REG_INDEX_MAX)
+ qla8044_wr_reg(ha, qla8044_reg_tbl[crb_reg], value);
+}
+
+static int
+qla8044_set_win_base(scsi_qla_host_t *vha, uint32_t addr)
+{
+ uint32_t val;
+ int ret_val = QLA_SUCCESS;
+ struct qla_hw_data *ha = vha->hw;
+
+ qla8044_wr_reg(ha, QLA8044_CRB_WIN_FUNC(ha->portnum), addr);
+ val = qla8044_rd_reg(ha, QLA8044_CRB_WIN_FUNC(ha->portnum));
+
+ if (val != addr) {
+ ql_log(ql_log_warn, vha, 0xb087,
+ "%s: Failed to set register window : "
+ "addr written 0x%x, read 0x%x!\n",
+ __func__, addr, val);
+ ret_val = QLA_FUNCTION_FAILED;
+ }
+ return ret_val;
+}
+
+static int
+qla8044_rd_reg_indirect(scsi_qla_host_t *vha, uint32_t addr, uint32_t *data)
+{
+ int ret_val = QLA_SUCCESS;
+ struct qla_hw_data *ha = vha->hw;
+
+ ret_val = qla8044_set_win_base(vha, addr);
+ if (!ret_val)
+ *data = qla8044_rd_reg(ha, QLA8044_WILDCARD);
+ else
+ ql_log(ql_log_warn, vha, 0xb088,
+ "%s: failed read of addr 0x%x!\n", __func__, addr);
+ return ret_val;
+}
+
+static int
+qla8044_wr_reg_indirect(scsi_qla_host_t *vha, uint32_t addr, uint32_t data)
+{
+ int ret_val = QLA_SUCCESS;
+ struct qla_hw_data *ha = vha->hw;
+
+ ret_val = qla8044_set_win_base(vha, addr);
+ if (!ret_val)
+ qla8044_wr_reg(ha, QLA8044_WILDCARD, data);
+ else
+ ql_log(ql_log_warn, vha, 0xb089,
+ "%s: failed wrt to addr 0x%x, data 0x%x\n",
+ __func__, addr, data);
+ return ret_val;
+}
+
+/*
+ * qla8044_read_write_crb_reg - Read from raddr and write value to waddr.
+ *
+ * @ha : Pointer to adapter structure
+ * @raddr : CRB address to read from
+ * @waddr : CRB address to write to
+ *
+ */
+static void
+qla8044_read_write_crb_reg(struct scsi_qla_host *vha,
+ uint32_t raddr, uint32_t waddr)
+{
+ uint32_t value;
+
+ qla8044_rd_reg_indirect(vha, raddr, &value);
+ qla8044_wr_reg_indirect(vha, waddr, value);
+}
+
+/*
+ * qla8044_rmw_crb_reg - Read value from raddr, AND with test_mask,
+ * Shift Left,Right/OR/XOR with values RMW header and write value to waddr.
+ *
+ * @vha : Pointer to adapter structure
+ * @raddr : CRB address to read from
+ * @waddr : CRB address to write to
+ * @p_rmw_hdr : header with shift/or/xor values.
+ *
+ */
+static void
+qla8044_rmw_crb_reg(struct scsi_qla_host *vha,
+ uint32_t raddr, uint32_t waddr, struct qla8044_rmw *p_rmw_hdr)
+{
+ uint32_t value;
+
+ if (p_rmw_hdr->index_a)
+ value = vha->reset_tmplt.array[p_rmw_hdr->index_a];
+ else
+ qla8044_rd_reg_indirect(vha, raddr, &value);
+ value &= p_rmw_hdr->test_mask;
+ value <<= p_rmw_hdr->shl;
+ value >>= p_rmw_hdr->shr;
+ value |= p_rmw_hdr->or_value;
+ value ^= p_rmw_hdr->xor_value;
+ qla8044_wr_reg_indirect(vha, waddr, value);
+ return;
+}
+
+inline void
+qla8044_set_qsnt_ready(struct scsi_qla_host *vha)
+{
+ uint32_t qsnt_state;
+ struct qla_hw_data *ha = vha->hw;
+
+ qsnt_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+ qsnt_state |= (1 << ha->portnum);
+ qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, qsnt_state);
+ ql_log(ql_log_info, vha, 0xb08e, "%s(%ld): qsnt_state: 0x%08x\n",
+ __func__, vha->host_no, qsnt_state);
+}
+
+void
+qla8044_clear_qsnt_ready(struct scsi_qla_host *vha)
+{
+ uint32_t qsnt_state;
+ struct qla_hw_data *ha = vha->hw;
+
+ qsnt_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+ qsnt_state &= ~(1 << ha->portnum);
+ qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, qsnt_state);
+ ql_log(ql_log_info, vha, 0xb08f, "%s(%ld): qsnt_state: 0x%08x\n",
+ __func__, vha->host_no, qsnt_state);
+}
+
+/**
+ *
+ * qla8044_lock_recovery - Recovers the idc_lock.
+ * @ha : Pointer to adapter structure
+ *
+ * Lock Recovery Register
+ * 5-2 Lock recovery owner: Function ID of driver doing lock recovery,
+ * valid if bits 1..0 are set by driver doing lock recovery.
+ * 1-0 1 - Driver intends to force unlock the IDC lock.
+ * 2 - Driver is moving forward to unlock the IDC lock. Driver clears
+ * this field after force unlocking the IDC lock.
+ *
+ * Lock Recovery process
+ * a. Read the IDC_LOCK_RECOVERY register. If the value in bits 1..0 is
+ * greater than 0, then wait for the other driver to unlock otherwise
+ * move to the next step.
+ * b. Indicate intent to force-unlock by writing 1h to the IDC_LOCK_RECOVERY
+ * register bits 1..0 and also set the function# in bits 5..2.
+ * c. Read the IDC_LOCK_RECOVERY register again after a delay of 200ms.
+ * Wait for the other driver to perform lock recovery if the function
+ * number in bits 5..2 has changed, otherwise move to the next step.
+ * d. Write a value of 2h to the IDC_LOCK_RECOVERY register bits 1..0
+ * leaving your function# in bits 5..2.
+ * e. Force unlock using the DRIVER_UNLOCK register and immediately clear
+ * the IDC_LOCK_RECOVERY bits 5..0 by writing 0.
+ **/
+static int
+qla8044_lock_recovery(struct scsi_qla_host *vha)
+{
+ uint32_t lock = 0, lockid;
+ struct qla_hw_data *ha = vha->hw;
+
+ lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCKRECOVERY);
+
+ /* Check for other Recovery in progress, go wait */
+ if ((lockid & IDC_LOCK_RECOVERY_STATE_MASK) != 0)
+ return QLA_FUNCTION_FAILED;
+
+ /* Intent to Recover */
+ qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY,
+ (ha->portnum <<
+ IDC_LOCK_RECOVERY_STATE_SHIFT_BITS) | INTENT_TO_RECOVER);
+ msleep(200);
+
+ /* Check Intent to Recover is advertised */
+ lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCKRECOVERY);
+ if ((lockid & IDC_LOCK_RECOVERY_OWNER_MASK) != (ha->portnum <<
+ IDC_LOCK_RECOVERY_STATE_SHIFT_BITS))
+ return QLA_FUNCTION_FAILED;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb08B, "%s:%d: IDC Lock recovery initiated\n"
+ , __func__, ha->portnum);
+
+ /* Proceed to Recover */
+ qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY,
+ (ha->portnum << IDC_LOCK_RECOVERY_STATE_SHIFT_BITS) |
+ PROCEED_TO_RECOVER);
+
+ /* Force Unlock() */
+ qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, 0xFF);
+ qla8044_rd_reg(ha, QLA8044_DRV_UNLOCK);
+
+ /* Clear bits 0-5 in IDC_RECOVERY register*/
+ qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY, 0);
+
+ /* Get lock() */
+ lock = qla8044_rd_reg(ha, QLA8044_DRV_LOCK);
+ if (lock) {
+ lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
+ lockid = ((lockid + (1 << 8)) & ~0xFF) | ha->portnum;
+ qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, lockid);
+ return QLA_SUCCESS;
+ } else
+ return QLA_FUNCTION_FAILED;
+}
+
+int
+qla8044_idc_lock(struct qla_hw_data *ha)
+{
+ uint32_t ret_val = QLA_SUCCESS, timeout = 0, status = 0;
+ uint32_t lock_id, lock_cnt, func_num, tmo_owner = 0, first_owner = 0;
+ scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
+ while (status == 0) {
+ /* acquire semaphore5 from PCI HW block */
+ status = qla8044_rd_reg(ha, QLA8044_DRV_LOCK);
+
+ if (status) {
+ /* Increment Counter (8-31) and update func_num (0-7) on
+ * getting a successful lock */
+ lock_id = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
+ lock_id = ((lock_id + (1 << 8)) & ~0xFF) | ha->portnum;
+ qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, lock_id);
+ break;
+ }
+
+ if (timeout == 0)
+ first_owner = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
+
+ if (++timeout >=
+ (QLA8044_DRV_LOCK_TIMEOUT / QLA8044_DRV_LOCK_MSLEEP)) {
+ tmo_owner = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
+ func_num = tmo_owner & 0xFF;
+ lock_cnt = tmo_owner >> 8;
+ ql_log(ql_log_warn, vha, 0xb114,
+ "%s: Lock by func %d failed after 2s, lock held "
+ "by func %d, lock count %d, first_owner %d\n",
+ __func__, ha->portnum, func_num, lock_cnt,
+ (first_owner & 0xFF));
+ if (first_owner != tmo_owner) {
+ /* Some other driver got lock,
+ * OR same driver got lock again (counter
+ * value changed), when we were waiting for
+ * lock. Retry for another 2 sec */
+ ql_dbg(ql_dbg_p3p, vha, 0xb115,
+ "%s: %d: IDC lock failed\n",
+ __func__, ha->portnum);
+ timeout = 0;
+ } else {
+ /* Same driver holding lock > 2sec.
+ * Force Recovery */
+ if (qla8044_lock_recovery(vha) == QLA_SUCCESS) {
+ /* Recovered and got lock */
+ ret_val = QLA_SUCCESS;
+ ql_dbg(ql_dbg_p3p, vha, 0xb116,
+ "%s:IDC lock Recovery by %d"
+ "successful...\n", __func__,
+ ha->portnum);
+ }
+ /* Recovery Failed, some other function
+ * has the lock, wait for 2secs
+ * and retry
+ */
+ ql_dbg(ql_dbg_p3p, vha, 0xb08a,
+ "%s: IDC lock Recovery by %d "
+ "failed, Retrying timout\n", __func__,
+ ha->portnum);
+ timeout = 0;
+ }
+ }
+ msleep(QLA8044_DRV_LOCK_MSLEEP);
+ }
+ return ret_val;
+}
+
+void
+qla8044_idc_unlock(struct qla_hw_data *ha)
+{
+ int id;
+ scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
+ id = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
+
+ if ((id & 0xFF) != ha->portnum) {
+ ql_log(ql_log_warn, vha, 0xb118,
+ "%s: IDC Unlock by %d failed, lock owner is %d!\n",
+ __func__, ha->portnum, (id & 0xFF));
+ return;
+ }
+
+ /* Keep lock counter value, update the ha->func_num to 0xFF */
+ qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, (id | 0xFF));
+ qla8044_rd_reg(ha, QLA8044_DRV_UNLOCK);
+}
+
+/* 8044 Flash Lock/Unlock functions */
+static int
+qla8044_flash_lock(scsi_qla_host_t *vha)
+{
+ int lock_owner;
+ int timeout = 0;
+ uint32_t lock_status = 0;
+ int ret_val = QLA_SUCCESS;
+ struct qla_hw_data *ha = vha->hw;
+
+ while (lock_status == 0) {
+ lock_status = qla8044_rd_reg(ha, QLA8044_FLASH_LOCK);
+ if (lock_status)
+ break;
+
+ if (++timeout >= QLA8044_FLASH_LOCK_TIMEOUT / 20) {
+ lock_owner = qla8044_rd_reg(ha,
+ QLA8044_FLASH_LOCK_ID);
+ ql_log(ql_log_warn, vha, 0xb113,
+ "%s: flash lock by %d failed, held by %d\n",
+ __func__, ha->portnum, lock_owner);
+ ret_val = QLA_FUNCTION_FAILED;
+ break;
+ }
+ msleep(20);
+ }
+ qla8044_wr_reg(ha, QLA8044_FLASH_LOCK_ID, ha->portnum);
+ return ret_val;
+}
+
+static void
+qla8044_flash_unlock(scsi_qla_host_t *vha)
+{
+ int ret_val;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Reading FLASH_UNLOCK register unlocks the Flash */
+ qla8044_wr_reg(ha, QLA8044_FLASH_LOCK_ID, 0xFF);
+ ret_val = qla8044_rd_reg(ha, QLA8044_FLASH_UNLOCK);
+}
+
+
+static
+void qla8044_flash_lock_recovery(struct scsi_qla_host *vha)
+{
+
+ if (qla8044_flash_lock(vha)) {
+ /* Someone else is holding the lock. */
+ ql_log(ql_log_warn, vha, 0xb120, "Resetting flash_lock\n");
+ }
+
+ /*
+ * Either we got the lock, or someone
+ * else died while holding it.
+ * In either case, unlock.
+ */
+ qla8044_flash_unlock(vha);
+}
+
+/*
+ * Address and length are byte address
+ */
+static int
+qla8044_read_flash_data(scsi_qla_host_t *vha, uint8_t *p_data,
+ uint32_t flash_addr, int u32_word_count)
+{
+ int i, ret_val = QLA_SUCCESS;
+ uint32_t u32_word;
+
+ if (qla8044_flash_lock(vha) != QLA_SUCCESS) {
+ ret_val = QLA_FUNCTION_FAILED;
+ goto exit_lock_error;
+ }
+
+ if (flash_addr & 0x03) {
+ ql_log(ql_log_warn, vha, 0xb117,
+ "%s: Illegal addr = 0x%x\n", __func__, flash_addr);
+ ret_val = QLA_FUNCTION_FAILED;
+ goto exit_flash_read;
+ }
+
+ for (i = 0; i < u32_word_count; i++) {
+ if (qla8044_wr_reg_indirect(vha, QLA8044_FLASH_DIRECT_WINDOW,
+ (flash_addr & 0xFFFF0000))) {
+ ql_log(ql_log_warn, vha, 0xb119,
+ "%s: failed to write addr 0x%x to "
+ "FLASH_DIRECT_WINDOW\n! ",
+ __func__, flash_addr);
+ ret_val = QLA_FUNCTION_FAILED;
+ goto exit_flash_read;
+ }
+
+ ret_val = qla8044_rd_reg_indirect(vha,
+ QLA8044_FLASH_DIRECT_DATA(flash_addr),
+ &u32_word);
+ if (ret_val != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0xb08c,
+ "%s: failed to read addr 0x%x!\n",
+ __func__, flash_addr);
+ goto exit_flash_read;
+ }
+
+ *(uint32_t *)p_data = u32_word;
+ p_data = p_data + 4;
+ flash_addr = flash_addr + 4;
+ }
+
+exit_flash_read:
+ qla8044_flash_unlock(vha);
+
+exit_lock_error:
+ return ret_val;
+}
+
+/*
+ * Address and length are byte address
+ */
+uint8_t *
+qla8044_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+ uint32_t offset, uint32_t length)
+{
+ scsi_block_requests(vha->host);
+ if (qla8044_read_flash_data(vha, (uint8_t *)buf, offset, length / 4)
+ != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0xb08d,
+ "%s: Failed to read from flash\n",
+ __func__);
+ }
+ scsi_unblock_requests(vha->host);
+ return buf;
+}
+
+inline int
+qla8044_need_reset(struct scsi_qla_host *vha)
+{
+ uint32_t drv_state, drv_active;
+ int rval;
+ struct qla_hw_data *ha = vha->hw;
+
+ drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
+ drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+
+ rval = drv_state & (1 << ha->portnum);
+
+ if (ha->flags.eeh_busy && drv_active)
+ rval = 1;
+ return rval;
+}
+
+/*
+ * qla8044_write_list - Write the value (p_entry->arg2) to address specified
+ * by p_entry->arg1 for all entries in header with delay of p_hdr->delay between
+ * entries.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : reset_entry header for WRITE_LIST opcode.
+ *
+ */
+static void
+qla8044_write_list(struct scsi_qla_host *vha,
+ struct qla8044_reset_entry_hdr *p_hdr)
+{
+ struct qla8044_entry *p_entry;
+ uint32_t i;
+
+ p_entry = (struct qla8044_entry *)((char *)p_hdr +
+ sizeof(struct qla8044_reset_entry_hdr));
+
+ for (i = 0; i < p_hdr->count; i++, p_entry++) {
+ qla8044_wr_reg_indirect(vha, p_entry->arg1, p_entry->arg2);
+ if (p_hdr->delay)
+ udelay((uint32_t)(p_hdr->delay));
+ }
+}
+
+/*
+ * qla8044_read_write_list - Read from address specified by p_entry->arg1,
+ * write value read to address specified by p_entry->arg2, for all entries in
+ * header with delay of p_hdr->delay between entries.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : reset_entry header for READ_WRITE_LIST opcode.
+ *
+ */
+static void
+qla8044_read_write_list(struct scsi_qla_host *vha,
+ struct qla8044_reset_entry_hdr *p_hdr)
+{
+ struct qla8044_entry *p_entry;
+ uint32_t i;
+
+ p_entry = (struct qla8044_entry *)((char *)p_hdr +
+ sizeof(struct qla8044_reset_entry_hdr));
+
+ for (i = 0; i < p_hdr->count; i++, p_entry++) {
+ qla8044_read_write_crb_reg(vha, p_entry->arg1,
+ p_entry->arg2);
+ if (p_hdr->delay)
+ udelay((uint32_t)(p_hdr->delay));
+ }
+}
+
+/*
+ * qla8044_poll_reg - Poll the given CRB addr for duration msecs till
+ * value read ANDed with test_mask is equal to test_result.
+ *
+ * @ha : Pointer to adapter structure
+ * @addr : CRB register address
+ * @duration : Poll for total of "duration" msecs
+ * @test_mask : Mask value read with "test_mask"
+ * @test_result : Compare (value&test_mask) with test_result.
+ *
+ * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
+ */
+static int
+qla8044_poll_reg(struct scsi_qla_host *vha, uint32_t addr,
+ int duration, uint32_t test_mask, uint32_t test_result)
+{
+ uint32_t value;
+ int timeout_error;
+ uint8_t retries;
+ int ret_val = QLA_SUCCESS;
+
+ ret_val = qla8044_rd_reg_indirect(vha, addr, &value);
+ if (ret_val == QLA_FUNCTION_FAILED) {
+ timeout_error = 1;
+ goto exit_poll_reg;
+ }
+
+ /* poll every 1/10 of the total duration */
+ retries = duration/10;
+
+ do {
+ if ((value & test_mask) != test_result) {
+ timeout_error = 1;
+ msleep(duration/10);
+ ret_val = qla8044_rd_reg_indirect(vha, addr, &value);
+ if (ret_val == QLA_FUNCTION_FAILED) {
+ timeout_error = 1;
+ goto exit_poll_reg;
+ }
+ } else {
+ timeout_error = 0;
+ break;
+ }
+ } while (retries--);
+
+exit_poll_reg:
+ if (timeout_error) {
+ vha->reset_tmplt.seq_error++;
+ ql_log(ql_log_fatal, vha, 0xb090,
+ "%s: Poll Failed: 0x%08x 0x%08x 0x%08x\n",
+ __func__, value, test_mask, test_result);
+ }
+
+ return timeout_error;
+}
+
+/*
+ * qla8044_poll_list - For all entries in the POLL_LIST header, poll read CRB
+ * register specified by p_entry->arg1 and compare (value AND test_mask) with
+ * test_result to validate it. Wait for p_hdr->delay between processing entries.
+ *
+ * @ha : Pointer to adapter structure
+ * @p_hdr : reset_entry header for POLL_LIST opcode.
+ *
+ */
+static void
+qla8044_poll_list(struct scsi_qla_host *vha,
+ struct qla8044_reset_entry_hdr *p_hdr)
+{
+ long delay;
+ struct qla8044_entry *p_entry;
+ struct qla8044_poll *p_poll;
+ uint32_t i;
+ uint32_t value;
+
+ p_poll = (struct qla8044_poll *)
+ ((char *)p_hdr + sizeof(struct qla8044_reset_entry_hdr));
+
+ /* Entries start after 8 byte qla8044_poll, poll header contains
+ * the test_mask, test_value.
+ */
+ p_entry = (struct qla8044_entry *)((char *)p_poll +
+ sizeof(struct qla8044_poll));
+
+ delay = (long)p_hdr->delay;
+
+ if (!delay) {
+ for (i = 0; i < p_hdr->count; i++, p_entry++)
+ qla8044_poll_reg(vha, p_entry->arg1,
+ delay, p_poll->test_mask, p_poll->test_value);
+ } else {
+ for (i = 0; i < p_hdr->count; i++, p_entry++) {
+ if (delay) {
+ if (qla8044_poll_reg(vha,
+ p_entry->arg1, delay,
+ p_poll->test_mask,
+ p_poll->test_value)) {
+ /*If
+ * (data_read&test_mask != test_value)
+ * read TIMEOUT_ADDR (arg1) and
+ * ADDR (arg2) registers
+ */
+ qla8044_rd_reg_indirect(vha,
+ p_entry->arg1, &value);
+ qla8044_rd_reg_indirect(vha,
+ p_entry->arg2, &value);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * qla8044_poll_write_list - Write dr_value, ar_value to dr_addr/ar_addr,
+ * read ar_addr, if (value& test_mask != test_mask) re-read till timeout
+ * expires.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : reset entry header for POLL_WRITE_LIST opcode.
+ *
+ */
+static void
+qla8044_poll_write_list(struct scsi_qla_host *vha,
+ struct qla8044_reset_entry_hdr *p_hdr)
+{
+ long delay;
+ struct qla8044_quad_entry *p_entry;
+ struct qla8044_poll *p_poll;
+ uint32_t i;
+
+ p_poll = (struct qla8044_poll *)((char *)p_hdr +
+ sizeof(struct qla8044_reset_entry_hdr));
+
+ p_entry = (struct qla8044_quad_entry *)((char *)p_poll +
+ sizeof(struct qla8044_poll));
+
+ delay = (long)p_hdr->delay;
+
+ for (i = 0; i < p_hdr->count; i++, p_entry++) {
+ qla8044_wr_reg_indirect(vha,
+ p_entry->dr_addr, p_entry->dr_value);
+ qla8044_wr_reg_indirect(vha,
+ p_entry->ar_addr, p_entry->ar_value);
+ if (delay) {
+ if (qla8044_poll_reg(vha,
+ p_entry->ar_addr, delay,
+ p_poll->test_mask,
+ p_poll->test_value)) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb091,
+ "%s: Timeout Error: poll list, ",
+ __func__);
+ ql_dbg(ql_dbg_p3p, vha, 0xb092,
+ "item_num %d, entry_num %d\n", i,
+ vha->reset_tmplt.seq_index);
+ }
+ }
+ }
+}
+
+/*
+ * qla8044_read_modify_write - Read value from p_entry->arg1, modify the
+ * value, write value to p_entry->arg2. Process entries with p_hdr->delay
+ * between entries.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : header with shift/or/xor values.
+ *
+ */
+static void
+qla8044_read_modify_write(struct scsi_qla_host *vha,
+ struct qla8044_reset_entry_hdr *p_hdr)
+{
+ struct qla8044_entry *p_entry;
+ struct qla8044_rmw *p_rmw_hdr;
+ uint32_t i;
+
+ p_rmw_hdr = (struct qla8044_rmw *)((char *)p_hdr +
+ sizeof(struct qla8044_reset_entry_hdr));
+
+ p_entry = (struct qla8044_entry *)((char *)p_rmw_hdr +
+ sizeof(struct qla8044_rmw));
+
+ for (i = 0; i < p_hdr->count; i++, p_entry++) {
+ qla8044_rmw_crb_reg(vha, p_entry->arg1,
+ p_entry->arg2, p_rmw_hdr);
+ if (p_hdr->delay)
+ udelay((uint32_t)(p_hdr->delay));
+ }
+}
+
+/*
+ * qla8044_pause - Wait for p_hdr->delay msecs, called between processing
+ * two entries of a sequence.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : Common reset entry header.
+ *
+ */
+static
+void qla8044_pause(struct scsi_qla_host *vha,
+ struct qla8044_reset_entry_hdr *p_hdr)
+{
+ if (p_hdr->delay)
+ mdelay((uint32_t)((long)p_hdr->delay));
+}
+
+/*
+ * qla8044_template_end - Indicates end of reset sequence processing.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : Common reset entry header.
+ *
+ */
+static void
+qla8044_template_end(struct scsi_qla_host *vha,
+ struct qla8044_reset_entry_hdr *p_hdr)
+{
+ vha->reset_tmplt.template_end = 1;
+
+ if (vha->reset_tmplt.seq_error == 0) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb093,
+ "%s: Reset sequence completed SUCCESSFULLY.\n", __func__);
+ } else {
+ ql_log(ql_log_fatal, vha, 0xb094,
+ "%s: Reset sequence completed with some timeout "
+ "errors.\n", __func__);
+ }
+}
+
+/*
+ * qla8044_poll_read_list - Write ar_value to ar_addr register, read ar_addr,
+ * if (value & test_mask != test_value) re-read till timeout value expires,
+ * read dr_addr register and assign to reset_tmplt.array.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : Common reset entry header.
+ *
+ */
+static void
+qla8044_poll_read_list(struct scsi_qla_host *vha,
+ struct qla8044_reset_entry_hdr *p_hdr)
+{
+ long delay;
+ int index;
+ struct qla8044_quad_entry *p_entry;
+ struct qla8044_poll *p_poll;
+ uint32_t i;
+ uint32_t value;
+
+ p_poll = (struct qla8044_poll *)
+ ((char *)p_hdr + sizeof(struct qla8044_reset_entry_hdr));
+
+ p_entry = (struct qla8044_quad_entry *)
+ ((char *)p_poll + sizeof(struct qla8044_poll));
+
+ delay = (long)p_hdr->delay;
+
+ for (i = 0; i < p_hdr->count; i++, p_entry++) {
+ qla8044_wr_reg_indirect(vha, p_entry->ar_addr,
+ p_entry->ar_value);
+ if (delay) {
+ if (qla8044_poll_reg(vha, p_entry->ar_addr, delay,
+ p_poll->test_mask, p_poll->test_value)) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb095,
+ "%s: Timeout Error: poll "
+ "list, ", __func__);
+ ql_dbg(ql_dbg_p3p, vha, 0xb096,
+ "Item_num %d, "
+ "entry_num %d\n", i,
+ vha->reset_tmplt.seq_index);
+ } else {
+ index = vha->reset_tmplt.array_index;
+ qla8044_rd_reg_indirect(vha,
+ p_entry->dr_addr, &value);
+ vha->reset_tmplt.array[index++] = value;
+ if (index == QLA8044_MAX_RESET_SEQ_ENTRIES)
+ vha->reset_tmplt.array_index = 1;
+ }
+ }
+ }
+}
+
+/*
+ * qla8031_process_reset_template - Process all entries in reset template
+ * till entry with SEQ_END opcode, which indicates end of the reset template
+ * processing. Each entry has a Reset Entry header, entry opcode/command, with
+ * size of the entry, number of entries in sub-sequence and delay in microsecs
+ * or timeout in millisecs.
+ *
+ * @ha : Pointer to adapter structure
+ * @p_buff : Common reset entry header.
+ *
+ */
+static void
+qla8044_process_reset_template(struct scsi_qla_host *vha,
+ char *p_buff)
+{
+ int index, entries;
+ struct qla8044_reset_entry_hdr *p_hdr;
+ char *p_entry = p_buff;
+
+ vha->reset_tmplt.seq_end = 0;
+ vha->reset_tmplt.template_end = 0;
+ entries = vha->reset_tmplt.hdr->entries;
+ index = vha->reset_tmplt.seq_index;
+
+ for (; (!vha->reset_tmplt.seq_end) && (index < entries); index++) {
+ p_hdr = (struct qla8044_reset_entry_hdr *)p_entry;
+ switch (p_hdr->cmd) {
+ case OPCODE_NOP:
+ break;
+ case OPCODE_WRITE_LIST:
+ qla8044_write_list(vha, p_hdr);
+ break;
+ case OPCODE_READ_WRITE_LIST:
+ qla8044_read_write_list(vha, p_hdr);
+ break;
+ case OPCODE_POLL_LIST:
+ qla8044_poll_list(vha, p_hdr);
+ break;
+ case OPCODE_POLL_WRITE_LIST:
+ qla8044_poll_write_list(vha, p_hdr);
+ break;
+ case OPCODE_READ_MODIFY_WRITE:
+ qla8044_read_modify_write(vha, p_hdr);
+ break;
+ case OPCODE_SEQ_PAUSE:
+ qla8044_pause(vha, p_hdr);
+ break;
+ case OPCODE_SEQ_END:
+ vha->reset_tmplt.seq_end = 1;
+ break;
+ case OPCODE_TMPL_END:
+ qla8044_template_end(vha, p_hdr);
+ break;
+ case OPCODE_POLL_READ_LIST:
+ qla8044_poll_read_list(vha, p_hdr);
+ break;
+ default:
+ ql_log(ql_log_fatal, vha, 0xb097,
+ "%s: Unknown command ==> 0x%04x on "
+ "entry = %d\n", __func__, p_hdr->cmd, index);
+ break;
+ }
+ /*
+ *Set pointer to next entry in the sequence.
+ */
+ p_entry += p_hdr->size;
+ }
+ vha->reset_tmplt.seq_index = index;
+}
+
+static void
+qla8044_process_init_seq(struct scsi_qla_host *vha)
+{
+ qla8044_process_reset_template(vha,
+ vha->reset_tmplt.init_offset);
+ if (vha->reset_tmplt.seq_end != 1)
+ ql_log(ql_log_fatal, vha, 0xb098,
+ "%s: Abrupt INIT Sub-Sequence end.\n",
+ __func__);
+}
+
+static void
+qla8044_process_stop_seq(struct scsi_qla_host *vha)
+{
+ vha->reset_tmplt.seq_index = 0;
+ qla8044_process_reset_template(vha, vha->reset_tmplt.stop_offset);
+ if (vha->reset_tmplt.seq_end != 1)
+ ql_log(ql_log_fatal, vha, 0xb099,
+ "%s: Abrupt STOP Sub-Sequence end.\n", __func__);
+}
+
+static void
+qla8044_process_start_seq(struct scsi_qla_host *vha)
+{
+ qla8044_process_reset_template(vha, vha->reset_tmplt.start_offset);
+ if (vha->reset_tmplt.template_end != 1)
+ ql_log(ql_log_fatal, vha, 0xb09a,
+ "%s: Abrupt START Sub-Sequence end.\n",
+ __func__);
+}
+
+static int
+qla8044_lockless_flash_read_u32(struct scsi_qla_host *vha,
+ uint32_t flash_addr, uint8_t *p_data, int u32_word_count)
+{
+ uint32_t i;
+ uint32_t u32_word;
+ uint32_t flash_offset;
+ uint32_t addr = flash_addr;
+ int ret_val = QLA_SUCCESS;
+
+ flash_offset = addr & (QLA8044_FLASH_SECTOR_SIZE - 1);
+
+ if (addr & 0x3) {
+ ql_log(ql_log_fatal, vha, 0xb09b, "%s: Illegal addr = 0x%x\n",
+ __func__, addr);
+ ret_val = QLA_FUNCTION_FAILED;
+ goto exit_lockless_read;
+ }
+
+ ret_val = qla8044_wr_reg_indirect(vha,
+ QLA8044_FLASH_DIRECT_WINDOW, (addr));
+
+ if (ret_val != QLA_SUCCESS) {
+ ql_log(ql_log_fatal, vha, 0xb09c,
+ "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n",
+ __func__, addr);
+ goto exit_lockless_read;
+ }
+
+ /* Check if data is spread across multiple sectors */
+ if ((flash_offset + (u32_word_count * sizeof(uint32_t))) >
+ (QLA8044_FLASH_SECTOR_SIZE - 1)) {
+ /* Multi sector read */
+ for (i = 0; i < u32_word_count; i++) {
+ ret_val = qla8044_rd_reg_indirect(vha,
+ QLA8044_FLASH_DIRECT_DATA(addr), &u32_word);
+ if (ret_val != QLA_SUCCESS) {
+ ql_log(ql_log_fatal, vha, 0xb09d,
+ "%s: failed to read addr 0x%x!\n",
+ __func__, addr);
+ goto exit_lockless_read;
+ }
+ *(uint32_t *)p_data = u32_word;
+ p_data = p_data + 4;
+ addr = addr + 4;
+ flash_offset = flash_offset + 4;
+ if (flash_offset > (QLA8044_FLASH_SECTOR_SIZE - 1)) {
+ /* This write is needed once for each sector */
+ ret_val = qla8044_wr_reg_indirect(vha,
+ QLA8044_FLASH_DIRECT_WINDOW, (addr));
+ if (ret_val != QLA_SUCCESS) {
+ ql_log(ql_log_fatal, vha, 0xb09f,
+ "%s: failed to write addr "
+ "0x%x to FLASH_DIRECT_WINDOW!\n",
+ __func__, addr);
+ goto exit_lockless_read;
+ }
+ flash_offset = 0;
+ }
+ }
+ } else {
+ /* Single sector read */
+ for (i = 0; i < u32_word_count; i++) {
+ ret_val = qla8044_rd_reg_indirect(vha,
+ QLA8044_FLASH_DIRECT_DATA(addr), &u32_word);
+ if (ret_val != QLA_SUCCESS) {
+ ql_log(ql_log_fatal, vha, 0xb0a0,
+ "%s: failed to read addr 0x%x!\n",
+ __func__, addr);
+ goto exit_lockless_read;
+ }
+ *(uint32_t *)p_data = u32_word;
+ p_data = p_data + 4;
+ addr = addr + 4;
+ }
+ }
+
+exit_lockless_read:
+ return ret_val;
+}
+
+/*
+ * qla8044_ms_mem_write_128b - Writes data to MS/off-chip memory
+ *
+ * @vha : Pointer to adapter structure
+ * addr : Flash address to write to
+ * data : Data to be written
+ * count : word_count to be written
+ *
+ * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
+ */
+static int
+qla8044_ms_mem_write_128b(struct scsi_qla_host *vha,
+ uint64_t addr, uint32_t *data, uint32_t count)
+{
+ int i, j, ret_val = QLA_SUCCESS;
+ uint32_t agt_ctrl;
+ unsigned long flags;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Only 128-bit aligned access */
+ if (addr & 0xF) {
+ ret_val = QLA_FUNCTION_FAILED;
+ goto exit_ms_mem_write;
+ }
+ write_lock_irqsave(&ha->hw_lock, flags);
+
+ /* Write address */
+ ret_val = qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_HI, 0);
+ if (ret_val == QLA_FUNCTION_FAILED) {
+ ql_log(ql_log_fatal, vha, 0xb0a1,
+ "%s: write to AGT_ADDR_HI failed!\n", __func__);
+ goto exit_ms_mem_write_unlock;
+ }
+
+ for (i = 0; i < count; i++, addr += 16) {
+ if (!((QLA8044_ADDR_IN_RANGE(addr, QLA8044_ADDR_QDR_NET,
+ QLA8044_ADDR_QDR_NET_MAX)) ||
+ (QLA8044_ADDR_IN_RANGE(addr, QLA8044_ADDR_DDR_NET,
+ QLA8044_ADDR_DDR_NET_MAX)))) {
+ ret_val = QLA_FUNCTION_FAILED;
+ goto exit_ms_mem_write_unlock;
+ }
+
+ ret_val = qla8044_wr_reg_indirect(vha,
+ MD_MIU_TEST_AGT_ADDR_LO, addr);
+
+ /* Write data */
+ ret_val += qla8044_wr_reg_indirect(vha,
+ MD_MIU_TEST_AGT_WRDATA_LO, *data++);
+ ret_val += qla8044_wr_reg_indirect(vha,
+ MD_MIU_TEST_AGT_WRDATA_HI, *data++);
+ ret_val += qla8044_wr_reg_indirect(vha,
+ MD_MIU_TEST_AGT_WRDATA_ULO, *data++);
+ ret_val += qla8044_wr_reg_indirect(vha,
+ MD_MIU_TEST_AGT_WRDATA_UHI, *data++);
+ if (ret_val == QLA_FUNCTION_FAILED) {
+ ql_log(ql_log_fatal, vha, 0xb0a2,
+ "%s: write to AGT_WRDATA failed!\n",
+ __func__);
+ goto exit_ms_mem_write_unlock;
+ }
+
+ /* Check write status */
+ ret_val = qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL,
+ MIU_TA_CTL_WRITE_ENABLE);
+ ret_val += qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL,
+ MIU_TA_CTL_WRITE_START);
+ if (ret_val == QLA_FUNCTION_FAILED) {
+ ql_log(ql_log_fatal, vha, 0xb0a3,
+ "%s: write to AGT_CTRL failed!\n", __func__);
+ goto exit_ms_mem_write_unlock;
+ }
+
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ ret_val = qla8044_rd_reg_indirect(vha,
+ MD_MIU_TEST_AGT_CTRL, &agt_ctrl);
+ if (ret_val == QLA_FUNCTION_FAILED) {
+ ql_log(ql_log_fatal, vha, 0xb0a4,
+ "%s: failed to read "
+ "MD_MIU_TEST_AGT_CTRL!\n", __func__);
+ goto exit_ms_mem_write_unlock;
+ }
+ if ((agt_ctrl & MIU_TA_CTL_BUSY) == 0)
+ break;
+ }
+
+ /* Status check failed */
+ if (j >= MAX_CTL_CHECK) {
+ ql_log(ql_log_fatal, vha, 0xb0a5,
+ "%s: MS memory write failed!\n",
+ __func__);
+ ret_val = QLA_FUNCTION_FAILED;
+ goto exit_ms_mem_write_unlock;
+ }
+ }
+
+exit_ms_mem_write_unlock:
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+
+exit_ms_mem_write:
+ return ret_val;
+}
+
+static int
+qla8044_copy_bootloader(struct scsi_qla_host *vha)
+{
+ uint8_t *p_cache;
+ uint32_t src, count, size;
+ uint64_t dest;
+ int ret_val = QLA_SUCCESS;
+ struct qla_hw_data *ha = vha->hw;
+
+ src = QLA8044_BOOTLOADER_FLASH_ADDR;
+ dest = qla8044_rd_reg(ha, QLA8044_BOOTLOADER_ADDR);
+ size = qla8044_rd_reg(ha, QLA8044_BOOTLOADER_SIZE);
+
+ /* 128 bit alignment check */
+ if (size & 0xF)
+ size = (size + 16) & ~0xF;
+
+ /* 16 byte count */
+ count = size/16;
+
+ p_cache = vmalloc(size);
+ if (p_cache == NULL) {
+ ql_log(ql_log_fatal, vha, 0xb0a6,
+ "%s: Failed to allocate memory for "
+ "boot loader cache\n", __func__);
+ ret_val = QLA_FUNCTION_FAILED;
+ goto exit_copy_bootloader;
+ }
+
+ ret_val = qla8044_lockless_flash_read_u32(vha, src,
+ p_cache, size/sizeof(uint32_t));
+ if (ret_val == QLA_FUNCTION_FAILED) {
+ ql_log(ql_log_fatal, vha, 0xb0a7,
+ "%s: Error reading F/W from flash!!!\n", __func__);
+ goto exit_copy_error;
+ }
+ ql_dbg(ql_dbg_p3p, vha, 0xb0a8, "%s: Read F/W from flash!\n",
+ __func__);
+
+ /* 128 bit/16 byte write to MS memory */
+ ret_val = qla8044_ms_mem_write_128b(vha, dest,
+ (uint32_t *)p_cache, count);
+ if (ret_val == QLA_FUNCTION_FAILED) {
+ ql_log(ql_log_fatal, vha, 0xb0a9,
+ "%s: Error writing F/W to MS !!!\n", __func__);
+ goto exit_copy_error;
+ }
+ ql_dbg(ql_dbg_p3p, vha, 0xb0aa,
+ "%s: Wrote F/W (size %d) to MS !!!\n",
+ __func__, size);
+
+exit_copy_error:
+ vfree(p_cache);
+
+exit_copy_bootloader:
+ return ret_val;
+}
+
+static int
+qla8044_restart(struct scsi_qla_host *vha)
+{
+ int ret_val = QLA_SUCCESS;
+ struct qla_hw_data *ha = vha->hw;
+
+ qla8044_process_stop_seq(vha);
+
+ /* Collect minidump */
+ if (ql2xmdenable)
+ qla8044_get_minidump(vha);
+ else
+ ql_log(ql_log_fatal, vha, 0xb14c,
+ "Minidump disabled.\n");
+
+ qla8044_process_init_seq(vha);
+
+ if (qla8044_copy_bootloader(vha)) {
+ ql_log(ql_log_fatal, vha, 0xb0ab,
+ "%s: Copy bootloader, firmware restart failed!\n",
+ __func__);
+ ret_val = QLA_FUNCTION_FAILED;
+ goto exit_restart;
+ }
+
+ /*
+ * Loads F/W from flash
+ */
+ qla8044_wr_reg(ha, QLA8044_FW_IMAGE_VALID, QLA8044_BOOT_FROM_FLASH);
+
+ qla8044_process_start_seq(vha);
+
+exit_restart:
+ return ret_val;
+}
+
+/*
+ * qla8044_check_cmd_peg_status - Check peg status to see if Peg is
+ * initialized.
+ *
+ * @ha : Pointer to adapter structure
+ *
+ * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
+ */
+static int
+qla8044_check_cmd_peg_status(struct scsi_qla_host *vha)
+{
+ uint32_t val, ret_val = QLA_FUNCTION_FAILED;
+ int retries = CRB_CMDPEG_CHECK_RETRY_COUNT;
+ struct qla_hw_data *ha = vha->hw;
+
+ do {
+ val = qla8044_rd_reg(ha, QLA8044_CMDPEG_STATE);
+ if (val == PHAN_INITIALIZE_COMPLETE) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb0ac,
+ "%s: Command Peg initialization "
+ "complete! state=0x%x\n", __func__, val);
+ ret_val = QLA_SUCCESS;
+ break;
+ }
+ msleep(CRB_CMDPEG_CHECK_DELAY);
+ } while (--retries);
+
+ return ret_val;
+}
+
+static int
+qla8044_start_firmware(struct scsi_qla_host *vha)
+{
+ int ret_val = QLA_SUCCESS;
+
+ if (qla8044_restart(vha)) {
+ ql_log(ql_log_fatal, vha, 0xb0ad,
+ "%s: Restart Error!!!, Need Reset!!!\n",
+ __func__);
+ ret_val = QLA_FUNCTION_FAILED;
+ goto exit_start_fw;
+ } else
+ ql_dbg(ql_dbg_p3p, vha, 0xb0af,
+ "%s: Restart done!\n", __func__);
+
+ ret_val = qla8044_check_cmd_peg_status(vha);
+ if (ret_val) {
+ ql_log(ql_log_fatal, vha, 0xb0b0,
+ "%s: Peg not initialized!\n", __func__);
+ ret_val = QLA_FUNCTION_FAILED;
+ }
+
+exit_start_fw:
+ return ret_val;
+}
+
+void
+qla8044_clear_drv_active(struct scsi_qla_host *vha)
+{
+ uint32_t drv_active;
+ struct qla_hw_data *ha = vha->hw;
+
+ drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
+ drv_active &= ~(1 << (ha->portnum));
+
+ ql_log(ql_log_info, vha, 0xb0b1,
+ "%s(%ld): drv_active: 0x%08x\n",
+ __func__, vha->host_no, drv_active);
+
+ qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, drv_active);
+}
+
+/*
+ * qla8044_device_bootstrap - Initialize device, set DEV_READY, start fw
+ * @ha: pointer to adapter structure
+ *
+ * Note: IDC lock must be held upon entry
+ **/
+static int
+qla8044_device_bootstrap(struct scsi_qla_host *vha)
+{
+ int rval = QLA_FUNCTION_FAILED;
+ int i;
+ uint32_t old_count = 0, count = 0;
+ int need_reset = 0;
+ uint32_t idc_ctrl;
+ struct qla_hw_data *ha = vha->hw;
+
+ need_reset = qla8044_need_reset(vha);
+
+ if (!need_reset) {
+ old_count = qla8044_rd_direct(vha,
+ QLA8044_PEG_ALIVE_COUNTER_INDEX);
+
+ for (i = 0; i < 10; i++) {
+ msleep(200);
+
+ count = qla8044_rd_direct(vha,
+ QLA8044_PEG_ALIVE_COUNTER_INDEX);
+ if (count != old_count) {
+ rval = QLA_SUCCESS;
+ goto dev_ready;
+ }
+ }
+ qla8044_flash_lock_recovery(vha);
+ } else {
+ /* We are trying to perform a recovery here. */
+ if (ha->flags.isp82xx_fw_hung)
+ qla8044_flash_lock_recovery(vha);
+ }
+
+ /* set to DEV_INITIALIZING */
+ ql_log(ql_log_info, vha, 0xb0b2,
+ "%s: HW State: INITIALIZING\n", __func__);
+ qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+ QLA8XXX_DEV_INITIALIZING);
+
+ qla8044_idc_unlock(ha);
+ rval = qla8044_start_firmware(vha);
+ qla8044_idc_lock(ha);
+
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_info, vha, 0xb0b3,
+ "%s: HW State: FAILED\n", __func__);
+ qla8044_clear_drv_active(vha);
+ qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+ QLA8XXX_DEV_FAILED);
+ return rval;
+ }
+
+ /* For ISP8044, If IDC_CTRL GRACEFUL_RESET_BIT1 is set , reset it after
+ * device goes to INIT state. */
+ idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
+ if (idc_ctrl & GRACEFUL_RESET_BIT1) {
+ qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL,
+ (idc_ctrl & ~GRACEFUL_RESET_BIT1));
+ ha->fw_dumped = 0;
+ }
+
+dev_ready:
+ ql_log(ql_log_info, vha, 0xb0b4,
+ "%s: HW State: READY\n", __func__);
+ qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX, QLA8XXX_DEV_READY);
+
+ return rval;
+}
+
+/*-------------------------Reset Sequence Functions-----------------------*/
+static void
+qla8044_dump_reset_seq_hdr(struct scsi_qla_host *vha)
+{
+ u8 *phdr;
+
+ if (!vha->reset_tmplt.buff) {
+ ql_log(ql_log_fatal, vha, 0xb0b5,
+ "%s: Error Invalid reset_seq_template\n", __func__);
+ return;
+ }
+
+ phdr = vha->reset_tmplt.buff;
+ ql_dbg(ql_dbg_p3p, vha, 0xb0b6,
+ "Reset Template :\n\t0x%X 0x%X 0x%X 0x%X"
+ "0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n"
+ "\t0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n\n",
+ *phdr, *(phdr+1), *(phdr+2), *(phdr+3), *(phdr+4),
+ *(phdr+5), *(phdr+6), *(phdr+7), *(phdr + 8),
+ *(phdr+9), *(phdr+10), *(phdr+11), *(phdr+12),
+ *(phdr+13), *(phdr+14), *(phdr+15));
+}
+
+/*
+ * qla8044_reset_seq_checksum_test - Validate Reset Sequence template.
+ *
+ * @ha : Pointer to adapter structure
+ *
+ * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
+ */
+static int
+qla8044_reset_seq_checksum_test(struct scsi_qla_host *vha)
+{
+ uint32_t sum = 0;
+ uint16_t *buff = (uint16_t *)vha->reset_tmplt.buff;
+ int u16_count = vha->reset_tmplt.hdr->size / sizeof(uint16_t);
+
+ while (u16_count-- > 0)
+ sum += *buff++;
+
+ while (sum >> 16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ /* checksum of 0 indicates a valid template */
+ if (~sum) {
+ return QLA_SUCCESS;
+ } else {
+ ql_log(ql_log_fatal, vha, 0xb0b7,
+ "%s: Reset seq checksum failed\n", __func__);
+ return QLA_FUNCTION_FAILED;
+ }
+}
+
+/*
+ * qla8044_read_reset_template - Read Reset Template from Flash, validate
+ * the template and store offsets of stop/start/init offsets in ha->reset_tmplt.
+ *
+ * @ha : Pointer to adapter structure
+ */
+void
+qla8044_read_reset_template(struct scsi_qla_host *vha)
+{
+ uint8_t *p_buff;
+ uint32_t addr, tmplt_hdr_def_size, tmplt_hdr_size;
+
+ vha->reset_tmplt.seq_error = 0;
+ vha->reset_tmplt.buff = vmalloc(QLA8044_RESTART_TEMPLATE_SIZE);
+ if (vha->reset_tmplt.buff == NULL) {
+ ql_log(ql_log_fatal, vha, 0xb0b8,
+ "%s: Failed to allocate reset template resources\n",
+ __func__);
+ goto exit_read_reset_template;
+ }
+
+ p_buff = vha->reset_tmplt.buff;
+ addr = QLA8044_RESET_TEMPLATE_ADDR;
+
+ tmplt_hdr_def_size =
+ sizeof(struct qla8044_reset_template_hdr) / sizeof(uint32_t);
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0b9,
+ "%s: Read template hdr size %d from Flash\n",
+ __func__, tmplt_hdr_def_size);
+
+ /* Copy template header from flash */
+ if (qla8044_read_flash_data(vha, p_buff, addr, tmplt_hdr_def_size)) {
+ ql_log(ql_log_fatal, vha, 0xb0ba,
+ "%s: Failed to read reset template\n", __func__);
+ goto exit_read_template_error;
+ }
+
+ vha->reset_tmplt.hdr =
+ (struct qla8044_reset_template_hdr *) vha->reset_tmplt.buff;
+
+ /* Validate the template header size and signature */
+ tmplt_hdr_size = vha->reset_tmplt.hdr->hdr_size/sizeof(uint32_t);
+ if ((tmplt_hdr_size != tmplt_hdr_def_size) ||
+ (vha->reset_tmplt.hdr->signature != RESET_TMPLT_HDR_SIGNATURE)) {
+ ql_log(ql_log_fatal, vha, 0xb0bb,
+ "%s: Template Header size invalid %d "
+ "tmplt_hdr_def_size %d!!!\n", __func__,
+ tmplt_hdr_size, tmplt_hdr_def_size);
+ goto exit_read_template_error;
+ }
+
+ addr = QLA8044_RESET_TEMPLATE_ADDR + vha->reset_tmplt.hdr->hdr_size;
+ p_buff = vha->reset_tmplt.buff + vha->reset_tmplt.hdr->hdr_size;
+ tmplt_hdr_def_size = (vha->reset_tmplt.hdr->size -
+ vha->reset_tmplt.hdr->hdr_size)/sizeof(uint32_t);
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0bc,
+ "%s: Read rest of the template size %d\n",
+ __func__, vha->reset_tmplt.hdr->size);
+
+ /* Copy rest of the template */
+ if (qla8044_read_flash_data(vha, p_buff, addr, tmplt_hdr_def_size)) {
+ ql_log(ql_log_fatal, vha, 0xb0bd,
+ "%s: Failed to read reset tempelate\n", __func__);
+ goto exit_read_template_error;
+ }
+
+ /* Integrity check */
+ if (qla8044_reset_seq_checksum_test(vha)) {
+ ql_log(ql_log_fatal, vha, 0xb0be,
+ "%s: Reset Seq checksum failed!\n", __func__);
+ goto exit_read_template_error;
+ }
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0bf,
+ "%s: Reset Seq checksum passed! Get stop, "
+ "start and init seq offsets\n", __func__);
+
+ /* Get STOP, START, INIT sequence offsets */
+ vha->reset_tmplt.init_offset = vha->reset_tmplt.buff +
+ vha->reset_tmplt.hdr->init_seq_offset;
+
+ vha->reset_tmplt.start_offset = vha->reset_tmplt.buff +
+ vha->reset_tmplt.hdr->start_seq_offset;
+
+ vha->reset_tmplt.stop_offset = vha->reset_tmplt.buff +
+ vha->reset_tmplt.hdr->hdr_size;
+
+ qla8044_dump_reset_seq_hdr(vha);
+
+ goto exit_read_reset_template;
+
+exit_read_template_error:
+ vfree(vha->reset_tmplt.buff);
+
+exit_read_reset_template:
+ return;
+}
+
+void
+qla8044_set_idc_dontreset(struct scsi_qla_host *vha)
+{
+ uint32_t idc_ctrl;
+ struct qla_hw_data *ha = vha->hw;
+
+ idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
+ idc_ctrl |= DONTRESET_BIT0;
+ ql_dbg(ql_dbg_p3p, vha, 0xb0c0,
+ "%s: idc_ctrl = %d\n", __func__, idc_ctrl);
+ qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, idc_ctrl);
+}
+
+inline void
+qla8044_set_rst_ready(struct scsi_qla_host *vha)
+{
+ uint32_t drv_state;
+ struct qla_hw_data *ha = vha->hw;
+
+ drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+
+ /* For ISP8044, drv_active register has 1 bit per function,
+ * shift 1 by func_num to set a bit for the function.*/
+ drv_state |= (1 << ha->portnum);
+
+ ql_log(ql_log_info, vha, 0xb0c1,
+ "%s(%ld): drv_state: 0x%08x\n",
+ __func__, vha->host_no, drv_state);
+ qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, drv_state);
+}
+
+/**
+ * qla8044_need_reset_handler - Code to start reset sequence
+ * @ha: pointer to adapter structure
+ *
+ * Note: IDC lock must be held upon entry
+ **/
+static void
+qla8044_need_reset_handler(struct scsi_qla_host *vha)
+{
+ uint32_t dev_state = 0, drv_state, drv_active;
+ unsigned long reset_timeout, dev_init_timeout;
+ struct qla_hw_data *ha = vha->hw;
+
+ ql_log(ql_log_fatal, vha, 0xb0c2,
+ "%s: Performing ISP error recovery\n", __func__);
+
+ if (vha->flags.online) {
+ qla8044_idc_unlock(ha);
+ qla2x00_abort_isp_cleanup(vha);
+ ha->isp_ops->get_flash_version(vha, vha->req->ring);
+ ha->isp_ops->nvram_config(vha);
+ qla8044_idc_lock(ha);
+ }
+
+ if (!ha->flags.nic_core_reset_owner) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb0c3,
+ "%s(%ld): reset acknowledged\n",
+ __func__, vha->host_no);
+ qla8044_set_rst_ready(vha);
+
+ /* Non-reset owners ACK Reset and wait for device INIT state
+ * as part of Reset Recovery by Reset Owner
+ */
+ dev_init_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
+
+ do {
+ if (time_after_eq(jiffies, dev_init_timeout)) {
+ ql_log(ql_log_info, vha, 0xb0c4,
+ "%s: Non Reset owner DEV INIT "
+ "TIMEOUT!\n", __func__);
+ break;
+ }
+
+ qla8044_idc_unlock(ha);
+ msleep(1000);
+ qla8044_idc_lock(ha);
+
+ dev_state = qla8044_rd_direct(vha,
+ QLA8044_CRB_DEV_STATE_INDEX);
+ } while (dev_state == QLA8XXX_DEV_NEED_RESET);
+ } else {
+ qla8044_set_rst_ready(vha);
+
+ /* wait for 10 seconds for reset ack from all functions */
+ reset_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
+
+ drv_state = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_STATE_INDEX);
+ drv_active = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_ACTIVE_INDEX);
+
+ ql_log(ql_log_info, vha, 0xb0c5,
+ "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n",
+ __func__, vha->host_no, drv_state, drv_active);
+
+ while (drv_state != drv_active) {
+ if (time_after_eq(jiffies, reset_timeout)) {
+ ql_log(ql_log_info, vha, 0xb0c6,
+ "%s: RESET TIMEOUT!"
+ "drv_state: 0x%08x, drv_active: 0x%08x\n",
+ QLA2XXX_DRIVER_NAME, drv_state, drv_active);
+ break;
+ }
+
+ qla8044_idc_unlock(ha);
+ msleep(1000);
+ qla8044_idc_lock(ha);
+
+ drv_state = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_STATE_INDEX);
+ drv_active = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_ACTIVE_INDEX);
+ }
+
+ if (drv_state != drv_active) {
+ ql_log(ql_log_info, vha, 0xb0c7,
+ "%s(%ld): Reset_owner turning off drv_active "
+ "of non-acking function 0x%x\n", __func__,
+ vha->host_no, (drv_active ^ drv_state));
+ drv_active = drv_active & drv_state;
+ qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX,
+ drv_active);
+ }
+
+ /*
+ * Clear RESET OWNER, will be set at next reset
+ * by next RST_OWNER
+ */
+ ha->flags.nic_core_reset_owner = 0;
+
+ /* Start Reset Recovery */
+ qla8044_device_bootstrap(vha);
+ }
+}
+
+static void
+qla8044_set_drv_active(struct scsi_qla_host *vha)
+{
+ uint32_t drv_active;
+ struct qla_hw_data *ha = vha->hw;
+
+ drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
+
+ /* For ISP8044, drv_active register has 1 bit per function,
+ * shift 1 by func_num to set a bit for the function.*/
+ drv_active |= (1 << ha->portnum);
+
+ ql_log(ql_log_info, vha, 0xb0c8,
+ "%s(%ld): drv_active: 0x%08x\n",
+ __func__, vha->host_no, drv_active);
+ qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, drv_active);
+}
+
+static void
+qla8044_clear_idc_dontreset(struct scsi_qla_host *vha)
+{
+ uint32_t idc_ctrl;
+ struct qla_hw_data *ha = vha->hw;
+
+ idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
+ idc_ctrl &= ~DONTRESET_BIT0;
+ ql_log(ql_log_info, vha, 0xb0c9,
+ "%s: idc_ctrl = %d\n", __func__,
+ idc_ctrl);
+ qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, idc_ctrl);
+}
+
+static int
+qla8044_set_idc_ver(struct scsi_qla_host *vha)
+{
+ int idc_ver;
+ uint32_t drv_active;
+ int rval = QLA_SUCCESS;
+ struct qla_hw_data *ha = vha->hw;
+
+ drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
+ if (drv_active == (1 << ha->portnum)) {
+ idc_ver = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_IDC_VERSION_INDEX);
+ idc_ver &= (~0xFF);
+ idc_ver |= QLA8044_IDC_VER_MAJ_VALUE;
+ qla8044_wr_direct(vha, QLA8044_CRB_DRV_IDC_VERSION_INDEX,
+ idc_ver);
+ ql_log(ql_log_info, vha, 0xb0ca,
+ "%s: IDC version updated to %d\n",
+ __func__, idc_ver);
+ } else {
+ idc_ver = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_IDC_VERSION_INDEX);
+ idc_ver &= 0xFF;
+ if (QLA8044_IDC_VER_MAJ_VALUE != idc_ver) {
+ ql_log(ql_log_info, vha, 0xb0cb,
+ "%s: qla4xxx driver IDC version %d "
+ "is not compatible with IDC version %d "
+ "of other drivers!\n",
+ __func__, QLA8044_IDC_VER_MAJ_VALUE,
+ idc_ver);
+ rval = QLA_FUNCTION_FAILED;
+ goto exit_set_idc_ver;
+ }
+ }
+
+ /* Update IDC_MINOR_VERSION */
+ idc_ver = qla8044_rd_reg(ha, QLA8044_CRB_IDC_VER_MINOR);
+ idc_ver &= ~(0x03 << (ha->portnum * 2));
+ idc_ver |= (QLA8044_IDC_VER_MIN_VALUE << (ha->portnum * 2));
+ qla8044_wr_reg(ha, QLA8044_CRB_IDC_VER_MINOR, idc_ver);
+
+exit_set_idc_ver:
+ return rval;
+}
+
+static int
+qla8044_update_idc_reg(struct scsi_qla_host *vha)
+{
+ uint32_t drv_active;
+ int rval = QLA_SUCCESS;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (vha->flags.init_done)
+ goto exit_update_idc_reg;
+
+ qla8044_idc_lock(ha);
+ qla8044_set_drv_active(vha);
+
+ drv_active = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_ACTIVE_INDEX);
+
+ /* If we are the first driver to load and
+ * ql2xdontresethba is not set, clear IDC_CTRL BIT0. */
+ if ((drv_active == (1 << ha->portnum)) && !ql2xdontresethba)
+ qla8044_clear_idc_dontreset(vha);
+
+ rval = qla8044_set_idc_ver(vha);
+ if (rval == QLA_FUNCTION_FAILED)
+ qla8044_clear_drv_active(vha);
+ qla8044_idc_unlock(ha);
+
+exit_update_idc_reg:
+ return rval;
+}
+
+/**
+ * qla8044_need_qsnt_handler - Code to start qsnt
+ * @ha: pointer to adapter structure
+ **/
+static void
+qla8044_need_qsnt_handler(struct scsi_qla_host *vha)
+{
+ unsigned long qsnt_timeout;
+ uint32_t drv_state, drv_active, dev_state;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (vha->flags.online)
+ qla2x00_quiesce_io(vha);
+ else
+ return;
+
+ qla8044_set_qsnt_ready(vha);
+
+ /* Wait for 30 secs for all functions to ack qsnt mode */
+ qsnt_timeout = jiffies + (QSNT_ACK_TOV * HZ);
+ drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+ drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
+
+ /* Shift drv_active by 1 to match drv_state. As quiescent ready bit
+ position is at bit 1 and drv active is at bit 0 */
+ drv_active = drv_active << 1;
+
+ while (drv_state != drv_active) {
+ if (time_after_eq(jiffies, qsnt_timeout)) {
+ /* Other functions did not ack, changing state to
+ * DEV_READY
+ */
+ clear_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
+ qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+ QLA8XXX_DEV_READY);
+ qla8044_clear_qsnt_ready(vha);
+ ql_log(ql_log_info, vha, 0xb0cc,
+ "Timeout waiting for quiescent ack!!!\n");
+ return;
+ }
+ qla8044_idc_unlock(ha);
+ msleep(1000);
+ qla8044_idc_lock(ha);
+
+ drv_state = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_STATE_INDEX);
+ drv_active = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_ACTIVE_INDEX);
+ drv_active = drv_active << 1;
+ }
+
+ /* All functions have Acked. Set quiescent state */
+ dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+
+ if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT) {
+ qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+ QLA8XXX_DEV_QUIESCENT);
+ ql_log(ql_log_info, vha, 0xb0cd,
+ "%s: HW State: QUIESCENT\n", __func__);
+ }
+}
+
+/*
+ * qla8044_device_state_handler - Adapter state machine
+ * @ha: pointer to host adapter structure.
+ *
+ * Note: IDC lock must be UNLOCKED upon entry
+ **/
+int
+qla8044_device_state_handler(struct scsi_qla_host *vha)
+{
+ uint32_t dev_state;
+ int rval = QLA_SUCCESS;
+ unsigned long dev_init_timeout;
+ struct qla_hw_data *ha = vha->hw;
+
+ rval = qla8044_update_idc_reg(vha);
+ if (rval == QLA_FUNCTION_FAILED)
+ goto exit_error;
+
+ dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+ ql_dbg(ql_dbg_p3p, vha, 0xb0ce,
+ "Device state is 0x%x = %s\n",
+ dev_state, dev_state < MAX_STATES ?
+ qdev_state(dev_state) : "Unknown");
+
+ /* wait for 30 seconds for device to go ready */
+ dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ);
+
+ qla8044_idc_lock(ha);
+
+ while (1) {
+ if (time_after_eq(jiffies, dev_init_timeout)) {
+ ql_log(ql_log_warn, vha, 0xb0cf,
+ "%s: Device Init Failed 0x%x = %s\n",
+ QLA2XXX_DRIVER_NAME, dev_state,
+ dev_state < MAX_STATES ?
+ qdev_state(dev_state) : "Unknown");
+
+ qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+ QLA8XXX_DEV_FAILED);
+ }
+
+ dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+ ql_log(ql_log_info, vha, 0xb0d0,
+ "Device state is 0x%x = %s\n",
+ dev_state, dev_state < MAX_STATES ?
+ qdev_state(dev_state) : "Unknown");
+
+ /* NOTE: Make sure idc unlocked upon exit of switch statement */
+ switch (dev_state) {
+ case QLA8XXX_DEV_READY:
+ ha->flags.nic_core_reset_owner = 0;
+ goto exit;
+ case QLA8XXX_DEV_COLD:
+ rval = qla8044_device_bootstrap(vha);
+ goto exit;
+ case QLA8XXX_DEV_INITIALIZING:
+ qla8044_idc_unlock(ha);
+ msleep(1000);
+ qla8044_idc_lock(ha);
+ break;
+ case QLA8XXX_DEV_NEED_RESET:
+ /* For ISP8044, if NEED_RESET is set by any driver,
+ * it should be honored, irrespective of IDC_CTRL
+ * DONTRESET_BIT0 */
+ qla8044_need_reset_handler(vha);
+ break;
+ case QLA8XXX_DEV_NEED_QUIESCENT:
+ /* idc locked/unlocked in handler */
+ qla8044_need_qsnt_handler(vha);
+
+ /* Reset the init timeout after qsnt handler */
+ dev_init_timeout = jiffies +
+ (ha->fcoe_reset_timeout * HZ);
+ break;
+ case QLA8XXX_DEV_QUIESCENT:
+ ql_log(ql_log_info, vha, 0xb0d1,
+ "HW State: QUIESCENT\n");
+
+ qla8044_idc_unlock(ha);
+ msleep(1000);
+ qla8044_idc_lock(ha);
+
+ /* Reset the init timeout after qsnt handler */
+ dev_init_timeout = jiffies +
+ (ha->fcoe_reset_timeout * HZ);
+ break;
+ case QLA8XXX_DEV_FAILED:
+ ha->flags.nic_core_reset_owner = 0;
+ qla8044_idc_unlock(ha);
+ qla8xxx_dev_failed_handler(vha);
+ rval = QLA_FUNCTION_FAILED;
+ qla8044_idc_lock(ha);
+ goto exit;
+ default:
+ qla8044_idc_unlock(ha);
+ qla8xxx_dev_failed_handler(vha);
+ rval = QLA_FUNCTION_FAILED;
+ qla8044_idc_lock(ha);
+ goto exit;
+ }
+ }
+exit:
+ qla8044_idc_unlock(ha);
+
+exit_error:
+ return rval;
+}
+
+/**
+ * qla4_8xxx_check_temp - Check the ISP82XX temperature.
+ * @ha: adapter block pointer.
+ *
+ * Note: The caller should not hold the idc lock.
+ **/
+static int
+qla8044_check_temp(struct scsi_qla_host *vha)
+{
+ uint32_t temp, temp_state, temp_val;
+ int status = QLA_SUCCESS;
+
+ temp = qla8044_rd_direct(vha, QLA8044_CRB_TEMP_STATE_INDEX);
+ temp_state = qla82xx_get_temp_state(temp);
+ temp_val = qla82xx_get_temp_val(temp);
+
+ if (temp_state == QLA82XX_TEMP_PANIC) {
+ ql_log(ql_log_warn, vha, 0xb0d2,
+ "Device temperature %d degrees C"
+ " exceeds maximum allowed. Hardware has been shut"
+ " down\n", temp_val);
+ status = QLA_FUNCTION_FAILED;
+ return status;
+ } else if (temp_state == QLA82XX_TEMP_WARN) {
+ ql_log(ql_log_warn, vha, 0xb0d3,
+ "Device temperature %d"
+ " degrees C exceeds operating range."
+ " Immediate action needed.\n", temp_val);
+ }
+ return 0;
+}
+
+int qla8044_read_temperature(scsi_qla_host_t *vha)
+{
+ uint32_t temp;
+
+ temp = qla8044_rd_direct(vha, QLA8044_CRB_TEMP_STATE_INDEX);
+ return qla82xx_get_temp_val(temp);
+}
+
+/**
+ * qla8044_check_fw_alive - Check firmware health
+ * @ha: Pointer to host adapter structure.
+ *
+ * Context: Interrupt
+ **/
+int
+qla8044_check_fw_alive(struct scsi_qla_host *vha)
+{
+ uint32_t fw_heartbeat_counter;
+ uint32_t halt_status1, halt_status2;
+ int status = QLA_SUCCESS;
+
+ fw_heartbeat_counter = qla8044_rd_direct(vha,
+ QLA8044_PEG_ALIVE_COUNTER_INDEX);
+
+ /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */
+ if (fw_heartbeat_counter == 0xffffffff) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb0d4,
+ "scsi%ld: %s: Device in frozen "
+ "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n",
+ vha->host_no, __func__);
+ return status;
+ }
+
+ if (vha->fw_heartbeat_counter == fw_heartbeat_counter) {
+ vha->seconds_since_last_heartbeat++;
+ /* FW not alive after 2 seconds */
+ if (vha->seconds_since_last_heartbeat == 2) {
+ vha->seconds_since_last_heartbeat = 0;
+ halt_status1 = qla8044_rd_direct(vha,
+ QLA8044_PEG_HALT_STATUS1_INDEX);
+ halt_status2 = qla8044_rd_direct(vha,
+ QLA8044_PEG_HALT_STATUS2_INDEX);
+
+ ql_log(ql_log_info, vha, 0xb0d5,
+ "scsi(%ld): %s, ISP8044 "
+ "Dumping hw/fw registers:\n"
+ " PEG_HALT_STATUS1: 0x%x, "
+ "PEG_HALT_STATUS2: 0x%x,\n",
+ vha->host_no, __func__, halt_status1,
+ halt_status2);
+ status = QLA_FUNCTION_FAILED;
+ }
+ } else
+ vha->seconds_since_last_heartbeat = 0;
+
+ vha->fw_heartbeat_counter = fw_heartbeat_counter;
+ return status;
+}
+
+void
+qla8044_watchdog(struct scsi_qla_host *vha)
+{
+ uint32_t dev_state, halt_status;
+ int halt_status_unrecoverable = 0;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* don't poll if reset is going on or FW hang in quiescent state */
+ if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+ test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+ test_bit(ISP_ABORT_RETRY, &vha->dpc_flags) ||
+ test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags))) {
+ dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+
+ if (qla8044_check_temp(vha)) {
+ set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags);
+ ha->flags.isp82xx_fw_hung = 1;
+ qla2xxx_wake_dpc(vha);
+ } else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
+ !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) {
+ ql_log(ql_log_info, vha, 0xb0d6,
+ "%s: HW State: NEED RESET!\n",
+ __func__);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ } else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
+ !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
+ ql_log(ql_log_info, vha, 0xb0d7,
+ "%s: HW State: NEED QUIES detected!\n",
+ __func__);
+ set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ } else {
+ /* Check firmware health */
+ if (qla8044_check_fw_alive(vha)) {
+ halt_status = qla8044_rd_direct(vha,
+ QLA8044_PEG_HALT_STATUS1_INDEX);
+ if (halt_status &
+ QLA8044_HALT_STATUS_FW_RESET) {
+ ql_log(ql_log_fatal, vha,
+ 0xb0d8, "%s: Firmware "
+ "error detected device "
+ "is being reset\n",
+ __func__);
+ } else if (halt_status &
+ QLA8044_HALT_STATUS_UNRECOVERABLE) {
+ halt_status_unrecoverable = 1;
+ }
+
+ /* Since we cannot change dev_state in interrupt
+ * context, set appropriate DPC flag then wakeup
+ * DPC */
+ if (halt_status_unrecoverable) {
+ set_bit(ISP_UNRECOVERABLE,
+ &vha->dpc_flags);
+ } else {
+ if (dev_state ==
+ QLA8XXX_DEV_QUIESCENT) {
+ set_bit(FCOE_CTX_RESET_NEEDED,
+ &vha->dpc_flags);
+ ql_log(ql_log_info, vha, 0xb0d9,
+ "%s: FW CONTEXT Reset "
+ "needed!\n", __func__);
+ } else {
+ ql_log(ql_log_info, vha,
+ 0xb0da, "%s: "
+ "detect abort needed\n",
+ __func__);
+ set_bit(ISP_ABORT_NEEDED,
+ &vha->dpc_flags);
+ qla82xx_clear_pending_mbx(vha);
+ }
+ }
+ ha->flags.isp82xx_fw_hung = 1;
+ ql_log(ql_log_warn, vha, 0xb10a,
+ "Firmware hung.\n");
+ qla2xxx_wake_dpc(vha);
+ }
+ }
+
+ }
+}
+
+static int
+qla8044_minidump_process_control(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr)
+{
+ struct qla8044_minidump_entry_crb *crb_entry;
+ uint32_t read_value, opcode, poll_time, addr, index;
+ uint32_t crb_addr, rval = QLA_SUCCESS;
+ unsigned long wtime;
+ struct qla8044_minidump_template_hdr *tmplt_hdr;
+ int i;
+ struct qla_hw_data *ha = vha->hw;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0dd, "Entering fn: %s\n", __func__);
+ tmplt_hdr = (struct qla8044_minidump_template_hdr *)
+ ha->md_tmplt_hdr;
+ crb_entry = (struct qla8044_minidump_entry_crb *)entry_hdr;
+
+ crb_addr = crb_entry->addr;
+ for (i = 0; i < crb_entry->op_count; i++) {
+ opcode = crb_entry->crb_ctrl.opcode;
+
+ if (opcode & QLA82XX_DBG_OPCODE_WR) {
+ qla8044_wr_reg_indirect(vha, crb_addr,
+ crb_entry->value_1);
+ opcode &= ~QLA82XX_DBG_OPCODE_WR;
+ }
+
+ if (opcode & QLA82XX_DBG_OPCODE_RW) {
+ qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
+ qla8044_wr_reg_indirect(vha, crb_addr, read_value);
+ opcode &= ~QLA82XX_DBG_OPCODE_RW;
+ }
+
+ if (opcode & QLA82XX_DBG_OPCODE_AND) {
+ qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
+ read_value &= crb_entry->value_2;
+ opcode &= ~QLA82XX_DBG_OPCODE_AND;
+ if (opcode & QLA82XX_DBG_OPCODE_OR) {
+ read_value |= crb_entry->value_3;
+ opcode &= ~QLA82XX_DBG_OPCODE_OR;
+ }
+ qla8044_wr_reg_indirect(vha, crb_addr, read_value);
+ }
+ if (opcode & QLA82XX_DBG_OPCODE_OR) {
+ qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
+ read_value |= crb_entry->value_3;
+ qla8044_wr_reg_indirect(vha, crb_addr, read_value);
+ opcode &= ~QLA82XX_DBG_OPCODE_OR;
+ }
+ if (opcode & QLA82XX_DBG_OPCODE_POLL) {
+ poll_time = crb_entry->crb_strd.poll_timeout;
+ wtime = jiffies + poll_time;
+ qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
+
+ do {
+ if ((read_value & crb_entry->value_2) ==
+ crb_entry->value_1) {
+ break;
+ } else if (time_after_eq(jiffies, wtime)) {
+ /* capturing dump failed */
+ rval = QLA_FUNCTION_FAILED;
+ break;
+ } else {
+ qla8044_rd_reg_indirect(vha,
+ crb_addr, &read_value);
+ }
+ } while (1);
+ opcode &= ~QLA82XX_DBG_OPCODE_POLL;
+ }
+
+ if (opcode & QLA82XX_DBG_OPCODE_RDSTATE) {
+ if (crb_entry->crb_strd.state_index_a) {
+ index = crb_entry->crb_strd.state_index_a;
+ addr = tmplt_hdr->saved_state_array[index];
+ } else {
+ addr = crb_addr;
+ }
+
+ qla8044_rd_reg_indirect(vha, addr, &read_value);
+ index = crb_entry->crb_ctrl.state_index_v;
+ tmplt_hdr->saved_state_array[index] = read_value;
+ opcode &= ~QLA82XX_DBG_OPCODE_RDSTATE;
+ }
+
+ if (opcode & QLA82XX_DBG_OPCODE_WRSTATE) {
+ if (crb_entry->crb_strd.state_index_a) {
+ index = crb_entry->crb_strd.state_index_a;
+ addr = tmplt_hdr->saved_state_array[index];
+ } else {
+ addr = crb_addr;
+ }
+
+ if (crb_entry->crb_ctrl.state_index_v) {
+ index = crb_entry->crb_ctrl.state_index_v;
+ read_value =
+ tmplt_hdr->saved_state_array[index];
+ } else {
+ read_value = crb_entry->value_1;
+ }
+
+ qla8044_wr_reg_indirect(vha, addr, read_value);
+ opcode &= ~QLA82XX_DBG_OPCODE_WRSTATE;
+ }
+
+ if (opcode & QLA82XX_DBG_OPCODE_MDSTATE) {
+ index = crb_entry->crb_ctrl.state_index_v;
+ read_value = tmplt_hdr->saved_state_array[index];
+ read_value <<= crb_entry->crb_ctrl.shl;
+ read_value >>= crb_entry->crb_ctrl.shr;
+ if (crb_entry->value_2)
+ read_value &= crb_entry->value_2;
+ read_value |= crb_entry->value_3;
+ read_value += crb_entry->value_1;
+ tmplt_hdr->saved_state_array[index] = read_value;
+ opcode &= ~QLA82XX_DBG_OPCODE_MDSTATE;
+ }
+ crb_addr += crb_entry->crb_strd.addr_stride;
+ }
+ return rval;
+}
+
+static void
+qla8044_minidump_process_rdcrb(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+ uint32_t r_addr, r_stride, loop_cnt, i, r_value;
+ struct qla8044_minidump_entry_crb *crb_hdr;
+ uint32_t *data_ptr = *d_ptr;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0de, "Entering fn: %s\n", __func__);
+ crb_hdr = (struct qla8044_minidump_entry_crb *)entry_hdr;
+ r_addr = crb_hdr->addr;
+ r_stride = crb_hdr->crb_strd.addr_stride;
+ loop_cnt = crb_hdr->op_count;
+
+ for (i = 0; i < loop_cnt; i++) {
+ qla8044_rd_reg_indirect(vha, r_addr, &r_value);
+ *data_ptr++ = r_addr;
+ *data_ptr++ = r_value;
+ r_addr += r_stride;
+ }
+ *d_ptr = data_ptr;
+}
+
+static int
+qla8044_minidump_process_rdmem(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+ uint32_t r_addr, r_value, r_data;
+ uint32_t i, j, loop_cnt;
+ struct qla8044_minidump_entry_rdmem *m_hdr;
+ unsigned long flags;
+ uint32_t *data_ptr = *d_ptr;
+ struct qla_hw_data *ha = vha->hw;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0df, "Entering fn: %s\n", __func__);
+ m_hdr = (struct qla8044_minidump_entry_rdmem *)entry_hdr;
+ r_addr = m_hdr->read_addr;
+ loop_cnt = m_hdr->read_data_size/16;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0f0,
+ "[%s]: Read addr: 0x%x, read_data_size: 0x%x\n",
+ __func__, r_addr, m_hdr->read_data_size);
+
+ if (r_addr & 0xf) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb0f1,
+ "[%s]: Read addr 0x%x not 16 bytes alligned\n",
+ __func__, r_addr);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ if (m_hdr->read_data_size % 16) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb0f2,
+ "[%s]: Read data[0x%x] not multiple of 16 bytes\n",
+ __func__, m_hdr->read_data_size);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0f3,
+ "[%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x\n",
+ __func__, r_addr, m_hdr->read_data_size, loop_cnt);
+
+ write_lock_irqsave(&ha->hw_lock, flags);
+ for (i = 0; i < loop_cnt; i++) {
+ qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_LO, r_addr);
+ r_value = 0;
+ qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_HI, r_value);
+ r_value = MIU_TA_CTL_ENABLE;
+ qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, r_value);
+ r_value = MIU_TA_CTL_START_ENABLE;
+ qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, r_value);
+
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ qla8044_rd_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL,
+ &r_value);
+ if ((r_value & MIU_TA_CTL_BUSY) == 0)
+ break;
+ }
+
+ if (j >= MAX_CTL_CHECK) {
+ printk_ratelimited(KERN_ERR
+ "%s: failed to read through agent\n", __func__);
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+ return QLA_SUCCESS;
+ }
+
+ for (j = 0; j < 4; j++) {
+ qla8044_rd_reg_indirect(vha, MD_MIU_TEST_AGT_RDDATA[j],
+ &r_data);
+ *data_ptr++ = r_data;
+ }
+
+ r_addr += 16;
+ }
+ write_unlock_irqrestore(&ha->hw_lock, flags);
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0f4,
+ "Leaving fn: %s datacount: 0x%x\n",
+ __func__, (loop_cnt * 16));
+
+ *d_ptr = data_ptr;
+ return QLA_SUCCESS;
+}
+
+/* ISP83xx flash read for _RDROM _BOARD */
+static uint32_t
+qla8044_minidump_process_rdrom(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+ uint32_t fl_addr, u32_count, rval;
+ struct qla8044_minidump_entry_rdrom *rom_hdr;
+ uint32_t *data_ptr = *d_ptr;
+
+ rom_hdr = (struct qla8044_minidump_entry_rdrom *)entry_hdr;
+ fl_addr = rom_hdr->read_addr;
+ u32_count = (rom_hdr->read_data_size)/sizeof(uint32_t);
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0f5, "[%s]: fl_addr: 0x%x, count: 0x%x\n",
+ __func__, fl_addr, u32_count);
+
+ rval = qla8044_lockless_flash_read_u32(vha, fl_addr,
+ (u8 *)(data_ptr), u32_count);
+
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_fatal, vha, 0xb0f6,
+ "%s: Flash Read Error,Count=%d\n", __func__, u32_count);
+ return QLA_FUNCTION_FAILED;
+ } else {
+ data_ptr += u32_count;
+ *d_ptr = data_ptr;
+ return QLA_SUCCESS;
+ }
+}
+
+static void
+qla8044_mark_entry_skipped(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr, int index)
+{
+ entry_hdr->d_ctrl.driver_flags |= QLA82XX_DBG_SKIPPED_FLAG;
+
+ ql_log(ql_log_info, vha, 0xb0f7,
+ "scsi(%ld): Skipping entry[%d]: ETYPE[0x%x]-ELEVEL[0x%x]\n",
+ vha->host_no, index, entry_hdr->entry_type,
+ entry_hdr->d_ctrl.entry_capture_mask);
+}
+
+static int
+qla8044_minidump_process_l2tag(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr,
+ uint32_t **d_ptr)
+{
+ uint32_t addr, r_addr, c_addr, t_r_addr;
+ uint32_t i, k, loop_count, t_value, r_cnt, r_value;
+ unsigned long p_wait, w_time, p_mask;
+ uint32_t c_value_w, c_value_r;
+ struct qla8044_minidump_entry_cache *cache_hdr;
+ int rval = QLA_FUNCTION_FAILED;
+ uint32_t *data_ptr = *d_ptr;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0f8, "Entering fn: %s\n", __func__);
+ cache_hdr = (struct qla8044_minidump_entry_cache *)entry_hdr;
+
+ loop_count = cache_hdr->op_count;
+ r_addr = cache_hdr->read_addr;
+ c_addr = cache_hdr->control_addr;
+ c_value_w = cache_hdr->cache_ctrl.write_value;
+
+ t_r_addr = cache_hdr->tag_reg_addr;
+ t_value = cache_hdr->addr_ctrl.init_tag_value;
+ r_cnt = cache_hdr->read_ctrl.read_addr_cnt;
+ p_wait = cache_hdr->cache_ctrl.poll_wait;
+ p_mask = cache_hdr->cache_ctrl.poll_mask;
+
+ for (i = 0; i < loop_count; i++) {
+ qla8044_wr_reg_indirect(vha, t_r_addr, t_value);
+ if (c_value_w)
+ qla8044_wr_reg_indirect(vha, c_addr, c_value_w);
+
+ if (p_mask) {
+ w_time = jiffies + p_wait;
+ do {
+ qla8044_rd_reg_indirect(vha, c_addr,
+ &c_value_r);
+ if ((c_value_r & p_mask) == 0) {
+ break;
+ } else if (time_after_eq(jiffies, w_time)) {
+ /* capturing dump failed */
+ return rval;
+ }
+ } while (1);
+ }
+
+ addr = r_addr;
+ for (k = 0; k < r_cnt; k++) {
+ qla8044_rd_reg_indirect(vha, addr, &r_value);
+ *data_ptr++ = r_value;
+ addr += cache_hdr->read_ctrl.read_addr_stride;
+ }
+ t_value += cache_hdr->addr_ctrl.tag_value_stride;
+ }
+ *d_ptr = data_ptr;
+ return QLA_SUCCESS;
+}
+
+static void
+qla8044_minidump_process_l1cache(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+ uint32_t addr, r_addr, c_addr, t_r_addr;
+ uint32_t i, k, loop_count, t_value, r_cnt, r_value;
+ uint32_t c_value_w;
+ struct qla8044_minidump_entry_cache *cache_hdr;
+ uint32_t *data_ptr = *d_ptr;
+
+ cache_hdr = (struct qla8044_minidump_entry_cache *)entry_hdr;
+ loop_count = cache_hdr->op_count;
+ r_addr = cache_hdr->read_addr;
+ c_addr = cache_hdr->control_addr;
+ c_value_w = cache_hdr->cache_ctrl.write_value;
+
+ t_r_addr = cache_hdr->tag_reg_addr;
+ t_value = cache_hdr->addr_ctrl.init_tag_value;
+ r_cnt = cache_hdr->read_ctrl.read_addr_cnt;
+
+ for (i = 0; i < loop_count; i++) {
+ qla8044_wr_reg_indirect(vha, t_r_addr, t_value);
+ qla8044_wr_reg_indirect(vha, c_addr, c_value_w);
+ addr = r_addr;
+ for (k = 0; k < r_cnt; k++) {
+ qla8044_rd_reg_indirect(vha, addr, &r_value);
+ *data_ptr++ = r_value;
+ addr += cache_hdr->read_ctrl.read_addr_stride;
+ }
+ t_value += cache_hdr->addr_ctrl.tag_value_stride;
+ }
+ *d_ptr = data_ptr;
+}
+
+static void
+qla8044_minidump_process_rdocm(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+ uint32_t r_addr, r_stride, loop_cnt, i, r_value;
+ struct qla8044_minidump_entry_rdocm *ocm_hdr;
+ uint32_t *data_ptr = *d_ptr;
+ struct qla_hw_data *ha = vha->hw;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0f9, "Entering fn: %s\n", __func__);
+
+ ocm_hdr = (struct qla8044_minidump_entry_rdocm *)entry_hdr;
+ r_addr = ocm_hdr->read_addr;
+ r_stride = ocm_hdr->read_addr_stride;
+ loop_cnt = ocm_hdr->op_count;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0fa,
+ "[%s]: r_addr: 0x%x, r_stride: 0x%x, loop_cnt: 0x%x\n",
+ __func__, r_addr, r_stride, loop_cnt);
+
+ for (i = 0; i < loop_cnt; i++) {
+ r_value = readl((void __iomem *)(r_addr + ha->nx_pcibase));
+ *data_ptr++ = r_value;
+ r_addr += r_stride;
+ }
+ ql_dbg(ql_dbg_p3p, vha, 0xb0fb, "Leaving fn: %s datacount: 0x%lx\n",
+ __func__, (long unsigned int) (loop_cnt * sizeof(uint32_t)));
+
+ *d_ptr = data_ptr;
+}
+
+static void
+qla8044_minidump_process_rdmux(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr,
+ uint32_t **d_ptr)
+{
+ uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value;
+ struct qla8044_minidump_entry_mux *mux_hdr;
+ uint32_t *data_ptr = *d_ptr;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0fc, "Entering fn: %s\n", __func__);
+
+ mux_hdr = (struct qla8044_minidump_entry_mux *)entry_hdr;
+ r_addr = mux_hdr->read_addr;
+ s_addr = mux_hdr->select_addr;
+ s_stride = mux_hdr->select_value_stride;
+ s_value = mux_hdr->select_value;
+ loop_cnt = mux_hdr->op_count;
+
+ for (i = 0; i < loop_cnt; i++) {
+ qla8044_wr_reg_indirect(vha, s_addr, s_value);
+ qla8044_rd_reg_indirect(vha, r_addr, &r_value);
+ *data_ptr++ = s_value;
+ *data_ptr++ = r_value;
+ s_value += s_stride;
+ }
+ *d_ptr = data_ptr;
+}
+
+static void
+qla8044_minidump_process_queue(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr,
+ uint32_t **d_ptr)
+{
+ uint32_t s_addr, r_addr;
+ uint32_t r_stride, r_value, r_cnt, qid = 0;
+ uint32_t i, k, loop_cnt;
+ struct qla8044_minidump_entry_queue *q_hdr;
+ uint32_t *data_ptr = *d_ptr;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb0fd, "Entering fn: %s\n", __func__);
+ q_hdr = (struct qla8044_minidump_entry_queue *)entry_hdr;
+ s_addr = q_hdr->select_addr;
+ r_cnt = q_hdr->rd_strd.read_addr_cnt;
+ r_stride = q_hdr->rd_strd.read_addr_stride;
+ loop_cnt = q_hdr->op_count;
+
+ for (i = 0; i < loop_cnt; i++) {
+ qla8044_wr_reg_indirect(vha, s_addr, qid);
+ r_addr = q_hdr->read_addr;
+ for (k = 0; k < r_cnt; k++) {
+ qla8044_rd_reg_indirect(vha, r_addr, &r_value);
+ *data_ptr++ = r_value;
+ r_addr += r_stride;
+ }
+ qid += q_hdr->q_strd.queue_id_stride;
+ }
+ *d_ptr = data_ptr;
+}
+
+/* ISP83xx functions to process new minidump entries... */
+static uint32_t
+qla8044_minidump_process_pollrd(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr,
+ uint32_t **d_ptr)
+{
+ uint32_t r_addr, s_addr, s_value, r_value, poll_wait, poll_mask;
+ uint16_t s_stride, i;
+ struct qla8044_minidump_entry_pollrd *pollrd_hdr;
+ uint32_t *data_ptr = *d_ptr;
+
+ pollrd_hdr = (struct qla8044_minidump_entry_pollrd *) entry_hdr;
+ s_addr = pollrd_hdr->select_addr;
+ r_addr = pollrd_hdr->read_addr;
+ s_value = pollrd_hdr->select_value;
+ s_stride = pollrd_hdr->select_value_stride;
+
+ poll_wait = pollrd_hdr->poll_wait;
+ poll_mask = pollrd_hdr->poll_mask;
+
+ for (i = 0; i < pollrd_hdr->op_count; i++) {
+ qla8044_wr_reg_indirect(vha, s_addr, s_value);
+ poll_wait = pollrd_hdr->poll_wait;
+ while (1) {
+ qla8044_rd_reg_indirect(vha, s_addr, &r_value);
+ if ((r_value & poll_mask) != 0) {
+ break;
+ } else {
+ usleep_range(1000, 1100);
+ if (--poll_wait == 0) {
+ ql_log(ql_log_fatal, vha, 0xb0fe,
+ "%s: TIMEOUT\n", __func__);
+ goto error;
+ }
+ }
+ }
+ qla8044_rd_reg_indirect(vha, r_addr, &r_value);
+ *data_ptr++ = s_value;
+ *data_ptr++ = r_value;
+
+ s_value += s_stride;
+ }
+ *d_ptr = data_ptr;
+ return QLA_SUCCESS;
+
+error:
+ return QLA_FUNCTION_FAILED;
+}
+
+static void
+qla8044_minidump_process_rdmux2(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+ uint32_t sel_val1, sel_val2, t_sel_val, data, i;
+ uint32_t sel_addr1, sel_addr2, sel_val_mask, read_addr;
+ struct qla8044_minidump_entry_rdmux2 *rdmux2_hdr;
+ uint32_t *data_ptr = *d_ptr;
+
+ rdmux2_hdr = (struct qla8044_minidump_entry_rdmux2 *) entry_hdr;
+ sel_val1 = rdmux2_hdr->select_value_1;
+ sel_val2 = rdmux2_hdr->select_value_2;
+ sel_addr1 = rdmux2_hdr->select_addr_1;
+ sel_addr2 = rdmux2_hdr->select_addr_2;
+ sel_val_mask = rdmux2_hdr->select_value_mask;
+ read_addr = rdmux2_hdr->read_addr;
+
+ for (i = 0; i < rdmux2_hdr->op_count; i++) {
+ qla8044_wr_reg_indirect(vha, sel_addr1, sel_val1);
+ t_sel_val = sel_val1 & sel_val_mask;
+ *data_ptr++ = t_sel_val;
+
+ qla8044_wr_reg_indirect(vha, sel_addr2, t_sel_val);
+ qla8044_rd_reg_indirect(vha, read_addr, &data);
+
+ *data_ptr++ = data;
+
+ qla8044_wr_reg_indirect(vha, sel_addr1, sel_val2);
+ t_sel_val = sel_val2 & sel_val_mask;
+ *data_ptr++ = t_sel_val;
+
+ qla8044_wr_reg_indirect(vha, sel_addr2, t_sel_val);
+ qla8044_rd_reg_indirect(vha, read_addr, &data);
+
+ *data_ptr++ = data;
+
+ sel_val1 += rdmux2_hdr->select_value_stride;
+ sel_val2 += rdmux2_hdr->select_value_stride;
+ }
+
+ *d_ptr = data_ptr;
+}
+
+static uint32_t
+qla8044_minidump_process_pollrdmwr(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr,
+ uint32_t **d_ptr)
+{
+ uint32_t poll_wait, poll_mask, r_value, data;
+ uint32_t addr_1, addr_2, value_1, value_2;
+ struct qla8044_minidump_entry_pollrdmwr *poll_hdr;
+ uint32_t *data_ptr = *d_ptr;
+
+ poll_hdr = (struct qla8044_minidump_entry_pollrdmwr *) entry_hdr;
+ addr_1 = poll_hdr->addr_1;
+ addr_2 = poll_hdr->addr_2;
+ value_1 = poll_hdr->value_1;
+ value_2 = poll_hdr->value_2;
+ poll_mask = poll_hdr->poll_mask;
+
+ qla8044_wr_reg_indirect(vha, addr_1, value_1);
+
+ poll_wait = poll_hdr->poll_wait;
+ while (1) {
+ qla8044_rd_reg_indirect(vha, addr_1, &r_value);
+
+ if ((r_value & poll_mask) != 0) {
+ break;
+ } else {
+ usleep_range(1000, 1100);
+ if (--poll_wait == 0) {
+ ql_log(ql_log_fatal, vha, 0xb0ff,
+ "%s: TIMEOUT\n", __func__);
+ goto error;
+ }
+ }
+ }
+
+ qla8044_rd_reg_indirect(vha, addr_2, &data);
+ data &= poll_hdr->modify_mask;
+ qla8044_wr_reg_indirect(vha, addr_2, data);
+ qla8044_wr_reg_indirect(vha, addr_1, value_2);
+
+ poll_wait = poll_hdr->poll_wait;
+ while (1) {
+ qla8044_rd_reg_indirect(vha, addr_1, &r_value);
+
+ if ((r_value & poll_mask) != 0) {
+ break;
+ } else {
+ usleep_range(1000, 1100);
+ if (--poll_wait == 0) {
+ ql_log(ql_log_fatal, vha, 0xb100,
+ "%s: TIMEOUT2\n", __func__);
+ goto error;
+ }
+ }
+ }
+
+ *data_ptr++ = addr_2;
+ *data_ptr++ = data;
+
+ *d_ptr = data_ptr;
+
+ return QLA_SUCCESS;
+
+error:
+ return QLA_FUNCTION_FAILED;
+}
+
+#define ISP8044_PEX_DMA_ENGINE_INDEX 8
+#define ISP8044_PEX_DMA_BASE_ADDRESS 0x77320000
+#define ISP8044_PEX_DMA_NUM_OFFSET 0x10000
+#define ISP8044_PEX_DMA_CMD_ADDR_LOW 0x0
+#define ISP8044_PEX_DMA_CMD_ADDR_HIGH 0x04
+#define ISP8044_PEX_DMA_CMD_STS_AND_CNTRL 0x08
+
+#define ISP8044_PEX_DMA_READ_SIZE (16 * 1024)
+#define ISP8044_PEX_DMA_MAX_WAIT (100 * 100) /* Max wait of 100 msecs */
+
+static int
+qla8044_check_dma_engine_state(struct scsi_qla_host *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ int rval = QLA_SUCCESS;
+ uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
+ uint64_t dma_base_addr = 0;
+ struct qla8044_minidump_template_hdr *tmplt_hdr = NULL;
+
+ tmplt_hdr = ha->md_tmplt_hdr;
+ dma_eng_num =
+ tmplt_hdr->saved_state_array[ISP8044_PEX_DMA_ENGINE_INDEX];
+ dma_base_addr = ISP8044_PEX_DMA_BASE_ADDRESS +
+ (dma_eng_num * ISP8044_PEX_DMA_NUM_OFFSET);
+
+ /* Read the pex-dma's command-status-and-control register. */
+ rval = qla8044_rd_reg_indirect(vha,
+ (dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL),
+ &cmd_sts_and_cntrl);
+ if (rval)
+ return QLA_FUNCTION_FAILED;
+
+ /* Check if requested pex-dma engine is available. */
+ if (cmd_sts_and_cntrl & BIT_31)
+ return QLA_SUCCESS;
+
+ return QLA_FUNCTION_FAILED;
+}
+
+static int
+qla8044_start_pex_dma(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_rdmem_pex_dma *m_hdr)
+{
+ struct qla_hw_data *ha = vha->hw;
+ int rval = QLA_SUCCESS, wait = 0;
+ uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
+ uint64_t dma_base_addr = 0;
+ struct qla8044_minidump_template_hdr *tmplt_hdr = NULL;
+
+ tmplt_hdr = ha->md_tmplt_hdr;
+ dma_eng_num =
+ tmplt_hdr->saved_state_array[ISP8044_PEX_DMA_ENGINE_INDEX];
+ dma_base_addr = ISP8044_PEX_DMA_BASE_ADDRESS +
+ (dma_eng_num * ISP8044_PEX_DMA_NUM_OFFSET);
+
+ rval = qla8044_wr_reg_indirect(vha,
+ dma_base_addr + ISP8044_PEX_DMA_CMD_ADDR_LOW,
+ m_hdr->desc_card_addr);
+ if (rval)
+ goto error_exit;
+
+ rval = qla8044_wr_reg_indirect(vha,
+ dma_base_addr + ISP8044_PEX_DMA_CMD_ADDR_HIGH, 0);
+ if (rval)
+ goto error_exit;
+
+ rval = qla8044_wr_reg_indirect(vha,
+ dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL,
+ m_hdr->start_dma_cmd);
+ if (rval)
+ goto error_exit;
+
+ /* Wait for dma operation to complete. */
+ for (wait = 0; wait < ISP8044_PEX_DMA_MAX_WAIT; wait++) {
+ rval = qla8044_rd_reg_indirect(vha,
+ (dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL),
+ &cmd_sts_and_cntrl);
+ if (rval)
+ goto error_exit;
+
+ if ((cmd_sts_and_cntrl & BIT_1) == 0)
+ break;
+
+ udelay(10);
+ }
+
+ /* Wait a max of 100 ms, otherwise fallback to rdmem entry read */
+ if (wait >= ISP8044_PEX_DMA_MAX_WAIT) {
+ rval = QLA_FUNCTION_FAILED;
+ goto error_exit;
+ }
+
+error_exit:
+ return rval;
+}
+
+static int
+qla8044_minidump_pex_dma_read(struct scsi_qla_host *vha,
+ struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+ struct qla_hw_data *ha = vha->hw;
+ int rval = QLA_SUCCESS;
+ struct qla8044_minidump_entry_rdmem_pex_dma *m_hdr = NULL;
+ uint32_t chunk_size, read_size;
+ uint8_t *data_ptr = (uint8_t *)*d_ptr;
+ void *rdmem_buffer = NULL;
+ dma_addr_t rdmem_dma;
+ struct qla8044_pex_dma_descriptor dma_desc;
+
+ rval = qla8044_check_dma_engine_state(vha);
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb147,
+ "DMA engine not available. Fallback to rdmem-read.\n");
+ return QLA_FUNCTION_FAILED;
+ }
+
+ m_hdr = (void *)entry_hdr;
+
+ rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev,
+ ISP8044_PEX_DMA_READ_SIZE, &rdmem_dma, GFP_KERNEL);
+ if (!rdmem_buffer) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb148,
+ "Unable to allocate rdmem dma buffer\n");
+ return QLA_FUNCTION_FAILED;
+ }
+
+ /* Prepare pex-dma descriptor to be written to MS memory. */
+ /* dma-desc-cmd layout:
+ * 0-3: dma-desc-cmd 0-3
+ * 4-7: pcid function number
+ * 8-15: dma-desc-cmd 8-15
+ * dma_bus_addr: dma buffer address
+ * cmd.read_data_size: amount of data-chunk to be read.
+ */
+ dma_desc.cmd.dma_desc_cmd = (m_hdr->dma_desc_cmd & 0xff0f);
+ dma_desc.cmd.dma_desc_cmd |=
+ ((PCI_FUNC(ha->pdev->devfn) & 0xf) << 0x4);
+
+ dma_desc.dma_bus_addr = rdmem_dma;
+ dma_desc.cmd.read_data_size = chunk_size = ISP8044_PEX_DMA_READ_SIZE;
+ read_size = 0;
+
+ /*
+ * Perform rdmem operation using pex-dma.
+ * Prepare dma in chunks of ISP8044_PEX_DMA_READ_SIZE.
+ */
+ while (read_size < m_hdr->read_data_size) {
+ if (m_hdr->read_data_size - read_size <
+ ISP8044_PEX_DMA_READ_SIZE) {
+ chunk_size = (m_hdr->read_data_size - read_size);
+ dma_desc.cmd.read_data_size = chunk_size;
+ }
+
+ dma_desc.src_addr = m_hdr->read_addr + read_size;
+
+ /* Prepare: Write pex-dma descriptor to MS memory. */
+ rval = qla8044_ms_mem_write_128b(vha,
+ m_hdr->desc_card_addr, (void *)&dma_desc,
+ (sizeof(struct qla8044_pex_dma_descriptor)/16));
+ if (rval) {
+ ql_log(ql_log_warn, vha, 0xb14a,
+ "%s: Error writing rdmem-dma-init to MS !!!\n",
+ __func__);
+ goto error_exit;
+ }
+ ql_dbg(ql_dbg_p3p, vha, 0xb14b,
+ "%s: Dma-descriptor: Instruct for rdmem dma "
+ "(chunk_size 0x%x).\n", __func__, chunk_size);
+
+ /* Execute: Start pex-dma operation. */
+ rval = qla8044_start_pex_dma(vha, m_hdr);
+ if (rval)
+ goto error_exit;
+
+ memcpy(data_ptr, rdmem_buffer, chunk_size);
+ data_ptr += chunk_size;
+ read_size += chunk_size;
+ }
+
+ *d_ptr = (void *)data_ptr;
+
+error_exit:
+ if (rdmem_buffer)
+ dma_free_coherent(&ha->pdev->dev, ISP8044_PEX_DMA_READ_SIZE,
+ rdmem_buffer, rdmem_dma);
+
+ return rval;
+}
+
+/*
+ *
+ * qla8044_collect_md_data - Retrieve firmware minidump data.
+ * @ha: pointer to adapter structure
+ **/
+int
+qla8044_collect_md_data(struct scsi_qla_host *vha)
+{
+ int num_entry_hdr = 0;
+ struct qla8044_minidump_entry_hdr *entry_hdr;
+ struct qla8044_minidump_template_hdr *tmplt_hdr;
+ uint32_t *data_ptr;
+ uint32_t data_collected = 0, f_capture_mask;
+ int i, rval = QLA_FUNCTION_FAILED;
+ uint64_t now;
+ uint32_t timestamp, idc_control;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!ha->md_dump) {
+ ql_log(ql_log_info, vha, 0xb101,
+ "%s(%ld) No buffer to dump\n",
+ __func__, vha->host_no);
+ return rval;
+ }
+
+ if (ha->fw_dumped) {
+ ql_log(ql_log_warn, vha, 0xb10d,
+ "Firmware has been previously dumped (%p) "
+ "-- ignoring request.\n", ha->fw_dump);
+ goto md_failed;
+ }
+
+ ha->fw_dumped = 0;
+
+ if (!ha->md_tmplt_hdr || !ha->md_dump) {
+ ql_log(ql_log_warn, vha, 0xb10e,
+ "Memory not allocated for minidump capture\n");
+ goto md_failed;
+ }
+
+ qla8044_idc_lock(ha);
+ idc_control = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
+ if (idc_control & GRACEFUL_RESET_BIT1) {
+ ql_log(ql_log_warn, vha, 0xb112,
+ "Forced reset from application, "
+ "ignore minidump capture\n");
+ qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL,
+ (idc_control & ~GRACEFUL_RESET_BIT1));
+ qla8044_idc_unlock(ha);
+
+ goto md_failed;
+ }
+ qla8044_idc_unlock(ha);
+
+ if (qla82xx_validate_template_chksum(vha)) {
+ ql_log(ql_log_info, vha, 0xb109,
+ "Template checksum validation error\n");
+ goto md_failed;
+ }
+
+ tmplt_hdr = (struct qla8044_minidump_template_hdr *)
+ ha->md_tmplt_hdr;
+ data_ptr = (uint32_t *)((uint8_t *)ha->md_dump);
+ num_entry_hdr = tmplt_hdr->num_of_entries;
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb11a,
+ "Capture Mask obtained: 0x%x\n", tmplt_hdr->capture_debug_level);
+
+ f_capture_mask = tmplt_hdr->capture_debug_level & 0xFF;
+
+ /* Validate whether required debug level is set */
+ if ((f_capture_mask & 0x3) != 0x3) {
+ ql_log(ql_log_warn, vha, 0xb10f,
+ "Minimum required capture mask[0x%x] level not set\n",
+ f_capture_mask);
+
+ }
+ tmplt_hdr->driver_capture_mask = ql2xmdcapmask;
+ ql_log(ql_log_info, vha, 0xb102,
+ "[%s]: starting data ptr: %p\n",
+ __func__, data_ptr);
+ ql_log(ql_log_info, vha, 0xb10b,
+ "[%s]: no of entry headers in Template: 0x%x\n",
+ __func__, num_entry_hdr);
+ ql_log(ql_log_info, vha, 0xb10c,
+ "[%s]: Total_data_size 0x%x, %d obtained\n",
+ __func__, ha->md_dump_size, ha->md_dump_size);
+
+ /* Update current timestamp before taking dump */
+ now = get_jiffies_64();
+ timestamp = (u32)(jiffies_to_msecs(now) / 1000);
+ tmplt_hdr->driver_timestamp = timestamp;
+
+ entry_hdr = (struct qla8044_minidump_entry_hdr *)
+ (((uint8_t *)ha->md_tmplt_hdr) + tmplt_hdr->first_entry_offset);
+ tmplt_hdr->saved_state_array[QLA8044_SS_OCM_WNDREG_INDEX] =
+ tmplt_hdr->ocm_window_reg[ha->portnum];
+
+ /* Walk through the entry headers - validate/perform required action */
+ for (i = 0; i < num_entry_hdr; i++) {
+ if (data_collected > ha->md_dump_size) {
+ ql_log(ql_log_info, vha, 0xb103,
+ "Data collected: [0x%x], "
+ "Total Dump size: [0x%x]\n",
+ data_collected, ha->md_dump_size);
+ return rval;
+ }
+
+ if (!(entry_hdr->d_ctrl.entry_capture_mask &
+ ql2xmdcapmask)) {
+ entry_hdr->d_ctrl.driver_flags |=
+ QLA82XX_DBG_SKIPPED_FLAG;
+ goto skip_nxt_entry;
+ }
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb104,
+ "Data collected: [0x%x], Dump size left:[0x%x]\n",
+ data_collected,
+ (ha->md_dump_size - data_collected));
+
+ /* Decode the entry type and take required action to capture
+ * debug data
+ */
+ switch (entry_hdr->entry_type) {
+ case QLA82XX_RDEND:
+ qla8044_mark_entry_skipped(vha, entry_hdr, i);
+ break;
+ case QLA82XX_CNTRL:
+ rval = qla8044_minidump_process_control(vha,
+ entry_hdr);
+ if (rval != QLA_SUCCESS) {
+ qla8044_mark_entry_skipped(vha, entry_hdr, i);
+ goto md_failed;
+ }
+ break;
+ case QLA82XX_RDCRB:
+ qla8044_minidump_process_rdcrb(vha,
+ entry_hdr, &data_ptr);
+ break;
+ case QLA82XX_RDMEM:
+ rval = qla8044_minidump_pex_dma_read(vha,
+ entry_hdr, &data_ptr);
+ if (rval != QLA_SUCCESS) {
+ rval = qla8044_minidump_process_rdmem(vha,
+ entry_hdr, &data_ptr);
+ if (rval != QLA_SUCCESS) {
+ qla8044_mark_entry_skipped(vha,
+ entry_hdr, i);
+ goto md_failed;
+ }
+ }
+ break;
+ case QLA82XX_BOARD:
+ case QLA82XX_RDROM:
+ rval = qla8044_minidump_process_rdrom(vha,
+ entry_hdr, &data_ptr);
+ if (rval != QLA_SUCCESS) {
+ qla8044_mark_entry_skipped(vha,
+ entry_hdr, i);
+ }
+ break;
+ case QLA82XX_L2DTG:
+ case QLA82XX_L2ITG:
+ case QLA82XX_L2DAT:
+ case QLA82XX_L2INS:
+ rval = qla8044_minidump_process_l2tag(vha,
+ entry_hdr, &data_ptr);
+ if (rval != QLA_SUCCESS) {
+ qla8044_mark_entry_skipped(vha, entry_hdr, i);
+ goto md_failed;
+ }
+ break;
+ case QLA8044_L1DTG:
+ case QLA8044_L1ITG:
+ case QLA82XX_L1DAT:
+ case QLA82XX_L1INS:
+ qla8044_minidump_process_l1cache(vha,
+ entry_hdr, &data_ptr);
+ break;
+ case QLA82XX_RDOCM:
+ qla8044_minidump_process_rdocm(vha,
+ entry_hdr, &data_ptr);
+ break;
+ case QLA82XX_RDMUX:
+ qla8044_minidump_process_rdmux(vha,
+ entry_hdr, &data_ptr);
+ break;
+ case QLA82XX_QUEUE:
+ qla8044_minidump_process_queue(vha,
+ entry_hdr, &data_ptr);
+ break;
+ case QLA8044_POLLRD:
+ rval = qla8044_minidump_process_pollrd(vha,
+ entry_hdr, &data_ptr);
+ if (rval != QLA_SUCCESS)
+ qla8044_mark_entry_skipped(vha, entry_hdr, i);
+ break;
+ case QLA8044_RDMUX2:
+ qla8044_minidump_process_rdmux2(vha,
+ entry_hdr, &data_ptr);
+ break;
+ case QLA8044_POLLRDMWR:
+ rval = qla8044_minidump_process_pollrdmwr(vha,
+ entry_hdr, &data_ptr);
+ if (rval != QLA_SUCCESS)
+ qla8044_mark_entry_skipped(vha, entry_hdr, i);
+ break;
+ case QLA82XX_RDNOP:
+ default:
+ qla8044_mark_entry_skipped(vha, entry_hdr, i);
+ break;
+ }
+
+ data_collected = (uint8_t *)data_ptr -
+ (uint8_t *)((uint8_t *)ha->md_dump);
+skip_nxt_entry:
+ /*
+ * next entry in the template
+ */
+ entry_hdr = (struct qla8044_minidump_entry_hdr *)
+ (((uint8_t *)entry_hdr) + entry_hdr->entry_size);
+ }
+
+ if (data_collected != ha->md_dump_size) {
+ ql_log(ql_log_info, vha, 0xb105,
+ "Dump data mismatch: Data collected: "
+ "[0x%x], total_data_size:[0x%x]\n",
+ data_collected, ha->md_dump_size);
+ goto md_failed;
+ }
+
+ ql_log(ql_log_info, vha, 0xb110,
+ "Firmware dump saved to temp buffer (%ld/%p %ld/%p).\n",
+ vha->host_no, ha->md_tmplt_hdr, vha->host_no, ha->md_dump);
+ ha->fw_dumped = 1;
+ qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
+
+
+ ql_log(ql_log_info, vha, 0xb106,
+ "Leaving fn: %s Last entry: 0x%x\n",
+ __func__, i);
+md_failed:
+ return rval;
+}
+
+void
+qla8044_get_minidump(struct scsi_qla_host *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!qla8044_collect_md_data(vha)) {
+ ha->fw_dumped = 1;
+ } else {
+ ql_log(ql_log_fatal, vha, 0xb0db,
+ "%s: Unable to collect minidump\n",
+ __func__);
+ }
+}
+
+static int
+qla8044_poll_flash_status_reg(struct scsi_qla_host *vha)
+{
+ uint32_t flash_status;
+ int retries = QLA8044_FLASH_READ_RETRY_COUNT;
+ int ret_val = QLA_SUCCESS;
+
+ while (retries--) {
+ ret_val = qla8044_rd_reg_indirect(vha, QLA8044_FLASH_STATUS,
+ &flash_status);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb13c,
+ "%s: Failed to read FLASH_STATUS reg.\n",
+ __func__);
+ break;
+ }
+ if ((flash_status & QLA8044_FLASH_STATUS_READY) ==
+ QLA8044_FLASH_STATUS_READY)
+ break;
+ msleep(QLA8044_FLASH_STATUS_REG_POLL_DELAY);
+ }
+
+ if (!retries)
+ ret_val = QLA_FUNCTION_FAILED;
+
+ return ret_val;
+}
+
+static int
+qla8044_write_flash_status_reg(struct scsi_qla_host *vha,
+ uint32_t data)
+{
+ int ret_val = QLA_SUCCESS;
+ uint32_t cmd;
+
+ cmd = vha->hw->fdt_wrt_sts_reg_cmd;
+
+ ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+ QLA8044_FLASH_STATUS_WRITE_DEF_SIG | cmd);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb125,
+ "%s: Failed to write to FLASH_ADDR.\n", __func__);
+ goto exit_func;
+ }
+
+ ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, data);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb126,
+ "%s: Failed to write to FLASH_WRDATA.\n", __func__);
+ goto exit_func;
+ }
+
+ ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
+ QLA8044_FLASH_SECOND_ERASE_MS_VAL);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb127,
+ "%s: Failed to write to FLASH_CONTROL.\n", __func__);
+ goto exit_func;
+ }
+
+ ret_val = qla8044_poll_flash_status_reg(vha);
+ if (ret_val)
+ ql_log(ql_log_warn, vha, 0xb128,
+ "%s: Error polling flash status reg.\n", __func__);
+
+exit_func:
+ return ret_val;
+}
+
+/*
+ * This function assumes that the flash lock is held.
+ */
+static int
+qla8044_unprotect_flash(scsi_qla_host_t *vha)
+{
+ int ret_val;
+ struct qla_hw_data *ha = vha->hw;
+
+ ret_val = qla8044_write_flash_status_reg(vha, ha->fdt_wrt_enable);
+ if (ret_val)
+ ql_log(ql_log_warn, vha, 0xb139,
+ "%s: Write flash status failed.\n", __func__);
+
+ return ret_val;
+}
+
+/*
+ * This function assumes that the flash lock is held.
+ */
+static int
+qla8044_protect_flash(scsi_qla_host_t *vha)
+{
+ int ret_val;
+ struct qla_hw_data *ha = vha->hw;
+
+ ret_val = qla8044_write_flash_status_reg(vha, ha->fdt_wrt_disable);
+ if (ret_val)
+ ql_log(ql_log_warn, vha, 0xb13b,
+ "%s: Write flash status failed.\n", __func__);
+
+ return ret_val;
+}
+
+
+static int
+qla8044_erase_flash_sector(struct scsi_qla_host *vha,
+ uint32_t sector_start_addr)
+{
+ uint32_t reversed_addr;
+ int ret_val = QLA_SUCCESS;
+
+ ret_val = qla8044_poll_flash_status_reg(vha);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb12e,
+ "%s: Poll flash status after erase failed..\n", __func__);
+ }
+
+ reversed_addr = (((sector_start_addr & 0xFF) << 16) |
+ (sector_start_addr & 0xFF00) |
+ ((sector_start_addr & 0xFF0000) >> 16));
+
+ ret_val = qla8044_wr_reg_indirect(vha,
+ QLA8044_FLASH_WRDATA, reversed_addr);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb12f,
+ "%s: Failed to write to FLASH_WRDATA.\n", __func__);
+ }
+ ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+ QLA8044_FLASH_ERASE_SIG | vha->hw->fdt_erase_cmd);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb130,
+ "%s: Failed to write to FLASH_ADDR.\n", __func__);
+ }
+ ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
+ QLA8044_FLASH_LAST_ERASE_MS_VAL);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb131,
+ "%s: Failed write to FLASH_CONTROL.\n", __func__);
+ }
+ ret_val = qla8044_poll_flash_status_reg(vha);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb132,
+ "%s: Poll flash status failed.\n", __func__);
+ }
+
+
+ return ret_val;
+}
+
+/*
+ * qla8044_flash_write_u32 - Write data to flash
+ *
+ * @ha : Pointer to adapter structure
+ * addr : Flash address to write to
+ * p_data : Data to be written
+ *
+ * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
+ *
+ * NOTE: Lock should be held on entry
+ */
+static int
+qla8044_flash_write_u32(struct scsi_qla_host *vha, uint32_t addr,
+ uint32_t *p_data)
+{
+ int ret_val = QLA_SUCCESS;
+
+ ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+ 0x00800000 | (addr >> 2));
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb134,
+ "%s: Failed write to FLASH_ADDR.\n", __func__);
+ goto exit_func;
+ }
+ ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *p_data);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb135,
+ "%s: Failed write to FLASH_WRDATA.\n", __func__);
+ goto exit_func;
+ }
+ ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL, 0x3D);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb136,
+ "%s: Failed write to FLASH_CONTROL.\n", __func__);
+ goto exit_func;
+ }
+ ret_val = qla8044_poll_flash_status_reg(vha);
+ if (ret_val) {
+ ql_log(ql_log_warn, vha, 0xb137,
+ "%s: Poll flash status failed.\n", __func__);
+ }
+
+exit_func:
+ return ret_val;
+}
+
+static int
+qla8044_write_flash_buffer_mode(scsi_qla_host_t *vha, uint32_t *dwptr,
+ uint32_t faddr, uint32_t dwords)
+{
+ int ret = QLA_FUNCTION_FAILED;
+ uint32_t spi_val;
+
+ if (dwords < QLA8044_MIN_OPTROM_BURST_DWORDS ||
+ dwords > QLA8044_MAX_OPTROM_BURST_DWORDS) {
+ ql_dbg(ql_dbg_user, vha, 0xb123,
+ "Got unsupported dwords = 0x%x.\n",
+ dwords);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL, &spi_val);
+ qla8044_wr_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL,
+ spi_val | QLA8044_FLASH_SPI_CTL);
+ qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+ QLA8044_FLASH_FIRST_TEMP_VAL);
+
+ /* First DWORD write to FLASH_WRDATA */
+ ret = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA,
+ *dwptr++);
+ qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
+ QLA8044_FLASH_FIRST_MS_PATTERN);
+
+ ret = qla8044_poll_flash_status_reg(vha);
+ if (ret) {
+ ql_log(ql_log_warn, vha, 0xb124,
+ "%s: Failed.\n", __func__);
+ goto exit_func;
+ }
+
+ dwords--;
+
+ qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+ QLA8044_FLASH_SECOND_TEMP_VAL);
+
+
+ /* Second to N-1 DWORDS writes */
+ while (dwords != 1) {
+ qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *dwptr++);
+ qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
+ QLA8044_FLASH_SECOND_MS_PATTERN);
+ ret = qla8044_poll_flash_status_reg(vha);
+ if (ret) {
+ ql_log(ql_log_warn, vha, 0xb129,
+ "%s: Failed.\n", __func__);
+ goto exit_func;
+ }
+ dwords--;
+ }
+
+ qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+ QLA8044_FLASH_FIRST_TEMP_VAL | (faddr >> 2));
+
+ /* Last DWORD write */
+ qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *dwptr++);
+ qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
+ QLA8044_FLASH_LAST_MS_PATTERN);
+ ret = qla8044_poll_flash_status_reg(vha);
+ if (ret) {
+ ql_log(ql_log_warn, vha, 0xb12a,
+ "%s: Failed.\n", __func__);
+ goto exit_func;
+ }
+ qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_STATUS, &spi_val);
+
+ if ((spi_val & QLA8044_FLASH_SPI_CTL) == QLA8044_FLASH_SPI_CTL) {
+ ql_log(ql_log_warn, vha, 0xb12b,
+ "%s: Failed.\n", __func__);
+ spi_val = 0;
+ /* Operation failed, clear error bit. */
+ qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL,
+ &spi_val);
+ qla8044_wr_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL,
+ spi_val | QLA8044_FLASH_SPI_CTL);
+ }
+exit_func:
+ return ret;
+}
+
+static int
+qla8044_write_flash_dword_mode(scsi_qla_host_t *vha, uint32_t *dwptr,
+ uint32_t faddr, uint32_t dwords)
+{
+ int ret = QLA_FUNCTION_FAILED;
+ uint32_t liter;
+
+ for (liter = 0; liter < dwords; liter++, faddr += 4, dwptr++) {
+ ret = qla8044_flash_write_u32(vha, faddr, dwptr);
+ if (ret) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb141,
+ "%s: flash address=%x data=%x.\n", __func__,
+ faddr, *dwptr);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int
+qla8044_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+ uint32_t offset, uint32_t length)
+{
+ int rval = QLA_FUNCTION_FAILED, i, burst_iter_count;
+ int dword_count, erase_sec_count;
+ uint32_t erase_offset;
+ uint8_t *p_cache, *p_src;
+
+ erase_offset = offset;
+
+ p_cache = kcalloc(length, sizeof(uint8_t), GFP_KERNEL);
+ if (!p_cache)
+ return QLA_FUNCTION_FAILED;
+
+ memcpy(p_cache, buf, length);
+ p_src = p_cache;
+ dword_count = length / sizeof(uint32_t);
+ /* Since the offset and legth are sector aligned, it will be always
+ * multiple of burst_iter_count (64)
+ */
+ burst_iter_count = dword_count / QLA8044_MAX_OPTROM_BURST_DWORDS;
+ erase_sec_count = length / QLA8044_SECTOR_SIZE;
+
+ /* Suspend HBA. */
+ scsi_block_requests(vha->host);
+ /* Lock and enable write for whole operation. */
+ qla8044_flash_lock(vha);
+ qla8044_unprotect_flash(vha);
+
+ /* Erasing the sectors */
+ for (i = 0; i < erase_sec_count; i++) {
+ rval = qla8044_erase_flash_sector(vha, erase_offset);
+ ql_dbg(ql_dbg_user, vha, 0xb138,
+ "Done erase of sector=0x%x.\n",
+ erase_offset);
+ if (rval) {
+ ql_log(ql_log_warn, vha, 0xb121,
+ "Failed to erase the sector having address: "
+ "0x%x.\n", erase_offset);
+ goto out;
+ }
+ erase_offset += QLA8044_SECTOR_SIZE;
+ }
+ ql_dbg(ql_dbg_user, vha, 0xb13f,
+ "Got write for addr = 0x%x length=0x%x.\n",
+ offset, length);
+
+ for (i = 0; i < burst_iter_count; i++) {
+
+ /* Go with write. */
+ rval = qla8044_write_flash_buffer_mode(vha, (uint32_t *)p_src,
+ offset, QLA8044_MAX_OPTROM_BURST_DWORDS);
+ if (rval) {
+ /* Buffer Mode failed skip to dword mode */
+ ql_log(ql_log_warn, vha, 0xb122,
+ "Failed to write flash in buffer mode, "
+ "Reverting to slow-write.\n");
+ rval = qla8044_write_flash_dword_mode(vha,
+ (uint32_t *)p_src, offset,
+ QLA8044_MAX_OPTROM_BURST_DWORDS);
+ }
+ p_src += sizeof(uint32_t) * QLA8044_MAX_OPTROM_BURST_DWORDS;
+ offset += sizeof(uint32_t) * QLA8044_MAX_OPTROM_BURST_DWORDS;
+ }
+ ql_dbg(ql_dbg_user, vha, 0xb133,
+ "Done writing.\n");
+
+out:
+ qla8044_protect_flash(vha);
+ qla8044_flash_unlock(vha);
+ scsi_unblock_requests(vha->host);
+ kfree(p_cache);
+
+ return rval;
+}
+
+#define LEG_INT_PTR_B31 (1 << 31)
+#define LEG_INT_PTR_B30 (1 << 30)
+#define PF_BITS_MASK (0xF << 16)
+/**
+ * qla8044_intr_handler() - Process interrupts for the ISP8044
+ * @irq:
+ * @dev_id: SCSI driver HA context
+ *
+ * Called by system whenever the host adapter generates an interrupt.
+ *
+ * Returns handled flag.
+ */
+irqreturn_t
+qla8044_intr_handler(int irq, void *dev_id)
+{
+ scsi_qla_host_t *vha;
+ struct qla_hw_data *ha;
+ struct rsp_que *rsp;
+ struct device_reg_82xx __iomem *reg;
+ int status = 0;
+ unsigned long flags;
+ unsigned long iter;
+ uint32_t stat;
+ uint16_t mb[4];
+ uint32_t leg_int_ptr = 0, pf_bit;
+
+ rsp = (struct rsp_que *) dev_id;
+ if (!rsp) {
+ ql_log(ql_log_info, NULL, 0xb143,
+ "%s(): NULL response queue pointer\n", __func__);
+ return IRQ_NONE;
+ }
+ ha = rsp->hw;
+ vha = pci_get_drvdata(ha->pdev);
+
+ if (unlikely(pci_channel_offline(ha->pdev)))
+ return IRQ_HANDLED;
+
+ leg_int_ptr = qla8044_rd_reg(ha, LEG_INTR_PTR_OFFSET);
+
+ /* Legacy interrupt is valid if bit31 of leg_int_ptr is set */
+ if (!(leg_int_ptr & (LEG_INT_PTR_B31))) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb144,
+ "%s: Legacy Interrupt Bit 31 not set, "
+ "spurious interrupt!\n", __func__);
+ return IRQ_NONE;
+ }
+
+ pf_bit = ha->portnum << 16;
+ /* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */
+ if ((leg_int_ptr & (PF_BITS_MASK)) != pf_bit) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb145,
+ "%s: Incorrect function ID 0x%x in "
+ "legacy interrupt register, "
+ "ha->pf_bit = 0x%x\n", __func__,
+ (leg_int_ptr & (PF_BITS_MASK)), pf_bit);
+ return IRQ_NONE;
+ }
+
+ /* To de-assert legacy interrupt, write 0 to Legacy Interrupt Trigger
+ * Control register and poll till Legacy Interrupt Pointer register
+ * bit32 is 0.
+ */
+ qla8044_wr_reg(ha, LEG_INTR_TRIG_OFFSET, 0);
+ do {
+ leg_int_ptr = qla8044_rd_reg(ha, LEG_INTR_PTR_OFFSET);
+ if ((leg_int_ptr & (PF_BITS_MASK)) != pf_bit)
+ break;
+ } while (leg_int_ptr & (LEG_INT_PTR_B30));
+
+ reg = &ha->iobase->isp82;
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (iter = 1; iter--; ) {
+
+ if (RD_REG_DWORD(&reg->host_int)) {
+ stat = RD_REG_DWORD(&reg->host_status);
+ if ((stat & HSRX_RISC_INT) == 0)
+ break;
+
+ switch (stat & 0xff) {
+ case 0x1:
+ case 0x2:
+ case 0x10:
+ case 0x11:
+ qla82xx_mbx_completion(vha, MSW(stat));
+ status |= MBX_INTERRUPT;
+ break;
+ case 0x12:
+ mb[0] = MSW(stat);
+ mb[1] = RD_REG_WORD(&reg->mailbox_out[1]);
+ mb[2] = RD_REG_WORD(&reg->mailbox_out[2]);
+ mb[3] = RD_REG_WORD(&reg->mailbox_out[3]);
+ qla2x00_async_event(vha, rsp, mb);
+ break;
+ case 0x13:
+ qla24xx_process_response_queue(vha, rsp);
+ break;
+ default:
+ ql_dbg(ql_dbg_p3p, vha, 0xb146,
+ "Unrecognized interrupt type "
+ "(%d).\n", stat & 0xff);
+ break;
+ }
+ }
+ WRT_REG_DWORD(&reg->host_int, 0);
+ }
+
+ qla2x00_handle_mbx_completion(ha, status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int
+qla8044_idc_dontreset(struct qla_hw_data *ha)
+{
+ uint32_t idc_ctrl;
+
+ idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
+ return idc_ctrl & DONTRESET_BIT0;
+}
+
+static void
+qla8044_clear_rst_ready(scsi_qla_host_t *vha)
+{
+ uint32_t drv_state;
+
+ drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+
+ /*
+ * For ISP8044, drv_active register has 1 bit per function,
+ * shift 1 by func_num to set a bit for the function.
+ * For ISP82xx, drv_active has 4 bits per function
+ */
+ drv_state &= ~(1 << vha->hw->portnum);
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb13d,
+ "drv_state: 0x%08x\n", drv_state);
+ qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, drv_state);
+}
+
+int
+qla8044_abort_isp(scsi_qla_host_t *vha)
+{
+ int rval;
+ uint32_t dev_state;
+ struct qla_hw_data *ha = vha->hw;
+
+ qla8044_idc_lock(ha);
+ dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+
+ if (ql2xdontresethba)
+ qla8044_set_idc_dontreset(vha);
+
+ /* If device_state is NEED_RESET, go ahead with
+ * Reset,irrespective of ql2xdontresethba. This is to allow a
+ * non-reset-owner to force a reset. Non-reset-owner sets
+ * the IDC_CTRL BIT0 to prevent Reset-owner from doing a Reset
+ * and then forces a Reset by setting device_state to
+ * NEED_RESET. */
+ if (dev_state == QLA8XXX_DEV_READY) {
+ /* If IDC_CTRL DONTRESETHBA_BIT0 is set don't do reset
+ * recovery */
+ if (qla8044_idc_dontreset(ha) == DONTRESET_BIT0) {
+ ql_dbg(ql_dbg_p3p, vha, 0xb13e,
+ "Reset recovery disabled\n");
+ rval = QLA_FUNCTION_FAILED;
+ goto exit_isp_reset;
+ }
+
+ ql_dbg(ql_dbg_p3p, vha, 0xb140,
+ "HW State: NEED RESET\n");
+ qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+ QLA8XXX_DEV_NEED_RESET);
+ }
+
+ /* For ISP8044, Reset owner is NIC, iSCSI or FCOE based on priority
+ * and which drivers are present. Unlike ISP82XX, the function setting
+ * NEED_RESET, may not be the Reset owner. */
+ qla83xx_reset_ownership(vha);
+
+ qla8044_idc_unlock(ha);
+ rval = qla8044_device_state_handler(vha);
+ qla8044_idc_lock(ha);
+ qla8044_clear_rst_ready(vha);
+
+exit_isp_reset:
+ qla8044_idc_unlock(ha);
+ if (rval == QLA_SUCCESS) {
+ ha->flags.isp82xx_fw_hung = 0;
+ ha->flags.nic_core_reset_hdlr_active = 0;
+ rval = qla82xx_restart_isp(vha);
+ }
+
+ return rval;
+}
+
diff --git a/drivers/scsi/qla2xxx/qla_nx2.h b/drivers/scsi/qla2xxx/qla_nx2.h
new file mode 100644
index 00000000000..2ab2eabab90
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_nx2.h
@@ -0,0 +1,551 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+
+#ifndef __QLA_NX2_H
+#define __QLA_NX2_H
+
+#define QSNT_ACK_TOV 30
+#define INTENT_TO_RECOVER 0x01
+#define PROCEED_TO_RECOVER 0x02
+#define IDC_LOCK_RECOVERY_OWNER_MASK 0x3C
+#define IDC_LOCK_RECOVERY_STATE_MASK 0x3
+#define IDC_LOCK_RECOVERY_STATE_SHIFT_BITS 2
+
+#define QLA8044_DRV_LOCK_MSLEEP 200
+#define QLA8044_ADDR_DDR_NET (0x0000000000000000ULL)
+#define QLA8044_ADDR_DDR_NET_MAX (0x000000000fffffffULL)
+
+#define MD_MIU_TEST_AGT_WRDATA_LO 0x410000A0
+#define MD_MIU_TEST_AGT_WRDATA_HI 0x410000A4
+#define MD_MIU_TEST_AGT_WRDATA_ULO 0x410000B0
+#define MD_MIU_TEST_AGT_WRDATA_UHI 0x410000B4
+#define MD_MIU_TEST_AGT_RDDATA_LO 0x410000A8
+#define MD_MIU_TEST_AGT_RDDATA_HI 0x410000AC
+#define MD_MIU_TEST_AGT_RDDATA_ULO 0x410000B8
+#define MD_MIU_TEST_AGT_RDDATA_UHI 0x410000BC
+
+/* MIU_TEST_AGT_CTRL flags. work for SIU as well */
+#define MIU_TA_CTL_WRITE_ENABLE (MIU_TA_CTL_WRITE | MIU_TA_CTL_ENABLE)
+#define MIU_TA_CTL_WRITE_START (MIU_TA_CTL_WRITE | MIU_TA_CTL_ENABLE | \
+ MIU_TA_CTL_START)
+#define MIU_TA_CTL_START_ENABLE (MIU_TA_CTL_START | MIU_TA_CTL_ENABLE)
+
+/* Imbus address bit used to indicate a host address. This bit is
+ * eliminated by the pcie bar and bar select before presentation
+ * over pcie. */
+/* host memory via IMBUS */
+#define QLA8044_P2_ADDR_PCIE (0x0000000800000000ULL)
+#define QLA8044_P3_ADDR_PCIE (0x0000008000000000ULL)
+#define QLA8044_ADDR_PCIE_MAX (0x0000000FFFFFFFFFULL)
+#define QLA8044_ADDR_OCM0 (0x0000000200000000ULL)
+#define QLA8044_ADDR_OCM0_MAX (0x00000002000fffffULL)
+#define QLA8044_ADDR_OCM1 (0x0000000200400000ULL)
+#define QLA8044_ADDR_OCM1_MAX (0x00000002004fffffULL)
+#define QLA8044_ADDR_QDR_NET (0x0000000300000000ULL)
+#define QLA8044_P2_ADDR_QDR_NET_MAX (0x00000003001fffffULL)
+#define QLA8044_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL)
+#define QLA8044_ADDR_QDR_NET_MAX (0x0000000307ffffffULL)
+#define QLA8044_PCI_CRBSPACE ((unsigned long)0x06000000)
+#define QLA8044_PCI_DIRECT_CRB ((unsigned long)0x04400000)
+#define QLA8044_PCI_CAMQM ((unsigned long)0x04800000)
+#define QLA8044_PCI_CAMQM_MAX ((unsigned long)0x04ffffff)
+#define QLA8044_PCI_DDR_NET ((unsigned long)0x00000000)
+#define QLA8044_PCI_QDR_NET ((unsigned long)0x04000000)
+#define QLA8044_PCI_QDR_NET_MAX ((unsigned long)0x043fffff)
+
+/* PCI Windowing for DDR regions. */
+#define QLA8044_ADDR_IN_RANGE(addr, low, high) \
+ (((addr) <= (high)) && ((addr) >= (low)))
+
+/* Indirectly Mapped Registers */
+#define QLA8044_FLASH_SPI_STATUS 0x2808E010
+#define QLA8044_FLASH_SPI_CONTROL 0x2808E014
+#define QLA8044_FLASH_STATUS 0x42100004
+#define QLA8044_FLASH_CONTROL 0x42110004
+#define QLA8044_FLASH_ADDR 0x42110008
+#define QLA8044_FLASH_WRDATA 0x4211000C
+#define QLA8044_FLASH_RDDATA 0x42110018
+#define QLA8044_FLASH_DIRECT_WINDOW 0x42110030
+#define QLA8044_FLASH_DIRECT_DATA(DATA) (0x42150000 | (0x0000FFFF&DATA))
+
+/* Flash access regs */
+#define QLA8044_FLASH_LOCK 0x3850
+#define QLA8044_FLASH_UNLOCK 0x3854
+#define QLA8044_FLASH_LOCK_ID 0x3500
+
+/* Driver Lock regs */
+#define QLA8044_DRV_LOCK 0x3868
+#define QLA8044_DRV_UNLOCK 0x386C
+#define QLA8044_DRV_LOCK_ID 0x3504
+#define QLA8044_DRV_LOCKRECOVERY 0x379C
+
+/* IDC version */
+#define QLA8044_IDC_VER_MAJ_VALUE 0x1
+#define QLA8044_IDC_VER_MIN_VALUE 0x0
+
+/* IDC Registers : Driver Coexistence Defines */
+#define QLA8044_CRB_IDC_VER_MAJOR 0x3780
+#define QLA8044_CRB_IDC_VER_MINOR 0x3798
+#define QLA8044_IDC_DRV_AUDIT 0x3794
+#define QLA8044_SRE_SHIM_CONTROL 0x0D200284
+#define QLA8044_PORT0_RXB_PAUSE_THRS 0x0B2003A4
+#define QLA8044_PORT1_RXB_PAUSE_THRS 0x0B2013A4
+#define QLA8044_PORT0_RXB_TC_MAX_CELL 0x0B200388
+#define QLA8044_PORT1_RXB_TC_MAX_CELL 0x0B201388
+#define QLA8044_PORT0_RXB_TC_STATS 0x0B20039C
+#define QLA8044_PORT1_RXB_TC_STATS 0x0B20139C
+#define QLA8044_PORT2_IFB_PAUSE_THRS 0x0B200704
+#define QLA8044_PORT3_IFB_PAUSE_THRS 0x0B201704
+
+/* set value to pause threshold value */
+#define QLA8044_SET_PAUSE_VAL 0x0
+#define QLA8044_SET_TC_MAX_CELL_VAL 0x03FF03FF
+#define QLA8044_PEG_HALT_STATUS1 0x34A8
+#define QLA8044_PEG_HALT_STATUS2 0x34AC
+#define QLA8044_PEG_ALIVE_COUNTER 0x34B0 /* FW_HEARTBEAT */
+#define QLA8044_FW_CAPABILITIES 0x3528
+#define QLA8044_CRB_DRV_ACTIVE 0x3788 /* IDC_DRV_PRESENCE */
+#define QLA8044_CRB_DEV_STATE 0x3784 /* IDC_DEV_STATE */
+#define QLA8044_CRB_DRV_STATE 0x378C /* IDC_DRV_ACK */
+#define QLA8044_CRB_DRV_SCRATCH 0x3548
+#define QLA8044_CRB_DEV_PART_INFO1 0x37E0
+#define QLA8044_CRB_DEV_PART_INFO2 0x37E4
+#define QLA8044_FW_VER_MAJOR 0x3550
+#define QLA8044_FW_VER_MINOR 0x3554
+#define QLA8044_FW_VER_SUB 0x3558
+#define QLA8044_NPAR_STATE 0x359C
+#define QLA8044_FW_IMAGE_VALID 0x35FC
+#define QLA8044_CMDPEG_STATE 0x3650
+#define QLA8044_ASIC_TEMP 0x37B4
+#define QLA8044_FW_API 0x356C
+#define QLA8044_DRV_OP_MODE 0x3570
+#define QLA8044_CRB_WIN_BASE 0x3800
+#define QLA8044_CRB_WIN_FUNC(f) (QLA8044_CRB_WIN_BASE+((f)*4))
+#define QLA8044_SEM_LOCK_BASE 0x3840
+#define QLA8044_SEM_UNLOCK_BASE 0x3844
+#define QLA8044_SEM_LOCK_FUNC(f) (QLA8044_SEM_LOCK_BASE+((f)*8))
+#define QLA8044_SEM_UNLOCK_FUNC(f) (QLA8044_SEM_UNLOCK_BASE+((f)*8))
+#define QLA8044_LINK_STATE(f) (0x3698+((f) > 7 ? 4 : 0))
+#define QLA8044_LINK_SPEED(f) (0x36E0+(((f) >> 2) * 4))
+#define QLA8044_MAX_LINK_SPEED(f) (0x36F0+(((f) / 4) * 4))
+#define QLA8044_LINK_SPEED_FACTOR 10
+
+/* FLASH API Defines */
+#define QLA8044_FLASH_MAX_WAIT_USEC 100
+#define QLA8044_FLASH_LOCK_TIMEOUT 10000
+#define QLA8044_FLASH_SECTOR_SIZE 65536
+#define QLA8044_DRV_LOCK_TIMEOUT 2000
+#define QLA8044_FLASH_SECTOR_ERASE_CMD 0xdeadbeef
+#define QLA8044_FLASH_WRITE_CMD 0xdacdacda
+#define QLA8044_FLASH_BUFFER_WRITE_CMD 0xcadcadca
+#define QLA8044_FLASH_READ_RETRY_COUNT 2000
+#define QLA8044_FLASH_STATUS_READY 0x6
+#define QLA8044_FLASH_BUFFER_WRITE_MIN 2
+#define QLA8044_FLASH_BUFFER_WRITE_MAX 64
+#define QLA8044_FLASH_STATUS_REG_POLL_DELAY 1
+#define QLA8044_ERASE_MODE 1
+#define QLA8044_WRITE_MODE 2
+#define QLA8044_DWORD_WRITE_MODE 3
+#define QLA8044_GLOBAL_RESET 0x38CC
+#define QLA8044_WILDCARD 0x38F0
+#define QLA8044_INFORMANT 0x38FC
+#define QLA8044_HOST_MBX_CTRL 0x3038
+#define QLA8044_FW_MBX_CTRL 0x303C
+#define QLA8044_BOOTLOADER_ADDR 0x355C
+#define QLA8044_BOOTLOADER_SIZE 0x3560
+#define QLA8044_FW_IMAGE_ADDR 0x3564
+#define QLA8044_MBX_INTR_ENABLE 0x1000
+#define QLA8044_MBX_INTR_MASK 0x1200
+
+/* IDC Control Register bit defines */
+#define DONTRESET_BIT0 0x1
+#define GRACEFUL_RESET_BIT1 0x2
+
+/* ISP8044 PEG_HALT_STATUS1 bits */
+#define QLA8044_HALT_STATUS_INFORMATIONAL (0x1 << 29)
+#define QLA8044_HALT_STATUS_FW_RESET (0x2 << 29)
+#define QLA8044_HALT_STATUS_UNRECOVERABLE (0x4 << 29)
+
+/* Firmware image definitions */
+#define QLA8044_BOOTLOADER_FLASH_ADDR 0x10000
+#define QLA8044_BOOT_FROM_FLASH 0
+#define QLA8044_IDC_PARAM_ADDR 0x3e8020
+
+/* FLASH related definitions */
+#define QLA8044_OPTROM_BURST_SIZE 0x100
+#define QLA8044_MAX_OPTROM_BURST_DWORDS (QLA8044_OPTROM_BURST_SIZE / 4)
+#define QLA8044_MIN_OPTROM_BURST_DWORDS 2
+#define QLA8044_SECTOR_SIZE (64 * 1024)
+
+#define QLA8044_FLASH_SPI_CTL 0x4
+#define QLA8044_FLASH_FIRST_TEMP_VAL 0x00800000
+#define QLA8044_FLASH_SECOND_TEMP_VAL 0x00800001
+#define QLA8044_FLASH_FIRST_MS_PATTERN 0x43
+#define QLA8044_FLASH_SECOND_MS_PATTERN 0x7F
+#define QLA8044_FLASH_LAST_MS_PATTERN 0x7D
+#define QLA8044_FLASH_STATUS_WRITE_DEF_SIG 0xFD0100
+#define QLA8044_FLASH_SECOND_ERASE_MS_VAL 0x5
+#define QLA8044_FLASH_ERASE_SIG 0xFD0300
+#define QLA8044_FLASH_LAST_ERASE_MS_VAL 0x3D
+
+/* Reset template definitions */
+#define QLA8044_MAX_RESET_SEQ_ENTRIES 16
+#define QLA8044_RESTART_TEMPLATE_SIZE 0x2000
+#define QLA8044_RESET_TEMPLATE_ADDR 0x4F0000
+#define QLA8044_RESET_SEQ_VERSION 0x0101
+
+/* Reset template entry opcodes */
+#define OPCODE_NOP 0x0000
+#define OPCODE_WRITE_LIST 0x0001
+#define OPCODE_READ_WRITE_LIST 0x0002
+#define OPCODE_POLL_LIST 0x0004
+#define OPCODE_POLL_WRITE_LIST 0x0008
+#define OPCODE_READ_MODIFY_WRITE 0x0010
+#define OPCODE_SEQ_PAUSE 0x0020
+#define OPCODE_SEQ_END 0x0040
+#define OPCODE_TMPL_END 0x0080
+#define OPCODE_POLL_READ_LIST 0x0100
+
+/* Template Header */
+#define RESET_TMPLT_HDR_SIGNATURE 0xCAFE
+#define QLA8044_IDC_DRV_CTRL 0x3790
+#define AF_8044_NO_FW_DUMP 27 /* 0x08000000 */
+
+#define MINIDUMP_SIZE_36K 36864
+
+struct qla8044_reset_template_hdr {
+ uint16_t version;
+ uint16_t signature;
+ uint16_t size;
+ uint16_t entries;
+ uint16_t hdr_size;
+ uint16_t checksum;
+ uint16_t init_seq_offset;
+ uint16_t start_seq_offset;
+} __packed;
+
+/* Common Entry Header. */
+struct qla8044_reset_entry_hdr {
+ uint16_t cmd;
+ uint16_t size;
+ uint16_t count;
+ uint16_t delay;
+} __packed;
+
+/* Generic poll entry type. */
+struct qla8044_poll {
+ uint32_t test_mask;
+ uint32_t test_value;
+} __packed;
+
+/* Read modify write entry type. */
+struct qla8044_rmw {
+ uint32_t test_mask;
+ uint32_t xor_value;
+ uint32_t or_value;
+ uint8_t shl;
+ uint8_t shr;
+ uint8_t index_a;
+ uint8_t rsvd;
+} __packed;
+
+/* Generic Entry Item with 2 DWords. */
+struct qla8044_entry {
+ uint32_t arg1;
+ uint32_t arg2;
+} __packed;
+
+/* Generic Entry Item with 4 DWords.*/
+struct qla8044_quad_entry {
+ uint32_t dr_addr;
+ uint32_t dr_value;
+ uint32_t ar_addr;
+ uint32_t ar_value;
+} __packed;
+
+struct qla8044_reset_template {
+ int seq_index;
+ int seq_error;
+ int array_index;
+ uint32_t array[QLA8044_MAX_RESET_SEQ_ENTRIES];
+ uint8_t *buff;
+ uint8_t *stop_offset;
+ uint8_t *start_offset;
+ uint8_t *init_offset;
+ struct qla8044_reset_template_hdr *hdr;
+ uint8_t seq_end;
+ uint8_t template_end;
+};
+
+/* Driver_code is for driver to write some info about the entry
+ * currently not used.
+ */
+struct qla8044_minidump_entry_hdr {
+ uint32_t entry_type;
+ uint32_t entry_size;
+ uint32_t entry_capture_size;
+ struct {
+ uint8_t entry_capture_mask;
+ uint8_t entry_code;
+ uint8_t driver_code;
+ uint8_t driver_flags;
+ } d_ctrl;
+} __packed;
+
+/* Read CRB entry header */
+struct qla8044_minidump_entry_crb {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t addr;
+ struct {
+ uint8_t addr_stride;
+ uint8_t state_index_a;
+ uint16_t poll_timeout;
+ } crb_strd;
+ uint32_t data_size;
+ uint32_t op_count;
+
+ struct {
+ uint8_t opcode;
+ uint8_t state_index_v;
+ uint8_t shl;
+ uint8_t shr;
+ } crb_ctrl;
+
+ uint32_t value_1;
+ uint32_t value_2;
+ uint32_t value_3;
+} __packed;
+
+struct qla8044_minidump_entry_cache {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t tag_reg_addr;
+ struct {
+ uint16_t tag_value_stride;
+ uint16_t init_tag_value;
+ } addr_ctrl;
+ uint32_t data_size;
+ uint32_t op_count;
+ uint32_t control_addr;
+ struct {
+ uint16_t write_value;
+ uint8_t poll_mask;
+ uint8_t poll_wait;
+ } cache_ctrl;
+ uint32_t read_addr;
+ struct {
+ uint8_t read_addr_stride;
+ uint8_t read_addr_cnt;
+ uint16_t rsvd_1;
+ } read_ctrl;
+} __packed;
+
+/* Read OCM */
+struct qla8044_minidump_entry_rdocm {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t rsvd_0;
+ uint32_t rsvd_1;
+ uint32_t data_size;
+ uint32_t op_count;
+ uint32_t rsvd_2;
+ uint32_t rsvd_3;
+ uint32_t read_addr;
+ uint32_t read_addr_stride;
+} __packed;
+
+/* Read Memory */
+struct qla8044_minidump_entry_rdmem {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t rsvd[6];
+ uint32_t read_addr;
+ uint32_t read_data_size;
+};
+
+/* Read Memory: For Pex-DMA */
+struct qla8044_minidump_entry_rdmem_pex_dma {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t desc_card_addr;
+ uint16_t dma_desc_cmd;
+ uint8_t rsvd[2];
+ uint32_t start_dma_cmd;
+ uint8_t rsvd2[12];
+ uint32_t read_addr;
+ uint32_t read_data_size;
+} __packed;
+
+/* Read ROM */
+struct qla8044_minidump_entry_rdrom {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t rsvd[6];
+ uint32_t read_addr;
+ uint32_t read_data_size;
+} __packed;
+
+/* Mux entry */
+struct qla8044_minidump_entry_mux {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t select_addr;
+ uint32_t rsvd_0;
+ uint32_t data_size;
+ uint32_t op_count;
+ uint32_t select_value;
+ uint32_t select_value_stride;
+ uint32_t read_addr;
+ uint32_t rsvd_1;
+} __packed;
+
+/* Queue entry */
+struct qla8044_minidump_entry_queue {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t select_addr;
+ struct {
+ uint16_t queue_id_stride;
+ uint16_t rsvd_0;
+ } q_strd;
+ uint32_t data_size;
+ uint32_t op_count;
+ uint32_t rsvd_1;
+ uint32_t rsvd_2;
+ uint32_t read_addr;
+ struct {
+ uint8_t read_addr_stride;
+ uint8_t read_addr_cnt;
+ uint16_t rsvd_3;
+ } rd_strd;
+} __packed;
+
+/* POLLRD Entry */
+struct qla8044_minidump_entry_pollrd {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t select_addr;
+ uint32_t read_addr;
+ uint32_t select_value;
+ uint16_t select_value_stride;
+ uint16_t op_count;
+ uint32_t poll_wait;
+ uint32_t poll_mask;
+ uint32_t data_size;
+ uint32_t rsvd_1;
+} __packed;
+
+/* RDMUX2 Entry */
+struct qla8044_minidump_entry_rdmux2 {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t select_addr_1;
+ uint32_t select_addr_2;
+ uint32_t select_value_1;
+ uint32_t select_value_2;
+ uint32_t op_count;
+ uint32_t select_value_mask;
+ uint32_t read_addr;
+ uint8_t select_value_stride;
+ uint8_t data_size;
+ uint8_t rsvd[2];
+} __packed;
+
+/* POLLRDMWR Entry */
+struct qla8044_minidump_entry_pollrdmwr {
+ struct qla8044_minidump_entry_hdr h;
+ uint32_t addr_1;
+ uint32_t addr_2;
+ uint32_t value_1;
+ uint32_t value_2;
+ uint32_t poll_wait;
+ uint32_t poll_mask;
+ uint32_t modify_mask;
+ uint32_t data_size;
+} __packed;
+
+/* IDC additional information */
+struct qla8044_idc_information {
+ uint32_t request_desc; /* IDC request descriptor */
+ uint32_t info1; /* IDC additional info */
+ uint32_t info2; /* IDC additional info */
+ uint32_t info3; /* IDC additional info */
+} __packed;
+
+enum qla_regs {
+ QLA8044_PEG_HALT_STATUS1_INDEX = 0,
+ QLA8044_PEG_HALT_STATUS2_INDEX,
+ QLA8044_PEG_ALIVE_COUNTER_INDEX,
+ QLA8044_CRB_DRV_ACTIVE_INDEX,
+ QLA8044_CRB_DEV_STATE_INDEX,
+ QLA8044_CRB_DRV_STATE_INDEX,
+ QLA8044_CRB_DRV_SCRATCH_INDEX,
+ QLA8044_CRB_DEV_PART_INFO_INDEX,
+ QLA8044_CRB_DRV_IDC_VERSION_INDEX,
+ QLA8044_FW_VERSION_MAJOR_INDEX,
+ QLA8044_FW_VERSION_MINOR_INDEX,
+ QLA8044_FW_VERSION_SUB_INDEX,
+ QLA8044_CRB_CMDPEG_STATE_INDEX,
+ QLA8044_CRB_TEMP_STATE_INDEX,
+} __packed;
+
+#define CRB_REG_INDEX_MAX 14
+#define CRB_CMDPEG_CHECK_RETRY_COUNT 60
+#define CRB_CMDPEG_CHECK_DELAY 500
+
+static const uint32_t qla8044_reg_tbl[] = {
+ QLA8044_PEG_HALT_STATUS1,
+ QLA8044_PEG_HALT_STATUS2,
+ QLA8044_PEG_ALIVE_COUNTER,
+ QLA8044_CRB_DRV_ACTIVE,
+ QLA8044_CRB_DEV_STATE,
+ QLA8044_CRB_DRV_STATE,
+ QLA8044_CRB_DRV_SCRATCH,
+ QLA8044_CRB_DEV_PART_INFO1,
+ QLA8044_CRB_IDC_VER_MAJOR,
+ QLA8044_FW_VER_MAJOR,
+ QLA8044_FW_VER_MINOR,
+ QLA8044_FW_VER_SUB,
+ QLA8044_CMDPEG_STATE,
+ QLA8044_ASIC_TEMP,
+};
+
+/* MiniDump Structures */
+
+/* Driver_code is for driver to write some info about the entry
+ * currently not used.
+ */
+#define QLA8044_SS_OCM_WNDREG_INDEX 3
+#define QLA8044_DBG_STATE_ARRAY_LEN 16
+#define QLA8044_DBG_CAP_SIZE_ARRAY_LEN 8
+#define QLA8044_DBG_RSVD_ARRAY_LEN 8
+#define QLA8044_DBG_OCM_WNDREG_ARRAY_LEN 16
+#define QLA8044_SS_PCI_INDEX 0
+
+struct qla8044_minidump_template_hdr {
+ uint32_t entry_type;
+ uint32_t first_entry_offset;
+ uint32_t size_of_template;
+ uint32_t capture_debug_level;
+ uint32_t num_of_entries;
+ uint32_t version;
+ uint32_t driver_timestamp;
+ uint32_t checksum;
+
+ uint32_t driver_capture_mask;
+ uint32_t driver_info_word2;
+ uint32_t driver_info_word3;
+ uint32_t driver_info_word4;
+
+ uint32_t saved_state_array[QLA8044_DBG_STATE_ARRAY_LEN];
+ uint32_t capture_size_array[QLA8044_DBG_CAP_SIZE_ARRAY_LEN];
+ uint32_t ocm_window_reg[QLA8044_DBG_OCM_WNDREG_ARRAY_LEN];
+};
+
+struct qla8044_pex_dma_descriptor {
+ struct {
+ uint32_t read_data_size; /* 0-23: size, 24-31: rsvd */
+ uint8_t rsvd[2];
+ uint16_t dma_desc_cmd;
+ } cmd;
+ uint64_t src_addr;
+ uint64_t dma_bus_addr; /*0-3: desc-cmd, 4-7: pci-func, 8-15: desc-cmd*/
+ uint8_t rsvd[24];
+} __packed;
+
+#endif
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 3e21e9fc9d9..9f01bbbf3a2 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1247,7 +1247,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
if (qla2x00_vp_abort_isp(vha))
goto eh_host_reset_lock;
} else {
- if (IS_QLA82XX(vha->hw)) {
+ if (IS_P3P_TYPE(vha->hw)) {
if (!qla82xx_fcoe_ctx_reset(vha)) {
/* Ctx reset success */
ret = SUCCESS;
@@ -1303,6 +1303,10 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
struct fc_port *fcport;
struct qla_hw_data *ha = vha->hw;
+ if (IS_QLAFX00(ha)) {
+ return qlafx00_loop_reset(vha);
+ }
+
if (ql2xtargetreset == 1 && ha->flags.enable_target_reset) {
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->port_type != FCT_TARGET)
@@ -1311,14 +1315,12 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
ret = ha->isp_ops->target_reset(fcport, 0, 0);
if (ret != QLA_SUCCESS) {
ql_dbg(ql_dbg_taskm, vha, 0x802c,
- "Bus Reset failed: Target Reset=%d "
+ "Bus Reset failed: Reset=%d "
"d_id=%x.\n", ret, fcport->d_id.b24);
}
}
}
- if (IS_QLAFX00(ha))
- return QLA_SUCCESS;
if (ha->flags.enable_lip_full_login && !IS_CNA_CAPABLE(ha)) {
atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -1506,7 +1508,7 @@ qla2x00_host_ramp_down_queuedepth(scsi_qla_host_t *vha)
if (sdev->queue_depth > shost->cmd_per_lun) {
if (sdev->queue_depth < ha->cfg_lun_q_depth)
continue;
- ql_log(ql_log_warn, vp, 0x3031,
+ ql_dbg(ql_dbg_io, vp, 0x3031,
"%ld:%d:%d: Ramping down queue depth to %d",
vp->host_no, sdev->id, sdev->lun,
ha->cfg_lun_q_depth);
@@ -1911,7 +1913,7 @@ static struct isp_operations qla2300_isp_ops = {
.get_flash_version = qla2x00_get_flash_version,
.start_scsi = qla2x00_start_scsi,
.abort_isp = qla2x00_abort_isp,
- .iospace_config = qla2x00_iospace_config,
+ .iospace_config = qla2x00_iospace_config,
.initialize_adapter = qla2x00_initialize_adapter,
};
@@ -1949,7 +1951,7 @@ static struct isp_operations qla24xx_isp_ops = {
.get_flash_version = qla24xx_get_flash_version,
.start_scsi = qla24xx_start_scsi,
.abort_isp = qla2x00_abort_isp,
- .iospace_config = qla2x00_iospace_config,
+ .iospace_config = qla2x00_iospace_config,
.initialize_adapter = qla2x00_initialize_adapter,
};
@@ -1987,7 +1989,7 @@ static struct isp_operations qla25xx_isp_ops = {
.get_flash_version = qla24xx_get_flash_version,
.start_scsi = qla24xx_dif_start_scsi,
.abort_isp = qla2x00_abort_isp,
- .iospace_config = qla2x00_iospace_config,
+ .iospace_config = qla2x00_iospace_config,
.initialize_adapter = qla2x00_initialize_adapter,
};
@@ -2025,7 +2027,7 @@ static struct isp_operations qla81xx_isp_ops = {
.get_flash_version = qla24xx_get_flash_version,
.start_scsi = qla24xx_dif_start_scsi,
.abort_isp = qla2x00_abort_isp,
- .iospace_config = qla2x00_iospace_config,
+ .iospace_config = qla2x00_iospace_config,
.initialize_adapter = qla2x00_initialize_adapter,
};
@@ -2060,13 +2062,51 @@ static struct isp_operations qla82xx_isp_ops = {
.beacon_blink = NULL,
.read_optrom = qla82xx_read_optrom_data,
.write_optrom = qla82xx_write_optrom_data,
- .get_flash_version = qla24xx_get_flash_version,
+ .get_flash_version = qla82xx_get_flash_version,
.start_scsi = qla82xx_start_scsi,
.abort_isp = qla82xx_abort_isp,
.iospace_config = qla82xx_iospace_config,
.initialize_adapter = qla2x00_initialize_adapter,
};
+static struct isp_operations qla8044_isp_ops = {
+ .pci_config = qla82xx_pci_config,
+ .reset_chip = qla82xx_reset_chip,
+ .chip_diag = qla24xx_chip_diag,
+ .config_rings = qla82xx_config_rings,
+ .reset_adapter = qla24xx_reset_adapter,
+ .nvram_config = qla81xx_nvram_config,
+ .update_fw_options = qla24xx_update_fw_options,
+ .load_risc = qla82xx_load_risc,
+ .pci_info_str = qla24xx_pci_info_str,
+ .fw_version_str = qla24xx_fw_version_str,
+ .intr_handler = qla8044_intr_handler,
+ .enable_intrs = qla82xx_enable_intrs,
+ .disable_intrs = qla82xx_disable_intrs,
+ .abort_command = qla24xx_abort_command,
+ .target_reset = qla24xx_abort_target,
+ .lun_reset = qla24xx_lun_reset,
+ .fabric_login = qla24xx_login_fabric,
+ .fabric_logout = qla24xx_fabric_logout,
+ .calc_req_entries = NULL,
+ .build_iocbs = NULL,
+ .prep_ms_iocb = qla24xx_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
+ .read_nvram = NULL,
+ .write_nvram = NULL,
+ .fw_dump = qla24xx_fw_dump,
+ .beacon_on = qla82xx_beacon_on,
+ .beacon_off = qla82xx_beacon_off,
+ .beacon_blink = NULL,
+ .read_optrom = qla82xx_read_optrom_data,
+ .write_optrom = qla8044_write_optrom_data,
+ .get_flash_version = qla82xx_get_flash_version,
+ .start_scsi = qla82xx_start_scsi,
+ .abort_isp = qla8044_abort_isp,
+ .iospace_config = qla82xx_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
+};
+
static struct isp_operations qla83xx_isp_ops = {
.pci_config = qla25xx_pci_config,
.reset_chip = qla24xx_reset_chip,
@@ -2237,6 +2277,14 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
/* Initialize 82XX ISP flags */
qla82xx_init_flags(ha);
break;
+ case PCI_DEVICE_ID_QLOGIC_ISP8044:
+ ha->device_type |= DT_ISP8044;
+ ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+ /* Initialize 82XX ISP flags */
+ qla82xx_init_flags(ha);
+ break;
case PCI_DEVICE_ID_QLOGIC_ISP2031:
ha->device_type |= DT_ISP2031;
ha->device_type |= DT_ZIO_SUPPORTED;
@@ -2317,7 +2365,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
uint16_t req_length = 0, rsp_length = 0;
struct req_que *req = NULL;
struct rsp_que *rsp = NULL;
-
bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
sht = &qla2xxx_driver_template;
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
@@ -2330,7 +2377,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2031 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8031 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISPF001) {
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISPF001 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8044) {
bars = pci_select_bars(pdev, IORESOURCE_MEM);
mem_only = 1;
ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
@@ -2484,6 +2532,21 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
+ } else if (IS_QLA8044(ha)) {
+ ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
+ ha->mbx_count = MAILBOX_REGISTER_COUNT;
+ req_length = REQUEST_ENTRY_CNT_82XX;
+ rsp_length = RESPONSE_ENTRY_CNT_82XX;
+ ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
+ ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
+ ha->gid_list_info_size = 8;
+ ha->optrom_size = OPTROM_SIZE_83XX;
+ ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
+ ha->isp_ops = &qla8044_isp_ops;
+ ha->flash_conf_off = FARX_ACCESS_FLASH_CONF;
+ ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
+ ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
+ ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
} else if (IS_QLA83XX(ha)) {
ha->portnum = PCI_FUNC(ha->pdev->devfn);
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
@@ -2512,6 +2575,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->port_down_retry_count = 30; /* default value */
ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL;
ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
+ ha->mr.fw_critemp_timer_tick = QLAFX00_CRITEMP_INTERVAL;
ha->mr.fw_hbt_en = 1;
}
@@ -2676,7 +2740,7 @@ que_init:
rsp->rsp_q_out = &ha->iobase->ispfx00.rsp_q_out;
}
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
req->req_q_out = &ha->iobase->isp82.req_q_out[0];
rsp->rsp_q_in = &ha->iobase->isp82.rsp_q_in[0];
rsp->rsp_q_out = &ha->iobase->isp82.rsp_q_out[0];
@@ -2709,6 +2773,14 @@ que_init:
qla82xx_idc_unlock(ha);
ql_log(ql_log_fatal, base_vha, 0x00d7,
"HW State: FAILED.\n");
+ } else if (IS_QLA8044(ha)) {
+ qla8044_idc_lock(ha);
+ qla8044_wr_direct(base_vha,
+ QLA8044_CRB_DEV_STATE_INDEX,
+ QLA8XXX_DEV_FAILED);
+ qla8044_idc_unlock(ha);
+ ql_log(ql_log_fatal, base_vha, 0x0150,
+ "HW State: FAILED.\n");
}
ret = -ENODEV;
@@ -2804,6 +2876,13 @@ skip_dpc:
ha->isp_ops->enable_intrs(ha);
+ if (IS_QLAFX00(ha)) {
+ ret = qlafx00_fx_disc(base_vha,
+ &base_vha->hw->mr.fcport, FXDISC_GET_CONFIG_INFO);
+ host->sg_tablesize = (ha->mr.extended_io_enabled) ?
+ QLA_SG_ALL : 128;
+ }
+
ret = scsi_add_host(host, &pdev->dev);
if (ret)
goto probe_failed;
@@ -2824,9 +2903,6 @@ skip_dpc:
if (IS_QLAFX00(ha)) {
ret = qlafx00_fx_disc(base_vha,
- &base_vha->hw->mr.fcport, FXDISC_GET_CONFIG_INFO);
-
- ret = qlafx00_fx_disc(base_vha,
&base_vha->hw->mr.fcport, FXDISC_GET_PORT_INFO);
/* Register system information */
@@ -2881,8 +2957,13 @@ probe_hw_failed:
qla82xx_clear_drv_active(ha);
qla82xx_idc_unlock(ha);
}
+ if (IS_QLA8044(ha)) {
+ qla8044_idc_lock(ha);
+ qla8044_clear_drv_active(base_vha);
+ qla8044_idc_unlock(ha);
+ }
iospace_config_failed:
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
if (!ha->nx_pcibase)
iounmap((device_reg_t __iomem *)ha->nx_pcibase);
if (!ql2xdbwr)
@@ -2930,6 +3011,10 @@ qla2x00_shutdown(struct pci_dev *pdev)
vha = pci_get_drvdata(pdev);
ha = vha->hw;
+ /* Notify ISPFX00 firmware */
+ if (IS_QLAFX00(ha))
+ qlafx00_driver_shutdown(vha, 20);
+
/* Turn-off FCE trace */
if (ha->flags.fce_enabled) {
qla2x00_disable_fce_trace(vha, NULL, NULL);
@@ -2977,6 +3062,9 @@ qla2x00_remove_one(struct pci_dev *pdev)
ha->flags.host_shutting_down = 1;
set_bit(UNLOADING, &base_vha->dpc_flags);
+ if (IS_QLAFX00(ha))
+ qlafx00_driver_shutdown(base_vha, 20);
+
mutex_lock(&ha->vport_lock);
while (ha->cur_vport_count) {
spin_lock_irqsave(&ha->vport_slock, flags);
@@ -3061,6 +3149,11 @@ qla2x00_remove_one(struct pci_dev *pdev)
scsi_host_put(base_vha->host);
+ if (IS_QLA8044(ha)) {
+ qla8044_idc_lock(ha);
+ qla8044_clear_drv_active(base_vha);
+ qla8044_idc_unlock(ha);
+ }
if (IS_QLA82XX(ha)) {
qla82xx_idc_lock(ha);
qla82xx_clear_drv_active(ha);
@@ -3210,14 +3303,8 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport,
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
ql_dbg(ql_dbg_disc, vha, 0x2067,
- "Port login retry "
- "%02x%02x%02x%02x%02x%02x%02x%02x, "
- "id = 0x%04x retry cnt=%d.\n",
- fcport->port_name[0], fcport->port_name[1],
- fcport->port_name[2], fcport->port_name[3],
- fcport->port_name[4], fcport->port_name[5],
- fcport->port_name[6], fcport->port_name[7],
- fcport->loop_id, fcport->login_retry);
+ "Port login retry %8phN, id = 0x%04x retry cnt=%d.\n",
+ fcport->port_name, fcport->loop_id, fcport->login_retry);
}
}
@@ -3290,7 +3377,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
if (!ha->srb_mempool)
goto fail_free_gid_list;
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
/* Allocate cache for CT6 Ctx. */
if (!ctx_cachep) {
ctx_cachep = kmem_cache_create("qla2xxx_ctx",
@@ -3324,7 +3411,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
"init_cb=%p gid_list=%p, srb_mempool=%p s_dma_pool=%p.\n",
ha->init_cb, ha->gid_list, ha->srb_mempool, ha->s_dma_pool);
- if (IS_QLA82XX(ha) || ql2xenabledif) {
+ if (IS_P3P_TYPE(ha) || ql2xenabledif) {
ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev,
DSD_LIST_DMA_POOL_SIZE, 8, 0);
if (!ha->dl_dma_pool) {
@@ -3532,7 +3619,7 @@ fail:
* Frees fw dump stuff.
*
* Input:
-* ha = adapter block pointer.
+* ha = adapter block pointer
*/
static void
qla2x00_free_fw_dump(struct qla_hw_data *ha)
@@ -4699,17 +4786,33 @@ qla2x00_do_dpc(void *data)
qla2x00_do_work(base_vha);
- if (IS_QLA82XX(ha)) {
- if (test_and_clear_bit(ISP_UNRECOVERABLE,
- &base_vha->dpc_flags)) {
- qla82xx_idc_lock(ha);
- qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
- QLA8XXX_DEV_FAILED);
- qla82xx_idc_unlock(ha);
- ql_log(ql_log_info, base_vha, 0x4004,
- "HW State: FAILED.\n");
- qla82xx_device_state_handler(base_vha);
- continue;
+ if (IS_P3P_TYPE(ha)) {
+ if (IS_QLA8044(ha)) {
+ if (test_and_clear_bit(ISP_UNRECOVERABLE,
+ &base_vha->dpc_flags)) {
+ qla8044_idc_lock(ha);
+ qla8044_wr_direct(base_vha,
+ QLA8044_CRB_DEV_STATE_INDEX,
+ QLA8XXX_DEV_FAILED);
+ qla8044_idc_unlock(ha);
+ ql_log(ql_log_info, base_vha, 0x4004,
+ "HW State: FAILED.\n");
+ qla8044_device_state_handler(base_vha);
+ continue;
+ }
+
+ } else {
+ if (test_and_clear_bit(ISP_UNRECOVERABLE,
+ &base_vha->dpc_flags)) {
+ qla82xx_idc_lock(ha);
+ qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+ QLA8XXX_DEV_FAILED);
+ qla82xx_idc_unlock(ha);
+ ql_log(ql_log_info, base_vha, 0x0151,
+ "HW State: FAILED.\n");
+ qla82xx_device_state_handler(base_vha);
+ continue;
+ }
}
if (test_and_clear_bit(FCOE_CTX_RESET_NEEDED,
@@ -4809,16 +4912,26 @@ qla2x00_do_dpc(void *data)
if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
"Quiescence mode scheduled.\n");
- if (IS_QLA82XX(ha)) {
- qla82xx_device_state_handler(base_vha);
+ if (IS_P3P_TYPE(ha)) {
+ if (IS_QLA82XX(ha))
+ qla82xx_device_state_handler(base_vha);
+ if (IS_QLA8044(ha))
+ qla8044_device_state_handler(base_vha);
clear_bit(ISP_QUIESCE_NEEDED,
&base_vha->dpc_flags);
if (!ha->flags.quiesce_owner) {
qla2x00_perform_loop_resync(base_vha);
-
- qla82xx_idc_lock(ha);
- qla82xx_clear_qsnt_ready(base_vha);
- qla82xx_idc_unlock(ha);
+ if (IS_QLA82XX(ha)) {
+ qla82xx_idc_lock(ha);
+ qla82xx_clear_qsnt_ready(
+ base_vha);
+ qla82xx_idc_unlock(ha);
+ } else if (IS_QLA8044(ha)) {
+ qla8044_idc_lock(ha);
+ qla8044_clear_qsnt_ready(
+ base_vha);
+ qla8044_idc_unlock(ha);
+ }
}
} else {
clear_bit(ISP_QUIESCE_NEEDED,
@@ -4992,10 +5105,13 @@ qla2x00_timer(scsi_qla_host_t *vha)
pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
/* Make sure qla82xx_watchdog is run only for physical port */
- if (!vha->vp_idx && IS_QLA82XX(ha)) {
+ if (!vha->vp_idx && IS_P3P_TYPE(ha)) {
if (test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags))
start_dpc++;
- qla82xx_watchdog(vha);
+ if (IS_QLA82XX(ha))
+ qla82xx_watchdog(vha);
+ else if (IS_QLA8044(ha))
+ qla8044_watchdog(vha);
}
if (!vha->vp_idx && IS_QLAFX00(ha))
@@ -5075,7 +5191,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
/* Check if beacon LED needs to be blinked for physical host only */
if (!vha->vp_idx && (ha->beacon_blink_led == 1)) {
/* There is no beacon_blink function for ISP82xx */
- if (!IS_QLA82XX(ha)) {
+ if (!IS_P3P_TYPE(ha)) {
set_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags);
start_dpc++;
}
@@ -5519,6 +5635,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8021) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8031) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISPF001) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8044) },
{ 0 },
};
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 3bef6736d88..bd56cde795f 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -565,7 +565,7 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
*start = FA_FLASH_LAYOUT_ADDR;
else if (IS_QLA81XX(ha))
*start = FA_FLASH_LAYOUT_ADDR_81;
- else if (IS_QLA82XX(ha)) {
+ else if (IS_P3P_TYPE(ha)) {
*start = FA_FLASH_LAYOUT_ADDR_82;
goto end;
} else if (IS_QLA83XX(ha)) {
@@ -719,7 +719,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
start = le32_to_cpu(region->start) >> 2;
ql_dbg(ql_dbg_init, vha, 0x0049,
"FLT[%02x]: start=0x%x "
- "end=0x%x size=0x%x.\n", le32_to_cpu(region->code),
+ "end=0x%x size=0x%x.\n", le32_to_cpu(region->code) & 0xff,
start, le32_to_cpu(region->end) >> 2,
le32_to_cpu(region->size));
@@ -741,13 +741,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
if (IS_QLA8031(ha))
break;
ha->flt_region_vpd_nvram = start;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
break;
if (ha->flags.port0)
ha->flt_region_vpd = start;
break;
case FLT_REG_VPD_1:
- if (IS_QLA82XX(ha) || IS_QLA8031(ha))
+ if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
break;
if (!ha->flags.port0)
ha->flt_region_vpd = start;
@@ -789,9 +789,17 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
case FLT_REG_BOOT_CODE_82XX:
ha->flt_region_boot = start;
break;
+ case FLT_REG_BOOT_CODE_8044:
+ if (IS_QLA8044(ha))
+ ha->flt_region_boot = start;
+ break;
case FLT_REG_FW_82XX:
ha->flt_region_fw = start;
break;
+ case FLT_REG_CNA_FW:
+ if (IS_CNA_CAPABLE(ha))
+ ha->flt_region_fw = start;
+ break;
case FLT_REG_GOLD_FW_82XX:
ha->flt_region_gold_fw = start;
break;
@@ -803,13 +811,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
ha->flt_region_vpd = start;
break;
case FLT_REG_FCOE_NVRAM_0:
- if (!IS_QLA8031(ha))
+ if (!(IS_QLA8031(ha) || IS_QLA8044(ha)))
break;
if (ha->flags.port0)
ha->flt_region_nvram = start;
break;
case FLT_REG_FCOE_NVRAM_1:
- if (!IS_QLA8031(ha))
+ if (!(IS_QLA8031(ha) || IS_QLA8044(ha)))
break;
if (!ha->flags.port0)
ha->flt_region_nvram = start;
@@ -883,7 +891,13 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
mid = le16_to_cpu(fdt->man_id);
fid = le16_to_cpu(fdt->id);
ha->fdt_wrt_disable = fdt->wrt_disable_bits;
- ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0300 | fdt->erase_cmd);
+ ha->fdt_wrt_enable = fdt->wrt_enable_bits;
+ ha->fdt_wrt_sts_reg_cmd = fdt->wrt_sts_reg_cmd;
+ if (IS_QLA8044(ha))
+ ha->fdt_erase_cmd = fdt->erase_cmd;
+ else
+ ha->fdt_erase_cmd =
+ flash_conf_addr(ha, 0x0300 | fdt->erase_cmd);
ha->fdt_block_size = le32_to_cpu(fdt->block_size);
if (fdt->unprotect_sec_cmd) {
ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0300 |
@@ -895,7 +909,7 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
goto done;
no_flash_data:
loc = locations[0];
- if (IS_QLA82XX(ha)) {
+ if (IS_P3P_TYPE(ha)) {
ha->fdt_block_size = FLASH_BLK_SIZE_64K;
goto done;
}
@@ -946,7 +960,7 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
- if (!IS_QLA82XX(ha))
+ if (!(IS_P3P_TYPE(ha)))
return;
wptr = (uint32_t *)req->ring;
@@ -1008,6 +1022,9 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
if (ha->flags.nic_core_reset_hdlr_active)
return;
+ if (IS_QLA8044(ha))
+ return;
+
ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr,
ha->flt_region_npiv_conf << 2, sizeof(struct qla_npiv_header));
if (hdr.version == __constant_cpu_to_le16(0xffff))
@@ -1302,7 +1319,7 @@ qla24xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
uint32_t *dwptr;
struct qla_hw_data *ha = vha->hw;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
return buf;
/* Dword reads to flash. */
@@ -1360,7 +1377,7 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
ret = QLA_SUCCESS;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
return ret;
/* Enable flash write. */
@@ -1474,7 +1491,7 @@ qla2x00_beacon_blink(struct scsi_qla_host *vha)
struct qla_hw_data *ha = vha->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
return;
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1752,7 +1769,7 @@ qla24xx_beacon_on(struct scsi_qla_host *vha)
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
return QLA_SUCCESS;
if (IS_QLA8031(ha) || IS_QLA81XX(ha))
@@ -1804,7 +1821,7 @@ qla24xx_beacon_off(struct scsi_qla_host *vha)
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
return QLA_SUCCESS;
ha->beacon_blink_led = 0;
@@ -2822,6 +2839,121 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
}
int
+qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
+{
+ int ret = QLA_SUCCESS;
+ uint32_t pcihdr, pcids;
+ uint32_t *dcode;
+ uint8_t *bcode;
+ uint8_t code_type, last_image;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!mbuf)
+ return QLA_FUNCTION_FAILED;
+
+ memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
+ memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
+ memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
+ memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
+
+ dcode = mbuf;
+
+ /* Begin with first PCI expansion ROM header. */
+ pcihdr = ha->flt_region_boot << 2;
+ last_image = 1;
+ do {
+ /* Verify PCI expansion ROM header. */
+ ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, pcihdr,
+ 0x20 * 4);
+ bcode = mbuf + (pcihdr % 4);
+ if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) {
+ /* No signature */
+ ql_log(ql_log_fatal, vha, 0x0154,
+ "No matching ROM signature.\n");
+ ret = QLA_FUNCTION_FAILED;
+ break;
+ }
+
+ /* Locate PCI data structure. */
+ pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
+
+ ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, pcids,
+ 0x20 * 4);
+ bcode = mbuf + (pcihdr % 4);
+
+ /* Validate signature of PCI data structure. */
+ if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
+ bcode[0x2] != 'I' || bcode[0x3] != 'R') {
+ /* Incorrect header. */
+ ql_log(ql_log_fatal, vha, 0x0155,
+ "PCI data struct not found pcir_adr=%x.\n", pcids);
+ ret = QLA_FUNCTION_FAILED;
+ break;
+ }
+
+ /* Read version */
+ code_type = bcode[0x14];
+ switch (code_type) {
+ case ROM_CODE_TYPE_BIOS:
+ /* Intel x86, PC-AT compatible. */
+ ha->bios_revision[0] = bcode[0x12];
+ ha->bios_revision[1] = bcode[0x13];
+ ql_dbg(ql_dbg_init, vha, 0x0156,
+ "Read BIOS %d.%d.\n",
+ ha->bios_revision[1], ha->bios_revision[0]);
+ break;
+ case ROM_CODE_TYPE_FCODE:
+ /* Open Firmware standard for PCI (FCode). */
+ ha->fcode_revision[0] = bcode[0x12];
+ ha->fcode_revision[1] = bcode[0x13];
+ ql_dbg(ql_dbg_init, vha, 0x0157,
+ "Read FCODE %d.%d.\n",
+ ha->fcode_revision[1], ha->fcode_revision[0]);
+ break;
+ case ROM_CODE_TYPE_EFI:
+ /* Extensible Firmware Interface (EFI). */
+ ha->efi_revision[0] = bcode[0x12];
+ ha->efi_revision[1] = bcode[0x13];
+ ql_dbg(ql_dbg_init, vha, 0x0158,
+ "Read EFI %d.%d.\n",
+ ha->efi_revision[1], ha->efi_revision[0]);
+ break;
+ default:
+ ql_log(ql_log_warn, vha, 0x0159,
+ "Unrecognized code type %x at pcids %x.\n",
+ code_type, pcids);
+ break;
+ }
+
+ last_image = bcode[0x15] & BIT_7;
+
+ /* Locate next PCI expansion ROM. */
+ pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
+ } while (!last_image);
+
+ /* Read firmware image information. */
+ memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
+ dcode = mbuf;
+ ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, ha->flt_region_fw << 2,
+ 0x20);
+ bcode = mbuf + (pcihdr % 4);
+
+ /* Validate signature of PCI data structure. */
+ if (bcode[0x0] == 0x3 && bcode[0x1] == 0x0 &&
+ bcode[0x2] == 0x40 && bcode[0x3] == 0x40) {
+ ha->fw_revision[0] = bcode[0x4];
+ ha->fw_revision[1] = bcode[0x5];
+ ha->fw_revision[2] = bcode[0x6];
+ ql_dbg(ql_dbg_init, vha, 0x0153,
+ "Firmware revision %d.%d.%d\n",
+ ha->fw_revision[0], ha->fw_revision[1],
+ ha->fw_revision[2]);
+ }
+
+ return ret;
+}
+
+int
qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
{
int ret = QLA_SUCCESS;
@@ -2832,7 +2964,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
int i;
struct qla_hw_data *ha = vha->hw;
- if (IS_QLA82XX(ha))
+ if (IS_P3P_TYPE(ha))
return ret;
if (!mbuf)
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 83a8f7a9ec7..ff12d4677cc 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -430,13 +430,8 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
}
ql_dbg(ql_dbg_tgt, vha, 0xe047,
- "scsi(%ld): resetting (session %p from port "
- "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, "
- "mcmd %x, loop_id %d)\n", vha->host_no, sess,
- 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],
+ "scsi(%ld): resetting (session %p from port %8phC mcmd %x, "
+ "loop_id %d)\n", vha->host_no, sess, sess->port_name,
mcmd, loop_id);
lun = a->u.isp24.fcp_cmnd.lun;
@@ -467,15 +462,10 @@ static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
sess->expires = jiffies + dev_loss_tmo * HZ;
ql_dbg(ql_dbg_tgt, sess->vha, 0xe048,
- "qla_target(%d): session for port %02x:%02x:%02x:"
- "%02x:%02x:%02x:%02x:%02x (loop ID %d) scheduled for "
+ "qla_target(%d): session for port %8phC (loop ID %d) scheduled for "
"deletion in %u secs (expires: %lu) immed: %d\n",
- sess->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, dev_loss_tmo, sess->expires, immediate);
+ sess->vha->vp_idx, sess->port_name, sess->loop_id, dev_loss_tmo,
+ sess->expires, immediate);
if (immediate)
schedule_delayed_work(&tgt->sess_del_work, 0);
@@ -630,13 +620,9 @@ static struct qla_tgt_sess *qlt_create_sess(
sess = kzalloc(sizeof(*sess), GFP_KERNEL);
if (!sess) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04a,
- "qla_target(%u): session allocation failed, "
- "all commands from port %02x:%02x:%02x:%02x:"
- "%02x:%02x:%02x:%02x will be refused", vha->vp_idx,
- fcport->port_name[0], fcport->port_name[1],
- fcport->port_name[2], fcport->port_name[3],
- fcport->port_name[4], fcport->port_name[5],
- fcport->port_name[6], fcport->port_name[7]);
+ "qla_target(%u): session allocation failed, all commands "
+ "from port %8phC will be refused", vha->vp_idx,
+ fcport->port_name);
return NULL;
}
@@ -680,15 +666,11 @@ static struct qla_tgt_sess *qlt_create_sess(
spin_unlock_irqrestore(&ha->hardware_lock, flags);
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b,
- "qla_target(%d): %ssession for wwn %02x:%02x:%02x:%02x:"
- "%02x:%02x:%02x:%02x (loop_id %d, s_id %x:%x:%x, confirmed"
- " completion %ssupported) added\n",
- vha->vp_idx, local ? "local " : "", fcport->port_name[0],
- fcport->port_name[1], fcport->port_name[2], fcport->port_name[3],
- fcport->port_name[4], fcport->port_name[5], fcport->port_name[6],
- fcport->port_name[7], fcport->loop_id, sess->s_id.b.domain,
- sess->s_id.b.area, sess->s_id.b.al_pa, sess->conf_compl_supported ?
- "" : "not ");
+ "qla_target(%d): %ssession for wwn %8phC (loop_id %d, "
+ "s_id %x:%x:%x, confirmed completion %ssupported) added\n",
+ vha->vp_idx, local ? "local " : "", fcport->port_name,
+ fcport->loop_id, sess->s_id.b.domain, sess->s_id.b.area,
+ sess->s_id.b.al_pa, sess->conf_compl_supported ? "" : "not ");
return sess;
}
@@ -730,13 +712,9 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
qlt_undelete_sess(sess);
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04c,
- "qla_target(%u): %ssession for port %02x:"
- "%02x:%02x:%02x:%02x:%02x:%02x:%02x (loop ID %d) "
- "reappeared\n", vha->vp_idx, sess->local ? "local "
- : "", 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],
+ "qla_target(%u): %ssession for port %8phC "
+ "(loop ID %d) reappeared\n", vha->vp_idx,
+ sess->local ? "local " : "", sess->port_name,
sess->loop_id);
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf007,
@@ -749,13 +727,8 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
if (sess && sess->local) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04d,
"qla_target(%u): local session for "
- "port %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
- "(loop ID %d) became global\n", vha->vp_idx,
- fcport->port_name[0], fcport->port_name[1],
- fcport->port_name[2], fcport->port_name[3],
- fcport->port_name[4], fcport->port_name[5],
- fcport->port_name[6], fcport->port_name[7],
- sess->loop_id);
+ "port %8phC (loop ID %d) became global\n", vha->vp_idx,
+ fcport->port_name, sess->loop_id);
sess->local = 0;
}
ha->tgt.tgt_ops->put_sess(sess);
@@ -2840,10 +2813,8 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
int res = 0;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf026,
- "qla_target(%d): Port ID: 0x%02x:%02x:%02x"
- " ELS opcode: 0x%02x\n", vha->vp_idx, iocb->u.isp24.port_id[0],
- iocb->u.isp24.port_id[1], iocb->u.isp24.port_id[2],
- iocb->u.isp24.status_subcode);
+ "qla_target(%d): Port ID: 0x%3phC ELS opcode: 0x%02x\n",
+ vha->vp_idx, iocb->u.isp24.port_id, iocb->u.isp24.status_subcode);
switch (iocb->u.isp24.status_subcode) {
case ELS_PLOGI:
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 6c66d22eb1b..a808e293dae 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.05.00.03-k"
+#define QLA2XXX_VERSION "8.06.00.08-k"
#define QLA_DRIVER_MAJOR_VER 8
-#define QLA_DRIVER_MINOR_VER 5
+#define QLA_DRIVER_MINOR_VER 6
#define QLA_DRIVER_PATCH_VER 0
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index a318092e033..a6da313e253 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1474,15 +1474,11 @@ static void tcm_qla2xxx_update_sess(struct qla_tgt_sess *sess, port_id_t s_id,
if (sess->loop_id != loop_id || sess->s_id.b24 != s_id.b24)
- pr_info("Updating session %p from port %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x loop_id %d -> %d s_id %x:%x:%x -> %x:%x:%x\n",
- sess,
- 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, loop_id,
- sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
- s_id.b.domain, s_id.b.area, s_id.b.al_pa);
+ pr_info("Updating session %p from port %8phC loop_id %d -> %d s_id %x:%x:%x -> %x:%x:%x\n",
+ sess, sess->port_name,
+ sess->loop_id, loop_id, sess->s_id.b.domain,
+ sess->s_id.b.area, sess->s_id.b.al_pa, s_id.b.domain,
+ s_id.b.area, s_id.b.al_pa);
if (sess->loop_id != loop_id) {
/*
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c
index d607eb8e24c..8196c2f7915 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.c
+++ b/drivers/scsi/qla4xxx/ql4_83xx.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -259,8 +259,8 @@ void qla4_83xx_rom_lock_recovery(struct scsi_qla_host *ha)
* Return: On success return QLA_SUCCESS
* On error return QLA_ERROR
**/
-static int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha, uint64_t addr,
- uint32_t *data, uint32_t count)
+int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha, uint64_t addr,
+ uint32_t *data, uint32_t count)
{
int i, j;
uint32_t agt_ctrl;
@@ -1473,9 +1473,9 @@ int qla4_83xx_isp_reset(struct scsi_qla_host *ha)
__func__));
}
- /* For ISP8324, Reset owner is NIC, iSCSI or FCOE based on priority
- * and which drivers are present. Unlike ISP8022, the function setting
- * NEED_RESET, may not be the Reset owner. */
+ /* For ISP8324 and ISP8042, Reset owner is NIC, iSCSI or FCOE based on
+ * priority and which drivers are present. Unlike ISP8022, the function
+ * setting NEED_RESET, may not be the Reset owner. */
if (qla4_83xx_can_perform_reset(ha))
set_bit(AF_8XXX_RST_OWNER, &ha->flags);
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.h b/drivers/scsi/qla4xxx/ql4_83xx.h
index fab237fa32c..a0de6e25ea5 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.h
+++ b/drivers/scsi/qla4xxx/ql4_83xx.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -290,4 +290,38 @@ struct qla4_83xx_idc_information {
uint32_t info3; /* IDC additional info */
};
+#define QLA83XX_PEX_DMA_ENGINE_INDEX 8
+#define QLA83XX_PEX_DMA_BASE_ADDRESS 0x77320000
+#define QLA83XX_PEX_DMA_NUM_OFFSET 0x10000
+#define QLA83XX_PEX_DMA_CMD_ADDR_LOW 0x0
+#define QLA83XX_PEX_DMA_CMD_ADDR_HIGH 0x04
+#define QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL 0x08
+
+#define QLA83XX_PEX_DMA_READ_SIZE (16 * 1024)
+#define QLA83XX_PEX_DMA_MAX_WAIT (100 * 100) /* Max wait of 100 msecs */
+
+/* Read Memory: For Pex-DMA */
+struct qla4_83xx_minidump_entry_rdmem_pex_dma {
+ struct qla8xxx_minidump_entry_hdr h;
+ uint32_t desc_card_addr;
+ uint16_t dma_desc_cmd;
+ uint8_t rsvd[2];
+ uint32_t start_dma_cmd;
+ uint8_t rsvd2[12];
+ uint32_t read_addr;
+ uint32_t read_data_size;
+};
+
+struct qla4_83xx_pex_dma_descriptor {
+ struct {
+ uint32_t read_data_size; /* 0-23: size, 24-31: rsvd */
+ uint8_t rsvd[2];
+ uint16_t dma_desc_cmd;
+ } cmd;
+ uint64_t src_addr;
+ uint64_t dma_bus_addr; /* 0-3: desc-cmd, 4-7: pci-func,
+ * 8-15: desc-cmd */
+ uint8_t rsvd[24];
+} __packed;
+
#endif
diff --git a/drivers/scsi/qla4xxx/ql4_attr.c b/drivers/scsi/qla4xxx/ql4_attr.c
index 19ee55a6226..463239c972b 100644
--- a/drivers/scsi/qla4xxx/ql4_attr.c
+++ b/drivers/scsi/qla4xxx/ql4_attr.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2011 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -83,7 +83,7 @@ qla4_8xxx_sysfs_write_fw_dump(struct file *filep, struct kobject *kobj,
qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
QLA8XXX_DEV_NEED_RESET);
if (is_qla8022(ha) ||
- (is_qla8032(ha) &&
+ ((is_qla8032(ha) || is_qla8042(ha)) &&
qla4_83xx_can_perform_reset(ha))) {
set_bit(AF_8XXX_RST_OWNER, &ha->flags);
set_bit(AF_FW_RECOVERY, &ha->flags);
@@ -158,14 +158,12 @@ qla4xxx_fw_version_show(struct device *dev,
if (is_qla80XX(ha))
return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
- ha->firmware_version[0],
- ha->firmware_version[1],
- ha->patch_number, ha->build_number);
+ ha->fw_info.fw_major, ha->fw_info.fw_minor,
+ ha->fw_info.fw_patch, ha->fw_info.fw_build);
else
return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d.%02d\n",
- ha->firmware_version[0],
- ha->firmware_version[1],
- ha->patch_number, ha->build_number);
+ ha->fw_info.fw_major, ha->fw_info.fw_minor,
+ ha->fw_info.fw_patch, ha->fw_info.fw_build);
}
static ssize_t
@@ -181,8 +179,8 @@ qla4xxx_iscsi_version_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
- return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->iscsi_major,
- ha->iscsi_minor);
+ return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fw_info.iscsi_major,
+ ha->fw_info.iscsi_minor);
}
static ssize_t
@@ -191,8 +189,8 @@ qla4xxx_optrom_version_show(struct device *dev, struct device_attribute *attr,
{
struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d.%02d\n",
- ha->bootload_major, ha->bootload_minor,
- ha->bootload_patch, ha->bootload_build);
+ ha->fw_info.bootload_major, ha->fw_info.bootload_minor,
+ ha->fw_info.bootload_patch, ha->fw_info.bootload_build);
}
static ssize_t
@@ -259,6 +257,63 @@ qla4xxx_hba_model_show(struct device *dev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_name);
}
+static ssize_t
+qla4xxx_fw_timestamp_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+ return snprintf(buf, PAGE_SIZE, "%s %s\n", ha->fw_info.fw_build_date,
+ ha->fw_info.fw_build_time);
+}
+
+static ssize_t
+qla4xxx_fw_build_user_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+ return snprintf(buf, PAGE_SIZE, "%s\n", ha->fw_info.fw_build_user);
+}
+
+static ssize_t
+qla4xxx_fw_ext_timestamp_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+ return snprintf(buf, PAGE_SIZE, "%s\n", ha->fw_info.extended_timestamp);
+}
+
+static ssize_t
+qla4xxx_fw_load_src_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+ char *load_src = NULL;
+
+ switch (ha->fw_info.fw_load_source) {
+ case 1:
+ load_src = "Flash Primary";
+ break;
+ case 2:
+ load_src = "Flash Secondary";
+ break;
+ case 3:
+ load_src = "Host Download";
+ break;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", load_src);
+}
+
+static ssize_t
+qla4xxx_fw_uptime_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+ qla4xxx_about_firmware(ha);
+ return snprintf(buf, PAGE_SIZE, "%u.%u secs\n", ha->fw_uptime_secs,
+ ha->fw_uptime_msecs);
+}
+
static DEVICE_ATTR(fw_version, S_IRUGO, qla4xxx_fw_version_show, NULL);
static DEVICE_ATTR(serial_num, S_IRUGO, qla4xxx_serial_num_show, NULL);
static DEVICE_ATTR(iscsi_version, S_IRUGO, qla4xxx_iscsi_version_show, NULL);
@@ -269,6 +324,12 @@ static DEVICE_ATTR(phy_port_cnt, S_IRUGO, qla4xxx_phy_port_cnt_show, NULL);
static DEVICE_ATTR(phy_port_num, S_IRUGO, qla4xxx_phy_port_num_show, NULL);
static DEVICE_ATTR(iscsi_func_cnt, S_IRUGO, qla4xxx_iscsi_func_cnt_show, NULL);
static DEVICE_ATTR(hba_model, S_IRUGO, qla4xxx_hba_model_show, NULL);
+static DEVICE_ATTR(fw_timestamp, S_IRUGO, qla4xxx_fw_timestamp_show, NULL);
+static DEVICE_ATTR(fw_build_user, S_IRUGO, qla4xxx_fw_build_user_show, NULL);
+static DEVICE_ATTR(fw_ext_timestamp, S_IRUGO, qla4xxx_fw_ext_timestamp_show,
+ NULL);
+static DEVICE_ATTR(fw_load_src, S_IRUGO, qla4xxx_fw_load_src_show, NULL);
+static DEVICE_ATTR(fw_uptime, S_IRUGO, qla4xxx_fw_uptime_show, NULL);
struct device_attribute *qla4xxx_host_attrs[] = {
&dev_attr_fw_version,
@@ -281,5 +342,10 @@ struct device_attribute *qla4xxx_host_attrs[] = {
&dev_attr_phy_port_num,
&dev_attr_iscsi_func_cnt,
&dev_attr_hba_model,
+ &dev_attr_fw_timestamp,
+ &dev_attr_fw_build_user,
+ &dev_attr_fw_ext_timestamp,
+ &dev_attr_fw_load_src,
+ &dev_attr_fw_uptime,
NULL,
};
diff --git a/drivers/scsi/qla4xxx/ql4_bsg.c b/drivers/scsi/qla4xxx/ql4_bsg.c
index 8acdc582ff6..cf8fdf1d125 100644
--- a/drivers/scsi/qla4xxx/ql4_bsg.c
+++ b/drivers/scsi/qla4xxx/ql4_bsg.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2011 QLogic Corporation
+ * Copyright (c) 2011-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
index 77b7c594010..5649e9ef59a 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.c
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -141,21 +141,22 @@ void qla4_8xxx_dump_peg_reg(struct scsi_qla_host *ha)
if (is_qla8022(ha)) {
ql4_printk(KERN_INFO, ha,
- "scsi(%ld): %s, ISP8022 Dumping hw/fw registers:\n"
+ "scsi(%ld): %s, ISP%04x Dumping hw/fw registers:\n"
" PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
" PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
" PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
- " PEG_NET_4_PC: 0x%x\n", ha->host_no,
- __func__, halt_status1, halt_status2,
+ " PEG_NET_4_PC: 0x%x\n", ha->host_no, __func__,
+ ha->pdev->device, halt_status1, halt_status2,
qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c),
qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c),
qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c),
qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c),
qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c));
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
ql4_printk(KERN_INFO, ha,
- "scsi(%ld): %s, ISP8324 Dumping hw/fw registers:\n"
+ "scsi(%ld): %s, ISP%04x Dumping hw/fw registers:\n"
" PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n",
- ha->host_no, __func__, halt_status1, halt_status2);
+ ha->host_no, __func__, ha->pdev->device,
+ halt_status1, halt_status2);
}
}
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index ddf16a86bbf..41327d46ecf 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -64,6 +64,10 @@
#define PCI_DEVICE_ID_QLOGIC_ISP8324 0x8032
#endif
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP8042
+#define PCI_DEVICE_ID_QLOGIC_ISP8042 0x8042
+#endif
+
#define ISP4XXX_PCI_FN_1 0x1
#define ISP4XXX_PCI_FN_2 0x3
@@ -201,6 +205,7 @@
#define MAX_RESET_HA_RETRIES 2
#define FW_ALIVE_WAIT_TOV 3
+#define IDC_EXTEND_TOV 8
#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr)
@@ -335,6 +340,7 @@ struct ql4_tuple_ddb {
#define DF_BOOT_TGT 1 /* Boot target entry */
#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */
#define DF_FO_MASKED 3
+#define DF_DISABLE_RELOGIN 4 /* Disable relogin to device */
enum qla4_work_type {
QLA4_EVENT_AEN,
@@ -557,6 +563,7 @@ struct scsi_qla_host {
#define DPC_HA_UNRECOVERABLE 21 /* 0x00080000 ISP-82xx only*/
#define DPC_HA_NEED_QUIESCENT 22 /* 0x00100000 ISP-82xx only*/
#define DPC_POST_IDC_ACK 23 /* 0x00200000 */
+#define DPC_RESTORE_ACB 24 /* 0x01000000 */
struct Scsi_Host *host; /* pointer to host data */
uint32_t tot_ddbs;
@@ -734,12 +741,9 @@ struct scsi_qla_host {
struct iscsi_iface *iface_ipv6_1;
/* --- From About Firmware --- */
- uint16_t iscsi_major;
- uint16_t iscsi_minor;
- uint16_t bootload_major;
- uint16_t bootload_minor;
- uint16_t bootload_patch;
- uint16_t bootload_build;
+ struct about_fw_info fw_info;
+ uint32_t fw_uptime_secs; /* seconds elapsed since fw bootup */
+ uint32_t fw_uptime_msecs; /* milliseconds beyond elapsed seconds */
uint16_t def_timeout; /* Default login timeout */
uint32_t flash_state;
@@ -780,9 +784,11 @@ struct scsi_qla_host {
uint32_t *reg_tbl;
struct qla4_83xx_reset_template reset_tmplt;
struct device_reg_83xx __iomem *qla4_83xx_reg; /* Base I/O address
- for ISP8324 */
+ for ISP8324 and
+ and ISP8042 */
uint32_t pf_bit;
struct qla4_83xx_idc_information idc_info;
+ struct addr_ctrl_blk *saved_acb;
};
struct ql4_task_data {
@@ -850,9 +856,14 @@ static inline int is_qla8032(struct scsi_qla_host *ha)
return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8324;
}
+static inline int is_qla8042(struct scsi_qla_host *ha)
+{
+ return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8042;
+}
+
static inline int is_qla80XX(struct scsi_qla_host *ha)
{
- return is_qla8022(ha) || is_qla8032(ha);
+ return is_qla8022(ha) || is_qla8032(ha) || is_qla8042(ha);
}
static inline int is_aer_supported(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index c7b8892b5a8..51d1a70f8b4 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -458,6 +458,7 @@ struct qla_flt_region {
#define MBOX_CMD_GET_CONN_EVENT_LOG 0x0077
#define MBOX_CMD_IDC_ACK 0x0101
+#define MBOX_CMD_IDC_TIME_EXTEND 0x0102
#define MBOX_CMD_PORT_RESET 0x0120
#define MBOX_CMD_SET_PORT_CONFIG 0x0122
@@ -502,6 +503,7 @@ struct qla_flt_region {
#define MBOX_ASTS_SYSTEM_WARNING_EVENT 0x8036
#define MBOX_ASTS_IDC_COMPLETE 0x8100
#define MBOX_ASTS_IDC_REQUEST_NOTIFICATION 0x8101
+#define MBOX_ASTS_IDC_TIME_EXTEND_NOTIFICATION 0x8102
#define MBOX_ASTS_DCBX_CONF_CHANGE 0x8110
#define MBOX_ASTS_TXSCVR_INSERTED 0x8130
#define MBOX_ASTS_TXSCVR_REMOVED 0x8131
@@ -512,6 +514,10 @@ struct qla_flt_region {
#define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR 0x8022
#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027
+/* ACB Configuration Defines */
+#define ACB_CONFIG_DISABLE 0x00
+#define ACB_CONFIG_SET 0x01
+
/* ACB State Defines */
#define ACB_STATE_UNCONFIGURED 0x00
#define ACB_STATE_INVALID 0x01
@@ -955,7 +961,7 @@ struct about_fw_info {
uint16_t bootload_minor; /* 46 - 47 */
uint16_t bootload_patch; /* 48 - 49 */
uint16_t bootload_build; /* 4A - 4B */
- uint8_t reserved2[180]; /* 4C - FF */
+ uint8_t extended_timestamp[180];/* 4C - FF */
};
struct crash_record {
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 4a428009f69..e6f2a2669db 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -266,6 +266,14 @@ int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options,
dma_addr_t dma_addr);
int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username,
char *password, uint16_t chap_index);
+int qla4xxx_disable_acb(struct scsi_qla_host *ha);
+int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
+ uint32_t *mbox_sts, dma_addr_t acb_dma);
+int qla4xxx_get_acb(struct scsi_qla_host *ha, dma_addr_t acb_dma,
+ uint32_t acb_type, uint32_t len);
+int qla4_84xx_config_acb(struct scsi_qla_host *ha, int acb_config);
+int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha,
+ uint64_t addr, uint32_t *data, uint32_t count);
extern int ql4xextended_error_logging;
extern int ql4xdontresethba;
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 8fc8548ba4b..7456eeb2e58 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -107,7 +107,7 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha)
(unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_in);
writel(0,
(unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_out);
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
writel(0,
(unsigned long __iomem *)&ha->qla4_83xx_reg->req_q_in);
writel(0,
@@ -940,7 +940,7 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset)
* while switching from polling to interrupt mode. IOCB interrupts are
* enabled via isp_ops->enable_intrs.
*/
- if (is_qla8032(ha))
+ if (is_qla8032(ha) || is_qla8042(ha))
qla4_83xx_enable_mbox_intrs(ha);
if (qla4xxx_about_firmware(ha) == QLA_ERROR)
diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h
index 6f4decd44c6..8503ad643bd 100644
--- a/drivers/scsi/qla4xxx/ql4_inline.h
+++ b/drivers/scsi/qla4xxx/ql4_inline.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index fad71ed067e..e5697ab144d 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 482287f4005..7dff09f09b7 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -588,7 +588,7 @@ static int qla4_83xx_loopback_in_progress(struct scsi_qla_host *ha)
{
int rval = 1;
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
if ((ha->idc_info.info2 & ENABLE_INTERNAL_LOOPBACK) ||
(ha->idc_info.info2 & ENABLE_EXTERNAL_LOOPBACK)) {
DEBUG2(ql4_printk(KERN_INFO, ha,
@@ -621,7 +621,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
__le32 __iomem *mailbox_out;
- if (is_qla8032(ha))
+ if (is_qla8032(ha) || is_qla8042(ha))
mailbox_out = &ha->qla4_83xx_reg->mailbox_out[0];
else if (is_qla8022(ha))
mailbox_out = &ha->qla4_82xx_reg->mailbox_out[0];
@@ -665,7 +665,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
qla4xxx_dump_registers(ha);
if ((is_qla8022(ha) && ql4xdontresethba) ||
- (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
+ ((is_qla8032(ha) || is_qla8042(ha)) &&
+ qla4_83xx_idc_dontreset(ha))) {
DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n",
ha->host_no, __func__));
} else {
@@ -744,17 +745,23 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
* mbox_sts[3] = new ACB state */
if ((mbox_sts[3] == ACB_STATE_VALID) &&
((mbox_sts[2] == ACB_STATE_TENTATIVE) ||
- (mbox_sts[2] == ACB_STATE_ACQUIRING)))
+ (mbox_sts[2] == ACB_STATE_ACQUIRING))) {
set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
- else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
- (mbox_sts[2] == ACB_STATE_VALID)) {
+ } else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
+ (mbox_sts[2] == ACB_STATE_VALID)) {
if (is_qla80XX(ha))
set_bit(DPC_RESET_HA_FW_CONTEXT,
&ha->dpc_flags);
else
set_bit(DPC_RESET_HA, &ha->dpc_flags);
- } else if ((mbox_sts[3] == ACB_STATE_UNCONFIGURED))
+ } else if (mbox_sts[3] == ACB_STATE_DISABLING) {
+ ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB in disabling state\n",
+ ha->host_no, __func__);
+ } else if ((mbox_sts[3] == ACB_STATE_UNCONFIGURED)) {
complete(&ha->disable_acb_comp);
+ ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB state unconfigured\n",
+ ha->host_no, __func__);
+ }
break;
case MBOX_ASTS_MAC_ADDRESS_CHANGED:
@@ -836,7 +843,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
case MBOX_ASTS_IDC_REQUEST_NOTIFICATION:
{
uint32_t opcode;
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x\n",
ha->host_no, mbox_sts[0],
@@ -858,7 +865,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
}
case MBOX_ASTS_IDC_COMPLETE:
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x\n",
ha->host_no, mbox_sts[0],
@@ -868,10 +875,15 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
"scsi:%ld: AEN %04x IDC Complete notification\n",
ha->host_no, mbox_sts[0]));
- if (qla4_83xx_loopback_in_progress(ha))
+ if (qla4_83xx_loopback_in_progress(ha)) {
set_bit(AF_LOOPBACK, &ha->flags);
- else
+ } else {
clear_bit(AF_LOOPBACK, &ha->flags);
+ if (ha->saved_acb)
+ set_bit(DPC_RESTORE_ACB,
+ &ha->dpc_flags);
+ }
+ qla4xxx_wake_dpc(ha);
}
break;
@@ -886,6 +898,17 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
ha->host_no, mbox_sts[0]));
break;
+ case MBOX_ASTS_IDC_TIME_EXTEND_NOTIFICATION:
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
+ ha->host_no, mbox_sts[0], mbox_sts[1],
+ mbox_sts[2], mbox_sts[3], mbox_sts[4],
+ mbox_sts[5]));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x Received IDC Extend Timeout notification\n",
+ ha->host_no, mbox_sts[0]));
+ break;
+
case MBOX_ASTS_INITIALIZATION_FAILED:
DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: AEN %04x, mbox_sts[3]=%08x\n",
@@ -1297,7 +1320,7 @@ qla4_8xxx_default_intr_handler(int irq, void *dev_id)
uint32_t intr_status;
uint8_t reqs_count = 0;
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
qla4_83xx_mailbox_intr_handler(irq, dev_id);
} else {
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1334,7 +1357,7 @@ qla4_8xxx_msix_rsp_q(int irq, void *dev_id)
uint32_t ival = 0;
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
ival = readl(&ha->qla4_83xx_reg->iocb_int_mask);
if (ival == 0) {
ql4_printk(KERN_INFO, ha, "%s: It is a spurious iocb interrupt!\n",
@@ -1425,10 +1448,10 @@ int qla4xxx_request_irqs(struct scsi_qla_host *ha)
goto try_intx;
if (ql4xenablemsix == 2) {
- /* Note: MSI Interrupts not supported for ISP8324 */
- if (is_qla8032(ha)) {
- ql4_printk(KERN_INFO, ha, "%s: MSI Interrupts not supported for ISP8324, Falling back-to INTx mode\n",
- __func__);
+ /* Note: MSI Interrupts not supported for ISP8324 and ISP8042 */
+ if (is_qla8032(ha) || is_qla8042(ha)) {
+ ql4_printk(KERN_INFO, ha, "%s: MSI Interrupts not supported for ISP%04x, Falling back-to INTx mode\n",
+ __func__, ha->pdev->device);
goto try_intx;
}
goto try_msi;
@@ -1444,9 +1467,9 @@ int qla4xxx_request_irqs(struct scsi_qla_host *ha)
"MSI-X: Enabled (0x%X).\n", ha->revision_id));
goto irq_attached;
} else {
- if (is_qla8032(ha)) {
- ql4_printk(KERN_INFO, ha, "%s: ISP8324: MSI-X: Falling back-to INTx mode. ret = %d\n",
- __func__, ret);
+ if (is_qla8032(ha) || is_qla8042(ha)) {
+ ql4_printk(KERN_INFO, ha, "%s: ISP%04x: MSI-X: Falling back-to INTx mode. ret = %d\n",
+ __func__, ha->pdev->device, ret);
goto try_intx;
}
}
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index a501beab3ff..62d4208af21 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -1,10 +1,11 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
+#include <linux/ctype.h>
#include "ql4_def.h"
#include "ql4_glbl.h"
#include "ql4_dbg.h"
@@ -52,7 +53,7 @@ static int qla4xxx_is_intr_poll_mode(struct scsi_qla_host *ha)
{
int rval = 1;
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
if (test_bit(AF_IRQ_ATTACHED, &ha->flags) &&
test_bit(AF_83XX_MBOX_INTR_ON, &ha->flags))
rval = 0;
@@ -223,7 +224,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
CRB_NIU_XG_PAUSE_CTL_P0 |
CRB_NIU_XG_PAUSE_CTL_P1);
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
ql4_printk(KERN_INFO, ha, " %s: disabling pause transmit on port 0 & 1.\n",
__func__);
qla4_83xx_disable_pause(ha);
@@ -1270,16 +1271,28 @@ int qla4xxx_about_firmware(struct scsi_qla_host *ha)
}
/* Save version information. */
- ha->firmware_version[0] = le16_to_cpu(about_fw->fw_major);
- ha->firmware_version[1] = le16_to_cpu(about_fw->fw_minor);
- ha->patch_number = le16_to_cpu(about_fw->fw_patch);
- ha->build_number = le16_to_cpu(about_fw->fw_build);
- ha->iscsi_major = le16_to_cpu(about_fw->iscsi_major);
- ha->iscsi_minor = le16_to_cpu(about_fw->iscsi_minor);
- ha->bootload_major = le16_to_cpu(about_fw->bootload_major);
- ha->bootload_minor = le16_to_cpu(about_fw->bootload_minor);
- ha->bootload_patch = le16_to_cpu(about_fw->bootload_patch);
- ha->bootload_build = le16_to_cpu(about_fw->bootload_build);
+ ha->fw_info.fw_major = le16_to_cpu(about_fw->fw_major);
+ ha->fw_info.fw_minor = le16_to_cpu(about_fw->fw_minor);
+ ha->fw_info.fw_patch = le16_to_cpu(about_fw->fw_patch);
+ ha->fw_info.fw_build = le16_to_cpu(about_fw->fw_build);
+ memcpy(ha->fw_info.fw_build_date, about_fw->fw_build_date,
+ sizeof(about_fw->fw_build_date));
+ memcpy(ha->fw_info.fw_build_time, about_fw->fw_build_time,
+ sizeof(about_fw->fw_build_time));
+ strcpy((char *)ha->fw_info.fw_build_user,
+ skip_spaces((char *)about_fw->fw_build_user));
+ ha->fw_info.fw_load_source = le16_to_cpu(about_fw->fw_load_source);
+ ha->fw_info.iscsi_major = le16_to_cpu(about_fw->iscsi_major);
+ ha->fw_info.iscsi_minor = le16_to_cpu(about_fw->iscsi_minor);
+ ha->fw_info.bootload_major = le16_to_cpu(about_fw->bootload_major);
+ ha->fw_info.bootload_minor = le16_to_cpu(about_fw->bootload_minor);
+ ha->fw_info.bootload_patch = le16_to_cpu(about_fw->bootload_patch);
+ ha->fw_info.bootload_build = le16_to_cpu(about_fw->bootload_build);
+ strcpy((char *)ha->fw_info.extended_timestamp,
+ skip_spaces((char *)about_fw->extended_timestamp));
+
+ ha->fw_uptime_secs = le32_to_cpu(mbox_sts[5]);
+ ha->fw_uptime_msecs = le32_to_cpu(mbox_sts[6]);
status = QLA_SUCCESS;
exit_about_fw:
@@ -1723,6 +1736,45 @@ int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha,
return status;
}
+/**
+ * qla4_84xx_extend_idc_tmo - Extend IDC Timeout.
+ * @ha: Pointer to host adapter structure.
+ * @ext_tmo: idc timeout value
+ *
+ * Requests firmware to extend the idc timeout value.
+ **/
+static int qla4_84xx_extend_idc_tmo(struct scsi_qla_host *ha, uint32_t ext_tmo)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ int status;
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ ext_tmo &= 0xf;
+
+ mbox_cmd[0] = MBOX_CMD_IDC_TIME_EXTEND;
+ mbox_cmd[1] = ((ha->idc_info.request_desc & 0xfffff0ff) |
+ (ext_tmo << 8)); /* new timeout */
+ mbox_cmd[2] = ha->idc_info.info1;
+ mbox_cmd[3] = ha->idc_info.info2;
+ mbox_cmd[4] = ha->idc_info.info3;
+
+ status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, MBOX_REG_COUNT,
+ mbox_cmd, mbox_sts);
+ if (status != QLA_SUCCESS) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: %s: failed status %04X\n",
+ ha->host_no, __func__, mbox_sts[0]));
+ return QLA_ERROR;
+ } else {
+ ql4_printk(KERN_INFO, ha, "%s: IDC timeout extended by %d secs\n",
+ __func__, ext_tmo);
+ }
+
+ return QLA_SUCCESS;
+}
+
int qla4xxx_disable_acb(struct scsi_qla_host *ha)
{
uint32_t mbox_cmd[MBOX_REG_COUNT];
@@ -1739,6 +1791,23 @@ int qla4xxx_disable_acb(struct scsi_qla_host *ha)
DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_DISABLE_ACB "
"failed w/ status %04X %04X %04X", __func__,
mbox_sts[0], mbox_sts[1], mbox_sts[2]));
+ } else {
+ if (is_qla8042(ha) &&
+ (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE)) {
+ /*
+ * Disable ACB mailbox command takes time to complete
+ * based on the total number of targets connected.
+ * For 512 targets, it took approximately 5 secs to
+ * complete. Setting the timeout value to 8, with the 3
+ * secs buffer.
+ */
+ qla4_84xx_extend_idc_tmo(ha, IDC_EXTEND_TOV);
+ if (!wait_for_completion_timeout(&ha->disable_acb_comp,
+ IDC_EXTEND_TOV * HZ)) {
+ ql4_printk(KERN_WARNING, ha, "%s: Disable ACB Completion not received\n",
+ __func__);
+ }
+ }
}
return status;
}
@@ -2145,8 +2214,80 @@ int qla4_83xx_post_idc_ack(struct scsi_qla_host *ha)
ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n", __func__,
mbox_sts[0]);
else
- DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IDC ACK posted\n",
- __func__));
+ ql4_printk(KERN_INFO, ha, "%s: IDC ACK posted\n", __func__);
return status;
}
+
+int qla4_84xx_config_acb(struct scsi_qla_host *ha, int acb_config)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ struct addr_ctrl_blk *acb = NULL;
+ uint32_t acb_len = sizeof(struct addr_ctrl_blk);
+ int rval = QLA_SUCCESS;
+ dma_addr_t acb_dma;
+
+ acb = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct addr_ctrl_blk),
+ &acb_dma, GFP_KERNEL);
+ if (!acb) {
+ ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n", __func__);
+ rval = QLA_ERROR;
+ goto exit_config_acb;
+ }
+ memset(acb, 0, acb_len);
+
+ switch (acb_config) {
+ case ACB_CONFIG_DISABLE:
+ rval = qla4xxx_get_acb(ha, acb_dma, 0, acb_len);
+ if (rval != QLA_SUCCESS)
+ goto exit_free_acb;
+
+ rval = qla4xxx_disable_acb(ha);
+ if (rval != QLA_SUCCESS)
+ goto exit_free_acb;
+
+ if (!ha->saved_acb)
+ ha->saved_acb = kzalloc(acb_len, GFP_KERNEL);
+
+ if (!ha->saved_acb) {
+ ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n",
+ __func__);
+ rval = QLA_ERROR;
+ goto exit_config_acb;
+ }
+ memcpy(ha->saved_acb, acb, acb_len);
+ break;
+ case ACB_CONFIG_SET:
+
+ if (!ha->saved_acb) {
+ ql4_printk(KERN_ERR, ha, "%s: Can't set ACB, Saved ACB not available\n",
+ __func__);
+ rval = QLA_ERROR;
+ goto exit_free_acb;
+ }
+
+ memcpy(acb, ha->saved_acb, acb_len);
+ kfree(ha->saved_acb);
+ ha->saved_acb = NULL;
+
+ rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma);
+ if (rval != QLA_SUCCESS)
+ goto exit_free_acb;
+
+ break;
+ default:
+ ql4_printk(KERN_ERR, ha, "%s: Invalid ACB Configuration\n",
+ __func__);
+ }
+
+exit_free_acb:
+ dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), acb,
+ acb_dma);
+exit_config_acb:
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "%s %s\n", __func__,
+ rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED"));
+ return rval;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
index 325db1f2c09..3bf418fbd43 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.c
+++ b/drivers/scsi/qla4xxx/ql4_nvram.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h
index dba0514d1c7..e97d79ff16f 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.h
+++ b/drivers/scsi/qla4xxx/ql4_nvram.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index eaf00c162eb..d001202d356 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -1514,11 +1514,11 @@ qla4_8xxx_set_drv_active(struct scsi_qla_host *ha)
drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
/*
- * For ISP8324, drv_active register has 1 bit per function,
+ * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
* shift 1 by func_num to set a bit for the function.
* For ISP8022, drv_active has 4 bits per function
*/
- if (is_qla8032(ha))
+ if (is_qla8032(ha) || is_qla8042(ha))
drv_active |= (1 << ha->func_num);
else
drv_active |= (1 << (ha->func_num * 4));
@@ -1536,11 +1536,11 @@ qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha)
drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
/*
- * For ISP8324, drv_active register has 1 bit per function,
+ * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
* shift 1 by func_num to set a bit for the function.
* For ISP8022, drv_active has 4 bits per function
*/
- if (is_qla8032(ha))
+ if (is_qla8032(ha) || is_qla8042(ha))
drv_active &= ~(1 << (ha->func_num));
else
drv_active &= ~(1 << (ha->func_num * 4));
@@ -1559,11 +1559,11 @@ inline int qla4_8xxx_need_reset(struct scsi_qla_host *ha)
drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
/*
- * For ISP8324, drv_active register has 1 bit per function,
+ * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
* shift 1 by func_num to set a bit for the function.
* For ISP8022, drv_active has 4 bits per function
*/
- if (is_qla8032(ha))
+ if (is_qla8032(ha) || is_qla8042(ha))
rval = drv_state & (1 << ha->func_num);
else
rval = drv_state & (1 << (ha->func_num * 4));
@@ -1581,11 +1581,11 @@ void qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha)
drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
/*
- * For ISP8324, drv_active register has 1 bit per function,
+ * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
* shift 1 by func_num to set a bit for the function.
* For ISP8022, drv_active has 4 bits per function
*/
- if (is_qla8032(ha))
+ if (is_qla8032(ha) || is_qla8042(ha))
drv_state |= (1 << ha->func_num);
else
drv_state |= (1 << (ha->func_num * 4));
@@ -1602,11 +1602,11 @@ void qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha)
drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
/*
- * For ISP8324, drv_active register has 1 bit per function,
+ * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
* shift 1 by func_num to set a bit for the function.
* For ISP8022, drv_active has 4 bits per function
*/
- if (is_qla8032(ha))
+ if (is_qla8032(ha) || is_qla8042(ha))
drv_state &= ~(1 << ha->func_num);
else
drv_state &= ~(1 << (ha->func_num * 4));
@@ -1624,11 +1624,11 @@ qla4_8xxx_set_qsnt_ready(struct scsi_qla_host *ha)
qsnt_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
/*
- * For ISP8324, drv_active register has 1 bit per function,
+ * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
* shift 1 by func_num to set a bit for the function.
* For ISP8022, drv_active has 4 bits per function.
*/
- if (is_qla8032(ha))
+ if (is_qla8032(ha) || is_qla8042(ha))
qsnt_state |= (1 << ha->func_num);
else
qsnt_state |= (2 << (ha->func_num * 4));
@@ -1737,6 +1737,208 @@ static void qla4_8xxx_minidump_process_rdcrb(struct scsi_qla_host *ha,
*d_ptr = data_ptr;
}
+static int qla4_83xx_check_dma_engine_state(struct scsi_qla_host *ha)
+{
+ int rval = QLA_SUCCESS;
+ uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
+ uint64_t dma_base_addr = 0;
+ struct qla4_8xxx_minidump_template_hdr *tmplt_hdr = NULL;
+
+ tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *)
+ ha->fw_dump_tmplt_hdr;
+ dma_eng_num =
+ tmplt_hdr->saved_state_array[QLA83XX_PEX_DMA_ENGINE_INDEX];
+ dma_base_addr = QLA83XX_PEX_DMA_BASE_ADDRESS +
+ (dma_eng_num * QLA83XX_PEX_DMA_NUM_OFFSET);
+
+ /* Read the pex-dma's command-status-and-control register. */
+ rval = ha->isp_ops->rd_reg_indirect(ha,
+ (dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL),
+ &cmd_sts_and_cntrl);
+
+ if (rval)
+ return QLA_ERROR;
+
+ /* Check if requested pex-dma engine is available. */
+ if (cmd_sts_and_cntrl & BIT_31)
+ return QLA_SUCCESS;
+ else
+ return QLA_ERROR;
+}
+
+static int qla4_83xx_start_pex_dma(struct scsi_qla_host *ha,
+ struct qla4_83xx_minidump_entry_rdmem_pex_dma *m_hdr)
+{
+ int rval = QLA_SUCCESS, wait = 0;
+ uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
+ uint64_t dma_base_addr = 0;
+ struct qla4_8xxx_minidump_template_hdr *tmplt_hdr = NULL;
+
+ tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *)
+ ha->fw_dump_tmplt_hdr;
+ dma_eng_num =
+ tmplt_hdr->saved_state_array[QLA83XX_PEX_DMA_ENGINE_INDEX];
+ dma_base_addr = QLA83XX_PEX_DMA_BASE_ADDRESS +
+ (dma_eng_num * QLA83XX_PEX_DMA_NUM_OFFSET);
+
+ rval = ha->isp_ops->wr_reg_indirect(ha,
+ dma_base_addr + QLA83XX_PEX_DMA_CMD_ADDR_LOW,
+ m_hdr->desc_card_addr);
+ if (rval)
+ goto error_exit;
+
+ rval = ha->isp_ops->wr_reg_indirect(ha,
+ dma_base_addr + QLA83XX_PEX_DMA_CMD_ADDR_HIGH, 0);
+ if (rval)
+ goto error_exit;
+
+ rval = ha->isp_ops->wr_reg_indirect(ha,
+ dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL,
+ m_hdr->start_dma_cmd);
+ if (rval)
+ goto error_exit;
+
+ /* Wait for dma operation to complete. */
+ for (wait = 0; wait < QLA83XX_PEX_DMA_MAX_WAIT; wait++) {
+ rval = ha->isp_ops->rd_reg_indirect(ha,
+ (dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL),
+ &cmd_sts_and_cntrl);
+ if (rval)
+ goto error_exit;
+
+ if ((cmd_sts_and_cntrl & BIT_1) == 0)
+ break;
+ else
+ udelay(10);
+ }
+
+ /* Wait a max of 100 ms, otherwise fallback to rdmem entry read */
+ if (wait >= QLA83XX_PEX_DMA_MAX_WAIT) {
+ rval = QLA_ERROR;
+ goto error_exit;
+ }
+
+error_exit:
+ return rval;
+}
+
+static int qla4_83xx_minidump_pex_dma_read(struct scsi_qla_host *ha,
+ struct qla8xxx_minidump_entry_hdr *entry_hdr,
+ uint32_t **d_ptr)
+{
+ int rval = QLA_SUCCESS;
+ struct qla4_83xx_minidump_entry_rdmem_pex_dma *m_hdr = NULL;
+ uint32_t size, read_size;
+ uint8_t *data_ptr = (uint8_t *)*d_ptr;
+ void *rdmem_buffer = NULL;
+ dma_addr_t rdmem_dma;
+ struct qla4_83xx_pex_dma_descriptor dma_desc;
+
+ DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
+
+ rval = qla4_83xx_check_dma_engine_state(ha);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "%s: DMA engine not available. Fallback to rdmem-read.\n",
+ __func__));
+ return QLA_ERROR;
+ }
+
+ m_hdr = (struct qla4_83xx_minidump_entry_rdmem_pex_dma *)entry_hdr;
+ rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev,
+ QLA83XX_PEX_DMA_READ_SIZE,
+ &rdmem_dma, GFP_KERNEL);
+ if (!rdmem_buffer) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "%s: Unable to allocate rdmem dma buffer\n",
+ __func__));
+ return QLA_ERROR;
+ }
+
+ /* Prepare pex-dma descriptor to be written to MS memory. */
+ /* dma-desc-cmd layout:
+ * 0-3: dma-desc-cmd 0-3
+ * 4-7: pcid function number
+ * 8-15: dma-desc-cmd 8-15
+ */
+ dma_desc.cmd.dma_desc_cmd = (m_hdr->dma_desc_cmd & 0xff0f);
+ dma_desc.cmd.dma_desc_cmd |= ((PCI_FUNC(ha->pdev->devfn) & 0xf) << 0x4);
+ dma_desc.dma_bus_addr = rdmem_dma;
+
+ size = 0;
+ read_size = 0;
+ /*
+ * Perform rdmem operation using pex-dma.
+ * Prepare dma in chunks of QLA83XX_PEX_DMA_READ_SIZE.
+ */
+ while (read_size < m_hdr->read_data_size) {
+ if (m_hdr->read_data_size - read_size >=
+ QLA83XX_PEX_DMA_READ_SIZE)
+ size = QLA83XX_PEX_DMA_READ_SIZE;
+ else {
+ size = (m_hdr->read_data_size - read_size);
+
+ if (rdmem_buffer)
+ dma_free_coherent(&ha->pdev->dev,
+ QLA83XX_PEX_DMA_READ_SIZE,
+ rdmem_buffer, rdmem_dma);
+
+ rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev, size,
+ &rdmem_dma,
+ GFP_KERNEL);
+ if (!rdmem_buffer) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "%s: Unable to allocate rdmem dma buffer\n",
+ __func__));
+ return QLA_ERROR;
+ }
+ dma_desc.dma_bus_addr = rdmem_dma;
+ }
+
+ dma_desc.src_addr = m_hdr->read_addr + read_size;
+ dma_desc.cmd.read_data_size = size;
+
+ /* Prepare: Write pex-dma descriptor to MS memory. */
+ rval = qla4_83xx_ms_mem_write_128b(ha,
+ (uint64_t)m_hdr->desc_card_addr,
+ (uint32_t *)&dma_desc,
+ (sizeof(struct qla4_83xx_pex_dma_descriptor)/16));
+ if (rval == -1) {
+ ql4_printk(KERN_INFO, ha,
+ "%s: Error writing rdmem-dma-init to MS !!!\n",
+ __func__);
+ goto error_exit;
+ }
+
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "%s: Dma-desc: Instruct for rdmem dma (size 0x%x).\n",
+ __func__, size));
+ /* Execute: Start pex-dma operation. */
+ rval = qla4_83xx_start_pex_dma(ha, m_hdr);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi(%ld): start-pex-dma failed rval=0x%x\n",
+ ha->host_no, rval));
+ goto error_exit;
+ }
+
+ memcpy(data_ptr, rdmem_buffer, size);
+ data_ptr += size;
+ read_size += size;
+ }
+
+ DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s\n", __func__));
+
+ *d_ptr = (uint32_t *)data_ptr;
+
+error_exit:
+ if (rdmem_buffer)
+ dma_free_coherent(&ha->pdev->dev, size, rdmem_buffer,
+ rdmem_dma);
+
+ return rval;
+}
+
static int qla4_8xxx_minidump_process_l2tag(struct scsi_qla_host *ha,
struct qla8xxx_minidump_entry_hdr *entry_hdr,
uint32_t **d_ptr)
@@ -2068,7 +2270,7 @@ static void qla4_82xx_minidump_process_rdrom(struct scsi_qla_host *ha,
#define MD_MIU_TEST_AGT_ADDR_LO 0x41000094
#define MD_MIU_TEST_AGT_ADDR_HI 0x41000098
-static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
+static int __qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
struct qla8xxx_minidump_entry_hdr *entry_hdr,
uint32_t **d_ptr)
{
@@ -2150,6 +2352,28 @@ static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
return QLA_SUCCESS;
}
+static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
+ struct qla8xxx_minidump_entry_hdr *entry_hdr,
+ uint32_t **d_ptr)
+{
+ uint32_t *data_ptr = *d_ptr;
+ int rval = QLA_SUCCESS;
+
+ if (is_qla8032(ha) || is_qla8042(ha)) {
+ rval = qla4_83xx_minidump_pex_dma_read(ha, entry_hdr,
+ &data_ptr);
+ if (rval != QLA_SUCCESS) {
+ rval = __qla4_8xxx_minidump_process_rdmem(ha, entry_hdr,
+ &data_ptr);
+ }
+ } else {
+ rval = __qla4_8xxx_minidump_process_rdmem(ha, entry_hdr,
+ &data_ptr);
+ }
+ *d_ptr = data_ptr;
+ return rval;
+}
+
static void qla4_8xxx_mark_entry_skipped(struct scsi_qla_host *ha,
struct qla8xxx_minidump_entry_hdr *entry_hdr,
int index)
@@ -2398,13 +2622,13 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
(((uint8_t *)ha->fw_dump_tmplt_hdr) +
tmplt_hdr->first_entry_offset);
- if (is_qla8032(ha))
+ if (is_qla8032(ha) || is_qla8042(ha))
tmplt_hdr->saved_state_array[QLA83XX_SS_OCM_WNDREG_INDEX] =
tmplt_hdr->ocm_window_reg[ha->func_num];
/* Walk through the entry headers - validate/perform required action */
for (i = 0; i < num_entry_hdr; i++) {
- if (data_collected >= ha->fw_dump_size) {
+ if (data_collected > ha->fw_dump_size) {
ql4_printk(KERN_INFO, ha,
"Data collected: [0x%x], Total Dump size: [0x%x]\n",
data_collected, ha->fw_dump_size);
@@ -2455,7 +2679,7 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
if (is_qla8022(ha)) {
qla4_82xx_minidump_process_rdrom(ha, entry_hdr,
&data_ptr);
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
rval = qla4_83xx_minidump_process_rdrom(ha,
entry_hdr,
&data_ptr);
@@ -2496,7 +2720,7 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
&data_ptr);
break;
case QLA83XX_POLLRD:
- if (!is_qla8032(ha)) {
+ if (is_qla8022(ha)) {
qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
break;
}
@@ -2506,7 +2730,7 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
break;
case QLA83XX_RDMUX2:
- if (!is_qla8032(ha)) {
+ if (is_qla8022(ha)) {
qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
break;
}
@@ -2514,7 +2738,7 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
&data_ptr);
break;
case QLA83XX_POLLRDMWR:
- if (!is_qla8032(ha)) {
+ if (is_qla8022(ha)) {
qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
break;
}
@@ -2529,9 +2753,7 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
break;
}
- data_collected = (uint8_t *)data_ptr -
- ((uint8_t *)((uint8_t *)ha->fw_dump +
- ha->fw_dump_tmplt_size));
+ data_collected = (uint8_t *)data_ptr - (uint8_t *)ha->fw_dump;
skip_nxt_entry:
/* next entry in the template */
entry_hdr = (struct qla8xxx_minidump_entry_hdr *)
@@ -2539,10 +2761,11 @@ skip_nxt_entry:
entry_hdr->entry_size);
}
- if ((data_collected + ha->fw_dump_tmplt_size) != ha->fw_dump_size) {
+ if (data_collected != ha->fw_dump_size) {
ql4_printk(KERN_INFO, ha,
"Dump data mismatch: Data collected: [0x%x], total_data_size:[0x%x]\n",
data_collected, ha->fw_dump_size);
+ rval = QLA_ERROR;
goto md_failed;
}
@@ -2642,10 +2865,10 @@ dev_initialize:
QLA8XXX_DEV_INITIALIZING);
/*
- * For ISP8324, if IDC_CTRL GRACEFUL_RESET_BIT1 is set, reset it after
- * device goes to INIT state.
+ * For ISP8324 and ISP8042, if IDC_CTRL GRACEFUL_RESET_BIT1 is set,
+ * reset it after device goes to INIT state.
*/
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
if (idc_ctrl & GRACEFUL_RESET_BIT1) {
qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
@@ -2846,7 +3069,7 @@ int qla4_8xxx_update_idc_reg(struct scsi_qla_host *ha)
* If we are the first driver to load and
* ql4xdontresethba is not set, clear IDC_CTRL BIT0.
*/
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
if ((drv_active == (1 << ha->func_num)) && !ql4xdontresethba)
qla4_83xx_clear_idc_dontreset(ha);
@@ -2854,7 +3077,7 @@ int qla4_8xxx_update_idc_reg(struct scsi_qla_host *ha)
if (is_qla8022(ha)) {
qla4_82xx_set_idc_ver(ha);
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
rval = qla4_83xx_set_idc_ver(ha);
if (rval == QLA_ERROR)
qla4_8xxx_clear_drv_active(ha);
@@ -2922,11 +3145,11 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha)
break;
case QLA8XXX_DEV_NEED_RESET:
/*
- * For ISP8324, if NEED_RESET is set by any driver,
- * it should be honored, irrespective of IDC_CTRL
- * DONTRESET_BIT0
+ * For ISP8324 and ISP8042, if NEED_RESET is set by any
+ * driver, it should be honored, irrespective of
+ * IDC_CTRL DONTRESET_BIT0
*/
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
qla4_83xx_need_reset_handler(ha);
} else if (is_qla8022(ha)) {
if (!ql4xdontresethba) {
@@ -2976,7 +3199,7 @@ int qla4_8xxx_load_risc(struct scsi_qla_host *ha)
int retval;
/* clear the interrupt */
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
writel(0, &ha->qla4_83xx_reg->risc_intr);
readl(&ha->qla4_83xx_reg->risc_intr);
} else if (is_qla8022(ha)) {
@@ -3094,7 +3317,7 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
if (is_qla8022(ha)) {
qla4_82xx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
flt_addr << 2, OPTROM_BURST_SIZE);
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
status = qla4_83xx_flash_read_u32(ha, flt_addr << 2,
(uint8_t *)ha->request_ring,
0x400);
@@ -3326,7 +3549,7 @@ qla4_8xxx_get_flash_info(struct scsi_qla_host *ha)
if (is_qla8022(ha)) {
qla4_82xx_get_fdt_info(ha);
qla4_82xx_get_idc_param(ha);
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
qla4_83xx_get_idc_param(ha);
}
@@ -3436,7 +3659,7 @@ int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha)
}
/* Make sure we receive the minimum required data to cache internally */
- if ((is_qla8032(ha) ? mbox_sts[3] : mbox_sts[4]) <
+ if (((is_qla8032(ha) || is_qla8042(ha)) ? mbox_sts[3] : mbox_sts[4]) <
offsetof(struct mbx_sys_info, reserved)) {
DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO data receive"
" error (%x)\n", ha->host_no, __func__, mbox_sts[4]));
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h
index 9dc0bbfe50d..14500a0f62c 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.h
+++ b/drivers/scsi/qla4xxx/ql4_nx.h
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index b246b3c2691..f8a0a26a3cd 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1,6 +1,6 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
@@ -378,6 +378,44 @@ static umode_t qla4_attr_is_visible(int param_type, int param)
case ISCSI_PARAM_PASSWORD:
case ISCSI_PARAM_USERNAME_IN:
case ISCSI_PARAM_PASSWORD_IN:
+ case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
+ case ISCSI_PARAM_DISCOVERY_SESS:
+ case ISCSI_PARAM_PORTAL_TYPE:
+ case ISCSI_PARAM_CHAP_AUTH_EN:
+ case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
+ case ISCSI_PARAM_BIDI_CHAP_EN:
+ case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
+ case ISCSI_PARAM_DEF_TIME2WAIT:
+ case ISCSI_PARAM_DEF_TIME2RETAIN:
+ case ISCSI_PARAM_HDRDGST_EN:
+ case ISCSI_PARAM_DATADGST_EN:
+ case ISCSI_PARAM_INITIAL_R2T_EN:
+ case ISCSI_PARAM_IMM_DATA_EN:
+ case ISCSI_PARAM_PDU_INORDER_EN:
+ case ISCSI_PARAM_DATASEQ_INORDER_EN:
+ case ISCSI_PARAM_MAX_SEGMENT_SIZE:
+ case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
+ case ISCSI_PARAM_TCP_WSF_DISABLE:
+ case ISCSI_PARAM_TCP_NAGLE_DISABLE:
+ case ISCSI_PARAM_TCP_TIMER_SCALE:
+ case ISCSI_PARAM_TCP_TIMESTAMP_EN:
+ case ISCSI_PARAM_TCP_XMIT_WSF:
+ case ISCSI_PARAM_TCP_RECV_WSF:
+ case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
+ case ISCSI_PARAM_IPV4_TOS:
+ case ISCSI_PARAM_IPV6_TC:
+ case ISCSI_PARAM_IPV6_FLOW_LABEL:
+ case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
+ case ISCSI_PARAM_KEEPALIVE_TMO:
+ case ISCSI_PARAM_LOCAL_PORT:
+ case ISCSI_PARAM_ISID:
+ case ISCSI_PARAM_TSID:
+ case ISCSI_PARAM_DEF_TASKMGMT_TMO:
+ case ISCSI_PARAM_ERL:
+ case ISCSI_PARAM_STATSN:
+ case ISCSI_PARAM_EXP_STATSN:
+ case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
+ case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
return S_IRUGO;
default:
return 0;
@@ -2218,19 +2256,23 @@ static int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess,
fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size);
fw_ddb_entry->tcp_xmt_wsf = (uint8_t) cpu_to_le32(conn->tcp_xmit_wsf);
fw_ddb_entry->tcp_rcv_wsf = (uint8_t) cpu_to_le32(conn->tcp_recv_wsf);
- fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label);
fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout);
fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port);
fw_ddb_entry->stat_sn = cpu_to_le32(conn->statsn);
fw_ddb_entry->exp_stat_sn = cpu_to_le32(conn->exp_statsn);
- fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_type);
+ fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_idx);
fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx);
fw_ddb_entry->tsid = cpu_to_le16(sess->tsid);
fw_ddb_entry->port = cpu_to_le16(conn->port);
fw_ddb_entry->def_timeout =
cpu_to_le16(sess->default_taskmgmt_timeout);
+ if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ fw_ddb_entry->ipv4_tos = conn->ipv6_traffic_class;
+ else
+ fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
+
if (conn->ipaddress)
memcpy(fw_ddb_entry->ip_addr, conn->ipaddress,
sizeof(fw_ddb_entry->ip_addr));
@@ -2257,6 +2299,101 @@ static int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess,
return rc;
}
+static void qla4xxx_copy_to_sess_conn_params(struct iscsi_conn *conn,
+ struct iscsi_session *sess,
+ struct dev_db_entry *fw_ddb_entry)
+{
+ unsigned long options = 0;
+ uint16_t ddb_link;
+ uint16_t disc_parent;
+
+ options = le16_to_cpu(fw_ddb_entry->options);
+ conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
+ sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
+ &options);
+ sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
+
+ options = le16_to_cpu(fw_ddb_entry->iscsi_options);
+ conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
+ conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
+ sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
+ sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
+ sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
+ &options);
+ sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
+ sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
+ sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
+ &options);
+ sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
+ sess->discovery_auth_optional =
+ test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
+ if (test_bit(ISCSIOPT_ERL1, &options))
+ sess->erl |= BIT_1;
+ if (test_bit(ISCSIOPT_ERL0, &options))
+ sess->erl |= BIT_0;
+
+ options = le16_to_cpu(fw_ddb_entry->tcp_options);
+ conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
+ conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
+ conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
+ if (test_bit(TCPOPT_TIMER_SCALE3, &options))
+ conn->tcp_timer_scale |= BIT_3;
+ if (test_bit(TCPOPT_TIMER_SCALE2, &options))
+ conn->tcp_timer_scale |= BIT_2;
+ if (test_bit(TCPOPT_TIMER_SCALE1, &options))
+ conn->tcp_timer_scale |= BIT_1;
+
+ conn->tcp_timer_scale >>= 1;
+ conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
+
+ options = le16_to_cpu(fw_ddb_entry->ip_options);
+ conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
+
+ conn->max_recv_dlength = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
+ conn->max_xmit_dlength = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
+ sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
+ sess->first_burst = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
+ sess->max_burst = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
+ sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
+ sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
+ sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
+ conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
+ conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
+ conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
+ conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
+ conn->keepalive_tmo = le16_to_cpu(fw_ddb_entry->ka_timeout);
+ conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
+ conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
+ conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
+ sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
+ COPY_ISID(sess->isid, fw_ddb_entry->isid);
+
+ ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
+ if (ddb_link < MAX_DDB_ENTRIES)
+ sess->discovery_parent_idx = ddb_link;
+ else
+ sess->discovery_parent_idx = DDB_NO_LINK;
+
+ if (ddb_link == DDB_ISNS)
+ disc_parent = ISCSI_DISC_PARENT_ISNS;
+ else if (ddb_link == DDB_NO_LINK)
+ disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
+ else if (ddb_link < MAX_DDB_ENTRIES)
+ disc_parent = ISCSI_DISC_PARENT_SENDTGT;
+ else
+ disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
+
+ iscsi_set_param(conn->cls_conn, ISCSI_PARAM_DISCOVERY_PARENT_TYPE,
+ iscsi_get_discovery_parent_name(disc_parent), 0);
+
+ iscsi_set_param(conn->cls_conn, ISCSI_PARAM_TARGET_ALIAS,
+ (char *)fw_ddb_entry->iscsi_alias, 0);
+}
+
static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
struct dev_db_entry *fw_ddb_entry,
struct iscsi_cls_session *cls_sess,
@@ -2275,47 +2412,29 @@ static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
- conn->max_recv_dlength = BYTE_UNITS *
- le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
-
- conn->max_xmit_dlength = BYTE_UNITS *
- le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
-
- sess->initial_r2t_en =
- (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options));
-
- sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
-
- sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options));
-
- sess->first_burst = BYTE_UNITS *
- le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
-
- sess->max_burst = BYTE_UNITS *
- le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
-
- sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
-
- sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
+ qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
+ sess->def_taskmgmt_tmo = le16_to_cpu(fw_ddb_entry->def_timeout);
conn->persistent_port = le16_to_cpu(fw_ddb_entry->port);
- sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
-
+ memset(ip_addr, 0, sizeof(ip_addr));
options = le16_to_cpu(fw_ddb_entry->options);
- if (options & DDB_OPT_IPV6_DEVICE)
+ if (options & DDB_OPT_IPV6_DEVICE) {
+ iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv6", 4);
+
+ memset(ip_addr, 0, sizeof(ip_addr));
sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr);
- else
+ } else {
+ iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv4", 4);
sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr);
+ }
+ iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS,
+ (char *)ip_addr, buflen);
iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME,
(char *)fw_ddb_entry->iscsi_name, buflen);
iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME,
(char *)ha->name_string, buflen);
- iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS,
- (char *)ip_addr, buflen);
- iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS,
- (char *)fw_ddb_entry->iscsi_alias, buflen);
}
void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha,
@@ -2403,37 +2522,11 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha,
/* Update params */
ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
- conn->max_recv_dlength = BYTE_UNITS *
- le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
-
- conn->max_xmit_dlength = BYTE_UNITS *
- le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
-
- sess->initial_r2t_en =
- (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options));
-
- sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
-
- sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options));
-
- sess->first_burst = BYTE_UNITS *
- le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
-
- sess->max_burst = BYTE_UNITS *
- le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
-
- sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
-
- sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
-
- sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
+ qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
memcpy(sess->initiatorname, ha->name_string,
min(sizeof(ha->name_string), sizeof(sess->initiatorname)));
- iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS,
- (char *)fw_ddb_entry->iscsi_alias, 0);
-
exit_session_conn_param:
if (fw_ddb_entry)
dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
@@ -2578,6 +2671,8 @@ static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
!test_bit(AF_ONLINE, &ha->flags) ||
!test_bit(AF_LINK_UP, &ha->flags) ||
test_bit(AF_LOOPBACK, &ha->flags) ||
+ test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags) ||
+ test_bit(DPC_RESTORE_ACB, &ha->dpc_flags) ||
test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))
goto qc_host_busy;
@@ -2652,7 +2747,7 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha)
if (ha->nx_pcibase)
iounmap(
(struct device_reg_82xx __iomem *)ha->nx_pcibase);
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
if (ha->nx_pcibase)
iounmap(
(struct device_reg_83xx __iomem *)ha->nx_pcibase);
@@ -2846,7 +2941,7 @@ static void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha)
__func__);
if (halt_status & HALT_STATUS_UNRECOVERABLE)
halt_status_unrecoverable = 1;
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
if (halt_status & QLA83XX_HALT_STATUS_FW_RESET)
ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n",
__func__);
@@ -2901,7 +2996,7 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET!\n",
__func__);
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
idc_ctrl = qla4_83xx_rd_reg(ha,
QLA83XX_IDC_DRV_CTRL);
if (!(idc_ctrl & GRACEFUL_RESET_BIT1)) {
@@ -2912,7 +3007,7 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
}
}
- if (is_qla8032(ha) ||
+ if ((is_qla8032(ha) || is_qla8042(ha)) ||
(is_qla8022(ha) && !ql4xdontresethba)) {
set_bit(DPC_RESET_HA, &ha->dpc_flags);
qla4xxx_wake_dpc(ha);
@@ -3296,7 +3391,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
- if (is_qla8032(ha) &&
+ if ((is_qla8032(ha) || is_qla8042(ha)) &&
!test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
__func__);
@@ -3494,7 +3589,9 @@ static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session)
} else {
/* Trigger relogin */
if (ddb_entry->ddb_type == FLASH_DDB) {
- if (!test_bit(DF_RELOGIN, &ddb_entry->flags))
+ if (!(test_bit(DF_RELOGIN, &ddb_entry->flags) ||
+ test_bit(DF_DISABLE_RELOGIN,
+ &ddb_entry->flags)))
qla4xxx_arm_relogin_timer(ddb_entry);
} else
iscsi_session_failure(cls_session->dd_data,
@@ -3597,6 +3694,9 @@ static void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess)
if (!(ddb_entry->ddb_type == FLASH_DDB))
return;
+ if (test_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
+ return;
+
if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
!iscsi_is_session_online(cls_sess)) {
DEBUG2(ql4_printk(KERN_INFO, ha,
@@ -3750,7 +3850,7 @@ static void qla4xxx_do_dpc(struct work_struct *work)
if (is_qla80XX(ha)) {
if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
__func__);
/* disable pause frame for ISP83xx */
@@ -3765,8 +3865,35 @@ static void qla4xxx_do_dpc(struct work_struct *work)
qla4_8xxx_device_state_handler(ha);
}
- if (test_and_clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags))
+ if (test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags)) {
+ if (is_qla8042(ha)) {
+ if (ha->idc_info.info2 &
+ ENABLE_INTERNAL_LOOPBACK) {
+ ql4_printk(KERN_INFO, ha, "%s: Disabling ACB\n",
+ __func__);
+ status = qla4_84xx_config_acb(ha,
+ ACB_CONFIG_DISABLE);
+ if (status != QLA_SUCCESS) {
+ ql4_printk(KERN_INFO, ha, "%s: ACB config failed\n",
+ __func__);
+ }
+ }
+ }
qla4_83xx_post_idc_ack(ha);
+ clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags);
+ }
+
+ if (is_qla8042(ha) &&
+ test_bit(DPC_RESTORE_ACB, &ha->dpc_flags)) {
+ ql4_printk(KERN_INFO, ha, "%s: Restoring ACB\n",
+ __func__);
+ if (qla4_84xx_config_acb(ha, ACB_CONFIG_SET) !=
+ QLA_SUCCESS) {
+ ql4_printk(KERN_INFO, ha, "%s: ACB config failed ",
+ __func__);
+ }
+ clear_bit(DPC_RESTORE_ACB, &ha->dpc_flags);
+ }
if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
qla4_8xxx_need_qsnt_handler(ha);
@@ -3778,7 +3905,8 @@ static void qla4xxx_do_dpc(struct work_struct *work)
test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
if ((is_qla8022(ha) && ql4xdontresethba) ||
- (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
+ ((is_qla8032(ha) || is_qla8042(ha)) &&
+ qla4_83xx_idc_dontreset(ha))) {
DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
ha->host_no, __func__));
clear_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -3870,7 +3998,7 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
} else if (is_qla8022(ha)) {
writel(0, &ha->qla4_82xx_reg->host_int);
readl(&ha->qla4_82xx_reg->host_int);
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
writel(0, &ha->qla4_83xx_reg->risc_intr);
readl(&ha->qla4_83xx_reg->risc_intr);
}
@@ -3945,7 +4073,7 @@ int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
(ha->pdev->devfn << 11));
ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
QLA82XX_CAM_RAM_DB2);
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *)
((uint8_t *)ha->nx_pcibase);
}
@@ -5609,7 +5737,8 @@ static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
goto exit_ddb_add;
}
- for (idx = 0; idx < max_ddbs; idx++) {
+ /* Index 0 and 1 are reserved for boot target entries */
+ for (idx = 2; idx < max_ddbs; idx++) {
if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry,
fw_ddb_entry_dma, idx))
break;
@@ -5925,13 +6054,6 @@ static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess)
goto exit_ddb_logout;
}
- options = LOGOUT_OPTION_CLOSE_SESSION;
- if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) {
- ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
- ret = -EIO;
- goto exit_ddb_logout;
- }
-
fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
&fw_ddb_entry_dma, GFP_KERNEL);
if (!fw_ddb_entry) {
@@ -5941,6 +6063,38 @@ static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess)
goto exit_ddb_logout;
}
+ if (test_and_set_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
+ goto ddb_logout_init;
+
+ ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
+ fw_ddb_entry, fw_ddb_entry_dma,
+ NULL, NULL, &ddb_state, NULL,
+ NULL, NULL);
+ if (ret == QLA_ERROR)
+ goto ddb_logout_init;
+
+ if (ddb_state == DDB_DS_SESSION_ACTIVE)
+ goto ddb_logout_init;
+
+ /* wait until next relogin is triggered using DF_RELOGIN and
+ * clear DF_RELOGIN to avoid invocation of further relogin
+ */
+ wtime = jiffies + (HZ * RELOGIN_TOV);
+ do {
+ if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags))
+ goto ddb_logout_init;
+
+ schedule_timeout_uninterruptible(HZ);
+ } while ((time_after(wtime, jiffies)));
+
+ddb_logout_init:
+ atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
+ atomic_set(&ddb_entry->relogin_timer, 0);
+
+ options = LOGOUT_OPTION_CLOSE_SESSION;
+ qla4xxx_session_logout_ddb(ha, ddb_entry, options);
+
+ memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
wtime = jiffies + (HZ * LOGOUT_TOV);
do {
ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
@@ -5970,10 +6124,12 @@ ddb_logout_clr_sess:
spin_lock_irqsave(&ha->hardware_lock, flags);
qla4xxx_free_ddb(ha, ddb_entry);
+ clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
iscsi_session_teardown(ddb_entry->sess);
+ clear_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags);
ret = QLA_SUCCESS;
exit_ddb_logout:
@@ -6110,7 +6266,7 @@ qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
struct iscsi_bus_flash_conn *fnode_conn;
struct ql4_chap_table chap_tbl;
struct device *dev;
- int parent_type, parent_index = 0xffff;
+ int parent_type;
int rc = 0;
dev = iscsi_find_flashnode_conn(fnode_sess);
@@ -6276,10 +6432,7 @@ qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
rc = sprintf(buf, "\n");
break;
case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
- if (fnode_sess->discovery_parent_idx < MAX_DDB_ENTRIES)
- parent_index = fnode_sess->discovery_parent_idx;
-
- rc = sprintf(buf, "%u\n", parent_index);
+ rc = sprintf(buf, "%u\n", fnode_sess->discovery_parent_idx);
break;
case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
if (fnode_sess->discovery_parent_type == DDB_ISNS)
@@ -6533,8 +6686,8 @@ qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
memcpy(fnode_conn->link_local_ipv6_addr,
fnode_param->value, IPv6_ADDR_LEN);
break;
- case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
- fnode_sess->discovery_parent_type =
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
+ fnode_sess->discovery_parent_idx =
*(uint16_t *)fnode_param->value;
break;
case ISCSI_FLASHNODE_TCP_XMIT_WSF:
@@ -6910,7 +7063,7 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev,
nx_legacy_intr->tgt_status_reg;
ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
- } else if (is_qla8032(ha)) {
+ } else if (is_qla8032(ha) || is_qla8042(ha)) {
ha->isp_ops = &qla4_83xx_isp_ops;
ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl;
} else {
@@ -6981,7 +7134,7 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev,
if (is_qla80XX(ha))
qla4_8xxx_get_flash_info(ha);
- if (is_qla8032(ha)) {
+ if (is_qla8032(ha) || is_qla8042(ha)) {
qla4_83xx_read_reset_template(ha);
/*
* NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0.
@@ -7036,7 +7189,8 @@ skip_retry_init:
ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
if ((is_qla8022(ha) && ql4xdontresethba) ||
- (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
+ ((is_qla8032(ha) || is_qla8042(ha)) &&
+ qla4_83xx_idc_dontreset(ha))) {
/* Put the device in failed state. */
DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
ha->isp_ops->idc_lock(ha);
@@ -7097,8 +7251,8 @@ skip_retry_init:
" QLogic iSCSI HBA Driver version: %s\n"
" QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
- ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
- ha->patch_number, ha->build_number);
+ ha->host_no, ha->fw_info.fw_major, ha->fw_info.fw_minor,
+ ha->fw_info.fw_patch, ha->fw_info.fw_build);
/* Set the driver version */
if (is_qla80XX(ha))
@@ -7645,16 +7799,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
ha = to_qla_host(cmd->device->host);
- if (is_qla8032(ha) && ql4xdontresethba)
+ if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba)
qla4_83xx_set_idc_dontreset(ha);
/*
- * For ISP8324, if IDC_CTRL DONTRESET_BIT0 is set by other
- * protocol drivers, we should not set device_state to
- * NEED_RESET
+ * For ISP8324 and ISP8042, if IDC_CTRL DONTRESET_BIT0 is set by other
+ * protocol drivers, we should not set device_state to NEED_RESET
*/
if (ql4xdontresethba ||
- (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
+ ((is_qla8032(ha) || is_qla8042(ha)) &&
+ qla4_83xx_idc_dontreset(ha))) {
DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
ha->host_no, __func__));
@@ -7779,9 +7933,10 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
}
recover_adapter:
- /* For ISP83XX set graceful reset bit in IDC_DRV_CTRL if
+ /* For ISP8324 and ISP8042 set graceful reset bit in IDC_DRV_CTRL if
* reset is issued by application */
- if (is_qla8032(ha) && test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+ if ((is_qla8032(ha) || is_qla8042(ha)) &&
+ test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
(idc_ctrl | GRACEFUL_RESET_BIT1));
@@ -8078,6 +8233,12 @@ static struct pci_device_id qla4xxx_pci_tbl[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
+ {
+ .vendor = PCI_VENDOR_ID_QLOGIC,
+ .device = PCI_DEVICE_ID_QLOGIC_ISP8042,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
{0, 0},
};
MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index fe873cf7570..f4fef72c9bc 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -1,8 +1,8 @@
/*
* QLogic iSCSI HBA Driver
- * Copyright (c) 2003-2012 QLogic Corporation
+ * Copyright (c) 2003-2013 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.03.00-k9"
+#define QLA4XXX_DRIVER_VERSION "5.04.00-k1"
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 3b1ea34e1f5..eaa808e6ba9 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1031,6 +1031,9 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
{
int i, result;
+ if (sdev->skip_vpd_pages)
+ goto fail;
+
/* Ask for all the pages supported by this device */
result = scsi_vpd_inquiry(sdev, buf, 0, buf_len);
if (result)
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index cb4fefa1bfb..01c0ffa3127 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1997,8 +1997,14 @@ static unsigned long lba_to_map_index(sector_t lba)
static sector_t map_index_to_lba(unsigned long index)
{
- return index * scsi_debug_unmap_granularity -
- scsi_debug_unmap_alignment;
+ sector_t lba = index * scsi_debug_unmap_granularity;
+
+ if (scsi_debug_unmap_alignment) {
+ lba -= scsi_debug_unmap_granularity -
+ scsi_debug_unmap_alignment;
+ }
+
+ return lba;
}
static unsigned int map_state(sector_t lba, unsigned int *num)
@@ -2659,8 +2665,8 @@ static void __init sdebug_build_parts(unsigned char *ramp,
/ sdebug_sectors_per;
pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
- pp->start_sect = start_sec;
- pp->nr_sects = end_sec - start_sec + 1;
+ pp->start_sect = cpu_to_le32(start_sec);
+ pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
pp->sys_ind = 0x83; /* plain Linux partition */
}
}
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 21505962f53..83e591b6019 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -223,12 +223,80 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
}
#endif
+ /**
+ * scsi_report_lun_change - Set flag on all *other* devices on the same target
+ * to indicate that a UNIT ATTENTION is expected.
+ * @sdev: Device reporting the UNIT ATTENTION
+ */
+static void scsi_report_lun_change(struct scsi_device *sdev)
+{
+ sdev->sdev_target->expecting_lun_change = 1;
+}
+
+/**
+ * scsi_report_sense - Examine scsi sense information and log messages for
+ * certain conditions, also issue uevents for some of them.
+ * @sdev: Device reporting the sense code
+ * @sshdr: sshdr to be examined
+ */
+static void scsi_report_sense(struct scsi_device *sdev,
+ struct scsi_sense_hdr *sshdr)
+{
+ enum scsi_device_event evt_type = SDEV_EVT_MAXBITS; /* i.e. none */
+
+ if (sshdr->sense_key == UNIT_ATTENTION) {
+ if (sshdr->asc == 0x3f && sshdr->ascq == 0x03) {
+ evt_type = SDEV_EVT_INQUIRY_CHANGE_REPORTED;
+ sdev_printk(KERN_WARNING, sdev,
+ "Inquiry data has changed");
+ } else if (sshdr->asc == 0x3f && sshdr->ascq == 0x0e) {
+ evt_type = SDEV_EVT_LUN_CHANGE_REPORTED;
+ scsi_report_lun_change(sdev);
+ sdev_printk(KERN_WARNING, sdev,
+ "Warning! Received an indication that the "
+ "LUN assignments on this target have "
+ "changed. The Linux SCSI layer does not "
+ "automatically remap LUN assignments.\n");
+ } else if (sshdr->asc == 0x3f)
+ sdev_printk(KERN_WARNING, sdev,
+ "Warning! Received an indication that the "
+ "operating parameters on this target have "
+ "changed. The Linux SCSI layer does not "
+ "automatically adjust these parameters.\n");
+
+ if (sshdr->asc == 0x38 && sshdr->ascq == 0x07) {
+ evt_type = SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED;
+ sdev_printk(KERN_WARNING, sdev,
+ "Warning! Received an indication that the "
+ "LUN reached a thin provisioning soft "
+ "threshold.\n");
+ }
+
+ if (sshdr->asc == 0x2a && sshdr->ascq == 0x01) {
+ evt_type = SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED;
+ sdev_printk(KERN_WARNING, sdev,
+ "Mode parameters changed");
+ } else if (sshdr->asc == 0x2a && sshdr->ascq == 0x09) {
+ evt_type = SDEV_EVT_CAPACITY_CHANGE_REPORTED;
+ sdev_printk(KERN_WARNING, sdev,
+ "Capacity data has changed");
+ } else if (sshdr->asc == 0x2a)
+ sdev_printk(KERN_WARNING, sdev,
+ "Parameters changed");
+ }
+
+ if (evt_type != SDEV_EVT_MAXBITS) {
+ set_bit(evt_type, sdev->pending_events);
+ schedule_work(&sdev->event_work);
+ }
+}
+
/**
* scsi_check_sense - Examine scsi cmd sense
* @scmd: Cmd to have sense checked.
*
* Return value:
- * SUCCESS or FAILED or NEEDS_RETRY or TARGET_ERROR
+ * SUCCESS or FAILED or NEEDS_RETRY or ADD_TO_MLQUEUE
*
* Notes:
* When a deferred error is detected the current command has
@@ -250,6 +318,8 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
*/
return SUCCESS;
+ scsi_report_sense(sdev, &sshdr);
+
if (scsi_sense_is_deferred(&sshdr))
return NEEDS_RETRY;
@@ -315,6 +385,14 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
}
}
/*
+ * we might also expect a cc/ua if another LUN on the target
+ * reported a UA with an ASC/ASCQ of 3F 0E -
+ * REPORTED LUNS DATA HAS CHANGED.
+ */
+ if (scmd->device->sdev_target->expecting_lun_change &&
+ sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
+ return NEEDS_RETRY;
+ /*
* if the device is in the process of becoming ready, we
* should retry.
*/
@@ -327,26 +405,6 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
if (scmd->device->allow_restart &&
(sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
return FAILED;
-
- if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
- scmd_printk(KERN_WARNING, scmd,
- "Warning! Received an indication that the "
- "LUN assignments on this target have "
- "changed. The Linux SCSI layer does not "
- "automatically remap LUN assignments.\n");
- else if (sshdr.asc == 0x3f)
- scmd_printk(KERN_WARNING, scmd,
- "Warning! Received an indication that the "
- "operating parameters on this target have "
- "changed. The Linux SCSI layer does not "
- "automatically adjust these parameters.\n");
-
- if (sshdr.asc == 0x38 && sshdr.ascq == 0x07)
- scmd_printk(KERN_WARNING, scmd,
- "Warning! Received an indication that the "
- "LUN reached a thin provisioning soft "
- "threshold.\n");
-
/*
* Pass the UA upwards for a determination in the completion
* functions.
@@ -354,18 +412,25 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
return SUCCESS;
/* these are not supported */
+ case DATA_PROTECT:
+ if (sshdr.asc == 0x27 && sshdr.ascq == 0x07) {
+ /* Thin provisioning hard threshold reached */
+ set_host_byte(scmd, DID_ALLOC_FAILURE);
+ return SUCCESS;
+ }
case COPY_ABORTED:
case VOLUME_OVERFLOW:
case MISCOMPARE:
case BLANK_CHECK:
- case DATA_PROTECT:
- return TARGET_ERROR;
+ set_host_byte(scmd, DID_TARGET_FAILURE);
+ return SUCCESS;
case MEDIUM_ERROR:
if (sshdr.asc == 0x11 || /* UNRECOVERED READ ERR */
sshdr.asc == 0x13 || /* AMNF DATA FIELD */
sshdr.asc == 0x14) { /* RECORD NOT FOUND */
- return TARGET_ERROR;
+ set_host_byte(scmd, DID_MEDIUM_ERROR);
+ return SUCCESS;
}
return NEEDS_RETRY;
@@ -373,14 +438,14 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
if (scmd->device->retry_hwerror)
return ADD_TO_MLQUEUE;
else
- return TARGET_ERROR;
+ set_host_byte(scmd, DID_TARGET_FAILURE);
case ILLEGAL_REQUEST:
if (sshdr.asc == 0x20 || /* Invalid command operation code */
sshdr.asc == 0x21 || /* Logical block address out of range */
sshdr.asc == 0x24 || /* Invalid field in cdb */
sshdr.asc == 0x26) { /* Parameter value invalid */
- return TARGET_ERROR;
+ set_host_byte(scmd, DID_TARGET_FAILURE);
}
return SUCCESS;
@@ -843,7 +908,6 @@ retry:
case SUCCESS:
case NEEDS_RETRY:
case FAILED:
- case TARGET_ERROR:
break;
case ADD_TO_MLQUEUE:
rtn = NEEDS_RETRY;
@@ -1568,6 +1632,8 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
*/
return ADD_TO_MLQUEUE;
case GOOD:
+ if (scmd->cmnd[0] == REPORT_LUNS)
+ scmd->device->sdev_target->expecting_lun_change = 0;
scsi_handle_queue_ramp_up(scmd->device);
case COMMAND_TERMINATED:
return SUCCESS;
@@ -1577,14 +1643,6 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
rtn = scsi_check_sense(scmd);
if (rtn == NEEDS_RETRY)
goto maybe_retry;
- else if (rtn == TARGET_ERROR) {
- /*
- * Need to modify host byte to signal a
- * permanent target failure
- */
- set_host_byte(scmd, DID_TARGET_FAILURE);
- rtn = SUCCESS;
- }
/* if rtn == FAILED, we have no sense information;
* returning FAILED will wake the error handler thread
* to collect the sense and redo the decide
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 124392f3091..d545931c85e 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -716,6 +716,20 @@ void scsi_release_buffers(struct scsi_cmnd *cmd)
}
EXPORT_SYMBOL(scsi_release_buffers);
+/**
+ * __scsi_error_from_host_byte - translate SCSI error code into errno
+ * @cmd: SCSI command (unused)
+ * @result: scsi error code
+ *
+ * Translate SCSI error code into standard UNIX errno.
+ * Return values:
+ * -ENOLINK temporary transport failure
+ * -EREMOTEIO permanent target failure, do not retry
+ * -EBADE permanent nexus failure, retry on other path
+ * -ENOSPC No write space available
+ * -ENODATA Medium error
+ * -EIO unspecified I/O error
+ */
static int __scsi_error_from_host_byte(struct scsi_cmnd *cmd, int result)
{
int error = 0;
@@ -732,6 +746,14 @@ static int __scsi_error_from_host_byte(struct scsi_cmnd *cmd, int result)
set_host_byte(cmd, DID_OK);
error = -EBADE;
break;
+ case DID_ALLOC_FAILURE:
+ set_host_byte(cmd, DID_OK);
+ error = -ENOSPC;
+ break;
+ case DID_MEDIUM_ERROR:
+ set_host_byte(cmd, DID_OK);
+ error = -ENODATA;
+ break;
default:
error = -EIO;
break;
@@ -2231,7 +2253,21 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
case SDEV_EVT_MEDIA_CHANGE:
envp[idx++] = "SDEV_MEDIA_CHANGE=1";
break;
-
+ case SDEV_EVT_INQUIRY_CHANGE_REPORTED:
+ envp[idx++] = "SDEV_UA=INQUIRY_DATA_HAS_CHANGED";
+ break;
+ case SDEV_EVT_CAPACITY_CHANGE_REPORTED:
+ envp[idx++] = "SDEV_UA=CAPACITY_DATA_HAS_CHANGED";
+ break;
+ case SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED:
+ envp[idx++] = "SDEV_UA=THIN_PROVISIONING_SOFT_THRESHOLD_REACHED";
+ break;
+ case SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED:
+ envp[idx++] = "SDEV_UA=MODE_PARAMETERS_CHANGED";
+ break;
+ case SDEV_EVT_LUN_CHANGE_REPORTED:
+ envp[idx++] = "SDEV_UA=REPORTED_LUNS_DATA_HAS_CHANGED";
+ break;
default:
/* do nothing */
break;
@@ -2252,10 +2288,15 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
void scsi_evt_thread(struct work_struct *work)
{
struct scsi_device *sdev;
+ enum scsi_device_event evt_type;
LIST_HEAD(event_list);
sdev = container_of(work, struct scsi_device, event_work);
+ for (evt_type = SDEV_EVT_FIRST; evt_type <= SDEV_EVT_LAST; evt_type++)
+ if (test_and_clear_bit(evt_type, sdev->pending_events))
+ sdev_evt_send_simple(sdev, evt_type, GFP_KERNEL);
+
while (1) {
struct scsi_event *evt;
struct list_head *this, *tmp;
@@ -2325,6 +2366,11 @@ struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,
/* evt_type-specific initialization, if any */
switch (evt_type) {
case SDEV_EVT_MEDIA_CHANGE:
+ case SDEV_EVT_INQUIRY_CHANGE_REPORTED:
+ case SDEV_EVT_CAPACITY_CHANGE_REPORTED:
+ case SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED:
+ case SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED:
+ case SDEV_EVT_LUN_CHANGE_REPORTED:
default:
/* do nothing */
break;
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 7e50061e9ef..40c639491b2 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -739,6 +739,11 @@ sdev_store_evt_##name(struct device *dev, struct device_attribute *attr,\
#define REF_EVT(name) &dev_attr_evt_##name.attr
DECLARE_EVT(media_change, MEDIA_CHANGE)
+DECLARE_EVT(inquiry_change_reported, INQUIRY_CHANGE_REPORTED)
+DECLARE_EVT(capacity_change_reported, CAPACITY_CHANGE_REPORTED)
+DECLARE_EVT(soft_threshold_reached, SOFT_THRESHOLD_REACHED_REPORTED)
+DECLARE_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED)
+DECLARE_EVT(lun_change_reported, LUN_CHANGE_REPORTED)
/* Default template for device attributes. May NOT be modified */
static struct attribute *scsi_sdev_attrs[] = {
@@ -759,6 +764,11 @@ static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_ioerr_cnt.attr,
&dev_attr_modalias.attr,
REF_EVT(media_change),
+ REF_EVT(inquiry_change_reported),
+ REF_EVT(capacity_change_reported),
+ REF_EVT(soft_threshold_reached),
+ REF_EVT(mode_parameter_change_reported),
+ REF_EVT(lun_change_reported),
NULL
};
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index abf7c402e1a..e4a989fa477 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -25,7 +25,6 @@
#include <linux/slab.h>
#include <linux/bsg-lib.h>
#include <linux/idr.h>
-#include <linux/list.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -3327,6 +3326,23 @@ iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
+iscsi_conn_attr(local_port, ISCSI_PARAM_LOCAL_PORT);
+iscsi_conn_attr(statsn, ISCSI_PARAM_STATSN);
+iscsi_conn_attr(keepalive_tmo, ISCSI_PARAM_KEEPALIVE_TMO);
+iscsi_conn_attr(max_segment_size, ISCSI_PARAM_MAX_SEGMENT_SIZE);
+iscsi_conn_attr(tcp_timestamp_stat, ISCSI_PARAM_TCP_TIMESTAMP_STAT);
+iscsi_conn_attr(tcp_wsf_disable, ISCSI_PARAM_TCP_WSF_DISABLE);
+iscsi_conn_attr(tcp_nagle_disable, ISCSI_PARAM_TCP_NAGLE_DISABLE);
+iscsi_conn_attr(tcp_timer_scale, ISCSI_PARAM_TCP_TIMER_SCALE);
+iscsi_conn_attr(tcp_timestamp_enable, ISCSI_PARAM_TCP_TIMESTAMP_EN);
+iscsi_conn_attr(fragment_disable, ISCSI_PARAM_IP_FRAGMENT_DISABLE);
+iscsi_conn_attr(ipv4_tos, ISCSI_PARAM_IPV4_TOS);
+iscsi_conn_attr(ipv6_traffic_class, ISCSI_PARAM_IPV6_TC);
+iscsi_conn_attr(ipv6_flow_label, ISCSI_PARAM_IPV6_FLOW_LABEL);
+iscsi_conn_attr(is_fw_assigned_ipv6, ISCSI_PARAM_IS_FW_ASSIGNED_IPV6);
+iscsi_conn_attr(tcp_xmit_wsf, ISCSI_PARAM_TCP_XMIT_WSF);
+iscsi_conn_attr(tcp_recv_wsf, ISCSI_PARAM_TCP_RECV_WSF);
+
#define iscsi_conn_ep_attr_show(param) \
static ssize_t show_conn_ep_param_##param(struct device *dev, \
@@ -3379,6 +3395,22 @@ static struct attribute *iscsi_conn_attrs[] = {
&dev_attr_conn_persistent_port.attr,
&dev_attr_conn_ping_tmo.attr,
&dev_attr_conn_recv_tmo.attr,
+ &dev_attr_conn_local_port.attr,
+ &dev_attr_conn_statsn.attr,
+ &dev_attr_conn_keepalive_tmo.attr,
+ &dev_attr_conn_max_segment_size.attr,
+ &dev_attr_conn_tcp_timestamp_stat.attr,
+ &dev_attr_conn_tcp_wsf_disable.attr,
+ &dev_attr_conn_tcp_nagle_disable.attr,
+ &dev_attr_conn_tcp_timer_scale.attr,
+ &dev_attr_conn_tcp_timestamp_enable.attr,
+ &dev_attr_conn_fragment_disable.attr,
+ &dev_attr_conn_ipv4_tos.attr,
+ &dev_attr_conn_ipv6_traffic_class.attr,
+ &dev_attr_conn_ipv6_flow_label.attr,
+ &dev_attr_conn_is_fw_assigned_ipv6.attr,
+ &dev_attr_conn_tcp_xmit_wsf.attr,
+ &dev_attr_conn_tcp_recv_wsf.attr,
NULL,
};
@@ -3416,6 +3448,38 @@ static umode_t iscsi_conn_attr_is_visible(struct kobject *kobj,
param = ISCSI_PARAM_PING_TMO;
else if (attr == &dev_attr_conn_recv_tmo.attr)
param = ISCSI_PARAM_RECV_TMO;
+ else if (attr == &dev_attr_conn_local_port.attr)
+ param = ISCSI_PARAM_LOCAL_PORT;
+ else if (attr == &dev_attr_conn_statsn.attr)
+ param = ISCSI_PARAM_STATSN;
+ else if (attr == &dev_attr_conn_keepalive_tmo.attr)
+ param = ISCSI_PARAM_KEEPALIVE_TMO;
+ else if (attr == &dev_attr_conn_max_segment_size.attr)
+ param = ISCSI_PARAM_MAX_SEGMENT_SIZE;
+ else if (attr == &dev_attr_conn_tcp_timestamp_stat.attr)
+ param = ISCSI_PARAM_TCP_TIMESTAMP_STAT;
+ else if (attr == &dev_attr_conn_tcp_wsf_disable.attr)
+ param = ISCSI_PARAM_TCP_WSF_DISABLE;
+ else if (attr == &dev_attr_conn_tcp_nagle_disable.attr)
+ param = ISCSI_PARAM_TCP_NAGLE_DISABLE;
+ else if (attr == &dev_attr_conn_tcp_timer_scale.attr)
+ param = ISCSI_PARAM_TCP_TIMER_SCALE;
+ else if (attr == &dev_attr_conn_tcp_timestamp_enable.attr)
+ param = ISCSI_PARAM_TCP_TIMESTAMP_EN;
+ else if (attr == &dev_attr_conn_fragment_disable.attr)
+ param = ISCSI_PARAM_IP_FRAGMENT_DISABLE;
+ else if (attr == &dev_attr_conn_ipv4_tos.attr)
+ param = ISCSI_PARAM_IPV4_TOS;
+ else if (attr == &dev_attr_conn_ipv6_traffic_class.attr)
+ param = ISCSI_PARAM_IPV6_TC;
+ else if (attr == &dev_attr_conn_ipv6_flow_label.attr)
+ param = ISCSI_PARAM_IPV6_FLOW_LABEL;
+ else if (attr == &dev_attr_conn_is_fw_assigned_ipv6.attr)
+ param = ISCSI_PARAM_IS_FW_ASSIGNED_IPV6;
+ else if (attr == &dev_attr_conn_tcp_xmit_wsf.attr)
+ param = ISCSI_PARAM_TCP_XMIT_WSF;
+ else if (attr == &dev_attr_conn_tcp_recv_wsf.attr)
+ param = ISCSI_PARAM_TCP_RECV_WSF;
else {
WARN_ONCE(1, "Invalid conn attr");
return 0;
@@ -3476,6 +3540,21 @@ iscsi_session_attr(targetalias, ISCSI_PARAM_TARGET_ALIAS, 0);
iscsi_session_attr(boot_root, ISCSI_PARAM_BOOT_ROOT, 0);
iscsi_session_attr(boot_nic, ISCSI_PARAM_BOOT_NIC, 0);
iscsi_session_attr(boot_target, ISCSI_PARAM_BOOT_TARGET, 0);
+iscsi_session_attr(auto_snd_tgt_disable, ISCSI_PARAM_AUTO_SND_TGT_DISABLE, 0);
+iscsi_session_attr(discovery_session, ISCSI_PARAM_DISCOVERY_SESS, 0);
+iscsi_session_attr(portal_type, ISCSI_PARAM_PORTAL_TYPE, 0);
+iscsi_session_attr(chap_auth, ISCSI_PARAM_CHAP_AUTH_EN, 0);
+iscsi_session_attr(discovery_logout, ISCSI_PARAM_DISCOVERY_LOGOUT_EN, 0);
+iscsi_session_attr(bidi_chap, ISCSI_PARAM_BIDI_CHAP_EN, 0);
+iscsi_session_attr(discovery_auth_optional,
+ ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL, 0);
+iscsi_session_attr(def_time2wait, ISCSI_PARAM_DEF_TIME2WAIT, 0);
+iscsi_session_attr(def_time2retain, ISCSI_PARAM_DEF_TIME2RETAIN, 0);
+iscsi_session_attr(isid, ISCSI_PARAM_ISID, 0);
+iscsi_session_attr(tsid, ISCSI_PARAM_TSID, 0);
+iscsi_session_attr(def_taskmgmt_tmo, ISCSI_PARAM_DEF_TASKMGMT_TMO, 0);
+iscsi_session_attr(discovery_parent_idx, ISCSI_PARAM_DISCOVERY_PARENT_IDX, 0);
+iscsi_session_attr(discovery_parent_type, ISCSI_PARAM_DISCOVERY_PARENT_TYPE, 0);
static ssize_t
show_priv_session_state(struct device *dev, struct device_attribute *attr,
@@ -3580,6 +3659,20 @@ static struct attribute *iscsi_session_attrs[] = {
&dev_attr_sess_chap_out_idx.attr,
&dev_attr_sess_chap_in_idx.attr,
&dev_attr_priv_sess_target_id.attr,
+ &dev_attr_sess_auto_snd_tgt_disable.attr,
+ &dev_attr_sess_discovery_session.attr,
+ &dev_attr_sess_portal_type.attr,
+ &dev_attr_sess_chap_auth.attr,
+ &dev_attr_sess_discovery_logout.attr,
+ &dev_attr_sess_bidi_chap.attr,
+ &dev_attr_sess_discovery_auth_optional.attr,
+ &dev_attr_sess_def_time2wait.attr,
+ &dev_attr_sess_def_time2retain.attr,
+ &dev_attr_sess_isid.attr,
+ &dev_attr_sess_tsid.attr,
+ &dev_attr_sess_def_taskmgmt_tmo.attr,
+ &dev_attr_sess_discovery_parent_idx.attr,
+ &dev_attr_sess_discovery_parent_type.attr,
NULL,
};
@@ -3643,6 +3736,34 @@ static umode_t iscsi_session_attr_is_visible(struct kobject *kobj,
param = ISCSI_PARAM_BOOT_NIC;
else if (attr == &dev_attr_sess_boot_target.attr)
param = ISCSI_PARAM_BOOT_TARGET;
+ else if (attr == &dev_attr_sess_auto_snd_tgt_disable.attr)
+ param = ISCSI_PARAM_AUTO_SND_TGT_DISABLE;
+ else if (attr == &dev_attr_sess_discovery_session.attr)
+ param = ISCSI_PARAM_DISCOVERY_SESS;
+ else if (attr == &dev_attr_sess_portal_type.attr)
+ param = ISCSI_PARAM_PORTAL_TYPE;
+ else if (attr == &dev_attr_sess_chap_auth.attr)
+ param = ISCSI_PARAM_CHAP_AUTH_EN;
+ else if (attr == &dev_attr_sess_discovery_logout.attr)
+ param = ISCSI_PARAM_DISCOVERY_LOGOUT_EN;
+ else if (attr == &dev_attr_sess_bidi_chap.attr)
+ param = ISCSI_PARAM_BIDI_CHAP_EN;
+ else if (attr == &dev_attr_sess_discovery_auth_optional.attr)
+ param = ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL;
+ else if (attr == &dev_attr_sess_def_time2wait.attr)
+ param = ISCSI_PARAM_DEF_TIME2WAIT;
+ else if (attr == &dev_attr_sess_def_time2retain.attr)
+ param = ISCSI_PARAM_DEF_TIME2RETAIN;
+ else if (attr == &dev_attr_sess_isid.attr)
+ param = ISCSI_PARAM_ISID;
+ else if (attr == &dev_attr_sess_tsid.attr)
+ param = ISCSI_PARAM_TSID;
+ else if (attr == &dev_attr_sess_def_taskmgmt_tmo.attr)
+ param = ISCSI_PARAM_DEF_TASKMGMT_TMO;
+ else if (attr == &dev_attr_sess_discovery_parent_idx.attr)
+ param = ISCSI_PARAM_DISCOVERY_PARENT_IDX;
+ else if (attr == &dev_attr_sess_discovery_parent_type.attr)
+ param = ISCSI_PARAM_DISCOVERY_PARENT_TYPE;
else if (attr == &dev_attr_priv_sess_recovery_tmo.attr)
return S_IRUGO | S_IWUSR;
else if (attr == &dev_attr_priv_sess_state.attr)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 80f39b8b022..b58e8f815a0 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -132,8 +132,8 @@ static const char *sd_cache_types[] = {
};
static ssize_t
-sd_store_cache_type(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+cache_type_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
int i, ct = -1, rcd, wce, sp;
struct scsi_disk *sdkp = to_scsi_disk(dev);
@@ -199,8 +199,18 @@ sd_store_cache_type(struct device *dev, struct device_attribute *attr,
}
static ssize_t
-sd_store_manage_start_stop(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+manage_start_stop_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(dev);
+ struct scsi_device *sdp = sdkp->device;
+
+ return snprintf(buf, 20, "%u\n", sdp->manage_start_stop);
+}
+
+static ssize_t
+manage_start_stop_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
@@ -212,10 +222,19 @@ sd_store_manage_start_stop(struct device *dev, struct device_attribute *attr,
return count;
}
+static DEVICE_ATTR_RW(manage_start_stop);
static ssize_t
-sd_store_allow_restart(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+allow_restart_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(dev);
+
+ return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);
+}
+
+static ssize_t
+allow_restart_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
@@ -230,47 +249,30 @@ sd_store_allow_restart(struct device *dev, struct device_attribute *attr,
return count;
}
+static DEVICE_ATTR_RW(allow_restart);
static ssize_t
-sd_show_cache_type(struct device *dev, struct device_attribute *attr,
- char *buf)
+cache_type_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
int ct = sdkp->RCD + 2*sdkp->WCE;
return snprintf(buf, 40, "%s\n", sd_cache_types[ct]);
}
+static DEVICE_ATTR_RW(cache_type);
static ssize_t
-sd_show_fua(struct device *dev, struct device_attribute *attr, char *buf)
+FUA_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
}
+static DEVICE_ATTR_RO(FUA);
static ssize_t
-sd_show_manage_start_stop(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct scsi_disk *sdkp = to_scsi_disk(dev);
- struct scsi_device *sdp = sdkp->device;
-
- return snprintf(buf, 20, "%u\n", sdp->manage_start_stop);
-}
-
-static ssize_t
-sd_show_allow_restart(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct scsi_disk *sdkp = to_scsi_disk(dev);
-
- return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);
-}
-
-static ssize_t
-sd_show_protection_type(struct device *dev, struct device_attribute *attr,
- char *buf)
+protection_type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
@@ -278,8 +280,8 @@ sd_show_protection_type(struct device *dev, struct device_attribute *attr,
}
static ssize_t
-sd_store_protection_type(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+protection_type_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
unsigned int val;
@@ -298,10 +300,11 @@ sd_store_protection_type(struct device *dev, struct device_attribute *attr,
return count;
}
+static DEVICE_ATTR_RW(protection_type);
static ssize_t
-sd_show_protection_mode(struct device *dev, struct device_attribute *attr,
- char *buf)
+protection_mode_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
@@ -320,24 +323,26 @@ sd_show_protection_mode(struct device *dev, struct device_attribute *attr,
return snprintf(buf, 20, "%s%u\n", dix ? "dix" : "dif", dif);
}
+static DEVICE_ATTR_RO(protection_mode);
static ssize_t
-sd_show_app_tag_own(struct device *dev, struct device_attribute *attr,
- char *buf)
+app_tag_own_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 20, "%u\n", sdkp->ATO);
}
+static DEVICE_ATTR_RO(app_tag_own);
static ssize_t
-sd_show_thin_provisioning(struct device *dev, struct device_attribute *attr,
- char *buf)
+thin_provisioning_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
return snprintf(buf, 20, "%u\n", sdkp->lbpme);
}
+static DEVICE_ATTR_RO(thin_provisioning);
static const char *lbp_mode[] = {
[SD_LBP_FULL] = "full",
@@ -349,8 +354,8 @@ static const char *lbp_mode[] = {
};
static ssize_t
-sd_show_provisioning_mode(struct device *dev, struct device_attribute *attr,
- char *buf)
+provisioning_mode_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
@@ -358,8 +363,8 @@ sd_show_provisioning_mode(struct device *dev, struct device_attribute *attr,
}
static ssize_t
-sd_store_provisioning_mode(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+provisioning_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
@@ -385,10 +390,11 @@ sd_store_provisioning_mode(struct device *dev, struct device_attribute *attr,
return count;
}
+static DEVICE_ATTR_RW(provisioning_mode);
static ssize_t
-sd_show_max_medium_access_timeouts(struct device *dev,
- struct device_attribute *attr, char *buf)
+max_medium_access_timeouts_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
@@ -396,9 +402,9 @@ sd_show_max_medium_access_timeouts(struct device *dev,
}
static ssize_t
-sd_store_max_medium_access_timeouts(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+max_medium_access_timeouts_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
int err;
@@ -410,10 +416,11 @@ sd_store_max_medium_access_timeouts(struct device *dev,
return err ? err : count;
}
+static DEVICE_ATTR_RW(max_medium_access_timeouts);
static ssize_t
-sd_show_write_same_blocks(struct device *dev, struct device_attribute *attr,
- char *buf)
+max_write_same_blocks_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
@@ -421,8 +428,8 @@ sd_show_write_same_blocks(struct device *dev, struct device_attribute *attr,
}
static ssize_t
-sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+max_write_same_blocks_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct scsi_device *sdp = sdkp->device;
@@ -451,35 +458,29 @@ sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr,
return count;
}
-
-static struct device_attribute sd_disk_attrs[] = {
- __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
- sd_store_cache_type),
- __ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
- __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,
- sd_store_allow_restart),
- __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,
- sd_store_manage_start_stop),
- __ATTR(protection_type, S_IRUGO|S_IWUSR, sd_show_protection_type,
- sd_store_protection_type),
- __ATTR(protection_mode, S_IRUGO, sd_show_protection_mode, NULL),
- __ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL),
- __ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL),
- __ATTR(provisioning_mode, S_IRUGO|S_IWUSR, sd_show_provisioning_mode,
- sd_store_provisioning_mode),
- __ATTR(max_write_same_blocks, S_IRUGO|S_IWUSR,
- sd_show_write_same_blocks, sd_store_write_same_blocks),
- __ATTR(max_medium_access_timeouts, S_IRUGO|S_IWUSR,
- sd_show_max_medium_access_timeouts,
- sd_store_max_medium_access_timeouts),
- __ATTR_NULL,
+static DEVICE_ATTR_RW(max_write_same_blocks);
+
+static struct attribute *sd_disk_attrs[] = {
+ &dev_attr_cache_type.attr,
+ &dev_attr_FUA.attr,
+ &dev_attr_allow_restart.attr,
+ &dev_attr_manage_start_stop.attr,
+ &dev_attr_protection_type.attr,
+ &dev_attr_protection_mode.attr,
+ &dev_attr_app_tag_own.attr,
+ &dev_attr_thin_provisioning.attr,
+ &dev_attr_provisioning_mode.attr,
+ &dev_attr_max_write_same_blocks.attr,
+ &dev_attr_max_medium_access_timeouts.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(sd_disk);
static struct class sd_disk_class = {
.name = "scsi_disk",
.owner = THIS_MODULE,
.dev_release = scsi_disk_release,
- .dev_attrs = sd_disk_attrs,
+ .dev_groups = sd_disk_groups,
};
static const struct dev_pm_ops sd_pm_ops = {
@@ -838,10 +839,17 @@ static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq)
static void sd_unprep_fn(struct request_queue *q, struct request *rq)
{
+ struct scsi_cmnd *SCpnt = rq->special;
+
if (rq->cmd_flags & REQ_DISCARD) {
free_page((unsigned long)rq->buffer);
rq->buffer = NULL;
}
+ if (SCpnt->cmnd != rq->cmd) {
+ mempool_free(SCpnt->cmnd, sd_cdb_pool);
+ SCpnt->cmnd = NULL;
+ SCpnt->cmd_len = 0;
+ }
}
/**
@@ -1720,21 +1728,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt))
sd_dif_complete(SCpnt, good_bytes);
- if (scsi_host_dif_capable(sdkp->device->host, sdkp->protection_type)
- == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd) {
-
- /* We have to print a failed command here as the
- * extended CDB gets freed before scsi_io_completion()
- * is called.
- */
- if (result)
- scsi_print_command(SCpnt);
-
- mempool_free(SCpnt->cmnd, sd_cdb_pool);
- SCpnt->cmnd = NULL;
- SCpnt->cmd_len = 0;
- }
-
return good_bytes;
}
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index df5e961484e..5cbc4bb1b39 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -105,11 +105,8 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ;
static int sg_add(struct device *, struct class_interface *);
static void sg_remove(struct device *, struct class_interface *);
-static DEFINE_SPINLOCK(sg_open_exclusive_lock);
-
static DEFINE_IDR(sg_index_idr);
-static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock
- file descriptor list for device */
+static DEFINE_RWLOCK(sg_index_lock);
static struct class_interface sg_interface = {
.add_dev = sg_add,
@@ -146,8 +143,7 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
} Sg_request;
typedef struct sg_fd { /* holds the state of a file descriptor */
- /* sfd_siblings is protected by sg_index_lock */
- struct list_head sfd_siblings;
+ struct list_head sfd_siblings; /* protected by sfd_lock of device */
struct sg_device *parentdp; /* owning device */
wait_queue_head_t read_wait; /* queue read until command done */
rwlock_t rq_list_lock; /* protect access to list in req_arr */
@@ -170,13 +166,12 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
typedef struct sg_device { /* holds the state of each scsi generic device */
struct scsi_device *device;
- wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */
u32 index; /* device index number */
- /* sfds is protected by sg_index_lock */
+ spinlock_t sfd_lock; /* protect file descriptor list for device */
struct list_head sfds;
+ struct rw_semaphore o_sem; /* exclude open should hold this rwsem */
volatile char detached; /* 0->attached, 1->detached pending removal */
- /* exclude protected by sg_open_exclusive_lock */
char exclude; /* opened for exclusive access */
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
struct gendisk *disk;
@@ -225,35 +220,14 @@ static int sg_allow_access(struct file *filp, unsigned char *cmd)
return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
}
-static int get_exclude(Sg_device *sdp)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&sg_open_exclusive_lock, flags);
- ret = sdp->exclude;
- spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
- return ret;
-}
-
-static int set_exclude(Sg_device *sdp, char val)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sg_open_exclusive_lock, flags);
- sdp->exclude = val;
- spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
- return val;
-}
-
static int sfds_list_empty(Sg_device *sdp)
{
unsigned long flags;
int ret;
- read_lock_irqsave(&sg_index_lock, flags);
+ spin_lock_irqsave(&sdp->sfd_lock, flags);
ret = list_empty(&sdp->sfds);
- read_unlock_irqrestore(&sg_index_lock, flags);
+ spin_unlock_irqrestore(&sdp->sfd_lock, flags);
return ret;
}
@@ -265,7 +239,6 @@ sg_open(struct inode *inode, struct file *filp)
struct request_queue *q;
Sg_device *sdp;
Sg_fd *sfp;
- int res;
int retval;
nonseekable_open(inode, filp);
@@ -294,54 +267,52 @@ sg_open(struct inode *inode, struct file *filp)
goto error_out;
}
- if (flags & O_EXCL) {
- if (O_RDONLY == (flags & O_ACCMODE)) {
- retval = -EPERM; /* Can't lock it with read only access */
- goto error_out;
- }
- if (!sfds_list_empty(sdp) && (flags & O_NONBLOCK)) {
- retval = -EBUSY;
- goto error_out;
- }
- res = wait_event_interruptible(sdp->o_excl_wait,
- ((!sfds_list_empty(sdp) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1)));
- if (res) {
- retval = res; /* -ERESTARTSYS because signal hit process */
- goto error_out;
- }
- } else if (get_exclude(sdp)) { /* some other fd has an exclusive lock on dev */
- if (flags & O_NONBLOCK) {
- retval = -EBUSY;
- goto error_out;
- }
- res = wait_event_interruptible(sdp->o_excl_wait, !get_exclude(sdp));
- if (res) {
- retval = res; /* -ERESTARTSYS because signal hit process */
- goto error_out;
- }
- }
- if (sdp->detached) {
- retval = -ENODEV;
+ if ((flags & O_EXCL) && (O_RDONLY == (flags & O_ACCMODE))) {
+ retval = -EPERM; /* Can't lock it with read only access */
goto error_out;
}
+ if (flags & O_NONBLOCK) {
+ if (flags & O_EXCL) {
+ if (!down_write_trylock(&sdp->o_sem)) {
+ retval = -EBUSY;
+ goto error_out;
+ }
+ } else {
+ if (!down_read_trylock(&sdp->o_sem)) {
+ retval = -EBUSY;
+ goto error_out;
+ }
+ }
+ } else {
+ if (flags & O_EXCL)
+ down_write(&sdp->o_sem);
+ else
+ down_read(&sdp->o_sem);
+ }
+ /* Since write lock is held, no need to check sfd_list */
+ if (flags & O_EXCL)
+ sdp->exclude = 1; /* used by release lock */
+
if (sfds_list_empty(sdp)) { /* no existing opens on this device */
sdp->sgdebug = 0;
q = sdp->device->request_queue;
sdp->sg_tablesize = queue_max_segments(q);
}
- if ((sfp = sg_add_sfp(sdp, dev)))
+ sfp = sg_add_sfp(sdp, dev);
+ if (!IS_ERR(sfp))
filp->private_data = sfp;
+ /* retval is already provably zero at this point because of the
+ * check after retval = scsi_autopm_get_device(sdp->device))
+ */
else {
+ retval = PTR_ERR(sfp);
+
if (flags & O_EXCL) {
- set_exclude(sdp, 0); /* undo if error */
- wake_up_interruptible(&sdp->o_excl_wait);
- }
- retval = -ENOMEM;
- goto error_out;
- }
- retval = 0;
+ sdp->exclude = 0; /* undo if error */
+ up_write(&sdp->o_sem);
+ } else
+ up_read(&sdp->o_sem);
error_out:
- if (retval) {
scsi_autopm_put_device(sdp->device);
sdp_put:
scsi_device_put(sdp->device);
@@ -358,13 +329,18 @@ sg_release(struct inode *inode, struct file *filp)
{
Sg_device *sdp;
Sg_fd *sfp;
+ int excl;
if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
- set_exclude(sdp, 0);
- wake_up_interruptible(&sdp->o_excl_wait);
+ excl = sdp->exclude;
+ sdp->exclude = 0;
+ if (excl)
+ up_write(&sdp->o_sem);
+ else
+ up_read(&sdp->o_sem);
scsi_autopm_put_device(sdp->device);
kref_put(&sfp->f_ref, sg_remove_sfp);
@@ -1415,8 +1391,9 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
disk->first_minor = k;
sdp->disk = disk;
sdp->device = scsidp;
+ spin_lock_init(&sdp->sfd_lock);
INIT_LIST_HEAD(&sdp->sfds);
- init_waitqueue_head(&sdp->o_excl_wait);
+ init_rwsem(&sdp->o_sem);
sdp->sg_tablesize = queue_max_segments(q);
sdp->index = k;
kref_init(&sdp->d_ref);
@@ -1549,11 +1526,13 @@ static void sg_remove(struct device *cl_dev, struct class_interface *cl_intf)
/* Need a write lock to set sdp->detached. */
write_lock_irqsave(&sg_index_lock, iflags);
+ spin_lock(&sdp->sfd_lock);
sdp->detached = 1;
list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) {
wake_up_interruptible(&sfp->read_wait);
kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
}
+ spin_unlock(&sdp->sfd_lock);
write_unlock_irqrestore(&sg_index_lock, iflags);
sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
@@ -2064,7 +2043,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN);
if (!sfp)
- return NULL;
+ return ERR_PTR(-ENOMEM);
init_waitqueue_head(&sfp->read_wait);
rwlock_init(&sfp->rq_list_lock);
@@ -2078,9 +2057,13 @@ sg_add_sfp(Sg_device * sdp, int dev)
sfp->cmd_q = SG_DEF_COMMAND_Q;
sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
sfp->parentdp = sdp;
- write_lock_irqsave(&sg_index_lock, iflags);
+ spin_lock_irqsave(&sdp->sfd_lock, iflags);
+ if (sdp->detached) {
+ spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
+ return ERR_PTR(-ENODEV);
+ }
list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
- write_unlock_irqrestore(&sg_index_lock, iflags);
+ spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
if (unlikely(sg_big_buff != def_reserved_size))
sg_big_buff = def_reserved_size;
@@ -2130,10 +2113,9 @@ static void sg_remove_sfp(struct kref *kref)
struct sg_device *sdp = sfp->parentdp;
unsigned long iflags;
- write_lock_irqsave(&sg_index_lock, iflags);
+ spin_lock_irqsave(&sdp->sfd_lock, iflags);
list_del(&sfp->sfd_siblings);
- write_unlock_irqrestore(&sg_index_lock, iflags);
- wake_up_interruptible(&sdp->o_excl_wait);
+ spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext);
schedule_work(&sfp->ew.work);
@@ -2520,7 +2502,7 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
return 0;
}
-/* must be called while holding sg_index_lock */
+/* must be called while holding sg_index_lock and sfd_lock */
static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
{
int k, m, new_interface, blen, usg;
@@ -2605,22 +2587,26 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
read_lock_irqsave(&sg_index_lock, iflags);
sdp = it ? sg_lookup_dev(it->index) : NULL;
- if (sdp && !list_empty(&sdp->sfds)) {
- struct scsi_device *scsidp = sdp->device;
+ if (sdp) {
+ spin_lock(&sdp->sfd_lock);
+ if (!list_empty(&sdp->sfds)) {
+ struct scsi_device *scsidp = sdp->device;
- seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
- if (sdp->detached)
- seq_printf(s, "detached pending close ");
- else
- seq_printf
- (s, "scsi%d chan=%d id=%d lun=%d em=%d",
- scsidp->host->host_no,
- scsidp->channel, scsidp->id,
- scsidp->lun,
- scsidp->host->hostt->emulated);
- seq_printf(s, " sg_tablesize=%d excl=%d\n",
- sdp->sg_tablesize, get_exclude(sdp));
- sg_proc_debug_helper(s, sdp);
+ seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
+ if (sdp->detached)
+ seq_printf(s, "detached pending close ");
+ else
+ seq_printf
+ (s, "scsi%d chan=%d id=%d lun=%d em=%d",
+ scsidp->host->host_no,
+ scsidp->channel, scsidp->id,
+ scsidp->lun,
+ scsidp->host->hostt->emulated);
+ seq_printf(s, " sg_tablesize=%d excl=%d\n",
+ sdp->sg_tablesize, sdp->exclude);
+ sg_proc_debug_helper(s, sdp);
+ }
+ spin_unlock(&sdp->sfd_lock);
}
read_unlock_irqrestore(&sg_index_lock, iflags);
return 0;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 2a32036a940..ff44b3c2cff 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -82,7 +82,7 @@ static int try_rdio = 1;
static int try_wdio = 1;
static struct class st_sysfs_class;
-static struct device_attribute st_dev_attrs[];
+static const struct attribute_group *st_dev_groups[];
MODULE_AUTHOR("Kai Makisara");
MODULE_DESCRIPTION("SCSI tape (st) driver");
@@ -4274,7 +4274,7 @@ static void scsi_tape_release(struct kref *kref)
static struct class st_sysfs_class = {
.name = "scsi_tape",
- .dev_attrs = st_dev_attrs,
+ .dev_groups = st_dev_groups,
};
static int __init init_st(void)
@@ -4408,6 +4408,7 @@ defined_show(struct device *dev, struct device_attribute *attr, char *buf)
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined);
return l;
}
+static DEVICE_ATTR_RO(defined);
static ssize_t
default_blksize_show(struct device *dev, struct device_attribute *attr,
@@ -4419,7 +4420,7 @@ default_blksize_show(struct device *dev, struct device_attribute *attr,
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize);
return l;
}
-
+static DEVICE_ATTR_RO(default_blksize);
static ssize_t
default_density_show(struct device *dev, struct device_attribute *attr,
@@ -4433,6 +4434,7 @@ default_density_show(struct device *dev, struct device_attribute *attr,
l = snprintf(buf, PAGE_SIZE, fmt, STm->default_density);
return l;
}
+static DEVICE_ATTR_RO(default_density);
static ssize_t
default_compression_show(struct device *dev, struct device_attribute *attr,
@@ -4444,6 +4446,7 @@ default_compression_show(struct device *dev, struct device_attribute *attr,
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1);
return l;
}
+static DEVICE_ATTR_RO(default_compression);
static ssize_t
options_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -4472,15 +4475,17 @@ options_show(struct device *dev, struct device_attribute *attr, char *buf)
l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options);
return l;
}
-
-static struct device_attribute st_dev_attrs[] = {
- __ATTR_RO(defined),
- __ATTR_RO(default_blksize),
- __ATTR_RO(default_density),
- __ATTR_RO(default_compression),
- __ATTR_RO(options),
- __ATTR_NULL,
+static DEVICE_ATTR_RO(options);
+
+static struct attribute *st_dev_attrs[] = {
+ &dev_attr_defined.attr,
+ &dev_attr_default_blksize.attr,
+ &dev_attr_default_density.attr,
+ &dev_attr_default_compression.attr,
+ &dev_attr_options.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(st_dev);
/* The following functions may be useful for a larger audience. */
static int sgl_map_user_pages(struct st_buffer *STbp,
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 83ec1aa8596..1a28f563279 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1879,7 +1879,6 @@ static void __exit storvsc_drv_exit(void)
}
MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V virtual storage driver");
module_init(storvsc_drv_init);
module_exit(storvsc_drv_exit);
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 139bc0647b4..bce09a6898c 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -36,10 +36,17 @@
#ifndef _UFS_H
#define _UFS_H
+#include <linux/mutex.h>
+#include <linux/types.h>
+
#define MAX_CDB_SIZE 16
+#define GENERAL_UPIU_REQUEST_SIZE 32
+#define QUERY_DESC_MAX_SIZE 256
+#define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \
+ (sizeof(struct utp_upiu_header)))
#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
- ((byte3 << 24) | (byte2 << 16) |\
+ cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
(byte1 << 8) | (byte0))
/*
@@ -62,7 +69,7 @@ enum {
UPIU_TRANSACTION_COMMAND = 0x01,
UPIU_TRANSACTION_DATA_OUT = 0x02,
UPIU_TRANSACTION_TASK_REQ = 0x04,
- UPIU_TRANSACTION_QUERY_REQ = 0x26,
+ UPIU_TRANSACTION_QUERY_REQ = 0x16,
};
/* UTP UPIU Transaction Codes Target to Initiator */
@@ -73,6 +80,7 @@ enum {
UPIU_TRANSACTION_TASK_RSP = 0x24,
UPIU_TRANSACTION_READY_XFER = 0x31,
UPIU_TRANSACTION_QUERY_RSP = 0x36,
+ UPIU_TRANSACTION_REJECT_UPIU = 0x3F,
};
/* UPIU Read/Write flags */
@@ -90,8 +98,41 @@ enum {
UPIU_TASK_ATTR_ACA = 0x03,
};
-/* UTP QUERY Transaction Specific Fields OpCode */
+/* UPIU Query request function */
enum {
+ UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
+ UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
+};
+
+/* Flag idn for Query Requests*/
+enum flag_idn {
+ QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
+ QUERY_FLAG_IDN_BKOPS_EN = 0x04,
+};
+
+/* Attribute idn for Query requests */
+enum attr_idn {
+ QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
+ QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
+ QUERY_ATTR_IDN_EE_STATUS = 0x0E,
+};
+
+/* Exception event mask values */
+enum {
+ MASK_EE_STATUS = 0xFFFF,
+ MASK_EE_URGENT_BKOPS = (1 << 2),
+};
+
+/* Background operation status */
+enum {
+ BKOPS_STATUS_NO_OP = 0x0,
+ BKOPS_STATUS_NON_CRITICAL = 0x1,
+ BKOPS_STATUS_PERF_IMPACT = 0x2,
+ BKOPS_STATUS_CRITICAL = 0x3,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum query_opcode {
UPIU_QUERY_OPCODE_NOP = 0x0,
UPIU_QUERY_OPCODE_READ_DESC = 0x1,
UPIU_QUERY_OPCODE_WRITE_DESC = 0x2,
@@ -103,6 +144,21 @@ enum {
UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
};
+/* Query response result code */
+enum {
+ QUERY_RESULT_SUCCESS = 0x00,
+ QUERY_RESULT_NOT_READABLE = 0xF6,
+ QUERY_RESULT_NOT_WRITEABLE = 0xF7,
+ QUERY_RESULT_ALREADY_WRITTEN = 0xF8,
+ QUERY_RESULT_INVALID_LENGTH = 0xF9,
+ QUERY_RESULT_INVALID_VALUE = 0xFA,
+ QUERY_RESULT_INVALID_SELECTOR = 0xFB,
+ QUERY_RESULT_INVALID_INDEX = 0xFC,
+ QUERY_RESULT_INVALID_IDN = 0xFD,
+ QUERY_RESULT_INVALID_OPCODE = 0xFE,
+ QUERY_RESULT_GENERAL_FAILURE = 0xFF,
+};
+
/* UTP Transfer Request Command Type (CT) */
enum {
UPIU_COMMAND_SET_TYPE_SCSI = 0x0,
@@ -110,10 +166,18 @@ enum {
UPIU_COMMAND_SET_TYPE_QUERY = 0x2,
};
+/* UTP Transfer Request Command Offset */
+#define UPIU_COMMAND_TYPE_OFFSET 28
+
+/* Offset of the response code in the UPIU header */
+#define UPIU_RSP_CODE_OFFSET 8
+
enum {
- MASK_SCSI_STATUS = 0xFF,
- MASK_TASK_RESPONSE = 0xFF00,
- MASK_RSP_UPIU_RESULT = 0xFFFF,
+ MASK_SCSI_STATUS = 0xFF,
+ MASK_TASK_RESPONSE = 0xFF00,
+ MASK_RSP_UPIU_RESULT = 0xFFFF,
+ MASK_QUERY_DATA_SEG_LEN = 0xFFFF,
+ MASK_RSP_EXCEPTION_EVENT = 0x10000,
};
/* Task management service response */
@@ -138,26 +202,59 @@ struct utp_upiu_header {
/**
* struct utp_upiu_cmd - Command UPIU structure
- * @header: UPIU header structure DW-0 to DW-2
* @data_transfer_len: Data Transfer Length DW-3
* @cdb: Command Descriptor Block CDB DW-4 to DW-7
*/
struct utp_upiu_cmd {
- struct utp_upiu_header header;
u32 exp_data_transfer_len;
u8 cdb[MAX_CDB_SIZE];
};
/**
- * struct utp_upiu_rsp - Response UPIU structure
- * @header: UPIU header DW-0 to DW-2
+ * struct utp_upiu_query - upiu request buffer structure for
+ * query request.
+ * @opcode: command to perform B-0
+ * @idn: a value that indicates the particular type of data B-1
+ * @index: Index to further identify data B-2
+ * @selector: Index to further identify data B-3
+ * @reserved_osf: spec reserved field B-4,5
+ * @length: number of descriptor bytes to read/write B-6,7
+ * @value: Attribute value to be written DW-5
+ * @reserved: spec reserved DW-6,7
+ */
+struct utp_upiu_query {
+ u8 opcode;
+ u8 idn;
+ u8 index;
+ u8 selector;
+ u16 reserved_osf;
+ u16 length;
+ u32 value;
+ u32 reserved[2];
+};
+
+/**
+ * struct utp_upiu_req - general upiu request structure
+ * @header:UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command DW-3 to DW-7
+ * @qr: fields structure for query request DW-3 to DW-7
+ */
+struct utp_upiu_req {
+ struct utp_upiu_header header;
+ union {
+ struct utp_upiu_cmd sc;
+ struct utp_upiu_query qr;
+ };
+};
+
+/**
+ * struct utp_cmd_rsp - Response UPIU structure
* @residual_transfer_count: Residual transfer count DW-3
* @reserved: Reserved double words DW-4 to DW-7
* @sense_data_len: Sense data length DW-8 U16
* @sense_data: Sense data field DW-8 to DW-12
*/
-struct utp_upiu_rsp {
- struct utp_upiu_header header;
+struct utp_cmd_rsp {
u32 residual_transfer_count;
u32 reserved[4];
u16 sense_data_len;
@@ -165,6 +262,20 @@ struct utp_upiu_rsp {
};
/**
+ * struct utp_upiu_rsp - general upiu response structure
+ * @header: UPIU header structure DW-0 to DW-2
+ * @sr: fields structure for scsi command DW-3 to DW-12
+ * @qr: fields structure for query request DW-3 to DW-7
+ */
+struct utp_upiu_rsp {
+ struct utp_upiu_header header;
+ union {
+ struct utp_cmd_rsp sr;
+ struct utp_upiu_query qr;
+ };
+};
+
+/**
* struct utp_upiu_task_req - Task request UPIU structure
* @header - UPIU header structure DW0 to DW-2
* @input_param1: Input parameter 1 DW-3
@@ -194,4 +305,24 @@ struct utp_upiu_task_rsp {
u32 reserved[3];
};
+/**
+ * struct ufs_query_req - parameters for building a query request
+ * @query_func: UPIU header query function
+ * @upiu_req: the query request data
+ */
+struct ufs_query_req {
+ u8 query_func;
+ struct utp_upiu_query upiu_req;
+};
+
+/**
+ * struct ufs_query_resp - UPIU QUERY
+ * @response: device response code
+ * @upiu_res: query response data
+ */
+struct ufs_query_res {
+ u8 response;
+ struct utp_upiu_query upiu_res;
+};
+
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 48be39a6f6d..a823cf44e94 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -35,6 +35,7 @@
#include "ufshcd.h"
#include <linux/pci.h>
+#include <linux/pm_runtime.h>
#ifdef CONFIG_PM
/**
@@ -44,7 +45,7 @@
*
* Returns -ENOSYS
*/
-static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int ufshcd_pci_suspend(struct device *dev)
{
/*
* TODO:
@@ -61,7 +62,7 @@ static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state)
*
* Returns -ENOSYS
*/
-static int ufshcd_pci_resume(struct pci_dev *pdev)
+static int ufshcd_pci_resume(struct device *dev)
{
/*
* TODO:
@@ -71,8 +72,45 @@ static int ufshcd_pci_resume(struct pci_dev *pdev)
return -ENOSYS;
}
+#else
+#define ufshcd_pci_suspend NULL
+#define ufshcd_pci_resume NULL
#endif /* CONFIG_PM */
+#ifdef CONFIG_PM_RUNTIME
+static int ufshcd_pci_runtime_suspend(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ if (!hba)
+ return 0;
+
+ return ufshcd_runtime_suspend(hba);
+}
+static int ufshcd_pci_runtime_resume(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ if (!hba)
+ return 0;
+
+ return ufshcd_runtime_resume(hba);
+}
+static int ufshcd_pci_runtime_idle(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ if (!hba)
+ return 0;
+
+ return ufshcd_runtime_idle(hba);
+}
+#else /* !CONFIG_PM_RUNTIME */
+#define ufshcd_pci_runtime_suspend NULL
+#define ufshcd_pci_runtime_resume NULL
+#define ufshcd_pci_runtime_idle NULL
+#endif /* CONFIG_PM_RUNTIME */
+
/**
* ufshcd_pci_shutdown - main function to put the controller in reset state
* @pdev: pointer to PCI device handle
@@ -91,12 +129,10 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
{
struct ufs_hba *hba = pci_get_drvdata(pdev);
- disable_irq(pdev->irq);
+ pm_runtime_forbid(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
ufshcd_remove(hba);
- pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
- pci_clear_master(pdev);
- pci_disable_device(pdev);
}
/**
@@ -133,55 +169,49 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
void __iomem *mmio_base;
int err;
- err = pci_enable_device(pdev);
+ err = pcim_enable_device(pdev);
if (err) {
- dev_err(&pdev->dev, "pci_enable_device failed\n");
- goto out_error;
+ dev_err(&pdev->dev, "pcim_enable_device failed\n");
+ return err;
}
pci_set_master(pdev);
-
- err = pci_request_regions(pdev, UFSHCD);
+ err = pcim_iomap_regions(pdev, 1 << 0, UFSHCD);
if (err < 0) {
- dev_err(&pdev->dev, "request regions failed\n");
- goto out_disable;
+ dev_err(&pdev->dev, "request and iomap failed\n");
+ return err;
}
- mmio_base = pci_ioremap_bar(pdev, 0);
- if (!mmio_base) {
- dev_err(&pdev->dev, "memory map failed\n");
- err = -ENOMEM;
- goto out_release_regions;
- }
+ mmio_base = pcim_iomap_table(pdev)[0];
err = ufshcd_set_dma_mask(pdev);
if (err) {
dev_err(&pdev->dev, "set dma mask failed\n");
- goto out_iounmap;
+ return err;
}
err = ufshcd_init(&pdev->dev, &hba, mmio_base, pdev->irq);
if (err) {
dev_err(&pdev->dev, "Initialization failed\n");
- goto out_iounmap;
+ return err;
}
pci_set_drvdata(pdev, hba);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
return 0;
-
-out_iounmap:
- iounmap(mmio_base);
-out_release_regions:
- pci_release_regions(pdev);
-out_disable:
- pci_clear_master(pdev);
- pci_disable_device(pdev);
-out_error:
- return err;
}
+static const struct dev_pm_ops ufshcd_pci_pm_ops = {
+ .suspend = ufshcd_pci_suspend,
+ .resume = ufshcd_pci_resume,
+ .runtime_suspend = ufshcd_pci_runtime_suspend,
+ .runtime_resume = ufshcd_pci_runtime_resume,
+ .runtime_idle = ufshcd_pci_runtime_idle,
+};
+
static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
{ PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ } /* terminate list */
@@ -195,10 +225,9 @@ static struct pci_driver ufshcd_pci_driver = {
.probe = ufshcd_pci_probe,
.remove = ufshcd_pci_remove,
.shutdown = ufshcd_pci_shutdown,
-#ifdef CONFIG_PM
- .suspend = ufshcd_pci_suspend,
- .resume = ufshcd_pci_resume,
-#endif
+ .driver = {
+ .pm = &ufshcd_pci_pm_ops
+ },
};
module_pci_driver(ufshcd_pci_driver);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index c42db40d4e5..5e462322542 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -34,6 +34,7 @@
*/
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include "ufshcd.h"
@@ -87,6 +88,40 @@ static int ufshcd_pltfrm_resume(struct device *dev)
#define ufshcd_pltfrm_resume NULL
#endif
+#ifdef CONFIG_PM_RUNTIME
+static int ufshcd_pltfrm_runtime_suspend(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ if (!hba)
+ return 0;
+
+ return ufshcd_runtime_suspend(hba);
+}
+static int ufshcd_pltfrm_runtime_resume(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ if (!hba)
+ return 0;
+
+ return ufshcd_runtime_resume(hba);
+}
+static int ufshcd_pltfrm_runtime_idle(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ if (!hba)
+ return 0;
+
+ return ufshcd_runtime_idle(hba);
+}
+#else /* !CONFIG_PM_RUNTIME */
+#define ufshcd_pltfrm_runtime_suspend NULL
+#define ufshcd_pltfrm_runtime_resume NULL
+#define ufshcd_pltfrm_runtime_idle NULL
+#endif /* CONFIG_PM_RUNTIME */
+
/**
* ufshcd_pltfrm_probe - probe routine of the driver
* @pdev: pointer to Platform device handle
@@ -102,15 +137,8 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- dev_err(dev, "Memory resource not available\n");
- err = -ENODEV;
- goto out;
- }
-
mmio_base = devm_ioremap_resource(dev, mem_res);
if (IS_ERR(mmio_base)) {
- dev_err(dev, "memory map failed\n");
err = PTR_ERR(mmio_base);
goto out;
}
@@ -122,14 +150,22 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
goto out;
}
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
err = ufshcd_init(dev, &hba, mmio_base, irq);
if (err) {
dev_err(dev, "Intialization failed\n");
- goto out;
+ goto out_disable_rpm;
}
platform_set_drvdata(pdev, hba);
+ return 0;
+
+out_disable_rpm:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
out:
return err;
}
@@ -144,7 +180,7 @@ static int ufshcd_pltfrm_remove(struct platform_device *pdev)
{
struct ufs_hba *hba = platform_get_drvdata(pdev);
- disable_irq(hba->irq);
+ pm_runtime_get_sync(&(pdev)->dev);
ufshcd_remove(hba);
return 0;
}
@@ -157,6 +193,9 @@ static const struct of_device_id ufs_of_match[] = {
static const struct dev_pm_ops ufshcd_dev_pm_ops = {
.suspend = ufshcd_pltfrm_suspend,
.resume = ufshcd_pltfrm_resume,
+ .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
+ .runtime_resume = ufshcd_pltfrm_runtime_resume,
+ .runtime_idle = ufshcd_pltfrm_runtime_idle,
};
static struct platform_driver ufshcd_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b743bd6fce6..b36ca9a2dfb 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -43,6 +43,19 @@
/* UIC command timeout, unit: ms */
#define UIC_CMD_TIMEOUT 500
+/* NOP OUT retries waiting for NOP IN response */
+#define NOP_OUT_RETRIES 10
+/* Timeout after 30 msecs if NOP OUT hangs without response */
+#define NOP_OUT_TIMEOUT 30 /* msecs */
+
+/* Query request retries */
+#define QUERY_REQ_RETRIES 10
+/* Query request timeout */
+#define QUERY_REQ_TIMEOUT 30 /* msec */
+
+/* Expose the flag value from utp_upiu_query.value */
+#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
+
enum {
UFSHCD_MAX_CHANNEL = 0,
UFSHCD_MAX_ID = 1,
@@ -71,6 +84,40 @@ enum {
INT_AGGR_CONFIG,
};
+/*
+ * ufshcd_wait_for_register - wait for register value to change
+ * @hba - per-adapter interface
+ * @reg - mmio register offset
+ * @mask - mask to apply to read register value
+ * @val - wait condition
+ * @interval_us - polling interval in microsecs
+ * @timeout_ms - timeout in millisecs
+ *
+ * Returns -ETIMEDOUT on error, zero on success
+ */
+static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+ u32 val, unsigned long interval_us, unsigned long timeout_ms)
+{
+ int err = 0;
+ unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
+
+ /* ignore bits that we don't intend to wait on */
+ val = val & mask;
+
+ while ((ufshcd_readl(hba, reg) & mask) != val) {
+ /* wakeup within 50us of expiry */
+ usleep_range(interval_us, interval_us + 50);
+
+ if (time_after(jiffies, timeout)) {
+ if ((ufshcd_readl(hba, reg) & mask) != val)
+ err = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ return err;
+}
+
/**
* ufshcd_get_intr_mask - Get the interrupt bit mask
* @hba - Pointer to adapter instance
@@ -191,18 +238,13 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
}
/**
- * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
+ * ufshcd_get_req_rsp - returns the TR response transaction type
* @ucd_rsp_ptr: pointer to response UPIU
- *
- * This function checks the response UPIU for valid transaction type in
- * response field
- * Returns 0 on success, non-zero on failure
*/
static inline int
-ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
+ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
{
- return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
- UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
+ return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
}
/**
@@ -219,6 +261,21 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr)
}
/**
+ * ufshcd_is_exception_event - Check if the device raised an exception event
+ * @ucd_rsp_ptr: pointer to response UPIU
+ *
+ * The function checks if the device raised an exception event indicated in
+ * the Device Information field of response UPIU.
+ *
+ * Returns true if exception is raised, false otherwise.
+ */
+static inline bool ufshcd_is_exception_event(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+ return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
+ MASK_RSP_EXCEPTION_EVENT ? true : false;
+}
+
+/**
* ufshcd_config_int_aggr - Configure interrupt aggregation values.
* Currently there is no use case where we want to configure
* interrupt aggregation dynamically. So to configure interrupt
@@ -299,14 +356,68 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
{
int len;
if (lrbp->sense_buffer) {
- len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
+ len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len);
memcpy(lrbp->sense_buffer,
- lrbp->ucd_rsp_ptr->sense_data,
+ lrbp->ucd_rsp_ptr->sr.sense_data,
min_t(int, len, SCSI_SENSE_BUFFERSIZE));
}
}
/**
+ * ufshcd_query_to_cpu() - formats the buffer to native cpu endian
+ * @response: upiu query response to convert
+ */
+static inline void ufshcd_query_to_cpu(struct utp_upiu_query *response)
+{
+ response->length = be16_to_cpu(response->length);
+ response->value = be32_to_cpu(response->value);
+}
+
+/**
+ * ufshcd_query_to_be() - formats the buffer to big endian
+ * @request: upiu query request to convert
+ */
+static inline void ufshcd_query_to_be(struct utp_upiu_query *request)
+{
+ request->length = cpu_to_be16(request->length);
+ request->value = cpu_to_be32(request->value);
+}
+
+/**
+ * ufshcd_copy_query_response() - Copy the Query Response and the data
+ * descriptor
+ * @hba: per adapter instance
+ * @lrb - pointer to local reference block
+ */
+static
+void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+ struct ufs_query_res *query_res = &hba->dev_cmd.query.response;
+
+ /* Get the UPIU response */
+ query_res->response = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr) >>
+ UPIU_RSP_CODE_OFFSET;
+
+ memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr, QUERY_OSF_SIZE);
+ ufshcd_query_to_cpu(&query_res->upiu_res);
+
+
+ /* Get the descriptor */
+ if (lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) {
+ u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr +
+ GENERAL_UPIU_REQUEST_SIZE;
+ u16 len;
+
+ /* data segment length */
+ len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) &
+ MASK_QUERY_DATA_SEG_LEN;
+
+ memcpy(hba->dev_cmd.query.descriptor, descp,
+ min_t(u16, len, QUERY_DESC_MAX_SIZE));
+ }
+}
+
+/**
* ufshcd_hba_capabilities - Read controller capabilities
* @hba: per adapter instance
*/
@@ -519,76 +630,170 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
}
/**
+ * ufshcd_prepare_req_desc_hdr() - Fills the requests header
+ * descriptor according to request
+ * @lrbp: pointer to local reference block
+ * @upiu_flags: flags required in the header
+ * @cmd_dir: requests data direction
+ */
+static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
+ u32 *upiu_flags, enum dma_data_direction cmd_dir)
+{
+ struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
+ u32 data_direction;
+ u32 dword_0;
+
+ if (cmd_dir == DMA_FROM_DEVICE) {
+ data_direction = UTP_DEVICE_TO_HOST;
+ *upiu_flags = UPIU_CMD_FLAGS_READ;
+ } else if (cmd_dir == DMA_TO_DEVICE) {
+ data_direction = UTP_HOST_TO_DEVICE;
+ *upiu_flags = UPIU_CMD_FLAGS_WRITE;
+ } else {
+ data_direction = UTP_NO_DATA_TRANSFER;
+ *upiu_flags = UPIU_CMD_FLAGS_NONE;
+ }
+
+ dword_0 = data_direction | (lrbp->command_type
+ << UPIU_COMMAND_TYPE_OFFSET);
+ if (lrbp->intr_cmd)
+ dword_0 |= UTP_REQ_DESC_INT_CMD;
+
+ /* Transfer request descriptor header fields */
+ req_desc->header.dword_0 = cpu_to_le32(dword_0);
+
+ /*
+ * assigning invalid value for command status. Controller
+ * updates OCS on command completion, with the command
+ * status
+ */
+ req_desc->header.dword_2 =
+ cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+}
+
+/**
+ * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc,
+ * for scsi commands
+ * @lrbp - local reference block pointer
+ * @upiu_flags - flags
+ */
+static
+void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
+{
+ struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+ /* command descriptor fields */
+ ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+ UPIU_TRANSACTION_COMMAND, upiu_flags,
+ lrbp->lun, lrbp->task_tag);
+ ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+ UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
+
+ /* Total EHS length and Data segment length will be zero */
+ ucd_req_ptr->header.dword_2 = 0;
+
+ ucd_req_ptr->sc.exp_data_transfer_len =
+ cpu_to_be32(lrbp->cmd->sdb.length);
+
+ memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
+ (min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
+}
+
+/**
+ * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
+ * for query requsts
+ * @hba: UFS hba
+ * @lrbp: local reference block pointer
+ * @upiu_flags: flags
+ */
+static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
+ struct ufshcd_lrb *lrbp, u32 upiu_flags)
+{
+ struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+ struct ufs_query *query = &hba->dev_cmd.query;
+ u16 len = query->request.upiu_req.length;
+ u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE;
+
+ /* Query request header */
+ ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+ UPIU_TRANSACTION_QUERY_REQ, upiu_flags,
+ lrbp->lun, lrbp->task_tag);
+ ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+ 0, query->request.query_func, 0, 0);
+
+ /* Data segment length */
+ ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD(
+ 0, 0, len >> 8, (u8)len);
+
+ /* Copy the Query Request buffer as is */
+ memcpy(&ucd_req_ptr->qr, &query->request.upiu_req,
+ QUERY_OSF_SIZE);
+ ufshcd_query_to_be(&ucd_req_ptr->qr);
+
+ /* Copy the Descriptor */
+ if ((len > 0) && (query->request.upiu_req.opcode ==
+ UPIU_QUERY_OPCODE_WRITE_DESC)) {
+ memcpy(descp, query->descriptor,
+ min_t(u16, len, QUERY_DESC_MAX_SIZE));
+ }
+}
+
+static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
+{
+ struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+ memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req));
+
+ /* command descriptor fields */
+ ucd_req_ptr->header.dword_0 =
+ UPIU_HEADER_DWORD(
+ UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag);
+}
+
+/**
* ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
+ * @hba - per adapter instance
* @lrb - pointer to local reference block
*/
-static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp)
+static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
{
- struct utp_transfer_req_desc *req_desc;
- struct utp_upiu_cmd *ucd_cmd_ptr;
- u32 data_direction;
u32 upiu_flags;
-
- ucd_cmd_ptr = lrbp->ucd_cmd_ptr;
- req_desc = lrbp->utr_descriptor_ptr;
+ int ret = 0;
switch (lrbp->command_type) {
case UTP_CMD_TYPE_SCSI:
- if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
- data_direction = UTP_DEVICE_TO_HOST;
- upiu_flags = UPIU_CMD_FLAGS_READ;
- } else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) {
- data_direction = UTP_HOST_TO_DEVICE;
- upiu_flags = UPIU_CMD_FLAGS_WRITE;
+ if (likely(lrbp->cmd)) {
+ ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags,
+ lrbp->cmd->sc_data_direction);
+ ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
} else {
- data_direction = UTP_NO_DATA_TRANSFER;
- upiu_flags = UPIU_CMD_FLAGS_NONE;
+ ret = -EINVAL;
}
-
- /* Transfer request descriptor header fields */
- req_desc->header.dword_0 =
- cpu_to_le32(data_direction | UTP_SCSI_COMMAND);
-
- /*
- * assigning invalid value for command status. Controller
- * updates OCS on command completion, with the command
- * status
- */
- req_desc->header.dword_2 =
- cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
-
- /* command descriptor fields */
- ucd_cmd_ptr->header.dword_0 =
- cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND,
- upiu_flags,
- lrbp->lun,
- lrbp->task_tag));
- ucd_cmd_ptr->header.dword_1 =
- cpu_to_be32(
- UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI,
- 0,
- 0,
- 0));
-
- /* Total EHS length and Data segment length will be zero */
- ucd_cmd_ptr->header.dword_2 = 0;
-
- ucd_cmd_ptr->exp_data_transfer_len =
- cpu_to_be32(lrbp->cmd->sdb.length);
-
- memcpy(ucd_cmd_ptr->cdb,
- lrbp->cmd->cmnd,
- (min_t(unsigned short,
- lrbp->cmd->cmd_len,
- MAX_CDB_SIZE)));
break;
case UTP_CMD_TYPE_DEV_MANAGE:
- /* For query function implementation */
+ ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
+ if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY)
+ ufshcd_prepare_utp_query_req_upiu(
+ hba, lrbp, upiu_flags);
+ else if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP)
+ ufshcd_prepare_utp_nop_upiu(lrbp);
+ else
+ ret = -EINVAL;
break;
case UTP_CMD_TYPE_UFS:
/* For UFS native command implementation */
+ ret = -ENOTSUPP;
+ dev_err(hba->dev, "%s: UFS native command are not supported\n",
+ __func__);
+ break;
+ default:
+ ret = -ENOTSUPP;
+ dev_err(hba->dev, "%s: unknown command type: 0x%x\n",
+ __func__, lrbp->command_type);
break;
} /* end of switch */
+
+ return ret;
}
/**
@@ -615,21 +820,37 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
goto out;
}
+ /* acquire the tag to make sure device cmds don't use it */
+ if (test_and_set_bit_lock(tag, &hba->lrb_in_use)) {
+ /*
+ * Dev manage command in progress, requeue the command.
+ * Requeuing the command helps in cases where the request *may*
+ * find different tag instead of waiting for dev manage command
+ * completion.
+ */
+ err = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ }
+
lrbp = &hba->lrb[tag];
+ WARN_ON(lrbp->cmd);
lrbp->cmd = cmd;
lrbp->sense_bufflen = SCSI_SENSE_BUFFERSIZE;
lrbp->sense_buffer = cmd->sense_buffer;
lrbp->task_tag = tag;
lrbp->lun = cmd->device->lun;
-
+ lrbp->intr_cmd = false;
lrbp->command_type = UTP_CMD_TYPE_SCSI;
/* form UPIU before issuing the command */
- ufshcd_compose_upiu(lrbp);
+ ufshcd_compose_upiu(hba, lrbp);
err = ufshcd_map_sg(lrbp);
- if (err)
+ if (err) {
+ lrbp->cmd = NULL;
+ clear_bit_unlock(tag, &hba->lrb_in_use);
goto out;
+ }
/* issue command to the controller */
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -639,6 +860,338 @@ out:
return err;
}
+static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
+ struct ufshcd_lrb *lrbp, enum dev_cmd_type cmd_type, int tag)
+{
+ lrbp->cmd = NULL;
+ lrbp->sense_bufflen = 0;
+ lrbp->sense_buffer = NULL;
+ lrbp->task_tag = tag;
+ lrbp->lun = 0; /* device management cmd is not specific to any LUN */
+ lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+ lrbp->intr_cmd = true; /* No interrupt aggregation */
+ hba->dev_cmd.type = cmd_type;
+
+ return ufshcd_compose_upiu(hba, lrbp);
+}
+
+static int
+ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
+{
+ int err = 0;
+ unsigned long flags;
+ u32 mask = 1 << tag;
+
+ /* clear outstanding transaction before retry */
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ ufshcd_utrl_clear(hba, tag);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ /*
+ * wait for for h/w to clear corresponding bit in door-bell.
+ * max. wait is 1 sec.
+ */
+ err = ufshcd_wait_for_register(hba,
+ REG_UTP_TRANSFER_REQ_DOOR_BELL,
+ mask, ~mask, 1000, 1000);
+
+ return err;
+}
+
+/**
+ * ufshcd_dev_cmd_completion() - handles device management command responses
+ * @hba: per adapter instance
+ * @lrbp: pointer to local reference block
+ */
+static int
+ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+ int resp;
+ int err = 0;
+
+ resp = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
+
+ switch (resp) {
+ case UPIU_TRANSACTION_NOP_IN:
+ if (hba->dev_cmd.type != DEV_CMD_TYPE_NOP) {
+ err = -EINVAL;
+ dev_err(hba->dev, "%s: unexpected response %x\n",
+ __func__, resp);
+ }
+ break;
+ case UPIU_TRANSACTION_QUERY_RSP:
+ ufshcd_copy_query_response(hba, lrbp);
+ break;
+ case UPIU_TRANSACTION_REJECT_UPIU:
+ /* TODO: handle Reject UPIU Response */
+ err = -EPERM;
+ dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n",
+ __func__);
+ break;
+ default:
+ err = -EINVAL;
+ dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n",
+ __func__, resp);
+ break;
+ }
+
+ return err;
+}
+
+static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
+ struct ufshcd_lrb *lrbp, int max_timeout)
+{
+ int err = 0;
+ unsigned long time_left;
+ unsigned long flags;
+
+ time_left = wait_for_completion_timeout(hba->dev_cmd.complete,
+ msecs_to_jiffies(max_timeout));
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->dev_cmd.complete = NULL;
+ if (likely(time_left)) {
+ err = ufshcd_get_tr_ocs(lrbp);
+ if (!err)
+ err = ufshcd_dev_cmd_completion(hba, lrbp);
+ }
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ if (!time_left) {
+ err = -ETIMEDOUT;
+ if (!ufshcd_clear_cmd(hba, lrbp->task_tag))
+ /* sucessfully cleared the command, retry if needed */
+ err = -EAGAIN;
+ }
+
+ return err;
+}
+
+/**
+ * ufshcd_get_dev_cmd_tag - Get device management command tag
+ * @hba: per-adapter instance
+ * @tag: pointer to variable with available slot value
+ *
+ * Get a free slot and lock it until device management command
+ * completes.
+ *
+ * Returns false if free slot is unavailable for locking, else
+ * return true with tag value in @tag.
+ */
+static bool ufshcd_get_dev_cmd_tag(struct ufs_hba *hba, int *tag_out)
+{
+ int tag;
+ bool ret = false;
+ unsigned long tmp;
+
+ if (!tag_out)
+ goto out;
+
+ do {
+ tmp = ~hba->lrb_in_use;
+ tag = find_last_bit(&tmp, hba->nutrs);
+ if (tag >= hba->nutrs)
+ goto out;
+ } while (test_and_set_bit_lock(tag, &hba->lrb_in_use));
+
+ *tag_out = tag;
+ ret = true;
+out:
+ return ret;
+}
+
+static inline void ufshcd_put_dev_cmd_tag(struct ufs_hba *hba, int tag)
+{
+ clear_bit_unlock(tag, &hba->lrb_in_use);
+}
+
+/**
+ * ufshcd_exec_dev_cmd - API for sending device management requests
+ * @hba - UFS hba
+ * @cmd_type - specifies the type (NOP, Query...)
+ * @timeout - time in seconds
+ *
+ * NOTE: Since there is only one available tag for device management commands,
+ * it is expected you hold the hba->dev_cmd.lock mutex.
+ */
+static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
+ enum dev_cmd_type cmd_type, int timeout)
+{
+ struct ufshcd_lrb *lrbp;
+ int err;
+ int tag;
+ struct completion wait;
+ unsigned long flags;
+
+ /*
+ * Get free slot, sleep if slots are unavailable.
+ * Even though we use wait_event() which sleeps indefinitely,
+ * the maximum wait time is bounded by SCSI request timeout.
+ */
+ wait_event(hba->dev_cmd.tag_wq, ufshcd_get_dev_cmd_tag(hba, &tag));
+
+ init_completion(&wait);
+ lrbp = &hba->lrb[tag];
+ WARN_ON(lrbp->cmd);
+ err = ufshcd_compose_dev_cmd(hba, lrbp, cmd_type, tag);
+ if (unlikely(err))
+ goto out_put_tag;
+
+ hba->dev_cmd.complete = &wait;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ ufshcd_send_command(hba, tag);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout);
+
+out_put_tag:
+ ufshcd_put_dev_cmd_tag(hba, tag);
+ wake_up(&hba->dev_cmd.tag_wq);
+ return err;
+}
+
+/**
+ * ufshcd_query_flag() - API function for sending flag query requests
+ * hba: per-adapter instance
+ * query_opcode: flag query to perform
+ * idn: flag idn to access
+ * flag_res: the flag value after the query request completes
+ *
+ * Returns 0 for success, non-zero in case of failure
+ */
+static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+ enum flag_idn idn, bool *flag_res)
+{
+ struct ufs_query_req *request;
+ struct ufs_query_res *response;
+ int err;
+
+ BUG_ON(!hba);
+
+ mutex_lock(&hba->dev_cmd.lock);
+ request = &hba->dev_cmd.query.request;
+ response = &hba->dev_cmd.query.response;
+ memset(request, 0, sizeof(struct ufs_query_req));
+ memset(response, 0, sizeof(struct ufs_query_res));
+
+ switch (opcode) {
+ case UPIU_QUERY_OPCODE_SET_FLAG:
+ case UPIU_QUERY_OPCODE_CLEAR_FLAG:
+ case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
+ request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+ break;
+ case UPIU_QUERY_OPCODE_READ_FLAG:
+ request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+ if (!flag_res) {
+ /* No dummy reads */
+ dev_err(hba->dev, "%s: Invalid argument for read request\n",
+ __func__);
+ err = -EINVAL;
+ goto out_unlock;
+ }
+ break;
+ default:
+ dev_err(hba->dev,
+ "%s: Expected query flag opcode but got = %d\n",
+ __func__, opcode);
+ err = -EINVAL;
+ goto out_unlock;
+ }
+ request->upiu_req.opcode = opcode;
+ request->upiu_req.idn = idn;
+
+ /* Send query request */
+ err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY,
+ QUERY_REQ_TIMEOUT);
+
+ if (err) {
+ dev_err(hba->dev,
+ "%s: Sending flag query for idn %d failed, err = %d\n",
+ __func__, idn, err);
+ goto out_unlock;
+ }
+
+ if (flag_res)
+ *flag_res = (response->upiu_res.value &
+ MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
+
+out_unlock:
+ mutex_unlock(&hba->dev_cmd.lock);
+ return err;
+}
+
+/**
+ * ufshcd_query_attr - API function for sending attribute requests
+ * hba: per-adapter instance
+ * opcode: attribute opcode
+ * idn: attribute idn to access
+ * index: index field
+ * selector: selector field
+ * attr_val: the attribute value after the query request completes
+ *
+ * Returns 0 for success, non-zero in case of failure
+*/
+int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
+ enum attr_idn idn, u8 index, u8 selector, u32 *attr_val)
+{
+ struct ufs_query_req *request;
+ struct ufs_query_res *response;
+ int err;
+
+ BUG_ON(!hba);
+
+ if (!attr_val) {
+ dev_err(hba->dev, "%s: attribute value required for opcode 0x%x\n",
+ __func__, opcode);
+ err = -EINVAL;
+ goto out;
+ }
+
+ mutex_lock(&hba->dev_cmd.lock);
+ request = &hba->dev_cmd.query.request;
+ response = &hba->dev_cmd.query.response;
+ memset(request, 0, sizeof(struct ufs_query_req));
+ memset(response, 0, sizeof(struct ufs_query_res));
+
+ switch (opcode) {
+ case UPIU_QUERY_OPCODE_WRITE_ATTR:
+ request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+ request->upiu_req.value = *attr_val;
+ break;
+ case UPIU_QUERY_OPCODE_READ_ATTR:
+ request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+ break;
+ default:
+ dev_err(hba->dev, "%s: Expected query attr opcode but got = 0x%.2x\n",
+ __func__, opcode);
+ err = -EINVAL;
+ goto out_unlock;
+ }
+
+ request->upiu_req.opcode = opcode;
+ request->upiu_req.idn = idn;
+ request->upiu_req.index = index;
+ request->upiu_req.selector = selector;
+
+ /* Send query request */
+ err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY,
+ QUERY_REQ_TIMEOUT);
+
+ if (err) {
+ dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, err = %d\n",
+ __func__, opcode, idn, err);
+ goto out_unlock;
+ }
+
+ *attr_val = response->upiu_res.value;
+
+out_unlock:
+ mutex_unlock(&hba->dev_cmd.lock);
+out:
+ return err;
+}
+
/**
* ufshcd_memory_alloc - allocate memory for host memory space data structures
* @hba: per adapter instance
@@ -774,8 +1327,8 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
cpu_to_le16(ALIGNED_UPIU_SIZE >> 2);
hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
- hba->lrb[i].ucd_cmd_ptr =
- (struct utp_upiu_cmd *)(cmd_descp + i);
+ hba->lrb[i].ucd_req_ptr =
+ (struct utp_upiu_req *)(cmd_descp + i);
hba->lrb[i].ucd_rsp_ptr =
(struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
hba->lrb[i].ucd_prdt_ptr =
@@ -809,6 +1362,57 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
}
/**
+ * ufshcd_complete_dev_init() - checks device readiness
+ * hba: per-adapter instance
+ *
+ * Set fDeviceInit flag and poll until device toggles it.
+ */
+static int ufshcd_complete_dev_init(struct ufs_hba *hba)
+{
+ int i, retries, err = 0;
+ bool flag_res = 1;
+
+ for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+ /* Set the fDeviceInit flag */
+ err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+ QUERY_FLAG_IDN_FDEVICEINIT, NULL);
+ if (!err || err == -ETIMEDOUT)
+ break;
+ dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+ }
+ if (err) {
+ dev_err(hba->dev,
+ "%s setting fDeviceInit flag failed with error %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ /* poll for max. 100 iterations for fDeviceInit flag to clear */
+ for (i = 0; i < 100 && !err && flag_res; i++) {
+ for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+ err = ufshcd_query_flag(hba,
+ UPIU_QUERY_OPCODE_READ_FLAG,
+ QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+ if (!err || err == -ETIMEDOUT)
+ break;
+ dev_dbg(hba->dev, "%s: error %d retrying\n", __func__,
+ err);
+ }
+ }
+ if (err)
+ dev_err(hba->dev,
+ "%s reading fDeviceInit flag failed with error %d\n",
+ __func__, err);
+ else if (flag_res)
+ dev_err(hba->dev,
+ "%s fDeviceInit was not cleared by the device\n",
+ __func__);
+
+out:
+ return err;
+}
+
+/**
* ufshcd_make_hba_operational - Make UFS controller operational
* @hba: per adapter instance
*
@@ -961,6 +1565,38 @@ out:
}
/**
+ * ufshcd_verify_dev_init() - Verify device initialization
+ * @hba: per-adapter instance
+ *
+ * Send NOP OUT UPIU and wait for NOP IN response to check whether the
+ * device Transport Protocol (UTP) layer is ready after a reset.
+ * If the UTP layer at the device side is not initialized, it may
+ * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT
+ * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations.
+ */
+static int ufshcd_verify_dev_init(struct ufs_hba *hba)
+{
+ int err = 0;
+ int retries;
+
+ mutex_lock(&hba->dev_cmd.lock);
+ for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
+ err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP,
+ NOP_OUT_TIMEOUT);
+
+ if (!err || err == -ETIMEDOUT)
+ break;
+
+ dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+ }
+ mutex_unlock(&hba->dev_cmd.lock);
+
+ if (err)
+ dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
+ return err;
+}
+
+/**
* ufshcd_do_reset - reset the host controller
* @hba: per adapter instance
*
@@ -986,13 +1622,20 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
for (tag = 0; tag < hba->nutrs; tag++) {
if (test_bit(tag, &hba->outstanding_reqs)) {
lrbp = &hba->lrb[tag];
- scsi_dma_unmap(lrbp->cmd);
- lrbp->cmd->result = DID_RESET << 16;
- lrbp->cmd->scsi_done(lrbp->cmd);
- lrbp->cmd = NULL;
+ if (lrbp->cmd) {
+ scsi_dma_unmap(lrbp->cmd);
+ lrbp->cmd->result = DID_RESET << 16;
+ lrbp->cmd->scsi_done(lrbp->cmd);
+ lrbp->cmd = NULL;
+ clear_bit_unlock(tag, &hba->lrb_in_use);
+ }
}
}
+ /* complete device management command */
+ if (hba->dev_cmd.complete)
+ complete(hba->dev_cmd.complete);
+
/* clear outstanding request/task bit maps */
hba->outstanding_reqs = 0;
hba->outstanding_tasks = 0;
@@ -1199,27 +1842,39 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
switch (ocs) {
case OCS_SUCCESS:
+ result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
- /* check if the returned transfer response is valid */
- result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
- if (result) {
+ switch (result) {
+ case UPIU_TRANSACTION_RESPONSE:
+ /*
+ * get the response UPIU result to extract
+ * the SCSI command status
+ */
+ result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+ /*
+ * get the result based on SCSI status response
+ * to notify the SCSI midlayer of the command status
+ */
+ scsi_status = result & MASK_SCSI_STATUS;
+ result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
+
+ if (ufshcd_is_exception_event(lrbp->ucd_rsp_ptr))
+ schedule_work(&hba->eeh_work);
+ break;
+ case UPIU_TRANSACTION_REJECT_UPIU:
+ /* TODO: handle Reject UPIU Response */
+ result = DID_ERROR << 16;
+ dev_err(hba->dev,
+ "Reject UPIU not fully implemented\n");
+ break;
+ default:
+ result = DID_ERROR << 16;
dev_err(hba->dev,
- "Invalid response = %x\n", result);
+ "Unexpected request response code = %x\n",
+ result);
break;
}
-
- /*
- * get the response UPIU result to extract
- * the SCSI command status
- */
- result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
-
- /*
- * get the result based on SCSI status response
- * to notify the SCSI midlayer of the command status
- */
- scsi_status = result & MASK_SCSI_STATUS;
- result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
break;
case OCS_ABORTED:
result |= DID_ABORT << 16;
@@ -1259,28 +1914,40 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
*/
static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
{
- struct ufshcd_lrb *lrb;
+ struct ufshcd_lrb *lrbp;
+ struct scsi_cmnd *cmd;
unsigned long completed_reqs;
u32 tr_doorbell;
int result;
int index;
+ bool int_aggr_reset = false;
- lrb = hba->lrb;
tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
for (index = 0; index < hba->nutrs; index++) {
if (test_bit(index, &completed_reqs)) {
+ lrbp = &hba->lrb[index];
+ cmd = lrbp->cmd;
+ /*
+ * Don't skip resetting interrupt aggregation counters
+ * if a regular command is present.
+ */
+ int_aggr_reset |= !lrbp->intr_cmd;
- result = ufshcd_transfer_rsp_status(hba, &lrb[index]);
-
- if (lrb[index].cmd) {
- scsi_dma_unmap(lrb[index].cmd);
- lrb[index].cmd->result = result;
- lrb[index].cmd->scsi_done(lrb[index].cmd);
-
+ if (cmd) {
+ result = ufshcd_transfer_rsp_status(hba, lrbp);
+ scsi_dma_unmap(cmd);
+ cmd->result = result;
/* Mark completed command as NULL in LRB */
- lrb[index].cmd = NULL;
+ lrbp->cmd = NULL;
+ clear_bit_unlock(index, &hba->lrb_in_use);
+ /* Do not touch lrbp after scsi done */
+ cmd->scsi_done(cmd);
+ } else if (lrbp->command_type ==
+ UTP_CMD_TYPE_DEV_MANAGE) {
+ if (hba->dev_cmd.complete)
+ complete(hba->dev_cmd.complete);
}
} /* end of if */
} /* end of for */
@@ -1288,8 +1955,238 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
/* clear corresponding bits of completed commands */
hba->outstanding_reqs ^= completed_reqs;
+ /* we might have free'd some tags above */
+ wake_up(&hba->dev_cmd.tag_wq);
+
/* Reset interrupt aggregation counters */
- ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+ if (int_aggr_reset)
+ ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+}
+
+/**
+ * ufshcd_disable_ee - disable exception event
+ * @hba: per-adapter instance
+ * @mask: exception event to disable
+ *
+ * Disables exception event in the device so that the EVENT_ALERT
+ * bit is not set.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_disable_ee(struct ufs_hba *hba, u16 mask)
+{
+ int err = 0;
+ u32 val;
+
+ if (!(hba->ee_ctrl_mask & mask))
+ goto out;
+
+ val = hba->ee_ctrl_mask & ~mask;
+ val &= 0xFFFF; /* 2 bytes */
+ err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+ QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val);
+ if (!err)
+ hba->ee_ctrl_mask &= ~mask;
+out:
+ return err;
+}
+
+/**
+ * ufshcd_enable_ee - enable exception event
+ * @hba: per-adapter instance
+ * @mask: exception event to enable
+ *
+ * Enable corresponding exception event in the device to allow
+ * device to alert host in critical scenarios.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask)
+{
+ int err = 0;
+ u32 val;
+
+ if (hba->ee_ctrl_mask & mask)
+ goto out;
+
+ val = hba->ee_ctrl_mask | mask;
+ val &= 0xFFFF; /* 2 bytes */
+ err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+ QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val);
+ if (!err)
+ hba->ee_ctrl_mask |= mask;
+out:
+ return err;
+}
+
+/**
+ * ufshcd_enable_auto_bkops - Allow device managed BKOPS
+ * @hba: per-adapter instance
+ *
+ * Allow device to manage background operations on its own. Enabling
+ * this might lead to inconsistent latencies during normal data transfers
+ * as the device is allowed to manage its own way of handling background
+ * operations.
+ *
+ * Returns zero on success, non-zero on failure.
+ */
+static int ufshcd_enable_auto_bkops(struct ufs_hba *hba)
+{
+ int err = 0;
+
+ if (hba->auto_bkops_enabled)
+ goto out;
+
+ err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+ QUERY_FLAG_IDN_BKOPS_EN, NULL);
+ if (err) {
+ dev_err(hba->dev, "%s: failed to enable bkops %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ hba->auto_bkops_enabled = true;
+
+ /* No need of URGENT_BKOPS exception from the device */
+ err = ufshcd_disable_ee(hba, MASK_EE_URGENT_BKOPS);
+ if (err)
+ dev_err(hba->dev, "%s: failed to disable exception event %d\n",
+ __func__, err);
+out:
+ return err;
+}
+
+/**
+ * ufshcd_disable_auto_bkops - block device in doing background operations
+ * @hba: per-adapter instance
+ *
+ * Disabling background operations improves command response latency but
+ * has drawback of device moving into critical state where the device is
+ * not-operable. Make sure to call ufshcd_enable_auto_bkops() whenever the
+ * host is idle so that BKOPS are managed effectively without any negative
+ * impacts.
+ *
+ * Returns zero on success, non-zero on failure.
+ */
+static int ufshcd_disable_auto_bkops(struct ufs_hba *hba)
+{
+ int err = 0;
+
+ if (!hba->auto_bkops_enabled)
+ goto out;
+
+ /*
+ * If host assisted BKOPs is to be enabled, make sure
+ * urgent bkops exception is allowed.
+ */
+ err = ufshcd_enable_ee(hba, MASK_EE_URGENT_BKOPS);
+ if (err) {
+ dev_err(hba->dev, "%s: failed to enable exception event %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG,
+ QUERY_FLAG_IDN_BKOPS_EN, NULL);
+ if (err) {
+ dev_err(hba->dev, "%s: failed to disable bkops %d\n",
+ __func__, err);
+ ufshcd_disable_ee(hba, MASK_EE_URGENT_BKOPS);
+ goto out;
+ }
+
+ hba->auto_bkops_enabled = false;
+out:
+ return err;
+}
+
+/**
+ * ufshcd_force_reset_auto_bkops - force enable of auto bkops
+ * @hba: per adapter instance
+ *
+ * After a device reset the device may toggle the BKOPS_EN flag
+ * to default value. The s/w tracking variables should be updated
+ * as well. Do this by forcing enable of auto bkops.
+ */
+static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba)
+{
+ hba->auto_bkops_enabled = false;
+ hba->ee_ctrl_mask |= MASK_EE_URGENT_BKOPS;
+ ufshcd_enable_auto_bkops(hba);
+}
+
+static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status)
+{
+ return ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+ QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, status);
+}
+
+/**
+ * ufshcd_urgent_bkops - handle urgent bkops exception event
+ * @hba: per-adapter instance
+ *
+ * Enable fBackgroundOpsEn flag in the device to permit background
+ * operations.
+ */
+static int ufshcd_urgent_bkops(struct ufs_hba *hba)
+{
+ int err;
+ u32 status = 0;
+
+ err = ufshcd_get_bkops_status(hba, &status);
+ if (err) {
+ dev_err(hba->dev, "%s: failed to get BKOPS status %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ status = status & 0xF;
+
+ /* handle only if status indicates performance impact or critical */
+ if (status >= BKOPS_STATUS_PERF_IMPACT)
+ err = ufshcd_enable_auto_bkops(hba);
+out:
+ return err;
+}
+
+static inline int ufshcd_get_ee_status(struct ufs_hba *hba, u32 *status)
+{
+ return ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+ QUERY_ATTR_IDN_EE_STATUS, 0, 0, status);
+}
+
+/**
+ * ufshcd_exception_event_handler - handle exceptions raised by device
+ * @work: pointer to work data
+ *
+ * Read bExceptionEventStatus attribute from the device and handle the
+ * exception event accordingly.
+ */
+static void ufshcd_exception_event_handler(struct work_struct *work)
+{
+ struct ufs_hba *hba;
+ int err;
+ u32 status = 0;
+ hba = container_of(work, struct ufs_hba, eeh_work);
+
+ pm_runtime_get_sync(hba->dev);
+ err = ufshcd_get_ee_status(hba, &status);
+ if (err) {
+ dev_err(hba->dev, "%s: failed to get exception status %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ status &= hba->ee_ctrl_mask;
+ if (status & MASK_EE_URGENT_BKOPS) {
+ err = ufshcd_urgent_bkops(hba);
+ if (err)
+ dev_err(hba->dev, "%s: failed to handle urgent bkops %d\n",
+ __func__, err);
+ }
+out:
+ pm_runtime_put_sync(hba->dev);
+ return;
}
/**
@@ -1301,9 +2198,11 @@ static void ufshcd_fatal_err_handler(struct work_struct *work)
struct ufs_hba *hba;
hba = container_of(work, struct ufs_hba, feh_workq);
+ pm_runtime_get_sync(hba->dev);
/* check if reset is already in progress */
if (hba->ufshcd_state != UFSHCD_STATE_RESET)
ufshcd_do_reset(hba);
+ pm_runtime_put_sync(hba->dev);
}
/**
@@ -1432,10 +2331,10 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
task_req_upiup =
(struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
task_req_upiup->header.dword_0 =
- cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
- lrbp->lun, lrbp->task_tag));
+ UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
+ lrbp->lun, lrbp->task_tag);
task_req_upiup->header.dword_1 =
- cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
+ UPIU_HEADER_DWORD(0, tm_function, 0, 0);
task_req_upiup->input_param1 = lrbp->lun;
task_req_upiup->input_param1 =
@@ -1502,9 +2401,11 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
if (hba->lrb[pos].cmd) {
scsi_dma_unmap(hba->lrb[pos].cmd);
hba->lrb[pos].cmd->result =
- DID_ABORT << 16;
+ DID_ABORT << 16;
hba->lrb[pos].cmd->scsi_done(cmd);
hba->lrb[pos].cmd = NULL;
+ clear_bit_unlock(pos, &hba->lrb_in_use);
+ wake_up(&hba->dev_cmd.tag_wq);
}
}
} /* end of for */
@@ -1572,6 +2473,9 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
__clear_bit(tag, &hba->outstanding_reqs);
hba->lrb[tag].cmd = NULL;
spin_unlock_irqrestore(host->host_lock, flags);
+
+ clear_bit_unlock(tag, &hba->lrb_in_use);
+ wake_up(&hba->dev_cmd.tag_wq);
out:
return err;
}
@@ -1587,8 +2491,22 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
int ret;
ret = ufshcd_link_startup(hba);
- if (!ret)
- scsi_scan_host(hba->host);
+ if (ret)
+ goto out;
+
+ ret = ufshcd_verify_dev_init(hba);
+ if (ret)
+ goto out;
+
+ ret = ufshcd_complete_dev_init(hba);
+ if (ret)
+ goto out;
+
+ ufshcd_force_reset_auto_bkops(hba);
+ scsi_scan_host(hba->host);
+ pm_runtime_put_sync(hba->dev);
+out:
+ return;
}
static struct scsi_host_template ufshcd_driver_template = {
@@ -1650,6 +2568,34 @@ int ufshcd_resume(struct ufs_hba *hba)
}
EXPORT_SYMBOL_GPL(ufshcd_resume);
+int ufshcd_runtime_suspend(struct ufs_hba *hba)
+{
+ if (!hba)
+ return 0;
+
+ /*
+ * The device is idle with no requests in the queue,
+ * allow background operations.
+ */
+ return ufshcd_enable_auto_bkops(hba);
+}
+EXPORT_SYMBOL(ufshcd_runtime_suspend);
+
+int ufshcd_runtime_resume(struct ufs_hba *hba)
+{
+ if (!hba)
+ return 0;
+
+ return ufshcd_disable_auto_bkops(hba);
+}
+EXPORT_SYMBOL(ufshcd_runtime_resume);
+
+int ufshcd_runtime_idle(struct ufs_hba *hba)
+{
+ return 0;
+}
+EXPORT_SYMBOL(ufshcd_runtime_idle);
+
/**
* ufshcd_remove - de-allocate SCSI host and host memory space
* data structure memory
@@ -1657,11 +2603,11 @@ EXPORT_SYMBOL_GPL(ufshcd_resume);
*/
void ufshcd_remove(struct ufs_hba *hba)
{
+ scsi_remove_host(hba->host);
/* disable interrupts */
ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba);
- scsi_remove_host(hba->host);
scsi_host_put(hba->host);
}
EXPORT_SYMBOL_GPL(ufshcd_remove);
@@ -1740,10 +2686,17 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
/* Initialize work queues */
INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
+ INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler);
/* Initialize UIC command mutex */
mutex_init(&hba->uic_cmd_mutex);
+ /* Initialize mutex for device management commands */
+ mutex_init(&hba->dev_cmd.lock);
+
+ /* Initialize device management tag acquire wait queue */
+ init_waitqueue_head(&hba->dev_cmd.tag_wq);
+
/* IRQ registration */
err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
if (err) {
@@ -1773,6 +2726,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
*hba_handle = hba;
+ /* Hold auto suspend until async scan completes */
+ pm_runtime_get_sync(dev);
+
async_schedule(ufshcd_async_scan, hba);
return 0;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 49590ee07ac..59c9c4848be 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -68,6 +68,11 @@
#define UFSHCD "ufshcd"
#define UFSHCD_DRIVER_VERSION "0.2"
+enum dev_cmd_type {
+ DEV_CMD_TYPE_NOP = 0x0,
+ DEV_CMD_TYPE_QUERY = 0x1,
+};
+
/**
* struct uic_command - UIC command structure
* @command: UIC command
@@ -91,7 +96,7 @@ struct uic_command {
/**
* struct ufshcd_lrb - local reference block
* @utr_descriptor_ptr: UTRD address of the command
- * @ucd_cmd_ptr: UCD address of the command
+ * @ucd_req_ptr: UCD address of the command
* @ucd_rsp_ptr: Response UPIU address for this command
* @ucd_prdt_ptr: PRDT address of the command
* @cmd: pointer to SCSI command
@@ -101,10 +106,11 @@ struct uic_command {
* @command_type: SCSI, UFS, Query.
* @task_tag: Task tag of the command
* @lun: LUN of the command
+ * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
*/
struct ufshcd_lrb {
struct utp_transfer_req_desc *utr_descriptor_ptr;
- struct utp_upiu_cmd *ucd_cmd_ptr;
+ struct utp_upiu_req *ucd_req_ptr;
struct utp_upiu_rsp *ucd_rsp_ptr;
struct ufshcd_sg_entry *ucd_prdt_ptr;
@@ -116,8 +122,35 @@ struct ufshcd_lrb {
int command_type;
int task_tag;
unsigned int lun;
+ bool intr_cmd;
};
+/**
+ * struct ufs_query - holds relevent data structures for query request
+ * @request: request upiu and function
+ * @descriptor: buffer for sending/receiving descriptor
+ * @response: response upiu and response
+ */
+struct ufs_query {
+ struct ufs_query_req request;
+ u8 *descriptor;
+ struct ufs_query_res response;
+};
+
+/**
+ * struct ufs_dev_cmd - all assosiated fields with device management commands
+ * @type: device management command type - Query, NOP OUT
+ * @lock: lock to allow one command at a time
+ * @complete: internal commands completion
+ * @tag_wq: wait queue until free command slot is available
+ */
+struct ufs_dev_cmd {
+ enum dev_cmd_type type;
+ struct mutex lock;
+ struct completion *complete;
+ wait_queue_head_t tag_wq;
+ struct ufs_query query;
+};
/**
* struct ufs_hba - per adapter private structure
@@ -131,6 +164,7 @@ struct ufshcd_lrb {
* @host: Scsi_Host instance of the driver
* @dev: device handle
* @lrb: local reference block
+ * @lrb_in_use: lrb in use
* @outstanding_tasks: Bits representing outstanding task requests
* @outstanding_reqs: Bits representing outstanding transfer requests
* @capabilities: UFS Controller Capabilities
@@ -144,8 +178,12 @@ struct ufshcd_lrb {
* @tm_condition: condition variable for task management
* @ufshcd_state: UFSHCD states
* @intr_mask: Interrupt Mask Bits
+ * @ee_ctrl_mask: Exception event control mask
* @feh_workq: Work queue for fatal controller error handling
+ * @eeh_work: Worker to handle exception events
* @errors: HBA errors
+ * @dev_cmd: ufs device management command information
+ * @auto_bkops_enabled: to track whether bkops is enabled in device
*/
struct ufs_hba {
void __iomem *mmio_base;
@@ -164,6 +202,7 @@ struct ufs_hba {
struct device *dev;
struct ufshcd_lrb *lrb;
+ unsigned long lrb_in_use;
unsigned long outstanding_tasks;
unsigned long outstanding_reqs;
@@ -182,12 +221,19 @@ struct ufs_hba {
u32 ufshcd_state;
u32 intr_mask;
+ u16 ee_ctrl_mask;
/* Work Queues */
struct work_struct feh_workq;
+ struct work_struct eeh_work;
/* HBA Errors */
u32 errors;
+
+ /* Device management request data */
+ struct ufs_dev_cmd dev_cmd;
+
+ bool auto_bkops_enabled;
};
#define ufshcd_writel(hba, val, reg) \
@@ -208,4 +254,13 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba)
ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
}
+static inline void check_upiu_size(void)
+{
+ BUILD_BUG_ON(ALIGNED_UPIU_SIZE <
+ GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE);
+}
+
+extern int ufshcd_runtime_suspend(struct ufs_hba *hba);
+extern int ufshcd_runtime_resume(struct ufs_hba *hba);
+extern int ufshcd_runtime_idle(struct ufs_hba *hba);
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d5c5f1482d7..f1e1b745910 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -39,7 +39,7 @@
enum {
TASK_REQ_UPIU_SIZE_DWORDS = 8,
TASK_RSP_UPIU_SIZE_DWORDS = 8,
- ALIGNED_UPIU_SIZE = 128,
+ ALIGNED_UPIU_SIZE = 512,
};
/* UFSHCI Registers */
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 2168258fb2c..74b88efde6a 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -751,7 +751,7 @@ static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
vscsi->affinity_hint_set = true;
} else {
- for (i = 0; i < vscsi->num_queues - VIRTIO_SCSI_VQ_BASE; i++)
+ for (i = 0; i < vscsi->num_queues; i++)
virtqueue_set_affinity(vscsi->req_vqs[i].vq, -1);
vscsi->affinity_hint_set = false;
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 89cbbabaff4..0170d4c4a8a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -70,14 +70,14 @@ config SPI_ATH79
config SPI_ATMEL
tristate "Atmel SPI Controller"
- depends on (ARCH_AT91 || AVR32)
+ depends on (ARCH_AT91 || AVR32 || COMPILE_TEST)
help
This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.
config SPI_BCM2835
tristate "BCM2835 SPI controller"
- depends on ARCH_BCM2835
+ depends on ARCH_BCM2835 || COMPILE_TEST
help
This selects a driver for the Broadcom BCM2835 SPI master.
@@ -88,10 +88,17 @@ config SPI_BCM2835
config SPI_BFIN5XX
tristate "SPI controller driver for ADI Blackfin5xx"
- depends on BLACKFIN
+ depends on BLACKFIN && !BF60x
help
This is the SPI controller master driver for Blackfin 5xx processor.
+config SPI_BFIN_V3
+ tristate "SPI controller v3 for Blackfin"
+ depends on BF60x
+ help
+ This is the SPI controller v3 master driver
+ found on Blackfin 60x processor.
+
config SPI_BFIN_SPORT
tristate "SPI bus via Blackfin SPORT"
depends on BLACKFIN
@@ -151,15 +158,22 @@ config SPI_COLDFIRE_QSPI
config SPI_DAVINCI
tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
- depends on ARCH_DAVINCI
+ depends on ARCH_DAVINCI || ARCH_KEYSTONE
select SPI_BITBANG
select TI_EDMA
help
SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
+config SPI_EFM32
+ tristate "EFM32 SPI controller"
+ depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST)
+ select SPI_BITBANG
+ help
+ Driver for the spi controller found on Energy Micro's EFM32 SoCs.
+
config SPI_EP93XX
tristate "Cirrus Logic EP93xx SPI controller"
- depends on ARCH_EP93XX
+ depends on ARCH_EP93XX || COMPILE_TEST
help
This enables using the Cirrus EP93xx SPI controller in master
mode.
@@ -191,7 +205,7 @@ config SPI_GPIO
config SPI_IMX
tristate "Freescale i.MX SPI controllers"
- depends on ARCH_MXC
+ depends on ARCH_MXC || COMPILE_TEST
select SPI_BITBANG
default m if IMX_HAVE_PLATFORM_SPI_IMX
help
@@ -248,6 +262,13 @@ config SPI_FSL_SPI
This also enables using the Aeroflex Gaisler GRLIB SPI controller in
master mode.
+config SPI_FSL_DSPI
+ tristate "Freescale DSPI controller"
+ select SPI_BITBANG
+ help
+ This enables support for the Freescale DSPI controller in master
+ mode. VF610 platform uses the controller.
+
config SPI_FSL_ESPI
bool "Freescale eSPI controller"
depends on FSL_SOC
@@ -280,20 +301,28 @@ config SPI_OMAP_UWIRE
config SPI_OMAP24XX
tristate "McSPI driver for OMAP"
- depends on ARCH_OMAP2PLUS
+ depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
SPI master controller for OMAP24XX and later Multichannel SPI
(McSPI) modules.
+config SPI_TI_QSPI
+ tristate "DRA7xxx QSPI controller support"
+ depends on ARCH_OMAP2PLUS || COMPILE_TEST
+ help
+ QSPI master controller for DRA7xxx used for flash devices.
+ This device supports single, dual and quad read support, while
+ it only supports single write mode.
+
config SPI_OMAP_100K
tristate "OMAP SPI 100K"
- depends on ARCH_OMAP850 || ARCH_OMAP730
+ depends on ARCH_OMAP850 || ARCH_OMAP730 || COMPILE_TEST
help
OMAP SPI 100K master controller for omap7xx boards.
config SPI_ORION
tristate "Orion SPI master"
- depends on PLAT_ORION
+ depends on PLAT_ORION || COMPILE_TEST
help
This enables using the SPI master controller on the Orion chips.
@@ -341,7 +370,7 @@ config SPI_PXA2XX_PCI
config SPI_RSPI
tristate "Renesas RSPI controller"
- depends on SUPERH
+ depends on SUPERH && SH_DMAE_BASE
help
SPI driver for Renesas RSPI blocks.
@@ -385,7 +414,7 @@ config SPI_SH_MSIOF
config SPI_SH
tristate "SuperH SPI controller"
- depends on SUPERH
+ depends on SUPERH || COMPILE_TEST
help
SPI driver for SuperH SPI blocks.
@@ -398,13 +427,13 @@ config SPI_SH_SCI
config SPI_SH_HSPI
tristate "SuperH HSPI controller"
- depends on ARCH_SHMOBILE
+ depends on ARCH_SHMOBILE || COMPILE_TEST
help
SPI driver for SuperH HSPI blocks.
config SPI_SIRF
tristate "CSR SiRFprimaII SPI controller"
- depends on ARCH_SIRF
+ depends on SIRF_DMA
select SPI_BITBANG
help
SPI driver for CSR SiRFprimaII SoCs
@@ -418,7 +447,7 @@ config SPI_MXS
config SPI_TEGRA114
tristate "NVIDIA Tegra114 SPI Controller"
- depends on ARCH_TEGRA && TEGRA20_APB_DMA
+ depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
help
SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller
is different than the older SoCs SPI controller and also register interface
@@ -426,7 +455,7 @@ config SPI_TEGRA114
config SPI_TEGRA20_SFLASH
tristate "Nvidia Tegra20 Serial flash Controller"
- depends on ARCH_TEGRA
+ depends on ARCH_TEGRA || COMPILE_TEST
help
SPI driver for Nvidia Tegra20 Serial flash Controller interface.
The main usecase of this controller is to use spi flash as boot
@@ -434,7 +463,7 @@ config SPI_TEGRA20_SFLASH
config SPI_TEGRA20_SLINK
tristate "Nvidia Tegra20/Tegra30 SLINK Controller"
- depends on ARCH_TEGRA && TEGRA20_APB_DMA
+ depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
help
SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
@@ -457,7 +486,7 @@ config SPI_TOPCLIFF_PCH
config SPI_TXX9
tristate "Toshiba TXx9 SPI controller"
- depends on GPIOLIB && CPU_TX49XX
+ depends on GPIOLIB && (CPU_TX49XX || COMPILE_TEST)
help
SPI driver for Toshiba TXx9 MIPS SoCs
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 33f9c09561e..ab8d8644af0 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
+obj-$(CONFIG_SPI_BFIN_V3) += spi-bfin-v3.o
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
@@ -27,9 +28,11 @@ obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o
spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o
+obj-$(CONFIG_SPI_EFM32) += spi-efm32.o
obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o
+obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o
obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o
obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o
obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o
@@ -46,6 +49,7 @@ obj-$(CONFIG_SPI_OCTEON) += spi-octeon.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o
obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o
obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o
+obj-$(CONFIG_SPI_TI_QSPI) += spi-ti-qspi.o
obj-$(CONFIG_SPI_ORION) += spi-orion.o
obj-$(CONFIG_SPI_PL022) += spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c
index 81b9adb6e76..f38855f7653 100644
--- a/drivers/spi/spi-altera.c
+++ b/drivers/spi/spi-altera.c
@@ -103,16 +103,6 @@ static void altera_spi_chipsel(struct spi_device *spi, int value)
}
}
-static int altera_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
-{
- return 0;
-}
-
-static int altera_spi_setup(struct spi_device *spi)
-{
- return 0;
-}
-
static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
{
if (hw->tx) {
@@ -134,7 +124,7 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
hw->count = 0;
- hw->bytes_per_word = t->bits_per_word / 8;
+ hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8);
hw->len = t->len / hw->bytes_per_word;
if (hw->irq >= 0) {
@@ -150,12 +140,12 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
} else {
- /* send the first byte */
- writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA);
-
- while (1) {
+ while (hw->count < hw->len) {
unsigned int rxd;
+ writel(hw_txbyte(hw, hw->count),
+ hw->base + ALTERA_SPI_TXDATA);
+
while (!(readl(hw->base + ALTERA_SPI_STATUS) &
ALTERA_SPI_STATUS_RRDY_MSK))
cpu_relax();
@@ -174,14 +164,7 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
}
hw->count++;
-
- if (hw->count < hw->len)
- writel(hw_txbyte(hw, hw->count),
- hw->base + ALTERA_SPI_TXDATA);
- else
- break;
}
-
}
return hw->count * hw->bytes_per_word;
@@ -217,7 +200,7 @@ static irqreturn_t altera_spi_irq(int irq, void *dev)
static int altera_spi_probe(struct platform_device *pdev)
{
- struct altera_spi_platform_data *platp = pdev->dev.platform_data;
+ struct altera_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
struct altera_spi *hw;
struct spi_master *master;
struct resource *res;
@@ -231,7 +214,6 @@ static int altera_spi_probe(struct platform_device *pdev)
master->bus_num = pdev->id;
master->num_chipselect = 16;
master->mode_bits = SPI_CS_HIGH;
- master->setup = altera_spi_setup;
hw = spi_master_get_devdata(master);
platform_set_drvdata(pdev, hw);
@@ -240,21 +222,16 @@ static int altera_spi_probe(struct platform_device *pdev)
hw->bitbang.master = spi_master_get(master);
if (!hw->bitbang.master)
return err;
- hw->bitbang.setup_transfer = altera_spi_setupxfer;
hw->bitbang.chipselect = altera_spi_chipsel;
hw->bitbang.txrx_bufs = altera_spi_txrx;
/* find and map our resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- goto exit_busy;
- if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
- pdev->name))
- goto exit_busy;
- hw->base = devm_ioremap_nocache(&pdev->dev, res->start,
- resource_size(res));
- if (!hw->base)
- goto exit_busy;
+ hw->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hw->base)) {
+ err = PTR_ERR(hw->base);
+ goto exit;
+ }
/* program defaults into the registers */
hw->imr = 0; /* disable spi interrupts */
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
@@ -281,9 +258,6 @@ static int altera_spi_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
return 0;
-
-exit_busy:
- err = -EBUSY;
exit:
spi_master_put(master);
return err;
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index 0e06407a467..37bad952ab3 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -221,7 +221,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
sp = spi_master_get_devdata(master);
platform_set_drvdata(pdev, sp);
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
master->setup = ath79_spi_setup;
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index ea1ec009f44..fd7cc566095 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -360,12 +360,12 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
gpio_set_value(asd->npcs_pin, !active);
}
-static void atmel_spi_lock(struct atmel_spi *as)
+static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock)
{
spin_lock_irqsave(&as->lock, as->flags);
}
-static void atmel_spi_unlock(struct atmel_spi *as)
+static void atmel_spi_unlock(struct atmel_spi *as) __releases(&as->lock)
{
spin_unlock_irqrestore(&as->lock, as->flags);
}
@@ -629,9 +629,9 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
goto err_dma;
dev_dbg(master->dev.parent,
- " start dma xfer %p: len %u tx %p/%08x rx %p/%08x\n",
- xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
- xfer->rx_buf, xfer->rx_dma);
+ " start dma xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
+ xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma,
+ xfer->rx_buf, (unsigned long long)xfer->rx_dma);
/* Enable relevant interrupts */
spi_writel(as, IER, SPI_BIT(OVRES));
@@ -732,9 +732,10 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
spi_writel(as, TCR, len);
dev_dbg(&msg->spi->dev,
- " start xfer %p: len %u tx %p/%08x rx %p/%08x\n",
- xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
- xfer->rx_buf, xfer->rx_dma);
+ " start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
+ xfer, xfer->len, xfer->tx_buf,
+ (unsigned long long)xfer->tx_dma, xfer->rx_buf,
+ (unsigned long long)xfer->rx_dma);
} else {
xfer = as->next_transfer;
remaining = as->next_remaining_bytes;
@@ -771,9 +772,10 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
spi_writel(as, TNCR, len);
dev_dbg(&msg->spi->dev,
- " next xfer %p: len %u tx %p/%08x rx %p/%08x\n",
- xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
- xfer->rx_buf, xfer->rx_dma);
+ " next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
+ xfer, xfer->len, xfer->tx_buf,
+ (unsigned long long)xfer->tx_dma, xfer->rx_buf,
+ (unsigned long long)xfer->rx_dma);
ieval = SPI_BIT(ENDRX) | SPI_BIT(OVRES);
} else {
spi_writel(as, RNCR, 0);
@@ -1579,7 +1581,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
goto out_unmap_regs;
/* Initialize the hardware */
- clk_enable(clk);
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ goto out_unmap_regs;
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
if (as->caps.has_wdrbt) {
@@ -1609,7 +1613,7 @@ out_free_dma:
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
- clk_disable(clk);
+ clk_disable_unprepare(clk);
free_irq(irq, master);
out_unmap_regs:
iounmap(as->regs);
@@ -1661,7 +1665,7 @@ static int atmel_spi_remove(struct platform_device *pdev)
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
as->buffer_dma);
- clk_disable(as->clk);
+ clk_disable_unprepare(as->clk);
clk_put(as->clk);
free_irq(as->irq, master);
iounmap(as->regs);
@@ -1678,7 +1682,7 @@ static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg)
struct spi_master *master = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_master_get_devdata(master);
- clk_disable(as->clk);
+ clk_disable_unprepare(as->clk);
return 0;
}
@@ -1687,7 +1691,7 @@ static int atmel_spi_resume(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_master_get_devdata(master);
- clk_enable(as->clk);
+ return clk_prepare_enable(as->clk);
return 0;
}
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index e1965553ab7..1d00d9b397d 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -776,7 +776,7 @@ static int au1550_spi_probe(struct platform_device *pdev)
hw = spi_master_get_devdata(master);
hw->master = spi_master_get(master);
- hw->pdata = pdev->dev.platform_data;
+ hw->pdata = dev_get_platdata(&pdev->dev);
hw->dev = &pdev->dev;
if (hw->pdata == NULL) {
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index a4185e49232..52c81481c5c 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -314,7 +314,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
master->mode_bits = BCM2835_SPI_MODE_BITS;
- master->bits_per_word_mask = BIT(8 - 1);
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
master->bus_num = -1;
master->num_chipselect = 3;
master->transfer_one_message = bcm2835_spi_transfer_one;
@@ -325,12 +325,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
init_completion(&bs->done);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "could not get memory resource\n");
- err = -ENODEV;
- goto out_master_put;
- }
-
bs->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(bs->regs)) {
err = PTR_ERR(bs->regs);
@@ -383,7 +377,7 @@ out_master_put:
static int bcm2835_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
struct bcm2835_spi *bs = spi_master_get_devdata(master);
free_irq(bs->irq, master);
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 9fd7a39b802..536b0e36382 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -231,24 +231,6 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
return 0;
}
-static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
-{
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
-
- pm_runtime_get_sync(&bs->pdev->dev);
-
- return 0;
-}
-
-static int bcm63xx_spi_unprepare_transfer(struct spi_master *master)
-{
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
-
- pm_runtime_put(&bs->pdev->dev);
-
- return 0;
-}
-
static int bcm63xx_spi_transfer_one(struct spi_master *master,
struct spi_message *m)
{
@@ -353,20 +335,13 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
{
struct resource *r;
struct device *dev = &pdev->dev;
- struct bcm63xx_spi_pdata *pdata = pdev->dev.platform_data;
+ struct bcm63xx_spi_pdata *pdata = dev_get_platdata(&pdev->dev);
int irq;
struct spi_master *master;
struct clk *clk;
struct bcm63xx_spi *bs;
int ret;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(dev, "no iomem\n");
- ret = -ENXIO;
- goto out;
- }
-
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "no irq\n");
@@ -393,6 +368,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
bs->pdev = pdev;
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bs->regs = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(bs->regs)) {
ret = PTR_ERR(bs->regs);
@@ -412,11 +388,10 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->num_chipselect;
- master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer;
- master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer;
master->transfer_one_message = bcm63xx_spi_transfer_one;
master->mode_bits = MODEBITS;
master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->auto_runtime_pm = true;
bs->msg_type_shift = pdata->msg_type_shift;
bs->msg_ctl_width = pdata->msg_ctl_width;
bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
@@ -480,8 +455,7 @@ static int bcm63xx_spi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int bcm63xx_spi_suspend(struct device *dev)
{
- struct spi_master *master =
- platform_get_drvdata(to_platform_device(dev));
+ struct spi_master *master = dev_get_drvdata(dev);
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
spi_master_suspend(master);
@@ -493,8 +467,7 @@ static int bcm63xx_spi_suspend(struct device *dev)
static int bcm63xx_spi_resume(struct device *dev)
{
- struct spi_master *master =
- platform_get_drvdata(to_platform_device(dev));
+ struct spi_master *master = dev_get_drvdata(dev);
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
clk_prepare_enable(bs->clk);
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c
index 07ec597f973..91921b5f581 100644
--- a/drivers/spi/spi-bfin-sport.c
+++ b/drivers/spi/spi-bfin-sport.c
@@ -756,7 +756,7 @@ static int bfin_sport_spi_probe(struct platform_device *pdev)
struct bfin_sport_spi_master_data *drv_data;
int status;
- platform_info = dev->platform_data;
+ platform_info = dev_get_platdata(dev);
/* Allocate master with space for drv_data */
master = spi_alloc_master(dev, sizeof(*master) + 16);
diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c
new file mode 100644
index 00000000000..f4bf81347d6
--- /dev/null
+++ b/drivers/spi/spi-bfin-v3.c
@@ -0,0 +1,965 @@
+/*
+ * Analog Devices SPI3 controller driver
+ *
+ * Copyright (c) 2013 Analog Devices Inc.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+
+#include <asm/bfin_spi3.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+enum bfin_spi_state {
+ START_STATE,
+ RUNNING_STATE,
+ DONE_STATE,
+ ERROR_STATE
+};
+
+struct bfin_spi_master;
+
+struct bfin_spi_transfer_ops {
+ void (*write) (struct bfin_spi_master *);
+ void (*read) (struct bfin_spi_master *);
+ void (*duplex) (struct bfin_spi_master *);
+};
+
+/* runtime info for spi master */
+struct bfin_spi_master {
+ /* SPI framework hookup */
+ struct spi_master *master;
+
+ /* Regs base of SPI controller */
+ struct bfin_spi_regs __iomem *regs;
+
+ /* Pin request list */
+ u16 *pin_req;
+
+ /* Message Transfer pump */
+ struct tasklet_struct pump_transfers;
+
+ /* Current message transfer state info */
+ struct spi_message *cur_msg;
+ struct spi_transfer *cur_transfer;
+ struct bfin_spi_device *cur_chip;
+ unsigned transfer_len;
+
+ /* transfer buffer */
+ void *tx;
+ void *tx_end;
+ void *rx;
+ void *rx_end;
+
+ /* dma info */
+ unsigned int tx_dma;
+ unsigned int rx_dma;
+ dma_addr_t tx_dma_addr;
+ dma_addr_t rx_dma_addr;
+ unsigned long dummy_buffer; /* used in unidirectional transfer */
+ unsigned long tx_dma_size;
+ unsigned long rx_dma_size;
+ int tx_num;
+ int rx_num;
+
+ /* store register value for suspend/resume */
+ u32 control;
+ u32 ssel;
+
+ unsigned long sclk;
+ enum bfin_spi_state state;
+
+ const struct bfin_spi_transfer_ops *ops;
+};
+
+struct bfin_spi_device {
+ u32 control;
+ u32 clock;
+ u32 ssel;
+
+ u8 cs;
+ u16 cs_chg_udelay; /* Some devices require > 255usec delay */
+ u32 cs_gpio;
+ u32 tx_dummy_val; /* tx value for rx only transfer */
+ bool enable_dma;
+ const struct bfin_spi_transfer_ops *ops;
+};
+
+static void bfin_spi_enable(struct bfin_spi_master *drv_data)
+{
+ bfin_write_or(&drv_data->regs->control, SPI_CTL_EN);
+}
+
+static void bfin_spi_disable(struct bfin_spi_master *drv_data)
+{
+ bfin_write_and(&drv_data->regs->control, ~SPI_CTL_EN);
+}
+
+/* Caculate the SPI_CLOCK register value based on input HZ */
+static u32 hz_to_spi_clock(u32 sclk, u32 speed_hz)
+{
+ u32 spi_clock = sclk / speed_hz;
+
+ if (spi_clock)
+ spi_clock--;
+ return spi_clock;
+}
+
+static int bfin_spi_flush(struct bfin_spi_master *drv_data)
+{
+ unsigned long limit = loops_per_jiffy << 1;
+
+ /* wait for stop and clear stat */
+ while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_SPIF) && --limit)
+ cpu_relax();
+
+ bfin_write(&drv_data->regs->status, 0xFFFFFFFF);
+
+ return limit;
+}
+
+/* Chip select operation functions for cs_change flag */
+static void bfin_spi_cs_active(struct bfin_spi_master *drv_data, struct bfin_spi_device *chip)
+{
+ if (likely(chip->cs < MAX_CTRL_CS))
+ bfin_write_and(&drv_data->regs->ssel, ~chip->ssel);
+ else
+ gpio_set_value(chip->cs_gpio, 0);
+}
+
+static void bfin_spi_cs_deactive(struct bfin_spi_master *drv_data,
+ struct bfin_spi_device *chip)
+{
+ if (likely(chip->cs < MAX_CTRL_CS))
+ bfin_write_or(&drv_data->regs->ssel, chip->ssel);
+ else
+ gpio_set_value(chip->cs_gpio, 1);
+
+ /* Move delay here for consistency */
+ if (chip->cs_chg_udelay)
+ udelay(chip->cs_chg_udelay);
+}
+
+/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */
+static inline void bfin_spi_cs_enable(struct bfin_spi_master *drv_data,
+ struct bfin_spi_device *chip)
+{
+ if (chip->cs < MAX_CTRL_CS)
+ bfin_write_or(&drv_data->regs->ssel, chip->ssel >> 8);
+}
+
+static inline void bfin_spi_cs_disable(struct bfin_spi_master *drv_data,
+ struct bfin_spi_device *chip)
+{
+ if (chip->cs < MAX_CTRL_CS)
+ bfin_write_and(&drv_data->regs->ssel, ~(chip->ssel >> 8));
+}
+
+/* stop controller and re-config current chip*/
+static void bfin_spi_restore_state(struct bfin_spi_master *drv_data)
+{
+ struct bfin_spi_device *chip = drv_data->cur_chip;
+
+ /* Clear status and disable clock */
+ bfin_write(&drv_data->regs->status, 0xFFFFFFFF);
+ bfin_write(&drv_data->regs->rx_control, 0x0);
+ bfin_write(&drv_data->regs->tx_control, 0x0);
+ bfin_spi_disable(drv_data);
+
+ SSYNC();
+
+ /* Load the registers */
+ bfin_write(&drv_data->regs->control, chip->control);
+ bfin_write(&drv_data->regs->clock, chip->clock);
+
+ bfin_spi_enable(drv_data);
+ drv_data->tx_num = drv_data->rx_num = 0;
+ /* we always choose tx transfer initiate */
+ bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN);
+ bfin_write(&drv_data->regs->tx_control,
+ SPI_TXCTL_TEN | SPI_TXCTL_TTI);
+ bfin_spi_cs_active(drv_data, chip);
+}
+
+/* discard invalid rx data and empty rfifo */
+static inline void dummy_read(struct bfin_spi_master *drv_data)
+{
+ while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_RFE))
+ bfin_read(&drv_data->regs->rfifo);
+}
+
+static void bfin_spi_u8_write(struct bfin_spi_master *drv_data)
+{
+ dummy_read(drv_data);
+ while (drv_data->tx < drv_data->tx_end) {
+ bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++)));
+ while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+ cpu_relax();
+ bfin_read(&drv_data->regs->rfifo);
+ }
+}
+
+static void bfin_spi_u8_read(struct bfin_spi_master *drv_data)
+{
+ u32 tx_val = drv_data->cur_chip->tx_dummy_val;
+
+ dummy_read(drv_data);
+ while (drv_data->rx < drv_data->rx_end) {
+ bfin_write(&drv_data->regs->tfifo, tx_val);
+ while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+ cpu_relax();
+ *(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo);
+ }
+}
+
+static void bfin_spi_u8_duplex(struct bfin_spi_master *drv_data)
+{
+ dummy_read(drv_data);
+ while (drv_data->rx < drv_data->rx_end) {
+ bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++)));
+ while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+ cpu_relax();
+ *(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo);
+ }
+}
+
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = {
+ .write = bfin_spi_u8_write,
+ .read = bfin_spi_u8_read,
+ .duplex = bfin_spi_u8_duplex,
+};
+
+static void bfin_spi_u16_write(struct bfin_spi_master *drv_data)
+{
+ dummy_read(drv_data);
+ while (drv_data->tx < drv_data->tx_end) {
+ bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx));
+ drv_data->tx += 2;
+ while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+ cpu_relax();
+ bfin_read(&drv_data->regs->rfifo);
+ }
+}
+
+static void bfin_spi_u16_read(struct bfin_spi_master *drv_data)
+{
+ u32 tx_val = drv_data->cur_chip->tx_dummy_val;
+
+ dummy_read(drv_data);
+ while (drv_data->rx < drv_data->rx_end) {
+ bfin_write(&drv_data->regs->tfifo, tx_val);
+ while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+ cpu_relax();
+ *(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+ drv_data->rx += 2;
+ }
+}
+
+static void bfin_spi_u16_duplex(struct bfin_spi_master *drv_data)
+{
+ dummy_read(drv_data);
+ while (drv_data->rx < drv_data->rx_end) {
+ bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx));
+ drv_data->tx += 2;
+ while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+ cpu_relax();
+ *(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+ drv_data->rx += 2;
+ }
+}
+
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = {
+ .write = bfin_spi_u16_write,
+ .read = bfin_spi_u16_read,
+ .duplex = bfin_spi_u16_duplex,
+};
+
+static void bfin_spi_u32_write(struct bfin_spi_master *drv_data)
+{
+ dummy_read(drv_data);
+ while (drv_data->tx < drv_data->tx_end) {
+ bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx));
+ drv_data->tx += 4;
+ while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+ cpu_relax();
+ bfin_read(&drv_data->regs->rfifo);
+ }
+}
+
+static void bfin_spi_u32_read(struct bfin_spi_master *drv_data)
+{
+ u32 tx_val = drv_data->cur_chip->tx_dummy_val;
+
+ dummy_read(drv_data);
+ while (drv_data->rx < drv_data->rx_end) {
+ bfin_write(&drv_data->regs->tfifo, tx_val);
+ while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+ cpu_relax();
+ *(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+ drv_data->rx += 4;
+ }
+}
+
+static void bfin_spi_u32_duplex(struct bfin_spi_master *drv_data)
+{
+ dummy_read(drv_data);
+ while (drv_data->rx < drv_data->rx_end) {
+ bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx));
+ drv_data->tx += 4;
+ while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+ cpu_relax();
+ *(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+ drv_data->rx += 4;
+ }
+}
+
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u32 = {
+ .write = bfin_spi_u32_write,
+ .read = bfin_spi_u32_read,
+ .duplex = bfin_spi_u32_duplex,
+};
+
+
+/* test if there is more transfer to be done */
+static void bfin_spi_next_transfer(struct bfin_spi_master *drv)
+{
+ struct spi_message *msg = drv->cur_msg;
+ struct spi_transfer *t = drv->cur_transfer;
+
+ /* Move to next transfer */
+ if (t->transfer_list.next != &msg->transfers) {
+ drv->cur_transfer = list_entry(t->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ drv->state = RUNNING_STATE;
+ } else {
+ drv->state = DONE_STATE;
+ drv->cur_transfer = NULL;
+ }
+}
+
+static void bfin_spi_giveback(struct bfin_spi_master *drv_data)
+{
+ struct bfin_spi_device *chip = drv_data->cur_chip;
+
+ bfin_spi_cs_deactive(drv_data, chip);
+ spi_finalize_current_message(drv_data->master);
+}
+
+static int bfin_spi_setup_transfer(struct bfin_spi_master *drv)
+{
+ struct spi_transfer *t = drv->cur_transfer;
+ u32 cr, cr_width;
+
+ if (t->tx_buf) {
+ drv->tx = (void *)t->tx_buf;
+ drv->tx_end = drv->tx + t->len;
+ } else {
+ drv->tx = NULL;
+ }
+
+ if (t->rx_buf) {
+ drv->rx = t->rx_buf;
+ drv->rx_end = drv->rx + t->len;
+ } else {
+ drv->rx = NULL;
+ }
+
+ drv->transfer_len = t->len;
+
+ /* bits per word setup */
+ switch (t->bits_per_word) {
+ case 8:
+ cr_width = SPI_CTL_SIZE08;
+ drv->ops = &bfin_bfin_spi_transfer_ops_u8;
+ break;
+ case 16:
+ cr_width = SPI_CTL_SIZE16;
+ drv->ops = &bfin_bfin_spi_transfer_ops_u16;
+ break;
+ case 32:
+ cr_width = SPI_CTL_SIZE32;
+ drv->ops = &bfin_bfin_spi_transfer_ops_u32;
+ break;
+ default:
+ return -EINVAL;
+ }
+ cr = bfin_read(&drv->regs->control) & ~SPI_CTL_SIZE;
+ cr |= cr_width;
+ bfin_write(&drv->regs->control, cr);
+
+ /* speed setup */
+ bfin_write(&drv->regs->clock,
+ hz_to_spi_clock(drv->sclk, t->speed_hz));
+ return 0;
+}
+
+static int bfin_spi_dma_xfer(struct bfin_spi_master *drv_data)
+{
+ struct spi_transfer *t = drv_data->cur_transfer;
+ struct spi_message *msg = drv_data->cur_msg;
+ struct bfin_spi_device *chip = drv_data->cur_chip;
+ u32 dma_config;
+ unsigned long word_count, word_size;
+ void *tx_buf, *rx_buf;
+
+ switch (t->bits_per_word) {
+ case 8:
+ dma_config = WDSIZE_8 | PSIZE_8;
+ word_count = drv_data->transfer_len;
+ word_size = 1;
+ break;
+ case 16:
+ dma_config = WDSIZE_16 | PSIZE_16;
+ word_count = drv_data->transfer_len / 2;
+ word_size = 2;
+ break;
+ default:
+ dma_config = WDSIZE_32 | PSIZE_32;
+ word_count = drv_data->transfer_len / 4;
+ word_size = 4;
+ break;
+ }
+
+ if (!drv_data->rx) {
+ tx_buf = drv_data->tx;
+ rx_buf = &drv_data->dummy_buffer;
+ drv_data->tx_dma_size = drv_data->transfer_len;
+ drv_data->rx_dma_size = sizeof(drv_data->dummy_buffer);
+ set_dma_x_modify(drv_data->tx_dma, word_size);
+ set_dma_x_modify(drv_data->rx_dma, 0);
+ } else if (!drv_data->tx) {
+ drv_data->dummy_buffer = chip->tx_dummy_val;
+ tx_buf = &drv_data->dummy_buffer;
+ rx_buf = drv_data->rx;
+ drv_data->tx_dma_size = sizeof(drv_data->dummy_buffer);
+ drv_data->rx_dma_size = drv_data->transfer_len;
+ set_dma_x_modify(drv_data->tx_dma, 0);
+ set_dma_x_modify(drv_data->rx_dma, word_size);
+ } else {
+ tx_buf = drv_data->tx;
+ rx_buf = drv_data->rx;
+ drv_data->tx_dma_size = drv_data->rx_dma_size
+ = drv_data->transfer_len;
+ set_dma_x_modify(drv_data->tx_dma, word_size);
+ set_dma_x_modify(drv_data->rx_dma, word_size);
+ }
+
+ drv_data->tx_dma_addr = dma_map_single(&msg->spi->dev,
+ (void *)tx_buf,
+ drv_data->tx_dma_size,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&msg->spi->dev,
+ drv_data->tx_dma_addr))
+ return -ENOMEM;
+
+ drv_data->rx_dma_addr = dma_map_single(&msg->spi->dev,
+ (void *)rx_buf,
+ drv_data->rx_dma_size,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&msg->spi->dev,
+ drv_data->rx_dma_addr)) {
+ dma_unmap_single(&msg->spi->dev,
+ drv_data->tx_dma_addr,
+ drv_data->tx_dma_size,
+ DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+
+ dummy_read(drv_data);
+ set_dma_x_count(drv_data->tx_dma, word_count);
+ set_dma_x_count(drv_data->rx_dma, word_count);
+ set_dma_start_addr(drv_data->tx_dma, drv_data->tx_dma_addr);
+ set_dma_start_addr(drv_data->rx_dma, drv_data->rx_dma_addr);
+ dma_config |= DMAFLOW_STOP | RESTART | DI_EN;
+ set_dma_config(drv_data->tx_dma, dma_config);
+ set_dma_config(drv_data->rx_dma, dma_config | WNR);
+ enable_dma(drv_data->tx_dma);
+ enable_dma(drv_data->rx_dma);
+ SSYNC();
+
+ bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN | SPI_RXCTL_RDR_NE);
+ SSYNC();
+ bfin_write(&drv_data->regs->tx_control,
+ SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF);
+
+ return 0;
+}
+
+static int bfin_spi_pio_xfer(struct bfin_spi_master *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+
+ if (!drv_data->rx) {
+ /* write only half duplex */
+ drv_data->ops->write(drv_data);
+ if (drv_data->tx != drv_data->tx_end)
+ return -EIO;
+ } else if (!drv_data->tx) {
+ /* read only half duplex */
+ drv_data->ops->read(drv_data);
+ if (drv_data->rx != drv_data->rx_end)
+ return -EIO;
+ } else {
+ /* full duplex mode */
+ drv_data->ops->duplex(drv_data);
+ if (drv_data->tx != drv_data->tx_end)
+ return -EIO;
+ }
+
+ if (!bfin_spi_flush(drv_data))
+ return -EIO;
+ msg->actual_length += drv_data->transfer_len;
+ tasklet_schedule(&drv_data->pump_transfers);
+ return 0;
+}
+
+static void bfin_spi_pump_transfers(unsigned long data)
+{
+ struct bfin_spi_master *drv_data = (struct bfin_spi_master *)data;
+ struct spi_message *msg = NULL;
+ struct spi_transfer *t = NULL;
+ struct bfin_spi_device *chip = NULL;
+ int ret;
+
+ /* Get current state information */
+ msg = drv_data->cur_msg;
+ t = drv_data->cur_transfer;
+ chip = drv_data->cur_chip;
+
+ /* Handle for abort */
+ if (drv_data->state == ERROR_STATE) {
+ msg->status = -EIO;
+ bfin_spi_giveback(drv_data);
+ return;
+ }
+
+ if (drv_data->state == RUNNING_STATE) {
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+ if (t->cs_change)
+ bfin_spi_cs_deactive(drv_data, chip);
+ bfin_spi_next_transfer(drv_data);
+ t = drv_data->cur_transfer;
+ }
+ /* Handle end of message */
+ if (drv_data->state == DONE_STATE) {
+ msg->status = 0;
+ bfin_spi_giveback(drv_data);
+ return;
+ }
+
+ if ((t->len == 0) || (t->tx_buf == NULL && t->rx_buf == NULL)) {
+ /* Schedule next transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+ return;
+ }
+
+ ret = bfin_spi_setup_transfer(drv_data);
+ if (ret) {
+ msg->status = ret;
+ bfin_spi_giveback(drv_data);
+ }
+
+ bfin_write(&drv_data->regs->status, 0xFFFFFFFF);
+ bfin_spi_cs_active(drv_data, chip);
+ drv_data->state = RUNNING_STATE;
+
+ if (chip->enable_dma)
+ ret = bfin_spi_dma_xfer(drv_data);
+ else
+ ret = bfin_spi_pio_xfer(drv_data);
+ if (ret) {
+ msg->status = ret;
+ bfin_spi_giveback(drv_data);
+ }
+}
+
+static int bfin_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+
+ drv_data->cur_msg = m;
+ drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+ bfin_spi_restore_state(drv_data);
+
+ drv_data->state = START_STATE;
+ drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+ struct spi_transfer, transfer_list);
+
+ tasklet_schedule(&drv_data->pump_transfers);
+ return 0;
+}
+
+#define MAX_SPI_SSEL 7
+
+static const u16 ssel[][MAX_SPI_SSEL] = {
+ {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
+ P_SPI0_SSEL4, P_SPI0_SSEL5,
+ P_SPI0_SSEL6, P_SPI0_SSEL7},
+
+ {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
+ P_SPI1_SSEL4, P_SPI1_SSEL5,
+ P_SPI1_SSEL6, P_SPI1_SSEL7},
+
+ {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
+ P_SPI2_SSEL4, P_SPI2_SSEL5,
+ P_SPI2_SSEL6, P_SPI2_SSEL7},
+};
+
+static int bfin_spi_setup(struct spi_device *spi)
+{
+ struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master);
+ struct bfin_spi_device *chip = spi_get_ctldata(spi);
+ u32 bfin_ctl_reg = SPI_CTL_ODM | SPI_CTL_PSSE;
+ int ret = -EINVAL;
+
+ if (!chip) {
+ struct bfin_spi3_chip *chip_info = spi->controller_data;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip) {
+ dev_err(&spi->dev, "can not allocate chip data\n");
+ return -ENOMEM;
+ }
+ if (chip_info) {
+ if (chip_info->control & ~bfin_ctl_reg) {
+ dev_err(&spi->dev,
+ "do not set bits that the SPI framework manages\n");
+ goto error;
+ }
+ chip->control = chip_info->control;
+ chip->cs_chg_udelay = chip_info->cs_chg_udelay;
+ chip->tx_dummy_val = chip_info->tx_dummy_val;
+ chip->enable_dma = chip_info->enable_dma;
+ }
+ chip->cs = spi->chip_select;
+ if (chip->cs < MAX_CTRL_CS) {
+ chip->ssel = (1 << chip->cs) << 8;
+ ret = peripheral_request(ssel[spi->master->bus_num]
+ [chip->cs-1], dev_name(&spi->dev));
+ if (ret) {
+ dev_err(&spi->dev, "peripheral_request() error\n");
+ goto error;
+ }
+ } else {
+ chip->cs_gpio = chip->cs - MAX_CTRL_CS;
+ ret = gpio_request_one(chip->cs_gpio, GPIOF_OUT_INIT_HIGH,
+ dev_name(&spi->dev));
+ if (ret) {
+ dev_err(&spi->dev, "gpio_request_one() error\n");
+ goto error;
+ }
+ }
+ spi_set_ctldata(spi, chip);
+ }
+
+ /* force a default base state */
+ chip->control &= bfin_ctl_reg;
+
+ if (spi->mode & SPI_CPOL)
+ chip->control |= SPI_CTL_CPOL;
+ if (spi->mode & SPI_CPHA)
+ chip->control |= SPI_CTL_CPHA;
+ if (spi->mode & SPI_LSB_FIRST)
+ chip->control |= SPI_CTL_LSBF;
+ chip->control |= SPI_CTL_MSTR;
+ /* we choose software to controll cs */
+ chip->control &= ~SPI_CTL_ASSEL;
+
+ chip->clock = hz_to_spi_clock(drv_data->sclk, spi->max_speed_hz);
+
+ bfin_spi_cs_enable(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
+
+ return 0;
+error:
+ if (chip) {
+ kfree(chip);
+ spi_set_ctldata(spi, NULL);
+ }
+
+ return ret;
+}
+
+static void bfin_spi_cleanup(struct spi_device *spi)
+{
+ struct bfin_spi_device *chip = spi_get_ctldata(spi);
+ struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master);
+
+ if (!chip)
+ return;
+
+ if (chip->cs < MAX_CTRL_CS) {
+ peripheral_free(ssel[spi->master->bus_num]
+ [chip->cs-1]);
+ bfin_spi_cs_disable(drv_data, chip);
+ } else {
+ gpio_free(chip->cs_gpio);
+ }
+
+ kfree(chip);
+ spi_set_ctldata(spi, NULL);
+}
+
+static irqreturn_t bfin_spi_tx_dma_isr(int irq, void *dev_id)
+{
+ struct bfin_spi_master *drv_data = dev_id;
+ u32 dma_stat = get_dma_curr_irqstat(drv_data->tx_dma);
+
+ clear_dma_irqstat(drv_data->tx_dma);
+ if (dma_stat & DMA_DONE) {
+ drv_data->tx_num++;
+ } else {
+ dev_err(&drv_data->master->dev,
+ "spi tx dma error: %d\n", dma_stat);
+ if (drv_data->tx)
+ drv_data->state = ERROR_STATE;
+ }
+ bfin_write_and(&drv_data->regs->tx_control, ~SPI_TXCTL_TDR_NF);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bfin_spi_rx_dma_isr(int irq, void *dev_id)
+{
+ struct bfin_spi_master *drv_data = dev_id;
+ struct spi_message *msg = drv_data->cur_msg;
+ u32 dma_stat = get_dma_curr_irqstat(drv_data->rx_dma);
+
+ clear_dma_irqstat(drv_data->rx_dma);
+ if (dma_stat & DMA_DONE) {
+ drv_data->rx_num++;
+ /* we may fail on tx dma */
+ if (drv_data->state != ERROR_STATE)
+ msg->actual_length += drv_data->transfer_len;
+ } else {
+ drv_data->state = ERROR_STATE;
+ dev_err(&drv_data->master->dev,
+ "spi rx dma error: %d\n", dma_stat);
+ }
+ bfin_write(&drv_data->regs->tx_control, 0);
+ bfin_write(&drv_data->regs->rx_control, 0);
+ if (drv_data->rx_num != drv_data->tx_num)
+ dev_dbg(&drv_data->master->dev,
+ "dma interrupt missing: tx=%d,rx=%d\n",
+ drv_data->tx_num, drv_data->rx_num);
+ tasklet_schedule(&drv_data->pump_transfers);
+ return IRQ_HANDLED;
+}
+
+static int bfin_spi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct bfin_spi3_master *info = dev_get_platdata(dev);
+ struct spi_master *master;
+ struct bfin_spi_master *drv_data;
+ struct resource *mem, *res;
+ unsigned int tx_dma, rx_dma;
+ unsigned long sclk;
+ int ret;
+
+ if (!info) {
+ dev_err(dev, "platform data missing!\n");
+ return -ENODEV;
+ }
+
+ sclk = get_sclk1();
+ if (!sclk) {
+ dev_err(dev, "can not get sclk1\n");
+ return -ENXIO;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(dev, "can not get tx dma resource\n");
+ return -ENXIO;
+ }
+ tx_dma = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(dev, "can not get rx dma resource\n");
+ return -ENXIO;
+ }
+ rx_dma = res->start;
+
+ /* allocate master with space for drv_data */
+ master = spi_alloc_master(dev, sizeof(*drv_data));
+ if (!master) {
+ dev_err(dev, "can not alloc spi_master\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, master);
+
+ /* the mode bits supported by this driver */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = info->num_chipselect;
+ master->cleanup = bfin_spi_cleanup;
+ master->setup = bfin_spi_setup;
+ master->transfer_one_message = bfin_spi_transfer_one_message;
+ master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
+
+ drv_data = spi_master_get_devdata(master);
+ drv_data->master = master;
+ drv_data->tx_dma = tx_dma;
+ drv_data->rx_dma = rx_dma;
+ drv_data->pin_req = info->pin_req;
+ drv_data->sclk = sclk;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ drv_data->regs = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(drv_data->regs)) {
+ ret = PTR_ERR(drv_data->regs);
+ goto err_put_master;
+ }
+
+ /* request tx and rx dma */
+ ret = request_dma(tx_dma, "SPI_TX_DMA");
+ if (ret) {
+ dev_err(dev, "can not request SPI TX DMA channel\n");
+ goto err_put_master;
+ }
+ set_dma_callback(tx_dma, bfin_spi_tx_dma_isr, drv_data);
+
+ ret = request_dma(rx_dma, "SPI_RX_DMA");
+ if (ret) {
+ dev_err(dev, "can not request SPI RX DMA channel\n");
+ goto err_free_tx_dma;
+ }
+ set_dma_callback(drv_data->rx_dma, bfin_spi_rx_dma_isr, drv_data);
+
+ /* request CLK, MOSI and MISO */
+ ret = peripheral_request_list(drv_data->pin_req, "bfin-spi3");
+ if (ret < 0) {
+ dev_err(dev, "can not request spi pins\n");
+ goto err_free_rx_dma;
+ }
+
+ bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA);
+ bfin_write(&drv_data->regs->ssel, 0x0000FE00);
+ bfin_write(&drv_data->regs->delay, 0x0);
+
+ tasklet_init(&drv_data->pump_transfers,
+ bfin_spi_pump_transfers, (unsigned long)drv_data);
+ /* register with the SPI framework */
+ ret = spi_register_master(master);
+ if (ret) {
+ dev_err(dev, "can not register spi master\n");
+ goto err_free_peripheral;
+ }
+
+ return ret;
+
+err_free_peripheral:
+ peripheral_free_list(drv_data->pin_req);
+err_free_rx_dma:
+ free_dma(rx_dma);
+err_free_tx_dma:
+ free_dma(tx_dma);
+err_put_master:
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int bfin_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+
+ bfin_spi_disable(drv_data);
+
+ peripheral_free_list(drv_data->pin_req);
+ free_dma(drv_data->rx_dma);
+ free_dma(drv_data->tx_dma);
+
+ spi_unregister_master(drv_data->master);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_spi_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+
+ spi_master_suspend(master);
+
+ drv_data->control = bfin_read(&drv_data->regs->control);
+ drv_data->ssel = bfin_read(&drv_data->regs->ssel);
+
+ bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA);
+ bfin_write(&drv_data->regs->ssel, 0x0000FE00);
+ dma_disable_irq(drv_data->rx_dma);
+ dma_disable_irq(drv_data->tx_dma);
+
+ return 0;
+}
+
+static int bfin_spi_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+ int ret = 0;
+
+ /* bootrom may modify spi and dma status when resume in spi boot mode */
+ disable_dma(drv_data->rx_dma);
+
+ dma_enable_irq(drv_data->rx_dma);
+ dma_enable_irq(drv_data->tx_dma);
+ bfin_write(&drv_data->regs->control, drv_data->control);
+ bfin_write(&drv_data->regs->ssel, drv_data->ssel);
+
+ ret = spi_master_resume(master);
+ if (ret) {
+ free_dma(drv_data->rx_dma);
+ free_dma(drv_data->tx_dma);
+ }
+
+ return ret;
+}
+#endif
+static const struct dev_pm_ops bfin_spi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(bfin_spi_suspend, bfin_spi_resume)
+};
+
+MODULE_ALIAS("platform:bfin-spi3");
+static struct platform_driver bfin_spi_driver = {
+ .driver = {
+ .name = "bfin-spi3",
+ .owner = THIS_MODULE,
+ .pm = &bfin_spi_pm_ops,
+ },
+ .remove = bfin_spi_remove,
+};
+
+module_platform_driver_probe(bfin_spi_driver, bfin_spi_probe);
+
+MODULE_DESCRIPTION("Analog Devices SPI3 controller driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c
index 59a73424419..45bdf73d686 100644
--- a/drivers/spi/spi-bfin5xx.c
+++ b/drivers/spi/spi-bfin5xx.c
@@ -1271,7 +1271,7 @@ static int bfin_spi_probe(struct platform_device *pdev)
struct resource *res;
int status = 0;
- platform_info = dev->platform_data;
+ platform_info = dev_get_platdata(dev);
/* Allocate master with space for drv_data */
master = spi_alloc_master(dev, sizeof(*drv_data));
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index a63d7da3bfe..e3946e44e07 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -255,150 +255,140 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
* Drivers can provide word-at-a-time i/o primitives, or provide
* transfer-at-a-time ones to leverage dma or fifo hardware.
*/
-static void bitbang_work(struct work_struct *work)
+
+static int spi_bitbang_prepare_hardware(struct spi_master *spi)
{
- struct spi_bitbang *bitbang =
- container_of(work, struct spi_bitbang, work);
+ struct spi_bitbang *bitbang;
unsigned long flags;
- struct spi_message *m, *_m;
+
+ bitbang = spi_master_get_devdata(spi);
spin_lock_irqsave(&bitbang->lock, flags);
bitbang->busy = 1;
- list_for_each_entry_safe(m, _m, &bitbang->queue, queue) {
- struct spi_device *spi;
- unsigned nsecs;
- struct spi_transfer *t = NULL;
- unsigned tmp;
- unsigned cs_change;
- int status;
- int do_setup = -1;
-
- list_del(&m->queue);
- spin_unlock_irqrestore(&bitbang->lock, flags);
-
- /* FIXME this is made-up ... the correct value is known to
- * word-at-a-time bitbang code, and presumably chipselect()
- * should enforce these requirements too?
- */
- nsecs = 100;
+ spin_unlock_irqrestore(&bitbang->lock, flags);
- spi = m->spi;
- tmp = 0;
- cs_change = 1;
- status = 0;
+ return 0;
+}
- list_for_each_entry (t, &m->transfers, transfer_list) {
-
- /* override speed or wordsize? */
- if (t->speed_hz || t->bits_per_word)
- do_setup = 1;
-
- /* init (-1) or override (1) transfer params */
- if (do_setup != 0) {
- status = bitbang->setup_transfer(spi, t);
- if (status < 0)
- break;
- if (do_setup == -1)
- do_setup = 0;
- }
-
- /* set up default clock polarity, and activate chip;
- * this implicitly updates clock and spi modes as
- * previously recorded for this device via setup().
- * (and also deselects any other chip that might be
- * selected ...)
- */
- if (cs_change) {
- bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
- ndelay(nsecs);
- }
- cs_change = t->cs_change;
- if (!t->tx_buf && !t->rx_buf && t->len) {
- status = -EINVAL;
- break;
- }
+static int spi_bitbang_transfer_one(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct spi_bitbang *bitbang;
+ unsigned nsecs;
+ struct spi_transfer *t = NULL;
+ unsigned cs_change;
+ int status;
+ int do_setup = -1;
+ struct spi_device *spi = m->spi;
+
+ bitbang = spi_master_get_devdata(master);
+
+ /* FIXME this is made-up ... the correct value is known to
+ * word-at-a-time bitbang code, and presumably chipselect()
+ * should enforce these requirements too?
+ */
+ nsecs = 100;
- /* transfer data. the lower level code handles any
- * new dma mappings it needs. our caller always gave
- * us dma-safe buffers.
- */
- if (t->len) {
- /* REVISIT dma API still needs a designated
- * DMA_ADDR_INVALID; ~0 might be better.
- */
- if (!m->is_dma_mapped)
- t->rx_dma = t->tx_dma = 0;
- status = bitbang->txrx_bufs(spi, t);
- }
- if (status > 0)
- m->actual_length += status;
- if (status != t->len) {
- /* always report some kind of error */
- if (status >= 0)
- status = -EREMOTEIO;
+ cs_change = 1;
+ status = 0;
+
+ list_for_each_entry (t, &m->transfers, transfer_list) {
+
+ /* override speed or wordsize? */
+ if (t->speed_hz || t->bits_per_word)
+ do_setup = 1;
+
+ /* init (-1) or override (1) transfer params */
+ if (do_setup != 0) {
+ status = bitbang->setup_transfer(spi, t);
+ if (status < 0)
break;
- }
- status = 0;
-
- /* protocol tweaks before next transfer */
- if (t->delay_usecs)
- udelay(t->delay_usecs);
-
- if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) {
- /* sometimes a short mid-message deselect of the chip
- * may be needed to terminate a mode or command
- */
- ndelay(nsecs);
- bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
- ndelay(nsecs);
- }
+ if (do_setup == -1)
+ do_setup = 0;
}
- m->status = status;
- m->complete(m->context);
+ /* set up default clock polarity, and activate chip;
+ * this implicitly updates clock and spi modes as
+ * previously recorded for this device via setup().
+ * (and also deselects any other chip that might be
+ * selected ...)
+ */
+ if (cs_change) {
+ bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
+ ndelay(nsecs);
+ }
+ cs_change = t->cs_change;
+ if (!t->tx_buf && !t->rx_buf && t->len) {
+ status = -EINVAL;
+ break;
+ }
- /* normally deactivate chipselect ... unless no error and
- * cs_change has hinted that the next message will probably
- * be for this chip too.
+ /* transfer data. the lower level code handles any
+ * new dma mappings it needs. our caller always gave
+ * us dma-safe buffers.
*/
- if (!(status == 0 && cs_change)) {
+ if (t->len) {
+ /* REVISIT dma API still needs a designated
+ * DMA_ADDR_INVALID; ~0 might be better.
+ */
+ if (!m->is_dma_mapped)
+ t->rx_dma = t->tx_dma = 0;
+ status = bitbang->txrx_bufs(spi, t);
+ }
+ if (status > 0)
+ m->actual_length += status;
+ if (status != t->len) {
+ /* always report some kind of error */
+ if (status >= 0)
+ status = -EREMOTEIO;
+ break;
+ }
+ status = 0;
+
+ /* protocol tweaks before next transfer */
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) {
+ /* sometimes a short mid-message deselect of the chip
+ * may be needed to terminate a mode or command
+ */
ndelay(nsecs);
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(nsecs);
}
+ }
+
+ m->status = status;
- spin_lock_irqsave(&bitbang->lock, flags);
+ /* normally deactivate chipselect ... unless no error and
+ * cs_change has hinted that the next message will probably
+ * be for this chip too.
+ */
+ if (!(status == 0 && cs_change)) {
+ ndelay(nsecs);
+ bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+ ndelay(nsecs);
}
- bitbang->busy = 0;
- spin_unlock_irqrestore(&bitbang->lock, flags);
+
+ spi_finalize_current_message(master);
+
+ return status;
}
-/**
- * spi_bitbang_transfer - default submit to transfer queue
- */
-int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
+static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
{
- struct spi_bitbang *bitbang;
+ struct spi_bitbang *bitbang;
unsigned long flags;
- int status = 0;
- m->actual_length = 0;
- m->status = -EINPROGRESS;
-
- bitbang = spi_master_get_devdata(spi->master);
+ bitbang = spi_master_get_devdata(spi);
spin_lock_irqsave(&bitbang->lock, flags);
- if (!spi->max_speed_hz)
- status = -ENETDOWN;
- else {
- list_add_tail(&m->queue, &bitbang->queue);
- queue_work(bitbang->workqueue, &bitbang->work);
- }
+ bitbang->busy = 0;
spin_unlock_irqrestore(&bitbang->lock, flags);
- return status;
+ return 0;
}
-EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
/*----------------------------------------------------------------------*/
@@ -428,20 +418,22 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
int spi_bitbang_start(struct spi_bitbang *bitbang)
{
struct spi_master *master = bitbang->master;
- int status;
if (!master || !bitbang->chipselect)
return -EINVAL;
- INIT_WORK(&bitbang->work, bitbang_work);
spin_lock_init(&bitbang->lock);
- INIT_LIST_HEAD(&bitbang->queue);
if (!master->mode_bits)
master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
- if (!master->transfer)
- master->transfer = spi_bitbang_transfer;
+ if (master->transfer || master->transfer_one_message)
+ return -EINVAL;
+
+ master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
+ master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;
+ master->transfer_one_message = spi_bitbang_transfer_one;
+
if (!bitbang->txrx_bufs) {
bitbang->use_dma = 0;
bitbang->txrx_bufs = spi_bitbang_bufs;
@@ -452,34 +444,12 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
master->setup = spi_bitbang_setup;
master->cleanup = spi_bitbang_cleanup;
}
- } else if (!master->setup)
- return -EINVAL;
- if (master->transfer == spi_bitbang_transfer &&
- !bitbang->setup_transfer)
- return -EINVAL;
-
- /* this task is the only thing to touch the SPI bits */
- bitbang->busy = 0;
- bitbang->workqueue = create_singlethread_workqueue(
- dev_name(master->dev.parent));
- if (bitbang->workqueue == NULL) {
- status = -EBUSY;
- goto err1;
}
/* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices
*/
- status = spi_register_master(master);
- if (status < 0)
- goto err2;
-
- return status;
-
-err2:
- destroy_workqueue(bitbang->workqueue);
-err1:
- return status;
+ return spi_register_master(master);
}
EXPORT_SYMBOL_GPL(spi_bitbang_start);
@@ -490,10 +460,6 @@ int spi_bitbang_stop(struct spi_bitbang *bitbang)
{
spi_unregister_master(bitbang->master);
- WARN_ON(!list_empty(&bitbang->queue));
-
- destroy_workqueue(bitbang->workqueue);
-
return 0;
}
EXPORT_SYMBOL_GPL(spi_bitbang_stop);
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index 17965fe225c..5655acf55bf 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -239,11 +239,8 @@ static int spi_clps711x_probe(struct platform_device *pdev)
}
dev_err(&pdev->dev, "Failed to register master\n");
- devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw);
clk_out:
- devm_clk_put(&pdev->dev, hw->spi_clk);
-
err_out:
while (--i >= 0)
if (gpio_is_valid(hw->chipselect[i]))
@@ -261,13 +258,10 @@ static int spi_clps711x_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
- devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw);
-
for (i = 0; i < master->num_chipselect; i++)
if (gpio_is_valid(hw->chipselect[i]))
gpio_free(hw->chipselect[i]);
- devm_clk_put(&pdev->dev, hw->spi_clk);
spi_unregister_master(master);
kfree(master);
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index 0631b9d4a5d..cc5b75d10c3 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -354,24 +354,6 @@ static int mcfqspi_transfer_one_message(struct spi_master *master,
}
-static int mcfqspi_prepare_transfer_hw(struct spi_master *master)
-{
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
-
- pm_runtime_get_sync(mcfqspi->dev);
-
- return 0;
-}
-
-static int mcfqspi_unprepare_transfer_hw(struct spi_master *master)
-{
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
-
- pm_runtime_put_sync(mcfqspi->dev);
-
- return 0;
-}
-
static int mcfqspi_setup(struct spi_device *spi)
{
if (spi->chip_select >= spi->master->num_chipselect) {
@@ -400,7 +382,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
struct mcfqspi_platform_data *pdata;
int status;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_dbg(&pdev->dev, "platform data is missing\n");
return -ENOENT;
@@ -473,8 +455,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
master->setup = mcfqspi_setup;
master->transfer_one_message = mcfqspi_transfer_one_message;
- master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw;
- master->unprepare_transfer_hardware = mcfqspi_unprepare_transfer_hw;
+ master->auto_runtime_pm = true;
platform_set_drvdata(pdev, master);
@@ -558,7 +539,7 @@ static int mcfqspi_resume(struct device *dev)
#ifdef CONFIG_PM_RUNTIME
static int mcfqspi_runtime_suspend(struct device *dev)
{
- struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+ struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
clk_disable(mcfqspi->clk);
@@ -567,7 +548,7 @@ static int mcfqspi_runtime_suspend(struct device *dev)
static int mcfqspi_runtime_resume(struct device *dev)
{
- struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+ struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
clk_enable(mcfqspi->clk);
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 222d3e37fc2..8fbfe2483ff 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -609,7 +609,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
else
buf = (void *)t->tx_buf;
t->tx_dma = dma_map_single(&spi->dev, buf,
- t->len, DMA_FROM_DEVICE);
+ t->len, DMA_TO_DEVICE);
if (!t->tx_dma) {
ret = -EFAULT;
goto err_tx_map;
@@ -872,8 +872,8 @@ static int davinci_spi_probe(struct platform_device *pdev)
goto free_master;
}
- if (pdev->dev.platform_data) {
- pdata = pdev->dev.platform_data;
+ if (dev_get_platdata(&pdev->dev)) {
+ pdata = dev_get_platdata(&pdev->dev);
dspi->pdata = *pdata;
} else {
/* update dspi pdata with that from the DT */
diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c
new file mode 100644
index 00000000000..7d84418a01d
--- /dev/null
+++ b/drivers/spi/spi-efm32.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (C) 2012-2013 Uwe Kleine-Koenig for Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_data/efm32-spi.h>
+
+#define DRIVER_NAME "efm32-spi"
+
+#define MASK_VAL(mask, val) ((val << __ffs(mask)) & mask)
+
+#define REG_CTRL 0x00
+#define REG_CTRL_SYNC 0x0001
+#define REG_CTRL_CLKPOL 0x0100
+#define REG_CTRL_CLKPHA 0x0200
+#define REG_CTRL_MSBF 0x0400
+#define REG_CTRL_TXBIL 0x1000
+
+#define REG_FRAME 0x04
+#define REG_FRAME_DATABITS__MASK 0x000f
+#define REG_FRAME_DATABITS(n) ((n) - 3)
+
+#define REG_CMD 0x0c
+#define REG_CMD_RXEN 0x0001
+#define REG_CMD_RXDIS 0x0002
+#define REG_CMD_TXEN 0x0004
+#define REG_CMD_TXDIS 0x0008
+#define REG_CMD_MASTEREN 0x0010
+
+#define REG_STATUS 0x10
+#define REG_STATUS_TXENS 0x0002
+#define REG_STATUS_TXC 0x0020
+#define REG_STATUS_TXBL 0x0040
+#define REG_STATUS_RXDATAV 0x0080
+
+#define REG_CLKDIV 0x14
+
+#define REG_RXDATAX 0x18
+#define REG_RXDATAX_RXDATA__MASK 0x01ff
+#define REG_RXDATAX_PERR 0x4000
+#define REG_RXDATAX_FERR 0x8000
+
+#define REG_TXDATA 0x34
+
+#define REG_IF 0x40
+#define REG_IF_TXBL 0x0002
+#define REG_IF_RXDATAV 0x0004
+
+#define REG_IFS 0x44
+#define REG_IFC 0x48
+#define REG_IEN 0x4c
+
+#define REG_ROUTE 0x54
+#define REG_ROUTE_RXPEN 0x0001
+#define REG_ROUTE_TXPEN 0x0002
+#define REG_ROUTE_CLKPEN 0x0008
+#define REG_ROUTE_LOCATION__MASK 0x0700
+#define REG_ROUTE_LOCATION(n) MASK_VAL(REG_ROUTE_LOCATION__MASK, (n))
+
+struct efm32_spi_ddata {
+ struct spi_bitbang bitbang;
+
+ spinlock_t lock;
+
+ struct clk *clk;
+ void __iomem *base;
+ unsigned int rxirq, txirq;
+ struct efm32_spi_pdata pdata;
+
+ /* irq data */
+ struct completion done;
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ unsigned tx_len, rx_len;
+
+ /* chip selects */
+ unsigned csgpio[];
+};
+
+#define ddata_to_dev(ddata) (&(ddata->bitbang.master->dev))
+#define efm32_spi_vdbg(ddata, format, arg...) \
+ dev_vdbg(ddata_to_dev(ddata), format, ##arg)
+
+static void efm32_spi_write32(struct efm32_spi_ddata *ddata,
+ u32 value, unsigned offset)
+{
+ writel_relaxed(value, ddata->base + offset);
+}
+
+static u32 efm32_spi_read32(struct efm32_spi_ddata *ddata, unsigned offset)
+{
+ return readl_relaxed(ddata->base + offset);
+}
+
+static void efm32_spi_chipselect(struct spi_device *spi, int is_on)
+{
+ struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
+ int value = !(spi->mode & SPI_CS_HIGH) == !(is_on == BITBANG_CS_ACTIVE);
+
+ gpio_set_value(ddata->csgpio[spi->chip_select], value);
+}
+
+static int efm32_spi_setup_transfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
+
+ unsigned bpw = t->bits_per_word ?: spi->bits_per_word;
+ unsigned speed = t->speed_hz ?: spi->max_speed_hz;
+ unsigned long clkfreq = clk_get_rate(ddata->clk);
+ u32 clkdiv;
+
+ efm32_spi_write32(ddata, REG_CTRL_SYNC | REG_CTRL_MSBF |
+ (spi->mode & SPI_CPHA ? REG_CTRL_CLKPHA : 0) |
+ (spi->mode & SPI_CPOL ? REG_CTRL_CLKPOL : 0), REG_CTRL);
+
+ efm32_spi_write32(ddata,
+ REG_FRAME_DATABITS(bpw), REG_FRAME);
+
+ if (2 * speed >= clkfreq)
+ clkdiv = 0;
+ else
+ clkdiv = 64 * (DIV_ROUND_UP(2 * clkfreq, speed) - 4);
+
+ if (clkdiv > (1U << 21))
+ return -EINVAL;
+
+ efm32_spi_write32(ddata, clkdiv, REG_CLKDIV);
+ efm32_spi_write32(ddata, REG_CMD_MASTEREN, REG_CMD);
+ efm32_spi_write32(ddata, REG_CMD_RXEN | REG_CMD_TXEN, REG_CMD);
+
+ return 0;
+}
+
+static void efm32_spi_tx_u8(struct efm32_spi_ddata *ddata)
+{
+ u8 val = 0;
+
+ if (ddata->tx_buf) {
+ val = *ddata->tx_buf;
+ ddata->tx_buf++;
+ }
+
+ ddata->tx_len--;
+ efm32_spi_write32(ddata, val, REG_TXDATA);
+ efm32_spi_vdbg(ddata, "%s: tx 0x%x\n", __func__, val);
+}
+
+static void efm32_spi_rx_u8(struct efm32_spi_ddata *ddata)
+{
+ u32 rxdata = efm32_spi_read32(ddata, REG_RXDATAX);
+ efm32_spi_vdbg(ddata, "%s: rx 0x%x\n", __func__, rxdata);
+
+ if (ddata->rx_buf) {
+ *ddata->rx_buf = rxdata;
+ ddata->rx_buf++;
+ }
+
+ ddata->rx_len--;
+}
+
+static void efm32_spi_filltx(struct efm32_spi_ddata *ddata)
+{
+ while (ddata->tx_len &&
+ ddata->tx_len + 2 > ddata->rx_len &&
+ efm32_spi_read32(ddata, REG_STATUS) & REG_STATUS_TXBL) {
+ efm32_spi_tx_u8(ddata);
+ }
+}
+
+static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
+ int ret = -EBUSY;
+
+ spin_lock_irq(&ddata->lock);
+
+ if (ddata->tx_buf || ddata->rx_buf)
+ goto out_unlock;
+
+ ddata->tx_buf = t->tx_buf;
+ ddata->rx_buf = t->rx_buf;
+ ddata->tx_len = ddata->rx_len =
+ t->len * DIV_ROUND_UP(t->bits_per_word, 8);
+
+ efm32_spi_filltx(ddata);
+
+ init_completion(&ddata->done);
+
+ efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN);
+
+ spin_unlock_irq(&ddata->lock);
+
+ wait_for_completion(&ddata->done);
+
+ spin_lock_irq(&ddata->lock);
+
+ ret = t->len - max(ddata->tx_len, ddata->rx_len);
+
+ efm32_spi_write32(ddata, 0, REG_IEN);
+ ddata->tx_buf = ddata->rx_buf = NULL;
+
+out_unlock:
+ spin_unlock_irq(&ddata->lock);
+
+ return ret;
+}
+
+static irqreturn_t efm32_spi_rxirq(int irq, void *data)
+{
+ struct efm32_spi_ddata *ddata = data;
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock(&ddata->lock);
+
+ while (ddata->rx_len > 0 &&
+ efm32_spi_read32(ddata, REG_STATUS) &
+ REG_STATUS_RXDATAV) {
+ efm32_spi_rx_u8(ddata);
+
+ ret = IRQ_HANDLED;
+ }
+
+ if (!ddata->rx_len) {
+ u32 ien = efm32_spi_read32(ddata, REG_IEN);
+
+ ien &= ~REG_IF_RXDATAV;
+
+ efm32_spi_write32(ddata, ien, REG_IEN);
+
+ complete(&ddata->done);
+ }
+
+ spin_unlock(&ddata->lock);
+
+ return ret;
+}
+
+static irqreturn_t efm32_spi_txirq(int irq, void *data)
+{
+ struct efm32_spi_ddata *ddata = data;
+
+ efm32_spi_vdbg(ddata,
+ "%s: txlen = %u, rxlen = %u, if=0x%08x, stat=0x%08x\n",
+ __func__, ddata->tx_len, ddata->rx_len,
+ efm32_spi_read32(ddata, REG_IF),
+ efm32_spi_read32(ddata, REG_STATUS));
+
+ spin_lock(&ddata->lock);
+
+ efm32_spi_filltx(ddata);
+
+ efm32_spi_vdbg(ddata, "%s: txlen = %u, rxlen = %u\n",
+ __func__, ddata->tx_len, ddata->rx_len);
+
+ if (!ddata->tx_len) {
+ u32 ien = efm32_spi_read32(ddata, REG_IEN);
+
+ ien &= ~REG_IF_TXBL;
+
+ efm32_spi_write32(ddata, ien, REG_IEN);
+ efm32_spi_vdbg(ddata, "disable TXBL\n");
+ }
+
+ spin_unlock(&ddata->lock);
+
+ return IRQ_HANDLED;
+}
+
+static const struct efm32_spi_pdata efm32_spi_pdata_default = {
+ .location = 1,
+};
+
+static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
+{
+ u32 reg = efm32_spi_read32(ddata, REG_ROUTE);
+
+ return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK);
+}
+
+static int efm32_spi_probe_dt(struct platform_device *pdev,
+ struct spi_master *master, struct efm32_spi_ddata *ddata)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 location;
+ int ret;
+
+ if (!np)
+ return 1;
+
+ ret = of_property_read_u32(np, "location", &location);
+ if (!ret) {
+ dev_dbg(&pdev->dev, "using location %u\n", location);
+ } else {
+ /* default to location configured in hardware */
+ location = efm32_spi_get_configured_location(ddata);
+
+ dev_info(&pdev->dev, "fall back to location %u\n", location);
+ }
+
+ ddata->pdata.location = location;
+
+ /* spi core takes care about the bus number using an alias */
+ master->bus_num = -1;
+
+ return 0;
+}
+
+static int efm32_spi_probe(struct platform_device *pdev)
+{
+ struct efm32_spi_ddata *ddata;
+ struct resource *res;
+ int ret;
+ struct spi_master *master;
+ struct device_node *np = pdev->dev.of_node;
+ unsigned int num_cs, i;
+
+ num_cs = of_gpio_named_count(np, "cs-gpios");
+
+ master = spi_alloc_master(&pdev->dev,
+ sizeof(*ddata) + num_cs * sizeof(unsigned));
+ if (!master) {
+ dev_dbg(&pdev->dev,
+ "failed to allocate spi master controller\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, master);
+
+ master->dev.of_node = pdev->dev.of_node;
+
+ master->num_chipselect = num_cs;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+
+ ddata = spi_master_get_devdata(master);
+
+ ddata->bitbang.master = spi_master_get(master);
+ ddata->bitbang.chipselect = efm32_spi_chipselect;
+ ddata->bitbang.setup_transfer = efm32_spi_setup_transfer;
+ ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
+
+ spin_lock_init(&ddata->lock);
+
+ ddata->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ddata->clk)) {
+ ret = PTR_ERR(ddata->clk);
+ dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
+ goto err;
+ }
+
+ for (i = 0; i < num_cs; ++i) {
+ ret = of_get_named_gpio(np, "cs-gpios", i);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get csgpio#%u (%d)\n",
+ i, ret);
+ goto err;
+ }
+ ddata->csgpio[i] = ret;
+ dev_dbg(&pdev->dev, "csgpio#%u = %u\n", i, ddata->csgpio[i]);
+ ret = devm_gpio_request_one(&pdev->dev, ddata->csgpio[i],
+ GPIOF_OUT_INIT_LOW, DRIVER_NAME);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "failed to configure csgpio#%u (%d)\n",
+ i, ret);
+ goto err;
+ }
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "failed to determine base address\n");
+ goto err;
+ }
+
+ if (resource_size(res) < 60) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev, "memory resource too small\n");
+ goto err;
+ }
+
+ ddata->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ddata->base)) {
+ ret = PTR_ERR(ddata->base);
+ goto err;
+ }
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
+ dev_err(&pdev->dev, "failed to get rx irq (%d)\n", ret);
+ goto err;
+ }
+
+ ddata->rxirq = ret;
+
+ ret = platform_get_irq(pdev, 1);
+ if (ret <= 0)
+ ret = ddata->rxirq + 1;
+
+ ddata->txirq = ret;
+
+ ret = clk_prepare_enable(ddata->clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret);
+ goto err;
+ }
+
+ ret = efm32_spi_probe_dt(pdev, master, ddata);
+ if (ret > 0) {
+ /* not created by device tree */
+ const struct efm32_spi_pdata *pdata =
+ dev_get_platdata(&pdev->dev);
+
+ if (pdata)
+ ddata->pdata = *pdata;
+ else
+ ddata->pdata.location =
+ efm32_spi_get_configured_location(ddata);
+
+ master->bus_num = pdev->id;
+
+ } else if (ret < 0) {
+ goto err_disable_clk;
+ }
+
+ efm32_spi_write32(ddata, 0, REG_IEN);
+ efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
+ REG_ROUTE_CLKPEN |
+ REG_ROUTE_LOCATION(ddata->pdata.location), REG_ROUTE);
+
+ ret = request_irq(ddata->rxirq, efm32_spi_rxirq,
+ 0, DRIVER_NAME " rx", ddata);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register rxirq (%d)\n", ret);
+ goto err_disable_clk;
+ }
+
+ ret = request_irq(ddata->txirq, efm32_spi_txirq,
+ 0, DRIVER_NAME " tx", ddata);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register txirq (%d)\n", ret);
+ goto err_free_rx_irq;
+ }
+
+ ret = spi_bitbang_start(&ddata->bitbang);
+ if (ret) {
+ dev_err(&pdev->dev, "spi_bitbang_start failed (%d)\n", ret);
+
+ free_irq(ddata->txirq, ddata);
+err_free_rx_irq:
+ free_irq(ddata->rxirq, ddata);
+err_disable_clk:
+ clk_disable_unprepare(ddata->clk);
+err:
+ spi_master_put(master);
+ kfree(master);
+ }
+
+ return ret;
+}
+
+static int efm32_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct efm32_spi_ddata *ddata = spi_master_get_devdata(master);
+
+ efm32_spi_write32(ddata, 0, REG_IEN);
+
+ free_irq(ddata->txirq, ddata);
+ free_irq(ddata->rxirq, ddata);
+ clk_disable_unprepare(ddata->clk);
+ spi_master_put(master);
+ kfree(master);
+
+ return 0;
+}
+
+static const struct of_device_id efm32_spi_dt_ids[] = {
+ {
+ .compatible = "efm32,spi",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, efm32_spi_dt_ids);
+
+static struct platform_driver efm32_spi_driver = {
+ .probe = efm32_spi_probe,
+ .remove = efm32_spi_remove,
+
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = efm32_spi_dt_ids,
+ },
+};
+module_platform_driver(efm32_spi_driver);
+
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_DESCRIPTION("EFM32 SPI driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index cad30b8a1d7..d22c00a227b 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -26,7 +26,6 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/workqueue.h>
#include <linux/sched.h>
#include <linux/scatterlist.h>
#include <linux/spi/spi.h>
@@ -70,19 +69,13 @@
/**
* struct ep93xx_spi - EP93xx SPI controller structure
- * @lock: spinlock that protects concurrent accesses to fields @running,
- * @current_msg and @msg_queue
* @pdev: pointer to platform device
* @clk: clock for the controller
* @regs_base: pointer to ioremap()'d registers
* @sspdr_phys: physical address of the SSPDR register
* @min_rate: minimum clock rate (in Hz) supported by the controller
* @max_rate: maximum clock rate (in Hz) supported by the controller
- * @running: is the queue running
- * @wq: workqueue used by the driver
- * @msg_work: work that is queued for the driver
* @wait: wait here until given transfer is completed
- * @msg_queue: queue for the messages
* @current_msg: message that is currently processed (or %NULL if none)
* @tx: current byte in transfer to transmit
* @rx: current byte in transfer to receive
@@ -96,30 +89,15 @@
* @tx_sgt: sg table for TX transfers
* @zeropage: dummy page used as RX buffer when only TX buffer is passed in by
* the client
- *
- * This structure holds EP93xx SPI controller specific information. When
- * @running is %true, driver accepts transfer requests from protocol drivers.
- * @current_msg is used to hold pointer to the message that is currently
- * processed. If @current_msg is %NULL, it means that no processing is going
- * on.
- *
- * Most of the fields are only written once and they can be accessed without
- * taking the @lock. Fields that are accessed concurrently are: @current_msg,
- * @running, and @msg_queue.
*/
struct ep93xx_spi {
- spinlock_t lock;
const struct platform_device *pdev;
struct clk *clk;
void __iomem *regs_base;
unsigned long sspdr_phys;
unsigned long min_rate;
unsigned long max_rate;
- bool running;
- struct workqueue_struct *wq;
- struct work_struct msg_work;
struct completion wait;
- struct list_head msg_queue;
struct spi_message *current_msg;
size_t tx;
size_t rx;
@@ -136,50 +114,36 @@ struct ep93xx_spi {
/**
* struct ep93xx_spi_chip - SPI device hardware settings
* @spi: back pointer to the SPI device
- * @rate: max rate in hz this chip supports
- * @div_cpsr: cpsr (pre-scaler) divider
- * @div_scr: scr divider
- * @dss: bits per word (4 - 16 bits)
* @ops: private chip operations
- *
- * This structure is used to store hardware register specific settings for each
- * SPI device. Settings are written to hardware by function
- * ep93xx_spi_chip_setup().
*/
struct ep93xx_spi_chip {
const struct spi_device *spi;
- unsigned long rate;
- u8 div_cpsr;
- u8 div_scr;
- u8 dss;
struct ep93xx_spi_chip_ops *ops;
};
/* converts bits per word to CR0.DSS value */
#define bits_per_word_to_dss(bpw) ((bpw) - 1)
-static inline void
-ep93xx_spi_write_u8(const struct ep93xx_spi *espi, u16 reg, u8 value)
+static void ep93xx_spi_write_u8(const struct ep93xx_spi *espi,
+ u16 reg, u8 value)
{
- __raw_writeb(value, espi->regs_base + reg);
+ writeb(value, espi->regs_base + reg);
}
-static inline u8
-ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
+static u8 ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
{
- return __raw_readb(spi->regs_base + reg);
+ return readb(spi->regs_base + reg);
}
-static inline void
-ep93xx_spi_write_u16(const struct ep93xx_spi *espi, u16 reg, u16 value)
+static void ep93xx_spi_write_u16(const struct ep93xx_spi *espi,
+ u16 reg, u16 value)
{
- __raw_writew(value, espi->regs_base + reg);
+ writew(value, espi->regs_base + reg);
}
-static inline u16
-ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
+static u16 ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
{
- return __raw_readw(spi->regs_base + reg);
+ return readw(spi->regs_base + reg);
}
static int ep93xx_spi_enable(const struct ep93xx_spi *espi)
@@ -230,17 +194,13 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
/**
* ep93xx_spi_calc_divisors() - calculates SPI clock divisors
* @espi: ep93xx SPI controller struct
- * @chip: divisors are calculated for this chip
* @rate: desired SPI output clock rate
- *
- * Function calculates cpsr (clock pre-scaler) and scr divisors based on
- * given @rate and places them to @chip->div_cpsr and @chip->div_scr. If,
- * for some reason, divisors cannot be calculated nothing is stored and
- * %-EINVAL is returned.
+ * @div_cpsr: pointer to return the cpsr (pre-scaler) divider
+ * @div_scr: pointer to return the scr divider
*/
static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
- struct ep93xx_spi_chip *chip,
- unsigned long rate)
+ unsigned long rate,
+ u8 *div_cpsr, u8 *div_scr)
{
unsigned long spi_clk_rate = clk_get_rate(espi->clk);
int cpsr, scr;
@@ -248,7 +208,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
/*
* Make sure that max value is between values supported by the
* controller. Note that minimum value is already checked in
- * ep93xx_spi_transfer().
+ * ep93xx_spi_transfer_one_message().
*/
rate = clamp(rate, espi->min_rate, espi->max_rate);
@@ -263,8 +223,8 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
for (cpsr = 2; cpsr <= 254; cpsr += 2) {
for (scr = 0; scr <= 255; scr++) {
if ((spi_clk_rate / (cpsr * (scr + 1))) <= rate) {
- chip->div_scr = (u8)scr;
- chip->div_cpsr = (u8)cpsr;
+ *div_scr = (u8)scr;
+ *div_cpsr = (u8)cpsr;
return 0;
}
}
@@ -319,73 +279,11 @@ static int ep93xx_spi_setup(struct spi_device *spi)
spi_set_ctldata(spi, chip);
}
- if (spi->max_speed_hz != chip->rate) {
- int err;
-
- err = ep93xx_spi_calc_divisors(espi, chip, spi->max_speed_hz);
- if (err != 0) {
- spi_set_ctldata(spi, NULL);
- kfree(chip);
- return err;
- }
- chip->rate = spi->max_speed_hz;
- }
-
- chip->dss = bits_per_word_to_dss(spi->bits_per_word);
-
ep93xx_spi_cs_control(spi, false);
return 0;
}
/**
- * ep93xx_spi_transfer() - queue message to be transferred
- * @spi: target SPI device
- * @msg: message to be transferred
- *
- * This function is called by SPI device drivers when they are going to transfer
- * a new message. It simply puts the message in the queue and schedules
- * workqueue to perform the actual transfer later on.
- *
- * Returns %0 on success and negative error in case of failure.
- */
-static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
-{
- struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
- struct spi_transfer *t;
- unsigned long flags;
-
- if (!msg || !msg->complete)
- return -EINVAL;
-
- /* first validate each transfer */
- list_for_each_entry(t, &msg->transfers, transfer_list) {
- if (t->speed_hz && t->speed_hz < espi->min_rate)
- return -EINVAL;
- }
-
- /*
- * Now that we own the message, let's initialize it so that it is
- * suitable for us. We use @msg->status to signal whether there was
- * error in transfer and @msg->state is used to hold pointer to the
- * current transfer (or %NULL if no active current transfer).
- */
- msg->state = NULL;
- msg->status = 0;
- msg->actual_length = 0;
-
- spin_lock_irqsave(&espi->lock, flags);
- if (!espi->running) {
- spin_unlock_irqrestore(&espi->lock, flags);
- return -ESHUTDOWN;
- }
- list_add_tail(&msg->queue, &espi->msg_queue);
- queue_work(espi->wq, &espi->msg_work);
- spin_unlock_irqrestore(&espi->lock, flags);
-
- return 0;
-}
-
-/**
* ep93xx_spi_cleanup() - cleans up master controller specific state
* @spi: SPI device to cleanup
*
@@ -409,39 +307,40 @@ static void ep93xx_spi_cleanup(struct spi_device *spi)
* ep93xx_spi_chip_setup() - configures hardware according to given @chip
* @espi: ep93xx SPI controller struct
* @chip: chip specific settings
- *
- * This function sets up the actual hardware registers with settings given in
- * @chip. Note that no validation is done so make sure that callers validate
- * settings before calling this.
+ * @speed_hz: transfer speed
+ * @bits_per_word: transfer bits_per_word
*/
-static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
- const struct ep93xx_spi_chip *chip)
+static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
+ const struct ep93xx_spi_chip *chip,
+ u32 speed_hz, u8 bits_per_word)
{
+ u8 dss = bits_per_word_to_dss(bits_per_word);
+ u8 div_cpsr = 0;
+ u8 div_scr = 0;
u16 cr0;
+ int err;
- cr0 = chip->div_scr << SSPCR0_SCR_SHIFT;
+ err = ep93xx_spi_calc_divisors(espi, speed_hz, &div_cpsr, &div_scr);
+ if (err)
+ return err;
+
+ cr0 = div_scr << SSPCR0_SCR_SHIFT;
cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT;
- cr0 |= chip->dss;
+ cr0 |= dss;
dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
- chip->spi->mode, chip->div_cpsr, chip->div_scr, chip->dss);
+ chip->spi->mode, div_cpsr, div_scr, dss);
dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0);
- ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr);
+ ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr);
ep93xx_spi_write_u16(espi, SSPCR0, cr0);
-}
-
-static inline int bits_per_word(const struct ep93xx_spi *espi)
-{
- struct spi_message *msg = espi->current_msg;
- struct spi_transfer *t = msg->state;
- return t->bits_per_word;
+ return 0;
}
static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
{
- if (bits_per_word(espi) > 8) {
+ if (t->bits_per_word > 8) {
u16 tx_val = 0;
if (t->tx_buf)
@@ -460,7 +359,7 @@ static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
{
- if (bits_per_word(espi) > 8) {
+ if (t->bits_per_word > 8) {
u16 rx_val;
rx_val = ep93xx_spi_read_u16(espi, SSPDR);
@@ -546,7 +445,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir)
size_t len = t->len;
int i, ret, nents;
- if (bits_per_word(espi) > 8)
+ if (t->bits_per_word > 8)
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
else
buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
@@ -610,7 +509,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir)
}
if (WARN_ON(len)) {
- dev_warn(&espi->pdev->dev, "len = %d expected 0!", len);
+ dev_warn(&espi->pdev->dev, "len = %zu expected 0!", len);
return ERR_PTR(-EINVAL);
}
@@ -708,37 +607,16 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
struct spi_transfer *t)
{
struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi);
+ int err;
msg->state = t;
- /*
- * Handle any transfer specific settings if needed. We use
- * temporary chip settings here and restore original later when
- * the transfer is finished.
- */
- if (t->speed_hz || t->bits_per_word) {
- struct ep93xx_spi_chip tmp_chip = *chip;
-
- if (t->speed_hz) {
- int err;
-
- err = ep93xx_spi_calc_divisors(espi, &tmp_chip,
- t->speed_hz);
- if (err) {
- dev_err(&espi->pdev->dev,
- "failed to adjust speed\n");
- msg->status = err;
- return;
- }
- }
-
- if (t->bits_per_word)
- tmp_chip.dss = bits_per_word_to_dss(t->bits_per_word);
-
- /*
- * Set up temporary new hw settings for this transfer.
- */
- ep93xx_spi_chip_setup(espi, &tmp_chip);
+ err = ep93xx_spi_chip_setup(espi, chip, t->speed_hz, t->bits_per_word);
+ if (err) {
+ dev_err(&espi->pdev->dev,
+ "failed to setup chip for transfer\n");
+ msg->status = err;
+ return;
}
espi->rx = 0;
@@ -783,9 +661,6 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
ep93xx_spi_cs_control(msg->spi, true);
}
}
-
- if (t->speed_hz || t->bits_per_word)
- ep93xx_spi_chip_setup(espi, chip);
}
/*
@@ -838,10 +713,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
espi->fifo_level = 0;
/*
- * Update SPI controller registers according to spi device and assert
- * the chipselect.
+ * Assert the chipselect.
*/
- ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
ep93xx_spi_cs_control(msg->spi, true);
list_for_each_entry(t, &msg->transfers, transfer_list) {
@@ -858,50 +731,29 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
ep93xx_spi_disable(espi);
}
-#define work_to_espi(work) (container_of((work), struct ep93xx_spi, msg_work))
-
-/**
- * ep93xx_spi_work() - EP93xx SPI workqueue worker function
- * @work: work struct
- *
- * Workqueue worker function. This function is called when there are new
- * SPI messages to be processed. Message is taken out from the queue and then
- * passed to ep93xx_spi_process_message().
- *
- * After message is transferred, protocol driver is notified by calling
- * @msg->complete(). In case of error, @msg->status is set to negative error
- * number, otherwise it contains zero (and @msg->actual_length is updated).
- */
-static void ep93xx_spi_work(struct work_struct *work)
+static int ep93xx_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg)
{
- struct ep93xx_spi *espi = work_to_espi(work);
- struct spi_message *msg;
+ struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct spi_transfer *t;
- spin_lock_irq(&espi->lock);
- if (!espi->running || espi->current_msg ||
- list_empty(&espi->msg_queue)) {
- spin_unlock_irq(&espi->lock);
- return;
+ /* first validate each transfer */
+ list_for_each_entry(t, &msg->transfers, transfer_list) {
+ if (t->speed_hz < espi->min_rate)
+ return -EINVAL;
}
- msg = list_first_entry(&espi->msg_queue, struct spi_message, queue);
- list_del_init(&msg->queue);
- espi->current_msg = msg;
- spin_unlock_irq(&espi->lock);
- ep93xx_spi_process_message(espi, msg);
+ msg->state = NULL;
+ msg->status = 0;
+ msg->actual_length = 0;
- /*
- * Update the current message and re-schedule ourselves if there are
- * more messages in the queue.
- */
- spin_lock_irq(&espi->lock);
+ espi->current_msg = msg;
+ ep93xx_spi_process_message(espi, msg);
espi->current_msg = NULL;
- if (espi->running && !list_empty(&espi->msg_queue))
- queue_work(espi->wq, &espi->msg_work);
- spin_unlock_irq(&espi->lock);
- /* notify the protocol driver that we are done with this message */
- msg->complete(msg->context);
+ spi_finalize_current_message(master);
+
+ return 0;
}
static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
@@ -1022,16 +874,26 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
int irq;
int error;
- info = pdev->dev.platform_data;
+ info = dev_get_platdata(&pdev->dev);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq resources\n");
+ return -EBUSY;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "unable to get iomem resource\n");
+ return -ENODEV;
+ }
master = spi_alloc_master(&pdev->dev, sizeof(*espi));
- if (!master) {
- dev_err(&pdev->dev, "failed to allocate spi master\n");
+ if (!master)
return -ENOMEM;
- }
master->setup = ep93xx_spi_setup;
- master->transfer = ep93xx_spi_transfer;
+ master->transfer_one_message = ep93xx_spi_transfer_one_message;
master->cleanup = ep93xx_spi_cleanup;
master->bus_num = pdev->id;
master->num_chipselect = info->num_chipselect;
@@ -1042,14 +904,13 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
espi = spi_master_get_devdata(master);
- espi->clk = clk_get(&pdev->dev, NULL);
+ espi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(espi->clk)) {
dev_err(&pdev->dev, "unable to get spi clock\n");
error = PTR_ERR(espi->clk);
goto fail_release_master;
}
- spin_lock_init(&espi->lock);
init_completion(&espi->wait);
/*
@@ -1060,55 +921,31 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
espi->pdev = pdev;
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- error = -EBUSY;
- dev_err(&pdev->dev, "failed to get irq resources\n");
- goto fail_put_clock;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "unable to get iomem resource\n");
- error = -ENODEV;
- goto fail_put_clock;
- }
-
espi->sspdr_phys = res->start + SSPDR;
espi->regs_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(espi->regs_base)) {
error = PTR_ERR(espi->regs_base);
- goto fail_put_clock;
+ goto fail_release_master;
}
error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt,
0, "ep93xx-spi", espi);
if (error) {
dev_err(&pdev->dev, "failed to request irq\n");
- goto fail_put_clock;
+ goto fail_release_master;
}
if (info->use_dma && ep93xx_spi_setup_dma(espi))
dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n");
- espi->wq = create_singlethread_workqueue("ep93xx_spid");
- if (!espi->wq) {
- dev_err(&pdev->dev, "unable to create workqueue\n");
- error = -ENOMEM;
- goto fail_free_dma;
- }
- INIT_WORK(&espi->msg_work, ep93xx_spi_work);
- INIT_LIST_HEAD(&espi->msg_queue);
- espi->running = true;
-
/* make sure that the hardware is disabled */
ep93xx_spi_write_u8(espi, SSPCR1, 0);
error = spi_register_master(master);
if (error) {
dev_err(&pdev->dev, "failed to register SPI master\n");
- goto fail_free_queue;
+ goto fail_free_dma;
}
dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n",
@@ -1116,12 +953,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
return 0;
-fail_free_queue:
- destroy_workqueue(espi->wq);
fail_free_dma:
ep93xx_spi_release_dma(espi);
-fail_put_clock:
- clk_put(espi->clk);
fail_release_master:
spi_master_put(master);
@@ -1133,31 +966,7 @@ static int ep93xx_spi_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct ep93xx_spi *espi = spi_master_get_devdata(master);
- spin_lock_irq(&espi->lock);
- espi->running = false;
- spin_unlock_irq(&espi->lock);
-
- destroy_workqueue(espi->wq);
-
- /*
- * Complete remaining messages with %-ESHUTDOWN status.
- */
- spin_lock_irq(&espi->lock);
- while (!list_empty(&espi->msg_queue)) {
- struct spi_message *msg;
-
- msg = list_first_entry(&espi->msg_queue,
- struct spi_message, queue);
- list_del_init(&msg->queue);
- msg->status = -ESHUTDOWN;
- spin_unlock_irq(&espi->lock);
- msg->complete(msg->context);
- spin_lock_irq(&espi->lock);
- }
- spin_unlock_irq(&espi->lock);
-
ep93xx_spi_release_dma(espi);
- clk_put(espi->clk);
spi_unregister_master(master);
return 0;
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
new file mode 100644
index 00000000000..6cd07d13eca
--- /dev/null
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -0,0 +1,557 @@
+/*
+ * drivers/spi/spi-fsl-dspi.c
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * Freescale DSPI driver
+ * This file contains a driver for the Freescale DSPI
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#define DRIVER_NAME "fsl-dspi"
+
+#define TRAN_STATE_RX_VOID 0x01
+#define TRAN_STATE_TX_VOID 0x02
+#define TRAN_STATE_WORD_ODD_NUM 0x04
+
+#define DSPI_FIFO_SIZE 4
+
+#define SPI_MCR 0x00
+#define SPI_MCR_MASTER (1 << 31)
+#define SPI_MCR_PCSIS (0x3F << 16)
+#define SPI_MCR_CLR_TXF (1 << 11)
+#define SPI_MCR_CLR_RXF (1 << 10)
+
+#define SPI_TCR 0x08
+
+#define SPI_CTAR(x) (0x0c + (x * 4))
+#define SPI_CTAR_FMSZ(x) (((x) & 0x0000000f) << 27)
+#define SPI_CTAR_CPOL(x) ((x) << 26)
+#define SPI_CTAR_CPHA(x) ((x) << 25)
+#define SPI_CTAR_LSBFE(x) ((x) << 24)
+#define SPI_CTAR_PCSSCR(x) (((x) & 0x00000003) << 22)
+#define SPI_CTAR_PASC(x) (((x) & 0x00000003) << 20)
+#define SPI_CTAR_PDT(x) (((x) & 0x00000003) << 18)
+#define SPI_CTAR_PBR(x) (((x) & 0x00000003) << 16)
+#define SPI_CTAR_CSSCK(x) (((x) & 0x0000000f) << 12)
+#define SPI_CTAR_ASC(x) (((x) & 0x0000000f) << 8)
+#define SPI_CTAR_DT(x) (((x) & 0x0000000f) << 4)
+#define SPI_CTAR_BR(x) ((x) & 0x0000000f)
+
+#define SPI_CTAR0_SLAVE 0x0c
+
+#define SPI_SR 0x2c
+#define SPI_SR_EOQF 0x10000000
+
+#define SPI_RSER 0x30
+#define SPI_RSER_EOQFE 0x10000000
+
+#define SPI_PUSHR 0x34
+#define SPI_PUSHR_CONT (1 << 31)
+#define SPI_PUSHR_CTAS(x) (((x) & 0x00000007) << 28)
+#define SPI_PUSHR_EOQ (1 << 27)
+#define SPI_PUSHR_CTCNT (1 << 26)
+#define SPI_PUSHR_PCS(x) (((1 << x) & 0x0000003f) << 16)
+#define SPI_PUSHR_TXDATA(x) ((x) & 0x0000ffff)
+
+#define SPI_PUSHR_SLAVE 0x34
+
+#define SPI_POPR 0x38
+#define SPI_POPR_RXDATA(x) ((x) & 0x0000ffff)
+
+#define SPI_TXFR0 0x3c
+#define SPI_TXFR1 0x40
+#define SPI_TXFR2 0x44
+#define SPI_TXFR3 0x48
+#define SPI_RXFR0 0x7c
+#define SPI_RXFR1 0x80
+#define SPI_RXFR2 0x84
+#define SPI_RXFR3 0x88
+
+#define SPI_FRAME_BITS(bits) SPI_CTAR_FMSZ((bits) - 1)
+#define SPI_FRAME_BITS_MASK SPI_CTAR_FMSZ(0xf)
+#define SPI_FRAME_BITS_16 SPI_CTAR_FMSZ(0xf)
+#define SPI_FRAME_BITS_8 SPI_CTAR_FMSZ(0x7)
+
+#define SPI_CS_INIT 0x01
+#define SPI_CS_ASSERT 0x02
+#define SPI_CS_DROP 0x04
+
+struct chip_data {
+ u32 mcr_val;
+ u32 ctar_val;
+ u16 void_write_data;
+};
+
+struct fsl_dspi {
+ struct spi_bitbang bitbang;
+ struct platform_device *pdev;
+
+ void *base;
+ int irq;
+ struct clk *clk;
+
+ struct spi_transfer *cur_transfer;
+ struct chip_data *cur_chip;
+ size_t len;
+ void *tx;
+ void *tx_end;
+ void *rx;
+ void *rx_end;
+ char dataflags;
+ u8 cs;
+ u16 void_write_data;
+
+ wait_queue_head_t waitq;
+ u32 waitflags;
+};
+
+static inline int is_double_byte_mode(struct fsl_dspi *dspi)
+{
+ return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK)
+ == SPI_FRAME_BITS(8)) ? 0 : 1;
+}
+
+static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits)
+{
+ u32 temp;
+
+ temp = readl(dspi->base + SPI_CTAR(dspi->cs));
+ temp &= ~SPI_FRAME_BITS_MASK;
+ temp |= SPI_FRAME_BITS(bits);
+ writel(temp, dspi->base + SPI_CTAR(dspi->cs));
+}
+
+static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
+ unsigned long clkrate)
+{
+ /* Valid baud rate pre-scaler values */
+ int pbr_tbl[4] = {2, 3, 5, 7};
+ int brs[16] = { 2, 4, 6, 8,
+ 16, 32, 64, 128,
+ 256, 512, 1024, 2048,
+ 4096, 8192, 16384, 32768 };
+ int temp, i = 0, j = 0;
+
+ temp = clkrate / 2 / speed_hz;
+
+ for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++)
+ for (j = 0; j < ARRAY_SIZE(brs); j++) {
+ if (pbr_tbl[i] * brs[j] >= temp) {
+ *pbr = i;
+ *br = j;
+ return;
+ }
+ }
+
+ pr_warn("Can not find valid buad rate,speed_hz is %d,clkrate is %ld\
+ ,we use the max prescaler value.\n", speed_hz, clkrate);
+ *pbr = ARRAY_SIZE(pbr_tbl) - 1;
+ *br = ARRAY_SIZE(brs) - 1;
+}
+
+static int dspi_transfer_write(struct fsl_dspi *dspi)
+{
+ int tx_count = 0;
+ int tx_word;
+ u16 d16;
+ u8 d8;
+ u32 dspi_pushr = 0;
+ int first = 1;
+
+ tx_word = is_double_byte_mode(dspi);
+
+ /* If we are in word mode, but only have a single byte to transfer
+ * then switch to byte mode temporarily. Will switch back at the
+ * end of the transfer.
+ */
+ if (tx_word && (dspi->len == 1)) {
+ dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
+ set_bit_mode(dspi, 8);
+ tx_word = 0;
+ }
+
+ while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) {
+ if (tx_word) {
+ if (dspi->len == 1)
+ break;
+
+ if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) {
+ d16 = *(u16 *)dspi->tx;
+ dspi->tx += 2;
+ } else {
+ d16 = dspi->void_write_data;
+ }
+
+ dspi_pushr = SPI_PUSHR_TXDATA(d16) |
+ SPI_PUSHR_PCS(dspi->cs) |
+ SPI_PUSHR_CTAS(dspi->cs) |
+ SPI_PUSHR_CONT;
+
+ dspi->len -= 2;
+ } else {
+ if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) {
+
+ d8 = *(u8 *)dspi->tx;
+ dspi->tx++;
+ } else {
+ d8 = (u8)dspi->void_write_data;
+ }
+
+ dspi_pushr = SPI_PUSHR_TXDATA(d8) |
+ SPI_PUSHR_PCS(dspi->cs) |
+ SPI_PUSHR_CTAS(dspi->cs) |
+ SPI_PUSHR_CONT;
+
+ dspi->len--;
+ }
+
+ if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) {
+ /* last transfer in the transfer */
+ dspi_pushr |= SPI_PUSHR_EOQ;
+ } else if (tx_word && (dspi->len == 1))
+ dspi_pushr |= SPI_PUSHR_EOQ;
+
+ if (first) {
+ first = 0;
+ dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */
+ }
+
+ writel(dspi_pushr, dspi->base + SPI_PUSHR);
+ tx_count++;
+ }
+
+ return tx_count * (tx_word + 1);
+}
+
+static int dspi_transfer_read(struct fsl_dspi *dspi)
+{
+ int rx_count = 0;
+ int rx_word = is_double_byte_mode(dspi);
+ u16 d;
+ while ((dspi->rx < dspi->rx_end)
+ && (rx_count < DSPI_FIFO_SIZE)) {
+ if (rx_word) {
+ if ((dspi->rx_end - dspi->rx) == 1)
+ break;
+
+ d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+
+ if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
+ *(u16 *)dspi->rx = d;
+ dspi->rx += 2;
+
+ } else {
+ d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+ if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
+ *(u8 *)dspi->rx = d;
+ dspi->rx++;
+ }
+ rx_count++;
+ }
+
+ return rx_count;
+}
+
+static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
+ dspi->cur_transfer = t;
+ dspi->cur_chip = spi_get_ctldata(spi);
+ dspi->cs = spi->chip_select;
+ dspi->void_write_data = dspi->cur_chip->void_write_data;
+
+ dspi->dataflags = 0;
+ dspi->tx = (void *)t->tx_buf;
+ dspi->tx_end = dspi->tx + t->len;
+ dspi->rx = t->rx_buf;
+ dspi->rx_end = dspi->rx + t->len;
+ dspi->len = t->len;
+
+ if (!dspi->rx)
+ dspi->dataflags |= TRAN_STATE_RX_VOID;
+
+ if (!dspi->tx)
+ dspi->dataflags |= TRAN_STATE_TX_VOID;
+
+ writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR);
+ writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs));
+ writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER);
+
+ if (t->speed_hz)
+ writel(dspi->cur_chip->ctar_val,
+ dspi->base + SPI_CTAR(dspi->cs));
+
+ dspi_transfer_write(dspi);
+
+ if (wait_event_interruptible(dspi->waitq, dspi->waitflags))
+ dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n");
+ dspi->waitflags = 0;
+
+ return t->len - dspi->len;
+}
+
+static void dspi_chipselect(struct spi_device *spi, int value)
+{
+ struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
+ u32 pushr = readl(dspi->base + SPI_PUSHR);
+
+ switch (value) {
+ case BITBANG_CS_ACTIVE:
+ pushr |= SPI_PUSHR_CONT;
+ case BITBANG_CS_INACTIVE:
+ pushr &= ~SPI_PUSHR_CONT;
+ }
+
+ writel(pushr, dspi->base + SPI_PUSHR);
+}
+
+static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct chip_data *chip;
+ struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
+ unsigned char br = 0, pbr = 0, fmsz = 0;
+
+ /* Only alloc on first setup */
+ chip = spi_get_ctldata(spi);
+ if (chip == NULL) {
+ chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+ }
+
+ chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
+ SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
+ if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
+ fmsz = spi->bits_per_word - 1;
+ } else {
+ pr_err("Invalid wordsize\n");
+ kfree(chip);
+ return -ENODEV;
+ }
+
+ chip->void_write_data = 0;
+
+ hz_to_spi_baud(&pbr, &br,
+ spi->max_speed_hz, clk_get_rate(dspi->clk));
+
+ chip->ctar_val = SPI_CTAR_FMSZ(fmsz)
+ | SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
+ | SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0)
+ | SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0)
+ | SPI_CTAR_PBR(pbr)
+ | SPI_CTAR_BR(br);
+
+ spi_set_ctldata(spi, chip);
+
+ return 0;
+}
+
+static int dspi_setup(struct spi_device *spi)
+{
+ if (!spi->max_speed_hz)
+ return -EINVAL;
+
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ return dspi_setup_transfer(spi, NULL);
+}
+
+static irqreturn_t dspi_interrupt(int irq, void *dev_id)
+{
+ struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
+
+ writel(SPI_SR_EOQF, dspi->base + SPI_SR);
+
+ dspi_transfer_read(dspi);
+
+ if (!dspi->len) {
+ if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
+ set_bit_mode(dspi, 16);
+ dspi->waitflags = 1;
+ wake_up_interruptible(&dspi->waitq);
+ } else {
+ dspi_transfer_write(dspi);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct of_device_id fsl_dspi_dt_ids[] = {
+ { .compatible = "fsl,vf610-dspi", .data = NULL, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids);
+
+#ifdef CONFIG_PM_SLEEP
+static int dspi_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct fsl_dspi *dspi = spi_master_get_devdata(master);
+
+ spi_master_suspend(master);
+ clk_disable_unprepare(dspi->clk);
+
+ return 0;
+}
+
+static int dspi_resume(struct device *dev)
+{
+
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct fsl_dspi *dspi = spi_master_get_devdata(master);
+
+ clk_prepare_enable(dspi->clk);
+ spi_master_resume(master);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops dspi_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume)
+};
+
+static int dspi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct spi_master *master;
+ struct fsl_dspi *dspi;
+ struct resource *res;
+ int ret = 0, cs_num, bus_num;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
+ if (!master)
+ return -ENOMEM;
+
+ dspi = spi_master_get_devdata(master);
+ dspi->pdev = pdev;
+ dspi->bitbang.master = spi_master_get(master);
+ dspi->bitbang.chipselect = dspi_chipselect;
+ dspi->bitbang.setup_transfer = dspi_setup_transfer;
+ dspi->bitbang.txrx_bufs = dspi_txrx_transfer;
+ dspi->bitbang.master->setup = dspi_setup;
+ dspi->bitbang.master->dev.of_node = pdev->dev.of_node;
+
+ master->mode_bits = SPI_CPOL | SPI_CPHA;
+ master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) |
+ SPI_BPW_MASK(16);
+
+ ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't get spi-num-chipselects\n");
+ goto out_master_put;
+ }
+ master->num_chipselect = cs_num;
+
+ ret = of_property_read_u32(np, "bus-num", &bus_num);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't get bus-num\n");
+ goto out_master_put;
+ }
+ master->bus_num = bus_num;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't get platform resource\n");
+ ret = -EINVAL;
+ goto out_master_put;
+ }
+
+ dspi->base = devm_ioremap_resource(&pdev->dev, res);
+ if (!dspi->base) {
+ ret = -EINVAL;
+ goto out_master_put;
+ }
+
+ dspi->irq = platform_get_irq(pdev, 0);
+ if (dspi->irq < 0) {
+ dev_err(&pdev->dev, "can't get platform irq\n");
+ ret = dspi->irq;
+ goto out_master_put;
+ }
+
+ ret = devm_request_irq(&pdev->dev, dspi->irq, dspi_interrupt, 0,
+ pdev->name, dspi);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to attach DSPI interrupt\n");
+ goto out_master_put;
+ }
+
+ dspi->clk = devm_clk_get(&pdev->dev, "dspi");
+ if (IS_ERR(dspi->clk)) {
+ ret = PTR_ERR(dspi->clk);
+ dev_err(&pdev->dev, "unable to get clock\n");
+ goto out_master_put;
+ }
+ clk_prepare_enable(dspi->clk);
+
+ init_waitqueue_head(&dspi->waitq);
+ platform_set_drvdata(pdev, dspi);
+
+ ret = spi_bitbang_start(&dspi->bitbang);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Problem registering DSPI master\n");
+ goto out_clk_put;
+ }
+
+ pr_info(KERN_INFO "Freescale DSPI master initialized\n");
+ return ret;
+
+out_clk_put:
+ clk_disable_unprepare(dspi->clk);
+out_master_put:
+ spi_master_put(master);
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int dspi_remove(struct platform_device *pdev)
+{
+ struct fsl_dspi *dspi = platform_get_drvdata(pdev);
+
+ /* Disconnect from the SPI framework */
+ spi_bitbang_stop(&dspi->bitbang);
+ spi_master_put(dspi->bitbang.master);
+
+ return 0;
+}
+
+static struct platform_driver fsl_dspi_driver = {
+ .driver.name = DRIVER_NAME,
+ .driver.of_match_table = fsl_dspi_dt_ids,
+ .driver.owner = THIS_MODULE,
+ .driver.pm = &dspi_pm,
+ .probe = dspi_probe,
+ .remove = dspi_remove,
+};
+module_platform_driver(fsl_dspi_driver);
+
+MODULE_DESCRIPTION("Freescale DSPI Controller Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 6a74d7848d9..b8f1103fe28 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -584,7 +584,7 @@ static void fsl_espi_remove(struct mpc8xxx_spi *mspi)
static struct spi_master * fsl_espi_probe(struct device *dev,
struct resource *mem, unsigned int irq)
{
- struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct spi_master *master;
struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_espi_reg *reg_base;
@@ -665,7 +665,7 @@ err:
static int of_fsl_espi_get_chipselects(struct device *dev)
{
struct device_node *np = dev->of_node;
- struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
const u32 *prop;
int len;
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index e947f2d1b2f..0b75f26158a 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -122,7 +122,7 @@ const char *mpc8xxx_spi_strmode(unsigned int flags)
int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
unsigned int irq)
{
- struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct spi_master *master;
struct mpc8xxx_spi *mpc8xxx_spi;
int ret = 0;
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 41e89c3e3ed..bbc94294891 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -574,7 +574,7 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
static void fsl_spi_grlib_probe(struct device *dev)
{
- struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct spi_master *master = dev_get_drvdata(dev);
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base;
@@ -600,7 +600,7 @@ static void fsl_spi_grlib_probe(struct device *dev)
static struct spi_master * fsl_spi_probe(struct device *dev,
struct resource *mem, unsigned int irq)
{
- struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct spi_master *master;
struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_spi_reg *reg_base;
@@ -700,7 +700,8 @@ err:
static void fsl_spi_cs_control(struct spi_device *spi, bool on)
{
struct device *dev = spi->dev.parent->parent;
- struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
+ struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
u16 cs = spi->chip_select;
int gpio = pinfo->gpios[cs];
bool alow = pinfo->alow_flags[cs];
@@ -711,7 +712,7 @@ static void fsl_spi_cs_control(struct spi_device *spi, bool on)
static int of_fsl_spi_get_chipselects(struct device *dev)
{
struct device_node *np = dev->of_node;
- struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
int ngpios;
int i = 0;
@@ -790,7 +791,7 @@ err_alloc_flags:
static int of_fsl_spi_free_chipselects(struct device *dev)
{
- struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
int i;
@@ -889,7 +890,7 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
int irq;
struct spi_master *master;
- if (!pdev->dev.platform_data)
+ if (!dev_get_platdata(&pdev->dev))
return -EINVAL;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index a54524cf42c..68b69fec13a 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -420,7 +420,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
if (status > 0)
use_of = 1;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
#ifdef GENERIC_BITBANG
if (!pdata || !pdata->num_chipselect)
return -ENODEV;
@@ -506,7 +506,7 @@ static int spi_gpio_remove(struct platform_device *pdev)
int status;
spi_gpio = platform_get_drvdata(pdev);
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
/* stop() unregisters child devices too */
status = spi_bitbang_stop(&spi_gpio->bitbang);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 7db4f43ee4d..15323d8bd9c 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -619,6 +619,7 @@ static const struct of_device_id spi_imx_dt_ids[] = {
{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
static void spi_imx_chipselect(struct spi_device *spi, int is_active)
{
@@ -796,10 +797,11 @@ static int spi_imx_probe(struct platform_device *pdev)
if (!gpio_is_valid(cs_gpio))
continue;
- ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
+ ret = devm_gpio_request(&pdev->dev, spi_imx->chipselect[i],
+ DRIVER_NAME);
if (ret) {
dev_err(&pdev->dev, "can't get cs gpios\n");
- goto out_gpio_free;
+ goto out_master_put;
}
}
@@ -816,50 +818,44 @@ static int spi_imx_probe(struct platform_device *pdev)
(struct spi_imx_devtype_data *) pdev->id_entry->driver_data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "can't get platform resource\n");
- ret = -ENOMEM;
- goto out_gpio_free;
- }
-
- if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
- dev_err(&pdev->dev, "request_mem_region failed\n");
- ret = -EBUSY;
- goto out_gpio_free;
- }
-
- spi_imx->base = ioremap(res->start, resource_size(res));
- if (!spi_imx->base) {
- ret = -EINVAL;
- goto out_release_mem;
+ spi_imx->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(spi_imx->base)) {
+ ret = PTR_ERR(spi_imx->base);
+ goto out_master_put;
}
spi_imx->irq = platform_get_irq(pdev, 0);
if (spi_imx->irq < 0) {
ret = -EINVAL;
- goto out_iounmap;
+ goto out_master_put;
}
- ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx);
+ ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0,
+ DRIVER_NAME, spi_imx);
if (ret) {
dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
- goto out_iounmap;
+ goto out_master_put;
}
spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(spi_imx->clk_ipg)) {
ret = PTR_ERR(spi_imx->clk_ipg);
- goto out_free_irq;
+ goto out_master_put;
}
spi_imx->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(spi_imx->clk_per)) {
ret = PTR_ERR(spi_imx->clk_per);
- goto out_free_irq;
+ goto out_master_put;
}
- clk_prepare_enable(spi_imx->clk_per);
- clk_prepare_enable(spi_imx->clk_ipg);
+ ret = clk_prepare_enable(spi_imx->clk_per);
+ if (ret)
+ goto out_master_put;
+
+ ret = clk_prepare_enable(spi_imx->clk_ipg);
+ if (ret)
+ goto out_put_per;
spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per);
@@ -879,47 +875,27 @@ static int spi_imx_probe(struct platform_device *pdev)
return ret;
out_clk_put:
- clk_disable_unprepare(spi_imx->clk_per);
clk_disable_unprepare(spi_imx->clk_ipg);
-out_free_irq:
- free_irq(spi_imx->irq, spi_imx);
-out_iounmap:
- iounmap(spi_imx->base);
-out_release_mem:
- release_mem_region(res->start, resource_size(res));
-out_gpio_free:
- while (--i >= 0) {
- if (gpio_is_valid(spi_imx->chipselect[i]))
- gpio_free(spi_imx->chipselect[i]);
- }
+out_put_per:
+ clk_disable_unprepare(spi_imx->clk_per);
+out_master_put:
spi_master_put(master);
- kfree(master);
+
return ret;
}
static int spi_imx_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
- int i;
spi_bitbang_stop(&spi_imx->bitbang);
writel(0, spi_imx->base + MXC_CSPICTRL);
- clk_disable_unprepare(spi_imx->clk_per);
clk_disable_unprepare(spi_imx->clk_ipg);
- free_irq(spi_imx->irq, spi_imx);
- iounmap(spi_imx->base);
-
- for (i = 0; i < master->num_chipselect; i++)
- if (gpio_is_valid(spi_imx->chipselect[i]))
- gpio_free(spi_imx->chipselect[i]);
-
+ clk_disable_unprepare(spi_imx->clk_per);
spi_master_put(master);
- release_mem_region(res->start, resource_size(res));
-
return 0;
}
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 29fce6af514..dbc5e999a1f 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -38,7 +38,8 @@ struct mpc512x_psc_spi {
struct mpc512x_psc_fifo __iomem *fifo;
unsigned int irq;
u8 bits_per_word;
- u32 mclk;
+ struct clk *clk_mclk;
+ u32 mclk_rate;
struct completion txisrdone;
};
@@ -72,6 +73,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
struct mpc52xx_psc __iomem *psc = mps->psc;
u32 sicr;
u32 ccr;
+ int speed;
u16 bclkdiv;
sicr = in_be32(&psc->sicr);
@@ -95,10 +97,10 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
ccr = in_be32(&psc->ccr);
ccr &= 0xFF000000;
- if (cs->speed_hz)
- bclkdiv = (mps->mclk / cs->speed_hz) - 1;
- else
- bclkdiv = (mps->mclk / 1000000) - 1; /* default 1MHz */
+ speed = cs->speed_hz;
+ if (!speed)
+ speed = 1000000; /* default 1MHz */
+ bclkdiv = (mps->mclk_rate / speed) - 1;
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
out_be32(&psc->ccr, ccr);
@@ -386,19 +388,11 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
{
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
- struct clk *spiclk;
- int ret = 0;
- char name[32];
u32 sicr;
u32 ccr;
+ int speed;
u16 bclkdiv;
- sprintf(name, "psc%d_mclk", master->bus_num);
- spiclk = clk_get(&master->dev, name);
- clk_enable(spiclk);
- mps->mclk = clk_get_rate(spiclk);
- clk_put(spiclk);
-
/* Reset the PSC into a known state */
out_8(&psc->command, MPC52xx_PSC_RST_RX);
out_8(&psc->command, MPC52xx_PSC_RST_TX);
@@ -425,7 +419,8 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
ccr = in_be32(&psc->ccr);
ccr &= 0xFF000000;
- bclkdiv = (mps->mclk / 1000000) - 1; /* default 1MHz */
+ speed = 1000000; /* default 1MHz */
+ bclkdiv = (mps->mclk_rate / speed) - 1;
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
out_be32(&psc->ccr, ccr);
@@ -445,7 +440,7 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
mps->bits_per_word = 8;
- return ret;
+ return 0;
}
static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
@@ -474,11 +469,14 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
u32 size, unsigned int irq,
s16 bus_num)
{
- struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct mpc512x_psc_spi *mps;
struct spi_master *master;
int ret;
void *tempp;
+ int psc_num;
+ char clk_name[16];
+ struct clk *clk;
master = spi_alloc_master(dev, sizeof *mps);
if (master == NULL)
@@ -521,16 +519,29 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
goto free_master;
init_completion(&mps->txisrdone);
+ psc_num = master->bus_num;
+ snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
+ clk = devm_clk_get(dev, clk_name);
+ if (IS_ERR(clk))
+ goto free_irq;
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ goto free_irq;
+ mps->clk_mclk = clk;
+ mps->mclk_rate = clk_get_rate(clk);
+
ret = mpc512x_psc_spi_port_config(master, mps);
if (ret < 0)
- goto free_irq;
+ goto free_clock;
ret = spi_register_master(master);
if (ret < 0)
- goto free_irq;
+ goto free_clock;
return ret;
+free_clock:
+ clk_disable_unprepare(mps->clk_mclk);
free_irq:
free_irq(mps->irq, mps);
free_master:
@@ -547,6 +558,7 @@ static int mpc512x_psc_spi_do_remove(struct device *dev)
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
spi_unregister_master(master);
+ clk_disable_unprepare(mps->clk_mclk);
free_irq(mps->irq, mps);
if (mps->psc)
iounmap(mps->psc);
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index fed0571d4de..6e925dc3439 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -366,7 +366,7 @@ static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
u32 size, unsigned int irq, s16 bus_num)
{
- struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct mpc52xx_psc_spi *mps;
struct spi_master *master;
int ret;
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 424d38e5942..de7b1141b90 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -67,13 +67,8 @@ static int mxs_spi_setup_transfer(struct spi_device *dev,
{
struct mxs_spi *spi = spi_master_get_devdata(dev->master);
struct mxs_ssp *ssp = &spi->ssp;
- uint8_t bits_per_word;
uint32_t hz = 0;
- bits_per_word = dev->bits_per_word;
- if (t && t->bits_per_word)
- bits_per_word = t->bits_per_word;
-
hz = dev->max_speed_hz;
if (t && t->speed_hz)
hz = min(hz, t->speed_hz);
@@ -513,7 +508,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq_err = platform_get_irq(pdev, 0);
- if (!iores || irq_err < 0)
+ if (irq_err < 0)
return -EINVAL;
base = devm_ioremap_resource(&pdev->dev, iores);
@@ -563,25 +558,31 @@ static int mxs_spi_probe(struct platform_device *pdev)
goto out_master_free;
}
- clk_prepare_enable(ssp->clk);
+ ret = clk_prepare_enable(ssp->clk);
+ if (ret)
+ goto out_dma_release;
+
clk_set_rate(ssp->clk, clk_freq);
ssp->clk_rate = clk_get_rate(ssp->clk) / 1000;
- stmp_reset_block(ssp->base);
+ ret = stmp_reset_block(ssp->base);
+ if (ret)
+ goto out_disable_clk;
platform_set_drvdata(pdev, master);
ret = spi_register_master(master);
if (ret) {
dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret);
- goto out_free_dma;
+ goto out_disable_clk;
}
return 0;
-out_free_dma:
- dma_release_channel(ssp->dmach);
+out_disable_clk:
clk_disable_unprepare(ssp->clk);
+out_dma_release:
+ dma_release_channel(ssp->dmach);
out_master_free:
spi_master_put(master);
return ret;
@@ -598,11 +599,8 @@ static int mxs_spi_remove(struct platform_device *pdev)
ssp = &spi->ssp;
spi_unregister_master(master);
-
- dma_release_channel(ssp->dmach);
-
clk_disable_unprepare(ssp->clk);
-
+ dma_release_channel(ssp->dmach);
spi_master_put(master);
return 0;
diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c
index 150d85453c2..47a68b43bcd 100644
--- a/drivers/spi/spi-nuc900.c
+++ b/drivers/spi/spi-nuc900.c
@@ -174,17 +174,6 @@ static void nuc900_spi_gobusy(struct nuc900_spi *hw)
spin_unlock_irqrestore(&hw->lock, flags);
}
-static int nuc900_spi_setupxfer(struct spi_device *spi,
- struct spi_transfer *t)
-{
- return 0;
-}
-
-static int nuc900_spi_setup(struct spi_device *spi)
-{
- return 0;
-}
-
static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count)
{
return hw->tx ? hw->tx[count] : 0;
@@ -361,7 +350,7 @@ static int nuc900_spi_probe(struct platform_device *pdev)
hw = spi_master_get_devdata(master);
hw->master = spi_master_get(master);
- hw->pdata = pdev->dev.platform_data;
+ hw->pdata = dev_get_platdata(&pdev->dev);
hw->dev = &pdev->dev;
if (hw->pdata == NULL) {
@@ -373,14 +362,12 @@ static int nuc900_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hw);
init_completion(&hw->done);
- master->mode_bits = SPI_MODE_0;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->num_chipselect = hw->pdata->num_cs;
master->bus_num = hw->pdata->bus_num;
hw->bitbang.master = hw->master;
- hw->bitbang.setup_transfer = nuc900_spi_setupxfer;
hw->bitbang.chipselect = nuc900_spi_chipsel;
hw->bitbang.txrx_bufs = nuc900_spi_txrx;
- hw->bitbang.master->setup = nuc900_spi_setup;
hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (hw->res == NULL) {
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index 58deb79d046..333cb1badcd 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -285,7 +285,7 @@ static int tiny_spi_of_probe(struct platform_device *pdev)
static int tiny_spi_probe(struct platform_device *pdev)
{
- struct tiny_spi_platform_data *platp = pdev->dev.platform_data;
+ struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
struct tiny_spi *hw;
struct spi_master *master;
struct resource *res;
@@ -315,15 +315,11 @@ static int tiny_spi_probe(struct platform_device *pdev)
/* find and map our resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- goto exit_busy;
- if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
- pdev->name))
- goto exit_busy;
- hw->base = devm_ioremap_nocache(&pdev->dev, res->start,
- resource_size(res));
- if (!hw->base)
- goto exit_busy;
+ hw->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hw->base)) {
+ err = PTR_ERR(hw->base);
+ goto exit;
+ }
/* irq is optional */
hw->irq = platform_get_irq(pdev, 0);
if (hw->irq >= 0) {
@@ -337,8 +333,10 @@ static int tiny_spi_probe(struct platform_device *pdev)
if (platp) {
hw->gpio_cs_count = platp->gpio_cs_count;
hw->gpio_cs = platp->gpio_cs;
- if (platp->gpio_cs_count && !platp->gpio_cs)
- goto exit_busy;
+ if (platp->gpio_cs_count && !platp->gpio_cs) {
+ err = -EBUSY;
+ goto exit;
+ }
hw->freq = platp->freq;
hw->baudwidth = platp->baudwidth;
} else {
@@ -365,8 +363,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
exit_gpio:
while (i-- > 0)
gpio_free(hw->gpio_cs[i]);
-exit_busy:
- err = -EBUSY;
exit:
spi_master_put(master);
return err;
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index 24daf964a40..5f28ddbe4f7 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -28,7 +28,6 @@
#define OCTEON_SPI_MAX_CLOCK_HZ 16000000
struct octeon_spi {
- struct spi_master *my_master;
u64 register_base;
u64 last_cfg;
u64 cs_enax;
@@ -64,7 +63,6 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
unsigned int speed_hz;
int mode;
bool cpha, cpol;
- int bits_per_word;
const u8 *tx_buf;
u8 *rx_buf;
int len;
@@ -76,12 +74,9 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
mode = msg_setup->mode;
cpha = mode & SPI_CPHA;
cpol = mode & SPI_CPOL;
- bits_per_word = msg_setup->bits_per_word;
if (xfer->speed_hz)
speed_hz = xfer->speed_hz;
- if (xfer->bits_per_word)
- bits_per_word = xfer->bits_per_word;
if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ)
speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
@@ -166,19 +161,6 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
return xfer->len;
}
-static int octeon_spi_validate_bpw(struct spi_device *spi, u32 speed)
-{
- switch (speed) {
- case 8:
- break;
- default:
- dev_err(&spi->dev, "Error: %d bits per word not supported\n",
- speed);
- return -EINVAL;
- }
- return 0;
-}
-
static int octeon_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -197,15 +179,6 @@ static int octeon_spi_transfer_one_message(struct spi_master *master,
}
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- if (xfer->bits_per_word) {
- status = octeon_spi_validate_bpw(msg->spi,
- xfer->bits_per_word);
- if (status)
- goto err;
- }
- }
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
bool last_xfer = &xfer->transfer_list == msg->transfers.prev;
int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer);
if (r < 0) {
@@ -236,14 +209,9 @@ static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi)
static int octeon_spi_setup(struct spi_device *spi)
{
- int r;
struct octeon_spi_setup *new_setup;
struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
- r = octeon_spi_validate_bpw(spi, spi->bits_per_word);
- if (r)
- return r;
-
new_setup = octeon_spi_new_setup(spi);
if (!new_setup)
return -ENOMEM;
@@ -261,14 +229,8 @@ static void octeon_spi_cleanup(struct spi_device *spi)
kfree(old_setup);
}
-static int octeon_spi_nop_transfer_hardware(struct spi_master *master)
-{
- return 0;
-}
-
static int octeon_spi_probe(struct platform_device *pdev)
{
-
struct resource *res_mem;
struct spi_master *master;
struct octeon_spi *p;
@@ -278,8 +240,7 @@ static int octeon_spi_probe(struct platform_device *pdev)
if (!master)
return -ENOMEM;
p = spi_master_get_devdata(master);
- platform_set_drvdata(pdev, p);
- p->my_master = master;
+ platform_set_drvdata(pdev, master);
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -307,9 +268,8 @@ static int octeon_spi_probe(struct platform_device *pdev)
master->setup = octeon_spi_setup;
master->cleanup = octeon_spi_cleanup;
- master->prepare_transfer_hardware = octeon_spi_nop_transfer_hardware;
master->transfer_one_message = octeon_spi_transfer_one_message;
- master->unprepare_transfer_hardware = octeon_spi_nop_transfer_hardware;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = pdev->dev.of_node;
err = spi_register_master(master);
@@ -328,10 +288,11 @@ fail:
static int octeon_spi_remove(struct platform_device *pdev)
{
- struct octeon_spi *p = platform_get_drvdata(pdev);
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct octeon_spi *p = spi_master_get_devdata(master);
u64 register_base = p->register_base;
- spi_unregister_master(p->my_master);
+ spi_unregister_master(master);
/* Clear the CSENA* and put everything in a known state. */
cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0);
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index ee25670f8cf..69ecf05757d 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -83,11 +83,6 @@
#define SPI_SHUTDOWN 1
struct omap1_spi100k {
- struct work_struct work;
-
- /* lock protects queue and registers */
- spinlock_t lock;
- struct list_head msg_queue;
struct spi_master *master;
struct clk *ick;
struct clk *fck;
@@ -104,8 +99,6 @@ struct omap1_spi100k_cs {
int word_len;
};
-static struct workqueue_struct *omap1_spi100k_wq;
-
#define MOD_REG_BIT(val, mask, set) do { \
if (set) \
val |= mask; \
@@ -310,170 +303,102 @@ static int omap1_spi100k_setup(struct spi_device *spi)
spi100k_open(spi->master);
- clk_enable(spi100k->ick);
- clk_enable(spi100k->fck);
+ clk_prepare_enable(spi100k->ick);
+ clk_prepare_enable(spi100k->fck);
ret = omap1_spi100k_setup_transfer(spi, NULL);
- clk_disable(spi100k->ick);
- clk_disable(spi100k->fck);
+ clk_disable_unprepare(spi100k->ick);
+ clk_disable_unprepare(spi100k->fck);
return ret;
}
-static void omap1_spi100k_work(struct work_struct *work)
+static int omap1_spi100k_prepare_hardware(struct spi_master *master)
{
- struct omap1_spi100k *spi100k;
- int status = 0;
+ struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
- spi100k = container_of(work, struct omap1_spi100k, work);
- spin_lock_irq(&spi100k->lock);
+ clk_prepare_enable(spi100k->ick);
+ clk_prepare_enable(spi100k->fck);
- clk_enable(spi100k->ick);
- clk_enable(spi100k->fck);
+ return 0;
+}
- /* We only enable one channel at a time -- the one whose message is
- * at the head of the queue -- although this controller would gladly
- * arbitrate among multiple channels. This corresponds to "single
- * channel" master mode. As a side effect, we need to manage the
- * chipselect with the FORCE bit ... CS != channel enable.
- */
- while (!list_empty(&spi100k->msg_queue)) {
- struct spi_message *m;
- struct spi_device *spi;
- struct spi_transfer *t = NULL;
- int cs_active = 0;
- struct omap1_spi100k_cs *cs;
- int par_override = 0;
-
- m = container_of(spi100k->msg_queue.next, struct spi_message,
- queue);
-
- list_del_init(&m->queue);
- spin_unlock_irq(&spi100k->lock);
-
- spi = m->spi;
- cs = spi->controller_state;
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
- status = -EINVAL;
+static int omap1_spi100k_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t = NULL;
+ int cs_active = 0;
+ int par_override = 0;
+ int status = 0;
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+ status = -EINVAL;
+ break;
+ }
+ if (par_override || t->speed_hz || t->bits_per_word) {
+ par_override = 1;
+ status = omap1_spi100k_setup_transfer(spi, t);
+ if (status < 0)
break;
- }
- if (par_override || t->speed_hz || t->bits_per_word) {
- par_override = 1;
- status = omap1_spi100k_setup_transfer(spi, t);
- if (status < 0)
- break;
- if (!t->speed_hz && !t->bits_per_word)
- par_override = 0;
- }
+ if (!t->speed_hz && !t->bits_per_word)
+ par_override = 0;
+ }
- if (!cs_active) {
- omap1_spi100k_force_cs(spi100k, 1);
- cs_active = 1;
- }
+ if (!cs_active) {
+ omap1_spi100k_force_cs(spi100k, 1);
+ cs_active = 1;
+ }
- if (t->len) {
- unsigned count;
+ if (t->len) {
+ unsigned count;
- count = omap1_spi100k_txrx_pio(spi, t);
- m->actual_length += count;
+ count = omap1_spi100k_txrx_pio(spi, t);
+ m->actual_length += count;
- if (count != t->len) {
- status = -EIO;
- break;
- }
+ if (count != t->len) {
+ status = -EIO;
+ break;
}
+ }
- if (t->delay_usecs)
- udelay(t->delay_usecs);
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
- /* ignore the "leave it on after last xfer" hint */
+ /* ignore the "leave it on after last xfer" hint */
- if (t->cs_change) {
- omap1_spi100k_force_cs(spi100k, 0);
- cs_active = 0;
- }
- }
-
- /* Restore defaults if they were overriden */
- if (par_override) {
- par_override = 0;
- status = omap1_spi100k_setup_transfer(spi, NULL);
+ if (t->cs_change) {
+ omap1_spi100k_force_cs(spi100k, 0);
+ cs_active = 0;
}
+ }
- if (cs_active)
- omap1_spi100k_force_cs(spi100k, 0);
+ /* Restore defaults if they were overriden */
+ if (par_override) {
+ par_override = 0;
+ status = omap1_spi100k_setup_transfer(spi, NULL);
+ }
- m->status = status;
- m->complete(m->context);
+ if (cs_active)
+ omap1_spi100k_force_cs(spi100k, 0);
- spin_lock_irq(&spi100k->lock);
- }
+ m->status = status;
- clk_disable(spi100k->ick);
- clk_disable(spi100k->fck);
- spin_unlock_irq(&spi100k->lock);
+ spi_finalize_current_message(master);
- if (status < 0)
- printk(KERN_WARNING "spi transfer failed with %d\n", status);
+ return status;
}
-static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
+static int omap1_spi100k_unprepare_hardware(struct spi_master *master)
{
- struct omap1_spi100k *spi100k;
- unsigned long flags;
- struct spi_transfer *t;
-
- m->actual_length = 0;
- m->status = -EINPROGRESS;
-
- spi100k = spi_master_get_devdata(spi->master);
-
- /* Don't accept new work if we're shutting down */
- if (spi100k->state == SPI_SHUTDOWN)
- return -ESHUTDOWN;
-
- /* reject invalid messages and transfers */
- if (list_empty(&m->transfers) || !m->complete)
- return -EINVAL;
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- const void *tx_buf = t->tx_buf;
- void *rx_buf = t->rx_buf;
- unsigned len = t->len;
-
- if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
- || (len && !(rx_buf || tx_buf))) {
- dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
- t->speed_hz,
- len,
- tx_buf ? "tx" : "",
- rx_buf ? "rx" : "",
- t->bits_per_word);
- return -EINVAL;
- }
-
- if (t->speed_hz && t->speed_hz < OMAP1_SPI100K_MAX_FREQ/(1<<16)) {
- dev_dbg(&spi->dev, "%d Hz max exceeds %d\n",
- t->speed_hz,
- OMAP1_SPI100K_MAX_FREQ/(1<<16));
- return -EINVAL;
- }
-
- }
-
- spin_lock_irqsave(&spi100k->lock, flags);
- list_add_tail(&m->queue, &spi100k->msg_queue);
- queue_work(omap1_spi100k_wq, &spi100k->work);
- spin_unlock_irqrestore(&spi100k->lock, flags);
+ struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
- return 0;
-}
+ clk_disable_unprepare(spi100k->ick);
+ clk_disable_unprepare(spi100k->fck);
-static int omap1_spi100k_reset(struct omap1_spi100k *spi100k)
-{
return 0;
}
@@ -496,11 +421,15 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
master->bus_num = pdev->id;
master->setup = omap1_spi100k_setup;
- master->transfer = omap1_spi100k_transfer;
+ master->transfer_one_message = omap1_spi100k_transfer_one_message;
+ master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware;
+ master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware;
master->cleanup = NULL;
master->num_chipselect = 2;
master->mode_bits = MODEBITS;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16);
+ master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ;
platform_set_drvdata(pdev, master);
@@ -512,42 +441,31 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
* You should allocate this with ioremap() before initializing
* the SPI.
*/
- spi100k->base = (void __iomem *) pdev->dev.platform_data;
-
- INIT_WORK(&spi100k->work, omap1_spi100k_work);
+ spi100k->base = (void __iomem *)dev_get_platdata(&pdev->dev);
- spin_lock_init(&spi100k->lock);
- INIT_LIST_HEAD(&spi100k->msg_queue);
- spi100k->ick = clk_get(&pdev->dev, "ick");
+ spi100k->ick = devm_clk_get(&pdev->dev, "ick");
if (IS_ERR(spi100k->ick)) {
dev_dbg(&pdev->dev, "can't get spi100k_ick\n");
status = PTR_ERR(spi100k->ick);
- goto err1;
+ goto err;
}
- spi100k->fck = clk_get(&pdev->dev, "fck");
+ spi100k->fck = devm_clk_get(&pdev->dev, "fck");
if (IS_ERR(spi100k->fck)) {
dev_dbg(&pdev->dev, "can't get spi100k_fck\n");
status = PTR_ERR(spi100k->fck);
- goto err2;
+ goto err;
}
- if (omap1_spi100k_reset(spi100k) < 0)
- goto err3;
-
status = spi_register_master(master);
if (status < 0)
- goto err3;
+ goto err;
spi100k->state = SPI_RUNNING;
return status;
-err3:
- clk_put(spi100k->fck);
-err2:
- clk_put(spi100k->ick);
-err1:
+err:
spi_master_put(master);
return status;
}
@@ -557,33 +475,14 @@ static int omap1_spi100k_remove(struct platform_device *pdev)
struct spi_master *master;
struct omap1_spi100k *spi100k;
struct resource *r;
- unsigned limit = 500;
- unsigned long flags;
int status = 0;
master = platform_get_drvdata(pdev);
spi100k = spi_master_get_devdata(master);
- spin_lock_irqsave(&spi100k->lock, flags);
-
- spi100k->state = SPI_SHUTDOWN;
- while (!list_empty(&spi100k->msg_queue) && limit--) {
- spin_unlock_irqrestore(&spi100k->lock, flags);
- msleep(10);
- spin_lock_irqsave(&spi100k->lock, flags);
- }
-
- if (!list_empty(&spi100k->msg_queue))
- status = -EBUSY;
-
- spin_unlock_irqrestore(&spi100k->lock, flags);
-
if (status != 0)
return status;
- clk_put(spi100k->fck);
- clk_put(spi100k->ick);
-
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spi_unregister_master(master);
@@ -596,30 +495,11 @@ static struct platform_driver omap1_spi100k_driver = {
.name = "omap1_spi100k",
.owner = THIS_MODULE,
},
+ .probe = omap1_spi100k_probe,
.remove = omap1_spi100k_remove,
};
-
-static int __init omap1_spi100k_init(void)
-{
- omap1_spi100k_wq = create_singlethread_workqueue(
- omap1_spi100k_driver.driver.name);
-
- if (omap1_spi100k_wq == NULL)
- return -1;
-
- return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe);
-}
-
-static void __exit omap1_spi100k_exit(void)
-{
- platform_driver_unregister(&omap1_spi100k_driver);
-
- destroy_workqueue(omap1_spi100k_wq);
-}
-
-module_init(omap1_spi100k_init);
-module_exit(omap1_spi100k_exit);
+module_platform_driver(omap1_spi100k_driver);
MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver");
MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>");
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 5994039758d..ed4af4708d9 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -335,23 +335,6 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
}
-static int omap2_prepare_transfer(struct spi_master *master)
-{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
-
- pm_runtime_get_sync(mcspi->dev);
- return 0;
-}
-
-static int omap2_unprepare_transfer(struct spi_master *master)
-{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
-
- pm_runtime_mark_last_busy(mcspi->dev);
- pm_runtime_put_autosuspend(mcspi->dev);
- return 0;
-}
-
static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
{
unsigned long timeout;
@@ -1318,8 +1301,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
master->setup = omap2_mcspi_setup;
- master->prepare_transfer_hardware = omap2_prepare_transfer;
- master->unprepare_transfer_hardware = omap2_unprepare_transfer;
+ master->auto_runtime_pm = true;
master->transfer_one_message = omap2_mcspi_transfer_one_message;
master->cleanup = omap2_mcspi_cleanup;
master->dev.of_node = node;
@@ -1340,7 +1322,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL))
mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
} else {
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
master->num_chipselect = pdata->num_cs;
if (pdev->id != -1)
master->bus_num = pdev->id;
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 5d90bebaa0f..1d1d321d90c 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/clk.h>
+#include <linux/sizes.h>
#include <asm/unaligned.h>
#define DRIVER_NAME "orion_spi"
@@ -446,30 +447,22 @@ static int orion_spi_probe(struct platform_device *pdev)
spi->min_speed = DIV_ROUND_UP(tclk_hz, 30);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- status = -ENODEV;
+ spi->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(spi->base)) {
+ status = PTR_ERR(spi->base);
goto out_rel_clk;
}
- if (!request_mem_region(r->start, resource_size(r),
- dev_name(&pdev->dev))) {
- status = -EBUSY;
- goto out_rel_clk;
- }
- spi->base = ioremap(r->start, SZ_1K);
-
if (orion_spi_reset(spi) < 0)
- goto out_rel_mem;
+ goto out_rel_clk;
master->dev.of_node = pdev->dev.of_node;
status = spi_register_master(master);
if (status < 0)
- goto out_rel_mem;
+ goto out_rel_clk;
return status;
-out_rel_mem:
- release_mem_region(r->start, resource_size(r));
out_rel_clk:
clk_disable_unprepare(spi->clk);
clk_put(spi->clk);
@@ -482,7 +475,6 @@ out:
static int orion_spi_remove(struct platform_device *pdev)
{
struct spi_master *master;
- struct resource *r;
struct orion_spi *spi;
master = platform_get_drvdata(pdev);
@@ -491,9 +483,6 @@ static int orion_spi_remove(struct platform_device *pdev)
clk_disable_unprepare(spi->clk);
clk_put(spi->clk);
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(r->start, resource_size(r));
-
spi_unregister_master(master);
return 0;
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index abef061fb84..9c511a954d2 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -1555,18 +1555,6 @@ static int pl022_transfer_one_message(struct spi_master *master,
return 0;
}
-static int pl022_prepare_transfer_hardware(struct spi_master *master)
-{
- struct pl022 *pl022 = spi_master_get_devdata(master);
-
- /*
- * Just make sure we have all we need to run the transfer by syncing
- * with the runtime PM framework.
- */
- pm_runtime_get_sync(&pl022->adev->dev);
- return 0;
-}
-
static int pl022_unprepare_transfer_hardware(struct spi_master *master)
{
struct pl022 *pl022 = spi_master_get_devdata(master);
@@ -1575,13 +1563,6 @@ static int pl022_unprepare_transfer_hardware(struct spi_master *master)
writew((readw(SSP_CR1(pl022->virtbase)) &
(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
- if (pl022->master_info->autosuspend_delay > 0) {
- pm_runtime_mark_last_busy(&pl022->adev->dev);
- pm_runtime_put_autosuspend(&pl022->adev->dev);
- } else {
- pm_runtime_put(&pl022->adev->dev);
- }
-
return 0;
}
@@ -2091,7 +2072,8 @@ pl022_platform_data_dt_get(struct device *dev)
static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
- struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
+ struct pl022_ssp_controller *platform_info =
+ dev_get_platdata(&adev->dev);
struct spi_master *master;
struct pl022 *pl022 = NULL; /*Data for this driver */
struct device_node *np = adev->dev.of_node;
@@ -2139,7 +2121,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
master->num_chipselect = num_cs;
master->cleanup = pl022_cleanup;
master->setup = pl022_setup;
- master->prepare_transfer_hardware = pl022_prepare_transfer_hardware;
+ master->auto_runtime_pm = true;
master->transfer_one_message = pl022_transfer_one_message;
master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
master->rt = platform_info->rt;
@@ -2193,8 +2175,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
status = -ENOMEM;
goto err_no_ioremap;
}
- printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n",
- adev->res.start, pl022->virtbase);
+ printk(KERN_INFO "pl022: mapped registers from %pa to %p\n",
+ &adev->res.start, pl022->virtbase);
pl022->clk = devm_clk_get(&adev->dev, NULL);
if (IS_ERR(pl022->clk)) {
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index f440dcee852..2eb06ee0b32 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -69,6 +69,8 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define LPSS_TX_HITHRESH_DFLT 224
/* Offset from drv_data->lpss_base */
+#define GENERAL_REG 0x08
+#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
#define SSP_REG 0x0c
#define SPI_CS_CONTROL 0x18
#define SPI_CS_CONTROL_SW_MODE BIT(0)
@@ -142,8 +144,13 @@ detection_done:
__lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
/* Enable multiblock DMA transfers */
- if (drv_data->master_info->enable_dma)
+ if (drv_data->master_info->enable_dma) {
__lpss_ssp_write_priv(drv_data, SSP_REG, 1);
+
+ value = __lpss_ssp_read_priv(drv_data, GENERAL_REG);
+ value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE;
+ __lpss_ssp_write_priv(drv_data, GENERAL_REG, value);
+ }
}
static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
@@ -804,14 +811,6 @@ static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
return 0;
}
-static int pxa2xx_spi_prepare_transfer(struct spi_master *master)
-{
- struct driver_data *drv_data = spi_master_get_devdata(master);
-
- pm_runtime_get_sync(&drv_data->pdev->dev);
- return 0;
-}
-
static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
{
struct driver_data *drv_data = spi_master_get_devdata(master);
@@ -820,8 +819,6 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE,
drv_data->ioaddr);
- pm_runtime_mark_last_busy(&drv_data->pdev->dev);
- pm_runtime_put_autosuspend(&drv_data->pdev->dev);
return 0;
}
@@ -1134,8 +1131,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
master->cleanup = cleanup;
master->setup = setup;
master->transfer_one_message = pxa2xx_spi_transfer_one_message;
- master->prepare_transfer_hardware = pxa2xx_spi_prepare_transfer;
master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
+ master->auto_runtime_pm = true;
drv_data->ssp_type = ssp->type;
drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index b44a6ac3cec..8719206a03a 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -564,8 +564,12 @@ static void rspi_work(struct work_struct *work)
unsigned long flags;
int ret;
- spin_lock_irqsave(&rspi->lock, flags);
- while (!list_empty(&rspi->queue)) {
+ while (1) {
+ spin_lock_irqsave(&rspi->lock, flags);
+ if (list_empty(&rspi->queue)) {
+ spin_unlock_irqrestore(&rspi->lock, flags);
+ break;
+ }
mesg = list_entry(rspi->queue.next, struct spi_message, queue);
list_del_init(&mesg->queue);
spin_unlock_irqrestore(&rspi->lock, flags);
@@ -595,8 +599,6 @@ static void rspi_work(struct work_struct *work)
mesg->status = 0;
mesg->complete(mesg->context);
-
- spin_lock_irqsave(&rspi->lock, flags);
}
return;
@@ -664,12 +666,13 @@ static irqreturn_t rspi_irq(int irq, void *_sr)
static int rspi_request_dma(struct rspi_data *rspi,
struct platform_device *pdev)
{
- struct rspi_plat_data *rspi_pd = pdev->dev.platform_data;
+ struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dma_cap_mask_t mask;
struct dma_slave_config cfg;
int ret;
- if (!rspi_pd)
+ if (!res || !rspi_pd)
return 0; /* The driver assumes no error. */
rspi->dma_width_16bit = rspi_pd->dma_width_16bit;
@@ -683,6 +686,8 @@ static int rspi_request_dma(struct rspi_data *rspi,
if (rspi->chan_rx) {
cfg.slave_id = rspi_pd->dma_rx_id;
cfg.direction = DMA_DEV_TO_MEM;
+ cfg.dst_addr = 0;
+ cfg.src_addr = res->start + RSPI_SPDR;
ret = dmaengine_slave_config(rspi->chan_rx, &cfg);
if (!ret)
dev_info(&pdev->dev, "Use DMA when rx.\n");
@@ -698,6 +703,8 @@ static int rspi_request_dma(struct rspi_data *rspi,
if (rspi->chan_tx) {
cfg.slave_id = rspi_pd->dma_tx_id;
cfg.direction = DMA_MEM_TO_DEV;
+ cfg.dst_addr = res->start + RSPI_SPDR;
+ cfg.src_addr = 0;
ret = dmaengine_slave_config(rspi->chan_tx, &cfg);
if (!ret)
dev_info(&pdev->dev, "Use DMA when tx\n");
@@ -719,7 +726,7 @@ static void rspi_release_dma(struct rspi_data *rspi)
static int rspi_remove(struct platform_device *pdev)
{
- struct rspi_data *rspi = platform_get_drvdata(pdev);
+ struct rspi_data *rspi = spi_master_get(platform_get_drvdata(pdev));
spi_unregister_master(rspi->master);
rspi_release_dma(rspi);
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c
index 68910b31015..ce318d95a6e 100644
--- a/drivers/spi/spi-s3c24xx.c
+++ b/drivers/spi/spi-s3c24xx.c
@@ -525,7 +525,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
memset(hw, 0, sizeof(struct s3c24xx_spi));
hw->master = spi_master_get(master);
- hw->pdata = pdata = pdev->dev.platform_data;
+ hw->pdata = pdata = dev_get_platdata(&pdev->dev);
hw->dev = &pdev->dev;
if (pdata == NULL) {
@@ -690,7 +690,7 @@ static int s3c24xx_spi_remove(struct platform_device *dev)
static int s3c24xx_spi_suspend(struct device *dev)
{
- struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev));
+ struct s3c24xx_spi *hw = dev_get_drvdata(dev);
if (hw->pdata && hw->pdata->gpio_setup)
hw->pdata->gpio_setup(hw->pdata, 0);
@@ -701,7 +701,7 @@ static int s3c24xx_spi_suspend(struct device *dev)
static int s3c24xx_spi_resume(struct device *dev)
{
- struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev));
+ struct s3c24xx_spi *hw = dev_get_drvdata(dev);
s3c24xx_spi_initialsetup(hw);
return 0;
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 63e2070c6c1..512b8893893 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -172,7 +172,6 @@ struct s3c64xx_spi_port_config {
* @master: Pointer to the SPI Protocol master.
* @cntrlr_info: Platform specific data for the controller this driver manages.
* @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint.
- * @queue: To log SPI xfer requests.
* @lock: Controller specific lock.
* @state: Set of FLAGS to indicate status.
* @rx_dmach: Controller's DMA channel for Rx.
@@ -193,7 +192,6 @@ struct s3c64xx_spi_driver_data {
struct spi_master *master;
struct s3c64xx_spi_info *cntrlr_info;
struct spi_device *tgl_spi;
- struct list_head queue;
spinlock_t lock;
unsigned long sfr_start;
struct completion xfer_completion;
@@ -338,8 +336,10 @@ static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
req.cap = DMA_SLAVE;
req.client = &s3c64xx_spi_dma_client;
- sdd->rx_dma.ch = (void *)sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx");
- sdd->tx_dma.ch = (void *)sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx");
+ sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
+ sdd->rx_dma.dmach, &req, dev, "rx");
+ sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
+ sdd->tx_dma.dmach, &req, dev, "tx");
return 1;
}
@@ -356,8 +356,6 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
while (!is_polling(sdd) && !acquire_dma(sdd))
usleep_range(10000, 11000);
- pm_runtime_get_sync(&sdd->pdev->dev);
-
return 0;
}
@@ -372,7 +370,6 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
sdd->ops->release((enum dma_ch)sdd->tx_dma.ch,
&s3c64xx_spi_dma_client);
}
- pm_runtime_put(&sdd->pdev->dev);
return 0;
}
@@ -389,9 +386,10 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
{
struct s3c64xx_spi_driver_data *sdd;
struct dma_slave_config config;
- struct scatterlist sg;
struct dma_async_tx_descriptor *desc;
+ memset(&config, 0, sizeof(config));
+
if (dma->direction == DMA_DEV_TO_MEM) {
sdd = container_of((void *)dma,
struct s3c64xx_spi_driver_data, rx_dma);
@@ -410,14 +408,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
dmaengine_slave_config(dma->ch, &config);
}
- sg_init_table(&sg, 1);
- sg_dma_len(&sg) = len;
- sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
- len, offset_in_page(buf));
- sg_dma_address(&sg) = buf;
-
- desc = dmaengine_prep_slave_sg(dma->ch,
- &sg, 1, dma->direction, DMA_PREP_INTERRUPT);
+ desc = dmaengine_prep_slave_single(dma->ch, buf, len,
+ dma->direction, DMA_PREP_INTERRUPT);
desc->callback = s3c64xx_spi_dmacb;
desc->callback_param = dma;
@@ -434,27 +426,26 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
dma_cap_mask_t mask;
int ret;
- if (is_polling(sdd))
- return 0;
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- /* Acquire DMA channels */
- sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
- (void*)sdd->rx_dma.dmach, dev, "rx");
- if (!sdd->rx_dma.ch) {
- dev_err(dev, "Failed to get RX DMA channel\n");
- ret = -EBUSY;
- goto out;
- }
+ if (!is_polling(sdd)) {
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ /* Acquire DMA channels */
+ sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
+ (void *)sdd->rx_dma.dmach, dev, "rx");
+ if (!sdd->rx_dma.ch) {
+ dev_err(dev, "Failed to get RX DMA channel\n");
+ ret = -EBUSY;
+ goto out;
+ }
- sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
- (void*)sdd->tx_dma.dmach, dev, "tx");
- if (!sdd->tx_dma.ch) {
- dev_err(dev, "Failed to get TX DMA channel\n");
- ret = -EBUSY;
- goto out_rx;
+ sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
+ (void *)sdd->tx_dma.dmach, dev, "tx");
+ if (!sdd->tx_dma.ch) {
+ dev_err(dev, "Failed to get TX DMA channel\n");
+ ret = -EBUSY;
+ goto out_rx;
+ }
}
ret = pm_runtime_get_sync(&sdd->pdev->dev);
@@ -1056,8 +1047,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_info *sci;
- struct spi_message *msg;
- unsigned long flags;
int err;
sdd = spi_master_get_devdata(spi->master);
@@ -1071,37 +1060,23 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
return -ENODEV;
}
- /* Request gpio only if cs line is asserted by gpio pins */
- if (sdd->cs_gpio) {
- err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH,
- dev_name(&spi->dev));
- if (err) {
- dev_err(&spi->dev,
- "Failed to get /CS gpio [%d]: %d\n",
- cs->line, err);
- goto err_gpio_req;
+ if (!spi_get_ctldata(spi)) {
+ /* Request gpio only if cs line is asserted by gpio pins */
+ if (sdd->cs_gpio) {
+ err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH,
+ dev_name(&spi->dev));
+ if (err) {
+ dev_err(&spi->dev,
+ "Failed to get /CS gpio [%d]: %d\n",
+ cs->line, err);
+ goto err_gpio_req;
+ }
}
- }
- if (!spi_get_ctldata(spi))
spi_set_ctldata(spi, cs);
-
- sci = sdd->cntrlr_info;
-
- spin_lock_irqsave(&sdd->lock, flags);
-
- list_for_each_entry(msg, &sdd->queue, queue) {
- /* Is some mssg is already queued for this device */
- if (msg->spi == spi) {
- dev_err(&spi->dev,
- "setup: attempt while mssg in queue!\n");
- spin_unlock_irqrestore(&sdd->lock, flags);
- err = -EBUSY;
- goto err_msgq;
- }
}
- spin_unlock_irqrestore(&sdd->lock, flags);
+ sci = sdd->cntrlr_info;
pm_runtime_get_sync(&sdd->pdev->dev);
@@ -1149,7 +1124,6 @@ setup_exit:
/* setup() returns with device de-selected */
disable_cs(sdd, spi);
-err_msgq:
gpio_free(cs->line);
spi_set_ctldata(spi, NULL);
@@ -1275,7 +1249,7 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
#else
static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
{
- return dev->platform_data;
+ return dev_get_platdata(dev);
}
#endif
@@ -1300,7 +1274,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
struct resource *mem_res;
struct resource *res;
struct s3c64xx_spi_driver_data *sdd;
- struct s3c64xx_spi_info *sci = pdev->dev.platform_data;
+ struct s3c64xx_spi_info *sci = dev_get_platdata(&pdev->dev);
struct spi_master *master;
int ret, irq;
char clk_name[16];
@@ -1364,16 +1338,14 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
if (!sdd->pdev->dev.of_node) {
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
- dev_warn(&pdev->dev, "Unable to get SPI tx dma "
- "resource. Switching to poll mode\n");
+ dev_warn(&pdev->dev, "Unable to get SPI tx dma resource. Switching to poll mode\n");
sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
} else
sdd->tx_dma.dmach = res->start;
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
- dev_warn(&pdev->dev, "Unable to get SPI rx dma "
- "resource. Switching to poll mode\n");
+ dev_warn(&pdev->dev, "Unable to get SPI rx dma resource. Switching to poll mode\n");
sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
} else
sdd->rx_dma.dmach = res->start;
@@ -1395,6 +1367,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
SPI_BPW_MASK(8);
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ master->auto_runtime_pm = true;
sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(sdd->regs)) {
@@ -1442,7 +1415,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
spin_lock_init(&sdd->lock);
init_completion(&sdd->xfer_completion);
- INIT_LIST_HEAD(&sdd->queue);
ret = devm_request_irq(&pdev->dev, irq, s3c64xx_spi_irq, 0,
"spi-s3c64xx", sdd);
@@ -1464,8 +1436,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
sdd->port_id, master->num_chipselect);
- dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
- mem_res->end, mem_res->start,
+ dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tDMA=[Rx-%d, Tx-%d]\n",
+ mem_res,
sdd->rx_dma.dmach, sdd->tx_dma.dmach);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 716edf99953..0b68cb592fa 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -99,21 +99,6 @@ static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val)
/*
* spi master function
*/
-static int hspi_prepare_transfer(struct spi_master *master)
-{
- struct hspi_priv *hspi = spi_master_get_devdata(master);
-
- pm_runtime_get_sync(hspi->dev);
- return 0;
-}
-
-static int hspi_unprepare_transfer(struct spi_master *master)
-{
- struct hspi_priv *hspi = spi_master_get_devdata(master);
-
- pm_runtime_put_sync(hspi->dev);
- return 0;
-}
#define hspi_hw_cs_enable(hspi) hspi_hw_cs_ctrl(hspi, 0)
#define hspi_hw_cs_disable(hspi) hspi_hw_cs_ctrl(hspi, 1)
@@ -316,9 +301,8 @@ static int hspi_probe(struct platform_device *pdev)
master->setup = hspi_setup;
master->cleanup = hspi_cleanup;
master->mode_bits = SPI_CPOL | SPI_CPHA;
- master->prepare_transfer_hardware = hspi_prepare_transfer;
+ master->auto_runtime_pm = true;
master->transfer_one_message = hspi_transfer_one_message;
- master->unprepare_transfer_hardware = hspi_unprepare_transfer;
ret = spi_register_master(master);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_master error.\n");
@@ -327,8 +311,6 @@ static int hspi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
- dev_info(&pdev->dev, "probed\n");
-
return 0;
error1:
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 2bc5a6b8630..2a95435a6a1 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -645,7 +645,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
if (pdev->dev.of_node)
p->info = sh_msiof_spi_parse_dt(&pdev->dev);
else
- p->info = pdev->dev.platform_data;
+ p->info = dev_get_platdata(&pdev->dev);
if (!p->info) {
dev_err(&pdev->dev, "failed to obtain device info\n");
@@ -745,18 +745,6 @@ static int sh_msiof_spi_remove(struct platform_device *pdev)
return ret;
}
-static int sh_msiof_spi_runtime_nop(struct device *dev)
-{
- /* Runtime PM callback shared between ->runtime_suspend()
- * and ->runtime_resume(). Simply returns success.
- *
- * This driver re-initializes all registers after
- * pm_runtime_get_sync() anyway so there is no need
- * to save and restore registers here.
- */
- return 0;
-}
-
#ifdef CONFIG_OF
static const struct of_device_id sh_msiof_match[] = {
{ .compatible = "renesas,sh-msiof", },
@@ -766,18 +754,12 @@ static const struct of_device_id sh_msiof_match[] = {
MODULE_DEVICE_TABLE(of, sh_msiof_match);
#endif
-static struct dev_pm_ops sh_msiof_spi_dev_pm_ops = {
- .runtime_suspend = sh_msiof_spi_runtime_nop,
- .runtime_resume = sh_msiof_spi_runtime_nop,
-};
-
static struct platform_driver sh_msiof_spi_drv = {
.probe = sh_msiof_spi_probe,
.remove = sh_msiof_spi_remove,
.driver = {
.name = "spi_sh_msiof",
.owner = THIS_MODULE,
- .pm = &sh_msiof_spi_dev_pm_ops,
.of_match_table = of_match_ptr(sh_msiof_match),
},
};
diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c
index 097e506042b..8eefeb6007d 100644
--- a/drivers/spi/spi-sh-sci.c
+++ b/drivers/spi/spi-sh-sci.c
@@ -130,7 +130,7 @@ static int sh_sci_spi_probe(struct platform_device *dev)
sp = spi_master_get_devdata(master);
platform_set_drvdata(dev, sp);
- sp->info = dev->dev.platform_data;
+ sp->info = dev_get_platdata(&dev->dev);
/* setup spi bitbang adaptor */
sp->bitbang.master = spi_master_get(master);
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index fc20bcfd90c..a1f21b74773 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -19,6 +19,10 @@
#include <linux/of_gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+#include <linux/sirfsoc_dma.h>
#define DRIVER_NAME "sirfsoc_spi"
@@ -119,9 +123,19 @@
#define SIRFSOC_SPI_FIFO_HC(x) (((x) & 0x3F) << 20)
#define SIRFSOC_SPI_FIFO_THD(x) (((x) & 0xFF) << 2)
+/*
+ * only if the rx/tx buffer and transfer size are 4-bytes aligned, we use dma
+ * due to the limitation of dma controller
+ */
+
+#define ALIGNED(x) (!((u32)x & 0x3))
+#define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \
+ ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
+
struct sirfsoc_spi {
struct spi_bitbang bitbang;
- struct completion done;
+ struct completion rx_done;
+ struct completion tx_done;
void __iomem *base;
u32 ctrl_freq; /* SPI controller clock speed */
@@ -137,8 +151,16 @@ struct sirfsoc_spi {
void (*tx_word) (struct sirfsoc_spi *);
/* number of words left to be tranmitted/received */
- unsigned int left_tx_cnt;
- unsigned int left_rx_cnt;
+ unsigned int left_tx_word;
+ unsigned int left_rx_word;
+
+ /* rx & tx DMA channels */
+ struct dma_chan *rx_chan;
+ struct dma_chan *tx_chan;
+ dma_addr_t src_start;
+ dma_addr_t dst_start;
+ void *dummypage;
+ int word_width; /* in bytes */
int chipselect[0];
};
@@ -155,7 +177,7 @@ static void spi_sirfsoc_rx_word_u8(struct sirfsoc_spi *sspi)
sspi->rx = rx;
}
- sspi->left_rx_cnt--;
+ sspi->left_rx_word--;
}
static void spi_sirfsoc_tx_word_u8(struct sirfsoc_spi *sspi)
@@ -169,7 +191,7 @@ static void spi_sirfsoc_tx_word_u8(struct sirfsoc_spi *sspi)
}
writel(data, sspi->base + SIRFSOC_SPI_TXFIFO_DATA);
- sspi->left_tx_cnt--;
+ sspi->left_tx_word--;
}
static void spi_sirfsoc_rx_word_u16(struct sirfsoc_spi *sspi)
@@ -184,7 +206,7 @@ static void spi_sirfsoc_rx_word_u16(struct sirfsoc_spi *sspi)
sspi->rx = rx;
}
- sspi->left_rx_cnt--;
+ sspi->left_rx_word--;
}
static void spi_sirfsoc_tx_word_u16(struct sirfsoc_spi *sspi)
@@ -198,7 +220,7 @@ static void spi_sirfsoc_tx_word_u16(struct sirfsoc_spi *sspi)
}
writel(data, sspi->base + SIRFSOC_SPI_TXFIFO_DATA);
- sspi->left_tx_cnt--;
+ sspi->left_tx_word--;
}
static void spi_sirfsoc_rx_word_u32(struct sirfsoc_spi *sspi)
@@ -213,7 +235,7 @@ static void spi_sirfsoc_rx_word_u32(struct sirfsoc_spi *sspi)
sspi->rx = rx;
}
- sspi->left_rx_cnt--;
+ sspi->left_rx_word--;
}
@@ -228,7 +250,7 @@ static void spi_sirfsoc_tx_word_u32(struct sirfsoc_spi *sspi)
}
writel(data, sspi->base + SIRFSOC_SPI_TXFIFO_DATA);
- sspi->left_tx_cnt--;
+ sspi->left_tx_word--;
}
static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
@@ -241,7 +263,7 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
/* Error Conditions */
if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
spi_stat & SIRFSOC_SPI_TX_UFLOW) {
- complete(&sspi->done);
+ complete(&sspi->rx_done);
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
}
@@ -249,50 +271,61 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
| SIRFSOC_SPI_RXFIFO_THD_REACH))
while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
& SIRFSOC_SPI_FIFO_EMPTY)) &&
- sspi->left_rx_cnt)
+ sspi->left_rx_word)
sspi->rx_word(sspi);
if (spi_stat & (SIRFSOC_SPI_FIFO_EMPTY
| SIRFSOC_SPI_TXFIFO_THD_REACH))
while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
& SIRFSOC_SPI_FIFO_FULL)) &&
- sspi->left_tx_cnt)
+ sspi->left_tx_word)
sspi->tx_word(sspi);
/* Received all words */
- if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) {
- complete(&sspi->done);
+ if ((sspi->left_rx_word == 0) && (sspi->left_tx_word == 0)) {
+ complete(&sspi->rx_done);
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
}
return IRQ_HANDLED;
}
+static void spi_sirfsoc_dma_fini_callback(void *data)
+{
+ struct completion *dma_complete = data;
+
+ complete(dma_complete);
+}
+
static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
{
struct sirfsoc_spi *sspi;
int timeout = t->len * 10;
sspi = spi_master_get_devdata(spi->master);
- sspi->tx = t->tx_buf;
- sspi->rx = t->rx_buf;
- sspi->left_tx_cnt = sspi->left_rx_cnt = t->len;
- INIT_COMPLETION(sspi->done);
+ sspi->tx = t->tx_buf ? t->tx_buf : sspi->dummypage;
+ sspi->rx = t->rx_buf ? t->rx_buf : sspi->dummypage;
+ sspi->left_tx_word = sspi->left_rx_word = t->len / sspi->word_width;
+ INIT_COMPLETION(sspi->rx_done);
+ INIT_COMPLETION(sspi->tx_done);
writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
- if (t->len == 1) {
+ if (sspi->left_tx_word == 1) {
writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
SIRFSOC_SPI_ENA_AUTO_CLR,
sspi->base + SIRFSOC_SPI_CTRL);
writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
writel(0, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
- } else if ((t->len > 1) && (t->len < SIRFSOC_SPI_DAT_FRM_LEN_MAX)) {
+ } else if ((sspi->left_tx_word > 1) && (sspi->left_tx_word <
+ SIRFSOC_SPI_DAT_FRM_LEN_MAX)) {
writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
SIRFSOC_SPI_MUL_DAT_MODE |
SIRFSOC_SPI_ENA_AUTO_CLR,
sspi->base + SIRFSOC_SPI_CTRL);
- writel(t->len - 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
- writel(t->len - 1, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
+ writel(sspi->left_tx_word - 1,
+ sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
+ writel(sspi->left_tx_word - 1,
+ sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
} else {
writel(readl(sspi->base + SIRFSOC_SPI_CTRL),
sspi->base + SIRFSOC_SPI_CTRL);
@@ -305,17 +338,64 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
- /* Send the first word to trigger the whole tx/rx process */
- sspi->tx_word(sspi);
+ if (IS_DMA_VALID(t)) {
+ struct dma_async_tx_descriptor *rx_desc, *tx_desc;
+
+ sspi->dst_start = dma_map_single(&spi->dev, sspi->rx, t->len, DMA_FROM_DEVICE);
+ rx_desc = dmaengine_prep_slave_single(sspi->rx_chan,
+ sspi->dst_start, t->len, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ rx_desc->callback = spi_sirfsoc_dma_fini_callback;
+ rx_desc->callback_param = &sspi->rx_done;
+
+ sspi->src_start = dma_map_single(&spi->dev, (void *)sspi->tx, t->len, DMA_TO_DEVICE);
+ tx_desc = dmaengine_prep_slave_single(sspi->tx_chan,
+ sspi->src_start, t->len, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ tx_desc->callback = spi_sirfsoc_dma_fini_callback;
+ tx_desc->callback_param = &sspi->tx_done;
+
+ dmaengine_submit(tx_desc);
+ dmaengine_submit(rx_desc);
+ dma_async_issue_pending(sspi->tx_chan);
+ dma_async_issue_pending(sspi->rx_chan);
+ } else {
+ /* Send the first word to trigger the whole tx/rx process */
+ sspi->tx_word(sspi);
+
+ writel(SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN |
+ SIRFSOC_SPI_RXFIFO_THD_INT_EN | SIRFSOC_SPI_TXFIFO_THD_INT_EN |
+ SIRFSOC_SPI_FRM_END_INT_EN | SIRFSOC_SPI_RXFIFO_FULL_INT_EN |
+ SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN, sspi->base + SIRFSOC_SPI_INT_EN);
+ }
- writel(SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN |
- SIRFSOC_SPI_RXFIFO_THD_INT_EN | SIRFSOC_SPI_TXFIFO_THD_INT_EN |
- SIRFSOC_SPI_FRM_END_INT_EN | SIRFSOC_SPI_RXFIFO_FULL_INT_EN |
- SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN, sspi->base + SIRFSOC_SPI_INT_EN);
writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, sspi->base + SIRFSOC_SPI_TX_RX_EN);
- if (wait_for_completion_timeout(&sspi->done, timeout) == 0)
+ if (!IS_DMA_VALID(t)) { /* for PIO */
+ if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0)
+ dev_err(&spi->dev, "transfer timeout\n");
+ } else if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) {
dev_err(&spi->dev, "transfer timeout\n");
+ dmaengine_terminate_all(sspi->rx_chan);
+ } else
+ sspi->left_rx_word = 0;
+
+ /*
+ * we only wait tx-done event if transferring by DMA. for PIO,
+ * we get rx data by writing tx data, so if rx is done, tx has
+ * done earlier
+ */
+ if (IS_DMA_VALID(t)) {
+ if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
+ dev_err(&spi->dev, "transfer timeout\n");
+ dmaengine_terminate_all(sspi->tx_chan);
+ }
+ }
+
+ if (IS_DMA_VALID(t)) {
+ dma_unmap_single(&spi->dev, sspi->src_start, t->len, DMA_TO_DEVICE);
+ dma_unmap_single(&spi->dev, sspi->dst_start, t->len, DMA_FROM_DEVICE);
+ }
/* TX, RX FIFO stop */
writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
@@ -323,7 +403,7 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN);
writel(0, sspi->base + SIRFSOC_SPI_INT_EN);
- return t->len - sspi->left_rx_cnt;
+ return t->len - sspi->left_rx_word * sspi->word_width;
}
static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
@@ -332,7 +412,6 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
if (sspi->chipselect[spi->chip_select] == 0) {
u32 regval = readl(sspi->base + SIRFSOC_SPI_CTRL);
- regval |= SIRFSOC_SPI_CS_IO_OUT;
switch (value) {
case BITBANG_CS_ACTIVE:
if (spi->mode & SPI_CS_HIGH)
@@ -369,11 +448,7 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
hz = t && t->speed_hz ? t->speed_hz : spi->max_speed_hz;
- /* Enable IO mode for RX, TX */
- writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL);
- writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL);
regval = (sspi->ctrl_freq / (2 * hz)) - 1;
-
if (regval > 0xFFFF || regval < 0) {
dev_err(&spi->dev, "Speed %d not supported\n", hz);
return -EINVAL;
@@ -388,6 +463,7 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
SIRFSOC_SPI_FIFO_WIDTH_BYTE;
rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
SIRFSOC_SPI_FIFO_WIDTH_BYTE;
+ sspi->word_width = 1;
break;
case 12:
case 16:
@@ -399,6 +475,7 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
SIRFSOC_SPI_FIFO_WIDTH_WORD;
rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
SIRFSOC_SPI_FIFO_WIDTH_WORD;
+ sspi->word_width = 2;
break;
case 32:
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32;
@@ -408,6 +485,7 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
SIRFSOC_SPI_FIFO_WIDTH_DWORD;
rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
SIRFSOC_SPI_FIFO_WIDTH_DWORD;
+ sspi->word_width = 4;
break;
default:
BUG();
@@ -442,6 +520,17 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL);
writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
+
+ if (IS_DMA_VALID(t)) {
+ /* Enable DMA mode for RX, TX */
+ writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL);
+ writel(SIRFSOC_SPI_RX_DMA_FLUSH, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL);
+ } else {
+ /* Enable IO mode for RX, TX */
+ writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL);
+ writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL);
+ }
+
return 0;
}
@@ -466,6 +555,8 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct spi_master *master;
struct resource *mem_res;
int num_cs, cs_gpio, irq;
+ u32 rx_dma_ch, tx_dma_ch;
+ dma_cap_mask_t dma_cap_mask;
int i;
int ret;
@@ -476,6 +567,20 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
goto err_cs;
}
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "sirf,spi-dma-rx-channel", &rx_dma_ch);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to get rx dma channel\n");
+ goto err_cs;
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "sirf,spi-dma-tx-channel", &tx_dma_ch);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to get tx dma channel\n");
+ goto err_cs;
+ }
+
master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs);
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI master\n");
@@ -484,12 +589,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master);
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- dev_err(&pdev->dev, "Unable to get IO resource\n");
- ret = -ENODEV;
- goto free_master;
- }
master->num_chipselect = num_cs;
for (i = 0; i < master->num_chipselect; i++) {
@@ -516,6 +615,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
}
}
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sspi->base = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(sspi->base)) {
ret = PTR_ERR(sspi->base);
@@ -538,19 +638,40 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer;
sspi->bitbang.master->setup = spi_sirfsoc_setup;
master->bus_num = pdev->id;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(12) |
SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
+ /* request DMA channels */
+ dma_cap_zero(dma_cap_mask);
+ dma_cap_set(DMA_INTERLEAVE, dma_cap_mask);
+
+ sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
+ (void *)rx_dma_ch);
+ if (!sspi->rx_chan) {
+ dev_err(&pdev->dev, "can not allocate rx dma channel\n");
+ ret = -ENODEV;
+ goto free_master;
+ }
+ sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
+ (void *)tx_dma_ch);
+ if (!sspi->tx_chan) {
+ dev_err(&pdev->dev, "can not allocate tx dma channel\n");
+ ret = -ENODEV;
+ goto free_rx_dma;
+ }
+
sspi->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(sspi->clk)) {
- ret = -EINVAL;
- goto free_master;
+ ret = PTR_ERR(sspi->clk);
+ goto free_tx_dma;
}
clk_prepare_enable(sspi->clk);
sspi->ctrl_freq = clk_get_rate(sspi->clk);
- init_completion(&sspi->done);
+ init_completion(&sspi->rx_done);
+ init_completion(&sspi->tx_done);
writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
@@ -559,17 +680,28 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
/* We are not using dummy delay between command and data */
writel(0, sspi->base + SIRFSOC_SPI_DUMMY_DELAY_CTL);
+ sspi->dummypage = kmalloc(2 * PAGE_SIZE, GFP_KERNEL);
+ if (!sspi->dummypage) {
+ ret = -ENOMEM;
+ goto free_clk;
+ }
+
ret = spi_bitbang_start(&sspi->bitbang);
if (ret)
- goto free_clk;
+ goto free_dummypage;
dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num);
return 0;
-
+free_dummypage:
+ kfree(sspi->dummypage);
free_clk:
clk_disable_unprepare(sspi->clk);
clk_put(sspi->clk);
+free_tx_dma:
+ dma_release_channel(sspi->tx_chan);
+free_rx_dma:
+ dma_release_channel(sspi->rx_chan);
free_master:
spi_master_put(master);
err_cs:
@@ -590,8 +722,11 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
if (sspi->chipselect[i] > 0)
gpio_free(sspi->chipselect[i]);
}
+ kfree(sspi->dummypage);
clk_disable_unprepare(sspi->clk);
clk_put(sspi->clk);
+ dma_release_channel(sspi->rx_chan);
+ dma_release_channel(sspi->tx_chan);
spi_master_put(master);
return 0;
}
@@ -599,8 +734,7 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int spi_sirfsoc_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_master *master = dev_get_drvdata(dev);
struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
clk_disable(sspi->clk);
@@ -609,8 +743,7 @@ static int spi_sirfsoc_suspend(struct device *dev)
static int spi_sirfsoc_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_master *master = dev_get_drvdata(dev);
struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
clk_enable(sspi->clk);
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index e8f542ab893..145dd435483 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -816,14 +816,6 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
msg->status = 0;
msg->actual_length = 0;
- ret = pm_runtime_get_sync(tspi->dev);
- if (ret < 0) {
- dev_err(tspi->dev, "runtime PM get failed: %d\n", ret);
- msg->status = ret;
- spi_finalize_current_message(master);
- return ret;
- }
-
single_xfer = list_is_singular(&msg->transfers);
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
INIT_COMPLETION(tspi->xfer_completion);
@@ -859,7 +851,6 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
ret = 0;
exit:
tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
- pm_runtime_put(tspi->dev);
msg->status = ret;
spi_finalize_current_message(master);
return ret;
@@ -1053,24 +1044,19 @@ static int tegra_spi_probe(struct platform_device *pdev)
master->transfer_one_message = tegra_spi_transfer_one_message;
master->num_chipselect = MAX_CHIP_SELECT;
master->bus_num = -1;
+ master->auto_runtime_pm = true;
tspi->master = master;
tspi->dev = &pdev->dev;
spin_lock_init(&tspi->lock);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "No IO memory resource\n");
- ret = -ENODEV;
- goto exit_free_master;
- }
- tspi->phys = r->start;
tspi->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(tspi->base)) {
ret = PTR_ERR(tspi->base);
- dev_err(&pdev->dev, "ioremap failed: err = %d\n", ret);
goto exit_free_master;
}
+ tspi->phys = r->start;
spi_irq = platform_get_irq(pdev, 0);
tspi->irq = spi_irq;
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index c1d5d95e70e..1d814dc6e00 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -335,12 +335,6 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master,
struct spi_device *spi = msg->spi;
int ret;
- ret = pm_runtime_get_sync(tsd->dev);
- if (ret < 0) {
- dev_err(tsd->dev, "pm_runtime_get() failed, err = %d\n", ret);
- return ret;
- }
-
msg->status = 0;
msg->actual_length = 0;
single_xfer = list_is_singular(&msg->transfers);
@@ -380,7 +374,6 @@ exit:
tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND);
msg->status = ret;
spi_finalize_current_message(master);
- pm_runtime_put(tsd->dev);
return ret;
}
@@ -477,6 +470,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->setup = tegra_sflash_setup;
master->transfer_one_message = tegra_sflash_transfer_one_message;
+ master->auto_runtime_pm = true;
master->num_chipselect = MAX_CHIP_SELECT;
master->bus_num = -1;
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index 80490cc11ce..c70353672a2 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -836,11 +836,6 @@ static int tegra_slink_transfer_one_message(struct spi_master *master,
msg->status = 0;
msg->actual_length = 0;
- ret = pm_runtime_get_sync(tspi->dev);
- if (ret < 0) {
- dev_err(tspi->dev, "runtime get failed: %d\n", ret);
- goto done;
- }
single_xfer = list_is_singular(&msg->transfers);
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
@@ -878,8 +873,6 @@ static int tegra_slink_transfer_one_message(struct spi_master *master,
exit:
tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
- pm_runtime_put(tspi->dev);
-done:
msg->status = ret;
spi_finalize_current_message(master);
return ret;
@@ -1086,6 +1079,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->setup = tegra_slink_setup;
master->transfer_one_message = tegra_slink_transfer_one_message;
+ master->auto_runtime_pm = true;
master->num_chipselect = MAX_CHIP_SELECT;
master->bus_num = -1;
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
new file mode 100644
index 00000000000..e12d962a289
--- /dev/null
+++ b/drivers/spi/spi-ti-qspi.c
@@ -0,0 +1,574 @@
+/*
+ * TI QSPI driver
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Sourav Poddar <sourav.poddar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GPLv2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/omap-dma.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <linux/spi/spi.h>
+
+struct ti_qspi_regs {
+ u32 clkctrl;
+};
+
+struct ti_qspi {
+ struct completion transfer_complete;
+
+ /* IRQ synchronization */
+ spinlock_t lock;
+
+ /* list synchronization */
+ struct mutex list_lock;
+
+ struct spi_master *master;
+ void __iomem *base;
+ struct clk *fclk;
+ struct device *dev;
+
+ struct ti_qspi_regs ctx_reg;
+
+ u32 spi_max_frequency;
+ u32 cmd;
+ u32 dc;
+ u32 stat;
+};
+
+#define QSPI_PID (0x0)
+#define QSPI_SYSCONFIG (0x10)
+#define QSPI_INTR_STATUS_RAW_SET (0x20)
+#define QSPI_INTR_STATUS_ENABLED_CLEAR (0x24)
+#define QSPI_INTR_ENABLE_SET_REG (0x28)
+#define QSPI_INTR_ENABLE_CLEAR_REG (0x2c)
+#define QSPI_SPI_CLOCK_CNTRL_REG (0x40)
+#define QSPI_SPI_DC_REG (0x44)
+#define QSPI_SPI_CMD_REG (0x48)
+#define QSPI_SPI_STATUS_REG (0x4c)
+#define QSPI_SPI_DATA_REG (0x50)
+#define QSPI_SPI_SETUP0_REG (0x54)
+#define QSPI_SPI_SWITCH_REG (0x64)
+#define QSPI_SPI_SETUP1_REG (0x58)
+#define QSPI_SPI_SETUP2_REG (0x5c)
+#define QSPI_SPI_SETUP3_REG (0x60)
+#define QSPI_SPI_DATA_REG_1 (0x68)
+#define QSPI_SPI_DATA_REG_2 (0x6c)
+#define QSPI_SPI_DATA_REG_3 (0x70)
+
+#define QSPI_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
+
+#define QSPI_FCLK 192000000
+
+/* Clock Control */
+#define QSPI_CLK_EN (1 << 31)
+#define QSPI_CLK_DIV_MAX 0xffff
+
+/* Command */
+#define QSPI_EN_CS(n) (n << 28)
+#define QSPI_WLEN(n) ((n - 1) << 19)
+#define QSPI_3_PIN (1 << 18)
+#define QSPI_RD_SNGL (1 << 16)
+#define QSPI_WR_SNGL (2 << 16)
+#define QSPI_RD_DUAL (3 << 16)
+#define QSPI_RD_QUAD (7 << 16)
+#define QSPI_INVAL (4 << 16)
+#define QSPI_WC_CMD_INT_EN (1 << 14)
+#define QSPI_FLEN(n) ((n - 1) << 0)
+
+/* STATUS REGISTER */
+#define WC 0x02
+
+/* INTERRUPT REGISTER */
+#define QSPI_WC_INT_EN (1 << 1)
+#define QSPI_WC_INT_DISABLE (1 << 1)
+
+/* Device Control */
+#define QSPI_DD(m, n) (m << (3 + n * 8))
+#define QSPI_CKPHA(n) (1 << (2 + n * 8))
+#define QSPI_CSPOL(n) (1 << (1 + n * 8))
+#define QSPI_CKPOL(n) (1 << (n * 8))
+
+#define QSPI_FRAME 4096
+
+#define QSPI_AUTOSUSPEND_TIMEOUT 2000
+
+static inline unsigned long ti_qspi_read(struct ti_qspi *qspi,
+ unsigned long reg)
+{
+ return readl(qspi->base + reg);
+}
+
+static inline void ti_qspi_write(struct ti_qspi *qspi,
+ unsigned long val, unsigned long reg)
+{
+ writel(val, qspi->base + reg);
+}
+
+static int ti_qspi_setup(struct spi_device *spi)
+{
+ struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
+ int clk_div = 0, ret;
+ u32 clk_ctrl_reg, clk_rate, clk_mask;
+
+ if (spi->master->busy) {
+ dev_dbg(qspi->dev, "master busy doing other trasnfers\n");
+ return -EBUSY;
+ }
+
+ if (!qspi->spi_max_frequency) {
+ dev_err(qspi->dev, "spi max frequency not defined\n");
+ return -EINVAL;
+ }
+
+ clk_rate = clk_get_rate(qspi->fclk);
+
+ clk_div = DIV_ROUND_UP(clk_rate, qspi->spi_max_frequency) - 1;
+
+ if (clk_div < 0) {
+ dev_dbg(qspi->dev, "clock divider < 0, using /1 divider\n");
+ return -EINVAL;
+ }
+
+ if (clk_div > QSPI_CLK_DIV_MAX) {
+ dev_dbg(qspi->dev, "clock divider >%d , using /%d divider\n",
+ QSPI_CLK_DIV_MAX, QSPI_CLK_DIV_MAX + 1);
+ return -EINVAL;
+ }
+
+ dev_dbg(qspi->dev, "hz: %d, clock divider %d\n",
+ qspi->spi_max_frequency, clk_div);
+
+ ret = pm_runtime_get_sync(qspi->dev);
+ if (ret) {
+ dev_err(qspi->dev, "pm_runtime_get_sync() failed\n");
+ return ret;
+ }
+
+ clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG);
+
+ clk_ctrl_reg &= ~QSPI_CLK_EN;
+
+ /* disable SCLK */
+ ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG);
+
+ /* enable SCLK */
+ clk_mask = QSPI_CLK_EN | clk_div;
+ ti_qspi_write(qspi, clk_mask, QSPI_SPI_CLOCK_CNTRL_REG);
+ ctx_reg->clkctrl = clk_mask;
+
+ pm_runtime_mark_last_busy(qspi->dev);
+ ret = pm_runtime_put_autosuspend(qspi->dev);
+ if (ret < 0) {
+ dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
+{
+ struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
+
+ ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG);
+}
+
+static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
+{
+ int wlen, count, ret;
+ unsigned int cmd;
+ const u8 *txbuf;
+
+ txbuf = t->tx_buf;
+ cmd = qspi->cmd | QSPI_WR_SNGL;
+ count = t->len;
+ wlen = t->bits_per_word;
+
+ while (count) {
+ switch (wlen) {
+ case 8:
+ dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
+ cmd, qspi->dc, *txbuf);
+ writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG);
+ ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
+ ret = wait_for_completion_timeout(&qspi->transfer_complete,
+ QSPI_COMPLETION_TIMEOUT);
+ if (ret == 0) {
+ dev_err(qspi->dev, "write timed out\n");
+ return -ETIMEDOUT;
+ }
+ txbuf += 1;
+ count -= 1;
+ break;
+ case 16:
+ dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n",
+ cmd, qspi->dc, *txbuf);
+ writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG);
+ ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
+ ret = wait_for_completion_timeout(&qspi->transfer_complete,
+ QSPI_COMPLETION_TIMEOUT);
+ if (ret == 0) {
+ dev_err(qspi->dev, "write timed out\n");
+ return -ETIMEDOUT;
+ }
+ txbuf += 2;
+ count -= 2;
+ break;
+ case 32:
+ dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n",
+ cmd, qspi->dc, *txbuf);
+ writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG);
+ ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
+ ret = wait_for_completion_timeout(&qspi->transfer_complete,
+ QSPI_COMPLETION_TIMEOUT);
+ if (ret == 0) {
+ dev_err(qspi->dev, "write timed out\n");
+ return -ETIMEDOUT;
+ }
+ txbuf += 4;
+ count -= 4;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t)
+{
+ int wlen, count, ret;
+ unsigned int cmd;
+ u8 *rxbuf;
+
+ rxbuf = t->rx_buf;
+ cmd = qspi->cmd;
+ switch (t->rx_nbits) {
+ case SPI_NBITS_DUAL:
+ cmd |= QSPI_RD_DUAL;
+ break;
+ case SPI_NBITS_QUAD:
+ cmd |= QSPI_RD_QUAD;
+ break;
+ default:
+ cmd |= QSPI_RD_SNGL;
+ break;
+ }
+ count = t->len;
+ wlen = t->bits_per_word;
+
+ while (count) {
+ dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
+ ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
+ ret = wait_for_completion_timeout(&qspi->transfer_complete,
+ QSPI_COMPLETION_TIMEOUT);
+ if (ret == 0) {
+ dev_err(qspi->dev, "read timed out\n");
+ return -ETIMEDOUT;
+ }
+ switch (wlen) {
+ case 8:
+ *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG);
+ rxbuf += 1;
+ count -= 1;
+ break;
+ case 16:
+ *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG);
+ rxbuf += 2;
+ count -= 2;
+ break;
+ case 32:
+ *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG);
+ rxbuf += 4;
+ count -= 4;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t)
+{
+ int ret;
+
+ if (t->tx_buf) {
+ ret = qspi_write_msg(qspi, t);
+ if (ret) {
+ dev_dbg(qspi->dev, "Error while writing\n");
+ return ret;
+ }
+ }
+
+ if (t->rx_buf) {
+ ret = qspi_read_msg(qspi, t);
+ if (ret) {
+ dev_dbg(qspi->dev, "Error while reading\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ti_qspi_start_transfer_one(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct ti_qspi *qspi = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t;
+ int status = 0, ret;
+ int frame_length;
+
+ /* setup device control reg */
+ qspi->dc = 0;
+
+ if (spi->mode & SPI_CPHA)
+ qspi->dc |= QSPI_CKPHA(spi->chip_select);
+ if (spi->mode & SPI_CPOL)
+ qspi->dc |= QSPI_CKPOL(spi->chip_select);
+ if (spi->mode & SPI_CS_HIGH)
+ qspi->dc |= QSPI_CSPOL(spi->chip_select);
+
+ frame_length = (m->frame_length << 3) / spi->bits_per_word;
+
+ frame_length = clamp(frame_length, 0, QSPI_FRAME);
+
+ /* setup command reg */
+ qspi->cmd = 0;
+ qspi->cmd |= QSPI_EN_CS(spi->chip_select);
+ qspi->cmd |= QSPI_FLEN(frame_length);
+ qspi->cmd |= QSPI_WC_CMD_INT_EN;
+
+ ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG);
+ ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG);
+
+ mutex_lock(&qspi->list_lock);
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ qspi->cmd |= QSPI_WLEN(t->bits_per_word);
+
+ ret = qspi_transfer_msg(qspi, t);
+ if (ret) {
+ dev_dbg(qspi->dev, "transfer message failed\n");
+ mutex_unlock(&qspi->list_lock);
+ return -EINVAL;
+ }
+
+ m->actual_length += t->len;
+ }
+
+ mutex_unlock(&qspi->list_lock);
+
+ m->status = status;
+ spi_finalize_current_message(master);
+
+ ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG);
+
+ return status;
+}
+
+static irqreturn_t ti_qspi_isr(int irq, void *dev_id)
+{
+ struct ti_qspi *qspi = dev_id;
+ u16 int_stat;
+
+ irqreturn_t ret = IRQ_HANDLED;
+
+ spin_lock(&qspi->lock);
+
+ int_stat = ti_qspi_read(qspi, QSPI_INTR_STATUS_ENABLED_CLEAR);
+ qspi->stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
+
+ if (!int_stat) {
+ dev_dbg(qspi->dev, "No IRQ triggered\n");
+ ret = IRQ_NONE;
+ goto out;
+ }
+
+ ret = IRQ_WAKE_THREAD;
+
+ ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG);
+ ti_qspi_write(qspi, QSPI_WC_INT_DISABLE,
+ QSPI_INTR_STATUS_ENABLED_CLEAR);
+
+out:
+ spin_unlock(&qspi->lock);
+
+ return ret;
+}
+
+static irqreturn_t ti_qspi_threaded_isr(int this_irq, void *dev_id)
+{
+ struct ti_qspi *qspi = dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qspi->lock, flags);
+
+ if (qspi->stat & WC)
+ complete(&qspi->transfer_complete);
+
+ spin_unlock_irqrestore(&qspi->lock, flags);
+
+ ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG);
+
+ return IRQ_HANDLED;
+}
+
+static int ti_qspi_runtime_resume(struct device *dev)
+{
+ struct ti_qspi *qspi;
+ struct spi_master *master;
+
+ master = dev_get_drvdata(dev);
+ qspi = spi_master_get_devdata(master);
+ ti_qspi_restore_ctx(qspi);
+
+ return 0;
+}
+
+static const struct of_device_id ti_qspi_match[] = {
+ {.compatible = "ti,dra7xxx-qspi" },
+ {.compatible = "ti,am4372-qspi" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ti_qspi_match);
+
+static int ti_qspi_probe(struct platform_device *pdev)
+{
+ struct ti_qspi *qspi;
+ struct spi_master *master;
+ struct resource *r;
+ struct device_node *np = pdev->dev.of_node;
+ u32 max_freq;
+ int ret = 0, num_cs, irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*qspi));
+ if (!master)
+ return -ENOMEM;
+
+ master->mode_bits = SPI_CPOL | SPI_CPHA;
+
+ master->bus_num = -1;
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->setup = ti_qspi_setup;
+ master->auto_runtime_pm = true;
+ master->transfer_one_message = ti_qspi_start_transfer_one;
+ master->dev.of_node = pdev->dev.of_node;
+ master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
+
+ if (!of_property_read_u32(np, "num-cs", &num_cs))
+ master->num_chipselect = num_cs;
+
+ platform_set_drvdata(pdev, master);
+
+ qspi = spi_master_get_devdata(master);
+ qspi->master = master;
+ qspi->dev = &pdev->dev;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return irq;
+ }
+
+ spin_lock_init(&qspi->lock);
+ mutex_init(&qspi->list_lock);
+
+ qspi->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(qspi->base)) {
+ ret = PTR_ERR(qspi->base);
+ goto free_master;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, ti_qspi_isr,
+ ti_qspi_threaded_isr, 0,
+ dev_name(&pdev->dev), qspi);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
+ irq);
+ goto free_master;
+ }
+
+ qspi->fclk = devm_clk_get(&pdev->dev, "fck");
+ if (IS_ERR(qspi->fclk)) {
+ ret = PTR_ERR(qspi->fclk);
+ dev_err(&pdev->dev, "could not get clk: %d\n", ret);
+ }
+
+ init_completion(&qspi->transfer_complete);
+
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, QSPI_AUTOSUSPEND_TIMEOUT);
+ pm_runtime_enable(&pdev->dev);
+
+ if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
+ qspi->spi_max_frequency = max_freq;
+
+ ret = spi_register_master(master);
+ if (ret)
+ goto free_master;
+
+ return 0;
+
+free_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int ti_qspi_remove(struct platform_device *pdev)
+{
+ struct ti_qspi *qspi = platform_get_drvdata(pdev);
+
+ spi_unregister_master(qspi->master);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ti_qspi_pm_ops = {
+ .runtime_resume = ti_qspi_runtime_resume,
+};
+
+static struct platform_driver ti_qspi_driver = {
+ .probe = ti_qspi_probe,
+ .remove = ti_qspi_remove,
+ .driver = {
+ .name = "ti,dra7xxx-qspi",
+ .owner = THIS_MODULE,
+ .pm = &ti_qspi_pm_ops,
+ .of_match_table = ti_qspi_match,
+ }
+};
+
+module_platform_driver(ti_qspi_driver);
+
+MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI QSPI controller driver");
diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c
index 10606fcc6ef..7d20e121e4c 100644
--- a/drivers/spi/spi-ti-ssp.c
+++ b/drivers/spi/spi-ti-ssp.c
@@ -283,7 +283,7 @@ static int ti_ssp_spi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int error = 0;
- pdata = dev->platform_data;
+ pdata = dev_get_platdata(dev);
if (!pdata) {
dev_err(dev, "platform data not found\n");
return -EINVAL;
diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c
index 6b0874d782e..2d4010d8082 100644
--- a/drivers/spi/spi-tle62x0.c
+++ b/drivers/spi/spi-tle62x0.c
@@ -52,8 +52,7 @@ static inline int tle62x0_write(struct tle62x0_state *st)
buff[1] = gpio_state;
}
- dev_dbg(&st->us->dev, "buff %02x,%02x,%02x\n",
- buff[0], buff[1], buff[2]);
+ dev_dbg(&st->us->dev, "buff %3ph\n", buff);
return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2);
}
@@ -247,7 +246,7 @@ static int tle62x0_probe(struct spi_device *spi)
int ptr;
int ret;
- pdata = spi->dev.platform_data;
+ pdata = dev_get_platdata(&spi->dev);
if (pdata == NULL) {
dev_err(&spi->dev, "no device data specified\n");
return -EINVAL;
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index dd55707a6aa..eaeeed51bbb 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1797,3 +1797,5 @@ MODULE_PARM_DESC(use_dma,
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor ML7xxx IOH SPI Driver");
+MODULE_DEVICE_TABLE(pci, pch_spi_pcidev_id);
+
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index e9b7681ff6a..7c6d15766c7 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -26,7 +26,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
#define SPI_FIFO_SIZE 4
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 09a94285259..0bf1b2c457a 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -80,10 +80,9 @@ struct xilinx_spi {
/* bitbang has to be first */
struct spi_bitbang bitbang;
struct completion done;
- struct resource mem; /* phys mem */
void __iomem *regs; /* virt. address of the control registers */
- u32 irq;
+ int irq;
u8 *rx_ptr; /* pointer in the Tx buffer */
const u8 *tx_ptr; /* pointer in the Rx buffer */
@@ -233,21 +232,6 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
return 0;
}
-static int xilinx_spi_setup(struct spi_device *spi)
-{
- /* always return 0, we can not check the number of bits.
- * There are cases when SPI setup is called before any driver is
- * there, in that case the SPI core defaults to 8 bits, which we
- * do not support in some cases. But if we return an error, the
- * SPI device would not be registered and no driver can get hold of it
- * When the driver is there, it will call SPI setup again with the
- * correct number of bits per transfer.
- * If a driver setups with the wrong bit number, it will fail when
- * it tries to do a transfer
- */
- return 0;
-}
-
static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
{
u8 sr;
@@ -355,17 +339,34 @@ static const struct of_device_id xilinx_spi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
-struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
- u32 irq, s16 bus_num, int num_cs, int bits_per_word)
+static int xilinx_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
struct xilinx_spi *xspi;
- int ret;
+ struct xspi_platform_data *pdata;
+ struct resource *res;
+ int ret, num_cs = 0, bits_per_word = 8;
+ struct spi_master *master;
u32 tmp;
+ u8 i;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (pdata) {
+ num_cs = pdata->num_chipselect;
+ bits_per_word = pdata->bits_per_word;
+ } else {
+ of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
+ &num_cs);
+ }
+
+ if (!num_cs) {
+ dev_err(&pdev->dev,
+ "Missing slave select configuration data\n");
+ return -EINVAL;
+ }
- master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
+ master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
if (!master)
- return NULL;
+ return -ENODEV;
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA;
@@ -375,25 +376,18 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
xspi->bitbang.chipselect = xilinx_spi_chipselect;
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
- xspi->bitbang.master->setup = xilinx_spi_setup;
init_completion(&xspi->done);
- if (!request_mem_region(mem->start, resource_size(mem),
- XILINX_SPI_NAME))
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xspi->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(xspi->regs)) {
+ ret = PTR_ERR(xspi->regs);
goto put_master;
-
- xspi->regs = ioremap(mem->start, resource_size(mem));
- if (xspi->regs == NULL) {
- dev_warn(dev, "ioremap failure\n");
- goto map_failed;
}
- master->bus_num = bus_num;
+ master->bus_num = pdev->dev.id;
master->num_chipselect = num_cs;
- master->dev.of_node = dev->of_node;
-
- xspi->mem = *mem;
- xspi->irq = irq;
+ master->dev.of_node = pdev->dev.of_node;
/*
* Detect endianess on the IP via loop bit in CR. Detection
@@ -423,113 +417,63 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
} else if (xspi->bits_per_word == 32) {
xspi->tx_fn = xspi_tx32;
xspi->rx_fn = xspi_rx32;
- } else
- goto unmap_io;
-
+ } else {
+ ret = -EINVAL;
+ goto put_master;
+ }
/* SPI controller initializations */
xspi_init_hw(xspi);
+ xspi->irq = platform_get_irq(pdev, 0);
+ if (xspi->irq < 0) {
+ ret = xspi->irq;
+ goto put_master;
+ }
+
/* Register for SPI Interrupt */
- ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
+ ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
+ dev_name(&pdev->dev), xspi);
if (ret)
- goto unmap_io;
+ goto put_master;
ret = spi_bitbang_start(&xspi->bitbang);
if (ret) {
- dev_err(dev, "spi_bitbang_start FAILED\n");
- goto free_irq;
- }
-
- dev_info(dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
- (unsigned long long)mem->start, xspi->regs, xspi->irq);
- return master;
-
-free_irq:
- free_irq(xspi->irq, xspi);
-unmap_io:
- iounmap(xspi->regs);
-map_failed:
- release_mem_region(mem->start, resource_size(mem));
-put_master:
- spi_master_put(master);
- return NULL;
-}
-EXPORT_SYMBOL(xilinx_spi_init);
-
-void xilinx_spi_deinit(struct spi_master *master)
-{
- struct xilinx_spi *xspi;
-
- xspi = spi_master_get_devdata(master);
-
- spi_bitbang_stop(&xspi->bitbang);
- free_irq(xspi->irq, xspi);
- iounmap(xspi->regs);
-
- release_mem_region(xspi->mem.start, resource_size(&xspi->mem));
- spi_master_put(xspi->bitbang.master);
-}
-EXPORT_SYMBOL(xilinx_spi_deinit);
-
-static int xilinx_spi_probe(struct platform_device *dev)
-{
- struct xspi_platform_data *pdata;
- struct resource *r;
- int irq, num_cs = 0, bits_per_word = 8;
- struct spi_master *master;
- u8 i;
-
- pdata = dev->dev.platform_data;
- if (pdata) {
- num_cs = pdata->num_chipselect;
- bits_per_word = pdata->bits_per_word;
- }
-
-#ifdef CONFIG_OF
- if (dev->dev.of_node) {
- const __be32 *prop;
- int len;
-
- /* number of slave select bits is required */
- prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits",
- &len);
- if (prop && len >= sizeof(*prop))
- num_cs = __be32_to_cpup(prop);
- }
-#endif
-
- if (!num_cs) {
- dev_err(&dev->dev, "Missing slave select configuration data\n");
- return -EINVAL;
+ dev_err(&pdev->dev, "spi_bitbang_start FAILED\n");
+ goto put_master;
}
-
- r = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!r)
- return -ENODEV;
-
- irq = platform_get_irq(dev, 0);
- if (irq < 0)
- return -ENXIO;
-
- master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs,
- bits_per_word);
- if (!master)
- return -ENODEV;
+ dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
+ (unsigned long long)res->start, xspi->regs, xspi->irq);
if (pdata) {
for (i = 0; i < pdata->num_devices; i++)
spi_new_device(master, pdata->devices + i);
}
- platform_set_drvdata(dev, master);
+ platform_set_drvdata(pdev, master);
return 0;
+
+put_master:
+ spi_master_put(master);
+
+ return ret;
}
-static int xilinx_spi_remove(struct platform_device *dev)
+static int xilinx_spi_remove(struct platform_device *pdev)
{
- xilinx_spi_deinit(platform_get_drvdata(dev));
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct xilinx_spi *xspi = spi_master_get_devdata(master);
+ void __iomem *regs_base = xspi->regs;
+
+ spi_bitbang_stop(&xspi->bitbang);
+
+ /* Disable all the interrupts just in case */
+ xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
+ /* Disable the global IPIF interrupt */
+ xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
+
+ spi_master_put(xspi->bitbang.master);
return 0;
}
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 978dda2c523..9e039c60c06 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -553,6 +553,10 @@ static void spi_pump_messages(struct kthread_work *work)
master->unprepare_transfer_hardware(master))
dev_err(&master->dev,
"failed to unprepare transfer hardware\n");
+ if (master->auto_runtime_pm) {
+ pm_runtime_mark_last_busy(master->dev.parent);
+ pm_runtime_put_autosuspend(master->dev.parent);
+ }
return;
}
@@ -572,11 +576,23 @@ static void spi_pump_messages(struct kthread_work *work)
master->busy = true;
spin_unlock_irqrestore(&master->queue_lock, flags);
+ if (!was_busy && master->auto_runtime_pm) {
+ ret = pm_runtime_get_sync(master->dev.parent);
+ if (ret < 0) {
+ dev_err(&master->dev, "Failed to power device: %d\n",
+ ret);
+ return;
+ }
+ }
+
if (!was_busy && master->prepare_transfer_hardware) {
ret = master->prepare_transfer_hardware(master);
if (ret) {
dev_err(&master->dev,
"failed to prepare transfer hardware\n");
+
+ if (master->auto_runtime_pm)
+ pm_runtime_put(master->dev.parent);
return;
}
}
@@ -774,7 +790,7 @@ static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
msg->status = -EINPROGRESS;
list_add_tail(&msg->queue, &master->queue);
- if (master->running && !master->busy)
+ if (!master->busy)
queue_kthread_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags);
@@ -869,6 +885,47 @@ static void of_register_spi_devices(struct spi_master *master)
if (of_find_property(nc, "spi-3wire", NULL))
spi->mode |= SPI_3WIRE;
+ /* Device DUAL/QUAD mode */
+ prop = of_get_property(nc, "spi-tx-bus-width", &len);
+ if (prop && len == sizeof(*prop)) {
+ switch (be32_to_cpup(prop)) {
+ case SPI_NBITS_SINGLE:
+ break;
+ case SPI_NBITS_DUAL:
+ spi->mode |= SPI_TX_DUAL;
+ break;
+ case SPI_NBITS_QUAD:
+ spi->mode |= SPI_TX_QUAD;
+ break;
+ default:
+ dev_err(&master->dev,
+ "spi-tx-bus-width %d not supported\n",
+ be32_to_cpup(prop));
+ spi_dev_put(spi);
+ continue;
+ }
+ }
+
+ prop = of_get_property(nc, "spi-rx-bus-width", &len);
+ if (prop && len == sizeof(*prop)) {
+ switch (be32_to_cpup(prop)) {
+ case SPI_NBITS_SINGLE:
+ break;
+ case SPI_NBITS_DUAL:
+ spi->mode |= SPI_RX_DUAL;
+ break;
+ case SPI_NBITS_QUAD:
+ spi->mode |= SPI_RX_QUAD;
+ break;
+ default:
+ dev_err(&master->dev,
+ "spi-rx-bus-width %d not supported\n",
+ be32_to_cpup(prop));
+ spi_dev_put(spi);
+ continue;
+ }
+ }
+
/* Device speed */
prop = of_get_property(nc, "spi-max-frequency", &len);
if (!prop || len < sizeof(*prop)) {
@@ -1169,7 +1226,7 @@ int spi_register_master(struct spi_master *master)
else {
status = spi_master_initialize_queue(master);
if (status) {
- device_unregister(&master->dev);
+ device_del(&master->dev);
goto done;
}
}
@@ -1316,6 +1373,19 @@ int spi_setup(struct spi_device *spi)
unsigned bad_bits;
int status = 0;
+ /* check mode to prevent that DUAL and QUAD set at the same time
+ */
+ if (((spi->mode & SPI_TX_DUAL) && (spi->mode & SPI_TX_QUAD)) ||
+ ((spi->mode & SPI_RX_DUAL) && (spi->mode & SPI_RX_QUAD))) {
+ dev_err(&spi->dev,
+ "setup: can not select dual and quad at the same time\n");
+ return -EINVAL;
+ }
+ /* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden
+ */
+ if ((spi->mode & SPI_3WIRE) && (spi->mode &
+ (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)))
+ return -EINVAL;
/* help drivers fail *cleanly* when they need options
* that aren't supported with their current master
*/
@@ -1351,6 +1421,11 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
struct spi_master *master = spi->master;
struct spi_transfer *xfer;
+ if (list_empty(&message->transfers))
+ return -EINVAL;
+ if (!message->complete)
+ return -EINVAL;
+
/* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where
* either MOSI or MISO is missing. They can also be caused by
@@ -1373,12 +1448,20 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
/**
* Set transfer bits_per_word and max speed as spi device default if
* it is not set for this transfer.
+ * Set transfer tx_nbits and rx_nbits as single transfer default
+ * (SPI_NBITS_SINGLE) if it is not set for this transfer.
*/
list_for_each_entry(xfer, &message->transfers, transfer_list) {
+ message->frame_length += xfer->len;
if (!xfer->bits_per_word)
xfer->bits_per_word = spi->bits_per_word;
- if (!xfer->speed_hz)
+ if (!xfer->speed_hz) {
xfer->speed_hz = spi->max_speed_hz;
+ if (master->max_speed_hz &&
+ xfer->speed_hz > master->max_speed_hz)
+ xfer->speed_hz = master->max_speed_hz;
+ }
+
if (master->bits_per_word_mask) {
/* Only 32 bits fit in the mask */
if (xfer->bits_per_word > 32)
@@ -1387,6 +1470,54 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
BIT(xfer->bits_per_word - 1)))
return -EINVAL;
}
+
+ if (xfer->speed_hz && master->min_speed_hz &&
+ xfer->speed_hz < master->min_speed_hz)
+ return -EINVAL;
+ if (xfer->speed_hz && master->max_speed_hz &&
+ xfer->speed_hz > master->max_speed_hz)
+ return -EINVAL;
+
+ if (xfer->tx_buf && !xfer->tx_nbits)
+ xfer->tx_nbits = SPI_NBITS_SINGLE;
+ if (xfer->rx_buf && !xfer->rx_nbits)
+ xfer->rx_nbits = SPI_NBITS_SINGLE;
+ /* check transfer tx/rx_nbits:
+ * 1. keep the value is not out of single, dual and quad
+ * 2. keep tx/rx_nbits is contained by mode in spi_device
+ * 3. if SPI_3WIRE, tx/rx_nbits should be in single
+ */
+ if (xfer->tx_buf) {
+ if (xfer->tx_nbits != SPI_NBITS_SINGLE &&
+ xfer->tx_nbits != SPI_NBITS_DUAL &&
+ xfer->tx_nbits != SPI_NBITS_QUAD)
+ return -EINVAL;
+ if ((xfer->tx_nbits == SPI_NBITS_DUAL) &&
+ !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
+ return -EINVAL;
+ if ((xfer->tx_nbits == SPI_NBITS_QUAD) &&
+ !(spi->mode & SPI_TX_QUAD))
+ return -EINVAL;
+ if ((spi->mode & SPI_3WIRE) &&
+ (xfer->tx_nbits != SPI_NBITS_SINGLE))
+ return -EINVAL;
+ }
+ /* check transfer rx_nbits */
+ if (xfer->rx_buf) {
+ if (xfer->rx_nbits != SPI_NBITS_SINGLE &&
+ xfer->rx_nbits != SPI_NBITS_DUAL &&
+ xfer->rx_nbits != SPI_NBITS_QUAD)
+ return -EINVAL;
+ if ((xfer->rx_nbits == SPI_NBITS_DUAL) &&
+ !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
+ return -EINVAL;
+ if ((xfer->rx_nbits == SPI_NBITS_QUAD) &&
+ !(spi->mode & SPI_RX_QUAD))
+ return -EINVAL;
+ if ((spi->mode & SPI_3WIRE) &&
+ (xfer->rx_nbits != SPI_NBITS_SINGLE))
+ return -EINVAL;
+ }
}
message->spi = spi;
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 57d8b344460..3626dbc8eb0 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -40,8 +40,6 @@ source "drivers/staging/comedi/Kconfig"
source "drivers/staging/olpc_dcon/Kconfig"
-source "drivers/staging/asus_oled/Kconfig"
-
source "drivers/staging/panel/Kconfig"
source "drivers/staging/rtl8187se/Kconfig"
@@ -52,6 +50,8 @@ source "drivers/staging/rtl8192e/Kconfig"
source "drivers/staging/rtl8712/Kconfig"
+source "drivers/staging/rtl8188eu/Kconfig"
+
source "drivers/staging/rts5139/Kconfig"
source "drivers/staging/frontier/Kconfig"
@@ -118,6 +118,8 @@ source "drivers/staging/ozwpan/Kconfig"
source "drivers/staging/gdm72xx/Kconfig"
+source "drivers/staging/gdm724x/Kconfig"
+
source "drivers/staging/silicom/Kconfig"
source "drivers/staging/ced1401/Kconfig"
@@ -130,8 +132,6 @@ source "drivers/staging/sb105x/Kconfig"
source "drivers/staging/fwserial/Kconfig"
-source "drivers/staging/zcache/Kconfig"
-
source "drivers/staging/goldfish/Kconfig"
source "drivers/staging/netlogic/Kconfig"
@@ -142,4 +142,10 @@ source "drivers/staging/lustre/Kconfig"
source "drivers/staging/btmtk_usb/Kconfig"
+source "drivers/staging/xillybus/Kconfig"
+
+source "drivers/staging/dgnc/Kconfig"
+
+source "drivers/staging/dgap/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 429321f1510..d1b4b8003c2 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -12,12 +12,12 @@ obj-$(CONFIG_PRISM2_USB) += wlan-ng/
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_COMEDI) += comedi/
obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/
-obj-$(CONFIG_ASUS_OLED) += asus_oled/
obj-$(CONFIG_PANEL) += panel/
obj-$(CONFIG_R8187SE) += rtl8187se/
obj-$(CONFIG_RTL8192U) += rtl8192u/
obj-$(CONFIG_RTL8192E) += rtl8192e/
obj-$(CONFIG_R8712U) += rtl8712/
+obj-$(CONFIG_R8188EU) += rtl8188eu/
obj-$(CONFIG_RTS5139) += rts5139/
obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_IDE_PHISON) += phison/
@@ -52,14 +52,17 @@ obj-$(CONFIG_MFD_NVEC) += nvec/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
+obj-$(CONFIG_LTE_GDM724X) += gdm724x/
obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
obj-$(CONFIG_CED1401) += ced1401/
obj-$(CONFIG_DRM_IMX) += imx-drm/
obj-$(CONFIG_DGRP) += dgrp/
obj-$(CONFIG_SB105X) += sb105x/
obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/
-obj-$(CONFIG_ZCACHE) += zcache/
obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_USB_DWC2) += dwc2/
obj-$(CONFIG_LUSTRE_FS) += lustre/
obj-$(CONFIG_USB_BTMTK) += btmtk_usb/
+obj-$(CONFIG_XILLYBUS) += xillybus/
+obj-$(CONFIG_DGNC) += dgnc/
+obj-$(CONFIG_DGAP) += dgap/
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 119d486a5cf..98ac020bf91 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -1248,7 +1248,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
struct flat_binder_object *fp;
if (*offp > buffer->data_size - sizeof(*fp) ||
buffer->data_size < sizeof(*fp) ||
- !IS_ALIGNED(*offp, sizeof(void *))) {
+ !IS_ALIGNED(*offp, sizeof(u32))) {
pr_err("transaction release %d bad offset %zd, size %zd\n",
debug_id, *offp, buffer->data_size);
continue;
@@ -1272,7 +1272,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
case BINDER_TYPE_WEAK_HANDLE: {
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
if (ref == NULL) {
- pr_err("transaction release %d bad handle %ld\n",
+ pr_err("transaction release %d bad handle %d\n",
debug_id, fp->handle);
break;
}
@@ -1284,13 +1284,13 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
case BINDER_TYPE_FD:
binder_debug(BINDER_DEBUG_TRANSACTION,
- " fd %ld\n", fp->handle);
+ " fd %d\n", fp->handle);
if (failed_at)
task_close_fd(proc, fp->handle);
break;
default:
- pr_err("transaction release %d bad object type %lx\n",
+ pr_err("transaction release %d bad object type %x\n",
debug_id, fp->type);
break;
}
@@ -1497,7 +1497,7 @@ static void binder_transaction(struct binder_proc *proc,
struct flat_binder_object *fp;
if (*offp > t->buffer->data_size - sizeof(*fp) ||
t->buffer->data_size < sizeof(*fp) ||
- !IS_ALIGNED(*offp, sizeof(void *))) {
+ !IS_ALIGNED(*offp, sizeof(u32))) {
binder_user_error("%d:%d got transaction with invalid offset, %zd\n",
proc->pid, thread->pid, *offp);
return_error = BR_FAILED_REPLY;
@@ -1548,7 +1548,7 @@ static void binder_transaction(struct binder_proc *proc,
case BINDER_TYPE_WEAK_HANDLE: {
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
if (ref == NULL) {
- binder_user_error("%d:%d got transaction with invalid handle, %ld\n",
+ binder_user_error("%d:%d got transaction with invalid handle, %d\n",
proc->pid,
thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
@@ -1591,13 +1591,13 @@ static void binder_transaction(struct binder_proc *proc,
if (reply) {
if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
- binder_user_error("%d:%d got reply with fd, %ld, but target does not allow fds\n",
+ binder_user_error("%d:%d got reply with fd, %d, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
}
} else if (!target_node->accept_fds) {
- binder_user_error("%d:%d got transaction with fd, %ld, but target does not allow fds\n",
+ binder_user_error("%d:%d got transaction with fd, %d, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
@@ -1605,7 +1605,7 @@ static void binder_transaction(struct binder_proc *proc,
file = fget(fp->handle);
if (file == NULL) {
- binder_user_error("%d:%d got transaction with invalid fd, %ld\n",
+ binder_user_error("%d:%d got transaction with invalid fd, %d\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fget_failed;
@@ -1619,13 +1619,13 @@ static void binder_transaction(struct binder_proc *proc,
task_fd_install(target_proc, target_fd, file);
trace_binder_transaction_fd(t, fp->handle, target_fd);
binder_debug(BINDER_DEBUG_TRANSACTION,
- " fd %ld -> %d\n", fp->handle, target_fd);
+ " fd %d -> %d\n", fp->handle, target_fd);
/* TODO: fput? */
fp->handle = target_fd;
} break;
default:
- binder_user_error("%d:%d got transaction with invalid object type, %lx\n",
+ binder_user_error("%d:%d got transaction with invalid object type, %x\n",
proc->pid, thread->pid, fp->type);
return_error = BR_FAILED_REPLY;
goto err_bad_object_type;
@@ -1701,7 +1701,7 @@ err_no_context_mgr_node:
}
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
- void __user *buffer, int size, signed long *consumed)
+ void __user *buffer, size_t size, size_t *consumed)
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;
@@ -2081,8 +2081,8 @@ static int binder_has_thread_work(struct binder_thread *thread)
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
- void __user *buffer, int size,
- signed long *consumed, int non_block)
+ void __user *buffer, size_t size,
+ size_t *consumed, int non_block)
{
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
@@ -2579,7 +2579,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
goto err;
}
binder_debug(BINDER_DEBUG_READ_WRITE,
- "%d:%d write %ld at %08lx, read %ld at %08lx\n",
+ "%d:%d write %zd at %016lx, read %zd at %016lx\n",
proc->pid, thread->pid, bwr.write_size,
bwr.write_buffer, bwr.read_size, bwr.read_buffer);
@@ -2605,7 +2605,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
}
binder_debug(BINDER_DEBUG_READ_WRITE,
- "%d:%d wrote %ld of %ld, read return %ld of %ld\n",
+ "%d:%d wrote %zd of %zd, read return %zd of %zd\n",
proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
bwr.read_consumed, bwr.read_size);
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h
index dbe81ceca1b..cbe34516806 100644
--- a/drivers/staging/android/binder.h
+++ b/drivers/staging/android/binder.h
@@ -48,13 +48,13 @@ enum {
*/
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
- unsigned long type;
- unsigned long flags;
+ __u32 type;
+ __u32 flags;
/* 8 bytes of data. */
union {
void __user *binder; /* local object */
- signed long handle; /* remote object */
+ __u32 handle; /* remote object */
};
/* extra data associated with local object */
@@ -67,18 +67,18 @@ struct flat_binder_object {
*/
struct binder_write_read {
- signed long write_size; /* bytes to write */
- signed long write_consumed; /* bytes consumed by driver */
+ size_t write_size; /* bytes to write */
+ size_t write_consumed; /* bytes consumed by driver */
unsigned long write_buffer;
- signed long read_size; /* bytes to read */
- signed long read_consumed; /* bytes consumed by driver */
+ size_t read_size; /* bytes to read */
+ size_t read_consumed; /* bytes consumed by driver */
unsigned long read_buffer;
};
/* Use with BINDER_VERSION, driver fills in fields. */
struct binder_version {
/* driver protocol version -- increment with incompatible change */
- signed long protocol_version;
+ __s32 protocol_version;
};
/* This is the current protocol version. */
@@ -86,7 +86,7 @@ struct binder_version {
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
-#define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t)
+#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
@@ -119,14 +119,14 @@ struct binder_transaction_data {
* identifying the target and contents of the transaction.
*/
union {
- size_t handle; /* target descriptor of command transaction */
+ __u32 handle; /* target descriptor of command transaction */
void *ptr; /* target descriptor of return transaction */
} target;
void *cookie; /* target object cookie */
- unsigned int code; /* transaction command */
+ __u32 code; /* transaction command */
/* General information about the transaction. */
- unsigned int flags;
+ __u32 flags;
pid_t sender_pid;
uid_t sender_euid;
size_t data_size; /* number of bytes of data */
@@ -143,7 +143,7 @@ struct binder_transaction_data {
/* offsets from buffer to flat_binder_object structs */
const void __user *offsets;
} ptr;
- uint8_t buf[8];
+ __u8 buf[8];
} data;
};
@@ -153,18 +153,18 @@ struct binder_ptr_cookie {
};
struct binder_pri_desc {
- int priority;
- int desc;
+ __s32 priority;
+ __u32 desc;
};
struct binder_pri_ptr_cookie {
- int priority;
+ __s32 priority;
void *ptr;
void *cookie;
};
enum binder_driver_return_protocol {
- BR_ERROR = _IOR('r', 0, int),
+ BR_ERROR = _IOR('r', 0, __s32),
/*
* int: error code
*/
@@ -178,7 +178,7 @@ enum binder_driver_return_protocol {
* binder_transaction_data: the received command.
*/
- BR_ACQUIRE_RESULT = _IOR('r', 4, int),
+ BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
/*
* not currently supported
* int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
@@ -258,22 +258,22 @@ enum binder_driver_command_protocol {
* binder_transaction_data: the sent command.
*/
- BC_ACQUIRE_RESULT = _IOW('c', 2, int),
+ BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
/*
* not currently supported
* int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful.
* Else you have acquired a primary reference on the object.
*/
- BC_FREE_BUFFER = _IOW('c', 3, int),
+ BC_FREE_BUFFER = _IOW('c', 3, void *),
/*
* void *: ptr to transaction data received on a read
*/
- BC_INCREFS = _IOW('c', 4, int),
- BC_ACQUIRE = _IOW('c', 5, int),
- BC_RELEASE = _IOW('c', 6, int),
- BC_DECREFS = _IOW('c', 7, int),
+ BC_INCREFS = _IOW('c', 4, __u32),
+ BC_ACQUIRE = _IOW('c', 5, __u32),
+ BC_RELEASE = _IOW('c', 6, __u32),
+ BC_DECREFS = _IOW('c', 7, __u32),
/*
* int: descriptor
*/
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index 080abf2faf9..a8c344422a7 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -469,7 +469,7 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t ppos)
{
struct logger_log *log = file_get_log(iocb->ki_filp);
- size_t orig = log->w_off;
+ size_t orig;
struct logger_entry header;
struct timespec now;
ssize_t ret = 0;
@@ -490,6 +490,8 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
mutex_lock(&log->mutex);
+ orig = log->w_off;
+
/*
* Fix up any readers, pulling them forward to the first readable
* entry after (what will be) the new write offset. We do this now
diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c
index 765c757b120..f24493ac65e 100644
--- a/drivers/staging/android/sw_sync.c
+++ b/drivers/staging/android/sw_sync.c
@@ -163,7 +163,7 @@ static int sw_sync_release(struct inode *inode, struct file *file)
static long sw_sync_ioctl_create_fence(struct sw_sync_timeline *obj,
unsigned long arg)
{
- int fd = get_unused_fd();
+ int fd = get_unused_fd_flags(O_CLOEXEC);
int err;
struct sync_pt *pt;
struct sync_fence *fence;
diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c
index 2996077fede..38e5d3b5ed9 100644
--- a/drivers/staging/android/sync.c
+++ b/drivers/staging/android/sync.c
@@ -697,7 +697,7 @@ static long sync_fence_ioctl_wait(struct sync_fence *fence, unsigned long arg)
static long sync_fence_ioctl_merge(struct sync_fence *fence, unsigned long arg)
{
- int fd = get_unused_fd();
+ int fd = get_unused_fd_flags(O_CLOEXEC);
int err;
struct sync_fence *fence2, *fence3;
struct sync_merge_data data;
diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c
index ee3a57f2283..2c617834dc4 100644
--- a/drivers/staging/android/timed_output.c
+++ b/drivers/staging/android/timed_output.c
@@ -28,7 +28,7 @@ static struct class *timed_output_class;
static atomic_t device_count;
static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct timed_output_dev *tdev = dev_get_drvdata(dev);
int remaining = tdev->get_time(tdev);
@@ -36,9 +36,8 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", remaining);
}
-static ssize_t enable_store(
- struct device *dev, struct device_attribute *attr,
- const char *buf, size_t size)
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
{
struct timed_output_dev *tdev = dev_get_drvdata(dev);
int value;
@@ -50,8 +49,13 @@ static ssize_t enable_store(
return size;
}
+static DEVICE_ATTR_RW(enable);
-static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
+static struct attribute *timed_output_attrs[] = {
+ &dev_attr_enable.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(timed_output);
static int create_timed_output_class(void)
{
@@ -60,6 +64,7 @@ static int create_timed_output_class(void)
if (IS_ERR(timed_output_class))
return PTR_ERR(timed_output_class);
atomic_set(&device_count, 0);
+ timed_output_class->dev_groups = timed_output_groups;
}
return 0;
@@ -82,27 +87,15 @@ int timed_output_dev_register(struct timed_output_dev *tdev)
if (IS_ERR(tdev->dev))
return PTR_ERR(tdev->dev);
- ret = device_create_file(tdev->dev, &dev_attr_enable);
- if (ret < 0)
- goto err_create_file;
-
dev_set_drvdata(tdev->dev, tdev);
tdev->state = 0;
return 0;
-
-err_create_file:
- device_destroy(timed_output_class, MKDEV(0, tdev->index));
- pr_err("failed to register driver %s\n",
- tdev->name);
-
- return ret;
}
EXPORT_SYMBOL_GPL(timed_output_dev_register);
void timed_output_dev_unregister(struct timed_output_dev *tdev)
{
tdev->enable(tdev, 0);
- device_remove_file(tdev->dev, &dev_attr_enable);
device_destroy(timed_output_class, MKDEV(0, tdev->index));
dev_set_drvdata(tdev->dev, NULL);
}
diff --git a/drivers/staging/asus_oled/Kconfig b/drivers/staging/asus_oled/Kconfig
deleted file mode 100644
index e56dbb25ac5..00000000000
--- a/drivers/staging/asus_oled/Kconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-config ASUS_OLED
- tristate "Asus OLED driver"
- depends on USB
- default N
- ---help---
- Enable support for the OLED display present in some Asus laptops.
diff --git a/drivers/staging/asus_oled/Makefile b/drivers/staging/asus_oled/Makefile
deleted file mode 100644
index e71f9aa9e03..00000000000
--- a/drivers/staging/asus_oled/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_ASUS_OLED) += asus_oled.o
diff --git a/drivers/staging/asus_oled/README b/drivers/staging/asus_oled/README
deleted file mode 100644
index 2d721232467..00000000000
--- a/drivers/staging/asus_oled/README
+++ /dev/null
@@ -1,156 +0,0 @@
-
- Driver for Asus OLED display present in some Asus laptops.
-
- The code of this driver is based on 'asusoled' program taken from
- <http://lapsus.berlios.de/asus_oled.html>. I just wanted to have a simple
- kernel driver for controlling this device, but I didn't know how
- to do that. Now I know ;) Also, that program can not be used
- with usbhid loaded, which means no USB mouse/keyboard while
- controlling OLED display :(
-
- It has been tested on Asus G1 and didn't cause any problems,
- but I don't guarantee that it won't do anything wrong :)
-
- It can (and probably does) have errors. It is usable
- in my case, and I hope others will find it useful too!
-
-*******
-
-Building the module
-
- To build the module you need kernel 2.6 include files and some C compiler.
-
- Just run:
- make
- make install (as a root)
-
- It will build (hopefully) the module and install it in
- /lib/modules/'uname -r'/extra/asus_oled.ko.
-
- To load it just use:
- modprobe asus_oled
-
- You can check if it has detected your OLED display by looking into dmesg output.
- There should be something like this:
- asus-oled 2-7:1.0: Attached Asus OLED device
-
- If it doesn't find your display, you can try removing usbhid module.
- If you add asus_oled into the list of modules loaded during system boot
- before usbhid, it will work even when usbhid is present.
-
- If it still doesn't detect your hardware, check lsusb output.
- There should be similar line:
- Bus 002 Device 005: ID 0b05:1726 ASUSTek Computer, Inc.
-
- If you don't see any lines with '0b05:1726' it means that you have different
- type of hardware that is not detected (it may or may not work, but the driver
- knows only '0b05:1726' device).
-
-*******
-
-Configuration
-
- There is only one option: start_off.
- You can use it by: 'modprobe asus_oled start_off=1', or by adding this
- line to /etc/modprobe.d/asus_oled.conf:
- options asus_oled start_off=1
-
- With this option provided, asus_oled driver will switch off the display
- when it is detected and attached. It is nice feature to just switch off the 'ASUS'
- logo. If you don't use the display, it is probably the good idea to switch it off,
- to protect OLEDs from "wearing off".
-
-*******
-
-Usage
-
- This module can be controlled with two special files:
- /sys/class/asus_oled/oled_N/enabled
- /sys/class/asus_oled/oled_N/picture
-
- (N is the device number, the first, and probably the only, has number 1,
- so it is /sys/class/asus_oled/oled_1/enabled
- and /sys/class/asus_oled/oled_1/picture)
-
- 'enabled' files is for reading and writing, 'picture' is writeable only.
-
- You can write 0 or 1 to 'enabled' file, which will switch
- on and off the display. Reading from this file will tell you the last
- status set, either 0 or 1. By default it is 1, so if the device was set to 'off',
- and the computer was rebooted without power-off, this file will contain wrong
- value - because the device is off, but hasn't been disabled this time and is
- assumed to be on...
-
- To 'picture' file you write pictures to be displayed by the OLED device.
- The format of the file:
- <M:WxH>
- 00001110010111000
- 00010101010101010
- ....
-
- First line is a configuration parameter. Meaning of fields in <M:WxH>:
- M - picture mode. It can be either 's' for static pictures,
- 'r' for rolling pictures, and 'f' for flashing pictures.
- W - width of the picture. May be between 1 and 1792
- H - height of the picture. May be between 1 and 32
-
- For example <s:128x32> means static picture, 128 pixels long and 32 pixels high.
-
- The physical size of the display is 128x32 pixels. Static and flashing pictures
- can't be larger than that (actually they can, but only part of them will be displayed ;) )
-
- If the picture is smaller than 128x32 it will be centered. Rolling pictures wider than
- 128 pixels will be centered too, unless their width = n*128. Vertically they will be
- centered just like static pictures, if their height is smaller than 32.
-
- Flashing pictures will be centered horizontally if their width < 128, but they were
- centered vertically in a different way. If their height < 16, they will be centered
- in the upper half of the display (rows 0-15). This is because only the first half
- of flashing pictures is used for flashing. When the picture with heigh = 32 is
- displayed in flashing mode, its upper 16 rows will be flashing in the upper half
- of the display, and the lower half will be empty. After few seconds upper part will
- stop flashing (but that part of the picture will remain there), and the lower
- half of the display will start displayin the lower half of the picture
- in rolling mode, unless it is empty, or the picture was small enough to fit in
- upper part. It is not mine idea, this is just the way Asus' display work ;)
- So if you need just flashing, use at most 128x16 picture. If you need flashing and
- rolling, use whole size of the display.
-
- Lines following the first, configuration, line are picture data. Each '1' means
- that the pixel is lit, and '0' means that it is not. You can also use '#' as ON,
- and ' ' (space) as OFF. Empty lines and all other characters are ignored.
-
- It is possible to write everything in one line <M:WxH>01010101010101010...,
- and W*H characters will be used. If there is not enough characters, nothing will be
- displayed. However, the 'line mode' is easier to read (and write), and it also
- lets to omit parts of data. Whenever End-Of-Line character is found, but
- the line is not W characters long, it is assumed that all missing characters
- are equal to the last character in the line.
-
- Following line represents '0', '1' and a lots of '0's, dependng on the width of the picture
- provided in configuration data:
- 010
-
- So if you need empty line, it is sufficient to write line with only one '0' in it.
- The same works with '1' (or ' ' and '#').
-
- If there are too many data in the file, they will be ignored. If you are not sure
- how many characters you are missing, you can add few lines with one zero in each of them.
-
- There are some example pictures in .txt format, that can be used as follows:
- cat foo.txt > /sys/class/asus_oled/oled_1/picture
-
- If the display is switched off you also need to run:
- echo 1 > /sys/class/asus_oled/oled_1/enabled
- To switch it off, just use:
- echo 0 > /sys/class/asus_oled/oled_1/enabled
-
-
-*******
-
- For any additional info please have a look at http://lapsus.berlios.de/asus_oled.html
-
-
-
- Jakub Schmidtke (sjakub@gmail.com)
-
diff --git a/drivers/staging/asus_oled/TODO b/drivers/staging/asus_oled/TODO
deleted file mode 100644
index 2514131670a..00000000000
--- a/drivers/staging/asus_oled/TODO
+++ /dev/null
@@ -1,10 +0,0 @@
-TODO:
- - checkpatch.pl cleanups
- - sparse fixes
- - audit the userspace interface
- - sysfs vs. char?
- - Documentation/ABI/ needs to be added
- - put the sample .txt files and README file somewhere.
-
-Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
-Cc: Jakub Schmidtke <sjakub@gmail.com>
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
deleted file mode 100644
index 3654dc32a0c..00000000000
--- a/drivers/staging/asus_oled/asus_oled.c
+++ /dev/null
@@ -1,847 +0,0 @@
-/*
- * Asus OLED USB driver
- *
- * Copyright (C) 2007,2008 Jakub Schmidtke (sjakub@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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *
- *
- * This module is based on usbled and asus-laptop modules.
- *
- *
- * Asus OLED support is based on asusoled program taken from
- * <http://lapsus.berlios.de/asus_oled.html>.
- *
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/platform_device.h>
-#include <linux/ctype.h>
-
-#define ASUS_OLED_VERSION "0.04-dev"
-#define ASUS_OLED_NAME "asus-oled"
-#define ASUS_OLED_UNDERSCORE_NAME "asus_oled"
-
-#define ASUS_OLED_STATIC 's'
-#define ASUS_OLED_ROLL 'r'
-#define ASUS_OLED_FLASH 'f'
-
-#define ASUS_OLED_MAX_WIDTH 1792
-#define ASUS_OLED_DISP_HEIGHT 32
-#define ASUS_OLED_PACKET_BUF_SIZE 256
-
-#define USB_VENDOR_ID_ASUS 0x0b05
-#define USB_DEVICE_ID_ASUS_LCM 0x1726
-#define USB_DEVICE_ID_ASUS_LCM2 0x175b
-
-MODULE_AUTHOR("Jakub Schmidtke, sjakub@gmail.com");
-MODULE_DESCRIPTION("Asus OLED Driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(ASUS_OLED_VERSION);
-
-static struct class *oled_class;
-static int oled_num;
-
-static uint start_off;
-
-module_param(start_off, uint, 0644);
-
-MODULE_PARM_DESC(start_off,
- "Set to 1 to switch off OLED display after it is attached");
-
-enum oled_pack_mode {
- PACK_MODE_G1,
- PACK_MODE_G50,
- PACK_MODE_LAST
-};
-
-struct oled_dev_desc_str {
- uint16_t idVendor;
- uint16_t idProduct;
- /* width of display */
- uint16_t devWidth;
- /* formula to be used while packing the picture */
- enum oled_pack_mode packMode;
- const char *devDesc;
-};
-
-/* table of devices that work with this driver */
-static const struct usb_device_id id_table[] = {
- /* Asus G1/G2 (and variants)*/
- { USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM) },
- /* Asus G50V (and possibly others - G70? G71?)*/
- { USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2) },
- { },
-};
-
-/* parameters of specific devices */
-static struct oled_dev_desc_str oled_dev_desc_table[] = {
- { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, 128, PACK_MODE_G1,
- "G1/G2" },
- { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2, 256, PACK_MODE_G50,
- "G50" },
- { },
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-struct asus_oled_header {
- uint8_t magic1;
- uint8_t magic2;
- uint8_t flags;
- uint8_t value3;
- uint8_t buffer1;
- uint8_t buffer2;
- uint8_t value6;
- uint8_t value7;
- uint8_t value8;
- uint8_t padding2[7];
-} __attribute((packed));
-
-struct asus_oled_packet {
- struct asus_oled_header header;
- uint8_t bitmap[ASUS_OLED_PACKET_BUF_SIZE];
-} __attribute((packed));
-
-struct asus_oled_dev {
- struct usb_device *udev;
- uint8_t pic_mode;
- uint16_t dev_width;
- enum oled_pack_mode pack_mode;
- size_t height;
- size_t width;
- size_t x_shift;
- size_t y_shift;
- size_t buf_offs;
- uint8_t last_val;
- size_t buf_size;
- char *buf;
- uint8_t enabled;
- uint8_t enabled_post_resume;
- struct device *dev;
-};
-
-static void setup_packet_header(struct asus_oled_packet *packet, char flags,
- char value3, char buffer1, char buffer2, char value6,
- char value7, char value8)
-{
- memset(packet, 0, sizeof(struct asus_oled_header));
- packet->header.magic1 = 0x55;
- packet->header.magic2 = 0xaa;
- packet->header.flags = flags;
- packet->header.value3 = value3;
- packet->header.buffer1 = buffer1;
- packet->header.buffer2 = buffer2;
- packet->header.value6 = value6;
- packet->header.value7 = value7;
- packet->header.value8 = value8;
-}
-
-static void enable_oled(struct asus_oled_dev *odev, uint8_t enabl)
-{
- int retval;
- int act_len;
- struct asus_oled_packet *packet;
-
- packet = kzalloc(sizeof(struct asus_oled_packet), GFP_KERNEL);
- if (!packet)
- return;
-
- setup_packet_header(packet, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00);
-
- if (enabl)
- packet->bitmap[0] = 0xaf;
- else
- packet->bitmap[0] = 0xae;
-
- retval = usb_bulk_msg(odev->udev,
- usb_sndbulkpipe(odev->udev, 2),
- packet,
- sizeof(struct asus_oled_header) + 1,
- &act_len,
- -1);
-
- if (retval)
- dev_dbg(&odev->udev->dev, "retval = %d\n", retval);
-
- odev->enabled = enabl;
-
- kfree(packet);
-}
-
-static ssize_t set_enabled(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_interface *intf = to_usb_interface(dev);
- struct asus_oled_dev *odev = usb_get_intfdata(intf);
- unsigned long value;
- if (kstrtoul(buf, 10, &value))
- return -EINVAL;
-
- enable_oled(odev, value);
-
- return count;
-}
-
-static ssize_t class_set_enabled(struct device *device,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct asus_oled_dev *odev =
- (struct asus_oled_dev *) dev_get_drvdata(device);
- unsigned long value;
-
- if (kstrtoul(buf, 10, &value))
- return -EINVAL;
-
- enable_oled(odev, value);
-
- return count;
-}
-
-static ssize_t get_enabled(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct usb_interface *intf = to_usb_interface(dev);
- struct asus_oled_dev *odev = usb_get_intfdata(intf);
-
- return sprintf(buf, "%d\n", odev->enabled);
-}
-
-static ssize_t class_get_enabled(struct device *device,
- struct device_attribute *attr, char *buf)
-{
- struct asus_oled_dev *odev =
- (struct asus_oled_dev *) dev_get_drvdata(device);
-
- return sprintf(buf, "%d\n", odev->enabled);
-}
-
-static void send_packets(struct usb_device *udev,
- struct asus_oled_packet *packet,
- char *buf, uint8_t p_type, size_t p_num)
-{
- size_t i;
- int act_len;
-
- for (i = 0; i < p_num; i++) {
- int retval;
-
- switch (p_type) {
- case ASUS_OLED_ROLL:
- setup_packet_header(packet, 0x40, 0x80, p_num,
- i + 1, 0x00, 0x01, 0xff);
- break;
- case ASUS_OLED_STATIC:
- setup_packet_header(packet, 0x10 + i, 0x80, 0x01,
- 0x01, 0x00, 0x01, 0x00);
- break;
- case ASUS_OLED_FLASH:
- setup_packet_header(packet, 0x10 + i, 0x80, 0x01,
- 0x01, 0x00, 0x00, 0xff);
- break;
- }
-
- memcpy(packet->bitmap, buf + (ASUS_OLED_PACKET_BUF_SIZE*i),
- ASUS_OLED_PACKET_BUF_SIZE);
-
- retval = usb_bulk_msg(udev, usb_sndctrlpipe(udev, 2),
- packet, sizeof(struct asus_oled_packet),
- &act_len, -1);
-
- if (retval)
- dev_dbg(&udev->dev, "retval = %d\n", retval);
- }
-}
-
-static void send_packet(struct usb_device *udev,
- struct asus_oled_packet *packet,
- size_t offset, size_t len, char *buf, uint8_t b1,
- uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5,
- uint8_t b6) {
- int retval;
- int act_len;
-
- setup_packet_header(packet, b1, b2, b3, b4, b5, b6, 0x00);
- memcpy(packet->bitmap, buf + offset, len);
-
- retval = usb_bulk_msg(udev,
- usb_sndctrlpipe(udev, 2),
- packet,
- sizeof(struct asus_oled_packet),
- &act_len,
- -1);
-
- if (retval)
- dev_dbg(&udev->dev, "retval = %d\n", retval);
-}
-
-
-static void send_packets_g50(struct usb_device *udev,
- struct asus_oled_packet *packet, char *buf)
-{
- send_packet(udev, packet, 0, 0x100, buf,
- 0x10, 0x00, 0x02, 0x01, 0x00, 0x01);
- send_packet(udev, packet, 0x100, 0x080, buf,
- 0x10, 0x00, 0x02, 0x02, 0x80, 0x00);
-
- send_packet(udev, packet, 0x180, 0x100, buf,
- 0x11, 0x00, 0x03, 0x01, 0x00, 0x01);
- send_packet(udev, packet, 0x280, 0x100, buf,
- 0x11, 0x00, 0x03, 0x02, 0x00, 0x01);
- send_packet(udev, packet, 0x380, 0x080, buf,
- 0x11, 0x00, 0x03, 0x03, 0x80, 0x00);
-}
-
-
-static void send_data(struct asus_oled_dev *odev)
-{
- size_t packet_num = odev->buf_size / ASUS_OLED_PACKET_BUF_SIZE;
- struct asus_oled_packet *packet;
-
- packet = kzalloc(sizeof(struct asus_oled_packet), GFP_KERNEL);
- if (!packet)
- return;
-
- if (odev->pack_mode == PACK_MODE_G1) {
- /*
- * When sending roll-mode data the display updated only
- * first packet. I have no idea why, but when static picture
- * is sent just before rolling picture everything works fine.
- */
- if (odev->pic_mode == ASUS_OLED_ROLL)
- send_packets(odev->udev, packet, odev->buf,
- ASUS_OLED_STATIC, 2);
-
- /* Only ROLL mode can use more than 2 packets.*/
- if (odev->pic_mode != ASUS_OLED_ROLL && packet_num > 2)
- packet_num = 2;
-
- send_packets(odev->udev, packet, odev->buf,
- odev->pic_mode, packet_num);
- } else if (odev->pack_mode == PACK_MODE_G50) {
- send_packets_g50(odev->udev, packet, odev->buf);
- }
-
- kfree(packet);
-}
-
-static int append_values(struct asus_oled_dev *odev, uint8_t val, size_t count)
-{
- odev->last_val = val;
-
- if (val == 0) {
- odev->buf_offs += count;
- return 0;
- }
-
- while (count-- > 0) {
- size_t x = odev->buf_offs % odev->width;
- size_t y = odev->buf_offs / odev->width;
- size_t i;
-
- x += odev->x_shift;
- y += odev->y_shift;
-
- switch (odev->pack_mode) {
- case PACK_MODE_G1:
- /*
- * i = (x/128)*640 + 127 - x + (y/8)*128;
- * This one for 128 is the same, but might be better
- * for different widths?
- */
- i = (x/odev->dev_width)*640 +
- odev->dev_width - 1 - x +
- (y/8)*odev->dev_width;
- break;
-
- case PACK_MODE_G50:
- i = (odev->dev_width - 1 - x)/8 + y*odev->dev_width/8;
- break;
-
- default:
- i = 0;
- dev_err(odev->dev, "Unknown OLED Pack Mode: %d!\n",
- odev->pack_mode);
- break;
- }
-
- if (i >= odev->buf_size) {
- dev_err(odev->dev, "Buffer overflow! Report a bug: offs: %zu >= %zu i: %zu (x: %zu y: %zu)\n",
- odev->buf_offs, odev->buf_size, i, x, y);
- return -EIO;
- }
-
- switch (odev->pack_mode) {
- case PACK_MODE_G1:
- odev->buf[i] &= ~(1<<(y%8));
- break;
-
- case PACK_MODE_G50:
- odev->buf[i] &= ~(1<<(x%8));
- break;
-
- default:
- /* cannot get here; stops gcc complaining*/
- break;
- }
-
- odev->buf_offs++;
- }
-
- return 0;
-}
-
-static ssize_t odev_set_picture(struct asus_oled_dev *odev,
- const char *buf, size_t count)
-{
- size_t offs = 0, max_offs;
-
- if (count < 1)
- return 0;
-
- if (tolower(buf[0]) == 'b') {
- /* binary mode, set the entire memory*/
-
- size_t i;
-
- odev->buf_size = (odev->dev_width * ASUS_OLED_DISP_HEIGHT) / 8;
-
- kfree(odev->buf);
- odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
- if (odev->buf == NULL) {
- odev->buf_size = 0;
- dev_err(odev->dev, "Out of memory!\n");
- return -ENOMEM;
- }
-
- memset(odev->buf, 0xff, odev->buf_size);
-
- for (i = 1; i < count && i <= 32 * 32; i++) {
- odev->buf[i-1] = buf[i];
- odev->buf_offs = i-1;
- }
-
- odev->width = odev->dev_width / 8;
- odev->height = ASUS_OLED_DISP_HEIGHT;
- odev->x_shift = 0;
- odev->y_shift = 0;
- odev->last_val = 0;
-
- send_data(odev);
-
- return count;
- }
-
- if (buf[0] == '<') {
- size_t i;
- size_t w = 0, h = 0;
- size_t w_mem, h_mem;
-
- if (count < 10 || buf[2] != ':')
- goto error_header;
-
-
- switch (tolower(buf[1])) {
- case ASUS_OLED_STATIC:
- case ASUS_OLED_ROLL:
- case ASUS_OLED_FLASH:
- odev->pic_mode = buf[1];
- break;
- default:
- dev_err(odev->dev, "Wrong picture mode: '%c'.\n",
- buf[1]);
- return -EIO;
- break;
- }
-
- for (i = 3; i < count; ++i) {
- if (buf[i] >= '0' && buf[i] <= '9') {
- w = 10*w + (buf[i] - '0');
-
- if (w > ASUS_OLED_MAX_WIDTH)
- goto error_width;
- } else if (tolower(buf[i]) == 'x') {
- break;
- } else {
- goto error_width;
- }
- }
-
- for (++i; i < count; ++i) {
- if (buf[i] >= '0' && buf[i] <= '9') {
- h = 10*h + (buf[i] - '0');
-
- if (h > ASUS_OLED_DISP_HEIGHT)
- goto error_height;
- } else if (tolower(buf[i]) == '>') {
- break;
- } else {
- goto error_height;
- }
- }
-
- if (w < 1 || w > ASUS_OLED_MAX_WIDTH)
- goto error_width;
-
- if (h < 1 || h > ASUS_OLED_DISP_HEIGHT)
- goto error_height;
-
- if (i >= count || buf[i] != '>')
- goto error_header;
-
- offs = i+1;
-
- if (w % (odev->dev_width) != 0)
- w_mem = (w/(odev->dev_width) + 1)*(odev->dev_width);
- else
- w_mem = w;
-
- if (h < ASUS_OLED_DISP_HEIGHT)
- h_mem = ASUS_OLED_DISP_HEIGHT;
- else
- h_mem = h;
-
- odev->buf_size = w_mem * h_mem / 8;
-
- kfree(odev->buf);
- odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
-
- if (odev->buf == NULL) {
- odev->buf_size = 0;
- dev_err(odev->dev, "Out of memory!\n");
- return -ENOMEM;
- }
-
- memset(odev->buf, 0xff, odev->buf_size);
-
- odev->buf_offs = 0;
- odev->width = w;
- odev->height = h;
- odev->x_shift = 0;
- odev->y_shift = 0;
- odev->last_val = 0;
-
- if (odev->pic_mode == ASUS_OLED_FLASH) {
- if (h < ASUS_OLED_DISP_HEIGHT/2)
- odev->y_shift = (ASUS_OLED_DISP_HEIGHT/2 - h)/2;
- } else {
- if (h < ASUS_OLED_DISP_HEIGHT)
- odev->y_shift = (ASUS_OLED_DISP_HEIGHT - h)/2;
- }
-
- if (w < (odev->dev_width))
- odev->x_shift = ((odev->dev_width) - w)/2;
- }
-
- max_offs = odev->width * odev->height;
-
- while (offs < count && odev->buf_offs < max_offs) {
- int ret = 0;
-
- if (buf[offs] == '1' || buf[offs] == '#') {
- ret = append_values(odev, 1, 1);
- if (ret < 0)
- return ret;
- } else if (buf[offs] == '0' || buf[offs] == ' ') {
- ret = append_values(odev, 0, 1);
- if (ret < 0)
- return ret;
- } else if (buf[offs] == '\n') {
- /*
- * New line detected. Lets assume, that all characters
- * till the end of the line were equal to the last
- * character in this line.
- */
- if (odev->buf_offs % odev->width != 0)
- ret = append_values(odev, odev->last_val,
- odev->width -
- (odev->buf_offs %
- odev->width));
- if (ret < 0)
- return ret;
- }
-
- offs++;
- }
-
- if (odev->buf_offs >= max_offs)
- send_data(odev);
-
- return count;
-
-error_width:
- dev_err(odev->dev, "Wrong picture width specified.\n");
- return -EIO;
-
-error_height:
- dev_err(odev->dev, "Wrong picture height specified.\n");
- return -EIO;
-
-error_header:
- dev_err(odev->dev, "Wrong picture header.\n");
- return -EIO;
-}
-
-static ssize_t set_picture(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_interface *intf = to_usb_interface(dev);
-
- return odev_set_picture(usb_get_intfdata(intf), buf, count);
-}
-
-static ssize_t class_set_picture(struct device *device,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return odev_set_picture((struct asus_oled_dev *)
- dev_get_drvdata(device), buf, count);
-}
-
-#define ASUS_OLED_DEVICE_ATTR(_file) dev_attr_asus_oled_##_file
-
-static DEVICE_ATTR(asus_oled_enabled, S_IWUSR | S_IRUGO,
- get_enabled, set_enabled);
-static DEVICE_ATTR(asus_oled_picture, S_IWUSR , NULL, set_picture);
-
-static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO,
- class_get_enabled, class_set_enabled);
-static DEVICE_ATTR(picture, S_IWUSR, NULL, class_set_picture);
-
-static int asus_oled_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(interface);
- struct asus_oled_dev *odev = NULL;
- int retval = -ENOMEM;
- uint16_t dev_width = 0;
- enum oled_pack_mode pack_mode = PACK_MODE_LAST;
- const struct oled_dev_desc_str *dev_desc = oled_dev_desc_table;
- const char *desc = NULL;
-
- if (!id) {
- /* Even possible? Just to make sure...*/
- dev_err(&interface->dev, "No usb_device_id provided!\n");
- return -ENODEV;
- }
-
- for (; dev_desc->idVendor; dev_desc++) {
- if (dev_desc->idVendor == id->idVendor
- && dev_desc->idProduct == id->idProduct) {
- dev_width = dev_desc->devWidth;
- desc = dev_desc->devDesc;
- pack_mode = dev_desc->packMode;
- break;
- }
- }
-
- if (!desc || dev_width < 1 || pack_mode == PACK_MODE_LAST) {
- dev_err(&interface->dev,
- "Missing or incomplete device description!\n");
- return -ENODEV;
- }
-
- odev = kzalloc(sizeof(struct asus_oled_dev), GFP_KERNEL);
- if (odev == NULL)
- return -ENOMEM;
-
- odev->udev = usb_get_dev(udev);
- odev->pic_mode = ASUS_OLED_STATIC;
- odev->dev_width = dev_width;
- odev->pack_mode = pack_mode;
- odev->height = 0;
- odev->width = 0;
- odev->x_shift = 0;
- odev->y_shift = 0;
- odev->buf_offs = 0;
- odev->buf_size = 0;
- odev->last_val = 0;
- odev->buf = NULL;
- odev->enabled = 1;
- odev->dev = NULL;
-
- usb_set_intfdata(interface, odev);
-
- retval = device_create_file(&interface->dev,
- &ASUS_OLED_DEVICE_ATTR(enabled));
- if (retval)
- goto err_files;
-
- retval = device_create_file(&interface->dev,
- &ASUS_OLED_DEVICE_ATTR(picture));
- if (retval)
- goto err_files;
-
- odev->dev = device_create(oled_class, &interface->dev, MKDEV(0, 0),
- NULL, "oled_%d", ++oled_num);
-
- if (IS_ERR(odev->dev)) {
- retval = PTR_ERR(odev->dev);
- goto err_files;
- }
-
- dev_set_drvdata(odev->dev, odev);
-
- retval = device_create_file(odev->dev, &dev_attr_enabled);
- if (retval)
- goto err_class_enabled;
-
- retval = device_create_file(odev->dev, &dev_attr_picture);
- if (retval)
- goto err_class_picture;
-
- dev_info(&interface->dev,
- "Attached Asus OLED device: %s [width %u, pack_mode %d]\n",
- desc, odev->dev_width, odev->pack_mode);
-
- if (start_off)
- enable_oled(odev, 0);
-
- return 0;
-
-err_class_picture:
- device_remove_file(odev->dev, &dev_attr_picture);
-
-err_class_enabled:
- device_remove_file(odev->dev, &dev_attr_enabled);
- device_unregister(odev->dev);
-
-err_files:
- device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled));
- device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture));
-
- usb_set_intfdata(interface, NULL);
- usb_put_dev(odev->udev);
- kfree(odev);
-
- return retval;
-}
-
-static void asus_oled_disconnect(struct usb_interface *interface)
-{
- struct asus_oled_dev *odev;
-
- odev = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
-
- device_remove_file(odev->dev, &dev_attr_picture);
- device_remove_file(odev->dev, &dev_attr_enabled);
- device_unregister(odev->dev);
-
- device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture));
- device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled));
-
- usb_put_dev(odev->udev);
-
- kfree(odev->buf);
-
- kfree(odev);
-
- dev_info(&interface->dev, "Disconnected Asus OLED device\n");
-}
-
-#ifdef CONFIG_PM
-static int asus_oled_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct asus_oled_dev *odev;
-
- odev = usb_get_intfdata(intf);
- if (!odev)
- return -ENODEV;
-
- odev->enabled_post_resume = odev->enabled;
- enable_oled(odev, 0);
-
- return 0;
-}
-
-static int asus_oled_resume(struct usb_interface *intf)
-{
- struct asus_oled_dev *odev;
-
- odev = usb_get_intfdata(intf);
- if (!odev)
- return -ENODEV;
-
- enable_oled(odev, odev->enabled_post_resume);
-
- return 0;
-}
-#else
-#define asus_oled_suspend NULL
-#define asus_oled_resume NULL
-#endif
-
-static struct usb_driver oled_driver = {
- .name = ASUS_OLED_NAME,
- .probe = asus_oled_probe,
- .disconnect = asus_oled_disconnect,
- .id_table = id_table,
- .suspend = asus_oled_suspend,
- .resume = asus_oled_resume,
-};
-
-static CLASS_ATTR_STRING(version, S_IRUGO,
- ASUS_OLED_UNDERSCORE_NAME " " ASUS_OLED_VERSION);
-
-static int __init asus_oled_init(void)
-{
- int retval = 0;
- oled_class = class_create(THIS_MODULE, ASUS_OLED_UNDERSCORE_NAME);
-
- if (IS_ERR(oled_class)) {
- pr_err("Error creating " ASUS_OLED_UNDERSCORE_NAME " class\n");
- return PTR_ERR(oled_class);
- }
-
- retval = class_create_file(oled_class, &class_attr_version.attr);
- if (retval) {
- pr_err("Error creating class version file\n");
- goto error;
- }
-
- retval = usb_register(&oled_driver);
-
- if (retval) {
- pr_err("usb_register failed. Error number %d\n", retval);
- goto error;
- }
-
- return retval;
-
-error:
- class_destroy(oled_class);
- return retval;
-}
-
-static void __exit asus_oled_exit(void)
-{
- usb_deregister(&oled_driver);
- class_remove_file(oled_class, &class_attr_version.attr);
- class_destroy(oled_class);
-}
-
-module_init(asus_oled_init);
-module_exit(asus_oled_exit);
-
diff --git a/drivers/staging/asus_oled/linux.txt b/drivers/staging/asus_oled/linux.txt
deleted file mode 100644
index dc758b0eb37..00000000000
--- a/drivers/staging/asus_oled/linux.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<s:74x32>
-0
-0
-00000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000
-01111111111000000000000000000000000000000000000000000000000000000000000000
-00011111100000000000000111000000000000000000000000000000000000000000000000
-00001111000000000000000111000000000000000000000000000000000000000000000000
-00001111000000000000000111000000000000000000000000000000000000000000000000
-00001111000000000000000000000000000000000000000000000000000000000000000000
-00001111000000000000000000000000000000000000000000000000000000000000000000
-00001111000000000000011100001111111111100000111110011111100011111101111000
-00001111000000000000111110000011111000111000111110000111100001111000110000
-00001111000000000001101110000011111000111000001111000111100000111100100000
-00001111000000000001001110000011110000111100001111000111100000111101100000
-00001111000000000100001110000011110000111100001111000111100000011111000000
-00001111000000000100011110000011110000111100001111000111100000001111000000
-00001111000000000100011110000011110000111100001111000111100000001111000000
-00001111000000000100011100100011110000111100001111000111100000001111100000
-00001111000000001100111100100011110000111100001111000111100000001111110000
-00001111000000001100111101100011110000111100001111000111100000011011110000
-00001111000000011100111101000011110000111100001111000111100000010001111000
-00011111000001111100111011000011110000111100001111001111100000110000111100
-11111111111111111100011110001111111011111110000111110111111011111011111110
-00000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000
-0
-0
-0
-0
diff --git a/drivers/staging/asus_oled/linux_f.txt b/drivers/staging/asus_oled/linux_f.txt
deleted file mode 100644
index b4bb85cc6eb..00000000000
--- a/drivers/staging/asus_oled/linux_f.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-<f:128x16>
-00000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000011000111111111100001111001111100111110111000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000111100001111000110001111000111100011100010000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000001011100001111000111000111100111100001110110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000011100001110000111000111100111100001111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100111001001110000111000111100111100000111110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000001100111011001110000111000111100111100000111110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000001100111010001110000111000111100111100000100111000000000000000000000000000000000000
-00000000000000000000000000000000000011110000111100110110001110000111000111100111100001000011100000000000000000000000000000000000
-00000000000000000000000000000000001111111111111100111100111111011111100011110111110111101111110000000000000000000000000000000000
-
diff --git a/drivers/staging/asus_oled/linux_fr.txt b/drivers/staging/asus_oled/linux_fr.txt
deleted file mode 100644
index f88e2b3bdd1..00000000000
--- a/drivers/staging/asus_oled/linux_fr.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<f:128x32>
-00000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000011000111111111100001111001111100111110111000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000111100001111000110001111000111100011100010000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000001011100001111000111000111100111100001110110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000011100001110000111000111100111100001111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100111001001110000111000111100111100000111110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000001100111011001110000111000111100111100000111110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000001100111010001110000111000111100111100000100111000000000000000000000000000000000000
-00000000000000000000000000000000000011110000111100110110001110000111000111100111100001000011100000000000000000000000000000000000
-00000000000000000000000000000000001111111111111100111100111111011111100011110111110111101111110000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000
-00000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000
-00000000000000000000000000011111100000000000000000000000000000000000000000000000000000000000011111100000000000000000000000000000
-00000000000000000000000000011111100000000000000000000000000000000000000000000000000000000000011111100000000000000000000000000000
-00000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000
-00000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/drivers/staging/asus_oled/tux.txt b/drivers/staging/asus_oled/tux.txt
deleted file mode 100644
index 9d2052854b6..00000000000
--- a/drivers/staging/asus_oled/tux.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<s:32x32>
-00000000000001111111000000000000
-0000000000001 100000000000
-000000000001 10000000000
-000000000001 10000000000
-000000000001 10000000000
-000000000001 1 111 10000000000
-000000000001 1 1 1000000000
-000000000001 111 1000000000
-000000000001 111111 1000000000
-000000000001 111111 1000000000
-000000000001 1 1 100000000
-00000000001 11 100000000
-00000000001 11111111 10000000
-0000000001 11111111 1000000
-000000001 111111111 1000000
-000000001 1111111111 100000
-00000001 11111111111 100000
-00000001 111111111111 10000
-0000001 111111111111 10000
-0000001 111111111111 10000
-0000001 111111111111 10000
-0000001 111111111111 10000
-000000011 11111111111 10000
-000011 11 11111111111 100000
-0001 1111 111111111111111 1000
-001 1111111 11111111111111 1000
-001 1111111 1111111 111111 100
-001 11111111 111111 1111111 10
-001 11111111 11111 100
-001 1111111 111 11100
-000111 111 11111 11 100000
-000000111 111111111 1000000
diff --git a/drivers/staging/asus_oled/tux_r.txt b/drivers/staging/asus_oled/tux_r.txt
deleted file mode 100644
index fd81a3e8494..00000000000
--- a/drivers/staging/asus_oled/tux_r.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<r:32x32>
-00000000000001111111000000000000
-0000000000001 100000000000
-000000000001 10000000000
-000000000001 10000000000
-000000000001 10000000000
-000000000001 1 111 10000000000
-000000000001 1 1 1000000000
-000000000001 111 1000000000
-000000000001 111111 1000000000
-000000000001 111111 1000000000
-000000000001 1 1 100000000
-00000000001 11 100000000
-00000000001 11111111 10000000
-0000000001 11111111 1000000
-000000001 111111111 1000000
-000000001 1111111111 100000
-00000001 11111111111 100000
-00000001 111111111111 10000
-0000001 111111111111 10000
-0000001 111111111111 10000
-0000001 111111111111 10000
-0000001 111111111111 10000
-000000011 11111111111 10000
-000011 11 11111111111 100000
-0001 1111 111111111111111 1000
-001 1111111 11111111111111 1000
-001 1111111 1111111 111111 100
-001 11111111 111111 1111111 10
-001 11111111 11111 100
-001 1111111 111 11100
-000111 111 11111 11 100000
-000000111 111111111 1000000
diff --git a/drivers/staging/asus_oled/tux_r2.txt b/drivers/staging/asus_oled/tux_r2.txt
deleted file mode 100644
index e94d84eaab0..00000000000
--- a/drivers/staging/asus_oled/tux_r2.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<r:256x32>
-000000000000000000000000000000000000000000000000000000000000011111110000000000000000000000000000000000000000000000000000000000000
-0000000000000000000000000000000000000000000000000000000000001 1000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 1 111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 1 1 100000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111100000000000000111000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000111000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000111000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 1 1 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000001 11 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000001 11111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000011100001111111111100000111110011111100011111101111000000000000000000000000000000
-0000000000000000000000000000000000000000000000000000000001 11111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000111110000011111000111000111110000111100001111000110000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000001 111111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000001101110000011111000111000001111000111100000111100100000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000001 1111111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000001001110000011110000111100001111000111100000111101100000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000001 11111111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000100001110000011110000111100001111000111100000011111000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000001 111111111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000011110000000001000111100000111100001111000011110001111000000011110000000
-0000000000000000000000000000000000000000000000000000001 111111111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000100011110000011110000111100001111000111100000001111000000
-0000000000000000000000000000000000000000000000000000001 111111111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000100011100100011110000111100001111000111100000001111100000000000000000000000000000000
-0000000000000000000000000000000000000000000000000000001 111111111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000001100111100100011110000111100001111000111100000001111110000000000000000000000000000000
-0000000000000000000000000000000000000000000000000000001 111111111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000001100111101100011110000111100001111000111100000011011110000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000011 11111111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000011100111101000011110000111100001111000111100000010001111000000000000000000000000000000
-000000000000000000000000000000000000000000000000000011 11 11111111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000011111000001111100111011000011110000111100001111001111100000110000111100000000000000000000000000000
-0000000000000000000000000000000000000000000000000001 1111 111111111111111 100000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111100011110001111111011111110000111110111111011111011111110000000000000000000000000000
-000000000000000000000000000000000000000000000000001 1111111 11111111111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000001 1111111 1111111 111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000001 11111111 111111 1111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000001 11111111 11111 1000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000001 1111111 111 111000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000111 111 11111 11 10
-000000000000000000000000000000000000000000000000000000111 111111111 10
diff --git a/drivers/staging/asus_oled/zig.txt b/drivers/staging/asus_oled/zig.txt
deleted file mode 100644
index 31573d8f799..00000000000
--- a/drivers/staging/asus_oled/zig.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<r:128x32>
-10000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000001
-01000000000000000000000000000000000000000000000000000000000000100100000000000000000000000000000000000000000000000000000000000010
-00100000000000000000000000000000000000000000000000000000000001000010000000000000000000000000000000000000000000000000000000000100
-00010000000000000000000000000000000000000000000000000000000010000001000000000000000000000000000000000000000000000000000000001000
-00001000000000000000000000000000000000000000000000000000000100000000100000000000000000000000000000000000000000000000000000010000
-00000100000000000000000000000000000000000000000000000000001000000000010000000000000000000000000000000000000000000000000000100000
-00000010000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000001000000
-00000001000000000000000000000000000000000000000000000000100000000000000100000000000000000000000000000000000000000000000010000000
-00000000100000000000000000000000000000000000000000000001000000000000000010000000000000000000000000000000000000000000000100000000
-00000000010000000000000000000000000000000000000000000010000000000000000001000000000000000000000000000000000000000000001000000000
-00000000001000000000000000000000000000000000000000000100000000000000000000100000000000000000000000000000000000000000010000000000
-00000000000100000000000000000000000000000000000000001000000000000000000000010000000000000000000000000000000000000000100000000000
-00000000000010000000000000000000000000000000000000010000000000000000000000001000000000000000000000000000000000000001000000000000
-00000000000001000000000000000000000000000000000000100000000000000000000000000100000000000000000000000000000000000010000000000000
-00000000000000100000000000000000000000000000000001000000000000000000000000000010000000000000000000000000000000000100000000000000
-00000000000000010000000000000000000000000000000010000000000000000000000000000001000000000000000000000000000000001000000000000000
-00000000000000001000000000000000000000000000000100000000000000000000000000000000100000000000000000000000000000010000000000000000
-00000000000000000100000000000000000000000000001000000000000000000000000000000000010000000000000000000000000000100000000000000000
-00000000000000000010000000000000000000000000010000000000000000000000000000000000001000000000000000000000000001000000000000000000
-00000000000000000001000000000000000000000000100000000000000000000000000000000000000100000000000000000000000010000000000000000000
-00000000000000000000100000000000000000000001000000000000000000000000000000000000000010000000000000000000000100000000000000000000
-00000000000000000000010000000000000000000010000000000000000000000000000000000000000001000000000000000000001000000000000000000000
-00000000000000000000001000000000000000000100000000000000000000000000000000000000000000100000000000000000010000000000000000000000
-00000000000000000000000100000000000000001000000000000000000000000000000000000000000000010000000000000000100000000000000000000000
-00000000000000000000000010000000000000010000000000000000000000000000000000000000000000001000000000000001000000000000000000000000
-00000000000000000000000001000000000000100000000000000000000000000000000000000000000000000100000000000010000000000000000000000000
-00000000000000000000000000100000000001000000000000000000000000000000000000000000000000000010000000000100000000000000000000000000
-00000000000000000000000000010000000010000000000000000000000000000000000000000000000000000001000000001000000000000000000000000000
-00000000000000000000000000001000000100000000000000000000000000000000000000000000000000000000100000010000000000000000000000000000
-00000000000000000000000000000100001000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000
-00000000000000000000000000000010010000000000000000000000000000000000000000000000000000000000001001000000000000000000000000000000
-00000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000
diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c
index f67a22536cb..f91bc1fdd89 100644
--- a/drivers/staging/bcm/Bcmchar.c
+++ b/drivers/staging/bcm/Bcmchar.c
@@ -1004,9 +1004,9 @@ cntrlEnd:
if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
return -EFAULT;
- len = min_t(ulong, IoBuffer.OutputLength, strlen(VER_FILEVERSION_STR) + 1);
+ len = min_t(ulong, IoBuffer.OutputLength, strlen(DRV_VERSION) + 1);
- if (copy_to_user(IoBuffer.OutputBuffer, VER_FILEVERSION_STR, len))
+ if (copy_to_user(IoBuffer.OutputBuffer, DRV_VERSION, len))
return -EFAULT;
Status = STATUS_SUCCESS;
break;
diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c
index 8c696b64ab2..f5eda96f0f8 100644
--- a/drivers/staging/bcm/DDRInit.c
+++ b/drivers/staging/bcm/DDRInit.c
@@ -828,13 +828,13 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
{
retval= rdmalt(Adapter,(UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
uiResetValue |= 0x44;
retval = wrmalt(Adapter,(UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, WRM, DBG_LVL_ALL, "%s:%d WRM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
}
@@ -972,7 +972,7 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
}
retval = wrmalt(Adapter, psDDRSetting->ulRegAddress, &value, sizeof(value));
if(STATUS_SUCCESS != retval) {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
break;
}
@@ -992,25 +992,25 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
uiResetValue = 0x01010001;
retval = wrmalt(Adapter, (UINT)0x0F007018, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
uiResetValue = 0x00040020;
retval = wrmalt(Adapter, (UINT)0x0F007094, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
uiResetValue = 0x01020101;
retval = wrmalt(Adapter, (UINT)0x0F00701c, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
uiResetValue = 0x01010000;
retval = wrmalt(Adapter, (UINT)0x0F007018, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
}
@@ -1026,34 +1026,34 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
{
retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
uiResetValue = 0x1322a8;
retval = wrmalt(Adapter, (UINT)0x0f000d1c, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
uiResetValue = 0x132296;
retval = wrmalt(Adapter, (UINT)0x0f000d14, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
}
@@ -1062,34 +1062,34 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
uiResetValue = 0x6003229a;
retval = wrmalt(Adapter, (UINT)0x0f000d14, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
uiResetValue = 0x1322a8;
retval = wrmalt(Adapter, (UINT)0x0f000d1c, &uiResetValue, sizeof(uiResetValue));
if(retval < 0) {
- BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
return retval;
}
}
@@ -1235,28 +1235,28 @@ int download_ddr_settings(struct bcm_mini_adapter *Adapter)
retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value));
if(retval)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
return retval;
}
- ul_ddr_setting_load_addr+=sizeof(ULONG);
+ ul_ddr_setting_load_addr += sizeof(ULONG);
/*signature */
value =(0x1d1e0dd0);
retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value));
if(retval)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
return retval;
}
- ul_ddr_setting_load_addr+=sizeof(ULONG);
+ ul_ddr_setting_load_addr += sizeof(ULONG);
RegCount*=(sizeof(struct bcm_ddr_setting)/sizeof(ULONG));
while(RegCount && !retval)
{
value = psDDRSetting->ulRegAddress ;
retval = wrmalt( Adapter, ul_ddr_setting_load_addr, &value, sizeof(value));
- ul_ddr_setting_load_addr+=sizeof(ULONG);
+ ul_ddr_setting_load_addr += sizeof(ULONG);
if(!retval)
{
if(bOverrideSelfRefresh && (psDDRSetting->ulRegAddress == 0x0F007018))
@@ -1264,7 +1264,7 @@ int download_ddr_settings(struct bcm_mini_adapter *Adapter)
value = (psDDRSetting->ulRegValue |(1<<8));
if(STATUS_SUCCESS != wrmalt(Adapter, ul_ddr_setting_load_addr,
&value, sizeof(value))){
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
break;
}
}
@@ -1274,12 +1274,12 @@ int download_ddr_settings(struct bcm_mini_adapter *Adapter)
if(STATUS_SUCCESS != wrmalt(Adapter, ul_ddr_setting_load_addr ,
&value, sizeof(value))){
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
break;
}
}
}
- ul_ddr_setting_load_addr+=sizeof(ULONG);
+ ul_ddr_setting_load_addr += sizeof(ULONG);
RegCount--;
psDDRSetting++;
}
diff --git a/drivers/staging/bcm/Ioctl.h b/drivers/staging/bcm/Ioctl.h
index e253c080a78..797f862b90c 100644
--- a/drivers/staging/bcm/Ioctl.h
+++ b/drivers/staging/bcm/Ioctl.h
@@ -175,7 +175,7 @@ struct bcm_flash2x_copy_section {
/*
* This section provide the complete bitmap of the Flash.
- * using this map lib/APP will isssue read/write command.
+ * using this map lib/APP will issue read/write command.
* Fields are defined as :
* Bit [0] = section is present //1:present, 0: Not present
* Bit [1] = section is valid //1: valid, 0: not valid
diff --git a/drivers/staging/bcm/LeakyBucket.c b/drivers/staging/bcm/LeakyBucket.c
index 877cf0b2bee..bc486163332 100644
--- a/drivers/staging/bcm/LeakyBucket.c
+++ b/drivers/staging/bcm/LeakyBucket.c
@@ -17,47 +17,42 @@
static VOID UpdateTokenCount(register struct bcm_mini_adapter *Adapter)
{
- ULONG liCurrentTime;
- INT i = 0;
+ ULONG liCurrentTime;
+ INT i = 0;
struct timeval tv;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL,
"=====>\n");
- if(NULL == Adapter)
- {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS,
+ if (NULL == Adapter) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS,
DBG_LVL_ALL, "Adapter found NULL!\n");
return;
}
do_gettimeofday(&tv);
- for(i = 0; i < NO_OF_QUEUES; i++)
- {
- if(TRUE == Adapter->PackInfo[i].bValid &&
- (1 == Adapter->PackInfo[i].ucDirection))
- {
+ for (i = 0; i < NO_OF_QUEUES; i++) {
+ if (TRUE == Adapter->PackInfo[i].bValid &&
+ (1 == Adapter->PackInfo[i].ucDirection)) {
liCurrentTime = ((tv.tv_sec-
Adapter->PackInfo[i].stLastUpdateTokenAt.tv_sec)*1000 +
(tv.tv_usec-Adapter->PackInfo[i].stLastUpdateTokenAt.tv_usec)/
1000);
- if(0!=liCurrentTime)
- {
+ if (0 != liCurrentTime) {
Adapter->PackInfo[i].uiCurrentTokenCount += (ULONG)
((Adapter->PackInfo[i].uiMaxAllowedRate) *
((ULONG)((liCurrentTime)))/1000);
memcpy(&Adapter->PackInfo[i].stLastUpdateTokenAt,
&tv, sizeof(struct timeval));
Adapter->PackInfo[i].liLastUpdateTokenAt = liCurrentTime;
- if((Adapter->PackInfo[i].uiCurrentTokenCount) >=
- Adapter->PackInfo[i].uiMaxBucketSize)
- {
+ if (Adapter->PackInfo[i].uiCurrentTokenCount >=
+ Adapter->PackInfo[i].uiMaxBucketSize) {
Adapter->PackInfo[i].uiCurrentTokenCount =
Adapter->PackInfo[i].uiMaxBucketSize;
}
}
}
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "<=====\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "<=====\n");
return;
}
@@ -79,33 +74,26 @@ static VOID UpdateTokenCount(register struct bcm_mini_adapter *Adapter)
***********************************************************************/
static ULONG GetSFTokenCount(struct bcm_mini_adapter *Adapter, struct bcm_packet_info *psSF)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow ===>");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow ===>");
/* Validate the parameters */
- if(NULL == Adapter || (psSF < Adapter->PackInfo &&
- (uintptr_t)psSF > (uintptr_t) &Adapter->PackInfo[HiPriority]))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %zd\n", Adapter, (psSF-Adapter->PackInfo));
+ if (NULL == Adapter || (psSF < Adapter->PackInfo &&
+ (uintptr_t)psSF > (uintptr_t) &Adapter->PackInfo[HiPriority])) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %zd\n", Adapter, (psSF-Adapter->PackInfo));
return 0;
}
- if(FALSE != psSF->bValid && psSF->ucDirection)
- {
- if(0 != psSF->uiCurrentTokenCount)
- {
+ if (FALSE != psSF->bValid && psSF->ucDirection) {
+ if (0 != psSF->uiCurrentTokenCount) {
return psSF->uiCurrentTokenCount;
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %zd Available %u\n",
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %zd Available %u\n",
psSF-Adapter->PackInfo, psSF->uiCurrentTokenCount);
psSF->uiPendedLast = 1;
}
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %zd not valid\n", psSF-Adapter->PackInfo);
}
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %zd not valid\n", psSF-Adapter->PackInfo);
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow <===");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow <===");
return 0;
}
@@ -116,33 +104,29 @@ This function despatches packet from the specified queue.
*/
static INT SendPacketFromQueue(struct bcm_mini_adapter *Adapter,/**<Logical Adapter*/
struct bcm_packet_info *psSF, /**<Queue identifier*/
- struct sk_buff* Packet) /**<Pointer to the packet to be sent*/
+ struct sk_buff *Packet) /**<Pointer to the packet to be sent*/
{
- INT Status=STATUS_FAILURE;
- UINT uiIndex =0,PktLen = 0;
+ INT Status = STATUS_FAILURE;
+ UINT uiIndex = 0, PktLen = 0;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "=====>");
- if(!Adapter || !Packet || !psSF)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "Got NULL Adapter or Packet");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "=====>");
+ if (!Adapter || !Packet || !psSF) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "Got NULL Adapter or Packet");
return -EINVAL;
}
- if(psSF->liDrainCalculated==0)
- {
+ if (psSF->liDrainCalculated == 0)
psSF->liDrainCalculated = jiffies;
- }
- ///send the packet to the fifo..
+ /* send the packet to the fifo.. */
PktLen = Packet->len;
Status = SetupNextSend(Adapter, Packet, psSF->usVCID_Value);
- if(Status == 0)
- {
- for(uiIndex = 0 ; uiIndex < MIBS_MAX_HIST_ENTRIES ; uiIndex++)
- { if((PktLen <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) && (PktLen > MIBS_PKTSIZEHIST_RANGE*(uiIndex)))
+ if (Status == 0) {
+ for (uiIndex = 0; uiIndex < MIBS_MAX_HIST_ENTRIES; uiIndex++) {
+ if ((PktLen <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) && (PktLen > MIBS_PKTSIZEHIST_RANGE*(uiIndex)))
Adapter->aTxPktSizeHist[uiIndex]++;
}
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "<=====");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "<=====");
return Status;
}
@@ -160,107 +144,93 @@ static INT SendPacketFromQueue(struct bcm_mini_adapter *Adapter,/**<Logical Adap
****************************************************************************/
static VOID CheckAndSendPacketFromIndex(struct bcm_mini_adapter *Adapter, struct bcm_packet_info *psSF)
{
- struct sk_buff *QueuePacket=NULL;
- char *pControlPacket = NULL;
- INT Status=0;
- int iPacketLen=0;
+ struct sk_buff *QueuePacket = NULL;
+ char *pControlPacket = NULL;
+ INT Status = 0;
+ int iPacketLen = 0;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%zd ====>", (psSF-Adapter->PackInfo));
- if((psSF != &Adapter->PackInfo[HiPriority]) && Adapter->LinkUpStatus && atomic_read(&psSF->uiPerSFTxResourceCount))//Get data packet
- {
- if(!psSF->ucDirection )
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%zd ====>", (psSF-Adapter->PackInfo));
+ if ((psSF != &Adapter->PackInfo[HiPriority]) && Adapter->LinkUpStatus && atomic_read(&psSF->uiPerSFTxResourceCount)) { /* Get data packet */
+ if (!psSF->ucDirection)
return;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "UpdateTokenCount ");
- if(Adapter->IdleMode || Adapter->bPreparingForLowPowerMode)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "UpdateTokenCount ");
+ if (Adapter->IdleMode || Adapter->bPreparingForLowPowerMode)
return; /* in idle mode */
- // Check for Free Descriptors
- if(atomic_read(&Adapter->CurrNumFreeTxDesc) <= MINIMUM_PENDING_DESCRIPTORS)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " No Free Tx Descriptor(%d) is available for Data pkt..",atomic_read(&Adapter->CurrNumFreeTxDesc));
- return ;
+ /* Check for Free Descriptors */
+ if (atomic_read(&Adapter->CurrNumFreeTxDesc) <= MINIMUM_PENDING_DESCRIPTORS) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " No Free Tx Descriptor(%d) is available for Data pkt..", atomic_read(&Adapter->CurrNumFreeTxDesc));
+ return;
}
spin_lock_bh(&psSF->SFQueueLock);
- QueuePacket=psSF->FirstTxQueue;
+ QueuePacket = psSF->FirstTxQueue;
- if(QueuePacket)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Dequeuing Data Packet");
+ if (QueuePacket) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Dequeuing Data Packet");
- if(psSF->bEthCSSupport)
+ if (psSF->bEthCSSupport)
iPacketLen = QueuePacket->len;
else
iPacketLen = QueuePacket->len-ETH_HLEN;
- iPacketLen<<=3;
- if(iPacketLen <= GetSFTokenCount(Adapter, psSF))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Allowed bytes %d",
+ iPacketLen <<= 3;
+ if (iPacketLen <= GetSFTokenCount(Adapter, psSF)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Allowed bytes %d",
(iPacketLen >> 3));
- DEQUEUEPACKET(psSF->FirstTxQueue,psSF->LastTxQueue);
+ DEQUEUEPACKET(psSF->FirstTxQueue, psSF->LastTxQueue);
psSF->uiCurrentBytesOnHost -= (QueuePacket->len);
psSF->uiCurrentPacketsOnHost--;
atomic_dec(&Adapter->TotalPacketCount);
spin_unlock_bh(&psSF->SFQueueLock);
- Status = SendPacketFromQueue(Adapter, psSF, QueuePacket);
+ Status = SendPacketFromQueue(Adapter, psSF, QueuePacket);
psSF->uiPendedLast = FALSE;
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", psSF-Adapter->PackInfo);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n",
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", psSF-Adapter->PackInfo);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n",
psSF->uiCurrentTokenCount, iPacketLen);
- //this part indicates that because of non-availability of the tokens
- //pkt has not been send out hence setting the pending flag indicating the host to send it out
- //first next iteration .
+ /*
+ this part indicates that because of non-availability of the tokens
+ pkt has not been send out hence setting the pending flag indicating the host to send it out
+ first next iteration.
+ */
psSF->uiPendedLast = TRUE;
spin_unlock_bh(&psSF->SFQueueLock);
}
- }
- else
- {
+ } else {
spin_unlock_bh(&psSF->SFQueueLock);
}
- }
- else
- {
-
- if((atomic_read(&Adapter->CurrNumFreeTxDesc) > 0 ) &&
- (atomic_read(&Adapter->index_rd_txcntrlpkt) !=
- atomic_read(&Adapter->index_wr_txcntrlpkt))
- )
- {
+ } else {
+
+ if ((atomic_read(&Adapter->CurrNumFreeTxDesc) > 0) &&
+ (atomic_read(&Adapter->index_rd_txcntrlpkt) !=
+ atomic_read(&Adapter->index_wr_txcntrlpkt))) {
pControlPacket = Adapter->txctlpacket
[(atomic_read(&Adapter->index_rd_txcntrlpkt)%MAX_CNTRL_PKTS)];
- if(pControlPacket)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Sending Control packet");
+ if (pControlPacket) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Sending Control packet");
Status = SendControlPacket(Adapter, pControlPacket);
- if(STATUS_SUCCESS==Status)
- {
+ if (STATUS_SUCCESS == Status) {
spin_lock_bh(&psSF->SFQueueLock);
psSF->NumOfPacketsSent++;
- psSF->uiSentBytes+=((struct bcm_leader *)pControlPacket)->PLength;
+ psSF->uiSentBytes += ((struct bcm_leader *)pControlPacket)->PLength;
psSF->uiSentPackets++;
atomic_dec(&Adapter->TotalPacketCount);
psSF->uiCurrentBytesOnHost -= ((struct bcm_leader *)pControlPacket)->PLength;
psSF->uiCurrentPacketsOnHost--;
atomic_inc(&Adapter->index_rd_txcntrlpkt);
spin_unlock_bh(&psSF->SFQueueLock);
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "SendControlPacket Failed\n");
}
- else
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "SendControlPacket Failed\n");
- }
- else
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " Control Pkt is not available, Indexing is wrong....");
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " Control Pkt is not available, Indexing is wrong....");
}
- }
+ }
}
}
@@ -277,79 +247,71 @@ static VOID CheckAndSendPacketFromIndex(struct bcm_mini_adapter *Adapter, struct
********************************************************************/
VOID transmit_packets(struct bcm_mini_adapter *Adapter)
{
- UINT uiPrevTotalCount = 0;
+ UINT uiPrevTotalCount = 0;
int iIndex = 0;
- BOOLEAN exit_flag = TRUE ;
+ BOOLEAN exit_flag = TRUE;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "=====>");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "=====>");
- if(NULL == Adapter)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX,TX_PACKETS, DBG_LVL_ALL, "Got NULL Adapter");
+ if (NULL == Adapter) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Got NULL Adapter");
return;
}
- if(Adapter->device_removed == TRUE)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device removed");
+ if (Adapter->device_removed == TRUE) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device removed");
return;
}
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nUpdateTokenCount ====>\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nUpdateTokenCount ====>\n");
UpdateTokenCount(Adapter);
- BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nPruneQueueAllSF ====>\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nPruneQueueAllSF ====>\n");
PruneQueueAllSF(Adapter);
uiPrevTotalCount = atomic_read(&Adapter->TotalPacketCount);
- for(iIndex=HiPriority;iIndex>=0;iIndex--)
- {
- if( !uiPrevTotalCount || (TRUE == Adapter->device_removed))
+ for (iIndex = HiPriority; iIndex >= 0; iIndex--) {
+ if (!uiPrevTotalCount || (TRUE == Adapter->device_removed))
break;
- if(Adapter->PackInfo[iIndex].bValid &&
- Adapter->PackInfo[iIndex].uiPendedLast &&
- Adapter->PackInfo[iIndex].uiCurrentBytesOnHost)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex..");
+ if (Adapter->PackInfo[iIndex].bValid &&
+ Adapter->PackInfo[iIndex].uiPendedLast &&
+ Adapter->PackInfo[iIndex].uiCurrentBytesOnHost) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex..");
CheckAndSendPacketFromIndex(Adapter, &Adapter->PackInfo[iIndex]);
uiPrevTotalCount--;
}
}
- while(uiPrevTotalCount > 0 && !Adapter->device_removed)
- {
- exit_flag = TRUE ;
- //second iteration to parse non-pending queues
- for(iIndex=HiPriority;iIndex>=0;iIndex--)
- {
- if( !uiPrevTotalCount || (TRUE == Adapter->device_removed))
- break;
-
- if(Adapter->PackInfo[iIndex].bValid &&
- Adapter->PackInfo[iIndex].uiCurrentBytesOnHost &&
- !Adapter->PackInfo[iIndex].uiPendedLast )
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex..");
+ while (uiPrevTotalCount > 0 && !Adapter->device_removed) {
+ exit_flag = TRUE;
+ /* second iteration to parse non-pending queues */
+ for (iIndex = HiPriority; iIndex >= 0; iIndex--) {
+ if (!uiPrevTotalCount || (TRUE == Adapter->device_removed))
+ break;
+
+ if (Adapter->PackInfo[iIndex].bValid &&
+ Adapter->PackInfo[iIndex].uiCurrentBytesOnHost &&
+ !Adapter->PackInfo[iIndex].uiPendedLast) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex..");
CheckAndSendPacketFromIndex(Adapter, &Adapter->PackInfo[iIndex]);
uiPrevTotalCount--;
exit_flag = FALSE;
}
}
- if(Adapter->IdleMode || Adapter->bPreparingForLowPowerMode)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "In Idle Mode\n");
+ if (Adapter->IdleMode || Adapter->bPreparingForLowPowerMode) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "In Idle Mode\n");
break;
}
- if(exit_flag == TRUE )
- break ;
- }/* end of inner while loop */
+ if (exit_flag == TRUE)
+ break;
+ } /* end of inner while loop */
- update_per_cid_rx (Adapter);
+ update_per_cid_rx(Adapter);
Adapter->txtransmit_running = 0;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<======");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<======");
}
diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c
index d23eeeb9506..4cfc2c33c69 100644
--- a/drivers/staging/bcm/Misc.c
+++ b/drivers/staging/bcm/Misc.c
@@ -210,7 +210,7 @@ exit_download:
* @ingroup ctrl_pkt_functions
* This function copies the contents of given buffer
* to the control packet and queues it for transmission.
- * @note Do not acquire the spinock, as it it already acquired.
+ * @note Do not acquire the spinlock, as it it already acquired.
* @return SUCCESS/FAILURE.
* Arguments:
* Logical Adapter
diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c
index 8d142a547e7..2d4a77cca91 100644
--- a/drivers/staging/bcm/Qos.c
+++ b/drivers/staging/bcm/Qos.c
@@ -4,11 +4,11 @@ This file contains the routines related to Quality of Service.
*/
#include "headers.h"
-static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter,PVOID pvEthPayload, struct bcm_eth_packet_info *pstEthCsPktInfo);
-static BOOLEAN EThCSClassifyPkt(struct bcm_mini_adapter *Adapter,struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo,struct bcm_classifier_rule *pstClassifierRule, B_UINT8 EthCSCupport);
+static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter, PVOID pvEthPayload, struct bcm_eth_packet_info *pstEthCsPktInfo);
+static BOOLEAN EThCSClassifyPkt(struct bcm_mini_adapter *Adapter, struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo, struct bcm_classifier_rule *pstClassifierRule, B_UINT8 EthCSCupport);
static USHORT IpVersion4(struct bcm_mini_adapter *Adapter, struct iphdr *iphd,
- struct bcm_classifier_rule *pstClassifierRule );
+ struct bcm_classifier_rule *pstClassifierRule);
static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex);
@@ -20,30 +20,30 @@ static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex);
* matches with that of Queue.
*
* Parameters - pstClassifierRule: Pointer to the packet info structure.
-* - ulSrcIP : Source IP address from the packet.
+* - ulSrcIP : Source IP address from the packet.
*
* Returns - TRUE(If address matches) else FAIL .
*********************************************************************/
-BOOLEAN MatchSrcIpAddress(struct bcm_classifier_rule *pstClassifierRule,ULONG ulSrcIP)
+BOOLEAN MatchSrcIpAddress(struct bcm_classifier_rule *pstClassifierRule, ULONG ulSrcIP)
{
- UCHAR ucLoopIndex=0;
-
- struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
-
- ulSrcIP=ntohl(ulSrcIP);
- if(0 == pstClassifierRule->ucIPSourceAddressLength)
- return TRUE;
- for(ucLoopIndex=0; ucLoopIndex < (pstClassifierRule->ucIPSourceAddressLength);ucLoopIndex++)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Mask:0x%x PacketIp:0x%x and Classification:0x%x", (UINT)pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)ulSrcIP, (UINT)pstClassifierRule->stSrcIpAddress.ulIpv6Addr[ucLoopIndex]);
- if((pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex] & ulSrcIP)==
- (pstClassifierRule->stSrcIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex] ))
- {
- return TRUE;
- }
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Not Matched");
- return FALSE;
+ UCHAR ucLoopIndex = 0;
+
+ struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
+
+ ulSrcIP = ntohl(ulSrcIP);
+ if (0 == pstClassifierRule->ucIPSourceAddressLength)
+ return TRUE;
+ for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPSourceAddressLength); ucLoopIndex++)
+ {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Mask:0x%x PacketIp:0x%x and Classification:0x%x", (UINT)pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)ulSrcIP, (UINT)pstClassifierRule->stSrcIpAddress.ulIpv6Addr[ucLoopIndex]);
+ if ((pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex] & ulSrcIP) ==
+ (pstClassifierRule->stSrcIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex]))
+ {
+ return TRUE;
+ }
+ }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Not Matched");
+ return FALSE;
}
@@ -54,30 +54,30 @@ BOOLEAN MatchSrcIpAddress(struct bcm_classifier_rule *pstClassifierRule,ULONG ul
* matches with that of Queue.
*
* Parameters - pstClassifierRule: Pointer to the packet info structure.
-* - ulDestIP : Destination IP address from the packet.
+* - ulDestIP : Destination IP address from the packet.
*
* Returns - TRUE(If address matches) else FAIL .
*********************************************************************/
-BOOLEAN MatchDestIpAddress(struct bcm_classifier_rule *pstClassifierRule,ULONG ulDestIP)
+BOOLEAN MatchDestIpAddress(struct bcm_classifier_rule *pstClassifierRule, ULONG ulDestIP)
{
- UCHAR ucLoopIndex=0;
+ UCHAR ucLoopIndex = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- ulDestIP=ntohl(ulDestIP);
- if(0 == pstClassifierRule->ucIPDestinationAddressLength)
- return TRUE;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address 0x%x 0x%x 0x%x ", (UINT)ulDestIP, (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex]);
-
- for(ucLoopIndex=0;ucLoopIndex<(pstClassifierRule->ucIPDestinationAddressLength);ucLoopIndex++)
- {
- if((pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex] & ulDestIP)==
- (pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex]))
- {
- return TRUE;
- }
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address Not Matched");
- return FALSE;
+ ulDestIP = ntohl(ulDestIP);
+ if (0 == pstClassifierRule->ucIPDestinationAddressLength)
+ return TRUE;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address 0x%x 0x%x 0x%x ", (UINT)ulDestIP, (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex]);
+
+ for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPDestinationAddressLength); ucLoopIndex++)
+ {
+ if ((pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex] & ulDestIP) ==
+ (pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex]))
+ {
+ return TRUE;
+ }
+ }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address Not Matched");
+ return FALSE;
}
@@ -87,23 +87,23 @@ BOOLEAN MatchDestIpAddress(struct bcm_classifier_rule *pstClassifierRule,ULONG u
* Description - Checks the TOS from the packet matches with that of queue.
*
* Parameters - pstClassifierRule : Pointer to the packet info structure.
-* - ucTypeOfService: TOS from the packet.
+* - ucTypeOfService: TOS from the packet.
*
* Returns - TRUE(If address matches) else FAIL.
**************************************************************************/
-BOOLEAN MatchTos(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucTypeOfService)
+BOOLEAN MatchTos(struct bcm_classifier_rule *pstClassifierRule, UCHAR ucTypeOfService)
{
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if( 3 != pstClassifierRule->ucIPTypeOfServiceLength )
- return TRUE;
-
- if(((pstClassifierRule->ucTosMask & ucTypeOfService)<=pstClassifierRule->ucTosHigh) && ((pstClassifierRule->ucTosMask & ucTypeOfService)>=pstClassifierRule->ucTosLow))
- {
- return TRUE;
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Type Of Service Not Matched");
- return FALSE;
+ if (3 != pstClassifierRule->ucIPTypeOfServiceLength)
+ return TRUE;
+
+ if (((pstClassifierRule->ucTosMask & ucTypeOfService) <= pstClassifierRule->ucTosHigh) && ((pstClassifierRule->ucTosMask & ucTypeOfService) >= pstClassifierRule->ucTosLow))
+ {
+ return TRUE;
+ }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Type Of Service Not Matched");
+ return FALSE;
}
@@ -113,26 +113,26 @@ BOOLEAN MatchTos(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucTypeOfSer
* Description - Checks the protocol from the packet matches with that of queue.
*
* Parameters - pstClassifierRule: Pointer to the packet info structure.
-* - ucProtocol : Protocol from the packet.
+* - ucProtocol : Protocol from the packet.
*
* Returns - TRUE(If address matches) else FAIL.
****************************************************************************/
-bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucProtocol)
+bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule, UCHAR ucProtocol)
{
- UCHAR ucLoopIndex=0;
+ UCHAR ucLoopIndex = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if(0 == pstClassifierRule->ucProtocolLength)
- return TRUE;
- for(ucLoopIndex=0;ucLoopIndex<pstClassifierRule->ucProtocolLength;ucLoopIndex++)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol:0x%X Classification Protocol:0x%X",ucProtocol,pstClassifierRule->ucProtocol[ucLoopIndex]);
- if(pstClassifierRule->ucProtocol[ucLoopIndex]==ucProtocol)
- {
- return TRUE;
- }
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Not Matched");
- return FALSE;
+ if (0 == pstClassifierRule->ucProtocolLength)
+ return TRUE;
+ for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucProtocolLength; ucLoopIndex++)
+ {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol:0x%X Classification Protocol:0x%X", ucProtocol, pstClassifierRule->ucProtocol[ucLoopIndex]);
+ if (pstClassifierRule->ucProtocol[ucLoopIndex] == ucProtocol)
+ {
+ return TRUE;
+ }
+ }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Not Matched");
+ return FALSE;
}
@@ -142,29 +142,29 @@ bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucProtoco
* Description - Checks, Source port from the packet matches with that of queue.
*
* Parameters - pstClassifierRule: Pointer to the packet info structure.
-* - ushSrcPort : Source port from the packet.
+* - ushSrcPort : Source port from the packet.
*
* Returns - TRUE(If address matches) else FAIL.
***************************************************************************/
-bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushSrcPort)
+bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule, USHORT ushSrcPort)
{
- UCHAR ucLoopIndex=0;
+ UCHAR ucLoopIndex = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if(0 == pstClassifierRule->ucSrcPortRangeLength)
- return TRUE;
- for(ucLoopIndex=0;ucLoopIndex<pstClassifierRule->ucSrcPortRangeLength;ucLoopIndex++)
- {
- if(ushSrcPort <= pstClassifierRule->usSrcPortRangeHi[ucLoopIndex] &&
- ushSrcPort >= pstClassifierRule->usSrcPortRangeLo[ucLoopIndex])
- {
- return TRUE;
- }
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port: %x Not Matched ",ushSrcPort);
- return FALSE;
+ if (0 == pstClassifierRule->ucSrcPortRangeLength)
+ return TRUE;
+ for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucSrcPortRangeLength; ucLoopIndex++)
+ {
+ if (ushSrcPort <= pstClassifierRule->usSrcPortRangeHi[ucLoopIndex] &&
+ ushSrcPort >= pstClassifierRule->usSrcPortRangeLo[ucLoopIndex])
+ {
+ return TRUE;
+ }
+ }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port: %x Not Matched ", ushSrcPort);
+ return FALSE;
}
@@ -174,30 +174,30 @@ bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushSrcPor
* Description - Checks, Destination port from packet matches with that of queue.
*
* Parameters - pstClassifierRule: Pointer to the packet info structure.
-* - ushDestPort : Destination port from the packet.
+* - ushDestPort : Destination port from the packet.
*
* Returns - TRUE(If address matches) else FAIL.
***************************************************************************/
-bool MatchDestPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushDestPort)
+bool MatchDestPort(struct bcm_classifier_rule *pstClassifierRule, USHORT ushDestPort)
{
- UCHAR ucLoopIndex=0;
+ UCHAR ucLoopIndex = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if(0 == pstClassifierRule->ucDestPortRangeLength)
- return TRUE;
-
- for(ucLoopIndex=0;ucLoopIndex<pstClassifierRule->ucDestPortRangeLength;ucLoopIndex++)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Matching Port:0x%X 0x%X 0x%X",ushDestPort,pstClassifierRule->usDestPortRangeLo[ucLoopIndex],pstClassifierRule->usDestPortRangeHi[ucLoopIndex]);
-
- if(ushDestPort <= pstClassifierRule->usDestPortRangeHi[ucLoopIndex] &&
- ushDestPort >= pstClassifierRule->usDestPortRangeLo[ucLoopIndex])
- {
- return TRUE;
- }
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dest Port: %x Not Matched",ushDestPort);
- return FALSE;
+ if (0 == pstClassifierRule->ucDestPortRangeLength)
+ return TRUE;
+
+ for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucDestPortRangeLength; ucLoopIndex++)
+ {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Matching Port:0x%X 0x%X 0x%X", ushDestPort, pstClassifierRule->usDestPortRangeLo[ucLoopIndex], pstClassifierRule->usDestPortRangeHi[ucLoopIndex]);
+
+ if (ushDestPort <= pstClassifierRule->usDestPortRangeHi[ucLoopIndex] &&
+ ushDestPort >= pstClassifierRule->usDestPortRangeLo[ucLoopIndex])
+ {
+ return TRUE;
+ }
+ }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dest Port: %x Not Matched", ushDestPort);
+ return FALSE;
}
/**
@ingroup tx_functions
@@ -209,95 +209,95 @@ static USHORT IpVersion4(struct bcm_mini_adapter *Adapter,
struct bcm_classifier_rule *pstClassifierRule)
{
struct bcm_transport_header *xprt_hdr = NULL;
- BOOLEAN bClassificationSucceed=FALSE;
+ BOOLEAN bClassificationSucceed = FALSE;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "========>");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "========>");
- xprt_hdr=(struct bcm_transport_header *)((PUCHAR)iphd + sizeof(struct iphdr));
+ xprt_hdr = (struct bcm_transport_header *)((PUCHAR)iphd + sizeof(struct iphdr));
do {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to see Direction = %d %d",
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to see Direction = %d %d",
pstClassifierRule->ucDirection,
pstClassifierRule->usVCID_Value);
//Checking classifier validity
- if(!pstClassifierRule->bUsed || pstClassifierRule->ucDirection == DOWNLINK_DIR)
+ if (!pstClassifierRule->bUsed || pstClassifierRule->ucDirection == DOWNLINK_DIR)
{
bClassificationSucceed = FALSE;
break;
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "is IPv6 check!");
- if(pstClassifierRule->bIpv6Protocol)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "is IPv6 check!");
+ if (pstClassifierRule->bIpv6Protocol)
break;
//**************Checking IP header parameter**************************//
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to match Source IP Address");
- if(FALSE == (bClassificationSucceed =
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to match Source IP Address");
+ if (FALSE == (bClassificationSucceed =
MatchSrcIpAddress(pstClassifierRule, iphd->saddr)))
break;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source IP Address Matched");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source IP Address Matched");
- if(FALSE == (bClassificationSucceed =
+ if (FALSE == (bClassificationSucceed =
MatchDestIpAddress(pstClassifierRule, iphd->daddr)))
break;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination IP Address Matched");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination IP Address Matched");
- if(FALSE == (bClassificationSucceed =
+ if (FALSE == (bClassificationSucceed =
MatchTos(pstClassifierRule, iphd->tos)))
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Match failed\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Match failed\n");
break;
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Matched");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Matched");
- if(FALSE == (bClassificationSucceed =
- MatchProtocol(pstClassifierRule,iphd->protocol)))
+ if (FALSE == (bClassificationSucceed =
+ MatchProtocol(pstClassifierRule, iphd->protocol)))
break;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Matched");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Matched");
//if protocol is not TCP or UDP then no need of comparing source port and destination port
- if(iphd->protocol!=TCP && iphd->protocol!=UDP)
+ if (iphd->protocol != TCP && iphd->protocol != UDP)
break;
//******************Checking Transport Layer Header field if present *****************//
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x",
- (iphd->protocol==UDP)?xprt_hdr->uhdr.source:xprt_hdr->thdr.source);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x",
+ (iphd->protocol == UDP) ? xprt_hdr->uhdr.source : xprt_hdr->thdr.source);
- if(FALSE == (bClassificationSucceed =
+ if (FALSE == (bClassificationSucceed =
MatchSrcPort(pstClassifierRule,
- ntohs((iphd->protocol == UDP)?
- xprt_hdr->uhdr.source:xprt_hdr->thdr.source))))
+ ntohs((iphd->protocol == UDP) ?
+ xprt_hdr->uhdr.source : xprt_hdr->thdr.source))))
break;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port Matched");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port Matched");
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Port %04x",
- (iphd->protocol==UDP)?xprt_hdr->uhdr.dest:
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Port %04x",
+ (iphd->protocol == UDP) ? xprt_hdr->uhdr.dest :
xprt_hdr->thdr.dest);
- if(FALSE == (bClassificationSucceed =
+ if (FALSE == (bClassificationSucceed =
MatchDestPort(pstClassifierRule,
- ntohs((iphd->protocol == UDP)?
- xprt_hdr->uhdr.dest:xprt_hdr->thdr.dest))))
+ ntohs((iphd->protocol == UDP) ?
+ xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest))))
break;
- } while(0);
+ } while (0);
- if(TRUE==bClassificationSucceed)
+ if (TRUE == bClassificationSucceed)
{
INT iMatchedSFQueueIndex = 0;
- iMatchedSFQueueIndex = SearchSfid(Adapter,pstClassifierRule->ulSFID);
- if(iMatchedSFQueueIndex >= NO_OF_QUEUES)
+ iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
+ if (iMatchedSFQueueIndex >= NO_OF_QUEUES)
{
bClassificationSucceed = FALSE;
}
else
{
- if(FALSE == Adapter->PackInfo[iMatchedSFQueueIndex].bActive)
+ if (FALSE == Adapter->PackInfo[iMatchedSFQueueIndex].bActive)
{
bClassificationSucceed = FALSE;
}
}
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "IpVersion4 <==========");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "IpVersion4 <==========");
return bClassificationSucceed;
}
@@ -306,9 +306,9 @@ VOID PruneQueueAllSF(struct bcm_mini_adapter *Adapter)
{
UINT iIndex = 0;
- for(iIndex = 0; iIndex < HiPriority; iIndex++)
+ for (iIndex = 0; iIndex < HiPriority; iIndex++)
{
- if(!Adapter->PackInfo[iIndex].bValid)
+ if (!Adapter->PackInfo[iIndex].bValid)
continue;
PruneQueue(Adapter, iIndex);
@@ -325,15 +325,15 @@ less than or equal to max queue size for the queue.
*/
static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex)
{
- struct sk_buff* PacketToDrop=NULL;
+ struct sk_buff* PacketToDrop = NULL;
struct net_device_stats *netstats;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "=====> Index %d",iIndex);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "=====> Index %d", iIndex);
- if(iIndex == HiPriority)
+ if (iIndex == HiPriority)
return;
- if(!Adapter || (iIndex < 0) || (iIndex > HiPriority))
+ if (!Adapter || (iIndex < 0) || (iIndex > HiPriority))
return;
/* To Store the netdevice statistic */
@@ -341,26 +341,26 @@ static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex)
spin_lock_bh(&Adapter->PackInfo[iIndex].SFQueueLock);
- while(1)
+ while (1)
// while((UINT)Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost >
// SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "uiCurrentBytesOnHost:%x uiMaxBucketSize :%x",
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "uiCurrentBytesOnHost:%x uiMaxBucketSize :%x",
Adapter->PackInfo[iIndex].uiCurrentBytesOnHost,
Adapter->PackInfo[iIndex].uiMaxBucketSize);
PacketToDrop = Adapter->PackInfo[iIndex].FirstTxQueue;
- if(PacketToDrop == NULL)
+ if (PacketToDrop == NULL)
break;
- if((Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost < SF_MAX_ALLOWED_PACKETS_TO_BACKUP) &&
+ if ((Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost < SF_MAX_ALLOWED_PACKETS_TO_BACKUP) &&
((1000*(jiffies - *((B_UINT32 *)(PacketToDrop->cb)+SKB_CB_LATENCY_OFFSET))/HZ) <= Adapter->PackInfo[iIndex].uiMaxLatency))
break;
- if(PacketToDrop)
+ if (PacketToDrop)
{
if (netif_msg_tx_err(Adapter))
- pr_info(PFX "%s: tx queue %d overlimit\n",
+ pr_info(PFX "%s: tx queue %d overlimit\n",
Adapter->dev->name, iIndex);
netstats->tx_dropped++;
@@ -378,7 +378,7 @@ static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex)
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "Dropped Bytes:%x Dropped Packets:%x",
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "Dropped Bytes:%x Dropped Packets:%x",
Adapter->PackInfo[iIndex].uiDroppedCountBytes,
Adapter->PackInfo[iIndex].uiDroppedCountPackets);
@@ -387,29 +387,29 @@ static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex)
spin_unlock_bh(&Adapter->PackInfo[iIndex].SFQueueLock);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "TotalPacketCount:%x",
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "TotalPacketCount:%x",
atomic_read(&Adapter->TotalPacketCount));
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "<=====");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "<=====");
}
VOID flush_all_queues(struct bcm_mini_adapter *Adapter)
{
INT iQIndex;
UINT uiTotalPacketLength;
- struct sk_buff* PacketToDrop=NULL;
+ struct sk_buff* PacketToDrop = NULL;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>");
// down(&Adapter->data_packet_queue_lock);
- for(iQIndex=LowPriority; iQIndex<HiPriority; iQIndex++)
+ for (iQIndex = LowPriority; iQIndex < HiPriority; iQIndex++)
{
struct net_device_stats *netstats = &Adapter->dev->stats;
spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
- while(Adapter->PackInfo[iQIndex].FirstTxQueue)
+ while (Adapter->PackInfo[iQIndex].FirstTxQueue)
{
PacketToDrop = Adapter->PackInfo[iQIndex].FirstTxQueue;
- if(PacketToDrop)
+ if (PacketToDrop)
{
uiTotalPacketLength = PacketToDrop->len;
netstats->tx_dropped++;
@@ -431,7 +431,7 @@ VOID flush_all_queues(struct bcm_mini_adapter *Adapter)
Adapter->PackInfo[iQIndex].uiDroppedCountBytes += uiTotalPacketLength;
Adapter->PackInfo[iQIndex].uiDroppedCountPackets++;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Dropped Bytes:%x Dropped Packets:%x",
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Dropped Bytes:%x Dropped Packets:%x",
Adapter->PackInfo[iQIndex].uiDroppedCountBytes,
Adapter->PackInfo[iQIndex].uiDroppedCountPackets);
atomic_dec(&Adapter->TotalPacketCount);
@@ -439,30 +439,30 @@ VOID flush_all_queues(struct bcm_mini_adapter *Adapter)
spin_unlock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
}
// up(&Adapter->data_packet_queue_lock);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "<=====");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "<=====");
}
-USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter,struct sk_buff* skb)
+USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb)
{
- INT uiLoopIndex=0;
+ INT uiLoopIndex = 0;
struct bcm_classifier_rule *pstClassifierRule = NULL;
struct bcm_eth_packet_info stEthCsPktInfo;
PVOID pvEThPayload = NULL;
- struct iphdr *pIpHeader = NULL;
- INT uiSfIndex=0;
- USHORT usIndex=Adapter->usBestEffortQueueIndex;
- BOOLEAN bFragmentedPkt=FALSE,bClassificationSucceed=FALSE;
- USHORT usCurrFragment =0;
+ struct iphdr *pIpHeader = NULL;
+ INT uiSfIndex = 0;
+ USHORT usIndex = Adapter->usBestEffortQueueIndex;
+ BOOLEAN bFragmentedPkt = FALSE, bClassificationSucceed = FALSE;
+ USHORT usCurrFragment = 0;
struct bcm_tcp_header *pTcpHeader;
UCHAR IpHeaderLength;
UCHAR TcpHeaderLength;
pvEThPayload = skb->data;
- *((UINT32*) (skb->cb) +SKB_CB_TCPACK_OFFSET ) = 0;
- EThCSGetPktInfo(Adapter,pvEThPayload,&stEthCsPktInfo);
+ *((UINT32*) (skb->cb) +SKB_CB_TCPACK_OFFSET) = 0;
+ EThCSGetPktInfo(Adapter, pvEThPayload, &stEthCsPktInfo);
- switch(stEthCsPktInfo.eNwpktEthFrameType)
+ switch (stEthCsPktInfo.eNwpktEthFrameType)
{
case eEth802LLCFrame:
{
@@ -497,75 +497,75 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter,struct sk_buff* skb)
}
}
- if(stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet)
+ if (stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet)
{
usCurrFragment = (ntohs(pIpHeader->frag_off) & IP_OFFSET);
- if((ntohs(pIpHeader->frag_off) & IP_MF) || usCurrFragment)
+ if ((ntohs(pIpHeader->frag_off) & IP_MF) || usCurrFragment)
bFragmentedPkt = TRUE;
- if(bFragmentedPkt)
+ if (bFragmentedPkt)
{
//Fragmented Packet. Get Frag Classifier Entry.
- pstClassifierRule = GetFragIPClsEntry(Adapter,pIpHeader->id, pIpHeader->saddr);
- if(pstClassifierRule)
+ pstClassifierRule = GetFragIPClsEntry(Adapter, pIpHeader->id, pIpHeader->saddr);
+ if (pstClassifierRule)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,"It is next Fragmented pkt");
- bClassificationSucceed=TRUE;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "It is next Fragmented pkt");
+ bClassificationSucceed = TRUE;
}
- if(!(ntohs(pIpHeader->frag_off) & IP_MF))
+ if (!(ntohs(pIpHeader->frag_off) & IP_MF))
{
//Fragmented Last packet . Remove Frag Classifier Entry
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,"This is the last fragmented Pkt");
- DelFragIPClsEntry(Adapter,pIpHeader->id, pIpHeader->saddr);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "This is the last fragmented Pkt");
+ DelFragIPClsEntry(Adapter, pIpHeader->id, pIpHeader->saddr);
}
}
}
- for(uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--)
+ for (uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--)
{
- if(bClassificationSucceed)
+ if (bClassificationSucceed)
break;
//Iterate through all classifiers which are already in order of priority
//to classify the packet until match found
do
{
- if(FALSE==Adapter->astClassifierTable[uiLoopIndex].bUsed)
+ if (FALSE == Adapter->astClassifierTable[uiLoopIndex].bUsed)
{
- bClassificationSucceed=FALSE;
+ bClassificationSucceed = FALSE;
break;
}
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Adapter->PackInfo[%d].bvalid=True\n",uiLoopIndex);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Adapter->PackInfo[%d].bvalid=True\n", uiLoopIndex);
- if(0 == Adapter->astClassifierTable[uiLoopIndex].ucDirection)
+ if (0 == Adapter->astClassifierTable[uiLoopIndex].ucDirection)
{
- bClassificationSucceed=FALSE;//cannot be processed for classification.
+ bClassificationSucceed = FALSE;//cannot be processed for classification.
break; // it is a down link connection
}
pstClassifierRule = &Adapter->astClassifierTable[uiLoopIndex];
- uiSfIndex = SearchSfid(Adapter,pstClassifierRule->ulSFID);
+ uiSfIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
if (uiSfIndex >= NO_OF_QUEUES) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Queue Not Valid. SearchSfid for this classifier Failed\n");
break;
}
- if(Adapter->PackInfo[uiSfIndex].bEthCSSupport)
+ if (Adapter->PackInfo[uiSfIndex].bEthCSSupport)
{
- if(eEthUnsupportedFrame==stEthCsPktInfo.eNwpktEthFrameType)
+ if (eEthUnsupportedFrame == stEthCsPktInfo.eNwpktEthFrameType)
{
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a Valid Supported Ethernet Frame \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a Valid Supported Ethernet Frame\n");
bClassificationSucceed = FALSE;
break;
}
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Performing ETH CS Classification on Classifier Rule ID : %x Service Flow ID : %lx\n",pstClassifierRule->uiClassifierRuleIndex,Adapter->PackInfo[uiSfIndex].ulSFID);
- bClassificationSucceed = EThCSClassifyPkt(Adapter,skb,&stEthCsPktInfo,pstClassifierRule, Adapter->PackInfo[uiSfIndex].bEthCSSupport);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Performing ETH CS Classification on Classifier Rule ID : %x Service Flow ID : %lx\n", pstClassifierRule->uiClassifierRuleIndex, Adapter->PackInfo[uiSfIndex].ulSFID);
+ bClassificationSucceed = EThCSClassifyPkt(Adapter, skb, &stEthCsPktInfo, pstClassifierRule, Adapter->PackInfo[uiSfIndex].bEthCSSupport);
- if(!bClassificationSucceed)
+ if (!bClassificationSucceed)
{
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : Ethernet CS Classification Failed\n");
break;
@@ -574,9 +574,9 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter,struct sk_buff* skb)
else // No ETH Supported on this SF
{
- if(eEthOtherFrame != stEthCsPktInfo.eNwpktEthFrameType)
+ if (eEthOtherFrame != stEthCsPktInfo.eNwpktEthFrameType)
{
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a 802.3 Ethernet Frame... hence not allowed over non-ETH CS SF \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a 802.3 Ethernet Frame... hence not allowed over non-ETH CS SF\n");
bClassificationSucceed = FALSE;
break;
}
@@ -584,51 +584,51 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter,struct sk_buff* skb)
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Proceeding to IP CS Clasification");
- if(Adapter->PackInfo[uiSfIndex].bIPCSSupport)
+ if (Adapter->PackInfo[uiSfIndex].bIPCSSupport)
{
- if(stEthCsPktInfo.eNwpktIPFrameType == eNonIPPacket)
+ if (stEthCsPktInfo.eNwpktIPFrameType == eNonIPPacket)
{
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet is Not an IP Packet \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet is Not an IP Packet\n");
bClassificationSucceed = FALSE;
break;
}
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dump IP Header : \n");
- DumpFullPacket((PUCHAR)pIpHeader,20);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dump IP Header :\n");
+ DumpFullPacket((PUCHAR)pIpHeader, 20);
- if(stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet)
- bClassificationSucceed = IpVersion4(Adapter,pIpHeader,pstClassifierRule);
- else if(stEthCsPktInfo.eNwpktIPFrameType == eIPv6Packet)
- bClassificationSucceed = IpVersion6(Adapter,pIpHeader,pstClassifierRule);
+ if (stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet)
+ bClassificationSucceed = IpVersion4(Adapter, pIpHeader, pstClassifierRule);
+ else if (stEthCsPktInfo.eNwpktIPFrameType == eIPv6Packet)
+ bClassificationSucceed = IpVersion6(Adapter, pIpHeader, pstClassifierRule);
}
- }while(0);
+ } while (0);
}
- if(bClassificationSucceed == TRUE)
+ if (bClassificationSucceed == TRUE)
{
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "CF id : %d, SF ID is =%lu",pstClassifierRule->uiClassifierRuleIndex, pstClassifierRule->ulSFID);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "CF id : %d, SF ID is =%lu", pstClassifierRule->uiClassifierRuleIndex, pstClassifierRule->ulSFID);
//Store The matched Classifier in SKB
*((UINT32*)(skb->cb)+SKB_CB_CLASSIFICATION_OFFSET) = pstClassifierRule->uiClassifierRuleIndex;
- if((TCP == pIpHeader->protocol ) && !bFragmentedPkt && (ETH_AND_IP_HEADER_LEN + TCP_HEADER_LEN <= skb->len) )
+ if ((TCP == pIpHeader->protocol) && !bFragmentedPkt && (ETH_AND_IP_HEADER_LEN + TCP_HEADER_LEN <= skb->len))
{
IpHeaderLength = pIpHeader->ihl;
pTcpHeader = (struct bcm_tcp_header *)(((PUCHAR)pIpHeader)+(IpHeaderLength*4));
TcpHeaderLength = GET_TCP_HEADER_LEN(pTcpHeader->HeaderLength);
- if((pTcpHeader->ucFlags & TCP_ACK) &&
+ if ((pTcpHeader->ucFlags & TCP_ACK) &&
(ntohs(pIpHeader->tot_len) == (IpHeaderLength*4)+(TcpHeaderLength*4)))
{
- *((UINT32*) (skb->cb) +SKB_CB_TCPACK_OFFSET ) = TCP_ACK;
+ *((UINT32*) (skb->cb) + SKB_CB_TCPACK_OFFSET) = TCP_ACK;
}
}
usIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "index is =%d", usIndex);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "index is =%d", usIndex);
//If this is the first fragment of a Fragmented pkt, add this CF. Only This CF should be used for all other fragment of this Pkt.
- if(bFragmentedPkt && (usCurrFragment == 0))
+ if (bFragmentedPkt && (usCurrFragment == 0))
{
//First Fragment of Fragmented Packet. Create Frag CLS Entry
struct bcm_fragmented_packet_info stFragPktInfo;
@@ -637,77 +637,77 @@ USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter,struct sk_buff* skb)
stFragPktInfo.usIpIdentification = pIpHeader->id;
stFragPktInfo.pstMatchedClassifierEntry = pstClassifierRule;
stFragPktInfo.bOutOfOrderFragment = FALSE;
- AddFragIPClsEntry(Adapter,&stFragPktInfo);
+ AddFragIPClsEntry(Adapter, &stFragPktInfo);
}
}
- if(bClassificationSucceed)
+ if (bClassificationSucceed)
return usIndex;
else
return INVALID_QUEUE_INDEX;
}
-static BOOLEAN EthCSMatchSrcMACAddress(struct bcm_classifier_rule *pstClassifierRule,PUCHAR Mac)
+static BOOLEAN EthCSMatchSrcMACAddress(struct bcm_classifier_rule *pstClassifierRule, PUCHAR Mac)
{
- UINT i=0;
+ UINT i = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if(pstClassifierRule->ucEthCSSrcMACLen==0)
+ if (pstClassifierRule->ucEthCSSrcMACLen == 0)
return TRUE;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s \n",__FUNCTION__);
- for(i=0;i<MAC_ADDRESS_SIZE;i++)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __FUNCTION__);
+ for (i = 0; i < MAC_ADDRESS_SIZE; i++)
{
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n",i,Mac[i],pstClassifierRule->au8EThCSSrcMAC[i],pstClassifierRule->au8EThCSSrcMACMask[i]);
- if((pstClassifierRule->au8EThCSSrcMAC[i] & pstClassifierRule->au8EThCSSrcMACMask[i])!=
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n", i, Mac[i], pstClassifierRule->au8EThCSSrcMAC[i], pstClassifierRule->au8EThCSSrcMACMask[i]);
+ if ((pstClassifierRule->au8EThCSSrcMAC[i] & pstClassifierRule->au8EThCSSrcMACMask[i]) !=
(Mac[i] & pstClassifierRule->au8EThCSSrcMACMask[i]))
return FALSE;
}
return TRUE;
}
-static BOOLEAN EthCSMatchDestMACAddress(struct bcm_classifier_rule *pstClassifierRule,PUCHAR Mac)
+static BOOLEAN EthCSMatchDestMACAddress(struct bcm_classifier_rule *pstClassifierRule, PUCHAR Mac)
{
- UINT i=0;
+ UINT i = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if(pstClassifierRule->ucEthCSDestMACLen==0)
+ if (pstClassifierRule->ucEthCSDestMACLen == 0)
return TRUE;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s \n",__FUNCTION__);
- for(i=0;i<MAC_ADDRESS_SIZE;i++)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __FUNCTION__);
+ for (i = 0; i < MAC_ADDRESS_SIZE; i++)
{
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n",i,Mac[i],pstClassifierRule->au8EThCSDestMAC[i],pstClassifierRule->au8EThCSDestMACMask[i]);
- if((pstClassifierRule->au8EThCSDestMAC[i] & pstClassifierRule->au8EThCSDestMACMask[i])!=
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n", i, Mac[i], pstClassifierRule->au8EThCSDestMAC[i], pstClassifierRule->au8EThCSDestMACMask[i]);
+ if ((pstClassifierRule->au8EThCSDestMAC[i] & pstClassifierRule->au8EThCSDestMACMask[i]) !=
(Mac[i] & pstClassifierRule->au8EThCSDestMACMask[i]))
return FALSE;
}
return TRUE;
}
-static BOOLEAN EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRule,struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo)
+static BOOLEAN EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRule, struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo)
{
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if((pstClassifierRule->ucEtherTypeLen==0)||
+ if ((pstClassifierRule->ucEtherTypeLen == 0) ||
(pstClassifierRule->au8EthCSEtherType[0] == 0))
return TRUE;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s SrcEtherType:%x CLS EtherType[0]:%x\n",__FUNCTION__,pstEthCsPktInfo->usEtherType,pstClassifierRule->au8EthCSEtherType[0]);
- if(pstClassifierRule->au8EthCSEtherType[0] == 1)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s SrcEtherType:%x CLS EtherType[0]:%x\n", __FUNCTION__, pstEthCsPktInfo->usEtherType, pstClassifierRule->au8EthCSEtherType[0]);
+ if (pstClassifierRule->au8EthCSEtherType[0] == 1)
{
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS EtherType[1]:%x EtherType[2]:%x\n",__FUNCTION__,pstClassifierRule->au8EthCSEtherType[1],pstClassifierRule->au8EthCSEtherType[2]);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS EtherType[1]:%x EtherType[2]:%x\n", __FUNCTION__, pstClassifierRule->au8EthCSEtherType[1], pstClassifierRule->au8EthCSEtherType[2]);
- if(memcmp(&pstEthCsPktInfo->usEtherType,&pstClassifierRule->au8EthCSEtherType[1],2)==0)
+ if (memcmp(&pstEthCsPktInfo->usEtherType, &pstClassifierRule->au8EthCSEtherType[1], 2) == 0)
return TRUE;
else
return FALSE;
}
- if(pstClassifierRule->au8EthCSEtherType[0] == 2)
+ if (pstClassifierRule->au8EthCSEtherType[0] == 2)
{
- if(eEth802LLCFrame != pstEthCsPktInfo->eNwpktEthFrameType)
+ if (eEth802LLCFrame != pstEthCsPktInfo->eNwpktEthFrameType)
return FALSE;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s EthCS DSAP:%x EtherType[2]:%x\n",__FUNCTION__,pstEthCsPktInfo->ucDSAP,pstClassifierRule->au8EthCSEtherType[2]);
- if(pstEthCsPktInfo->ucDSAP == pstClassifierRule->au8EthCSEtherType[2])
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s EthCS DSAP:%x EtherType[2]:%x\n", __FUNCTION__, pstEthCsPktInfo->ucDSAP, pstClassifierRule->au8EthCSEtherType[2]);
+ if (pstEthCsPktInfo->ucDSAP == pstClassifierRule->au8EthCSEtherType[2])
return TRUE;
else
return FALSE;
@@ -718,27 +718,27 @@ static BOOLEAN EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRul
}
-static BOOLEAN EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule,struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo)
+static BOOLEAN EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule, struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo)
{
BOOLEAN bClassificationSucceed = FALSE;
USHORT usVLANID;
B_UINT8 uPriority = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS UserPrio:%x CLS VLANID:%x\n",__FUNCTION__,ntohs(*((USHORT *)pstClassifierRule->usUserPriority)),pstClassifierRule->usVLANID);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS UserPrio:%x CLS VLANID:%x\n", __FUNCTION__, ntohs(*((USHORT *)pstClassifierRule->usUserPriority)), pstClassifierRule->usVLANID);
/* In case FW didn't receive the TLV, the priority field should be ignored */
- if(pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_USER_PRIORITY_VALID))
+ if (pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_USER_PRIORITY_VALID))
{
- if(pstEthCsPktInfo->eNwpktEthFrameType!=eEth802QVLANFrame)
+ if (pstEthCsPktInfo->eNwpktEthFrameType != eEth802QVLANFrame)
return FALSE;
uPriority = (ntohs(*(USHORT *)(skb->data + sizeof(struct bcm_eth_header))) & 0xF000) >> 13;
- if((uPriority >= pstClassifierRule->usUserPriority[0]) && (uPriority <= pstClassifierRule->usUserPriority[1]))
+ if ((uPriority >= pstClassifierRule->usUserPriority[0]) && (uPriority <= pstClassifierRule->usUserPriority[1]))
bClassificationSucceed = TRUE;
- if(!bClassificationSucceed)
+ if (!bClassificationSucceed)
return FALSE;
}
@@ -746,19 +746,19 @@ static BOOLEAN EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule
bClassificationSucceed = FALSE;
- if(pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_VLANID_VALID))
+ if (pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_VLANID_VALID))
{
- if(pstEthCsPktInfo->eNwpktEthFrameType!=eEth802QVLANFrame)
+ if (pstEthCsPktInfo->eNwpktEthFrameType != eEth802QVLANFrame)
return FALSE;
usVLANID = ntohs(*(USHORT *)(skb->data + sizeof(struct bcm_eth_header))) & 0xFFF;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s Pkt VLANID %x Priority: %d\n",__FUNCTION__,usVLANID, uPriority);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s Pkt VLANID %x Priority: %d\n", __FUNCTION__, usVLANID, uPriority);
- if(usVLANID == ((pstClassifierRule->usVLANID & 0xFFF0) >> 4))
+ if (usVLANID == ((pstClassifierRule->usVLANID & 0xFFF0) >> 4))
bClassificationSucceed = TRUE;
- if(!bClassificationSucceed)
+ if (!bClassificationSucceed)
return FALSE;
}
@@ -768,50 +768,50 @@ static BOOLEAN EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule
}
-static BOOLEAN EThCSClassifyPkt(struct bcm_mini_adapter *Adapter,struct sk_buff* skb,
+static BOOLEAN EThCSClassifyPkt(struct bcm_mini_adapter *Adapter, struct sk_buff* skb,
struct bcm_eth_packet_info *pstEthCsPktInfo,
struct bcm_classifier_rule *pstClassifierRule,
B_UINT8 EthCSCupport)
{
BOOLEAN bClassificationSucceed = FALSE;
- bClassificationSucceed = EthCSMatchSrcMACAddress(pstClassifierRule,((struct bcm_eth_header *)(skb->data))->au8SourceAddress);
- if(!bClassificationSucceed)
+ bClassificationSucceed = EthCSMatchSrcMACAddress(pstClassifierRule, ((struct bcm_eth_header *)(skb->data))->au8SourceAddress);
+ if (!bClassificationSucceed)
return FALSE;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ETH CS SrcMAC Matched\n");
- bClassificationSucceed = EthCSMatchDestMACAddress(pstClassifierRule,((struct bcm_eth_header *)(skb->data))->au8DestinationAddress);
- if(!bClassificationSucceed)
+ bClassificationSucceed = EthCSMatchDestMACAddress(pstClassifierRule, ((struct bcm_eth_header *)(skb->data))->au8DestinationAddress);
+ if (!bClassificationSucceed)
return FALSE;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ETH CS DestMAC Matched\n");
//classify on ETHType/802.2SAP TLV
- bClassificationSucceed = EthCSMatchEThTypeSAP(pstClassifierRule,skb,pstEthCsPktInfo);
- if(!bClassificationSucceed)
+ bClassificationSucceed = EthCSMatchEThTypeSAP(pstClassifierRule, skb, pstEthCsPktInfo);
+ if (!bClassificationSucceed)
return FALSE;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ETH CS EthType/802.2SAP Matched\n");
//classify on 802.1VLAN Header Parameters
- bClassificationSucceed = EthCSMatchVLANRules(pstClassifierRule,skb,pstEthCsPktInfo);
- if(!bClassificationSucceed)
+ bClassificationSucceed = EthCSMatchVLANRules(pstClassifierRule, skb, pstEthCsPktInfo);
+ if (!bClassificationSucceed)
return FALSE;
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ETH CS 802.1 VLAN Rules Matched\n");
return bClassificationSucceed;
}
-static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter,PVOID pvEthPayload,
+static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter, PVOID pvEthPayload,
struct bcm_eth_packet_info *pstEthCsPktInfo)
{
USHORT u16Etype = ntohs(((struct bcm_eth_header *)pvEthPayload)->u16Etype);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : Eth Hdr Type : %X\n",u16Etype);
- if(u16Etype > 0x5dc)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : Eth Hdr Type : %X\n", u16Etype);
+ if (u16Etype > 0x5dc)
{
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : ETH2 Frame \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : ETH2 Frame\n");
//ETH2 Frame
- if(u16Etype == ETHERNET_FRAMETYPE_802QVLAN)
+ if (u16Etype == ETHERNET_FRAMETYPE_802QVLAN)
{
//802.1Q VLAN Header
pstEthCsPktInfo->eNwpktEthFrameType = eEth802QVLANFrame;
@@ -828,27 +828,27 @@ static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter,PVOID pvEthPayload,
else
{
//802.2 LLC
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "802.2 LLC Frame \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "802.2 LLC Frame\n");
pstEthCsPktInfo->eNwpktEthFrameType = eEth802LLCFrame;
pstEthCsPktInfo->ucDSAP = ((struct bcm_eth_llc_frame *)pvEthPayload)->DSAP;
- if(pstEthCsPktInfo->ucDSAP == 0xAA && ((struct bcm_eth_llc_frame *)pvEthPayload)->SSAP == 0xAA)
+ if (pstEthCsPktInfo->ucDSAP == 0xAA && ((struct bcm_eth_llc_frame *)pvEthPayload)->SSAP == 0xAA)
{
//SNAP Frame
pstEthCsPktInfo->eNwpktEthFrameType = eEth802LLCSNAPFrame;
u16Etype = ((struct bcm_eth_llc_snap_frame *)pvEthPayload)->usEtherType;
}
}
- if(u16Etype == ETHERNET_FRAMETYPE_IPV4)
+ if (u16Etype == ETHERNET_FRAMETYPE_IPV4)
pstEthCsPktInfo->eNwpktIPFrameType = eIPv4Packet;
- else if(u16Etype == ETHERNET_FRAMETYPE_IPV6)
+ else if (u16Etype == ETHERNET_FRAMETYPE_IPV6)
pstEthCsPktInfo->eNwpktIPFrameType = eIPv6Packet;
else
pstEthCsPktInfo->eNwpktIPFrameType = eNonIPPacket;
pstEthCsPktInfo->usEtherType = ((struct bcm_eth_header *)pvEthPayload)->u16Etype;
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCsPktInfo->eNwpktIPFrameType : %x\n",pstEthCsPktInfo->eNwpktIPFrameType);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCsPktInfo->eNwpktEthFrameType : %x\n",pstEthCsPktInfo->eNwpktEthFrameType);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCsPktInfo->usEtherType : %x\n",pstEthCsPktInfo->usEtherType);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCsPktInfo->eNwpktIPFrameType : %x\n", pstEthCsPktInfo->eNwpktIPFrameType);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCsPktInfo->eNwpktEthFrameType : %x\n", pstEthCsPktInfo->eNwpktEthFrameType);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCsPktInfo->usEtherType : %x\n", pstEthCsPktInfo->usEtherType);
}
diff --git a/drivers/staging/bcm/Version.h b/drivers/staging/bcm/Version.h
deleted file mode 100644
index f1cb9de734a..00000000000
--- a/drivers/staging/bcm/Version.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*Copyright (c) 2005 Beceem Communications Inc.
-
-Module Name:
-
- Version.h
-
-Abstract:
-
-
---*/
-
-#ifndef VERSION_H
-#define VERSION_H
-
-
-#define VER_FILETYPE VFT_DRV
-#define VER_FILESUBTYPE VFT2_DRV_NETWORK
-
-#define VER_FILEVERSION 5.2.45
-#define VER_FILEVERSION_STR "5.2.45"
-
-#undef VER_PRODUCTVERSION
-#define VER_PRODUCTVERSION VER_FILEVERSION
-
-#undef VER_PRODUCTVERSION_STR
-#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
-
-
-#endif /* VERSION_H */
diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h
index da47db8c8f2..7fd21c6923c 100644
--- a/drivers/staging/bcm/headers.h
+++ b/drivers/staging/bcm/headers.h
@@ -38,7 +38,6 @@
#include <net/ip.h>
#include "Typedefs.h"
-#include "Version.h"
#include "Macros.h"
#include "HostMIBSInterface.h"
#include "cntrl_SignalingInterface.h"
@@ -71,7 +70,7 @@
#define DEV_NAME "tarang"
#define DRV_DESCRIPTION "Beceem Communications Inc. WiMAX driver"
#define DRV_COPYRIGHT "Copyright 2010. Beceem Communications Inc"
-#define DRV_VERSION VER_FILEVERSION_STR
+#define DRV_VERSION "5.2.45"
#define PFX DRV_NAME " "
extern struct class *bcm_class;
diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c
index bea1330f7ea..91a5715964b 100644
--- a/drivers/staging/bcm/nvm.c
+++ b/drivers/staging/bcm/nvm.c
@@ -2966,7 +2966,7 @@ int BcmFlash2xBulkWrite(struct bcm_mini_adapter *Adapter,
* @Adapter :-Drivers private Data Structure
*
* Return Value:-
- * Return STATUS_SUCESS if get success in setting the right DSD else negaive error code
+ * Return STATUS_SUCESS if get success in setting the right DSD else negative error code
*
*/
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 8c8a5513225..a84aab47a11 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -100,7 +100,6 @@ endif # COMEDI_MISC_DRIVERS
menuconfig COMEDI_ISA_DRIVERS
bool "Comedi ISA and PC/104 drivers"
- depends on ISA
---help---
Enable comedi ISA and PC/104 drivers to be built
@@ -122,8 +121,18 @@ config COMEDI_PCL724
tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO"
select COMEDI_8255
---help---
- Enable support for Advantech PCL-724, PCL-722, PCL-731 and
- ADlink ACL-7122, ACL-7124, PET-48DIO ISA cards
+ Enable support for ISA and PC/104 based 8255 digital i/o boards. This
+ driver provides a legacy comedi driver wrapper for the generic 8255
+ support driver.
+
+ Supported boards include:
+ Advantech PCL-724 24 channels
+ Advantech PCL-722 144 (or 96) channels
+ Advantech PCL-731 48 channels
+ ADlink ACL-7122 144 (or 96) channels
+ ADlink ACL-7124 24 channels
+ ADlink PET-48DIO 48 channels
+ WinSystems PCM-IO48 48 channels (PC/104)
To compile this driver as a module, choose M here: the module will be
called pcl724.
@@ -403,6 +412,15 @@ config COMEDI_AIO_IIRO_16
To compile this driver as a module, choose M here: the module will be
called aio_iiro_16.
+config COMEDI_II_PCI20KC
+ tristate "Intelligent Instruments PCI-20001C carrier support"
+ ---help---
+ Enable support for Intelligent Instruments PCI-20001C carrier
+ PCI-20001, PCI-20006 and PCI-20341
+
+ To compile this driver as a module, choose M here: the module will be
+ called ii_pci20kc.
+
config COMEDI_C6XDIGIO
tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support"
---help---
@@ -448,7 +466,6 @@ config COMEDI_NI_AT_AO
config COMEDI_NI_ATMIO
tristate "NI AT-MIO E series ISA-PNP card support"
- depends on ISAPNP
select COMEDI_8255
select COMEDI_NI_TIO
---help---
@@ -461,11 +478,10 @@ config COMEDI_NI_ATMIO
called ni_atmio.
config COMEDI_NI_ATMIO16D
- tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support"
- depends on ISAPNP
+ tristate "NI AT-MIO-16/AT-MIO-16D series ISA card support"
select COMEDI_8255
---help---
- Enable support for National Instruments AT-MIO16/AT-MIO16D cards.
+ Enable support for National Instruments AT-MIO-16/AT-MIO-16D cards.
To compile this driver as a module, choose M here: the module will be
called ni_atmio16d.
@@ -473,7 +489,7 @@ config COMEDI_NI_ATMIO16D
config COMEDI_NI_LABPC_ISA
tristate "NI Lab-PC and compatibles ISA support"
select COMEDI_NI_LABPC
- depends on VIRT_TO_BUS
+ select COMEDI_NI_LABPC_ISADMA if ISA_DMA_API && VIRT_TO_BUS
---help---
Enable support for National Instruments Lab-PC and compatibles
Lab-PC-1200, Lab-PC-1200AI, Lab-PC+.
@@ -866,15 +882,6 @@ config COMEDI_ICP_MULTI
To compile this driver as a module, choose M here: the module will be
called icp_multi.
-config COMEDI_II_PCI20KC
- tristate "Intelligent Instruments PCI-20001C carrier support"
- ---help---
- Enable support for Intelligent Instruments PCI-20001C carrier
- PCI-20001, PCI-20006 and PCI-20341
-
- To compile this driver as a module, choose M here: the module will be
- called ii_pci20kc.
-
config COMEDI_DAQBOARD2000
tristate "IOtech DAQboard/2000 support"
select COMEDI_8255
@@ -1262,6 +1269,9 @@ config COMEDI_NI_LABPC
select COMEDI_8255
select COMEDI_FC
+config COMEDI_NI_LABPC_ISADMA
+ tristate
+
config COMEDI_NI_TIO
tristate
diff --git a/drivers/staging/comedi/TODO b/drivers/staging/comedi/TODO
index b10f739b7e3..fa8da9aada3 100644
--- a/drivers/staging/comedi/TODO
+++ b/drivers/staging/comedi/TODO
@@ -9,4 +9,4 @@ TODO:
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
copy:
Ian Abbott <abbotti@mev.co.uk>
- Frank Mori Hess <fmhess@users.sourceforge.net>
+ H Hartley Sweeten <hsweeten@visionengravers.com>
diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c
index b4c001b6f88..94b2385fb0a 100644
--- a/drivers/staging/comedi/comedi_buf.c
+++ b/drivers/staging/comedi/comedi_buf.c
@@ -15,6 +15,8 @@
* GNU General Public License for more details.
*/
+#include <linux/vmalloc.h>
+
#include "comedidev.h"
#include "comedi_internal.h"
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 8647518259f..1636c7ca57e 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -26,7 +26,6 @@
#include <linux/sched.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
-#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/kmod.h>
@@ -262,7 +261,7 @@ static int resize_async_buffer(struct comedi_device *dev,
/* sysfs attribute files */
-static ssize_t show_max_read_buffer_kb(struct device *csdev,
+static ssize_t max_read_buffer_kb_show(struct device *csdev,
struct device_attribute *attr, char *buf)
{
unsigned int minor = MINOR(csdev->devt);
@@ -283,7 +282,7 @@ static ssize_t show_max_read_buffer_kb(struct device *csdev,
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_max_read_buffer_kb(struct device *csdev,
+static ssize_t max_read_buffer_kb_store(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -314,8 +313,9 @@ static ssize_t store_max_read_buffer_kb(struct device *csdev,
return err ? err : count;
}
+static DEVICE_ATTR_RW(max_read_buffer_kb);
-static ssize_t show_read_buffer_kb(struct device *csdev,
+static ssize_t read_buffer_kb_show(struct device *csdev,
struct device_attribute *attr, char *buf)
{
unsigned int minor = MINOR(csdev->devt);
@@ -336,7 +336,7 @@ static ssize_t show_read_buffer_kb(struct device *csdev,
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_read_buffer_kb(struct device *csdev,
+static ssize_t read_buffer_kb_store(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -367,8 +367,9 @@ static ssize_t store_read_buffer_kb(struct device *csdev,
return err ? err : count;
}
+static DEVICE_ATTR_RW(read_buffer_kb);
-static ssize_t show_max_write_buffer_kb(struct device *csdev,
+static ssize_t max_write_buffer_kb_show(struct device *csdev,
struct device_attribute *attr,
char *buf)
{
@@ -390,7 +391,7 @@ static ssize_t show_max_write_buffer_kb(struct device *csdev,
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_max_write_buffer_kb(struct device *csdev,
+static ssize_t max_write_buffer_kb_store(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -421,8 +422,9 @@ static ssize_t store_max_write_buffer_kb(struct device *csdev,
return err ? err : count;
}
+static DEVICE_ATTR_RW(max_write_buffer_kb);
-static ssize_t show_write_buffer_kb(struct device *csdev,
+static ssize_t write_buffer_kb_show(struct device *csdev,
struct device_attribute *attr, char *buf)
{
unsigned int minor = MINOR(csdev->devt);
@@ -443,7 +445,7 @@ static ssize_t show_write_buffer_kb(struct device *csdev,
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_write_buffer_kb(struct device *csdev,
+static ssize_t write_buffer_kb_store(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -474,18 +476,16 @@ static ssize_t store_write_buffer_kb(struct device *csdev,
return err ? err : count;
}
+static DEVICE_ATTR_RW(write_buffer_kb);
-static struct device_attribute comedi_dev_attrs[] = {
- __ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR,
- show_max_read_buffer_kb, store_max_read_buffer_kb),
- __ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
- show_read_buffer_kb, store_read_buffer_kb),
- __ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR,
- show_max_write_buffer_kb, store_max_write_buffer_kb),
- __ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
- show_write_buffer_kb, store_write_buffer_kb),
- __ATTR_NULL
+static struct attribute *comedi_dev_attrs[] = {
+ &dev_attr_max_read_buffer_kb.attr,
+ &dev_attr_read_buffer_kb.attr,
+ &dev_attr_max_write_buffer_kb.attr,
+ &dev_attr_write_buffer_kb.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(comedi_dev);
static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
unsigned mask, unsigned bits)
@@ -1413,22 +1413,19 @@ static int do_cmd_ioctl(struct comedi_device *dev,
DPRINTK("subdevice busy\n");
return -EBUSY;
}
- s->busy = file;
/* make sure channel/gain list isn't too long */
if (cmd.chanlist_len > s->len_chanlist) {
DPRINTK("channel/gain list too long %u > %d\n",
cmd.chanlist_len, s->len_chanlist);
- ret = -EINVAL;
- goto cleanup;
+ return -EINVAL;
}
/* make sure channel/gain list isn't too short */
if (cmd.chanlist_len < 1) {
DPRINTK("channel/gain list too short %u < 1\n",
cmd.chanlist_len);
- ret = -EINVAL;
- goto cleanup;
+ return -EINVAL;
}
async->cmd = cmd;
@@ -1438,8 +1435,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
if (!async->cmd.chanlist) {
DPRINTK("allocation failed\n");
- ret = -ENOMEM;
- goto cleanup;
+ return -ENOMEM;
}
if (copy_from_user(async->cmd.chanlist, user_chanlist,
@@ -1491,6 +1487,9 @@ static int do_cmd_ioctl(struct comedi_device *dev,
comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
+ /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with
+ * comedi_read() or comedi_write() */
+ s->busy = file;
ret = s->do_cmd(dev, s);
if (ret == 0)
return 0;
@@ -1705,6 +1704,7 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
void *file)
{
struct comedi_subdevice *s;
+ int ret;
if (arg >= dev->n_subdevices)
return -EINVAL;
@@ -1721,7 +1721,11 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
if (s->busy != file)
return -EBUSY;
- return do_cancel(dev, s);
+ ret = do_cancel(dev, s);
+ if (comedi_get_subdevice_runflags(s) & SRF_USER)
+ wake_up_interruptible(&s->async->wait_head);
+
+ return ret;
}
/*
@@ -2053,11 +2057,13 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
if (!comedi_is_subdevice_running(s)) {
if (count == 0) {
+ mutex_lock(&dev->mutex);
if (comedi_is_subdevice_in_error(s))
retval = -EPIPE;
else
retval = 0;
do_become_nonbusy(dev, s);
+ mutex_unlock(&dev->mutex);
}
break;
}
@@ -2156,11 +2162,13 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
if (n == 0) {
if (!comedi_is_subdevice_running(s)) {
+ mutex_lock(&dev->mutex);
do_become_nonbusy(dev, s);
if (comedi_is_subdevice_in_error(s))
retval = -EPIPE;
else
retval = 0;
+ mutex_unlock(&dev->mutex);
break;
}
if (file->f_flags & O_NONBLOCK) {
@@ -2198,9 +2206,11 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
buf += n;
break; /* makes device work like a pipe */
}
- if (comedi_is_subdevice_idle(s) &&
- async->buf_read_count - async->buf_write_count == 0) {
- do_become_nonbusy(dev, s);
+ if (comedi_is_subdevice_idle(s)) {
+ mutex_lock(&dev->mutex);
+ if (async->buf_read_count - async->buf_write_count == 0)
+ do_become_nonbusy(dev, s);
+ mutex_unlock(&dev->mutex);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&async->wait_head, &wait);
@@ -2554,7 +2564,7 @@ static int __init comedi_init(void)
return PTR_ERR(comedi_class);
}
- comedi_class->dev_attrs = comedi_dev_attrs;
+ comedi_class->dev_groups = comedi_dev_groups;
/* XXX requires /proc interface */
comedi_proc_init();
diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h
index d5e03e558b3..fda1a7ba0e1 100644
--- a/drivers/staging/comedi/comedi_internal.h
+++ b/drivers/staging/comedi/comedi_internal.h
@@ -24,6 +24,7 @@ extern unsigned int comedi_default_buf_maxsize_kb;
/* drivers.c */
extern struct comedi_driver *comedi_drivers;
+extern struct mutex comedi_drivers_list_lock;
int insn_inval(struct comedi_device *, struct comedi_subdevice *,
struct comedi_insn *, unsigned int *);
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index b75915f30f4..2e19f659cd2 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -19,22 +19,7 @@
#ifndef _COMEDIDEV_H
#define _COMEDIDEV_H
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/kdev_t.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/wait.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
#include <linux/dma-mapping.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/timer.h>
#include "comedi.h"
@@ -357,6 +342,11 @@ void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
/* drivers.c - general comedi driver functions */
+int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *data,
+ unsigned int mask);
+
+void *comedi_alloc_devpriv(struct comedi_device *, size_t);
int comedi_alloc_subdevices(struct comedi_device *, int);
int comedi_load_firmware(struct comedi_device *, struct device *,
@@ -377,7 +367,7 @@ int comedi_auto_config(struct device *, struct comedi_driver *,
void comedi_auto_unconfig(struct device *);
int comedi_driver_register(struct comedi_driver *);
-int comedi_driver_unregister(struct comedi_driver *);
+void comedi_driver_unregister(struct comedi_driver *);
/**
* module_comedi_driver() - Helper macro for registering a comedi driver
@@ -400,7 +390,6 @@ int comedi_driver_unregister(struct comedi_driver *);
*/
#define PCI_VENDOR_ID_KOLTER 0x1001
#define PCI_VENDOR_ID_ICP 0x104c
-#define PCI_VENDOR_ID_AMCC 0x10e8
#define PCI_VENDOR_ID_DT 0x1116
#define PCI_VENDOR_ID_IOTECH 0x1616
#define PCI_VENDOR_ID_CONTEC 0x1221
diff --git a/drivers/staging/comedi/comedilib.h b/drivers/staging/comedi/comedilib.h
index 1a78b15543c..56baf852ecf 100644
--- a/drivers/staging/comedi/comedilib.h
+++ b/drivers/staging/comedi/comedilib.h
@@ -21,10 +21,13 @@
struct comedi_device *comedi_open(const char *path);
int comedi_close(struct comedi_device *dev);
+int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev,
+ unsigned int chan, unsigned int *io);
int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
unsigned int chan, unsigned int io);
-int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev,
- unsigned int mask, unsigned int *bits);
+int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev,
+ unsigned int mask, unsigned int *bits,
+ unsigned int base_channel);
int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
unsigned int subd);
int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice);
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index e25eba5713c..317a821b790 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -23,7 +23,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fcntl.h>
-#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -39,6 +38,7 @@
#include "comedi_internal.h"
struct comedi_driver *comedi_drivers;
+DEFINE_MUTEX(comedi_drivers_list_lock);
int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev)
{
@@ -57,6 +57,18 @@ static void comedi_clear_hw_dev(struct comedi_device *dev)
dev->hw_dev = NULL;
}
+/**
+ * comedi_alloc_devpriv() - Allocate memory for the device private data.
+ * @dev: comedi_device struct
+ * @size: size of the memory to allocate
+ */
+void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size)
+{
+ dev->private = kzalloc(size, GFP_KERNEL);
+ return dev->private;
+}
+EXPORT_SYMBOL_GPL(comedi_alloc_devpriv);
+
int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
{
struct comedi_subdevice *s;
@@ -138,6 +150,46 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
return -EINVAL;
}
+/**
+ * comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices.
+ * @dev: comedi_device struct
+ * @s: comedi_subdevice struct
+ * @insn: comedi_insn struct
+ * @data: parameters for the @insn
+ * @mask: io_bits mask for grouped channels
+ */
+int comedi_dio_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data,
+ unsigned int mask)
+{
+ unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec);
+
+ if (!mask)
+ mask = chan_mask;
+
+ switch (data[0]) {
+ case INSN_CONFIG_DIO_INPUT:
+ s->io_bits &= ~mask;
+ break;
+
+ case INSN_CONFIG_DIO_OUTPUT:
+ s->io_bits |= mask;
+ break;
+
+ case INSN_CONFIG_DIO_QUERY:
+ data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
+ return insn->n;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(comedi_dio_insn_config);
+
static int insn_rw_emulate_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -442,6 +494,7 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (dev->attached)
return -EBUSY;
+ mutex_lock(&comedi_drivers_list_lock);
for (driv = comedi_drivers; driv; driv = driv->next) {
if (!try_module_get(driv->module))
continue;
@@ -462,7 +515,8 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
comedi_report_boards(driv);
module_put(driv->module);
}
- return -EIO;
+ ret = -EIO;
+ goto out;
}
if (driv->attach == NULL) {
/* driver does not support manual configuration */
@@ -470,7 +524,8 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
"driver '%s' does not support attach using comedi_config\n",
driv->driver_name);
module_put(driv->module);
- return -ENOSYS;
+ ret = -ENOSYS;
+ goto out;
}
/* initialize dev->driver here so
* comedi_error() can be called from attach */
@@ -482,9 +537,11 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = comedi_device_postconfig(dev);
if (ret < 0) {
comedi_device_detach(dev);
- module_put(dev->driver->module);
+ module_put(driv->module);
}
/* On success, the driver module count has been incremented. */
+out:
+ mutex_unlock(&comedi_drivers_list_lock);
return ret;
}
@@ -541,18 +598,34 @@ EXPORT_SYMBOL_GPL(comedi_auto_unconfig);
int comedi_driver_register(struct comedi_driver *driver)
{
+ mutex_lock(&comedi_drivers_list_lock);
driver->next = comedi_drivers;
comedi_drivers = driver;
+ mutex_unlock(&comedi_drivers_list_lock);
return 0;
}
EXPORT_SYMBOL_GPL(comedi_driver_register);
-int comedi_driver_unregister(struct comedi_driver *driver)
+void comedi_driver_unregister(struct comedi_driver *driver)
{
struct comedi_driver *prev;
int i;
+ /* unlink the driver */
+ mutex_lock(&comedi_drivers_list_lock);
+ if (comedi_drivers == driver) {
+ comedi_drivers = driver->next;
+ } else {
+ for (prev = comedi_drivers; prev->next; prev = prev->next) {
+ if (prev->next == driver) {
+ prev->next = driver->next;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&comedi_drivers_list_lock);
+
/* check for devices using this driver */
for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
struct comedi_device *dev = comedi_dev_from_minor(i);
@@ -570,18 +643,5 @@ int comedi_driver_unregister(struct comedi_driver *driver)
}
mutex_unlock(&dev->mutex);
}
-
- if (comedi_drivers == driver) {
- comedi_drivers = driver->next;
- return 0;
- }
-
- for (prev = comedi_drivers; prev->next; prev = prev->next) {
- if (prev->next == driver) {
- prev->next = driver->next;
- return 0;
- }
- }
- return -EINVAL;
}
EXPORT_SYMBOL_GPL(comedi_driver_unregister);
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index 94e17500150..2f070fdbbb1 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -73,10 +73,9 @@ I/O port base address can be found in the output of 'lspci -v'.
will copy the latched value to a Comedi buffer.
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
#include "comedi_fc.h"
#include "8255.h"
@@ -185,39 +184,29 @@ static void subdev_8255_do_config(struct comedi_device *dev,
static int subdev_8255_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int mask;
- unsigned int bits;
+ int ret;
- mask = 1 << CR_CHAN(insn->chanspec);
- if (mask & 0x0000ff)
- bits = 0x0000ff;
- else if (mask & 0x00ff00)
- bits = 0x00ff00;
- else if (mask & 0x0f0000)
- bits = 0x0f0000;
+ if (chan < 8)
+ mask = 0x0000ff;
+ else if (chan < 16)
+ mask = 0x00ff00;
+ else if (chan < 20)
+ mask = 0x0f0000;
else
- bits = 0xf00000;
-
- switch (data[0]) {
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~bits;
- break;
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= bits;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- }
+ mask = 0xf00000;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
subdev_8255_do_config(dev, s);
- return 1;
+ return insn->n;
}
static int subdev_8255_cmdtest(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c
index 3d3547c1948..432e3f9c330 100644
--- a/drivers/staging/comedi/drivers/8255_pci.c
+++ b/drivers/staging/comedi/drivers/8255_pci.c
@@ -50,6 +50,7 @@ Interrupt support for these boards is also not currently supported.
Configuration Options: not applicable, uses PCI auto config
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -186,10 +187,9 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
dev->board_ptr = board;
dev->board_name = board->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index dbb93e33248..94cbd2618fc 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_COMEDI_DMM32AT) += dmm32at.o
obj-$(CONFIG_COMEDI_FL512) += fl512.o
obj-$(CONFIG_COMEDI_AIO_AIO12_8) += aio_aio12_8.o
obj-$(CONFIG_COMEDI_AIO_IIRO_16) += aio_iiro_16.o
+obj-$(CONFIG_COMEDI_II_PCI20KC) += ii_pci20kc.o
obj-$(CONFIG_COMEDI_C6XDIGIO) += c6xdigio.o
obj-$(CONFIG_COMEDI_MPC624) += mpc624.o
obj-$(CONFIG_COMEDI_ADQ12B) += adq12b.o
@@ -89,7 +90,6 @@ obj-$(CONFIG_COMEDI_DYNA_PCI10XX) += dyna_pci10xx.o
obj-$(CONFIG_COMEDI_UNIOXX5) += unioxx5.o
obj-$(CONFIG_COMEDI_GSC_HPDI) += gsc_hpdi.o
obj-$(CONFIG_COMEDI_ICP_MULTI) += icp_multi.o
-obj-$(CONFIG_COMEDI_II_PCI20KC) += ii_pci20kc.o
obj-$(CONFIG_COMEDI_DAQBOARD2000) += daqboard2000.o
obj-$(CONFIG_COMEDI_JR3_PCI) += jr3_pci.o
obj-$(CONFIG_COMEDI_KE_COUNTER) += ke_counter.o
@@ -132,6 +132,7 @@ obj-$(CONFIG_COMEDI_MITE) += mite.o
obj-$(CONFIG_COMEDI_NI_TIO) += ni_tio.o
obj-$(CONFIG_COMEDI_NI_TIOCMD) += ni_tiocmd.o
obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc.o
+obj-$(CONFIG_COMEDI_NI_LABPC_ISADMA) += ni_labpc_isadma.o
obj-$(CONFIG_COMEDI_8255) += 8255.o
obj-$(CONFIG_COMEDI_AMPLC_DIO200) += amplc_dio200_common.o
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c
deleted file mode 100644
index d0702084caa..00000000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c
+++ /dev/null
@@ -1,1068 +0,0 @@
-/*
- * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
- *
- * ADDI-DATA GmbH
- * Dieselstrasse 3
- * D-77833 Ottersweier
- * Tel: +19(0)7223/9493-0
- * Fax: +49(0)7223/9493-92
- * http://www.addi-data.com
- * info@addi-data.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.
- */
-/*
- | Description : APCI-1710 82X54 timer module |
-*/
-
-#define APCI1710_PCI_BUS_CLOCK 0
-#define APCI1710_FRONT_CONNECTOR_INPUT 1
-#define APCI1710_TIMER_READVALUE 0
-#define APCI1710_TIMER_GETOUTPUTLEVEL 1
-#define APCI1710_TIMER_GETPROGRESSSTATUS 2
-#define APCI1710_TIMER_WRITEVALUE 3
-
-#define APCI1710_TIMER_READINTERRUPT 1
-#define APCI1710_TIMER_READALLTIMER 2
-
-#ifndef APCI1710_10MHZ
-#define APCI1710_10MHZ 10
-#endif
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitTimer |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_TimerNbr, |
-| unsigned char_ b_TimerMode, |
-| ULONG_ ul_ReloadValue, |
-| unsigned char_ b_InputClockSelection, |
-| unsigned char_ b_InputClockLevel, |
-| unsigned char_ b_OutputLevel, |
-| unsigned char_ b_HardwareGateLevel)
-int i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s,
- struct comedi_insn *insn,unsigned int *data)
-|
-+----------------------------------------------------------------------------+
-| Task : Configure the Timer (b_TimerNbr) operating mode |
-| (b_TimerMode) from selected module (b_ModulNbr). |
-| You must calling this function be for you call any |
-| other function witch access of the timer. |
-| |
-| |
-| Timer mode description table |
-| |
-|+--------+-----------------------------+--------------+--------------------+|
-||Selected+ Mode description +u_ReloadValue | Hardware gate input||
-|| mode | | description | action ||
-|+--------+-----------------------------+--------------+--------------------+|
-|| |Mode 0 is typically used | | ||
-|| |for event counting. After | | ||
-|| |the initialisation, OUT | | ||
-|| |is initially low, and | | ||
-|| 0 |will remain low until the |Start counting| Hardware gate ||
-|| |counter reaches zero. | value | ||
-|| |OUT then goes high and | | ||
-|| |remains high until a new | | ||
-|| |count is written. See | | ||
-|| |"i_APCI1710_WriteTimerValue" | | ||
-|| |function. | | ||
-|+--------+-----------------------------+--------------+--------------------+|
-|| |Mode 1 is similar to mode 0 | | ||
-|| |except for the gate input | | ||
-|| 1 |action. The gate input is not|Start counting| Hardware trigger ||
-|| |used for enabled or disabled | value | ||
-|| |the timer. | | ||
-|| |The gate input is used for | | ||
-|| |triggered the timer. | | ||
-|+--------+-----------------------------+--------------+--------------------+|
-|| |This mode functions like a | | ||
-|| |divide-by-ul_ReloadValue | | ||
-|| |counter. It is typically used| | ||
-|| |to generate a real time clock| | ||
-|| |interrupt. OUT will initially| | ||
-|| 2 |be high after the | Division | Hardware gate ||
-|| |initialisation. When the | factor | ||
-|| |initial count has decremented| | ||
-|| |to 1, OUT goes low for one | | ||
-|| |CLK pule. OUT then goes high | | ||
-|| |again, the counter reloads | | ||
-|| |the initial count | | ||
-|| |(ul_ReloadValue) and the | | ||
-|| |process is repeated. | | ||
-|| |This action can generated a | | ||
-|| |interrupt. See function | | ||
-|| |"i_APCI1710_SetBoardInt- | | ||
-|| |RoutineX" | | ||
-|| |and "i_APCI1710_EnableTimer" | | ||
-|+--------+-----------------------------+--------------+--------------------+|
-|| |Mode 3 is typically used for | | ||
-|| |baud rate generation. This | | ||
-|| |mode is similar to mode 2 | | ||
-|| |except for the duty cycle of | | ||
-|| 3 |OUT. OUT will initially be | Division | Hardware gate ||
-|| |high after the initialisation| factor | ||
-|| |When half the initial count | | ||
-|| |(ul_ReloadValue) has expired,| | ||
-|| |OUT goes low for the | | ||
-|| |remainder of the count. The | | ||
-|| |mode is periodic; the | | ||
-|| |sequence above is repeated | | ||
-|| |indefinitely. | | ||
-|+--------+-----------------------------+--------------+--------------------+|
-|| |OUT will be initially high | | ||
-|| |after the initialisation. | | ||
-|| |When the initial count | | ||
-|| 4 |expires OUT will go low for |Start counting| Hardware gate ||
-|| |one CLK pulse and then go | value | ||
-|| |high again. | | ||
-|| |The counting sequences is | | ||
-|| |triggered by writing a new | | ||
-|| |value. See | | ||
-|| |"i_APCI1710_WriteTimerValue" | | ||
-|| |function. If a new count is | | ||
-|| |written during counting, | | ||
-|| |it will be loaded on the | | ||
-|| |next CLK pulse | | ||
-|+--------+-----------------------------+--------------+--------------------+|
-|| |Mode 5 is similar to mode 4 | | ||
-|| |except for the gate input | | ||
-|| |action. The gate input is not| | ||
-|| 5 |used for enabled or disabled |Start counting| Hardware trigger ||
-|| |the timer. The gate input is | value | ||
-|| |used for triggered the timer.| | ||
-|+--------+-----------------------------+--------------+--------------------+|
-| |
-| |
-| |
-| Input clock selection table |
-| |
-| +--------------------------------+------------------------------------+ |
-| | b_InputClockSelection | Description | |
-| | parameter | | |
-| +--------------------------------+------------------------------------+ |
-| | APCI1710_PCI_BUS_CLOCK | For the timer input clock, the PCI | |
-| | | bus clock / 4 is used. This PCI bus| |
-| | | clock can be 30MHz or 33MHz. For | |
-| | | Timer 0 only this selection are | |
-| | | available. | |
-| +--------------------------------+------------------------------------+ |
-| | APCI1710_ FRONT_CONNECTOR_INPUT| Of the front connector you have the| |
-| | | possibility to inject a input clock| |
-| | | for Timer 1 or Timer 2. The source | |
-| | | from this clock can eat the output | |
-| | | clock from Timer 0 or any other | |
-| | | clock source. | |
-| +--------------------------------+------------------------------------+ |
-| |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board |
-| APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to |
-| configure (0 to 3) |
-| unsigned char_ b_TimerNbr : Timer number to |
-| configure (0 to 2) |
-| unsigned char_ b_TimerMode : Timer mode selection |
-| (0 to 5) |
-| 0: Interrupt on terminal|
-| count |
-| 1: Hardware |
-| retriggerable one- |
-| shot |
-| 2: Rate generator |
-| 3: Square wave mode |
-| 4: Software triggered |
-| strobe |
-| 5: Hardware triggered |
-| strobe |
-| See timer mode |
-| description table. |
-| ULONG_ ul_ReloadValue : Start counting value |
-| or division factor |
-| See timer mode |
-| description table. |
-| unsigned char_ b_InputClockSelection : Selection from input |
-| timer clock. |
-| See input clock |
-| selection table. |
-| unsigned char_ b_InputClockLevel : Selection from input |
-| clock level. |
-| 0 : Low active |
-| (Input inverted) |
-| 1 : High active |
-| unsigned char_ b_OutputLevel, : Selection from output |
-| clock level. |
-| 0 : Low active |
-| 1 : High active |
-| (Output inverted) |
-| unsigned char_ b_HardwareGateLevel : Selection from |
-| hardware gate level. |
-| 0 : Low active |
-| (Input inverted) |
-| 1 : High active |
-| If you will not used |
-| the hardware gate set |
-| this value to 0.
-|b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec);
- b_TimerMode = (unsigned char) data[0];
- ul_ReloadValue = (unsigned int) data[1];
- b_InputClockSelection =(unsigned char) data[2];
- b_InputClockLevel =(unsigned char) data[3];
- b_OutputLevel =(unsigned char) data[4];
- b_HardwareGateLevel =(unsigned char) data[5];
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: Timer selection wrong |
-| -4: The module is not a TIMER module |
-| -5: Timer mode selection is wrong |
-| -6: Input timer clock selection is wrong |
-| -7: Selection from input clock level is wrong |
-| -8: Selection from output clock level is wrong |
-| -9: Selection from hardware gate level is wrong |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnConfigInitTimer(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned char b_ModulNbr;
- unsigned char b_TimerNbr;
- unsigned char b_TimerMode;
- unsigned int ul_ReloadValue;
- unsigned char b_InputClockSelection;
- unsigned char b_InputClockLevel;
- unsigned char b_OutputLevel;
- unsigned char b_HardwareGateLevel;
-
- /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */
- unsigned int dw_Test = 0;
- /* END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */
-
- i_ReturnValue = insn->n;
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec);
- b_TimerMode = (unsigned char) data[0];
- ul_ReloadValue = (unsigned int) data[1];
- b_InputClockSelection = (unsigned char) data[2];
- b_InputClockLevel = (unsigned char) data[3];
- b_OutputLevel = (unsigned char) data[4];
- b_HardwareGateLevel = (unsigned char) data[5];
-
- /* Test the module number */
- if (b_ModulNbr < 4) {
- /* Test if 82X54 timer */
- if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
- /* Test the timer number */
-
- if (b_TimerNbr <= 2) {
- /* Test the timer mode */
- if (b_TimerMode <= 5) {
- /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */
- /* Test te imput clock selection */
- /*
- if (((b_TimerNbr == 0) && (b_InputClockSelection == 0)) ||
- ((b_TimerNbr != 0) && ((b_InputClockSelection == 0) || (b_InputClockSelection == 1))))
- */
-
- if (((b_TimerNbr == 0) &&
- (b_InputClockSelection == APCI1710_PCI_BUS_CLOCK)) ||
- ((b_TimerNbr == 0) &&
- (b_InputClockSelection == APCI1710_10MHZ)) ||
- ((b_TimerNbr != 0) &&
- ((b_InputClockSelection == APCI1710_PCI_BUS_CLOCK) ||
- (b_InputClockSelection == APCI1710_FRONT_CONNECTOR_INPUT) ||
- (b_InputClockSelection == APCI1710_10MHZ)))) {
- /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */
- if (((b_InputClockSelection == APCI1710_10MHZ) &&
- ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) >= 0x3131)) ||
- (b_InputClockSelection != APCI1710_10MHZ)) {
- /* END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */
- /* Test the input clock level selection */
-
- if ((b_InputClockLevel == 0) ||
- (b_InputClockLevel == 1)) {
- /* Test the output clock level selection */
- if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) {
- /* Test the hardware gate level selection */
- if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) {
- /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
- /* Test if version > 1.1 and clock selection = 10MHz */
- if ((b_InputClockSelection == APCI1710_10MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) > 0x3131)) {
- /* Test if 40MHz quartz on board */
- dw_Test = inl(devpriv->s_BoardInfos.ui_Address + (16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)));
-
- dw_Test = (dw_Test >> 16) & 1;
- } else {
- dw_Test = 1;
- }
-
- /* Test if detection OK */
- if (dw_Test == 1) {
- /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
- /* Initialisation OK */
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init = 1;
-
- /* Save the input clock selection */
- devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockSelection = b_InputClockSelection;
-
- /* Save the input clock level */
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockLevel = ~b_InputClockLevel & 1;
-
- /* Save the output level */
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel = ~b_OutputLevel & 1;
-
- /* Save the gate level */
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_HardwareGateLevel = b_HardwareGateLevel;
-
- /* Set the configuration word and disable the timer */
- /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
- /*
- devpriv->s_ModuleInfo [b_ModulNbr].
- s_82X54ModuleInfo.
- s_82X54TimerInfo [b_TimerNbr].
- dw_ConfigurationWord = (unsigned int) (((b_HardwareGateLevel << 0) & 0x1) |
- ((b_InputClockLevel << 1) & 0x2) |
- (((~b_OutputLevel & 1) << 2) & 0x4) |
- ((b_InputClockSelection << 4) & 0x10));
- */
- /* Test if 10MHz selected */
- if (b_InputClockSelection == APCI1710_10MHZ) {
- b_InputClockSelection = 2;
- }
-
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = (unsigned int)(((b_HardwareGateLevel << 0) & 0x1) | ((b_InputClockLevel << 1) & 0x2) | (((~b_OutputLevel & 1) << 2) & 0x4) | ((b_InputClockSelection << 4) & 0x30));
- /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
- outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
- /* Initialise the 82X54 Timer */
- outl((unsigned int) b_TimerMode, devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
- /* Write the reload value */
- outl(ul_ReloadValue, devpriv->s_BoardInfos.ui_Address + 0 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
- /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
- } /* if (dw_Test == 1) */
- else {
- /* Input timer clock selection is wrong */
- i_ReturnValue = -6;
- } /* if (dw_Test == 1) */
- /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
- } /* if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) */
- else {
- /* Selection from hardware gate level is wrong */
- DPRINTK("Selection from hardware gate level is wrong\n");
- i_ReturnValue = -9;
- } /* if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) */
- } /* if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) */
- else {
- /* Selection from output clock level is wrong */
- DPRINTK("Selection from output clock level is wrong\n");
- i_ReturnValue = -8;
- } /* if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) */
- } /* if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) */
- else {
- /* Selection from input clock level is wrong */
- DPRINTK("Selection from input clock level is wrong\n");
- i_ReturnValue = -7;
- } /* if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) */
- } else {
- /* Input timer clock selection is wrong */
- DPRINTK("Input timer clock selection is wrong\n");
- i_ReturnValue = -6;
- }
- } else {
- /* Input timer clock selection is wrong */
- DPRINTK("Input timer clock selection is wrong\n");
- i_ReturnValue = -6;
- }
- } /* if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) */
- else {
- /* Timer mode selection is wrong */
- DPRINTK("Timer mode selection is wrong\n");
- i_ReturnValue = -5;
- } /* if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) */
- } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
- else {
- /* Timer selection wrong */
- DPRINTK("Timer selection wrong\n");
- i_ReturnValue = -3;
- } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
- } else {
- /* The module is not a TIMER module */
- DPRINTK("The module is not a TIMER module\n");
- i_ReturnValue = -4;
- }
- } else {
- /* Module number error */
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_EnableTimer |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_TimerNbr, |
-| unsigned char_ b_InterruptEnable)
-int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,struct comedi_subdevice *s,
- struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Enable OR Disable the Timer (b_TimerNbr) from selected module |
-| (b_ModulNbr). You must calling the |
-| "i_APCI1710_InitTimer" function be for you call this |
-| function. If you enable the timer interrupt, the timer |
-| generate a interrupt after the timer value reach |
-| the zero. See function "i_APCI1710_SetBoardIntRoutineX"|
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board |
-| APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number |
-| (0 to 3) |
-| unsigned char_ b_TimerNbr : Timer number to enable |
-| (0 to 2) |
-| unsigned char_ b_InterruptEnable : Enable or disable the |
-| timer interrupt. |
-| APCI1710_ENABLE : |
-| Enable the timer interrupt |
-| APCI1710_DISABLE : |
-| Disable the timer interrupt|
-i_ReturnValue=insn->n;
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec);
- b_ActionType = (unsigned char) data[0]; /* enable disable */
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: Timer selection wrong |
-| -4: The module is not a TIMER module |
-| -5: Timer not initialised see function |
-| "i_APCI1710_InitTimer" |
-| -6: Interrupt parameter is wrong |
-| -7: Interrupt function not initialised. |
-| See function "i_APCI1710_SetBoardIntRoutineX" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_DummyRead;
- unsigned char b_ModulNbr;
- unsigned char b_TimerNbr;
- unsigned char b_ActionType;
- unsigned char b_InterruptEnable;
-
- i_ReturnValue = insn->n;
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec);
- b_ActionType = (unsigned char) data[0]; /* enable disable */
-
- /* Test the module number */
- if (b_ModulNbr < 4) {
- /* Test if 82X54 timer */
- if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
- /* Test the timer number */
- if (b_TimerNbr <= 2) {
- /* Test if timer initialised */
- if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
-
- switch (b_ActionType) {
- case APCI1710_ENABLE:
- b_InterruptEnable = (unsigned char) data[1];
- /* Test the interrupt selection */
- if ((b_InterruptEnable == APCI1710_ENABLE) ||
- (b_InterruptEnable == APCI1710_DISABLE)) {
- if (b_InterruptEnable == APCI1710_ENABLE) {
-
- dw_DummyRead = inl(devpriv->s_BoardInfos.ui_Address + 12 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
- /* Enable the interrupt */
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord | 0x8;
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
- devpriv->tsk_Current = current; /* Save the current process task structure */
-
- } /* if (b_InterruptEnable == APCI1710_ENABLE) */
- else {
- /* Disable the interrupt */
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7;
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
- /* Save the interrupt flag */
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr));
- } /* if (b_InterruptEnable == APCI1710_ENABLE) */
-
- /* Test if error occur */
- if (i_ReturnValue >= 0) {
- /* Save the interrupt flag */
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask | ((1 & b_InterruptEnable) << b_TimerNbr);
-
- /* Enable the timer */
- outl(1, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
- }
- } else {
- /* Interrupt parameter is wrong */
- DPRINTK("\n");
- i_ReturnValue = -6;
- }
- break;
- case APCI1710_DISABLE:
- /* Test the interrupt flag */
- if (((devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask >> b_TimerNbr) & 1) == 1) {
- /* Disable the interrupt */
-
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr]. dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7;
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
- /* Save the interrupt flag */
- devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr));
- }
-
- /* Disable the timer */
- outl(0, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
- break;
- } /* Switch end */
- } else {
- /* Timer not initialised see function */
- DPRINTK ("Timer not initialised see function\n");
- i_ReturnValue = -5;
- }
- } else {
- /* Timer selection wrong */
- DPRINTK("Timer selection wrong\n");
- i_ReturnValue = -3;
- } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
- } else {
- /* The module is not a TIMER module */
- DPRINTK("The module is not a TIMER module\n");
- i_ReturnValue = -4;
- }
- } else {
- /* Module number error */
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadAllTimerValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| PULONG_ pul_TimerValueArray)
-int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,struct comedi_subdevice *s,
- struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Return the all timer values from selected timer |
-| module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board |
-| APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_TimerValueArray : Timer value array. |
-| Element 0 contain the timer 0 value. |
-| Element 1 contain the timer 1 value. |
-| Element 2 contain the timer 2 value. |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a TIMER module |
-| -4: Timer 0 not initialised see function |
-| "i_APCI1710_InitTimer" |
-| -5: Timer 1 not initialised see function |
-| "i_APCI1710_InitTimer" |
-| -6: Timer 2 not initialised see function |
-| "i_APCI1710_InitTimer" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned char b_ModulNbr, b_ReadType;
- unsigned int *pul_TimerValueArray;
-
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_ReadType = CR_CHAN(insn->chanspec);
- pul_TimerValueArray = (unsigned int *) data;
- i_ReturnValue = insn->n;
-
- switch (b_ReadType) {
- case APCI1710_TIMER_READINTERRUPT:
-
- data[0] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].b_OldModuleMask;
- data[1] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldInterruptMask;
- data[2] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
- /* Increment the read FIFO */
- devpriv->s_InterruptParameters.ui_Read = (devpriv->s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-
- break;
-
- case APCI1710_TIMER_READALLTIMER:
- /* Test the module number */
- if (b_ModulNbr < 4) {
- /* Test if 82X54 timer */
- if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
- /* Test if timer 0 iniutialised */
- if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[0].b_82X54Init == 1) {
- /* Test if timer 1 iniutialised */
- if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[1].b_82X54Init == 1) {
- /* Test if timer 2 iniutialised */
- if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[2].b_82X54Init == 1) {
- /* Latch all counter */
- outl(0x17, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
-
- /* Read the timer 0 value */
- pul_TimerValueArray[0] = inl(devpriv->s_BoardInfos.ui_Address + 0 + (64 * b_ModulNbr));
-
- /* Read the timer 1 value */
- pul_TimerValueArray[1] = inl(devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
-
- /* Read the timer 2 value */
- pul_TimerValueArray[2] = inl(devpriv->s_BoardInfos.ui_Address + 8 + (64 * b_ModulNbr));
- } else {
- /* Timer 2 not initialised see function */
- DPRINTK("Timer 2 not initialised see function\n");
- i_ReturnValue = -6;
- }
- } else {
- /* Timer 1 not initialised see function */
- DPRINTK("Timer 1 not initialised see function\n");
- i_ReturnValue = -5;
- }
- } else {
- /* Timer 0 not initialised see function */
- DPRINTK("Timer 0 not initialised see function\n");
- i_ReturnValue = -4;
- }
- } else {
- /* The module is not a TIMER module */
- DPRINTK("The module is not a TIMER module\n");
- i_ReturnValue = -3;
- }
- } else {
- /* Module number error */
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- } /* End of Switch */
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadTimerValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_TimerNbr, |
-| PULONG_ pul_TimerValue) |
-+----------------------------------------------------------------------------+
-| Task : Return the timer value from selected digital timer |
-| (b_TimerNbr) from selected timer module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board |
-| APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number |
-| (0 to 3) |
-| unsigned char_ b_TimerNbr : Timer number to read |
-| (0 to 2) |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_TimerValue : Timer value |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: Timer selection wrong |
-| -4: The module is not a TIMER module |
-| -5: Timer not initialised see function |
-| "i_APCI1710_InitTimer" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ReadTimerValue(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_TimerNbr,
- unsigned int *pul_TimerValue)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /* Test the module number */
- if (b_ModulNbr < 4) {
- /* Test if 82X54 timer */
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
- /* Test the timer number */
- if (b_TimerNbr <= 2) {
- /* Test if timer initialised */
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_82X54ModuleInfo.
- s_82X54TimerInfo[b_TimerNbr].
- b_82X54Init == 1) {
- /* Latch the timer value */
- outl((2 << b_TimerNbr) | 0xD0,
- devpriv->s_BoardInfos.
- ui_Address + 12 +
- (64 * b_ModulNbr));
-
- /* Read the counter value */
- *pul_TimerValue =
- inl(devpriv->s_BoardInfos.
- ui_Address + (b_TimerNbr * 4) +
- (64 * b_ModulNbr));
- } else {
- /* Timer not initialised see function */
- DPRINTK("Timer not initialised see function\n");
- i_ReturnValue = -5;
- }
- } else {
- /* Timer selection wrong */
- DPRINTK("Timer selection wrong\n");
- i_ReturnValue = -3;
- } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
- } else {
- /* The module is not a TIMER module */
- DPRINTK("The module is not a TIMER module\n");
- i_ReturnValue = -4;
- }
- } else {
- /* Module number error */
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
- /*
- +----------------------------------------------------------------------------+
- | Function Name : _INT_ i_APCI1710_GetTimerOutputLevel |
- | (unsigned char_ b_BoardHandle, |
- | unsigned char_ b_ModulNbr, |
- | unsigned char_ b_TimerNbr, |
- | unsigned char *_ pb_OutputLevel) |
- +----------------------------------------------------------------------------+
- | Task : Return the output signal level (pb_OutputLevel) from |
- | selected digital timer (b_TimerNbr) from selected timer|
- | module (b_ModulNbr). |
- +----------------------------------------------------------------------------+
- | Input Parameters : unsigned char_ b_BoardHandle : Handle of board |
- | APCI-1710 |
- | unsigned char_ b_ModulNbr : Selected module number |
- | (0 to 3) |
- | unsigned char_ b_TimerNbr : Timer number to test |
- | (0 to 2) |
- +----------------------------------------------------------------------------+
- | Output Parameters : unsigned char *_ pb_OutputLevel : Output signal level |
- | 0 : The output is low |
- | 1 : The output is high |
- +----------------------------------------------------------------------------+
- | Return Value : 0: No error |
- | -1: The handle parameter of the board is wrong |
- | -2: Module selection wrong |
- | -3: Timer selection wrong |
- | -4: The module is not a TIMER module |
- | -5: Timer not initialised see function |
- | "i_APCI1710_InitTimer" |
- +----------------------------------------------------------------------------+
- */
-static int i_APCI1710_GetTimerOutputLevel(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_TimerNbr,
- unsigned char *pb_OutputLevel)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_TimerStatus;
-
- /* Test the module number */
- if (b_ModulNbr < 4) {
- /* Test if 82X54 timer */
- if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
- /* Test the timer number */
- if (b_TimerNbr <= 2) {
- /* Test if timer initialised */
- if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
- /* Latch the timer value */
- outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
-
- /* Read the timer status */
- dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
- *pb_OutputLevel = (unsigned char) (((dw_TimerStatus >> 7) & 1) ^ devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel);
- } else {
- /* Timer not initialised see function */
- DPRINTK("Timer not initialised see function\n");
- i_ReturnValue = -5;
- }
- } else {
- /* Timer selection wrong */
- DPRINTK("Timer selection wrong\n");
- i_ReturnValue = -3;
- } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
- } else {
- /* The module is not a TIMER module */
- DPRINTK("The module is not a TIMER module\n");
- i_ReturnValue = -4;
- }
- } else {
- /* Module number error */
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetTimerProgressStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_TimerNbr, |
-| unsigned char *_ pb_TimerStatus) |
-+----------------------------------------------------------------------------+
-| Task : Return the progress status (pb_TimerStatus) from |
-| selected digital timer (b_TimerNbr) from selected timer|
-| module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board |
-| APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number |
-| (0 to 3) |
-| unsigned char_ b_TimerNbr : Timer number to test |
-| (0 to 2) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_TimerStatus : Output signal level |
-| 0 : Timer not in progress |
-| 1 : Timer in progress |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: Timer selection wrong |
-| -4: The module is not a TIMER module |
-| -5: Timer not initialised see function |
-| "i_APCI1710_InitTimer" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_TimerNbr,
- unsigned char *pb_TimerStatus)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_TimerStatus;
-
- /* Test the module number */
- if (b_ModulNbr < 4) {
- /* Test if 82X54 timer */
-
- if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
- /* Test the timer number */
- if (b_TimerNbr <= 2) {
- /* Test if timer initialised */
- if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
- /* Latch the timer value */
- outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
-
- /* Read the timer status */
- dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
- *pb_TimerStatus = (unsigned char) ((dw_TimerStatus) >> 8) & 1;
- printk("ProgressStatus : %d", *pb_TimerStatus);
- } else {
- /* Timer not initialised see function */
- i_ReturnValue = -5;
- }
- } else {
- /* Timer selection wrong */
- i_ReturnValue = -3;
- } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
- } else {
- /* The module is not a TIMER module */
-
- i_ReturnValue = -4;
- }
- } else {
- /* Module number error */
-
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_WriteTimerValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_TimerNbr, |
-| ULONG_ ul_WriteValue) |
-+----------------------------------------------------------------------------+
-| Task : Write the value (ul_WriteValue) into the selected timer|
-| (b_TimerNbr) from selected timer module (b_ModulNbr). |
-| The action in depend of the time mode selection. |
-| See timer mode description table. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board |
-| APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number |
-| (0 to 3) |
-| unsigned char_ b_TimerNbr : Timer number to write |
-| (0 to 2) |
-| ULONG_ ul_WriteValue : Value to write |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: Timer selection wrong |
-| -4: The module is not a TIMER module |
-| -5: Timer not initialised see function |
-| "i_APCI1710_InitTimer" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_WriteTimerValue(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_TimerNbr,
- unsigned int ul_WriteValue)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /* Test the module number */
- if (b_ModulNbr < 4) {
- /* Test if 82X54 timer */
- if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
- /* Test the timer number */
- if (b_TimerNbr <= 2) {
- /* Test if timer initialised */
- if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
- /* Write the value */
- outl(ul_WriteValue, devpriv->s_BoardInfos.ui_Address + (b_TimerNbr * 4) + (64 * b_ModulNbr));
- } else {
- /* Timer not initialised see function */
- DPRINTK("Timer not initialised see function\n");
- i_ReturnValue = -5;
- }
- } else {
- /* Timer selection wrong */
- DPRINTK("Timer selection wrong\n");
- i_ReturnValue = -3;
- } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
- } else {
- /* The module is not a TIMER module */
- DPRINTK("The module is not a TIMER module\n");
- i_ReturnValue = -4;
- }
- } else {
- /* Module number error */
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name :INT i_APCI1710_InsnBitsTimer(struct comedi_device *dev,
-struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Read write functions for Timer |
-+----------------------------------------------------------------------------+
-| Input Parameters :
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value :
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnBitsTimer(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- unsigned char b_BitsType;
- int i_ReturnValue = 0;
- b_BitsType = data[0];
-
- printk("\n82X54");
-
- switch (b_BitsType) {
- case APCI1710_TIMER_READVALUE:
- i_ReturnValue = i_APCI1710_ReadTimerValue(dev,
- (unsigned char)CR_AREF(insn->chanspec),
- (unsigned char)CR_CHAN(insn->chanspec),
- (unsigned int *) &data[0]);
- break;
-
- case APCI1710_TIMER_GETOUTPUTLEVEL:
- i_ReturnValue = i_APCI1710_GetTimerOutputLevel(dev,
- (unsigned char)CR_AREF(insn->chanspec),
- (unsigned char)CR_CHAN(insn->chanspec),
- (unsigned char *) &data[0]);
- break;
-
- case APCI1710_TIMER_GETPROGRESSSTATUS:
- i_ReturnValue = i_APCI1710_GetTimerProgressStatus(dev,
- (unsigned char)CR_AREF(insn->chanspec),
- (unsigned char)CR_CHAN(insn->chanspec),
- (unsigned char *)&data[0]);
- break;
-
- case APCI1710_TIMER_WRITEVALUE:
- i_ReturnValue = i_APCI1710_WriteTimerValue(dev,
- (unsigned char)CR_AREF(insn->chanspec),
- (unsigned char)CR_CHAN(insn->chanspec),
- (unsigned int)data[1]);
-
- break;
-
- default:
- printk("Bits Config Parameter Wrong\n");
- i_ReturnValue = -1;
- }
-
- if (i_ReturnValue >= 0)
- i_ReturnValue = insn->n;
- return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c
deleted file mode 100644
index d91f586fdd2..00000000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c
+++ /dev/null
@@ -1,2050 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-----------------------------------------------------------------------+
- | Project : API APCI1710 | Compiler : gcc |
- | Module name : CHRONO.C | Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-----------------------------------------------------------------------+
- | Description : APCI-1710 chronometer module |
- | |
- | |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +-----------------------------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | 29/06/98 | S. Weber | Digital input / output implementation |
- |----------|-----------|------------------------------------------------|
- | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 |
- | | | available |
- +-----------------------------------------------------------------------+
- | | | |
- | | | |
- +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_30MHZ 30
-#define APCI1710_33MHZ 33
-#define APCI1710_40MHZ 40
-
-#define APCI1710_SINGLE 0
-#define APCI1710_CONTINUOUS 1
-
-#define APCI1710_CHRONO_PROGRESS_STATUS 0
-#define APCI1710_CHRONO_READVALUE 1
-#define APCI1710_CHRONO_CONVERTVALUE 2
-#define APCI1710_CHRONO_READINTERRUPT 3
-
-#define APCI1710_CHRONO_SET_CHANNELON 0
-#define APCI1710_CHRONO_SET_CHANNELOFF 1
-#define APCI1710_CHRONO_READ_CHANNEL 2
-#define APCI1710_CHRONO_READ_PORT 3
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitChrono |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_ChronoMode, |
-| unsigned char_ b_PCIInputClock, |
-| unsigned char_ b_TimingUnit, |
-| ULONG_ ul_TimingInterval, |
-| PULONG_ pul_RealTimingInterval)
-
-+----------------------------------------------------------------------------+
-| Task : Configure the chronometer operating mode (b_ChronoMode)|
-| from selected module (b_ModulNbr). |
-| The ul_TimingInterval and ul_TimingUnit determine the |
-| timing base for the measurement. |
-| The pul_RealTimingInterval return the real timing |
-| value. You must calling this function be for you call |
-| any other function witch access of the chronometer. |
-| |
-| Witch this functionality from the APCI-1710 you have |
-| the possibility to measure the timing witch two event. |
-| |
-| The mode 0 and 1 is appropriate for period measurement.|
-| The mode 2 and 3 is appropriate for frequent |
-| measurement. |
-| The mode 4 to 7 is appropriate for measuring the timing|
-| between two event. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr CR_AREF(insn->chanspec) : Module number to configure |
-| (0 to 3) |
-| unsigned char_ b_ChronoMode data[0] : Chronometer action mode |
-| (0 to 7). |
-| unsigned char_ b_PCIInputClock data[1] : Selection from PCI bus clock|
-| - APCI1710_30MHZ : |
-| The PC have a PCI bus |
-| clock from 30 MHz |
-| - APCI1710_33MHZ : |
-| The PC have a PCI bus |
-| clock from 33 MHz |
-| - APCI1710_40MHZ |
-| The APCI-1710 have a |
-| integrated 40Mhz |
-| quartz. |
-| unsigned char_ b_TimingUnit data[2] : Base timing unity (0 to 4) |
-| 0 : ns |
-| 1 : µs |
-| 2 : ms |
-| 3 : s |
-| 4 : mn |
-| ULONG_ ul_TimingInterval : data[3] Base timing value. |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_RealTimingInterval : Real base timing |
-| value.
-| data[0]
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a Chronometer module |
-| -4: Chronometer mode selection is wrong |
-| -5: The selected PCI input clock is wrong |
-| -6: Timing unity selection is wrong |
-| -7: Base timing selection is wrong |
-| -8: You can not used the 40MHz clock selection with |
-| this board |
-| -9: You can not used the 40MHz clock selection with |
-| this CHRONOS version |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnConfigInitChrono(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int ul_TimerValue = 0;
- unsigned int ul_TimingInterval = 0;
- unsigned int ul_RealTimingInterval = 0;
- double d_RealTimingInterval = 0;
- unsigned int dw_ModeArray[8] =
- { 0x01, 0x05, 0x00, 0x04, 0x02, 0x0E, 0x0A, 0x06 };
- unsigned char b_ModulNbr, b_ChronoMode, b_PCIInputClock, b_TimingUnit;
-
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_ChronoMode = (unsigned char) data[0];
- b_PCIInputClock = (unsigned char) data[1];
- b_TimingUnit = (unsigned char) data[2];
- ul_TimingInterval = (unsigned int) data[3];
- i_ReturnValue = insn->n;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if chronometer */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_CHRONOMETER) {
- /*****************************/
- /* Test the chronometer mode */
- /*****************************/
-
- if (b_ChronoMode <= 7) {
- /**************************/
- /* Test the PCI bus clock */
- /**************************/
-
- if ((b_PCIInputClock == APCI1710_30MHZ) ||
- (b_PCIInputClock == APCI1710_33MHZ) ||
- (b_PCIInputClock == APCI1710_40MHZ)) {
- /*************************/
- /* Test the timing unity */
- /*************************/
-
- if (b_TimingUnit <= 4) {
- /**********************************/
- /* Test the base timing selection */
- /**********************************/
-
- if (((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 66) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143165576UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143165UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 2UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 60) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130150240UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130150UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 2UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 50) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107374182UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107374UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 1UL))) {
- /**************************/
- /* Test the board version */
- /**************************/
-
- if (((b_PCIInputClock == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_PCIInputClock != APCI1710_40MHZ)) {
- /************************/
- /* Test the TOR version */
- /************************/
-
- if (((b_PCIInputClock == APCI1710_40MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131)) || (b_PCIInputClock != APCI1710_40MHZ)) {
- fpu_begin
- ();
-
- /****************************************/
- /* Calculate the timer 0 division fator */
- /****************************************/
-
- switch (b_TimingUnit) {
- /******/
- /* ns */
- /******/
-
- case 0:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- (unsigned int)
- (ul_TimingInterval
- *
- (0.001 * b_PCIInputClock));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (0.001 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (0.001 * (double)b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (0.001
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (0.001 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
- ul_RealTimingInterval
- =
- ul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
- if (b_PCIInputClock != APCI1710_40MHZ) {
- ul_TimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_TimerValue)
- *
- 0.99392);
- }
-
- break;
-
- /******/
- /* æs */
- /******/
-
- case 1:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- (unsigned int)
- (ul_TimingInterval
- *
- (1.0 * b_PCIInputClock));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (1.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (1.0 * (double)b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (
- (double)
- 1.0
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (1.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
- ul_RealTimingInterval
- =
- ul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
- if (b_PCIInputClock != APCI1710_40MHZ) {
- ul_TimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_TimerValue)
- *
- 0.99392);
- }
-
- break;
-
- /******/
- /* ms */
- /******/
-
- case 2:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- ul_TimingInterval
- *
- (1000
- *
- b_PCIInputClock);
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (1000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (1000.0 * (double)b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (1000.0
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (1000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
- ul_RealTimingInterval
- =
- ul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
- if (b_PCIInputClock != APCI1710_40MHZ) {
- ul_TimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_TimerValue)
- *
- 0.99392);
- }
-
- break;
-
- /*****/
- /* s */
- /*****/
-
- case 3:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- (unsigned int)
- (ul_TimingInterval
- *
- (1000000.0
- *
- b_PCIInputClock));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (1000000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (1000000.0
- *
- (double)
- b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (1000000.0
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (1000000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
- ul_RealTimingInterval
- =
- ul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
- if (b_PCIInputClock != APCI1710_40MHZ) {
- ul_TimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_TimerValue)
- *
- 0.99392);
- }
-
- break;
-
- /******/
- /* mn */
- /******/
-
- case 4:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- (unsigned int)
- (
- (ul_TimingInterval
- *
- 60)
- *
- (1000000.0
- *
- b_PCIInputClock));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)(ul_TimingInterval * 60.0) * (1000000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (1000000.0
- *
- (double)
- b_PCIInputClock))
- /
- 60;
- d_RealTimingInterval
- =
- (
- (double)
- ul_TimerValue
- /
- (0.001 * (double)b_PCIInputClock)) / 60.0;
-
- if ((double)(((double)ul_TimerValue / (1000000.0 * (double)b_PCIInputClock)) / 60.0) >= (double)((double)ul_RealTimingInterval + 0.5)) {
- ul_RealTimingInterval
- =
- ul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
- if (b_PCIInputClock != APCI1710_40MHZ) {
- ul_TimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_TimerValue)
- *
- 0.99392);
- }
-
- break;
- }
-
- fpu_end();
-
- /****************************/
- /* Save the PCI input clock */
- /****************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- b_PCIInputClock
- =
- b_PCIInputClock;
-
- /*************************/
- /* Save the timing unity */
- /*************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- b_TimingUnit
- =
- b_TimingUnit;
-
- /************************/
- /* Save the base timing */
- /************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- d_TimingInterval
- =
- d_RealTimingInterval;
-
- /****************************/
- /* Set the chronometer mode */
- /****************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- dw_ConfigReg
- =
- dw_ModeArray
- [b_ChronoMode];
-
- /***********************/
- /* Test if 40 MHz used */
- /***********************/
-
- if (b_PCIInputClock == APCI1710_40MHZ) {
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- dw_ConfigReg
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- dw_ConfigReg
- |
- 0x80;
- }
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].s_ChronoModuleInfo.dw_ConfigReg, devpriv->s_BoardInfos.ui_Address + 16 + (64 * b_ModulNbr));
-
- /***********************/
- /* Write timer 0 value */
- /***********************/
-
- outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr));
-
- /*********************/
- /* Chronometer init. */
- /*********************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- b_ChronoInit
- =
- 1;
- } else {
- /***********************************************/
- /* TOR version error for 40MHz clock selection */
- /***********************************************/
-
- DPRINTK("TOR version error for 40MHz clock selection\n");
- i_ReturnValue
- =
- -9;
- }
- } else {
- /**************************************************************/
- /* You can not use the 40MHz clock selection with this board */
- /**************************************************************/
-
- DPRINTK("You can not used the 40MHz clock selection with this board\n");
- i_ReturnValue =
- -8;
- }
- } else {
- /**********************************/
- /* Base timing selection is wrong */
- /**********************************/
-
- DPRINTK("Base timing selection is wrong\n");
- i_ReturnValue = -7;
- }
- } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
- else {
- /***********************************/
- /* Timing unity selection is wrong */
- /***********************************/
-
- DPRINTK("Timing unity selection is wrong\n");
- i_ReturnValue = -6;
- } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
- } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */
- else {
- /*****************************************/
- /* The selected PCI input clock is wrong */
- /*****************************************/
-
- DPRINTK("The selected PCI input clock is wrong\n");
- i_ReturnValue = -5;
- } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */
- } /* if (b_ChronoMode >= 0 && b_ChronoMode <= 7) */
- else {
- /***************************************/
- /* Chronometer mode selection is wrong */
- /***************************************/
-
- DPRINTK("Chronometer mode selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_ChronoMode >= 0 && b_ChronoMode <= 7) */
- } else {
- /******************************************/
- /* The module is not a Chronometer module */
- /******************************************/
-
- DPRINTK("The module is not a Chronometer module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
- data[0] = ul_RealTimingInterval;
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_EnableChrono |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_CycleMode, |
-| unsigned char_ b_InterruptEnable)
-int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev,
-struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Enable the chronometer from selected module |
-| (b_ModulNbr). You must calling the |
-| "i_APCI1710_InitChrono" function be for you call this |
-| function. |
-| If you enable the chronometer interrupt, the |
-| chronometer generate a interrupt after the stop signal.|
-| See function "i_APCI1710_SetBoardIntRoutineX" and the |
-| Interrupt mask description chapter from this manual. |
-| The b_CycleMode parameter determine if you will |
-| measured a single or more cycle.
-
-| Disable the chronometer from selected module |
-| (b_ModulNbr). If you disable the chronometer after a |
-| start signal occur and you restart the chronometer |
-| witch the " i_APCI1710_EnableChrono" function, if no |
-| stop signal occur this start signal is ignored.
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr CR_AREF(chanspec) : Selected module number (0 to 3) |
- data[0] ENABle/Disable chrono
-| unsigned char_ b_CycleMode : Selected the chronometer |
-| data[1] acquisition mode |
-| unsigned char_ b_InterruptEnable : Enable or disable the |
-| data[2] chronometer interrupt. |
-| APCI1710_ENABLE: |
-| Enable the chronometer |
-| interrupt |
-| APCI1710_DISABLE: |
-| Disable the chronometer |
-| interrupt |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a Chronometer module |
-| -4: Chronometer not initialised see function |
-| "i_APCI1710_InitChrono" |
-| -5: Chronometer acquisition mode cycle is wrong |
-| -6: Interrupt parameter is wrong |
-| -7: Interrupt function not initialised. |
-| See function "i_APCI1710_SetBoardIntRoutineX"
- -8: data[0] wrong input |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned char b_ModulNbr, b_CycleMode, b_InterruptEnable, b_Action;
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_Action = (unsigned char) data[0];
- b_CycleMode = (unsigned char) data[1];
- b_InterruptEnable = (unsigned char) data[2];
- i_ReturnValue = insn->n;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if chronometer */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_CHRONOMETER) {
- /***********************************/
- /* Test if chronometer initialised */
- /***********************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.b_ChronoInit == 1) {
-
- switch (b_Action) {
-
- case APCI1710_ENABLE:
-
- /*********************************/
- /* Test the cycle mode parameter */
- /*********************************/
-
- if ((b_CycleMode == APCI1710_SINGLE)
- || (b_CycleMode ==
- APCI1710_CONTINUOUS)) {
- /***************************/
- /* Test the interrupt flag */
- /***************************/
-
- if ((b_InterruptEnable ==
- APCI1710_ENABLE)
- || (b_InterruptEnable ==
- APCI1710_DISABLE))
- {
-
- /***************************/
- /* Save the interrupt flag */
- /***************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- b_InterruptMask
- =
- b_InterruptEnable;
-
- /***********************/
- /* Save the cycle mode */
- /***********************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- b_CycleMode =
- b_CycleMode;
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- dw_ConfigReg =
- (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- dw_ConfigReg &
- 0x8F) | ((1 &
- b_InterruptEnable)
- << 5) | ((1 &
- b_CycleMode)
- << 6) | 0x10;
-
- /*****************************/
- /* Test if interrupt enabled */
- /*****************************/
-
- if (b_InterruptEnable ==
- APCI1710_ENABLE)
- {
- /****************************/
- /* Clear the interrupt flag */
- /****************************/
-
- outl(devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- dw_ConfigReg,
- devpriv->
- s_BoardInfos.
- ui_Address
- + 32 +
- (64 * b_ModulNbr));
- devpriv->tsk_Current = current; /* Save the current process task structure */
- }
-
- /***********************************/
- /* Enable or disable the interrupt */
- /* Enable the chronometer */
- /***********************************/
-
- outl(devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- dw_ConfigReg,
- devpriv->
- s_BoardInfos.
- ui_Address +
- 16 +
- (64 * b_ModulNbr));
-
- /*************************/
- /* Clear status register */
- /*************************/
-
- outl(0, devpriv->
- s_BoardInfos.
- ui_Address +
- 36 +
- (64 * b_ModulNbr));
-
- } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */
- else {
- /********************************/
- /* Interrupt parameter is wrong */
- /********************************/
-
- DPRINTK("Interrupt parameter is wrong\n");
- i_ReturnValue = -6;
- } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */
- } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */
- else {
- /***********************************************/
- /* Chronometer acquisition mode cycle is wrong */
- /***********************************************/
-
- DPRINTK("Chronometer acquisition mode cycle is wrong\n");
- i_ReturnValue = -5;
- } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */
- break;
-
- case APCI1710_DISABLE:
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.
- b_InterruptMask = 0;
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.
- dw_ConfigReg =
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.
- dw_ConfigReg & 0x2F;
-
- /***************************/
- /* Disable the interrupt */
- /* Disable the chronometer */
- /***************************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.dw_ConfigReg,
- devpriv->s_BoardInfos.
- ui_Address + 16 +
- (64 * b_ModulNbr));
-
- /***************************/
- /* Test if continuous mode */
- /***************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.
- b_CycleMode ==
- APCI1710_CONTINUOUS) {
- /*************************/
- /* Clear status register */
- /*************************/
-
- outl(0, devpriv->s_BoardInfos.
- ui_Address + 36 +
- (64 * b_ModulNbr));
- }
- break;
-
- default:
- DPRINTK("Inputs wrong! Enable or Disable chrono\n");
- i_ReturnValue = -8;
- } /* switch ENABLE/DISABLE */
- } else {
- /*******************************/
- /* Chronometer not initialised */
- /*******************************/
-
- DPRINTK("Chronometer not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /******************************************/
- /* The module is not a Chronometer module */
- /******************************************/
-
- DPRINTK("The module is not a Chronometer module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetChronoProgressStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char *_ pb_ChronoStatus) |
-+----------------------------------------------------------------------------+
-| Task : Return the chronometer status (pb_ChronoStatus) from |
-| selected chronometer module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pb_ChronoStatus : Return the chronometer |
-| status. |
-| 0 : Measurement not started.|
-| No start signal occur. |
-| 1 : Measurement started. |
-| A start signal occur. |
-| 2 : Measurement stopped. |
-| A stop signal occur. |
-| The measurement is |
-| terminate. |
-| 3: A overflow occur. You |
-| must change the base |
-| timing witch the |
-| function |
-| "i_APCI1710_InitChrono" |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a Chronometer module |
-| -4: Chronometer not initialised see function |
-| "i_APCI1710_InitChrono" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetChronoProgressStatus(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char *pb_ChronoStatus)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_Status;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if chronometer */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_CHRONOMETER) {
- /***********************************/
- /* Test if chronometer initialised */
- /***********************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.b_ChronoInit == 1) {
-
- dw_Status = inl(devpriv->s_BoardInfos.
- ui_Address + 8 + (64 * b_ModulNbr));
-
- /********************/
- /* Test if overflow */
- /********************/
-
- if ((dw_Status & 8) == 8) {
- /******************/
- /* Overflow occur */
- /******************/
-
- *pb_ChronoStatus = 3;
- } /* if ((dw_Status & 8) == 8) */
- else {
- /*******************************/
- /* Test if measurement stopped */
- /*******************************/
-
- if ((dw_Status & 2) == 2) {
- /***********************/
- /* A stop signal occur */
- /***********************/
-
- *pb_ChronoStatus = 2;
- } /* if ((dw_Status & 2) == 2) */
- else {
- /*******************************/
- /* Test if measurement started */
- /*******************************/
-
- if ((dw_Status & 1) == 1) {
- /************************/
- /* A start signal occur */
- /************************/
-
- *pb_ChronoStatus = 1;
- } /* if ((dw_Status & 1) == 1) */
- else {
- /***************************/
- /* Measurement not started */
- /***************************/
-
- *pb_ChronoStatus = 0;
- } /* if ((dw_Status & 1) == 1) */
- } /* if ((dw_Status & 2) == 2) */
- } /* if ((dw_Status & 8) == 8) */
- } else {
- /*******************************/
- /* Chronometer not initialised */
- /*******************************/
- DPRINTK("Chronometer not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /******************************************/
- /* The module is not a Chronometer module */
- /******************************************/
- DPRINTK("The module is not a Chronometer module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadChronoValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned int_ ui_TimeOut, |
-| unsigned char *_ pb_ChronoStatus, |
-| PULONG_ pul_ChronoValue) |
-+----------------------------------------------------------------------------+
-| Task : Return the chronometer status (pb_ChronoStatus) and the|
-| timing value (pul_ChronoValue) after a stop signal |
-| occur from selected chronometer module (b_ModulNbr). |
-| This function are only avaible if you have disabled |
-| the interrupt functionality. See function |
-| "i_APCI1710_EnableChrono" and the Interrupt mask |
-| description chapter. |
-| You can test the chronometer status witch the |
-| "i_APCI1710_GetChronoProgressStatus" function. |
-| |
-| The returned value from pul_ChronoValue parameter is |
-| not real measured timing. |
-| You must used the "i_APCI1710_ConvertChronoValue" |
-| function or make this operation for calculate the |
-| timing: |
-| |
-| Timing = pul_ChronoValue * pul_RealTimingInterval. |
-| |
-| pul_RealTimingInterval is the returned parameter from |
-| "i_APCI1710_InitChrono" function and the time unity is |
-| the b_TimingUnit from "i_APCI1710_InitChrono" function|
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pb_ChronoStatus : Return the chronometer |
-| status. |
-| 0 : Measurement not started.|
-| No start signal occur. |
-| 1 : Measurement started. |
-| A start signal occur. |
-| 2 : Measurement stopped. |
-| A stop signal occur. |
-| The measurement is |
-| terminate. |
-| 3: A overflow occur. You |
-| must change the base |
-| timing witch the |
-| function |
-| "i_APCI1710_InitChrono" |
-| unsigned int * pul_ChronoValue : Chronometer timing value. |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a Chronometer module |
-| -4: Chronometer not initialised see function |
-| "i_APCI1710_InitChrono" |
-| -5: Timeout parameter is wrong (0 to 65535) |
-| -6: Interrupt routine installed. You can not read |
-| directly the chronometer measured timing. |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ReadChronoValue(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned int ui_TimeOut,
- unsigned char *pb_ChronoStatus,
- unsigned int *pul_ChronoValue)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_Status;
- unsigned int dw_TimeOut = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if chronometer */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_CHRONOMETER) {
- /***********************************/
- /* Test if chronometer initialised */
- /***********************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.b_ChronoInit == 1) {
- /*****************************/
- /* Test the timout parameter */
- /*****************************/
-
- if (ui_TimeOut <= 65535UL) {
-
- for (;;) {
- /*******************/
- /* Read the status */
- /*******************/
-
- dw_Status =
- inl(devpriv->
- s_BoardInfos.
- ui_Address + 8 +
- (64 * b_ModulNbr));
-
- /********************/
- /* Test if overflow */
- /********************/
-
- if ((dw_Status & 8) == 8) {
- /******************/
- /* Overflow occur */
- /******************/
-
- *pb_ChronoStatus = 3;
-
- /***************************/
- /* Test if continuous mode */
- /***************************/
-
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- b_CycleMode ==
- APCI1710_CONTINUOUS)
- {
- /*************************/
- /* Clear status register */
- /*************************/
-
- outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr));
- }
-
- break;
- } /* if ((dw_Status & 8) == 8) */
- else {
- /*******************************/
- /* Test if measurement stopped */
- /*******************************/
-
- if ((dw_Status & 2) ==
- 2) {
- /***********************/
- /* A stop signal occur */
- /***********************/
-
- *pb_ChronoStatus
- = 2;
-
- /***************************/
- /* Test if continnous mode */
- /***************************/
-
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_ChronoModuleInfo.
- b_CycleMode
- ==
- APCI1710_CONTINUOUS)
- {
- /*************************/
- /* Clear status register */
- /*************************/
-
- outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr));
- }
- break;
- } /* if ((dw_Status & 2) == 2) */
- else {
- /*******************************/
- /* Test if measurement started */
- /*******************************/
-
- if ((dw_Status & 1) == 1) {
- /************************/
- /* A start signal occur */
- /************************/
-
- *pb_ChronoStatus
- =
- 1;
- } /* if ((dw_Status & 1) == 1) */
- else {
- /***************************/
- /* Measurement not started */
- /***************************/
-
- *pb_ChronoStatus
- =
- 0;
- } /* if ((dw_Status & 1) == 1) */
- } /* if ((dw_Status & 2) == 2) */
- } /* if ((dw_Status & 8) == 8) */
-
- if (dw_TimeOut == ui_TimeOut) {
- /*****************/
- /* Timeout occur */
- /*****************/
-
- break;
- } else {
- /*************************/
- /* Increment the timeout */
- /*************************/
-
- dw_TimeOut =
- dw_TimeOut + 1;
- mdelay(1000);
-
- }
- } /* for (;;) */
-
- /*****************************/
- /* Test if stop signal occur */
- /*****************************/
-
- if (*pb_ChronoStatus == 2) {
- /**********************************/
- /* Read the measured timing value */
- /**********************************/
-
- *pul_ChronoValue =
- inl(devpriv->
- s_BoardInfos.
- ui_Address + 4 +
- (64 * b_ModulNbr));
-
- if (*pul_ChronoValue != 0) {
- *pul_ChronoValue =
- *pul_ChronoValue
- - 1;
- }
- } else {
- /*************************/
- /* Test if timeout occur */
- /*************************/
-
- if ((*pb_ChronoStatus != 3)
- && (dw_TimeOut ==
- ui_TimeOut)
- && (ui_TimeOut != 0)) {
- /*****************/
- /* Timeout occur */
- /*****************/
-
- *pb_ChronoStatus = 4;
- }
- }
-
- } else {
- /******************************/
- /* Timeout parameter is wrong */
- /******************************/
- DPRINTK("Timeout parameter is wrong\n");
- i_ReturnValue = -5;
- }
- } else {
- /*******************************/
- /* Chronometer not initialised */
- /*******************************/
- DPRINTK("Chronometer not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /******************************************/
- /* The module is not a Chronometer module */
- /******************************************/
- DPRINTK("The module is not a Chronometer module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ConvertChronoValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| ULONG_ ul_ChronoValue, |
-| PULONG_ pul_Hour, |
-| unsigned char *_ pb_Minute, |
-| unsigned char *_ pb_Second, |
-| unsigned int *_ pui_MilliSecond, |
-| unsigned int *_ pui_MicroSecond, |
-| unsigned int *_ pui_NanoSecond) |
-+----------------------------------------------------------------------------+
-| Task : Convert the chronometer measured timing |
-| (ul_ChronoValue) in to h, mn, s, ms, µs, ns. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3)|
-| ULONG_ ul_ChronoValue : Measured chronometer timing |
-| value. |
-| See"i_APCI1710_ReadChronoValue"|
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_Hour : Chronometer timing hour |
-| unsigned char *_ pb_Minute : Chronometer timing minute |
-| unsigned char *_ pb_Second : Chronometer timing second |
-| unsigned int *_ pui_MilliSecond : Chronometer timing mini |
-| second |
-| unsigned int *_ pui_MicroSecond : Chronometer timing micro |
-| second |
-| unsigned int *_ pui_NanoSecond : Chronometer timing nano |
-| second |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a Chronometer module |
-| -4: Chronometer not initialised see function |
-| "i_APCI1710_InitChrono" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ConvertChronoValue(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned int ul_ChronoValue,
- unsigned int *pul_Hour,
- unsigned char *pb_Minute,
- unsigned char *pb_Second,
- unsigned int *pui_MilliSecond,
- unsigned int *pui_MicroSecond,
- unsigned int *pui_NanoSecond)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- double d_Hour;
- double d_Minute;
- double d_Second;
- double d_MilliSecond;
- double d_MicroSecond;
- double d_NanoSecond;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if chronometer */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_CHRONOMETER) {
- /***********************************/
- /* Test if chronometer initialised */
- /***********************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.b_ChronoInit == 1) {
- fpu_begin();
-
- d_Hour = (double)ul_ChronoValue *(double)
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.d_TimingInterval;
-
- switch (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.b_TimingUnit) {
- case 0:
- d_Hour = d_Hour / (double)1000.0;
-
- case 1:
- d_Hour = d_Hour / (double)1000.0;
-
- case 2:
- d_Hour = d_Hour / (double)1000.0;
-
- case 3:
- d_Hour = d_Hour / (double)60.0;
-
- case 4:
- /**********************/
- /* Calculate the hour */
- /**********************/
-
- d_Hour = d_Hour / (double)60.0;
- *pul_Hour = (unsigned int) d_Hour;
-
- /************************/
- /* Calculate the minute */
- /************************/
-
- d_Minute = d_Hour - *pul_Hour;
- d_Minute = d_Minute * 60;
- *pb_Minute = (unsigned char) d_Minute;
-
- /************************/
- /* Calculate the second */
- /************************/
-
- d_Second = d_Minute - *pb_Minute;
- d_Second = d_Second * 60;
- *pb_Second = (unsigned char) d_Second;
-
- /*****************************/
- /* Calculate the mini second */
- /*****************************/
-
- d_MilliSecond = d_Second - *pb_Second;
- d_MilliSecond = d_MilliSecond * 1000;
- *pui_MilliSecond = (unsigned int) d_MilliSecond;
-
- /******************************/
- /* Calculate the micro second */
- /******************************/
-
- d_MicroSecond =
- d_MilliSecond -
- *pui_MilliSecond;
- d_MicroSecond = d_MicroSecond * 1000;
- *pui_MicroSecond = (unsigned int) d_MicroSecond;
-
- /******************************/
- /* Calculate the micro second */
- /******************************/
-
- d_NanoSecond =
- d_MicroSecond -
- *pui_MicroSecond;
- d_NanoSecond = d_NanoSecond * 1000;
- *pui_NanoSecond = (unsigned int) d_NanoSecond;
- break;
- }
-
- fpu_end();
- } else {
- /*******************************/
- /* Chronometer not initialised */
- /*******************************/
- DPRINTK("Chronometer not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /******************************************/
- /* The module is not a Chronometer module */
- /******************************************/
- DPRINTK("The module is not a Chronometer module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name :INT i_APCI1710_InsnReadChrono(struct comedi_device *dev,struct comedi_subdevice *s,
-struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Read functions for Timer |
-+----------------------------------------------------------------------------+
-| Input Parameters :
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value :
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnReadChrono(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- unsigned char b_ReadType;
- int i_ReturnValue = insn->n;
-
- b_ReadType = CR_CHAN(insn->chanspec);
-
- switch (b_ReadType) {
- case APCI1710_CHRONO_PROGRESS_STATUS:
- i_ReturnValue = i_APCI1710_GetChronoProgressStatus(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
- break;
-
- case APCI1710_CHRONO_READVALUE:
- i_ReturnValue = i_APCI1710_ReadChronoValue(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned int) insn->unused[0],
- (unsigned char *) &data[0], (unsigned int *) &data[1]);
- break;
-
- case APCI1710_CHRONO_CONVERTVALUE:
- i_ReturnValue = i_APCI1710_ConvertChronoValue(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned int) insn->unused[0],
- (unsigned int *) &data[0],
- (unsigned char *) &data[1],
- (unsigned char *) &data[2],
- (unsigned int *) &data[3],
- (unsigned int *) &data[4], (unsigned int *) &data[5]);
- break;
-
- case APCI1710_CHRONO_READINTERRUPT:
- printk("In Chrono Read Interrupt\n");
-
- data[0] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].b_OldModuleMask;
- data[1] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].ul_OldInterruptMask;
- data[2] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
- /**************************/
- /* Increment the read FIFO */
- /***************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Read = (devpriv->
- s_InterruptParameters.
- ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
- break;
-
- default:
- printk("ReadType Parameter wrong\n");
- }
-
- if (i_ReturnValue >= 0)
- i_ReturnValue = insn->n;
- return i_ReturnValue;
-
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev,struct comedi_subdevice *s,
- struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Sets the output witch has been passed with the |
-| parameter b_Channel. Setting an output means setting an|
-| output high. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3)|
-| unsigned char_ b_OutputChannel : Selection from digital output |
-| CR_CHAN() channel (0 to 2) |
-| 0 : Channel H |
-| 1 : Channel A |
-| 2 : Channel B |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a Chronometer module |
-| -4: The selected digital output is wrong |
-| -5: Chronometer not initialised see function |
-| "i_APCI1710_InitChrono" |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_SetChronoChlOff |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_OutputChannel) |
-+----------------------------------------------------------------------------+
-| Task : Resets the output witch has been passed with the |
-| parameter b_Channel. Resetting an output means setting |
-| an output low. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710
- data[0] : Chl ON, Chl OFF , Chl Read , Port Read
-
-| unsigned char_ b_ModulNbr CR_AREF : Selected module number (0 to 3)|
-| unsigned char_ b_OutputChannel CR_CHAN : Selection from digital output |
-| channel (0 to 2) |
-| 0 : Channel H |
-| 1 : Channel A |
-| 2 : Channel B |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a Chronometer module |
-| -4: The selected digital output is wrong |
-| -5: Chronometer not initialised see function |
-| "i_APCI1710_InitChrono" |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadChronoChlValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_InputChannel, |
-| unsigned char *_ pb_ChannelStatus) |
-+----------------------------------------------------------------------------+
-| Task : Return the status from selected digital input |
-| (b_InputChannel) from selected chronometer |
-| module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3)|
-| unsigned char_ b_InputChannel : Selection from digital input |
-| channel (0 to 2) |
-| CR_CHAN() 0 : Channel E |
-| 1 : Channel F |
-| 2 : Channel G |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_ChannelStatus : Digital input channel status.|
-| data[0] 0 : Channel is not active |
-| 1 : Channel is active |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a Chronometer module |
-| -4: The selected digital input is wrong |
-| -5: Chronometer not initialised see function |
-| "i_APCI1710_InitChrono" |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadChronoPortValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char *_ pb_PortValue) |
-+----------------------------------------------------------------------------+
-| Task : Return the status from digital inputs port from |
-| selected (b_ModulNbr) chronometer module. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3)|
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_PortValue : Digital inputs port status.
-| data[0]
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a Chronometer module |
-| -4: Chronometer not initialised see function |
-| "i_APCI1710_InitChrono" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned char b_ModulNbr, b_OutputChannel, b_InputChannel, b_IOType;
- unsigned int dw_Status;
- unsigned char *pb_ChannelStatus;
- unsigned char *pb_PortValue;
-
- b_ModulNbr = CR_AREF(insn->chanspec);
- i_ReturnValue = insn->n;
- b_IOType = (unsigned char) data[0];
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if chronometer */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_CHRONOMETER) {
- /***********************************/
- /* Test if chronometer initialised */
- /***********************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_ChronoModuleInfo.b_ChronoInit == 1) {
- /***********************************/
- /* Test the digital output channel */
- /***********************************/
- switch (b_IOType) {
-
- case APCI1710_CHRONO_SET_CHANNELOFF:
-
- b_OutputChannel =
- (unsigned char) CR_CHAN(insn->chanspec);
- if (b_OutputChannel <= 2) {
-
- outl(0, devpriv->s_BoardInfos.
- ui_Address + 20 +
- (b_OutputChannel * 4) +
- (64 * b_ModulNbr));
- } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */
- else {
- /****************************************/
- /* The selected digital output is wrong */
- /****************************************/
-
- DPRINTK("The selected digital output is wrong\n");
- i_ReturnValue = -4;
-
- } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */
-
- break;
-
- case APCI1710_CHRONO_SET_CHANNELON:
-
- b_OutputChannel =
- (unsigned char) CR_CHAN(insn->chanspec);
- if (b_OutputChannel <= 2) {
-
- outl(1, devpriv->s_BoardInfos.
- ui_Address + 20 +
- (b_OutputChannel * 4) +
- (64 * b_ModulNbr));
- } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */
- else {
- /****************************************/
- /* The selected digital output is wrong */
- /****************************************/
-
- DPRINTK("The selected digital output is wrong\n");
- i_ReturnValue = -4;
-
- } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */
-
- break;
-
- case APCI1710_CHRONO_READ_CHANNEL:
- /**********************************/
- /* Test the digital input channel */
- /**********************************/
- pb_ChannelStatus = (unsigned char *) &data[0];
- b_InputChannel =
- (unsigned char) CR_CHAN(insn->chanspec);
-
- if (b_InputChannel <= 2) {
-
- dw_Status =
- inl(devpriv->
- s_BoardInfos.
- ui_Address + 12 +
- (64 * b_ModulNbr));
-
- *pb_ChannelStatus =
- (unsigned char) (((dw_Status >>
- b_InputChannel)
- & 1) ^ 1);
- } /* if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) */
- else {
- /***************************************/
- /* The selected digital input is wrong */
- /***************************************/
-
- DPRINTK("The selected digital input is wrong\n");
- i_ReturnValue = -4;
- } /* if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) */
-
- break;
-
- case APCI1710_CHRONO_READ_PORT:
-
- pb_PortValue = (unsigned char *) &data[0];
-
- dw_Status =
- inl(devpriv->s_BoardInfos.
- ui_Address + 12 +
- (64 * b_ModulNbr));
-
- *pb_PortValue =
- (unsigned char) ((dw_Status & 0x7) ^ 7);
- break;
- }
- } else {
- /*******************************/
- /* Chronometer not initialised */
- /*******************************/
-
- DPRINTK("Chronometer not initialised\n");
- i_ReturnValue = -5;
- }
- } else {
- /******************************************/
- /* The module is not a Chronometer module */
- /******************************************/
-
- DPRINTK("The module is not a Chronometer module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c
deleted file mode 100644
index 27de18e7989..00000000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c
+++ /dev/null
@@ -1,1037 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-----------------------------------------------------------------------+
- | Project : API APCI1710 | Compiler : gcc |
- | Module name : DIG_IO.C | Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-----------------------------------------------------------------------+
- | Description : APCI-1710 digital I/O module |
- | |
- | |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +-----------------------------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | 16/06/98 | S. Weber | Digital input / output implementation |
- |----------|-----------|------------------------------------------------|
- | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 |
- | | | available |
- +-----------------------------------------------------------------------+
- | | | |
- | | | |
- +-----------------------------------------------------------------------+
-*/
-
-/* Digital Output ON or OFF */
-#define APCI1710_ON 1
-#define APCI1710_OFF 0
-
-/* Digital I/O */
-#define APCI1710_INPUT 0
-#define APCI1710_OUTPUT 1
-
-#define APCI1710_DIGIO_MEMORYONOFF 0x10
-#define APCI1710_DIGIO_INIT 0x11
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, |
-| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)|
-+----------------------------------------------------------------------------+
-| Task : Configure the digital I/O operating mode from selected |
-| module (b_ModulNbr). You must calling this function be|
-| for you call any other function witch access of digital|
-| I/O. |
-+----------------------------------------------------------------------------+
-| Input Parameters : |
-| unsigned char_ b_ModulNbr data[0]: Module number to |
-| configure (0 to 3) |
-| unsigned char_ b_ChannelAMode data[1] : Channel A mode selection |
-| 0 : Channel used for digital |
-| input |
-| 1 : Channel used for digital |
-| output |
-| unsigned char_ b_ChannelBMode data[2] : Channel B mode selection |
-| 0 : Channel used for digital |
-| input |
-| 1 : Channel used for digital |
-| output |
- data[0] memory on/off
-Activates and deactivates the digital output memory.
- After having |
-| called up this function with memory on,the output you have previously|
-| activated with the function are not reset
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a digital I/O module |
-| -4: Bi-directional channel A configuration error |
-| -5: Bi-directional channel B configuration error |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- unsigned char b_ModulNbr, b_ChannelAMode, b_ChannelBMode;
- unsigned char b_MemoryOnOff, b_ConfigType;
- int i_ReturnValue = 0;
- unsigned int dw_WriteConfig = 0;
-
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_ConfigType = (unsigned char) data[0]; /* Memory or Init */
- b_ChannelAMode = (unsigned char) data[1];
- b_ChannelBMode = (unsigned char) data[2];
- b_MemoryOnOff = (unsigned char) data[1]; /* if memory operation */
- i_ReturnValue = insn->n;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr >= 4) {
- DPRINTK("Module Number invalid\n");
- i_ReturnValue = -2;
- return i_ReturnValue;
- }
- switch (b_ConfigType) {
- case APCI1710_DIGIO_MEMORYONOFF:
-
- if (b_MemoryOnOff) /* If Memory ON */
- {
- /****************************/
- /* Set the output memory on */
- /****************************/
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.b_OutputMemoryEnabled = 1;
-
- /***************************/
- /* Clear the output memory */
- /***************************/
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.dw_OutputMemory = 0;
- } else /* If memory off */
- {
- /*****************************/
- /* Set the output memory off */
- /*****************************/
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.b_OutputMemoryEnabled = 0;
- }
- break;
-
- case APCI1710_DIGIO_INIT:
-
- /*******************************/
- /* Test if digital I/O counter */
- /*******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
-
- /***************************************************/
- /* Test the bi-directional channel A configuration */
- /***************************************************/
-
- if ((b_ChannelAMode == 0) || (b_ChannelAMode == 1)) {
- /***************************************************/
- /* Test the bi-directional channel B configuration */
- /***************************************************/
-
- if ((b_ChannelBMode == 0)
- || (b_ChannelBMode == 1)) {
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.b_DigitalInit =
- 1;
-
- /********************************/
- /* Save channel A configuration */
- /********************************/
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.
- b_ChannelAMode = b_ChannelAMode;
-
- /********************************/
- /* Save channel B configuration */
- /********************************/
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.
- b_ChannelBMode = b_ChannelBMode;
-
- /*****************************************/
- /* Set the channel A and B configuration */
- /*****************************************/
-
- dw_WriteConfig =
- (unsigned int) (b_ChannelAMode |
- (b_ChannelBMode * 2));
-
- /***************************/
- /* Write the configuration */
- /***************************/
-
- outl(dw_WriteConfig,
- devpriv->s_BoardInfos.
- ui_Address + 4 +
- (64 * b_ModulNbr));
-
- } else {
- /************************************************/
- /* Bi-directional channel B configuration error */
- /************************************************/
- DPRINTK("Bi-directional channel B configuration error\n");
- i_ReturnValue = -5;
- }
-
- } else {
- /************************************************/
- /* Bi-directional channel A configuration error */
- /************************************************/
- DPRINTK("Bi-directional channel A configuration error\n");
- i_ReturnValue = -4;
-
- }
-
- } else {
- /******************************************/
- /* The module is not a digital I/O module */
- /******************************************/
- DPRINTK("The module is not a digital I/O module\n");
- i_ReturnValue = -3;
- }
- } /* end of Switch */
- printk("Return Value %d\n", i_ReturnValue);
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| INPUT FUNCTIONS |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-
-|INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev,comedi_subdevice
-*s, struct comedi_insn *insn,unsigned int *data)
-
-+----------------------------------------------------------------------------+
-| Task : Read the status from selected digital I/O digital input|
-| (b_InputChannel) |
-+----------------------------------------------------------------------------|
-
-
-|
-| unsigned char_ b_ModulNbr CR_AREF(chanspec) : Selected module number |
-| (0 to 3) |
-| unsigned char_ b_InputChannel CR_CHAN(chanspec) : Selection from digital |
-| input ( 0 to 6) |
-| 0 : Channel C |
-| 1 : Channel D |
-| 2 : Channel E |
-| 3 : Channel F |
-| 4 : Channel G |
-| 5 : Channel A |
-| 6 : Channel B
-
-
- |
-+----------------------------------------------------------------------------+
-| Output Parameters : data[0] : Digital input channel |
-| status |
-| 0 : Channle is not active|
-| 1 : Channle is active |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a digital I/O module |
-| -4: The selected digital I/O digital input is wrong |
-| -5: Digital I/O not initialised |
-| -6: The digital channel A is used for output |
-| -7: The digital channel B is used for output |
-+----------------------------------------------------------------------------+
-*/
-
-/* _INT_ i_APCI1710_ReadDigitalIOChlValue (unsigned char_ b_BoardHandle, */
-/*
-* unsigned char_ b_ModulNbr, unsigned char_ b_InputChannel,
-* unsigned char *_ pb_ChannelStatus)
-*/
-static int i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg;
- unsigned char b_ModulNbr, b_InputChannel;
- unsigned char *pb_ChannelStatus;
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec);
- data[0] = 0;
- pb_ChannelStatus = (unsigned char *) &data[0];
- i_ReturnValue = insn->n;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if digital I/O counter */
- /*******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
- /******************************************/
- /* Test the digital imnput channel number */
- /******************************************/
-
- if (b_InputChannel <= 6) {
- /**********************************************/
- /* Test if the digital I/O module initialised */
- /**********************************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.b_DigitalInit == 1) {
- /**********************************/
- /* Test if channel A or channel B */
- /**********************************/
-
- if (b_InputChannel > 4) {
- /*********************/
- /* Test if channel A */
- /*********************/
-
- if (b_InputChannel == 5) {
- /***************************/
- /* Test the channel A mode */
- /***************************/
-
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- b_ChannelAMode
- != 0) {
- /********************************************/
- /* The digital channel A is used for output */
- /********************************************/
-
- i_ReturnValue =
- -6;
- }
- } /* if (b_InputChannel == 5) */
- else {
- /***************************/
- /* Test the channel B mode */
- /***************************/
-
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- b_ChannelBMode
- != 0) {
- /********************************************/
- /* The digital channel B is used for output */
- /********************************************/
-
- i_ReturnValue =
- -7;
- }
- } /* if (b_InputChannel == 5) */
- } /* if (b_InputChannel > 4) */
-
- /***********************/
- /* Test if error occur */
- /***********************/
-
- if (i_ReturnValue >= 0) {
- /**************************/
- /* Read all digital input */
- /**************************/
-
-/*
-* INPDW (ps_APCI1710Variable-> s_Board [b_BoardHandle].
-* s_BoardInfos. ui_Address + (64 * b_ModulNbr), &dw_StatusReg);
-*/
-
- dw_StatusReg =
- inl(devpriv->
- s_BoardInfos.
- ui_Address +
- (64 * b_ModulNbr));
-
- *pb_ChannelStatus =
- (unsigned char) ((dw_StatusReg ^
- 0x1C) >>
- b_InputChannel) & 1;
-
- } /* if (i_ReturnValue == 0) */
- } else {
- /*******************************/
- /* Digital I/O not initialised */
- /*******************************/
- DPRINTK("Digital I/O not initialised\n");
- i_ReturnValue = -5;
- }
- } else {
- /********************************/
- /* Selected digital input error */
- /********************************/
- DPRINTK("Selected digital input error\n");
- i_ReturnValue = -4;
- }
- } else {
- /******************************************/
- /* The module is not a digital I/O module */
- /******************************************/
- DPRINTK("The module is not a digital I/O module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| OUTPUT FUNCTIONS |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1710_InsnWriteDigitalIOChlOnOff(comedi_device
-|*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)
-
-+----------------------------------------------------------------------------+
-| Task : Sets or resets the output witch has been passed with the |
-| parameter b_Channel. Setting an output means setting |
-| an ouput high. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr (aref ) : Selected module number (0 to 3)|
-| unsigned char_ b_OutputChannel (CR_CHAN) : Selection from digital output |
-| channel (0 to 2) |
-| 0 : Channel H |
-| 1 : Channel A |
-| 2 : Channel B |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a digital I/O module |
-| -4: The selected digital output is wrong |
-| -5: digital I/O not initialised see function |
-| " i_APCI1710_InitDigitalIO" |
-| -6: The digital channel A is used for input |
-| -7: The digital channel B is used for input
- -8: Digital Output Memory OFF. |
-| Use previously the function |
-| "i_APCI1710_SetDigitalIOMemoryOn". |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-* _INT_ i_APCI1710_SetDigitalIOChlOn (unsigned char_ b_BoardHandle,
-* unsigned char_ b_ModulNbr, unsigned char_ b_OutputChannel)
-*/
-static int i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_WriteValue = 0;
- unsigned char b_ModulNbr, b_OutputChannel;
- i_ReturnValue = insn->n;
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_OutputChannel = CR_CHAN(insn->chanspec);
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if digital I/O counter */
- /*******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
- /**********************************************/
- /* Test if the digital I/O module initialised */
- /**********************************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.b_DigitalInit == 1) {
- /******************************************/
- /* Test the digital output channel number */
- /******************************************/
-
- switch (b_OutputChannel) {
- /*************/
- /* Channel H */
- /*************/
-
- case 0:
- break;
-
- /*************/
- /* Channel A */
- /*************/
-
- case 1:
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.
- b_ChannelAMode != 1) {
- /*******************************************/
- /* The digital channel A is used for input */
- /*******************************************/
-
- i_ReturnValue = -6;
- }
- break;
-
- /*************/
- /* Channel B */
- /*************/
-
- case 2:
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.
- b_ChannelBMode != 1) {
- /*******************************************/
- /* The digital channel B is used for input */
- /*******************************************/
-
- i_ReturnValue = -7;
- }
- break;
-
- default:
- /****************************************/
- /* The selected digital output is wrong */
- /****************************************/
-
- i_ReturnValue = -4;
- break;
- }
-
- /***********************/
- /* Test if error occur */
- /***********************/
-
- if (i_ReturnValue >= 0) {
-
- /*********************************/
- /* Test if set channel ON */
- /*********************************/
- if (data[0]) {
- /*********************************/
- /* Test if output memory enabled */
- /*********************************/
-
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- b_OutputMemoryEnabled ==
- 1) {
- dw_WriteValue =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- dw_OutputMemory
- | (1 <<
- b_OutputChannel);
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- dw_OutputMemory
- = dw_WriteValue;
- } else {
- dw_WriteValue =
- 1 <<
- b_OutputChannel;
- }
- } /* set channel off */
- else {
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- b_OutputMemoryEnabled ==
- 1) {
- dw_WriteValue =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- dw_OutputMemory
- & (0xFFFFFFFFUL
- -
- (1 << b_OutputChannel));
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- dw_OutputMemory
- = dw_WriteValue;
- } else {
- /*****************************/
- /* Digital Output Memory OFF */
- /*****************************/
- /* +Use previously the function "i_APCI1710_SetDigitalIOMemoryOn" */
- i_ReturnValue = -8;
- }
-
- }
- /*******************/
- /* Write the value */
- /*******************/
-
- /* OUTPDW (ps_APCI1710Variable->
- * s_Board [b_BoardHandle].
- * s_BoardInfos. ui_Address + (64 * b_ModulNbr),
- * dw_WriteValue);
- */
-*/
- outl(dw_WriteValue,
- devpriv->s_BoardInfos.
- ui_Address + (64 * b_ModulNbr));
- }
- } else {
- /*******************************/
- /* Digital I/O not initialised */
- /*******************************/
-
- i_ReturnValue = -5;
- }
- } else {
- /******************************************/
- /* The module is not a digital I/O module */
- /******************************************/
-
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-
-|INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev,comedi_subdevice
- *s, struct comedi_insn *insn,unsigned int *data)
-+----------------------------------------------------------------------------+
-| Task : write:
- Sets or resets one or several outputs from port. |
-| Setting an output means setting an output high. |
-| If you have switched OFF the digital output memory |
-| (OFF), all the other output are set to "0".
-
-| read:
- Read the status from digital input port |
-| from selected digital I/O module (b_ModulNbr)
-+----------------------------------------------------------------------------+
-| Input Parameters :
- unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr CR_AREF(aref) : Selected module number (0 to 3)|
-| unsigned char_ b_PortValue CR_CHAN(chanspec) : Output Value ( 0 To 7 )
-| data[0] read or write port
-| data[1] if write then indicate ON or OFF
-
-| if read : data[1] will return port status.
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value :
-
-| INPUT :
-
- 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a digital I/O module |
-| -4: Digital I/O not initialised
-
- OUTPUT: 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a digital I/O module |
-| -4: Output value wrong |
-| -5: digital I/O not initialised see function |
-| " i_APCI1710_InitDigitalIO" |
-| -6: The digital channel A is used for input |
-| -7: The digital channel B is used for input
- -8: Digital Output Memory OFF. |
-| Use previously the function |
-| "i_APCI1710_SetDigitalIOMemoryOn". |
-+----------------------------------------------------------------------------+
-*/
-
-/*
- * _INT_ i_APCI1710_SetDigitalIOPortOn (unsigned char_
- * b_BoardHandle, unsigned char_ b_ModulNbr, unsigned char_
- * b_PortValue)
-*/
-static int i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_WriteValue = 0;
- unsigned int dw_StatusReg;
- unsigned char b_ModulNbr, b_PortValue;
- unsigned char b_PortOperation, b_PortOnOFF;
-
- unsigned char *pb_PortValue;
-
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_PortOperation = (unsigned char) data[0]; /* Input or output */
- b_PortOnOFF = (unsigned char) data[1]; /* if output then On or Off */
- b_PortValue = (unsigned char) data[2]; /* if out put then Value */
- i_ReturnValue = insn->n;
- pb_PortValue = (unsigned char *) &data[0];
-/* if input then read value */
-
- switch (b_PortOperation) {
- case APCI1710_INPUT:
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if digital I/O counter */
- /*******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
- /**********************************************/
- /* Test if the digital I/O module initialised */
- /**********************************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.b_DigitalInit == 1) {
- /**************************/
- /* Read all digital input */
- /**************************/
-
- /* INPDW (ps_APCI1710Variable->
- * s_Board [b_BoardHandle].
- * s_BoardInfos.
- * ui_Address + (64 * b_ModulNbr),
- * &dw_StatusReg);
- */
-
- dw_StatusReg =
- inl(devpriv->s_BoardInfos.
- ui_Address + (64 * b_ModulNbr));
- *pb_PortValue =
- (unsigned char) (dw_StatusReg ^ 0x1C);
-
- } else {
- /*******************************/
- /* Digital I/O not initialised */
- /*******************************/
-
- i_ReturnValue = -4;
- }
- } else {
- /******************************************/
- /* The module is not a digital I/O module */
- /******************************************/
-
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- i_ReturnValue = -2;
- }
-
- break;
-
- case APCI1710_OUTPUT:
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if digital I/O counter */
- /*******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
- /**********************************************/
- /* Test if the digital I/O module initialised */
- /**********************************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_DigitalIOInfo.b_DigitalInit == 1) {
- /***********************/
- /* Test the port value */
- /***********************/
-
- if (b_PortValue <= 7) {
- /***********************************/
- /* Test the digital output channel */
- /***********************************/
-
- /**************************/
- /* Test if channel A used */
- /**************************/
-
- if ((b_PortValue & 2) == 2) {
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- b_ChannelAMode
- != 1) {
- /*******************************************/
- /* The digital channel A is used for input */
- /*******************************************/
-
- i_ReturnValue =
- -6;
- }
- } /* if ((b_PortValue & 2) == 2) */
-
- /**************************/
- /* Test if channel B used */
- /**************************/
-
- if ((b_PortValue & 4) == 4) {
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- b_ChannelBMode
- != 1) {
- /*******************************************/
- /* The digital channel B is used for input */
- /*******************************************/
-
- i_ReturnValue =
- -7;
- }
- } /* if ((b_PortValue & 4) == 4) */
-
- /***********************/
- /* Test if error occur */
- /***********************/
-
- if (i_ReturnValue >= 0) {
-
- /* if(data[1]) { */
-
- switch (b_PortOnOFF) {
- /*********************************/
- /* Test if set Port ON */
- /*********************************/
-
- case APCI1710_ON:
-
- /*********************************/
- /* Test if output memory enabled */
- /*********************************/
-
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- b_OutputMemoryEnabled
- == 1) {
- dw_WriteValue
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- dw_OutputMemory
- |
- b_PortValue;
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- dw_OutputMemory
- =
- dw_WriteValue;
- } else {
- dw_WriteValue
- =
- b_PortValue;
- }
- break;
-
- /* If Set PORT OFF */
- case APCI1710_OFF:
-
- /*********************************/
- /* Test if output memory enabled */
- /*********************************/
-
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- b_OutputMemoryEnabled
- == 1) {
- dw_WriteValue
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- dw_OutputMemory
- &
- (0xFFFFFFFFUL
- -
- b_PortValue);
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_DigitalIOInfo.
- dw_OutputMemory
- =
- dw_WriteValue;
- } else {
- /*****************************/
- /* Digital Output Memory OFF */
- /*****************************/
-
- i_ReturnValue
- =
- -8;
- }
- } /* switch */
-
- /*******************/
- /* Write the value */
- /*******************/
-
- /* OUTPDW (ps_APCI1710Variable->
- * s_Board [b_BoardHandle].
- * s_BoardInfos.
- * ui_Address + (64 * b_ModulNbr),
- * dw_WriteValue); */
-
- outl(dw_WriteValue,
- devpriv->
- s_BoardInfos.
- ui_Address +
- (64 * b_ModulNbr));
- }
- } else {
- /**********************/
- /* Output value wrong */
- /**********************/
-
- i_ReturnValue = -4;
- }
- } else {
- /*******************************/
- /* Digital I/O not initialised */
- /*******************************/
-
- i_ReturnValue = -5;
- }
- } else {
- /******************************************/
- /* The module is not a digital I/O module */
- /******************************************/
-
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- i_ReturnValue = -2;
- }
- break;
-
- default:
- i_ReturnValue = -9;
- DPRINTK("NO INPUT/OUTPUT specified\n");
- } /* switch INPUT / OUTPUT */
- return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c
deleted file mode 100644
index c9db601da2c..00000000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c
+++ /dev/null
@@ -1,5461 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-----------------------------------------------------------------------+
- | Project : API APCI1710 | Compiler : gcc |
- | Module name : INC_CPT.C | Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-----------------------------------------------------------------------+
- | Description : APCI-1710 incremental counter module |
- | |
- | |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +-----------------------------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | | | |
- |----------|-----------|------------------------------------------------|
- | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 |
- | | | available |
- +-----------------------------------------------------------------------+
- | 29/06/01 | Guinot C. | - 1100/0231 -> 0701/0232 |
- | | | See i_APCI1710_DisableFrequencyMeasurement |
- +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_16BIT_COUNTER 0x10
-#define APCI1710_32BIT_COUNTER 0x0
-#define APCI1710_QUADRUPLE_MODE 0x0
-#define APCI1710_DOUBLE_MODE 0x3
-#define APCI1710_SIMPLE_MODE 0xF
-#define APCI1710_DIRECT_MODE 0x80
-#define APCI1710_HYSTERESIS_ON 0x60
-#define APCI1710_HYSTERESIS_OFF 0x0
-#define APCI1710_INCREMENT 0x60
-#define APCI1710_DECREMENT 0x0
-#define APCI1710_LATCH_COUNTER 0x1
-#define APCI1710_CLEAR_COUNTER 0x0
-#define APCI1710_LOW 0x0
-#define APCI1710_HIGH 0x1
-
-/*********************/
-/* Version 0600-0229 */
-/*********************/
-#define APCI1710_HIGH_EDGE_CLEAR_COUNTER 0x0
-#define APCI1710_HIGH_EDGE_LATCH_COUNTER 0x1
-#define APCI1710_LOW_EDGE_CLEAR_COUNTER 0x2
-#define APCI1710_LOW_EDGE_LATCH_COUNTER 0x3
-#define APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER 0x4
-#define APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER 0x5
-#define APCI1710_SOURCE_0 0x0
-#define APCI1710_SOURCE_1 0x1
-
-#define APCI1710_30MHZ 30
-#define APCI1710_33MHZ 33
-#define APCI1710_40MHZ 40
-
-#define APCI1710_ENABLE_LATCH_INT 0x80
-#define APCI1710_DISABLE_LATCH_INT (~APCI1710_ENABLE_LATCH_INT)
-
-#define APCI1710_INDEX_LATCH_COUNTER 0x10
-#define APCI1710_INDEX_AUTO_MODE 0x8
-#define APCI1710_ENABLE_INDEX 0x4
-#define APCI1710_DISABLE_INDEX (~APCI1710_ENABLE_INDEX)
-#define APCI1710_ENABLE_LATCH_AND_CLEAR 0x8
-#define APCI1710_DISABLE_LATCH_AND_CLEAR (~APCI1710_ENABLE_LATCH_AND_CLEAR)
-#define APCI1710_SET_LOW_INDEX_LEVEL 0x4
-#define APCI1710_SET_HIGH_INDEX_LEVEL (~APCI1710_SET_LOW_INDEX_LEVEL)
-#define APCI1710_INVERT_INDEX_RFERENCE 0x2
-#define APCI1710_DEFAULT_INDEX_RFERENCE (~APCI1710_INVERT_INDEX_RFERENCE)
-
-#define APCI1710_ENABLE_INDEX_INT 0x1
-#define APCI1710_DISABLE_INDEX_INT (~APCI1710_ENABLE_INDEX_INT)
-
-#define APCI1710_ENABLE_FREQUENCY 0x4
-#define APCI1710_DISABLE_FREQUENCY (~APCI1710_ENABLE_FREQUENCY)
-
-#define APCI1710_ENABLE_FREQUENCY_INT 0x8
-#define APCI1710_DISABLE_FREQUENCY_INT (~APCI1710_ENABLE_FREQUENCY_INT)
-
-#define APCI1710_ENABLE_40MHZ_FREQUENCY 0x40
-#define APCI1710_DISABLE_40MHZ_FREQUENCY (~APCI1710_ENABLE_40MHZ_FREQUENCY)
-
-#define APCI1710_ENABLE_40MHZ_FILTER 0x80
-#define APCI1710_DISABLE_40MHZ_FILTER (~APCI1710_ENABLE_40MHZ_FILTER)
-
-#define APCI1710_ENABLE_COMPARE_INT 0x2
-#define APCI1710_DISABLE_COMPARE_INT (~APCI1710_ENABLE_COMPARE_INT)
-
-#define APCI1710_ENABLE_INDEX_ACTION 0x20
-#define APCI1710_DISABLE_INDEX_ACTION (~APCI1710_ENABLE_INDEX_ACTION)
-#define APCI1710_REFERENCE_HIGH 0x40
-#define APCI1710_REFERENCE_LOW (~APCI1710_REFERENCE_HIGH)
-
-#define APCI1710_TOR_GATE_LOW 0x40
-#define APCI1710_TOR_GATE_HIGH (~APCI1710_TOR_GATE_LOW)
-
-/* INSN CONFIG */
-#define APCI1710_INCCPT_INITCOUNTER 100
-#define APCI1710_INCCPT_COUNTERAUTOTEST 101
-#define APCI1710_INCCPT_INITINDEX 102
-#define APCI1710_INCCPT_INITREFERENCE 103
-#define APCI1710_INCCPT_INITEXTERNALSTROBE 104
-#define APCI1710_INCCPT_INITCOMPARELOGIC 105
-#define APCI1710_INCCPT_INITFREQUENCYMEASUREMENT 106
-
-/* INSN READ */
-#define APCI1710_INCCPT_READLATCHREGISTERSTATUS 200
-#define APCI1710_INCCPT_READLATCHREGISTERVALUE 201
-#define APCI1710_INCCPT_READ16BITCOUNTERVALUE 202
-#define APCI1710_INCCPT_READ32BITCOUNTERVALUE 203
-#define APCI1710_INCCPT_GETINDEXSTATUS 204
-#define APCI1710_INCCPT_GETREFERENCESTATUS 205
-#define APCI1710_INCCPT_GETUASSTATUS 206
-#define APCI1710_INCCPT_GETCBSTATUS 207
-#define APCI1710_INCCPT_GET16BITCBSTATUS 208
-#define APCI1710_INCCPT_GETUDSTATUS 209
-#define APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS 210
-#define APCI1710_INCCPT_READFREQUENCYMEASUREMENT 211
-#define APCI1710_INCCPT_READINTERRUPT 212
-
-/* INSN BITS */
-#define APCI1710_INCCPT_CLEARCOUNTERVALUE 300
-#define APCI1710_INCCPT_CLEARALLCOUNTERVALUE 301
-#define APCI1710_INCCPT_SETINPUTFILTER 302
-#define APCI1710_INCCPT_LATCHCOUNTER 303
-#define APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE 304
-#define APCI1710_INCCPT_SETDIGITALCHLON 305
-#define APCI1710_INCCPT_SETDIGITALCHLOFF 306
-
-/* INSN WRITE */
-#define APCI1710_INCCPT_ENABLELATCHINTERRUPT 400
-#define APCI1710_INCCPT_DISABLELATCHINTERRUPT 401
-#define APCI1710_INCCPT_WRITE16BITCOUNTERVALUE 402
-#define APCI1710_INCCPT_WRITE32BITCOUNTERVALUE 403
-#define APCI1710_INCCPT_ENABLEINDEX 404
-#define APCI1710_INCCPT_DISABLEINDEX 405
-#define APCI1710_INCCPT_ENABLECOMPARELOGIC 406
-#define APCI1710_INCCPT_DISABLECOMPARELOGIC 407
-#define APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT 408
-#define APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT 409
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitCounter |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_CounterRange, |
-| unsigned char_ b_FirstCounterModus, |
-| unsigned char_ b_FirstCounterOption, |
-| unsigned char_ b_SecondCounterModus, |
-| unsigned char_ b_SecondCounterOption) |
-+----------------------------------------------------------------------------+
-| Task : Configure the counter operating mode from selected |
-| module (b_ModulNbr). You must calling this function be |
-| for you call any other function witch access of |
-| counters. |
-| |
-| Counter range |
-| ------------- |
-| +------------------------------------+-----------------------------------+ |
-| | Parameter Passed value | Description | |
-| |------------------------------------+-----------------------------------| |
-| |b_ModulNbr APCI1710_16BIT_COUNTER | The module is configured for | |
-| | | two 16-bit counter. | |
-| | | - b_FirstCounterModus and | |
-| | | b_FirstCounterOption | |
-| | | configure the first 16 bit | |
-| | | counter. | |
-| | | - b_SecondCounterModus and | |
-| | | b_SecondCounterOption | |
-| | | configure the second 16 bit | |
-| | | counter. | |
-| |------------------------------------+-----------------------------------| |
-| |b_ModulNbr APCI1710_32BIT_COUNTER | The module is configured for one | |
-| | | 32-bit counter. | |
-| | | - b_FirstCounterModus and | |
-| | | b_FirstCounterOption | |
-| | | configure the 32 bit counter. | |
-| | | - b_SecondCounterModus and | |
-| | | b_SecondCounterOption | |
-| | | are not used and have no | |
-| | | importance. | |
-| +------------------------------------+-----------------------------------+ |
-| |
-| Counter operating mode |
-| ---------------------- |
-| |
-| +--------------------+-------------------------+-------------------------+ |
-| | Parameter | Passed value | Description | |
-| |--------------------+-------------------------+-------------------------| |
-| |b_FirstCounterModus | APCI1710_QUADRUPLE_MODE | In the quadruple mode, | |
-| | or | | the edge analysis | |
-| |b_SecondCounterModus| | circuit generates a | |
-| | | | counting pulse from | |
-| | | | each edge of 2 signals | |
-| | | | which are phase shifted | |
-| | | | in relation to each | |
-| | | | other. | |
-| |--------------------+-------------------------+-------------------------| |
-| |b_FirstCounterModus | APCI1710_DOUBLE_MODE | Functions in the same | |
-| | or | | way as the quadruple | |
-| |b_SecondCounterModus| | mode, except that only | |
-| | | | two of the four edges | |
-| | | | are analysed per | |
-| | | | period | |
-| |--------------------+-------------------------+-------------------------| |
-| |b_FirstCounterModus | APCI1710_SIMPLE_MODE | Functions in the same | |
-| | or | | way as the quadruple | |
-| |b_SecondCounterModus| | mode, except that only | |
-| | | | one of the four edges | |
-| | | | is analysed per | |
-| | | | period. | |
-| |--------------------+-------------------------+-------------------------| |
-| |b_FirstCounterModus | APCI1710_DIRECT_MODE | In the direct mode the | |
-| | or | | both edge analysis | |
-| |b_SecondCounterModus| | circuits are inactive. | |
-| | | | The inputs A, B in the | |
-| | | | 32-bit mode or A, B and | |
-| | | | C, D in the 16-bit mode | |
-| | | | represent, each, one | |
-| | | | clock pulse gate circuit| |
-| | | | There by frequency and | |
-| | | | pulse duration | |
-| | | | measurements can be | |
-| | | | performed. | |
-| +--------------------+-------------------------+-------------------------+ |
-| |
-| |
-| IMPORTANT! |
-| If you have configured the module for two 16-bit counter, a mixed |
-| mode with a counter in quadruple/double/single mode |
-| and the other counter in direct mode is not possible! |
-| |
-| |
-| Counter operating option for quadruple/double/simple mode |
-| --------------------------------------------------------- |
-| |
-| +----------------------+-------------------------+------------------------+|
-| | Parameter | Passed value | Description ||
-| |----------------------+-------------------------+------------------------||
-| |b_FirstCounterOption | APCI1710_HYSTERESIS_ON | In both edge analysis ||
-| | or | | circuits is available ||
-| |b_SecondCounterOption | | one hysteresis circuit.||
-| | | | It suppresses each ||
-| | | | time the first counting||
-| | | | pulse after a change ||
-| | | | of rotation. ||
-| |----------------------+-------------------------+------------------------||
-| |b_FirstCounterOption | APCI1710_HYSTERESIS_OFF | The first counting ||
-| | or | | pulse is not suppress ||
-| |b_SecondCounterOption | | after a change of ||
-| | | | rotation. ||
-| +----------------------+-------------------------+------------------------+|
-| |
-| |
-| IMPORTANT! |
-| This option are only avaible if you have selected the direct mode. |
-| |
-| |
-| Counter operating option for direct mode |
-| ---------------------------------------- |
-| |
-| +----------------------+--------------------+----------------------------+ |
-| | Parameter | Passed value | Description | |
-| |----------------------+--------------------+----------------------------| |
-| |b_FirstCounterOption | APCI1710_INCREMENT | The counter increment for | |
-| | or | | each counting pulse | |
-| |b_SecondCounterOption | | | |
-| |----------------------+--------------------+----------------------------| |
-| |b_FirstCounterOption | APCI1710_DECREMENT | The counter decrement for | |
-| | or | | each counting pulse | |
-| |b_SecondCounterOption | | | |
-| +----------------------+--------------------+----------------------------+ |
-| |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710|
-| unsigned char_ b_ModulNbr : Module number to |
-| configure (0 to 3) |
-| unsigned char_ b_CounterRange : Selection form counter |
-| range. |
-| unsigned char_ b_FirstCounterModus : First counter operating |
-| mode. |
-| unsigned char_ b_FirstCounterOption : First counter option. |
-| unsigned char_ b_SecondCounterModus : Second counter operating |
-| mode. |
-| unsigned char_ b_SecondCounterOption : Second counter option. |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module is not a counter module |
-| -3: The selected counter range is wrong. |
-| -4: The selected first counter operating mode is wrong. |
-| -5: The selected first counter operating option is wrong|
-| -6: The selected second counter operating mode is wrong.|
-| -7: The selected second counter operating option is |
-| wrong. |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitCounter(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_CounterRange,
- unsigned char b_FirstCounterModus,
- unsigned char b_FirstCounterOption,
- unsigned char b_SecondCounterModus,
- unsigned char b_SecondCounterOption)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /*******************************/
- /* Test if incremental counter */
- /*******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER) {
- /**************************/
- /* Test the counter range */
- /**************************/
-
- if (b_CounterRange == APCI1710_16BIT_COUNTER
- || b_CounterRange == APCI1710_32BIT_COUNTER) {
- /********************************/
- /* Test the first counter modus */
- /********************************/
-
- if (b_FirstCounterModus == APCI1710_QUADRUPLE_MODE ||
- b_FirstCounterModus == APCI1710_DOUBLE_MODE ||
- b_FirstCounterModus == APCI1710_SIMPLE_MODE ||
- b_FirstCounterModus == APCI1710_DIRECT_MODE) {
- /*********************************/
- /* Test the first counter option */
- /*********************************/
-
- if ((b_FirstCounterModus == APCI1710_DIRECT_MODE
- && (b_FirstCounterOption ==
- APCI1710_INCREMENT
- || b_FirstCounterOption
- == APCI1710_DECREMENT))
- || (b_FirstCounterModus !=
- APCI1710_DIRECT_MODE
- && (b_FirstCounterOption ==
- APCI1710_HYSTERESIS_ON
- || b_FirstCounterOption
- ==
- APCI1710_HYSTERESIS_OFF)))
- {
- /**************************/
- /* Test if 16-bit counter */
- /**************************/
-
- if (b_CounterRange ==
- APCI1710_16BIT_COUNTER) {
- /*********************************/
- /* Test the second counter modus */
- /*********************************/
-
- if ((b_FirstCounterModus !=
- APCI1710_DIRECT_MODE
- &&
- (b_SecondCounterModus
- ==
- APCI1710_QUADRUPLE_MODE
- ||
- b_SecondCounterModus
- ==
- APCI1710_DOUBLE_MODE
- ||
- b_SecondCounterModus
- ==
- APCI1710_SIMPLE_MODE))
- || (b_FirstCounterModus
- ==
- APCI1710_DIRECT_MODE
- &&
- b_SecondCounterModus
- ==
- APCI1710_DIRECT_MODE))
- {
- /**********************************/
- /* Test the second counter option */
- /**********************************/
-
- if ((b_SecondCounterModus == APCI1710_DIRECT_MODE && (b_SecondCounterOption == APCI1710_INCREMENT || b_SecondCounterOption == APCI1710_DECREMENT)) || (b_SecondCounterModus != APCI1710_DIRECT_MODE && (b_SecondCounterOption == APCI1710_HYSTERESIS_ON || b_SecondCounterOption == APCI1710_HYSTERESIS_OFF))) {
- i_ReturnValue =
- 0;
- } else {
- /*********************************************************/
- /* The selected second counter operating option is wrong */
- /*********************************************************/
-
- DPRINTK("The selected second counter operating option is wrong\n");
- i_ReturnValue =
- -7;
- }
- } else {
- /*******************************************************/
- /* The selected second counter operating mode is wrong */
- /*******************************************************/
-
- DPRINTK("The selected second counter operating mode is wrong\n");
- i_ReturnValue = -6;
- }
- }
- } else {
- /********************************************************/
- /* The selected first counter operating option is wrong */
- /********************************************************/
-
- DPRINTK("The selected first counter operating option is wrong\n");
- i_ReturnValue = -5;
- }
- } else {
- /******************************************************/
- /* The selected first counter operating mode is wrong */
- /******************************************************/
- DPRINTK("The selected first counter operating mode is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /***************************************/
- /* The selected counter range is wrong */
- /***************************************/
-
- DPRINTK("The selected counter range is wrong\n");
- i_ReturnValue = -3;
- }
-
- /*************************/
- /* Test if a error occur */
- /*************************/
-
- if (i_ReturnValue == 0) {
- /**************************/
- /* Test if 16-Bit counter */
- /**************************/
-
- if (b_CounterRange == APCI1710_32BIT_COUNTER) {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister1 = b_CounterRange |
- b_FirstCounterModus |
- b_FirstCounterOption;
- } else {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister1 = b_CounterRange |
- (b_FirstCounterModus & 0x5) |
- (b_FirstCounterOption & 0x20) |
- (b_SecondCounterModus & 0xA) |
- (b_SecondCounterOption & 0x40);
-
- /***********************/
- /* Test if direct mode */
- /***********************/
-
- if (b_FirstCounterModus == APCI1710_DIRECT_MODE) {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister1 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister1 |
- APCI1710_DIRECT_MODE;
- }
- }
-
- /***************************/
- /* Write the configuration */
- /***************************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4,
- devpriv->s_BoardInfos.
- ui_Address + 20 + (64 * b_ModulNbr));
-
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_CounterInit = 1;
- }
- } else {
- /**************************************/
- /* The module is not a counter module */
- /**************************************/
-
- DPRINTK("The module is not a counter module\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_CounterAutoTest |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char *_ pb_TestStatus) |
-+----------------------------------------------------------------------------+
-| Task : A test mode is intended for testing the component and |
-| the connected periphery. All the 8-bit counter chains |
-| are operated internally as down counters. |
-| Independently from the external signals, |
-| all the four 8-bit counter chains are decremented in |
-| parallel by each negative clock pulse edge of CLKX. |
-| |
-| Counter auto test conclusion |
-| ---------------------------- |
-| +-----------------+-----------------------------+ |
-| | pb_TestStatus | Error description | |
-| | mask | | |
-| |-----------------+-----------------------------| |
-| | 0000 | No error detected | |
-| |-----------------|-----------------------------| |
-| | 0001 | Error detected of counter 0 | |
-| |-----------------|-----------------------------| |
-| | 0010 | Error detected of counter 1 | |
-| |-----------------|-----------------------------| |
-| | 0100 | Error detected of counter 2 | |
-| |-----------------|-----------------------------| |
-| | 1000 | Error detected of counter 3 | |
-| +-----------------+-----------------------------+ |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_TestStatus : Auto test conclusion. See table|
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_CounterAutoTest(struct comedi_device *dev,
- unsigned char *pb_TestStatus)
-{
- struct addi_private *devpriv = dev->private;
- unsigned char b_ModulCpt = 0;
- int i_ReturnValue = 0;
- unsigned int dw_LathchValue;
-
- *pb_TestStatus = 0;
-
- /********************************/
- /* Test if counter module found */
- /********************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[0] & 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER
- || (devpriv->s_BoardInfos.
- dw_MolduleConfiguration[1] & 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER
- || (devpriv->s_BoardInfos.
- dw_MolduleConfiguration[2] & 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER
- || (devpriv->s_BoardInfos.
- dw_MolduleConfiguration[3] & 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER) {
- for (b_ModulCpt = 0; b_ModulCpt < 4; b_ModulCpt++) {
- /*******************************/
- /* Test if incremental counter */
- /*******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulCpt] &
- 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER) {
- /******************/
- /* Start the test */
- /******************/
-
- outl(3, devpriv->s_BoardInfos.
- ui_Address + 16 + (64 * b_ModulCpt));
-
- /*********************/
- /* Tatch the counter */
- /*********************/
-
- outl(1, devpriv->s_BoardInfos.
- ui_Address + (64 * b_ModulCpt));
-
- /************************/
- /* Read the latch value */
- /************************/
-
- dw_LathchValue = inl(devpriv->s_BoardInfos.
- ui_Address + 4 + (64 * b_ModulCpt));
-
- if ((dw_LathchValue & 0xFF) !=
- ((dw_LathchValue >> 8) & 0xFF)
- && (dw_LathchValue & 0xFF) !=
- ((dw_LathchValue >> 16) & 0xFF)
- && (dw_LathchValue & 0xFF) !=
- ((dw_LathchValue >> 24) & 0xFF)) {
- *pb_TestStatus =
- *pb_TestStatus | (1 <<
- b_ModulCpt);
- }
-
- /*****************/
- /* Stop the test */
- /*****************/
-
- outl(0, devpriv->s_BoardInfos.
- ui_Address + 16 + (64 * b_ModulCpt));
- }
- }
- } else {
- /***************************/
- /* No counter module found */
- /***************************/
-
- DPRINTK("No counter module found\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitIndex (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_ReferenceAction, |
-| unsigned char_ b_IndexOperation, |
-| unsigned char_ b_AutoMode, |
-| unsigned char_ b_InterruptEnable) |
-+----------------------------------------------------------------------------+
-| Task : Initialise the index corresponding to the selected |
-| module (b_ModulNbr). If a INDEX flag occur, you have |
-| the possibility to clear the 32-Bit counter or to latch|
-| the current 32-Bit value in to the first latch |
-| register. The b_IndexOperation parameter give the |
-| possibility to choice the INDEX action. |
-| If you have enabled the automatic mode, each INDEX |
-| action is cleared automatically, else you must read |
-| the index status ("i_APCI1710_ReadIndexStatus") |
-| after each INDEX action. |
-| |
-| |
-| Index action |
-| ------------ |
-| |
-| +------------------------+------------------------------------+ |
-| | b_IndexOperation | Operation | |
-| |------------------------+------------------------------------| |
-| |APCI1710_LATCH_COUNTER | After a index signal, the counter | |
-| | | value (32-Bit) is latched in to | |
-| | | the first latch register | |
-| |------------------------|------------------------------------| |
-| |APCI1710_CLEAR_COUNTER | After a index signal, the counter | |
-| | | value is cleared (32-Bit) | |
-| +------------------------+------------------------------------+ |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| unsigned char_ b_ReferenceAction : Determine if the reference |
-| must set or no for the |
-| acceptance from index |
-| APCI1710_ENABLE : |
-| Reference must be set for |
-| accepted the index |
-| APCI1710_DISABLE : |
-| Reference have not |
-| importance |
-| unsigned char_ b_IndexOperation : Index operating mode. |
-| See table. |
-| unsigned char_ b_AutoMode : Enable or disable the |
-| automatic index reset. |
-| APCI1710_ENABLE : |
-| Enable the automatic mode |
-| APCI1710_DISABLE : |
-| Disable the automatic mode |
-| unsigned char_ b_InterruptEnable : Enable or disable the |
-| interrupt. |
-| APCI1710_ENABLE : |
-| Enable the interrupt |
-| APCI1710_DISABLE : |
-| Disable the interrupt |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4 The reference action parameter is wrong |
-| -5: The index operating mode parameter is wrong |
-| -6: The auto mode parameter is wrong |
-| -7: Interrupt parameter is wrong |
-| -8: Interrupt function not initialised. |
-| See function "i_APCI1710_SetBoardIntRoutineX" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitIndex(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_ReferenceAction,
- unsigned char b_IndexOperation,
- unsigned char b_AutoMode,
- unsigned char b_InterruptEnable)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /********************************/
- /* Test the reference parameter */
- /********************************/
-
- if (b_ReferenceAction == APCI1710_ENABLE ||
- b_ReferenceAction == APCI1710_DISABLE) {
- /****************************/
- /* Test the index parameter */
- /****************************/
-
- if (b_IndexOperation ==
- APCI1710_HIGH_EDGE_LATCH_COUNTER
- || b_IndexOperation ==
- APCI1710_LOW_EDGE_LATCH_COUNTER
- || b_IndexOperation ==
- APCI1710_HIGH_EDGE_CLEAR_COUNTER
- || b_IndexOperation ==
- APCI1710_LOW_EDGE_CLEAR_COUNTER
- || b_IndexOperation ==
- APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER
- || b_IndexOperation ==
- APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
- {
- /********************************/
- /* Test the auto mode parameter */
- /********************************/
-
- if (b_AutoMode == APCI1710_ENABLE ||
- b_AutoMode == APCI1710_DISABLE)
- {
- /***************************/
- /* Test the interrupt mode */
- /***************************/
-
- if (b_InterruptEnable ==
- APCI1710_ENABLE
- || b_InterruptEnable ==
- APCI1710_DISABLE) {
-
- /************************************/
- /* Makte the configuration commando */
- /************************************/
-
- if (b_ReferenceAction ==
- APCI1710_ENABLE)
- {
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- |
- APCI1710_ENABLE_INDEX_ACTION;
- } else {
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- &
- APCI1710_DISABLE_INDEX_ACTION;
- }
-
- /****************************************/
- /* Test if low level latch or/and clear */
- /****************************************/
-
- if (b_IndexOperation ==
- APCI1710_LOW_EDGE_LATCH_COUNTER
- ||
- b_IndexOperation
- ==
- APCI1710_LOW_EDGE_CLEAR_COUNTER
- ||
- b_IndexOperation
- ==
- APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
- {
- /*************************************/
- /* Set the index level to low (DQ26) */
- /*************************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- |
- APCI1710_SET_LOW_INDEX_LEVEL;
- } else {
- /**************************************/
- /* Set the index level to high (DQ26) */
- /**************************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- &
- APCI1710_SET_HIGH_INDEX_LEVEL;
- }
-
- /***********************************/
- /* Test if latch and clear counter */
- /***********************************/
-
- if (b_IndexOperation ==
- APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER
- ||
- b_IndexOperation
- ==
- APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
- {
- /***************************************/
- /* Set the latch and clear flag (DQ27) */
- /***************************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- |
- APCI1710_ENABLE_LATCH_AND_CLEAR;
- } /* if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) */
- else {
- /*****************************************/
- /* Clear the latch and clear flag (DQ27) */
- /*****************************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- &
- APCI1710_DISABLE_LATCH_AND_CLEAR;
-
- /*************************/
- /* Test if latch counter */
- /*************************/
-
- if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_COUNTER) {
- /*********************************/
- /* Enable the latch from counter */
- /*********************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- |
- APCI1710_INDEX_LATCH_COUNTER;
- } else {
- /*********************************/
- /* Enable the clear from counter */
- /*********************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- &
- (~APCI1710_INDEX_LATCH_COUNTER);
- }
- } /* // if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) */
-
- if (b_AutoMode ==
- APCI1710_DISABLE)
- {
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- |
- APCI1710_INDEX_AUTO_MODE;
- } else {
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2
- &
- (~APCI1710_INDEX_AUTO_MODE);
- }
-
- if (b_InterruptEnable ==
- APCI1710_ENABLE)
- {
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3
- |
- APCI1710_ENABLE_INDEX_INT;
- } else {
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3
- &
- APCI1710_DISABLE_INDEX_INT;
- }
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.
- b_IndexInit = 1;
-
- } else {
- /********************************/
- /* Interrupt parameter is wrong */
- /********************************/
- DPRINTK("Interrupt parameter is wrong\n");
- i_ReturnValue = -7;
- }
- } else {
- /************************************/
- /* The auto mode parameter is wrong */
- /************************************/
-
- DPRINTK("The auto mode parameter is wrong\n");
- i_ReturnValue = -6;
- }
- } else {
- /***********************************************/
- /* The index operating mode parameter is wrong */
- /***********************************************/
-
- DPRINTK("The index operating mode parameter is wrong\n");
- i_ReturnValue = -5;
- }
- } else {
- /*******************************************/
- /* The reference action parameter is wrong */
- /*******************************************/
-
- DPRINTK("The reference action parameter is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitReference |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_ReferenceLevel) |
-+----------------------------------------------------------------------------+
-| Task : Initialise the reference corresponding to the selected |
-| module (b_ModulNbr). |
-| |
-| Reference level |
-| --------------- |
-| +--------------------+-------------------------+ |
-| | b_ReferenceLevel | Operation | |
-| +--------------------+-------------------------+ |
-| | APCI1710_LOW | Reference occur if "0" | |
-| |--------------------|-------------------------| |
-| | APCI1710_HIGH | Reference occur if "1" | |
-| +--------------------+-------------------------+ |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| unsigned char_ b_ReferenceLevel : Reference level. |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The selected module number parameter is wrong |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Reference level parameter is wrong |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitReference(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_ReferenceLevel)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /**************************************/
- /* Test the reference level parameter */
- /**************************************/
-
- if (b_ReferenceLevel == 0 || b_ReferenceLevel == 1) {
- if (b_ReferenceLevel == 1) {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 |
- APCI1710_REFERENCE_HIGH;
- } else {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 &
- APCI1710_REFERENCE_LOW;
- }
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4,
- devpriv->s_BoardInfos.ui_Address + 20 +
- (64 * b_ModulNbr));
-
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_ReferenceInit = 1;
- } else {
- /**************************************/
- /* Reference level parameter is wrong */
- /**************************************/
-
- DPRINTK("Reference level parameter is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitExternalStrobe |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_ExternalStrobe, |
-| unsigned char_ b_ExternalStrobeLevel) |
-+----------------------------------------------------------------------------+
-| Task : Initialises the external strobe level corresponding to |
-| the selected module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| unsigned char_ b_ExternalStrobe : External strobe selection |
-| 0 : External strobe A |
-| 1 : External strobe B |
-| unsigned char_ b_ExternalStrobeLevel : External strobe level |
-| APCI1710_LOW : |
-| External latch occurs if "0" |
-| APCI1710_HIGH : |
-| External latch occurs if "1" |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The selected module number is wrong |
-| -3: Counter not initialised. |
-| See function "i_APCI1710_InitCounter" |
-| -4: External strobe selection is wrong |
-| -5: External strobe level parameter is wrong |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitExternalStrobe(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_ExternalStrobe,
- unsigned char b_ExternalStrobeLevel)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /**************************************/
- /* Test the external strobe selection */
- /**************************************/
-
- if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) {
- /******************/
- /* Test the level */
- /******************/
-
- if ((b_ExternalStrobeLevel == APCI1710_HIGH) ||
- ((b_ExternalStrobeLevel == APCI1710_LOW
- && (devpriv->
- s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr] &
- 0xFFFF) >=
- 0x3135))) {
- /*****************/
- /* Set the level */
- /*****************/
-
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4 = (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4 & (0xFF -
- (0x10 << b_ExternalStrobe))) | ((b_ExternalStrobeLevel ^ 1) << (4 + b_ExternalStrobe));
- } else {
- /********************************************/
- /* External strobe level parameter is wrong */
- /********************************************/
-
- DPRINTK("External strobe level parameter is wrong\n");
- i_ReturnValue = -5;
- }
- } /* if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) */
- else {
- /**************************************/
- /* External strobe selection is wrong */
- /**************************************/
-
- DPRINTK("External strobe selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) */
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
- /*
- +----------------------------------------------------------------------------+
- | Function Name : _INT_ i_APCI1710_InitCompareLogic |
- | (unsigned char_ b_BoardHandle, |
- | unsigned char_ b_ModulNbr, |
- | unsigned int_ ui_CompareValue) |
- +----------------------------------------------------------------------------+
- | Task : Set the 32-Bit compare value. At that moment that the |
- | incremental counter arrive to the compare value |
- | (ui_CompareValue) a interrupt is generated. |
- +----------------------------------------------------------------------------+
- | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
- | unsigned char_ b_ModulNbr : Module number to configure |
- | (0 to 3) |
- | unsigned int_ ui_CompareValue : 32-Bit compare value |
- +----------------------------------------------------------------------------+
- | Output Parameters : -
- +----------------------------------------------------------------------------+
- | Return Value : 0: No error |
- | -1: The handle parameter of the board is wrong |
- | -2: No counter module found |
- | -3: Counter not initialised see function |
- | "i_APCI1710_InitCounter" |
- +----------------------------------------------------------------------------+
- */
-static int i_APCI1710_InitCompareLogic(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned int ui_CompareValue)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-
- outl(ui_CompareValue, devpriv->s_BoardInfos.
- ui_Address + 28 + (64 * b_ModulNbr));
-
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_CompareLogicInit = 1;
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitFrequencyMeasurement |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PCIInputClock, |
-| unsigned char_ b_TimingUnity, |
-| ULONG_ ul_TimingInterval, |
-| PULONG_ pul_RealTimingInterval) |
-+----------------------------------------------------------------------------+
-| Task : Sets the time for the frequency measurement. |
-| Configures the selected TOR incremental counter of the |
-| selected module (b_ModulNbr). The ul_TimingInterval and|
-| ul_TimingUnity determine the time base for the |
-| measurement. The pul_RealTimingInterval returns the |
-| real time value. You must call up this function before |
-| you call up any other function which gives access to |
-| the frequency measurement. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Number of the module to be |
-| configured (0 to 3) |
-| unsigned char_ b_PCIInputClock : Selection of the PCI bus |
-| clock |
-| - APCI1710_30MHZ : |
-| The PC has a PCI bus clock |
-| of 30 MHz |
-| - APCI1710_33MHZ : |
-| The PC has a PCI bus clock |
-| of 33 MHz |
-| unsigned char_ b_TimingUnity : Base time unit (0 to 2) |
-| 0 : ns |
-| 1 : æs |
-| 2 : ms |
-| ULONG_ ul_TimingInterval: Base time value. |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_RealTimingInterval : Real base time value. |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The selected module number is wrong |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: The selected PCI input clock is wrong |
-| -5: Timing unity selection is wrong |
-| -6: Base timing selection is wrong |
-| -7: 40MHz quartz not on board |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitFrequencyMeasurement(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_PCIInputClock,
- unsigned char b_TimingUnity,
- unsigned int ul_TimingInterval,
- unsigned int *pul_RealTimingInterval)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int ul_TimerValue = 0;
- double d_RealTimingInterval;
- unsigned int dw_Status = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /**************************/
- /* Test the PCI bus clock */
- /**************************/
-
- if ((b_PCIInputClock == APCI1710_30MHZ) ||
- (b_PCIInputClock == APCI1710_33MHZ) ||
- (b_PCIInputClock == APCI1710_40MHZ)) {
- /************************/
- /* Test the timing unit */
- /************************/
-
- if (b_TimingUnity <= 2) {
- /**********************************/
- /* Test the base timing selection */
- /**********************************/
-
- if (((b_PCIInputClock == APCI1710_30MHZ)
- && (b_TimingUnity == 0)
- && (ul_TimingInterval >=
- 266)
- && (ul_TimingInterval <=
- 8738133UL))
- || ((b_PCIInputClock ==
- APCI1710_30MHZ)
- && (b_TimingUnity == 1)
- && (ul_TimingInterval >=
- 1)
- && (ul_TimingInterval <=
- 8738UL))
- || ((b_PCIInputClock ==
- APCI1710_30MHZ)
- && (b_TimingUnity == 2)
- && (ul_TimingInterval >=
- 1)
- && (ul_TimingInterval <=
- 8UL))
- || ((b_PCIInputClock ==
- APCI1710_33MHZ)
- && (b_TimingUnity == 0)
- && (ul_TimingInterval >=
- 242)
- && (ul_TimingInterval <=
- 7943757UL))
- || ((b_PCIInputClock ==
- APCI1710_33MHZ)
- && (b_TimingUnity == 1)
- && (ul_TimingInterval >=
- 1)
- && (ul_TimingInterval <=
- 7943UL))
- || ((b_PCIInputClock ==
- APCI1710_33MHZ)
- && (b_TimingUnity == 2)
- && (ul_TimingInterval >=
- 1)
- && (ul_TimingInterval <=
- 7UL))
- || ((b_PCIInputClock ==
- APCI1710_40MHZ)
- && (b_TimingUnity == 0)
- && (ul_TimingInterval >=
- 200)
- && (ul_TimingInterval <=
- 6553500UL))
- || ((b_PCIInputClock ==
- APCI1710_40MHZ)
- && (b_TimingUnity == 1)
- && (ul_TimingInterval >=
- 1)
- && (ul_TimingInterval <=
- 6553UL))
- || ((b_PCIInputClock ==
- APCI1710_40MHZ)
- && (b_TimingUnity == 2)
- && (ul_TimingInterval >=
- 1)
- && (ul_TimingInterval <=
- 6UL))) {
- /**********************/
- /* Test if 40MHz used */
- /**********************/
-
- if (b_PCIInputClock ==
- APCI1710_40MHZ) {
- /******************************/
- /* Test if firmware >= Rev1.5 */
- /******************************/
-
- if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3135) {
- /*********************************/
- /* Test if 40MHz quartz on board */
- /*********************************/
-
- /*INPDW (ps_APCI1710Variable->
- s_Board [b_BoardHandle].
- s_BoardInfos.
- ui_Address + 36 + (64 * b_ModulNbr), &dw_Status); */
- dw_Status =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- + 36 +
- (64 * b_ModulNbr));
-
- /******************************/
- /* Test the quartz flag (DQ0) */
- /******************************/
-
- if ((dw_Status & 1) != 1) {
- /*****************************/
- /* 40MHz quartz not on board */
- /*****************************/
-
- DPRINTK("40MHz quartz not on board\n");
- i_ReturnValue
- =
- -7;
- }
- } else {
- /*****************************/
- /* 40MHz quartz not on board */
- /*****************************/
- DPRINTK("40MHz quartz not on board\n");
- i_ReturnValue =
- -7;
- }
- } /* if (b_PCIInputClock == APCI1710_40MHZ) */
-
- /***************************/
- /* Test if not error occur */
- /***************************/
-
- if (i_ReturnValue == 0) {
- /****************************/
- /* Test the INC_CPT version */
- /****************************/
-
- if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131) {
-
- /**********************/
- /* Test if 40MHz used */
- /**********************/
-
- if (b_PCIInputClock == APCI1710_40MHZ) {
- /*********************************/
- /* Enable the 40MHz quarz (DQ30) */
- /*********************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- |
- APCI1710_ENABLE_40MHZ_FREQUENCY;
- } /* if (b_PCIInputClock == APCI1710_40MHZ) */
- else {
- /**********************************/
- /* Disable the 40MHz quarz (DQ30) */
- /**********************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- &
- APCI1710_DISABLE_40MHZ_FREQUENCY;
-
- } /* if (b_PCIInputClock == APCI1710_40MHZ) */
-
- /********************************/
- /* Calculate the division fator */
- /********************************/
-
- fpu_begin();
- switch (b_TimingUnity) {
- /******/
- /* ns */
- /******/
-
- case 0:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- (unsigned int)
- (ul_TimingInterval
- *
- (0.00025 * b_PCIInputClock));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (0.00025 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (0.00025 * (double)b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (0.00025
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (0.00025 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) {
- *pul_RealTimingInterval
- =
- *pul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
-
- break;
-
- /******/
- /* æs */
- /******/
-
- case 1:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- (unsigned int)
- (ul_TimingInterval
- *
- (0.25 * b_PCIInputClock));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (0.25 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (0.25 * (double)b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (
- (double)
- 0.25
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (0.25 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) {
- *pul_RealTimingInterval
- =
- *pul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
-
- break;
-
- /******/
- /* ms */
- /******/
-
- case 2:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- ul_TimingInterval
- *
- (250.0
- *
- b_PCIInputClock);
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (250.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (250.0 * (double)b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (250.0
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (250.0 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) {
- *pul_RealTimingInterval
- =
- *pul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
-
- break;
- }
-
- fpu_end();
- /*************************/
- /* Write the timer value */
- /*************************/
-
- outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + 32 + (64 * b_ModulNbr));
-
- /*******************************/
- /* Set the initialisation flag */
- /*******************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.
- b_FrequencyMeasurementInit
- = 1;
- } else {
- /***************************/
- /* Counter not initialised */
- /***************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue =
- -3;
- }
- } /* if (i_ReturnValue == 0) */
- } else {
- /**********************************/
- /* Base timing selection is wrong */
- /**********************************/
-
- DPRINTK("Base timing selection is wrong\n");
- i_ReturnValue = -6;
- }
- } else {
- /***********************************/
- /* Timing unity selection is wrong */
- /***********************************/
-
- DPRINTK("Timing unity selection is wrong\n");
- i_ReturnValue = -5;
- }
- } else {
- /*****************************************/
- /* The selected PCI input clock is wrong */
- /*****************************************/
-
- DPRINTK("The selected PCI input clock is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
- * Configuration function for INC_CPT
- */
-static int i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- unsigned int ui_ConfigType;
- int i_ReturnValue = 0;
-
- ui_ConfigType = CR_CHAN(insn->chanspec);
-
- printk("\nINC_CPT");
-
- devpriv->tsk_Current = current; /* Save the current process task structure */
- switch (ui_ConfigType) {
- case APCI1710_INCCPT_INITCOUNTER:
- i_ReturnValue = i_APCI1710_InitCounter(dev,
- CR_AREF(insn->chanspec),
- (unsigned char) data[0],
- (unsigned char) data[1],
- (unsigned char) data[2], (unsigned char) data[3], (unsigned char) data[4]);
- break;
-
- case APCI1710_INCCPT_COUNTERAUTOTEST:
- i_ReturnValue = i_APCI1710_CounterAutoTest(dev,
- (unsigned char *) &data[0]);
- break;
-
- case APCI1710_INCCPT_INITINDEX:
- i_ReturnValue = i_APCI1710_InitIndex(dev,
- CR_AREF(insn->chanspec),
- (unsigned char) data[0],
- (unsigned char) data[1], (unsigned char) data[2], (unsigned char) data[3]);
- break;
-
- case APCI1710_INCCPT_INITREFERENCE:
- i_ReturnValue = i_APCI1710_InitReference(dev,
- CR_AREF(insn->chanspec), (unsigned char) data[0]);
- break;
-
- case APCI1710_INCCPT_INITEXTERNALSTROBE:
- i_ReturnValue = i_APCI1710_InitExternalStrobe(dev,
- CR_AREF(insn->chanspec),
- (unsigned char) data[0], (unsigned char) data[1]);
- break;
-
- case APCI1710_INCCPT_INITCOMPARELOGIC:
- i_ReturnValue = i_APCI1710_InitCompareLogic(dev,
- CR_AREF(insn->chanspec), (unsigned int) data[0]);
- break;
-
- case APCI1710_INCCPT_INITFREQUENCYMEASUREMENT:
- i_ReturnValue = i_APCI1710_InitFrequencyMeasurement(dev,
- CR_AREF(insn->chanspec),
- (unsigned char) data[0],
- (unsigned char) data[1], (unsigned int) data[2], (unsigned int *) &data[0]);
- break;
-
- default:
- printk("Insn Config : Config Parameter Wrong\n");
-
- }
-
- if (i_ReturnValue >= 0)
- i_ReturnValue = insn->n;
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ClearCounterValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Task : Clear the counter value from selected module |
-| (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The selected module number parameter is wrong |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ClearCounterValue(struct comedi_device *dev,
- unsigned char b_ModulNbr)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*********************/
- /* Clear the counter */
- /*********************/
-
- outl(1, devpriv->s_BoardInfos.
- ui_Address + 16 + (64 * b_ModulNbr));
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ClearAllCounterValue |
-| (unsigned char_ b_BoardHandle) |
-+----------------------------------------------------------------------------+
-| Task : Clear all counter value. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ClearAllCounterValue(struct comedi_device *dev)
-{
- struct addi_private *devpriv = dev->private;
- unsigned char b_ModulCpt = 0;
- int i_ReturnValue = 0;
-
- /********************************/
- /* Test if counter module found */
- /********************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[0] & 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER
- || (devpriv->s_BoardInfos.
- dw_MolduleConfiguration[1] & 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER
- || (devpriv->s_BoardInfos.
- dw_MolduleConfiguration[2] & 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER
- || (devpriv->s_BoardInfos.
- dw_MolduleConfiguration[3] & 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER) {
- for (b_ModulCpt = 0; b_ModulCpt < 4; b_ModulCpt++) {
- /*******************************/
- /* Test if incremental counter */
- /*******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulCpt] &
- 0xFFFF0000UL) ==
- APCI1710_INCREMENTAL_COUNTER) {
- /*********************/
- /* Clear the counter */
- /*********************/
-
- outl(1, devpriv->s_BoardInfos.
- ui_Address + 16 + (64 * b_ModulCpt));
- }
- }
- } else {
- /***************************/
- /* No counter module found */
- /***************************/
-
- DPRINTK("No counter module found\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_SetInputFilter |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_Module, |
-| unsigned char_ b_PCIInputClock, |
-| unsigned char_ b_Filter) |
-+----------------------------------------------------------------------------+
-| Task : Disable or enable the software filter from selected |
-| module (b_ModulNbr). b_Filter determine the filter time|
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Number of the module to be |
-| configured (0 to 3) |
-| unsigned char_ b_PCIInputClock : Selection of the PCI bus |
-| clock |
-| - APCI1710_30MHZ : |
-| The PC has a PCI bus clock |
-| of 30 MHz |
-| - APCI1710_33MHZ : |
-| The PC has a PCI bus clock |
-| of 33 MHz |
-| - APCI1710_40MHZ : |
-| The APCI1710 has a 40MHz |
-| quartz |
-| unsigned char_ b_Filter : Filter selection |
-| |
-| 30 MHz |
-| ------ |
-| 0: Software filter not used |
-| 1: Filter from 266ns (3.750000MHz) |
-| 2: Filter from 400ns (2.500000MHz) |
-| 3: Filter from 533ns (1.876170MHz) |
-| 4: Filter from 666ns (1.501501MHz) |
-| 5: Filter from 800ns (1.250000MHz) |
-| 6: Filter from 933ns (1.071800MHz) |
-| 7: Filter from 1066ns (0.938080MHz) |
-| 8: Filter from 1200ns (0.833333MHz) |
-| 9: Filter from 1333ns (0.750000MHz) |
-| 10: Filter from 1466ns (0.682100MHz) |
-| 11: Filter from 1600ns (0.625000MHz) |
-| 12: Filter from 1733ns (0.577777MHz) |
-| 13: Filter from 1866ns (0.535900MHz) |
-| 14: Filter from 2000ns (0.500000MHz) |
-| 15: Filter from 2133ns (0.468800MHz) |
-| |
-| 33 MHz |
-| ------ |
-| 0: Software filter not used |
-| 1: Filter from 242ns (4.125000MHz) |
-| 2: Filter from 363ns (2.754820MHz) |
-| 3: Filter from 484ns (2.066115MHz) |
-| 4: Filter from 605ns (1.652892MHz) |
-| 5: Filter from 726ns (1.357741MHz) |
-| 6: Filter from 847ns (1.180637MHz) |
-| 7: Filter from 968ns (1.033055MHz) |
-| 8: Filter from 1089ns (0.918273MHz) |
-| 9: Filter from 1210ns (0.826446MHz) |
-| 10: Filter from 1331ns (0.751314MHz) |
-| 11: Filter from 1452ns (0.688705MHz) |
-| 12: Filter from 1573ns (0.635727MHz) |
-| 13: Filter from 1694ns (0.590318MHz) |
-| 14: Filter from 1815ns (0.550964MHz) |
-| 15: Filter from 1936ns (0.516528MHz) |
-| |
-| 40 MHz |
-| ------ |
-| 0: Software filter not used |
-| 1: Filter from 200ns (5.000000MHz) |
-| 2: Filter from 300ns (3.333333MHz) |
-| 3: Filter from 400ns (2.500000MHz) |
-| 4: Filter from 500ns (2.000000MHz) |
-| 5: Filter from 600ns (1.666666MHz) |
-| 6: Filter from 700ns (1.428500MHz) |
-| 7: Filter from 800ns (1.250000MHz) |
-| 8: Filter from 900ns (1.111111MHz) |
-| 9: Filter from 1000ns (1.000000MHz) |
-| 10: Filter from 1100ns (0.909090MHz) |
-| 11: Filter from 1200ns (0.833333MHz) |
-| 12: Filter from 1300ns (0.769200MHz) |
-| 13: Filter from 1400ns (0.714200MHz) |
-| 14: Filter from 1500ns (0.666666MHz) |
-| 15: Filter from 1600ns (0.625000MHz) |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The selected module number is wrong |
-| -3: The module is not a counter module |
-| -4: The selected PCI input clock is wrong |
-| -5: The selected filter value is wrong |
-| -6: 40MHz quartz not on board |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_SetInputFilter(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_PCIInputClock,
- unsigned char b_Filter)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_Status = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if incremental counter */
- /*******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) {
- /******************************/
- /* Test if firmware >= Rev1.5 */
- /******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF) >= 0x3135) {
- /**************************/
- /* Test the PCI bus clock */
- /**************************/
-
- if ((b_PCIInputClock == APCI1710_30MHZ) ||
- (b_PCIInputClock == APCI1710_33MHZ) ||
- (b_PCIInputClock == APCI1710_40MHZ)) {
- /*************************/
- /* Test the filter value */
- /*************************/
-
- if (b_Filter < 16) {
- /**********************/
- /* Test if 40MHz used */
- /**********************/
-
- if (b_PCIInputClock ==
- APCI1710_40MHZ) {
- /*********************************/
- /* Test if 40MHz quartz on board */
- /*********************************/
-
- dw_Status =
- inl(devpriv->
- s_BoardInfos.
- ui_Address +
- 36 +
- (64 * b_ModulNbr));
-
- /******************************/
- /* Test the quartz flag (DQ0) */
- /******************************/
-
- if ((dw_Status & 1) !=
- 1) {
- /*****************************/
- /* 40MHz quartz not on board */
- /*****************************/
-
- DPRINTK("40MHz quartz not on board\n");
- i_ReturnValue =
- -6;
- }
- } /* if (b_PCIInputClock == APCI1710_40MHZ) */
-
- /***************************/
- /* Test if error not occur */
- /***************************/
-
- if (i_ReturnValue == 0) {
- /**********************/
- /* Test if 40MHz used */
- /**********************/
-
- if (b_PCIInputClock ==
- APCI1710_40MHZ)
- {
- /*********************************/
- /* Enable the 40MHz quarz (DQ31) */
- /*********************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- |
- APCI1710_ENABLE_40MHZ_FILTER;
-
- } /* if (b_PCIInputClock == APCI1710_40MHZ) */
- else {
- /**********************************/
- /* Disable the 40MHz quarz (DQ31) */
- /**********************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- &
- APCI1710_DISABLE_40MHZ_FILTER;
-
- } /* if (b_PCIInputClock == APCI1710_40MHZ) */
-
- /************************/
- /* Set the filter value */
- /************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3
- =
- (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3
- & 0x1F) |
- ((b_Filter &
- 0x7) <<
- 5);
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- =
- (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4
- & 0xFE) |
- ((b_Filter &
- 0x8) >>
- 3);
-
- /***************************/
- /* Write the configuration */
- /***************************/
-
- outl(devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4,
- devpriv->
- s_BoardInfos.
- ui_Address +
- 20 +
- (64 * b_ModulNbr));
- } /* if (i_ReturnValue == 0) */
- } /* if (b_Filter < 16) */
- else {
- /**************************************/
- /* The selected filter value is wrong */
- /**************************************/
-
- DPRINTK("The selected filter value is wrong\n");
- i_ReturnValue = -5;
- } /* if (b_Filter < 16) */
- } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) */
- else {
- /*****************************************/
- /* The selected PCI input clock is wrong */
- /*****************************************/
-
- DPRINTK("The selected PCI input clock is wrong\n");
- i_ReturnValue = 4;
- } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) */
- } else {
- /**************************************/
- /* The module is not a counter module */
- /**************************************/
-
- DPRINTK("The module is not a counter module\n");
- i_ReturnValue = -3;
- }
- } else {
- /**************************************/
- /* The module is not a counter module */
- /**************************************/
-
- DPRINTK("The module is not a counter module\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_LatchCounter (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_LatchReg) |
-+----------------------------------------------------------------------------+
-| Task : Latch the courant value from selected module |
-| (b_ModulNbr) in to the selected latch register |
-| (b_LatchReg). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| unsigned char_ b_LatchReg : Selected latch register |
-| 0 : for the first latch register |
-| 1 : for the second latch register |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: The selected latch register parameter is wrong |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_LatchCounter(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_LatchReg)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*************************************/
- /* Test the latch register parameter */
- /*************************************/
-
- if (b_LatchReg < 2) {
- /*********************/
- /* Tatch the counter */
- /*********************/
-
- outl(1 << (b_LatchReg * 4),
- devpriv->s_BoardInfos.ui_Address +
- (64 * b_ModulNbr));
- } else {
- /**************************************************/
- /* The selected latch register parameter is wrong */
- /**************************************************/
-
- DPRINTK("The selected latch register parameter is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_SetIndexAndReferenceSource |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_SourceSelection) |
-+----------------------------------------------------------------------------+
-| Task : Determine the hardware source for the index and the |
-| reference logic. Per default the index logic is |
-| connected to the difference input C and the reference |
-| logic is connected to the 24V input E |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| unsigned char_ b_SourceSelection : APCI1710_SOURCE_0 : |
-| The index logic is connected |
-| to the difference input C and|
-| the reference logic is |
-| connected to the 24V input E.|
-| This is the default |
-| configuration. |
-| APCI1710_SOURCE_1 : |
-| The reference logic is |
-| connected to the difference |
-| input C and the index logic |
-| is connected to the 24V |
-| input E |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The selected module number is wrong |
-| -3: The module is not a counter module. |
-| -4: The source selection is wrong |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_SetIndexAndReferenceSource(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_SourceSelection)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if incremental counter */
- /*******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) {
- /******************************/
- /* Test if firmware >= Rev1.5 */
- /******************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF) >= 0x3135) {
- /*****************************/
- /* Test the source selection */
- /*****************************/
-
- if (b_SourceSelection == APCI1710_SOURCE_0 ||
- b_SourceSelection == APCI1710_SOURCE_1)
- {
- /******************************************/
- /* Test if invert the index and reference */
- /******************************************/
-
- if (b_SourceSelection ==
- APCI1710_SOURCE_1) {
- /********************************************/
- /* Invert index and reference source (DQ25) */
- /********************************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4 =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4 |
- APCI1710_INVERT_INDEX_RFERENCE;
- } else {
- /****************************************/
- /* Set the default configuration (DQ25) */
- /****************************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4 =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister4 &
- APCI1710_DEFAULT_INDEX_RFERENCE;
- }
- } /* if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) */
- else {
- /*********************************/
- /* The source selection is wrong */
- /*********************************/
-
- DPRINTK("The source selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) */
- } else {
- /**************************************/
- /* The module is not a counter module */
- /**************************************/
-
- DPRINTK("The module is not a counter module\n");
- i_ReturnValue = -3;
- }
- } else {
- /**************************************/
- /* The module is not a counter module */
- /**************************************/
-
- DPRINTK("The module is not a counter module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***************************************/
- /* The selected module number is wrong */
- /***************************************/
-
- DPRINTK("The selected module number is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_SetDigitalChlOn |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Task : Sets the digital output H Setting an output means |
-| setting an ouput high. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Number of the module to be |
-| configured (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The selected module number is wrong |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_SetDigitalChlOn(struct comedi_device *dev,
- unsigned char b_ModulNbr)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.b_ModeRegister3 | 0x10;
-
- /*********************/
- /* Set the output On */
- /*********************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos.
- ui_Address + 20 + (64 * b_ModulNbr));
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_SetDigitalChlOff |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Task : Resets the digital output H. Resetting an output means |
-| setting an ouput low. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Number of the module to be |
-| configured (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The selected module number is wrong |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_SetDigitalChlOff(struct comedi_device *dev,
- unsigned char b_ModulNbr)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.b_ModeRegister3 & 0xEF;
-
- /**********************/
- /* Set the output Off */
- /**********************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos.
- ui_Address + 20 + (64 * b_ModulNbr));
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
- * Set & Clear Functions for INC_CPT
- */
-static int i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- unsigned int ui_BitsType;
- int i_ReturnValue = 0;
-
- ui_BitsType = CR_CHAN(insn->chanspec);
- devpriv->tsk_Current = current; /* Save the current process task structure */
-
- switch (ui_BitsType) {
- case APCI1710_INCCPT_CLEARCOUNTERVALUE:
- i_ReturnValue = i_APCI1710_ClearCounterValue(dev,
- (unsigned char) CR_AREF(insn->chanspec));
- break;
-
- case APCI1710_INCCPT_CLEARALLCOUNTERVALUE:
- i_ReturnValue = i_APCI1710_ClearAllCounterValue(dev);
- break;
-
- case APCI1710_INCCPT_SETINPUTFILTER:
- i_ReturnValue = i_APCI1710_SetInputFilter(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned char) data[0], (unsigned char) data[1]);
- break;
-
- case APCI1710_INCCPT_LATCHCOUNTER:
- i_ReturnValue = i_APCI1710_LatchCounter(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]);
- break;
-
- case APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE:
- i_ReturnValue = i_APCI1710_SetIndexAndReferenceSource(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]);
- break;
-
- case APCI1710_INCCPT_SETDIGITALCHLON:
- i_ReturnValue = i_APCI1710_SetDigitalChlOn(dev,
- (unsigned char) CR_AREF(insn->chanspec));
- break;
-
- case APCI1710_INCCPT_SETDIGITALCHLOFF:
- i_ReturnValue = i_APCI1710_SetDigitalChlOff(dev,
- (unsigned char) CR_AREF(insn->chanspec));
- break;
-
- default:
- printk("Bits Config Parameter Wrong\n");
- }
-
- if (i_ReturnValue >= 0)
- i_ReturnValue = insn->n;
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_EnableLatchInterrupt |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Task : Enable the latch interrupt from selected module |
-| (b_ModulNbr). Each software or hardware latch occur a |
-| interrupt. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Interrupt routine not installed see function |
-| "i_APCI1710_SetBoardIntRoutine" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_EnableLatchInterrupt(struct comedi_device *dev,
- unsigned char b_ModulNbr)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-
- /********************/
- /* Enable interrupt */
- /********************/
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 | APCI1710_ENABLE_LATCH_INT;
-
- /***************************/
- /* Write the configuration */
- /***************************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos.
- ui_Address + 20 + (64 * b_ModulNbr));
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_DisableLatchInterrupt |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Task : Disable the latch interrupt from selected module |
-| (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Interrupt routine not installed see function |
-| "i_APCI1710_SetBoardIntRoutine" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_DisableLatchInterrupt(struct comedi_device *dev,
- unsigned char b_ModulNbr)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-
- /***************************/
- /* Write the configuration */
- /***************************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4 &
- ((APCI1710_DISABLE_LATCH_INT << 8) | 0xFF),
- devpriv->s_BoardInfos.ui_Address + 20 +
- (64 * b_ModulNbr));
-
- mdelay(1000);
-
- /*********************/
- /* Disable interrupt */
- /*********************/
-
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 & APCI1710_DISABLE_LATCH_INT;
-
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_Write16BitCounterValue |
-| (unsigned char_ b_BoardHandle |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_SelectedCounter, |
-| unsigned int_ ui_WriteValue) |
-+----------------------------------------------------------------------------+
-| Task : Write a 16-Bit value (ui_WriteValue) in to the selected|
-| 16-Bit counter (b_SelectedCounter) from selected module|
-| (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| unsigned char_ b_SelectedCounter : Selected 16-Bit counter |
-| (0 or 1) |
-| unsigned int_ ui_WriteValue : 16-Bit write value |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: The selected 16-Bit counter parameter is wrong |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_Write16BitCounterValue(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_SelectedCounter,
- unsigned int ui_WriteValue)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /******************************/
- /* Test the counter selection */
- /******************************/
-
- if (b_SelectedCounter < 2) {
- /*******************/
- /* Write the value */
- /*******************/
-
- outl((unsigned int) ((unsigned int) (ui_WriteValue) << (16 *
- b_SelectedCounter)),
- devpriv->s_BoardInfos.ui_Address + 8 +
- (b_SelectedCounter * 4) +
- (64 * b_ModulNbr));
- } else {
- /**************************************************/
- /* The selected 16-Bit counter parameter is wrong */
- /**************************************************/
-
- DPRINTK("The selected 16-Bit counter parameter is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_Write32BitCounterValue |
-| (unsigned char_ b_BoardHandle |
-| unsigned char_ b_ModulNbr, |
-| ULONG_ ul_WriteValue) |
-+----------------------------------------------------------------------------+
-| Task : Write a 32-Bit value (ui_WriteValue) in to the selected|
-| module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| ULONG_ ul_WriteValue : 32-Bit write value |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_Write32BitCounterValue(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned int ul_WriteValue)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*******************/
- /* Write the value */
- /*******************/
-
- outl(ul_WriteValue, devpriv->s_BoardInfos.
- ui_Address + 4 + (64 * b_ModulNbr));
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_EnableIndex (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Task : Enable the INDEX actions |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Index not initialised see function |
-| "i_APCI1710_InitIndex" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_EnableIndex(struct comedi_device *dev,
- unsigned char b_ModulNbr)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int ul_InterruptLatchReg;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*****************************/
- /* Test if index initialised */
- /*****************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_IndexInit) {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 | APCI1710_ENABLE_INDEX;
-
- ul_InterruptLatchReg =
- inl(devpriv->s_BoardInfos.ui_Address +
- 24 + (64 * b_ModulNbr));
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4,
- devpriv->s_BoardInfos.ui_Address + 20 +
- (64 * b_ModulNbr));
- } else {
- /*************************************************************/
- /* Index not initialised see function "i_APCI1710_InitIndex" */
- /*************************************************************/
-
- DPRINTK("Index not initialised \n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_DisableIndex (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Task : Disable the INDEX actions |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Index not initialised see function |
-| "i_APCI1710_InitIndex" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_DisableIndex(struct comedi_device *dev,
- unsigned char b_ModulNbr)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*****************************/
- /* Test if index initialised */
- /*****************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_IndexInit) {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 &
- APCI1710_DISABLE_INDEX;
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4,
- devpriv->s_BoardInfos.ui_Address + 20 +
- (64 * b_ModulNbr));
- } else {
- /*************************************************************/
- /* Index not initialised see function "i_APCI1710_InitIndex" */
- /*************************************************************/
-
- DPRINTK("Index not initialised \n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_EnableCompareLogic |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Task : Enable the 32-Bit compare logic. At that moment that |
-| the incremental counter arrive to the compare value a |
-| interrupt is generated. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : -
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Compare logic not initialised. |
-| See function "i_APCI1710_InitCompareLogic" |
-| -5: Interrupt function not initialised. |
-| See function "i_APCI1710_SetBoardIntRoutineX" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_EnableCompareLogic(struct comedi_device *dev,
- unsigned char b_ModulNbr)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*************************************/
- /* Test if compare logic initialised */
- /*************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_CompareLogicInit == 1) {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 |
- APCI1710_ENABLE_COMPARE_INT;
-
- /***************************/
- /* Write the configuration */
- /***************************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4,
- devpriv->s_BoardInfos.ui_Address + 20 +
- (64 * b_ModulNbr));
- } else {
- /*********************************/
- /* Compare logic not initialised */
- /*********************************/
-
- DPRINTK("Compare logic not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_DisableCompareLogic |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Task : Disable the 32-Bit compare logic.
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : -
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Compare logic not initialised. |
-| See function "i_APCI1710_InitCompareLogic" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_DisableCompareLogic(struct comedi_device *dev,
- unsigned char b_ModulNbr)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*************************************/
- /* Test if compare logic initialised */
- /*************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_CompareLogicInit == 1) {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 &
- APCI1710_DISABLE_COMPARE_INT;
-
- /***************************/
- /* Write the configuration */
- /***************************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4,
- devpriv->s_BoardInfos.ui_Address + 20 +
- (64 * b_ModulNbr));
- } else {
- /*********************************/
- /* Compare logic not initialised */
- /*********************************/
-
- DPRINTK("Compare logic not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
- /*
- +----------------------------------------------------------------------------+
- | Function Name : _INT_ i_APCI1710_EnableFrequencyMeasurement |
- | (unsigned char_ b_BoardHandle, |
- | unsigned char_ b_ModulNbr, |
- | unsigned char_ b_InterruptEnable) |
- +----------------------------------------------------------------------------+
- | Task : Enables the frequency measurement function |
- +----------------------------------------------------------------------------+
- | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
- | unsigned char_ b_ModulNbr : Number of the module to be |
- | configured (0 to 3) |
- | unsigned char_ b_InterruptEnable: Enable or disable the |
- | interrupt. |
- | APCI1710_ENABLE: |
- | Enable the interrupt |
- | APCI1710_DISABLE: |
- | Disable the interrupt |
- +----------------------------------------------------------------------------+
- | Output Parameters : - |
- +----------------------------------------------------------------------------+
- | Return Value : 0: No error |
- | -1: The handle parameter of the board is wrong |
- | -2: The selected module number is wrong |
- | -3: Counter not initialised see function |
- | "i_APCI1710_InitCounter" |
- | -4: Frequency measurement logic not initialised. |
- | See function "i_APCI1710_InitFrequencyMeasurement" |
- | -5: Interrupt parameter is wrong |
- | -6: Interrupt function not initialised. |
- +----------------------------------------------------------------------------+
- */
-static int i_APCI1710_EnableFrequencyMeasurement(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_InterruptEnable)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /********************************************/
- /* Test if frequency measurement initialised */
- /********************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_FrequencyMeasurementInit == 1) {
- /***************************/
- /* Test the interrupt mode */
- /***************************/
-
- if ((b_InterruptEnable == APCI1710_DISABLE) ||
- (b_InterruptEnable == APCI1710_ENABLE))
- {
-
- /************************************/
- /* Enable the frequency measurement */
- /************************************/
-
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 |
- APCI1710_ENABLE_FREQUENCY;
-
- /*********************************************/
- /* Disable or enable the frequency interrupt */
- /*********************************************/
-
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 = (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 &
- APCI1710_DISABLE_FREQUENCY_INT)
- | (b_InterruptEnable << 3);
-
- /***************************/
- /* Write the configuration */
- /***************************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4,
- devpriv->s_BoardInfos.
- ui_Address + 20 +
- (64 * b_ModulNbr));
-
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.
- b_FrequencyMeasurementEnable =
- 1;
- } else {
- /********************************/
- /* Interrupt parameter is wrong */
- /********************************/
-
- DPRINTK("Interrupt parameter is wrong\n");
- i_ReturnValue = -5;
- }
- } else {
- /***********************************************/
- /* Frequency measurement logic not initialised */
- /***********************************************/
-
- DPRINTK("Frequency measurement logic not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
- /*
- +----------------------------------------------------------------------------+
- | Function Name : _INT_ i_APCI1710_DisableFrequencyMeasurement |
- | (unsigned char_ b_BoardHandle, |
- | unsigned char_ b_ModulNbr) |
- +----------------------------------------------------------------------------+
- | Task : Disables the frequency measurement function |
- +----------------------------------------------------------------------------+
- | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
- | unsigned char_ b_ModulNbr : Number of the module to be |
- | configured (0 to 3) |
- +----------------------------------------------------------------------------+
- | Output Parameters : - |
- +----------------------------------------------------------------------------+
- | Return Value : 0: No error |
- | -1: The handle parameter of the board is wrong |
- | -2: The selected module number is wrong |
- | -3: Counter not initialised see function |
- | "i_APCI1710_InitCounter" |
- | -4: Frequency measurement logic not initialised. |
- | See function "i_APCI1710_InitFrequencyMeasurement" |
- +----------------------------------------------------------------------------+
- */
-static int i_APCI1710_DisableFrequencyMeasurement(struct comedi_device *dev,
- unsigned char b_ModulNbr)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /********************************************/
- /* Test if frequency measurement initialised */
- /********************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_FrequencyMeasurementInit == 1) {
- /*************************************/
- /* Disable the frequency measurement */
- /*************************************/
-
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 &
- APCI1710_DISABLE_FREQUENCY
- /* Begin CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared */
- & APCI1710_DISABLE_FREQUENCY_INT;
- /* End CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared */
-
- /***************************/
- /* Write the configuration */
- /***************************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4,
- devpriv->s_BoardInfos.ui_Address + 20 +
- (64 * b_ModulNbr));
-
- /*************************************/
- /* Disable the frequency measurement */
- /*************************************/
-
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.
- b_FrequencyMeasurementEnable = 0;
- } else {
- /***********************************************/
- /* Frequency measurement logic not initialised */
- /***********************************************/
-
- DPRINTK("Frequency measurement logic not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
- * Enable Disable functions for INC_CPT
- */
-static int i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- unsigned int ui_WriteType;
- int i_ReturnValue = 0;
-
- ui_WriteType = CR_CHAN(insn->chanspec);
- devpriv->tsk_Current = current; /* Save the current process task structure */
-
- switch (ui_WriteType) {
- case APCI1710_INCCPT_ENABLELATCHINTERRUPT:
- i_ReturnValue = i_APCI1710_EnableLatchInterrupt(dev,
- (unsigned char) CR_AREF(insn->chanspec));
- break;
-
- case APCI1710_INCCPT_DISABLELATCHINTERRUPT:
- i_ReturnValue = i_APCI1710_DisableLatchInterrupt(dev,
- (unsigned char) CR_AREF(insn->chanspec));
- break;
-
- case APCI1710_INCCPT_WRITE16BITCOUNTERVALUE:
- i_ReturnValue = i_APCI1710_Write16BitCounterValue(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned char) data[0], (unsigned int) data[1]);
- break;
-
- case APCI1710_INCCPT_WRITE32BITCOUNTERVALUE:
- i_ReturnValue = i_APCI1710_Write32BitCounterValue(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned int) data[0]);
-
- break;
-
- case APCI1710_INCCPT_ENABLEINDEX:
- i_APCI1710_EnableIndex(dev, (unsigned char) CR_AREF(insn->chanspec));
- break;
-
- case APCI1710_INCCPT_DISABLEINDEX:
- i_ReturnValue = i_APCI1710_DisableIndex(dev,
- (unsigned char) CR_AREF(insn->chanspec));
- break;
-
- case APCI1710_INCCPT_ENABLECOMPARELOGIC:
- i_ReturnValue = i_APCI1710_EnableCompareLogic(dev,
- (unsigned char) CR_AREF(insn->chanspec));
- break;
-
- case APCI1710_INCCPT_DISABLECOMPARELOGIC:
- i_ReturnValue = i_APCI1710_DisableCompareLogic(dev,
- (unsigned char) CR_AREF(insn->chanspec));
- break;
-
- case APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT:
- i_ReturnValue = i_APCI1710_EnableFrequencyMeasurement(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]);
- break;
-
- case APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT:
- i_ReturnValue = i_APCI1710_DisableFrequencyMeasurement(dev,
- (unsigned char) CR_AREF(insn->chanspec));
- break;
-
- default:
- printk("Write Config Parameter Wrong\n");
- }
-
- if (i_ReturnValue >= 0)
- i_ReturnValue = insn->n;
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadLatchRegisterStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_LatchReg, |
-| unsigned char *_ pb_LatchStatus) |
-+----------------------------------------------------------------------------+
-| Task : Read the latch register status from selected module |
-| (b_ModulNbr) and selected latch register (b_LatchReg). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| unsigned char_ b_LatchReg : Selected latch register |
-| 0 : for the first latch register |
-| 1 : for the second latch register |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_LatchStatus : Latch register status. |
-| 0 : No latch occur |
-| 1 : A software latch occur |
-| 2 : A hardware latch occur |
-| 3 : A software and hardware |
-| latch occur |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: The selected latch register parameter is wrong |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ReadLatchRegisterStatus(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_LatchReg,
- unsigned char *pb_LatchStatus)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_LatchReg;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*************************************/
- /* Test the latch register parameter */
- /*************************************/
-
- if (b_LatchReg < 2) {
- dw_LatchReg = inl(devpriv->s_BoardInfos.
- ui_Address + (64 * b_ModulNbr));
-
- *pb_LatchStatus =
- (unsigned char) ((dw_LatchReg >> (b_LatchReg *
- 4)) & 0x3);
- } else {
- /**************************************************/
- /* The selected latch register parameter is wrong */
- /**************************************************/
-
- DPRINTK("The selected latch register parameter is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadLatchRegisterValue |
-| (unsigned char_ b_BoardHandle,|
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_LatchReg, |
-| PULONG_ pul_LatchValue) |
-+----------------------------------------------------------------------------+
-| Task : Read the latch register value from selected module |
-| (b_ModulNbr) and selected latch register (b_LatchReg). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| unsigned char_ b_LatchReg : Selected latch register |
-| 0 : for the first latch register |
-| 1 : for the second latch register |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_LatchValue : Latch register value |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: The selected latch register parameter is wrong |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ReadLatchRegisterValue(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_LatchReg,
- unsigned int *pul_LatchValue)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*************************************/
- /* Test the latch register parameter */
- /*************************************/
-
- if (b_LatchReg < 2) {
- *pul_LatchValue = inl(devpriv->s_BoardInfos.
- ui_Address + ((b_LatchReg + 1) * 4) +
- (64 * b_ModulNbr));
-
- } else {
- /**************************************************/
- /* The selected latch register parameter is wrong */
- /**************************************************/
-
- DPRINTK("The selected latch register parameter is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_Read16BitCounterValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_SelectedCounter, |
-| unsigned int *_ pui_CounterValue) |
-+----------------------------------------------------------------------------+
-| Task : Latch the selected 16-Bit counter (b_SelectedCounter) |
-| from selected module (b_ModulNbr) in to the first |
-| latch register and return the latched value. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| unsigned char_ b_SelectedCounter : Selected 16-Bit counter |
-| (0 or 1) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned int *_ pui_CounterValue : 16-Bit counter value |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: The selected 16-Bit counter parameter is wrong |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_Read16BitCounterValue(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_SelectedCounter,
- unsigned int *pui_CounterValue)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_LathchValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /******************************/
- /* Test the counter selection */
- /******************************/
-
- if (b_SelectedCounter < 2) {
- /*********************/
- /* Latch the counter */
- /*********************/
-
- outl(1, devpriv->s_BoardInfos.
- ui_Address + (64 * b_ModulNbr));
-
- /************************/
- /* Read the latch value */
- /************************/
-
- dw_LathchValue = inl(devpriv->s_BoardInfos.
- ui_Address + 4 + (64 * b_ModulNbr));
-
- *pui_CounterValue =
- (unsigned int) ((dw_LathchValue >> (16 *
- b_SelectedCounter)) &
- 0xFFFFU);
- } else {
- /**************************************************/
- /* The selected 16-Bit counter parameter is wrong */
- /**************************************************/
-
- DPRINTK("The selected 16-Bit counter parameter is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_Read32BitCounterValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| PULONG_ pul_CounterValue) |
-+----------------------------------------------------------------------------+
-| Task : Latch the 32-Bit counter from selected module |
-| (b_ModulNbr) in to the first latch register and return |
-| the latched value. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_CounterValue : 32-Bit counter value |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_Read32BitCounterValue(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned int *pul_CounterValue)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*********************/
- /* Tatch the counter */
- /*********************/
-
- outl(1, devpriv->s_BoardInfos.
- ui_Address + (64 * b_ModulNbr));
-
- /************************/
- /* Read the latch value */
- /************************/
-
- *pul_CounterValue = inl(devpriv->s_BoardInfos.
- ui_Address + 4 + (64 * b_ModulNbr));
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetIndexStatus (unsigned char_ b_BoardHandle,|
-| unsigned char_ b_ModulNbr, |
-| unsigned char *_ pb_IndexStatus)|
-+----------------------------------------------------------------------------+
-| Task : Return the index status |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_IndexStatus : 0 : No INDEX occur |
-| 1 : A INDEX occur |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Index not initialised see function |
-| "i_APCI1710_InitIndex" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetIndexStatus(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char *pb_IndexStatus)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*****************************/
- /* Test if index initialised */
- /*****************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_IndexInit) {
- dw_StatusReg = inl(devpriv->s_BoardInfos.
- ui_Address + 12 + (64 * b_ModulNbr));
-
- *pb_IndexStatus = (unsigned char) (dw_StatusReg & 1);
- } else {
- /*************************************************************/
- /* Index not initialised see function "i_APCI1710_InitIndex" */
- /*************************************************************/
-
- DPRINTK("Index not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetReferenceStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char *_ pb_ReferenceStatus) |
-+----------------------------------------------------------------------------+
-| Task : Return the reference status |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_ReferenceStatus : 0 : No REFERENCE occur |
-| 1 : A REFERENCE occur |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Reference not initialised see function |
-| "i_APCI1710_InitReference" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetReferenceStatus(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char *pb_ReferenceStatus)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*********************************/
- /* Test if reference initialised */
- /*********************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_ReferenceInit) {
- dw_StatusReg = inl(devpriv->s_BoardInfos.
- ui_Address + 24 + (64 * b_ModulNbr));
-
- *pb_ReferenceStatus =
- (unsigned char) (~dw_StatusReg & 1);
- } else {
- /*********************************************************************/
- /* Reference not initialised see function "i_APCI1710_InitReference" */
- /*********************************************************************/
-
- DPRINTK("Reference not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetUASStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char *_ pb_UASStatus) |
-+----------------------------------------------------------------------------+
-| Task : Return the error signal (UAS) status |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_UASStatus : 0 : UAS is low "0" |
-| 1 : UAS is high "1" |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetUASStatus(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char *pb_UASStatus)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- dw_StatusReg = inl(devpriv->s_BoardInfos.
- ui_Address + 24 + (64 * b_ModulNbr));
-
- *pb_UASStatus = (unsigned char) ((dw_StatusReg >> 1) & 1);
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
-
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetCBStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char *_ pb_CBStatus) |
-+----------------------------------------------------------------------------+
-| Task : Return the counter overflow status |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_CBStatus : 0 : Counter no overflow |
-| 1 : Counter overflow |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetCBStatus(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char *pb_CBStatus)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- dw_StatusReg = inl(devpriv->s_BoardInfos.
- ui_Address + 16 + (64 * b_ModulNbr));
-
- *pb_CBStatus = (unsigned char) (dw_StatusReg & 1);
-
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_Get16BitCBStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char *_ pb_CBStatusCounter0, |
-| unsigned char *_ pb_CBStatusCounter1) |
-+----------------------------------------------------------------------------+
-| Task : Returns the counter overflow (counter initialised to |
-| 2*16-bit) status from selected incremental counter |
-| module |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_CBStatusCounter0 : 0 : No overflow occur for |
-| the first 16-bit |
-| counter |
-| 1 : Overflow occur for the|
-| first 16-bit counter |
-| unsigned char *_ pb_CBStatusCounter1 : 0 : No overflow occur for |
-| the second 16-bit |
-| counter |
-| 1 : Overflow occur for the|
-| second 16-bit counter |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Counter not initialised to 2*16-bit mode. |
-| See function "i_APCI1710_InitCounter" |
-| -5: Firmware revision error |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_Get16BitCBStatus(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char *pb_CBStatusCounter0,
- unsigned char *pb_CBStatusCounter1)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*************************/
- /* Test if 2*16-Bit mode */
- /*************************/
-
- if ((devpriv->s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister1 & 0x10) == 0x10) {
- /*****************************/
- /* Test the Firmware version */
- /*****************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr] & 0xFFFF) >=
- 0x3136) {
- dw_StatusReg =
- inl(devpriv->s_BoardInfos.
- ui_Address + 16 +
- (64 * b_ModulNbr));
-
- *pb_CBStatusCounter1 =
- (unsigned char) ((dw_StatusReg >> 0) &
- 1);
- *pb_CBStatusCounter0 =
- (unsigned char) ((dw_StatusReg >> 1) &
- 1);
- } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) */
- else {
- /****************************/
- /* Firmware revision error */
- /****************************/
-
- i_ReturnValue = -5;
- } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) */
- } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) */
- else {
- /********************************************/
- /* Counter not initialised to 2*16-bit mode */
- /* "i_APCI1710_InitCounter" */
- /********************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -4;
- } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) */
- } /* if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) */
- else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- } /* if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) */
- } /* if (b_ModulNbr < 4) */
- else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- } /* if (b_ModulNbr < 4) */
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetUDStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char *_ pb_UDStatus) |
-+----------------------------------------------------------------------------+
-| Task : Return the counter progress status |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_UDStatus : 0 : Counter progress in the |
-| selected mode down |
-| 1 : Counter progress in the |
-| selected mode up |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetUDStatus(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char *pb_UDStatus)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- dw_StatusReg = inl(devpriv->s_BoardInfos.
- ui_Address + 24 + (64 * b_ModulNbr));
-
- *pb_UDStatus = (unsigned char) ((dw_StatusReg >> 2) & 1);
-
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetInterruptUDLatchedStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char *_ pb_UDStatus) |
-+----------------------------------------------------------------------------+
-| Task : Return the counter progress latched status after a |
-| index interrupt occur. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_UDStatus : 0 : Counter progress in the |
-| selected mode down |
-| 1 : Counter progress in the |
-| selected mode up |
-| 2 : No index interrupt occur |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: No counter module found |
-| -3: Counter not initialised see function |
-| "i_APCI1710_InitCounter" |
-| -4: Interrupt function not initialised. |
-| See function "i_APCI1710_SetBoardIntRoutineX" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char *pb_UDStatus)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /*********************************/
- /* Test if index interrupt occur */
- /*********************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_IndexInterruptOccur == 1) {
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_IndexInterruptOccur = 0;
-
- dw_StatusReg = inl(devpriv->s_BoardInfos.
- ui_Address + 12 + (64 * b_ModulNbr));
-
- *pb_UDStatus = (unsigned char) ((dw_StatusReg >> 1) & 1);
- } else {
- /****************************/
- /* No index interrupt occur */
- /****************************/
-
- *pb_UDStatus = 2;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
- /*
- +----------------------------------------------------------------------------+
- | Function Name : _INT_ i_APCI1710_ReadFrequencyMeasurement |
- | (unsigned char_ b_BoardHandle, |
- | unsigned char_ b_ModulNbr, |
- | unsigned char *_ pb_Status, |
- | PULONG_ pul_ReadValue) |
- +----------------------------------------------------------------------------+
- | Task : Returns the status (pb_Status) and the number of |
- | increments in the set time. |
- | See function " i_APCI1710_InitFrequencyMeasurement " |
- +----------------------------------------------------------------------------+
- | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
- | unsigned char_ b_ModulNbr : Number of the module to be |
- | configured (0 to 3) |
- +----------------------------------------------------------------------------+
- | Output Parameters : unsigned char *_ pb_Status : Returns the frequency |
- | measurement status |
- | 0 : Counting cycle not |
- | started. |
- | 1 : Counting cycle started. |
- | 2 : Counting cycle stopped. |
- | The measurement cycle is |
- | completed. |
- | unsigned char *_ pb_UDStatus : 0 : Counter progress in the |
- | selected mode down |
- | 1 : Counter progress in the |
- | selected mode up |
- | PULONG_ pul_ReadValue : Return the number of |
- | increments in the defined |
- | time base. |
- +----------------------------------------------------------------------------+
- | Return Value : 0: No error |
- | -1: The handle parameter of the board is wrong |
- | -2: The selected module number is wrong |
- | -3: Counter not initialised see function |
- | "i_APCI1710_InitCounter" |
- | -4: Frequency measurement logic not initialised. |
- | See function "i_APCI1710_InitFrequencyMeasurement" |
- +----------------------------------------------------------------------------+
- */
-static int i_APCI1710_ReadFrequencyMeasurement(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char *pb_Status,
- unsigned char *pb_UDStatus,
- unsigned int *pul_ReadValue)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int ui_16BitValue;
- unsigned int dw_StatusReg;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
- /********************************************/
- /* Test if frequency measurement initialised */
- /********************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.b_FrequencyMeasurementInit == 1) {
- /******************/
- /* Test if enable */
- /******************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SiemensCounterInfo.
- s_InitFlag.
- b_FrequencyMeasurementEnable == 1) {
- /*******************/
- /* Read the status */
- /*******************/
-
- dw_StatusReg =
- inl(devpriv->s_BoardInfos.
- ui_Address + 32 +
- (64 * b_ModulNbr));
-
- /**************************/
- /* Test if frequency stop */
- /**************************/
-
- if (dw_StatusReg & 1) {
- *pb_Status = 2;
- *pb_UDStatus =
- (unsigned char) ((dw_StatusReg >>
- 1) & 3);
-
- /******************/
- /* Read the value */
- /******************/
-
- *pul_ReadValue =
- inl(devpriv->
- s_BoardInfos.
- ui_Address + 28 +
- (64 * b_ModulNbr));
-
- if (*pb_UDStatus == 0) {
- /*************************/
- /* Test the counter mode */
- /*************************/
-
- if ((devpriv->s_ModuleInfo[b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & APCI1710_16BIT_COUNTER) == APCI1710_16BIT_COUNTER) {
- /****************************************/
- /* Test if 16-bit counter 1 pulse occur */
- /****************************************/
-
- if ((*pul_ReadValue & 0xFFFFU) != 0) {
- ui_16BitValue
- =
- (unsigned int)
- *
- pul_ReadValue
- &
- 0xFFFFU;
- *pul_ReadValue
- =
- (*pul_ReadValue
- &
- 0xFFFF0000UL)
- |
- (0xFFFFU
- -
- ui_16BitValue);
- }
-
- /****************************************/
- /* Test if 16-bit counter 2 pulse occur */
- /****************************************/
-
- if ((*pul_ReadValue & 0xFFFF0000UL) != 0) {
- ui_16BitValue
- =
- (unsigned int)
- (
- (*pul_ReadValue
- >>
- 16)
- &
- 0xFFFFU);
- *pul_ReadValue
- =
- (*pul_ReadValue
- &
- 0xFFFFUL)
- |
- (
- (0xFFFFU - ui_16BitValue) << 16);
- }
- } else {
- if (*pul_ReadValue != 0) {
- *pul_ReadValue
- =
- 0xFFFFFFFFUL
- -
- *pul_ReadValue;
- }
- }
- } else {
- if (*pb_UDStatus == 1) {
- /****************************************/
- /* Test if 16-bit counter 2 pulse occur */
- /****************************************/
-
- if ((*pul_ReadValue & 0xFFFF0000UL) != 0) {
- ui_16BitValue
- =
- (unsigned int)
- (
- (*pul_ReadValue
- >>
- 16)
- &
- 0xFFFFU);
- *pul_ReadValue
- =
- (*pul_ReadValue
- &
- 0xFFFFUL)
- |
- (
- (0xFFFFU - ui_16BitValue) << 16);
- }
- } else {
- if (*pb_UDStatus
- == 2) {
- /****************************************/
- /* Test if 16-bit counter 1 pulse occur */
- /****************************************/
-
- if ((*pul_ReadValue & 0xFFFFU) != 0) {
- ui_16BitValue
- =
- (unsigned int)
- *
- pul_ReadValue
- &
- 0xFFFFU;
- *pul_ReadValue
- =
- (*pul_ReadValue
- &
- 0xFFFF0000UL)
- |
- (0xFFFFU
- -
- ui_16BitValue);
- }
- }
- }
- }
- } else {
- *pb_Status = 1;
- *pb_UDStatus = 0;
- }
- } else {
- *pb_Status = 0;
- *pb_UDStatus = 0;
- }
- } else {
- /***********************************************/
- /* Frequency measurement logic not initialised */
- /***********************************************/
-
- DPRINTK("Frequency measurement logic not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /****************************************/
- /* Counter not initialised see function */
- /* "i_APCI1710_InitCounter" */
- /****************************************/
-
- DPRINTK("Counter not initialised\n");
- i_ReturnValue = -3;
- }
- } else {
- /*************************************************/
- /* The selected module number parameter is wrong */
- /*************************************************/
-
- DPRINTK("The selected module number parameter is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-/*
- * Read and Get functions for INC_CPT
- */
-static int i_APCI1710_InsnReadINCCPT(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- unsigned int ui_ReadType;
- int i_ReturnValue = 0;
-
- ui_ReadType = CR_CHAN(insn->chanspec);
-
- devpriv->tsk_Current = current; /* Save the current process task structure */
- switch (ui_ReadType) {
- case APCI1710_INCCPT_READLATCHREGISTERSTATUS:
- i_ReturnValue = i_APCI1710_ReadLatchRegisterStatus(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned char) CR_RANGE(insn->chanspec), (unsigned char *) &data[0]);
- break;
-
- case APCI1710_INCCPT_READLATCHREGISTERVALUE:
- i_ReturnValue = i_APCI1710_ReadLatchRegisterValue(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned char) CR_RANGE(insn->chanspec), (unsigned int *) &data[0]);
- printk("Latch Register Value %d\n", data[0]);
- break;
-
- case APCI1710_INCCPT_READ16BITCOUNTERVALUE:
- i_ReturnValue = i_APCI1710_Read16BitCounterValue(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned char) CR_RANGE(insn->chanspec), (unsigned int *) &data[0]);
- break;
-
- case APCI1710_INCCPT_READ32BITCOUNTERVALUE:
- i_ReturnValue = i_APCI1710_Read32BitCounterValue(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned int *) &data[0]);
- break;
-
- case APCI1710_INCCPT_GETINDEXSTATUS:
- i_ReturnValue = i_APCI1710_GetIndexStatus(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
- break;
-
- case APCI1710_INCCPT_GETREFERENCESTATUS:
- i_ReturnValue = i_APCI1710_GetReferenceStatus(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
- break;
-
- case APCI1710_INCCPT_GETUASSTATUS:
- i_ReturnValue = i_APCI1710_GetUASStatus(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
- break;
-
- case APCI1710_INCCPT_GETCBSTATUS:
- i_ReturnValue = i_APCI1710_GetCBStatus(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
- break;
-
- case APCI1710_INCCPT_GET16BITCBSTATUS:
- i_ReturnValue = i_APCI1710_Get16BitCBStatus(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned char *) &data[0], (unsigned char *) &data[1]);
- break;
-
- case APCI1710_INCCPT_GETUDSTATUS:
- i_ReturnValue = i_APCI1710_GetUDStatus(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
-
- break;
-
- case APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS:
- i_ReturnValue = i_APCI1710_GetInterruptUDLatchedStatus(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
- break;
-
- case APCI1710_INCCPT_READFREQUENCYMEASUREMENT:
- i_ReturnValue = i_APCI1710_ReadFrequencyMeasurement(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned char *) &data[0],
- (unsigned char *) &data[1], (unsigned int *) &data[2]);
- break;
-
- case APCI1710_INCCPT_READINTERRUPT:
- data[0] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].b_OldModuleMask;
- data[1] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].ul_OldInterruptMask;
- data[2] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
- /**************************/
- /* Increment the read FIFO */
- /***************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Read = (devpriv->s_InterruptParameters.
- ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-
- break;
-
- default:
- printk("ReadType Parameter wrong\n");
- }
-
- if (i_ReturnValue >= 0)
- i_ReturnValue = insn->n;
- return i_ReturnValue;
-
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c
deleted file mode 100644
index 6bbcb06cc27..00000000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c
+++ /dev/null
@@ -1,866 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-----------------------------------------------------------------------+
- | Project : API APCI1710 | Compiler : gcc |
- | Module name : Inp_CPT.C | Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-----------------------------------------------------------------------+
- | Description : APCI-1710 pulse encoder module |
- | |
- | |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +-----------------------------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | | | |
- |----------|-----------|------------------------------------------------|
- | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 |
- | | | available |
- +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_SINGLE 0
-#define APCI1710_CONTINUOUS 1
-
-#define APCI1710_PULSEENCODER_READ 0
-#define APCI1710_PULSEENCODER_WRITE 1
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitPulseEncoder |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PulseEncoderNbr, |
-| unsigned char_ b_InputLevelSelection, |
-| unsigned char_ b_TriggerOutputAction, |
-| ULONG_ ul_StartValue) |
-+----------------------------------------------------------------------------+
-| Task : Configure the pulse encoder operating mode selected via|
-| b_ModulNbr and b_PulseEncoderNbr. The pulse encoder |
-| after each pulse decrement the counter value from 1. |
-| |
-| You must calling this function be for you call any |
-| other function witch access of pulse encoders. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710|
-| unsigned char_ b_ModulNbr : Module number to |
-| configure (0 to 3) |
-| unsigned char_ b_PulseEncoderNbr : Pulse encoder selection |
-| (0 to 3) |
-| unsigned char_ b_InputLevelSelection : Input level selection |
-| (0 or 1) |
-| 0 : Set pulse encoder|
-| count the the low|
-| level pulse. |
-| 1 : Set pulse encoder|
-| count the the |
-| high level pulse.|
-| unsigned char_ b_TriggerOutputAction : Digital TRIGGER output |
-| action |
-| 0 : No action |
-| 1 : Set the trigger |
-| output to "1" |
-| (high) after the |
-| passage from 1 to|
-| 0 from pulse |
-| encoder. |
-| 2 : Set the trigger |
-| output to "0" |
-| (low) after the |
-| passage from 1 to|
-| 0 from pulse |
-| encoder |
-| ULONG_ ul_StartValue : Pulse encoder start value|
-| (1 to 4294967295)
- b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec);
- b_PulseEncoderNbr =(unsigned char) data[0];
- b_InputLevelSelection =(unsigned char) data[1];
- b_TriggerOutputAction =(unsigned char) data[2];
- ul_StartValue =(unsigned int) data[3];
- |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module is not a pulse encoder module |
-| -3: Pulse encoder selection is wrong |
-| -4: Input level selection is wrong |
-| -5: Digital TRIGGER output action selection is wrong |
-| -6: Pulse encoder start value is wrong |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_IntRegister;
- unsigned char b_ModulNbr;
- unsigned char b_PulseEncoderNbr;
- unsigned char b_InputLevelSelection;
- unsigned char b_TriggerOutputAction;
- unsigned int ul_StartValue;
-
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_PulseEncoderNbr = (unsigned char) data[0];
- b_InputLevelSelection = (unsigned char) data[1];
- b_TriggerOutputAction = (unsigned char) data[2];
- ul_StartValue = (unsigned int) data[3];
-
- i_ReturnValue = insn->n;
-
- /***********************************/
- /* Test the selected module number */
- /***********************************/
-
- if (b_ModulNbr <= 3) {
- /*************************/
- /* Test if pulse encoder */
- /*************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- APCI1710_PULSE_ENCODER) ==
- APCI1710_PULSE_ENCODER) {
- /******************************************/
- /* Test the selected pulse encoder number */
- /******************************************/
-
- if (b_PulseEncoderNbr <= 3) {
- /************************/
- /* Test the input level */
- /************************/
-
- if ((b_InputLevelSelection == 0)
- || (b_InputLevelSelection == 1)) {
- /*******************************************/
- /* Test the ouput TRIGGER action selection */
- /*******************************************/
-
- if ((b_TriggerOutputAction <= 2)
- || (b_PulseEncoderNbr > 0)) {
- if (ul_StartValue > 1) {
-
- dw_IntRegister =
- inl(devpriv->
- s_BoardInfos.
- ui_Address +
- 20 +
- (64 * b_ModulNbr));
-
- /***********************/
- /* Set the start value */
- /***********************/
-
- outl(ul_StartValue,
- devpriv->
- s_BoardInfos.
- ui_Address +
- (b_PulseEncoderNbr
- * 4) +
- (64 * b_ModulNbr));
-
- /***********************/
- /* Set the input level */
- /***********************/
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister =
- (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister &
- (0xFFFFFFFFUL -
- (1UL << (8 + b_PulseEncoderNbr)))) | ((1UL & (~b_InputLevelSelection)) << (8 + b_PulseEncoderNbr));
-
- /*******************************/
- /* Test if output trigger used */
- /*******************************/
-
- if ((b_TriggerOutputAction > 0) && (b_PulseEncoderNbr > 1)) {
- /****************************/
- /* Enable the output action */
- /****************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister
- | (1UL
- << (4 + b_PulseEncoderNbr));
-
- /*********************************/
- /* Set the output TRIGGER action */
- /*********************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister
- =
- (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister
- &
- (0xFFFFFFFFUL
- -
- (1UL << (12 + b_PulseEncoderNbr)))) | ((1UL & (b_TriggerOutputAction - 1)) << (12 + b_PulseEncoderNbr));
- } else {
- /*****************************/
- /* Disable the output action */
- /*****************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister
- &
- (0xFFFFFFFFUL
- -
- (1UL << (4 + b_PulseEncoderNbr)));
- }
-
- /*************************/
- /* Set the configuration */
- /*************************/
-
- outl(devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister,
- devpriv->
- s_BoardInfos.
- ui_Address +
- 20 +
- (64 * b_ModulNbr));
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- s_PulseEncoderInfo
- [b_PulseEncoderNbr].
- b_PulseEncoderInit
- = 1;
- } else {
- /**************************************/
- /* Pulse encoder start value is wrong */
- /**************************************/
-
- DPRINTK("Pulse encoder start value is wrong\n");
- i_ReturnValue = -6;
- }
- } else {
- /****************************************************/
- /* Digital TRIGGER output action selection is wrong */
- /****************************************************/
-
- DPRINTK("Digital TRIGGER output action selection is wrong\n");
- i_ReturnValue = -5;
- }
- } else {
- /**********************************/
- /* Input level selection is wrong */
- /**********************************/
-
- DPRINTK("Input level selection is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /************************************/
- /* Pulse encoder selection is wrong */
- /************************************/
-
- DPRINTK("Pulse encoder selection is wrong\n");
- i_ReturnValue = -3;
- }
- } else {
- /********************************************/
- /* The module is not a pulse encoder module */
- /********************************************/
-
- DPRINTK("The module is not a pulse encoder module\n");
- i_ReturnValue = -2;
- }
- } else {
- /********************************************/
- /* The module is not a pulse encoder module */
- /********************************************/
-
- DPRINTK("The module is not a pulse encoder module\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_EnablePulseEncoder |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PulseEncoderNbr, |
-| unsigned char_ b_CycleSelection, |
-| unsigned char_ b_InterruptHandling) |
-+----------------------------------------------------------------------------+
-| Task : Enableor disable the selected pulse encoder (b_PulseEncoderNbr) |
-| from selected module (b_ModulNbr). Each input pulse |
-| decrement the pulse encoder counter value from 1. |
-| If you enabled the interrupt (b_InterruptHandling), a |
-| interrupt is generated when the pulse encoder has run |
-| down. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710|
-| unsigned char_ b_ModulNbr : Module number to |
-| configure (0 to 3) |
-| unsigned char_ b_PulseEncoderNbr : Pulse encoder selection |
-| (0 to 3) |
-| unsigned char_ b_CycleSelection : APCI1710_CONTINUOUS: |
-| Each time the |
-| counting value is set|
-| on "0", the pulse |
-| encoder load the |
-| start value after |
-| the next pulse. |
-| APCI1710_SINGLE: |
-| If the counter is set|
-| on "0", the pulse |
-| encoder is stopped. |
-| unsigned char_ b_InterruptHandling : Interrupts can be |
-| generated, when the pulse|
-| encoder has run down. |
-| With this parameter the |
-| user decides if |
-| interrupts are used or |
-| not. |
-| APCI1710_ENABLE: |
-| Interrupts are enabled |
-| APCI1710_DISABLE: |
-| Interrupts are disabled
-
- b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec);
- b_Action =(unsigned char) data[0];
- b_PulseEncoderNbr =(unsigned char) data[1];
- b_CycleSelection =(unsigned char) data[2];
- b_InterruptHandling =(unsigned char) data[3];|
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection is wrong |
-| -3: Pulse encoder selection is wrong |
-| -4: Pulse encoder not initialised. |
-| See function "i_APCI1710_InitPulseEncoder" |
-| -5: Cycle selection mode is wrong |
-| -6: Interrupt handling mode is wrong |
-| -7: Interrupt routine not installed. |
-| See function "i_APCI1710_SetBoardIntRoutineX" |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned char b_ModulNbr;
- unsigned char b_PulseEncoderNbr;
- unsigned char b_CycleSelection;
- unsigned char b_InterruptHandling;
- unsigned char b_Action;
-
- i_ReturnValue = insn->n;
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_Action = (unsigned char) data[0];
- b_PulseEncoderNbr = (unsigned char) data[1];
- b_CycleSelection = (unsigned char) data[2];
- b_InterruptHandling = (unsigned char) data[3];
-
- /***********************************/
- /* Test the selected module number */
- /***********************************/
-
- if (b_ModulNbr <= 3) {
- /******************************************/
- /* Test the selected pulse encoder number */
- /******************************************/
-
- if (b_PulseEncoderNbr <= 3) {
- /*************************************/
- /* Test if pulse encoder initialised */
- /*************************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_PulseEncoderModuleInfo.
- s_PulseEncoderInfo[b_PulseEncoderNbr].
- b_PulseEncoderInit == 1) {
- switch (b_Action) {
-
- case APCI1710_ENABLE:
- /****************************/
- /* Test the cycle selection */
- /****************************/
-
- if (b_CycleSelection ==
- APCI1710_CONTINUOUS
- || b_CycleSelection ==
- APCI1710_SINGLE) {
- /*******************************/
- /* Test the interrupt handling */
- /*******************************/
-
- if (b_InterruptHandling ==
- APCI1710_ENABLE
- || b_InterruptHandling
- == APCI1710_DISABLE) {
- /******************************/
- /* Test if interrupt not used */
- /******************************/
-
- if (b_InterruptHandling
- ==
- APCI1710_DISABLE)
- {
- /*************************/
- /* Disable the interrupt */
- /*************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister
- &
- (0xFFFFFFFFUL
- -
- (1UL << b_PulseEncoderNbr));
- } else {
-
- /************************/
- /* Enable the interrupt */
- /************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister
- | (1UL
- <<
- b_PulseEncoderNbr);
- devpriv->tsk_Current = current; /* Save the current process task structure */
-
- }
-
- if (i_ReturnValue >= 0) {
- /***********************************/
- /* Enable or disable the interrupt */
- /***********************************/
-
- outl(devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_SetRegister,
- devpriv->
- s_BoardInfos.
- ui_Address
- + 20 +
- (64 * b_ModulNbr));
-
- /****************************/
- /* Enable the pulse encoder */
- /****************************/
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_ControlRegister
- =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_ControlRegister
- | (1UL
- <<
- b_PulseEncoderNbr);
-
- /**********************/
- /* Set the cycle mode */
- /**********************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_ControlRegister
- =
- (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_ControlRegister
- &
- (0xFFFFFFFFUL
- -
- (1 << (b_PulseEncoderNbr + 4)))) | ((b_CycleSelection & 1UL) << (4 + b_PulseEncoderNbr));
-
- /****************************/
- /* Enable the pulse encoder */
- /****************************/
-
- outl(devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_ControlRegister,
- devpriv->
- s_BoardInfos.
- ui_Address
- + 16 +
- (64 * b_ModulNbr));
- }
- } else {
- /************************************/
- /* Interrupt handling mode is wrong */
- /************************************/
-
- DPRINTK("Interrupt handling mode is wrong\n");
- i_ReturnValue = -6;
- }
- } else {
- /*********************************/
- /* Cycle selection mode is wrong */
- /*********************************/
-
- DPRINTK("Cycle selection mode is wrong\n");
- i_ReturnValue = -5;
- }
- break;
-
- case APCI1710_DISABLE:
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_ControlRegister =
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_ControlRegister &
- (0xFFFFFFFFUL -
- (1UL << b_PulseEncoderNbr));
-
- /*****************************/
- /* Disable the pulse encoder */
- /*****************************/
-
- outl(devpriv->s_ModuleInfo[b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_ControlRegister,
- devpriv->s_BoardInfos.
- ui_Address + 16 +
- (64 * b_ModulNbr));
-
- break;
- } /* switch End */
-
- } else {
- /*********************************/
- /* Pulse encoder not initialised */
- /*********************************/
-
- DPRINTK("Pulse encoder not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /************************************/
- /* Pulse encoder selection is wrong */
- /************************************/
-
- DPRINTK("Pulse encoder selection is wrong\n");
- i_ReturnValue = -3;
- }
- } else {
- /*****************************/
- /* Module selection is wrong */
- /*****************************/
-
- DPRINTK("Module selection is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadPulseEncoderStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PulseEncoderNbr, |
-| unsigned char *_ pb_Status) |
-+----------------------------------------------------------------------------+
-| Task APCI1710_PULSEENCODER_READ : Reads the pulse encoder status
- and valuefrom selected pulse |
-| encoder (b_PulseEncoderNbr) from selected module |
-| (b_ModulNbr). |
-+----------------------------------------------------------------------------+
- unsigned char b_Type; data[0]
- APCI1710_PULSEENCODER_WRITE
- Writes a 32-bit value (ul_WriteValue) into the selected|
-| pulse encoder (b_PulseEncoderNbr) from selected module |
-| (b_ModulNbr). This operation set the new start pulse |
-| encoder value.
- APCI1710_PULSEENCODER_READ
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710|
-| CRAREF() unsigned char_ b_ModulNbr : Module number to |
-| configure (0 to 3) |
-| data[1] unsigned char_ b_PulseEncoderNbr : Pulse encoder selection |
-| (0 to 3)
- APCI1710_PULSEENCODER_WRITE
- data[2] ULONG_ ul_WriteValue : 32-bit value to be |
-| written |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_Status : Pulse encoder status. |
-| 0 : No overflow occur|
-| 1 : Overflow occur
- PULONG_ pul_ReadValue : Pulse encoder value | |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection is wrong |
-| -3: Pulse encoder selection is wrong |
-| -4: Pulse encoder not initialised. |
-| See function "i_APCI1710_InitPulseEncoder" |
-+----------------------------------------------------------------------------+
-*/
-
-/*_INT_ i_APCI1710_ReadPulseEncoderStatus (unsigned char_ b_BoardHandle,
- unsigned char_ b_ModulNbr,
- unsigned char_ b_PulseEncoderNbr,
-
- unsigned char *_ pb_Status)
- */
-static int i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusRegister;
- unsigned char b_ModulNbr;
- unsigned char b_PulseEncoderNbr;
- unsigned char *pb_Status;
- unsigned char b_Type;
- unsigned int *pul_ReadValue;
- unsigned int ul_WriteValue;
-
- i_ReturnValue = insn->n;
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_Type = (unsigned char) data[0];
- b_PulseEncoderNbr = (unsigned char) data[1];
- pb_Status = (unsigned char *) &data[0];
- pul_ReadValue = (unsigned int *) &data[1];
-
- /***********************************/
- /* Test the selected module number */
- /***********************************/
-
- if (b_ModulNbr <= 3) {
- /******************************************/
- /* Test the selected pulse encoder number */
- /******************************************/
-
- if (b_PulseEncoderNbr <= 3) {
- /*************************************/
- /* Test if pulse encoder initialised */
- /*************************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_PulseEncoderModuleInfo.
- s_PulseEncoderInfo[b_PulseEncoderNbr].
- b_PulseEncoderInit == 1) {
-
- switch (b_Type) {
- case APCI1710_PULSEENCODER_READ:
- /****************************/
- /* Read the status register */
- /****************************/
-
- dw_StatusRegister =
- inl(devpriv->s_BoardInfos.
- ui_Address + 16 +
- (64 * b_ModulNbr));
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_StatusRegister = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_StatusRegister |
- dw_StatusRegister;
-
- *pb_Status =
- (unsigned char) (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_StatusRegister >> (1 +
- b_PulseEncoderNbr)) & 1;
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_StatusRegister =
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_PulseEncoderModuleInfo.
- dw_StatusRegister &
- (0xFFFFFFFFUL - (1 << (1 +
- b_PulseEncoderNbr)));
-
- /******************/
- /* Read the value */
- /******************/
-
- *pul_ReadValue =
- inl(devpriv->s_BoardInfos.
- ui_Address +
- (4 * b_PulseEncoderNbr) +
- (64 * b_ModulNbr));
- break;
-
- case APCI1710_PULSEENCODER_WRITE:
- ul_WriteValue = (unsigned int) data[2];
- /*******************/
- /* Write the value */
- /*******************/
-
- outl(ul_WriteValue,
- devpriv->s_BoardInfos.
- ui_Address +
- (4 * b_PulseEncoderNbr) +
- (64 * b_ModulNbr));
-
- } /* end of switch */
- } else {
- /*********************************/
- /* Pulse encoder not initialised */
- /*********************************/
-
- DPRINTK("Pulse encoder not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /************************************/
- /* Pulse encoder selection is wrong */
- /************************************/
-
- DPRINTK("Pulse encoder selection is wrong\n");
- i_ReturnValue = -3;
- }
- } else {
- /*****************************/
- /* Module selection is wrong */
- /*****************************/
-
- DPRINTK("Module selection is wrong\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-static int i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
-
- data[0] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].b_OldModuleMask;
- data[1] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].ul_OldInterruptMask;
- data[2] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
- /***************************/
- /* Increment the read FIFO */
- /***************************/
-
- devpriv->s_InterruptParameters.
- ui_Read = (devpriv->
- s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-
- return insn->n;
-
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c
deleted file mode 100644
index 5c830337db8..00000000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c
+++ /dev/null
@@ -1,3582 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-----------------------------------------------------------------------+
- | Project : API APCI1710 | Compiler : gcc |
- | Module name : PWM.C | Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-----------------------------------------------------------------------+
- | Description : APCI-1710 Wulse wide modulation module |
- | |
- | |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +-----------------------------------------------------------------------+
- | Date | Author | Description of updates |
- +-----------------------------------------------------------------------+
- | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 |
- | | | available |
- +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_30MHZ 30
-#define APCI1710_33MHZ 33
-#define APCI1710_40MHZ 40
-
-#define APCI1710_PWM_INIT 0
-#define APCI1710_PWM_GETINITDATA 1
-
-#define APCI1710_PWM_DISABLE 0
-#define APCI1710_PWM_ENABLE 1
-#define APCI1710_PWM_NEWTIMING 2
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitPWM |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PWM, |
-| unsigned char_ b_ClockSelection, |
-| unsigned char_ b_TimingUnit, |
-| ULONG_ ul_LowTiming, |
-| ULONG_ ul_HighTiming, |
-| PULONG_ pul_RealLowTiming, |
-| PULONG_ pul_RealHighTiming) |
-+----------------------------------------------------------------------------+
-| Task : Configure the selected PWM (b_PWM) from selected module|
-| (b_ModulNbr). The ul_LowTiming, ul_HighTiming and |
-| ul_TimingUnit determine the low/high timing base for |
-| the period. pul_RealLowTiming, pul_RealHighTiming |
-| return the real timing value. |
-| You must calling this function be for you call any |
-| other function witch access of the PWM. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure|
-| (0 to 3) |
-| unsigned char_ b_PWM : Selected PWM (0 or 1). |
-| unsigned char_ b_ClockSelection : Selection from PCI bus |
-| clock |
-| - APCI1710_30MHZ : |
-| The PC have a 30 MHz |
-| PCI bus clock |
-| - APCI1710_33MHZ : |
-| The PC have a 33 MHz |
-| PCI bus clock |
-| - APCI1710_40MHZ |
-| The APCI-1710 have a |
-| integrated 40Mhz |
-| quartz. |
-| unsigned char_ b_TimingUnit : Base timing Unit (0 to 4) |
-| 0 : ns |
-| 1 : æs |
-| 2 : ms |
-| 3 : s |
-| 4 : mn |
-| ULONG_ ul_LowTiming : Low base timing value. |
-| ULONG_ ul_HighTiming : High base timing value. |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_RealLowTiming : Real low base timing |
-| value. |
-| PULONG_ pul_RealHighTiming : Real high base timing |
-| value. |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a PWM module |
-| -4: PWM selection is wrong |
-| -5: The selected input clock is wrong |
-| -6: Timing Unit selection is wrong |
-| -7: Low base timing selection is wrong |
-| -8: High base timing selection is wrong |
-| -9: You can not used the 40MHz clock selection with |
-| this board |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitPWM(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_PWM,
- unsigned char b_ClockSelection,
- unsigned char b_TimingUnit,
- unsigned int ul_LowTiming,
- unsigned int ul_HighTiming,
- unsigned int *pul_RealLowTiming,
- unsigned int *pul_RealHighTiming)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int ul_LowTimerValue = 0;
- unsigned int ul_HighTimerValue = 0;
- unsigned int dw_Command;
- double d_RealLowTiming = 0;
- double d_RealHighTiming = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***************/
- /* Test if PWM */
- /***************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_PWM) {
- /**************************/
- /* Test the PWM selection */
- /**************************/
-
- if (b_PWM <= 1) {
- /******************/
- /* Test the clock */
- /******************/
-
- if ((b_ClockSelection == APCI1710_30MHZ) ||
- (b_ClockSelection == APCI1710_33MHZ) ||
- (b_ClockSelection == APCI1710_40MHZ)) {
- /************************/
- /* Test the timing unit */
- /************************/
-
- if (b_TimingUnit <= 4) {
- /*********************************/
- /* Test the low timing selection */
- /*********************************/
-
- if (((b_ClockSelection ==
- APCI1710_30MHZ)
- && (b_TimingUnit
- == 0)
- && (ul_LowTiming
- >= 266)
- && (ul_LowTiming
- <=
- 0xFFFFFFFFUL))
- || ((b_ClockSelection ==
- APCI1710_30MHZ)
- && (b_TimingUnit
- == 1)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 571230650UL))
- || ((b_ClockSelection ==
- APCI1710_30MHZ)
- && (b_TimingUnit
- == 2)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 571230UL))
- || ((b_ClockSelection ==
- APCI1710_30MHZ)
- && (b_TimingUnit
- == 3)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 571UL))
- || ((b_ClockSelection ==
- APCI1710_30MHZ)
- && (b_TimingUnit
- == 4)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <= 9UL))
- || ((b_ClockSelection ==
- APCI1710_33MHZ)
- && (b_TimingUnit
- == 0)
- && (ul_LowTiming
- >= 242)
- && (ul_LowTiming
- <=
- 0xFFFFFFFFUL))
- || ((b_ClockSelection ==
- APCI1710_33MHZ)
- && (b_TimingUnit
- == 1)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 519691043UL))
- || ((b_ClockSelection ==
- APCI1710_33MHZ)
- && (b_TimingUnit
- == 2)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 519691UL))
- || ((b_ClockSelection ==
- APCI1710_33MHZ)
- && (b_TimingUnit
- == 3)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 520UL))
- || ((b_ClockSelection ==
- APCI1710_33MHZ)
- && (b_TimingUnit
- == 4)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <= 8UL))
- || ((b_ClockSelection ==
- APCI1710_40MHZ)
- && (b_TimingUnit
- == 0)
- && (ul_LowTiming
- >= 200)
- && (ul_LowTiming
- <=
- 0xFFFFFFFFUL))
- || ((b_ClockSelection ==
- APCI1710_40MHZ)
- && (b_TimingUnit
- == 1)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 429496729UL))
- || ((b_ClockSelection ==
- APCI1710_40MHZ)
- && (b_TimingUnit
- == 2)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 429496UL))
- || ((b_ClockSelection ==
- APCI1710_40MHZ)
- && (b_TimingUnit
- == 3)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 429UL))
- || ((b_ClockSelection ==
- APCI1710_40MHZ)
- && (b_TimingUnit
- == 4)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 7UL))) {
- /**********************************/
- /* Test the High timing selection */
- /**********************************/
-
- if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) {
- /**************************/
- /* Test the board version */
- /**************************/
-
- if (((b_ClockSelection == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_ClockSelection != APCI1710_40MHZ)) {
-
- /************************************/
- /* Calculate the low division fator */
- /************************************/
-
- fpu_begin
- ();
-
- switch (b_TimingUnit) {
- /******/
- /* ns */
- /******/
-
- case 0:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_LowTimerValue
- =
- (unsigned int)
- (ul_LowTiming
- *
- (0.00025 * b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
- ul_LowTimerValue
- =
- ul_LowTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealLowTiming
- =
- (unsigned int)
- (ul_LowTimerValue
- /
- (0.00025 * (double)b_ClockSelection));
- d_RealLowTiming
- =
- (double)
- ul_LowTimerValue
- /
- (0.00025
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
- *pul_RealLowTiming
- =
- *pul_RealLowTiming
- +
- 1;
- }
-
- ul_LowTiming
- =
- ul_LowTiming
- -
- 1;
- ul_LowTimerValue
- =
- ul_LowTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_LowTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* æs */
- /******/
-
- case 1:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_LowTimerValue
- =
- (unsigned int)
- (ul_LowTiming
- *
- (0.25 * b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
- ul_LowTimerValue
- =
- ul_LowTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealLowTiming
- =
- (unsigned int)
- (ul_LowTimerValue
- /
- (0.25 * (double)b_ClockSelection));
- d_RealLowTiming
- =
- (double)
- ul_LowTimerValue
- /
- (
- (double)
- 0.25
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_LowTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
- *pul_RealLowTiming
- =
- *pul_RealLowTiming
- +
- 1;
- }
-
- ul_LowTiming
- =
- ul_LowTiming
- -
- 1;
- ul_LowTimerValue
- =
- ul_LowTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_LowTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* ms */
- /******/
-
- case 2:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_LowTimerValue
- =
- ul_LowTiming
- *
- (250.0
- *
- b_ClockSelection);
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
- ul_LowTimerValue
- =
- ul_LowTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealLowTiming
- =
- (unsigned int)
- (ul_LowTimerValue
- /
- (250.0 * (double)b_ClockSelection));
- d_RealLowTiming
- =
- (double)
- ul_LowTimerValue
- /
- (250.0
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_LowTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
- *pul_RealLowTiming
- =
- *pul_RealLowTiming
- +
- 1;
- }
-
- ul_LowTiming
- =
- ul_LowTiming
- -
- 1;
- ul_LowTimerValue
- =
- ul_LowTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_LowTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /*****/
- /* s */
- /*****/
-
- case 3:
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_LowTimerValue
- =
- (unsigned int)
- (ul_LowTiming
- *
- (250000.0
- *
- b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
- ul_LowTimerValue
- =
- ul_LowTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealLowTiming
- =
- (unsigned int)
- (ul_LowTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection));
- d_RealLowTiming
- =
- (double)
- ul_LowTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
- *pul_RealLowTiming
- =
- *pul_RealLowTiming
- +
- 1;
- }
-
- ul_LowTiming
- =
- ul_LowTiming
- -
- 1;
- ul_LowTimerValue
- =
- ul_LowTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_LowTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* mn */
- /******/
-
- case 4:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (ul_LowTiming
- *
- 60)
- *
- (250000.0
- *
- b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
- ul_LowTimerValue
- =
- ul_LowTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealLowTiming
- =
- (unsigned int)
- (ul_LowTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection))
- /
- 60;
- d_RealLowTiming
- =
- (
- (double)
- ul_LowTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection))
- /
- 60.0;
-
- if ((double)(((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)*pul_RealLowTiming + 0.5)) {
- *pul_RealLowTiming
- =
- *pul_RealLowTiming
- +
- 1;
- }
-
- ul_LowTiming
- =
- ul_LowTiming
- -
- 1;
- ul_LowTimerValue
- =
- ul_LowTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_LowTimerValue)
- *
- 1.007752288);
- }
-
- break;
- }
-
- /*************************************/
- /* Calculate the high division fator */
- /*************************************/
-
- switch (b_TimingUnit) {
- /******/
- /* ns */
- /******/
-
- case 0:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_HighTimerValue
- =
- (unsigned int)
- (ul_HighTiming
- *
- (0.00025 * b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
- ul_HighTimerValue
- =
- ul_HighTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealHighTiming
- =
- (unsigned int)
- (ul_HighTimerValue
- /
- (0.00025 * (double)b_ClockSelection));
- d_RealHighTiming
- =
- (double)
- ul_HighTimerValue
- /
- (0.00025
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
- *pul_RealHighTiming
- =
- *pul_RealHighTiming
- +
- 1;
- }
-
- ul_HighTiming
- =
- ul_HighTiming
- -
- 1;
- ul_HighTimerValue
- =
- ul_HighTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_HighTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* æs */
- /******/
-
- case 1:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_HighTimerValue
- =
- (unsigned int)
- (ul_HighTiming
- *
- (0.25 * b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
- ul_HighTimerValue
- =
- ul_HighTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealHighTiming
- =
- (unsigned int)
- (ul_HighTimerValue
- /
- (0.25 * (double)b_ClockSelection));
- d_RealHighTiming
- =
- (double)
- ul_HighTimerValue
- /
- (
- (double)
- 0.25
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_HighTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
- *pul_RealHighTiming
- =
- *pul_RealHighTiming
- +
- 1;
- }
-
- ul_HighTiming
- =
- ul_HighTiming
- -
- 1;
- ul_HighTimerValue
- =
- ul_HighTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_HighTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* ms */
- /******/
-
- case 2:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_HighTimerValue
- =
- ul_HighTiming
- *
- (250.0
- *
- b_ClockSelection);
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
- ul_HighTimerValue
- =
- ul_HighTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealHighTiming
- =
- (unsigned int)
- (ul_HighTimerValue
- /
- (250.0 * (double)b_ClockSelection));
- d_RealHighTiming
- =
- (double)
- ul_HighTimerValue
- /
- (250.0
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_HighTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
- *pul_RealHighTiming
- =
- *pul_RealHighTiming
- +
- 1;
- }
-
- ul_HighTiming
- =
- ul_HighTiming
- -
- 1;
- ul_HighTimerValue
- =
- ul_HighTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_HighTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /*****/
- /* s */
- /*****/
-
- case 3:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_HighTimerValue
- =
- (unsigned int)
- (ul_HighTiming
- *
- (250000.0
- *
- b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
- ul_HighTimerValue
- =
- ul_HighTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealHighTiming
- =
- (unsigned int)
- (ul_HighTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection));
- d_RealHighTiming
- =
- (double)
- ul_HighTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
- *pul_RealHighTiming
- =
- *pul_RealHighTiming
- +
- 1;
- }
-
- ul_HighTiming
- =
- ul_HighTiming
- -
- 1;
- ul_HighTimerValue
- =
- ul_HighTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_HighTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* mn */
- /******/
-
- case 4:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (ul_HighTiming
- *
- 60)
- *
- (250000.0
- *
- b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
- ul_HighTimerValue
- =
- ul_HighTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- *pul_RealHighTiming
- =
- (unsigned int)
- (ul_HighTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection))
- /
- 60;
- d_RealHighTiming
- =
- (
- (double)
- ul_HighTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection))
- /
- 60.0;
-
- if ((double)(((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)*pul_RealHighTiming + 0.5)) {
- *pul_RealHighTiming
- =
- *pul_RealHighTiming
- +
- 1;
- }
-
- ul_HighTiming
- =
- ul_HighTiming
- -
- 1;
- ul_HighTimerValue
- =
- ul_HighTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_HighTimerValue)
- *
- 1.007752288);
- }
-
- break;
- }
-
- fpu_end();
- /****************************/
- /* Save the clock selection */
- /****************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- b_ClockSelection
- =
- b_ClockSelection;
-
- /************************/
- /* Save the timing unit */
- /************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- b_TimingUnit
- =
- b_TimingUnit;
-
- /****************************/
- /* Save the low base timing */
- /****************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- d_LowTiming
- =
- d_RealLowTiming;
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- ul_RealLowTiming
- =
- *pul_RealLowTiming;
-
- /****************************/
- /* Save the high base timing */
- /****************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- d_HighTiming
- =
- d_RealHighTiming;
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- ul_RealHighTiming
- =
- *pul_RealHighTiming;
-
- /************************/
- /* Write the low timing */
- /************************/
-
- outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr));
-
- /*************************/
- /* Write the high timing */
- /*************************/
-
- outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr));
-
- /***************************/
- /* Set the clock selection */
- /***************************/
-
- dw_Command
- =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- 8
- +
- (20 * b_PWM) + (64 * b_ModulNbr));
-
- dw_Command
- =
- dw_Command
- &
- 0x7F;
-
- if (b_ClockSelection == APCI1710_40MHZ) {
- dw_Command
- =
- dw_Command
- |
- 0x80;
- }
-
- /***************************/
- /* Set the clock selection */
- /***************************/
-
- outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr));
-
- /*************/
- /* PWM init. */
- /*************/
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- b_PWMInit
- =
- 1;
- } else {
- /***************************************************/
- /* You can not used the 40MHz clock selection with */
- /* this board */
- /***************************************************/
- DPRINTK("You can not used the 40MHz clock selection with this board\n");
- i_ReturnValue
- =
- -9;
- }
- } else {
- /***************************************/
- /* High base timing selection is wrong */
- /***************************************/
- DPRINTK("High base timing selection is wrong\n");
- i_ReturnValue =
- -8;
- }
- } else {
- /**************************************/
- /* Low base timing selection is wrong */
- /**************************************/
- DPRINTK("Low base timing selection is wrong\n");
- i_ReturnValue = -7;
- }
- } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
- else {
- /**********************************/
- /* Timing unit selection is wrong */
- /**********************************/
- DPRINTK("Timing unit selection is wrong\n");
- i_ReturnValue = -6;
- } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
- } /* if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) */
- else {
- /*******************************/
- /* The selected clock is wrong */
- /*******************************/
- DPRINTK("The selected clock is wrong\n");
- i_ReturnValue = -5;
- } /* if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) */
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- else {
- /******************************/
- /* Tor PWM selection is wrong */
- /******************************/
- DPRINTK("Tor PWM selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- } else {
- /**********************************/
- /* The module is not a PWM module */
- /**********************************/
- DPRINTK("The module is not a PWM module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetPWMInitialisation |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PWM, |
-| unsigned char *_ pb_TimingUnit, |
-| PULONG_ pul_LowTiming, |
-| PULONG_ pul_HighTiming, |
-| unsigned char *_ pb_StartLevel, |
-| unsigned char *_ pb_StopMode, |
-| unsigned char *_ pb_StopLevel, |
-| unsigned char *_ pb_ExternGate, |
-| unsigned char *_ pb_InterruptEnable, |
-| unsigned char *_ pb_Enable) |
-+----------------------------------------------------------------------------+
-| Task : Return the PWM (b_PWM) initialisation from selected |
-| module (b_ModulNbr). You must calling the |
-| "i_APCI1710_InitPWM" function be for you call this |
-| function. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3) |
-| unsigned char_ b_PWM : Selected PWM (0 or 1) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_TimingUnit : Base timing Unit (0 to 4) |
-| 0 : ns |
-| 1 : æs |
-| 2 : ms |
-| 3 : s |
-| 4 : mn |
-| PULONG_ pul_LowTiming : Low base timing value. |
-| PULONG_ pul_HighTiming : High base timing value. |
-| unsigned char *_ pb_StartLevel : Start period level |
-| selection |
-| 0 : The period start |
-| with a low level |
-| 1 : The period start |
-| with a high level|
-| unsigned char *_ pb_StopMode : Stop mode selection |
-| 0 : The PWM is stopped |
-| directly after the |
-| "i_APCI1710_DisablePWM"|
-| function and break the|
-| last period |
-| 1 : After the |
-| "i_APCI1710_DisablePWM"|
-| function the PWM is |
-| stopped at the end |
-| from last period cycle|
-| unsigned char *_ pb_StopLevel : Stop PWM level selection |
-| 0 : The output signal |
-| keep the level after|
-| the |
-| "i_APCI1710_DisablePWM"|
-| function |
-| 1 : The output signal is|
-| set to low after the|
-| "i_APCI1710_DisablePWM"|
-| function |
-| 2 : The output signal is|
-| set to high after |
-| the |
-| "i_APCI1710_DisablePWM"|
-| function |
-| unsigned char *_ pb_ExternGate : Extern gate action |
-| selection |
-| 0 : Extern gate signal |
-| not used. |
-| 1 : Extern gate signal |
-| used. |
-| unsigned char *_ pb_InterruptEnable : Enable or disable the PWM |
-| interrupt. |
-| - APCI1710_ENABLE : |
-| Enable the PWM interrupt|
-| A interrupt occur after |
-| each period |
-| - APCI1710_DISABLE : |
-| Disable the PWM |
-| interrupt |
-| unsigned char *_ pb_Enable : Indicate if the PWM is |
-| enabled or no |
-| 0 : PWM not enabled |
-| 1 : PWM enabled |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a PWM module |
-| -4: PWM selection is wrong |
-| -5: PWM not initialised see function |
-| "i_APCI1710_InitPWM" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetPWMInitialisation(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_PWM,
- unsigned char *pb_TimingUnit,
- unsigned int *pul_LowTiming,
- unsigned int *pul_HighTiming,
- unsigned char *pb_StartLevel,
- unsigned char *pb_StopMode,
- unsigned char *pb_StopLevel,
- unsigned char *pb_ExternGate,
- unsigned char *pb_InterruptEnable,
- unsigned char *pb_Enable)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_Status;
- unsigned int dw_Command;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***************/
- /* Test if PWM */
- /***************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_PWM) {
- /**************************/
- /* Test the PWM selection */
- /**************************/
-
- if (b_PWM <= 1) {
- /***************************/
- /* Test if PWM initialised */
- /***************************/
-
- dw_Status = inl(devpriv->s_BoardInfos.
- ui_Address + 12 + (20 * b_PWM) +
- (64 * b_ModulNbr));
-
- if (dw_Status & 0x10) {
- /***********************/
- /* Read the low timing */
- /***********************/
-
- *pul_LowTiming =
- inl(devpriv->s_BoardInfos.
- ui_Address + 0 + (20 * b_PWM) +
- (64 * b_ModulNbr));
-
- /************************/
- /* Read the high timing */
- /************************/
-
- *pul_HighTiming =
- inl(devpriv->s_BoardInfos.
- ui_Address + 4 + (20 * b_PWM) +
- (64 * b_ModulNbr));
-
- /********************/
- /* Read the command */
- /********************/
-
- dw_Command = inl(devpriv->s_BoardInfos.
- ui_Address + 8 + (20 * b_PWM) +
- (64 * b_ModulNbr));
-
- *pb_StartLevel =
- (unsigned char) ((dw_Command >> 5) & 1);
- *pb_StopMode =
- (unsigned char) ((dw_Command >> 0) & 1);
- *pb_StopLevel =
- (unsigned char) ((dw_Command >> 1) & 1);
- *pb_ExternGate =
- (unsigned char) ((dw_Command >> 4) & 1);
- *pb_InterruptEnable =
- (unsigned char) ((dw_Command >> 3) & 1);
-
- if (*pb_StopLevel) {
- *pb_StopLevel =
- *pb_StopLevel +
- (unsigned char) ((dw_Command >>
- 2) & 1);
- }
-
- /********************/
- /* Read the command */
- /********************/
-
- dw_Command = inl(devpriv->s_BoardInfos.
- ui_Address + 8 + (20 * b_PWM) +
- (64 * b_ModulNbr));
-
- *pb_Enable =
- (unsigned char) ((dw_Command >> 0) & 1);
-
- *pb_TimingUnit = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo[b_PWM].b_TimingUnit;
- } /* if (dw_Status & 0x10) */
- else {
- /***********************/
- /* PWM not initialised */
- /***********************/
- DPRINTK("PWM not initialised\n");
- i_ReturnValue = -5;
- } /* if (dw_Status & 0x10) */
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- else {
- /******************************/
- /* Tor PWM selection is wrong */
- /******************************/
- DPRINTK("Tor PWM selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- } else {
- /**********************************/
- /* The module is not a PWM module */
- /**********************************/
- DPRINTK("The module is not a PWM module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
- * Pwm Init and Get Pwm Initialisation
- */
-static int i_APCI1710_InsnConfigPWM(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- unsigned char b_ConfigType;
- int i_ReturnValue = 0;
- b_ConfigType = CR_CHAN(insn->chanspec);
-
- switch (b_ConfigType) {
- case APCI1710_PWM_INIT:
- i_ReturnValue = i_APCI1710_InitPWM(dev, (unsigned char) CR_AREF(insn->chanspec), /* b_ModulNbr */
- (unsigned char) data[0], /* b_PWM */
- (unsigned char) data[1], /* b_ClockSelection */
- (unsigned char) data[2], /* b_TimingUnit */
- (unsigned int) data[3], /* ul_LowTiming */
- (unsigned int) data[4], /* ul_HighTiming */
- (unsigned int *) &data[0], /* pul_RealLowTiming */
- (unsigned int *) &data[1] /* pul_RealHighTiming */
- );
- break;
-
- case APCI1710_PWM_GETINITDATA:
- i_ReturnValue = i_APCI1710_GetPWMInitialisation(dev, (unsigned char) CR_AREF(insn->chanspec), /* b_ModulNbr */
- (unsigned char) data[0], /* b_PWM */
- (unsigned char *) &data[0], /* pb_TimingUnit */
- (unsigned int *) &data[1], /* pul_LowTiming */
- (unsigned int *) &data[2], /* pul_HighTiming */
- (unsigned char *) &data[3], /* pb_StartLevel */
- (unsigned char *) &data[4], /* pb_StopMode */
- (unsigned char *) &data[5], /* pb_StopLevel */
- (unsigned char *) &data[6], /* pb_ExternGate */
- (unsigned char *) &data[7], /* pb_InterruptEnable */
- (unsigned char *) &data[8] /* pb_Enable */
- );
- break;
-
- default:
- printk(" Config Parameter Wrong\n");
- }
-
- if (i_ReturnValue >= 0)
- i_ReturnValue = insn->n;
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_EnablePWM |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PWM, |
-| unsigned char_ b_StartLevel, |
-| unsigned char_ b_StopMode, |
-| unsigned char_ b_StopLevel, |
-| unsigned char_ b_ExternGate, |
-| unsigned char_ b_InterruptEnable) |
-+----------------------------------------------------------------------------+
-| Task : Enable the selected PWM (b_PWM) from selected module |
-| (b_ModulNbr). You must calling the "i_APCI1710_InitPWM"|
-| function be for you call this function. |
-| If you enable the PWM interrupt, the PWM generate a |
-| interrupt after each period. |
-| See function "i_APCI1710_SetBoardIntRoutineX" and the |
-| Interrupt mask description chapter. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number |
-| (0 to 3) |
-| unsigned char_ b_PWM : Selected PWM (0 or 1) |
-| unsigned char_ b_StartLevel : Start period level selection |
-| 0 : The period start with a |
-| low level |
-| 1 : The period start with a |
-| high level |
-| unsigned char_ b_StopMode : Stop mode selection |
-| 0 : The PWM is stopped |
-| directly after the |
-| "i_APCI1710_DisablePWM" |
-| function and break the |
-| last period |
-| 1 : After the |
-| "i_APCI1710_DisablePWM" |
-| function the PWM is |
-| stopped at the end from|
-| last period cycle. |
-| unsigned char_ b_StopLevel : Stop PWM level selection |
-| 0 : The output signal keep |
-| the level after the |
-| "i_APCI1710_DisablePWM" |
-| function |
-| 1 : The output signal is set|
-| to low after the |
-| "i_APCI1710_DisablePWM" |
-| function |
-| 2 : The output signal is set|
-| to high after the |
-| "i_APCI1710_DisablePWM" |
-| function |
-| unsigned char_ b_ExternGate : Extern gate action selection |
-| 0 : Extern gate signal not |
-| used. |
-| 1 : Extern gate signal used.|
-| unsigned char_ b_InterruptEnable : Enable or disable the PWM |
-| interrupt. |
-| - APCI1710_ENABLE : |
-| Enable the PWM interrupt |
-| A interrupt occur after |
-| each period |
-| - APCI1710_DISABLE : |
-| Disable the PWM interrupt |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a PWM module |
-| -4: PWM selection is wrong |
-| -5: PWM not initialised see function |
-| "i_APCI1710_InitPWM" |
-| -6: PWM start level selection is wrong |
-| -7: PWM stop mode selection is wrong |
-| -8: PWM stop level selection is wrong |
-| -9: Extern gate signal selection is wrong |
-| -10: Interrupt parameter is wrong |
-| -11: Interrupt function not initialised. |
-| See function "i_APCI1710_SetBoardIntRoutineX" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_EnablePWM(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_PWM,
- unsigned char b_StartLevel,
- unsigned char b_StopMode,
- unsigned char b_StopLevel,
- unsigned char b_ExternGate,
- unsigned char b_InterruptEnable)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_Status;
- unsigned int dw_Command;
-
- devpriv->tsk_Current = current; /* Save the current process task structure */
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***************/
- /* Test if PWM */
- /***************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_PWM) {
- /**************************/
- /* Test the PWM selection */
- /**************************/
-
- if (b_PWM <= 1) {
- /***************************/
- /* Test if PWM initialised */
- /***************************/
-
- dw_Status = inl(devpriv->s_BoardInfos.
- ui_Address + 12 + (20 * b_PWM) +
- (64 * b_ModulNbr));
-
- if (dw_Status & 0x10) {
- /**********************************/
- /* Test the start level selection */
- /**********************************/
-
- if (b_StartLevel <= 1) {
- /**********************/
- /* Test the stop mode */
- /**********************/
-
- if (b_StopMode <= 1) {
- /***********************/
- /* Test the stop level */
- /***********************/
-
- if (b_StopLevel <= 2) {
- /*****************************/
- /* Test the extern gate mode */
- /*****************************/
-
- if (b_ExternGate
- <= 1) {
- /*****************************/
- /* Test the interrupt action */
- /*****************************/
-
- if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) {
- /******************************************/
- /* Test if interrupt function initialised */
- /******************************************/
-
- /********************/
- /* Read the command */
- /********************/
-
- dw_Command
- =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- 8
- +
- (20 * b_PWM) + (64 * b_ModulNbr));
-
- dw_Command
- =
- dw_Command
- &
- 0x80;
-
- /********************/
- /* Make the command */
- /********************/
-
- dw_Command
- =
- dw_Command
- |
- b_StopMode
- |
- (b_InterruptEnable
- <<
- 3)
- |
- (b_ExternGate
- <<
- 4)
- |
- (b_StartLevel
- <<
- 5);
-
- if (b_StopLevel & 3) {
- dw_Command
- =
- dw_Command
- |
- 2;
-
- if (b_StopLevel & 2) {
- dw_Command
- =
- dw_Command
- |
- 4;
- }
- }
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- b_InterruptEnable
- =
- b_InterruptEnable;
-
- /*******************/
- /* Set the command */
- /*******************/
-
- outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr));
-
- /******************/
- /* Enable the PWM */
- /******************/
- outl(1, devpriv->s_BoardInfos.ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr));
- } /* if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) */
- else {
- /********************************/
- /* Interrupt parameter is wrong */
- /********************************/
- DPRINTK("Interrupt parameter is wrong\n");
- i_ReturnValue
- =
- -10;
- } /* if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) */
- } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */
- else {
- /*****************************************/
- /* Extern gate signal selection is wrong */
- /*****************************************/
- DPRINTK("Extern gate signal selection is wrong\n");
- i_ReturnValue
- =
- -9;
- } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */
- } /* if (b_StopLevel >= 0 && b_StopLevel <= 2) */
- else {
- /*************************************/
- /* PWM stop level selection is wrong */
- /*************************************/
- DPRINTK("PWM stop level selection is wrong\n");
- i_ReturnValue =
- -8;
- } /* if (b_StopLevel >= 0 && b_StopLevel <= 2) */
- } /* if (b_StopMode >= 0 && b_StopMode <= 1) */
- else {
- /************************************/
- /* PWM stop mode selection is wrong */
- /************************************/
- DPRINTK("PWM stop mode selection is wrong\n");
- i_ReturnValue = -7;
- } /* if (b_StopMode >= 0 && b_StopMode <= 1) */
- } /* if (b_StartLevel >= 0 && b_StartLevel <= 1) */
- else {
- /**************************************/
- /* PWM start level selection is wrong */
- /**************************************/
- DPRINTK("PWM start level selection is wrong\n");
- i_ReturnValue = -6;
- } /* if (b_StartLevel >= 0 && b_StartLevel <= 1) */
- } /* if (dw_Status & 0x10) */
- else {
- /***********************/
- /* PWM not initialised */
- /***********************/
- DPRINTK("PWM not initialised\n");
- i_ReturnValue = -5;
- } /* if (dw_Status & 0x10) */
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- else {
- /******************************/
- /* Tor PWM selection is wrong */
- /******************************/
- DPRINTK("Tor PWM selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- } else {
- /**********************************/
- /* The module is not a PWM module */
- /**********************************/
- DPRINTK("The module is not a PWM module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_DisablePWM (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PWM) |
-+----------------------------------------------------------------------------+
-| Task : Disable the selected PWM (b_PWM) from selected module |
-| (b_ModulNbr). The output signal level depend of the |
-| initialisation by the "i_APCI1710_EnablePWM". |
-| See the b_StartLevel, b_StopMode and b_StopLevel |
-| parameters from this function. |
-+----------------------------------------------------------------------------+
-| Input Parameters :BYTE_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3) |
-| unsigned char_ b_PWM : Selected PWM (0 or 1) |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a PWM module |
-| -4: PWM selection is wrong |
-| -5: PWM not initialised see function |
-| "i_APCI1710_InitPWM" |
-| -6: PWM not enabled see function |
-| "i_APCI1710_EnablePWM" |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_DisablePWM(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_PWM)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_Status;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***************/
- /* Test if PWM */
- /***************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_PWM) {
- /**************************/
- /* Test the PWM selection */
- /**************************/
-
- if (b_PWM <= 1) {
- /***************************/
- /* Test if PWM initialised */
- /***************************/
-
- dw_Status = inl(devpriv->s_BoardInfos.
- ui_Address + 12 + (20 * b_PWM) +
- (64 * b_ModulNbr));
-
- if (dw_Status & 0x10) {
- /***********************/
- /* Test if PWM enabled */
- /***********************/
-
- if (dw_Status & 0x1) {
- /*******************/
- /* Disable the PWM */
- /*******************/
- outl(0, devpriv->s_BoardInfos.
- ui_Address + 12 +
- (20 * b_PWM) +
- (64 * b_ModulNbr));
- } /* if (dw_Status & 0x1) */
- else {
- /*******************/
- /* PWM not enabled */
- /*******************/
- DPRINTK("PWM not enabled\n");
- i_ReturnValue = -6;
- } /* if (dw_Status & 0x1) */
- } /* if (dw_Status & 0x10) */
- else {
- /***********************/
- /* PWM not initialised */
- /***********************/
- DPRINTK(" PWM not initialised\n");
- i_ReturnValue = -5;
- } /* if (dw_Status & 0x10) */
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- else {
- /******************************/
- /* Tor PWM selection is wrong */
- /******************************/
- DPRINTK("Tor PWM selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- } else {
- /**********************************/
- /* The module is not a PWM module */
- /**********************************/
- DPRINTK("The module is not a PWM module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_SetNewPWMTiming |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PWM, |
-| unsigned char_ b_ClockSelection, |
-| unsigned char_ b_TimingUnit, |
-| ULONG_ ul_LowTiming, |
-| ULONG_ ul_HighTiming) |
-+----------------------------------------------------------------------------+
-| Task : Set a new timing. The ul_LowTiming, ul_HighTiming and |
-| ul_TimingUnit determine the low/high timing base for |
-| the period. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Module number to configure|
-| (0 to 3) |
-| unsigned char_ b_PWM : Selected PWM (0 or 1). |
-| unsigned char_ b_TimingUnit : Base timing Unit (0 to 4) |
-| 0 : ns |
-| 1 : æs |
-| 2 : ms |
-| 3 : s |
-| 4 : mn |
-| ULONG_ ul_LowTiming : Low base timing value. |
-| ULONG_ ul_HighTiming : High base timing value. |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a PWM module |
-| -4: PWM selection is wrong |
-| -5: PWM not initialised |
-| -6: Timing Unit selection is wrong |
-| -7: Low base timing selection is wrong |
-| -8: High base timing selection is wrong |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_SetNewPWMTiming(struct comedi_device *dev,
- unsigned char b_ModulNbr,
- unsigned char b_PWM,
- unsigned char b_TimingUnit,
- unsigned int ul_LowTiming,
- unsigned int ul_HighTiming)
-{
- struct addi_private *devpriv = dev->private;
- unsigned char b_ClockSelection;
- int i_ReturnValue = 0;
- unsigned int ul_LowTimerValue = 0;
- unsigned int ul_HighTimerValue = 0;
- unsigned int ul_RealLowTiming = 0;
- unsigned int ul_RealHighTiming = 0;
- unsigned int dw_Status;
- unsigned int dw_Command;
- double d_RealLowTiming = 0;
- double d_RealHighTiming = 0;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***************/
- /* Test if PWM */
- /***************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_PWM) {
- /**************************/
- /* Test the PWM selection */
- /**************************/
-
- if (b_PWM <= 1) {
- /***************************/
- /* Test if PWM initialised */
- /***************************/
-
- dw_Status = inl(devpriv->s_BoardInfos.
- ui_Address + 12 + (20 * b_PWM) +
- (64 * b_ModulNbr));
-
- if (dw_Status & 0x10) {
- b_ClockSelection = devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_PWMModuleInfo.
- b_ClockSelection;
-
- /************************/
- /* Test the timing unit */
- /************************/
-
- if (b_TimingUnit <= 4) {
- /*********************************/
- /* Test the low timing selection */
- /*********************************/
-
- if (((b_ClockSelection ==
- APCI1710_30MHZ)
- && (b_TimingUnit
- == 0)
- && (ul_LowTiming
- >= 266)
- && (ul_LowTiming
- <=
- 0xFFFFFFFFUL))
- || ((b_ClockSelection ==
- APCI1710_30MHZ)
- && (b_TimingUnit
- == 1)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 571230650UL))
- || ((b_ClockSelection ==
- APCI1710_30MHZ)
- && (b_TimingUnit
- == 2)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 571230UL))
- || ((b_ClockSelection ==
- APCI1710_30MHZ)
- && (b_TimingUnit
- == 3)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 571UL))
- || ((b_ClockSelection ==
- APCI1710_30MHZ)
- && (b_TimingUnit
- == 4)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <= 9UL))
- || ((b_ClockSelection ==
- APCI1710_33MHZ)
- && (b_TimingUnit
- == 0)
- && (ul_LowTiming
- >= 242)
- && (ul_LowTiming
- <=
- 0xFFFFFFFFUL))
- || ((b_ClockSelection ==
- APCI1710_33MHZ)
- && (b_TimingUnit
- == 1)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 519691043UL))
- || ((b_ClockSelection ==
- APCI1710_33MHZ)
- && (b_TimingUnit
- == 2)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 519691UL))
- || ((b_ClockSelection ==
- APCI1710_33MHZ)
- && (b_TimingUnit
- == 3)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 520UL))
- || ((b_ClockSelection ==
- APCI1710_33MHZ)
- && (b_TimingUnit
- == 4)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <= 8UL))
- || ((b_ClockSelection ==
- APCI1710_40MHZ)
- && (b_TimingUnit
- == 0)
- && (ul_LowTiming
- >= 200)
- && (ul_LowTiming
- <=
- 0xFFFFFFFFUL))
- || ((b_ClockSelection ==
- APCI1710_40MHZ)
- && (b_TimingUnit
- == 1)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 429496729UL))
- || ((b_ClockSelection ==
- APCI1710_40MHZ)
- && (b_TimingUnit
- == 2)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 429496UL))
- || ((b_ClockSelection ==
- APCI1710_40MHZ)
- && (b_TimingUnit
- == 3)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 429UL))
- || ((b_ClockSelection ==
- APCI1710_40MHZ)
- && (b_TimingUnit
- == 4)
- && (ul_LowTiming
- >= 1)
- && (ul_LowTiming
- <=
- 7UL))) {
- /**********************************/
- /* Test the High timing selection */
- /**********************************/
-
- if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) {
- /************************************/
- /* Calculate the low division fator */
- /************************************/
-
- fpu_begin();
- switch (b_TimingUnit) {
- /******/
- /* ns */
- /******/
-
- case 0:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_LowTimerValue
- =
- (unsigned int)
- (ul_LowTiming
- *
- (0.00025 * b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
- ul_LowTimerValue
- =
- ul_LowTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealLowTiming
- =
- (unsigned int)
- (ul_LowTimerValue
- /
- (0.00025 * (double)b_ClockSelection));
- d_RealLowTiming
- =
- (double)
- ul_LowTimerValue
- /
- (0.00025
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
- ul_RealLowTiming
- =
- ul_RealLowTiming
- +
- 1;
- }
-
- ul_LowTiming
- =
- ul_LowTiming
- -
- 1;
- ul_LowTimerValue
- =
- ul_LowTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_LowTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* æs */
- /******/
-
- case 1:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_LowTimerValue
- =
- (unsigned int)
- (ul_LowTiming
- *
- (0.25 * b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
- ul_LowTimerValue
- =
- ul_LowTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealLowTiming
- =
- (unsigned int)
- (ul_LowTimerValue
- /
- (0.25 * (double)b_ClockSelection));
- d_RealLowTiming
- =
- (double)
- ul_LowTimerValue
- /
- (
- (double)
- 0.25
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_LowTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
- ul_RealLowTiming
- =
- ul_RealLowTiming
- +
- 1;
- }
-
- ul_LowTiming
- =
- ul_LowTiming
- -
- 1;
- ul_LowTimerValue
- =
- ul_LowTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_LowTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* ms */
- /******/
-
- case 2:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_LowTimerValue
- =
- ul_LowTiming
- *
- (250.0
- *
- b_ClockSelection);
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
- ul_LowTimerValue
- =
- ul_LowTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealLowTiming
- =
- (unsigned int)
- (ul_LowTimerValue
- /
- (250.0 * (double)b_ClockSelection));
- d_RealLowTiming
- =
- (double)
- ul_LowTimerValue
- /
- (250.0
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_LowTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
- ul_RealLowTiming
- =
- ul_RealLowTiming
- +
- 1;
- }
-
- ul_LowTiming
- =
- ul_LowTiming
- -
- 1;
- ul_LowTimerValue
- =
- ul_LowTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_LowTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /*****/
- /* s */
- /*****/
-
- case 3:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_LowTimerValue
- =
- (unsigned int)
- (ul_LowTiming
- *
- (250000.0
- *
- b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
- ul_LowTimerValue
- =
- ul_LowTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealLowTiming
- =
- (unsigned int)
- (ul_LowTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection));
- d_RealLowTiming
- =
- (double)
- ul_LowTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
- ul_RealLowTiming
- =
- ul_RealLowTiming
- +
- 1;
- }
-
- ul_LowTiming
- =
- ul_LowTiming
- -
- 1;
- ul_LowTimerValue
- =
- ul_LowTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_LowTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* mn */
- /******/
-
- case 4:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (ul_LowTiming
- *
- 60)
- *
- (250000.0
- *
- b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
- ul_LowTimerValue
- =
- ul_LowTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealLowTiming
- =
- (unsigned int)
- (ul_LowTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection))
- /
- 60;
- d_RealLowTiming
- =
- (
- (double)
- ul_LowTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection))
- /
- 60.0;
-
- if ((double)(((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)ul_RealLowTiming + 0.5)) {
- ul_RealLowTiming
- =
- ul_RealLowTiming
- +
- 1;
- }
-
- ul_LowTiming
- =
- ul_LowTiming
- -
- 1;
- ul_LowTimerValue
- =
- ul_LowTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_LowTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_LowTimerValue)
- *
- 1.007752288);
- }
-
- break;
- }
-
- /*************************************/
- /* Calculate the high division fator */
- /*************************************/
-
- switch (b_TimingUnit) {
- /******/
- /* ns */
- /******/
-
- case 0:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_HighTimerValue
- =
- (unsigned int)
- (ul_HighTiming
- *
- (0.00025 * b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
- ul_HighTimerValue
- =
- ul_HighTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealHighTiming
- =
- (unsigned int)
- (ul_HighTimerValue
- /
- (0.00025 * (double)b_ClockSelection));
- d_RealHighTiming
- =
- (double)
- ul_HighTimerValue
- /
- (0.00025
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
- ul_RealHighTiming
- =
- ul_RealHighTiming
- +
- 1;
- }
-
- ul_HighTiming
- =
- ul_HighTiming
- -
- 1;
- ul_HighTimerValue
- =
- ul_HighTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_HighTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* æs */
- /******/
-
- case 1:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_HighTimerValue
- =
- (unsigned int)
- (ul_HighTiming
- *
- (0.25 * b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
- ul_HighTimerValue
- =
- ul_HighTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealHighTiming
- =
- (unsigned int)
- (ul_HighTimerValue
- /
- (0.25 * (double)b_ClockSelection));
- d_RealHighTiming
- =
- (double)
- ul_HighTimerValue
- /
- (
- (double)
- 0.25
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_HighTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
- ul_RealHighTiming
- =
- ul_RealHighTiming
- +
- 1;
- }
-
- ul_HighTiming
- =
- ul_HighTiming
- -
- 1;
- ul_HighTimerValue
- =
- ul_HighTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_HighTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* ms */
- /******/
-
- case 2:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_HighTimerValue
- =
- ul_HighTiming
- *
- (250.0
- *
- b_ClockSelection);
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
- ul_HighTimerValue
- =
- ul_HighTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealHighTiming
- =
- (unsigned int)
- (ul_HighTimerValue
- /
- (250.0 * (double)b_ClockSelection));
- d_RealHighTiming
- =
- (double)
- ul_HighTimerValue
- /
- (250.0
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_HighTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
- ul_RealHighTiming
- =
- ul_RealHighTiming
- +
- 1;
- }
-
- ul_HighTiming
- =
- ul_HighTiming
- -
- 1;
- ul_HighTimerValue
- =
- ul_HighTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_HighTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /*****/
- /* s */
- /*****/
-
- case 3:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_HighTimerValue
- =
- (unsigned int)
- (ul_HighTiming
- *
- (250000.0
- *
- b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
- ul_HighTimerValue
- =
- ul_HighTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealHighTiming
- =
- (unsigned int)
- (ul_HighTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection));
- d_RealHighTiming
- =
- (double)
- ul_HighTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection);
-
- if ((double)((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
- ul_RealHighTiming
- =
- ul_RealHighTiming
- +
- 1;
- }
-
- ul_HighTiming
- =
- ul_HighTiming
- -
- 1;
- ul_HighTimerValue
- =
- ul_HighTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_HighTimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* mn */
- /******/
-
- case 4:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (ul_HighTiming
- *
- 60)
- *
- (250000.0
- *
- b_ClockSelection));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
- ul_HighTimerValue
- =
- ul_HighTimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealHighTiming
- =
- (unsigned int)
- (ul_HighTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection))
- /
- 60;
- d_RealHighTiming
- =
- (
- (double)
- ul_HighTimerValue
- /
- (250000.0
- *
- (double)
- b_ClockSelection))
- /
- 60.0;
-
- if ((double)(((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)ul_RealHighTiming + 0.5)) {
- ul_RealHighTiming
- =
- ul_RealHighTiming
- +
- 1;
- }
-
- ul_HighTiming
- =
- ul_HighTiming
- -
- 1;
- ul_HighTimerValue
- =
- ul_HighTimerValue
- -
- 2;
-
- if (b_ClockSelection != APCI1710_40MHZ) {
- ul_HighTimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_HighTimerValue)
- *
- 1.007752288);
- }
-
- break;
- }
-
- fpu_end();
-
- /************************/
- /* Save the timing unit */
- /************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- b_TimingUnit
- =
- b_TimingUnit;
-
- /****************************/
- /* Save the low base timing */
- /****************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- d_LowTiming
- =
- d_RealLowTiming;
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- ul_RealLowTiming
- =
- ul_RealLowTiming;
-
- /****************************/
- /* Save the high base timing */
- /****************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- d_HighTiming
- =
- d_RealHighTiming;
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_PWMModuleInfo.
- s_PWMInfo
- [b_PWM].
- ul_RealHighTiming
- =
- ul_RealHighTiming;
-
- /************************/
- /* Write the low timing */
- /************************/
-
- outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr));
-
- /*************************/
- /* Write the high timing */
- /*************************/
-
- outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr));
-
- /***************************/
- /* Set the clock selection */
- /***************************/
-
- dw_Command =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- + 8 +
- (20 * b_PWM) + (64 * b_ModulNbr));
-
- dw_Command =
- dw_Command
- & 0x7F;
-
- if (b_ClockSelection == APCI1710_40MHZ) {
- dw_Command
- =
- dw_Command
- |
- 0x80;
- }
-
- /***************************/
- /* Set the clock selection */
- /***************************/
-
- outl(dw_Command,
- devpriv->
- s_BoardInfos.
- ui_Address
- + 8 +
- (20 * b_PWM) + (64 * b_ModulNbr));
- } else {
- /***************************************/
- /* High base timing selection is wrong */
- /***************************************/
- DPRINTK("High base timing selection is wrong\n");
- i_ReturnValue =
- -8;
- }
- } else {
- /**************************************/
- /* Low base timing selection is wrong */
- /**************************************/
- DPRINTK("Low base timing selection is wrong\n");
- i_ReturnValue = -7;
- }
- } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
- else {
- /**********************************/
- /* Timing unit selection is wrong */
- /**********************************/
- DPRINTK("Timing unit selection is wrong\n");
- i_ReturnValue = -6;
- } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
- } /* if (dw_Status & 0x10) */
- else {
- /***********************/
- /* PWM not initialised */
- /***********************/
- DPRINTK("PWM not initialised\n");
- i_ReturnValue = -5;
- } /* if (dw_Status & 0x10) */
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- else {
- /******************************/
- /* Tor PWM selection is wrong */
- /******************************/
- DPRINTK("Tor PWM selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- } else {
- /**********************************/
- /* The module is not a PWM module */
- /**********************************/
- DPRINTK("The module is not a PWM module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
- * Pwm Enable Disable and Set New Timing
- */
-static int i_APCI1710_InsnWritePWM(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- unsigned char b_WriteType;
- int i_ReturnValue = 0;
- b_WriteType = CR_CHAN(insn->chanspec);
-
- switch (b_WriteType) {
- case APCI1710_PWM_ENABLE:
- i_ReturnValue = i_APCI1710_EnablePWM(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned char) data[0],
- (unsigned char) data[1],
- (unsigned char) data[2],
- (unsigned char) data[3], (unsigned char) data[4], (unsigned char) data[5]);
- break;
-
- case APCI1710_PWM_DISABLE:
- i_ReturnValue = i_APCI1710_DisablePWM(dev,
- (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]);
- break;
-
- case APCI1710_PWM_NEWTIMING:
- i_ReturnValue = i_APCI1710_SetNewPWMTiming(dev,
- (unsigned char) CR_AREF(insn->chanspec),
- (unsigned char) data[0],
- (unsigned char) data[1], (unsigned int) data[2], (unsigned int) data[3]);
- break;
-
- default:
- printk("Write Config Parameter Wrong\n");
- }
-
- if (i_ReturnValue >= 0)
- i_ReturnValue = insn->n;
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetPWMStatus |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PWM, |
-| unsigned char *_ pb_PWMOutputStatus, |
-| unsigned char *_ pb_ExternGateStatus) |
-+----------------------------------------------------------------------------+
-| Task : Return the status from selected PWM (b_PWM) from |
-| selected module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_PWM : Selected PWM (0 or 1) |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3)
- b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec);
- b_PWM =(unsigned char) data[0];
-
- |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_PWMOutputStatus : Return the PWM output |
-| level status. |
-| 0 : The PWM output level|
-| is low. |
-| 1 : The PWM output level|
-| is high. |
-| unsigned char *_ pb_ExternGateStatus : Return the extern gate |
-| level status. |
-| 0 : The extern gate is |
-| low. |
-| 1 : The extern gate is |
-| high.
- pb_PWMOutputStatus =(unsigned char *) data[0];
- pb_ExternGateStatus =(unsigned char *) data[1]; |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a PWM module |
-| -4: PWM selection is wrong |
-| -5: PWM not initialised see function |
-| "i_APCI1710_InitPWM" |
-| -6: PWM not enabled see function "i_APCI1710_EnablePWM"|
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnReadGetPWMStatus(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_Status;
- unsigned char b_ModulNbr;
- unsigned char b_PWM;
- unsigned char *pb_PWMOutputStatus;
- unsigned char *pb_ExternGateStatus;
-
- i_ReturnValue = insn->n;
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_PWM = (unsigned char) CR_CHAN(insn->chanspec);
- pb_PWMOutputStatus = (unsigned char *) &data[0];
- pb_ExternGateStatus = (unsigned char *) &data[1];
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***************/
- /* Test if PWM */
- /***************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_PWM) {
- /**************************/
- /* Test the PWM selection */
- /**************************/
-
- if (b_PWM <= 1) {
- /***************************/
- /* Test if PWM initialised */
- /***************************/
-
- dw_Status = inl(devpriv->s_BoardInfos.
- ui_Address + 12 + (20 * b_PWM) +
- (64 * b_ModulNbr));
-
- if (dw_Status & 0x10) {
- /***********************/
- /* Test if PWM enabled */
- /***********************/
-
- if (dw_Status & 0x1) {
- *pb_PWMOutputStatus =
- (unsigned char) ((dw_Status >> 7)
- & 1);
- *pb_ExternGateStatus =
- (unsigned char) ((dw_Status >> 6)
- & 1);
- } /* if (dw_Status & 0x1) */
- else {
- /*******************/
- /* PWM not enabled */
- /*******************/
-
- DPRINTK("PWM not enabled \n");
- i_ReturnValue = -6;
- } /* if (dw_Status & 0x1) */
- } /* if (dw_Status & 0x10) */
- else {
- /***********************/
- /* PWM not initialised */
- /***********************/
-
- DPRINTK("PWM not initialised\n");
- i_ReturnValue = -5;
- } /* if (dw_Status & 0x10) */
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- else {
- /******************************/
- /* Tor PWM selection is wrong */
- /******************************/
-
- DPRINTK("Tor PWM selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_PWM >= 0 && b_PWM <= 1) */
- } else {
- /**********************************/
- /* The module is not a PWM module */
- /**********************************/
-
- DPRINTK("The module is not a PWM module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-static int i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
-
- data[0] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].b_OldModuleMask;
- data[1] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].ul_OldInterruptMask;
- data[2] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
- /**************************/
- /* Increment the read FIFO */
- /***************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Read = (devpriv->
- s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-
- return insn->n;
-
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
deleted file mode 100644
index 6ef1d6a434d..00000000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
+++ /dev/null
@@ -1,845 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-----------------------------------------------------------------------+
- | Project : API APCI1710 | Compiler : gcc |
- | Module name : SSI.C | Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-----------------------------------------------------------------------+
- | Description : APCI-1710 SSI counter module |
- +-----------------------------------------------------------------------+
- | several changes done by S. Weber in 1998 and C. Guinot in 2000 |
- +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_30MHZ 30
-#define APCI1710_33MHZ 33
-#define APCI1710_40MHZ 40
-
-#define APCI1710_BINARY_MODE 0x1
-#define APCI1710_GRAY_MODE 0x0
-
-#define APCI1710_SSI_READ1VALUE 1
-#define APCI1710_SSI_READALLVALUE 2
-
-#define APCI1710_SSI_SET_CHANNELON 0
-#define APCI1710_SSI_SET_CHANNELOFF 1
-#define APCI1710_SSI_READ_1CHANNEL 2
-#define APCI1710_SSI_READ_ALLCHANNEL 3
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitSSI |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_SSIProfile, |
-| unsigned char_ b_PositionTurnLength, |
-| unsigned char_ b_TurnCptLength, |
-| unsigned char_ b_PCIInputClock, |
-| ULONG_ ul_SSIOutputClock, |
-| unsigned char_ b_SSICountingMode) |
-+----------------------------------------------------------------------------+
-| Task : Configure the SSI operating mode from selected module |
-| (b_ModulNbr). You must calling this function be for you|
-| call any other function witch access of SSI. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710|
-| unsigned char_ b_ModulNbr : Module number to |
-| configure (0 to 3) |
-| unsigned char_ b_SSIProfile : Selection from SSI |
-| profile length (2 to 32).|
-| unsigned char_ b_PositionTurnLength : Selection from SSI |
-| position data length |
-| (1 to 31). |
-| unsigned char_ b_TurnCptLength : Selection from SSI turn |
-| counter data length |
-| (1 to 31). |
-| unsigned char b_PCIInputClock : Selection from PCI bus |
-| clock |
-| - APCI1710_30MHZ : |
-| The PC have a PCI bus |
-| clock from 30 MHz |
-| - APCI1710_33MHZ : |
-| The PC have a PCI bus |
-| clock from 33 MHz |
-| ULONG_ ul_SSIOutputClock : Selection from SSI output|
-| clock. |
-| From 229 to 5 000 000 Hz|
-| for 30 MHz selection. |
-| From 252 to 5 000 000 Hz|
-| for 33 MHz selection. |
-| unsigned char b_SSICountingMode : SSI counting mode |
-| selection |
-| - APCI1710_BINARY_MODE : |
-| Binary counting mode. |
-| - APCI1710_GRAY_MODE : |
-| Gray counting mode.
-
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_SSIProfile = (unsigned char) data[0];
- b_PositionTurnLength= (unsigned char) data[1];
- b_TurnCptLength = (unsigned char) data[2];
- b_PCIInputClock = (unsigned char) data[3];
- ul_SSIOutputClock = (unsigned int) data[4];
- b_SSICountingMode = (unsigned char) data[5]; |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a SSI module |
-| -4: The selected SSI profile length is wrong |
-| -5: The selected SSI position data length is wrong |
-| -6: The selected SSI turn counter data length is wrong |
-| -7: The selected PCI input clock is wrong |
-| -8: The selected SSI output clock is wrong |
-| -9: The selected SSI counting mode parameter is wrong |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int ui_TimerValue;
- unsigned char b_ModulNbr, b_SSIProfile, b_PositionTurnLength, b_TurnCptLength,
- b_PCIInputClock, b_SSICountingMode;
- unsigned int ul_SSIOutputClock;
-
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_SSIProfile = (unsigned char) data[0];
- b_PositionTurnLength = (unsigned char) data[1];
- b_TurnCptLength = (unsigned char) data[2];
- b_PCIInputClock = (unsigned char) data[3];
- ul_SSIOutputClock = (unsigned int) data[4];
- b_SSICountingMode = (unsigned char) data[5];
-
- i_ReturnValue = insn->n;
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if SSI counter */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
- /*******************************/
- /* Test the SSI profile length */
- /*******************************/
-
- /* CG 22/03/00 b_SSIProfile >= 2 anstatt b_SSIProfile > 2 */
- if (b_SSIProfile >= 2 && b_SSIProfile < 33) {
- /*************************************/
- /* Test the SSI position data length */
- /*************************************/
-
- if (b_PositionTurnLength > 0
- && b_PositionTurnLength < 32) {
- /*****************************************/
- /* Test the SSI turn counter data length */
- /*****************************************/
-
- if (b_TurnCptLength > 0
- && b_TurnCptLength < 32) {
- /***************************/
- /* Test the profile length */
- /***************************/
-
- if ((b_TurnCptLength +
- b_PositionTurnLength)
- <= b_SSIProfile) {
- /****************************/
- /* Test the PCI input clock */
- /****************************/
-
- if (b_PCIInputClock ==
- APCI1710_30MHZ
- ||
- b_PCIInputClock
- ==
- APCI1710_33MHZ)
- {
- /*************************/
- /* Test the output clock */
- /*************************/
-
- if ((b_PCIInputClock == APCI1710_30MHZ && (ul_SSIOutputClock > 228 && ul_SSIOutputClock <= 5000000UL)) || (b_PCIInputClock == APCI1710_33MHZ && (ul_SSIOutputClock > 251 && ul_SSIOutputClock <= 5000000UL))) {
- if (b_SSICountingMode == APCI1710_BINARY_MODE || b_SSICountingMode == APCI1710_GRAY_MODE) {
- /**********************/
- /* Save configuration */
- /**********************/
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_SSIProfile
- =
- b_SSIProfile;
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_PositionTurnLength
- =
- b_PositionTurnLength;
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_TurnCptLength
- =
- b_TurnCptLength;
-
- /*********************************/
- /* Initialise the profile length */
- /*********************************/
-
- if (b_SSICountingMode == APCI1710_BINARY_MODE) {
-
- outl(b_SSIProfile + 1, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
- } else {
-
- outl(b_SSIProfile, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
- }
-
- /******************************/
- /* Calculate the output clock */
- /******************************/
-
- ui_TimerValue
- =
- (unsigned int)
- (
- ((unsigned int) (b_PCIInputClock) * 500000UL) / ul_SSIOutputClock);
-
- /************************/
- /* Initialise the timer */
- /************************/
-
- outl(ui_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr));
-
- /********************************/
- /* Initialise the counting mode */
- /********************************/
-
- outl(7 * b_SSICountingMode, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_SSIInit
- =
- 1;
- } else {
- /*****************************************************/
- /* The selected SSI counting mode parameter is wrong */
- /*****************************************************/
-
- DPRINTK("The selected SSI counting mode parameter is wrong\n");
- i_ReturnValue
- =
- -9;
- }
- } else {
- /******************************************/
- /* The selected SSI output clock is wrong */
- /******************************************/
-
- DPRINTK("The selected SSI output clock is wrong\n");
- i_ReturnValue
- =
- -8;
- }
- } else {
- /*****************************************/
- /* The selected PCI input clock is wrong */
- /*****************************************/
-
- DPRINTK("The selected PCI input clock is wrong\n");
- i_ReturnValue =
- -7;
- }
- } else {
- /********************************************/
- /* The selected SSI profile length is wrong */
- /********************************************/
-
- DPRINTK("The selected SSI profile length is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /******************************************************/
- /* The selected SSI turn counter data length is wrong */
- /******************************************************/
-
- DPRINTK("The selected SSI turn counter data length is wrong\n");
- i_ReturnValue = -6;
- }
- } else {
- /**************************************************/
- /* The selected SSI position data length is wrong */
- /**************************************************/
-
- DPRINTK("The selected SSI position data length is wrong\n");
- i_ReturnValue = -5;
- }
- } else {
- /********************************************/
- /* The selected SSI profile length is wrong */
- /********************************************/
-
- DPRINTK("The selected SSI profile length is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /**********************************/
- /* The module is not a SSI module */
- /**********************************/
-
- DPRINTK("The module is not a SSI module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_Read1SSIValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_SelectedSSI, |
-| PULONG_ pul_Position, |
-| PULONG_ pul_TurnCpt)
- int i_APCI1710_ReadSSIValue(struct comedi_device *dev,struct comedi_subdevice *s,
- struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task :
-
-
- Read the selected SSI counter (b_SelectedSSI) from |
-| selected module (b_ModulNbr).
- or Read all SSI counter (b_SelectedSSI) from |
-| selected module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710|
-| unsigned char_ b_ModulNbr : Module number to |
-| configure (0 to 3) |
-| unsigned char_ b_SelectedSSI : Selection from SSI |
-| counter (0 to 2)
-
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec); (in case of single ssi)
- b_ReadType = (unsigned char) CR_RANGE(insn->chanspec);
-|
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_Position : SSI position in the turn |
-| PULONG_ pul_TurnCpt : Number of turns
-
-pul_Position = (unsigned int *) &data[0];
- pul_TurnCpt = (unsigned int *) &data[1]; |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a SSI module |
-| -4: SSI not initialised see function |
-| "i_APCI1710_InitSSI" |
-| -5: The selected SSI is wrong |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned char b_Cpt;
- unsigned char b_Length;
- unsigned char b_Schift;
- unsigned char b_SSICpt;
- unsigned int dw_And;
- unsigned int dw_And1;
- unsigned int dw_And2;
- unsigned int dw_StatusReg;
- unsigned int dw_CounterValue;
- unsigned char b_ModulNbr;
- unsigned char b_SelectedSSI;
- unsigned char b_ReadType;
- unsigned int *pul_Position;
- unsigned int *pul_TurnCpt;
- unsigned int *pul_Position1;
- unsigned int *pul_TurnCpt1;
-
- i_ReturnValue = insn->n;
- pul_Position1 = (unsigned int *) &data[0];
-/* For Read1 */
- pul_TurnCpt1 = (unsigned int *) &data[1];
-/* For Read all */
- pul_Position = (unsigned int *) &data[0]; /* 0-2 */
- pul_TurnCpt = (unsigned int *) &data[3]; /* 3-5 */
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec);
- b_ReadType = (unsigned char) CR_RANGE(insn->chanspec);
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if SSI counter */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
- /***************************/
- /* Test if SSI initialised */
- /***************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_SSICounterInfo.b_SSIInit == 1) {
-
- switch (b_ReadType) {
-
- case APCI1710_SSI_READ1VALUE:
- /****************************************/
- /* Test the selected SSI counter number */
- /****************************************/
-
- if (b_SelectedSSI < 3) {
- /************************/
- /* Start the conversion */
- /************************/
-
- outl(0, devpriv->s_BoardInfos.
- ui_Address + 8 +
- (64 * b_ModulNbr));
-
- do {
- /*******************/
- /* Read the status */
- /*******************/
-
- dw_StatusReg =
- inl(devpriv->
- s_BoardInfos.
- ui_Address +
- (64 * b_ModulNbr));
- } while ((dw_StatusReg & 0x1)
- != 0);
-
- /******************************/
- /* Read the SSI counter value */
- /******************************/
-
- dw_CounterValue =
- inl(devpriv->
- s_BoardInfos.
- ui_Address + 4 +
- (b_SelectedSSI * 4) +
- (64 * b_ModulNbr));
-
- b_Length =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_SSIProfile / 2;
-
- if ((b_Length * 2) !=
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_SSIProfile) {
- b_Length++;
- }
-
- b_Schift =
- b_Length -
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_PositionTurnLength;
-
- *pul_Position1 =
- dw_CounterValue >>
- b_Schift;
-
- dw_And = 1;
-
- for (b_Cpt = 0;
- b_Cpt <
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_PositionTurnLength;
- b_Cpt++) {
- dw_And = dw_And * 2;
- }
-
- *pul_Position1 =
- *pul_Position1 &
- ((dw_And) - 1);
-
- *pul_TurnCpt1 =
- dw_CounterValue >>
- b_Length;
-
- dw_And = 1;
-
- for (b_Cpt = 0;
- b_Cpt <
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_TurnCptLength;
- b_Cpt++) {
- dw_And = dw_And * 2;
- }
-
- *pul_TurnCpt1 =
- *pul_TurnCpt1 &
- ((dw_And) - 1);
- } else {
- /*****************************/
- /* The selected SSI is wrong */
- /*****************************/
-
- DPRINTK("The selected SSI is wrong\n");
- i_ReturnValue = -5;
- }
- break;
-
- case APCI1710_SSI_READALLVALUE:
- dw_And1 = 1;
-
- for (b_Cpt = 0;
- b_Cpt <
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SSICounterInfo.
- b_PositionTurnLength; b_Cpt++) {
- dw_And1 = dw_And1 * 2;
- }
-
- dw_And2 = 1;
-
- for (b_Cpt = 0;
- b_Cpt <
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_SSICounterInfo.
- b_TurnCptLength; b_Cpt++) {
- dw_And2 = dw_And2 * 2;
- }
-
- /************************/
- /* Start the conversion */
- /************************/
-
- outl(0, devpriv->s_BoardInfos.
- ui_Address + 8 +
- (64 * b_ModulNbr));
-
- do {
- /*******************/
- /* Read the status */
- /*******************/
-
- dw_StatusReg =
- inl(devpriv->
- s_BoardInfos.
- ui_Address +
- (64 * b_ModulNbr));
- } while ((dw_StatusReg & 0x1) != 0);
-
- for (b_SSICpt = 0; b_SSICpt < 3;
- b_SSICpt++) {
- /******************************/
- /* Read the SSI counter value */
- /******************************/
-
- dw_CounterValue =
- inl(devpriv->
- s_BoardInfos.
- ui_Address + 4 +
- (b_SSICpt * 4) +
- (64 * b_ModulNbr));
-
- b_Length =
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_SSIProfile / 2;
-
- if ((b_Length * 2) !=
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_SSIProfile) {
- b_Length++;
- }
-
- b_Schift =
- b_Length -
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_SSICounterInfo.
- b_PositionTurnLength;
-
- pul_Position[b_SSICpt] =
- dw_CounterValue >>
- b_Schift;
- pul_Position[b_SSICpt] =
- pul_Position[b_SSICpt] &
- ((dw_And1) - 1);
-
- pul_TurnCpt[b_SSICpt] =
- dw_CounterValue >>
- b_Length;
- pul_TurnCpt[b_SSICpt] =
- pul_TurnCpt[b_SSICpt] &
- ((dw_And2) - 1);
- }
- break;
-
- default:
- printk("Read Type Inputs Wrong\n");
-
- } /* switch ending */
-
- } else {
- /***********************/
- /* SSI not initialised */
- /***********************/
-
- DPRINTK("SSI not initialised\n");
- i_ReturnValue = -4;
- }
- } else {
- /**********************************/
- /* The module is not a SSI module */
- /**********************************/
-
- DPRINTK("The module is not a SSI module\n");
- i_ReturnValue = -3;
-
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadSSI1DigitalInput |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_InputChannel, |
-| unsigned char *_ pb_ChannelStatus) |
-+----------------------------------------------------------------------------+
-| Task :
- (0) Set the digital output from selected SSI module |
-| (b_ModuleNbr) ON
- (1) Set the digital output from selected SSI module |
-| (b_ModuleNbr) OFF
- (2)Read the status from selected SSI digital input |
-| (b_InputChannel)
- (3)Read the status from all SSI digital inputs from |
-| selected SSI module (b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710|
-| unsigned char_ b_ModulNbr CR_AREF : Module number to |
-| configure (0 to 3) |
-| unsigned char_ b_InputChannel CR_CHAN : Selection from digital |
-| data[0] which IOTYPE input ( 0 to 2) |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_ChannelStatus : Digital input channel |
-| data[0] status |
-| 0 : Channle is not active|
-| 1 : Channle is active |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a SSI module |
-| -4: The selected SSI digital input is wrong |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg;
- unsigned char b_ModulNbr;
- unsigned char b_InputChannel;
- unsigned char *pb_ChannelStatus;
- unsigned char *pb_InputStatus;
- unsigned char b_IOType;
-
- i_ReturnValue = insn->n;
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_IOType = (unsigned char) data[0];
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if SSI counter */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
- switch (b_IOType) {
- case APCI1710_SSI_SET_CHANNELON:
- /*****************************/
- /* Set the digital output ON */
- /*****************************/
-
- outl(1, devpriv->s_BoardInfos.ui_Address + 16 +
- (64 * b_ModulNbr));
- break;
-
- case APCI1710_SSI_SET_CHANNELOFF:
- /******************************/
- /* Set the digital output OFF */
- /******************************/
-
- outl(0, devpriv->s_BoardInfos.ui_Address + 16 +
- (64 * b_ModulNbr));
- break;
-
- case APCI1710_SSI_READ_1CHANNEL:
- /******************************************/
- /* Test the digital imnput channel number */
- /******************************************/
-
- b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec);
- pb_ChannelStatus = (unsigned char *) &data[0];
-
- if (b_InputChannel <= 2) {
- /**************************/
- /* Read all digital input */
- /**************************/
-
- dw_StatusReg =
- inl(devpriv->s_BoardInfos.
- ui_Address + (64 * b_ModulNbr));
- *pb_ChannelStatus =
- (unsigned char) (((~dw_StatusReg) >> (4 +
- b_InputChannel))
- & 1);
- } else {
- /********************************/
- /* Selected digital input error */
- /********************************/
-
- DPRINTK("Selected digital input error\n");
- i_ReturnValue = -4;
- }
- break;
-
- case APCI1710_SSI_READ_ALLCHANNEL:
- /**************************/
- /* Read all digital input */
- /**************************/
- pb_InputStatus = (unsigned char *) &data[0];
-
- dw_StatusReg =
- inl(devpriv->s_BoardInfos.ui_Address +
- (64 * b_ModulNbr));
- *pb_InputStatus =
- (unsigned char) (((~dw_StatusReg) >> 4) & 7);
- break;
-
- default:
- printk("IO type wrong\n");
-
- } /* switch end */
- } else {
- /**********************************/
- /* The module is not a SSI module */
- /**********************************/
-
- DPRINTK("The module is not a SSI module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
deleted file mode 100644
index 0b79531ac24..00000000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
+++ /dev/null
@@ -1,2065 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-----------------------------------------------------------------------+
- | Project : API APCI1710 | Compiler : gcc |
- | Module name : TOR.C | Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-----------------------------------------------------------------------+
- | Description : APCI-1710 tor counter module |
- | |
- | |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +-----------------------------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | 27/01/99 | S. Weber | 40 MHz implementation |
- +-----------------------------------------------------------------------+
- | 28/04/00 | S. Weber | Simple,double and quadruple mode implementation|
- | | | Extern clock implementation |
- +-----------------------------------------------------------------------+
- | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 |
- | | | available |
- +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_30MHZ 30
-#define APCI1710_33MHZ 33
-#define APCI1710_40MHZ 40
-
-#define APCI1710_GATE_INPUT 10
-
-#define APCI1710_TOR_SIMPLE_MODE 2
-#define APCI1710_TOR_DOUBLE_MODE 3
-#define APCI1710_TOR_QUADRUPLE_MODE 4
-
-#define APCI1710_SINGLE 0
-#define APCI1710_CONTINUOUS 1
-
-#define APCI1710_TOR_GETPROGRESSSTATUS 0
-#define APCI1710_TOR_GETCOUNTERVALUE 1
-#define APCI1710_TOR_READINTERRUPT 2
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitTorCounter |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_TorCounter, |
-| unsigned char_ b_PCIInputClock, |
-| unsigned char_ b_TimingUnit, |
-| ULONG_ ul_TimingInterval, |
-| PULONG_ pul_RealTimingInterval) |
-+----------------------------------------------------------------------------+
-| Task : Configure the selected tor counter (b_TorCounter) |
-| from selected module (b_ModulNbr). |
-| The ul_TimingInterval and ul_TimingUnit determine the |
-| timing base for the measurement. |
-| The pul_RealTimingInterval return the real timing |
-| value. You must calling this function be for you call |
-| any other function witch access of the tor counter. |
-| |
-+----------------------------------------------------------------------------+
-| Input Parameters : |
-|
- CR_AREF unsigned char_ b_ModulNbr : Module number to configure |
-| (0 to 3) |
-| data[0] unsigned char_ b_TorCounter : Tor counter selection |
-| (0 or 1). |
-| data[1] unsigned char_ b_PCIInputClock : Selection from PCI bus clock|
-| - APCI1710_30MHZ : |
-| The PC have a PCI bus |
-| clock from 30 MHz |
-| - APCI1710_33MHZ : |
-| The PC have a PCI bus |
-| clock from 33 MHz |
-| - APCI1710_40MHZ |
-| The APCI-1710 have a |
-| integrated 40Mhz |
-| quartz. |
-| - APCI1710_GATE_INPUT |
-| Used the gate input for |
-| the base clock. If you |
-| have selected this option,|
-| than it is not possibl to |
-| used the gate input for |
-| enabled the acquisition |
-| data[2] unsigned char_ b_TimingUnit : Base timing unit (0 to 4) |
-| 0 : ns |
-| 1 : µs |
-| 2 : ms |
-| 3 : s |
-| 4 : mn |
-| data[3] ULONG_ ul_TimingInterval : Base timing value. |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_RealTimingInterval : Real base timing |
-| data[0] value. |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a tor counter module |
-| -4: Tor counter selection is wrong |
-| -5: The selected PCI input clock is wrong |
-| -6: Timing unit selection is wrong |
-| -7: Base timing selection is wrong |
-| -8: You can not used the 40MHz clock selection wich |
-| this board |
-| -9: You can not used the 40MHz clock selection wich |
-| this TOR version |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnConfigInitTorCounter(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int ul_TimerValue = 0;
- unsigned int dw_Command;
- double d_RealTimingInterval = 0;
- unsigned char b_ModulNbr;
- unsigned char b_TorCounter;
- unsigned char b_PCIInputClock;
- unsigned char b_TimingUnit;
- unsigned int ul_TimingInterval;
- unsigned int ul_RealTimingInterval = 0;
-
- i_ReturnValue = insn->n;
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-
- b_TorCounter = (unsigned char) data[0];
- b_PCIInputClock = (unsigned char) data[1];
- b_TimingUnit = (unsigned char) data[2];
- ul_TimingInterval = (unsigned int) data[3];
- printk("INPUT clock %d\n", b_PCIInputClock);
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if tor counter */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
- /**********************************/
- /* Test the tor counter selection */
- /**********************************/
-
- if (b_TorCounter <= 1) {
- /**************************/
- /* Test the PCI bus clock */
- /**************************/
-
- if ((b_PCIInputClock == APCI1710_30MHZ) ||
- (b_PCIInputClock == APCI1710_33MHZ) ||
- (b_PCIInputClock == APCI1710_40MHZ) ||
- (b_PCIInputClock ==
- APCI1710_GATE_INPUT)) {
- /************************/
- /* Test the timing unit */
- /************************/
-
- if ((b_TimingUnit <= 4)
- || (b_PCIInputClock ==
- APCI1710_GATE_INPUT)) {
- /**********************************/
- /* Test the base timing selection */
- /**********************************/
-
- if (((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 133) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571230650UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571230UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 9UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 121) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 519691043UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 519691UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 520UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 8UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 100) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429496729UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429496UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 7UL)) || ((b_PCIInputClock == APCI1710_GATE_INPUT) && (ul_TimingInterval >= 2))) {
- /**************************/
- /* Test the board version */
- /**************************/
-
- if (((b_PCIInputClock == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_PCIInputClock != APCI1710_40MHZ)) {
- /************************/
- /* Test the TOR version */
- /************************/
-
- if (((b_PCIInputClock == APCI1710_40MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131)) || ((b_PCIInputClock == APCI1710_GATE_INPUT) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3132)) || (b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) {
- /*********************************/
- /* Test if not extern clock used */
- /*********************************/
-
- if (b_PCIInputClock != APCI1710_GATE_INPUT) {
- fpu_begin
- ();
- /****************************************/
- /* Calculate the timer 0 division fator */
- /****************************************/
-
- switch (b_TimingUnit) {
- /******/
- /* ns */
- /******/
-
- case 0:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- (unsigned int)
- (ul_TimingInterval
- *
- (0.00025 * b_PCIInputClock));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (0.00025 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (0.00025 * (double)b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (0.00025
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (0.00025 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
- ul_RealTimingInterval
- =
- ul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
-
- if (b_PCIInputClock != APCI1710_40MHZ) {
- ul_TimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_TimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* æs */
- /******/
-
- case 1:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- (unsigned int)
- (ul_TimingInterval
- *
- (0.25 * b_PCIInputClock));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (0.25 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (0.25 * (double)b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (
- (double)
- 0.25
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (0.25 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
- ul_RealTimingInterval
- =
- ul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
-
- if (b_PCIInputClock != APCI1710_40MHZ) {
- ul_TimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_TimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* ms */
- /******/
-
- case 2:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- ul_TimingInterval
- *
- (250.0
- *
- b_PCIInputClock);
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (250.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (250.0 * (double)b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (250.0
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (250.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
- ul_RealTimingInterval
- =
- ul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
-
- if (b_PCIInputClock != APCI1710_40MHZ) {
- ul_TimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_TimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /*****/
- /* s */
- /*****/
-
- case 3:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- (unsigned int)
- (ul_TimingInterval
- *
- (250000.0
- *
- b_PCIInputClock));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)ul_TimingInterval * (250000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (250000.0
- *
- (double)
- b_PCIInputClock));
- d_RealTimingInterval
- =
- (double)
- ul_TimerValue
- /
- (250000.0
- *
- (double)
- b_PCIInputClock);
-
- if ((double)((double)ul_TimerValue / (250000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
- ul_RealTimingInterval
- =
- ul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
-
- if (b_PCIInputClock != APCI1710_40MHZ) {
- ul_TimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_TimerValue)
- *
- 1.007752288);
- }
-
- break;
-
- /******/
- /* mn */
- /******/
-
- case 4:
-
- /******************/
- /* Timer 0 factor */
- /******************/
-
- ul_TimerValue
- =
- (unsigned int)
- (
- (ul_TimingInterval
- *
- 60)
- *
- (250000.0
- *
- b_PCIInputClock));
-
- /*******************/
- /* Round the value */
- /*******************/
-
- if ((double)((double)(ul_TimingInterval * 60.0) * (250000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
- ul_TimerValue
- =
- ul_TimerValue
- +
- 1;
- }
-
- /*****************************/
- /* Calculate the real timing */
- /*****************************/
-
- ul_RealTimingInterval
- =
- (unsigned int)
- (ul_TimerValue
- /
- (250000.0
- *
- (double)
- b_PCIInputClock))
- /
- 60;
- d_RealTimingInterval
- =
- (
- (double)
- ul_TimerValue
- /
- (250000.0
- *
- (double)
- b_PCIInputClock))
- /
- 60.0;
-
- if ((double)(((double)ul_TimerValue / (250000.0 * (double)b_PCIInputClock)) / 60.0) >= (double)((double)ul_RealTimingInterval + 0.5)) {
- ul_RealTimingInterval
- =
- ul_RealTimingInterval
- +
- 1;
- }
-
- ul_TimingInterval
- =
- ul_TimingInterval
- -
- 1;
- ul_TimerValue
- =
- ul_TimerValue
- -
- 2;
-
- if (b_PCIInputClock != APCI1710_40MHZ) {
- ul_TimerValue
- =
- (unsigned int)
- (
- (double)
- (ul_TimerValue)
- *
- 1.007752288);
- }
-
- break;
- }
-
- fpu_end();
- } /* if (b_PCIInputClock != APCI1710_GATE_INPUT) */
- else {
- /*************************************************************/
- /* 2 Clock used for the overflow and the reload from counter */
- /*************************************************************/
-
- ul_TimerValue
- =
- ul_TimingInterval
- -
- 2;
- } /* if (b_PCIInputClock != APCI1710_GATE_INPUT) */
-
- /****************************/
- /* Save the PCI input clock */
- /****************************/
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TorCounterModuleInfo.
- b_PCIInputClock
- =
- b_PCIInputClock;
-
- /************************/
- /* Save the timing unit */
- /************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TorCounterModuleInfo.
- s_TorCounterInfo
- [b_TorCounter].
- b_TimingUnit
- =
- b_TimingUnit;
-
- /************************/
- /* Save the base timing */
- /************************/
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TorCounterModuleInfo.
- s_TorCounterInfo
- [b_TorCounter].
- d_TimingInterval
- =
- d_RealTimingInterval;
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TorCounterModuleInfo.
- s_TorCounterInfo
- [b_TorCounter].
- ul_RealTimingInterval
- =
- ul_RealTimingInterval;
-
- /*******************/
- /* Get the command */
- /*******************/
-
- dw_Command
- =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- 4
- +
- (16 * b_TorCounter) + (64 * b_ModulNbr));
-
- dw_Command
- =
- (dw_Command
- >>
- 4)
- &
- 0xF;
-
- /******************/
- /* Test if 40 MHz */
- /******************/
-
- if (b_PCIInputClock == APCI1710_40MHZ) {
- /****************************/
- /* Set the 40 MHz selection */
- /****************************/
-
- dw_Command
- =
- dw_Command
- |
- 0x10;
- }
-
- /*****************************/
- /* Test if extern clock used */
- /*****************************/
-
- if (b_PCIInputClock == APCI1710_GATE_INPUT) {
- /****************************/
- /* Set the 40 MHz selection */
- /****************************/
-
- dw_Command
- =
- dw_Command
- |
- 0x20;
- }
-
- /*************************/
- /* Write the new command */
- /*************************/
-
- outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 4 + (16 * b_TorCounter) + (64 * b_ModulNbr));
-
- /*******************/
- /* Disable the tor */
- /*******************/
-
- outl(0, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr));
- /*************************/
- /* Set the timer 1 value */
- /*************************/
-
- outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (16 * b_TorCounter) + (64 * b_ModulNbr));
-
- /*********************/
- /* Tor counter init. */
- /*********************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TorCounterModuleInfo.
- s_TorCounterInfo
- [b_TorCounter].
- b_TorCounterInit
- =
- 1;
- } else {
- /***********************************************/
- /* TOR version error for 40MHz clock selection */
- /***********************************************/
-
- DPRINTK("TOR version error for 40MHz clock selection\n");
- i_ReturnValue
- =
- -9;
- }
- } else {
- /**************************************************************/
- /* You can not used the 40MHz clock selection wich this board */
- /**************************************************************/
-
- DPRINTK("You can not used the 40MHz clock selection wich this board\n");
- i_ReturnValue =
- -8;
- }
- } else {
- /**********************************/
- /* Base timing selection is wrong */
- /**********************************/
-
- DPRINTK("Base timing selection is wrong\n");
- i_ReturnValue = -7;
- }
- } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
- else {
- /**********************************/
- /* Timing unit selection is wrong */
- /**********************************/
-
- DPRINTK("Timing unit selection is wrong\n");
- i_ReturnValue = -6;
- } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
- } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */
- else {
- /*****************************************/
- /* The selected PCI input clock is wrong */
- /*****************************************/
-
- DPRINTK("The selected PCI input clock is wrong\n");
- i_ReturnValue = -5;
- } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */
- } /* if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) */
- else {
- /**********************************/
- /* Tor Counter selection is wrong */
- /**********************************/
-
- DPRINTK("Tor Counter selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) */
- } else {
- /******************************************/
- /* The module is not a tor counter module */
- /******************************************/
-
- DPRINTK("The module is not a tor counter module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
- data[0] = (unsigned int) ul_RealTimingInterval;
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_EnableTorCounter |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_TorCounter, |
-| unsigned char_ b_InputMode, |
-| unsigned char_ b_ExternGate, |
-| unsigned char_ b_CycleMode, |
-| unsigned char_ b_InterruptEnable) |
-+----------------------------------------------------------------------------+
-| Task : Enable the tor counter (b_TorCounter) from selected |
-| module (b_ModulNbr). You must calling the |
-| "i_APCI1710_InitTorCounter" function be for you call |
-| this function. |
-| If you enable the tor counter interrupt, the |
-| tor counter generate a interrupt after the timing cycle|
-| See function "i_APCI1710_SetBoardIntRoutineX" and the |
-| Interrupt mask description chapter from this manual. |
-| The b_CycleMode parameter determine if you will |
-| measured a single or more cycle. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3) |
-| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). |
-| unsigned char_ b_InputMode : Input signal level selection |
-| 0 : Tor count each low level |
-| 1 : Tor count each high level|
-| unsigned char_ b_ExternGate : Extern gate action selection |
-| 0 : Extern gate signal not |
-| used |
-| 1 : Extern gate signal used. |
-| If you selected the |
-| single mode, each high |
-| level signal start the |
-| counter. |
-| If you selected the |
-| continuous mode, the |
-| first high level signal |
-| start the tor counter |
-| |
-| APCI1710_TOR_QUADRUPLE _MODE : |
-| In the quadruple mode, the edge|
-| analysis circuit generates a |
-| counting pulse from each edge |
-| of 2 signals which are phase |
-| shifted in relation to each |
-| other. |
-| The gate input is used for the |
-| signal B |
-| |
-| APCI1710_TOR_DOUBLE_MODE: |
-| Functions in the same way as |
-| the quadruple mode, except that|
-| only two of the four edges are |
-| analysed per period. |
-| The gate input is used for the |
-| signal B |
-| |
-| APCI1710_TOR_SIMPLE_MODE: |
-| Functions in the same way as |
-| the quadruple mode, except that|
-| only one of the four edges is |
-| analysed per period. |
-| The gate input is used for the |
-| signal B |
-| |
-| unsigned char_ b_CycleMode : Selected the tor counter |
-| acquisition mode |
-| unsigned char_ b_InterruptEnable : Enable or disable the |
-| tor counter interrupt. |
-| APCI1710_ENABLE: |
-| Enable the tor counter |
-| interrupt |
-| APCI1710_DISABLE: |
-| Disable the tor counter |
-| interrupt |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a tor counter module |
-| -4: Tor counter selection is wrong |
-| -5: Tor counter not initialised see function |
-| "i_APCI1710_InitTorCounter" |
-| -6: Tor input signal selection is wrong |
-| -7: Extern gate signal mode is wrong |
-| -8: Tor counter acquisition mode cycle is wrong |
-| -9: Interrupt parameter is wrong |
-| -10:Interrupt function not initialised. |
-| See function "i_APCI1710_SetBoardIntRoutineX" |
-+----------------------------------------------------------------------------+
-*/
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_DisableTorCounter |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_TorCounter) |
-+----------------------------------------------------------------------------+
-| Task : Disable the tor counter (b_TorCounter) from selected |
-| module (b_ModulNbr). If you disable the tor counter |
-| after a start cycle occur and you restart the tor |
-| counter witch the " i_APCI1710_EnableTorCounter" |
-| function, the status register is cleared |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3) |
-| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a tor counter module |
-| -4: Tor counter selection is wrong |
-| -5: Tor counter not initialised see function |
-| "i_APCI1710_InitTorCounter" |
-| -6: Tor counter not enabled see function |
-| "i_APCI1710_EnableTorCounter" |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_Status;
- unsigned int dw_DummyRead;
- unsigned int dw_ConfigReg;
- unsigned char b_ModulNbr, b_Action;
- unsigned char b_TorCounter;
- unsigned char b_InputMode;
- unsigned char b_ExternGate;
- unsigned char b_CycleMode;
- unsigned char b_InterruptEnable;
-
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_Action = (unsigned char) data[0]; /* enable or disable */
- b_TorCounter = (unsigned char) data[1];
- b_InputMode = (unsigned char) data[2];
- b_ExternGate = (unsigned char) data[3];
- b_CycleMode = (unsigned char) data[4];
- b_InterruptEnable = (unsigned char) data[5];
- i_ReturnValue = insn->n;
- devpriv->tsk_Current = current; /* Save the current process task structure */
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if tor counter */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
- /**********************************/
- /* Test the tor counter selection */
- /**********************************/
-
- if (b_TorCounter <= 1) {
- switch (b_Action) /* Enable or Disable */
- {
- case APCI1710_ENABLE:
- /***********************************/
- /* Test if tor counter initialised */
- /***********************************/
-
- dw_Status =
- inl(devpriv->s_BoardInfos.
- ui_Address + 8 +
- (16 * b_TorCounter) +
- (64 * b_ModulNbr));
-
- if (dw_Status & 0x10) {
- /******************************/
- /* Test the input signal mode */
- /******************************/
-
- if (b_InputMode == 0 ||
- b_InputMode == 1 ||
- b_InputMode ==
- APCI1710_TOR_SIMPLE_MODE
- || b_InputMode ==
- APCI1710_TOR_DOUBLE_MODE
- || b_InputMode ==
- APCI1710_TOR_QUADRUPLE_MODE)
- {
- /************************************/
- /* Test the extern gate signal mode */
- /************************************/
-
- if (b_ExternGate == 0
- || b_ExternGate
- == 1
- || b_InputMode >
- 1) {
- /*********************************/
- /* Test the cycle mode parameter */
- /*********************************/
-
- if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) {
- /***************************/
- /* Test the interrupt flag */
- /***************************/
-
- if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) {
-
- /***************************/
- /* Save the interrupt mode */
- /***************************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TorCounterModuleInfo.
- s_TorCounterInfo
- [b_TorCounter].
- b_InterruptEnable
- =
- b_InterruptEnable;
-
- /*******************/
- /* Get the command */
- /*******************/
-
- dw_ConfigReg
- =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- 4
- +
- (16 * b_TorCounter) + (64 * b_ModulNbr));
-
- dw_ConfigReg
- =
- (dw_ConfigReg
- >>
- 4)
- &
- 0x30;
-
- /********************************/
- /* Test if not direct mode used */
- /********************************/
-
- if (b_InputMode > 1) {
- /*******************************/
- /* Extern gate can not be used */
- /*******************************/
-
- b_ExternGate
- =
- 0;
-
- /*******************************************/
- /* Enable the extern gate for the Signal B */
- /*******************************************/
-
- dw_ConfigReg
- =
- dw_ConfigReg
- |
- 0x40;
-
- /***********************/
- /* Test if simple mode */
- /***********************/
-
- if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) {
- /**************************/
- /* Enable the sinple mode */
- /**************************/
-
- dw_ConfigReg
- =
- dw_ConfigReg
- |
- 0x780;
-
- } /* if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) */
-
- /***********************/
- /* Test if double mode */
- /***********************/
-
- if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) {
- /**************************/
- /* Enable the double mode */
- /**************************/
-
- dw_ConfigReg
- =
- dw_ConfigReg
- |
- 0x180;
-
- } /* if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) */
-
- b_InputMode
- =
- 0;
- } /* if (b_InputMode > 1) */
-
- /*******************/
- /* Set the command */
- /*******************/
-
- dw_ConfigReg
- =
- dw_ConfigReg
- |
- b_CycleMode
- |
- (b_InterruptEnable
- *
- 2)
- |
- (b_InputMode
- *
- 4)
- |
- (b_ExternGate
- *
- 8);
-
- /*****************************/
- /* Clear the status register */
- /*****************************/
-
- dw_DummyRead
- =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- 0
- +
- (16 * b_TorCounter) + (64 * b_ModulNbr));
-
- /***************************************/
- /* Clear the interrupt status register */
- /***************************************/
-
- dw_DummyRead
- =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- 12
- +
- (16 * b_TorCounter) + (64 * b_ModulNbr));
-
- /********************/
- /* Set the commando */
- /********************/
-
- outl(dw_ConfigReg, devpriv->s_BoardInfos.ui_Address + 4 + (16 * b_TorCounter) + (64 * b_ModulNbr));
-
- /****************/
- /* Set the gate */
- /****************/
-
- outl(1, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr));
-
- } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */
- else {
- /********************************/
- /* Interrupt parameter is wrong */
- /********************************/
-
- DPRINTK("Interrupt parameter is wrong\n");
- i_ReturnValue
- =
- -9;
- } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */
- } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */
- else {
- /***********************************************/
- /* Tor counter acquisition mode cycle is wrong */
- /***********************************************/
-
- DPRINTK("Tor counter acquisition mode cycle is wrong\n");
- i_ReturnValue
- =
- -8;
- } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */
- } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */
- else {
- /***********************************/
- /* Extern gate input mode is wrong */
- /***********************************/
-
- DPRINTK("Extern gate input mode is wrong\n");
- i_ReturnValue =
- -7;
- } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */
- } /* if (b_InputMode >= 0 && b_InputMode <= 1) */
- else {
- /***************************************/
- /* Tor input signal selection is wrong */
- /***************************************/
-
- DPRINTK("Tor input signal selection is wrong\n");
- i_ReturnValue = -6;
- }
- } else {
- /*******************************/
- /* Tor counter not initialised */
- /*******************************/
-
- DPRINTK("Tor counter not initialised\n");
- i_ReturnValue = -5;
- }
- break;
-
- case APCI1710_DISABLE:
- /***********************************/
- /* Test if tor counter initialised */
- /***********************************/
-
- dw_Status = inl(devpriv->s_BoardInfos.
- ui_Address + 8 +
- (16 * b_TorCounter) +
- (64 * b_ModulNbr));
-
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (dw_Status & 0x10) {
- /***************************/
- /* Test if counter enabled */
- /***************************/
-
- if (dw_Status & 0x1) {
- /****************************/
- /* Clear the interrupt mode */
- /****************************/
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TorCounterModuleInfo.
- s_TorCounterInfo
- [b_TorCounter].
- b_InterruptEnable
- =
- APCI1710_DISABLE;
-
- /******************/
- /* Clear the gate */
- /******************/
-
- outl(0, devpriv->
- s_BoardInfos.
- ui_Address + 8 +
- (16 * b_TorCounter) + (64 * b_ModulNbr));
- } /* if (dw_Status & 0x1) */
- else {
- /***************************/
- /* Tor counter not enabled */
- /***************************/
-
- DPRINTK("Tor counter not enabled \n");
- i_ReturnValue = -6;
- } /* if (dw_Status & 0x1) */
- } /* if (dw_Status & 0x10) */
- else {
- /*******************************/
- /* Tor counter not initialised */
- /*******************************/
-
- DPRINTK("Tor counter not initialised\n");
- i_ReturnValue = -5;
- } /* // if (dw_Status & 0x10) */
-
- } /* switch */
- } /* if (b_TorCounter <= 1) */
- else {
- /**********************************/
- /* Tor counter selection is wrong */
- /**********************************/
-
- DPRINTK("Tor counter selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_TorCounter <= 1) */
- } else {
- /******************************************/
- /* The module is not a tor counter module */
- /******************************************/
-
- DPRINTK("The module is not a tor counter module \n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error \n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_GetTorCounterInitialisation |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_TorCounter, |
-| unsigned char *_ pb_TimingUnit, |
-| PULONG_ pul_TimingInterval, |
-| unsigned char *_ pb_InputMode, |
-| unsigned char *_ pb_ExternGate, |
-| unsigned char *_ pb_CycleMode, |
-| unsigned char *_ pb_Enable, |
-| unsigned char *_ pb_InterruptEnable)|
-+----------------------------------------------------------------------------+
-| Task : Enable the tor counter (b_TorCounter) from selected |
-| module (b_ModulNbr). You must calling the |
-| "i_APCI1710_InitTorCounter" function be for you call |
-| this function. |
-| If you enable the tor counter interrupt, the |
-| tor counter generate a interrupt after the timing cycle|
-| See function "i_APCI1710_SetBoardIntRoutineX" and the |
-| Interrupt mask description chapter from this manual. |
-| The b_CycleMode parameter determine if you will |
-| measured a single or more cycle. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3) |
-| unsigned char_ b_TorCounter : Tor counter selection (0 or 1)
-
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_TorCounter = CR_CHAN(insn->chanspec);
-. |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_TimingUnit : Base timing unit (0 to 4) |
-| 0 : ns |
-| 1 : µs |
-| 2 : ms |
-| 3 : s |
-| 4 : mn |
-| PULONG_ pul_TimingInterval : Base timing value. |
-| unsigned char *_ pb_InputMode : Input signal level |
-| selection |
-| 0 : Tor count each low level |
-| 1 : Tor count each high level|
-| unsigned char *_ pb_ExternGate : Extern gate action |
-| selection |
-| 0 : Extern gate signal not |
-| used |
-| 1 : Extern gate signal used|
-| unsigned char *_ pb_CycleMode : Tor counter acquisition |
-| mode |
-| unsigned char *_ pb_Enable : Indicate if the tor counter|
-| is enabled or no |
-| 0 : Tor counter disabled |
-| 1 : Tor counter enabled |
-| unsigned char *_ pb_InterruptEnable : Enable or disable the |
-| tor counter interrupt. |
-| APCI1710_ENABLE: |
-| Enable the tor counter |
-| interrupt |
-| APCI1710_DISABLE: |
-| Disable the tor counter |
-| interrupt
- pb_TimingUnit = (unsigned char *) &data[0];
- pul_TimingInterval = (unsigned int *) &data[1];
- pb_InputMode = (unsigned char *) &data[2];
- pb_ExternGate = (unsigned char *) &data[3];
- pb_CycleMode = (unsigned char *) &data[4];
- pb_Enable = (unsigned char *) &data[5];
- pb_InterruptEnable = (unsigned char *) &data[6];
- |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a tor counter module |
-| -4: Tor counter selection is wrong |
-| -5: Tor counter not initialised see function |
-| "i_APCI1710_InitTorCounter" |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_Status;
- unsigned char b_ModulNbr;
- unsigned char b_TorCounter;
- unsigned char *pb_TimingUnit;
- unsigned int *pul_TimingInterval;
- unsigned char *pb_InputMode;
- unsigned char *pb_ExternGate;
- unsigned char *pb_CycleMode;
- unsigned char *pb_Enable;
- unsigned char *pb_InterruptEnable;
-
- i_ReturnValue = insn->n;
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_TorCounter = CR_CHAN(insn->chanspec);
-
- pb_TimingUnit = (unsigned char *) &data[0];
- pul_TimingInterval = (unsigned int *) &data[1];
- pb_InputMode = (unsigned char *) &data[2];
- pb_ExternGate = (unsigned char *) &data[3];
- pb_CycleMode = (unsigned char *) &data[4];
- pb_Enable = (unsigned char *) &data[5];
- pb_InterruptEnable = (unsigned char *) &data[6];
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if tor counter */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
- /**********************************/
- /* Test the tor counter selection */
- /**********************************/
-
- if (b_TorCounter <= 1) {
-
- /***********************************/
- /* Test if tor counter initialised */
- /***********************************/
-
- dw_Status = inl(devpriv->s_BoardInfos.
- ui_Address + 8 + (16 * b_TorCounter) +
- (64 * b_ModulNbr));
-
- if (dw_Status & 0x10) {
- *pb_Enable = dw_Status & 1;
-
- /********************/
- /* Get the commando */
- /********************/
-
- dw_Status = inl(devpriv->s_BoardInfos.
- ui_Address + 4 +
- (16 * b_TorCounter) +
- (64 * b_ModulNbr));
-
- *pb_CycleMode =
- (unsigned char) ((dw_Status >> 4) & 1);
- *pb_InterruptEnable =
- (unsigned char) ((dw_Status >> 5) & 1);
-
- /******************************************************/
- /* Test if extern gate used for clock or for signal B */
- /******************************************************/
-
- if (dw_Status & 0x600) {
- /*****************************************/
- /* Test if extern gate used for signal B */
- /*****************************************/
-
- if (dw_Status & 0x400) {
- /***********************/
- /* Test if simple mode */
- /***********************/
-
- if ((dw_Status & 0x7800)
- == 0x7800) {
- *pb_InputMode =
- APCI1710_TOR_SIMPLE_MODE;
- }
-
- /***********************/
- /* Test if double mode */
- /***********************/
-
- if ((dw_Status & 0x7800)
- == 0x1800) {
- *pb_InputMode =
- APCI1710_TOR_DOUBLE_MODE;
- }
-
- /**************************/
- /* Test if quadruple mode */
- /**************************/
-
- if ((dw_Status & 0x7800)
- == 0x0000) {
- *pb_InputMode =
- APCI1710_TOR_QUADRUPLE_MODE;
- }
- } /* if (dw_Status & 0x400) */
- else {
- *pb_InputMode = 1;
- } /* // if (dw_Status & 0x400) */
-
- /************************/
- /* Extern gate not used */
- /************************/
-
- *pb_ExternGate = 0;
- } /* if (dw_Status & 0x600) */
- else {
- *pb_InputMode =
- (unsigned char) ((dw_Status >> 6)
- & 1);
- *pb_ExternGate =
- (unsigned char) ((dw_Status >> 7)
- & 1);
- } /* if (dw_Status & 0x600) */
-
- *pb_TimingUnit =
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_TorCounterModuleInfo.
- s_TorCounterInfo[b_TorCounter].
- b_TimingUnit;
-
- *pul_TimingInterval =
- devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_TorCounterModuleInfo.
- s_TorCounterInfo[b_TorCounter].
- ul_RealTimingInterval;
- } else {
- /*******************************/
- /* Tor counter not initialised */
- /*******************************/
-
- DPRINTK("Tor counter not initialised\n");
- i_ReturnValue = -5;
- }
-
- } /* if (b_TorCounter <= 1) */
- else {
- /**********************************/
- /* Tor counter selection is wrong */
- /**********************************/
-
- DPRINTK("Tor counter selection is wrong \n");
- i_ReturnValue = -4;
- } /* if (b_TorCounter <= 1) */
- } else {
- /******************************************/
- /* The module is not a tor counter module */
- /******************************************/
-
- DPRINTK("The module is not a tor counter module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadTorCounterValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_TorCounter, |
-| unsigned int_ ui_TimeOut, |
-| unsigned char *_ pb_TorCounterStatus, |
-| PULONG_ pul_TorCounterValue) |
-+----------------------------------------------------------------------------+
-| Task case APCI1710_TOR_GETPROGRESSSTATUS: Return the tor counter
-(b_TorCounter) status (pb_TorCounterStatus) from selected tor counter |
-| module (b_ModulNbr).
-
- case APCI1710_TOR_GETCOUNTERVALUE :
- Return the tor counter (b_TorCounter) status |
-| (pb_TorCounterStatus) and the timing value |
-| (pul_TorCounterValue) after a conting cycle stop |
-| from selected tor counter module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3) |
-| unsigned char_ b_TorCounter : Tor counter selection (0 or 1).
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_ReadType = (unsigned char) data[0];
- b_TorCounter = (unsigned char) data[1];
- ui_TimeOut = (unsigned int) data[2]; |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_TorCounterStatus : Return the tor counter |
-| status. |
-| 0 : Conting cycle not started|
-| Software gate not set. |
-| 1 : Conting cycle started. |
-| Software gate set. |
-| 2 : Conting cycle stopped. |
-| The conting cycle is |
-| terminate. |
-| 3 : A overflow occur. You |
-| must change the base |
-| timing witch the |
-| function |
-| "i_APCI1710_InitTorCounter"|
-| 4 : Timeeout occur |
-| unsigned int * pul_TorCounterValue : Tor counter value.
- pb_TorCounterStatus=(unsigned char *) &data[0];
- pul_TorCounterValue=(unsigned int *) &data[1]; |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: Module selection wrong |
-| -3: The module is not a tor counter module |
-| -4: Tor counter selection is wrong |
-| -5: Tor counter not initialised see function |
-| "i_APCI1710_InitTorCounter" |
-| -6: Tor counter not enabled see function |
-| "i_APCI1710_EnableTorCounter" |
-| -7: Timeout parameter is wrong (0 to 65535) |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_Status;
- unsigned int dw_TimeOut = 0;
- unsigned char b_ModulNbr;
- unsigned char b_TorCounter;
- unsigned char b_ReadType;
- unsigned int ui_TimeOut;
- unsigned char *pb_TorCounterStatus;
- unsigned int *pul_TorCounterValue;
-
- i_ReturnValue = insn->n;
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_ReadType = (unsigned char) data[0];
- b_TorCounter = (unsigned char) data[1];
- ui_TimeOut = (unsigned int) data[2];
- pb_TorCounterStatus = (unsigned char *) &data[0];
- pul_TorCounterValue = (unsigned int *) &data[1];
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ReadType == APCI1710_TOR_READINTERRUPT) {
-
- data[0] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].b_OldModuleMask;
- data[1] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].ul_OldInterruptMask;
- data[2] = devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
- /**************************/
- /* Increment the read FIFO */
- /***************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Read = (devpriv->
- s_InterruptParameters.
- ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-
- return insn->n;
- }
-
- if (b_ModulNbr < 4) {
- /***********************/
- /* Test if tor counter */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
- /**********************************/
- /* Test the tor counter selection */
- /**********************************/
-
- if (b_TorCounter <= 1) {
- /***********************************/
- /* Test if tor counter initialised */
- /***********************************/
-
- dw_Status = inl(devpriv->s_BoardInfos.
- ui_Address + 8 + (16 * b_TorCounter) +
- (64 * b_ModulNbr));
-
- /*******************************/
- /* Test if counter initialised */
- /*******************************/
-
- if (dw_Status & 0x10) {
- /***************************/
- /* Test if counter enabled */
- /***************************/
-
- if (dw_Status & 0x1) {
-
- switch (b_ReadType) {
-
- case APCI1710_TOR_GETPROGRESSSTATUS:
- /*******************/
- /* Read the status */
- /*******************/
-
- dw_Status =
- inl(devpriv->
- s_BoardInfos.
- ui_Address + 4 +
- (16 * b_TorCounter) + (64 * b_ModulNbr));
-
- dw_Status =
- dw_Status & 0xF;
-
- /*****************/
- /* Test if start */
- /*****************/
-
- if (dw_Status & 1) {
- if (dw_Status &
- 2) {
- if (dw_Status & 4) {
- /************************/
- /* Tor counter overflow */
- /************************/
-
- *pb_TorCounterStatus
- =
- 3;
- } else {
- /***********************/
- /* Tor counter started */
- /***********************/
-
- *pb_TorCounterStatus
- =
- 2;
- }
- } else {
- /***********************/
- /* Tor counter started */
- /***********************/
-
- *pb_TorCounterStatus
- =
- 1;
- }
- } else {
- /***************************/
- /* Tor counter not started */
- /***************************/
-
- *pb_TorCounterStatus
- = 0;
- }
- break;
-
- case APCI1710_TOR_GETCOUNTERVALUE:
-
- /*****************************/
- /* Test the timout parameter */
- /*****************************/
-
- if ((ui_TimeOut >= 0)
- && (ui_TimeOut
- <=
- 65535UL))
- {
- for (;;) {
- /*******************/
- /* Read the status */
- /*******************/
-
- dw_Status
- =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- 4
- +
- (16 * b_TorCounter) + (64 * b_ModulNbr));
- /********************/
- /* Test if overflow */
- /********************/
-
- if ((dw_Status & 4) == 4) {
- /******************/
- /* Overflow occur */
- /******************/
-
- *pb_TorCounterStatus
- =
- 3;
-
- /******************/
- /* Read the value */
- /******************/
-
- *pul_TorCounterValue
- =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- 0
- +
- (16 * b_TorCounter) + (64 * b_ModulNbr));
- break;
- } /* if ((dw_Status & 4) == 4) */
- else {
- /*******************************/
- /* Test if measurement stopped */
- /*******************************/
-
- if ((dw_Status & 2) == 2) {
- /***********************/
- /* A stop signal occur */
- /***********************/
-
- *pb_TorCounterStatus
- =
- 2;
-
- /******************/
- /* Read the value */
- /******************/
-
- *pul_TorCounterValue
- =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- 0
- +
- (16 * b_TorCounter) + (64 * b_ModulNbr));
-
- break;
- } /* if ((dw_Status & 2) == 2) */
- else {
- /*******************************/
- /* Test if measurement started */
- /*******************************/
-
- if ((dw_Status & 1) == 1) {
- /************************/
- /* A start signal occur */
- /************************/
-
- *pb_TorCounterStatus
- =
- 1;
- } /* if ((dw_Status & 1) == 1) */
- else {
- /***************************/
- /* Measurement not started */
- /***************************/
-
- *pb_TorCounterStatus
- =
- 0;
- } /* if ((dw_Status & 1) == 1) */
- } /* if ((dw_Status & 2) == 2) */
- } /* if ((dw_Status & 8) == 8) */
-
- if (dw_TimeOut == ui_TimeOut) {
- /*****************/
- /* Timeout occur */
- /*****************/
-
- break;
- } else {
- /*************************/
- /* Increment the timeout */
- /*************************/
-
- dw_TimeOut
- =
- dw_TimeOut
- +
- 1;
-
- mdelay(1000);
- }
- } /* for (;;) */
-
- /*************************/
- /* Test if timeout occur */
- /*************************/
-
- if ((*pb_TorCounterStatus != 3) && (dw_TimeOut == ui_TimeOut) && (ui_TimeOut != 0)) {
- /*****************/
- /* Timeout occur */
- /*****************/
-
- *pb_TorCounterStatus
- =
- 4;
- }
- } else {
- /******************************/
- /* Timeout parameter is wrong */
- /******************************/
-
- DPRINTK("Timeout parameter is wrong\n");
- i_ReturnValue =
- -7;
- }
- break;
-
- default:
- printk("Inputs wrong\n");
- } /* switch end */
- } /* if (dw_Status & 0x1) */
- else {
- /***************************/
- /* Tor counter not enabled */
- /***************************/
-
- DPRINTK("Tor counter not enabled\n");
- i_ReturnValue = -6;
- } /* if (dw_Status & 0x1) */
- } else {
- /*******************************/
- /* Tor counter not initialised */
- /*******************************/
-
- DPRINTK("Tor counter not initialised\n");
- i_ReturnValue = -5;
- }
- } /* if (b_TorCounter <= 1) */
- else {
- /**********************************/
- /* Tor counter selection is wrong */
- /**********************************/
-
- DPRINTK("Tor counter selection is wrong\n");
- i_ReturnValue = -4;
- } /* if (b_TorCounter <= 1) */
- } else {
- /******************************************/
- /* The module is not a tor counter module */
- /******************************************/
-
- DPRINTK("The module is not a tor counter module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c
deleted file mode 100644
index fb56360444e..00000000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c
+++ /dev/null
@@ -1,1044 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-----------------------------------------------------------------------+
- | Project : API APCI1710 | Compiler : gcc |
- | Module name : TTL.C | Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-----------------------------------------------------------------------+
- | Description : APCI-1710 TTL I/O module |
- | |
- | |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +-----------------------------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | 13/05/98 | S. Weber | TTL digital input / output implementation |
- |----------|-----------|------------------------------------------------|
- | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 |
- | | | available |
- +-----------------------------------------------------------------------+
- | | | |
- | | | |
- +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_TTL_INIT 0
-#define APCI1710_TTL_INITDIRECTION 1
-
-#define APCI1710_TTL_READCHANNEL 0
-#define APCI1710_TTL_READPORT 1
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_InitTTLIODirection |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_PortAMode, |
-| unsigned char_ b_PortBMode, |
-| unsigned char_ b_PortCMode, |
-| unsigned char_ b_PortDMode) |
-+----------------------------------------------------------------------------+
-| Task APCI1710_TTL_INIT (using defaults) : Configure the TTL I/O operating mode from selected |
-| module (b_ModulNbr). You must calling this function be|
-| for you call any other function witch access of TTL. |
- APCI1710_TTL_INITDIRECTION(user inputs for direction)
-
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710|
-| unsigned char_ b_ModulNbr : Module number to |
-| configure (0 to 3)
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_InitType = (unsigned char) data[0];
- b_PortAMode = (unsigned char) data[1];
- b_PortBMode = (unsigned char) data[2];
- b_PortCMode = (unsigned char) data[3];
- b_PortDMode = (unsigned char) data[4];|
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a TTL module |
-| -4: Function not available for this version |
-| -5: Port A mode selection is wrong |
-| -6: Port B mode selection is wrong |
-| -7: Port C mode selection is wrong |
-| -8: Port D mode selection is wrong |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnConfigInitTTLIO(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned char b_ModulNbr;
- unsigned char b_InitType;
- unsigned char b_PortAMode;
- unsigned char b_PortBMode;
- unsigned char b_PortCMode;
- unsigned char b_PortDMode;
-
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- b_InitType = (unsigned char) data[0];
- i_ReturnValue = insn->n;
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /**************************/
- /* Test if TTL I/O module */
- /**************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_TTL_IO) {
- switch (b_InitType) {
- case APCI1710_TTL_INIT:
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.b_TTLInit = 1;
-
- /***************************/
- /* Set TTL port A to input */
- /***************************/
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.b_PortConfiguration[0] = 0;
-
- /***************************/
- /* Set TTL port B to input */
- /***************************/
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.b_PortConfiguration[1] = 0;
-
- /***************************/
- /* Set TTL port C to input */
- /***************************/
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.b_PortConfiguration[2] = 0;
-
- /****************************/
- /* Set TTL port D to output */
- /****************************/
-
- devpriv->s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.b_PortConfiguration[3] = 1;
-
- /*************************/
- /* Set the configuration */
- /*************************/
-
- outl(0x8,
- devpriv->s_BoardInfos.ui_Address + 20 +
- (64 * b_ModulNbr));
- break;
-
- case APCI1710_TTL_INITDIRECTION:
-
- b_PortAMode = (unsigned char) data[1];
- b_PortBMode = (unsigned char) data[2];
- b_PortCMode = (unsigned char) data[3];
- b_PortDMode = (unsigned char) data[4];
-
- /********************/
- /* Test the version */
- /********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr] & 0xFFFF) >=
- 0x3230) {
- /************************/
- /* Test the port A mode */
- /************************/
-
- if ((b_PortAMode == 0)
- || (b_PortAMode == 1)) {
- /************************/
- /* Test the port B mode */
- /************************/
-
- if ((b_PortBMode == 0)
- || (b_PortBMode == 1)) {
- /************************/
- /* Test the port C mode */
- /************************/
-
- if ((b_PortCMode == 0)
- || (b_PortCMode
- == 1)) {
- /************************/
- /* Test the port D mode */
- /************************/
-
- if ((b_PortDMode == 0) || (b_PortDMode == 1)) {
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TTLIOInfo.
- b_TTLInit
- =
- 1;
-
- /***********************/
- /* Set TTL port A mode */
- /***********************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration
- [0]
- =
- b_PortAMode;
-
- /***********************/
- /* Set TTL port B mode */
- /***********************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration
- [1]
- =
- b_PortBMode;
-
- /***********************/
- /* Set TTL port C mode */
- /***********************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration
- [2]
- =
- b_PortCMode;
-
- /***********************/
- /* Set TTL port D mode */
- /***********************/
-
- devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration
- [3]
- =
- b_PortDMode;
-
- /*************************/
- /* Set the configuration */
- /*************************/
-
- outl((b_PortAMode << 0) | (b_PortBMode << 1) | (b_PortCMode << 2) | (b_PortDMode << 3), devpriv->s_BoardInfos.ui_Address + 20 + (64 * b_ModulNbr));
- } else {
- /**********************************/
- /* Port D mode selection is wrong */
- /**********************************/
-
- DPRINTK("Port D mode selection is wrong\n");
- i_ReturnValue
- =
- -8;
- }
- } else {
- /**********************************/
- /* Port C mode selection is wrong */
- /**********************************/
-
- DPRINTK("Port C mode selection is wrong\n");
- i_ReturnValue =
- -7;
- }
- } else {
- /**********************************/
- /* Port B mode selection is wrong */
- /**********************************/
-
- DPRINTK("Port B mode selection is wrong\n");
- i_ReturnValue = -6;
- }
- } else {
- /**********************************/
- /* Port A mode selection is wrong */
- /**********************************/
-
- DPRINTK("Port A mode selection is wrong\n");
- i_ReturnValue = -5;
- }
- } else {
- /*******************************************/
- /* Function not available for this version */
- /*******************************************/
-
- DPRINTK("Function not available for this version\n");
- i_ReturnValue = -4;
- }
- break;
-
- DPRINTK("\n");
- default:
- printk("Bad Config Type\n");
- } /* switch end */
- } else {
- /**********************************/
- /* The module is not a TTL module */
- /**********************************/
-
- DPRINTK("The module is not a TTL module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| INPUT FUNCTIONS |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_ReadTTLIOChannelValue |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_SelectedPort, |
-| unsigned char_ b_InputChannel, |
-| unsigned char *_ pb_ChannelStatus) |
-+----------------------------------------------------------------------------+
-| Task : Read the status from selected TTL digital input |
-| (b_InputChannel)
-+----------------------------------------------------------------------------+
-| Task : Read the status from digital input port |
-| (b_SelectedPort) from selected TTL module (b_ModulNbr) |
-+----------------------------------------------------------------------------+
-
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710|
-| unsigned char_ b_ModulNbr : Module number to |
-| configure (0 to 7) |
-| unsigned char_ b_SelectedPort, : Selection from TTL I/O |
-| port (0 to 2) |
-| 0 : Port A selection |
-| 1 : Port B selection |
-| 2 : Port C selection |
-| 3 : Port D selection |
-| unsigned char_ b_InputChannel : Selection from digital |
-| input ( 0 to 2)
-APCI1710_TTL_READCHANNEL
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_SelectedPort= CR_RANGE(insn->chanspec);
- b_InputChannel= CR_CHAN(insn->chanspec);
- b_ReadType = (unsigned char) data[0];
-
- APCI1710_TTL_READPORT|
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_SelectedPort= CR_RANGE(insn->chanspec);
- b_ReadType = (unsigned char) data[0];
-
-+----------------------------------------------------------------------------+
-| Output Parameters : data[0]
-
- unsigned char *_ pb_ChannelStatus : Digital input channel |
-| status |
-| 0 : Channle is not active|
-| 1 : Channle is active |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a TTL module |
-| -4: The selected TTL input port is wrong |
-| -5: The selected TTL digital input is wrong |
-| -6: TTL I/O not initialised |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnBitsReadTTLIO(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg;
- unsigned char b_ModulNbr;
- unsigned char b_SelectedPort;
- unsigned char b_InputChannel;
- unsigned char b_ReadType;
- unsigned char *pb_ChannelStatus;
- unsigned char *pb_PortValue;
-
- i_ReturnValue = insn->n;
- b_ReadType = (unsigned char) data[0];
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_SelectedPort = CR_RANGE(insn->chanspec);
- b_InputChannel = CR_CHAN(insn->chanspec);
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /**************************/
- /* Test if TTL I/O module */
- /**************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_TTL_IO) {
- switch (b_ReadType) {
-
- case APCI1710_TTL_READCHANNEL:
- pb_ChannelStatus = (unsigned char *) &data[0];
- /********************************/
- /* Test the TTL I/O port number */
- /********************************/
-
- if (((b_SelectedPort <= 2)
- && ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr] &
- 0xFFFF) ==
- 0x3130))
- || ((b_SelectedPort <= 3)
- && ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr] &
- 0xFFFF) >=
- 0x3230))) {
- /******************************************/
- /* Test the digital imnput channel number */
- /******************************************/
-
- if (((b_InputChannel <= 7)
- && (b_SelectedPort < 3))
- || ((b_InputChannel <= 1)
- && (b_SelectedPort ==
- 3))) {
- /******************************************/
- /* Test if the TTL I/O module initialised */
- /******************************************/
-
- if (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TTLIOInfo.b_TTLInit ==
- 1) {
- /***********************************/
- /* Test if TTL port used for input */
- /***********************************/
-
- if (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) == 0x3130) || (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3230) && (devpriv->s_ModuleInfo[b_ModulNbr].s_TTLIOInfo.b_PortConfiguration[b_SelectedPort] == 0))) {
- /**************************/
- /* Read all digital input */
- /**************************/
-
- dw_StatusReg =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- (64 * b_ModulNbr));
-
- *pb_ChannelStatus
- =
- (unsigned char) (
- (dw_StatusReg
- >>
- (8 * b_SelectedPort)) >> b_InputChannel) & 1;
- } else {
- /*******************************/
- /* Selected TTL I/O port error */
- /*******************************/
-
- DPRINTK("Selected TTL I/O port error\n");
- i_ReturnValue =
- -4;
- }
- } else {
- /***************************/
- /* TTL I/O not initialised */
- /***************************/
-
- DPRINTK("TTL I/O not initialised\n");
- i_ReturnValue = -6;
- }
- } else {
- /********************************/
- /* Selected digital input error */
- /********************************/
-
- DPRINTK("Selected digital input error\n");
- i_ReturnValue = -5;
- }
- } else {
- /*******************************/
- /* Selected TTL I/O port error */
- /*******************************/
-
- DPRINTK("Selected TTL I/O port error\n");
- i_ReturnValue = -4;
- }
- break;
-
- case APCI1710_TTL_READPORT:
- pb_PortValue = (unsigned char *) &data[0];
- /********************************/
- /* Test the TTL I/O port number */
- /********************************/
-
- if (((b_SelectedPort <= 2)
- && ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr] &
- 0xFFFF) ==
- 0x3130))
- || ((b_SelectedPort <= 3)
- && ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr] &
- 0xFFFF) >=
- 0x3230))) {
- /******************************************/
- /* Test if the TTL I/O module initialised */
- /******************************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.b_TTLInit == 1) {
- /***********************************/
- /* Test if TTL port used for input */
- /***********************************/
-
- if (((devpriv->s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr]
- &
- 0xFFFF)
- == 0x3130)
- || (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3230) && (devpriv->s_ModuleInfo[b_ModulNbr].s_TTLIOInfo.b_PortConfiguration[b_SelectedPort] == 0))) {
- /**************************/
- /* Read all digital input */
- /**************************/
-
- dw_StatusReg =
- inl(devpriv->
- s_BoardInfos.
- ui_Address +
- (64 * b_ModulNbr));
-
- *pb_PortValue =
- (unsigned char) (
- (dw_StatusReg >>
- (8 * b_SelectedPort)) & 0xFF);
- } else {
- /*******************************/
- /* Selected TTL I/O port error */
- /*******************************/
-
- DPRINTK("Selected TTL I/O port error\n");
- i_ReturnValue = -4;
- }
- } else {
- /***************************/
- /* TTL I/O not initialised */
- /***************************/
-
- DPRINTK("TTL I/O not initialised\n");
- i_ReturnValue = -5;
- }
- } else {
- /*******************************/
- /* Selected TTL I/O port error */
- /*******************************/
-
- DPRINTK("Selected TTL I/O port error\n");
- i_ReturnValue = -4;
- }
- break;
-
- default:
- printk("Bad ReadType\n");
-
- } /* End Switch */
- } else {
- /**********************************/
- /* The module is not a TTL module */
- /**********************************/
-
- DPRINTK("The module is not a TTL module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1710_InsnReadTTLIOAllPortValue(comedi_device
-*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Read the status from all digital input ports |
-| (port A, port B and port C) from selected TTL |
-| module (b_ModulNbr) |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710|
-| unsigned char_ b_ModulNbr : Module number to |
-| configure (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_PortValue : Digital TTL inputs port |
-| status |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a TTL module |
-| -4: TTL I/O not initialised |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg;
- unsigned char b_ModulNbr;
- unsigned int *pul_PortValue;
-
- b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
- i_ReturnValue = insn->n;
- pul_PortValue = (unsigned int *) &data[0];
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /**************************/
- /* Test if TTL I/O module */
- /**************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_TTL_IO) {
- /******************************************/
- /* Test if the TTL I/O module initialised */
- /******************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.b_TTLInit == 1) {
- /**************************/
- /* Read all digital input */
- /**************************/
-
- dw_StatusReg = inl(devpriv->s_BoardInfos.
- ui_Address + (64 * b_ModulNbr));
-
- /**********************/
- /* Test if TTL Rev1.0 */
- /**********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr] & 0xFFFF) ==
- 0x3130) {
- *pul_PortValue =
- dw_StatusReg & 0xFFFFFFUL;
- } else {
- /**************************************/
- /* Test if port A not used for output */
- /**************************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration[0] == 1) {
- *pul_PortValue =
- dw_StatusReg &
- 0x3FFFF00UL;
- }
-
- /**************************************/
- /* Test if port B not used for output */
- /**************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration[1] == 1) {
- *pul_PortValue =
- dw_StatusReg &
- 0x3FF00FFUL;
- }
-
- /**************************************/
- /* Test if port C not used for output */
- /**************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration[2] == 1) {
- *pul_PortValue =
- dw_StatusReg &
- 0x300FFFFUL;
- }
-
- /**************************************/
- /* Test if port D not used for output */
- /**************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration[3] == 1) {
- *pul_PortValue =
- dw_StatusReg &
- 0xFFFFFFUL;
- }
- }
- } else {
- /***************************/
- /* TTL I/O not initialised */
- /***************************/
- DPRINTK("TTL I/O not initialised\n");
- i_ReturnValue = -5;
- }
- } else {
- /**********************************/
- /* The module is not a TTL module */
- /**********************************/
- DPRINTK("The module is not a TTL module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| OUTPUT FUNCTIONS |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : _INT_ i_APCI1710_SetTTLIOChlOn |
-| (unsigned char_ b_BoardHandle, |
-| unsigned char_ b_ModulNbr, |
-| unsigned char_ b_OutputChannel)
-int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,struct comedi_subdevice *s,
- struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Sets or resets the output witch has been passed with the |
-| parameter b_Channel. Setting an output means setting |
-| an ouput high. |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 |
-| unsigned char_ b_ModulNbr : Selected module number (0 to 3)|
-| unsigned char_ b_OutputChannel : Selection from digital output |
-| channel (0 or 1) |
-| 0 : PD0 |
-| 1 : PD1 |
-| 2 to 9 : PA |
-| 10 to 17: PB |
-| 18 to 25: PC |
-
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_OutputChannel= CR_CHAN(insn->chanspec);
- ui_State = data[0]; /* ON or OFF */
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0: No error |
-| -1: The handle parameter of the board is wrong |
-| -2: The module parameter is wrong |
-| -3: The module is not a TTL I/O module |
-| -4: The selected digital output is wrong |
-| -5: TTL I/O not initialised see function |
-| " i_APCI1710_InitTTLIO"
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
- int i_ReturnValue = 0;
- unsigned int dw_StatusReg = 0;
- unsigned char b_ModulNbr;
- unsigned char b_OutputChannel;
- unsigned int ui_State;
-
- i_ReturnValue = insn->n;
- b_ModulNbr = CR_AREF(insn->chanspec);
- b_OutputChannel = CR_CHAN(insn->chanspec);
- ui_State = data[0]; /* ON or OFF */
-
- /**************************/
- /* Test the module number */
- /**************************/
-
- if (b_ModulNbr < 4) {
- /**************************/
- /* Test if TTL I/O module */
- /**************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModulNbr] &
- 0xFFFF0000UL) == APCI1710_TTL_IO) {
- /******************************************/
- /* Test if the TTL I/O module initialised */
- /******************************************/
-
- if (devpriv->s_ModuleInfo[b_ModulNbr].
- s_TTLIOInfo.b_TTLInit == 1) {
- /***********************************/
- /* Test the TTL I/O channel number */
- /***********************************/
-
- if (((b_OutputChannel <= 1)
- && ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr] &
- 0xFFFF) ==
- 0x3130))
- || ((b_OutputChannel <= 25)
- && ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration
- [b_ModulNbr] &
- 0xFFFF) >=
- 0x3230))) {
- /****************************************************/
- /* Test if the selected channel is a output channel */
- /****************************************************/
-
- if (((b_OutputChannel <= 1)
- && (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration
- [3] == 1))
- || ((b_OutputChannel >= 2)
- && (b_OutputChannel <=
- 9)
- && (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration
- [0] == 1))
- || ((b_OutputChannel >= 10)
- && (b_OutputChannel <=
- 17)
- && (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration
- [1] == 1))
- || ((b_OutputChannel >= 18)
- && (b_OutputChannel <=
- 25)
- && (devpriv->
- s_ModuleInfo
- [b_ModulNbr].
- s_TTLIOInfo.
- b_PortConfiguration
- [2] == 1))) {
- /************************/
- /* Test if PD0 selected */
- /************************/
-
- if (b_OutputChannel == 0) {
-
- outl(ui_State,
- devpriv->
- s_BoardInfos.
- ui_Address +
- (64 * b_ModulNbr));
- } else {
- /************************/
- /* Test if PD1 selected */
- /************************/
-
- if (b_OutputChannel ==
- 1) {
-
- outl(ui_State,
- devpriv->
- s_BoardInfos.
- ui_Address
- + 4 +
- (64 * b_ModulNbr));
- } else {
- b_OutputChannel
- =
- b_OutputChannel
- - 2;
-
- /********************/
- /* Read all channel */
- /********************/
-
- dw_StatusReg =
- inl
- (devpriv->
- s_BoardInfos.
- ui_Address
- +
- (64 * b_ModulNbr));
- if (ui_State) /* ON */
- {
- dw_StatusReg
- =
- (dw_StatusReg
- >>
- ((b_OutputChannel / 8) * 8)) & 0xFF;
- dw_StatusReg
- =
- dw_StatusReg
- |
- (1
- <<
- (b_OutputChannel
- %
- 8));
- } else /* Off */
- {
- dw_StatusReg
- =
- (dw_StatusReg
- >>
- ((b_OutputChannel / 8) * 8)) & 0xFF;
- dw_StatusReg
- =
- dw_StatusReg
- &
- (0xFF
- -
- (1 << (b_OutputChannel % 8)));
-
- }
-
- /****************************/
- /* Set the new output value */
- /****************************/
-
- outl(dw_StatusReg, devpriv->s_BoardInfos.ui_Address + 8 + ((b_OutputChannel / 8) * 4) + (64 * b_ModulNbr));
- }
- }
- } else {
- /************************************/
- /* The selected TTL output is wrong */
- /************************************/
-
- DPRINTK(" The selected TTL output is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /************************************/
- /* The selected TTL output is wrong */
- /************************************/
-
- DPRINTK("The selected TTL output is wrong\n");
- i_ReturnValue = -4;
- }
- } else {
- /***************************/
- /* TTL I/O not initialised */
- /***************************/
-
- DPRINTK("TTL I/O not initialised\n");
- i_ReturnValue = -5;
- }
- } else {
- /**************************************/
- /* The module is not a TTL I/O module */
- /**************************************/
-
- DPRINTK("The module is not a TTL I/O module\n");
- i_ReturnValue = -3;
- }
- } else {
- /***********************/
- /* Module number error */
- /***********************/
-
- DPRINTK("Module number error\n");
- i_ReturnValue = -2;
- }
-
- return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index f25e0085219..63dff7729ea 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -85,10 +85,9 @@ static int addi_auto_attach(struct comedi_device *dev,
dev->board_name = this_board->pc_DriverName;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h
index f1be5ade996..dfd1e666cc1 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h
@@ -113,150 +113,6 @@ struct addi_board {
struct comedi_insn *, unsigned int *);
};
-/* MODULE INFO STRUCTURE */
-
-union str_ModuleInfo {
- /* Incremental counter infos */
- struct {
- union {
- struct {
- unsigned char b_ModeRegister1;
- unsigned char b_ModeRegister2;
- unsigned char b_ModeRegister3;
- unsigned char b_ModeRegister4;
- } s_ByteModeRegister;
- unsigned int dw_ModeRegister1_2_3_4;
- } s_ModeRegister;
-
- struct {
- unsigned int b_IndexInit:1;
- unsigned int b_CounterInit:1;
- unsigned int b_ReferenceInit:1;
- unsigned int b_IndexInterruptOccur:1;
- unsigned int b_CompareLogicInit:1;
- unsigned int b_FrequencyMeasurementInit:1;
- unsigned int b_FrequencyMeasurementEnable:1;
- } s_InitFlag;
-
- } s_SiemensCounterInfo;
-
- /* SSI infos */
- struct {
- unsigned char b_SSIProfile;
- unsigned char b_PositionTurnLength;
- unsigned char b_TurnCptLength;
- unsigned char b_SSIInit;
- } s_SSICounterInfo;
-
- /* TTL I/O infos */
- struct {
- unsigned char b_TTLInit;
- unsigned char b_PortConfiguration[4];
- } s_TTLIOInfo;
-
- /* Digital I/O infos */
- struct {
- unsigned char b_DigitalInit;
- unsigned char b_ChannelAMode;
- unsigned char b_ChannelBMode;
- unsigned char b_OutputMemoryEnabled;
- unsigned int dw_OutputMemory;
- } s_DigitalIOInfo;
-
- /*********************/
- /* 82X54 timer infos */
- /*********************/
-
- struct {
- struct {
- unsigned char b_82X54Init;
- unsigned char b_InputClockSelection;
- unsigned char b_InputClockLevel;
- unsigned char b_OutputLevel;
- unsigned char b_HardwareGateLevel;
- unsigned int dw_ConfigurationWord;
- } s_82X54TimerInfo[3];
- unsigned char b_InterruptMask;
- } s_82X54ModuleInfo;
-
- /*********************/
- /* Chronometer infos */
- /*********************/
-
- struct {
- unsigned char b_ChronoInit;
- unsigned char b_InterruptMask;
- unsigned char b_PCIInputClock;
- unsigned char b_TimingUnit;
- unsigned char b_CycleMode;
- double d_TimingInterval;
- unsigned int dw_ConfigReg;
- } s_ChronoModuleInfo;
-
- /***********************/
- /* Pulse encoder infos */
- /***********************/
-
- struct {
- struct {
- unsigned char b_PulseEncoderInit;
- } s_PulseEncoderInfo[4];
- unsigned int dw_SetRegister;
- unsigned int dw_ControlRegister;
- unsigned int dw_StatusRegister;
- } s_PulseEncoderModuleInfo;
-
- /* Tor conter infos */
- struct {
- struct {
- unsigned char b_TorCounterInit;
- unsigned char b_TimingUnit;
- unsigned char b_InterruptEnable;
- double d_TimingInterval;
- unsigned int ul_RealTimingInterval;
- } s_TorCounterInfo[2];
- unsigned char b_PCIInputClock;
- } s_TorCounterModuleInfo;
-
- /* PWM infos */
- struct {
- struct {
- unsigned char b_PWMInit;
- unsigned char b_TimingUnit;
- unsigned char b_InterruptEnable;
- double d_LowTiming;
- double d_HighTiming;
- unsigned int ul_RealLowTiming;
- unsigned int ul_RealHighTiming;
- } s_PWMInfo[2];
- unsigned char b_ClockSelection;
- } s_PWMModuleInfo;
-
- /* ETM infos */
- struct {
- struct {
- unsigned char b_ETMEnable;
- unsigned char b_ETMInterrupt;
- } s_ETMInfo[2];
- unsigned char b_ETMInit;
- unsigned char b_TimingUnit;
- unsigned char b_ClockSelection;
- double d_TimingInterval;
- unsigned int ul_Timing;
- } s_ETMModuleInfo;
-
- /* CDA infos */
- struct {
- unsigned char b_CDAEnable;
- unsigned char b_CDAInterrupt;
- unsigned char b_CDAInit;
- unsigned char b_FctSelection;
- unsigned char b_CDAReadFIFOOverflow;
- } s_CDAModuleInfo;
-
-};
-
-/* Private structure for the addi_apci3120 driver */
struct addi_private {
int iobase;
int i_IobaseAmcc; /* base+size for AMCC chip */
@@ -299,31 +155,6 @@ struct addi_private {
/* Pointer to the current process */
struct task_struct *tsk_Current;
- /* Hardware board infos for 1710 */
- struct {
- unsigned int ui_Address; /* Board address */
- unsigned int ui_FlashAddress;
- unsigned char b_InterruptNbr; /* Board interrupt number */
- unsigned char b_SlotNumber; /* PCI slot number */
- unsigned char b_BoardVersion;
- unsigned int dw_MolduleConfiguration[4]; /* Module config */
- } s_BoardInfos;
-
- /* Interrupt infos */
- struct {
- unsigned int ul_InterruptOccur; /* 0 : No interrupt occur */
- /* > 0 : Interrupt occur */
- unsigned int ui_Read; /* Read FIFO */
- unsigned int ui_Write; /* Write FIFO */
- struct {
- unsigned char b_OldModuleMask;
- unsigned int ul_OldInterruptMask; /* Interrupt mask */
- unsigned int ul_OldCounterLatchValue; /* Interrupt counter value */
- } s_FIFOInterruptParameters[APCI1710_SAVE_INTERRUPT];
- } s_InterruptParameters;
-
- union str_ModuleInfo s_ModuleInfo[4];
-
/* Parameters read from EEPROM overriding static board info */
struct {
int i_NbrAiChannel; /* num of A/D chans */
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
index dc031c494a2..aafc172f3a9 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
@@ -22,6 +22,8 @@
* for more details.
*/
+#include <linux/delay.h>
+
#define NVRAM_USER_DATA_START 0x100
#define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
deleted file mode 100644
index b1a7ec1035e..00000000000
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
+++ /dev/null
@@ -1,1314 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-------------------------------+---------------------------------------+
- | Project : APCI-1710 | Compiler : GCC |
- | Module name : hwdrv_apci1710.c| Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-------------------------------+---------------------------------------+
- | Description : Hardware Layer Access For APCI-1710 |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +----------+-----------+------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | | | |
- | | | |
- | | | |
- +----------+-----------+------------------------------------------------+
-*/
-
-#define COMEDI_SUBD_TTLIO 11 /* Digital Input Output But TTL */
-#define COMEDI_SUBD_PWM 12 /* Pulse width Measurement */
-#define COMEDI_SUBD_SSI 13 /* Synchronous serial interface */
-#define COMEDI_SUBD_TOR 14 /* Tor counter */
-#define COMEDI_SUBD_CHRONO 15 /* Chrono meter */
-#define COMEDI_SUBD_PULSEENCODER 16 /* Pulse Encoder INP CPT */
-#define COMEDI_SUBD_INCREMENTALCOUNTER 17 /* Incremental Counter */
-
-#define APCI1710_BOARD_NAME "apci1710"
-#define APCI1710_BOARD_DEVICE_ID 0x818F
-#define APCI1710_ADDRESS_RANGE 256
-#define APCI1710_CONFIG_ADDRESS_RANGE 8
-#define APCI1710_INCREMENTAL_COUNTER 0x53430000UL
-#define APCI1710_SSI_COUNTER 0x53490000UL
-#define APCI1710_TTL_IO 0x544C0000UL
-#define APCI1710_DIGITAL_IO 0x44490000UL
-#define APCI1710_82X54_TIMER 0x49430000UL
-#define APCI1710_CHRONOMETER 0x43480000UL
-#define APCI1710_PULSE_ENCODER 0x495A0000UL
-#define APCI1710_TOR_COUNTER 0x544F0000UL
-#define APCI1710_PWM 0x50570000UL
-#define APCI1710_ETM 0x45540000UL
-#define APCI1710_CDA 0x43440000UL
-#define APCI1710_DISABLE 0
-#define APCI1710_ENABLE 1
-#define APCI1710_SYNCHRONOUS_MODE 1
-#define APCI1710_ASYNCHRONOUS_MODE 0
-
-#include "APCI1710_Inp_cpt.c"
-
-#include "APCI1710_Ssi.c"
-#include "APCI1710_Tor.c"
-#include "APCI1710_Ttl.c"
-#include "APCI1710_Dig_io.c"
-#include "APCI1710_82x54.c"
-#include "APCI1710_Chrono.c"
-#include "APCI1710_Pwm.c"
-#include "APCI1710_INCCPT.c"
-
-static const struct comedi_lrange range_apci1710_ttl = {
- 4, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2),
- BIP_RANGE(1)
- }
-};
-
-static const struct comedi_lrange range_apci1710_ssi = {
- 4, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2),
- BIP_RANGE(1)
- }
-};
-
-static const struct comedi_lrange range_apci1710_inccpt = {
- 4, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2),
- BIP_RANGE(1)
- }
-};
-
-static void i_ADDI_AttachPCI1710(struct comedi_device *dev)
-{
- struct comedi_subdevice *s;
- int ret = 0;
- int n_subdevices = 9;
-
- ret = comedi_alloc_subdevices(dev, n_subdevices);
- if (ret)
- return;
-
- /* Allocate and Initialise Timer Subdevice Structures */
- s = &dev->subdevices[0];
-
- s->type = COMEDI_SUBD_TIMER;
- s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 3;
- s->maxdata = 0;
- s->len_chanlist = 3;
- s->range_table = &range_digital;
- s->insn_write = i_APCI1710_InsnWriteEnableDisableTimer;
- s->insn_read = i_APCI1710_InsnReadAllTimerValue;
- s->insn_config = i_APCI1710_InsnConfigInitTimer;
- s->insn_bits = i_APCI1710_InsnBitsTimer;
-
- /* Allocate and Initialise DIO Subdevice Structures */
- s = &dev->subdevices[1];
-
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags =
- SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 7;
- s->maxdata = 1;
- s->len_chanlist = 7;
- s->range_table = &range_digital;
- s->insn_config = i_APCI1710_InsnConfigDigitalIO;
- s->insn_read = i_APCI1710_InsnReadDigitalIOChlValue;
- s->insn_bits = i_APCI1710_InsnBitsDigitalIOPortOnOff;
- s->insn_write = i_APCI1710_InsnWriteDigitalIOChlOnOff;
-
- /* Allocate and Initialise Chrono Subdevice Structures */
- s = &dev->subdevices[2];
-
- s->type = COMEDI_SUBD_CHRONO;
- s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 4;
- s->maxdata = 0;
- s->len_chanlist = 4;
- s->range_table = &range_digital;
- s->insn_write = i_APCI1710_InsnWriteEnableDisableChrono;
- s->insn_read = i_APCI1710_InsnReadChrono;
- s->insn_config = i_APCI1710_InsnConfigInitChrono;
- s->insn_bits = i_APCI1710_InsnBitsChronoDigitalIO;
-
- /* Allocate and Initialise PWM Subdevice Structures */
- s = &dev->subdevices[3];
- s->type = COMEDI_SUBD_PWM;
- s->subdev_flags =
- SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 3;
- s->maxdata = 1;
- s->len_chanlist = 3;
- s->range_table = &range_digital;
- s->io_bits = 0; /* all bits input */
- s->insn_config = i_APCI1710_InsnConfigPWM;
- s->insn_read = i_APCI1710_InsnReadGetPWMStatus;
- s->insn_write = i_APCI1710_InsnWritePWM;
- s->insn_bits = i_APCI1710_InsnBitsReadPWMInterrupt;
-
- /* Allocate and Initialise TTLIO Subdevice Structures */
- s = &dev->subdevices[4];
- s->type = COMEDI_SUBD_TTLIO;
- s->subdev_flags =
- SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 8;
- s->maxdata = 1;
- s->len_chanlist = 8;
- s->range_table = &range_apci1710_ttl; /* to pass arguments in range */
- s->insn_config = i_APCI1710_InsnConfigInitTTLIO;
- s->insn_bits = i_APCI1710_InsnBitsReadTTLIO;
- s->insn_write = i_APCI1710_InsnWriteSetTTLIOChlOnOff;
- s->insn_read = i_APCI1710_InsnReadTTLIOAllPortValue;
-
- /* Allocate and Initialise TOR Subdevice Structures */
- s = &dev->subdevices[5];
- s->type = COMEDI_SUBD_TOR;
- s->subdev_flags =
- SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 8;
- s->maxdata = 1;
- s->len_chanlist = 8;
- s->range_table = &range_digital;
- s->io_bits = 0; /* all bits input */
- s->insn_config = i_APCI1710_InsnConfigInitTorCounter;
- s->insn_read = i_APCI1710_InsnReadGetTorCounterInitialisation;
- s->insn_write = i_APCI1710_InsnWriteEnableDisableTorCounter;
- s->insn_bits = i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue;
-
- /* Allocate and Initialise SSI Subdevice Structures */
- s = &dev->subdevices[6];
- s->type = COMEDI_SUBD_SSI;
- s->subdev_flags =
- SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 4;
- s->maxdata = 1;
- s->len_chanlist = 4;
- s->range_table = &range_apci1710_ssi;
- s->insn_config = i_APCI1710_InsnConfigInitSSI;
- s->insn_read = i_APCI1710_InsnReadSSIValue;
- s->insn_bits = i_APCI1710_InsnBitsSSIDigitalIO;
-
- /* Allocate and Initialise PULSEENCODER Subdevice Structures */
- s = &dev->subdevices[7];
- s->type = COMEDI_SUBD_PULSEENCODER;
- s->subdev_flags =
- SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 4;
- s->maxdata = 1;
- s->len_chanlist = 4;
- s->range_table = &range_digital;
- s->insn_config = i_APCI1710_InsnConfigInitPulseEncoder;
- s->insn_write = i_APCI1710_InsnWriteEnableDisablePulseEncoder;
- s->insn_bits = i_APCI1710_InsnBitsReadWritePulseEncoder;
- s->insn_read = i_APCI1710_InsnReadInterruptPulseEncoder;
-
- /* Allocate and Initialise INCREMENTALCOUNTER Subdevice Structures */
- s = &dev->subdevices[8];
- s->type = COMEDI_SUBD_INCREMENTALCOUNTER;
- s->subdev_flags =
- SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 500;
- s->maxdata = 1;
- s->len_chanlist = 500;
- s->range_table = &range_apci1710_inccpt;
- s->insn_config = i_APCI1710_InsnConfigINCCPT;
- s->insn_write = i_APCI1710_InsnWriteINCCPT;
- s->insn_read = i_APCI1710_InsnReadINCCPT;
- s->insn_bits = i_APCI1710_InsnBitsINCCPT;
-}
-
-static int i_APCI1710_Reset(struct comedi_device *dev)
-{
- struct addi_private *devpriv = dev->private;
- int ret;
- unsigned int dw_Dummy;
-
- /*********************************/
- /* Read all module configuration */
- /*********************************/
- ret = inl(devpriv->s_BoardInfos.ui_Address + 60);
- devpriv->s_BoardInfos.dw_MolduleConfiguration[0] = ret;
-
- ret = inl(devpriv->s_BoardInfos.ui_Address + 124);
- devpriv->s_BoardInfos.dw_MolduleConfiguration[1] = ret;
-
- ret = inl(devpriv->s_BoardInfos.ui_Address + 188);
- devpriv->s_BoardInfos.dw_MolduleConfiguration[2] = ret;
-
- ret = inl(devpriv->s_BoardInfos.ui_Address + 252);
- devpriv->s_BoardInfos.dw_MolduleConfiguration[3] = ret;
-
- /* outl(0x80808082,devpriv->s_BoardInfos.ui_Address+0x60); */
- outl(0x83838383, devpriv->s_BoardInfos.ui_Address + 0x60);
-
- devpriv->s_BoardInfos.b_BoardVersion = 1;
-
- /* Enable the interrupt for the controller */
- dw_Dummy = inl(devpriv->s_BoardInfos.ui_Address + 0x38);
- outl(dw_Dummy | 0x2000, devpriv->s_BoardInfos.ui_Address + 0x38);
-
- return 0;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function's Name : __void__ v_APCI1710_InterruptFunction |
-| (unsigned char b_Interrupt, __CPPARGS) |
-+----------------------------------------------------------------------------+
-| Task : APCI-1710 interrupt function |
-+----------------------------------------------------------------------------+
-| Input Parameters : unsigned char b_Interrupt : Interrupt number |
-+----------------------------------------------------------------------------+
-| Output Parameters : - |
-+----------------------------------------------------------------------------+
-| Return Value : 0 : OK |
-| -1 : Error |
-+----------------------------------------------------------------------------+
-*/
-
-static void v_APCI1710_Interrupt(int irq, void *d)
-{
- struct comedi_device *dev = d;
- struct addi_private *devpriv = dev->private;
- unsigned char b_ModuleCpt = 0;
- unsigned char b_InterruptFlag = 0;
- unsigned char b_PWMCpt = 0;
- unsigned char b_TorCounterCpt = 0;
- unsigned char b_PulseIncoderCpt = 0;
- unsigned int ui_16BitValue;
- unsigned int ul_InterruptLatchReg = 0;
- unsigned int ul_LatchRegisterValue = 0;
- unsigned int ul_82X54InterruptStatus;
- unsigned int ul_StatusRegister;
-
- union str_ModuleInfo *ps_ModuleInfo;
-
- printk("APCI1710 Interrupt\n");
- for (b_ModuleCpt = 0; b_ModuleCpt < 4; b_ModuleCpt++, ps_ModuleInfo++) {
-
- /**************************/
- /* 1199/0225 to 0100/0226 */
- /**************************/
- ps_ModuleInfo = &devpriv->s_ModuleInfo[b_ModuleCpt];
-
- /***********************/
- /* Test if 82X54 timer */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModuleCpt] &
- 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
-
- /* printk("TIMER Interrupt Occurred\n"); */
- ul_82X54InterruptStatus = inl(devpriv->s_BoardInfos.
- ui_Address + 12 + (64 * b_ModuleCpt));
-
- /***************************/
- /* Test if interrupt occur */
- /***************************/
-
- if ((ul_82X54InterruptStatus & ps_ModuleInfo->
- s_82X54ModuleInfo.
- b_InterruptMask) != 0) {
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.
- ui_Write].
- ul_OldInterruptMask =
- (ul_82X54InterruptStatus &
- ps_ModuleInfo->s_82X54ModuleInfo.
- b_InterruptMask) << 4;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.
- ui_Write].
- b_OldModuleMask = 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.
- ui_Write].ul_OldCounterLatchValue = 0;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write + 1) % APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO, devpriv->tsk_Current, 0);
-
- } /* if ((ul_82X54InterruptStatus & 0x7) != 0) */
- } /* 82X54 timer */
-
- /***************************/
- /* Test if increm. counter */
- /***************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModuleCpt] &
- 0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) {
-
- ul_InterruptLatchReg = inl(devpriv->s_BoardInfos.
- ui_Address + (64 * b_ModuleCpt));
-
- /*********************/
- /* Test if interrupt */
- /*********************/
-
- if ((ul_InterruptLatchReg & 0x22) && (ps_ModuleInfo->
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 & 0x80)) {
- /************************************/
- /* Test if strobe latch I interrupt */
- /************************************/
-
- if (ul_InterruptLatchReg & 2) {
- ul_LatchRegisterValue =
- inl(devpriv->s_BoardInfos.
- ui_Address + 4 +
- (64 * b_ModuleCpt));
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].ul_OldInterruptMask =
- 1UL;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].b_OldModuleMask =
- 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].
- ul_OldCounterLatchValue =
- ul_LatchRegisterValue;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* 0899/0224 to 1199/0225 */
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write +
- 1) % APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO, devpriv->tsk_Current,
- 0);
-
- }
-
- /*************************************/
- /* Test if strobe latch II interrupt */
- /*************************************/
-
- if (ul_InterruptLatchReg & 0x20) {
-
- ul_LatchRegisterValue =
- inl(devpriv->s_BoardInfos.
- ui_Address + 8 +
- (64 * b_ModuleCpt));
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].ul_OldInterruptMask =
- 2UL;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].b_OldModuleMask =
- 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].
- ul_OldCounterLatchValue =
- ul_LatchRegisterValue;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* 0899/0224 to 1199/0225 */
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write +
- 1) % APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO, devpriv->tsk_Current,
- 0);
-
- }
- }
-
- ul_InterruptLatchReg = inl(devpriv->s_BoardInfos.
- ui_Address + 24 + (64 * b_ModuleCpt));
-
- /***************************/
- /* Test if index interrupt */
- /***************************/
-
- if (ul_InterruptLatchReg & 0x8) {
- ps_ModuleInfo->
- s_SiemensCounterInfo.
- s_InitFlag.b_IndexInterruptOccur = 1;
-
- if (ps_ModuleInfo->
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister2 &
- APCI1710_INDEX_AUTO_MODE) {
-
- outl(ps_ModuleInfo->
- s_SiemensCounterInfo.
- s_ModeRegister.
- dw_ModeRegister1_2_3_4,
- devpriv->s_BoardInfos.
- ui_Address + 20 +
- (64 * b_ModuleCpt));
- }
-
- /*****************************/
- /* Test if interrupt enabled */
- /*****************************/
-
- if ((ps_ModuleInfo->
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 &
- APCI1710_ENABLE_INDEX_INT) ==
- APCI1710_ENABLE_INDEX_INT) {
- devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].ul_OldInterruptMask =
- 4UL;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].b_OldModuleMask =
- 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].
- ul_OldCounterLatchValue =
- ul_LatchRegisterValue;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* 0899/0224 to 1199/0225 */
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write +
- 1) % APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO, devpriv->tsk_Current,
- 0);
-
- }
- }
-
- /*****************************/
- /* Test if compare interrupt */
- /*****************************/
-
- if (ul_InterruptLatchReg & 0x10) {
- /*****************************/
- /* Test if interrupt enabled */
- /*****************************/
-
- if ((ps_ModuleInfo->
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister3 &
- APCI1710_ENABLE_COMPARE_INT) ==
- APCI1710_ENABLE_COMPARE_INT) {
- devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].ul_OldInterruptMask =
- 8UL;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].b_OldModuleMask =
- 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].
- ul_OldCounterLatchValue =
- ul_LatchRegisterValue;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* 0899/0224 to 1199/0225 */
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write +
- 1) % APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO, devpriv->tsk_Current,
- 0);
-
- }
- }
-
- /*******************************************/
- /* Test if frequency measurement interrupt */
- /*******************************************/
-
- if (ul_InterruptLatchReg & 0x20) {
- /*******************/
- /* Read the status */
- /*******************/
-
- ul_StatusRegister = inl(devpriv->s_BoardInfos.
- ui_Address + 32 + (64 * b_ModuleCpt));
-
- /******************/
- /* Read the value */
- /******************/
-
- ul_LatchRegisterValue =
- inl(devpriv->s_BoardInfos.ui_Address +
- 28 + (64 * b_ModuleCpt));
-
- switch ((ul_StatusRegister >> 1) & 3) {
- case 0:
- /*************************/
- /* Test the counter mode */
- /*************************/
-
- if ((devpriv->s_ModuleInfo[b_ModuleCpt].
- s_SiemensCounterInfo.
- s_ModeRegister.
- s_ByteModeRegister.
- b_ModeRegister1 &
- APCI1710_16BIT_COUNTER)
- == APCI1710_16BIT_COUNTER) {
- /****************************************/
- /* Test if 16-bit counter 1 pulse occur */
- /****************************************/
-
- if ((ul_LatchRegisterValue &
- 0xFFFFU) != 0) {
- ui_16BitValue =
- (unsigned int)
- ul_LatchRegisterValue
- & 0xFFFFU;
- ul_LatchRegisterValue =
- (ul_LatchRegisterValue
- & 0xFFFF0000UL)
- | (0xFFFFU -
- ui_16BitValue);
- }
-
- /****************************************/
- /* Test if 16-bit counter 2 pulse occur */
- /****************************************/
-
- if ((ul_LatchRegisterValue &
- 0xFFFF0000UL) !=
- 0) {
- ui_16BitValue =
- (unsigned int) (
- (ul_LatchRegisterValue
- >> 16) &
- 0xFFFFU);
- ul_LatchRegisterValue =
- (ul_LatchRegisterValue
- & 0xFFFFUL) |
- ((0xFFFFU -
- ui_16BitValue)
- << 16);
- }
- } else {
- if (ul_LatchRegisterValue != 0) {
- ul_LatchRegisterValue =
- 0xFFFFFFFFUL -
- ul_LatchRegisterValue;
- }
- }
- break;
-
- case 1:
- /****************************************/
- /* Test if 16-bit counter 2 pulse occur */
- /****************************************/
-
- if ((ul_LatchRegisterValue &
- 0xFFFF0000UL) != 0) {
- ui_16BitValue =
- (unsigned int) (
- (ul_LatchRegisterValue
- >> 16) &
- 0xFFFFU);
- ul_LatchRegisterValue =
- (ul_LatchRegisterValue &
- 0xFFFFUL) | ((0xFFFFU -
- ui_16BitValue)
- << 16);
- }
- break;
-
- case 2:
- /****************************************/
- /* Test if 16-bit counter 1 pulse occur */
- /****************************************/
-
- if ((ul_LatchRegisterValue & 0xFFFFU) !=
- 0) {
- ui_16BitValue =
- (unsigned int)
- ul_LatchRegisterValue &
- 0xFFFFU;
- ul_LatchRegisterValue =
- (ul_LatchRegisterValue &
- 0xFFFF0000UL) | (0xFFFFU
- - ui_16BitValue);
- }
- break;
- }
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.
- ui_Write].
- ul_OldInterruptMask = 0x10000UL;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.
- ui_Write].
- b_OldModuleMask = 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters[devpriv->
- s_InterruptParameters.
- ui_Write].
- ul_OldCounterLatchValue =
- ul_LatchRegisterValue;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* 0899/0224 to 1199/0225 */
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write + 1) % APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO, devpriv->tsk_Current, 0);
-
- }
- } /* Incremental counter */
-
- /***************/
- /* Test if CDA */
- /***************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModuleCpt] &
- 0xFFFF0000UL) == APCI1710_CDA) {
- /******************************************/
- /* Test if CDA enable and functionality 0 */
- /******************************************/
-
- if ((devpriv->s_ModuleInfo[b_ModuleCpt].
- s_CDAModuleInfo.
- b_CDAEnable == APCI1710_ENABLE)
- && (devpriv->s_ModuleInfo[b_ModuleCpt].
- s_CDAModuleInfo.b_FctSelection == 0)) {
- /****************************/
- /* Get the interrupt status */
- /****************************/
-
- ul_StatusRegister = inl(devpriv->s_BoardInfos.
- ui_Address + 16 + (64 * b_ModuleCpt));
- /***************************/
- /* Test if interrupt occur */
- /***************************/
-
- if (ul_StatusRegister & 1) {
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].ul_OldInterruptMask =
- 0x80000UL;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].b_OldModuleMask =
- 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].
- ul_OldCounterLatchValue = 0;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write +
- 1) % APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
-
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO, devpriv->tsk_Current,
- 0);
-
- } /* if (ul_StatusRegister & 1) */
-
- }
- } /* CDA */
-
- /***********************/
- /* Test if PWM counter */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModuleCpt] &
- 0xFFFF0000UL) == APCI1710_PWM) {
- for (b_PWMCpt = 0; b_PWMCpt < 2; b_PWMCpt++) {
- /*************************************/
- /* Test if PWM interrupt initialised */
- /*************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModuleCpt].
- s_PWMModuleInfo.
- s_PWMInfo[b_PWMCpt].
- b_InterruptEnable == APCI1710_ENABLE) {
- /*****************************/
- /* Read the interrupt status */
- /*****************************/
-
- ul_StatusRegister =
- inl(devpriv->s_BoardInfos.
- ui_Address + 16 +
- (20 * b_PWMCpt) +
- (64 * b_ModuleCpt));
-
- /***************************/
- /* Test if interrupt occur */
- /***************************/
-
- if (ul_StatusRegister & 0x1) {
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->
- s_InterruptParameters.
- ui_Write].
- ul_OldInterruptMask =
- 0x4000UL << b_PWMCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->
- s_InterruptParameters.
- ui_Write].
- b_OldModuleMask =
- 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write +
- 1) %
- APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO,
- devpriv->tsk_Current,
- 0);
-
- } /* if (ul_StatusRegister & 0x1) */
- } /* if (APCI1710_ENABLE) */
- } /* for (b_PWMCpt == 0; b_PWMCpt < 0; b_PWMCpt ++) */
- } /* PWM counter */
-
- /***********************/
- /* Test if tor counter */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModuleCpt] &
- 0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
- for (b_TorCounterCpt = 0; b_TorCounterCpt < 2;
- b_TorCounterCpt++) {
- /*************************************/
- /* Test if tor interrupt initialised */
- /*************************************/
-
- if (devpriv->
- s_ModuleInfo[b_ModuleCpt].
- s_TorCounterModuleInfo.
- s_TorCounterInfo[b_TorCounterCpt].
- b_InterruptEnable == APCI1710_ENABLE) {
- /*****************************/
- /* Read the interrupt status */
- /*****************************/
-
- ul_StatusRegister =
- inl(devpriv->s_BoardInfos.
- ui_Address + 12 +
- (16 * b_TorCounterCpt) +
- (64 * b_ModuleCpt));
-
- /***************************/
- /* Test if interrupt occur */
- /***************************/
-
- if (ul_StatusRegister & 0x1) {
- /******************************/
- /* Read the tor counter value */
- /******************************/
-
- ul_LatchRegisterValue =
- inl(devpriv->
- s_BoardInfos.
- ui_Address + 0 +
- (16 * b_TorCounterCpt) +
- (64 * b_ModuleCpt));
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->
- s_InterruptParameters.
- ui_Write].
- ul_OldInterruptMask =
- 0x1000UL <<
- b_TorCounterCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->
- s_InterruptParameters.
- ui_Write].
- b_OldModuleMask =
- 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->
- s_InterruptParameters.
- ui_Write].
- ul_OldCounterLatchValue
- = ul_LatchRegisterValue;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write +
- 1) %
- APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
-
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO,
- devpriv->tsk_Current,
- 0);
- } /* if (ul_StatusRegister & 0x1) */
- } /* if (APCI1710_ENABLE) */
- } /* for (b_TorCounterCpt == 0; b_TorCounterCpt < 0; b_TorCounterCpt ++) */
- } /* Tor counter */
-
- /***********************/
- /* Test if chronometer */
- /***********************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModuleCpt] &
- 0xFFFF0000UL) == APCI1710_CHRONOMETER) {
-
- /* printk("APCI1710 Chrono Interrupt\n"); */
- /*****************************/
- /* Read the interrupt status */
- /*****************************/
-
- ul_InterruptLatchReg = inl(devpriv->s_BoardInfos.
- ui_Address + 12 + (64 * b_ModuleCpt));
-
- /***************************/
- /* Test if interrupt occur */
- /***************************/
-
- if ((ul_InterruptLatchReg & 0x8) == 0x8) {
- /****************************/
- /* Clear the interrupt flag */
- /****************************/
-
- outl(0, devpriv->s_BoardInfos.
- ui_Address + 32 + (64 * b_ModuleCpt));
-
- /***************************/
- /* Test if continuous mode */
- /***************************/
-
- if (ps_ModuleInfo->
- s_ChronoModuleInfo.
- b_CycleMode == APCI1710_ENABLE) {
- /********************/
- /* Clear the status */
- /********************/
-
- outl(0, devpriv->s_BoardInfos.
- ui_Address + 36 +
- (64 * b_ModuleCpt));
- }
-
- /*************************/
- /* Read the timing value */
- /*************************/
-
- ul_LatchRegisterValue =
- inl(devpriv->s_BoardInfos.ui_Address +
- 4 + (64 * b_ModuleCpt));
-
- /*****************************/
- /* Test if interrupt enabled */
- /*****************************/
-
- if (ps_ModuleInfo->
- s_ChronoModuleInfo.b_InterruptMask) {
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].ul_OldInterruptMask =
- 0x80;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].b_OldModuleMask =
- 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->s_InterruptParameters.
- ui_Write].
- ul_OldCounterLatchValue =
- ul_LatchRegisterValue;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write +
- 1) % APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO, devpriv->tsk_Current,
- 0);
-
- }
- }
- } /* Chronometer */
-
- /*************************/
- /* Test if pulse encoder */
- /*************************/
-
- if ((devpriv->s_BoardInfos.
- dw_MolduleConfiguration[b_ModuleCpt] &
- 0xFFFF0000UL) == APCI1710_PULSE_ENCODER) {
- /****************************/
- /* Read the status register */
- /****************************/
-
- ul_StatusRegister = inl(devpriv->s_BoardInfos.
- ui_Address + 20 + (64 * b_ModuleCpt));
-
- if (ul_StatusRegister & 0xF) {
- for (b_PulseIncoderCpt = 0;
- b_PulseIncoderCpt < 4;
- b_PulseIncoderCpt++) {
- /*************************************/
- /* Test if pulse encoder initialised */
- /*************************************/
-
- if ((ps_ModuleInfo->
- s_PulseEncoderModuleInfo.
- s_PulseEncoderInfo
- [b_PulseIncoderCpt].
- b_PulseEncoderInit == 1)
- && (((ps_ModuleInfo->s_PulseEncoderModuleInfo.dw_SetRegister >> b_PulseIncoderCpt) & 1) == 1) && (((ul_StatusRegister >> (b_PulseIncoderCpt)) & 1) == 1)) {
- devpriv->s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->
- s_InterruptParameters.
- ui_Write].
- ul_OldInterruptMask =
- 0x100UL <<
- b_PulseIncoderCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->
- s_InterruptParameters.
- ui_Write].
- b_OldModuleMask =
- 1 << b_ModuleCpt;
-
- devpriv->
- s_InterruptParameters.
- s_FIFOInterruptParameters
- [devpriv->
- s_InterruptParameters.
- ui_Write].
- ul_OldCounterLatchValue
- = ul_LatchRegisterValue;
-
- devpriv->
- s_InterruptParameters.
- ul_InterruptOccur++;
-
- /****************************/
- /* 0899/0224 to 1199/0225 */
- /****************************/
- /* Increment the write FIFO */
- /****************************/
-
- devpriv->
- s_InterruptParameters.
- ui_Write = (devpriv->
- s_InterruptParameters.
- ui_Write +
- 1) %
- APCI1710_SAVE_INTERRUPT;
-
- b_InterruptFlag = 1;
-
- /**********************/
- /* Call user function */
- /**********************/
- /* Send a signal to from kernel to user space */
- send_sig(SIGIO,
- devpriv->tsk_Current,
- 0);
-
- }
- }
- }
- } /* pulse encoder */
-
- }
- return;
-
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index a89e505c8a3..1449b92403e 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -40,6 +40,8 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
+----------+-----------+------------------------------------------------+
*/
+#include <linux/delay.h>
+
/*
* ADDON RELATED ADDITIONS
*/
diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c
index 43c2c10a7c3..8d229b2f097 100644
--- a/drivers/staging/comedi/drivers/addi_apci_035.c
+++ b/drivers/staging/comedi/drivers/addi_apci_035.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c
index 8a93542faed..34ab0679e99 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1032.c
@@ -22,6 +22,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -289,10 +290,9 @@ static int apci1032_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c
index b52cfe01e6c..ae9ded63dce 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c
index b626738bb73..08674c18cf4 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1516.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1516.c
@@ -22,6 +22,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -136,10 +137,9 @@ static int apci1516_auto_attach(struct comedi_device *dev,
dev->board_ptr = this_board;
dev->board_name = this_board->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c
index 22bace62210..c5717d63e16 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1564.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1564.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c
index 1f7bed9a3f7..96523744b8d 100644
--- a/drivers/staging/comedi/drivers/addi_apci_16xx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c
@@ -22,6 +22,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -59,36 +60,22 @@ static int apci16xx_insn_config(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec);
- unsigned int bits;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
+ int ret;
- /*
- * Each 8-bit "port" is configurable as either input or
- * output. Changing the configuration of any channel in
- * a port changes the entire port.
- */
- if (chan_mask & 0x000000ff)
- bits = 0x000000ff;
- else if (chan_mask & 0x0000ff00)
- bits = 0x0000ff00;
- else if (chan_mask & 0x00ff0000)
- bits = 0x00ff0000;
+ if (chan < 8)
+ mask = 0x000000ff;
+ else if (chan < 16)
+ mask = 0x0000ff00;
+ else if (chan < 24)
+ mask = 0x00ff0000;
else
- bits = 0xff000000;
-
- switch (data[0]) {
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~bits;
- break;
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= bits;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & bits) ? COMEDI_INPUT : COMEDI_OUTPUT;
- return insn->n;
- default:
- return -EINVAL;
- }
+ mask = 0xff000000;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(s->index));
diff --git a/drivers/staging/comedi/drivers/addi_apci_1710.c b/drivers/staging/comedi/drivers/addi_apci_1710.c
deleted file mode 100644
index c9e6471eb06..00000000000
--- a/drivers/staging/comedi/drivers/addi_apci_1710.c
+++ /dev/null
@@ -1,99 +0,0 @@
-#include <linux/pci.h>
-
-#include <asm/i387.h>
-
-#include "../comedidev.h"
-#include "comedi_fc.h"
-#include "amcc_s5933.h"
-
-#include "addi-data/addi_common.h"
-
-static void fpu_begin(void)
-{
- kernel_fpu_begin();
-}
-
-static void fpu_end(void)
-{
- kernel_fpu_end();
-}
-
-#include "addi-data/addi_eeprom.c"
-#include "addi-data/hwdrv_APCI1710.c"
-
-static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
-{
- v_APCI1710_Interrupt(irq, d);
- return IRQ_RETVAL(1);
-}
-
-static int apci1710_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct addi_private *devpriv;
- struct comedi_subdevice *s;
- int ret;
-
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv)
- return -ENOMEM;
- dev->private = devpriv;
-
- ret = comedi_pci_enable(dev);
- if (ret)
- return ret;
- devpriv->s_BoardInfos.ui_Address = pci_resource_start(pcidev, 2);
-
- if (pcidev->irq > 0) {
- ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED,
- dev->board_name, dev);
- if (ret == 0)
- dev->irq = pcidev->irq;
- }
-
- i_ADDI_AttachPCI1710(dev);
-
- i_APCI1710_Reset(dev);
- return 0;
-}
-
-static void apci1710_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- i_APCI1710_Reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
-}
-
-static struct comedi_driver apci1710_driver = {
- .driver_name = "addi_apci_1710",
- .module = THIS_MODULE,
- .auto_attach = apci1710_auto_attach,
- .detach = apci1710_detach,
-};
-
-static int apci1710_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- return comedi_pci_auto_config(dev, &apci1710_driver, id->driver_data);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(apci1710_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMCC, APCI1710_BOARD_DEVICE_ID) },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, apci1710_pci_table);
-
-static struct pci_driver apci1710_pci_driver = {
- .name = "addi_apci_1710",
- .id_table = apci1710_pci_table,
- .probe = apci1710_pci_probe,
- .remove = comedi_pci_auto_unconfig,
-};
-module_comedi_pci_driver(apci1710_driver, apci1710_pci_driver);
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c
index 89ead8eb3c7..6b0ea16ff54 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2032.c
@@ -22,8 +22,10 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/slab.h>
#include "../comedidev.h"
#include "addi_watchdog.h"
diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c
index ca1bd92ecb1..92ac8ece849 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2200.c
@@ -22,6 +22,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c
index 61452848510..d804957018a 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3120.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3120.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -65,10 +66,9 @@ static int apci3120_auto_attach(struct comedi_device *dev,
dev->board_ptr = this_board;
dev->board_name = this_board->pc_DriverName;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c
index 17b540d3c6a..1213d5aa6be 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3200.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
#include <linux/pci.h>
#include <asm/i387.h>
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index f9b63689a12..d9650ffb7d2 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -22,6 +22,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
@@ -332,10 +333,9 @@ static int apci3501_auto_attach(struct comedi_device *dev,
int ao_n_chan;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
index 5b37cbf9228..cf5dd10eaf9 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
@@ -22,6 +22,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -685,38 +686,28 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev,
unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int mask = 1 << chan;
- unsigned int bits;
+ unsigned int mask;
+ int ret;
/*
* Port 0 (channels 0-7) are always inputs
* Port 1 (channels 8-15) are always outputs
* Port 2 (channels 16-23) are programmable i/o
- *
- * Changing any channel in port 2 changes the entire port.
*/
- if (mask & 0xff0000)
- bits = 0xff0000;
- else
- bits = 0;
-
- switch (data[0]) {
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~bits;
- break;
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= bits;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- default:
- return -EINVAL;
+ if (chan < 16) {
+ if (data[0] != INSN_CONFIG_DIO_QUERY)
+ return -EINVAL;
+ } else {
+ /* changing any channel in port 2 changes the entire port */
+ mask = 0xff0000;
}
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
+
/* update port 2 configuration */
- if (bits)
- outl((s->io_bits >> 24) & 0xff, dev->iobase + 224);
+ outl((s->io_bits >> 24) & 0xff, dev->iobase + 224);
return insn->n;
}
@@ -801,10 +792,9 @@ static int apci3xxx_auto_attach(struct comedi_device *dev,
dev->board_ptr = board;
dev->board_name = board->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/addi_watchdog.c b/drivers/staging/comedi/drivers/addi_watchdog.c
index 7b21acc9392..23031feaa09 100644
--- a/drivers/staging/comedi/drivers/addi_watchdog.c
+++ b/drivers/staging/comedi/drivers/addi_watchdog.c
@@ -18,6 +18,7 @@
* GNU General Public License for more details.
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include "addi_watchdog.h"
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index b5e4e53f737..a67ad57cefc 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -38,6 +38,7 @@ References:
- adl_pci9118.c
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -172,10 +173,9 @@ static int pci6208_auto_attach(struct comedi_device *dev,
dev->board_ptr = boardinfo;
dev->board_name = boardinfo->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
index 0d9243a5f49..81b7203f824 100644
--- a/drivers/staging/comedi/drivers/adl_pci7x3x.c
+++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c
@@ -44,6 +44,7 @@ driver.
Configuration Options: not applicable, uses comedi PCI auto config
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index 0b591b0b550..b3d009285ed 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -27,6 +27,7 @@
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index af51c746004..78cea193504 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -64,6 +64,7 @@ TODO:
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -855,10 +856,9 @@ static int pci9111_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev_private = kzalloc(sizeof(*dev_private), GFP_KERNEL);
+ dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private));
if (!dev_private)
return -ENOMEM;
- dev->private = dev_private;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index cb4ef2dcbf0..22196ada036 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -77,6 +77,7 @@ Configuration options:
* manual attachment.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/gfp.h>
@@ -2140,10 +2141,9 @@ static int pci9118_attach(struct comedi_device *dev,
softsshdelay = it->options[4];
hw_err_mask = it->options[5];
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
pcidev = pci9118_find_pci(dev, it);
if (!pcidev)
@@ -2160,10 +2160,9 @@ static int pci9118_auto_attach(struct comedi_device *dev,
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct pci9118_private *devpriv;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
dev->board_ptr = pci9118_find_boardinfo(pcidev);
if (dev->board_ptr == NULL) {
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index d187a7bf0a5..cdf5ba26c59 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -73,6 +73,9 @@ If you do not specify any options, they will default to
*/
+#include <linux/module.h>
+#include <linux/delay.h>
+
#include "../comedidev.h"
/* address scheme (page 2.17 of the manual) */
@@ -214,10 +217,9 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
devpriv->unipolar = it->options[1];
devpriv->differential = it->options[2];
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index f847bbc175e..f84df46d326 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -41,6 +41,7 @@ Configuration options:
device will be used.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -1233,10 +1234,9 @@ static int pci1710_auto_attach(struct comedi_device *dev,
dev->board_ptr = this_board;
dev->board_name = this_board->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 8430a27ec1b..b793d6987b8 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -43,6 +43,7 @@ TODO:
3. Implement calibration.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -179,38 +180,29 @@ static int pci1723_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int mask;
- unsigned int bits;
- unsigned short dio_mode;
+ unsigned short mode;
+ int ret;
- mask = 1 << CR_CHAN(insn->chanspec);
- if (mask & 0x00FF)
- bits = 0x00FF;
+ if (chan < 8)
+ mask = 0x00ff;
else
- bits = 0xFF00;
+ mask = 0xff00;
- switch (data[0]) {
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~bits;
- break;
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= bits;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- default:
- return -EINVAL;
- }
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
/* update hardware DIO mode */
- dio_mode = 0x0000; /* low byte output, high byte output */
- if ((s->io_bits & 0x00FF) == 0)
- dio_mode |= 0x0001; /* low byte input */
- if ((s->io_bits & 0xFF00) == 0)
- dio_mode |= 0x0002; /* high byte input */
- outw(dio_mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET);
- return 1;
+ mode = 0x0000; /* assume output */
+ if (!(s->io_bits & 0x00ff))
+ mode |= 0x0001; /* low byte input */
+ if (!(s->io_bits & 0xff00))
+ mode |= 0x0002; /* high byte input */
+ outw(mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET);
+
+ return insn->n;
}
/*
@@ -237,10 +229,9 @@ static int pci1723_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c
index da7462e01fa..009a3039fc4 100644
--- a/drivers/staging/comedi/drivers/adv_pci1724.c
+++ b/drivers/staging/comedi/drivers/adv_pci1724.c
@@ -52,6 +52,8 @@ supported PCI devices are configured as comedi devices automatically.
*/
+#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -123,10 +125,6 @@ static const struct comedi_lrange ao_ranges_1724 = { 4,
}
};
-static const struct comedi_lrange *const ao_range_list_1724[NUM_AO_CHANNELS] = {
- [0 ... NUM_AO_CHANNELS - 1] = &ao_ranges_1724,
-};
-
/* this structure is for data unique to this hardware driver. */
struct adv_pci1724_private {
int ao_value[NUM_AO_CHANNELS];
@@ -306,7 +304,7 @@ static int setup_subdevices(struct comedi_device *dev)
s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
s->n_chan = NUM_AO_CHANNELS;
s->maxdata = 0x3fff;
- s->range_table_list = ao_range_list_1724;
+ s->range_table = &ao_ranges_1724;
s->insn_read = ao_readback_insn;
s->insn_write = ao_winsn;
@@ -340,10 +338,9 @@ static int adv_pci1724_auto_attach(struct comedi_device *dev,
int retval;
unsigned int board_id;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
/* init software copies of output values to indicate we don't know
* what the output value is since it has never been written. */
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 8e6ec75bd29..f091fa0d304 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -29,6 +29,7 @@ Configuration options:
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
@@ -1107,10 +1108,9 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
dev->board_ptr = this_board;
dev->board_name = this_board->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index 279dfe8951f..abb28498b58 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -35,8 +35,8 @@ Notes:
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include "8255.h"
/*
@@ -202,10 +202,9 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 029834d0ff1..afe87cc8976 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -30,8 +30,8 @@ Configuration Options:
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#define AIO_IIRO_16_SIZE 0x08
#define AIO_IIRO_16_RELAY_0_7 0x00
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index e2478105ac1..dc1dee79fc1 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -192,8 +192,7 @@
* order they appear in the channel list.
*/
-#include <linux/slab.h>
-
+#include <linux/module.h>
#include "../comedidev.h"
#include "amplc_dio200.h"
@@ -272,10 +271,9 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
irq = it->options[1];
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_request_region(dev, it->options[0], thisboard->mainsize);
if (ret)
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c
index 649fc69724f..c1f723e8614 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_common.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c
@@ -19,8 +19,8 @@
GNU General Public License for more details.
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include "../comedidev.h"
@@ -976,34 +976,26 @@ static int dio200_subdev_8255_config(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
+ unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int mask;
- unsigned int bits;
-
- mask = 1 << CR_CHAN(insn->chanspec);
- if (mask & 0x0000ff)
- bits = 0x0000ff;
- else if (mask & 0x00ff00)
- bits = 0x00ff00;
- else if (mask & 0x0f0000)
- bits = 0x0f0000;
+ int ret;
+
+ if (chan < 8)
+ mask = 0x0000ff;
+ else if (chan < 16)
+ mask = 0x00ff00;
+ else if (chan < 20)
+ mask = 0x0f0000;
else
- bits = 0xf00000;
- switch (data[0]) {
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~bits;
- break;
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= bits;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- }
+ mask = 0xf00000;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
+
dio200_subdev_8255_set_dir(dev, s);
- return 1;
+
+ return insn->n;
}
/*
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_pci.c b/drivers/staging/comedi/drivers/amplc_dio200_pci.c
index d7d9f5cc3ab..a810a241644 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_pci.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_pci.c
@@ -220,9 +220,9 @@
* order they appear in the channel list.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include "../comedidev.h"
@@ -380,10 +380,9 @@ static int dio200_pci_auto_attach(struct comedi_device *dev,
dev_info(dev->class_dev, "%s: attach pci %s (%s)\n",
dev->driver->driver_name, pci_name(pci_dev), dev->board_name);
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 4e889b82cbf..98075f999c9 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -47,6 +47,7 @@ the IRQ jumper. If no interrupt is connected, then subdevice 1 is
unused.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -467,10 +468,9 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct pc236_private *devpriv;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
/* Process options according to bus type. */
if (is_isa_board(thisboard)) {
@@ -510,10 +510,9 @@ static int pc236_auto_attach(struct comedi_device *dev,
dev_info(dev->class_dev, PC236_DRIVER_NAME ": attach pci %s\n",
pci_name(pci_dev));
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
dev->board_ptr = pc236_find_pci_board(pci_dev);
if (dev->board_ptr == NULL) {
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 6546095e7a4..e7108045f55 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -33,6 +33,7 @@ connected to a reed-relay. Relay contacts are closed when output is 1.
The state of the outputs can be read.
*/
+#include <linux/module.h>
#include "../comedidev.h"
#define PC263_DRIVER_NAME "amplc_pc263"
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index f1e36f08b10..179de53a86f 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -98,6 +98,7 @@ Caveats:
correctly.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -1419,10 +1420,9 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev_info(dev->class_dev, DRIVER_NAME ": attach\n");
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
pci_dev = pci224_find_pci_dev(dev, it);
if (!pci_dev)
@@ -1440,10 +1440,9 @@ pci224_auto_attach(struct comedi_device *dev, unsigned long context_unused)
dev_info(dev->class_dev, DRIVER_NAME ": attach pci %s\n",
pci_name(pci_dev));
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
dev->board_ptr = pci224_find_pci_board(pci_dev);
if (dev->board_ptr == NULL) {
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 846d6448fa4..43059c25d5e 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -184,6 +184,7 @@ Support for PCI230+/260+, more triggered scan functionality, and workarounds
for (or detection of) various hardware problems added by Ian Abbott.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -2615,10 +2616,9 @@ static int pci230_alloc_private(struct comedi_device *dev)
{
struct pci230_private *devpriv;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
spin_lock_init(&devpriv->isr_spinlock);
spin_lock_init(&devpriv->res_spinlock);
diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c
index 4da900cc584..145bb48f618 100644
--- a/drivers/staging/comedi/drivers/amplc_pci263.c
+++ b/drivers/staging/comedi/drivers/amplc_pci263.c
@@ -32,6 +32,7 @@ connected to a reed-relay. Relay contacts are closed when output is 1.
The state of the outputs can be read.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index 929218a3597..217aa19cdc3 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -35,8 +35,6 @@ http://robot0.ge.uiuc.edu/~spong/mecha/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/timer.h>
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index ae9a2082b5a..0ce93da7084 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -34,8 +34,8 @@ Status: experimental
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include <linux/delay.h>
#include "../comedidev.h"
@@ -341,33 +341,22 @@ static int das16cs_dio_insn_bits(struct comedi_device *dev,
static int das16cs_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct das16cs_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
- int bits;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
+ int ret;
if (chan < 4)
- bits = 0x0f;
+ mask = 0x0f;
else
- bits = 0xf0;
+ mask = 0xf0;
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= bits;
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= bits;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- break;
- }
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
devpriv->status2 &= ~0x00c0;
devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0;
@@ -420,10 +409,9 @@ static int das16cs_auto_attach(struct comedi_device *dev,
return ret;
dev->irq = link->irq;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_alloc_subdevices(dev, 3);
if (ret)
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 58bca184bf2..41d89ee7fa3 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -61,6 +61,7 @@ TODO:
analog triggering on 1602 series
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -1444,10 +1445,9 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
dev->board_ptr = thisboard;
dev->board_name = thisboard->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 43c0bf58771..388dbd7a5d2 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -82,6 +82,7 @@ TODO:
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -3509,31 +3510,20 @@ static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
static int dio_60xx_config_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct pcidas64_private *devpriv = dev->private;
- unsigned int mask;
-
- mask = 1 << CR_CHAN(insn->chanspec);
+ int ret;
- switch (data[0]) {
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~mask;
- break;
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= mask;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return 2;
- default:
- return -EINVAL;
- }
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
writeb(s->io_bits,
devpriv->dio_counter_iobase + DIO_DIRECTION_60XX_REG);
- return 1;
+ return insn->n;
}
static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -4034,10 +4024,9 @@ static int auto_attach(struct comedi_device *dev,
return -ENODEV;
dev->board_ptr = thisboard;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
retval = comedi_pci_enable(dev);
if (retval)
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 2d3e920e598..94f11582027 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -37,6 +37,7 @@
* Only simple analog output writing is supported.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -348,10 +349,9 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev,
dev->board_ptr = thisboard;
dev->board_name = thisboard->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 8b5c198862a..30520d4c16a 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -35,8 +35,8 @@ No interrupts, multi channel or FIFO AI, although the card looks like it could s
See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details.
*/
+#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
@@ -210,10 +210,9 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
unsigned long iobase_8255;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index 406cba8cba8..edf17b63096 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -74,6 +74,7 @@ Configuration Options: not applicable, uses PCI auto config
-Calin Culianu <calin@ajvar.org>
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -156,10 +157,9 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index 1a51866be6f..51a59e5b8ec 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -1,130 +1,131 @@
/*
- comedi/drivers/comedi_bond.c
- A Comedi driver to 'bond' or merge multiple drivers and devices as one.
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 2000 David A. Schleef <ds@schleef.org>
- Copyright (C) 2005 Calin A. Culianu <calin@ajvar.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
-/*
-Driver: comedi_bond
-Description: A driver to 'bond' (merge) multiple subdevices from multiple
- devices together as one.
-Devices:
-Author: ds
-Updated: Mon, 10 Oct 00:18:25 -0500
-Status: works
-
-This driver allows you to 'bond' (merge) multiple comedi subdevices
-(coming from possibly difference boards and/or drivers) together. For
-example, if you had a board with 2 different DIO subdevices, and
-another with 1 DIO subdevice, you could 'bond' them with this driver
-so that they look like one big fat DIO subdevice. This makes writing
-applications slightly easier as you don't have to worry about managing
-different subdevices in the application -- you just worry about
-indexing one linear array of channel id's.
-
-Right now only DIO subdevices are supported as that's the personal itch
-I am scratching with this driver. If you want to add support for AI and AO
-subdevs, go right on ahead and do so!
-
-Commands aren't supported -- although it would be cool if they were.
-
-Configuration Options:
- List of comedi-minors to bond. All subdevices of the same type
- within each minor will be concatenated together in the order given here.
-*/
+ * comedi_bond.c
+ * A Comedi driver to 'bond' or merge multiple drivers and devices as one.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2005 Calin A. Culianu <calin@ajvar.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+/*
+ * Driver: comedi_bond
+ * Description: A driver to 'bond' (merge) multiple subdevices from multiple
+ * devices together as one.
+ * Devices:
+ * Author: ds
+ * Updated: Mon, 10 Oct 00:18:25 -0500
+ * Status: works
+ *
+ * This driver allows you to 'bond' (merge) multiple comedi subdevices
+ * (coming from possibly difference boards and/or drivers) together. For
+ * example, if you had a board with 2 different DIO subdevices, and
+ * another with 1 DIO subdevice, you could 'bond' them with this driver
+ * so that they look like one big fat DIO subdevice. This makes writing
+ * applications slightly easier as you don't have to worry about managing
+ * different subdevices in the application -- you just worry about
+ * indexing one linear array of channel id's.
+ *
+ * Right now only DIO subdevices are supported as that's the personal itch
+ * I am scratching with this driver. If you want to add support for AI and AO
+ * subdevs, go right on ahead and do so!
+ *
+ * Commands aren't supported -- although it would be cool if they were.
+ *
+ * Configuration Options:
+ * List of comedi-minors to bond. All subdevices of the same type
+ * within each minor will be concatenated together in the order given here.
+ */
+
+#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "../comedi.h"
#include "../comedilib.h"
#include "../comedidev.h"
-/* The maxiumum number of channels per subdevice. */
-#define MAX_CHANS 256
-
-struct BondedDevice {
+struct bonded_device {
struct comedi_device *dev;
unsigned minor;
unsigned subdev;
- unsigned subdev_type;
unsigned nchans;
- unsigned chanid_offset; /* The offset into our unified linear
- channel-id's of chanid 0 on this
- subdevice. */
};
-/* this structure is for data unique to this hardware driver. If
- several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct. */
struct comedi_bond_private {
# define MAX_BOARD_NAME 256
char name[MAX_BOARD_NAME];
- struct BondedDevice **devs;
+ struct bonded_device **devs;
unsigned ndevs;
- struct BondedDevice *chanIdDevMap[MAX_CHANS];
unsigned nchans;
};
-/* DIO devices are slightly special. Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels. The
- * comedi core can convert between insn_bits and insn_read/write */
static int bonding_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct comedi_bond_private *devpriv = dev->private;
-#define LSAMPL_BITS (sizeof(unsigned int)*8)
- unsigned nchans = LSAMPL_BITS, num_done = 0, i;
-
- if (devpriv->nchans < nchans)
- nchans = devpriv->nchans;
-
- /* The insn data is a mask in data[0] and the new data
- * in data[1], each channel cooresponding to a bit. */
- for (i = 0; num_done < nchans && i < devpriv->ndevs; ++i) {
- struct BondedDevice *bdev = devpriv->devs[i];
- /* Grab the channel mask and data of only the bits corresponding
- to this subdevice.. need to shift them to zero position of
- course. */
- /* Bits corresponding to this subdev. */
- unsigned int subdevMask = ((1 << bdev->nchans) - 1);
- unsigned int writeMask, dataBits;
-
- /* Argh, we have >= LSAMPL_BITS chans.. take all bits */
- if (bdev->nchans >= LSAMPL_BITS)
- subdevMask = (unsigned int)(-1);
-
- writeMask = (data[0] >> num_done) & subdevMask;
- dataBits = (data[1] >> num_done) & subdevMask;
-
- /* Read/Write the new digital lines */
- if (comedi_dio_bitfield(bdev->dev, bdev->subdev, writeMask,
- &dataBits) != 2)
- return -EINVAL;
-
- /* Make room for the new bits in data[1], the return value */
- data[1] &= ~(subdevMask << num_done);
- /* Put the bits in the return value */
- data[1] |= (dataBits & subdevMask) << num_done;
- /* Save the new bits to the saved state.. */
- s->state = data[1];
-
- num_done += bdev->nchans;
- }
+ unsigned int n_left, n_done, base_chan;
+ unsigned int write_mask, data_bits;
+ struct bonded_device **devs;
+
+ write_mask = data[0];
+ data_bits = data[1];
+ base_chan = CR_CHAN(insn->chanspec);
+ /* do a maximum of 32 channels, starting from base_chan. */
+ n_left = devpriv->nchans - base_chan;
+ if (n_left > 32)
+ n_left = 32;
+
+ n_done = 0;
+ devs = devpriv->devs;
+ do {
+ struct bonded_device *bdev = *devs++;
+
+ if (base_chan < bdev->nchans) {
+ /* base channel falls within bonded device */
+ unsigned int b_chans, b_mask, b_write_mask, b_data_bits;
+ int ret;
+
+ /*
+ * Get num channels to do for bonded device and set
+ * up mask and data bits for bonded device.
+ */
+ b_chans = bdev->nchans - base_chan;
+ if (b_chans > n_left)
+ b_chans = n_left;
+ b_mask = (1U << b_chans) - 1;
+ b_write_mask = (write_mask >> n_done) & b_mask;
+ b_data_bits = (data_bits >> n_done) & b_mask;
+ /* Read/Write the new digital lines. */
+ ret = comedi_dio_bitfield2(bdev->dev, bdev->subdev,
+ b_write_mask, &b_data_bits,
+ base_chan);
+ if (ret < 0)
+ return ret;
+ /* Place read bits into data[1]. */
+ data[1] &= ~(b_mask << n_done);
+ data[1] |= (b_data_bits & b_mask) << n_done;
+ /*
+ * Set up for following bonded device (if still have
+ * channels to read/write).
+ */
+ base_chan = 0;
+ n_done += b_chans;
+ n_left -= b_chans;
+ } else {
+ /* Skip bonded devices before base channel. */
+ base_chan -= bdev->nchans;
+ }
+ } while (n_left);
return insn->n;
}
@@ -134,99 +135,91 @@ static int bonding_dio_insn_config(struct comedi_device *dev,
struct comedi_insn *insn, unsigned int *data)
{
struct comedi_bond_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits;
- unsigned int io;
- struct BondedDevice *bdev;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int ret;
+ struct bonded_device *bdev;
+ struct bonded_device **devs;
- if (chan < 0 || chan >= devpriv->nchans)
- return -EINVAL;
- bdev = devpriv->chanIdDevMap[chan];
+ /*
+ * Locate bonded subdevice and adjust channel.
+ */
+ devs = devpriv->devs;
+ for (bdev = *devs++; chan >= bdev->nchans; bdev = *devs++)
+ chan -= bdev->nchans;
- /* The input or output configuration of each digital line is
+ /*
+ * The input or output configuration of each digital line is
* configured by a special insn_config instruction. chanspec
* contains the channel to be changed, and data[0] contains the
- * value COMEDI_INPUT or COMEDI_OUTPUT. */
+ * configuration instruction INSN_CONFIG_DIO_OUTPUT,
+ * INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_QUERY.
+ *
+ * Note that INSN_CONFIG_DIO_OUTPUT == COMEDI_OUTPUT,
+ * and INSN_CONFIG_DIO_INPUT == COMEDI_INPUT. This is deliberate ;)
+ */
switch (data[0]) {
case INSN_CONFIG_DIO_OUTPUT:
- io = COMEDI_OUTPUT; /* is this really necessary? */
- io_bits |= 1 << chan;
- break;
case INSN_CONFIG_DIO_INPUT:
- io = COMEDI_INPUT; /* is this really necessary? */
- io_bits &= ~(1 << chan);
+ ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, data[0]);
break;
case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
+ ret = comedi_dio_get_config(bdev->dev, bdev->subdev, chan,
+ &data[1]);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
break;
}
- /* 'real' channel id for this subdev.. */
- chan -= bdev->chanid_offset;
- ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, io);
- if (ret != 1)
- return -EINVAL;
- /* Finally, save the new io_bits values since we didn't get
- an error above. */
- s->io_bits = io_bits;
- return insn->n;
+ if (ret >= 0)
+ ret = insn->n;
+ return ret;
}
-static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen)
-{
- void *newmem = kmalloc(newlen, GFP_KERNEL);
-
- if (newmem && oldmem)
- memcpy(newmem, oldmem, min(oldlen, newlen));
- kfree(oldmem);
- return newmem;
-}
-
-static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
+static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_bond_private *devpriv = dev->private;
+ DECLARE_BITMAP(devs_opened, COMEDI_NUM_BOARD_MINORS);
int i;
- struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS];
- memset(devs_opened, 0, sizeof(devs_opened));
+ memset(&devs_opened, 0, sizeof(devs_opened));
devpriv->name[0] = 0;
- /* Loop through all comedi devices specified on the command-line,
- building our device list */
+ /*
+ * Loop through all comedi devices specified on the command-line,
+ * building our device list.
+ */
for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) {
- char file[] = "/dev/comediXXXXXX";
+ char file[sizeof("/dev/comediXXXXXX")];
int minor = it->options[i];
struct comedi_device *d;
- int sdev = -1, nchans, tmp;
- struct BondedDevice *bdev = NULL;
+ int sdev = -1, nchans;
+ struct bonded_device *bdev;
+ struct bonded_device **devs;
if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) {
dev_err(dev->class_dev,
"Minor %d is invalid!\n", minor);
- return 0;
+ return -EINVAL;
}
if (minor == dev->minor) {
dev_err(dev->class_dev,
"Cannot bond this driver to itself!\n");
- return 0;
+ return -EINVAL;
}
- if (devs_opened[minor]) {
+ if (test_and_set_bit(minor, devs_opened)) {
dev_err(dev->class_dev,
"Minor %d specified more than once!\n", minor);
- return 0;
+ return -EINVAL;
}
snprintf(file, sizeof(file), "/dev/comedi%u", minor);
file[sizeof(file) - 1] = 0;
- d = devs_opened[minor] = comedi_open(file);
+ d = comedi_open(file);
if (!d) {
dev_err(dev->class_dev,
"Minor %u could not be opened\n", minor);
- return 0;
+ return -ENODEV;
}
/* Do DIO, as that's all we support now.. */
@@ -237,45 +230,41 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
dev_err(dev->class_dev,
"comedi_get_n_channels() returned %d on minor %u subdev %d!\n",
nchans, minor, sdev);
- return 0;
+ return -EINVAL;
}
bdev = kmalloc(sizeof(*bdev), GFP_KERNEL);
if (!bdev)
- return 0;
+ return -ENOMEM;
bdev->dev = d;
bdev->minor = minor;
bdev->subdev = sdev;
- bdev->subdev_type = COMEDI_SUBD_DIO;
bdev->nchans = nchans;
- bdev->chanid_offset = devpriv->nchans;
+ devpriv->nchans += nchans;
- /* map channel id's to BondedDevice * pointer.. */
- while (nchans--)
- devpriv->chanIdDevMap[devpriv->nchans++] = bdev;
-
- /* Now put bdev pointer at end of devpriv->devs array
- * list.. */
+ /*
+ * Now put bdev pointer at end of devpriv->devs array
+ * list..
+ */
/* ergh.. ugly.. we need to realloc :( */
- tmp = devpriv->ndevs * sizeof(bdev);
- devpriv->devs =
- Realloc(devpriv->devs,
- ++devpriv->ndevs * sizeof(bdev), tmp);
- if (!devpriv->devs) {
+ devs = krealloc(devpriv->devs,
+ (devpriv->ndevs + 1) * sizeof(*devs),
+ GFP_KERNEL);
+ if (!devs) {
dev_err(dev->class_dev,
"Could not allocate memory. Out of memory?\n");
- return 0;
+ return -ENOMEM;
}
-
- devpriv->devs[devpriv->ndevs - 1] = bdev;
+ devpriv->devs = devs;
+ devpriv->devs[devpriv->ndevs++] = bdev;
{
- /** Append dev:subdev to devpriv->name */
+ /* Append dev:subdev to devpriv->name */
char buf[20];
int left =
MAX_BOARD_NAME - strlen(devpriv->name) - 1;
- snprintf(buf, sizeof(buf), "%d:%d ", dev->minor,
- bdev->subdev);
+ snprintf(buf, sizeof(buf), "%d:%d ",
+ bdev->minor, bdev->subdev);
buf[sizeof(buf) - 1] = 0;
strncat(devpriv->name, buf, left);
}
@@ -285,10 +274,10 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
if (!devpriv->nchans) {
dev_err(dev->class_dev, "No channels found!\n");
- return 0;
+ return -EINVAL;
}
- return 1;
+ return 0;
}
static int bonding_attach(struct comedi_device *dev,
@@ -298,16 +287,16 @@ static int bonding_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
/*
* Setup our bonding from config params.. sets up our private struct..
*/
- if (!doDevConfig(dev, it))
- return -EINVAL;
+ ret = do_dev_config(dev, it);
+ if (ret)
+ return ret;
dev->board_name = devpriv->name;
@@ -329,31 +318,29 @@ static int bonding_attach(struct comedi_device *dev,
dev->driver->driver_name, dev->board_name,
devpriv->nchans, devpriv->ndevs);
- return 1;
+ return 0;
}
static void bonding_detach(struct comedi_device *dev)
{
struct comedi_bond_private *devpriv = dev->private;
- unsigned long devs_closed = 0;
- if (devpriv) {
- while (devpriv->ndevs-- && devpriv->devs) {
- struct BondedDevice *bdev;
+ if (devpriv && devpriv->devs) {
+ DECLARE_BITMAP(devs_closed, COMEDI_NUM_BOARD_MINORS);
+
+ memset(&devs_closed, 0, sizeof(devs_closed));
+ while (devpriv->ndevs--) {
+ struct bonded_device *bdev;
bdev = devpriv->devs[devpriv->ndevs];
if (!bdev)
continue;
- if (!(devs_closed & (0x1 << bdev->minor))) {
+ if (!test_and_set_bit(bdev->minor, devs_closed))
comedi_close(bdev->dev);
- devs_closed |= (0x1 << bdev->minor);
- }
kfree(bdev);
}
kfree(devpriv->devs);
devpriv->devs = NULL;
- kfree(devpriv);
- dev->private = NULL;
}
}
@@ -366,7 +353,5 @@ static struct comedi_driver bonding_driver = {
module_comedi_driver(bonding_driver);
MODULE_AUTHOR("Calin A. Culianu");
-MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI "
- "devices together as one. In the words of John Lennon: "
- "'And the world will live as one...'");
+MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI devices together as one.");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c
index b3d89c82d08..26d9dbcf8bd 100644
--- a/drivers/staging/comedi/drivers/comedi_fc.c
+++ b/drivers/staging/comedi/drivers/comedi_fc.c
@@ -19,6 +19,7 @@
GNU General Public License for more details.
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include "comedi_fc.h"
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 772a8f5f0c1..f28a15f0274 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -76,9 +76,9 @@ pin, which can be used to wake up tasks.
or http://www.linux-magazin.de/ausgabe/1999/10/IO/io.html
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include <linux/interrupt.h>
-#include <linux/ioport.h>
#include "comedi_fc.h"
@@ -279,10 +279,9 @@ static int parport_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
s = &dev->subdevices[0];
s->type = COMEDI_SUBD_DIO;
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index 907e7a3822f..16c07802107 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -45,6 +45,7 @@ zero volts).
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include <asm/div64.h>
@@ -379,10 +380,9 @@ static int waveform_attach(struct comedi_device *dev,
int i;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
/* set default amplitude and period */
if (amplitude <= 0)
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index 0fb9027dde2..e781716bf35 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -25,6 +25,7 @@ Status: works
Configuration Options: not applicable, uses comedi PCI auto config
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index 44c912b48b6..de920ccff40 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -102,6 +102,7 @@ Configuration options: not applicable, uses PCI auto config
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -683,10 +684,9 @@ static int daqboard2000_auto_attach(struct comedi_device *dev,
dev->board_ptr = board;
dev->board_name = board->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
result = comedi_pci_enable(dev);
if (result)
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index 2e7e3e20239..5f669709501 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -33,7 +33,7 @@
* cheap das08 hardware doesn't really support them.
*/
-#include <linux/delay.h>
+#include <linux/module.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index 885fb179c9b..f3ccc2ce6d4 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -39,8 +39,7 @@ Options (for pcm-das08):
Command support does not exist, but could be added for this board.
*/
-#include <linux/delay.h>
-#include <linux/slab.h>
+#include <linux/module.h>
#include "../comedidev.h"
@@ -78,10 +77,9 @@ static int das08_cs_auto_attach(struct comedi_device *dev,
return ret;
iobase = link->resource[0]->start;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
return das08_common_attach(dev, iobase);
}
diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c
index 21a94389b8b..4fb03d3852d 100644
--- a/drivers/staging/comedi/drivers/das08_isa.c
+++ b/drivers/staging/comedi/drivers/das08_isa.c
@@ -43,6 +43,7 @@
* [0] - base io address
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include "das08.h"
@@ -177,10 +178,9 @@ static int das08_isa_attach(struct comedi_device *dev,
struct das08_private_struct *devpriv;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_request_region(dev, it->options[0], thisboard->iosize);
if (ret)
diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c
index 9c5d234e063..3a6d3725b25 100644
--- a/drivers/staging/comedi/drivers/das08_pci.c
+++ b/drivers/staging/comedi/drivers/das08_pci.c
@@ -31,6 +31,7 @@
* Configuration Options: not applicable, uses PCI auto config
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -59,10 +60,9 @@ static int das08_pci_auto_attach(struct comedi_device *dev,
struct das08_private_struct *devpriv;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
/* The das08 driver needs the board_ptr */
dev->board_ptr = &das08_pci_boards[0];
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index dbec3ba9954..1b0793f33b9 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -1,80 +1,89 @@
/*
- comedi/drivers/das16.c
- DAS16 driver
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 2000 David A. Schleef <ds@schleef.org>
- Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
- Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.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.
-
- 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.
-*/
-/*
-Driver: das16
-Description: DAS16 compatible boards
-Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
-Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g),
- DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202),
- DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601),
- DAS-1602 (das-1602),
- [ComputerBoards] PC104-DAS16/JR (pc104-das16jr),
- PC104-DAS16JR/16 (pc104-das16jr/16),
- CIO-DAS16JR/16 (cio-das16jr/16),
- CIO-DAS16/JR (cio-das16/jr), CIO-DAS1401/12 (cio-das1401/12),
- CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16),
- CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12),
- CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330)
-Status: works
-Updated: 2003-10-12
-
-A rewrite of the das16 and das1600 drivers.
-Options:
- [0] - base io address
- [1] - irq (does nothing, irq is not used anymore)
- [2] - dma (optional, required for comedi_command support)
- [3] - master clock speed in MHz (optional, 1 or 10, ignored if
- board can probe clock, defaults to 1)
- [4] - analog input range lowest voltage in microvolts (optional,
- only useful if your board does not have software
- programmable gain)
- [5] - analog input range highest voltage in microvolts (optional,
- only useful if board does not have software programmable
- gain)
- [6] - analog output range lowest voltage in microvolts (optional)
- [7] - analog output range highest voltage in microvolts (optional)
- [8] - use timer mode for DMA. Timer mode is needed e.g. for
- buggy DMA controllers in NS CS5530A (Geode Companion), and for
- 'jr' cards that lack a hardware fifo. This option is no
- longer needed, since timer mode is _always_ used.
-
-Passing a zero for an option is the same as leaving it unspecified.
+ * das16.c
+ * DAS16 driver
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
+ * Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.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.
+ *
+ * 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.
+ */
-*/
/*
+ * Driver: das16
+ * Description: DAS16 compatible boards
+ * Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
+ * Devices: (Keithley Metrabyte) DAS-16 [das-16]
+ * (Keithley Metrabyte) DAS-16G [das-16g]
+ * (Keithley Metrabyte) DAS-16F [das-16f]
+ * (Keithley Metrabyte) DAS-1201 [das-1201]
+ * (Keithley Metrabyte) DAS-1202 [das-1202]
+ * (Keithley Metrabyte) DAS-1401 [das-1401]
+ * (Keithley Metrabyte) DAS-1402 [das-1402]
+ * (Keithley Metrabyte) DAS-1601 [das-1601]
+ * (Keithley Metrabyte) DAS-1602 [das-1602]
+ * (ComputerBoards) PC104-DAS16/JR [pc104-das16jr]
+ * (ComputerBoards) PC104-DAS16JR/16 [pc104-das16jr/16]
+ * (ComputerBoards) CIO-DAS16 [cio-das16]
+ * (ComputerBoards) CIO-DAS16F [cio-das16/f]
+ * (ComputerBoards) CIO-DAS16/JR [cio-das16/jr]
+ * (ComputerBoards) CIO-DAS16JR/16 [cio-das16jr/16]
+ * (ComputerBoards) CIO-DAS1401/12 [cio-das1401/12]
+ * (ComputerBoards) CIO-DAS1402/12 [cio-das1402/12]
+ * (ComputerBoards) CIO-DAS1402/16 [cio-das1402/16]
+ * (ComputerBoards) CIO-DAS1601/12 [cio-das1601/12]
+ * (ComputerBoards) CIO-DAS1602/12 [cio-das1602/12]
+ * (ComputerBoards) CIO-DAS1602/16 [cio-das1602/16]
+ * (ComputerBoards) CIO-DAS16/330 [cio-das16/330]
+ * Status: works
+ * Updated: 2003-10-12
+ *
+ * A rewrite of the das16 and das1600 drivers.
+ *
+ * Options:
+ * [0] - base io address
+ * [1] - irq (does nothing, irq is not used anymore)
+ * [2] - dma channel (optional, required for comedi_command support)
+ * [3] - master clock speed in MHz (optional, 1 or 10, ignored if
+ * board can probe clock, defaults to 1)
+ * [4] - analog input range lowest voltage in microvolts (optional,
+ * only useful if your board does not have software
+ * programmable gain)
+ * [5] - analog input range highest voltage in microvolts (optional,
+ * only useful if board does not have software programmable
+ * gain)
+ * [6] - analog output range lowest voltage in microvolts (optional)
+ * [7] - analog output range highest voltage in microvolts (optional)
+ *
+ * Passing a zero for an option is the same as leaving it unspecified.
+ */
-Testing and debugging help provided by Daniel Koch.
-
-Keithley Manuals:
- 2309.PDF (das16)
- 4919.PDF (das1400, 1600)
- 4922.PDF (das-1400)
- 4923.PDF (das1200, 1400, 1600)
-
-Computer boards manuals also available from their website
-www.measurementcomputing.com
-
-*/
+/*
+ * Testing and debugging help provided by Daniel Koch.
+ *
+ * Keithley Manuals:
+ * 2309.PDF (das16)
+ * 4919.PDF (das1400, 1600)
+ * 4922.PDF (das-1400)
+ * 4923.PDF (das1200, 1400, 1600)
+ *
+ * Computer boards manuals also available from their website
+ * www.measurementcomputing.com
+ */
-#include <linux/pci.h>
+#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
#include <linux/interrupt.h>
#include <asm/dma.h>
@@ -85,214 +94,112 @@ www.measurementcomputing.com
#include "8255.h"
#include "comedi_fc.h"
-#undef DEBUG
-/* #define DEBUG */
-
-#ifdef DEBUG
-#define DEBUG_PRINT(format, args...) \
- printk(KERN_DEBUG "das16: " format, ## args)
-#else
-#define DEBUG_PRINT(format, args...)
-#endif
-
-#define DAS16_SIZE 20 /* number of ioports */
#define DAS16_DMA_SIZE 0xff00 /* size in bytes of allocated dma buffer */
/*
- cio-das16.pdf
-
- "das16"
- "das16/f"
-
- 0 a/d bits 0-3 start 12 bit
- 1 a/d bits 4-11 unused
- 2 mux read mux set
- 3 di 4 bit do 4 bit
- 4 unused ao0_lsb
- 5 unused ao0_msb
- 6 unused ao1_lsb
- 7 unused ao1_msb
- 8 status eoc uni/bip interrupt reset
- 9 dma, int, trig ctrl set dma, int
- a pacer control unused
- b reserved reserved
- cdef 8254
- 0123 8255
-
-*/
-
-/*
- cio-das16jr.pdf
-
- "das16jr"
-
- 0 a/d bits 0-3 start 12 bit
- 1 a/d bits 4-11 unused
- 2 mux read mux set
- 3 di 4 bit do 4 bit
- 4567 unused unused
- 8 status eoc uni/bip interrupt reset
- 9 dma, int, trig ctrl set dma, int
- a pacer control unused
- b gain status gain control
- cdef 8254
-
-*/
-
-/*
- cio-das16jr_16.pdf
-
- "das16jr_16"
-
- 0 a/d bits 0-7 start 16 bit
- 1 a/d bits 8-15 unused
- 2 mux read mux set
- 3 di 4 bit do 4 bit
- 4567 unused unused
- 8 status eoc uni/bip interrupt reset
- 9 dma, int, trig ctrl set dma, int
- a pacer control unused
- b gain status gain control
- cdef 8254
-
-*/
-/*
- cio-das160x-1x.pdf
-
- "das1601/12"
- "das1602/12"
- "das1602/16"
-
- 0 a/d bits 0-3 start 12 bit
- 1 a/d bits 4-11 unused
- 2 mux read mux set
- 3 di 4 bit do 4 bit
- 4 unused ao0_lsb
- 5 unused ao0_msb
- 6 unused ao1_lsb
- 7 unused ao1_msb
- 8 status eoc uni/bip interrupt reset
- 9 dma, int, trig ctrl set dma, int
- a pacer control unused
- b gain status gain control
- cdef 8254
- 400 8255
- 404 unused conversion enable
- 405 unused burst enable
- 406 unused das1600 enable
- 407 status
-
-*/
-
-/* size in bytes of a sample from board */
-static const int sample_size = 2;
-
-#define DAS16_TRIG 0
-#define DAS16_AI_LSB 0
-#define DAS16_AI_MSB 1
-#define DAS16_MUX 2
-#define DAS16_DIO 3
-#define DAS16_AO_LSB(x) ((x) ? 6 : 4)
-#define DAS16_AO_MSB(x) ((x) ? 7 : 5)
-#define DAS16_STATUS 8
-#define BUSY (1<<7)
-#define UNIPOLAR (1<<6)
-#define DAS16_MUXBIT (1<<5)
-#define DAS16_INT (1<<4)
-#define DAS16_CONTROL 9
-#define DAS16_INTE (1<<7)
-#define DAS16_IRQ(x) (((x) & 0x7) << 4)
-#define DMA_ENABLE (1<<2)
-#define PACING_MASK 0x3
-#define INT_PACER 0x03
-#define EXT_PACER 0x02
-#define DAS16_SOFT 0x00
-#define DAS16_PACER 0x0A
-#define DAS16_CTR0 (1<<1)
-#define DAS16_TRIG0 (1<<0)
-#define BURST_LEN_BITS(x) (((x) & 0xf) << 4)
-#define DAS16_GAIN 0x0B
-#define DAS16_CNTR0_DATA 0x0C
-#define DAS16_CNTR1_DATA 0x0D
-#define DAS16_CNTR2_DATA 0x0E
-#define DAS16_CNTR_CONTROL 0x0F
-#define DAS16_TERM_CNT 0x00
-#define DAS16_ONE_SHOT 0x02
-#define DAS16_RATE_GEN 0x04
-#define DAS16_CNTR_LSB_MSB 0x30
-#define DAS16_CNTR0 0x00
-#define DAS16_CNTR1 0x40
-#define DAS16_CNTR2 0x80
-
-#define DAS1600_CONV 0x404
-#define DAS1600_CONV_DISABLE 0x40
-#define DAS1600_BURST 0x405
-#define DAS1600_BURST_VAL 0x40
-#define DAS1600_ENABLE 0x406
-#define DAS1600_ENABLE_VAL 0x40
-#define DAS1600_STATUS_B 0x407
-#define DAS1600_BME 0x40
-#define DAS1600_ME 0x20
-#define DAS1600_CD 0x10
-#define DAS1600_WS 0x02
-#define DAS1600_CLK_10MHZ 0x01
-
-static const struct comedi_lrange range_das1x01_bip = { 4, {
- BIP_RANGE(10),
- BIP_RANGE(1),
- BIP_RANGE(0.1),
- BIP_RANGE(0.01),
- }
+ * Register I/O map
+ */
+#define DAS16_TRIG_REG 0x00
+#define DAS16_AI_LSB_REG 0x00
+#define DAS16_AI_MSB_REG 0x01
+#define DAS16_MUX_REG 0x02
+#define DAS16_DIO_REG 0x03
+#define DAS16_AO_LSB_REG(x) ((x) ? 0x06 : 0x04)
+#define DAS16_AO_MSB_REG(x) ((x) ? 0x07 : 0x05)
+#define DAS16_STATUS_REG 0x08
+#define DAS16_STATUS_BUSY (1 << 7)
+#define DAS16_STATUS_UNIPOLAR (1 << 6)
+#define DAS16_STATUS_MUXBIT (1 << 5)
+#define DAS16_STATUS_INT (1 << 4)
+#define DAS16_CTRL_REG 0x09
+#define DAS16_CTRL_INTE (1 << 7)
+#define DAS16_CTRL_IRQ(x) (((x) & 0x7) << 4)
+#define DAS16_CTRL_DMAE (1 << 2)
+#define DAS16_CTRL_PACING_MASK (3 << 0)
+#define DAS16_CTRL_INT_PACER (3 << 0)
+#define DAS16_CTRL_EXT_PACER (2 << 0)
+#define DAS16_CTRL_SOFT_PACER (0 << 0)
+#define DAS16_PACER_REG 0x0a
+#define DAS16_PACER_BURST_LEN(x) (((x) & 0xf) << 4)
+#define DAS16_PACER_CTR0 (1 << 1)
+#define DAS16_PACER_TRIG0 (1 << 0)
+#define DAS16_GAIN_REG 0x0b
+#define DAS16_TIMER_BASE_REG 0x0c /* to 0x0f */
+
+#define DAS1600_CONV_REG 0x404
+#define DAS1600_CONV_DISABLE (1 << 6)
+#define DAS1600_BURST_REG 0x405
+#define DAS1600_BURST_VAL (1 << 6)
+#define DAS1600_ENABLE_REG 0x406
+#define DAS1600_ENABLE_VAL (1 << 6)
+#define DAS1600_STATUS_REG 0x407
+#define DAS1600_STATUS_BME (1 << 6)
+#define DAS1600_STATUS_ME (1 << 5)
+#define DAS1600_STATUS_CD (1 << 4)
+#define DAS1600_STATUS_WS (1 << 1)
+#define DAS1600_STATUS_CLK_10MHZ (1 << 0)
+
+static const struct comedi_lrange range_das1x01_bip = {
+ 4, {
+ BIP_RANGE(10),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.01)
+ }
};
-static const struct comedi_lrange range_das1x01_unip = { 4, {
- UNI_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(0.1),
- UNI_RANGE(0.01),
- }
+static const struct comedi_lrange range_das1x01_unip = {
+ 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.01)
+ }
};
-static const struct comedi_lrange range_das1x02_bip = { 4, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- }
+static const struct comedi_lrange range_das1x02_bip = {
+ 4, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25)
+ }
};
-static const struct comedi_lrange range_das1x02_unip = { 4, {
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- }
+static const struct comedi_lrange range_das1x02_unip = {
+ 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
-static const struct comedi_lrange range_das16jr = { 9, {
- /* also used by 16/330 */
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- }
+static const struct comedi_lrange range_das16jr = {
+ 9, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
-static const struct comedi_lrange range_das16jr_16 = { 8, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- }
+static const struct comedi_lrange range_das16jr_16 = {
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
static const int das16jr_gainlist[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 };
@@ -330,30 +237,211 @@ static const struct comedi_lrange *const das16_ai_bip_lranges[] = {
&range_das1x02_bip,
};
-struct munge_info {
- uint8_t byte;
- unsigned have_byte:1;
-};
-
struct das16_board {
const char *name;
- void *ai;
- unsigned int ai_nbits;
+ unsigned int ai_maxdata;
unsigned int ai_speed; /* max conversion speed in nanosec */
unsigned int ai_pg;
- void *ao;
- unsigned int ao_nbits;
- void *di;
- void *do_;
+ unsigned int has_ao:1;
+ unsigned int has_8255:1;
unsigned int i8255_offset;
- unsigned int i8254_offset;
unsigned int size;
unsigned int id;
};
-#define DAS16_TIMEOUT 1000
+static const struct das16_board das16_boards[] = {
+ {
+ .name = "das-16",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 15000,
+ .ai_pg = das16_pg_none,
+ .has_ao = 1,
+ .has_8255 = 1,
+ .i8255_offset = 0x10,
+ .size = 0x14,
+ .id = 0x00,
+ }, {
+ .name = "das-16g",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 15000,
+ .ai_pg = das16_pg_none,
+ .has_ao = 1,
+ .has_8255 = 1,
+ .i8255_offset = 0x10,
+ .size = 0x14,
+ .id = 0x00,
+ }, {
+ .name = "das-16f",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 8500,
+ .ai_pg = das16_pg_none,
+ .has_ao = 1,
+ .has_8255 = 1,
+ .i8255_offset = 0x10,
+ .size = 0x14,
+ .id = 0x00,
+ }, {
+ .name = "cio-das16",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 20000,
+ .ai_pg = das16_pg_none,
+ .has_ao = 1,
+ .has_8255 = 1,
+ .i8255_offset = 0x10,
+ .size = 0x14,
+ .id = 0x80,
+ }, {
+ .name = "cio-das16/f",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_none,
+ .has_ao = 1,
+ .has_8255 = 1,
+ .i8255_offset = 0x10,
+ .size = 0x14,
+ .id = 0x80,
+ }, {
+ .name = "cio-das16/jr",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 7692,
+ .ai_pg = das16_pg_16jr,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "pc104-das16jr",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 3300,
+ .ai_pg = das16_pg_16jr,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "cio-das16jr/16",
+ .ai_maxdata = 0xffff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_16jr_16,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "pc104-das16jr/16",
+ .ai_maxdata = 0xffff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_16jr_16,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "das-1201",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 20000,
+ .ai_pg = das16_pg_none,
+ .has_8255 = 1,
+ .i8255_offset = 0x400,
+ .size = 0x408,
+ .id = 0x20,
+ }, {
+ .name = "das-1202",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_none,
+ .has_8255 = 1,
+ .i8255_offset = 0x400,
+ .size = 0x408,
+ .id = 0x20,
+ }, {
+ .name = "das-1401",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1601,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "das-1402",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "das-1601",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1601,
+ .has_ao = 1,
+ .has_8255 = 1,
+ .i8255_offset = 0x400,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "das-1602",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .has_ao = 1,
+ .has_8255 = 1,
+ .i8255_offset = 0x400,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1401/12",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 6250,
+ .ai_pg = das16_pg_1601,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1402/12",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 6250,
+ .ai_pg = das16_pg_1602,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1402/16",
+ .ai_maxdata = 0xffff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1601/12",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 6250,
+ .ai_pg = das16_pg_1601,
+ .has_ao = 1,
+ .has_8255 = 1,
+ .i8255_offset = 0x400,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1602/12",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .has_ao = 1,
+ .has_8255 = 1,
+ .i8255_offset = 0x400,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1602/16",
+ .ai_maxdata = 0xffff,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .has_ao = 1,
+ .has_8255 = 1,
+ .i8255_offset = 0x400,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das16/330",
+ .ai_maxdata = 0x0fff,
+ .ai_speed = 3030,
+ .ai_pg = das16_pg_16jr,
+ .size = 0x14,
+ .id = 0xf0,
+ },
+};
/* Period for timer interrupt in jiffies. It's a function
* to deal with possibility of dynamic HZ patches */
@@ -363,34 +451,155 @@ static inline int timer_period(void)
}
struct das16_private_struct {
- unsigned int ai_unipolar; /* unipolar flag */
- unsigned int ai_singleended; /* single ended flag */
- unsigned int clockbase; /* master clock speed in ns */
- volatile unsigned int control_state; /* dma, interrupt and trigger control bits */
- volatile unsigned long adc_byte_count; /* number of bytes remaining */
- /* divisor dividing master clock to get conversion frequency */
- unsigned int divisor1;
- /* divisor dividing master clock to get conversion frequency */
- unsigned int divisor2;
- unsigned int dma_chan; /* dma channel */
- uint16_t *dma_buffer[2];
- dma_addr_t dma_buffer_addr[2];
- unsigned int current_buffer;
- volatile unsigned int dma_transfer_size; /* target number of bytes to transfer per dma shot */
- /**
- * user-defined analog input and output ranges
- * defined from config options
- */
- struct comedi_lrange *user_ai_range_table;
- struct comedi_lrange *user_ao_range_table;
-
- struct timer_list timer; /* for timed interrupt */
- volatile short timer_running;
- volatile short timer_mode; /* true if using timer mode */
-
- unsigned long extra_iobase;
+ unsigned int clockbase;
+ unsigned int ctrl_reg;
+ unsigned long adc_byte_count;
+ unsigned int divisor1;
+ unsigned int divisor2;
+ unsigned int dma_chan;
+ uint16_t *dma_buffer[2];
+ dma_addr_t dma_buffer_addr[2];
+ unsigned int current_buffer;
+ unsigned int dma_transfer_size;
+ struct comedi_lrange *user_ai_range_table;
+ struct comedi_lrange *user_ao_range_table;
+ struct timer_list timer;
+ short timer_running;
+ unsigned long extra_iobase;
+ unsigned int can_burst:1;
};
+static void das16_ai_enable(struct comedi_device *dev,
+ unsigned int mode, unsigned int src)
+{
+ struct das16_private_struct *devpriv = dev->private;
+
+ devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE |
+ DAS16_CTRL_DMAE |
+ DAS16_CTRL_PACING_MASK);
+ devpriv->ctrl_reg |= mode;
+
+ if (src == TRIG_EXT)
+ devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER;
+ else
+ devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER;
+ outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
+}
+
+static void das16_ai_disable(struct comedi_device *dev)
+{
+ struct das16_private_struct *devpriv = dev->private;
+
+ /* disable interrupts, dma and pacer clocked conversions */
+ devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE |
+ DAS16_CTRL_DMAE |
+ DAS16_CTRL_PACING_MASK);
+ outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
+}
+
+/* the pc104-das16jr (at least) has problems if the dma
+ transfer is interrupted in the middle of transferring
+ a 16 bit sample, so this function takes care to get
+ an even transfer count after disabling dma
+ channel.
+*/
+static int disable_dma_on_even(struct comedi_device *dev)
+{
+ struct das16_private_struct *devpriv = dev->private;
+ int residue;
+ int i;
+ static const int disable_limit = 100;
+ static const int enable_timeout = 100;
+
+ disable_dma(devpriv->dma_chan);
+ residue = get_dma_residue(devpriv->dma_chan);
+ for (i = 0; i < disable_limit && (residue % 2); ++i) {
+ int j;
+ enable_dma(devpriv->dma_chan);
+ for (j = 0; j < enable_timeout; ++j) {
+ int new_residue;
+ udelay(2);
+ new_residue = get_dma_residue(devpriv->dma_chan);
+ if (new_residue != residue)
+ break;
+ }
+ disable_dma(devpriv->dma_chan);
+ residue = get_dma_residue(devpriv->dma_chan);
+ }
+ if (i == disable_limit) {
+ dev_err(dev->class_dev,
+ "failed to get an even dma transfer, could be trouble\n");
+ }
+ return residue;
+}
+
+static void das16_interrupt(struct comedi_device *dev)
+{
+ struct das16_private_struct *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ unsigned long spin_flags;
+ unsigned long dma_flags;
+ int num_bytes, residue;
+ int buffer_index;
+
+ spin_lock_irqsave(&dev->spinlock, spin_flags);
+ if (!(devpriv->ctrl_reg & DAS16_CTRL_DMAE)) {
+ spin_unlock_irqrestore(&dev->spinlock, spin_flags);
+ return;
+ }
+
+ dma_flags = claim_dma_lock();
+ clear_dma_ff(devpriv->dma_chan);
+ residue = disable_dma_on_even(dev);
+
+ /* figure out how many points to read */
+ if (residue > devpriv->dma_transfer_size) {
+ dev_err(dev->class_dev, "residue > transfer size!\n");
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ num_bytes = 0;
+ } else
+ num_bytes = devpriv->dma_transfer_size - residue;
+
+ if (cmd->stop_src == TRIG_COUNT &&
+ num_bytes >= devpriv->adc_byte_count) {
+ num_bytes = devpriv->adc_byte_count;
+ async->events |= COMEDI_CB_EOA;
+ }
+
+ buffer_index = devpriv->current_buffer;
+ devpriv->current_buffer = (devpriv->current_buffer + 1) % 2;
+ devpriv->adc_byte_count -= num_bytes;
+
+ /* re-enable dma */
+ if ((async->events & COMEDI_CB_EOA) == 0) {
+ set_dma_addr(devpriv->dma_chan,
+ devpriv->dma_buffer_addr[devpriv->current_buffer]);
+ set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
+ enable_dma(devpriv->dma_chan);
+ }
+ release_dma_lock(dma_flags);
+
+ spin_unlock_irqrestore(&dev->spinlock, spin_flags);
+
+ cfc_write_array_to_buffer(s,
+ devpriv->dma_buffer[buffer_index], num_bytes);
+
+ cfc_handle_events(dev, s);
+}
+
+static void das16_timer_interrupt(unsigned long arg)
+{
+ struct comedi_device *dev = (struct comedi_device *)arg;
+ struct das16_private_struct *devpriv = dev->private;
+
+ das16_interrupt(dev);
+
+ if (devpriv->timer_running)
+ mod_timer(&devpriv->timer, jiffies + timer_period());
+}
+
static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
@@ -405,15 +614,13 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
mask = TRIG_FOLLOW;
- /* if board supports burst mode */
- if (board->size > 0x400)
+ if (devpriv->can_burst)
mask |= TRIG_TIMER | TRIG_EXT;
err |= cfc_check_trigger_src(&cmd->scan_begin_src, mask);
tmp = cmd->convert_src;
mask = TRIG_TIMER | TRIG_EXT;
- /* if board supports burst mode */
- if (board->size > 0x400)
+ if (devpriv->can_burst)
mask |= TRIG_NOW;
err |= cfc_check_trigger_src(&cmd->convert_src, mask);
@@ -469,9 +676,9 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned int tmp = cmd->scan_begin_arg;
/* set divisors, correct timing arguments */
i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
- &(devpriv->divisor1),
- &(devpriv->divisor2),
- &(cmd->scan_begin_arg),
+ &devpriv->divisor1,
+ &devpriv->divisor2,
+ &cmd->scan_begin_arg,
cmd->flags & TRIG_ROUND_MASK);
err += (tmp != cmd->scan_begin_arg);
}
@@ -479,9 +686,9 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned int tmp = cmd->convert_arg;
/* set divisors, correct timing arguments */
i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
- &(devpriv->divisor1),
- &(devpriv->divisor2),
- &(cmd->convert_arg),
+ &devpriv->divisor1,
+ &devpriv->divisor2,
+ &cmd->convert_arg,
cmd->flags & TRIG_ROUND_MASK);
err += (tmp != cmd->convert_arg);
}
@@ -495,16 +702,13 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
for (i = 1; i < cmd->chanlist_len; i++) {
if (CR_CHAN(cmd->chanlist[i]) !=
(start_chan + i) % s->n_chan) {
- comedi_error(dev,
- "entries in chanlist must be "
- "consecutive channels, "
- "counting upwards\n");
+ dev_err(dev->class_dev,
+ "entries in chanlist must be consecutive channels, counting upwards\n");
err++;
}
if (CR_RANGE(cmd->chanlist[i]) != gain) {
- comedi_error(dev,
- "entries in chanlist must all "
- "have the same gain\n");
+ dev_err(dev->class_dev,
+ "entries in chanlist must all have the same gain\n");
err++;
}
}
@@ -515,61 +719,21 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
-/* utility function that suggests a dma transfer size in bytes */
-static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
- const struct comedi_cmd *cmd)
-{
- struct das16_private_struct *devpriv = dev->private;
- unsigned int size;
- unsigned int freq;
-
- /* if we are using timer interrupt, we don't care how long it
- * will take to complete transfer since it will be interrupted
- * by timer interrupt */
- if (devpriv->timer_mode)
- return DAS16_DMA_SIZE;
-
- /* otherwise, we are relying on dma terminal count interrupt,
- * so pick a reasonable size */
- if (cmd->convert_src == TRIG_TIMER)
- freq = 1000000000 / cmd->convert_arg;
- else if (cmd->scan_begin_src == TRIG_TIMER)
- freq = (1000000000 / cmd->scan_begin_arg) * cmd->chanlist_len;
- /* return some default value */
- else
- freq = 0xffffffff;
-
- if (cmd->flags & TRIG_WAKE_EOS) {
- size = sample_size * cmd->chanlist_len;
- } else {
- /* make buffer fill in no more than 1/3 second */
- size = (freq / 3) * sample_size;
- }
-
- /* set a minimum and maximum size allowed */
- if (size > DAS16_DMA_SIZE)
- size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size;
- else if (size < sample_size)
- size = sample_size;
-
- if (cmd->stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
- size = devpriv->adc_byte_count;
-
- return size;
-}
-
static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
int rounding_flags)
{
struct das16_private_struct *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + DAS16_TIMER_BASE_REG;
- i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1),
- &(devpriv->divisor2), &ns,
+ i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
+ &devpriv->divisor1,
+ &devpriv->divisor2,
+ &ns,
rounding_flags & TRIG_ROUND_MASK);
/* Write the values of ctr1 and ctr2 into counters 1 and 2 */
- i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2);
- i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2);
+ i8254_load(timer_base, 0, 1, devpriv->divisor1, 2);
+ i8254_load(timer_base, 0, 2, devpriv->divisor2, 2);
return ns;
}
@@ -584,30 +748,22 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
unsigned long flags;
int range;
- if (devpriv->dma_chan == 0 || (dev->irq == 0
- && devpriv->timer_mode == 0)) {
- comedi_error(dev,
- "irq (or use of 'timer mode') dma required to "
- "execute comedi_cmd");
- return -1;
- }
if (cmd->flags & TRIG_RT) {
- comedi_error(dev, "isa dma transfers cannot be performed with "
- "TRIG_RT, aborting");
+ dev_err(dev->class_dev,
+ "isa dma transfers cannot be performed with TRIG_RT, aborting\n");
return -1;
}
devpriv->adc_byte_count =
cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t);
- /* disable conversions for das1600 mode */
- if (board->size > 0x400)
- outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV);
+ if (devpriv->can_burst)
+ outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG);
/* set scan limits */
byte = CR_CHAN(cmd->chanlist[0]);
byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4;
- outb(byte, dev->iobase + DAS16_MUX);
+ outb(byte, dev->iobase + DAS16_MUX_REG);
/* set gain (this is also burst rate register but according to
* computer boards manual, burst rate does nothing, even on
@@ -615,28 +771,27 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
if (board->ai_pg != das16_pg_none) {
range = CR_RANGE(cmd->chanlist[0]);
outb((das16_gainlists[board->ai_pg])[range],
- dev->iobase + DAS16_GAIN);
+ dev->iobase + DAS16_GAIN_REG);
}
/* set counter mode and counts */
cmd->convert_arg =
das16_set_pacer(dev, cmd->convert_arg,
cmd->flags & TRIG_ROUND_MASK);
- DEBUG_PRINT("pacer period: %d ns\n", cmd->convert_arg);
/* enable counters */
byte = 0;
- /* Enable burst mode if appropriate. */
- if (board->size > 0x400) {
+ if (devpriv->can_burst) {
if (cmd->convert_src == TRIG_NOW) {
- outb(DAS1600_BURST_VAL, dev->iobase + DAS1600_BURST);
+ outb(DAS1600_BURST_VAL,
+ dev->iobase + DAS1600_BURST_REG);
/* set burst length */
- byte |= BURST_LEN_BITS(cmd->chanlist_len - 1);
+ byte |= DAS16_PACER_BURST_LEN(cmd->chanlist_len - 1);
} else {
- outb(0, dev->iobase + DAS1600_BURST);
+ outb(0, dev->iobase + DAS1600_BURST_REG);
}
}
- outb(byte, dev->iobase + DAS16_PACER);
+ outb(byte, dev->iobase + DAS16_PACER_REG);
/* set up dma transfer */
flags = claim_dma_lock();
@@ -647,465 +802,220 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->current_buffer = 0;
set_dma_addr(devpriv->dma_chan,
devpriv->dma_buffer_addr[devpriv->current_buffer]);
- /* set appropriate size of transfer */
- devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, cmd);
+ devpriv->dma_transfer_size = DAS16_DMA_SIZE;
set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
enable_dma(devpriv->dma_chan);
release_dma_lock(flags);
/* set up interrupt */
- if (devpriv->timer_mode) {
- devpriv->timer_running = 1;
- devpriv->timer.expires = jiffies + timer_period();
- add_timer(&devpriv->timer);
- devpriv->control_state &= ~DAS16_INTE;
- } else {
- /* clear interrupt bit */
- outb(0x00, dev->iobase + DAS16_STATUS);
- /* enable interrupts */
- devpriv->control_state |= DAS16_INTE;
- }
- devpriv->control_state |= DMA_ENABLE;
- devpriv->control_state &= ~PACING_MASK;
- if (cmd->convert_src == TRIG_EXT)
- devpriv->control_state |= EXT_PACER;
- else
- devpriv->control_state |= INT_PACER;
- outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
+ devpriv->timer_running = 1;
+ devpriv->timer.expires = jiffies + timer_period();
+ add_timer(&devpriv->timer);
- /* Enable conversions if using das1600 mode */
- if (board->size > 0x400)
- outb(0, dev->iobase + DAS1600_CONV);
+ das16_ai_enable(dev, DAS16_CTRL_DMAE, cmd->convert_src);
+ if (devpriv->can_burst)
+ outb(0, dev->iobase + DAS1600_CONV_REG);
return 0;
}
static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct das16_board *board = comedi_board(dev);
struct das16_private_struct *devpriv = dev->private;
unsigned long flags;
spin_lock_irqsave(&dev->spinlock, flags);
- /* disable interrupts, dma and pacer clocked conversions */
- devpriv->control_state &= ~DAS16_INTE & ~PACING_MASK & ~DMA_ENABLE;
- outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
- if (devpriv->dma_chan)
- disable_dma(devpriv->dma_chan);
+
+ das16_ai_disable(dev);
+ disable_dma(devpriv->dma_chan);
/* disable SW timer */
- if (devpriv->timer_mode && devpriv->timer_running) {
+ if (devpriv->timer_running) {
devpriv->timer_running = 0;
del_timer(&devpriv->timer);
}
- /* disable burst mode */
- if (board->size > 0x400)
- outb(0, dev->iobase + DAS1600_BURST);
-
+ if (devpriv->can_burst)
+ outb(0, dev->iobase + DAS1600_BURST_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
return 0;
}
-static void das16_reset(struct comedi_device *dev)
+static void das16_ai_munge(struct comedi_device *dev,
+ struct comedi_subdevice *s, void *array,
+ unsigned int num_bytes,
+ unsigned int start_chan_index)
{
- outb(0, dev->iobase + DAS16_STATUS);
- outb(0, dev->iobase + DAS16_CONTROL);
- outb(0, dev->iobase + DAS16_PACER);
- outb(0, dev->iobase + DAS16_CNTR_CONTROL);
+ unsigned int i, num_samples = num_bytes / sizeof(short);
+ short *data = array;
+
+ for (i = 0; i < num_samples; i++) {
+ data[i] = le16_to_cpu(data[i]);
+ if (s->maxdata == 0x0fff)
+ data[i] >>= 4;
+ data[i] &= s->maxdata;
+ }
}
-static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int das16_ai_wait_for_conv(struct comedi_device *dev,
+ unsigned int timeout)
+{
+ unsigned int status;
+ int i;
+
+ for (i = 0; i < timeout; i++) {
+ status = inb(dev->iobase + DAS16_STATUS_REG);
+ if (!(status & DAS16_STATUS_BUSY))
+ return 0;
+ }
+ return -ETIME;
+}
+
+static int das16_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
const struct das16_board *board = comedi_board(dev);
- struct das16_private_struct *devpriv = dev->private;
- int i, n;
- int range;
- int chan;
- int msb, lsb;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val;
+ int ret;
+ int i;
- /* disable interrupts and pacing */
- devpriv->control_state &= ~DAS16_INTE & ~DMA_ENABLE & ~PACING_MASK;
- outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
+ das16_ai_disable(dev);
/* set multiplexer */
- chan = CR_CHAN(insn->chanspec);
- chan |= CR_CHAN(insn->chanspec) << 4;
- outb(chan, dev->iobase + DAS16_MUX);
+ outb(chan | (chan << 4), dev->iobase + DAS16_MUX_REG);
/* set gain */
if (board->ai_pg != das16_pg_none) {
- range = CR_RANGE(insn->chanspec);
outb((das16_gainlists[board->ai_pg])[range],
- dev->iobase + DAS16_GAIN);
+ dev->iobase + DAS16_GAIN_REG);
}
- for (n = 0; n < insn->n; n++) {
+ for (i = 0; i < insn->n; i++) {
/* trigger conversion */
- outb_p(0, dev->iobase + DAS16_TRIG);
-
- for (i = 0; i < DAS16_TIMEOUT; i++) {
- if (!(inb(dev->iobase + DAS16_STATUS) & BUSY))
- break;
- }
- if (i == DAS16_TIMEOUT) {
- printk("das16: timeout\n");
- return -ETIME;
- }
- msb = inb(dev->iobase + DAS16_AI_MSB);
- lsb = inb(dev->iobase + DAS16_AI_LSB);
- if (board->ai_nbits == 12)
- data[n] = ((lsb >> 4) & 0xf) | (msb << 4);
- else
- data[n] = lsb | (msb << 8);
-
- }
-
- return n;
-}
-
-static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- unsigned int bits;
-
- bits = inb(dev->iobase + DAS16_DIO) & 0xf;
- data[1] = bits;
- data[0] = 0;
-
- return insn->n;
-}
+ outb_p(0, dev->iobase + DAS16_TRIG_REG);
-static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- unsigned int wbits;
+ ret = das16_ai_wait_for_conv(dev, 1000);
+ if (ret)
+ return ret;
- /* only set bits that have been masked */
- data[0] &= 0xf;
- wbits = s->state;
- /* zero bits that have been masked */
- wbits &= ~data[0];
- /* set masked bits */
- wbits |= data[0] & data[1];
- s->state = wbits;
- data[1] = wbits;
+ val = inb(dev->iobase + DAS16_AI_MSB_REG) << 8;
+ val |= inb(dev->iobase + DAS16_AI_LSB_REG);
+ if (s->maxdata == 0x0fff)
+ val >>= 4;
+ val &= s->maxdata;
- outb(s->state, dev->iobase + DAS16_DIO);
+ data[i] = val;
+ }
return insn->n;
}
-static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int das16_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- const struct das16_board *board = comedi_board(dev);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
int i;
- int lsb, msb;
- int chan;
-
- chan = CR_CHAN(insn->chanspec);
for (i = 0; i < insn->n; i++) {
- if (board->ao_nbits == 12) {
- lsb = (data[i] << 4) & 0xff;
- msb = (data[i] >> 4) & 0xff;
- } else {
- lsb = data[i] & 0xff;
- msb = (data[i] >> 8) & 0xff;
- }
- outb(lsb, dev->iobase + DAS16_AO_LSB(chan));
- outb(msb, dev->iobase + DAS16_AO_MSB(chan));
- }
-
- return i;
-}
-
-/* the pc104-das16jr (at least) has problems if the dma
- transfer is interrupted in the middle of transferring
- a 16 bit sample, so this function takes care to get
- an even transfer count after disabling dma
- channel.
-*/
-static int disable_dma_on_even(struct comedi_device *dev)
-{
- struct das16_private_struct *devpriv = dev->private;
- int residue;
- int i;
- static const int disable_limit = 100;
- static const int enable_timeout = 100;
+ val = data[i];
+ val <<= 4;
- disable_dma(devpriv->dma_chan);
- residue = get_dma_residue(devpriv->dma_chan);
- for (i = 0; i < disable_limit && (residue % 2); ++i) {
- int j;
- enable_dma(devpriv->dma_chan);
- for (j = 0; j < enable_timeout; ++j) {
- int new_residue;
- udelay(2);
- new_residue = get_dma_residue(devpriv->dma_chan);
- if (new_residue != residue)
- break;
- }
- disable_dma(devpriv->dma_chan);
- residue = get_dma_residue(devpriv->dma_chan);
- }
- if (i == disable_limit) {
- comedi_error(dev, "failed to get an even dma transfer, "
- "could be trouble.");
+ outb(val & 0xff, dev->iobase + DAS16_AO_LSB_REG(chan));
+ outb((val >> 8) & 0xff, dev->iobase + DAS16_AO_MSB_REG(chan));
}
- return residue;
+
+ return insn->n;
}
-static void das16_interrupt(struct comedi_device *dev)
+static int das16_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- const struct das16_board *board = comedi_board(dev);
- struct das16_private_struct *devpriv = dev->private;
- unsigned long dma_flags, spin_flags;
- struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async;
- struct comedi_cmd *cmd;
- int num_bytes, residue;
- int buffer_index;
-
- if (!dev->attached) {
- comedi_error(dev, "premature interrupt");
- return;
- }
- /* initialize async here to make sure it is not NULL */
- async = s->async;
- cmd = &async->cmd;
-
- if (devpriv->dma_chan == 0) {
- comedi_error(dev, "interrupt with no dma channel?");
- return;
- }
-
- spin_lock_irqsave(&dev->spinlock, spin_flags);
- if ((devpriv->control_state & DMA_ENABLE) == 0) {
- spin_unlock_irqrestore(&dev->spinlock, spin_flags);
- DEBUG_PRINT("interrupt while dma disabled?\n");
- return;
- }
-
- dma_flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma_chan);
- residue = disable_dma_on_even(dev);
-
- /* figure out how many points to read */
- if (residue > devpriv->dma_transfer_size) {
- comedi_error(dev, "residue > transfer size!\n");
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- num_bytes = 0;
- } else
- num_bytes = devpriv->dma_transfer_size - residue;
+ data[1] = inb(dev->iobase + DAS16_DIO_REG) & 0xf;
- if (cmd->stop_src == TRIG_COUNT &&
- num_bytes >= devpriv->adc_byte_count) {
- num_bytes = devpriv->adc_byte_count;
- async->events |= COMEDI_CB_EOA;
- }
-
- buffer_index = devpriv->current_buffer;
- devpriv->current_buffer = (devpriv->current_buffer + 1) % 2;
- devpriv->adc_byte_count -= num_bytes;
-
- /* figure out how many bytes for next transfer */
- if (cmd->stop_src == TRIG_COUNT && devpriv->timer_mode == 0 &&
- devpriv->dma_transfer_size > devpriv->adc_byte_count)
- devpriv->dma_transfer_size = devpriv->adc_byte_count;
-
- /* re-enable dma */
- if ((async->events & COMEDI_CB_EOA) == 0) {
- set_dma_addr(devpriv->dma_chan,
- devpriv->dma_buffer_addr[devpriv->current_buffer]);
- set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
- enable_dma(devpriv->dma_chan);
- /* reenable conversions for das1600 mode, (stupid hardware) */
- if (board->size > 0x400 && devpriv->timer_mode == 0)
- outb(0x00, dev->iobase + DAS1600_CONV);
-
- }
- release_dma_lock(dma_flags);
-
- spin_unlock_irqrestore(&dev->spinlock, spin_flags);
-
- cfc_write_array_to_buffer(s,
- devpriv->dma_buffer[buffer_index], num_bytes);
-
- cfc_handle_events(dev, s);
+ return insn->n;
}
-static irqreturn_t das16_dma_interrupt(int irq, void *d)
+static int das16_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int status;
- struct comedi_device *dev = d;
+ unsigned int mask = data[0];
+ unsigned int bits = data[1];
- status = inb(dev->iobase + DAS16_STATUS);
+ if (mask) {
+ s->state &= ~mask;
+ s->state |= (bits & mask);
- if ((status & DAS16_INT) == 0) {
- DEBUG_PRINT("spurious interrupt\n");
- return IRQ_NONE;
+ outb(s->state, dev->iobase + DAS16_DIO_REG);
}
- /* clear interrupt */
- outb(0x00, dev->iobase + DAS16_STATUS);
- das16_interrupt(dev);
- return IRQ_HANDLED;
-}
-
-static void das16_timer_interrupt(unsigned long arg)
-{
- struct comedi_device *dev = (struct comedi_device *)arg;
- struct das16_private_struct *devpriv = dev->private;
-
- das16_interrupt(dev);
-
- if (devpriv->timer_running)
- mod_timer(&devpriv->timer, jiffies + timer_period());
-}
+ data[1] = s->state;
-static void reg_dump(struct comedi_device *dev)
-{
- DEBUG_PRINT("********DAS1600 REGISTER DUMP********\n");
- DEBUG_PRINT("DAS16_MUX: %x\n", inb(dev->iobase + DAS16_MUX));
- DEBUG_PRINT("DAS16_DIO: %x\n", inb(dev->iobase + DAS16_DIO));
- DEBUG_PRINT("DAS16_STATUS: %x\n", inb(dev->iobase + DAS16_STATUS));
- DEBUG_PRINT("DAS16_CONTROL: %x\n", inb(dev->iobase + DAS16_CONTROL));
- DEBUG_PRINT("DAS16_PACER: %x\n", inb(dev->iobase + DAS16_PACER));
- DEBUG_PRINT("DAS16_GAIN: %x\n", inb(dev->iobase + DAS16_GAIN));
- DEBUG_PRINT("DAS16_CNTR_CONTROL: %x\n",
- inb(dev->iobase + DAS16_CNTR_CONTROL));
- DEBUG_PRINT("DAS1600_CONV: %x\n", inb(dev->iobase + DAS1600_CONV));
- DEBUG_PRINT("DAS1600_BURST: %x\n", inb(dev->iobase + DAS1600_BURST));
- DEBUG_PRINT("DAS1600_ENABLE: %x\n", inb(dev->iobase + DAS1600_ENABLE));
- DEBUG_PRINT("DAS1600_STATUS_B: %x\n",
- inb(dev->iobase + DAS1600_STATUS_B));
+ return insn->n;
}
static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct das16_board *board = comedi_board(dev);
- struct das16_private_struct *devpriv = dev->private;
- int status;
int diobits;
- /* status is available on all boards */
-
- status = inb(dev->iobase + DAS16_STATUS);
-
- if ((status & UNIPOLAR))
- devpriv->ai_unipolar = 1;
- else
- devpriv->ai_unipolar = 0;
-
-
- if ((status & DAS16_MUXBIT))
- devpriv->ai_singleended = 1;
- else
- devpriv->ai_singleended = 0;
-
-
/* diobits indicates boards */
-
- diobits = inb(dev->iobase + DAS16_DIO) & 0xf0;
-
- printk(KERN_INFO " id bits are 0x%02x\n", diobits);
+ diobits = inb(dev->iobase + DAS16_DIO_REG) & 0xf0;
if (board->id != diobits) {
- printk(KERN_INFO " requested board's id bits are 0x%x (ignore)\n",
- board->id);
- }
-
- return 0;
-}
-
-static int das1600_mode_detect(struct comedi_device *dev)
-{
- struct das16_private_struct *devpriv = dev->private;
- int status = 0;
-
- status = inb(dev->iobase + DAS1600_STATUS_B);
-
- if (status & DAS1600_CLK_10MHZ) {
- devpriv->clockbase = 100;
- printk(KERN_INFO " 10MHz pacer clock\n");
- } else {
- devpriv->clockbase = 1000;
- printk(KERN_INFO " 1MHz pacer clock\n");
+ dev_err(dev->class_dev,
+ "requested board's id bits are incorrect (0x%x != 0x%x)\n",
+ board->id, diobits);
+ return -EINVAL;
}
- reg_dump(dev);
-
return 0;
}
-static void das16_ai_munge(struct comedi_device *dev,
- struct comedi_subdevice *s, void *array,
- unsigned int num_bytes,
- unsigned int start_chan_index)
+static void das16_reset(struct comedi_device *dev)
{
- const struct das16_board *board = comedi_board(dev);
- unsigned int i, num_samples = num_bytes / sizeof(short);
- short *data = array;
-
- for (i = 0; i < num_samples; i++) {
- data[i] = le16_to_cpu(data[i]);
- if (board->ai_nbits == 12)
- data[i] = (data[i] >> 4) & 0xfff;
-
- }
+ outb(0, dev->iobase + DAS16_STATUS_REG);
+ outb(0, dev->iobase + DAS16_CTRL_REG);
+ outb(0, dev->iobase + DAS16_PACER_REG);
+ outb(0, dev->iobase + DAS16_TIMER_BASE_REG + i8254_control_reg);
}
-/*
- *
- * Options list:
- * 0 I/O base
- * 1 IRQ
- * 2 DMA
- * 3 Clock speed (in MHz)
- */
static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct das16_board *board = comedi_board(dev);
struct das16_private_struct *devpriv;
struct comedi_subdevice *s;
+ struct comedi_lrange *lrange;
+ struct comedi_krange *krange;
+ unsigned int dma_chan = it->options[2];
+ unsigned int status;
int ret;
- unsigned int irq;
- unsigned int dma_chan;
- int timer_mode;
- unsigned long flags;
- struct comedi_krange *user_ai_range, *user_ao_range;
-
-#if 0
- irq = it->options[1];
- timer_mode = it->options[8];
-#endif
- /* always use time_mode since using irq can drop samples while
- * waiting for dma done interrupt (due to hardware limitations) */
- irq = 0;
- timer_mode = 1;
- if (timer_mode)
- irq = 0;
/* check that clock setting is valid */
if (it->options[3]) {
if (it->options[3] != 0 &&
it->options[3] != 1 && it->options[3] != 10) {
- printk
- ("\n Invalid option. Master clock must be set "
- "to 1 or 10 (MHz)\n");
+ dev_err(dev->class_dev,
+ "Invalid option. Master clock must be set to 1 or 10 (MHz)\n");
return -EINVAL;
}
}
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
if (board->size < 0x400) {
ret = comedi_request_region(dev, it->options[0], board->size);
@@ -1121,207 +1031,183 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
devpriv->extra_iobase = dev->iobase + 0x400;
+ devpriv->can_burst = 1;
}
/* probe id bits to make sure they are consistent */
- if (das16_probe(dev, it)) {
- printk(KERN_ERR " id bits do not match selected board, aborting\n");
+ if (das16_probe(dev, it))
return -EINVAL;
- }
/* get master clock speed */
- if (board->size < 0x400) {
+ if (devpriv->can_burst) {
+ status = inb(dev->iobase + DAS1600_STATUS_REG);
+
+ if (status & DAS1600_STATUS_CLK_10MHZ)
+ devpriv->clockbase = 100;
+ else
+ devpriv->clockbase = 1000;
+ } else {
if (it->options[3])
devpriv->clockbase = 1000 / it->options[3];
else
devpriv->clockbase = 1000; /* 1 MHz default */
- } else {
- das1600_mode_detect(dev);
- }
-
- /* now for the irq */
- if (irq > 1 && irq < 8) {
- ret = request_irq(irq, das16_dma_interrupt, 0,
- dev->board_name, dev);
-
- if (ret < 0)
- return ret;
- dev->irq = irq;
- printk(KERN_INFO " ( irq = %u )", irq);
- } else if (irq == 0) {
- printk(" ( no irq )");
- } else {
- printk(" invalid irq\n");
- return -EINVAL;
}
- /* initialize dma */
- dma_chan = it->options[2];
+ /* initialize dma */
if (dma_chan == 1 || dma_chan == 3) {
- /* allocate dma buffers */
+ unsigned long flags;
int i;
- for (i = 0; i < 2; i++) {
- devpriv->dma_buffer[i] = pci_alloc_consistent(
- NULL, DAS16_DMA_SIZE,
- &devpriv->dma_buffer_addr[i]);
- if (devpriv->dma_buffer[i] == NULL)
- return -ENOMEM;
- }
if (request_dma(dma_chan, dev->board_name)) {
- printk(KERN_ERR " failed to allocate dma channel %i\n",
- dma_chan);
+ dev_err(dev->class_dev,
+ "failed to request dma channel %i\n",
+ dma_chan);
return -EINVAL;
}
devpriv->dma_chan = dma_chan;
+
+ /* allocate dma buffers */
+ for (i = 0; i < 2; i++) {
+ void *p;
+
+ p = pci_alloc_consistent(NULL, DAS16_DMA_SIZE,
+ &devpriv->dma_buffer_addr[i]);
+ if (!p)
+ return -ENOMEM;
+ devpriv->dma_buffer[i] = p;
+ }
+
flags = claim_dma_lock();
disable_dma(devpriv->dma_chan);
set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
release_dma_lock(flags);
- printk(KERN_INFO " ( dma = %u)\n", dma_chan);
- } else if (dma_chan == 0) {
- printk(KERN_INFO " ( no dma )\n");
- } else {
- printk(KERN_ERR " invalid dma channel\n");
- return -EINVAL;
+
+ init_timer(&devpriv->timer);
+ devpriv->timer.function = das16_timer_interrupt;
+ devpriv->timer.data = (unsigned long)dev;
}
- /* get any user-defined input range */
+ /* get any user-defined input range */
if (board->ai_pg == das16_pg_none &&
(it->options[4] || it->options[5])) {
- /* allocate single-range range table */
- devpriv->user_ai_range_table =
- kmalloc(sizeof(struct comedi_lrange) +
- sizeof(struct comedi_krange), GFP_KERNEL);
- /* initialize ai range */
- devpriv->user_ai_range_table->length = 1;
- user_ai_range = devpriv->user_ai_range_table->range;
- user_ai_range->min = it->options[4];
- user_ai_range->max = it->options[5];
- user_ai_range->flags = UNIT_volt;
- }
- /* get any user-defined output range */
- if (it->options[6] || it->options[7]) {
- /* allocate single-range range table */
- devpriv->user_ao_range_table =
- kmalloc(sizeof(struct comedi_lrange) +
- sizeof(struct comedi_krange), GFP_KERNEL);
- /* initialize ao range */
- devpriv->user_ao_range_table->length = 1;
- user_ao_range = devpriv->user_ao_range_table->range;
- user_ao_range->min = it->options[6];
- user_ao_range->max = it->options[7];
- user_ao_range->flags = UNIT_volt;
+ /* allocate single-range range table */
+ lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL);
+ if (!lrange)
+ return -ENOMEM;
+
+ /* initialize ai range */
+ devpriv->user_ai_range_table = lrange;
+ lrange->length = 1;
+ krange = devpriv->user_ai_range_table->range;
+ krange->min = it->options[4];
+ krange->max = it->options[5];
+ krange->flags = UNIT_volt;
}
- if (timer_mode) {
- init_timer(&(devpriv->timer));
- devpriv->timer.function = das16_timer_interrupt;
- devpriv->timer.data = (unsigned long)dev;
+ /* get any user-defined output range */
+ if (it->options[6] || it->options[7]) {
+ /* allocate single-range range table */
+ lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL);
+ if (!lrange)
+ return -ENOMEM;
+
+ /* initialize ao range */
+ devpriv->user_ao_range_table = lrange;
+ lrange->length = 1;
+ krange = devpriv->user_ao_range_table->range;
+ krange->min = it->options[6];
+ krange->max = it->options[7];
+ krange->flags = UNIT_volt;
}
- devpriv->timer_mode = timer_mode ? 1 : 0;
- ret = comedi_alloc_subdevices(dev, 5);
+ ret = comedi_alloc_subdevices(dev, 4 + board->has_8255);
if (ret)
return ret;
+ status = inb(dev->iobase + DAS16_STATUS_REG);
+
+ /* Analog Input subdevice */
s = &dev->subdevices[0];
- dev->read_subdev = s;
- /* ai */
- if (board->ai) {
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
- if (devpriv->ai_singleended) {
- s->n_chan = 16;
- s->len_chanlist = 16;
- s->subdev_flags |= SDF_GROUND;
- } else {
- s->n_chan = 8;
- s->len_chanlist = 8;
- s->subdev_flags |= SDF_DIFF;
- }
- s->maxdata = (1 << board->ai_nbits) - 1;
- if (devpriv->user_ai_range_table) { /* user defined ai range */
- s->range_table = devpriv->user_ai_range_table;
- } else if (devpriv->ai_unipolar) {
- s->range_table = das16_ai_uni_lranges[board->ai_pg];
- } else {
- s->range_table = das16_ai_bip_lranges[board->ai_pg];
- }
- s->insn_read = board->ai;
- s->do_cmdtest = das16_cmd_test;
- s->do_cmd = das16_cmd_exec;
- s->cancel = das16_cancel;
- s->munge = das16_ai_munge;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE;
+ if (status & DAS16_STATUS_MUXBIT) {
+ s->subdev_flags |= SDF_GROUND;
+ s->n_chan = 16;
} else {
- s->type = COMEDI_SUBD_UNUSED;
+ s->subdev_flags |= SDF_DIFF;
+ s->n_chan = 8;
}
-
- s = &dev->subdevices[1];
- /* ao */
- if (board->ao) {
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 2;
- s->maxdata = (1 << board->ao_nbits) - 1;
- /* user defined ao range */
- if (devpriv->user_ao_range_table)
- s->range_table = devpriv->user_ao_range_table;
- else
- s->range_table = &range_unknown;
-
- s->insn_write = board->ao;
+ s->len_chanlist = s->n_chan;
+ s->maxdata = board->ai_maxdata;
+ if (devpriv->user_ai_range_table) { /* user defined ai range */
+ s->range_table = devpriv->user_ai_range_table;
+ } else if (status & DAS16_STATUS_UNIPOLAR) {
+ s->range_table = das16_ai_uni_lranges[board->ai_pg];
} else {
- s->type = COMEDI_SUBD_UNUSED;
+ s->range_table = das16_ai_bip_lranges[board->ai_pg];
}
-
- s = &dev->subdevices[2];
- /* di */
- if (board->di) {
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = 4;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = board->di;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
+ s->insn_read = das16_ai_insn_read;
+ if (devpriv->dma_chan) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->do_cmdtest = das16_cmd_test;
+ s->do_cmd = das16_cmd_exec;
+ s->cancel = das16_cancel;
+ s->munge = das16_ai_munge;
}
- s = &dev->subdevices[3];
- /* do */
- if (board->do_) {
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
- s->n_chan = 4;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = board->do_;
- /* initialize digital output lines */
- outb(s->state, dev->iobase + DAS16_DIO);
+ /* Analog Output subdevice */
+ s = &dev->subdevices[1];
+ if (board->has_ao) {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 2;
+ s->maxdata = 0x0fff;
+ s->range_table = devpriv->user_ao_range_table;
+ s->insn_write = das16_ao_insn_write;
} else {
- s->type = COMEDI_SUBD_UNUSED;
+ s->type = COMEDI_SUBD_UNUSED;
}
- s = &dev->subdevices[4];
- /* 8255 */
- if (board->i8255_offset != 0) {
- subdev_8255_init(dev, s, NULL, (dev->iobase +
- board->i8255_offset));
- } else {
- s->type = COMEDI_SUBD_UNUSED;
+ /* Digital Input subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = das16_di_insn_bits;
+
+ /* Digital Output subdevice */
+ s = &dev->subdevices[3];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = das16_do_insn_bits;
+
+ /* initialize digital output lines */
+ outb(s->state, dev->iobase + DAS16_DIO_REG);
+
+ /* 8255 Digital I/O subdevice */
+ if (board->has_8255) {
+ s = &dev->subdevices[4];
+ ret = subdev_8255_init(dev, s, NULL,
+ dev->iobase + board->i8255_offset);
+ if (ret)
+ return ret;
}
das16_reset(dev);
/* set the interrupt level */
- devpriv->control_state = DAS16_IRQ(dev->irq);
- outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
-
- /* turn on das1600 mode if available */
- if (board->size > 0x400) {
- outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE);
- outb(0, dev->iobase + DAS1600_CONV);
- outb(0, dev->iobase + DAS1600_BURST);
+ devpriv->ctrl_reg = DAS16_CTRL_IRQ(dev->irq);
+ outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
+
+ if (devpriv->can_burst) {
+ outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE_REG);
+ outb(0, dev->iobase + DAS1600_CONV_REG);
+ outb(0, dev->iobase + DAS1600_BURST_REG);
}
return 0;
@@ -1331,10 +1217,12 @@ static void das16_detach(struct comedi_device *dev)
{
const struct das16_board *board = comedi_board(dev);
struct das16_private_struct *devpriv = dev->private;
+ int i;
- das16_reset(dev);
if (devpriv) {
- int i;
+ if (dev->iobase)
+ das16_reset(dev);
+
for (i = 0; i < 2; i++) {
if (devpriv->dma_buffer[i])
pci_free_consistent(NULL, DAS16_DMA_SIZE,
@@ -1346,312 +1234,15 @@ static void das16_detach(struct comedi_device *dev)
free_dma(devpriv->dma_chan);
kfree(devpriv->user_ai_range_table);
kfree(devpriv->user_ao_range_table);
+
+ if (devpriv->extra_iobase)
+ release_region(devpriv->extra_iobase,
+ board->size & 0x3ff);
}
- if (devpriv->extra_iobase)
- release_region(devpriv->extra_iobase, board->size & 0x3ff);
+
comedi_legacy_detach(dev);
}
-static const struct das16_board das16_boards[] = {
- {
- .name = "das-16",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 15000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x00,
- }, {
- .name = "das-16g",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 15000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x00,
- }, {
- .name = "das-16f",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 8500,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x00,
- }, {
- .name = "cio-das16",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 20000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x80,
- }, {
- .name = "cio-das16/f",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x80,
- }, {
- .name = "cio-das16/jr",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 7692,
- .ai_pg = das16_pg_16jr,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- }, {
- .name = "pc104-das16jr",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 3300,
- .ai_pg = das16_pg_16jr,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- }, {
- .name = "cio-das16jr/16",
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_16jr_16,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- }, {
- .name = "pc104-das16jr/16",
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_16jr_16,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- }, {
- .name = "das-1201",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 20000,
- .ai_pg = das16_pg_none,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0x20,
- }, {
- .name = "das-1202",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_none,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0x20,
- }, {
- .name = "das-1401",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1601,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0,
- }, {
- .name = "das-1402",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0,
- }, {
- .name = "das-1601",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1601,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0,
- }, {
- .name = "das-1602",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0,
- }, {
- .name = "cio-das1401/12",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 6250,
- .ai_pg = das16_pg_1601,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0,
- }, {
- .name = "cio-das1402/12",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 6250,
- .ai_pg = das16_pg_1602,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0,
- }, {
- .name = "cio-das1402/16",
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0,
- }, {
- .name = "cio-das1601/12",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 6250,
- .ai_pg = das16_pg_1601,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0,
- }, {
- .name = "cio-das1602/12",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0,
- }, {
- .name = "cio-das1602/16",
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0,
- }, {
- .name = "cio-das16/330",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 3030,
- .ai_pg = das16_pg_16jr,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0xf0,
- },
-};
-
static struct comedi_driver das16_driver = {
.driver_name = "das16",
.module = THIS_MODULE,
@@ -1664,5 +1255,5 @@ static struct comedi_driver das16_driver = {
module_comedi_driver(das16_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for DAS16 compatible boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index 0b33808c3a7..b943c449b69 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -52,7 +52,7 @@ Options:
irq can be omitted, although the cmd interface will not work without it.
*/
-#include <linux/ioport.h>
+#include <linux/module.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
@@ -567,10 +567,9 @@ static int das16m1_attach(struct comedi_device *dev,
int ret;
unsigned int irq;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_request_region(dev, it->options[0], DAS16M1_SIZE);
if (ret)
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 23b4a661eb1..5b300294d32 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -94,12 +94,12 @@ TODO:
read insn for analog out
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/io.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include <asm/dma.h>
#include "8253.h"
@@ -1511,10 +1511,9 @@ static int das1800_attach(struct comedi_device *dev,
int board;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_request_region(dev, it->options[0], DAS1800_SIZE);
if (ret)
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index f0530778bb3..fb25cb84703 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -33,11 +33,10 @@ Devices: [Keithley Metrabyte] DAS6402 (das6402)
This driver has suffered bitrot.
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
#define DAS6402_SIZE 16
#define N_WORDS (3000*64)
@@ -294,10 +293,9 @@ static int das6402_attach(struct comedi_device *dev,
dev->irq = irq;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index 091cd911b38..11e16114e4e 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -56,10 +56,10 @@ cmd triggers supported:
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include <linux/delay.h>
#include "8253.h"
@@ -700,10 +700,9 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int board;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_request_region(dev, it->options[0], DAS800_SIZE);
if (ret)
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index e29847d73b4..118a4fd129f 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -32,9 +32,10 @@ Configuration Options:
comedi_config /dev/comedi0 dmm32at baseaddr,irq
*/
+#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include "comedi_fc.h"
@@ -647,31 +648,34 @@ static int dmm32at_dio_insn_bits(struct comedi_device *dev,
static int dmm32at_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct dmm32at_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
unsigned char chanbit;
- int chan = CR_CHAN(insn->chanspec);
-
- if (insn->n != 1)
- return -EINVAL;
+ int ret;
- if (chan < 8)
+ if (chan < 8) {
+ mask = 0x0000ff;
chanbit = DMM32AT_DIRA;
- else if (chan < 16)
+ } else if (chan < 16) {
+ mask = 0x00ff00;
chanbit = DMM32AT_DIRB;
- else if (chan < 20)
+ } else if (chan < 20) {
+ mask = 0x0f0000;
chanbit = DMM32AT_DIRCL;
- else
+ } else {
+ mask = 0xf00000;
chanbit = DMM32AT_DIRCH;
+ }
- /* The input or output configuration of each digital line is
- * configured by a special insn_config instruction. chanspec
- * contains the channel to be changed, and data[0] contains the
- * value COMEDI_INPUT or COMEDI_OUTPUT. */
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
- /* if output clear the bit, otherwise set it */
- if (data[0] == COMEDI_OUTPUT)
+ if (data[0] == INSN_CONFIG_DIO_OUTPUT)
devpriv->dio_config &= ~chanbit;
else
devpriv->dio_config |= chanbit;
@@ -680,7 +684,7 @@ static int dmm32at_dio_insn_config(struct comedi_device *dev,
/* set the DIO's to the new configuration setting */
outb(devpriv->dio_config, dev->iobase + DMM32AT_DIOCONF);
- return 1;
+ return insn->n;
}
static int dmm32at_attach(struct comedi_device *dev,
@@ -753,10 +757,9 @@ static int dmm32at_attach(struct comedi_device *dev,
dev->irq = irq;
}
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_alloc_subdevices(dev, 3);
if (ret)
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index 8f5006d70da..38918a1198a 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -29,9 +29,9 @@ Configuration options:
[5] - D/A 1 range (same choices)
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include <linux/delay.h>
-#include <linux/ioport.h>
#define DT2801_TIMEOUT 1000
@@ -551,32 +551,19 @@ static int dt2801_dio_insn_bits(struct comedi_device *dev,
static int dt2801_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int which = 0;
+ int ret;
- if (s == &dev->subdevices[3])
- which = 1;
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0xff);
+ if (ret)
+ return ret;
- /* configure */
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits = 0xff;
- dt2801_writecmd(dev, DT_C_SET_DIGOUT);
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits = 0;
- dt2801_writecmd(dev, DT_C_SET_DIGIN);
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- default:
- return -EINVAL;
- }
- dt2801_writedata(dev, which);
+ dt2801_writecmd(dev, s->io_bits ? DT_C_SET_DIGOUT : DT_C_SET_DIGIN);
+ dt2801_writedata(dev, (s == &dev->subdevices[3]) ? 1 : 0);
- return 1;
+ return insn->n;
}
/*
@@ -627,10 +614,9 @@ havetype:
if (ret)
goto out;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
dev->board_name = board->name;
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index 5348cdae408..a41a5716f35 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -41,11 +41,10 @@ Configuration options:
[4] - D/A 1 range (same choices)
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = {
4, {
RANGE(0, 5),
@@ -450,10 +449,9 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
switch (it->options[2]) {
case 0:
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index 87e9749c4be..6514b9e0055 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -34,10 +34,10 @@ a power of 10, from 1 to 10^7, of which only 3 or 4 are useful. In
addition, the clock does not seem to be very accurate.
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include <linux/delay.h>
#include "comedi_fc.h"
@@ -298,10 +298,9 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
s = &dev->subdevices[0];
dev->read_subdev = s;
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index 0fcd4fe7acd..34040f0175e 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -51,9 +51,9 @@ Configuration options:
[12] - Analog output 7 range configuration (same options)
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include <linux/delay.h>
#define DT2815_SIZE 2
@@ -165,10 +165,9 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
s = &dev->subdevices[0];
/* ao subdevice */
diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c
index 2f46be715f7..f4a8529239b 100644
--- a/drivers/staging/comedi/drivers/dt2817.c
+++ b/drivers/staging/comedi/drivers/dt2817.c
@@ -33,10 +33,9 @@ Configuration options:
[0] - I/O port base base address
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
#define DT2817_SIZE 5
#define DT2817_CR 0
@@ -44,28 +43,26 @@ Configuration options:
static int dt2817_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int mask;
- int chan;
- int oe = 0;
-
- if (insn->n != 1)
- return -EINVAL;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int oe = 0;
+ unsigned int mask;
+ int ret;
- chan = CR_CHAN(insn->chanspec);
if (chan < 8)
- mask = 0xff;
+ mask = 0x000000ff;
else if (chan < 16)
- mask = 0xff00;
+ mask = 0x0000ff00;
else if (chan < 24)
- mask = 0xff0000;
+ mask = 0x00ff0000;
else
mask = 0xff000000;
- if (data[0])
- s->io_bits |= mask;
- else
- s->io_bits &= ~mask;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
if (s->io_bits & 0x000000ff)
oe |= 0x1;
@@ -78,7 +75,7 @@ static int dt2817_dio_insn_config(struct comedi_device *dev,
outb(oe, dev->iobase + DT2817_CR);
- return 1;
+ return insn->n;
}
static int dt2817_dio_insn_bits(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index c1950e3b19a..da3ee859bdb 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -51,13 +51,16 @@ Notes:
be fixed to check for this situation and return an error.
*/
+#include <linux/module.h>
#include "../comedidev.h"
+#include <linux/delay.h>
#include <linux/gfp.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+
#include <asm/dma.h>
+
#include "comedi_fc.h"
#define DEBUG
@@ -264,8 +267,9 @@ struct dt282x_private {
} \
udelay(5); \
} \
- if (_i) \
+ if (_i) { \
b \
+ } \
} while (0)
static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
@@ -978,29 +982,32 @@ static int dt282x_dio_insn_bits(struct comedi_device *dev,
static int dt282x_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct dt282x_private *devpriv = dev->private;
- int mask;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
+ int ret;
- mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
- if (data[0])
- s->io_bits |= mask;
+ if (chan < 8)
+ mask = 0x00ff;
else
- s->io_bits &= ~mask;
+ mask = 0xff00;
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
+
+ devpriv->dacsr &= ~(DT2821_LBOE | DT2821_HBOE);
if (s->io_bits & 0x00ff)
devpriv->dacsr |= DT2821_LBOE;
- else
- devpriv->dacsr &= ~DT2821_LBOE;
if (s->io_bits & 0xff00)
devpriv->dacsr |= DT2821_HBOE;
- else
- devpriv->dacsr &= ~DT2821_HBOE;
outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
- return 1;
+ return insn->n;
}
static const struct comedi_lrange *const ai_range_table[] = {
@@ -1188,10 +1195,9 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#endif
}
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = dt282x_grab_dma(dev, it->options[opt_dma1],
it->options[opt_dma2]);
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 01a2f889d5b..64ef87598b6 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -50,6 +50,7 @@ AO commands are not supported.
#define DEBUG 1
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -641,32 +642,23 @@ static void dt3k_dio_config(struct comedi_device *dev, int bits)
static int dt3k_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int mask;
-
- mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
-
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= mask;
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~mask;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->
- io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
- COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- break;
- }
- mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
- dt3k_dio_config(dev, mask);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
+ int ret;
+
+ if (chan < 4)
+ mask = 0x0f;
+ else
+ mask = 0xf0;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
+
+ dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
return insn->n;
}
@@ -722,10 +714,9 @@ static int dt3000_auto_attach(struct comedi_device *dev,
dev->board_ptr = this_board;
dev->board_name = this_board->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret < 0)
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 6c60949d919..b5e6f33dc21 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -39,10 +39,9 @@ for my needs.
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
@@ -188,8 +187,8 @@ enum {
};
struct dt9812_flash_data {
- u16 numbytes;
- u16 address;
+ __le16 numbytes;
+ __le16 address;
};
#define DT9812_MAX_NUM_MULTI_BYTE_RDS \
@@ -230,7 +229,7 @@ struct dt9812_rmw_multi {
};
struct dt9812_usb_cmd {
- u32 cmd;
+ __le32 cmd;
union {
struct dt9812_flash_data flash_data_info;
struct dt9812_read_multi read_multi_info;
@@ -707,8 +706,9 @@ static int dt9812_reset_device(struct comedi_device *dev)
u32 serial;
u16 vendor;
u16 product;
- u16 tmp16;
u8 tmp8;
+ __le16 tmp16;
+ __le32 tmp32;
int ret;
int i;
@@ -731,19 +731,19 @@ static int dt9812_reset_device(struct comedi_device *dev)
}
}
- ret = dt9812_read_info(dev, 1, &vendor, sizeof(vendor));
+ ret = dt9812_read_info(dev, 1, &tmp16, sizeof(tmp16));
if (ret) {
dev_err(dev->class_dev, "failed to read vendor id\n");
return ret;
}
- vendor = le16_to_cpu(vendor);
+ vendor = le16_to_cpu(tmp16);
- ret = dt9812_read_info(dev, 3, &product, sizeof(product));
+ ret = dt9812_read_info(dev, 3, &tmp16, sizeof(tmp16));
if (ret) {
dev_err(dev->class_dev, "failed to read product id\n");
return ret;
}
- product = le16_to_cpu(product);
+ product = le16_to_cpu(tmp16);
ret = dt9812_read_info(dev, 5, &tmp16, sizeof(tmp16));
if (ret) {
@@ -752,12 +752,12 @@ static int dt9812_reset_device(struct comedi_device *dev)
}
devpriv->device = le16_to_cpu(tmp16);
- ret = dt9812_read_info(dev, 7, &serial, sizeof(serial));
+ ret = dt9812_read_info(dev, 7, &tmp32, sizeof(tmp32));
if (ret) {
dev_err(dev->class_dev, "failed to read serial number\n");
return ret;
}
- serial = le32_to_cpu(serial);
+ serial = le32_to_cpu(tmp32);
/* let the user know what node this device is now attached to */
dev_info(dev->class_dev, "USB DT9812 (%4.4x.%4.4x.%4.4x) #0x%8.8x\n",
@@ -781,10 +781,9 @@ static int dt9812_auto_attach(struct comedi_device *dev,
bool is_unipolar;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
sema_init(&devpriv->sem, 1);
usb_set_intfdata(intf, devpriv);
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index e14dd3ae9ec..fd525f499f2 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -33,6 +33,8 @@
their cards in their manuals.
*/
+#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/mutex.h>
@@ -183,10 +185,9 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index ff6f0bd7c86..8d70f64b157 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -18,10 +18,10 @@ Configuration options:
#define DEBUG 0
+#include <linux/module.h>
#include "../comedidev.h"
#include <linux/delay.h>
-#include <linux/ioport.h>
#define FL512_SIZE 16 /* the size of the used memory */
struct fl512_private {
@@ -118,10 +118,9 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_alloc_subdevices(dev, 2);
if (ret)
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index 2fceff93867..559bf558353 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -42,6 +42,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -223,37 +224,26 @@ struct hpdi_private {
volatile uint32_t bits[24];
/* number of bytes at which to generate COMEDI_CB_BLOCK events */
volatile unsigned int block_size;
- unsigned dio_config_output:1;
};
static int dio_config_insn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
unsigned int *data)
{
- struct hpdi_private *devpriv = dev->private;
+ int ret;
switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- devpriv->dio_config_output = 1;
- return insn->n;
- break;
- case INSN_CONFIG_DIO_INPUT:
- devpriv->dio_config_output = 0;
- return insn->n;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- devpriv->dio_config_output ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
case INSN_CONFIG_BLOCK_SIZE:
return dio_config_block_size(dev, data);
- break;
default:
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0xffffffff);
+ if (ret)
+ return ret;
break;
}
- return -EINVAL;
+ return insn->n;
}
static void disable_plx_interrupts(struct comedi_device *dev)
@@ -483,10 +473,9 @@ static int hpdi_auto_attach(struct comedi_device *dev,
dev->board_ptr = thisboard;
dev->board_name = thisboard->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
retval = comedi_pci_enable(dev);
if (retval)
@@ -673,9 +662,7 @@ static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- struct hpdi_private *devpriv = dev->private;
-
- if (devpriv->dio_config_output)
+ if (s->io_bits)
return -EINVAL;
else
return di_cmd_test(dev, s, cmd);
@@ -746,9 +733,7 @@ static int di_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- struct hpdi_private *devpriv = dev->private;
-
- if (devpriv->dio_config_output)
+ if (s->io_bits)
return -EINVAL;
else
return di_cmd(dev, s);
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index a11e015dc03..3889d23292d 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -42,6 +42,7 @@ There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V
Configuration options: not applicable, uses PCI auto config
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -495,10 +496,9 @@ static int icp_multi_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index ee7537daf47..5c3a318b464 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -1,662 +1,537 @@
/*
- * comedi/drivers/ii_pci20kc.c
- * Driver for Intelligent Instruments PCI-20001C carrier board
- * and modules.
+ * ii_pci20kc.c
+ * Driver for Intelligent Instruments PCI-20001C carrier board and modules.
*
- * Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de>
- * with suggestions from David Schleef
- * 16.06.2000
- *
- * Linux device driver for COMEDI
- * Intelligent Instrumentation
- * PCI-20001 C-2A Carrier Board
- * PCI-20341 M-1A 16-Bit analog input module
- * - differential
- * - range (-5V - +5V)
- * - 16 bit
- * PCI-20006 M-2 16-Bit analog output module
- * - ranges (-10V - +10V) (0V - +10V) (-5V - +5V)
- * - 16 bit
- *
- * only ONE PCI-20341 module possible
- * only ONE PCI-20006 module possible
- * no extern trigger implemented
- *
- * NOT WORKING (but soon) only 4 on-board differential channels supported
- * NOT WORKING (but soon) only ONE di-port and ONE do-port supported
- * instead of 4 digital ports
- * di-port == Port 0
- * do-port == Port 1
- *
- * The state of this driver is only a starting point for a complete
- * COMEDI-driver. The final driver should support all features of the
- * carrier board and modules.
+ * Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de>
+ * with suggestions from David Schleef 16.06.2000
+ */
+
+/*
+ * Driver: ii_pci20kc
+ * Description: Intelligent Instruments PCI-20001C carrier board
+ * Devices: (Intelligent Instrumentation) PCI-20001C [ii_pci20kc]
+ * Author: Markus Kempf <kempf@matsci.uni-sb.de>
+ * Status: works
*
- * The test configuration:
+ * Supports the PCI-20001C-1a and PCI-20001C-2a carrier boards. The
+ * -2a version has 32 on-board DIO channels. Three add-on modules
+ * can be added to the carrier board for additional functionality.
*
- * kernel 2.2.14 with RTAI v1.2 and patch-2.2.14rthal2
- * COMEDI 0.7.45
- * COMEDILIB 0.7.9
+ * Supported add-on modules:
+ * PCI-20006M-1 1 channel, 16-bit analog output module
+ * PCI-20006M-2 2 channel, 16-bit analog output module
+ * PCI-20341M-1A 4 channel, 16-bit analog input module
*
+ * Options:
+ * 0 Board base address
+ * 1 IRQ (not-used)
*/
-/*
-Driver: ii_pci20kc
-Description: Intelligent Instruments PCI-20001C carrier board
-Author: Markus Kempf <kempf@matsci.uni-sb.de>
-Devices: [Intelligent Instrumentation] PCI-20001C (ii_pci20kc)
-Status: works
-
-Supports the PCI-20001 C-2a Carrier board, and could probably support
-the other carrier boards with small modifications. Modules supported
-are:
- PCI-20006 M-2 16-bit analog output module
- PCI-20341 M-1A 16-bit analog input module
-
-Options:
- 0 Board base address
- 1 IRQ
- 2 first option for module 1
- 3 second option for module 1
- 4 first option for module 2
- 5 second option for module 2
- 6 first option for module 3
- 7 second option for module 3
-
-options for PCI-20006M:
- first: Analog output channel 0 range configuration
- 0 bipolar 10 (-10V -- +10V)
- 1 unipolar 10 (0V -- +10V)
- 2 bipolar 5 (-5V -- 5V)
- second: Analog output channel 1 range configuration
-
-options for PCI-20341M:
- first: Analog input gain configuration
- 0 1
- 1 10
- 2 100
- 3 200
-*/
+#include <linux/module.h>
#include "../comedidev.h"
-#define PCI20000_ID 0x1d
-#define PCI20341_ID 0x77
-#define PCI20006_ID 0xe3
-#define PCI20xxx_EMPTY_ID 0xff
-
-#define PCI20000_OFFSET 0x100
-#define PCI20000_MODULES 3
-
-#define PCI20000_DIO_0 0x80
-#define PCI20000_DIO_1 0x81
-#define PCI20000_DIO_2 0xc0
-#define PCI20000_DIO_3 0xc1
-#define PCI20000_DIO_CONTROL_01 0x83 /* port 0, 1 control */
-#define PCI20000_DIO_CONTROL_23 0xc3 /* port 2, 3 control */
-#define PCI20000_DIO_BUFFER 0x82 /* buffer direction & enable */
-#define PCI20000_DIO_EOC 0xef /* even port, control output */
-#define PCI20000_DIO_OOC 0xfd /* odd port, control output */
-#define PCI20000_DIO_EIC 0x90 /* even port, control input */
-#define PCI20000_DIO_OIC 0x82 /* odd port, control input */
-#define DIO_CAND 0x12 /* and bit 1 & 4 of control */
-#define DIO_BE 0x01 /* buffer: port enable */
-#define DIO_BO 0x04 /* buffer: output */
-#define DIO_BI 0x05 /* buffer: input */
-#define DIO_PS_0 0x00 /* buffer: port shift 0 */
-#define DIO_PS_1 0x01 /* buffer: port shift 1 */
-#define DIO_PS_2 0x04 /* buffer: port shift 2 */
-#define DIO_PS_3 0x05 /* buffer: port shift 3 */
-
-#define PCI20006_LCHAN0 0x0d
-#define PCI20006_STROBE0 0x0b
-#define PCI20006_LCHAN1 0x15
-#define PCI20006_STROBE1 0x13
-
-#define PCI20341_INIT 0x04
-#define PCI20341_REPMODE 0x00 /* single shot mode */
-#define PCI20341_PACER 0x00 /* Hardware Pacer disabled */
-#define PCI20341_CHAN_NR 0x04 /* number of input channels */
-#define PCI20341_CONFIG_REG 0x10
-#define PCI20341_MOD_STATUS 0x01
-#define PCI20341_OPT_REG 0x11
-#define PCI20341_SET_TIME_REG 0x15
-#define PCI20341_LCHAN_ADDR_REG 0x13
-#define PCI20341_CHAN_LIST 0x80
-#define PCI20341_CC_RESET 0x1b
-#define PCI20341_CHAN_RESET 0x19
-#define PCI20341_SOFT_PACER 0x04
-#define PCI20341_STATUS_REG 0x12
-#define PCI20341_LDATA 0x02
-#define PCI20341_DAISY_CHAIN 0x20 /* On-board inputs only */
-#define PCI20341_MUX 0x04 /* Enable on-board MUX */
-#define PCI20341_SCANLIST 0x80 /* Channel/Gain Scan List */
-
-union pci20xxx_subdev_private {
- void __iomem *iobase;
- struct {
- void __iomem *iobase;
- const struct comedi_lrange *ao_range_list[2];
- /* range of channels of ao module */
- unsigned int last_data[2];
- } pci20006;
- struct {
- void __iomem *iobase;
- int timebase;
- int settling_time;
- int ai_gain;
- } pci20341;
+/*
+ * Register I/O map
+ */
+#define II20K_MOD_OFFSET 0x100
+#define II20K_ID_REG 0x00
+#define II20K_ID_MOD1_EMPTY (1 << 7)
+#define II20K_ID_MOD2_EMPTY (1 << 6)
+#define II20K_ID_MOD3_EMPTY (1 << 5)
+#define II20K_ID_MASK 0x1f
+#define II20K_ID_PCI20001C_1A 0x1b /* no on-board DIO */
+#define II20K_ID_PCI20001C_2A 0x1d /* on-board DIO */
+#define II20K_MOD_STATUS_REG 0x40
+#define II20K_MOD_STATUS_IRQ_MOD1 (1 << 7)
+#define II20K_MOD_STATUS_IRQ_MOD2 (1 << 6)
+#define II20K_MOD_STATUS_IRQ_MOD3 (1 << 5)
+#define II20K_DIO0_REG 0x80
+#define II20K_DIO1_REG 0x81
+#define II20K_DIR_ENA_REG 0x82
+#define II20K_DIR_DIO3_OUT (1 << 7)
+#define II20K_DIR_DIO2_OUT (1 << 6)
+#define II20K_BUF_DISAB_DIO3 (1 << 5)
+#define II20K_BUF_DISAB_DIO2 (1 << 4)
+#define II20K_DIR_DIO1_OUT (1 << 3)
+#define II20K_DIR_DIO0_OUT (1 << 2)
+#define II20K_BUF_DISAB_DIO1 (1 << 1)
+#define II20K_BUF_DISAB_DIO0 (1 << 0)
+#define II20K_CTRL01_REG 0x83
+#define II20K_CTRL01_SET (1 << 7)
+#define II20K_CTRL01_DIO0_IN (1 << 4)
+#define II20K_CTRL01_DIO1_IN (1 << 1)
+#define II20K_DIO2_REG 0xc0
+#define II20K_DIO3_REG 0xc1
+#define II20K_CTRL23_REG 0xc3
+#define II20K_CTRL23_SET (1 << 7)
+#define II20K_CTRL23_DIO2_IN (1 << 4)
+#define II20K_CTRL23_DIO3_IN (1 << 1)
+
+#define II20K_ID_PCI20006M_1 0xe2 /* 1 AO channels */
+#define II20K_ID_PCI20006M_2 0xe3 /* 2 AO channels */
+#define II20K_AO_STRB_REG(x) (0x0b + ((x) * 0x08))
+#define II20K_AO_LSB_REG(x) (0x0d + ((x) * 0x08))
+#define II20K_AO_MSB_REG(x) (0x0e + ((x) * 0x08))
+#define II20K_AO_STRB_BOTH_REG 0x1b
+
+#define II20K_ID_PCI20341M_1 0x77 /* 4 AI channels */
+#define II20K_AI_STATUS_CMD_REG 0x01
+#define II20K_AI_STATUS_CMD_BUSY (1 << 7)
+#define II20K_AI_STATUS_CMD_HW_ENA (1 << 1)
+#define II20K_AI_STATUS_CMD_EXT_START (1 << 0)
+#define II20K_AI_LSB_REG 0x02
+#define II20K_AI_MSB_REG 0x03
+#define II20K_AI_PACER_RESET_REG 0x04
+#define II20K_AI_16BIT_DATA_REG 0x06
+#define II20K_AI_CONF_REG 0x10
+#define II20K_AI_CONF_ENA (1 << 2)
+#define II20K_AI_OPT_REG 0x11
+#define II20K_AI_OPT_TRIG_ENA (1 << 5)
+#define II20K_AI_OPT_TRIG_INV (1 << 4)
+#define II20K_AI_OPT_TIMEBASE(x) (((x) & 0x3) << 1)
+#define II20K_AI_OPT_BURST_MODE (1 << 0)
+#define II20K_AI_STATUS_REG 0x12
+#define II20K_AI_STATUS_INT (1 << 7)
+#define II20K_AI_STATUS_TRIG (1 << 6)
+#define II20K_AI_STATUS_TRIG_ENA (1 << 5)
+#define II20K_AI_STATUS_PACER_ERR (1 << 2)
+#define II20K_AI_STATUS_DATA_ERR (1 << 1)
+#define II20K_AI_STATUS_SET_TIME_ERR (1 << 0)
+#define II20K_AI_LAST_CHAN_ADDR_REG 0x13
+#define II20K_AI_CUR_ADDR_REG 0x14
+#define II20K_AI_SET_TIME_REG 0x15
+#define II20K_AI_DELAY_LSB_REG 0x16
+#define II20K_AI_DELAY_MSB_REG 0x17
+#define II20K_AI_CHAN_ADV_REG 0x18
+#define II20K_AI_CHAN_RESET_REG 0x19
+#define II20K_AI_START_TRIG_REG 0x1a
+#define II20K_AI_COUNT_RESET_REG 0x1b
+#define II20K_AI_CHANLIST_REG 0x80
+#define II20K_AI_CHANLIST_ONBOARD_ONLY (1 << 5)
+#define II20K_AI_CHANLIST_GAIN(x) (((x) & 0x3) << 3)
+#define II20K_AI_CHANLIST_MUX_ENA (1 << 2)
+#define II20K_AI_CHANLIST_CHAN(x) (((x) & 0x3) << 0)
+#define II20K_AI_CHANLIST_LEN 0x80
+
+/* the AO range is set by jumpers on the 20006M module */
+static const struct comedi_lrange ii20k_ao_ranges = {
+ 3, {
+ BIP_RANGE(5), /* Chan 0 - W1/W3 in Chan 1 - W2/W4 in */
+ UNI_RANGE(10), /* Chan 0 - W1/W3 out Chan 1 - W2/W4 in */
+ BIP_RANGE(10) /* Chan 0 - W1/W3 in Chan 1 - W2/W4 out */
+ }
};
-struct pci20xxx_private {
-
- void __iomem *ioaddr;
- union pci20xxx_subdev_private subdev_private[PCI20000_MODULES];
+static const struct comedi_lrange ii20k_ai_ranges = {
+ 4, {
+ BIP_RANGE(5), /* gain 1 */
+ BIP_RANGE(0.5), /* gain 10 */
+ BIP_RANGE(0.05), /* gain 100 */
+ BIP_RANGE(0.025) /* gain 200 */
+ },
};
-#define CHAN (CR_CHAN(it->chanlist[0]))
+struct ii20k_ao_private {
+ unsigned int last_data[2];
+};
-static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s,
- int opt0, int opt1);
-static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s,
- int opt0, int opt1);
-static int pci20xxx_dio_init(struct comedi_device *dev,
- struct comedi_subdevice *s);
+struct ii20k_private {
+ void __iomem *ioaddr;
+};
-/*
- options[0] Board base address
- options[1] IRQ
- options[2] first option for module 1
- options[3] second option for module 1
- options[4] first option for module 2
- options[5] second option for module 2
- options[6] first option for module 3
- options[7] second option for module 3
-
- options for PCI-20341M:
- first Analog input gain configuration
- 0 == 1
- 1 == 10
- 2 == 100
- 3 == 200
-
- options for PCI-20006M:
- first Analog output channel 0 range configuration
- 0 == bipolar 10 (-10V -- +10V)
- 1 == unipolar 10V (0V -- +10V)
- 2 == bipolar 5V (-5V -- +5V)
- second Analog output channel 1 range configuration
- 0 == bipolar 10 (-10V -- +10V)
- 1 == unipolar 10V (0V -- +10V)
- 2 == bipolar 5V (-5V -- +5V)
-*/
-static int pci20xxx_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
+static void __iomem *ii20k_module_iobase(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct pci20xxx_private *devpriv;
- unsigned char i;
- int ret;
- int id;
- struct comedi_subdevice *s;
- union pci20xxx_subdev_private *sdp;
-
- ret = comedi_alloc_subdevices(dev, 1 + PCI20000_MODULES);
- if (ret)
- return ret;
+ struct ii20k_private *devpriv = dev->private;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv)
- return -ENOMEM;
- dev->private = devpriv;
-
- devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0];
+ return devpriv->ioaddr + (s->index + 1) * II20K_MOD_OFFSET;
+}
- /* Check PCI-20001 C-2A Carrier Board ID */
- if ((readb(devpriv->ioaddr) & PCI20000_ID) != PCI20000_ID) {
- dev_warn(dev->class_dev,
- "PCI-20001 C-2A Carrier Board at base=0x%p not found !\n",
- devpriv->ioaddr);
- return -EINVAL;
- }
- dev_info(dev->class_dev, "PCI-20001 C-2A at base=0x%p\n",
- devpriv->ioaddr);
-
- for (i = 0; i < PCI20000_MODULES; i++) {
- s = &dev->subdevices[i];
- id = readb(devpriv->ioaddr + (i + 1) * PCI20000_OFFSET);
- s->private = devpriv->subdev_private + i;
- sdp = s->private;
- switch (id) {
- case PCI20006_ID:
- sdp->pci20006.iobase =
- devpriv->ioaddr + (i + 1) * PCI20000_OFFSET;
- pci20006_init(dev, s, it->options[2 * i + 2],
- it->options[2 * i + 3]);
- dev_info(dev->class_dev,
- "PCI-20006 module in slot %d\n", i + 1);
- break;
- case PCI20341_ID:
- sdp->pci20341.iobase =
- devpriv->ioaddr + (i + 1) * PCI20000_OFFSET;
- pci20341_init(dev, s, it->options[2 * i + 2],
- it->options[2 * i + 3]);
- dev_info(dev->class_dev,
- "PCI-20341 module in slot %d\n", i + 1);
- break;
- default:
- dev_warn(dev->class_dev,
- "unknown module code 0x%02x in slot %d: module disabled\n",
- id, i); /* XXX this looks like a bug! i + 1 ?? */
- /* fall through */
- case PCI20xxx_EMPTY_ID:
- s->type = COMEDI_SUBD_UNUSED;
- break;
- }
- }
+static int ii20k_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct ii20k_ao_private *ao_spriv = s->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
- /* initialize struct pci20xxx_private */
- pci20xxx_dio_init(dev, &dev->subdevices[PCI20000_MODULES]);
+ for (i = 0; i < insn->n; i++)
+ data[i] = ao_spriv->last_data[chan];
- return 1;
+ return insn->n;
}
-static void pci20xxx_detach(struct comedi_device *dev)
+static int ii20k_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- /* Nothing to cleanup */
-}
+ struct ii20k_ao_private *ao_spriv = s->private;
+ void __iomem *iobase = ii20k_module_iobase(dev, s);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = ao_spriv->last_data[chan];
+ int i;
-/* pci20006m */
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
-static int pci20006_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pci20006_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ /* munge data */
+ val += ((s->maxdata + 1) >> 1);
+ val &= s->maxdata;
-static const struct comedi_lrange *pci20006_range_list[] = {
- &range_bipolar10,
- &range_unipolar10,
- &range_bipolar5,
-};
+ writeb(val & 0xff, iobase + II20K_AO_LSB_REG(chan));
+ writeb((val >> 8) & 0xff, iobase + II20K_AO_MSB_REG(chan));
+ writeb(0x00, iobase + II20K_AO_STRB_REG(chan));
+ }
-static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s,
- int opt0, int opt1)
-{
- union pci20xxx_subdev_private *sdp = s->private;
-
- if (opt0 < 0 || opt0 > 2)
- opt0 = 0;
- if (opt1 < 0 || opt1 > 2)
- opt1 = 0;
-
- sdp->pci20006.ao_range_list[0] = pci20006_range_list[opt0];
- sdp->pci20006.ao_range_list[1] = pci20006_range_list[opt1];
-
- /* ao subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 2;
- s->len_chanlist = 2;
- s->insn_read = pci20006_insn_read;
- s->insn_write = pci20006_insn_write;
- s->maxdata = 0xffff;
- s->range_table_list = sdp->pci20006.ao_range_list;
- return 0;
+ ao_spriv->last_data[chan] = val;
+
+ return insn->n;
}
-static int pci20006_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int ii20k_ai_wait_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ int timeout)
{
- union pci20xxx_subdev_private *sdp = s->private;
+ void __iomem *iobase = ii20k_module_iobase(dev, s);
+ unsigned char status;
- data[0] = sdp->pci20006.last_data[CR_CHAN(insn->chanspec)];
+ do {
+ status = readb(iobase + II20K_AI_STATUS_REG);
+ if ((status & II20K_AI_STATUS_INT) == 0)
+ return 0;
+ } while (timeout--);
- return 1;
+ return -ETIME;
}
-static int pci20006_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void ii20k_ai_setup(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chanspec)
{
- union pci20xxx_subdev_private *sdp = s->private;
- int hi, lo;
- unsigned int boarddata;
-
- sdp->pci20006.last_data[CR_CHAN(insn->chanspec)] = data[0];
- boarddata = (((unsigned int)data[0] + 0x8000) & 0xffff);
- /* comedi-data -> board-data */
- lo = (boarddata & 0xff);
- hi = ((boarddata >> 8) & 0xff);
-
- switch (CR_CHAN(insn->chanspec)) {
- case 0:
- writeb(lo, sdp->iobase + PCI20006_LCHAN0);
- writeb(hi, sdp->iobase + PCI20006_LCHAN0 + 1);
- writeb(0x00, sdp->iobase + PCI20006_STROBE0);
- break;
- case 1:
- writeb(lo, sdp->iobase + PCI20006_LCHAN1);
- writeb(hi, sdp->iobase + PCI20006_LCHAN1 + 1);
- writeb(0x00, sdp->iobase + PCI20006_STROBE1);
- break;
- default:
- dev_warn(dev->class_dev, "ao channel Error!\n");
- return -EINVAL;
- }
-
- return 1;
-}
+ void __iomem *iobase = ii20k_module_iobase(dev, s);
+ unsigned int chan = CR_CHAN(chanspec);
+ unsigned int range = CR_RANGE(chanspec);
+ unsigned char val;
-/* PCI20341M */
+ /* initialize module */
+ writeb(II20K_AI_CONF_ENA, iobase + II20K_AI_CONF_REG);
-static int pci20341_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ /* software conversion */
+ writeb(0, iobase + II20K_AI_STATUS_CMD_REG);
-static const int pci20341_timebase[] = { 0x00, 0x00, 0x00, 0x04 };
-static const int pci20341_settling_time[] = { 0x58, 0x58, 0x93, 0x99 };
+ /* set the time base for the settling time counter based on the gain */
+ val = (range < 3) ? II20K_AI_OPT_TIMEBASE(0) : II20K_AI_OPT_TIMEBASE(2);
+ writeb(val, iobase + II20K_AI_OPT_REG);
-static const struct comedi_lrange range_bipolar0_5 = {
- 1,
- {BIP_RANGE(0.5)}
-};
+ /* set the settling time counter based on the gain */
+ val = (range < 2) ? 0x58 : (range < 3) ? 0x93 : 0x99;
+ writeb(val, iobase + II20K_AI_SET_TIME_REG);
-static const struct comedi_lrange range_bipolar0_05 = {
- 1,
- {BIP_RANGE(0.05)}
-};
+ /* set number of input channels */
+ writeb(1, iobase + II20K_AI_LAST_CHAN_ADDR_REG);
-static const struct comedi_lrange range_bipolar0_025 = {
- 1,
- {BIP_RANGE(0.025)}
-};
+ /* set the channel list byte */
+ val = II20K_AI_CHANLIST_ONBOARD_ONLY |
+ II20K_AI_CHANLIST_MUX_ENA |
+ II20K_AI_CHANLIST_GAIN(range) |
+ II20K_AI_CHANLIST_CHAN(chan);
+ writeb(val, iobase + II20K_AI_CHANLIST_REG);
-static const struct comedi_lrange *const pci20341_ranges[] = {
- &range_bipolar5,
- &range_bipolar0_5,
- &range_bipolar0_05,
- &range_bipolar0_025,
-};
+ /* reset settling time counter and trigger delay counter */
+ writeb(0, iobase + II20K_AI_COUNT_RESET_REG);
-static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s,
- int opt0, int opt1)
-{
- union pci20xxx_subdev_private *sdp = s->private;
- int option;
-
- /* options handling */
- if (opt0 < 0 || opt0 > 3)
- opt0 = 0;
- sdp->pci20341.timebase = pci20341_timebase[opt0];
- sdp->pci20341.settling_time = pci20341_settling_time[opt0];
-
- /* ai subdevice */
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = PCI20341_CHAN_NR;
- s->len_chanlist = PCI20341_SCANLIST;
- s->insn_read = pci20341_insn_read;
- s->maxdata = 0xffff;
- s->range_table = pci20341_ranges[opt0];
-
- /* depends on gain, trigger, repetition mode */
- option = sdp->pci20341.timebase | PCI20341_REPMODE;
-
- /* initialize Module */
- writeb(PCI20341_INIT, sdp->iobase + PCI20341_CONFIG_REG);
- /* set Pacer */
- writeb(PCI20341_PACER, sdp->iobase + PCI20341_MOD_STATUS);
- /* option register */
- writeb(option, sdp->iobase + PCI20341_OPT_REG);
- /* settling time counter */
- writeb(sdp->pci20341.settling_time,
- sdp->iobase + PCI20341_SET_TIME_REG);
- /* trigger not implemented */
- return 0;
+ /* reset channel scanner */
+ writeb(0, iobase + II20K_AI_CHAN_RESET_REG);
}
-static int pci20341_insn_read(struct comedi_device *dev,
+static int ii20k_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- union pci20xxx_subdev_private *sdp = s->private;
- unsigned int i = 0, j = 0;
- int lo, hi;
- unsigned char eoc; /* end of conversion */
- unsigned int clb; /* channel list byte */
- unsigned int boarddata;
-
- /* write number of input channels */
- writeb(1, sdp->iobase + PCI20341_LCHAN_ADDR_REG);
- clb = PCI20341_DAISY_CHAIN | PCI20341_MUX | (sdp->pci20341.ai_gain << 3)
- | CR_CHAN(insn->chanspec);
- writeb(clb, sdp->iobase + PCI20341_CHAN_LIST);
+ void __iomem *iobase = ii20k_module_iobase(dev, s);
+ int ret;
+ int i;
- /* reset settling time counter and trigger delay counter */
- writeb(0x00, sdp->iobase + PCI20341_CC_RESET);
+ ii20k_ai_setup(dev, s, insn->chanspec);
- writeb(0x00, sdp->iobase + PCI20341_CHAN_RESET);
+ for (i = 0; i < insn->n; i++) {
+ unsigned int val;
- /* generate Pacer */
+ /* generate a software start convert signal */
+ readb(iobase + II20K_AI_PACER_RESET_REG);
- for (i = 0; i < insn->n; i++) {
- /* data polling isn't the niciest way to get the data, I know,
- * but there are only 6 cycles (mean) and it is easier than
- * the whole interrupt stuff
- */
- j = 0;
- /* generate Pacer */
- readb(sdp->iobase + PCI20341_SOFT_PACER);
-
- eoc = readb(sdp->iobase + PCI20341_STATUS_REG);
- /* poll Interrupt Flag */
- while ((eoc < 0x80) && j < 100) {
- j++;
- eoc = readb(sdp->iobase + PCI20341_STATUS_REG);
- }
- if (j >= 100) {
- dev_warn(dev->class_dev,
- "AI interrupt channel %i polling exit !\n", i);
- return -EINVAL;
- }
- lo = readb(sdp->iobase + PCI20341_LDATA);
- hi = readb(sdp->iobase + PCI20341_LDATA + 1);
- boarddata = lo + 0x100 * hi;
-
- /* board-data -> comedi-data */
- data[i] = (short)((boarddata + 0x8000) & 0xffff);
- }
+ ret = ii20k_ai_wait_eoc(dev, s, 100);
+ if (ret)
+ return ret;
- return i;
-}
+ val = readb(iobase + II20K_AI_LSB_REG);
+ val |= (readb(iobase + II20K_AI_MSB_REG) << 8);
+
+ /* munge two's complement data */
+ val += ((s->maxdata + 1) >> 1);
+ val &= s->maxdata;
-/* native DIO */
+ data[i] = val;
+ }
-static void pci20xxx_dio_config(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int pci20xxx_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pci20xxx_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ return insn->n;
+}
-/* initialize struct pci20xxx_private */
-static int pci20xxx_dio_init(struct comedi_device *dev,
+static void ii20k_dio_config(struct comedi_device *dev,
struct comedi_subdevice *s)
{
+ struct ii20k_private *devpriv = dev->private;
+ unsigned char ctrl01 = 0;
+ unsigned char ctrl23 = 0;
+ unsigned char dir_ena = 0;
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 32;
- s->insn_bits = pci20xxx_dio_insn_bits;
- s->insn_config = pci20xxx_dio_insn_config;
- s->maxdata = 1;
- s->len_chanlist = 32;
- s->range_table = &range_digital;
- s->io_bits = 0;
+ /* port 0 - channels 0-7 */
+ if (s->io_bits & 0x000000ff) {
+ /* output port */
+ ctrl01 &= ~II20K_CTRL01_DIO0_IN;
+ dir_ena &= ~II20K_BUF_DISAB_DIO0;
+ dir_ena |= II20K_DIR_DIO0_OUT;
+ } else {
+ /* input port */
+ ctrl01 |= II20K_CTRL01_DIO0_IN;
+ dir_ena &= ~II20K_DIR_DIO0_OUT;
+ }
- /* digital I/O lines default to input on board reset. */
- pci20xxx_dio_config(dev, s);
+ /* port 1 - channels 8-15 */
+ if (s->io_bits & 0x0000ff00) {
+ /* output port */
+ ctrl01 &= ~II20K_CTRL01_DIO1_IN;
+ dir_ena &= ~II20K_BUF_DISAB_DIO1;
+ dir_ena |= II20K_DIR_DIO1_OUT;
+ } else {
+ /* input port */
+ ctrl01 |= II20K_CTRL01_DIO1_IN;
+ dir_ena &= ~II20K_DIR_DIO1_OUT;
+ }
- return 0;
+ /* port 2 - channels 16-23 */
+ if (s->io_bits & 0x00ff0000) {
+ /* output port */
+ ctrl23 &= ~II20K_CTRL23_DIO2_IN;
+ dir_ena &= ~II20K_BUF_DISAB_DIO2;
+ dir_ena |= II20K_DIR_DIO2_OUT;
+ } else {
+ /* input port */
+ ctrl23 |= II20K_CTRL23_DIO2_IN;
+ dir_ena &= ~II20K_DIR_DIO2_OUT;
+ }
+
+ /* port 3 - channels 24-31 */
+ if (s->io_bits & 0xff000000) {
+ /* output port */
+ ctrl23 &= ~II20K_CTRL23_DIO3_IN;
+ dir_ena &= ~II20K_BUF_DISAB_DIO3;
+ dir_ena |= II20K_DIR_DIO3_OUT;
+ } else {
+ /* input port */
+ ctrl23 |= II20K_CTRL23_DIO3_IN;
+ dir_ena &= ~II20K_DIR_DIO3_OUT;
+ }
+
+ ctrl23 |= II20K_CTRL01_SET;
+ ctrl23 |= II20K_CTRL23_SET;
+
+ /* order is important */
+ writeb(ctrl01, devpriv->ioaddr + II20K_CTRL01_REG);
+ writeb(ctrl23, devpriv->ioaddr + II20K_CTRL23_REG);
+ writeb(dir_ena, devpriv->ioaddr + II20K_DIR_ENA_REG);
}
-static int pci20xxx_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int ii20k_dio_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int mask, bits;
-
- mask = 1 << CR_CHAN(insn->chanspec);
- if (mask & 0x000000ff)
- bits = 0x000000ff;
- else if (mask & 0x0000ff00)
- bits = 0x0000ff00;
- else if (mask & 0x00ff0000)
- bits = 0x00ff0000;
- else
- bits = 0xff000000;
- if (data[0])
- s->io_bits |= bits;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
+ int ret;
+
+ if (chan < 8)
+ mask = 0x000000ff;
+ else if (chan < 16)
+ mask = 0x0000ff00;
+ else if (chan < 24)
+ mask = 0x00ff0000;
else
- s->io_bits &= ~bits;
- pci20xxx_dio_config(dev, s);
+ mask = 0xff000000;
- return 1;
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
+
+ ii20k_dio_config(dev, s);
+
+ return insn->n;
}
-static int pci20xxx_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int ii20k_dio_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct pci20xxx_private *devpriv = dev->private;
- unsigned int mask = data[0];
-
- s->state &= ~mask;
- s->state |= (mask & data[1]);
-
- mask &= s->io_bits;
- if (mask & 0x000000ff)
- writeb((s->state >> 0) & 0xff,
- devpriv->ioaddr + PCI20000_DIO_0);
- if (mask & 0x0000ff00)
- writeb((s->state >> 8) & 0xff,
- devpriv->ioaddr + PCI20000_DIO_1);
- if (mask & 0x00ff0000)
- writeb((s->state >> 16) & 0xff,
- devpriv->ioaddr + PCI20000_DIO_2);
- if (mask & 0xff000000)
- writeb((s->state >> 24) & 0xff,
- devpriv->ioaddr + PCI20000_DIO_3);
-
- data[1] = readb(devpriv->ioaddr + PCI20000_DIO_0);
- data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8;
- data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16;
- data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24;
+ struct ii20k_private *devpriv = dev->private;
+ unsigned int mask = data[0] & s->io_bits; /* outputs only */
+ unsigned int bits = data[1];
+
+ if (mask) {
+ s->state &= ~mask;
+ s->state |= (bits & mask);
+
+ if (mask & 0x000000ff)
+ writeb((s->state >> 0) & 0xff,
+ devpriv->ioaddr + II20K_DIO0_REG);
+ if (mask & 0x0000ff00)
+ writeb((s->state >> 8) & 0xff,
+ devpriv->ioaddr + II20K_DIO1_REG);
+ if (mask & 0x00ff0000)
+ writeb((s->state >> 16) & 0xff,
+ devpriv->ioaddr + II20K_DIO2_REG);
+ if (mask & 0xff000000)
+ writeb((s->state >> 24) & 0xff,
+ devpriv->ioaddr + II20K_DIO3_REG);
+ }
+
+ data[1] = readb(devpriv->ioaddr + II20K_DIO0_REG);
+ data[1] |= readb(devpriv->ioaddr + II20K_DIO1_REG) << 8;
+ data[1] |= readb(devpriv->ioaddr + II20K_DIO2_REG) << 16;
+ data[1] |= readb(devpriv->ioaddr + II20K_DIO3_REG) << 24;
return insn->n;
}
-static void pci20xxx_dio_config(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int ii20k_init_module(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct ii20k_ao_private *ao_spriv;
+ void __iomem *iobase = ii20k_module_iobase(dev, s);
+ unsigned char id;
+
+ id = readb(iobase + II20K_ID_REG);
+ switch (id) {
+ case II20K_ID_PCI20006M_1:
+ case II20K_ID_PCI20006M_2:
+ ao_spriv = comedi_alloc_spriv(s, sizeof(*ao_spriv));
+ if (!ao_spriv)
+ return -ENOMEM;
+
+ /* Analog Output subdevice */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = (id == II20K_ID_PCI20006M_2) ? 2 : 1;
+ s->maxdata = 0xffff;
+ s->range_table = &ii20k_ao_ranges;
+ s->insn_read = ii20k_ao_insn_read;
+ s->insn_write = ii20k_ao_insn_write;
+ break;
+ case II20K_ID_PCI20341M_1:
+ /* Analog Input subdevice */
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_DIFF;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->range_table = &ii20k_ai_ranges;
+ s->insn_read = ii20k_ai_insn_read;
+ break;
+ default:
+ s->type = COMEDI_SUBD_UNUSED;
+ break;
+ }
+
+ return 0;
+}
+
+static int ii20k_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
{
- struct pci20xxx_private *devpriv = dev->private;
- unsigned char control_01;
- unsigned char control_23;
- unsigned char buffer;
+ struct ii20k_private *devpriv;
+ struct comedi_subdevice *s;
+ unsigned char id;
+ bool has_dio;
+ int ret;
- control_01 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_01);
- control_23 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_23);
- buffer = readb(devpriv->ioaddr + PCI20000_DIO_BUFFER);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
- if (s->io_bits & 0x000000ff) {
- /* output port 0 */
- control_01 &= PCI20000_DIO_EOC;
- buffer = (buffer & (~(DIO_BE << DIO_PS_0))) | (DIO_BO <<
- DIO_PS_0);
- } else {
- /* input port 0 */
- control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_EIC;
- buffer = (buffer & (~(DIO_BI << DIO_PS_0)));
+ devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0];
+
+ id = readb(devpriv->ioaddr + II20K_ID_REG);
+ switch (id & II20K_ID_MASK) {
+ case II20K_ID_PCI20001C_1A:
+ break;
+ case II20K_ID_PCI20001C_2A:
+ has_dio = true;
+ break;
+ default:
+ return -ENODEV;
}
- if (s->io_bits & 0x0000ff00) {
- /* output port 1 */
- control_01 &= PCI20000_DIO_OOC;
- buffer = (buffer & (~(DIO_BE << DIO_PS_1))) | (DIO_BO <<
- DIO_PS_1);
+
+ ret = comedi_alloc_subdevices(dev, 4);
+ if (ret)
+ return ret;
+
+ s = &dev->subdevices[0];
+ if (id & II20K_ID_MOD1_EMPTY) {
+ s->type = COMEDI_SUBD_UNUSED;
} else {
- /* input port 1 */
- control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_OIC;
- buffer = (buffer & (~(DIO_BI << DIO_PS_1)));
+ ret = ii20k_init_module(dev, s);
+ if (ret)
+ return ret;
}
- if (s->io_bits & 0x00ff0000) {
- /* output port 2 */
- control_23 &= PCI20000_DIO_EOC;
- buffer = (buffer & (~(DIO_BE << DIO_PS_2))) | (DIO_BO <<
- DIO_PS_2);
+
+ s = &dev->subdevices[1];
+ if (id & II20K_ID_MOD2_EMPTY) {
+ s->type = COMEDI_SUBD_UNUSED;
} else {
- /* input port 2 */
- control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_EIC;
- buffer = (buffer & (~(DIO_BI << DIO_PS_2)));
+ ret = ii20k_init_module(dev, s);
+ if (ret)
+ return ret;
}
- if (s->io_bits & 0xff000000) {
- /* output port 3 */
- control_23 &= PCI20000_DIO_OOC;
- buffer = (buffer & (~(DIO_BE << DIO_PS_3))) | (DIO_BO <<
- DIO_PS_3);
+
+ s = &dev->subdevices[2];
+ if (id & II20K_ID_MOD3_EMPTY) {
+ s->type = COMEDI_SUBD_UNUSED;
} else {
- /* input port 3 */
- control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_OIC;
- buffer = (buffer & (~(DIO_BI << DIO_PS_3)));
+ ret = ii20k_init_module(dev, s);
+ if (ret)
+ return ret;
}
- writeb(control_01, devpriv->ioaddr + PCI20000_DIO_CONTROL_01);
- writeb(control_23, devpriv->ioaddr + PCI20000_DIO_CONTROL_23);
- writeb(buffer, devpriv->ioaddr + PCI20000_DIO_BUFFER);
-}
-#if 0
-static void pci20xxx_do(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- struct pci20xxx_private *devpriv = dev->private;
-
- /* XXX if the channel is configured for input, does this
- do bad things? */
- /* XXX it would be a good idea to only update the registers
- that _need_ to be updated. This requires changes to
- comedi, however. */
- writeb((s->state >> 0) & 0xff, devpriv->ioaddr + PCI20000_DIO_0);
- writeb((s->state >> 8) & 0xff, devpriv->ioaddr + PCI20000_DIO_1);
- writeb((s->state >> 16) & 0xff, devpriv->ioaddr + PCI20000_DIO_2);
- writeb((s->state >> 24) & 0xff, devpriv->ioaddr + PCI20000_DIO_3);
-}
-
-static unsigned int pci20xxx_di(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pci20xxx_private *devpriv = dev->private;
- unsigned int bits;
-
- /* XXX same note as above */
- bits = readb(devpriv->ioaddr + PCI20000_DIO_0);
- bits |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8;
- bits |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16;
- bits |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24;
+ /* Digital I/O subdevice */
+ s = &dev->subdevices[3];
+ if (has_dio) {
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 32;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = ii20k_dio_insn_bits;
+ s->insn_config = ii20k_dio_insn_config;
+
+ /* default all channels to input */
+ ii20k_dio_config(dev, s);
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
- return bits;
+ return 0;
}
-#endif
-static struct comedi_driver pci20xxx_driver = {
+static struct comedi_driver ii20k_driver = {
.driver_name = "ii_pci20kc",
.module = THIS_MODULE,
- .attach = pci20xxx_attach,
- .detach = pci20xxx_detach,
+ .attach = ii20k_attach,
+ .detach = comedi_legacy_detach,
};
-module_comedi_driver(pci20xxx_driver);
+module_comedi_driver(ii20k_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 94609f4aa4c..b52d58e5de2 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -38,6 +38,7 @@
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ctype.h>
@@ -638,10 +639,9 @@ static int jr3_pci_auto_attach(struct comedi_device *dev,
return -EINVAL;
}
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
init_timer(&devpriv->timer);
switch (pcidev->device) {
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index f10cf10e5fe..15589f62a61 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -29,6 +29,7 @@ This driver is a simple driver to read the counter values from
Kolter Electronic PCI Counter Card.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index c2308fd24d6..8f4afadab76 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -40,6 +40,7 @@ broken.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -1357,98 +1358,57 @@ static int me4000_dio_insn_bits(struct comedi_device *dev,
static int me4000_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- unsigned long tmp;
- int chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
+ unsigned int tmp;
+ int ret;
- switch (data[0]) {
- default:
- return -EINVAL;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- case INSN_CONFIG_DIO_INPUT:
- case INSN_CONFIG_DIO_OUTPUT:
- break;
- }
+ if (chan < 8)
+ mask = 0x000000ff;
+ else if (chan < 16)
+ mask = 0x0000ff00;
+ else if (chan < 24)
+ mask = 0x00ff0000;
+ else
+ mask = 0xff000000;
- /*
- * The input or output configuration of each digital line is
- * configured by a special insn_config instruction. chanspec
- * contains the channel to be changed, and data[0] contains the
- * value INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_OUTPUT.
- * On the ME-4000 it is only possible to switch port wise (8 bit)
- */
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG);
+ tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | ME4000_DIO_CTRL_BIT_MODE_1 |
+ ME4000_DIO_CTRL_BIT_MODE_2 | ME4000_DIO_CTRL_BIT_MODE_3 |
+ ME4000_DIO_CTRL_BIT_MODE_4 | ME4000_DIO_CTRL_BIT_MODE_5 |
+ ME4000_DIO_CTRL_BIT_MODE_6 | ME4000_DIO_CTRL_BIT_MODE_7);
+ if (s->io_bits & 0x000000ff)
+ tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
+ if (s->io_bits & 0x0000ff00)
+ tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
+ if (s->io_bits & 0x00ff0000)
+ tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
+ if (s->io_bits & 0xff000000)
+ tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
- if (data[0] == INSN_CONFIG_DIO_OUTPUT) {
- if (chan < 8) {
- s->io_bits |= 0xFF;
- tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
- ME4000_DIO_CTRL_BIT_MODE_1);
- tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
- } else if (chan < 16) {
- /*
- * Chech for optoisolated ME-4000 version.
- * If one the first port is a fixed output
- * port and the second is a fixed input port.
- */
- if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
- return -ENODEV;
-
- s->io_bits |= 0xFF00;
- tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
- ME4000_DIO_CTRL_BIT_MODE_3);
- tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
- } else if (chan < 24) {
- s->io_bits |= 0xFF0000;
- tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 |
- ME4000_DIO_CTRL_BIT_MODE_5);
- tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
- } else if (chan < 32) {
- s->io_bits |= 0xFF000000;
- tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 |
- ME4000_DIO_CTRL_BIT_MODE_7);
- tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
- } else {
- return -EINVAL;
- }
- } else {
- if (chan < 8) {
- /*
- * Chech for optoisolated ME-4000 version.
- * If one the first port is a fixed output
- * port and the second is a fixed input port.
- */
- if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
- return -ENODEV;
-
- s->io_bits &= ~0xFF;
- tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
- ME4000_DIO_CTRL_BIT_MODE_1);
- } else if (chan < 16) {
- s->io_bits &= ~0xFF00;
- tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
- ME4000_DIO_CTRL_BIT_MODE_3);
- } else if (chan < 24) {
- s->io_bits &= ~0xFF0000;
- tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 |
- ME4000_DIO_CTRL_BIT_MODE_5);
- } else if (chan < 32) {
- s->io_bits &= ~0xFF000000;
- tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 |
- ME4000_DIO_CTRL_BIT_MODE_7);
- } else {
- return -EINVAL;
- }
+ /*
+ * Check for optoisolated ME-4000 version.
+ * If one the first port is a fixed output
+ * port and the second is a fixed input port.
+ */
+ if (inl(dev->iobase + ME4000_DIO_DIR_REG)) {
+ s->io_bits |= 0x000000ff;
+ s->io_bits &= ~0x0000ff00;
+ tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
+ tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
+ ME4000_DIO_CTRL_BIT_MODE_3);
}
outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG);
- return 1;
+ return insn->n;
}
/*=============================================================================
@@ -1544,10 +1504,9 @@ static int me4000_auto_attach(struct comedi_device *dev,
dev->board_ptr = thisboard;
dev->board_name = thisboard->name;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = comedi_alloc_devpriv(dev, sizeof(*info));
if (!info)
return -ENOMEM;
- dev->private = info;
result = comedi_pci_enable(dev);
if (result)
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 7533ece3670..a6f6d4a4658 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -30,6 +30,7 @@
* Analog Input, Analog Output, Digital I/O
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
@@ -185,38 +186,30 @@ static int me_dio_insn_config(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct me_private_data *dev_private = dev->private;
- unsigned int mask = 1 << CR_CHAN(insn->chanspec);
- unsigned int bits;
- unsigned int port;
+ struct me_private_data *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
+ int ret;
- if (mask & 0x0000ffff) {
- bits = 0x0000ffff;
- port = ENABLE_PORT_A;
- } else {
- bits = 0xffff0000;
- port = ENABLE_PORT_B;
- }
+ if (chan < 16)
+ mask = 0x0000ffff;
+ else
+ mask = 0xffff0000;
- switch (data[0]) {
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~bits;
- dev_private->control_2 &= ~port;
- break;
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= bits;
- dev_private->control_2 |= port;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- }
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
- /* Update the port configuration */
- writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
+ if (s->io_bits & 0x0000ffff)
+ devpriv->control_2 |= ENABLE_PORT_A;
+ else
+ devpriv->control_2 &= ~ENABLE_PORT_A;
+ if (s->io_bits & 0xffff0000)
+ devpriv->control_2 |= ENABLE_PORT_B;
+ else
+ devpriv->control_2 &= ~ENABLE_PORT_B;
+
+ writew(devpriv->control_2, devpriv->me_regbase + ME_CONTROL_2);
return insn->n;
}
@@ -490,10 +483,9 @@ static int me_auto_attach(struct comedi_device *dev,
dev->board_ptr = board;
dev->board_name = board->name;
- dev_private = kzalloc(sizeof(*dev_private), GFP_KERNEL);
+ dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private));
if (!dev_private)
return -ENOMEM;
- dev->private = dev_private;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index 12c34db61d6..35cb4ace797 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -46,6 +46,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h
index d4487e888e6..8423b8bf338 100644
--- a/drivers/staging/comedi/drivers/mite.h
+++ b/drivers/staging/comedi/drivers/mite.h
@@ -21,6 +21,7 @@
#include <linux/pci.h>
#include <linux/log2.h>
+#include <linux/slab.h>
#include "../comedidev.h"
/* #define DEBUG_MITE */
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index 713842ad6ff..acbaeee6250 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -51,9 +51,9 @@ Configuration Options:
1 -10.1V .. +10.1V
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include <linux/delay.h>
/* Consecutive I/O port addresses */
@@ -286,10 +286,9 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
switch (it->options[1]) {
case 0:
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index 5ecd1b1666f..9d75ea4e201 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -24,11 +24,10 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3)
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
#define MULTIQ3_SIZE 16
/*
@@ -232,10 +231,9 @@ static int multiq3_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
s = &dev->subdevices[0];
/* ai subdevice */
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index 903c2ef5dd9..c2745f201f2 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -36,6 +36,7 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800
#define DEBUG 1
#define DEBUG_FLAGS
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -335,10 +336,9 @@ static int ni6527_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
devpriv->mite = mite_alloc(pcidev);
if (!devpriv->mite)
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 42a78de4731..3ba4c5712df 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -46,9 +46,9 @@ except maybe the 6514.
#define DEBUG 1
#define DEBUG_FLAGS
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include "../comedidev.h"
@@ -591,10 +591,9 @@ static int ni_65xx_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
devpriv->mite = mite_alloc(pcidev);
if (!devpriv->mite)
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index a9e000461ec..3607336dafe 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -34,6 +34,7 @@
* DAQ 6601/6602 User Manual (NI 322137B-01)
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -929,10 +930,9 @@ static int ni_660x_allocate_private(struct comedi_device *dev)
struct ni_660x_private *devpriv;
unsigned i;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
spin_lock_init(&devpriv->mite_channel_lock);
spin_lock_init(&devpriv->interrupt_lock);
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index 1a185b9c529..e2926ce3fb2 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -36,9 +36,9 @@ Commands are not supported.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include "../comedidev.h"
@@ -158,27 +158,16 @@ static int ni_670x_dio_insn_bits(struct comedi_device *dev,
static int ni_670x_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct ni_670x_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
+ int ret;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= 1 << chan;
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~(1 << chan);
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- break;
- }
writel(s->io_bits, devpriv->mite->daq_io_addr + DIO_PORT0_DIR_OFFSET);
return insn->n;
@@ -205,10 +194,9 @@ static int ni_670x_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
devpriv->mite = mite_alloc(pcidev);
if (!devpriv->mite)
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index 7ea5aa32e9d..2512ce8dfca 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -58,12 +58,14 @@ TRIG_WAKE_EOS
*/
+#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include <linux/io.h>
+
#include <asm/dma.h>
#include "8253.h"
@@ -719,10 +721,9 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int i;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_request_region(dev, it->options[0], A2150_SIZE);
if (ret)
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index e080053c697..b9122fd835e 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -36,10 +36,9 @@ Configuration options:
* document 320379.pdf.
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
/* board egisters */
/* registers with _2_ are accessed when GRP2WR is set in CFG1 */
@@ -249,42 +248,35 @@ static int atao_dio_insn_bits(struct comedi_device *dev,
static int atao_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct atao_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
- unsigned int mask, bit;
-
- /* The input or output configuration of each digital line is
- * configured by a special insn_config instruction. chanspec
- * contains the channel to be changed, and data[0] contains the
- * value COMEDI_INPUT or COMEDI_OUTPUT. */
-
- mask = (chan < 4) ? 0x0f : 0xf0;
- bit = (chan < 4) ? DOUTEN1 : DOUTEN2;
-
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= mask;
- devpriv->cfg3 |= bit;
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~mask;
- devpriv->cfg3 &= ~bit;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- break;
- }
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
+ int ret;
+
+ if (chan < 4)
+ mask = 0x0f;
+ else
+ mask = 0xf0;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
+
+ if (s->io_bits & 0x0f)
+ devpriv->cfg3 |= DOUTEN1;
+ else
+ devpriv->cfg3 &= ~DOUTEN1;
+ if (s->io_bits & 0xf0)
+ devpriv->cfg3 |= DOUTEN2;
+ else
+ devpriv->cfg3 &= ~DOUTEN2;
outw(devpriv->cfg3, dev->iobase + ATAO_CFG3);
- return 1;
+ return insn->n;
}
/*
@@ -341,10 +333,9 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 713edd55a91..856c73d8b7c 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -89,10 +89,10 @@ are not supported.
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
-#include <linux/delay.h>
#include <linux/isapnp.h>
#include "ni_stc.h"
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index da7396f9429..bb3491f5ad2 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -30,11 +30,10 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d)
*
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
#include "comedi_fc.h"
#include "8255.h"
@@ -577,15 +576,19 @@ static int atmio16d_dio_insn_config(struct comedi_device *dev,
unsigned int *data)
{
struct atmio16d_private *devpriv = dev->private;
- int i;
- int mask;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
+ int ret;
+
+ if (chan < 4)
+ mask = 0x0f;
+ else
+ mask = 0xf0;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
- for (i = 0; i < insn->n; i++) {
- mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
- s->io_bits &= ~mask;
- if (data[i])
- s->io_bits |= mask;
- }
devpriv->com_reg_2_state &= ~(COMREG2_DOUTEN0 | COMREG2_DOUTEN1);
if (s->io_bits & 0x0f)
devpriv->com_reg_2_state |= COMREG2_DOUTEN0;
@@ -593,7 +596,7 @@ static int atmio16d_dio_insn_config(struct comedi_device *dev,
devpriv->com_reg_2_state |= COMREG2_DOUTEN1;
outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2);
- return i;
+ return insn->n;
}
/*
@@ -645,10 +648,9 @@ static int atmio16d_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
/* reset the atmio16d hardware */
reset_atmio16d(dev);
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 3c50e31ecc6..404f83de276 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -45,9 +45,9 @@ Manuals: Register level: http://www.ni.com/pdf/manuals/340698.pdf
User Manual: http://www.ni.com/pdf/manuals/320676d.pdf
*/
-#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include "../comedidev.h"
@@ -90,21 +90,17 @@ static int daq700_dio_insn_bits(struct comedi_device *dev,
static int daq700_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- unsigned int chan = 1 << CR_CHAN(insn->chanspec);
-
- switch (data[0]) {
- case INSN_CONFIG_DIO_INPUT:
- break;
- case INSN_CONFIG_DIO_OUTPUT:
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & chan) ? COMEDI_OUTPUT : COMEDI_INPUT;
- break;
- default:
- return -EINVAL;
- }
+ int ret;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
+
+ /* The DIO channels are not configurable, fix the io_bits */
+ s->io_bits = 0x00ff;
return insn->n;
}
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index d3d4eb9356a..335ea34fa57 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -31,6 +31,7 @@ This is just a wrapper around the 8255.o driver to properly handle
the PCMCIA interface.
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include <pcmcia/cistpl.h>
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index f161e70b3a0..1add114dc0b 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -57,6 +57,7 @@
* 320502b (lab-pc+)
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/io.h>
@@ -64,79 +65,12 @@
#include "../comedidev.h"
-#include <asm/dma.h>
-
#include "8253.h"
#include "8255.h"
#include "comedi_fc.h"
#include "ni_labpc.h"
-
-/*
- * Register map (all registers are 8-bit)
- */
-#define STAT1_REG 0x00 /* R: Status 1 reg */
-#define STAT1_DAVAIL (1 << 0)
-#define STAT1_OVERRUN (1 << 1)
-#define STAT1_OVERFLOW (1 << 2)
-#define STAT1_CNTINT (1 << 3)
-#define STAT1_GATA0 (1 << 5)
-#define STAT1_EXTGATA0 (1 << 6)
-#define CMD1_REG 0x00 /* W: Command 1 reg */
-#define CMD1_MA(x) (((x) & 0x7) << 0)
-#define CMD1_TWOSCMP (1 << 3)
-#define CMD1_GAIN(x) (((x) & 0x7) << 4)
-#define CMD1_SCANEN (1 << 7)
-#define CMD2_REG 0x01 /* W: Command 2 reg */
-#define CMD2_PRETRIG (1 << 0)
-#define CMD2_HWTRIG (1 << 1)
-#define CMD2_SWTRIG (1 << 2)
-#define CMD2_TBSEL (1 << 3)
-#define CMD2_2SDAC0 (1 << 4)
-#define CMD2_2SDAC1 (1 << 5)
-#define CMD2_LDAC(x) (1 << (6 + (x)))
-#define CMD3_REG 0x02 /* W: Command 3 reg */
-#define CMD3_DMAEN (1 << 0)
-#define CMD3_DIOINTEN (1 << 1)
-#define CMD3_DMATCINTEN (1 << 2)
-#define CMD3_CNTINTEN (1 << 3)
-#define CMD3_ERRINTEN (1 << 4)
-#define CMD3_FIFOINTEN (1 << 5)
-#define ADC_START_CONVERT_REG 0x03 /* W: Start Convert reg */
-#define DAC_LSB_REG(x) (0x04 + 2 * (x)) /* W: DAC0/1 LSB reg */
-#define DAC_MSB_REG(x) (0x05 + 2 * (x)) /* W: DAC0/1 MSB reg */
-#define ADC_FIFO_CLEAR_REG 0x08 /* W: A/D FIFO Clear reg */
-#define ADC_FIFO_REG 0x0a /* R: A/D FIFO reg */
-#define DMATC_CLEAR_REG 0x0a /* W: DMA Interrupt Clear reg */
-#define TIMER_CLEAR_REG 0x0c /* W: Timer Interrupt Clear reg */
-#define CMD6_REG 0x0e /* W: Command 6 reg */
-#define CMD6_NRSE (1 << 0)
-#define CMD6_ADCUNI (1 << 1)
-#define CMD6_DACUNI(x) (1 << (2 + (x)))
-#define CMD6_HFINTEN (1 << 5)
-#define CMD6_DQINTEN (1 << 6)
-#define CMD6_SCANUP (1 << 7)
-#define CMD4_REG 0x0f /* W: Command 3 reg */
-#define CMD4_INTSCAN (1 << 0)
-#define CMD4_EOIRCV (1 << 1)
-#define CMD4_ECLKDRV (1 << 2)
-#define CMD4_SEDIFF (1 << 3)
-#define CMD4_ECLKRCV (1 << 4)
-#define DIO_BASE_REG 0x10 /* R/W: 8255 DIO base reg */
-#define COUNTER_A_BASE_REG 0x14 /* R/W: 8253 Counter A base reg */
-#define COUNTER_B_BASE_REG 0x18 /* R/W: 8253 Counter B base reg */
-#define CMD5_REG 0x1c /* W: Command 5 reg */
-#define CMD5_WRTPRT (1 << 2)
-#define CMD5_DITHEREN (1 << 3)
-#define CMD5_CALDACLD (1 << 4)
-#define CMD5_SCLK (1 << 5)
-#define CMD5_SDATA (1 << 6)
-#define CMD5_EEPROMCS (1 << 7)
-#define STAT2_REG 0x1d /* R: Status 2 reg */
-#define STAT2_PROMOUT (1 << 0)
-#define STAT2_OUTA1 (1 << 1)
-#define STAT2_FIFONHF (1 << 2)
-#define INTERVAL_COUNT_REG 0x1e /* W: Interval Counter Data reg */
-#define INTERVAL_STROBE_REG 0x1f /* W: Interval Counter Strobe reg */
+#include "ni_labpc_regs.h"
+#include "ni_labpc_isadma.h"
#define LABPC_SIZE 0x20 /* size of ISA io region */
#define LABPC_TIMER_BASE 500 /* 2 MHz master clock */
@@ -239,11 +173,6 @@ static const struct labpc_boardinfo labpc_boards[] = {
};
#endif
-/* size in bytes of dma buffer */
-static const int dma_buffer_size = 0xff00;
-/* 2 bytes per sample */
-static const int sample_size = 2;
-
static int labpc_counter_load(struct comedi_device *dev,
unsigned long base_address,
unsigned int counter_number,
@@ -451,32 +380,6 @@ static int labpc_ai_insn_read(struct comedi_device *dev,
return insn->n;
}
-#ifdef CONFIG_ISA_DMA_API
-/* utility function that suggests a dma transfer size in bytes */
-static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
-{
- unsigned int size;
- unsigned int freq;
-
- if (cmd->convert_src == TRIG_TIMER)
- freq = 1000000000 / cmd->convert_arg;
- /* return some default value */
- else
- freq = 0xffffffff;
-
- /* make buffer fill in no more than 1/3 second */
- size = (freq / 3) * sample_size;
-
- /* set a minimum and maximum size allowed */
- if (size > dma_buffer_size)
- size = dma_buffer_size - dma_buffer_size % sample_size;
- else if (size < sample_size)
- size = sample_size;
-
- return size;
-}
-#endif
-
static bool labpc_use_continuous_mode(const struct comedi_cmd *cmd,
enum scan_mode mode)
{
@@ -869,25 +772,20 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return ret;
}
-#ifdef CONFIG_ISA_DMA_API
- /* figure out what method we will use to transfer data */
- if (devpriv->dma_chan && /* need a dma channel allocated */
- /*
- * dma unsafe at RT priority,
- * and too much setup time for TRIG_WAKE_EOS for
- */
- (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0) {
+ /* figure out what method we will use to transfer data */
+ if (labpc_have_dma_chan(dev) &&
+ /* dma unsafe at RT priority,
+ * and too much setup time for TRIG_WAKE_EOS */
+ (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0)
xfer = isa_dma_transfer;
- /* pc-plus has no fifo-half full interrupt */
- } else
-#endif
- if (board->is_labpc1200 &&
- /* wake-end-of-scan should interrupt on fifo not empty */
- (cmd->flags & TRIG_WAKE_EOS) == 0 &&
- /* make sure we are taking more than just a few points */
- (cmd->stop_src != TRIG_COUNT || devpriv->count > 256)) {
+ else if (/* pc-plus has no fifo-half full interrupt */
+ board->is_labpc1200 &&
+ /* wake-end-of-scan should interrupt on fifo not empty */
+ (cmd->flags & TRIG_WAKE_EOS) == 0 &&
+ /* make sure we are taking more than just a few points */
+ (cmd->stop_src != TRIG_COUNT || devpriv->count > 256))
xfer = fifo_half_full_transfer;
- } else
+ else
xfer = fifo_not_empty_transfer;
devpriv->current_transfer = xfer;
@@ -952,40 +850,14 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
labpc_clear_adc_fifo(dev);
-#ifdef CONFIG_ISA_DMA_API
- /* set up dma transfer */
- if (xfer == isa_dma_transfer) {
- unsigned long irq_flags;
-
- irq_flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- /* clear flip-flop to make sure 2-byte registers for
- * count and address get set correctly */
- clear_dma_ff(devpriv->dma_chan);
- set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
- /* set appropriate size of transfer */
- devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd);
- if (cmd->stop_src == TRIG_COUNT &&
- devpriv->count * sample_size < devpriv->dma_transfer_size) {
- devpriv->dma_transfer_size =
- devpriv->count * sample_size;
- }
- set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
- enable_dma(devpriv->dma_chan);
- release_dma_lock(irq_flags);
- /* enable board's dma */
- devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN);
- } else
- devpriv->cmd3 &= ~(CMD3_DMAEN | CMD3_DMATCINTEN);
-#endif
+ if (xfer == isa_dma_transfer)
+ labpc_setup_dma(dev, s);
/* enable error interrupts */
devpriv->cmd3 |= CMD3_ERRINTEN;
/* enable fifo not empty interrupt? */
if (xfer == fifo_not_empty_transfer)
devpriv->cmd3 |= CMD3_FIFOINTEN;
- else
- devpriv->cmd3 &= ~CMD3_FIFOINTEN;
devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG);
/* setup any external triggering/pacing (cmd4 register) */
@@ -1026,74 +898,6 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
-#ifdef CONFIG_ISA_DMA_API
-static void labpc_drain_dma(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async = s->async;
- int status;
- unsigned long flags;
- unsigned int max_points, num_points, residue, leftover;
- int i;
-
- status = devpriv->stat1;
-
- flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- /* clear flip-flop to make sure 2-byte registers for
- * count and address get set correctly */
- clear_dma_ff(devpriv->dma_chan);
-
- /* figure out how many points to read */
- max_points = devpriv->dma_transfer_size / sample_size;
- /* residue is the number of points left to be done on the dma
- * transfer. It should always be zero at this point unless
- * the stop_src is set to external triggering.
- */
- residue = get_dma_residue(devpriv->dma_chan) / sample_size;
- num_points = max_points - residue;
- if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT)
- num_points = devpriv->count;
-
- /* figure out how many points will be stored next time */
- leftover = 0;
- if (async->cmd.stop_src != TRIG_COUNT) {
- leftover = devpriv->dma_transfer_size / sample_size;
- } else if (devpriv->count > num_points) {
- leftover = devpriv->count - num_points;
- if (leftover > max_points)
- leftover = max_points;
- }
-
- /* write data to comedi buffer */
- for (i = 0; i < num_points; i++)
- cfc_write_to_buffer(s, devpriv->dma_buffer[i]);
-
- if (async->cmd.stop_src == TRIG_COUNT)
- devpriv->count -= num_points;
-
- /* set address and count for next transfer */
- set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
- set_dma_count(devpriv->dma_chan, leftover * sample_size);
- release_dma_lock(flags);
-
- async->events |= COMEDI_CB_BLOCK;
-}
-
-static void handle_isa_dma(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
-
- labpc_drain_dma(dev);
-
- enable_dma(devpriv->dma_chan);
-
- /* clear dma tc interrupt */
- devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG);
-}
-#endif
-
/* read all available samples from ai fifo */
static int labpc_drain_fifo(struct comedi_device *dev)
{
@@ -1130,12 +934,10 @@ static int labpc_drain_fifo(struct comedi_device *dev)
* when acquisition is terminated by stop_src == TRIG_EXT). */
static void labpc_drain_dregs(struct comedi_device *dev)
{
-#ifdef CONFIG_ISA_DMA_API
struct labpc_private *devpriv = dev->private;
if (devpriv->current_transfer == isa_dma_transfer)
labpc_drain_dma(dev);
-#endif
labpc_drain_fifo(dev);
}
@@ -1180,18 +982,9 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
return IRQ_HANDLED;
}
-#ifdef CONFIG_ISA_DMA_API
- if (devpriv->current_transfer == isa_dma_transfer) {
- /*
- * if a dma terminal count of external stop trigger
- * has occurred
- */
- if (devpriv->stat1 & STAT1_GATA0 ||
- (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1)) {
- handle_isa_dma(dev);
- }
- } else
-#endif
+ if (devpriv->current_transfer == isa_dma_transfer)
+ labpc_handle_dma_status(dev);
+ else
labpc_drain_fifo(dev);
if (devpriv->stat1 & STAT1_CNTINT) {
@@ -1697,10 +1490,9 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned int dma_chan = it->options[2];
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_request_region(dev, it->options[0], LABPC_SIZE);
if (ret)
@@ -1710,29 +1502,8 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
-#ifdef CONFIG_ISA_DMA_API
- if (dev->irq && (dma_chan == 1 || dma_chan == 3)) {
- devpriv->dma_buffer = kmalloc(dma_buffer_size,
- GFP_KERNEL | GFP_DMA);
- if (devpriv->dma_buffer) {
- ret = request_dma(dma_chan, dev->board_name);
- if (ret == 0) {
- unsigned long dma_flags;
-
- devpriv->dma_chan = dma_chan;
- devpriv->dma_addr =
- virt_to_bus(devpriv->dma_buffer);
-
- dma_flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
- release_dma_lock(dma_flags);
- } else {
- kfree(devpriv->dma_buffer);
- }
- }
- }
-#endif
+ if (dev->irq)
+ labpc_init_dma_chan(dev, dma_chan);
return 0;
}
@@ -1741,11 +1512,9 @@ static void labpc_detach(struct comedi_device *dev)
{
struct labpc_private *devpriv = dev->private;
- if (devpriv) {
- kfree(devpriv->dma_buffer);
- if (devpriv->dma_chan)
- free_dma(devpriv->dma_chan);
- }
+ if (devpriv)
+ labpc_free_dma_chan(dev);
+
comedi_legacy_detach(dev);
}
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index ce67f4bbb1f..0a8b3223f74 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -53,10 +53,10 @@ NI manuals:
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include <linux/delay.h>
-#include <linux/slab.h>
#include "8253.h"
#include "8255.h"
@@ -96,10 +96,9 @@ static int labpc_auto_attach(struct comedi_device *dev,
if (!link->irq)
return -EINVAL;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
return labpc_common_attach(dev, link->irq, IRQF_SHARED);
}
diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
new file mode 100644
index 00000000000..2149596830a
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
@@ -0,0 +1,226 @@
+/*
+ * comedi/drivers/ni_labpc_isadma.c
+ * ISA DMA support for National Instruments Lab-PC series boards and
+ * compatibles.
+ *
+ * Extracted from ni_labpc.c:
+ * Copyright (C) 2001-2003 Frank Mori Hess <fmhess@users.sourceforge.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "../comedidev.h"
+
+#include <asm/dma.h>
+
+#include "comedi_fc.h"
+#include "ni_labpc.h"
+#include "ni_labpc_regs.h"
+#include "ni_labpc_isadma.h"
+
+/* size in bytes of dma buffer */
+static const int dma_buffer_size = 0xff00;
+/* 2 bytes per sample */
+static const int sample_size = 2;
+
+/* utility function that suggests a dma transfer size in bytes */
+static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
+{
+ unsigned int size;
+ unsigned int freq;
+
+ if (cmd->convert_src == TRIG_TIMER)
+ freq = 1000000000 / cmd->convert_arg;
+ else
+ /* return some default value */
+ freq = 0xffffffff;
+
+ /* make buffer fill in no more than 1/3 second */
+ size = (freq / 3) * sample_size;
+
+ /* set a minimum and maximum size allowed */
+ if (size > dma_buffer_size)
+ size = dma_buffer_size - dma_buffer_size % sample_size;
+ else if (size < sample_size)
+ size = sample_size;
+
+ return size;
+}
+
+void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned long irq_flags;
+
+ irq_flags = claim_dma_lock();
+ disable_dma(devpriv->dma_chan);
+ /* clear flip-flop to make sure 2-byte registers for
+ * count and address get set correctly */
+ clear_dma_ff(devpriv->dma_chan);
+ set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
+ /* set appropriate size of transfer */
+ devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd);
+ if (cmd->stop_src == TRIG_COUNT &&
+ devpriv->count * sample_size < devpriv->dma_transfer_size)
+ devpriv->dma_transfer_size = devpriv->count * sample_size;
+ set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
+ enable_dma(devpriv->dma_chan);
+ release_dma_lock(irq_flags);
+ /* set CMD3 bits for caller to enable DMA and interrupt */
+ devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN);
+}
+EXPORT_SYMBOL_GPL(labpc_setup_dma);
+
+void labpc_drain_dma(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async = s->async;
+ int status;
+ unsigned long flags;
+ unsigned int max_points, num_points, residue, leftover;
+ int i;
+
+ status = devpriv->stat1;
+
+ flags = claim_dma_lock();
+ disable_dma(devpriv->dma_chan);
+ /* clear flip-flop to make sure 2-byte registers for
+ * count and address get set correctly */
+ clear_dma_ff(devpriv->dma_chan);
+
+ /* figure out how many points to read */
+ max_points = devpriv->dma_transfer_size / sample_size;
+ /* residue is the number of points left to be done on the dma
+ * transfer. It should always be zero at this point unless
+ * the stop_src is set to external triggering.
+ */
+ residue = get_dma_residue(devpriv->dma_chan) / sample_size;
+ num_points = max_points - residue;
+ if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT)
+ num_points = devpriv->count;
+
+ /* figure out how many points will be stored next time */
+ leftover = 0;
+ if (async->cmd.stop_src != TRIG_COUNT) {
+ leftover = devpriv->dma_transfer_size / sample_size;
+ } else if (devpriv->count > num_points) {
+ leftover = devpriv->count - num_points;
+ if (leftover > max_points)
+ leftover = max_points;
+ }
+
+ /* write data to comedi buffer */
+ for (i = 0; i < num_points; i++)
+ cfc_write_to_buffer(s, devpriv->dma_buffer[i]);
+
+ if (async->cmd.stop_src == TRIG_COUNT)
+ devpriv->count -= num_points;
+
+ /* set address and count for next transfer */
+ set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
+ set_dma_count(devpriv->dma_chan, leftover * sample_size);
+ release_dma_lock(flags);
+
+ async->events |= COMEDI_CB_BLOCK;
+}
+EXPORT_SYMBOL_GPL(labpc_drain_dma);
+
+static void handle_isa_dma(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ labpc_drain_dma(dev);
+
+ enable_dma(devpriv->dma_chan);
+
+ /* clear dma tc interrupt */
+ devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG);
+}
+
+void labpc_handle_dma_status(struct comedi_device *dev)
+{
+ const struct labpc_boardinfo *board = comedi_board(dev);
+ struct labpc_private *devpriv = dev->private;
+
+ /*
+ * if a dma terminal count of external stop trigger
+ * has occurred
+ */
+ if (devpriv->stat1 & STAT1_GATA0 ||
+ (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1))
+ handle_isa_dma(dev);
+}
+EXPORT_SYMBOL_GPL(labpc_handle_dma_status);
+
+int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan)
+{
+ struct labpc_private *devpriv = dev->private;
+ void *dma_buffer;
+ unsigned long dma_flags;
+ int ret;
+
+ if (dma_chan != 1 && dma_chan != 3)
+ return -EINVAL;
+
+ dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA);
+ if (!dma_buffer)
+ return -ENOMEM;
+
+ ret = request_dma(dma_chan, dev->board_name);
+ if (ret) {
+ kfree(dma_buffer);
+ return ret;
+ }
+
+ devpriv->dma_buffer = dma_buffer;
+ devpriv->dma_chan = dma_chan;
+ devpriv->dma_addr = virt_to_bus(devpriv->dma_buffer);
+
+ dma_flags = claim_dma_lock();
+ disable_dma(devpriv->dma_chan);
+ set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
+ release_dma_lock(dma_flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(labpc_init_dma_chan);
+
+void labpc_free_dma_chan(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ kfree(devpriv->dma_buffer);
+ devpriv->dma_buffer = NULL;
+ if (devpriv->dma_chan) {
+ free_dma(devpriv->dma_chan);
+ devpriv->dma_chan = 0;
+ }
+}
+EXPORT_SYMBOL_GPL(labpc_free_dma_chan);
+
+static int __init ni_labpc_isadma_init_module(void)
+{
+ return 0;
+}
+module_init(ni_labpc_isadma_init_module);
+
+static void __exit ni_labpc_isadma_cleanup_module(void)
+{
+}
+module_exit(ni_labpc_isadma_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi NI Lab-PC ISA DMA support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.h b/drivers/staging/comedi/drivers/ni_labpc_isadma.h
new file mode 100644
index 00000000000..771af4bd5a7
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.h
@@ -0,0 +1,57 @@
+/*
+ * ni_labpc ISA DMA support.
+*/
+
+#ifndef _NI_LABPC_ISADMA_H
+#define _NI_LABPC_ISADMA_H
+
+#define NI_LABPC_HAVE_ISA_DMA IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISADMA)
+
+#if NI_LABPC_HAVE_ISA_DMA
+
+static inline bool labpc_have_dma_chan(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ return (bool)devpriv->dma_chan;
+}
+
+int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan);
+void labpc_free_dma_chan(struct comedi_device *dev);
+void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s);
+void labpc_drain_dma(struct comedi_device *dev);
+void labpc_handle_dma_status(struct comedi_device *dev);
+
+#else
+
+static inline bool labpc_have_dma_chan(struct comedi_device *dev)
+{
+ return false;
+}
+
+static inline int labpc_init_dma_chan(struct comedi_device *dev,
+ unsigned int dma_chan)
+{
+ return -ENOTSUPP;
+}
+
+static inline void labpc_free_dma_chan(struct comedi_device *dev)
+{
+}
+
+static inline void labpc_setup_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+}
+
+static inline void labpc_drain_dma(struct comedi_device *dev)
+{
+}
+
+static inline void labpc_handle_dma_status(struct comedi_device *dev)
+{
+}
+
+#endif
+
+#endif /* _NI_LABPC_ISADMA_H */
diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c
index 6c79237b2b5..8be681fca90 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_pci.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c
@@ -29,8 +29,8 @@
* 340914a (pci-1200)
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -72,10 +72,9 @@ static int labpc_pci_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
devpriv->mite = mite_alloc(pcidev);
if (!devpriv->mite)
diff --git a/drivers/staging/comedi/drivers/ni_labpc_regs.h b/drivers/staging/comedi/drivers/ni_labpc_regs.h
new file mode 100644
index 00000000000..2a274a3e4e7
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_labpc_regs.h
@@ -0,0 +1,75 @@
+/*
+ * ni_labpc register definitions.
+*/
+
+#ifndef _NI_LABPC_REGS_H
+#define _NI_LABPC_REGS_H
+
+/*
+ * Register map (all registers are 8-bit)
+ */
+#define STAT1_REG 0x00 /* R: Status 1 reg */
+#define STAT1_DAVAIL (1 << 0)
+#define STAT1_OVERRUN (1 << 1)
+#define STAT1_OVERFLOW (1 << 2)
+#define STAT1_CNTINT (1 << 3)
+#define STAT1_GATA0 (1 << 5)
+#define STAT1_EXTGATA0 (1 << 6)
+#define CMD1_REG 0x00 /* W: Command 1 reg */
+#define CMD1_MA(x) (((x) & 0x7) << 0)
+#define CMD1_TWOSCMP (1 << 3)
+#define CMD1_GAIN(x) (((x) & 0x7) << 4)
+#define CMD1_SCANEN (1 << 7)
+#define CMD2_REG 0x01 /* W: Command 2 reg */
+#define CMD2_PRETRIG (1 << 0)
+#define CMD2_HWTRIG (1 << 1)
+#define CMD2_SWTRIG (1 << 2)
+#define CMD2_TBSEL (1 << 3)
+#define CMD2_2SDAC0 (1 << 4)
+#define CMD2_2SDAC1 (1 << 5)
+#define CMD2_LDAC(x) (1 << (6 + (x)))
+#define CMD3_REG 0x02 /* W: Command 3 reg */
+#define CMD3_DMAEN (1 << 0)
+#define CMD3_DIOINTEN (1 << 1)
+#define CMD3_DMATCINTEN (1 << 2)
+#define CMD3_CNTINTEN (1 << 3)
+#define CMD3_ERRINTEN (1 << 4)
+#define CMD3_FIFOINTEN (1 << 5)
+#define ADC_START_CONVERT_REG 0x03 /* W: Start Convert reg */
+#define DAC_LSB_REG(x) (0x04 + 2 * (x)) /* W: DAC0/1 LSB reg */
+#define DAC_MSB_REG(x) (0x05 + 2 * (x)) /* W: DAC0/1 MSB reg */
+#define ADC_FIFO_CLEAR_REG 0x08 /* W: A/D FIFO Clear reg */
+#define ADC_FIFO_REG 0x0a /* R: A/D FIFO reg */
+#define DMATC_CLEAR_REG 0x0a /* W: DMA Interrupt Clear reg */
+#define TIMER_CLEAR_REG 0x0c /* W: Timer Interrupt Clear reg */
+#define CMD6_REG 0x0e /* W: Command 6 reg */
+#define CMD6_NRSE (1 << 0)
+#define CMD6_ADCUNI (1 << 1)
+#define CMD6_DACUNI(x) (1 << (2 + (x)))
+#define CMD6_HFINTEN (1 << 5)
+#define CMD6_DQINTEN (1 << 6)
+#define CMD6_SCANUP (1 << 7)
+#define CMD4_REG 0x0f /* W: Command 3 reg */
+#define CMD4_INTSCAN (1 << 0)
+#define CMD4_EOIRCV (1 << 1)
+#define CMD4_ECLKDRV (1 << 2)
+#define CMD4_SEDIFF (1 << 3)
+#define CMD4_ECLKRCV (1 << 4)
+#define DIO_BASE_REG 0x10 /* R/W: 8255 DIO base reg */
+#define COUNTER_A_BASE_REG 0x14 /* R/W: 8253 Counter A base reg */
+#define COUNTER_B_BASE_REG 0x18 /* R/W: 8253 Counter B base reg */
+#define CMD5_REG 0x1c /* W: Command 5 reg */
+#define CMD5_WRTPRT (1 << 2)
+#define CMD5_DITHEREN (1 << 3)
+#define CMD5_CALDACLD (1 << 4)
+#define CMD5_SCLK (1 << 5)
+#define CMD5_SDATA (1 << 6)
+#define CMD5_EEPROMCS (1 << 7)
+#define STAT2_REG 0x1d /* R: Status 2 reg */
+#define STAT2_PROMOUT (1 << 0)
+#define STAT2_OUTA1 (1 << 1)
+#define STAT2_FIFONHF (1 << 2)
+#define INTERVAL_COUNT_REG 0x1e /* W: Interval Counter Data reg */
+#define INTERVAL_STROBE_REG 0x1f /* W: Interval Counter Strobe reg */
+
+#endif /* _NI_LABPC_REGS_H */
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 3e9f544e67f..4e02770e834 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -58,6 +58,7 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
+#include <linux/delay.h>
#include "8255.h"
#include "mite.h"
#include "comedi_fc.h"
@@ -3527,37 +3528,21 @@ static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s)
static int ni_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct ni_private *devpriv = dev->private;
+ int ret;
-#ifdef DEBUG_DIO
- printk("ni_dio_insn_config() chan=%d io=%d\n",
- CR_CHAN(insn->chanspec), data[0]);
-#endif
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= 1 << CR_CHAN(insn->chanspec);
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->
- io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
- COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- }
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
devpriv->dio_control &= ~DIO_Pins_Dir_Mask;
devpriv->dio_control |= DIO_Pins_Dir(s->io_bits);
devpriv->stc_writew(dev, devpriv->dio_control, DIO_Control_Register);
- return 1;
+ return insn->n;
}
static int ni_dio_insn_bits(struct comedi_device *dev,
@@ -3595,32 +3580,15 @@ static int ni_m_series_dio_insn_config(struct comedi_device *dev,
unsigned int *data)
{
struct ni_private *devpriv __maybe_unused = dev->private;
+ int ret;
-#ifdef DEBUG_DIO
- printk("ni_m_series_dio_insn_config() chan=%d io=%d\n",
- CR_CHAN(insn->chanspec), data[0]);
-#endif
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= 1 << CR_CHAN(insn->chanspec);
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->
- io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
- COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- }
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
ni_writel(s->io_bits, M_Offset_DIO_Direction);
- return 1;
+ return insn->n;
}
static int ni_m_series_dio_insn_bits(struct comedi_device *dev,
@@ -4363,10 +4331,9 @@ static int ni_alloc_private(struct comedi_device *dev)
{
struct ni_private *devpriv;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
spin_lock_init(&devpriv->window_lock);
spin_lock_init(&devpriv->soft_reg_copy_lock);
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index f813f576367..229a273f201 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -36,6 +36,7 @@ See the notes in the ni_atmio.o driver.
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include <linux/delay.h>
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 5b2f72e102e..fad81bc97b6 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -50,6 +50,7 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org
/* #define DEBUG 1 */
/* #define DEBUG_FLAGS */
+#include <linux/module.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
@@ -639,32 +640,19 @@ static void debug_int(struct comedi_device *dev)
static int ni_pcidio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct nidio96_private *devpriv = dev->private;
+ int ret;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
- if (insn->n != 1)
- return -EINVAL;
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= 1 << CR_CHAN(insn->chanspec);
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->
- io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
- COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- }
writel(s->io_bits, devpriv->mite->daq_io_addr + Port_Pin_Directions(0));
- return 1;
+ return insn->n;
}
static int ni_pcidio_insn_bits(struct comedi_device *dev,
@@ -1108,10 +1096,9 @@ static int nidio_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
spin_lock_init(&devpriv->mite_channel_lock);
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 35681ba1f36..536be83af54 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -106,6 +106,7 @@ Bugs:
*/
+#include <linux/module.h>
#include <linux/delay.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c
index f2cf76d15d7..9b120c77d83 100644
--- a/drivers/staging/comedi/drivers/ni_tio.c
+++ b/drivers/staging/comedi/drivers/ni_tio.c
@@ -44,6 +44,9 @@ TODO:
Support use of both banks X and Y
*/
+#include <linux/module.h>
+#include <linux/slab.h>
+
#include "ni_tio_internal.h"
static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter,
diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c
index cff50bc45bc..45691efefd0 100644
--- a/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ b/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -44,6 +44,7 @@ TODO:
Support use of both banks X and Y
*/
+#include <linux/module.h>
#include "comedi_fc.h"
#include "ni_tio_internal.h"
#include "mite.h"
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index 7abf3f74144..e859f85a8e1 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -53,10 +53,10 @@ supported.
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include <linux/delay.h>
#include "comedi_fc.h"
@@ -474,10 +474,9 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
s = &dev->subdevices[0];
/* AI subdevice */
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index cea657c7801..8af13e790ad 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -1,6 +1,6 @@
/*
* pcl724.c
- * Comedi driver for 8255 based ISA DIO boards
+ * Comedi driver for 8255 based ISA and PC/104 DIO boards
*
* Michal Dobes <dobes@tesnet.cz>
*/
@@ -14,6 +14,7 @@
* (ADLink) ACL-7122 [acl7122]
* (ADLink) ACL-7124 [acl7124]
* (ADLink) PET-48DIO [pet48dio]
+ * (WinSystems) PCM-IO48 [pcmio48]
* Author: Michal Dobes <dobes@tesnet.cz>
* Status: untested
*
@@ -25,11 +26,9 @@
* 1, 96: 96 DIO configuration
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-#include <linux/delay.h>
-
#include "8255.h"
#define SIZE_8255 4
@@ -70,6 +69,10 @@ static const struct pcl724_board boardtypes[] = {
.io_range = 0x02,
.is_pet48 = 1,
.numofports = 2, /* 48 DIO channels */
+ }, {
+ .name = "pcmio48",
+ .io_range = 0x08,
+ .numofports = 2, /* 48 DIO channels */
},
};
@@ -148,5 +151,5 @@ static struct comedi_driver pcl724_driver = {
module_comedi_driver(pcl724_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi driver for 8255 based ISA DIO boards");
+MODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 893f012a1b7..a4d0bcc31e5 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -62,10 +62,9 @@ Interrupts are not supported.
their web page. (http://www.cir.com/)
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
#undef ACL6126_IRQ /* no interrupt support (yet) */
#define PCL726_SIZE 16
@@ -229,10 +228,9 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
for (i = 0; i < 12; i++) {
devpriv->bipolar[i] = 0;
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index 862e75fd68f..2a659f23ecd 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -27,10 +27,9 @@
* The ACL-7130 card has an 8254 timer/counter not supported by this driver.
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
/*
* Register map
*
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index cd02786702c..03a098900d3 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -108,12 +108,12 @@
* 3= 20V unipolar inputs
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/gfp.h>
#include "../comedidev.h"
#include <linux/delay.h>
-#include <linux/ioport.h>
#include <linux/io.h>
#include <asm/dma.h>
@@ -1110,10 +1110,9 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
irq = 0;
if (board->IRQbits != 0) { /* board support IRQ */
@@ -1405,6 +1404,7 @@ no_dma:
if (it->options[3] > 0)
/* we use external trigger */
devpriv->use_ext_trg = 1;
+ break;
case boardA821:
devpriv->max_812_ai_mode0_rangewait = 1;
devpriv->mode_reg_int = (irq << 4) & 0xf0;
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index 91bd2071f57..f0313496259 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -32,9 +32,9 @@ Configuration Options:
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -922,10 +922,9 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -EIO;
}
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
/* grab our IRQ */
irq = 0;
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 91cb1bd6717..a52ba82ff0e 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -98,7 +98,7 @@ A word or two about DMA. Driver support DMA operations at two ways:
*/
-#include <linux/ioport.h>
+#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -1227,10 +1227,9 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned long pages;
struct comedi_subdevice *s;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
devpriv->io_range = board->io_range;
if ((board->fifo) && (it->options[2] == -1)) {
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index 5a9cd38e15f..cc1dc7f66e5 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -28,11 +28,9 @@ Copy/pasted/hacked from pcm724.c
* struct comedi_insn
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-#include <linux/delay.h>
-
#include "8255.h"
#define PCM3724_SIZE 16
@@ -186,39 +184,30 @@ static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s,
/* overriding the 8255 insn config */
static int subdev_3724_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int mask;
- unsigned int bits;
-
- mask = 1 << CR_CHAN(insn->chanspec);
- if (mask & 0x0000ff)
- bits = 0x0000ff;
- else if (mask & 0x00ff00)
- bits = 0x00ff00;
- else if (mask & 0x0f0000)
- bits = 0x0f0000;
+ int ret;
+
+ if (chan < 8)
+ mask = 0x0000ff;
+ else if (chan < 16)
+ mask = 0x00ff00;
+ else if (chan < 20)
+ mask = 0x0f0000;
else
- bits = 0xf00000;
-
- switch (data[0]) {
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~bits;
- break;
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= bits;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- }
+ mask = 0xf00000;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
do_3724_config(dev, s, insn->chanspec);
enable_chan(dev, s, insn->chanspec);
- return 1;
+
+ return insn->n;
}
static int pcm3724_attach(struct comedi_device *dev,
@@ -228,10 +217,9 @@ static int pcm3724_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret, i;
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = comedi_alloc_devpriv(dev, sizeof(*priv));
if (!priv)
return -ENOMEM;
- dev->private = priv;
ret = comedi_request_region(dev, it->options[0], PCM3724_SIZE);
if (ret)
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index d5c728dc619..423f23676d2 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -38,6 +38,7 @@
* 1 = two's complement (+-10V input range)
*/
+#include <linux/module.h>
#include "../comedidev.h"
#define PCMAD_STATUS 0
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 774a63dfe04..1c7a135c91d 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -48,6 +48,7 @@
* [1] - Do Simultaneous Xfer (see description)
*/
+#include <linux/module.h>
#include "../comedidev.h"
/* AI range is not configurable, it's set by jumpers on the board */
@@ -138,10 +139,9 @@ static int pcmda12_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
devpriv->simultaneous_xfer_mode = it->options[1];
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index 9f76b1f5998..574443df42d 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -72,6 +72,7 @@ Configuration Options:
leave out if you don't need this feature)
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -309,68 +310,27 @@ static int pcmmio_dio_insn_bits(struct comedi_device *dev,
return insn->n;
}
-/* The input or output configuration of each digital line is
- * configured by a special insn_config instruction. chanspec
- * contains the channel to be changed, and data[0] contains the
- * value COMEDI_INPUT or COMEDI_OUTPUT. */
static int pcmmio_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
- chan % 8;
- unsigned long ioaddr;
- unsigned char byte;
-
- /* Compute ioaddr for this channel */
- ioaddr = subpriv->iobases[byte_no];
-
- /* NOTE:
- writing a 0 an IO channel's bit sets the channel to INPUT
- and pulls the line high as well
-
- writing a 1 to an IO channel's bit pulls the line low
-
- All channels are implicitly always in OUTPUT mode -- but when
- they are high they can be considered to be in INPUT mode..
-
- Thus, we only force channels low if the config request was INPUT,
- otherwise we do nothing to the hardware. */
-
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- /* save to io_bits -- don't actually do anything since
- all input channels are also output channels... */
- s->io_bits |= 1 << chan;
- break;
- case INSN_CONFIG_DIO_INPUT:
- /* write a 0 to the actual register representing the channel
- to set it to 'input'. 0 means "float high". */
- byte = inb(ioaddr);
- byte &= ~(1 << bit_no);
- /**< set input channel to '0' */
-
- /*
- * write out byte -- this is the only time we actually affect
- * the hardware as all channels are implicitly output
- * -- but input channels are set to float-high
- */
- outb(byte, ioaddr);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int byte_no = chan / 8;
+ int bit_no = chan % 8;
+ int ret;
- /* save to io_bits */
- s->io_bits &= ~(1 << chan);
- break;
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
- case INSN_CONFIG_DIO_QUERY:
- /* retrieve from shadow register */
- data[1] =
- (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
+ if (data[0] == INSN_CONFIG_DIO_INPUT) {
+ unsigned long ioaddr = subpriv->iobases[byte_no];
+ unsigned char val;
- default:
- return -EINVAL;
- break;
+ val = inb(ioaddr);
+ val &= ~(1 << bit_no);
+ outb(val, ioaddr);
}
return insn->n;
@@ -1039,10 +999,9 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
for (asic = 0; asic < MAX_ASICS; ++asic) {
devpriv->asics[asic].num = asic;
@@ -1197,12 +1156,13 @@ static void pcmmio_detach(struct comedi_device *dev)
struct pcmmio_private *devpriv = dev->private;
int i;
- for (i = 0; i < MAX_ASICS; ++i) {
- if (devpriv && devpriv->asics[i].irq)
- free_irq(devpriv->asics[i].irq, dev);
- }
- if (devpriv && devpriv->sprivs)
+ if (devpriv) {
+ for (i = 0; i < MAX_ASICS; ++i) {
+ if (devpriv->asics[i].irq)
+ free_irq(devpriv->asics[i].irq, dev);
+ }
kfree(devpriv->sprivs);
+ }
comedi_legacy_detach(dev);
}
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index c43b6334cea..67e2bb1d66f 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -73,6 +73,7 @@
* can be the same as first irq!)
*/
+#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -232,27 +233,19 @@ static int pcmuio_dio_insn_bits(struct comedi_device *dev,
static int pcmuio_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec);
int asic = s->index / 2;
int port = (s->index % 2) ? 3 : 0;
+ int ret;
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= chan_mask;
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~chan_mask;
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
+
+ if (data[0] == INSN_CONFIG_DIO_INPUT)
pcmuio_write(dev, s->io_bits, asic, 0, port);
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & chan_mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
- break;
- default:
- return -EINVAL;
- break;
- }
return insn->n;
}
@@ -609,10 +602,9 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
for (asic = 0; asic < PCMUIO_MAX_ASICS; ++asic)
spin_lock_init(&devpriv->asics[asic].spinlock);
@@ -680,12 +672,13 @@ static void pcmuio_detach(struct comedi_device *dev)
struct pcmuio_private *devpriv = dev->private;
int i;
- for (i = 0; i < PCMUIO_MAX_ASICS; ++i) {
- if (devpriv->asics[i].irq)
- free_irq(devpriv->asics[i].irq, dev);
- }
- if (devpriv && devpriv->sprivs)
+ if (devpriv) {
+ for (i = 0; i < PCMUIO_MAX_ASICS; ++i) {
+ if (devpriv->asics[i].irq)
+ free_irq(devpriv->asics[i].irq, dev);
+ }
kfree(devpriv->sprivs);
+ }
comedi_legacy_detach(dev);
}
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
index 005fbefae29..2ae4ee15704 100644
--- a/drivers/staging/comedi/drivers/poc.c
+++ b/drivers/staging/comedi/drivers/poc.c
@@ -30,10 +30,9 @@ Configuration options:
[0] - I/O port base
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
struct boarddef_struct {
const char *name;
unsigned int iosize;
@@ -109,10 +108,9 @@ static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
/* analog output subdevice */
s = &dev->subdevices[0];
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index e092ce87722..9775d3622a6 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -47,6 +47,7 @@ Status: works
Devices: [Quatech] DAQP-208 (daqp), DAQP-308
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include <linux/semaphore.h>
@@ -715,10 +716,9 @@ static int daqp_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
ret = comedi_pcmcia_enable(dev, NULL);
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 9b93a1fc4a5..93c980c62a2 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -95,6 +95,7 @@
* Digital-IO and Analog-Out only support instruction mode.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -1237,23 +1238,11 @@ static int rtd_dio_insn_config(struct comedi_device *dev,
unsigned int *data)
{
struct rtd_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int mask = 1 << chan;
+ int ret;
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= mask;
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~mask;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- }
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
/* TODO support digital match interrupts and strobes */
@@ -1338,10 +1327,9 @@ static int rtd_auto_attach(struct comedi_device *dev,
dev->board_ptr = board;
dev->board_name = board->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index f698c7fc572..cbb4ba5b852 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -49,11 +49,11 @@
* [8] - DAC 1 encoding (same as DAC 0)
*/
+#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
/*
* Register map
*/
@@ -298,10 +298,9 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
inb(dev->iobase + RTI800_ADCHI);
outb(0, dev->iobase + RTI800_CLRFLAGS);
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
devpriv->adc_2comp = (it->options[4] == 0);
devpriv->dac_2comp[0] = (it->options[6] == 0);
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index 9e744505548..a3fa2a4baef 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -32,10 +32,9 @@ Configuration Options:
[17] - dac#7 ...
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-
#define RTI802_SIZE 4
#define RTI802_SELECT 0
@@ -93,10 +92,9 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index e1587e58a73..d629463b85a 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -36,8 +36,8 @@ comedi_config /dev/comedi0 s526 0x2C0,0x3
*/
+#include <linux/module.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
#include <asm/byteorder.h>
#define S526_SIZE 64
@@ -515,32 +515,35 @@ static int s526_dio_insn_bits(struct comedi_device *dev,
static int s526_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
- int group, mask;
+ unsigned int mask;
+ int ret;
+
+ if (chan < 4)
+ mask = 0x0f;
+ else
+ mask = 0xf0;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+ if (ret)
+ return ret;
+
+ /* bit 10/11 set the group 1/2's mode */
+ if (s->io_bits & 0x0f)
+ s->state |= (1 << 10);
+ else
+ s->state &= ~(1 << 10);
+ if (s->io_bits & 0xf0)
+ s->state |= (1 << 11);
+ else
+ s->state &= ~(1 << 11);
- group = chan >> 2;
- mask = 0xF << (group << 2);
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- /* bit 10/11 set the group 1/2's mode */
- s->state |= 1 << (group + 10);
- s->io_bits |= mask;
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->state &= ~(1 << (group + 10)); /* 1 is output, 0 is input. */
- s->io_bits &= ~mask;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- default:
- return -EINVAL;
- }
outw(s->state, dev->iobase + REG_DIO);
- return 1;
+ return insn->n;
}
static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -553,10 +556,9 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 48c4b70b736..d22b95dcb9b 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -59,6 +59,8 @@ INSN_CONFIG instructions:
comedi_do_insn(cf,&insn); //executing configuration
*/
+#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -1660,24 +1662,12 @@ static int s626_dio_insn_config(struct comedi_device *dev,
unsigned int *data)
{
unsigned long group = (unsigned long)s->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int mask = 1 << chan;
+ int ret;
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
- switch (data[0]) {
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- case COMEDI_INPUT:
- s->io_bits &= ~mask;
- break;
- case COMEDI_OUTPUT:
- s->io_bits |= mask;
- break;
- default:
- return -EINVAL;
- break;
- }
DEBIwrite(dev, LP_WRDOUT(group), s->io_bits);
return insn->n;
@@ -2585,10 +2575,9 @@ static int s626_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
ret = comedi_pci_enable(dev);
if (ret)
diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h
index d2756b83b62..a85e6bdcad0 100644
--- a/drivers/staging/comedi/drivers/s626.h
+++ b/drivers/staging/comedi/drivers/s626.h
@@ -65,8 +65,6 @@
#define FALSE (0)
#endif
-#include <linux/slab.h>
-
#define S626_SIZE 0x0200
#define DMABUF_SIZE 4096 /* 4k pages */
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index b4f5fe35b0f..441813ffb17 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -26,10 +26,10 @@ Status: in development
*/
+#include <linux/module.h>
#include "../comedidev.h"
#include <linux/delay.h>
-#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -719,10 +719,9 @@ static int serial2002_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
devpriv->port = it->options[0];
devpriv->speed = it->options[1];
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index 06aee302bbc..9e964950a56 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -67,6 +67,7 @@ Configuration Options:
* options that are used with comedi_config.
*/
+#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
@@ -361,31 +362,27 @@ static int skel_dio_insn_bits(struct comedi_device *dev,
static int skel_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int chan = CR_CHAN(insn->chanspec);
+ int ret;
- /* The input or output configuration of each digital line is
- * configured by a special insn_config instruction. chanspec
- * contains the channel to be changed, and data[0] contains the
- * value COMEDI_INPUT or COMEDI_OUTPUT. */
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= 1 << chan;
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~(1 << chan);
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- break;
- }
- /* outw(s->io_bits,dev->iobase + SKEL_DIO_CONFIG); */
+ /*
+ * The input or output configuration of each digital line is
+ * configured by special insn_config instructions.
+ *
+ * chanspec contains the channel to be changed
+ * data[0] contains the instruction to perform on the channel
+ *
+ * Normally the core provided comedi_dio_insn_config() function
+ * can be used to handle the boilerplpate.
+ */
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
+
+ /* Update the hardware to the new configuration */
+ /* outw(s->io_bits, dev->iobase + SKEL_DIO_CONFIG); */
return insn->n;
}
@@ -484,10 +481,9 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* dev->board_name = thisboard->name; */
/* Allocate the private data */
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
/*
* Supported boards are usually either auto-attached via the
@@ -558,10 +554,9 @@ static int skel_auto_attach(struct comedi_device *dev,
dev->board_name = thisboard->name;
/* Allocate the private data */
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
/* Enable the PCI device. */
ret = comedi_pci_enable(dev);
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index 45c661cbdbb..11758a515c1 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -26,6 +26,7 @@ Status: unknown
/* include files ----------------------------------------------------------- */
+#include <linux/module.h>
#include "../comedidev.h"
/* Some global definitions: the registers of the DNP ----------------------- */
@@ -92,68 +93,48 @@ static int dnp_dio_insn_bits(struct comedi_device *dev,
}
-/* ------------------------------------------------------------------------- */
-/* Configure the direction of the bidirectional digital i/o pins. chanspec */
-/* contains the channel to be changed and data[0] contains either */
-/* COMEDI_INPUT or COMEDI_OUTPUT. */
-/* ------------------------------------------------------------------------- */
-
static int dnp_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask;
+ unsigned int val;
+ int ret;
- u8 register_buffer;
-
- /* reduces chanspec to lower 16 bits */
- int chan = CR_CHAN(insn->chanspec);
-
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- case INSN_CONFIG_DIO_INPUT:
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (inb(CSCDR) & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- break;
- }
- /* Test: which port does the channel belong to? */
-
- /* We have to pay attention with port C: this is the meaning of PCMR: */
- /* Bit in PCMR: 7 6 5 4 3 2 1 0 */
- /* Corresponding port C pin: d 3 d 2 d 1 d 0 d= don't touch */
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
- if ((chan >= 0) && (chan <= 7)) {
- /* this is port A */
+ if (chan < 8) { /* Port A */
+ mask = 1 << chan;
outb(PAMR, CSCIR);
- } else if ((chan >= 8) && (chan <= 15)) {
- /* this is port B */
- chan -= 8;
+ } else if (chan < 16) { /* Port B */
+ mask = 1 << (chan - 8);
outb(PBMR, CSCIR);
- } else if ((chan >= 16) && (chan <= 19)) {
- /* this is port C; multiplication with 2 brings bits into */
- /* correct position for PCMR! */
- chan -= 16;
- chan *= 2;
+ } else { /* Port C */
+ /*
+ * We have to pay attention with port C.
+ * This is the meaning of PCMR:
+ * Bit in PCMR: 7 6 5 4 3 2 1 0
+ * Corresponding port C pin: d 3 d 2 d 1 d 0 d= don't touch
+ *
+ * Multiplication by 2 brings bits into correct position
+ * for PCMR!
+ */
+ mask = 1 << ((chan - 16) * 2);
outb(PCMR, CSCIR);
- } else {
- return -EINVAL;
}
- /* read 'old' direction of the port and set bits (out=1, in=0) */
- register_buffer = inb(CSCDR);
+ val = inb(CSCDR);
if (data[0] == COMEDI_OUTPUT)
- register_buffer |= (1 << chan);
+ val |= mask;
else
- register_buffer &= ~(1 << chan);
-
- outb(register_buffer, CSCDR);
+ val &= ~mask;
+ outb(val, CSCDR);
- return 1;
+ return insn->n;
}
diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c
index c9201d821fb..93eec2fc254 100644
--- a/drivers/staging/comedi/drivers/unioxx5.c
+++ b/drivers/staging/comedi/drivers/unioxx5.c
@@ -40,9 +40,9 @@ Devices: [Fastwel] UNIOxx-5 (unioxx5),
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/delay.h>
#include "../comedidev.h"
-#include <linux/ioport.h>
-#include <linux/slab.h>
#define DRIVER_NAME "unioxx5"
#define UNIOXX5_SIZE 0x10
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 279e5bd493f..701ad1a6939 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -78,9 +78,6 @@ sampling rate. If you sample two channels you get 4kHz and so on.
*
*/
-/* generates loads of debug info */
-/* #define NOISY_DUX_DEBUGBUG */
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -94,42 +91,29 @@ sampling rate. If you sample two channels you get 4kHz and so on.
#include "comedi_fc.h"
-/* timeout for the USB-transfer in ms*/
-#define BULK_TIMEOUT 1000
-
-/* constants for "firmware" upload and download */
-#define FIRMWARE "usbdux_firmware.bin"
-#define USBDUXSUB_FIRMWARE 0xA0
-#define VENDOR_DIR_IN 0xC0
-#define VENDOR_DIR_OUT 0x40
-
-/* internal addresses of the 8051 processor */
-#define USBDUXSUB_CPUCS 0xE600
-
-/*
- * the minor device number, major is 180 only for debugging purposes and to
- * upload special firmware (programming the eeprom etc) which is not compatible
- * with the comedi framwork
- */
-#define USBDUXSUB_MINOR 32
-
-/* max lenghth of the transfer-buffer for software upload */
-#define TB_LEN 0x2000
-
-/* Input endpoint number: ISO/IRQ */
-#define ISOINEP 6
-
-/* Output endpoint number: ISO/IRQ */
-#define ISOOUTEP 2
-
-/* This EP sends DUX commands to USBDUX */
-#define COMMAND_OUT_EP 1
-
-/* This EP receives the DUX commands from USBDUX */
-#define COMMAND_IN_EP 8
-
-/* Output endpoint for PWM */
-#define PWM_EP 4
+/* constants for firmware upload and download */
+#define USBDUX_FIRMWARE "usbdux_firmware.bin"
+#define USBDUX_FIRMWARE_MAX_LEN 0x2000
+#define USBDUX_FIRMWARE_CMD 0xa0
+#define VENDOR_DIR_IN 0xc0
+#define VENDOR_DIR_OUT 0x40
+#define USBDUX_CPU_CS 0xe600
+
+/* usbdux bulk transfer commands */
+#define USBDUX_CMD_MULT_AI 0
+#define USBDUX_CMD_AO 1
+#define USBDUX_CMD_DIO_CFG 2
+#define USBDUX_CMD_DIO_BITS 3
+#define USBDUX_CMD_SINGLE_AI 4
+#define USBDUX_CMD_TIMER_RD 5
+#define USBDUX_CMD_TIMER_WR 6
+#define USBDUX_CMD_PWM_ON 7
+#define USBDUX_CMD_PWM_OFF 8
+
+#define USBDUX_NUM_AO_CHAN 4
+
+/* timeout for the USB-transfer in ms */
+#define BULK_TIMEOUT 1000
/* 300Hz max frequ under PWM */
#define MIN_PWM_PERIOD ((long)(1E9/300))
@@ -137,9 +121,6 @@ sampling rate. If you sample two channels you get 4kHz and so on.
/* Default PWM frequency */
#define PWM_DEFAULT_PERIOD ((long)(1E9/100))
-/* Number of channels */
-#define NUMCHANNELS 8
-
/* Size of one A/D value */
#define SIZEADIN ((sizeof(int16_t)))
@@ -152,9 +133,6 @@ sampling rate. If you sample two channels you get 4kHz and so on.
/* 16 bytes. */
#define SIZEINSNBUF 16
-/* Number of DA channels */
-#define NUMOUTCHANNELS 8
-
/* size of one value for the D/A converter: channel and value */
#define SIZEDAOUT ((sizeof(int8_t)+sizeof(int16_t)))
@@ -185,101 +163,56 @@ sampling rate. If you sample two channels you get 4kHz and so on.
/* must have more buffers due to buggy USB ctr */
#define NUMOFOUTBUFFERSHIGH 10
-/* Total number of usbdux devices */
-#define NUMUSBDUX 16
-
-/* Analogue in subdevice */
-#define SUBDEV_AD 0
-
-/* Analogue out subdevice */
-#define SUBDEV_DA 1
-
-/* Digital I/O */
-#define SUBDEV_DIO 2
-
-/* counter */
-#define SUBDEV_COUNTER 3
-
-/* timer aka pwm output */
-#define SUBDEV_PWM 4
-
/* number of retries to get the right dux command */
#define RETRIES 10
-/**************************************************/
-/* comedi constants */
-static const struct comedi_lrange range_usbdux_ai_range = { 4, {
- BIP_RANGE
- (4.096),
- BIP_RANGE(4.096
- / 2),
- UNI_RANGE
- (4.096),
- UNI_RANGE(4.096
- / 2)
- }
+static const struct comedi_lrange range_usbdux_ai_range = {
+ 4, {
+ BIP_RANGE(4.096),
+ BIP_RANGE(4.096 / 2),
+ UNI_RANGE(4.096),
+ UNI_RANGE(4.096 / 2)
+ }
};
-static const struct comedi_lrange range_usbdux_ao_range = { 2, {
- BIP_RANGE
- (4.096),
- UNI_RANGE
- (4.096),
- }
+static const struct comedi_lrange range_usbdux_ao_range = {
+ 2, {
+ BIP_RANGE(4.096),
+ UNI_RANGE(4.096)
+ }
};
-/*
- * private structure of one subdevice
- */
-
-/*
- * This is the structure which holds all the data of
- * this driver one sub device just now: A/D
- */
-struct usbduxsub {
- /* attached? */
- int attached;
- /* is it associated with a subdevice? */
- int probed;
- /* pointer to the usb-device */
- struct usb_device *usbdev;
+struct usbdux_private {
/* actual number of in-buffers */
- int num_in_buffers;
+ int n_ai_urbs;
/* actual number of out-buffers */
- int num_out_buffers;
+ int n_ao_urbs;
/* ISO-transfer handling: buffers */
- struct urb **urb_in;
- struct urb **urb_out;
+ struct urb **ai_urbs;
+ struct urb **ao_urbs;
/* pwm-transfer handling */
- struct urb *urb_pwm;
+ struct urb *pwm_urb;
/* PWM period */
unsigned int pwm_period;
/* PWM internal delay for the GPIF in the FX2 */
- int8_t pwn_delay;
+ int8_t pwm_delay;
/* size of the PWM buffer which holds the bit pattern */
- int size_pwm_buf;
+ int pwm_buf_sz;
/* input buffer for the ISO-transfer */
- int16_t *in_buffer;
+ int16_t *in_buf;
/* input buffer for single insn */
- int16_t *insn_buffer;
- /* output buffer for single DA outputs */
- int16_t *out_buffer;
- /* interface number */
- int ifnum;
- /* interface structure in 2.6 */
- struct usb_interface *interface;
- /* comedi device for the interrupt context */
- struct comedi_device *comedidev;
- /* is it USB_SPEED_HIGH or not? */
- short int high_speed;
- /* asynchronous command is running */
- short int ai_cmd_running;
- short int ao_cmd_running;
- /* pwm is running */
- short int pwm_cmd_running;
- /* continous acquisition */
- short int ai_continous;
- short int ao_continous;
+ int16_t *insn_buf;
+
+ int8_t ao_chanlist[USBDUX_NUM_AO_CHAN];
+ unsigned int ao_readback[USBDUX_NUM_AO_CHAN];
+
+ unsigned int high_speed:1;
+ unsigned int ai_cmd_running:1;
+ unsigned int ai_continous:1;
+ unsigned int ao_cmd_running:1;
+ unsigned int ao_continous:1;
+ unsigned int pwm_cmd_running:1;
+
/* number of samples to acquire */
int ai_sample_count;
int ao_sample_count;
@@ -291,132 +224,62 @@ struct usbduxsub {
unsigned int ao_counter;
/* interval in frames/uframes */
unsigned int ai_interval;
- /* D/A commands */
- int8_t *dac_commands;
/* commands */
int8_t *dux_commands;
struct semaphore sem;
};
-/*
- * The pointer to the private usb-data of the driver is also the private data
- * for the comedi-device. This has to be global as the usb subsystem needs
- * global variables. The other reason is that this structure must be there
- * _before_ any comedi command is issued. The usb subsystem must be initialised
- * before comedi can access it.
- */
-static struct usbduxsub usbduxsub[NUMUSBDUX];
-
-static DEFINE_SEMAPHORE(start_stop_sem);
-
-/*
- * Stops the data acquision
- * It should be safe to call this function from any context
- */
-static int usbduxsub_unlink_inurbs(struct usbduxsub *usbduxsub_tmp)
+static void usbdux_unlink_urbs(struct urb **urbs, int num_urbs)
{
- int i = 0;
- int err = 0;
+ int i;
- if (usbduxsub_tmp && usbduxsub_tmp->urb_in) {
- for (i = 0; i < usbduxsub_tmp->num_in_buffers; i++) {
- if (usbduxsub_tmp->urb_in[i]) {
- /* We wait here until all transfers have been
- * cancelled. */
- usb_kill_urb(usbduxsub_tmp->urb_in[i]);
- }
- dev_dbg(&usbduxsub_tmp->interface->dev,
- "comedi: usbdux: unlinked InURB %d, err=%d\n",
- i, err);
- }
- }
- return err;
+ for (i = 0; i < num_urbs; i++)
+ usb_kill_urb(urbs[i]);
}
-/*
- * This will stop a running acquisition operation
- * Is called from within this driver from both the
- * interrupt context and from comedi
- */
-static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
+static void usbdux_ai_stop(struct comedi_device *dev, int do_unlink)
{
- int ret = 0;
-
- if (!this_usbduxsub) {
- pr_err("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n");
- return -EFAULT;
- }
- dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_stop\n");
+ struct usbdux_private *devpriv = dev->private;
- if (do_unlink) {
- /* stop aquistion */
- ret = usbduxsub_unlink_inurbs(this_usbduxsub);
- }
+ if (do_unlink && devpriv->ai_urbs)
+ usbdux_unlink_urbs(devpriv->ai_urbs, devpriv->n_ai_urbs);
- this_usbduxsub->ai_cmd_running = 0;
-
- return ret;
+ devpriv->ai_cmd_running = 0;
}
-/*
- * This will cancel a running acquisition operation.
- * This is called by comedi but never from inside the driver.
- */
static int usbdux_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- struct usbduxsub *this_usbduxsub;
- int res = 0;
-
- /* force unlink of all urbs */
- this_usbduxsub = dev->private;
- if (!this_usbduxsub)
- return -EFAULT;
-
- dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_cancel\n");
+ struct usbdux_private *devpriv = dev->private;
/* prevent other CPUs from submitting new commands just now */
- down(&this_usbduxsub->sem);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
+ down(&devpriv->sem);
/* unlink only if the urb really has been submitted */
- res = usbdux_ai_stop(this_usbduxsub, this_usbduxsub->ai_cmd_running);
- up(&this_usbduxsub->sem);
- return res;
+ usbdux_ai_stop(dev, devpriv->ai_cmd_running);
+ up(&devpriv->sem);
+
+ return 0;
}
/* analogue IN - interrupt service routine */
static void usbduxsub_ai_isoc_irq(struct urb *urb)
{
+ struct comedi_device *dev = urb->context;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct usbdux_private *devpriv = dev->private;
int i, err, n;
- struct usbduxsub *this_usbduxsub;
- struct comedi_device *this_comedidev;
- struct comedi_subdevice *s;
-
- /* the context variable points to the subdevice */
- this_comedidev = urb->context;
- /* the private structure of the subdevice is struct usbduxsub */
- this_usbduxsub = this_comedidev->private;
- /* subdevice which is the AD converter */
- s = &this_comedidev->subdevices[SUBDEV_AD];
/* first we test if something unusual has just happened */
switch (urb->status) {
case 0:
/* copy the result in the transfer buffer */
- memcpy(this_usbduxsub->in_buffer,
- urb->transfer_buffer, SIZEINBUF);
+ memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF);
break;
case -EILSEQ:
/* error in the ISOchronous data */
/* we don't copy the data into the transfer buffer */
/* and recycle the last data byte */
- dev_dbg(&urb->dev->dev,
- "comedi%d: usbdux: CRC error in ISO IN stream.\n",
- this_usbduxsub->comedidev->minor);
-
+ dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n");
break;
case -ECONNRESET:
@@ -424,29 +287,27 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb)
case -ESHUTDOWN:
case -ECONNABORTED:
/* happens after an unlink command */
- if (this_usbduxsub->ai_cmd_running) {
- /* we are still running a command */
- /* tell this comedi */
+ if (devpriv->ai_cmd_running) {
s->async->events |= COMEDI_CB_EOA;
s->async->events |= COMEDI_CB_ERROR;
- comedi_event(this_usbduxsub->comedidev, s);
+ comedi_event(dev, s);
/* stop the transfer w/o unlink */
- usbdux_ai_stop(this_usbduxsub, 0);
+ usbdux_ai_stop(dev, 0);
}
return;
default:
/* a real error on the bus */
/* pass error to comedi if we are really running a command */
- if (this_usbduxsub->ai_cmd_running) {
- dev_err(&urb->dev->dev,
- "Non-zero urb status received in ai intr "
- "context: %d\n", urb->status);
+ if (devpriv->ai_cmd_running) {
+ dev_err(dev->class_dev,
+ "Non-zero urb status received in ai intr context: %d\n",
+ urb->status);
s->async->events |= COMEDI_CB_EOA;
s->async->events |= COMEDI_CB_ERROR;
- comedi_event(this_usbduxsub->comedidev, s);
+ comedi_event(dev, s);
/* don't do an unlink here */
- usbdux_ai_stop(this_usbduxsub, 0);
+ usbdux_ai_stop(dev, 0);
}
return;
}
@@ -455,7 +316,7 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb)
* at this point we are reasonably sure that nothing dodgy has happened
* are we running a command?
*/
- if (unlikely((!(this_usbduxsub->ai_cmd_running)))) {
+ if (unlikely(!devpriv->ai_cmd_running)) {
/*
* not running a command, do not continue execution if no
* asynchronous command is running in particular not resubmit
@@ -463,144 +324,101 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb)
return;
}
- urb->dev = this_usbduxsub->usbdev;
+ urb->dev = comedi_to_usb_dev(dev);
/* resubmit the urb */
err = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(err < 0)) {
- dev_err(&urb->dev->dev,
- "comedi_: urb resubmit failed in int-context! err=%d\n",
- err);
+ dev_err(dev->class_dev,
+ "urb resubmit failed in int-context! err=%d\n", err);
if (err == -EL2NSYNC)
- dev_err(&urb->dev->dev,
- "buggy USB host controller or bug in IRQ "
- "handler!\n");
+ dev_err(dev->class_dev,
+ "buggy USB host controller or bug in IRQ handler!\n");
s->async->events |= COMEDI_CB_EOA;
s->async->events |= COMEDI_CB_ERROR;
- comedi_event(this_usbduxsub->comedidev, s);
+ comedi_event(dev, s);
/* don't do an unlink here */
- usbdux_ai_stop(this_usbduxsub, 0);
+ usbdux_ai_stop(dev, 0);
return;
}
- this_usbduxsub->ai_counter--;
- if (likely(this_usbduxsub->ai_counter > 0))
+ devpriv->ai_counter--;
+ if (likely(devpriv->ai_counter > 0))
return;
/* timer zero, transfer measurements to comedi */
- this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
+ devpriv->ai_counter = devpriv->ai_timer;
/* test, if we transmit only a fixed number of samples */
- if (!(this_usbduxsub->ai_continous)) {
+ if (!devpriv->ai_continous) {
/* not continuous, fixed number of samples */
- this_usbduxsub->ai_sample_count--;
+ devpriv->ai_sample_count--;
/* all samples received? */
- if (this_usbduxsub->ai_sample_count < 0) {
+ if (devpriv->ai_sample_count < 0) {
/* prevent a resubmit next time */
- usbdux_ai_stop(this_usbduxsub, 0);
+ usbdux_ai_stop(dev, 0);
/* say comedi that the acquistion is over */
s->async->events |= COMEDI_CB_EOA;
- comedi_event(this_usbduxsub->comedidev, s);
+ comedi_event(dev, s);
return;
}
}
/* get the data from the USB bus and hand it over to comedi */
n = s->async->cmd.chanlist_len;
for (i = 0; i < n; i++) {
+ unsigned int range = CR_RANGE(s->async->cmd.chanlist[i]);
+ int16_t val = le16_to_cpu(devpriv->in_buf[i]);
+
+ /* bipolar data is two's-complement */
+ if (comedi_range_is_bipolar(s, range))
+ val ^= ((s->maxdata + 1) >> 1);
+
/* transfer data */
- if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) {
- err = comedi_buf_put
- (s->async,
- le16_to_cpu(this_usbduxsub->in_buffer[i]) ^ 0x800);
- } else {
- err = comedi_buf_put
- (s->async,
- le16_to_cpu(this_usbduxsub->in_buffer[i]));
- }
+ err = comedi_buf_put(s->async, val);
if (unlikely(err == 0)) {
/* buffer overflow */
- usbdux_ai_stop(this_usbduxsub, 0);
+ usbdux_ai_stop(dev, 0);
return;
}
}
/* tell comedi that data is there */
s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
- comedi_event(this_usbduxsub->comedidev, s);
-}
-
-static int usbduxsub_unlink_outurbs(struct usbduxsub *usbduxsub_tmp)
-{
- int i = 0;
- int err = 0;
-
- if (usbduxsub_tmp && usbduxsub_tmp->urb_out) {
- for (i = 0; i < usbduxsub_tmp->num_out_buffers; i++) {
- if (usbduxsub_tmp->urb_out[i])
- usb_kill_urb(usbduxsub_tmp->urb_out[i]);
-
- dev_dbg(&usbduxsub_tmp->interface->dev,
- "comedi: usbdux: unlinked OutURB %d: res=%d\n",
- i, err);
- }
- }
- return err;
+ comedi_event(dev, s);
}
-/* This will cancel a running acquisition operation
- * in any context.
- */
-static int usbdux_ao_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
+static void usbdux_ao_stop(struct comedi_device *dev, int do_unlink)
{
- int ret = 0;
-
- if (!this_usbduxsub)
- return -EFAULT;
- dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ao_cancel\n");
-
- if (do_unlink)
- ret = usbduxsub_unlink_outurbs(this_usbduxsub);
+ struct usbdux_private *devpriv = dev->private;
- this_usbduxsub->ao_cmd_running = 0;
+ if (do_unlink && devpriv->ao_urbs)
+ usbdux_unlink_urbs(devpriv->ao_urbs, devpriv->n_ao_urbs);
- return ret;
+ devpriv->ao_cmd_running = 0;
}
-/* force unlink, is called by comedi */
static int usbdux_ao_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- struct usbduxsub *this_usbduxsub = dev->private;
- int res = 0;
-
- if (!this_usbduxsub)
- return -EFAULT;
+ struct usbdux_private *devpriv = dev->private;
/* prevent other CPUs from submitting a command just now */
- down(&this_usbduxsub->sem);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
+ down(&devpriv->sem);
/* unlink only if it is really running */
- res = usbdux_ao_stop(this_usbduxsub, this_usbduxsub->ao_cmd_running);
- up(&this_usbduxsub->sem);
- return res;
+ usbdux_ao_stop(dev, devpriv->ao_cmd_running);
+ up(&devpriv->sem);
+
+ return 0;
}
static void usbduxsub_ao_isoc_irq(struct urb *urb)
{
- int i, ret;
+ struct comedi_device *dev = urb->context;
+ struct comedi_subdevice *s = dev->write_subdev;
+ struct usbdux_private *devpriv = dev->private;
int8_t *datap;
- struct usbduxsub *this_usbduxsub;
- struct comedi_device *this_comedidev;
- struct comedi_subdevice *s;
-
- /* the context variable points to the subdevice */
- this_comedidev = urb->context;
- /* the private structure of the subdevice is struct usbduxsub */
- this_usbduxsub = this_comedidev->private;
-
- s = &this_comedidev->subdevices[SUBDEV_DA];
+ int len;
+ int ret;
+ int i;
switch (urb->status) {
case 0:
@@ -613,246 +431,131 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb)
case -ECONNABORTED:
/* after an unlink command, unplug, ... etc */
/* no unlink needed here. Already shutting down. */
- if (this_usbduxsub->ao_cmd_running) {
+ if (devpriv->ao_cmd_running) {
s->async->events |= COMEDI_CB_EOA;
- comedi_event(this_usbduxsub->comedidev, s);
- usbdux_ao_stop(this_usbduxsub, 0);
+ comedi_event(dev, s);
+ usbdux_ao_stop(dev, 0);
}
return;
default:
/* a real error */
- if (this_usbduxsub->ao_cmd_running) {
- dev_err(&urb->dev->dev,
- "comedi_: Non-zero urb status received in ao "
- "intr context: %d\n", urb->status);
+ if (devpriv->ao_cmd_running) {
+ dev_err(dev->class_dev,
+ "Non-zero urb status received in ao intr context: %d\n",
+ urb->status);
s->async->events |= COMEDI_CB_ERROR;
s->async->events |= COMEDI_CB_EOA;
- comedi_event(this_usbduxsub->comedidev, s);
+ comedi_event(dev, s);
/* we do an unlink if we are in the high speed mode */
- usbdux_ao_stop(this_usbduxsub, 0);
+ usbdux_ao_stop(dev, 0);
}
return;
}
/* are we actually running? */
- if (!(this_usbduxsub->ao_cmd_running))
+ if (!devpriv->ao_cmd_running)
return;
/* normal operation: executing a command in this subdevice */
- this_usbduxsub->ao_counter--;
- if ((int)this_usbduxsub->ao_counter <= 0) {
+ devpriv->ao_counter--;
+ if ((int)devpriv->ao_counter <= 0) {
/* timer zero */
- this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
+ devpriv->ao_counter = devpriv->ao_timer;
/* handle non continous acquisition */
- if (!(this_usbduxsub->ao_continous)) {
+ if (!devpriv->ao_continous) {
/* fixed number of samples */
- this_usbduxsub->ao_sample_count--;
- if (this_usbduxsub->ao_sample_count < 0) {
+ devpriv->ao_sample_count--;
+ if (devpriv->ao_sample_count < 0) {
/* all samples transmitted */
- usbdux_ao_stop(this_usbduxsub, 0);
+ usbdux_ao_stop(dev, 0);
s->async->events |= COMEDI_CB_EOA;
- comedi_event(this_usbduxsub->comedidev, s);
+ comedi_event(dev, s);
/* no resubmit of the urb */
return;
}
}
+
/* transmit data to the USB bus */
- ((uint8_t *) (urb->transfer_buffer))[0] =
- s->async->cmd.chanlist_len;
+ datap = urb->transfer_buffer;
+ len = s->async->cmd.chanlist_len;
+ *datap++ = len;
for (i = 0; i < s->async->cmd.chanlist_len; i++) {
- short temp;
- if (i >= NUMOUTCHANNELS)
- break;
+ unsigned int chan = devpriv->ao_chanlist[i];
+ short val;
- /* pointer to the DA */
- datap =
- (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1]));
- /* get the data from comedi */
- ret = comedi_buf_get(s->async, &temp);
- datap[0] = temp;
- datap[1] = temp >> 8;
- datap[2] = this_usbduxsub->dac_commands[i];
- /* printk("data[0]=%x, data[1]=%x, data[2]=%x\n", */
- /* datap[0],datap[1],datap[2]); */
+ ret = comedi_buf_get(s->async, &val);
if (ret < 0) {
- dev_err(&urb->dev->dev,
- "comedi: buffer underflow\n");
- s->async->events |= COMEDI_CB_EOA;
- s->async->events |= COMEDI_CB_OVERFLOW;
+ dev_err(dev->class_dev, "buffer underflow\n");
+ s->async->events |= (COMEDI_CB_EOA |
+ COMEDI_CB_OVERFLOW);
}
- /* transmit data to comedi */
+ /* pointer to the DA */
+ *datap++ = val & 0xff;
+ *datap++ = (val >> 8) & 0xff;
+ *datap++ = chan;
+ devpriv->ao_readback[chan] = val;
+
s->async->events |= COMEDI_CB_BLOCK;
- comedi_event(this_usbduxsub->comedidev, s);
+ comedi_event(dev, s);
}
}
urb->transfer_buffer_length = SIZEOUTBUF;
- urb->dev = this_usbduxsub->usbdev;
+ urb->dev = comedi_to_usb_dev(dev);
urb->status = 0;
- if (this_usbduxsub->ao_cmd_running) {
- if (this_usbduxsub->high_speed) {
- /* uframes */
- urb->interval = 8;
- } else {
- /* frames */
- urb->interval = 1;
- }
+ if (devpriv->ao_cmd_running) {
+ if (devpriv->high_speed)
+ urb->interval = 8; /* uframes */
+ else
+ urb->interval = 1; /* frames */
urb->number_of_packets = 1;
urb->iso_frame_desc[0].offset = 0;
urb->iso_frame_desc[0].length = SIZEOUTBUF;
urb->iso_frame_desc[0].status = 0;
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) {
- dev_err(&urb->dev->dev,
- "comedi_: ao urb resubm failed in int-cont. "
- "ret=%d", ret);
+ dev_err(dev->class_dev,
+ "ao urb resubm failed in int-cont. ret=%d",
+ ret);
if (ret == EL2NSYNC)
- dev_err(&urb->dev->dev,
- "buggy USB host controller or bug in "
- "IRQ handling!\n");
+ dev_err(dev->class_dev,
+ "buggy USB host controller or bug in IRQ handling!\n");
s->async->events |= COMEDI_CB_EOA;
s->async->events |= COMEDI_CB_ERROR;
- comedi_event(this_usbduxsub->comedidev, s);
+ comedi_event(dev, s);
/* don't do an unlink here */
- usbdux_ao_stop(this_usbduxsub, 0);
+ usbdux_ao_stop(dev, 0);
}
}
}
-#define FIRMWARE_MAX_LEN 0x2000
-
-static int usbdux_firmware_upload(struct comedi_device *dev,
- const u8 *data, size_t size,
- unsigned long context)
+static int usbdux_submit_urbs(struct comedi_device *dev,
+ struct urb **urbs, int num_urbs,
+ int input_urb)
{
- struct usbduxsub *usbduxsub = dev->private;
- struct usb_device *usb = usbduxsub->usbdev;
- uint8_t *buf;
- uint8_t *tmp;
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct usbdux_private *devpriv = dev->private;
+ struct urb *urb;
int ret;
-
- if (!data)
- return 0;
-
- if (size > FIRMWARE_MAX_LEN) {
- dev_err(&usbduxsub->interface->dev,
- "usbdux firmware binary it too large for FX2.\n");
- return -ENOMEM;
- }
-
- /* we generate a local buffer for the firmware */
- buf = kmemdup(data, size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- /* we need a malloc'ed buffer for usb_control_msg() */
- tmp = kmalloc(1, GFP_KERNEL);
- if (!tmp) {
- kfree(buf);
- return -ENOMEM;
- }
-
- /* stop the current firmware on the device */
- *tmp = 1; /* 7f92 to one */
- ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
- USBDUXSUB_FIRMWARE,
- VENDOR_DIR_OUT,
- USBDUXSUB_CPUCS, 0x0000,
- tmp, 1,
- BULK_TIMEOUT);
- if (ret < 0) {
- dev_err(&usbduxsub->interface->dev,
- "comedi_: can not stop firmware\n");
- goto done;
- }
-
- /* upload the new firmware to the device */
- ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
- USBDUXSUB_FIRMWARE,
- VENDOR_DIR_OUT,
- 0, 0x0000,
- buf, size,
- BULK_TIMEOUT);
- if (ret < 0) {
- dev_err(&usbduxsub->interface->dev,
- "comedi_: firmware upload failed\n");
- goto done;
- }
-
- /* start the new firmware on the device */
- *tmp = 0; /* 7f92 to zero */
- ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
- USBDUXSUB_FIRMWARE,
- VENDOR_DIR_OUT,
- USBDUXSUB_CPUCS, 0x0000,
- tmp, 1,
- BULK_TIMEOUT);
- if (ret < 0)
- dev_err(&usbduxsub->interface->dev,
- "comedi_: can not start firmware\n");
-
-done:
- kfree(tmp);
- kfree(buf);
- return ret;
-}
-
-static int usbduxsub_submit_inurbs(struct usbduxsub *usbduxsub)
-{
- int i, err_flag;
-
- if (!usbduxsub)
- return -EFAULT;
+ int i;
/* Submit all URBs and start the transfer on the bus */
- for (i = 0; i < usbduxsub->num_in_buffers; i++) {
- /* in case of a resubmission after an unlink... */
- usbduxsub->urb_in[i]->interval = usbduxsub->ai_interval;
- usbduxsub->urb_in[i]->context = usbduxsub->comedidev;
- usbduxsub->urb_in[i]->dev = usbduxsub->usbdev;
- usbduxsub->urb_in[i]->status = 0;
- usbduxsub->urb_in[i]->transfer_flags = URB_ISO_ASAP;
- dev_dbg(&usbduxsub->interface->dev,
- "comedi%d: submitting in-urb[%d]: %p,%p intv=%d\n",
- usbduxsub->comedidev->minor, i,
- (usbduxsub->urb_in[i]->context),
- (usbduxsub->urb_in[i]->dev),
- (usbduxsub->urb_in[i]->interval));
- err_flag = usb_submit_urb(usbduxsub->urb_in[i], GFP_ATOMIC);
- if (err_flag) {
- dev_err(&usbduxsub->interface->dev,
- "comedi_: ai: usb_submit_urb(%d) error %d\n",
- i, err_flag);
- return err_flag;
- }
- }
- return 0;
-}
+ for (i = 0; i < num_urbs; i++) {
+ urb = urbs[i];
-static int usbduxsub_submit_outurbs(struct usbduxsub *usbduxsub)
-{
- int i, err_flag;
-
- if (!usbduxsub)
- return -EFAULT;
-
- for (i = 0; i < usbduxsub->num_out_buffers; i++) {
- dev_dbg(&usbduxsub->interface->dev,
- "comedi_: submitting out-urb[%d]\n", i);
/* in case of a resubmission after an unlink... */
- usbduxsub->urb_out[i]->context = usbduxsub->comedidev;
- usbduxsub->urb_out[i]->dev = usbduxsub->usbdev;
- usbduxsub->urb_out[i]->status = 0;
- usbduxsub->urb_out[i]->transfer_flags = URB_ISO_ASAP;
- err_flag = usb_submit_urb(usbduxsub->urb_out[i], GFP_ATOMIC);
- if (err_flag) {
- dev_err(&usbduxsub->interface->dev,
- "comedi_: ao: usb_submit_urb(%d) error %d\n",
- i, err_flag);
- return err_flag;
- }
+ if (input_urb)
+ urb->interval = devpriv->ai_interval;
+ urb->context = dev;
+ urb->dev = usb;
+ urb->status = 0;
+ urb->transfer_flags = URB_ISO_ASAP;
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ return ret;
}
return 0;
}
@@ -860,13 +563,10 @@ static int usbduxsub_submit_outurbs(struct usbduxsub *usbduxsub)
static int usbdux_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
- struct usbduxsub *this_usbduxsub = dev->private;
+ struct usbdux_private *this_usbduxsub = dev->private;
int err = 0, i;
unsigned int tmp_timer;
- if (!(this_usbduxsub->probed))
- return -ENODEV;
-
/* Step 1 : check if triggers are trivially valid */
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
@@ -956,221 +656,143 @@ static int8_t create_adc_command(unsigned int chan, int range)
return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3);
}
-/* bulk transfers to usbdux */
+static int send_dux_commands(struct comedi_device *dev, int cmd_type)
+{
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct usbdux_private *devpriv = dev->private;
+ int nsent;
-#define SENDADCOMMANDS 0
-#define SENDDACOMMANDS 1
-#define SENDDIOCONFIGCOMMAND 2
-#define SENDDIOBITSCOMMAND 3
-#define SENDSINGLEAD 4
-#define READCOUNTERCOMMAND 5
-#define WRITECOUNTERCOMMAND 6
-#define SENDPWMON 7
-#define SENDPWMOFF 8
+ devpriv->dux_commands[0] = cmd_type;
-static int send_dux_commands(struct usbduxsub *this_usbduxsub, int cmd_type)
-{
- int result, nsent;
-
- this_usbduxsub->dux_commands[0] = cmd_type;
-#ifdef NOISY_DUX_DEBUGBUG
- printk(KERN_DEBUG "comedi%d: usbdux: dux_commands: ",
- this_usbduxsub->comedidev->minor);
- for (result = 0; result < SIZEOFDUXBUFFER; result++)
- printk(" %02x", this_usbduxsub->dux_commands[result]);
- printk("\n");
-#endif
- result = usb_bulk_msg(this_usbduxsub->usbdev,
- usb_sndbulkpipe(this_usbduxsub->usbdev,
- COMMAND_OUT_EP),
- this_usbduxsub->dux_commands, SIZEOFDUXBUFFER,
- &nsent, BULK_TIMEOUT);
- if (result < 0)
- dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
- "could not transmit dux_command to the usb-device, "
- "err=%d\n", this_usbduxsub->comedidev->minor, result);
-
- return result;
+ return usb_bulk_msg(usb, usb_sndbulkpipe(usb, 1),
+ devpriv->dux_commands, SIZEOFDUXBUFFER,
+ &nsent, BULK_TIMEOUT);
}
-static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command)
+static int receive_dux_commands(struct comedi_device *dev, int command)
{
- int result = (-EFAULT);
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct usbdux_private *devpriv = dev->private;
+ int ret;
int nrec;
int i;
for (i = 0; i < RETRIES; i++) {
- result = usb_bulk_msg(this_usbduxsub->usbdev,
- usb_rcvbulkpipe(this_usbduxsub->usbdev,
- COMMAND_IN_EP),
- this_usbduxsub->insn_buffer, SIZEINSNBUF,
+ ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, 8),
+ devpriv->insn_buf, SIZEINSNBUF,
&nrec, BULK_TIMEOUT);
- if (result < 0) {
- dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
- "insn: USB error %d while receiving DUX command"
- "\n", this_usbduxsub->comedidev->minor, result);
- return result;
- }
- if (le16_to_cpu(this_usbduxsub->insn_buffer[0]) == command)
- return result;
+ if (ret < 0)
+ return ret;
+ if (le16_to_cpu(devpriv->insn_buf[0]) == command)
+ return ret;
}
- /* this is only reached if the data has been requested a couple of
- * times */
- dev_err(&this_usbduxsub->interface->dev, "comedi%d: insn: "
- "wrong data returned from firmware: want cmd %d, got cmd %d.\n",
- this_usbduxsub->comedidev->minor, command,
- le16_to_cpu(this_usbduxsub->insn_buffer[0]));
+ /* command not received */
return -EFAULT;
}
static int usbdux_ai_inttrig(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int trignum)
+ struct comedi_subdevice *s,
+ unsigned int trignum)
{
- int ret;
- struct usbduxsub *this_usbduxsub = dev->private;
- if (!this_usbduxsub)
- return -EFAULT;
+ struct usbdux_private *devpriv = dev->private;
+ int ret = -EINVAL;
- down(&this_usbduxsub->sem);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: usbdux_ai_inttrig\n", dev->minor);
-
- if (trignum != 0) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: usbdux_ai_inttrig: invalid trignum\n",
- dev->minor);
- up(&this_usbduxsub->sem);
- return -EINVAL;
- }
- if (!(this_usbduxsub->ai_cmd_running)) {
- this_usbduxsub->ai_cmd_running = 1;
- ret = usbduxsub_submit_inurbs(this_usbduxsub);
+ down(&devpriv->sem);
+
+ if (trignum != 0)
+ goto ai_trig_exit;
+
+ if (!devpriv->ai_cmd_running) {
+ devpriv->ai_cmd_running = 1;
+ ret = usbdux_submit_urbs(dev, devpriv->ai_urbs,
+ devpriv->n_ai_urbs, 1);
if (ret < 0) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: usbdux_ai_inttrig: "
- "urbSubmit: err=%d\n", dev->minor, ret);
- this_usbduxsub->ai_cmd_running = 0;
- up(&this_usbduxsub->sem);
- return ret;
+ devpriv->ai_cmd_running = 0;
+ goto ai_trig_exit;
}
s->async->inttrig = NULL;
} else {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: ai_inttrig but acqu is already running\n",
- dev->minor);
+ ret = -EBUSY;
}
- up(&this_usbduxsub->sem);
- return 1;
+
+ai_trig_exit:
+ up(&devpriv->sem);
+ return ret;
}
static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ struct usbdux_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- unsigned int chan, range;
- int i, ret;
- struct usbduxsub *this_usbduxsub = dev->private;
- int result;
-
- if (!this_usbduxsub)
- return -EFAULT;
-
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: usbdux_ai_cmd\n", dev->minor);
+ int len = cmd->chanlist_len;
+ int ret = -EBUSY;
+ int i;
/* block other CPUs from starting an ai_cmd */
- down(&this_usbduxsub->sem);
+ down(&devpriv->sem);
+
+ if (devpriv->ai_cmd_running)
+ goto ai_cmd_exit;
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
- if (this_usbduxsub->ai_cmd_running) {
- dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
- "ai_cmd not possible. Another ai_cmd is running.\n",
- dev->minor);
- up(&this_usbduxsub->sem);
- return -EBUSY;
- }
/* set current channel of the running acquisition to zero */
s->async->cur_chan = 0;
- this_usbduxsub->dux_commands[1] = cmd->chanlist_len;
- for (i = 0; i < cmd->chanlist_len; ++i) {
- chan = CR_CHAN(cmd->chanlist[i]);
- range = CR_RANGE(cmd->chanlist[i]);
- if (i >= NUMCHANNELS) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: channel list too long\n",
- dev->minor);
- break;
- }
- this_usbduxsub->dux_commands[i + 2] =
- create_adc_command(chan, range);
- }
-
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi %d: sending commands to the usb device: size=%u\n",
- dev->minor, NUMCHANNELS);
+ devpriv->dux_commands[1] = len;
+ for (i = 0; i < len; ++i) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
- result = send_dux_commands(this_usbduxsub, SENDADCOMMANDS);
- if (result < 0) {
- up(&this_usbduxsub->sem);
- return result;
+ devpriv->dux_commands[i + 2] = create_adc_command(chan, range);
}
- if (this_usbduxsub->high_speed) {
+ ret = send_dux_commands(dev, USBDUX_CMD_MULT_AI);
+ if (ret < 0)
+ goto ai_cmd_exit;
+
+ if (devpriv->high_speed) {
/*
* every channel gets a time window of 125us. Thus, if we
* sample all 8 channels we need 1ms. If we sample only one
* channel we need only 125us
*/
- this_usbduxsub->ai_interval = 1;
+ devpriv->ai_interval = 1;
/* find a power of 2 for the interval */
- while ((this_usbduxsub->ai_interval) < (cmd->chanlist_len)) {
- this_usbduxsub->ai_interval =
- (this_usbduxsub->ai_interval) * 2;
- }
- this_usbduxsub->ai_timer = cmd->scan_begin_arg / (125000 *
- (this_usbduxsub->
- ai_interval));
+ while (devpriv->ai_interval < len)
+ devpriv->ai_interval *= 2;
+
+ devpriv->ai_timer = cmd->scan_begin_arg /
+ (125000 * devpriv->ai_interval);
} else {
/* interval always 1ms */
- this_usbduxsub->ai_interval = 1;
- this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000;
+ devpriv->ai_interval = 1;
+ devpriv->ai_timer = cmd->scan_begin_arg / 1000000;
}
- if (this_usbduxsub->ai_timer < 1) {
- dev_err(&this_usbduxsub->interface->dev, "comedi%d: ai_cmd: "
- "timer=%d, scan_begin_arg=%d. "
- "Not properly tested by cmdtest?\n", dev->minor,
- this_usbduxsub->ai_timer, cmd->scan_begin_arg);
- up(&this_usbduxsub->sem);
- return -EINVAL;
+ if (devpriv->ai_timer < 1) {
+ ret = -EINVAL;
+ goto ai_cmd_exit;
}
- this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
+
+ devpriv->ai_counter = devpriv->ai_timer;
if (cmd->stop_src == TRIG_COUNT) {
/* data arrives as one packet */
- this_usbduxsub->ai_sample_count = cmd->stop_arg;
- this_usbduxsub->ai_continous = 0;
+ devpriv->ai_sample_count = cmd->stop_arg;
+ devpriv->ai_continous = 0;
} else {
/* continous acquisition */
- this_usbduxsub->ai_continous = 1;
- this_usbduxsub->ai_sample_count = 0;
+ devpriv->ai_continous = 1;
+ devpriv->ai_sample_count = 0;
}
if (cmd->start_src == TRIG_NOW) {
/* enable this acquisition operation */
- this_usbduxsub->ai_cmd_running = 1;
- ret = usbduxsub_submit_inurbs(this_usbduxsub);
+ devpriv->ai_cmd_running = 1;
+ ret = usbdux_submit_urbs(dev, devpriv->ai_urbs,
+ devpriv->n_ai_urbs, 1);
if (ret < 0) {
- this_usbduxsub->ai_cmd_running = 0;
+ devpriv->ai_cmd_running = 0;
/* fixme: unlink here?? */
- up(&this_usbduxsub->sem);
- return ret;
+ goto ai_cmd_exit;
}
s->async->inttrig = NULL;
} else {
@@ -1179,202 +801,156 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* wait for an internal signal */
s->async->inttrig = usbdux_ai_inttrig;
}
- up(&this_usbduxsub->sem);
- return 0;
+
+ai_cmd_exit:
+ up(&devpriv->sem);
+
+ return ret;
}
/* Mode 0 is used to get a single conversion on demand */
static int usbdux_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ struct usbdux_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val;
+ int ret = -EBUSY;
int i;
- unsigned int one = 0;
- int chan, range;
- int err;
- struct usbduxsub *this_usbduxsub = dev->private;
-
- if (!this_usbduxsub)
- return 0;
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n",
- dev->minor, insn->n, insn->subdev);
+ down(&devpriv->sem);
- down(&this_usbduxsub->sem);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
- if (this_usbduxsub->ai_cmd_running) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: ai_insn_read not possible. "
- "Async Command is running.\n", dev->minor);
- up(&this_usbduxsub->sem);
- return 0;
- }
+ if (devpriv->ai_cmd_running)
+ goto ai_read_exit;
- /* sample one channel */
- chan = CR_CHAN(insn->chanspec);
- range = CR_RANGE(insn->chanspec);
/* set command for the first channel */
- this_usbduxsub->dux_commands[1] = create_adc_command(chan, range);
+ devpriv->dux_commands[1] = create_adc_command(chan, range);
/* adc commands */
- err = send_dux_commands(this_usbduxsub, SENDSINGLEAD);
- if (err < 0) {
- up(&this_usbduxsub->sem);
- return err;
- }
+ ret = send_dux_commands(dev, USBDUX_CMD_SINGLE_AI);
+ if (ret < 0)
+ goto ai_read_exit;
for (i = 0; i < insn->n; i++) {
- err = receive_dux_commands(this_usbduxsub, SENDSINGLEAD);
- if (err < 0) {
- up(&this_usbduxsub->sem);
- return 0;
- }
- one = le16_to_cpu(this_usbduxsub->insn_buffer[1]);
- if (CR_RANGE(insn->chanspec) <= 1)
- one = one ^ 0x800;
+ ret = receive_dux_commands(dev, USBDUX_CMD_SINGLE_AI);
+ if (ret < 0)
+ goto ai_read_exit;
+
+ val = le16_to_cpu(devpriv->insn_buf[1]);
- data[i] = one;
+ /* bipolar data is two's-complement */
+ if (comedi_range_is_bipolar(s, range))
+ val ^= ((s->maxdata + 1) >> 1);
+
+ data[i] = val;
}
- up(&this_usbduxsub->sem);
- return i;
-}
-/************************************/
-/* analog out */
+ai_read_exit:
+ up(&devpriv->sem);
+
+ return ret ? ret : insn->n;
+}
static int usbdux_ao_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ struct usbdux_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
int i;
- int chan = CR_CHAN(insn->chanspec);
- struct usbduxsub *this_usbduxsub = dev->private;
-
- if (!this_usbduxsub)
- return -EFAULT;
- down(&this_usbduxsub->sem);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
+ down(&devpriv->sem);
for (i = 0; i < insn->n; i++)
- data[i] = this_usbduxsub->out_buffer[chan];
+ data[i] = devpriv->ao_readback[chan];
+ up(&devpriv->sem);
- up(&this_usbduxsub->sem);
- return i;
+ return insn->n;
}
static int usbdux_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int i, err;
- int chan = CR_CHAN(insn->chanspec);
- struct usbduxsub *this_usbduxsub = dev->private;
+ struct usbdux_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = devpriv->ao_readback[chan];
+ int16_t *p = (int16_t *)&devpriv->dux_commands[2];
+ int ret = -EBUSY;
+ int i;
- if (!this_usbduxsub)
- return -EFAULT;
+ down(&devpriv->sem);
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: ao_insn_write\n", dev->minor);
+ if (devpriv->ao_cmd_running)
+ goto ao_write_exit;
- down(&this_usbduxsub->sem);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
- if (this_usbduxsub->ao_cmd_running) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: ao_insn_write: "
- "ERROR: asynchronous ao_cmd is running\n", dev->minor);
- up(&this_usbduxsub->sem);
- return 0;
- }
+ /* number of channels: 1 */
+ devpriv->dux_commands[1] = 1;
+ /* channel number */
+ devpriv->dux_commands[4] = chan << 6;
for (i = 0; i < insn->n; i++) {
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: ao_insn_write: data[chan=%d,i=%d]=%d\n",
- dev->minor, chan, i, data[i]);
+ val = data[i];
- /* number of channels: 1 */
- this_usbduxsub->dux_commands[1] = 1;
/* one 16 bit value */
- *((int16_t *) (this_usbduxsub->dux_commands + 2)) =
- cpu_to_le16(data[i]);
- this_usbduxsub->out_buffer[chan] = data[i];
- /* channel number */
- this_usbduxsub->dux_commands[4] = (chan << 6);
- err = send_dux_commands(this_usbduxsub, SENDDACOMMANDS);
- if (err < 0) {
- up(&this_usbduxsub->sem);
- return err;
- }
+ *p = cpu_to_le16(val);
+
+ ret = send_dux_commands(dev, USBDUX_CMD_AO);
+ if (ret < 0)
+ goto ao_write_exit;
}
- up(&this_usbduxsub->sem);
+ devpriv->ao_readback[chan] = val;
+
+ao_write_exit:
+ up(&devpriv->sem);
- return i;
+ return ret ? ret : insn->n;
}
static int usbdux_ao_inttrig(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int trignum)
+ struct comedi_subdevice *s,
+ unsigned int trignum)
{
- int ret;
- struct usbduxsub *this_usbduxsub = dev->private;
+ struct usbdux_private *devpriv = dev->private;
+ int ret = -EINVAL;
- if (!this_usbduxsub)
- return -EFAULT;
+ down(&devpriv->sem);
- down(&this_usbduxsub->sem);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
- if (trignum != 0) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: usbdux_ao_inttrig: invalid trignum\n",
- dev->minor);
- up(&this_usbduxsub->sem);
- return -EINVAL;
- }
- if (!(this_usbduxsub->ao_cmd_running)) {
- this_usbduxsub->ao_cmd_running = 1;
- ret = usbduxsub_submit_outurbs(this_usbduxsub);
+ if (trignum != 0)
+ goto ao_trig_exit;
+
+ if (!devpriv->ao_cmd_running) {
+ devpriv->ao_cmd_running = 1;
+ ret = usbdux_submit_urbs(dev, devpriv->ao_urbs,
+ devpriv->n_ao_urbs, 0);
if (ret < 0) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: usbdux_ao_inttrig: submitURB: "
- "err=%d\n", dev->minor, ret);
- this_usbduxsub->ao_cmd_running = 0;
- up(&this_usbduxsub->sem);
- return ret;
+ devpriv->ao_cmd_running = 0;
+ goto ao_trig_exit;
}
s->async->inttrig = NULL;
} else {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: ao_inttrig but acqu is already running.\n",
- dev->minor);
+ ret = -EBUSY;
}
- up(&this_usbduxsub->sem);
- return 1;
+
+ao_trig_exit:
+ up(&devpriv->sem);
+ return ret;
}
static int usbdux_ao_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
- struct usbduxsub *this_usbduxsub = dev->private;
+ struct usbdux_private *this_usbduxsub = dev->private;
int err = 0;
unsigned int flags;
if (!this_usbduxsub)
return -EFAULT;
- if (!(this_usbduxsub->probed))
- return -ENODEV;
-
/* Step 1 : check if triggers are trivially valid */
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
@@ -1451,99 +1027,72 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev,
static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ struct usbdux_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- unsigned int chan, gain;
- int i, ret;
- struct usbduxsub *this_usbduxsub = dev->private;
+ int ret = -EBUSY;
+ int i;
- if (!this_usbduxsub)
- return -EFAULT;
+ down(&devpriv->sem);
- down(&this_usbduxsub->sem);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: %s\n", dev->minor, __func__);
+ if (devpriv->ao_cmd_running)
+ goto ao_cmd_exit;
/* set current channel of the running acquisition to zero */
s->async->cur_chan = 0;
+
for (i = 0; i < cmd->chanlist_len; ++i) {
- chan = CR_CHAN(cmd->chanlist[i]);
- gain = CR_RANGE(cmd->chanlist[i]);
- if (i >= NUMOUTCHANNELS) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: %s: channel list too long\n",
- dev->minor, __func__);
- break;
- }
- this_usbduxsub->dac_commands[i] = (chan << 6);
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: dac command for ch %d is %x\n",
- dev->minor, i, this_usbduxsub->dac_commands[i]);
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
+ devpriv->ao_chanlist[i] = chan << 6;
}
/* we count in steps of 1ms (125us) */
/* 125us mode not used yet */
- if (0) { /* (this_usbduxsub->high_speed) */
+ if (0) { /* (devpriv->high_speed) */
/* 125us */
/* timing of the conversion itself: every 125 us */
- this_usbduxsub->ao_timer = cmd->convert_arg / 125000;
+ devpriv->ao_timer = cmd->convert_arg / 125000;
} else {
/* 1ms */
/* timing of the scan: we get all channels at once */
- this_usbduxsub->ao_timer = cmd->scan_begin_arg / 1000000;
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: scan_begin_src=%d, scan_begin_arg=%d, "
- "convert_src=%d, convert_arg=%d\n", dev->minor,
- cmd->scan_begin_src, cmd->scan_begin_arg,
- cmd->convert_src, cmd->convert_arg);
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: ao_timer=%d (ms)\n",
- dev->minor, this_usbduxsub->ao_timer);
- if (this_usbduxsub->ao_timer < 1) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: usbdux: ao_timer=%d, "
- "scan_begin_arg=%d. "
- "Not properly tested by cmdtest?\n",
- dev->minor, this_usbduxsub->ao_timer,
- cmd->scan_begin_arg);
- up(&this_usbduxsub->sem);
- return -EINVAL;
+ devpriv->ao_timer = cmd->scan_begin_arg / 1000000;
+ if (devpriv->ao_timer < 1) {
+ ret = -EINVAL;
+ goto ao_cmd_exit;
}
}
- this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
+
+ devpriv->ao_counter = devpriv->ao_timer;
if (cmd->stop_src == TRIG_COUNT) {
/* not continuous */
/* counter */
/* high speed also scans everything at once */
- if (0) { /* (this_usbduxsub->high_speed) */
- this_usbduxsub->ao_sample_count =
- (cmd->stop_arg) * (cmd->scan_end_arg);
+ if (0) { /* (devpriv->high_speed) */
+ devpriv->ao_sample_count = cmd->stop_arg *
+ cmd->scan_end_arg;
} else {
/* there's no scan as the scan has been */
/* perf inside the FX2 */
/* data arrives as one packet */
- this_usbduxsub->ao_sample_count = cmd->stop_arg;
+ devpriv->ao_sample_count = cmd->stop_arg;
}
- this_usbduxsub->ao_continous = 0;
+ devpriv->ao_continous = 0;
} else {
/* continous acquisition */
- this_usbduxsub->ao_continous = 1;
- this_usbduxsub->ao_sample_count = 0;
+ devpriv->ao_continous = 1;
+ devpriv->ao_sample_count = 0;
}
if (cmd->start_src == TRIG_NOW) {
/* enable this acquisition operation */
- this_usbduxsub->ao_cmd_running = 1;
- ret = usbduxsub_submit_outurbs(this_usbduxsub);
+ devpriv->ao_cmd_running = 1;
+ ret = usbdux_submit_urbs(dev, devpriv->ao_urbs,
+ devpriv->n_ao_urbs, 0);
if (ret < 0) {
- this_usbduxsub->ao_cmd_running = 0;
+ devpriv->ao_cmd_running = 0;
/* fixme: unlink here?? */
- up(&this_usbduxsub->sem);
- return ret;
+ goto ao_cmd_exit;
}
s->async->inttrig = NULL;
} else {
@@ -1553,149 +1102,123 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
s->async->inttrig = usbdux_ao_inttrig;
}
- up(&this_usbduxsub->sem);
- return 0;
+ao_cmd_exit:
+ up(&devpriv->sem);
+
+ return ret;
}
static int usbdux_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int chan = CR_CHAN(insn->chanspec);
+ int ret;
- /* The input or output configuration of each digital line is
- * configured by a special insn_config instruction. chanspec
- * contains the channel to be changed, and data[0] contains the
- * value COMEDI_INPUT or COMEDI_OUTPUT. */
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= 1 << chan; /* 1 means Out */
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~(1 << chan);
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
- break;
- default:
- return -EINVAL;
- break;
- }
- /* we don't tell the firmware here as it would take 8 frames */
- /* to submit the information. We do it in the insn_bits. */
+ /*
+ * We don't tell the firmware here as it would take 8 frames
+ * to submit the information. We do it in the insn_bits.
+ */
return insn->n;
}
static int usbdux_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct usbduxsub *this_usbduxsub = dev->private;
- int err;
+ struct usbdux_private *devpriv = dev->private;
+ unsigned int mask = data[0];
+ unsigned int bits = data[1];
+ int ret;
- if (!this_usbduxsub)
- return -EFAULT;
+ down(&devpriv->sem);
- down(&this_usbduxsub->sem);
+ s->state &= ~mask;
+ s->state |= (bits & mask);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
+ devpriv->dux_commands[1] = s->io_bits;
+ devpriv->dux_commands[2] = s->state;
- /* The insn data is a mask in data[0] and the new data
- * in data[1], each channel cooresponding to a bit. */
- s->state &= ~data[0];
- s->state |= data[0] & data[1];
- this_usbduxsub->dux_commands[1] = s->io_bits;
- this_usbduxsub->dux_commands[2] = s->state;
-
- /* This command also tells the firmware to return */
- /* the digital input lines */
- err = send_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND);
- if (err < 0) {
- up(&this_usbduxsub->sem);
- return err;
- }
- err = receive_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND);
- if (err < 0) {
- up(&this_usbduxsub->sem);
- return err;
- }
+ /*
+ * This command also tells the firmware to return
+ * the digital input lines.
+ */
+ ret = send_dux_commands(dev, USBDUX_CMD_DIO_BITS);
+ if (ret < 0)
+ goto dio_exit;
+ ret = receive_dux_commands(dev, USBDUX_CMD_DIO_BITS);
+ if (ret < 0)
+ goto dio_exit;
- data[1] = le16_to_cpu(this_usbduxsub->insn_buffer[1]);
- up(&this_usbduxsub->sem);
- return insn->n;
+ data[1] = le16_to_cpu(devpriv->insn_buf[1]);
+
+dio_exit:
+ up(&devpriv->sem);
+
+ return ret ? ret : insn->n;
}
-/* reads the 4 counters, only two are used just now */
static int usbdux_counter_read(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct usbduxsub *this_usbduxsub = dev->private;
- int chan = insn->chanspec;
- int err;
-
- if (!this_usbduxsub)
- return -EFAULT;
+ struct usbdux_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int ret = 0;
+ int i;
- down(&this_usbduxsub->sem);
+ down(&devpriv->sem);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
+ for (i = 0; i < insn->n; i++) {
+ ret = send_dux_commands(dev, USBDUX_CMD_TIMER_RD);
+ if (ret < 0)
+ goto counter_read_exit;
+ ret = receive_dux_commands(dev, USBDUX_CMD_TIMER_RD);
+ if (ret < 0)
+ goto counter_read_exit;
- err = send_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
- if (err < 0) {
- up(&this_usbduxsub->sem);
- return err;
+ data[i] = le16_to_cpu(devpriv->insn_buf[chan + 1]);
}
- err = receive_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
- if (err < 0) {
- up(&this_usbduxsub->sem);
- return err;
- }
+counter_read_exit:
+ up(&devpriv->sem);
- data[0] = le16_to_cpu(this_usbduxsub->insn_buffer[chan + 1]);
- up(&this_usbduxsub->sem);
- return 1;
+ return ret ? ret : insn->n;
}
static int usbdux_counter_write(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct usbduxsub *this_usbduxsub = dev->private;
- int err;
-
- if (!this_usbduxsub)
- return -EFAULT;
+ struct usbdux_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int16_t *p = (int16_t *)&devpriv->dux_commands[2];
+ int ret = 0;
+ int i;
- down(&this_usbduxsub->sem);
+ down(&devpriv->sem);
- if (!(this_usbduxsub->probed)) {
- up(&this_usbduxsub->sem);
- return -ENODEV;
- }
+ devpriv->dux_commands[1] = chan;
- this_usbduxsub->dux_commands[1] = insn->chanspec;
- *((int16_t *) (this_usbduxsub->dux_commands + 2)) = cpu_to_le16(*data);
+ for (i = 0; i < insn->n; i++) {
+ *p = cpu_to_le16(data[i]);
- err = send_dux_commands(this_usbduxsub, WRITECOUNTERCOMMAND);
- if (err < 0) {
- up(&this_usbduxsub->sem);
- return err;
+ ret = send_dux_commands(dev, USBDUX_CMD_TIMER_WR);
+ if (ret < 0)
+ break;
}
- up(&this_usbduxsub->sem);
+ up(&devpriv->sem);
- return 1;
+ return ret ? ret : insn->n;
}
static int usbdux_counter_config(struct comedi_device *dev,
@@ -1706,73 +1229,43 @@ static int usbdux_counter_config(struct comedi_device *dev,
return 2;
}
-/***********************************/
-/* PWM */
-
-static int usbduxsub_unlink_pwm_urbs(struct usbduxsub *usbduxsub_tmp)
+static void usbduxsub_unlink_pwm_urbs(struct comedi_device *dev)
{
- int err = 0;
+ struct usbdux_private *devpriv = dev->private;
- if (usbduxsub_tmp && usbduxsub_tmp->urb_pwm) {
- if (usbduxsub_tmp->urb_pwm)
- usb_kill_urb(usbduxsub_tmp->urb_pwm);
- dev_dbg(&usbduxsub_tmp->interface->dev,
- "comedi: unlinked PwmURB: res=%d\n", err);
- }
- return err;
+ usb_kill_urb(devpriv->pwm_urb);
}
-/* This cancels a running acquisition operation
- * in any context.
- */
-static int usbdux_pwm_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
+static void usbdux_pwm_stop(struct comedi_device *dev, int do_unlink)
{
- int ret = 0;
-
- if (!this_usbduxsub)
- return -EFAULT;
+ struct usbdux_private *devpriv = dev->private;
- dev_dbg(&this_usbduxsub->interface->dev, "comedi: %s\n", __func__);
if (do_unlink)
- ret = usbduxsub_unlink_pwm_urbs(this_usbduxsub);
-
- this_usbduxsub->pwm_cmd_running = 0;
+ usbduxsub_unlink_pwm_urbs(dev);
- return ret;
+ devpriv->pwm_cmd_running = 0;
}
-/* force unlink - is called by comedi */
static int usbdux_pwm_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- struct usbduxsub *this_usbduxsub = dev->private;
- int res = 0;
+ struct usbdux_private *devpriv = dev->private;
+ int ret;
+ down(&devpriv->sem);
/* unlink only if it is really running */
- res = usbdux_pwm_stop(this_usbduxsub, this_usbduxsub->pwm_cmd_running);
+ usbdux_pwm_stop(dev, devpriv->pwm_cmd_running);
+ ret = send_dux_commands(dev, USBDUX_CMD_PWM_OFF);
+ up(&devpriv->sem);
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi %d: sending pwm off command to the usb device.\n",
- dev->minor);
-
- return send_dux_commands(this_usbduxsub, SENDPWMOFF);
+ return ret;
}
static void usbduxsub_pwm_irq(struct urb *urb)
{
+ struct comedi_device *dev = urb->context;
+ struct usbdux_private *devpriv = dev->private;
int ret;
- struct usbduxsub *this_usbduxsub;
- struct comedi_device *this_comedidev;
- struct comedi_subdevice *s;
-
- /* printk(KERN_DEBUG "PWM: IRQ\n"); */
-
- /* the context variable points to the subdevice */
- this_comedidev = urb->context;
- /* the private structure of the subdevice is struct usbduxsub */
- this_usbduxsub = this_comedidev->private;
-
- s = &this_comedidev->subdevices[SUBDEV_DA];
switch (urb->status) {
case 0:
@@ -1787,220 +1280,171 @@ static void usbduxsub_pwm_irq(struct urb *urb)
* after an unlink command, unplug, ... etc
* no unlink needed here. Already shutting down.
*/
- if (this_usbduxsub->pwm_cmd_running)
- usbdux_pwm_stop(this_usbduxsub, 0);
+ if (devpriv->pwm_cmd_running)
+ usbdux_pwm_stop(dev, 0);
return;
default:
/* a real error */
- if (this_usbduxsub->pwm_cmd_running) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi_: Non-zero urb status received in "
- "pwm intr context: %d\n", urb->status);
- usbdux_pwm_stop(this_usbduxsub, 0);
+ if (devpriv->pwm_cmd_running) {
+ dev_err(dev->class_dev,
+ "Non-zero urb status received in pwm intr context: %d\n",
+ urb->status);
+ usbdux_pwm_stop(dev, 0);
}
return;
}
/* are we actually running? */
- if (!(this_usbduxsub->pwm_cmd_running))
+ if (!devpriv->pwm_cmd_running)
return;
- urb->transfer_buffer_length = this_usbduxsub->size_pwm_buf;
- urb->dev = this_usbduxsub->usbdev;
+ urb->transfer_buffer_length = devpriv->pwm_buf_sz;
+ urb->dev = comedi_to_usb_dev(dev);
urb->status = 0;
- if (this_usbduxsub->pwm_cmd_running) {
+ if (devpriv->pwm_cmd_running) {
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi_: pwm urb resubm failed in int-cont. "
- "ret=%d", ret);
+ dev_err(dev->class_dev,
+ "pwm urb resubm failed in int-cont. ret=%d",
+ ret);
if (ret == EL2NSYNC)
- dev_err(&this_usbduxsub->interface->dev,
- "buggy USB host controller or bug in "
- "IRQ handling!\n");
+ dev_err(dev->class_dev,
+ "buggy USB host controller or bug in IRQ handling!\n");
/* don't do an unlink here */
- usbdux_pwm_stop(this_usbduxsub, 0);
+ usbdux_pwm_stop(dev, 0);
}
}
}
-static int usbduxsub_submit_pwm_urbs(struct usbduxsub *usbduxsub)
+static int usbduxsub_submit_pwm_urbs(struct comedi_device *dev)
{
- int err_flag;
-
- if (!usbduxsub)
- return -EFAULT;
-
- dev_dbg(&usbduxsub->interface->dev, "comedi_: submitting pwm-urb\n");
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct usbdux_private *devpriv = dev->private;
+ struct urb *urb = devpriv->pwm_urb;
/* in case of a resubmission after an unlink... */
- usb_fill_bulk_urb(usbduxsub->urb_pwm,
- usbduxsub->usbdev,
- usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP),
- usbduxsub->urb_pwm->transfer_buffer,
- usbduxsub->size_pwm_buf, usbduxsub_pwm_irq,
- usbduxsub->comedidev);
-
- err_flag = usb_submit_urb(usbduxsub->urb_pwm, GFP_ATOMIC);
- if (err_flag) {
- dev_err(&usbduxsub->interface->dev,
- "comedi_: usbdux: pwm: usb_submit_urb error %d\n",
- err_flag);
- return err_flag;
- }
- return 0;
+ usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, 4),
+ urb->transfer_buffer,
+ devpriv->pwm_buf_sz,
+ usbduxsub_pwm_irq,
+ dev);
+
+ return usb_submit_urb(urb, GFP_ATOMIC);
}
static int usbdux_pwm_period(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int period)
+ struct comedi_subdevice *s,
+ unsigned int period)
{
- struct usbduxsub *this_usbduxsub = dev->private;
+ struct usbdux_private *devpriv = dev->private;
int fx2delay = 255;
if (period < MIN_PWM_PERIOD) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: illegal period setting for pwm.\n",
- dev->minor);
return -EAGAIN;
} else {
- fx2delay = period / ((int)(6 * 512 * (1.0 / 0.033))) - 6;
- if (fx2delay > 255) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi%d: period %d for pwm is too low.\n",
- dev->minor, period);
+ fx2delay = (period / (6 * 512 * 1000 / 33)) - 6;
+ if (fx2delay > 255)
return -EAGAIN;
- }
}
- this_usbduxsub->pwn_delay = fx2delay;
- this_usbduxsub->pwm_period = period;
- dev_dbg(&this_usbduxsub->interface->dev, "%s: frequ=%d, period=%d\n",
- __func__, period, fx2delay);
+ devpriv->pwm_delay = fx2delay;
+ devpriv->pwm_period = period;
+
return 0;
}
-/* is called from insn so there's no need to do all the sanity checks */
static int usbdux_pwm_start(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- int ret, i;
- struct usbduxsub *this_usbduxsub = dev->private;
+ struct usbdux_private *devpriv = dev->private;
+ int ret = 0;
- dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: %s\n",
- dev->minor, __func__);
+ down(&devpriv->sem);
- if (this_usbduxsub->pwm_cmd_running) {
- /* already running */
- return 0;
- }
+ if (devpriv->pwm_cmd_running)
+ goto pwm_start_exit;
- this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwn_delay);
- ret = send_dux_commands(this_usbduxsub, SENDPWMON);
+ devpriv->dux_commands[1] = devpriv->pwm_delay;
+ ret = send_dux_commands(dev, USBDUX_CMD_PWM_ON);
if (ret < 0)
- return ret;
+ goto pwm_start_exit;
/* initialise the buffer */
- for (i = 0; i < this_usbduxsub->size_pwm_buf; i++)
- ((char *)(this_usbduxsub->urb_pwm->transfer_buffer))[i] = 0;
+ memset(devpriv->pwm_urb->transfer_buffer, 0, devpriv->pwm_buf_sz);
- this_usbduxsub->pwm_cmd_running = 1;
- ret = usbduxsub_submit_pwm_urbs(this_usbduxsub);
- if (ret < 0) {
- this_usbduxsub->pwm_cmd_running = 0;
- return ret;
- }
- return 0;
+ devpriv->pwm_cmd_running = 1;
+ ret = usbduxsub_submit_pwm_urbs(dev);
+ if (ret < 0)
+ devpriv->pwm_cmd_running = 0;
+
+pwm_start_exit:
+ up(&devpriv->sem);
+
+ return ret;
}
-/* generates the bit pattern for PWM with the optional sign bit */
-static int usbdux_pwm_pattern(struct comedi_device *dev,
- struct comedi_subdevice *s, int channel,
- unsigned int value, unsigned int sign)
+static void usbdux_pwm_pattern(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chan,
+ unsigned int value,
+ unsigned int sign)
{
- struct usbduxsub *this_usbduxsub = dev->private;
- int i, szbuf;
- char *p_buf;
- char pwm_mask;
- char sgn_mask;
- char c;
-
- if (!this_usbduxsub)
- return -EFAULT;
+ struct usbdux_private *devpriv = dev->private;
+ char pwm_mask = (1 << chan); /* DIO bit for the PWM data */
+ char sgn_mask = (16 << chan); /* DIO bit for the sign */
+ char *buf = (char *)(devpriv->pwm_urb->transfer_buffer);
+ int szbuf = devpriv->pwm_buf_sz;
+ int i;
- /* this is the DIO bit which carries the PWM data */
- pwm_mask = (1 << channel);
- /* this is the DIO bit which carries the optional direction bit */
- sgn_mask = (16 << channel);
- /* this is the buffer which will be filled with the with bit */
- /* pattern for one period */
- szbuf = this_usbduxsub->size_pwm_buf;
- p_buf = (char *)(this_usbduxsub->urb_pwm->transfer_buffer);
for (i = 0; i < szbuf; i++) {
- c = *p_buf;
- /* reset bits */
- c = c & (~pwm_mask);
- /* set the bit as long as the index is lower than the value */
+ char c = *buf;
+
+ c &= ~pwm_mask;
if (i < value)
- c = c | pwm_mask;
- /* set the optional sign bit for a relay */
- if (!sign) {
- /* positive value */
- c = c & (~sgn_mask);
- } else {
- /* negative value */
- c = c | sgn_mask;
- }
- *(p_buf++) = c;
+ c |= pwm_mask;
+ if (!sign)
+ c &= ~sgn_mask;
+ else
+ c |= sgn_mask;
+ *buf++ = c;
}
- return 1;
}
static int usbdux_pwm_write(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct usbduxsub *this_usbduxsub = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
- if (!this_usbduxsub)
- return -EFAULT;
-
- if ((insn->n) != 1) {
- /*
- * doesn't make sense to have more than one value here because
- * it would just overwrite the PWM buffer a couple of times
- */
+ /*
+ * It doesn't make sense to support more than one value here
+ * because it would just overwrite the PWM buffer.
+ */
+ if (insn->n != 1)
return -EINVAL;
- }
/*
- * the sign is set via a special INSN only, this gives us 8 bits for
- * normal operation
- * relay sign 0 by default
+ * The sign is set via a special INSN only, this gives us 8 bits
+ * for normal operation, sign is 0 by default.
*/
- return usbdux_pwm_pattern(dev, s, CR_CHAN(insn->chanspec), data[0], 0);
-}
+ usbdux_pwm_pattern(dev, s, chan, data[0], 0);
-static int usbdux_pwm_read(struct comedi_device *x1,
- struct comedi_subdevice *x2, struct comedi_insn *x3,
- unsigned int *x4)
-{
- /* not needed */
- return -EINVAL;
-};
+ return insn->n;
+}
-/* switches on/off PWM */
static int usbdux_pwm_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct usbduxsub *this_usbduxsub = dev->private;
+ struct usbdux_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+
switch (data[0]) {
case INSN_CONFIG_ARM:
- /* switch it on */
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: %s: pwm on\n", dev->minor, __func__);
/*
* if not zero the PWM is limited to a certain time which is
* not supported here
@@ -2009,33 +1453,22 @@ static int usbdux_pwm_config(struct comedi_device *dev,
return -EINVAL;
return usbdux_pwm_start(dev, s);
case INSN_CONFIG_DISARM:
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: %s: pwm off\n", dev->minor, __func__);
return usbdux_pwm_cancel(dev, s);
case INSN_CONFIG_GET_PWM_STATUS:
- /*
- * to check if the USB transmission has failed or in case PWM
- * was limited to n cycles to check if it has terminated
- */
- data[1] = this_usbduxsub->pwm_cmd_running;
+ data[1] = devpriv->pwm_cmd_running;
return 0;
case INSN_CONFIG_PWM_SET_PERIOD:
- dev_dbg(&this_usbduxsub->interface->dev,
- "comedi%d: %s: setting period\n", dev->minor, __func__);
return usbdux_pwm_period(dev, s, data[1]);
case INSN_CONFIG_PWM_GET_PERIOD:
- data[1] = this_usbduxsub->pwm_period;
+ data[1] = devpriv->pwm_period;
return 0;
case INSN_CONFIG_PWM_SET_H_BRIDGE:
- /* value in the first byte and the sign in the second for a
- relay */
- return usbdux_pwm_pattern(dev, s,
- /* the channel number */
- CR_CHAN(insn->chanspec),
- /* actual PWM data */
- data[1],
- /* just a sign */
- (data[2] != 0));
+ /*
+ * data[1] = value
+ * data[2] = sign (for a relay)
+ */
+ usbdux_pwm_pattern(dev, s, chan, data[1], (data[2] != 0));
+ return 0;
case INSN_CONFIG_PWM_GET_H_BRIDGE:
/* values are not kept in this driver, nothing to return here */
return -EINVAL;
@@ -2043,253 +1476,331 @@ static int usbdux_pwm_config(struct comedi_device *dev,
return -EINVAL;
}
-/* end of PWM */
-/*****************************************************************/
-
-static void tidy_up(struct usbduxsub *usbduxsub_tmp)
+static int usbdux_firmware_upload(struct comedi_device *dev,
+ const u8 *data, size_t size,
+ unsigned long context)
{
- int i;
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ uint8_t *buf;
+ uint8_t *tmp;
+ int ret;
- if (!usbduxsub_tmp)
- return;
- dev_dbg(&usbduxsub_tmp->interface->dev, "comedi_: tiding up\n");
+ if (!data)
+ return 0;
- /* shows the usb subsystem that the driver is down */
- if (usbduxsub_tmp->interface)
- usb_set_intfdata(usbduxsub_tmp->interface, NULL);
+ if (size > USBDUX_FIRMWARE_MAX_LEN) {
+ dev_err(dev->class_dev,
+ "usbdux firmware binary it too large for FX2.\n");
+ return -ENOMEM;
+ }
- usbduxsub_tmp->probed = 0;
+ /* we generate a local buffer for the firmware */
+ buf = kmemdup(data, size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- if (usbduxsub_tmp->urb_in) {
- if (usbduxsub_tmp->ai_cmd_running) {
- usbduxsub_tmp->ai_cmd_running = 0;
- usbduxsub_unlink_inurbs(usbduxsub_tmp);
- }
- for (i = 0; i < usbduxsub_tmp->num_in_buffers; i++) {
- kfree(usbduxsub_tmp->urb_in[i]->transfer_buffer);
- usbduxsub_tmp->urb_in[i]->transfer_buffer = NULL;
- usb_kill_urb(usbduxsub_tmp->urb_in[i]);
- usb_free_urb(usbduxsub_tmp->urb_in[i]);
- usbduxsub_tmp->urb_in[i] = NULL;
- }
- kfree(usbduxsub_tmp->urb_in);
- usbduxsub_tmp->urb_in = NULL;
+ /* we need a malloc'ed buffer for usb_control_msg() */
+ tmp = kmalloc(1, GFP_KERNEL);
+ if (!tmp) {
+ kfree(buf);
+ return -ENOMEM;
}
- if (usbduxsub_tmp->urb_out) {
- if (usbduxsub_tmp->ao_cmd_running) {
- usbduxsub_tmp->ao_cmd_running = 0;
- usbduxsub_unlink_outurbs(usbduxsub_tmp);
- }
- for (i = 0; i < usbduxsub_tmp->num_out_buffers; i++) {
- kfree(usbduxsub_tmp->urb_out[i]->transfer_buffer);
- usbduxsub_tmp->urb_out[i]->transfer_buffer = NULL;
- if (usbduxsub_tmp->urb_out[i]) {
- usb_kill_urb(usbduxsub_tmp->urb_out[i]);
- usb_free_urb(usbduxsub_tmp->urb_out[i]);
- usbduxsub_tmp->urb_out[i] = NULL;
- }
- }
- kfree(usbduxsub_tmp->urb_out);
- usbduxsub_tmp->urb_out = NULL;
+
+ /* stop the current firmware on the device */
+ *tmp = 1; /* 7f92 to one */
+ ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
+ USBDUX_FIRMWARE_CMD,
+ VENDOR_DIR_OUT,
+ USBDUX_CPU_CS, 0x0000,
+ tmp, 1,
+ BULK_TIMEOUT);
+ if (ret < 0) {
+ dev_err(dev->class_dev, "can not stop firmware\n");
+ goto done;
}
- if (usbduxsub_tmp->urb_pwm) {
- if (usbduxsub_tmp->pwm_cmd_running) {
- usbduxsub_tmp->pwm_cmd_running = 0;
- usbduxsub_unlink_pwm_urbs(usbduxsub_tmp);
- }
- kfree(usbduxsub_tmp->urb_pwm->transfer_buffer);
- usbduxsub_tmp->urb_pwm->transfer_buffer = NULL;
- usb_kill_urb(usbduxsub_tmp->urb_pwm);
- usb_free_urb(usbduxsub_tmp->urb_pwm);
- usbduxsub_tmp->urb_pwm = NULL;
+
+ /* upload the new firmware to the device */
+ ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
+ USBDUX_FIRMWARE_CMD,
+ VENDOR_DIR_OUT,
+ 0, 0x0000,
+ buf, size,
+ BULK_TIMEOUT);
+ if (ret < 0) {
+ dev_err(dev->class_dev, "firmware upload failed\n");
+ goto done;
}
- kfree(usbduxsub_tmp->in_buffer);
- usbduxsub_tmp->in_buffer = NULL;
- kfree(usbduxsub_tmp->insn_buffer);
- usbduxsub_tmp->insn_buffer = NULL;
- kfree(usbduxsub_tmp->out_buffer);
- usbduxsub_tmp->out_buffer = NULL;
- kfree(usbduxsub_tmp->dac_commands);
- usbduxsub_tmp->dac_commands = NULL;
- kfree(usbduxsub_tmp->dux_commands);
- usbduxsub_tmp->dux_commands = NULL;
- usbduxsub_tmp->ai_cmd_running = 0;
- usbduxsub_tmp->ao_cmd_running = 0;
- usbduxsub_tmp->pwm_cmd_running = 0;
+
+ /* start the new firmware on the device */
+ *tmp = 0; /* 7f92 to zero */
+ ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
+ USBDUX_FIRMWARE_CMD,
+ VENDOR_DIR_OUT,
+ USBDUX_CPU_CS, 0x0000,
+ tmp, 1,
+ BULK_TIMEOUT);
+ if (ret < 0)
+ dev_err(dev->class_dev, "can not start firmware\n");
+
+done:
+ kfree(tmp);
+ kfree(buf);
+ return ret;
}
-static int usbdux_attach_common(struct comedi_device *dev,
- struct usbduxsub *udev)
+static int usbdux_alloc_usb_buffers(struct comedi_device *dev)
{
- int ret;
- struct comedi_subdevice *s = NULL;
- int n_subdevs;
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct usbdux_private *devpriv = dev->private;
+ struct urb *urb;
+ int i;
- down(&udev->sem);
- /* pointer back to the corresponding comedi device */
- udev->comedidev = dev;
+ devpriv->dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
+ devpriv->in_buf = kzalloc(SIZEINBUF, GFP_KERNEL);
+ devpriv->insn_buf = kzalloc(SIZEINSNBUF, GFP_KERNEL);
+ devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(void *),
+ GFP_KERNEL);
+ devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(void *),
+ GFP_KERNEL);
+ if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf ||
+ !devpriv->ai_urbs || !devpriv->ao_urbs)
+ return -ENOMEM;
- /* set number of subdevices */
- if (udev->high_speed) {
- /* with pwm */
- n_subdevs = 5;
- } else {
- /* without pwm */
- n_subdevs = 4;
- }
+ for (i = 0; i < devpriv->n_ai_urbs; i++) {
+ /* one frame: 1ms */
+ urb = usb_alloc_urb(1, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
+ devpriv->ai_urbs[i] = urb;
+
+ urb->dev = usb;
+ urb->context = dev;
+ urb->pipe = usb_rcvisocpipe(usb, 6);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL);
+ if (!urb->transfer_buffer)
+ return -ENOMEM;
- ret = comedi_alloc_subdevices(dev, n_subdevs);
- if (ret) {
- up(&udev->sem);
- return ret;
+ urb->complete = usbduxsub_ai_isoc_irq;
+ urb->number_of_packets = 1;
+ urb->transfer_buffer_length = SIZEINBUF;
+ urb->iso_frame_desc[0].offset = 0;
+ urb->iso_frame_desc[0].length = SIZEINBUF;
}
- /* private structure is also simply the usb-structure */
- dev->private = udev;
+ for (i = 0; i < devpriv->n_ao_urbs; i++) {
+ /* one frame: 1ms */
+ urb = usb_alloc_urb(1, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
+ devpriv->ao_urbs[i] = urb;
+
+ urb->dev = usb;
+ urb->context = dev;
+ urb->pipe = usb_sndisocpipe(usb, 2);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
+ if (!urb->transfer_buffer)
+ return -ENOMEM;
- /* the first subdevice is the A/D converter */
- s = &dev->subdevices[SUBDEV_AD];
- /* the URBs get the comedi subdevice */
- /* which is responsible for reading */
- /* this is the subdevice which reads data */
- dev->read_subdev = s;
- /* the subdevice receives as private structure the */
- /* usb-structure */
- s->private = NULL;
- /* analog input */
- s->type = COMEDI_SUBD_AI;
- /* readable and ref is to ground */
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
- /* 8 channels */
- s->n_chan = 8;
- /* length of the channellist */
- s->len_chanlist = 8;
- /* callback functions */
- s->insn_read = usbdux_ai_insn_read;
- s->do_cmdtest = usbdux_ai_cmdtest;
- s->do_cmd = usbdux_ai_cmd;
- s->cancel = usbdux_ai_cancel;
- /* max value from the A/D converter (12bit) */
- s->maxdata = 0xfff;
- /* range table to convert to physical units */
- s->range_table = (&range_usbdux_ai_range);
-
- /* analog out */
- s = &dev->subdevices[SUBDEV_DA];
- /* analog out */
- s->type = COMEDI_SUBD_AO;
- /* backward pointer */
- dev->write_subdev = s;
- /* the subdevice receives as private structure the */
- /* usb-structure */
- s->private = NULL;
- /* are writable */
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
- /* 4 channels */
- s->n_chan = 4;
- /* length of the channellist */
- s->len_chanlist = 4;
- /* 12 bit resolution */
- s->maxdata = 0x0fff;
- /* bipolar range */
- s->range_table = (&range_usbdux_ao_range);
- /* callback */
- s->do_cmdtest = usbdux_ao_cmdtest;
- s->do_cmd = usbdux_ao_cmd;
- s->cancel = usbdux_ao_cancel;
- s->insn_read = usbdux_ao_insn_read;
- s->insn_write = usbdux_ao_insn_write;
-
- /* digital I/O */
- s = &dev->subdevices[SUBDEV_DIO];
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 8;
- s->maxdata = 1;
- s->range_table = (&range_digital);
- s->insn_bits = usbdux_dio_insn_bits;
- s->insn_config = usbdux_dio_insn_config;
- /* we don't use it */
- s->private = NULL;
-
- /* counter */
- s = &dev->subdevices[SUBDEV_COUNTER];
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
- s->n_chan = 4;
- s->maxdata = 0xFFFF;
- s->insn_read = usbdux_counter_read;
- s->insn_write = usbdux_counter_write;
- s->insn_config = usbdux_counter_config;
-
- if (udev->high_speed) {
- /* timer / pwm */
- s = &dev->subdevices[SUBDEV_PWM];
- s->type = COMEDI_SUBD_PWM;
- s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
- s->n_chan = 8;
- /* this defines the max duty cycle resolution */
- s->maxdata = udev->size_pwm_buf;
- s->insn_write = usbdux_pwm_write;
- s->insn_read = usbdux_pwm_read;
- s->insn_config = usbdux_pwm_config;
- usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
+ urb->complete = usbduxsub_ao_isoc_irq;
+ urb->number_of_packets = 1;
+ urb->transfer_buffer_length = SIZEOUTBUF;
+ urb->iso_frame_desc[0].offset = 0;
+ urb->iso_frame_desc[0].length = SIZEOUTBUF;
+ if (devpriv->high_speed)
+ urb->interval = 8; /* uframes */
+ else
+ urb->interval = 1; /* frames */
}
- /* finally decide that it's attached */
- udev->attached = 1;
- up(&udev->sem);
+ /* pwm */
+ if (devpriv->pwm_buf_sz) {
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
+ devpriv->pwm_urb = urb;
- dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n",
- dev->minor);
+ /* max bulk ep size in high speed */
+ urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz,
+ GFP_KERNEL);
+ if (!urb->transfer_buffer)
+ return -ENOMEM;
+ }
return 0;
}
+static void usbdux_free_usb_buffers(struct comedi_device *dev)
+{
+ struct usbdux_private *devpriv = dev->private;
+ struct urb *urb;
+ int i;
+
+ urb = devpriv->pwm_urb;
+ if (urb) {
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ }
+ if (devpriv->ao_urbs) {
+ for (i = 0; i < devpriv->n_ao_urbs; i++) {
+ urb = devpriv->ao_urbs[i];
+ if (urb) {
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ }
+ }
+ kfree(devpriv->ao_urbs);
+ }
+ if (devpriv->ai_urbs) {
+ for (i = 0; i < devpriv->n_ai_urbs; i++) {
+ urb = devpriv->ai_urbs[i];
+ if (urb) {
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ }
+ }
+ kfree(devpriv->ai_urbs);
+ }
+ kfree(devpriv->insn_buf);
+ kfree(devpriv->in_buf);
+ kfree(devpriv->dux_commands);
+}
+
static int usbdux_auto_attach(struct comedi_device *dev,
unsigned long context_unused)
{
- struct usb_interface *uinterf = comedi_to_usb_interface(dev);
- struct usbduxsub *this_usbduxsub = usb_get_intfdata(uinterf);
- struct usb_device *usb = usbduxsub->usbdev;
+ struct usb_interface *intf = comedi_to_usb_interface(dev);
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct usbdux_private *devpriv;
+ struct comedi_subdevice *s;
int ret;
- dev->private = this_usbduxsub; /* This is temporary... */
- ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE,
- usbdux_firmware_upload, 0);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
+
+ sema_init(&devpriv->sem, 1);
+
+ usb_set_intfdata(intf, devpriv);
+
+ devpriv->high_speed = (usb->speed == USB_SPEED_HIGH);
+ if (devpriv->high_speed) {
+ devpriv->n_ai_urbs = NUMOFINBUFFERSHIGH;
+ devpriv->n_ao_urbs = NUMOFOUTBUFFERSHIGH;
+ devpriv->pwm_buf_sz = 512;
+ } else {
+ devpriv->n_ai_urbs = NUMOFINBUFFERSFULL;
+ devpriv->n_ao_urbs = NUMOFOUTBUFFERSFULL;
+ }
+
+ ret = usbdux_alloc_usb_buffers(dev);
+ if (ret)
+ return ret;
+
+ /* setting to alternate setting 3: enabling iso ep and bulk ep. */
+ ret = usb_set_interface(usb, intf->altsetting->desc.bInterfaceNumber,
+ 3);
if (ret < 0) {
- dev->private = NULL;
+ dev_err(dev->class_dev,
+ "could not set alternate setting 3 in high speed\n");
return ret;
}
- dev->private = NULL;
+ ret = comedi_load_firmware(dev, &usb->dev, USBDUX_FIRMWARE,
+ usbdux_firmware_upload, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = comedi_alloc_subdevices(dev, (devpriv->high_speed) ? 5 : 4);
+ if (ret)
+ return ret;
- down(&start_stop_sem);
- if (!this_usbduxsub || !this_usbduxsub->probed) {
- dev_err(dev->class_dev,
- "usbdux: error: auto_attach failed, not connected\n");
- ret = -ENODEV;
- } else if (this_usbduxsub->attached) {
- dev_err(dev->class_dev,
- "error: auto_attach failed, already attached\n");
- ret = -ENODEV;
- } else
- ret = usbdux_attach_common(dev, this_usbduxsub);
- up(&start_stop_sem);
- return ret;
+ /* Analog Input subdevice */
+ s = &dev->subdevices[0];
+ dev->read_subdev = s;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
+ s->n_chan = 8;
+ s->maxdata = 0x0fff;
+ s->len_chanlist = 8;
+ s->range_table = &range_usbdux_ai_range;
+ s->insn_read = usbdux_ai_insn_read;
+ s->do_cmdtest = usbdux_ai_cmdtest;
+ s->do_cmd = usbdux_ai_cmd;
+ s->cancel = usbdux_ai_cancel;
+
+ /* Analog Output subdevice */
+ s = &dev->subdevices[1];
+ dev->write_subdev = s;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
+ s->n_chan = USBDUX_NUM_AO_CHAN;
+ s->maxdata = 0x0fff;
+ s->len_chanlist = s->n_chan;
+ s->range_table = &range_usbdux_ao_range;
+ s->do_cmdtest = usbdux_ao_cmdtest;
+ s->do_cmd = usbdux_ao_cmd;
+ s->cancel = usbdux_ao_cancel;
+ s->insn_read = usbdux_ao_insn_read;
+ s->insn_write = usbdux_ao_insn_write;
+
+ /* Digital I/O subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = usbdux_dio_insn_bits;
+ s->insn_config = usbdux_dio_insn_config;
+
+ /* Counter subdevice */
+ s = &dev->subdevices[3];
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->insn_read = usbdux_counter_read;
+ s->insn_write = usbdux_counter_write;
+ s->insn_config = usbdux_counter_config;
+
+ if (devpriv->high_speed) {
+ /* PWM subdevice */
+ s = &dev->subdevices[4];
+ s->type = COMEDI_SUBD_PWM;
+ s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
+ s->n_chan = 8;
+ s->maxdata = devpriv->pwm_buf_sz;
+ s->insn_write = usbdux_pwm_write;
+ s->insn_config = usbdux_pwm_config;
+
+ usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
+ }
+
+ return 0;
}
static void usbdux_detach(struct comedi_device *dev)
{
- struct usbduxsub *usb = dev->private;
-
- if (usb) {
- down(&usb->sem);
- dev->private = NULL;
- usb->attached = 0;
- usb->comedidev = NULL;
- up(&usb->sem);
- }
+ struct usb_interface *intf = comedi_to_usb_interface(dev);
+ struct usbdux_private *devpriv = dev->private;
+
+ usb_set_intfdata(intf, NULL);
+
+ if (!devpriv)
+ return;
+
+ down(&devpriv->sem);
+
+ /* force unlink all urbs */
+ usbdux_pwm_stop(dev, 1);
+ usbdux_ao_stop(dev, 1);
+ usbdux_ai_stop(dev, 1);
+
+ usbdux_free_usb_buffers(dev);
+
+ up(&devpriv->sem);
}
static struct comedi_driver usbdux_driver = {
@@ -2299,253 +1810,10 @@ static struct comedi_driver usbdux_driver = {
.detach = usbdux_detach,
};
-static int usbdux_usb_probe(struct usb_interface *uinterf,
+static int usbdux_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct usb_device *udev = interface_to_usbdev(uinterf);
- struct device *dev = &uinterf->dev;
- int i;
- int index;
-
- dev_dbg(dev, "comedi_: usbdux_: "
- "finding a free structure for the usb-device\n");
-
- down(&start_stop_sem);
- /* look for a free place in the usbdux array */
- index = -1;
- for (i = 0; i < NUMUSBDUX; i++) {
- if (!(usbduxsub[i].probed)) {
- index = i;
- break;
- }
- }
-
- /* no more space */
- if (index == -1) {
- dev_err(dev, "Too many usbdux-devices connected.\n");
- up(&start_stop_sem);
- return -EMFILE;
- }
- dev_dbg(dev, "comedi_: usbdux: "
- "usbduxsub[%d] is ready to connect to comedi.\n", index);
-
- sema_init(&(usbduxsub[index].sem), 1);
- /* save a pointer to the usb device */
- usbduxsub[index].usbdev = udev;
-
- /* 2.6: save the interface itself */
- usbduxsub[index].interface = uinterf;
- /* get the interface number from the interface */
- usbduxsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber;
- /* hand the private data over to the usb subsystem */
- /* will be needed for disconnect */
- usb_set_intfdata(uinterf, &(usbduxsub[index]));
-
- dev_dbg(dev, "comedi_: usbdux: ifnum=%d\n", usbduxsub[index].ifnum);
-
- /* test if it is high speed (USB 2.0) */
- usbduxsub[index].high_speed =
- (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH);
-
- /* create space for the commands of the DA converter */
- usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL);
- if (!usbduxsub[index].dac_commands) {
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- /* create space for the commands going to the usb device */
- usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
- if (!usbduxsub[index].dux_commands) {
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- /* create space for the in buffer and set it to zero */
- usbduxsub[index].in_buffer = kzalloc(SIZEINBUF, GFP_KERNEL);
- if (!(usbduxsub[index].in_buffer)) {
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- /* create space of the instruction buffer */
- usbduxsub[index].insn_buffer = kzalloc(SIZEINSNBUF, GFP_KERNEL);
- if (!(usbduxsub[index].insn_buffer)) {
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- /* create space for the outbuffer */
- usbduxsub[index].out_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
- if (!(usbduxsub[index].out_buffer)) {
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- /* setting to alternate setting 3: enabling iso ep and bulk ep. */
- i = usb_set_interface(usbduxsub[index].usbdev,
- usbduxsub[index].ifnum, 3);
- if (i < 0) {
- dev_err(dev, "comedi_: usbdux%d: "
- "could not set alternate setting 3 in high speed.\n",
- index);
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENODEV;
- }
- if (usbduxsub[index].high_speed)
- usbduxsub[index].num_in_buffers = NUMOFINBUFFERSHIGH;
- else
- usbduxsub[index].num_in_buffers = NUMOFINBUFFERSFULL;
-
- usbduxsub[index].urb_in =
- kcalloc(usbduxsub[index].num_in_buffers, sizeof(struct urb *),
- GFP_KERNEL);
- if (!(usbduxsub[index].urb_in)) {
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- for (i = 0; i < usbduxsub[index].num_in_buffers; i++) {
- /* one frame: 1ms */
- usbduxsub[index].urb_in[i] = usb_alloc_urb(1, GFP_KERNEL);
- if (usbduxsub[index].urb_in[i] == NULL) {
- dev_err(dev, "comedi_: usbdux%d: "
- "Could not alloc. urb(%d)\n", index, i);
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- usbduxsub[index].urb_in[i]->dev = usbduxsub[index].usbdev;
- /* will be filled later with a pointer to the comedi-device */
- /* and ONLY then the urb should be submitted */
- usbduxsub[index].urb_in[i]->context = NULL;
- usbduxsub[index].urb_in[i]->pipe =
- usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP);
- usbduxsub[index].urb_in[i]->transfer_flags = URB_ISO_ASAP;
- usbduxsub[index].urb_in[i]->transfer_buffer =
- kzalloc(SIZEINBUF, GFP_KERNEL);
- if (!(usbduxsub[index].urb_in[i]->transfer_buffer)) {
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- usbduxsub[index].urb_in[i]->complete = usbduxsub_ai_isoc_irq;
- usbduxsub[index].urb_in[i]->number_of_packets = 1;
- usbduxsub[index].urb_in[i]->transfer_buffer_length = SIZEINBUF;
- usbduxsub[index].urb_in[i]->iso_frame_desc[0].offset = 0;
- usbduxsub[index].urb_in[i]->iso_frame_desc[0].length = SIZEINBUF;
- }
-
- /* out */
- if (usbduxsub[index].high_speed)
- usbduxsub[index].num_out_buffers = NUMOFOUTBUFFERSHIGH;
- else
- usbduxsub[index].num_out_buffers = NUMOFOUTBUFFERSFULL;
-
- usbduxsub[index].urb_out =
- kcalloc(usbduxsub[index].num_out_buffers, sizeof(struct urb *),
- GFP_KERNEL);
- if (!(usbduxsub[index].urb_out)) {
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- for (i = 0; i < usbduxsub[index].num_out_buffers; i++) {
- /* one frame: 1ms */
- usbduxsub[index].urb_out[i] = usb_alloc_urb(1, GFP_KERNEL);
- if (usbduxsub[index].urb_out[i] == NULL) {
- dev_err(dev, "comedi_: usbdux%d: "
- "Could not alloc. urb(%d)\n", index, i);
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- usbduxsub[index].urb_out[i]->dev = usbduxsub[index].usbdev;
- /* will be filled later with a pointer to the comedi-device */
- /* and ONLY then the urb should be submitted */
- usbduxsub[index].urb_out[i]->context = NULL;
- usbduxsub[index].urb_out[i]->pipe =
- usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP);
- usbduxsub[index].urb_out[i]->transfer_flags = URB_ISO_ASAP;
- usbduxsub[index].urb_out[i]->transfer_buffer =
- kzalloc(SIZEOUTBUF, GFP_KERNEL);
- if (!(usbduxsub[index].urb_out[i]->transfer_buffer)) {
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- usbduxsub[index].urb_out[i]->complete = usbduxsub_ao_isoc_irq;
- usbduxsub[index].urb_out[i]->number_of_packets = 1;
- usbduxsub[index].urb_out[i]->transfer_buffer_length = SIZEOUTBUF;
- usbduxsub[index].urb_out[i]->iso_frame_desc[0].offset = 0;
- usbduxsub[index].urb_out[i]->iso_frame_desc[0].length =
- SIZEOUTBUF;
- if (usbduxsub[index].high_speed) {
- /* uframes */
- usbduxsub[index].urb_out[i]->interval = 8;
- } else {
- /* frames */
- usbduxsub[index].urb_out[i]->interval = 1;
- }
- }
-
- /* pwm */
- if (usbduxsub[index].high_speed) {
- /* max bulk ep size in high speed */
- usbduxsub[index].size_pwm_buf = 512;
- usbduxsub[index].urb_pwm = usb_alloc_urb(0, GFP_KERNEL);
- if (usbduxsub[index].urb_pwm == NULL) {
- dev_err(dev, "comedi_: usbdux%d: "
- "Could not alloc. pwm urb\n", index);
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- usbduxsub[index].urb_pwm->transfer_buffer =
- kzalloc(usbduxsub[index].size_pwm_buf, GFP_KERNEL);
- if (!(usbduxsub[index].urb_pwm->transfer_buffer)) {
- tidy_up(&(usbduxsub[index]));
- up(&start_stop_sem);
- return -ENOMEM;
- }
- } else {
- usbduxsub[index].urb_pwm = NULL;
- usbduxsub[index].size_pwm_buf = 0;
- }
-
- usbduxsub[index].ai_cmd_running = 0;
- usbduxsub[index].ao_cmd_running = 0;
- usbduxsub[index].pwm_cmd_running = 0;
-
- /* we've reached the bottom of the function */
- usbduxsub[index].probed = 1;
- up(&start_stop_sem);
-
- return comedi_usb_auto_config(uinterf, &usbdux_driver, 0);
-}
-
-static void usbdux_usb_disconnect(struct usb_interface *intf)
-{
- struct usbduxsub *usbduxsub_tmp = usb_get_intfdata(intf);
- struct usb_device *udev = interface_to_usbdev(intf);
-
- if (!usbduxsub_tmp) {
- dev_err(&intf->dev,
- "comedi_: disconnect called with null pointer.\n");
- return;
- }
- if (usbduxsub_tmp->usbdev != udev) {
- dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n");
- return;
- }
- comedi_usb_auto_unconfig(intf);
- down(&start_stop_sem);
- down(&usbduxsub_tmp->sem);
- tidy_up(usbduxsub_tmp);
- up(&usbduxsub_tmp->sem);
- up(&start_stop_sem);
- dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n");
+ return comedi_usb_auto_config(intf, &usbdux_driver, 0);
}
static const struct usb_device_id usbdux_usb_table[] = {
@@ -2553,13 +1821,12 @@ static const struct usb_device_id usbdux_usb_table[] = {
{ USB_DEVICE(0x13d8, 0x0002) },
{ }
};
-
MODULE_DEVICE_TABLE(usb, usbdux_usb_table);
static struct usb_driver usbdux_usb_driver = {
.name = "usbdux",
.probe = usbdux_usb_probe,
- .disconnect = usbdux_usb_disconnect,
+ .disconnect = comedi_usb_auto_unconfig,
.id_table = usbdux_usb_table,
};
module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver);
@@ -2567,4 +1834,4 @@ module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver);
MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
MODULE_DESCRIPTION("Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com");
MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(FIRMWARE);
+MODULE_FIRMWARE(USBDUX_FIRMWARE);
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 27898c44e54..9707dd1239c 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -1061,10 +1061,9 @@ static int usbduxfast_auto_attach(struct comedi_device *dev,
return -ENODEV;
}
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
sema_init(&devpriv->sem, 1);
usb_set_intfdata(intf, devpriv);
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index 898c3c45040..c47f4087568 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -66,13 +66,6 @@
/* internal addresses of the 8051 processor */
#define USBDUXSUB_CPUCS 0xE600
-/* USB endpoints */
-#define USBDUXSIGMA_CMD_OUT_EP 1 /* command output */
-#define USBDUXSIGMA_ISO_OUT_EP 2 /* analog output ISO/IRQ */
-#define USBDUXSIGMA_PWM_OUT_EP 4 /* pwm output */
-#define USBDUXSIGMA_ISO_IN_EP 6 /* analog input ISO/IRQ */
-#define USBDUXSIGMA_CMD_IN_EP 8 /* command input */
-
/* 300Hz max frequ under PWM */
#define MIN_PWM_PERIOD ((long)(1E9/300))
@@ -168,6 +161,7 @@ struct usbduxsigma_private {
/* input buffer for single insn */
int8_t *insn_buf;
+ int8_t ao_chanlist[USBDUXSIGMA_NUM_AO_CHAN];
unsigned int ao_readback[USBDUXSIGMA_NUM_AO_CHAN];
unsigned high_speed:1;
@@ -188,25 +182,25 @@ struct usbduxsigma_private {
unsigned int ao_counter;
/* interval in frames/uframes */
unsigned int ai_interval;
- /* D/A commands */
- uint8_t *dac_commands;
/* commands */
uint8_t *dux_commands;
struct semaphore sem;
};
+static void usbduxsigma_unlink_urbs(struct urb **urbs, int num_urbs)
+{
+ int i;
+
+ for (i = 0; i < num_urbs; i++)
+ usb_kill_urb(urbs[i]);
+}
+
static void usbduxsigma_ai_stop(struct comedi_device *dev, int do_unlink)
{
struct usbduxsigma_private *devpriv = dev->private;
- if (do_unlink) {
- int i;
-
- for (i = 0; i < devpriv->n_ai_urbs; i++) {
- if (devpriv->ai_urbs[i])
- usb_kill_urb(devpriv->ai_urbs[i]);
- }
- }
+ if (do_unlink && devpriv->ai_urbs)
+ usbduxsigma_unlink_urbs(devpriv->ai_urbs, devpriv->n_ai_urbs);
devpriv->ai_cmd_running = 0;
}
@@ -342,14 +336,8 @@ static void usbduxsigma_ao_stop(struct comedi_device *dev, int do_unlink)
{
struct usbduxsigma_private *devpriv = dev->private;
- if (do_unlink) {
- int i;
-
- for (i = 0; i < devpriv->n_ao_urbs; i++) {
- if (devpriv->ao_urbs[i])
- usb_kill_urb(devpriv->ao_urbs[i]);
- }
- }
+ if (do_unlink && devpriv->ao_urbs)
+ usbduxsigma_unlink_urbs(devpriv->ao_urbs, devpriv->n_ao_urbs);
devpriv->ao_cmd_running = 0;
}
@@ -432,7 +420,7 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb)
len = s->async->cmd.chanlist_len;
*datap++ = len;
for (i = 0; i < len; i++) {
- unsigned int chan = devpriv->dac_commands[i];
+ unsigned int chan = devpriv->ao_chanlist[i];
short val;
ret = comedi_buf_get(s->async, &val);
@@ -643,7 +631,7 @@ static int usbbuxsigma_send_cmd(struct comedi_device *dev, int cmd_type)
devpriv->dux_commands[0] = cmd_type;
- return usb_bulk_msg(usb, usb_sndbulkpipe(usb, USBDUXSIGMA_CMD_OUT_EP),
+ return usb_bulk_msg(usb, usb_sndbulkpipe(usb, 1),
devpriv->dux_commands, SIZEOFDUXBUFFER,
&nsent, BULK_TIMEOUT);
}
@@ -657,8 +645,7 @@ static int usbduxsigma_receive_cmd(struct comedi_device *dev, int command)
int i;
for (i = 0; i < RETRIES; i++) {
- ret = usb_bulk_msg(usb,
- usb_rcvbulkpipe(usb, USBDUXSIGMA_CMD_IN_EP),
+ ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, 8),
devpriv->insn_buf, SIZEINSNBUF,
&nrec, BULK_TIMEOUT);
if (ret < 0)
@@ -686,13 +673,14 @@ static int usbduxsigma_ai_inttrig(struct comedi_device *dev,
down(&devpriv->sem);
if (!devpriv->ai_cmd_running) {
+ devpriv->ai_cmd_running = 1;
ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs,
devpriv->n_ai_urbs, 1);
if (ret < 0) {
+ devpriv->ai_cmd_running = 0;
up(&devpriv->sem);
return ret;
}
- devpriv->ai_cmd_running = 1;
s->async->inttrig = NULL;
}
up(&devpriv->sem);
@@ -740,14 +728,15 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev,
if (cmd->start_src == TRIG_NOW) {
/* enable this acquisition operation */
+ devpriv->ai_cmd_running = 1;
ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs,
devpriv->n_ai_urbs, 1);
if (ret < 0) {
+ devpriv->ai_cmd_running = 0;
up(&devpriv->sem);
return ret;
}
s->async->inttrig = NULL;
- devpriv->ai_cmd_running = 1;
} else { /* TRIG_INT */
/* wait for an internal signal and submit the urbs later */
s->async->inttrig = usbduxsigma_ai_inttrig;
@@ -876,13 +865,14 @@ static int usbduxsigma_ao_inttrig(struct comedi_device *dev,
down(&devpriv->sem);
if (!devpriv->ao_cmd_running) {
+ devpriv->ao_cmd_running = 1;
ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs,
devpriv->n_ao_urbs, 0);
if (ret < 0) {
+ devpriv->ao_cmd_running = 0;
up(&devpriv->sem);
return ret;
}
- devpriv->ao_cmd_running = 1;
s->async->inttrig = NULL;
}
up(&devpriv->sem);
@@ -1020,20 +1010,21 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev,
/* set current channel of the running acquisition to zero */
s->async->cur_chan = 0;
for (i = 0; i < cmd->chanlist_len; ++i)
- devpriv->dac_commands[i] = CR_CHAN(cmd->chanlist[i]);
+ devpriv->ao_chanlist[i] = CR_CHAN(cmd->chanlist[i]);
devpriv->ao_counter = devpriv->ao_timer;
if (cmd->start_src == TRIG_NOW) {
/* enable this acquisition operation */
+ devpriv->ao_cmd_running = 1;
ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs,
devpriv->n_ao_urbs, 0);
if (ret < 0) {
+ devpriv->ao_cmd_running = 0;
up(&devpriv->sem);
return ret;
}
s->async->inttrig = NULL;
- devpriv->ao_cmd_running = 1;
} else { /* TRIG_INT */
/* wait for an internal signal and submit the urbs later */
s->async->inttrig = usbduxsigma_ao_inttrig;
@@ -1049,23 +1040,11 @@ static int usbduxsigma_dio_insn_config(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int mask = 1 << chan;
+ int ret;
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= mask;
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~mask;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
- break;
- default:
- return -EINVAL;
- break;
- }
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
/*
* We don't tell the firmware here as it would take 8 frames
@@ -1194,8 +1173,7 @@ static int usbduxsigma_submit_pwm_urb(struct comedi_device *dev)
struct urb *urb = devpriv->pwm_urb;
/* in case of a resubmission after an unlink... */
- usb_fill_bulk_urb(urb,
- usb, usb_sndbulkpipe(usb, USBDUXSIGMA_PWM_OUT_EP),
+ usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, 4),
urb->transfer_buffer, devpriv->pwm_buf_sz,
usbduxsigma_pwm_urb_complete, dev);
@@ -1237,19 +1215,21 @@ static int usbduxsigma_pwm_start(struct comedi_device *dev,
memset(devpriv->pwm_urb->transfer_buffer, 0, devpriv->pwm_buf_sz);
+ devpriv->pwm_cmd_running = 1;
ret = usbduxsigma_submit_pwm_urb(dev);
- if (ret < 0)
+ if (ret < 0) {
+ devpriv->pwm_cmd_running = 0;
return ret;
- devpriv->pwm_cmd_running = 1;
+ }
return 0;
}
-static int usbduxsigma_pwm_pattern(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int chan,
- unsigned int value,
- unsigned int sign)
+static void usbduxsigma_pwm_pattern(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chan,
+ unsigned int value,
+ unsigned int sign)
{
struct usbduxsigma_private *devpriv = dev->private;
char pwm_mask = (1 << chan); /* DIO bit for the PWM data */
@@ -1270,7 +1250,6 @@ static int usbduxsigma_pwm_pattern(struct comedi_device *dev,
c |= sgn_mask;
*buf++ = c;
}
- return 1;
}
static int usbduxsigma_pwm_write(struct comedi_device *dev,
@@ -1291,7 +1270,9 @@ static int usbduxsigma_pwm_write(struct comedi_device *dev,
* The sign is set via a special INSN only, this gives us 8 bits
* for normal operation, sign is 0 by default.
*/
- return usbduxsigma_pwm_pattern(dev, s, chan, data[0], 0);
+ usbduxsigma_pwm_pattern(dev, s, chan, data[0], 0);
+
+ return insn->n;
}
static int usbduxsigma_pwm_config(struct comedi_device *dev,
@@ -1326,8 +1307,8 @@ static int usbduxsigma_pwm_config(struct comedi_device *dev,
* data[1] = value
* data[2] = sign (for a relay)
*/
- return usbduxsigma_pwm_pattern(dev, s, chan,
- data[1], (data[2] != 0));
+ usbduxsigma_pwm_pattern(dev, s, chan, data[1], (data[2] != 0));
+ return 0;
case INSN_CONFIG_PWM_GET_H_BRIDGE:
/* values are not kept in this driver, nothing to return */
return -EINVAL;
@@ -1386,90 +1367,6 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan)
return (int)val;
}
-static int usbduxsigma_attach_common(struct comedi_device *dev)
-{
- struct usbduxsigma_private *devpriv = dev->private;
- struct comedi_subdevice *s;
- int n_subdevs;
- int offset;
- int ret;
-
- down(&devpriv->sem);
-
- if (devpriv->high_speed)
- n_subdevs = 4; /* with pwm */
- else
- n_subdevs = 3; /* without pwm */
- ret = comedi_alloc_subdevices(dev, n_subdevs);
- if (ret) {
- up(&devpriv->sem);
- return ret;
- }
-
- /* Analog Input subdevice */
- s = &dev->subdevices[0];
- dev->read_subdev = s;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ | SDF_LSAMPL;
- s->n_chan = NUMCHANNELS;
- s->len_chanlist = NUMCHANNELS;
- s->maxdata = 0x00ffffff;
- s->range_table = &usbduxsigma_ai_range;
- s->insn_read = usbduxsigma_ai_insn_read;
- s->do_cmdtest = usbduxsigma_ai_cmdtest;
- s->do_cmd = usbduxsigma_ai_cmd;
- s->cancel = usbduxsigma_ai_cancel;
-
- /* Analog Output subdevice */
- s = &dev->subdevices[1];
- dev->write_subdev = s;
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
- s->n_chan = USBDUXSIGMA_NUM_AO_CHAN;
- s->len_chanlist = s->n_chan;
- s->maxdata = 0x00ff;
- s->range_table = &range_unipolar2_5;
- s->insn_write = usbduxsigma_ao_insn_write;
- s->insn_read = usbduxsigma_ao_insn_read;
- s->do_cmdtest = usbduxsigma_ao_cmdtest;
- s->do_cmd = usbduxsigma_ao_cmd;
- s->cancel = usbduxsigma_ao_cancel;
-
- /* Digital I/O subdevice */
- s = &dev->subdevices[2];
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 24;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = usbduxsigma_dio_insn_bits;
- s->insn_config = usbduxsigma_dio_insn_config;
-
- if (devpriv->high_speed) {
- /* Timer / pwm subdevice */
- s = &dev->subdevices[3];
- s->type = COMEDI_SUBD_PWM;
- s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
- s->n_chan = 8;
- s->maxdata = devpriv->pwm_buf_sz;
- s->insn_write = usbduxsigma_pwm_write;
- s->insn_config = usbduxsigma_pwm_config;
-
- usbduxsigma_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
- }
-
- up(&devpriv->sem);
-
- offset = usbduxsigma_getstatusinfo(dev, 0);
- if (offset < 0)
- dev_err(dev->class_dev,
- "Communication to USBDUXSIGMA failed! Check firmware and cabling\n");
-
- dev_info(dev->class_dev, "attached, ADC_zero = %x\n", offset);
-
- return 0;
-}
-
static int usbduxsigma_firmware_upload(struct comedi_device *dev,
const u8 *data, size_t size,
unsigned long context)
@@ -1548,7 +1445,6 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev)
struct urb *urb;
int i;
- devpriv->dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL);
devpriv->dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
devpriv->in_buf = kzalloc(SIZEINBUF, GFP_KERNEL);
devpriv->insn_buf = kzalloc(SIZEINSNBUF, GFP_KERNEL);
@@ -1556,8 +1452,7 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev)
GFP_KERNEL);
devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(*urb),
GFP_KERNEL);
- if (!devpriv->dac_commands || !devpriv->dux_commands ||
- !devpriv->in_buf || !devpriv->insn_buf ||
+ if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf ||
!devpriv->ai_urbs || !devpriv->ao_urbs)
return -ENOMEM;
@@ -1571,7 +1466,7 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev)
/* will be filled later with a pointer to the comedi-device */
/* and ONLY then the urb should be submitted */
urb->context = NULL;
- urb->pipe = usb_rcvisocpipe(usb, USBDUXSIGMA_ISO_IN_EP);
+ urb->pipe = usb_rcvisocpipe(usb, 6);
urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL);
if (!urb->transfer_buffer)
@@ -1593,7 +1488,7 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev)
/* will be filled later with a pointer to the comedi-device */
/* and ONLY then the urb should be submitted */
urb->context = NULL;
- urb->pipe = usb_sndisocpipe(usb, USBDUXSIGMA_ISO_OUT_EP);
+ urb->pipe = usb_sndisocpipe(usb, 2);
urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
if (!urb->transfer_buffer)
@@ -1609,19 +1504,16 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev)
urb->interval = 1; /* frames */
}
- if (devpriv->high_speed) {
- /* max bulk ep size in high speed */
- devpriv->pwm_buf_sz = 512;
+ if (devpriv->pwm_buf_sz) {
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
devpriv->pwm_urb = urb;
- urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz, GFP_KERNEL);
+
+ urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz,
+ GFP_KERNEL);
if (!urb->transfer_buffer)
return -ENOMEM;
- } else {
- devpriv->pwm_urb = NULL;
- devpriv->pwm_buf_sz = 0;
}
return 0;
@@ -1633,11 +1525,6 @@ static void usbduxsigma_free_usb_buffers(struct comedi_device *dev)
struct urb *urb;
int i;
- /* force unlink all urbs */
- usbduxsigma_ai_stop(dev, 1);
- usbduxsigma_ao_stop(dev, 1);
- usbduxsigma_pwm_stop(dev, 1);
-
urb = devpriv->pwm_urb;
if (urb) {
kfree(urb->transfer_buffer);
@@ -1666,7 +1553,6 @@ static void usbduxsigma_free_usb_buffers(struct comedi_device *dev)
kfree(devpriv->insn_buf);
kfree(devpriv->in_buf);
kfree(devpriv->dux_commands);
- kfree(devpriv->dac_commands);
}
static int usbduxsigma_auto_attach(struct comedi_device *dev,
@@ -1675,29 +1561,23 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev,
struct usb_interface *intf = comedi_to_usb_interface(dev);
struct usb_device *usb = comedi_to_usb_dev(dev);
struct usbduxsigma_private *devpriv;
+ struct comedi_subdevice *s;
+ int offset;
int ret;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
sema_init(&devpriv->sem, 1);
- usb_set_intfdata(intf, devpriv);
- ret = usb_set_interface(usb,
- intf->altsetting->desc.bInterfaceNumber, 3);
- if (ret < 0) {
- dev_err(dev->class_dev,
- "could not set alternate setting 3 in high speed\n");
- return -ENODEV;
- }
+ usb_set_intfdata(intf, devpriv);
- /* test if it is high speed (USB 2.0) */
devpriv->high_speed = (usb->speed == USB_SPEED_HIGH);
if (devpriv->high_speed) {
devpriv->n_ai_urbs = NUMOFINBUFFERSHIGH;
devpriv->n_ao_urbs = NUMOFOUTBUFFERSHIGH;
+ devpriv->pwm_buf_sz = 512;
} else {
devpriv->n_ai_urbs = NUMOFINBUFFERSFULL;
devpriv->n_ao_urbs = NUMOFOUTBUFFERSFULL;
@@ -1707,12 +1587,84 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
+ /* setting to alternate setting 3: enabling iso ep and bulk ep. */
+ ret = usb_set_interface(usb, intf->altsetting->desc.bInterfaceNumber,
+ 3);
+ if (ret < 0) {
+ dev_err(dev->class_dev,
+ "could not set alternate setting 3 in high speed\n");
+ return ret;
+ }
+
ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE,
usbduxsigma_firmware_upload, 0);
if (ret)
return ret;
- return usbduxsigma_attach_common(dev);
+ ret = comedi_alloc_subdevices(dev, (devpriv->high_speed) ? 4 : 3);
+ if (ret)
+ return ret;
+
+ /* Analog Input subdevice */
+ s = &dev->subdevices[0];
+ dev->read_subdev = s;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ | SDF_LSAMPL;
+ s->n_chan = NUMCHANNELS;
+ s->len_chanlist = NUMCHANNELS;
+ s->maxdata = 0x00ffffff;
+ s->range_table = &usbduxsigma_ai_range;
+ s->insn_read = usbduxsigma_ai_insn_read;
+ s->do_cmdtest = usbduxsigma_ai_cmdtest;
+ s->do_cmd = usbduxsigma_ai_cmd;
+ s->cancel = usbduxsigma_ai_cancel;
+
+ /* Analog Output subdevice */
+ s = &dev->subdevices[1];
+ dev->write_subdev = s;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
+ s->n_chan = USBDUXSIGMA_NUM_AO_CHAN;
+ s->len_chanlist = s->n_chan;
+ s->maxdata = 0x00ff;
+ s->range_table = &range_unipolar2_5;
+ s->insn_write = usbduxsigma_ao_insn_write;
+ s->insn_read = usbduxsigma_ao_insn_read;
+ s->do_cmdtest = usbduxsigma_ao_cmdtest;
+ s->do_cmd = usbduxsigma_ao_cmd;
+ s->cancel = usbduxsigma_ao_cancel;
+
+ /* Digital I/O subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 24;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = usbduxsigma_dio_insn_bits;
+ s->insn_config = usbduxsigma_dio_insn_config;
+
+ if (devpriv->high_speed) {
+ /* Timer / pwm subdevice */
+ s = &dev->subdevices[3];
+ s->type = COMEDI_SUBD_PWM;
+ s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
+ s->n_chan = 8;
+ s->maxdata = devpriv->pwm_buf_sz;
+ s->insn_write = usbduxsigma_pwm_write;
+ s->insn_config = usbduxsigma_pwm_config;
+
+ usbduxsigma_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
+ }
+
+ offset = usbduxsigma_getstatusinfo(dev, 0);
+ if (offset < 0)
+ dev_err(dev->class_dev,
+ "Communication to USBDUXSIGMA failed! Check firmware and cabling\n");
+
+ dev_info(dev->class_dev, "attached, ADC_zero = %x\n", offset);
+
+ return 0;
}
static void usbduxsigma_detach(struct comedi_device *dev)
@@ -1720,13 +1672,20 @@ static void usbduxsigma_detach(struct comedi_device *dev)
struct usb_interface *intf = comedi_to_usb_interface(dev);
struct usbduxsigma_private *devpriv = dev->private;
+ usb_set_intfdata(intf, NULL);
+
if (!devpriv)
return;
- usb_set_intfdata(intf, NULL);
-
down(&devpriv->sem);
+
+ /* force unlink all urbs */
+ usbduxsigma_ai_stop(dev, 1);
+ usbduxsigma_ao_stop(dev, 1);
+ usbduxsigma_pwm_stop(dev, 1);
+
usbduxsigma_free_usb_buffers(dev);
+
up(&devpriv->sem);
}
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index 0ab04c0dd41..06efa16b9af 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -875,10 +875,9 @@ static int vmk80xx_auto_attach(struct comedi_device *dev,
dev->board_ptr = boardinfo;
dev->board_name = boardinfo->name;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- dev->private = devpriv;
devpriv->model = boardinfo->model;
diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index da8988c6bf5..cd60677a3ed 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -22,8 +22,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fcntl.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/io.h>
@@ -125,6 +123,27 @@ error:
return ret;
}
+int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev,
+ unsigned int chan, unsigned int *io)
+{
+ struct comedi_insn insn;
+ unsigned int data[2];
+ int ret;
+
+ memset(&insn, 0, sizeof(insn));
+ insn.insn = INSN_CONFIG;
+ insn.n = 2;
+ insn.subdev = subdev;
+ insn.chanspec = CR_PACK(chan, 0, 0);
+ data[0] = INSN_CONFIG_DIO_QUERY;
+ data[1] = 0;
+ ret = comedi_do_insn(dev, &insn, data);
+ if (ret >= 0)
+ *io = data[1];
+ return ret;
+}
+EXPORT_SYMBOL_GPL(comedi_dio_get_config);
+
int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
unsigned int chan, unsigned int io)
{
@@ -140,28 +159,53 @@ int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
}
EXPORT_SYMBOL_GPL(comedi_dio_config);
-int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev,
- unsigned int mask, unsigned int *bits)
+int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev,
+ unsigned int mask, unsigned int *bits,
+ unsigned int base_channel)
{
struct comedi_insn insn;
unsigned int data[2];
+ unsigned int n_chan;
+ unsigned int shift;
int ret;
+ if (subdev >= dev->n_subdevices)
+ return -EINVAL;
+
+ base_channel = CR_CHAN(base_channel);
+ n_chan = comedi_get_n_channels(dev, subdev);
+ if (base_channel >= n_chan)
+ return -EINVAL;
+
memset(&insn, 0, sizeof(insn));
insn.insn = INSN_BITS;
+ insn.chanspec = base_channel;
insn.n = 2;
insn.subdev = subdev;
data[0] = mask;
data[1] = *bits;
- ret = comedi_do_insn(dev, &insn, data);
-
- *bits = data[1];
+ /*
+ * Most drivers ignore the base channel in insn->chanspec.
+ * Fix this here if the subdevice has <= 32 channels.
+ */
+ if (n_chan <= 32) {
+ shift = base_channel;
+ if (shift) {
+ insn.chanspec = 0;
+ data[0] <<= shift;
+ data[1] <<= shift;
+ }
+ } else {
+ shift = 0;
+ }
+ ret = comedi_do_insn(dev, &insn, data);
+ *bits = data[1] >> shift;
return ret;
}
-EXPORT_SYMBOL_GPL(comedi_dio_bitfield);
+EXPORT_SYMBOL_GPL(comedi_dio_bitfield2);
int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
unsigned int subd)
diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c
index 8ee94424bc8..ade00035d3b 100644
--- a/drivers/staging/comedi/proc.c
+++ b/drivers/staging/comedi/proc.c
@@ -55,6 +55,7 @@ static int comedi_read(struct seq_file *m, void *v)
if (!devices_q)
seq_puts(m, "no devices\n");
+ mutex_lock(&comedi_drivers_list_lock);
for (driv = comedi_drivers; driv; driv = driv->next) {
seq_printf(m, "%s:\n", driv->driver_name);
for (i = 0; i < driv->num_names; i++)
@@ -65,6 +66,7 @@ static int comedi_read(struct seq_file *m, void *v)
if (!driv->num_names)
seq_printf(m, " %s\n", driv->driver_name);
}
+ mutex_unlock(&comedi_drivers_list_lock);
return 0;
}
diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c
index 1f20332cc45..8fde55495d3 100644
--- a/drivers/staging/comedi/range.c
+++ b/drivers/staging/comedi/range.c
@@ -127,38 +127,35 @@ static int aref_invalid(struct comedi_subdevice *s, unsigned int chanspec)
return 1;
}
-/*
- This function checks each element in a channel/gain list to make
- make sure it is valid.
+/**
+ * comedi_check_chanlist() - Validate each element in a chanlist.
+ * @s: comedi_subdevice struct
+ * @n: number of elements in the chanlist
+ * @chanlist: the chanlist to validate
*/
int comedi_check_chanlist(struct comedi_subdevice *s, int n,
unsigned int *chanlist)
{
struct comedi_device *dev = s->device;
- int i;
- int chan;
+ unsigned int chanspec;
+ int chan, range_len, i;
- if (s->range_table) {
- for (i = 0; i < n; i++)
- if (CR_CHAN(chanlist[i]) >= s->n_chan ||
- CR_RANGE(chanlist[i]) >= s->range_table->length
- || aref_invalid(s, chanlist[i])) {
- dev_warn(dev->class_dev,
- "bad chanlist[%d]=0x%08x in_chan=%d range length=%d\n",
- i, chanlist[i], s->n_chan,
- s->range_table->length);
- return -EINVAL;
- }
- } else if (s->range_table_list) {
+ if (s->range_table || s->range_table_list) {
for (i = 0; i < n; i++) {
- chan = CR_CHAN(chanlist[i]);
+ chanspec = chanlist[i];
+ chan = CR_CHAN(chanspec);
+ if (s->range_table)
+ range_len = s->range_table->length;
+ else if (s->range_table_list && chan < s->n_chan)
+ range_len = s->range_table_list[chan]->length;
+ else
+ range_len = 0;
if (chan >= s->n_chan ||
- CR_RANGE(chanlist[i]) >=
- s->range_table_list[chan]->length
- || aref_invalid(s, chanlist[i])) {
+ CR_RANGE(chanspec) >= range_len ||
+ aref_invalid(s, chanspec)) {
dev_warn(dev->class_dev,
- "bad chanlist[%d]=0x%08x\n",
- i, chanlist[i]);
+ "bad chanlist[%d]=0x%08x chan=%d range length=%d\n",
+ i, chanspec, chan, range_len);
return -EINVAL;
}
}
diff --git a/drivers/staging/crystalhd/crystalhd_cmds.c b/drivers/staging/crystalhd/crystalhd_cmds.c
index 3ab502b8c3b..07a2f24d0d4 100644
--- a/drivers/staging/crystalhd/crystalhd_cmds.c
+++ b/drivers/staging/crystalhd/crystalhd_cmds.c
@@ -94,8 +94,7 @@ static enum BC_STATUS bc_cproc_notify_mode(struct crystalhd_cmd *ctx,
for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
if (ctx->user[i].mode == DTS_DIAG_MODE ||
ctx->user[i].mode == DTS_PLAYBACK_MODE) {
- BCMLOG_ERR("multiple playback sessions are not "
- "supported..\n");
+ BCMLOG_ERR("multiple playback sessions are not supported..\n");
return BC_STS_ERR_USAGE;
}
}
diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c
index 0c8cb329420..5845e899ee8 100644
--- a/drivers/staging/crystalhd/crystalhd_hw.c
+++ b/drivers/staging/crystalhd/crystalhd_hw.c
@@ -1061,7 +1061,7 @@ static void cpy_pib_to_app(struct c011_pib *src_pib,
dst_pib->aspect_ratio = src_pib->ppb.aspect_ratio;
dst_pib->colour_primaries = src_pib->ppb.colour_primaries;
dst_pib->picture_meta_payload = src_pib->ppb.picture_meta_payload;
- dst_pib->frame_rate = src_pib->resolution ;
+ dst_pib->frame_rate = src_pib->resolution;
return;
}
@@ -1553,11 +1553,10 @@ static void crystalhd_rx_isr(struct crystalhd_hw *hw, uint32_t intr_sts)
crystalhd_get_dnsz(hw, i, &y_dn_sz, &uv_dn_sz);
/* FIXME: jarod: this is where
my mini pci-e card is tripping up */
- BCMLOG(BCMLOG_DBG, "list_index:%x rx[%d] Y:%x "
- "UV:%x Int:%x YDnSz:%x UVDnSz:%x\n",
+ BCMLOG(BCMLOG_DBG, "list_index:%x rx[%d] Y:%x UV:%x Int:%x YDnSz:%x UVDnSz:%x\n",
i, hw->stats.rx_errors, y_err_sts,
uv_err_sts, intr_sts, y_dn_sz,
- uv_dn_sz);
+ uv_dn_sz);
hw->rx_list_sts[i] = sts_free;
comp_sts = BC_STS_ERROR;
break;
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c
index c1f6163cdeb..b17fbf8181c 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.c
+++ b/drivers/staging/crystalhd/crystalhd_lnx.c
@@ -545,8 +545,7 @@ static int chd_dec_pci_probe(struct pci_dev *pdev,
int rc;
enum BC_STATUS sts = BC_STS_SUCCESS;
- BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x "
- "s_vendor:0x%04x s_device: 0x%04x\n",
+ BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x s_vendor:0x%04x s_device: 0x%04x\n",
pdev->vendor, pdev->device, pdev->subsystem_vendor,
pdev->subsystem_device);
diff --git a/drivers/staging/crystalhd/crystalhd_misc.h b/drivers/staging/crystalhd/crystalhd_misc.h
index 4dae3a797e9..aa736c8855d 100644
--- a/drivers/staging/crystalhd/crystalhd_misc.h
+++ b/drivers/staging/crystalhd/crystalhd_misc.h
@@ -177,8 +177,8 @@ extern enum BC_STATUS crystalhd_map_dio(struct crystalhd_adp *, void *,
extern enum BC_STATUS crystalhd_unmap_dio(struct crystalhd_adp *,
struct crystalhd_dio_req*);
-#define crystalhd_get_sgle_paddr(_dio, _ix) (cpu_to_le64(sg_dma_address(&_dio->sg[_ix])))
-#define crystalhd_get_sgle_len(_dio, _ix) (cpu_to_le32(sg_dma_len(&_dio->sg[_ix])))
+#define crystalhd_get_sgle_paddr(_dio, _ix) (sg_dma_address(&_dio->sg[_ix]))
+#define crystalhd_get_sgle_len(_dio, _ix) (sg_dma_len(&_dio->sg[_ix]))
/*================ General Purpose Queues ==================*/
extern enum BC_STATUS crystalhd_create_dioq(struct crystalhd_adp *,
diff --git a/drivers/staging/cxt1e1/Makefile b/drivers/staging/cxt1e1/Makefile
index b9ccb765025..2f217e9daac 100644
--- a/drivers/staging/cxt1e1/Makefile
+++ b/drivers/staging/cxt1e1/Makefile
@@ -2,7 +2,6 @@ obj-$(CONFIG_CXT1E1) += cxt1e1.o
ccflags-y := -DSBE_PMCC4_ENABLE
ccflags-y += -DSBE_ISR_TASKLET
-ccflags-y += -DSBE_INCLUDE_SYMBOLS
cxt1e1-y := \
ossiRelease.o \
diff --git a/drivers/staging/cxt1e1/comet.c b/drivers/staging/cxt1e1/comet.c
index fabfd779c66..d71aea54181 100644
--- a/drivers/staging/cxt1e1/comet.c
+++ b/drivers/staging/cxt1e1/comet.c
@@ -22,22 +22,15 @@
#include "comet.h"
#include "comet_tables.h"
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC static
-#endif
-
-
extern int cxt1e1_log_level;
#define COMET_NUM_SAMPLES 24 /* Number of entries in the waveform table */
#define COMET_NUM_UNITS 5 /* Number of points per entry in table */
/* forward references */
-STATIC void SetPwrLevel(comet_t *comet);
-STATIC void WrtRcvEqualizerTbl(ci_t *ci, comet_t *comet, u_int32_t *table);
-STATIC void WrtXmtWaveformTbl(ci_t *ci, comet_t *comet, u_int8_t table[COMET_NUM_SAMPLES][COMET_NUM_UNITS]);
+static void SetPwrLevel(comet_t *comet);
+static void WrtRcvEqualizerTbl(ci_t *ci, comet_t *comet, u_int32_t *table);
+static void WrtXmtWaveformTbl(ci_t *ci, comet_t *comet, u_int8_t table[COMET_NUM_SAMPLES][COMET_NUM_UNITS]);
void *TWV_table[12] = {
@@ -407,7 +400,7 @@ void init_comet(void *ci, comet_t *comet, u_int32_t port_mode, int clockmaster,
** Write the data to the Pulse Waveform Storage Data register.
** Returns: Nothing
*/
-STATIC void
+static void
WrtXmtWaveform(ci_t *ci, comet_t *comet, u_int32_t sample, u_int32_t unit, u_int8_t data)
{
u_int8_t WaveformAddr;
@@ -425,7 +418,7 @@ WrtXmtWaveform(ci_t *ci, comet_t *comet, u_int32_t sample, u_int32_t unit, u_int
** for driving the transmitter DAC.
** Returns: Nothing
*/
-STATIC void
+static void
WrtXmtWaveformTbl(ci_t *ci, comet_t *comet,
u_int8_t table[COMET_NUM_SAMPLES][COMET_NUM_UNITS])
{
@@ -452,7 +445,7 @@ WrtXmtWaveformTbl(ci_t *ci, comet_t *comet,
** is coded with early setup of indirect address.
*/
-STATIC void
+static void
WrtRcvEqualizerTbl(ci_t *ci, comet_t *comet, u_int32_t *table)
{
u_int32_t ramaddr;
@@ -516,7 +509,7 @@ WrtRcvEqualizerTbl(ci_t *ci, comet_t *comet, u_int32_t *table)
** Returns: Nothing
*/
-STATIC void
+static void
SetPwrLevel(comet_t *comet)
{
volatile u_int32_t temp;
@@ -558,7 +551,7 @@ SetPwrLevel(comet_t *comet)
** Returns: Nothing
*/
#if 0
-STATIC void
+static void
SetCometOps(comet_t *comet)
{
volatile u_int8_t rd_value;
diff --git a/drivers/staging/cxt1e1/functions.c b/drivers/staging/cxt1e1/functions.c
index 6167dc57457..d021b312ffa 100644
--- a/drivers/staging/cxt1e1/functions.c
+++ b/drivers/staging/cxt1e1/functions.c
@@ -24,13 +24,6 @@
#include "libsbew.h"
#include "pmcc4.h"
-
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC static
-#endif
-
#if defined(CONFIG_SBE_HDLC_V7) || defined(CONFIG_SBE_WAN256T3_HDLC_V7) || \
defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE)
#define _v7_hdlc_ 1
@@ -111,7 +104,7 @@ pci_flush_write (ci_t *ci)
}
-STATIC void
+static void
watchdog_func (unsigned long arg)
{
struct watchdog *wd = (void *) arg;
diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c
index 110c252d38d..53e923701ae 100644
--- a/drivers/staging/cxt1e1/hwprobe.c
+++ b/drivers/staging/cxt1e1/hwprobe.c
@@ -31,12 +31,6 @@
#include "sbeproc.h"
#endif
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC static
-#endif
-
extern int cxt1e1_log_level;
extern int error_flag;
extern int drvr_state;
@@ -221,7 +215,7 @@ cleanup_devs (void)
}
-STATIC int __init
+static int __init
c4_hdw_init (struct pci_dev *pdev, int found)
{
hdw_info_t *hi;
diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c
index e5889ef190a..142691c8d8d 100644
--- a/drivers/staging/cxt1e1/linux.c
+++ b/drivers/staging/cxt1e1/linux.c
@@ -52,12 +52,6 @@
/*****************************************************************************************/
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC static
-#endif
-
#define CHANNAME "hdlc"
/*******************************************************************/
@@ -285,7 +279,7 @@ void_open (struct net_device *ndev)
}
-STATIC int
+static int
chan_open (struct net_device *ndev)
{
hdlc_device *hdlc = dev_to_hdlc (ndev);
@@ -305,7 +299,7 @@ chan_open (struct net_device *ndev)
}
-STATIC int
+static int
chan_close (struct net_device *ndev)
{
hdlc_device *hdlc = dev_to_hdlc (ndev);
@@ -319,14 +313,14 @@ chan_close (struct net_device *ndev)
}
-STATIC int
+static int
chan_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
{
return hdlc_ioctl (dev, ifr, cmd);
}
-STATIC int
+static int
chan_attach_noop (struct net_device *ndev, unsigned short foo_1, unsigned short foo_2)
{
return 0; /* our driver has nothing to do here, show's
@@ -334,7 +328,7 @@ chan_attach_noop (struct net_device *ndev, unsigned short foo_1, unsigned short
}
-STATIC struct net_device_stats *
+static struct net_device_stats *
chan_get_stats (struct net_device *ndev)
{
mch_t *ch;
@@ -394,7 +388,7 @@ get_ci_by_dev (struct net_device *ndev)
}
-STATIC int
+static int
c4_linux_xmit (struct sk_buff *skb, struct net_device *ndev)
{
const struct c4_priv *priv;
@@ -416,7 +410,7 @@ static const struct net_device_ops chan_ops = {
.ndo_get_stats = chan_get_stats,
};
-STATIC struct net_device *
+static struct net_device *
create_chan (struct net_device *ndev, ci_t *ci,
struct sbecom_chan_param *cp)
{
@@ -509,7 +503,7 @@ create_chan (struct net_device *ndev, ci_t *ci,
/* the idea here is to get port information and pass it back (using pointer) */
-STATIC status_t
+static status_t
do_get_port (struct net_device *ndev, void *data)
{
int ret;
@@ -534,7 +528,7 @@ do_get_port (struct net_device *ndev, void *data)
}
/* this function copys the user data and then calls the real action function */
-STATIC status_t
+static status_t
do_set_port (struct net_device *ndev, void *data)
{
ci_t *ci; /* ci stands for card information */
@@ -556,7 +550,7 @@ do_set_port (struct net_device *ndev, void *data)
}
/* work the port loopback mode as per directed */
-STATIC status_t
+static status_t
do_port_loop (struct net_device *ndev, void *data)
{
struct sbecom_port_param pp;
@@ -571,7 +565,7 @@ do_port_loop (struct net_device *ndev, void *data)
}
/* set the specified register with the given value / or just read it */
-STATIC status_t
+static status_t
do_framer_rw (struct net_device *ndev, void *data)
{
struct sbecom_port_param pp;
@@ -592,7 +586,7 @@ do_framer_rw (struct net_device *ndev, void *data)
}
/* set the specified register with the given value / or just read it */
-STATIC status_t
+static status_t
do_pld_rw (struct net_device *ndev, void *data)
{
struct sbecom_port_param pp;
@@ -613,7 +607,7 @@ do_pld_rw (struct net_device *ndev, void *data)
}
/* set the specified register with the given value / or just read it */
-STATIC status_t
+static status_t
do_musycc_rw (struct net_device *ndev, void *data)
{
struct c4_musycc_param mp;
@@ -633,7 +627,7 @@ do_musycc_rw (struct net_device *ndev, void *data)
return 0;
}
-STATIC status_t
+static status_t
do_get_chan (struct net_device *ndev, void *data)
{
struct sbecom_chan_param cp;
@@ -651,7 +645,7 @@ do_get_chan (struct net_device *ndev, void *data)
return 0;
}
-STATIC status_t
+static status_t
do_set_chan (struct net_device *ndev, void *data)
{
struct sbecom_chan_param cp;
@@ -672,7 +666,7 @@ do_set_chan (struct net_device *ndev, void *data)
}
}
-STATIC status_t
+static status_t
do_create_chan (struct net_device *ndev, void *data)
{
ci_t *ci;
@@ -699,7 +693,7 @@ do_create_chan (struct net_device *ndev, void *data)
return ret;
}
-STATIC status_t
+static status_t
do_get_chan_stats (struct net_device *ndev, void *data)
{
struct c4_chan_stats_wrap ccs;
@@ -720,7 +714,7 @@ do_get_chan_stats (struct net_device *ndev, void *data)
return -EFAULT;
return 0;
}
-STATIC status_t
+static status_t
do_set_loglevel (struct net_device *ndev, void *data)
{
unsigned int cxt1e1_log_level;
@@ -731,7 +725,7 @@ do_set_loglevel (struct net_device *ndev, void *data)
return 0;
}
-STATIC status_t
+static status_t
do_deluser (struct net_device *ndev, int lockit)
{
if (ndev->flags & IFF_UP)
@@ -826,7 +820,7 @@ do_reset_chan_stats (struct net_device *musycc_dev, void *data)
return mkret (c4_del_chan_stats (cp.channum));
}
-STATIC status_t
+static status_t
c4_ioctl (struct net_device *ndev, struct ifreq *ifr, int cmd)
{
ci_t *ci;
@@ -1102,7 +1096,7 @@ c4_add_dev (hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1,
return ndev;
}
-STATIC int __init
+static int __init
c4_mod_init (void)
{
int rtn;
@@ -1144,7 +1138,7 @@ c4_mod_init (void)
* do_deluser()
*/
-STATIC void __exit
+static void __exit
cleanup_hdlc (void)
{
hdw_info_t *hi;
@@ -1168,7 +1162,7 @@ cleanup_hdlc (void)
}
-STATIC void __exit
+static void __exit
c4_mod_remove (void)
{
cleanup_hdlc(); /* delete any missed channels */
diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c
index 1037086d00a..52b6d7f5fd4 100644
--- a/drivers/staging/cxt1e1/musycc.c
+++ b/drivers/staging/cxt1e1/musycc.c
@@ -35,12 +35,6 @@ unsigned int max_bh = 0;
#include "pmcc4.h"
#include "musycc.h"
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC static
-#endif
-
#define sd_find_chan(ci,ch) c4_find_chan(ch)
@@ -65,7 +59,6 @@ void c4_wk_chan_restart(mch_t *);
void musycc_bh_tx_eom(mpi_t *, int);
int musycc_chan_up(ci_t *, int);
status_t __init musycc_init(ci_t *);
-STATIC void __init musycc_init_port(mpi_t *);
void musycc_intr_bh_tasklet(ci_t *);
void musycc_serv_req(mpi_t *, u_int32_t);
void musycc_update_timeslots(mpi_t *);
@@ -73,7 +66,7 @@ void musycc_update_timeslots(mpi_t *);
/*******************************************************************/
#if 1
-STATIC int
+static int
musycc_dump_rxbuffer_ring(mch_t *ch, int lockit)
{
struct mdesc *m;
@@ -139,7 +132,7 @@ musycc_dump_rxbuffer_ring(mch_t *ch, int lockit)
#endif
#if 1
-STATIC int
+static int
musycc_dump_txbuffer_ring(mch_t *ch, int lockit)
{
struct mdesc *m;
@@ -702,7 +695,7 @@ musycc_chan_proto(int proto)
}
#ifdef SBE_WAN256T3_ENABLE
-STATIC void __init
+static void __init
musycc_init_port(mpi_t *pi)
{
pci_write_32((u_int32_t *) &pi->reg->gbp, OS_vtophys(pi->regram));
@@ -1009,7 +1002,7 @@ musycc_bh_tx_eom(mpi_t *pi, int gchan)
}
-STATIC void
+static void
musycc_bh_rx_eom(mpi_t *pi, int gchan)
{
mch_t *ch;
diff --git a/drivers/staging/cxt1e1/pmc93x6_eeprom.c b/drivers/staging/cxt1e1/pmc93x6_eeprom.c
index 62b12fb45fc..137b63cb553 100644
--- a/drivers/staging/cxt1e1/pmc93x6_eeprom.c
+++ b/drivers/staging/cxt1e1/pmc93x6_eeprom.c
@@ -34,13 +34,6 @@
#define FALSE 0
#endif
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC static
-#endif
-
-
/*------------------------------------------------------------------------
* EEPROM address definitions
*------------------------------------------------------------------------
@@ -120,7 +113,7 @@ short mfg_template[sizeof (FLD_TYPE2)] =
* (the MSB becomes the LSB etc.).
*/
-STATIC void
+static void
BuildByteReverse (void)
{
long half; /* Used to build by powers to 2 */
@@ -141,7 +134,7 @@ BuildByteReverse (void)
*------------------------------------------------------------------------
*/
-STATIC void
+static void
eeprom_delay (void)
{
int timeout;
@@ -224,7 +217,7 @@ eeprom_get_byte (long addr)
* Issue the EEPROM command to disable writes.
*/
-STATIC void
+static void
disable_pmc_eeprom (long addr)
{
eeprom_put_byte (addr, EPROM_EWDS, SIZE_ADDR_OP);
@@ -241,7 +234,7 @@ disable_pmc_eeprom (long addr)
* Issue the EEPROM command to enable writes.
*/
-STATIC void
+static void
enable_pmc_eeprom (long addr)
{
eeprom_put_byte (addr, EPROM_EWEN, SIZE_ADDR_OP);
diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c
index 32d7a216a41..2383c609bf3 100644
--- a/drivers/staging/cxt1e1/pmcc4_drv.c
+++ b/drivers/staging/cxt1e1/pmcc4_drv.c
@@ -39,13 +39,6 @@
#include "comet.h"
#include "sbe_bid.h"
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC static
-#endif
-
-
#define KERN_WARN KERN_WARNING
/* forward references */
@@ -458,7 +451,7 @@ checkPorts (ci_t *ci)
}
-STATIC void
+static void
c4_watchdog (ci_t *ci)
{
if (drvr_state != SBE_DRVR_AVAILABLE)
@@ -1184,7 +1177,7 @@ c4_get_chan_stats (int channum, struct sbecom_chan_stats *p)
return 0;
}
-STATIC int
+static int
c4_fifo_alloc (mpi_t *pi, int chan, int *len)
{
int i, l = 0, start = 0, max = 0, maxstart = 0;
diff --git a/drivers/staging/cxt1e1/sbeid.c b/drivers/staging/cxt1e1/sbeid.c
index 0f9bd5f8136..791993fec96 100644
--- a/drivers/staging/cxt1e1/sbeid.c
+++ b/drivers/staging/cxt1e1/sbeid.c
@@ -19,13 +19,6 @@
#include "pmcc4.h"
#include "sbe_bid.h"
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC static
-#endif
-
-
char *
sbeid_get_bdname (ci_t *ci)
{
diff --git a/drivers/staging/dgap/Kconfig b/drivers/staging/dgap/Kconfig
new file mode 100644
index 00000000000..31f1d7533ee
--- /dev/null
+++ b/drivers/staging/dgap/Kconfig
@@ -0,0 +1,6 @@
+config DGAP
+ tristate "Digi EPCA PCI products"
+ default n
+ depends on TTY
+ ---help---
+ Driver for the Digi International EPCA PCI based product line
diff --git a/drivers/staging/dgap/Makefile b/drivers/staging/dgap/Makefile
new file mode 100644
index 00000000000..9f1fce157c7
--- /dev/null
+++ b/drivers/staging/dgap/Makefile
@@ -0,0 +1,9 @@
+EXTRA_CFLAGS += -DDG_NAME=\"dgap-1.3-16\" -DDG_PART=\"40002347_C\"
+
+obj-$(CONFIG_DGAP) += dgap.o
+
+
+dgap-objs := dgap_driver.o dgap_fep5.o \
+ dgap_parse.o dgap_trace.o \
+ dgap_tty.o dgap_sysfs.o
+
diff --git a/drivers/staging/dgap/dgap_conf.h b/drivers/staging/dgap/dgap_conf.h
new file mode 100644
index 00000000000..88097013ed0
--- /dev/null
+++ b/drivers/staging/dgap/dgap_conf.h
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************
+ *
+ * dgap_conf.h - Header file for installations and parse files.
+ *
+ * $Id: dgap_conf.h,v 1.1 2009/10/23 14:01:57 markh Exp $
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef _DGAP_CONF_H
+#define _DGAP_CONF_H
+
+#define NULLNODE 0 /* header node, not used */
+#define BNODE 1 /* Board node */
+#define LNODE 2 /* Line node */
+#define CNODE 3 /* Concentrator node */
+#define MNODE 4 /* EBI Module node */
+#define TNODE 5 /* tty name prefix node */
+#define CUNODE 6 /* cu name prefix (non-SCO) */
+#define PNODE 7 /* trans. print prefix node */
+#define JNODE 8 /* maJor number node */
+#define ANODE 9 /* altpin */
+#define TSNODE 10 /* tty structure size */
+#define CSNODE 11 /* channel structure size */
+#define BSNODE 12 /* board structure size */
+#define USNODE 13 /* unit schedule structure size */
+#define FSNODE 14 /* f2200 structure size */
+#define VSNODE 15 /* size of VPIX structures */
+#define INTRNODE 16 /* enable interrupt */
+
+/* Enumeration of tokens */
+#define BEGIN 1
+#define END 2
+#define BOARD 10
+
+#define EPCFS 11 /* start of EPC family definitions */
+#define ICX 11
+#define MCX 13
+#define PCX 14
+#define IEPC 15
+#define EEPC 16
+#define MEPC 17
+#define IPCM 18
+#define EPCM 19
+#define MPCM 20
+#define PEPC 21
+#define PPCM 22
+#ifdef CP
+#define ICP 23
+#define ECP 24
+#define MCP 25
+#endif
+#define EPCFE 25 /* end of EPC family definitions */
+#define PC2E 26
+#define PC4E 27
+#define PC4E8K 28
+#define PC8E 29
+#define PC8E8K 30
+#define PC16E 31
+#define MC2E8K 34
+#define MC4E8K 35
+#define MC8E8K 36
+
+#define AVANFS 42 /* start of Avanstar family definitions */
+#define A8P 42
+#define A16P 43
+#define AVANFE 43 /* end of Avanstar family definitions */
+
+#define DA2000FS 44 /* start of AccelePort 2000 family definitions */
+#define DA22 44 /* AccelePort 2002 */
+#define DA24 45 /* AccelePort 2004 */
+#define DA28 46 /* AccelePort 2008 */
+#define DA216 47 /* AccelePort 2016 */
+#define DAR4 48 /* AccelePort RAS 4 port */
+#define DAR8 49 /* AccelePort RAS 8 port */
+#define DDR24 50 /* DataFire RAS 24 port */
+#define DDR30 51 /* DataFire RAS 30 port */
+#define DDR48 52 /* DataFire RAS 48 port */
+#define DDR60 53 /* DataFire RAS 60 port */
+#define DA2000FE 53 /* end of AccelePort 2000/RAS family definitions */
+
+#define PCXRFS 106 /* start of PCXR family definitions */
+#define APORT4 106
+#define APORT8 107
+#define PAPORT4 108
+#define PAPORT8 109
+#define APORT4_920I 110
+#define APORT8_920I 111
+#define APORT4_920P 112
+#define APORT8_920P 113
+#define APORT2_920P 114
+#define PCXRFE 117 /* end of PCXR family definitions */
+
+#define LINE 82
+#ifdef T1
+#define T1M 83
+#define E1M 84
+#endif
+#define CONC 64
+#define CX 65
+#define EPC 66
+#define MOD 67
+#define PORTS 68
+#define METHOD 69
+#define CUSTOM 70
+#define BASIC 71
+#define STATUS 72
+#define MODEM 73
+/* The following tokens can appear in multiple places */
+#define SPEED 74
+#define NPORTS 75
+#define ID 76
+#define CABLE 77
+#define CONNECT 78
+#define IO 79
+#define MEM 80
+#define DPSZ 81
+
+#define TTYN 90
+#define CU 91
+#define PRINT 92
+#define XPRINT 93
+#define CMAJOR 94
+#define ALTPIN 95
+#define STARTO 96
+#define USEINTR 97
+#define PCIINFO 98
+
+#define TTSIZ 100
+#define CHSIZ 101
+#define BSSIZ 102
+#define UNTSIZ 103
+#define F2SIZ 104
+#define VPSIZ 105
+
+#define TOTAL_BOARD 2
+#define CURRENT_BRD 4
+#define BOARD_TYPE 6
+#define IO_ADDRESS 8
+#define MEM_ADDRESS 10
+
+#define FIELDS_PER_PAGE 18
+
+#define TB_FIELD 1
+#define CB_FIELD 3
+#define BT_FIELD 5
+#define IO_FIELD 7
+#define ID_FIELD 8
+#define ME_FIELD 9
+#define TTY_FIELD 11
+#define CU_FIELD 13
+#define PR_FIELD 15
+#define MPR_FIELD 17
+
+#define MAX_FIELD 512
+
+#define INIT 0
+#define NITEMS 128
+#define MAX_ITEM 512
+
+#define DSCRINST 1
+#define DSCRNUM 3
+#define ALTPINQ 5
+#define SSAVE 7
+
+#define DSCR "32"
+#define ONETONINE "123456789"
+#define ALL "1234567890"
+
+
+struct cnode {
+ struct cnode *next;
+ int type;
+ int numbrd;
+
+ union {
+ struct {
+ char type; /* Board Type */
+ short port; /* I/O Address */
+ char *portstr; /* I/O Address in string */
+ long addr; /* Memory Address */
+ char *addrstr; /* Memory Address in string */
+ long pcibus; /* PCI BUS */
+ char *pcibusstr; /* PCI BUS in string */
+ long pcislot; /* PCI SLOT */
+ char *pcislotstr; /* PCI SLOT in string */
+ char nport; /* Number of Ports */
+ char *id; /* tty id */
+ int start; /* start of tty counting */
+ char *method; /* Install method */
+ char v_type;
+ char v_port;
+ char v_addr;
+ char v_pcibus;
+ char v_pcislot;
+ char v_nport;
+ char v_id;
+ char v_start;
+ char v_method;
+ char line1;
+ char line2;
+ char conc1; /* total concs in line1 */
+ char conc2; /* total concs in line2 */
+ char module1; /* total modules for line1 */
+ char module2; /* total modules for line2 */
+ char *status; /* config status */
+ char *dimstatus; /* Y/N */
+ int status_index; /* field pointer */
+ } board;
+
+ struct {
+ char *cable;
+ char v_cable;
+ char speed;
+ char v_speed;
+ } line;
+
+ struct {
+ char type;
+ char *connect;
+ char speed;
+ char nport;
+ char *id;
+ char *idstr;
+ int start;
+ char v_type;
+ char v_connect;
+ char v_speed;
+ char v_nport;
+ char v_id;
+ char v_start;
+ } conc;
+
+ struct {
+ char type;
+ char nport;
+ char *id;
+ char *idstr;
+ int start;
+ char v_type;
+ char v_nport;
+ char v_id;
+ char v_start;
+ } module;
+
+ char *ttyname;
+
+ char *cuname;
+
+ char *printname;
+
+ int majornumber;
+
+ int altpin;
+
+ int ttysize;
+
+ int chsize;
+
+ int bssize;
+
+ int unsize;
+
+ int f2size;
+
+ int vpixsize;
+
+ int useintr;
+ } u;
+};
+
+#endif
diff --git a/drivers/staging/dgap/dgap_downld.h b/drivers/staging/dgap/dgap_downld.h
new file mode 100644
index 00000000000..f79e65cd1d5
--- /dev/null
+++ b/drivers/staging/dgap/dgap_downld.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: dgap_downld.h,v 1.1 2009/10/23 14:01:57 markh Exp $
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ */
+
+/*
+** downld.h
+** - describes the interface between the user level download process
+** and the concentrator download driver.
+*/
+
+#ifndef _DGAP_DOWNLD_H_
+#define _DGAP_DOWNLD_H_
+
+
+struct fepimg {
+ int type; /* board type */
+ int len; /* length of image */
+ char fepimage[1]; /* begining of image */
+};
+
+struct downldio {
+ unsigned int req_type; /* FEP or concentrator */
+ unsigned int bdid; /* opaque board identifier */
+ union {
+ struct downld_t dl; /* download structure */
+ struct fepimg fi; /* fep/bios image structure */
+ } image;
+};
+
+#define DIGI_DLREQ_GET (('d'<<8) | 220)
+#define DIGI_DLREQ_SET (('d'<<8) | 221)
+
+#define DIGI_DL_NUKE (('d'<<8) | 222) /* Not really a dl request, but
+ dangerous enuff to not put in
+ digi.h */
+/* Packed bits of intarg for DIGI_DL_NUKE */
+#define DIGI_NUKE_RESET_ALL (1 << 31)
+#define DIGI_NUKE_INHIBIT_POLLER (1 << 30)
+#define DIGI_NUKE_BRD_NUMB 0x0f
+
+
+
+#define DLREQ_BIOS 0
+#define DLREQ_FEP 1
+#define DLREQ_CONC 2
+#define DLREQ_CONFIG 3
+#define DLREQ_DEVCREATE 4
+
+#endif
diff --git a/drivers/staging/dgap/dgap_driver.c b/drivers/staging/dgap/dgap_driver.c
new file mode 100644
index 00000000000..724a685753d
--- /dev/null
+++ b/drivers/staging/dgap/dgap_driver.c
@@ -0,0 +1,1048 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ * $Id: dgap_driver.c,v 1.3 2011/06/21 10:35:16 markh Exp $
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h> /* For udelay */
+#include <linux/slab.h>
+#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+#include <linux/sched.h>
+#endif
+
+#include "dgap_driver.h"
+#include "dgap_pci.h"
+#include "dgap_fep5.h"
+#include "dgap_tty.h"
+#include "dgap_conf.h"
+#include "dgap_parse.h"
+#include "dgap_trace.h"
+#include "dgap_sysfs.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_DESCRIPTION("Driver for the Digi International EPCA PCI based product line");
+MODULE_SUPPORTED_DEVICE("dgap");
+
+/*
+ * insmod command line overrideable parameters
+ *
+ * NOTE: we use a set of macros to create the variables, which allows
+ * us to specify the variable type, name, initial value, and description.
+ */
+PARM_INT(debug, 0x00, 0644, "Driver debugging level");
+PARM_INT(rawreadok, 1, 0644, "Bypass flip buffers on input");
+PARM_INT(trcbuf_size, 0x100000, 0644, "Debugging trace buffer size.");
+
+
+/**************************************************************************
+ *
+ * protos for this file
+ *
+ */
+
+static int dgap_start(void);
+static void dgap_init_globals(void);
+static int dgap_found_board(struct pci_dev *pdev, int id);
+static void dgap_cleanup_board(struct board_t *brd);
+static void dgap_poll_handler(ulong dummy);
+static int dgap_init_pci(void);
+static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void dgap_remove_one(struct pci_dev *dev);
+static int dgap_probe1(struct pci_dev *pdev, int card_type);
+static void dgap_mbuf(struct board_t *brd, const char *fmt, ...);
+static int dgap_do_remap(struct board_t *brd);
+static irqreturn_t dgap_intr(int irq, void *voidbrd);
+
+/* Driver load/unload functions */
+int dgap_init_module(void);
+void dgap_cleanup_module(void);
+
+module_init(dgap_init_module);
+module_exit(dgap_cleanup_module);
+
+
+/*
+ * File operations permitted on Control/Management major.
+ */
+static struct file_operations DgapBoardFops =
+{
+ .owner = THIS_MODULE,
+};
+
+
+/*
+ * Globals
+ */
+uint dgap_NumBoards;
+struct board_t *dgap_Board[MAXBOARDS];
+DEFINE_SPINLOCK(dgap_global_lock);
+ulong dgap_poll_counter;
+char *dgap_config_buf;
+int dgap_driver_state = DRIVER_INITIALIZED;
+DEFINE_SPINLOCK(dgap_dl_lock);
+wait_queue_head_t dgap_dl_wait;
+int dgap_dl_action;
+int dgap_poll_tick = 20; /* Poll interval - 20 ms */
+
+/*
+ * Static vars.
+ */
+static int dgap_Major_Control_Registered = FALSE;
+static uint dgap_driver_start = FALSE;
+
+static struct class * dgap_class;
+
+/*
+ * Poller stuff
+ */
+static DEFINE_SPINLOCK(dgap_poll_lock); /* Poll scheduling lock */
+static ulong dgap_poll_time; /* Time of next poll */
+static uint dgap_poll_stop; /* Used to tell poller to stop */
+static struct timer_list dgap_poll_timer;
+
+
+static struct pci_device_id dgap_pci_tbl[] = {
+ { DIGI_VID, PCI_DEVICE_XEM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { DIGI_VID, PCI_DEVICE_CX_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+ { DIGI_VID, PCI_DEVICE_CX_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+ { DIGI_VID, PCI_DEVICE_EPCJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+ { DIGI_VID, PCI_DEVICE_920_2_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { DIGI_VID, PCI_DEVICE_920_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+ { DIGI_VID, PCI_DEVICE_920_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
+ { DIGI_VID, PCI_DEVICE_XR_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
+ { DIGI_VID, PCI_DEVICE_XRJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { DIGI_VID, PCI_DEVICE_XR_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
+ { DIGI_VID, PCI_DEVICE_XR_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
+ { DIGI_VID, PCI_DEVICE_XR_SAIP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
+ { DIGI_VID, PCI_DEVICE_XR_BULL_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
+ { DIGI_VID, PCI_DEVICE_920_8_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
+ { DIGI_VID, PCI_DEVICE_XEM_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
+ {0,} /* 0 terminated list. */
+};
+MODULE_DEVICE_TABLE(pci, dgap_pci_tbl);
+
+
+/*
+ * A generic list of Product names, PCI Vendor ID, and PCI Device ID.
+ */
+struct board_id {
+ uint config_type;
+ uchar *name;
+ uint maxports;
+ uint dpatype;
+};
+
+static struct board_id dgap_Ids[] =
+{
+ { PPCM, PCI_DEVICE_XEM_NAME, 64, (T_PCXM | T_PCLITE | T_PCIBUS) },
+ { PCX, PCI_DEVICE_CX_NAME, 128, (T_CX | T_PCIBUS) },
+ { PCX, PCI_DEVICE_CX_IBM_NAME, 128, (T_CX | T_PCIBUS) },
+ { PEPC, PCI_DEVICE_EPCJ_NAME, 224, (T_EPC | T_PCIBUS) },
+ { APORT2_920P, PCI_DEVICE_920_2_NAME, 2, (T_PCXR | T_PCLITE | T_PCIBUS) },
+ { APORT4_920P, PCI_DEVICE_920_4_NAME, 4, (T_PCXR | T_PCLITE | T_PCIBUS) },
+ { APORT8_920P, PCI_DEVICE_920_8_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
+ { PAPORT8, PCI_DEVICE_XR_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
+ { PAPORT8, PCI_DEVICE_XRJ_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
+ { PAPORT8, PCI_DEVICE_XR_422_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
+ { PAPORT8, PCI_DEVICE_XR_IBM_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
+ { PAPORT8, PCI_DEVICE_XR_SAIP_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
+ { PAPORT8, PCI_DEVICE_XR_BULL_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
+ { APORT8_920P, PCI_DEVICE_920_8_HP_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) },
+ { PPCM, PCI_DEVICE_XEM_HP_NAME, 64, (T_PCXM | T_PCLITE | T_PCIBUS) },
+ {0,} /* 0 terminated list. */
+};
+
+static struct pci_driver dgap_driver = {
+ .name = "dgap",
+ .probe = dgap_init_one,
+ .id_table = dgap_pci_tbl,
+ .remove = dgap_remove_one,
+};
+
+
+char *dgap_state_text[] = {
+ "Board Failed",
+ "Configuration for board not found.\n\t\t\tRun mpi to configure board.",
+ "Board Found",
+ "Need Reset",
+ "Finished Reset",
+ "Need Config",
+ "Finished Config",
+ "Need Device Creation",
+ "Requested Device Creation",
+ "Finished Device Creation",
+ "Need BIOS Load",
+ "Requested BIOS",
+ "Doing BIOS Load",
+ "Finished BIOS Load",
+ "Need FEP Load",
+ "Requested FEP",
+ "Doing FEP Load",
+ "Finished FEP Load",
+ "Requested PROC creation",
+ "Finished PROC creation",
+ "Board READY",
+};
+
+char *dgap_driver_state_text[] = {
+ "Driver Initialized",
+ "Driver needs configuration load.",
+ "Driver requested configuration from download daemon.",
+ "Driver Ready."
+};
+
+
+
+/************************************************************************
+ *
+ * Driver load/unload functions
+ *
+ ************************************************************************/
+
+/*
+ * init_module()
+ *
+ * Module load. This is where it all starts.
+ */
+int dgap_init_module(void)
+{
+ int rc = 0;
+
+ APR(("%s, Digi International Part Number %s\n", DG_NAME, DG_PART));
+
+ /*
+ * Initialize global stuff
+ */
+ rc = dgap_start();
+
+ if (rc < 0) {
+ return(rc);
+ }
+
+ /*
+ * Find and configure all the cards
+ */
+ rc = dgap_init_pci();
+
+ /*
+ * If something went wrong in the scan, bail out of driver.
+ */
+ if (rc < 0) {
+ /* Only unregister the pci driver if it was actually registered. */
+ if (dgap_NumBoards)
+ pci_unregister_driver(&dgap_driver);
+ else
+ printk("WARNING: dgap driver load failed. No DGAP boards found.\n");
+
+ dgap_cleanup_module();
+ }
+ else {
+ dgap_create_driver_sysfiles(&dgap_driver);
+ }
+
+ DPR_INIT(("Finished init_module. Returning %d\n", rc));
+ return (rc);
+}
+
+
+/*
+ * Start of driver.
+ */
+static int dgap_start(void)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ if (dgap_driver_start == FALSE) {
+
+ dgap_driver_start = TRUE;
+
+ /* make sure that the globals are init'd before we do anything else */
+ dgap_init_globals();
+
+ dgap_NumBoards = 0;
+
+ APR(("For the tools package or updated drivers please visit http://www.digi.com\n"));
+
+ /*
+ * Register our base character device into the kernel.
+ * This allows the download daemon to connect to the downld device
+ * before any of the boards are init'ed.
+ */
+ if (!dgap_Major_Control_Registered) {
+ /*
+ * Register management/dpa devices
+ */
+ rc = register_chrdev(DIGI_DGAP_MAJOR, "dgap", &DgapBoardFops);
+ if (rc < 0) {
+ APR(("Can't register dgap driver device (%d)\n", rc));
+ return (rc);
+ }
+
+ dgap_class = class_create(THIS_MODULE, "dgap_mgmt");
+ device_create(dgap_class, NULL,
+ MKDEV(DIGI_DGAP_MAJOR, 0),
+ NULL, "dgap_mgmt");
+ device_create(dgap_class, NULL,
+ MKDEV(DIGI_DGAP_MAJOR, 1),
+ NULL, "dgap_downld");
+ dgap_Major_Control_Registered = TRUE;
+ }
+
+ /*
+ * Init any global tty stuff.
+ */
+ rc = dgap_tty_preinit();
+
+ if (rc < 0) {
+ APR(("tty preinit - not enough memory (%d)\n", rc));
+ return(rc);
+ }
+
+ /* Start the poller */
+ DGAP_LOCK(dgap_poll_lock, flags);
+ init_timer(&dgap_poll_timer);
+ dgap_poll_timer.function = dgap_poll_handler;
+ dgap_poll_timer.data = 0;
+ dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick);
+ dgap_poll_timer.expires = dgap_poll_time;
+ DGAP_UNLOCK(dgap_poll_lock, flags);
+
+ add_timer(&dgap_poll_timer);
+
+ dgap_driver_state = DRIVER_NEED_CONFIG_LOAD;
+ }
+
+ return (rc);
+}
+
+
+/*
+ * Register pci driver, and return how many boards we have.
+ */
+static int dgap_init_pci(void)
+{
+ return pci_register_driver(&dgap_driver);
+}
+
+
+/* returns count (>= 0), or negative on error */
+static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int rc;
+
+ /* wake up and enable device */
+ rc = pci_enable_device(pdev);
+
+ if (rc < 0) {
+ rc = -EIO;
+ } else {
+ rc = dgap_probe1(pdev, ent->driver_data);
+ if (rc == 0) {
+ dgap_NumBoards++;
+ DPR_INIT(("Incrementing numboards to %d\n", dgap_NumBoards));
+ }
+ }
+ return rc;
+}
+
+
+static int dgap_probe1(struct pci_dev *pdev, int card_type)
+{
+ return dgap_found_board(pdev, card_type);
+}
+
+
+static void dgap_remove_one(struct pci_dev *dev)
+{
+ /* Do Nothing */
+}
+
+
+/*
+ * dgap_cleanup_module()
+ *
+ * Module unload. This is where it all ends.
+ */
+void dgap_cleanup_module(void)
+{
+ int i;
+ ulong lock_flags;
+
+ DGAP_LOCK(dgap_poll_lock, lock_flags);
+ dgap_poll_stop = 1;
+ DGAP_UNLOCK(dgap_poll_lock, lock_flags);
+
+ /* Turn off poller right away. */
+ del_timer_sync( &dgap_poll_timer);
+
+ dgap_remove_driver_sysfiles(&dgap_driver);
+
+
+ if (dgap_Major_Control_Registered) {
+ device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0));
+ device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 1));
+ class_destroy(dgap_class);
+ unregister_chrdev(DIGI_DGAP_MAJOR, "dgap");
+ }
+
+ if (dgap_config_buf)
+ kfree(dgap_config_buf);
+
+ for (i = 0; i < dgap_NumBoards; ++i) {
+ dgap_remove_ports_sysfiles(dgap_Board[i]);
+ dgap_tty_uninit(dgap_Board[i]);
+ dgap_cleanup_board(dgap_Board[i]);
+ }
+
+ dgap_tty_post_uninit();
+
+#if defined(DGAP_TRACER)
+ /* last thing, make sure we release the tracebuffer */
+ dgap_tracer_free();
+#endif
+ if (dgap_NumBoards)
+ pci_unregister_driver(&dgap_driver);
+}
+
+
+/*
+ * dgap_cleanup_board()
+ *
+ * Free all the memory associated with a board
+ */
+static void dgap_cleanup_board(struct board_t *brd)
+{
+ int i = 0;
+
+ if(!brd || brd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ if (brd->intr_used && brd->irq)
+ free_irq(brd->irq, brd);
+
+ tasklet_kill(&brd->helper_tasklet);
+
+ if (brd->re_map_port) {
+ release_mem_region(brd->membase + 0x200000, 0x200000);
+ iounmap(brd->re_map_port);
+ brd->re_map_port = NULL;
+ }
+
+ if (brd->re_map_membase) {
+ release_mem_region(brd->membase, 0x200000);
+ iounmap(brd->re_map_membase);
+ brd->re_map_membase = NULL;
+ }
+
+ if (brd->msgbuf_head) {
+ unsigned long flags;
+
+ DGAP_LOCK(dgap_global_lock, flags);
+ brd->msgbuf = NULL;
+ printk(brd->msgbuf_head);
+ kfree(brd->msgbuf_head);
+ brd->msgbuf_head = NULL;
+ DGAP_UNLOCK(dgap_global_lock, flags);
+ }
+
+ /* Free all allocated channels structs */
+ for (i = 0; i < MAXPORTS ; i++) {
+ if (brd->channels[i]) {
+ kfree(brd->channels[i]);
+ brd->channels[i] = NULL;
+ }
+ }
+
+ if (brd->flipbuf)
+ kfree(brd->flipbuf);
+ if (brd->flipflagbuf)
+ kfree(brd->flipflagbuf);
+
+ dgap_Board[brd->boardnum] = NULL;
+
+ kfree(brd);
+}
+
+
+/*
+ * dgap_found_board()
+ *
+ * A board has been found, init it.
+ */
+static int dgap_found_board(struct pci_dev *pdev, int id)
+{
+ struct board_t *brd;
+ unsigned int pci_irq;
+ int i = 0;
+ unsigned long flags;
+
+ /* get the board structure and prep it */
+ brd = dgap_Board[dgap_NumBoards] =
+ (struct board_t *) dgap_driver_kzmalloc(sizeof(struct board_t), GFP_KERNEL);
+ if (!brd) {
+ APR(("memory allocation for board structure failed\n"));
+ return(-ENOMEM);
+ }
+
+ /* make a temporary message buffer for the boot messages */
+ brd->msgbuf = brd->msgbuf_head =
+ (char *) dgap_driver_kzmalloc(sizeof(char) * 8192, GFP_KERNEL);
+ if(!brd->msgbuf) {
+ kfree(brd);
+ APR(("memory allocation for board msgbuf failed\n"));
+ return(-ENOMEM);
+ }
+
+ /* store the info for the board we've found */
+ brd->magic = DGAP_BOARD_MAGIC;
+ brd->boardnum = dgap_NumBoards;
+ brd->firstminor = 0;
+ brd->vendor = dgap_pci_tbl[id].vendor;
+ brd->device = dgap_pci_tbl[id].device;
+ brd->pdev = pdev;
+ brd->pci_bus = pdev->bus->number;
+ brd->pci_slot = PCI_SLOT(pdev->devfn);
+ brd->name = dgap_Ids[id].name;
+ brd->maxports = dgap_Ids[id].maxports;
+ brd->type = dgap_Ids[id].config_type;
+ brd->dpatype = dgap_Ids[id].dpatype;
+ brd->dpastatus = BD_NOFEP;
+ init_waitqueue_head(&brd->state_wait);
+
+ DGAP_SPINLOCK_INIT(brd->bd_lock);
+
+ brd->state = BOARD_FOUND;
+ brd->runwait = 0;
+ brd->inhibit_poller = FALSE;
+ brd->wait_for_bios = 0;
+ brd->wait_for_fep = 0;
+
+ for (i = 0; i < MAXPORTS; i++) {
+ brd->channels[i] = NULL;
+ }
+
+ /* store which card & revision we have */
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor);
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
+
+ pci_irq = pdev->irq;
+ brd->irq = pci_irq;
+
+ /* get the PCI Base Address Registers */
+
+ /* Xr Jupiter and EPC use BAR 2 */
+ if (brd->device == PCI_DEVICE_XRJ_DID || brd->device == PCI_DEVICE_EPCJ_DID) {
+ brd->membase = pci_resource_start(pdev, 2);
+ brd->membase_end = pci_resource_end(pdev, 2);
+ }
+ /* Everyone else uses BAR 0 */
+ else {
+ brd->membase = pci_resource_start(pdev, 0);
+ brd->membase_end = pci_resource_end(pdev, 0);
+ }
+
+ if (!brd->membase) {
+ APR(("card has no PCI IO resources, failing board.\n"));
+ return -ENODEV;
+ }
+
+ if (brd->membase & 1)
+ brd->membase &= ~3;
+ else
+ brd->membase &= ~15;
+
+ /*
+ * On the PCI boards, there is no IO space allocated
+ * The I/O registers will be in the first 3 bytes of the
+ * upper 2MB of the 4MB memory space. The board memory
+ * will be mapped into the low 2MB of the 4MB memory space
+ */
+ brd->port = brd->membase + PCI_IO_OFFSET;
+ brd->port_end = brd->port + PCI_IO_SIZE;
+
+
+ /*
+ * Special initialization for non-PLX boards
+ */
+ if (brd->device != PCI_DEVICE_XRJ_DID && brd->device != PCI_DEVICE_EPCJ_DID) {
+ unsigned short cmd;
+
+ pci_write_config_byte(pdev, 0x40, 0);
+ pci_write_config_byte(pdev, 0x46, 0);
+
+ /* Limit burst length to 2 doubleword transactions */
+ pci_write_config_byte(pdev, 0x42, 1);
+
+ /*
+ * Enable IO and mem if not already done.
+ * This was needed for support on Itanium.
+ */
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+ }
+
+ /* init our poll helper tasklet */
+ tasklet_init(&brd->helper_tasklet, dgap_poll_tasklet, (unsigned long) brd);
+
+ /* Log the information about the board */
+ dgap_mbuf(brd, DRVSTR": board %d: %s (rev %d), irq %d\n",
+ dgap_NumBoards, brd->name, brd->rev, brd->irq);
+
+ DPR_INIT(("dgap_scan(%d) - printing out the msgbuf\n", i));
+ DGAP_LOCK(dgap_global_lock, flags);
+ brd->msgbuf = NULL;
+ printk(brd->msgbuf_head);
+ kfree(brd->msgbuf_head);
+ brd->msgbuf_head = NULL;
+ DGAP_UNLOCK(dgap_global_lock, flags);
+
+ i = dgap_do_remap(brd);
+ if (i)
+ brd->state = BOARD_FAILED;
+ else
+ brd->state = NEED_RESET;
+
+ return(0);
+}
+
+
+int dgap_finalize_board_init(struct board_t *brd) {
+
+ int rc;
+
+ DPR_INIT(("dgap_finalize_board_init() - start\n"));
+
+ if (!brd || brd->magic != DGAP_BOARD_MAGIC)
+ return(-ENODEV);
+
+ DPR_INIT(("dgap_finalize_board_init() - start #2\n"));
+
+ brd->use_interrupts = dgap_config_get_useintr(brd);
+
+ /*
+ * Set up our interrupt handler if we are set to do interrupts.
+ */
+ if (brd->use_interrupts && brd->irq) {
+
+ rc = request_irq(brd->irq, dgap_intr, IRQF_SHARED, "DGAP", brd);
+
+ if (rc) {
+ dgap_mbuf(brd, DRVSTR": Failed to hook IRQ %d. Board will work in poll mode.\n",
+ brd->irq);
+ brd->intr_used = 0;
+ }
+ else
+ brd->intr_used = 1;
+ } else {
+ brd->intr_used = 0;
+ }
+
+ return(0);
+}
+
+
+/*
+ * Remap PCI memory.
+ */
+static int dgap_do_remap(struct board_t *brd)
+{
+ if (!brd || brd->magic != DGAP_BOARD_MAGIC)
+ return -ENXIO;
+
+ if (!request_mem_region(brd->membase, 0x200000, "dgap")) {
+ APR(("dgap: mem_region %lx already in use.\n", brd->membase));
+ return -ENOMEM;
+ }
+
+ if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000, "dgap")) {
+ APR(("dgap: mem_region IO %lx already in use.\n",
+ brd->membase + PCI_IO_OFFSET));
+ release_mem_region(brd->membase, 0x200000);
+ return -ENOMEM;
+ }
+
+ brd->re_map_membase = ioremap(brd->membase, 0x200000);
+ if (!brd->re_map_membase) {
+ APR(("dgap: ioremap mem %lx cannot be mapped.\n", brd->membase));
+ release_mem_region(brd->membase, 0x200000);
+ release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
+ return -ENOMEM;
+ }
+
+ brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000);
+ if (!brd->re_map_port) {
+ release_mem_region(brd->membase, 0x200000);
+ release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
+ iounmap(brd->re_map_membase);
+ APR(("dgap: ioremap IO mem %lx cannot be mapped.\n",
+ brd->membase + PCI_IO_OFFSET));
+ return -ENOMEM;
+ }
+
+ DPR_INIT(("remapped io: 0x%p remapped mem: 0x%p\n",
+ brd->re_map_port, brd->re_map_membase));
+ return 0;
+}
+
+
+/*****************************************************************************
+*
+* Function:
+*
+* dgap_poll_handler
+*
+* Author:
+*
+* Scott H Kilau
+*
+* Parameters:
+*
+* dummy -- ignored
+*
+* Return Values:
+*
+* none
+*
+* Description:
+*
+* As each timer expires, it determines (a) whether the "transmit"
+* waiter needs to be woken up, and (b) whether the poller needs to
+* be rescheduled.
+*
+******************************************************************************/
+
+static void dgap_poll_handler(ulong dummy)
+{
+ int i;
+ struct board_t *brd;
+ unsigned long lock_flags;
+ unsigned long lock_flags2;
+ ulong new_time;
+
+ dgap_poll_counter++;
+
+
+ /*
+ * If driver needs the config file still,
+ * keep trying to wake up the downloader to
+ * send us the file.
+ */
+ if (dgap_driver_state == DRIVER_NEED_CONFIG_LOAD) {
+ /*
+ * Signal downloader, its got some work to do.
+ */
+ DGAP_LOCK(dgap_dl_lock, lock_flags2);
+ if (dgap_dl_action != 1) {
+ dgap_dl_action = 1;
+ wake_up_interruptible(&dgap_dl_wait);
+ }
+ DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+ goto schedule_poller;
+ }
+ /*
+ * Do not start the board state machine until
+ * driver tells us its up and running, and has
+ * everything it needs.
+ */
+ else if (dgap_driver_state != DRIVER_READY) {
+ goto schedule_poller;
+ }
+
+ /*
+ * If we have just 1 board, or the system is not SMP,
+ * then use the typical old style poller.
+ * Otherwise, use our new tasklet based poller, which should
+ * speed things up for multiple boards.
+ */
+ if ( (dgap_NumBoards == 1) || (num_online_cpus() <= 1) ) {
+ for (i = 0; i < dgap_NumBoards; i++) {
+
+ brd = dgap_Board[i];
+
+ if (brd->state == BOARD_FAILED) {
+ continue;
+ }
+ if (!brd->intr_running) {
+ /* Call the real board poller directly */
+ dgap_poll_tasklet((unsigned long) brd);
+ }
+ }
+ }
+ else {
+ /* Go thru each board, kicking off a tasklet for each if needed */
+ for (i = 0; i < dgap_NumBoards; i++) {
+ brd = dgap_Board[i];
+
+ /*
+ * Attempt to grab the board lock.
+ *
+ * If we can't get it, no big deal, the next poll will get it.
+ * Basically, I just really don't want to spin in here, because I want
+ * to kick off my tasklets as fast as I can, and then get out the poller.
+ */
+ if (!spin_trylock(&brd->bd_lock)) {
+ continue;
+ }
+
+ /* If board is in a failed state, don't bother scheduling a tasklet */
+ if (brd->state == BOARD_FAILED) {
+ spin_unlock(&brd->bd_lock);
+ continue;
+ }
+
+ /* Schedule a poll helper task */
+ if (!brd->intr_running) {
+ tasklet_schedule(&brd->helper_tasklet);
+ }
+
+ /*
+ * Can't do DGAP_UNLOCK here, as we don't have
+ * lock_flags because we did a trylock above.
+ */
+ spin_unlock(&brd->bd_lock);
+ }
+ }
+
+schedule_poller:
+
+ /*
+ * Schedule ourself back at the nominal wakeup interval.
+ */
+ DGAP_LOCK(dgap_poll_lock, lock_flags );
+ dgap_poll_time += dgap_jiffies_from_ms(dgap_poll_tick);
+
+ new_time = dgap_poll_time - jiffies;
+
+ if ((ulong) new_time >= 2 * dgap_poll_tick) {
+ dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick);
+ }
+
+ dgap_poll_timer.function = dgap_poll_handler;
+ dgap_poll_timer.data = 0;
+ dgap_poll_timer.expires = dgap_poll_time;
+ DGAP_UNLOCK(dgap_poll_lock, lock_flags );
+
+ if (!dgap_poll_stop)
+ add_timer(&dgap_poll_timer);
+}
+
+
+
+
+/*
+ * dgap_intr()
+ *
+ * Driver interrupt handler.
+ */
+static irqreturn_t dgap_intr(int irq, void *voidbrd)
+{
+ struct board_t *brd = (struct board_t *) voidbrd;
+
+ if (!brd) {
+ APR(("Received interrupt (%d) with null board associated\n", irq));
+ return IRQ_NONE;
+ }
+
+ /*
+ * Check to make sure its for us.
+ */
+ if (brd->magic != DGAP_BOARD_MAGIC) {
+ APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n", irq));
+ return IRQ_NONE;
+ }
+
+ brd->intr_count++;
+
+ /*
+ * Schedule tasklet to run at a better time.
+ */
+ tasklet_schedule(&brd->helper_tasklet);
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * dgap_init_globals()
+ *
+ * This is where we initialize the globals from the static insmod
+ * configuration variables. These are declared near the head of
+ * this file.
+ */
+static void dgap_init_globals(void)
+{
+ int i = 0;
+
+ dgap_rawreadok = rawreadok;
+ dgap_trcbuf_size = trcbuf_size;
+ dgap_debug = debug;
+
+ for (i = 0; i < MAXBOARDS; i++) {
+ dgap_Board[i] = NULL;
+ }
+
+ init_timer( &dgap_poll_timer );
+
+ init_waitqueue_head(&dgap_dl_wait);
+ dgap_dl_action = 0;
+}
+
+
+/************************************************************************
+ *
+ * Utility functions
+ *
+ ************************************************************************/
+
+
+/*
+ * dgap_driver_kzmalloc()
+ *
+ * Malloc and clear memory,
+ */
+void *dgap_driver_kzmalloc(size_t size, int priority)
+{
+ void *p = kmalloc(size, priority);
+ if(p)
+ memset(p, 0, size);
+ return(p);
+}
+
+
+/*
+ * dgap_mbuf()
+ *
+ * Used to print to the message buffer during board init.
+ */
+static void dgap_mbuf(struct board_t *brd, const char *fmt, ...) {
+ va_list ap;
+ char buf[1024];
+ int i;
+ unsigned long flags;
+
+ DGAP_LOCK(dgap_global_lock, flags);
+
+ /* Format buf using fmt and arguments contained in ap. */
+ va_start(ap, fmt);
+ i = vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ DPR((buf));
+
+ if (!brd || !brd->msgbuf) {
+ printk(buf);
+ DGAP_UNLOCK(dgap_global_lock, flags);
+ return;
+ }
+
+ memcpy(brd->msgbuf, buf, strlen(buf));
+ brd->msgbuf += strlen(buf);
+ *brd->msgbuf = 0;
+
+ DGAP_UNLOCK(dgap_global_lock, flags);
+}
+
+
+/*
+ * dgap_ms_sleep()
+ *
+ * Put the driver to sleep for x ms's
+ *
+ * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal.
+ */
+int dgap_ms_sleep(ulong ms)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((ms * HZ) / 1000);
+ return (signal_pending(current));
+}
+
+
+
+/*
+ * dgap_ioctl_name() : Returns a text version of each ioctl value.
+ */
+char *dgap_ioctl_name(int cmd)
+{
+ switch(cmd) {
+
+ case TCGETA: return("TCGETA");
+ case TCGETS: return("TCGETS");
+ case TCSETA: return("TCSETA");
+ case TCSETS: return("TCSETS");
+ case TCSETAW: return("TCSETAW");
+ case TCSETSW: return("TCSETSW");
+ case TCSETAF: return("TCSETAF");
+ case TCSETSF: return("TCSETSF");
+ case TCSBRK: return("TCSBRK");
+ case TCXONC: return("TCXONC");
+ case TCFLSH: return("TCFLSH");
+ case TIOCGSID: return("TIOCGSID");
+
+ case TIOCGETD: return("TIOCGETD");
+ case TIOCSETD: return("TIOCSETD");
+ case TIOCGWINSZ: return("TIOCGWINSZ");
+ case TIOCSWINSZ: return("TIOCSWINSZ");
+
+ case TIOCMGET: return("TIOCMGET");
+ case TIOCMSET: return("TIOCMSET");
+ case TIOCMBIS: return("TIOCMBIS");
+ case TIOCMBIC: return("TIOCMBIC");
+
+ /* from digi.h */
+ case DIGI_SETA: return("DIGI_SETA");
+ case DIGI_SETAW: return("DIGI_SETAW");
+ case DIGI_SETAF: return("DIGI_SETAF");
+ case DIGI_SETFLOW: return("DIGI_SETFLOW");
+ case DIGI_SETAFLOW: return("DIGI_SETAFLOW");
+ case DIGI_GETFLOW: return("DIGI_GETFLOW");
+ case DIGI_GETAFLOW: return("DIGI_GETAFLOW");
+ case DIGI_GETA: return("DIGI_GETA");
+ case DIGI_GEDELAY: return("DIGI_GEDELAY");
+ case DIGI_SEDELAY: return("DIGI_SEDELAY");
+ case DIGI_GETCUSTOMBAUD: return("DIGI_GETCUSTOMBAUD");
+ case DIGI_SETCUSTOMBAUD: return("DIGI_SETCUSTOMBAUD");
+ case TIOCMODG: return("TIOCMODG");
+ case TIOCMODS: return("TIOCMODS");
+ case TIOCSDTR: return("TIOCSDTR");
+ case TIOCCDTR: return("TIOCCDTR");
+
+ default: return("unknown");
+ }
+}
diff --git a/drivers/staging/dgap/dgap_driver.h b/drivers/staging/dgap/dgap_driver.h
new file mode 100644
index 00000000000..b1cf489a729
--- /dev/null
+++ b/drivers/staging/dgap/dgap_driver.h
@@ -0,0 +1,618 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *************************************************************************
+ *
+ * Driver includes
+ *
+ *************************************************************************/
+
+#ifndef __DGAP_DRIVER_H
+#define __DGAP_DRIVER_H
+
+#include <linux/version.h> /* To get the current Linux version */
+#include <linux/types.h> /* To pick up the varions Linux types */
+#include <linux/tty.h> /* To pick up the various tty structs/defines */
+#include <linux/interrupt.h> /* For irqreturn_t type */
+
+#include "dgap_types.h" /* Additional types needed by the Digi header files */
+#include "digi.h" /* Digi specific ioctl header */
+#include "dgap_kcompat.h" /* Kernel 2.4/2.6 compat includes */
+#include "dgap_sysfs.h" /* Support for SYSFS */
+
+/*************************************************************************
+ *
+ * Driver defines
+ *
+ *************************************************************************/
+
+/*
+ * Driver identification, error and debugging statments
+ *
+ * In theory, you can change all occurances of "digi" in the next
+ * three lines, and the driver printk's will all automagically change.
+ *
+ * APR((fmt, args, ...)); Always prints message
+ * DPR((fmt, args, ...)); Only prints if DGAP_TRACER is defined at
+ * compile time and dgap_debug!=0
+ */
+#define PROCSTR "dgap" /* /proc entries */
+#define DEVSTR "/dev/dg/dgap" /* /dev entries */
+#define DRVSTR "dgap" /* Driver name string
+ * displayed by APR */
+#define APR(args) do { PRINTF_TO_KMEM(args); printk(DRVSTR": "); printk args; \
+ } while (0)
+#define RAPR(args) do { PRINTF_TO_KMEM(args); printk args; } while (0)
+
+#define TRC_TO_CONSOLE 1
+
+/*
+ * Debugging levels can be set using debug insmod variable
+ * They can also be compiled out completely.
+ */
+
+#define DBG_INIT (dgap_debug & 0x01)
+#define DBG_BASIC (dgap_debug & 0x02)
+#define DBG_CORE (dgap_debug & 0x04)
+
+#define DBG_OPEN (dgap_debug & 0x08)
+#define DBG_CLOSE (dgap_debug & 0x10)
+#define DBG_READ (dgap_debug & 0x20)
+#define DBG_WRITE (dgap_debug & 0x40)
+
+#define DBG_IOCTL (dgap_debug & 0x80)
+
+#define DBG_PROC (dgap_debug & 0x100)
+#define DBG_PARAM (dgap_debug & 0x200)
+#define DBG_PSCAN (dgap_debug & 0x400)
+#define DBG_EVENT (dgap_debug & 0x800)
+
+#define DBG_DRAIN (dgap_debug & 0x1000)
+#define DBG_CARR (dgap_debug & 0x2000)
+
+#define DBG_MGMT (dgap_debug & 0x4000)
+
+
+#if defined(DGAP_TRACER)
+
+# if defined(TRC_TO_KMEM)
+/* Choose one: */
+# define TRC_ON_OVERFLOW_WRAP_AROUND
+# undef TRC_ON_OVERFLOW_SHIFT_BUFFER
+# endif //TRC_TO_KMEM
+
+# define TRC_MAXMSG 1024
+# define TRC_OVERFLOW "(OVERFLOW)"
+# define TRC_DTRC "/usr/bin/dtrc"
+
+#if defined TRC_TO_CONSOLE
+#define PRINTF_TO_CONSOLE(args) { printk(DRVSTR": "); printk args; }
+#else //!defined TRACE_TO_CONSOLE
+#define PRINTF_TO_CONSOLE(args)
+#endif
+
+#if defined TRC_TO_KMEM
+#define PRINTF_TO_KMEM(args) dgap_tracef args
+#else //!defined TRC_TO_KMEM
+#define PRINTF_TO_KMEM(args)
+#endif
+
+#define TRC(args) { PRINTF_TO_KMEM(args); PRINTF_TO_CONSOLE(args) }
+
+# define DPR_INIT(ARGS) if (DBG_INIT) TRC(ARGS)
+# define DPR_BASIC(ARGS) if (DBG_BASIC) TRC(ARGS)
+# define DPR_CORE(ARGS) if (DBG_CORE) TRC(ARGS)
+# define DPR_OPEN(ARGS) if (DBG_OPEN) TRC(ARGS)
+# define DPR_CLOSE(ARGS) if (DBG_CLOSE) TRC(ARGS)
+# define DPR_READ(ARGS) if (DBG_READ) TRC(ARGS)
+# define DPR_WRITE(ARGS) if (DBG_WRITE) TRC(ARGS)
+# define DPR_IOCTL(ARGS) if (DBG_IOCTL) TRC(ARGS)
+# define DPR_PROC(ARGS) if (DBG_PROC) TRC(ARGS)
+# define DPR_PARAM(ARGS) if (DBG_PARAM) TRC(ARGS)
+# define DPR_PSCAN(ARGS) if (DBG_PSCAN) TRC(ARGS)
+# define DPR_EVENT(ARGS) if (DBG_EVENT) TRC(ARGS)
+# define DPR_DRAIN(ARGS) if (DBG_DRAIN) TRC(ARGS)
+# define DPR_CARR(ARGS) if (DBG_CARR) TRC(ARGS)
+# define DPR_MGMT(ARGS) if (DBG_MGMT) TRC(ARGS)
+
+# define DPR(ARGS) if (dgap_debug) TRC(ARGS)
+# define P(X) dgap_tracef(#X "=%p\n", X)
+# define X(X) dgap_tracef(#X "=%x\n", X)
+
+#else//!defined DGAP_TRACER
+
+#define PRINTF_TO_KMEM(args)
+# define TRC(ARGS)
+# define DPR_INIT(ARGS)
+# define DPR_BASIC(ARGS)
+# define DPR_CORE(ARGS)
+# define DPR_OPEN(ARGS)
+# define DPR_CLOSE(ARGS)
+# define DPR_READ(ARGS)
+# define DPR_WRITE(ARGS)
+# define DPR_IOCTL(ARGS)
+# define DPR_PROC(ARGS)
+# define DPR_PARAM(ARGS)
+# define DPR_PSCAN(ARGS)
+# define DPR_EVENT(ARGS)
+# define DPR_DRAIN(ARGS)
+# define DPR_CARR(ARGS)
+# define DPR_MGMT(ARGS)
+
+# define DPR(args)
+
+#endif//DGAP_TRACER
+
+/* Number of boards we support at once. */
+#define MAXBOARDS 32
+#define MAXPORTS 224
+#define MAXTTYNAMELEN 200
+
+/* Our 3 magic numbers for our board, channel and unit structs */
+#define DGAP_BOARD_MAGIC 0x5c6df104
+#define DGAP_CHANNEL_MAGIC 0x6c6df104
+#define DGAP_UNIT_MAGIC 0x7c6df104
+
+/* Serial port types */
+#define DGAP_SERIAL 0
+#define DGAP_PRINT 1
+
+#define SERIAL_TYPE_NORMAL 1
+
+/* 4 extra for alignment play space */
+#define WRITEBUFLEN ((4096) + 4)
+#define MYFLIPLEN N_TTY_BUF_SIZE
+
+#define SBREAK_TIME 0x25
+#define U2BSIZE 0x400
+
+#define dgap_jiffies_from_ms(a) (((a) * HZ) / 1000)
+
+/*
+ * Our major for the mgmt devices.
+ *
+ * We can use 22, because Digi was allocated 22 and 23 for the epca driver.
+ * 22 has now become obsolete now that the "cu" devices have
+ * been removed from 2.6.
+ * Also, this *IS* the epca driver, just PCI only now.
+ */
+#ifndef DIGI_DGAP_MAJOR
+# define DIGI_DGAP_MAJOR 22
+#endif
+
+/*
+ * The parameters we use to define the periods of the moving averages.
+ */
+#define MA_PERIOD (HZ / 10)
+#define SMA_DUR (1 * HZ)
+#define EMA_DUR (1 * HZ)
+#define SMA_NPERIODS (SMA_DUR / MA_PERIOD)
+#define EMA_NPERIODS (EMA_DUR / MA_PERIOD)
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially. This is the same structure that is defined
+ * as the default in tty_io.c with the same settings overriden as in serial.c
+ *
+ * In short, this should match the internal serial ports' defaults.
+ */
+#define DEFAULT_IFLAGS (ICRNL | IXON)
+#define DEFAULT_OFLAGS (OPOST | ONLCR)
+#define DEFAULT_CFLAGS (B9600 | CS8 | CREAD | HUPCL | CLOCAL)
+#define DEFAULT_LFLAGS (ISIG | ICANON | ECHO | ECHOE | ECHOK | \
+ ECHOCTL | ECHOKE | IEXTEN)
+
+#ifndef _POSIX_VDISABLE
+#define _POSIX_VDISABLE '\0'
+#endif
+
+#define SNIFF_MAX 65536 /* Sniff buffer size (2^n) */
+#define SNIFF_MASK (SNIFF_MAX - 1) /* Sniff wrap mask */
+
+#define VPDSIZE (512)
+
+/*
+ * Lock function/defines.
+ * Makes spotting lock/unlock locations easier.
+ */
+# define DGAP_SPINLOCK_INIT(x) spin_lock_init(&(x))
+# define DGAP_LOCK(x,y) spin_lock_irqsave(&(x), y)
+# define DGAP_UNLOCK(x,y) spin_unlock_irqrestore(&(x), y)
+# define DGAP_TRYLOCK(x,y) spin_trylock(&(x))
+
+/*
+ * All the possible states the driver can be while being loaded.
+ */
+enum {
+ DRIVER_INITIALIZED = 0,
+ DRIVER_NEED_CONFIG_LOAD,
+ DRIVER_REQUESTED_CONFIG,
+ DRIVER_READY
+};
+
+/*
+ * All the possible states the board can be while booting up.
+ */
+enum {
+ BOARD_FAILED = 0,
+ CONFIG_NOT_FOUND,
+ BOARD_FOUND,
+ NEED_RESET,
+ FINISHED_RESET,
+ NEED_CONFIG,
+ FINISHED_CONFIG,
+ NEED_DEVICE_CREATION,
+ REQUESTED_DEVICE_CREATION,
+ FINISHED_DEVICE_CREATION,
+ NEED_BIOS_LOAD,
+ REQUESTED_BIOS,
+ WAIT_BIOS_LOAD,
+ FINISHED_BIOS_LOAD,
+ NEED_FEP_LOAD,
+ REQUESTED_FEP,
+ WAIT_FEP_LOAD,
+ FINISHED_FEP_LOAD,
+ NEED_PROC_CREATION,
+ FINISHED_PROC_CREATION,
+ BOARD_READY
+};
+
+/*
+ * All the possible states that a requested concentrator image can be in.
+ */
+enum {
+ NO_PENDING_CONCENTRATOR_REQUESTS = 0,
+ NEED_CONCENTRATOR,
+ REQUESTED_CONCENTRATOR
+};
+
+extern char *dgap_state_text[];
+extern char *dgap_driver_state_text[];
+
+
+/*
+ * Modem line constants are defined as macros because DSR and
+ * DCD are swapable using the ditty altpin option.
+ */
+#define D_CD(ch) ch->ch_cd /* Carrier detect */
+#define D_DSR(ch) ch->ch_dsr /* Data set ready */
+#define D_RTS(ch) DM_RTS /* Request to send */
+#define D_CTS(ch) DM_CTS /* Clear to send */
+#define D_RI(ch) DM_RI /* Ring indicator */
+#define D_DTR(ch) DM_DTR /* Data terminal ready */
+
+
+/*************************************************************************
+ *
+ * Structures and closely related defines.
+ *
+ *************************************************************************/
+
+
+/*
+ * A structure to hold a statistics counter. We also
+ * compute moving averages for this counter.
+ */
+struct macounter
+{
+ u32 cnt; /* Total count */
+ ulong accum; /* Acuumulator per period */
+ ulong sma; /* Simple moving average */
+ ulong ema; /* Exponential moving average */
+};
+
+
+/************************************************************************
+ * Device flag definitions for bd_flags.
+ ************************************************************************/
+#define BD_FEP5PLUS 0x0001 /* Supports FEP5 Plus commands */
+#define BD_HAS_VPD 0x0002 /* Board has VPD info available */
+
+
+/*
+ * Per-board information
+ */
+struct board_t
+{
+ int magic; /* Board Magic number. */
+ int boardnum; /* Board number: 0-3 */
+ int firstminor; /* First minor, e.g. 0, 30, 60 */
+
+ int type; /* Type of board */
+ char *name; /* Product Name */
+ struct pci_dev *pdev; /* Pointer to the pci_dev struct */
+ u16 vendor; /* PCI vendor ID */
+ u16 device; /* PCI device ID */
+ u16 subvendor; /* PCI subsystem vendor ID */
+ u16 subdevice; /* PCI subsystem device ID */
+ uchar rev; /* PCI revision ID */
+ uint pci_bus; /* PCI bus value */
+ uint pci_slot; /* PCI slot value */
+ u16 maxports; /* MAX ports this board can handle */
+ uchar vpd[VPDSIZE]; /* VPD of board, if found */
+ u32 bd_flags; /* Board flags */
+
+ spinlock_t bd_lock; /* Used to protect board */
+
+ u32 state; /* State of card. */
+ wait_queue_head_t state_wait; /* Place to sleep on for state change */
+
+ struct tasklet_struct helper_tasklet; /* Poll helper tasklet */
+
+ u32 wait_for_bios;
+ u32 wait_for_fep;
+
+ struct cnode * bd_config; /* Config of board */
+
+ u16 nasync; /* Number of ports on card */
+
+ u32 use_interrupts; /* Should we be interrupt driven? */
+ ulong irq; /* Interrupt request number */
+ ulong intr_count; /* Count of interrupts */
+ u32 intr_used; /* Non-zero if using interrupts */
+ u32 intr_running; /* Non-zero if FEP knows its doing interrupts */
+
+ ulong port; /* Start of base io port of the card */
+ ulong port_end; /* End of base io port of the card */
+ ulong membase; /* Start of base memory of the card */
+ ulong membase_end; /* End of base memory of the card */
+
+ uchar *re_map_port; /* Remapped io port of the card */
+ uchar *re_map_membase;/* Remapped memory of the card */
+
+ uchar runwait; /* # Processes waiting for FEP */
+ uchar inhibit_poller; /* Tells the poller to leave us alone */
+
+ struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */
+
+ struct tty_driver *SerialDriver;
+ char SerialName[200];
+ struct tty_driver *PrintDriver;
+ char PrintName[200];
+
+ u32 dgap_Major_Serial_Registered;
+ u32 dgap_Major_TransparentPrint_Registered;
+
+ u32 dgap_Serial_Major;
+ u32 dgap_TransparentPrint_Major;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+ u32 TtyRefCnt;
+#endif
+
+ struct bs_t *bd_bs; /* Base structure pointer */
+
+ char *flipbuf; /* Our flip buffer, alloced if board is found */
+ char *flipflagbuf; /* Our flip flag buffer, alloced if board is found */
+
+ u16 dpatype; /* The board "type", as defined by DPA */
+ u16 dpastatus; /* The board "status", as defined by DPA */
+ wait_queue_head_t kme_wait; /* Needed for DPA support */
+
+ u32 conc_dl_status; /* Status of any pending conc download */
+ /*
+ * Mgmt data.
+ */
+ char *msgbuf_head;
+ char *msgbuf;
+};
+
+
+
+/************************************************************************
+ * Unit flag definitions for un_flags.
+ ************************************************************************/
+#define UN_ISOPEN 0x0001 /* Device is open */
+#define UN_CLOSING 0x0002 /* Line is being closed */
+#define UN_IMM 0x0004 /* Service immediately */
+#define UN_BUSY 0x0008 /* Some work this channel */
+#define UN_BREAKI 0x0010 /* Input break received */
+#define UN_PWAIT 0x0020 /* Printer waiting for terminal */
+#define UN_TIME 0x0040 /* Waiting on time */
+#define UN_EMPTY 0x0080 /* Waiting output queue empty */
+#define UN_LOW 0x0100 /* Waiting output low water mark*/
+#define UN_EXCL_OPEN 0x0200 /* Open for exclusive use */
+#define UN_WOPEN 0x0400 /* Device waiting for open */
+#define UN_WIOCTL 0x0800 /* Device waiting for open */
+#define UN_HANGUP 0x8000 /* Carrier lost */
+
+struct device;
+
+/************************************************************************
+ * Structure for terminal or printer unit.
+ ************************************************************************/
+struct un_t {
+ int magic; /* Unit Magic Number. */
+ struct channel_t *un_ch;
+ u32 un_time;
+ u32 un_type;
+ u32 un_open_count; /* Counter of opens to port */
+ struct tty_struct *un_tty;/* Pointer to unit tty structure */
+ u32 un_flags; /* Unit flags */
+ wait_queue_head_t un_flags_wait; /* Place to sleep to wait on unit */
+ u32 un_dev; /* Minor device number */
+ tcflag_t un_oflag; /* oflags being done on board */
+ tcflag_t un_lflag; /* lflags being done on board */
+ struct device *un_sysfs;
+};
+
+
+/************************************************************************
+ * Device flag definitions for ch_flags.
+ ************************************************************************/
+#define CH_PRON 0x0001 /* Printer on string */
+#define CH_OUT 0x0002 /* Dial-out device open */
+#define CH_STOP 0x0004 /* Output is stopped */
+#define CH_STOPI 0x0008 /* Input is stopped */
+#define CH_CD 0x0010 /* Carrier is present */
+#define CH_FCAR 0x0020 /* Carrier forced on */
+
+#define CH_RXBLOCK 0x0080 /* Enable rx blocked flag */
+#define CH_WLOW 0x0100 /* Term waiting low event */
+#define CH_WEMPTY 0x0200 /* Term waiting empty event */
+#define CH_RENABLE 0x0400 /* Buffer just emptied */
+#define CH_RACTIVE 0x0800 /* Process active in xxread() */
+#define CH_RWAIT 0x1000 /* Process waiting in xxread() */
+#define CH_BAUD0 0x2000 /* Used for checking B0 transitions */
+#define CH_HANGUP 0x8000 /* Hangup received */
+
+/*
+ * Definitions for ch_sniff_flags
+ */
+#define SNIFF_OPEN 0x1
+#define SNIFF_WAIT_DATA 0x2
+#define SNIFF_WAIT_SPACE 0x4
+
+
+/************************************************************************
+ * Channel information structure.
+ ************************************************************************/
+struct channel_t {
+ int magic; /* Channel Magic Number */
+ struct bs_t *ch_bs; /* Base structure pointer */
+ struct cm_t *ch_cm; /* Command queue pointer */
+ struct board_t *ch_bd; /* Board structure pointer */
+ unsigned char *ch_vaddr; /* FEP memory origin */
+ unsigned char *ch_taddr; /* Write buffer origin */
+ unsigned char *ch_raddr; /* Read buffer origin */
+ struct digi_t ch_digi; /* Transparent Print structure */
+ struct un_t ch_tun; /* Terminal unit info */
+ struct un_t ch_pun; /* Printer unit info */
+
+ spinlock_t ch_lock; /* provide for serialization */
+ wait_queue_head_t ch_flags_wait;
+
+ u32 pscan_state;
+ uchar pscan_savechar;
+
+ u32 ch_portnum; /* Port number, 0 offset. */
+ u32 ch_open_count; /* open count */
+ u32 ch_flags; /* Channel flags */
+
+
+ u32 ch_close_delay; /* How long we should drop RTS/DTR for */
+
+ u32 ch_cpstime; /* Time for CPS calculations */
+
+ tcflag_t ch_c_iflag; /* channel iflags */
+ tcflag_t ch_c_cflag; /* channel cflags */
+ tcflag_t ch_c_oflag; /* channel oflags */
+ tcflag_t ch_c_lflag; /* channel lflags */
+
+ u16 ch_fepiflag; /* FEP tty iflags */
+ u16 ch_fepcflag; /* FEP tty cflags */
+ u16 ch_fepoflag; /* FEP tty oflags */
+ u16 ch_wopen; /* Waiting for open process cnt */
+ u16 ch_tstart; /* Transmit buffer start */
+ u16 ch_tsize; /* Transmit buffer size */
+ u16 ch_rstart; /* Receive buffer start */
+ u16 ch_rsize; /* Receive buffer size */
+ u16 ch_rdelay; /* Receive delay time */
+
+ u16 ch_tlw; /* Our currently set low water mark */
+
+ u16 ch_cook; /* Output character mask */
+
+ uchar ch_card; /* Card channel is on */
+ uchar ch_stopc; /* Stop character */
+ uchar ch_startc; /* Start character */
+
+ uchar ch_mostat; /* FEP output modem status */
+ uchar ch_mistat; /* FEP input modem status */
+ uchar ch_mforce; /* Modem values to be forced */
+ uchar ch_mval; /* Force values */
+ uchar ch_fepstopc; /* FEP stop character */
+ uchar ch_fepstartc; /* FEP start character */
+
+ uchar ch_astopc; /* Auxiliary Stop character */
+ uchar ch_astartc; /* Auxiliary Start character */
+ uchar ch_fepastopc; /* Auxiliary FEP stop char */
+ uchar ch_fepastartc; /* Auxiliary FEP start char */
+
+ uchar ch_hflow; /* FEP hardware handshake */
+ uchar ch_dsr; /* stores real dsr value */
+ uchar ch_cd; /* stores real cd value */
+ uchar ch_tx_win; /* channel tx buffer window */
+ uchar ch_rx_win; /* channel rx buffer window */
+ uint ch_custom_speed; /* Custom baud, if set */
+ uint ch_baud_info; /* Current baud info for /proc output */
+ ulong ch_rxcount; /* total of data received so far */
+ ulong ch_txcount; /* total of data transmitted so far */
+ ulong ch_err_parity; /* Count of parity errors on channel */
+ ulong ch_err_frame; /* Count of framing errors on channel */
+ ulong ch_err_break; /* Count of breaks on channel */
+ ulong ch_err_overrun; /* Count of overruns on channel */
+
+ uint ch_sniff_in;
+ uint ch_sniff_out;
+ char *ch_sniff_buf; /* Sniff buffer for proc */
+ ulong ch_sniff_flags; /* Channel flags */
+ wait_queue_head_t ch_sniff_wait;
+};
+
+
+/*************************************************************************
+ *
+ * Prototypes for non-static functions used in more than one module
+ *
+ *************************************************************************/
+
+extern int dgap_ms_sleep(ulong ms);
+extern void *dgap_driver_kzmalloc(size_t size, int priority);
+extern char *dgap_ioctl_name(int cmd);
+extern void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len);
+extern void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len);
+extern void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len);
+extern void dgap_do_config_load(uchar __user *uaddr, int len);
+extern int dgap_after_config_loaded(void);
+extern int dgap_finalize_board_init(struct board_t *brd);
+
+/*
+ * Our Global Variables.
+ */
+extern int dgap_driver_state; /* The state of the driver */
+extern int dgap_debug; /* Debug variable */
+extern int dgap_rawreadok; /* Set if user wants rawreads */
+extern int dgap_poll_tick; /* Poll interval - 20 ms */
+extern spinlock_t dgap_global_lock; /* Driver global spinlock */
+extern uint dgap_NumBoards; /* Total number of boards */
+extern struct board_t *dgap_Board[MAXBOARDS]; /* Array of board structs */
+extern ulong dgap_poll_counter; /* Times the poller has run */
+extern char *dgap_config_buf; /* The config file buffer */
+extern spinlock_t dgap_dl_lock; /* Downloader spinlock */
+extern wait_queue_head_t dgap_dl_wait; /* Wait queue for downloader */
+extern int dgap_dl_action; /* Action flag for downloader */
+extern int dgap_registerttyswithsysfs; /* Should we register the */
+ /* ttys with sysfs or not */
+
+/*
+ * Global functions declared in dgap_fep5.c, but must be hidden from
+ * user space programs.
+ */
+extern void dgap_poll_tasklet(unsigned long data);
+extern void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds);
+extern void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds);
+extern void dgap_wmove(struct channel_t *ch, char *buf, uint cnt);
+extern int dgap_param(struct tty_struct *tty);
+extern void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len);
+extern uint dgap_get_custom_baud(struct channel_t *ch);
+extern void dgap_firmware_reset_port(struct channel_t *ch);
+
+#endif
diff --git a/drivers/staging/dgap/dgap_fep5.c b/drivers/staging/dgap/dgap_fep5.c
new file mode 100644
index 00000000000..4464f02c957
--- /dev/null
+++ b/drivers/staging/dgap/dgap_fep5.c
@@ -0,0 +1,1953 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ * $Id: dgap_fep5.c,v 1.2 2011/06/21 10:35:40 markh Exp $
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h> /* For udelay */
+#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */
+#include <linux/tty.h>
+#include <linux/tty_flip.h> /* For tty_schedule_flip */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+#include <linux/sched.h>
+#endif
+
+#include "dgap_driver.h"
+#include "dgap_pci.h"
+#include "dgap_fep5.h"
+#include "dgap_tty.h"
+#include "dgap_conf.h"
+#include "dgap_parse.h"
+#include "dgap_trace.h"
+
+/*
+ * Our function prototypes
+ */
+static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds);
+static int dgap_event(struct board_t *bd);
+
+/*
+ * internal variables
+ */
+static uint dgap_count = 500;
+
+
+/*
+ * Loads the dgap.conf config file from the user.
+ */
+void dgap_do_config_load(uchar __user *uaddr, int len)
+{
+ int orig_len = len;
+ char *to_addr;
+ uchar __user *from_addr = uaddr;
+ char buf[U2BSIZE];
+ int n;
+
+ to_addr = dgap_config_buf = dgap_driver_kzmalloc(len + 1, GFP_ATOMIC);
+ if (!dgap_config_buf) {
+ DPR_INIT(("dgap_do_config_load - unable to allocate memory for file\n"));
+ dgap_driver_state = DRIVER_NEED_CONFIG_LOAD;
+ return;
+ }
+
+ n = U2BSIZE;
+ while (len) {
+
+ if (n > len)
+ n = len;
+
+ if (copy_from_user((char *) &buf, from_addr, n) == -1 )
+ return;
+
+ /* Copy data from buffer to kernel memory */
+ memcpy(to_addr, buf, n);
+
+ /* increment counts */
+ len -= n;
+ to_addr += n;
+ from_addr += n;
+ n = U2BSIZE;
+ }
+
+ dgap_config_buf[orig_len] = '\0';
+
+ to_addr = dgap_config_buf;
+ dgap_parsefile(&to_addr, TRUE);
+
+ DPR_INIT(("dgap_config_load() finish\n"));
+
+ return;
+}
+
+
+int dgap_after_config_loaded(void)
+{
+ int i = 0;
+ int rc = 0;
+
+ /*
+ * Register our ttys, now that we have the config loaded.
+ */
+ for (i = 0; i < dgap_NumBoards; ++i) {
+
+ /*
+ * Initialize KME waitqueues...
+ */
+ init_waitqueue_head(&(dgap_Board[i]->kme_wait));
+
+ /*
+ * allocate flip buffer for board.
+ */
+ dgap_Board[i]->flipbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC);
+ dgap_Board[i]->flipflagbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC);
+ }
+
+ return (rc);
+}
+
+
+
+/*=======================================================================
+ *
+ * usertoboard - copy from user space to board space.
+ *
+ *=======================================================================*/
+static int dgap_usertoboard(struct board_t *brd, char *to_addr, char __user *from_addr, int len)
+{
+ char buf[U2BSIZE];
+ int n = U2BSIZE;
+
+ if (!brd || brd->magic != DGAP_BOARD_MAGIC)
+ return(-EFAULT);
+
+ while (len) {
+ if (n > len)
+ n = len;
+
+ if (copy_from_user((char *) &buf, from_addr, n) == -1 ) {
+ return(-EFAULT);
+ }
+
+ /* Copy data from buffer to card memory */
+ memcpy_toio(to_addr, buf, n);
+
+ /* increment counts */
+ len -= n;
+ to_addr += n;
+ from_addr += n;
+ n = U2BSIZE;
+ }
+ return(0);
+}
+
+
+/*
+ * Copies the BIOS code from the user to the board,
+ * and starts the BIOS running.
+ */
+void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len)
+{
+ uchar *addr;
+ uint offset;
+ int i;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+ return;
+
+ DPR_INIT(("dgap_do_bios_load() start\n"));
+
+ addr = brd->re_map_membase;
+
+ /*
+ * clear POST area
+ */
+ for (i = 0; i < 16; i++)
+ writeb(0, addr + POSTAREA + i);
+
+ /*
+ * Download bios
+ */
+ offset = 0x1000;
+ if (dgap_usertoboard(brd, addr + offset, ubios, len) == -1 ) {
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ return;
+ }
+
+ writel(0x0bf00401, addr);
+ writel(0, (addr + 4));
+
+ /* Clear the reset, and change states. */
+ writeb(FEPCLR, brd->re_map_port);
+ brd->state = WAIT_BIOS_LOAD;
+}
+
+
+/*
+ * Checks to see if the BIOS completed running on the card.
+ */
+static void dgap_do_wait_for_bios(struct board_t *brd)
+{
+ uchar *addr;
+ u16 word;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+ return;
+
+ addr = brd->re_map_membase;
+ word = readw(addr + POSTAREA);
+
+ /* Check to see if BIOS thinks board is good. (GD). */
+ if (word == *(u16 *) "GD") {
+ DPR_INIT(("GOT GD in memory, moving states.\n"));
+ brd->state = FINISHED_BIOS_LOAD;
+ return;
+ }
+
+ /* Give up on board after too long of time taken */
+ if (brd->wait_for_bios++ > 5000) {
+ u16 err1 = readw(addr + SEQUENCE);
+ u16 err2 = readw(addr + ERROR);
+ APR(("***WARNING*** %s failed diagnostics. Error #(%x,%x).\n",
+ brd->name, err1, err2));
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ }
+}
+
+
+/*
+ * Copies the FEP code from the user to the board,
+ * and starts the FEP running.
+ */
+void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len)
+{
+ uchar *addr;
+ uint offset;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+ return;
+
+ addr = brd->re_map_membase;
+
+ DPR_INIT(("dgap_do_fep_load() for board %s : start\n", brd->name));
+
+ /*
+ * Download FEP
+ */
+ offset = 0x1000;
+ if (dgap_usertoboard(brd, addr + offset, ufep, len) == -1 ) {
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ return;
+ }
+
+ /*
+ * If board is a concentrator product, we need to give
+ * it its config string describing how the concentrators look.
+ */
+ if ((brd->type == PCX) || (brd->type == PEPC)) {
+ uchar string[100];
+ uchar *config, *xconfig;
+ int i = 0;
+
+ xconfig = dgap_create_config_string(brd, string);
+
+ /* Write string to board memory */
+ config = addr + CONFIG;
+ for (; i < CONFIGSIZE; i++, config++, xconfig++) {
+ writeb(*xconfig, config);
+ if ((*xconfig & 0xff) == 0xff)
+ break;
+ }
+ }
+
+ writel(0xbfc01004, (addr + 0xc34));
+ writel(0x3, (addr + 0xc30));
+
+ /* change states. */
+ brd->state = WAIT_FEP_LOAD;
+
+ DPR_INIT(("dgap_do_fep_load() for board %s : finish\n", brd->name));
+
+}
+
+
+/*
+ * Waits for the FEP to report thats its ready for us to use.
+ */
+static void dgap_do_wait_for_fep(struct board_t *brd)
+{
+ uchar *addr;
+ u16 word;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+ return;
+
+ addr = brd->re_map_membase;
+
+ DPR_INIT(("dgap_do_wait_for_fep() for board %s : start. addr: %p\n", brd->name, addr));
+
+ word = readw(addr + FEPSTAT);
+
+ /* Check to see if FEP is up and running now. */
+ if (word == *(u16 *) "OS") {
+ DPR_INIT(("GOT OS in memory for board %s, moving states.\n", brd->name));
+ brd->state = FINISHED_FEP_LOAD;
+
+ /*
+ * Check to see if the board can support FEP5+ commands.
+ */
+ word = readw(addr + FEP5_PLUS);
+ if (word == *(u16 *) "5A") {
+ DPR_INIT(("GOT 5A in memory for board %s, board supports extended FEP5 commands.\n", brd->name));
+ brd->bd_flags |= BD_FEP5PLUS;
+ }
+
+ return;
+ }
+
+ /* Give up on board after too long of time taken */
+ if (brd->wait_for_fep++ > 5000) {
+ u16 err1 = readw(addr + SEQUENCE);
+ u16 err2 = readw(addr + ERROR);
+ APR(("***WARNING*** FEPOS for %s not functioning. Error #(%x,%x).\n",
+ brd->name, err1, err2));
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ }
+
+ DPR_INIT(("dgap_do_wait_for_fep() for board %s : finish\n", brd->name));
+}
+
+
+/*
+ * Physically forces the FEP5 card to reset itself.
+ */
+static void dgap_do_reset_board(struct board_t *brd)
+{
+ uchar check;
+ u32 check1;
+ u32 check2;
+ int i = 0;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase || !brd->re_map_port) {
+ DPR_INIT(("dgap_do_reset_board() start. bad values. brd: %p mem: %p io: %p\n",
+ brd, brd ? brd->re_map_membase : 0, brd ? brd->re_map_port : 0));
+ return;
+ }
+
+ DPR_INIT(("dgap_do_reset_board() start. io: %p\n", brd->re_map_port));
+
+ /* FEPRST does not vary among supported boards */
+ writeb(FEPRST, brd->re_map_port);
+
+ for (i = 0; i <= 1000; i++) {
+ check = readb(brd->re_map_port) & 0xe;
+ if (check == FEPRST)
+ break;
+ udelay(10);
+
+ }
+ if (i > 1000) {
+ APR(("*** WARNING *** Board not resetting... Failing board.\n"));
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ goto failed;
+ }
+
+ /*
+ * Make sure there really is memory out there.
+ */
+ writel(0xa55a3cc3, (brd->re_map_membase + LOWMEM));
+ writel(0x5aa5c33c, (brd->re_map_membase + HIGHMEM));
+ check1 = readl(brd->re_map_membase + LOWMEM);
+ check2 = readl(brd->re_map_membase + HIGHMEM);
+
+ if ((check1 != 0xa55a3cc3) || (check2 != 0x5aa5c33c)) {
+ APR(("*** Warning *** No memory at %p for board.\n", brd->re_map_membase));
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ goto failed;
+ }
+
+ if (brd->state != BOARD_FAILED)
+ brd->state = FINISHED_RESET;
+
+failed:
+ DPR_INIT(("dgap_do_reset_board() finish\n"));
+}
+
+
+/*
+ * Sends a concentrator image into the FEP5 board.
+ */
+void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len)
+{
+ char *vaddr;
+ u16 offset = 0;
+ struct downld_t *to_dp;
+
+ if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+ return;
+
+ vaddr = brd->re_map_membase;
+
+ offset = readw((u16 *) (vaddr + DOWNREQ));
+ to_dp = (struct downld_t *) (vaddr + (int) offset);
+
+ /*
+ * The image was already read into kernel space,
+ * we do NOT need a user space read here
+ */
+ memcpy_toio((char *) to_dp, uaddr, sizeof(struct downld_t));
+
+ /* Tell card we have data for it */
+ writew(0, vaddr + (DOWNREQ));
+
+ brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS;
+}
+
+
+#define EXPANSION_ROM_SIZE (64 * 1024)
+#define FEP5_ROM_MAGIC (0xFEFFFFFF)
+
+static void dgap_get_vpd(struct board_t *brd)
+{
+ u32 magic;
+ u32 base_offset;
+ u16 rom_offset;
+ u16 vpd_offset;
+ u16 image_length;
+ u16 i;
+ uchar byte1;
+ uchar byte2;
+
+ /*
+ * Poke the magic number at the PCI Rom Address location.
+ * If VPD is supported, the value read from that address
+ * will be non-zero.
+ */
+ magic = FEP5_ROM_MAGIC;
+ pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
+ pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic);
+
+ /* VPD not supported, bail */
+ if (!magic)
+ return;
+
+ /*
+ * To get to the OTPROM memory, we have to send the boards base
+ * address or'ed with 1 into the PCI Rom Address location.
+ */
+ magic = brd->membase | 0x01;
+ pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
+ pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic);
+
+ byte1 = readb(brd->re_map_membase);
+ byte2 = readb(brd->re_map_membase + 1);
+
+ /*
+ * If the board correctly swapped to the OTPROM memory,
+ * the first 2 bytes (header) should be 0x55, 0xAA
+ */
+ if (byte1 == 0x55 && byte2 == 0xAA) {
+
+ base_offset = 0;
+
+ /*
+ * We have to run through all the OTPROM memory looking
+ * for the VPD offset.
+ */
+ while (base_offset <= EXPANSION_ROM_SIZE) {
+
+ /*
+ * Lots of magic numbers here.
+ *
+ * The VPD offset is located inside the ROM Data Structure.
+ * We also have to remember the length of each
+ * ROM Data Structure, so we can "hop" to the next
+ * entry if the VPD isn't in the current
+ * ROM Data Structure.
+ */
+ rom_offset = readw(brd->re_map_membase + base_offset + 0x18);
+ image_length = readw(brd->re_map_membase + rom_offset + 0x10) * 512;
+ vpd_offset = readw(brd->re_map_membase + rom_offset + 0x08);
+
+ /* Found the VPD entry */
+ if (vpd_offset)
+ break;
+
+ /* We didn't find a VPD entry, go to next ROM entry. */
+ base_offset += image_length;
+
+ byte1 = readb(brd->re_map_membase + base_offset);
+ byte2 = readb(brd->re_map_membase + base_offset + 1);
+
+ /*
+ * If the new ROM offset doesn't have 0x55, 0xAA
+ * as its header, we have run out of ROM.
+ */
+ if (byte1 != 0x55 || byte2 != 0xAA)
+ break;
+ }
+
+ /*
+ * If we have a VPD offset, then mark the board
+ * as having a valid VPD, and copy VPDSIZE (512) bytes of
+ * that VPD to the buffer we have in our board structure.
+ */
+ if (vpd_offset) {
+ brd->bd_flags |= BD_HAS_VPD;
+ for (i = 0; i < VPDSIZE; i++)
+ brd->vpd[i] = readb(brd->re_map_membase + vpd_offset + i);
+ }
+ }
+
+ /*
+ * We MUST poke the magic number at the PCI Rom Address location again.
+ * This makes the card report the regular board memory back to us,
+ * rather than the OTPROM memory.
+ */
+ magic = FEP5_ROM_MAGIC;
+ pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
+}
+
+
+/*
+ * Our board poller function.
+ */
+void dgap_poll_tasklet(unsigned long data)
+{
+ struct board_t *bd = (struct board_t *) data;
+ ulong lock_flags;
+ ulong lock_flags2;
+ char *vaddr;
+ u16 head, tail;
+ u16 *chk_addr;
+ u16 check = 0;
+
+ if (!bd || (bd->magic != DGAP_BOARD_MAGIC)) {
+ APR(("dgap_poll_tasklet() - NULL or bad bd.\n"));
+ return;
+ }
+
+ if (bd->inhibit_poller)
+ return;
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+
+ vaddr = bd->re_map_membase;
+
+ /*
+ * If board is ready, parse deeper to see if there is anything to do.
+ */
+ if (bd->state == BOARD_READY) {
+
+ struct ev_t *eaddr = NULL;
+
+ if (!bd->re_map_membase) {
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return;
+ }
+ if (!bd->re_map_port) {
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return;
+ }
+
+ if (!bd->nasync) {
+ goto out;
+ }
+
+ /*
+ * If this is a CX or EPCX, we need to see if the firmware
+ * is requesting a concentrator image from us.
+ */
+ if ((bd->type == PCX) || (bd->type == PEPC)) {
+ chk_addr = (u16 *) (vaddr + DOWNREQ);
+ check = readw(chk_addr);
+ /* Nonzero if FEP is requesting concentrator image. */
+ if (check) {
+ if (bd->conc_dl_status == NO_PENDING_CONCENTRATOR_REQUESTS)
+ bd->conc_dl_status = NEED_CONCENTRATOR;
+ /*
+ * Signal downloader, its got some work to do.
+ */
+ DGAP_LOCK(dgap_dl_lock, lock_flags2);
+ if (dgap_dl_action != 1) {
+ dgap_dl_action = 1;
+ wake_up_interruptible(&dgap_dl_wait);
+ }
+ DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+
+ }
+ }
+
+ eaddr = (struct ev_t *) (vaddr + EVBUF);
+
+ /* Get our head and tail */
+ head = readw(&(eaddr->ev_head));
+ tail = readw(&(eaddr->ev_tail));
+
+ /*
+ * If there is an event pending. Go service it.
+ */
+ if (head != tail) {
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ dgap_event(bd);
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ }
+
+out:
+ /*
+ * If board is doing interrupts, ACK the interrupt.
+ */
+ if (bd && bd->intr_running) {
+ readb(bd->re_map_port + 2);
+ }
+
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return;
+ }
+
+ /* Our state machine to get the board up and running */
+
+ /* Reset board */
+ if (bd->state == NEED_RESET) {
+
+ /* Get VPD info */
+ dgap_get_vpd(bd);
+
+ dgap_do_reset_board(bd);
+ }
+
+ /* Move to next state */
+ if (bd->state == FINISHED_RESET) {
+ bd->state = NEED_CONFIG;
+ }
+
+ if (bd->state == NEED_CONFIG) {
+ /*
+ * Match this board to a config the user created for us.
+ */
+ bd->bd_config = dgap_find_config(bd->type, bd->pci_bus, bd->pci_slot);
+
+ /*
+ * Because the 4 port Xr products share the same PCI ID
+ * as the 8 port Xr products, if we receive a NULL config
+ * back, and this is a PAPORT8 board, retry with a
+ * PAPORT4 attempt as well.
+ */
+ if (bd->type == PAPORT8 && !bd->bd_config) {
+ bd->bd_config = dgap_find_config(PAPORT4, bd->pci_bus, bd->pci_slot);
+ }
+
+ /*
+ * Register the ttys (if any) into the kernel.
+ */
+ if (bd->bd_config) {
+ bd->state = FINISHED_CONFIG;
+ }
+ else {
+ bd->state = CONFIG_NOT_FOUND;
+ }
+ }
+
+ /* Move to next state */
+ if (bd->state == FINISHED_CONFIG) {
+ bd->state = NEED_DEVICE_CREATION;
+ }
+
+ /* Move to next state */
+ if (bd->state == NEED_DEVICE_CREATION) {
+ /*
+ * Signal downloader, its got some work to do.
+ */
+ DGAP_LOCK(dgap_dl_lock, lock_flags2);
+ if (dgap_dl_action != 1) {
+ dgap_dl_action = 1;
+ wake_up_interruptible(&dgap_dl_wait);
+ }
+ DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+ }
+
+ /* Move to next state */
+ if (bd->state == FINISHED_DEVICE_CREATION) {
+ bd->state = NEED_BIOS_LOAD;
+ }
+
+ /* Move to next state */
+ if (bd->state == NEED_BIOS_LOAD) {
+ /*
+ * Signal downloader, its got some work to do.
+ */
+ DGAP_LOCK(dgap_dl_lock, lock_flags2);
+ if (dgap_dl_action != 1) {
+ dgap_dl_action = 1;
+ wake_up_interruptible(&dgap_dl_wait);
+ }
+ DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+ }
+
+ /* Wait for BIOS to test board... */
+ if (bd->state == WAIT_BIOS_LOAD) {
+ dgap_do_wait_for_bios(bd);
+ }
+
+ /* Move to next state */
+ if (bd->state == FINISHED_BIOS_LOAD) {
+ bd->state = NEED_FEP_LOAD;
+
+ /*
+ * Signal downloader, its got some work to do.
+ */
+ DGAP_LOCK(dgap_dl_lock, lock_flags2);
+ if (dgap_dl_action != 1) {
+ dgap_dl_action = 1;
+ wake_up_interruptible(&dgap_dl_wait);
+ }
+ DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+ }
+
+ /* Wait for FEP to load on board... */
+ if (bd->state == WAIT_FEP_LOAD) {
+ dgap_do_wait_for_fep(bd);
+ }
+
+
+ /* Move to next state */
+ if (bd->state == FINISHED_FEP_LOAD) {
+
+ /*
+ * Do tty device initialization.
+ */
+ int rc = dgap_tty_init(bd);
+
+ if (rc < 0) {
+ dgap_tty_uninit(bd);
+ APR(("Can't init tty devices (%d)\n", rc));
+ bd->state = BOARD_FAILED;
+ bd->dpastatus = BD_NOFEP;
+ }
+ else {
+ bd->state = NEED_PROC_CREATION;
+
+ /*
+ * Signal downloader, its got some work to do.
+ */
+ DGAP_LOCK(dgap_dl_lock, lock_flags2);
+ if (dgap_dl_action != 1) {
+ dgap_dl_action = 1;
+ wake_up_interruptible(&dgap_dl_wait);
+ }
+ DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+ }
+ }
+
+ /* Move to next state */
+ if (bd->state == FINISHED_PROC_CREATION) {
+
+ bd->state = BOARD_READY;
+ bd->dpastatus = BD_RUNNING;
+
+ /*
+ * If user requested the board to run in interrupt mode,
+ * go and set it up on the board.
+ */
+ if (bd->intr_used) {
+ writew(1, (bd->re_map_membase + ENABLE_INTR));
+ /*
+ * Tell the board to poll the UARTS as fast as possible.
+ */
+ writew(FEPPOLL_MIN, (bd->re_map_membase + FEPPOLL));
+ bd->intr_running = 1;
+ }
+
+ /* Wake up anyone waiting for board state to change to ready */
+ wake_up_interruptible(&bd->state_wait);
+ }
+
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+}
+
+
+/*=======================================================================
+ *
+ * dgap_cmdb - Sends a 2 byte command to the FEP.
+ *
+ * ch - Pointer to channel structure.
+ * cmd - Command to be sent.
+ * byte1 - Integer containing first byte to be sent.
+ * byte2 - Integer containing second byte to be sent.
+ * ncmds - Wait until ncmds or fewer cmds are left
+ * in the cmd buffer before returning.
+ *
+ *=======================================================================*/
+void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds)
+{
+ char *vaddr = NULL;
+ struct cm_t *cm_addr = NULL;
+ uint count;
+ uint n;
+ u16 head;
+ u16 tail;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ /*
+ * Check if board is still alive.
+ */
+ if (ch->ch_bd->state == BOARD_FAILED) {
+ DPR_CORE(("%s:%d board is in failed state.\n", __FILE__, __LINE__));
+ return;
+ }
+
+ /*
+ * Make sure the pointers are in range before
+ * writing to the FEP memory.
+ */
+ vaddr = ch->ch_bd->re_map_membase;
+
+ if (!vaddr)
+ return;
+
+ cm_addr = (struct cm_t *) (vaddr + CMDBUF);
+ head = readw(&(cm_addr->cm_head));
+
+ /*
+ * Forget it if pointers out of range.
+ */
+ if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
+ DPR_CORE(("%s:%d pointers out of range, failing board!\n", __FILE__, __LINE__));
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+
+ /*
+ * Put the data in the circular command buffer.
+ */
+ writeb(cmd, (char *) (vaddr + head + CMDSTART + 0));
+ writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1));
+ writeb(byte1, (char *) (vaddr + head + CMDSTART + 2));
+ writeb(byte2, (char *) (vaddr + head + CMDSTART + 3));
+
+ head = (head + 4) & (CMDMAX - CMDSTART - 4);
+
+ writew(head, &(cm_addr->cm_head));
+
+ /*
+ * Wait if necessary before updating the head
+ * pointer to limit the number of outstanding
+ * commands to the FEP. If the time spent waiting
+ * is outlandish, declare the FEP dead.
+ */
+ for (count = dgap_count ;;) {
+
+ head = readw(&(cm_addr->cm_head));
+ tail = readw(&(cm_addr->cm_tail));
+
+ n = (head - tail) & (CMDMAX - CMDSTART - 4);
+
+ if (n <= ncmds * sizeof(struct cm_t))
+ break;
+
+ if (--count == 0) {
+ DPR_CORE(("%s:%d failing board.\n",__FILE__, __LINE__));
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+ udelay(10);
+ }
+}
+
+
+/*=======================================================================
+ *
+ * dgap_cmdw - Sends a 1 word command to the FEP.
+ *
+ * ch - Pointer to channel structure.
+ * cmd - Command to be sent.
+ * word - Integer containing word to be sent.
+ * ncmds - Wait until ncmds or fewer cmds are left
+ * in the cmd buffer before returning.
+ *
+ *=======================================================================*/
+void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds)
+{
+ char *vaddr = NULL;
+ struct cm_t *cm_addr = NULL;
+ uint count;
+ uint n;
+ u16 head;
+ u16 tail;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ /*
+ * Check if board is still alive.
+ */
+ if (ch->ch_bd->state == BOARD_FAILED) {
+ DPR_CORE(("%s:%d board is failed!\n", __FILE__, __LINE__));
+ return;
+ }
+
+ /*
+ * Make sure the pointers are in range before
+ * writing to the FEP memory.
+ */
+ vaddr = ch->ch_bd->re_map_membase;
+ if (!vaddr)
+ return;
+
+ cm_addr = (struct cm_t *) (vaddr + CMDBUF);
+ head = readw(&(cm_addr->cm_head));
+
+ /*
+ * Forget it if pointers out of range.
+ */
+ if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
+ DPR_CORE(("%s:%d Pointers out of range. Failing board.\n",__FILE__, __LINE__));
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+
+ /*
+ * Put the data in the circular command buffer.
+ */
+ writeb(cmd, (char *) (vaddr + head + CMDSTART + 0));
+ writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1));
+ writew((u16) word, (char *) (vaddr + head + CMDSTART + 2));
+
+ head = (head + 4) & (CMDMAX - CMDSTART - 4);
+
+ writew(head, &(cm_addr->cm_head));
+
+ /*
+ * Wait if necessary before updating the head
+ * pointer to limit the number of outstanding
+ * commands to the FEP. If the time spent waiting
+ * is outlandish, declare the FEP dead.
+ */
+ for (count = dgap_count ;;) {
+
+ head = readw(&(cm_addr->cm_head));
+ tail = readw(&(cm_addr->cm_tail));
+
+ n = (head - tail) & (CMDMAX - CMDSTART - 4);
+
+ if (n <= ncmds * sizeof(struct cm_t))
+ break;
+
+ if (--count == 0) {
+ DPR_CORE(("%s:%d Failing board.\n",__FILE__, __LINE__));
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+ udelay(10);
+ }
+}
+
+
+
+/*=======================================================================
+ *
+ * dgap_cmdw_ext - Sends a extended word command to the FEP.
+ *
+ * ch - Pointer to channel structure.
+ * cmd - Command to be sent.
+ * word - Integer containing word to be sent.
+ * ncmds - Wait until ncmds or fewer cmds are left
+ * in the cmd buffer before returning.
+ *
+ *=======================================================================*/
+static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds)
+{
+ char *vaddr = NULL;
+ struct cm_t *cm_addr = NULL;
+ uint count;
+ uint n;
+ u16 head;
+ u16 tail;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ /*
+ * Check if board is still alive.
+ */
+ if (ch->ch_bd->state == BOARD_FAILED) {
+ DPR_CORE(("%s:%d board is failed!\n", __FILE__, __LINE__));
+ return;
+ }
+
+ /*
+ * Make sure the pointers are in range before
+ * writing to the FEP memory.
+ */
+ vaddr = ch->ch_bd->re_map_membase;
+ if (!vaddr)
+ return;
+
+ cm_addr = (struct cm_t *) (vaddr + CMDBUF);
+ head = readw(&(cm_addr->cm_head));
+
+ /*
+ * Forget it if pointers out of range.
+ */
+ if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
+ DPR_CORE(("%s:%d Pointers out of range. Failing board.\n",__FILE__, __LINE__));
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+
+ /*
+ * Put the data in the circular command buffer.
+ */
+
+ /* Write an FF to tell the FEP that we want an extended command */
+ writeb((uchar) 0xff, (char *) (vaddr + head + CMDSTART + 0));
+
+ writeb((uchar) ch->ch_portnum, (uchar *) (vaddr + head + CMDSTART + 1));
+ writew((u16) cmd, (char *) (vaddr + head + CMDSTART + 2));
+
+ /*
+ * If the second part of the command won't fit,
+ * put it at the beginning of the circular buffer.
+ */
+ if (((head + 4) >= ((CMDMAX - CMDSTART)) || (head & 03))) {
+ writew((u16) word, (char *) (vaddr + CMDSTART));
+ } else {
+ writew((u16) word, (char *) (vaddr + head + CMDSTART + 4));
+ }
+
+ head = (head + 8) & (CMDMAX - CMDSTART - 4);
+
+ writew(head, &(cm_addr->cm_head));
+
+ /*
+ * Wait if necessary before updating the head
+ * pointer to limit the number of outstanding
+ * commands to the FEP. If the time spent waiting
+ * is outlandish, declare the FEP dead.
+ */
+ for (count = dgap_count ;;) {
+
+ head = readw(&(cm_addr->cm_head));
+ tail = readw(&(cm_addr->cm_tail));
+
+ n = (head - tail) & (CMDMAX - CMDSTART - 4);
+
+ if (n <= ncmds * sizeof(struct cm_t))
+ break;
+
+ if (--count == 0) {
+ DPR_CORE(("%s:%d Failing board.\n",__FILE__, __LINE__));
+ ch->ch_bd->state = BOARD_FAILED;
+ return;
+ }
+ udelay(10);
+ }
+}
+
+
+/*=======================================================================
+ *
+ * dgap_wmove - Write data to FEP buffer.
+ *
+ * ch - Pointer to channel structure.
+ * buf - Poiter to characters to be moved.
+ * cnt - Number of characters to move.
+ *
+ *=======================================================================*/
+void dgap_wmove(struct channel_t *ch, char *buf, uint cnt)
+{
+ int n;
+ char *taddr;
+ struct bs_t *bs;
+ u16 head;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ /*
+ * Check parameters.
+ */
+ bs = ch->ch_bs;
+ head = readw(&(bs->tx_head));
+
+ /*
+ * If pointers are out of range, just return.
+ */
+ if ((cnt > ch->ch_tsize) || (unsigned)(head - ch->ch_tstart) >= ch->ch_tsize) {
+ DPR_CORE(("%s:%d pointer out of range", __FILE__, __LINE__));
+ return;
+ }
+
+ /*
+ * If the write wraps over the top of the circular buffer,
+ * move the portion up to the wrap point, and reset the
+ * pointers to the bottom.
+ */
+ n = ch->ch_tstart + ch->ch_tsize - head;
+
+ if (cnt >= n) {
+ cnt -= n;
+ taddr = ch->ch_taddr + head;
+ memcpy_toio(taddr, buf, n);
+ head = ch->ch_tstart;
+ buf += n;
+ }
+
+ /*
+ * Move rest of data.
+ */
+ taddr = ch->ch_taddr + head;
+ n = cnt;
+ memcpy_toio(taddr, buf, n);
+ head += cnt;
+
+ writew(head, &(bs->tx_head));
+}
+
+/*
+ * Retrives the current custom baud rate from FEP memory,
+ * and returns it back to the user.
+ * Returns 0 on error.
+ */
+uint dgap_get_custom_baud(struct channel_t *ch)
+{
+ uchar *vaddr;
+ ulong offset = 0;
+ uint value = 0;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) {
+ return (0);
+ }
+
+ if (!ch->ch_bd || ch->ch_bd->magic != DGAP_BOARD_MAGIC) {
+ return (0);
+ }
+
+ if (!(ch->ch_bd->bd_flags & BD_FEP5PLUS))
+ return (0);
+
+ vaddr = ch->ch_bd->re_map_membase;
+
+ if (!vaddr)
+ return (0);
+
+ /*
+ * Go get from fep mem, what the fep
+ * believes the custom baud rate is.
+ */
+ offset = ((((*(unsigned short *)(vaddr + ECS_SEG)) << 4) +
+ (ch->ch_portnum * 0x28) + LINE_SPEED));
+
+ value = readw(vaddr + offset);
+ return (value);
+}
+
+
+/*
+ * Calls the firmware to reset this channel.
+ */
+void dgap_firmware_reset_port(struct channel_t *ch)
+{
+ dgap_cmdb(ch, CHRESET, 0, 0, 0);
+
+ /*
+ * Now that the channel is reset, we need to make sure
+ * all the current settings get reapplied to the port
+ * in the firmware.
+ *
+ * So we will set the driver's cache of firmware
+ * settings all to 0, and then call param.
+ */
+ ch->ch_fepiflag = 0;
+ ch->ch_fepcflag = 0;
+ ch->ch_fepoflag = 0;
+ ch->ch_fepstartc = 0;
+ ch->ch_fepstopc = 0;
+ ch->ch_fepastartc = 0;
+ ch->ch_fepastopc = 0;
+ ch->ch_mostat = 0;
+ ch->ch_hflow = 0;
+}
+
+
+/*=======================================================================
+ *
+ * dgap_param - Set Digi parameters.
+ *
+ * struct tty_struct * - TTY for port.
+ *
+ *=======================================================================*/
+int dgap_param(struct tty_struct *tty)
+{
+ struct ktermios *ts;
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct bs_t *bs;
+ struct un_t *un;
+ u16 head;
+ u16 cflag;
+ u16 iflag;
+ uchar mval;
+ uchar hflow;
+
+ if (!tty || tty->magic != TTY_MAGIC) {
+ return (-ENXIO);
+ }
+
+ un = (struct un_t *) tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC) {
+ return (-ENXIO);
+ }
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) {
+ return (-ENXIO);
+ }
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC) {
+ return (-ENXIO);
+ }
+
+ bs = ch->ch_bs;
+ if (bs == 0) {
+ return (-ENXIO);
+ }
+
+ DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n",
+ ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag));
+
+ ts = &tty->termios;
+
+ /*
+ * If baud rate is zero, flush queues, and set mval to drop DTR.
+ */
+ if ((ch->ch_c_cflag & (CBAUD)) == 0) {
+
+ /* flush rx */
+ head = readw(&(ch->ch_bs->rx_head));
+ writew(head, &(ch->ch_bs->rx_tail));
+
+ /* flush tx */
+ head = readw(&(ch->ch_bs->tx_head));
+ writew(head, &(ch->ch_bs->tx_tail));
+
+ ch->ch_flags |= (CH_BAUD0);
+
+ /* Drop RTS and DTR */
+ ch->ch_mval &= ~(D_RTS(ch)|D_DTR(ch));
+ mval = D_DTR(ch) | D_RTS(ch);
+ ch->ch_baud_info = 0;
+
+ } else if (ch->ch_custom_speed && (bd->bd_flags & BD_FEP5PLUS)) {
+ /*
+ * Tell the fep to do the command
+ */
+
+ DPR_PARAM(("param: Want %d speed\n", ch->ch_custom_speed));
+
+ dgap_cmdw_ext(ch, 0xff01, ch->ch_custom_speed, 0);
+
+ /*
+ * Now go get from fep mem, what the fep
+ * believes the custom baud rate is.
+ */
+ ch->ch_baud_info = ch->ch_custom_speed = dgap_get_custom_baud(ch);
+
+ DPR_PARAM(("param: Got %d speed\n", ch->ch_custom_speed));
+
+ /* Handle transition from B0 */
+ if (ch->ch_flags & CH_BAUD0) {
+ ch->ch_flags &= ~(CH_BAUD0);
+ ch->ch_mval |= (D_RTS(ch)|D_DTR(ch));
+ }
+ mval = D_DTR(ch) | D_RTS(ch);
+
+ } else {
+ /*
+ * Set baud rate, character size, and parity.
+ */
+
+
+ int iindex = 0;
+ int jindex = 0;
+ int baud = 0;
+
+ ulong bauds[4][16] = {
+ { /* slowbaud */
+ 0, 50, 75, 110,
+ 134, 150, 200, 300,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* slowbaud & CBAUDEX */
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* fastbaud */
+ 0, 57600, 76800, 115200,
+ 14400, 57600, 230400, 76800,
+ 115200, 230400, 28800, 460800,
+ 921600, 9600, 19200, 38400 },
+ { /* fastbaud & CBAUDEX */
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 }
+ };
+
+ /* Only use the TXPrint baud rate if the terminal unit is NOT open */
+ if (!(ch->ch_tun.un_flags & UN_ISOPEN) && (un->un_type == DGAP_PRINT))
+ baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
+ else
+ baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
+
+ if (ch->ch_c_cflag & CBAUDEX)
+ iindex = 1;
+
+ if (ch->ch_digi.digi_flags & DIGI_FAST)
+ iindex += 2;
+
+ jindex = baud;
+
+ if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16)) {
+ baud = bauds[iindex][jindex];
+ } else {
+ DPR_IOCTL(("baud indices were out of range (%d)(%d)",
+ iindex, jindex));
+ baud = 0;
+ }
+
+ if (baud == 0)
+ baud = 9600;
+
+ ch->ch_baud_info = baud;
+
+
+ /*
+ * CBAUD has bit position 0x1000 set these days to indicate Linux
+ * baud rate remap.
+ * We use a different bit assignment for high speed. Clear this
+ * bit out while grabbing the parts of "cflag" we want.
+ */
+ cflag = ch->ch_c_cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
+
+ /*
+ * HUPCL bit is used by FEP to indicate fast baud
+ * table is to be used.
+ */
+ if ((ch->ch_digi.digi_flags & DIGI_FAST) || (ch->ch_c_cflag & CBAUDEX))
+ cflag |= HUPCL;
+
+
+ if ((ch->ch_c_cflag & CBAUDEX) && !(ch->ch_digi.digi_flags & DIGI_FAST)) {
+ /*
+ * The below code is trying to guarantee that only baud rates
+ * 115200, 230400, 460800, 921600 are remapped. We use exclusive or
+ * because the various baud rates share common bit positions
+ * and therefore can't be tested for easily.
+ */
+ tcflag_t tcflag = (ch->ch_c_cflag & CBAUD) | CBAUDEX;
+ int baudpart = 0;
+
+ /* Map high speed requests to index into FEP's baud table */
+ switch (tcflag) {
+ case B57600 :
+ baudpart = 1;
+ break;
+#ifdef B76800
+ case B76800 :
+ baudpart = 2;
+ break;
+#endif
+ case B115200 :
+ baudpart = 3;
+ break;
+ case B230400 :
+ baudpart = 9;
+ break;
+ case B460800 :
+ baudpart = 11;
+ break;
+#ifdef B921600
+ case B921600 :
+ baudpart = 12;
+ break;
+#endif
+ default:
+ baudpart = 0;
+ }
+
+ if (baudpart)
+ cflag = (cflag & ~(CBAUD | CBAUDEX)) | baudpart;
+ }
+
+ cflag &= 0xffff;
+
+ if (cflag != ch->ch_fepcflag) {
+ ch->ch_fepcflag = (u16) (cflag & 0xffff);
+
+ /* Okay to have channel and board locks held calling this */
+ dgap_cmdw(ch, SCFLAG, (u16) cflag, 0);
+ }
+
+ /* Handle transition from B0 */
+ if (ch->ch_flags & CH_BAUD0) {
+ ch->ch_flags &= ~(CH_BAUD0);
+ ch->ch_mval |= (D_RTS(ch)|D_DTR(ch));
+ }
+ mval = D_DTR(ch) | D_RTS(ch);
+ }
+
+ /*
+ * Get input flags.
+ */
+ iflag = ch->ch_c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | IXON | IXANY | IXOFF);
+
+ if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE)) {
+ iflag &= ~(IXON | IXOFF);
+ ch->ch_c_iflag &= ~(IXON | IXOFF);
+ }
+
+ /*
+ * Only the IBM Xr card can switch between
+ * 232 and 422 modes on the fly
+ */
+ if (bd->device == PCI_DEVICE_XR_IBM_DID) {
+ if (ch->ch_digi.digi_flags & DIGI_422)
+ dgap_cmdb(ch, SCOMMODE, MODE_422, 0, 0);
+ else
+ dgap_cmdb(ch, SCOMMODE, MODE_232, 0, 0);
+ }
+
+ if (ch->ch_digi.digi_flags & DIGI_ALTPIN)
+ iflag |= IALTPIN ;
+
+ if (iflag != ch->ch_fepiflag) {
+ ch->ch_fepiflag = iflag;
+
+ /* Okay to have channel and board locks held calling this */
+ dgap_cmdw(ch, SIFLAG, (u16) ch->ch_fepiflag, 0);
+ }
+
+ /*
+ * Select hardware handshaking.
+ */
+ hflow = 0;
+
+ if (ch->ch_c_cflag & CRTSCTS) {
+ hflow |= (D_RTS(ch) | D_CTS(ch));
+ }
+ if (ch->ch_digi.digi_flags & RTSPACE)
+ hflow |= D_RTS(ch);
+ if (ch->ch_digi.digi_flags & DTRPACE)
+ hflow |= D_DTR(ch);
+ if (ch->ch_digi.digi_flags & CTSPACE)
+ hflow |= D_CTS(ch);
+ if (ch->ch_digi.digi_flags & DSRPACE)
+ hflow |= D_DSR(ch);
+ if (ch->ch_digi.digi_flags & DCDPACE)
+ hflow |= D_CD(ch);
+
+ if (hflow != ch->ch_hflow) {
+ ch->ch_hflow = hflow;
+
+ /* Okay to have channel and board locks held calling this */
+ dgap_cmdb(ch, SHFLOW, (uchar) hflow, 0xff, 0);
+ }
+
+
+ /*
+ * Set RTS and/or DTR Toggle if needed, but only if product is FEP5+ based.
+ */
+ if (bd->bd_flags & BD_FEP5PLUS) {
+ u16 hflow2 = 0;
+ if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
+ hflow2 |= (D_RTS(ch));
+ }
+ if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
+ hflow2 |= (D_DTR(ch));
+ }
+
+ dgap_cmdw_ext(ch, 0xff03, hflow2, 0);
+ }
+
+ /*
+ * Set modem control lines.
+ */
+
+ mval ^= ch->ch_mforce & (mval ^ ch->ch_mval);
+
+ DPR_PARAM(("dgap_param: mval: %x ch_mforce: %x ch_mval: %x ch_mostat: %x\n",
+ mval, ch->ch_mforce, ch->ch_mval, ch->ch_mostat));
+
+ if (ch->ch_mostat ^ mval) {
+ ch->ch_mostat = mval;
+
+ /* Okay to have channel and board locks held calling this */
+ DPR_PARAM(("dgap_param: Sending SMODEM mval: %x\n", mval));
+ dgap_cmdb(ch, SMODEM, (uchar) mval, D_RTS(ch)|D_DTR(ch), 0);
+ }
+
+ /*
+ * Read modem signals, and then call carrier function.
+ */
+ ch->ch_mistat = readb(&(bs->m_stat));
+ dgap_carrier(ch);
+
+ /*
+ * Set the start and stop characters.
+ */
+ if (ch->ch_startc != ch->ch_fepstartc || ch->ch_stopc != ch->ch_fepstopc) {
+ ch->ch_fepstartc = ch->ch_startc;
+ ch->ch_fepstopc = ch->ch_stopc;
+
+ /* Okay to have channel and board locks held calling this */
+ dgap_cmdb(ch, SFLOWC, ch->ch_fepstartc, ch->ch_fepstopc, 0);
+ }
+
+ /*
+ * Set the Auxiliary start and stop characters.
+ */
+ if (ch->ch_astartc != ch->ch_fepastartc || ch->ch_astopc != ch->ch_fepastopc) {
+ ch->ch_fepastartc = ch->ch_astartc;
+ ch->ch_fepastopc = ch->ch_astopc;
+
+ /* Okay to have channel and board locks held calling this */
+ dgap_cmdb(ch, SAFLOWC, ch->ch_fepastartc, ch->ch_fepastopc, 0);
+ }
+
+ DPR_PARAM(("param finish\n"));
+
+ return (0);
+}
+
+
+/*
+ * dgap_parity_scan()
+ *
+ * Convert the FEP5 way of reporting parity errors and breaks into
+ * the Linux line discipline way.
+ */
+void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len)
+{
+ int l = *len;
+ int count = 0;
+ unsigned char *in, *cout, *fout;
+ unsigned char c;
+
+ in = cbuf;
+ cout = cbuf;
+ fout = fbuf;
+
+ DPR_PSCAN(("dgap_parity_scan start\n"));
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ while (l--) {
+ c = *in++;
+ switch (ch->pscan_state) {
+ default:
+ /* reset to sanity and fall through */
+ ch->pscan_state = 0;
+
+ case 0:
+ /* No FF seen yet */
+ if (c == (unsigned char) '\377') {
+ /* delete this character from stream */
+ ch->pscan_state = 1;
+ } else {
+ *cout++ = c;
+ *fout++ = TTY_NORMAL;
+ count += 1;
+ }
+ break;
+
+ case 1:
+ /* first FF seen */
+ if (c == (unsigned char) '\377') {
+ /* doubled ff, transform to single ff */
+ *cout++ = c;
+ *fout++ = TTY_NORMAL;
+ count += 1;
+ ch->pscan_state = 0;
+ } else {
+ /* save value examination in next state */
+ ch->pscan_savechar = c;
+ ch->pscan_state = 2;
+ }
+ break;
+
+ case 2:
+ /* third character of ff sequence */
+
+ *cout++ = c;
+
+ if (ch->pscan_savechar == 0x0) {
+
+ if (c == 0x0) {
+ DPR_PSCAN(("dgap_parity_scan in 3rd char of ff seq. c: %x setting break.\n", c));
+ ch->ch_err_break++;
+ *fout++ = TTY_BREAK;
+ }
+ else {
+ DPR_PSCAN(("dgap_parity_scan in 3rd char of ff seq. c: %x setting parity.\n", c));
+ ch->ch_err_parity++;
+ *fout++ = TTY_PARITY;
+ }
+ }
+ else {
+ DPR_PSCAN(("%s:%d Logic Error.\n", __FILE__, __LINE__));
+ }
+
+ count += 1;
+ ch->pscan_state = 0;
+ }
+ }
+ *len = count;
+ DPR_PSCAN(("dgap_parity_scan finish\n"));
+}
+
+
+
+
+/*=======================================================================
+ *
+ * dgap_event - FEP to host event processing routine.
+ *
+ * bd - Board of current event.
+ *
+ *=======================================================================*/
+static int dgap_event(struct board_t *bd)
+{
+ struct channel_t *ch;
+ ulong lock_flags;
+ ulong lock_flags2;
+ struct bs_t *bs;
+ uchar *event;
+ uchar *vaddr = NULL;
+ struct ev_t *eaddr = NULL;
+ uint head;
+ uint tail;
+ int port;
+ int reason;
+ int modem;
+ int b1;
+
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (-ENXIO);
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+
+ vaddr = bd->re_map_membase;
+
+ if (!vaddr) {
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return (-ENXIO);
+ }
+
+ eaddr = (struct ev_t *) (vaddr + EVBUF);
+
+ /* Get our head and tail */
+ head = readw(&(eaddr->ev_head));
+ tail = readw(&(eaddr->ev_tail));
+
+ /*
+ * Forget it if pointers out of range.
+ */
+
+ if (head >= EVMAX - EVSTART || tail >= EVMAX - EVSTART ||
+ (head | tail) & 03) {
+ DPR_EVENT(("should be calling xxfail %d\n", __LINE__));
+ /* Let go of board lock */
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return (-ENXIO);
+ }
+
+ /*
+ * Loop to process all the events in the buffer.
+ */
+ while (tail != head) {
+
+ /*
+ * Get interrupt information.
+ */
+
+ event = bd->re_map_membase + tail + EVSTART;
+
+ port = event[0];
+ reason = event[1];
+ modem = event[2];
+ b1 = event[3];
+
+ DPR_EVENT(("event: jiffies: %ld port: %d reason: %x modem: %x\n",
+ jiffies, port, reason, modem));
+
+ /*
+ * Make sure the interrupt is valid.
+ */
+ if ( port >= bd->nasync) {
+ goto next;
+ }
+
+ if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA))) {
+ goto next;
+ }
+
+ ch = bd->channels[port];
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) {
+ goto next;
+ }
+
+ /*
+ * If we have made it here, the event was valid.
+ * Lock down the channel.
+ */
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ bs = ch->ch_bs;
+
+ if (!bs) {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ goto next;
+ }
+
+ /*
+ * Process received data.
+ */
+ if (reason & IFDATA) {
+
+ /*
+ * ALL LOCKS *MUST* BE DROPPED BEFORE CALLING INPUT!
+ * input could send some data to ld, which in turn
+ * could do a callback to one of our other functions.
+ */
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ dgap_input(ch);
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ if (ch->ch_flags & CH_RACTIVE)
+ ch->ch_flags |= CH_RENABLE;
+ else
+ writeb(1, &(bs->idata));
+
+ if (ch->ch_flags & CH_RWAIT) {
+ ch->ch_flags &= ~CH_RWAIT;
+
+ wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+ }
+ }
+
+ /*
+ * Process Modem change signals.
+ */
+ if (reason & IFMODEM) {
+ ch->ch_mistat = modem;
+ dgap_carrier(ch);
+ }
+
+ /*
+ * Process break.
+ */
+ if (reason & IFBREAK) {
+
+ DPR_EVENT(("got IFBREAK\n"));
+
+ if (ch->ch_tun.un_tty) {
+ /* A break has been indicated */
+ ch->ch_err_break++;
+ tty_buffer_request_room(ch->ch_tun.un_tty->port, 1);
+ tty_insert_flip_char(ch->ch_tun.un_tty->port, 0, TTY_BREAK);
+ tty_flip_buffer_push(ch->ch_tun.un_tty->port);
+ }
+ }
+
+ /*
+ * Process Transmit low.
+ */
+ if (reason & IFTLW) {
+
+ DPR_EVENT(("event: got low event\n"));
+
+ if (ch->ch_tun.un_flags & UN_LOW) {
+ ch->ch_tun.un_flags &= ~UN_LOW;
+
+ if (ch->ch_tun.un_flags & UN_ISOPEN) {
+ if ((ch->ch_tun.un_tty->flags &
+ (1 << TTY_DO_WRITE_WAKEUP)) &&
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+ ch->ch_tun.un_tty->ldisc->ops->write_wakeup)
+#else
+ ch->ch_tun.un_tty->ldisc.ops->write_wakeup)
+#endif
+ {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+ (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty);
+#else
+ (ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty);
+#endif
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+ }
+ wake_up_interruptible(&ch->ch_tun.un_tty->write_wait);
+ wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+
+ DPR_EVENT(("event: Got low event. jiffies: %lu\n", jiffies));
+ }
+ }
+
+ if (ch->ch_pun.un_flags & UN_LOW) {
+ ch->ch_pun.un_flags &= ~UN_LOW;
+ if (ch->ch_pun.un_flags & UN_ISOPEN) {
+ if ((ch->ch_pun.un_tty->flags &
+ (1 << TTY_DO_WRITE_WAKEUP)) &&
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+ ch->ch_pun.un_tty->ldisc->ops->write_wakeup)
+#else
+ ch->ch_pun.un_tty->ldisc.ops->write_wakeup)
+#endif
+ {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+ (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty);
+#else
+ (ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty);
+#endif
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+ }
+ wake_up_interruptible(&ch->ch_pun.un_tty->write_wait);
+ wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+ }
+ }
+
+ if (ch->ch_flags & CH_WLOW) {
+ ch->ch_flags &= ~CH_WLOW;
+ wake_up_interruptible(&ch->ch_flags_wait);
+ }
+ }
+
+ /*
+ * Process Transmit empty.
+ */
+ if (reason & IFTEM) {
+ DPR_EVENT(("event: got empty event\n"));
+
+ if (ch->ch_tun.un_flags & UN_EMPTY) {
+ ch->ch_tun.un_flags &= ~UN_EMPTY;
+ if (ch->ch_tun.un_flags & UN_ISOPEN) {
+ if ((ch->ch_tun.un_tty->flags &
+ (1 << TTY_DO_WRITE_WAKEUP)) &&
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+ ch->ch_tun.un_tty->ldisc->ops->write_wakeup)
+#else
+ ch->ch_tun.un_tty->ldisc.ops->write_wakeup)
+#endif
+ {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+ (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty);
+#else
+ (ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty);
+#endif
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+ }
+ wake_up_interruptible(&ch->ch_tun.un_tty->write_wait);
+ wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+ }
+ }
+
+ if (ch->ch_pun.un_flags & UN_EMPTY) {
+ ch->ch_pun.un_flags &= ~UN_EMPTY;
+ if (ch->ch_pun.un_flags & UN_ISOPEN) {
+ if ((ch->ch_pun.un_tty->flags &
+ (1 << TTY_DO_WRITE_WAKEUP)) &&
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+ ch->ch_pun.un_tty->ldisc->ops->write_wakeup)
+#else
+ ch->ch_pun.un_tty->ldisc.ops->write_wakeup)
+#endif
+ {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+ (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty);
+#else
+ (ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty);
+#endif
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+ }
+ wake_up_interruptible(&ch->ch_pun.un_tty->write_wait);
+ wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+ }
+ }
+
+
+ if (ch->ch_flags & CH_WEMPTY) {
+ ch->ch_flags &= ~CH_WEMPTY;
+ wake_up_interruptible(&ch->ch_flags_wait);
+ }
+ }
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+
+next:
+ tail = (tail + 4) & (EVMAX - EVSTART - 4);
+ }
+
+ writew(tail, &(eaddr->ev_tail));
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ return (0);
+}
diff --git a/drivers/staging/dgap/dgap_fep5.h b/drivers/staging/dgap/dgap_fep5.h
new file mode 100644
index 00000000000..3a12ba5e3c2
--- /dev/null
+++ b/drivers/staging/dgap/dgap_fep5.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ ************************************************************************
+ *** FEP Version 5 dependent definitions
+ ************************************************************************/
+
+#ifndef __DGAP_FEP5_H
+#define __DGAP_FEP5_H
+
+/************************************************************************
+ * FEP memory offsets
+ ************************************************************************/
+#define START 0x0004L /* Execution start address */
+
+#define CMDBUF 0x0d10L /* Command (cm_t) structure offset */
+#define CMDSTART 0x0400L /* Start of command buffer */
+#define CMDMAX 0x0800L /* End of command buffer */
+
+#define EVBUF 0x0d18L /* Event (ev_t) structure */
+#define EVSTART 0x0800L /* Start of event buffer */
+#define EVMAX 0x0c00L /* End of event buffer */
+#define FEP5_PLUS 0x0E40 /* ASCII '5' and ASCII 'A' is here */
+#define ECS_SEG 0x0E44 /* Segment of the extended channel structure */
+#define LINE_SPEED 0x10 /* Offset into ECS_SEG for line speed */
+ /* if the fep has extended capabilities */
+
+/* BIOS MAGIC SPOTS */
+#define ERROR 0x0C14L /* BIOS error code */
+#define SEQUENCE 0x0C12L /* BIOS sequence indicator */
+#define POSTAREA 0x0C00L /* POST complete message area */
+
+/* FEP MAGIC SPOTS */
+#define FEPSTAT POSTAREA /* OS here when FEP comes up */
+#define NCHAN 0x0C02L /* number of ports FEP sees */
+#define PANIC 0x0C10L /* PANIC area for FEP */
+#define KMEMEM 0x0C30L /* Memory for KME use */
+#define CONFIG 0x0CD0L /* Concentrator configuration info */
+#define CONFIGSIZE 0x0030 /* configuration info size */
+#define DOWNREQ 0x0D00 /* Download request buffer pointer */
+
+#define CHANBUF 0x1000L /* Async channel (bs_t) structs */
+#define FEPOSSIZE 0x1FFF /* 8K FEPOS */
+
+#define XEMPORTS 0xC02 /*
+ * Offset in board memory where FEP5 stores
+ * how many ports it has detected.
+ * NOTE: FEP5 reports 64 ports when the user
+ * has the cable in EBI OUT instead of EBI IN.
+ */
+
+#define FEPCLR 0x00
+#define FEPMEM 0x02
+#define FEPRST 0x04
+#define FEPINT 0x08
+#define FEPMASK 0x0e
+#define FEPWIN 0x80
+
+#define LOWMEM 0x0100
+#define HIGHMEM 0x7f00
+
+#define FEPTIMEOUT 200000
+
+#define ENABLE_INTR 0x0e04 /* Enable interrupts flag */
+#define FEPPOLL_MIN 1 /* minimum of 1 millisecond */
+#define FEPPOLL_MAX 20 /* maximum of 20 milliseconds */
+#define FEPPOLL 0x0c26 /* Fep event poll interval */
+
+#define IALTPIN 0x0080 /* Input flag to swap DSR <-> DCD */
+
+/************************************************************************
+ * Command structure definition.
+ ************************************************************************/
+struct cm_t {
+ volatile unsigned short cm_head; /* Command buffer head offset */
+ volatile unsigned short cm_tail; /* Command buffer tail offset */
+ volatile unsigned short cm_start; /* start offset of buffer */
+ volatile unsigned short cm_max; /* last offset of buffer */
+};
+
+/************************************************************************
+ * Event structure definition.
+ ************************************************************************/
+struct ev_t {
+ volatile unsigned short ev_head; /* Command buffer head offset */
+ volatile unsigned short ev_tail; /* Command buffer tail offset */
+ volatile unsigned short ev_start; /* start offset of buffer */
+ volatile unsigned short ev_max; /* last offset of buffer */
+};
+
+/************************************************************************
+ * Download buffer structure.
+ ************************************************************************/
+struct downld_t {
+ uchar dl_type; /* Header */
+ uchar dl_seq; /* Download sequence */
+ ushort dl_srev; /* Software revision number */
+ ushort dl_lrev; /* Low revision number */
+ ushort dl_hrev; /* High revision number */
+ ushort dl_seg; /* Start segment address */
+ ushort dl_size; /* Number of bytes to download */
+ uchar dl_data[1024]; /* Download data */
+};
+
+/************************************************************************
+ * Per channel buffer structure
+ ************************************************************************
+ * Base Structure Entries Usage Meanings to Host *
+ * *
+ * W = read write R = read only *
+ * C = changed by commands only *
+ * U = unknown (may be changed w/o notice) *
+ ************************************************************************/
+struct bs_t {
+ volatile unsigned short tp_jmp; /* Transmit poll jump */
+ volatile unsigned short tc_jmp; /* Cooked procedure jump */
+ volatile unsigned short ri_jmp; /* Not currently used */
+ volatile unsigned short rp_jmp; /* Receive poll jump */
+
+ volatile unsigned short tx_seg; /* W Tx segment */
+ volatile unsigned short tx_head; /* W Tx buffer head offset */
+ volatile unsigned short tx_tail; /* R Tx buffer tail offset */
+ volatile unsigned short tx_max; /* W Tx buffer size - 1 */
+
+ volatile unsigned short rx_seg; /* W Rx segment */
+ volatile unsigned short rx_head; /* W Rx buffer head offset */
+ volatile unsigned short rx_tail; /* R Rx buffer tail offset */
+ volatile unsigned short rx_max; /* W Rx buffer size - 1 */
+
+ volatile unsigned short tx_lw; /* W Tx buffer low water mark */
+ volatile unsigned short rx_lw; /* W Rx buffer low water mark */
+ volatile unsigned short rx_hw; /* W Rx buffer high water mark */
+ volatile unsigned short incr; /* W Increment to next channel */
+
+ volatile unsigned short fepdev; /* U SCC device base address */
+ volatile unsigned short edelay; /* W Exception delay */
+ volatile unsigned short blen; /* W Break length */
+ volatile unsigned short btime; /* U Break complete time */
+
+ volatile unsigned short iflag; /* C UNIX input flags */
+ volatile unsigned short oflag; /* C UNIX output flags */
+ volatile unsigned short cflag; /* C UNIX control flags */
+ volatile unsigned short wfill[13]; /* U Reserved for expansion */
+
+ volatile unsigned char num; /* U Channel number */
+ volatile unsigned char ract; /* U Receiver active counter */
+ volatile unsigned char bstat; /* U Break status bits */
+ volatile unsigned char tbusy; /* W Transmit busy */
+ volatile unsigned char iempty; /* W Transmit empty event enable */
+ volatile unsigned char ilow; /* W Transmit low-water event enable */
+ volatile unsigned char idata; /* W Receive data interrupt enable */
+ volatile unsigned char eflag; /* U Host event flags */
+
+ volatile unsigned char tflag; /* U Transmit flags */
+ volatile unsigned char rflag; /* U Receive flags */
+ volatile unsigned char xmask; /* U Transmit ready flags */
+ volatile unsigned char xval; /* U Transmit ready value */
+ volatile unsigned char m_stat; /* RC Modem status bits */
+ volatile unsigned char m_change; /* U Modem bits which changed */
+ volatile unsigned char m_int; /* W Modem interrupt enable bits */
+ volatile unsigned char m_last; /* U Last modem status */
+
+ volatile unsigned char mtran; /* C Unreported modem trans */
+ volatile unsigned char orun; /* C Buffer overrun occurred */
+ volatile unsigned char astartc; /* W Auxiliary Xon char */
+ volatile unsigned char astopc; /* W Auxiliary Xoff char */
+ volatile unsigned char startc; /* W Xon character */
+ volatile unsigned char stopc; /* W Xoff character */
+ volatile unsigned char vnextc; /* W Vnext character */
+ volatile unsigned char hflow; /* C Software flow control */
+
+ volatile unsigned char fillc; /* U Delay Fill character */
+ volatile unsigned char ochar; /* U Saved output character */
+ volatile unsigned char omask; /* U Output character mask */
+
+ volatile unsigned char bfill[13]; /* U Reserved for expansion */
+
+ volatile unsigned char scc[16]; /* U SCC registers */
+};
+
+
+/************************************************************************
+ * FEP supported functions
+ ************************************************************************/
+#define SRLOW 0xe0 /* Set receive low water */
+#define SRHIGH 0xe1 /* Set receive high water */
+#define FLUSHTX 0xe2 /* Flush transmit buffer */
+#define PAUSETX 0xe3 /* Pause data transmission */
+#define RESUMETX 0xe4 /* Resume data transmission */
+#define SMINT 0xe5 /* Set Modem Interrupt */
+#define SAFLOWC 0xe6 /* Set Aux. flow control chars */
+#define SBREAK 0xe8 /* Send break */
+#define SMODEM 0xe9 /* Set 8530 modem control lines */
+#define SIFLAG 0xea /* Set UNIX iflags */
+#define SFLOWC 0xeb /* Set flow control characters */
+#define STLOW 0xec /* Set transmit low water mark */
+#define RPAUSE 0xee /* Pause recieve */
+#define RRESUME 0xef /* Resume receive */
+#define CHRESET 0xf0 /* Reset Channel */
+#define BUFSETALL 0xf2 /* Set Tx & Rx buffer size avail*/
+#define SOFLAG 0xf3 /* Set UNIX oflags */
+#define SHFLOW 0xf4 /* Set hardware handshake */
+#define SCFLAG 0xf5 /* Set UNIX cflags */
+#define SVNEXT 0xf6 /* Set VNEXT character */
+#define SPINTFC 0xfc /* Reserved */
+#define SCOMMODE 0xfd /* Set RS232/422 mode */
+
+
+/************************************************************************
+ * Modes for SCOMMODE
+ ************************************************************************/
+#define MODE_232 0x00
+#define MODE_422 0x01
+
+
+/************************************************************************
+ * Event flags.
+ ************************************************************************/
+#define IFBREAK 0x01 /* Break received */
+#define IFTLW 0x02 /* Transmit low water */
+#define IFTEM 0x04 /* Transmitter empty */
+#define IFDATA 0x08 /* Receive data present */
+#define IFMODEM 0x20 /* Modem status change */
+
+/************************************************************************
+ * Modem flags
+ ************************************************************************/
+# define DM_RTS 0x02 /* Request to send */
+# define DM_CD 0x80 /* Carrier detect */
+# define DM_DSR 0x20 /* Data set ready */
+# define DM_CTS 0x10 /* Clear to send */
+# define DM_RI 0x40 /* Ring indicator */
+# define DM_DTR 0x01 /* Data terminal ready */
+
+
+#endif
diff --git a/drivers/staging/dgap/dgap_kcompat.h b/drivers/staging/dgap/dgap_kcompat.h
new file mode 100644
index 00000000000..8ebf4b7373b
--- /dev/null
+++ b/drivers/staging/dgap/dgap_kcompat.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2004 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *************************************************************************
+ *
+ * This file is intended to contain all the kernel "differences" between the
+ * various kernels that we support.
+ *
+ *************************************************************************/
+
+#ifndef __DGAP_KCOMPAT_H
+#define __DGAP_KCOMPAT_H
+
+# ifndef KERNEL_VERSION
+# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+# endif
+
+
+#if !defined(TTY_FLIPBUF_SIZE)
+# define TTY_FLIPBUF_SIZE 512
+#endif
+
+
+/* Sparse stuff */
+# ifndef __user
+# define __user
+# define __kernel
+# define __safe
+# define __force
+# define __chk_user_ptr(x) (void)0
+# endif
+
+
+# define PARM_STR(VAR, INIT, PERM, DESC) \
+ static char *VAR = INIT; \
+ char *dgap_##VAR; \
+ module_param(VAR, charp, PERM); \
+ MODULE_PARM_DESC(VAR, DESC);
+
+# define PARM_INT(VAR, INIT, PERM, DESC) \
+ static int VAR = INIT; \
+ int dgap_##VAR; \
+ module_param(VAR, int, PERM); \
+ MODULE_PARM_DESC(VAR, DESC);
+
+# define PARM_ULONG(VAR, INIT, PERM, DESC) \
+ static ulong VAR = INIT; \
+ ulong dgap_##VAR; \
+ module_param(VAR, long, PERM); \
+ MODULE_PARM_DESC(VAR, DESC);
+
+
+
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+
+
+
+
+/* NOTHING YET */
+
+
+
+
+# else
+
+
+
+# error "this driver does not support anything below the 2.6.27 kernel series."
+
+
+
+# endif
+
+#endif /* ! __DGAP_KCOMPAT_H */
diff --git a/drivers/staging/dgap/dgap_parse.c b/drivers/staging/dgap/dgap_parse.c
new file mode 100644
index 00000000000..5497e6de060
--- /dev/null
+++ b/drivers/staging/dgap/dgap_parse.c
@@ -0,0 +1,1371 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ *
+ *****************************************************************************
+ *
+ * dgap_parse.c - Parses the configuration information from the input file.
+ *
+ * $Id: dgap_parse.c,v 1.1 2009/10/23 14:01:57 markh Exp $
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+
+#include "dgap_types.h"
+#include "dgap_fep5.h"
+#include "dgap_driver.h"
+#include "dgap_conf.h"
+
+
+/*
+ * Function prototypes.
+ */
+static int dgap_gettok(char **in, struct cnode *p);
+static char *dgap_getword(char **in);
+static char *dgap_savestring(char *s);
+static struct cnode *dgap_newnode(int t);
+static int dgap_checknode(struct cnode *p);
+static void dgap_err(char *s);
+
+/*
+ * Our needed internal static variables...
+ */
+static struct cnode dgap_head;
+#define MAXCWORD 200
+static char dgap_cword[MAXCWORD];
+
+struct toklist {
+ int token;
+ char *string;
+};
+
+static struct toklist dgap_tlist[] = {
+ { BEGIN, "config_begin" },
+ { END, "config_end" },
+ { BOARD, "board" },
+ { PCX, "Digi_AccelePort_C/X_PCI" }, /* C/X_PCI */
+ { PEPC, "Digi_AccelePort_EPC/X_PCI" }, /* EPC/X_PCI */
+ { PPCM, "Digi_AccelePort_Xem_PCI" }, /* PCI/Xem */
+ { APORT2_920P, "Digi_AccelePort_2r_920_PCI" },
+ { APORT4_920P, "Digi_AccelePort_4r_920_PCI" },
+ { APORT8_920P, "Digi_AccelePort_8r_920_PCI" },
+ { PAPORT4, "Digi_AccelePort_4r_PCI(EIA-232/RS-422)" },
+ { PAPORT8, "Digi_AccelePort_8r_PCI(EIA-232/RS-422)" },
+ { IO, "io" },
+ { PCIINFO, "pciinfo" },
+ { LINE, "line" },
+ { CONC, "conc" },
+ { CONC, "concentrator" },
+ { CX, "cx" },
+ { CX, "ccon" },
+ { EPC, "epccon" },
+ { EPC, "epc" },
+ { MOD, "module" },
+ { ID, "id" },
+ { STARTO, "start" },
+ { SPEED, "speed" },
+ { CABLE, "cable" },
+ { CONNECT, "connect" },
+ { METHOD, "method" },
+ { STATUS, "status" },
+ { CUSTOM, "Custom" },
+ { BASIC, "Basic" },
+ { MEM, "mem" },
+ { MEM, "memory" },
+ { PORTS, "ports" },
+ { MODEM, "modem" },
+ { NPORTS, "nports" },
+ { TTYN, "ttyname" },
+ { CU, "cuname" },
+ { PRINT, "prname" },
+ { CMAJOR, "major" },
+ { ALTPIN, "altpin" },
+ { USEINTR, "useintr" },
+ { TTSIZ, "ttysize" },
+ { CHSIZ, "chsize" },
+ { BSSIZ, "boardsize" },
+ { UNTSIZ, "schedsize" },
+ { F2SIZ, "f2200size" },
+ { VPSIZ, "vpixsize" },
+ { 0, NULL }
+};
+
+
+/*
+ * Parse a configuration file read into memory as a string.
+ */
+int dgap_parsefile(char **in, int Remove)
+{
+ struct cnode *p, *brd, *line, *conc;
+ int rc;
+ char *s = NULL, *s2 = NULL;
+ int linecnt = 0;
+
+ p = &dgap_head;
+ brd = line = conc = NULL;
+
+ /* perhaps we are adding to an existing list? */
+ while (p->next != NULL) {
+ p = p->next;
+ }
+
+ /* file must start with a BEGIN */
+ while ( (rc = dgap_gettok(in,p)) != BEGIN ) {
+ if (rc == 0) {
+ dgap_err("unexpected EOF");
+ return(-1);
+ }
+ }
+
+ for (; ; ) {
+ rc = dgap_gettok(in,p);
+ if (rc == 0) {
+ dgap_err("unexpected EOF");
+ return(-1);
+ }
+
+ switch (rc) {
+ case 0:
+ dgap_err("unexpected end of file");
+ return(-1);
+
+ case BEGIN: /* should only be 1 begin */
+ dgap_err("unexpected config_begin\n");
+ return(-1);
+
+ case END:
+ return(0);
+
+ case BOARD: /* board info */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(BNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+
+ p->u.board.status = dgap_savestring("No");
+ line = conc = NULL;
+ brd = p;
+ linecnt = -1;
+ break;
+
+ case APORT2_920P: /* AccelePort_4 */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_2r_920 string");
+ return(-1);
+ }
+ p->u.board.type = APORT2_920P;
+ p->u.board.v_type = 1;
+ DPR_INIT(("Adding Digi_2r_920 PCI to config...\n"));
+ break;
+
+ case APORT4_920P: /* AccelePort_4 */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_4r_920 string");
+ return(-1);
+ }
+ p->u.board.type = APORT4_920P;
+ p->u.board.v_type = 1;
+ DPR_INIT(("Adding Digi_4r_920 PCI to config...\n"));
+ break;
+
+ case APORT8_920P: /* AccelePort_8 */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_8r_920 string");
+ return(-1);
+ }
+ p->u.board.type = APORT8_920P;
+ p->u.board.v_type = 1;
+ DPR_INIT(("Adding Digi_8r_920 PCI to config...\n"));
+ break;
+
+ case PAPORT4: /* AccelePort_4 PCI */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_4r(PCI) string");
+ return(-1);
+ }
+ p->u.board.type = PAPORT4;
+ p->u.board.v_type = 1;
+ DPR_INIT(("Adding Digi_4r PCI to config...\n"));
+ break;
+
+ case PAPORT8: /* AccelePort_8 PCI */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_8r string");
+ return(-1);
+ }
+ p->u.board.type = PAPORT8;
+ p->u.board.v_type = 1;
+ DPR_INIT(("Adding Digi_8r PCI to config...\n"));
+ break;
+
+ case PCX: /* PCI C/X */
+ if (p->type != BNODE) {
+ dgap_err("unexpected Digi_C/X_(PCI) string");
+ return(-1);
+ }
+ p->u.board.type = PCX;
+ p->u.board.v_type = 1;
+ p->u.board.conc1 = 0;
+ p->u.board.conc2 = 0;
+ p->u.board.module1 = 0;
+ p->u.board.module2 = 0;
+ DPR_INIT(("Adding PCI C/X to config...\n"));
+ break;
+
+ case PEPC: /* PCI EPC/X */
+ if (p->type != BNODE) {
+ dgap_err("unexpected \"Digi_EPC/X_(PCI)\" string");
+ return(-1);
+ }
+ p->u.board.type = PEPC;
+ p->u.board.v_type = 1;
+ p->u.board.conc1 = 0;
+ p->u.board.conc2 = 0;
+ p->u.board.module1 = 0;
+ p->u.board.module2 = 0;
+ DPR_INIT(("Adding PCI EPC/X to config...\n"));
+ break;
+
+ case PPCM: /* PCI/Xem */
+ if (p->type != BNODE) {
+ dgap_err("unexpected PCI/Xem string");
+ return(-1);
+ }
+ p->u.board.type = PPCM;
+ p->u.board.v_type = 1;
+ p->u.board.conc1 = 0;
+ p->u.board.conc2 = 0;
+ DPR_INIT(("Adding PCI XEM to config...\n"));
+ break;
+
+ case IO: /* i/o port */
+ if (p->type != BNODE) {
+ dgap_err("IO port only vaild for boards");
+ return(-1);
+ }
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.board.portstr = dgap_savestring(s);
+ p->u.board.port = (short)simple_strtol(s, &s2, 0);
+ if ((short)strlen(s) > (short)(s2 - s)) {
+ dgap_err("bad number for IO port");
+ return(-1);
+ }
+ p->u.board.v_port = 1;
+ DPR_INIT(("Adding IO (%s) to config...\n", s));
+ break;
+
+ case MEM: /* memory address */
+ if (p->type != BNODE) {
+ dgap_err("memory address only vaild for boards");
+ return(-1);
+ }
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.board.addrstr = dgap_savestring(s);
+ p->u.board.addr = simple_strtoul(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for memory address");
+ return(-1);
+ }
+ p->u.board.v_addr = 1;
+ DPR_INIT(("Adding MEM (%s) to config...\n", s));
+ break;
+
+ case PCIINFO: /* pci information */
+ if (p->type != BNODE) {
+ dgap_err("memory address only vaild for boards");
+ return(-1);
+ }
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.board.pcibusstr = dgap_savestring(s);
+ p->u.board.pcibus = simple_strtoul(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for pci bus");
+ return(-1);
+ }
+ p->u.board.v_pcibus = 1;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.board.pcislotstr = dgap_savestring(s);
+ p->u.board.pcislot = simple_strtoul(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for pci slot");
+ return(-1);
+ }
+ p->u.board.v_pcislot = 1;
+
+ DPR_INIT(("Adding PCIINFO (%s %s) to config...\n", p->u.board.pcibusstr,
+ p->u.board.pcislotstr));
+ break;
+
+ case METHOD:
+ if (p->type != BNODE) {
+ dgap_err("install method only vaild for boards");
+ return(-1);
+ }
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.board.method = dgap_savestring(s);
+ p->u.board.v_method = 1;
+ DPR_INIT(("Adding METHOD (%s) to config...\n", s));
+ break;
+
+ case STATUS:
+ if (p->type != BNODE) {
+ dgap_err("config status only vaild for boards");
+ return(-1);
+ }
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.board.status = dgap_savestring(s);
+ DPR_INIT(("Adding STATUS (%s) to config...\n", s));
+ break;
+
+ case NPORTS: /* number of ports */
+ if (p->type == BNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.board.nport = (char)simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for number of ports");
+ return(-1);
+ }
+ p->u.board.v_nport = 1;
+ } else if (p->type == CNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.conc.nport = (char)simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for number of ports");
+ return(-1);
+ }
+ p->u.conc.v_nport = 1;
+ } else if (p->type == MNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.module.nport = (char)simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for number of ports");
+ return(-1);
+ }
+ p->u.module.v_nport = 1;
+ } else {
+ dgap_err("nports only valid for concentrators or modules");
+ return(-1);
+ }
+ DPR_INIT(("Adding NPORTS (%s) to config...\n", s));
+ break;
+
+ case ID: /* letter ID used in tty name */
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+
+ p->u.board.status = dgap_savestring(s);
+
+ if (p->type == CNODE) {
+ p->u.conc.id = dgap_savestring(s);
+ p->u.conc.v_id = 1;
+ } else if (p->type == MNODE) {
+ p->u.module.id = dgap_savestring(s);
+ p->u.module.v_id = 1;
+ } else {
+ dgap_err("id only valid for concentrators or modules");
+ return(-1);
+ }
+ DPR_INIT(("Adding ID (%s) to config...\n", s));
+ break;
+
+ case STARTO: /* start offset of ID */
+ if (p->type == BNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.board.start = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for start of tty count");
+ return(-1);
+ }
+ p->u.board.v_start = 1;
+ } else if (p->type == CNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.conc.start = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for start of tty count");
+ return(-1);
+ }
+ p->u.conc.v_start = 1;
+ } else if (p->type == MNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.module.start = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for start of tty count");
+ return(-1);
+ }
+ p->u.module.v_start = 1;
+ } else {
+ dgap_err("start only valid for concentrators or modules");
+ return(-1);
+ }
+ DPR_INIT(("Adding START (%s) to config...\n", s));
+ break;
+
+ case TTYN: /* tty name prefix */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(TNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ if ( (s = dgap_getword(in)) == NULL ) {
+ dgap_err("unexpeced end of file");
+ return(-1);
+ }
+ if ( (p->u.ttyname = dgap_savestring(s)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ DPR_INIT(("Adding TTY (%s) to config...\n", s));
+ break;
+
+ case CU: /* cu name prefix */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(CUNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ if ( (s = dgap_getword(in)) == NULL ) {
+ dgap_err("unexpeced end of file");
+ return(-1);
+ }
+ if ( (p->u.cuname = dgap_savestring(s)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ DPR_INIT(("Adding CU (%s) to config...\n", s));
+ break;
+
+ case LINE: /* line information */
+ if (dgap_checknode(p))
+ return(-1);
+ if (brd == NULL) {
+ dgap_err("must specify board before line info");
+ return(-1);
+ }
+ switch (brd->u.board.type) {
+ case PPCM:
+ dgap_err("line not vaild for PC/em");
+ return(-1);
+ }
+ if ( (p->next = dgap_newnode(LNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ conc = NULL;
+ line = p;
+ linecnt++;
+ DPR_INIT(("Adding LINE to config...\n"));
+ break;
+
+ case CONC: /* concentrator information */
+ if (dgap_checknode(p))
+ return(-1);
+ if (line == NULL) {
+ dgap_err("must specify line info before concentrator");
+ return(-1);
+ }
+ if ( (p->next = dgap_newnode(CNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ conc = p;
+ if (linecnt)
+ brd->u.board.conc2++;
+ else
+ brd->u.board.conc1++;
+
+ DPR_INIT(("Adding CONC to config...\n"));
+ break;
+
+ case CX: /* c/x type concentrator */
+ if (p->type != CNODE) {
+ dgap_err("cx only valid for concentrators");
+ return(-1);
+ }
+ p->u.conc.type = CX;
+ p->u.conc.v_type = 1;
+ DPR_INIT(("Adding CX to config...\n"));
+ break;
+
+ case EPC: /* epc type concentrator */
+ if (p->type != CNODE) {
+ dgap_err("cx only valid for concentrators");
+ return(-1);
+ }
+ p->u.conc.type = EPC;
+ p->u.conc.v_type = 1;
+ DPR_INIT(("Adding EPC to config...\n"));
+ break;
+
+ case MOD: /* EBI module */
+ if (dgap_checknode(p))
+ return(-1);
+ if (brd == NULL) {
+ dgap_err("must specify board info before EBI modules");
+ return(-1);
+ }
+ switch (brd->u.board.type) {
+ case PPCM:
+ linecnt = 0;
+ break;
+ default:
+ if (conc == NULL) {
+ dgap_err("must specify concentrator info before EBI module");
+ return(-1);
+ }
+ }
+ if ( (p->next = dgap_newnode(MNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ if (linecnt)
+ brd->u.board.module2++;
+ else
+ brd->u.board.module1++;
+
+ DPR_INIT(("Adding MOD to config...\n"));
+ break;
+
+ case PORTS: /* ports type EBI module */
+ if (p->type != MNODE) {
+ dgap_err("ports only valid for EBI modules");
+ return(-1);
+ }
+ p->u.module.type = PORTS;
+ p->u.module.v_type = 1;
+ DPR_INIT(("Adding PORTS to config...\n"));
+ break;
+
+ case MODEM: /* ports type EBI module */
+ if (p->type != MNODE) {
+ dgap_err("modem only valid for modem modules");
+ return(-1);
+ }
+ p->u.module.type = MODEM;
+ p->u.module.v_type = 1;
+ DPR_INIT(("Adding MODEM to config...\n"));
+ break;
+
+ case CABLE:
+ if (p->type == LNODE) {
+ if ((s = dgap_getword(in)) == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.line.cable = dgap_savestring(s);
+ p->u.line.v_cable = 1;
+ }
+ DPR_INIT(("Adding CABLE (%s) to config...\n", s));
+ break;
+
+ case SPEED: /* sync line speed indication */
+ if (p->type == LNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.line.speed = (char)simple_strtol(s, &s2, 0);
+ if ((short)strlen(s) > (short)(s2 - s)) {
+ dgap_err("bad number for line speed");
+ return(-1);
+ }
+ p->u.line.v_speed = 1;
+ } else if (p->type == CNODE) {
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.conc.speed = (char)simple_strtol(s, &s2, 0);
+ if ((short)strlen(s) > (short)(s2 - s)) {
+ dgap_err("bad number for line speed");
+ return(-1);
+ }
+ p->u.conc.v_speed = 1;
+ } else {
+ dgap_err("speed valid only for lines or concentrators.");
+ return(-1);
+ }
+ DPR_INIT(("Adding SPEED (%s) to config...\n", s));
+ break;
+
+ case CONNECT:
+ if (p->type == CNODE) {
+ if ((s = dgap_getword(in)) == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.conc.connect = dgap_savestring(s);
+ p->u.conc.v_connect = 1;
+ }
+ DPR_INIT(("Adding CONNECT (%s) to config...\n", s));
+ break;
+ case PRINT: /* transparent print name prefix */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(PNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ if ( (s = dgap_getword(in)) == NULL ) {
+ dgap_err("unexpeced end of file");
+ return(-1);
+ }
+ if ( (p->u.printname = dgap_savestring(s)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ DPR_INIT(("Adding PRINT (%s) to config...\n", s));
+ break;
+
+ case CMAJOR: /* major number */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(JNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.majornumber = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for major number");
+ return(-1);
+ }
+ DPR_INIT(("Adding CMAJOR (%s) to config...\n", s));
+ break;
+
+ case ALTPIN: /* altpin setting */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(ANODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.altpin = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for altpin");
+ return(-1);
+ }
+ DPR_INIT(("Adding ALTPIN (%s) to config...\n", s));
+ break;
+
+ case USEINTR: /* enable interrupt setting */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(INTRNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.useintr = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for useintr");
+ return(-1);
+ }
+ DPR_INIT(("Adding USEINTR (%s) to config...\n", s));
+ break;
+
+ case TTSIZ: /* size of tty structure */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(TSNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.ttysize = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for ttysize");
+ return(-1);
+ }
+ DPR_INIT(("Adding TTSIZ (%s) to config...\n", s));
+ break;
+
+ case CHSIZ: /* channel structure size */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(CSNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.chsize = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for chsize");
+ return(-1);
+ }
+ DPR_INIT(("Adding CHSIZE (%s) to config...\n", s));
+ break;
+
+ case BSSIZ: /* board structure size */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(BSNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.bssize = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for bssize");
+ return(-1);
+ }
+ DPR_INIT(("Adding BSSIZ (%s) to config...\n", s));
+ break;
+
+ case UNTSIZ: /* sched structure size */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(USNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.unsize = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for schedsize");
+ return(-1);
+ }
+ DPR_INIT(("Adding UNTSIZ (%s) to config...\n", s));
+ break;
+
+ case F2SIZ: /* f2200 structure size */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(FSNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.f2size = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for f2200size");
+ return(-1);
+ }
+ DPR_INIT(("Adding F2SIZ (%s) to config...\n", s));
+ break;
+
+ case VPSIZ: /* vpix structure size */
+ if (dgap_checknode(p))
+ return(-1);
+ if ( (p->next = dgap_newnode(VSNODE)) == NULL ) {
+ dgap_err("out of memory");
+ return(-1);
+ }
+ p = p->next;
+ s = dgap_getword(in);
+ if (s == NULL) {
+ dgap_err("unexpected end of file");
+ return(-1);
+ }
+ p->u.vpixsize = simple_strtol(s, &s2, 0);
+ if ((int)strlen(s) > (int)(s2 - s)) {
+ dgap_err("bad number for vpixsize");
+ return(-1);
+ }
+ DPR_INIT(("Adding VPSIZ (%s) to config...\n", s));
+ break;
+ }
+ }
+}
+
+
+/*
+ * dgap_sindex: much like index(), but it looks for a match of any character in
+ * the group, and returns that position. If the first character is a ^, then
+ * this will match the first occurence not in that group.
+ */
+static char *dgap_sindex (char *string, char *group)
+{
+ char *ptr;
+
+ if (!string || !group)
+ return (char *) NULL;
+
+ if (*group == '^') {
+ group++;
+ for (; *string; string++) {
+ for (ptr = group; *ptr; ptr++) {
+ if (*ptr == *string)
+ break;
+ }
+ if (*ptr == '\0')
+ return string;
+ }
+ }
+ else {
+ for (; *string; string++) {
+ for (ptr = group; *ptr; ptr++) {
+ if (*ptr == *string)
+ return string;
+ }
+ }
+ }
+
+ return (char *) NULL;
+}
+
+
+/*
+ * Get a token from the input file; return 0 if end of file is reached
+ */
+static int dgap_gettok(char **in, struct cnode *p)
+{
+ char *w;
+ struct toklist *t;
+
+ if (strstr(dgap_cword, "boar")) {
+ w = dgap_getword(in);
+ snprintf(dgap_cword, MAXCWORD, "%s", w);
+ for (t = dgap_tlist; t->token != 0; t++) {
+ if ( !strcmp(w, t->string)) {
+ return(t->token);
+ }
+ }
+ dgap_err("board !!type not specified");
+ return(1);
+ }
+ else {
+ while ( (w = dgap_getword(in)) != NULL ) {
+ snprintf(dgap_cword, MAXCWORD, "%s", w);
+ for (t = dgap_tlist; t->token != 0; t++) {
+ if ( !strcmp(w, t->string) )
+ return(t->token);
+ }
+ }
+ return(0);
+ }
+}
+
+
+/*
+ * get a word from the input stream, also keep track of current line number.
+ * words are separated by whitespace.
+ */
+static char *dgap_getword(char **in)
+{
+ char *ret_ptr = *in;
+
+ char *ptr = dgap_sindex(*in, " \t\n");
+
+ /* If no word found, return null */
+ if (!ptr)
+ return NULL;
+
+ /* Mark new location for our buffer */
+ *ptr = '\0';
+ *in = ptr + 1;
+
+ /* Eat any extra spaces/tabs/newlines that might be present */
+ while (*in && **in && ((**in == ' ') || (**in == '\t') || (**in == '\n'))) {
+ **in = '\0';
+ *in = *in + 1;
+ }
+
+ return ret_ptr;
+}
+
+
+/*
+ * print an error message, giving the line number in the file where
+ * the error occurred.
+ */
+static void dgap_err(char *s)
+{
+ printk("DGAP: parse: %s\n", s);
+}
+
+
+/*
+ * allocate a new configuration node of type t
+ */
+static struct cnode *dgap_newnode(int t)
+{
+ struct cnode *n;
+ if ( (n = (struct cnode *) kmalloc(sizeof(struct cnode ), GFP_ATOMIC) ) != NULL) {
+ memset( (char *)n, 0, sizeof(struct cnode ) );
+ n->type = t;
+ }
+ return(n);
+}
+
+
+/*
+ * dgap_checknode: see if all the necessary info has been supplied for a node
+ * before creating the next node.
+ */
+static int dgap_checknode(struct cnode *p)
+{
+ switch (p->type) {
+ case BNODE:
+ if (p->u.board.v_type == 0) {
+ dgap_err("board type !not specified");
+ return(1);
+ }
+
+ return(0);
+
+ case LNODE:
+ if (p->u.line.v_speed == 0) {
+ dgap_err("line speed not specified");
+ return(1);
+ }
+ return(0);
+
+ case CNODE:
+ if (p->u.conc.v_type == 0) {
+ dgap_err("concentrator type not specified");
+ return(1);
+ }
+ if (p->u.conc.v_speed == 0) {
+ dgap_err("concentrator line speed not specified");
+ return(1);
+ }
+ if (p->u.conc.v_nport == 0) {
+ dgap_err("number of ports on concentrator not specified");
+ return(1);
+ }
+ if (p->u.conc.v_id == 0) {
+ dgap_err("concentrator id letter not specified");
+ return(1);
+ }
+ return(0);
+
+ case MNODE:
+ if (p->u.module.v_type == 0) {
+ dgap_err("EBI module type not specified");
+ return(1);
+ }
+ if (p->u.module.v_nport == 0) {
+ dgap_err("number of ports on EBI module not specified");
+ return(1);
+ }
+ if (p->u.module.v_id == 0) {
+ dgap_err("EBI module id letter not specified");
+ return(1);
+ }
+ return(0);
+ }
+ return(0);
+}
+
+/*
+ * save a string somewhere
+ */
+static char *dgap_savestring(char *s)
+{
+ char *p;
+ if ( (p = kmalloc(strlen(s) + 1, GFP_ATOMIC) ) != NULL) {
+ strcpy(p, s);
+ }
+ return(p);
+}
+
+
+/*
+ * Given a board pointer, returns whether we should use interrupts or not.
+ */
+uint dgap_config_get_useintr(struct board_t *bd)
+{
+ struct cnode *p = NULL;
+
+ if (!bd)
+ return(0);
+
+ for (p = bd->bd_config; p; p = p->next) {
+ switch (p->type) {
+ case INTRNODE:
+ /*
+ * check for pcxr types.
+ */
+ return p->u.useintr;
+ default:
+ break;
+ }
+ }
+
+ /* If not found, then don't turn on interrupts. */
+ return 0;
+}
+
+
+/*
+ * Given a board pointer, returns whether we turn on altpin or not.
+ */
+uint dgap_config_get_altpin(struct board_t *bd)
+{
+ struct cnode *p = NULL;
+
+ if (!bd)
+ return(0);
+
+ for (p = bd->bd_config; p; p = p->next) {
+ switch (p->type) {
+ case ANODE:
+ /*
+ * check for pcxr types.
+ */
+ return p->u.altpin;
+ default:
+ break;
+ }
+ }
+
+ /* If not found, then don't turn on interrupts. */
+ return 0;
+}
+
+
+
+/*
+ * Given a specific type of board, if found, detached link and
+ * returns the first occurance in the list.
+ */
+struct cnode *dgap_find_config(int type, int bus, int slot)
+{
+ struct cnode *p, *prev = NULL, *prev2 = NULL, *found = NULL;
+
+ p = &dgap_head;
+
+ while (p->next != NULL) {
+ prev = p;
+ p = p->next;
+
+ if (p->type == BNODE) {
+
+ if (p->u.board.type == type) {
+
+ if (p->u.board.v_pcibus && p->u.board.pcibus != bus) {
+ DPR(("Found matching board, but wrong bus position. System says bus %d, we want bus %ld\n",
+ bus, p->u.board.pcibus));
+ continue;
+ }
+ if (p->u.board.v_pcislot && p->u.board.pcislot != slot) {
+ DPR_INIT(("Found matching board, but wrong slot position. System says slot %d, we want slot %ld\n",
+ slot, p->u.board.pcislot));
+ continue;
+ }
+
+ DPR_INIT(("Matched type in config file\n"));
+
+ found = p;
+ /*
+ * Keep walking thru the list till we find the next board.
+ */
+ while (p->next != NULL) {
+ prev2 = p;
+ p = p->next;
+ if (p->type == BNODE) {
+
+ /*
+ * Mark the end of our 1 board chain of configs.
+ */
+ prev2->next = NULL;
+
+ /*
+ * Link the "next" board to the previous board,
+ * effectively "unlinking" our board from the main config.
+ */
+ prev->next = p;
+
+ return found;
+ }
+ }
+ /*
+ * It must be the last board in the list.
+ */
+ prev->next = NULL;
+ return found;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Given a board pointer, walks the config link, counting up
+ * all ports user specified should be on the board.
+ * (This does NOT mean they are all actually present right now tho)
+ */
+uint dgap_config_get_number_of_ports(struct board_t *bd)
+{
+ int count = 0;
+ struct cnode *p = NULL;
+
+ if (!bd)
+ return(0);
+
+ for (p = bd->bd_config; p; p = p->next) {
+
+ switch (p->type) {
+ case BNODE:
+ /*
+ * check for pcxr types.
+ */
+ if (p->u.board.type > EPCFE)
+ count += p->u.board.nport;
+ break;
+ case CNODE:
+ count += p->u.conc.nport;
+ break;
+ case MNODE:
+ count += p->u.module.nport;
+ break;
+ }
+ }
+ return (count);
+}
+
+char *dgap_create_config_string(struct board_t *bd, char *string)
+{
+ char *ptr = string;
+ struct cnode *p = NULL;
+ struct cnode *q = NULL;
+ int speed;
+
+ if (!bd) {
+ *ptr = 0xff;
+ return string;
+ }
+
+ for (p = bd->bd_config; p; p = p->next) {
+
+ switch (p->type) {
+ case LNODE:
+ *ptr = '\0';
+ ptr++;
+ *ptr = p->u.line.speed;
+ ptr++;
+ break;
+ case CNODE:
+ /*
+ * Because the EPC/con concentrators can have EM modules
+ * hanging off of them, we have to walk ahead in the list
+ * and keep adding the number of ports on each EM to the config.
+ * UGH!
+ */
+ speed = p->u.conc.speed;
+ q = p->next;
+ if ((q != NULL) && (q->type == MNODE) ) {
+ *ptr = (p->u.conc.nport + 0x80);
+ ptr++;
+ p = q;
+ while ((q->next != NULL) && (q->next->type) == MNODE) {
+ *ptr = (q->u.module.nport + 0x80);
+ ptr++;
+ p = q;
+ q = q->next;
+ }
+ *ptr = q->u.module.nport;
+ ptr++;
+ } else {
+ *ptr = p->u.conc.nport;
+ ptr++;
+ }
+
+ *ptr = speed;
+ ptr++;
+ break;
+ }
+ }
+
+ *ptr = 0xff;
+ return string;
+}
+
+
+
+char *dgap_get_config_letters(struct board_t *bd, char *string)
+{
+ int found = FALSE;
+ char *ptr = string;
+ struct cnode *cptr = NULL;
+ int len = 0;
+ int left = MAXTTYNAMELEN;
+
+ if (!bd) {
+ return "<NULL>";
+ }
+
+ for (cptr = bd->bd_config; cptr; cptr = cptr->next) {
+
+ if ((cptr->type == BNODE) &&
+ ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) ||
+ (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) ||
+ (cptr->u.board.type == PAPORT8))) {
+
+ found = TRUE;
+ }
+
+ if (cptr->type == TNODE && found == TRUE) {
+ char *ptr1;
+ if (strstr(cptr->u.ttyname, "tty")) {
+ ptr1 = cptr->u.ttyname;
+ ptr1 += 3;
+ }
+ else {
+ ptr1 = cptr->u.ttyname;
+ }
+ if (ptr1) {
+ len = snprintf(ptr, left, "%s", ptr1);
+ left -= len;
+ ptr += len;
+ if (left <= 0)
+ break;
+ }
+ }
+
+ if (cptr->type == CNODE) {
+ if (cptr->u.conc.id) {
+ len = snprintf(ptr, left, "%s", cptr->u.conc.id);
+ left -= len;
+ ptr += len;
+ if (left <= 0)
+ break;
+ }
+ }
+
+ if (cptr->type == MNODE) {
+ if (cptr->u.module.id) {
+ len = snprintf(ptr, left, "%s", cptr->u.module.id);
+ left -= len;
+ ptr += len;
+ if (left <= 0)
+ break;
+ }
+ }
+ }
+
+ return string;
+}
diff --git a/drivers/staging/dgap/dgap_parse.h b/drivers/staging/dgap/dgap_parse.h
new file mode 100644
index 00000000000..8128c47343c
--- /dev/null
+++ b/drivers/staging/dgap/dgap_parse.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef _DGAP_PARSE_H
+#define _DGAP_PARSE_H
+
+#include "dgap_driver.h"
+
+extern int dgap_parsefile(char **in, int Remove);
+extern struct cnode *dgap_find_config(int type, int bus, int slot);
+extern uint dgap_config_get_number_of_ports(struct board_t *bd);
+extern char *dgap_create_config_string(struct board_t *bd, char *string);
+extern char *dgap_get_config_letters(struct board_t *bd, char *string);
+extern uint dgap_config_get_useintr(struct board_t *bd);
+extern uint dgap_config_get_altpin(struct board_t *bd);
+
+#endif
diff --git a/drivers/staging/dgap/dgap_pci.h b/drivers/staging/dgap/dgap_pci.h
new file mode 100644
index 00000000000..05ed374f08e
--- /dev/null
+++ b/drivers/staging/dgap/dgap_pci.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+/* $Id: dgap_pci.h,v 1.1 2009/10/23 14:01:57 markh Exp $ */
+
+#ifndef __DGAP_PCI_H
+#define __DGAP_PCI_H
+
+#define PCIMAX 32 /* maximum number of PCI boards */
+
+#define DIGI_VID 0x114F
+
+#define PCI_DEVICE_EPC_DID 0x0002
+#define PCI_DEVICE_XEM_DID 0x0004
+#define PCI_DEVICE_XR_DID 0x0005
+#define PCI_DEVICE_CX_DID 0x0006
+#define PCI_DEVICE_XRJ_DID 0x0009 /* PLX-based Xr adapter */
+#define PCI_DEVICE_XR_IBM_DID 0x0011 /* IBM 8-port Async Adapter */
+#define PCI_DEVICE_XR_BULL_DID 0x0013 /* BULL 8-port Async Adapter */
+#define PCI_DEVICE_XR_SAIP_DID 0x001c /* SAIP card - Xr adapter */
+#define PCI_DEVICE_XR_422_DID 0x0012 /* Xr-422 */
+#define PCI_DEVICE_920_2_DID 0x0034 /* XR-Plus 920 K, 2 port */
+#define PCI_DEVICE_920_4_DID 0x0026 /* XR-Plus 920 K, 4 port */
+#define PCI_DEVICE_920_8_DID 0x0027 /* XR-Plus 920 K, 8 port */
+#define PCI_DEVICE_EPCJ_DID 0x000a /* PLX 9060 chip for PCI */
+#define PCI_DEVICE_CX_IBM_DID 0x001b /* IBM 128-port Async Adapter */
+#define PCI_DEVICE_920_8_HP_DID 0x0058 /* HP XR-Plus 920 K, 8 port */
+#define PCI_DEVICE_XEM_HP_DID 0x0059 /* HP Xem PCI */
+
+#define PCI_DEVICE_XEM_NAME "AccelePort XEM"
+#define PCI_DEVICE_CX_NAME "AccelePort CX"
+#define PCI_DEVICE_XR_NAME "AccelePort Xr"
+#define PCI_DEVICE_XRJ_NAME "AccelePort Xr (PLX)"
+#define PCI_DEVICE_XR_SAIP_NAME "AccelePort Xr (SAIP)"
+#define PCI_DEVICE_920_2_NAME "AccelePort Xr920 2 port"
+#define PCI_DEVICE_920_4_NAME "AccelePort Xr920 4 port"
+#define PCI_DEVICE_920_8_NAME "AccelePort Xr920 8 port"
+#define PCI_DEVICE_XR_422_NAME "AccelePort Xr 422"
+#define PCI_DEVICE_EPCJ_NAME "AccelePort EPC (PLX)"
+#define PCI_DEVICE_XR_BULL_NAME "AccelePort Xr (BULL)"
+#define PCI_DEVICE_XR_IBM_NAME "AccelePort Xr (IBM)"
+#define PCI_DEVICE_CX_IBM_NAME "AccelePort CX (IBM)"
+#define PCI_DEVICE_920_8_HP_NAME "AccelePort Xr920 8 port (HP)"
+#define PCI_DEVICE_XEM_HP_NAME "AccelePort XEM (HP)"
+
+
+/*
+ * On the PCI boards, there is no IO space allocated
+ * The I/O registers will be in the first 3 bytes of the
+ * upper 2MB of the 4MB memory space. The board memory
+ * will be mapped into the low 2MB of the 4MB memory space
+ */
+
+/* Potential location of PCI Bios from E0000 to FFFFF*/
+#define PCI_BIOS_SIZE 0x00020000
+
+/* Size of Memory and I/O for PCI (4MB) */
+#define PCI_RAM_SIZE 0x00400000
+
+/* Size of Memory (2MB) */
+#define PCI_MEM_SIZE 0x00200000
+
+/* Max PCI Window Size (2MB) */
+#define PCI_WIN_SIZE 0x00200000
+
+#define PCI_WIN_SHIFT 21 /* 21 bits max */
+
+/* Offset of I/0 in Memory (2MB) */
+#define PCI_IO_OFFSET 0x00200000
+
+/* Size of IO (2MB) */
+#define PCI_IO_SIZE 0x00200000
+
+#endif
diff --git a/drivers/staging/dgap/dgap_sysfs.c b/drivers/staging/dgap/dgap_sysfs.c
new file mode 100644
index 00000000000..94da06fcf7e
--- /dev/null
+++ b/drivers/staging/dgap/dgap_sysfs.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright 2004 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ *
+ *
+ * $Id: dgap_sysfs.c,v 1.1 2009/10/23 14:01:57 markh Exp $
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/serial_reg.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+
+#include "dgap_driver.h"
+#include "dgap_conf.h"
+#include "dgap_parse.h"
+
+
+static ssize_t dgap_driver_version_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART);
+}
+static DRIVER_ATTR(version, S_IRUSR, dgap_driver_version_show, NULL);
+
+
+static ssize_t dgap_driver_boards_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", dgap_NumBoards);
+}
+static DRIVER_ATTR(boards, S_IRUSR, dgap_driver_boards_show, NULL);
+
+
+static ssize_t dgap_driver_maxboards_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS);
+}
+static DRIVER_ATTR(maxboards, S_IRUSR, dgap_driver_maxboards_show, NULL);
+
+
+static ssize_t dgap_driver_pollcounter_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%ld\n", dgap_poll_counter);
+}
+static DRIVER_ATTR(pollcounter, S_IRUSR, dgap_driver_pollcounter_show, NULL);
+
+
+static ssize_t dgap_driver_state_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", dgap_driver_state_text[dgap_driver_state]);
+}
+static DRIVER_ATTR(state, S_IRUSR, dgap_driver_state_show, NULL);
+
+
+static ssize_t dgap_driver_debug_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_debug);
+}
+
+static ssize_t dgap_driver_debug_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+ sscanf(buf, "0x%x\n", &dgap_debug);
+ return count;
+}
+static DRIVER_ATTR(debug, (S_IRUSR | S_IWUSR), dgap_driver_debug_show, dgap_driver_debug_store);
+
+
+static ssize_t dgap_driver_rawreadok_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_rawreadok);
+}
+
+static ssize_t dgap_driver_rawreadok_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+ sscanf(buf, "0x%x\n", &dgap_rawreadok);
+ return count;
+}
+static DRIVER_ATTR(rawreadok, (S_IRUSR | S_IWUSR), dgap_driver_rawreadok_show, dgap_driver_rawreadok_store);
+
+
+static ssize_t dgap_driver_pollrate_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%dms\n", dgap_poll_tick);
+}
+
+static ssize_t dgap_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+ sscanf(buf, "%d\n", &dgap_poll_tick);
+ return count;
+}
+static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgap_driver_pollrate_show, dgap_driver_pollrate_store);
+
+
+void dgap_create_driver_sysfiles(struct pci_driver *dgap_driver)
+{
+ int rc = 0;
+ struct device_driver *driverfs = &dgap_driver->driver;
+
+ rc |= driver_create_file(driverfs, &driver_attr_version);
+ rc |= driver_create_file(driverfs, &driver_attr_boards);
+ rc |= driver_create_file(driverfs, &driver_attr_maxboards);
+ rc |= driver_create_file(driverfs, &driver_attr_debug);
+ rc |= driver_create_file(driverfs, &driver_attr_rawreadok);
+ rc |= driver_create_file(driverfs, &driver_attr_pollrate);
+ rc |= driver_create_file(driverfs, &driver_attr_pollcounter);
+ rc |= driver_create_file(driverfs, &driver_attr_state);
+ if (rc) {
+ printk(KERN_ERR "DGAP: sysfs driver_create_file failed!\n");
+ }
+}
+
+
+void dgap_remove_driver_sysfiles(struct pci_driver *dgap_driver)
+{
+ struct device_driver *driverfs = &dgap_driver->driver;
+ driver_remove_file(driverfs, &driver_attr_version);
+ driver_remove_file(driverfs, &driver_attr_boards);
+ driver_remove_file(driverfs, &driver_attr_maxboards);
+ driver_remove_file(driverfs, &driver_attr_debug);
+ driver_remove_file(driverfs, &driver_attr_rawreadok);
+ driver_remove_file(driverfs, &driver_attr_pollrate);
+ driver_remove_file(driverfs, &driver_attr_pollcounter);
+ driver_remove_file(driverfs, &driver_attr_state);
+}
+
+
+#define DGAP_VERIFY_BOARD(p, bd) \
+ if (!p) \
+ return (0); \
+ \
+ bd = dev_get_drvdata(p); \
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC) \
+ return (0); \
+ if (bd->state != BOARD_READY) \
+ return (0); \
+
+
+static ssize_t dgap_ports_state_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGAP_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %s\n", bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_open_count ? "Open" : "Closed");
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_state, S_IRUSR, dgap_ports_state_show, NULL);
+
+
+static ssize_t dgap_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGAP_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_baud_info);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_baud, S_IRUSR, dgap_ports_baud_show, NULL);
+
+
+static ssize_t dgap_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGAP_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ if (bd->channels[i]->ch_open_count) {
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum,
+ (bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
+ (bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
+ (bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
+ (bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
+ (bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
+ (bd->channels[i]->ch_mistat & UART_MSR_RI) ? "RI" : "");
+ } else {
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d\n", bd->channels[i]->ch_portnum);
+ }
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_msignals, S_IRUSR, dgap_ports_msignals_show, NULL);
+
+
+static ssize_t dgap_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGAP_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_iflag, S_IRUSR, dgap_ports_iflag_show, NULL);
+
+
+static ssize_t dgap_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGAP_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_cflag, S_IRUSR, dgap_ports_cflag_show, NULL);
+
+
+static ssize_t dgap_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGAP_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_oflag, S_IRUSR, dgap_ports_oflag_show, NULL);
+
+
+static ssize_t dgap_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGAP_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_lflag, S_IRUSR, dgap_ports_lflag_show, NULL);
+
+
+static ssize_t dgap_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGAP_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgap_ports_digi_flag_show, NULL);
+
+
+static ssize_t dgap_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGAP_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgap_ports_rxcount_show, NULL);
+
+
+static ssize_t dgap_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGAP_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_txcount, S_IRUSR, dgap_ports_txcount_show, NULL);
+
+
+/* this function creates the sys files that will export each signal status
+ * to sysfs each value will be put in a separate filename
+ */
+void dgap_create_ports_sysfiles(struct board_t *bd)
+{
+ int rc = 0;
+
+ dev_set_drvdata(&bd->pdev->dev, bd);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
+ if (rc) {
+ printk(KERN_ERR "DGAP: sysfs device_create_file failed!\n");
+ }
+}
+
+
+/* removes all the sys files created for that port */
+void dgap_remove_ports_sysfiles(struct board_t *bd)
+{
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
+}
+
+
+static ssize_t dgap_tty_state_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed");
+}
+static DEVICE_ATTR(state, S_IRUSR, dgap_tty_state_show, NULL);
+
+
+static ssize_t dgap_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_baud_info);
+}
+static DEVICE_ATTR(baud, S_IRUSR, dgap_tty_baud_show, NULL);
+
+
+static ssize_t dgap_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ if (ch->ch_open_count) {
+ return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
+ (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
+ (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
+ (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
+ (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
+ (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
+ (ch->ch_mistat & UART_MSR_RI) ? "RI" : "");
+ }
+ return 0;
+}
+static DEVICE_ATTR(msignals, S_IRUSR, dgap_tty_msignals_show, NULL);
+
+
+static ssize_t dgap_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag);
+}
+static DEVICE_ATTR(iflag, S_IRUSR, dgap_tty_iflag_show, NULL);
+
+
+static ssize_t dgap_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag);
+}
+static DEVICE_ATTR(cflag, S_IRUSR, dgap_tty_cflag_show, NULL);
+
+
+static ssize_t dgap_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag);
+}
+static DEVICE_ATTR(oflag, S_IRUSR, dgap_tty_oflag_show, NULL);
+
+
+static ssize_t dgap_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag);
+}
+static DEVICE_ATTR(lflag, S_IRUSR, dgap_tty_lflag_show, NULL);
+
+
+static ssize_t dgap_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
+}
+static DEVICE_ATTR(digi_flag, S_IRUSR, dgap_tty_digi_flag_show, NULL);
+
+
+static ssize_t dgap_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount);
+}
+static DEVICE_ATTR(rxcount, S_IRUSR, dgap_tty_rxcount_show, NULL);
+
+
+static ssize_t dgap_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount);
+}
+static DEVICE_ATTR(txcount, S_IRUSR, dgap_tty_txcount_show, NULL);
+
+
+static ssize_t dgap_tty_name_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int cn;
+ int bn;
+ struct cnode *cptr = NULL;
+ int found = FALSE;
+ int ncount = 0;
+ int starto = 0;
+ int i = 0;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ bn = bd->boardnum;
+ cn = ch->ch_portnum;
+
+ for (cptr = bd->bd_config; cptr; cptr = cptr->next) {
+
+ if ((cptr->type == BNODE) &&
+ ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) ||
+ (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) ||
+ (cptr->u.board.type == PAPORT8))) {
+
+ found = TRUE;
+ if (cptr->u.board.v_start)
+ starto = cptr->u.board.start;
+ else
+ starto = 1;
+ }
+
+ if (cptr->type == TNODE && found == TRUE) {
+ char *ptr1;
+ if (strstr(cptr->u.ttyname, "tty")) {
+ ptr1 = cptr->u.ttyname;
+ ptr1 += 3;
+ }
+ else {
+ ptr1 = cptr->u.ttyname;
+ }
+
+ for (i = 0; i < dgap_config_get_number_of_ports(bd); i++) {
+ if (cn == i) {
+ return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
+ (un->un_type == DGAP_PRINT) ? "pr" : "tty",
+ ptr1, i + starto);
+ }
+ }
+ }
+
+ if (cptr->type == CNODE) {
+
+ for (i = 0; i < cptr->u.conc.nport; i++) {
+ if (cn == (i + ncount)) {
+
+ return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
+ (un->un_type == DGAP_PRINT) ? "pr" : "tty",
+ cptr->u.conc.id,
+ i + (cptr->u.conc.v_start ? cptr->u.conc.start : 1));
+ }
+ }
+
+ ncount += cptr->u.conc.nport;
+ }
+
+ if (cptr->type == MNODE) {
+
+ for (i = 0; i < cptr->u.module.nport; i++) {
+ if (cn == (i + ncount)) {
+ return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
+ (un->un_type == DGAP_PRINT) ? "pr" : "tty",
+ cptr->u.module.id,
+ i + (cptr->u.module.v_start ? cptr->u.module.start : 1));
+ }
+ }
+
+ ncount += cptr->u.module.nport;
+
+ }
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%s_dgap_%d_%d\n",
+ (un->un_type == DGAP_PRINT) ? "pr" : "tty", bn, cn);
+
+}
+static DEVICE_ATTR(custom_name, S_IRUSR, dgap_tty_name_show, NULL);
+
+
+static struct attribute *dgap_sysfs_tty_entries[] = {
+ &dev_attr_state.attr,
+ &dev_attr_baud.attr,
+ &dev_attr_msignals.attr,
+ &dev_attr_iflag.attr,
+ &dev_attr_cflag.attr,
+ &dev_attr_oflag.attr,
+ &dev_attr_lflag.attr,
+ &dev_attr_digi_flag.attr,
+ &dev_attr_rxcount.attr,
+ &dev_attr_txcount.attr,
+ &dev_attr_custom_name.attr,
+ NULL
+};
+
+
+static struct attribute_group dgap_tty_attribute_group = {
+ .name = NULL,
+ .attrs = dgap_sysfs_tty_entries,
+};
+
+
+
+
+void dgap_create_tty_sysfs(struct un_t *un, struct device *c)
+{
+ int ret;
+
+ ret = sysfs_create_group(&c->kobj, &dgap_tty_attribute_group);
+ if (ret) {
+ printk(KERN_ERR "dgap: failed to create sysfs tty device attributes.\n");
+ sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group);
+ return;
+ }
+
+ dev_set_drvdata(c, un);
+
+}
+
+
+void dgap_remove_tty_sysfs(struct device *c)
+{
+ sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group);
+}
diff --git a/drivers/staging/dgap/dgap_sysfs.h b/drivers/staging/dgap/dgap_sysfs.h
new file mode 100644
index 00000000000..dde690eec5c
--- /dev/null
+++ b/drivers/staging/dgap/dgap_sysfs.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGAP_SYSFS_H
+#define __DGAP_SYSFS_H
+
+#include "dgap_driver.h"
+
+#include <linux/device.h>
+
+struct board_t;
+struct channel_t;
+struct un_t;
+struct pci_driver;
+struct class_device;
+
+extern void dgap_create_ports_sysfiles(struct board_t *bd);
+extern void dgap_remove_ports_sysfiles(struct board_t *bd);
+
+extern void dgap_create_driver_sysfiles(struct pci_driver *);
+extern void dgap_remove_driver_sysfiles(struct pci_driver *);
+
+extern int dgap_tty_class_init(void);
+extern int dgap_tty_class_destroy(void);
+
+extern void dgap_create_tty_sysfs(struct un_t *un, struct device *c);
+extern void dgap_remove_tty_sysfs(struct device *c);
+
+
+#endif
diff --git a/drivers/staging/dgap/dgap_trace.c b/drivers/staging/dgap/dgap_trace.c
new file mode 100644
index 00000000000..0f9a9569ea2
--- /dev/null
+++ b/drivers/staging/dgap/dgap_trace.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ */
+
+/* $Id: dgap_trace.c,v 1.1 2009/10/23 14:01:57 markh Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h> /* For jiffies, task states */
+#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
+#include <linux/vmalloc.h>
+
+#include "dgap_driver.h"
+
+#define TRC_TO_CONSOLE 1
+
+/* file level globals */
+static char *dgap_trcbuf; /* the ringbuffer */
+
+#if defined(TRC_TO_KMEM)
+static int dgap_trcbufi = 0; /* index of the tilde at the end of */
+#endif
+
+extern int dgap_trcbuf_size; /* size of the ringbuffer */
+
+#if defined(TRC_TO_KMEM)
+static DEFINE_SPINLOCK(dgap_tracef_lock);
+#endif
+
+#if 0
+
+#if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE)
+void dgap_tracef(const char *fmt, ...)
+{
+ return;
+}
+
+#else /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
+
+void dgap_tracef(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[TRC_MAXMSG+1];
+ size_t lenbuf;
+ int i;
+ static int failed = FALSE;
+# if defined(TRC_TO_KMEM)
+ unsigned long flags;
+#endif
+
+ if(failed)
+ return;
+# if defined(TRC_TO_KMEM)
+ DGAP_LOCK(dgap_tracef_lock, flags);
+#endif
+
+ /* Format buf using fmt and arguments contained in ap. */
+ va_start(ap, fmt);
+ i = vsprintf(buf, fmt, ap);
+ va_end(ap);
+ lenbuf = strlen(buf);
+
+# if defined(TRC_TO_KMEM)
+ {
+ static int initd=0;
+
+ /*
+ * Now, in addition to (or instead of) printing this stuff out
+ * (which is a buffered operation), also tuck it away into a
+ * corner of memory which can be examined post-crash in kdb.
+ */
+ if (!initd) {
+ dgap_trcbuf = (char *) vmalloc(dgap_trcbuf_size);
+ if(!dgap_trcbuf) {
+ failed = TRUE;
+ printk("dgap: tracing init failed!\n");
+ return;
+ }
+
+ memset(dgap_trcbuf, '\0', dgap_trcbuf_size);
+ dgap_trcbufi = 0;
+ initd++;
+
+ printk("dgap: tracing enabled - " TRC_DTRC
+ " 0x%lx 0x%x\n",
+ (unsigned long)dgap_trcbuf,
+ dgap_trcbuf_size);
+ }
+
+# if defined(TRC_ON_OVERFLOW_WRAP_AROUND)
+ /*
+ * This is the less CPU-intensive way to do things. We simply
+ * wrap around before we fall off the end of the buffer. A
+ * tilde (~) demarcates the current end of the trace.
+ *
+ * This method should be used if you are concerned about race
+ * conditions as it is less likely to affect the timing of
+ * things.
+ */
+
+ if (dgap_trcbufi + lenbuf >= dgap_trcbuf_size) {
+ /* We are wrapping, so wipe out the last tilde. */
+ dgap_trcbuf[dgap_trcbufi] = '\0';
+ /* put the new string at the beginning of the buffer */
+ dgap_trcbufi = 0;
+ }
+
+ strcpy(&dgap_trcbuf[dgap_trcbufi], buf);
+ dgap_trcbufi += lenbuf;
+ dgap_trcbuf[dgap_trcbufi] = '~';
+
+# elif defined(TRC_ON_OVERFLOW_SHIFT_BUFFER)
+ /*
+ * This is the more CPU-intensive way to do things. If we
+ * venture into the last 1/8 of the buffer, we shift the
+ * last 7/8 of the buffer forward, wiping out the first 1/8.
+ * Advantage: No wrap-around, only truncation from the
+ * beginning.
+ *
+ * This method should not be used if you are concerned about
+ * timing changes affecting the behaviour of the driver (ie,
+ * race conditions).
+ */
+ strcpy(&dgap_trcbuf[dgap_trcbufi], buf);
+ dgap_trcbufi += lenbuf;
+ dgap_trcbuf[dgap_trcbufi] = '~';
+ dgap_trcbuf[dgap_trcbufi+1] = '\0';
+
+ /* If we're near the end of the trace buffer... */
+ if (dgap_trcbufi > (dgap_trcbuf_size/8)*7) {
+ /* Wipe out the first eighth to make some more room. */
+ strcpy(dgap_trcbuf, &dgap_trcbuf[dgap_trcbuf_size/8]);
+ dgap_trcbufi = strlen(dgap_trcbuf)-1;
+ /* Plop overflow message at the top of the buffer. */
+ bcopy(TRC_OVERFLOW, dgap_trcbuf, strlen(TRC_OVERFLOW));
+ }
+# else
+# error "TRC_ON_OVERFLOW_WRAP_AROUND or TRC_ON_OVERFLOW_SHIFT_BUFFER?"
+# endif
+ }
+ DGAP_UNLOCK(dgap_tracef_lock, flags);
+
+# endif /* defined(TRC_TO_KMEM) */
+}
+
+#endif /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
+
+#endif
+
+/*
+ * dgap_tracer_free()
+ *
+ *
+ */
+void dgap_tracer_free(void)
+{
+ if(dgap_trcbuf)
+ vfree(dgap_trcbuf);
+}
diff --git a/drivers/staging/dgap/dgap_trace.h b/drivers/staging/dgap/dgap_trace.h
new file mode 100644
index 00000000000..b21f46198e7
--- /dev/null
+++ b/drivers/staging/dgap/dgap_trace.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *****************************************************************************
+ * Header file for dgap_trace.c
+ *
+ * $Id: dgap_trace.h,v 1.1 2009/10/23 14:01:57 markh Exp $
+ */
+
+#ifndef __DGAP_TRACE_H
+#define __DGAP_TRACE_H
+
+#include "dgap_driver.h"
+
+void dgap_tracef(const char *fmt, ...);
+void dgap_tracer_free(void);
+
+#endif
+
diff --git a/drivers/staging/dgap/dgap_tty.c b/drivers/staging/dgap/dgap_tty.c
new file mode 100644
index 00000000000..b906db30b61
--- /dev/null
+++ b/drivers/staging/dgap/dgap_tty.c
@@ -0,0 +1,3597 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ */
+
+/************************************************************************
+ *
+ * This file implements the tty driver functionality for the
+ * FEP5 based product lines.
+ *
+ ************************************************************************
+ *
+ * $Id: dgap_tty.c,v 1.3 2011/06/23 12:11:31 markh Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/sched.h> /* For jiffies, task states */
+#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
+#include <linux/delay.h> /* For udelay */
+#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */
+#include <asm/io.h> /* For read[bwl]/write[bwl] */
+#include <linux/pci.h>
+
+#include "dgap_driver.h"
+#include "dgap_tty.h"
+#include "dgap_types.h"
+#include "dgap_fep5.h"
+#include "dgap_parse.h"
+#include "dgap_conf.h"
+#include "dgap_sysfs.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+#define init_MUTEX(sem) sema_init(sem, 1)
+#define DECLARE_MUTEX(name) \
+ struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
+#endif
+
+/*
+ * internal variables
+ */
+static struct board_t *dgap_BoardsByMajor[256];
+static uchar *dgap_TmpWriteBuf = NULL;
+static DECLARE_MUTEX(dgap_TmpWriteSem);
+
+/*
+ * Default transparent print information.
+ */
+static struct digi_t dgap_digi_init = {
+ .digi_flags = DIGI_COOK, /* Flags */
+ .digi_maxcps = 100, /* Max CPS */
+ .digi_maxchar = 50, /* Max chars in print queue */
+ .digi_bufsize = 100, /* Printer buffer size */
+ .digi_onlen = 4, /* size of printer on string */
+ .digi_offlen = 4, /* size of printer off string */
+ .digi_onstr = "\033[5i", /* ANSI printer on string ] */
+ .digi_offstr = "\033[4i", /* ANSI printer off string ] */
+ .digi_term = "ansi" /* default terminal type */
+};
+
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially.
+ *
+ * This defines a raw port at 9600 baud, 8 data bits, no parity,
+ * 1 stop bit.
+ */
+
+static struct ktermios DgapDefaultTermios =
+{
+ .c_iflag = (DEFAULT_IFLAGS), /* iflags */
+ .c_oflag = (DEFAULT_OFLAGS), /* oflags */
+ .c_cflag = (DEFAULT_CFLAGS), /* cflags */
+ .c_lflag = (DEFAULT_LFLAGS), /* lflags */
+ .c_cc = INIT_C_CC,
+ .c_line = 0,
+};
+
+/* Our function prototypes */
+static int dgap_tty_open(struct tty_struct *tty, struct file *file);
+static void dgap_tty_close(struct tty_struct *tty, struct file *file);
+static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch);
+static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
+static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo);
+static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info);
+static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo);
+static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info);
+static int dgap_tty_write_room(struct tty_struct* tty);
+static int dgap_tty_chars_in_buffer(struct tty_struct* tty);
+static void dgap_tty_start(struct tty_struct *tty);
+static void dgap_tty_stop(struct tty_struct *tty);
+static void dgap_tty_throttle(struct tty_struct *tty);
+static void dgap_tty_unthrottle(struct tty_struct *tty);
+static void dgap_tty_flush_chars(struct tty_struct *tty);
+static void dgap_tty_flush_buffer(struct tty_struct *tty);
+static void dgap_tty_hangup(struct tty_struct *tty);
+static int dgap_wait_for_drain(struct tty_struct *tty);
+static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value);
+static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value);
+static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info);
+static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgap_tty_tiocmget(struct tty_struct *tty);
+static int dgap_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear);
+#else
+static int dgap_tty_tiocmget(struct tty_struct *tty, struct file *file);
+static int dgap_tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear);
+#endif
+static int dgap_tty_send_break(struct tty_struct *tty, int msec);
+static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout);
+static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count);
+static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios);
+static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c);
+static void dgap_tty_send_xchar(struct tty_struct *tty, char ch);
+
+static const struct tty_operations dgap_tty_ops = {
+ .open = dgap_tty_open,
+ .close = dgap_tty_close,
+ .write = dgap_tty_write,
+ .write_room = dgap_tty_write_room,
+ .flush_buffer = dgap_tty_flush_buffer,
+ .chars_in_buffer = dgap_tty_chars_in_buffer,
+ .flush_chars = dgap_tty_flush_chars,
+ .ioctl = dgap_tty_ioctl,
+ .set_termios = dgap_tty_set_termios,
+ .stop = dgap_tty_stop,
+ .start = dgap_tty_start,
+ .throttle = dgap_tty_throttle,
+ .unthrottle = dgap_tty_unthrottle,
+ .hangup = dgap_tty_hangup,
+ .put_char = dgap_tty_put_char,
+ .tiocmget = dgap_tty_tiocmget,
+ .tiocmset = dgap_tty_tiocmset,
+ .break_ctl = dgap_tty_send_break,
+ .wait_until_sent = dgap_tty_wait_until_sent,
+ .send_xchar = dgap_tty_send_xchar
+};
+
+
+
+
+
+/************************************************************************
+ *
+ * TTY Initialization/Cleanup Functions
+ *
+ ************************************************************************/
+
+/*
+ * dgap_tty_preinit()
+ *
+ * Initialize any global tty related data before we download any boards.
+ */
+int dgap_tty_preinit(void)
+{
+ unsigned long flags;
+
+ DGAP_LOCK(dgap_global_lock, flags);
+
+ /*
+ * Allocate a buffer for doing the copy from user space to
+ * kernel space in dgap_input(). We only use one buffer and
+ * control access to it with a semaphore. If we are paging, we
+ * are already in trouble so one buffer won't hurt much anyway.
+ */
+ dgap_TmpWriteBuf = kmalloc(WRITEBUFLEN, GFP_ATOMIC);
+
+ if (!dgap_TmpWriteBuf) {
+ DGAP_UNLOCK(dgap_global_lock, flags);
+ DPR_INIT(("unable to allocate tmp write buf"));
+ return (-ENOMEM);
+ }
+
+ DGAP_UNLOCK(dgap_global_lock, flags);
+ return(0);
+}
+
+
+/*
+ * dgap_tty_register()
+ *
+ * Init the tty subsystem for this board.
+ */
+int dgap_tty_register(struct board_t *brd)
+{
+ int rc = 0;
+
+ DPR_INIT(("tty_register start"));
+
+ brd->SerialDriver = alloc_tty_driver(MAXPORTS);
+
+ snprintf(brd->SerialName, MAXTTYNAMELEN, "tty_dgap_%d_", brd->boardnum);
+ brd->SerialDriver->name = brd->SerialName;
+ brd->SerialDriver->name_base = 0;
+ brd->SerialDriver->major = 0;
+ brd->SerialDriver->minor_start = 0;
+ brd->SerialDriver->type = TTY_DRIVER_TYPE_SERIAL;
+ brd->SerialDriver->subtype = SERIAL_TYPE_NORMAL;
+ brd->SerialDriver->init_termios = DgapDefaultTermios;
+ brd->SerialDriver->driver_name = DRVSTR;
+ brd->SerialDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
+
+ /* The kernel wants space to store pointers to tty_structs */
+ brd->SerialDriver->ttys = dgap_driver_kzmalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL);
+ if (!brd->SerialDriver->ttys)
+ return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+ brd->SerialDriver->refcount = brd->TtyRefCnt;
+#endif
+
+ /*
+ * Entry points for driver. Called by the kernel from
+ * tty_io.c and n_tty.c.
+ */
+ tty_set_operations(brd->SerialDriver, &dgap_tty_ops);
+
+ /*
+ * If we're doing transparent print, we have to do all of the above
+ * again, seperately so we don't get the LD confused about what major
+ * we are when we get into the dgap_tty_open() routine.
+ */
+ brd->PrintDriver = alloc_tty_driver(MAXPORTS);
+
+ snprintf(brd->PrintName, MAXTTYNAMELEN, "pr_dgap_%d_", brd->boardnum);
+ brd->PrintDriver->name = brd->PrintName;
+ brd->PrintDriver->name_base = 0;
+ brd->PrintDriver->major = 0;
+ brd->PrintDriver->minor_start = 0;
+ brd->PrintDriver->type = TTY_DRIVER_TYPE_SERIAL;
+ brd->PrintDriver->subtype = SERIAL_TYPE_NORMAL;
+ brd->PrintDriver->init_termios = DgapDefaultTermios;
+ brd->PrintDriver->driver_name = DRVSTR;
+ brd->PrintDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
+
+ /* The kernel wants space to store pointers to tty_structs */
+ brd->PrintDriver->ttys = dgap_driver_kzmalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL);
+ if (!brd->PrintDriver->ttys)
+ return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+ brd->PrintDriver->refcount = brd->TtyRefCnt;
+#endif
+
+ /*
+ * Entry points for driver. Called by the kernel from
+ * tty_io.c and n_tty.c.
+ */
+ tty_set_operations(brd->PrintDriver, &dgap_tty_ops);
+
+ if (!brd->dgap_Major_Serial_Registered) {
+ /* Register tty devices */
+ rc = tty_register_driver(brd->SerialDriver);
+ if (rc < 0) {
+ APR(("Can't register tty device (%d)\n", rc));
+ return(rc);
+ }
+ brd->dgap_Major_Serial_Registered = TRUE;
+ dgap_BoardsByMajor[brd->SerialDriver->major] = brd;
+ brd->dgap_Serial_Major = brd->SerialDriver->major;
+ }
+
+ if (!brd->dgap_Major_TransparentPrint_Registered) {
+ /* Register Transparent Print devices */
+ rc = tty_register_driver(brd->PrintDriver);
+ if (rc < 0) {
+ APR(("Can't register Transparent Print device (%d)\n", rc));
+ return(rc);
+ }
+ brd->dgap_Major_TransparentPrint_Registered = TRUE;
+ dgap_BoardsByMajor[brd->PrintDriver->major] = brd;
+ brd->dgap_TransparentPrint_Major = brd->PrintDriver->major;
+ }
+
+ DPR_INIT(("DGAP REGISTER TTY: MAJORS: %d %d\n", brd->SerialDriver->major,
+ brd->PrintDriver->major));
+
+ return (rc);
+}
+
+
+/*
+ * dgap_tty_init()
+ *
+ * Init the tty subsystem. Called once per board after board has been
+ * downloaded and init'ed.
+ */
+int dgap_tty_init(struct board_t *brd)
+{
+ int i;
+ int tlw;
+ uint true_count = 0;
+ uchar *vaddr;
+ uchar modem = 0;
+ struct channel_t *ch;
+ struct bs_t *bs;
+ struct cm_t *cm;
+
+ if (!brd)
+ return (-ENXIO);
+
+ DPR_INIT(("dgap_tty_init start\n"));
+
+ /*
+ * Initialize board structure elements.
+ */
+
+ vaddr = brd->re_map_membase;
+ true_count = readw((vaddr + NCHAN));
+
+ brd->nasync = dgap_config_get_number_of_ports(brd);
+
+ if (!brd->nasync) {
+ brd->nasync = brd->maxports;
+ }
+
+ if (brd->nasync > brd->maxports) {
+ brd->nasync = brd->maxports;
+ }
+
+ if (true_count != brd->nasync) {
+ if ((brd->type == PPCM) && (true_count == 64)) {
+ APR(("***WARNING**** %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n",
+ brd->name, brd->nasync, true_count));
+ }
+ else if ((brd->type == PPCM) && (true_count == 0)) {
+ APR(("***WARNING**** %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n",
+ brd->name, brd->nasync, true_count));
+ }
+ else {
+ APR(("***WARNING**** %s configured for %d ports, has %d ports.\n",
+ brd->name, brd->nasync, true_count));
+ }
+
+ brd->nasync = true_count;
+
+ /* If no ports, don't bother going any further */
+ if (!brd->nasync) {
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ return(-ENXIO);
+ }
+ }
+
+ /*
+ * Allocate channel memory that might not have been allocated
+ * when the driver was first loaded.
+ */
+ for (i = 0; i < brd->nasync; i++) {
+ if (!brd->channels[i]) {
+ brd->channels[i] = dgap_driver_kzmalloc(sizeof(struct channel_t), GFP_ATOMIC);
+ if (!brd->channels[i]) {
+ DPR_CORE(("%s:%d Unable to allocate memory for channel struct\n",
+ __FILE__, __LINE__));
+ }
+ }
+ }
+
+ ch = brd->channels[0];
+ vaddr = brd->re_map_membase;
+
+ bs = (struct bs_t *) ((ulong) vaddr + CHANBUF);
+ cm = (struct cm_t *) ((ulong) vaddr + CMDBUF);
+
+ brd->bd_bs = bs;
+
+ /* Set up channel variables */
+ for (i = 0; i < brd->nasync; i++, ch = brd->channels[i], bs++) {
+
+ if (!brd->channels[i])
+ continue;
+
+ DGAP_SPINLOCK_INIT(ch->ch_lock);
+
+ /* Store all our magic numbers */
+ ch->magic = DGAP_CHANNEL_MAGIC;
+ ch->ch_tun.magic = DGAP_UNIT_MAGIC;
+ ch->ch_tun.un_type = DGAP_SERIAL;
+ ch->ch_tun.un_ch = ch;
+ ch->ch_tun.un_dev = i;
+
+ ch->ch_pun.magic = DGAP_UNIT_MAGIC;
+ ch->ch_pun.un_type = DGAP_PRINT;
+ ch->ch_pun.un_ch = ch;
+ ch->ch_pun.un_dev = i;
+
+ ch->ch_vaddr = vaddr;
+ ch->ch_bs = bs;
+ ch->ch_cm = cm;
+ ch->ch_bd = brd;
+ ch->ch_portnum = i;
+ ch->ch_digi = dgap_digi_init;
+
+ /*
+ * Set up digi dsr and dcd bits based on altpin flag.
+ */
+ if (dgap_config_get_altpin(brd)) {
+ ch->ch_dsr = DM_CD;
+ ch->ch_cd = DM_DSR;
+ ch->ch_digi.digi_flags |= DIGI_ALTPIN;
+ }
+ else {
+ ch->ch_cd = DM_CD;
+ ch->ch_dsr = DM_DSR;
+ }
+
+ ch->ch_taddr = vaddr + ((ch->ch_bs->tx_seg) << 4);
+ ch->ch_raddr = vaddr + ((ch->ch_bs->rx_seg) << 4);
+ ch->ch_tx_win = 0;
+ ch->ch_rx_win = 0;
+ ch->ch_tsize = readw(&(ch->ch_bs->tx_max)) + 1;
+ ch->ch_rsize = readw(&(ch->ch_bs->rx_max)) + 1;
+ ch->ch_tstart = 0;
+ ch->ch_rstart = 0;
+
+ /* .25 second delay */
+ ch->ch_close_delay = 250;
+
+ /*
+ * Set queue water marks, interrupt mask,
+ * and general tty parameters.
+ */
+ ch->ch_tlw = tlw = ch->ch_tsize >= 2000 ? ((ch->ch_tsize * 5) / 8) : ch->ch_tsize / 2;
+
+ dgap_cmdw(ch, STLOW, tlw, 0);
+
+ dgap_cmdw(ch, SRLOW, ch->ch_rsize / 2, 0);
+
+ dgap_cmdw(ch, SRHIGH, 7 * ch->ch_rsize / 8, 0);
+
+ ch->ch_mistat = readb(&(ch->ch_bs->m_stat));
+
+ init_waitqueue_head(&ch->ch_flags_wait);
+ init_waitqueue_head(&ch->ch_tun.un_flags_wait);
+ init_waitqueue_head(&ch->ch_pun.un_flags_wait);
+ init_waitqueue_head(&ch->ch_sniff_wait);
+
+ /* Turn on all modem interrupts for now */
+ modem = (DM_CD | DM_DSR | DM_CTS | DM_RI);
+ writeb(modem, &(ch->ch_bs->m_int));
+
+ /*
+ * Set edelay to 0 if interrupts are turned on,
+ * otherwise set edelay to the usual 100.
+ */
+ if (brd->intr_used)
+ writew(0, &(ch->ch_bs->edelay));
+ else
+ writew(100, &(ch->ch_bs->edelay));
+
+ writeb(1, &(ch->ch_bs->idata));
+ }
+
+
+ DPR_INIT(("dgap_tty_init finish\n"));
+
+ return (0);
+}
+
+
+/*
+ * dgap_tty_post_uninit()
+ *
+ * UnInitialize any global tty related data.
+ */
+void dgap_tty_post_uninit(void)
+{
+ if (dgap_TmpWriteBuf) {
+ kfree(dgap_TmpWriteBuf);
+ dgap_TmpWriteBuf = NULL;
+ }
+}
+
+
+/*
+ * dgap_tty_uninit()
+ *
+ * Uninitialize the TTY portion of this driver. Free all memory and
+ * resources.
+ */
+void dgap_tty_uninit(struct board_t *brd)
+{
+ int i = 0;
+
+ if (brd->dgap_Major_Serial_Registered) {
+ dgap_BoardsByMajor[brd->SerialDriver->major] = NULL;
+ brd->dgap_Serial_Major = 0;
+ for (i = 0; i < brd->nasync; i++) {
+ dgap_remove_tty_sysfs(brd->channels[i]->ch_tun.un_sysfs);
+ tty_unregister_device(brd->SerialDriver, i);
+ }
+ tty_unregister_driver(brd->SerialDriver);
+ if (brd->SerialDriver->ttys) {
+ kfree(brd->SerialDriver->ttys);
+ brd->SerialDriver->ttys = NULL;
+ }
+ put_tty_driver(brd->SerialDriver);
+ brd->dgap_Major_Serial_Registered = FALSE;
+ }
+
+ if (brd->dgap_Major_TransparentPrint_Registered) {
+ dgap_BoardsByMajor[brd->PrintDriver->major] = NULL;
+ brd->dgap_TransparentPrint_Major = 0;
+ for (i = 0; i < brd->nasync; i++) {
+ dgap_remove_tty_sysfs(brd->channels[i]->ch_pun.un_sysfs);
+ tty_unregister_device(brd->PrintDriver, i);
+ }
+ tty_unregister_driver(brd->PrintDriver);
+ if (brd->PrintDriver->ttys) {
+ kfree(brd->PrintDriver->ttys);
+ brd->PrintDriver->ttys = NULL;
+ }
+ put_tty_driver(brd->PrintDriver);
+ brd->dgap_Major_TransparentPrint_Registered = FALSE;
+ }
+}
+
+
+#define TMPBUFLEN (1024)
+
+/*
+ * dgap_sniff - Dump data out to the "sniff" buffer if the
+ * proc sniff file is opened...
+ */
+static void dgap_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int len)
+{
+ struct timeval tv;
+ int n;
+ int r;
+ int nbuf;
+ int i;
+ int tmpbuflen;
+ char tmpbuf[TMPBUFLEN];
+ char *p = tmpbuf;
+ int too_much_data;
+
+ /* Leave if sniff not open */
+ if (!(ch->ch_sniff_flags & SNIFF_OPEN))
+ return;
+
+ do_gettimeofday(&tv);
+
+ /* Create our header for data dump */
+ p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text);
+ tmpbuflen = p - tmpbuf;
+
+ do {
+ too_much_data = 0;
+
+ for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) {
+ p += sprintf(p, "%02x ", *buf);
+ buf++;
+ tmpbuflen = p - tmpbuf;
+ }
+
+ if (tmpbuflen < (TMPBUFLEN - 4)) {
+ if (i > 0)
+ p += sprintf(p - 1, "%s\n", ">");
+ else
+ p += sprintf(p, "%s\n", ">");
+ } else {
+ too_much_data = 1;
+ len -= i;
+ }
+
+ nbuf = strlen(tmpbuf);
+ p = tmpbuf;
+
+ /*
+ * Loop while data remains.
+ */
+ while (nbuf > 0 && ch->ch_sniff_buf != 0) {
+ /*
+ * Determine the amount of available space left in the
+ * buffer. If there's none, wait until some appears.
+ */
+ n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) & SNIFF_MASK;
+
+ /*
+ * If there is no space left to write to in our sniff buffer,
+ * we have no choice but to drop the data.
+ * We *cannot* sleep here waiting for space, because this
+ * function was probably called by the interrupt/timer routines!
+ */
+ if (n == 0) {
+ return;
+ }
+
+ /*
+ * Copy as much data as will fit.
+ */
+
+ if (n > nbuf)
+ n = nbuf;
+
+ r = SNIFF_MAX - ch->ch_sniff_in;
+
+ if (r <= n) {
+ memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, r);
+
+ n -= r;
+ ch->ch_sniff_in = 0;
+ p += r;
+ nbuf -= r;
+ }
+
+ memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n);
+
+ ch->ch_sniff_in += n;
+ p += n;
+ nbuf -= n;
+
+ /*
+ * Wakeup any thread waiting for data
+ */
+ if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) {
+ ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA;
+ wake_up_interruptible(&ch->ch_sniff_wait);
+ }
+ }
+
+ /*
+ * If the user sent us too much data to push into our tmpbuf,
+ * we need to keep looping around on all the data.
+ */
+ if (too_much_data) {
+ p = tmpbuf;
+ tmpbuflen = 0;
+ }
+
+ } while (too_much_data);
+}
+
+
+/*=======================================================================
+ *
+ * dgap_input - Process received data.
+ *
+ * ch - Pointer to channel structure.
+ *
+ *=======================================================================*/
+
+void dgap_input(struct channel_t *ch)
+{
+ struct board_t *bd;
+ struct bs_t *bs;
+ struct tty_struct *tp;
+ struct tty_ldisc *ld;
+ uint rmask;
+ uint head;
+ uint tail;
+ int data_len;
+ ulong lock_flags;
+ ulong lock_flags2;
+ int flip_len;
+ int len = 0;
+ int n = 0;
+ uchar *buf;
+ uchar tmpchar;
+ int s = 0;
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ tp = ch->ch_tun.un_tty;
+
+ bs = ch->ch_bs;
+ if (!bs) {
+ return;
+ }
+
+ bd = ch->ch_bd;
+ if(!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ DPR_READ(("dgap_input start\n"));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ /*
+ * Figure the number of characters in the buffer.
+ * Exit immediately if none.
+ */
+
+ rmask = ch->ch_rsize - 1;
+
+ head = readw(&(bs->rx_head));
+ head &= rmask;
+ tail = readw(&(bs->rx_tail));
+ tail &= rmask;
+
+ data_len = (head - tail) & rmask;
+
+ if (data_len == 0) {
+ writeb(1, &(bs->idata));
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ DPR_READ(("No data on port %d\n", ch->ch_portnum));
+ return;
+ }
+
+ /*
+ * If the device is not open, or CREAD is off, flush
+ * input data and return immediately.
+ */
+ if ((bd->state != BOARD_READY) || !tp || (tp->magic != TTY_MAGIC) ||
+ !(ch->ch_tun.un_flags & UN_ISOPEN) || !(tp->termios.c_cflag & CREAD) ||
+ (ch->ch_tun.un_flags & UN_CLOSING)) {
+
+ DPR_READ(("input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum));
+ DPR_READ(("input. tp: %p tp->magic: %x MAGIC:%x ch flags: %x\n",
+ tp, tp ? tp->magic : 0, TTY_MAGIC, ch->ch_tun.un_flags));
+ writew(head, &(bs->rx_tail));
+ writeb(1, &(bs->idata));
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return;
+ }
+
+ /*
+ * If we are throttled, simply don't read any data.
+ */
+ if (ch->ch_flags & CH_RXBLOCK) {
+ writeb(1, &(bs->idata));
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ DPR_READ(("Port %d throttled, not reading any data. head: %x tail: %x\n",
+ ch->ch_portnum, head, tail));
+ return;
+ }
+
+ /*
+ * Ignore oruns.
+ */
+ tmpchar = readb(&(bs->orun));
+ if (tmpchar) {
+ ch->ch_err_overrun++;
+ writeb(0, &(bs->orun));
+ }
+
+ DPR_READ(("dgap_input start 2\n"));
+
+ /* Decide how much data we can send into the tty layer */
+ flip_len = TTY_FLIPBUF_SIZE;
+
+ /* Chop down the length, if needed */
+ len = min(data_len, flip_len);
+ len = min(len, (N_TTY_BUF_SIZE - 1));
+
+ ld = tty_ldisc_ref(tp);
+
+#ifdef TTY_DONT_FLIP
+ /*
+ * If the DONT_FLIP flag is on, don't flush our buffer, and act
+ * like the ld doesn't have any space to put the data right now.
+ */
+ if (test_bit(TTY_DONT_FLIP, &tp->flags))
+ len = 0;
+#endif
+
+ /*
+ * If we were unable to get a reference to the ld,
+ * don't flush our buffer, and act like the ld doesn't
+ * have any space to put the data right now.
+ */
+ if (!ld) {
+ len = 0;
+ } else {
+ /*
+ * If ld doesn't have a pointer to a receive_buf function,
+ * flush the data, then act like the ld doesn't have any
+ * space to put the data right now.
+ */
+ if (!ld->ops->receive_buf) {
+ writew(head, &(bs->rx_tail));
+ len = 0;
+ }
+ }
+
+ if (len <= 0) {
+ writeb(1, &(bs->idata));
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ DPR_READ(("dgap_input 1 - finish\n"));
+ if (ld)
+ tty_ldisc_deref(ld);
+ return;
+ }
+
+ buf = ch->ch_bd->flipbuf;
+ n = len;
+
+ /*
+ * n now contains the most amount of data we can copy,
+ * bounded either by our buffer size or the amount
+ * of data the card actually has pending...
+ */
+ while (n) {
+
+ s = ((head >= tail) ? head : ch->ch_rsize) - tail;
+ s = min(s, n);
+
+ if (s <= 0)
+ break;
+
+ memcpy_fromio(buf, (char *) ch->ch_raddr + tail, s);
+ dgap_sniff_nowait_nolock(ch, "USER READ", buf, s);
+
+ tail += s;
+ buf += s;
+
+ n -= s;
+ /* Flip queue if needed */
+ tail &= rmask;
+ }
+
+ writew(tail, &(bs->rx_tail));
+ writeb(1, &(bs->idata));
+ ch->ch_rxcount += len;
+
+ /*
+ * If we are completely raw, we don't need to go through a lot
+ * of the tty layers that exist.
+ * In this case, we take the shortest and fastest route we
+ * can to relay the data to the user.
+ *
+ * On the other hand, if we are not raw, we need to go through
+ * the tty layer, which has its API more well defined.
+ */
+ if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+ dgap_parity_scan(ch, ch->ch_bd->flipbuf, ch->ch_bd->flipflagbuf, &len);
+
+ len = tty_buffer_request_room(tp->port, len);
+ tty_insert_flip_string_flags(tp->port, ch->ch_bd->flipbuf,
+ ch->ch_bd->flipflagbuf, len);
+ }
+ else {
+ len = tty_buffer_request_room(tp->port, len);
+ tty_insert_flip_string(tp->port, ch->ch_bd->flipbuf, len);
+ }
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ /* Tell the tty layer its okay to "eat" the data now */
+ tty_flip_buffer_push(tp->port);
+
+ if (ld)
+ tty_ldisc_deref(ld);
+
+ DPR_READ(("dgap_input - finish\n"));
+}
+
+
+/************************************************************************
+ * Determines when CARRIER changes state and takes appropriate
+ * action.
+ ************************************************************************/
+void dgap_carrier(struct channel_t *ch)
+{
+ struct board_t *bd;
+
+ int virt_carrier = 0;
+ int phys_carrier = 0;
+
+ DPR_CARR(("dgap_carrier called...\n"));
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ /* Make sure altpin is always set correctly */
+ if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
+ ch->ch_dsr = DM_CD;
+ ch->ch_cd = DM_DSR;
+ }
+ else {
+ ch->ch_dsr = DM_DSR;
+ ch->ch_cd = DM_CD;
+ }
+
+ if (ch->ch_mistat & D_CD(ch)) {
+ DPR_CARR(("mistat: %x D_CD: %x\n", ch->ch_mistat, D_CD(ch)));
+ phys_carrier = 1;
+ }
+
+ if (ch->ch_digi.digi_flags & DIGI_FORCEDCD) {
+ virt_carrier = 1;
+ }
+
+ if (ch->ch_c_cflag & CLOCAL) {
+ virt_carrier = 1;
+ }
+
+
+ DPR_CARR(("DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier));
+
+ /*
+ * Test for a VIRTUAL carrier transition to HIGH.
+ */
+ if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
+
+ /*
+ * When carrier rises, wake any threads waiting
+ * for carrier in the open routine.
+ */
+
+ DPR_CARR(("carrier: virt DCD rose\n"));
+
+ if (waitqueue_active(&(ch->ch_flags_wait)))
+ wake_up_interruptible(&ch->ch_flags_wait);
+ }
+
+ /*
+ * Test for a PHYSICAL carrier transition to HIGH.
+ */
+ if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
+
+ /*
+ * When carrier rises, wake any threads waiting
+ * for carrier in the open routine.
+ */
+
+ DPR_CARR(("carrier: physical DCD rose\n"));
+
+ if (waitqueue_active(&(ch->ch_flags_wait)))
+ wake_up_interruptible(&ch->ch_flags_wait);
+ }
+
+ /*
+ * Test for a PHYSICAL transition to low, so long as we aren't
+ * currently ignoring physical transitions (which is what "virtual
+ * carrier" indicates).
+ *
+ * The transition of the virtual carrier to low really doesn't
+ * matter... it really only means "ignore carrier state", not
+ * "make pretend that carrier is there".
+ */
+ if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) &&
+ (phys_carrier == 0))
+ {
+
+ /*
+ * When carrier drops:
+ *
+ * Drop carrier on all open units.
+ *
+ * Flush queues, waking up any task waiting in the
+ * line discipline.
+ *
+ * Send a hangup to the control terminal.
+ *
+ * Enable all select calls.
+ */
+ if (waitqueue_active(&(ch->ch_flags_wait)))
+ wake_up_interruptible(&ch->ch_flags_wait);
+
+ if (ch->ch_tun.un_open_count > 0) {
+ DPR_CARR(("Sending tty hangup\n"));
+ tty_hangup(ch->ch_tun.un_tty);
+ }
+
+ if (ch->ch_pun.un_open_count > 0) {
+ DPR_CARR(("Sending pr hangup\n"));
+ tty_hangup(ch->ch_pun.un_tty);
+ }
+ }
+
+ /*
+ * Make sure that our cached values reflect the current reality.
+ */
+ if (virt_carrier == 1)
+ ch->ch_flags |= CH_FCAR;
+ else
+ ch->ch_flags &= ~CH_FCAR;
+
+ if (phys_carrier == 1)
+ ch->ch_flags |= CH_CD;
+ else
+ ch->ch_flags &= ~CH_CD;
+}
+
+
+/************************************************************************
+ *
+ * TTY Entry points and helper functions
+ *
+ ************************************************************************/
+
+/*
+ * dgap_tty_open()
+ *
+ */
+static int dgap_tty_open(struct tty_struct *tty, struct file *file)
+{
+ struct board_t *brd;
+ struct channel_t *ch;
+ struct un_t *un;
+ struct bs_t *bs;
+ uint major = 0;
+ uint minor = 0;
+ int rc = 0;
+ ulong lock_flags;
+ ulong lock_flags2;
+ u16 head;
+
+ rc = 0;
+
+ major = MAJOR(tty_devnum(tty));
+ minor = MINOR(tty_devnum(tty));
+
+ if (major > 255) {
+ return -ENXIO;
+ }
+
+ /* Get board pointer from our array of majors we have allocated */
+ brd = dgap_BoardsByMajor[major];
+ if (!brd) {
+ return -ENXIO;
+ }
+
+ /*
+ * If board is not yet up to a state of READY, go to
+ * sleep waiting for it to happen or they cancel the open.
+ */
+ rc = wait_event_interruptible(brd->state_wait,
+ (brd->state & BOARD_READY));
+
+ if (rc) {
+ return rc;
+ }
+
+ DGAP_LOCK(brd->bd_lock, lock_flags);
+
+ /* The wait above should guarentee this cannot happen */
+ if (brd->state != BOARD_READY) {
+ DGAP_UNLOCK(brd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ /* If opened device is greater than our number of ports, bail. */
+ if (MINOR(tty_devnum(tty)) > brd->nasync) {
+ DGAP_UNLOCK(brd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ ch = brd->channels[minor];
+ if (!ch) {
+ DGAP_UNLOCK(brd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ /* Grab channel lock */
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ /* Figure out our type */
+ if (major == brd->dgap_Serial_Major) {
+ un = &brd->channels[minor]->ch_tun;
+ un->un_type = DGAP_SERIAL;
+ }
+ else if (major == brd->dgap_TransparentPrint_Major) {
+ un = &brd->channels[minor]->ch_pun;
+ un->un_type = DGAP_PRINT;
+ }
+ else {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(brd->bd_lock, lock_flags);
+ DPR_OPEN(("%d Unknown TYPE!\n", __LINE__));
+ return -ENXIO;
+ }
+
+ /* Store our unit into driver_data, so we always have it available. */
+ tty->driver_data = un;
+
+ DPR_OPEN(("Open called. MAJOR: %d MINOR:%d unit: %p NAME: %s\n",
+ MAJOR(tty_devnum(tty)), MINOR(tty_devnum(tty)), un, brd->name));
+
+ /*
+ * Error if channel info pointer is 0.
+ */
+ if ((bs = ch->ch_bs) == 0) {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(brd->bd_lock, lock_flags);
+ DPR_OPEN(("%d BS is 0!\n", __LINE__));
+ return -ENXIO;
+ }
+
+ DPR_OPEN(("%d: tflag=%x pflag=%x\n", __LINE__, ch->ch_tun.un_flags, ch->ch_pun.un_flags));
+
+ /*
+ * Initialize tty's
+ */
+ if (!(un->un_flags & UN_ISOPEN)) {
+ /* Store important variables. */
+ un->un_tty = tty;
+
+ /* Maybe do something here to the TTY struct as well? */
+ }
+
+ /*
+ * Initialize if neither terminal or printer is open.
+ */
+ if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) {
+
+ DPR_OPEN(("dgap_open: initializing channel in open...\n"));
+
+ ch->ch_mforce = 0;
+ ch->ch_mval = 0;
+
+ /*
+ * Flush input queue.
+ */
+ head = readw(&(bs->rx_head));
+ writew(head, &(bs->rx_tail));
+
+ ch->ch_flags = 0;
+ ch->pscan_state = 0;
+ ch->pscan_savechar = 0;
+
+ ch->ch_c_cflag = tty->termios.c_cflag;
+ ch->ch_c_iflag = tty->termios.c_iflag;
+ ch->ch_c_oflag = tty->termios.c_oflag;
+ ch->ch_c_lflag = tty->termios.c_lflag;
+ ch->ch_startc = tty->termios.c_cc[VSTART];
+ ch->ch_stopc = tty->termios.c_cc[VSTOP];
+
+ /* TODO: flush our TTY struct here? */
+ }
+
+ dgap_carrier(ch);
+ /*
+ * Run param in case we changed anything
+ */
+ dgap_param(tty);
+
+ /*
+ * follow protocol for opening port
+ */
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(brd->bd_lock, lock_flags);
+
+ rc = dgap_block_til_ready(tty, file, ch);
+
+ if (!un->un_tty) {
+ return -ENODEV;
+ }
+
+ if (rc) {
+ DPR_OPEN(("dgap_tty_open returning after dgap_block_til_ready "
+ "with %d\n", rc));
+ }
+
+ /* No going back now, increment our unit and channel counters */
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_open_count++;
+ un->un_open_count++;
+ un->un_flags |= (UN_ISOPEN);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_OPEN(("dgap_tty_open finished\n"));
+ return (rc);
+}
+
+
+/*
+ * dgap_block_til_ready()
+ *
+ * Wait for DCD, if needed.
+ */
+static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch)
+{
+ int retval = 0;
+ struct un_t *un = NULL;
+ ulong lock_flags;
+ uint old_flags = 0;
+ int sleep_on_un_flags = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC || !file || !ch || ch->magic != DGAP_CHANNEL_MAGIC) {
+ return (-ENXIO);
+ }
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC) {
+ return (-ENXIO);
+ }
+
+ DPR_OPEN(("dgap_block_til_ready - before block.\n"));
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_wopen++;
+
+ /* Loop forever */
+ while (1) {
+
+ sleep_on_un_flags = 0;
+
+ /*
+ * If board has failed somehow during our sleep, bail with error.
+ */
+ if (ch->ch_bd->state == BOARD_FAILED) {
+ retval = -ENXIO;
+ break;
+ }
+
+ /* If tty was hung up, break out of loop and set error. */
+ if (tty_hung_up_p(file)) {
+ retval = -EAGAIN;
+ break;
+ }
+
+ /*
+ * If either unit is in the middle of the fragile part of close,
+ * we just cannot touch the channel safely.
+ * Go back to sleep, knowing that when the channel can be
+ * touched safely, the close routine will signal the
+ * ch_wait_flags to wake us back up.
+ */
+ if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_CLOSING)) {
+
+ /*
+ * Our conditions to leave cleanly and happily:
+ * 1) NONBLOCKING on the tty is set.
+ * 2) CLOCAL is set.
+ * 3) DCD (fake or real) is active.
+ */
+
+ if (file->f_flags & O_NONBLOCK) {
+ break;
+ }
+
+ if (tty->flags & (1 << TTY_IO_ERROR)) {
+ break;
+ }
+
+ if (ch->ch_flags & CH_CD) {
+ DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags));
+ break;
+ }
+
+ if (ch->ch_flags & CH_FCAR) {
+ DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags));
+ break;
+ }
+ }
+ else {
+ sleep_on_un_flags = 1;
+ }
+
+ /*
+ * If there is a signal pending, the user probably
+ * interrupted (ctrl-c) us.
+ * Leave loop with error set.
+ */
+ if (signal_pending(current)) {
+ DPR_OPEN(("%d: signal pending...\n", __LINE__));
+ retval = -ERESTARTSYS;
+ break;
+ }
+
+ DPR_OPEN(("dgap_block_til_ready - blocking.\n"));
+
+ /*
+ * Store the flags before we let go of channel lock
+ */
+ if (sleep_on_un_flags)
+ old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags;
+ else
+ old_flags = ch->ch_flags;
+
+ /*
+ * Let go of channel lock before calling schedule.
+ * Our poller will get any FEP events and wake us up when DCD
+ * eventually goes active.
+ */
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_OPEN(("Going to sleep on %s flags...\n",
+ (sleep_on_un_flags ? "un" : "ch")));
+
+ /*
+ * Wait for something in the flags to change from the current value.
+ */
+ if (sleep_on_un_flags) {
+ retval = wait_event_interruptible(un->un_flags_wait,
+ (old_flags != (ch->ch_tun.un_flags | ch->ch_pun.un_flags)));
+ }
+ else {
+ retval = wait_event_interruptible(ch->ch_flags_wait,
+ (old_flags != ch->ch_flags));
+ }
+
+ DPR_OPEN(("After sleep... retval: %x\n", retval));
+
+ /*
+ * We got woken up for some reason.
+ * Before looping around, grab our channel lock.
+ */
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+ }
+
+ ch->ch_wopen--;
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_OPEN(("dgap_block_til_ready - after blocking.\n"));
+
+ if (retval) {
+ DPR_OPEN(("dgap_block_til_ready - done. error. retval: %x\n", retval));
+ return(retval);
+ }
+
+ DPR_OPEN(("dgap_block_til_ready - done no error. jiffies: %lu\n", jiffies));
+
+ return(0);
+}
+
+
+/*
+ * dgap_tty_hangup()
+ *
+ * Hangup the port. Like a close, but don't wait for output to drain.
+ */
+static void dgap_tty_hangup(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ DPR_CLOSE(("dgap_hangup called. ch->ch_open_count: %d un->un_open_count: %d\n",
+ ch->ch_open_count, un->un_open_count));
+
+ /* flush the transmit queues */
+ dgap_tty_flush_buffer(tty);
+
+ DPR_CLOSE(("dgap_hangup finished. ch->ch_open_count: %d un->un_open_count: %d\n",
+ ch->ch_open_count, un->un_open_count));
+}
+
+
+
+/*
+ * dgap_tty_close()
+ *
+ */
+static void dgap_tty_close(struct tty_struct *tty, struct file *file)
+{
+ struct ktermios *ts;
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ int rc = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ ts = &tty->termios;
+
+ DPR_CLOSE(("Close called\n"));
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * Determine if this is the last close or not - and if we agree about
+ * which type of close it is with the Line Discipline
+ */
+ if ((tty->count == 1) && (un->un_open_count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. un_open_count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ APR(("tty->count is 1, un open count is %d\n", un->un_open_count));
+ un->un_open_count = 1;
+ }
+
+ if (--un->un_open_count < 0) {
+ APR(("bad serial port open count of %d\n", un->un_open_count));
+ un->un_open_count = 0;
+ }
+
+ ch->ch_open_count--;
+
+ if (ch->ch_open_count && un->un_open_count) {
+ DPR_CLOSE(("dgap_tty_close: not last close ch: %d un:%d\n",
+ ch->ch_open_count, un->un_open_count));
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ /* OK, its the last close on the unit */
+ DPR_CLOSE(("dgap_tty_close - last close on unit procedures\n"));
+
+ un->un_flags |= UN_CLOSING;
+
+ tty->closing = 1;
+
+ /*
+ * Only officially close channel if count is 0 and
+ * DIGI_PRINTER bit is not set.
+ */
+ if ((ch->ch_open_count == 0) && !(ch->ch_digi.digi_flags & DIGI_PRINTER)) {
+
+ ch->ch_flags &= ~(CH_RXBLOCK);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ /* wait for output to drain */
+ /* This will also return if we take an interrupt */
+
+ DPR_CLOSE(("Calling wait_for_drain\n"));
+ rc = dgap_wait_for_drain(tty);
+ DPR_CLOSE(("After calling wait_for_drain\n"));
+
+ if (rc) {
+ DPR_BASIC(("dgap_tty_close - bad return: %d ", rc));
+ }
+
+ dgap_tty_flush_buffer(tty);
+ tty_ldisc_flush(tty);
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+
+ tty->closing = 0;
+
+ /*
+ * If we have HUPCL set, lower DTR and RTS
+ */
+ if (ch->ch_c_cflag & HUPCL ) {
+ DPR_CLOSE(("Close. HUPCL set, dropping DTR/RTS\n"));
+ ch->ch_mostat &= ~(D_RTS(ch)|D_DTR(ch));
+ dgap_cmdb( ch, SMODEM, 0, D_DTR(ch)|D_RTS(ch), 0 );
+
+ /*
+ * Go to sleep to ensure RTS/DTR
+ * have been dropped for modems to see it.
+ */
+ if (ch->ch_close_delay) {
+ DPR_CLOSE(("Close. Sleeping for RTS/DTR drop\n"));
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+ dgap_ms_sleep(ch->ch_close_delay);
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+
+ DPR_CLOSE(("Close. After sleeping for RTS/DTR drop\n"));
+ }
+ }
+
+ ch->pscan_state = 0;
+ ch->pscan_savechar = 0;
+ ch->ch_baud_info = 0;
+
+ }
+
+ /*
+ * turn off print device when closing print device.
+ */
+ if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON) ) {
+ dgap_wmove(ch, ch->ch_digi.digi_offstr,
+ (int) ch->ch_digi.digi_offlen);
+ ch->ch_flags &= ~CH_PRON;
+ }
+
+ un->un_tty = NULL;
+ un->un_flags &= ~(UN_ISOPEN | UN_CLOSING);
+ tty->driver_data = NULL;
+
+ DPR_CLOSE(("Close. Doing wakeups\n"));
+ wake_up_interruptible(&ch->ch_flags_wait);
+ wake_up_interruptible(&un->un_flags_wait);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_BASIC(("dgap_tty_close - complete\n"));
+}
+
+
+/*
+ * dgap_tty_chars_in_buffer()
+ *
+ * Return number of characters that have not been transmitted yet.
+ *
+ * This routine is used by the line discipline to determine if there
+ * is data waiting to be transmitted/drained/flushed or not.
+ */
+static int dgap_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ struct board_t *bd = NULL;
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+ struct bs_t *bs = NULL;
+ uchar tbusy;
+ uint chars = 0;
+ u16 thead, ttail, tmask, chead, ctail;
+ ulong lock_flags = 0;
+ ulong lock_flags2 = 0;
+
+ if (tty == NULL)
+ return(0);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (0);
+
+ bs = ch->ch_bs;
+ if (!bs)
+ return (0);
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ tmask = (ch->ch_tsize - 1);
+
+ /* Get Transmit queue pointers */
+ thead = readw(&(bs->tx_head)) & tmask;
+ ttail = readw(&(bs->tx_tail)) & tmask;
+
+ /* Get tbusy flag */
+ tbusy = readb(&(bs->tbusy));
+
+ /* Get Command queue pointers */
+ chead = readw(&(ch->ch_cm->cm_head));
+ ctail = readw(&(ch->ch_cm->cm_tail));
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ /*
+ * The only way we know for sure if there is no pending
+ * data left to be transferred, is if:
+ * 1) Transmit head and tail are equal (empty).
+ * 2) Command queue head and tail are equal (empty).
+ * 3) The "TBUSY" flag is 0. (Transmitter not busy).
+ */
+
+ if ((ttail == thead) && (tbusy == 0) && (chead == ctail)) {
+ chars = 0;
+ }
+ else {
+ if (thead >= ttail)
+ chars = thead - ttail;
+ else
+ chars = thead - ttail + ch->ch_tsize;
+ /*
+ * Fudge factor here.
+ * If chars is zero, we know that the command queue had
+ * something in it or tbusy was set. Because we cannot
+ * be sure if there is still some data to be transmitted,
+ * lets lie, and tell ld we have 1 byte left.
+ */
+ if (chars == 0) {
+ /*
+ * If TBUSY is still set, and our tx buffers are empty,
+ * force the firmware to send me another wakeup after
+ * TBUSY has been cleared.
+ */
+ if (tbusy != 0) {
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+ un->un_flags |= UN_EMPTY;
+ writeb(1, &(bs->iempty));
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+ }
+ chars = 1;
+ }
+ }
+
+ DPR_WRITE(("dgap_tty_chars_in_buffer. Port: %x - %d (head: %d tail: %d tsize: %d)\n",
+ ch->ch_portnum, chars, thead, ttail, ch->ch_tsize));
+ return(chars);
+}
+
+
+static int dgap_wait_for_drain(struct tty_struct *tty)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ struct bs_t *bs;
+ int ret = -EIO;
+ uint count = 1;
+ ulong lock_flags = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return ret;
+
+ bs = ch->ch_bs;
+ if (!bs)
+ return ret;
+
+ ret = 0;
+
+ DPR_DRAIN(("dgap_wait_for_drain start\n"));
+
+ /* Loop until data is drained */
+ while (count != 0) {
+
+ count = dgap_tty_chars_in_buffer(tty);
+
+ if (count == 0)
+ break;
+
+ /* Set flag waiting for drain */
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+ un->un_flags |= UN_EMPTY;
+ writeb(1, &(bs->iempty));
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ /* Go to sleep till we get woken up */
+ ret = wait_event_interruptible(un->un_flags_wait, ((un->un_flags & UN_EMPTY) == 0));
+ /* If ret is non-zero, user ctrl-c'ed us */
+ if (ret) {
+ break;
+ }
+ }
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+ un->un_flags &= ~(UN_EMPTY);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_DRAIN(("dgap_wait_for_drain finish\n"));
+ return (ret);
+}
+
+
+/*
+ * dgap_maxcps_room
+ *
+ * Reduces bytes_available to the max number of characters
+ * that can be sent currently given the maxcps value, and
+ * returns the new bytes_available. This only affects printer
+ * output.
+ */
+static int dgap_maxcps_room(struct tty_struct *tty, int bytes_available)
+{
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+
+ if (tty == NULL)
+ return (bytes_available);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (bytes_available);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (bytes_available);
+
+ /*
+ * If its not the Transparent print device, return
+ * the full data amount.
+ */
+ if (un->un_type != DGAP_PRINT)
+ return (bytes_available);
+
+ if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0 ) {
+ int cps_limit = 0;
+ unsigned long current_time = jiffies;
+ unsigned long buffer_time = current_time +
+ (HZ * ch->ch_digi.digi_bufsize) / ch->ch_digi.digi_maxcps;
+
+ if (ch->ch_cpstime < current_time) {
+ /* buffer is empty */
+ ch->ch_cpstime = current_time; /* reset ch_cpstime */
+ cps_limit = ch->ch_digi.digi_bufsize;
+ }
+ else if (ch->ch_cpstime < buffer_time) {
+ /* still room in the buffer */
+ cps_limit = ((buffer_time - ch->ch_cpstime) * ch->ch_digi.digi_maxcps) / HZ;
+ }
+ else {
+ /* no room in the buffer */
+ cps_limit = 0;
+ }
+
+ bytes_available = min(cps_limit, bytes_available);
+ }
+
+ return (bytes_available);
+}
+
+
+static inline void dgap_set_firmware_event(struct un_t *un, unsigned int event)
+{
+ struct channel_t *ch = NULL;
+ struct bs_t *bs = NULL;
+
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+ bs = ch->ch_bs;
+ if (!bs)
+ return;
+
+ if ((event & UN_LOW) != 0) {
+ if ((un->un_flags & UN_LOW) == 0) {
+ un->un_flags |= UN_LOW;
+ writeb(1, &(bs->ilow));
+ }
+ }
+ if ((event & UN_LOW) != 0) {
+ if ((un->un_flags & UN_EMPTY) == 0) {
+ un->un_flags |= UN_EMPTY;
+ writeb(1, &(bs->iempty));
+ }
+ }
+}
+
+
+/*
+ * dgap_tty_write_room()
+ *
+ * Return space available in Tx buffer
+ */
+static int dgap_tty_write_room(struct tty_struct *tty)
+{
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+ struct bs_t *bs = NULL;
+ u16 head, tail, tmask;
+ int ret = 0;
+ ulong lock_flags = 0;
+
+ if (tty == NULL || dgap_TmpWriteBuf == NULL)
+ return(0);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (0);
+
+ bs = ch->ch_bs;
+ if (!bs)
+ return (0);
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+
+ tmask = ch->ch_tsize - 1;
+ head = readw(&(bs->tx_head)) & tmask;
+ tail = readw(&(bs->tx_tail)) & tmask;
+
+ if ((ret = tail - head - 1) < 0)
+ ret += ch->ch_tsize;
+
+ /* Limit printer to maxcps */
+ ret = dgap_maxcps_room(tty, ret);
+
+ /*
+ * If we are printer device, leave space for
+ * possibly both the on and off strings.
+ */
+ if (un->un_type == DGAP_PRINT) {
+ if (!(ch->ch_flags & CH_PRON))
+ ret -= ch->ch_digi.digi_onlen;
+ ret -= ch->ch_digi.digi_offlen;
+ }
+ else {
+ if (ch->ch_flags & CH_PRON)
+ ret -= ch->ch_digi.digi_offlen;
+ }
+
+ if (ret < 0)
+ ret = 0;
+
+ /*
+ * Schedule FEP to wake us up if needed.
+ *
+ * TODO: This might be overkill...
+ * Do we really need to schedule callbacks from the FEP
+ * in every case? Can we get smarter based on ret?
+ */
+ dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_WRITE(("dgap_tty_write_room - %d tail: %d head: %d\n", ret, tail, head));
+
+ return(ret);
+}
+
+
+/*
+ * dgap_tty_put_char()
+ *
+ * Put a character into ch->ch_buf
+ *
+ * - used by the line discipline for OPOST processing
+ */
+static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c)
+{
+ /*
+ * Simply call tty_write.
+ */
+ DPR_WRITE(("dgap_tty_put_char called\n"));
+ dgap_tty_write(tty, &c, 1);
+ return 1;
+}
+
+
+/*
+ * dgap_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+ struct bs_t *bs = NULL;
+ char *vaddr = NULL;
+ u16 head, tail, tmask, remain;
+ int bufcount = 0, n = 0;
+ int orig_count = 0;
+ ulong lock_flags;
+ int from_user = 0;
+
+ if (tty == NULL || dgap_TmpWriteBuf == NULL)
+ return(0);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (0);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return(0);
+
+ bs = ch->ch_bs;
+ if (!bs)
+ return(0);
+
+ if (!count)
+ return(0);
+
+ DPR_WRITE(("dgap_tty_write: Port: %x tty=%p user=%d len=%d\n",
+ ch->ch_portnum, tty, from_user, count));
+
+ /*
+ * Store original amount of characters passed in.
+ * This helps to figure out if we should ask the FEP
+ * to send us an event when it has more space available.
+ */
+ orig_count = count;
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+
+ /* Get our space available for the channel from the board */
+ tmask = ch->ch_tsize - 1;
+ head = readw(&(bs->tx_head)) & tmask;
+ tail = readw(&(bs->tx_tail)) & tmask;
+
+ if ((bufcount = tail - head - 1) < 0)
+ bufcount += ch->ch_tsize;
+
+ DPR_WRITE(("%d: bufcount: %x count: %x tail: %x head: %x tmask: %x\n",
+ __LINE__, bufcount, count, tail, head, tmask));
+
+ /*
+ * Limit printer output to maxcps overall, with bursts allowed
+ * up to bufsize characters.
+ */
+ bufcount = dgap_maxcps_room(tty, bufcount);
+
+ /*
+ * Take minimum of what the user wants to send, and the
+ * space available in the FEP buffer.
+ */
+ count = min(count, bufcount);
+
+ /*
+ * Bail if no space left.
+ */
+ if (count <= 0) {
+ dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+ return(0);
+ }
+
+ /*
+ * Output the printer ON string, if we are in terminal mode, but
+ * need to be in printer mode.
+ */
+ if ((un->un_type == DGAP_PRINT) && !(ch->ch_flags & CH_PRON)) {
+ dgap_wmove(ch, ch->ch_digi.digi_onstr,
+ (int) ch->ch_digi.digi_onlen);
+ head = readw(&(bs->tx_head)) & tmask;
+ ch->ch_flags |= CH_PRON;
+ }
+
+ /*
+ * On the other hand, output the printer OFF string, if we are
+ * currently in printer mode, but need to output to the terminal.
+ */
+ if ((un->un_type != DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
+ dgap_wmove(ch, ch->ch_digi.digi_offstr,
+ (int) ch->ch_digi.digi_offlen);
+ head = readw(&(bs->tx_head)) & tmask;
+ ch->ch_flags &= ~CH_PRON;
+ }
+
+ /*
+ * If there is nothing left to copy, or I can't handle any more data, leave.
+ */
+ if (count <= 0) {
+ dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+ return(0);
+ }
+
+ if (from_user) {
+
+ count = min(count, WRITEBUFLEN);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * If data is coming from user space, copy it into a temporary
+ * buffer so we don't get swapped out while doing the copy to
+ * the board.
+ */
+ /* we're allowed to block if it's from_user */
+ if (down_interruptible(&dgap_TmpWriteSem)) {
+ return (-EINTR);
+ }
+
+ if (copy_from_user(dgap_TmpWriteBuf, (const uchar __user *) buf, count)) {
+ up(&dgap_TmpWriteSem);
+ printk("Write: Copy from user failed!\n");
+ return -EFAULT;
+ }
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+
+ buf = dgap_TmpWriteBuf;
+ }
+
+ n = count;
+
+ /*
+ * If the write wraps over the top of the circular buffer,
+ * move the portion up to the wrap point, and reset the
+ * pointers to the bottom.
+ */
+ remain = ch->ch_tstart + ch->ch_tsize - head;
+
+ if (n >= remain) {
+ n -= remain;
+ vaddr = ch->ch_taddr + head;
+
+ memcpy_toio(vaddr, (uchar *) buf, remain);
+ dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain);
+
+ head = ch->ch_tstart;
+ buf += remain;
+ }
+
+ if (n > 0) {
+
+ /*
+ * Move rest of data.
+ */
+ vaddr = ch->ch_taddr + head;
+ remain = n;
+
+ memcpy_toio(vaddr, (uchar *) buf, remain);
+ dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain);
+
+ head += remain;
+
+ }
+
+ if (count) {
+ ch->ch_txcount += count;
+ head &= tmask;
+ writew(head, &(bs->tx_head));
+ }
+
+
+ dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+
+ /*
+ * If this is the print device, and the
+ * printer is still on, we need to turn it
+ * off before going idle. If the buffer is
+ * non-empty, wait until it goes empty.
+ * Otherwise turn it off right now.
+ */
+ if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
+ tail = readw(&(bs->tx_tail)) & tmask;
+
+ if (tail != head) {
+ un->un_flags |= UN_EMPTY;
+ writeb(1, &(bs->iempty));
+ }
+ else {
+ dgap_wmove(ch, ch->ch_digi.digi_offstr,
+ (int) ch->ch_digi.digi_offlen);
+ head = readw(&(bs->tx_head)) & tmask;
+ ch->ch_flags &= ~CH_PRON;
+ }
+ }
+
+ /* Update printer buffer empty time. */
+ if ((un->un_type == DGAP_PRINT) && (ch->ch_digi.digi_maxcps > 0)
+ && (ch->ch_digi.digi_bufsize > 0)) {
+ ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps;
+ }
+
+ if (from_user) {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+ up(&dgap_TmpWriteSem);
+ }
+ else {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+ }
+
+ DPR_WRITE(("Write finished - Write %d bytes of %d.\n", count, orig_count));
+
+ return (count);
+}
+
+
+
+/*
+ * Return modem signals to ld.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgap_tty_tiocmget(struct tty_struct *tty)
+#else
+static int dgap_tty_tiocmget(struct tty_struct *tty, struct file *file)
+#endif
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ int result = -EIO;
+ uchar mstat = 0;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return result;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return result;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return result;
+
+ DPR_IOCTL(("dgap_tty_tiocmget start\n"));
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+
+ mstat = readb(&(ch->ch_bs->m_stat));
+ /* Append any outbound signals that might be pending... */
+ mstat |= ch->ch_mostat;
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ result = 0;
+
+ if (mstat & D_DTR(ch))
+ result |= TIOCM_DTR;
+ if (mstat & D_RTS(ch))
+ result |= TIOCM_RTS;
+ if (mstat & D_CTS(ch))
+ result |= TIOCM_CTS;
+ if (mstat & D_DSR(ch))
+ result |= TIOCM_DSR;
+ if (mstat & D_RI(ch))
+ result |= TIOCM_RI;
+ if (mstat & D_CD(ch))
+ result |= TIOCM_CD;
+
+ DPR_IOCTL(("dgap_tty_tiocmget finish\n"));
+
+ return result;
+}
+
+
+/*
+ * dgap_tty_tiocmset()
+ *
+ * Set modem signals, called by ld.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgap_tty_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+#else
+static int dgap_tty_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+#endif
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int ret = -EIO;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return ret;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return ret;
+
+ DPR_IOCTL(("dgap_tty_tiocmset start\n"));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ if (set & TIOCM_RTS) {
+ ch->ch_mforce |= D_RTS(ch);
+ ch->ch_mval |= D_RTS(ch);
+ }
+
+ if (set & TIOCM_DTR) {
+ ch->ch_mforce |= D_DTR(ch);
+ ch->ch_mval |= D_DTR(ch);
+ }
+
+ if (clear & TIOCM_RTS) {
+ ch->ch_mforce |= D_RTS(ch);
+ ch->ch_mval &= ~(D_RTS(ch));
+ }
+
+ if (clear & TIOCM_DTR) {
+ ch->ch_mforce |= D_DTR(ch);
+ ch->ch_mval &= ~(D_DTR(ch));
+ }
+
+ dgap_param(tty);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_tiocmset finish\n"));
+
+ return (0);
+}
+
+
+
+/*
+ * dgap_tty_send_break()
+ *
+ * Send a Break, called by ld.
+ */
+static int dgap_tty_send_break(struct tty_struct *tty, int msec)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int ret = -EIO;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return ret;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return ret;
+
+ switch (msec) {
+ case -1:
+ msec = 0xFFFF;
+ break;
+ case 0:
+ msec = 1;
+ break;
+ default:
+ msec /= 10;
+ break;
+ }
+
+ DPR_IOCTL(("dgap_tty_send_break start 1. %lx\n", jiffies));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+#if 0
+ dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+#endif
+ dgap_cmdw(ch, SBREAK, (u16) msec, 0);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_send_break finish\n"));
+
+ return (0);
+}
+
+
+
+
+/*
+ * dgap_tty_wait_until_sent()
+ *
+ * wait until data has been transmitted, called by ld.
+ */
+static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ int rc;
+ rc = dgap_wait_for_drain(tty);
+ if (rc) {
+ DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+ return;
+ }
+ return;
+}
+
+
+
+/*
+ * dgap_send_xchar()
+ *
+ * send a high priority character, called by ld.
+ */
+static void dgap_tty_send_xchar(struct tty_struct *tty, char c)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgap_tty_send_xchar start 1. %lx\n", jiffies));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ /*
+ * This is technically what we should do.
+ * However, the NIST tests specifically want
+ * to see each XON or XOFF character that it
+ * sends, so lets just send each character
+ * by hand...
+ */
+#if 0
+ if (c == STOP_CHAR(tty)) {
+ dgap_cmdw(ch, RPAUSE, 0, 0);
+ }
+ else if (c == START_CHAR(tty)) {
+ dgap_cmdw(ch, RRESUME, 0, 0);
+ }
+ else {
+ dgap_wmove(ch, &c, 1);
+ }
+#else
+ dgap_wmove(ch, &c, 1);
+#endif
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_send_xchar finish\n"));
+
+ return;
+}
+
+
+
+
+/*
+ * Return modem signals to ld.
+ */
+static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value)
+{
+ int result = 0;
+ uchar mstat = 0;
+ ulong lock_flags;
+ int rc = 0;
+
+ DPR_IOCTL(("dgap_get_modem_info start\n"));
+
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return(-ENXIO);
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+
+ mstat = readb(&(ch->ch_bs->m_stat));
+ /* Append any outbound signals that might be pending... */
+ mstat |= ch->ch_mostat;
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ result = 0;
+
+ if (mstat & D_DTR(ch))
+ result |= TIOCM_DTR;
+ if (mstat & D_RTS(ch))
+ result |= TIOCM_RTS;
+ if (mstat & D_CTS(ch))
+ result |= TIOCM_CTS;
+ if (mstat & D_DSR(ch))
+ result |= TIOCM_DSR;
+ if (mstat & D_RI(ch))
+ result |= TIOCM_RI;
+ if (mstat & D_CD(ch))
+ result |= TIOCM_CD;
+
+ rc = put_user(result, value);
+
+ DPR_IOCTL(("dgap_get_modem_info finish\n"));
+ return(rc);
+}
+
+
+/*
+ * dgap_set_modem_info()
+ *
+ * Set modem signals, called by ld.
+ */
+static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int ret = -ENXIO;
+ unsigned int arg = 0;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return ret;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return ret;
+
+ DPR_IOCTL(("dgap_set_modem_info() start\n"));
+
+ ret = get_user(arg, value);
+ if (ret) {
+ DPR_IOCTL(("dgap_set_modem_info %d ret: %x. finished.\n", __LINE__, ret));
+ return(ret);
+ }
+
+ DPR_IOCTL(("dgap_set_modem_info: command: %x arg: %x\n", command, arg));
+
+ switch (command) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS) {
+ ch->ch_mforce |= D_RTS(ch);
+ ch->ch_mval |= D_RTS(ch);
+ }
+
+ if (arg & TIOCM_DTR) {
+ ch->ch_mforce |= D_DTR(ch);
+ ch->ch_mval |= D_DTR(ch);
+ }
+
+ break;
+
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS) {
+ ch->ch_mforce |= D_RTS(ch);
+ ch->ch_mval &= ~(D_RTS(ch));
+ }
+
+ if (arg & TIOCM_DTR) {
+ ch->ch_mforce |= D_DTR(ch);
+ ch->ch_mval &= ~(D_DTR(ch));
+ }
+
+ break;
+
+ case TIOCMSET:
+ ch->ch_mforce = D_DTR(ch)|D_RTS(ch);
+
+ if (arg & TIOCM_RTS) {
+ ch->ch_mval |= D_RTS(ch);
+ }
+ else {
+ ch->ch_mval &= ~(D_RTS(ch));
+ }
+
+ if (arg & TIOCM_DTR) {
+ ch->ch_mval |= (D_DTR(ch));
+ }
+ else {
+ ch->ch_mval &= ~(D_DTR(ch));
+ }
+
+ break;
+
+ default:
+ return(-EINVAL);
+ }
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ dgap_param(tty);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_set_modem_info finish\n"));
+
+ return (0);
+}
+
+
+/*
+ * dgap_tty_digigeta()
+ *
+ * Ioctl to get the information for ditty.
+ *
+ *
+ *
+ */
+static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ struct digi_t tmp;
+ ulong lock_flags;
+
+ if (!retinfo)
+ return (-EFAULT);
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return (-EFAULT);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (-EFAULT);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (-EFAULT);
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+ memcpy(&tmp, &ch->ch_digi, sizeof(tmp));
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return (-EFAULT);
+
+ return (0);
+}
+
+
+/*
+ * dgap_tty_digiseta()
+ *
+ * Ioctl to set the information for ditty.
+ *
+ *
+ *
+ */
+static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ struct digi_t new_digi;
+ ulong lock_flags = 0;
+ unsigned long lock_flags2;
+
+ DPR_IOCTL(("DIGI_SETA start\n"));
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return (-EFAULT);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (-EFAULT);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (-EFAULT);
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (-EFAULT);
+
+ if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t))) {
+ DPR_IOCTL(("DIGI_SETA failed copy_from_user\n"));
+ return(-EFAULT);
+ }
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t));
+
+ if (ch->ch_digi.digi_maxcps < 1)
+ ch->ch_digi.digi_maxcps = 1;
+
+ if (ch->ch_digi.digi_maxcps > 10000)
+ ch->ch_digi.digi_maxcps = 10000;
+
+ if (ch->ch_digi.digi_bufsize < 10)
+ ch->ch_digi.digi_bufsize = 10;
+
+ if (ch->ch_digi.digi_maxchar < 1)
+ ch->ch_digi.digi_maxchar = 1;
+
+ if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize)
+ ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize;
+
+ if (ch->ch_digi.digi_onlen > DIGI_PLEN)
+ ch->ch_digi.digi_onlen = DIGI_PLEN;
+
+ if (ch->ch_digi.digi_offlen > DIGI_PLEN)
+ ch->ch_digi.digi_offlen = DIGI_PLEN;
+
+ dgap_param(tty);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("DIGI_SETA finish\n"));
+
+ return(0);
+}
+
+
+/*
+ * dgap_tty_digigetedelay()
+ *
+ * Ioctl to get the current edelay setting.
+ *
+ *
+ *
+ */
+static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ int tmp;
+ ulong lock_flags;
+
+ if (!retinfo)
+ return (-EFAULT);
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return (-EFAULT);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (-EFAULT);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (-EFAULT);
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+ tmp = readw(&(ch->ch_bs->edelay));
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return (-EFAULT);
+
+ return (0);
+}
+
+
+/*
+ * dgap_tty_digisetedelay()
+ *
+ * Ioctl to set the EDELAY setting
+ *
+ */
+static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int new_digi;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ DPR_IOCTL(("DIGI_SETA start\n"));
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return (-EFAULT);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (-EFAULT);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (-EFAULT);
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (-EFAULT);
+
+ if (copy_from_user(&new_digi, new_info, sizeof(int))) {
+ DPR_IOCTL(("DIGI_SETEDELAY failed copy_from_user\n"));
+ return(-EFAULT);
+ }
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ writew((u16) new_digi, &(ch->ch_bs->edelay));
+
+ dgap_param(tty);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("DIGI_SETA finish\n"));
+
+ return(0);
+}
+
+
+/*
+ * dgap_tty_digigetcustombaud()
+ *
+ * Ioctl to get the current custom baud rate setting.
+ */
+static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ int tmp;
+ ulong lock_flags;
+
+ if (!retinfo)
+ return (-EFAULT);
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return (-EFAULT);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (-EFAULT);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (-EFAULT);
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ DGAP_LOCK(ch->ch_lock, lock_flags);
+ tmp = dgap_get_custom_baud(ch);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("DIGI_GETCUSTOMBAUD. Returning %d\n", tmp));
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return (-EFAULT);
+
+ return (0);
+}
+
+
+/*
+ * dgap_tty_digisetcustombaud()
+ *
+ * Ioctl to set the custom baud rate setting
+ */
+static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ uint new_rate;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ DPR_IOCTL(("DIGI_SETCUSTOMBAUD start\n"));
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return (-EFAULT);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (-EFAULT);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (-EFAULT);
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (-EFAULT);
+
+
+ if (copy_from_user(&new_rate, new_info, sizeof(unsigned int))) {
+ DPR_IOCTL(("DIGI_SETCUSTOMBAUD failed copy_from_user\n"));
+ return(-EFAULT);
+ }
+
+ if (bd->bd_flags & BD_FEP5PLUS) {
+
+ DPR_IOCTL(("DIGI_SETCUSTOMBAUD. Setting %d\n", new_rate));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ ch->ch_custom_speed = new_rate;
+
+ dgap_param(tty);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ }
+
+ DPR_IOCTL(("DIGI_SETCUSTOMBAUD finish\n"));
+
+ return(0);
+}
+
+
+/*
+ * dgap_set_termios()
+ */
+static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ unsigned long lock_flags;
+ unsigned long lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ ch->ch_c_cflag = tty->termios.c_cflag;
+ ch->ch_c_iflag = tty->termios.c_iflag;
+ ch->ch_c_oflag = tty->termios.c_oflag;
+ ch->ch_c_lflag = tty->termios.c_lflag;
+ ch->ch_startc = tty->termios.c_cc[VSTART];
+ ch->ch_stopc = tty->termios.c_cc[VSTOP];
+
+ dgap_carrier(ch);
+ dgap_param(tty);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+}
+
+
+static void dgap_tty_throttle(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgap_tty_throttle start\n"));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ ch->ch_flags |= (CH_RXBLOCK);
+#if 1
+ dgap_cmdw(ch, RPAUSE, 0, 0);
+#endif
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_throttle finish\n"));
+}
+
+
+static void dgap_tty_unthrottle(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgap_tty_unthrottle start\n"));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ ch->ch_flags &= ~(CH_RXBLOCK);
+
+#if 1
+ dgap_cmdw(ch, RRESUME, 0, 0);
+#endif
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_unthrottle finish\n"));
+}
+
+
+static void dgap_tty_start(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgap_tty_start start\n"));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ dgap_cmdw(ch, RESUMETX, 0, 0);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_start finish\n"));
+}
+
+
+static void dgap_tty_stop(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgap_tty_stop start\n"));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ dgap_cmdw(ch, PAUSETX, 0, 0);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_stop finish\n"));
+}
+
+
+/*
+ * dgap_tty_flush_chars()
+ *
+ * Flush the cook buffer
+ *
+ * Note to self, and any other poor souls who venture here:
+ *
+ * flush in this case DOES NOT mean dispose of the data.
+ * instead, it means "stop buffering and send it if you
+ * haven't already." Just guess how I figured that out... SRW 2-Jun-98
+ *
+ * It is also always called in interrupt context - JAR 8-Sept-99
+ */
+static void dgap_tty_flush_chars(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgap_tty_flush_chars start\n"));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ /* TODO: Do something here */
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_flush_chars finish\n"));
+}
+
+
+
+/*
+ * dgap_tty_flush_buffer()
+ *
+ * Flush Tx buffer (make in == out)
+ */
+static void dgap_tty_flush_buffer(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ ulong lock_flags2;
+ u16 head = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgap_tty_flush_buffer on port: %d start\n", ch->ch_portnum));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ ch->ch_flags &= ~CH_STOP;
+ head = readw(&(ch->ch_bs->tx_head));
+ dgap_cmdw(ch, FLUSHTX, (u16) head, 0);
+ dgap_cmdw(ch, RESUMETX, 0, 0);
+ if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+ }
+ if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+ }
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ if (waitqueue_active(&tty->write_wait))
+ wake_up_interruptible(&tty->write_wait);
+ tty_wakeup(tty);
+
+ DPR_IOCTL(("dgap_tty_flush_buffer finish\n"));
+}
+
+
+
+/*****************************************************************************
+ *
+ * The IOCTL function and all of its helpers
+ *
+ *****************************************************************************/
+
+/*
+ * dgap_tty_ioctl()
+ *
+ * The usual assortment of ioctl's
+ */
+static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
+ unsigned long arg)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int rc;
+ u16 head = 0;
+ ulong lock_flags = 0;
+ ulong lock_flags2 = 0;
+ void __user *uarg = (void __user *) arg;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return (-ENODEV);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGAP_UNIT_MAGIC)
+ return (-ENODEV);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+ return (-ENODEV);
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+ return (-ENODEV);
+
+ DPR_IOCTL(("dgap_tty_ioctl start on port %d - cmd %s (%x), arg %lx\n",
+ ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ if (un->un_open_count <= 0) {
+ DPR_BASIC(("dgap_tty_ioctl - unit not open.\n"));
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(-EIO);
+ }
+
+ switch (cmd) {
+
+ /* Here are all the standard ioctl's that we MUST implement */
+
+ case TCSBRK:
+ /*
+ * TCSBRK is SVID version: non-zero arg --> no break
+ * this behaviour is exploited by tcdrain().
+ *
+ * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+ * between 0.25 and 0.5 seconds so we'll ask for something
+ * in the middle: 0.375 seconds.
+ */
+ rc = tty_check_change(tty);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ if (rc) {
+ return(rc);
+ }
+
+ rc = dgap_wait_for_drain(tty);
+
+ if (rc) {
+ DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ if(((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) {
+ dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+ }
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+ ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+ return(0);
+
+
+ case TCSBRKP:
+ /* support for POSIX tcsendbreak()
+
+ * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+ * between 0.25 and 0.5 seconds so we'll ask for something
+ * in the middle: 0.375 seconds.
+ */
+ rc = tty_check_change(tty);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ if (rc) {
+ return(rc);
+ }
+
+ rc = dgap_wait_for_drain(tty);
+ if (rc) {
+ DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+ ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+ return(0);
+
+ case TIOCSBRK:
+ /*
+ * FEP5 doesn't support turning on a break unconditionally.
+ * The FEP5 device will stop sending a break automatically
+ * after the specified time value that was sent when turning on
+ * the break.
+ */
+ rc = tty_check_change(tty);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ if (rc) {
+ return(rc);
+ }
+
+ rc = dgap_wait_for_drain(tty);
+ if (rc) {
+ DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+ dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+ ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+ return 0;
+
+ case TIOCCBRK:
+ /*
+ * FEP5 doesn't support turning off a break unconditionally.
+ * The FEP5 device will stop sending a break automatically
+ * after the specified time value that was sent when turning on
+ * the break.
+ */
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return 0;
+
+ case TIOCGSOFTCAR:
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg);
+ return(rc);
+
+ case TIOCSSOFTCAR:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ rc = get_user(arg, (unsigned long __user *) arg);
+ if (rc)
+ return(rc);
+
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+ tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+ dgap_param(tty);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ return(0);
+
+ case TIOCMGET:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(dgap_get_modem_info(ch, uarg));
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(dgap_set_modem_info(tty, cmd, uarg));
+
+ /*
+ * Here are any additional ioctl's that we want to implement
+ */
+
+ case TCFLSH:
+ /*
+ * The linux tty driver doesn't have a flush
+ * input routine for the driver, assuming all backed
+ * up data is in the line disc. buffers. However,
+ * we all know that's not the case. Here, we
+ * act on the ioctl, but then lie and say we didn't
+ * so the line discipline will process the flush
+ * also.
+ */
+ rc = tty_check_change(tty);
+ if (rc) {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(rc);
+ }
+
+ if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) {
+ if (!(un->un_type == DGAP_PRINT)) {
+ head = readw(&(ch->ch_bs->rx_head));
+ writew(head, &(ch->ch_bs->rx_tail));
+ writeb(0, &(ch->ch_bs->orun));
+ }
+ }
+
+ if ((arg == TCOFLUSH) || (arg == TCIOFLUSH)) {
+ ch->ch_flags &= ~CH_STOP;
+ head = readw(&(ch->ch_bs->tx_head));
+ dgap_cmdw(ch, FLUSHTX, (u16) head, 0 );
+ dgap_cmdw(ch, RESUMETX, 0, 0);
+ if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+ }
+ if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+ }
+ if (waitqueue_active(&tty->write_wait))
+ wake_up_interruptible(&tty->write_wait);
+
+ /* Can't hold any locks when calling tty_wakeup! */
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ tty_wakeup(tty);
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+ }
+
+ /* pretend we didn't recognize this IOCTL */
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_ioctl (LINE:%d) finish on port %d - cmd %s (%x), arg %lx\n",
+ __LINE__, ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+ return(-ENOIOCTLCMD);
+
+ case TCSETSF:
+ case TCSETSW:
+ /*
+ * The linux tty driver doesn't have a flush
+ * input routine for the driver, assuming all backed
+ * up data is in the line disc. buffers. However,
+ * we all know that's not the case. Here, we
+ * act on the ioctl, but then lie and say we didn't
+ * so the line discipline will process the flush
+ * also.
+ */
+ if (cmd == TCSETSF) {
+ /* flush rx */
+ ch->ch_flags &= ~CH_STOP;
+ head = readw(&(ch->ch_bs->rx_head));
+ writew(head, &(ch->ch_bs->rx_tail));
+ }
+
+ /* now wait for all the output to drain */
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ rc = dgap_wait_for_drain(tty);
+ if (rc) {
+ DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+
+ DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+ ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+ /* pretend we didn't recognize this */
+ return(-ENOIOCTLCMD);
+
+ case TCSETAW:
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ rc = dgap_wait_for_drain(tty);
+ if (rc) {
+ DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+
+ /* pretend we didn't recognize this */
+ return(-ENOIOCTLCMD);
+
+ case TCXONC:
+ /*
+ * The Linux Line Discipline (LD) would do this for us if we
+ * let it, but we have the special firmware options to do this
+ * the "right way" regardless of hardware or software flow
+ * control so we'll do it outselves instead of letting the LD
+ * do it.
+ */
+ rc = tty_check_change(tty);
+ if (rc) {
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(rc);
+ }
+
+ DPR_IOCTL(("dgap_ioctl - in TCXONC - %d\n", cmd));
+ switch (arg) {
+
+ case TCOON:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ dgap_tty_start(tty);
+ return(0);
+ case TCOOFF:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ dgap_tty_stop(tty);
+ return(0);
+ case TCION:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ /* Make the ld do it */
+ return(-ENOIOCTLCMD);
+ case TCIOFF:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ /* Make the ld do it */
+ return(-ENOIOCTLCMD);
+ default:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(-EINVAL);
+ }
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(-ENOIOCTLCMD);
+
+ case DIGI_GETA:
+ /* get information for ditty */
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(dgap_tty_digigeta(tty, uarg));
+
+ case DIGI_SETAW:
+ case DIGI_SETAF:
+
+ /* set information for ditty */
+ if (cmd == (DIGI_SETAW)) {
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ rc = dgap_wait_for_drain(tty);
+ if (rc) {
+ DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+ DGAP_LOCK(bd->bd_lock, lock_flags);
+ DGAP_LOCK(ch->ch_lock, lock_flags2);
+ }
+ else {
+ tty_ldisc_flush(tty);
+ }
+ /* fall thru */
+
+ case DIGI_SETA:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(dgap_tty_digiseta(tty, uarg));
+
+ case DIGI_GEDELAY:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(dgap_tty_digigetedelay(tty, uarg));
+
+ case DIGI_SEDELAY:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(dgap_tty_digisetedelay(tty, uarg));
+
+ case DIGI_GETCUSTOMBAUD:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(dgap_tty_digigetcustombaud(tty, uarg));
+
+ case DIGI_SETCUSTOMBAUD:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return(dgap_tty_digisetcustombaud(tty, uarg));
+
+ case DIGI_RESET_PORT:
+ dgap_firmware_reset_port(ch);
+ dgap_param(tty);
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+ return 0;
+
+ default:
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_ioctl - in default\n"));
+ DPR_IOCTL(("dgap_tty_ioctl end - cmd %s (%x), arg %lx\n",
+ dgap_ioctl_name(cmd), cmd, arg));
+
+ return(-ENOIOCTLCMD);
+ }
+
+ DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+ DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+ DPR_IOCTL(("dgap_tty_ioctl end - cmd %s (%x), arg %lx\n",
+ dgap_ioctl_name(cmd), cmd, arg));
+
+ return(0);
+}
diff --git a/drivers/staging/dgap/dgap_tty.h b/drivers/staging/dgap/dgap_tty.h
new file mode 100644
index 00000000000..464a460b6be
--- /dev/null
+++ b/drivers/staging/dgap/dgap_tty.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGAP_TTY_H
+#define __DGAP_TTY_H
+
+#include "dgap_driver.h"
+
+int dgap_tty_register(struct board_t *brd);
+
+int dgap_tty_preinit(void);
+int dgap_tty_init(struct board_t *);
+
+void dgap_tty_post_uninit(void);
+void dgap_tty_uninit(struct board_t *);
+
+void dgap_carrier(struct channel_t *ch);
+void dgap_input(struct channel_t *ch);
+
+
+#endif
diff --git a/drivers/staging/dgap/dgap_types.h b/drivers/staging/dgap/dgap_types.h
new file mode 100644
index 00000000000..eca38c7f359
--- /dev/null
+++ b/drivers/staging/dgap/dgap_types.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGAP_TYPES_H
+#define __DGAP_TYPES_H
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+/* Required for our shared headers! */
+typedef unsigned char uchar;
+
+#endif
diff --git a/drivers/staging/dgap/digi.h b/drivers/staging/dgap/digi.h
new file mode 100644
index 00000000000..651e2e5e93c
--- /dev/null
+++ b/drivers/staging/dgap/digi.h
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: digi.h,v 1.1 2009/10/23 14:01:57 markh Exp $
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DIGI_H
+#define __DIGI_H
+
+/************************************************************************
+ *** Definitions for Digi ditty(1) command.
+ ************************************************************************/
+
+
+/*
+ * Copyright (c) 1988-96 Digi International Inc., All Rights Reserved.
+ */
+
+/************************************************************************
+ * This module provides application access to special Digi
+ * serial line enhancements which are not standard UNIX(tm) features.
+ ************************************************************************/
+
+#if !defined(TIOCMODG)
+
+#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */
+#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */
+
+#ifndef TIOCM_LE
+#define TIOCM_LE 0x01 /* line enable */
+#define TIOCM_DTR 0x02 /* data terminal ready */
+#define TIOCM_RTS 0x04 /* request to send */
+#define TIOCM_ST 0x08 /* secondary transmit */
+#define TIOCM_SR 0x10 /* secondary receive */
+#define TIOCM_CTS 0x20 /* clear to send */
+#define TIOCM_CAR 0x40 /* carrier detect */
+#define TIOCM_RNG 0x80 /* ring indicator */
+#define TIOCM_DSR 0x100 /* data set ready */
+#define TIOCM_RI TIOCM_RNG /* ring (alternate) */
+#define TIOCM_CD TIOCM_CAR /* carrier detect (alt) */
+#endif
+
+#endif
+
+#if !defined(TIOCMSET)
+#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */
+#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */
+#endif
+
+#if !defined(TIOCMBIC)
+#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */
+#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */
+#endif
+
+
+#if !defined(TIOCSDTR)
+#define TIOCSDTR ('e'<<8) | 0 /* set DTR */
+#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */
+#endif
+
+/************************************************************************
+ * Ioctl command arguments for DIGI parameters.
+ ************************************************************************/
+#define DIGI_GETA ('e'<<8) | 94 /* Read params */
+
+#define DIGI_SETA ('e'<<8) | 95 /* Set params */
+#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */
+#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */
+
+#define DIGI_KME ('e'<<8) | 98 /* Read/Write Host */
+ /* Adapter Memory */
+
+#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */
+ /* control characters */
+#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */
+ /* control characters */
+#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */
+ /* flow control chars */
+#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */
+ /* flow control chars */
+
+#define DIGI_GEDELAY ('d'<<8) | 246 /* Get edelay */
+#define DIGI_SEDELAY ('d'<<8) | 247 /* Set edelay */
+
+struct digiflow_t {
+ unsigned char startc; /* flow cntl start char */
+ unsigned char stopc; /* flow cntl stop char */
+};
+
+
+#ifdef FLOW_2200
+#define F2200_GETA ('e'<<8) | 104 /* Get 2x36 flow cntl flags */
+#define F2200_SETAW ('e'<<8) | 105 /* Set 2x36 flow cntl flags */
+#define F2200_MASK 0x03 /* 2200 flow cntl bit mask */
+#define FCNTL_2200 0x01 /* 2x36 terminal flow cntl */
+#define PCNTL_2200 0x02 /* 2x36 printer flow cntl */
+#define F2200_XON 0xf8
+#define P2200_XON 0xf9
+#define F2200_XOFF 0xfa
+#define P2200_XOFF 0xfb
+
+#define FXOFF_MASK 0x03 /* 2200 flow status mask */
+#define RCVD_FXOFF 0x01 /* 2x36 Terminal XOFF rcvd */
+#define RCVD_PXOFF 0x02 /* 2x36 Printer XOFF rcvd */
+#endif
+
+/************************************************************************
+ * Values for digi_flags
+ ************************************************************************/
+#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */
+#define DIGI_FAST 0x0002 /* Fast baud rates */
+#define RTSPACE 0x0004 /* RTS input flow control */
+#define CTSPACE 0x0008 /* CTS output flow control */
+#define DSRPACE 0x0010 /* DSR output flow control */
+#define DCDPACE 0x0020 /* DCD output flow control */
+#define DTRPACE 0x0040 /* DTR input flow control */
+#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */
+#define DIGI_FORCEDCD 0x0100 /* Force carrier */
+#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
+#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
+#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl*/
+#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input*/
+#define DIGI_DTR_TOGGLE 0x2000 /* Support DTR Toggle */
+#define DIGI_422 0x4000 /* for 422/232 selectable panel */
+#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */
+
+/************************************************************************
+ * These options are not supported on the comxi.
+ ************************************************************************/
+#define DIGI_COMXI (DIGI_FAST|DIGI_COOK|DSRPACE|DCDPACE|DTRPACE)
+
+#define DIGI_PLEN 28 /* String length */
+#define DIGI_TSIZ 10 /* Terminal string len */
+
+/************************************************************************
+ * Structure used with ioctl commands for DIGI parameters.
+ ************************************************************************/
+struct digi_t {
+ unsigned short digi_flags; /* Flags (see above) */
+ unsigned short digi_maxcps; /* Max printer CPS */
+ unsigned short digi_maxchar; /* Max chars in print queue */
+ unsigned short digi_bufsize; /* Buffer size */
+ unsigned char digi_onlen; /* Length of ON string */
+ unsigned char digi_offlen; /* Length of OFF string */
+ char digi_onstr[DIGI_PLEN]; /* Printer on string */
+ char digi_offstr[DIGI_PLEN]; /* Printer off string */
+ char digi_term[DIGI_TSIZ]; /* terminal string */
+};
+
+/************************************************************************
+ * KME definitions and structures.
+ ************************************************************************/
+#define RW_IDLE 0 /* Operation complete */
+#define RW_READ 1 /* Read Concentrator Memory */
+#define RW_WRITE 2 /* Write Concentrator Memory */
+
+struct rw_t {
+ unsigned char rw_req; /* Request type */
+ unsigned char rw_board; /* Host Adapter board number */
+ unsigned char rw_conc; /* Concentrator number */
+ unsigned char rw_reserved; /* Reserved for expansion */
+ unsigned long rw_addr; /* Address in concentrator */
+ unsigned short rw_size; /* Read/write request length */
+ unsigned char rw_data[128]; /* Data to read/write */
+};
+
+/***********************************************************************
+ * Shrink Buffer and Board Information definitions and structures.
+
+ ************************************************************************/
+ /* Board type return codes */
+#define PCXI_TYPE 1 /* Board type at the designated port is a PC/Xi */
+#define PCXM_TYPE 2 /* Board type at the designated port is a PC/Xm */
+#define PCXE_TYPE 3 /* Board type at the designated port is a PC/Xe */
+#define MCXI_TYPE 4 /* Board type at the designated port is a MC/Xi */
+#define COMXI_TYPE 5 /* Board type at the designated port is a COM/Xi */
+
+ /* Non-Zero Result codes. */
+#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */
+#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */
+#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */
+#define RESULT_TOOSML 4 /* Too small an area to shrink. */
+#define RESULT_NOCHAN 5 /* Channel structure for the board was not found */
+
+struct shrink_buf_struct {
+ unsigned long shrink_buf_vaddr; /* Virtual address of board */
+ unsigned long shrink_buf_phys; /* Physical address of board */
+ unsigned long shrink_buf_bseg; /* Amount of board memory */
+ unsigned long shrink_buf_hseg; /* '186 Begining of Dual-Port */
+
+ unsigned long shrink_buf_lseg; /* '186 Begining of freed memory */
+ unsigned long shrink_buf_mseg; /* Linear address from start of
+ dual-port were freed memory
+ begins, host viewpoint. */
+
+ unsigned long shrink_buf_bdparam; /* Parameter for xxmemon and
+ xxmemoff */
+
+ unsigned long shrink_buf_reserva; /* Reserved */
+ unsigned long shrink_buf_reservb; /* Reserved */
+ unsigned long shrink_buf_reservc; /* Reserved */
+ unsigned long shrink_buf_reservd; /* Reserved */
+
+ unsigned char shrink_buf_result; /* Reason for call failing
+ Zero is Good return */
+ unsigned char shrink_buf_init; /* Non-Zero if it caused an
+ xxinit call. */
+
+ unsigned char shrink_buf_anports; /* Number of async ports */
+ unsigned char shrink_buf_snports; /* Number of sync ports */
+ unsigned char shrink_buf_type; /* Board type 1 = PC/Xi,
+ 2 = PC/Xm,
+ 3 = PC/Xe
+ 4 = MC/Xi
+ 5 = COMX/i */
+ unsigned char shrink_buf_card; /* Card number */
+
+};
+
+/************************************************************************
+ * Structure to get driver status information
+ ************************************************************************/
+struct digi_dinfo {
+ unsigned long dinfo_nboards; /* # boards configured */
+ char dinfo_reserved[12]; /* for future expansion */
+ char dinfo_version[16]; /* driver version */
+};
+
+#define DIGI_GETDD ('d'<<8) | 248 /* get driver info */
+
+/************************************************************************
+ * Structure used with ioctl commands for per-board information
+ *
+ * physsize and memsize differ when board has "windowed" memory
+ ************************************************************************/
+struct digi_info {
+ unsigned long info_bdnum; /* Board number (0 based) */
+ unsigned long info_ioport; /* io port address */
+ unsigned long info_physaddr; /* memory address */
+ unsigned long info_physsize; /* Size of host mem window */
+ unsigned long info_memsize; /* Amount of dual-port mem */
+ /* on board */
+ unsigned short info_bdtype; /* Board type */
+ unsigned short info_nports; /* number of ports */
+ char info_bdstate; /* board state */
+ char info_reserved[7]; /* for future expansion */
+};
+
+#define DIGI_GETBD ('d'<<8) | 249 /* get board info */
+
+struct digi_stat {
+ unsigned int info_chan; /* Channel number (0 based) */
+ unsigned int info_brd; /* Board number (0 based) */
+ unsigned long info_cflag; /* cflag for channel */
+ unsigned long info_iflag; /* iflag for channel */
+ unsigned long info_oflag; /* oflag for channel */
+ unsigned long info_mstat; /* mstat for channel */
+ unsigned long info_tx_data; /* tx_data for channel */
+ unsigned long info_rx_data; /* rx_data for channel */
+ unsigned long info_hflow; /* hflow for channel */
+ unsigned long info_reserved[8]; /* for future expansion */
+};
+
+#define DIGI_GETSTAT ('d'<<8) | 244 /* get board info */
+/************************************************************************
+ *
+ * Structure used with ioctl commands for per-channel information
+ *
+ ************************************************************************/
+struct digi_ch {
+ unsigned long info_bdnum; /* Board number (0 based) */
+ unsigned long info_channel; /* Channel index number */
+ unsigned long info_ch_cflag; /* Channel cflag */
+ unsigned long info_ch_iflag; /* Channel iflag */
+ unsigned long info_ch_oflag; /* Channel oflag */
+ unsigned long info_chsize; /* Channel structure size */
+ unsigned long info_sleep_stat; /* sleep status */
+ dev_t info_dev; /* device number */
+ unsigned char info_initstate; /* Channel init state */
+ unsigned char info_running; /* Channel running state */
+ long reserved[8]; /* reserved for future use */
+};
+
+/*
+* This structure is used with the DIGI_FEPCMD ioctl to
+* tell the driver which port to send the command for.
+*/
+struct digi_cmd {
+ int cmd;
+ int word;
+ int ncmds;
+ int chan; /* channel index (zero based) */
+ int bdid; /* board index (zero based) */
+};
+
+/*
+* info_sleep_stat defines
+*/
+#define INFO_RUNWAIT 0x0001
+#define INFO_WOPEN 0x0002
+#define INFO_TTIOW 0x0004
+#define INFO_CH_RWAIT 0x0008
+#define INFO_CH_WEMPTY 0x0010
+#define INFO_CH_WLOW 0x0020
+#define INFO_XXBUF_BUSY 0x0040
+
+#define DIGI_GETCH ('d'<<8) | 245 /* get board info */
+
+/* Board type definitions */
+
+#define SUBTYPE 0007
+#define T_PCXI 0000
+#define T_PCXM 0001
+#define T_PCXE 0002
+#define T_PCXR 0003
+#define T_SP 0004
+#define T_SP_PLUS 0005
+# define T_HERC 0000
+# define T_HOU 0001
+# define T_LON 0002
+# define T_CHA 0003
+#define FAMILY 0070
+#define T_COMXI 0000
+#define T_PCXX 0010
+#define T_CX 0020
+#define T_EPC 0030
+#define T_PCLITE 0040
+#define T_SPXX 0050
+#define T_AVXX 0060
+#define T_DXB 0070
+#define T_A2K_4_8 0070
+#define BUSTYPE 0700
+#define T_ISABUS 0000
+#define T_MCBUS 0100
+#define T_EISABUS 0200
+#define T_PCIBUS 0400
+
+/* Board State Definitions */
+
+#define BD_RUNNING 0x0
+#define BD_REASON 0x7f
+#define BD_NOTFOUND 0x1
+#define BD_NOIOPORT 0x2
+#define BD_NOMEM 0x3
+#define BD_NOBIOS 0x4
+#define BD_NOFEP 0x5
+#define BD_FAILED 0x6
+#define BD_ALLOCATED 0x7
+#define BD_TRIBOOT 0x8
+#define BD_BADKME 0x80
+
+#define DIGI_LOOPBACK ('d'<<8) | 252 /* Enable/disable UART internal loopback */
+#define DIGI_SPOLL ('d'<<8) | 254 /* change poller rate */
+
+#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */
+#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */
+#define DIGI_RESET_PORT ('e'<<8) | 93 /* Reset port */
+
+#endif /* DIGI_H */
diff --git a/drivers/staging/dgap/downld.c b/drivers/staging/dgap/downld.c
new file mode 100644
index 00000000000..57dfd6bafcf
--- /dev/null
+++ b/drivers/staging/dgap/downld.c
@@ -0,0 +1,798 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: downld.c,v 1.6 2009/01/14 14:10:54 markh Exp $
+ */
+
+/*
+** downld.c
+**
+** This is the daemon that sends the fep, bios, and concentrator images
+** from user space to the driver.
+** BUGS:
+** If the file changes in the middle of the download, you probably
+** will get what you deserve.
+**
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+
+#include "dgap_types.h"
+#include "digi.h"
+#include "dgap_fep5.h"
+
+#include "dgap_downld.h"
+
+#include <string.h>
+#include <malloc.h>
+#include <stddef.h>
+#include <unistd.h>
+
+char *pgm;
+void myperror();
+
+/*
+** This structure is used to keep track of the diferent images available
+** to give to the driver. It is arranged so that the things that are
+** constants or that have defaults are first inthe strucutre to simplify
+** the table of initializers.
+*/
+struct image_info {
+ short type; /* bios, fep, conc */
+ short family; /* boards this applies to */
+ short subtype; /* subtype */
+ int len; /* size of image */
+ char *image; /* ioctl struct + image */
+ char *name;
+ char *fname; /* filename of binary (i.e. "asfep.bin") */
+ char *pathname; /* pathname to this binary ("/etc/dgap/xrfep.bin"); */
+ time_t mtime; /* Last modification time */
+};
+
+#define IBIOS 0
+#define IFEP 1
+#define ICONC 2
+#define ICONFIG 3
+#define IBAD 4
+
+#define DEFAULT_LOC "/lib/firmware/dgap/"
+
+struct image_info *image_list;
+int nimages, count;
+
+struct image_info images[] = {
+{IBIOS, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxbios.bin", DEFAULT_LOC "fxbios.bin", 0 },
+{IFEP, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxfep.bin", DEFAULT_LOC "fxfep.bin", 0 },
+{ICONC, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxcon.bin", DEFAULT_LOC "fxcon.bin", 0 },
+
+{IBIOS, T_CX, SUBTYPE, 0, NULL, "C/X", "cxbios.bin", DEFAULT_LOC "cxbios.bin", 0 },
+{IFEP, T_CX, SUBTYPE, 0, NULL, "C/X", "cxhost.bin", DEFAULT_LOC "cxhost.bin", 0 },
+
+{IBIOS, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpbios.bin", DEFAULT_LOC "cxpbios.bin", 0 },
+{IFEP, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpfep.bin", DEFAULT_LOC "cxpfep.bin", 0 },
+
+{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "cxcon.bin", DEFAULT_LOC "cxcon.bin", 0 },
+{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmcxcon.bin", DEFAULT_LOC "ibmcxcon.bin", 0 },
+{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmencon.bin", DEFAULT_LOC "ibmencon.bin", 0 },
+
+{IBIOS, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrbios.bin", DEFAULT_LOC "xrbios.bin", 0 },
+{IFEP, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrfep.bin", DEFAULT_LOC "xrfep.bin", 0 },
+
+{IBIOS, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxbios.bin", DEFAULT_LOC "sxbios.bin", 0 },
+{IFEP, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxfep.bin", DEFAULT_LOC "sxfep.bin", 0 },
+
+{IBIOS, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcibios.bin", DEFAULT_LOC "pcibios.bin", 0 },
+{IFEP, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcifep.bin", DEFAULT_LOC "pcifep.bin", 0 },
+{ICONFIG, 0, 0, 0, NULL, NULL, "dgap.conf", "/etc/dgap.conf", 0 },
+
+/* IBAD/NULL entry indicating end-of-table */
+
+{IBAD, 0, 0, 0, NULL, NULL, NULL, NULL, 0 }
+
+} ;
+
+int errorprint = 1;
+int nodldprint = 1;
+int debugflag;
+int fd;
+
+struct downld_t *ip; /* Image pointer in current image */
+struct downld_t *dp; /* conc. download */
+
+
+/*
+ * The same for either the FEP or the BIOS.
+ * Append the downldio header, issue the ioctl, then free
+ * the buffer. Not horribly CPU efficient, but quite RAM efficient.
+ */
+
+void squirt(int req_type, int bdid, struct image_info *ii)
+{
+ struct downldio *dliop;
+ int size_buf;
+ int sfd;
+ struct stat sb;
+
+ /*
+ * If this binary comes from a file, stat it to see how
+ * large it is. Yes, we intentionally do this each
+ * time for the binary may change between loads.
+ */
+
+ if (ii->pathname) {
+ sfd = open(ii->pathname, O_RDONLY);
+
+ if (sfd < 0 ) {
+ myperror(ii->pathname);
+ goto squirt_end;
+ }
+
+ if (fstat(sfd, &sb) == -1 ) {
+ myperror(ii->pathname);
+ goto squirt_end;
+ }
+
+ ii->len = sb.st_size ;
+ }
+
+ size_buf = ii->len + sizeof(struct downldio);
+
+ /*
+ * This buffer will be freed at the end of this function. It is
+ * not resilient and should be around only long enough for the d/l
+ * to happen.
+ */
+ dliop = (struct downldio *) malloc(size_buf);
+
+ if (dliop == NULL) {
+ fprintf(stderr,"%s: can't get %d bytes of memory; aborting\n",
+ pgm, size_buf);
+ exit (1);
+ }
+
+ /* Now, stick the image in fepimage. This can come from either
+ * the compiled-in image or from the filesystem.
+ */
+ if (ii->pathname)
+ read(sfd, dliop->image.fi.fepimage, ii->len);
+ else
+ memcpy(dliop ->image.fi.fepimage, ii->image, ii->len);
+
+ dliop->req_type = req_type;
+ dliop->bdid = bdid;
+
+ dliop->image.fi.len = ii->len;
+
+ if (debugflag)
+ printf("sending %d bytes of %s %s from %s\n",
+ ii->len,
+ (ii->type == IFEP) ? "FEP" : (ii->type == IBIOS) ? "BIOS" : "CONFIG",
+ ii->name ? ii->name : "",
+ (ii->pathname) ? ii->pathname : "internal image" );
+
+ if (ioctl(fd, DIGI_DLREQ_SET, (char *) dliop) == -1) {
+ if(errorprint) {
+ fprintf(stderr,
+ "%s: warning - download ioctl failed\n",pgm);
+ errorprint = 0;
+ }
+ sleep(2);
+ }
+
+squirt_end:
+
+ if (ii->pathname) {
+ close(sfd);
+ }
+ free(dliop);
+}
+
+
+/*
+ * See if we need to reload the download image in core
+ *
+ */
+void consider_file_rescan(struct image_info *ii)
+{
+ int sfd ;
+ int len ;
+ struct stat sb;
+
+ /* This operation only makes sense when we're working from a file */
+
+ if (ii->pathname) {
+
+ sfd = open (ii->pathname, O_RDONLY) ;
+ if (sfd < 0 ) {
+ myperror(ii->pathname);
+ exit(1) ;
+ }
+
+ if( fstat(sfd,&sb) == -1 ) {
+ myperror(ii->pathname);
+ exit(1);
+ }
+
+ /* If the file hasn't changed since we last did this,
+ * and we have not done a free() on the image, bail
+ */
+ if (ii->image && (sb.st_mtime == ii->mtime))
+ goto end_rescan;
+
+ ii->len = len = sb.st_size ;
+
+ /* Record the timestamp of the file */
+ ii->mtime = sb.st_mtime;
+
+ /* image should be NULL unless there is an image malloced
+ * in already. Before we malloc again, make sure we don't
+ * have a memory leak.
+ */
+ if ( ii->image ) {
+ free( ii->image );
+ /* ii->image = NULL; */ /* not necessary */
+ }
+
+ /* This image will be kept only long enough for the
+ * download to happen. After sending the last block,
+ * it will be freed
+ */
+ ii->image = malloc(len) ;
+
+ if (ii->image == NULL) {
+ fprintf(stderr,
+ "%s: can't get %d bytes of memory; aborting\n",
+ pgm, len);
+ exit (1);
+ }
+
+ if (read(sfd, ii->image, len) < len) {
+ fprintf(stderr,"%s: read error on %s; aborting\n",
+ pgm, ii->pathname);
+ exit (1);
+ }
+
+end_rescan:
+ close(sfd);
+
+ }
+}
+
+/*
+ * Scan for images to match the driver requests
+ */
+
+struct image_info * find_conc_image()
+{
+ int x ;
+ struct image_info *i = NULL ;
+
+ for ( x = 0; x < nimages; x++ ) {
+ i=&image_list[x];
+
+ if(i->type != ICONC)
+ continue;
+
+ consider_file_rescan(i) ;
+
+ ip = (struct downld_t *) image_list[x].image;
+ if (ip == NULL) continue;
+
+ /*
+ * When I removed Clusterport, I kept only the code that I
+ * was SURE wasn't ClusterPort. We may not need the next two
+ * lines of code.
+ */
+ if ((dp->dl_type != 'P' ) && ( ip->dl_srev == dp->dl_srev ))
+ return i;
+ }
+ return NULL ;
+}
+
+
+int main(int argc, char **argv)
+{
+ struct downldio dlio;
+ int offset, bsize;
+ int x;
+ char *down, *image, *fname;
+ struct image_info *ii;
+
+ pgm = argv[0];
+ dp = &dlio.image.dl; /* conc. download */
+
+ while((argc > 2) && !strcmp(argv[1],"-d")) {
+ debugflag++ ;
+ argc-- ;
+ argv++ ;
+ }
+
+ if(argc < 2) {
+ fprintf(stderr,
+ "usage: %s download-device [image-file] ...\n",
+ pgm);
+ exit(1);
+ }
+
+
+
+ /*
+ * Daemonize, unless debugging is turned on.
+ */
+ if (debugflag == 0) {
+ switch (fork())
+ {
+ case 0:
+ break;
+
+ case -1:
+ return 1;
+
+ default:
+ return 0;
+ }
+
+ setsid();
+
+ /*
+ * The child no longer needs "stdin", "stdout", or "stderr",
+ * and should not block processes waiting for them to close.
+ */
+ fclose(stdin);
+ fclose(stdout);
+ fclose(stderr);
+
+ }
+
+ while (1) {
+ if( (fd = open(argv[1], O_RDWR)) == -1 ) {
+ sleep(1);
+ }
+ else
+ break;
+ }
+
+ /*
+ ** create a list of images to search through when trying to match
+ ** requests from the driver. Put images from the command line in
+ ** the list before built in images so that the command line images
+ ** can override the built in ones.
+ */
+
+ /* allocate space for the list */
+
+ nimages = argc - 2;
+
+ /* count the number of default list entries */
+
+ for (count = 0; images[count].type != IBAD; ++count) ;
+
+ nimages += count;
+
+ /* Really should just remove the variable "image_list".... robertl */
+ image_list = images ;
+
+ /* get the images from the command line */
+ for(x = 2; x < argc; x++) {
+ int xx;
+
+ /*
+ * strip off any leading path information for
+ * determining file type
+ */
+ if( (fname = strrchr(argv[x],'/')) == NULL)
+ fname = argv[x];
+ else
+ fname++; /* skip the slash */
+
+ for (xx = 0; xx < count; xx++) {
+ if (strcmp(fname, images[xx].fname) == 0 ) {
+ images[xx].pathname = argv[x];
+
+ /* image should be NULL until */
+ /* space is malloced */
+ images[xx].image = NULL ;
+ }
+ }
+ }
+
+ sleep(3);
+
+ /*
+ ** Endless loop: get a request from the fep, and service that request.
+ */
+ for(;;) {
+ /* get the request */
+ if (debugflag)
+ printf("b4 get ioctl...");
+
+ if (ioctl(fd,DIGI_DLREQ_GET, &dlio) == -1 ) {
+ if (errorprint) {
+ fprintf(stderr,
+ "%s: warning - download ioctl failed\n",
+ pgm);
+ errorprint = 0;
+ }
+ sleep(2);
+ } else {
+ if (debugflag)
+ printf("dlio.req_type is %d bd %d\n",
+ dlio.req_type,dlio.bdid);
+
+ switch(dlio.req_type) {
+ case DLREQ_BIOS:
+ /*
+ ** find the bios image for this type
+ */
+ for ( x = 0; x < nimages; x++ ) {
+ if(image_list[x].type != IBIOS)
+ continue;
+
+ if ((dlio.image.fi.type & FAMILY) ==
+ image_list[x].family) {
+
+ if ( image_list[x].family == T_CX ) {
+ if ((dlio.image.fi.type & BUSTYPE)
+ == T_PCIBUS ) {
+ if ( image_list[x].subtype
+ == T_PCIBUS )
+ break;
+ }
+ else {
+ break;
+ }
+ }
+ else if ( image_list[x].family == T_EPC ) {
+ /* If subtype of image is T_PCIBUS, it is */
+ /* a PCI EPC image, so the board must */
+ /* have bus type T_PCIBUS to match */
+ if ((dlio.image.fi.type & BUSTYPE)
+ == T_PCIBUS ) {
+ if ( image_list[x].subtype
+ == T_PCIBUS )
+ break;
+ }
+ else {
+ /* NON PCI EPC doesn't use PCI image */
+ if ( image_list[x].subtype
+ != T_PCIBUS )
+ break;
+ }
+ }
+ else
+ break;
+ }
+ else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
+ /* PCXR board will break out of the loop here */
+ if ( image_list[x].subtype == T_PCXR ) {
+ break;
+ }
+ }
+ }
+
+ if ( x >= nimages) {
+ /*
+ ** no valid images exist
+ */
+ if(nodldprint) {
+ fprintf(stderr,
+ "%s: cannot find correct BIOS image\n",
+ pgm);
+ nodldprint = 0;
+ }
+ dlio.image.fi.type = -1;
+ if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1) {
+ if (errorprint) {
+ fprintf(stderr,
+ "%s: warning - download ioctl failed\n",
+ pgm);
+ errorprint = 0;
+ }
+ sleep(2);
+ }
+ break;
+ }
+ squirt(dlio.req_type, dlio.bdid, &image_list[x]);
+ break ;
+
+ case DLREQ_FEP:
+ /*
+ ** find the fep image for this type
+ */
+ for ( x = 0; x < nimages; x++ ) {
+ if(image_list[x].type != IFEP)
+ continue;
+ if( (dlio.image.fi.type & FAMILY) ==
+ image_list[x].family ) {
+ if ( image_list[x].family == T_CX ) {
+ /* C/X PCI board */
+ if ((dlio.image.fi.type & BUSTYPE)
+ == T_PCIBUS ) {
+ if ( image_list[x].subtype
+ == T_PCIBUS )
+ break;
+ }
+ else {
+ /* Regular CX */
+ break;
+ }
+ }
+ else if ( image_list[x].family == T_EPC ) {
+ /* If subtype of image is T_PCIBUS, it is */
+ /* a PCI EPC image, so the board must */
+ /* have bus type T_PCIBUS to match */
+ if ((dlio.image.fi.type & BUSTYPE)
+ == T_PCIBUS ) {
+ if ( image_list[x].subtype
+ == T_PCIBUS )
+ break;
+ }
+ else {
+ /* NON PCI EPC doesn't use PCI image */
+ if ( image_list[x].subtype
+ != T_PCIBUS )
+ break;
+ }
+ }
+ else
+ break;
+ }
+ else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
+ /* PCXR board will break out of the loop here */
+ if ( image_list[x].subtype == T_PCXR ) {
+ break;
+ }
+ }
+ }
+
+ if ( x >= nimages) {
+ /*
+ ** no valid images exist
+ */
+ if(nodldprint) {
+ fprintf(stderr,
+ "%s: cannot find correct FEP image\n",
+ pgm);
+ nodldprint = 0;
+ }
+ dlio.image.fi.type=-1;
+ if( ioctl(fd,DIGI_DLREQ_SET,&dlio) == -1 ) {
+ if(errorprint) {
+ fprintf(stderr,
+ "%s: warning - download ioctl failed\n",
+ pgm);
+ errorprint=0;
+ }
+ sleep(2);
+ }
+ break;
+ }
+ squirt(dlio.req_type, dlio.bdid, &image_list[x]);
+ break;
+
+ case DLREQ_DEVCREATE:
+ {
+ char string[1024];
+#if 0
+ sprintf(string, "%s /proc/dgap/%d/mknod", DEFSHELL, dlio.bdid);
+#endif
+ sprintf(string, "%s /usr/sbin/dgap_updatedevs %d", DEFSHELL, dlio.bdid);
+ system(string);
+
+ if (debugflag)
+ printf("Created Devices.\n");
+ if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
+ if(errorprint) {
+ fprintf(stderr, "%s: warning - DEVCREATE ioctl failed\n",pgm);
+ errorprint = 0;
+ }
+ sleep(2);
+ }
+ if (debugflag)
+ printf("After ioctl set - Created Device.\n");
+ }
+
+ break;
+
+ case DLREQ_CONFIG:
+ for ( x = 0; x < nimages; x++ ) {
+ if(image_list[x].type != ICONFIG)
+ continue;
+ else
+ break;
+ }
+
+ if ( x >= nimages) {
+ /*
+ ** no valid images exist
+ */
+ if(nodldprint) {
+ fprintf(stderr,
+ "%s: cannot find correct CONFIG image\n",
+ pgm);
+ nodldprint = 0;
+ }
+ dlio.image.fi.type=-1;
+ if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
+ if(errorprint) {
+ fprintf(stderr,
+ "%s: warning - download ioctl failed\n",
+ pgm);
+ errorprint=0;
+ }
+ sleep(2);
+ }
+ break;
+ }
+
+ squirt(dlio.req_type, dlio.bdid, &image_list[x]);
+ break;
+
+ case DLREQ_CONC:
+ /*
+ ** find the image needed for this download
+ */
+ if ( dp->dl_seq == 0 ) {
+ /*
+ ** find image for hardware rev range
+ */
+ for ( x = 0; x < nimages; x++ ) {
+ ii=&image_list[x];
+
+ if(image_list[x].type != ICONC)
+ continue;
+
+ consider_file_rescan(ii) ;
+
+ ip = (struct downld_t *) image_list[x].image;
+ if (ip == NULL) continue;
+
+ /*
+ * When I removed Clusterport, I kept only the
+ * code that I was SURE wasn't ClusterPort.
+ * We may not need the next four lines of code.
+ */
+
+ if ((dp->dl_type != 'P' ) &&
+ (ip->dl_lrev <= dp->dl_lrev ) &&
+ ( dp->dl_lrev <= ip->dl_hrev))
+ break;
+ }
+
+ if ( x >= nimages ) {
+ /*
+ ** No valid images exist
+ */
+ if(nodldprint) {
+ fprintf(stderr,
+ "%s: cannot find correct download image %d\n",
+ pgm, dp->dl_lrev);
+ nodldprint=0;
+ }
+ continue;
+ }
+
+ } else {
+ /*
+ ** find image version required
+ */
+ if ((ii = find_conc_image()) == NULL ) {
+ /*
+ ** No valid images exist
+ */
+ fprintf(stderr,
+ "%s: can't find rest of download image??\n",
+ pgm);
+ continue;
+ }
+ }
+
+ /*
+ ** download block of image
+ */
+
+ offset = 1024 * dp->dl_seq;
+
+ /*
+ ** test if block requested within image
+ */
+ if ( offset < ii->len ) {
+
+ /*
+ ** if it is, determine block size, set segment,
+ ** set size, set pointers, and copy block
+ */
+ if (( bsize = ii->len - offset ) > 1024 )
+ bsize = 1024;
+
+ /*
+ ** copy image version info to download area
+ */
+ dp->dl_srev = ip->dl_srev;
+ dp->dl_lrev = ip->dl_lrev;
+ dp->dl_hrev = ip->dl_hrev;
+
+ dp->dl_seg = (64 * dp->dl_seq) + ip->dl_seg;
+ dp->dl_size = bsize;
+
+ down = (char *)&dp->dl_data[0];
+ image = (char *)((char *)ip + offset);
+
+ memcpy(down, image, bsize);
+ }
+ else {
+ /*
+ ** Image has been downloaded, set segment and
+ ** size to indicate no more blocks
+ */
+ dp->dl_seg = ip->dl_seg;
+ dp->dl_size = 0;
+
+ /* Now, we can release the concentrator */
+ /* image from memory if we're running */
+ /* from filesystem images */
+
+ if (ii->pathname)
+ if (ii->image) {
+ free(ii->image);
+ ii->image = NULL ;
+ }
+ }
+
+ if (debugflag)
+ printf(
+ "sending conc dl section %d to %s from %s\n",
+ dp->dl_seq, ii->name,
+ ii->pathname ? ii->pathname : "Internal Image");
+
+ if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
+ if (errorprint) {
+ fprintf(stderr,
+ "%s: warning - download ioctl failed\n",
+ pgm);
+ errorprint=0;
+ }
+ sleep(2);
+ }
+ break;
+ } /* switch */
+ }
+ if (debugflag > 1) {
+ printf("pausing: "); fflush(stdout);
+ fflush(stdin);
+ while(getchar() != '\n');
+ printf("continuing\n");
+ }
+ }
+}
+
+/*
+** myperror()
+**
+** Same as normal perror(), but places the program name at the begining
+** of the message.
+*/
+void myperror(char *s)
+{
+ fprintf(stderr,"%s: %s: %s.\n",pgm, s, strerror(errno));
+}
diff --git a/drivers/staging/dgnc/Kconfig b/drivers/staging/dgnc/Kconfig
new file mode 100644
index 00000000000..032c2a79523
--- /dev/null
+++ b/drivers/staging/dgnc/Kconfig
@@ -0,0 +1,6 @@
+config DGNC
+ tristate "Digi Neo and Classic PCI Products"
+ default n
+ depends on TTY && PCI
+ ---help---
+ Driver for the Digi International Neo and Classic PCI based product line.
diff --git a/drivers/staging/dgnc/Makefile b/drivers/staging/dgnc/Makefile
new file mode 100644
index 00000000000..888c4334236
--- /dev/null
+++ b/drivers/staging/dgnc/Makefile
@@ -0,0 +1,7 @@
+EXTRA_CFLAGS += -DDG_NAME=\"dgnc-1.3-16\" -DDG_PART=\"40002369_F\"
+
+obj-$(CONFIG_DGNC) += dgnc.o
+
+dgnc-objs := dgnc_cls.o dgnc_driver.o\
+ dgnc_mgmt.o dgnc_neo.o\
+ dgnc_trace.o dgnc_tty.o dgnc_sysfs.o
diff --git a/drivers/staging/dgnc/TODO b/drivers/staging/dgnc/TODO
new file mode 100644
index 00000000000..1ff2d1874aa
--- /dev/null
+++ b/drivers/staging/dgnc/TODO
@@ -0,0 +1,17 @@
+* remove kzalloc casts
+* checkpatch fixes
+* sparse fixes
+* fix use of sizeof(). Example replace sizeof(struct board_t)
+ with sizeof(*brd) and remove sizeof(char)
+* change name of board_t to dgnc_board
+* split two assignments into the two assignments on two lines;
+ don't use two equals signs
+* remove unecessary comments
+* remove unecessary error messages. Example kzalloc() has its
+ own error message. Adding an extra one is useless.
+* use goto statements for error handling when appropriate
+* there is a lot of unecessary code in the driver. It was
+ originally a standalone driver. Remove uneeded code.
+
+Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
+Cc: Lidza Louina <lidza.louina@gmail.com>
diff --git a/drivers/staging/dgnc/dgnc_cls.c b/drivers/staging/dgnc/dgnc_cls.c
new file mode 100644
index 00000000000..117e1580824
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_cls.c
@@ -0,0 +1,1409 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h> /* For jiffies, task states */
+#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
+#include <linux/delay.h> /* For udelay */
+#include <asm/io.h> /* For read[bwl]/write[bwl] */
+#include <linux/serial.h> /* For struct async_serial */
+#include <linux/serial_reg.h> /* For the various UART offsets */
+#include <linux/pci.h>
+
+#include "dgnc_driver.h" /* Driver main header file */
+#include "dgnc_cls.h"
+#include "dgnc_tty.h"
+#include "dgnc_trace.h"
+
+static inline void cls_parse_isr(struct board_t *brd, uint port);
+static inline void cls_clear_break(struct channel_t *ch, int force);
+static inline void cls_set_cts_flow_control(struct channel_t *ch);
+static inline void cls_set_rts_flow_control(struct channel_t *ch);
+static inline void cls_set_ixon_flow_control(struct channel_t *ch);
+static inline void cls_set_ixoff_flow_control(struct channel_t *ch);
+static inline void cls_set_no_output_flow_control(struct channel_t *ch);
+static inline void cls_set_no_input_flow_control(struct channel_t *ch);
+static void cls_parse_modem(struct channel_t *ch, uchar signals);
+static void cls_tasklet(unsigned long data);
+static void cls_vpd(struct board_t *brd);
+static void cls_uart_init(struct channel_t *ch);
+static void cls_uart_off(struct channel_t *ch);
+static int cls_drain(struct tty_struct *tty, uint seconds);
+static void cls_param(struct tty_struct *tty);
+static void cls_assert_modem_signals(struct channel_t *ch);
+static void cls_flush_uart_write(struct channel_t *ch);
+static void cls_flush_uart_read(struct channel_t *ch);
+static void cls_disable_receiver(struct channel_t *ch);
+static void cls_enable_receiver(struct channel_t *ch);
+static void cls_send_break(struct channel_t *ch, int msecs);
+static void cls_send_start_character(struct channel_t *ch);
+static void cls_send_stop_character(struct channel_t *ch);
+static void cls_copy_data_from_uart_to_queue(struct channel_t *ch);
+static void cls_copy_data_from_queue_to_uart(struct channel_t *ch);
+static uint cls_get_uart_bytes_left(struct channel_t *ch);
+static void cls_send_immediate_char(struct channel_t *ch, unsigned char);
+static irqreturn_t cls_intr(int irq, void *voidbrd);
+
+struct board_ops dgnc_cls_ops = {
+ .tasklet = cls_tasklet,
+ .intr = cls_intr,
+ .uart_init = cls_uart_init,
+ .uart_off = cls_uart_off,
+ .drain = cls_drain,
+ .param = cls_param,
+ .vpd = cls_vpd,
+ .assert_modem_signals = cls_assert_modem_signals,
+ .flush_uart_write = cls_flush_uart_write,
+ .flush_uart_read = cls_flush_uart_read,
+ .disable_receiver = cls_disable_receiver,
+ .enable_receiver = cls_enable_receiver,
+ .send_break = cls_send_break,
+ .send_start_character = cls_send_start_character,
+ .send_stop_character = cls_send_stop_character,
+ .copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart,
+ .get_uart_bytes_left = cls_get_uart_bytes_left,
+ .send_immediate_char = cls_send_immediate_char
+};
+
+
+static inline void cls_set_cts_flow_control(struct channel_t *ch)
+{
+ uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+ uchar ier = readb(&ch->ch_cls_uart->ier);
+ uchar isr_fcr = 0;
+
+ DPR_PARAM(("Setting CTSFLOW\n"));
+
+ /*
+ * The Enhanced Register Set may only be accessed when
+ * the Line Control Register is set to 0xBFh.
+ */
+ writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+ isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+ /* Turn on CTS flow control, turn off IXON flow control */
+ isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR);
+ isr_fcr &= ~(UART_EXAR654_EFR_IXON);
+
+ writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+ /* Write old LCR value back out, which turns enhanced access off */
+ writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+ /* Enable interrupts for CTS flow, turn off interrupts for received XOFF chars */
+ ier |= (UART_EXAR654_IER_CTSDSR);
+ ier &= ~(UART_EXAR654_IER_XOFF);
+ writeb(ier, &ch->ch_cls_uart->ier);
+
+ /* Set the usual FIFO values */
+ writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+ writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
+ UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+ &ch->ch_cls_uart->isr_fcr);
+
+ ch->ch_t_tlevel = 16;
+
+}
+
+
+static inline void cls_set_ixon_flow_control(struct channel_t *ch)
+{
+ uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+ uchar ier = readb(&ch->ch_cls_uart->ier);
+ uchar isr_fcr = 0;
+
+ DPR_PARAM(("Setting IXON FLOW\n"));
+
+ /*
+ * The Enhanced Register Set may only be accessed when
+ * the Line Control Register is set to 0xBFh.
+ */
+ writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+ isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+ /* Turn on IXON flow control, turn off CTS flow control */
+ isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON);
+ isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR);
+
+ writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+ /* Now set our current start/stop chars while in enhanced mode */
+ writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
+ writeb(0, &ch->ch_cls_uart->lsr);
+ writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
+ writeb(0, &ch->ch_cls_uart->spr);
+
+ /* Write old LCR value back out, which turns enhanced access off */
+ writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+ /* Disable interrupts for CTS flow, turn on interrupts for received XOFF chars */
+ ier &= ~(UART_EXAR654_IER_CTSDSR);
+ ier |= (UART_EXAR654_IER_XOFF);
+ writeb(ier, &ch->ch_cls_uart->ier);
+
+ /* Set the usual FIFO values */
+ writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+ writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
+ UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+ &ch->ch_cls_uart->isr_fcr);
+
+}
+
+
+static inline void cls_set_no_output_flow_control(struct channel_t *ch)
+{
+ uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+ uchar ier = readb(&ch->ch_cls_uart->ier);
+ uchar isr_fcr = 0;
+
+ DPR_PARAM(("Unsetting Output FLOW\n"));
+
+ /*
+ * The Enhanced Register Set may only be accessed when
+ * the Line Control Register is set to 0xBFh.
+ */
+ writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+ isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+ /* Turn off IXON flow control, turn off CTS flow control */
+ isr_fcr |= (UART_EXAR654_EFR_ECB);
+ isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON);
+
+ writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+ /* Write old LCR value back out, which turns enhanced access off */
+ writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+ /* Disable interrupts for CTS flow, turn off interrupts for received XOFF chars */
+ ier &= ~(UART_EXAR654_IER_CTSDSR);
+ ier &= ~(UART_EXAR654_IER_XOFF);
+ writeb(ier, &ch->ch_cls_uart->ier);
+
+ /* Set the usual FIFO values */
+ writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+ writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
+ UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+ &ch->ch_cls_uart->isr_fcr);
+
+ ch->ch_r_watermark = 0;
+ ch->ch_t_tlevel = 16;
+ ch->ch_r_tlevel = 16;
+
+}
+
+
+static inline void cls_set_rts_flow_control(struct channel_t *ch)
+{
+ uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+ uchar ier = readb(&ch->ch_cls_uart->ier);
+ uchar isr_fcr = 0;
+
+ DPR_PARAM(("Setting RTSFLOW\n"));
+
+ /*
+ * The Enhanced Register Set may only be accessed when
+ * the Line Control Register is set to 0xBFh.
+ */
+ writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+ isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+ /* Turn on RTS flow control, turn off IXOFF flow control */
+ isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR);
+ isr_fcr &= ~(UART_EXAR654_EFR_IXOFF);
+
+ writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+ /* Write old LCR value back out, which turns enhanced access off */
+ writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+ /* Enable interrupts for RTS flow */
+ ier |= (UART_EXAR654_IER_RTSDTR);
+ writeb(ier, &ch->ch_cls_uart->ier);
+
+ /* Set the usual FIFO values */
+ writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+ writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
+ UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+ &ch->ch_cls_uart->isr_fcr);
+
+
+ ch->ch_r_watermark = 4;
+ ch->ch_r_tlevel = 8;
+
+}
+
+
+static inline void cls_set_ixoff_flow_control(struct channel_t *ch)
+{
+ uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+ uchar ier = readb(&ch->ch_cls_uart->ier);
+ uchar isr_fcr = 0;
+
+ DPR_PARAM(("Setting IXOFF FLOW\n"));
+
+ /*
+ * The Enhanced Register Set may only be accessed when
+ * the Line Control Register is set to 0xBFh.
+ */
+ writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+ isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+ /* Turn on IXOFF flow control, turn off RTS flow control */
+ isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF);
+ isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR);
+
+ writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+ /* Now set our current start/stop chars while in enhanced mode */
+ writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
+ writeb(0, &ch->ch_cls_uart->lsr);
+ writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
+ writeb(0, &ch->ch_cls_uart->spr);
+
+ /* Write old LCR value back out, which turns enhanced access off */
+ writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+ /* Disable interrupts for RTS flow */
+ ier &= ~(UART_EXAR654_IER_RTSDTR);
+ writeb(ier, &ch->ch_cls_uart->ier);
+
+ /* Set the usual FIFO values */
+ writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+ writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
+ UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+ &ch->ch_cls_uart->isr_fcr);
+
+}
+
+
+static inline void cls_set_no_input_flow_control(struct channel_t *ch)
+{
+ uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+ uchar ier = readb(&ch->ch_cls_uart->ier);
+ uchar isr_fcr = 0;
+
+ DPR_PARAM(("Unsetting Input FLOW\n"));
+
+ /*
+ * The Enhanced Register Set may only be accessed when
+ * the Line Control Register is set to 0xBFh.
+ */
+ writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+ isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+ /* Turn off IXOFF flow control, turn off RTS flow control */
+ isr_fcr |= (UART_EXAR654_EFR_ECB);
+ isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF);
+
+ writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+ /* Write old LCR value back out, which turns enhanced access off */
+ writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+ /* Disable interrupts for RTS flow */
+ ier &= ~(UART_EXAR654_IER_RTSDTR);
+ writeb(ier, &ch->ch_cls_uart->ier);
+
+ /* Set the usual FIFO values */
+ writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+ writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
+ UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+ &ch->ch_cls_uart->isr_fcr);
+
+ ch->ch_t_tlevel = 16;
+ ch->ch_r_tlevel = 16;
+
+}
+
+
+/*
+ * cls_clear_break.
+ * Determines whether its time to shut off break condition.
+ *
+ * No locks are assumed to be held when calling this function.
+ * channel lock is held and released in this function.
+ */
+static inline void cls_clear_break(struct channel_t *ch, int force)
+{
+ ulong lock_flags;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /* Bail if we aren't currently sending a break. */
+ if (!ch->ch_stop_sending_break) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ /* Turn break off, and unset some variables */
+ if (ch->ch_flags & CH_BREAK_SENDING) {
+ if ((jiffies >= ch->ch_stop_sending_break) || force) {
+ uchar temp = readb(&ch->ch_cls_uart->lcr);
+ writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
+ ch->ch_flags &= ~(CH_BREAK_SENDING);
+ ch->ch_stop_sending_break = 0;
+ DPR_IOCTL(("Finishing UART_LCR_SBC! finished: %lx\n", jiffies));
+ }
+ }
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+/* Parse the ISR register for the specific port */
+static inline void cls_parse_isr(struct board_t *brd, uint port)
+{
+ struct channel_t *ch;
+ uchar isr = 0;
+ ulong lock_flags;
+
+ /*
+ * No need to verify board pointer, it was already
+ * verified in the interrupt routine.
+ */
+
+ if (port > brd->nasync)
+ return;
+
+ ch = brd->channels[port];
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ /* Here we try to figure out what caused the interrupt to happen */
+ while (1) {
+
+ isr = readb(&ch->ch_cls_uart->isr_fcr);
+
+ /* Bail if no pending interrupt on port */
+ if (isr & UART_IIR_NO_INT) {
+ break;
+ }
+
+ DPR_INTR(("%s:%d port: %x isr: %x\n", __FILE__, __LINE__, port, isr));
+
+ /* Receive Interrupt pending */
+ if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) {
+ /* Read data from uart -> queue */
+ brd->intr_rx++;
+ ch->ch_intr_rx++;
+ cls_copy_data_from_uart_to_queue(ch);
+ dgnc_check_queue_flow_control(ch);
+ }
+
+ /* Transmit Hold register empty pending */
+ if (isr & UART_IIR_THRI) {
+ /* Transfer data (if any) from Write Queue -> UART. */
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+ brd->intr_tx++;
+ ch->ch_intr_tx++;
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ cls_copy_data_from_queue_to_uart(ch);
+ }
+
+ /* Received Xoff signal/Special character */
+ if (isr & UART_IIR_XOFF) {
+ /* Empty */
+ }
+
+ /* CTS/RTS change of state */
+ if (isr & UART_IIR_CTSRTS) {
+ brd->intr_modem++;
+ ch->ch_intr_modem++;
+ /*
+ * Don't need to do anything, the cls_parse_modem
+ * below will grab the updated modem signals.
+ */
+ }
+
+ /* Parse any modem signal changes */
+ DPR_INTR(("MOD_STAT: sending to parse_modem_sigs\n"));
+ cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
+ }
+}
+
+
+/*
+ * cls_param()
+ * Send any/all changes to the line to the UART.
+ */
+static void cls_param(struct tty_struct *tty)
+{
+ uchar lcr = 0;
+ uchar uart_lcr = 0;
+ uchar ier = 0;
+ uchar uart_ier = 0;
+ uint baud = 9600;
+ int quot = 0;
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!tty || tty->magic != TTY_MAGIC) {
+ return;
+ }
+
+ un = (struct un_t *) tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC) {
+ return;
+ }
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+ return;
+ }
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC) {
+ return;
+ }
+
+ DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n",
+ ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag));
+
+ /*
+ * If baud rate is zero, flush queues, and set mval to drop DTR.
+ */
+ if ((ch->ch_c_cflag & (CBAUD)) == 0) {
+ ch->ch_r_head = ch->ch_r_tail = 0;
+ ch->ch_e_head = ch->ch_e_tail = 0;
+ ch->ch_w_head = ch->ch_w_tail = 0;
+
+ cls_flush_uart_write(ch);
+ cls_flush_uart_read(ch);
+
+ /* The baudrate is B0 so all modem lines are to be dropped. */
+ ch->ch_flags |= (CH_BAUD0);
+ ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
+ cls_assert_modem_signals(ch);
+ ch->ch_old_baud = 0;
+ return;
+ } else if (ch->ch_custom_speed) {
+
+ baud = ch->ch_custom_speed;
+ /* Handle transition from B0 */
+ if (ch->ch_flags & CH_BAUD0) {
+ ch->ch_flags &= ~(CH_BAUD0);
+
+ /*
+ * Bring back up RTS and DTR...
+ * Also handle RTS or DTR toggle if set.
+ */
+ if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_RTS);
+ if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_DTR);
+ }
+
+ } else {
+ int iindex = 0;
+ int jindex = 0;
+
+ ulong bauds[4][16] = {
+ { /* slowbaud */
+ 0, 50, 75, 110,
+ 134, 150, 200, 300,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* slowbaud & CBAUDEX */
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* fastbaud */
+ 0, 57600, 76800, 115200,
+ 131657, 153600, 230400, 460800,
+ 921600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* fastbaud & CBAUDEX */
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 }
+ };
+
+ /* Only use the TXPrint baud rate if the terminal unit is NOT open */
+ if (!(ch->ch_tun.un_flags & UN_ISOPEN) && (un->un_type == DGNC_PRINT))
+ baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
+ else
+ baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
+
+ if (ch->ch_c_cflag & CBAUDEX)
+ iindex = 1;
+
+ if (ch->ch_digi.digi_flags & DIGI_FAST)
+ iindex += 2;
+
+ jindex = baud;
+
+ if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16)) {
+ baud = bauds[iindex][jindex];
+ } else {
+ DPR_IOCTL(("baud indices were out of range (%d)(%d)",
+ iindex, jindex));
+ baud = 0;
+ }
+
+ if (baud == 0)
+ baud = 9600;
+
+ /* Handle transition from B0 */
+ if (ch->ch_flags & CH_BAUD0) {
+ ch->ch_flags &= ~(CH_BAUD0);
+
+ /*
+ * Bring back up RTS and DTR...
+ * Also handle RTS or DTR toggle if set.
+ */
+ if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_RTS);
+ if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_DTR);
+ }
+ }
+
+ if (ch->ch_c_cflag & PARENB) {
+ lcr |= UART_LCR_PARITY;
+ }
+
+ if (!(ch->ch_c_cflag & PARODD)) {
+ lcr |= UART_LCR_EPAR;
+ }
+
+ /*
+ * Not all platforms support mark/space parity,
+ * so this will hide behind an ifdef.
+ */
+#ifdef CMSPAR
+ if (ch->ch_c_cflag & CMSPAR)
+ lcr |= UART_LCR_SPAR;
+#endif
+
+ if (ch->ch_c_cflag & CSTOPB)
+ lcr |= UART_LCR_STOP;
+
+ switch (ch->ch_c_cflag & CSIZE) {
+ case CS5:
+ lcr |= UART_LCR_WLEN5;
+ break;
+ case CS6:
+ lcr |= UART_LCR_WLEN6;
+ break;
+ case CS7:
+ lcr |= UART_LCR_WLEN7;
+ break;
+ case CS8:
+ default:
+ lcr |= UART_LCR_WLEN8;
+ break;
+ }
+
+ ier = uart_ier = readb(&ch->ch_cls_uart->ier);
+ uart_lcr = readb(&ch->ch_cls_uart->lcr);
+
+ if (baud == 0)
+ baud = 9600;
+
+ quot = ch->ch_bd->bd_dividend / baud;
+
+ if (quot != 0 && ch->ch_old_baud != baud) {
+ ch->ch_old_baud = baud;
+ writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr);
+ writeb((quot & 0xff), &ch->ch_cls_uart->txrx);
+ writeb((quot >> 8), &ch->ch_cls_uart->ier);
+ writeb(lcr, &ch->ch_cls_uart->lcr);
+ }
+
+ if (uart_lcr != lcr)
+ writeb(lcr, &ch->ch_cls_uart->lcr);
+
+ if (ch->ch_c_cflag & CREAD) {
+ ier |= (UART_IER_RDI | UART_IER_RLSI);
+ }
+ else {
+ ier &= ~(UART_IER_RDI | UART_IER_RLSI);
+ }
+
+ /*
+ * Have the UART interrupt on modem signal changes ONLY when
+ * we are in hardware flow control mode, or CLOCAL/FORCEDCD is not set.
+ */
+ if ((ch->ch_digi.digi_flags & CTSPACE) || (ch->ch_digi.digi_flags & RTSPACE) ||
+ (ch->ch_c_cflag & CRTSCTS) || !(ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
+ !(ch->ch_c_cflag & CLOCAL))
+ {
+ ier |= UART_IER_MSI;
+ }
+ else {
+ ier &= ~UART_IER_MSI;
+ }
+
+ ier |= UART_IER_THRI;
+
+ if (ier != uart_ier)
+ writeb(ier, &ch->ch_cls_uart->ier);
+
+ if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
+ cls_set_cts_flow_control(ch);
+ }
+ else if (ch->ch_c_iflag & IXON) {
+ /* If start/stop is set to disable, then we should disable flow control */
+ if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE))
+ cls_set_no_output_flow_control(ch);
+ else
+ cls_set_ixon_flow_control(ch);
+ }
+ else {
+ cls_set_no_output_flow_control(ch);
+ }
+
+ if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
+ cls_set_rts_flow_control(ch);
+ }
+ else if (ch->ch_c_iflag & IXOFF) {
+ /* If start/stop is set to disable, then we should disable flow control */
+ if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE))
+ cls_set_no_input_flow_control(ch);
+ else
+ cls_set_ixoff_flow_control(ch);
+ }
+ else {
+ cls_set_no_input_flow_control(ch);
+ }
+
+ cls_assert_modem_signals(ch);
+
+ /* Get current status of the modem signals now */
+ cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
+}
+
+
+/*
+ * Our board poller function.
+ */
+static void cls_tasklet(unsigned long data)
+{
+ struct board_t *bd = (struct board_t *) data;
+ struct channel_t *ch;
+ ulong lock_flags;
+ int i;
+ int state = 0;
+ int ports = 0;
+
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC) {
+ APR(("poll_tasklet() - NULL or bad bd.\n"));
+ return;
+ }
+
+ /* Cache a couple board values */
+ DGNC_LOCK(bd->bd_lock, lock_flags);
+ state = bd->state;
+ ports = bd->nasync;
+ DGNC_UNLOCK(bd->bd_lock, lock_flags);
+
+ /*
+ * Do NOT allow the interrupt routine to read the intr registers
+ * Until we release this lock.
+ */
+ DGNC_LOCK(bd->bd_intr_lock, lock_flags);
+
+ /*
+ * If board is ready, parse deeper to see if there is anything to do.
+ */
+ if ((state == BOARD_READY) && (ports > 0)) {
+
+ /* Loop on each port */
+ for (i = 0; i < ports; i++) {
+ ch = bd->channels[i];
+ if (!ch)
+ continue;
+
+ /*
+ * NOTE: Remember you CANNOT hold any channel
+ * locks when calling input.
+ * During input processing, its possible we
+ * will call ld, which might do callbacks back
+ * into us.
+ */
+ dgnc_input(ch);
+
+ /*
+ * Channel lock is grabbed and then released
+ * inside this routine.
+ */
+ cls_copy_data_from_queue_to_uart(ch);
+ dgnc_wakeup_writes(ch);
+
+ /*
+ * Check carrier function.
+ */
+ dgnc_carrier(ch);
+
+ /*
+ * The timing check of turning off the break is done
+ * inside clear_break()
+ */
+ if (ch->ch_stop_sending_break)
+ cls_clear_break(ch, 0);
+ }
+ }
+
+ DGNC_UNLOCK(bd->bd_intr_lock, lock_flags);
+
+}
+
+
+/*
+ * cls_intr()
+ *
+ * Classic specific interrupt handler.
+ */
+static irqreturn_t cls_intr(int irq, void *voidbrd)
+{
+ struct board_t *brd = (struct board_t *) voidbrd;
+ uint i = 0;
+ uchar poll_reg;
+ unsigned long lock_flags;
+
+ if (!brd) {
+ APR(("Received interrupt (%d) with null board associated\n", irq));
+ return IRQ_NONE;
+ }
+
+ /*
+ * Check to make sure its for us.
+ */
+ if (brd->magic != DGNC_BOARD_MAGIC) {
+ APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n", irq));
+ return IRQ_NONE;
+ }
+
+ DGNC_LOCK(brd->bd_intr_lock, lock_flags);
+
+ brd->intr_count++;
+
+ /*
+ * Check the board's global interrupt offset to see if we
+ * we actually do have an interrupt pending for us.
+ */
+ poll_reg = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET);
+
+ /* If 0, no interrupts pending */
+ if (!poll_reg) {
+ DPR_INTR(("Kernel interrupted to me, but no pending interrupts...\n"));
+ DGNC_UNLOCK(brd->bd_intr_lock, lock_flags);
+ return IRQ_NONE;
+ }
+
+ DPR_INTR(("%s:%d poll_reg: %x\n", __FILE__, __LINE__, poll_reg));
+
+ /* Parse each port to find out what caused the interrupt */
+ for (i = 0; i < brd->nasync; i++) {
+ cls_parse_isr(brd, i);
+ }
+
+ /*
+ * Schedule tasklet to more in-depth servicing at a better time.
+ */
+ tasklet_schedule(&brd->helper_tasklet);
+
+ DGNC_UNLOCK(brd->bd_intr_lock, lock_flags);
+
+ DPR_INTR(("dgnc_intr finish.\n"));
+ return IRQ_HANDLED;
+}
+
+
+static void cls_disable_receiver(struct channel_t *ch)
+{
+ uchar tmp = readb(&ch->ch_cls_uart->ier);
+ tmp &= ~(UART_IER_RDI);
+ writeb(tmp, &ch->ch_cls_uart->ier);
+}
+
+
+static void cls_enable_receiver(struct channel_t *ch)
+{
+ uchar tmp = readb(&ch->ch_cls_uart->ier);
+ tmp |= (UART_IER_RDI);
+ writeb(tmp, &ch->ch_cls_uart->ier);
+}
+
+
+static void cls_copy_data_from_uart_to_queue(struct channel_t *ch)
+{
+ int qleft = 0;
+ uchar linestatus = 0;
+ uchar error_mask = 0;
+ ushort head;
+ ushort tail;
+ ulong lock_flags;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /* cache head and tail of queue */
+ head = ch->ch_r_head;
+ tail = ch->ch_r_tail;
+
+ /* Store how much space we have left in the queue */
+ if ((qleft = tail - head - 1) < 0)
+ qleft += RQUEUEMASK + 1;
+
+ /*
+ * Create a mask to determine whether we should
+ * insert the character (if any) into our queue.
+ */
+ if (ch->ch_c_iflag & IGNBRK)
+ error_mask |= UART_LSR_BI;
+
+ while (1) {
+ linestatus = readb(&ch->ch_cls_uart->lsr);
+
+ if (!(linestatus & (UART_LSR_DR)))
+ break;
+
+ /*
+ * Discard character if we are ignoring the error mask.
+ */
+ if (linestatus & error_mask) {
+ uchar discard;
+ linestatus = 0;
+ discard = readb(&ch->ch_cls_uart->txrx);
+ continue;
+ }
+
+ /*
+ * If our queue is full, we have no choice but to drop some data.
+ * The assumption is that HWFLOW or SWFLOW should have stopped
+ * things way way before we got to this point.
+ *
+ * I decided that I wanted to ditch the oldest data first,
+ * I hope thats okay with everyone? Yes? Good.
+ */
+ while (qleft < 1) {
+ DPR_READ(("Queue full, dropping DATA:%x LSR:%x\n",
+ ch->ch_rqueue[tail], ch->ch_equeue[tail]));
+
+ ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK;
+ ch->ch_err_overrun++;
+ qleft++;
+ }
+
+ ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE);
+ ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx);
+ dgnc_sniff_nowait_nolock(ch, "UART READ", ch->ch_rqueue + head, 1);
+
+ qleft--;
+
+ DPR_READ(("DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]));
+
+ if (ch->ch_equeue[head] & UART_LSR_PE)
+ ch->ch_err_parity++;
+ if (ch->ch_equeue[head] & UART_LSR_BI)
+ ch->ch_err_break++;
+ if (ch->ch_equeue[head] & UART_LSR_FE)
+ ch->ch_err_frame++;
+
+ /* Add to, and flip head if needed */
+ head = (head + 1) & RQUEUEMASK;
+ ch->ch_rxcount++;
+ }
+
+ /*
+ * Write new final heads to channel structure.
+ */
+ ch->ch_r_head = head & RQUEUEMASK;
+ ch->ch_e_head = head & EQUEUEMASK;
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+/*
+ * This function basically goes to sleep for secs, or until
+ * it gets signalled that the port has fully drained.
+ */
+static int cls_drain(struct tty_struct *tty, uint seconds)
+{
+ ulong lock_flags;
+ struct channel_t *ch;
+ struct un_t *un;
+ int rc = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC) {
+ return (-ENXIO);
+ }
+
+ un = (struct un_t *) tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC) {
+ return (-ENXIO);
+ }
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+ return (-ENXIO);
+ }
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ un->un_flags |= UN_EMPTY;
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * NOTE: Do something with time passed in.
+ */
+ rc = wait_event_interruptible(un->un_flags_wait, ((un->un_flags & UN_EMPTY) == 0));
+
+ /* If ret is non-zero, user ctrl-c'ed us */
+ if (rc)
+ DPR_IOCTL(("%d Drain - User ctrl c'ed\n", __LINE__));
+
+ return (rc);
+}
+
+
+/* Channel lock MUST be held before calling this function! */
+static void cls_flush_uart_write(struct channel_t *ch)
+{
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+ return;
+ }
+
+ writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_cls_uart->isr_fcr);
+ udelay(10);
+
+ ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+}
+
+
+/* Channel lock MUST be held before calling this function! */
+static void cls_flush_uart_read(struct channel_t *ch)
+{
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+ return;
+ }
+
+ /*
+ * For complete POSIX compatibility, we should be purging the
+ * read FIFO in the UART here.
+ *
+ * However, doing the statement below also incorrectly flushes
+ * write data as well as just basically trashing the FIFO.
+ *
+ * I believe this is a BUG in this UART.
+ * So for now, we will leave the code #ifdef'ed out...
+ */
+#if 0
+ writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_cls_uart->isr_fcr);
+#endif
+ udelay(10);
+}
+
+
+static void cls_copy_data_from_queue_to_uart(struct channel_t *ch)
+{
+ ushort head;
+ ushort tail;
+ int n;
+ int qlen;
+ uint len_written = 0;
+ ulong lock_flags;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /* No data to write to the UART */
+ if (ch->ch_w_tail == ch->ch_w_head) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ /* If port is "stopped", don't send any data to the UART */
+ if ((ch->ch_flags & CH_FORCED_STOP) || (ch->ch_flags & CH_BREAK_SENDING)) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM))) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ n = 32;
+
+ /* cache head and tail of queue */
+ head = ch->ch_w_head & WQUEUEMASK;
+ tail = ch->ch_w_tail & WQUEUEMASK;
+ qlen = (head - tail) & WQUEUEMASK;
+
+ /* Find minimum of the FIFO space, versus queue length */
+ n = min(n, qlen);
+
+ while (n > 0) {
+
+ /*
+ * If RTS Toggle mode is on, turn on RTS now if not already set,
+ * and make sure we get an event when the data transfer has completed.
+ */
+ if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
+ if (!(ch->ch_mostat & UART_MCR_RTS)) {
+ ch->ch_mostat |= (UART_MCR_RTS);
+ cls_assert_modem_signals(ch);
+ }
+ ch->ch_tun.un_flags |= (UN_EMPTY);
+ }
+
+ /*
+ * If DTR Toggle mode is on, turn on DTR now if not already set,
+ * and make sure we get an event when the data transfer has completed.
+ */
+ if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
+ if (!(ch->ch_mostat & UART_MCR_DTR)) {
+ ch->ch_mostat |= (UART_MCR_DTR);
+ cls_assert_modem_signals(ch);
+ }
+ ch->ch_tun.un_flags |= (UN_EMPTY);
+ }
+ writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_cls_uart->txrx);
+ dgnc_sniff_nowait_nolock(ch, "UART WRITE", ch->ch_wqueue + ch->ch_w_tail, 1);
+ DPR_WRITE(("Tx data: %x\n", ch->ch_wqueue[ch->ch_w_tail]));
+ ch->ch_w_tail++;
+ ch->ch_w_tail &= WQUEUEMASK;
+ ch->ch_txcount++;
+ len_written++;
+ n--;
+ }
+
+ if (len_written > 0)
+ ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ return;
+}
+
+
+static void cls_parse_modem(struct channel_t *ch, uchar signals)
+{
+ volatile uchar msignals = signals;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DPR_MSIGS(("cls_parse_modem: port: %d signals: %d\n", ch->ch_portnum, msignals));
+
+ /*
+ * Do altpin switching. Altpin switches DCD and DSR.
+ * This prolly breaks DSRPACE, so we should be more clever here.
+ */
+ if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
+ uchar mswap = signals;
+ if (mswap & UART_MSR_DDCD) {
+ msignals &= ~UART_MSR_DDCD;
+ msignals |= UART_MSR_DDSR;
+ }
+ if (mswap & UART_MSR_DDSR) {
+ msignals &= ~UART_MSR_DDSR;
+ msignals |= UART_MSR_DDCD;
+ }
+ if (mswap & UART_MSR_DCD) {
+ msignals &= ~UART_MSR_DCD;
+ msignals |= UART_MSR_DSR;
+ }
+ if (mswap & UART_MSR_DSR) {
+ msignals &= ~UART_MSR_DSR;
+ msignals |= UART_MSR_DCD;
+ }
+ }
+
+ /* Scrub off lower bits. They signify delta's, which I don't care about */
+ signals &= 0xf0;
+
+ if (msignals & UART_MSR_DCD)
+ ch->ch_mistat |= UART_MSR_DCD;
+ else
+ ch->ch_mistat &= ~UART_MSR_DCD;
+
+ if (msignals & UART_MSR_DSR)
+ ch->ch_mistat |= UART_MSR_DSR;
+ else
+ ch->ch_mistat &= ~UART_MSR_DSR;
+
+ if (msignals & UART_MSR_RI)
+ ch->ch_mistat |= UART_MSR_RI;
+ else
+ ch->ch_mistat &= ~UART_MSR_RI;
+
+ if (msignals & UART_MSR_CTS)
+ ch->ch_mistat |= UART_MSR_CTS;
+ else
+ ch->ch_mistat &= ~UART_MSR_CTS;
+
+
+ DPR_MSIGS(("Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
+ ch->ch_portnum,
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD)));
+}
+
+
+/* Make the UART raise any of the output signals we want up */
+static void cls_assert_modem_signals(struct channel_t *ch)
+{
+ uchar out;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ out = ch->ch_mostat;
+
+ if (ch->ch_flags & CH_LOOPBACK)
+ out |= UART_MCR_LOOP;
+
+ writeb(out, &ch->ch_cls_uart->mcr);
+
+ /* Give time for the UART to actually drop the signals */
+ udelay(10);
+}
+
+
+static void cls_send_start_character(struct channel_t *ch)
+{
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ if (ch->ch_startc != _POSIX_VDISABLE) {
+ ch->ch_xon_sends++;
+ writeb(ch->ch_startc, &ch->ch_cls_uart->txrx);
+ }
+}
+
+
+static void cls_send_stop_character(struct channel_t *ch)
+{
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ if (ch->ch_stopc != _POSIX_VDISABLE) {
+ ch->ch_xoff_sends++;
+ writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx);
+ }
+}
+
+
+/* Inits UART */
+static void cls_uart_init(struct channel_t *ch)
+{
+ uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+ uchar isr_fcr = 0;
+
+ writeb(0, &ch->ch_cls_uart->ier);
+
+ /*
+ * The Enhanced Register Set may only be accessed when
+ * the Line Control Register is set to 0xBFh.
+ */
+ writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+ isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+ /* Turn on Enhanced/Extended controls */
+ isr_fcr |= (UART_EXAR654_EFR_ECB);
+
+ writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+ /* Write old LCR value back out, which turns enhanced access off */
+ writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+ /* Clear out UART and FIFO */
+ readb(&ch->ch_cls_uart->txrx);
+
+ writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_cls_uart->isr_fcr);
+ udelay(10);
+
+ ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+
+ readb(&ch->ch_cls_uart->lsr);
+ readb(&ch->ch_cls_uart->msr);
+}
+
+
+/*
+ * Turns off UART.
+ */
+static void cls_uart_off(struct channel_t *ch)
+{
+ writeb(0, &ch->ch_cls_uart->ier);
+}
+
+
+/*
+ * cls_get_uarts_bytes_left.
+ * Returns 0 is nothing left in the FIFO, returns 1 otherwise.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static uint cls_get_uart_bytes_left(struct channel_t *ch)
+{
+ uchar left = 0;
+ uchar lsr = 0;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return 0;
+
+ lsr = readb(&ch->ch_cls_uart->lsr);
+
+ /* Determine whether the Transmitter is empty or not */
+ if (!(lsr & UART_LSR_TEMT)) {
+ if (ch->ch_flags & CH_TX_FIFO_EMPTY) {
+ tasklet_schedule(&ch->ch_bd->helper_tasklet);
+ }
+ left = 1;
+ }
+ else {
+ ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+ left = 0;
+ }
+
+ return left;
+}
+
+
+/*
+ * cls_send_break.
+ * Starts sending a break thru the UART.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static void cls_send_break(struct channel_t *ch, int msecs)
+{
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ /*
+ * If we receive a time of 0, this means turn off the break.
+ */
+ if (msecs == 0) {
+ /* Turn break off, and unset some variables */
+ if (ch->ch_flags & CH_BREAK_SENDING) {
+ uchar temp = readb(&ch->ch_cls_uart->lcr);
+ writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
+ ch->ch_flags &= ~(CH_BREAK_SENDING);
+ ch->ch_stop_sending_break = 0;
+ DPR_IOCTL(("Finishing UART_LCR_SBC! finished: %lx\n", jiffies));
+ }
+ return;
+ }
+
+ /*
+ * Set the time we should stop sending the break.
+ * If we are already sending a break, toss away the existing
+ * time to stop, and use this new value instead.
+ */
+ ch->ch_stop_sending_break = jiffies + dgnc_jiffies_from_ms(msecs);
+
+ /* Tell the UART to start sending the break */
+ if (!(ch->ch_flags & CH_BREAK_SENDING)) {
+ uchar temp = readb(&ch->ch_cls_uart->lcr);
+ writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr);
+ ch->ch_flags |= (CH_BREAK_SENDING);
+ DPR_IOCTL(("Port %d. Starting UART_LCR_SBC! start: %lx should end: %lx\n",
+ ch->ch_portnum, jiffies, ch->ch_stop_sending_break));
+ }
+}
+
+
+/*
+ * cls_send_immediate_char.
+ * Sends a specific character as soon as possible to the UART,
+ * jumping over any bytes that might be in the write queue.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static void cls_send_immediate_char(struct channel_t *ch, unsigned char c)
+{
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ writeb(c, &ch->ch_cls_uart->txrx);
+}
+
+static void cls_vpd(struct board_t *brd)
+{
+ ulong vpdbase; /* Start of io base of the card */
+ u8 __iomem *re_map_vpdbase;/* Remapped memory of the card */
+ int i = 0;
+
+
+ vpdbase = pci_resource_start(brd->pdev, 3);
+
+ /* No VPD */
+ if (!vpdbase)
+ return;
+
+ re_map_vpdbase = ioremap(vpdbase, 0x400);
+
+ if (!re_map_vpdbase)
+ return;
+
+ /* Store the VPD into our buffer */
+ for (i = 0; i < 0x40; i++) {
+ brd->vpd[i] = readb(re_map_vpdbase + i);
+ printk("%x ", brd->vpd[i]);
+ }
+ printk("\n");
+
+ if (re_map_vpdbase)
+ iounmap(re_map_vpdbase);
+}
+
diff --git a/drivers/staging/dgnc/dgnc_cls.h b/drivers/staging/dgnc/dgnc_cls.h
new file mode 100644
index 00000000000..ffe8535a84a
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_cls.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ */
+
+#ifndef __DGNC_CLS_H
+#define __DGNC_CLS_H
+
+#include "dgnc_types.h"
+
+
+/************************************************************************
+ * Per channel/port Classic UART structure *
+ ************************************************************************
+ * Base Structure Entries Usage Meanings to Host *
+ * *
+ * W = read write R = read only *
+ * U = Unused. *
+ ************************************************************************/
+
+struct cls_uart_struct {
+ u8 txrx; /* WR RHR/THR - Holding Reg */
+ u8 ier; /* WR IER - Interrupt Enable Reg */
+ u8 isr_fcr; /* WR ISR/FCR - Interrupt Status Reg/Fifo Control Reg */
+ u8 lcr; /* WR LCR - Line Control Reg */
+ u8 mcr; /* WR MCR - Modem Control Reg */
+ u8 lsr; /* WR LSR - Line Status Reg */
+ u8 msr; /* WR MSR - Modem Status Reg */
+ u8 spr; /* WR SPR - Scratch Pad Reg */
+};
+
+/* Where to read the interrupt register (8bits) */
+#define UART_CLASSIC_POLL_ADDR_OFFSET 0x40
+
+#define UART_EXAR654_ENHANCED_REGISTER_SET 0xBF
+
+#define UART_16654_FCR_TXTRIGGER_8 0x0
+#define UART_16654_FCR_TXTRIGGER_16 0x10
+#define UART_16654_FCR_TXTRIGGER_32 0x20
+#define UART_16654_FCR_TXTRIGGER_56 0x30
+
+#define UART_16654_FCR_RXTRIGGER_8 0x0
+#define UART_16654_FCR_RXTRIGGER_16 0x40
+#define UART_16654_FCR_RXTRIGGER_56 0x80
+#define UART_16654_FCR_RXTRIGGER_60 0xC0
+
+#define UART_IIR_XOFF 0x10 /* Received Xoff signal/Special character */
+#define UART_IIR_CTSRTS 0x20 /* Received CTS/RTS change of state */
+#define UART_IIR_RDI_TIMEOUT 0x0C /* Receiver data TIMEOUT */
+
+/*
+ * These are the EXTENDED definitions for the Exar 654's Interrupt
+ * Enable Register.
+ */
+#define UART_EXAR654_EFR_ECB 0x10 /* Enhanced control bit */
+#define UART_EXAR654_EFR_IXON 0x2 /* Receiver compares Xon1/Xoff1 */
+#define UART_EXAR654_EFR_IXOFF 0x8 /* Transmit Xon1/Xoff1 */
+#define UART_EXAR654_EFR_RTSDTR 0x40 /* Auto RTS/DTR Flow Control Enable */
+#define UART_EXAR654_EFR_CTSDSR 0x80 /* Auto CTS/DSR Flow COntrol Enable */
+
+#define UART_EXAR654_XOFF_DETECT 0x1 /* Indicates whether chip saw an incoming XOFF char */
+#define UART_EXAR654_XON_DETECT 0x2 /* Indicates whether chip saw an incoming XON char */
+
+#define UART_EXAR654_IER_XOFF 0x20 /* Xoff Interrupt Enable */
+#define UART_EXAR654_IER_RTSDTR 0x40 /* Output Interrupt Enable */
+#define UART_EXAR654_IER_CTSDSR 0x80 /* Input Interrupt Enable */
+
+/*
+ * Our Global Variables
+ */
+extern struct board_ops dgnc_cls_ops;
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c
new file mode 100644
index 00000000000..f8c1e22585d
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_driver.c
@@ -0,0 +1,958 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+#include <linux/sched.h>
+#endif
+
+#include "dgnc_driver.h"
+#include "dgnc_pci.h"
+#include "dpacompat.h"
+#include "dgnc_mgmt.h"
+#include "dgnc_tty.h"
+#include "dgnc_trace.h"
+#include "dgnc_cls.h"
+#include "dgnc_neo.h"
+#include "dgnc_sysfs.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line");
+MODULE_SUPPORTED_DEVICE("dgnc");
+
+/*
+ * insmod command line overrideable parameters
+ *
+ * NOTE: we use a set of macros to create the variables, which allows
+ * us to specify the variable type, name, initial value, and description.
+ */
+PARM_INT(debug, 0x00, 0644, "Driver debugging level");
+PARM_INT(rawreadok, 1, 0644, "Bypass flip buffers on input");
+PARM_INT(trcbuf_size, 0x100000, 0644, "Debugging trace buffer size.");
+
+/**************************************************************************
+ *
+ * protos for this file
+ *
+ */
+static int dgnc_start(void);
+static int dgnc_finalize_board_init(struct board_t *brd);
+static void dgnc_init_globals(void);
+static int dgnc_found_board(struct pci_dev *pdev, int id);
+static void dgnc_cleanup_board(struct board_t *brd);
+static void dgnc_poll_handler(ulong dummy);
+static int dgnc_init_pci(void);
+static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void dgnc_remove_one(struct pci_dev *dev);
+static int dgnc_probe1(struct pci_dev *pdev, int card_type);
+static void dgnc_do_remap(struct board_t *brd);
+
+/* Driver load/unload functions */
+int dgnc_init_module(void);
+void dgnc_cleanup_module(void);
+
+module_init(dgnc_init_module);
+module_exit(dgnc_cleanup_module);
+
+
+/*
+ * File operations permitted on Control/Management major.
+ */
+static struct file_operations dgnc_BoardFops =
+{
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = dgnc_mgmt_ioctl,
+ .open = dgnc_mgmt_open,
+ .release = dgnc_mgmt_close
+};
+
+
+/*
+ * Globals
+ */
+uint dgnc_NumBoards;
+struct board_t *dgnc_Board[MAXBOARDS];
+DEFINE_SPINLOCK(dgnc_global_lock);
+int dgnc_driver_state = DRIVER_INITIALIZED;
+ulong dgnc_poll_counter;
+uint dgnc_Major;
+int dgnc_poll_tick = 20; /* Poll interval - 20 ms */
+
+/*
+ * Static vars.
+ */
+static uint dgnc_Major_Control_Registered = FALSE;
+static uint dgnc_driver_start = FALSE;
+
+static struct class *dgnc_class;
+
+/*
+ * Poller stuff
+ */
+static DEFINE_SPINLOCK(dgnc_poll_lock); /* Poll scheduling lock */
+static ulong dgnc_poll_time; /* Time of next poll */
+static uint dgnc_poll_stop; /* Used to tell poller to stop */
+static struct timer_list dgnc_poll_timer;
+
+
+static struct pci_device_id dgnc_pci_tbl[] = {
+ { DIGI_VID, PCI_DEVICE_CLASSIC_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+ { DIGI_VID, PCI_DEVICE_CLASSIC_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+ { DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+ { DIGI_VID, PCI_DEVICE_NEO_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { DIGI_VID, PCI_DEVICE_NEO_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+ { DIGI_VID, PCI_DEVICE_NEO_2DB9_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
+ { DIGI_VID, PCI_DEVICE_NEO_2DB9PRI_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
+ { DIGI_VID, PCI_DEVICE_NEO_2RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { DIGI_VID, PCI_DEVICE_NEO_2RJ45PRI_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
+ { DIGI_VID, PCI_DEVICE_NEO_1_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
+ { DIGI_VID, PCI_DEVICE_NEO_1_422_485_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
+ { DIGI_VID, PCI_DEVICE_NEO_2_422_485_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
+ { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
+ { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
+ { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_4RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
+ { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_8RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
+ {0,} /* 0 terminated list. */
+};
+MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl);
+
+struct board_id {
+ uchar *name;
+ uint maxports;
+ unsigned int is_pci_express;
+};
+
+static struct board_id dgnc_Ids[] =
+{
+ { PCI_DEVICE_CLASSIC_4_PCI_NAME, 4, 0 },
+ { PCI_DEVICE_CLASSIC_4_422_PCI_NAME, 4, 0 },
+ { PCI_DEVICE_CLASSIC_8_PCI_NAME, 8, 0 },
+ { PCI_DEVICE_CLASSIC_8_422_PCI_NAME, 8, 0 },
+ { PCI_DEVICE_NEO_4_PCI_NAME, 4, 0 },
+ { PCI_DEVICE_NEO_8_PCI_NAME, 8, 0 },
+ { PCI_DEVICE_NEO_2DB9_PCI_NAME, 2, 0 },
+ { PCI_DEVICE_NEO_2DB9PRI_PCI_NAME, 2, 0 },
+ { PCI_DEVICE_NEO_2RJ45_PCI_NAME, 2, 0 },
+ { PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME, 2, 0 },
+ { PCI_DEVICE_NEO_1_422_PCI_NAME, 1, 0 },
+ { PCI_DEVICE_NEO_1_422_485_PCI_NAME, 1, 0 },
+ { PCI_DEVICE_NEO_2_422_485_PCI_NAME, 2, 0 },
+ { PCI_DEVICE_NEO_EXPRESS_8_PCI_NAME, 8, 1 },
+ { PCI_DEVICE_NEO_EXPRESS_4_PCI_NAME, 4, 1 },
+ { PCI_DEVICE_NEO_EXPRESS_4RJ45_PCI_NAME, 4, 1 },
+ { PCI_DEVICE_NEO_EXPRESS_8RJ45_PCI_NAME, 8, 1 },
+ { NULL, 0, 0 }
+};
+
+static struct pci_driver dgnc_driver = {
+ .name = "dgnc",
+ .probe = dgnc_init_one,
+ .id_table = dgnc_pci_tbl,
+ .remove = dgnc_remove_one,
+};
+
+
+char *dgnc_state_text[] = {
+ "Board Failed",
+ "Board Found",
+ "Board READY",
+};
+
+char *dgnc_driver_state_text[] = {
+ "Driver Initialized",
+ "Driver Ready."
+};
+
+
+
+/************************************************************************
+ *
+ * Driver load/unload functions
+ *
+ ************************************************************************/
+
+
+/*
+ * init_module()
+ *
+ * Module load. This is where it all starts.
+ */
+int dgnc_init_module(void)
+{
+ int rc = 0;
+
+ APR(("%s, Digi International Part Number %s\n", DG_NAME, DG_PART));
+
+ /*
+ * Initialize global stuff
+ */
+ rc = dgnc_start();
+
+ if (rc < 0) {
+ return(rc);
+ }
+
+ /*
+ * Find and configure all the cards
+ */
+ rc = dgnc_init_pci();
+
+ /*
+ * If something went wrong in the scan, bail out of driver.
+ */
+ if (rc < 0) {
+ /* Only unregister the pci driver if it was actually registered. */
+ if (dgnc_NumBoards)
+ pci_unregister_driver(&dgnc_driver);
+ else
+ printk("WARNING: dgnc driver load failed. No Digi Neo or Classic boards found.\n");
+
+ dgnc_cleanup_module();
+ }
+ else {
+ dgnc_create_driver_sysfiles(&dgnc_driver);
+ }
+
+ DPR_INIT(("Finished init_module. Returning %d\n", rc));
+ return (rc);
+}
+
+
+/*
+ * Start of driver.
+ */
+static int dgnc_start(void)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ if (dgnc_driver_start == FALSE) {
+
+ dgnc_driver_start = TRUE;
+
+ /* make sure that the globals are init'd before we do anything else */
+ dgnc_init_globals();
+
+ dgnc_NumBoards = 0;
+
+ APR(("For the tools package or updated drivers please visit http://www.digi.com\n"));
+
+ /*
+ * Register our base character device into the kernel.
+ * This allows the download daemon to connect to the downld device
+ * before any of the boards are init'ed.
+ */
+ if (!dgnc_Major_Control_Registered) {
+ /*
+ * Register management/dpa devices
+ */
+ rc = register_chrdev(0, "dgnc", &dgnc_BoardFops);
+ if (rc <= 0) {
+ APR(("Can't register dgnc driver device (%d)\n", rc));
+ rc = -ENXIO;
+ return(rc);
+ }
+ dgnc_Major = rc;
+
+ dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+ device_create_drvdata(dgnc_class, NULL,
+ MKDEV(dgnc_Major, 0),
+ NULL, "dgnc_mgmt");
+#else
+ device_create(dgnc_class, NULL,
+ MKDEV(dgnc_Major, 0),
+ NULL, "dgnc_mgmt");
+#endif
+
+ dgnc_Major_Control_Registered = TRUE;
+ }
+
+ /*
+ * Init any global tty stuff.
+ */
+ rc = dgnc_tty_preinit();
+
+ if (rc < 0) {
+ APR(("tty preinit - not enough memory (%d)\n", rc));
+ return(rc);
+ }
+
+ /* Start the poller */
+ DGNC_LOCK(dgnc_poll_lock, flags);
+ init_timer(&dgnc_poll_timer);
+ dgnc_poll_timer.function = dgnc_poll_handler;
+ dgnc_poll_timer.data = 0;
+ dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
+ dgnc_poll_timer.expires = dgnc_poll_time;
+ DGNC_UNLOCK(dgnc_poll_lock, flags);
+
+ add_timer(&dgnc_poll_timer);
+
+ dgnc_driver_state = DRIVER_READY;
+ }
+
+ return(rc);
+}
+
+/*
+ * Register pci driver, and return how many boards we have.
+ */
+static int dgnc_init_pci(void)
+{
+ return pci_register_driver(&dgnc_driver);
+}
+
+
+/* returns count (>= 0), or negative on error */
+static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int rc;
+
+ /* wake up and enable device */
+ rc = pci_enable_device(pdev);
+
+ if (rc < 0) {
+ rc = -EIO;
+ } else {
+ rc = dgnc_probe1(pdev, ent->driver_data);
+ if (rc == 0) {
+ dgnc_NumBoards++;
+ DPR_INIT(("Incrementing numboards to %d\n", dgnc_NumBoards));
+ }
+ }
+ return rc;
+}
+
+static int dgnc_probe1(struct pci_dev *pdev, int card_type)
+{
+ return dgnc_found_board(pdev, card_type);
+}
+
+
+static void dgnc_remove_one(struct pci_dev *dev)
+{
+ /* Do Nothing */
+}
+
+/*
+ * dgnc_cleanup_module()
+ *
+ * Module unload. This is where it all ends.
+ */
+void dgnc_cleanup_module(void)
+{
+ int i;
+ ulong lock_flags;
+
+ DGNC_LOCK(dgnc_poll_lock, lock_flags);
+ dgnc_poll_stop = 1;
+ DGNC_UNLOCK(dgnc_poll_lock, lock_flags);
+
+ /* Turn off poller right away. */
+ del_timer_sync(&dgnc_poll_timer);
+
+ dgnc_remove_driver_sysfiles(&dgnc_driver);
+
+ if (dgnc_Major_Control_Registered) {
+ device_destroy(dgnc_class, MKDEV(dgnc_Major, 0));
+ class_destroy(dgnc_class);
+ unregister_chrdev(dgnc_Major, "dgnc");
+ }
+
+ for (i = 0; i < dgnc_NumBoards; ++i) {
+ dgnc_remove_ports_sysfiles(dgnc_Board[i]);
+ dgnc_tty_uninit(dgnc_Board[i]);
+ dgnc_cleanup_board(dgnc_Board[i]);
+ }
+
+ dgnc_tty_post_uninit();
+
+#if defined(DGNC_TRACER)
+ /* last thing, make sure we release the tracebuffer */
+ dgnc_tracer_free();
+#endif
+ if (dgnc_NumBoards)
+ pci_unregister_driver(&dgnc_driver);
+}
+
+
+/*
+ * dgnc_cleanup_board()
+ *
+ * Free all the memory associated with a board
+ */
+static void dgnc_cleanup_board(struct board_t *brd)
+{
+ int i = 0;
+
+ if(!brd || brd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ switch (brd->device) {
+ case PCI_DEVICE_CLASSIC_4_DID:
+ case PCI_DEVICE_CLASSIC_8_DID:
+ case PCI_DEVICE_CLASSIC_4_422_DID:
+ case PCI_DEVICE_CLASSIC_8_422_DID:
+
+ /* Tell card not to interrupt anymore. */
+ outb(0, brd->iobase + 0x4c);
+ break;
+
+ default:
+ break;
+ }
+
+ if (brd->irq)
+ free_irq(brd->irq, brd);
+
+ tasklet_kill(&brd->helper_tasklet);
+
+ if (brd->re_map_membase) {
+ iounmap(brd->re_map_membase);
+ brd->re_map_membase = NULL;
+ }
+
+ if (brd->msgbuf_head) {
+ unsigned long flags;
+
+ DGNC_LOCK(dgnc_global_lock, flags);
+ brd->msgbuf = NULL;
+ printk(brd->msgbuf_head);
+ kfree(brd->msgbuf_head);
+ brd->msgbuf_head = NULL;
+ DGNC_UNLOCK(dgnc_global_lock, flags);
+ }
+
+ /* Free all allocated channels structs */
+ for (i = 0; i < MAXPORTS ; i++) {
+ if (brd->channels[i]) {
+ if (brd->channels[i]->ch_rqueue)
+ kfree(brd->channels[i]->ch_rqueue);
+ if (brd->channels[i]->ch_equeue)
+ kfree(brd->channels[i]->ch_equeue);
+ if (brd->channels[i]->ch_wqueue)
+ kfree(brd->channels[i]->ch_wqueue);
+
+ kfree(brd->channels[i]);
+ brd->channels[i] = NULL;
+ }
+ }
+
+ if (brd->flipbuf)
+ kfree(brd->flipbuf);
+
+ dgnc_Board[brd->boardnum] = NULL;
+
+ kfree(brd);
+}
+
+
+/*
+ * dgnc_found_board()
+ *
+ * A board has been found, init it.
+ */
+static int dgnc_found_board(struct pci_dev *pdev, int id)
+{
+ struct board_t *brd;
+ unsigned int pci_irq;
+ int i = 0;
+ int rc = 0;
+ unsigned long flags;
+
+ /* get the board structure and prep it */
+ brd = dgnc_Board[dgnc_NumBoards] =
+ (struct board_t *) kzalloc(sizeof(struct board_t), GFP_KERNEL);
+ if (!brd) {
+ APR(("memory allocation for board structure failed\n"));
+ return(-ENOMEM);
+ }
+
+ /* make a temporary message buffer for the boot messages */
+ brd->msgbuf = brd->msgbuf_head =
+ (char *) kzalloc(sizeof(char) * 8192, GFP_KERNEL);
+ if (!brd->msgbuf) {
+ kfree(brd);
+ APR(("memory allocation for board msgbuf failed\n"));
+ return(-ENOMEM);
+ }
+
+ /* store the info for the board we've found */
+ brd->magic = DGNC_BOARD_MAGIC;
+ brd->boardnum = dgnc_NumBoards;
+ brd->vendor = dgnc_pci_tbl[id].vendor;
+ brd->device = dgnc_pci_tbl[id].device;
+ brd->pdev = pdev;
+ brd->pci_bus = pdev->bus->number;
+ brd->pci_slot = PCI_SLOT(pdev->devfn);
+ brd->name = dgnc_Ids[id].name;
+ brd->maxports = dgnc_Ids[id].maxports;
+ if (dgnc_Ids[i].is_pci_express)
+ brd->bd_flags |= BD_IS_PCI_EXPRESS;
+ brd->dpastatus = BD_NOFEP;
+ init_waitqueue_head(&brd->state_wait);
+
+ DGNC_SPINLOCK_INIT(brd->bd_lock);
+ DGNC_SPINLOCK_INIT(brd->bd_intr_lock);
+
+ brd->state = BOARD_FOUND;
+
+ for (i = 0; i < MAXPORTS; i++) {
+ brd->channels[i] = NULL;
+ }
+
+ /* store which card & revision we have */
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor);
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
+
+ pci_irq = pdev->irq;
+ brd->irq = pci_irq;
+
+
+ switch(brd->device) {
+
+ case PCI_DEVICE_CLASSIC_4_DID:
+ case PCI_DEVICE_CLASSIC_8_DID:
+ case PCI_DEVICE_CLASSIC_4_422_DID:
+ case PCI_DEVICE_CLASSIC_8_422_DID:
+
+ brd->dpatype = T_CLASSIC | T_PCIBUS;
+
+ DPR_INIT(("dgnc_found_board - Classic.\n"));
+
+ /*
+ * For PCI ClassicBoards
+ * PCI Local Address (i.e. "resource" number) space
+ * 0 PLX Memory Mapped Config
+ * 1 PLX I/O Mapped Config
+ * 2 I/O Mapped UARTs and Status
+ * 3 Memory Mapped VPD
+ * 4 Memory Mapped UARTs and Status
+ */
+
+
+ /* get the PCI Base Address Registers */
+ brd->membase = pci_resource_start(pdev, 4);
+
+ if (!brd->membase) {
+ APR(("card has no PCI IO resources, failing board.\n"));
+ return -ENODEV;
+ }
+
+ brd->membase_end = pci_resource_end(pdev, 4);
+
+ if (brd->membase & 1)
+ brd->membase &= ~3;
+ else
+ brd->membase &= ~15;
+
+ brd->iobase = pci_resource_start(pdev, 1);
+ brd->iobase_end = pci_resource_end(pdev, 1);
+ brd->iobase = ((unsigned int) (brd->iobase)) & 0xFFFE;
+
+ /* Assign the board_ops struct */
+ brd->bd_ops = &dgnc_cls_ops;
+
+ brd->bd_uart_offset = 0x8;
+ brd->bd_dividend = 921600;
+
+ dgnc_do_remap(brd);
+
+ /* Get and store the board VPD, if it exists */
+ brd->bd_ops->vpd(brd);
+
+ /*
+ * Enable Local Interrupt 1 (0x1),
+ * Local Interrupt 1 Polarity Active high (0x2),
+ * Enable PCI interrupt (0x40)
+ */
+ outb(0x43, brd->iobase + 0x4c);
+
+ break;
+
+
+ case PCI_DEVICE_NEO_4_DID:
+ case PCI_DEVICE_NEO_8_DID:
+ case PCI_DEVICE_NEO_2DB9_DID:
+ case PCI_DEVICE_NEO_2DB9PRI_DID:
+ case PCI_DEVICE_NEO_2RJ45_DID:
+ case PCI_DEVICE_NEO_2RJ45PRI_DID:
+ case PCI_DEVICE_NEO_1_422_DID:
+ case PCI_DEVICE_NEO_1_422_485_DID:
+ case PCI_DEVICE_NEO_2_422_485_DID:
+ case PCI_DEVICE_NEO_EXPRESS_8_DID:
+ case PCI_DEVICE_NEO_EXPRESS_4_DID:
+ case PCI_DEVICE_NEO_EXPRESS_4RJ45_DID:
+ case PCI_DEVICE_NEO_EXPRESS_8RJ45_DID:
+
+ /*
+ * This chip is set up 100% when we get to it.
+ * No need to enable global interrupts or anything.
+ */
+ if (brd->bd_flags & BD_IS_PCI_EXPRESS)
+ brd->dpatype = T_NEO_EXPRESS | T_PCIBUS;
+ else
+ brd->dpatype = T_NEO | T_PCIBUS;
+
+ DPR_INIT(("dgnc_found_board - NEO.\n"));
+
+ /* get the PCI Base Address Registers */
+ brd->membase = pci_resource_start(pdev, 0);
+ brd->membase_end = pci_resource_end(pdev, 0);
+
+ if (brd->membase & 1)
+ brd->membase &= ~3;
+ else
+ brd->membase &= ~15;
+
+ /* Assign the board_ops struct */
+ brd->bd_ops = &dgnc_neo_ops;
+
+ brd->bd_uart_offset = 0x200;
+ brd->bd_dividend = 921600;
+
+ dgnc_do_remap(brd);
+
+ if (brd->re_map_membase) {
+
+ /* After remap is complete, we need to read and store the dvid */
+ brd->dvid = readb(brd->re_map_membase + 0x8D);
+
+ /* Get and store the board VPD, if it exists */
+ brd->bd_ops->vpd(brd);
+ }
+ break;
+
+ default:
+ APR(("Did not find any compatible Neo or Classic PCI boards in system.\n"));
+ return (-ENXIO);
+
+ }
+
+ /*
+ * Do tty device initialization.
+ */
+
+ rc = dgnc_tty_register(brd);
+ if (rc < 0) {
+ dgnc_tty_uninit(brd);
+ APR(("Can't register tty devices (%d)\n", rc));
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ goto failed;
+ }
+
+ rc = dgnc_finalize_board_init(brd);
+ if (rc < 0) {
+ APR(("Can't finalize board init (%d)\n", rc));
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+
+ goto failed;
+ }
+
+ rc = dgnc_tty_init(brd);
+ if (rc < 0) {
+ dgnc_tty_uninit(brd);
+ APR(("Can't init tty devices (%d)\n", rc));
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+
+ goto failed;
+ }
+
+ brd->state = BOARD_READY;
+ brd->dpastatus = BD_RUNNING;
+
+ dgnc_create_ports_sysfiles(brd);
+
+ /* init our poll helper tasklet */
+ tasklet_init(&brd->helper_tasklet, brd->bd_ops->tasklet, (unsigned long) brd);
+
+ DPR_INIT(("dgnc_scan(%d) - printing out the msgbuf\n", i));
+ DGNC_LOCK(dgnc_global_lock, flags);
+ brd->msgbuf = NULL;
+ printk(brd->msgbuf_head);
+ kfree(brd->msgbuf_head);
+ brd->msgbuf_head = NULL;
+ DGNC_UNLOCK(dgnc_global_lock, flags);
+
+ /*
+ * allocate flip buffer for board.
+ *
+ * Okay to malloc with GFP_KERNEL, we are not at interrupt
+ * context, and there are no locks held.
+ */
+ brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
+
+ wake_up_interruptible(&brd->state_wait);
+
+ return(0);
+
+failed:
+
+ return (-ENXIO);
+
+}
+
+
+static int dgnc_finalize_board_init(struct board_t *brd) {
+ int rc = 0;
+
+ DPR_INIT(("dgnc_finalize_board_init() - start\n"));
+
+ if (!brd || brd->magic != DGNC_BOARD_MAGIC)
+ return(-ENODEV);
+
+ DPR_INIT(("dgnc_finalize_board_init() - start #2\n"));
+
+ if (brd->irq) {
+ rc = request_irq(brd->irq, brd->bd_ops->intr, IRQF_SHARED, "DGNC", brd);
+
+ if (rc) {
+ printk("Failed to hook IRQ %d\n",brd->irq);
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
+ rc = -ENODEV;
+ } else {
+ DPR_INIT(("Requested and received usage of IRQ %d\n", brd->irq));
+ }
+ }
+ return(rc);
+}
+
+/*
+ * Remap PCI memory.
+ */
+static void dgnc_do_remap(struct board_t *brd)
+{
+
+ if (!brd || brd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ brd->re_map_membase = ioremap(brd->membase, 0x1000);
+
+ DPR_INIT(("remapped mem: 0x%p\n", brd->re_map_membase));
+}
+
+
+/*****************************************************************************
+*
+* Function:
+*
+* dgnc_poll_handler
+*
+* Author:
+*
+* Scott H Kilau
+*
+* Parameters:
+*
+* dummy -- ignored
+*
+* Return Values:
+*
+* none
+*
+* Description:
+*
+* As each timer expires, it determines (a) whether the "transmit"
+* waiter needs to be woken up, and (b) whether the poller needs to
+* be rescheduled.
+*
+******************************************************************************/
+
+static void dgnc_poll_handler(ulong dummy)
+{
+ struct board_t *brd;
+ unsigned long lock_flags;
+ int i;
+ unsigned long new_time;
+
+ dgnc_poll_counter++;
+
+ /*
+ * Do not start the board state machine until
+ * driver tells us its up and running, and has
+ * everything it needs.
+ */
+ if (dgnc_driver_state != DRIVER_READY) {
+ goto schedule_poller;
+ }
+
+ /* Go thru each board, kicking off a tasklet for each if needed */
+ for (i = 0; i < dgnc_NumBoards; i++) {
+ brd = dgnc_Board[i];
+
+ DGNC_LOCK(brd->bd_lock, lock_flags);
+
+ /* If board is in a failed state, don't bother scheduling a tasklet */
+ if (brd->state == BOARD_FAILED) {
+ DGNC_UNLOCK(brd->bd_lock, lock_flags);
+ continue;
+ }
+
+ /* Schedule a poll helper task */
+ tasklet_schedule(&brd->helper_tasklet);
+
+ DGNC_UNLOCK(brd->bd_lock, lock_flags);
+ }
+
+schedule_poller:
+
+ /*
+ * Schedule ourself back at the nominal wakeup interval.
+ */
+ DGNC_LOCK(dgnc_poll_lock, lock_flags);
+ dgnc_poll_time += dgnc_jiffies_from_ms(dgnc_poll_tick);
+
+ new_time = dgnc_poll_time - jiffies;
+
+ if ((ulong) new_time >= 2 * dgnc_poll_tick) {
+ dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
+ }
+
+ init_timer(&dgnc_poll_timer);
+ dgnc_poll_timer.function = dgnc_poll_handler;
+ dgnc_poll_timer.data = 0;
+ dgnc_poll_timer.expires = dgnc_poll_time;
+ DGNC_UNLOCK(dgnc_poll_lock, lock_flags);
+
+ if (!dgnc_poll_stop)
+ add_timer(&dgnc_poll_timer);
+}
+
+/*
+ * dgnc_init_globals()
+ *
+ * This is where we initialize the globals from the static insmod
+ * configuration variables. These are declared near the head of
+ * this file.
+ */
+static void dgnc_init_globals(void)
+{
+ int i = 0;
+
+ dgnc_rawreadok = rawreadok;
+ dgnc_trcbuf_size = trcbuf_size;
+ dgnc_debug = debug;
+
+ for (i = 0; i < MAXBOARDS; i++) {
+ dgnc_Board[i] = NULL;
+ }
+
+ init_timer(&dgnc_poll_timer);
+}
+
+
+/************************************************************************
+ *
+ * Utility functions
+ *
+ ************************************************************************/
+
+/*
+ * dgnc_ms_sleep()
+ *
+ * Put the driver to sleep for x ms's
+ *
+ * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal.
+ */
+int dgnc_ms_sleep(ulong ms)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout((ms * HZ) / 1000);
+ return (signal_pending(current));
+}
+
+
+
+/*
+ * dgnc_ioctl_name() : Returns a text version of each ioctl value.
+ */
+char *dgnc_ioctl_name(int cmd)
+{
+ switch(cmd) {
+
+ case TCGETA: return("TCGETA");
+ case TCGETS: return("TCGETS");
+ case TCSETA: return("TCSETA");
+ case TCSETS: return("TCSETS");
+ case TCSETAW: return("TCSETAW");
+ case TCSETSW: return("TCSETSW");
+ case TCSETAF: return("TCSETAF");
+ case TCSETSF: return("TCSETSF");
+ case TCSBRK: return("TCSBRK");
+ case TCXONC: return("TCXONC");
+ case TCFLSH: return("TCFLSH");
+ case TIOCGSID: return("TIOCGSID");
+
+ case TIOCGETD: return("TIOCGETD");
+ case TIOCSETD: return("TIOCSETD");
+ case TIOCGWINSZ: return("TIOCGWINSZ");
+ case TIOCSWINSZ: return("TIOCSWINSZ");
+
+ case TIOCMGET: return("TIOCMGET");
+ case TIOCMSET: return("TIOCMSET");
+ case TIOCMBIS: return("TIOCMBIS");
+ case TIOCMBIC: return("TIOCMBIC");
+
+ /* from digi.h */
+ case DIGI_SETA: return("DIGI_SETA");
+ case DIGI_SETAW: return("DIGI_SETAW");
+ case DIGI_SETAF: return("DIGI_SETAF");
+ case DIGI_SETFLOW: return("DIGI_SETFLOW");
+ case DIGI_SETAFLOW: return("DIGI_SETAFLOW");
+ case DIGI_GETFLOW: return("DIGI_GETFLOW");
+ case DIGI_GETAFLOW: return("DIGI_GETAFLOW");
+ case DIGI_GETA: return("DIGI_GETA");
+ case DIGI_GEDELAY: return("DIGI_GEDELAY");
+ case DIGI_SEDELAY: return("DIGI_SEDELAY");
+ case DIGI_GETCUSTOMBAUD: return("DIGI_GETCUSTOMBAUD");
+ case DIGI_SETCUSTOMBAUD: return("DIGI_SETCUSTOMBAUD");
+ case TIOCMODG: return("TIOCMODG");
+ case TIOCMODS: return("TIOCMODS");
+ case TIOCSDTR: return("TIOCSDTR");
+ case TIOCCDTR: return("TIOCCDTR");
+
+ default: return("unknown");
+ }
+}
diff --git a/drivers/staging/dgnc/dgnc_driver.h b/drivers/staging/dgnc/dgnc_driver.h
new file mode 100644
index 00000000000..218b15dccb7
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_driver.h
@@ -0,0 +1,563 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *************************************************************************
+ *
+ * Driver includes
+ *
+ *************************************************************************/
+
+#ifndef __DGNC_DRIVER_H
+#define __DGNC_DRIVER_H
+
+#include <linux/types.h> /* To pick up the varions Linux types */
+#include <linux/tty.h> /* To pick up the various tty structs/defines */
+#include <linux/interrupt.h> /* For irqreturn_t type */
+
+#include "dgnc_types.h" /* Additional types needed by the Digi header files */
+#include "digi.h" /* Digi specific ioctl header */
+#include "dgnc_kcompat.h" /* Kernel 2.4/2.6 compat includes */
+#include "dgnc_sysfs.h" /* Support for SYSFS */
+
+/*************************************************************************
+ *
+ * Driver defines
+ *
+ *************************************************************************/
+
+/*
+ * Driver identification, error and debugging statments
+ *
+ * In theory, you can change all occurances of "digi" in the next
+ * three lines, and the driver printk's will all automagically change.
+ *
+ * APR((fmt, args, ...)); Always prints message
+ * DPR((fmt, args, ...)); Only prints if DGNC_TRACER is defined at
+ * compile time and dgnc_debug!=0
+ */
+#define PROCSTR "dgnc" /* /proc entries */
+#define DEVSTR "/dev/dg/dgnc" /* /dev entries */
+#define DRVSTR "dgnc" /* Driver name string
+ * displayed by APR */
+#define APR(args) do { PRINTF_TO_KMEM(args); printk(DRVSTR": "); printk args; \
+ } while (0)
+#define RAPR(args) do { PRINTF_TO_KMEM(args); printk args; } while (0)
+
+#define TRC_TO_CONSOLE 1
+
+/*
+ * Debugging levels can be set using debug insmod variable
+ * They can also be compiled out completely.
+ */
+
+#define DBG_INIT (dgnc_debug & 0x01)
+#define DBG_BASIC (dgnc_debug & 0x02)
+#define DBG_CORE (dgnc_debug & 0x04)
+
+#define DBG_OPEN (dgnc_debug & 0x08)
+#define DBG_CLOSE (dgnc_debug & 0x10)
+#define DBG_READ (dgnc_debug & 0x20)
+#define DBG_WRITE (dgnc_debug & 0x40)
+
+#define DBG_IOCTL (dgnc_debug & 0x80)
+
+#define DBG_PROC (dgnc_debug & 0x100)
+#define DBG_PARAM (dgnc_debug & 0x200)
+#define DBG_PSCAN (dgnc_debug & 0x400)
+#define DBG_EVENT (dgnc_debug & 0x800)
+
+#define DBG_DRAIN (dgnc_debug & 0x1000)
+#define DBG_MSIGS (dgnc_debug & 0x2000)
+
+#define DBG_MGMT (dgnc_debug & 0x4000)
+#define DBG_INTR (dgnc_debug & 0x8000)
+
+#define DBG_CARR (dgnc_debug & 0x10000)
+
+
+#if defined(DGNC_TRACER)
+
+# if defined(TRC_TO_KMEM)
+/* Choose one: */
+# define TRC_ON_OVERFLOW_WRAP_AROUND
+# undef TRC_ON_OVERFLOW_SHIFT_BUFFER
+# endif //TRC_TO_KMEM
+
+# define TRC_MAXMSG 1024
+# define TRC_OVERFLOW "(OVERFLOW)"
+# define TRC_DTRC "/usr/bin/dtrc"
+
+#if defined TRC_TO_CONSOLE
+#define PRINTF_TO_CONSOLE(args) { printk(DRVSTR": "); printk args; }
+#else //!defined TRACE_TO_CONSOLE
+#define PRINTF_TO_CONSOLE(args)
+#endif
+
+#if defined TRC_TO_KMEM
+#define PRINTF_TO_KMEM(args) dgnc_tracef args
+#else //!defined TRC_TO_KMEM
+#define PRINTF_TO_KMEM(args)
+#endif
+
+#define TRC(args) { PRINTF_TO_KMEM(args); PRINTF_TO_CONSOLE(args) }
+
+# define DPR_INIT(ARGS) if (DBG_INIT) TRC(ARGS)
+# define DPR_BASIC(ARGS) if (DBG_BASIC) TRC(ARGS)
+# define DPR_CORE(ARGS) if (DBG_CORE) TRC(ARGS)
+# define DPR_OPEN(ARGS) if (DBG_OPEN) TRC(ARGS)
+# define DPR_CLOSE(ARGS) if (DBG_CLOSE) TRC(ARGS)
+# define DPR_READ(ARGS) if (DBG_READ) TRC(ARGS)
+# define DPR_WRITE(ARGS) if (DBG_WRITE) TRC(ARGS)
+# define DPR_IOCTL(ARGS) if (DBG_IOCTL) TRC(ARGS)
+# define DPR_PROC(ARGS) if (DBG_PROC) TRC(ARGS)
+# define DPR_PARAM(ARGS) if (DBG_PARAM) TRC(ARGS)
+# define DPR_PSCAN(ARGS) if (DBG_PSCAN) TRC(ARGS)
+# define DPR_EVENT(ARGS) if (DBG_EVENT) TRC(ARGS)
+# define DPR_DRAIN(ARGS) if (DBG_DRAIN) TRC(ARGS)
+# define DPR_CARR(ARGS) if (DBG_CARR) TRC(ARGS)
+# define DPR_MGMT(ARGS) if (DBG_MGMT) TRC(ARGS)
+# define DPR_INTR(ARGS) if (DBG_INTR) TRC(ARGS)
+# define DPR_MSIGS(ARGS) if (DBG_MSIGS) TRC(ARGS)
+
+# define DPR(ARGS) if (dgnc_debug) TRC(ARGS)
+# define P(X) dgnc_tracef(#X "=%p\n", X)
+# define X(X) dgnc_tracef(#X "=%x\n", X)
+
+#else//!defined DGNC_TRACER
+
+#define PRINTF_TO_KMEM(args)
+# define TRC(ARGS)
+# define DPR_INIT(ARGS)
+# define DPR_BASIC(ARGS)
+# define DPR_CORE(ARGS)
+# define DPR_OPEN(ARGS)
+# define DPR_CLOSE(ARGS)
+# define DPR_READ(ARGS)
+# define DPR_WRITE(ARGS)
+# define DPR_IOCTL(ARGS)
+# define DPR_PROC(ARGS)
+# define DPR_PARAM(ARGS)
+# define DPR_PSCAN(ARGS)
+# define DPR_EVENT(ARGS)
+# define DPR_DRAIN(ARGS)
+# define DPR_CARR(ARGS)
+# define DPR_MGMT(ARGS)
+# define DPR_INTR(ARGS)
+# define DPR_MSIGS(ARGS)
+
+# define DPR(args)
+
+#endif//DGNC_TRACER
+
+/* Number of boards we support at once. */
+#define MAXBOARDS 20
+#define MAXPORTS 8
+#define MAXTTYNAMELEN 200
+
+/* Our 3 magic numbers for our board, channel and unit structs */
+#define DGNC_BOARD_MAGIC 0x5c6df104
+#define DGNC_CHANNEL_MAGIC 0x6c6df104
+#define DGNC_UNIT_MAGIC 0x7c6df104
+
+/* Serial port types */
+#define DGNC_SERIAL 0
+#define DGNC_PRINT 1
+
+#define SERIAL_TYPE_NORMAL 1
+
+#define PORT_NUM(dev) ((dev) & 0x7f)
+#define IS_PRINT(dev) (((dev) & 0xff) >= 0x80)
+
+/* MAX number of stop characters we will send when our read queue is getting full */
+#define MAX_STOPS_SENT 5
+
+/* 4 extra for alignment play space */
+#define WRITEBUFLEN ((4096) + 4)
+#define MYFLIPLEN N_TTY_BUF_SIZE
+
+#define dgnc_jiffies_from_ms(a) (((a) * HZ) / 1000)
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially. This is the same structure that is defined
+ * as the default in tty_io.c with the same settings overriden as in serial.c
+ *
+ * In short, this should match the internal serial ports' defaults.
+ */
+#define DEFAULT_IFLAGS (ICRNL | IXON)
+#define DEFAULT_OFLAGS (OPOST | ONLCR)
+#define DEFAULT_CFLAGS (B9600 | CS8 | CREAD | HUPCL | CLOCAL)
+#define DEFAULT_LFLAGS (ISIG | ICANON | ECHO | ECHOE | ECHOK | \
+ ECHOCTL | ECHOKE | IEXTEN)
+
+#ifndef _POSIX_VDISABLE
+#define _POSIX_VDISABLE '\0'
+#endif
+
+#define SNIFF_MAX 65536 /* Sniff buffer size (2^n) */
+#define SNIFF_MASK (SNIFF_MAX - 1) /* Sniff wrap mask */
+
+/*
+ * Lock function/defines.
+ * Makes spotting lock/unlock locations easier.
+ */
+# define DGNC_SPINLOCK_INIT(x) spin_lock_init(&(x))
+# define DGNC_LOCK(x,y) spin_lock_irqsave(&(x), y)
+# define DGNC_UNLOCK(x,y) spin_unlock_irqrestore(&(x), y)
+
+/*
+ * All the possible states the driver can be while being loaded.
+ */
+enum {
+ DRIVER_INITIALIZED = 0,
+ DRIVER_READY
+};
+
+/*
+ * All the possible states the board can be while booting up.
+ */
+enum {
+ BOARD_FAILED = 0,
+ BOARD_FOUND,
+ BOARD_READY
+};
+
+
+/*************************************************************************
+ *
+ * Structures and closely related defines.
+ *
+ *************************************************************************/
+
+struct board_t;
+struct channel_t;
+
+/************************************************************************
+ * Per board operations structure *
+ ************************************************************************/
+struct board_ops {
+ void (*tasklet) (unsigned long data);
+ irqreturn_t (*intr) (int irq, void *voidbrd);
+ void (*uart_init) (struct channel_t *ch);
+ void (*uart_off) (struct channel_t *ch);
+ int (*drain) (struct tty_struct *tty, uint seconds);
+ void (*param) (struct tty_struct *tty);
+ void (*vpd) (struct board_t *brd);
+ void (*assert_modem_signals) (struct channel_t *ch);
+ void (*flush_uart_write) (struct channel_t *ch);
+ void (*flush_uart_read) (struct channel_t *ch);
+ void (*disable_receiver) (struct channel_t *ch);
+ void (*enable_receiver) (struct channel_t *ch);
+ void (*send_break) (struct channel_t *ch, int);
+ void (*send_start_character) (struct channel_t *ch);
+ void (*send_stop_character) (struct channel_t *ch);
+ void (*copy_data_from_queue_to_uart) (struct channel_t *ch);
+ uint (*get_uart_bytes_left) (struct channel_t *ch);
+ void (*send_immediate_char) (struct channel_t *ch, unsigned char);
+};
+
+/************************************************************************
+ * Device flag definitions for bd_flags.
+ ************************************************************************/
+#define BD_IS_PCI_EXPRESS 0x0001 /* Is a PCI Express board */
+
+
+/*
+ * Per-board information
+ */
+struct board_t {
+ int magic; /* Board Magic number. */
+ int boardnum; /* Board number: 0-32 */
+
+ int type; /* Type of board */
+ char *name; /* Product Name */
+ struct pci_dev *pdev; /* Pointer to the pci_dev struct */
+ unsigned long bd_flags; /* Board flags */
+ u16 vendor; /* PCI vendor ID */
+ u16 device; /* PCI device ID */
+ u16 subvendor; /* PCI subsystem vendor ID */
+ u16 subdevice; /* PCI subsystem device ID */
+ uchar rev; /* PCI revision ID */
+ uint pci_bus; /* PCI bus value */
+ uint pci_slot; /* PCI slot value */
+ uint maxports; /* MAX ports this board can handle */
+ uchar dvid; /* Board specific device id */
+ uchar vpd[128]; /* VPD of board, if found */
+ uchar serial_num[20]; /* Serial number of board, if found in VPD */
+
+ spinlock_t bd_lock; /* Used to protect board */
+
+ spinlock_t bd_intr_lock; /* Used to protect the poller tasklet and
+ * the interrupt routine from each other.
+ */
+
+ uint state; /* State of card. */
+ wait_queue_head_t state_wait; /* Place to sleep on for state change */
+
+ struct tasklet_struct helper_tasklet; /* Poll helper tasklet */
+
+ uint nasync; /* Number of ports on card */
+
+ uint irq; /* Interrupt request number */
+ ulong intr_count; /* Count of interrupts */
+ ulong intr_modem; /* Count of interrupts */
+ ulong intr_tx; /* Count of interrupts */
+ ulong intr_rx; /* Count of interrupts */
+
+ ulong membase; /* Start of base memory of the card */
+ ulong membase_end; /* End of base memory of the card */
+
+ u8 __iomem *re_map_membase;/* Remapped memory of the card */
+
+ ulong iobase; /* Start of io base of the card */
+ ulong iobase_end; /* End of io base of the card */
+
+ uint bd_uart_offset; /* Space between each UART */
+
+ struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */
+
+ struct tty_driver SerialDriver;
+ char SerialName[200];
+ struct tty_driver PrintDriver;
+ char PrintName[200];
+
+ uint dgnc_Major_Serial_Registered;
+ uint dgnc_Major_TransparentPrint_Registered;
+
+ uint dgnc_Serial_Major;
+ uint dgnc_TransparentPrint_Major;
+
+ uint TtyRefCnt;
+
+ char *flipbuf; /* Our flip buffer, alloced if board is found */
+
+ u16 dpatype; /* The board "type", as defined by DPA */
+ u16 dpastatus; /* The board "status", as defined by DPA */
+
+ /*
+ * Mgmt data.
+ */
+ char *msgbuf_head;
+ char *msgbuf;
+
+ uint bd_dividend; /* Board/UARTs specific dividend */
+
+ struct board_ops *bd_ops;
+
+ /* /proc/<board> entries */
+ struct proc_dir_entry *proc_entry_pointer;
+ struct dgnc_proc_entry *dgnc_board_table;
+
+};
+
+
+/************************************************************************
+ * Unit flag definitions for un_flags.
+ ************************************************************************/
+#define UN_ISOPEN 0x0001 /* Device is open */
+#define UN_CLOSING 0x0002 /* Line is being closed */
+#define UN_IMM 0x0004 /* Service immediately */
+#define UN_BUSY 0x0008 /* Some work this channel */
+#define UN_BREAKI 0x0010 /* Input break received */
+#define UN_PWAIT 0x0020 /* Printer waiting for terminal */
+#define UN_TIME 0x0040 /* Waiting on time */
+#define UN_EMPTY 0x0080 /* Waiting output queue empty */
+#define UN_LOW 0x0100 /* Waiting output low water mark*/
+#define UN_EXCL_OPEN 0x0200 /* Open for exclusive use */
+#define UN_WOPEN 0x0400 /* Device waiting for open */
+#define UN_WIOCTL 0x0800 /* Device waiting for open */
+#define UN_HANGUP 0x8000 /* Carrier lost */
+
+struct device;
+
+/************************************************************************
+ * Structure for terminal or printer unit.
+ ************************************************************************/
+struct un_t {
+ int magic; /* Unit Magic Number. */
+ struct channel_t *un_ch;
+ ulong un_time;
+ uint un_type;
+ uint un_open_count; /* Counter of opens to port */
+ struct tty_struct *un_tty;/* Pointer to unit tty structure */
+ uint un_flags; /* Unit flags */
+ wait_queue_head_t un_flags_wait; /* Place to sleep to wait on unit */
+ uint un_dev; /* Minor device number */
+ struct device *un_sysfs;
+};
+
+
+/************************************************************************
+ * Device flag definitions for ch_flags.
+ ************************************************************************/
+#define CH_PRON 0x0001 /* Printer on string */
+#define CH_STOP 0x0002 /* Output is stopped */
+#define CH_STOPI 0x0004 /* Input is stopped */
+#define CH_CD 0x0008 /* Carrier is present */
+#define CH_FCAR 0x0010 /* Carrier forced on */
+#define CH_HANGUP 0x0020 /* Hangup received */
+
+#define CH_RECEIVER_OFF 0x0040 /* Receiver is off */
+#define CH_OPENING 0x0080 /* Port in fragile open state */
+#define CH_CLOSING 0x0100 /* Port in fragile close state */
+#define CH_FIFO_ENABLED 0x0200 /* Port has FIFOs enabled */
+#define CH_TX_FIFO_EMPTY 0x0400 /* TX Fifo is completely empty */
+#define CH_TX_FIFO_LWM 0x0800 /* TX Fifo is below Low Water */
+#define CH_BREAK_SENDING 0x1000 /* Break is being sent */
+#define CH_LOOPBACK 0x2000 /* Channel is in lookback mode */
+#define CH_FLIPBUF_IN_USE 0x4000 /* Channel's flipbuf is in use */
+#define CH_BAUD0 0x08000 /* Used for checking B0 transitions */
+#define CH_FORCED_STOP 0x20000 /* Output is forcibly stopped */
+#define CH_FORCED_STOPI 0x40000 /* Input is forcibly stopped */
+
+/*
+ * Definitions for ch_sniff_flags
+ */
+#define SNIFF_OPEN 0x1
+#define SNIFF_WAIT_DATA 0x2
+#define SNIFF_WAIT_SPACE 0x4
+
+
+/* Our Read/Error/Write queue sizes */
+#define RQUEUEMASK 0x1FFF /* 8 K - 1 */
+#define EQUEUEMASK 0x1FFF /* 8 K - 1 */
+#define WQUEUEMASK 0x0FFF /* 4 K - 1 */
+#define RQUEUESIZE (RQUEUEMASK + 1)
+#define EQUEUESIZE RQUEUESIZE
+#define WQUEUESIZE (WQUEUEMASK + 1)
+
+
+/************************************************************************
+ * Channel information structure.
+ ************************************************************************/
+struct channel_t {
+ int magic; /* Channel Magic Number */
+ struct board_t *ch_bd; /* Board structure pointer */
+ struct digi_t ch_digi; /* Transparent Print structure */
+ struct un_t ch_tun; /* Terminal unit info */
+ struct un_t ch_pun; /* Printer unit info */
+
+ spinlock_t ch_lock; /* provide for serialization */
+ wait_queue_head_t ch_flags_wait;
+
+ uint ch_portnum; /* Port number, 0 offset. */
+ uint ch_open_count; /* open count */
+ uint ch_flags; /* Channel flags */
+
+ ulong ch_close_delay; /* How long we should drop RTS/DTR for */
+
+ ulong ch_cpstime; /* Time for CPS calculations */
+
+ tcflag_t ch_c_iflag; /* channel iflags */
+ tcflag_t ch_c_cflag; /* channel cflags */
+ tcflag_t ch_c_oflag; /* channel oflags */
+ tcflag_t ch_c_lflag; /* channel lflags */
+ uchar ch_stopc; /* Stop character */
+ uchar ch_startc; /* Start character */
+
+ uint ch_old_baud; /* Cache of the current baud */
+ uint ch_custom_speed;/* Custom baud, if set */
+
+ uint ch_wopen; /* Waiting for open process cnt */
+
+ uchar ch_mostat; /* FEP output modem status */
+ uchar ch_mistat; /* FEP input modem status */
+
+ struct neo_uart_struct __iomem *ch_neo_uart; /* Pointer to the "mapped" UART struct */
+ struct cls_uart_struct __iomem *ch_cls_uart; /* Pointer to the "mapped" UART struct */
+
+ uchar ch_cached_lsr; /* Cached value of the LSR register */
+
+ uchar *ch_rqueue; /* Our read queue buffer - malloc'ed */
+ ushort ch_r_head; /* Head location of the read queue */
+ ushort ch_r_tail; /* Tail location of the read queue */
+
+ uchar *ch_equeue; /* Our error queue buffer - malloc'ed */
+ ushort ch_e_head; /* Head location of the error queue */
+ ushort ch_e_tail; /* Tail location of the error queue */
+
+ uchar *ch_wqueue; /* Our write queue buffer - malloc'ed */
+ ushort ch_w_head; /* Head location of the write queue */
+ ushort ch_w_tail; /* Tail location of the write queue */
+
+ ulong ch_rxcount; /* total of data received so far */
+ ulong ch_txcount; /* total of data transmitted so far */
+
+ uchar ch_r_tlevel; /* Receive Trigger level */
+ uchar ch_t_tlevel; /* Transmit Trigger level */
+
+ uchar ch_r_watermark; /* Receive Watermark */
+
+ ulong ch_stop_sending_break; /* Time we should STOP sending a break */
+
+ uint ch_stops_sent; /* How many times I have sent a stop character
+ * to try to stop the other guy sending.
+ */
+ ulong ch_err_parity; /* Count of parity errors on channel */
+ ulong ch_err_frame; /* Count of framing errors on channel */
+ ulong ch_err_break; /* Count of breaks on channel */
+ ulong ch_err_overrun; /* Count of overruns on channel */
+
+ ulong ch_xon_sends; /* Count of xons transmitted */
+ ulong ch_xoff_sends; /* Count of xoffs transmitted */
+
+ ulong ch_intr_modem; /* Count of interrupts */
+ ulong ch_intr_tx; /* Count of interrupts */
+ ulong ch_intr_rx; /* Count of interrupts */
+
+
+ /* /proc/<board>/<channel> entries */
+ struct proc_dir_entry *proc_entry_pointer;
+ struct dgnc_proc_entry *dgnc_channel_table;
+
+ uint ch_sniff_in;
+ uint ch_sniff_out;
+ char *ch_sniff_buf; /* Sniff buffer for proc */
+ ulong ch_sniff_flags; /* Channel flags */
+ wait_queue_head_t ch_sniff_wait;
+};
+
+
+/*************************************************************************
+ *
+ * Prototypes for non-static functions used in more than one module
+ *
+ *************************************************************************/
+
+extern int dgnc_ms_sleep(ulong ms);
+extern char *dgnc_ioctl_name(int cmd);
+
+/*
+ * Our Global Variables.
+ */
+extern int dgnc_driver_state; /* The state of the driver */
+extern uint dgnc_Major; /* Our driver/mgmt major */
+extern int dgnc_debug; /* Debug variable */
+extern int dgnc_rawreadok; /* Set if user wants rawreads */
+extern int dgnc_poll_tick; /* Poll interval - 20 ms */
+extern int dgnc_trcbuf_size; /* Size of the ringbuffer */
+extern spinlock_t dgnc_global_lock; /* Driver global spinlock */
+extern uint dgnc_NumBoards; /* Total number of boards */
+extern struct board_t *dgnc_Board[MAXBOARDS]; /* Array of board structs */
+extern ulong dgnc_poll_counter; /* Times the poller has run */
+extern char *dgnc_state_text[]; /* Array of state text */
+extern char *dgnc_driver_state_text[];/* Array of driver state text */
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_kcompat.h b/drivers/staging/dgnc/dgnc_kcompat.h
new file mode 100644
index 00000000000..00f589a13ab
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_kcompat.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2004 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *************************************************************************
+ *
+ * This file is intended to contain all the kernel "differences" between the
+ * various kernels that we support.
+ *
+ *************************************************************************/
+
+#ifndef __DGNC_KCOMPAT_H
+#define __DGNC_KCOMPAT_H
+
+#include <linux/version.h>
+
+# ifndef KERNEL_VERSION
+# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+# endif
+
+
+#if !defined(TTY_FLIPBUF_SIZE)
+# define TTY_FLIPBUF_SIZE 512
+#endif
+
+
+/* Sparse stuff */
+# ifndef __user
+# define __user
+# define __kernel
+# define __safe
+# define __force
+# define __chk_user_ptr(x) (void)0
+# endif
+
+
+# define PARM_STR(VAR, INIT, PERM, DESC) \
+ static char *VAR = INIT; \
+ char *dgnc_##VAR; \
+ module_param(VAR, charp, PERM); \
+ MODULE_PARM_DESC(VAR, DESC);
+
+# define PARM_INT(VAR, INIT, PERM, DESC) \
+ static int VAR = INIT; \
+ int dgnc_##VAR; \
+ module_param(VAR, int, PERM); \
+ MODULE_PARM_DESC(VAR, DESC);
+
+# define PARM_ULONG(VAR, INIT, PERM, DESC) \
+ static ulong VAR = INIT; \
+ ulong dgnc_##VAR; \
+ module_param(VAR, long, PERM); \
+ MODULE_PARM_DESC(VAR, DESC);
+
+
+
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+
+
+
+/* NOTHING YET */
+
+
+
+# else
+
+
+
+# error "this driver does not support anything below the 2.6.27 kernel series."
+
+
+
+# endif
+
+#endif /* ! __DGNC_KCOMPAT_H */
diff --git a/drivers/staging/dgnc/dgnc_mgmt.c b/drivers/staging/dgnc/dgnc_mgmt.c
new file mode 100644
index 00000000000..c4629d7c80b
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_mgmt.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ */
+
+/************************************************************************
+ *
+ * This file implements the mgmt functionality for the
+ * Neo and ClassicBoard based product lines.
+ *
+ ************************************************************************
+ */
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/sched.h> /* For jiffies, task states */
+#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
+#include <linux/serial_reg.h>
+#include <linux/termios.h>
+#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */
+
+#include "dgnc_driver.h"
+#include "dgnc_pci.h"
+#include "dgnc_kcompat.h" /* Kernel 2.4/2.6 compat includes */
+#include "dgnc_mgmt.h"
+#include "dpacompat.h"
+
+
+/* Our "in use" variables, to enforce 1 open only */
+static int dgnc_mgmt_in_use[MAXMGMTDEVICES];
+
+
+/*
+ * dgnc_mgmt_open()
+ *
+ * Open the mgmt/downld/dpa device
+ */
+int dgnc_mgmt_open(struct inode *inode, struct file *file)
+{
+ unsigned long lock_flags;
+ unsigned int minor = iminor(inode);
+
+ DPR_MGMT(("dgnc_mgmt_open start.\n"));
+
+ DGNC_LOCK(dgnc_global_lock, lock_flags);
+
+ /* mgmt device */
+ if (minor < MAXMGMTDEVICES) {
+ /* Only allow 1 open at a time on mgmt device */
+ if (dgnc_mgmt_in_use[minor]) {
+ DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+ return (-EBUSY);
+ }
+ dgnc_mgmt_in_use[minor]++;
+ }
+ else {
+ DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+ return (-ENXIO);
+ }
+
+ DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+
+ DPR_MGMT(("dgnc_mgmt_open finish.\n"));
+
+ return 0;
+}
+
+
+/*
+ * dgnc_mgmt_close()
+ *
+ * Open the mgmt/dpa device
+ */
+int dgnc_mgmt_close(struct inode *inode, struct file *file)
+{
+ unsigned long lock_flags;
+ unsigned int minor = iminor(inode);
+
+ DPR_MGMT(("dgnc_mgmt_close start.\n"));
+
+ DGNC_LOCK(dgnc_global_lock, lock_flags);
+
+ /* mgmt device */
+ if (minor < MAXMGMTDEVICES) {
+ if (dgnc_mgmt_in_use[minor]) {
+ dgnc_mgmt_in_use[minor] = 0;
+ }
+ }
+ DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+
+ DPR_MGMT(("dgnc_mgmt_close finish.\n"));
+
+ return 0;
+}
+
+
+/*
+ * dgnc_mgmt_ioctl()
+ *
+ * ioctl the mgmt/dpa device
+ */
+
+long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ unsigned long lock_flags;
+ void __user *uarg = (void __user *) arg;
+
+ DPR_MGMT(("dgnc_mgmt_ioctl start.\n"));
+
+ switch (cmd) {
+
+ case DIGI_GETDD:
+ {
+ /*
+ * This returns the total number of boards
+ * in the system, as well as driver version
+ * and has space for a reserved entry
+ */
+ struct digi_dinfo ddi;
+
+ DGNC_LOCK(dgnc_global_lock, lock_flags);
+
+ ddi.dinfo_nboards = dgnc_NumBoards;
+ sprintf(ddi.dinfo_version, "%s", DG_PART);
+
+ DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+
+ DPR_MGMT(("DIGI_GETDD returning numboards: %d version: %s\n",
+ ddi.dinfo_nboards, ddi.dinfo_version));
+
+ if (copy_to_user(uarg, &ddi, sizeof (ddi)))
+ return(-EFAULT);
+
+ break;
+ }
+
+ case DIGI_GETBD:
+ {
+ int brd;
+
+ struct digi_info di;
+
+ if (copy_from_user(&brd, uarg, sizeof(int))) {
+ return(-EFAULT);
+ }
+
+ DPR_MGMT(("DIGI_GETBD asking about board: %d\n", brd));
+
+ if ((brd < 0) || (brd > dgnc_NumBoards) || (dgnc_NumBoards == 0))
+ return (-ENODEV);
+
+ memset(&di, 0, sizeof(di));
+
+ di.info_bdnum = brd;
+
+ DGNC_LOCK(dgnc_Board[brd]->bd_lock, lock_flags);
+
+ di.info_bdtype = dgnc_Board[brd]->dpatype;
+ di.info_bdstate = dgnc_Board[brd]->dpastatus;
+ di.info_ioport = 0;
+ di.info_physaddr = (ulong) dgnc_Board[brd]->membase;
+ di.info_physsize = (ulong) dgnc_Board[brd]->membase - dgnc_Board[brd]->membase_end;
+ if (dgnc_Board[brd]->state != BOARD_FAILED)
+ di.info_nports = dgnc_Board[brd]->nasync;
+ else
+ di.info_nports = 0;
+
+ DGNC_UNLOCK(dgnc_Board[brd]->bd_lock, lock_flags);
+
+ DPR_MGMT(("DIGI_GETBD returning type: %x state: %x ports: %x size: %x\n",
+ di.info_bdtype, di.info_bdstate, di.info_nports, di.info_physsize));
+
+ if (copy_to_user(uarg, &di, sizeof (di)))
+ return (-EFAULT);
+
+ break;
+ }
+
+ case DIGI_GET_NI_INFO:
+ {
+ struct channel_t *ch;
+ struct ni_info ni;
+ uchar mstat = 0;
+ uint board = 0;
+ uint channel = 0;
+
+ if (copy_from_user(&ni, uarg, sizeof(struct ni_info))) {
+ return(-EFAULT);
+ }
+
+ DPR_MGMT(("DIGI_GETBD asking about board: %d channel: %d\n",
+ ni.board, ni.channel));
+
+ board = ni.board;
+ channel = ni.channel;
+
+ /* Verify boundaries on board */
+ if ((board < 0) || (board > dgnc_NumBoards) || (dgnc_NumBoards == 0))
+ return (-ENODEV);
+
+ /* Verify boundaries on channel */
+ if ((channel < 0) || (channel > dgnc_Board[board]->nasync))
+ return (-ENODEV);
+
+ ch = dgnc_Board[board]->channels[channel];
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (-ENODEV);
+
+ memset(&ni, 0, sizeof(ni));
+ ni.board = board;
+ ni.channel = channel;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ mstat = (ch->ch_mostat | ch->ch_mistat);
+
+ if (mstat & UART_MCR_DTR) {
+ ni.mstat |= TIOCM_DTR;
+ ni.dtr = TIOCM_DTR;
+ }
+ if (mstat & UART_MCR_RTS) {
+ ni.mstat |= TIOCM_RTS;
+ ni.rts = TIOCM_RTS;
+ }
+ if (mstat & UART_MSR_CTS) {
+ ni.mstat |= TIOCM_CTS;
+ ni.cts = TIOCM_CTS;
+ }
+ if (mstat & UART_MSR_RI) {
+ ni.mstat |= TIOCM_RI;
+ ni.ri = TIOCM_RI;
+ }
+ if (mstat & UART_MSR_DCD) {
+ ni.mstat |= TIOCM_CD;
+ ni.dcd = TIOCM_CD;
+ }
+ if (mstat & UART_MSR_DSR)
+ ni.mstat |= TIOCM_DSR;
+
+ ni.iflag = ch->ch_c_iflag;
+ ni.oflag = ch->ch_c_oflag;
+ ni.cflag = ch->ch_c_cflag;
+ ni.lflag = ch->ch_c_lflag;
+
+ if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS)
+ ni.hflow = 1;
+ else
+ ni.hflow = 0;
+
+ if ((ch->ch_flags & CH_STOPI) || (ch->ch_flags & CH_FORCED_STOPI))
+ ni.recv_stopped = 1;
+ else
+ ni.recv_stopped = 0;
+
+ if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_FORCED_STOP))
+ ni.xmit_stopped = 1;
+ else
+ ni.xmit_stopped = 0;
+
+ ni.curtx = ch->ch_txcount;
+ ni.currx = ch->ch_rxcount;
+
+ ni.baud = ch->ch_old_baud;
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ if (copy_to_user(uarg, &ni, sizeof(ni)))
+ return (-EFAULT);
+
+ break;
+ }
+
+
+ }
+
+ DPR_MGMT(("dgnc_mgmt_ioctl finish.\n"));
+
+ return 0;
+}
diff --git a/drivers/staging/dgnc/dgnc_mgmt.h b/drivers/staging/dgnc/dgnc_mgmt.h
new file mode 100644
index 00000000000..567f687b18d
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_mgmt.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGNC_MGMT_H
+#define __DGNC_MGMT_H
+
+#define MAXMGMTDEVICES 8
+
+int dgnc_mgmt_open(struct inode *inode, struct file *file);
+int dgnc_mgmt_close(struct inode *inode, struct file *file);
+long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#endif
+
diff --git a/drivers/staging/dgnc/dgnc_neo.c b/drivers/staging/dgnc/dgnc_neo.c
new file mode 100644
index 00000000000..8b9e09a83f7
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_neo.c
@@ -0,0 +1,1974 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h> /* For jiffies, task states */
+#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
+#include <linux/delay.h> /* For udelay */
+#include <asm/io.h> /* For read[bwl]/write[bwl] */
+#include <linux/serial.h> /* For struct async_serial */
+#include <linux/serial_reg.h> /* For the various UART offsets */
+
+#include "dgnc_driver.h" /* Driver main header file */
+#include "dgnc_neo.h" /* Our header file */
+#include "dgnc_tty.h"
+#include "dgnc_trace.h"
+
+static inline void neo_parse_lsr(struct board_t *brd, uint port);
+static inline void neo_parse_isr(struct board_t *brd, uint port);
+static void neo_copy_data_from_uart_to_queue(struct channel_t *ch);
+static inline void neo_clear_break(struct channel_t *ch, int force);
+static inline void neo_set_cts_flow_control(struct channel_t *ch);
+static inline void neo_set_rts_flow_control(struct channel_t *ch);
+static inline void neo_set_ixon_flow_control(struct channel_t *ch);
+static inline void neo_set_ixoff_flow_control(struct channel_t *ch);
+static inline void neo_set_no_output_flow_control(struct channel_t *ch);
+static inline void neo_set_no_input_flow_control(struct channel_t *ch);
+static inline void neo_set_new_start_stop_chars(struct channel_t *ch);
+static void neo_parse_modem(struct channel_t *ch, uchar signals);
+static void neo_tasklet(unsigned long data);
+static void neo_vpd(struct board_t *brd);
+static void neo_uart_init(struct channel_t *ch);
+static void neo_uart_off(struct channel_t *ch);
+static int neo_drain(struct tty_struct *tty, uint seconds);
+static void neo_param(struct tty_struct *tty);
+static void neo_assert_modem_signals(struct channel_t *ch);
+static void neo_flush_uart_write(struct channel_t *ch);
+static void neo_flush_uart_read(struct channel_t *ch);
+static void neo_disable_receiver(struct channel_t *ch);
+static void neo_enable_receiver(struct channel_t *ch);
+static void neo_send_break(struct channel_t *ch, int msecs);
+static void neo_send_start_character(struct channel_t *ch);
+static void neo_send_stop_character(struct channel_t *ch);
+static void neo_copy_data_from_queue_to_uart(struct channel_t *ch);
+static uint neo_get_uart_bytes_left(struct channel_t *ch);
+static void neo_send_immediate_char(struct channel_t *ch, unsigned char c);
+static irqreturn_t neo_intr(int irq, void *voidbrd);
+
+
+struct board_ops dgnc_neo_ops = {
+ .tasklet = neo_tasklet,
+ .intr = neo_intr,
+ .uart_init = neo_uart_init,
+ .uart_off = neo_uart_off,
+ .drain = neo_drain,
+ .param = neo_param,
+ .vpd = neo_vpd,
+ .assert_modem_signals = neo_assert_modem_signals,
+ .flush_uart_write = neo_flush_uart_write,
+ .flush_uart_read = neo_flush_uart_read,
+ .disable_receiver = neo_disable_receiver,
+ .enable_receiver = neo_enable_receiver,
+ .send_break = neo_send_break,
+ .send_start_character = neo_send_start_character,
+ .send_stop_character = neo_send_stop_character,
+ .copy_data_from_queue_to_uart = neo_copy_data_from_queue_to_uart,
+ .get_uart_bytes_left = neo_get_uart_bytes_left,
+ .send_immediate_char = neo_send_immediate_char
+};
+
+static uint dgnc_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+
+
+/*
+ * This function allows calls to ensure that all outstanding
+ * PCI writes have been completed, by doing a PCI read against
+ * a non-destructive, read-only location on the Neo card.
+ *
+ * In this case, we are reading the DVID (Read-only Device Identification)
+ * value of the Neo card.
+ */
+static inline void neo_pci_posting_flush(struct board_t *bd)
+{
+ readb(bd->re_map_membase + 0x8D);
+}
+
+static inline void neo_set_cts_flow_control(struct channel_t *ch)
+{
+ uchar ier = readb(&ch->ch_neo_uart->ier);
+ uchar efr = readb(&ch->ch_neo_uart->efr);
+
+
+ DPR_PARAM(("Setting CTSFLOW\n"));
+
+ /* Turn on auto CTS flow control */
+#if 1
+ ier |= (UART_17158_IER_CTSDSR);
+#else
+ ier &= ~(UART_17158_IER_CTSDSR);
+#endif
+
+ efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR);
+
+ /* Turn off auto Xon flow control */
+ efr &= ~(UART_17158_EFR_IXON);
+
+ /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+ writeb(0, &ch->ch_neo_uart->efr);
+
+ /* Turn on UART enhanced bits */
+ writeb(efr, &ch->ch_neo_uart->efr);
+
+ /* Turn on table D, with 8 char hi/low watermarks */
+ writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
+
+ /* Feed the UART our trigger levels */
+ writeb(8, &ch->ch_neo_uart->tfifo);
+ ch->ch_t_tlevel = 8;
+
+ writeb(ier, &ch->ch_neo_uart->ier);
+
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static inline void neo_set_rts_flow_control(struct channel_t *ch)
+{
+ uchar ier = readb(&ch->ch_neo_uart->ier);
+ uchar efr = readb(&ch->ch_neo_uart->efr);
+
+ DPR_PARAM(("Setting RTSFLOW\n"));
+
+ /* Turn on auto RTS flow control */
+#if 1
+ ier |= (UART_17158_IER_RTSDTR);
+#else
+ ier &= ~(UART_17158_IER_RTSDTR);
+#endif
+ efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR);
+
+ /* Turn off auto Xoff flow control */
+ ier &= ~(UART_17158_IER_XOFF);
+ efr &= ~(UART_17158_EFR_IXOFF);
+
+ /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+ writeb(0, &ch->ch_neo_uart->efr);
+
+ /* Turn on UART enhanced bits */
+ writeb(efr, &ch->ch_neo_uart->efr);
+
+ writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
+ ch->ch_r_watermark = 4;
+
+ writeb(32, &ch->ch_neo_uart->rfifo);
+ ch->ch_r_tlevel = 32;
+
+ writeb(ier, &ch->ch_neo_uart->ier);
+
+ /*
+ * From the Neo UART spec sheet:
+ * The auto RTS/DTR function must be started by asserting
+ * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after
+ * it is enabled.
+ */
+ ch->ch_mostat |= (UART_MCR_RTS);
+
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static inline void neo_set_ixon_flow_control(struct channel_t *ch)
+{
+ uchar ier = readb(&ch->ch_neo_uart->ier);
+ uchar efr = readb(&ch->ch_neo_uart->efr);
+
+ DPR_PARAM(("Setting IXON FLOW\n"));
+
+ /* Turn off auto CTS flow control */
+ ier &= ~(UART_17158_IER_CTSDSR);
+ efr &= ~(UART_17158_EFR_CTSDSR);
+
+ /* Turn on auto Xon flow control */
+ efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON);
+
+ /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+ writeb(0, &ch->ch_neo_uart->efr);
+
+ /* Turn on UART enhanced bits */
+ writeb(efr, &ch->ch_neo_uart->efr);
+
+ writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+ ch->ch_r_watermark = 4;
+
+ writeb(32, &ch->ch_neo_uart->rfifo);
+ ch->ch_r_tlevel = 32;
+
+ /* Tell UART what start/stop chars it should be looking for */
+ writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+ writeb(0, &ch->ch_neo_uart->xonchar2);
+
+ writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+ writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+ writeb(ier, &ch->ch_neo_uart->ier);
+
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static inline void neo_set_ixoff_flow_control(struct channel_t *ch)
+{
+ uchar ier = readb(&ch->ch_neo_uart->ier);
+ uchar efr = readb(&ch->ch_neo_uart->efr);
+
+ DPR_PARAM(("Setting IXOFF FLOW\n"));
+
+ /* Turn off auto RTS flow control */
+ ier &= ~(UART_17158_IER_RTSDTR);
+ efr &= ~(UART_17158_EFR_RTSDTR);
+
+ /* Turn on auto Xoff flow control */
+ ier |= (UART_17158_IER_XOFF);
+ efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
+
+ /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+ writeb(0, &ch->ch_neo_uart->efr);
+
+ /* Turn on UART enhanced bits */
+ writeb(efr, &ch->ch_neo_uart->efr);
+
+ /* Turn on table D, with 8 char hi/low watermarks */
+ writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+ writeb(8, &ch->ch_neo_uart->tfifo);
+ ch->ch_t_tlevel = 8;
+
+ /* Tell UART what start/stop chars it should be looking for */
+ writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+ writeb(0, &ch->ch_neo_uart->xonchar2);
+
+ writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+ writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+ writeb(ier, &ch->ch_neo_uart->ier);
+
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static inline void neo_set_no_input_flow_control(struct channel_t *ch)
+{
+ uchar ier = readb(&ch->ch_neo_uart->ier);
+ uchar efr = readb(&ch->ch_neo_uart->efr);
+
+ DPR_PARAM(("Unsetting Input FLOW\n"));
+
+ /* Turn off auto RTS flow control */
+ ier &= ~(UART_17158_IER_RTSDTR);
+ efr &= ~(UART_17158_EFR_RTSDTR);
+
+ /* Turn off auto Xoff flow control */
+ ier &= ~(UART_17158_IER_XOFF);
+ if (ch->ch_c_iflag & IXON)
+ efr &= ~(UART_17158_EFR_IXOFF);
+ else
+ efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
+
+
+ /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+ writeb(0, &ch->ch_neo_uart->efr);
+
+ /* Turn on UART enhanced bits */
+ writeb(efr, &ch->ch_neo_uart->efr);
+
+ /* Turn on table D, with 8 char hi/low watermarks */
+ writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+ ch->ch_r_watermark = 0;
+
+ writeb(16, &ch->ch_neo_uart->tfifo);
+ ch->ch_t_tlevel = 16;
+
+ writeb(16, &ch->ch_neo_uart->rfifo);
+ ch->ch_r_tlevel = 16;
+
+ writeb(ier, &ch->ch_neo_uart->ier);
+
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static inline void neo_set_no_output_flow_control(struct channel_t *ch)
+{
+ uchar ier = readb(&ch->ch_neo_uart->ier);
+ uchar efr = readb(&ch->ch_neo_uart->efr);
+
+ DPR_PARAM(("Unsetting Output FLOW\n"));
+
+ /* Turn off auto CTS flow control */
+ ier &= ~(UART_17158_IER_CTSDSR);
+ efr &= ~(UART_17158_EFR_CTSDSR);
+
+ /* Turn off auto Xon flow control */
+ if (ch->ch_c_iflag & IXOFF)
+ efr &= ~(UART_17158_EFR_IXON);
+ else
+ efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON);
+
+ /* Why? Becuz Exar's spec says we have to zero it out before setting it */
+ writeb(0, &ch->ch_neo_uart->efr);
+
+ /* Turn on UART enhanced bits */
+ writeb(efr, &ch->ch_neo_uart->efr);
+
+ /* Turn on table D, with 8 char hi/low watermarks */
+ writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+ ch->ch_r_watermark = 0;
+
+ writeb(16, &ch->ch_neo_uart->tfifo);
+ ch->ch_t_tlevel = 16;
+
+ writeb(16, &ch->ch_neo_uart->rfifo);
+ ch->ch_r_tlevel = 16;
+
+ writeb(ier, &ch->ch_neo_uart->ier);
+
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/* change UARTs start/stop chars */
+static inline void neo_set_new_start_stop_chars(struct channel_t *ch)
+{
+
+ /* if hardware flow control is set, then skip this whole thing */
+ if (ch->ch_digi.digi_flags & (CTSPACE | RTSPACE) || ch->ch_c_cflag & CRTSCTS)
+ return;
+
+ DPR_PARAM(("In new start stop chars\n"));
+
+ /* Tell UART what start/stop chars it should be looking for */
+ writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+ writeb(0, &ch->ch_neo_uart->xonchar2);
+
+ writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+ writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/*
+ * No locks are assumed to be held when calling this function.
+ */
+static inline void neo_clear_break(struct channel_t *ch, int force)
+{
+ ulong lock_flags;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /* Bail if we aren't currently sending a break. */
+ if (!ch->ch_stop_sending_break) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ /* Turn break off, and unset some variables */
+ if (ch->ch_flags & CH_BREAK_SENDING) {
+ if ((jiffies >= ch->ch_stop_sending_break) || force) {
+ uchar temp = readb(&ch->ch_neo_uart->lcr);
+ writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+ neo_pci_posting_flush(ch->ch_bd);
+ ch->ch_flags &= ~(CH_BREAK_SENDING);
+ ch->ch_stop_sending_break = 0;
+ DPR_IOCTL(("Finishing UART_LCR_SBC! finished: %lx\n", jiffies));
+ }
+ }
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+/*
+ * Parse the ISR register.
+ */
+static inline void neo_parse_isr(struct board_t *brd, uint port)
+{
+ struct channel_t *ch;
+ uchar isr;
+ uchar cause;
+ ulong lock_flags;
+
+ if (!brd || brd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ if (port > brd->maxports)
+ return;
+
+ ch = brd->channels[port];
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ /* Here we try to figure out what caused the interrupt to happen */
+ while (1) {
+
+ isr = readb(&ch->ch_neo_uart->isr_fcr);
+
+ /* Bail if no pending interrupt */
+ if (isr & UART_IIR_NO_INT) {
+ break;
+ }
+
+ /*
+ * Yank off the upper 2 bits, which just show that the FIFO's are enabled.
+ */
+ isr &= ~(UART_17158_IIR_FIFO_ENABLED);
+
+ DPR_INTR(("%s:%d isr: %x\n", __FILE__, __LINE__, isr));
+
+ if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) {
+ /* Read data from uart -> queue */
+ brd->intr_rx++;
+ ch->ch_intr_rx++;
+ neo_copy_data_from_uart_to_queue(ch);
+
+ /* Call our tty layer to enforce queue flow control if needed. */
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ dgnc_check_queue_flow_control(ch);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ }
+
+ if (isr & UART_IIR_THRI) {
+ brd->intr_tx++;
+ ch->ch_intr_tx++;
+ /* Transfer data (if any) from Write Queue -> UART. */
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ neo_copy_data_from_queue_to_uart(ch);
+ }
+
+ if (isr & UART_17158_IIR_XONXOFF) {
+ cause = readb(&ch->ch_neo_uart->xoffchar1);
+
+ DPR_INTR(("Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause));
+
+ /*
+ * Since the UART detected either an XON or
+ * XOFF match, we need to figure out which
+ * one it was, so we can suspend or resume data flow.
+ */
+ if (cause == UART_17158_XON_DETECT) {
+ /* Is output stopped right now, if so, resume it */
+ if (brd->channels[port]->ch_flags & CH_STOP) {
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_flags &= ~(CH_STOP);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ }
+ DPR_INTR(("Port %d. XON detected in incoming data\n", port));
+ }
+ else if (cause == UART_17158_XOFF_DETECT) {
+ if (!(brd->channels[port]->ch_flags & CH_STOP)) {
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_flags |= CH_STOP;
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ DPR_INTR(("Setting CH_STOP\n"));
+ }
+ DPR_INTR(("Port: %d. XOFF detected in incoming data\n", port));
+ }
+ }
+
+ if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) {
+ /*
+ * If we get here, this means the hardware is doing auto flow control.
+ * Check to see whether RTS/DTR or CTS/DSR caused this interrupt.
+ */
+ brd->intr_modem++;
+ ch->ch_intr_modem++;
+ cause = readb(&ch->ch_neo_uart->mcr);
+ /* Which pin is doing auto flow? RTS or DTR? */
+ if ((cause & 0x4) == 0) {
+ if (cause & UART_MCR_RTS) {
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_mostat |= UART_MCR_RTS;
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ }
+ else {
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_mostat &= ~(UART_MCR_RTS);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ }
+ } else {
+ if (cause & UART_MCR_DTR) {
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_mostat |= UART_MCR_DTR;
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ }
+ else {
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_mostat &= ~(UART_MCR_DTR);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ }
+ }
+ }
+
+ /* Parse any modem signal changes */
+ DPR_INTR(("MOD_STAT: sending to parse_modem_sigs\n"));
+ neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+ }
+}
+
+
+static inline void neo_parse_lsr(struct board_t *brd, uint port)
+{
+ struct channel_t *ch;
+ int linestatus;
+ ulong lock_flags;
+
+ if (!brd)
+ return;
+
+ if (brd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ if (port > brd->maxports)
+ return;
+
+ ch = brd->channels[port];
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ linestatus = readb(&ch->ch_neo_uart->lsr);
+
+ DPR_INTR(("%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus));
+
+ ch->ch_cached_lsr |= linestatus;
+
+ if (ch->ch_cached_lsr & UART_LSR_DR) {
+ brd->intr_rx++;
+ ch->ch_intr_rx++;
+ /* Read data from uart -> queue */
+ neo_copy_data_from_uart_to_queue(ch);
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ dgnc_check_queue_flow_control(ch);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ }
+
+ /*
+ * This is a special flag. It indicates that at least 1
+ * RX error (parity, framing, or break) has happened.
+ * Mark this in our struct, which will tell me that I have
+ *to do the special RX+LSR read for this FIFO load.
+ */
+ if (linestatus & UART_17158_RX_FIFO_DATA_ERROR) {
+ DPR_INTR(("%s:%d Port: %d Got an RX error, need to parse LSR\n",
+ __FILE__, __LINE__, port));
+ }
+
+ /*
+ * The next 3 tests should *NOT* happen, as the above test
+ * should encapsulate all 3... At least, thats what Exar says.
+ */
+
+ if (linestatus & UART_LSR_PE) {
+ ch->ch_err_parity++;
+ DPR_INTR(("%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port));
+ }
+
+ if (linestatus & UART_LSR_FE) {
+ ch->ch_err_frame++;
+ DPR_INTR(("%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port));
+ }
+
+ if (linestatus & UART_LSR_BI) {
+ ch->ch_err_break++;
+ DPR_INTR(("%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port));
+ }
+
+ if (linestatus & UART_LSR_OE) {
+ /*
+ * Rx Oruns. Exar says that an orun will NOT corrupt
+ * the FIFO. It will just replace the holding register
+ * with this new data byte. So basically just ignore this.
+ * Probably we should eventually have an orun stat in our driver...
+ */
+ ch->ch_err_overrun++;
+ DPR_INTR(("%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port));
+ }
+
+ if (linestatus & UART_LSR_THRE) {
+ brd->intr_tx++;
+ ch->ch_intr_tx++;
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ /* Transfer data (if any) from Write Queue -> UART. */
+ neo_copy_data_from_queue_to_uart(ch);
+ }
+ else if (linestatus & UART_17158_TX_AND_FIFO_CLR) {
+ brd->intr_tx++;
+ ch->ch_intr_tx++;
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ /* Transfer data (if any) from Write Queue -> UART. */
+ neo_copy_data_from_queue_to_uart(ch);
+ }
+}
+
+
+/*
+ * neo_param()
+ * Send any/all changes to the line to the UART.
+ */
+static void neo_param(struct tty_struct *tty)
+{
+ uchar lcr = 0;
+ uchar uart_lcr = 0;
+ uchar ier = 0;
+ uchar uart_ier = 0;
+ uint baud = 9600;
+ int quot = 0;
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!tty || tty->magic != TTY_MAGIC) {
+ return;
+ }
+
+ un = (struct un_t *) tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC) {
+ return;
+ }
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+ return;
+ }
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC) {
+ return;
+ }
+
+ DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n",
+ ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag));
+
+ /*
+ * If baud rate is zero, flush queues, and set mval to drop DTR.
+ */
+ if ((ch->ch_c_cflag & (CBAUD)) == 0) {
+ ch->ch_r_head = ch->ch_r_tail = 0;
+ ch->ch_e_head = ch->ch_e_tail = 0;
+ ch->ch_w_head = ch->ch_w_tail = 0;
+
+ neo_flush_uart_write(ch);
+ neo_flush_uart_read(ch);
+
+ /* The baudrate is B0 so all modem lines are to be dropped. */
+ ch->ch_flags |= (CH_BAUD0);
+ ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
+ neo_assert_modem_signals(ch);
+ ch->ch_old_baud = 0;
+ return;
+
+ } else if (ch->ch_custom_speed) {
+
+ baud = ch->ch_custom_speed;
+ /* Handle transition from B0 */
+ if (ch->ch_flags & CH_BAUD0) {
+ ch->ch_flags &= ~(CH_BAUD0);
+
+ /*
+ * Bring back up RTS and DTR...
+ * Also handle RTS or DTR toggle if set.
+ */
+ if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_RTS);
+ if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_DTR);
+ }
+ } else {
+ int iindex = 0;
+ int jindex = 0;
+
+ ulong bauds[4][16] = {
+ { /* slowbaud */
+ 0, 50, 75, 110,
+ 134, 150, 200, 300,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* slowbaud & CBAUDEX */
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* fastbaud */
+ 0, 57600, 76800, 115200,
+ 131657, 153600, 230400, 460800,
+ 921600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 },
+ { /* fastbaud & CBAUDEX */
+ 0, 57600, 115200, 230400,
+ 460800, 150, 200, 921600,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 }
+ };
+
+ /* Only use the TXPrint baud rate if the terminal unit is NOT open */
+ if (!(ch->ch_tun.un_flags & UN_ISOPEN) && (un->un_type == DGNC_PRINT))
+ baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
+ else
+ baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
+
+ if (ch->ch_c_cflag & CBAUDEX)
+ iindex = 1;
+
+ if (ch->ch_digi.digi_flags & DIGI_FAST)
+ iindex += 2;
+
+ jindex = baud;
+
+ if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16)) {
+ baud = bauds[iindex][jindex];
+ } else {
+ DPR_IOCTL(("baud indices were out of range (%d)(%d)",
+ iindex, jindex));
+ baud = 0;
+ }
+
+ if (baud == 0)
+ baud = 9600;
+
+ /* Handle transition from B0 */
+ if (ch->ch_flags & CH_BAUD0) {
+ ch->ch_flags &= ~(CH_BAUD0);
+
+ /*
+ * Bring back up RTS and DTR...
+ * Also handle RTS or DTR toggle if set.
+ */
+ if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_RTS);
+ if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_DTR);
+ }
+ }
+
+ if (ch->ch_c_cflag & PARENB) {
+ lcr |= UART_LCR_PARITY;
+ }
+
+ if (!(ch->ch_c_cflag & PARODD)) {
+ lcr |= UART_LCR_EPAR;
+ }
+
+ /*
+ * Not all platforms support mark/space parity,
+ * so this will hide behind an ifdef.
+ */
+#ifdef CMSPAR
+ if (ch->ch_c_cflag & CMSPAR)
+ lcr |= UART_LCR_SPAR;
+#endif
+
+ if (ch->ch_c_cflag & CSTOPB)
+ lcr |= UART_LCR_STOP;
+
+ switch (ch->ch_c_cflag & CSIZE) {
+ case CS5:
+ lcr |= UART_LCR_WLEN5;
+ break;
+ case CS6:
+ lcr |= UART_LCR_WLEN6;
+ break;
+ case CS7:
+ lcr |= UART_LCR_WLEN7;
+ break;
+ case CS8:
+ default:
+ lcr |= UART_LCR_WLEN8;
+ break;
+ }
+
+ ier = uart_ier = readb(&ch->ch_neo_uart->ier);
+ uart_lcr = readb(&ch->ch_neo_uart->lcr);
+
+ if (baud == 0)
+ baud = 9600;
+
+ quot = ch->ch_bd->bd_dividend / baud;
+
+ if (quot != 0 && ch->ch_old_baud != baud) {
+ ch->ch_old_baud = baud;
+ writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
+ writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
+ writeb((quot >> 8), &ch->ch_neo_uart->ier);
+ writeb(lcr, &ch->ch_neo_uart->lcr);
+ }
+
+ if (uart_lcr != lcr)
+ writeb(lcr, &ch->ch_neo_uart->lcr);
+
+ if (ch->ch_c_cflag & CREAD) {
+ ier |= (UART_IER_RDI | UART_IER_RLSI);
+ }
+ else {
+ ier &= ~(UART_IER_RDI | UART_IER_RLSI);
+ }
+
+ /*
+ * Have the UART interrupt on modem signal changes ONLY when
+ * we are in hardware flow control mode, or CLOCAL/FORCEDCD is not set.
+ */
+ if ((ch->ch_digi.digi_flags & CTSPACE) || (ch->ch_digi.digi_flags & RTSPACE) ||
+ (ch->ch_c_cflag & CRTSCTS) || !(ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
+ !(ch->ch_c_cflag & CLOCAL))
+ {
+ ier |= UART_IER_MSI;
+ }
+ else {
+ ier &= ~UART_IER_MSI;
+ }
+
+ ier |= UART_IER_THRI;
+
+ if (ier != uart_ier)
+ writeb(ier, &ch->ch_neo_uart->ier);
+
+ /* Set new start/stop chars */
+ neo_set_new_start_stop_chars(ch);
+
+ if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
+ neo_set_cts_flow_control(ch);
+ }
+ else if (ch->ch_c_iflag & IXON) {
+ /* If start/stop is set to disable, then we should disable flow control */
+ if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE))
+ neo_set_no_output_flow_control(ch);
+ else
+ neo_set_ixon_flow_control(ch);
+ }
+ else {
+ neo_set_no_output_flow_control(ch);
+ }
+
+ if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
+ neo_set_rts_flow_control(ch);
+ }
+ else if (ch->ch_c_iflag & IXOFF) {
+ /* If start/stop is set to disable, then we should disable flow control */
+ if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE))
+ neo_set_no_input_flow_control(ch);
+ else
+ neo_set_ixoff_flow_control(ch);
+ }
+ else {
+ neo_set_no_input_flow_control(ch);
+ }
+
+ /*
+ * Adjust the RX FIFO Trigger level if baud is less than 9600.
+ * Not exactly elegant, but this is needed because of the Exar chip's
+ * delay on firing off the RX FIFO interrupt on slower baud rates.
+ */
+ if (baud < 9600) {
+ writeb(1, &ch->ch_neo_uart->rfifo);
+ ch->ch_r_tlevel = 1;
+ }
+
+ neo_assert_modem_signals(ch);
+
+ /* Get current status of the modem signals now */
+ neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+}
+
+
+/*
+ * Our board poller function.
+ */
+static void neo_tasklet(unsigned long data)
+{
+ struct board_t *bd = (struct board_t *) data;
+ struct channel_t *ch;
+ ulong lock_flags;
+ int i;
+ int state = 0;
+ int ports = 0;
+
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC) {
+ APR(("poll_tasklet() - NULL or bad bd.\n"));
+ return;
+ }
+
+ /* Cache a couple board values */
+ DGNC_LOCK(bd->bd_lock, lock_flags);
+ state = bd->state;
+ ports = bd->nasync;
+ DGNC_UNLOCK(bd->bd_lock, lock_flags);
+
+ /*
+ * Do NOT allow the interrupt routine to read the intr registers
+ * Until we release this lock.
+ */
+ DGNC_LOCK(bd->bd_intr_lock, lock_flags);
+
+ /*
+ * If board is ready, parse deeper to see if there is anything to do.
+ */
+ if ((state == BOARD_READY) && (ports > 0)) {
+ /* Loop on each port */
+ for (i = 0; i < ports; i++) {
+ ch = bd->channels[i];
+
+ /* Just being careful... */
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ continue;
+
+ /*
+ * NOTE: Remember you CANNOT hold any channel
+ * locks when calling the input routine.
+ *
+ * During input processing, its possible we
+ * will call the Linux ld, which might in turn,
+ * do a callback right back into us, resulting
+ * in us trying to grab the channel lock twice!
+ */
+ dgnc_input(ch);
+
+ /*
+ * Channel lock is grabbed and then released
+ * inside both of these routines, but neither
+ * call anything else that could call back into us.
+ */
+ neo_copy_data_from_queue_to_uart(ch);
+ dgnc_wakeup_writes(ch);
+
+ /*
+ * Call carrier carrier function, in case something
+ * has changed.
+ */
+ dgnc_carrier(ch);
+
+ /*
+ * Check to see if we need to turn off a sending break.
+ * The timing check is done inside clear_break()
+ */
+ if (ch->ch_stop_sending_break)
+ neo_clear_break(ch, 0);
+ }
+ }
+
+ /* Allow interrupt routine to access the interrupt register again */
+ DGNC_UNLOCK(bd->bd_intr_lock, lock_flags);
+
+}
+
+
+/*
+ * dgnc_neo_intr()
+ *
+ * Neo specific interrupt handler.
+ */
+static irqreturn_t neo_intr(int irq, void *voidbrd)
+{
+ struct board_t *brd = (struct board_t *) voidbrd;
+ struct channel_t *ch;
+ int port = 0;
+ int type = 0;
+ int current_port;
+ u32 tmp;
+ u32 uart_poll;
+ unsigned long lock_flags;
+ unsigned long lock_flags2;
+
+ if (!brd) {
+ APR(("Received interrupt (%d) with null board associated\n", irq));
+ return IRQ_NONE;
+ }
+
+ /*
+ * Check to make sure its for us.
+ */
+ if (brd->magic != DGNC_BOARD_MAGIC) {
+ APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n", irq));
+ return IRQ_NONE;
+ }
+
+ brd->intr_count++;
+
+ /* Lock out the slow poller from running on this board. */
+ DGNC_LOCK(brd->bd_intr_lock, lock_flags);
+
+ /*
+ * Read in "extended" IRQ information from the 32bit Neo register.
+ * Bits 0-7: What port triggered the interrupt.
+ * Bits 8-31: Each 3bits indicate what type of interrupt occurred.
+ */
+ uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET);
+
+ DPR_INTR(("%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll));
+
+ /*
+ * If 0, no interrupts pending.
+ * This can happen if the IRQ is shared among a couple Neo/Classic boards.
+ */
+ if (!uart_poll) {
+ DPR_INTR(("Kernel interrupted to me, but no pending interrupts...\n"));
+ DGNC_UNLOCK(brd->bd_intr_lock, lock_flags);
+ return IRQ_NONE;
+ }
+
+ /* At this point, we have at least SOMETHING to service, dig further... */
+
+ current_port = 0;
+
+ /* Loop on each port */
+ while ((uart_poll & 0xff) != 0) {
+
+ tmp = uart_poll;
+
+ /* Check current port to see if it has interrupt pending */
+ if ((tmp & dgnc_offset_table[current_port]) != 0) {
+ port = current_port;
+ type = tmp >> (8 + (port * 3));
+ type &= 0x7;
+ } else {
+ current_port++;
+ continue;
+ }
+
+ DPR_INTR(("%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type));
+
+ /* Remove this port + type from uart_poll */
+ uart_poll &= ~(dgnc_offset_table[port]);
+
+ if (!type) {
+ /* If no type, just ignore it, and move onto next port */
+ DPR_INTR(("Interrupt with no type! port: %d\n", port));
+ continue;
+ }
+
+ /* Switch on type of interrupt we have */
+ switch (type) {
+
+ case UART_17158_RXRDY_TIMEOUT:
+ /*
+ * RXRDY Time-out is cleared by reading data in the
+ * RX FIFO until it falls below the trigger level.
+ */
+
+ /* Verify the port is in range. */
+ if (port > brd->nasync)
+ continue;
+
+ ch = brd->channels[port];
+ neo_copy_data_from_uart_to_queue(ch);
+
+ /* Call our tty layer to enforce queue flow control if needed. */
+ DGNC_LOCK(ch->ch_lock, lock_flags2);
+ dgnc_check_queue_flow_control(ch);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags2);
+
+ continue;
+
+ case UART_17158_RX_LINE_STATUS:
+ /*
+ * RXRDY and RX LINE Status (logic OR of LSR[4:1])
+ */
+ neo_parse_lsr(brd, port);
+ continue;
+
+ case UART_17158_TXRDY:
+ /*
+ * TXRDY interrupt clears after reading ISR register for the UART channel.
+ */
+
+ /*
+ * Yes, this is odd...
+ * Why would I check EVERY possibility of type of
+ * interrupt, when we know its TXRDY???
+ * Becuz for some reason, even tho we got triggered for TXRDY,
+ * it seems to be occassionally wrong. Instead of TX, which
+ * it should be, I was getting things like RXDY too. Weird.
+ */
+ neo_parse_isr(brd, port);
+ continue;
+
+ case UART_17158_MSR:
+ /*
+ * MSR or flow control was seen.
+ */
+ neo_parse_isr(brd, port);
+ continue;
+
+ default:
+ /*
+ * The UART triggered us with a bogus interrupt type.
+ * It appears the Exar chip, when REALLY bogged down, will throw
+ * these once and awhile.
+ * Its harmless, just ignore it and move on.
+ */
+ DPR_INTR(("%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type));
+ continue;
+ }
+ }
+
+ /*
+ * Schedule tasklet to more in-depth servicing at a better time.
+ */
+ tasklet_schedule(&brd->helper_tasklet);
+
+ DGNC_UNLOCK(brd->bd_intr_lock, lock_flags);
+
+ DPR_INTR(("dgnc_intr finish.\n"));
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * Neo specific way of turning off the receiver.
+ * Used as a way to enforce queue flow control when in
+ * hardware flow control mode.
+ */
+static void neo_disable_receiver(struct channel_t *ch)
+{
+ uchar tmp = readb(&ch->ch_neo_uart->ier);
+ tmp &= ~(UART_IER_RDI);
+ writeb(tmp, &ch->ch_neo_uart->ier);
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/*
+ * Neo specific way of turning on the receiver.
+ * Used as a way to un-enforce queue flow control when in
+ * hardware flow control mode.
+ */
+static void neo_enable_receiver(struct channel_t *ch)
+{
+ uchar tmp = readb(&ch->ch_neo_uart->ier);
+ tmp |= (UART_IER_RDI);
+ writeb(tmp, &ch->ch_neo_uart->ier);
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
+{
+ int qleft = 0;
+ uchar linestatus = 0;
+ uchar error_mask = 0;
+ int n = 0;
+ int total = 0;
+ ushort head;
+ ushort tail;
+ ulong lock_flags;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /* cache head and tail of queue */
+ head = ch->ch_r_head & RQUEUEMASK;
+ tail = ch->ch_r_tail & RQUEUEMASK;
+
+ /* Get our cached LSR */
+ linestatus = ch->ch_cached_lsr;
+ ch->ch_cached_lsr = 0;
+
+ /* Store how much space we have left in the queue */
+ if ((qleft = tail - head - 1) < 0)
+ qleft += RQUEUEMASK + 1;
+
+ /*
+ * If the UART is not in FIFO mode, force the FIFO copy to
+ * NOT be run, by setting total to 0.
+ *
+ * On the other hand, if the UART IS in FIFO mode, then ask
+ * the UART to give us an approximation of data it has RX'ed.
+ */
+ if (!(ch->ch_flags & CH_FIFO_ENABLED))
+ total = 0;
+ else {
+ total = readb(&ch->ch_neo_uart->rfifo);
+
+ /*
+ * EXAR chip bug - RX FIFO COUNT - Fudge factor.
+ *
+ * This resolves a problem/bug with the Exar chip that sometimes
+ * returns a bogus value in the rfifo register.
+ * The count can be any where from 0-3 bytes "off".
+ * Bizarre, but true.
+ */
+ if ((ch->ch_bd->dvid & 0xf0) >= UART_XR17E158_DVID) {
+ total -= 1;
+ }
+ else {
+ total -= 3;
+ }
+ }
+
+
+ /*
+ * Finally, bound the copy to make sure we don't overflow
+ * our own queue...
+ * The byte by byte copy loop below this loop this will
+ * deal with the queue overflow possibility.
+ */
+ total = min(total, qleft);
+
+ while (total > 0) {
+
+ /*
+ * Grab the linestatus register, we need to check
+ * to see if there are any errors in the FIFO.
+ */
+ linestatus = readb(&ch->ch_neo_uart->lsr);
+
+ /*
+ * Break out if there is a FIFO error somewhere.
+ * This will allow us to go byte by byte down below,
+ * finding the exact location of the error.
+ */
+ if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
+ break;
+
+ /* Make sure we don't go over the end of our queue */
+ n = min(((uint) total), (RQUEUESIZE - (uint) head));
+
+ /*
+ * Cut down n even further if needed, this is to fix
+ * a problem with memcpy_fromio() with the Neo on the
+ * IBM pSeries platform.
+ * 15 bytes max appears to be the magic number.
+ */
+ n = min((uint) n, (uint) 12);
+
+ /*
+ * Since we are grabbing the linestatus register, which
+ * will reset some bits after our read, we need to ensure
+ * we don't miss our TX FIFO emptys.
+ */
+ if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) {
+ ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+ }
+
+ linestatus = 0;
+
+ /* Copy data from uart to the queue */
+ memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n);
+ dgnc_sniff_nowait_nolock(ch, "UART READ", ch->ch_rqueue + head, n);
+
+ /*
+ * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed
+ * that all the data currently in the FIFO is free of
+ * breaks and parity/frame/orun errors.
+ */
+ memset(ch->ch_equeue + head, 0, n);
+
+ /* Add to and flip head if needed */
+ head = (head + n) & RQUEUEMASK;
+ total -= n;
+ qleft -= n;
+ ch->ch_rxcount += n;
+ }
+
+ /*
+ * Create a mask to determine whether we should
+ * insert the character (if any) into our queue.
+ */
+ if (ch->ch_c_iflag & IGNBRK)
+ error_mask |= UART_LSR_BI;
+
+ /*
+ * Now cleanup any leftover bytes still in the UART.
+ * Also deal with any possible queue overflow here as well.
+ */
+ while (1) {
+
+ /*
+ * Its possible we have a linestatus from the loop above
+ * this, so we "OR" on any extra bits.
+ */
+ linestatus |= readb(&ch->ch_neo_uart->lsr);
+
+ /*
+ * If the chip tells us there is no more data pending to
+ * be read, we can then leave.
+ * But before we do, cache the linestatus, just in case.
+ */
+ if (!(linestatus & UART_LSR_DR)) {
+ ch->ch_cached_lsr = linestatus;
+ break;
+ }
+
+ /* No need to store this bit */
+ linestatus &= ~UART_LSR_DR;
+
+ /*
+ * Since we are grabbing the linestatus register, which
+ * will reset some bits after our read, we need to ensure
+ * we don't miss our TX FIFO emptys.
+ */
+ if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) {
+ linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR);
+ ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+ }
+
+ /*
+ * Discard character if we are ignoring the error mask.
+ */
+ if (linestatus & error_mask) {
+ uchar discard;
+ linestatus = 0;
+ memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1);
+ continue;
+ }
+
+ /*
+ * If our queue is full, we have no choice but to drop some data.
+ * The assumption is that HWFLOW or SWFLOW should have stopped
+ * things way way before we got to this point.
+ *
+ * I decided that I wanted to ditch the oldest data first,
+ * I hope thats okay with everyone? Yes? Good.
+ */
+ while (qleft < 1) {
+ DPR_READ(("Queue full, dropping DATA:%x LSR:%x\n",
+ ch->ch_rqueue[tail], ch->ch_equeue[tail]));
+
+ ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK;
+ ch->ch_err_overrun++;
+ qleft++;
+ }
+
+ memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1);
+ ch->ch_equeue[head] = (uchar) linestatus;
+ dgnc_sniff_nowait_nolock(ch, "UART READ", ch->ch_rqueue + head, 1);
+
+ DPR_READ(("DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]));
+
+ /* Ditch any remaining linestatus value. */
+ linestatus = 0;
+
+ /* Add to and flip head if needed */
+ head = (head + 1) & RQUEUEMASK;
+
+ qleft--;
+ ch->ch_rxcount++;
+ }
+
+ /*
+ * Write new final heads to channel structure.
+ */
+ ch->ch_r_head = head & RQUEUEMASK;
+ ch->ch_e_head = head & EQUEUEMASK;
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+/*
+ * This function basically goes to sleep for secs, or until
+ * it gets signalled that the port has fully drained.
+ */
+static int neo_drain(struct tty_struct *tty, uint seconds)
+{
+ ulong lock_flags;
+ struct channel_t *ch;
+ struct un_t *un;
+ int rc = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC) {
+ return (-ENXIO);
+ }
+
+ un = (struct un_t *) tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC) {
+ return (-ENXIO);
+ }
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+ return (-ENXIO);
+ }
+
+ DPR_IOCTL(("%d Drain wait started.\n", __LINE__));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ un->un_flags |= UN_EMPTY;
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * Go to sleep waiting for the tty layer to wake me back up when
+ * the empty flag goes away.
+ *
+ * NOTE: TODO: Do something with time passed in.
+ */
+ rc = wait_event_interruptible(un->un_flags_wait, ((un->un_flags & UN_EMPTY) == 0));
+
+ /* If ret is non-zero, user ctrl-c'ed us */
+ if (rc) {
+ DPR_IOCTL(("%d Drain - User ctrl c'ed\n", __LINE__));
+ }
+ else {
+ DPR_IOCTL(("%d Drain wait finished.\n", __LINE__));
+ }
+
+ return (rc);
+}
+
+
+/*
+ * Flush the WRITE FIFO on the Neo.
+ *
+ * NOTE: Channel lock MUST be held before calling this function!
+ */
+static void neo_flush_uart_write(struct channel_t *ch)
+{
+ uchar tmp = 0;
+ int i = 0;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+ return;
+ }
+
+ writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+ neo_pci_posting_flush(ch->ch_bd);
+
+ for (i = 0; i < 10; i++) {
+
+ /* Check to see if the UART feels it completely flushed the FIFO. */
+ tmp = readb(&ch->ch_neo_uart->isr_fcr);
+ if (tmp & 4) {
+ DPR_IOCTL(("Still flushing TX UART... i: %d\n", i));
+ udelay(10);
+ }
+ else
+ break;
+ }
+
+ ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+}
+
+
+/*
+ * Flush the READ FIFO on the Neo.
+ *
+ * NOTE: Channel lock MUST be held before calling this function!
+ */
+static void neo_flush_uart_read(struct channel_t *ch)
+{
+ uchar tmp = 0;
+ int i = 0;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+ return;
+ }
+
+ writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr);
+ neo_pci_posting_flush(ch->ch_bd);
+
+ for (i = 0; i < 10; i++) {
+
+ /* Check to see if the UART feels it completely flushed the FIFO. */
+ tmp = readb(&ch->ch_neo_uart->isr_fcr);
+ if (tmp & 2) {
+ DPR_IOCTL(("Still flushing RX UART... i: %d\n", i));
+ udelay(10);
+ }
+ else
+ break;
+ }
+}
+
+
+static void neo_copy_data_from_queue_to_uart(struct channel_t *ch)
+{
+ ushort head;
+ ushort tail;
+ int n;
+ int s;
+ int qlen;
+ uint len_written = 0;
+ ulong lock_flags;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /* No data to write to the UART */
+ if (ch->ch_w_tail == ch->ch_w_head) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ /* If port is "stopped", don't send any data to the UART */
+ if ((ch->ch_flags & CH_FORCED_STOP) || (ch->ch_flags & CH_BREAK_SENDING)) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ /*
+ * If FIFOs are disabled. Send data directly to txrx register
+ */
+ if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
+ uchar lsrbits = readb(&ch->ch_neo_uart->lsr);
+
+ /* Cache the LSR bits for later parsing */
+ ch->ch_cached_lsr |= lsrbits;
+ if (ch->ch_cached_lsr & UART_LSR_THRE) {
+ ch->ch_cached_lsr &= ~(UART_LSR_THRE);
+
+ /*
+ * If RTS Toggle mode is on, turn on RTS now if not already set,
+ * and make sure we get an event when the data transfer has completed.
+ */
+ if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
+ if (!(ch->ch_mostat & UART_MCR_RTS)) {
+ ch->ch_mostat |= (UART_MCR_RTS);
+ neo_assert_modem_signals(ch);
+ }
+ ch->ch_tun.un_flags |= (UN_EMPTY);
+ }
+ /*
+ * If DTR Toggle mode is on, turn on DTR now if not already set,
+ * and make sure we get an event when the data transfer has completed.
+ */
+ if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
+ if (!(ch->ch_mostat & UART_MCR_DTR)) {
+ ch->ch_mostat |= (UART_MCR_DTR);
+ neo_assert_modem_signals(ch);
+ }
+ ch->ch_tun.un_flags |= (UN_EMPTY);
+ }
+
+ writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx);
+ DPR_WRITE(("Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]));
+ ch->ch_w_tail++;
+ ch->ch_w_tail &= WQUEUEMASK;
+ ch->ch_txcount++;
+ }
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ /*
+ * We have to do it this way, because of the EXAR TXFIFO count bug.
+ */
+ if ((ch->ch_bd->dvid & 0xf0) < UART_XR17E158_DVID) {
+ if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM))) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ len_written = 0;
+
+ n = readb(&ch->ch_neo_uart->tfifo);
+
+ if ((unsigned int) n > ch->ch_t_tlevel) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
+ }
+ else {
+ n = UART_17158_TX_FIFOSIZE - readb(&ch->ch_neo_uart->tfifo);
+ }
+
+ /* cache head and tail of queue */
+ head = ch->ch_w_head & WQUEUEMASK;
+ tail = ch->ch_w_tail & WQUEUEMASK;
+ qlen = (head - tail) & WQUEUEMASK;
+
+ /* Find minimum of the FIFO space, versus queue length */
+ n = min(n, qlen);
+
+ while (n > 0) {
+
+ s = ((head >= tail) ? head : WQUEUESIZE) - tail;
+ s = min(s, n);
+
+ if (s <= 0)
+ break;
+
+ /*
+ * If RTS Toggle mode is on, turn on RTS now if not already set,
+ * and make sure we get an event when the data transfer has completed.
+ */
+ if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
+ if (!(ch->ch_mostat & UART_MCR_RTS)) {
+ ch->ch_mostat |= (UART_MCR_RTS);
+ neo_assert_modem_signals(ch);
+ }
+ ch->ch_tun.un_flags |= (UN_EMPTY);
+ }
+
+ /*
+ * If DTR Toggle mode is on, turn on DTR now if not already set,
+ * and make sure we get an event when the data transfer has completed.
+ */
+ if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
+ if (!(ch->ch_mostat & UART_MCR_DTR)) {
+ ch->ch_mostat |= (UART_MCR_DTR);
+ neo_assert_modem_signals(ch);
+ }
+ ch->ch_tun.un_flags |= (UN_EMPTY);
+ }
+
+ memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s);
+ dgnc_sniff_nowait_nolock(ch, "UART WRITE", ch->ch_wqueue + tail, s);
+
+ /* Add and flip queue if needed */
+ tail = (tail + s) & WQUEUEMASK;
+ n -= s;
+ ch->ch_txcount += s;
+ len_written += s;
+ }
+
+ /* Update the final tail */
+ ch->ch_w_tail = tail & WQUEUEMASK;
+
+ if (len_written > 0) {
+ neo_pci_posting_flush(ch->ch_bd);
+ ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+ }
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+static void neo_parse_modem(struct channel_t *ch, uchar signals)
+{
+ volatile uchar msignals = signals;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DPR_MSIGS(("neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals));
+
+ /*
+ * Do altpin switching. Altpin switches DCD and DSR.
+ * This prolly breaks DSRPACE, so we should be more clever here.
+ */
+ if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
+ uchar mswap = msignals;
+
+ if (mswap & UART_MSR_DDCD) {
+ msignals &= ~UART_MSR_DDCD;
+ msignals |= UART_MSR_DDSR;
+ }
+ if (mswap & UART_MSR_DDSR) {
+ msignals &= ~UART_MSR_DDSR;
+ msignals |= UART_MSR_DDCD;
+ }
+ if (mswap & UART_MSR_DCD) {
+ msignals &= ~UART_MSR_DCD;
+ msignals |= UART_MSR_DSR;
+ }
+ if (mswap & UART_MSR_DSR) {
+ msignals &= ~UART_MSR_DSR;
+ msignals |= UART_MSR_DCD;
+ }
+ }
+
+ /* Scrub off lower bits. They signify delta's, which I don't care about */
+ msignals &= 0xf0;
+
+ if (msignals & UART_MSR_DCD)
+ ch->ch_mistat |= UART_MSR_DCD;
+ else
+ ch->ch_mistat &= ~UART_MSR_DCD;
+
+ if (msignals & UART_MSR_DSR)
+ ch->ch_mistat |= UART_MSR_DSR;
+ else
+ ch->ch_mistat &= ~UART_MSR_DSR;
+
+ if (msignals & UART_MSR_RI)
+ ch->ch_mistat |= UART_MSR_RI;
+ else
+ ch->ch_mistat &= ~UART_MSR_RI;
+
+ if (msignals & UART_MSR_CTS)
+ ch->ch_mistat |= UART_MSR_CTS;
+ else
+ ch->ch_mistat &= ~UART_MSR_CTS;
+
+ DPR_MSIGS(("Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
+ ch->ch_portnum,
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
+ !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD)));
+}
+
+
+/* Make the UART raise any of the output signals we want up */
+static void neo_assert_modem_signals(struct channel_t *ch)
+{
+ uchar out;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ out = ch->ch_mostat;
+
+ if (ch->ch_flags & CH_LOOPBACK)
+ out |= UART_MCR_LOOP;
+
+ writeb(out, &ch->ch_neo_uart->mcr);
+ neo_pci_posting_flush(ch->ch_bd);
+
+ /* Give time for the UART to actually raise/drop the signals */
+ udelay(10);
+}
+
+
+static void neo_send_start_character(struct channel_t *ch)
+{
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ if (ch->ch_startc != _POSIX_VDISABLE) {
+ ch->ch_xon_sends++;
+ writeb(ch->ch_startc, &ch->ch_neo_uart->txrx);
+ neo_pci_posting_flush(ch->ch_bd);
+ udelay(10);
+ }
+}
+
+
+static void neo_send_stop_character(struct channel_t *ch)
+{
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ if (ch->ch_stopc != _POSIX_VDISABLE) {
+ ch->ch_xoff_sends++;
+ writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx);
+ neo_pci_posting_flush(ch->ch_bd);
+ udelay(10);
+ }
+}
+
+
+/*
+ * neo_uart_init
+ */
+static void neo_uart_init(struct channel_t *ch)
+{
+
+ writeb(0, &ch->ch_neo_uart->ier);
+ writeb(0, &ch->ch_neo_uart->efr);
+ writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr);
+
+
+ /* Clear out UART and FIFO */
+ readb(&ch->ch_neo_uart->txrx);
+ writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+ readb(&ch->ch_neo_uart->lsr);
+ readb(&ch->ch_neo_uart->msr);
+
+ ch->ch_flags |= CH_FIFO_ENABLED;
+
+ /* Assert any signals we want up */
+ writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/*
+ * Make the UART completely turn off.
+ */
+static void neo_uart_off(struct channel_t *ch)
+{
+ /* Turn off UART enhanced bits */
+ writeb(0, &ch->ch_neo_uart->efr);
+
+ /* Stop all interrupts from occurring. */
+ writeb(0, &ch->ch_neo_uart->ier);
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static uint neo_get_uart_bytes_left(struct channel_t *ch)
+{
+ uchar left = 0;
+ uchar lsr = readb(&ch->ch_neo_uart->lsr);
+
+ /* We must cache the LSR as some of the bits get reset once read... */
+ ch->ch_cached_lsr |= lsr;
+
+ /* Determine whether the Transmitter is empty or not */
+ if (!(lsr & UART_LSR_TEMT)) {
+ if (ch->ch_flags & CH_TX_FIFO_EMPTY) {
+ tasklet_schedule(&ch->ch_bd->helper_tasklet);
+ }
+ left = 1;
+ } else {
+ ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+ left = 0;
+ }
+
+ return left;
+}
+
+
+/* Channel lock MUST be held by the calling function! */
+static void neo_send_break(struct channel_t *ch, int msecs)
+{
+ /*
+ * If we receive a time of 0, this means turn off the break.
+ */
+ if (msecs == 0) {
+ if (ch->ch_flags & CH_BREAK_SENDING) {
+ uchar temp = readb(&ch->ch_neo_uart->lcr);
+ writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+ neo_pci_posting_flush(ch->ch_bd);
+ ch->ch_flags &= ~(CH_BREAK_SENDING);
+ ch->ch_stop_sending_break = 0;
+ DPR_IOCTL(("Finishing UART_LCR_SBC! finished: %lx\n", jiffies));
+ }
+ return;
+ }
+
+ /*
+ * Set the time we should stop sending the break.
+ * If we are already sending a break, toss away the existing
+ * time to stop, and use this new value instead.
+ */
+ ch->ch_stop_sending_break = jiffies + dgnc_jiffies_from_ms(msecs);
+
+ /* Tell the UART to start sending the break */
+ if (!(ch->ch_flags & CH_BREAK_SENDING)) {
+ uchar temp = readb(&ch->ch_neo_uart->lcr);
+ writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+ neo_pci_posting_flush(ch->ch_bd);
+ ch->ch_flags |= (CH_BREAK_SENDING);
+ DPR_IOCTL(("Port %d. Starting UART_LCR_SBC! start: %lx should end: %lx\n",
+ ch->ch_portnum, jiffies, ch->ch_stop_sending_break));
+ }
+}
+
+
+/*
+ * neo_send_immediate_char.
+ *
+ * Sends a specific character as soon as possible to the UART,
+ * jumping over any bytes that might be in the write queue.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static void neo_send_immediate_char(struct channel_t *ch, unsigned char c)
+{
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ writeb(c, &ch->ch_neo_uart->txrx);
+ neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static unsigned int neo_read_eeprom(unsigned char __iomem *base, unsigned int address)
+{
+ unsigned int enable;
+ unsigned int bits;
+ unsigned int databit;
+ unsigned int val;
+
+ /* enable chip select */
+ writeb(NEO_EECS, base + NEO_EEREG);
+ /* READ */
+ enable = (address | 0x180);
+
+ for (bits = 9; bits--; ) {
+ databit = (enable & (1 << bits)) ? NEO_EEDI : 0;
+ /* Set read address */
+ writeb(databit | NEO_EECS, base + NEO_EEREG);
+ writeb(databit | NEO_EECS | NEO_EECK, base + NEO_EEREG);
+ }
+
+ val = 0;
+
+ for (bits = 17; bits--; ) {
+ /* clock to EEPROM */
+ writeb(NEO_EECS, base + NEO_EEREG);
+ writeb(NEO_EECS | NEO_EECK, base + NEO_EEREG);
+ val <<= 1;
+ /* read EEPROM */
+ if (readb(base + NEO_EEREG) & NEO_EEDO)
+ val |= 1;
+ }
+
+ /* clock falling edge */
+ writeb(NEO_EECS, base + NEO_EEREG);
+
+ /* drop chip select */
+ writeb(0x00, base + NEO_EEREG);
+
+ return val;
+}
+
+
+static void neo_vpd(struct board_t *brd)
+{
+ unsigned int i = 0;
+ unsigned int a;
+
+ if (!brd || brd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ if (!brd->re_map_membase)
+ return;
+
+ /* Store the VPD into our buffer */
+ for (i = 0; i < NEO_VPD_IMAGESIZE; i++) {
+ a = neo_read_eeprom(brd->re_map_membase, i);
+ brd->vpd[i*2] = a & 0xff;
+ brd->vpd[(i*2)+1] = (a >> 8) & 0xff;
+ }
+
+ if (((brd->vpd[0x08] != 0x82) /* long resource name tag */
+ && (brd->vpd[0x10] != 0x82)) /* long resource name tag (PCI-66 files)*/
+ || (brd->vpd[0x7F] != 0x78)) /* small resource end tag */
+ {
+ memset(brd->vpd, '\0', NEO_VPD_IMAGESIZE);
+ }
+ else {
+ /* Search for the serial number */
+ for (i = 0; i < NEO_VPD_IMAGESIZE * 2; i++) {
+ if (brd->vpd[i] == 'S' && brd->vpd[i + 1] == 'N') {
+ strncpy(brd->serial_num, &(brd->vpd[i + 3]), 9);
+ }
+ }
+ }
+}
diff --git a/drivers/staging/dgnc/dgnc_neo.h b/drivers/staging/dgnc/dgnc_neo.h
new file mode 100644
index 00000000000..7ec5710a434
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_neo.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ */
+
+#ifndef __DGNC_NEO_H
+#define __DGNC_NEO_H
+
+#include "dgnc_types.h"
+#include "dgnc_driver.h"
+
+/************************************************************************
+ * Per channel/port NEO UART structure *
+ ************************************************************************
+ * Base Structure Entries Usage Meanings to Host *
+ * *
+ * W = read write R = read only *
+ * U = Unused. *
+ ************************************************************************/
+
+struct neo_uart_struct {
+ u8 txrx; /* WR RHR/THR - Holding Reg */
+ u8 ier; /* WR IER - Interrupt Enable Reg */
+ u8 isr_fcr; /* WR ISR/FCR - Interrupt Status Reg/Fifo Control Reg */
+ u8 lcr; /* WR LCR - Line Control Reg */
+ u8 mcr; /* WR MCR - Modem Control Reg */
+ u8 lsr; /* WR LSR - Line Status Reg */
+ u8 msr; /* WR MSR - Modem Status Reg */
+ u8 spr; /* WR SPR - Scratch Pad Reg */
+ u8 fctr; /* WR FCTR - Feature Control Reg */
+ u8 efr; /* WR EFR - Enhanced Function Reg */
+ u8 tfifo; /* WR TXCNT/TXTRG - Transmit FIFO Reg */
+ u8 rfifo; /* WR RXCNT/RXTRG - Recieve FIFO Reg */
+ u8 xoffchar1; /* WR XOFF 1 - XOff Character 1 Reg */
+ u8 xoffchar2; /* WR XOFF 2 - XOff Character 2 Reg */
+ u8 xonchar1; /* WR XON 1 - Xon Character 1 Reg */
+ u8 xonchar2; /* WR XON 2 - XOn Character 2 Reg */
+
+ u8 reserved1[0x2ff - 0x200]; /* U Reserved by Exar */
+ u8 txrxburst[64]; /* RW 64 bytes of RX/TX FIFO Data */
+ u8 reserved2[0x37f - 0x340]; /* U Reserved by Exar */
+ u8 rxburst_with_errors[64]; /* R 64 bytes of RX FIFO Data + LSR */
+};
+
+/* Where to read the extended interrupt register (32bits instead of 8bits) */
+#define UART_17158_POLL_ADDR_OFFSET 0x80
+
+/* These are the current dvid's of the Neo boards */
+#define UART_XR17C158_DVID 0x20
+#define UART_XR17D158_DVID 0x20
+#define UART_XR17E158_DVID 0x40
+
+#define NEO_EECK 0x10 /* Clock */
+#define NEO_EECS 0x20 /* Chip Select */
+#define NEO_EEDI 0x40 /* Data In is an Output Pin */
+#define NEO_EEDO 0x80 /* Data Out is an Input Pin */
+#define NEO_EEREG 0x8E /* offset to EEPROM control reg */
+
+
+#define NEO_VPD_IMAGESIZE 0x40 /* size of image to read from EEPROM in words */
+#define NEO_VPD_IMAGEBYTES (NEO_VPD_IMAGESIZE * 2)
+
+/*
+ * These are the redefinitions for the FCTR on the XR17C158, since
+ * Exar made them different than their earlier design. (XR16C854)
+ */
+
+/* These are only applicable when table D is selected */
+#define UART_17158_FCTR_RTS_NODELAY 0x00
+#define UART_17158_FCTR_RTS_4DELAY 0x01
+#define UART_17158_FCTR_RTS_6DELAY 0x02
+#define UART_17158_FCTR_RTS_8DELAY 0x03
+#define UART_17158_FCTR_RTS_12DELAY 0x12
+#define UART_17158_FCTR_RTS_16DELAY 0x05
+#define UART_17158_FCTR_RTS_20DELAY 0x13
+#define UART_17158_FCTR_RTS_24DELAY 0x06
+#define UART_17158_FCTR_RTS_28DELAY 0x14
+#define UART_17158_FCTR_RTS_32DELAY 0x07
+#define UART_17158_FCTR_RTS_36DELAY 0x16
+#define UART_17158_FCTR_RTS_40DELAY 0x08
+#define UART_17158_FCTR_RTS_44DELAY 0x09
+#define UART_17158_FCTR_RTS_48DELAY 0x10
+#define UART_17158_FCTR_RTS_52DELAY 0x11
+
+#define UART_17158_FCTR_RTS_IRDA 0x10
+#define UART_17158_FCTR_RS485 0x20
+#define UART_17158_FCTR_TRGA 0x00
+#define UART_17158_FCTR_TRGB 0x40
+#define UART_17158_FCTR_TRGC 0x80
+#define UART_17158_FCTR_TRGD 0xC0
+
+/* 17158 trigger table selects.. */
+#define UART_17158_FCTR_BIT6 0x40
+#define UART_17158_FCTR_BIT7 0x80
+
+/* 17158 TX/RX memmapped buffer offsets */
+#define UART_17158_RX_FIFOSIZE 64
+#define UART_17158_TX_FIFOSIZE 64
+
+/* 17158 Extended IIR's */
+#define UART_17158_IIR_RDI_TIMEOUT 0x0C /* Receiver data TIMEOUT */
+#define UART_17158_IIR_XONXOFF 0x10 /* Received an XON/XOFF char */
+#define UART_17158_IIR_HWFLOW_STATE_CHANGE 0x20 /* CTS/DSR or RTS/DTR state change */
+#define UART_17158_IIR_FIFO_ENABLED 0xC0 /* 16550 FIFOs are Enabled */
+
+/*
+ * These are the extended interrupts that get sent
+ * back to us from the UART's 32bit interrupt register
+ */
+#define UART_17158_RX_LINE_STATUS 0x1 /* RX Ready */
+#define UART_17158_RXRDY_TIMEOUT 0x2 /* RX Ready Timeout */
+#define UART_17158_TXRDY 0x3 /* TX Ready */
+#define UART_17158_MSR 0x4 /* Modem State Change */
+#define UART_17158_TX_AND_FIFO_CLR 0x40 /* Transmitter Holding Reg Empty */
+#define UART_17158_RX_FIFO_DATA_ERROR 0x80 /* UART detected an RX FIFO Data error */
+
+/*
+ * These are the EXTENDED definitions for the 17C158's Interrupt
+ * Enable Register.
+ */
+#define UART_17158_EFR_ECB 0x10 /* Enhanced control bit */
+#define UART_17158_EFR_IXON 0x2 /* Receiver compares Xon1/Xoff1 */
+#define UART_17158_EFR_IXOFF 0x8 /* Transmit Xon1/Xoff1 */
+#define UART_17158_EFR_RTSDTR 0x40 /* Auto RTS/DTR Flow Control Enable */
+#define UART_17158_EFR_CTSDSR 0x80 /* Auto CTS/DSR Flow COntrol Enable */
+
+#define UART_17158_XOFF_DETECT 0x1 /* Indicates whether chip saw an incoming XOFF char */
+#define UART_17158_XON_DETECT 0x2 /* Indicates whether chip saw an incoming XON char */
+
+#define UART_17158_IER_RSVD1 0x10 /* Reserved by Exar */
+#define UART_17158_IER_XOFF 0x20 /* Xoff Interrupt Enable */
+#define UART_17158_IER_RTSDTR 0x40 /* Output Interrupt Enable */
+#define UART_17158_IER_CTSDSR 0x80 /* Input Interrupt Enable */
+
+/*
+ * Our Global Variables
+ */
+extern struct board_ops dgnc_neo_ops;
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_pci.h b/drivers/staging/dgnc/dgnc_pci.h
new file mode 100644
index 00000000000..5b6f76d98aa
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_pci.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGNC_PCI_H
+#define __DGNC_PCI_H
+
+#define PCIMAX 32 /* maximum number of PCI boards */
+
+#define DIGI_VID 0x114F
+
+#define PCI_DEVICE_CLASSIC_4_DID 0x0028
+#define PCI_DEVICE_CLASSIC_8_DID 0x0029
+#define PCI_DEVICE_CLASSIC_4_422_DID 0x00D0
+#define PCI_DEVICE_CLASSIC_8_422_DID 0x00D1
+#define PCI_DEVICE_NEO_4_DID 0x00B0
+#define PCI_DEVICE_NEO_8_DID 0x00B1
+#define PCI_DEVICE_NEO_2DB9_DID 0x00C8
+#define PCI_DEVICE_NEO_2DB9PRI_DID 0x00C9
+#define PCI_DEVICE_NEO_2RJ45_DID 0x00CA
+#define PCI_DEVICE_NEO_2RJ45PRI_DID 0x00CB
+#define PCI_DEVICE_NEO_1_422_DID 0x00CC
+#define PCI_DEVICE_NEO_1_422_485_DID 0x00CD
+#define PCI_DEVICE_NEO_2_422_485_DID 0x00CE
+#define PCI_DEVICE_NEO_EXPRESS_8_DID 0x00F0
+#define PCI_DEVICE_NEO_EXPRESS_4_DID 0x00F1
+#define PCI_DEVICE_NEO_EXPRESS_4RJ45_DID 0x00F2
+#define PCI_DEVICE_NEO_EXPRESS_8RJ45_DID 0x00F3
+#define PCI_DEVICE_NEO_EXPRESS_4_IBM_DID 0x00F4
+
+#define PCI_DEVICE_CLASSIC_4_PCI_NAME "ClassicBoard 4 PCI"
+#define PCI_DEVICE_CLASSIC_8_PCI_NAME "ClassicBoard 8 PCI"
+#define PCI_DEVICE_CLASSIC_4_422_PCI_NAME "ClassicBoard 4 422 PCI"
+#define PCI_DEVICE_CLASSIC_8_422_PCI_NAME "ClassicBoard 8 422 PCI"
+#define PCI_DEVICE_NEO_4_PCI_NAME "Neo 4 PCI"
+#define PCI_DEVICE_NEO_8_PCI_NAME "Neo 8 PCI"
+#define PCI_DEVICE_NEO_2DB9_PCI_NAME "Neo 2 - DB9 Universal PCI"
+#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME "Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
+#define PCI_DEVICE_NEO_2RJ45_PCI_NAME "Neo 2 - RJ45 Universal PCI"
+#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
+#define PCI_DEVICE_NEO_1_422_PCI_NAME "Neo 1 422 PCI"
+#define PCI_DEVICE_NEO_1_422_485_PCI_NAME "Neo 1 422/485 PCI"
+#define PCI_DEVICE_NEO_2_422_485_PCI_NAME "Neo 2 422/485 PCI"
+
+#define PCI_DEVICE_NEO_EXPRESS_8_PCI_NAME "Neo 8 PCI Express"
+#define PCI_DEVICE_NEO_EXPRESS_4_PCI_NAME "Neo 4 PCI Express"
+#define PCI_DEVICE_NEO_EXPRESS_4RJ45_PCI_NAME "Neo 4 PCI Express RJ45"
+#define PCI_DEVICE_NEO_EXPRESS_8RJ45_PCI_NAME "Neo 8 PCI Express RJ45"
+#define PCI_DEVICE_NEO_EXPRESS_4_IBM_PCI_NAME "Neo 4 PCI Express IBM"
+
+
+/* Size of Memory and I/O for PCI (4 K) */
+#define PCI_RAM_SIZE 0x1000
+
+/* Size of Memory (2MB) */
+#define PCI_MEM_SIZE 0x1000
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_sysfs.c b/drivers/staging/dgnc/dgnc_sysfs.c
new file mode 100644
index 00000000000..0ea6c800280
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_sysfs.c
@@ -0,0 +1,756 @@
+/*
+ * Copyright 2004 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/serial_reg.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+
+#include "dgnc_driver.h"
+#include "dgnc_mgmt.h"
+
+
+static ssize_t dgnc_driver_version_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART);
+}
+static DRIVER_ATTR(version, S_IRUSR, dgnc_driver_version_show, NULL);
+
+
+static ssize_t dgnc_driver_boards_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", dgnc_NumBoards);
+}
+static DRIVER_ATTR(boards, S_IRUSR, dgnc_driver_boards_show, NULL);
+
+
+static ssize_t dgnc_driver_maxboards_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS);
+}
+static DRIVER_ATTR(maxboards, S_IRUSR, dgnc_driver_maxboards_show, NULL);
+
+
+static ssize_t dgnc_driver_pollcounter_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%ld\n", dgnc_poll_counter);
+}
+static DRIVER_ATTR(pollcounter, S_IRUSR, dgnc_driver_pollcounter_show, NULL);
+
+
+static ssize_t dgnc_driver_state_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", dgnc_driver_state_text[dgnc_driver_state]);
+}
+static DRIVER_ATTR(state, S_IRUSR, dgnc_driver_state_show, NULL);
+
+
+static ssize_t dgnc_driver_debug_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", dgnc_debug);
+}
+
+static ssize_t dgnc_driver_debug_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+ sscanf(buf, "0x%x\n", &dgnc_debug);
+ return count;
+}
+static DRIVER_ATTR(debug, (S_IRUSR | S_IWUSR), dgnc_driver_debug_show, dgnc_driver_debug_store);
+
+
+static ssize_t dgnc_driver_rawreadok_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", dgnc_rawreadok);
+}
+
+static ssize_t dgnc_driver_rawreadok_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+ sscanf(buf, "0x%x\n", &dgnc_rawreadok);
+ return count;
+}
+static DRIVER_ATTR(rawreadok, (S_IRUSR | S_IWUSR), dgnc_driver_rawreadok_show, dgnc_driver_rawreadok_store);
+
+
+static ssize_t dgnc_driver_pollrate_show(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%dms\n", dgnc_poll_tick);
+}
+
+static ssize_t dgnc_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+ sscanf(buf, "%d\n", &dgnc_poll_tick);
+ return count;
+}
+static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgnc_driver_pollrate_show, dgnc_driver_pollrate_store);
+
+
+void dgnc_create_driver_sysfiles(struct pci_driver *dgnc_driver)
+{
+ int rc = 0;
+ struct device_driver *driverfs = &dgnc_driver->driver;
+
+ rc |= driver_create_file(driverfs, &driver_attr_version);
+ rc |= driver_create_file(driverfs, &driver_attr_boards);
+ rc |= driver_create_file(driverfs, &driver_attr_maxboards);
+ rc |= driver_create_file(driverfs, &driver_attr_debug);
+ rc |= driver_create_file(driverfs, &driver_attr_rawreadok);
+ rc |= driver_create_file(driverfs, &driver_attr_pollrate);
+ rc |= driver_create_file(driverfs, &driver_attr_pollcounter);
+ rc |= driver_create_file(driverfs, &driver_attr_state);
+ if (rc) {
+ printk(KERN_ERR "DGNC: sysfs driver_create_file failed!\n");
+ }
+}
+
+
+void dgnc_remove_driver_sysfiles(struct pci_driver *dgnc_driver)
+{
+ struct device_driver *driverfs = &dgnc_driver->driver;
+ driver_remove_file(driverfs, &driver_attr_version);
+ driver_remove_file(driverfs, &driver_attr_boards);
+ driver_remove_file(driverfs, &driver_attr_maxboards);
+ driver_remove_file(driverfs, &driver_attr_debug);
+ driver_remove_file(driverfs, &driver_attr_rawreadok);
+ driver_remove_file(driverfs, &driver_attr_pollrate);
+ driver_remove_file(driverfs, &driver_attr_pollcounter);
+ driver_remove_file(driverfs, &driver_attr_state);
+}
+
+
+#define DGNC_VERIFY_BOARD(p, bd) \
+ if (!p) \
+ return (0); \
+ \
+ bd = dev_get_drvdata(p); \
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC) \
+ return (0); \
+ if (bd->state != BOARD_READY) \
+ return (0); \
+
+
+
+static ssize_t dgnc_vpd_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ count += sprintf(buf + count, "\n 0 1 2 3 4 5 6 7 8 9 A B C D E F");
+ for (i = 0; i < 0x40 * 2; i++) {
+ if (!(i % 16))
+ count += sprintf(buf + count, "\n%04X ", i * 2);
+ count += sprintf(buf + count, "%02X ", bd->vpd[i]);
+ }
+ count += sprintf(buf + count, "\n");
+
+ return count;
+}
+static DEVICE_ATTR(vpd, S_IRUSR, dgnc_vpd_show, NULL);
+
+static ssize_t dgnc_serial_number_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ if (bd->serial_num[0] == '\0')
+ count += sprintf(buf + count, "<UNKNOWN>\n");
+ else
+ count += sprintf(buf + count, "%s\n", bd->serial_num);
+
+ return count;
+}
+static DEVICE_ATTR(serial_number, S_IRUSR, dgnc_serial_number_show, NULL);
+
+
+static ssize_t dgnc_ports_state_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %s\n", bd->channels[i]->ch_portnum,
+ bd->channels[i]->ch_open_count ? "Open" : "Closed");
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_state, S_IRUSR, dgnc_ports_state_show, NULL);
+
+
+static ssize_t dgnc_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_old_baud);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_baud, S_IRUSR, dgnc_ports_baud_show, NULL);
+
+
+static ssize_t dgnc_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ if (bd->channels[i]->ch_open_count) {
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum,
+ (bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
+ (bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
+ (bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
+ (bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
+ (bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
+ (bd->channels[i]->ch_mistat & UART_MSR_RI) ? "RI" : "");
+ } else {
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d\n", bd->channels[i]->ch_portnum);
+ }
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_msignals, S_IRUSR, dgnc_ports_msignals_show, NULL);
+
+
+static ssize_t dgnc_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_iflag, S_IRUSR, dgnc_ports_iflag_show, NULL);
+
+
+static ssize_t dgnc_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_cflag, S_IRUSR, dgnc_ports_cflag_show, NULL);
+
+
+static ssize_t dgnc_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_oflag, S_IRUSR, dgnc_ports_oflag_show, NULL);
+
+
+static ssize_t dgnc_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_lflag, S_IRUSR, dgnc_ports_lflag_show, NULL);
+
+
+static ssize_t dgnc_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgnc_ports_digi_flag_show, NULL);
+
+
+static ssize_t dgnc_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgnc_ports_rxcount_show, NULL);
+
+
+static ssize_t dgnc_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ int count = 0;
+ int i = 0;
+
+ DGNC_VERIFY_BOARD(p, bd);
+
+ for (i = 0; i < bd->nasync; i++) {
+ count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
+ bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount);
+ }
+ return count;
+}
+static DEVICE_ATTR(ports_txcount, S_IRUSR, dgnc_ports_txcount_show, NULL);
+
+
+/* this function creates the sys files that will export each signal status
+ * to sysfs each value will be put in a separate filename
+ */
+void dgnc_create_ports_sysfiles(struct board_t *bd)
+{
+ int rc = 0;
+
+ dev_set_drvdata(&bd->pdev->dev, bd);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_vpd);
+ rc |= device_create_file(&(bd->pdev->dev), &dev_attr_serial_number);
+ if (rc) {
+ printk(KERN_ERR "DGNC: sysfs device_create_file failed!\n");
+ }
+}
+
+
+/* removes all the sys files created for that port */
+void dgnc_remove_ports_sysfiles(struct board_t *bd)
+{
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_vpd);
+ device_remove_file(&(bd->pdev->dev), &dev_attr_serial_number);
+}
+
+
+static ssize_t dgnc_tty_state_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed");
+}
+static DEVICE_ATTR(state, S_IRUSR, dgnc_tty_state_show, NULL);
+
+
+static ssize_t dgnc_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_old_baud);
+}
+static DEVICE_ATTR(baud, S_IRUSR, dgnc_tty_baud_show, NULL);
+
+
+static ssize_t dgnc_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ if (ch->ch_open_count) {
+ return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
+ (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
+ (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
+ (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
+ (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
+ (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
+ (ch->ch_mistat & UART_MSR_RI) ? "RI" : "");
+ }
+ return 0;
+}
+static DEVICE_ATTR(msignals, S_IRUSR, dgnc_tty_msignals_show, NULL);
+
+
+static ssize_t dgnc_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag);
+}
+static DEVICE_ATTR(iflag, S_IRUSR, dgnc_tty_iflag_show, NULL);
+
+
+static ssize_t dgnc_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag);
+}
+static DEVICE_ATTR(cflag, S_IRUSR, dgnc_tty_cflag_show, NULL);
+
+
+static ssize_t dgnc_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag);
+}
+static DEVICE_ATTR(oflag, S_IRUSR, dgnc_tty_oflag_show, NULL);
+
+
+static ssize_t dgnc_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag);
+}
+static DEVICE_ATTR(lflag, S_IRUSR, dgnc_tty_lflag_show, NULL);
+
+
+static ssize_t dgnc_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
+}
+static DEVICE_ATTR(digi_flag, S_IRUSR, dgnc_tty_digi_flag_show, NULL);
+
+
+static ssize_t dgnc_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount);
+}
+static DEVICE_ATTR(rxcount, S_IRUSR, dgnc_tty_rxcount_show, NULL);
+
+
+static ssize_t dgnc_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount);
+}
+static DEVICE_ATTR(txcount, S_IRUSR, dgnc_tty_txcount_show, NULL);
+
+
+static ssize_t dgnc_tty_name_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+
+ if (!d)
+ return (0);
+ un = (struct un_t *) dev_get_drvdata(d);
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (0);
+ if (bd->state != BOARD_READY)
+ return (0);
+
+ return snprintf(buf, PAGE_SIZE, "%sn%d%c\n",
+ (un->un_type == DGNC_PRINT) ? "pr" : "tty",
+ bd->boardnum + 1, 'a' + ch->ch_portnum);
+}
+static DEVICE_ATTR(custom_name, S_IRUSR, dgnc_tty_name_show, NULL);
+
+
+static struct attribute *dgnc_sysfs_tty_entries[] = {
+ &dev_attr_state.attr,
+ &dev_attr_baud.attr,
+ &dev_attr_msignals.attr,
+ &dev_attr_iflag.attr,
+ &dev_attr_cflag.attr,
+ &dev_attr_oflag.attr,
+ &dev_attr_lflag.attr,
+ &dev_attr_digi_flag.attr,
+ &dev_attr_rxcount.attr,
+ &dev_attr_txcount.attr,
+ &dev_attr_custom_name.attr,
+ NULL
+};
+
+
+static struct attribute_group dgnc_tty_attribute_group = {
+ .name = NULL,
+ .attrs = dgnc_sysfs_tty_entries,
+};
+
+
+void dgnc_create_tty_sysfs(struct un_t *un, struct device *c)
+{
+ int ret;
+
+ ret = sysfs_create_group(&c->kobj, &dgnc_tty_attribute_group);
+ if (ret) {
+ printk(KERN_ERR "dgnc: failed to create sysfs tty device attributes.\n");
+ sysfs_remove_group(&c->kobj, &dgnc_tty_attribute_group);
+ return;
+ }
+
+ dev_set_drvdata(c, un);
+
+}
+
+
+void dgnc_remove_tty_sysfs(struct device *c)
+{
+ sysfs_remove_group(&c->kobj, &dgnc_tty_attribute_group);
+}
+
diff --git a/drivers/staging/dgnc/dgnc_sysfs.h b/drivers/staging/dgnc/dgnc_sysfs.h
new file mode 100644
index 00000000000..4b87ce1cc7a
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_sysfs.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGNC_SYSFS_H
+#define __DGNC_SYSFS_H
+
+#include "dgnc_driver.h"
+
+#include <linux/device.h>
+
+struct board_t;
+struct channel_t;
+struct un_t;
+struct pci_driver;
+struct class_device;
+
+extern void dgnc_create_ports_sysfiles(struct board_t *bd);
+extern void dgnc_remove_ports_sysfiles(struct board_t *bd);
+
+extern void dgnc_create_driver_sysfiles(struct pci_driver *);
+extern void dgnc_remove_driver_sysfiles(struct pci_driver *);
+
+extern int dgnc_tty_class_init(void);
+extern int dgnc_tty_class_destroy(void);
+
+extern void dgnc_create_tty_sysfs(struct un_t *un, struct device *c);
+extern void dgnc_remove_tty_sysfs(struct device *c);
+
+
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_trace.c b/drivers/staging/dgnc/dgnc_trace.c
new file mode 100644
index 00000000000..a98b7d4255c
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_trace.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h> /* For jiffies, task states */
+#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
+#include <linux/vmalloc.h>
+
+#include "dgnc_driver.h"
+
+#define TRC_TO_CONSOLE 1
+
+/* file level globals */
+static char *dgnc_trcbuf; /* the ringbuffer */
+
+#if defined(TRC_TO_KMEM)
+static int dgnc_trcbufi = 0; /* index of the tilde at the end of */
+#endif
+
+#if defined(TRC_TO_KMEM)
+static DEFINE_SPINLOCK(dgnc_tracef_lock);
+#endif
+
+
+#if 0
+
+#if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE)
+
+void dgnc_tracef(const char *fmt, ...)
+{
+ return;
+}
+
+#else /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
+
+void dgnc_tracef(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[TRC_MAXMSG+1];
+ size_t lenbuf;
+ int i;
+ static int failed = FALSE;
+# if defined(TRC_TO_KMEM)
+ unsigned long flags;
+#endif
+
+ if(failed)
+ return;
+# if defined(TRC_TO_KMEM)
+ DGNC_LOCK(dgnc_tracef_lock, flags);
+#endif
+
+ /* Format buf using fmt and arguments contained in ap. */
+ va_start(ap, fmt);
+ i = vsprintf(buf, fmt, ap);
+ va_end(ap);
+ lenbuf = strlen(buf);
+
+# if defined(TRC_TO_KMEM)
+ {
+ static int initd=0;
+
+ /*
+ * Now, in addition to (or instead of) printing this stuff out
+ * (which is a buffered operation), also tuck it away into a
+ * corner of memory which can be examined post-crash in kdb.
+ */
+ if (!initd) {
+ dgnc_trcbuf = (char *) vmalloc(dgnc_trcbuf_size);
+ if(!dgnc_trcbuf) {
+ failed = TRUE;
+ printk("dgnc: tracing init failed!\n");
+ return;
+ }
+
+ memset(dgnc_trcbuf, '\0', dgnc_trcbuf_size);
+ dgnc_trcbufi = 0;
+ initd++;
+
+ printk("dgnc: tracing enabled - " TRC_DTRC
+ " 0x%lx 0x%x\n",
+ (unsigned long)dgnc_trcbuf,
+ dgnc_trcbuf_size);
+ }
+
+# if defined(TRC_ON_OVERFLOW_WRAP_AROUND)
+ /*
+ * This is the less CPU-intensive way to do things. We simply
+ * wrap around before we fall off the end of the buffer. A
+ * tilde (~) demarcates the current end of the trace.
+ *
+ * This method should be used if you are concerned about race
+ * conditions as it is less likely to affect the timing of
+ * things.
+ */
+
+ if (dgnc_trcbufi + lenbuf >= dgnc_trcbuf_size) {
+ /* We are wrapping, so wipe out the last tilde. */
+ dgnc_trcbuf[dgnc_trcbufi] = '\0';
+ /* put the new string at the beginning of the buffer */
+ dgnc_trcbufi = 0;
+ }
+
+ strcpy(&dgnc_trcbuf[dgnc_trcbufi], buf);
+ dgnc_trcbufi += lenbuf;
+ dgnc_trcbuf[dgnc_trcbufi] = '~';
+
+# elif defined(TRC_ON_OVERFLOW_SHIFT_BUFFER)
+ /*
+ * This is the more CPU-intensive way to do things. If we
+ * venture into the last 1/8 of the buffer, we shift the
+ * last 7/8 of the buffer forward, wiping out the first 1/8.
+ * Advantage: No wrap-around, only truncation from the
+ * beginning.
+ *
+ * This method should not be used if you are concerned about
+ * timing changes affecting the behaviour of the driver (ie,
+ * race conditions).
+ */
+ strcpy(&dgnc_trcbuf[dgnc_trcbufi], buf);
+ dgnc_trcbufi += lenbuf;
+ dgnc_trcbuf[dgnc_trcbufi] = '~';
+ dgnc_trcbuf[dgnc_trcbufi+1] = '\0';
+
+ /* If we're near the end of the trace buffer... */
+ if (dgnc_trcbufi > (dgnc_trcbuf_size/8)*7) {
+ /* Wipe out the first eighth to make some more room. */
+ strcpy(dgnc_trcbuf, &dgnc_trcbuf[dgnc_trcbuf_size/8]);
+ dgnc_trcbufi = strlen(dgnc_trcbuf)-1;
+ /* Plop overflow message at the top of the buffer. */
+ bcopy(TRC_OVERFLOW, dgnc_trcbuf, strlen(TRC_OVERFLOW));
+ }
+# else
+# error "TRC_ON_OVERFLOW_WRAP_AROUND or TRC_ON_OVERFLOW_SHIFT_BUFFER?"
+# endif
+ }
+ DGNC_UNLOCK(dgnc_tracef_lock, flags);
+
+# endif /* defined(TRC_TO_KMEM) */
+}
+
+#endif /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
+
+#endif
+
+
+/*
+ * dgnc_tracer_free()
+ *
+ *
+ */
+void dgnc_tracer_free(void)
+{
+ if(dgnc_trcbuf)
+ vfree(dgnc_trcbuf);
+}
diff --git a/drivers/staging/dgnc/dgnc_trace.h b/drivers/staging/dgnc/dgnc_trace.h
new file mode 100644
index 00000000000..efed88a627d
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_trace.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *****************************************************************************
+ * Header file for dgnc_trace.c
+ *
+ */
+
+#ifndef __DGNC_TRACE_H
+#define __DGNC_TRACE_H
+
+#include "dgnc_driver.h"
+
+#if 0
+
+# if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE)
+ void dgnc_tracef(const char *fmt, ...);
+# else
+ void dgnc_tracef(const char *fmt, ...);
+# endif
+
+#endif
+
+void dgnc_tracer_free(void);
+
+#endif
+
diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c
new file mode 100644
index 00000000000..a7bb6bceb9e
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_tty.c
@@ -0,0 +1,3544 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
+ *
+ * This is shared code between Digi's CVS archive and the
+ * Linux Kernel sources.
+ * Changing the source just for reformatting needlessly breaks
+ * our CVS diff history.
+ *
+ * Send any bug fixes/changes to: Eng.Linux at digi dot com.
+ * Thank you.
+ */
+
+/************************************************************************
+ *
+ * This file implements the tty driver functionality for the
+ * Neo and ClassicBoard PCI based product lines.
+ *
+ ************************************************************************
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/sched.h> /* For jiffies, task states */
+#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
+#include <linux/delay.h> /* For udelay */
+#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */
+#include <linux/pci.h>
+
+#include "dgnc_driver.h"
+#include "dgnc_tty.h"
+#include "dgnc_types.h"
+#include "dgnc_trace.h"
+#include "dgnc_neo.h"
+#include "dgnc_cls.h"
+#include "dpacompat.h"
+#include "dgnc_sysfs.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+#define init_MUTEX(sem) sema_init(sem, 1)
+#define DECLARE_MUTEX(name) \
+ struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
+#endif
+
+/*
+ * internal variables
+ */
+static struct board_t *dgnc_BoardsByMajor[256];
+static uchar *dgnc_TmpWriteBuf = NULL;
+static DECLARE_MUTEX(dgnc_TmpWriteSem);
+
+/*
+ * Default transparent print information.
+ */
+static struct digi_t dgnc_digi_init = {
+ .digi_flags = DIGI_COOK, /* Flags */
+ .digi_maxcps = 100, /* Max CPS */
+ .digi_maxchar = 50, /* Max chars in print queue */
+ .digi_bufsize = 100, /* Printer buffer size */
+ .digi_onlen = 4, /* size of printer on string */
+ .digi_offlen = 4, /* size of printer off string */
+ .digi_onstr = "\033[5i", /* ANSI printer on string ] */
+ .digi_offstr = "\033[4i", /* ANSI printer off string ] */
+ .digi_term = "ansi" /* default terminal type */
+};
+
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially.
+ *
+ * This defines a raw port at 9600 baud, 8 data bits, no parity,
+ * 1 stop bit.
+ */
+static struct ktermios DgncDefaultTermios =
+{
+ .c_iflag = (DEFAULT_IFLAGS), /* iflags */
+ .c_oflag = (DEFAULT_OFLAGS), /* oflags */
+ .c_cflag = (DEFAULT_CFLAGS), /* cflags */
+ .c_lflag = (DEFAULT_LFLAGS), /* lflags */
+ .c_cc = INIT_C_CC,
+ .c_line = 0,
+};
+
+
+/* Our function prototypes */
+static int dgnc_tty_open(struct tty_struct *tty, struct file *file);
+static void dgnc_tty_close(struct tty_struct *tty, struct file *file);
+static int dgnc_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch);
+static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
+static int dgnc_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo);
+static int dgnc_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info);
+static int dgnc_tty_write_room(struct tty_struct *tty);
+static int dgnc_tty_put_char(struct tty_struct *tty, unsigned char c);
+static int dgnc_tty_chars_in_buffer(struct tty_struct *tty);
+static void dgnc_tty_start(struct tty_struct *tty);
+static void dgnc_tty_stop(struct tty_struct *tty);
+static void dgnc_tty_throttle(struct tty_struct *tty);
+static void dgnc_tty_unthrottle(struct tty_struct *tty);
+static void dgnc_tty_flush_chars(struct tty_struct *tty);
+static void dgnc_tty_flush_buffer(struct tty_struct *tty);
+static void dgnc_tty_hangup(struct tty_struct *tty);
+static int dgnc_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value);
+static int dgnc_get_modem_info(struct channel_t *ch, unsigned int __user *value);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgnc_tty_tiocmget(struct tty_struct *tty);
+static int dgnc_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear);
+#else
+static int dgnc_tty_tiocmget(struct tty_struct *tty, struct file *file);
+static int dgnc_tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear);
+#endif
+static int dgnc_tty_send_break(struct tty_struct *tty, int msec);
+static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout);
+static int dgnc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count);
+static void dgnc_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios);
+static void dgnc_tty_send_xchar(struct tty_struct *tty, char ch);
+
+
+static const struct tty_operations dgnc_tty_ops = {
+ .open = dgnc_tty_open,
+ .close = dgnc_tty_close,
+ .write = dgnc_tty_write,
+ .write_room = dgnc_tty_write_room,
+ .flush_buffer = dgnc_tty_flush_buffer,
+ .chars_in_buffer = dgnc_tty_chars_in_buffer,
+ .flush_chars = dgnc_tty_flush_chars,
+ .ioctl = dgnc_tty_ioctl,
+ .set_termios = dgnc_tty_set_termios,
+ .stop = dgnc_tty_stop,
+ .start = dgnc_tty_start,
+ .throttle = dgnc_tty_throttle,
+ .unthrottle = dgnc_tty_unthrottle,
+ .hangup = dgnc_tty_hangup,
+ .put_char = dgnc_tty_put_char,
+ .tiocmget = dgnc_tty_tiocmget,
+ .tiocmset = dgnc_tty_tiocmset,
+ .break_ctl = dgnc_tty_send_break,
+ .wait_until_sent = dgnc_tty_wait_until_sent,
+ .send_xchar = dgnc_tty_send_xchar
+};
+
+/************************************************************************
+ *
+ * TTY Initialization/Cleanup Functions
+ *
+ ************************************************************************/
+
+/*
+ * dgnc_tty_preinit()
+ *
+ * Initialize any global tty related data before we download any boards.
+ */
+int dgnc_tty_preinit(void)
+{
+ /*
+ * Allocate a buffer for doing the copy from user space to
+ * kernel space in dgnc_write(). We only use one buffer and
+ * control access to it with a semaphore. If we are paging, we
+ * are already in trouble so one buffer won't hurt much anyway.
+ *
+ * We are okay to sleep in the malloc, as this routine
+ * is only called during module load, (not in interrupt context),
+ * and with no locks held.
+ */
+ dgnc_TmpWriteBuf = kmalloc(WRITEBUFLEN, GFP_KERNEL);
+
+ if (!dgnc_TmpWriteBuf) {
+ DPR_INIT(("unable to allocate tmp write buf"));
+ return (-ENOMEM);
+ }
+
+ return(0);
+}
+
+
+/*
+ * dgnc_tty_register()
+ *
+ * Init the tty subsystem for this board.
+ */
+int dgnc_tty_register(struct board_t *brd)
+{
+ int rc = 0;
+
+ DPR_INIT(("tty_register start\n"));
+
+ memset(&brd->SerialDriver, 0, sizeof(struct tty_driver));
+ memset(&brd->PrintDriver, 0, sizeof(struct tty_driver));
+
+ brd->SerialDriver.magic = TTY_DRIVER_MAGIC;
+
+ snprintf(brd->SerialName, MAXTTYNAMELEN, "tty_dgnc_%d_", brd->boardnum);
+
+ brd->SerialDriver.name = brd->SerialName;
+ brd->SerialDriver.name_base = 0;
+ brd->SerialDriver.major = 0;
+ brd->SerialDriver.minor_start = 0;
+ brd->SerialDriver.num = brd->maxports;
+ brd->SerialDriver.type = TTY_DRIVER_TYPE_SERIAL;
+ brd->SerialDriver.subtype = SERIAL_TYPE_NORMAL;
+ brd->SerialDriver.init_termios = DgncDefaultTermios;
+ brd->SerialDriver.driver_name = DRVSTR;
+ brd->SerialDriver.flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
+
+ /*
+ * The kernel wants space to store pointers to
+ * tty_struct's and termios's.
+ */
+ brd->SerialDriver.ttys = kzalloc(brd->maxports * sizeof(struct tty_struct *), GFP_KERNEL);
+ if (!brd->SerialDriver.ttys)
+ return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+ brd->SerialDriver.refcount = brd->TtyRefCnt;
+#else
+ kref_init(&brd->SerialDriver.kref);
+#endif
+
+ brd->SerialDriver.termios = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL);
+ if (!brd->SerialDriver.termios)
+ return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)
+ brd->SerialDriver.termios_locked = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL);
+ if (!brd->SerialDriver.termios_locked)
+ return(-ENOMEM);
+#endif
+ /*
+ * Entry points for driver. Called by the kernel from
+ * tty_io.c and n_tty.c.
+ */
+ tty_set_operations(&brd->SerialDriver, &dgnc_tty_ops);
+
+ if (!brd->dgnc_Major_Serial_Registered) {
+ /* Register tty devices */
+ rc = tty_register_driver(&brd->SerialDriver);
+ if (rc < 0) {
+ APR(("Can't register tty device (%d)\n", rc));
+ return(rc);
+ }
+ brd->dgnc_Major_Serial_Registered = TRUE;
+ }
+
+ /*
+ * If we're doing transparent print, we have to do all of the above
+ * again, seperately so we don't get the LD confused about what major
+ * we are when we get into the dgnc_tty_open() routine.
+ */
+ brd->PrintDriver.magic = TTY_DRIVER_MAGIC;
+ snprintf(brd->PrintName, MAXTTYNAMELEN, "pr_dgnc_%d_", brd->boardnum);
+
+ brd->PrintDriver.name = brd->PrintName;
+ brd->PrintDriver.name_base = 0;
+ brd->PrintDriver.major = brd->SerialDriver.major;
+ brd->PrintDriver.minor_start = 0x80;
+ brd->PrintDriver.num = brd->maxports;
+ brd->PrintDriver.type = TTY_DRIVER_TYPE_SERIAL;
+ brd->PrintDriver.subtype = SERIAL_TYPE_NORMAL;
+ brd->PrintDriver.init_termios = DgncDefaultTermios;
+ brd->PrintDriver.driver_name = DRVSTR;
+ brd->PrintDriver.flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
+
+ /*
+ * The kernel wants space to store pointers to
+ * tty_struct's and termios's. Must be seperate from
+ * the Serial Driver so we don't get confused
+ */
+ brd->PrintDriver.ttys = kzalloc(brd->maxports * sizeof(struct tty_struct *), GFP_KERNEL);
+ if (!brd->PrintDriver.ttys)
+ return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+ brd->PrintDriver.refcount = brd->TtyRefCnt;
+#else
+ kref_init(&brd->PrintDriver.kref);
+#endif
+
+ brd->PrintDriver.termios = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL);
+ if (!brd->PrintDriver.termios)
+ return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)
+ brd->PrintDriver.termios_locked = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL);
+ if (!brd->PrintDriver.termios_locked)
+ return(-ENOMEM);
+#endif
+
+ /*
+ * Entry points for driver. Called by the kernel from
+ * tty_io.c and n_tty.c.
+ */
+ tty_set_operations(&brd->PrintDriver, &dgnc_tty_ops);
+
+ if (!brd->dgnc_Major_TransparentPrint_Registered) {
+ /* Register Transparent Print devices */
+ rc = tty_register_driver(&brd->PrintDriver);
+ if (rc < 0) {
+ APR(("Can't register Transparent Print device (%d)\n", rc));
+ return(rc);
+ }
+ brd->dgnc_Major_TransparentPrint_Registered = TRUE;
+ }
+
+ dgnc_BoardsByMajor[brd->SerialDriver.major] = brd;
+ brd->dgnc_Serial_Major = brd->SerialDriver.major;
+ brd->dgnc_TransparentPrint_Major = brd->PrintDriver.major;
+
+ DPR_INIT(("DGNC REGISTER TTY: MAJOR: %d\n", brd->SerialDriver.major));
+
+ return (rc);
+}
+
+
+/*
+ * dgnc_tty_init()
+ *
+ * Init the tty subsystem. Called once per board after board has been
+ * downloaded and init'ed.
+ */
+int dgnc_tty_init(struct board_t *brd)
+{
+ int i;
+ void __iomem *vaddr;
+ struct channel_t *ch;
+
+ if (!brd)
+ return (-ENXIO);
+
+ DPR_INIT(("dgnc_tty_init start\n"));
+
+ /*
+ * Initialize board structure elements.
+ */
+
+ vaddr = brd->re_map_membase;
+
+ brd->nasync = brd->maxports;
+
+ /*
+ * Allocate channel memory that might not have been allocated
+ * when the driver was first loaded.
+ */
+ for (i = 0; i < brd->nasync; i++) {
+ if (!brd->channels[i]) {
+
+ /*
+ * Okay to malloc with GFP_KERNEL, we are not at
+ * interrupt context, and there are no locks held.
+ */
+ brd->channels[i] = kzalloc(sizeof(struct channel_t), GFP_KERNEL);
+ if (!brd->channels[i]) {
+ DPR_CORE(("%s:%d Unable to allocate memory for channel struct\n",
+ __FILE__, __LINE__));
+ }
+ }
+ }
+
+ ch = brd->channels[0];
+ vaddr = brd->re_map_membase;
+
+ /* Set up channel variables */
+ for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+ if (!brd->channels[i])
+ continue;
+
+ DGNC_SPINLOCK_INIT(ch->ch_lock);
+
+ /* Store all our magic numbers */
+ ch->magic = DGNC_CHANNEL_MAGIC;
+ ch->ch_tun.magic = DGNC_UNIT_MAGIC;
+ ch->ch_tun.un_ch = ch;
+ ch->ch_tun.un_type = DGNC_SERIAL;
+ ch->ch_tun.un_dev = i;
+
+ ch->ch_pun.magic = DGNC_UNIT_MAGIC;
+ ch->ch_pun.un_ch = ch;
+ ch->ch_pun.un_type = DGNC_PRINT;
+ ch->ch_pun.un_dev = i + 128;
+
+ if (brd->bd_uart_offset == 0x200)
+ ch->ch_neo_uart = vaddr + (brd->bd_uart_offset * i);
+ else
+ ch->ch_cls_uart = vaddr + (brd->bd_uart_offset * i);
+
+ ch->ch_bd = brd;
+ ch->ch_portnum = i;
+ ch->ch_digi = dgnc_digi_init;
+
+ /* .25 second delay */
+ ch->ch_close_delay = 250;
+
+ init_waitqueue_head(&ch->ch_flags_wait);
+ init_waitqueue_head(&ch->ch_tun.un_flags_wait);
+ init_waitqueue_head(&ch->ch_pun.un_flags_wait);
+ init_waitqueue_head(&ch->ch_sniff_wait);
+
+ {
+ struct device *classp;
+ classp = tty_register_device(&brd->SerialDriver, i,
+ &(ch->ch_bd->pdev->dev));
+ ch->ch_tun.un_sysfs = classp;
+ dgnc_create_tty_sysfs(&ch->ch_tun, classp);
+
+ classp = tty_register_device(&brd->PrintDriver, i,
+ &(ch->ch_bd->pdev->dev));
+ ch->ch_pun.un_sysfs = classp;
+ dgnc_create_tty_sysfs(&ch->ch_pun, classp);
+ }
+
+ }
+
+ DPR_INIT(("dgnc_tty_init finish\n"));
+
+ return (0);
+}
+
+
+/*
+ * dgnc_tty_post_uninit()
+ *
+ * UnInitialize any global tty related data.
+ */
+void dgnc_tty_post_uninit(void)
+{
+ if (dgnc_TmpWriteBuf) {
+ kfree(dgnc_TmpWriteBuf);
+ dgnc_TmpWriteBuf = NULL;
+ }
+}
+
+
+/*
+ * dgnc_tty_uninit()
+ *
+ * Uninitialize the TTY portion of this driver. Free all memory and
+ * resources.
+ */
+void dgnc_tty_uninit(struct board_t *brd)
+{
+ int i = 0;
+
+ if (brd->dgnc_Major_Serial_Registered) {
+ dgnc_BoardsByMajor[brd->SerialDriver.major] = NULL;
+ brd->dgnc_Serial_Major = 0;
+ for (i = 0; i < brd->nasync; i++) {
+ dgnc_remove_tty_sysfs(brd->channels[i]->ch_tun.un_sysfs);
+ tty_unregister_device(&brd->SerialDriver, i);
+ }
+ tty_unregister_driver(&brd->SerialDriver);
+ brd->dgnc_Major_Serial_Registered = FALSE;
+ }
+
+ if (brd->dgnc_Major_TransparentPrint_Registered) {
+ dgnc_BoardsByMajor[brd->PrintDriver.major] = NULL;
+ brd->dgnc_TransparentPrint_Major = 0;
+ for (i = 0; i < brd->nasync; i++) {
+ dgnc_remove_tty_sysfs(brd->channels[i]->ch_pun.un_sysfs);
+ tty_unregister_device(&brd->PrintDriver, i);
+ }
+ tty_unregister_driver(&brd->PrintDriver);
+ brd->dgnc_Major_TransparentPrint_Registered = FALSE;
+ }
+
+ if (brd->SerialDriver.ttys) {
+ kfree(brd->SerialDriver.ttys);
+ brd->SerialDriver.ttys = NULL;
+ }
+ if (brd->PrintDriver.ttys) {
+ kfree(brd->PrintDriver.ttys);
+ brd->PrintDriver.ttys = NULL;
+ }
+}
+
+
+#define TMPBUFLEN (1024)
+
+/*
+ * dgnc_sniff - Dump data out to the "sniff" buffer if the
+ * proc sniff file is opened...
+ */
+void dgnc_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int len)
+{
+ struct timeval tv;
+ int n;
+ int r;
+ int nbuf;
+ int i;
+ int tmpbuflen;
+ char tmpbuf[TMPBUFLEN];
+ char *p = tmpbuf;
+ int too_much_data;
+
+ /* Leave if sniff not open */
+ if (!(ch->ch_sniff_flags & SNIFF_OPEN))
+ return;
+
+ do_gettimeofday(&tv);
+
+ /* Create our header for data dump */
+ p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text);
+ tmpbuflen = p - tmpbuf;
+
+ do {
+ too_much_data = 0;
+
+ for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) {
+ p += sprintf(p, "%02x ", *buf);
+ buf++;
+ tmpbuflen = p - tmpbuf;
+ }
+
+ if (tmpbuflen < (TMPBUFLEN - 4)) {
+ if (i > 0)
+ p += sprintf(p - 1, "%s\n", ">");
+ else
+ p += sprintf(p, "%s\n", ">");
+ } else {
+ too_much_data = 1;
+ len -= i;
+ }
+
+ nbuf = strlen(tmpbuf);
+ p = tmpbuf;
+
+ /*
+ * Loop while data remains.
+ */
+ while (nbuf > 0 && ch->ch_sniff_buf != 0) {
+ /*
+ * Determine the amount of available space left in the
+ * buffer. If there's none, wait until some appears.
+ */
+ n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) & SNIFF_MASK;
+
+ /*
+ * If there is no space left to write to in our sniff buffer,
+ * we have no choice but to drop the data.
+ * We *cannot* sleep here waiting for space, because this
+ * function was probably called by the interrupt/timer routines!
+ */
+ if (n == 0) {
+ return;
+ }
+
+ /*
+ * Copy as much data as will fit.
+ */
+
+ if (n > nbuf)
+ n = nbuf;
+
+ r = SNIFF_MAX - ch->ch_sniff_in;
+
+ if (r <= n) {
+ memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, r);
+
+ n -= r;
+ ch->ch_sniff_in = 0;
+ p += r;
+ nbuf -= r;
+ }
+
+ memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n);
+
+ ch->ch_sniff_in += n;
+ p += n;
+ nbuf -= n;
+
+ /*
+ * Wakeup any thread waiting for data
+ */
+ if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) {
+ ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA;
+ wake_up_interruptible(&ch->ch_sniff_wait);
+ }
+ }
+
+ /*
+ * If the user sent us too much data to push into our tmpbuf,
+ * we need to keep looping around on all the data.
+ */
+ if (too_much_data) {
+ p = tmpbuf;
+ tmpbuflen = 0;
+ }
+
+ } while (too_much_data);
+}
+
+
+/*=======================================================================
+ *
+ * dgnc_wmove - Write data to transmit queue.
+ *
+ * ch - Pointer to channel structure.
+ * buf - Poiter to characters to be moved.
+ * n - Number of characters to move.
+ *
+ *=======================================================================*/
+static void dgnc_wmove(struct channel_t *ch, char *buf, uint n)
+{
+ int remain;
+ uint head;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ head = ch->ch_w_head & WQUEUEMASK;
+
+ /*
+ * If the write wraps over the top of the circular buffer,
+ * move the portion up to the wrap point, and reset the
+ * pointers to the bottom.
+ */
+ remain = WQUEUESIZE - head;
+
+ if (n >= remain) {
+ n -= remain;
+ memcpy(ch->ch_wqueue + head, buf, remain);
+ head = 0;
+ buf += remain;
+ }
+
+ if (n > 0) {
+ /*
+ * Move rest of data.
+ */
+ remain = n;
+ memcpy(ch->ch_wqueue + head, buf, remain);
+ head += remain;
+ }
+
+ head &= WQUEUEMASK;
+ ch->ch_w_head = head;
+}
+
+
+
+
+/*=======================================================================
+ *
+ * dgnc_input - Process received data.
+ *
+ * ch - Pointer to channel structure.
+ *
+ *=======================================================================*/
+void dgnc_input(struct channel_t *ch)
+{
+ struct board_t *bd;
+ struct tty_struct *tp;
+ struct tty_ldisc *ld;
+ uint rmask;
+ ushort head;
+ ushort tail;
+ int data_len;
+ ulong lock_flags;
+ int flip_len;
+ int len = 0;
+ int n = 0;
+ int s = 0;
+ int i = 0;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ tp = ch->ch_tun.un_tty;
+
+ bd = ch->ch_bd;
+ if(!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * Figure the number of characters in the buffer.
+ * Exit immediately if none.
+ */
+ rmask = RQUEUEMASK;
+ head = ch->ch_r_head & rmask;
+ tail = ch->ch_r_tail & rmask;
+ data_len = (head - tail) & rmask;
+
+ if (data_len == 0) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ DPR_READ(("dgnc_input start\n"));
+
+ /*
+ * If the device is not open, or CREAD is off,
+ * flush input data and return immediately.
+ */
+ if (!tp || (tp->magic != TTY_MAGIC) || !(ch->ch_tun.un_flags & UN_ISOPEN) ||
+ !(tp->termios.c_cflag & CREAD) || (ch->ch_tun.un_flags & UN_CLOSING)) {
+
+ DPR_READ(("input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum));
+ DPR_READ(("input. tp: %p tp->magic: %x MAGIC:%x ch flags: %x\n",
+ tp, tp ? tp->magic : 0, TTY_MAGIC, ch->ch_tun.un_flags));
+
+ ch->ch_r_head = tail;
+
+ /* Force queue flow control to be released, if needed */
+ dgnc_check_queue_flow_control(ch);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ /*
+ * If we are throttled, simply don't read any data.
+ */
+ if (ch->ch_flags & CH_FORCED_STOPI) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ DPR_READ(("Port %d throttled, not reading any data. head: %x tail: %x\n",
+ ch->ch_portnum, head, tail));
+ return;
+ }
+
+ DPR_READ(("dgnc_input start 2\n"));
+
+ flip_len = TTY_FLIPBUF_SIZE;
+
+ /* Chop down the length, if needed */
+ len = min(data_len, flip_len);
+ len = min(len, (N_TTY_BUF_SIZE - 1));
+
+ ld = tty_ldisc_ref(tp);
+
+#ifdef TTY_DONT_FLIP
+ /*
+ * If the DONT_FLIP flag is on, don't flush our buffer, and act
+ * like the ld doesn't have any space to put the data right now.
+ */
+ if (test_bit(TTY_DONT_FLIP, &tp->flags))
+ len = 0;
+#endif
+
+ /*
+ * If we were unable to get a reference to the ld,
+ * don't flush our buffer, and act like the ld doesn't
+ * have any space to put the data right now.
+ */
+ if (!ld) {
+ len = 0;
+ } else {
+ /*
+ * If ld doesn't have a pointer to a receive_buf function,
+ * flush the data, then act like the ld doesn't have any
+ * space to put the data right now.
+ */
+ if (!ld->ops->receive_buf) {
+ ch->ch_r_head = ch->ch_r_tail;
+ len = 0;
+ }
+ }
+
+ if (len <= 0) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ if (ld)
+ tty_ldisc_deref(ld);
+ return;
+ }
+
+ /*
+ * The tty layer in the kernel has changed in 2.6.16+.
+ *
+ * The flip buffers in the tty structure are no longer exposed,
+ * and probably will be going away eventually.
+ *
+ * If we are completely raw, we don't need to go through a lot
+ * of the tty layers that exist.
+ * In this case, we take the shortest and fastest route we
+ * can to relay the data to the user.
+ *
+ * On the other hand, if we are not raw, we need to go through
+ * the new 2.6.16+ tty layer, which has its API more well defined.
+ */
+ len = tty_buffer_request_room(tp->port, len);
+ n = len;
+
+ /*
+ * n now contains the most amount of data we can copy,
+ * bounded either by how much the Linux tty layer can handle,
+ * or the amount of data the card actually has pending...
+ */
+ while (n) {
+ s = ((head >= tail) ? head : RQUEUESIZE) - tail;
+ s = min(s, n);
+
+ if (s <= 0)
+ break;
+
+ /*
+ * If conditions are such that ld needs to see all
+ * UART errors, we will have to walk each character
+ * and error byte and send them to the buffer one at
+ * a time.
+ */
+ if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+ for (i = 0; i < s; i++) {
+ if (*(ch->ch_equeue + tail + i) & UART_LSR_BI)
+ tty_insert_flip_char(tp->port, *(ch->ch_rqueue + tail + i), TTY_BREAK);
+ else if (*(ch->ch_equeue + tail + i) & UART_LSR_PE)
+ tty_insert_flip_char(tp->port, *(ch->ch_rqueue + tail + i), TTY_PARITY);
+ else if (*(ch->ch_equeue + tail + i) & UART_LSR_FE)
+ tty_insert_flip_char(tp->port, *(ch->ch_rqueue + tail + i), TTY_FRAME);
+ else
+ tty_insert_flip_char(tp->port, *(ch->ch_rqueue + tail + i), TTY_NORMAL);
+ }
+ }
+ else {
+ tty_insert_flip_string(tp->port, ch->ch_rqueue + tail, s);
+ }
+
+ dgnc_sniff_nowait_nolock(ch, "USER READ", ch->ch_rqueue + tail, s);
+
+ tail += s;
+ n -= s;
+ /* Flip queue if needed */
+ tail &= rmask;
+ }
+
+ ch->ch_r_tail = tail & rmask;
+ ch->ch_e_tail = tail & rmask;
+ dgnc_check_queue_flow_control(ch);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ /* Tell the tty layer its okay to "eat" the data now */
+ tty_flip_buffer_push(tp->port);
+
+ if (ld)
+ tty_ldisc_deref(ld);
+
+ DPR_READ(("dgnc_input - finish\n"));
+}
+
+
+/************************************************************************
+ * Determines when CARRIER changes state and takes appropriate
+ * action.
+ ************************************************************************/
+void dgnc_carrier(struct channel_t *ch)
+{
+ struct board_t *bd;
+
+ int virt_carrier = 0;
+ int phys_carrier = 0;
+
+ DPR_CARR(("dgnc_carrier called...\n"));
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ if (ch->ch_mistat & UART_MSR_DCD) {
+ DPR_CARR(("mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD));
+ phys_carrier = 1;
+ }
+
+ if (ch->ch_digi.digi_flags & DIGI_FORCEDCD) {
+ virt_carrier = 1;
+ }
+
+ if (ch->ch_c_cflag & CLOCAL) {
+ virt_carrier = 1;
+ }
+
+
+ DPR_CARR(("DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier));
+
+ /*
+ * Test for a VIRTUAL carrier transition to HIGH.
+ */
+ if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
+
+ /*
+ * When carrier rises, wake any threads waiting
+ * for carrier in the open routine.
+ */
+
+ DPR_CARR(("carrier: virt DCD rose\n"));
+
+ if (waitqueue_active(&(ch->ch_flags_wait)))
+ wake_up_interruptible(&ch->ch_flags_wait);
+ }
+
+ /*
+ * Test for a PHYSICAL carrier transition to HIGH.
+ */
+ if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
+
+ /*
+ * When carrier rises, wake any threads waiting
+ * for carrier in the open routine.
+ */
+
+ DPR_CARR(("carrier: physical DCD rose\n"));
+
+ if (waitqueue_active(&(ch->ch_flags_wait)))
+ wake_up_interruptible(&ch->ch_flags_wait);
+ }
+
+ /*
+ * Test for a PHYSICAL transition to low, so long as we aren't
+ * currently ignoring physical transitions (which is what "virtual
+ * carrier" indicates).
+ *
+ * The transition of the virtual carrier to low really doesn't
+ * matter... it really only means "ignore carrier state", not
+ * "make pretend that carrier is there".
+ */
+ if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) &&
+ (phys_carrier == 0))
+ {
+
+ /*
+ * When carrier drops:
+ *
+ * Drop carrier on all open units.
+ *
+ * Flush queues, waking up any task waiting in the
+ * line discipline.
+ *
+ * Send a hangup to the control terminal.
+ *
+ * Enable all select calls.
+ */
+ if (waitqueue_active(&(ch->ch_flags_wait)))
+ wake_up_interruptible(&ch->ch_flags_wait);
+
+ if (ch->ch_tun.un_open_count > 0) {
+ DPR_CARR(("Sending tty hangup\n"));
+ tty_hangup(ch->ch_tun.un_tty);
+ }
+
+ if (ch->ch_pun.un_open_count > 0) {
+ DPR_CARR(("Sending pr hangup\n"));
+ tty_hangup(ch->ch_pun.un_tty);
+ }
+ }
+
+ /*
+ * Make sure that our cached values reflect the current reality.
+ */
+ if (virt_carrier == 1)
+ ch->ch_flags |= CH_FCAR;
+ else
+ ch->ch_flags &= ~CH_FCAR;
+
+ if (phys_carrier == 1)
+ ch->ch_flags |= CH_CD;
+ else
+ ch->ch_flags &= ~CH_CD;
+}
+
+/*
+ * Assign the custom baud rate to the channel structure
+ */
+static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate)
+{
+ int testdiv;
+ int testrate_high;
+ int testrate_low;
+ int deltahigh;
+ int deltalow;
+
+ if (newrate < 0)
+ newrate = 0;
+
+ /*
+ * Since the divisor is stored in a 16-bit integer, we make sure
+ * we don't allow any rates smaller than a 16-bit integer would allow.
+ * And of course, rates above the dividend won't fly.
+ */
+ if (newrate && newrate < ((ch->ch_bd->bd_dividend / 0xFFFF) + 1))
+ newrate = ((ch->ch_bd->bd_dividend / 0xFFFF) + 1);
+
+ if (newrate && newrate > ch->ch_bd->bd_dividend)
+ newrate = ch->ch_bd->bd_dividend;
+
+ while (newrate > 0) {
+ testdiv = ch->ch_bd->bd_dividend / newrate;
+
+ /*
+ * If we try to figure out what rate the board would use
+ * with the test divisor, it will be either equal or higher
+ * than the requested baud rate. If we then determine the
+ * rate with a divisor one higher, we will get the next lower
+ * supported rate below the requested.
+ */
+ testrate_high = ch->ch_bd->bd_dividend / testdiv;
+ testrate_low = ch->ch_bd->bd_dividend / (testdiv + 1);
+
+ /*
+ * If the rate for the requested divisor is correct, just
+ * use it and be done.
+ */
+ if (testrate_high == newrate )
+ break;
+
+ /*
+ * Otherwise, pick the rate that is closer (i.e. whichever rate
+ * has a smaller delta).
+ */
+ deltahigh = testrate_high - newrate;
+ deltalow = newrate - testrate_low;
+
+ if (deltahigh < deltalow) {
+ newrate = testrate_high;
+ } else {
+ newrate = testrate_low;
+ }
+
+ break;
+ }
+
+ ch->ch_custom_speed = newrate;
+
+ return;
+}
+
+
+void dgnc_check_queue_flow_control(struct channel_t *ch)
+{
+ int qleft = 0;
+
+ /* Store how much space we have left in the queue */
+ if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0)
+ qleft += RQUEUEMASK + 1;
+
+ /*
+ * Check to see if we should enforce flow control on our queue because
+ * the ld (or user) isn't reading data out of our queue fast enuf.
+ *
+ * NOTE: This is done based on what the current flow control of the
+ * port is set for.
+ *
+ * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
+ * This will cause the UART's FIFO to back up, and force
+ * the RTS signal to be dropped.
+ * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
+ * the other side, in hopes it will stop sending data to us.
+ * 3) NONE - Nothing we can do. We will simply drop any extra data
+ * that gets sent into us when the queue fills up.
+ */
+ if (qleft < 256) {
+ /* HWFLOW */
+ if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
+ if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
+ ch->ch_bd->bd_ops->disable_receiver(ch);
+ ch->ch_flags |= (CH_RECEIVER_OFF);
+ DPR_READ(("Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
+ qleft));
+ }
+ }
+ /* SWFLOW */
+ else if (ch->ch_c_iflag & IXOFF) {
+ if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
+ ch->ch_bd->bd_ops->send_stop_character(ch);
+ ch->ch_stops_sent++;
+ DPR_READ(("Sending stop char! Times sent: %x\n", ch->ch_stops_sent));
+ }
+ }
+ /* No FLOW */
+ else {
+ /* Empty... Can't do anything about the impending overflow... */
+ }
+ }
+
+ /*
+ * Check to see if we should unenforce flow control because
+ * ld (or user) finally read enuf data out of our queue.
+ *
+ * NOTE: This is done based on what the current flow control of the
+ * port is set for.
+ *
+ * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
+ * This will cause the UART's FIFO to raise RTS back up,
+ * which will allow the other side to start sending data again.
+ * 2) SWFLOW (IXOFF) - Send a start character to
+ * the other side, so it will start sending data to us again.
+ * 3) NONE - Do nothing. Since we didn't do anything to turn off the
+ * other side, we don't need to do anything now.
+ */
+ if (qleft > (RQUEUESIZE / 2)) {
+ /* HWFLOW */
+ if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
+ if (ch->ch_flags & CH_RECEIVER_OFF) {
+ ch->ch_bd->bd_ops->enable_receiver(ch);
+ ch->ch_flags &= ~(CH_RECEIVER_OFF);
+ DPR_READ(("Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
+ qleft));
+ }
+ }
+ /* SWFLOW */
+ else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
+ ch->ch_stops_sent = 0;
+ ch->ch_bd->bd_ops->send_start_character(ch);
+ DPR_READ(("Sending start char!\n"));
+ }
+ /* No FLOW */
+ else {
+ /* Nothing needed. */
+ }
+ }
+}
+
+
+void dgnc_wakeup_writes(struct channel_t *ch)
+{
+ int qlen = 0;
+ ulong lock_flags;
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * If channel now has space, wake up anyone waiting on the condition.
+ */
+ if ((qlen = ch->ch_w_head - ch->ch_w_tail) < 0)
+ qlen += WQUEUESIZE;
+
+ if (qlen >= (WQUEUESIZE - 256)) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ if (ch->ch_tun.un_flags & UN_ISOPEN) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+ if ((ch->ch_tun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ ch->ch_tun.un_tty->ldisc->ops->write_wakeup)
+ {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty);
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ }
+#else
+ if ((ch->ch_tun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ ch->ch_tun.un_tty->ldisc.ops->write_wakeup)
+ {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ (ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty);
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ }
+#endif
+
+ wake_up_interruptible(&ch->ch_tun.un_tty->write_wait);
+
+ /*
+ * If unit is set to wait until empty, check to make sure
+ * the queue AND FIFO are both empty.
+ */
+ if (ch->ch_tun.un_flags & UN_EMPTY) {
+ if ((qlen == 0) && (ch->ch_bd->bd_ops->get_uart_bytes_left(ch) == 0)) {
+ ch->ch_tun.un_flags &= ~(UN_EMPTY);
+
+ /*
+ * If RTS Toggle mode is on, whenever
+ * the queue and UART is empty, keep RTS low.
+ */
+ if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
+ ch->ch_mostat &= ~(UART_MCR_RTS);
+ ch->ch_bd->bd_ops->assert_modem_signals(ch);
+ }
+
+ /*
+ * If DTR Toggle mode is on, whenever
+ * the queue and UART is empty, keep DTR low.
+ */
+ if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
+ ch->ch_mostat &= ~(UART_MCR_DTR);
+ ch->ch_bd->bd_ops->assert_modem_signals(ch);
+ }
+ }
+ }
+
+ wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+ }
+
+ if (ch->ch_pun.un_flags & UN_ISOPEN) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+ if ((ch->ch_pun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ ch->ch_pun.un_tty->ldisc->ops->write_wakeup)
+ {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty);
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ }
+#else
+ if ((ch->ch_pun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ ch->ch_pun.un_tty->ldisc.ops->write_wakeup)
+ {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ (ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty);
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ }
+#endif
+
+ wake_up_interruptible(&ch->ch_pun.un_tty->write_wait);
+
+ /*
+ * If unit is set to wait until empty, check to make sure
+ * the queue AND FIFO are both empty.
+ */
+ if (ch->ch_pun.un_flags & UN_EMPTY) {
+ if ((qlen == 0) && (ch->ch_bd->bd_ops->get_uart_bytes_left(ch) == 0)) {
+ ch->ch_pun.un_flags &= ~(UN_EMPTY);
+ }
+ }
+
+ wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+ }
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+
+/************************************************************************
+ *
+ * TTY Entry points and helper functions
+ *
+ ************************************************************************/
+
+/*
+ * dgnc_tty_open()
+ *
+ */
+static int dgnc_tty_open(struct tty_struct *tty, struct file *file)
+{
+ struct board_t *brd;
+ struct channel_t *ch;
+ struct un_t *un;
+ uint major = 0;
+ uint minor = 0;
+ int rc = 0;
+ ulong lock_flags;
+
+ rc = 0;
+
+ major = MAJOR(tty_devnum(tty));
+ minor = MINOR(tty_devnum(tty));
+
+ if (major > 255) {
+ return -ENXIO;
+ }
+
+ /* Get board pointer from our array of majors we have allocated */
+ brd = dgnc_BoardsByMajor[major];
+ if (!brd) {
+ return -ENXIO;
+ }
+
+ /*
+ * If board is not yet up to a state of READY, go to
+ * sleep waiting for it to happen or they cancel the open.
+ */
+ rc = wait_event_interruptible(brd->state_wait,
+ (brd->state & BOARD_READY));
+
+ if (rc) {
+ return rc;
+ }
+
+ DGNC_LOCK(brd->bd_lock, lock_flags);
+
+ /* If opened device is greater than our number of ports, bail. */
+ if (PORT_NUM(minor) > brd->nasync) {
+ DGNC_UNLOCK(brd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ ch = brd->channels[PORT_NUM(minor)];
+ if (!ch) {
+ DGNC_UNLOCK(brd->bd_lock, lock_flags);
+ return -ENXIO;
+ }
+
+ /* Drop board lock */
+ DGNC_UNLOCK(brd->bd_lock, lock_flags);
+
+ /* Grab channel lock */
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /* Figure out our type */
+ if (!IS_PRINT(minor)) {
+ un = &brd->channels[PORT_NUM(minor)]->ch_tun;
+ un->un_type = DGNC_SERIAL;
+ }
+ else if (IS_PRINT(minor)) {
+ un = &brd->channels[PORT_NUM(minor)]->ch_pun;
+ un->un_type = DGNC_PRINT;
+ }
+ else {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ DPR_OPEN(("%d Unknown TYPE!\n", __LINE__));
+ return -ENXIO;
+ }
+
+ /*
+ * If the port is still in a previous open, and in a state
+ * where we simply cannot safely keep going, wait until the
+ * state clears.
+ */
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ rc = wait_event_interruptible(ch->ch_flags_wait, ((ch->ch_flags & CH_OPENING) == 0));
+
+ /* If ret is non-zero, user ctrl-c'ed us */
+ if (rc) {
+ DPR_OPEN(("%d User ctrl c'ed\n", __LINE__));
+ return -EINTR;
+ }
+
+ /*
+ * If either unit is in the middle of the fragile part of close,
+ * we just cannot touch the channel safely.
+ * Go to sleep, knowing that when the channel can be
+ * touched safely, the close routine will signal the
+ * ch_flags_wait to wake us back up.
+ */
+ rc = wait_event_interruptible(ch->ch_flags_wait,
+ (((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_CLOSING) == 0));
+
+ /* If ret is non-zero, user ctrl-c'ed us */
+ if (rc) {
+ DPR_OPEN(("%d User ctrl c'ed\n", __LINE__));
+ return -EINTR;
+ }
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+
+ /* Store our unit into driver_data, so we always have it available. */
+ tty->driver_data = un;
+
+ DPR_OPEN(("Open called. MAJOR: %d MINOR:%d PORT_NUM: %x unit: %p NAME: %s\n",
+ MAJOR(tty_devnum(tty)), MINOR(tty_devnum(tty)), PORT_NUM(minor), un, brd->name));
+
+ DPR_OPEN(("%d: tflag=%x pflag=%x\n", __LINE__, ch->ch_tun.un_flags, ch->ch_pun.un_flags));
+
+ /*
+ * Initialize tty's
+ */
+ if (!(un->un_flags & UN_ISOPEN)) {
+ /* Store important variables. */
+ un->un_tty = tty;
+
+ /* Maybe do something here to the TTY struct as well? */
+ }
+
+
+ /*
+ * Allocate channel buffers for read/write/error.
+ * Set flag, so we don't get trounced on.
+ */
+ ch->ch_flags |= (CH_OPENING);
+
+ /* Drop locks, as malloc with GFP_KERNEL can sleep */
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ if (!ch->ch_rqueue)
+ ch->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
+ if (!ch->ch_equeue)
+ ch->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
+ if (!ch->ch_wqueue)
+ ch->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_flags &= ~(CH_OPENING);
+ wake_up_interruptible(&ch->ch_flags_wait);
+
+ /*
+ * Initialize if neither terminal or printer is open.
+ */
+ if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) {
+
+ DPR_OPEN(("dgnc_open: initializing channel in open...\n"));
+
+ /*
+ * Flush input queues.
+ */
+ ch->ch_r_head = ch->ch_r_tail = 0;
+ ch->ch_e_head = ch->ch_e_tail = 0;
+ ch->ch_w_head = ch->ch_w_tail = 0;
+
+ brd->bd_ops->flush_uart_write(ch);
+ brd->bd_ops->flush_uart_read(ch);
+
+ ch->ch_flags = 0;
+ ch->ch_cached_lsr = 0;
+ ch->ch_stop_sending_break = 0;
+ ch->ch_stops_sent = 0;
+
+ ch->ch_c_cflag = tty->termios.c_cflag;
+ ch->ch_c_iflag = tty->termios.c_iflag;
+ ch->ch_c_oflag = tty->termios.c_oflag;
+ ch->ch_c_lflag = tty->termios.c_lflag;
+ ch->ch_startc = tty->termios.c_cc[VSTART];
+ ch->ch_stopc = tty->termios.c_cc[VSTOP];
+
+ /*
+ * Bring up RTS and DTR...
+ * Also handle RTS or DTR toggle if set.
+ */
+ if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_RTS);
+ if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_DTR);
+
+ /* Tell UART to init itself */
+ brd->bd_ops->uart_init(ch);
+ }
+
+ /*
+ * Run param in case we changed anything
+ */
+ brd->bd_ops->param(tty);
+
+ dgnc_carrier(ch);
+
+ /*
+ * follow protocol for opening port
+ */
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ rc = dgnc_block_til_ready(tty, file, ch);
+
+ if (rc) {
+ DPR_OPEN(("dgnc_tty_open returning after dgnc_block_til_ready "
+ "with %d\n", rc));
+ }
+
+ /* No going back now, increment our unit and channel counters */
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_open_count++;
+ un->un_open_count++;
+ un->un_flags |= (UN_ISOPEN);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_OPEN(("dgnc_tty_open finished\n"));
+ return (rc);
+}
+
+
+/*
+ * dgnc_block_til_ready()
+ *
+ * Wait for DCD, if needed.
+ */
+static int dgnc_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch)
+{
+ int retval = 0;
+ struct un_t *un = NULL;
+ ulong lock_flags;
+ uint old_flags = 0;
+ int sleep_on_un_flags = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC || !file || !ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+ return (-ENXIO);
+ }
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC) {
+ return (-ENXIO);
+ }
+
+ DPR_OPEN(("dgnc_block_til_ready - before block.\n"));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_wopen++;
+
+ /* Loop forever */
+ while (1) {
+
+ sleep_on_un_flags = 0;
+
+ /*
+ * If board has failed somehow during our sleep, bail with error.
+ */
+ if (ch->ch_bd->state == BOARD_FAILED) {
+ retval = -ENXIO;
+ break;
+ }
+
+ /* If tty was hung up, break out of loop and set error. */
+ if (tty_hung_up_p(file)) {
+ retval = -EAGAIN;
+ break;
+ }
+
+ /*
+ * If either unit is in the middle of the fragile part of close,
+ * we just cannot touch the channel safely.
+ * Go back to sleep, knowing that when the channel can be
+ * touched safely, the close routine will signal the
+ * ch_wait_flags to wake us back up.
+ */
+ if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_CLOSING)) {
+
+ /*
+ * Our conditions to leave cleanly and happily:
+ * 1) NONBLOCKING on the tty is set.
+ * 2) CLOCAL is set.
+ * 3) DCD (fake or real) is active.
+ */
+
+ if (file->f_flags & O_NONBLOCK) {
+ break;
+ }
+
+ if (tty->flags & (1 << TTY_IO_ERROR)) {
+ retval = -EIO;
+ break;
+ }
+
+ if (ch->ch_flags & CH_CD) {
+ DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags));
+ break;
+ }
+
+ if (ch->ch_flags & CH_FCAR) {
+ DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags));
+ break;
+ }
+ }
+ else {
+ sleep_on_un_flags = 1;
+ }
+
+ /*
+ * If there is a signal pending, the user probably
+ * interrupted (ctrl-c) us.
+ * Leave loop with error set.
+ */
+ if (signal_pending(current)) {
+ DPR_OPEN(("%d: signal pending...\n", __LINE__));
+ retval = -ERESTARTSYS;
+ break;
+ }
+
+ DPR_OPEN(("dgnc_block_til_ready - blocking.\n"));
+
+ /*
+ * Store the flags before we let go of channel lock
+ */
+ if (sleep_on_un_flags)
+ old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags;
+ else
+ old_flags = ch->ch_flags;
+
+ /*
+ * Let go of channel lock before calling schedule.
+ * Our poller will get any FEP events and wake us up when DCD
+ * eventually goes active.
+ */
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_OPEN(("Going to sleep on %s flags...\n",
+ (sleep_on_un_flags ? "un" : "ch")));
+
+ /*
+ * Wait for something in the flags to change from the current value.
+ */
+ if (sleep_on_un_flags) {
+ retval = wait_event_interruptible(un->un_flags_wait,
+ (old_flags != (ch->ch_tun.un_flags | ch->ch_pun.un_flags)));
+ }
+ else {
+ retval = wait_event_interruptible(ch->ch_flags_wait,
+ (old_flags != ch->ch_flags));
+ }
+
+ DPR_OPEN(("After sleep... retval: %x\n", retval));
+
+ /*
+ * We got woken up for some reason.
+ * Before looping around, grab our channel lock.
+ */
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ }
+
+ ch->ch_wopen--;
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_OPEN(("dgnc_block_til_ready - after blocking.\n"));
+
+ if (retval) {
+ DPR_OPEN(("dgnc_block_til_ready - done. error. retval: %x\n", retval));
+ return(retval);
+ }
+
+ DPR_OPEN(("dgnc_block_til_ready - done no error. jiffies: %lu\n", jiffies));
+
+ return(0);
+}
+
+
+/*
+ * dgnc_tty_hangup()
+ *
+ * Hangup the port. Like a close, but don't wait for output to drain.
+ */
+static void dgnc_tty_hangup(struct tty_struct *tty)
+{
+ struct un_t *un;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ DPR_CLOSE(("dgnc_hangup called. ch->ch_open_count: %d un->un_open_count: %d\n",
+ un->un_ch->ch_open_count, un->un_open_count));
+
+ /* flush the transmit queues */
+ dgnc_tty_flush_buffer(tty);
+
+ DPR_CLOSE(("dgnc_hangup finished. ch->ch_open_count: %d un->un_open_count: %d\n",
+ un->un_ch->ch_open_count, un->un_open_count));
+}
+
+
+/*
+ * dgnc_tty_close()
+ *
+ */
+static void dgnc_tty_close(struct tty_struct *tty, struct file *file)
+{
+ struct ktermios *ts;
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+ int rc = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ ts = &tty->termios;
+
+ DPR_CLOSE(("Close called\n"));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * Determine if this is the last close or not - and if we agree about
+ * which type of close it is with the Line Discipline
+ */
+ if ((tty->count == 1) && (un->un_open_count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. un_open_count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ APR(("tty->count is 1, un open count is %d\n", un->un_open_count));
+ un->un_open_count = 1;
+ }
+
+ if (--un->un_open_count < 0) {
+ APR(("bad serial port open count of %d\n", un->un_open_count));
+ un->un_open_count = 0;
+ }
+
+ ch->ch_open_count--;
+
+ if (ch->ch_open_count && un->un_open_count) {
+ DPR_CLOSE(("dgnc_tty_close: not last close ch: %d un:%d\n",
+ ch->ch_open_count, un->un_open_count));
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return;
+ }
+
+ /* OK, its the last close on the unit */
+ DPR_CLOSE(("dgnc_tty_close - last close on unit procedures\n"));
+
+ un->un_flags |= UN_CLOSING;
+
+ tty->closing = 1;
+
+
+ /*
+ * Only officially close channel if count is 0 and
+ * DIGI_PRINTER bit is not set.
+ */
+ if ((ch->ch_open_count == 0) && !(ch->ch_digi.digi_flags & DIGI_PRINTER)) {
+
+ ch->ch_flags &= ~(CH_STOPI | CH_FORCED_STOPI);
+
+ /*
+ * turn off print device when closing print device.
+ */
+ if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON) ) {
+ dgnc_wmove(ch, ch->ch_digi.digi_offstr,
+ (int) ch->ch_digi.digi_offlen);
+ ch->ch_flags &= ~CH_PRON;
+ }
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ /* wait for output to drain */
+ /* This will also return if we take an interrupt */
+
+ DPR_CLOSE(("Calling wait_for_drain\n"));
+ rc = bd->bd_ops->drain(tty, 0);
+
+ DPR_CLOSE(("After calling wait_for_drain\n"));
+
+ if (rc) {
+ DPR_BASIC(("dgnc_tty_close - bad return: %d ", rc));
+ }
+
+ dgnc_tty_flush_buffer(tty);
+ tty_ldisc_flush(tty);
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ tty->closing = 0;
+
+ /*
+ * If we have HUPCL set, lower DTR and RTS
+ */
+ if (ch->ch_c_cflag & HUPCL) {
+ DPR_CLOSE(("Close. HUPCL set, dropping DTR/RTS\n"));
+
+ /* Drop RTS/DTR */
+ ch->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
+ bd->bd_ops->assert_modem_signals(ch);
+
+ /*
+ * Go to sleep to ensure RTS/DTR
+ * have been dropped for modems to see it.
+ */
+ if (ch->ch_close_delay) {
+ DPR_CLOSE(("Close. Sleeping for RTS/DTR drop\n"));
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ dgnc_ms_sleep(ch->ch_close_delay);
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ DPR_CLOSE(("Close. After sleeping for RTS/DTR drop\n"));
+ }
+ }
+
+ ch->ch_old_baud = 0;
+
+ /* Turn off UART interrupts for this port */
+ ch->ch_bd->bd_ops->uart_off(ch);
+ }
+ else {
+ /*
+ * turn off print device when closing print device.
+ */
+ if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON) ) {
+ dgnc_wmove(ch, ch->ch_digi.digi_offstr,
+ (int) ch->ch_digi.digi_offlen);
+ ch->ch_flags &= ~CH_PRON;
+ }
+ }
+
+ un->un_tty = NULL;
+ un->un_flags &= ~(UN_ISOPEN | UN_CLOSING);
+
+ DPR_CLOSE(("Close. Doing wakeups\n"));
+ wake_up_interruptible(&ch->ch_flags_wait);
+ wake_up_interruptible(&un->un_flags_wait);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_BASIC(("dgnc_tty_close - complete\n"));
+}
+
+
+/*
+ * dgnc_tty_chars_in_buffer()
+ *
+ * Return number of characters that have not been transmitted yet.
+ *
+ * This routine is used by the line discipline to determine if there
+ * is data waiting to be transmitted/drained/flushed or not.
+ */
+static int dgnc_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+ ushort thead;
+ ushort ttail;
+ uint tmask;
+ uint chars = 0;
+ ulong lock_flags = 0;
+
+ if (tty == NULL)
+ return(0);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ tmask = WQUEUEMASK;
+ thead = ch->ch_w_head & tmask;
+ ttail = ch->ch_w_tail & tmask;
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ if (ttail == thead) {
+ chars = 0;
+ } else {
+ if (thead >= ttail)
+ chars = thead - ttail;
+ else
+ chars = thead - ttail + WQUEUESIZE;
+ }
+
+ DPR_WRITE(("dgnc_tty_chars_in_buffer. Port: %x - %d (head: %d tail: %d)\n",
+ ch->ch_portnum, chars, thead, ttail));
+
+ return(chars);
+}
+
+
+/*
+ * dgnc_maxcps_room
+ *
+ * Reduces bytes_available to the max number of characters
+ * that can be sent currently given the maxcps value, and
+ * returns the new bytes_available. This only affects printer
+ * output.
+ */
+static int dgnc_maxcps_room(struct tty_struct *tty, int bytes_available)
+{
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+
+ if (!tty)
+ return (bytes_available);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (bytes_available);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (bytes_available);
+
+ /*
+ * If its not the Transparent print device, return
+ * the full data amount.
+ */
+ if (un->un_type != DGNC_PRINT)
+ return (bytes_available);
+
+ if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0 ) {
+ int cps_limit = 0;
+ unsigned long current_time = jiffies;
+ unsigned long buffer_time = current_time +
+ (HZ * ch->ch_digi.digi_bufsize) / ch->ch_digi.digi_maxcps;
+
+ if (ch->ch_cpstime < current_time) {
+ /* buffer is empty */
+ ch->ch_cpstime = current_time; /* reset ch_cpstime */
+ cps_limit = ch->ch_digi.digi_bufsize;
+ }
+ else if (ch->ch_cpstime < buffer_time) {
+ /* still room in the buffer */
+ cps_limit = ((buffer_time - ch->ch_cpstime) * ch->ch_digi.digi_maxcps) / HZ;
+ }
+ else {
+ /* no room in the buffer */
+ cps_limit = 0;
+ }
+
+ bytes_available = min(cps_limit, bytes_available);
+ }
+
+ return (bytes_available);
+}
+
+
+/*
+ * dgnc_tty_write_room()
+ *
+ * Return space available in Tx buffer
+ */
+static int dgnc_tty_write_room(struct tty_struct *tty)
+{
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+ ushort head;
+ ushort tail;
+ ushort tmask;
+ int ret = 0;
+ ulong lock_flags = 0;
+
+ if (tty == NULL || dgnc_TmpWriteBuf == NULL)
+ return(0);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (0);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (0);
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ tmask = WQUEUEMASK;
+ head = (ch->ch_w_head) & tmask;
+ tail = (ch->ch_w_tail) & tmask;
+
+ if ((ret = tail - head - 1) < 0)
+ ret += WQUEUESIZE;
+
+ /* Limit printer to maxcps */
+ ret = dgnc_maxcps_room(tty, ret);
+
+ /*
+ * If we are printer device, leave space for
+ * possibly both the on and off strings.
+ */
+ if (un->un_type == DGNC_PRINT) {
+ if (!(ch->ch_flags & CH_PRON))
+ ret -= ch->ch_digi.digi_onlen;
+ ret -= ch->ch_digi.digi_offlen;
+ }
+ else {
+ if (ch->ch_flags & CH_PRON)
+ ret -= ch->ch_digi.digi_offlen;
+ }
+
+ if (ret < 0)
+ ret = 0;
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_WRITE(("dgnc_tty_write_room - %d tail: %d head: %d\n", ret, tail, head));
+
+ return(ret);
+}
+
+
+/*
+ * dgnc_tty_put_char()
+ *
+ * Put a character into ch->ch_buf
+ *
+ * - used by the line discipline for OPOST processing
+ */
+static int dgnc_tty_put_char(struct tty_struct *tty, unsigned char c)
+{
+ /*
+ * Simply call tty_write.
+ */
+ DPR_WRITE(("dgnc_tty_put_char called\n"));
+ dgnc_tty_write(tty, &c, 1);
+ return 1;
+}
+
+
+/*
+ * dgnc_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+static int dgnc_tty_write(struct tty_struct *tty,
+ const unsigned char *buf, int count)
+{
+ struct channel_t *ch = NULL;
+ struct un_t *un = NULL;
+ int bufcount = 0, n = 0;
+ int orig_count = 0;
+ ulong lock_flags;
+ ushort head;
+ ushort tail;
+ ushort tmask;
+ uint remain;
+ int from_user = 0;
+
+ if (tty == NULL || dgnc_TmpWriteBuf == NULL)
+ return(0);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return(0);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return(0);
+
+ if (!count)
+ return(0);
+
+ DPR_WRITE(("dgnc_tty_write: Port: %x tty=%p user=%d len=%d\n",
+ ch->ch_portnum, tty, from_user, count));
+
+ /*
+ * Store original amount of characters passed in.
+ * This helps to figure out if we should ask the FEP
+ * to send us an event when it has more space available.
+ */
+ orig_count = count;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /* Get our space available for the channel from the board */
+ tmask = WQUEUEMASK;
+ head = (ch->ch_w_head) & tmask;
+ tail = (ch->ch_w_tail) & tmask;
+
+ if ((bufcount = tail - head - 1) < 0)
+ bufcount += WQUEUESIZE;
+
+ DPR_WRITE(("%d: bufcount: %x count: %x tail: %x head: %x tmask: %x\n",
+ __LINE__, bufcount, count, tail, head, tmask));
+
+ /*
+ * Limit printer output to maxcps overall, with bursts allowed
+ * up to bufsize characters.
+ */
+ bufcount = dgnc_maxcps_room(tty, bufcount);
+
+ /*
+ * Take minimum of what the user wants to send, and the
+ * space available in the FEP buffer.
+ */
+ count = min(count, bufcount);
+
+ /*
+ * Bail if no space left.
+ */
+ if (count <= 0) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(0);
+ }
+
+ /*
+ * Output the printer ON string, if we are in terminal mode, but
+ * need to be in printer mode.
+ */
+ if ((un->un_type == DGNC_PRINT) && !(ch->ch_flags & CH_PRON)) {
+ dgnc_wmove(ch, ch->ch_digi.digi_onstr,
+ (int) ch->ch_digi.digi_onlen);
+ head = (ch->ch_w_head) & tmask;
+ ch->ch_flags |= CH_PRON;
+ }
+
+ /*
+ * On the other hand, output the printer OFF string, if we are
+ * currently in printer mode, but need to output to the terminal.
+ */
+ if ((un->un_type != DGNC_PRINT) && (ch->ch_flags & CH_PRON)) {
+ dgnc_wmove(ch, ch->ch_digi.digi_offstr,
+ (int) ch->ch_digi.digi_offlen);
+ head = (ch->ch_w_head) & tmask;
+ ch->ch_flags &= ~CH_PRON;
+ }
+
+ /*
+ * If there is nothing left to copy, or I can't handle any more data, leave.
+ */
+ if (count <= 0) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(0);
+ }
+
+ if (from_user) {
+
+ count = min(count, WRITEBUFLEN);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * If data is coming from user space, copy it into a temporary
+ * buffer so we don't get swapped out while doing the copy to
+ * the board.
+ */
+ /* we're allowed to block if it's from_user */
+ if (down_interruptible(&dgnc_TmpWriteSem)) {
+ return (-EINTR);
+ }
+
+ /*
+ * copy_from_user() returns the number
+ * of bytes that could *NOT* be copied.
+ */
+ count -= copy_from_user(dgnc_TmpWriteBuf, (const uchar __user *) buf, count);
+
+ if (!count) {
+ up(&dgnc_TmpWriteSem);
+ return(-EFAULT);
+ }
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ buf = dgnc_TmpWriteBuf;
+
+ }
+
+ n = count;
+
+ /*
+ * If the write wraps over the top of the circular buffer,
+ * move the portion up to the wrap point, and reset the
+ * pointers to the bottom.
+ */
+ remain = WQUEUESIZE - head;
+
+ if (n >= remain) {
+ n -= remain;
+ memcpy(ch->ch_wqueue + head, buf, remain);
+ dgnc_sniff_nowait_nolock(ch, "USER WRITE", ch->ch_wqueue + head, remain);
+ head = 0;
+ buf += remain;
+ }
+
+ if (n > 0) {
+ /*
+ * Move rest of data.
+ */
+ remain = n;
+ memcpy(ch->ch_wqueue + head, buf, remain);
+ dgnc_sniff_nowait_nolock(ch, "USER WRITE", ch->ch_wqueue + head, remain);
+ head += remain;
+ }
+
+ if (count) {
+ head &= tmask;
+ ch->ch_w_head = head;
+ }
+
+#if 0
+ /*
+ * If this is the print device, and the
+ * printer is still on, we need to turn it
+ * off before going idle.
+ */
+ if (count == orig_count) {
+ if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON)) {
+ head &= tmask;
+ ch->ch_w_head = head;
+ dgnc_wmove(ch, ch->ch_digi.digi_offstr,
+ (int) ch->ch_digi.digi_offlen);
+ head = (ch->ch_w_head) & tmask;
+ ch->ch_flags &= ~CH_PRON;
+ }
+ }
+#endif
+
+ /* Update printer buffer empty time. */
+ if ((un->un_type == DGNC_PRINT) && (ch->ch_digi.digi_maxcps > 0)
+ && (ch->ch_digi.digi_bufsize > 0)) {
+ ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps;
+ }
+
+ if (from_user) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ up(&dgnc_TmpWriteSem);
+ } else {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ }
+
+ DPR_WRITE(("Write finished - Write %d bytes of %d.\n", count, orig_count));
+
+ if (count) {
+ /*
+ * Channel lock is grabbed and then released
+ * inside this routine.
+ */
+ ch->ch_bd->bd_ops->copy_data_from_queue_to_uart(ch);
+ }
+
+ return (count);
+}
+
+
+/*
+ * Return modem signals to ld.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgnc_tty_tiocmget(struct tty_struct *tty)
+#else
+static int dgnc_tty_tiocmget(struct tty_struct *tty, struct file *file)
+#endif
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ int result = -EIO;
+ uchar mstat = 0;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return result;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return result;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return result;
+
+ DPR_IOCTL(("dgnc_tty_tiocmget start\n"));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ mstat = (ch->ch_mostat | ch->ch_mistat);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ result = 0;
+
+ if (mstat & UART_MCR_DTR)
+ result |= TIOCM_DTR;
+ if (mstat & UART_MCR_RTS)
+ result |= TIOCM_RTS;
+ if (mstat & UART_MSR_CTS)
+ result |= TIOCM_CTS;
+ if (mstat & UART_MSR_DSR)
+ result |= TIOCM_DSR;
+ if (mstat & UART_MSR_RI)
+ result |= TIOCM_RI;
+ if (mstat & UART_MSR_DCD)
+ result |= TIOCM_CD;
+
+ DPR_IOCTL(("dgnc_tty_tiocmget finish\n"));
+
+ return result;
+}
+
+
+/*
+ * dgnc_tty_tiocmset()
+ *
+ * Set modem signals, called by ld.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgnc_tty_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+#else
+static int dgnc_tty_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+#endif
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int ret = -EIO;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return ret;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return ret;
+
+ DPR_IOCTL(("dgnc_tty_tiocmset start\n"));
+
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ if (set & TIOCM_RTS) {
+ ch->ch_mostat |= UART_MCR_RTS;
+ }
+
+ if (set & TIOCM_DTR) {
+ ch->ch_mostat |= UART_MCR_DTR;
+ }
+
+ if (clear & TIOCM_RTS) {
+ ch->ch_mostat &= ~(UART_MCR_RTS);
+ }
+
+ if (clear & TIOCM_DTR) {
+ ch->ch_mostat &= ~(UART_MCR_DTR);
+ }
+
+ ch->ch_bd->bd_ops->assert_modem_signals(ch);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_tiocmset finish\n"));
+
+ return (0);
+}
+
+
+/*
+ * dgnc_tty_send_break()
+ *
+ * Send a Break, called by ld.
+ */
+static int dgnc_tty_send_break(struct tty_struct *tty, int msec)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int ret = -EIO;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return ret;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return ret;
+
+ switch (msec) {
+ case -1:
+ msec = 0xFFFF;
+ break;
+ case 0:
+ msec = 0;
+ break;
+ default:
+ break;
+ }
+
+ DPR_IOCTL(("dgnc_tty_send_break start 1. %lx\n", jiffies));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_bd->bd_ops->send_break(ch, msec);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_send_break finish\n"));
+
+ return (0);
+
+}
+
+
+/*
+ * dgnc_tty_wait_until_sent()
+ *
+ * wait until data has been transmitted, called by ld.
+ */
+static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int rc;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ rc = bd->bd_ops->drain(tty, 0);
+ if (rc) {
+ DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+ return;
+ }
+ return;
+}
+
+
+/*
+ * dgnc_send_xchar()
+ *
+ * send a high priority character, called by ld.
+ */
+static void dgnc_tty_send_xchar(struct tty_struct *tty, char c)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgnc_tty_send_xchar start\n"));
+ printk("dgnc_tty_send_xchar start\n");
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ bd->bd_ops->send_immediate_char(ch, c);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_send_xchar finish\n"));
+ printk("dgnc_tty_send_xchar finish\n");
+ return;
+}
+
+
+
+
+/*
+ * Return modem signals to ld.
+ */
+static inline int dgnc_get_mstat(struct channel_t *ch)
+{
+ unsigned char mstat;
+ int result = -EIO;
+ ulong lock_flags;
+
+ DPR_IOCTL(("dgnc_getmstat start\n"));
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return(-ENXIO);
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ mstat = (ch->ch_mostat | ch->ch_mistat);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ result = 0;
+
+ if (mstat & UART_MCR_DTR)
+ result |= TIOCM_DTR;
+ if (mstat & UART_MCR_RTS)
+ result |= TIOCM_RTS;
+ if (mstat & UART_MSR_CTS)
+ result |= TIOCM_CTS;
+ if (mstat & UART_MSR_DSR)
+ result |= TIOCM_DSR;
+ if (mstat & UART_MSR_RI)
+ result |= TIOCM_RI;
+ if (mstat & UART_MSR_DCD)
+ result |= TIOCM_CD;
+
+ DPR_IOCTL(("dgnc_getmstat finish\n"));
+
+ return(result);
+}
+
+
+
+/*
+ * Return modem signals to ld.
+ */
+static int dgnc_get_modem_info(struct channel_t *ch, unsigned int __user *value)
+{
+ int result;
+ int rc;
+
+ DPR_IOCTL(("dgnc_get_modem_info start\n"));
+
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return(-ENXIO);
+
+ result = dgnc_get_mstat(ch);
+
+ if (result < 0)
+ return (-ENXIO);
+
+ rc = put_user(result, value);
+
+ DPR_IOCTL(("dgnc_get_modem_info finish\n"));
+ return(rc);
+}
+
+
+/*
+ * dgnc_set_modem_info()
+ *
+ * Set modem signals, called by ld.
+ */
+static int dgnc_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int ret = -ENXIO;
+ unsigned int arg = 0;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return ret;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return ret;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return ret;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return ret;
+
+ ret = 0;
+
+ DPR_IOCTL(("dgnc_set_modem_info() start\n"));
+
+ ret = get_user(arg, value);
+ if (ret)
+ return(ret);
+
+ switch (command) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS) {
+ ch->ch_mostat |= UART_MCR_RTS;
+ }
+
+ if (arg & TIOCM_DTR) {
+ ch->ch_mostat |= UART_MCR_DTR;
+ }
+
+ break;
+
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS) {
+ ch->ch_mostat &= ~(UART_MCR_RTS);
+ }
+
+ if (arg & TIOCM_DTR) {
+ ch->ch_mostat &= ~(UART_MCR_DTR);
+ }
+
+ break;
+
+ case TIOCMSET:
+
+ if (arg & TIOCM_RTS) {
+ ch->ch_mostat |= UART_MCR_RTS;
+ }
+ else {
+ ch->ch_mostat &= ~(UART_MCR_RTS);
+ }
+
+ if (arg & TIOCM_DTR) {
+ ch->ch_mostat |= UART_MCR_DTR;
+ }
+ else {
+ ch->ch_mostat &= ~(UART_MCR_DTR);
+ }
+
+ break;
+
+ default:
+ return(-EINVAL);
+ }
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_bd->bd_ops->assert_modem_signals(ch);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_set_modem_info finish\n"));
+
+ return (0);
+}
+
+
+/*
+ * dgnc_tty_digigeta()
+ *
+ * Ioctl to get the information for ditty.
+ *
+ *
+ *
+ */
+static int dgnc_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ struct digi_t tmp;
+ ulong lock_flags;
+
+ if (!retinfo)
+ return (-EFAULT);
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return (-EFAULT);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (-EFAULT);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (-EFAULT);
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ memcpy(&tmp, &ch->ch_digi, sizeof(tmp));
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return (-EFAULT);
+
+ return (0);
+}
+
+
+/*
+ * dgnc_tty_digiseta()
+ *
+ * Ioctl to set the information for ditty.
+ *
+ *
+ *
+ */
+static int dgnc_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ struct digi_t new_digi;
+ ulong lock_flags;
+
+ DPR_IOCTL(("DIGI_SETA start\n"));
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return (-EFAULT);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (-EFAULT);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (-EFAULT);
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (-EFAULT);
+
+ if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t))) {
+ DPR_IOCTL(("DIGI_SETA failed copy_from_user\n"));
+ return(-EFAULT);
+ }
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * Handle transistions to and from RTS Toggle.
+ */
+ if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) && (new_digi.digi_flags & DIGI_RTS_TOGGLE))
+ ch->ch_mostat &= ~(UART_MCR_RTS);
+ if ((ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) && !(new_digi.digi_flags & DIGI_RTS_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_RTS);
+
+ /*
+ * Handle transistions to and from DTR Toggle.
+ */
+ if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) && (new_digi.digi_flags & DIGI_DTR_TOGGLE))
+ ch->ch_mostat &= ~(UART_MCR_DTR);
+ if ((ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) && !(new_digi.digi_flags & DIGI_DTR_TOGGLE))
+ ch->ch_mostat |= (UART_MCR_DTR);
+
+ memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t));
+
+ if (ch->ch_digi.digi_maxcps < 1)
+ ch->ch_digi.digi_maxcps = 1;
+
+ if (ch->ch_digi.digi_maxcps > 10000)
+ ch->ch_digi.digi_maxcps = 10000;
+
+ if (ch->ch_digi.digi_bufsize < 10)
+ ch->ch_digi.digi_bufsize = 10;
+
+ if (ch->ch_digi.digi_maxchar < 1)
+ ch->ch_digi.digi_maxchar = 1;
+
+ if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize)
+ ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize;
+
+ if (ch->ch_digi.digi_onlen > DIGI_PLEN)
+ ch->ch_digi.digi_onlen = DIGI_PLEN;
+
+ if (ch->ch_digi.digi_offlen > DIGI_PLEN)
+ ch->ch_digi.digi_offlen = DIGI_PLEN;
+
+ ch->ch_bd->bd_ops->param(tty);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("DIGI_SETA finish\n"));
+
+ return(0);
+}
+
+
+/*
+ * dgnc_set_termios()
+ */
+static void dgnc_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ unsigned long lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_c_cflag = tty->termios.c_cflag;
+ ch->ch_c_iflag = tty->termios.c_iflag;
+ ch->ch_c_oflag = tty->termios.c_oflag;
+ ch->ch_c_lflag = tty->termios.c_lflag;
+ ch->ch_startc = tty->termios.c_cc[VSTART];
+ ch->ch_stopc = tty->termios.c_cc[VSTOP];
+
+ ch->ch_bd->bd_ops->param(tty);
+ dgnc_carrier(ch);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+static void dgnc_tty_throttle(struct tty_struct *tty)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags = 0;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgnc_tty_throttle start\n"));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_flags |= (CH_FORCED_STOPI);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_throttle finish\n"));
+}
+
+
+static void dgnc_tty_unthrottle(struct tty_struct *tty)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgnc_tty_unthrottle start\n"));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_flags &= ~(CH_FORCED_STOPI);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_unthrottle finish\n"));
+}
+
+
+static void dgnc_tty_start(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgcn_tty_start start\n"));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_flags &= ~(CH_FORCED_STOP);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_start finish\n"));
+}
+
+
+static void dgnc_tty_stop(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgnc_tty_stop start\n"));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_flags |= (CH_FORCED_STOP);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_stop finish\n"));
+}
+
+
+/*
+ * dgnc_tty_flush_chars()
+ *
+ * Flush the cook buffer
+ *
+ * Note to self, and any other poor souls who venture here:
+ *
+ * flush in this case DOES NOT mean dispose of the data.
+ * instead, it means "stop buffering and send it if you
+ * haven't already." Just guess how I figured that out... SRW 2-Jun-98
+ *
+ * It is also always called in interrupt context - JAR 8-Sept-99
+ */
+static void dgnc_tty_flush_chars(struct tty_struct *tty)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgnc_tty_flush_chars start\n"));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /* Do something maybe here */
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_flush_chars finish\n"));
+}
+
+
+
+/*
+ * dgnc_tty_flush_buffer()
+ *
+ * Flush Tx buffer (make in == out)
+ */
+static void dgnc_tty_flush_buffer(struct tty_struct *tty)
+{
+ struct channel_t *ch;
+ struct un_t *un;
+ ulong lock_flags;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return;
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return;
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return;
+
+ DPR_IOCTL(("dgnc_tty_flush_buffer on port: %d start\n", ch->ch_portnum));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_flags &= ~CH_STOP;
+
+ /* Flush our write queue */
+ ch->ch_w_head = ch->ch_w_tail;
+
+ /* Flush UARTs transmit FIFO */
+ ch->ch_bd->bd_ops->flush_uart_write(ch);
+
+ if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+ }
+ if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+ }
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_flush_buffer finish\n"));
+}
+
+
+
+/*****************************************************************************
+ *
+ * The IOCTL function and all of its helpers
+ *
+ *****************************************************************************/
+
+/*
+ * dgnc_tty_ioctl()
+ *
+ * The usual assortment of ioctl's
+ */
+static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
+ unsigned long arg)
+{
+ struct board_t *bd;
+ struct channel_t *ch;
+ struct un_t *un;
+ int rc;
+ ulong lock_flags;
+ void __user *uarg = (void __user *) arg;
+
+ if (!tty || tty->magic != TTY_MAGIC)
+ return (-ENODEV);
+
+ un = tty->driver_data;
+ if (!un || un->magic != DGNC_UNIT_MAGIC)
+ return (-ENODEV);
+
+ ch = un->un_ch;
+ if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+ return (-ENODEV);
+
+ bd = ch->ch_bd;
+ if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+ return (-ENODEV);
+
+ DPR_IOCTL(("dgnc_tty_ioctl start on port %d - cmd %s (%x), arg %lx\n",
+ ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg));
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ if (un->un_open_count <= 0) {
+ DPR_BASIC(("dgnc_tty_ioctl - unit not open.\n"));
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(-EIO);
+ }
+
+ switch (cmd) {
+
+ /* Here are all the standard ioctl's that we MUST implement */
+
+ case TCSBRK:
+ /*
+ * TCSBRK is SVID version: non-zero arg --> no break
+ * this behaviour is exploited by tcdrain().
+ *
+ * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+ * between 0.25 and 0.5 seconds so we'll ask for something
+ * in the middle: 0.375 seconds.
+ */
+ rc = tty_check_change(tty);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ if (rc) {
+ return(rc);
+ }
+
+ rc = ch->ch_bd->bd_ops->drain(tty, 0);
+
+ if (rc) {
+ DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ if(((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) {
+ ch->ch_bd->bd_ops->send_break(ch, 250);
+ }
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+ ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg));
+
+ return(0);
+
+
+ case TCSBRKP:
+ /* support for POSIX tcsendbreak()
+ * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+ * between 0.25 and 0.5 seconds so we'll ask for something
+ * in the middle: 0.375 seconds.
+ */
+ rc = tty_check_change(tty);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ if (rc) {
+ return(rc);
+ }
+
+ rc = ch->ch_bd->bd_ops->drain(tty, 0);
+ if (rc) {
+ DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_bd->bd_ops->send_break(ch, 250);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+ ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg));
+
+ return(0);
+
+ case TIOCSBRK:
+ rc = tty_check_change(tty);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ if (rc) {
+ return(rc);
+ }
+
+ rc = ch->ch_bd->bd_ops->drain(tty, 0);
+ if (rc) {
+ DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ ch->ch_bd->bd_ops->send_break(ch, 250);
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+ ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg));
+
+ return(0);
+
+ case TIOCCBRK:
+ /* Do Nothing */
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return 0;
+
+ case TIOCGSOFTCAR:
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg);
+ return(rc);
+
+ case TIOCSSOFTCAR:
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ rc = get_user(arg, (unsigned long __user *) arg);
+ if (rc)
+ return(rc);
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+ ch->ch_bd->bd_ops->param(tty);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ return(0);
+
+ case TIOCMGET:
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(dgnc_get_modem_info(ch, uarg));
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(dgnc_set_modem_info(tty, cmd, uarg));
+
+ /*
+ * Here are any additional ioctl's that we want to implement
+ */
+
+ case TCFLSH:
+ /*
+ * The linux tty driver doesn't have a flush
+ * input routine for the driver, assuming all backed
+ * up data is in the line disc. buffers. However,
+ * we all know that's not the case. Here, we
+ * act on the ioctl, but then lie and say we didn't
+ * so the line discipline will process the flush
+ * also.
+ */
+ rc = tty_check_change(tty);
+ if (rc) {
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(rc);
+ }
+
+ if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) {
+ ch->ch_r_head = ch->ch_r_tail;
+ ch->ch_bd->bd_ops->flush_uart_read(ch);
+ /* Force queue flow control to be released, if needed */
+ dgnc_check_queue_flow_control(ch);
+ }
+
+ if ((arg == TCOFLUSH) || (arg == TCIOFLUSH)) {
+ if (!(un->un_type == DGNC_PRINT)) {
+ ch->ch_w_head = ch->ch_w_tail;
+ ch->ch_bd->bd_ops->flush_uart_write(ch);
+
+ if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+ }
+
+ if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
+ ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
+ wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+ }
+
+ }
+ }
+
+ /* pretend we didn't recognize this IOCTL */
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(-ENOIOCTLCMD);
+ case TCSETSF:
+ case TCSETSW:
+ /*
+ * The linux tty driver doesn't have a flush
+ * input routine for the driver, assuming all backed
+ * up data is in the line disc. buffers. However,
+ * we all know that's not the case. Here, we
+ * act on the ioctl, but then lie and say we didn't
+ * so the line discipline will process the flush
+ * also.
+ */
+ if (cmd == TCSETSF) {
+ /* flush rx */
+ ch->ch_flags &= ~CH_STOP;
+ ch->ch_r_head = ch->ch_r_tail;
+ ch->ch_bd->bd_ops->flush_uart_read(ch);
+ /* Force queue flow control to be released, if needed */
+ dgnc_check_queue_flow_control(ch);
+ }
+
+ /* now wait for all the output to drain */
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ rc = ch->ch_bd->bd_ops->drain(tty, 0);
+ if (rc) {
+ DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d\n", rc));
+ return(-EINTR);
+ }
+
+ DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+ ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg));
+
+ /* pretend we didn't recognize this */
+ return(-ENOIOCTLCMD);
+
+ case TCSETAW:
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ rc = ch->ch_bd->bd_ops->drain(tty, 0);
+ if (rc) {
+ DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+
+ /* pretend we didn't recognize this */
+ return(-ENOIOCTLCMD);
+
+ case TCXONC:
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ /* Make the ld do it */
+ return(-ENOIOCTLCMD);
+
+ case DIGI_GETA:
+ /* get information for ditty */
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(dgnc_tty_digigeta(tty, uarg));
+
+ case DIGI_SETAW:
+ case DIGI_SETAF:
+
+ /* set information for ditty */
+ if (cmd == (DIGI_SETAW)) {
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ rc = ch->ch_bd->bd_ops->drain(tty, 0);
+ if (rc) {
+ DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+ return(-EINTR);
+ }
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ }
+ else {
+ tty_ldisc_flush(tty);
+ }
+ /* fall thru */
+
+ case DIGI_SETA:
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(dgnc_tty_digiseta(tty, uarg));
+
+ case DIGI_LOOPBACK:
+ {
+ uint loopback = 0;
+ /* Let go of locks when accessing user space, could sleep */
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ rc = get_user(loopback, (unsigned int __user *) arg);
+ if (rc)
+ return(rc);
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /* Enable/disable internal loopback for this port */
+ if (loopback)
+ ch->ch_flags |= CH_LOOPBACK;
+ else
+ ch->ch_flags &= ~(CH_LOOPBACK);
+
+ ch->ch_bd->bd_ops->param(tty);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(0);
+ }
+
+ case DIGI_GETCUSTOMBAUD:
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ rc = put_user(ch->ch_custom_speed, (unsigned int __user *) arg);
+ return(rc);
+
+ case DIGI_SETCUSTOMBAUD:
+ {
+ uint new_rate;
+ /* Let go of locks when accessing user space, could sleep */
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ rc = get_user(new_rate, (unsigned int __user *) arg);
+ if (rc)
+ return(rc);
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ dgnc_set_custom_speed(ch, new_rate);
+ ch->ch_bd->bd_ops->param(tty);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(0);
+ }
+
+ /*
+ * This ioctl allows insertion of a character into the front
+ * of any pending data to be transmitted.
+ *
+ * This ioctl is to satify the "Send Character Immediate"
+ * call that the RealPort protocol spec requires.
+ */
+ case DIGI_REALPORT_SENDIMMEDIATE:
+ {
+ unsigned char c;
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ rc = get_user(c, (unsigned char __user *) arg);
+ if (rc)
+ return(rc);
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+ ch->ch_bd->bd_ops->send_immediate_char(ch, c);
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ return(0);
+ }
+
+ /*
+ * This ioctl returns all the current counts for the port.
+ *
+ * This ioctl is to satify the "Line Error Counters"
+ * call that the RealPort protocol spec requires.
+ */
+ case DIGI_REALPORT_GETCOUNTERS:
+ {
+ struct digi_getcounter buf;
+
+ buf.norun = ch->ch_err_overrun;
+ buf.noflow = 0; /* The driver doesn't keep this stat */
+ buf.nframe = ch->ch_err_frame;
+ buf.nparity = ch->ch_err_parity;
+ buf.nbreak = ch->ch_err_break;
+ buf.rbytes = ch->ch_rxcount;
+ buf.tbytes = ch->ch_txcount;
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ if (copy_to_user(uarg, &buf, sizeof(struct digi_getcounter))) {
+ return (-EFAULT);
+ }
+ return(0);
+ }
+
+ /*
+ * This ioctl returns all current events.
+ *
+ * This ioctl is to satify the "Event Reporting"
+ * call that the RealPort protocol spec requires.
+ */
+ case DIGI_REALPORT_GETEVENTS:
+ {
+ unsigned int events = 0;
+
+ /* NOTE: MORE EVENTS NEEDS TO BE ADDED HERE */
+ if (ch->ch_flags & CH_BREAK_SENDING)
+ events |= EV_TXB;
+ if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_FORCED_STOP)) {
+ events |= (EV_OPU | EV_OPS);
+ }
+ if ((ch->ch_flags & CH_STOPI) || (ch->ch_flags & CH_FORCED_STOPI)) {
+ events |= (EV_IPU | EV_IPS);
+ }
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+ rc = put_user(events, (unsigned int __user *) arg);
+ return(rc);
+ }
+
+ /*
+ * This ioctl returns TOUT and TIN counters based
+ * upon the values passed in by the RealPort Server.
+ * It also passes back whether the UART Transmitter is
+ * empty as well.
+ */
+ case DIGI_REALPORT_GETBUFFERS:
+ {
+ struct digi_getbuffer buf;
+ int tdist;
+ int count;
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * Get data from user first.
+ */
+ if (copy_from_user(&buf, uarg, sizeof(struct digi_getbuffer))) {
+ return (-EFAULT);
+ }
+
+ DGNC_LOCK(ch->ch_lock, lock_flags);
+
+ /*
+ * Figure out how much data is in our RX and TX queues.
+ */
+ buf.rxbuf = (ch->ch_r_head - ch->ch_r_tail) & RQUEUEMASK;
+ buf.txbuf = (ch->ch_w_head - ch->ch_w_tail) & WQUEUEMASK;
+
+ /*
+ * Is the UART empty? Add that value to whats in our TX queue.
+ */
+ count = buf.txbuf + ch->ch_bd->bd_ops->get_uart_bytes_left(ch);
+
+ /*
+ * Figure out how much data the RealPort Server believes should
+ * be in our TX queue.
+ */
+ tdist = (buf.tIn - buf.tOut) & 0xffff;
+
+ /*
+ * If we have more data than the RealPort Server believes we
+ * should have, reduce our count to its amount.
+ *
+ * This count difference CAN happen because the Linux LD can
+ * insert more characters into our queue for OPOST processing
+ * that the RealPort Server doesn't know about.
+ */
+ if (buf.txbuf > tdist) {
+ buf.txbuf = tdist;
+ }
+
+ /*
+ * Report whether our queue and UART TX are completely empty.
+ */
+ if (count) {
+ buf.txdone = 0;
+ } else {
+ buf.txdone = 1;
+ }
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ if (copy_to_user(uarg, &buf, sizeof(struct digi_getbuffer))) {
+ return (-EFAULT);
+ }
+ return(0);
+ }
+ default:
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_ioctl - in default\n"));
+ DPR_IOCTL(("dgnc_tty_ioctl end - cmd %s (%x), arg %lx\n",
+ dgnc_ioctl_name(cmd), cmd, arg));
+
+ return(-ENOIOCTLCMD);
+ }
+
+ DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+ DPR_IOCTL(("dgnc_tty_ioctl end - cmd %s (%x), arg %lx\n",
+ dgnc_ioctl_name(cmd), cmd, arg));
+
+ return(0);
+}
diff --git a/drivers/staging/dgnc/dgnc_tty.h b/drivers/staging/dgnc/dgnc_tty.h
new file mode 100644
index 00000000000..deb388d2f4c
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_tty.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGNC_TTY_H
+#define __DGNC_TTY_H
+
+#include "dgnc_driver.h"
+
+int dgnc_tty_register(struct board_t *brd);
+
+int dgnc_tty_preinit(void);
+int dgnc_tty_init(struct board_t *);
+
+void dgnc_tty_post_uninit(void);
+void dgnc_tty_uninit(struct board_t *);
+
+void dgnc_input(struct channel_t *ch);
+void dgnc_carrier(struct channel_t *ch);
+void dgnc_wakeup_writes(struct channel_t *ch);
+void dgnc_check_queue_flow_control(struct channel_t *ch);
+
+void dgnc_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int nbuf);
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_types.h b/drivers/staging/dgnc/dgnc_types.h
new file mode 100644
index 00000000000..4fa358535f8
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_types.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGNC_TYPES_H
+#define __DGNC_TYPES_H
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+/* Required for our shared headers! */
+typedef unsigned char uchar;
+
+#endif
diff --git a/drivers/staging/dgnc/digi.h b/drivers/staging/dgnc/digi.h
new file mode 100644
index 00000000000..eb6e3712572
--- /dev/null
+++ b/drivers/staging/dgnc/digi.h
@@ -0,0 +1,416 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DIGI_H
+#define __DIGI_H
+
+/************************************************************************
+ *** Definitions for Digi ditty(1) command.
+ ************************************************************************/
+
+
+/*
+ * Copyright (c) 1988-96 Digi International Inc., All Rights Reserved.
+ */
+
+/************************************************************************
+ * This module provides application access to special Digi
+ * serial line enhancements which are not standard UNIX(tm) features.
+ ************************************************************************/
+
+#if !defined(TIOCMODG)
+
+#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */
+#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */
+
+#ifndef TIOCM_LE
+#define TIOCM_LE 0x01 /* line enable */
+#define TIOCM_DTR 0x02 /* data terminal ready */
+#define TIOCM_RTS 0x04 /* request to send */
+#define TIOCM_ST 0x08 /* secondary transmit */
+#define TIOCM_SR 0x10 /* secondary receive */
+#define TIOCM_CTS 0x20 /* clear to send */
+#define TIOCM_CAR 0x40 /* carrier detect */
+#define TIOCM_RNG 0x80 /* ring indicator */
+#define TIOCM_DSR 0x100 /* data set ready */
+#define TIOCM_RI TIOCM_RNG /* ring (alternate) */
+#define TIOCM_CD TIOCM_CAR /* carrier detect (alt) */
+#endif
+
+#endif
+
+#if !defined(TIOCMSET)
+#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */
+#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */
+#endif
+
+#if !defined(TIOCMBIC)
+#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */
+#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */
+#endif
+
+
+#if !defined(TIOCSDTR)
+#define TIOCSDTR ('e'<<8) | 0 /* set DTR */
+#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */
+#endif
+
+/************************************************************************
+ * Ioctl command arguments for DIGI parameters.
+ ************************************************************************/
+#define DIGI_GETA ('e'<<8) | 94 /* Read params */
+
+#define DIGI_SETA ('e'<<8) | 95 /* Set params */
+#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */
+#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */
+
+#define DIGI_KME ('e'<<8) | 98 /* Read/Write Host */
+ /* Adapter Memory */
+
+#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */
+ /* control characters */
+#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */
+ /* control characters */
+#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */
+ /* flow control chars */
+#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */
+ /* flow control chars */
+
+#define DIGI_GEDELAY ('d'<<8) | 246 /* Get edelay */
+#define DIGI_SEDELAY ('d'<<8) | 247 /* Set edelay */
+
+struct digiflow_t {
+ unsigned char startc; /* flow cntl start char */
+ unsigned char stopc; /* flow cntl stop char */
+};
+
+
+#ifdef FLOW_2200
+#define F2200_GETA ('e'<<8) | 104 /* Get 2x36 flow cntl flags */
+#define F2200_SETAW ('e'<<8) | 105 /* Set 2x36 flow cntl flags */
+#define F2200_MASK 0x03 /* 2200 flow cntl bit mask */
+#define FCNTL_2200 0x01 /* 2x36 terminal flow cntl */
+#define PCNTL_2200 0x02 /* 2x36 printer flow cntl */
+#define F2200_XON 0xf8
+#define P2200_XON 0xf9
+#define F2200_XOFF 0xfa
+#define P2200_XOFF 0xfb
+
+#define FXOFF_MASK 0x03 /* 2200 flow status mask */
+#define RCVD_FXOFF 0x01 /* 2x36 Terminal XOFF rcvd */
+#define RCVD_PXOFF 0x02 /* 2x36 Printer XOFF rcvd */
+#endif
+
+/************************************************************************
+ * Values for digi_flags
+ ************************************************************************/
+#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */
+#define DIGI_FAST 0x0002 /* Fast baud rates */
+#define RTSPACE 0x0004 /* RTS input flow control */
+#define CTSPACE 0x0008 /* CTS output flow control */
+#define DSRPACE 0x0010 /* DSR output flow control */
+#define DCDPACE 0x0020 /* DCD output flow control */
+#define DTRPACE 0x0040 /* DTR input flow control */
+#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */
+#define DIGI_FORCEDCD 0x0100 /* Force carrier */
+#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
+#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
+#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl*/
+#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input*/
+#define DIGI_DTR_TOGGLE 0x2000 /* Support DTR Toggle */
+#define DIGI_422 0x4000 /* for 422/232 selectable panel */
+#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */
+
+/************************************************************************
+ * These options are not supported on the comxi.
+ ************************************************************************/
+#define DIGI_COMXI (DIGI_FAST|DIGI_COOK|DSRPACE|DCDPACE|DTRPACE)
+
+#define DIGI_PLEN 28 /* String length */
+#define DIGI_TSIZ 10 /* Terminal string len */
+
+/************************************************************************
+ * Structure used with ioctl commands for DIGI parameters.
+ ************************************************************************/
+struct digi_t {
+ unsigned short digi_flags; /* Flags (see above) */
+ unsigned short digi_maxcps; /* Max printer CPS */
+ unsigned short digi_maxchar; /* Max chars in print queue */
+ unsigned short digi_bufsize; /* Buffer size */
+ unsigned char digi_onlen; /* Length of ON string */
+ unsigned char digi_offlen; /* Length of OFF string */
+ char digi_onstr[DIGI_PLEN]; /* Printer on string */
+ char digi_offstr[DIGI_PLEN]; /* Printer off string */
+ char digi_term[DIGI_TSIZ]; /* terminal string */
+};
+
+/************************************************************************
+ * KME definitions and structures.
+ ************************************************************************/
+#define RW_IDLE 0 /* Operation complete */
+#define RW_READ 1 /* Read Concentrator Memory */
+#define RW_WRITE 2 /* Write Concentrator Memory */
+
+struct rw_t {
+ unsigned char rw_req; /* Request type */
+ unsigned char rw_board; /* Host Adapter board number */
+ unsigned char rw_conc; /* Concentrator number */
+ unsigned char rw_reserved; /* Reserved for expansion */
+ unsigned int rw_addr; /* Address in concentrator */
+ unsigned short rw_size; /* Read/write request length */
+ unsigned char rw_data[128]; /* Data to read/write */
+};
+
+/***********************************************************************
+ * Shrink Buffer and Board Information definitions and structures.
+
+ ************************************************************************/
+ /* Board type return codes */
+#define PCXI_TYPE 1 /* Board type at the designated port is a PC/Xi */
+#define PCXM_TYPE 2 /* Board type at the designated port is a PC/Xm */
+#define PCXE_TYPE 3 /* Board type at the designated port is a PC/Xe */
+#define MCXI_TYPE 4 /* Board type at the designated port is a MC/Xi */
+#define COMXI_TYPE 5 /* Board type at the designated port is a COM/Xi */
+
+ /* Non-Zero Result codes. */
+#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */
+#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */
+#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */
+#define RESULT_TOOSML 4 /* Too small an area to shrink. */
+#define RESULT_NOCHAN 5 /* Channel structure for the board was not found */
+
+struct shrink_buf_struct {
+ unsigned int shrink_buf_vaddr; /* Virtual address of board */
+ unsigned int shrink_buf_phys; /* Physical address of board */
+ unsigned int shrink_buf_bseg; /* Amount of board memory */
+ unsigned int shrink_buf_hseg; /* '186 Begining of Dual-Port */
+
+ unsigned int shrink_buf_lseg; /* '186 Begining of freed memory */
+ unsigned int shrink_buf_mseg; /* Linear address from start of
+ dual-port were freed memory
+ begins, host viewpoint. */
+
+ unsigned int shrink_buf_bdparam; /* Parameter for xxmemon and
+ xxmemoff */
+
+ unsigned int shrink_buf_reserva; /* Reserved */
+ unsigned int shrink_buf_reservb; /* Reserved */
+ unsigned int shrink_buf_reservc; /* Reserved */
+ unsigned int shrink_buf_reservd; /* Reserved */
+
+ unsigned char shrink_buf_result; /* Reason for call failing
+ Zero is Good return */
+ unsigned char shrink_buf_init; /* Non-Zero if it caused an
+ xxinit call. */
+
+ unsigned char shrink_buf_anports; /* Number of async ports */
+ unsigned char shrink_buf_snports; /* Number of sync ports */
+ unsigned char shrink_buf_type; /* Board type 1 = PC/Xi,
+ 2 = PC/Xm,
+ 3 = PC/Xe
+ 4 = MC/Xi
+ 5 = COMX/i */
+ unsigned char shrink_buf_card; /* Card number */
+
+};
+
+/************************************************************************
+ * Structure to get driver status information
+ ************************************************************************/
+struct digi_dinfo {
+ unsigned int dinfo_nboards; /* # boards configured */
+ char dinfo_reserved[12]; /* for future expansion */
+ char dinfo_version[16]; /* driver version */
+};
+
+#define DIGI_GETDD ('d'<<8) | 248 /* get driver info */
+
+/************************************************************************
+ * Structure used with ioctl commands for per-board information
+ *
+ * physsize and memsize differ when board has "windowed" memory
+ ************************************************************************/
+struct digi_info {
+ unsigned int info_bdnum; /* Board number (0 based) */
+ unsigned int info_ioport; /* io port address */
+ unsigned int info_physaddr; /* memory address */
+ unsigned int info_physsize; /* Size of host mem window */
+ unsigned int info_memsize; /* Amount of dual-port mem */
+ /* on board */
+ unsigned short info_bdtype; /* Board type */
+ unsigned short info_nports; /* number of ports */
+ char info_bdstate; /* board state */
+ char info_reserved[7]; /* for future expansion */
+};
+
+#define DIGI_GETBD ('d'<<8) | 249 /* get board info */
+
+struct digi_stat {
+ unsigned int info_chan; /* Channel number (0 based) */
+ unsigned int info_brd; /* Board number (0 based) */
+ unsigned int info_cflag; /* cflag for channel */
+ unsigned int info_iflag; /* iflag for channel */
+ unsigned int info_oflag; /* oflag for channel */
+ unsigned int info_mstat; /* mstat for channel */
+ unsigned int info_tx_data; /* tx_data for channel */
+ unsigned int info_rx_data; /* rx_data for channel */
+ unsigned int info_hflow; /* hflow for channel */
+ unsigned int info_reserved[8]; /* for future expansion */
+};
+
+#define DIGI_GETSTAT ('d'<<8) | 244 /* get board info */
+/************************************************************************
+ *
+ * Structure used with ioctl commands for per-channel information
+ *
+ ************************************************************************/
+struct digi_ch {
+ unsigned int info_bdnum; /* Board number (0 based) */
+ unsigned int info_channel; /* Channel index number */
+ unsigned int info_ch_cflag; /* Channel cflag */
+ unsigned int info_ch_iflag; /* Channel iflag */
+ unsigned int info_ch_oflag; /* Channel oflag */
+ unsigned int info_chsize; /* Channel structure size */
+ unsigned int info_sleep_stat; /* sleep status */
+ dev_t info_dev; /* device number */
+ unsigned char info_initstate; /* Channel init state */
+ unsigned char info_running; /* Channel running state */
+ int reserved[8]; /* reserved for future use */
+};
+
+/*
+* This structure is used with the DIGI_FEPCMD ioctl to
+* tell the driver which port to send the command for.
+*/
+struct digi_cmd {
+ int cmd;
+ int word;
+ int ncmds;
+ int chan; /* channel index (zero based) */
+ int bdid; /* board index (zero based) */
+};
+
+
+struct digi_getbuffer /* Struct for holding buffer use counts */
+{
+ unsigned long tIn;
+ unsigned long tOut;
+ unsigned long rxbuf;
+ unsigned long txbuf;
+ unsigned long txdone;
+};
+
+struct digi_getcounter {
+ unsigned long norun; /* number of UART overrun errors */
+ unsigned long noflow; /* number of buffer overflow errors */
+ unsigned long nframe; /* number of framing errors */
+ unsigned long nparity; /* number of parity errors */
+ unsigned long nbreak; /* number of breaks received */
+ unsigned long rbytes; /* number of received bytes */
+ unsigned long tbytes; /* number of bytes transmitted fully */
+};
+
+/*
+* info_sleep_stat defines
+*/
+#define INFO_RUNWAIT 0x0001
+#define INFO_WOPEN 0x0002
+#define INFO_TTIOW 0x0004
+#define INFO_CH_RWAIT 0x0008
+#define INFO_CH_WEMPTY 0x0010
+#define INFO_CH_WLOW 0x0020
+#define INFO_XXBUF_BUSY 0x0040
+
+#define DIGI_GETCH ('d'<<8) | 245 /* get board info */
+
+/* Board type definitions */
+
+#define SUBTYPE 0007
+#define T_PCXI 0000
+#define T_PCXM 0001
+#define T_PCXE 0002
+#define T_PCXR 0003
+#define T_SP 0004
+#define T_SP_PLUS 0005
+# define T_HERC 0000
+# define T_HOU 0001
+# define T_LON 0002
+# define T_CHA 0003
+#define FAMILY 0070
+#define T_COMXI 0000
+#define T_PCXX 0010
+#define T_CX 0020
+#define T_EPC 0030
+#define T_PCLITE 0040
+#define T_SPXX 0050
+#define T_AVXX 0060
+#define T_DXB 0070
+#define T_A2K_4_8 0070
+#define BUSTYPE 0700
+#define T_ISABUS 0000
+#define T_MCBUS 0100
+#define T_EISABUS 0200
+#define T_PCIBUS 0400
+
+/* Board State Definitions */
+
+#define BD_RUNNING 0x0
+#define BD_REASON 0x7f
+#define BD_NOTFOUND 0x1
+#define BD_NOIOPORT 0x2
+#define BD_NOMEM 0x3
+#define BD_NOBIOS 0x4
+#define BD_NOFEP 0x5
+#define BD_FAILED 0x6
+#define BD_ALLOCATED 0x7
+#define BD_TRIBOOT 0x8
+#define BD_BADKME 0x80
+
+#define DIGI_SPOLL ('d'<<8) | 254 /* change poller rate */
+
+#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */
+#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */
+
+#define DIGI_REALPORT_GETBUFFERS ('e'<<8 ) | 108
+#define DIGI_REALPORT_SENDIMMEDIATE ('e'<<8 ) | 109
+#define DIGI_REALPORT_GETCOUNTERS ('e'<<8 ) | 110
+#define DIGI_REALPORT_GETEVENTS ('e'<<8 ) | 111
+
+#define EV_OPU 0x0001 //!<Output paused by client
+#define EV_OPS 0x0002 //!<Output paused by reqular sw flowctrl
+#define EV_OPX 0x0004 //!<Output paused by extra sw flowctrl
+#define EV_OPH 0x0008 //!<Output paused by hw flowctrl
+#define EV_OPT 0x0800 //!<Output paused for RTS Toggle predelay
+
+#define EV_IPU 0x0010 //!<Input paused unconditionally by user
+#define EV_IPS 0x0020 //!<Input paused by high/low water marks
+//#define EV_IPH 0x0040 //!<Input paused w/ hardware
+#define EV_IPA 0x0400 //!<Input paused by pattern alarm module
+
+#define EV_TXB 0x0040 //!<Transmit break pending
+#define EV_TXI 0x0080 //!<Transmit immediate pending
+#define EV_TXF 0x0100 //!<Transmit flowctrl char pending
+#define EV_RXB 0x0200 //!<Break received
+
+#define EV_OPALL 0x080f //!<Output pause flags
+#define EV_IPALL 0x0430 //!<Input pause flags
+
+#endif /* DIGI_H */
diff --git a/drivers/staging/dgnc/dpacompat.h b/drivers/staging/dgnc/dpacompat.h
new file mode 100644
index 00000000000..f96963b9843
--- /dev/null
+++ b/drivers/staging/dgnc/dpacompat.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+
+/*
+ * This structure holds data needed for the intelligent <--> nonintelligent
+ * DPA translation
+ */
+ struct ni_info {
+ int board;
+ int channel;
+ int dtr;
+ int rts;
+ int cts;
+ int dsr;
+ int ri;
+ int dcd;
+ int curtx;
+ int currx;
+ unsigned short iflag;
+ unsigned short oflag;
+ unsigned short cflag;
+ unsigned short lflag;
+
+ unsigned int mstat;
+ unsigned char hflow;
+
+ unsigned char xmit_stopped;
+ unsigned char recv_stopped;
+
+ unsigned int baud;
+};
+
+#define RW_READ 1
+#define RW_WRITE 2
+#define DIGI_KME ('e'<<8) | 98 /* Read/Write Host */
+
+#define SUBTYPE 0007
+#define T_PCXI 0000
+#define T_PCXEM 0001
+#define T_PCXE 0002
+#define T_PCXR 0003
+#define T_SP 0004
+#define T_SP_PLUS 0005
+
+#define T_HERC 0000
+#define T_HOU 0001
+#define T_LON 0002
+#define T_CHA 0003
+
+#define T_NEO 0000
+#define T_NEO_EXPRESS 0001
+#define T_CLASSIC 0002
+
+#define FAMILY 0070
+#define T_COMXI 0000
+#define T_NI 0000
+#define T_PCXX 0010
+#define T_CX 0020
+#define T_EPC 0030
+#define T_PCLITE 0040
+#define T_SPXX 0050
+#define T_AVXX 0060
+#define T_DXB 0070
+#define T_A2K_4_8 0070
+
+#define BUSTYPE 0700
+#define T_ISABUS 0000
+#define T_MCBUS 0100
+#define T_EISABUS 0200
+#define T_PCIBUS 0400
+
+/* Board State Definitions */
+
+#define BD_RUNNING 0x0
+#define BD_REASON 0x7f
+#define BD_NOTFOUND 0x1
+#define BD_NOIOPORT 0x2
+#define BD_NOMEM 0x3
+#define BD_NOBIOS 0x4
+#define BD_NOFEP 0x5
+#define BD_FAILED 0x6
+#define BD_ALLOCATED 0x7
+#define BD_TRIBOOT 0x8
+#define BD_BADKME 0x80
+
+#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
+
+/* Ioctls needed for dpa operation */
+
+#define DIGI_GETDD ('d'<<8) | 248 /* get driver info */
+#define DIGI_GETBD ('d'<<8) | 249 /* get board info */
+#define DIGI_GET_NI_INFO ('d'<<8) | 250 /* nonintelligent state snfo */
+
+/* Other special ioctls */
+#define DIGI_TIMERIRQ ('d'<<8) | 251 /* Enable/disable RS_TIMER use */
+#define DIGI_LOOPBACK ('d'<<8) | 252 /* Enable/disable UART internal loopback */
diff --git a/drivers/staging/dgrp/dgrp_driver.c b/drivers/staging/dgrp/dgrp_driver.c
index e456dc6cb36..08eedf0867e 100644
--- a/drivers/staging/dgrp/dgrp_driver.c
+++ b/drivers/staging/dgrp/dgrp_driver.c
@@ -52,19 +52,12 @@ MODULE_PARM_DESC(register_prdevices, "Turn on/off registering transparent print
module_param_named(pollrate, dgrp_poll_tick, int, 0644);
MODULE_PARM_DESC(pollrate, "Poll interval in ms");
-/* Driver load/unload functions */
-static int dgrp_init_module(void);
-static void dgrp_cleanup_module(void);
-
-module_init(dgrp_init_module);
-module_exit(dgrp_cleanup_module);
-
/*
* init_module()
*
* Module load. This is where it all starts.
*/
-static int dgrp_init_module(void)
+static int __init dgrp_init_module(void)
{
int ret;
@@ -89,7 +82,7 @@ static int dgrp_init_module(void)
/*
* Module unload. This is where it all ends.
*/
-static void dgrp_cleanup_module(void)
+static void __exit dgrp_cleanup_module(void)
{
struct nd_struct *nd, *next;
@@ -108,3 +101,6 @@ static void dgrp_cleanup_module(void)
kfree(nd);
}
}
+
+module_init(dgrp_init_module);
+module_exit(dgrp_cleanup_module);
diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c
index 654f6010b47..0d52de3729c 100644
--- a/drivers/staging/dgrp/dgrp_tty.c
+++ b/drivers/staging/dgrp/dgrp_tty.c
@@ -1120,7 +1120,9 @@ static void dgrp_tty_close(struct tty_struct *tty, struct file *file)
if (!sent_printer_offstr)
dgrp_tty_flush_buffer(tty);
+ spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
tty_ldisc_flush(tty);
+ spin_lock_irqsave(&nd->nd_lock, lock_flags);
break;
}
diff --git a/drivers/staging/dwc2/Kconfig b/drivers/staging/dwc2/Kconfig
index d15d9d58e5a..be947d67384 100644
--- a/drivers/staging/dwc2/Kconfig
+++ b/drivers/staging/dwc2/Kconfig
@@ -1,7 +1,6 @@
config USB_DWC2
tristate "DesignWare USB2 DRD Core Support"
depends on USB
- depends on VIRT_TO_BUS
help
Say Y or M here if your system has a Dual Role HighSpeed
USB controller based on the DesignWare HSOTG IP Core.
diff --git a/drivers/staging/dwc2/core.c b/drivers/staging/dwc2/core.c
index e3a0e770301..06dae67a9d6 100644
--- a/drivers/staging/dwc2/core.c
+++ b/drivers/staging/dwc2/core.c
@@ -90,12 +90,10 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
*/
static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
{
- u32 hs_phy_type = hsotg->hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK;
- u32 fs_phy_type = hsotg->hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK;
u32 hcfg, val;
- if ((hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
- fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+ if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+ hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
hsotg->core_params->ulpi_fs_ls > 0) ||
hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
/* Full speed PHY */
@@ -108,7 +106,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val);
hcfg = readl(hsotg->regs + HCFG);
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
- hcfg |= val;
+ hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT;
writel(hcfg, hsotg->regs + HCFG);
}
@@ -245,7 +243,7 @@ static void dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
static void dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
{
- u32 usbcfg, hs_phy_type, fs_phy_type;
+ u32 usbcfg;
if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL &&
hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
@@ -256,11 +254,8 @@ static void dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
dwc2_hs_phy_init(hsotg, select_phy);
}
- hs_phy_type = hsotg->hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK;
- fs_phy_type = hsotg->hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK;
-
- if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
- fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+ if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+ hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
hsotg->core_params->ulpi_fs_ls > 0) {
dev_dbg(hsotg->dev, "Setting ULPI FSLS\n");
usbcfg = readl(hsotg->regs + GUSBCFG);
@@ -277,20 +272,20 @@ static void dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
{
- u32 ahbcfg = 0;
+ u32 ahbcfg = readl(hsotg->regs + GAHBCFG);
- switch (hsotg->hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) {
+ switch (hsotg->hw_params.arch) {
case GHWCFG2_EXT_DMA_ARCH:
dev_err(hsotg->dev, "External DMA Mode not supported\n");
return -EINVAL;
case GHWCFG2_INT_DMA_ARCH:
dev_dbg(hsotg->dev, "Internal DMA Mode\n");
- /*
- * Old value was GAHBCFG_HBSTLEN_INCR - done for
- * Host mode ISOC in issue fix - vahrama
- */
- ahbcfg |= GAHBCFG_HBSTLEN_INCR4;
+ if (hsotg->core_params->ahbcfg != -1) {
+ ahbcfg &= GAHBCFG_CTRL_MASK;
+ ahbcfg |= hsotg->core_params->ahbcfg &
+ ~GAHBCFG_CTRL_MASK;
+ }
break;
case GHWCFG2_SLAVE_ONLY_ARCH:
@@ -313,9 +308,6 @@ static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
hsotg->core_params->dma_desc_enable = 0;
}
- if (hsotg->core_params->ahb_single > 0)
- ahbcfg |= GAHBCFG_AHB_SINGLE;
-
if (hsotg->core_params->dma_enable > 0)
ahbcfg |= GAHBCFG_DMA_EN;
@@ -331,7 +323,7 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
usbcfg = readl(hsotg->regs + GUSBCFG);
usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP);
- switch (hsotg->hwcfg2 & GHWCFG2_OP_MODE_MASK) {
+ switch (hsotg->hw_params.op_mode) {
case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
if (hsotg->core_params->otg_cap ==
DWC2_CAP_PARAM_HNP_SRP_CAPABLE)
@@ -392,21 +384,6 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
/* Reset the Controller */
dwc2_core_reset(hsotg);
- dev_dbg(hsotg->dev, "num_dev_perio_in_ep=%d\n",
- hsotg->hwcfg4 >> GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT &
- GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK >>
- GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT);
-
- hsotg->total_fifo_size = hsotg->hwcfg3 >> GHWCFG3_DFIFO_DEPTH_SHIFT &
- GHWCFG3_DFIFO_DEPTH_MASK >> GHWCFG3_DFIFO_DEPTH_SHIFT;
- hsotg->rx_fifo_size = readl(hsotg->regs + GRXFSIZ);
- hsotg->nperio_tx_fifo_size =
- readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff;
-
- dev_dbg(hsotg->dev, "Total FIFO SZ=%d\n", hsotg->total_fifo_size);
- dev_dbg(hsotg->dev, "RxFIFO SZ=%d\n", hsotg->rx_fifo_size);
- dev_dbg(hsotg->dev, "NP TxFIFO SZ=%d\n", hsotg->nperio_tx_fifo_size);
-
/*
* This needs to happen in FS mode before any other programming occurs
*/
@@ -504,22 +481,18 @@ void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg)
static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *params = hsotg->core_params;
- u32 rxfsiz, nptxfsiz, ptxfsiz, hptxfsiz, dfifocfg;
+ u32 nptxfsiz, hptxfsiz, dfifocfg, grxfsiz;
if (!params->enable_dynamic_fifo)
return;
- dev_dbg(hsotg->dev, "Total FIFO Size=%d\n", hsotg->total_fifo_size);
- dev_dbg(hsotg->dev, "Rx FIFO Size=%d\n", params->host_rx_fifo_size);
- dev_dbg(hsotg->dev, "NP Tx FIFO Size=%d\n",
- params->host_nperio_tx_fifo_size);
- dev_dbg(hsotg->dev, "P Tx FIFO Size=%d\n",
- params->host_perio_tx_fifo_size);
-
/* Rx FIFO */
- dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n",
- readl(hsotg->regs + GRXFSIZ));
- writel(params->host_rx_fifo_size, hsotg->regs + GRXFSIZ);
+ grxfsiz = readl(hsotg->regs + GRXFSIZ);
+ dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz);
+ grxfsiz &= ~GRXFSIZ_DEPTH_MASK;
+ grxfsiz |= params->host_rx_fifo_size <<
+ GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK;
+ writel(grxfsiz, hsotg->regs + GRXFSIZ);
dev_dbg(hsotg->dev, "new grxfsiz=%08x\n", readl(hsotg->regs + GRXFSIZ));
/* Non-periodic Tx FIFO */
@@ -536,27 +509,26 @@ static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
/* Periodic Tx FIFO */
dev_dbg(hsotg->dev, "initial hptxfsiz=%08x\n",
readl(hsotg->regs + HPTXFSIZ));
- ptxfsiz = params->host_perio_tx_fifo_size <<
- FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
- ptxfsiz |= (params->host_rx_fifo_size +
- params->host_nperio_tx_fifo_size) <<
- FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
- writel(ptxfsiz, hsotg->regs + HPTXFSIZ);
+ hptxfsiz = params->host_perio_tx_fifo_size <<
+ FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
+ hptxfsiz |= (params->host_rx_fifo_size +
+ params->host_nperio_tx_fifo_size) <<
+ FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
+ writel(hptxfsiz, hsotg->regs + HPTXFSIZ);
dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n",
readl(hsotg->regs + HPTXFSIZ));
if (hsotg->core_params->en_multiple_tx_fifo > 0 &&
- hsotg->snpsid <= DWC2_CORE_REV_2_94a) {
+ hsotg->hw_params.snpsid <= DWC2_CORE_REV_2_94a) {
/*
* Global DFIFOCFG calculation for Host mode -
* include RxFIFO, NPTXFIFO and HPTXFIFO
*/
dfifocfg = readl(hsotg->regs + GDFIFOCFG);
- rxfsiz = readl(hsotg->regs + GRXFSIZ) & 0x0000ffff;
- nptxfsiz = readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff;
- hptxfsiz = readl(hsotg->regs + HPTXFSIZ) >> 16 & 0xffff;
dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK;
- dfifocfg |= (rxfsiz + nptxfsiz + hptxfsiz) <<
+ dfifocfg |= (params->host_rx_fifo_size +
+ params->host_nperio_tx_fifo_size +
+ params->host_perio_tx_fifo_size) <<
GDFIFOCFG_EPINFOBASE_SHIFT &
GDFIFOCFG_EPINFOBASE_MASK;
writel(dfifocfg, hsotg->regs + GDFIFOCFG);
@@ -602,10 +574,9 @@ void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
}
if (hsotg->core_params->dma_desc_enable > 0) {
- u32 op_mode = hsotg->hwcfg2 & GHWCFG2_OP_MODE_MASK;
-
- if (hsotg->snpsid < DWC2_CORE_REV_2_90a ||
- !(hsotg->hwcfg4 & GHWCFG4_DESC_DMA) ||
+ u32 op_mode = hsotg->hw_params.op_mode;
+ if (hsotg->hw_params.snpsid < DWC2_CORE_REV_2_90a ||
+ !hsotg->hw_params.dma_desc_enable ||
op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE ||
op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE ||
op_mode == GHWCFG2_OP_MODE_UNDEFINED) {
@@ -883,26 +854,20 @@ void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
dev_vdbg(hsotg->dev, "set HCCHAR(%d) to %08x\n",
hc_num, hcchar);
- dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__, hc_num);
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n",
+ __func__, hc_num);
dev_vdbg(hsotg->dev, " Dev Addr: %d\n",
- hcchar >> HCCHAR_DEVADDR_SHIFT &
- HCCHAR_DEVADDR_MASK >> HCCHAR_DEVADDR_SHIFT);
+ chan->dev_addr);
dev_vdbg(hsotg->dev, " Ep Num: %d\n",
- hcchar >> HCCHAR_EPNUM_SHIFT &
- HCCHAR_EPNUM_MASK >> HCCHAR_EPNUM_SHIFT);
+ chan->ep_num);
dev_vdbg(hsotg->dev, " Is In: %d\n",
- !!(hcchar & HCCHAR_EPDIR));
+ chan->ep_is_in);
dev_vdbg(hsotg->dev, " Is Low Speed: %d\n",
- !!(hcchar & HCCHAR_LSPDDEV));
+ chan->speed == USB_SPEED_LOW);
dev_vdbg(hsotg->dev, " Ep Type: %d\n",
- hcchar >> HCCHAR_EPTYPE_SHIFT &
- HCCHAR_EPTYPE_MASK >> HCCHAR_EPTYPE_SHIFT);
+ chan->ep_type);
dev_vdbg(hsotg->dev, " Max Pkt: %d\n",
- hcchar >> HCCHAR_MPS_SHIFT &
- HCCHAR_MPS_MASK >> HCCHAR_MPS_SHIFT);
- dev_vdbg(hsotg->dev, " Multi Cnt: %d\n",
- hcchar >> HCCHAR_MULTICNT_SHIFT &
- HCCHAR_MULTICNT_MASK >> HCCHAR_MULTICNT_SHIFT);
+ chan->max_packet);
}
/* Program the HCSPLT register for SPLITs */
@@ -932,8 +897,7 @@ void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
dev_vdbg(hsotg->dev, " is_in %d\n",
chan->ep_is_in);
dev_vdbg(hsotg->dev, " Max Pkt %d\n",
- hcchar >> HCCHAR_MPS_SHIFT &
- HCCHAR_MPS_MASK >> HCCHAR_MPS_SHIFT);
+ chan->max_packet);
dev_vdbg(hsotg->dev, " xferlen %d\n",
chan->xfer_len);
}
@@ -1382,14 +1346,14 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
chan->hc_num);
dev_vdbg(hsotg->dev, " Xfer Size: %d\n",
- hctsiz >> TSIZ_XFERSIZE_SHIFT &
- TSIZ_XFERSIZE_MASK >> TSIZ_XFERSIZE_SHIFT);
+ (hctsiz & TSIZ_XFERSIZE_MASK) >>
+ TSIZ_XFERSIZE_SHIFT);
dev_vdbg(hsotg->dev, " Num Pkts: %d\n",
- hctsiz >> TSIZ_PKTCNT_SHIFT &
- TSIZ_PKTCNT_MASK >> TSIZ_PKTCNT_SHIFT);
+ (hctsiz & TSIZ_PKTCNT_MASK) >>
+ TSIZ_PKTCNT_SHIFT);
dev_vdbg(hsotg->dev, " Start PID: %d\n",
- hctsiz >> TSIZ_SC_MC_PID_SHIFT &
- TSIZ_SC_MC_PID_MASK >> TSIZ_SC_MC_PID_SHIFT);
+ (hctsiz & TSIZ_SC_MC_PID_MASK) >>
+ TSIZ_SC_MC_PID_SHIFT);
}
if (hsotg->core_params->dma_enable > 0) {
@@ -1433,8 +1397,8 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
if (dbg_hc(chan))
dev_vdbg(hsotg->dev, " Multi Cnt: %d\n",
- hcchar >> HCCHAR_MULTICNT_SHIFT &
- HCCHAR_MULTICNT_MASK >> HCCHAR_MULTICNT_SHIFT);
+ (hcchar & HCCHAR_MULTICNT_MASK) >>
+ HCCHAR_MULTICNT_SHIFT);
writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
if (dbg_hc(chan))
@@ -1522,8 +1486,8 @@ void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
if (dbg_hc(chan))
dev_vdbg(hsotg->dev, " Multi Cnt: %d\n",
- hcchar >> HCCHAR_MULTICNT_SHIFT &
- HCCHAR_MULTICNT_MASK >> HCCHAR_MULTICNT_SHIFT);
+ (hcchar & HCCHAR_MULTICNT_MASK) >>
+ HCCHAR_MULTICNT_SHIFT);
writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
if (dbg_hc(chan))
@@ -1658,18 +1622,16 @@ void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
{
u32 usbcfg;
- u32 hwcfg2;
u32 hprt0;
int clock = 60; /* default value */
usbcfg = readl(hsotg->regs + GUSBCFG);
- hwcfg2 = readl(hsotg->regs + GHWCFG2);
hprt0 = readl(hsotg->regs + HPRT0);
if (!(usbcfg & GUSBCFG_PHYSEL) && (usbcfg & GUSBCFG_ULPI_UTMI_SEL) &&
!(usbcfg & GUSBCFG_PHYIF16))
clock = 60;
- if ((usbcfg & GUSBCFG_PHYSEL) && (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) ==
+ if ((usbcfg & GUSBCFG_PHYSEL) && hsotg->hw_params.fs_phy_type ==
GHWCFG2_FS_PHY_TYPE_SHARED_ULPI)
clock = 48;
if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
@@ -1682,14 +1644,13 @@ u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
!(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
clock = 48;
if ((usbcfg & GUSBCFG_PHYSEL) && !(usbcfg & GUSBCFG_PHYIF16) &&
- (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) ==
- GHWCFG2_FS_PHY_TYPE_SHARED_UTMI)
+ hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_SHARED_UTMI)
clock = 48;
- if ((usbcfg & GUSBCFG_PHYSEL) && (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) ==
- GHWCFG2_FS_PHY_TYPE_DEDICATED)
+ if ((usbcfg & GUSBCFG_PHYSEL) &&
+ hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED)
clock = 48;
- if ((hprt0 & HPRT0_SPD_MASK) == HPRT0_SPD_HIGH_SPEED)
+ if ((hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT == HPRT0_SPD_HIGH_SPEED)
/* High speed case */
return 125 * clock;
else
@@ -1958,17 +1919,14 @@ int dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val)
{
int valid = 1;
int retval = 0;
- u32 op_mode;
-
- op_mode = hsotg->hwcfg2 & GHWCFG2_OP_MODE_MASK;
switch (val) {
case DWC2_CAP_PARAM_HNP_SRP_CAPABLE:
- if (op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE)
+ if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE)
valid = 0;
break;
case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE:
- switch (op_mode) {
+ switch (hsotg->hw_params.op_mode) {
case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
@@ -1992,7 +1950,7 @@ int dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for otg_cap parameter. Check HW configuration.\n",
val);
- switch (op_mode) {
+ switch (hsotg->hw_params.op_mode) {
case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE;
break;
@@ -2018,8 +1976,7 @@ int dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val)
int valid = 1;
int retval = 0;
- if (val > 0 && (hsotg->hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) ==
- GHWCFG2_SLAVE_ONLY_ARCH)
+ if (val > 0 && hsotg->hw_params.arch == GHWCFG2_SLAVE_ONLY_ARCH)
valid = 0;
if (val < 0)
valid = 0;
@@ -2029,8 +1986,7 @@ int dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for dma_enable parameter. Check HW configuration.\n",
val);
- val = (hsotg->hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) !=
- GHWCFG2_SLAVE_ONLY_ARCH;
+ val = hsotg->hw_params.arch != GHWCFG2_SLAVE_ONLY_ARCH;
dev_dbg(hsotg->dev, "Setting dma_enable to %d\n", val);
retval = -EINVAL;
}
@@ -2045,7 +2001,7 @@ int dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val)
int retval = 0;
if (val > 0 && (hsotg->core_params->dma_enable <= 0 ||
- !(hsotg->hwcfg4 & GHWCFG4_DESC_DMA)))
+ !hsotg->hw_params.dma_desc_enable))
valid = 0;
if (val < 0)
valid = 0;
@@ -2056,7 +2012,7 @@ int dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val)
"%d invalid for dma_desc_enable parameter. Check HW configuration.\n",
val);
val = (hsotg->core_params->dma_enable > 0 &&
- (hsotg->hwcfg4 & GHWCFG4_DESC_DMA));
+ hsotg->hw_params.dma_desc_enable);
dev_dbg(hsotg->dev, "Setting dma_desc_enable to %d\n", val);
retval = -EINVAL;
}
@@ -2092,7 +2048,7 @@ int dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg, int val)
int valid = 1;
int retval = 0;
- if (val > 0 && !(hsotg->hwcfg2 & GHWCFG2_DYNAMIC_FIFO))
+ if (val > 0 && !hsotg->hw_params.enable_dynamic_fifo)
valid = 0;
if (val < 0)
valid = 0;
@@ -2102,7 +2058,7 @@ int dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for enable_dynamic_fifo parameter. Check HW configuration.\n",
val);
- val = !!(hsotg->hwcfg2 & GHWCFG2_DYNAMIC_FIFO);
+ val = hsotg->hw_params.enable_dynamic_fifo;
dev_dbg(hsotg->dev, "Setting enable_dynamic_fifo to %d\n", val);
retval = -EINVAL;
}
@@ -2116,7 +2072,7 @@ int dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val)
int valid = 1;
int retval = 0;
- if (val < 16 || val > readl(hsotg->regs + GRXFSIZ))
+ if (val < 16 || val > hsotg->hw_params.host_rx_fifo_size)
valid = 0;
if (!valid) {
@@ -2124,7 +2080,7 @@ int dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for host_rx_fifo_size. Check HW configuration.\n",
val);
- val = readl(hsotg->regs + GRXFSIZ);
+ val = hsotg->hw_params.host_rx_fifo_size;
dev_dbg(hsotg->dev, "Setting host_rx_fifo_size to %d\n", val);
retval = -EINVAL;
}
@@ -2138,7 +2094,7 @@ int dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val)
int valid = 1;
int retval = 0;
- if (val < 16 || val > (readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff))
+ if (val < 16 || val > hsotg->hw_params.host_nperio_tx_fifo_size)
valid = 0;
if (!valid) {
@@ -2146,7 +2102,7 @@ int dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
val);
- val = readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff;
+ val = hsotg->hw_params.host_nperio_tx_fifo_size;
dev_dbg(hsotg->dev, "Setting host_nperio_tx_fifo_size to %d\n",
val);
retval = -EINVAL;
@@ -2161,7 +2117,7 @@ int dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val)
int valid = 1;
int retval = 0;
- if (val < 16 || val > (hsotg->hptxfsiz >> 16))
+ if (val < 16 || val > hsotg->hw_params.host_perio_tx_fifo_size)
valid = 0;
if (!valid) {
@@ -2169,7 +2125,7 @@ int dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
val);
- val = hsotg->hptxfsiz >> 16;
+ val = hsotg->hw_params.host_perio_tx_fifo_size;
dev_dbg(hsotg->dev, "Setting host_perio_tx_fifo_size to %d\n",
val);
retval = -EINVAL;
@@ -2183,11 +2139,8 @@ int dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val)
{
int valid = 1;
int retval = 0;
- int width = hsotg->hwcfg3 >> GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT &
- GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK >>
- GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
- if (val < 2047 || val >= (1 << (width + 11)))
+ if (val < 2047 || val > hsotg->hw_params.max_transfer_size)
valid = 0;
if (!valid) {
@@ -2195,7 +2148,7 @@ int dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for max_transfer_size. Check HW configuration.\n",
val);
- val = (1 << (width + 11)) - 1;
+ val = hsotg->hw_params.max_transfer_size;
dev_dbg(hsotg->dev, "Setting max_transfer_size to %d\n", val);
retval = -EINVAL;
}
@@ -2208,11 +2161,8 @@ int dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val)
{
int valid = 1;
int retval = 0;
- int width = hsotg->hwcfg3 >> GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT &
- GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK >>
- GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
- if (val < 15 || val > (1 << (width + 4)))
+ if (val < 15 || val > hsotg->hw_params.max_packet_count)
valid = 0;
if (!valid) {
@@ -2220,7 +2170,7 @@ int dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for max_packet_count. Check HW configuration.\n",
val);
- val = (1 << (width + 4)) - 1;
+ val = hsotg->hw_params.max_packet_count;
dev_dbg(hsotg->dev, "Setting max_packet_count to %d\n", val);
retval = -EINVAL;
}
@@ -2233,10 +2183,8 @@ int dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val)
{
int valid = 1;
int retval = 0;
- int num_chan = hsotg->hwcfg2 >> GHWCFG2_NUM_HOST_CHAN_SHIFT &
- GHWCFG2_NUM_HOST_CHAN_MASK >> GHWCFG2_NUM_HOST_CHAN_SHIFT;
- if (val < 1 || val > num_chan + 1)
+ if (val < 1 || val > hsotg->hw_params.host_channels)
valid = 0;
if (!valid) {
@@ -2244,7 +2192,7 @@ int dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for host_channels. Check HW configuration.\n",
val);
- val = num_chan + 1;
+ val = hsotg->hw_params.host_channels;
dev_dbg(hsotg->dev, "Setting host_channels to %d\n", val);
retval = -EINVAL;
}
@@ -2257,8 +2205,7 @@ int dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val)
{
#ifndef NO_FS_PHY_HW_CHECKS
int valid = 0;
- u32 hs_phy_type;
- u32 fs_phy_type;
+ u32 hs_phy_type, fs_phy_type;
#endif
int retval = 0;
@@ -2279,9 +2226,8 @@ int dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val)
}
#ifndef NO_FS_PHY_HW_CHECKS
- hs_phy_type = hsotg->hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK;
- fs_phy_type = hsotg->hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK;
-
+ hs_phy_type = hsotg->hw_params.hs_phy_type;
+ fs_phy_type = hsotg->hw_params.fs_phy_type;
if (val == DWC2_PHY_TYPE_PARAM_UTMI &&
(hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI ||
hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI))
@@ -2430,14 +2376,29 @@ int dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val)
int dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val)
{
+ int valid = 0;
int retval = 0;
- if (DWC2_PARAM_TEST(val, 8, 8) && DWC2_PARAM_TEST(val, 16, 16)) {
+ switch (hsotg->hw_params.utmi_phy_data_width) {
+ case GHWCFG4_UTMI_PHY_DATA_WIDTH_8:
+ valid = (val == 8);
+ break;
+ case GHWCFG4_UTMI_PHY_DATA_WIDTH_16:
+ valid = (val == 16);
+ break;
+ case GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16:
+ valid = (val == 8 || val == 16);
+ break;
+ }
+
+ if (!valid) {
if (val >= 0) {
- dev_err(hsotg->dev, "Wrong value for phy_utmi_width\n");
- dev_err(hsotg->dev, "phy_utmi_width must be 8 or 16\n");
+ dev_err(hsotg->dev,
+ "%d invalid for phy_utmi_width. Check HW configuration.\n",
+ val);
}
- val = 8;
+ val = (hsotg->hw_params.utmi_phy_data_width ==
+ GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16;
dev_dbg(hsotg->dev, "Setting phy_utmi_width to %d\n", val);
retval = -EINVAL;
}
@@ -2505,7 +2466,7 @@ int dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val)
}
#ifndef NO_FS_PHY_HW_CHECKS
- if (val == 1 && !(hsotg->hwcfg3 & GHWCFG3_I2C))
+ if (val == 1 && !(hsotg->hw_params.i2c_enable))
valid = 0;
if (!valid) {
@@ -2513,7 +2474,7 @@ int dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for i2c_enable. Check HW configuration.\n",
val);
- val = !!(hsotg->hwcfg3 & GHWCFG3_I2C);
+ val = hsotg->hw_params.i2c_enable;
dev_dbg(hsotg->dev, "Setting i2c_enable to %d\n", val);
retval = -EINVAL;
}
@@ -2538,7 +2499,7 @@ int dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg, int val)
valid = 0;
}
- if (val == 1 && !(hsotg->hwcfg4 & GHWCFG4_DED_FIFO_EN))
+ if (val == 1 && !hsotg->hw_params.en_multiple_tx_fifo)
valid = 0;
if (!valid) {
@@ -2546,7 +2507,7 @@ int dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
val);
- val = !!(hsotg->hwcfg4 & GHWCFG4_DED_FIFO_EN);
+ val = hsotg->hw_params.en_multiple_tx_fifo;
dev_dbg(hsotg->dev, "Setting en_multiple_tx_fifo to %d\n", val);
retval = -EINVAL;
}
@@ -2569,7 +2530,7 @@ int dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val)
valid = 0;
}
- if (val == 1 && hsotg->snpsid < DWC2_CORE_REV_2_92a)
+ if (val == 1 && hsotg->hw_params.snpsid < DWC2_CORE_REV_2_92a)
valid = 0;
if (!valid) {
@@ -2577,7 +2538,7 @@ int dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val)
dev_err(hsotg->dev,
"%d invalid for parameter reload_ctl. Check HW configuration.\n",
val);
- val = hsotg->snpsid >= DWC2_CORE_REV_2_92a;
+ val = hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_92a;
dev_dbg(hsotg->dev, "Setting reload_ctl to %d\n", val);
retval = -EINVAL;
}
@@ -2586,35 +2547,14 @@ int dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val)
return retval;
}
-int dwc2_set_param_ahb_single(struct dwc2_hsotg *hsotg, int val)
+int dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val)
{
- int valid = 1;
- int retval = 0;
-
- if (DWC2_PARAM_TEST(val, 0, 1)) {
- if (val >= 0) {
- dev_err(hsotg->dev,
- "'%d' invalid for parameter ahb_single\n", val);
- dev_err(hsotg->dev, "ahb_single must be 0 or 1\n");
- }
- valid = 0;
- }
-
- if (val > 0 && hsotg->snpsid < DWC2_CORE_REV_2_94a)
- valid = 0;
-
- if (!valid) {
- if (val >= 0)
- dev_err(hsotg->dev,
- "%d invalid for parameter ahb_single. Check HW configuration.\n",
- val);
- val = 0;
- dev_dbg(hsotg->dev, "Setting ahb_single to %d\n", val);
- retval = -EINVAL;
- }
-
- hsotg->core_params->ahb_single = val;
- return retval;
+ if (val != -1)
+ hsotg->core_params->ahbcfg = val;
+ else
+ hsotg->core_params->ahbcfg = GAHBCFG_HBSTLEN_INCR4 <<
+ GAHBCFG_HBSTLEN_SHIFT;
+ return 0;
}
int dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val)
@@ -2637,6 +2577,165 @@ int dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val)
return retval;
}
+/**
+ * During device initialization, read various hardware configuration
+ * registers and interpret the contents.
+ */
+int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_hw_params *hw = &hsotg->hw_params;
+ unsigned width;
+ u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
+ u32 hptxfsiz, grxfsiz, gnptxfsiz;
+ u32 gusbcfg;
+
+ /*
+ * Attempt to ensure this device is really a DWC_otg Controller.
+ * Read and verify the GSNPSID register contents. The value should be
+ * 0x45f42xxx or 0x45f43xxx, which corresponds to either "OT2" or "OT3",
+ * as in "OTG version 2.xx" or "OTG version 3.xx".
+ */
+ hw->snpsid = readl(hsotg->regs + GSNPSID);
+ if ((hw->snpsid & 0xfffff000) != 0x4f542000 &&
+ (hw->snpsid & 0xfffff000) != 0x4f543000) {
+ dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
+ hw->snpsid);
+ return -ENODEV;
+ }
+
+ dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
+ hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
+ hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
+
+ hwcfg1 = readl(hsotg->regs + GHWCFG1);
+ hwcfg2 = readl(hsotg->regs + GHWCFG2);
+ hwcfg3 = readl(hsotg->regs + GHWCFG3);
+ hwcfg4 = readl(hsotg->regs + GHWCFG4);
+ gnptxfsiz = readl(hsotg->regs + GNPTXFSIZ);
+ grxfsiz = readl(hsotg->regs + GRXFSIZ);
+
+ dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hwcfg1);
+ dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hwcfg2);
+ dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hwcfg3);
+ dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4);
+ dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
+ dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz);
+
+ /* Force host mode to get HPTXFSIZ exact power on value */
+ gusbcfg = readl(hsotg->regs + GUSBCFG);
+ gusbcfg |= GUSBCFG_FORCEHOSTMODE;
+ writel(gusbcfg, hsotg->regs + GUSBCFG);
+ usleep_range(100000, 150000);
+
+ hptxfsiz = readl(hsotg->regs + HPTXFSIZ);
+ dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz);
+ gusbcfg = readl(hsotg->regs + GUSBCFG);
+ gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
+ writel(gusbcfg, hsotg->regs + GUSBCFG);
+ usleep_range(100000, 150000);
+
+ /* hwcfg2 */
+ hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >>
+ GHWCFG2_OP_MODE_SHIFT;
+ hw->arch = (hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) >>
+ GHWCFG2_ARCHITECTURE_SHIFT;
+ hw->enable_dynamic_fifo = !!(hwcfg2 & GHWCFG2_DYNAMIC_FIFO);
+ hw->host_channels = 1 + ((hwcfg2 & GHWCFG2_NUM_HOST_CHAN_MASK) >>
+ GHWCFG2_NUM_HOST_CHAN_SHIFT);
+ hw->hs_phy_type = (hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK) >>
+ GHWCFG2_HS_PHY_TYPE_SHIFT;
+ hw->fs_phy_type = (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) >>
+ GHWCFG2_FS_PHY_TYPE_SHIFT;
+ hw->num_dev_ep = (hwcfg2 & GHWCFG2_NUM_DEV_EP_MASK) >>
+ GHWCFG2_NUM_DEV_EP_SHIFT;
+ hw->nperio_tx_q_depth =
+ (hwcfg2 & GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK) >>
+ GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT << 1;
+ hw->host_perio_tx_q_depth =
+ (hwcfg2 & GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK) >>
+ GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT << 1;
+ hw->dev_token_q_depth =
+ (hwcfg2 & GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK) >>
+ GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT;
+
+ /* hwcfg3 */
+ width = (hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK) >>
+ GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
+ hw->max_transfer_size = (1 << (width + 11)) - 1;
+ width = (hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK) >>
+ GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
+ hw->max_packet_count = (1 << (width + 4)) - 1;
+ hw->i2c_enable = !!(hwcfg3 & GHWCFG3_I2C);
+ hw->total_fifo_size = (hwcfg3 & GHWCFG3_DFIFO_DEPTH_MASK) >>
+ GHWCFG3_DFIFO_DEPTH_SHIFT;
+
+ /* hwcfg4 */
+ hw->en_multiple_tx_fifo = !!(hwcfg4 & GHWCFG4_DED_FIFO_EN);
+ hw->num_dev_perio_in_ep = (hwcfg4 & GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK) >>
+ GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT;
+ hw->dma_desc_enable = !!(hwcfg4 & GHWCFG4_DESC_DMA);
+ hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ);
+ hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >>
+ GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
+
+ /* fifo sizes */
+ hw->host_rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
+ GRXFSIZ_DEPTH_SHIFT;
+ hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+ FIFOSIZE_DEPTH_SHIFT;
+ hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+ FIFOSIZE_DEPTH_SHIFT;
+
+ dev_dbg(hsotg->dev, "Detected values from hardware:\n");
+ dev_dbg(hsotg->dev, " op_mode=%d\n",
+ hw->op_mode);
+ dev_dbg(hsotg->dev, " arch=%d\n",
+ hw->arch);
+ dev_dbg(hsotg->dev, " dma_desc_enable=%d\n",
+ hw->dma_desc_enable);
+ dev_dbg(hsotg->dev, " power_optimized=%d\n",
+ hw->power_optimized);
+ dev_dbg(hsotg->dev, " i2c_enable=%d\n",
+ hw->i2c_enable);
+ dev_dbg(hsotg->dev, " hs_phy_type=%d\n",
+ hw->hs_phy_type);
+ dev_dbg(hsotg->dev, " fs_phy_type=%d\n",
+ hw->fs_phy_type);
+ dev_dbg(hsotg->dev, " utmi_phy_data_wdith=%d\n",
+ hw->utmi_phy_data_width);
+ dev_dbg(hsotg->dev, " num_dev_ep=%d\n",
+ hw->num_dev_ep);
+ dev_dbg(hsotg->dev, " num_dev_perio_in_ep=%d\n",
+ hw->num_dev_perio_in_ep);
+ dev_dbg(hsotg->dev, " host_channels=%d\n",
+ hw->host_channels);
+ dev_dbg(hsotg->dev, " max_transfer_size=%d\n",
+ hw->max_transfer_size);
+ dev_dbg(hsotg->dev, " max_packet_count=%d\n",
+ hw->max_packet_count);
+ dev_dbg(hsotg->dev, " nperio_tx_q_depth=0x%0x\n",
+ hw->nperio_tx_q_depth);
+ dev_dbg(hsotg->dev, " host_perio_tx_q_depth=0x%0x\n",
+ hw->host_perio_tx_q_depth);
+ dev_dbg(hsotg->dev, " dev_token_q_depth=0x%0x\n",
+ hw->dev_token_q_depth);
+ dev_dbg(hsotg->dev, " enable_dynamic_fifo=%d\n",
+ hw->enable_dynamic_fifo);
+ dev_dbg(hsotg->dev, " en_multiple_tx_fifo=%d\n",
+ hw->en_multiple_tx_fifo);
+ dev_dbg(hsotg->dev, " total_fifo_size=%d\n",
+ hw->total_fifo_size);
+ dev_dbg(hsotg->dev, " host_rx_fifo_size=%d\n",
+ hw->host_rx_fifo_size);
+ dev_dbg(hsotg->dev, " host_nperio_tx_fifo_size=%d\n",
+ hw->host_nperio_tx_fifo_size);
+ dev_dbg(hsotg->dev, " host_perio_tx_fifo_size=%d\n",
+ hw->host_perio_tx_fifo_size);
+ dev_dbg(hsotg->dev, "\n");
+
+ return 0;
+}
+
/*
* This function is called during module intialization to pass module parameters
* for the DWC_otg core. It returns non-0 if any parameters are invalid.
@@ -2681,7 +2780,7 @@ int dwc2_set_parameters(struct dwc2_hsotg *hsotg,
retval |= dwc2_set_param_en_multiple_tx_fifo(hsotg,
params->en_multiple_tx_fifo);
retval |= dwc2_set_param_reload_ctl(hsotg, params->reload_ctl);
- retval |= dwc2_set_param_ahb_single(hsotg, params->ahb_single);
+ retval |= dwc2_set_param_ahbcfg(hsotg, params->ahbcfg);
retval |= dwc2_set_param_otg_ver(hsotg, params->otg_ver);
return retval;
diff --git a/drivers/staging/dwc2/core.h b/drivers/staging/dwc2/core.h
index fc075a7c1de..9102f66d011 100644
--- a/drivers/staging/dwc2/core.h
+++ b/drivers/staging/dwc2/core.h
@@ -68,16 +68,18 @@ enum dwc2_lx_state {
/**
* struct dwc2_core_params - Parameters for configuring the core
*
- * @otg_cap: Specifies the OTG capabilities. The driver will
- * automatically detect the value for this parameter if
- * none is specified.
- * 0 - HNP and SRP capable (default)
+ * @otg_cap: Specifies the OTG capabilities.
+ * 0 - HNP and SRP capable
* 1 - SRP Only capable
- * 2 - No HNP/SRP capable
+ * 2 - No HNP/SRP capable (always available)
+ * Defaults to best available option (0, 1, then 2)
+ * @otg_ver: OTG version supported
+ * 0 - 1.3 (default)
+ * 1 - 2.0
* @dma_enable: Specifies whether to use slave or DMA mode for accessing
* the data FIFOs. The driver will automatically detect the
* value for this parameter if none is specified.
- * 0 - Slave
+ * 0 - Slave (always available)
* 1 - DMA (default, if available)
* @dma_desc_enable: When DMA mode is enabled, specifies whether to use
* address DMA mode or descriptor DMA mode for accessing
@@ -88,39 +90,47 @@ enum dwc2_lx_state {
* @speed: Specifies the maximum speed of operation in host and
* device mode. The actual speed depends on the speed of
* the attached device and the value of phy_type.
- * 0 - High Speed (default)
+ * 0 - High Speed
+ * (default when phy_type is UTMI+ or ULPI)
* 1 - Full Speed
- * @host_support_fs_ls_low_power: Specifies whether low power mode is supported
- * when attached to a Full Speed or Low Speed device in
- * host mode.
- * 0 - Don't support low power mode (default)
- * 1 - Support low power mode
- * @host_ls_low_power_phy_clk: Specifies the PHY clock rate in low power mode
- * when connected to a Low Speed device in host mode. This
- * parameter is applicable only if
- * host_support_fs_ls_low_power is enabled. If phy_type is
- * set to FS then defaults to 6 MHZ otherwise 48 MHZ.
- * 0 - 48 MHz
- * 1 - 6 MHz
+ * (default when phy_type is Full Speed)
* @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters
- * 1 - Allow dynamic FIFO sizing (default)
+ * 1 - Allow dynamic FIFO sizing (default, if available)
+ * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
+ * are enabled
* @host_rx_fifo_size: Number of 4-byte words in the Rx FIFO in host mode when
* dynamic FIFO sizing is enabled
- * 16 to 32768 (default 1024)
+ * 16 to 32768
+ * Actual maximum value is autodetected and also
+ * the default.
* @host_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO
* in host mode when dynamic FIFO sizing is enabled
- * 16 to 32768 (default 1024)
+ * 16 to 32768
+ * Actual maximum value is autodetected and also
+ * the default.
* @host_perio_tx_fifo_size: Number of 4-byte words in the periodic Tx FIFO in
* host mode when dynamic FIFO sizing is enabled
- * 16 to 32768 (default 1024)
+ * 16 to 32768
+ * Actual maximum value is autodetected and also
+ * the default.
* @max_transfer_size: The maximum transfer size supported, in bytes
- * 2047 to 65,535 (default 65,535)
+ * 2047 to 65,535
+ * Actual maximum value is autodetected and also
+ * the default.
* @max_packet_count: The maximum number of packets in a transfer
- * 15 to 511 (default 511)
+ * 15 to 511
+ * Actual maximum value is autodetected and also
+ * the default.
* @host_channels: The number of host channel registers to use
- * 1 to 16 (default 12)
+ * 1 to 16
+ * Actual maximum value is autodetected and also
+ * the default.
* @phy_type: Specifies the type of PHY interface to use. By default,
* the driver will automatically detect the phy_type.
+ * 0 - Full Speed Phy
+ * 1 - UTMI+ Phy
+ * 2 - ULPI Phy
+ * Defaults to best available option (2, 1, then 0)
* @phy_utmi_width: Specifies the UTMI+ Data Width (in bits). This parameter
* is applicable for a phy_type of UTMI+ or ULPI. (For a
* ULPI phy_type, this parameter indicates the data width
@@ -129,7 +139,7 @@ enum dwc2_lx_state {
* parameter was set to "8 and 16 bits", meaning that the
* core has been configured to work at either data path
* width.
- * 8 or 16 (default 16)
+ * 8 or 16 (default 16 if available)
* @phy_ulpi_ddr: Specifies whether the ULPI operates at double or single
* data rate. This parameter is only applicable if phy_type
* is ULPI.
@@ -139,27 +149,51 @@ enum dwc2_lx_state {
* data bus
* @phy_ulpi_ext_vbus: For a ULPI phy, specifies whether to use the internal or
* external supply to drive the VBus
+ * 0 - Internal supply (default)
+ * 1 - External supply
* @i2c_enable: Specifies whether to use the I2Cinterface for a full
* speed PHY. This parameter is only applicable if phy_type
* is FS.
* 0 - No (default)
* 1 - Yes
- * @ulpi_fs_ls: True to make ULPI phy operate in FS/LS mode only
- * @ts_dline: True to enable Term Select Dline pulsing
- * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
- * are enabled
- * @reload_ctl: True to allow dynamic reloading of HFIR register during
- * runtime
- * @ahb_single: This bit enables SINGLE transfers for remainder data in
- * a transfer for DMA mode of operation.
- * 0 - remainder data will be sent using INCR burst size
- * 1 - remainder data will be sent using SINGLE burst size
- * @otg_ver: OTG version supported
- * 0 - 1.3
- * 1 - 2.0
+ * @ulpi_fs_ls: Make ULPI phy operate in FS/LS mode only
+ * 0 - No (default)
+ * 1 - Yes
+ * @host_support_fs_ls_low_power: Specifies whether low power mode is supported
+ * when attached to a Full Speed or Low Speed device in
+ * host mode.
+ * 0 - Don't support low power mode (default)
+ * 1 - Support low power mode
+ * @host_ls_low_power_phy_clk: Specifies the PHY clock rate in low power mode
+ * when connected to a Low Speed device in host
+ * mode. This parameter is applicable only if
+ * host_support_fs_ls_low_power is enabled.
+ * 0 - 48 MHz
+ * (default when phy_type is UTMI+ or ULPI)
+ * 1 - 6 MHz
+ * (default when phy_type is Full Speed)
+ * @ts_dline: Enable Term Select Dline pulsing
+ * 0 - No (default)
+ * 1 - Yes
+ * @reload_ctl: Allow dynamic reloading of HFIR register during runtime
+ * 0 - No (default for core < 2.92a)
+ * 1 - Yes (default for core >= 2.92a)
+ * @ahbcfg: This field allows the default value of the GAHBCFG
+ * register to be overridden
+ * -1 - GAHBCFG value will be set to 0x06
+ * (INCR4, default)
+ * all others - GAHBCFG value will be overridden with
+ * this value
+ * Not all bits can be controlled like this, the
+ * bits defined by GAHBCFG_CTRL_MASK are controlled
+ * by the driver and are ignored in this
+ * configuration value.
*
* The following parameters may be specified when starting the module. These
- * parameters define how the DWC_otg controller should be configured.
+ * parameters define how the DWC_otg controller should be configured. A
+ * value of -1 (or any other out of range value) for any parameter means
+ * to read the value from hardware (if possible) or use the builtin
+ * default described above.
*/
struct dwc2_core_params {
/*
@@ -189,7 +223,85 @@ struct dwc2_core_params {
int host_ls_low_power_phy_clk;
int ts_dline;
int reload_ctl;
- int ahb_single;
+ int ahbcfg;
+};
+
+/**
+ * struct dwc2_hw_params - Autodetected parameters.
+ *
+ * These parameters are the various parameters read from hardware
+ * registers during initialization. They typically contain the best
+ * supported or maximum value that can be configured in the
+ * corresponding dwc2_core_params value.
+ *
+ * The values that are not in dwc2_core_params are documented below.
+ *
+ * @op_mode Mode of Operation
+ * 0 - HNP- and SRP-Capable OTG (Host & Device)
+ * 1 - SRP-Capable OTG (Host & Device)
+ * 2 - Non-HNP and Non-SRP Capable OTG (Host & Device)
+ * 3 - SRP-Capable Device
+ * 4 - Non-OTG Device
+ * 5 - SRP-Capable Host
+ * 6 - Non-OTG Host
+ * @arch Architecture
+ * 0 - Slave only
+ * 1 - External DMA
+ * 2 - Internal DMA
+ * @power_optimized Are power optimizations enabled?
+ * @num_dev_ep Number of device endpoints available
+ * @num_dev_perio_in_ep Number of device periodic IN endpoints
+ * avaialable
+ * @dev_token_q_depth Device Mode IN Token Sequence Learning Queue
+ * Depth
+ * 0 to 30
+ * @host_perio_tx_q_depth
+ * Host Mode Periodic Request Queue Depth
+ * 2, 4 or 8
+ * @nperio_tx_q_depth
+ * Non-Periodic Request Queue Depth
+ * 2, 4 or 8
+ * @hs_phy_type High-speed PHY interface type
+ * 0 - High-speed interface not supported
+ * 1 - UTMI+
+ * 2 - ULPI
+ * 3 - UTMI+ and ULPI
+ * @fs_phy_type Full-speed PHY interface type
+ * 0 - Full speed interface not supported
+ * 1 - Dedicated full speed interface
+ * 2 - FS pins shared with UTMI+ pins
+ * 3 - FS pins shared with ULPI pins
+ * @total_fifo_size: Total internal RAM for FIFOs (bytes)
+ * @utmi_phy_data_width UTMI+ PHY data width
+ * 0 - 8 bits
+ * 1 - 16 bits
+ * 2 - 8 or 16 bits
+ * @snpsid: Value from SNPSID register
+ */
+struct dwc2_hw_params {
+ unsigned op_mode:3;
+ unsigned arch:2;
+ unsigned dma_desc_enable:1;
+ unsigned enable_dynamic_fifo:1;
+ unsigned en_multiple_tx_fifo:1;
+ unsigned host_rx_fifo_size:16;
+ unsigned host_nperio_tx_fifo_size:16;
+ unsigned host_perio_tx_fifo_size:16;
+ unsigned nperio_tx_q_depth:3;
+ unsigned host_perio_tx_q_depth:3;
+ unsigned dev_token_q_depth:5;
+ unsigned max_transfer_size:26;
+ unsigned max_packet_count:11;
+ unsigned host_channels:4;
+ unsigned hs_phy_type:2;
+ unsigned fs_phy_type:2;
+ unsigned i2c_enable:1;
+ unsigned num_dev_ep:4;
+ unsigned num_dev_perio_in_ep:4;
+ unsigned total_fifo_size:16;
+ unsigned power_optimized:1;
+ unsigned utmi_phy_data_width:2;
+ u32 snpsid;
};
/**
@@ -199,15 +311,8 @@ struct dwc2_core_params {
* @dev: The struct device pointer
* @regs: Pointer to controller regs
* @core_params: Parameters that define how the core should be configured
- * @hwcfg1: Hardware Configuration - stored here for convenience
- * @hwcfg2: Hardware Configuration - stored here for convenience
- * @hwcfg3: Hardware Configuration - stored here for convenience
- * @hwcfg4: Hardware Configuration - stored here for convenience
- * @hptxfsiz: Hardware Configuration - stored here for convenience
- * @snpsid: Value from SNPSID register
- * @total_fifo_size: Total internal RAM for FIFOs (bytes)
- * @rx_fifo_size: Size of Rx FIFO (bytes)
- * @nperio_tx_fifo_size: Size of Non-periodic Tx FIFO (Bytes)
+ * @hw_params: Parameters that were autodetected from the
+ * hardware registers
* @op_state: The operational State, during transitions (a_host=>
* a_peripheral and b_device=>b_host) this may not match
* the core, but allows the software to determine
@@ -295,16 +400,10 @@ struct dwc2_core_params {
struct dwc2_hsotg {
struct device *dev;
void __iomem *regs;
+ /** Params detected from hardware */
+ struct dwc2_hw_params hw_params;
+ /** Params to actually use */
struct dwc2_core_params *core_params;
- u32 hwcfg1;
- u32 hwcfg2;
- u32 hwcfg3;
- u32 hwcfg4;
- u32 hptxfsiz;
- u32 snpsid;
- u16 total_fifo_size;
- u16 rx_fifo_size;
- u16 nperio_tx_fifo_size;
enum usb_otg_state op_state;
unsigned int queuing_high_bandwidth:1;
@@ -643,7 +742,7 @@ extern int dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg,
extern int dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val);
-extern int dwc2_set_param_ahb_single(struct dwc2_hsotg *hsotg, int val);
+extern int dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val);
extern int dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val);
diff --git a/drivers/staging/dwc2/core_intr.c b/drivers/staging/dwc2/core_intr.c
index 98c51bba662..07cfa2f6aa2 100644
--- a/drivers/staging/dwc2/core_intr.c
+++ b/drivers/staging/dwc2/core_intr.c
@@ -166,7 +166,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
* WA for 3.00a- HW is not setting cur_mode, even sometimes
* this does not help
*/
- if (hsotg->snpsid >= DWC2_CORE_REV_3_00a)
+ if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)
udelay(100);
if (gotgctl & GOTGCTL_HSTNEGSCS) {
if (dwc2_is_host_mode(hsotg)) {
@@ -380,7 +380,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev,
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
!!(dsts & DSTS_SUSPSTS),
- !!(hsotg->hwcfg4 & GHWCFG4_POWER_OPTIMIZ));
+ hsotg->hw_params.power_optimized);
} else {
if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
diff --git a/drivers/staging/dwc2/hcd.c b/drivers/staging/dwc2/hcd.c
index 2ed54b172a3..da0d35cc33c 100644
--- a/drivers/staging/dwc2/hcd.c
+++ b/drivers/staging/dwc2/hcd.c
@@ -134,11 +134,8 @@ static void dwc2_kill_urbs_in_qh_list(struct dwc2_hsotg *hsotg,
list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
qtd_list_entry) {
- if (qtd->urb != NULL) {
- dwc2_host_complete(hsotg, qtd->urb->priv,
- qtd->urb, -ETIMEDOUT);
- dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
- }
+ dwc2_host_complete(hsotg, qtd, -ETIMEDOUT);
+ dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
}
}
}
@@ -421,6 +418,8 @@ static int dwc2_hcd_urb_dequeue(struct dwc2_hsotg *hsotg,
return -EINVAL;
}
+ urb->priv = NULL;
+
if (urb_qtd->in_process && qh->channel) {
dwc2_dump_channel_info(hsotg, qh->channel);
@@ -1006,10 +1005,10 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
tx_status = readl(hsotg->regs + HPTXSTS);
- qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
- TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
- fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
- TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+ TXSTS_QSPCAVAIL_SHIFT;
+ fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+ TXSTS_FSPCAVAIL_SHIFT;
if (dbg_perio()) {
dev_vdbg(hsotg->dev, " P Tx Req Queue Space Avail (before queue): %d\n",
@@ -1021,7 +1020,9 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
qh_ptr = hsotg->periodic_sched_assigned.next;
while (qh_ptr != &hsotg->periodic_sched_assigned) {
tx_status = readl(hsotg->regs + HPTXSTS);
- if ((tx_status & TXSTS_QSPCAVAIL_MASK) == 0) {
+ qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+ TXSTS_QSPCAVAIL_SHIFT;
+ if (qspcavail == 0) {
no_queue_space = 1;
break;
}
@@ -1047,8 +1048,8 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
qh->channel->multi_count > 1)
hsotg->queuing_high_bandwidth = 1;
- fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
- TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+ TXSTS_FSPCAVAIL_SHIFT;
status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
if (status < 0) {
no_fifo_space = 1;
@@ -1079,10 +1080,10 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
if (hsotg->core_params->dma_enable <= 0) {
tx_status = readl(hsotg->regs + HPTXSTS);
- qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
- TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
- fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
- TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+ TXSTS_QSPCAVAIL_SHIFT;
+ fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+ TXSTS_FSPCAVAIL_SHIFT;
if (dbg_perio()) {
dev_vdbg(hsotg->dev,
" P Tx Req Queue Space Avail (after queue): %d\n",
@@ -1144,10 +1145,10 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
dev_vdbg(hsotg->dev, "Queue non-periodic transactions\n");
tx_status = readl(hsotg->regs + GNPTXSTS);
- qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
- TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
- fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
- TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+ TXSTS_QSPCAVAIL_SHIFT;
+ fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+ TXSTS_FSPCAVAIL_SHIFT;
dev_vdbg(hsotg->dev, " NP Tx Req Queue Space Avail (before queue): %d\n",
qspcavail);
dev_vdbg(hsotg->dev, " NP Tx FIFO Space Avail (before queue): %d\n",
@@ -1167,8 +1168,8 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
*/
do {
tx_status = readl(hsotg->regs + GNPTXSTS);
- qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
- TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
+ qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+ TXSTS_QSPCAVAIL_SHIFT;
if (hsotg->core_params->dma_enable <= 0 && qspcavail == 0) {
no_queue_space = 1;
break;
@@ -1183,8 +1184,8 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
if (qh->tt_buffer_dirty)
goto next;
- fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
- TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+ TXSTS_FSPCAVAIL_SHIFT;
status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
if (status > 0) {
@@ -1204,10 +1205,10 @@ next:
if (hsotg->core_params->dma_enable <= 0) {
tx_status = readl(hsotg->regs + GNPTXSTS);
- qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
- TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
- fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
- TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+ TXSTS_QSPCAVAIL_SHIFT;
+ fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+ TXSTS_FSPCAVAIL_SHIFT;
dev_vdbg(hsotg->dev,
" NP Tx Req Queue Space Avail (after queue): %d\n",
qspcavail);
@@ -1613,7 +1614,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
if (hprt0 & HPRT0_PWR)
port_status |= USB_PORT_STAT_POWER;
- speed = hprt0 & HPRT0_SPD_MASK;
+ speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
if (speed == HPRT0_SPD_HIGH_SPEED)
port_status |= USB_PORT_STAT_HIGH_SPEED;
else if (speed == HPRT0_SPD_LOW_SPEED)
@@ -1762,11 +1763,9 @@ int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
#ifdef DWC2_DEBUG_SOF
dev_vdbg(hsotg->dev, "DWC OTG HCD GET FRAME NUMBER %d\n",
- hfnum >> HFNUM_FRNUM_SHIFT &
- HFNUM_FRNUM_MASK >> HFNUM_FRNUM_SHIFT);
+ (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT);
#endif
- return hfnum >> HFNUM_FRNUM_SHIFT &
- HFNUM_FRNUM_MASK >> HFNUM_FRNUM_SHIFT;
+ return (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
}
int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg)
@@ -1917,18 +1916,14 @@ void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, " periodic_usecs: %d\n", hsotg->periodic_usecs);
np_tx_status = readl(hsotg->regs + GNPTXSTS);
dev_dbg(hsotg->dev, " NP Tx Req Queue Space Avail: %d\n",
- np_tx_status >> TXSTS_QSPCAVAIL_SHIFT &
- TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT);
+ (np_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
dev_dbg(hsotg->dev, " NP Tx FIFO Space Avail: %d\n",
- np_tx_status >> TXSTS_FSPCAVAIL_SHIFT &
- TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT);
+ (np_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
p_tx_status = readl(hsotg->regs + HPTXSTS);
dev_dbg(hsotg->dev, " P Tx Req Queue Space Avail: %d\n",
- p_tx_status >> TXSTS_QSPCAVAIL_SHIFT &
- TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT);
+ (p_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
dev_dbg(hsotg->dev, " P Tx FIFO Space Avail: %d\n",
- p_tx_status >> TXSTS_FSPCAVAIL_SHIFT &
- TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT);
+ (p_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
dwc2_hcd_dump_frrem(hsotg);
dwc2_dump_global_registers(hsotg);
dwc2_dump_host_registers(hsotg);
@@ -2088,23 +2083,29 @@ static void dwc2_free_bus_bandwidth(struct usb_hcd *hcd, u16 bw,
*
* Must be called with interrupt disabled and spinlock held
*/
-void dwc2_host_complete(struct dwc2_hsotg *hsotg, void *context,
- struct dwc2_hcd_urb *dwc2_urb, int status)
+void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
+ int status)
{
- struct urb *urb = context;
+ struct urb *urb;
int i;
- if (!urb) {
- dev_dbg(hsotg->dev, "## %s: context is NULL ##\n", __func__);
+ if (!qtd) {
+ dev_dbg(hsotg->dev, "## %s: qtd is NULL ##\n", __func__);
return;
}
- if (!dwc2_urb) {
- dev_dbg(hsotg->dev, "## %s: dwc2_urb is NULL ##\n", __func__);
+ if (!qtd->urb) {
+ dev_dbg(hsotg->dev, "## %s: qtd->urb is NULL ##\n", __func__);
+ return;
+ }
+
+ urb = qtd->urb->priv;
+ if (!urb) {
+ dev_dbg(hsotg->dev, "## %s: urb->priv is NULL ##\n", __func__);
return;
}
- urb->actual_length = dwc2_hcd_urb_get_actual_length(dwc2_urb);
+ urb->actual_length = dwc2_hcd_urb_get_actual_length(qtd->urb);
if (dbg_urb(urb))
dev_vdbg(hsotg->dev,
@@ -2121,18 +2122,17 @@ void dwc2_host_complete(struct dwc2_hsotg *hsotg, void *context,
}
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
- urb->error_count = dwc2_hcd_urb_get_error_count(dwc2_urb);
+ urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb);
for (i = 0; i < urb->number_of_packets; ++i) {
urb->iso_frame_desc[i].actual_length =
dwc2_hcd_urb_get_iso_desc_actual_length(
- dwc2_urb, i);
+ qtd->urb, i);
urb->iso_frame_desc[i].status =
- dwc2_hcd_urb_get_iso_desc_status(dwc2_urb, i);
+ dwc2_hcd_urb_get_iso_desc_status(qtd->urb, i);
}
}
urb->status = status;
- urb->hcpriv = NULL;
if (!status) {
if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
urb->actual_length < urb->transfer_buffer_length)
@@ -2149,7 +2149,10 @@ void dwc2_host_complete(struct dwc2_hsotg *hsotg, void *context,
urb);
}
- kfree(dwc2_urb);
+ usb_hcd_unlink_urb_from_ep(dwc2_hsotg_to_hcd(hsotg), urb);
+ urb->hcpriv = NULL;
+ kfree(qtd->urb);
+ qtd->urb = NULL;
spin_unlock(&hsotg->lock);
usb_hcd_giveback_urb(dwc2_hsotg_to_hcd(hsotg), urb, status);
@@ -2337,8 +2340,8 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
struct usb_host_endpoint *ep = urb->ep;
struct dwc2_hcd_urb *dwc2_urb;
int i;
+ int retval;
int alloc_bandwidth = 0;
- int retval = 0;
u8 ep_type = 0;
u32 tflags = 0;
void *buf;
@@ -2389,14 +2392,15 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
!(usb_pipein(urb->pipe))));
buf = urb->transfer_buffer;
+
if (hcd->self.uses_dma) {
- /*
- * Calculate virtual address from physical address, because
- * some class driver may not fill transfer_buffer.
- * In Buffer DMA mode virtual address is used, when handling
- * non-DWORD aligned buffers.
- */
- buf = bus_to_virt(urb->transfer_dma);
+ if (!buf && (urb->transfer_dma & 3)) {
+ dev_err(hsotg->dev,
+ "%s: unaligned transfer with no transfer_buffer",
+ __func__);
+ retval = -EINVAL;
+ goto fail1;
+ }
}
if (!(urb->transfer_flags & URB_NO_INTERRUPT))
@@ -2420,21 +2424,36 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
urb->iso_frame_desc[i].length);
urb->hcpriv = dwc2_urb;
- retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv,
- mem_flags);
- if (retval) {
- urb->hcpriv = NULL;
- kfree(dwc2_urb);
- } else {
- if (alloc_bandwidth) {
- spin_lock_irqsave(&hsotg->lock, flags);
- dwc2_allocate_bus_bandwidth(hcd,
- dwc2_hcd_get_ep_bandwidth(hsotg, ep),
- urb);
- spin_unlock_irqrestore(&hsotg->lock, flags);
- }
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ if (retval)
+ goto fail1;
+
+ retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv, mem_flags);
+ if (retval)
+ goto fail2;
+
+ if (alloc_bandwidth) {
+ spin_lock_irqsave(&hsotg->lock, flags);
+ dwc2_allocate_bus_bandwidth(hcd,
+ dwc2_hcd_get_ep_bandwidth(hsotg, ep),
+ urb);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
}
+ return 0;
+
+fail2:
+ spin_lock_irqsave(&hsotg->lock, flags);
+ dwc2_urb->priv = NULL;
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+fail1:
+ urb->hcpriv = NULL;
+ kfree(dwc2_urb);
+
return retval;
}
@@ -2445,7 +2464,7 @@ static int _dwc2_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
int status)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
- int rc = 0;
+ int rc;
unsigned long flags;
dev_dbg(hsotg->dev, "DWC OTG HCD URB Dequeue\n");
@@ -2453,6 +2472,10 @@ static int _dwc2_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
spin_lock_irqsave(&hsotg->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto out;
+
if (!urb->hcpriv) {
dev_dbg(hsotg->dev, "## urb->hcpriv is NULL ##\n");
goto out;
@@ -2460,6 +2483,8 @@ static int _dwc2_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
rc = dwc2_hcd_urb_dequeue(hsotg, urb->hcpriv);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
kfree(urb->hcpriv);
urb->hcpriv = NULL;
@@ -2653,7 +2678,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
writel(ahbcfg, hsotg->regs + GAHBCFG);
writel(0, hsotg->regs + GINTMSK);
- if (hsotg->snpsid >= DWC2_CORE_REV_3_00a) {
+ if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) {
dctl = readl(hsotg->regs + DCTL);
dctl |= DCTL_SFTDISCON;
writel(dctl, hsotg->regs + DCTL);
@@ -2690,7 +2715,7 @@ void dwc2_set_all_params(struct dwc2_core_params *params, int value)
int i;
for (i = 0; i < size; i++)
- p[i] = -1;
+ p[i] = value;
}
EXPORT_SYMBOL_GPL(dwc2_set_all_params);
@@ -2705,79 +2730,22 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
{
struct usb_hcd *hcd;
struct dwc2_host_chan *channel;
- u32 snpsid, gusbcfg, hcfg;
+ u32 hcfg;
int i, num_channels;
- int retval = -ENOMEM;
+ int retval;
dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
- /*
- * Attempt to ensure this device is really a DWC_otg Controller.
- * Read and verify the GSNPSID register contents. The value should be
- * 0x45f42xxx or 0x45f43xxx, which corresponds to either "OT2" or "OT3",
- * as in "OTG version 2.xx" or "OTG version 3.xx".
- */
- snpsid = readl(hsotg->regs + GSNPSID);
- if ((snpsid & 0xfffff000) != 0x4f542000 &&
- (snpsid & 0xfffff000) != 0x4f543000) {
- dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n", snpsid);
- retval = -ENODEV;
- goto error1;
- }
+ /* Detect config values from hardware */
+ retval = dwc2_get_hwparams(hsotg);
- /*
- * Store the contents of the hardware configuration registers here for
- * easy access later
- */
- hsotg->hwcfg1 = readl(hsotg->regs + GHWCFG1);
- hsotg->hwcfg2 = readl(hsotg->regs + GHWCFG2);
- hsotg->hwcfg3 = readl(hsotg->regs + GHWCFG3);
- hsotg->hwcfg4 = readl(hsotg->regs + GHWCFG4);
-
- dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hsotg->hwcfg1);
- dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hsotg->hwcfg2);
- dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hsotg->hwcfg3);
- dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hsotg->hwcfg4);
-
- /* Force host mode to get HPTXFSIZ exact power on value */
- gusbcfg = readl(hsotg->regs + GUSBCFG);
- gusbcfg |= GUSBCFG_FORCEHOSTMODE;
- writel(gusbcfg, hsotg->regs + GUSBCFG);
- usleep_range(100000, 150000);
-
- hsotg->hptxfsiz = readl(hsotg->regs + HPTXFSIZ);
- dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hsotg->hptxfsiz);
- gusbcfg = readl(hsotg->regs + GUSBCFG);
- gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
- writel(gusbcfg, hsotg->regs + GUSBCFG);
- usleep_range(100000, 150000);
+ if (retval)
+ return retval;
+
+ retval = -ENOMEM;
hcfg = readl(hsotg->regs + HCFG);
dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);
- dev_dbg(hsotg->dev, "op_mode=%0x\n",
- hsotg->hwcfg2 >> GHWCFG2_OP_MODE_SHIFT &
- GHWCFG2_OP_MODE_MASK >> GHWCFG2_OP_MODE_SHIFT);
- dev_dbg(hsotg->dev, "arch=%0x\n",
- hsotg->hwcfg2 >> GHWCFG2_ARCHITECTURE_SHIFT &
- GHWCFG2_ARCHITECTURE_MASK >> GHWCFG2_ARCHITECTURE_SHIFT);
- dev_dbg(hsotg->dev, "num_dev_ep=%d\n",
- hsotg->hwcfg2 >> GHWCFG2_NUM_DEV_EP_SHIFT &
- GHWCFG2_NUM_DEV_EP_MASK >> GHWCFG2_NUM_DEV_EP_SHIFT);
- dev_dbg(hsotg->dev, "max_host_chan=%d\n",
- hsotg->hwcfg2 >> GHWCFG2_NUM_HOST_CHAN_SHIFT &
- GHWCFG2_NUM_HOST_CHAN_MASK >> GHWCFG2_NUM_HOST_CHAN_SHIFT);
- dev_dbg(hsotg->dev, "nonperio_tx_q_depth=0x%0x\n",
- hsotg->hwcfg2 >> GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT &
- GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK >>
- GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT);
- dev_dbg(hsotg->dev, "host_perio_tx_q_depth=0x%0x\n",
- hsotg->hwcfg2 >> GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT &
- GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK >>
- GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT);
- dev_dbg(hsotg->dev, "dev_token_q_depth=0x%0x\n",
- hsotg->hwcfg2 >> GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT &
- GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK >>
- GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT);
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
hsotg->frame_num_array = kzalloc(sizeof(*hsotg->frame_num_array) *
@@ -2801,22 +2769,30 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
/* Validate parameter values */
dwc2_set_parameters(hsotg, params);
+ /* Check if the bus driver or platform code has setup a dma_mask */
+ if (hsotg->core_params->dma_enable > 0 &&
+ hsotg->dev->dma_mask == NULL) {
+ dev_warn(hsotg->dev,
+ "dma_mask not set, disabling DMA\n");
+ hsotg->core_params->dma_enable = 0;
+ hsotg->core_params->dma_desc_enable = 0;
+ }
+
/* Set device flags indicating whether the HCD supports DMA */
if (hsotg->core_params->dma_enable > 0) {
if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
dev_warn(hsotg->dev, "can't set DMA mask\n");
- if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(31)) < 0)
- dev_warn(hsotg->dev,
- "can't enable workaround for >2GB RAM\n");
- } else {
- dma_set_mask(hsotg->dev, 0);
- dma_set_coherent_mask(hsotg->dev, 0);
+ if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
+ dev_warn(hsotg->dev, "can't set coherent DMA mask\n");
}
hcd = usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev));
if (!hcd)
goto error1;
+ if (hsotg->core_params->dma_enable <= 0)
+ hcd->self.uses_dma = 0;
+
hcd->has_tt = 1;
spin_lock_init(&hsotg->lock);
@@ -2843,11 +2819,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
}
INIT_WORK(&hsotg->wf_otg, dwc2_conn_id_status_change);
- hsotg->snpsid = readl(hsotg->regs + GSNPSID);
- dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x\n",
- hsotg->snpsid >> 12 & 0xf, hsotg->snpsid >> 8 & 0xf,
- hsotg->snpsid >> 4 & 0xf, hsotg->snpsid & 0xf);
-
setup_timer(&hsotg->wkp_timer, dwc2_wakeup_detected,
(unsigned long)hsotg);
@@ -2922,8 +2893,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
if (retval < 0)
goto error3;
- dwc2_dump_global_registers(hsotg);
- dwc2_dump_host_registers(hsotg);
dwc2_hcd_dump_state(hsotg);
dwc2_enable_global_interrupts(hsotg);
diff --git a/drivers/staging/dwc2/hcd.h b/drivers/staging/dwc2/hcd.h
index cf6c055aec8..cc0a1170831 100644
--- a/drivers/staging/dwc2/hcd.h
+++ b/drivers/staging/dwc2/hcd.h
@@ -122,11 +122,11 @@ struct dwc2_host_chan {
unsigned ep_type:2;
unsigned max_packet:11;
unsigned data_pid_start:2;
-#define DWC2_HC_PID_DATA0 (TSIZ_SC_MC_PID_DATA0 >> TSIZ_SC_MC_PID_SHIFT)
-#define DWC2_HC_PID_DATA2 (TSIZ_SC_MC_PID_DATA2 >> TSIZ_SC_MC_PID_SHIFT)
-#define DWC2_HC_PID_DATA1 (TSIZ_SC_MC_PID_DATA1 >> TSIZ_SC_MC_PID_SHIFT)
-#define DWC2_HC_PID_MDATA (TSIZ_SC_MC_PID_MDATA >> TSIZ_SC_MC_PID_SHIFT)
-#define DWC2_HC_PID_SETUP (TSIZ_SC_MC_PID_SETUP >> TSIZ_SC_MC_PID_SHIFT)
+#define DWC2_HC_PID_DATA0 TSIZ_SC_MC_PID_DATA0
+#define DWC2_HC_PID_DATA2 TSIZ_SC_MC_PID_DATA2
+#define DWC2_HC_PID_DATA1 TSIZ_SC_MC_PID_DATA1
+#define DWC2_HC_PID_MDATA TSIZ_SC_MC_PID_MDATA
+#define DWC2_HC_PID_SETUP TSIZ_SC_MC_PID_SETUP
unsigned multi_count:2;
@@ -146,10 +146,10 @@ struct dwc2_host_chan {
u8 hub_addr;
u8 hub_port;
u8 xact_pos;
-#define DWC2_HCSPLT_XACTPOS_MID (HCSPLT_XACTPOS_MID >> HCSPLT_XACTPOS_SHIFT)
-#define DWC2_HCSPLT_XACTPOS_END (HCSPLT_XACTPOS_END >> HCSPLT_XACTPOS_SHIFT)
-#define DWC2_HCSPLT_XACTPOS_BEGIN (HCSPLT_XACTPOS_BEGIN >> HCSPLT_XACTPOS_SHIFT)
-#define DWC2_HCSPLT_XACTPOS_ALL (HCSPLT_XACTPOS_ALL >> HCSPLT_XACTPOS_SHIFT)
+#define DWC2_HCSPLT_XACTPOS_MID HCSPLT_XACTPOS_MID
+#define DWC2_HCSPLT_XACTPOS_END HCSPLT_XACTPOS_END
+#define DWC2_HCSPLT_XACTPOS_BEGIN HCSPLT_XACTPOS_BEGIN
+#define DWC2_HCSPLT_XACTPOS_ALL HCSPLT_XACTPOS_ALL
u8 requests;
u8 schinfo;
@@ -232,16 +232,19 @@ enum dwc2_transaction_type {
* - DWC2_HC_PID_DATA1
* @ping_state: Ping state
* @do_split: Full/low speed endpoint on high-speed hub requires split
- * @qtd_list: List of QTDs for this QH
- * @channel: Host channel currently processing transfers for this QH
+ * @td_first: Index of first activated isochronous transfer descriptor
+ * @td_last: Index of last activated isochronous transfer descriptor
* @usecs: Bandwidth in microseconds per (micro)frame
* @interval: Interval between transfers in (micro)frames
- * @sched_frame: (micro)frame to initialize a periodic transfer.
+ * @sched_frame: (Micro)frame to initialize a periodic transfer.
* The transfer executes in the following (micro)frame.
* @start_split_frame: (Micro)frame at which last start split was initialized
+ * @ntd: Actual number of transfer descriptors in a list
* @dw_align_buf: Used instead of original buffer if its physical address
* is not dword-aligned
* @dw_align_buf_dma: DMA address for align_buf
+ * @qtd_list: List of QTDs for this QH
+ * @channel: Host channel currently processing transfers for this QH
* @qh_list_entry: Entry for QH in either the periodic or non-periodic
* schedule
* @desc_list: List of transfer descriptors
@@ -249,9 +252,6 @@ enum dwc2_transaction_type {
* @n_bytes: Xfer Bytes array. Each element corresponds to a transfer
* descriptor and indicates original XferSize value for the
* descriptor
- * @ntd: Actual number of transfer descriptors in a list
- * @td_first: Index of first activated isochronous transfer descriptor
- * @td_last: Index of last activated isochronous transfer descriptor
* @tt_buffer_dirty True if clear_tt_buffer_complete is pending
*
* A Queue Head (QH) holds the static characteristics of an endpoint and
@@ -266,21 +266,21 @@ struct dwc2_qh {
u8 data_toggle;
u8 ping_state;
u8 do_split;
- struct list_head qtd_list;
- struct dwc2_host_chan *channel;
+ u8 td_first;
+ u8 td_last;
u16 usecs;
u16 interval;
u16 sched_frame;
u16 start_split_frame;
+ u16 ntd;
u8 *dw_align_buf;
dma_addr_t dw_align_buf_dma;
+ struct list_head qtd_list;
+ struct dwc2_host_chan *channel;
struct list_head qh_list_entry;
struct dwc2_hcd_dma_desc *desc_list;
dma_addr_t desc_list_dma;
u32 *n_bytes;
- u16 ntd;
- u8 td_first;
- u8 td_last;
unsigned tt_buffer_dirty:1;
};
@@ -453,6 +453,7 @@ extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg);
extern int dwc2_set_parameters(struct dwc2_hsotg *hsotg,
const struct dwc2_core_params *params);
extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
+extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
/* Transaction Execution Functions */
extern enum dwc2_transaction_type dwc2_hcd_select_transactions(
@@ -716,8 +717,8 @@ extern void dwc2_host_disconnect(struct dwc2_hsotg *hsotg);
extern void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context,
int *hub_addr, int *hub_port);
extern int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context);
-extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, void *context,
- struct dwc2_hcd_urb *dwc2_urb, int status);
+extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
+ int status);
#ifdef DEBUG
/*
diff --git a/drivers/staging/dwc2/hcd_ddma.c b/drivers/staging/dwc2/hcd_ddma.c
index 5c0fd273a7b..69070f4442a 100644
--- a/drivers/staging/dwc2/hcd_ddma.c
+++ b/drivers/staging/dwc2/hcd_ddma.c
@@ -800,11 +800,14 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
u16 remain = 0;
int rc = 0;
+ if (!qtd->urb)
+ return -EINVAL;
+
frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
if (chan->ep_is_in)
- remain = dma_desc->status >> HOST_DMA_ISOC_NBYTES_SHIFT &
- HOST_DMA_ISOC_NBYTES_MASK >> HOST_DMA_ISOC_NBYTES_SHIFT;
+ remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >>
+ HOST_DMA_ISOC_NBYTES_SHIFT;
if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) {
/*
@@ -826,7 +829,7 @@ static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
* urb->status is not used for isoc transfers here. The
* individual frame_desc status are used instead.
*/
- dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb, 0);
+ dwc2_host_complete(hsotg, qtd, 0);
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
/*
@@ -884,13 +887,16 @@ static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
qtd_list_entry) {
- for (idx = 0; idx < qtd->urb->packet_count; idx++) {
- frame_desc = &qtd->urb->iso_descs[idx];
- frame_desc->status = err;
+ if (qtd->urb) {
+ for (idx = 0; idx < qtd->urb->packet_count;
+ idx++) {
+ frame_desc = &qtd->urb->iso_descs[idx];
+ frame_desc->status = err;
+ }
+
+ dwc2_host_complete(hsotg, qtd, err);
}
- dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
- err);
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
}
@@ -929,8 +935,8 @@ static int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg,
u16 remain = 0;
if (chan->ep_is_in)
- remain = dma_desc->status >> HOST_DMA_NBYTES_SHIFT &
- HOST_DMA_NBYTES_MASK >> HOST_DMA_NBYTES_SHIFT;
+ remain = (dma_desc->status & HOST_DMA_NBYTES_MASK) >>
+ HOST_DMA_NBYTES_SHIFT;
dev_vdbg(hsotg->dev, "remain=%d dwc2_urb=%p\n", remain, urb);
@@ -1015,6 +1021,9 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
dev_vdbg(hsotg->dev, "%s()\n", __func__);
+ if (!urb)
+ return -EINVAL;
+
dma_desc = &qh->desc_list[desc_num];
n_bytes = qh->n_bytes[desc_num];
dev_vdbg(hsotg->dev,
@@ -1024,7 +1033,7 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
halt_status, n_bytes,
xfer_done);
if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
- dwc2_host_complete(hsotg, urb->priv, urb, urb->status);
+ dwc2_host_complete(hsotg, qtd, urb->status);
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n",
failed, *xfer_done, urb->status);
diff --git a/drivers/staging/dwc2/hcd_intr.c b/drivers/staging/dwc2/hcd_intr.c
index e75dccb3b80..e143f69939f 100644
--- a/drivers/staging/dwc2/hcd_intr.c
+++ b/drivers/staging/dwc2/hcd_intr.c
@@ -89,15 +89,20 @@ static void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg,
{
struct urb *usb_urb;
- if (!chan->qh || !qtd->urb)
+ if (!chan->qh)
+ return;
+
+ if (chan->qh->dev_speed == USB_SPEED_HIGH)
+ return;
+
+ if (!qtd->urb)
return;
usb_urb = qtd->urb->priv;
- if (!usb_urb || !usb_urb->dev)
+ if (!usb_urb || !usb_urb->dev || !usb_urb->dev->tt)
return;
- if (chan->qh->dev_speed != USB_SPEED_HIGH &&
- qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) {
+ if (qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) {
chan->qh->tt_buffer_dirty = 1;
if (usb_hub_clear_tt_buffer(usb_urb))
/* Clear failed; let's hope things work anyway */
@@ -160,19 +165,16 @@ static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg)
dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
grxsts = readl(hsotg->regs + GRXSTSP);
- chnum = grxsts >> GRXSTS_HCHNUM_SHIFT &
- GRXSTS_HCHNUM_MASK >> GRXSTS_HCHNUM_SHIFT;
+ chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
chan = hsotg->hc_ptr_array[chnum];
if (!chan) {
dev_err(hsotg->dev, "Unable to get corresponding channel\n");
return;
}
- bcnt = grxsts >> GRXSTS_BYTECNT_SHIFT &
- GRXSTS_BYTECNT_MASK >> GRXSTS_BYTECNT_SHIFT;
- dpid = grxsts >> GRXSTS_DPID_SHIFT &
- GRXSTS_DPID_MASK >> GRXSTS_DPID_SHIFT;
- pktsts = grxsts & GRXSTS_PKTSTS_MASK;
+ bcnt = (grxsts & GRXSTS_BYTECNT_MASK) >> GRXSTS_BYTECNT_SHIFT;
+ dpid = (grxsts & GRXSTS_DPID_MASK) >> GRXSTS_DPID_SHIFT;
+ pktsts = (grxsts & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT;
/* Packet Status */
if (dbg_perio()) {
@@ -180,9 +182,7 @@ static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg)
dev_vdbg(hsotg->dev, " Count = %d\n", bcnt);
dev_vdbg(hsotg->dev, " DPID = %d, chan.dpid = %d\n", dpid,
chan->data_pid_start);
- dev_vdbg(hsotg->dev, " PStatus = %d\n",
- pktsts >> GRXSTS_PKTSTS_SHIFT &
- GRXSTS_PKTSTS_MASK >> GRXSTS_PKTSTS_SHIFT);
+ dev_vdbg(hsotg->dev, " PStatus = %d\n", pktsts);
}
switch (pktsts) {
@@ -261,7 +261,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
}
usbcfg = readl(hsotg->regs + GUSBCFG);
- prtspd = hprt0 & HPRT0_SPD_MASK;
+ prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
/* Low power */
@@ -273,7 +273,8 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
}
hcfg = readl(hsotg->regs + HCFG);
- fslspclksel = hcfg & HCFG_FSLSPCLKSEL_MASK;
+ fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
+ HCFG_FSLSPCLKSEL_SHIFT;
if (prtspd == HPRT0_SPD_LOW_SPEED &&
params->host_ls_low_power_phy_clk ==
@@ -282,8 +283,9 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
dev_vdbg(hsotg->dev,
"FS_PHY programming HCFG to 6 MHz\n");
if (fslspclksel != HCFG_FSLSPCLKSEL_6_MHZ) {
+ fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
- hcfg |= HCFG_FSLSPCLKSEL_6_MHZ;
+ hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
writel(hcfg, hsotg->regs + HCFG);
do_reset = 1;
}
@@ -292,8 +294,9 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
dev_vdbg(hsotg->dev,
"FS_PHY programming HCFG to 48 MHz\n");
if (fslspclksel != HCFG_FSLSPCLKSEL_48_MHZ) {
+ fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
- hcfg |= HCFG_FSLSPCLKSEL_48_MHZ;
+ hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
writel(hcfg, hsotg->regs + HCFG);
do_reset = 1;
}
@@ -406,8 +409,8 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
if (halt_status == DWC2_HC_XFER_COMPLETE) {
if (chan->ep_is_in) {
- count = hctsiz >> TSIZ_XFERSIZE_SHIFT &
- TSIZ_XFERSIZE_MASK >> TSIZ_XFERSIZE_SHIFT;
+ count = (hctsiz & TSIZ_XFERSIZE_MASK) >>
+ TSIZ_XFERSIZE_SHIFT;
length = chan->xfer_len - count;
if (short_read != NULL)
*short_read = (count != 0);
@@ -426,8 +429,7 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
* hctsiz.xfersize field because that reflects the number of
* bytes transferred via the AHB, not the USB).
*/
- count = hctsiz >> TSIZ_PKTCNT_SHIFT &
- TSIZ_PKTCNT_MASK >> TSIZ_PKTCNT_SHIFT;
+ count = (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT;
length = (chan->start_pkt_count - count) * chan->max_packet;
}
@@ -462,7 +464,7 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
/* Non DWORD-aligned buffer case handling */
if (chan->align_buf && xfer_length && chan->ep_is_in) {
- dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+ dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
DMA_FROM_DEVICE);
memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
@@ -490,8 +492,7 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
dev_vdbg(hsotg->dev, " chan->xfer_len %d\n", chan->xfer_len);
dev_vdbg(hsotg->dev, " hctsiz.xfersize %d\n",
- hctsiz >> TSIZ_XFERSIZE_SHIFT &
- TSIZ_XFERSIZE_MASK >> TSIZ_XFERSIZE_SHIFT);
+ (hctsiz & TSIZ_XFERSIZE_MASK) >> TSIZ_XFERSIZE_SHIFT);
dev_vdbg(hsotg->dev, " urb->transfer_buffer_length %d\n", urb->length);
dev_vdbg(hsotg->dev, " urb->actual_length %d\n", urb->actual_length);
dev_vdbg(hsotg->dev, " short_read %d, xfer_done %d\n", short_read,
@@ -510,7 +511,7 @@ void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
struct dwc2_qtd *qtd)
{
u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
- u32 pid = hctsiz & TSIZ_SC_MC_PID_MASK;
+ u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
if (pid == TSIZ_SC_MC_PID_DATA0)
@@ -557,8 +558,8 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
/* Non DWORD-aligned buffer case handling */
if (chan->align_buf && frame_desc->actual_length &&
chan->ep_is_in) {
- dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n",
- __func__);
+ dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
+ __func__);
dma_sync_single_for_cpu(hsotg->dev, urb->dma,
urb->length, DMA_FROM_DEVICE);
memcpy(urb->buf + frame_desc->offset +
@@ -591,8 +592,8 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
/* Non DWORD-aligned buffer case handling */
if (chan->align_buf && frame_desc->actual_length &&
chan->ep_is_in) {
- dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n",
- __func__);
+ dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
+ __func__);
dma_sync_single_for_cpu(hsotg->dev, urb->dma,
urb->length, DMA_FROM_DEVICE);
memcpy(urb->buf + frame_desc->offset +
@@ -623,7 +624,7 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
* urb->status is not used for isoc transfers. The individual
* frame_desc statuses are used instead.
*/
- dwc2_host_complete(hsotg, urb->priv, urb, 0);
+ dwc2_host_complete(hsotg, qtd, 0);
halt_status = DWC2_HC_XFER_URB_COMPLETE;
} else {
halt_status = DWC2_HC_XFER_COMPLETE;
@@ -714,11 +715,7 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg,
dev_vdbg(hsotg->dev,
" Complete URB with transaction error\n");
free_qtd = 1;
- if (qtd->urb) {
- qtd->urb->status = -EPROTO;
- dwc2_host_complete(hsotg, qtd->urb->priv,
- qtd->urb, -EPROTO);
- }
+ dwc2_host_complete(hsotg, qtd, -EPROTO);
}
break;
case DWC2_HC_XFER_URB_DEQUEUE:
@@ -731,11 +728,7 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg,
case DWC2_HC_XFER_PERIODIC_INCOMPLETE:
dev_vdbg(hsotg->dev, " Complete URB with I/O error\n");
free_qtd = 1;
- if (qtd && qtd->urb) {
- qtd->urb->status = -EIO;
- dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
- -EIO);
- }
+ dwc2_host_complete(hsotg, qtd, -EIO);
break;
case DWC2_HC_XFER_NO_HALT_STATUS:
default:
@@ -938,7 +931,7 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
frame_desc->actual_length += len;
if (chan->align_buf && len) {
- dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+ dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
dma_sync_single_for_cpu(hsotg->dev, qtd->urb->dma,
qtd->urb->length, DMA_FROM_DEVICE);
memcpy(qtd->urb->buf + frame_desc->offset +
@@ -957,7 +950,7 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
}
if (qtd->isoc_frame_index == qtd->urb->packet_count) {
- dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb, 0);
+ dwc2_host_complete(hsotg, qtd, 0);
dwc2_release_channel(hsotg, chan, qtd,
DWC2_HC_XFER_URB_COMPLETE);
} else {
@@ -1040,7 +1033,7 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg,
dev_vdbg(hsotg->dev, " Control transfer complete\n");
if (urb->status == -EINPROGRESS)
urb->status = 0;
- dwc2_host_complete(hsotg, urb->priv, urb, urb->status);
+ dwc2_host_complete(hsotg, qtd, urb->status);
halt_status = DWC2_HC_XFER_URB_COMPLETE;
break;
}
@@ -1053,7 +1046,7 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg,
urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb,
qtd);
if (urb_xfer_done) {
- dwc2_host_complete(hsotg, urb->priv, urb, urb->status);
+ dwc2_host_complete(hsotg, qtd, urb->status);
halt_status = DWC2_HC_XFER_URB_COMPLETE;
} else {
halt_status = DWC2_HC_XFER_COMPLETE;
@@ -1073,11 +1066,10 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg,
* interrupt
*/
if (urb_xfer_done) {
- dwc2_host_complete(hsotg, urb->priv, urb,
- urb->status);
- halt_status = DWC2_HC_XFER_URB_COMPLETE;
+ dwc2_host_complete(hsotg, qtd, urb->status);
+ halt_status = DWC2_HC_XFER_URB_COMPLETE;
} else {
- halt_status = DWC2_HC_XFER_COMPLETE;
+ halt_status = DWC2_HC_XFER_COMPLETE;
}
dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
@@ -1123,11 +1115,11 @@ static void dwc2_hc_stall_intr(struct dwc2_hsotg *hsotg,
goto handle_stall_halt;
if (pipe_type == USB_ENDPOINT_XFER_CONTROL)
- dwc2_host_complete(hsotg, urb->priv, urb, -EPIPE);
+ dwc2_host_complete(hsotg, qtd, -EPIPE);
if (pipe_type == USB_ENDPOINT_XFER_BULK ||
pipe_type == USB_ENDPOINT_XFER_INT) {
- dwc2_host_complete(hsotg, urb->priv, urb, -EPIPE);
+ dwc2_host_complete(hsotg, qtd, -EPIPE);
/*
* USB protocol requires resetting the data toggle for bulk
* and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
@@ -1168,7 +1160,7 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
/* Non DWORD-aligned buffer case handling */
if (chan->align_buf && xfer_length && chan->ep_is_in) {
- dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+ dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
DMA_FROM_DEVICE);
memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
@@ -1185,8 +1177,7 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
dev_vdbg(hsotg->dev, " chan->start_pkt_count %d\n",
chan->start_pkt_count);
dev_vdbg(hsotg->dev, " hctsiz.pktcnt %d\n",
- hctsiz >> TSIZ_PKTCNT_SHIFT &
- TSIZ_PKTCNT_MASK >> TSIZ_PKTCNT_SHIFT);
+ (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT);
dev_vdbg(hsotg->dev, " chan->max_packet %d\n", chan->max_packet);
dev_vdbg(hsotg->dev, " bytes_transferred %d\n",
xfer_length);
@@ -1372,10 +1363,10 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg,
hsotg->core_params->dma_enable > 0) {
qtd->complete_split = 0;
qtd->isoc_split_offset = 0;
+ qtd->isoc_frame_index++;
if (qtd->urb &&
- ++qtd->isoc_frame_index == qtd->urb->packet_count) {
- dwc2_host_complete(hsotg, qtd->urb->priv,
- qtd->urb, 0);
+ qtd->isoc_frame_index == qtd->urb->packet_count) {
+ dwc2_host_complete(hsotg, qtd, 0);
dwc2_release_channel(hsotg, chan, qtd,
DWC2_HC_XFER_URB_COMPLETE);
} else {
@@ -1445,16 +1436,16 @@ static void dwc2_hc_babble_intr(struct dwc2_hsotg *hsotg,
dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Babble Error--\n",
chnum);
+ dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
if (hsotg->core_params->dma_desc_enable > 0) {
dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
DWC2_HC_XFER_BABBLE_ERR);
- goto handle_babble_done;
+ goto disable_int;
}
if (chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
- if (qtd->urb)
- dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
- -EOVERFLOW);
+ dwc2_host_complete(hsotg, qtd, -EOVERFLOW);
dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_BABBLE_ERR);
} else {
enum dwc2_halt_status halt_status;
@@ -1464,8 +1455,7 @@ static void dwc2_hc_babble_intr(struct dwc2_hsotg *hsotg,
dwc2_halt_channel(hsotg, chan, qtd, halt_status);
}
-handle_babble_done:
- dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+disable_int:
disable_hc_int(hsotg, chnum, HCINTMSK_BBLERR);
}
@@ -1490,6 +1480,8 @@ static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg,
if (!urb)
goto handle_ahberr_halt;
+ dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
hcchar = readl(hsotg->regs + HCCHAR(chnum));
hcsplt = readl(hsotg->regs + HCSPLT(chnum));
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
@@ -1557,7 +1549,7 @@ static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg,
goto handle_ahberr_done;
}
- dwc2_host_complete(hsotg, urb->priv, urb, -EIO);
+ dwc2_host_complete(hsotg, qtd, -EIO);
handle_ahberr_halt:
/*
@@ -1567,7 +1559,6 @@ handle_ahberr_halt:
dwc2_hc_halt(hsotg, chan, DWC2_HC_XFER_AHB_ERR);
handle_ahberr_done:
- dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
disable_hc_int(hsotg, chnum, HCINTMSK_AHBERR);
}
@@ -1582,6 +1573,8 @@ static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg,
dev_dbg(hsotg->dev,
"--Host Channel %d Interrupt: Transaction Error--\n", chnum);
+ dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
if (hsotg->core_params->dma_desc_enable > 0) {
dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
DWC2_HC_XFER_XACT_ERR);
@@ -1625,7 +1618,6 @@ static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg,
}
handle_xacterr_done:
- dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
disable_hc_int(hsotg, chnum, HCINTMSK_XACTERR);
}
@@ -1643,6 +1635,8 @@ static void dwc2_hc_frmovrun_intr(struct dwc2_hsotg *hsotg,
dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Frame Overrun--\n",
chnum);
+ dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_BULK:
@@ -1657,7 +1651,6 @@ static void dwc2_hc_frmovrun_intr(struct dwc2_hsotg *hsotg,
break;
}
- dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
disable_hc_int(hsotg, chnum, HCINTMSK_FRMOVRUN);
}
@@ -1766,7 +1759,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
* For core with OUT NAK enhancement, the flow for high-speed
* CONTROL/BULK OUT is handled a little differently
*/
- if (hsotg->snpsid >= DWC2_CORE_REV_2_71a) {
+ if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_71a) {
if (chan->speed == USB_SPEED_HIGH && !chan->ep_is_in &&
(chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
chan->ep_type == USB_ENDPOINT_XFER_BULK)) {
diff --git a/drivers/staging/dwc2/hcd_queue.c b/drivers/staging/dwc2/hcd_queue.c
index b36f783dd3e..b1980ef28fa 100644
--- a/drivers/staging/dwc2/hcd_queue.c
+++ b/drivers/staging/dwc2/hcd_queue.c
@@ -116,7 +116,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
qh->interval = 8;
#endif
hprt = readl(hsotg->regs + HPRT0);
- prtspd = hprt & HPRT0_SPD_MASK;
+ prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
if (prtspd == HPRT0_SPD_HIGH_SPEED &&
(dev_speed == USB_SPEED_LOW ||
dev_speed == USB_SPEED_FULL)) {
@@ -197,6 +197,9 @@ static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
{
struct dwc2_qh *qh;
+ if (!urb->priv)
+ return NULL;
+
/* Allocate memory */
qh = kzalloc(sizeof(*qh), mem_flags);
if (!qh)
@@ -638,7 +641,7 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
struct dwc2_hcd_urb *urb = qtd->urb;
unsigned long flags;
int allocated = 0;
- int retval = 0;
+ int retval;
/*
* Get the QH which holds the QTD-list to insert to. Create QH if it
@@ -652,8 +655,19 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
}
spin_lock_irqsave(&hsotg->lock, flags);
+
retval = dwc2_hcd_qh_add(hsotg, *qh);
- if (retval && allocated) {
+ if (retval)
+ goto fail;
+
+ qtd->qh = *qh;
+ list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ return 0;
+
+fail:
+ if (allocated) {
struct dwc2_qtd *qtd2, *qtd2_tmp;
struct dwc2_qh *qh_tmp = *qh;
@@ -668,8 +682,6 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_hcd_qh_free(hsotg, qh_tmp);
} else {
- qtd->qh = *qh;
- list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
spin_unlock_irqrestore(&hsotg->lock, flags);
}
diff --git a/drivers/staging/dwc2/hw.h b/drivers/staging/dwc2/hw.h
index 382a1d74865..9c92a3c7588 100644
--- a/drivers/staging/dwc2/hw.h
+++ b/drivers/staging/dwc2/hw.h
@@ -72,12 +72,16 @@
#define GAHBCFG_DMA_EN (1 << 5)
#define GAHBCFG_HBSTLEN_MASK (0xf << 1)
#define GAHBCFG_HBSTLEN_SHIFT 1
-#define GAHBCFG_HBSTLEN_SINGLE (0 << 1)
-#define GAHBCFG_HBSTLEN_INCR (1 << 1)
-#define GAHBCFG_HBSTLEN_INCR4 (3 << 1)
-#define GAHBCFG_HBSTLEN_INCR8 (5 << 1)
-#define GAHBCFG_HBSTLEN_INCR16 (7 << 1)
+#define GAHBCFG_HBSTLEN_SINGLE 0
+#define GAHBCFG_HBSTLEN_INCR 1
+#define GAHBCFG_HBSTLEN_INCR4 3
+#define GAHBCFG_HBSTLEN_INCR8 5
+#define GAHBCFG_HBSTLEN_INCR16 7
#define GAHBCFG_GLBL_INTR_EN (1 << 0)
+#define GAHBCFG_CTRL_MASK (GAHBCFG_P_TXF_EMP_LVL | \
+ GAHBCFG_NP_TXF_EMP_LVL | \
+ GAHBCFG_DMA_EN | \
+ GAHBCFG_GLBL_INTR_EN)
#define GUSBCFG HSOTG_REG(0x00C)
#define GUSBCFG_FORCEDEVMODE (1 << 30)
@@ -165,15 +169,15 @@
#define GRXSTS_FN_SHIFT 25
#define GRXSTS_PKTSTS_MASK (0xf << 17)
#define GRXSTS_PKTSTS_SHIFT 17
-#define GRXSTS_PKTSTS_GLOBALOUTNAK (1 << 17)
-#define GRXSTS_PKTSTS_OUTRX (2 << 17)
-#define GRXSTS_PKTSTS_HCHIN (2 << 17)
-#define GRXSTS_PKTSTS_OUTDONE (3 << 17)
-#define GRXSTS_PKTSTS_HCHIN_XFER_COMP (3 << 17)
-#define GRXSTS_PKTSTS_SETUPDONE (4 << 17)
-#define GRXSTS_PKTSTS_DATATOGGLEERR (5 << 17)
-#define GRXSTS_PKTSTS_SETUPRX (6 << 17)
-#define GRXSTS_PKTSTS_HCHHALTED (7 << 17)
+#define GRXSTS_PKTSTS_GLOBALOUTNAK 1
+#define GRXSTS_PKTSTS_OUTRX 2
+#define GRXSTS_PKTSTS_HCHIN 2
+#define GRXSTS_PKTSTS_OUTDONE 3
+#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3
+#define GRXSTS_PKTSTS_SETUPDONE 4
+#define GRXSTS_PKTSTS_DATATOGGLEERR 5
+#define GRXSTS_PKTSTS_SETUPRX 6
+#define GRXSTS_PKTSTS_HCHHALTED 7
#define GRXSTS_HCHNUM_MASK (0xf << 0)
#define GRXSTS_HCHNUM_SHIFT 0
#define GRXSTS_DPID_MASK (0x3 << 15)
@@ -184,16 +188,11 @@
#define GRXSTS_EPNUM_SHIFT 0
#define GRXFSIZ HSOTG_REG(0x024)
+#define GRXFSIZ_DEPTH_MASK (0xffff << 0)
+#define GRXFSIZ_DEPTH_SHIFT 0
#define GNPTXFSIZ HSOTG_REG(0x028)
-#define GNPTXFSIZ_NP_TXF_DEP_MASK (0xffff << 16)
-#define GNPTXFSIZ_NP_TXF_DEP_SHIFT 16
-#define GNPTXFSIZ_NP_TXF_DEP_LIMIT 0xffff
-#define GNPTXFSIZ_NP_TXF_DEP(_x) ((_x) << 16)
-#define GNPTXFSIZ_NP_TXF_ST_ADDR_MASK (0xffff << 0)
-#define GNPTXFSIZ_NP_TXF_ST_ADDR_SHIFT 0
-#define GNPTXFSIZ_NP_TXF_ST_ADDR_LIMIT 0xffff
-#define GNPTXFSIZ_NP_TXF_ST_ADDR(_x) ((_x) << 0)
+/* Use FIFOSIZE_* constants to access this register */
#define GNPTXSTS HSOTG_REG(0x02C)
#define GNPTXSTS_NP_TXQ_TOP_MASK (0x7f << 24)
@@ -244,32 +243,32 @@
#define GHWCFG2_NUM_DEV_EP_SHIFT 10
#define GHWCFG2_FS_PHY_TYPE_MASK (0x3 << 8)
#define GHWCFG2_FS_PHY_TYPE_SHIFT 8
-#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED (0 << 8)
-#define GHWCFG2_FS_PHY_TYPE_DEDICATED (1 << 8)
-#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI (2 << 8)
-#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI (3 << 8)
+#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0
+#define GHWCFG2_FS_PHY_TYPE_DEDICATED 1
+#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI 2
+#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI 3
#define GHWCFG2_HS_PHY_TYPE_MASK (0x3 << 6)
#define GHWCFG2_HS_PHY_TYPE_SHIFT 6
-#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED (0 << 6)
-#define GHWCFG2_HS_PHY_TYPE_UTMI (1 << 6)
-#define GHWCFG2_HS_PHY_TYPE_ULPI (2 << 6)
-#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI (3 << 6)
+#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
+#define GHWCFG2_HS_PHY_TYPE_UTMI 1
+#define GHWCFG2_HS_PHY_TYPE_ULPI 2
+#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
#define GHWCFG2_POINT2POINT (1 << 5)
#define GHWCFG2_ARCHITECTURE_MASK (0x3 << 3)
#define GHWCFG2_ARCHITECTURE_SHIFT 3
-#define GHWCFG2_SLAVE_ONLY_ARCH (0 << 3)
-#define GHWCFG2_EXT_DMA_ARCH (1 << 3)
-#define GHWCFG2_INT_DMA_ARCH (2 << 3)
+#define GHWCFG2_SLAVE_ONLY_ARCH 0
+#define GHWCFG2_EXT_DMA_ARCH 1
+#define GHWCFG2_INT_DMA_ARCH 2
#define GHWCFG2_OP_MODE_MASK (0x7 << 0)
#define GHWCFG2_OP_MODE_SHIFT 0
-#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE (0 << 0)
-#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE (1 << 0)
-#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE (2 << 0)
-#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE (3 << 0)
-#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE (4 << 0)
-#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST (5 << 0)
-#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST (6 << 0)
-#define GHWCFG2_OP_MODE_UNDEFINED (7 << 0)
+#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE 0
+#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE 1
+#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE 2
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
+#define GHWCFG2_OP_MODE_UNDEFINED 7
#define GHWCFG3 HSOTG_REG(0x004c)
#define GHWCFG3_DFIFO_DEPTH_MASK (0xffff << 16)
@@ -303,6 +302,9 @@
#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14)
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2
#define GHWCFG4_XHIBER (1 << 7)
#define GHWCFG4_HIBER (1 << 6)
#define GHWCFG4_MIN_AHB_FREQ (1 << 5)
@@ -391,16 +393,12 @@
#define ADPCTL_PRB_DSCHRG_SHIFT 0
#define HPTXFSIZ HSOTG_REG(0x100)
+/* Use FIFOSIZE_* constants to access this register */
#define DPTXFSIZN(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4))
-#define DPTXFSIZN_DP_TXF_SIZE_MASK (0xffff << 16)
-#define DPTXFSIZN_DP_TXF_SIZE_SHIFT 16
-#define DPTXFSIZN_DP_TXF_SIZE_GET(_v) (((_v) >> 16) & 0xffff)
-#define DPTXFSIZN_DP_TXF_SIZE_LIMIT 0xffff
-#define DPTXFSIZN_DP_TXF_SIZE(_x) ((_x) << 16)
-#define DPTXFSIZN_DP_TXF_ST_ADDR_MASK (0xffff << 0)
-#define DPTXFSIZN_DP_TXF_ST_ADDR_SHIFT 0
+/* Use FIFOSIZE_* constants to access this register */
+/* These apply to the GNPTXFSIZ, HPTXFSIZ and DPTXFSIZN registers */
#define FIFOSIZE_DEPTH_MASK (0xffff << 16)
#define FIFOSIZE_DEPTH_SHIFT 16
#define FIFOSIZE_STARTADDR_MASK (0xffff << 0)
@@ -424,10 +422,10 @@
#define DCFG_NZ_STS_OUT_HSHK (1 << 2)
#define DCFG_DEVSPD_MASK (0x3 << 0)
#define DCFG_DEVSPD_SHIFT 0
-#define DCFG_DEVSPD_HS (0 << 0)
-#define DCFG_DEVSPD_FS (1 << 0)
-#define DCFG_DEVSPD_LS (2 << 0)
-#define DCFG_DEVSPD_FS48 (3 << 0)
+#define DCFG_DEVSPD_HS 0
+#define DCFG_DEVSPD_FS 1
+#define DCFG_DEVSPD_LS 2
+#define DCFG_DEVSPD_FS48 3
#define DCTL HSOTG_REG(0x804)
#define DCTL_PWRONPRGDONE (1 << 11)
@@ -450,10 +448,10 @@
#define DSTS_ERRATICERR (1 << 3)
#define DSTS_ENUMSPD_MASK (0x3 << 1)
#define DSTS_ENUMSPD_SHIFT 1
-#define DSTS_ENUMSPD_HS (0 << 1)
-#define DSTS_ENUMSPD_FS (1 << 1)
-#define DSTS_ENUMSPD_LS (2 << 1)
-#define DSTS_ENUMSPD_FS48 (3 << 1)
+#define DSTS_ENUMSPD_HS 0
+#define DSTS_ENUMSPD_FS 1
+#define DSTS_ENUMSPD_LS 2
+#define DSTS_ENUMSPD_FS48 3
#define DSTS_SUSPSTS (1 << 0)
#define DIEPMSK HSOTG_REG(0x810)
@@ -501,10 +499,10 @@
*/
#define D0EPCTL_MPS_MASK (0x3 << 0)
#define D0EPCTL_MPS_SHIFT 0
-#define D0EPCTL_MPS_64 (0 << 0)
-#define D0EPCTL_MPS_32 (1 << 0)
-#define D0EPCTL_MPS_16 (2 << 0)
-#define D0EPCTL_MPS_8 (3 << 0)
+#define D0EPCTL_MPS_64 0
+#define D0EPCTL_MPS_32 1
+#define D0EPCTL_MPS_16 2
+#define D0EPCTL_MPS_8 3
#define DXEPCTL_EPENA (1 << 31)
#define DXEPCTL_EPDIS (1 << 30)
@@ -522,10 +520,10 @@
#define DXEPCTL_SNP (1 << 20)
#define DXEPCTL_EPTYPE_MASK (0x3 << 18)
#define DXEPCTL_EPTYPE_SHIFT 18
-#define DXEPCTL_EPTYPE_CONTROL (0 << 18)
-#define DXEPCTL_EPTYPE_ISO (1 << 18)
-#define DXEPCTL_EPTYPE_BULK (2 << 18)
-#define DXEPCTL_EPTYPE_INTTERUPT (3 << 18)
+#define DXEPCTL_EPTYPE_CONTROL 0
+#define DXEPCTL_EPTYPE_ISO 1
+#define DXEPCTL_EPTYPE_BULK 2
+#define DXEPCTL_EPTYPE_INTTERUPT 3
#define DXEPCTL_NAKSTS (1 << 17)
#define DXEPCTL_DPID (1 << 16)
#define DXEPCTL_EOFRNUM (1 << 16)
@@ -645,9 +643,9 @@
#define HCFG_FSLSSUPP (1 << 2)
#define HCFG_FSLSPCLKSEL_MASK (0x3 << 0)
#define HCFG_FSLSPCLKSEL_SHIFT 0
-#define HCFG_FSLSPCLKSEL_30_60_MHZ (0 << 0)
-#define HCFG_FSLSPCLKSEL_48_MHZ (1 << 0)
-#define HCFG_FSLSPCLKSEL_6_MHZ (2 << 0)
+#define HCFG_FSLSPCLKSEL_30_60_MHZ 0
+#define HCFG_FSLSPCLKSEL_48_MHZ 1
+#define HCFG_FSLSPCLKSEL_6_MHZ 2
#define HFIR HSOTG_REG(0x0404)
#define HFIR_FRINT_MASK (0xffff << 0)
@@ -680,9 +678,9 @@
#define HPRT0 HSOTG_REG(0x0440)
#define HPRT0_SPD_MASK (0x3 << 17)
#define HPRT0_SPD_SHIFT 17
-#define HPRT0_SPD_HIGH_SPEED (0 << 17)
-#define HPRT0_SPD_FULL_SPEED (1 << 17)
-#define HPRT0_SPD_LOW_SPEED (2 << 17)
+#define HPRT0_SPD_HIGH_SPEED 0
+#define HPRT0_SPD_FULL_SPEED 1
+#define HPRT0_SPD_LOW_SPEED 2
#define HPRT0_TSTCTL_MASK (0xf << 13)
#define HPRT0_TSTCTL_SHIFT 13
#define HPRT0_PWR (1 << 12)
@@ -720,10 +718,10 @@
#define HCSPLT_COMPSPLT (1 << 16)
#define HCSPLT_XACTPOS_MASK (0x3 << 14)
#define HCSPLT_XACTPOS_SHIFT 14
-#define HCSPLT_XACTPOS_MID (0 << 14)
-#define HCSPLT_XACTPOS_END (1 << 14)
-#define HCSPLT_XACTPOS_BEGIN (2 << 14)
-#define HCSPLT_XACTPOS_ALL (3 << 14)
+#define HCSPLT_XACTPOS_MID 0
+#define HCSPLT_XACTPOS_END 1
+#define HCSPLT_XACTPOS_BEGIN 2
+#define HCSPLT_XACTPOS_ALL 3
#define HCSPLT_HUBADDR_MASK (0x7f << 7)
#define HCSPLT_HUBADDR_SHIFT 7
#define HCSPLT_PRTADDR_MASK (0x7f << 0)
@@ -751,11 +749,11 @@
#define TSIZ_DOPNG (1 << 31)
#define TSIZ_SC_MC_PID_MASK (0x3 << 29)
#define TSIZ_SC_MC_PID_SHIFT 29
-#define TSIZ_SC_MC_PID_DATA0 (0 << 29)
-#define TSIZ_SC_MC_PID_DATA2 (1 << 29)
-#define TSIZ_SC_MC_PID_DATA1 (2 << 29)
-#define TSIZ_SC_MC_PID_MDATA (3 << 29)
-#define TSIZ_SC_MC_PID_SETUP (3 << 29)
+#define TSIZ_SC_MC_PID_DATA0 0
+#define TSIZ_SC_MC_PID_DATA2 1
+#define TSIZ_SC_MC_PID_DATA1 2
+#define TSIZ_SC_MC_PID_MDATA 3
+#define TSIZ_SC_MC_PID_SETUP 3
#define TSIZ_PKTCNT_MASK (0x3ff << 19)
#define TSIZ_PKTCNT_SHIFT 19
#define TSIZ_NTD_MASK (0xff << 8)
diff --git a/drivers/staging/dwc2/pci.c b/drivers/staging/dwc2/pci.c
index 3ca54d6782f..9020260d5df 100644
--- a/drivers/staging/dwc2/pci.c
+++ b/drivers/staging/dwc2/pci.c
@@ -74,7 +74,7 @@ static const struct dwc2_core_params dwc2_module_params = {
.max_packet_count = 511,
.host_channels = -1,
.phy_type = -1,
- .phy_utmi_width = 16, /* 16 bits - NOT DETECTABLE */
+ .phy_utmi_width = -1,
.phy_ulpi_ddr = -1,
.phy_ulpi_ext_vbus = -1,
.i2c_enable = -1,
@@ -83,7 +83,7 @@ static const struct dwc2_core_params dwc2_module_params = {
.host_ls_low_power_phy_clk = -1,
.ts_dline = -1,
.reload_ctl = -1,
- .ahb_single = -1,
+ .ahbcfg = -1,
};
/**
diff --git a/drivers/staging/et131x/README b/drivers/staging/et131x/README
index 05ad0850166..9272a24ae61 100644
--- a/drivers/staging/et131x/README
+++ b/drivers/staging/et131x/README
@@ -8,7 +8,6 @@ Note, the powermanagement options were removed from the vendor provided
driver as they did not build properly at the time.
TODO:
- - some rx packets have CRC/code/frame errors
- Look at reducing the number of spinlocks
- Simplify code in nic_rx_pkts(), when determining multicast_pkts_rcvd
- Implement NAPI support
diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c
index 5590ebf1da1..817f837b240 100644
--- a/drivers/staging/frontier/alphatrack.c
+++ b/drivers/staging/frontier/alphatrack.c
@@ -827,11 +827,11 @@ static void usb_alphatrack_disconnect(struct usb_interface *intf)
mutex_unlock(&dev->mtx);
usb_alphatrack_delete(dev);
} else {
+ atomic_set(&dev->writes_pending, 0);
dev->intf = NULL;
mutex_unlock(&dev->mtx);
}
- atomic_set(&dev->writes_pending, 0);
mutex_unlock(&disconnect_mutex);
dev_info(&intf->dev, "Alphatrack Surface #%d now disconnected\n",
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
index 6cbf9c7c1d3..074b0e5bcc6 100644
--- a/drivers/staging/frontier/tranzport.c
+++ b/drivers/staging/frontier/tranzport.c
@@ -177,24 +177,24 @@ static void usb_tranzport_abort_transfers(struct usb_tranzport *dev)
}
#define show_int(value) \
- static ssize_t show_##value(struct device *dev, \
+ static ssize_t value##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
struct usb_tranzport *t = usb_get_intfdata(intf); \
return sprintf(buf, "%d\n", t->value); \
} \
- static DEVICE_ATTR(value, S_IRUGO, show_##value, NULL);
+ static DEVICE_ATTR_RO(value)
#define show_set_int(value) \
- static ssize_t show_##value(struct device *dev, \
+ static ssize_t value##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
struct usb_tranzport *t = usb_get_intfdata(intf); \
return sprintf(buf, "%d\n", t->value); \
} \
- static ssize_t set_##value(struct device *dev, \
+ static ssize_t value##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
@@ -206,7 +206,7 @@ static void usb_tranzport_abort_transfers(struct usb_tranzport *dev)
t->value = temp; \
return count; \
} \
- static DEVICE_ATTR(value, S_IWUSR | S_IRUGO, show_##value, set_##value);
+ static DEVICE_ATTR_RW(value)
show_int(enable);
show_int(offline);
diff --git a/drivers/staging/gdm724x/Kconfig b/drivers/staging/gdm724x/Kconfig
new file mode 100644
index 00000000000..0a1f090bbf3
--- /dev/null
+++ b/drivers/staging/gdm724x/Kconfig
@@ -0,0 +1,15 @@
+#
+# GCT GDM724x LTE driver configuration
+#
+
+config LTE_GDM724X
+ tristate "GCT GDM724x LTE support"
+ depends on NET && USB && TTY && m
+ help
+ This driver supports GCT GDM724x LTE chip based USB modem devices.
+ It exposes 4 network devices to be used per PDN and 2 tty devices to be
+ used for AT commands and DM monitoring applications.
+ The modules will be called gdmulte.ko and gdmtty.ko
+
+ GCT-ATCx can be used for AT Commands
+ GCT-DMx can be used for LTE protocol monitoring
diff --git a/drivers/staging/gdm724x/Makefile b/drivers/staging/gdm724x/Makefile
new file mode 100644
index 00000000000..ba7f11a6a09
--- /dev/null
+++ b/drivers/staging/gdm724x/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_LTE_GDM724X) := gdmulte.o
+gdmulte-y += gdm_lte.o netlink_k.o
+gdmulte-y += gdm_usb.o gdm_endian.o
+
+obj-$(CONFIG_LTE_GDM724X) += gdmtty.o
+gdmtty-y := gdm_tty.o gdm_mux.o
+
diff --git a/drivers/staging/gdm724x/TODO b/drivers/staging/gdm724x/TODO
new file mode 100644
index 00000000000..b2b571ecb06
--- /dev/null
+++ b/drivers/staging/gdm724x/TODO
@@ -0,0 +1,16 @@
+TODO:
+- Clean up coding style to meet kernel standard. (80 line limit, netdev_err)
+- Remove test for host endian
+- Remove confusing macros (endian, hci_send, sdu_send, rcv_with_cb)
+- Fixes for every instances of function returning -1
+- Check for skb->len in gdm_lte_emulate_arp()
+- Use ALIGN() macro for dummy_cnt in up_to_host()
+- Error handling in init_usb()
+- Explain reason for multiples of 512 bytes in alloc_tx_struct()
+- Review use of atomic allocation for tx structs
+- No error checking for alloc_tx_struct in do_tx()
+- fix up static tty port allocation to be dynamic
+
+Patches to:
+ Jonathan Kim <jonathankim@gctsemi.com>
+ Dean ahn <deanahn@gctsemi.com>
diff --git a/drivers/staging/gdm724x/gdm_endian.c b/drivers/staging/gdm724x/gdm_endian.c
new file mode 100644
index 00000000000..f6cc90ae9ba
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_endian.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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 <linux/slab.h>
+#include "gdm_endian.h"
+
+void gdm_set_endian(struct gdm_endian *ed, u8 dev_endian)
+{
+ u8 a[2] = {0x12, 0x34};
+ u8 b[2] = {0, };
+ u16 c = 0x1234;
+
+ if (dev_endian == ENDIANNESS_BIG)
+ ed->dev_ed = ENDIANNESS_BIG;
+ else
+ ed->dev_ed = ENDIANNESS_LITTLE;
+
+ memcpy(b, &c, 2);
+
+ if (a[0] != b[0])
+ ed->host_ed = ENDIANNESS_LITTLE;
+ else
+ ed->host_ed = ENDIANNESS_BIG;
+
+}
+
+u16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x)
+{
+ if (ed->dev_ed == ed->host_ed)
+ return x;
+
+ return Endian16_Swap(x);
+}
+
+u16 gdm_dev16_to_cpu(struct gdm_endian *ed, u16 x)
+{
+ if (ed->dev_ed == ed->host_ed)
+ return x;
+
+ return Endian16_Swap(x);
+}
+
+u32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x)
+{
+ if (ed->dev_ed == ed->host_ed)
+ return x;
+
+ return Endian32_Swap(x);
+}
+
+u32 gdm_dev32_to_cpu(struct gdm_endian *ed, u32 x)
+{
+ if (ed->dev_ed == ed->host_ed)
+ return x;
+
+ return Endian32_Swap(x);
+}
diff --git a/drivers/staging/gdm724x/gdm_endian.h b/drivers/staging/gdm724x/gdm_endian.h
new file mode 100644
index 00000000000..9b2531ff908
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_endian.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef __GDM_ENDIAN_H__
+#define __GDM_ENDIAN_H__
+
+#include <linux/types.h>
+
+#define Endian16_Swap(value) \
+ ((((u16)((value) & 0x00FF)) << 8) | \
+ (((u16)((value) & 0xFF00)) >> 8))
+
+#define Endian32_Swap(value) \
+ ((((u32)((value) & 0x000000FF)) << 24) | \
+ (((u32)((value) & 0x0000FF00)) << 8) | \
+ (((u32)((value) & 0x00FF0000)) >> 8) | \
+ (((u32)((value) & 0xFF000000)) >> 24))
+
+enum {
+ ENDIANNESS_MIN = 0,
+ ENDIANNESS_UNKNOWN,
+ ENDIANNESS_LITTLE,
+ ENDIANNESS_BIG,
+ ENDIANNESS_MIDDLE,
+ ENDIANNESS_MAX
+};
+
+struct gdm_endian {
+ u8 dev_ed;
+ u8 host_ed;
+};
+
+void gdm_set_endian(struct gdm_endian *ed, u8 dev_endian);
+u16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x);
+u16 gdm_dev16_to_cpu(struct gdm_endian *ed, u16 x);
+u32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x);
+u32 gdm_dev32_to_cpu(struct gdm_endian *ed, u32 x);
+
+#endif /*__GDM_ENDIAN_H__*/
diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c
new file mode 100644
index 00000000000..bc0d510fb0a
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_lte.c
@@ -0,0 +1,877 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/in6.h>
+#include <linux/tcp.h>
+#include <linux/icmp.h>
+#include <linux/icmpv6.h>
+#include <linux/uaccess.h>
+#include <net/ndisc.h>
+
+#include "gdm_lte.h"
+#include "netlink_k.h"
+#include "hci.h"
+#include "hci_packet.h"
+#include "gdm_endian.h"
+
+/*
+ * Netlink protocol number
+ */
+#define NETLINK_LTE 30
+
+/*
+ * Default MTU Size
+ */
+#define DEFAULT_MTU_SIZE 1500
+
+#define gdm_dev_endian(n) (\
+ n->phy_dev->get_endian(n->phy_dev->priv_dev))
+
+#define gdm_lte_hci_send(n, d, l) (\
+ n->phy_dev->send_hci_func(n->phy_dev->priv_dev, d, l, NULL, NULL))
+
+#define gdm_lte_sdu_send(n, d, l, c, b, i, t) (\
+ n->phy_dev->send_sdu_func(n->phy_dev->priv_dev, d, l, n->pdn_table.dft_eps_id, 0, c, b, i, t))
+
+#define gdm_lte_rcv_with_cb(n, c, b, e) (\
+ n->rcv_func(n->priv_dev, c, b, e))
+
+#define IP_VERSION_4 4
+#define IP_VERSION_6 6
+
+static struct {
+ int ref_cnt;
+ struct sock *sock;
+} lte_event;
+
+static struct device_type wwan_type = {
+ .name = "wwan",
+};
+
+static int gdm_lte_open(struct net_device *dev)
+{
+ netif_start_queue(dev);
+ return 0;
+}
+
+static int gdm_lte_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ return 0;
+}
+
+static int gdm_lte_set_config(struct net_device *dev, struct ifmap *map)
+{
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+ return 0;
+}
+
+static void tx_complete(void *arg)
+{
+ struct nic *nic = arg;
+
+ if (netif_queue_stopped(nic->netdev))
+ netif_wake_queue(nic->netdev);
+}
+
+static int gdm_lte_rx(struct sk_buff *skb, struct nic *nic, int nic_type)
+{
+ int ret;
+
+ ret = netif_rx_ni(skb);
+ if (ret == NET_RX_DROP) {
+ nic->stats.rx_dropped++;
+ } else {
+ nic->stats.rx_packets++;
+ nic->stats.rx_bytes += skb->len + ETH_HLEN;
+ }
+
+ return 0;
+}
+
+int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type)
+{
+ struct nic *nic = netdev_priv(skb_in->dev);
+ struct sk_buff *skb_out;
+ struct ethhdr eth;
+ struct vlan_ethhdr vlan_eth;
+ struct arphdr *arp_in;
+ struct arphdr *arp_out;
+ struct arpdata {
+ u8 ar_sha[ETH_ALEN];
+ u8 ar_sip[4];
+ u8 ar_tha[ETH_ALEN];
+ u8 ar_tip[4];
+ };
+ struct arpdata *arp_data_in;
+ struct arpdata *arp_data_out;
+ u8 arp_temp[60];
+ void *mac_header_data;
+ u32 mac_header_len;
+
+ /* Format the mac header so that it can be put to skb */
+ if (ntohs(((struct ethhdr *)skb_in->data)->h_proto) == ETH_P_8021Q) {
+ memcpy(&vlan_eth, skb_in->data, sizeof(struct vlan_ethhdr));
+ mac_header_data = &vlan_eth;
+ mac_header_len = VLAN_ETH_HLEN;
+ } else {
+ memcpy(&eth, skb_in->data, sizeof(struct ethhdr));
+ mac_header_data = &eth;
+ mac_header_len = ETH_HLEN;
+ }
+
+ /* Get the pointer of the original request */
+ arp_in = (struct arphdr *)(skb_in->data + mac_header_len);
+ arp_data_in = (struct arpdata *)(skb_in->data + mac_header_len + sizeof(struct arphdr));
+
+ /* Get the pointer of the outgoing response */
+ arp_out = (struct arphdr *)arp_temp;
+ arp_data_out = (struct arpdata *)(arp_temp + sizeof(struct arphdr));
+
+ /* Copy the arp header */
+ memcpy(arp_out, arp_in, sizeof(struct arphdr));
+ arp_out->ar_op = htons(ARPOP_REPLY);
+
+ /* Copy the arp payload: based on 2 bytes of mac and fill the IP */
+ arp_data_out->ar_sha[0] = arp_data_in->ar_sha[0];
+ arp_data_out->ar_sha[1] = arp_data_in->ar_sha[1];
+ memcpy(&arp_data_out->ar_sha[2], &arp_data_in->ar_tip[0], 4);
+ memcpy(&arp_data_out->ar_sip[0], &arp_data_in->ar_tip[0], 4);
+ memcpy(&arp_data_out->ar_tha[0], &arp_data_in->ar_sha[0], 6);
+ memcpy(&arp_data_out->ar_tip[0], &arp_data_in->ar_sip[0], 4);
+
+ /* Fill the destination mac with source mac of the received packet */
+ memcpy(mac_header_data, mac_header_data + ETH_ALEN, ETH_ALEN);
+ /* Fill the source mac with nic's source mac */
+ memcpy(mac_header_data + ETH_ALEN, nic->src_mac_addr, ETH_ALEN);
+
+ /* Alloc skb and reserve align */
+ skb_out = dev_alloc_skb(skb_in->len);
+ if (!skb_out)
+ return -ENOMEM;
+ skb_reserve(skb_out, NET_IP_ALIGN);
+
+ memcpy(skb_put(skb_out, mac_header_len), mac_header_data, mac_header_len);
+ memcpy(skb_put(skb_out, sizeof(struct arphdr)), arp_out, sizeof(struct arphdr));
+ memcpy(skb_put(skb_out, sizeof(struct arpdata)), arp_data_out, sizeof(struct arpdata));
+
+ skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto;
+ skb_out->dev = skb_in->dev;
+ skb_reset_mac_header(skb_out);
+ skb_pull(skb_out, ETH_HLEN);
+
+ gdm_lte_rx(skb_out, nic, nic_type);
+
+ return 0;
+}
+
+int icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len)
+{
+ unsigned short *w = ptr;
+ int sum = 0;
+ int i;
+
+ union {
+ struct {
+ u8 ph_src[16];
+ u8 ph_dst[16];
+ u32 ph_len;
+ u8 ph_zero[3];
+ u8 ph_nxt;
+ } ph __packed;
+ u16 pa[20];
+ } pseudo_header;
+
+ memset(&pseudo_header, 0, sizeof(pseudo_header));
+ memcpy(&pseudo_header.ph.ph_src, &ipv6->saddr.in6_u.u6_addr8, 16);
+ memcpy(&pseudo_header.ph.ph_dst, &ipv6->daddr.in6_u.u6_addr8, 16);
+ pseudo_header.ph.ph_len = ipv6->payload_len;
+ pseudo_header.ph.ph_nxt = ipv6->nexthdr;
+
+ w = (u16 *)&pseudo_header;
+ for (i = 0; i < sizeof(pseudo_header.pa) / sizeof(pseudo_header.pa[0]); i++)
+ sum += pseudo_header.pa[i];
+
+ w = ptr;
+ while (len > 1) {
+ sum += *w++;
+ len -= 2;
+ }
+
+ sum = (sum >> 16) + (sum & 0xFFFF);
+ sum += (sum >> 16);
+ sum = ~sum & 0xffff;
+
+ return sum;
+}
+
+int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type)
+{
+ struct nic *nic = netdev_priv(skb_in->dev);
+ struct sk_buff *skb_out;
+ struct ethhdr eth;
+ struct vlan_ethhdr vlan_eth;
+ struct neighbour_advertisement {
+ u8 target_address[16];
+ u8 type;
+ u8 length;
+ u8 link_layer_address[6];
+ };
+ struct neighbour_advertisement na;
+ struct neighbour_solicitation {
+ u8 target_address[16];
+ };
+ struct neighbour_solicitation *ns;
+ struct ipv6hdr *ipv6_in;
+ struct ipv6hdr ipv6_out;
+ struct icmp6hdr *icmp6_in;
+ struct icmp6hdr icmp6_out;
+
+ void *mac_header_data;
+ u32 mac_header_len;
+
+ /* Format the mac header so that it can be put to skb */
+ if (ntohs(((struct ethhdr *)skb_in->data)->h_proto) == ETH_P_8021Q) {
+ memcpy(&vlan_eth, skb_in->data, sizeof(struct vlan_ethhdr));
+ if (ntohs(vlan_eth.h_vlan_encapsulated_proto) != ETH_P_IPV6)
+ return -1;
+ mac_header_data = &vlan_eth;
+ mac_header_len = VLAN_ETH_HLEN;
+ } else {
+ memcpy(&eth, skb_in->data, sizeof(struct ethhdr));
+ if (ntohs(eth.h_proto) != ETH_P_IPV6)
+ return -1;
+ mac_header_data = &eth;
+ mac_header_len = ETH_HLEN;
+ }
+
+ /* Check if this is IPv6 ICMP packet */
+ ipv6_in = (struct ipv6hdr *)(skb_in->data + mac_header_len);
+ if (ipv6_in->version != 6 || ipv6_in->nexthdr != IPPROTO_ICMPV6)
+ return -1;
+
+ /* Check if this is NDP packet */
+ icmp6_in = (struct icmp6hdr *)(skb_in->data + mac_header_len + sizeof(struct ipv6hdr));
+ if (icmp6_in->icmp6_type == NDISC_ROUTER_SOLICITATION) { /* Check RS */
+ return -1;
+ } else if (icmp6_in->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { /* Check NS */
+ u8 icmp_na[sizeof(struct icmp6hdr) + sizeof(struct neighbour_advertisement)];
+ u8 zero_addr8[16] = {0,};
+
+ if (memcmp(ipv6_in->saddr.in6_u.u6_addr8, zero_addr8, 16) == 0)
+ /* Duplicate Address Detection: Source IP is all zero */
+ return 0;
+
+ icmp6_out.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+ icmp6_out.icmp6_code = 0;
+ icmp6_out.icmp6_cksum = 0;
+ icmp6_out.icmp6_dataun.un_data32[0] = htonl(0x60000000); /* R=0, S=1, O=1 */
+
+ ns = (struct neighbour_solicitation *)(skb_in->data + mac_header_len + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr));
+ memcpy(&na.target_address, ns->target_address, 16);
+ na.type = 0x02;
+ na.length = 1;
+ na.link_layer_address[0] = 0x00;
+ na.link_layer_address[1] = 0x0a;
+ na.link_layer_address[2] = 0x3b;
+ na.link_layer_address[3] = 0xaf;
+ na.link_layer_address[4] = 0x63;
+ na.link_layer_address[5] = 0xc7;
+
+ memcpy(&ipv6_out, ipv6_in, sizeof(struct ipv6hdr));
+ memcpy(ipv6_out.saddr.in6_u.u6_addr8, &na.target_address, 16);
+ memcpy(ipv6_out.daddr.in6_u.u6_addr8, ipv6_in->saddr.in6_u.u6_addr8, 16);
+ ipv6_out.payload_len = htons(sizeof(struct icmp6hdr) + sizeof(struct neighbour_advertisement));
+
+ memcpy(icmp_na, &icmp6_out, sizeof(struct icmp6hdr));
+ memcpy(icmp_na + sizeof(struct icmp6hdr), &na, sizeof(struct neighbour_advertisement));
+
+ icmp6_out.icmp6_cksum = icmp6_checksum(&ipv6_out, (u16 *)icmp_na, sizeof(icmp_na));
+ } else {
+ return -1;
+ }
+
+ /* Fill the destination mac with source mac of the received packet */
+ memcpy(mac_header_data, mac_header_data + ETH_ALEN, ETH_ALEN);
+ /* Fill the source mac with nic's source mac */
+ memcpy(mac_header_data + ETH_ALEN, nic->src_mac_addr, ETH_ALEN);
+
+ /* Alloc skb and reserve align */
+ skb_out = dev_alloc_skb(skb_in->len);
+ if (!skb_out)
+ return -ENOMEM;
+ skb_reserve(skb_out, NET_IP_ALIGN);
+
+ memcpy(skb_put(skb_out, mac_header_len), mac_header_data, mac_header_len);
+ memcpy(skb_put(skb_out, sizeof(struct ipv6hdr)), &ipv6_out, sizeof(struct ipv6hdr));
+ memcpy(skb_put(skb_out, sizeof(struct icmp6hdr)), &icmp6_out, sizeof(struct icmp6hdr));
+ memcpy(skb_put(skb_out, sizeof(struct neighbour_advertisement)), &na, sizeof(struct neighbour_advertisement));
+
+ skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto;
+ skb_out->dev = skb_in->dev;
+ skb_reset_mac_header(skb_out);
+ skb_pull(skb_out, ETH_HLEN);
+
+ gdm_lte_rx(skb_out, nic, nic_type);
+
+ return 0;
+}
+
+static s32 gdm_lte_tx_nic_type(struct net_device *dev, struct sk_buff *skb)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct ethhdr *eth;
+ struct vlan_ethhdr *vlan_eth;
+ struct iphdr *ip;
+ struct ipv6hdr *ipv6;
+ int mac_proto;
+ void *network_data;
+ u32 nic_type = 0;
+
+ /* NIC TYPE is based on the nic_id of this net_device */
+ nic_type = 0x00000010 | nic->nic_id;
+
+ /* Get ethernet protocol */
+ eth = (struct ethhdr *)skb->data;
+ if (ntohs(eth->h_proto) == ETH_P_8021Q) {
+ vlan_eth = (struct vlan_ethhdr *)skb->data;
+ mac_proto = ntohs(vlan_eth->h_vlan_encapsulated_proto);
+ network_data = skb->data + VLAN_ETH_HLEN;
+ nic_type |= NIC_TYPE_F_VLAN;
+ } else {
+ mac_proto = ntohs(eth->h_proto);
+ network_data = skb->data + ETH_HLEN;
+ }
+
+ /* Process packet for nic type */
+ switch (mac_proto) {
+ case ETH_P_ARP:
+ nic_type |= NIC_TYPE_ARP;
+ break;
+ case ETH_P_IP:
+ nic_type |= NIC_TYPE_F_IPV4;
+ ip = (struct iphdr *)network_data;
+
+ /* Check DHCPv4 */
+ if (ip->protocol == IPPROTO_UDP) {
+ struct udphdr *udp = (struct udphdr *)(network_data + sizeof(struct iphdr));
+ if (ntohs(udp->dest) == 67 || ntohs(udp->dest) == 68)
+ nic_type |= NIC_TYPE_F_DHCP;
+ }
+ break;
+ case ETH_P_IPV6:
+ nic_type |= NIC_TYPE_F_IPV6;
+ ipv6 = (struct ipv6hdr *)network_data;
+
+ if (ipv6->nexthdr == IPPROTO_ICMPV6) /* Check NDP request */ {
+ struct icmp6hdr *icmp6 = (struct icmp6hdr *)(network_data + sizeof(struct ipv6hdr));
+ if (/*icmp6->icmp6_type == NDISC_ROUTER_SOLICITATION || */
+ icmp6->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION)
+ nic_type |= NIC_TYPE_ICMPV6;
+ } else if (ipv6->nexthdr == IPPROTO_UDP) /* Check DHCPv6 */ {
+ struct udphdr *udp = (struct udphdr *)(network_data + sizeof(struct ipv6hdr));
+ if (ntohs(udp->dest) == 546 || ntohs(udp->dest) == 547)
+ nic_type |= NIC_TYPE_F_DHCP;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return nic_type;
+}
+
+static int gdm_lte_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ u32 nic_type;
+ void *data_buf;
+ int data_len;
+ int idx;
+ int ret = 0;
+
+ nic_type = gdm_lte_tx_nic_type(dev, skb);
+ if (nic_type == 0) {
+ netdev_err(dev, "tx - invalid nic_type\n");
+ return -1;
+ }
+
+ if (nic_type & NIC_TYPE_ARP) {
+ if (gdm_lte_emulate_arp(skb, nic_type) == 0) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ }
+
+ if (nic_type & NIC_TYPE_ICMPV6) {
+ if (gdm_lte_emulate_ndp(skb, nic_type) == 0) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ }
+
+ /*
+ Need byte shift (that is, remove VLAN tag) if there is one
+ For the case of ARP, this breaks the offset as vlan_ethhdr+4 is treated as ethhdr
+ However, it shouldn't be a problem as the response starts from arp_hdr and ethhdr
+ is created by this driver based on the NIC mac
+ */
+ if (nic_type & NIC_TYPE_F_VLAN) {
+ struct vlan_ethhdr *vlan_eth = (struct vlan_ethhdr *)skb->data;
+ nic->vlan_id = ntohs(vlan_eth->h_vlan_TCI) & VLAN_VID_MASK;
+ data_buf = skb->data + (VLAN_ETH_HLEN - ETH_HLEN);
+ data_len = skb->len - (VLAN_ETH_HLEN - ETH_HLEN);
+ } else {
+ nic->vlan_id = 0;
+ data_buf = skb->data;
+ data_len = skb->len;
+ }
+
+ /* If it is a ICMPV6 packet, clear all the other bits : for backward compatibility with the firmware */
+ if (nic_type & NIC_TYPE_ICMPV6)
+ nic_type = NIC_TYPE_ICMPV6;
+
+ /* If it is not a dhcp packet, clear all the flag bits : original NIC, otherwise the special flag (IPVX | DHCP) */
+ if (!(nic_type & NIC_TYPE_F_DHCP))
+ nic_type &= NIC_TYPE_MASK;
+
+ sscanf(dev->name, "lte%d", &idx);
+
+ ret = gdm_lte_sdu_send(nic,
+ data_buf,
+ data_len,
+ tx_complete,
+ nic,
+ idx,
+ nic_type);
+
+ if (ret == TX_NO_BUFFER || ret == TX_NO_SPC) {
+ netif_stop_queue(dev);
+ if (ret == TX_NO_BUFFER)
+ ret = 0;
+ else
+ ret = -ENOSPC;
+ } else if (ret == TX_NO_DEV) {
+ ret = -ENODEV;
+ }
+
+ /* Updates tx stats */
+ if (ret) {
+ nic->stats.tx_dropped++;
+ } else {
+ nic->stats.tx_packets++;
+ nic->stats.tx_bytes += data_len;
+ }
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+static struct net_device_stats *gdm_lte_stats(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ return &nic->stats;
+}
+
+static int gdm_lte_event_send(struct net_device *dev, char *buf, int len)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct hci_packet *hci = (struct hci_packet *)buf;
+ int idx;
+
+ sscanf(dev->name, "lte%d", &idx);
+
+ return netlink_send(lte_event.sock, idx, 0, buf,
+ gdm_dev16_to_cpu(gdm_dev_endian(nic), hci->len) + HCI_HEADER_SIZE);
+}
+
+static void gdm_lte_event_rcv(struct net_device *dev, u16 type, void *msg, int len)
+{
+ struct nic *nic = netdev_priv(dev);
+
+ gdm_lte_hci_send(nic, msg, len);
+}
+
+int gdm_lte_event_init(void)
+{
+ if (lte_event.ref_cnt == 0)
+ lte_event.sock = netlink_init(NETLINK_LTE, gdm_lte_event_rcv);
+
+ if (lte_event.sock) {
+ lte_event.ref_cnt++;
+ return 0;
+ }
+
+ pr_err("event init failed\n");
+ return -1;
+}
+
+void gdm_lte_event_exit(void)
+{
+ if (lte_event.sock && --lte_event.ref_cnt == 0) {
+ netlink_exit(lte_event.sock);
+ lte_event.sock = NULL;
+ }
+}
+
+static u8 find_dev_index(u32 nic_type)
+{
+ u8 index;
+
+ index = (u8)(nic_type & 0x0000000f);
+ if (index > MAX_NIC_TYPE)
+ index = 0;
+
+ return index;
+}
+
+static void gdm_lte_netif_rx(struct net_device *dev, char *buf, int len, int flagged_nic_type)
+{
+ u32 nic_type;
+ struct nic *nic;
+ struct sk_buff *skb;
+ struct ethhdr eth;
+ struct vlan_ethhdr vlan_eth;
+ void *mac_header_data;
+ u32 mac_header_len;
+ char ip_version = 0;
+
+ nic_type = flagged_nic_type & NIC_TYPE_MASK;
+ nic = netdev_priv(dev);
+
+ if (flagged_nic_type & NIC_TYPE_F_DHCP) {
+ /* Change the destination mac address with the one requested the IP */
+ if (flagged_nic_type & NIC_TYPE_F_IPV4) {
+ struct dhcp_packet {
+ u8 op; /* BOOTREQUEST or BOOTREPLY */
+ u8 htype; /* hardware address type. 1 = 10mb ethernet */
+ u8 hlen; /* hardware address length */
+ u8 hops; /* used by relay agents only */
+ u32 xid; /* unique id */
+ u16 secs; /* elapsed since client began acquisition/renewal */
+ u16 flags; /* only one flag so far: */
+ #define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */
+ u32 ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */
+ u32 yiaddr; /* 'your' (client) IP address */
+ /* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */
+ u32 siaddr_nip;
+ u32 gateway_nip; /* relay agent IP address */
+ u8 chaddr[16]; /* link-layer client hardware address (MAC) */
+ u8 sname[64]; /* server host name (ASCIZ) */
+ u8 file[128]; /* boot file name (ASCIZ) */
+ u32 cookie; /* fixed first four option bytes (99,130,83,99 dec) */
+ } __packed;
+ void *addr = buf + sizeof(struct iphdr) + sizeof(struct udphdr) + offsetof(struct dhcp_packet, chaddr);
+ memcpy(nic->dest_mac_addr, addr, ETH_ALEN);
+ }
+ }
+
+ if (nic->vlan_id > 0) {
+ mac_header_data = (void *)&vlan_eth;
+ mac_header_len = VLAN_ETH_HLEN;
+ } else {
+ mac_header_data = (void *)&eth;
+ mac_header_len = ETH_HLEN;
+ }
+
+ /* Format the data so that it can be put to skb */
+ memcpy(mac_header_data, nic->dest_mac_addr, ETH_ALEN);
+ memcpy(mac_header_data + ETH_ALEN, nic->src_mac_addr, ETH_ALEN);
+
+ vlan_eth.h_vlan_TCI = htons(nic->vlan_id);
+ vlan_eth.h_vlan_proto = htons(ETH_P_8021Q);
+
+ if (nic_type == NIC_TYPE_ARP) {
+ /* Should be response: Only happens because there was a request from the host */
+ eth.h_proto = htons(ETH_P_ARP);
+ vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_ARP);
+ } else {
+ ip_version = buf[0] >> 4;
+ if (ip_version == IP_VERSION_4) {
+ eth.h_proto = htons(ETH_P_IP);
+ vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_IP);
+ } else if (ip_version == IP_VERSION_6) {
+ eth.h_proto = htons(ETH_P_IPV6);
+ vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_IPV6);
+ } else {
+ netdev_err(dev, "Unknown IP version %d\n", ip_version);
+ return;
+ }
+ }
+
+ /* Alloc skb and reserve align */
+ skb = dev_alloc_skb(len + mac_header_len + NET_IP_ALIGN);
+ if (!skb)
+ return;
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ memcpy(skb_put(skb, mac_header_len), mac_header_data, mac_header_len);
+ memcpy(skb_put(skb, len), buf, len);
+
+ skb->protocol = ((struct ethhdr *)mac_header_data)->h_proto;
+ skb->dev = dev;
+ skb_reset_mac_header(skb);
+ skb_pull(skb, ETH_HLEN);
+
+ gdm_lte_rx(skb, nic, nic_type);
+}
+
+static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len)
+{
+ struct net_device *dev;
+ struct multi_sdu *multi_sdu = (struct multi_sdu *)buf;
+ struct sdu *sdu = NULL;
+ u8 *data = (u8 *)multi_sdu->data;
+ u16 i = 0;
+ u16 num_packet;
+ u16 hci_len;
+ u16 cmd_evt;
+ u32 nic_type;
+ u8 index;
+
+ hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), multi_sdu->len);
+ num_packet = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), multi_sdu->num_packet);
+
+ for (i = 0; i < num_packet; i++) {
+ sdu = (struct sdu *)data;
+
+ cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->cmd_evt);
+ hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->len);
+ nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->nic_type);
+
+ if (cmd_evt != LTE_RX_SDU) {
+ pr_err("rx sdu wrong hci %04x\n", cmd_evt);
+ return;
+ }
+ if (hci_len < 12) {
+ pr_err("rx sdu invalid len %d\n", hci_len);
+ return;
+ }
+
+ index = find_dev_index(nic_type);
+ if (index < MAX_NIC_TYPE) {
+ dev = phy_dev->dev[index];
+ gdm_lte_netif_rx(dev, (char *)sdu->data, (int)(hci_len-12), nic_type);
+ } else {
+ pr_err("rx sdu invalid nic_type :%x\n", nic_type);
+ }
+
+ data += ((hci_len+3) & 0xfffc) + HCI_HEADER_SIZE;
+ }
+}
+
+static void gdm_lte_pdn_table(struct net_device *dev, char *buf, int len)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf;
+
+ if (pdn_table->activate) {
+ nic->pdn_table.activate = pdn_table->activate;
+ nic->pdn_table.dft_eps_id = gdm_dev32_to_cpu(gdm_dev_endian(nic), pdn_table->dft_eps_id);
+ nic->pdn_table.nic_type = gdm_dev32_to_cpu(gdm_dev_endian(nic), pdn_table->nic_type);
+
+ netdev_info(dev, "pdn activated, nic_type=0x%x\n",
+ nic->pdn_table.nic_type);
+ } else {
+ memset(&nic->pdn_table, 0x00, sizeof(struct pdn_table));
+ netdev_info(dev, "pdn deactivated\n");
+ }
+}
+
+static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len)
+{
+ struct hci_packet *hci = (struct hci_packet *)buf;
+ struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf;
+ struct sdu *sdu;
+ struct net_device *dev;
+ int ret = 0;
+ u16 cmd_evt;
+ u32 nic_type;
+ u8 index;
+
+ if (!len)
+ return ret;
+
+ cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), hci->cmd_evt);
+
+ dev = phy_dev->dev[0];
+ if (dev == NULL)
+ return 0;
+
+ switch (cmd_evt) {
+ case LTE_RX_SDU:
+ sdu = (struct sdu *)hci->data;
+ nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->nic_type);
+ index = find_dev_index(nic_type);
+ dev = phy_dev->dev[index];
+ gdm_lte_netif_rx(dev, hci->data, len, nic_type);
+ break;
+ case LTE_RX_MULTI_SDU:
+ gdm_lte_multi_sdu_pkt(phy_dev, buf, len);
+ break;
+ case LTE_LINK_ON_OFF_INDICATION:
+ netdev_info(dev, "link %s\n",
+ ((struct hci_connect_ind *)buf)->connect
+ ? "on" : "off");
+ break;
+ case LTE_PDN_TABLE_IND:
+ pdn_table = (struct hci_pdn_table_ind *)buf;
+ nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), pdn_table->nic_type);
+ index = find_dev_index(nic_type);
+ dev = phy_dev->dev[index];
+ gdm_lte_pdn_table(dev, buf, len);
+ /* Fall through */
+ default:
+ ret = gdm_lte_event_send(dev, buf, len);
+ break;
+ }
+
+ return ret;
+}
+
+static int rx_complete(void *arg, void *data, int len, int context)
+{
+ struct phy_dev *phy_dev = (struct phy_dev *)arg;
+
+ return gdm_lte_receive_pkt(phy_dev, (char *)data, len);
+}
+
+void start_rx_proc(struct phy_dev *phy_dev)
+{
+ int i;
+
+ for (i = 0; i < MAX_RX_SUBMIT_COUNT; i++)
+ gdm_lte_rcv_with_cb(phy_dev, rx_complete, phy_dev, USB_COMPLETE);
+}
+
+static struct net_device_ops gdm_netdev_ops = {
+ .ndo_open = gdm_lte_open,
+ .ndo_stop = gdm_lte_close,
+ .ndo_set_config = gdm_lte_set_config,
+ .ndo_start_xmit = gdm_lte_tx,
+ .ndo_get_stats = gdm_lte_stats,
+};
+
+static u8 gdm_lte_macaddr[ETH_ALEN] = {0x00, 0x0a, 0x3b, 0x00, 0x00, 0x00};
+
+static void form_mac_address(u8 *dev_addr, u8 *nic_src, u8 *nic_dest, u8 *mac_address, u8 index)
+{
+ /* Form the dev_addr */
+ if (!mac_address)
+ memcpy(dev_addr, gdm_lte_macaddr, ETH_ALEN);
+ else
+ memcpy(dev_addr, mac_address, ETH_ALEN);
+
+ /* The last byte of the mac address should be less than or equal to 0xFC */
+ dev_addr[ETH_ALEN-1] += index;
+
+ /* Create random nic src and copy the first 3 bytes to be the same as dev_addr */
+ random_ether_addr(nic_src);
+ memcpy(nic_src, dev_addr, 3);
+
+ /* Copy the nic_dest from dev_addr*/
+ memcpy(nic_dest, dev_addr, ETH_ALEN);
+}
+
+static void validate_mac_address(u8 *mac_address)
+{
+ /* if zero address or multicast bit set, restore the default value */
+ if (is_zero_ether_addr(mac_address) || (mac_address[0] & 0x01)) {
+ pr_err("MAC invalid, restoring default\n");
+ memcpy(mac_address, gdm_lte_macaddr, 6);
+ }
+}
+
+int register_lte_device(struct phy_dev *phy_dev, struct device *dev, u8 *mac_address)
+{
+ struct nic *nic;
+ struct net_device *net;
+ char pdn_dev_name[16];
+ int ret = 0;
+ u8 index;
+
+ validate_mac_address(mac_address);
+
+ for (index = 0; index < MAX_NIC_TYPE; index++) {
+ /* Create device name lteXpdnX */
+ sprintf(pdn_dev_name, "lte%%dpdn%d", index);
+
+ /* Allocate netdev */
+ net = alloc_netdev(sizeof(struct nic), pdn_dev_name, ether_setup);
+ if (net == NULL) {
+ pr_err("alloc_netdev failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ net->netdev_ops = &gdm_netdev_ops;
+ net->flags &= ~IFF_MULTICAST;
+ net->mtu = DEFAULT_MTU_SIZE;
+
+ nic = netdev_priv(net);
+ memset(nic, 0, sizeof(struct nic));
+ nic->netdev = net;
+ nic->phy_dev = phy_dev;
+ nic->nic_id = index;
+
+ form_mac_address(
+ net->dev_addr,
+ nic->src_mac_addr,
+ nic->dest_mac_addr,
+ mac_address,
+ index);
+
+ SET_NETDEV_DEV(net, dev);
+ SET_NETDEV_DEVTYPE(net, &wwan_type);
+
+ ret = register_netdev(net);
+ if (ret)
+ goto err;
+
+ netif_carrier_on(net);
+
+ phy_dev->dev[index] = net;
+ }
+
+ return 0;
+
+err:
+ unregister_lte_device(phy_dev);
+
+ return ret;
+}
+
+void unregister_lte_device(struct phy_dev *phy_dev)
+{
+ struct net_device *net;
+ int index;
+
+ for (index = 0; index < MAX_NIC_TYPE; index++) {
+ net = phy_dev->dev[index];
+ if (net == NULL)
+ continue;
+
+ unregister_netdev(net);
+ free_netdev(net);
+ }
+}
diff --git a/drivers/staging/gdm724x/gdm_lte.h b/drivers/staging/gdm724x/gdm_lte.h
new file mode 100644
index 00000000000..9287d310d8e
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_lte.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _GDM_LTE_H_
+#define _GDM_LTE_H_
+
+#include <linux/netdevice.h>
+#include <linux/types.h>
+
+#include "gdm_endian.h"
+
+#define MAX_NIC_TYPE 4
+#define MAX_RX_SUBMIT_COUNT 3
+#define DRIVER_VERSION "3.7.17.0"
+
+enum TX_ERROR_CODE {
+ TX_NO_ERROR = 0,
+ TX_NO_DEV,
+ TX_NO_SPC,
+ TX_NO_BUFFER,
+};
+
+enum CALLBACK_CONTEXT {
+ KERNEL_THREAD = 0,
+ USB_COMPLETE,
+};
+
+struct pdn_table {
+ u8 activate;
+ u32 dft_eps_id;
+ u32 nic_type;
+} __packed;
+
+struct nic;
+
+struct phy_dev {
+ void *priv_dev;
+ struct net_device *dev[MAX_NIC_TYPE];
+ int (*send_hci_func)(void *priv_dev, void *data, int len,
+ void (*cb)(void *cb_data), void *cb_data);
+ int (*send_sdu_func)(void *priv_dev, void *data, int len,
+ unsigned int dftEpsId, unsigned int epsId,
+ void (*cb)(void *cb_data), void *cb_data,
+ int dev_idx, int nic_type);
+ int (*rcv_func)(void *priv_dev,
+ int (*cb)(void *cb_data, void *data, int len,
+ int context),
+ void *cb_data, int context);
+ struct gdm_endian *(*get_endian)(void *priv_dev);
+};
+
+struct nic {
+ struct net_device *netdev;
+ struct phy_dev *phy_dev;
+ struct net_device_stats stats;
+ struct pdn_table pdn_table;
+ u8 dest_mac_addr[ETH_ALEN];
+ u8 src_mac_addr[ETH_ALEN];
+ u32 nic_id;
+ u16 vlan_id;
+};
+
+int gdm_lte_event_init(void);
+void gdm_lte_event_exit(void);
+
+void start_rx_proc(struct phy_dev *phy_dev);
+int register_lte_device(struct phy_dev *phy_dev, struct device *dev,
+ u8 *mac_address);
+void unregister_lte_device(struct phy_dev *phy_dev);
+
+#endif /* _GDM_LTE_H_ */
diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c
new file mode 100644
index 00000000000..5b1ef4000d0
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_mux.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/usb/cdc.h>
+
+#include "gdm_mux.h"
+
+struct workqueue_struct *mux_rx_wq;
+
+static u16 packet_type[TTY_MAX_COUNT] = {0xF011, 0xF010};
+
+#define USB_DEVICE_CDC_DATA(vid, pid) \
+ .match_flags = \
+ USB_DEVICE_ID_MATCH_DEVICE |\
+ USB_DEVICE_ID_MATCH_INT_CLASS |\
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS,\
+ .idVendor = vid,\
+ .idProduct = pid,\
+ .bInterfaceClass = USB_CLASS_COMM,\
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM
+
+static const struct usb_device_id id_table[] = {
+ { USB_DEVICE_CDC_DATA(0x1076, 0x8000) }, /* GCT GDM7240 */
+ { USB_DEVICE_CDC_DATA(0x1076, 0x8f00) }, /* GCT GDM7243 */
+ { USB_DEVICE_CDC_DATA(0x1076, 0x9000) }, /* GCT GDM7243 */
+ { USB_DEVICE_CDC_DATA(0x1d74, 0x2300) }, /* LGIT Phoenix */
+ {}
+};
+
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+int packet_type_to_index(u16 packetType)
+{
+ int i;
+
+ for (i = 0; i < TTY_MAX_COUNT; i++) {
+ if (packet_type[i] == packetType)
+ return i;
+ }
+
+ return -1;
+}
+
+static struct mux_tx *alloc_mux_tx(int len)
+{
+ struct mux_tx *t = NULL;
+
+ t = kzalloc(sizeof(struct mux_tx), GFP_ATOMIC);
+ if (!t)
+ return NULL;
+
+ t->urb = usb_alloc_urb(0, GFP_ATOMIC);
+ t->buf = kmalloc(MUX_TX_MAX_SIZE, GFP_ATOMIC);
+ if (!t->urb || !t->buf) {
+ usb_free_urb(t->urb);
+ kfree(t->buf);
+ kfree(t);
+ return NULL;
+ }
+
+ return t;
+}
+
+static void free_mux_tx(struct mux_tx *t)
+{
+ if (t) {
+ usb_free_urb(t->urb);
+ kfree(t->buf);
+ kfree(t);
+ }
+}
+
+static struct mux_rx *alloc_mux_rx(void)
+{
+ struct mux_rx *r = NULL;
+
+ r = kzalloc(sizeof(struct mux_rx), GFP_ATOMIC);
+ if (!r)
+ return NULL;
+
+ r->urb = usb_alloc_urb(0, GFP_ATOMIC);
+ r->buf = kmalloc(MUX_RX_MAX_SIZE, GFP_ATOMIC);
+ if (!r->urb || !r->buf) {
+ usb_free_urb(r->urb);
+ kfree(r->buf);
+ kfree(r);
+ return NULL;
+ }
+
+ return r;
+}
+
+static void free_mux_rx(struct mux_rx *r)
+{
+ if (r) {
+ usb_free_urb(r->urb);
+ kfree(r->buf);
+ kfree(r);
+ }
+}
+
+static struct mux_rx *get_rx_struct(struct rx_cxt *rx)
+{
+ struct mux_rx *r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rx->free_list_lock, flags);
+
+ if (list_empty(&rx->rx_free_list)) {
+ spin_unlock_irqrestore(&rx->free_list_lock, flags);
+ return NULL;
+ }
+
+ r = list_entry(rx->rx_free_list.prev, struct mux_rx, free_list);
+ list_del(&r->free_list);
+
+ spin_unlock_irqrestore(&rx->free_list_lock, flags);
+
+ return r;
+}
+
+static void put_rx_struct(struct rx_cxt *rx, struct mux_rx *r)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rx->free_list_lock, flags);
+ list_add_tail(&r->free_list, &rx->rx_free_list);
+ spin_unlock_irqrestore(&rx->free_list_lock, flags);
+}
+
+
+static int up_to_host(struct mux_rx *r)
+{
+ struct mux_dev *mux_dev = (struct mux_dev *)r->mux_dev;
+ struct mux_pkt_header *mux_header;
+ unsigned int start_flag;
+ unsigned int payload_size;
+ unsigned short packet_type;
+ int remain;
+ int dummy_cnt;
+ u32 packet_size_sum = r->offset;
+ int index;
+ int ret = TO_HOST_INVALID_PACKET;
+ int len = r->len;
+
+ while (1) {
+ mux_header = (struct mux_pkt_header *)(r->buf + packet_size_sum);
+ start_flag = __le32_to_cpu(mux_header->start_flag);
+ payload_size = __le32_to_cpu(mux_header->payload_size);
+ packet_type = __le16_to_cpu(mux_header->packet_type);
+
+ if (start_flag != START_FLAG) {
+ pr_err("invalid START_FLAG %x\n", start_flag);
+ break;
+ }
+
+ remain = (MUX_HEADER_SIZE + payload_size) % 4;
+ dummy_cnt = remain ? (4-remain) : 0;
+
+ if (len - packet_size_sum <
+ MUX_HEADER_SIZE + payload_size + dummy_cnt) {
+ pr_err("invalid payload : %d %d %04x\n",
+ payload_size, len, packet_type);
+ break;
+ }
+
+ index = packet_type_to_index(packet_type);
+ if (index < 0) {
+ pr_err("invalid index %d\n", index);
+ break;
+ }
+
+ ret = r->callback(mux_header->data,
+ payload_size,
+ index,
+ mux_dev->tty_dev,
+ RECV_PACKET_PROCESS_CONTINUE
+ );
+ if (ret == TO_HOST_BUFFER_REQUEST_FAIL) {
+ r->offset += packet_size_sum;
+ break;
+ }
+
+ packet_size_sum += MUX_HEADER_SIZE + payload_size + dummy_cnt;
+ if (len - packet_size_sum <= MUX_HEADER_SIZE + 2) {
+ ret = r->callback(NULL,
+ 0,
+ index,
+ mux_dev->tty_dev,
+ RECV_PACKET_PROCESS_COMPLETE
+ );
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void do_rx(struct work_struct *work)
+{
+ struct mux_dev *mux_dev =
+ container_of(work, struct mux_dev , work_rx.work);
+ struct mux_rx *r;
+ struct rx_cxt *rx = (struct rx_cxt *)&mux_dev->rx;
+ unsigned long flags;
+ int ret = 0;
+
+ while (1) {
+ spin_lock_irqsave(&rx->to_host_lock, flags);
+ if (list_empty(&rx->to_host_list)) {
+ spin_unlock_irqrestore(&rx->to_host_lock, flags);
+ break;
+ }
+ r = list_entry(rx->to_host_list.next, struct mux_rx, to_host_list);
+ list_del(&r->to_host_list);
+ spin_unlock_irqrestore(&rx->to_host_lock, flags);
+
+ ret = up_to_host(r);
+ if (ret == TO_HOST_BUFFER_REQUEST_FAIL)
+ pr_err("failed to send mux data to host\n");
+ else
+ put_rx_struct(rx, r);
+ }
+}
+
+static void remove_rx_submit_list(struct mux_rx *r, struct rx_cxt *rx)
+{
+ unsigned long flags;
+ struct mux_rx *r_remove, *r_remove_next;
+
+ spin_lock_irqsave(&rx->submit_list_lock, flags);
+ list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, rx_submit_list) {
+ if (r == r_remove)
+ list_del(&r->rx_submit_list);
+ }
+ spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+}
+
+static void gdm_mux_rcv_complete(struct urb *urb)
+{
+ struct mux_rx *r = urb->context;
+ struct mux_dev *mux_dev = (struct mux_dev *)r->mux_dev;
+ struct rx_cxt *rx = &mux_dev->rx;
+ unsigned long flags;
+
+ remove_rx_submit_list(r, rx);
+
+ if (urb->status) {
+ if (mux_dev->usb_state == PM_NORMAL)
+ pr_err("%s: urb status error %d\n",
+ __func__, urb->status);
+ put_rx_struct(rx, r);
+ } else {
+ r->len = r->urb->actual_length;
+ spin_lock_irqsave(&rx->to_host_lock, flags);
+ list_add_tail(&r->to_host_list, &rx->to_host_list);
+ queue_work(mux_rx_wq, &mux_dev->work_rx.work);
+ spin_unlock_irqrestore(&rx->to_host_lock, flags);
+ }
+}
+
+static int gdm_mux_recv(void *priv_dev,
+ int (*cb)(void *data, int len, int tty_index, struct tty_dev *tty_dev, int complete)
+ )
+{
+ struct mux_dev *mux_dev = priv_dev;
+ struct usb_device *usbdev = mux_dev->usbdev;
+ struct mux_rx *r;
+ struct rx_cxt *rx = &mux_dev->rx;
+ unsigned long flags;
+ int ret;
+
+ if (!usbdev) {
+ pr_err("device is disconnected\n");
+ return -ENODEV;
+ }
+
+ r = get_rx_struct(rx);
+ if (!r) {
+ pr_err("get_rx_struct fail\n");
+ return -ENOMEM;
+ }
+
+ r->offset = 0;
+ r->mux_dev = (void *)mux_dev;
+ r->callback = cb;
+ mux_dev->rx_cb = cb;
+
+ usb_fill_bulk_urb(r->urb,
+ usbdev,
+ usb_rcvbulkpipe(usbdev, 0x86),
+ r->buf,
+ MUX_RX_MAX_SIZE,
+ gdm_mux_rcv_complete,
+ r);
+
+ spin_lock_irqsave(&rx->submit_list_lock, flags);
+ list_add_tail(&r->rx_submit_list, &rx->rx_submit_list);
+ spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+
+ ret = usb_submit_urb(r->urb, GFP_KERNEL);
+
+ if (ret) {
+ spin_lock_irqsave(&rx->submit_list_lock, flags);
+ list_del(&r->rx_submit_list);
+ spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+
+ put_rx_struct(rx, r);
+
+ pr_err("usb_submit_urb ret=%d\n", ret);
+ }
+
+ usb_mark_last_busy(usbdev);
+
+ return ret;
+}
+
+static void gdm_mux_send_complete(struct urb *urb)
+{
+ struct mux_tx *t = urb->context;
+
+ if (urb->status == -ECONNRESET) {
+ pr_info("CONNRESET\n");
+ free_mux_tx(t);
+ return;
+ }
+
+ if (t->callback)
+ t->callback(t->cb_data);
+
+ free_mux_tx(t);
+}
+
+static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index,
+ void (*cb)(void *data), void *cb_data)
+{
+ struct mux_dev *mux_dev = priv_dev;
+ struct usb_device *usbdev = mux_dev->usbdev;
+ struct mux_pkt_header *mux_header;
+ struct mux_tx *t = NULL;
+ static u32 seq_num = 1;
+ int remain;
+ int dummy_cnt;
+ int total_len;
+ int ret;
+ unsigned long flags;
+
+ if (mux_dev->usb_state == PM_SUSPEND) {
+ ret = usb_autopm_get_interface(mux_dev->intf);
+ if (!ret)
+ usb_autopm_put_interface(mux_dev->intf);
+ }
+
+ spin_lock_irqsave(&mux_dev->write_lock, flags);
+
+ remain = (MUX_HEADER_SIZE + len) % 4;
+ dummy_cnt = remain ? (4 - remain) : 0;
+
+ total_len = len + MUX_HEADER_SIZE + dummy_cnt;
+
+ t = alloc_mux_tx(total_len);
+ if (!t) {
+ pr_err("alloc_mux_tx fail\n");
+ spin_unlock_irqrestore(&mux_dev->write_lock, flags);
+ return -ENOMEM;
+ }
+
+ mux_header = (struct mux_pkt_header *)t->buf;
+ mux_header->start_flag = __cpu_to_le32(START_FLAG);
+ mux_header->seq_num = __cpu_to_le32(seq_num++);
+ mux_header->payload_size = __cpu_to_le32((u32)len);
+ mux_header->packet_type = __cpu_to_le16(packet_type[tty_index]);
+
+ memcpy(t->buf+MUX_HEADER_SIZE, data, len);
+ memset(t->buf+MUX_HEADER_SIZE+len, 0, dummy_cnt);
+
+ t->len = total_len;
+ t->callback = cb;
+ t->cb_data = cb_data;
+
+ usb_fill_bulk_urb(t->urb,
+ usbdev,
+ usb_sndbulkpipe(usbdev, 5),
+ t->buf,
+ total_len,
+ gdm_mux_send_complete,
+ t);
+
+ ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+
+ spin_unlock_irqrestore(&mux_dev->write_lock, flags);
+
+ if (ret)
+ pr_err("usb_submit_urb Error: %d\n", ret);
+
+ usb_mark_last_busy(usbdev);
+
+ return ret;
+}
+
+static int gdm_mux_send_control(void *priv_dev, int request, int value, void *buf, int len)
+{
+ struct mux_dev *mux_dev = priv_dev;
+ struct usb_device *usbdev = mux_dev->usbdev;
+ int ret;
+
+ ret = usb_control_msg(usbdev,
+ usb_sndctrlpipe(usbdev, 0),
+ request,
+ USB_RT_ACM,
+ value,
+ 2,
+ buf,
+ len,
+ 5000
+ );
+
+ if (ret < 0)
+ pr_err("usb_control_msg error: %d\n", ret);
+
+ return ret < 0 ? ret : 0;
+}
+
+static void release_usb(struct mux_dev *mux_dev)
+{
+ struct rx_cxt *rx = &mux_dev->rx;
+ struct mux_rx *r, *r_next;
+ unsigned long flags;
+
+ cancel_delayed_work(&mux_dev->work_rx);
+
+ spin_lock_irqsave(&rx->submit_list_lock, flags);
+ list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list) {
+ spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+ usb_kill_urb(r->urb);
+ spin_lock_irqsave(&rx->submit_list_lock, flags);
+ }
+ spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+
+ spin_lock_irqsave(&rx->free_list_lock, flags);
+ list_for_each_entry_safe(r, r_next, &rx->rx_free_list, free_list) {
+ list_del(&r->free_list);
+ free_mux_rx(r);
+ }
+ spin_unlock_irqrestore(&rx->free_list_lock, flags);
+
+ spin_lock_irqsave(&rx->to_host_lock, flags);
+ list_for_each_entry_safe(r, r_next, &rx->to_host_list, to_host_list) {
+ if (r->mux_dev == (void *)mux_dev) {
+ list_del(&r->to_host_list);
+ free_mux_rx(r);
+ }
+ }
+ spin_unlock_irqrestore(&rx->to_host_lock, flags);
+}
+
+
+static int init_usb(struct mux_dev *mux_dev)
+{
+ struct mux_rx *r;
+ struct rx_cxt *rx = &mux_dev->rx;
+ int ret = 0;
+ int i;
+
+ spin_lock_init(&mux_dev->write_lock);
+ INIT_LIST_HEAD(&rx->to_host_list);
+ INIT_LIST_HEAD(&rx->rx_submit_list);
+ INIT_LIST_HEAD(&rx->rx_free_list);
+ spin_lock_init(&rx->to_host_lock);
+ spin_lock_init(&rx->submit_list_lock);
+ spin_lock_init(&rx->free_list_lock);
+
+ for (i = 0; i < MAX_ISSUE_NUM * 2; i++) {
+ r = alloc_mux_rx();
+ if (r == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ list_add(&r->free_list, &rx->rx_free_list);
+ }
+
+ INIT_DELAYED_WORK(&mux_dev->work_rx, do_rx);
+
+ return ret;
+}
+
+static int gdm_mux_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct mux_dev *mux_dev;
+ struct tty_dev *tty_dev;
+ u16 idVendor, idProduct;
+ int bInterfaceNumber;
+ int ret;
+ int i;
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+ bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
+
+ idVendor = __le16_to_cpu(usbdev->descriptor.idVendor);
+ idProduct = __le16_to_cpu(usbdev->descriptor.idProduct);
+
+ pr_info("mux vid = 0x%04x pid = 0x%04x\n", idVendor, idProduct);
+
+ if (bInterfaceNumber != 2)
+ return -ENODEV;
+
+ mux_dev = kzalloc(sizeof(struct mux_dev), GFP_KERNEL);
+ if (!mux_dev)
+ return -ENOMEM;
+
+ tty_dev = kzalloc(sizeof(struct tty_dev), GFP_KERNEL);
+ if (!tty_dev) {
+ ret = -ENOMEM;
+ goto err_free_mux;
+ }
+
+ mux_dev->usbdev = usbdev;
+ mux_dev->control_intf = intf;
+
+ ret = init_usb(mux_dev);
+ if (ret)
+ goto err_free_tty;
+
+ tty_dev->priv_dev = (void *)mux_dev;
+ tty_dev->send_func = gdm_mux_send;
+ tty_dev->recv_func = gdm_mux_recv;
+ tty_dev->send_control = gdm_mux_send_control;
+
+ ret = register_lte_tty_device(tty_dev, &intf->dev);
+ if (ret)
+ goto err_unregister_tty;
+
+ for (i = 0; i < TTY_MAX_COUNT; i++)
+ mux_dev->tty_dev = tty_dev;
+
+ mux_dev->intf = intf;
+ mux_dev->usb_state = PM_NORMAL;
+
+ usb_get_dev(usbdev);
+ usb_set_intfdata(intf, tty_dev);
+
+ return 0;
+
+err_unregister_tty:
+ unregister_lte_tty_device(tty_dev);
+ release_usb(mux_dev);
+err_free_tty:
+ kfree(tty_dev);
+err_free_mux:
+ kfree(mux_dev);
+
+ return ret;
+}
+
+static void gdm_mux_disconnect(struct usb_interface *intf)
+{
+ struct tty_dev *tty_dev;
+ struct mux_dev *mux_dev;
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+
+ tty_dev = usb_get_intfdata(intf);
+
+ mux_dev = tty_dev->priv_dev;
+
+ release_usb(mux_dev);
+ unregister_lte_tty_device(tty_dev);
+
+ kfree(mux_dev);
+ kfree(tty_dev);
+
+ usb_put_dev(usbdev);
+}
+
+static int gdm_mux_suspend(struct usb_interface *intf, pm_message_t pm_msg)
+{
+ struct tty_dev *tty_dev;
+ struct mux_dev *mux_dev;
+ struct rx_cxt *rx;
+ struct mux_rx *r, *r_next;
+ unsigned long flags;
+
+ tty_dev = usb_get_intfdata(intf);
+ mux_dev = tty_dev->priv_dev;
+ rx = &mux_dev->rx;
+
+ if (mux_dev->usb_state != PM_NORMAL) {
+ pr_err("usb suspend - invalid state\n");
+ return -1;
+ }
+
+ mux_dev->usb_state = PM_SUSPEND;
+
+
+ spin_lock_irqsave(&rx->submit_list_lock, flags);
+ list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list) {
+ spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+ usb_kill_urb(r->urb);
+ spin_lock_irqsave(&rx->submit_list_lock, flags);
+ }
+ spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+
+ return 0;
+}
+
+static int gdm_mux_resume(struct usb_interface *intf)
+{
+ struct tty_dev *tty_dev;
+ struct mux_dev *mux_dev;
+ u8 i;
+
+ tty_dev = usb_get_intfdata(intf);
+ mux_dev = tty_dev->priv_dev;
+
+ if (mux_dev->usb_state != PM_SUSPEND) {
+ pr_err("usb resume - invalid state\n");
+ return -1;
+ }
+
+ mux_dev->usb_state = PM_NORMAL;
+
+ for (i = 0; i < MAX_ISSUE_NUM; i++)
+ gdm_mux_recv(mux_dev, mux_dev->rx_cb);
+
+ return 0;
+}
+
+static struct usb_driver gdm_mux_driver = {
+ .name = "gdm_mux",
+ .probe = gdm_mux_probe,
+ .disconnect = gdm_mux_disconnect,
+ .id_table = id_table,
+ .supports_autosuspend = 1,
+ .suspend = gdm_mux_suspend,
+ .resume = gdm_mux_resume,
+ .reset_resume = gdm_mux_resume,
+};
+
+static int __init gdm_usb_mux_init(void)
+{
+
+ mux_rx_wq = create_workqueue("mux_rx_wq");
+ if (mux_rx_wq == NULL) {
+ pr_err("work queue create fail\n");
+ return -1;
+ }
+
+ register_lte_tty_driver();
+
+ return usb_register(&gdm_mux_driver);
+}
+
+static void __exit gdm_usb_mux_exit(void)
+{
+ unregister_lte_tty_driver();
+
+ if (mux_rx_wq) {
+ flush_workqueue(mux_rx_wq);
+ destroy_workqueue(mux_rx_wq);
+ }
+
+ usb_deregister(&gdm_mux_driver);
+}
+
+module_init(gdm_usb_mux_init);
+module_exit(gdm_usb_mux_exit);
+
+MODULE_DESCRIPTION("GCT LTE TTY Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gdm724x/gdm_mux.h b/drivers/staging/gdm724x/gdm_mux.h
new file mode 100644
index 00000000000..0163b243d3e
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_mux.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _GDM_MUX_H_
+#define _GDM_MUX_H_
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+
+#include "gdm_tty.h"
+
+#define PM_NORMAL 0
+#define PM_SUSPEND 1
+
+#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+
+#define START_FLAG 0xA512485A
+#define MUX_HEADER_SIZE 14
+#define MUX_TX_MAX_SIZE (1024*10)
+#define MUX_RX_MAX_SIZE (1024*30)
+#define AT_PKT_TYPE 0xF011
+#define DM_PKT_TYPE 0xF010
+
+#define RETRY_TIMER 30 /* msec */
+
+struct mux_pkt_header {
+ unsigned int start_flag;
+ unsigned int seq_num;
+ unsigned int payload_size;
+ unsigned short packet_type;
+ unsigned char data[0];
+};
+
+struct mux_tx {
+ struct urb *urb;
+ u8 *buf;
+ int len;
+ void (*callback)(void *cb_data);
+ void *cb_data;
+};
+
+struct mux_rx {
+ struct list_head free_list;
+ struct list_head rx_submit_list;
+ struct list_head to_host_list;
+ struct urb *urb;
+ u8 *buf;
+ void *mux_dev;
+ u32 offset;
+ u32 len;
+ int (*callback)(void *data,
+ int len,
+ int tty_index,
+ struct tty_dev *tty_dev,
+ int complete);
+};
+
+struct rx_cxt {
+ struct list_head to_host_list;
+ struct list_head rx_submit_list;
+ struct list_head rx_free_list;
+ spinlock_t to_host_lock;
+ spinlock_t submit_list_lock;
+ spinlock_t free_list_lock;
+};
+
+struct mux_dev {
+ struct usb_device *usbdev;
+ struct usb_interface *control_intf;
+ struct usb_interface *data_intf;
+ struct rx_cxt rx;
+ struct delayed_work work_rx;
+ struct usb_interface *intf;
+ int usb_state;
+ int (*rx_cb)(void *data,
+ int len,
+ int tty_index,
+ struct tty_dev *tty_dev,
+ int complete);
+ spinlock_t write_lock;
+ struct tty_dev *tty_dev;
+};
+
+#endif /* _GDM_MUX_H_ */
diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c
new file mode 100644
index 00000000000..0247a2055e8
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_tty.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb/cdc.h>
+#include <linux/serial.h>
+#include "gdm_tty.h"
+
+#define GDM_TTY_MAJOR 0
+#define GDM_TTY_MINOR 32
+
+#define ACM_CTRL_DTR 0x01
+#define ACM_CTRL_RTS 0x02
+#define ACM_CTRL_DSR 0x02
+#define ACM_CTRL_RI 0x08
+#define ACM_CTRL_DCD 0x01
+
+#define WRITE_SIZE 2048
+
+#define MUX_TX_MAX_SIZE 2048
+
+#define gdm_tty_send(n, d, l, i, c, b) (\
+ n->tty_dev->send_func(n->tty_dev->priv_dev, d, l, i, c, b))
+#define gdm_tty_recv(n, c) (\
+ n->tty_dev->recv_func(n->tty_dev->priv_dev, c))
+#define gdm_tty_send_control(n, r, v, d, l) (\
+ n->tty_dev->send_control(n->tty_dev->priv_dev, r, v, d, l))
+
+#define GDM_TTY_READY(gdm) (gdm && gdm->tty_dev && gdm->port.count)
+
+static struct tty_driver *gdm_driver[TTY_MAX_COUNT];
+static struct gdm *gdm_table[TTY_MAX_COUNT][GDM_TTY_MINOR];
+static DEFINE_MUTEX(gdm_table_lock);
+
+static char *DRIVER_STRING[TTY_MAX_COUNT] = {"GCTATC", "GCTDM"};
+static char *DEVICE_STRING[TTY_MAX_COUNT] = {"GCT-ATC", "GCT-DM"};
+
+static void gdm_port_destruct(struct tty_port *port)
+{
+ struct gdm *gdm = container_of(port, struct gdm, port);
+
+ mutex_lock(&gdm_table_lock);
+ gdm_table[gdm->index][gdm->minor] = NULL;
+ mutex_unlock(&gdm_table_lock);
+
+ kfree(gdm);
+}
+
+static struct tty_port_operations gdm_port_ops = {
+ .destruct = gdm_port_destruct,
+};
+
+static int gdm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct gdm *gdm = NULL;
+ int ret;
+ int i;
+ int j;
+
+ j = GDM_TTY_MINOR;
+ for (i = 0; i < TTY_MAX_COUNT; i++) {
+ if (!strcmp(tty->driver->driver_name, DRIVER_STRING[i])) {
+ j = tty->index;
+ break;
+ }
+ }
+
+ if (j == GDM_TTY_MINOR)
+ return -ENODEV;
+
+ mutex_lock(&gdm_table_lock);
+ gdm = gdm_table[i][j];
+ if (gdm == NULL) {
+ mutex_unlock(&gdm_table_lock);
+ return -ENODEV;
+ }
+
+ tty_port_get(&gdm->port);
+
+ ret = tty_standard_install(driver, tty);
+ if (ret) {
+ tty_port_put(&gdm->port);
+ mutex_unlock(&gdm_table_lock);
+ return ret;
+ }
+
+ tty->driver_data = gdm;
+ mutex_unlock(&gdm_table_lock);
+
+ return 0;
+}
+
+static int gdm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+ struct gdm *gdm = tty->driver_data;
+ return tty_port_open(&gdm->port, tty, filp);
+}
+
+static void gdm_tty_cleanup(struct tty_struct *tty)
+{
+ struct gdm *gdm = tty->driver_data;
+ tty_port_put(&gdm->port);
+}
+
+static void gdm_tty_hangup(struct tty_struct *tty)
+{
+ struct gdm *gdm = tty->driver_data;
+ tty_port_hangup(&gdm->port);
+}
+
+static void gdm_tty_close(struct tty_struct *tty, struct file *filp)
+{
+ struct gdm *gdm = tty->driver_data;
+ tty_port_close(&gdm->port, tty, filp);
+}
+
+static int gdm_tty_recv_complete(void *data,
+ int len,
+ int index,
+ struct tty_dev *tty_dev,
+ int complete)
+{
+ struct gdm *gdm = tty_dev->gdm[index];
+ if (!GDM_TTY_READY(gdm)) {
+ if (complete == RECV_PACKET_PROCESS_COMPLETE)
+ gdm_tty_recv(gdm, gdm_tty_recv_complete);
+ return TO_HOST_PORT_CLOSE;
+ }
+
+ if (data && len) {
+ if (tty_buffer_request_room(&gdm->port, len) == len) {
+ tty_insert_flip_string(&gdm->port, data, len);
+ tty_flip_buffer_push(&gdm->port);
+ } else {
+ return TO_HOST_BUFFER_REQUEST_FAIL;
+ }
+ }
+
+ if (complete == RECV_PACKET_PROCESS_COMPLETE)
+ gdm_tty_recv(gdm, gdm_tty_recv_complete);
+
+ return 0;
+}
+
+static void gdm_tty_send_complete(void *arg)
+{
+ struct gdm *gdm = (struct gdm *)arg;
+
+ if (!GDM_TTY_READY(gdm))
+ return;
+
+ tty_port_tty_wakeup(&gdm->port);
+}
+
+static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf, int len)
+{
+ struct gdm *gdm = tty->driver_data;
+ int remain = len;
+ int sent_len = 0;
+ int sending_len = 0;
+
+ if (!GDM_TTY_READY(gdm))
+ return -ENODEV;
+
+ if (!len)
+ return 0;
+
+ while (1) {
+ sending_len = remain > MUX_TX_MAX_SIZE ? MUX_TX_MAX_SIZE : remain;
+ gdm_tty_send(gdm,
+ (void *)(buf+sent_len),
+ sending_len,
+ gdm->index,
+ gdm_tty_send_complete,
+ gdm
+ );
+ sent_len += sending_len;
+ remain -= sending_len;
+ if (remain <= 0)
+ break;
+ }
+
+ return len;
+}
+
+static int gdm_tty_write_room(struct tty_struct *tty)
+{
+ struct gdm *gdm = tty->driver_data;
+
+ if (!GDM_TTY_READY(gdm))
+ return -ENODEV;
+
+ return WRITE_SIZE;
+}
+
+int register_lte_tty_device(struct tty_dev *tty_dev, struct device *device)
+{
+ struct gdm *gdm;
+ int i;
+ int j;
+
+ for (i = 0; i < TTY_MAX_COUNT; i++) {
+
+ gdm = kmalloc(sizeof(struct gdm), GFP_KERNEL);
+ if (!gdm)
+ return -ENOMEM;
+
+ mutex_lock(&gdm_table_lock);
+ for (j = 0; j < GDM_TTY_MINOR; j++) {
+ if (!gdm_table[i][j])
+ break;
+ }
+
+ if (j == GDM_TTY_MINOR) {
+ kfree(gdm);
+ mutex_unlock(&gdm_table_lock);
+ return -EINVAL;
+ }
+
+ gdm_table[i][j] = gdm;
+ mutex_unlock(&gdm_table_lock);
+
+ tty_dev->gdm[i] = gdm;
+ tty_port_init(&gdm->port);
+
+ gdm->port.ops = &gdm_port_ops;
+ gdm->index = i;
+ gdm->minor = j;
+ gdm->tty_dev = tty_dev;
+
+ tty_port_register_device(&gdm->port, gdm_driver[i], gdm->minor, device);
+ }
+
+ for (i = 0; i < MAX_ISSUE_NUM; i++)
+ gdm_tty_recv(gdm, gdm_tty_recv_complete);
+
+ return 0;
+}
+
+void unregister_lte_tty_device(struct tty_dev *tty_dev)
+{
+ struct gdm *gdm;
+ struct tty_struct *tty;
+ int i;
+
+ for (i = 0; i < TTY_MAX_COUNT; i++) {
+ gdm = tty_dev->gdm[i];
+ if (!gdm)
+ continue;
+
+ mutex_lock(&gdm_table_lock);
+ gdm_table[gdm->index][gdm->minor] = NULL;
+ mutex_unlock(&gdm_table_lock);
+
+ tty = tty_port_tty_get(&gdm->port);
+ if (tty) {
+ tty_vhangup(tty);
+ tty_kref_put(tty);
+ }
+
+ tty_unregister_device(gdm_driver[i], gdm->minor);
+ tty_port_put(&gdm->port);
+ }
+}
+
+static const struct tty_operations gdm_tty_ops = {
+ .install = gdm_tty_install,
+ .open = gdm_tty_open,
+ .close = gdm_tty_close,
+ .cleanup = gdm_tty_cleanup,
+ .hangup = gdm_tty_hangup,
+ .write = gdm_tty_write,
+ .write_room = gdm_tty_write_room,
+};
+
+int register_lte_tty_driver(void)
+{
+ struct tty_driver *tty_driver;
+ int i;
+ int ret;
+
+ for (i = 0; i < TTY_MAX_COUNT; i++) {
+ tty_driver = alloc_tty_driver(GDM_TTY_MINOR);
+ if (!tty_driver)
+ return -ENOMEM;
+
+ tty_driver->owner = THIS_MODULE;
+ tty_driver->driver_name = DRIVER_STRING[i];
+ tty_driver->name = DEVICE_STRING[i];
+ tty_driver->major = GDM_TTY_MAJOR;
+ tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ tty_driver->subtype = SERIAL_TYPE_NORMAL;
+ tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_driver->init_termios = tty_std_termios;
+ tty_driver->init_termios.c_cflag = B9600 | CS8 | HUPCL | CLOCAL;
+ tty_driver->init_termios.c_lflag = ISIG | ICANON | IEXTEN;
+ tty_set_operations(tty_driver, &gdm_tty_ops);
+
+ ret = tty_register_driver(tty_driver);
+ if (ret) {
+ put_tty_driver(tty_driver);
+ return ret;
+ }
+
+ gdm_driver[i] = tty_driver;
+ }
+
+ return ret;
+}
+
+void unregister_lte_tty_driver(void)
+{
+ struct tty_driver *tty_driver;
+ int i;
+
+ for (i = 0; i < TTY_MAX_COUNT; i++) {
+ tty_driver = gdm_driver[i];
+ if (tty_driver) {
+ tty_unregister_driver(tty_driver);
+ put_tty_driver(tty_driver);
+ }
+ }
+}
+
diff --git a/drivers/staging/gdm724x/gdm_tty.h b/drivers/staging/gdm724x/gdm_tty.h
new file mode 100644
index 00000000000..297438b4ddc
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_tty.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _GDM_TTY_H_
+#define _GDM_TTY_H_
+
+#include <linux/types.h>
+#include <linux/tty.h>
+
+
+#define TTY_MAX_COUNT 2
+
+#define MAX_ISSUE_NUM 3
+
+enum TO_HOST_RESULT {
+ TO_HOST_BUFFER_REQUEST_FAIL = 1,
+ TO_HOST_PORT_CLOSE = 2,
+ TO_HOST_INVALID_PACKET = 3,
+};
+
+enum RECV_PACKET_PROCESS {
+ RECV_PACKET_PROCESS_COMPLETE = 0,
+ RECV_PACKET_PROCESS_CONTINUE = 1,
+};
+
+struct gdm {
+ struct tty_dev *tty_dev;
+ struct tty_port port;
+ unsigned int index;
+ unsigned int minor;
+};
+
+struct tty_dev {
+ void *priv_dev;
+ int (*send_func)(void *priv_dev,
+ void *data,
+ int len,
+ int tty_index,
+ void (*cb)(void *cb_data),
+ void *cb_data);
+ int (*recv_func)(void *priv_dev,
+ int (*cb)(void *data,
+ int len,
+ int tty_index,
+ struct tty_dev *tty_dev,
+ int complete));
+ int (*send_control)(void *priv_dev,
+ int request,
+ int value,
+ void *data,
+ int len);
+ struct gdm *gdm[2];
+};
+
+int register_lte_tty_driver(void);
+void unregister_lte_tty_driver(void);
+int register_lte_tty_device(struct tty_dev *tty_dev, struct device *dev);
+void unregister_lte_tty_device(struct tty_dev *tty_dev);
+
+#endif /* _GDM_USB_H_ */
+
diff --git a/drivers/staging/gdm724x/gdm_usb.c b/drivers/staging/gdm724x/gdm_usb.c
new file mode 100644
index 00000000000..bdc96370e43
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_usb.c
@@ -0,0 +1,1049 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/usb/cdc.h>
+#include <linux/wait.h>
+#include <linux/if_ether.h>
+#include <linux/pm_runtime.h>
+
+#include "gdm_usb.h"
+#include "gdm_lte.h"
+#include "hci.h"
+#include "hci_packet.h"
+#include "gdm_endian.h"
+
+#define USB_DEVICE_CDC_DATA(vid, pid) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS,\
+ .idVendor = vid,\
+ .idProduct = pid,\
+ .bInterfaceClass = USB_CLASS_COMM,\
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET
+
+#define USB_DEVICE_MASS_DATA(vid, pid) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,\
+ .idVendor = vid,\
+ .idProduct = pid,\
+ .bInterfaceSubClass = USB_SC_SCSI, \
+ .bInterfaceClass = USB_CLASS_MASS_STORAGE,\
+ .bInterfaceProtocol = USB_PR_BULK
+
+static const struct usb_device_id id_table[] = {
+ { USB_DEVICE_CDC_DATA(VID_GCT, PID_GDM7240) }, /* GCT GDM7240 */
+ { USB_DEVICE_CDC_DATA(VID_GCT, PID_GDM7243) }, /* GCT GDM7243 */
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct workqueue_struct *usb_tx_wq;
+static struct workqueue_struct *usb_rx_wq;
+
+static void do_tx(struct work_struct *work);
+static void do_rx(struct work_struct *work);
+
+static int gdm_usb_recv(void *priv_dev,
+ int (*cb)(void *cb_data, void *data, int len, int context),
+ void *cb_data,
+ int context);
+
+static int request_mac_address(struct lte_udev *udev)
+{
+ u8 buf[16] = {0,};
+ struct hci_packet *hci = (struct hci_packet *)buf;
+ struct usb_device *usbdev = udev->usbdev;
+ int actual;
+ int ret = -1;
+
+ hci->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_GET_INFORMATION);
+ hci->len = gdm_cpu_to_dev16(&udev->gdm_ed, 1);
+ hci->data[0] = MAC_ADDRESS;
+
+ ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 2), buf, 5,
+ &actual, 1000);
+
+ udev->request_mac_addr = 1;
+
+ return ret;
+}
+
+static struct usb_tx *alloc_tx_struct(int len)
+{
+ struct usb_tx *t = NULL;
+ int ret = 0;
+
+ t = kmalloc(sizeof(struct usb_tx), GFP_ATOMIC);
+ if (!t) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ memset(t, 0, sizeof(struct usb_tx));
+
+ t->urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!(len % 512))
+ len++;
+
+ t->buf = kmalloc(len, GFP_ATOMIC);
+ if (!t->urb || !t->buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+out:
+ if (ret < 0) {
+ if (t) {
+ usb_free_urb(t->urb);
+ kfree(t->buf);
+ kfree(t);
+ }
+ return NULL;
+ }
+
+ return t;
+}
+
+static struct usb_tx_sdu *alloc_tx_sdu_struct(void)
+{
+ struct usb_tx_sdu *t_sdu = NULL;
+ int ret = 0;
+
+
+ t_sdu = kmalloc(sizeof(struct usb_tx_sdu), GFP_ATOMIC);
+ if (!t_sdu) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ memset(t_sdu, 0, sizeof(struct usb_tx_sdu));
+
+ t_sdu->buf = kmalloc(SDU_BUF_SIZE, GFP_ATOMIC);
+ if (!t_sdu->buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+out:
+
+ if (ret < 0) {
+ if (t_sdu) {
+ kfree(t_sdu->buf);
+ kfree(t_sdu);
+ }
+ return NULL;
+ }
+
+ return t_sdu;
+}
+
+static void free_tx_struct(struct usb_tx *t)
+{
+ if (t) {
+ usb_free_urb(t->urb);
+ kfree(t->buf);
+ kfree(t);
+ }
+}
+
+static void free_tx_sdu_struct(struct usb_tx_sdu *t_sdu)
+{
+ if (t_sdu) {
+ kfree(t_sdu->buf);
+ kfree(t_sdu);
+ }
+}
+
+static struct usb_tx_sdu *get_tx_sdu_struct(struct tx_cxt *tx, int *no_spc)
+{
+ struct usb_tx_sdu *t_sdu;
+
+ if (list_empty(&tx->free_list))
+ return NULL;
+
+ t_sdu = list_entry(tx->free_list.next, struct usb_tx_sdu, list);
+ list_del(&t_sdu->list);
+
+ tx->avail_count--;
+
+ *no_spc = list_empty(&tx->free_list) ? 1 : 0;
+
+ return t_sdu;
+}
+
+static void put_tx_struct(struct tx_cxt *tx, struct usb_tx_sdu *t_sdu)
+{
+ list_add_tail(&t_sdu->list, &tx->free_list);
+ tx->avail_count++;
+}
+
+static struct usb_rx *alloc_rx_struct(void)
+{
+ struct usb_rx *r = NULL;
+ int ret = 0;
+
+ r = kmalloc(sizeof(struct usb_rx), GFP_ATOMIC);
+ if (!r) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ r->urb = usb_alloc_urb(0, GFP_ATOMIC);
+ r->buf = kmalloc(RX_BUF_SIZE, GFP_ATOMIC);
+ if (!r->urb || !r->buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+out:
+
+ if (ret < 0) {
+ if (r) {
+ usb_free_urb(r->urb);
+ kfree(r->buf);
+ kfree(r);
+ }
+ return NULL;
+ }
+
+ return r;
+}
+
+static void free_rx_struct(struct usb_rx *r)
+{
+ if (r) {
+ usb_free_urb(r->urb);
+ kfree(r->buf);
+ kfree(r);
+ }
+}
+
+static struct usb_rx *get_rx_struct(struct rx_cxt *rx, int *no_spc)
+{
+ struct usb_rx *r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rx->rx_lock, flags);
+
+ if (list_empty(&rx->free_list)) {
+ spin_unlock_irqrestore(&rx->rx_lock, flags);
+ return NULL;
+ }
+
+ r = list_entry(rx->free_list.next, struct usb_rx, free_list);
+ list_del(&r->free_list);
+
+ rx->avail_count--;
+
+ *no_spc = list_empty(&rx->free_list) ? 1 : 0;
+
+ spin_unlock_irqrestore(&rx->rx_lock, flags);
+
+ return r;
+}
+
+static void put_rx_struct(struct rx_cxt *rx, struct usb_rx *r)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rx->rx_lock, flags);
+
+ list_add_tail(&r->free_list, &rx->free_list);
+ rx->avail_count++;
+
+ spin_unlock_irqrestore(&rx->rx_lock, flags);
+}
+
+static void release_usb(struct lte_udev *udev)
+{
+ struct rx_cxt *rx = &udev->rx;
+ struct tx_cxt *tx = &udev->tx;
+ struct usb_tx *t, *t_next;
+ struct usb_rx *r, *r_next;
+ struct usb_tx_sdu *t_sdu, *t_sdu_next;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tx->lock, flags);
+ list_for_each_entry_safe(t_sdu, t_sdu_next, &tx->sdu_list, list)
+ {
+ list_del(&t_sdu->list);
+ free_tx_sdu_struct(t_sdu);
+ }
+
+ list_for_each_entry_safe(t, t_next, &tx->hci_list, list)
+ {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(t_sdu, t_sdu_next, &tx->free_list, list)
+ {
+ list_del(&t_sdu->list);
+ free_tx_sdu_struct(t_sdu);
+ }
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ spin_lock_irqsave(&rx->submit_lock, flags);
+ list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list)
+ {
+ spin_unlock_irqrestore(&rx->submit_lock, flags);
+ usb_kill_urb(r->urb);
+ spin_lock_irqsave(&rx->submit_lock, flags);
+ }
+ spin_unlock_irqrestore(&rx->submit_lock, flags);
+
+ spin_lock_irqsave(&rx->rx_lock, flags);
+ list_for_each_entry_safe(r, r_next, &rx->free_list, free_list)
+ {
+ list_del(&r->free_list);
+ free_rx_struct(r);
+ }
+ spin_unlock_irqrestore(&rx->rx_lock, flags);
+
+ spin_lock_irqsave(&rx->to_host_lock, flags);
+ list_for_each_entry_safe(r, r_next, &rx->to_host_list, to_host_list)
+ {
+ if (r->index == (void *)udev) {
+ list_del(&r->to_host_list);
+ free_rx_struct(r);
+ }
+ }
+ spin_unlock_irqrestore(&rx->to_host_lock, flags);
+}
+
+static int init_usb(struct lte_udev *udev)
+{
+ int ret = 0;
+ int i;
+ struct tx_cxt *tx = &udev->tx;
+ struct rx_cxt *rx = &udev->rx;
+ struct usb_tx_sdu *t_sdu = NULL;
+ struct usb_rx *r = NULL;
+
+ udev->send_complete = 1;
+ udev->tx_stop = 0;
+ udev->request_mac_addr = 0;
+ udev->usb_state = PM_NORMAL;
+
+ INIT_LIST_HEAD(&tx->sdu_list);
+ INIT_LIST_HEAD(&tx->hci_list);
+ INIT_LIST_HEAD(&tx->free_list);
+ INIT_LIST_HEAD(&rx->rx_submit_list);
+ INIT_LIST_HEAD(&rx->free_list);
+ INIT_LIST_HEAD(&rx->to_host_list);
+ spin_lock_init(&tx->lock);
+ spin_lock_init(&rx->rx_lock);
+ spin_lock_init(&rx->submit_lock);
+ spin_lock_init(&rx->to_host_lock);
+
+ tx->avail_count = 0;
+ rx->avail_count = 0;
+
+ udev->rx_cb = NULL;
+
+ for (i = 0; i < MAX_NUM_SDU_BUF; i++) {
+ t_sdu = alloc_tx_sdu_struct();
+ if (t_sdu == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ list_add(&t_sdu->list, &tx->free_list);
+ tx->avail_count++;
+ }
+
+ for (i = 0; i < MAX_RX_SUBMIT_COUNT*2; i++) {
+ r = alloc_rx_struct();
+ if (r == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ list_add(&r->free_list, &rx->free_list);
+ rx->avail_count++;
+ }
+ INIT_DELAYED_WORK(&udev->work_tx, do_tx);
+ INIT_DELAYED_WORK(&udev->work_rx, do_rx);
+ return 0;
+fail:
+ return ret;
+}
+
+static int set_mac_address(u8 *data, void *arg)
+{
+ struct phy_dev *phy_dev = (struct phy_dev *)arg;
+ struct lte_udev *udev = phy_dev->priv_dev;
+ struct tlv *tlv = (struct tlv *)data;
+ u8 mac_address[ETH_ALEN] = {0, };
+
+ if (tlv->type == MAC_ADDRESS && udev->request_mac_addr) {
+ memcpy(mac_address, tlv->data, tlv->len);
+
+ if (register_lte_device(phy_dev, &udev->intf->dev, mac_address) < 0)
+ pr_err("register lte device failed\n");
+
+ udev->request_mac_addr = 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static void do_rx(struct work_struct *work)
+{
+ struct lte_udev *udev = container_of(work, struct lte_udev, work_rx.work);
+ struct rx_cxt *rx = &udev->rx;
+ struct usb_rx *r;
+ struct hci_packet *hci;
+ struct phy_dev *phy_dev;
+ u16 cmd_evt;
+ int ret;
+ unsigned long flags;
+
+ while (1) {
+ spin_lock_irqsave(&rx->to_host_lock, flags);
+ if (list_empty(&rx->to_host_list)) {
+ spin_unlock_irqrestore(&rx->to_host_lock, flags);
+ break;
+ }
+ r = list_entry(rx->to_host_list.next, struct usb_rx, to_host_list);
+ list_del(&r->to_host_list);
+ spin_unlock_irqrestore(&rx->to_host_lock, flags);
+
+ phy_dev = (struct phy_dev *)r->cb_data;
+ udev = (struct lte_udev *)phy_dev->priv_dev;
+ hci = (struct hci_packet *)r->buf;
+ cmd_evt = gdm_dev16_to_cpu(&udev->gdm_ed, hci->cmd_evt);
+
+ switch (cmd_evt) {
+ case LTE_GET_INFORMATION_RESULT:
+ if (set_mac_address(hci->data, r->cb_data) == 0) {
+ ret = r->callback(r->cb_data,
+ r->buf,
+ r->urb->actual_length,
+ KERNEL_THREAD);
+ }
+ break;
+
+ default:
+ if (r->callback) {
+ ret = r->callback(r->cb_data,
+ r->buf,
+ r->urb->actual_length,
+ KERNEL_THREAD);
+
+ if (ret == -EAGAIN)
+ pr_err("failed to send received data\n");
+ }
+ break;
+ }
+
+ put_rx_struct(rx, r);
+
+ gdm_usb_recv(udev,
+ r->callback,
+ r->cb_data,
+ USB_COMPLETE);
+ }
+}
+
+static void remove_rx_submit_list(struct usb_rx *r, struct rx_cxt *rx)
+{
+ unsigned long flags;
+ struct usb_rx *r_remove, *r_remove_next;
+
+ spin_lock_irqsave(&rx->submit_lock, flags);
+ list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, rx_submit_list)
+ {
+ if (r == r_remove) {
+ list_del(&r->rx_submit_list);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&rx->submit_lock, flags);
+}
+
+static void gdm_usb_rcv_complete(struct urb *urb)
+{
+ struct usb_rx *r = urb->context;
+ struct rx_cxt *rx = r->rx;
+ unsigned long flags;
+ struct lte_udev *udev = container_of(r->rx, struct lte_udev, rx);
+ struct usb_device *usbdev = udev->usbdev;
+
+ remove_rx_submit_list(r, rx);
+
+ if (!urb->status && r->callback) {
+ spin_lock_irqsave(&rx->to_host_lock, flags);
+ list_add_tail(&r->to_host_list, &rx->to_host_list);
+ queue_work(usb_rx_wq, &udev->work_rx.work);
+ spin_unlock_irqrestore(&rx->to_host_lock, flags);
+ } else {
+ if (urb->status && udev->usb_state == PM_NORMAL)
+ pr_err("%s: urb status error %d\n",
+ __func__, urb->status);
+
+ put_rx_struct(rx, r);
+ }
+
+ usb_mark_last_busy(usbdev);
+}
+
+static int gdm_usb_recv(void *priv_dev,
+ int (*cb)(void *cb_data, void *data, int len, int context),
+ void *cb_data,
+ int context)
+{
+ struct lte_udev *udev = priv_dev;
+ struct usb_device *usbdev = udev->usbdev;
+ struct rx_cxt *rx = &udev->rx;
+ struct usb_rx *r;
+ int no_spc;
+ int ret;
+ unsigned long flags;
+
+ if (!udev->usbdev) {
+ pr_err("invalid device\n");
+ return -ENODEV;
+ }
+
+ r = get_rx_struct(rx, &no_spc);
+ if (!r) {
+ pr_err("Out of Memory\n");
+ return -ENOMEM;
+ }
+
+ udev->rx_cb = cb;
+ r->callback = cb;
+ r->cb_data = cb_data;
+ r->index = (void *)udev;
+ r->rx = rx;
+
+ usb_fill_bulk_urb(r->urb,
+ usbdev,
+ usb_rcvbulkpipe(usbdev, 0x83),
+ r->buf,
+ RX_BUF_SIZE,
+ gdm_usb_rcv_complete,
+ r);
+
+ spin_lock_irqsave(&rx->submit_lock, flags);
+ list_add_tail(&r->rx_submit_list, &rx->rx_submit_list);
+ spin_unlock_irqrestore(&rx->submit_lock, flags);
+
+ if (context == KERNEL_THREAD)
+ ret = usb_submit_urb(r->urb, GFP_KERNEL);
+ else
+ ret = usb_submit_urb(r->urb, GFP_ATOMIC);
+
+ if (ret) {
+ spin_lock_irqsave(&rx->submit_lock, flags);
+ list_del(&r->rx_submit_list);
+ spin_unlock_irqrestore(&rx->submit_lock, flags);
+
+ pr_err("usb_submit_urb failed (%p)\n", r);
+ put_rx_struct(rx, r);
+ }
+
+ return ret;
+}
+
+static void gdm_usb_send_complete(struct urb *urb)
+{
+ struct usb_tx *t = urb->context;
+ struct tx_cxt *tx = t->tx;
+ struct lte_udev *udev = container_of(tx, struct lte_udev, tx);
+ unsigned long flags;
+
+ if (urb->status == -ECONNRESET) {
+ pr_info("CONNRESET\n");
+ return;
+ }
+
+ if (t->callback)
+ t->callback(t->cb_data);
+
+ free_tx_struct(t);
+
+ spin_lock_irqsave(&tx->lock, flags);
+ udev->send_complete = 1;
+ queue_work(usb_tx_wq, &udev->work_tx.work);
+ spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static int send_tx_packet(struct usb_device *usbdev, struct usb_tx *t, u32 len)
+{
+ int ret = 0;
+
+ if (!(len%512))
+ len++;
+
+ usb_fill_bulk_urb(t->urb,
+ usbdev,
+ usb_sndbulkpipe(usbdev, 2),
+ t->buf,
+ len,
+ gdm_usb_send_complete,
+ t);
+
+ ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+
+ if (ret)
+ pr_err("usb_submit_urb failed: %d\n", ret);
+
+ usb_mark_last_busy(usbdev);
+
+ return ret;
+}
+
+static u32 packet_aggregation(struct lte_udev *udev, u8 *send_buf)
+{
+ struct tx_cxt *tx = &udev->tx;
+ struct usb_tx_sdu *t_sdu = NULL;
+ struct multi_sdu *multi_sdu = (struct multi_sdu *)send_buf;
+ u16 send_len = 0;
+ u16 num_packet = 0;
+ unsigned long flags;
+
+ multi_sdu->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_TX_MULTI_SDU);
+
+ while (num_packet < MAX_PACKET_IN_MULTI_SDU) {
+ spin_lock_irqsave(&tx->lock, flags);
+ if (list_empty(&tx->sdu_list)) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ break;
+ }
+
+ t_sdu = list_entry(tx->sdu_list.next, struct usb_tx_sdu, list);
+ if (send_len + t_sdu->len > MAX_SDU_SIZE) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ break;
+ }
+
+ list_del(&t_sdu->list);
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ memcpy(multi_sdu->data + send_len, t_sdu->buf, t_sdu->len);
+
+ send_len += (t_sdu->len + 3) & 0xfffc;
+ num_packet++;
+
+ if (tx->avail_count > 10)
+ t_sdu->callback(t_sdu->cb_data);
+
+ spin_lock_irqsave(&tx->lock, flags);
+ put_tx_struct(tx, t_sdu);
+ spin_unlock_irqrestore(&tx->lock, flags);
+ }
+
+ multi_sdu->len = gdm_cpu_to_dev16(&udev->gdm_ed, send_len);
+ multi_sdu->num_packet = gdm_cpu_to_dev16(&udev->gdm_ed, num_packet);
+
+ return send_len + offsetof(struct multi_sdu, data);
+}
+
+static void do_tx(struct work_struct *work)
+{
+ struct lte_udev *udev = container_of(work, struct lte_udev, work_tx.work);
+ struct usb_device *usbdev = udev->usbdev;
+ struct tx_cxt *tx = &udev->tx;
+ struct usb_tx *t = NULL;
+ int is_send = 0;
+ u32 len = 0;
+ unsigned long flags;
+
+ if (!usb_autopm_get_interface(udev->intf))
+ usb_autopm_put_interface(udev->intf);
+
+ if (udev->usb_state == PM_SUSPEND)
+ return;
+
+ spin_lock_irqsave(&tx->lock, flags);
+ if (!udev->send_complete) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return;
+ } else {
+ udev->send_complete = 0;
+ }
+
+ if (!list_empty(&tx->hci_list)) {
+ t = list_entry(tx->hci_list.next, struct usb_tx, list);
+ list_del(&t->list);
+ len = t->len;
+ t->is_sdu = 0;
+ is_send = 1;
+ } else if (!list_empty(&tx->sdu_list)) {
+ if (udev->tx_stop) {
+ udev->send_complete = 1;
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return;
+ }
+
+ t = alloc_tx_struct(TX_BUF_SIZE);
+ t->callback = NULL;
+ t->tx = tx;
+ t->is_sdu = 1;
+ is_send = 1;
+ }
+
+ if (!is_send) {
+ udev->send_complete = 1;
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ if (t->is_sdu)
+ len = packet_aggregation(udev, t->buf);
+
+ if (send_tx_packet(usbdev, t, len)) {
+ pr_err("send_tx_packet failed\n");
+ t->callback = NULL;
+ gdm_usb_send_complete(t->urb);
+ }
+}
+
+#define SDU_PARAM_LEN 12
+static int gdm_usb_sdu_send(void *priv_dev, void *data, int len,
+ unsigned int dftEpsId, unsigned int epsId,
+ void (*cb)(void *data), void *cb_data,
+ int dev_idx, int nic_type)
+{
+ struct lte_udev *udev = priv_dev;
+ struct tx_cxt *tx = &udev->tx;
+ struct usb_tx_sdu *t_sdu;
+ struct sdu *sdu = NULL;
+ unsigned long flags;
+ int no_spc = 0;
+ u16 send_len;
+
+ if (!udev->usbdev) {
+ pr_err("sdu send - invalid device\n");
+ return TX_NO_DEV;
+ }
+
+ spin_lock_irqsave(&tx->lock, flags);
+ t_sdu = get_tx_sdu_struct(tx, &no_spc);
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ if (t_sdu == NULL) {
+ pr_err("sdu send - free list empty\n");
+ return TX_NO_SPC;
+ }
+
+ sdu = (struct sdu *)t_sdu->buf;
+ sdu->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_TX_SDU);
+ if (nic_type == NIC_TYPE_ARP) {
+ send_len = len + SDU_PARAM_LEN;
+ memcpy(sdu->data, data, len);
+ } else {
+ send_len = len - ETH_HLEN;
+ send_len += SDU_PARAM_LEN;
+ memcpy(sdu->data, data+ETH_HLEN, len-ETH_HLEN);
+ }
+
+ sdu->len = gdm_cpu_to_dev16(&udev->gdm_ed, send_len);
+ sdu->dftEpsId = gdm_cpu_to_dev32(&udev->gdm_ed, dftEpsId);
+ sdu->bearer_ID = gdm_cpu_to_dev32(&udev->gdm_ed, epsId);
+ sdu->nic_type = gdm_cpu_to_dev32(&udev->gdm_ed, nic_type);
+
+ t_sdu->len = send_len + HCI_HEADER_SIZE;
+ t_sdu->callback = cb;
+ t_sdu->cb_data = cb_data;
+
+ spin_lock_irqsave(&tx->lock, flags);
+ list_add_tail(&t_sdu->list, &tx->sdu_list);
+ queue_work(usb_tx_wq, &udev->work_tx.work);
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ if (no_spc)
+ return TX_NO_BUFFER;
+
+ return 0;
+}
+
+static int gdm_usb_hci_send(void *priv_dev, void *data, int len,
+ void (*cb)(void *data), void *cb_data)
+{
+ struct lte_udev *udev = priv_dev;
+ struct tx_cxt *tx = &udev->tx;
+ struct usb_tx *t;
+ unsigned long flags;
+
+ if (!udev->usbdev) {
+ pr_err("hci send - invalid device\n");
+ return -ENODEV;
+ }
+
+ t = alloc_tx_struct(len);
+ if (t == NULL) {
+ pr_err("hci_send - out of memory\n");
+ return -ENOMEM;
+ }
+
+ memcpy(t->buf, data, len);
+ t->callback = cb;
+ t->cb_data = cb_data;
+ t->len = len;
+ t->tx = tx;
+ t->is_sdu = 0;
+
+ spin_lock_irqsave(&tx->lock, flags);
+ list_add_tail(&t->list, &tx->hci_list);
+ queue_work(usb_tx_wq, &udev->work_tx.work);
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ return 0;
+}
+
+static struct gdm_endian *gdm_usb_get_endian(void *priv_dev)
+{
+ struct lte_udev *udev = priv_dev;
+
+ return &udev->gdm_ed;
+}
+
+static int gdm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ int ret = 0;
+ struct phy_dev *phy_dev = NULL;
+ struct lte_udev *udev = NULL;
+ u16 idVendor, idProduct;
+ int bInterfaceNumber;
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+
+ bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
+ idVendor = __le16_to_cpu(usbdev->descriptor.idVendor);
+ idProduct = __le16_to_cpu(usbdev->descriptor.idProduct);
+
+ pr_info("net vid = 0x%04x pid = 0x%04x\n", idVendor, idProduct);
+
+ if (bInterfaceNumber > NETWORK_INTERFACE) {
+ pr_info("not a network device\n");
+ return -1;
+ }
+
+ phy_dev = kmalloc(sizeof(struct phy_dev), GFP_ATOMIC);
+ if (!phy_dev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ udev = kmalloc(sizeof(struct lte_udev), GFP_ATOMIC);
+ if (!udev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(phy_dev, 0, sizeof(struct phy_dev));
+ memset(udev, 0, sizeof(struct lte_udev));
+
+ phy_dev->priv_dev = (void *)udev;
+ phy_dev->send_hci_func = gdm_usb_hci_send;
+ phy_dev->send_sdu_func = gdm_usb_sdu_send;
+ phy_dev->rcv_func = gdm_usb_recv;
+ phy_dev->get_endian = gdm_usb_get_endian;
+
+ udev->usbdev = usbdev;
+ ret = init_usb(udev);
+ if (ret < 0) {
+ pr_err("init_usb func failed\n");
+ goto out;
+ }
+ udev->intf = intf;
+
+ intf->needs_remote_wakeup = 1;
+ usb_enable_autosuspend(usbdev);
+ pm_runtime_set_autosuspend_delay(&usbdev->dev, AUTO_SUSPEND_TIMER);
+
+ /* List up hosts with big endians, otherwise, defaults to little endian */
+ if (idProduct == PID_GDM7243)
+ gdm_set_endian(&udev->gdm_ed, ENDIANNESS_BIG);
+ else
+ gdm_set_endian(&udev->gdm_ed, ENDIANNESS_LITTLE);
+
+ ret = request_mac_address(udev);
+ if (ret < 0) {
+ pr_err("request Mac address failed\n");
+ goto out;
+ }
+
+ start_rx_proc(phy_dev);
+out:
+
+ if (ret < 0) {
+ kfree(phy_dev);
+ if (udev) {
+ release_usb(udev);
+ kfree(udev);
+ }
+ }
+
+ usb_get_dev(usbdev);
+ usb_set_intfdata(intf, phy_dev);
+
+ return ret;
+}
+
+static void gdm_usb_disconnect(struct usb_interface *intf)
+{
+ struct phy_dev *phy_dev;
+ struct lte_udev *udev;
+ u16 idVendor, idProduct;
+ struct usb_device *usbdev;
+ usbdev = interface_to_usbdev(intf);
+
+ idVendor = __le16_to_cpu(usbdev->descriptor.idVendor);
+ idProduct = __le16_to_cpu(usbdev->descriptor.idProduct);
+
+ phy_dev = usb_get_intfdata(intf);
+
+ udev = phy_dev->priv_dev;
+ unregister_lte_device(phy_dev);
+
+ release_usb(udev);
+
+ kfree(udev);
+ udev = NULL;
+
+ kfree(phy_dev);
+ phy_dev = NULL;
+
+ usb_put_dev(usbdev);
+}
+
+static int gdm_usb_suspend(struct usb_interface *intf, pm_message_t pm_msg)
+{
+ struct phy_dev *phy_dev;
+ struct lte_udev *udev;
+ struct rx_cxt *rx;
+ struct usb_rx *r;
+ struct usb_rx *r_next;
+ unsigned long flags;
+
+ phy_dev = usb_get_intfdata(intf);
+ udev = phy_dev->priv_dev;
+ rx = &udev->rx;
+ if (udev->usb_state != PM_NORMAL) {
+ pr_err("usb suspend - invalid state\n");
+ return -1;
+ }
+
+ udev->usb_state = PM_SUSPEND;
+
+ spin_lock_irqsave(&rx->submit_lock, flags);
+ list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list)
+ {
+ spin_unlock_irqrestore(&rx->submit_lock, flags);
+ usb_kill_urb(r->urb);
+ spin_lock_irqsave(&rx->submit_lock, flags);
+ }
+ spin_unlock_irqrestore(&rx->submit_lock, flags);
+
+ return 0;
+}
+
+static int gdm_usb_resume(struct usb_interface *intf)
+{
+ struct phy_dev *phy_dev;
+ struct lte_udev *udev;
+ struct tx_cxt *tx;
+ struct rx_cxt *rx;
+ unsigned long flags;
+ int issue_count;
+ int i;
+
+ phy_dev = usb_get_intfdata(intf);
+ udev = phy_dev->priv_dev;
+ rx = &udev->rx;
+
+ if (udev->usb_state != PM_SUSPEND) {
+ pr_err("usb resume - invalid state\n");
+ return -1;
+ }
+ udev->usb_state = PM_NORMAL;
+
+ spin_lock_irqsave(&rx->rx_lock, flags);
+ issue_count = rx->avail_count - MAX_RX_SUBMIT_COUNT;
+ spin_unlock_irqrestore(&rx->rx_lock, flags);
+
+ if (issue_count >= 0) {
+ for (i = 0; i < issue_count; i++)
+ gdm_usb_recv(phy_dev->priv_dev,
+ udev->rx_cb,
+ phy_dev,
+ USB_COMPLETE);
+ }
+
+ tx = &udev->tx;
+ spin_lock_irqsave(&tx->lock, flags);
+ queue_work(usb_tx_wq, &udev->work_tx.work);
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ return 0;
+}
+
+static struct usb_driver gdm_usb_lte_driver = {
+ .name = "gdm_lte",
+ .probe = gdm_usb_probe,
+ .disconnect = gdm_usb_disconnect,
+ .id_table = id_table,
+ .supports_autosuspend = 1,
+ .suspend = gdm_usb_suspend,
+ .resume = gdm_usb_resume,
+ .reset_resume = gdm_usb_resume,
+};
+
+static int __init gdm_usb_lte_init(void)
+{
+ if (gdm_lte_event_init() < 0) {
+ pr_err("error creating event\n");
+ return -1;
+ }
+
+ usb_tx_wq = create_workqueue("usb_tx_wq");
+ if (usb_tx_wq == NULL)
+ return -1;
+
+ usb_rx_wq = create_workqueue("usb_rx_wq");
+ if (usb_rx_wq == NULL)
+ return -1;
+
+ return usb_register(&gdm_usb_lte_driver);
+}
+
+static void __exit gdm_usb_lte_exit(void)
+{
+ gdm_lte_event_exit();
+
+ usb_deregister(&gdm_usb_lte_driver);
+
+ if (usb_tx_wq) {
+ flush_workqueue(usb_tx_wq);
+ destroy_workqueue(usb_tx_wq);
+ }
+
+ if (usb_rx_wq) {
+ flush_workqueue(usb_rx_wq);
+ destroy_workqueue(usb_rx_wq);
+ }
+}
+
+module_init(gdm_usb_lte_init);
+module_exit(gdm_usb_lte_exit);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("GCT LTE USB Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gdm724x/gdm_usb.h b/drivers/staging/gdm724x/gdm_usb.h
new file mode 100644
index 00000000000..e6486e71a42
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_usb.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _GDM_USB_H_
+#define _GDM_USB_H_
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+#include <linux/time.h>
+
+#include "gdm_endian.h"
+#include "hci_packet.h"
+
+#define PM_NORMAL 0
+#define PM_SUSPEND 1
+#define AUTO_SUSPEND_TIMER 5000 /* ms */
+
+#define RX_BUF_SIZE (1024*32)
+#define TX_BUF_SIZE (1024*32)
+#define SDU_BUF_SIZE 2048
+#define MAX_SDU_SIZE (1024*30)
+#define MAX_PACKET_IN_MULTI_SDU 256
+
+#define VID_GCT 0x1076
+#define PID_GDM7240 0x8000
+#define PID_GDM7243 0x9000
+
+#define NETWORK_INTERFACE 1
+#define USB_SC_SCSI 0x06
+#define USB_PR_BULK 0x50
+
+#define MAX_NUM_SDU_BUF 64
+
+struct usb_tx {
+ struct list_head list;
+ struct urb *urb;
+ u8 *buf;
+ u32 len;
+ void (*callback)(void *cb_data);
+ void *cb_data;
+ struct tx_cxt *tx;
+ u8 is_sdu;
+};
+
+struct usb_tx_sdu {
+ struct list_head list;
+ u8 *buf;
+ u32 len;
+ void (*callback)(void *cb_data);
+ void *cb_data;
+};
+
+struct usb_rx {
+ struct list_head to_host_list;
+ struct list_head free_list;
+ struct list_head rx_submit_list;
+ struct rx_cxt *rx;
+ struct urb *urb;
+ u8 *buf;
+ int (*callback)(void *cb_data, void *data, int len, int context);
+ void *cb_data;
+ void *index;
+};
+
+struct tx_cxt {
+ struct list_head sdu_list;
+ struct list_head hci_list;
+ struct list_head free_list;
+ u32 avail_count;
+ spinlock_t lock;
+};
+
+struct rx_cxt {
+ struct list_head to_host_list;
+ struct list_head rx_submit_list;
+ struct list_head free_list;
+ u32 avail_count;
+ spinlock_t to_host_lock;
+ spinlock_t rx_lock;
+ spinlock_t submit_lock;
+};
+
+struct lte_udev {
+ struct usb_device *usbdev;
+ struct gdm_endian gdm_ed;
+ struct tx_cxt tx;
+ struct rx_cxt rx;
+ struct delayed_work work_tx;
+ struct delayed_work work_rx;
+ u8 send_complete;
+ u8 tx_stop;
+ struct usb_interface *intf;
+ int (*rx_cb)(void *cb_data, void *data, int len, int context);
+ int usb_state;
+ u8 request_mac_addr;
+};
+
+#endif /* _GDM_USB_H_ */
diff --git a/drivers/staging/gdm724x/hci.h b/drivers/staging/gdm724x/hci.h
new file mode 100644
index 00000000000..9a591b0db51
--- /dev/null
+++ b/drivers/staging/gdm724x/hci.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _HCI_H_
+#define _HCI_H_
+
+#define LTE_GET_INFORMATION 0x3002
+#define LTE_GET_INFORMATION_RESULT 0xB003
+ #define MAC_ADDRESS 0xA2
+
+#define LTE_LINK_ON_OFF_INDICATION 0xB133
+#define LTE_PDN_TABLE_IND 0xB143
+
+#define LTE_TX_SDU 0x3200
+#define LTE_RX_SDU 0xB201
+#define LTE_TX_MULTI_SDU 0x3202
+#define LTE_RX_MULTI_SDU 0xB203
+
+#define LTE_DL_SDU_FLOW_CONTROL 0x3305
+#define LTE_UL_SDU_FLOW_CONTROL 0xB306
+
+#define LTE_AT_CMD_TO_DEVICE 0x3307
+#define LTE_AT_CMD_FROM_DEVICE 0xB308
+
+#define LTE_SDIO_DM_SEND_PKT 0x3312
+#define LTE_SDIO_DM_RECV_PKT 0xB313
+
+#define LTE_NV_RESTORE_REQUEST 0xB30C
+#define LTE_NV_RESTORE_RESPONSE 0x330D
+#define LTE_NV_SAVE_REQUEST 0xB30E
+ #define NV_TYPE_LTE_INFO 0x00
+ #define NV_TYPE_BOARD_CONFIG 0x01
+ #define NV_TYPE_RF_CAL 0x02
+ #define NV_TYPE_TEMP 0x03
+ #define NV_TYPE_NET_INFO 0x04
+ #define NV_TYPE_SAFETY_INFO 0x05
+ #define NV_TYPE_CDMA_CAL 0x06
+ #define NV_TYPE_VENDOR 0x07
+ #define NV_TYPE_ALL 0xff
+#define LTE_NV_SAVE_RESPONSE 0x330F
+
+#define LTE_AT_CMD_TO_DEVICE_EXT 0x3323
+#define LTE_AT_CMD_FROM_DEVICE_EXT 0xB324
+
+#endif /* _HCI_H_ */
diff --git a/drivers/staging/gdm724x/hci_packet.h b/drivers/staging/gdm724x/hci_packet.h
new file mode 100644
index 00000000000..7fba8a687fa
--- /dev/null
+++ b/drivers/staging/gdm724x/hci_packet.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _HCI_PACKET_H_
+#define _HCI_PACKET_H_
+
+#define HCI_HEADER_SIZE 4
+
+/*
+ * The NIC type definition:
+ * For backward compatibility, lower 16 bits used as they were.
+ * Lower 16 bit: NIC_TYPE values
+ * Uppoer 16 bit: NIC_TYPE Flags
+ */
+#define NIC_TYPE_NIC0 0x00000010
+#define NIC_TYPE_NIC1 0x00000011
+#define NIC_TYPE_NIC2 0x00000012
+#define NIC_TYPE_NIC3 0x00000013
+#define NIC_TYPE_ARP 0x00000100
+#define NIC_TYPE_ICMPV6 0x00000200
+#define NIC_TYPE_MASK 0x0000FFFF
+#define NIC_TYPE_F_IPV4 0x00010000
+#define NIC_TYPE_F_IPV6 0x00020000
+#define NIC_TYPE_F_DHCP 0x00040000
+#define NIC_TYPE_F_NDP 0x00080000
+#define NIC_TYPE_F_VLAN 0x00100000
+
+struct hci_packet {
+ u16 cmd_evt;
+ u16 len;
+ u8 data[0];
+} __packed;
+
+struct tlv {
+ u8 type;
+ u8 len;
+ u8 *data[1];
+} __packed;
+
+struct sdu_header {
+ u16 cmd_evt;
+ u16 len;
+ u32 dftEpsId;
+ u32 bearer_ID;
+ u32 nic_type;
+} __packed;
+
+struct sdu {
+ u16 cmd_evt;
+ u16 len;
+ u32 dftEpsId;
+ u32 bearer_ID;
+ u32 nic_type;
+ u8 data[0];
+} __packed;
+
+struct multi_sdu {
+ u16 cmd_evt;
+ u16 len;
+ u16 num_packet;
+ u16 reserved;
+ u8 data[0];
+} __packed;
+
+struct hci_pdn_table_ind {
+ u16 cmd_evt;
+ u16 len;
+ u8 activate;
+ u32 dft_eps_id;
+ u32 nic_type;
+ u8 pdn_type;
+ u8 ipv4_addr[4];
+ u8 ipv6_intf_id[8];
+} __packed;
+
+struct hci_connect_ind {
+ u16 cmd_evt;
+ u16 len;
+ u32 connect;
+} __packed;
+
+
+#endif /* _HCI_PACKET_H_ */
diff --git a/drivers/staging/gdm724x/netlink_k.c b/drivers/staging/gdm724x/netlink_k.c
new file mode 100644
index 00000000000..77fc64e2842
--- /dev/null
+++ b/drivers/staging/gdm724x/netlink_k.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/export.h>
+#include <linux/etherdevice.h>
+#include <linux/netlink.h>
+#include <asm/byteorder.h>
+#include <net/sock.h>
+
+#include "netlink_k.h"
+
+#if defined(DEFINE_MUTEX)
+static DEFINE_MUTEX(netlink_mutex);
+#else
+static struct semaphore netlink_mutex;
+#define mutex_lock(x) down(x)
+#define mutex_unlock(x) up(x)
+#endif
+
+#define ND_MAX_GROUP 30
+#define ND_IFINDEX_LEN sizeof(int)
+#define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN)
+#define ND_NLMSG_DATA(nlh) ((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN))
+#define ND_NLMSG_S_LEN(len) (len+ND_IFINDEX_LEN)
+#define ND_NLMSG_R_LEN(nlh) (nlh->nlmsg_len-ND_IFINDEX_LEN)
+#define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh)
+#define ND_MAX_MSG_LEN (1024 * 32)
+
+static void (*rcv_cb)(struct net_device *dev, u16 type, void *msg, int len);
+
+static void netlink_rcv_cb(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh;
+ struct net_device *dev;
+ u32 mlen;
+ void *msg;
+ int ifindex;
+
+ if (!rcv_cb) {
+ pr_err("nl cb - unregistered\n");
+ return;
+ }
+
+ if (skb->len < NLMSG_SPACE(0)) {
+ pr_err("nl cb - invalid skb length\n");
+ return;
+ }
+
+ nlh = (struct nlmsghdr *)skb->data;
+
+ if (skb->len < nlh->nlmsg_len || nlh->nlmsg_len > ND_MAX_MSG_LEN) {
+ pr_err("nl cb - invalid length (%d,%d)\n",
+ skb->len, nlh->nlmsg_len);
+ return;
+ }
+
+ memcpy(&ifindex, ND_NLMSG_IFIDX(nlh), ND_IFINDEX_LEN);
+ msg = ND_NLMSG_DATA(nlh);
+ mlen = ND_NLMSG_R_LEN(nlh);
+
+ dev = dev_get_by_index(&init_net, ifindex);
+ if (dev) {
+ rcv_cb(dev, nlh->nlmsg_type, msg, mlen);
+ dev_put(dev);
+ } else {
+ pr_err("nl cb - dev (%d) not found\n", ifindex);
+ }
+}
+
+static void netlink_rcv(struct sk_buff *skb)
+{
+ mutex_lock(&netlink_mutex);
+ netlink_rcv_cb(skb);
+ mutex_unlock(&netlink_mutex);
+}
+
+struct sock *netlink_init(int unit,
+ void (*cb)(struct net_device *dev, u16 type, void *msg, int len))
+{
+ struct sock *sock;
+ struct netlink_kernel_cfg cfg = {
+ .input = netlink_rcv,
+ };
+
+#if !defined(DEFINE_MUTEX)
+ init_MUTEX(&netlink_mutex);
+#endif
+
+ sock = netlink_kernel_create(&init_net, unit, &cfg);
+
+ if (sock)
+ rcv_cb = cb;
+
+ return sock;
+}
+
+void netlink_exit(struct sock *sock)
+{
+ sock_release(sock->sk_socket);
+}
+
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
+{
+ static u32 seq;
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh;
+ int ret = 0;
+
+ if (group > ND_MAX_GROUP)
+ return -EINVAL;
+
+ if (!netlink_has_listeners(sock, group+1))
+ return -ESRCH;
+
+ skb = alloc_skb(NLMSG_SPACE(len), GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ seq++;
+
+ nlh = nlmsg_put(skb, 0, seq, type, len, 0);
+ memcpy(NLMSG_DATA(nlh), msg, len);
+ NETLINK_CB(skb).portid = 0;
+ NETLINK_CB(skb).dst_group = 0;
+
+ ret = netlink_broadcast(sock, skb, 0, group+1, GFP_ATOMIC);
+ if (!ret)
+ return len;
+
+ if (ret != -ESRCH)
+ pr_err("nl broadcast g=%d, t=%d, l=%d, r=%d\n",
+ group, type, len, ret);
+ else if (netlink_has_listeners(sock, group+1))
+ return -EAGAIN;
+
+ return ret;
+}
diff --git a/drivers/staging/gdm724x/netlink_k.h b/drivers/staging/gdm724x/netlink_k.h
new file mode 100644
index 00000000000..589486d7671
--- /dev/null
+++ b/drivers/staging/gdm724x/netlink_k.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef _NETLINK_K_H
+#define _NETLINK_K_H
+
+#include <linux/netdevice.h>
+#include <net/sock.h>
+
+struct sock *netlink_init(int unit,
+ void (*cb)(struct net_device *dev, u16 type, void *msg, int len));
+void netlink_exit(struct sock *sock);
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len);
+
+#endif /* _NETLINK_K_H_ */
diff --git a/drivers/staging/gdm72xx/gdm_qos.c b/drivers/staging/gdm72xx/gdm_qos.c
index b795353e834..cc3692439a5 100644
--- a/drivers/staging/gdm72xx/gdm_qos.c
+++ b/drivers/staging/gdm72xx/gdm_qos.c
@@ -250,8 +250,8 @@ static void send_qos_list(struct nic *nic, struct list_head *head)
list_for_each_entry_safe(entry, n, head, list) {
list_del(&entry->list);
- free_qos_entry(entry);
gdm_wimax_send_tx(entry->skb, entry->dev);
+ free_qos_entry(entry);
}
}
diff --git a/drivers/staging/iio/Documentation/device.txt b/drivers/staging/iio/Documentation/device.txt
index ea08d621337..8be32e5a0af 100644
--- a/drivers/staging/iio/Documentation/device.txt
+++ b/drivers/staging/iio/Documentation/device.txt
@@ -56,7 +56,7 @@ Then fill in the following:
- indio_dev->modes:
Specify whether direct access and / or ring buffer access is supported.
-- indio_dev->ring:
+- indio_dev->buffer:
An optional associated buffer.
- indio_dev->pollfunc:
Poll function related elements. This controls what occurs when a trigger
@@ -67,7 +67,7 @@ Then fill in the following:
- indio_dev->num_channels:
How many channels are there?
-Once these are set up, a call to iio_device_register(indio_dev),
+Once these are set up, a call to iio_device_register(indio_dev)
will register the device with the iio core.
Worth noting here is that, if a ring buffer is to be used, it can be
diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
index ab8ec7af88b..2105576fa77 100644
--- a/drivers/staging/iio/accel/adis16201_core.c
+++ b/drivers/staging/iio/accel/adis16201_core.c
@@ -182,11 +182,10 @@ static int adis16201_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
@@ -201,10 +200,10 @@ static int adis16201_probe(struct spi_device *spi)
ret = adis_init(st, indio_dev, spi, &adis16201_data);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret)
- goto error_free_dev;
+ return ret;
/* Get the device into a sane initial state */
ret = adis_initial_startup(st);
@@ -218,9 +217,6 @@ static int adis16201_probe(struct spi_device *spi)
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(st, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -231,7 +227,6 @@ static int adis16201_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
adis_cleanup_buffer_and_trigger(st, indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
index b08ac8fdeee..409a28ed904 100644
--- a/drivers/staging/iio/accel/adis16203_core.c
+++ b/drivers/staging/iio/accel/adis16203_core.c
@@ -148,11 +148,9 @@ static int adis16203_probe(struct spi_device *spi)
struct adis *st;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
@@ -166,11 +164,11 @@ static int adis16203_probe(struct spi_device *spi)
ret = adis_init(st, indio_dev, spi, &adis16203_data);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret)
- goto error_free_dev;
+ return ret;
/* Get the device into a sane initial state */
ret = adis_initial_startup(st);
@@ -185,9 +183,6 @@ static int adis16203_probe(struct spi_device *spi)
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(st, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -198,7 +193,6 @@ static int adis16203_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
adis_cleanup_buffer_and_trigger(st, indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c
index 792ec25a50d..b8ea76857cd 100644
--- a/drivers/staging/iio/accel/adis16204_core.c
+++ b/drivers/staging/iio/accel/adis16204_core.c
@@ -187,11 +187,9 @@ static int adis16204_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
@@ -205,11 +203,11 @@ static int adis16204_probe(struct spi_device *spi)
ret = adis_init(st, indio_dev, spi, &adis16204_data);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret)
- goto error_free_dev;
+ return ret;
/* Get the device into a sane initial state */
ret = adis_initial_startup(st);
@@ -223,9 +221,6 @@ static int adis16204_probe(struct spi_device *spi)
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(st, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -236,7 +231,6 @@ static int adis16204_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
adis_cleanup_buffer_and_trigger(st, indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index 323c169d699..4492e51d888 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -183,11 +183,9 @@ static int adis16209_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
@@ -201,10 +199,10 @@ static int adis16209_probe(struct spi_device *spi)
ret = adis_init(st, indio_dev, spi, &adis16209_data);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret)
- goto error_free_dev;
+ return ret;
/* Get the device into a sane initial state */
ret = adis_initial_startup(st);
@@ -218,9 +216,6 @@ static int adis16209_probe(struct spi_device *spi)
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(st, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -231,7 +226,6 @@ static int adis16209_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
adis_cleanup_buffer_and_trigger(st, indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
index 0e72f795ed0..5c289614357 100644
--- a/drivers/staging/iio/accel/adis16220_core.c
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -428,11 +428,9 @@ static int adis16220_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
@@ -447,7 +445,7 @@ static int adis16220_probe(struct spi_device *spi)
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_dev;
+ return ret;
ret = sysfs_create_bin_file(&indio_dev->dev.kobj, &accel_bin);
if (ret)
@@ -478,9 +476,6 @@ error_rm_accel_bin:
sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
error_unregister_dev:
iio_device_unregister(indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -492,7 +487,6 @@ static int adis16220_remove(struct spi_device *spi)
sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin);
sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
iio_device_unregister(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index fd1f0fd0fba..3a303a03d02 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -236,11 +236,9 @@ static int adis16240_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
@@ -254,10 +252,10 @@ static int adis16240_probe(struct spi_device *spi)
ret = adis_init(st, indio_dev, spi, &adis16240_data);
if (ret)
- goto error_free_dev;
+ return ret;
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret)
- goto error_free_dev;
+ return ret;
/* Get the device into a sane initial state */
ret = adis_initial_startup(st);
@@ -270,9 +268,6 @@ static int adis16240_probe(struct spi_device *spi)
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(st, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -283,7 +278,6 @@ static int adis16240_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
adis_cleanup_buffer_and_trigger(st, indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index 8ed75a94f46..bb852dc9c98 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -668,11 +668,9 @@ static int lis3l02dq_probe(struct spi_device *spi)
struct lis3l02dq_state *st;
struct iio_dev *indio_dev;
- indio_dev = iio_device_alloc(sizeof *st);
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
@@ -690,7 +688,7 @@ static int lis3l02dq_probe(struct spi_device *spi)
ret = lis3l02dq_configure_buffer(indio_dev);
if (ret)
- goto error_free_dev;
+ return ret;
ret = iio_buffer_register(indio_dev,
lis3l02dq_channels,
@@ -736,9 +734,6 @@ error_uninitialize_buffer:
iio_buffer_unregister(indio_dev);
error_unreg_buffer_funcs:
lis3l02dq_unconfigure_buffer(indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
return ret;
}
@@ -786,8 +781,6 @@ static int lis3l02dq_remove(struct spi_device *spi)
iio_buffer_unregister(indio_dev);
lis3l02dq_unconfigure_buffer(indio_dev);
- iio_device_free(indio_dev);
-
return 0;
}
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index 32950ad9485..48a25ba290f 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -1135,11 +1135,9 @@ static int sca3000_probe(struct spi_device *spi)
struct sca3000_state *st;
struct iio_dev *indio_dev;
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
@@ -1162,7 +1160,7 @@ static int sca3000_probe(struct spi_device *spi)
sca3000_configure_ring(indio_dev);
ret = iio_device_register(indio_dev);
if (ret < 0)
- goto error_free_dev;
+ return ret;
ret = iio_buffer_register(indio_dev,
sca3000_channels,
@@ -1198,10 +1196,6 @@ error_unregister_ring:
iio_buffer_unregister(indio_dev);
error_unregister_dev:
iio_device_unregister(indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-
-error_ret:
return ret;
}
@@ -1235,7 +1229,6 @@ static int sca3000_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
iio_buffer_unregister(indio_dev);
sca3000_unconfigure_ring(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
index 9f52a285792..a08c1736458 100644
--- a/drivers/staging/iio/adc/mxs-lradc.c
+++ b/drivers/staging/iio/adc/mxs-lradc.c
@@ -225,6 +225,9 @@ struct mxs_lradc {
#define LRADC_CTRL4_LRADCSELECT_MASK(n) (0xf << ((n) * 4))
#define LRADC_CTRL4_LRADCSELECT_OFFSET(n) ((n) * 4)
+#define LRADC_RESOLUTION 12
+#define LRADC_SINGLE_SAMPLE_MASK ((1 << LRADC_RESOLUTION) - 1)
+
/*
* Raw I/O operations
*/
@@ -540,9 +543,10 @@ static int mxs_lradc_ts_register(struct mxs_lradc *lradc)
__set_bit(EV_ABS, input->evbit);
__set_bit(EV_KEY, input->evbit);
__set_bit(BTN_TOUCH, input->keybit);
- input_set_abs_params(input, ABS_X, 0, LRADC_CH_VALUE_MASK, 0, 0);
- input_set_abs_params(input, ABS_Y, 0, LRADC_CH_VALUE_MASK, 0, 0);
- input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_CH_VALUE_MASK, 0, 0);
+ input_set_abs_params(input, ABS_X, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0);
+ input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_SINGLE_SAMPLE_MASK,
+ 0, 0);
lradc->ts_input = input;
input_set_drvdata(input, lradc);
@@ -817,7 +821,7 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
.channel = (idx), \
.scan_type = { \
.sign = 'u', \
- .realbits = 18, \
+ .realbits = LRADC_RESOLUTION, \
.storagebits = 32, \
}, \
}
@@ -841,14 +845,16 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
MXS_ADC_CHAN(15, IIO_VOLTAGE), /* VDD5V */
};
-static void mxs_lradc_hw_init(struct mxs_lradc *lradc)
+static int mxs_lradc_hw_init(struct mxs_lradc *lradc)
{
/* The ADC always uses DELAY CHANNEL 0. */
const uint32_t adc_cfg =
(1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + 0)) |
(LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET);
- stmp_reset_block(lradc->base);
+ int ret = stmp_reset_block(lradc->base);
+ if (ret)
+ return ret;
/* Configure DELAY CHANNEL 0 for generic ADC sampling. */
writel(adc_cfg, lradc->base + LRADC_DELAY(0));
@@ -869,6 +875,8 @@ static void mxs_lradc_hw_init(struct mxs_lradc *lradc)
/* Start internal temperature sensing. */
writel(0, lradc->base + LRADC_CTRL2);
+
+ return 0;
}
static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
@@ -905,7 +913,7 @@ static int mxs_lradc_probe(struct platform_device *pdev)
int i;
/* Allocate the IIO device. */
- iio = iio_device_alloc(sizeof(*lradc));
+ iio = devm_iio_device_alloc(dev, sizeof(*lradc));
if (!iio) {
dev_err(dev, "Failed to allocate IIO device\n");
return -ENOMEM;
@@ -917,10 +925,8 @@ static int mxs_lradc_probe(struct platform_device *pdev)
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
lradc->dev = &pdev->dev;
lradc->base = devm_ioremap_resource(dev, iores);
- if (IS_ERR(lradc->base)) {
- ret = PTR_ERR(lradc->base);
- goto err_addr;
- }
+ if (IS_ERR(lradc->base))
+ return PTR_ERR(lradc->base);
INIT_WORK(&lradc->ts_work, mxs_lradc_ts_work);
@@ -940,16 +946,14 @@ static int mxs_lradc_probe(struct platform_device *pdev)
/* Grab all IRQ sources */
for (i = 0; i < of_cfg->irq_count; i++) {
lradc->irq[i] = platform_get_irq(pdev, i);
- if (lradc->irq[i] < 0) {
- ret = -EINVAL;
- goto err_addr;
- }
+ if (lradc->irq[i] < 0)
+ return -EINVAL;
ret = devm_request_irq(dev, lradc->irq[i],
mxs_lradc_handle_irq, 0,
of_cfg->irq_name[i], iio);
if (ret)
- goto err_addr;
+ return ret;
}
platform_set_drvdata(pdev, iio);
@@ -969,14 +973,16 @@ static int mxs_lradc_probe(struct platform_device *pdev)
&mxs_lradc_trigger_handler,
&mxs_lradc_buffer_ops);
if (ret)
- goto err_addr;
+ return ret;
ret = mxs_lradc_trigger_init(iio);
if (ret)
goto err_trig;
/* Configure the hardware. */
- mxs_lradc_hw_init(lradc);
+ ret = mxs_lradc_hw_init(lradc);
+ if (ret)
+ goto err_dev;
/* Register the touchscreen input device. */
ret = mxs_lradc_ts_register(lradc);
@@ -998,8 +1004,6 @@ err_dev:
mxs_lradc_trigger_remove(iio);
err_trig:
iio_triggered_buffer_cleanup(iio);
-err_addr:
- iio_device_free(iio);
return ret;
}
@@ -1015,7 +1019,6 @@ static int mxs_lradc_remove(struct platform_device *pdev)
iio_device_unregister(iio);
iio_triggered_buffer_cleanup(iio);
mxs_lradc_trigger_remove(iio);
- iio_device_free(iio);
return 0;
}
diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c
index 736219c3030..20f2d555e7c 100644
--- a/drivers/staging/iio/adc/spear_adc.c
+++ b/drivers/staging/iio/adc/spear_adc.c
@@ -300,11 +300,10 @@ static int spear_adc_probe(struct platform_device *pdev)
int ret = -ENODEV;
int irq;
- iodev = iio_device_alloc(sizeof(struct spear_adc_info));
+ iodev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_info));
if (!iodev) {
dev_err(dev, "failed allocating iio device\n");
- ret = -ENOMEM;
- goto errout1;
+ return -ENOMEM;
}
info = iio_priv(iodev);
@@ -318,8 +317,7 @@ static int spear_adc_probe(struct platform_device *pdev)
info->adc_base_spear6xx = of_iomap(np, 0);
if (!info->adc_base_spear6xx) {
dev_err(dev, "failed mapping memory\n");
- ret = -ENOMEM;
- goto errout2;
+ return -ENOMEM;
}
info->adc_base_spear3xx =
(struct adc_regs_spear3xx *)info->adc_base_spear6xx;
@@ -327,33 +325,33 @@ static int spear_adc_probe(struct platform_device *pdev)
info->clk = clk_get(dev, NULL);
if (IS_ERR(info->clk)) {
dev_err(dev, "failed getting clock\n");
- goto errout3;
+ goto errout1;
}
ret = clk_prepare_enable(info->clk);
if (ret) {
dev_err(dev, "failed enabling clock\n");
- goto errout4;
+ goto errout2;
}
irq = platform_get_irq(pdev, 0);
if ((irq < 0) || (irq >= NR_IRQS)) {
dev_err(dev, "failed getting interrupt resource\n");
ret = -EINVAL;
- goto errout5;
+ goto errout3;
}
ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info);
if (ret < 0) {
dev_err(dev, "failed requesting interrupt\n");
- goto errout5;
+ goto errout3;
}
if (of_property_read_u32(np, "sampling-frequency",
&info->sampling_freq)) {
dev_err(dev, "sampling-frequency missing in DT\n");
ret = -EINVAL;
- goto errout5;
+ goto errout3;
}
/*
@@ -383,21 +381,18 @@ static int spear_adc_probe(struct platform_device *pdev)
ret = iio_device_register(iodev);
if (ret)
- goto errout5;
+ goto errout3;
dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq);
return 0;
-errout5:
- clk_disable_unprepare(info->clk);
-errout4:
- clk_put(info->clk);
errout3:
- iounmap(info->adc_base_spear6xx);
+ clk_disable_unprepare(info->clk);
errout2:
- iio_device_free(iodev);
+ clk_put(info->clk);
errout1:
+ iounmap(info->adc_base_spear6xx);
return ret;
}
@@ -410,7 +405,6 @@ static int spear_adc_remove(struct platform_device *pdev)
clk_disable_unprepare(info->clk);
clk_put(info->clk);
iounmap(info->adc_base_spear6xx);
- iio_device_free(iodev);
return 0;
}
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index 506b5a7d96c..1e1356825d6 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -551,31 +551,6 @@ static IIO_DEVICE_ATTR(enable_smbus_timeout, S_IRUGO | S_IWUSR,
adt7316_store_enable_smbus_timeout,
0);
-
-static ssize_t adt7316_store_reset(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7316_chip_info *chip = iio_priv(dev_info);
- u8 config2;
- int ret;
-
- config2 = chip->config2 | ADT7316_RESET;
-
- ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
- if (ret)
- return -EIO;
-
- return len;
-}
-
-static IIO_DEVICE_ATTR(reset, S_IWUSR,
- NULL,
- adt7316_store_reset,
- 0);
-
static ssize_t adt7316_show_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1675,7 +1650,6 @@ static IIO_DEVICE_ATTR(bus_type, S_IRUGO, adt7316_show_bus_type, NULL, 0);
static struct attribute *adt7316_attributes[] = {
&iio_dev_attr_all_modes.dev_attr.attr,
&iio_dev_attr_mode.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
&iio_dev_attr_enabled.dev_attr.attr,
&iio_dev_attr_ad_channel.dev_attr.attr,
&iio_dev_attr_all_ad_channels.dev_attr.attr,
@@ -1719,7 +1693,6 @@ static struct attribute *adt7516_attributes[] = {
&iio_dev_attr_all_modes.dev_attr.attr,
&iio_dev_attr_mode.dev_attr.attr,
&iio_dev_attr_select_ex_temp.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
&iio_dev_attr_enabled.dev_attr.attr,
&iio_dev_attr_ad_channel.dev_attr.attr,
&iio_dev_attr_all_ad_channels.dev_attr.attr,
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index 687dd2c9143..f4a0341cc70 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -558,11 +558,9 @@ static int ad7150_probe(struct i2c_client *client,
struct ad7150_chip_info *chip;
struct iio_dev *indio_dev;
- indio_dev = iio_device_alloc(sizeof(*chip));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+ if (!indio_dev)
+ return -ENOMEM;
chip = iio_priv(indio_dev);
mutex_init(&chip->state_lock);
/* this is only used for device removal purposes */
@@ -581,7 +579,7 @@ static int ad7150_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
if (client->irq) {
- ret = request_threaded_irq(client->irq,
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL,
&ad7150_event_handler,
IRQF_TRIGGER_RISING |
@@ -590,11 +588,11 @@ static int ad7150_probe(struct i2c_client *client,
"ad7150_irq1",
indio_dev);
if (ret)
- goto error_free_dev;
+ return ret;
}
if (client->dev.platform_data) {
- ret = request_threaded_irq(*(unsigned int *)
+ ret = devm_request_threaded_irq(&client->dev, *(unsigned int *)
client->dev.platform_data,
NULL,
&ad7150_event_handler,
@@ -604,28 +602,17 @@ static int ad7150_probe(struct i2c_client *client,
"ad7150_irq2",
indio_dev);
if (ret)
- goto error_free_irq;
+ return ret;
}
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_irq2;
+ return ret;
dev_info(&client->dev, "%s capacitive sensor registered,irq: %d\n",
id->name, client->irq);
return 0;
-error_free_irq2:
- if (client->dev.platform_data)
- free_irq(*(unsigned int *)client->dev.platform_data,
- indio_dev);
-error_free_irq:
- if (client->irq)
- free_irq(client->irq, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
- return ret;
}
static int ad7150_remove(struct i2c_client *client)
@@ -633,13 +620,6 @@ static int ad7150_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
- if (client->irq)
- free_irq(client->irq, indio_dev);
-
- if (client->dev.platform_data)
- free_irq(*(unsigned int *)client->dev.platform_data, indio_dev);
-
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c
index 1d7c5283a85..f2c309d1eb5 100644
--- a/drivers/staging/iio/cdc/ad7152.c
+++ b/drivers/staging/iio/cdc/ad7152.c
@@ -481,11 +481,9 @@ static int ad7152_probe(struct i2c_client *client,
struct ad7152_chip_info *chip;
struct iio_dev *indio_dev;
- indio_dev = iio_device_alloc(sizeof(*chip));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+ if (!indio_dev)
+ return -ENOMEM;
chip = iio_priv(indio_dev);
/* this is only used for device removal purposes */
i2c_set_clientdata(client, indio_dev);
@@ -506,16 +504,11 @@ static int ad7152_probe(struct i2c_client *client,
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_dev;
+ return ret;
dev_err(&client->dev, "%s capacitive sensor registered\n", id->name);
return 0;
-
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
- return ret;
}
static int ad7152_remove(struct i2c_client *client)
@@ -523,7 +516,6 @@ static int ad7152_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index 94f9ca726d1..75a533bce02 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -699,11 +699,9 @@ static int ad7746_probe(struct i2c_client *client,
int ret = 0;
unsigned char regval = 0;
- indio_dev = iio_device_alloc(sizeof(*chip));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+ if (!indio_dev)
+ return -ENOMEM;
chip = iio_priv(indio_dev);
/* this is only used for device removal purposes */
i2c_set_clientdata(client, indio_dev);
@@ -748,20 +746,15 @@ static int ad7746_probe(struct i2c_client *client,
ret = i2c_smbus_write_byte_data(chip->client,
AD7746_REG_EXC_SETUP, regval);
if (ret < 0)
- goto error_free_dev;
+ return ret;
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_dev;
+ return ret;
dev_info(&client->dev, "%s capacitive sensor registered\n", id->name);
return 0;
-
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
- return ret;
}
static int ad7746_remove(struct i2c_client *client)
@@ -769,7 +762,6 @@ static int ad7746_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig
index b4333715536..88b199bb292 100644
--- a/drivers/staging/iio/gyro/Kconfig
+++ b/drivers/staging/iio/gyro/Kconfig
@@ -10,16 +10,4 @@ config ADIS16060
Say yes here to build support for Analog Devices adis16060 wide bandwidth
yaw rate gyroscope with SPI.
-config ADIS16260
- tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver"
- depends on SPI
- select IIO_ADIS_LIB
- select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
- help
- Say yes here to build support for Analog Devices ADIS16260 ADIS16265
- ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors.
-
- This driver can also be built as a module. If so, the module
- will be called adis16260.
-
endmenu
diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile
index 975f95b141d..cf22d6d55e2 100644
--- a/drivers/staging/iio/gyro/Makefile
+++ b/drivers/staging/iio/gyro/Makefile
@@ -4,6 +4,3 @@
adis16060-y := adis16060_core.o
obj-$(CONFIG_ADIS16060) += adis16060.o
-
-adis16260-y := adis16260_core.o
-obj-$(CONFIG_ADIS16260) += adis16260.o
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
index c67d3a832ae..6d3d771154f 100644
--- a/drivers/staging/iio/gyro/adis16060_core.c
+++ b/drivers/staging/iio/gyro/adis16060_core.c
@@ -151,11 +151,9 @@ static int adis16060_r_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_device_alloc(sizeof(*st));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
@@ -171,23 +169,16 @@ static int adis16060_r_probe(struct spi_device *spi)
ret = iio_device_register(indio_dev);
if (ret)
- goto error_free_dev;
+ return ret;
adis16060_iio_dev = indio_dev;
return 0;
-
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
- return ret;
}
/* fixme, confirm ordering in this function */
static int adis16060_r_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_device_free(spi_get_drvdata(spi));
-
return 0;
}
diff --git a/drivers/staging/iio/gyro/adis16260.h b/drivers/staging/iio/gyro/adis16260.h
deleted file mode 100644
index df3c0b7e954..00000000000
--- a/drivers/staging/iio/gyro/adis16260.h
+++ /dev/null
@@ -1,98 +0,0 @@
-#ifndef SPI_ADIS16260_H_
-#define SPI_ADIS16260_H_
-
-#include "adis16260_platform_data.h"
-#include <linux/iio/imu/adis.h>
-
-#define ADIS16260_STARTUP_DELAY 220 /* ms */
-
-#define ADIS16260_FLASH_CNT 0x00 /* Flash memory write count */
-#define ADIS16260_SUPPLY_OUT 0x02 /* Power supply measurement */
-#define ADIS16260_GYRO_OUT 0x04 /* X-axis gyroscope output */
-#define ADIS16260_AUX_ADC 0x0A /* analog input channel measurement */
-#define ADIS16260_TEMP_OUT 0x0C /* internal temperature measurement */
-#define ADIS16260_ANGL_OUT 0x0E /* angle displacement */
-#define ADIS16260_GYRO_OFF 0x14 /* Calibration, offset/bias adjustment */
-#define ADIS16260_GYRO_SCALE 0x16 /* Calibration, scale adjustment */
-#define ADIS16260_ALM_MAG1 0x20 /* Alarm 1 magnitude/polarity setting */
-#define ADIS16260_ALM_MAG2 0x22 /* Alarm 2 magnitude/polarity setting */
-#define ADIS16260_ALM_SMPL1 0x24 /* Alarm 1 dynamic rate of change setting */
-#define ADIS16260_ALM_SMPL2 0x26 /* Alarm 2 dynamic rate of change setting */
-#define ADIS16260_ALM_CTRL 0x28 /* Alarm control */
-#define ADIS16260_AUX_DAC 0x30 /* Auxiliary DAC data */
-#define ADIS16260_GPIO_CTRL 0x32 /* Control, digital I/O line */
-#define ADIS16260_MSC_CTRL 0x34 /* Control, data ready, self-test settings */
-#define ADIS16260_SMPL_PRD 0x36 /* Control, internal sample rate */
-#define ADIS16260_SENS_AVG 0x38 /* Control, dynamic range, filtering */
-#define ADIS16260_SLP_CNT 0x3A /* Control, sleep mode initiation */
-#define ADIS16260_DIAG_STAT 0x3C /* Diagnostic, error flags */
-#define ADIS16260_GLOB_CMD 0x3E /* Control, global commands */
-#define ADIS16260_LOT_ID1 0x52 /* Lot Identification Code 1 */
-#define ADIS16260_LOT_ID2 0x54 /* Lot Identification Code 2 */
-#define ADIS16260_PROD_ID 0x56 /* Product identifier;
- * convert to decimal = 16,265/16,260 */
-#define ADIS16260_SERIAL_NUM 0x58 /* Serial number */
-
-#define ADIS16260_ERROR_ACTIVE (1<<14)
-#define ADIS16260_NEW_DATA (1<<15)
-
-/* MSC_CTRL */
-#define ADIS16260_MSC_CTRL_MEM_TEST (1<<11)
-/* Internal self-test enable */
-#define ADIS16260_MSC_CTRL_INT_SELF_TEST (1<<10)
-#define ADIS16260_MSC_CTRL_NEG_SELF_TEST (1<<9)
-#define ADIS16260_MSC_CTRL_POS_SELF_TEST (1<<8)
-#define ADIS16260_MSC_CTRL_DATA_RDY_EN (1<<2)
-#define ADIS16260_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1)
-#define ADIS16260_MSC_CTRL_DATA_RDY_DIO2 (1<<0)
-
-/* SMPL_PRD */
-/* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */
-#define ADIS16260_SMPL_PRD_TIME_BASE (1<<7)
-#define ADIS16260_SMPL_PRD_DIV_MASK 0x7F
-
-/* SLP_CNT */
-#define ADIS16260_SLP_CNT_POWER_OFF 0x80
-
-/* DIAG_STAT */
-#define ADIS16260_DIAG_STAT_ALARM2 (1<<9)
-#define ADIS16260_DIAG_STAT_ALARM1 (1<<8)
-#define ADIS16260_DIAG_STAT_FLASH_CHK_BIT 6
-#define ADIS16260_DIAG_STAT_SELF_TEST_BIT 5
-#define ADIS16260_DIAG_STAT_OVERFLOW_BIT 4
-#define ADIS16260_DIAG_STAT_SPI_FAIL_BIT 3
-#define ADIS16260_DIAG_STAT_FLASH_UPT_BIT 2
-#define ADIS16260_DIAG_STAT_POWER_HIGH_BIT 1
-#define ADIS16260_DIAG_STAT_POWER_LOW_BIT 0
-
-/* GLOB_CMD */
-#define ADIS16260_GLOB_CMD_SW_RESET (1<<7)
-#define ADIS16260_GLOB_CMD_FLASH_UPD (1<<3)
-#define ADIS16260_GLOB_CMD_DAC_LATCH (1<<2)
-#define ADIS16260_GLOB_CMD_FAC_CALIB (1<<1)
-#define ADIS16260_GLOB_CMD_AUTO_NULL (1<<0)
-
-#define ADIS16260_SPI_SLOW (u32)(300 * 1000)
-#define ADIS16260_SPI_BURST (u32)(1000 * 1000)
-#define ADIS16260_SPI_FAST (u32)(2000 * 1000)
-
-/**
- * struct adis16260_state - device instance specific data
- * @negate: negate the scale parameter
- **/
-struct adis16260_state {
- unsigned negate:1;
- struct adis adis;
-};
-
-/* At the moment triggers are only used for ring buffer
- * filling. This may change!
- */
-
-#define ADIS16260_SCAN_GYRO 0
-#define ADIS16260_SCAN_SUPPLY 1
-#define ADIS16260_SCAN_AUX_ADC 2
-#define ADIS16260_SCAN_TEMP 3
-#define ADIS16260_SCAN_ANGL 4
-
-#endif /* SPI_ADIS16260_H_ */
diff --git a/drivers/staging/iio/gyro/adis16260_platform_data.h b/drivers/staging/iio/gyro/adis16260_platform_data.h
deleted file mode 100644
index 12802e97be9..00000000000
--- a/drivers/staging/iio/gyro/adis16260_platform_data.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * ADIS16260 Programmable Digital Gyroscope Sensor Driver Platform Data
- *
- * Based on adis16255.h Matthia Brugger <m_brugger&web.de>
- *
- * Copyright (C) 2010 Fraunhofer Institute for Integrated Circuits
- *
- * Licensed under the GPL-2 or later.
- */
-
-/**
- * struct adis16260_platform_data - instance specific data
- * @direction: x y or z
- * @negate: flag to indicate value should be inverted.
- **/
-struct adis16260_platform_data {
- char direction;
- unsigned negate:1;
-};
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index 82478a59e42..351936c3efd 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -550,11 +550,10 @@ static int isl29018_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int err;
- indio_dev = iio_device_alloc(sizeof(*chip));
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
if (indio_dev == NULL) {
dev_err(&client->dev, "iio allocation fails\n");
- err = -ENOMEM;
- goto exit;
+ return -ENOMEM;
}
chip = iio_priv(indio_dev);
@@ -572,12 +571,12 @@ static int isl29018_probe(struct i2c_client *client,
if (IS_ERR(chip->regmap)) {
err = PTR_ERR(chip->regmap);
dev_err(chip->dev, "regmap initialization failed: %d\n", err);
- goto exit;
+ return err;
}
err = isl29018_chip_init(chip);
if (err)
- goto exit_iio_free;
+ return err;
indio_dev->info = &isl29108_info;
indio_dev->channels = isl29018_channels;
@@ -588,14 +587,10 @@ static int isl29018_probe(struct i2c_client *client,
err = iio_device_register(indio_dev);
if (err) {
dev_err(&client->dev, "iio registration fails\n");
- goto exit_iio_free;
+ return err;
}
return 0;
-exit_iio_free:
- iio_device_free(indio_dev);
-exit:
- return err;
}
static int isl29018_remove(struct i2c_client *client)
@@ -604,7 +599,6 @@ static int isl29018_remove(struct i2c_client *client)
dev_dbg(&client->dev, "%s()\n", __func__);
iio_device_unregister(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
index 8bb0d03627f..6014625920b 100644
--- a/drivers/staging/iio/light/isl29028.c
+++ b/drivers/staging/iio/light/isl29028.c
@@ -482,7 +482,7 @@ static int isl29028_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int ret;
- indio_dev = iio_device_alloc(sizeof(*chip));
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
if (!indio_dev) {
dev_err(&client->dev, "iio allocation fails\n");
return -ENOMEM;
@@ -498,13 +498,13 @@ static int isl29028_probe(struct i2c_client *client,
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
dev_err(chip->dev, "regmap initialization failed: %d\n", ret);
- goto exit_iio_free;
+ return ret;
}
ret = isl29028_chip_init(chip);
if (ret < 0) {
dev_err(chip->dev, "chip initialization failed: %d\n", ret);
- goto exit_iio_free;
+ return ret;
}
indio_dev->info = &isl29028_info;
@@ -517,13 +517,9 @@ static int isl29028_probe(struct i2c_client *client,
if (ret < 0) {
dev_err(chip->dev, "iio registration fails with error %d\n",
ret);
- goto exit_iio_free;
+ return ret;
}
return 0;
-
-exit_iio_free:
- iio_device_free(indio_dev);
- return ret;
}
static int isl29028_remove(struct i2c_client *client)
@@ -531,7 +527,6 @@ static int isl29028_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
- iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
index 86c6bf9d5dd..d2748c329ea 100644
--- a/drivers/staging/iio/magnetometer/hmc5843.c
+++ b/drivers/staging/iio/magnetometer/hmc5843.c
@@ -20,12 +20,10 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/types.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
+#include <linux/delay.h>
#define HMC5843_CONFIG_REG_A 0x00
#define HMC5843_CONFIG_REG_B 0x01
@@ -42,9 +40,6 @@
#define HMC5883_DATA_OUT_Y_MSB_REG 0x07
#define HMC5883_DATA_OUT_Y_LSB_REG 0x08
#define HMC5843_STATUS_REG 0x09
-#define HMC5843_ID_REG_A 0x0A
-#define HMC5843_ID_REG_B 0x0B
-#define HMC5843_ID_REG_C 0x0C
enum hmc5843_ids {
HMC5843_ID,
@@ -53,14 +48,6 @@ enum hmc5843_ids {
};
/*
- * Beware: identification of the HMC5883 is still "H43";
- * I2C address is also unchanged
- */
-#define HMC5843_ID_REG_LENGTH 0x03
-#define HMC5843_ID_STRING "H43"
-#define HMC5843_I2C_ADDRESS 0x1E
-
-/*
* Range gain settings in (+-)Ga
* Beware: HMC5843 and HMC5883 have different recommended sensor field
* ranges; default corresponds to +-1.0 Ga and +-1.3 Ga, respectively
@@ -185,14 +172,9 @@ static const char * const hmc5883_regval_to_sample_freq[] = {
"0.75", "1.5", "3", "7.5", "15", "30", "75",
};
-/* Addresses to scan: 0x1E */
-static const unsigned short normal_i2c[] = { HMC5843_I2C_ADDRESS,
- I2C_CLIENT_END };
-
/* Describe chip variants */
struct hmc5843_chip_info {
const struct iio_chan_spec *channels;
- int num_channels;
const char * const *regval_to_sample_freq;
const int *regval_to_input_field_mga;
const int *regval_to_nanoscale;
@@ -225,18 +207,29 @@ static int hmc5843_read_measurement(struct iio_dev *indio_dev,
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
struct hmc5843_data *data = iio_priv(indio_dev);
s32 result;
+ int tries = 150;
mutex_lock(&data->lock);
- result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
- while (!(result & HMC5843_DATA_READY))
- result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
+ while (tries-- > 0) {
+ result = i2c_smbus_read_byte_data(client,
+ HMC5843_STATUS_REG);
+ if (result & HMC5843_DATA_READY)
+ break;
+ msleep(20);
+ }
+
+ if (tries < 0) {
+ dev_err(&client->dev, "data not ready\n");
+ mutex_unlock(&data->lock);
+ return -EIO;
+ }
- result = i2c_smbus_read_word_data(client, address);
+ result = i2c_smbus_read_word_swapped(client, address);
mutex_unlock(&data->lock);
if (result < 0)
return -EINVAL;
- *val = (s16)swab16((u16)result);
+ *val = result;
return IIO_VAL_INT;
}
@@ -559,14 +552,14 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
-#define HMC5843_CHANNEL(axis, add) \
+#define HMC5843_CHANNEL(axis, addr) \
{ \
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .address = add \
+ .address = addr \
}
static const struct iio_chan_spec hmc5843_channels[] = {
@@ -597,7 +590,6 @@ static const struct attribute_group hmc5843_group = {
static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
[HMC5843_ID] = {
.channels = hmc5843_channels,
- .num_channels = ARRAY_SIZE(hmc5843_channels),
.regval_to_sample_freq = hmc5843_regval_to_sample_freq,
.regval_to_input_field_mga =
hmc5843_regval_to_input_field_mga,
@@ -605,7 +597,6 @@ static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
},
[HMC5883_ID] = {
.channels = hmc5883_channels,
- .num_channels = ARRAY_SIZE(hmc5883_channels),
.regval_to_sample_freq = hmc5883_regval_to_sample_freq,
.regval_to_input_field_mga =
hmc5883_regval_to_input_field_mga,
@@ -613,7 +604,6 @@ static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
},
[HMC5883L_ID] = {
.channels = hmc5883_channels,
- .num_channels = ARRAY_SIZE(hmc5883_channels),
.regval_to_sample_freq = hmc5883_regval_to_sample_freq,
.regval_to_input_field_mga =
hmc5883l_regval_to_input_field_mga,
@@ -621,25 +611,6 @@ static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
},
};
-static int hmc5843_detect(struct i2c_client *client,
- struct i2c_board_info *info)
-{
- unsigned char id_str[HMC5843_ID_REG_LENGTH];
-
- if (client->addr != HMC5843_I2C_ADDRESS)
- return -ENODEV;
-
- if (i2c_smbus_read_i2c_block_data(client, HMC5843_ID_REG_A,
- HMC5843_ID_REG_LENGTH, id_str)
- != HMC5843_ID_REG_LENGTH)
- return -ENODEV;
-
- if (0 != strncmp(id_str, HMC5843_ID_STRING, HMC5843_ID_REG_LENGTH))
- return -ENODEV;
-
- return 0;
-}
-
/* Called when we have found a new HMC58X3 */
static void hmc5843_init_client(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -649,7 +620,7 @@ static void hmc5843_init_client(struct i2c_client *client,
data->variant = &hmc5843_chip_info_tbl[id->driver_data];
indio_dev->channels = data->variant->channels;
- indio_dev->num_channels = data->variant->num_channels;
+ indio_dev->num_channels = 3;
hmc5843_set_meas_conf(client, data->meas_conf);
hmc5843_set_rate(client, data->rate);
hmc5843_configure(client, data->operating_mode);
@@ -756,8 +727,6 @@ static struct i2c_driver hmc5843_driver = {
.id_table = hmc5843_id,
.probe = hmc5843_probe,
.remove = hmc5843_remove,
- .detect = hmc5843_detect,
- .address_list = normal_i2c,
};
module_i2c_driver(hmc5843_driver);
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
index e5943e2287c..74025fbae67 100644
--- a/drivers/staging/iio/meter/ade7753.c
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -225,21 +225,6 @@ static int ade7753_reset(struct device *dev)
return ade7753_spi_write_reg_16(dev, ADE7753_MODE, val);
}
-static ssize_t ade7753_write_reset(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- if (len < 1)
- return -1;
- switch (buf[0]) {
- case '1':
- case 'y':
- case 'Y':
- return ade7753_reset(dev);
- }
- return -1;
-}
-
static IIO_DEV_ATTR_AENERGY(ade7753_read_24bit, ADE7753_AENERGY);
static IIO_DEV_ATTR_LAENERGY(ade7753_read_24bit, ADE7753_LAENERGY);
static IIO_DEV_ATTR_VAENERGY(ade7753_read_24bit, ADE7753_VAENERGY);
@@ -458,8 +443,6 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
ade7753_read_frequency,
ade7753_write_frequency);
-static IIO_DEV_ATTR_RESET(ade7753_write_reset);
-
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
static struct attribute *ade7753_attributes[] = {
@@ -468,7 +451,6 @@ static struct attribute *ade7753_attributes[] = {
&iio_const_attr_in_temp_scale.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
&iio_dev_attr_phcal.dev_attr.attr,
&iio_dev_attr_cfden.dev_attr.attr,
&iio_dev_attr_aenergy.dev_attr.attr,
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
index 7b6503bf9a7..f649ebe55a0 100644
--- a/drivers/staging/iio/meter/ade7754.c
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -224,22 +224,6 @@ static int ade7754_reset(struct device *dev)
return ade7754_spi_write_reg_8(dev, ADE7754_OPMODE, val);
}
-
-static ssize_t ade7754_write_reset(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- if (len < 1)
- return -1;
- switch (buf[0]) {
- case '1':
- case 'y':
- case 'Y':
- return ade7754_reset(dev);
- }
- return -1;
-}
-
static IIO_DEV_ATTR_AENERGY(ade7754_read_24bit, ADE7754_AENERGY);
static IIO_DEV_ATTR_LAENERGY(ade7754_read_24bit, ADE7754_LAENERGY);
static IIO_DEV_ATTR_VAENERGY(ade7754_read_24bit, ADE7754_VAENERGY);
@@ -478,8 +462,6 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
ade7754_read_frequency,
ade7754_write_frequency);
-static IIO_DEV_ATTR_RESET(ade7754_write_reset);
-
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26000 13000 65000 33000");
static struct attribute *ade7754_attributes[] = {
@@ -488,7 +470,6 @@ static struct attribute *ade7754_attributes[] = {
&iio_const_attr_in_temp_scale.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
&iio_dev_attr_aenergy.dev_attr.attr,
&iio_dev_attr_laenergy.dev_attr.attr,
&iio_dev_attr_vaenergy.dev_attr.attr,
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index 8f5bcfab356..6005d4aab0c 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -313,21 +313,6 @@ static int ade7758_reset(struct device *dev)
return ret;
}
-static ssize_t ade7758_write_reset(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- if (len < 1)
- return -1;
- switch (buf[0]) {
- case '1':
- case 'y':
- case 'Y':
- return ade7758_reset(dev);
- }
- return len;
-}
-
static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
ade7758_read_8bit,
ade7758_write_8bit,
@@ -591,8 +576,6 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
ade7758_read_frequency,
ade7758_write_frequency);
-static IIO_DEV_ATTR_RESET(ade7758_write_reset);
-
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26040 13020 6510 3255");
static struct attribute *ade7758_attributes[] = {
@@ -601,7 +584,6 @@ static struct attribute *ade7758_attributes[] = {
&iio_const_attr_in_temp_scale.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
&iio_dev_attr_awatthr.dev_attr.attr,
&iio_dev_attr_bwatthr.dev_attr.attr,
&iio_dev_attr_cwatthr.dev_attr.attr,
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index b29e2d5d993..7d5db717557 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -54,7 +54,7 @@ out:
return ret;
}
-/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
+/* Whilst this makes a lot of calls to iio_sw_ring functions - it is too device
* specific to be rolled into the core.
*/
static irqreturn_t ade7758_trigger_handler(int irq, void *p)
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index 17dc373e108..d214ac4932c 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -229,21 +229,6 @@ static int ade7759_reset(struct device *dev)
return ret;
}
-static ssize_t ade7759_write_reset(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- if (len < 1)
- return -1;
- switch (buf[0]) {
- case '1':
- case 'y':
- case 'Y':
- return ade7759_reset(dev);
- }
- return -1;
-}
-
static IIO_DEV_ATTR_AENERGY(ade7759_read_40bit, ADE7759_AENERGY);
static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
ade7759_read_16bit,
@@ -418,8 +403,6 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
ade7759_read_frequency,
ade7759_write_frequency);
-static IIO_DEV_ATTR_RESET(ade7759_write_reset);
-
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
static struct attribute *ade7759_attributes[] = {
@@ -428,7 +411,6 @@ static struct attribute *ade7759_attributes[] = {
&iio_const_attr_in_temp_scale.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
&iio_dev_attr_phcal.dev_attr.attr,
&iio_dev_attr_cfden.dev_attr.attr,
&iio_dev_attr_aenergy.dev_attr.attr,
diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c
index c642da84842..e8379c0f117 100644
--- a/drivers/staging/iio/meter/ade7854.c
+++ b/drivers/staging/iio/meter/ade7854.c
@@ -186,22 +186,6 @@ static int ade7854_reset(struct device *dev)
return st->write_reg_16(dev, ADE7854_CONFIG, val);
}
-
-static ssize_t ade7854_write_reset(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- if (len < 1)
- return -1;
- switch (buf[0]) {
- case '1':
- case 'y':
- case 'Y':
- return ade7854_reset(dev);
- }
- return -1;
-}
-
static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO,
ade7854_read_24bit,
ade7854_write_24bit,
@@ -468,8 +452,6 @@ err_ret:
return ret;
}
-static IIO_DEV_ATTR_RESET(ade7854_write_reset);
-
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("8000");
static IIO_CONST_ATTR(name, "ade7854");
@@ -515,7 +497,6 @@ static struct attribute *ade7854_attributes[] = {
&iio_dev_attr_bvahr.dev_attr.attr,
&iio_dev_attr_cvahr.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
&iio_const_attr_name.dev_attr.attr,
&iio_dev_attr_vpeak.dev_attr.attr,
&iio_dev_attr_ipeak.dev_attr.attr,
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index 0d3356d4b7d..dcdadbbcf7e 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -192,21 +192,6 @@ static inline int ad2s1210_soft_reset(struct ad2s1210_state *st)
return ad2s1210_config_write(st, 0x0);
}
-static ssize_t ad2s1210_store_softreset(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
- int ret;
-
- mutex_lock(&st->lock);
- ret = ad2s1210_soft_reset(st);
- mutex_unlock(&st->lock);
-
- return ret < 0 ? ret : len;
-}
-
static ssize_t ad2s1210_show_fclkin(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -536,8 +521,6 @@ error_ret:
return ret;
}
-static IIO_DEVICE_ATTR(reset, S_IWUSR,
- NULL, ad2s1210_store_softreset, 0);
static IIO_DEVICE_ATTR(fclkin, S_IRUGO | S_IWUSR,
ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0);
static IIO_DEVICE_ATTR(fexcit, S_IRUGO | S_IWUSR,
@@ -587,7 +570,6 @@ static const struct iio_chan_spec ad2s1210_channels[] = {
};
static struct attribute *ad2s1210_attributes[] = {
- &iio_dev_attr_reset.dev_attr.attr,
&iio_dev_attr_fclkin.dev_attr.attr,
&iio_dev_attr_fexcit.dev_attr.attr,
&iio_dev_attr_control.dev_attr.attr,
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index 22339059837..394254f7d6b 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -15,7 +15,7 @@ config DRM_IMX_FB_HELPER
help
The DRM framework can provide a legacy /dev/fb0 framebuffer
for your device. This is necessary to get a framebuffer console
- and also for appplications using the legacy framebuffer API
+ and also for applications using the legacy framebuffer API
config DRM_IMX_PARALLEL_DISPLAY
tristate "Support for parallel displays"
@@ -32,8 +32,7 @@ config DRM_IMX_TVE
config DRM_IMX_LDB
tristate "Support for LVDS displays"
- depends on DRM_IMX
- select OF_VIDEOMODE
+ depends on DRM_IMX && MFD_SYSCON
help
Choose this to enable the internal LVDS Display Bridge (LDB)
found on i.MX53 and i.MX6 processors.
diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO
index f80641528f7..9cfa2a7efdc 100644
--- a/drivers/staging/imx-drm/TODO
+++ b/drivers/staging/imx-drm/TODO
@@ -10,7 +10,6 @@ TODO:
Missing features (not necessarily for moving out of staging):
- Add KMS plane support for CRTC driver
-- Add LDB (LVDS Display Bridge) support
- Add i.MX6 HDMI support
- Add support for IC (Image converter)
- Add support for CSI (CMOS Sensor interface)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 9854a1daf60..878f1688210 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -69,28 +69,20 @@ struct imx_drm_connector {
struct module *owner;
};
-static int imx_drm_driver_firstopen(struct drm_device *drm)
-{
- if (!imx_drm_device_get())
- return -EINVAL;
-
- return 0;
-}
-
static void imx_drm_driver_lastclose(struct drm_device *drm)
{
struct imx_drm_device *imxdrm = drm->dev_private;
if (imxdrm->fbhelper)
drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
-
- imx_drm_device_put();
}
static int imx_drm_driver_unload(struct drm_device *drm)
{
struct imx_drm_device *imxdrm = drm->dev_private;
+ imx_drm_device_put();
+
drm_mode_config_cleanup(imxdrm->drm);
drm_kms_helper_poll_fini(imxdrm->drm);
@@ -226,8 +218,6 @@ struct drm_device *imx_drm_device_get(void)
struct imx_drm_connector *con;
struct imx_drm_crtc *crtc;
- mutex_lock(&imxdrm->mutex);
-
list_for_each_entry(enc, &imxdrm->encoder_list, list) {
if (!try_module_get(enc->owner)) {
dev_err(imxdrm->dev, "could not get module %s\n",
@@ -254,8 +244,6 @@ struct drm_device *imx_drm_device_get(void)
imxdrm->references++;
- mutex_unlock(&imxdrm->mutex);
-
return imxdrm->drm;
unwind_crtc:
@@ -447,6 +435,9 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
*/
imxdrm->drm->vblank_disable_allowed = 1;
+ if (!imx_drm_device_get())
+ ret = -EINVAL;
+
ret = 0;
err_init:
@@ -678,6 +669,7 @@ found:
return i;
}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
/*
* imx_drm_remove_encoder - remove an encoder
@@ -791,7 +783,6 @@ static struct drm_driver imx_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM,
.load = imx_drm_driver_load,
.unload = imx_drm_driver_unload,
- .firstopen = imx_drm_driver_firstopen,
.lastclose = imx_drm_driver_lastclose,
.gem_free_object = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 8af7f3b40ba..af733ea4856 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -497,7 +497,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
imx_ldb->ldb_ctrl |= LDB_SPLIT_MODE_EN;
/*
- * There are three diferent possible clock mux configurations:
+ * There are three different possible clock mux configurations:
* i.MX53: ipu1_di0_sel, ipu1_di1_sel
* i.MX6q: ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, ipu2_di1_sel
* i.MX6dl: ipu1_di0_sel, ipu1_di1_sel, lcdif_sel
@@ -623,3 +623,4 @@ module_platform_driver(imx_ldb_driver);
MODULE_DESCRIPTION("i.MX LVDS driver");
MODULE_AUTHOR("Sascha Hauer, Pengutronix");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index a56797d88ed..3c024b40b4f 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -131,12 +131,14 @@ struct imx_tve {
};
static void tve_lock(void *__tve)
+__acquires(&tve->lock)
{
struct imx_tve *tve = __tve;
spin_lock(&tve->lock);
}
static void tve_unlock(void *__tve)
+__releases(&tve->lock)
{
struct imx_tve *tve = __tve;
spin_unlock(&tve->lock);
@@ -164,7 +166,10 @@ static void tve_enable(struct imx_tve *tve)
regmap_write(tve->regmap, TVE_INT_CONT_REG, 0);
else
regmap_write(tve->regmap, TVE_INT_CONT_REG,
- TVE_CD_SM_IEN | TVE_CD_LM_IEN | TVE_CD_MON_END_IEN);
+ TVE_CD_SM_IEN |
+ TVE_CD_LM_IEN |
+ TVE_CD_MON_END_IEN);
+
spin_unlock_irqrestore(&tve->enable_lock, flags);
}
@@ -465,7 +470,9 @@ static int clk_tve_di_set_rate(struct clk_hw *hw, unsigned long rate,
else
val = TVE_DAC_FULL_RATE;
- ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, TVE_DAC_SAMP_RATE_MASK, val);
+ ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
+ TVE_DAC_SAMP_RATE_MASK, val);
+
if (ret < 0) {
dev_err(tve->dev, "failed to set divider: %d\n", ret);
return ret;
@@ -609,13 +616,17 @@ static int imx_tve_probe(struct platform_device *pdev)
}
if (tve->mode == TVE_MODE_VGA) {
- ret = of_property_read_u32(np, "fsl,hsync-pin", &tve->hsync_pin);
+ ret = of_property_read_u32(np, "fsl,hsync-pin",
+ &tve->hsync_pin);
+
if (ret < 0) {
dev_err(&pdev->dev, "failed to get vsync pin\n");
return ret;
}
- ret |= of_property_read_u32(np, "fsl,vsync-pin", &tve->vsync_pin);
+ ret |= of_property_read_u32(np, "fsl,vsync-pin",
+ &tve->vsync_pin);
+
if (ret < 0) {
dev_err(&pdev->dev, "failed to get vsync pin\n");
return ret;
@@ -623,11 +634,6 @@ static int imx_tve_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "failed to get memory region\n");
- return -ENOENT;
- }
-
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -743,3 +749,4 @@ module_platform_driver(imx_tve_driver);
MODULE_DESCRIPTION("i.MX Television Encoder driver");
MODULE_AUTHOR("Philipp Zabel, Pengutronix");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-tve");
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index e35d0bf03c7..ba464e5d9f1 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -1075,21 +1075,23 @@ static int ipu_probe(struct platform_device *pdev)
ipu->cpmem_base = devm_ioremap(&pdev->dev,
ipu_base + devtype->cpmem_ofs, PAGE_SIZE);
- if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base) {
- ret = -ENOMEM;
- goto failed_ioremap;
- }
+ if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base)
+ return -ENOMEM;
ipu->clk = devm_clk_get(&pdev->dev, "bus");
if (IS_ERR(ipu->clk)) {
ret = PTR_ERR(ipu->clk);
dev_err(&pdev->dev, "clk_get failed with %d", ret);
- goto failed_clk_get;
+ return ret;
}
platform_set_drvdata(pdev, ipu);
- clk_prepare_enable(ipu->clk);
+ ret = clk_prepare_enable(ipu->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
ipu->dev = &pdev->dev;
ipu->irq_sync = irq_sync;
@@ -1134,8 +1136,6 @@ out_failed_reset:
ipu_irq_exit(ipu);
out_failed_irq:
clk_disable_unprepare(ipu->clk);
-failed_clk_get:
-failed_ioremap:
return ret;
}
@@ -1163,6 +1163,7 @@ static struct platform_driver imx_ipu_driver = {
module_platform_driver(imx_ipu_driver);
+MODULE_ALIAS("platform:imx-ipuv3");
MODULE_DESCRIPTION("i.MX IPU v3 driver");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
index 59f03f9aefc..21bf1c80652 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
@@ -161,14 +161,15 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
u32 pixel_fmt, u32 width)
{
struct ipu_dc_priv *priv = dc->priv;
- u32 reg = 0, map;
+ u32 reg = 0;
+ int map;
dc->di = ipu_di_get_num(di);
map = ipu_pixfmt_to_map(pixel_fmt);
if (map < 0) {
dev_dbg(priv->dev, "IPU_DISP: No MAP\n");
- return -EINVAL;
+ return map;
}
if (interlaced) {
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 0b6806e2069..948a49b289e 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -654,7 +654,9 @@ EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
int ipu_di_enable(struct ipu_di *di)
{
- clk_prepare_enable(di->clk_di_pixel);
+ int ret = clk_prepare_enable(di->clk_di_pixel);
+ if (ret)
+ return ret;
ipu_module_enable(di->ipu, di->module);
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
index 113b046c022..231afd6c60f 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
@@ -46,6 +46,8 @@
#define DP_COM_CONF_CSC_DEF_BG (2 << 8)
#define DP_COM_CONF_CSC_DEF_BOTH (1 << 8)
+#define IPUV3_NUM_FLOWS 3
+
struct ipu_dp_priv;
struct ipu_dp {
@@ -67,7 +69,7 @@ struct ipu_dp_priv {
struct ipu_soc *ipu;
struct device *dev;
void __iomem *base;
- struct ipu_flow flow[3];
+ struct ipu_flow flow[IPUV3_NUM_FLOWS];
struct mutex mutex;
int use_count;
};
@@ -280,7 +282,7 @@ struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
struct ipu_dp_priv *priv = ipu->dp_priv;
struct ipu_dp *dp;
- if (flow > 5)
+ if ((flow >> 1) >= IPUV3_NUM_FLOWS)
return ERR_PTR(-EINVAL);
if (flow & 1)
@@ -309,19 +311,20 @@ int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
int i;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
priv->dev = dev;
priv->ipu = ipu;
ipu->dp_priv = priv;
priv->base = devm_ioremap(dev, base, PAGE_SIZE);
- if (!priv->base) {
+ if (!priv->base)
return -ENOMEM;
- }
mutex_init(&priv->mutex);
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
priv->flow[i].foreground.foreground = 1;
priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
priv->flow[i].priv = priv;
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 9176a8171e6..bae0e2e8191 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -562,3 +562,4 @@ module_platform_driver(ipu_drm_driver);
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-ipuv3-crtc");
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index cea9f14fff4..24aa9beedcf 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -272,3 +272,4 @@ module_platform_driver(imx_pd_driver);
MODULE_DESCRIPTION("i.MX parallel display driver");
MODULE_AUTHOR("Sascha Hauer, Pengutronix");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-parallel-display");
diff --git a/drivers/staging/keucr/scsiglue.c b/drivers/staging/keucr/scsiglue.c
index afb00d84679..ac3d34dcc43 100644
--- a/drivers/staging/keucr/scsiglue.c
+++ b/drivers/staging/keucr/scsiglue.c
@@ -289,10 +289,7 @@ US_DO_ALL_FLAGS
***********************************************************************/
/* Output routine for the sysfs max_sectors file */
-/*
- * show_max_sectors()
- */
-static ssize_t show_max_sectors(struct device *dev,
+static ssize_t max_sectors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -302,10 +299,7 @@ static ssize_t show_max_sectors(struct device *dev,
}
/* Input routine for the sysfs max_sectors file */
-/*
- * store_max_sectors()
- */
-static ssize_t store_max_sectors(struct device *dev,
+static ssize_t max_sectors_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -319,9 +313,8 @@ static ssize_t store_max_sectors(struct device *dev,
}
return -EINVAL;
}
+static DEVICE_ATTR_RW(max_sectors);
-static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors,
- store_max_sectors);
static struct device_attribute *sysfs_device_attr_list[] = {
&dev_attr_max_sectors, NULL,
};
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index 6252aca8286..471c10c116e 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -568,15 +568,6 @@ ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr,
}
/*
- No operation (i.e., unsupported).
-*/
-ssize_t line6_nop_write(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return count;
-}
-
-/*
Generic destructor.
*/
static void line6_destruct(struct usb_interface *interface)
diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h
index a8341f9fdb9..34ae95e7e51 100644
--- a/drivers/staging/line6/driver.h
+++ b/drivers/staging/line6/driver.h
@@ -190,9 +190,6 @@ extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
int code2, int size);
extern ssize_t line6_nop_read(struct device *dev,
struct device_attribute *attr, char *buf);
-extern ssize_t line6_nop_write(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count);
extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
size_t datalen);
extern int line6_read_serial_number(struct usb_line6 *line6,
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
index 0dd08ef5139..6a0648cd03a 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -34,8 +34,8 @@ static struct snd_line6_pcm *dev2pcm(struct device *dev)
/*
"read" request on "impulse_volume" special file.
*/
-static ssize_t pcm_get_impulse_volume(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t impulse_volume_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
}
@@ -43,9 +43,9 @@ static ssize_t pcm_get_impulse_volume(struct device *dev,
/*
"write" request on "impulse_volume" special file.
*/
-static ssize_t pcm_set_impulse_volume(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t impulse_volume_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct snd_line6_pcm *line6pcm = dev2pcm(dev);
int value;
@@ -64,12 +64,13 @@ static ssize_t pcm_set_impulse_volume(struct device *dev,
return count;
}
+static DEVICE_ATTR_RW(impulse_volume);
/*
"read" request on "impulse_period" special file.
*/
-static ssize_t pcm_get_impulse_period(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t impulse_period_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
}
@@ -77,9 +78,9 @@ static ssize_t pcm_get_impulse_period(struct device *dev,
/*
"write" request on "impulse_period" special file.
*/
-static ssize_t pcm_set_impulse_period(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t impulse_period_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int value;
int ret;
@@ -91,11 +92,7 @@ static ssize_t pcm_set_impulse_period(struct device *dev,
dev2pcm(dev)->impulse_period = value;
return count;
}
-
-static DEVICE_ATTR(impulse_volume, S_IWUSR | S_IRUGO, pcm_get_impulse_volume,
- pcm_set_impulse_volume);
-static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period,
- pcm_set_impulse_period);
+static DEVICE_ATTR_RW(impulse_period);
#endif
diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c
index 699b2172506..f4e95a614e3 100644
--- a/drivers/staging/line6/pod.c
+++ b/drivers/staging/line6/pod.c
@@ -192,8 +192,8 @@ static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
/*
"read" request on "serial_number" special file.
*/
-static ssize_t pod_get_serial_number(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t serial_number_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_interface *interface = to_usb_interface(dev);
struct usb_line6_pod *pod = usb_get_intfdata(interface);
@@ -203,9 +203,8 @@ static ssize_t pod_get_serial_number(struct device *dev,
/*
"read" request on "firmware_version" special file.
*/
-static ssize_t pod_get_firmware_version(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t firmware_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_interface *interface = to_usb_interface(dev);
struct usb_line6_pod *pod = usb_get_intfdata(interface);
@@ -216,8 +215,8 @@ static ssize_t pod_get_firmware_version(struct device *dev,
/*
"read" request on "device_id" special file.
*/
-static ssize_t pod_get_device_id(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t device_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_interface *interface = to_usb_interface(dev);
struct usb_line6_pod *pod = usb_get_intfdata(interface);
@@ -274,11 +273,9 @@ static void pod_startup4(struct work_struct *work)
}
/* POD special files: */
-static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
-static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
- line6_nop_write);
-static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
- line6_nop_write);
+static DEVICE_ATTR_RO(device_id);
+static DEVICE_ATTR_RO(firmware_version);
+static DEVICE_ATTR_RO(serial_number);
/* control info callback */
static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
diff --git a/drivers/staging/lustre/Makefile b/drivers/staging/lustre/Makefile
index 26162893fd2..fb0e0faf076 100644
--- a/drivers/staging/lustre/Makefile
+++ b/drivers/staging/lustre/Makefile
@@ -1,4 +1,4 @@
subdir-ccflags-y := -I$(src)/include/
-obj-$(CONFIG_LUSTRE_FS) += lustre/
obj-$(CONFIG_LNET) += lnet/
+obj-$(CONFIG_LUSTRE_FS) += lustre/
diff --git a/drivers/staging/lustre/include/linux/libcfs/bitmap.h b/drivers/staging/lustre/include/linux/libcfs/bitmap.h
index 3f1c37b4bb7..f3d4a896a75 100644
--- a/drivers/staging/lustre/include/linux/libcfs/bitmap.h
+++ b/drivers/staging/lustre/include/linux/libcfs/bitmap.h
@@ -52,11 +52,11 @@ cfs_bitmap_t *CFS_ALLOCATE_BITMAP(int size)
OBD_ALLOC(ptr, CFS_BITMAP_SIZE(size));
if (ptr == NULL)
- RETURN(ptr);
+ return ptr;
ptr->size = size;
- RETURN (ptr);
+ return ptr;
}
#define CFS_FREE_BITMAP(ptr) OBD_FREE(ptr, CFS_BITMAP_SIZE(ptr->size))
diff --git a/drivers/staging/lustre/include/linux/libcfs/curproc.h b/drivers/staging/lustre/include/linux/libcfs/curproc.h
index 90d7ce630e9..de8e35b796a 100644
--- a/drivers/staging/lustre/include/linux/libcfs/curproc.h
+++ b/drivers/staging/lustre/include/linux/libcfs/curproc.h
@@ -49,8 +49,6 @@
* Implemented in portals/include/libcfs/<os>/
*/
int cfs_curproc_groups_nr(void);
-int current_is_in_group(gid_t group);
-void cfs_curproc_groups_dump(gid_t *array, int size);
/*
* Plus, platform-specific constant
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
index 1ab1f2be9aa..687dbab2c4e 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
@@ -80,26 +80,10 @@ static inline int __is_po2(unsigned long long val)
#define LERRCHKSUM(hexnum) (((hexnum) & 0xf) ^ ((hexnum) >> 4 & 0xf) ^ \
((hexnum) >> 8 & 0xf))
-
-/*
- * Some (nomina odiosa sunt) platforms define NULL as naked 0. This confuses
- * Lustre RETURN(NULL) macro.
- */
-#if defined(NULL)
-#undef NULL
-#endif
-
-#define NULL ((void *)0)
-
#define LUSTRE_SRV_LNET_PID LUSTRE_LNET_PID
-
#include <linux/list.h>
-#ifndef cfs_for_each_possible_cpu
-# error cfs_for_each_possible_cpu is not supported by kernel!
-#endif
-
/* libcfs tcpip */
int libcfs_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask);
int libcfs_ipif_enumerate(char ***names);
@@ -117,31 +101,6 @@ int libcfs_sock_write(socket_t *sock, void *buffer, int nob, int timeout);
int libcfs_sock_read(socket_t *sock, void *buffer, int nob, int timeout);
void libcfs_sock_release(socket_t *sock);
-/* libcfs watchdogs */
-struct lc_watchdog;
-
-/* Add a watchdog which fires after "time" milliseconds of delay. You have to
- * touch it once to enable it. */
-struct lc_watchdog *lc_watchdog_add(int time,
- void (*cb)(pid_t pid, void *),
- void *data);
-
-/* Enables a watchdog and resets its timer. */
-void lc_watchdog_touch(struct lc_watchdog *lcw, int timeout);
-#define CFS_GET_TIMEOUT(svc) (max_t(int, obd_timeout, \
- AT_OFF ? 0 : at_get(&svc->srv_at_estimate)) * \
- svc->srv_watchdog_factor)
-
-/* Disable a watchdog; touch it to restart it. */
-void lc_watchdog_disable(struct lc_watchdog *lcw);
-
-/* Clean up the watchdog */
-void lc_watchdog_delete(struct lc_watchdog *lcw);
-
-/* Dump a debug log */
-void lc_watchdog_dumplog(pid_t pid, void *data);
-
-
/* need both kernel and user-land acceptor */
#define LNET_ACCEPTOR_MIN_RESERVED_PORT 512
#define LNET_ACCEPTOR_MAX_RESERVED_PORT 1023
@@ -149,11 +108,6 @@ void lc_watchdog_dumplog(pid_t pid, void *data);
/*
* libcfs pseudo device operations
*
- * struct psdev_t and
- * misc_register() and
- * misc_deregister() are declared in
- * libcfs/<os>/<os>-prim.h
- *
* It's just draft now.
*/
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h
index 6ae7415a3b9..c87efb49ebc 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h
@@ -75,11 +75,19 @@
#ifndef __LIBCFS_CPU_H__
#define __LIBCFS_CPU_H__
-#ifndef HAVE_LIBCFS_CPT
-
-typedef unsigned long cpumask_t;
-typedef unsigned long nodemask_t;
+/* any CPU partition */
+#define CFS_CPT_ANY (-1)
+#ifdef CONFIG_SMP
+/**
+ * return cpumask of CPU partition \a cpt
+ */
+cpumask_t *cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt);
+/**
+ * print string information of cpt-table
+ */
+int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len);
+#else /* !CONFIG_SMP */
struct cfs_cpt_table {
/* # of CPU partitions */
int ctb_nparts;
@@ -91,10 +99,18 @@ struct cfs_cpt_table {
__u64 ctb_version;
};
-#endif /* !HAVE_LIBCFS_CPT */
+static inline cpumask_t *
+cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt)
+{
+ return NULL;
+}
-/* any CPU partition */
-#define CFS_CPT_ANY (-1)
+static inline int
+cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len)
+{
+ return 0;
+}
+#endif /* CONFIG_SMP */
extern struct cfs_cpt_table *cfs_cpt_table;
@@ -107,10 +123,6 @@ void cfs_cpt_table_free(struct cfs_cpt_table *cptab);
*/
struct cfs_cpt_table *cfs_cpt_table_alloc(unsigned int ncpt);
/**
- * print string information of cpt-table
- */
-int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len);
-/**
* return total number of CPU partitions in \a cptab
*/
int
@@ -124,10 +136,6 @@ int cfs_cpt_weight(struct cfs_cpt_table *cptab, int cpt);
*/
int cfs_cpt_online(struct cfs_cpt_table *cptab, int cpt);
/**
- * return cpumask of CPU partition \a cpt
- */
-cpumask_t *cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt);
-/**
* return nodemask of CPU partition \a cpt
*/
nodemask_t *cfs_cpt_nodemask(struct cfs_cpt_table *cptab, int cpt);
@@ -200,14 +208,6 @@ int cfs_cpt_spread_node(struct cfs_cpt_table *cptab, int cpt);
#define cfs_cpt_for_each(i, cptab) \
for (i = 0; i < cfs_cpt_number(cptab); i++)
-#ifndef __read_mostly
-# define __read_mostly
-#endif
-
-#ifndef ____cacheline_aligned
-#define ____cacheline_aligned
-#endif
-
int cfs_cpu_init(void);
void cfs_cpu_fini(void);
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h
index 64ca62f0cc9..776e9c0e48c 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h
@@ -136,13 +136,13 @@ int cfs_crypto_hash_digest(unsigned char alg,
/* cfs crypto hash descriptor */
struct cfs_crypto_hash_desc;
-/** Allocate and initialize desriptor for hash algorithm.
+/** Allocate and initialize descriptor for hash algorithm.
* @param alg algorithm id
* @param key initial value for algorithm, if it is NULL,
* default initial value should be used.
* @param key_len len of initial value
* @returns pointer to descriptor of hash instance
- * @retval ERR_PTR(error) when errors occured.
+ * @retval ERR_PTR(error) when errors occurred.
*/
struct cfs_crypto_hash_desc*
cfs_crypto_hash_init(unsigned char alg,
@@ -175,7 +175,7 @@ int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *desc, const void *buf,
* @param desc hash descriptor
* @param hash buffer pointer to store hash digest
* @param hash_len pointer to hash buffer size, if NULL
- * destory hash descriptor
+ * destroy hash descriptor
* @returns status of operation
* @retval -ENOSPC if hash is NULL, or *hash_len less than
* digest size
@@ -195,7 +195,7 @@ int cfs_crypto_register(void);
void cfs_crypto_unregister(void);
/** Return hash speed in Mbytes per second for valid hash algorithm
- * identifier. If test was unsuccessfull -1 would be return.
+ * identifier. If test was unsuccessful -1 would be returned.
*/
int cfs_crypto_hash_speed(unsigned char hash_alg);
#endif
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
index dd8ac2f52c9..e6439d19f3e 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
@@ -262,74 +262,6 @@ do { \
} while (0)
-/*
- * if rc == NULL, we need to code as RETURN((void *)NULL), otherwise
- * there will be a warning in osx.
- */
-#if defined(__GNUC__)
-
-long libcfs_log_return(struct libcfs_debug_msg_data *, long rc);
-#if BITS_PER_LONG > 32
-#define RETURN(rc) \
-do { \
- EXIT_NESTING; \
- if (cfs_cdebug_show(D_TRACE, DEBUG_SUBSYSTEM)) { \
- LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, D_TRACE, NULL); \
- return (typeof(rc))libcfs_log_return(&msgdata, \
- (long)(rc)); \
- } \
- \
- return (rc); \
-} while (0)
-#else /* BITS_PER_LONG == 32 */
-/* We need an on-stack variable, because we cannot case a 32-bit pointer
- * directly to (long long) without generating a complier warning/error, yet
- * casting directly to (long) will truncate 64-bit return values. The log
- * values will print as 32-bit values, but they always have been. LU-1436
- */
-#define RETURN(rc) \
-do { \
- EXIT_NESTING; \
- if (cfs_cdebug_show(D_TRACE, DEBUG_SUBSYSTEM)) { \
- typeof(rc) __rc = (rc); \
- LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, D_TRACE, NULL); \
- libcfs_log_return(&msgdata, (long_ptr_t)__rc); \
- return __rc; \
- } \
- \
- return (rc); \
-} while (0)
-#endif /* BITS_PER_LONG > 32 */
-
-#elif defined(_MSC_VER)
-#define RETURN(rc) \
-do { \
- CDEBUG(D_TRACE, "Process leaving.\n"); \
- EXIT_NESTING; \
- return (rc); \
-} while (0)
-#else
-# error "Unkown compiler"
-#endif /* __GNUC__ */
-
-#define ENTRY \
-ENTRY_NESTING; \
-do { \
- CDEBUG(D_TRACE, "Process entered\n"); \
-} while (0)
-
-#define EXIT \
-do { \
- CDEBUG(D_TRACE, "Process leaving\n"); \
- EXIT_NESTING; \
-} while(0)
-
-#define RETURN_EXIT \
-do { \
- EXIT; \
- return; \
-} while (0)
-
extern int libcfs_debug_msg(struct libcfs_debug_msg_data *msgdata,
const char *format1, ...)
__attribute__ ((format (printf, 2, 3)));
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
index f6361b3f0a0..98f5be243c8 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
@@ -720,7 +720,7 @@ __u64 cfs_hash_size_get(cfs_hash_t *hs);
/*
* Rehash - Theta is calculated to be the average chained
- * hash depth assuming a perfectly uniform hash funcion.
+ * hash depth assuming a perfectly uniform hash function.
*/
void cfs_hash_rehash_cancel_locked(cfs_hash_t *hs);
void cfs_hash_rehash_cancel(cfs_hash_t *hs);
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h
index 9c40ed904da..e6e417aeefd 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h
@@ -40,10 +40,6 @@
#ifndef __LIBCFS_PRIM_H__
#define __LIBCFS_PRIM_H__
-#ifndef EXPORT_SYMBOL
-# define EXPORT_SYMBOL(s)
-#endif
-
/*
* Schedule
*/
@@ -53,20 +49,20 @@ void cfs_pause(cfs_duration_t ticks);
* Timer
*/
typedef void (cfs_timer_func_t)(ulong_ptr_t);
-void schedule_timeout_and_set_state(cfs_task_state_t, int64_t);
+void schedule_timeout_and_set_state(long, int64_t);
void init_waitqueue_entry_current(wait_queue_t *link);
-int64_t waitq_timedwait(wait_queue_t *, cfs_task_state_t, int64_t);
-void waitq_wait(wait_queue_t *, cfs_task_state_t);
+int64_t waitq_timedwait(wait_queue_t *, long, int64_t);
+void waitq_wait(wait_queue_t *, long);
void add_wait_queue_exclusive_head(wait_queue_head_t *, wait_queue_t *);
-void cfs_init_timer(timer_list_t *t);
-void cfs_timer_init(timer_list_t *t, cfs_timer_func_t *func, void *arg);
-void cfs_timer_done(timer_list_t *t);
-void cfs_timer_arm(timer_list_t *t, cfs_time_t deadline);
-void cfs_timer_disarm(timer_list_t *t);
-int cfs_timer_is_armed(timer_list_t *t);
-cfs_time_t cfs_timer_deadline(timer_list_t *t);
+void cfs_init_timer(struct timer_list *t);
+void cfs_timer_init(struct timer_list *t, cfs_timer_func_t *func, void *arg);
+void cfs_timer_done(struct timer_list *t);
+void cfs_timer_arm(struct timer_list *t, cfs_time_t deadline);
+void cfs_timer_disarm(struct timer_list *t);
+int cfs_timer_is_armed(struct timer_list *t);
+cfs_time_t cfs_timer_deadline(struct timer_list *t);
/*
* Memory
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
index 056caa46712..d0d942ced01 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
@@ -210,7 +210,6 @@ do { \
#define ntohs(x) ___ntohs(x)
#endif
-void libcfs_debug_dumpstack(task_t *tsk);
void libcfs_run_upcall(char **argv);
void libcfs_run_lbug_upcall(struct libcfs_debug_msg_data *);
void libcfs_debug_dumplog(void);
@@ -230,7 +229,7 @@ void libcfs_debug_set_level(unsigned int debug_level);
*/
void *cfs_percpt_alloc(struct cfs_cpt_table *cptab, unsigned int size);
/*
- * destory per-cpu-partition variable
+ * destroy per-cpu-partition variable
*/
void cfs_percpt_free(void *vars);
int cfs_percpt_number(void *vars);
@@ -456,10 +455,6 @@ int cfs_match_nid(lnet_nid_t nid, struct list_head *list);
/* logical equivalence */
#define equi(a, b) (!!(a) == !!(b))
-#ifndef CFS_CURRENT_TIME
-# define CFS_CURRENT_TIME time(0)
-#endif
-
/* --------------------------------------------------------------------
* Light-weight trace
* Support for temporary event tracing with minimal Heisenberg effect.
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/kp30.h b/drivers/staging/lustre/include/linux/libcfs/linux/kp30.h
index 4b7ae1c5bd3..c204b677796 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/kp30.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/kp30.h
@@ -55,7 +55,6 @@
#include <linux/interrupt.h>
#include <linux/highmem.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <linux/rwsem.h>
@@ -74,34 +73,6 @@
#include <linux/libcfs/linux/portals_compat25.h>
-#define prepare_work(wq,cb,cbdata) \
-do { \
- INIT_WORK((wq), (void *)(cb)); \
-} while (0)
-
-#define cfs_get_work_data(type,field,data) container_of(data,type,field)
-
-
-#define our_recalc_sigpending(current) recalc_sigpending()
-#define strtok(a,b) strpbrk(a, b)
-#define work_struct_t struct work_struct
-
-#ifdef CONFIG_SMP
-#else
-#endif
-
-
-#define SEM_COUNT(sem) ((sem)->count)
-
-
-/* ------------------------------------------------------------------- */
-
-#define PORTAL_SYMBOL_REGISTER(x)
-#define PORTAL_SYMBOL_UNREGISTER(x)
-
-
-
-
/******************************************************************************/
/* Module parameter support */
#define CFS_MODULE_PARM(name, t, type, perm, desc) \
@@ -111,26 +82,6 @@ do { \
#define CFS_SYSFS_MODULE_PARM 1 /* module parameters accessible via sysfs */
/******************************************************************************/
-
-#if (__GNUC__)
-/* Use the special GNU C __attribute__ hack to have the compiler check the
- * printf style argument string against the actual argument count and
- * types.
- */
-#ifdef printf
-# warning printf has been defined as a macro...
-# undef printf
-#endif
-
-#endif /* __GNUC__ */
-
-# define fprintf(a, format, b...) CDEBUG(D_OTHER, format , ## b)
-# define printf(format, b...) CDEBUG(D_OTHER, format , ## b)
-# define time(a) CURRENT_TIME
-
-# define cfs_num_present_cpus() num_present_cpus()
-
-/******************************************************************************/
/* Light-weight trace
* Support for temporary event tracing with minimal Heisenberg effect. */
#define LWT_SUPPORT 0
@@ -236,9 +187,13 @@ extern int lwt_snapshot (cfs_cycles_t *now, int *ncpu, int *total_size,
# endif
#endif
-# define LI_POISON ((int)0x5a5a5a5a5a5a5a5a)
-# define LL_POISON ((long)0x5a5a5a5a5a5a5a5a)
-# define LP_POISON ((void *)(long)0x5a5a5a5a5a5a5a5a)
+# define LI_POISON 0x5a5a5a5a
+#if BITS_PER_LONG > 32
+# define LL_POISON 0x5a5a5a5a5a5a5a5aL
+#else
+# define LL_POISON 0x5a5a5a5aL
+#endif
+# define LP_POISON ((void *)LL_POISON)
/* this is a bit chunky */
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h
index 292a3ba1fb9..60ecaf63f9f 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h
@@ -97,9 +97,6 @@ do { \
/* initial pid */
#define LUSTRE_LNET_PID 12345
-#define ENTRY_NESTING_SUPPORT (1)
-#define ENTRY_NESTING do {;} while (0)
-#define EXIT_NESTING do {;} while (0)
#define __current_nesting_level() (0)
/**
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-cpu.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-cpu.h
index 224371c92f7..8dd354d5160 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-cpu.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-cpu.h
@@ -46,8 +46,6 @@
#include <linux/cpu.h>
#include <linux/cpuset.h>
#include <linux/topology.h>
-#include <linux/version.h>
-
#ifdef CONFIG_SMP
@@ -81,15 +79,8 @@ struct cfs_cpt_table {
nodemask_t *ctb_nodemask;
};
-void cfs_cpu_core_siblings(int cpu, cpumask_t *mask);
-void cfs_cpu_ht_siblings(int cpu, cpumask_t *mask);
-void cfs_node_to_cpumask(int node, cpumask_t *mask);
-int cfs_cpu_core_nsiblings(int cpu);
-int cfs_cpu_ht_nsiblings(int cpu);
-
/**
* comment out definitions for compatible layer
- * #define CFS_CPU_NR NR_CPUS
*
* typedef cpumask_t cfs_cpumask_t;
*
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h
index 6fbcbf3ab0d..d6e00f92e4a 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h
@@ -52,7 +52,7 @@
* IMPORTANT !!!!!!!!
*
* All locks' declaration are not guaranteed to be initialized,
- * Althought some of they are initialized in Linux. All locks
+ * although some of them are initialized in Linux. All locks
* declared by CFS_DECL_* should be initialized explicitly.
*/
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h
index 042a2bc432b..63efb7b456c 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h
@@ -63,9 +63,9 @@
#if BITS_PER_LONG == 32
/* limit to lowmem on 32-bit systems */
#define NUM_CACHEPAGES \
- min(num_physpages, 1UL << (30 - PAGE_CACHE_SHIFT) * 3 / 4)
+ min(totalram_pages, 1UL << (30 - PAGE_CACHE_SHIFT) * 3 / 4)
#else
-#define NUM_CACHEPAGES num_physpages
+#define NUM_CACHEPAGES totalram_pages
#endif
/*
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-prim.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-prim.h
index a4963a8dfdd..1ec4ca1a6e3 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-prim.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-prim.h
@@ -49,7 +49,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/proc_fs.h>
#include <linux/mm.h>
#include <linux/timer.h>
@@ -64,43 +63,12 @@
#include <linux/libcfs/linux/linux-time.h>
-
-/*
- * CPU
- */
-#ifdef for_each_possible_cpu
-#define cfs_for_each_possible_cpu(cpu) for_each_possible_cpu(cpu)
-#elif defined(for_each_cpu)
-#define cfs_for_each_possible_cpu(cpu) for_each_cpu(cpu)
-#endif
-
-#ifdef NR_CPUS
-#else
-#define NR_CPUS 1
-#endif
-
-/*
- * cache
- */
-
-/*
- * IRQs
- */
-
-
-/*
- * Pseudo device register
- */
-typedef struct miscdevice psdev_t;
-
/*
* Sysctl register
*/
typedef struct ctl_table ctl_table_t;
typedef struct ctl_table_header ctl_table_header_t;
-#define cfs_register_sysctl_table(t, a) register_sysctl_table(t)
-
#define DECLARE_PROC_HANDLER(name) \
static int \
LL_PROC_PROTO(name) \
@@ -112,130 +80,4 @@ LL_PROC_PROTO(name) \
__##name); \
}
-/*
- * Symbol register
- */
-#define cfs_symbol_register(s, p) do {} while(0)
-#define cfs_symbol_unregister(s) do {} while(0)
-#define cfs_symbol_get(s) symbol_get(s)
-#define cfs_symbol_put(s) symbol_put(s)
-
-typedef struct module module_t;
-
-/*
- * Proc file system APIs
- */
-typedef struct proc_dir_entry proc_dir_entry_t;
-
-/*
- * Wait Queue
- */
-
-
-typedef long cfs_task_state_t;
-
-#define CFS_DECL_WAITQ(wq) DECLARE_WAIT_QUEUE_HEAD(wq)
-
-/*
- * Task struct
- */
-typedef struct task_struct task_t;
-#define DECL_JOURNAL_DATA void *journal_info
-#define PUSH_JOURNAL do { \
- journal_info = current->journal_info; \
- current->journal_info = NULL; \
- } while(0)
-#define POP_JOURNAL do { \
- current->journal_info = journal_info; \
- } while(0)
-
-/* Module interfaces */
-#define cfs_module(name, version, init, fini) \
- module_init(init); \
- module_exit(fini)
-
-/*
- * Signal
- */
-
-/*
- * Timer
- */
-typedef struct timer_list timer_list_t;
-
-
-#ifndef wait_event_timeout /* Only for RHEL3 2.4.21 kernel */
-#define __wait_event_timeout(wq, condition, timeout, ret) \
-do { \
- int __ret = 0; \
- if (!(condition)) { \
- wait_queue_t __wait; \
- unsigned long expire; \
- \
- init_waitqueue_entry(&__wait, current); \
- expire = timeout + jiffies; \
- add_wait_queue(&wq, &__wait); \
- for (;;) { \
- set_current_state(TASK_UNINTERRUPTIBLE); \
- if (condition) \
- break; \
- if (jiffies > expire) { \
- ret = jiffies - expire; \
- break; \
- } \
- schedule_timeout(timeout); \
- } \
- current->state = TASK_RUNNING; \
- remove_wait_queue(&wq, &__wait); \
- } \
-} while (0)
-/*
- retval == 0; condition met; we're good.
- retval > 0; timed out.
-*/
-#define cfs_waitq_wait_event_timeout(wq, condition, timeout, ret) \
-do { \
- ret = 0; \
- if (!(condition)) \
- __wait_event_timeout(wq, condition, timeout, ret); \
-} while (0)
-#else
-#define cfs_waitq_wait_event_timeout(wq, condition, timeout, ret) \
- ret = wait_event_timeout(wq, condition, timeout)
-#endif
-
-#define cfs_waitq_wait_event_interruptible_timeout(wq, c, timeout, ret) \
- ret = wait_event_interruptible_timeout(wq, c, timeout)
-
-/*
- * atomic
- */
-
-
-#define cfs_atomic_add_unless(atom, a, u) atomic_add_unless(atom, a, u)
-#define cfs_atomic_cmpxchg(atom, old, nv) atomic_cmpxchg(atom, old, nv)
-
-/*
- * membar
- */
-
-
-/*
- * interrupt
- */
-
-
-/*
- * might_sleep
- */
-
-/*
- * group_info
- */
-typedef struct group_info group_info_t;
-
-
-/*
- * Random bytes
- */
#endif
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-tcpip.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-tcpip.h
index 687f33f4e8a..7a8d006903b 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-tcpip.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-tcpip.h
@@ -48,21 +48,6 @@
#include <net/sock.h>
-#ifndef HIPQUAD
-// XXX Should just kill all users
-#if defined(__LITTLE_ENDIAN)
-#define HIPQUAD(addr) \
- ((unsigned char *)&addr)[3], \
- ((unsigned char *)&addr)[2], \
- ((unsigned char *)&addr)[1], \
- ((unsigned char *)&addr)[0]
-#elif defined(__BIG_ENDIAN)
-#define HIPQUAD NIPQUAD
-#else
-#error "Please fix asm/byteorder.h"
-#endif /* __LITTLE_ENDIAN */
-#endif
-
typedef struct socket socket_t;
#define SOCK_SNDBUF(so) ((so)->sk->sk_sndbuf)
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
index 4a48b914b42..a386d1b1286 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
@@ -91,7 +91,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/time.h>
#include <asm/div64.h>
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/portals_compat25.h b/drivers/staging/lustre/include/linux/libcfs/linux/portals_compat25.h
index 132a4bec357..fe4c63fb40a 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/portals_compat25.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/portals_compat25.h
@@ -95,20 +95,5 @@ int proc_call_handler(void *data, int write,
loff_t *ppos, void *buffer, size_t *lenp,
int (*handler)(void *data, int write,
loff_t pos, void *buffer, int len));
-/*
- * CPU
- */
-#ifdef for_each_possible_cpu
-#define cfs_for_each_possible_cpu(cpu) for_each_possible_cpu(cpu)
-#elif defined(for_each_cpu)
-#define cfs_for_each_possible_cpu(cpu) for_each_cpu(cpu)
-#endif
-
-#ifdef NR_CPUS
-#else
-#define NR_CPUS 1
-#endif
-
-#define cfs_register_sysctl_table(t, a) register_sysctl_table(t)
#endif /* _PORTALS_COMPAT_H */
diff --git a/drivers/staging/lustre/include/linux/libcfs/lucache.h b/drivers/staging/lustre/include/linux/libcfs/lucache.h
index 7ae36fc88d7..9668b397f0f 100644
--- a/drivers/staging/lustre/include/linux/libcfs/lucache.h
+++ b/drivers/staging/lustre/include/linux/libcfs/lucache.h
@@ -77,7 +77,7 @@ struct md_identity {
struct upcall_cache_entry *mi_uc_entry;
uid_t mi_uid;
gid_t mi_gid;
- group_info_t *mi_ginfo;
+ struct group_info *mi_ginfo;
int mi_nperms;
struct md_perm *mi_perms;
};
diff --git a/drivers/staging/lustre/include/linux/libcfs/params_tree.h b/drivers/staging/lustre/include/linux/libcfs/params_tree.h
index 3f18a446703..78a2c4ed4d6 100644
--- a/drivers/staging/lustre/include/linux/libcfs/params_tree.h
+++ b/drivers/staging/lustre/include/linux/libcfs/params_tree.h
@@ -54,7 +54,6 @@ typedef struct proc_inode cfs_proc_inode_t;
typedef struct seq_file cfs_seq_file_t;
typedef struct seq_operations cfs_seq_ops_t;
typedef struct file_operations cfs_param_file_ops_t;
-typedef module_t *cfs_param_module_t;
typedef struct proc_dir_entry cfs_param_dentry_t;
typedef struct poll_table_struct cfs_poll_table_t;
#define CFS_PARAM_MODULE THIS_MODULE
@@ -115,11 +114,10 @@ typedef struct cfs_seq_operations {
int (*show) (cfs_seq_file_t *m, void *v);
} cfs_seq_ops_t;
-typedef void *cfs_param_module_t;
typedef void *cfs_poll_table_t;
typedef struct cfs_param_file_ops {
- cfs_param_module_t owner;
+ struct module *owner;
int (*open) (cfs_inode_t *, struct file *);
loff_t (*llseek)(struct file *, loff_t, int);
int (*release) (cfs_inode_t *, cfs_param_file_t *);
diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h
index 86428d4b993..e579e7ed507 100644
--- a/drivers/staging/lustre/include/linux/lnet/lib-types.h
+++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h
@@ -181,11 +181,11 @@ typedef struct lnet_msg {
lnet_nid_t msg_from;
__u32 msg_type;
- /* commited for sending */
+ /* committed for sending */
unsigned int msg_tx_committed:1;
/* CPT # this message committed for sending */
unsigned int msg_tx_cpt:15;
- /* commited for receiving */
+ /* committed for receiving */
unsigned int msg_rx_committed:1;
/* CPT # this message committed for receiving */
unsigned int msg_rx_cpt:15;
@@ -619,7 +619,7 @@ typedef struct lnet_portal {
unsigned int ptl_index; /* portal ID, reserved */
/* flags on this portal: lazy, unique... */
unsigned int ptl_options;
- /* list of messags which are stealing buffer */
+ /* list of messages which are stealing buffer */
struct list_head ptl_msg_stealing;
/* messages blocking for MD */
struct list_head ptl_msg_delayed;
diff --git a/drivers/staging/lustre/include/linux/lnet/lnetst.h b/drivers/staging/lustre/include/linux/lnet/lnetst.h
index d90f94e9460..e060599314d 100644
--- a/drivers/staging/lustre/include/linux/lnet/lnetst.h
+++ b/drivers/staging/lustre/include/linux/lnet/lnetst.h
@@ -59,7 +59,7 @@
#define LSTIO_SESSION_INFO 0xC03 /* query session */
#define LSTIO_GROUP_ADD 0xC10 /* add group */
#define LSTIO_GROUP_LIST 0xC11 /* list all groups in session */
-#define LSTIO_GROUP_INFO 0xC12 /* query defailt infomation of specified group */
+#define LSTIO_GROUP_INFO 0xC12 /* query default information of specified group */
#define LSTIO_GROUP_DEL 0xC13 /* delete group */
#define LSTIO_NODES_ADD 0xC14 /* add nodes to specified group */
#define LSTIO_GROUP_UPDATE 0xC15 /* update group */
diff --git a/drivers/staging/lustre/include/linux/lnet/ptllnd.h b/drivers/staging/lustre/include/linux/lnet/ptllnd.h
index fc1ce8ed1f8..564f5d3a9b4 100644
--- a/drivers/staging/lustre/include/linux/lnet/ptllnd.h
+++ b/drivers/staging/lustre/include/linux/lnet/ptllnd.h
@@ -68,7 +68,7 @@
/* Can compare handles directly on Cray Portals */
#define PtlHandleIsEqual(a,b) ((a) == (b))
-/* Diffrent error types on Cray Portals*/
+/* Different error types on Cray Portals*/
#define ptl_err_t ptl_ni_fail_t
/*
@@ -76,7 +76,7 @@
* maximum is limited only by memory and size of the
* int parameters (2^31-1).
* Lustre only really require that the underyling
- * implemenation to support at least LNET_MAX_IOV,
+ * implementation to support at least LNET_MAX_IOV,
* so for Cray portals we can safely just use that
* value here.
*
diff --git a/drivers/staging/lustre/lnet/Makefile b/drivers/staging/lustre/lnet/Makefile
index 374212b1555..f6f03e304d8 100644
--- a/drivers/staging/lustre/lnet/Makefile
+++ b/drivers/staging/lustre/lnet/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_LNET) := klnds/ lnet/ selftest/
+obj-$(CONFIG_LNET) += lnet/ klnds/ selftest/
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index 29a97943e4c..86397f96b03 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -702,6 +702,8 @@ kiblnd_get_completion_vector(kib_conn_t *conn, int cpt)
return 0;
mask = cfs_cpt_cpumask(lnet_cpt_table(), cpt);
+ if (mask == NULL)
+ return 0;
/* hash NID to CPU id in this partition... */
off = do_div(nid, cpus_weight(*mask));
@@ -2574,8 +2576,8 @@ kiblnd_dev_need_failover(kib_dev_t *dev)
rc = rdma_resolve_addr(cmid, (struct sockaddr *)&srcaddr,
(struct sockaddr *)&dstaddr, 1);
if (rc != 0 || cmid->device == NULL) {
- CERROR("Failed to bind %s:%u.%u.%u.%u to device(%p): %d\n",
- dev->ibd_ifname, HIPQUAD(dev->ibd_ifip),
+ CERROR("Failed to bind %s:%pI4h to device(%p): %d\n",
+ dev->ibd_ifname, &dev->ibd_ifip,
cmid->device, rc);
rdma_destroy_id(cmid);
return rc;
@@ -2647,8 +2649,8 @@ kiblnd_dev_failover(kib_dev_t *dev)
/* Bind to failover device or port */
rc = rdma_bind_addr(cmid, (struct sockaddr *)&addr);
if (rc != 0 || cmid->device == NULL) {
- CERROR("Failed to bind %s:%u.%u.%u.%u to device(%p): %d\n",
- dev->ibd_ifname, HIPQUAD(dev->ibd_ifip),
+ CERROR("Failed to bind %s:%pI4h to device(%p): %d\n",
+ dev->ibd_ifname, &dev->ibd_ifip,
cmid->device, rc);
rdma_destroy_id(cmid);
goto out;
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
index e4626bf82fc..938df0cf8c6 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
@@ -53,7 +53,6 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/file.h>
-#include <linux/stat.h>
#include <linux/list.h>
#include <linux/kmod.h>
#include <linux/sysctl.h>
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index cc6232126dd..086ca3d7241 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -1319,9 +1319,9 @@ kiblnd_connect_peer (kib_peer_t *peer)
}
LASSERT (cmid->device != NULL);
- CDEBUG(D_NET, "%s: connection bound to %s:%u.%u.%u.%u:%s\n",
+ CDEBUG(D_NET, "%s: connection bound to %s:%pI4h:%s\n",
libcfs_nid2str(peer->ibp_nid), dev->ibd_ifname,
- HIPQUAD(dev->ibd_ifip), cmid->device->name);
+ &dev->ibd_ifip, cmid->device->name);
return;
@@ -1802,7 +1802,7 @@ kiblnd_recv (lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed,
int
kiblnd_thread_start(int (*fn)(void *arg), void *arg, char *name)
{
- task_t *task = kthread_run(fn, arg, name);
+ struct task_struct *task = kthread_run(fn, arg, name);
if (IS_ERR(task))
return PTR_ERR(task);
@@ -2209,8 +2209,8 @@ kiblnd_passive_connect (struct rdma_cm_id *cmid, void *priv, int priv_nob)
if (*kiblnd_tunables.kib_require_priv_port &&
ntohs(peer_addr->sin_port) >= PROT_SOCK) {
__u32 ip = ntohl(peer_addr->sin_addr.s_addr);
- CERROR("Peer's port (%u.%u.%u.%u:%hu) is not privileged\n",
- HIPQUAD(ip), ntohs(peer_addr->sin_port));
+ CERROR("Peer's port (%pI4h:%hu) is not privileged\n",
+ &ip, ntohs(peer_addr->sin_port));
goto failed;
}
@@ -2254,11 +2254,11 @@ kiblnd_passive_connect (struct rdma_cm_id *cmid, void *priv, int priv_nob)
if (ni == NULL || /* no matching net */
ni->ni_nid != reqmsg->ibm_dstnid || /* right NET, wrong NID! */
net->ibn_dev != ibdev) { /* wrong device */
- CERROR("Can't accept %s on %s (%s:%d:%u.%u.%u.%u): "
+ CERROR("Can't accept %s on %s (%s:%d:%pI4h): "
"bad dst nid %s\n", libcfs_nid2str(nid),
ni == NULL ? "NA" : libcfs_nid2str(ni->ni_nid),
ibdev->ibd_ifname, ibdev->ibd_nnets,
- HIPQUAD(ibdev->ibd_ifip),
+ &ibdev->ibd_ifip,
libcfs_nid2str(reqmsg->ibm_dstnid));
goto failed;
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c
index e21028b7230..92dc5672e2d 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c
@@ -404,7 +404,7 @@ kiblnd_sysctl_init (void)
sizeof(ipif_basename_space));
kiblnd_tunables.kib_sysctl =
- cfs_register_sysctl_table(kiblnd_top_ctl_table, 0);
+ register_sysctl_table(kiblnd_top_ctl_table);
if (kiblnd_tunables.kib_sysctl == NULL)
CWARN("Can't setup /proc tunables\n");
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
index c826bf9d49a..6825b452e5f 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
@@ -334,17 +334,17 @@ ksocknal_associate_route_conn_locked(ksock_route_t *route, ksock_conn_t *conn)
if (route->ksnr_myipaddr != conn->ksnc_myipaddr) {
if (route->ksnr_myipaddr == 0) {
/* route wasn't bound locally yet (the initial route) */
- CDEBUG(D_NET, "Binding %s %u.%u.%u.%u to %u.%u.%u.%u\n",
+ CDEBUG(D_NET, "Binding %s %pI4h to %pI4h\n",
libcfs_id2str(peer->ksnp_id),
- HIPQUAD(route->ksnr_ipaddr),
- HIPQUAD(conn->ksnc_myipaddr));
+ &route->ksnr_ipaddr,
+ &conn->ksnc_myipaddr);
} else {
- CDEBUG(D_NET, "Rebinding %s %u.%u.%u.%u from "
- "%u.%u.%u.%u to %u.%u.%u.%u\n",
+ CDEBUG(D_NET, "Rebinding %s %pI4h from "
+ "%pI4h to %pI4h\n",
libcfs_id2str(peer->ksnp_id),
- HIPQUAD(route->ksnr_ipaddr),
- HIPQUAD(route->ksnr_myipaddr),
- HIPQUAD(conn->ksnc_myipaddr));
+ &route->ksnr_ipaddr,
+ &route->ksnr_myipaddr,
+ &conn->ksnc_myipaddr);
iface = ksocknal_ip2iface(route->ksnr_peer->ksnp_ni,
route->ksnr_myipaddr);
@@ -384,9 +384,9 @@ ksocknal_add_route_locked (ksock_peer_t *peer, ksock_route_t *route)
route2 = list_entry(tmp, ksock_route_t, ksnr_list);
if (route2->ksnr_ipaddr == route->ksnr_ipaddr) {
- CERROR ("Duplicate route %s %u.%u.%u.%u\n",
+ CERROR("Duplicate route %s %pI4h\n",
libcfs_id2str(peer->ksnp_id),
- HIPQUAD(route->ksnr_ipaddr));
+ &route->ksnr_ipaddr);
LBUG();
}
}
@@ -982,8 +982,8 @@ ksocknal_accept (lnet_ni_t *ni, socket_t *sock)
LIBCFS_ALLOC(cr, sizeof(*cr));
if (cr == NULL) {
LCONSOLE_ERROR_MSG(0x12f, "Dropping connection request from "
- "%u.%u.%u.%u: memory exhausted\n",
- HIPQUAD(peer_ip));
+ "%pI4h: memory exhausted\n",
+ &peer_ip);
return -ENOMEM;
}
@@ -1236,10 +1236,10 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route,
* code below probably isn't going to work. */
if (active &&
route->ksnr_ipaddr != conn->ksnc_ipaddr) {
- CERROR("Route %s %u.%u.%u.%u connected to %u.%u.%u.%u\n",
+ CERROR("Route %s %pI4h connected to %pI4h\n",
libcfs_id2str(peer->ksnp_id),
- HIPQUAD(route->ksnr_ipaddr),
- HIPQUAD(conn->ksnc_ipaddr));
+ &route->ksnr_ipaddr,
+ &conn->ksnc_ipaddr);
}
/* Search for a route corresponding to the new connection and
@@ -1297,10 +1297,10 @@ ksocknal_create_conn (lnet_ni_t *ni, ksock_route_t *route,
* socket callbacks.
*/
- CDEBUG(D_NET, "New conn %s p %d.x %u.%u.%u.%u -> %u.%u.%u.%u/%d"
+ CDEBUG(D_NET, "New conn %s p %d.x %pI4h -> %pI4h/%d"
" incarnation:"LPD64" sched[%d:%d]\n",
libcfs_id2str(peerid), conn->ksnc_proto->pro_version,
- HIPQUAD(conn->ksnc_myipaddr), HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_myipaddr, &conn->ksnc_ipaddr,
conn->ksnc_port, incarnation, cpt,
(int)(sched - &sched->kss_info->ksi_scheds[0]));
@@ -1441,7 +1441,7 @@ ksocknal_close_conn_locked (ksock_conn_t *conn, int error)
conn->ksnc_route = NULL;
-#if 0 /* irrelevent with only eager routes */
+#if 0 /* irrelevant with only eager routes */
/* make route least favourite */
list_del (&route->ksnr_list);
list_add_tail (&route->ksnr_list, &peer->ksnp_routes);
@@ -1496,7 +1496,7 @@ ksocknal_peer_failed (ksock_peer_t *peer)
/* There has been a connection failure or comms error; but I'll only
* tell LNET I think the peer is dead if it's to another kernel and
- * there are no connections or connection attempts in existance. */
+ * there are no connections or connection attempts in existence. */
read_lock(&ksocknal_data.ksnd_global_lock);
@@ -1648,10 +1648,10 @@ ksocknal_destroy_conn (ksock_conn_t *conn)
last_rcv = conn->ksnc_rx_deadline -
cfs_time_seconds(*ksocknal_tunables.ksnd_timeout);
CERROR("Completing partial receive from %s[%d]"
- ", ip %d.%d.%d.%d:%d, with error, wanted: %d, left: %d, "
+ ", ip %pI4h:%d, with error, wanted: %d, left: %d, "
"last alive is %ld secs ago\n",
libcfs_id2str(conn->ksnc_peer->ksnp_id), conn->ksnc_type,
- HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port,
+ &conn->ksnc_ipaddr, conn->ksnc_port,
conn->ksnc_rx_nob_wanted, conn->ksnc_rx_nob_left,
cfs_duration_sec(cfs_time_sub(cfs_time_current(),
last_rcv)));
@@ -1661,25 +1661,25 @@ ksocknal_destroy_conn (ksock_conn_t *conn)
case SOCKNAL_RX_LNET_HEADER:
if (conn->ksnc_rx_started)
CERROR("Incomplete receive of lnet header from %s"
- ", ip %d.%d.%d.%d:%d, with error, protocol: %d.x.\n",
+ ", ip %pI4h:%d, with error, protocol: %d.x.\n",
libcfs_id2str(conn->ksnc_peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port,
+ &conn->ksnc_ipaddr, conn->ksnc_port,
conn->ksnc_proto->pro_version);
break;
case SOCKNAL_RX_KSM_HEADER:
if (conn->ksnc_rx_started)
CERROR("Incomplete receive of ksock message from %s"
- ", ip %d.%d.%d.%d:%d, with error, protocol: %d.x.\n",
+ ", ip %pI4h:%d, with error, protocol: %d.x.\n",
libcfs_id2str(conn->ksnc_peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port,
+ &conn->ksnc_ipaddr, conn->ksnc_port,
conn->ksnc_proto->pro_version);
break;
case SOCKNAL_RX_SLOP:
if (conn->ksnc_rx_started)
CERROR("Incomplete receive of slops from %s"
- ", ip %d.%d.%d.%d:%d, with error\n",
+ ", ip %pI4h:%d, with error\n",
libcfs_id2str(conn->ksnc_peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port);
+ &conn->ksnc_ipaddr, conn->ksnc_port);
break;
default:
LBUG ();
@@ -2358,7 +2358,7 @@ ksocknal_new_incarnation (void)
/* The incarnation number is the time this module loaded and it
* identifies this particular instance of the socknal. Hopefully
* we won't be able to reboot more frequently than 1MHz for the
- * forseeable future :) */
+ * foreseeable future :) */
do_gettimeofday(&tv);
@@ -2898,5 +2898,7 @@ ksocknal_module_init (void)
MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Kernel TCP Socket LND v3.0.0");
MODULE_LICENSE("GPL");
+MODULE_VERSION("3.0.0");
-cfs_module(ksocknal, "3.0.0", ksocknal_module_init, ksocknal_module_fini);
+module_init(ksocknal_module_init);
+module_exit(ksocknal_module_fini);
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
index ad5e2410423..2c581b7fa8a 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
@@ -343,7 +343,6 @@ ksocknal_receive (ksock_conn_t *conn)
* Caller checks ksnc_rx_nob_wanted to determine
* progress/completion. */
int rc;
- ENTRY;
if (ksocknal_data.ksnd_stall_rx != 0) {
cfs_pause(cfs_time_seconds (ksocknal_data.ksnd_stall_rx));
@@ -381,7 +380,7 @@ ksocknal_receive (ksock_conn_t *conn)
}
ksocknal_connsock_decref(conn);
- RETURN (rc);
+ return rc;
}
void
@@ -389,7 +388,6 @@ ksocknal_tx_done (lnet_ni_t *ni, ksock_tx_t *tx)
{
lnet_msg_t *lnetmsg = tx->tx_lnetmsg;
int rc = (tx->tx_resid == 0 && !tx->tx_zc_aborted) ? 0 : -EIO;
- ENTRY;
LASSERT(ni != NULL || tx->tx_conn != NULL);
@@ -402,8 +400,6 @@ ksocknal_tx_done (lnet_ni_t *ni, ksock_tx_t *tx)
ksocknal_free_tx (tx);
if (lnetmsg != NULL) /* KSOCK_MSG_NOOP go without lnetmsg */
lnet_finalize (ni, lnetmsg, rc);
-
- EXIT;
}
void
@@ -553,21 +549,21 @@ ksocknal_process_transmit (ksock_conn_t *conn, ksock_tx_t *tx)
if (!conn->ksnc_closing) {
switch (rc) {
case -ECONNRESET:
- LCONSOLE_WARN("Host %u.%u.%u.%u reset our connection "
+ LCONSOLE_WARN("Host %pI4h reset our connection "
"while we were sending data; it may have "
"rebooted.\n",
- HIPQUAD(conn->ksnc_ipaddr));
+ &conn->ksnc_ipaddr);
break;
default:
LCONSOLE_WARN("There was an unexpected network error "
- "while writing to %u.%u.%u.%u: %d.\n",
- HIPQUAD(conn->ksnc_ipaddr), rc);
+ "while writing to %pI4h: %d.\n",
+ &conn->ksnc_ipaddr, rc);
break;
}
CDEBUG(D_NET, "[%p] Error %d on write to %s"
- " ip %d.%d.%d.%d:%d\n", conn, rc,
+ " ip %pI4h:%d\n", conn, rc,
libcfs_id2str(conn->ksnc_peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
conn->ksnc_port);
}
@@ -700,9 +696,9 @@ ksocknal_queue_tx_locked (ksock_tx_t *tx, ksock_conn_t *conn)
* ksnc_sock... */
LASSERT(!conn->ksnc_closing);
- CDEBUG (D_NET, "Sending to %s ip %d.%d.%d.%d:%d\n",
+ CDEBUG(D_NET, "Sending to %s ip %pI4h:%d\n",
libcfs_id2str(conn->ksnc_peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
conn->ksnc_port);
ksocknal_tx_prep(conn, tx);
@@ -801,9 +797,9 @@ ksocknal_find_connectable_route_locked (ksock_peer_t *peer)
if (!(route->ksnr_retry_interval == 0 || /* first attempt */
cfs_time_aftereq(now, route->ksnr_timeout))) {
CDEBUG(D_NET,
- "Too soon to retry route %u.%u.%u.%u "
+ "Too soon to retry route %pI4h "
"(cnted %d, interval %ld, %ld secs later)\n",
- HIPQUAD(route->ksnr_ipaddr),
+ &route->ksnr_ipaddr,
route->ksnr_connected,
route->ksnr_retry_interval,
cfs_duration_sec(route->ksnr_timeout - now));
@@ -1009,7 +1005,7 @@ ksocknal_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg)
int
ksocknal_thread_start(int (*fn)(void *arg), void *arg, char *name)
{
- task_t *task = kthread_run(fn, arg, name);
+ struct task_struct *task = kthread_run(fn, arg, name);
if (IS_ERR(task))
return PTR_ERR(task);
@@ -1120,7 +1116,7 @@ ksocknal_process_receive (ksock_conn_t *conn)
LASSERT (atomic_read(&conn->ksnc_conn_refcount) > 0);
/* NB: sched lock NOT held */
- /* SOCKNAL_RX_LNET_HEADER is here for backward compatability */
+ /* SOCKNAL_RX_LNET_HEADER is here for backward compatibility */
LASSERT (conn->ksnc_rx_state == SOCKNAL_RX_KSM_HEADER ||
conn->ksnc_rx_state == SOCKNAL_RX_LNET_PAYLOAD ||
conn->ksnc_rx_state == SOCKNAL_RX_LNET_HEADER ||
@@ -1133,17 +1129,17 @@ ksocknal_process_receive (ksock_conn_t *conn)
LASSERT (rc != -EAGAIN);
if (rc == 0)
- CDEBUG (D_NET, "[%p] EOF from %s"
- " ip %d.%d.%d.%d:%d\n", conn,
+ CDEBUG(D_NET, "[%p] EOF from %s"
+ " ip %pI4h:%d\n", conn,
libcfs_id2str(conn->ksnc_peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
conn->ksnc_port);
else if (!conn->ksnc_closing)
- CERROR ("[%p] Error %d on read from %s"
- " ip %d.%d.%d.%d:%d\n",
+ CERROR("[%p] Error %d on read from %s"
+ " ip %pI4h:%d\n",
conn, rc,
libcfs_id2str(conn->ksnc_peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
conn->ksnc_port);
/* it's not an error if conn is being closed */
@@ -1562,7 +1558,6 @@ int ksocknal_scheduler(void *arg)
void ksocknal_read_callback (ksock_conn_t *conn)
{
ksock_sched_t *sched;
- ENTRY;
sched = conn->ksnc_scheduler;
@@ -1580,8 +1575,6 @@ void ksocknal_read_callback (ksock_conn_t *conn)
wake_up (&sched->kss_waitq);
}
spin_unlock_bh(&sched->kss_lock);
-
- EXIT;
}
/*
@@ -1591,7 +1584,6 @@ void ksocknal_read_callback (ksock_conn_t *conn)
void ksocknal_write_callback (ksock_conn_t *conn)
{
ksock_sched_t *sched;
- ENTRY;
sched = conn->ksnc_scheduler;
@@ -1611,8 +1603,6 @@ void ksocknal_write_callback (ksock_conn_t *conn)
}
spin_unlock_bh(&sched->kss_lock);
-
- EXIT;
}
ksock_proto_t *
@@ -1722,8 +1712,8 @@ ksocknal_recv_hello (lnet_ni_t *ni, ksock_conn_t *conn,
rc = libcfs_sock_read(sock, &hello->kshm_magic, sizeof (hello->kshm_magic), timeout);
if (rc != 0) {
- CERROR ("Error %d reading HELLO from %u.%u.%u.%u\n",
- rc, HIPQUAD(conn->ksnc_ipaddr));
+ CERROR("Error %d reading HELLO from %pI4h\n",
+ rc, &conn->ksnc_ipaddr);
LASSERT (rc < 0);
return rc;
}
@@ -1732,18 +1722,18 @@ ksocknal_recv_hello (lnet_ni_t *ni, ksock_conn_t *conn,
hello->kshm_magic != __swab32(LNET_PROTO_MAGIC) &&
hello->kshm_magic != le32_to_cpu (LNET_PROTO_TCP_MAGIC)) {
/* Unexpected magic! */
- CERROR ("Bad magic(1) %#08x (%#08x expected) from "
- "%u.%u.%u.%u\n", __cpu_to_le32 (hello->kshm_magic),
+ CERROR("Bad magic(1) %#08x (%#08x expected) from "
+ "%pI4h\n", __cpu_to_le32 (hello->kshm_magic),
LNET_PROTO_TCP_MAGIC,
- HIPQUAD(conn->ksnc_ipaddr));
+ &conn->ksnc_ipaddr);
return -EPROTO;
}
rc = libcfs_sock_read(sock, &hello->kshm_version,
sizeof(hello->kshm_version), timeout);
if (rc != 0) {
- CERROR ("Error %d reading HELLO from %u.%u.%u.%u\n",
- rc, HIPQUAD(conn->ksnc_ipaddr));
+ CERROR("Error %d reading HELLO from %pI4h\n",
+ rc, &conn->ksnc_ipaddr);
LASSERT (rc < 0);
return rc;
}
@@ -1763,10 +1753,10 @@ ksocknal_recv_hello (lnet_ni_t *ni, ksock_conn_t *conn,
ksocknal_send_hello(ni, conn, ni->ni_nid, hello);
}
- CERROR ("Unknown protocol version (%d.x expected)"
- " from %u.%u.%u.%u\n",
+ CERROR("Unknown protocol version (%d.x expected)"
+ " from %pI4h\n",
conn->ksnc_proto->pro_version,
- HIPQUAD(conn->ksnc_ipaddr));
+ &conn->ksnc_ipaddr);
return -EPROTO;
}
@@ -1777,8 +1767,8 @@ ksocknal_recv_hello (lnet_ni_t *ni, ksock_conn_t *conn,
/* receive the rest of hello message anyway */
rc = conn->ksnc_proto->pro_recv_hello(conn, hello, timeout);
if (rc != 0) {
- CERROR("Error %d reading or checking hello from from %u.%u.%u.%u\n",
- rc, HIPQUAD(conn->ksnc_ipaddr));
+ CERROR("Error %d reading or checking hello from from %pI4h\n",
+ rc, &conn->ksnc_ipaddr);
LASSERT (rc < 0);
return rc;
}
@@ -1787,7 +1777,7 @@ ksocknal_recv_hello (lnet_ni_t *ni, ksock_conn_t *conn,
if (hello->kshm_src_nid == LNET_NID_ANY) {
CERROR("Expecting a HELLO hdr with a NID, but got LNET_NID_ANY"
- "from %u.%u.%u.%u\n", HIPQUAD(conn->ksnc_ipaddr));
+ "from %pI4h\n", &conn->ksnc_ipaddr);
return -EPROTO;
}
@@ -1807,9 +1797,9 @@ ksocknal_recv_hello (lnet_ni_t *ni, ksock_conn_t *conn,
/* peer determines type */
conn->ksnc_type = ksocknal_invert_type(hello->kshm_ctype);
if (conn->ksnc_type == SOCKLND_CONN_NONE) {
- CERROR ("Unexpected type %d from %s ip %u.%u.%u.%u\n",
+ CERROR("Unexpected type %d from %s ip %pI4h\n",
hello->kshm_ctype, libcfs_id2str(*peerid),
- HIPQUAD(conn->ksnc_ipaddr));
+ &conn->ksnc_ipaddr);
return -EPROTO;
}
@@ -1819,11 +1809,11 @@ ksocknal_recv_hello (lnet_ni_t *ni, ksock_conn_t *conn,
if (peerid->pid != recv_id.pid ||
peerid->nid != recv_id.nid) {
LCONSOLE_ERROR_MSG(0x130, "Connected successfully to %s on host"
- " %u.%u.%u.%u, but they claimed they were "
+ " %pI4h, but they claimed they were "
"%s; please check your Lustre "
"configuration.\n",
libcfs_id2str(*peerid),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
libcfs_id2str(recv_id));
return -EPROTO;
}
@@ -1834,9 +1824,9 @@ ksocknal_recv_hello (lnet_ni_t *ni, ksock_conn_t *conn,
}
if (ksocknal_invert_type(hello->kshm_ctype) != conn->ksnc_type) {
- CERROR ("Mismatched types: me %d, %s ip %u.%u.%u.%u %d\n",
+ CERROR("Mismatched types: me %d, %s ip %pI4h %d\n",
conn->ksnc_type, libcfs_id2str(*peerid),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
hello->kshm_ctype);
return -EPROTO;
}
@@ -1995,7 +1985,7 @@ ksocknal_connect (ksock_route_t *route)
list_splice_init(&peer->ksnp_tx_queue, &zombies);
}
-#if 0 /* irrelevent with only eager routes */
+#if 0 /* irrelevant with only eager routes */
if (!route->ksnr_deleted) {
/* make this route least-favourite for re-selection */
list_del(&route->ksnr_list);
@@ -2208,8 +2198,8 @@ ksocknal_connd (void *arg)
/* consecutive retry */
if (cons_retry++ > SOCKNAL_INSANITY_RECONN) {
CWARN("massive consecutive "
- "re-connecting to %u.%u.%u.%u\n",
- HIPQUAD(route->ksnr_ipaddr));
+ "re-connecting to %pI4h\n",
+ &route->ksnr_ipaddr);
cons_retry = 0;
}
} else {
@@ -2274,26 +2264,26 @@ ksocknal_find_timed_out_conn (ksock_peer_t *peer)
switch (error) {
case ECONNRESET:
CNETERR("A connection with %s "
- "(%u.%u.%u.%u:%d) was reset; "
+ "(%pI4h:%d) was reset; "
"it may have rebooted.\n",
libcfs_id2str(peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
conn->ksnc_port);
break;
case ETIMEDOUT:
CNETERR("A connection with %s "
- "(%u.%u.%u.%u:%d) timed out; the "
+ "(%pI4h:%d) timed out; the "
"network or node may be down.\n",
libcfs_id2str(peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
conn->ksnc_port);
break;
default:
CNETERR("An unexpected network error %d "
"occurred with %s "
- "(%u.%u.%u.%u:%d\n", error,
+ "(%pI4h:%d\n", error,
libcfs_id2str(peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
conn->ksnc_port);
break;
}
@@ -2306,10 +2296,10 @@ ksocknal_find_timed_out_conn (ksock_peer_t *peer)
conn->ksnc_rx_deadline)) {
/* Timed out incomplete incoming message */
ksocknal_conn_addref(conn);
- CNETERR("Timeout receiving from %s (%u.%u.%u.%u:%d), "
+ CNETERR("Timeout receiving from %s (%pI4h:%d), "
"state %d wanted %d left %d\n",
libcfs_id2str(peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
conn->ksnc_port,
conn->ksnc_rx_state,
conn->ksnc_rx_nob_wanted,
@@ -2324,10 +2314,10 @@ ksocknal_find_timed_out_conn (ksock_peer_t *peer)
/* Timed out messages queued for sending or
* buffered in the socket's send buffer */
ksocknal_conn_addref(conn);
- CNETERR("Timeout sending data to %s (%u.%u.%u.%u:%d) "
+ CNETERR("Timeout sending data to %s (%pI4h:%d) "
"the network or that node may be down.\n",
libcfs_id2str(peer->ksnp_id),
- HIPQUAD(conn->ksnc_ipaddr),
+ &conn->ksnc_ipaddr,
conn->ksnc_port);
return (conn);
}
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
index 3e08fe2d148..a1c6a519bf5 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
@@ -316,7 +316,7 @@ ksocknal_lib_tunables_init ()
*ksocknal_tunables.ksnd_zc_recv_min_nfrags = LNET_MAX_IOV;
ksocknal_tunables.ksnd_sysctl =
- cfs_register_sysctl_table(ksocknal_top_ctl_table, 0);
+ register_sysctl_table(ksocknal_top_ctl_table);
if (ksocknal_tunables.ksnd_sysctl == NULL)
CWARN("Can't setup /proc tunables\n");
@@ -325,20 +325,20 @@ ksocknal_lib_tunables_init ()
}
void
-ksocknal_lib_tunables_fini ()
+ksocknal_lib_tunables_fini(void)
{
if (ksocknal_tunables.ksnd_sysctl != NULL)
unregister_sysctl_table(ksocknal_tunables.ksnd_sysctl);
}
#else
int
-ksocknal_lib_tunables_init ()
+ksocknal_lib_tunables_init(void)
{
return 0;
}
void
-ksocknal_lib_tunables_fini ()
+ksocknal_lib_tunables_fini(void)
{
}
#endif /* # if CONFIG_SYSCTL && !CFS_SYSFS_MODULE_PARM */
@@ -964,7 +964,6 @@ static void
ksocknal_data_ready (struct sock *sk, int n)
{
ksock_conn_t *conn;
- ENTRY;
/* interleave correctly with closing sockets... */
LASSERT(!in_irq());
@@ -978,8 +977,6 @@ ksocknal_data_ready (struct sock *sk, int n)
ksocknal_read_callback(conn);
read_unlock(&ksocknal_data.ksnd_global_lock);
-
- EXIT;
}
static void
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.h
index 3c135786dc1..1cfc1b168be 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.h
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.h
@@ -41,7 +41,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
@@ -58,11 +57,9 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/file.h>
-#include <linux/stat.h>
#include <linux/list.h>
#include <linux/kmod.h>
#include <linux/sysctl.h>
-#include <asm/uaccess.h>
#include <asm/div64.h>
#include <linux/syscalls.h>
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
index ec57179f8d2..71205e2015c 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
@@ -218,7 +218,7 @@ ksocknal_queue_tx_zcack_v3(ksock_conn_t *conn,
if (tx->tx_msg.ksm_zc_cookies[0] > tx->tx_msg.ksm_zc_cookies[1]) {
__u64 tmp = 0;
- /* two seperated cookies: (a+2, a) or (a+1, a) */
+ /* two separated cookies: (a+2, a) or (a+1, a) */
LASSERT (tx->tx_msg.ksm_zc_cookies[0] -
tx->tx_msg.ksm_zc_cookies[1] <= 2);
@@ -496,8 +496,8 @@ ksocknal_send_hello_v1 (ksock_conn_t *conn, ksock_hello_msg_t *hello)
rc = libcfs_sock_write(sock, hdr, sizeof(*hdr),lnet_acceptor_timeout());
if (rc != 0) {
- CNETERR("Error %d sending HELLO hdr to %u.%u.%u.%u/%d\n",
- rc, HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port);
+ CNETERR("Error %d sending HELLO hdr to %pI4h/%d\n",
+ rc, &conn->ksnc_ipaddr, conn->ksnc_port);
goto out;
}
@@ -513,8 +513,8 @@ ksocknal_send_hello_v1 (ksock_conn_t *conn, ksock_hello_msg_t *hello)
lnet_acceptor_timeout());
if (rc != 0) {
CNETERR("Error %d sending HELLO payload (%d)"
- " to %u.%u.%u.%u/%d\n", rc, hello->kshm_nips,
- HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port);
+ " to %pI4h/%d\n", rc, hello->kshm_nips,
+ &conn->ksnc_ipaddr, conn->ksnc_port);
}
out:
LIBCFS_FREE(hdr, sizeof(*hdr));
@@ -545,8 +545,8 @@ ksocknal_send_hello_v2 (ksock_conn_t *conn, ksock_hello_msg_t *hello)
lnet_acceptor_timeout());
if (rc != 0) {
- CNETERR("Error %d sending HELLO hdr to %u.%u.%u.%u/%d\n",
- rc, HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port);
+ CNETERR("Error %d sending HELLO hdr to %pI4h/%d\n",
+ rc, &conn->ksnc_ipaddr, conn->ksnc_port);
return rc;
}
@@ -558,8 +558,8 @@ ksocknal_send_hello_v2 (ksock_conn_t *conn, ksock_hello_msg_t *hello)
lnet_acceptor_timeout());
if (rc != 0) {
CNETERR("Error %d sending HELLO payload (%d)"
- " to %u.%u.%u.%u/%d\n", rc, hello->kshm_nips,
- HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port);
+ " to %pI4h/%d\n", rc, hello->kshm_nips,
+ &conn->ksnc_ipaddr, conn->ksnc_port);
}
return rc;
@@ -583,18 +583,18 @@ ksocknal_recv_hello_v1(ksock_conn_t *conn, ksock_hello_msg_t *hello,int timeout)
sizeof (*hdr) - offsetof (lnet_hdr_t, src_nid),
timeout);
if (rc != 0) {
- CERROR ("Error %d reading rest of HELLO hdr from %u.%u.%u.%u\n",
- rc, HIPQUAD(conn->ksnc_ipaddr));
+ CERROR("Error %d reading rest of HELLO hdr from %pI4h\n",
+ rc, &conn->ksnc_ipaddr);
LASSERT (rc < 0 && rc != -EALREADY);
goto out;
}
/* ...and check we got what we expected */
if (hdr->type != cpu_to_le32 (LNET_MSG_HELLO)) {
- CERROR ("Expecting a HELLO hdr,"
- " but got type %d from %u.%u.%u.%u\n",
+ CERROR("Expecting a HELLO hdr,"
+ " but got type %d from %pI4h\n",
le32_to_cpu (hdr->type),
- HIPQUAD(conn->ksnc_ipaddr));
+ &conn->ksnc_ipaddr);
rc = -EPROTO;
goto out;
}
@@ -607,8 +607,8 @@ ksocknal_recv_hello_v1(ksock_conn_t *conn, ksock_hello_msg_t *hello,int timeout)
sizeof (__u32);
if (hello->kshm_nips > LNET_MAX_INTERFACES) {
- CERROR("Bad nips %d from ip %u.%u.%u.%u\n",
- hello->kshm_nips, HIPQUAD(conn->ksnc_ipaddr));
+ CERROR("Bad nips %d from ip %pI4h\n",
+ hello->kshm_nips, &conn->ksnc_ipaddr);
rc = -EPROTO;
goto out;
}
@@ -619,9 +619,9 @@ ksocknal_recv_hello_v1(ksock_conn_t *conn, ksock_hello_msg_t *hello,int timeout)
rc = libcfs_sock_read(sock, hello->kshm_ips,
hello->kshm_nips * sizeof(__u32), timeout);
if (rc != 0) {
- CERROR ("Error %d reading IPs from ip %u.%u.%u.%u\n",
- rc, HIPQUAD(conn->ksnc_ipaddr));
- LASSERT (rc < 0 && rc != -EALREADY);
+ CERROR("Error %d reading IPs from ip %pI4h\n",
+ rc, &conn->ksnc_ipaddr);
+ LASSERT(rc < 0 && rc != -EALREADY);
goto out;
}
@@ -629,8 +629,8 @@ ksocknal_recv_hello_v1(ksock_conn_t *conn, ksock_hello_msg_t *hello,int timeout)
hello->kshm_ips[i] = __le32_to_cpu(hello->kshm_ips[i]);
if (hello->kshm_ips[i] == 0) {
- CERROR("Zero IP[%d] from ip %u.%u.%u.%u\n",
- i, HIPQUAD(conn->ksnc_ipaddr));
+ CERROR("Zero IP[%d] from ip %pI4h\n",
+ i, &conn->ksnc_ipaddr);
rc = -EPROTO;
break;
}
@@ -658,9 +658,9 @@ ksocknal_recv_hello_v2 (ksock_conn_t *conn, ksock_hello_msg_t *hello, int timeou
offsetof(ksock_hello_msg_t, kshm_src_nid),
timeout);
if (rc != 0) {
- CERROR ("Error %d reading HELLO from %u.%u.%u.%u\n",
- rc, HIPQUAD(conn->ksnc_ipaddr));
- LASSERT (rc < 0 && rc != -EALREADY);
+ CERROR("Error %d reading HELLO from %pI4h\n",
+ rc, &conn->ksnc_ipaddr);
+ LASSERT(rc < 0 && rc != -EALREADY);
return rc;
}
@@ -676,8 +676,8 @@ ksocknal_recv_hello_v2 (ksock_conn_t *conn, ksock_hello_msg_t *hello, int timeou
}
if (hello->kshm_nips > LNET_MAX_INTERFACES) {
- CERROR("Bad nips %d from ip %u.%u.%u.%u\n",
- hello->kshm_nips, HIPQUAD(conn->ksnc_ipaddr));
+ CERROR("Bad nips %d from ip %pI4h\n",
+ hello->kshm_nips, &conn->ksnc_ipaddr);
return -EPROTO;
}
@@ -687,9 +687,9 @@ ksocknal_recv_hello_v2 (ksock_conn_t *conn, ksock_hello_msg_t *hello, int timeou
rc = libcfs_sock_read(sock, hello->kshm_ips,
hello->kshm_nips * sizeof(__u32), timeout);
if (rc != 0) {
- CERROR ("Error %d reading IPs from ip %u.%u.%u.%u\n",
- rc, HIPQUAD(conn->ksnc_ipaddr));
- LASSERT (rc < 0 && rc != -EALREADY);
+ CERROR("Error %d reading IPs from ip %pI4h\n",
+ rc, &conn->ksnc_ipaddr);
+ LASSERT(rc < 0 && rc != -EALREADY);
return rc;
}
@@ -698,8 +698,8 @@ ksocknal_recv_hello_v2 (ksock_conn_t *conn, ksock_hello_msg_t *hello, int timeou
__swab32s(&hello->kshm_ips[i]);
if (hello->kshm_ips[i] == 0) {
- CERROR("Zero IP[%d] from ip %u.%u.%u.%u\n",
- i, HIPQUAD(conn->ksnc_ipaddr));
+ CERROR("Zero IP[%d] from ip %pI4h\n",
+ i, &conn->ksnc_ipaddr);
return -EPROTO;
}
}
diff --git a/drivers/staging/lustre/lnet/lnet/Makefile b/drivers/staging/lustre/lnet/lnet/Makefile
index 1bd9ef77420..b815fe12b10 100644
--- a/drivers/staging/lustre/lnet/lnet/Makefile
+++ b/drivers/staging/lustre/lnet/lnet/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_LNET) += lnet.o
-lnet-y := api-errno.o api-ni.o config.o lib-me.o lib-msg.o lib-eq.o \
+lnet-y := api-ni.o config.o lib-me.o lib-msg.o lib-eq.o \
lib-md.o lib-ptl.o lib-move.o module.o lo.o router.o \
router_proc.o acceptor.o peer.o
diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c
index 81ef28bbcba..bb15bde0704 100644
--- a/drivers/staging/lustre/lnet/lnet/acceptor.c
+++ b/drivers/staging/lustre/lnet/lnet/acceptor.c
@@ -101,52 +101,52 @@ lnet_connect_console_error (int rc, lnet_nid_t peer_nid,
switch (rc) {
/* "normal" errors */
case -ECONNREFUSED:
- CNETERR("Connection to %s at host %u.%u.%u.%u on port %d was "
+ CNETERR("Connection to %s at host %pI4h on port %d was "
"refused: check that Lustre is running on that node.\n",
libcfs_nid2str(peer_nid),
- HIPQUAD(peer_ip), peer_port);
+ &peer_ip, peer_port);
break;
case -EHOSTUNREACH:
case -ENETUNREACH:
- CNETERR("Connection to %s at host %u.%u.%u.%u "
+ CNETERR("Connection to %s at host %pI4h "
"was unreachable: the network or that node may "
"be down, or Lustre may be misconfigured.\n",
- libcfs_nid2str(peer_nid), HIPQUAD(peer_ip));
+ libcfs_nid2str(peer_nid), &peer_ip);
break;
case -ETIMEDOUT:
- CNETERR("Connection to %s at host %u.%u.%u.%u on "
+ CNETERR("Connection to %s at host %pI4h on "
"port %d took too long: that node may be hung "
"or experiencing high load.\n",
libcfs_nid2str(peer_nid),
- HIPQUAD(peer_ip), peer_port);
+ &peer_ip, peer_port);
break;
case -ECONNRESET:
- LCONSOLE_ERROR_MSG(0x11b, "Connection to %s at host %u.%u.%u.%u"
+ LCONSOLE_ERROR_MSG(0x11b, "Connection to %s at host %pI4h"
" on port %d was reset: "
"is it running a compatible version of "
"Lustre and is %s one of its NIDs?\n",
libcfs_nid2str(peer_nid),
- HIPQUAD(peer_ip), peer_port,
+ &peer_ip, peer_port,
libcfs_nid2str(peer_nid));
break;
case -EPROTO:
LCONSOLE_ERROR_MSG(0x11c, "Protocol error connecting to %s at "
- "host %u.%u.%u.%u on port %d: is it running "
+ "host %pI4h on port %d: is it running "
"a compatible version of Lustre?\n",
libcfs_nid2str(peer_nid),
- HIPQUAD(peer_ip), peer_port);
+ &peer_ip, peer_port);
break;
case -EADDRINUSE:
LCONSOLE_ERROR_MSG(0x11d, "No privileged ports available to "
- "connect to %s at host %u.%u.%u.%u on port "
+ "connect to %s at host %pI4h on port "
"%d\n", libcfs_nid2str(peer_nid),
- HIPQUAD(peer_ip), peer_port);
+ &peer_ip, peer_port);
break;
default:
LCONSOLE_ERROR_MSG(0x11e, "Unexpected error %d connecting to %s"
- " at host %u.%u.%u.%u on port %d\n", rc,
+ " at host %pI4h on port %d\n", rc,
libcfs_nid2str(peer_nid),
- HIPQUAD(peer_ip), peer_port);
+ &peer_ip, peer_port);
break;
}
}
@@ -253,8 +253,8 @@ lnet_accept(socket_t *sock, __u32 magic)
if (rc != 0)
CERROR("Error sending magic+version in response"
- "to LNET magic from %u.%u.%u.%u: %d\n",
- HIPQUAD(peer_ip), rc);
+ "to LNET magic from %pI4h: %d\n",
+ &peer_ip, rc);
return -EPROTO;
}
@@ -265,9 +265,9 @@ lnet_accept(socket_t *sock, __u32 magic)
else
str = "unrecognised";
- LCONSOLE_ERROR_MSG(0x11f, "Refusing connection from %u.%u.%u.%u"
+ LCONSOLE_ERROR_MSG(0x11f, "Refusing connection from %pI4h"
" magic %08x: %s acceptor protocol\n",
- HIPQUAD(peer_ip), magic, str);
+ &peer_ip, magic, str);
return -EPROTO;
}
@@ -278,7 +278,7 @@ lnet_accept(socket_t *sock, __u32 magic)
accept_timeout);
if (rc != 0) {
CERROR("Error %d reading connection request version from "
- "%u.%u.%u.%u\n", rc, HIPQUAD(peer_ip));
+ "%pI4h\n", rc, &peer_ip);
return -EIO;
}
@@ -301,8 +301,8 @@ lnet_accept(socket_t *sock, __u32 magic)
if (rc != 0)
CERROR("Error sending magic+version in response"
- "to version %d from %u.%u.%u.%u: %d\n",
- peer_version, HIPQUAD(peer_ip), rc);
+ "to version %d from %pI4h: %d\n",
+ peer_version, &peer_ip, rc);
return -EPROTO;
}
@@ -312,7 +312,7 @@ lnet_accept(socket_t *sock, __u32 magic)
accept_timeout);
if (rc != 0) {
CERROR("Error %d reading connection request from "
- "%u.%u.%u.%u\n", rc, HIPQUAD(peer_ip));
+ "%pI4h\n", rc, &peer_ip);
return -EIO;
}
@@ -324,23 +324,23 @@ lnet_accept(socket_t *sock, __u32 magic)
ni->ni_nid != cr.acr_nid) { /* right NET, wrong NID! */
if (ni != NULL)
lnet_ni_decref(ni);
- LCONSOLE_ERROR_MSG(0x120, "Refusing connection from %u.%u.%u.%u"
+ LCONSOLE_ERROR_MSG(0x120, "Refusing connection from %pI4h"
" for %s: No matching NI\n",
- HIPQUAD(peer_ip), libcfs_nid2str(cr.acr_nid));
+ &peer_ip, libcfs_nid2str(cr.acr_nid));
return -EPERM;
}
if (ni->ni_lnd->lnd_accept == NULL) {
/* This catches a request for the loopback LND */
lnet_ni_decref(ni);
- LCONSOLE_ERROR_MSG(0x121, "Refusing connection from %u.%u.%u.%u"
+ LCONSOLE_ERROR_MSG(0x121, "Refusing connection from %pI4h"
" for %s: NI doesn not accept IP connections\n",
- HIPQUAD(peer_ip), libcfs_nid2str(cr.acr_nid));
+ &peer_ip, libcfs_nid2str(cr.acr_nid));
return -EPERM;
}
- CDEBUG(D_NET, "Accept %s from %u.%u.%u.%u\n",
- libcfs_nid2str(cr.acr_nid), HIPQUAD(peer_ip));
+ CDEBUG(D_NET, "Accept %s from %pI4h\n",
+ libcfs_nid2str(cr.acr_nid), &peer_ip);
rc = ni->ni_lnd->lnd_accept(ni, sock);
@@ -410,9 +410,9 @@ lnet_acceptor(void *arg)
}
if (secure && peer_port > LNET_ACCEPTOR_MAX_RESERVED_PORT) {
- CERROR("Refusing connection from %u.%u.%u.%u: "
+ CERROR("Refusing connection from %pI4h: "
"insecure port %d\n",
- HIPQUAD(peer_ip), peer_port);
+ &peer_ip, peer_port);
goto failed;
}
@@ -420,7 +420,7 @@ lnet_acceptor(void *arg)
accept_timeout);
if (rc != 0) {
CERROR("Error %d reading connection request from "
- "%u.%u.%u.%u\n", rc, HIPQUAD(peer_ip));
+ "%pI4h\n", rc, &peer_ip);
goto failed;
}
diff --git a/drivers/staging/lustre/lnet/lnet/api-errno.c b/drivers/staging/lustre/lnet/lnet/api-errno.c
deleted file mode 100644
index 695b27265e2..00000000000
--- a/drivers/staging/lustre/lnet/lnet/api-errno.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * lnet/lnet/api-errno.c
- *
- * Instantiate the string table of errors
- */
-
-/* If you change these, you must update the number table in portals/errno.h */
diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c
index e88bee36249..160a4292c6c 100644
--- a/drivers/staging/lustre/lnet/lnet/api-ni.c
+++ b/drivers/staging/lustre/lnet/lnet/api-ni.c
@@ -1371,7 +1371,7 @@ EXPORT_SYMBOL(LNetNIInit);
* \return always 0 for current implementation.
*/
int
-LNetNIFini()
+LNetNIFini(void)
{
LNET_MUTEX_LOCK(&the_lnet.ln_api_mutex);
@@ -1541,7 +1541,10 @@ LNetGetId(unsigned int index, lnet_process_id_t *id)
int rc = -ENOENT;
LASSERT(the_lnet.ln_init);
- LASSERT(the_lnet.ln_refcount > 0);
+
+ /* LNetNI initilization failed? */
+ if (the_lnet.ln_refcount == 0)
+ return rc;
cpt = lnet_net_lock_current();
diff --git a/drivers/staging/lustre/lnet/lnet/lib-eq.c b/drivers/staging/lustre/lnet/lnet/lib-eq.c
index 78297a7d94e..4ce68d3b093 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-eq.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-eq.c
@@ -244,11 +244,10 @@ lnet_eq_dequeue_event(lnet_eq_t *eq, lnet_event_t *ev)
int new_index = eq->eq_deq_seq & (eq->eq_size - 1);
lnet_event_t *new_event = &eq->eq_events[new_index];
int rc;
- ENTRY;
/* must called with lnet_eq_wait_lock hold */
if (LNET_SEQ_GT(eq->eq_deq_seq, new_event->sequence))
- RETURN(0);
+ return 0;
/* We've got a new event... */
*ev = *new_event;
@@ -268,7 +267,7 @@ lnet_eq_dequeue_event(lnet_eq_t *eq, lnet_event_t *ev)
}
eq->eq_deq_seq = new_event->sequence + 1;
- RETURN(rc);
+ return rc;
}
/**
@@ -400,13 +399,12 @@ LNetEQPoll(lnet_handle_eq_t *eventqs, int neq, int timeout_ms,
int wait = 1;
int rc;
int i;
- ENTRY;
LASSERT (the_lnet.ln_init);
LASSERT (the_lnet.ln_refcount > 0);
if (neq < 1)
- RETURN(-ENOENT);
+ return -ENOENT;
lnet_eq_wait_lock();
@@ -416,14 +414,14 @@ LNetEQPoll(lnet_handle_eq_t *eventqs, int neq, int timeout_ms,
if (eq == NULL) {
lnet_eq_wait_unlock();
- RETURN(-ENOENT);
+ return -ENOENT;
}
rc = lnet_eq_dequeue_event(eq, event);
if (rc != 0) {
lnet_eq_wait_unlock();
*which = i;
- RETURN(rc);
+ return rc;
}
}
@@ -443,5 +441,5 @@ LNetEQPoll(lnet_handle_eq_t *eventqs, int neq, int timeout_ms,
}
lnet_eq_wait_unlock();
- RETURN(0);
+ return 0;
}
diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c
index 8f3a50bd5f6..61ae88be6f0 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-msg.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c
@@ -45,8 +45,6 @@
void
lnet_build_unlink_event (lnet_libmd_t *md, lnet_event_t *ev)
{
- ENTRY;
-
memset(ev, 0, sizeof(*ev));
ev->status = 0;
@@ -54,7 +52,6 @@ lnet_build_unlink_event (lnet_libmd_t *md, lnet_event_t *ev)
ev->type = LNET_EVENT_UNLINK;
lnet_md_deconstruct(md, &ev->md);
lnet_md2handle(&ev->md_handle, md);
- EXIT;
}
/*
@@ -319,7 +316,7 @@ lnet_msg_attach_md(lnet_msg_t *msg, lnet_libmd_t *md,
LASSERT(!msg->msg_routing);
msg->msg_md = md;
- if (msg->msg_receiving) { /* commited for receiving */
+ if (msg->msg_receiving) { /* committed for receiving */
msg->msg_offset = offset;
msg->msg_wanted = mlen;
}
@@ -395,7 +392,7 @@ lnet_complete_msg_locked(lnet_msg_t *msg, int cpt)
* NB: message is committed for sending, we should return
* on success because LND will finalize this message later.
*
- * Also, there is possibility that message is commited for
+ * Also, there is possibility that message is committed for
* sending and also failed before delivering to LND,
* i.e: ENOMEM, in that case we can't fall through either
* because CPT for sending can be different with CPT for
@@ -417,7 +414,7 @@ lnet_complete_msg_locked(lnet_msg_t *msg, int cpt)
* NB: message is committed for sending, we should return
* on success because LND will finalize this message later.
*
- * Also, there is possibility that message is commited for
+ * Also, there is possibility that message is committed for
* sending and also failed before delivering to LND,
* i.e: ENOMEM, in that case we can't fall through either:
* - The rule is message must decommit for sending first if
@@ -477,14 +474,14 @@ lnet_finalize (lnet_ni_t *ni, lnet_msg_t *msg, int status)
again:
rc = 0;
if (!msg->msg_tx_committed && !msg->msg_rx_committed) {
- /* not commited to network yet */
+ /* not committed to network yet */
LASSERT(!msg->msg_onactivelist);
lnet_msg_free(msg);
return;
}
/*
- * NB: routed message can be commited for both receiving and sending,
+ * NB: routed message can be committed for both receiving and sending,
* we should finalize in LIFO order and keep counters correct.
* (finalize sending first then finalize receiving)
*/
diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c
index c8323854580..afb81755cba 100644
--- a/drivers/staging/lustre/lnet/lnet/module.c
+++ b/drivers/staging/lustre/lnet/lnet/module.c
@@ -114,14 +114,13 @@ int
init_lnet(void)
{
int rc;
- ENTRY;
mutex_init(&lnet_config_mutex);
rc = LNetInit();
if (rc != 0) {
CERROR("LNetInit: error %d\n", rc);
- RETURN(rc);
+ return rc;
}
rc = libcfs_register_ioctl(&lnet_ioctl_handler);
@@ -133,7 +132,7 @@ init_lnet(void)
(void) kthread_run(lnet_configure, NULL, "lnet_initd");
}
- RETURN(0);
+ return 0;
}
void
@@ -150,5 +149,7 @@ fini_lnet(void)
MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
MODULE_DESCRIPTION("Portals v3.1");
MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
-cfs_module(lnet, "1.0.0", init_lnet, fini_lnet);
+module_init(init_lnet);
+module_exit(fini_lnet);
diff --git a/drivers/staging/lustre/lnet/lnet/router_proc.c b/drivers/staging/lustre/lnet/lnet/router_proc.c
index 3084b0c7598..931f6ca25dc 100644
--- a/drivers/staging/lustre/lnet/lnet/router_proc.c
+++ b/drivers/staging/lustre/lnet/lnet/router_proc.c
@@ -920,7 +920,7 @@ lnet_proc_init(void)
{
#ifdef CONFIG_SYSCTL
if (lnet_table_header == NULL)
- lnet_table_header = cfs_register_sysctl_table(top_table, 0);
+ lnet_table_header = register_sysctl_table(top_table);
#endif
}
diff --git a/drivers/staging/lustre/lnet/selftest/brw_test.c b/drivers/staging/lustre/lnet/selftest/brw_test.c
index 3bb6fbe23f7..ef5064e0055 100644
--- a/drivers/staging/lustre/lnet/selftest/brw_test.c
+++ b/drivers/staging/lustre/lnet/selftest/brw_test.c
@@ -361,7 +361,7 @@ brw_server_rpc_done (srpc_server_rpc_t *rpc)
blk->bk_sink ? "from" : "to",
libcfs_id2str(rpc->srpc_peer), rpc->srpc_status);
else
- CDEBUG (D_NET, "Transfered %d pages bulk data %s %s\n",
+ CDEBUG (D_NET, "Transferred %d pages bulk data %s %s\n",
blk->bk_niov, blk->bk_sink ? "from" : "to",
libcfs_id2str(rpc->srpc_peer));
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c
index 446de0e4672..cbce662b987 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.c
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.c
@@ -1356,7 +1356,7 @@ lstcon_rpc_cleanup_wait(void)
lst_wait_until((atomic_read(&console_session.ses_rpc_counter) == 0),
console_session.ses_rpc_lock,
- "Network is not accessable or target is down, "
+ "Network is not accessible or target is down, "
"waiting for %d console RPCs to being recycled\n",
atomic_read(&console_session.ses_rpc_counter));
diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c
index 78e8d046726..09e4700af64 100644
--- a/drivers/staging/lustre/lnet/selftest/console.c
+++ b/drivers/staging/lustre/lnet/selftest/console.c
@@ -1773,7 +1773,7 @@ lstcon_session_info(lst_sid_t *sid_up, int *key_up, unsigned *featp,
}
int
-lstcon_session_end()
+lstcon_session_end(void)
{
lstcon_rpc_trans_t *trans;
lstcon_group_t *grp;
diff --git a/drivers/staging/lustre/lnet/selftest/module.c b/drivers/staging/lustre/lnet/selftest/module.c
index 5257e5630a0..6dd4309dc5e 100644
--- a/drivers/staging/lustre/lnet/selftest/module.c
+++ b/drivers/staging/lustre/lnet/selftest/module.c
@@ -165,5 +165,7 @@ error:
MODULE_DESCRIPTION("LNet Selftest");
MODULE_LICENSE("GPL");
+MODULE_VERSION("0.9.0");
-cfs_module(lnet, "0.9.0", lnet_selftest_init, lnet_selftest_fini);
+module_init(lnet_selftest_init);
+module_exit(lnet_selftest_fini);
diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c
index bc1f38b8048..7659a26676b 100644
--- a/drivers/staging/lustre/lnet/selftest/rpc.c
+++ b/drivers/staging/lustre/lnet/selftest/rpc.c
@@ -661,8 +661,10 @@ srpc_finish_service(struct srpc_service *sv)
cfs_percpt_for_each(scd, i, sv->sv_cpt_data) {
spin_lock(&scd->scd_lock);
- if (!swi_deschedule_workitem(&scd->scd_buf_wi))
+ if (!swi_deschedule_workitem(&scd->scd_buf_wi)) {
+ spin_unlock(&scd->scd_lock);
return 0;
+ }
if (scd->scd_buf_nposted > 0) {
CDEBUG(D_NET, "waiting for %d posted buffers to unlink",
@@ -1115,7 +1117,7 @@ srpc_del_client_rpc_timer (srpc_client_rpc_t *rpc)
if (rpc->crpc_timeout == 0)
return;
- /* timer sucessfully defused */
+ /* timer successfully defused */
if (stt_del_timer(&rpc->crpc_timer))
return;
diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c
index 2c078550277..3bf4afb42ff 100644
--- a/drivers/staging/lustre/lnet/selftest/timer.c
+++ b/drivers/staging/lustre/lnet/selftest/timer.c
@@ -195,7 +195,7 @@ stt_timer_main (void *arg)
int
stt_start_timer_thread (void)
{
- task_t *task;
+ struct task_struct *task;
LASSERT(!stt_data.stt_shuttingdown);
diff --git a/drivers/staging/lustre/lustre/Kconfig b/drivers/staging/lustre/lustre/Kconfig
index e0eb8303a50..4e898e49186 100644
--- a/drivers/staging/lustre/lustre/Kconfig
+++ b/drivers/staging/lustre/lustre/Kconfig
@@ -1,6 +1,6 @@
config LUSTRE_FS
tristate "Lustre file system client support"
- depends on STAGING && INET && BROKEN
+ depends on INET && m
select LNET
select CRYPTO
select CRYPTO_CRC32
@@ -43,9 +43,18 @@ config LUSTRE_OBD_MAX_IOCTL_BUFFER
config LUSTRE_DEBUG_EXPENSIVE_CHECK
bool "Enable Lustre DEBUG checks"
depends on LUSTRE_FS
- default false
help
This option is mainly for debug purpose. It enables Lustre code to do
expensive checks that may have a performance impact.
Use with caution. If unsure, say N.
+
+config LUSTRE_TRANSLATE_ERRNOS
+ bool
+ depends on LUSTRE_FS && !X86
+ default true
+
+config LUSTRE_LLITE_LLOOP
+ bool "Lustre virtual block device"
+ depends on LUSTRE_FS && BLOCK
+ default m
diff --git a/drivers/staging/lustre/lustre/Makefile b/drivers/staging/lustre/lustre/Makefile
index 3fb94fc1206..d1eb0bdef06 100644
--- a/drivers/staging/lustre/lustre/Makefile
+++ b/drivers/staging/lustre/lustre/Makefile
@@ -1,2 +1,2 @@
-obj-$(CONFIG_LUSTRE_FS) := fid/ lvfs/ obdclass/ ptlrpc/ obdecho/ mgc/ lov/ \
- osc/ mdc/ lmv/ llite/ fld/ libcfs/
+obj-$(CONFIG_LUSTRE_FS) += libcfs/ lvfs/ obdclass/ ptlrpc/ fld/ osc/ mgc/ \
+ fid/ lov/ mdc/ lmv/ llite/ obdecho/
diff --git a/drivers/staging/lustre/lustre/fid/Makefile b/drivers/staging/lustre/lustre/fid/Makefile
index b8d6d21b39f..ed21bea162b 100644
--- a/drivers/staging/lustre/lustre/fid/Makefile
+++ b/drivers/staging/lustre/lustre/fid/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_LUSTRE_FS) += fid.o
-fid-y := fid_handler.o fid_store.o fid_request.o lproc_fid.o fid_lib.o
+fid-y := fid_request.o lproc_fid.o fid_lib.o
ccflags-y := -I$(src)/../include
diff --git a/drivers/staging/lustre/lustre/fid/fid_handler.c b/drivers/staging/lustre/lustre/fid/fid_handler.c
deleted file mode 100644
index bbbb3cfe57b..00000000000
--- a/drivers/staging/lustre/lustre/fid/fid_handler.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2012, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * lustre/fid/fid_handler.c
- *
- * Lustre Sequence Manager
- *
- * Author: Yury Umanets <umka@clusterfs.com>
- */
-
-#define DEBUG_SUBSYSTEM S_FID
-
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
-
-#include <obd.h>
-#include <obd_class.h>
-#include <dt_object.h>
-#include <md_object.h>
-#include <obd_support.h>
-#include <lustre_req_layout.h>
-#include <lustre_fid.h>
-#include "fid_internal.h"
-
-int client_fid_init(struct obd_device *obd,
- struct obd_export *exp, enum lu_cli_type type)
-{
- struct client_obd *cli = &obd->u.cli;
- char *prefix;
- int rc;
- ENTRY;
-
- OBD_ALLOC_PTR(cli->cl_seq);
- if (cli->cl_seq == NULL)
- RETURN(-ENOMEM);
-
- OBD_ALLOC(prefix, MAX_OBD_NAME + 5);
- if (prefix == NULL)
- GOTO(out_free_seq, rc = -ENOMEM);
-
- snprintf(prefix, MAX_OBD_NAME + 5, "cli-%s", obd->obd_name);
-
- /* Init client side sequence-manager */
- rc = seq_client_init(cli->cl_seq, exp, type, prefix, NULL);
- OBD_FREE(prefix, MAX_OBD_NAME + 5);
- if (rc)
- GOTO(out_free_seq, rc);
-
- RETURN(rc);
-out_free_seq:
- OBD_FREE_PTR(cli->cl_seq);
- cli->cl_seq = NULL;
- return rc;
-}
-EXPORT_SYMBOL(client_fid_init);
-
-int client_fid_fini(struct obd_device *obd)
-{
- struct client_obd *cli = &obd->u.cli;
- ENTRY;
-
- if (cli->cl_seq != NULL) {
- seq_client_fini(cli->cl_seq);
- OBD_FREE_PTR(cli->cl_seq);
- cli->cl_seq = NULL;
- }
-
- RETURN(0);
-}
-EXPORT_SYMBOL(client_fid_fini);
-
-static void seq_server_proc_fini(struct lu_server_seq *seq);
-
-/* Assigns client to sequence controller node. */
-int seq_server_set_cli(struct lu_server_seq *seq,
- struct lu_client_seq *cli,
- const struct lu_env *env)
-{
- int rc = 0;
- ENTRY;
-
- /*
- * Ask client for new range, assign that range to ->seq_space and write
- * seq state to backing store should be atomic.
- */
- mutex_lock(&seq->lss_mutex);
-
- if (cli == NULL) {
- CDEBUG(D_INFO, "%s: Detached sequence client %s\n",
- seq->lss_name, cli->lcs_name);
- seq->lss_cli = cli;
- GOTO(out_up, rc = 0);
- }
-
- if (seq->lss_cli != NULL) {
- CDEBUG(D_HA, "%s: Sequence controller is already "
- "assigned\n", seq->lss_name);
- GOTO(out_up, rc = -EEXIST);
- }
-
- CDEBUG(D_INFO, "%s: Attached sequence controller %s\n",
- seq->lss_name, cli->lcs_name);
-
- seq->lss_cli = cli;
- cli->lcs_space.lsr_index = seq->lss_site->ss_node_id;
- EXIT;
-out_up:
- mutex_unlock(&seq->lss_mutex);
- return rc;
-}
-EXPORT_SYMBOL(seq_server_set_cli);
-/*
- * allocate \a w units of sequence from range \a from.
- */
-static inline void range_alloc(struct lu_seq_range *to,
- struct lu_seq_range *from,
- __u64 width)
-{
- width = min(range_space(from), width);
- to->lsr_start = from->lsr_start;
- to->lsr_end = from->lsr_start + width;
- from->lsr_start += width;
-}
-
-/**
- * On controller node, allocate new super sequence for regular sequence server.
- * As this super sequence controller, this node suppose to maintain fld
- * and update index.
- * \a out range always has currect mds node number of requester.
- */
-
-static int __seq_server_alloc_super(struct lu_server_seq *seq,
- struct lu_seq_range *out,
- const struct lu_env *env)
-{
- struct lu_seq_range *space = &seq->lss_space;
- int rc;
- ENTRY;
-
- LASSERT(range_is_sane(space));
-
- if (range_is_exhausted(space)) {
- CERROR("%s: Sequences space is exhausted\n",
- seq->lss_name);
- RETURN(-ENOSPC);
- } else {
- range_alloc(out, space, seq->lss_width);
- }
-
- rc = seq_store_update(env, seq, out, 1 /* sync */);
-
- LCONSOLE_INFO("%s: super-sequence allocation rc = %d " DRANGE"\n",
- seq->lss_name, rc, PRANGE(out));
-
- RETURN(rc);
-}
-
-int seq_server_alloc_super(struct lu_server_seq *seq,
- struct lu_seq_range *out,
- const struct lu_env *env)
-{
- int rc;
- ENTRY;
-
- mutex_lock(&seq->lss_mutex);
- rc = __seq_server_alloc_super(seq, out, env);
- mutex_unlock(&seq->lss_mutex);
-
- RETURN(rc);
-}
-
-static int __seq_set_init(const struct lu_env *env,
- struct lu_server_seq *seq)
-{
- struct lu_seq_range *space = &seq->lss_space;
- int rc;
-
- range_alloc(&seq->lss_lowater_set, space, seq->lss_set_width);
- range_alloc(&seq->lss_hiwater_set, space, seq->lss_set_width);
-
- rc = seq_store_update(env, seq, NULL, 1);
-
- return rc;
-}
-
-/*
- * This function implements new seq allocation algorithm using async
- * updates to seq file on disk. ref bug 18857 for details.
- * there are four variable to keep track of this process
- *
- * lss_space; - available lss_space
- * lss_lowater_set; - lu_seq_range for all seqs before barrier, i.e. safe to use
- * lss_hiwater_set; - lu_seq_range after barrier, i.e. allocated but may be
- * not yet committed
- *
- * when lss_lowater_set reaches the end it is replaced with hiwater one and
- * a write operation is initiated to allocate new hiwater range.
- * if last seq write opearion is still not commited, current operation is
- * flaged as sync write op.
- */
-static int range_alloc_set(const struct lu_env *env,
- struct lu_seq_range *out,
- struct lu_server_seq *seq)
-{
- struct lu_seq_range *space = &seq->lss_space;
- struct lu_seq_range *loset = &seq->lss_lowater_set;
- struct lu_seq_range *hiset = &seq->lss_hiwater_set;
- int rc = 0;
-
- if (range_is_zero(loset))
- __seq_set_init(env, seq);
-
- if (OBD_FAIL_CHECK(OBD_FAIL_SEQ_ALLOC)) /* exhaust set */
- loset->lsr_start = loset->lsr_end;
-
- if (range_is_exhausted(loset)) {
- /* reached high water mark. */
- struct lu_device *dev = seq->lss_site->ss_lu->ls_top_dev;
- int obd_num_clients = dev->ld_obd->obd_num_exports;
- __u64 set_sz;
-
- /* calculate new seq width based on number of clients */
- set_sz = max(seq->lss_set_width,
- obd_num_clients * seq->lss_width);
- set_sz = min(range_space(space), set_sz);
-
- /* Switch to hiwater range now */
- *loset = *hiset;
- /* allocate new hiwater range */
- range_alloc(hiset, space, set_sz);
-
- /* update ondisk seq with new *space */
- rc = seq_store_update(env, seq, NULL, seq->lss_need_sync);
- }
-
- LASSERTF(!range_is_exhausted(loset) || range_is_sane(loset),
- DRANGE"\n", PRANGE(loset));
-
- if (rc == 0)
- range_alloc(out, loset, seq->lss_width);
-
- RETURN(rc);
-}
-
-static int __seq_server_alloc_meta(struct lu_server_seq *seq,
- struct lu_seq_range *out,
- const struct lu_env *env)
-{
- struct lu_seq_range *space = &seq->lss_space;
- int rc = 0;
-
- ENTRY;
-
- LASSERT(range_is_sane(space));
-
- /* Check if available space ends and allocate new super seq */
- if (range_is_exhausted(space)) {
- if (!seq->lss_cli) {
- CERROR("%s: No sequence controller is attached.\n",
- seq->lss_name);
- RETURN(-ENODEV);
- }
-
- rc = seq_client_alloc_super(seq->lss_cli, env);
- if (rc) {
- CERROR("%s: Can't allocate super-sequence, rc %d\n",
- seq->lss_name, rc);
- RETURN(rc);
- }
-
- /* Saving new range to allocation space. */
- *space = seq->lss_cli->lcs_space;
- LASSERT(range_is_sane(space));
- }
-
- rc = range_alloc_set(env, out, seq);
- if (rc != 0) {
- CERROR("%s: Allocated meta-sequence failed: rc = %d\n",
- seq->lss_name, rc);
- RETURN(rc);
- }
-
- CDEBUG(D_INFO, "%s: Allocated meta-sequence " DRANGE"\n",
- seq->lss_name, PRANGE(out));
-
- RETURN(rc);
-}
-
-int seq_server_alloc_meta(struct lu_server_seq *seq,
- struct lu_seq_range *out,
- const struct lu_env *env)
-{
- int rc;
- ENTRY;
-
- mutex_lock(&seq->lss_mutex);
- rc = __seq_server_alloc_meta(seq, out, env);
- mutex_unlock(&seq->lss_mutex);
-
- RETURN(rc);
-}
-EXPORT_SYMBOL(seq_server_alloc_meta);
-
-static int seq_server_handle(struct lu_site *site,
- const struct lu_env *env,
- __u32 opc, struct lu_seq_range *out)
-{
- int rc;
- struct seq_server_site *ss_site;
- ENTRY;
-
- ss_site = lu_site2seq(site);
-
- switch (opc) {
- case SEQ_ALLOC_META:
- if (!ss_site->ss_server_seq) {
- CERROR("Sequence server is not "
- "initialized\n");
- RETURN(-EINVAL);
- }
- rc = seq_server_alloc_meta(ss_site->ss_server_seq, out, env);
- break;
- case SEQ_ALLOC_SUPER:
- if (!ss_site->ss_control_seq) {
- CERROR("Sequence controller is not "
- "initialized\n");
- RETURN(-EINVAL);
- }
- rc = seq_server_alloc_super(ss_site->ss_control_seq, out, env);
- break;
- default:
- rc = -EINVAL;
- break;
- }
-
- RETURN(rc);
-}
-
-static int seq_req_handle(struct ptlrpc_request *req,
- const struct lu_env *env,
- struct seq_thread_info *info)
-{
- struct lu_seq_range *out, *tmp;
- struct lu_site *site;
- int rc = -EPROTO;
- __u32 *opc;
- ENTRY;
-
- LASSERT(!(lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY));
- site = req->rq_export->exp_obd->obd_lu_dev->ld_site;
- LASSERT(site != NULL);
-
- rc = req_capsule_server_pack(info->sti_pill);
- if (rc)
- RETURN(err_serious(rc));
-
- opc = req_capsule_client_get(info->sti_pill, &RMF_SEQ_OPC);
- if (opc != NULL) {
- out = req_capsule_server_get(info->sti_pill, &RMF_SEQ_RANGE);
- if (out == NULL)
- RETURN(err_serious(-EPROTO));
-
- tmp = req_capsule_client_get(info->sti_pill, &RMF_SEQ_RANGE);
-
- /* seq client passed mdt id, we need to pass that using out
- * range parameter */
-
- out->lsr_index = tmp->lsr_index;
- out->lsr_flags = tmp->lsr_flags;
- rc = seq_server_handle(site, env, *opc, out);
- } else
- rc = err_serious(-EPROTO);
-
- RETURN(rc);
-}
-
-/* context key constructor/destructor: seq_key_init, seq_key_fini */
-LU_KEY_INIT_FINI(seq, struct seq_thread_info);
-
-/* context key: seq_thread_key */
-LU_CONTEXT_KEY_DEFINE(seq, LCT_MD_THREAD | LCT_DT_THREAD);
-
-static void seq_thread_info_init(struct ptlrpc_request *req,
- struct seq_thread_info *info)
-{
- info->sti_pill = &req->rq_pill;
- /* Init request capsule */
- req_capsule_init(info->sti_pill, req, RCL_SERVER);
- req_capsule_set(info->sti_pill, &RQF_SEQ_QUERY);
-}
-
-static void seq_thread_info_fini(struct seq_thread_info *info)
-{
- req_capsule_fini(info->sti_pill);
-}
-
-int seq_handle(struct ptlrpc_request *req)
-{
- const struct lu_env *env;
- struct seq_thread_info *info;
- int rc;
-
- env = req->rq_svc_thread->t_env;
- LASSERT(env != NULL);
-
- info = lu_context_key_get(&env->le_ctx, &seq_thread_key);
- LASSERT(info != NULL);
-
- seq_thread_info_init(req, info);
- rc = seq_req_handle(req, env, info);
- /* XXX: we don't need replay but MDT assign transno in any case,
- * remove it manually before reply*/
- lustre_msg_set_transno(req->rq_repmsg, 0);
- seq_thread_info_fini(info);
-
- return rc;
-}
-EXPORT_SYMBOL(seq_handle);
-
-/*
- * Entry point for handling FLD RPCs called from MDT.
- */
-int seq_query(struct com_thread_info *info)
-{
- return seq_handle(info->cti_pill->rc_req);
-}
-EXPORT_SYMBOL(seq_query);
-
-
-#ifdef LPROCFS
-static int seq_server_proc_init(struct lu_server_seq *seq)
-{
- int rc;
- ENTRY;
-
- seq->lss_proc_dir = lprocfs_register(seq->lss_name,
- seq_type_proc_dir,
- NULL, NULL);
- if (IS_ERR(seq->lss_proc_dir)) {
- rc = PTR_ERR(seq->lss_proc_dir);
- RETURN(rc);
- }
-
- rc = lprocfs_add_vars(seq->lss_proc_dir,
- seq_server_proc_list, seq);
- if (rc) {
- CERROR("%s: Can't init sequence manager "
- "proc, rc %d\n", seq->lss_name, rc);
- GOTO(out_cleanup, rc);
- }
-
- RETURN(0);
-
-out_cleanup:
- seq_server_proc_fini(seq);
- return rc;
-}
-
-static void seq_server_proc_fini(struct lu_server_seq *seq)
-{
- ENTRY;
- if (seq->lss_proc_dir != NULL) {
- if (!IS_ERR(seq->lss_proc_dir))
- lprocfs_remove(&seq->lss_proc_dir);
- seq->lss_proc_dir = NULL;
- }
- EXIT;
-}
-#else
-static int seq_server_proc_init(struct lu_server_seq *seq)
-{
- return 0;
-}
-
-static void seq_server_proc_fini(struct lu_server_seq *seq)
-{
- return;
-}
-#endif
-
-
-int seq_server_init(struct lu_server_seq *seq,
- struct dt_device *dev,
- const char *prefix,
- enum lu_mgr_type type,
- struct seq_server_site *ss,
- const struct lu_env *env)
-{
- int rc, is_srv = (type == LUSTRE_SEQ_SERVER);
- ENTRY;
-
- LASSERT(dev != NULL);
- LASSERT(prefix != NULL);
- LASSERT(ss != NULL);
- LASSERT(ss->ss_lu != NULL);
-
- seq->lss_cli = NULL;
- seq->lss_type = type;
- seq->lss_site = ss;
- range_init(&seq->lss_space);
-
- range_init(&seq->lss_lowater_set);
- range_init(&seq->lss_hiwater_set);
- seq->lss_set_width = LUSTRE_SEQ_BATCH_WIDTH;
-
- mutex_init(&seq->lss_mutex);
-
- seq->lss_width = is_srv ?
- LUSTRE_SEQ_META_WIDTH : LUSTRE_SEQ_SUPER_WIDTH;
-
- snprintf(seq->lss_name, sizeof(seq->lss_name),
- "%s-%s", (is_srv ? "srv" : "ctl"), prefix);
-
- rc = seq_store_init(seq, env, dev);
- if (rc)
- GOTO(out, rc);
- /* Request backing store for saved sequence info. */
- rc = seq_store_read(seq, env);
- if (rc == -ENODATA) {
-
- /* Nothing is read, init by default value. */
- seq->lss_space = is_srv ?
- LUSTRE_SEQ_ZERO_RANGE:
- LUSTRE_SEQ_SPACE_RANGE;
-
- LASSERT(ss != NULL);
- seq->lss_space.lsr_index = ss->ss_node_id;
- LCONSOLE_INFO("%s: No data found "
- "on store. Initialize space\n",
- seq->lss_name);
-
- rc = seq_store_update(env, seq, NULL, 0);
- if (rc) {
- CERROR("%s: Can't write space data, "
- "rc %d\n", seq->lss_name, rc);
- }
- } else if (rc) {
- CERROR("%s: Can't read space data, rc %d\n",
- seq->lss_name, rc);
- GOTO(out, rc);
- }
-
- if (is_srv) {
- LASSERT(range_is_sane(&seq->lss_space));
- } else {
- LASSERT(!range_is_zero(&seq->lss_space) &&
- range_is_sane(&seq->lss_space));
- }
-
- rc = seq_server_proc_init(seq);
- if (rc)
- GOTO(out, rc);
-
- EXIT;
-out:
- if (rc)
- seq_server_fini(seq, env);
- return rc;
-}
-EXPORT_SYMBOL(seq_server_init);
-
-void seq_server_fini(struct lu_server_seq *seq,
- const struct lu_env *env)
-{
- ENTRY;
-
- seq_server_proc_fini(seq);
- seq_store_fini(seq, env);
-
- EXIT;
-}
-EXPORT_SYMBOL(seq_server_fini);
-
-int seq_site_fini(const struct lu_env *env, struct seq_server_site *ss)
-{
- if (ss == NULL)
- RETURN(0);
-
- if (ss->ss_server_seq) {
- seq_server_fini(ss->ss_server_seq, env);
- OBD_FREE_PTR(ss->ss_server_seq);
- ss->ss_server_seq = NULL;
- }
-
- if (ss->ss_control_seq) {
- seq_server_fini(ss->ss_control_seq, env);
- OBD_FREE_PTR(ss->ss_control_seq);
- ss->ss_control_seq = NULL;
- }
-
- if (ss->ss_client_seq) {
- seq_client_fini(ss->ss_client_seq);
- OBD_FREE_PTR(ss->ss_client_seq);
- ss->ss_client_seq = NULL;
- }
-
- RETURN(0);
-}
-EXPORT_SYMBOL(seq_site_fini);
-
-proc_dir_entry_t *seq_type_proc_dir = NULL;
-
-static int __init fid_mod_init(void)
-{
- seq_type_proc_dir = lprocfs_register(LUSTRE_SEQ_NAME,
- proc_lustre_root,
- NULL, NULL);
- if (IS_ERR(seq_type_proc_dir))
- return PTR_ERR(seq_type_proc_dir);
-
- LU_CONTEXT_KEY_INIT(&seq_thread_key);
- lu_context_key_register(&seq_thread_key);
- return 0;
-}
-
-static void __exit fid_mod_exit(void)
-{
- lu_context_key_degister(&seq_thread_key);
- if (seq_type_proc_dir != NULL && !IS_ERR(seq_type_proc_dir)) {
- lprocfs_remove(&seq_type_proc_dir);
- seq_type_proc_dir = NULL;
- }
-}
-
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
-MODULE_DESCRIPTION("Lustre FID Module");
-MODULE_LICENSE("GPL");
-
-cfs_module(fid, "0.1.0", fid_mod_init, fid_mod_exit);
diff --git a/drivers/staging/lustre/lustre/fid/fid_internal.h b/drivers/staging/lustre/lustre/fid/fid_internal.h
index 407a7435583..1dbe46be0f4 100644
--- a/drivers/staging/lustre/lustre/fid/fid_internal.h
+++ b/drivers/staging/lustre/lustre/fid/fid_internal.h
@@ -41,44 +41,16 @@
#define __FID_INTERNAL_H
#include <lustre/lustre_idl.h>
-#include <dt_object.h>
-
#include <linux/libcfs/libcfs.h>
-struct seq_thread_info {
- struct req_capsule *sti_pill;
- struct lu_seq_range sti_space;
- struct lu_buf sti_buf;
-};
-
-enum {
- SEQ_TXN_STORE_CREDITS = 20
-};
-
-extern struct lu_context_key seq_thread_key;
-
+/* Functions used internally in module. */
int seq_client_alloc_super(struct lu_client_seq *seq,
const struct lu_env *env);
-/* Store API functions. */
-int seq_store_init(struct lu_server_seq *seq,
- const struct lu_env *env,
- struct dt_device *dt);
-void seq_store_fini(struct lu_server_seq *seq,
- const struct lu_env *env);
-
-int seq_store_read(struct lu_server_seq *seq,
- const struct lu_env *env);
-
-int seq_store_update(const struct lu_env *env, struct lu_server_seq *seq,
- struct lu_seq_range *out, int sync);
-
-#ifdef LPROCFS
-extern struct lprocfs_vars seq_server_proc_list[];
+# ifdef LPROCFS
extern struct lprocfs_vars seq_client_proc_list[];
-#endif
-
+# endif
-extern proc_dir_entry_t *seq_type_proc_dir;
+extern struct proc_dir_entry *seq_type_proc_dir;
#endif /* __FID_INTERNAL_H */
diff --git a/drivers/staging/lustre/lustre/fid/fid_lib.c b/drivers/staging/lustre/lustre/fid/fid_lib.c
index eaff51a555f..f03afdec027 100644
--- a/drivers/staging/lustre/lustre/fid/fid_lib.c
+++ b/drivers/staging/lustre/lustre/fid/fid_lib.c
@@ -43,11 +43,9 @@
#define DEBUG_SUBSYSTEM S_FID
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
-
-#include <obd.h>
-#include <lu_object.h>
+#include <linux/libcfs/libcfs.h>
+#include <linux/module.h>
+#include <lustre/lustre_idl.h>
#include <lustre_fid.h>
/**
@@ -56,9 +54,9 @@
*
* Fid namespace:
* <pre>
- * Normal FID: seq:64 [2^33,2^64-1] oid:32 ver:32
- * IGIF : 0:32, ino:32 gen:32 0:32
- * IDIF : 0:31, 1:1, ost-index:16, objd:48 0:32
+ * Normal FID: seq:64 [2^33,2^64-1] oid:32 ver:32
+ * IGIF : 0:32, ino:32 gen:32 0:32
+ * IDIF : 0:31, 1:1, ost-index:16, objd:48 0:32
* </pre>
*
* The first 0x400 sequences of normal FID are reserved for special purpose.
diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c
index fcaaca7e2e0..66007b57018 100644
--- a/drivers/staging/lustre/lustre/fid/fid_request.c
+++ b/drivers/staging/lustre/lustre/fid/fid_request.c
@@ -27,7 +27,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2013, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
@@ -42,15 +42,12 @@
#define DEBUG_SUBSYSTEM S_FID
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
+#include <linux/libcfs/libcfs.h>
+#include <linux/module.h>
#include <obd.h>
#include <obd_class.h>
-#include <dt_object.h>
-#include <md_object.h>
#include <obd_support.h>
-#include <lustre_req_layout.h>
#include <lustre_fid.h>
/* mdc RPC locks */
#include <lustre_mdc.h>
@@ -63,15 +60,14 @@ static int seq_client_rpc(struct lu_client_seq *seq,
struct obd_export *exp = seq->lcs_exp;
struct ptlrpc_request *req;
struct lu_seq_range *out, *in;
- __u32 *op;
- unsigned int debug_mask;
- int rc;
- ENTRY;
+ __u32 *op;
+ unsigned int debug_mask;
+ int rc;
req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp), &RQF_SEQ_QUERY,
LUSTRE_MDS_VERSION, SEQ_QUERY);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* Init operation code */
op = req_capsule_client_get(&req->rq_pill, &RMF_SEQ_OPC);
@@ -137,7 +133,6 @@ static int seq_client_rpc(struct lu_client_seq *seq,
CDEBUG_LIMIT(debug_mask, "%s: Allocated %s-sequence "DRANGE"]\n",
seq->lcs_name, opcname, PRANGE(output));
- EXIT;
out_req:
ptlrpc_req_finished(req);
return rc;
@@ -148,27 +143,24 @@ int seq_client_alloc_super(struct lu_client_seq *seq,
const struct lu_env *env)
{
int rc;
- ENTRY;
mutex_lock(&seq->lcs_mutex);
if (seq->lcs_srv) {
- LASSERT(env != NULL);
- rc = seq_server_alloc_super(seq->lcs_srv, &seq->lcs_space,
- env);
+ rc = 0;
} else {
/* Check whether the connection to seq controller has been
* setup (lcs_exp != NULL) */
if (seq->lcs_exp == NULL) {
mutex_unlock(&seq->lcs_mutex);
- RETURN(-EINPROGRESS);
+ return -EINPROGRESS;
}
rc = seq_client_rpc(seq, &seq->lcs_space,
SEQ_ALLOC_SUPER, "super");
}
mutex_unlock(&seq->lcs_mutex);
- RETURN(rc);
+ return rc;
}
/* Request sequence-controller node to allocate new meta-sequence. */
@@ -176,11 +168,9 @@ static int seq_client_alloc_meta(const struct lu_env *env,
struct lu_client_seq *seq)
{
int rc;
- ENTRY;
if (seq->lcs_srv) {
- LASSERT(env != NULL);
- rc = seq_server_alloc_meta(seq->lcs_srv, &seq->lcs_space, env);
+ rc = 0;
} else {
do {
/* If meta server return -EINPROGRESS or EAGAIN,
@@ -191,7 +181,8 @@ static int seq_client_alloc_meta(const struct lu_env *env,
SEQ_ALLOC_META, "meta");
} while (rc == -EINPROGRESS || rc == -EAGAIN);
}
- RETURN(rc);
+
+ return rc;
}
/* Allocate new sequence for client. */
@@ -199,7 +190,6 @@ static int seq_client_alloc_seq(const struct lu_env *env,
struct lu_client_seq *seq, seqno_t *seqnr)
{
int rc;
- ENTRY;
LASSERT(range_is_sane(&seq->lcs_space));
@@ -208,7 +198,7 @@ static int seq_client_alloc_seq(const struct lu_env *env,
if (rc) {
CERROR("%s: Can't allocate new meta-sequence,"
"rc %d\n", seq->lcs_name, rc);
- RETURN(rc);
+ return rc;
} else {
CDEBUG(D_INFO, "%s: New range - "DRANGE"\n",
seq->lcs_name, PRANGE(&seq->lcs_space));
@@ -224,7 +214,7 @@ static int seq_client_alloc_seq(const struct lu_env *env,
CDEBUG(D_INFO, "%s: Allocated sequence ["LPX64"]\n", seq->lcs_name,
*seqnr);
- RETURN(rc);
+ return rc;
}
static int seq_fid_alloc_prep(struct lu_client_seq *seq,
@@ -312,7 +302,6 @@ int seq_client_alloc_fid(const struct lu_env *env,
{
wait_queue_t link;
int rc;
- ENTRY;
LASSERT(seq != NULL);
LASSERT(fid != NULL);
@@ -344,7 +333,7 @@ int seq_client_alloc_fid(const struct lu_env *env,
"rc %d\n", seq->lcs_name, rc);
seq_fid_alloc_fini(seq);
mutex_unlock(&seq->lcs_mutex);
- RETURN(rc);
+ return rc;
}
CDEBUG(D_INFO, "%s: Switch to sequence "
@@ -368,7 +357,7 @@ int seq_client_alloc_fid(const struct lu_env *env,
mutex_unlock(&seq->lcs_mutex);
CDEBUG(D_INFO, "%s: Allocated FID "DFID"\n", seq->lcs_name, PFID(fid));
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(seq_client_alloc_fid);
@@ -409,13 +398,21 @@ void seq_client_flush(struct lu_client_seq *seq)
}
EXPORT_SYMBOL(seq_client_flush);
-static void seq_client_proc_fini(struct lu_client_seq *seq);
-
+static void seq_client_proc_fini(struct lu_client_seq *seq)
+{
#ifdef LPROCFS
+ if (seq->lcs_proc_dir) {
+ if (!IS_ERR(seq->lcs_proc_dir))
+ lprocfs_remove(&seq->lcs_proc_dir);
+ seq->lcs_proc_dir = NULL;
+ }
+#endif /* LPROCFS */
+}
+
static int seq_client_proc_init(struct lu_client_seq *seq)
{
+#ifdef LPROCFS
int rc;
- ENTRY;
seq->lcs_proc_dir = lprocfs_register(seq->lcs_name,
seq_type_proc_dir,
@@ -425,7 +422,7 @@ static int seq_client_proc_init(struct lu_client_seq *seq)
CERROR("%s: LProcFS failed in seq-init\n",
seq->lcs_name);
rc = PTR_ERR(seq->lcs_proc_dir);
- RETURN(rc);
+ return rc;
}
rc = lprocfs_add_vars(seq->lcs_proc_dir,
@@ -436,34 +433,16 @@ static int seq_client_proc_init(struct lu_client_seq *seq)
GOTO(out_cleanup, rc);
}
- RETURN(0);
+ return 0;
out_cleanup:
seq_client_proc_fini(seq);
return rc;
-}
-static void seq_client_proc_fini(struct lu_client_seq *seq)
-{
- ENTRY;
- if (seq->lcs_proc_dir) {
- if (!IS_ERR(seq->lcs_proc_dir))
- lprocfs_remove(&seq->lcs_proc_dir);
- seq->lcs_proc_dir = NULL;
- }
- EXIT;
-}
-#else
-static int seq_client_proc_init(struct lu_client_seq *seq)
-{
+#else /* LPROCFS */
return 0;
-}
-
-static void seq_client_proc_fini(struct lu_client_seq *seq)
-{
- return;
-}
#endif
+}
int seq_client_init(struct lu_client_seq *seq,
struct obd_export *exp,
@@ -472,7 +451,6 @@ int seq_client_init(struct lu_client_seq *seq,
struct lu_server_seq *srv)
{
int rc;
- ENTRY;
LASSERT(seq != NULL);
LASSERT(prefix != NULL);
@@ -501,14 +479,12 @@ int seq_client_init(struct lu_client_seq *seq,
rc = seq_client_proc_init(seq);
if (rc)
seq_client_fini(seq);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(seq_client_init);
void seq_client_fini(struct lu_client_seq *seq)
{
- ENTRY;
-
seq_client_proc_fini(seq);
if (seq->lcs_exp != NULL) {
@@ -517,6 +493,78 @@ void seq_client_fini(struct lu_client_seq *seq)
}
seq->lcs_srv = NULL;
- EXIT;
}
EXPORT_SYMBOL(seq_client_fini);
+
+int client_fid_init(struct obd_device *obd,
+ struct obd_export *exp, enum lu_cli_type type)
+{
+ struct client_obd *cli = &obd->u.cli;
+ char *prefix;
+ int rc;
+
+ OBD_ALLOC_PTR(cli->cl_seq);
+ if (cli->cl_seq == NULL)
+ return -ENOMEM;
+
+ OBD_ALLOC(prefix, MAX_OBD_NAME + 5);
+ if (prefix == NULL)
+ GOTO(out_free_seq, rc = -ENOMEM);
+
+ snprintf(prefix, MAX_OBD_NAME + 5, "cli-%s", obd->obd_name);
+
+ /* Init client side sequence-manager */
+ rc = seq_client_init(cli->cl_seq, exp, type, prefix, NULL);
+ OBD_FREE(prefix, MAX_OBD_NAME + 5);
+ if (rc)
+ GOTO(out_free_seq, rc);
+
+ return rc;
+out_free_seq:
+ OBD_FREE_PTR(cli->cl_seq);
+ cli->cl_seq = NULL;
+ return rc;
+}
+EXPORT_SYMBOL(client_fid_init);
+
+int client_fid_fini(struct obd_device *obd)
+{
+ struct client_obd *cli = &obd->u.cli;
+
+ if (cli->cl_seq != NULL) {
+ seq_client_fini(cli->cl_seq);
+ OBD_FREE_PTR(cli->cl_seq);
+ cli->cl_seq = NULL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(client_fid_fini);
+
+struct proc_dir_entry *seq_type_proc_dir;
+
+static int __init fid_mod_init(void)
+{
+ seq_type_proc_dir = lprocfs_register(LUSTRE_SEQ_NAME,
+ proc_lustre_root,
+ NULL, NULL);
+ if (IS_ERR(seq_type_proc_dir))
+ return PTR_ERR(seq_type_proc_dir);
+ return 0;
+}
+
+static void __exit fid_mod_exit(void)
+{
+ if (seq_type_proc_dir != NULL && !IS_ERR(seq_type_proc_dir)) {
+ lprocfs_remove(&seq_type_proc_dir);
+ seq_type_proc_dir = NULL;
+ }
+}
+
+MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_DESCRIPTION("Lustre FID Module");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1.0");
+
+module_init(fid_mod_init);
+module_exit(fid_mod_exit);
diff --git a/drivers/staging/lustre/lustre/fid/fid_store.c b/drivers/staging/lustre/lustre/fid/fid_store.c
deleted file mode 100644
index a90e6e37d68..00000000000
--- a/drivers/staging/lustre/lustre/fid/fid_store.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2013, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * lustre/fid/fid_store.c
- *
- * Lustre Sequence Manager
- *
- * Author: Yury Umanets <umka@clusterfs.com>
- */
-
-#define DEBUG_SUBSYSTEM S_FID
-
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
-
-#include <obd.h>
-#include <obd_class.h>
-#include <dt_object.h>
-#include <md_object.h>
-#include <obd_support.h>
-#include <lustre_req_layout.h>
-#include <lustre_fid.h>
-#include "fid_internal.h"
-
-
-static struct lu_buf *seq_store_buf(struct seq_thread_info *info)
-{
- struct lu_buf *buf;
-
- buf = &info->sti_buf;
- buf->lb_buf = &info->sti_space;
- buf->lb_len = sizeof(info->sti_space);
- return buf;
-}
-
-struct seq_update_callback {
- struct dt_txn_commit_cb suc_cb;
- struct lu_server_seq *suc_seq;
-};
-
-void seq_update_cb(struct lu_env *env, struct thandle *th,
- struct dt_txn_commit_cb *cb, int err)
-{
- struct seq_update_callback *ccb;
-
- ccb = container_of0(cb, struct seq_update_callback, suc_cb);
-
- LASSERT(ccb->suc_seq != NULL);
-
- ccb->suc_seq->lss_need_sync = 0;
- OBD_FREE_PTR(ccb);
-}
-
-int seq_update_cb_add(struct thandle *th, struct lu_server_seq *seq)
-{
- struct seq_update_callback *ccb;
- struct dt_txn_commit_cb *dcb;
- int rc;
-
- OBD_ALLOC_PTR(ccb);
- if (ccb == NULL)
- return -ENOMEM;
-
- ccb->suc_seq = seq;
- seq->lss_need_sync = 1;
-
- dcb = &ccb->suc_cb;
- dcb->dcb_func = seq_update_cb;
- INIT_LIST_HEAD(&dcb->dcb_linkage);
- strncpy(dcb->dcb_name, "seq_update_cb", MAX_COMMIT_CB_STR_LEN);
- dcb->dcb_name[MAX_COMMIT_CB_STR_LEN - 1] = '\0';
-
- rc = dt_trans_cb_add(th, dcb);
- if (rc)
- OBD_FREE_PTR(ccb);
- return rc;
-}
-
-/* This function implies that caller takes care about locking. */
-int seq_store_update(const struct lu_env *env, struct lu_server_seq *seq,
- struct lu_seq_range *out, int sync)
-{
- struct dt_device *dt_dev = lu2dt_dev(seq->lss_obj->do_lu.lo_dev);
- struct seq_thread_info *info;
- struct thandle *th;
- loff_t pos = 0;
- int rc;
-
- info = lu_context_key_get(&env->le_ctx, &seq_thread_key);
- LASSERT(info != NULL);
-
- th = dt_trans_create(env, dt_dev);
- if (IS_ERR(th))
- RETURN(PTR_ERR(th));
-
- rc = dt_declare_record_write(env, seq->lss_obj,
- sizeof(struct lu_seq_range), 0, th);
- if (rc)
- GOTO(exit, rc);
-
- if (out != NULL) {
- rc = fld_declare_server_create(env,
- seq->lss_site->ss_server_fld,
- out, th);
- if (rc)
- GOTO(exit, rc);
- }
-
- rc = dt_trans_start_local(env, dt_dev, th);
- if (rc)
- GOTO(exit, rc);
-
- /* Store ranges in le format. */
- range_cpu_to_le(&info->sti_space, &seq->lss_space);
-
- rc = dt_record_write(env, seq->lss_obj, seq_store_buf(info), &pos, th);
- if (rc) {
- CERROR("%s: Can't write space data, rc %d\n",
- seq->lss_name, rc);
- GOTO(exit, rc);
- } else if (out != NULL) {
- rc = fld_server_create(env, seq->lss_site->ss_server_fld, out,
- th);
- if (rc) {
- CERROR("%s: Can't Update fld database, rc %d\n",
- seq->lss_name, rc);
- GOTO(exit, rc);
- }
- }
- /* next sequence update will need sync until this update is committed
- * in case of sync operation this is not needed obviously */
- if (!sync)
- /* if callback can't be added then sync always */
- sync = !!seq_update_cb_add(th, seq);
-
- th->th_sync |= sync;
-exit:
- dt_trans_stop(env, dt_dev, th);
- return rc;
-}
-
-/*
- * This function implies that caller takes care about locking or locking is not
- * needed (init time).
- */
-int seq_store_read(struct lu_server_seq *seq,
- const struct lu_env *env)
-{
- struct seq_thread_info *info;
- loff_t pos = 0;
- int rc;
- ENTRY;
-
- info = lu_context_key_get(&env->le_ctx, &seq_thread_key);
- LASSERT(info != NULL);
-
- rc = seq->lss_obj->do_body_ops->dbo_read(env, seq->lss_obj,
- seq_store_buf(info),
- &pos, BYPASS_CAPA);
-
- if (rc == sizeof(info->sti_space)) {
- range_le_to_cpu(&seq->lss_space, &info->sti_space);
- CDEBUG(D_INFO, "%s: Space - "DRANGE"\n",
- seq->lss_name, PRANGE(&seq->lss_space));
- rc = 0;
- } else if (rc == 0) {
- rc = -ENODATA;
- } else if (rc > 0) {
- CERROR("%s: Read only %d bytes of %d\n", seq->lss_name,
- rc, (int)sizeof(info->sti_space));
- rc = -EIO;
- }
-
- RETURN(rc);
-}
-
-int seq_store_init(struct lu_server_seq *seq,
- const struct lu_env *env,
- struct dt_device *dt)
-{
- struct dt_object *dt_obj;
- struct lu_fid fid;
- struct lu_attr attr;
- struct dt_object_format dof;
- const char *name;
- int rc;
- ENTRY;
-
- name = seq->lss_type == LUSTRE_SEQ_SERVER ?
- LUSTRE_SEQ_SRV_NAME : LUSTRE_SEQ_CTL_NAME;
-
- if (seq->lss_type == LUSTRE_SEQ_SERVER)
- lu_local_obj_fid(&fid, FID_SEQ_SRV_OID);
- else
- lu_local_obj_fid(&fid, FID_SEQ_CTL_OID);
-
- memset(&attr, 0, sizeof(attr));
- attr.la_valid = LA_MODE;
- attr.la_mode = S_IFREG | 0666;
- dof.dof_type = DFT_REGULAR;
-
- dt_obj = dt_find_or_create(env, dt, &fid, &dof, &attr);
- if (!IS_ERR(dt_obj)) {
- seq->lss_obj = dt_obj;
- rc = 0;
- } else {
- CERROR("%s: Can't find \"%s\" obj %d\n",
- seq->lss_name, name, (int)PTR_ERR(dt_obj));
- rc = PTR_ERR(dt_obj);
- }
-
- RETURN(rc);
-}
-
-void seq_store_fini(struct lu_server_seq *seq,
- const struct lu_env *env)
-{
- ENTRY;
-
- if (seq->lss_obj != NULL) {
- if (!IS_ERR(seq->lss_obj))
- lu_object_put(env, &seq->lss_obj->do_lu);
- seq->lss_obj = NULL;
- }
-
- EXIT;
-}
diff --git a/drivers/staging/lustre/lustre/fid/lproc_fid.c b/drivers/staging/lustre/lustre/fid/lproc_fid.c
index af817a867f8..294070da9d4 100644
--- a/drivers/staging/lustre/lustre/fid/lproc_fid.c
+++ b/drivers/staging/lustre/lustre/fid/lproc_fid.c
@@ -65,7 +65,6 @@ lprocfs_fid_write_common(const char *buffer, unsigned long count,
{
struct lu_seq_range tmp;
int rc;
- ENTRY;
LASSERT(range != NULL);
@@ -73,9 +72,9 @@ lprocfs_fid_write_common(const char *buffer, unsigned long count,
(long long unsigned *)&tmp.lsr_start,
(long long unsigned *)&tmp.lsr_end);
if (rc != 2 || !range_is_sane(&tmp) || range_is_zero(&tmp))
- RETURN(-EINVAL);
+ return -EINVAL;
*range = tmp;
- RETURN(0);
+ return 0;
}
/* Client side procfs stuff */
@@ -85,7 +84,6 @@ lprocfs_fid_space_seq_write(struct file *file, const char *buffer,
{
struct lu_client_seq *seq = ((struct seq_file *)file->private_data)->private;
int rc;
- ENTRY;
LASSERT(seq != NULL);
@@ -99,7 +97,7 @@ lprocfs_fid_space_seq_write(struct file *file, const char *buffer,
mutex_unlock(&seq->lcs_mutex);
- RETURN(count);
+ return count;
}
static int
@@ -107,7 +105,6 @@ lprocfs_fid_space_seq_show(struct seq_file *m, void *unused)
{
struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
int rc;
- ENTRY;
LASSERT(seq != NULL);
@@ -115,7 +112,7 @@ lprocfs_fid_space_seq_show(struct seq_file *m, void *unused)
rc = seq_printf(m, "["LPX64" - "LPX64"]:%x:%s\n", PRANGE(&seq->lcs_space));
mutex_unlock(&seq->lcs_mutex);
- RETURN(rc);
+ return rc;
}
static ssize_t
@@ -125,13 +122,12 @@ lprocfs_fid_width_seq_write(struct file *file, const char *buffer,
struct lu_client_seq *seq = ((struct seq_file *)file->private_data)->private;
__u64 max;
int rc, val;
- ENTRY;
LASSERT(seq != NULL);
rc = lprocfs_write_helper(buffer, count, &val);
if (rc)
- RETURN(rc);
+ return rc;
mutex_lock(&seq->lcs_mutex);
if (seq->lcs_type == LUSTRE_SEQ_DATA)
@@ -150,7 +146,7 @@ lprocfs_fid_width_seq_write(struct file *file, const char *buffer,
mutex_unlock(&seq->lcs_mutex);
- RETURN(count);
+ return count;
}
static int
@@ -158,7 +154,6 @@ lprocfs_fid_width_seq_show(struct seq_file *m, void *unused)
{
struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
int rc;
- ENTRY;
LASSERT(seq != NULL);
@@ -166,7 +161,7 @@ lprocfs_fid_width_seq_show(struct seq_file *m, void *unused)
rc = seq_printf(m, LPU64"\n", seq->lcs_width);
mutex_unlock(&seq->lcs_mutex);
- RETURN(rc);
+ return rc;
}
static int
@@ -174,7 +169,6 @@ lprocfs_fid_fid_seq_show(struct seq_file *m, void *unused)
{
struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
int rc;
- ENTRY;
LASSERT(seq != NULL);
@@ -182,7 +176,7 @@ lprocfs_fid_fid_seq_show(struct seq_file *m, void *unused)
rc = seq_printf(m, DFID"\n", PFID(&seq->lcs_fid));
mutex_unlock(&seq->lcs_mutex);
- RETURN(rc);
+ return rc;
}
static int
@@ -191,7 +185,6 @@ lprocfs_fid_server_seq_show(struct seq_file *m, void *unused)
struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
struct client_obd *cli;
int rc;
- ENTRY;
LASSERT(seq != NULL);
@@ -201,12 +194,9 @@ lprocfs_fid_server_seq_show(struct seq_file *m, void *unused)
} else {
rc = seq_printf(m, "%s\n", seq->lcs_srv->lss_name);
}
- RETURN(rc);
+ return rc;
}
-struct lprocfs_vars seq_server_proc_list[] = {
-};
-
LPROC_SEQ_FOPS(lprocfs_fid_space);
LPROC_SEQ_FOPS(lprocfs_fid_width);
LPROC_SEQ_FOPS_RO(lprocfs_fid_server);
diff --git a/drivers/staging/lustre/lustre/fld/Makefile b/drivers/staging/lustre/lustre/fld/Makefile
index e7f2881a1d9..90d46d84fbb 100644
--- a/drivers/staging/lustre/lustre/fld/Makefile
+++ b/drivers/staging/lustre/lustre/fld/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_LUSTRE_FS) += fld.o
-fld-y := fld_handler.o fld_request.o fld_cache.o fld_index.o lproc_fld.o
+fld-y := fld_request.o fld_cache.o lproc_fld.o
ccflags-y := -I$(src)/../include
diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c
index 347f2ae83bc..25099cbe37e 100644
--- a/drivers/staging/lustre/lustre/fld/fld_cache.c
+++ b/drivers/staging/lustre/lustre/fld/fld_cache.c
@@ -45,7 +45,6 @@
# include <linux/libcfs/libcfs.h>
# include <linux/module.h>
-# include <linux/jbd.h>
# include <asm/div64.h>
#include <obd.h>
@@ -67,14 +66,13 @@ struct fld_cache *fld_cache_init(const char *name,
int cache_size, int cache_threshold)
{
struct fld_cache *cache;
- ENTRY;
LASSERT(name != NULL);
LASSERT(cache_threshold < cache_size);
OBD_ALLOC_PTR(cache);
if (cache == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&cache->fci_entries_head);
INIT_LIST_HEAD(&cache->fci_lru);
@@ -94,7 +92,7 @@ struct fld_cache *fld_cache_init(const char *name,
CDEBUG(D_INFO, "%s: FLD cache - Size: %d, Threshold: %d\n",
cache->fci_name, cache_size, cache_threshold);
- RETURN(cache);
+ return cache;
}
/**
@@ -103,7 +101,6 @@ struct fld_cache *fld_cache_init(const char *name,
void fld_cache_fini(struct fld_cache *cache)
{
__u64 pct;
- ENTRY;
LASSERT(cache != NULL);
fld_cache_flush(cache);
@@ -121,8 +118,6 @@ void fld_cache_fini(struct fld_cache *cache)
CDEBUG(D_INFO, " Cache hits: "LPU64"%%\n", pct);
OBD_FREE_PTR(cache);
-
- EXIT;
}
/**
@@ -147,7 +142,6 @@ static void fld_fix_new_list(struct fld_cache *cache)
struct lu_seq_range *c_range;
struct lu_seq_range *n_range;
struct list_head *head = &cache->fci_entries_head;
- ENTRY;
restart_fixup:
@@ -200,8 +194,6 @@ restart_fixup:
c_range->lsr_end == n_range->lsr_end)
fld_cache_entry_delete(cache, f_curr);
}
-
- EXIT;
}
/**
@@ -227,12 +219,11 @@ static int fld_cache_shrink(struct fld_cache *cache)
struct fld_cache_entry *flde;
struct list_head *curr;
int num = 0;
- ENTRY;
LASSERT(cache != NULL);
if (cache->fci_cache_count < cache->fci_cache_size)
- RETURN(0);
+ return 0;
curr = cache->fci_lru.prev;
@@ -248,7 +239,7 @@ static int fld_cache_shrink(struct fld_cache *cache)
CDEBUG(D_INFO, "%s: FLD cache - Shrunk by "
"%d entries\n", cache->fci_name, num);
- RETURN(0);
+ return 0;
}
/**
@@ -256,14 +247,10 @@ static int fld_cache_shrink(struct fld_cache *cache)
*/
void fld_cache_flush(struct fld_cache *cache)
{
- ENTRY;
-
write_lock(&cache->fci_lock);
cache->fci_cache_size = 0;
fld_cache_shrink(cache);
write_unlock(&cache->fci_lock);
-
- EXIT;
}
/**
@@ -280,11 +267,9 @@ void fld_cache_punch_hole(struct fld_cache *cache,
const seqno_t new_end = range->lsr_end;
struct fld_cache_entry *fldt;
- ENTRY;
OBD_ALLOC_GFP(fldt, sizeof *fldt, GFP_ATOMIC);
if (!fldt) {
OBD_FREE_PTR(f_new);
- EXIT;
/* overlap is not allowed, so dont mess up list. */
return;
}
@@ -307,7 +292,6 @@ void fld_cache_punch_hole(struct fld_cache *cache,
fld_cache_entry_add(cache, fldt, &f_new->fce_list);
/* no need to fixup */
- EXIT;
}
/**
@@ -383,10 +367,10 @@ struct fld_cache_entry
OBD_ALLOC_PTR(f_new);
if (!f_new)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
f_new->fce_range = *range;
- RETURN(f_new);
+ return f_new;
}
/**
@@ -405,7 +389,6 @@ int fld_cache_insert_nolock(struct fld_cache *cache,
const seqno_t new_start = f_new->fce_range.lsr_start;
const seqno_t new_end = f_new->fce_range.lsr_end;
__u32 new_flags = f_new->fce_range.lsr_flags;
- ENTRY;
/*
* Duplicate entries are eliminated in insert op.
@@ -441,7 +424,7 @@ int fld_cache_insert_nolock(struct fld_cache *cache,
/* Add new entry to cache and lru list. */
fld_cache_entry_add(cache, f_new, prev);
out:
- RETURN(0);
+ return 0;
}
int fld_cache_insert(struct fld_cache *cache,
@@ -452,7 +435,7 @@ int fld_cache_insert(struct fld_cache *cache,
flde = fld_cache_entry_create(range);
if (IS_ERR(flde))
- RETURN(PTR_ERR(flde));
+ return PTR_ERR(flde);
write_lock(&cache->fci_lock);
rc = fld_cache_insert_nolock(cache, flde);
@@ -460,7 +443,7 @@ int fld_cache_insert(struct fld_cache *cache,
if (rc)
OBD_FREE_PTR(flde);
- RETURN(rc);
+ return rc;
}
void fld_cache_delete_nolock(struct fld_cache *cache,
@@ -512,7 +495,7 @@ struct fld_cache_entry
}
}
- RETURN(got);
+ return got;
}
/**
@@ -522,12 +505,11 @@ struct fld_cache_entry
*fld_cache_entry_lookup(struct fld_cache *cache, struct lu_seq_range *range)
{
struct fld_cache_entry *got = NULL;
- ENTRY;
read_lock(&cache->fci_lock);
got = fld_cache_entry_lookup_nolock(cache, range);
read_unlock(&cache->fci_lock);
- RETURN(got);
+ return got;
}
/**
@@ -539,7 +521,6 @@ int fld_cache_lookup(struct fld_cache *cache,
struct fld_cache_entry *flde;
struct fld_cache_entry *prev = NULL;
struct list_head *head;
- ENTRY;
read_lock(&cache->fci_lock);
head = &cache->fci_entries_head;
@@ -558,9 +539,9 @@ int fld_cache_lookup(struct fld_cache *cache,
cache->fci_stat.fst_cache++;
read_unlock(&cache->fci_lock);
- RETURN(0);
+ return 0;
}
}
read_unlock(&cache->fci_lock);
- RETURN(-ENOENT);
+ return -ENOENT;
}
diff --git a/drivers/staging/lustre/lustre/fld/fld_handler.c b/drivers/staging/lustre/lustre/fld/fld_handler.c
deleted file mode 100644
index d2707ae4ad5..00000000000
--- a/drivers/staging/lustre/lustre/fld/fld_handler.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2013, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * lustre/fld/fld_handler.c
- *
- * FLD (Fids Location Database)
- *
- * Author: Yury Umanets <umka@clusterfs.com>
- * Author: WangDi <wangdi@clusterfs.com>
- * Author: Pravin Shelar <pravin.shelar@sun.com>
- */
-
-#define DEBUG_SUBSYSTEM S_FLD
-
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
-# include <linux/jbd.h>
-# include <asm/div64.h>
-
-#include <obd.h>
-#include <obd_class.h>
-#include <lustre_ver.h>
-#include <obd_support.h>
-#include <lprocfs_status.h>
-
-#include <md_object.h>
-#include <lustre_fid.h>
-#include <lustre_req_layout.h>
-#include "fld_internal.h"
-#include <lustre_fid.h>
-
-
-/* context key constructor/destructor: fld_key_init, fld_key_fini */
-LU_KEY_INIT_FINI(fld, struct fld_thread_info);
-
-/* context key: fld_thread_key */
-LU_CONTEXT_KEY_DEFINE(fld, LCT_MD_THREAD | LCT_DT_THREAD | LCT_MG_THREAD);
-
-proc_dir_entry_t *fld_type_proc_dir = NULL;
-
-static int __init fld_mod_init(void)
-{
- fld_type_proc_dir = lprocfs_register(LUSTRE_FLD_NAME,
- proc_lustre_root,
- NULL, NULL);
- if (IS_ERR(fld_type_proc_dir))
- return PTR_ERR(fld_type_proc_dir);
-
- LU_CONTEXT_KEY_INIT(&fld_thread_key);
- lu_context_key_register(&fld_thread_key);
- return 0;
-}
-
-static void __exit fld_mod_exit(void)
-{
- lu_context_key_degister(&fld_thread_key);
- if (fld_type_proc_dir != NULL && !IS_ERR(fld_type_proc_dir)) {
- lprocfs_remove(&fld_type_proc_dir);
- fld_type_proc_dir = NULL;
- }
-}
-
-int fld_declare_server_create(const struct lu_env *env,
- struct lu_server_fld *fld,
- struct lu_seq_range *range,
- struct thandle *th)
-{
- int rc;
-
- rc = fld_declare_index_create(env, fld, range, th);
- RETURN(rc);
-}
-EXPORT_SYMBOL(fld_declare_server_create);
-
-/**
- * Insert FLD index entry and update FLD cache.
- *
- * This function is called from the sequence allocator when a super-sequence
- * is granted to a server.
- */
-int fld_server_create(const struct lu_env *env, struct lu_server_fld *fld,
- struct lu_seq_range *range, struct thandle *th)
-{
- int rc;
-
- mutex_lock(&fld->lsf_lock);
- rc = fld_index_create(env, fld, range, th);
- mutex_unlock(&fld->lsf_lock);
-
- RETURN(rc);
-}
-EXPORT_SYMBOL(fld_server_create);
-
-/**
- * Lookup mds by seq, returns a range for given seq.
- *
- * If that entry is not cached in fld cache, request is sent to super
- * sequence controller node (MDT0). All other MDT[1...N] and client
- * cache fld entries, but this cache is not persistent.
- */
-int fld_server_lookup(const struct lu_env *env, struct lu_server_fld *fld,
- seqno_t seq, struct lu_seq_range *range)
-{
- struct lu_seq_range *erange;
- struct fld_thread_info *info;
- int rc;
- ENTRY;
-
- info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
- LASSERT(info != NULL);
- erange = &info->fti_lrange;
-
- /* Lookup it in the cache. */
- rc = fld_cache_lookup(fld->lsf_cache, seq, erange);
- if (rc == 0) {
- if (unlikely(fld_range_type(erange) != fld_range_type(range) &&
- !fld_range_is_any(range))) {
- CERROR("%s: FLD cache range "DRANGE" does not match"
- "requested flag %x: rc = %d\n", fld->lsf_name,
- PRANGE(erange), range->lsr_flags, -EIO);
- RETURN(-EIO);
- }
- *range = *erange;
- RETURN(0);
- }
-
- if (fld->lsf_obj) {
- /* On server side, all entries should be in cache.
- * If we can not find it in cache, just return error */
- CERROR("%s: Cannot find sequence "LPX64": rc = %d\n",
- fld->lsf_name, seq, -EIO);
- RETURN(-EIO);
- } else {
- LASSERT(fld->lsf_control_exp);
- /* send request to mdt0 i.e. super seq. controller.
- * This is temporary solution, long term solution is fld
- * replication on all mdt servers.
- */
- range->lsr_start = seq;
- rc = fld_client_rpc(fld->lsf_control_exp,
- range, FLD_LOOKUP);
- if (rc == 0)
- fld_cache_insert(fld->lsf_cache, range);
- }
- RETURN(rc);
-}
-EXPORT_SYMBOL(fld_server_lookup);
-
-/**
- * All MDT server handle fld lookup operation. But only MDT0 has fld index.
- * if entry is not found in cache we need to forward lookup request to MDT0
- */
-
-static int fld_server_handle(struct lu_server_fld *fld,
- const struct lu_env *env,
- __u32 opc, struct lu_seq_range *range,
- struct fld_thread_info *info)
-{
- int rc;
- ENTRY;
-
- switch (opc) {
- case FLD_LOOKUP:
- rc = fld_server_lookup(env, fld, range->lsr_start, range);
- break;
- default:
- rc = -EINVAL;
- break;
- }
-
- CDEBUG(D_INFO, "%s: FLD req handle: error %d (opc: %d, range: "
- DRANGE"\n", fld->lsf_name, rc, opc, PRANGE(range));
-
- RETURN(rc);
-
-}
-
-static int fld_req_handle(struct ptlrpc_request *req,
- struct fld_thread_info *info)
-{
- struct obd_export *exp = req->rq_export;
- struct lu_site *site = exp->exp_obd->obd_lu_dev->ld_site;
- struct lu_seq_range *in;
- struct lu_seq_range *out;
- int rc;
- __u32 *opc;
- ENTRY;
-
- rc = req_capsule_server_pack(info->fti_pill);
- if (rc)
- RETURN(err_serious(rc));
-
- opc = req_capsule_client_get(info->fti_pill, &RMF_FLD_OPC);
- if (opc != NULL) {
- in = req_capsule_client_get(info->fti_pill, &RMF_FLD_MDFLD);
- if (in == NULL)
- RETURN(err_serious(-EPROTO));
- out = req_capsule_server_get(info->fti_pill, &RMF_FLD_MDFLD);
- if (out == NULL)
- RETURN(err_serious(-EPROTO));
- *out = *in;
-
- /* For old 2.0 client, the 'lsr_flags' is uninitialized.
- * Set it as 'LU_SEQ_RANGE_MDT' by default. */
- if (!(exp_connect_flags(exp) & OBD_CONNECT_64BITHASH) &&
- !(exp_connect_flags(exp) & OBD_CONNECT_MDS_MDS) &&
- !(exp_connect_flags(exp) & OBD_CONNECT_LIGHTWEIGHT) &&
- !exp->exp_libclient)
- fld_range_set_mdt(out);
-
- rc = fld_server_handle(lu_site2seq(site)->ss_server_fld,
- req->rq_svc_thread->t_env,
- *opc, out, info);
- } else {
- rc = err_serious(-EPROTO);
- }
-
- RETURN(rc);
-}
-
-static void fld_thread_info_init(struct ptlrpc_request *req,
- struct fld_thread_info *info)
-{
- info->fti_pill = &req->rq_pill;
- /* Init request capsule. */
- req_capsule_init(info->fti_pill, req, RCL_SERVER);
- req_capsule_set(info->fti_pill, &RQF_FLD_QUERY);
-}
-
-static void fld_thread_info_fini(struct fld_thread_info *info)
-{
- req_capsule_fini(info->fti_pill);
-}
-
-static int fld_handle(struct ptlrpc_request *req)
-{
- struct fld_thread_info *info;
- const struct lu_env *env;
- int rc;
-
- env = req->rq_svc_thread->t_env;
- LASSERT(env != NULL);
-
- info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
- LASSERT(info != NULL);
-
- fld_thread_info_init(req, info);
- rc = fld_req_handle(req, info);
- fld_thread_info_fini(info);
-
- return rc;
-}
-
-/*
- * Entry point for handling FLD RPCs called from MDT.
- */
-int fld_query(struct com_thread_info *info)
-{
- return fld_handle(info->cti_pill->rc_req);
-}
-EXPORT_SYMBOL(fld_query);
-
-/*
- * Returns true, if fid is local to this server node.
- *
- * WARNING: this function is *not* guaranteed to return false if fid is
- * remote: it makes an educated conservative guess only.
- *
- * fid_is_local() is supposed to be used in assertion checks only.
- */
-int fid_is_local(const struct lu_env *env,
- struct lu_site *site, const struct lu_fid *fid)
-{
- int result;
- struct seq_server_site *ss_site;
- struct lu_seq_range *range;
- struct fld_thread_info *info;
- ENTRY;
-
- info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
- range = &info->fti_lrange;
-
- result = 1; /* conservatively assume fid is local */
- ss_site = lu_site2seq(site);
- if (ss_site->ss_client_fld != NULL) {
- int rc;
-
- rc = fld_cache_lookup(ss_site->ss_client_fld->lcf_cache,
- fid_seq(fid), range);
- if (rc == 0)
- result = (range->lsr_index == ss_site->ss_node_id);
- }
- return result;
-}
-EXPORT_SYMBOL(fid_is_local);
-
-static void fld_server_proc_fini(struct lu_server_fld *fld);
-
-#ifdef LPROCFS
-static int fld_server_proc_init(struct lu_server_fld *fld)
-{
- int rc = 0;
- ENTRY;
-
- fld->lsf_proc_dir = lprocfs_register(fld->lsf_name,
- fld_type_proc_dir,
- fld_server_proc_list, fld);
- if (IS_ERR(fld->lsf_proc_dir)) {
- rc = PTR_ERR(fld->lsf_proc_dir);
- RETURN(rc);
- }
-
- rc = lprocfs_seq_create(fld->lsf_proc_dir, "fldb", 0444,
- &fld_proc_seq_fops, fld);
- if (rc) {
- lprocfs_remove(&fld->lsf_proc_dir);
- fld->lsf_proc_dir = NULL;
- }
-
- RETURN(rc);
-}
-
-static void fld_server_proc_fini(struct lu_server_fld *fld)
-{
- ENTRY;
- if (fld->lsf_proc_dir != NULL) {
- if (!IS_ERR(fld->lsf_proc_dir))
- lprocfs_remove(&fld->lsf_proc_dir);
- fld->lsf_proc_dir = NULL;
- }
- EXIT;
-}
-#else
-static int fld_server_proc_init(struct lu_server_fld *fld)
-{
- return 0;
-}
-
-static void fld_server_proc_fini(struct lu_server_fld *fld)
-{
- return;
-}
-#endif
-
-int fld_server_init(const struct lu_env *env, struct lu_server_fld *fld,
- struct dt_device *dt, const char *prefix, int mds_node_id,
- int type)
-{
- int cache_size, cache_threshold;
- int rc;
- ENTRY;
-
- snprintf(fld->lsf_name, sizeof(fld->lsf_name),
- "srv-%s", prefix);
-
- cache_size = FLD_SERVER_CACHE_SIZE /
- sizeof(struct fld_cache_entry);
-
- cache_threshold = cache_size *
- FLD_SERVER_CACHE_THRESHOLD / 100;
-
- mutex_init(&fld->lsf_lock);
- fld->lsf_cache = fld_cache_init(fld->lsf_name,
- cache_size, cache_threshold);
- if (IS_ERR(fld->lsf_cache)) {
- rc = PTR_ERR(fld->lsf_cache);
- fld->lsf_cache = NULL;
- GOTO(out, rc);
- }
-
- if (!mds_node_id && type == LU_SEQ_RANGE_MDT) {
- rc = fld_index_init(env, fld, dt);
- if (rc)
- GOTO(out, rc);
- } else {
- fld->lsf_obj = NULL;
- }
-
- rc = fld_server_proc_init(fld);
- if (rc)
- GOTO(out, rc);
-
- fld->lsf_control_exp = NULL;
-
- GOTO(out, rc);
-
-out:
- if (rc)
- fld_server_fini(env, fld);
- return rc;
-}
-EXPORT_SYMBOL(fld_server_init);
-
-void fld_server_fini(const struct lu_env *env, struct lu_server_fld *fld)
-{
- ENTRY;
-
- fld_server_proc_fini(fld);
- fld_index_fini(env, fld);
-
- if (fld->lsf_cache != NULL) {
- if (!IS_ERR(fld->lsf_cache))
- fld_cache_fini(fld->lsf_cache);
- fld->lsf_cache = NULL;
- }
-
- EXIT;
-}
-EXPORT_SYMBOL(fld_server_fini);
-
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
-MODULE_DESCRIPTION("Lustre FLD");
-MODULE_LICENSE("GPL");
-
-cfs_module(mdd, "0.1.0", fld_mod_init, fld_mod_exit);
diff --git a/drivers/staging/lustre/lustre/fld/fld_index.c b/drivers/staging/lustre/lustre/fld/fld_index.c
deleted file mode 100644
index ec68a54c23b..00000000000
--- a/drivers/staging/lustre/lustre/fld/fld_index.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2013, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * lustre/fld/fld_index.c
- *
- * Author: WangDi <wangdi@clusterfs.com>
- * Author: Yury Umanets <umka@clusterfs.com>
- */
-
-#define DEBUG_SUBSYSTEM S_FLD
-
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
-# include <linux/jbd.h>
-
-#include <obd.h>
-#include <obd_class.h>
-#include <lustre_ver.h>
-#include <obd_support.h>
-#include <lprocfs_status.h>
-
-#include <dt_object.h>
-#include <md_object.h>
-#include <lustre_mdc.h>
-#include <lustre_fid.h>
-#include <lustre_fld.h>
-#include "fld_internal.h"
-
-const char fld_index_name[] = "fld";
-
-static const struct lu_seq_range IGIF_FLD_RANGE = {
- .lsr_start = FID_SEQ_IGIF,
- .lsr_end = FID_SEQ_IGIF_MAX + 1,
- .lsr_index = 0,
- .lsr_flags = LU_SEQ_RANGE_MDT
-};
-
-static const struct lu_seq_range DOT_LUSTRE_FLD_RANGE = {
- .lsr_start = FID_SEQ_DOT_LUSTRE,
- .lsr_end = FID_SEQ_DOT_LUSTRE + 1,
- .lsr_index = 0,
- .lsr_flags = LU_SEQ_RANGE_MDT
-};
-
-static const struct lu_seq_range ROOT_FLD_RANGE = {
- .lsr_start = FID_SEQ_ROOT,
- .lsr_end = FID_SEQ_ROOT + 1,
- .lsr_index = 0,
- .lsr_flags = LU_SEQ_RANGE_MDT
-};
-
-const struct dt_index_features fld_index_features = {
- .dif_flags = DT_IND_UPDATE,
- .dif_keysize_min = sizeof(seqno_t),
- .dif_keysize_max = sizeof(seqno_t),
- .dif_recsize_min = sizeof(struct lu_seq_range),
- .dif_recsize_max = sizeof(struct lu_seq_range),
- .dif_ptrsize = 4
-};
-
-extern struct lu_context_key fld_thread_key;
-
-int fld_declare_index_create(const struct lu_env *env,
- struct lu_server_fld *fld,
- const struct lu_seq_range *new_range,
- struct thandle *th)
-{
- struct lu_seq_range *tmp;
- struct lu_seq_range *range;
- struct fld_thread_info *info;
- int rc = 0;
-
- ENTRY;
-
- info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
- range = &info->fti_lrange;
- tmp = &info->fti_irange;
- memset(range, 0, sizeof(*range));
-
- rc = fld_index_lookup(env, fld, new_range->lsr_start, range);
- if (rc == 0) {
- /* In case of duplicate entry, the location must be same */
- LASSERT((range_compare_loc(new_range, range) == 0));
- GOTO(out, rc = -EEXIST);
- }
-
- if (rc != -ENOENT) {
- CERROR("%s: lookup range "DRANGE" error: rc = %d\n",
- fld->lsf_name, PRANGE(range), rc);
- GOTO(out, rc);
- }
-
- /* Check for merge case, since the fld entry can only be increamental,
- * so we will only check whether it can be merged from the left. */
- if (new_range->lsr_start == range->lsr_end && range->lsr_end != 0 &&
- range_compare_loc(new_range, range) == 0) {
- range_cpu_to_be(tmp, range);
- rc = dt_declare_delete(env, fld->lsf_obj,
- (struct dt_key *)&tmp->lsr_start, th);
- if (rc) {
- CERROR("%s: declare record "DRANGE" failed: rc = %d\n",
- fld->lsf_name, PRANGE(range), rc);
- GOTO(out, rc);
- }
- memcpy(tmp, new_range, sizeof(*new_range));
- tmp->lsr_start = range->lsr_start;
- } else {
- memcpy(tmp, new_range, sizeof(*new_range));
- }
-
- range_cpu_to_be(tmp, tmp);
- rc = dt_declare_insert(env, fld->lsf_obj, (struct dt_rec *)tmp,
- (struct dt_key *)&tmp->lsr_start, th);
-out:
- RETURN(rc);
-}
-
-/**
- * insert range in fld store.
- *
- * \param range range to be inserted
- * \param th transaction for this operation as it could compound
- * transaction.
- *
- * \retval 0 success
- * \retval -ve error
- *
- * The whole fld index insertion is protected by seq->lss_mutex (see
- * seq_server_alloc_super), i.e. only one thread will access fldb each
- * time, so we do not need worry the fld file and cache will being
- * changed between declare and create.
- * Because the fld entry can only be increamental, so we will only check
- * whether it can be merged from the left.
- **/
-int fld_index_create(const struct lu_env *env, struct lu_server_fld *fld,
- const struct lu_seq_range *new_range, struct thandle *th)
-{
- struct lu_seq_range *range;
- struct lu_seq_range *tmp;
- struct fld_thread_info *info;
- int rc = 0;
- int deleted = 0;
- struct fld_cache_entry *flde;
- ENTRY;
-
- info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
-
- LASSERT(mutex_is_locked(&fld->lsf_lock));
-
- range = &info->fti_lrange;
- memset(range, 0, sizeof(*range));
- tmp = &info->fti_irange;
- rc = fld_index_lookup(env, fld, new_range->lsr_start, range);
- if (rc != -ENOENT) {
- rc = rc == 0 ? -EEXIST : rc;
- GOTO(out, rc);
- }
-
- if (new_range->lsr_start == range->lsr_end && range->lsr_end != 0 &&
- range_compare_loc(new_range, range) == 0) {
- range_cpu_to_be(tmp, range);
- rc = dt_delete(env, fld->lsf_obj,
- (struct dt_key *)&tmp->lsr_start, th,
- BYPASS_CAPA);
- if (rc != 0)
- GOTO(out, rc);
- memcpy(tmp, new_range, sizeof(*new_range));
- tmp->lsr_start = range->lsr_start;
- deleted = 1;
- } else {
- memcpy(tmp, new_range, sizeof(*new_range));
- }
-
- range_cpu_to_be(tmp, tmp);
- rc = dt_insert(env, fld->lsf_obj, (struct dt_rec *)tmp,
- (struct dt_key *)&tmp->lsr_start, th, BYPASS_CAPA, 1);
- if (rc != 0) {
- CERROR("%s: insert range "DRANGE" failed: rc = %d\n",
- fld->lsf_name, PRANGE(new_range), rc);
- GOTO(out, rc);
- }
-
- flde = fld_cache_entry_create(new_range);
- if (IS_ERR(flde))
- GOTO(out, rc = PTR_ERR(flde));
-
- write_lock(&fld->lsf_cache->fci_lock);
- if (deleted)
- fld_cache_delete_nolock(fld->lsf_cache, new_range);
- rc = fld_cache_insert_nolock(fld->lsf_cache, flde);
- write_unlock(&fld->lsf_cache->fci_lock);
- if (rc)
- OBD_FREE_PTR(flde);
-out:
- RETURN(rc);
-}
-
-/**
- * lookup range for a seq passed. note here we only care about the start/end,
- * caller should handle the attached location data (flags, index).
- *
- * \param seq seq for lookup.
- * \param range result of lookup.
- *
- * \retval 0 found, \a range is the matched range;
- * \retval -ENOENT not found, \a range is the left-side range;
- * \retval -ve other error;
- */
-int fld_index_lookup(const struct lu_env *env, struct lu_server_fld *fld,
- seqno_t seq, struct lu_seq_range *range)
-{
- struct lu_seq_range *fld_rec;
- struct fld_thread_info *info;
- int rc;
-
- ENTRY;
-
- info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
- fld_rec = &info->fti_rec;
-
- rc = fld_cache_lookup(fld->lsf_cache, seq, fld_rec);
- if (rc == 0) {
- *range = *fld_rec;
- if (range_within(range, seq))
- rc = 0;
- else
- rc = -ENOENT;
- }
-
- CDEBUG(D_INFO, "%s: lookup seq = "LPX64" range : "DRANGE" rc = %d\n",
- fld->lsf_name, seq, PRANGE(range), rc);
-
- RETURN(rc);
-}
-
-int fld_insert_entry(const struct lu_env *env,
- struct lu_server_fld *fld,
- const struct lu_seq_range *range)
-{
- struct thandle *th;
- int rc;
- ENTRY;
-
- th = dt_trans_create(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev));
- if (IS_ERR(th))
- RETURN(PTR_ERR(th));
-
- rc = fld_declare_index_create(env, fld, range, th);
- if (rc != 0) {
- if (rc == -EEXIST)
- rc = 0;
- GOTO(out, rc);
- }
-
- rc = dt_trans_start_local(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev),
- th);
- if (rc)
- GOTO(out, rc);
-
- rc = fld_index_create(env, fld, range, th);
- if (rc == -EEXIST)
- rc = 0;
-out:
- dt_trans_stop(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev), th);
- RETURN(rc);
-}
-EXPORT_SYMBOL(fld_insert_entry);
-
-static int fld_insert_special_entries(const struct lu_env *env,
- struct lu_server_fld *fld)
-{
- int rc;
-
- rc = fld_insert_entry(env, fld, &IGIF_FLD_RANGE);
- if (rc != 0)
- RETURN(rc);
-
- rc = fld_insert_entry(env, fld, &DOT_LUSTRE_FLD_RANGE);
- if (rc != 0)
- RETURN(rc);
-
- rc = fld_insert_entry(env, fld, &ROOT_FLD_RANGE);
-
- RETURN(rc);
-}
-
-int fld_index_init(const struct lu_env *env, struct lu_server_fld *fld,
- struct dt_device *dt)
-{
- struct dt_object *dt_obj = NULL;
- struct lu_fid fid;
- struct lu_attr *attr = NULL;
- struct lu_seq_range *range = NULL;
- struct fld_thread_info *info;
- struct dt_object_format dof;
- struct dt_it *it;
- const struct dt_it_ops *iops;
- int rc;
- ENTRY;
-
- info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
- LASSERT(info != NULL);
-
- lu_local_obj_fid(&fid, FLD_INDEX_OID);
- OBD_ALLOC_PTR(attr);
- if (attr == NULL)
- RETURN(-ENOMEM);
-
- memset(attr, 0, sizeof(*attr));
- attr->la_valid = LA_MODE;
- attr->la_mode = S_IFREG | 0666;
- dof.dof_type = DFT_INDEX;
- dof.u.dof_idx.di_feat = &fld_index_features;
-
- dt_obj = dt_find_or_create(env, dt, &fid, &dof, attr);
- if (IS_ERR(dt_obj)) {
- rc = PTR_ERR(dt_obj);
- CERROR("%s: Can't find \"%s\" obj %d\n", fld->lsf_name,
- fld_index_name, rc);
- dt_obj = NULL;
- GOTO(out, rc);
- }
-
- fld->lsf_obj = dt_obj;
- rc = dt_obj->do_ops->do_index_try(env, dt_obj, &fld_index_features);
- if (rc != 0) {
- CERROR("%s: File \"%s\" is not an index: rc = %d!\n",
- fld->lsf_name, fld_index_name, rc);
- GOTO(out, rc);
- }
-
- range = &info->fti_rec;
- /* Load fld entry to cache */
- iops = &dt_obj->do_index_ops->dio_it;
- it = iops->init(env, dt_obj, 0, NULL);
- if (IS_ERR(it))
- GOTO(out, rc = PTR_ERR(it));
-
- rc = iops->load(env, it, 0);
- if (rc < 0)
- GOTO(out_it_fini, rc);
-
- if (rc > 0) {
- /* Load FLD entry into server cache */
- do {
- rc = iops->rec(env, it, (struct dt_rec *)range, 0);
- if (rc != 0)
- GOTO(out_it_put, rc);
- LASSERT(range != NULL);
- range_be_to_cpu(range, range);
- rc = fld_cache_insert(fld->lsf_cache, range);
- if (rc != 0)
- GOTO(out_it_put, rc);
- rc = iops->next(env, it);
- } while (rc == 0);
- }
-
- /* Note: fld_insert_entry will detect whether these
- * special entries already exist inside FLDB */
- mutex_lock(&fld->lsf_lock);
- rc = fld_insert_special_entries(env, fld);
- mutex_unlock(&fld->lsf_lock);
- if (rc != 0) {
- CERROR("%s: insert special entries failed!: rc = %d\n",
- fld->lsf_name, rc);
- GOTO(out_it_put, rc);
- }
-
-out_it_put:
- iops->put(env, it);
-out_it_fini:
- iops->fini(env, it);
-out:
- if (attr != NULL)
- OBD_FREE_PTR(attr);
-
- if (rc != 0) {
- if (dt_obj != NULL)
- lu_object_put(env, &dt_obj->do_lu);
- fld->lsf_obj = NULL;
- }
- RETURN(rc);
-}
-
-void fld_index_fini(const struct lu_env *env, struct lu_server_fld *fld)
-{
- ENTRY;
- if (fld->lsf_obj != NULL) {
- if (!IS_ERR(fld->lsf_obj))
- lu_object_put(env, &fld->lsf_obj->do_lu);
- fld->lsf_obj = NULL;
- }
- EXIT;
-}
diff --git a/drivers/staging/lustre/lustre/fld/fld_internal.h b/drivers/staging/lustre/lustre/fld/fld_internal.h
index 9fa9e01cdb6..56686b138ac 100644
--- a/drivers/staging/lustre/lustre/fld/fld_internal.h
+++ b/drivers/staging/lustre/lustre/fld/fld_internal.h
@@ -139,38 +139,10 @@ enum {
extern struct lu_fld_hash fld_hash[];
-
-struct fld_thread_info {
- struct req_capsule *fti_pill;
- __u64 fti_key;
- struct lu_seq_range fti_rec;
- struct lu_seq_range fti_lrange;
- struct lu_seq_range fti_irange;
-};
-
-extern struct lu_context_key fld_thread_key;
-
-int fld_index_init(const struct lu_env *env, struct lu_server_fld *fld,
- struct dt_device *dt);
-
-void fld_index_fini(const struct lu_env *env, struct lu_server_fld *fld);
-
-int fld_declare_index_create(const struct lu_env *env,
- struct lu_server_fld *fld,
- const struct lu_seq_range *new,
- struct thandle *th);
-
-int fld_index_create(const struct lu_env *env, struct lu_server_fld *fld,
- const struct lu_seq_range *new, struct thandle *th);
-
-int fld_index_lookup(const struct lu_env *env, struct lu_server_fld *fld,
- seqno_t seq, struct lu_seq_range *range);
-
int fld_client_rpc(struct obd_export *exp,
struct lu_seq_range *range, __u32 fld_op);
#ifdef LPROCFS
-extern struct lprocfs_vars fld_server_proc_list[];
extern struct lprocfs_vars fld_client_proc_list[];
#endif
@@ -218,6 +190,5 @@ fld_target_name(struct lu_fld_target *tar)
return (const char *)tar->ft_exp->exp_obd->obd_name;
}
-extern proc_dir_entry_t *fld_type_proc_dir;
-extern struct file_operations fld_proc_seq_fops;
+extern struct proc_dir_entry *fld_type_proc_dir;
#endif /* __FLD_INTERNAL_H */
diff --git a/drivers/staging/lustre/lustre/fld/fld_request.c b/drivers/staging/lustre/lustre/fld/fld_request.c
index e9f07398b68..078e98bda68 100644
--- a/drivers/staging/lustre/lustre/fld/fld_request.c
+++ b/drivers/staging/lustre/lustre/fld/fld_request.c
@@ -44,7 +44,6 @@
# include <linux/libcfs/libcfs.h>
# include <linux/module.h>
-# include <linux/jbd.h>
# include <asm/div64.h>
#include <obd.h>
@@ -60,16 +59,18 @@
#include <lustre_mdc.h>
#include "fld_internal.h"
+struct lu_context_key fld_thread_key;
+
/* TODO: these 3 functions are copies of flow-control code from mdc_lib.c
* It should be common thing. The same about mdc RPC lock */
static int fld_req_avail(struct client_obd *cli, struct mdc_cache_waiter *mcw)
{
int rc;
- ENTRY;
+
client_obd_list_lock(&cli->cl_loi_list_lock);
rc = list_empty(&mcw->mcw_entry);
client_obd_list_unlock(&cli->cl_loi_list_lock);
- RETURN(rc);
+ return rc;
};
static void fld_enter_request(struct client_obd *cli)
@@ -123,7 +124,6 @@ fld_rrb_scan(struct lu_client_fld *fld, seqno_t seq)
{
struct lu_fld_target *target;
int hash;
- ENTRY;
/* Because almost all of special sequence located in MDT0,
* it should go to index 0 directly, instead of calculating
@@ -137,7 +137,7 @@ fld_rrb_scan(struct lu_client_fld *fld, seqno_t seq)
list_for_each_entry(target, &fld->lcf_targets, ft_chain) {
if (target->ft_idx == hash)
- RETURN(target);
+ return target;
}
CERROR("%s: Can't find target by hash %d (seq "LPX64"). "
@@ -161,7 +161,7 @@ fld_rrb_scan(struct lu_client_fld *fld, seqno_t seq)
* LBUG() to catch this situation.
*/
LBUG();
- RETURN(NULL);
+ return NULL;
}
struct lu_fld_hash fld_hash[] = {
@@ -179,7 +179,6 @@ static struct lu_fld_target *
fld_client_get_target(struct lu_client_fld *fld, seqno_t seq)
{
struct lu_fld_target *target;
- ENTRY;
LASSERT(fld->lcf_hash != NULL);
@@ -193,7 +192,7 @@ fld_client_get_target(struct lu_client_fld *fld, seqno_t seq)
target->ft_idx, seq);
}
- RETURN(target);
+ return target;
}
/*
@@ -205,7 +204,6 @@ int fld_client_add_target(struct lu_client_fld *fld,
{
const char *name;
struct lu_fld_target *target, *tmp;
- ENTRY;
LASSERT(tar != NULL);
name = fld_target_name(tar);
@@ -216,7 +214,7 @@ int fld_client_add_target(struct lu_client_fld *fld,
CERROR("%s: Attempt to add target %s (idx "LPU64") "
"on fly - skip it\n", fld->lcf_name, name,
tar->ft_idx);
- RETURN(0);
+ return 0;
} else {
CDEBUG(D_INFO, "%s: Adding target %s (idx "
LPU64")\n", fld->lcf_name, name, tar->ft_idx);
@@ -224,7 +222,7 @@ int fld_client_add_target(struct lu_client_fld *fld,
OBD_ALLOC_PTR(target);
if (target == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
spin_lock(&fld->lcf_lock);
list_for_each_entry(tmp, &fld->lcf_targets, ft_chain) {
@@ -233,7 +231,7 @@ int fld_client_add_target(struct lu_client_fld *fld,
OBD_FREE_PTR(target);
CERROR("Target %s exists in FLD and known as %s:#"LPU64"\n",
name, fld_target_name(tmp), tmp->ft_idx);
- RETURN(-EEXIST);
+ return -EEXIST;
}
}
@@ -249,7 +247,7 @@ int fld_client_add_target(struct lu_client_fld *fld,
fld->lcf_count++;
spin_unlock(&fld->lcf_lock);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(fld_client_add_target);
@@ -257,7 +255,6 @@ EXPORT_SYMBOL(fld_client_add_target);
int fld_client_del_target(struct lu_client_fld *fld, __u64 idx)
{
struct lu_fld_target *target, *tmp;
- ENTRY;
spin_lock(&fld->lcf_lock);
list_for_each_entry_safe(target, tmp,
@@ -271,19 +268,20 @@ int fld_client_del_target(struct lu_client_fld *fld, __u64 idx)
class_export_put(target->ft_exp);
OBD_FREE_PTR(target);
- RETURN(0);
+ return 0;
}
}
spin_unlock(&fld->lcf_lock);
- RETURN(-ENOENT);
+ return -ENOENT;
}
EXPORT_SYMBOL(fld_client_del_target);
#ifdef LPROCFS
+struct proc_dir_entry *fld_type_proc_dir = NULL;
+
static int fld_client_proc_init(struct lu_client_fld *fld)
{
int rc;
- ENTRY;
fld->lcf_proc_dir = lprocfs_register(fld->lcf_name,
fld_type_proc_dir,
@@ -293,7 +291,7 @@ static int fld_client_proc_init(struct lu_client_fld *fld)
CERROR("%s: LProcFS failed in fld-init\n",
fld->lcf_name);
rc = PTR_ERR(fld->lcf_proc_dir);
- RETURN(rc);
+ return rc;
}
rc = lprocfs_add_vars(fld->lcf_proc_dir,
@@ -304,7 +302,7 @@ static int fld_client_proc_init(struct lu_client_fld *fld)
GOTO(out_cleanup, rc);
}
- RETURN(0);
+ return 0;
out_cleanup:
fld_client_proc_fini(fld);
@@ -313,13 +311,11 @@ out_cleanup:
void fld_client_proc_fini(struct lu_client_fld *fld)
{
- ENTRY;
if (fld->lcf_proc_dir) {
if (!IS_ERR(fld->lcf_proc_dir))
lprocfs_remove(&fld->lcf_proc_dir);
fld->lcf_proc_dir = NULL;
}
- EXIT;
}
#else
static int fld_client_proc_init(struct lu_client_fld *fld)
@@ -345,7 +341,6 @@ int fld_client_init(struct lu_client_fld *fld,
{
int cache_size, cache_threshold;
int rc;
- ENTRY;
LASSERT(fld != NULL);
@@ -355,7 +350,7 @@ int fld_client_init(struct lu_client_fld *fld,
if (!hash_is_sane(hash)) {
CERROR("%s: Wrong hash function %#x\n",
fld->lcf_name, hash);
- RETURN(-EINVAL);
+ return -EINVAL;
}
fld->lcf_count = 0;
@@ -381,7 +376,6 @@ int fld_client_init(struct lu_client_fld *fld,
rc = fld_client_proc_init(fld);
if (rc)
GOTO(out, rc);
- EXIT;
out:
if (rc)
fld_client_fini(fld);
@@ -395,7 +389,6 @@ EXPORT_SYMBOL(fld_client_init);
void fld_client_fini(struct lu_client_fld *fld)
{
struct lu_fld_target *target, *tmp;
- ENTRY;
spin_lock(&fld->lcf_lock);
list_for_each_entry_safe(target, tmp,
@@ -413,8 +406,6 @@ void fld_client_fini(struct lu_client_fld *fld)
fld_cache_fini(fld->lcf_cache);
fld->lcf_cache = NULL;
}
-
- EXIT;
}
EXPORT_SYMBOL(fld_client_fini);
@@ -426,7 +417,6 @@ int fld_client_rpc(struct obd_export *exp,
__u32 *op;
int rc;
struct obd_import *imp;
- ENTRY;
LASSERT(exp != NULL);
@@ -434,7 +424,7 @@ int fld_client_rpc(struct obd_export *exp,
req = ptlrpc_request_alloc_pack(imp, &RQF_FLD_QUERY, LUSTRE_MDS_VERSION,
FLD_QUERY);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
op = req_capsule_client_get(&req->rq_pill, &RMF_FLD_OPC);
*op = fld_op;
@@ -464,7 +454,6 @@ int fld_client_rpc(struct obd_export *exp,
if (prange == NULL)
GOTO(out_req, rc = -EFAULT);
*range = *prange;
- EXIT;
out_req:
ptlrpc_req_finished(req);
return rc;
@@ -476,14 +465,13 @@ int fld_client_lookup(struct lu_client_fld *fld, seqno_t seq, mdsno_t *mds,
struct lu_seq_range res = { 0 };
struct lu_fld_target *target;
int rc;
- ENTRY;
fld->lcf_flags |= LUSTRE_FLD_RUN;
rc = fld_cache_lookup(fld->lcf_cache, seq, &res);
if (rc == 0) {
*mds = res.lsr_index;
- RETURN(0);
+ return 0;
}
/* Can not find it in the cache */
@@ -496,19 +484,14 @@ int fld_client_lookup(struct lu_client_fld *fld, seqno_t seq, mdsno_t *mds,
res.lsr_start = seq;
fld_range_set_type(&res, flags);
- if (target->ft_srv != NULL) {
- LASSERT(env != NULL);
- rc = fld_server_lookup(env, target->ft_srv, seq, &res);
- } else {
- rc = fld_client_rpc(target->ft_exp, &res, FLD_LOOKUP);
- }
+ rc = fld_client_rpc(target->ft_exp, &res, FLD_LOOKUP);
if (rc == 0) {
*mds = res.lsr_index;
fld_cache_insert(fld->lcf_cache, &res);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(fld_client_lookup);
@@ -517,3 +500,32 @@ void fld_client_flush(struct lu_client_fld *fld)
fld_cache_flush(fld->lcf_cache);
}
EXPORT_SYMBOL(fld_client_flush);
+
+static int __init fld_mod_init(void)
+{
+ fld_type_proc_dir = lprocfs_register(LUSTRE_FLD_NAME,
+ proc_lustre_root,
+ NULL, NULL);
+ if (IS_ERR(fld_type_proc_dir))
+ return PTR_ERR(fld_type_proc_dir);
+
+ LU_CONTEXT_KEY_INIT(&fld_thread_key);
+ lu_context_key_register(&fld_thread_key);
+ return 0;
+}
+
+static void __exit fld_mod_exit(void)
+{
+ lu_context_key_degister(&fld_thread_key);
+ if (fld_type_proc_dir != NULL && !IS_ERR(fld_type_proc_dir)) {
+ lprocfs_remove(&fld_type_proc_dir);
+ fld_type_proc_dir = NULL;
+ }
+}
+
+MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_DESCRIPTION("Lustre FLD");
+MODULE_LICENSE("GPL");
+
+module_init(fld_mod_init)
+module_exit(fld_mod_exit)
diff --git a/drivers/staging/lustre/lustre/fld/lproc_fld.c b/drivers/staging/lustre/lustre/fld/lproc_fld.c
index c1bd80339e6..052f7d51a07 100644
--- a/drivers/staging/lustre/lustre/fld/lproc_fld.c
+++ b/drivers/staging/lustre/lustre/fld/lproc_fld.c
@@ -62,7 +62,6 @@ fld_proc_targets_seq_show(struct seq_file *m, void *unused)
{
struct lu_client_fld *fld = (struct lu_client_fld *)m->private;
struct lu_fld_target *target;
- ENTRY;
LASSERT(fld != NULL);
@@ -72,14 +71,13 @@ fld_proc_targets_seq_show(struct seq_file *m, void *unused)
seq_printf(m, "%s\n", fld_target_name(target));
spin_unlock(&fld->lcf_lock);
- RETURN(0);
+ return 0;
}
static int
fld_proc_hash_seq_show(struct seq_file *m, void *unused)
{
struct lu_client_fld *fld = (struct lu_client_fld *)m->private;
- ENTRY;
LASSERT(fld != NULL);
@@ -87,7 +85,7 @@ fld_proc_hash_seq_show(struct seq_file *m, void *unused)
seq_printf(m, "%s\n", fld->lcf_hash->fh_name);
spin_unlock(&fld->lcf_lock);
- RETURN(0);
+ return 0;
}
static ssize_t
@@ -97,7 +95,6 @@ fld_proc_hash_seq_write(struct file *file, const char *buffer,
struct lu_client_fld *fld = ((struct seq_file *)file->private_data)->private;
struct lu_fld_hash *hash = NULL;
int i;
- ENTRY;
LASSERT(fld != NULL);
@@ -120,7 +117,7 @@ fld_proc_hash_seq_write(struct file *file, const char *buffer,
fld->lcf_name, hash->fh_name);
}
- RETURN(count);
+ return count;
}
static ssize_t
@@ -128,7 +125,6 @@ fld_proc_cache_flush_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
struct lu_client_fld *fld = file->private_data;
- ENTRY;
LASSERT(fld != NULL);
@@ -136,7 +132,7 @@ fld_proc_cache_flush_write(struct file *file, const char __user *buffer,
CDEBUG(D_INFO, "%s: Lookup cache is flushed\n", fld->lcf_name);
- RETURN(count);
+ return count;
}
static int fld_proc_cache_flush_open(struct inode *inode, struct file *file)
@@ -158,202 +154,6 @@ struct file_operations fld_proc_cache_flush_fops = {
.release = fld_proc_cache_flush_release,
};
-struct fld_seq_param {
- struct lu_env fsp_env;
- struct dt_it *fsp_it;
- struct lu_server_fld *fsp_fld;
- unsigned int fsp_stop:1;
-};
-
-static void *fldb_seq_start(struct seq_file *p, loff_t *pos)
-{
- struct fld_seq_param *param = p->private;
- struct lu_server_fld *fld;
- struct dt_object *obj;
- const struct dt_it_ops *iops;
-
- if (param == NULL || param->fsp_stop)
- return NULL;
-
- fld = param->fsp_fld;
- obj = fld->lsf_obj;
- LASSERT(obj != NULL);
- iops = &obj->do_index_ops->dio_it;
-
- iops->load(&param->fsp_env, param->fsp_it, *pos);
-
- *pos = be64_to_cpu(*(__u64 *)iops->key(&param->fsp_env, param->fsp_it));
- return param;
-}
-
-static void fldb_seq_stop(struct seq_file *p, void *v)
-{
- struct fld_seq_param *param = p->private;
- const struct dt_it_ops *iops;
- struct lu_server_fld *fld;
- struct dt_object *obj;
-
- if (param == NULL)
- return;
-
- fld = param->fsp_fld;
- obj = fld->lsf_obj;
- LASSERT(obj != NULL);
- iops = &obj->do_index_ops->dio_it;
-
- iops->put(&param->fsp_env, param->fsp_it);
-}
-
-static void *fldb_seq_next(struct seq_file *p, void *v, loff_t *pos)
-{
- struct fld_seq_param *param = p->private;
- struct lu_server_fld *fld;
- struct dt_object *obj;
- const struct dt_it_ops *iops;
- int rc;
-
- if (param == NULL || param->fsp_stop)
- return NULL;
-
- fld = param->fsp_fld;
- obj = fld->lsf_obj;
- LASSERT(obj != NULL);
- iops = &obj->do_index_ops->dio_it;
-
- rc = iops->next(&param->fsp_env, param->fsp_it);
- if (rc > 0) {
- param->fsp_stop = 1;
- return NULL;
- }
-
- *pos = be64_to_cpu(*(__u64 *)iops->key(&param->fsp_env, param->fsp_it));
- return param;
-}
-
-static int fldb_seq_show(struct seq_file *p, void *v)
-{
- struct fld_seq_param *param = p->private;
- struct lu_server_fld *fld;
- struct dt_object *obj;
- const struct dt_it_ops *iops;
- struct fld_thread_info *info;
- struct lu_seq_range *fld_rec;
- int rc;
-
- if (param == NULL || param->fsp_stop)
- return 0;
-
- fld = param->fsp_fld;
- obj = fld->lsf_obj;
- LASSERT(obj != NULL);
- iops = &obj->do_index_ops->dio_it;
-
- info = lu_context_key_get(&param->fsp_env.le_ctx,
- &fld_thread_key);
- fld_rec = &info->fti_rec;
- rc = iops->rec(&param->fsp_env, param->fsp_it,
- (struct dt_rec *)fld_rec, 0);
- if (rc != 0) {
- CERROR("%s:read record error: rc %d\n",
- fld->lsf_name, rc);
- } else if (fld_rec->lsr_start != 0) {
- range_be_to_cpu(fld_rec, fld_rec);
- rc = seq_printf(p, DRANGE"\n", PRANGE(fld_rec));
- }
-
- return rc;
-}
-
-struct seq_operations fldb_sops = {
- .start = fldb_seq_start,
- .stop = fldb_seq_stop,
- .next = fldb_seq_next,
- .show = fldb_seq_show,
-};
-
-static int fldb_seq_open(struct inode *inode, struct file *file)
-{
- struct seq_file *seq;
- struct lu_server_fld *fld = (struct lu_server_fld *)PDE_DATA(inode);
- struct dt_object *obj;
- const struct dt_it_ops *iops;
- struct fld_seq_param *param = NULL;
- int env_init = 0;
- int rc;
-
- rc = seq_open(file, &fldb_sops);
- if (rc)
- GOTO(out, rc);
-
- obj = fld->lsf_obj;
- if (obj == NULL) {
- seq = file->private_data;
- seq->private = NULL;
- return 0;
- }
-
- OBD_ALLOC_PTR(param);
- if (param == NULL)
- GOTO(out, rc = -ENOMEM);
-
- rc = lu_env_init(&param->fsp_env, LCT_MD_THREAD);
- if (rc != 0)
- GOTO(out, rc);
-
- env_init = 1;
- iops = &obj->do_index_ops->dio_it;
- param->fsp_it = iops->init(&param->fsp_env, obj, 0, NULL);
- if (IS_ERR(param->fsp_it))
- GOTO(out, rc = PTR_ERR(param->fsp_it));
-
- param->fsp_fld = fld;
- param->fsp_stop = 0;
-
- seq = file->private_data;
- seq->private = param;
-out:
- if (rc != 0) {
- if (env_init == 1)
- lu_env_fini(&param->fsp_env);
- if (param != NULL)
- OBD_FREE_PTR(param);
- }
- return rc;
-}
-
-static int fldb_seq_release(struct inode *inode, struct file *file)
-{
- struct seq_file *seq = file->private_data;
- struct fld_seq_param *param;
- struct lu_server_fld *fld;
- struct dt_object *obj;
- const struct dt_it_ops *iops;
-
- param = seq->private;
- if (param == NULL) {
- lprocfs_seq_release(inode, file);
- return 0;
- }
-
- fld = param->fsp_fld;
- obj = fld->lsf_obj;
- LASSERT(obj != NULL);
- iops = &obj->do_index_ops->dio_it;
-
- LASSERT(iops != NULL);
- LASSERT(obj != NULL);
- LASSERT(param->fsp_it != NULL);
- iops->fini(&param->fsp_env, param->fsp_it);
- lu_env_fini(&param->fsp_env);
- OBD_FREE_PTR(param);
- lprocfs_seq_release(inode, file);
-
- return 0;
-}
-
-struct lprocfs_vars fld_server_proc_list[] = {
- { NULL }};
-
LPROC_SEQ_FOPS_RO(fld_proc_targets);
LPROC_SEQ_FOPS(fld_proc_hash);
@@ -363,11 +163,4 @@ struct lprocfs_vars fld_client_proc_list[] = {
{ "cache_flush", &fld_proc_cache_flush_fops },
{ NULL }};
-struct file_operations fld_proc_seq_fops = {
- .owner = THIS_MODULE,
- .open = fldb_seq_open,
- .read = seq_read,
- .release = fldb_seq_release,
-};
-
-#endif
+#endif /* LPROCFS */
diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h
index 4bb68801d3a..edb40afe66f 100644
--- a/drivers/staging/lustre/lustre/include/cl_object.h
+++ b/drivers/staging/lustre/lustre/include/cl_object.h
@@ -758,7 +758,7 @@ struct cl_page {
/**
* Debug information, the task is owning the page.
*/
- task_t *cp_task;
+ struct task_struct *cp_task;
/**
* Owning IO request in cl_page_state::CPS_PAGEOUT and
* cl_page_state::CPS_PAGEIN states. This field is maintained only in
@@ -768,11 +768,11 @@ struct cl_page {
/** List of references to this page, for debugging. */
struct lu_ref cp_reference;
/** Link to an object, for debugging. */
- struct lu_ref_link *cp_obj_ref;
+ struct lu_ref_link cp_obj_ref;
/** Link to a queue, for debugging. */
- struct lu_ref_link *cp_queue_ref;
+ struct lu_ref_link cp_queue_ref;
/** Per-page flags from enum cl_page_flags. Protected by a VM lock. */
- unsigned cp_flags;
+ unsigned cp_flags;
/** Assigned if doing a sync_io */
struct cl_sync_io *cp_sync_io;
};
@@ -1576,13 +1576,13 @@ struct cl_lock {
* \see osc_lock_enqueue_wait(), lov_lock_cancel(), lov_sublock_wait().
*/
struct mutex cll_guard;
- task_t *cll_guarder;
+ struct task_struct *cll_guarder;
int cll_depth;
/**
* the owner for INTRANSIT state
*/
- task_t *cll_intransit_owner;
+ struct task_struct *cll_intransit_owner;
int cll_error;
/**
* Number of holds on a lock. A hold prevents a lock from being
@@ -1625,7 +1625,7 @@ struct cl_lock {
/**
* A reference for cl_lock::cll_descr::cld_obj. For debugging.
*/
- struct lu_ref_link *cll_obj_ref;
+ struct lu_ref_link cll_obj_ref;
#ifdef CONFIG_LOCKDEP
/* "dep_map" name is assumed by lockdep.h macros. */
struct lockdep_map dep_map;
@@ -1869,7 +1869,7 @@ do { \
struct cl_page_list {
unsigned pl_nr;
struct list_head pl_pages;
- task_t *pl_owner;
+ struct task_struct *pl_owner;
};
/**
@@ -2517,7 +2517,7 @@ struct cl_req_obj {
/** object itself */
struct cl_object *ro_obj;
/** reference to cl_req_obj::ro_obj. For debugging. */
- struct lu_ref_link *ro_obj_ref;
+ struct lu_ref_link ro_obj_ref;
/* something else? Number of pages for a given object? */
};
diff --git a/drivers/staging/lustre/lustre/include/linux/lprocfs_status.h b/drivers/staging/lustre/lustre/include/linux/lprocfs_status.h
index 586692272d7..4bcc4dcca3d 100644
--- a/drivers/staging/lustre/lustre/include/linux/lprocfs_status.h
+++ b/drivers/staging/lustre/lustre/include/linux/lprocfs_status.h
@@ -48,7 +48,6 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/version.h>
#include <linux/smp.h>
#include <linux/rwsem.h>
#include <linux/libcfs/libcfs.h>
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h
index dff04688945..9243dfab43d 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h
@@ -87,22 +87,6 @@ static inline void ll_set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt,
#define LTIME_S(time) (time.tv_sec)
-#define ll_permission(inode,mask,nd) inode_permission(inode,mask)
-
-# define ll_generic_permission(inode, mask, flags, check_acl) \
- generic_permission(inode, mask)
-
-#define ll_blkdev_put(a, b) blkdev_put(a, b)
-
-#define ll_dentry_open(a,b,c) dentry_open(a,b,c)
-
-#define ll_vfs_symlink(dir, dentry, mnt, path, mode) \
- vfs_symlink(dir, dentry, path)
-
-
-#define ll_generic_file_llseek_size(file, offset, origin, maxbytes, eof) \
- generic_file_llseek_size(file, offset, origin, maxbytes, eof);
-
/* inode_dio_wait(i) use as-is for write lock */
# define inode_dio_write_done(i) do {} while (0) /* for write unlock */
# define inode_dio_read(i) atomic_inc(&(i)->i_dio_count)
@@ -111,88 +95,10 @@ static inline void ll_set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt,
#define TREE_READ_LOCK_IRQ(mapping) spin_lock_irq(&(mapping)->tree_lock)
#define TREE_READ_UNLOCK_IRQ(mapping) spin_unlock_irq(&(mapping)->tree_lock)
-static inline
-int ll_unregister_blkdev(unsigned int dev, const char *name)
-{
- unregister_blkdev(dev, name);
- return 0;
-}
-
-#define ll_invalidate_bdev(a,b) invalidate_bdev((a))
-
#ifndef FS_HAS_FIEMAP
#define FS_HAS_FIEMAP (0)
#endif
-
-
-/* add a lustre compatible layer for crypto API */
-#include <linux/crypto.h>
-#define ll_crypto_hash crypto_hash
-#define ll_crypto_cipher crypto_blkcipher
-#define ll_crypto_alloc_hash(name, type, mask) crypto_alloc_hash(name, type, mask)
-#define ll_crypto_hash_setkey(tfm, key, keylen) crypto_hash_setkey(tfm, key, keylen)
-#define ll_crypto_hash_init(desc) crypto_hash_init(desc)
-#define ll_crypto_hash_update(desc, sl, bytes) crypto_hash_update(desc, sl, bytes)
-#define ll_crypto_hash_final(desc, out) crypto_hash_final(desc, out)
-#define ll_crypto_blkcipher_setkey(tfm, key, keylen) \
- crypto_blkcipher_setkey(tfm, key, keylen)
-#define ll_crypto_blkcipher_set_iv(tfm, src, len) \
- crypto_blkcipher_set_iv(tfm, src, len)
-#define ll_crypto_blkcipher_get_iv(tfm, dst, len) \
- crypto_blkcipher_get_iv(tfm, dst, len)
-#define ll_crypto_blkcipher_encrypt(desc, dst, src, bytes) \
- crypto_blkcipher_encrypt(desc, dst, src, bytes)
-#define ll_crypto_blkcipher_decrypt(desc, dst, src, bytes) \
- crypto_blkcipher_decrypt(desc, dst, src, bytes)
-#define ll_crypto_blkcipher_encrypt_iv(desc, dst, src, bytes) \
- crypto_blkcipher_encrypt_iv(desc, dst, src, bytes)
-#define ll_crypto_blkcipher_decrypt_iv(desc, dst, src, bytes) \
- crypto_blkcipher_decrypt_iv(desc, dst, src, bytes)
-
-static inline
-struct ll_crypto_cipher *ll_crypto_alloc_blkcipher(const char *name,
- u32 type, u32 mask)
-{
- struct ll_crypto_cipher *rtn = crypto_alloc_blkcipher(name, type, mask);
-
- return (rtn == NULL ? ERR_PTR(-ENOMEM) : rtn);
-}
-
-static inline int ll_crypto_hmac(struct ll_crypto_hash *tfm,
- u8 *key, unsigned int *keylen,
- struct scatterlist *sg,
- unsigned int size, u8 *result)
-{
- struct hash_desc desc;
- int rv;
- desc.tfm = tfm;
- desc.flags = 0;
- rv = crypto_hash_setkey(desc.tfm, key, *keylen);
- if (rv) {
- CERROR("failed to hash setkey: %d\n", rv);
- return rv;
- }
- return crypto_hash_digest(&desc, sg, size, result);
-}
-static inline
-unsigned int ll_crypto_tfm_alg_max_keysize(struct crypto_blkcipher *tfm)
-{
- return crypto_blkcipher_tfm(tfm)->__crt_alg->cra_blkcipher.max_keysize;
-}
-static inline
-unsigned int ll_crypto_tfm_alg_min_keysize(struct crypto_blkcipher *tfm)
-{
- return crypto_blkcipher_tfm(tfm)->__crt_alg->cra_blkcipher.min_keysize;
-}
-
-#define ll_crypto_hash_blocksize(tfm) crypto_hash_blocksize(tfm)
-#define ll_crypto_hash_digestsize(tfm) crypto_hash_digestsize(tfm)
-#define ll_crypto_blkcipher_ivsize(tfm) crypto_blkcipher_ivsize(tfm)
-#define ll_crypto_blkcipher_blocksize(tfm) crypto_blkcipher_blocksize(tfm)
-#define ll_crypto_free_hash(tfm) crypto_free_hash(tfm)
-#define ll_crypto_free_blkcipher(tfm) crypto_free_blkcipher(tfm)
-
#define ll_vfs_rmdir(dir,entry,mnt) vfs_rmdir(dir,entry)
#define ll_vfs_mkdir(inode,dir,mnt,mode) vfs_mkdir(inode,dir,mode)
#define ll_vfs_link(old,mnt,dir,new,mnt1) vfs_link(old,dir,new)
@@ -202,12 +108,6 @@ unsigned int ll_crypto_tfm_alg_min_keysize(struct crypto_blkcipher *tfm)
#define ll_vfs_rename(old,old_dir,mnt,new,new_dir,mnt1) \
vfs_rename(old,old_dir,new,new_dir)
-#ifdef for_each_possible_cpu
-#define cfs_for_each_possible_cpu(cpu) for_each_possible_cpu(cpu)
-#elif defined(for_each_cpu)
-#define cfs_for_each_possible_cpu(cpu) for_each_cpu(cpu)
-#endif
-
#define cfs_bio_io_error(a,b) bio_io_error((a))
#define cfs_bio_endio(a,b,c) bio_endio((a),(c))
@@ -266,9 +166,6 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount)
#define queue_max_phys_segments(rq) queue_max_segments(rq)
#define queue_max_hw_segments(rq) queue_max_segments(rq)
-#define ll_kmap_atomic(a, b) kmap_atomic(a)
-#define ll_kunmap_atomic(a, b) kunmap_atomic(a)
-
#define ll_d_hlist_node hlist_node
#define ll_d_hlist_empty(list) hlist_empty(list)
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_fsfilt.h b/drivers/staging/lustre/lustre/include/linux/lustre_fsfilt.h
index 6c726095738..4da6e372e00 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_fsfilt.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_fsfilt.h
@@ -54,7 +54,7 @@ typedef void (*fsfilt_cb_t)(struct obd_device *obd, __u64 last_rcvd,
struct fsfilt_operations {
struct list_head fs_list;
- module_t *fs_owner;
+ struct module *fs_owner;
char *fs_type;
char *(* fs_getlabel)(struct super_block *sb);
void *(* fs_start)(struct inode *inode, int op, void *desc_private,
@@ -145,16 +145,6 @@ static inline int fsfilt_commit(struct obd_device *obd, struct inode *inode,
return rc;
}
-static inline int fsfilt_map_inode_pages(struct obd_device *obd,
- struct inode *inode,
- struct page **page, int pages,
- unsigned long *blocks,
- int create, struct mutex *mutex)
-{
- return obd->obd_fsops->fs_map_inode_pages(inode, page, pages, blocks,
- create, mutex);
-}
-
static inline int fsfilt_read_record(struct obd_device *obd, struct file *file,
void *buf, loff_t size, loff_t *offs)
{
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_handles.h b/drivers/staging/lustre/lustre/include/linux/lustre_handles.h
index ecf18405125..459b2380600 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_handles.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_handles.h
@@ -42,7 +42,6 @@
#include <asm/types.h>
#include <asm/atomic.h>
#include <linux/list.h>
-#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/types.h>
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_lib.h b/drivers/staging/lustre/lustre/include/linux/lustre_lib.h
index b2f755acadf..57f3b01d1a3 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_lib.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_lib.h
@@ -53,15 +53,13 @@
# include <linux/lustre_common.h>
#ifndef LP_POISON
+# define LI_POISON 0x5a5a5a5a
#if BITS_PER_LONG > 32
-# define LI_POISON ((int)0x5a5a5a5a5a5a5a5a)
-# define LL_POISON ((long)0x5a5a5a5a5a5a5a5a)
-# define LP_POISON ((void *)(long)0x5a5a5a5a5a5a5a5a)
+# define LL_POISON 0x5a5a5a5a5a5a5a5aL
#else
-# define LI_POISON ((int)0x5a5a5a5a)
-# define LL_POISON ((long)0x5a5a5a5a)
-# define LP_POISON ((void *)(long)0x5a5a5a5a)
+# define LL_POISON 0x5a5a5a5aL
#endif
+# define LP_POISON ((void *)LL_POISON)
#endif
/* This macro is only for compatibility reasons with older Linux Lustre user
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_lite.h b/drivers/staging/lustre/lustre/include/linux/lustre_lite.h
index c95dff900b5..9e5df8dabe8 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_lite.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_lite.h
@@ -40,8 +40,6 @@
#endif
-#include <linux/version.h>
-
#include <asm/statfs.h>
#include <linux/fs.h>
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_net.h b/drivers/staging/lustre/lustre/include/linux/lustre_net.h
index 2d7c425d701..05de4d87db9 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_net.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_net.h
@@ -39,7 +39,6 @@
#error Do not #include this file directly. #include <lustre_net.h> instead
#endif
-#include <linux/version.h>
#include <linux/workqueue.h>
/* XXX Liang: should be moved to other header instead of here */
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h b/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h
index a8e9c0c8ffd..a260e99a444 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h
@@ -53,7 +53,7 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
return;
if (PagePrivate(page))
- page->mapping->a_ops->invalidatepage(page, 0);
+ page->mapping->a_ops->invalidatepage(page, 0, PAGE_CACHE_SIZE);
cancel_dirty_page(page, PAGE_SIZE);
ClearPageMappedToDisk(page);
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_quota.h b/drivers/staging/lustre/lustre/include/linux/lustre_quota.h
index 421866b004c..a39505014c8 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_quota.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_quota.h
@@ -39,7 +39,6 @@
#error Do not #include this file directly. #include <lustre_quota.h> instead
#endif
-#include <linux/version.h>
#include <linux/fs.h>
#include <linux/quota.h>
#include <linux/quotaops.h>
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_user.h b/drivers/staging/lustre/lustre/include/linux/lustre_user.h
index ebaf92977f7..9cc2849f3f8 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_user.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_user.h
@@ -41,7 +41,6 @@
#ifndef _LINUX_LUSTRE_USER_H
#define _LINUX_LUSTRE_USER_H
-# include <linux/version.h>
# include <linux/quota.h>
/*
@@ -53,15 +52,19 @@
#include <linux/string.h>
-#if defined(__x86_64__) || defined(__ia64__) || defined(__ppc64__) || \
- defined(__craynv) || defined (__mips64__) || defined(__powerpc64__)
-typedef struct stat lstat_t;
-#define lstat_f lstat
-#define HAVE_LOV_USER_MDS_DATA
-#else
+/*
+ * We need to always use 64bit version because the structure
+ * is shared across entire cluster where 32bit and 64bit machines
+ * are co-existing.
+ */
+#if __BITS_PER_LONG != 64 || defined(__ARCH_WANT_STAT64)
typedef struct stat64 lstat_t;
#define lstat_f lstat64
-#define HAVE_LOV_USER_MDS_DATA
+#else
+typedef struct stat lstat_t;
+#define lstat_f lstat
#endif
+#define HAVE_LOV_USER_MDS_DATA
+
#endif /* _LUSTRE_USER_H */
diff --git a/drivers/staging/lustre/lustre/include/linux/lvfs.h b/drivers/staging/lustre/lustre/include/linux/lvfs.h
index eb59ac7d594..e61f1b87f82 100644
--- a/drivers/staging/lustre/lustre/include/linux/lvfs.h
+++ b/drivers/staging/lustre/lustre/include/linux/lvfs.h
@@ -54,10 +54,10 @@
/* simple.c */
struct lvfs_ucred {
- __u32 luc_uid;
- __u32 luc_gid;
- __u32 luc_fsuid;
- __u32 luc_fsgid;
+ kuid_t luc_uid;
+ kgid_t luc_gid;
+ kuid_t luc_fsuid;
+ kgid_t luc_fsgid;
kernel_cap_t luc_cap;
__u32 luc_umask;
struct group_info *luc_ginfo;
diff --git a/drivers/staging/lustre/lustre/include/linux/obd.h b/drivers/staging/lustre/lustre/include/linux/obd.h
index 2c36c0d19d0..01a50265239 100644
--- a/drivers/staging/lustre/lustre/include/linux/obd.h
+++ b/drivers/staging/lustre/lustre/include/linux/obd.h
@@ -93,11 +93,8 @@ static inline void __client_obd_list_lock(client_obd_lock_t *lock,
lock, task->comm, task->pid,
lock->func, lock->line,
(jiffies - lock->time) / HZ);
- LCONSOLE_WARN("====== for process holding the "
- "lock =====\n");
- libcfs_debug_dumpstack(task);
LCONSOLE_WARN("====== for current process =====\n");
- libcfs_debug_dumpstack(NULL);
+ dump_stack();
LCONSOLE_WARN("====== end =======\n");
cfs_pause(1000 * HZ);
}
diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h
index 55f182205d7..56b05728f61 100644
--- a/drivers/staging/lustre/lustre/include/lprocfs_status.h
+++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h
@@ -345,7 +345,7 @@ enum {
#define EXTRA_FIRST_OPC LDLM_GLIMPSE_ENQUEUE
/* class_obd.c */
-extern proc_dir_entry_t *proc_lustre_root;
+extern struct proc_dir_entry *proc_lustre_root;
struct obd_device;
struct obd_histogram;
@@ -370,18 +370,6 @@ static inline void s2dhms(struct dhms *ts, time_t secs)
#define JOBSTATS_DISABLE "disable"
#define JOBSTATS_PROCNAME_UID "procname_uid"
-typedef void (*cntr_init_callback)(struct lprocfs_stats *stats);
-
-struct obd_job_stats {
- cfs_hash_t *ojs_hash;
- struct list_head ojs_list;
- rwlock_t ojs_lock; /* protect the obj_list */
- cntr_init_callback ojs_cntr_init_fn;
- int ojs_cntr_num;
- int ojs_cleanup_interval;
- time_t ojs_last_cleanup;
-};
-
#ifdef LPROCFS
extern int lprocfs_stats_alloc_one(struct lprocfs_stats *stats,
@@ -562,11 +550,11 @@ extern void lprocfs_free_md_stats(struct obd_device *obddev);
struct obd_export;
struct nid_stat;
extern int lprocfs_add_clear_entry(struct obd_device * obd,
- proc_dir_entry_t *entry);
+ struct proc_dir_entry *entry);
extern int lprocfs_exp_setup(struct obd_export *exp,
lnet_nid_t *peer_nid, int *newnid);
extern int lprocfs_exp_cleanup(struct obd_export *exp);
-extern proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
+extern struct proc_dir_entry *lprocfs_add_simple(struct proc_dir_entry *root,
char *name,
void *data,
struct file_operations *fops);
@@ -579,27 +567,27 @@ lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
unsigned long count, void *data);
extern int lprocfs_nid_stats_clear_read(struct seq_file *m, void *data);
-extern int lprocfs_register_stats(proc_dir_entry_t *root, const char *name,
+extern int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
struct lprocfs_stats *stats);
/* lprocfs_status.c */
-extern int lprocfs_add_vars(proc_dir_entry_t *root,
+extern int lprocfs_add_vars(struct proc_dir_entry *root,
struct lprocfs_vars *var,
void *data);
-extern proc_dir_entry_t *lprocfs_register(const char *name,
- proc_dir_entry_t *parent,
+extern struct proc_dir_entry *lprocfs_register(const char *name,
+ struct proc_dir_entry *parent,
struct lprocfs_vars *list,
void *data);
-extern void lprocfs_remove(proc_dir_entry_t **root);
+extern void lprocfs_remove(struct proc_dir_entry **root);
extern void lprocfs_remove_proc_entry(const char *name,
struct proc_dir_entry *parent);
extern int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list);
extern int lprocfs_obd_cleanup(struct obd_device *obd);
-extern int lprocfs_seq_create(proc_dir_entry_t *parent, const char *name,
+extern int lprocfs_seq_create(struct proc_dir_entry *parent, const char *name,
umode_t mode,
const struct file_operations *seq_fops,
void *data);
@@ -663,8 +651,8 @@ extern int lprocfs_write_u64_helper(const char *buffer, unsigned long count,
extern int lprocfs_write_frac_u64_helper(const char *buffer,
unsigned long count,
__u64 *val, int mult);
-char *lprocfs_find_named_value(const char *buffer, const char *name,
- unsigned long *count);
+extern char *lprocfs_find_named_value(const char *buffer, const char *name,
+ size_t *count);
void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value);
void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value);
void lprocfs_oh_clear(struct obd_histogram *oh);
@@ -748,16 +736,6 @@ struct file_operations name##_fops = { \
.release = lprocfs_single_release, \
};
-/* lprocfs_jobstats.c */
-int lprocfs_job_stats_log(struct obd_device *obd, char *jobid,
- int event, long amount);
-void lprocfs_job_stats_fini(struct obd_device *obd);
-int lprocfs_job_stats_init(struct obd_device *obd, int cntr_num,
- cntr_init_callback fn);
-int lprocfs_rd_job_interval(struct seq_file *m, void *data);
-int lprocfs_wr_job_interval(struct file *file, const char *buffer,
- unsigned long count, void *data);
-
/* lproc_ptlrpc.c */
struct ptlrpc_request;
extern void target_print_req(void *seq_file, struct ptlrpc_request *req);
@@ -826,9 +804,6 @@ extern int lprocfs_quota_rd_qs_factor(char *page, char **start, loff_t off,
extern int lprocfs_quota_wr_qs_factor(struct file *file,
const char *buffer,
unsigned long count, void *data);
-
-
-
#else
/* LPROCFS is not defined */
@@ -863,7 +838,7 @@ static inline void lprocfs_clear_stats(struct lprocfs_stats *stats)
{ return; }
static inline void lprocfs_free_stats(struct lprocfs_stats **stats)
{ return; }
-static inline int lprocfs_register_stats(proc_dir_entry_t *root,
+static inline int lprocfs_register_stats(struct proc_dir_entry *root,
const char *name,
struct lprocfs_stats *stats)
{ return 0; }
@@ -894,7 +869,7 @@ static inline int lprocfs_exp_setup(struct obd_export *exp,lnet_nid_t *peer_nid,
{ return 0; }
static inline int lprocfs_exp_cleanup(struct obd_export *exp)
{ return 0; }
-static inline proc_dir_entry_t *
+static inline struct proc_dir_entry *
lprocfs_add_simple(struct proc_dir_entry *root, char *name,
void *data, struct file_operations *fops)
{return 0; }
@@ -912,15 +887,15 @@ static inline
int lprocfs_nid_stats_clear_read(struct seq_file *m, void *data)
{ return 0; }
-static inline proc_dir_entry_t *
-lprocfs_register(const char *name, proc_dir_entry_t *parent,
+static inline struct proc_dir_entry *
+lprocfs_register(const char *name, struct proc_dir_entry *parent,
struct lprocfs_vars *list, void *data)
{ return NULL; }
-static inline int lprocfs_add_vars(proc_dir_entry_t *root,
+static inline int lprocfs_add_vars(struct proc_dir_entry *root,
struct lprocfs_vars *var,
void *data)
{ return 0; }
-static inline void lprocfs_remove(proc_dir_entry_t **root)
+static inline void lprocfs_remove(struct proc_dir_entry **root)
{ return; }
static inline void lprocfs_remove_proc_entry(const char *name,
struct proc_dir_entry *parent)
@@ -1021,20 +996,6 @@ __u64 lprocfs_stats_collector(struct lprocfs_stats *stats, int idx,
#define LPROC_SEQ_FOPS_RW_TYPE(name, type)
#define LPROC_SEQ_FOPS_WR_ONLY(name, type)
-/* lprocfs_jobstats.c */
-static inline
-int lprocfs_job_stats_log(struct obd_device *obd, char *jobid, int event,
- long amount)
-{ return 0; }
-static inline
-void lprocfs_job_stats_fini(struct obd_device *obd)
-{ return; }
-static inline
-int lprocfs_job_stats_init(struct obd_device *obd, int cntr_num,
- cntr_init_callback fn)
-{ return 0; }
-
-
/* lproc_ptlrpc.c */
#define target_print_req NULL
diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h
index d40ad81b4eb..fa31be886ef 100644
--- a/drivers/staging/lustre/lustre/include/lu_object.h
+++ b/drivers/staging/lustre/lustre/include/lu_object.h
@@ -496,7 +496,7 @@ struct lu_object {
/**
* Link to the device, for debugging.
*/
- struct lu_ref_link *lo_dev_ref;
+ struct lu_ref_link lo_dev_ref;
};
enum lu_object_header_flags {
@@ -665,6 +665,11 @@ lu_site_bkt_from_fid(struct lu_site *site, struct lu_fid *fid)
return cfs_hash_bd_extra_get(site->ls_obj_hash, &bd);
}
+static inline struct seq_server_site *lu_site2seq(const struct lu_site *s)
+{
+ return s->ld_seq_site;
+}
+
/** \name ctors
* Constructors/destructors.
* @{
@@ -868,11 +873,19 @@ static inline __u32 lu_object_attr(const struct lu_object *o)
return o->lo_header->loh_attr;
}
-static inline struct lu_ref_link *lu_object_ref_add(struct lu_object *o,
- const char *scope,
- const void *source)
+static inline void lu_object_ref_add(struct lu_object *o,
+ const char *scope,
+ const void *source)
+{
+ lu_ref_add(&o->lo_header->loh_reference, scope, source);
+}
+
+static inline void lu_object_ref_add_at(struct lu_object *o,
+ struct lu_ref_link *link,
+ const char *scope,
+ const void *source)
{
- return lu_ref_add(&o->lo_header->loh_reference, scope, source);
+ lu_ref_add_at(&o->lo_header->loh_reference, link, scope, source);
}
static inline void lu_object_ref_del(struct lu_object *o,
@@ -1118,7 +1131,7 @@ struct lu_context_key {
/**
* Internal implementation detail: module for this key.
*/
- module_t *lct_owner;
+ struct module *lct_owner;
/**
* References to this key. For debugging.
*/
diff --git a/drivers/staging/lustre/lustre/include/lu_ref.h b/drivers/staging/lustre/lustre/include/lu_ref.h
index 624c19be152..50a2a7f786d 100644
--- a/drivers/staging/lustre/lustre/include/lu_ref.h
+++ b/drivers/staging/lustre/lustre/include/lu_ref.h
@@ -108,7 +108,12 @@
*/
-struct lu_ref {};
+/*
+ * dummy data structures/functions to pass compile for now.
+ * We need to reimplement them with kref.
+ */
+struct lu_ref {};
+struct lu_ref_link {};
static inline void lu_ref_init(struct lu_ref *ref)
{
@@ -132,6 +137,13 @@ static inline struct lu_ref_link *lu_ref_add_atomic(struct lu_ref *ref,
return NULL;
}
+static inline void lu_ref_add_at(struct lu_ref *ref,
+ struct lu_ref_link *link,
+ const char *scope,
+ const void *source)
+{
+}
+
static inline void lu_ref_del(struct lu_ref *ref, const char *scope,
const void *source)
{
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h b/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h
new file mode 100644
index 00000000000..2870487dd28
--- /dev/null
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h
@@ -0,0 +1,215 @@
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.txt
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (C) 2011 FUJITSU LIMITED. All rights reserved.
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ */
+
+#ifndef LUSTRE_ERRNO_H
+#define LUSTRE_ERRNO_H
+
+/*
+ * Only "network" errnos, which are defined below, are allowed on wire (or on
+ * disk). Generic routines exist to help translate between these and a subset
+ * of the "host" errnos. Some host errnos (e.g., EDEADLOCK) are intentionally
+ * left out. See also the comment on lustre_errno_hton_mapping[].
+ *
+ * To maintain compatibility with existing x86 clients and servers, each of
+ * these network errnos has the same numerical value as its corresponding host
+ * errno on x86.
+ */
+#define LUSTRE_EPERM 1 /* Operation not permitted */
+#define LUSTRE_ENOENT 2 /* No such file or directory */
+#define LUSTRE_ESRCH 3 /* No such process */
+#define LUSTRE_EINTR 4 /* Interrupted system call */
+#define LUSTRE_EIO 5 /* I/O error */
+#define LUSTRE_ENXIO 6 /* No such device or address */
+#define LUSTRE_E2BIG 7 /* Argument list too long */
+#define LUSTRE_ENOEXEC 8 /* Exec format error */
+#define LUSTRE_EBADF 9 /* Bad file number */
+#define LUSTRE_ECHILD 10 /* No child processes */
+#define LUSTRE_EAGAIN 11 /* Try again */
+#define LUSTRE_ENOMEM 12 /* Out of memory */
+#define LUSTRE_EACCES 13 /* Permission denied */
+#define LUSTRE_EFAULT 14 /* Bad address */
+#define LUSTRE_ENOTBLK 15 /* Block device required */
+#define LUSTRE_EBUSY 16 /* Device or resource busy */
+#define LUSTRE_EEXIST 17 /* File exists */
+#define LUSTRE_EXDEV 18 /* Cross-device link */
+#define LUSTRE_ENODEV 19 /* No such device */
+#define LUSTRE_ENOTDIR 20 /* Not a directory */
+#define LUSTRE_EISDIR 21 /* Is a directory */
+#define LUSTRE_EINVAL 22 /* Invalid argument */
+#define LUSTRE_ENFILE 23 /* File table overflow */
+#define LUSTRE_EMFILE 24 /* Too many open files */
+#define LUSTRE_ENOTTY 25 /* Not a typewriter */
+#define LUSTRE_ETXTBSY 26 /* Text file busy */
+#define LUSTRE_EFBIG 27 /* File too large */
+#define LUSTRE_ENOSPC 28 /* No space left on device */
+#define LUSTRE_ESPIPE 29 /* Illegal seek */
+#define LUSTRE_EROFS 30 /* Read-only file system */
+#define LUSTRE_EMLINK 31 /* Too many links */
+#define LUSTRE_EPIPE 32 /* Broken pipe */
+#define LUSTRE_EDOM 33 /* Math argument out of domain of
+ func */
+#define LUSTRE_ERANGE 34 /* Math result not representable */
+#define LUSTRE_EDEADLK 35 /* Resource deadlock would occur */
+#define LUSTRE_ENAMETOOLONG 36 /* File name too long */
+#define LUSTRE_ENOLCK 37 /* No record locks available */
+#define LUSTRE_ENOSYS 38 /* Function not implemented */
+#define LUSTRE_ENOTEMPTY 39 /* Directory not empty */
+#define LUSTRE_ELOOP 40 /* Too many symbolic links
+ encountered */
+#define LUSTRE_ENOMSG 42 /* No message of desired type */
+#define LUSTRE_EIDRM 43 /* Identifier removed */
+#define LUSTRE_ECHRNG 44 /* Channel number out of range */
+#define LUSTRE_EL2NSYNC 45 /* Level 2 not synchronized */
+#define LUSTRE_EL3HLT 46 /* Level 3 halted */
+#define LUSTRE_EL3RST 47 /* Level 3 reset */
+#define LUSTRE_ELNRNG 48 /* Link number out of range */
+#define LUSTRE_EUNATCH 49 /* Protocol driver not attached */
+#define LUSTRE_ENOCSI 50 /* No CSI structure available */
+#define LUSTRE_EL2HLT 51 /* Level 2 halted */
+#define LUSTRE_EBADE 52 /* Invalid exchange */
+#define LUSTRE_EBADR 53 /* Invalid request descriptor */
+#define LUSTRE_EXFULL 54 /* Exchange full */
+#define LUSTRE_ENOANO 55 /* No anode */
+#define LUSTRE_EBADRQC 56 /* Invalid request code */
+#define LUSTRE_EBADSLT 57 /* Invalid slot */
+#define LUSTRE_EBFONT 59 /* Bad font file format */
+#define LUSTRE_ENOSTR 60 /* Device not a stream */
+#define LUSTRE_ENODATA 61 /* No data available */
+#define LUSTRE_ETIME 62 /* Timer expired */
+#define LUSTRE_ENOSR 63 /* Out of streams resources */
+#define LUSTRE_ENONET 64 /* Machine is not on the network */
+#define LUSTRE_ENOPKG 65 /* Package not installed */
+#define LUSTRE_EREMOTE 66 /* Object is remote */
+#define LUSTRE_ENOLINK 67 /* Link has been severed */
+#define LUSTRE_EADV 68 /* Advertise error */
+#define LUSTRE_ESRMNT 69 /* Srmount error */
+#define LUSTRE_ECOMM 70 /* Communication error on send */
+#define LUSTRE_EPROTO 71 /* Protocol error */
+#define LUSTRE_EMULTIHOP 72 /* Multihop attempted */
+#define LUSTRE_EDOTDOT 73 /* RFS specific error */
+#define LUSTRE_EBADMSG 74 /* Not a data message */
+#define LUSTRE_EOVERFLOW 75 /* Value too large for defined data
+ type */
+#define LUSTRE_ENOTUNIQ 76 /* Name not unique on network */
+#define LUSTRE_EBADFD 77 /* File descriptor in bad state */
+#define LUSTRE_EREMCHG 78 /* Remote address changed */
+#define LUSTRE_ELIBACC 79 /* Can not access a needed shared
+ library */
+#define LUSTRE_ELIBBAD 80 /* Accessing a corrupted shared
+ library */
+#define LUSTRE_ELIBSCN 81 /* .lib section in a.out corrupted */
+#define LUSTRE_ELIBMAX 82 /* Attempting to link in too many shared
+ libraries */
+#define LUSTRE_ELIBEXEC 83 /* Cannot exec a shared library
+ directly */
+#define LUSTRE_EILSEQ 84 /* Illegal byte sequence */
+#define LUSTRE_ERESTART 85 /* Interrupted system call should be
+ restarted */
+#define LUSTRE_ESTRPIPE 86 /* Streams pipe error */
+#define LUSTRE_EUSERS 87 /* Too many users */
+#define LUSTRE_ENOTSOCK 88 /* Socket operation on non-socket */
+#define LUSTRE_EDESTADDRREQ 89 /* Destination address required */
+#define LUSTRE_EMSGSIZE 90 /* Message too long */
+#define LUSTRE_EPROTOTYPE 91 /* Protocol wrong type for socket */
+#define LUSTRE_ENOPROTOOPT 92 /* Protocol not available */
+#define LUSTRE_EPROTONOSUPPORT 93 /* Protocol not supported */
+#define LUSTRE_ESOCKTNOSUPPORT 94 /* Socket type not supported */
+#define LUSTRE_EOPNOTSUPP 95 /* Operation not supported on transport
+ endpoint */
+#define LUSTRE_EPFNOSUPPORT 96 /* Protocol family not supported */
+#define LUSTRE_EAFNOSUPPORT 97 /* Address family not supported by
+ protocol */
+#define LUSTRE_EADDRINUSE 98 /* Address already in use */
+#define LUSTRE_EADDRNOTAVAIL 99 /* Cannot assign requested address */
+#define LUSTRE_ENETDOWN 100 /* Network is down */
+#define LUSTRE_ENETUNREACH 101 /* Network is unreachable */
+#define LUSTRE_ENETRESET 102 /* Network dropped connection because of
+ reset */
+#define LUSTRE_ECONNABORTED 103 /* Software caused connection abort */
+#define LUSTRE_ECONNRESET 104 /* Connection reset by peer */
+#define LUSTRE_ENOBUFS 105 /* No buffer space available */
+#define LUSTRE_EISCONN 106 /* Transport endpoint is already
+ connected */
+#define LUSTRE_ENOTCONN 107 /* Transport endpoint is not
+ connected */
+#define LUSTRE_ESHUTDOWN 108 /* Cannot send after transport endpoint
+ shutdown */
+#define LUSTRE_ETOOMANYREFS 109 /* Too many references: cannot splice */
+#define LUSTRE_ETIMEDOUT 110 /* Connection timed out */
+#define LUSTRE_ECONNREFUSED 111 /* Connection refused */
+#define LUSTRE_EHOSTDOWN 112 /* Host is down */
+#define LUSTRE_EHOSTUNREACH 113 /* No route to host */
+#define LUSTRE_EALREADY 114 /* Operation already in progress */
+#define LUSTRE_EINPROGRESS 115 /* Operation now in progress */
+#define LUSTRE_ESTALE 116 /* Stale NFS file handle */
+#define LUSTRE_EUCLEAN 117 /* Structure needs cleaning */
+#define LUSTRE_ENOTNAM 118 /* Not a XENIX named type file */
+#define LUSTRE_ENAVAIL 119 /* No XENIX semaphores available */
+#define LUSTRE_EISNAM 120 /* Is a named type file */
+#define LUSTRE_EREMOTEIO 121 /* Remote I/O error */
+#define LUSTRE_EDQUOT 122 /* Quota exceeded */
+#define LUSTRE_ENOMEDIUM 123 /* No medium found */
+#define LUSTRE_EMEDIUMTYPE 124 /* Wrong medium type */
+#define LUSTRE_ECANCELED 125 /* Operation Canceled */
+#define LUSTRE_ENOKEY 126 /* Required key not available */
+#define LUSTRE_EKEYEXPIRED 127 /* Key has expired */
+#define LUSTRE_EKEYREVOKED 128 /* Key has been revoked */
+#define LUSTRE_EKEYREJECTED 129 /* Key was rejected by service */
+#define LUSTRE_EOWNERDEAD 130 /* Owner died */
+#define LUSTRE_ENOTRECOVERABLE 131 /* State not recoverable */
+#define LUSTRE_ERESTARTSYS 512
+#define LUSTRE_ERESTARTNOINTR 513
+#define LUSTRE_ERESTARTNOHAND 514 /* restart if no handler.. */
+#define LUSTRE_ENOIOCTLCMD 515 /* No ioctl command */
+#define LUSTRE_ERESTART_RESTARTBLOCK 516 /* restart by calling
+ sys_restart_syscall */
+#define LUSTRE_EBADHANDLE 521 /* Illegal NFS file handle */
+#define LUSTRE_ENOTSYNC 522 /* Update synchronization mismatch */
+#define LUSTRE_EBADCOOKIE 523 /* Cookie is stale */
+#define LUSTRE_ENOTSUPP 524 /* Operation is not supported */
+#define LUSTRE_ETOOSMALL 525 /* Buffer or request is too small */
+#define LUSTRE_ESERVERFAULT 526 /* An untranslatable error occurred */
+#define LUSTRE_EBADTYPE 527 /* Type not supported by server */
+#define LUSTRE_EJUKEBOX 528 /* Request initiated, but will not
+ complete before timeout */
+#define LUSTRE_EIOCBQUEUED 529 /* iocb queued, will get completion
+ event */
+#define LUSTRE_EIOCBRETRY 530 /* iocb queued, will trigger a retry */
+
+/*
+ * Translations are optimized away on x86. Host errnos that shouldn't be put
+ * on wire could leak through as a result. Do not count on this side effect.
+ */
+#ifdef CONFIG_LUSTRE_TRANSLATE_ERRNOS
+unsigned int lustre_errno_hton(unsigned int h);
+unsigned int lustre_errno_ntoh(unsigned int n);
+#else
+#define lustre_errno_hton(h) (h)
+#define lustre_errno_ntoh(n) (n)
+#endif
+
+#endif /* LUSTRE_ERRNO_H */
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
index 8825460f12a..984235ccd3a 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
@@ -98,6 +98,8 @@
/* Defn's shared with user-space. */
#include <lustre/lustre_user.h>
+#include <lustre/lustre_errno.h>
+
/*
* GENERAL STUFF
*/
@@ -911,7 +913,7 @@ static inline int lu_fid_cmp(const struct lu_fid *f0,
__diff_normalize(fid_ver(f0), fid_ver(f1));
}
-static inline void ostid_cpu_to_le(struct ost_id *src_oi,
+static inline void ostid_cpu_to_le(const struct ost_id *src_oi,
struct ost_id *dst_oi)
{
if (fid_seq_is_mdt0(ostid_seq(src_oi))) {
@@ -922,7 +924,7 @@ static inline void ostid_cpu_to_le(struct ost_id *src_oi,
}
}
-static inline void ostid_le_to_cpu(struct ost_id *src_oi,
+static inline void ostid_le_to_cpu(const struct ost_id *src_oi,
struct ost_id *dst_oi)
{
if (fid_seq_is_mdt0(ostid_seq(src_oi))) {
@@ -1544,10 +1546,16 @@ enum obdo_flags {
#define LOV_MAGIC_V1_DEF 0x0CD10BD0
#define LOV_MAGIC_V3_DEF 0x0CD30BD0
-#define LOV_PATTERN_RAID0 0x001 /* stripes are used round-robin */
-#define LOV_PATTERN_RAID1 0x002 /* stripes are mirrors of each other */
-#define LOV_PATTERN_FIRST 0x100 /* first stripe is not in round-robin */
-#define LOV_PATTERN_CMOBD 0x200
+#define LOV_PATTERN_RAID0 0x001 /* stripes are used round-robin */
+#define LOV_PATTERN_RAID1 0x002 /* stripes are mirrors of each other */
+#define LOV_PATTERN_FIRST 0x100 /* first stripe is not in round-robin */
+#define LOV_PATTERN_CMOBD 0x200
+
+#define LOV_PATTERN_F_MASK 0xffff0000
+#define LOV_PATTERN_F_RELEASED 0x80000000 /* HSM released file */
+
+#define lov_pattern(pattern) (pattern & ~LOV_PATTERN_F_MASK)
+#define lov_pattern_flags(pattern) (pattern & LOV_PATTERN_F_MASK)
#define lov_ost_data lov_ost_data_v1
struct lov_ost_data_v1 { /* per-stripe data structure (little-endian)*/
@@ -1662,6 +1670,17 @@ struct lov_mds_md_v3 { /* LOV EA mds/wire data (little-endian) */
struct lov_ost_data_v1 lmm_objects[0]; /* per-stripe data */
};
+static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic)
+{
+ if (lmm_magic == LOV_MAGIC_V3)
+ return sizeof(struct lov_mds_md_v3) +
+ stripes * sizeof(struct lov_ost_data_v1);
+ else
+ return sizeof(struct lov_mds_md_v1) +
+ stripes * sizeof(struct lov_ost_data_v1);
+}
+
+
#define OBD_MD_FLID (0x00000001ULL) /* object ID */
#define OBD_MD_FLATIME (0x00000002ULL) /* access time */
#define OBD_MD_FLMTIME (0x00000004ULL) /* data modification time */
@@ -2671,6 +2690,10 @@ struct ldlm_res_id {
__u64 name[RES_NAME_SIZE];
};
+#define DLDLMRES "["LPX64":"LPX64":"LPX64"]."LPX64i
+#define PLDLMRES(res) (res)->lr_name.name[0], (res)->lr_name.name[1], \
+ (res)->lr_name.name[2], (res)->lr_name.name[3]
+
extern void lustre_swab_ldlm_res_id (struct ldlm_res_id *id);
static inline int ldlm_res_eq(const struct ldlm_res_id *res0,
@@ -2963,6 +2986,7 @@ typedef enum {
/* LLOG_JOIN_REC = LLOG_OP_MAGIC | 0x50000, obsolete 1.8.0 */
CHANGELOG_REC = LLOG_OP_MAGIC | 0x60000,
CHANGELOG_USER_REC = LLOG_OP_MAGIC | 0x70000,
+ HSM_AGENT_REC = LLOG_OP_MAGIC | 0x80000,
LLOG_HDR_MAGIC = LLOG_OP_MAGIC | 0x45539,
LLOG_LOGID_MAGIC = LLOG_OP_MAGIC | 0x4553b,
} llog_op_type;
@@ -3082,6 +3106,52 @@ struct llog_changelog_user_rec {
struct llog_rec_tail cur_tail;
} __attribute__((packed));
+enum agent_req_status {
+ ARS_WAITING,
+ ARS_STARTED,
+ ARS_FAILED,
+ ARS_CANCELED,
+ ARS_SUCCEED,
+};
+
+static inline char *agent_req_status2name(enum agent_req_status ars)
+{
+ switch (ars) {
+ case ARS_WAITING:
+ return "WAITING";
+ case ARS_STARTED:
+ return "STARTED";
+ case ARS_FAILED:
+ return "FAILED";
+ case ARS_CANCELED:
+ return "CANCELED";
+ case ARS_SUCCEED:
+ return "SUCCEED";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static inline bool agent_req_in_final_state(enum agent_req_status ars)
+{
+ return ((ars == ARS_SUCCEED) || (ars == ARS_FAILED) ||
+ (ars == ARS_CANCELED));
+}
+
+struct llog_agent_req_rec {
+ struct llog_rec_hdr arr_hdr; /**< record header */
+ __u32 arr_status; /**< status of the request */
+ /* must match enum
+ * agent_req_status */
+ __u32 arr_archive_id; /**< backend archive number */
+ __u64 arr_flags; /**< req flags */
+ __u64 arr_compound_id; /**< compound cookie */
+ __u64 arr_req_create; /**< req. creation time */
+ __u64 arr_req_change; /**< req. status change time */
+ struct hsm_action_item arr_hai; /**< req. to the agent */
+ struct llog_rec_tail arr_tail; /**< record tail for_sizezof_only */
+} __attribute__((packed));
+
/* Old llog gen for compatibility */
struct llog_gen {
__u64 mnt_cnt;
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
index 7e9f57507f0..c7bd4473a1d 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
@@ -347,6 +347,16 @@ struct lov_user_md_v3 { /* LOV EA user data (host-endian) */
struct lov_user_ost_data_v1 lmm_objects[0]; /* per-stripe data */
} __attribute__((packed));
+static inline __u32 lov_user_md_size(__u16 stripes, __u32 lmm_magic)
+{
+ if (lmm_magic == LOV_USER_MAGIC_V3)
+ return sizeof(struct lov_user_md_v3) +
+ stripes * sizeof(struct lov_user_ost_data_v1);
+ else
+ return sizeof(struct lov_user_md_v1) +
+ stripes * sizeof(struct lov_user_ost_data_v1);
+}
+
/* Compile with -D_LARGEFILE64_SOURCE or -D_GNU_SOURCE (or #define) to
* use this. It is unsafe to #define those values in this header as it
* is possible the application has already #included <sys/stat.h>. */
@@ -462,6 +472,8 @@ static inline void obd_uuid2fsname(char *buf, char *uuid, int buflen)
/* printf display format
e.g. printf("file FID is "DFID"\n", PFID(fid)); */
+#define FID_NOBRACE_LEN 40
+#define FID_LEN (FID_NOBRACE_LEN + 2)
#define DFID_NOBRACE LPX64":0x%x:0x%x"
#define DFID "["DFID_NOBRACE"]"
#define PFID(fid) \
diff --git a/drivers/staging/lustre/lustre/include/lustre_cfg.h b/drivers/staging/lustre/lustre/include/lustre_cfg.h
index f12429f3821..e14a5f674e8 100644
--- a/drivers/staging/lustre/lustre/include/lustre_cfg.h
+++ b/drivers/staging/lustre/lustre/include/lustre_cfg.h
@@ -211,13 +211,12 @@ static inline int lustre_cfg_len(__u32 bufcount, __u32 *buflens)
{
int i;
int len;
- ENTRY;
len = LCFG_HDR_SIZE(bufcount);
for (i = 0; i < bufcount; i++)
len += cfs_size_round(buflens[i]);
- RETURN(cfs_size_round(len));
+ return cfs_size_round(len);
}
@@ -230,12 +229,10 @@ static inline struct lustre_cfg *lustre_cfg_new(int cmd,
char *ptr;
int i;
- ENTRY;
-
OBD_ALLOC(lcfg, lustre_cfg_len(bufs->lcfg_bufcount,
bufs->lcfg_buflen));
if (!lcfg)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
lcfg->lcfg_version = LUSTRE_CFG_VERSION;
lcfg->lcfg_command = cmd;
@@ -246,7 +243,7 @@ static inline struct lustre_cfg *lustre_cfg_new(int cmd,
lcfg->lcfg_buflens[i] = bufs->lcfg_buflen[i];
LOGL((char *)bufs->lcfg_buf[i], bufs->lcfg_buflen[i], ptr);
}
- RETURN(lcfg);
+ return lcfg;
}
static inline void lustre_cfg_free(struct lustre_cfg *lcfg)
@@ -256,44 +253,39 @@ static inline void lustre_cfg_free(struct lustre_cfg *lcfg)
len = lustre_cfg_len(lcfg->lcfg_bufcount, lcfg->lcfg_buflens);
OBD_FREE(lcfg, len);
- EXIT;
return;
}
static inline int lustre_cfg_sanity_check(void *buf, int len)
{
struct lustre_cfg *lcfg = (struct lustre_cfg *)buf;
- ENTRY;
+
if (!lcfg)
- RETURN(-EINVAL);
+ return -EINVAL;
/* check that the first bits of the struct are valid */
if (len < LCFG_HDR_SIZE(0))
- RETURN(-EINVAL);
+ return -EINVAL;
if (lcfg->lcfg_version != LUSTRE_CFG_VERSION)
- RETURN(-EINVAL);
+ return -EINVAL;
if (lcfg->lcfg_bufcount >= LUSTRE_CFG_MAX_BUFCOUNT)
- RETURN(-EINVAL);
+ return -EINVAL;
/* check that the buflens are valid */
if (len < LCFG_HDR_SIZE(lcfg->lcfg_bufcount))
- RETURN(-EINVAL);
+ return -EINVAL;
/* make sure all the pointers point inside the data */
if (len < lustre_cfg_len(lcfg->lcfg_bufcount, lcfg->lcfg_buflens))
- RETURN(-EINVAL);
+ return -EINVAL;
- RETURN(0);
+ return 0;
}
#include <lustre/lustre_user.h>
-#ifndef INVALID_UID
-#define INVALID_UID (-1)
-#endif
-
/** @} cfg */
#endif // _LUSTRE_CFG_H
diff --git a/drivers/staging/lustre/lustre/include/lustre_disk.h b/drivers/staging/lustre/lustre/include/lustre_disk.h
index 8db6086ea4e..9228b165b25 100644
--- a/drivers/staging/lustre/lustre/include/lustre_disk.h
+++ b/drivers/staging/lustre/lustre/include/lustre_disk.h
@@ -53,20 +53,21 @@
/****************** on-disk files *********************/
-#define MDT_LOGS_DIR "LOGS" /* COMPAT_146 */
-#define MOUNT_CONFIGS_DIR "CONFIGS"
-#define CONFIGS_FILE "mountdata"
+#define MDT_LOGS_DIR "LOGS" /* COMPAT_146 */
+#define MOUNT_CONFIGS_DIR "CONFIGS"
+#define CONFIGS_FILE "mountdata"
/** Persistent mount data are stored on the disk in this file. */
-#define MOUNT_DATA_FILE MOUNT_CONFIGS_DIR"/"CONFIGS_FILE
-#define LAST_RCVD "last_rcvd"
-#define LOV_OBJID "lov_objid"
+#define MOUNT_DATA_FILE MOUNT_CONFIGS_DIR"/"CONFIGS_FILE
+#define LAST_RCVD "last_rcvd"
+#define LOV_OBJID "lov_objid"
#define LOV_OBJSEQ "lov_objseq"
-#define HEALTH_CHECK "health_check"
-#define CAPA_KEYS "capa_keys"
-#define CHANGELOG_USERS "changelog_users"
-#define MGS_NIDTBL_DIR "NIDTBL_VERSIONS"
-#define QMT_DIR "quota_master"
-#define QSD_DIR "quota_slave"
+#define HEALTH_CHECK "health_check"
+#define CAPA_KEYS "capa_keys"
+#define CHANGELOG_USERS "changelog_users"
+#define MGS_NIDTBL_DIR "NIDTBL_VERSIONS"
+#define QMT_DIR "quota_master"
+#define QSD_DIR "quota_slave"
+#define HSM_ACTIONS "hsm_actions"
/****************** persistent mount data *********************/
@@ -226,21 +227,22 @@ struct lustre_mount_data {
char *lmd_osd_type; /* OSD type */
};
-#define LMD_FLG_SERVER 0x0001 /* Mounting a server */
-#define LMD_FLG_CLIENT 0x0002 /* Mounting a client */
-#define LMD_FLG_ABORT_RECOV 0x0008 /* Abort recovery */
-#define LMD_FLG_NOSVC 0x0010 /* Only start MGS/MGC for servers,
- no other services */
-#define LMD_FLG_NOMGS 0x0020 /* Only start target for servers, reusing
- existing MGS services */
-#define LMD_FLG_WRITECONF 0x0040 /* Rewrite config log */
-#define LMD_FLG_NOIR 0x0080 /* NO imperative recovery */
-#define LMD_FLG_NOSCRUB 0x0100 /* Do not trigger scrub automatically */
-#define LMD_FLG_MGS 0x0200 /* Also start MGS along with server */
-#define LMD_FLG_IAM 0x0400 /* IAM dir */
-#define LMD_FLG_NO_PRIMNODE 0x0800 /* all nodes are service nodes */
-#define LMD_FLG_VIRGIN 0x1000 /* the service registers first time */
-#define LMD_FLG_UPDATE 0x2000 /* update parameters */
+#define LMD_FLG_SERVER 0x0001 /* Mounting a server */
+#define LMD_FLG_CLIENT 0x0002 /* Mounting a client */
+#define LMD_FLG_ABORT_RECOV 0x0008 /* Abort recovery */
+#define LMD_FLG_NOSVC 0x0010 /* Only start MGS/MGC for servers,
+ no other services */
+#define LMD_FLG_NOMGS 0x0020 /* Only start target for servers, reusing
+ existing MGS services */
+#define LMD_FLG_WRITECONF 0x0040 /* Rewrite config log */
+#define LMD_FLG_NOIR 0x0080 /* NO imperative recovery */
+#define LMD_FLG_NOSCRUB 0x0100 /* Do not trigger scrub automatically */
+#define LMD_FLG_MGS 0x0200 /* Also start MGS along with server */
+#define LMD_FLG_IAM 0x0400 /* IAM dir */
+#define LMD_FLG_NO_PRIMNODE 0x0800 /* all nodes are service nodes */
+#define LMD_FLG_VIRGIN 0x1000 /* the service registers first time */
+#define LMD_FLG_UPDATE 0x2000 /* update parameters */
+#define LMD_FLG_HSM 0x4000 /* Start coordinator */
#define lmd_is_client(x) ((x)->lmd_flags & LMD_FLG_CLIENT)
diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h
index 317f928fc15..7020d9cd9eb 100644
--- a/drivers/staging/lustre/lustre/include/lustre_dlm.h
+++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h
@@ -57,6 +57,8 @@
#include <interval_tree.h> /* for interval_node{}, ldlm_extent */
#include <lu_ref.h>
+#include "lustre_dlm_flags.h"
+
struct obd_ops;
struct obd_device;
@@ -96,161 +98,6 @@ typedef enum {
} ldlm_side_t;
/**
- * Declaration of flags sent through the wire.
- **/
-#define LDLM_FL_LOCK_CHANGED 0x000001 /* extent, mode, or resource changed */
-
-/**
- * If the server returns one of these flags, then the lock was put on that list.
- * If the client sends one of these flags (during recovery ONLY!), it wants the
- * lock added to the specified list, no questions asked.
- */
-#define LDLM_FL_BLOCK_GRANTED 0x000002
-#define LDLM_FL_BLOCK_CONV 0x000004
-#define LDLM_FL_BLOCK_WAIT 0x000008
-
-/* Used to be LDLM_FL_CBPENDING 0x000010 moved to non-wire flags */
-
-#define LDLM_FL_AST_SENT 0x000020 /* blocking or cancel packet was
- * queued for sending. */
-/* Used to be LDLM_FL_WAIT_NOREPROC 0x000040 moved to non-wire flags */
-/* Used to be LDLM_FL_CANCEL 0x000080 moved to non-wire flags */
-
-/**
- * Lock is being replayed. This could probably be implied by the fact that one
- * of BLOCK_{GRANTED,CONV,WAIT} is set, but that is pretty dangerous.
- */
-#define LDLM_FL_REPLAY 0x000100
-
-#define LDLM_FL_INTENT_ONLY 0x000200 /* Don't grant lock, just do intent. */
-
-/* Used to be LDLM_FL_LOCAL_ONLY 0x000400 moved to non-wire flags */
-/* Used to be LDLM_FL_FAILED 0x000800 moved to non-wire flags */
-
-#define LDLM_FL_HAS_INTENT 0x001000 /* lock request has intent */
-
-/* Used to be LDLM_FL_CANCELING 0x002000 moved to non-wire flags */
-/* Used to be LDLM_FL_LOCAL 0x004000 moved to non-wire flags */
-
-#define LDLM_FL_DISCARD_DATA 0x010000 /* discard (no writeback) on cancel */
-
-#define LDLM_FL_NO_TIMEOUT 0x020000 /* Blocked by group lock - wait
- * indefinitely */
-
-/** file & record locking */
-#define LDLM_FL_BLOCK_NOWAIT 0x040000 /* Server told not to wait if blocked.
- * For AGL, OST will not send glimpse
- * callback. */
-#define LDLM_FL_TEST_LOCK 0x080000 // return blocking lock
-
-/* Used to be LDLM_FL_LVB_READY 0x100000 moved to non-wire flags */
-/* Used to be LDLM_FL_KMS_IGNORE 0x200000 moved to non-wire flags */
-/* Used to be LDLM_FL_NO_LRU 0x400000 moved to non-wire flags */
-
-/* Immediatelly cancel such locks when they block some other locks. Send
- * cancel notification to original lock holder, but expect no reply. This is
- * for clients (like liblustre) that cannot be expected to reliably response
- * to blocking AST. */
-#define LDLM_FL_CANCEL_ON_BLOCK 0x800000
-
-/* Flags flags inherited from parent lock when doing intents. */
-#define LDLM_INHERIT_FLAGS (LDLM_FL_CANCEL_ON_BLOCK)
-
-/* Used to be LDLM_FL_CP_REQD 0x1000000 moved to non-wire flags */
-/* Used to be LDLM_FL_CLEANED 0x2000000 moved to non-wire flags */
-/* Used to be LDLM_FL_ATOMIC_CB 0x4000000 moved to non-wire flags */
-/* Used to be LDLM_FL_BL_AST 0x10000000 moved to non-wire flags */
-/* Used to be LDLM_FL_BL_DONE 0x20000000 moved to non-wire flags */
-
-/* measure lock contention and return -EUSERS if locking contention is high */
-#define LDLM_FL_DENY_ON_CONTENTION 0x40000000
-
-/* These are flags that are mapped into the flags and ASTs of blocking locks */
-#define LDLM_AST_DISCARD_DATA 0x80000000 /* Add FL_DISCARD to blocking ASTs */
-
-/* Flags sent in AST lock_flags to be mapped into the receiving lock. */
-#define LDLM_AST_FLAGS (LDLM_FL_DISCARD_DATA)
-
-/*
- * --------------------------------------------------------------------------
- * NOTE! Starting from this point, that is, LDLM_FL_* flags with values above
- * 0x80000000 will not be sent over the wire.
- * --------------------------------------------------------------------------
- */
-
-/**
- * Declaration of flags not sent through the wire.
- **/
-
-/**
- * Used for marking lock as a target for -EINTR while cp_ast sleep
- * emulation + race with upcoming bl_ast.
- */
-#define LDLM_FL_FAIL_LOC 0x100000000ULL
-
-/**
- * Used while processing the unused list to know that we have already
- * handled this lock and decided to skip it.
- */
-#define LDLM_FL_SKIPPED 0x200000000ULL
-/* this lock is being destroyed */
-#define LDLM_FL_CBPENDING 0x400000000ULL
-/* not a real flag, not saved in lock */
-#define LDLM_FL_WAIT_NOREPROC 0x800000000ULL
-/* cancellation callback already run */
-#define LDLM_FL_CANCEL 0x1000000000ULL
-#define LDLM_FL_LOCAL_ONLY 0x2000000000ULL
-/* don't run the cancel callback under ldlm_cli_cancel_unused */
-#define LDLM_FL_FAILED 0x4000000000ULL
-/* lock cancel has already been sent */
-#define LDLM_FL_CANCELING 0x8000000000ULL
-/* local lock (ie, no srv/cli split) */
-#define LDLM_FL_LOCAL 0x10000000000ULL
-/* XXX FIXME: This is being added to b_size as a low-risk fix to the fact that
- * the LVB filling happens _after_ the lock has been granted, so another thread
- * can match it before the LVB has been updated. As a dirty hack, we set
- * LDLM_FL_LVB_READY only after we've done the LVB poop.
- * this is only needed on LOV/OSC now, where LVB is actually used and callers
- * must set it in input flags.
- *
- * The proper fix is to do the granting inside of the completion AST, which can
- * be replaced with a LVB-aware wrapping function for OSC locks. That change is
- * pretty high-risk, though, and would need a lot more testing. */
-#define LDLM_FL_LVB_READY 0x20000000000ULL
-/* A lock contributes to the known minimum size (KMS) calculation until it has
- * finished the part of its cancelation that performs write back on its dirty
- * pages. It can remain on the granted list during this whole time. Threads
- * racing to update the KMS after performing their writeback need to know to
- * exclude each other's locks from the calculation as they walk the granted
- * list. */
-#define LDLM_FL_KMS_IGNORE 0x40000000000ULL
-/* completion AST to be executed */
-#define LDLM_FL_CP_REQD 0x80000000000ULL
-/* cleanup_resource has already handled the lock */
-#define LDLM_FL_CLEANED 0x100000000000ULL
-/* optimization hint: LDLM can run blocking callback from current context
- * w/o involving separate thread. in order to decrease cs rate */
-#define LDLM_FL_ATOMIC_CB 0x200000000000ULL
-
-/* It may happen that a client initiates two operations, e.g. unlink and
- * mkdir, such that the server sends a blocking AST for conflicting
- * locks to this client for the first operation, whereas the second
- * operation has canceled this lock and is waiting for rpc_lock which is
- * taken by the first operation. LDLM_FL_BL_AST is set by
- * ldlm_callback_handler() in the lock to prevent the Early Lock Cancel
- * (ELC) code from cancelling it.
- *
- * LDLM_FL_BL_DONE is to be set by ldlm_cancel_callback() when lock
- * cache is dropped to let ldlm_callback_handler() return EINVAL to the
- * server. It is used when ELC RPC is already prepared and is waiting
- * for rpc_lock, too late to send a separate CANCEL RPC. */
-#define LDLM_FL_BL_AST 0x400000000000ULL
-#define LDLM_FL_BL_DONE 0x800000000000ULL
-/* Don't put lock into the LRU list, so that it is not canceled due to aging.
- * Used by MGC locks, they are cancelled only at unmount or by callback. */
-#define LDLM_FL_NO_LRU 0x1000000000000ULL
-
-/**
* The blocking callback is overloaded to perform two functions. These flags
* indicate which operation should be performed.
*/
@@ -388,7 +235,7 @@ struct ldlm_pool_ops {
*/
struct ldlm_pool {
/** Pool proc directory. */
- proc_dir_entry_t *pl_proc_dir;
+ struct proc_dir_entry *pl_proc_dir;
/** Pool name, must be long enough to hold compound proc entry name. */
char pl_name[100];
/** Lock for protecting SLV/CLV updates. */
@@ -720,8 +567,6 @@ typedef int (*ldlm_completion_callback)(struct ldlm_lock *lock, __u64 flags,
void *data);
/** Type for glimpse callback function of a lock. */
typedef int (*ldlm_glimpse_callback)(struct ldlm_lock *lock, void *data);
-/** Type for weight callback function of a lock. */
-typedef unsigned long (*ldlm_weigh_callback)(struct ldlm_lock *lock);
/** Work list for sending GL ASTs to multiple locks. */
struct ldlm_glimpse_work {
@@ -890,9 +735,6 @@ struct ldlm_lock {
*/
ldlm_glimpse_callback l_glimpse_ast;
- /** XXX apparently unused "weight" handler. To be removed? */
- ldlm_weigh_callback l_weigh_ast;
-
/**
* Lock export.
* This is a pointer to actual client export for locks that were granted
@@ -919,11 +761,11 @@ struct ldlm_lock {
ldlm_policy_data_t l_policy_data;
/**
- * Lock state flags.
- * Like whenever we receive any blocking requests for this lock, etc.
- * Protected by lr_lock.
+ * Lock state flags. Protected by lr_lock.
+ * \see lustre_dlm_flags.h where the bits are defined.
*/
__u64 l_flags;
+
/**
* Lock r/w usage counters.
* Protected by lr_lock.
@@ -952,34 +794,6 @@ struct ldlm_lock {
/** Originally requested extent for the extent lock. */
struct ldlm_extent l_req_extent;
- unsigned int l_failed:1,
- /**
- * Set for locks that were removed from class hash table and will be
- * destroyed when last reference to them is released. Set by
- * ldlm_lock_destroy_internal().
- *
- * Protected by lock and resource locks.
- */
- l_destroyed:1,
- /*
- * it's set in lock_res_and_lock() and unset in unlock_res_and_lock().
- *
- * NB: compared with check_res_locked(), checking this bit is cheaper.
- * Also, spin_is_locked() is deprecated for kernel code; one reason is
- * because it works only for SMP so user needs to add extra macros like
- * LASSERT_SPIN_LOCKED for uniprocessor kernels.
- */
- l_res_locked:1,
- /*
- * It's set once we call ldlm_add_waiting_lock_res_locked()
- * to start the lock-timeout timer and it will never be reset.
- *
- * Protected by lock_res_and_lock().
- */
- l_waited:1,
- /** Flag whether this is a server namespace lock. */
- l_ns_srv:1;
-
/*
* Client-side-only members.
*/
@@ -1230,7 +1044,6 @@ struct ldlm_enqueue_info {
void *ei_cb_bl; /** blocking lock callback */
void *ei_cb_cp; /** lock completion callback */
void *ei_cb_gl; /** lock glimpse callback */
- void *ei_cb_wg; /** lock weigh callback */
void *ei_cbdata; /** Data to be passed into callbacks. */
};
@@ -1328,7 +1141,6 @@ struct ldlm_callback_suite {
ldlm_completion_callback lcs_completion;
ldlm_blocking_callback lcs_blocking;
ldlm_glimpse_callback lcs_glimpse;
- ldlm_weigh_callback lcs_weigh;
};
/* ldlm_lockd.c */
@@ -1471,8 +1283,6 @@ void ldlm_namespace_free(struct ldlm_namespace *ns,
struct obd_import *imp, int force);
void ldlm_namespace_register(struct ldlm_namespace *ns, ldlm_side_t client);
void ldlm_namespace_unregister(struct ldlm_namespace *ns, ldlm_side_t client);
-void ldlm_namespace_move_locked(struct ldlm_namespace *ns, ldlm_side_t client);
-struct ldlm_namespace *ldlm_namespace_first_locked(ldlm_side_t client);
void ldlm_namespace_get(struct ldlm_namespace *ns);
void ldlm_namespace_put(struct ldlm_namespace *ns);
int ldlm_proc_setup(void);
@@ -1645,7 +1455,7 @@ void unlock_res_and_lock(struct ldlm_lock *lock);
* There are not used outside of ldlm.
* @{
*/
-void ldlm_pools_recalc(ldlm_side_t client);
+int ldlm_pools_recalc(ldlm_side_t client);
int ldlm_pools_init(void);
void ldlm_pools_fini(void);
diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h b/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h
new file mode 100644
index 00000000000..8c34d9d4d25
--- /dev/null
+++ b/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h
@@ -0,0 +1,460 @@
+/* -*- buffer-read-only: t -*- vi: set ro:
+ *
+ * DO NOT EDIT THIS FILE (lustre_dlm_flags.h)
+ *
+ * It has been AutoGen-ed
+ * From the definitions lustre_dlm_flags.def
+ * and the template file lustre_dlm_flags.tpl
+ *
+ * lustre 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * lustre is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * \file lustre_dlm_flags.h
+ * The flags and collections of flags (masks) for \see struct ldlm_lock.
+ * This file is derived from flag definitions in lustre_dlm_flags.def.
+ * The format is defined in the lustre_dlm_flags.tpl template file.
+ *
+ * \addtogroup LDLM Lustre Distributed Lock Manager
+ * @{
+ *
+ * \name flags
+ * The flags and collections of flags (masks) for \see struct ldlm_lock.
+ * @{
+ */
+#ifndef LDLM_ALL_FLAGS_MASK
+
+/** l_flags bits marked as "all_flags" bits */
+#define LDLM_FL_ALL_FLAGS_MASK 0x007FFFFFC08F132FULL
+
+/** l_flags bits marked as "ast" bits */
+#define LDLM_FL_AST_MASK 0x0000000080000000ULL
+
+/** l_flags bits marked as "blocked" bits */
+#define LDLM_FL_BLOCKED_MASK 0x000000000000000EULL
+
+/** l_flags bits marked as "gone" bits */
+#define LDLM_FL_GONE_MASK 0x0006004000000000ULL
+
+/** l_flags bits marked as "hide_lock" bits */
+#define LDLM_FL_HIDE_LOCK_MASK 0x0000206400000000ULL
+
+/** l_flags bits marked as "inherit" bits */
+#define LDLM_FL_INHERIT_MASK 0x0000000000800000ULL
+
+/** l_flags bits marked as "local_only" bits */
+#define LDLM_FL_LOCAL_ONLY_MASK 0x007FFFFF00000000ULL
+
+/** l_flags bits marked as "on_wire" bits */
+#define LDLM_FL_ON_WIRE_MASK 0x00000000C08F132FULL
+
+/** extent, mode, or resource changed */
+#define LDLM_FL_LOCK_CHANGED 0x0000000000000001ULL // bit 0
+#define ldlm_is_lock_changed(_l) LDLM_TEST_FLAG(( _l), 1ULL << 0)
+#define ldlm_set_lock_changed(_l) LDLM_SET_FLAG(( _l), 1ULL << 0)
+#define ldlm_clear_lock_changed(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 0)
+
+/**
+ * Server placed lock on granted list, or a recovering client wants the
+ * lock added to the granted list, no questions asked. */
+#define LDLM_FL_BLOCK_GRANTED 0x0000000000000002ULL // bit 1
+#define ldlm_is_block_granted(_l) LDLM_TEST_FLAG(( _l), 1ULL << 1)
+#define ldlm_set_block_granted(_l) LDLM_SET_FLAG(( _l), 1ULL << 1)
+#define ldlm_clear_block_granted(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 1)
+
+/**
+ * Server placed lock on conv list, or a recovering client wants the lock
+ * added to the conv list, no questions asked. */
+#define LDLM_FL_BLOCK_CONV 0x0000000000000004ULL // bit 2
+#define ldlm_is_block_conv(_l) LDLM_TEST_FLAG(( _l), 1ULL << 2)
+#define ldlm_set_block_conv(_l) LDLM_SET_FLAG(( _l), 1ULL << 2)
+#define ldlm_clear_block_conv(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 2)
+
+/**
+ * Server placed lock on wait list, or a recovering client wants the lock
+ * added to the wait list, no questions asked. */
+#define LDLM_FL_BLOCK_WAIT 0x0000000000000008ULL // bit 3
+#define ldlm_is_block_wait(_l) LDLM_TEST_FLAG(( _l), 1ULL << 3)
+#define ldlm_set_block_wait(_l) LDLM_SET_FLAG(( _l), 1ULL << 3)
+#define ldlm_clear_block_wait(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 3)
+
+/** blocking or cancel packet was queued for sending. */
+#define LDLM_FL_AST_SENT 0x0000000000000020ULL // bit 5
+#define ldlm_is_ast_sent(_l) LDLM_TEST_FLAG(( _l), 1ULL << 5)
+#define ldlm_set_ast_sent(_l) LDLM_SET_FLAG(( _l), 1ULL << 5)
+#define ldlm_clear_ast_sent(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 5)
+
+/**
+ * Lock is being replayed. This could probably be implied by the fact that
+ * one of BLOCK_{GRANTED,CONV,WAIT} is set, but that is pretty dangerous. */
+#define LDLM_FL_REPLAY 0x0000000000000100ULL // bit 8
+#define ldlm_is_replay(_l) LDLM_TEST_FLAG(( _l), 1ULL << 8)
+#define ldlm_set_replay(_l) LDLM_SET_FLAG(( _l), 1ULL << 8)
+#define ldlm_clear_replay(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 8)
+
+/** Don't grant lock, just do intent. */
+#define LDLM_FL_INTENT_ONLY 0x0000000000000200ULL // bit 9
+#define ldlm_is_intent_only(_l) LDLM_TEST_FLAG(( _l), 1ULL << 9)
+#define ldlm_set_intent_only(_l) LDLM_SET_FLAG(( _l), 1ULL << 9)
+#define ldlm_clear_intent_only(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 9)
+
+/** lock request has intent */
+#define LDLM_FL_HAS_INTENT 0x0000000000001000ULL // bit 12
+#define ldlm_is_has_intent(_l) LDLM_TEST_FLAG(( _l), 1ULL << 12)
+#define ldlm_set_has_intent(_l) LDLM_SET_FLAG(( _l), 1ULL << 12)
+#define ldlm_clear_has_intent(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 12)
+
+/** discard (no writeback) on cancel */
+#define LDLM_FL_DISCARD_DATA 0x0000000000010000ULL // bit 16
+#define ldlm_is_discard_data(_l) LDLM_TEST_FLAG(( _l), 1ULL << 16)
+#define ldlm_set_discard_data(_l) LDLM_SET_FLAG(( _l), 1ULL << 16)
+#define ldlm_clear_discard_data(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 16)
+
+/** Blocked by group lock - wait indefinitely */
+#define LDLM_FL_NO_TIMEOUT 0x0000000000020000ULL // bit 17
+#define ldlm_is_no_timeout(_l) LDLM_TEST_FLAG(( _l), 1ULL << 17)
+#define ldlm_set_no_timeout(_l) LDLM_SET_FLAG(( _l), 1ULL << 17)
+#define ldlm_clear_no_timeout(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 17)
+
+/**
+ * Server told not to wait if blocked. For AGL, OST will not send glimpse
+ * callback. */
+#define LDLM_FL_BLOCK_NOWAIT 0x0000000000040000ULL // bit 18
+#define ldlm_is_block_nowait(_l) LDLM_TEST_FLAG(( _l), 1ULL << 18)
+#define ldlm_set_block_nowait(_l) LDLM_SET_FLAG(( _l), 1ULL << 18)
+#define ldlm_clear_block_nowait(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 18)
+
+/** return blocking lock */
+#define LDLM_FL_TEST_LOCK 0x0000000000080000ULL // bit 19
+#define ldlm_is_test_lock(_l) LDLM_TEST_FLAG(( _l), 1ULL << 19)
+#define ldlm_set_test_lock(_l) LDLM_SET_FLAG(( _l), 1ULL << 19)
+#define ldlm_clear_test_lock(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 19)
+
+/**
+ * Immediatelly cancel such locks when they block some other locks. Send
+ * cancel notification to original lock holder, but expect no reply. This
+ * is for clients (like liblustre) that cannot be expected to reliably
+ * response to blocking AST. */
+#define LDLM_FL_CANCEL_ON_BLOCK 0x0000000000800000ULL // bit 23
+#define ldlm_is_cancel_on_block(_l) LDLM_TEST_FLAG(( _l), 1ULL << 23)
+#define ldlm_set_cancel_on_block(_l) LDLM_SET_FLAG(( _l), 1ULL << 23)
+#define ldlm_clear_cancel_on_block(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 23)
+
+/**
+ * measure lock contention and return -EUSERS if locking contention is high */
+#define LDLM_FL_DENY_ON_CONTENTION 0x0000000040000000ULL // bit 30
+#define ldlm_is_deny_on_contention(_l) LDLM_TEST_FLAG(( _l), 1ULL << 30)
+#define ldlm_set_deny_on_contention(_l) LDLM_SET_FLAG(( _l), 1ULL << 30)
+#define ldlm_clear_deny_on_contention(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 30)
+
+/**
+ * These are flags that are mapped into the flags and ASTs of blocking
+ * locks Add FL_DISCARD to blocking ASTs */
+#define LDLM_FL_AST_DISCARD_DATA 0x0000000080000000ULL // bit 31
+#define ldlm_is_ast_discard_data(_l) LDLM_TEST_FLAG(( _l), 1ULL << 31)
+#define ldlm_set_ast_discard_data(_l) LDLM_SET_FLAG(( _l), 1ULL << 31)
+#define ldlm_clear_ast_discard_data(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 31)
+
+/**
+ * Used for marking lock as a target for -EINTR while cp_ast sleep emulation
+ * + race with upcoming bl_ast. */
+#define LDLM_FL_FAIL_LOC 0x0000000100000000ULL // bit 32
+#define ldlm_is_fail_loc(_l) LDLM_TEST_FLAG(( _l), 1ULL << 32)
+#define ldlm_set_fail_loc(_l) LDLM_SET_FLAG(( _l), 1ULL << 32)
+#define ldlm_clear_fail_loc(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 32)
+
+/**
+ * Used while processing the unused list to know that we have already
+ * handled this lock and decided to skip it. */
+#define LDLM_FL_SKIPPED 0x0000000200000000ULL // bit 33
+#define ldlm_is_skipped(_l) LDLM_TEST_FLAG(( _l), 1ULL << 33)
+#define ldlm_set_skipped(_l) LDLM_SET_FLAG(( _l), 1ULL << 33)
+#define ldlm_clear_skipped(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 33)
+
+/** this lock is being destroyed */
+#define LDLM_FL_CBPENDING 0x0000000400000000ULL // bit 34
+#define ldlm_is_cbpending(_l) LDLM_TEST_FLAG(( _l), 1ULL << 34)
+#define ldlm_set_cbpending(_l) LDLM_SET_FLAG(( _l), 1ULL << 34)
+#define ldlm_clear_cbpending(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 34)
+
+/** not a real flag, not saved in lock */
+#define LDLM_FL_WAIT_NOREPROC 0x0000000800000000ULL // bit 35
+#define ldlm_is_wait_noreproc(_l) LDLM_TEST_FLAG(( _l), 1ULL << 35)
+#define ldlm_set_wait_noreproc(_l) LDLM_SET_FLAG(( _l), 1ULL << 35)
+#define ldlm_clear_wait_noreproc(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 35)
+
+/** cancellation callback already run */
+#define LDLM_FL_CANCEL 0x0000001000000000ULL // bit 36
+#define ldlm_is_cancel(_l) LDLM_TEST_FLAG(( _l), 1ULL << 36)
+#define ldlm_set_cancel(_l) LDLM_SET_FLAG(( _l), 1ULL << 36)
+#define ldlm_clear_cancel(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 36)
+
+/** whatever it might mean */
+#define LDLM_FL_LOCAL_ONLY 0x0000002000000000ULL // bit 37
+#define ldlm_is_local_only(_l) LDLM_TEST_FLAG(( _l), 1ULL << 37)
+#define ldlm_set_local_only(_l) LDLM_SET_FLAG(( _l), 1ULL << 37)
+#define ldlm_clear_local_only(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 37)
+
+/** don't run the cancel callback under ldlm_cli_cancel_unused */
+#define LDLM_FL_FAILED 0x0000004000000000ULL // bit 38
+#define ldlm_is_failed(_l) LDLM_TEST_FLAG(( _l), 1ULL << 38)
+#define ldlm_set_failed(_l) LDLM_SET_FLAG(( _l), 1ULL << 38)
+#define ldlm_clear_failed(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 38)
+
+/** lock cancel has already been sent */
+#define LDLM_FL_CANCELING 0x0000008000000000ULL // bit 39
+#define ldlm_is_canceling(_l) LDLM_TEST_FLAG(( _l), 1ULL << 39)
+#define ldlm_set_canceling(_l) LDLM_SET_FLAG(( _l), 1ULL << 39)
+#define ldlm_clear_canceling(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 39)
+
+/** local lock (ie, no srv/cli split) */
+#define LDLM_FL_LOCAL 0x0000010000000000ULL // bit 40
+#define ldlm_is_local(_l) LDLM_TEST_FLAG(( _l), 1ULL << 40)
+#define ldlm_set_local(_l) LDLM_SET_FLAG(( _l), 1ULL << 40)
+#define ldlm_clear_local(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 40)
+
+/**
+ * XXX FIXME: This is being added to b_size as a low-risk fix to the
+ * fact that the LVB filling happens _after_ the lock has been granted,
+ * so another thread can match it before the LVB has been updated. As a
+ * dirty hack, we set LDLM_FL_LVB_READY only after we've done the LVB poop.
+ * this is only needed on LOV/OSC now, where LVB is actually used and
+ * callers must set it in input flags.
+ *
+ * The proper fix is to do the granting inside of the completion AST,
+ * which can be replaced with a LVB-aware wrapping function for OSC locks.
+ * That change is pretty high-risk, though, and would need a lot more
+ * testing. */
+#define LDLM_FL_LVB_READY 0x0000020000000000ULL // bit 41
+#define ldlm_is_lvb_ready(_l) LDLM_TEST_FLAG(( _l), 1ULL << 41)
+#define ldlm_set_lvb_ready(_l) LDLM_SET_FLAG(( _l), 1ULL << 41)
+#define ldlm_clear_lvb_ready(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 41)
+
+/**
+ * A lock contributes to the known minimum size (KMS) calculation until it
+ * has finished the part of its cancelation that performs write back on its
+ * dirty pages. It can remain on the granted list during this whole time.
+ * Threads racing to update the KMS after performing their writeback need
+ * to know to exclude each other's locks from the calculation as they walk
+ * the granted list. */
+#define LDLM_FL_KMS_IGNORE 0x0000040000000000ULL // bit 42
+#define ldlm_is_kms_ignore(_l) LDLM_TEST_FLAG(( _l), 1ULL << 42)
+#define ldlm_set_kms_ignore(_l) LDLM_SET_FLAG(( _l), 1ULL << 42)
+#define ldlm_clear_kms_ignore(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 42)
+
+/** completion AST to be executed */
+#define LDLM_FL_CP_REQD 0x0000080000000000ULL // bit 43
+#define ldlm_is_cp_reqd(_l) LDLM_TEST_FLAG(( _l), 1ULL << 43)
+#define ldlm_set_cp_reqd(_l) LDLM_SET_FLAG(( _l), 1ULL << 43)
+#define ldlm_clear_cp_reqd(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 43)
+
+/** cleanup_resource has already handled the lock */
+#define LDLM_FL_CLEANED 0x0000100000000000ULL // bit 44
+#define ldlm_is_cleaned(_l) LDLM_TEST_FLAG(( _l), 1ULL << 44)
+#define ldlm_set_cleaned(_l) LDLM_SET_FLAG(( _l), 1ULL << 44)
+#define ldlm_clear_cleaned(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 44)
+
+/**
+ * optimization hint: LDLM can run blocking callback from current context
+ * w/o involving separate thread. in order to decrease cs rate */
+#define LDLM_FL_ATOMIC_CB 0x0000200000000000ULL // bit 45
+#define ldlm_is_atomic_cb(_l) LDLM_TEST_FLAG(( _l), 1ULL << 45)
+#define ldlm_set_atomic_cb(_l) LDLM_SET_FLAG(( _l), 1ULL << 45)
+#define ldlm_clear_atomic_cb(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 45)
+
+/**
+ * It may happen that a client initiates two operations, e.g. unlink and
+ * mkdir, such that the server sends a blocking AST for conflicting locks
+ * to this client for the first operation, whereas the second operation
+ * has canceled this lock and is waiting for rpc_lock which is taken by
+ * the first operation. LDLM_FL_BL_AST is set by ldlm_callback_handler() in
+ * the lock to prevent the Early Lock Cancel (ELC) code from cancelling it.
+ *
+ * LDLM_FL_BL_DONE is to be set by ldlm_cancel_callback() when lock cache is
+ * dropped to let ldlm_callback_handler() return EINVAL to the server. It
+ * is used when ELC RPC is already prepared and is waiting for rpc_lock,
+ * too late to send a separate CANCEL RPC. */
+#define LDLM_FL_BL_AST 0x0000400000000000ULL // bit 46
+#define ldlm_is_bl_ast(_l) LDLM_TEST_FLAG(( _l), 1ULL << 46)
+#define ldlm_set_bl_ast(_l) LDLM_SET_FLAG(( _l), 1ULL << 46)
+#define ldlm_clear_bl_ast(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 46)
+
+/** whatever it might mean */
+#define LDLM_FL_BL_DONE 0x0000800000000000ULL // bit 47
+#define ldlm_is_bl_done(_l) LDLM_TEST_FLAG(( _l), 1ULL << 47)
+#define ldlm_set_bl_done(_l) LDLM_SET_FLAG(( _l), 1ULL << 47)
+#define ldlm_clear_bl_done(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 47)
+
+/**
+ * Don't put lock into the LRU list, so that it is not canceled due
+ * to aging. Used by MGC locks, they are cancelled only at unmount or
+ * by callback. */
+#define LDLM_FL_NO_LRU 0x0001000000000000ULL // bit 48
+#define ldlm_is_no_lru(_l) LDLM_TEST_FLAG(( _l), 1ULL << 48)
+#define ldlm_set_no_lru(_l) LDLM_SET_FLAG(( _l), 1ULL << 48)
+#define ldlm_clear_no_lru(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 48)
+
+/**
+ * Set for locks that failed and where the server has been notified.
+ *
+ * Protected by lock and resource locks. */
+#define LDLM_FL_FAIL_NOTIFIED 0x0002000000000000ULL // bit 49
+#define ldlm_is_fail_notified(_l) LDLM_TEST_FLAG(( _l), 1ULL << 49)
+#define ldlm_set_fail_notified(_l) LDLM_SET_FLAG(( _l), 1ULL << 49)
+#define ldlm_clear_fail_notified(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 49)
+
+/**
+ * Set for locks that were removed from class hash table and will
+ * be destroyed when last reference to them is released. Set by
+ * ldlm_lock_destroy_internal().
+ *
+ * Protected by lock and resource locks. */
+#define LDLM_FL_DESTROYED 0x0004000000000000ULL // bit 50
+#define ldlm_is_destroyed(_l) LDLM_TEST_FLAG(( _l), 1ULL << 50)
+#define ldlm_set_destroyed(_l) LDLM_SET_FLAG(( _l), 1ULL << 50)
+#define ldlm_clear_destroyed(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 50)
+
+/** flag whether this is a server namespace lock */
+#define LDLM_FL_SERVER_LOCK 0x0008000000000000ULL // bit 51
+#define ldlm_is_server_lock(_l) LDLM_TEST_FLAG(( _l), 1ULL << 51)
+#define ldlm_set_server_lock(_l) LDLM_SET_FLAG(( _l), 1ULL << 51)
+#define ldlm_clear_server_lock(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 51)
+
+/**
+ * It's set in lock_res_and_lock() and unset in unlock_res_and_lock().
+ *
+ * NB: compared with check_res_locked(), checking this bit is cheaper.
+ * Also, spin_is_locked() is deprecated for kernel code; one reason is
+ * because it works only for SMP so user needs to add extra macros like
+ * LASSERT_SPIN_LOCKED for uniprocessor kernels. */
+#define LDLM_FL_RES_LOCKED 0x0010000000000000ULL // bit 52
+#define ldlm_is_res_locked(_l) LDLM_TEST_FLAG(( _l), 1ULL << 52)
+#define ldlm_set_res_locked(_l) LDLM_SET_FLAG(( _l), 1ULL << 52)
+#define ldlm_clear_res_locked(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 52)
+
+/**
+ * It's set once we call ldlm_add_waiting_lock_res_locked() to start the
+ * lock-timeout timer and it will never be reset.
+ *
+ * Protected by lock and resource locks. */
+#define LDLM_FL_WAITED 0x0020000000000000ULL // bit 53
+#define ldlm_is_waited(_l) LDLM_TEST_FLAG(( _l), 1ULL << 53)
+#define ldlm_set_waited(_l) LDLM_SET_FLAG(( _l), 1ULL << 53)
+#define ldlm_clear_waited(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 53)
+
+/** Flag whether this is a server namespace lock. */
+#define LDLM_FL_NS_SRV 0x0040000000000000ULL // bit 54
+#define ldlm_is_ns_srv(_l) LDLM_TEST_FLAG(( _l), 1ULL << 54)
+#define ldlm_set_ns_srv(_l) LDLM_SET_FLAG(( _l), 1ULL << 54)
+#define ldlm_clear_ns_srv(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 54)
+
+/** test for ldlm_lock flag bit set */
+#define LDLM_TEST_FLAG(_l, _b) (((_l)->l_flags & (_b)) != 0)
+
+/** set a ldlm_lock flag bit */
+#define LDLM_SET_FLAG(_l, _b) (((_l)->l_flags |= (_b))
+
+/** clear a ldlm_lock flag bit */
+#define LDLM_CLEAR_FLAG(_l, _b) (((_l)->l_flags &= ~(_b))
+
+/** Mask of flags inherited from parent lock when doing intents. */
+#define LDLM_INHERIT_FLAGS LDLM_FL_INHERIT_MASK
+
+/** Mask of Flags sent in AST lock_flags to map into the receiving lock. */
+#define LDLM_AST_FLAGS LDLM_FL_AST_MASK
+
+/** @} subgroup */
+/** @} group */
+#ifdef WIRESHARK_COMPILE
+static int hf_lustre_ldlm_fl_lock_changed = -1;
+static int hf_lustre_ldlm_fl_block_granted = -1;
+static int hf_lustre_ldlm_fl_block_conv = -1;
+static int hf_lustre_ldlm_fl_block_wait = -1;
+static int hf_lustre_ldlm_fl_ast_sent = -1;
+static int hf_lustre_ldlm_fl_replay = -1;
+static int hf_lustre_ldlm_fl_intent_only = -1;
+static int hf_lustre_ldlm_fl_has_intent = -1;
+static int hf_lustre_ldlm_fl_discard_data = -1;
+static int hf_lustre_ldlm_fl_no_timeout = -1;
+static int hf_lustre_ldlm_fl_block_nowait = -1;
+static int hf_lustre_ldlm_fl_test_lock = -1;
+static int hf_lustre_ldlm_fl_cancel_on_block = -1;
+static int hf_lustre_ldlm_fl_deny_on_contention = -1;
+static int hf_lustre_ldlm_fl_ast_discard_data = -1;
+static int hf_lustre_ldlm_fl_fail_loc = -1;
+static int hf_lustre_ldlm_fl_skipped = -1;
+static int hf_lustre_ldlm_fl_cbpending = -1;
+static int hf_lustre_ldlm_fl_wait_noreproc = -1;
+static int hf_lustre_ldlm_fl_cancel = -1;
+static int hf_lustre_ldlm_fl_local_only = -1;
+static int hf_lustre_ldlm_fl_failed = -1;
+static int hf_lustre_ldlm_fl_canceling = -1;
+static int hf_lustre_ldlm_fl_local = -1;
+static int hf_lustre_ldlm_fl_lvb_ready = -1;
+static int hf_lustre_ldlm_fl_kms_ignore = -1;
+static int hf_lustre_ldlm_fl_cp_reqd = -1;
+static int hf_lustre_ldlm_fl_cleaned = -1;
+static int hf_lustre_ldlm_fl_atomic_cb = -1;
+static int hf_lustre_ldlm_fl_bl_ast = -1;
+static int hf_lustre_ldlm_fl_bl_done = -1;
+static int hf_lustre_ldlm_fl_no_lru = -1;
+static int hf_lustre_ldlm_fl_fail_notified = -1;
+static int hf_lustre_ldlm_fl_destroyed = -1;
+static int hf_lustre_ldlm_fl_server_lock = -1;
+static int hf_lustre_ldlm_fl_res_locked = -1;
+static int hf_lustre_ldlm_fl_waited = -1;
+static int hf_lustre_ldlm_fl_ns_srv = -1;
+
+const value_string lustre_ldlm_flags_vals[] = {
+ {LDLM_FL_LOCK_CHANGED, "LDLM_FL_LOCK_CHANGED"},
+ {LDLM_FL_BLOCK_GRANTED, "LDLM_FL_BLOCK_GRANTED"},
+ {LDLM_FL_BLOCK_CONV, "LDLM_FL_BLOCK_CONV"},
+ {LDLM_FL_BLOCK_WAIT, "LDLM_FL_BLOCK_WAIT"},
+ {LDLM_FL_AST_SENT, "LDLM_FL_AST_SENT"},
+ {LDLM_FL_REPLAY, "LDLM_FL_REPLAY"},
+ {LDLM_FL_INTENT_ONLY, "LDLM_FL_INTENT_ONLY"},
+ {LDLM_FL_HAS_INTENT, "LDLM_FL_HAS_INTENT"},
+ {LDLM_FL_DISCARD_DATA, "LDLM_FL_DISCARD_DATA"},
+ {LDLM_FL_NO_TIMEOUT, "LDLM_FL_NO_TIMEOUT"},
+ {LDLM_FL_BLOCK_NOWAIT, "LDLM_FL_BLOCK_NOWAIT"},
+ {LDLM_FL_TEST_LOCK, "LDLM_FL_TEST_LOCK"},
+ {LDLM_FL_CANCEL_ON_BLOCK, "LDLM_FL_CANCEL_ON_BLOCK"},
+ {LDLM_FL_DENY_ON_CONTENTION, "LDLM_FL_DENY_ON_CONTENTION"},
+ {LDLM_FL_AST_DISCARD_DATA, "LDLM_FL_AST_DISCARD_DATA"},
+ {LDLM_FL_FAIL_LOC, "LDLM_FL_FAIL_LOC"},
+ {LDLM_FL_SKIPPED, "LDLM_FL_SKIPPED"},
+ {LDLM_FL_CBPENDING, "LDLM_FL_CBPENDING"},
+ {LDLM_FL_WAIT_NOREPROC, "LDLM_FL_WAIT_NOREPROC"},
+ {LDLM_FL_CANCEL, "LDLM_FL_CANCEL"},
+ {LDLM_FL_LOCAL_ONLY, "LDLM_FL_LOCAL_ONLY"},
+ {LDLM_FL_FAILED, "LDLM_FL_FAILED"},
+ {LDLM_FL_CANCELING, "LDLM_FL_CANCELING"},
+ {LDLM_FL_LOCAL, "LDLM_FL_LOCAL"},
+ {LDLM_FL_LVB_READY, "LDLM_FL_LVB_READY"},
+ {LDLM_FL_KMS_IGNORE, "LDLM_FL_KMS_IGNORE"},
+ {LDLM_FL_CP_REQD, "LDLM_FL_CP_REQD"},
+ {LDLM_FL_CLEANED, "LDLM_FL_CLEANED"},
+ {LDLM_FL_ATOMIC_CB, "LDLM_FL_ATOMIC_CB"},
+ {LDLM_FL_BL_AST, "LDLM_FL_BL_AST"},
+ {LDLM_FL_BL_DONE, "LDLM_FL_BL_DONE"},
+ {LDLM_FL_NO_LRU, "LDLM_FL_NO_LRU"},
+ {LDLM_FL_FAIL_NOTIFIED, "LDLM_FL_FAIL_NOTIFIED"},
+ {LDLM_FL_DESTROYED, "LDLM_FL_DESTROYED"},
+ {LDLM_FL_SERVER_LOCK, "LDLM_FL_SERVER_LOCK"},
+ {LDLM_FL_RES_LOCKED, "LDLM_FL_RES_LOCKED"},
+ {LDLM_FL_WAITED, "LDLM_FL_WAITED"},
+ {LDLM_FL_NS_SRV, "LDLM_FL_NS_SRV"},
+ { 0, NULL }
+};
+#endif /* WIRESHARK_COMPILE */
+#endif /* LDLM_ALL_FLAGS_MASK */
diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h
index 7d20cba0728..d9d5814e318 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fid.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fid.h
@@ -38,8 +38,8 @@
* Author: Yury Umanets <umka@clusterfs.com>
*/
-#ifndef __LINUX_FID_H
-#define __LINUX_FID_H
+#ifndef __LUSTRE_FID_H
+#define __LUSTRE_FID_H
/** \defgroup fid fid
*
@@ -154,13 +154,12 @@
#include <linux/libcfs/libcfs.h>
#include <lustre/lustre_idl.h>
-#include <lustre_req_layout.h>
-#include <lustre_mdt.h>
-#include <obd.h>
-
+struct lu_env;
struct lu_site;
struct lu_context;
+struct obd_device;
+struct obd_export;
/* Whole sequences space range and zero range definitions */
extern const struct lu_seq_range LUSTRE_SEQ_SPACE_RANGE;
@@ -320,6 +319,12 @@ static inline void lu_last_id_fid(struct lu_fid *fid, __u64 seq)
fid->f_ver = 0;
}
+/* seq client type */
+enum lu_cli_type {
+ LUSTRE_SEQ_METADATA = 1,
+ LUSTRE_SEQ_DATA
+};
+
enum lu_mgr_type {
LUSTRE_SEQ_SERVER,
LUSTRE_SEQ_CONTROLLER
@@ -341,7 +346,7 @@ struct lu_client_seq {
struct lu_seq_range lcs_space;
/* Seq related proc */
- proc_dir_entry_t *lcs_proc_dir;
+ struct proc_dir_entry *lcs_proc_dir;
/* This holds last allocated fid in last obtained seq */
struct lu_fid lcs_fid;
@@ -388,7 +393,7 @@ struct lu_server_seq {
struct dt_object *lss_obj;
/* Seq related proc */
- proc_dir_entry_t *lss_proc_dir;
+ struct proc_dir_entry *lss_proc_dir;
/* LUSTRE_SEQ_SERVER or LUSTRE_SEQ_CONTROLLER */
enum lu_mgr_type lss_type;
@@ -426,10 +431,14 @@ struct lu_server_seq {
struct seq_server_site *lss_site;
};
+struct com_thread_info;
int seq_query(struct com_thread_info *info);
+
+struct ptlrpc_request;
int seq_handle(struct ptlrpc_request *req);
/* Server methods */
+
int seq_server_init(struct lu_server_seq *seq,
struct dt_device *dev,
const char *prefix,
@@ -472,6 +481,7 @@ int seq_site_fini(const struct lu_env *env, struct seq_server_site *ss);
int fid_is_local(const struct lu_env *env,
struct lu_site *site, const struct lu_fid *fid);
+enum lu_cli_type;
int client_fid_init(struct obd_device *obd, struct obd_export *exp,
enum lu_cli_type type);
int client_fid_fini(struct obd_device *obd);
@@ -488,74 +498,75 @@ struct ldlm_namespace;
* renaming name[2,3] fields that need to be used for the quota identifier.
*/
static inline struct ldlm_res_id *
-fid_build_reg_res_name(const struct lu_fid *f,
- struct ldlm_res_id *name)
+fid_build_reg_res_name(const struct lu_fid *fid, struct ldlm_res_id *res)
{
- memset(name, 0, sizeof *name);
- name->name[LUSTRE_RES_ID_SEQ_OFF] = fid_seq(f);
- name->name[LUSTRE_RES_ID_VER_OID_OFF] = fid_ver_oid(f);
- return name;
+ memset(res, 0, sizeof(*res));
+ res->name[LUSTRE_RES_ID_SEQ_OFF] = fid_seq(fid);
+ res->name[LUSTRE_RES_ID_VER_OID_OFF] = fid_ver_oid(fid);
+
+ return res;
+}
+
+/*
+ * Return true if resource is for object identified by FID.
+ */
+static inline int fid_res_name_eq(const struct lu_fid *fid,
+ const struct ldlm_res_id *res)
+{
+ return res->name[LUSTRE_RES_ID_SEQ_OFF] == fid_seq(fid) &&
+ res->name[LUSTRE_RES_ID_VER_OID_OFF] == fid_ver_oid(fid);
+}
+
+/*
+ * Extract FID from LDLM resource. Reverse of fid_build_reg_res_name().
+ */
+static inline struct lu_fid *
+fid_extract_from_res_name(struct lu_fid *fid, const struct ldlm_res_id *res)
+{
+ fid->f_seq = res->name[LUSTRE_RES_ID_SEQ_OFF];
+ fid->f_oid = (__u32)(res->name[LUSTRE_RES_ID_VER_OID_OFF]);
+ fid->f_ver = (__u32)(res->name[LUSTRE_RES_ID_VER_OID_OFF] >> 32);
+ LASSERT(fid_res_name_eq(fid, res));
+
+ return fid;
}
/*
* Build (DLM) resource identifier from global quota FID and quota ID.
*/
static inline struct ldlm_res_id *
-fid_build_quota_resid(const struct lu_fid *glb_fid, union lquota_id *qid,
+fid_build_quota_res_name(const struct lu_fid *glb_fid, union lquota_id *qid,
struct ldlm_res_id *res)
{
fid_build_reg_res_name(glb_fid, res);
res->name[LUSTRE_RES_ID_QUOTA_SEQ_OFF] = fid_seq(&qid->qid_fid);
res->name[LUSTRE_RES_ID_QUOTA_VER_OID_OFF] = fid_ver_oid(&qid->qid_fid);
+
return res;
}
/*
* Extract global FID and quota ID from resource name
*/
-static inline void fid_extract_quota_resid(struct ldlm_res_id *res,
- struct lu_fid *glb_fid,
- union lquota_id *qid)
+static inline void fid_extract_from_quota_res(struct lu_fid *glb_fid,
+ union lquota_id *qid,
+ const struct ldlm_res_id *res)
{
- glb_fid->f_seq = res->name[LUSTRE_RES_ID_SEQ_OFF];
- glb_fid->f_oid = (__u32)res->name[LUSTRE_RES_ID_VER_OID_OFF];
- glb_fid->f_ver = (__u32)(res->name[LUSTRE_RES_ID_VER_OID_OFF] >> 32);
-
+ fid_extract_from_res_name(glb_fid, res);
qid->qid_fid.f_seq = res->name[LUSTRE_RES_ID_QUOTA_SEQ_OFF];
qid->qid_fid.f_oid = (__u32)res->name[LUSTRE_RES_ID_QUOTA_VER_OID_OFF];
qid->qid_fid.f_ver =
(__u32)(res->name[LUSTRE_RES_ID_QUOTA_VER_OID_OFF] >> 32);
}
-/*
- * Return true if resource is for object identified by fid.
- */
-static inline int fid_res_name_eq(const struct lu_fid *f,
- const struct ldlm_res_id *name)
-{
- return name->name[LUSTRE_RES_ID_SEQ_OFF] == fid_seq(f) &&
- name->name[LUSTRE_RES_ID_VER_OID_OFF] == fid_ver_oid(f);
-}
-
-/* reverse function of fid_build_reg_res_name() */
-static inline void fid_build_from_res_name(struct lu_fid *f,
- const struct ldlm_res_id *name)
-{
- fid_zero(f);
- f->f_seq = name->name[LUSTRE_RES_ID_SEQ_OFF];
- f->f_oid = name->name[LUSTRE_RES_ID_VER_OID_OFF] & 0xffffffff;
- f->f_ver = name->name[LUSTRE_RES_ID_VER_OID_OFF] >> 32;
- LASSERT(fid_res_name_eq(f, name));
-}
-
static inline struct ldlm_res_id *
-fid_build_pdo_res_name(const struct lu_fid *f,
- unsigned int hash,
- struct ldlm_res_id *name)
+fid_build_pdo_res_name(const struct lu_fid *fid, unsigned int hash,
+ struct ldlm_res_id *res)
{
- fid_build_reg_res_name(f, name);
- name->name[LUSTRE_RES_ID_HSH_OFF] = hash;
- return name;
+ fid_build_reg_res_name(fid, res);
+ res->name[LUSTRE_RES_ID_HSH_OFF] = hash;
+
+ return res;
}
/**
@@ -584,7 +595,7 @@ static inline void ostid_build_res_name(struct ost_id *oi,
name->name[LUSTRE_RES_ID_SEQ_OFF] = ostid_id(oi);
name->name[LUSTRE_RES_ID_VER_OID_OFF] = ostid_seq(oi);
} else {
- fid_build_reg_res_name((struct lu_fid *)oi, name);
+ fid_build_reg_res_name(&oi->oi_fid, name);
}
}
@@ -597,7 +608,7 @@ static inline void ostid_res_name_to_id(struct ost_id *oi,
ostid_set_id(oi, name->name[LUSTRE_RES_ID_SEQ_OFF]);
} else {
/* new resid */
- fid_build_from_res_name((struct lu_fid *)oi, name);
+ fid_extract_from_res_name(&oi->oi_fid, name);
}
}
@@ -644,7 +655,7 @@ static inline void ost_fid_from_resid(struct lu_fid *fid,
ostid_to_fid(fid, &oi, 0);
} else {
/* new resid */
- fid_build_from_res_name(fid, name);
+ fid_extract_from_res_name(fid, name);
}
}
@@ -666,14 +677,14 @@ static inline __u64 fid_flatten(const struct lu_fid *fid)
if (fid_is_igif(fid)) {
ino = lu_igif_ino(fid);
- RETURN(ino);
+ return ino;
}
seq = fid_seq(fid);
ino = (seq << 24) + ((seq >> 24) & 0xffffff0000ULL) + fid_oid(fid);
- RETURN(ino ? ino : fid_oid(fid));
+ return ino ? ino : fid_oid(fid);
}
static inline __u32 fid_hash(const struct lu_fid *f, int bits)
@@ -692,7 +703,7 @@ static inline __u32 fid_flatten32(const struct lu_fid *fid)
if (fid_is_igif(fid)) {
ino = lu_igif_ino(fid);
- RETURN(ino);
+ return ino;
}
seq = fid_seq(fid) - FID_SEQ_START;
@@ -706,7 +717,7 @@ static inline __u32 fid_flatten32(const struct lu_fid *fid)
(seq >> (64 - (40-8)) & 0xffffff00) +
(fid_oid(fid) & 0xff000fff) + ((fid_oid(fid) & 0x00fff000) << 8);
- RETURN(ino ? ino : fid_oid(fid));
+ return ino ? ino : fid_oid(fid);
}
static inline int lu_fid_diff(struct lu_fid *fid1, struct lu_fid *fid2)
@@ -759,4 +770,4 @@ static inline void range_be_to_cpu(struct lu_seq_range *dst, const struct lu_seq
/** @} fid */
-#endif /* __LINUX_FID_H */
+#endif /* __LUSTRE_FID_H */
diff --git a/drivers/staging/lustre/lustre/include/lustre_fld.h b/drivers/staging/lustre/lustre/include/lustre_fld.h
index 11e034a65b1..550fff58745 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fld.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fld.h
@@ -43,9 +43,6 @@
*/
#include <lustre/lustre_idl.h>
-#include <lustre_mdt.h>
-#include <dt_object.h>
-
#include <linux/libcfs/libcfs.h>
struct lu_client_fld;
@@ -75,7 +72,7 @@ struct lu_fld_target {
struct lu_server_fld {
/**
* Fld dir proc entry. */
- proc_dir_entry_t *lsf_proc_dir;
+ struct proc_dir_entry *lsf_proc_dir;
/**
* /fld file object device */
@@ -103,7 +100,7 @@ struct lu_server_fld {
struct lu_client_fld {
/**
* Client side proc entry. */
- proc_dir_entry_t *lcf_proc_dir;
+ struct proc_dir_entry *lcf_proc_dir;
/**
* List of exports client FLD knows about. */
@@ -129,47 +126,9 @@ struct lu_client_fld {
* Client fld proc entry name. */
char lcf_name[80];
- const struct lu_context *lcf_ctx;
-
int lcf_flags;
};
-/**
- * number of blocks to reserve for particular operations. Should be function of
- * ... something. Stub for now.
- */
-enum {
- /* one insert operation can involve two delete and one insert */
- FLD_TXN_INDEX_INSERT_CREDITS = 60,
- FLD_TXN_INDEX_DELETE_CREDITS = 20,
-};
-
-int fld_query(struct com_thread_info *info);
-
-/* Server methods */
-int fld_server_init(const struct lu_env *env, struct lu_server_fld *fld,
- struct dt_device *dt, const char *prefix, int mds_node_id,
- int type);
-
-void fld_server_fini(const struct lu_env *env, struct lu_server_fld *fld);
-
-int fld_declare_server_create(const struct lu_env *env,
- struct lu_server_fld *fld,
- struct lu_seq_range *new,
- struct thandle *th);
-
-int fld_server_create(const struct lu_env *env,
- struct lu_server_fld *fld,
- struct lu_seq_range *add_range,
- struct thandle *th);
-
-int fld_insert_entry(const struct lu_env *env,
- struct lu_server_fld *fld,
- const struct lu_seq_range *range);
-
-int fld_server_lookup(const struct lu_env *env, struct lu_server_fld *fld,
- seqno_t seq, struct lu_seq_range *range);
-
/* Client methods */
int fld_client_init(struct lu_client_fld *fld,
const char *prefix, int hash);
diff --git a/drivers/staging/lustre/lustre/include/lustre_idmap.h b/drivers/staging/lustre/lustre/include/lustre_idmap.h
index 084bdd6ab4d..2da859691d6 100644
--- a/drivers/staging/lustre/lustre/include/lustre_idmap.h
+++ b/drivers/staging/lustre/lustre/include/lustre_idmap.h
@@ -80,8 +80,8 @@ struct lustre_idmap_table {
struct lu_ucred;
-extern void lustre_groups_from_list(group_info_t *ginfo, gid_t *glist);
-extern void lustre_groups_sort(group_info_t *group_info);
+extern void lustre_groups_from_list(struct group_info *ginfo, gid_t *glist);
+extern void lustre_groups_sort(struct group_info *group_info);
extern int lustre_in_group_p(struct lu_ucred *mu, gid_t grp);
extern int lustre_idmap_add(struct lustre_idmap_table *t,
diff --git a/drivers/staging/lustre/lustre/include/lustre_import.h b/drivers/staging/lustre/lustre/include/lustre_import.h
index 3a5dd6a94c0..67259eb43cd 100644
--- a/drivers/staging/lustre/lustre/include/lustre_import.h
+++ b/drivers/staging/lustre/lustre/include/lustre_import.h
@@ -336,9 +336,11 @@ static inline unsigned int at_timeout2est(unsigned int val)
}
static inline void at_reset(struct adaptive_timeout *at, int val) {
+ spin_lock(&at->at_lock);
at->at_current = val;
at->at_worst_ever = val;
at->at_worst_time = cfs_time_current_sec();
+ spin_unlock(&at->at_lock);
}
static inline void at_init(struct adaptive_timeout *at, int val, int flags) {
memset(at, 0, sizeof(*at));
diff --git a/drivers/staging/lustre/lustre/include/lustre_lib.h b/drivers/staging/lustre/lustre/include/lustre_lib.h
index bdfc5391c6d..5e11107d4c6 100644
--- a/drivers/staging/lustre/lustre/include/lustre_lib.h
+++ b/drivers/staging/lustre/lustre/include/lustre_lib.h
@@ -96,7 +96,7 @@ void statfs_unpack(struct kstatfs *sfs, struct obd_statfs *osfs);
/* l_lock.c */
struct lustre_lock {
int l_depth;
- task_t *l_owner;
+ struct task_struct *l_owner;
struct semaphore l_sem;
spinlock_t l_spin;
};
@@ -260,10 +260,7 @@ int obd_ioctl_popdata(void *arg, void *data, int len);
static inline void obd_ioctl_freedata(char *buf, int len)
{
- ENTRY;
-
OBD_FREE_LARGE(buf, len);
- EXIT;
return;
}
diff --git a/drivers/staging/lustre/lustre/include/lustre_log.h b/drivers/staging/lustre/lustre/include/lustre_log.h
index 714ab378e43..721aa05dff3 100644
--- a/drivers/staging/lustre/lustre/include/lustre_log.h
+++ b/drivers/staging/lustre/lustre/include/lustre_log.h
@@ -469,16 +469,14 @@ static inline int llog_destroy(const struct lu_env *env,
struct llog_operations *lop;
int rc;
- ENTRY;
-
rc = llog_handle2ops(handle, &lop);
if (rc)
- RETURN(rc);
+ return rc;
if (lop->lop_destroy == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
rc = lop->lop_destroy(env, handle);
- RETURN(rc);
+ return rc;
}
static inline int llog_next_block(const struct lu_env *env,
@@ -489,17 +487,15 @@ static inline int llog_next_block(const struct lu_env *env,
struct llog_operations *lop;
int rc;
- ENTRY;
-
rc = llog_handle2ops(loghandle, &lop);
if (rc)
- RETURN(rc);
+ return rc;
if (lop->lop_next_block == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
rc = lop->lop_next_block(env, loghandle, cur_idx, next_idx,
cur_offset, buf, len);
- RETURN(rc);
+ return rc;
}
static inline int llog_prev_block(const struct lu_env *env,
@@ -509,16 +505,14 @@ static inline int llog_prev_block(const struct lu_env *env,
struct llog_operations *lop;
int rc;
- ENTRY;
-
rc = llog_handle2ops(loghandle, &lop);
if (rc)
- RETURN(rc);
+ return rc;
if (lop->lop_prev_block == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
rc = lop->lop_prev_block(env, loghandle, prev_idx, buf, len);
- RETURN(rc);
+ return rc;
}
static inline int llog_connect(struct llog_ctxt *ctxt,
@@ -528,16 +522,14 @@ static inline int llog_connect(struct llog_ctxt *ctxt,
struct llog_operations *lop;
int rc;
- ENTRY;
-
rc = llog_obd2ops(ctxt, &lop);
if (rc)
- RETURN(rc);
+ return rc;
if (lop->lop_connect == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
rc = lop->lop_connect(ctxt, logid, gen, uuid);
- RETURN(rc);
+ return rc;
}
/* llog.c */
diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h
index fb1561a809b..19000259a5e 100644
--- a/drivers/staging/lustre/lustre/include/lustre_mdc.h
+++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h
@@ -84,9 +84,8 @@ static inline void mdc_init_rpc_lock(struct mdc_rpc_lock *lck)
static inline void mdc_get_rpc_lock(struct mdc_rpc_lock *lck,
struct lookup_intent *it)
{
- ENTRY;
-
- if (it != NULL && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP))
+ if (it != NULL && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP ||
+ it->it_op == IT_LAYOUT))
return;
/* This would normally block until the existing request finishes.
@@ -123,8 +122,9 @@ static inline void mdc_get_rpc_lock(struct mdc_rpc_lock *lck,
static inline void mdc_put_rpc_lock(struct mdc_rpc_lock *lck,
struct lookup_intent *it)
{
- if (it != NULL && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP))
- goto out;
+ if (it != NULL && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP ||
+ it->it_op == IT_LAYOUT))
+ return;
if (lck->rpcl_it == MDC_FAKE_RPCL_IT) { /* OBD_FAIL_MDC_RPCS_SEM */
mutex_lock(&lck->rpcl_mutex);
@@ -141,8 +141,6 @@ static inline void mdc_put_rpc_lock(struct mdc_rpc_lock *lck,
}
mutex_unlock(&lck->rpcl_mutex);
- out:
- EXIT;
}
static inline void mdc_update_max_ea_from_body(struct obd_export *exp,
diff --git a/drivers/staging/lustre/lustre/include/lustre_mdt.h b/drivers/staging/lustre/lustre/include/lustre_mdt.h
deleted file mode 100644
index dba26a6cfa3..00000000000
--- a/drivers/staging/lustre/lustre/include/lustre_mdt.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- */
-
-#ifndef __LINUX_MDT_H
-#define __LINUX_MDT_H
-
-/** \defgroup mdt mdt
- *
- * @{
- */
-
-#include <lustre/lustre_idl.h>
-#include <lustre_req_layout.h>
-#include <md_object.h>
-#include <dt_object.h>
-#include <linux/libcfs/libcfs.h>
-
-/*
- * Common thread info for mdt, seq and fld
- */
-struct com_thread_info {
- /*
- * for req-layout interface.
- */
- struct req_capsule *cti_pill;
-};
-
-enum {
- ESERIOUS = 0x0001000
-};
-
-static inline int err_serious(int rc)
-{
- LASSERT(rc < 0);
- LASSERT(-rc < ESERIOUS);
- return -(-rc | ESERIOUS);
-}
-
-static inline int clear_serious(int rc)
-{
- if (rc < 0)
- rc = -(-rc & ~ESERIOUS);
- return rc;
-}
-
-static inline int is_serious(int rc)
-{
- return (rc < 0 && -rc & ESERIOUS);
-}
-
-/** @} mdt */
-
-#endif
diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h
index 293dd90e5b6..e947002fae0 100644
--- a/drivers/staging/lustre/lustre/include/lustre_net.h
+++ b/drivers/staging/lustre/lustre/include/lustre_net.h
@@ -1136,7 +1136,7 @@ struct ptlrpc_nrs_pol_conf {
* different module to the one the NRS framework is held within
* (currently ptlrpc), should set this field to THIS_MODULE.
*/
- module_t *nc_owner;
+ struct module *nc_owner;
/**
* Policy registration flags; a bitmast of \e nrs_policy_flags
*/
@@ -1211,7 +1211,7 @@ struct ptlrpc_nrs_pol_desc {
* then unregistration and lprocfs operations will be properly
* serialized.
*/
- module_t *pd_owner;
+ struct module *pd_owner;
/**
* Bitmask of \e nrs_policy_flags
*/
@@ -2322,8 +2322,13 @@ struct ptlrpc_thread {
pid_t t_pid;
/**
* put watchdog in the structure per thread b=14840
+ *
+ * Lustre watchdog is removed for client in the hope
+ * of a generic watchdog can be merged in kernel.
+ * When that happens, we should add below back.
+ *
+ * struct lc_watchdog *t_watchdog;
*/
- struct lc_watchdog *t_watchdog;
/**
* the svc this thread belonged to b=18582
*/
@@ -2484,7 +2489,7 @@ struct ptlrpc_service {
/** limit of threads number for each partition */
int srv_nthrs_cpt_limit;
/** Root of /proc dir tree for this service */
- proc_dir_entry_t *srv_procroot;
+ struct proc_dir_entry *srv_procroot;
/** Pointer to statistic data for this service */
struct lprocfs_stats *srv_stats;
/** # hp per lp reqs to handle */
@@ -2631,7 +2636,7 @@ struct ptlrpc_service_part {
/** reqs waiting for replies */
struct ptlrpc_at_array scp_at_array;
/** early reply timer */
- timer_list_t scp_at_timer;
+ struct timer_list scp_at_timer;
/** debug */
cfs_time_t scp_at_checktime;
/** check early replies */
@@ -3161,6 +3166,38 @@ lustre_shrink_reply(struct ptlrpc_request *req, int segment,
req->rq_replen = lustre_shrink_msg(req->rq_repmsg, segment,
newlen, move_data);
}
+
+#ifdef CONFIG_LUSTRE_TRANSLATE_ERRNOS
+
+static inline int ptlrpc_status_hton(int h)
+{
+ /*
+ * Positive errnos must be network errnos, such as LUSTRE_EDEADLK,
+ * ELDLM_LOCK_ABORTED, etc.
+ */
+ if (h < 0)
+ return -lustre_errno_hton(-h);
+ else
+ return h;
+}
+
+static inline int ptlrpc_status_ntoh(int n)
+{
+ /*
+ * See the comment in ptlrpc_status_hton().
+ */
+ if (n < 0)
+ return -lustre_errno_ntoh(-n);
+ else
+ return n;
+}
+
+#else
+
+#define ptlrpc_status_hton(h) (h)
+#define ptlrpc_status_ntoh(n) (n)
+
+#endif
/** @} */
/** Change request phase of \a req to \a new_phase */
diff --git a/drivers/staging/lustre/lustre/include/lustre_quota.h b/drivers/staging/lustre/lustre/include/lustre_quota.h
index 1c3041f5004..71b5d97e034 100644
--- a/drivers/staging/lustre/lustre/include/lustre_quota.h
+++ b/drivers/staging/lustre/lustre/include/lustre_quota.h
@@ -168,7 +168,7 @@ struct qsd_instance;
* enforcement. Arguments are documented where each function is defined. */
struct qsd_instance *qsd_init(const struct lu_env *, char *, struct dt_device *,
- proc_dir_entry_t *);
+ struct proc_dir_entry *);
int qsd_prepare(const struct lu_env *, struct qsd_instance *);
int qsd_start(const struct lu_env *, struct qsd_instance *);
void qsd_fini(const struct lu_env *, struct qsd_instance *);
diff --git a/drivers/staging/lustre/lustre/include/lustre_sec.h b/drivers/staging/lustre/lustre/include/lustre_sec.h
index 9e0908e1c4d..70b8b133a5c 100644
--- a/drivers/staging/lustre/lustre/include/lustre_sec.h
+++ b/drivers/staging/lustre/lustre/include/lustre_sec.h
@@ -796,7 +796,7 @@ struct ptlrpc_sec_sops {
};
struct ptlrpc_sec_policy {
- module_t *sp_owner;
+ struct module *sp_owner;
char *sp_name;
__u16 sp_policy; /* policy number */
struct ptlrpc_sec_cops *sp_cops; /* client ops */
diff --git a/drivers/staging/lustre/lustre/include/md_object.h b/drivers/staging/lustre/lustre/include/md_object.h
index 92d6420b21d..daf93afe3fe 100644
--- a/drivers/staging/lustre/lustre/include/md_object.h
+++ b/drivers/staging/lustre/lustre/include/md_object.h
@@ -503,11 +503,6 @@ static inline struct md_device *md_obj2dev(const struct md_object *o)
return container_of0(o->mo_lu.lo_dev, struct md_device, md_lu_dev);
}
-static inline struct seq_server_site *lu_site2seq(const struct lu_site *s)
-{
- return s->ld_seq_site;
-}
-
static inline int md_device_init(struct md_device *md, struct lu_device_type *t)
{
return lu_device_init(&md->md_lu_dev, t);
@@ -876,7 +871,7 @@ struct lu_ucred {
__u32 uc_suppgids[2];
cfs_cap_t uc_cap;
__u32 uc_umask;
- group_info_t *uc_ginfo;
+ struct group_info *uc_ginfo;
struct md_identity *uc_identity;
};
diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h
index 0a251fdfe16..a6122559d55 100644
--- a/drivers/staging/lustre/lustre/include/obd.h
+++ b/drivers/staging/lustre/lustre/include/obd.h
@@ -49,15 +49,14 @@
#define IOC_MDC_MAX_NR 50
#include <lustre/lustre_idl.h>
-#include <lu_ref.h>
#include <lustre_lib.h>
+#include <linux/libcfs/bitmap.h>
+#include <lu_ref.h>
#include <lustre_export.h>
+#include <lustre_fid.h>
#include <lustre_fld.h>
#include <lustre_capa.h>
-#include <linux/libcfs/bitmap.h>
-
-
#define MAX_OBD_DEVICES 8192
struct osc_async_rc {
@@ -119,6 +118,20 @@ struct lov_stripe_md {
#define lsm_stripe_count lsm_wire.lw_stripe_count
#define lsm_pool_name lsm_wire.lw_pool_name
+static inline bool lsm_is_released(struct lov_stripe_md *lsm)
+{
+ return !!(lsm->lsm_pattern & LOV_PATTERN_F_RELEASED);
+}
+
+static inline bool lsm_has_objects(struct lov_stripe_md *lsm)
+{
+ if (lsm == NULL)
+ return false;
+ if (lsm_is_released(lsm))
+ return false;
+ return true;
+}
+
struct obd_info;
typedef int (*obd_enqueue_update_f)(void *cookie, int rc);
@@ -225,7 +238,7 @@ struct obd_type {
struct list_head typ_chain;
struct obd_ops *typ_dt_ops;
struct md_ops *typ_md_ops;
- proc_dir_entry_t *typ_procroot;
+ struct proc_dir_entry *typ_procroot;
char *typ_name;
int typ_refcnt;
struct lu_device_type *typ_lu;
@@ -239,30 +252,6 @@ struct brw_page {
obd_flag flag;
};
-/* Individual type definitions */
-
-struct ost_server_data;
-
-struct osd_properties {
- size_t osd_max_ea_size;
-};
-
-#define OBT_MAGIC 0xBDDECEAE
-/* hold common fields for "target" device */
-struct obd_device_target {
- __u32 obt_magic;
- __u32 obt_instance;
- struct super_block *obt_sb;
- /** last_rcvd file */
- struct file *obt_rcvd_filp;
- __u64 obt_mount_count;
- struct rw_semaphore obt_rwsem;
- struct vfsmount *obt_vfsmnt;
- struct file *obt_health_check_filp;
- struct osd_properties obt_osd_properties;
- struct obd_job_stats obt_jobstats;
-};
-
/* llog contexts */
enum llog_ctxt_id {
LLOG_CONFIG_ORIG_CTXT = 0,
@@ -277,100 +266,13 @@ enum llog_ctxt_id {
LLOG_TEST_REPL_CTXT,
LLOG_LOVEA_ORIG_CTXT,
LLOG_LOVEA_REPL_CTXT,
- LLOG_CHANGELOG_ORIG_CTXT, /**< changelog generation on mdd */
- LLOG_CHANGELOG_REPL_CTXT, /**< changelog access on clients */
- LLOG_CHANGELOG_USER_ORIG_CTXT, /**< for multiple changelog consumers */
+ LLOG_CHANGELOG_ORIG_CTXT, /**< changelog generation on mdd */
+ LLOG_CHANGELOG_REPL_CTXT, /**< changelog access on clients */
+ LLOG_CHANGELOG_USER_ORIG_CTXT, /**< for multiple changelog consumers */
+ LLOG_AGENT_ORIG_CTXT, /**< agent requests generation on cdt */
LLOG_MAX_CTXTS
};
-#define FILTER_SUBDIR_COUNT 32 /* set to zero for no subdirs */
-
-struct filter_subdirs {
- struct dentry *dentry[FILTER_SUBDIR_COUNT];
-};
-
-
-struct filter_ext {
- __u64 fe_start;
- __u64 fe_end;
-};
-
-struct filter_obd {
- /* NB this field MUST be first */
- struct obd_device_target fo_obt;
- const char *fo_fstype;
-
- int fo_group_count;
- struct dentry *fo_dentry_O;
- struct dentry **fo_dentry_O_groups;
- struct filter_subdirs *fo_dentry_O_sub;
- struct mutex fo_init_lock; /* group initialization lock*/
- int fo_committed_group;
-
- spinlock_t fo_objidlock; /* protect fo_lastobjid */
-
- unsigned long fo_destroys_in_progress;
- struct mutex fo_create_locks[FILTER_SUBDIR_COUNT];
-
- struct list_head fo_export_list;
- int fo_subdir_count;
-
- obd_size fo_tot_dirty; /* protected by obd_osfs_lock */
- obd_size fo_tot_granted; /* all values in bytes */
- obd_size fo_tot_pending;
- int fo_tot_granted_clients;
-
- obd_size fo_readcache_max_filesize;
- spinlock_t fo_flags_lock;
- unsigned int fo_read_cache:1, /**< enable read-only cache */
- fo_writethrough_cache:1,/**< read cache writes */
- fo_mds_ost_sync:1, /**< MDS-OST orphan recovery*/
- fo_raid_degraded:1;/**< RAID device degraded */
-
- struct obd_import *fo_mdc_imp;
- struct obd_uuid fo_mdc_uuid;
- struct lustre_handle fo_mdc_conn;
- struct file **fo_last_objid_files;
- __u64 *fo_last_objids; /* last created objid for groups,
- * protected by fo_objidlock */
-
- struct mutex fo_alloc_lock;
-
- atomic_t fo_r_in_flight;
- atomic_t fo_w_in_flight;
-
- /*
- * per-filter pool of kiobuf's allocated by filter_common_setup() and
- * torn down by filter_cleanup().
- *
- * This pool contains kiobuf used by
- * filter_{prep,commit}rw_{read,write}() and is shared by all OST
- * threads.
- *
- * Locking: protected by internal lock of cfs_hash, pool can be
- * found from this hash table by t_id of ptlrpc_thread.
- */
- struct cfs_hash *fo_iobuf_hash;
-
- struct brw_stats fo_filter_stats;
-
- int fo_fmd_max_num; /* per exp filter_mod_data */
- int fo_fmd_max_age; /* jiffies to fmd expiry */
- unsigned long fo_syncjournal:1, /* sync journal on writes */
- fo_sync_lock_cancel:2;/* sync on lock cancel */
-
-
- /* sptlrpc stuff */
- rwlock_t fo_sptlrpc_lock;
- struct sptlrpc_rule_set fo_sptlrpc_rset;
-
- /* capability related */
- unsigned int fo_fl_oss_capa;
- struct list_head fo_capa_keys;
- struct hlist_head *fo_capa_hash;
- int fo_sec_level;
-};
-
struct timeout_item {
enum timeout_event ti_event;
cfs_time_t ti_timeout;
@@ -536,25 +438,6 @@ struct obd_id_info {
obd_id *data;
};
-/* */
-
-struct echo_obd {
- struct obd_device_target eo_obt;
- struct obdo eo_oa;
- spinlock_t eo_lock;
- __u64 eo_lastino;
- struct lustre_handle eo_nl_lock;
- atomic_t eo_prep;
-};
-
-struct ost_obd {
- struct ptlrpc_service *ost_service;
- struct ptlrpc_service *ost_create_service;
- struct ptlrpc_service *ost_io_service;
- struct ptlrpc_service *ost_seq_service;
- struct mutex ost_health_mutex;
-};
-
struct echo_client_obd {
struct obd_export *ec_exp; /* the local connection to osc/lov */
spinlock_t ec_lock;
@@ -654,7 +537,7 @@ struct pool_desc {
struct lov_qos_rr pool_rr; /* round robin qos */
struct hlist_node pool_hash; /* access by poolname */
struct list_head pool_list; /* serial access */
- proc_dir_entry_t *pool_proc_entry; /* file in /proc */
+ struct proc_dir_entry *pool_proc_entry; /* file in /proc */
struct obd_device *pool_lobd; /* obd of the lov/lod to which
* this pool belongs */
};
@@ -675,7 +558,7 @@ struct lov_obd {
int lov_pool_count;
cfs_hash_t *lov_pools_hash_body; /* used for key access */
struct list_head lov_pool_list; /* used for sequential access */
- proc_dir_entry_t *lov_pool_proc_entry;
+ struct proc_dir_entry *lov_pool_proc_entry;
enum lustre_sec_part lov_sp_me;
/* Cached LRU pages from upper layer */
@@ -1017,7 +900,7 @@ struct obd_device {
int obd_requests_queued_for_recovery;
wait_queue_head_t obd_next_transno_waitq;
/* protected by obd_recovery_task_lock */
- timer_list_t obd_recovery_timer;
+ struct timer_list obd_recovery_timer;
time_t obd_recovery_start; /* seconds */
time_t obd_recovery_end; /* seconds, for lprocfs_status */
int obd_recovery_time_hard;
@@ -1036,12 +919,8 @@ struct obd_device {
int obd_recovery_stage;
union {
- struct obd_device_target obt;
- struct filter_obd filter;
struct client_obd cli;
- struct ost_obd ost;
struct echo_client_obd echo_client;
- struct echo_obd echo;
struct lov_obd lov;
struct lmv_obd lmv;
} u;
@@ -1052,10 +931,10 @@ struct obd_device {
unsigned int md_cntr_base;
struct lprocfs_stats *md_stats;
- proc_dir_entry_t *obd_proc_entry;
+ struct proc_dir_entry *obd_proc_entry;
void *obd_proc_private; /* type private PDEs */
- proc_dir_entry_t *obd_proc_exports_entry;
- proc_dir_entry_t *obd_svc_procroot;
+ struct proc_dir_entry *obd_proc_exports_entry;
+ struct proc_dir_entry *obd_svc_procroot;
struct lprocfs_stats *obd_svc_stats;
atomic_t obd_evict_inprogress;
wait_queue_head_t obd_evict_inprogress_waitq;
@@ -1218,12 +1097,6 @@ typedef int (* md_enqueue_cb_t)(struct ptlrpc_request *req,
struct md_enqueue_info *minfo,
int rc);
-/* seq client type */
-enum lu_cli_type {
- LUSTRE_SEQ_METADATA = 1,
- LUSTRE_SEQ_DATA
-};
-
struct md_enqueue_info {
struct md_op_data mi_data;
struct lookup_intent mi_it;
@@ -1235,7 +1108,7 @@ struct md_enqueue_info {
};
struct obd_ops {
- module_t *o_owner;
+ struct module *o_owner;
int (*o_iocontrol)(unsigned int cmd, struct obd_export *exp, int len,
void *karg, void *uarg);
int (*o_get_info)(const struct lu_env *env, struct obd_export *,
diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h
index de5c5853647..983718fe1e5 100644
--- a/drivers/staging/lustre/lustre/include/obd_class.h
+++ b/drivers/staging/lustre/lustre/include/obd_class.h
@@ -326,7 +326,7 @@ void obdo_le_to_cpu(struct obdo *dobdo, struct obdo *sobdo);
do { \
if (!(obd)) { \
CERROR("NULL device\n"); \
- RETURN(-ENODEV); \
+ return -ENODEV; \
} \
} while (0)
@@ -337,7 +337,7 @@ do { \
if (!(obd)->obd_set_up || (obd)->obd_stopping) { \
CERROR("Device %d not setup\n", \
(obd)->obd_minor); \
- RETURN(-ENODEV); \
+ return -ENODEV; \
} \
} while (0)
@@ -424,7 +424,7 @@ do { \
if (err) \
CERROR("md_" #op ": dev %s/%d no operation\n", \
obd->obd_name, obd->obd_minor); \
- RETURN(err); \
+ return err; \
} \
} while (0)
@@ -432,17 +432,17 @@ do { \
do { \
if ((exp) == NULL) { \
CERROR("obd_" #op ": NULL export\n"); \
- RETURN(-ENODEV); \
+ return -ENODEV; \
} \
if ((exp)->exp_obd == NULL || !OBT((exp)->exp_obd)) { \
CERROR("obd_" #op ": cleaned up obd\n"); \
- RETURN(-EOPNOTSUPP); \
+ return -EOPNOTSUPP; \
} \
if (!OBT((exp)->exp_obd) || !MDP((exp)->exp_obd, op)) { \
CERROR("obd_" #op ": dev %s/%d no operation\n", \
(exp)->exp_obd->obd_name, \
(exp)->exp_obd->obd_minor); \
- RETURN(-EOPNOTSUPP); \
+ return -EOPNOTSUPP; \
} \
} while (0)
@@ -453,7 +453,7 @@ do { \
if (err) \
CERROR("obd_" #op ": dev %d no operation\n", \
obd->obd_minor); \
- RETURN(err); \
+ return err; \
} \
} while (0)
@@ -461,16 +461,16 @@ do { \
do { \
if ((exp) == NULL) { \
CERROR("obd_" #op ": NULL export\n"); \
- RETURN(-ENODEV); \
+ return -ENODEV; \
} \
if ((exp)->exp_obd == NULL || !OBT((exp)->exp_obd)) { \
CERROR("obd_" #op ": cleaned up obd\n"); \
- RETURN(-EOPNOTSUPP); \
+ return -EOPNOTSUPP; \
} \
if (!OBT((exp)->exp_obd) || !OBP((exp)->exp_obd, op)) { \
CERROR("obd_" #op ": dev %d no operation\n", \
(exp)->exp_obd->obd_minor); \
- RETURN(-EOPNOTSUPP); \
+ return -EOPNOTSUPP; \
} \
} while (0)
@@ -480,7 +480,7 @@ do { \
if (err) \
CERROR("lop_" #op ": dev %d no operation\n", \
ctxt->loc_obd->obd_minor); \
- RETURN(err); \
+ return err; \
} \
} while (0)
@@ -495,14 +495,13 @@ static inline int obd_get_info(const struct lu_env *env,
struct lov_stripe_md *lsm)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, get_info);
EXP_COUNTER_INCREMENT(exp, get_info);
rc = OBP(exp->exp_obd, get_info)(env, exp, keylen, key, vallen, val,
lsm);
- RETURN(rc);
+ return rc;
}
static inline int obd_set_info_async(const struct lu_env *env,
@@ -511,14 +510,13 @@ static inline int obd_set_info_async(const struct lu_env *env,
struct ptlrpc_request_set *set)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, set_info_async);
EXP_COUNTER_INCREMENT(exp, set_info_async);
rc = OBP(exp->exp_obd, set_info_async)(env, exp, keylen, key, vallen,
val, set);
- RETURN(rc);
+ return rc;
}
/*
@@ -547,7 +545,6 @@ static inline int obd_setup(struct obd_device *obd, struct lustre_cfg *cfg)
{
int rc;
DECLARE_LU_VARS(ldt, d);
- ENTRY;
ldt = obd->obd_type->typ_lu;
if (ldt != NULL) {
@@ -577,7 +574,7 @@ static inline int obd_setup(struct obd_device *obd, struct lustre_cfg *cfg)
OBD_COUNTER_INCREMENT(obd, setup);
rc = OBP(obd, setup)(obd, cfg);
}
- RETURN(rc);
+ return rc;
}
static inline int obd_precleanup(struct obd_device *obd,
@@ -585,7 +582,6 @@ static inline int obd_precleanup(struct obd_device *obd,
{
int rc;
DECLARE_LU_VARS(ldt, d);
- ENTRY;
OBD_CHECK_DEV(obd);
ldt = obd->obd_type->typ_lu;
@@ -605,14 +601,13 @@ static inline int obd_precleanup(struct obd_device *obd,
OBD_COUNTER_INCREMENT(obd, precleanup);
rc = OBP(obd, precleanup)(obd, cleanup_stage);
- RETURN(rc);
+ return rc;
}
static inline int obd_cleanup(struct obd_device *obd)
{
int rc;
DECLARE_LU_VARS(ldt, d);
- ENTRY;
OBD_CHECK_DEV(obd);
@@ -632,13 +627,11 @@ static inline int obd_cleanup(struct obd_device *obd)
OBD_COUNTER_INCREMENT(obd, cleanup);
rc = OBP(obd, cleanup)(obd);
- RETURN(rc);
+ return rc;
}
static inline void obd_cleanup_client_import(struct obd_device *obd)
{
- ENTRY;
-
/* If we set up but never connected, the
client import will not have been cleaned. */
down_write(&obd->u.cli.cl_sem);
@@ -656,8 +649,6 @@ static inline void obd_cleanup_client_import(struct obd_device *obd)
obd->u.cli.cl_import = NULL;
}
up_write(&obd->u.cli.cl_sem);
-
- EXIT;
}
static inline int
@@ -665,7 +656,6 @@ obd_process_config(struct obd_device *obd, int datalen, void *data)
{
int rc;
DECLARE_LU_VARS(ldt, d);
- ENTRY;
OBD_CHECK_DEV(obd);
@@ -687,7 +677,7 @@ obd_process_config(struct obd_device *obd, int datalen, void *data)
OBD_COUNTER_INCREMENT(obd, process_config);
obd->obd_process_conf = 0;
- RETURN(rc);
+ return rc;
}
/* Pack an in-memory MD struct for storage on disk.
@@ -702,13 +692,12 @@ static inline int obd_packmd(struct obd_export *exp,
struct lov_stripe_md *mem_src)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, packmd);
EXP_COUNTER_INCREMENT(exp, packmd);
rc = OBP(exp->exp_obd, packmd)(exp, disk_tgt, mem_src);
- RETURN(rc);
+ return rc;
}
static inline int obd_size_diskmd(struct obd_export *exp,
@@ -757,13 +746,12 @@ static inline int obd_unpackmd(struct obd_export *exp,
int disk_len)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, unpackmd);
EXP_COUNTER_INCREMENT(exp, unpackmd);
rc = OBP(exp->exp_obd, unpackmd)(exp, mem_tgt, disk_src, disk_len);
- RETURN(rc);
+ return rc;
}
/* helper functions */
@@ -790,13 +778,12 @@ static inline int obd_free_memmd(struct obd_export *exp,
static inline int obd_precreate(struct obd_export *exp)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, precreate);
OBD_COUNTER_INCREMENT(exp->exp_obd, precreate);
rc = OBP(exp->exp_obd, precreate)(exp);
- RETURN(rc);
+ return rc;
}
static inline int obd_create_async(struct obd_export *exp,
@@ -805,13 +792,12 @@ static inline int obd_create_async(struct obd_export *exp,
struct obd_trans_info *oti)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, create_async);
EXP_COUNTER_INCREMENT(exp, create_async);
rc = OBP(exp->exp_obd, create_async)(exp, oinfo, ea, oti);
- RETURN(rc);
+ return rc;
}
static inline int obd_create(const struct lu_env *env, struct obd_export *exp,
@@ -819,13 +805,12 @@ static inline int obd_create(const struct lu_env *env, struct obd_export *exp,
struct obd_trans_info *oti)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, create);
EXP_COUNTER_INCREMENT(exp, create);
rc = OBP(exp->exp_obd, create)(env, exp, obdo, ea, oti);
- RETURN(rc);
+ return rc;
}
static inline int obd_destroy(const struct lu_env *env, struct obd_export *exp,
@@ -834,26 +819,24 @@ static inline int obd_destroy(const struct lu_env *env, struct obd_export *exp,
struct obd_export *md_exp, void *capa)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, destroy);
EXP_COUNTER_INCREMENT(exp, destroy);
rc = OBP(exp->exp_obd, destroy)(env, exp, obdo, ea, oti, md_exp, capa);
- RETURN(rc);
+ return rc;
}
static inline int obd_getattr(const struct lu_env *env, struct obd_export *exp,
struct obd_info *oinfo)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, getattr);
EXP_COUNTER_INCREMENT(exp, getattr);
rc = OBP(exp->exp_obd, getattr)(env, exp, oinfo);
- RETURN(rc);
+ return rc;
}
static inline int obd_getattr_async(struct obd_export *exp,
@@ -861,13 +844,12 @@ static inline int obd_getattr_async(struct obd_export *exp,
struct ptlrpc_request_set *set)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, getattr_async);
EXP_COUNTER_INCREMENT(exp, getattr_async);
rc = OBP(exp->exp_obd, getattr_async)(exp, oinfo, set);
- RETURN(rc);
+ return rc;
}
static inline int obd_setattr(const struct lu_env *env, struct obd_export *exp,
@@ -875,13 +857,12 @@ static inline int obd_setattr(const struct lu_env *env, struct obd_export *exp,
struct obd_trans_info *oti)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, setattr);
EXP_COUNTER_INCREMENT(exp, setattr);
rc = OBP(exp->exp_obd, setattr)(env, exp, oinfo, oti);
- RETURN(rc);
+ return rc;
}
/* This performs all the requests set init/wait/destroy actions. */
@@ -891,20 +872,19 @@ static inline int obd_setattr_rqset(struct obd_export *exp,
{
struct ptlrpc_request_set *set = NULL;
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, setattr_async);
EXP_COUNTER_INCREMENT(exp, setattr_async);
set = ptlrpc_prep_set();
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = OBP(exp->exp_obd, setattr_async)(exp, oinfo, oti, set);
if (rc == 0)
rc = ptlrpc_set_wait(set);
ptlrpc_set_destroy(set);
- RETURN(rc);
+ return rc;
}
/* This adds all the requests into @set if @set != NULL, otherwise
@@ -915,13 +895,12 @@ static inline int obd_setattr_async(struct obd_export *exp,
struct ptlrpc_request_set *set)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, setattr_async);
EXP_COUNTER_INCREMENT(exp, setattr_async);
rc = OBP(exp->exp_obd, setattr_async)(exp, oinfo, oti, set);
- RETURN(rc);
+ return rc;
}
static inline int obd_add_conn(struct obd_import *imp, struct obd_uuid *uuid,
@@ -929,40 +908,37 @@ static inline int obd_add_conn(struct obd_import *imp, struct obd_uuid *uuid,
{
struct obd_device *obd = imp->imp_obd;
int rc;
- ENTRY;
OBD_CHECK_DEV_ACTIVE(obd);
OBD_CHECK_DT_OP(obd, add_conn, -EOPNOTSUPP);
OBD_COUNTER_INCREMENT(obd, add_conn);
rc = OBP(obd, add_conn)(imp, uuid, priority);
- RETURN(rc);
+ return rc;
}
static inline int obd_del_conn(struct obd_import *imp, struct obd_uuid *uuid)
{
struct obd_device *obd = imp->imp_obd;
int rc;
- ENTRY;
OBD_CHECK_DEV_ACTIVE(obd);
OBD_CHECK_DT_OP(obd, del_conn, -EOPNOTSUPP);
OBD_COUNTER_INCREMENT(obd, del_conn);
rc = OBP(obd, del_conn)(imp, uuid);
- RETURN(rc);
+ return rc;
}
static inline struct obd_uuid *obd_get_uuid(struct obd_export *exp)
{
struct obd_uuid *uuid;
- ENTRY;
OBD_CHECK_DT_OP(exp->exp_obd, get_uuid, NULL);
EXP_COUNTER_INCREMENT(exp, get_uuid);
uuid = OBP(exp->exp_obd, get_uuid)(exp);
- RETURN(uuid);
+ return uuid;
}
/** Create a new /a exp on device /a obd for the uuid /a cluuid
@@ -979,7 +955,6 @@ static inline int obd_connect(const struct lu_env *env,
int rc;
__u64 ocf = data ? data->ocd_connect_flags : 0; /* for post-condition
* check */
- ENTRY;
OBD_CHECK_DEV_ACTIVE(obd);
OBD_CHECK_DT_OP(obd, connect, -EOPNOTSUPP);
@@ -989,7 +964,7 @@ static inline int obd_connect(const struct lu_env *env,
/* check that only subset is granted */
LASSERT(ergo(data != NULL, (data->ocd_connect_flags & ocf) ==
data->ocd_connect_flags));
- RETURN(rc);
+ return rc;
}
static inline int obd_reconnect(const struct lu_env *env,
@@ -1003,8 +978,6 @@ static inline int obd_reconnect(const struct lu_env *env,
__u64 ocf = d ? d->ocd_connect_flags : 0; /* for post-condition
* check */
- ENTRY;
-
OBD_CHECK_DEV_ACTIVE(obd);
OBD_CHECK_DT_OP(obd, reconnect, 0);
OBD_COUNTER_INCREMENT(obd, reconnect);
@@ -1013,44 +986,41 @@ static inline int obd_reconnect(const struct lu_env *env,
/* check that only subset is granted */
LASSERT(ergo(d != NULL,
(d->ocd_connect_flags & ocf) == d->ocd_connect_flags));
- RETURN(rc);
+ return rc;
}
static inline int obd_disconnect(struct obd_export *exp)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, disconnect);
EXP_COUNTER_INCREMENT(exp, disconnect);
rc = OBP(exp->exp_obd, disconnect)(exp);
- RETURN(rc);
+ return rc;
}
static inline int obd_fid_init(struct obd_device *obd, struct obd_export *exp,
enum lu_cli_type type)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(obd, fid_init, 0);
OBD_COUNTER_INCREMENT(obd, fid_init);
rc = OBP(obd, fid_init)(obd, exp, type);
- RETURN(rc);
+ return rc;
}
static inline int obd_fid_fini(struct obd_device *obd)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(obd, fid_fini, 0);
OBD_COUNTER_INCREMENT(obd, fid_fini);
rc = OBP(obd, fid_fini)(obd);
- RETURN(rc);
+ return rc;
}
static inline int obd_fid_alloc(struct obd_export *exp,
@@ -1058,113 +1028,101 @@ static inline int obd_fid_alloc(struct obd_export *exp,
struct md_op_data *op_data)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, fid_alloc);
EXP_COUNTER_INCREMENT(exp, fid_alloc);
rc = OBP(exp->exp_obd, fid_alloc)(exp, fid, op_data);
- RETURN(rc);
+ return rc;
}
static inline int obd_ping(const struct lu_env *env, struct obd_export *exp)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(exp->exp_obd, ping, 0);
EXP_COUNTER_INCREMENT(exp, ping);
rc = OBP(exp->exp_obd, ping)(env, exp);
- RETURN(rc);
+ return rc;
}
static inline int obd_pool_new(struct obd_device *obd, char *poolname)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(obd, pool_new, -EOPNOTSUPP);
OBD_COUNTER_INCREMENT(obd, pool_new);
rc = OBP(obd, pool_new)(obd, poolname);
- RETURN(rc);
+ return rc;
}
static inline int obd_pool_del(struct obd_device *obd, char *poolname)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(obd, pool_del, -EOPNOTSUPP);
OBD_COUNTER_INCREMENT(obd, pool_del);
rc = OBP(obd, pool_del)(obd, poolname);
- RETURN(rc);
+ return rc;
}
static inline int obd_pool_add(struct obd_device *obd, char *poolname, char *ostname)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(obd, pool_add, -EOPNOTSUPP);
OBD_COUNTER_INCREMENT(obd, pool_add);
rc = OBP(obd, pool_add)(obd, poolname, ostname);
- RETURN(rc);
+ return rc;
}
static inline int obd_pool_rem(struct obd_device *obd, char *poolname, char *ostname)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(obd, pool_rem, -EOPNOTSUPP);
OBD_COUNTER_INCREMENT(obd, pool_rem);
rc = OBP(obd, pool_rem)(obd, poolname, ostname);
- RETURN(rc);
+ return rc;
}
static inline void obd_getref(struct obd_device *obd)
{
- ENTRY;
if (OBT(obd) && OBP(obd, getref)) {
OBD_COUNTER_INCREMENT(obd, getref);
OBP(obd, getref)(obd);
}
- EXIT;
}
static inline void obd_putref(struct obd_device *obd)
{
- ENTRY;
if (OBT(obd) && OBP(obd, putref)) {
OBD_COUNTER_INCREMENT(obd, putref);
OBP(obd, putref)(obd);
}
- EXIT;
}
static inline int obd_init_export(struct obd_export *exp)
{
int rc = 0;
- ENTRY;
if ((exp)->exp_obd != NULL && OBT((exp)->exp_obd) &&
OBP((exp)->exp_obd, init_export))
rc = OBP(exp->exp_obd, init_export)(exp);
- RETURN(rc);
+ return rc;
}
static inline int obd_destroy_export(struct obd_export *exp)
{
- ENTRY;
if ((exp)->exp_obd != NULL && OBT((exp)->exp_obd) &&
OBP((exp)->exp_obd, destroy_export))
OBP(exp->exp_obd, destroy_export)(exp);
- RETURN(0);
+ return 0;
}
static inline int obd_extent_calc(struct obd_export *exp,
@@ -1172,10 +1130,10 @@ static inline int obd_extent_calc(struct obd_export *exp,
int cmd, obd_off *offset)
{
int rc;
- ENTRY;
+
EXP_CHECK_DT_OP(exp, extent_calc);
rc = OBP(exp->exp_obd, extent_calc)(exp, md, cmd, offset);
- RETURN(rc);
+ return rc;
}
static inline struct dentry *
@@ -1198,10 +1156,9 @@ static inline int obd_statfs_async(struct obd_export *exp,
{
int rc = 0;
struct obd_device *obd;
- ENTRY;
if (exp == NULL || exp->exp_obd == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
obd = exp->exp_obd;
OBD_CHECK_DT_OP(obd, statfs, -EOPNOTSUPP);
@@ -1224,7 +1181,7 @@ static inline int obd_statfs_async(struct obd_export *exp,
if (oinfo->oi_cb_up)
oinfo->oi_cb_up(oinfo, 0);
}
- RETURN(rc);
+ return rc;
}
static inline int obd_statfs_rqset(struct obd_export *exp,
@@ -1234,11 +1191,10 @@ static inline int obd_statfs_rqset(struct obd_export *exp,
struct ptlrpc_request_set *set = NULL;
struct obd_info oinfo = { { { 0 } } };
int rc = 0;
- ENTRY;
set = ptlrpc_prep_set();
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
oinfo.oi_osfs = osfs;
oinfo.oi_flags = flags;
@@ -1246,7 +1202,7 @@ static inline int obd_statfs_rqset(struct obd_export *exp,
if (rc == 0)
rc = ptlrpc_set_wait(set);
ptlrpc_set_destroy(set);
- RETURN(rc);
+ return rc;
}
/* @max_age is the oldest time in jiffies that we accept using a cached data.
@@ -1258,10 +1214,9 @@ static inline int obd_statfs(const struct lu_env *env, struct obd_export *exp,
{
int rc = 0;
struct obd_device *obd = exp->exp_obd;
- ENTRY;
if (obd == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
OBD_CHECK_DT_OP(obd, statfs, -EOPNOTSUPP);
OBD_COUNTER_INCREMENT(obd, statfs);
@@ -1286,7 +1241,7 @@ static inline int obd_statfs(const struct lu_env *env, struct obd_export *exp,
memcpy(osfs, &obd->obd_osfs, sizeof(*osfs));
spin_unlock(&obd->obd_osfs_lock);
}
- RETURN(rc);
+ return rc;
}
static inline int obd_sync_rqset(struct obd_export *exp, struct obd_info *oinfo,
@@ -1294,20 +1249,19 @@ static inline int obd_sync_rqset(struct obd_export *exp, struct obd_info *oinfo,
{
struct ptlrpc_request_set *set = NULL;
int rc;
- ENTRY;
OBD_CHECK_DT_OP(exp->exp_obd, sync, -EOPNOTSUPP);
EXP_COUNTER_INCREMENT(exp, sync);
set = ptlrpc_prep_set();
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = OBP(exp->exp_obd, sync)(NULL, exp, oinfo, start, end, set);
if (rc == 0)
rc = ptlrpc_set_wait(set);
ptlrpc_set_destroy(set);
- RETURN(rc);
+ return rc;
}
static inline int obd_sync(const struct lu_env *env, struct obd_export *exp,
@@ -1315,13 +1269,12 @@ static inline int obd_sync(const struct lu_env *env, struct obd_export *exp,
struct ptlrpc_request_set *set)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(exp->exp_obd, sync, -EOPNOTSUPP);
EXP_COUNTER_INCREMENT(exp, sync);
rc = OBP(exp->exp_obd, sync)(env, exp, oinfo, start, end, set);
- RETURN(rc);
+ return rc;
}
static inline int obd_punch_rqset(struct obd_export *exp,
@@ -1330,20 +1283,19 @@ static inline int obd_punch_rqset(struct obd_export *exp,
{
struct ptlrpc_request_set *set = NULL;
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, punch);
EXP_COUNTER_INCREMENT(exp, punch);
set = ptlrpc_prep_set();
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = OBP(exp->exp_obd, punch)(NULL, exp, oinfo, oti, set);
if (rc == 0)
rc = ptlrpc_set_wait(set);
ptlrpc_set_destroy(set);
- RETURN(rc);
+ return rc;
}
static inline int obd_punch(const struct lu_env *env, struct obd_export *exp,
@@ -1351,13 +1303,12 @@ static inline int obd_punch(const struct lu_env *env, struct obd_export *exp,
struct ptlrpc_request_set *rqset)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, punch);
EXP_COUNTER_INCREMENT(exp, punch);
rc = OBP(exp->exp_obd, punch)(env, exp, oinfo, oti, rqset);
- RETURN(rc);
+ return rc;
}
static inline int obd_brw(int cmd, struct obd_export *exp,
@@ -1365,7 +1316,6 @@ static inline int obd_brw(int cmd, struct obd_export *exp,
struct brw_page *pg, struct obd_trans_info *oti)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, brw);
EXP_COUNTER_INCREMENT(exp, brw);
@@ -1377,7 +1327,7 @@ static inline int obd_brw(int cmd, struct obd_export *exp,
}
rc = OBP(exp->exp_obd, brw)(cmd, exp, oinfo, oa_bufs, pg, oti);
- RETURN(rc);
+ return rc;
}
static inline int obd_preprw(const struct lu_env *env, int cmd,
@@ -1389,14 +1339,13 @@ static inline int obd_preprw(const struct lu_env *env, int cmd,
struct lustre_capa *capa)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, preprw);
EXP_COUNTER_INCREMENT(exp, preprw);
rc = OBP(exp->exp_obd, preprw)(env, cmd, exp, oa, objcount, obj, remote,
pages, local, oti, capa);
- RETURN(rc);
+ return rc;
}
static inline int obd_commitrw(const struct lu_env *env, int cmd,
@@ -1406,14 +1355,12 @@ static inline int obd_commitrw(const struct lu_env *env, int cmd,
struct niobuf_local *local,
struct obd_trans_info *oti, int rc)
{
- ENTRY;
-
EXP_CHECK_DT_OP(exp, commitrw);
EXP_COUNTER_INCREMENT(exp, commitrw);
rc = OBP(exp->exp_obd, commitrw)(env, cmd, exp, oa, objcount, obj,
rnb, pages, local, oti, rc);
- RETURN(rc);
+ return rc;
}
static inline int obd_merge_lvb(struct obd_export *exp,
@@ -1421,13 +1368,12 @@ static inline int obd_merge_lvb(struct obd_export *exp,
struct ost_lvb *lvb, int kms_only)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, merge_lvb);
EXP_COUNTER_INCREMENT(exp, merge_lvb);
rc = OBP(exp->exp_obd, merge_lvb)(exp, lsm, lvb, kms_only);
- RETURN(rc);
+ return rc;
}
static inline int obd_adjust_kms(struct obd_export *exp,
@@ -1435,26 +1381,24 @@ static inline int obd_adjust_kms(struct obd_export *exp,
int shrink)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, adjust_kms);
EXP_COUNTER_INCREMENT(exp, adjust_kms);
rc = OBP(exp->exp_obd, adjust_kms)(exp, lsm, size, shrink);
- RETURN(rc);
+ return rc;
}
static inline int obd_iocontrol(unsigned int cmd, struct obd_export *exp,
int len, void *karg, void *uarg)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, iocontrol);
EXP_COUNTER_INCREMENT(exp, iocontrol);
rc = OBP(exp->exp_obd, iocontrol)(cmd, exp, len, karg, uarg);
- RETURN(rc);
+ return rc;
}
static inline int obd_enqueue_rqset(struct obd_export *exp,
@@ -1463,20 +1407,19 @@ static inline int obd_enqueue_rqset(struct obd_export *exp,
{
struct ptlrpc_request_set *set = NULL;
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, enqueue);
EXP_COUNTER_INCREMENT(exp, enqueue);
set = ptlrpc_prep_set();
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = OBP(exp->exp_obd, enqueue)(exp, oinfo, einfo, set);
if (rc == 0)
rc = ptlrpc_set_wait(set);
ptlrpc_set_destroy(set);
- RETURN(rc);
+ return rc;
}
static inline int obd_enqueue(struct obd_export *exp,
@@ -1485,13 +1428,12 @@ static inline int obd_enqueue(struct obd_export *exp,
struct ptlrpc_request_set *set)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, enqueue);
EXP_COUNTER_INCREMENT(exp, enqueue);
rc = OBP(exp->exp_obd, enqueue)(exp, oinfo, einfo, set);
- RETURN(rc);
+ return rc;
}
static inline int obd_change_cbdata(struct obd_export *exp,
@@ -1499,13 +1441,12 @@ static inline int obd_change_cbdata(struct obd_export *exp,
ldlm_iterator_t it, void *data)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, change_cbdata);
EXP_COUNTER_INCREMENT(exp, change_cbdata);
rc = OBP(exp->exp_obd, change_cbdata)(exp, lsm, it, data);
- RETURN(rc);
+ return rc;
}
static inline int obd_find_cbdata(struct obd_export *exp,
@@ -1513,13 +1454,12 @@ static inline int obd_find_cbdata(struct obd_export *exp,
ldlm_iterator_t it, void *data)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, find_cbdata);
EXP_COUNTER_INCREMENT(exp, find_cbdata);
rc = OBP(exp->exp_obd, find_cbdata)(exp, lsm, it, data);
- RETURN(rc);
+ return rc;
}
static inline int obd_cancel(struct obd_export *exp,
@@ -1527,13 +1467,12 @@ static inline int obd_cancel(struct obd_export *exp,
struct lustre_handle *lockh)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, cancel);
EXP_COUNTER_INCREMENT(exp, cancel);
rc = OBP(exp->exp_obd, cancel)(exp, ea, mode, lockh);
- RETURN(rc);
+ return rc;
}
static inline int obd_cancel_unused(struct obd_export *exp,
@@ -1542,13 +1481,12 @@ static inline int obd_cancel_unused(struct obd_export *exp,
void *opaque)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, cancel_unused);
EXP_COUNTER_INCREMENT(exp, cancel_unused);
rc = OBP(exp->exp_obd, cancel_unused)(exp, ea, flags, opaque);
- RETURN(rc);
+ return rc;
}
static inline int obd_pin(struct obd_export *exp, const struct lu_fid *fid,
@@ -1556,26 +1494,24 @@ static inline int obd_pin(struct obd_export *exp, const struct lu_fid *fid,
int flag)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, pin);
EXP_COUNTER_INCREMENT(exp, pin);
rc = OBP(exp->exp_obd, pin)(exp, fid, oc, handle, flag);
- RETURN(rc);
+ return rc;
}
static inline int obd_unpin(struct obd_export *exp,
struct obd_client_handle *handle, int flag)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, unpin);
EXP_COUNTER_INCREMENT(exp, unpin);
rc = OBP(exp->exp_obd, unpin)(exp, handle, flag);
- RETURN(rc);
+ return rc;
}
@@ -1583,30 +1519,26 @@ static inline void obd_import_event(struct obd_device *obd,
struct obd_import *imp,
enum obd_import_event event)
{
- ENTRY;
if (!obd) {
CERROR("NULL device\n");
- EXIT;
return;
}
if (obd->obd_set_up && OBP(obd, import_event)) {
OBD_COUNTER_INCREMENT(obd, import_event);
OBP(obd, import_event)(obd, imp, event);
}
- EXIT;
}
static inline int obd_llog_connect(struct obd_export *exp,
struct llogd_conn_body *body)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(exp->exp_obd, llog_connect, 0);
EXP_COUNTER_INCREMENT(exp, llog_connect);
rc = OBP(exp->exp_obd, llog_connect)(exp, body);
- RETURN(rc);
+ return rc;
}
@@ -1616,7 +1548,7 @@ static inline int obd_notify(struct obd_device *obd,
void *data)
{
int rc;
- ENTRY;
+
OBD_CHECK_DEV(obd);
/* the check for async_recov is a complete hack - I'm hereby
@@ -1625,17 +1557,17 @@ static inline int obd_notify(struct obd_device *obd,
by this point, and it needs to get them to execute mds_postrecov. */
if (!obd->obd_set_up && !obd->obd_async_recov) {
CDEBUG(D_HA, "obd %s not set up\n", obd->obd_name);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (!OBP(obd, notify)) {
CDEBUG(D_HA, "obd %s has no notify handler\n", obd->obd_name);
- RETURN(-ENOSYS);
+ return -ENOSYS;
}
OBD_COUNTER_INCREMENT(obd, notify);
rc = OBP(obd, notify)(obd, watched, ev, data);
- RETURN(rc);
+ return rc;
}
static inline int obd_notify_observer(struct obd_device *observer,
@@ -1669,26 +1601,24 @@ static inline int obd_quotacheck(struct obd_export *exp,
struct obd_quotactl *oqctl)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, quotacheck);
EXP_COUNTER_INCREMENT(exp, quotacheck);
rc = OBP(exp->exp_obd, quotacheck)(exp->exp_obd, exp, oqctl);
- RETURN(rc);
+ return rc;
}
static inline int obd_quotactl(struct obd_export *exp,
struct obd_quotactl *oqctl)
{
int rc;
- ENTRY;
EXP_CHECK_DT_OP(exp, quotactl);
EXP_COUNTER_INCREMENT(exp, quotactl);
rc = OBP(exp->exp_obd, quotactl)(exp->exp_obd, exp, oqctl);
- RETURN(rc);
+ return rc;
}
static inline int obd_health_check(const struct lu_env *env,
@@ -1702,56 +1632,52 @@ static inline int obd_health_check(const struct lu_env *env,
* <0 on error
*/
int rc;
- ENTRY;
/* don't use EXP_CHECK_DT_OP, because NULL method is normal here */
if (obd == NULL || !OBT(obd)) {
CERROR("cleaned up obd\n");
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
}
if (!obd->obd_set_up || obd->obd_stopping)
- RETURN(0);
+ return 0;
if (!OBP(obd, health_check))
- RETURN(0);
+ return 0;
rc = OBP(obd, health_check)(env, obd);
- RETURN(rc);
+ return rc;
}
static inline int obd_register_observer(struct obd_device *obd,
struct obd_device *observer)
{
- ENTRY;
OBD_CHECK_DEV(obd);
down_write(&obd->obd_observer_link_sem);
if (obd->obd_observer && observer) {
up_write(&obd->obd_observer_link_sem);
- RETURN(-EALREADY);
+ return -EALREADY;
}
obd->obd_observer = observer;
up_write(&obd->obd_observer_link_sem);
- RETURN(0);
+ return 0;
}
static inline int obd_pin_observer(struct obd_device *obd,
struct obd_device **observer)
{
- ENTRY;
down_read(&obd->obd_observer_link_sem);
if (!obd->obd_observer) {
*observer = NULL;
up_read(&obd->obd_observer_link_sem);
- RETURN(-ENOENT);
+ return -ENOENT;
}
*observer = obd->obd_observer;
- RETURN(0);
+ return 0;
}
static inline int obd_unpin_observer(struct obd_device *obd)
{
- ENTRY;
up_read(&obd->obd_observer_link_sem);
- RETURN(0);
+ return 0;
}
#if 0
@@ -1760,52 +1686,48 @@ static inline int obd_register_page_removal_cb(struct obd_export *exp,
obd_pin_extent_cb pin_cb)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(exp->exp_obd, register_page_removal_cb, 0);
OBD_COUNTER_INCREMENT(exp->exp_obd, register_page_removal_cb);
rc = OBP(exp->exp_obd, register_page_removal_cb)(exp, cb, pin_cb);
- RETURN(rc);
+ return rc;
}
static inline int obd_unregister_page_removal_cb(struct obd_export *exp,
obd_page_removal_cb_t cb)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(exp->exp_obd, unregister_page_removal_cb, 0);
OBD_COUNTER_INCREMENT(exp->exp_obd, unregister_page_removal_cb);
rc = OBP(exp->exp_obd, unregister_page_removal_cb)(exp, cb);
- RETURN(rc);
+ return rc;
}
static inline int obd_register_lock_cancel_cb(struct obd_export *exp,
obd_lock_cancel_cb cb)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(exp->exp_obd, register_lock_cancel_cb, 0);
OBD_COUNTER_INCREMENT(exp->exp_obd, register_lock_cancel_cb);
rc = OBP(exp->exp_obd, register_lock_cancel_cb)(exp, cb);
- RETURN(rc);
+ return rc;
}
static inline int obd_unregister_lock_cancel_cb(struct obd_export *exp,
obd_lock_cancel_cb cb)
{
int rc;
- ENTRY;
OBD_CHECK_DT_OP(exp->exp_obd, unregister_lock_cancel_cb, 0);
OBD_COUNTER_INCREMENT(exp->exp_obd, unregister_lock_cancel_cb);
rc = OBP(exp->exp_obd, unregister_lock_cancel_cb)(exp, cb);
- RETURN(rc);
+ return rc;
}
#endif
@@ -1814,34 +1736,33 @@ static inline int md_getstatus(struct obd_export *exp,
struct lu_fid *fid, struct obd_capa **pc)
{
int rc;
- ENTRY;
EXP_CHECK_MD_OP(exp, getstatus);
EXP_MD_COUNTER_INCREMENT(exp, getstatus);
rc = MDP(exp->exp_obd, getstatus)(exp, fid, pc);
- RETURN(rc);
+ return rc;
}
static inline int md_getattr(struct obd_export *exp, struct md_op_data *op_data,
struct ptlrpc_request **request)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, getattr);
EXP_MD_COUNTER_INCREMENT(exp, getattr);
rc = MDP(exp->exp_obd, getattr)(exp, op_data, request);
- RETURN(rc);
+ return rc;
}
static inline int md_null_inode(struct obd_export *exp,
const struct lu_fid *fid)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, null_inode);
EXP_MD_COUNTER_INCREMENT(exp, null_inode);
rc = MDP(exp->exp_obd, null_inode)(exp, fid);
- RETURN(rc);
+ return rc;
}
static inline int md_find_cbdata(struct obd_export *exp,
@@ -1849,11 +1770,11 @@ static inline int md_find_cbdata(struct obd_export *exp,
ldlm_iterator_t it, void *data)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, find_cbdata);
EXP_MD_COUNTER_INCREMENT(exp, find_cbdata);
rc = MDP(exp->exp_obd, find_cbdata)(exp, fid, it, data);
- RETURN(rc);
+ return rc;
}
static inline int md_close(struct obd_export *exp, struct md_op_data *op_data,
@@ -1861,11 +1782,11 @@ static inline int md_close(struct obd_export *exp, struct md_op_data *op_data,
struct ptlrpc_request **request)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, close);
EXP_MD_COUNTER_INCREMENT(exp, close);
rc = MDP(exp->exp_obd, close)(exp, op_data, mod, request);
- RETURN(rc);
+ return rc;
}
static inline int md_create(struct obd_export *exp, struct md_op_data *op_data,
@@ -1874,12 +1795,12 @@ static inline int md_create(struct obd_export *exp, struct md_op_data *op_data,
struct ptlrpc_request **request)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, create);
EXP_MD_COUNTER_INCREMENT(exp, create);
rc = MDP(exp->exp_obd, create)(exp, op_data, data, datalen, mode,
uid, gid, cap_effective, rdev, request);
- RETURN(rc);
+ return rc;
}
static inline int md_done_writing(struct obd_export *exp,
@@ -1887,11 +1808,11 @@ static inline int md_done_writing(struct obd_export *exp,
struct md_open_data *mod)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, done_writing);
EXP_MD_COUNTER_INCREMENT(exp, done_writing);
rc = MDP(exp->exp_obd, done_writing)(exp, op_data, mod);
- RETURN(rc);
+ return rc;
}
static inline int md_enqueue(struct obd_export *exp,
@@ -1904,12 +1825,12 @@ static inline int md_enqueue(struct obd_export *exp,
int extra_lock_flags)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, enqueue);
EXP_MD_COUNTER_INCREMENT(exp, enqueue);
rc = MDP(exp->exp_obd, enqueue)(exp, einfo, it, op_data, lockh,
lmm, lmmsize, req, extra_lock_flags);
- RETURN(rc);
+ return rc;
}
static inline int md_getattr_name(struct obd_export *exp,
@@ -1917,11 +1838,11 @@ static inline int md_getattr_name(struct obd_export *exp,
struct ptlrpc_request **request)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, getattr_name);
EXP_MD_COUNTER_INCREMENT(exp, getattr_name);
rc = MDP(exp->exp_obd, getattr_name)(exp, op_data, request);
- RETURN(rc);
+ return rc;
}
static inline int md_intent_lock(struct obd_export *exp,
@@ -1932,24 +1853,24 @@ static inline int md_intent_lock(struct obd_export *exp,
__u64 extra_lock_flags)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, intent_lock);
EXP_MD_COUNTER_INCREMENT(exp, intent_lock);
rc = MDP(exp->exp_obd, intent_lock)(exp, op_data, lmm, lmmsize,
it, lookup_flags, reqp, cb_blocking,
extra_lock_flags);
- RETURN(rc);
+ return rc;
}
static inline int md_link(struct obd_export *exp, struct md_op_data *op_data,
struct ptlrpc_request **request)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, link);
EXP_MD_COUNTER_INCREMENT(exp, link);
rc = MDP(exp->exp_obd, link)(exp, op_data, request);
- RETURN(rc);
+ return rc;
}
static inline int md_rename(struct obd_export *exp, struct md_op_data *op_data,
@@ -1957,12 +1878,12 @@ static inline int md_rename(struct obd_export *exp, struct md_op_data *op_data,
int newlen, struct ptlrpc_request **request)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, rename);
EXP_MD_COUNTER_INCREMENT(exp, rename);
rc = MDP(exp->exp_obd, rename)(exp, op_data, old, oldlen, new,
newlen, request);
- RETURN(rc);
+ return rc;
}
static inline int md_is_subdir(struct obd_export *exp,
@@ -1971,11 +1892,11 @@ static inline int md_is_subdir(struct obd_export *exp,
struct ptlrpc_request **request)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, is_subdir);
EXP_MD_COUNTER_INCREMENT(exp, is_subdir);
rc = MDP(exp->exp_obd, is_subdir)(exp, pfid, cfid, request);
- RETURN(rc);
+ return rc;
}
static inline int md_setattr(struct obd_export *exp, struct md_op_data *op_data,
@@ -1984,23 +1905,23 @@ static inline int md_setattr(struct obd_export *exp, struct md_op_data *op_data,
struct md_open_data **mod)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, setattr);
EXP_MD_COUNTER_INCREMENT(exp, setattr);
rc = MDP(exp->exp_obd, setattr)(exp, op_data, ea, ealen,
ea2, ea2len, request, mod);
- RETURN(rc);
+ return rc;
}
static inline int md_sync(struct obd_export *exp, const struct lu_fid *fid,
struct obd_capa *oc, struct ptlrpc_request **request)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, sync);
EXP_MD_COUNTER_INCREMENT(exp, sync);
rc = MDP(exp->exp_obd, sync)(exp, fid, oc, request);
- RETURN(rc);
+ return rc;
}
static inline int md_readpage(struct obd_export *exp, struct md_op_data *opdata,
@@ -2008,22 +1929,22 @@ static inline int md_readpage(struct obd_export *exp, struct md_op_data *opdata,
struct ptlrpc_request **request)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, readpage);
EXP_MD_COUNTER_INCREMENT(exp, readpage);
rc = MDP(exp->exp_obd, readpage)(exp, opdata, pages, request);
- RETURN(rc);
+ return rc;
}
static inline int md_unlink(struct obd_export *exp, struct md_op_data *op_data,
struct ptlrpc_request **request)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, unlink);
EXP_MD_COUNTER_INCREMENT(exp, unlink);
rc = MDP(exp->exp_obd, unlink)(exp, op_data, request);
- RETURN(rc);
+ return rc;
}
static inline int md_get_lustre_md(struct obd_export *exp,
@@ -2032,19 +1953,17 @@ static inline int md_get_lustre_md(struct obd_export *exp,
struct obd_export *md_exp,
struct lustre_md *md)
{
- ENTRY;
EXP_CHECK_MD_OP(exp, get_lustre_md);
EXP_MD_COUNTER_INCREMENT(exp, get_lustre_md);
- RETURN(MDP(exp->exp_obd, get_lustre_md)(exp, req, dt_exp, md_exp, md));
+ return MDP(exp->exp_obd, get_lustre_md)(exp, req, dt_exp, md_exp, md);
}
static inline int md_free_lustre_md(struct obd_export *exp,
struct lustre_md *md)
{
- ENTRY;
EXP_CHECK_MD_OP(exp, free_lustre_md);
EXP_MD_COUNTER_INCREMENT(exp, free_lustre_md);
- RETURN(MDP(exp->exp_obd, free_lustre_md)(exp, md));
+ return MDP(exp->exp_obd, free_lustre_md)(exp, md);
}
static inline int md_setxattr(struct obd_export *exp,
@@ -2054,12 +1973,11 @@ static inline int md_setxattr(struct obd_export *exp,
int output_size, int flags, __u32 suppgid,
struct ptlrpc_request **request)
{
- ENTRY;
EXP_CHECK_MD_OP(exp, setxattr);
EXP_MD_COUNTER_INCREMENT(exp, setxattr);
- RETURN(MDP(exp->exp_obd, setxattr)(exp, fid, oc, valid, name, input,
+ return MDP(exp->exp_obd, setxattr)(exp, fid, oc, valid, name, input,
input_size, output_size, flags,
- suppgid, request));
+ suppgid, request);
}
static inline int md_getxattr(struct obd_export *exp,
@@ -2069,40 +1987,36 @@ static inline int md_getxattr(struct obd_export *exp,
int output_size, int flags,
struct ptlrpc_request **request)
{
- ENTRY;
EXP_CHECK_MD_OP(exp, getxattr);
EXP_MD_COUNTER_INCREMENT(exp, getxattr);
- RETURN(MDP(exp->exp_obd, getxattr)(exp, fid, oc, valid, name, input,
+ return MDP(exp->exp_obd, getxattr)(exp, fid, oc, valid, name, input,
input_size, output_size, flags,
- request));
+ request);
}
static inline int md_set_open_replay_data(struct obd_export *exp,
struct obd_client_handle *och,
struct ptlrpc_request *open_req)
{
- ENTRY;
EXP_CHECK_MD_OP(exp, set_open_replay_data);
EXP_MD_COUNTER_INCREMENT(exp, set_open_replay_data);
- RETURN(MDP(exp->exp_obd, set_open_replay_data)(exp, och, open_req));
+ return MDP(exp->exp_obd, set_open_replay_data)(exp, och, open_req);
}
static inline int md_clear_open_replay_data(struct obd_export *exp,
struct obd_client_handle *och)
{
- ENTRY;
EXP_CHECK_MD_OP(exp, clear_open_replay_data);
EXP_MD_COUNTER_INCREMENT(exp, clear_open_replay_data);
- RETURN(MDP(exp->exp_obd, clear_open_replay_data)(exp, och));
+ return MDP(exp->exp_obd, clear_open_replay_data)(exp, och);
}
static inline int md_set_lock_data(struct obd_export *exp,
__u64 *lockh, void *data, __u64 *bits)
{
- ENTRY;
EXP_CHECK_MD_OP(exp, set_lock_data);
EXP_MD_COUNTER_INCREMENT(exp, set_lock_data);
- RETURN(MDP(exp->exp_obd, set_lock_data)(exp, lockh, data, bits));
+ return MDP(exp->exp_obd, set_lock_data)(exp, lockh, data, bits);
}
static inline int md_cancel_unused(struct obd_export *exp,
@@ -2113,14 +2027,13 @@ static inline int md_cancel_unused(struct obd_export *exp,
void *opaque)
{
int rc;
- ENTRY;
EXP_CHECK_MD_OP(exp, cancel_unused);
EXP_MD_COUNTER_INCREMENT(exp, cancel_unused);
rc = MDP(exp->exp_obd, cancel_unused)(exp, fid, policy, mode,
flags, opaque);
- RETURN(rc);
+ return rc;
}
static inline ldlm_mode_t md_lock_match(struct obd_export *exp, __u64 flags,
@@ -2130,21 +2043,19 @@ static inline ldlm_mode_t md_lock_match(struct obd_export *exp, __u64 flags,
ldlm_mode_t mode,
struct lustre_handle *lockh)
{
- ENTRY;
EXP_CHECK_MD_OP(exp, lock_match);
EXP_MD_COUNTER_INCREMENT(exp, lock_match);
- RETURN(MDP(exp->exp_obd, lock_match)(exp, flags, fid, type,
- policy, mode, lockh));
+ return MDP(exp->exp_obd, lock_match)(exp, flags, fid, type,
+ policy, mode, lockh);
}
static inline int md_init_ea_size(struct obd_export *exp, int easize,
int def_asize, int cookiesize)
{
- ENTRY;
EXP_CHECK_MD_OP(exp, init_ea_size);
EXP_MD_COUNTER_INCREMENT(exp, init_ea_size);
- RETURN(MDP(exp->exp_obd, init_ea_size)(exp, easize, def_asize,
- cookiesize));
+ return MDP(exp->exp_obd, init_ea_size)(exp, easize, def_asize,
+ cookiesize);
}
static inline int md_get_remote_perm(struct obd_export *exp,
@@ -2152,22 +2063,21 @@ static inline int md_get_remote_perm(struct obd_export *exp,
struct obd_capa *oc, __u32 suppgid,
struct ptlrpc_request **request)
{
- ENTRY;
EXP_CHECK_MD_OP(exp, get_remote_perm);
EXP_MD_COUNTER_INCREMENT(exp, get_remote_perm);
- RETURN(MDP(exp->exp_obd, get_remote_perm)(exp, fid, oc, suppgid,
- request));
+ return MDP(exp->exp_obd, get_remote_perm)(exp, fid, oc, suppgid,
+ request);
}
static inline int md_renew_capa(struct obd_export *exp, struct obd_capa *ocapa,
renew_capa_cb_t cb)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, renew_capa);
EXP_MD_COUNTER_INCREMENT(exp, renew_capa);
rc = MDP(exp->exp_obd, renew_capa)(exp, ocapa, cb);
- RETURN(rc);
+ return rc;
}
static inline int md_unpack_capa(struct obd_export *exp,
@@ -2176,11 +2086,11 @@ static inline int md_unpack_capa(struct obd_export *exp,
struct obd_capa **oc)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, unpack_capa);
EXP_MD_COUNTER_INCREMENT(exp, unpack_capa);
rc = MDP(exp->exp_obd, unpack_capa)(exp, req, field, oc);
- RETURN(rc);
+ return rc;
}
static inline int md_intent_getattr_async(struct obd_export *exp,
@@ -2188,11 +2098,11 @@ static inline int md_intent_getattr_async(struct obd_export *exp,
struct ldlm_enqueue_info *einfo)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, intent_getattr_async);
EXP_MD_COUNTER_INCREMENT(exp, intent_getattr_async);
rc = MDP(exp->exp_obd, intent_getattr_async)(exp, minfo, einfo);
- RETURN(rc);
+ return rc;
}
static inline int md_revalidate_lock(struct obd_export *exp,
@@ -2200,11 +2110,11 @@ static inline int md_revalidate_lock(struct obd_export *exp,
struct lu_fid *fid, __u64 *bits)
{
int rc;
- ENTRY;
+
EXP_CHECK_MD_OP(exp, revalidate_lock);
EXP_MD_COUNTER_INCREMENT(exp, revalidate_lock);
rc = MDP(exp->exp_obd, revalidate_lock)(exp, it, fid, bits);
- RETURN(rc);
+ return rc;
}
diff --git a/drivers/staging/lustre/lustre/include/obd_lov.h b/drivers/staging/lustre/lustre/include/obd_lov.h
index d82f3341d0a..235718b366d 100644
--- a/drivers/staging/lustre/lustre/include/obd_lov.h
+++ b/drivers/staging/lustre/lustre/include/obd_lov.h
@@ -44,16 +44,6 @@ static inline int lov_stripe_md_size(__u16 stripes)
return sizeof(struct lov_stripe_md) + stripes*sizeof(struct lov_oinfo*);
}
-static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic)
-{
- if (lmm_magic == LOV_MAGIC_V3)
- return sizeof(struct lov_mds_md_v3) +
- stripes * sizeof(struct lov_ost_data_v1);
- else
- return sizeof(struct lov_mds_md_v1) +
- stripes * sizeof(struct lov_ost_data_v1);
-}
-
struct lov_version_size {
__u32 lvs_magic;
size_t lvs_lmm_size;
diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h
index b5d40afc359..03e6133ef50 100644
--- a/drivers/staging/lustre/lustre/include/obd_support.h
+++ b/drivers/staging/lustre/lustre/include/obd_support.h
@@ -470,6 +470,7 @@ int obd_alloc_fail(const void *ptr, const char *name, const char *type,
#define OBD_FAIL_LFSCK_DELAY3 0x1602
#define OBD_FAIL_LFSCK_LINKEA_CRASH 0x1603
#define OBD_FAIL_LFSCK_LINKEA_MORE 0x1604
+#define OBD_FAIL_LFSCK_LINKEA_MORE2 0x1605
#define OBD_FAIL_LFSCK_FATAL1 0x1608
#define OBD_FAIL_LFSCK_FATAL2 0x1609
#define OBD_FAIL_LFSCK_CRASH 0x160a
diff --git a/drivers/staging/lustre/lustre/lclient/glimpse.c b/drivers/staging/lustre/lustre/lclient/glimpse.c
index 7f3974be1f9..7bbca4bf6b8 100644
--- a/drivers/staging/lustre/lustre/lclient/glimpse.c
+++ b/drivers/staging/lustre/lustre/lclient/glimpse.c
@@ -93,7 +93,6 @@ int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io,
struct cl_lock *lock;
int result;
- ENTRY;
result = 0;
if (!(lli->lli_flags & LLIF_MDS_SIZE_LOCK)) {
CDEBUG(D_DLMTRACE, "Glimpsing inode "DFID"\n", PFID(fid));
@@ -131,10 +130,10 @@ int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io,
cio->cui_glimpse = 0;
if (lock == NULL)
- RETURN(0);
+ return 0;
if (IS_ERR(lock))
- RETURN(PTR_ERR(lock));
+ return PTR_ERR(lock);
LASSERT(agl == 0);
result = cl_wait(env, lock);
@@ -159,7 +158,7 @@ int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io,
}
}
- RETURN(result);
+ return result;
}
static int cl_io_get(struct inode *inode, struct lu_env **envout,
@@ -203,8 +202,6 @@ int cl_glimpse_size0(struct inode *inode, int agl)
int result;
int refcheck;
- ENTRY;
-
result = cl_io_get(inode, &env, &io, &refcheck);
if (result > 0) {
again:
@@ -226,7 +223,7 @@ int cl_glimpse_size0(struct inode *inode, int agl)
goto again;
cl_env_put(env, &refcheck);
}
- RETURN(result);
+ return result;
}
int cl_local_size(struct inode *inode)
@@ -240,14 +237,12 @@ int cl_local_size(struct inode *inode)
int result;
int refcheck;
- ENTRY;
-
if (!cl_i2info(inode)->lli_has_smd)
- RETURN(0);
+ return 0;
result = cl_io_get(inode, &env, &io, &refcheck);
if (result <= 0)
- RETURN(result);
+ return result;
clob = io->ci_obj;
result = cl_io_init(env, io, CIT_MISC, clob);
@@ -270,5 +265,5 @@ int cl_local_size(struct inode *inode)
}
cl_io_fini(env, io);
cl_env_put(env, &refcheck);
- RETURN(result);
+ return result;
}
diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
index 4a0166687f0..8ff38c64b7a 100644
--- a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
+++ b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
@@ -169,7 +169,6 @@ int ccc_device_init(const struct lu_env *env, struct lu_device *d,
{
struct ccc_device *vdv;
int rc;
- ENTRY;
vdv = lu2ccc_dev(d);
vdv->cdv_next = lu2cl_dev(next);
@@ -182,7 +181,7 @@ int ccc_device_init(const struct lu_env *env, struct lu_device *d,
lu_device_get(next);
lu_ref_add(&next->ld_reference, "lu-stack", &lu_site_init);
}
- RETURN(rc);
+ return rc;
}
struct lu_device *ccc_device_fini(const struct lu_env *env,
@@ -201,11 +200,10 @@ struct lu_device *ccc_device_alloc(const struct lu_env *env,
struct lu_device *lud;
struct cl_site *site;
int rc;
- ENTRY;
OBD_ALLOC_PTR(vdv);
if (vdv == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
lud = &vdv->cdv_cl.cd_lu_dev;
cl_device_init(&vdv->cdv_cl, t);
@@ -228,7 +226,7 @@ struct lu_device *ccc_device_alloc(const struct lu_env *env,
ccc_device_free(env, lud);
lud = ERR_PTR(rc);
}
- RETURN(lud);
+ return lud;
}
struct lu_device *ccc_device_free(const struct lu_env *env,
@@ -418,7 +416,6 @@ int ccc_object_glimpse(const struct lu_env *env,
{
struct inode *inode = ccc_object_inode(obj);
- ENTRY;
lvb->lvb_mtime = cl_inode_mtime(inode);
lvb->lvb_atime = cl_inode_atime(inode);
lvb->lvb_ctime = cl_inode_ctime(inode);
@@ -429,7 +426,7 @@ int ccc_object_glimpse(const struct lu_env *env,
*/
if (lvb->lvb_size > 0 && lvb->lvb_blocks == 0)
lvb->lvb_blocks = dirty_cnt(inode);
- RETURN(0);
+ return 0;
}
@@ -479,8 +476,6 @@ int ccc_page_is_under_lock(const struct lu_env *env,
int result;
- ENTRY;
-
if (io->ci_type == CIT_READ || io->ci_type == CIT_WRITE ||
io->ci_type == CIT_FAULT) {
if (cio->cui_fd->fd_flags & LL_FILE_GROUP_LOCKED)
@@ -495,7 +490,7 @@ int ccc_page_is_under_lock(const struct lu_env *env,
}
} else
result = 0;
- RETURN(result);
+ return result;
}
int ccc_fail(const struct lu_env *env, const struct cl_page_slice *slice)
@@ -559,9 +554,8 @@ int ccc_transient_page_prep(const struct lu_env *env,
const struct cl_page_slice *slice,
struct cl_io *unused)
{
- ENTRY;
/* transient page should always be sent. */
- RETURN(0);
+ return 0;
}
/*****************************************************************************
@@ -623,7 +617,6 @@ int ccc_lock_fits_into(const struct lu_env *env,
const struct ccc_io *cio = ccc_env_io(env);
int result;
- ENTRY;
/*
* Work around DLM peculiarity: it assumes that glimpse
* (LDLM_FL_HAS_INTENT) lock is always LCK_PR, and returns reads lock
@@ -642,7 +635,7 @@ int ccc_lock_fits_into(const struct lu_env *env,
result = lock->cll_state >= CLS_ENQUEUED;
else
result = 1;
- RETURN(result);
+ return result;
}
/**
@@ -655,7 +648,6 @@ void ccc_lock_state(const struct lu_env *env,
enum cl_lock_state state)
{
struct cl_lock *lock = slice->cls_lock;
- ENTRY;
/*
* Refresh inode attributes when the lock is moving into CLS_HELD
@@ -682,7 +674,6 @@ void ccc_lock_state(const struct lu_env *env,
lock->cll_descr.cld_end == CL_PAGE_EOF)
cl_merge_lvb(env, inode);
}
- EXIT;
}
/*****************************************************************************
@@ -707,7 +698,6 @@ int ccc_io_one_lock_index(const struct lu_env *env, struct cl_io *io,
struct cl_object *obj = io->ci_obj;
CLOBINVRNT(env, obj, ccc_object_invariant(obj));
- ENTRY;
CDEBUG(D_VFSTRACE, "lock: %d [%lu, %lu]\n", mode, start, end);
@@ -725,7 +715,7 @@ int ccc_io_one_lock_index(const struct lu_env *env, struct cl_io *io,
descr->cld_enq_flags = enqflags;
cl_io_lock_add(env, io, &cio->cui_link);
- RETURN(0);
+ return 0;
}
void ccc_io_update_iov(const struct lu_env *env,
@@ -986,11 +976,9 @@ int cl_setattr_ost(struct inode *inode, const struct iattr *attr,
int result;
int refcheck;
- ENTRY;
-
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
io = ccc_env_thread_io(env);
io->ci_obj = cl_i2info(inode)->lli_clob;
@@ -1019,7 +1007,7 @@ again:
if (unlikely(io->ci_need_restart))
goto again;
cl_env_put(env, &refcheck);
- RETURN(result);
+ return result;
}
/*****************************************************************************
@@ -1166,7 +1154,7 @@ int cl_file_inode_init(struct inode *inode, struct lustre_md *md)
* locked by I_NEW bit.
*/
lli->lli_clob = clob;
- lli->lli_has_smd = md->lsm != NULL;
+ lli->lli_has_smd = lsm_has_objects(md->lsm);
lu_object_ref_add(&clob->co_lu, "inode", inode);
} else
result = PTR_ERR(clob);
@@ -1284,9 +1272,9 @@ __u16 ll_dirent_type_get(struct lu_dirent *ent)
__u64 cl_fid_build_ino(const struct lu_fid *fid, int api32)
{
if (BITS_PER_LONG == 32 || api32)
- RETURN(fid_flatten32(fid));
+ return fid_flatten32(fid);
else
- RETURN(fid_flatten(fid));
+ return fid_flatten(fid);
}
/**
@@ -1295,15 +1283,14 @@ __u64 cl_fid_build_ino(const struct lu_fid *fid, int api32)
__u32 cl_fid_build_gen(const struct lu_fid *fid)
{
__u32 gen;
- ENTRY;
if (fid_is_igif(fid)) {
gen = lu_igif_gen(fid);
- RETURN(gen);
+ return gen;
}
gen = (fid_flatten(fid) >> 32);
- RETURN(gen);
+ return gen;
}
/* lsm is unreliable after hsm implementation as layout can be changed at
diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_misc.c b/drivers/staging/lustre/lustre/lclient/lcommon_misc.c
index 8ecbef92753..2b4dbeebcd5 100644
--- a/drivers/staging/lustre/lustre/lclient/lcommon_misc.c
+++ b/drivers/staging/lustre/lustre/lclient/lcommon_misc.c
@@ -57,12 +57,11 @@ int cl_init_ea_size(struct obd_export *md_exp, struct obd_export *dt_exp)
int rc, easize, def_easize, cookiesize;
struct lov_desc desc;
__u16 stripes;
- ENTRY;
rc = obd_get_info(NULL, dt_exp, sizeof(KEY_LOVDESC), KEY_LOVDESC,
&valsize, &desc, NULL);
if (rc)
- RETURN(rc);
+ return rc;
stripes = min(desc.ld_tgt_count, (__u32)LOV_MAX_STRIPE_COUNT);
lsm.lsm_stripe_count = stripes;
@@ -77,7 +76,7 @@ int cl_init_ea_size(struct obd_export *md_exp, struct obd_export *dt_exp)
easize, cookiesize);
rc = md_init_ea_size(md_exp, easize, def_easize, cookiesize);
- RETURN(rc);
+ return rc;
}
/**
@@ -95,7 +94,6 @@ int cl_ocd_update(struct obd_device *host,
__u64 flags;
int result;
- ENTRY;
if (!strcmp(watched->obd_type->typ_name, LUSTRE_OSC_NAME)) {
cli = &watched->u.cli;
lco = owner;
@@ -116,7 +114,7 @@ int cl_ocd_update(struct obd_device *host,
watched->obd_name);
result = -EINVAL;
}
- RETURN(result);
+ return result;
}
#define GROUPLOCK_SCOPE "grouplock"
diff --git a/drivers/staging/lustre/lustre/ldlm/interval_tree.c b/drivers/staging/lustre/lustre/ldlm/interval_tree.c
index ce90c7e3c48..c65b13c800f 100644
--- a/drivers/staging/lustre/lustre/ldlm/interval_tree.c
+++ b/drivers/staging/lustre/lustre/ldlm/interval_tree.c
@@ -133,53 +133,45 @@ for (node = interval_last(root); node != NULL; \
static struct interval_node *interval_first(struct interval_node *node)
{
- ENTRY;
-
if (!node)
- RETURN(NULL);
+ return NULL;
while (node->in_left)
node = node->in_left;
- RETURN(node);
+ return node;
}
static struct interval_node *interval_last(struct interval_node *node)
{
- ENTRY;
-
if (!node)
- RETURN(NULL);
+ return NULL;
while (node->in_right)
node = node->in_right;
- RETURN(node);
+ return node;
}
static struct interval_node *interval_next(struct interval_node *node)
{
- ENTRY;
-
if (!node)
- RETURN(NULL);
+ return NULL;
if (node->in_right)
- RETURN(interval_first(node->in_right));
+ return interval_first(node->in_right);
while (node->in_parent && node_is_right_child(node))
node = node->in_parent;
- RETURN(node->in_parent);
+ return node->in_parent;
}
static struct interval_node *interval_prev(struct interval_node *node)
{
- ENTRY;
-
if (!node)
- RETURN(NULL);
+ return NULL;
if (node->in_left)
- RETURN(interval_last(node->in_left));
+ return interval_last(node->in_left);
while (node->in_parent && node_is_left_child(node))
node = node->in_parent;
- RETURN(node->in_parent);
+ return node->in_parent;
}
enum interval_iter interval_iterate(struct interval_node *root,
@@ -188,7 +180,6 @@ enum interval_iter interval_iterate(struct interval_node *root,
{
struct interval_node *node;
enum interval_iter rc = INTERVAL_ITER_CONT;
- ENTRY;
interval_for_each(node, root) {
rc = func(node, data);
@@ -196,7 +187,7 @@ enum interval_iter interval_iterate(struct interval_node *root,
break;
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(interval_iterate);
@@ -206,7 +197,6 @@ enum interval_iter interval_iterate_reverse(struct interval_node *root,
{
struct interval_node *node;
enum interval_iter rc = INTERVAL_ITER_CONT;
- ENTRY;
interval_for_each_reverse(node, root) {
rc = func(node, data);
@@ -214,7 +204,7 @@ enum interval_iter interval_iterate_reverse(struct interval_node *root,
break;
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(interval_iterate_reverse);
@@ -225,7 +215,6 @@ struct interval_node *interval_find(struct interval_node *root,
{
struct interval_node *walk = root;
int rc;
- ENTRY;
while (walk) {
rc = extent_compare(ex, &walk->in_extent);
@@ -237,7 +226,7 @@ struct interval_node *interval_find(struct interval_node *root,
walk = walk->in_right;
}
- RETURN(walk);
+ return walk;
}
EXPORT_SYMBOL(interval_find);
@@ -326,7 +315,6 @@ static void interval_insert_color(struct interval_node *node,
struct interval_node **root)
{
struct interval_node *parent, *gparent;
- ENTRY;
while ((parent = node->in_parent) && node_is_red(parent)) {
gparent = parent->in_parent;
@@ -373,7 +361,6 @@ static void interval_insert_color(struct interval_node *node,
}
(*root)->in_color = INTERVAL_BLACK;
- EXIT;
}
struct interval_node *interval_insert(struct interval_node *node,
@@ -381,14 +368,13 @@ struct interval_node *interval_insert(struct interval_node *node,
{
struct interval_node **p, *parent = NULL;
- ENTRY;
LASSERT(!interval_is_intree(node));
p = root;
while (*p) {
parent = *p;
if (node_equal(parent, node))
- RETURN(parent);
+ return parent;
/* max_high field must be updated after each iteration */
if (parent->in_max_high < interval_high(node))
@@ -409,7 +395,7 @@ struct interval_node *interval_insert(struct interval_node *node,
interval_insert_color(node, root);
node->in_intree = 1;
- RETURN(NULL);
+ return NULL;
}
EXPORT_SYMBOL(interval_insert);
@@ -423,7 +409,6 @@ static void interval_erase_color(struct interval_node *node,
struct interval_node **root)
{
struct interval_node *tmp;
- ENTRY;
while (node_is_black_or_0(node) && node != *root) {
if (parent->in_left == node) {
@@ -490,7 +475,6 @@ static void interval_erase_color(struct interval_node *node,
}
if (node)
node->in_color = INTERVAL_BLACK;
- EXIT;
}
/*
@@ -501,7 +485,6 @@ static void update_maxhigh(struct interval_node *node,
__u64 old_maxhigh)
{
__u64 left_max, right_max;
- ENTRY;
while (node) {
left_max = node->in_left ? node->in_left->in_max_high : 0;
@@ -513,7 +496,6 @@ static void update_maxhigh(struct interval_node *node,
break;
node = node->in_parent;
}
- EXIT;
}
void interval_erase(struct interval_node *node,
@@ -521,7 +503,6 @@ void interval_erase(struct interval_node *node,
{
struct interval_node *child, *parent;
int color;
- ENTRY;
LASSERT(interval_is_intree(node));
node->in_intree = 0;
@@ -586,7 +567,6 @@ void interval_erase(struct interval_node *node,
color:
if (color == INTERVAL_BLACK)
interval_erase_color(child, parent, root);
- EXIT;
}
EXPORT_SYMBOL(interval_erase);
diff --git a/drivers/staging/lustre/lustre/ldlm/l_lock.c b/drivers/staging/lustre/lustre/ldlm/l_lock.c
index 853409aa945..32f4d52b536 100644
--- a/drivers/staging/lustre/lustre/ldlm/l_lock.c
+++ b/drivers/staging/lustre/lustre/ldlm/l_lock.c
@@ -51,12 +51,12 @@
struct ldlm_resource *lock_res_and_lock(struct ldlm_lock *lock)
{
/* on server-side resource of lock doesn't change */
- if (!lock->l_ns_srv)
+ if ((lock->l_flags & LDLM_FL_NS_SRV) == 0)
spin_lock(&lock->l_lock);
lock_res(lock->l_resource);
- lock->l_res_locked = 1;
+ lock->l_flags |= LDLM_FL_RES_LOCKED;
return lock->l_resource;
}
EXPORT_SYMBOL(lock_res_and_lock);
@@ -67,10 +67,10 @@ EXPORT_SYMBOL(lock_res_and_lock);
void unlock_res_and_lock(struct ldlm_lock *lock)
{
/* on server-side resource of lock doesn't change */
- lock->l_res_locked = 0;
+ lock->l_flags &= ~LDLM_FL_RES_LOCKED;
unlock_res(lock->l_resource);
- if (!lock->l_ns_srv)
+ if ((lock->l_flags & LDLM_FL_NS_SRV) == 0)
spin_unlock(&lock->l_lock);
}
EXPORT_SYMBOL(unlock_res_and_lock);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c
index f7432f78e39..7e316637369 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c
@@ -72,7 +72,6 @@ __u64 ldlm_extent_shift_kms(struct ldlm_lock *lock, __u64 old_kms)
struct list_head *tmp;
struct ldlm_lock *lck;
__u64 kms = 0;
- ENTRY;
/* don't let another thread in ldlm_extent_shift_kms race in
* just after we finish and take our lock into account in its
@@ -86,7 +85,7 @@ __u64 ldlm_extent_shift_kms(struct ldlm_lock *lock, __u64 old_kms)
continue;
if (lck->l_policy_data.l_extent.end >= old_kms)
- RETURN(old_kms);
+ return old_kms;
/* This extent _has_ to be smaller than old_kms (checked above)
* so kms can only ever be smaller or the same as old_kms. */
@@ -95,7 +94,7 @@ __u64 ldlm_extent_shift_kms(struct ldlm_lock *lock, __u64 old_kms)
}
LASSERTF(kms <= old_kms, "kms "LPU64" old_kms "LPU64"\n", kms, old_kms);
- RETURN(kms);
+ return kms;
}
EXPORT_SYMBOL(ldlm_extent_shift_kms);
@@ -103,16 +102,15 @@ struct kmem_cache *ldlm_interval_slab;
struct ldlm_interval *ldlm_interval_alloc(struct ldlm_lock *lock)
{
struct ldlm_interval *node;
- ENTRY;
LASSERT(lock->l_resource->lr_type == LDLM_EXTENT);
OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, __GFP_IO);
if (node == NULL)
- RETURN(NULL);
+ return NULL;
INIT_LIST_HEAD(&node->li_group);
ldlm_interval_attach(node, lock);
- RETURN(node);
+ return node;
}
void ldlm_interval_free(struct ldlm_interval *node)
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
index f100a84bde7..c68ed276633 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
@@ -142,8 +142,6 @@ static inline void ldlm_flock_blocking_unlink(struct ldlm_lock *req)
static inline void
ldlm_flock_destroy(struct ldlm_lock *lock, ldlm_mode_t mode, __u64 flags)
{
- ENTRY;
-
LDLM_DEBUG(lock, "ldlm_flock_destroy(mode: %d, flags: 0x%llx)",
mode, flags);
@@ -162,7 +160,6 @@ ldlm_flock_destroy(struct ldlm_lock *lock, ldlm_mode_t mode, __u64 flags)
}
ldlm_lock_destroy_nolock(lock);
- EXIT;
}
/**
@@ -198,6 +195,7 @@ ldlm_flock_deadlock(struct ldlm_lock *req, struct ldlm_lock *bl_lock)
if (lock == NULL)
break;
+ LASSERT(req != lock);
flock = &lock->l_policy_data.l_flock;
LASSERT(flock->owner == bl_owner);
bl_owner = flock->blocking_owner;
@@ -253,7 +251,6 @@ ldlm_process_flock_lock(struct ldlm_lock *req, __u64 *flags, int first_enq,
int splitted = 0;
const struct ldlm_callback_suite null_cbs = { NULL };
int rc;
- ENTRY;
CDEBUG(D_DLMTRACE, "flags %#llx owner "LPU64" pid %u mode %u start "
LPU64" end "LPU64"\n", *flags,
@@ -308,12 +305,12 @@ reprocess:
continue;
if (!first_enq)
- RETURN(LDLM_ITER_CONTINUE);
+ return LDLM_ITER_CONTINUE;
if (*flags & LDLM_FL_BLOCK_NOWAIT) {
ldlm_flock_destroy(req, mode, *flags);
*err = -EAGAIN;
- RETURN(LDLM_ITER_STOP);
+ return LDLM_ITER_STOP;
}
if (*flags & LDLM_FL_TEST_LOCK) {
@@ -326,24 +323,27 @@ reprocess:
req->l_policy_data.l_flock.end =
lock->l_policy_data.l_flock.end;
*flags |= LDLM_FL_LOCK_CHANGED;
- RETURN(LDLM_ITER_STOP);
- }
-
- if (ldlm_flock_deadlock(req, lock)) {
- ldlm_flock_destroy(req, mode, *flags);
- *err = -EDEADLK;
- RETURN(LDLM_ITER_STOP);
+ return LDLM_ITER_STOP;
}
+ /* add lock to blocking list before deadlock
+ * check to prevent race */
rc = ldlm_flock_blocking_link(req, lock);
if (rc) {
ldlm_flock_destroy(req, mode, *flags);
*err = rc;
- RETURN(LDLM_ITER_STOP);
+ return LDLM_ITER_STOP;
+ }
+ if (ldlm_flock_deadlock(req, lock)) {
+ ldlm_flock_blocking_unlink(req);
+ ldlm_flock_destroy(req, mode, *flags);
+ *err = -EDEADLK;
+ return LDLM_ITER_STOP;
}
+
ldlm_resource_add_lock(res, &res->lr_waiting, req);
*flags |= LDLM_FL_BLOCK_GRANTED;
- RETURN(LDLM_ITER_STOP);
+ return LDLM_ITER_STOP;
}
}
@@ -351,7 +351,7 @@ reprocess:
ldlm_flock_destroy(req, mode, *flags);
req->l_req_mode = LCK_NL;
*flags |= LDLM_FL_LOCK_CHANGED;
- RETURN(LDLM_ITER_STOP);
+ return LDLM_ITER_STOP;
}
/* In case we had slept on this lock request take it off of the
@@ -463,7 +463,7 @@ reprocess:
ldlm_flock_destroy(req, lock->l_granted_mode,
*flags);
*err = -ENOLCK;
- RETURN(LDLM_ITER_STOP);
+ return LDLM_ITER_STOP;
}
goto reprocess;
}
@@ -530,7 +530,7 @@ reprocess:
ldlm_flock_destroy(req, mode, *flags);
ldlm_resource_dump(D_INFO, res);
- RETURN(LDLM_ITER_CONTINUE);
+ return LDLM_ITER_CONTINUE;
}
struct ldlm_flock_wait_data {
@@ -542,7 +542,6 @@ static void
ldlm_flock_interrupted_wait(void *data)
{
struct ldlm_lock *lock;
- ENTRY;
lock = ((struct ldlm_flock_wait_data *)data)->fwd_lock;
@@ -553,8 +552,6 @@ ldlm_flock_interrupted_wait(void *data)
/* client side - set flag to prevent lock from being put on LRU list */
lock->l_flags |= LDLM_FL_CBPENDING;
unlock_res_and_lock(lock);
-
- EXIT;
}
/**
@@ -577,7 +574,6 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
struct l_wait_info lwi;
ldlm_error_t err;
int rc = 0;
- ENTRY;
CDEBUG(D_DLMTRACE, "flags: 0x%llx data: %p getlk: %p\n",
flags, data, getlk);
@@ -595,7 +591,7 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
/* Need to wake up the waiter if we were evicted */
wake_up(&lock->l_waitq);
- RETURN(0);
+ return 0;
}
LASSERT(flags != LDLM_FL_WAIT_NOREPROC);
@@ -607,7 +603,7 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
goto granted;
/* CP AST RPC: lock get granted, wake it up */
wake_up(&lock->l_waitq);
- RETURN(0);
+ return 0;
}
LDLM_DEBUG(lock, "client-side enqueue returned a blocked lock, "
@@ -633,26 +629,26 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
if (rc) {
LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)",
rc);
- RETURN(rc);
+ return rc;
}
granted:
OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_CP_CB_WAIT, 10);
- if (lock->l_destroyed) {
+ if (lock->l_flags & LDLM_FL_DESTROYED) {
LDLM_DEBUG(lock, "client-side enqueue waking up: destroyed");
- RETURN(0);
+ return 0;
}
if (lock->l_flags & LDLM_FL_FAILED) {
LDLM_DEBUG(lock, "client-side enqueue waking up: failed");
- RETURN(-EIO);
+ return -EIO;
}
if (rc) {
LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)",
rc);
- RETURN(rc);
+ return rc;
}
LDLM_DEBUG(lock, "client-side enqueue granted");
@@ -694,15 +690,13 @@ granted:
ldlm_process_flock_lock(lock, &noreproc, 1, &err, NULL);
}
unlock_res_and_lock(lock);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_flock_completion_ast);
int ldlm_flock_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
void *data, int flag)
{
- ENTRY;
-
LASSERT(lock);
LASSERT(flag == LDLM_CB_CANCELING);
@@ -710,7 +704,7 @@ int ldlm_flock_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
lock_res_and_lock(lock);
ldlm_flock_blocking_unlink(lock);
unlock_res_and_lock(lock);
- RETURN(0);
+ return 0;
}
void ldlm_flock_policy_wire18_to_local(const ldlm_wire_policy_data_t *wpolicy,
@@ -831,19 +825,17 @@ int ldlm_init_flock_export(struct obd_export *exp)
&ldlm_export_flock_ops,
CFS_HASH_DEFAULT | CFS_HASH_NBLK_CHANGE);
if (!exp->exp_flock_hash)
- RETURN(-ENOMEM);
+ return -ENOMEM;
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_init_flock_export);
void ldlm_destroy_flock_export(struct obd_export *exp)
{
- ENTRY;
if (exp->exp_flock_hash) {
cfs_hash_putref(exp->exp_flock_hash);
exp->exp_flock_hash = NULL;
}
- EXIT;
}
EXPORT_SYMBOL(ldlm_destroy_flock_export);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
index 141a957462f..8cd79633dea 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
@@ -36,23 +36,46 @@
#define MAX_STRING_SIZE 128
-extern atomic_t ldlm_srv_namespace_nr;
-extern atomic_t ldlm_cli_namespace_nr;
+extern int ldlm_srv_namespace_nr;
+extern int ldlm_cli_namespace_nr;
extern struct mutex ldlm_srv_namespace_lock;
extern struct list_head ldlm_srv_namespace_list;
extern struct mutex ldlm_cli_namespace_lock;
-extern struct list_head ldlm_cli_namespace_list;
+extern struct list_head ldlm_cli_active_namespace_list;
+extern struct list_head ldlm_cli_inactive_namespace_list;
-static inline atomic_t *ldlm_namespace_nr(ldlm_side_t client)
+static inline int ldlm_namespace_nr_read(ldlm_side_t client)
{
return client == LDLM_NAMESPACE_SERVER ?
- &ldlm_srv_namespace_nr : &ldlm_cli_namespace_nr;
+ ldlm_srv_namespace_nr : ldlm_cli_namespace_nr;
+}
+
+static inline void ldlm_namespace_nr_inc(ldlm_side_t client)
+{
+ if (client == LDLM_NAMESPACE_SERVER)
+ ldlm_srv_namespace_nr++;
+ else
+ ldlm_cli_namespace_nr++;
+}
+
+static inline void ldlm_namespace_nr_dec(ldlm_side_t client)
+{
+ if (client == LDLM_NAMESPACE_SERVER)
+ ldlm_srv_namespace_nr--;
+ else
+ ldlm_cli_namespace_nr--;
}
static inline struct list_head *ldlm_namespace_list(ldlm_side_t client)
{
return client == LDLM_NAMESPACE_SERVER ?
- &ldlm_srv_namespace_list : &ldlm_cli_namespace_list;
+ &ldlm_srv_namespace_list : &ldlm_cli_active_namespace_list;
+}
+
+static inline struct list_head *ldlm_namespace_inactive_list(ldlm_side_t client)
+{
+ return client == LDLM_NAMESPACE_SERVER ?
+ &ldlm_srv_namespace_list : &ldlm_cli_inactive_namespace_list;
}
static inline struct mutex *ldlm_namespace_lock(ldlm_side_t client)
@@ -61,6 +84,16 @@ static inline struct mutex *ldlm_namespace_lock(ldlm_side_t client)
&ldlm_srv_namespace_lock : &ldlm_cli_namespace_lock;
}
+/* ns_bref is the number of resources in this namespace */
+static inline int ldlm_ns_empty(struct ldlm_namespace *ns)
+{
+ return atomic_read(&ns->ns_bref) == 0;
+}
+
+void ldlm_namespace_move_to_active_locked(struct ldlm_namespace *, ldlm_side_t);
+void ldlm_namespace_move_to_inactive_locked(struct ldlm_namespace *, ldlm_side_t);
+struct ldlm_namespace *ldlm_namespace_first_locked(ldlm_side_t);
+
/* ldlm_request.c */
/* Cancel lru flag, it indicates we cancel aged locks. */
enum {
@@ -159,8 +192,8 @@ void ldlm_destroy_flock_export(struct obd_export *exp);
void l_check_ns_lock(struct ldlm_namespace *ns);
void l_check_no_ns_lock(struct ldlm_namespace *ns);
-extern proc_dir_entry_t *ldlm_svc_proc_dir;
-extern proc_dir_entry_t *ldlm_type_proc_dir;
+extern struct proc_dir_entry *ldlm_svc_proc_dir;
+extern struct proc_dir_entry *ldlm_type_proc_dir;
struct ldlm_state {
struct ptlrpc_service *ldlm_cb_service;
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c
index 42df53072dc..1a8c0d7005c 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c
@@ -60,17 +60,16 @@ static int import_set_conn(struct obd_import *imp, struct obd_uuid *uuid,
struct ptlrpc_connection *ptlrpc_conn;
struct obd_import_conn *imp_conn = NULL, *item;
int rc = 0;
- ENTRY;
if (!create && !priority) {
CDEBUG(D_HA, "Nothing to do\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
ptlrpc_conn = ptlrpc_uuid_to_connection(uuid);
if (!ptlrpc_conn) {
CDEBUG(D_HA, "can't find connection %s\n", uuid->uuid);
- RETURN (-ENOENT);
+ return -ENOENT;
}
if (create) {
@@ -115,13 +114,13 @@ static int import_set_conn(struct obd_import *imp, struct obd_uuid *uuid,
}
spin_unlock(&imp->imp_lock);
- RETURN(0);
+ return 0;
out_free:
if (imp_conn)
OBD_FREE(imp_conn, sizeof(*imp_conn));
out_put:
ptlrpc_connection_put(ptlrpc_conn);
- RETURN(rc);
+ return rc;
}
int import_set_conn_priority(struct obd_import *imp, struct obd_uuid *uuid)
@@ -141,7 +140,6 @@ int client_import_del_conn(struct obd_import *imp, struct obd_uuid *uuid)
struct obd_import_conn *imp_conn;
struct obd_export *dlmexp;
int rc = -ENOENT;
- ENTRY;
spin_lock(&imp->imp_lock);
if (list_empty(&imp->imp_conn_list)) {
@@ -187,7 +185,7 @@ out:
spin_unlock(&imp->imp_lock);
if (rc == -ENOENT)
CERROR("connection %s not found\n", uuid->uuid);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(client_import_del_conn);
@@ -200,7 +198,6 @@ int client_import_find_conn(struct obd_import *imp, lnet_nid_t peer,
{
struct obd_import_conn *conn;
int rc = -ENOENT;
- ENTRY;
spin_lock(&imp->imp_lock);
list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
@@ -212,7 +209,7 @@ int client_import_find_conn(struct obd_import *imp, lnet_nid_t peer,
}
}
spin_unlock(&imp->imp_lock);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(client_import_find_conn);
@@ -267,7 +264,6 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg)
ldlm_ns_type_t ns_type = LDLM_NS_TYPE_UNKNOWN;
int rc;
char *cli_name = lustre_cfg_buf(lcfg, 0);
- ENTRY;
/* In a more perfect world, we would hang a ptlrpc_client off of
* obd_type and just use the values from there. */
@@ -305,27 +301,27 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg)
} else {
CERROR("unknown client OBD type \"%s\", can't setup\n",
name);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1) {
CERROR("requires a TARGET UUID\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (LUSTRE_CFG_BUFLEN(lcfg, 1) > 37) {
CERROR("client UUID must be less than 38 characters\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (LUSTRE_CFG_BUFLEN(lcfg, 2) < 1) {
CERROR("setup requires a SERVER UUID\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (LUSTRE_CFG_BUFLEN(lcfg, 2) > 37) {
CERROR("target UUID must be less than 38 characters\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
init_rwsem(&cli->cl_sem);
@@ -339,8 +335,8 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg)
cli->cl_avail_grant = 0;
/* FIXME: Should limit this for the sum of all cl_dirty_max. */
cli->cl_dirty_max = OSC_MAX_DIRTY_DEFAULT * 1024 * 1024;
- if (cli->cl_dirty_max >> PAGE_CACHE_SHIFT > num_physpages / 8)
- cli->cl_dirty_max = num_physpages << (PAGE_CACHE_SHIFT - 3);
+ if (cli->cl_dirty_max >> PAGE_CACHE_SHIFT > totalram_pages / 8)
+ cli->cl_dirty_max = totalram_pages << (PAGE_CACHE_SHIFT - 3);
INIT_LIST_HEAD(&cli->cl_cache_waiters);
INIT_LIST_HEAD(&cli->cl_loi_ready_list);
INIT_LIST_HEAD(&cli->cl_loi_hp_ready_list);
@@ -388,11 +384,11 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg)
if (!strcmp(name, LUSTRE_MDC_NAME)) {
cli->cl_max_rpcs_in_flight = MDC_MAX_RIF_DEFAULT;
- } else if (num_physpages >> (20 - PAGE_CACHE_SHIFT) <= 128 /* MB */) {
+ } else if (totalram_pages >> (20 - PAGE_CACHE_SHIFT) <= 128 /* MB */) {
cli->cl_max_rpcs_in_flight = 2;
- } else if (num_physpages >> (20 - PAGE_CACHE_SHIFT) <= 256 /* MB */) {
+ } else if (totalram_pages >> (20 - PAGE_CACHE_SHIFT) <= 256 /* MB */) {
cli->cl_max_rpcs_in_flight = 3;
- } else if (num_physpages >> (20 - PAGE_CACHE_SHIFT) <= 512 /* MB */) {
+ } else if (totalram_pages >> (20 - PAGE_CACHE_SHIFT) <= 512 /* MB */) {
cli->cl_max_rpcs_in_flight = 4;
} else {
if (osc_on_mdt(obddev->obd_name))
@@ -452,29 +448,27 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg)
cli->cl_qchk_stat = CL_NOT_QUOTACHECKED;
- RETURN(rc);
+ return rc;
err_import:
class_destroy_import(imp);
err_ldlm:
ldlm_put_ref();
err:
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(client_obd_setup);
int client_obd_cleanup(struct obd_device *obddev)
{
- ENTRY;
-
ldlm_namespace_free_post(obddev->obd_namespace);
obddev->obd_namespace = NULL;
LASSERT(obddev->u.cli.cl_import == NULL);
ldlm_put_ref();
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(client_obd_cleanup);
@@ -489,7 +483,6 @@ int client_connect_import(const struct lu_env *env,
struct obd_connect_data *ocd;
struct lustre_handle conn = { 0 };
int rc;
- ENTRY;
*exp = NULL;
down_write(&cli->cl_sem);
@@ -532,8 +525,6 @@ int client_connect_import(const struct lu_env *env,
ptlrpc_pinger_add_import(imp);
- EXIT;
-
if (rc) {
out_ldlm:
cli->cl_conn_count--;
@@ -553,12 +544,11 @@ int client_disconnect_export(struct obd_export *exp)
struct client_obd *cli;
struct obd_import *imp;
int rc = 0, err;
- ENTRY;
if (!obd) {
CERROR("invalid export for disconnect: exp %p cookie "LPX64"\n",
exp, exp ? exp->exp_handle.h_cookie : -1);
- RETURN(-EINVAL);
+ return -EINVAL;
}
cli = &obd->u.cli;
@@ -605,8 +595,6 @@ int client_disconnect_export(struct obd_export *exp)
ptlrpc_invalidate_import(imp);
- EXIT;
-
out_disconnect:
/* Use server style - class_disconnect should be always called for
* o_disconnect. */
@@ -616,7 +604,7 @@ out_disconnect:
up_write(&cli->cl_sem);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(client_disconnect_export);
@@ -627,7 +615,6 @@ EXPORT_SYMBOL(client_disconnect_export);
int target_pack_pool_reply(struct ptlrpc_request *req)
{
struct obd_device *obd;
- ENTRY;
/* Check that we still have all structures alive as this may
* be some late RPC at shutdown time. */
@@ -635,7 +622,7 @@ int target_pack_pool_reply(struct ptlrpc_request *req)
!exp_connect_lru_resize(req->rq_export))) {
lustre_msg_set_slv(req->rq_repmsg, 0);
lustre_msg_set_limit(req->rq_repmsg, 0);
- RETURN(0);
+ return 0;
}
/* OBD is alive here as export is alive, which we checked above. */
@@ -646,7 +633,7 @@ int target_pack_pool_reply(struct ptlrpc_request *req)
lustre_msg_set_limit(req->rq_repmsg, obd->obd_pool_limit);
read_unlock(&obd->obd_pool_lock);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(target_pack_pool_reply);
@@ -674,10 +661,8 @@ void target_send_reply(struct ptlrpc_request *req, int rc, int fail_id)
int netrc;
struct ptlrpc_reply_state *rs;
struct obd_export *exp;
- ENTRY;
if (req->rq_no_reply) {
- EXIT;
return;
}
@@ -686,7 +671,6 @@ void target_send_reply(struct ptlrpc_request *req, int rc, int fail_id)
if (rs == NULL || !rs->rs_difficult) {
/* no notifiers */
target_send_reply_msg (req, rc, fail_id);
- EXIT;
return;
}
@@ -757,19 +741,18 @@ void target_send_reply(struct ptlrpc_request *req, int rc, int fail_id)
}
spin_unlock(&rs->rs_lock);
spin_unlock(&svcpt->scp_rep_lock);
- EXIT;
}
EXPORT_SYMBOL(target_send_reply);
ldlm_mode_t lck_compat_array[] = {
- [LCK_EX] LCK_COMPAT_EX,
- [LCK_PW] LCK_COMPAT_PW,
- [LCK_PR] LCK_COMPAT_PR,
- [LCK_CW] LCK_COMPAT_CW,
- [LCK_CR] LCK_COMPAT_CR,
- [LCK_NL] LCK_COMPAT_NL,
- [LCK_GROUP] LCK_COMPAT_GROUP,
- [LCK_COS] LCK_COMPAT_COS,
+ [LCK_EX] = LCK_COMPAT_EX,
+ [LCK_PW] = LCK_COMPAT_PW,
+ [LCK_PR] = LCK_COMPAT_PR,
+ [LCK_CW] = LCK_COMPAT_CW,
+ [LCK_CR] = LCK_COMPAT_CR,
+ [LCK_NL] = LCK_COMPAT_NL,
+ [LCK_GROUP] = LCK_COMPAT_GROUP,
+ [LCK_COS] = LCK_COMPAT_COS,
};
/**
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
index 33b76a1e5de..6133b3f3471 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
@@ -49,45 +49,45 @@
/* lock types */
char *ldlm_lockname[] = {
- [0] "--",
- [LCK_EX] "EX",
- [LCK_PW] "PW",
- [LCK_PR] "PR",
- [LCK_CW] "CW",
- [LCK_CR] "CR",
- [LCK_NL] "NL",
- [LCK_GROUP] "GROUP",
- [LCK_COS] "COS"
+ [0] = "--",
+ [LCK_EX] = "EX",
+ [LCK_PW] = "PW",
+ [LCK_PR] = "PR",
+ [LCK_CW] = "CW",
+ [LCK_CR] = "CR",
+ [LCK_NL] = "NL",
+ [LCK_GROUP] = "GROUP",
+ [LCK_COS] = "COS",
};
EXPORT_SYMBOL(ldlm_lockname);
char *ldlm_typename[] = {
- [LDLM_PLAIN] "PLN",
- [LDLM_EXTENT] "EXT",
- [LDLM_FLOCK] "FLK",
- [LDLM_IBITS] "IBT",
+ [LDLM_PLAIN] = "PLN",
+ [LDLM_EXTENT] = "EXT",
+ [LDLM_FLOCK] = "FLK",
+ [LDLM_IBITS] = "IBT",
};
EXPORT_SYMBOL(ldlm_typename);
static ldlm_policy_wire_to_local_t ldlm_policy_wire18_to_local[] = {
- [LDLM_PLAIN - LDLM_MIN_TYPE] ldlm_plain_policy_wire_to_local,
- [LDLM_EXTENT - LDLM_MIN_TYPE] ldlm_extent_policy_wire_to_local,
- [LDLM_FLOCK - LDLM_MIN_TYPE] ldlm_flock_policy_wire18_to_local,
- [LDLM_IBITS - LDLM_MIN_TYPE] ldlm_ibits_policy_wire_to_local,
+ [LDLM_PLAIN - LDLM_MIN_TYPE] = ldlm_plain_policy_wire_to_local,
+ [LDLM_EXTENT - LDLM_MIN_TYPE] = ldlm_extent_policy_wire_to_local,
+ [LDLM_FLOCK - LDLM_MIN_TYPE] = ldlm_flock_policy_wire18_to_local,
+ [LDLM_IBITS - LDLM_MIN_TYPE] = ldlm_ibits_policy_wire_to_local,
};
static ldlm_policy_wire_to_local_t ldlm_policy_wire21_to_local[] = {
- [LDLM_PLAIN - LDLM_MIN_TYPE] ldlm_plain_policy_wire_to_local,
- [LDLM_EXTENT - LDLM_MIN_TYPE] ldlm_extent_policy_wire_to_local,
- [LDLM_FLOCK - LDLM_MIN_TYPE] ldlm_flock_policy_wire21_to_local,
- [LDLM_IBITS - LDLM_MIN_TYPE] ldlm_ibits_policy_wire_to_local,
+ [LDLM_PLAIN - LDLM_MIN_TYPE] = ldlm_plain_policy_wire_to_local,
+ [LDLM_EXTENT - LDLM_MIN_TYPE] = ldlm_extent_policy_wire_to_local,
+ [LDLM_FLOCK - LDLM_MIN_TYPE] = ldlm_flock_policy_wire21_to_local,
+ [LDLM_IBITS - LDLM_MIN_TYPE] = ldlm_ibits_policy_wire_to_local,
};
static ldlm_policy_local_to_wire_t ldlm_policy_local_to_wire[] = {
- [LDLM_PLAIN - LDLM_MIN_TYPE] ldlm_plain_policy_local_to_wire,
- [LDLM_EXTENT - LDLM_MIN_TYPE] ldlm_extent_policy_local_to_wire,
- [LDLM_FLOCK - LDLM_MIN_TYPE] ldlm_flock_policy_local_to_wire,
- [LDLM_IBITS - LDLM_MIN_TYPE] ldlm_ibits_policy_local_to_wire,
+ [LDLM_PLAIN - LDLM_MIN_TYPE] = ldlm_plain_policy_local_to_wire,
+ [LDLM_EXTENT - LDLM_MIN_TYPE] = ldlm_extent_policy_local_to_wire,
+ [LDLM_FLOCK - LDLM_MIN_TYPE] = ldlm_flock_policy_local_to_wire,
+ [LDLM_IBITS - LDLM_MIN_TYPE] = ldlm_ibits_policy_local_to_wire,
};
/**
@@ -188,8 +188,6 @@ EXPORT_SYMBOL(ldlm_lock_get);
*/
void ldlm_lock_put(struct ldlm_lock *lock)
{
- ENTRY;
-
LASSERT(lock->l_resource != LP_POISON);
LASSERT(atomic_read(&lock->l_refc) > 0);
if (atomic_dec_and_test(&lock->l_refc)) {
@@ -199,7 +197,7 @@ void ldlm_lock_put(struct ldlm_lock *lock)
"final lock_put on destroyed lock, freeing it.");
res = lock->l_resource;
- LASSERT(lock->l_destroyed);
+ LASSERT(lock->l_flags & LDLM_FL_DESTROYED);
LASSERT(list_empty(&lock->l_res_link));
LASSERT(list_empty(&lock->l_pending_chain));
@@ -220,8 +218,6 @@ void ldlm_lock_put(struct ldlm_lock *lock)
lu_ref_fini(&lock->l_reference);
OBD_FREE_RCU(lock, sizeof(*lock), &lock->l_handle);
}
-
- EXIT;
}
EXPORT_SYMBOL(ldlm_lock_put);
@@ -253,16 +249,14 @@ int ldlm_lock_remove_from_lru(struct ldlm_lock *lock)
struct ldlm_namespace *ns = ldlm_lock_to_ns(lock);
int rc;
- ENTRY;
- if (lock->l_ns_srv) {
+ if (lock->l_flags & LDLM_FL_NS_SRV) {
LASSERT(list_empty(&lock->l_lru));
- RETURN(0);
+ return 0;
}
spin_lock(&ns->ns_lock);
rc = ldlm_lock_remove_from_lru_nolock(lock);
spin_unlock(&ns->ns_lock);
- EXIT;
return rc;
}
@@ -289,11 +283,9 @@ void ldlm_lock_add_to_lru(struct ldlm_lock *lock)
{
struct ldlm_namespace *ns = ldlm_lock_to_ns(lock);
- ENTRY;
spin_lock(&ns->ns_lock);
ldlm_lock_add_to_lru_nolock(lock);
spin_unlock(&ns->ns_lock);
- EXIT;
}
/**
@@ -304,10 +296,8 @@ void ldlm_lock_touch_in_lru(struct ldlm_lock *lock)
{
struct ldlm_namespace *ns = ldlm_lock_to_ns(lock);
- ENTRY;
- if (lock->l_ns_srv) {
+ if (lock->l_flags & LDLM_FL_NS_SRV) {
LASSERT(list_empty(&lock->l_lru));
- EXIT;
return;
}
@@ -317,7 +307,6 @@ void ldlm_lock_touch_in_lru(struct ldlm_lock *lock)
ldlm_lock_add_to_lru_nolock(lock);
}
spin_unlock(&ns->ns_lock);
- EXIT;
}
/**
@@ -341,8 +330,6 @@ void ldlm_lock_touch_in_lru(struct ldlm_lock *lock)
*/
int ldlm_lock_destroy_internal(struct ldlm_lock *lock)
{
- ENTRY;
-
if (lock->l_readers || lock->l_writers) {
LDLM_ERROR(lock, "lock still has references");
LBUG();
@@ -353,12 +340,11 @@ int ldlm_lock_destroy_internal(struct ldlm_lock *lock)
LBUG();
}
- if (lock->l_destroyed) {
+ if (lock->l_flags & LDLM_FL_DESTROYED) {
LASSERT(list_empty(&lock->l_lru));
- EXIT;
return 0;
}
- lock->l_destroyed = 1;
+ lock->l_flags |= LDLM_FL_DESTROYED;
if (lock->l_export && lock->l_export->exp_lock_hash) {
/* NB: it's safe to call cfs_hash_del() even lock isn't
@@ -383,7 +369,6 @@ int ldlm_lock_destroy_internal(struct ldlm_lock *lock)
if (lock->l_export && lock->l_completion_ast)
lock->l_completion_ast(lock, 0);
#endif
- EXIT;
return 1;
}
@@ -393,7 +378,7 @@ int ldlm_lock_destroy_internal(struct ldlm_lock *lock)
void ldlm_lock_destroy(struct ldlm_lock *lock)
{
int first;
- ENTRY;
+
lock_res_and_lock(lock);
first = ldlm_lock_destroy_internal(lock);
unlock_res_and_lock(lock);
@@ -403,7 +388,6 @@ void ldlm_lock_destroy(struct ldlm_lock *lock)
lu_ref_del(&lock->l_reference, "hash", lock);
LDLM_LOCK_RELEASE(lock);
}
- EXIT;
}
/**
@@ -412,14 +396,13 @@ void ldlm_lock_destroy(struct ldlm_lock *lock)
void ldlm_lock_destroy_nolock(struct ldlm_lock *lock)
{
int first;
- ENTRY;
+
first = ldlm_lock_destroy_internal(lock);
/* drop reference from hashtable only for first destroy */
if (first) {
lu_ref_del(&lock->l_reference, "hash", lock);
LDLM_LOCK_RELEASE(lock);
}
- EXIT;
}
/* this is called by portals_handle2object with the handle lock taken */
@@ -450,14 +433,13 @@ struct portals_handle_ops lock_handle_ops = {
static struct ldlm_lock *ldlm_lock_new(struct ldlm_resource *resource)
{
struct ldlm_lock *lock;
- ENTRY;
if (resource == NULL)
LBUG();
OBD_SLAB_ALLOC_PTR_GFP(lock, ldlm_lock_slab, __GFP_IO);
if (lock == NULL)
- RETURN(NULL);
+ return NULL;
spin_lock_init(&lock->l_lock);
lock->l_resource = resource;
@@ -493,7 +475,7 @@ static struct ldlm_lock *ldlm_lock_new(struct ldlm_resource *resource)
#endif
INIT_LIST_HEAD(&lock->l_exp_list);
- RETURN(lock);
+ return lock;
}
/**
@@ -507,7 +489,6 @@ int ldlm_lock_change_resource(struct ldlm_namespace *ns, struct ldlm_lock *lock,
struct ldlm_resource *oldres = lock->l_resource;
struct ldlm_resource *newres;
int type;
- ENTRY;
LASSERT(ns_is_client(ns));
@@ -516,7 +497,7 @@ int ldlm_lock_change_resource(struct ldlm_namespace *ns, struct ldlm_lock *lock,
sizeof(lock->l_resource->lr_name)) == 0) {
/* Nothing to do */
unlock_res_and_lock(lock);
- RETURN(0);
+ return 0;
}
LASSERT(new_resid->name[0] != 0);
@@ -529,7 +510,7 @@ int ldlm_lock_change_resource(struct ldlm_namespace *ns, struct ldlm_lock *lock,
newres = ldlm_resource_get(ns, NULL, new_resid, type, 1);
if (newres == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lu_ref_add(&newres->lr_reference, "lock", lock);
/*
@@ -557,7 +538,7 @@ int ldlm_lock_change_resource(struct ldlm_namespace *ns, struct ldlm_lock *lock,
lu_ref_del(&oldres->lr_reference, "lock", lock);
ldlm_resource_putref(oldres);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_lock_change_resource);
@@ -586,19 +567,18 @@ struct ldlm_lock *__ldlm_handle2lock(const struct lustre_handle *handle,
__u64 flags)
{
struct ldlm_lock *lock;
- ENTRY;
LASSERT(handle);
lock = class_handle2object(handle->cookie);
if (lock == NULL)
- RETURN(NULL);
+ return NULL;
/* It's unlikely but possible that someone marked the lock as
* destroyed after we did handle2object on it */
- if (flags == 0 && !lock->l_destroyed) {
+ if (flags == 0 && ((lock->l_flags & LDLM_FL_DESTROYED)== 0)) {
lu_ref_add(&lock->l_reference, "handle", current);
- RETURN(lock);
+ return lock;
}
lock_res_and_lock(lock);
@@ -606,24 +586,24 @@ struct ldlm_lock *__ldlm_handle2lock(const struct lustre_handle *handle,
LASSERT(lock->l_resource != NULL);
lu_ref_add_atomic(&lock->l_reference, "handle", current);
- if (unlikely(lock->l_destroyed)) {
+ if (unlikely(lock->l_flags & LDLM_FL_DESTROYED)) {
unlock_res_and_lock(lock);
CDEBUG(D_INFO, "lock already destroyed: lock %p\n", lock);
LDLM_LOCK_PUT(lock);
- RETURN(NULL);
+ return NULL;
}
if (flags && (lock->l_flags & flags)) {
unlock_res_and_lock(lock);
LDLM_LOCK_PUT(lock);
- RETURN(NULL);
+ return NULL;
}
if (flags)
lock->l_flags |= flags;
unlock_res_and_lock(lock);
- RETURN(lock);
+ return lock;
}
EXPORT_SYMBOL(__ldlm_handle2lock);
/** @} ldlm_handles */
@@ -695,7 +675,7 @@ void ldlm_add_bl_work_item(struct ldlm_lock *lock, struct ldlm_lock *new,
lock->l_flags |= LDLM_FL_AST_SENT;
/* If the enqueuing client said so, tell the AST recipient to
* discard dirty data, rather than writing back. */
- if (new->l_flags & LDLM_AST_DISCARD_DATA)
+ if (new->l_flags & LDLM_FL_AST_DISCARD_DATA)
lock->l_flags |= LDLM_FL_DISCARD_DATA;
LASSERT(list_empty(&lock->l_bl_ast));
list_add(&lock->l_bl_ast, work_list);
@@ -728,13 +708,11 @@ void ldlm_add_cp_work_item(struct ldlm_lock *lock, struct list_head *work_list)
void ldlm_add_ast_work_item(struct ldlm_lock *lock, struct ldlm_lock *new,
struct list_head *work_list)
{
- ENTRY;
check_res_locked(lock->l_resource);
if (new)
ldlm_add_bl_work_item(lock, new, work_list);
else
ldlm_add_cp_work_item(lock, work_list);
- EXIT;
}
/**
@@ -853,7 +831,6 @@ void ldlm_lock_decref_internal_nolock(struct ldlm_lock *lock, __u32 mode)
void ldlm_lock_decref_internal(struct ldlm_lock *lock, __u32 mode)
{
struct ldlm_namespace *ns;
- ENTRY;
lock_res_and_lock(lock);
@@ -873,7 +850,7 @@ void ldlm_lock_decref_internal(struct ldlm_lock *lock, __u32 mode)
(lock->l_flags & LDLM_FL_CBPENDING)) {
/* If we received a blocked AST and this was the last reference,
* run the callback. */
- if (lock->l_ns_srv && lock->l_export)
+ if ((lock->l_flags & LDLM_FL_NS_SRV) && lock->l_export)
CERROR("FL_CBPENDING set on non-local lock--just a "
"warning\n");
@@ -914,8 +891,6 @@ void ldlm_lock_decref_internal(struct ldlm_lock *lock, __u32 mode)
LDLM_DEBUG(lock, "do not add lock into lru list");
unlock_res_and_lock(lock);
}
-
- EXIT;
}
/**
@@ -940,7 +915,6 @@ EXPORT_SYMBOL(ldlm_lock_decref);
void ldlm_lock_decref_and_cancel(struct lustre_handle *lockh, __u32 mode)
{
struct ldlm_lock *lock = __ldlm_handle2lock(lockh, 0);
- ENTRY;
LASSERT(lock != NULL);
@@ -979,7 +953,6 @@ static void search_granted_lock(struct list_head *queue,
{
struct list_head *tmp;
struct ldlm_lock *lock, *mode_end, *policy_end;
- ENTRY;
list_for_each(tmp, queue) {
lock = list_entry(tmp, struct ldlm_lock, l_res_link);
@@ -999,7 +972,6 @@ static void search_granted_lock(struct list_head *queue,
prev->res_link = &mode_end->l_res_link;
prev->mode_link = &mode_end->l_sl_mode;
prev->policy_link = &req->l_sl_policy;
- EXIT;
return;
} else if (lock->l_resource->lr_type == LDLM_IBITS) {
for (;;) {
@@ -1018,7 +990,6 @@ static void search_granted_lock(struct list_head *queue,
&policy_end->l_sl_mode;
prev->policy_link =
&policy_end->l_sl_policy;
- EXIT;
return;
}
@@ -1037,7 +1008,6 @@ static void search_granted_lock(struct list_head *queue,
prev->res_link = &mode_end->l_res_link;
prev->mode_link = &mode_end->l_sl_mode;
prev->policy_link = &req->l_sl_policy;
- EXIT;
return;
} else {
LDLM_ERROR(lock,"is not LDLM_PLAIN or LDLM_IBITS lock");
@@ -1050,7 +1020,6 @@ static void search_granted_lock(struct list_head *queue,
prev->res_link = queue->prev;
prev->mode_link = &req->l_sl_mode;
prev->policy_link = &req->l_sl_policy;
- EXIT;
return;
}
@@ -1062,14 +1031,13 @@ static void ldlm_granted_list_add_lock(struct ldlm_lock *lock,
struct sl_insert_point *prev)
{
struct ldlm_resource *res = lock->l_resource;
- ENTRY;
check_res_locked(res);
ldlm_resource_dump(D_INFO, res);
LDLM_DEBUG(lock, "About to add lock:");
- if (lock->l_destroyed) {
+ if (lock->l_flags & LDLM_FL_DESTROYED) {
CDEBUG(D_OTHER, "Lock destroyed, not adding to resource\n");
return;
}
@@ -1088,8 +1056,6 @@ static void ldlm_granted_list_add_lock(struct ldlm_lock *lock,
list_add(&lock->l_sl_mode, prev->mode_link);
if (&lock->l_sl_policy != prev->policy_link)
list_add(&lock->l_sl_policy, prev->policy_link);
-
- EXIT;
}
/**
@@ -1099,13 +1065,11 @@ static void ldlm_granted_list_add_lock(struct ldlm_lock *lock,
static void ldlm_grant_lock_with_skiplist(struct ldlm_lock *lock)
{
struct sl_insert_point prev;
- ENTRY;
LASSERT(lock->l_req_mode == lock->l_granted_mode);
search_granted_lock(&lock->l_resource->lr_granted, lock, &prev);
ldlm_granted_list_add_lock(lock, &prev);
- EXIT;
}
/**
@@ -1122,7 +1086,6 @@ static void ldlm_grant_lock_with_skiplist(struct ldlm_lock *lock)
void ldlm_grant_lock(struct ldlm_lock *lock, struct list_head *work_list)
{
struct ldlm_resource *res = lock->l_resource;
- ENTRY;
check_res_locked(res);
@@ -1141,7 +1104,6 @@ void ldlm_grant_lock(struct ldlm_lock *lock, struct list_head *work_list)
ldlm_add_ast_work_item(lock, NULL, work_list);
ldlm_pool_add(&ldlm_res_to_ns(res)->ns_pool, lock);
- EXIT;
}
/**
@@ -1203,9 +1165,7 @@ static struct ldlm_lock *search_queue(struct list_head *queue,
policy->l_inodebits.bits))
continue;
- if (!unref &&
- (lock->l_destroyed || lock->l_flags & LDLM_FL_FAILED ||
- lock->l_failed))
+ if (!unref && (lock->l_flags & LDLM_FL_GONE_MASK))
continue;
if ((flags & LDLM_FL_LOCAL_ONLY) &&
@@ -1227,8 +1187,8 @@ static struct ldlm_lock *search_queue(struct list_head *queue,
void ldlm_lock_fail_match_locked(struct ldlm_lock *lock)
{
- if (!lock->l_failed) {
- lock->l_failed = 1;
+ if ((lock->l_flags & LDLM_FL_FAIL_NOTIFIED) == 0) {
+ lock->l_flags |= LDLM_FL_FAIL_NOTIFIED;
wake_up_all(&lock->l_waitq);
}
}
@@ -1306,7 +1266,6 @@ ldlm_mode_t ldlm_lock_match(struct ldlm_namespace *ns, __u64 flags,
struct ldlm_resource *res;
struct ldlm_lock *lock, *old_lock = NULL;
int rc = 0;
- ENTRY;
if (ns == NULL) {
old_lock = ldlm_handle2lock(lockh);
@@ -1321,7 +1280,7 @@ ldlm_mode_t ldlm_lock_match(struct ldlm_namespace *ns, __u64 flags,
res = ldlm_resource_get(ns, NULL, res_id, type, 0);
if (res == NULL) {
LASSERT(old_lock == NULL);
- RETURN(0);
+ return 0;
}
LDLM_RESOURCE_ADDREF(res);
@@ -1342,7 +1301,6 @@ ldlm_mode_t ldlm_lock_match(struct ldlm_namespace *ns, __u64 flags,
if (lock != NULL)
GOTO(out, rc = 1);
- EXIT;
out:
unlock_res(res);
LDLM_RESOURCE_DELREF(res);
@@ -1352,6 +1310,8 @@ ldlm_mode_t ldlm_lock_match(struct ldlm_namespace *ns, __u64 flags,
ldlm_lock2handle(lock, lockh);
if ((flags & LDLM_FL_LVB_READY) &&
(!(lock->l_flags & LDLM_FL_LVB_READY))) {
+ __u64 wait_flags = LDLM_FL_LVB_READY |
+ LDLM_FL_DESTROYED | LDLM_FL_FAIL_NOTIFIED;
struct l_wait_info lwi;
if (lock->l_completion_ast) {
int err = lock->l_completion_ast(lock,
@@ -1373,8 +1333,7 @@ ldlm_mode_t ldlm_lock_match(struct ldlm_namespace *ns, __u64 flags,
/* XXX FIXME see comment on CAN_MATCH in lustre_dlm.h */
l_wait_event(lock->l_waitq,
- lock->l_flags & LDLM_FL_LVB_READY ||
- lock->l_destroyed || lock->l_failed,
+ lock->l_flags & wait_flags,
&lwi);
if (!(lock->l_flags & LDLM_FL_LVB_READY)) {
if (flags & LDLM_FL_TEST_LOCK)
@@ -1426,13 +1385,11 @@ ldlm_mode_t ldlm_revalidate_lock_handle(struct lustre_handle *lockh,
{
struct ldlm_lock *lock;
ldlm_mode_t mode = 0;
- ENTRY;
lock = ldlm_handle2lock(lockh);
if (lock != NULL) {
lock_res_and_lock(lock);
- if (lock->l_destroyed || lock->l_flags & LDLM_FL_FAILED ||
- lock->l_failed)
+ if (lock->l_flags & LDLM_FL_GONE_MASK)
GOTO(out, mode);
if (lock->l_flags & LDLM_FL_CBPENDING &&
@@ -1445,8 +1402,6 @@ ldlm_mode_t ldlm_revalidate_lock_handle(struct lustre_handle *lockh,
ldlm_lock_addref_internal_nolock(lock, mode);
}
- EXIT;
-
out:
if (lock != NULL) {
unlock_res_and_lock(lock);
@@ -1461,7 +1416,6 @@ int ldlm_fill_lvb(struct ldlm_lock *lock, struct req_capsule *pill,
enum req_location loc, void *data, int size)
{
void *lvb;
- ENTRY;
LASSERT(data != NULL);
LASSERT(size >= 0);
@@ -1479,7 +1433,7 @@ int ldlm_fill_lvb(struct ldlm_lock *lock, struct req_capsule *pill,
lustre_swab_ost_lvb);
if (unlikely(lvb == NULL)) {
LDLM_ERROR(lock, "no LVB");
- RETURN(-EPROTO);
+ return -EPROTO;
}
memcpy(data, lvb, size);
@@ -1496,7 +1450,7 @@ int ldlm_fill_lvb(struct ldlm_lock *lock, struct req_capsule *pill,
lustre_swab_ost_lvb_v1);
if (unlikely(lvb == NULL)) {
LDLM_ERROR(lock, "no LVB");
- RETURN(-EPROTO);
+ return -EPROTO;
}
memcpy(data, lvb, size);
@@ -1506,7 +1460,7 @@ int ldlm_fill_lvb(struct ldlm_lock *lock, struct req_capsule *pill,
} else {
LDLM_ERROR(lock, "Replied unexpected ost LVB size %d",
size);
- RETURN(-EINVAL);
+ return -EINVAL;
}
break;
case LVB_T_LQUOTA:
@@ -1521,14 +1475,14 @@ int ldlm_fill_lvb(struct ldlm_lock *lock, struct req_capsule *pill,
lustre_swab_lquota_lvb);
if (unlikely(lvb == NULL)) {
LDLM_ERROR(lock, "no LVB");
- RETURN(-EPROTO);
+ return -EPROTO;
}
memcpy(data, lvb, size);
} else {
LDLM_ERROR(lock, "Replied unexpected lquota LVB size %d",
size);
- RETURN(-EINVAL);
+ return -EINVAL;
}
break;
case LVB_T_LAYOUT:
@@ -1541,18 +1495,18 @@ int ldlm_fill_lvb(struct ldlm_lock *lock, struct req_capsule *pill,
lvb = req_capsule_server_get(pill, &RMF_DLM_LVB);
if (unlikely(lvb == NULL)) {
LDLM_ERROR(lock, "no LVB");
- RETURN(-EPROTO);
+ return -EPROTO;
}
memcpy(data, lvb, size);
break;
default:
LDLM_ERROR(lock, "Unknown LVB type: %d\n", lock->l_lvb_type);
- libcfs_debug_dumpstack(NULL);
- RETURN(-EINVAL);
+ dump_stack();
+ return -EINVAL;
}
- RETURN(0);
+ return 0;
}
/**
@@ -1569,26 +1523,25 @@ struct ldlm_lock *ldlm_lock_create(struct ldlm_namespace *ns,
{
struct ldlm_lock *lock;
struct ldlm_resource *res;
- ENTRY;
res = ldlm_resource_get(ns, NULL, res_id, type, 1);
if (res == NULL)
- RETURN(NULL);
+ return NULL;
lock = ldlm_lock_new(res);
if (lock == NULL)
- RETURN(NULL);
+ return NULL;
lock->l_req_mode = mode;
lock->l_ast_data = data;
lock->l_pid = current_pid();
- lock->l_ns_srv = !!ns_is_server(ns);
+ if (ns_is_server(ns))
+ lock->l_flags |= LDLM_FL_NS_SRV;
if (cbs) {
lock->l_blocking_ast = cbs->lcs_blocking;
lock->l_completion_ast = cbs->lcs_completion;
lock->l_glimpse_ast = cbs->lcs_glimpse;
- lock->l_weigh_ast = cbs->lcs_weigh;
}
lock->l_tree_node = NULL;
@@ -1609,7 +1562,7 @@ struct ldlm_lock *ldlm_lock_create(struct ldlm_namespace *ns,
if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_NEW_LOCK))
GOTO(out, 0);
- RETURN(lock);
+ return lock;
out:
ldlm_lock_destroy(lock);
@@ -1636,7 +1589,6 @@ ldlm_error_t ldlm_lock_enqueue(struct ldlm_namespace *ns,
int local = ns_is_client(ldlm_res_to_ns(res));
ldlm_error_t rc = ELDLM_OK;
struct ldlm_interval *node = NULL;
- ENTRY;
lock->l_last_activity = cfs_time_current_sec();
/* policies are not executed on the client or during replay */
@@ -1654,11 +1606,11 @@ ldlm_error_t ldlm_lock_enqueue(struct ldlm_namespace *ns,
LDLM_LOCK_RELEASE(lock);
}
*flags |= LDLM_FL_LOCK_CHANGED;
- RETURN(0);
+ return 0;
} else if (rc != ELDLM_OK ||
(rc == ELDLM_OK && (*flags & LDLM_FL_INTENT_ONLY))) {
ldlm_lock_destroy(lock);
- RETURN(rc);
+ return rc;
}
}
@@ -1693,7 +1645,7 @@ ldlm_error_t ldlm_lock_enqueue(struct ldlm_namespace *ns,
/* Some flags from the enqueue want to make it into the AST, via the
* lock's l_flags. */
- lock->l_flags |= *flags & LDLM_AST_DISCARD_DATA;
+ lock->l_flags |= *flags & LDLM_FL_AST_DISCARD_DATA;
/* This distinction between local lock trees is very important; a client
* namespace only has information about locks taken by that client, and
@@ -1738,10 +1690,9 @@ ldlm_work_bl_ast_lock(struct ptlrpc_request_set *rqset, void *opaq)
struct ldlm_lock_desc d;
int rc;
struct ldlm_lock *lock;
- ENTRY;
if (list_empty(arg->list))
- RETURN(-ENOENT);
+ return -ENOENT;
lock = list_entry(arg->list->next, struct ldlm_lock, l_bl_ast);
@@ -1762,7 +1713,7 @@ ldlm_work_bl_ast_lock(struct ptlrpc_request_set *rqset, void *opaq)
lock->l_blocking_lock = NULL;
LDLM_LOCK_RELEASE(lock);
- RETURN(rc);
+ return rc;
}
/**
@@ -1775,10 +1726,9 @@ ldlm_work_cp_ast_lock(struct ptlrpc_request_set *rqset, void *opaq)
int rc = 0;
struct ldlm_lock *lock;
ldlm_completion_callback completion_callback;
- ENTRY;
if (list_empty(arg->list))
- RETURN(-ENOENT);
+ return -ENOENT;
lock = list_entry(arg->list->next, struct ldlm_lock, l_cp_ast);
@@ -1807,7 +1757,7 @@ ldlm_work_cp_ast_lock(struct ptlrpc_request_set *rqset, void *opaq)
rc = completion_callback(lock, 0, (void *)arg);
LDLM_LOCK_RELEASE(lock);
- RETURN(rc);
+ return rc;
}
/**
@@ -1820,10 +1770,9 @@ ldlm_work_revoke_ast_lock(struct ptlrpc_request_set *rqset, void *opaq)
struct ldlm_lock_desc desc;
int rc;
struct ldlm_lock *lock;
- ENTRY;
if (list_empty(arg->list))
- RETURN(-ENOENT);
+ return -ENOENT;
lock = list_entry(arg->list->next, struct ldlm_lock, l_rk_ast);
list_del_init(&lock->l_rk_ast);
@@ -1836,7 +1785,7 @@ ldlm_work_revoke_ast_lock(struct ptlrpc_request_set *rqset, void *opaq)
rc = lock->l_blocking_ast(lock, &desc, (void*)arg, LDLM_CB_BLOCKING);
LDLM_LOCK_RELEASE(lock);
- RETURN(rc);
+ return rc;
}
/**
@@ -1848,10 +1797,9 @@ int ldlm_work_gl_ast_lock(struct ptlrpc_request_set *rqset, void *opaq)
struct ldlm_glimpse_work *gl_work;
struct ldlm_lock *lock;
int rc = 0;
- ENTRY;
if (list_empty(arg->list))
- RETURN(-ENOENT);
+ return -ENOENT;
gl_work = list_entry(arg->list->next, struct ldlm_glimpse_work,
gl_list);
@@ -1871,7 +1819,7 @@ int ldlm_work_gl_ast_lock(struct ptlrpc_request_set *rqset, void *opaq)
if ((gl_work->gl_flags & LDLM_GL_WORK_NOFREE) == 0)
OBD_FREE_PTR(gl_work);
- RETURN(rc);
+ return rc;
}
/**
@@ -1888,11 +1836,11 @@ int ldlm_run_ast_work(struct ldlm_namespace *ns, struct list_head *rpc_list,
int rc;
if (list_empty(rpc_list))
- RETURN(0);
+ return 0;
OBD_ALLOC_PTR(arg);
if (arg == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
atomic_set(&arg->restart, 0);
arg->list = rpc_list;
@@ -1960,13 +1908,10 @@ static int ldlm_reprocess_res(cfs_hash_t *hs, cfs_hash_bd_t *bd,
*/
void ldlm_reprocess_all_ns(struct ldlm_namespace *ns)
{
- ENTRY;
-
if (ns != NULL) {
cfs_hash_for_each_nolock(ns->ns_rs_hash,
ldlm_reprocess_res, NULL);
}
- EXIT;
}
EXPORT_SYMBOL(ldlm_reprocess_all_ns);
@@ -1982,13 +1927,11 @@ void ldlm_reprocess_all(struct ldlm_resource *res)
{
LIST_HEAD(rpc_list);
- ENTRY;
if (!ns_is_client(ldlm_res_to_ns(res))) {
CERROR("This is client-side-only module, cannot handle "
"LDLM_NAMESPACE_SERVER resource type lock.\n");
LBUG();
}
- EXIT;
}
/**
@@ -2032,7 +1975,6 @@ void ldlm_lock_cancel(struct ldlm_lock *lock)
{
struct ldlm_resource *res;
struct ldlm_namespace *ns;
- ENTRY;
lock_res_and_lock(lock);
@@ -2046,15 +1988,15 @@ void ldlm_lock_cancel(struct ldlm_lock *lock)
LBUG();
}
- if (lock->l_waited)
+ if (lock->l_flags & LDLM_FL_WAITED)
ldlm_del_waiting_lock(lock);
/* Releases cancel callback. */
ldlm_cancel_callback(lock);
/* Yes, second time, just in case it was added again while we were
- running with no res lock in ldlm_cancel_callback */
- if (lock->l_waited)
+ * running with no res lock in ldlm_cancel_callback */
+ if (lock->l_flags & LDLM_FL_WAITED)
ldlm_del_waiting_lock(lock);
ldlm_resource_unlink_lock(lock);
@@ -2067,8 +2009,6 @@ void ldlm_lock_cancel(struct ldlm_lock *lock)
* if not to zero out lock->l_granted_mode */
lock->l_granted_mode = LCK_MINMODE;
unlock_res_and_lock(lock);
-
- EXIT;
}
EXPORT_SYMBOL(ldlm_lock_cancel);
@@ -2079,7 +2019,6 @@ int ldlm_lock_set_data(struct lustre_handle *lockh, void *data)
{
struct ldlm_lock *lock = ldlm_handle2lock(lockh);
int rc = -EINVAL;
- ENTRY;
if (lock) {
if (lock->l_ast_data == NULL)
@@ -2088,7 +2027,7 @@ int ldlm_lock_set_data(struct lustre_handle *lockh, void *data)
rc = 0;
LDLM_LOCK_PUT(lock);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ldlm_lock_set_data);
@@ -2160,8 +2099,6 @@ void ldlm_cancel_locks_for_export(struct obd_export *exp)
*/
void ldlm_lock_downgrade(struct ldlm_lock *lock, int new_mode)
{
- ENTRY;
-
LASSERT(lock->l_granted_mode & (LCK_PW | LCK_EX));
LASSERT(new_mode == LCK_COS);
@@ -2177,8 +2114,6 @@ void ldlm_lock_downgrade(struct ldlm_lock *lock, int new_mode)
ldlm_grant_lock(lock, NULL);
unlock_res_and_lock(lock);
ldlm_reprocess_all(lock->l_resource);
-
- EXIT;
}
EXPORT_SYMBOL(ldlm_lock_downgrade);
@@ -2197,19 +2132,19 @@ struct ldlm_resource *ldlm_lock_convert(struct ldlm_lock *lock, int new_mode,
struct ldlm_namespace *ns;
int granted = 0;
struct ldlm_interval *node;
- ENTRY;
/* Just return if mode is unchanged. */
if (new_mode == lock->l_granted_mode) {
*flags |= LDLM_FL_BLOCK_GRANTED;
- RETURN(lock->l_resource);
+ return lock->l_resource;
}
/* I can't check the type of lock here because the bitlock of lock
* is not held here, so do the allocation blindly. -jay */
OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, __GFP_IO);
- if (node == NULL) /* Actually, this causes EDEADLOCK to be returned */
- RETURN(NULL);
+ if (node == NULL)
+ /* Actually, this causes EDEADLOCK to be returned */
+ return NULL;
LASSERTF((new_mode == LCK_PW && lock->l_granted_mode == LCK_PR),
"new_mode %u, granted %u\n", new_mode, lock->l_granted_mode);
@@ -2268,7 +2203,7 @@ struct ldlm_resource *ldlm_lock_convert(struct ldlm_lock *lock, int new_mode,
ldlm_run_ast_work(ns, &rpc_list, LDLM_WORK_CP_AST);
if (node)
OBD_SLAB_FREE(node, ldlm_interval_slab, sizeof(*node));
- RETURN(res);
+ return res;
}
EXPORT_SYMBOL(ldlm_lock_convert);
@@ -2337,91 +2272,90 @@ void _ldlm_lock_debug(struct ldlm_lock *lock,
switch (resource->lr_type) {
case LDLM_EXTENT:
libcfs_debug_vmsg2(msgdata, fmt, args,
- " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
- "res: "LPU64"/"LPU64" rrc: %d type: %s ["LPU64"->"LPU64
- "] (req "LPU64"->"LPU64") flags: "LPX64" nid: %s remote:"
- " "LPX64" expref: %d pid: %u timeout: %lu lvb_type: %d\n",
- ldlm_lock_to_ns_name(lock), lock,
- lock->l_handle.h_cookie, atomic_read(&lock->l_refc),
- lock->l_readers, lock->l_writers,
- ldlm_lockname[lock->l_granted_mode],
- ldlm_lockname[lock->l_req_mode],
- resource->lr_name.name[0],
- resource->lr_name.name[1],
- atomic_read(&resource->lr_refcount),
- ldlm_typename[resource->lr_type],
- lock->l_policy_data.l_extent.start,
- lock->l_policy_data.l_extent.end,
- lock->l_req_extent.start, lock->l_req_extent.end,
- lock->l_flags, nid, lock->l_remote_handle.cookie,
- exp ? atomic_read(&exp->exp_refcount) : -99,
- lock->l_pid, lock->l_callback_timeout, lock->l_lvb_type);
+ " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
+ "res: "DLDLMRES" rrc: %d type: %s ["LPU64"->"LPU64"] "
+ "(req "LPU64"->"LPU64") flags: "LPX64" nid: %s remote: "
+ LPX64" expref: %d pid: %u timeout: %lu lvb_type: %d\n",
+ ldlm_lock_to_ns_name(lock), lock,
+ lock->l_handle.h_cookie, atomic_read(&lock->l_refc),
+ lock->l_readers, lock->l_writers,
+ ldlm_lockname[lock->l_granted_mode],
+ ldlm_lockname[lock->l_req_mode],
+ PLDLMRES(resource),
+ atomic_read(&resource->lr_refcount),
+ ldlm_typename[resource->lr_type],
+ lock->l_policy_data.l_extent.start,
+ lock->l_policy_data.l_extent.end,
+ lock->l_req_extent.start, lock->l_req_extent.end,
+ lock->l_flags, nid, lock->l_remote_handle.cookie,
+ exp ? atomic_read(&exp->exp_refcount) : -99,
+ lock->l_pid, lock->l_callback_timeout,
+ lock->l_lvb_type);
break;
case LDLM_FLOCK:
libcfs_debug_vmsg2(msgdata, fmt, args,
- " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
- "res: "LPU64"/"LPU64" rrc: %d type: %s pid: %d "
- "["LPU64"->"LPU64"] flags: "LPX64" nid: %s remote: "LPX64
- " expref: %d pid: %u timeout: %lu\n",
- ldlm_lock_to_ns_name(lock), lock,
- lock->l_handle.h_cookie, atomic_read(&lock->l_refc),
- lock->l_readers, lock->l_writers,
- ldlm_lockname[lock->l_granted_mode],
- ldlm_lockname[lock->l_req_mode],
- resource->lr_name.name[0],
- resource->lr_name.name[1],
- atomic_read(&resource->lr_refcount),
- ldlm_typename[resource->lr_type],
- lock->l_policy_data.l_flock.pid,
- lock->l_policy_data.l_flock.start,
- lock->l_policy_data.l_flock.end,
- lock->l_flags, nid, lock->l_remote_handle.cookie,
- exp ? atomic_read(&exp->exp_refcount) : -99,
- lock->l_pid, lock->l_callback_timeout);
+ " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
+ "res: "DLDLMRES" rrc: %d type: %s pid: %d "
+ "["LPU64"->"LPU64"] flags: "LPX64" nid: %s "
+ "remote: "LPX64" expref: %d pid: %u timeout: %lu\n",
+ ldlm_lock_to_ns_name(lock), lock,
+ lock->l_handle.h_cookie, atomic_read(&lock->l_refc),
+ lock->l_readers, lock->l_writers,
+ ldlm_lockname[lock->l_granted_mode],
+ ldlm_lockname[lock->l_req_mode],
+ PLDLMRES(resource),
+ atomic_read(&resource->lr_refcount),
+ ldlm_typename[resource->lr_type],
+ lock->l_policy_data.l_flock.pid,
+ lock->l_policy_data.l_flock.start,
+ lock->l_policy_data.l_flock.end,
+ lock->l_flags, nid, lock->l_remote_handle.cookie,
+ exp ? atomic_read(&exp->exp_refcount) : -99,
+ lock->l_pid, lock->l_callback_timeout);
break;
case LDLM_IBITS:
libcfs_debug_vmsg2(msgdata, fmt, args,
- " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
- "res: "LPU64"/"LPU64" bits "LPX64" rrc: %d type: %s "
- "flags: "LPX64" nid: %s remote: "LPX64" expref: %d "
- "pid: %u timeout: %lu lvb_type: %d\n",
- ldlm_lock_to_ns_name(lock),
- lock, lock->l_handle.h_cookie,
- atomic_read (&lock->l_refc),
- lock->l_readers, lock->l_writers,
- ldlm_lockname[lock->l_granted_mode],
- ldlm_lockname[lock->l_req_mode],
- resource->lr_name.name[0],
- resource->lr_name.name[1],
- lock->l_policy_data.l_inodebits.bits,
- atomic_read(&resource->lr_refcount),
- ldlm_typename[resource->lr_type],
- lock->l_flags, nid, lock->l_remote_handle.cookie,
- exp ? atomic_read(&exp->exp_refcount) : -99,
- lock->l_pid, lock->l_callback_timeout, lock->l_lvb_type);
+ " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
+ "res: "DLDLMRES" bits "LPX64" rrc: %d type: %s "
+ "flags: "LPX64" nid: %s remote: "LPX64" expref: %d "
+ "pid: %u timeout: %lu lvb_type: %d\n",
+ ldlm_lock_to_ns_name(lock),
+ lock, lock->l_handle.h_cookie,
+ atomic_read(&lock->l_refc),
+ lock->l_readers, lock->l_writers,
+ ldlm_lockname[lock->l_granted_mode],
+ ldlm_lockname[lock->l_req_mode],
+ PLDLMRES(resource),
+ lock->l_policy_data.l_inodebits.bits,
+ atomic_read(&resource->lr_refcount),
+ ldlm_typename[resource->lr_type],
+ lock->l_flags, nid, lock->l_remote_handle.cookie,
+ exp ? atomic_read(&exp->exp_refcount) : -99,
+ lock->l_pid, lock->l_callback_timeout,
+ lock->l_lvb_type);
break;
default:
libcfs_debug_vmsg2(msgdata, fmt, args,
- " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
- "res: "LPU64"/"LPU64" rrc: %d type: %s flags: "LPX64" "
- "nid: %s remote: "LPX64" expref: %d pid: %u timeout: %lu"
- "lvb_type: %d\n",
- ldlm_lock_to_ns_name(lock),
- lock, lock->l_handle.h_cookie,
- atomic_read (&lock->l_refc),
- lock->l_readers, lock->l_writers,
- ldlm_lockname[lock->l_granted_mode],
- ldlm_lockname[lock->l_req_mode],
- resource->lr_name.name[0],
- resource->lr_name.name[1],
- atomic_read(&resource->lr_refcount),
- ldlm_typename[resource->lr_type],
- lock->l_flags, nid, lock->l_remote_handle.cookie,
- exp ? atomic_read(&exp->exp_refcount) : -99,
- lock->l_pid, lock->l_callback_timeout, lock->l_lvb_type);
+ " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
+ "res: "DLDLMRES" rrc: %d type: %s flags: "LPX64" "
+ "nid: %s remote: "LPX64" expref: %d pid: %u "
+ "timeout: %lu lvb_type: %d\n",
+ ldlm_lock_to_ns_name(lock),
+ lock, lock->l_handle.h_cookie,
+ atomic_read(&lock->l_refc),
+ lock->l_readers, lock->l_writers,
+ ldlm_lockname[lock->l_granted_mode],
+ ldlm_lockname[lock->l_req_mode],
+ PLDLMRES(resource),
+ atomic_read(&resource->lr_refcount),
+ ldlm_typename[resource->lr_type],
+ lock->l_flags, nid, lock->l_remote_handle.cookie,
+ exp ? atomic_read(&exp->exp_refcount) : -99,
+ lock->l_pid, lock->l_callback_timeout,
+ lock->l_lvb_type);
break;
}
va_end(args);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
index 324d5e4286d..3916bda3004 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
@@ -127,12 +127,12 @@ struct ldlm_bl_work_item {
int ldlm_del_waiting_lock(struct ldlm_lock *lock)
{
- RETURN(0);
+ return 0;
}
int ldlm_refresh_waiting_lock(struct ldlm_lock *lock, int timeout)
{
- RETURN(0);
+ return 0;
}
@@ -146,7 +146,6 @@ void ldlm_handle_bl_callback(struct ldlm_namespace *ns,
struct ldlm_lock_desc *ld, struct ldlm_lock *lock)
{
int do_ast;
- ENTRY;
LDLM_DEBUG(lock, "client blocking AST callback handler");
@@ -172,7 +171,6 @@ void ldlm_handle_bl_callback(struct ldlm_namespace *ns,
LDLM_DEBUG(lock, "client blocking callback handler END");
LDLM_LOCK_RELEASE(lock);
- EXIT;
}
/**
@@ -188,7 +186,6 @@ static void ldlm_handle_cp_callback(struct ptlrpc_request *req,
int lvb_len;
LIST_HEAD(ast_list);
int rc = 0;
- ENTRY;
LDLM_DEBUG(lock, "client completion callback handler START");
@@ -198,7 +195,7 @@ static void ldlm_handle_cp_callback(struct ptlrpc_request *req,
schedule_timeout_and_set_state(
TASK_INTERRUPTIBLE, to);
if (lock->l_granted_mode == lock->l_req_mode ||
- lock->l_destroyed)
+ lock->l_flags & LDLM_FL_DESTROYED)
break;
}
}
@@ -238,7 +235,7 @@ static void ldlm_handle_cp_callback(struct ptlrpc_request *req,
}
lock_res_and_lock(lock);
- if (lock->l_destroyed ||
+ if ((lock->l_flags & LDLM_FL_DESTROYED) ||
lock->l_granted_mode == lock->l_req_mode) {
/* bug 11300: the lock has already been granted */
unlock_res_and_lock(lock);
@@ -332,7 +329,6 @@ static void ldlm_handle_gl_callback(struct ptlrpc_request *req,
struct ldlm_lock *lock)
{
int rc = -ENOSYS;
- ENTRY;
LDLM_DEBUG(lock, "client glimpse AST callback handler");
@@ -356,12 +352,10 @@ static void ldlm_handle_gl_callback(struct ptlrpc_request *req,
if (ldlm_bl_to_thread_lock(ns, NULL, lock))
ldlm_handle_bl_callback(ns, NULL, lock);
- EXIT;
return;
}
unlock_res_and_lock(lock);
LDLM_LOCK_RELEASE(lock);
- EXIT;
}
static int ldlm_callback_reply(struct ptlrpc_request *req, int rc)
@@ -382,7 +376,6 @@ static int __ldlm_bl_to_thread(struct ldlm_bl_work_item *blwi,
ldlm_cancel_flags_t cancel_flags)
{
struct ldlm_bl_pool *blp = ldlm_state->ldlm_bl_pool;
- ENTRY;
spin_lock(&blp->blp_lock);
if (blwi->blwi_lock &&
@@ -402,7 +395,7 @@ static int __ldlm_bl_to_thread(struct ldlm_bl_work_item *blwi,
if (!(cancel_flags & LCF_ASYNC))
wait_for_completion(&blwi->blwi_comp);
- RETURN(0);
+ return 0;
}
static inline void init_blwi(struct ldlm_bl_work_item *blwi,
@@ -446,20 +439,18 @@ static int ldlm_bl_to_thread(struct ldlm_namespace *ns,
struct list_head *cancels, int count,
ldlm_cancel_flags_t cancel_flags)
{
- ENTRY;
-
if (cancels && count == 0)
- RETURN(0);
+ return 0;
if (cancel_flags & LCF_ASYNC) {
struct ldlm_bl_work_item *blwi;
OBD_ALLOC(blwi, sizeof(*blwi));
if (blwi == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
init_blwi(blwi, ns, ld, cancels, count, lock, cancel_flags);
- RETURN(__ldlm_bl_to_thread(blwi, cancel_flags));
+ return __ldlm_bl_to_thread(blwi, cancel_flags);
} else {
/* if it is synchronous call do minimum mem alloc, as it could
* be triggered from kernel shrinker
@@ -468,7 +459,7 @@ static int ldlm_bl_to_thread(struct ldlm_namespace *ns,
memset(&blwi, 0, sizeof(blwi));
init_blwi(&blwi, ns, ld, cancels, count, lock, cancel_flags);
- RETURN(__ldlm_bl_to_thread(&blwi, cancel_flags));
+ return __ldlm_bl_to_thread(&blwi, cancel_flags);
}
}
@@ -494,7 +485,6 @@ static int ldlm_handle_setinfo(struct ptlrpc_request *req)
void *val;
int keylen, vallen;
int rc = -ENOSYS;
- ENTRY;
DEBUG_REQ(D_HSM, req, "%s: handle setinfo\n", obd->obd_name);
@@ -503,14 +493,14 @@ static int ldlm_handle_setinfo(struct ptlrpc_request *req)
key = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_KEY);
if (key == NULL) {
DEBUG_REQ(D_IOCTL, req, "no set_info key");
- RETURN(-EFAULT);
+ return -EFAULT;
}
keylen = req_capsule_get_size(&req->rq_pill, &RMF_SETINFO_KEY,
RCL_CLIENT);
val = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_VAL);
if (val == NULL) {
DEBUG_REQ(D_IOCTL, req, "no set_info val");
- RETURN(-EFAULT);
+ return -EFAULT;
}
vallen = req_capsule_get_size(&req->rq_pill, &RMF_SETINFO_VAL,
RCL_CLIENT);
@@ -552,9 +542,11 @@ static int ldlm_handle_qc_callback(struct ptlrpc_request *req)
oqctl = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
if (oqctl == NULL) {
CERROR("Can't unpack obd_quotactl\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
+ oqctl->qc_stat = ptlrpc_status_ntoh(oqctl->qc_stat);
+
cli->cl_qchk_stat = oqctl->qc_stat;
return 0;
}
@@ -566,7 +558,6 @@ static int ldlm_callback_handler(struct ptlrpc_request *req)
struct ldlm_request *dlm_req;
struct ldlm_lock *lock;
int rc;
- ENTRY;
/* Requests arrive in sender's byte order. The ptlrpc service
* handler has already checked and, if necessary, byte-swapped the
@@ -575,7 +566,7 @@ static int ldlm_callback_handler(struct ptlrpc_request *req)
/* do nothing for sec context finalize */
if (lustre_msg_get_opc(req->rq_reqmsg) == SEC_CTX_FINI)
- RETURN(0);
+ return 0;
req_capsule_init(&req->rq_pill, req, RCL_SERVER);
@@ -583,7 +574,7 @@ static int ldlm_callback_handler(struct ptlrpc_request *req)
rc = ldlm_callback_reply(req, -ENOTCONN);
ldlm_callback_errmsg(req, "Operate on unconnected server",
rc, NULL);
- RETURN(0);
+ return 0;
}
LASSERT(req->rq_export != NULL);
@@ -592,71 +583,71 @@ static int ldlm_callback_handler(struct ptlrpc_request *req)
switch (lustre_msg_get_opc(req->rq_reqmsg)) {
case LDLM_BL_CALLBACK:
if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_BL_CALLBACK_NET))
- RETURN(0);
+ return 0;
break;
case LDLM_CP_CALLBACK:
if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_CP_CALLBACK_NET))
- RETURN(0);
+ return 0;
break;
case LDLM_GL_CALLBACK:
if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_GL_CALLBACK_NET))
- RETURN(0);
+ return 0;
break;
case LDLM_SET_INFO:
rc = ldlm_handle_setinfo(req);
ldlm_callback_reply(req, rc);
- RETURN(0);
+ return 0;
case OBD_LOG_CANCEL: /* remove this eventually - for 1.4.0 compat */
CERROR("shouldn't be handling OBD_LOG_CANCEL on DLM thread\n");
req_capsule_set(&req->rq_pill, &RQF_LOG_CANCEL);
if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOG_CANCEL_NET))
- RETURN(0);
+ return 0;
rc = llog_origin_handle_cancel(req);
if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOG_CANCEL_REP))
- RETURN(0);
+ return 0;
ldlm_callback_reply(req, rc);
- RETURN(0);
+ return 0;
case LLOG_ORIGIN_HANDLE_CREATE:
req_capsule_set(&req->rq_pill, &RQF_LLOG_ORIGIN_HANDLE_CREATE);
if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOGD_NET))
- RETURN(0);
+ return 0;
rc = llog_origin_handle_open(req);
ldlm_callback_reply(req, rc);
- RETURN(0);
+ return 0;
case LLOG_ORIGIN_HANDLE_NEXT_BLOCK:
req_capsule_set(&req->rq_pill,
&RQF_LLOG_ORIGIN_HANDLE_NEXT_BLOCK);
if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOGD_NET))
- RETURN(0);
+ return 0;
rc = llog_origin_handle_next_block(req);
ldlm_callback_reply(req, rc);
- RETURN(0);
+ return 0;
case LLOG_ORIGIN_HANDLE_READ_HEADER:
req_capsule_set(&req->rq_pill,
&RQF_LLOG_ORIGIN_HANDLE_READ_HEADER);
if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOGD_NET))
- RETURN(0);
+ return 0;
rc = llog_origin_handle_read_header(req);
ldlm_callback_reply(req, rc);
- RETURN(0);
+ return 0;
case LLOG_ORIGIN_HANDLE_CLOSE:
if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOGD_NET))
- RETURN(0);
+ return 0;
rc = llog_origin_handle_close(req);
ldlm_callback_reply(req, rc);
- RETURN(0);
+ return 0;
case OBD_QC_CALLBACK:
req_capsule_set(&req->rq_pill, &RQF_QC_CALLBACK);
if (OBD_FAIL_CHECK(OBD_FAIL_OBD_QC_CALLBACK_NET))
- RETURN(0);
+ return 0;
rc = ldlm_handle_qc_callback(req);
ldlm_callback_reply(req, rc);
- RETURN(0);
+ return 0;
default:
CERROR("unknown opcode %u\n",
lustre_msg_get_opc(req->rq_reqmsg));
ldlm_callback_reply(req, -EPROTO);
- RETURN(0);
+ return 0;
}
ns = req->rq_export->exp_obd->obd_namespace;
@@ -669,7 +660,7 @@ static int ldlm_callback_handler(struct ptlrpc_request *req)
rc = ldlm_callback_reply(req, -EPROTO);
ldlm_callback_errmsg(req, "Operate without parameter", rc,
NULL);
- RETURN(0);
+ return 0;
}
/* Force a known safe race, send a cancel to the server for a lock
@@ -688,7 +679,7 @@ static int ldlm_callback_handler(struct ptlrpc_request *req)
rc = ldlm_callback_reply(req, -EINVAL);
ldlm_callback_errmsg(req, "Operate with invalid parameter", rc,
&dlm_req->lock_handle[0]);
- RETURN(0);
+ return 0;
}
if ((lock->l_flags & LDLM_FL_FAIL_LOC) &&
@@ -715,7 +706,7 @@ static int ldlm_callback_handler(struct ptlrpc_request *req)
rc = ldlm_callback_reply(req, -EINVAL);
ldlm_callback_errmsg(req, "Operate on stale lock", rc,
&dlm_req->lock_handle[0]);
- RETURN(0);
+ return 0;
}
/* BL_AST locks are not needed in LRU.
* Let ldlm_cancel_lru() be fast. */
@@ -761,7 +752,7 @@ static int ldlm_callback_handler(struct ptlrpc_request *req)
LBUG(); /* checked above */
}
- RETURN(0);
+ return 0;
}
@@ -805,7 +796,7 @@ static int ldlm_bl_thread_main(void *arg);
static int ldlm_bl_thread_start(struct ldlm_bl_pool *blp)
{
struct ldlm_bl_thread_data bltd = { .bltd_blp = blp };
- task_t *task;
+ struct task_struct *task;
init_completion(&bltd.bltd_comp);
bltd.bltd_num = atomic_read(&blp->blp_num_threads);
@@ -832,7 +823,6 @@ static int ldlm_bl_thread_start(struct ldlm_bl_pool *blp)
static int ldlm_bl_thread_main(void *arg)
{
struct ldlm_bl_pool *blp;
- ENTRY;
{
struct ldlm_bl_thread_data *bltd = arg;
@@ -904,7 +894,7 @@ static int ldlm_bl_thread_main(void *arg)
atomic_dec(&blp->blp_busy_threads);
atomic_dec(&blp->blp_num_threads);
complete(&blp->blp_comp);
- RETURN(0);
+ return 0;
}
@@ -914,7 +904,7 @@ static int ldlm_cleanup(void);
int ldlm_get_ref(void)
{
int rc = 0;
- ENTRY;
+
mutex_lock(&ldlm_ref_mutex);
if (++ldlm_refcount == 1) {
rc = ldlm_setup();
@@ -923,13 +913,12 @@ int ldlm_get_ref(void)
}
mutex_unlock(&ldlm_ref_mutex);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ldlm_get_ref);
void ldlm_put_ref(void)
{
- ENTRY;
mutex_lock(&ldlm_ref_mutex);
if (ldlm_refcount == 1) {
int rc = ldlm_cleanup();
@@ -941,8 +930,6 @@ void ldlm_put_ref(void)
ldlm_refcount--;
}
mutex_unlock(&ldlm_ref_mutex);
-
- EXIT;
}
EXPORT_SYMBOL(ldlm_put_ref);
@@ -1016,8 +1003,6 @@ static cfs_hash_ops_t ldlm_export_lock_ops = {
int ldlm_init_export(struct obd_export *exp)
{
- ENTRY;
-
exp->exp_lock_hash =
cfs_hash_create(obd_uuid2str(&exp->exp_client_uuid),
HASH_EXP_LOCK_CUR_BITS,
@@ -1029,20 +1014,18 @@ int ldlm_init_export(struct obd_export *exp)
CFS_HASH_NBLK_CHANGE);
if (!exp->exp_lock_hash)
- RETURN(-ENOMEM);
+ return -ENOMEM;
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_init_export);
void ldlm_destroy_export(struct obd_export *exp)
{
- ENTRY;
cfs_hash_putref(exp->exp_lock_hash);
exp->exp_lock_hash = NULL;
ldlm_destroy_flock_export(exp);
- EXIT;
}
EXPORT_SYMBOL(ldlm_destroy_export);
@@ -1052,14 +1035,13 @@ static int ldlm_setup(void)
struct ldlm_bl_pool *blp = NULL;
int rc = 0;
int i;
- ENTRY;
if (ldlm_state != NULL)
- RETURN(-EALREADY);
+ return -EALREADY;
OBD_ALLOC(ldlm_state, sizeof(*ldlm_state));
if (ldlm_state == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
#ifdef LPROCFS
rc = ldlm_proc_setup();
@@ -1139,23 +1121,21 @@ static int ldlm_setup(void)
CERROR("Failed to initialize LDLM pools: %d\n", rc);
GOTO(out, rc);
}
- RETURN(0);
+ return 0;
out:
ldlm_cleanup();
- RETURN(rc);
+ return rc;
}
static int ldlm_cleanup(void)
{
- ENTRY;
-
if (!list_empty(ldlm_namespace_list(LDLM_NAMESPACE_SERVER)) ||
!list_empty(ldlm_namespace_list(LDLM_NAMESPACE_CLIENT))) {
CERROR("ldlm still has namespaces; clean these up first.\n");
ldlm_dump_all_namespaces(LDLM_NAMESPACE_SERVER, D_DLMTRACE);
ldlm_dump_all_namespaces(LDLM_NAMESPACE_CLIENT, D_DLMTRACE);
- RETURN(-EBUSY);
+ return -EBUSY;
}
ldlm_pools_fini();
@@ -1188,7 +1168,7 @@ static int ldlm_cleanup(void)
OBD_FREE(ldlm_state, sizeof(*ldlm_state));
ldlm_state = NULL;
- RETURN(0);
+ return 0;
}
int ldlm_init(void)
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
index b3b60288e5f..454027d68d5 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
@@ -142,7 +142,7 @@
*/
#define LDLM_POOL_SLV_SHIFT (10)
-extern proc_dir_entry_t *ldlm_ns_proc_dir;
+extern struct proc_dir_entry *ldlm_ns_proc_dir;
static inline __u64 dru(__u64 val, __u32 shift, int round_up)
{
@@ -335,17 +335,16 @@ static void ldlm_srv_pool_push_slv(struct ldlm_pool *pl)
static int ldlm_srv_pool_recalc(struct ldlm_pool *pl)
{
time_t recalc_interval_sec;
- ENTRY;
recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
if (recalc_interval_sec < pl->pl_recalc_period)
- RETURN(0);
+ return 0;
spin_lock(&pl->pl_lock);
recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
if (recalc_interval_sec < pl->pl_recalc_period) {
spin_unlock(&pl->pl_lock);
- RETURN(0);
+ return 0;
}
/*
* Recalc SLV after last period. This should be done
@@ -367,7 +366,7 @@ static int ldlm_srv_pool_recalc(struct ldlm_pool *pl)
lprocfs_counter_add(pl->pl_stats, LDLM_POOL_TIMING_STAT,
recalc_interval_sec);
spin_unlock(&pl->pl_lock);
- RETURN(0);
+ return 0;
}
/**
@@ -394,7 +393,7 @@ static int ldlm_srv_pool_shrink(struct ldlm_pool *pl,
* and can't cancel anything. Let's catch this race.
*/
if (atomic_read(&pl->pl_granted) == 0)
- RETURN(0);
+ return 0;
spin_lock(&pl->pl_lock);
@@ -473,11 +472,10 @@ static void ldlm_cli_pool_pop_slv(struct ldlm_pool *pl)
static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
{
time_t recalc_interval_sec;
- ENTRY;
recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
if (recalc_interval_sec < pl->pl_recalc_period)
- RETURN(0);
+ return 0;
spin_lock(&pl->pl_lock);
/*
@@ -486,7 +484,7 @@ static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
if (recalc_interval_sec < pl->pl_recalc_period) {
spin_unlock(&pl->pl_lock);
- RETURN(0);
+ return 0;
}
/*
@@ -503,7 +501,7 @@ static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
* Do not cancel locks in case lru resize is disabled for this ns.
*/
if (!ns_connect_lru_resize(ldlm_pl2ns(pl)))
- RETURN(0);
+ return 0;
/*
* In the time of canceling locks on client we do not need to maintain
@@ -511,8 +509,7 @@ static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
* It may be called when SLV has changed much, this is why we do not
* take into account pl->pl_recalc_time here.
*/
- RETURN(ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC,
- LDLM_CANCEL_LRUR));
+ return ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC, LDLM_CANCEL_LRUR);
}
/**
@@ -532,7 +529,7 @@ static int ldlm_cli_pool_shrink(struct ldlm_pool *pl,
* Do not cancel locks in case lru resize is disabled for this ns.
*/
if (!ns_connect_lru_resize(ns))
- RETURN(0);
+ return 0;
/*
* Make sure that pool knows last SLV and Limit from obd.
@@ -578,7 +575,6 @@ int ldlm_pool_recalc(struct ldlm_pool *pl)
goto recalc;
spin_lock(&pl->pl_lock);
- recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
if (recalc_interval_sec > 0) {
/*
* Update pool statistics every 1s.
@@ -598,12 +594,12 @@ int ldlm_pool_recalc(struct ldlm_pool *pl)
count = pl->pl_ops->po_recalc(pl);
lprocfs_counter_add(pl->pl_stats, LDLM_POOL_RECALC_STAT,
count);
- return count;
}
+ recalc_interval_sec = pl->pl_recalc_time - cfs_time_current_sec() +
+ pl->pl_recalc_period;
- return 0;
+ return recalc_interval_sec;
}
-EXPORT_SYMBOL(ldlm_pool_recalc);
/**
* Pool shrink wrapper. Will call either client or server pool recalc callback
@@ -734,11 +730,10 @@ static int ldlm_pool_proc_init(struct ldlm_pool *pl)
struct lprocfs_vars pool_vars[2];
char *var_name = NULL;
int rc = 0;
- ENTRY;
OBD_ALLOC(var_name, MAX_STRING_SIZE + 1);
if (!var_name)
- RETURN(-ENOMEM);
+ return -ENOMEM;
parent_ns_proc = ns->ns_proc_dir_entry;
if (parent_ns_proc == NULL) {
@@ -751,6 +746,7 @@ static int ldlm_pool_proc_init(struct ldlm_pool *pl)
if (IS_ERR(pl->pl_proc_dir)) {
CERROR("LProcFS failed in ldlm-pool-init\n");
rc = PTR_ERR(pl->pl_proc_dir);
+ pl->pl_proc_dir = NULL;
GOTO(out_free_name, rc);
}
@@ -813,7 +809,6 @@ static int ldlm_pool_proc_init(struct ldlm_pool *pl)
"recalc_timing", "sec");
rc = lprocfs_register_stats(pl->pl_proc_dir, "stats", pl->pl_stats);
- EXIT;
out_free_name:
OBD_FREE(var_name, MAX_STRING_SIZE + 1);
return rc;
@@ -835,7 +830,6 @@ int ldlm_pool_init(struct ldlm_pool *pl, struct ldlm_namespace *ns,
int idx, ldlm_side_t client)
{
int rc;
- ENTRY;
spin_lock_init(&pl->pl_lock);
atomic_set(&pl->pl_granted, 0);
@@ -863,17 +857,16 @@ int ldlm_pool_init(struct ldlm_pool *pl, struct ldlm_namespace *ns,
pl->pl_client_lock_volume = 0;
rc = ldlm_pool_proc_init(pl);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_DLMTRACE, "Lock pool %s is initialized\n", pl->pl_name);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ldlm_pool_init);
void ldlm_pool_fini(struct ldlm_pool *pl)
{
- ENTRY;
ldlm_pool_proc_fini(pl);
/*
@@ -882,7 +875,6 @@ void ldlm_pool_fini(struct ldlm_pool *pl)
* any abnormal using cases.
*/
POISON(pl, 0x5a, sizeof(*pl));
- EXIT;
}
EXPORT_SYMBOL(ldlm_pool_fini);
@@ -1039,6 +1031,7 @@ static int ldlm_pools_shrink(ldlm_side_t client, int nr,
{
int total = 0, cached = 0, nr_ns;
struct ldlm_namespace *ns;
+ struct ldlm_namespace *ns_old = NULL; /* loop detection */
void *cookie;
if (client == LDLM_NAMESPACE_CLIENT && nr != 0 &&
@@ -1053,7 +1046,7 @@ static int ldlm_pools_shrink(ldlm_side_t client, int nr,
/*
* Find out how many resources we may release.
*/
- for (nr_ns = atomic_read(ldlm_namespace_nr(client));
+ for (nr_ns = ldlm_namespace_nr_read(client);
nr_ns > 0; nr_ns--)
{
mutex_lock(ldlm_namespace_lock(client));
@@ -1063,8 +1056,23 @@ static int ldlm_pools_shrink(ldlm_side_t client, int nr,
return 0;
}
ns = ldlm_namespace_first_locked(client);
+
+ if (ns == ns_old) {
+ mutex_unlock(ldlm_namespace_lock(client));
+ break;
+ }
+
+ if (ldlm_ns_empty(ns)) {
+ ldlm_namespace_move_to_inactive_locked(ns, client);
+ mutex_unlock(ldlm_namespace_lock(client));
+ continue;
+ }
+
+ if (ns_old == NULL)
+ ns_old = ns;
+
ldlm_namespace_get(ns);
- ldlm_namespace_move_locked(ns, client);
+ ldlm_namespace_move_to_active_locked(ns, client);
mutex_unlock(ldlm_namespace_lock(client));
total += ldlm_pool_shrink(&ns->ns_pool, 0, gfp_mask);
ldlm_namespace_put(ns);
@@ -1078,7 +1086,7 @@ static int ldlm_pools_shrink(ldlm_side_t client, int nr,
/*
* Shrink at least ldlm_namespace_nr(client) namespaces.
*/
- for (nr_ns = atomic_read(ldlm_namespace_nr(client));
+ for (nr_ns = ldlm_namespace_nr_read(client) - nr_ns;
nr_ns > 0; nr_ns--)
{
int cancel, nr_locks;
@@ -1099,7 +1107,7 @@ static int ldlm_pools_shrink(ldlm_side_t client, int nr,
}
ns = ldlm_namespace_first_locked(client);
ldlm_namespace_get(ns);
- ldlm_namespace_move_locked(ns, client);
+ ldlm_namespace_move_to_active_locked(ns, client);
mutex_unlock(ldlm_namespace_lock(client));
nr_locks = ldlm_pool_granted(&ns->ns_pool);
@@ -1128,11 +1136,13 @@ static int ldlm_pools_cli_shrink(SHRINKER_ARGS(sc, nr_to_scan, gfp_mask))
shrink_param(sc, gfp_mask));
}
-void ldlm_pools_recalc(ldlm_side_t client)
+int ldlm_pools_recalc(ldlm_side_t client)
{
__u32 nr_l = 0, nr_p = 0, l;
struct ldlm_namespace *ns;
+ struct ldlm_namespace *ns_old = NULL;
int nr, equal = 0;
+ int time = 50; /* seconds of sleep if no active namespaces */
/*
* No need to setup pool limit for client pools.
@@ -1190,16 +1200,14 @@ void ldlm_pools_recalc(ldlm_side_t client)
* for _all_ pools.
*/
l = LDLM_POOL_HOST_L /
- atomic_read(
- ldlm_namespace_nr(client));
+ ldlm_namespace_nr_read(client);
} else {
/*
* All the rest of greedy pools will have
* all locks in equal parts.
*/
l = (LDLM_POOL_HOST_L - nr_l) /
- (atomic_read(
- ldlm_namespace_nr(client)) -
+ (ldlm_namespace_nr_read(client) -
nr_p);
}
ldlm_pool_setup(&ns->ns_pool, l);
@@ -1210,7 +1218,7 @@ void ldlm_pools_recalc(ldlm_side_t client)
/*
* Recalc at least ldlm_namespace_nr(client) namespaces.
*/
- for (nr = atomic_read(ldlm_namespace_nr(client)); nr > 0; nr--) {
+ for (nr = ldlm_namespace_nr_read(client); nr > 0; nr--) {
int skip;
/*
* Lock the list, get first @ns in the list, getref, move it
@@ -1226,6 +1234,30 @@ void ldlm_pools_recalc(ldlm_side_t client)
}
ns = ldlm_namespace_first_locked(client);
+ if (ns_old == ns) { /* Full pass complete */
+ mutex_unlock(ldlm_namespace_lock(client));
+ break;
+ }
+
+ /* We got an empty namespace, need to move it back to inactive
+ * list.
+ * The race with parallel resource creation is fine:
+ * - If they do namespace_get before our check, we fail the
+ * check and they move this item to the end of the list anyway
+ * - If we do the check and then they do namespace_get, then
+ * we move the namespace to inactive and they will move
+ * it back to active (synchronised by the lock, so no clash
+ * there).
+ */
+ if (ldlm_ns_empty(ns)) {
+ ldlm_namespace_move_to_inactive_locked(ns, client);
+ mutex_unlock(ldlm_namespace_lock(client));
+ continue;
+ }
+
+ if (ns_old == NULL)
+ ns_old = ns;
+
spin_lock(&ns->ns_lock);
/*
* skip ns which is being freed, and we don't want to increase
@@ -1239,24 +1271,29 @@ void ldlm_pools_recalc(ldlm_side_t client)
}
spin_unlock(&ns->ns_lock);
- ldlm_namespace_move_locked(ns, client);
+ ldlm_namespace_move_to_active_locked(ns, client);
mutex_unlock(ldlm_namespace_lock(client));
/*
* After setup is done - recalc the pool.
*/
if (!skip) {
- ldlm_pool_recalc(&ns->ns_pool);
+ int ttime = ldlm_pool_recalc(&ns->ns_pool);
+
+ if (ttime < time)
+ time = ttime;
+
ldlm_namespace_put(ns);
}
}
+ return time;
}
EXPORT_SYMBOL(ldlm_pools_recalc);
static int ldlm_pools_thread_main(void *arg)
{
struct ptlrpc_thread *thread = (struct ptlrpc_thread *)arg;
- ENTRY;
+ int s_time, c_time;
thread_set_flags(thread, SVC_RUNNING);
wake_up(&thread->t_ctl_waitq);
@@ -1270,14 +1307,14 @@ static int ldlm_pools_thread_main(void *arg)
/*
* Recal all pools on this tick.
*/
- ldlm_pools_recalc(LDLM_NAMESPACE_SERVER);
- ldlm_pools_recalc(LDLM_NAMESPACE_CLIENT);
+ s_time = ldlm_pools_recalc(LDLM_NAMESPACE_SERVER);
+ c_time = ldlm_pools_recalc(LDLM_NAMESPACE_CLIENT);
/*
* Wait until the next check time, or until we're
* stopped.
*/
- lwi = LWI_TIMEOUT(cfs_time_seconds(LDLM_POOLS_THREAD_PERIOD),
+ lwi = LWI_TIMEOUT(cfs_time_seconds(min(s_time, c_time)),
NULL, NULL);
l_wait_event(thread->t_ctl_waitq,
thread_is_stopping(thread) ||
@@ -1302,15 +1339,14 @@ static int ldlm_pools_thread_main(void *arg)
static int ldlm_pools_thread_start(void)
{
struct l_wait_info lwi = { 0 };
- task_t *task;
- ENTRY;
+ struct task_struct *task;
if (ldlm_pools_thread != NULL)
- RETURN(-EALREADY);
+ return -EALREADY;
OBD_ALLOC_PTR(ldlm_pools_thread);
if (ldlm_pools_thread == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
init_completion(&ldlm_pools_comp);
init_waitqueue_head(&ldlm_pools_thread->t_ctl_waitq);
@@ -1321,19 +1357,16 @@ static int ldlm_pools_thread_start(void)
CERROR("Can't start pool thread, error %ld\n", PTR_ERR(task));
OBD_FREE(ldlm_pools_thread, sizeof(*ldlm_pools_thread));
ldlm_pools_thread = NULL;
- RETURN(PTR_ERR(task));
+ return PTR_ERR(task);
}
l_wait_event(ldlm_pools_thread->t_ctl_waitq,
thread_is_running(ldlm_pools_thread), &lwi);
- RETURN(0);
+ return 0;
}
static void ldlm_pools_thread_stop(void)
{
- ENTRY;
-
if (ldlm_pools_thread == NULL) {
- EXIT;
return;
}
@@ -1348,13 +1381,11 @@ static void ldlm_pools_thread_stop(void)
wait_for_completion(&ldlm_pools_comp);
OBD_FREE_PTR(ldlm_pools_thread);
ldlm_pools_thread = NULL;
- EXIT;
}
int ldlm_pools_init(void)
{
int rc;
- ENTRY;
rc = ldlm_pools_thread_start();
if (rc == 0) {
@@ -1365,7 +1396,7 @@ int ldlm_pools_init(void)
set_shrinker(DEFAULT_SEEKS,
ldlm_pools_cli_shrink);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ldlm_pools_init);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
index 1a690edaba0..21cb523ac4a 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
@@ -94,12 +94,11 @@ int ldlm_expired_completion_wait(void *data)
struct obd_import *imp;
struct obd_device *obd;
- ENTRY;
if (lock->l_conn_export == NULL) {
static cfs_time_t next_dump = 0, last_dump = 0;
if (ptlrpc_check_suspend())
- RETURN(0);
+ return 0;
LCONSOLE_WARN("lock timed out (enqueued at "CFS_TIME_T", "
CFS_DURATION_T"s ago)\n",
@@ -120,7 +119,7 @@ int ldlm_expired_completion_wait(void *data)
if (last_dump == 0)
libcfs_debug_dumplog();
}
- RETURN(0);
+ return 0;
}
obd = lock->l_conn_export->exp_obd;
@@ -132,7 +131,7 @@ int ldlm_expired_completion_wait(void *data)
cfs_time_sub(cfs_time_current_sec(), lock->l_last_activity),
obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_expired_completion_wait);
@@ -160,7 +159,7 @@ static int ldlm_completion_tail(struct ldlm_lock *lock)
long delay;
int result;
- if (lock->l_destroyed || lock->l_flags & LDLM_FL_FAILED) {
+ if (lock->l_flags & (LDLM_FL_DESTROYED | LDLM_FL_FAILED)) {
LDLM_DEBUG(lock, "client-side enqueue: destroyed");
result = -EIO;
} else {
@@ -184,23 +183,21 @@ static int ldlm_completion_tail(struct ldlm_lock *lock)
*/
int ldlm_completion_ast_async(struct ldlm_lock *lock, __u64 flags, void *data)
{
- ENTRY;
-
if (flags == LDLM_FL_WAIT_NOREPROC) {
LDLM_DEBUG(lock, "client-side enqueue waiting on pending lock");
- RETURN(0);
+ return 0;
}
if (!(flags & (LDLM_FL_BLOCK_WAIT | LDLM_FL_BLOCK_GRANTED |
LDLM_FL_BLOCK_CONV))) {
wake_up(&lock->l_waitq);
- RETURN(ldlm_completion_tail(lock));
+ return ldlm_completion_tail(lock);
}
LDLM_DEBUG(lock, "client-side enqueue returned a blocked lock, "
"going forward");
ldlm_reprocess_all(lock->l_resource);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_completion_ast_async);
@@ -234,7 +231,6 @@ int ldlm_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
struct l_wait_info lwi;
__u32 timeout;
int rc = 0;
- ENTRY;
if (flags == LDLM_FL_WAIT_NOREPROC) {
LDLM_DEBUG(lock, "client-side enqueue waiting on pending lock");
@@ -244,7 +240,7 @@ int ldlm_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
if (!(flags & (LDLM_FL_BLOCK_WAIT | LDLM_FL_BLOCK_GRANTED |
LDLM_FL_BLOCK_CONV))) {
wake_up(&lock->l_waitq);
- RETURN(0);
+ return 0;
}
LDLM_DEBUG(lock, "client-side enqueue returned a blocked lock, "
@@ -295,10 +291,10 @@ noreproc:
if (rc) {
LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)",
rc);
- RETURN(rc);
+ return rc;
}
- RETURN(ldlm_completion_tail(lock));
+ return ldlm_completion_tail(lock);
}
EXPORT_SYMBOL(ldlm_completion_ast);
@@ -316,7 +312,6 @@ EXPORT_SYMBOL(ldlm_completion_ast);
int ldlm_blocking_ast_nocheck(struct ldlm_lock *lock)
{
int do_ast;
- ENTRY;
lock->l_flags |= LDLM_FL_CBPENDING;
do_ast = (!lock->l_readers && !lock->l_writers);
@@ -335,7 +330,7 @@ int ldlm_blocking_ast_nocheck(struct ldlm_lock *lock)
LDLM_DEBUG(lock, "Lock still has references, will be "
"cancelled later");
}
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_blocking_ast_nocheck);
@@ -355,11 +350,9 @@ EXPORT_SYMBOL(ldlm_blocking_ast_nocheck);
int ldlm_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
void *data, int flag)
{
- ENTRY;
-
if (flag == LDLM_CB_CANCELING) {
/* Don't need to do anything here. */
- RETURN(0);
+ return 0;
}
lock_res_and_lock(lock);
@@ -370,9 +363,9 @@ int ldlm_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
* early, if so. */
if (lock->l_blocking_ast != ldlm_blocking_ast) {
unlock_res_and_lock(lock);
- RETURN(0);
+ return 0;
}
- RETURN(ldlm_blocking_ast_nocheck(lock));
+ return ldlm_blocking_ast_nocheck(lock);
}
EXPORT_SYMBOL(ldlm_blocking_ast);
@@ -424,7 +417,6 @@ int ldlm_cli_enqueue_local(struct ldlm_namespace *ns,
.lcs_blocking = blocking,
.lcs_glimpse = glimpse,
};
- ENTRY;
LASSERT(!(*flags & LDLM_FL_REPLAY));
if (unlikely(ns_is_client(ns))) {
@@ -464,7 +456,6 @@ int ldlm_cli_enqueue_local(struct ldlm_namespace *ns,
lock->l_completion_ast(lock, *flags, NULL);
LDLM_DEBUG(lock, "client-side local enqueue handler, new lock created");
- EXIT;
out:
LDLM_LOCK_RELEASE(lock);
out_nolock:
@@ -530,13 +521,12 @@ int ldlm_cli_enqueue_fini(struct obd_export *exp, struct ptlrpc_request *req,
struct ldlm_reply *reply;
int cleanup_phase = 1;
int size = 0;
- ENTRY;
lock = ldlm_handle2lock(lockh);
/* ldlm_cli_enqueue is holding a reference on this lock. */
if (!lock) {
LASSERT(type == LDLM_FLOCK);
- RETURN(-ENOLCK);
+ return -ENOLCK;
}
LASSERTF(ergo(lvb_len != 0, lvb_len == lock->l_lvb_len),
@@ -698,7 +688,6 @@ int ldlm_cli_enqueue_fini(struct obd_export *exp, struct ptlrpc_request *req,
}
LDLM_DEBUG(lock, "client-side enqueue END");
- EXIT;
cleanup:
if (cleanup_phase == 1 && rc)
failed_lock_cleanup(ns, lock, mode);
@@ -763,7 +752,6 @@ int ldlm_prep_elc_req(struct obd_export *exp, struct ptlrpc_request *req,
int flags, avail, to_free, pack = 0;
LIST_HEAD(head);
int rc;
- ENTRY;
if (cancels == NULL)
cancels = &head;
@@ -794,7 +782,7 @@ int ldlm_prep_elc_req(struct obd_export *exp, struct ptlrpc_request *req,
rc = ptlrpc_request_pack(req, version, opc);
if (rc) {
ldlm_lock_list_put(cancels, l_bl_ast, count);
- RETURN(rc);
+ return rc;
}
if (ns_connect_cancelset(ns)) {
@@ -814,7 +802,7 @@ int ldlm_prep_elc_req(struct obd_export *exp, struct ptlrpc_request *req,
} else {
ldlm_lock_list_put(cancels, l_bl_ast, count);
}
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_prep_elc_req);
@@ -830,21 +818,20 @@ struct ptlrpc_request *ldlm_enqueue_pack(struct obd_export *exp, int lvb_len)
{
struct ptlrpc_request *req;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_LDLM_ENQUEUE);
if (req == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
if (rc) {
ptlrpc_request_free(req);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER, lvb_len);
ptlrpc_request_set_replen(req);
- RETURN(req);
+ return req;
}
EXPORT_SYMBOL(ldlm_enqueue_pack);
@@ -872,7 +859,6 @@ int ldlm_cli_enqueue(struct obd_export *exp, struct ptlrpc_request **reqp,
int req_passed_in = 1;
int rc, err;
struct ptlrpc_request *req;
- ENTRY;
LASSERT(exp != NULL);
@@ -888,15 +874,14 @@ int ldlm_cli_enqueue(struct obd_export *exp, struct ptlrpc_request **reqp,
} else {
const struct ldlm_callback_suite cbs = {
.lcs_completion = einfo->ei_cb_cp,
- .lcs_blocking = einfo->ei_cb_bl,
- .lcs_glimpse = einfo->ei_cb_gl,
- .lcs_weigh = einfo->ei_cb_wg
+ .lcs_blocking = einfo->ei_cb_bl,
+ .lcs_glimpse = einfo->ei_cb_gl
};
lock = ldlm_lock_create(ns, res_id, einfo->ei_type,
einfo->ei_mode, &cbs, einfo->ei_cbdata,
lvb_len, lvb_type);
if (lock == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* for the local lock, add the reference */
ldlm_lock_addref_internal(lock, einfo->ei_mode);
ldlm_lock2handle(lock, lockh);
@@ -937,7 +922,7 @@ int ldlm_cli_enqueue(struct obd_export *exp, struct ptlrpc_request **reqp,
if (req == NULL) {
failed_lock_cleanup(ns, lock, einfo->ei_mode);
LDLM_LOCK_RELEASE(lock);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
req_passed_in = 0;
if (reqp)
@@ -978,7 +963,7 @@ int ldlm_cli_enqueue(struct obd_export *exp, struct ptlrpc_request **reqp,
if (async) {
LASSERT(reqp != NULL);
- RETURN(0);
+ return 0;
}
LDLM_DEBUG(lock, "sending request");
@@ -1002,7 +987,7 @@ int ldlm_cli_enqueue(struct obd_export *exp, struct ptlrpc_request **reqp,
*reqp = NULL;
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ldlm_cli_enqueue);
@@ -1011,7 +996,7 @@ static int ldlm_cli_convert_local(struct ldlm_lock *lock, int new_mode,
{
struct ldlm_resource *res;
int rc;
- ENTRY;
+
if (ns_is_client(ldlm_lock_to_ns(lock))) {
CERROR("Trying to cancel local lock\n");
LBUG();
@@ -1023,11 +1008,11 @@ static int ldlm_cli_convert_local(struct ldlm_lock *lock, int new_mode,
ldlm_reprocess_all(res);
rc = 0;
} else {
- rc = EDEADLOCK;
+ rc = LUSTRE_EDEADLK;
}
LDLM_DEBUG(lock, "client-side local convert handler END");
LDLM_LOCK_PUT(lock);
- RETURN(rc);
+ return rc;
}
/* FIXME: one of ldlm_cli_convert or the server side should reject attempted
@@ -1042,17 +1027,16 @@ int ldlm_cli_convert(struct lustre_handle *lockh, int new_mode, __u32 *flags)
struct ldlm_resource *res;
struct ptlrpc_request *req;
int rc;
- ENTRY;
lock = ldlm_handle2lock(lockh);
if (!lock) {
LBUG();
- RETURN(-EINVAL);
+ return -EINVAL;
}
*flags = 0;
if (lock->l_conn_export == NULL)
- RETURN(ldlm_cli_convert_local(lock, new_mode, flags));
+ return ldlm_cli_convert_local(lock, new_mode, flags);
LDLM_DEBUG(lock, "client-side convert");
@@ -1061,7 +1045,7 @@ int ldlm_cli_convert(struct lustre_handle *lockh, int new_mode, __u32 *flags)
LDLM_CONVERT);
if (req == NULL) {
LDLM_LOCK_PUT(lock);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
body = req_capsule_client_get(&req->rq_pill, &RMF_DLM_REQ);
@@ -1095,9 +1079,8 @@ int ldlm_cli_convert(struct lustre_handle *lockh, int new_mode, __u32 *flags)
GOTO(out, rc);
}
} else {
- rc = EDEADLOCK;
+ rc = LUSTRE_EDEADLK;
}
- EXIT;
out:
LDLM_LOCK_PUT(lock);
ptlrpc_req_finished(req);
@@ -1115,7 +1098,6 @@ EXPORT_SYMBOL(ldlm_cli_convert);
static __u64 ldlm_cli_cancel_local(struct ldlm_lock *lock)
{
__u64 rc = LDLM_FL_LOCAL_ONLY;
- ENTRY;
if (lock->l_conn_export) {
bool local_only;
@@ -1147,7 +1129,7 @@ static __u64 ldlm_cli_cancel_local(struct ldlm_lock *lock)
ldlm_reprocess_all(lock->l_resource);
}
- RETURN(rc);
+ return rc;
}
/**
@@ -1159,7 +1141,6 @@ static void ldlm_cancel_pack(struct ptlrpc_request *req,
struct ldlm_request *dlm;
struct ldlm_lock *lock;
int max, packed = 0;
- ENTRY;
dlm = req_capsule_client_get(&req->rq_pill, &RMF_DLM_REQ);
LASSERT(dlm != NULL);
@@ -1184,7 +1165,6 @@ static void ldlm_cancel_pack(struct ptlrpc_request *req,
packed++;
}
CDEBUG(D_DLMTRACE, "%d locks packed\n", packed);
- EXIT;
}
/**
@@ -1197,7 +1177,6 @@ int ldlm_cli_cancel_req(struct obd_export *exp, struct list_head *cancels,
struct obd_import *imp;
int free, sent = 0;
int rc = 0;
- ENTRY;
LASSERT(exp != NULL);
LASSERT(count > 0);
@@ -1205,7 +1184,7 @@ int ldlm_cli_cancel_req(struct obd_export *exp, struct list_head *cancels,
CFS_FAIL_TIMEOUT(OBD_FAIL_LDLM_PAUSE_CANCEL, cfs_fail_val);
if (CFS_FAIL_CHECK(OBD_FAIL_LDLM_CANCEL_RACE))
- RETURN(count);
+ return count;
free = ldlm_format_handles_avail(class_exp2cliimp(exp),
&RQF_LDLM_CANCEL, RCL_CLIENT, 0);
@@ -1217,7 +1196,7 @@ int ldlm_cli_cancel_req(struct obd_export *exp, struct list_head *cancels,
if (imp == NULL || imp->imp_invalid) {
CDEBUG(D_DLMTRACE,
"skipping cancel on invalid import %p\n", imp);
- RETURN(count);
+ return count;
}
req = ptlrpc_request_alloc(imp, &RQF_LDLM_CANCEL);
@@ -1248,7 +1227,7 @@ int ldlm_cli_cancel_req(struct obd_export *exp, struct list_head *cancels,
} else {
rc = ptlrpc_queue_wait(req);
}
- if (rc == ESTALE) {
+ if (rc == LUSTRE_ESTALE) {
CDEBUG(D_DLMTRACE, "client/server (nid %s) "
"out of sync -- not fatal\n",
libcfs_nid2str(req->rq_import->
@@ -1270,7 +1249,6 @@ int ldlm_cli_cancel_req(struct obd_export *exp, struct list_head *cancels,
}
ptlrpc_req_finished(req);
- EXIT;
out:
return sent ? sent : rc;
}
@@ -1290,14 +1268,14 @@ int ldlm_cli_update_pool(struct ptlrpc_request *req)
struct obd_device *obd;
__u64 new_slv;
__u32 new_limit;
- ENTRY;
+
if (unlikely(!req->rq_import || !req->rq_import->imp_obd ||
!imp_connect_lru_resize(req->rq_import)))
{
/*
* Do nothing for corner cases.
*/
- RETURN(0);
+ return 0;
}
/* In some cases RPC may contain SLV and limit zeroed out. This
@@ -1311,7 +1289,7 @@ int ldlm_cli_update_pool(struct ptlrpc_request *req)
"(SLV: "LPU64", Limit: %u)",
lustre_msg_get_slv(req->rq_repmsg),
lustre_msg_get_limit(req->rq_repmsg));
- RETURN(0);
+ return 0;
}
new_limit = lustre_msg_get_limit(req->rq_repmsg);
@@ -1328,7 +1306,7 @@ int ldlm_cli_update_pool(struct ptlrpc_request *req)
obd->obd_pool_limit = new_limit;
write_unlock(&obd->obd_pool_lock);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_cli_update_pool);
@@ -1346,19 +1324,18 @@ int ldlm_cli_cancel(struct lustre_handle *lockh,
struct ldlm_namespace *ns;
struct ldlm_lock *lock;
LIST_HEAD(cancels);
- ENTRY;
/* concurrent cancels on the same handle can happen */
lock = ldlm_handle2lock_long(lockh, LDLM_FL_CANCELING);
if (lock == NULL) {
LDLM_DEBUG_NOLOCK("lock is already being destroyed\n");
- RETURN(0);
+ return 0;
}
rc = ldlm_cli_cancel_local(lock);
if (rc == LDLM_FL_LOCAL_ONLY) {
LDLM_LOCK_RELEASE(lock);
- RETURN(0);
+ return 0;
}
/* Even if the lock is marked as LDLM_FL_BL_AST, this is a LDLM_CANCEL
* RPC which goes to canceld portal, so we can cancel other LRU locks
@@ -1380,7 +1357,7 @@ int ldlm_cli_cancel(struct lustre_handle *lockh,
LCF_BL_AST, flags);
}
ldlm_cli_cancel_list(&cancels, count, NULL, cancel_flags);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_cli_cancel);
@@ -1430,7 +1407,7 @@ int ldlm_cli_cancel_list_local(struct list_head *cancels, int count,
ldlm_cli_cancel_list(&head, bl_ast, NULL, 0);
}
- RETURN(count);
+ return count;
}
EXPORT_SYMBOL(ldlm_cli_cancel_list_local);
@@ -1462,7 +1439,7 @@ static ldlm_policy_res_t ldlm_cancel_no_wait_policy(struct ldlm_namespace *ns,
}
unlock_res_and_lock(lock);
- RETURN(result);
+ return result;
}
/**
@@ -1631,7 +1608,6 @@ static int ldlm_prepare_lru_list(struct ldlm_namespace *ns, struct list_head *ca
ldlm_cancel_lru_policy_t pf;
struct ldlm_lock *lock, *next;
int added = 0, unused, remained;
- ENTRY;
spin_lock(&ns->ns_lock);
unused = ns->ns_nr_unused;
@@ -1754,7 +1730,7 @@ static int ldlm_prepare_lru_list(struct ldlm_namespace *ns, struct list_head *ca
unused--;
}
spin_unlock(&ns->ns_lock);
- RETURN(added);
+ return added;
}
int ldlm_cancel_lru_local(struct ldlm_namespace *ns, struct list_head *cancels,
@@ -1782,16 +1758,15 @@ int ldlm_cancel_lru(struct ldlm_namespace *ns, int nr,
{
LIST_HEAD(cancels);
int count, rc;
- ENTRY;
/* Just prepare the list of locks, do not actually cancel them yet.
* Locks are cancelled later in a separate thread. */
count = ldlm_prepare_lru_list(ns, &cancels, nr, 0, flags);
rc = ldlm_bl_to_thread_list(ns, NULL, &cancels, count, cancel_flags);
if (rc == 0)
- RETURN(count);
+ return count;
- RETURN(0);
+ return 0;
}
/**
@@ -1807,7 +1782,6 @@ int ldlm_cancel_resource_local(struct ldlm_resource *res,
{
struct ldlm_lock *lock;
int count = 0;
- ENTRY;
lock_res(res);
list_for_each_entry(lock, &res->lr_granted, l_res_link) {
@@ -1848,7 +1822,7 @@ int ldlm_cancel_resource_local(struct ldlm_resource *res,
}
unlock_res(res);
- RETURN(ldlm_cli_cancel_list_local(cancels, count, cancel_flags));
+ return ldlm_cli_cancel_list_local(cancels, count, cancel_flags);
}
EXPORT_SYMBOL(ldlm_cancel_resource_local);
@@ -1867,10 +1841,9 @@ int ldlm_cli_cancel_list(struct list_head *cancels, int count,
{
struct ldlm_lock *lock;
int res = 0;
- ENTRY;
if (list_empty(cancels) || count == 0)
- RETURN(0);
+ return 0;
/* XXX: requests (both batched and not) could be sent in parallel.
* Usually it is enough to have just 1 RPC, but it is possible that
@@ -1906,7 +1879,7 @@ int ldlm_cli_cancel_list(struct list_head *cancels, int count,
ldlm_lock_list_put(cancels, l_bl_ast, res);
}
LASSERT(count == 0);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_cli_cancel_list);
@@ -1926,13 +1899,12 @@ int ldlm_cli_cancel_unused_resource(struct ldlm_namespace *ns,
LIST_HEAD(cancels);
int count;
int rc;
- ENTRY;
res = ldlm_resource_get(ns, NULL, res_id, 0, 0);
if (res == NULL) {
/* This is not a problem. */
CDEBUG(D_INFO, "No resource "LPU64"\n", res_id->name[0]);
- RETURN(0);
+ return 0;
}
LDLM_RESOURCE_ADDREF(res);
@@ -1944,7 +1916,7 @@ int ldlm_cli_cancel_unused_resource(struct ldlm_namespace *ns,
LDLM_RESOURCE_DELREF(res);
ldlm_resource_putref(res);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ldlm_cli_cancel_unused_resource);
@@ -1986,19 +1958,17 @@ int ldlm_cli_cancel_unused(struct ldlm_namespace *ns,
.lc_opaque = opaque,
};
- ENTRY;
-
if (ns == NULL)
- RETURN(ELDLM_OK);
+ return ELDLM_OK;
if (res_id != NULL) {
- RETURN(ldlm_cli_cancel_unused_resource(ns, res_id, NULL,
+ return ldlm_cli_cancel_unused_resource(ns, res_id, NULL,
LCK_MINMODE, flags,
- opaque));
+ opaque);
} else {
cfs_hash_for_each_nolock(ns->ns_rs_hash,
ldlm_cli_hash_cancel_unused, &arg);
- RETURN(ELDLM_OK);
+ return ELDLM_OK;
}
}
EXPORT_SYMBOL(ldlm_cli_cancel_unused);
@@ -2012,10 +1982,8 @@ int ldlm_resource_foreach(struct ldlm_resource *res, ldlm_iterator_t iter,
struct ldlm_lock *lock;
int rc = LDLM_ITER_CONTINUE;
- ENTRY;
-
if (!res)
- RETURN(LDLM_ITER_CONTINUE);
+ return LDLM_ITER_CONTINUE;
lock_res(res);
list_for_each_safe(tmp, next, &res->lr_granted) {
@@ -2040,7 +2008,7 @@ int ldlm_resource_foreach(struct ldlm_resource *res, ldlm_iterator_t iter,
}
out:
unlock_res(res);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ldlm_resource_foreach);
@@ -2069,7 +2037,10 @@ void ldlm_namespace_foreach(struct ldlm_namespace *ns,
ldlm_iterator_t iter, void *closure)
{
- struct iter_helper_data helper = { iter: iter, closure: closure };
+ struct iter_helper_data helper = {
+ .iter = iter,
+ .closure = closure,
+ };
cfs_hash_for_each_nolock(ns->ns_rs_hash,
ldlm_res_iter_helper, &helper);
@@ -2088,7 +2059,6 @@ int ldlm_resource_iterate(struct ldlm_namespace *ns,
{
struct ldlm_resource *res;
int rc;
- ENTRY;
if (ns == NULL) {
CERROR("must pass in namespace\n");
@@ -2097,13 +2067,13 @@ int ldlm_resource_iterate(struct ldlm_namespace *ns,
res = ldlm_resource_get(ns, NULL, res_id, 0, 0);
if (res == NULL)
- RETURN(0);
+ return 0;
LDLM_RESOURCE_ADDREF(res);
rc = ldlm_resource_foreach(res, iter, data);
LDLM_RESOURCE_DELREF(res);
ldlm_resource_putref(res);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ldlm_resource_iterate);
@@ -2137,7 +2107,6 @@ static int replay_lock_interpret(const struct lu_env *env,
struct ldlm_reply *reply;
struct obd_export *exp;
- ENTRY;
atomic_dec(&req->rq_import->imp_replay_inflight);
if (rc != ELDLM_OK)
GOTO(out, rc);
@@ -2178,7 +2147,7 @@ out:
if (rc != ELDLM_OK)
ptlrpc_connect_import(req->rq_import);
- RETURN(rc);
+ return rc;
}
static int replay_one_lock(struct obd_import *imp, struct ldlm_lock *lock)
@@ -2187,13 +2156,11 @@ static int replay_one_lock(struct obd_import *imp, struct ldlm_lock *lock)
struct ldlm_async_args *aa;
struct ldlm_request *body;
int flags;
- ENTRY;
-
/* Bug 11974: Do not replay a lock which is actively being canceled */
if (lock->l_flags & LDLM_FL_CANCELING) {
LDLM_DEBUG(lock, "Not replaying canceled lock:");
- RETURN(0);
+ return 0;
}
/* If this is reply-less callback lock, we cannot replay it, since
@@ -2202,7 +2169,7 @@ static int replay_one_lock(struct obd_import *imp, struct ldlm_lock *lock)
if (lock->l_flags & LDLM_FL_CANCEL_ON_BLOCK) {
LDLM_DEBUG(lock, "Not replaying reply-less lock:");
ldlm_lock_cancel(lock);
- RETURN(0);
+ return 0;
}
/*
@@ -2231,7 +2198,7 @@ static int replay_one_lock(struct obd_import *imp, struct ldlm_lock *lock)
req = ptlrpc_request_alloc_pack(imp, &RQF_LDLM_ENQUEUE,
LUSTRE_DLM_VERSION, LDLM_ENQUEUE);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* We're part of recovery, so don't wait for it. */
req->rq_send_state = LUSTRE_IMP_REPLAY_LOCKS;
@@ -2261,7 +2228,7 @@ static int replay_one_lock(struct obd_import *imp, struct ldlm_lock *lock)
req->rq_interpret_reply = (ptlrpc_interpterer_t)replay_lock_interpret;
ptlrpcd_add_req(req, PDL_POLICY_LOCAL, -1);
- RETURN(0);
+ return 0;
}
/**
@@ -2300,13 +2267,11 @@ int ldlm_replay_locks(struct obd_import *imp)
struct ldlm_lock *lock, *next;
int rc = 0;
- ENTRY;
-
LASSERT(atomic_read(&imp->imp_replay_inflight) == 0);
/* don't replay locks if import failed recovery */
if (imp->imp_vbr_failed)
- RETURN(0);
+ return 0;
/* ensure this doesn't fall to 0 before all have been queued */
atomic_inc(&imp->imp_replay_inflight);
@@ -2328,6 +2293,6 @@ int ldlm_replay_locks(struct obd_import *imp)
atomic_dec(&imp->imp_replay_inflight);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ldlm_replay_locks);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
index 9052dc5e7ad..208751a154b 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
@@ -48,18 +48,23 @@
struct kmem_cache *ldlm_resource_slab, *ldlm_lock_slab;
-atomic_t ldlm_srv_namespace_nr = ATOMIC_INIT(0);
-atomic_t ldlm_cli_namespace_nr = ATOMIC_INIT(0);
+int ldlm_srv_namespace_nr = 0;
+int ldlm_cli_namespace_nr = 0;
struct mutex ldlm_srv_namespace_lock;
LIST_HEAD(ldlm_srv_namespace_list);
struct mutex ldlm_cli_namespace_lock;
-LIST_HEAD(ldlm_cli_namespace_list);
+/* Client Namespaces that have active resources in them.
+ * Once all resources go away, ldlm_poold moves such namespaces to the
+ * inactive list */
+LIST_HEAD(ldlm_cli_active_namespace_list);
+/* Client namespaces that don't have any locks in them */
+LIST_HEAD(ldlm_cli_inactive_namespace_list);
-proc_dir_entry_t *ldlm_type_proc_dir = NULL;
-proc_dir_entry_t *ldlm_ns_proc_dir = NULL;
-proc_dir_entry_t *ldlm_svc_proc_dir = NULL;
+struct proc_dir_entry *ldlm_type_proc_dir = NULL;
+struct proc_dir_entry *ldlm_ns_proc_dir = NULL;
+struct proc_dir_entry *ldlm_svc_proc_dir = NULL;
extern unsigned int ldlm_cancel_unused_locks_before_replay;
@@ -73,7 +78,7 @@ static ssize_t lprocfs_wr_dump_ns(struct file *file, const char *buffer,
{
ldlm_dump_all_namespaces(LDLM_NAMESPACE_SERVER, D_DLMTRACE);
ldlm_dump_all_namespaces(LDLM_NAMESPACE_CLIENT, D_DLMTRACE);
- RETURN(count);
+ return count;
}
LPROC_SEQ_FOPS_WR_ONLY(ldlm, dump_ns);
@@ -90,7 +95,6 @@ int ldlm_proc_setup(void)
{ "cancel_unused_locks_before_replay", &ldlm_rw_uint_fops,
&ldlm_cancel_unused_locks_before_replay },
{ NULL }};
- ENTRY;
LASSERT(ldlm_ns_proc_dir == NULL);
ldlm_type_proc_dir = lprocfs_register(OBD_LDLM_DEVICENAME,
@@ -122,7 +126,7 @@ int ldlm_proc_setup(void)
rc = lprocfs_add_vars(ldlm_type_proc_dir, list, NULL);
- RETURN(0);
+ return 0;
err_ns:
lprocfs_remove(&ldlm_ns_proc_dir);
@@ -132,7 +136,7 @@ err:
ldlm_svc_proc_dir = NULL;
ldlm_type_proc_dir = NULL;
ldlm_ns_proc_dir = NULL;
- RETURN(rc);
+ return rc;
}
void ldlm_proc_cleanup(void)
@@ -325,7 +329,7 @@ int ldlm_namespace_proc_register(struct ldlm_namespace *ns)
{
struct lprocfs_vars lock_vars[2];
char lock_name[MAX_STRING_SIZE + 1];
- proc_dir_entry_t *ns_pde;
+ struct proc_dir_entry *ns_pde;
LASSERT(ns != NULL);
LASSERT(ns->ns_rs_hash != NULL);
@@ -563,14 +567,13 @@ struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obd, char *name,
cfs_hash_bd_t bd;
int idx;
int rc;
- ENTRY;
LASSERT(obd != NULL);
rc = ldlm_get_ref();
if (rc) {
CERROR("ldlm_get_ref failed: %d\n", rc);
- RETURN(NULL);
+ return NULL;
}
for (idx = 0;;idx++) {
@@ -636,7 +639,7 @@ struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obd, char *name,
GOTO(out_hash, rc);
}
- idx = atomic_read(ldlm_namespace_nr(client));
+ idx = ldlm_namespace_nr_read(client);
rc = ldlm_pool_init(&ns->ns_pool, ns, idx, client);
if (rc) {
CERROR("Can't initialize lock pool, rc %d\n", rc);
@@ -644,7 +647,7 @@ struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obd, char *name,
}
ldlm_namespace_register(ns, client);
- RETURN(ns);
+ return ns;
out_proc:
ldlm_namespace_proc_unregister(ns);
ldlm_namespace_cleanup(ns, 0);
@@ -654,7 +657,7 @@ out_ns:
OBD_FREE_PTR(ns);
out_ref:
ldlm_put_ref();
- RETURN(NULL);
+ return NULL;
}
EXPORT_SYMBOL(ldlm_namespace_new);
@@ -803,8 +806,6 @@ EXPORT_SYMBOL(ldlm_namespace_cleanup);
*/
static int __ldlm_namespace_free(struct ldlm_namespace *ns, int force)
{
- ENTRY;
-
/* At shutdown time, don't call the cancellation callback */
ldlm_namespace_cleanup(ns, force ? LDLM_FL_LOCAL_ONLY : 0);
@@ -836,13 +837,13 @@ force_wait:
"with %d resources in use, (rc=%d)\n",
ldlm_ns_name(ns),
atomic_read(&ns->ns_bref), rc);
- RETURN(ELDLM_NAMESPACE_EXISTS);
+ return ELDLM_NAMESPACE_EXISTS;
}
CDEBUG(D_DLMTRACE, "dlm namespace %s free done waiting\n",
ldlm_ns_name(ns));
}
- RETURN(ELDLM_OK);
+ return ELDLM_OK;
}
/**
@@ -859,9 +860,8 @@ void ldlm_namespace_free_prior(struct ldlm_namespace *ns,
int force)
{
int rc;
- ENTRY;
+
if (!ns) {
- EXIT;
return;
}
@@ -886,7 +886,6 @@ void ldlm_namespace_free_prior(struct ldlm_namespace *ns,
rc = __ldlm_namespace_free(ns, 1);
LASSERT(rc == 0);
}
- EXIT;
}
/**
@@ -896,9 +895,7 @@ void ldlm_namespace_free_prior(struct ldlm_namespace *ns,
*/
void ldlm_namespace_free_post(struct ldlm_namespace *ns)
{
- ENTRY;
if (!ns) {
- EXIT;
return;
}
@@ -917,7 +914,6 @@ void ldlm_namespace_free_post(struct ldlm_namespace *ns)
LASSERT(list_empty(&ns->ns_list_chain));
OBD_FREE_PTR(ns);
ldlm_put_ref();
- EXIT;
}
/**
@@ -953,6 +949,12 @@ void ldlm_namespace_get(struct ldlm_namespace *ns)
}
EXPORT_SYMBOL(ldlm_namespace_get);
+/* This is only for callers that care about refcount */
+int ldlm_namespace_get_return(struct ldlm_namespace *ns)
+{
+ return atomic_inc_return(&ns->ns_bref);
+}
+
void ldlm_namespace_put(struct ldlm_namespace *ns)
{
if (atomic_dec_and_lock(&ns->ns_bref, &ns->ns_lock)) {
@@ -967,8 +969,8 @@ void ldlm_namespace_register(struct ldlm_namespace *ns, ldlm_side_t client)
{
mutex_lock(ldlm_namespace_lock(client));
LASSERT(list_empty(&ns->ns_list_chain));
- list_add(&ns->ns_list_chain, ldlm_namespace_list(client));
- atomic_inc(ldlm_namespace_nr(client));
+ list_add(&ns->ns_list_chain, ldlm_namespace_inactive_list(client));
+ ldlm_namespace_nr_inc(client);
mutex_unlock(ldlm_namespace_lock(client));
}
@@ -981,12 +983,13 @@ void ldlm_namespace_unregister(struct ldlm_namespace *ns, ldlm_side_t client)
* using list_empty(&ns->ns_list_chain). This is why it is
* important to use list_del_init() here. */
list_del_init(&ns->ns_list_chain);
- atomic_dec(ldlm_namespace_nr(client));
+ ldlm_namespace_nr_dec(client);
mutex_unlock(ldlm_namespace_lock(client));
}
/** Should be called with ldlm_namespace_lock(client) taken. */
-void ldlm_namespace_move_locked(struct ldlm_namespace *ns, ldlm_side_t client)
+void ldlm_namespace_move_to_active_locked(struct ldlm_namespace *ns,
+ ldlm_side_t client)
{
LASSERT(!list_empty(&ns->ns_list_chain));
LASSERT(mutex_is_locked(ldlm_namespace_lock(client)));
@@ -994,6 +997,16 @@ void ldlm_namespace_move_locked(struct ldlm_namespace *ns, ldlm_side_t client)
}
/** Should be called with ldlm_namespace_lock(client) taken. */
+void ldlm_namespace_move_to_inactive_locked(struct ldlm_namespace *ns,
+ ldlm_side_t client)
+{
+ LASSERT(!list_empty(&ns->ns_list_chain));
+ LASSERT(mutex_is_locked(ldlm_namespace_lock(client)));
+ list_move_tail(&ns->ns_list_chain,
+ ldlm_namespace_inactive_list(client));
+}
+
+/** Should be called with ldlm_namespace_lock(client) taken. */
struct ldlm_namespace *ldlm_namespace_first_locked(ldlm_side_t client)
{
LASSERT(mutex_is_locked(ldlm_namespace_lock(client)));
@@ -1049,6 +1062,7 @@ ldlm_resource_get(struct ldlm_namespace *ns, struct ldlm_resource *parent,
struct ldlm_resource *res;
cfs_hash_bd_t bd;
__u64 version;
+ int ns_refcount = 0;
LASSERT(ns != NULL);
LASSERT(parent == NULL);
@@ -1119,7 +1133,7 @@ ldlm_resource_get(struct ldlm_namespace *ns, struct ldlm_resource *parent,
/* We won! Let's add the resource. */
cfs_hash_bd_add_locked(ns->ns_rs_hash, &bd, &res->lr_hash);
if (cfs_hash_bd_count_get(&bd) == 1)
- ldlm_namespace_get(ns);
+ ns_refcount = ldlm_namespace_get_return(ns);
cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1);
if (ns->ns_lvbo && ns->ns_lvbo->lvbo_init) {
@@ -1128,8 +1142,9 @@ ldlm_resource_get(struct ldlm_namespace *ns, struct ldlm_resource *parent,
OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_CREATE_RESOURCE, 2);
rc = ns->ns_lvbo->lvbo_init(res);
if (rc < 0) {
- CERROR("lvbo_init failed for resource "
- LPU64": rc %d\n", name->name[0], rc);
+ CERROR("%s: lvbo_init failed for resource "LPX64":"
+ LPX64": rc = %d\n", ns->ns_obd->obd_name,
+ name->name[0], name->name[1], rc);
if (res->lr_lvb_data) {
OBD_FREE(res->lr_lvb_data, res->lr_lvb_len);
res->lr_lvb_data = NULL;
@@ -1144,6 +1159,16 @@ ldlm_resource_get(struct ldlm_namespace *ns, struct ldlm_resource *parent,
/* We create resource with locked lr_lvb_mutex. */
mutex_unlock(&res->lr_lvb_mutex);
+ /* Let's see if we happened to be the very first resource in this
+ * namespace. If so, and this is a client namespace, we need to move
+ * the namespace into the active namespaces list to be patrolled by
+ * the ldlm_poold. */
+ if (ns_is_client(ns) && ns_refcount == 1) {
+ mutex_lock(ldlm_namespace_lock(LDLM_NAMESPACE_CLIENT));
+ ldlm_namespace_move_to_active_locked(ns, LDLM_NAMESPACE_CLIENT);
+ mutex_unlock(ldlm_namespace_lock(LDLM_NAMESPACE_CLIENT));
+ }
+
return res;
}
EXPORT_SYMBOL(ldlm_resource_get);
@@ -1249,7 +1274,7 @@ void ldlm_resource_add_lock(struct ldlm_resource *res, struct list_head *head,
LDLM_DEBUG(lock, "About to add this lock:\n");
- if (lock->l_destroyed) {
+ if (lock->l_flags & LDLM_FL_DESTROYED) {
CDEBUG(D_OTHER, "Lock destroyed, not adding to resource\n");
return;
}
@@ -1274,7 +1299,7 @@ void ldlm_resource_insert_lock_after(struct ldlm_lock *original,
ldlm_resource_dump(D_INFO, res);
LDLM_DEBUG(new, "About to insert this lock after %p:\n", original);
- if (new->l_destroyed) {
+ if (new->l_flags & LDLM_FL_DESTROYED) {
CDEBUG(D_OTHER, "Lock destroyed, not adding to resource\n");
goto out;
}
diff --git a/drivers/staging/lustre/lustre/libcfs/Makefile b/drivers/staging/lustre/lustre/libcfs/Makefile
index bf5c563dcac..6e489d7aaa8 100644
--- a/drivers/staging/lustre/lustre/libcfs/Makefile
+++ b/drivers/staging/lustre/lustre/libcfs/Makefile
@@ -11,7 +11,7 @@ libcfs-linux-objs += linux-crypto-adler.o
libcfs-linux-objs := $(addprefix linux/,$(libcfs-linux-objs))
libcfs-all-objs := debug.o fail.o nidstrings.o module.o tracefile.o \
- watchdog.o libcfs_string.o hash.o kernel_user_comm.o \
+ libcfs_string.o hash.o kernel_user_comm.o \
prng.o workitem.o upcall_cache.o libcfs_cpu.o \
libcfs_mem.o libcfs_lock.o
diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c
index 5a87b083207..9b9c45116ee 100644
--- a/drivers/staging/lustre/lustre/libcfs/debug.c
+++ b/drivers/staging/lustre/lustre/libcfs/debug.c
@@ -335,9 +335,10 @@ libcfs_debug_str2mask(int *mask, const char *str, int is_subsys)
*/
void libcfs_debug_dumplog_internal(void *arg)
{
- DECL_JOURNAL_DATA;
+ void *journal_info;
- PUSH_JOURNAL;
+ journal_info = current->journal_info;
+ current->journal_info = NULL;
if (strncmp(libcfs_debug_file_path_arr, "NONE", 4) != 0) {
snprintf(debug_file_name, sizeof(debug_file_name) - 1,
@@ -348,7 +349,8 @@ void libcfs_debug_dumplog_internal(void *arg)
cfs_tracefile_dump_all_pages(debug_file_name);
libcfs_run_debug_log_upcall(debug_file_name);
}
- POP_JOURNAL;
+
+ current->journal_info = journal_info;
}
int libcfs_debug_dumplog_thread(void *arg)
@@ -361,8 +363,7 @@ int libcfs_debug_dumplog_thread(void *arg)
void libcfs_debug_dumplog(void)
{
wait_queue_t wait;
- task_t *dumper;
- ENTRY;
+ struct task_struct *dumper;
/* we're being careful to ensure that the kernel thread is
* able to set our state to running as it exits before we
@@ -459,14 +460,6 @@ void libcfs_debug_set_level(unsigned int debug_level)
EXPORT_SYMBOL(libcfs_debug_set_level);
-long libcfs_log_return(struct libcfs_debug_msg_data *msgdata, long rc)
-{
- libcfs_debug_msg(msgdata, "Process leaving (rc=%lu : %ld : %lx)\n",
- rc, rc, rc);
- return rc;
-}
-EXPORT_SYMBOL(libcfs_log_return);
-
void libcfs_log_goto(struct libcfs_debug_msg_data *msgdata, const char *label,
long_ptr_t rc)
{
diff --git a/drivers/staging/lustre/lustre/libcfs/hash.c b/drivers/staging/lustre/lustre/libcfs/hash.c
index 98c76dfac3d..0dd12c8c91b 100644
--- a/drivers/staging/lustre/lustre/libcfs/hash.c
+++ b/drivers/staging/lustre/lustre/libcfs/hash.c
@@ -1026,8 +1026,6 @@ cfs_hash_create(char *name, unsigned cur_bits, unsigned max_bits,
cfs_hash_t *hs;
int len;
- ENTRY;
-
CLASSERT(CFS_HASH_THETA_BITS < 15);
LASSERT(name != NULL);
@@ -1055,7 +1053,7 @@ cfs_hash_create(char *name, unsigned cur_bits, unsigned max_bits,
CFS_HASH_NAME_LEN : CFS_HASH_BIGNAME_LEN;
LIBCFS_ALLOC(hs, offsetof(cfs_hash_t, hs_name[len]));
if (hs == NULL)
- RETURN(NULL);
+ return NULL;
strncpy(hs->hs_name, name, len);
hs->hs_name[len - 1] = '\0';
@@ -1087,7 +1085,7 @@ cfs_hash_create(char *name, unsigned cur_bits, unsigned max_bits,
return hs;
LIBCFS_FREE(hs, offsetof(cfs_hash_t, hs_name[len]));
- RETURN(NULL);
+ return NULL;
}
EXPORT_SYMBOL(cfs_hash_create);
@@ -1101,7 +1099,6 @@ cfs_hash_destroy(cfs_hash_t *hs)
struct hlist_node *pos;
cfs_hash_bd_t bd;
int i;
- ENTRY;
LASSERT(hs != NULL);
LASSERT(!cfs_hash_is_exiting(hs) &&
@@ -1152,8 +1149,6 @@ cfs_hash_destroy(cfs_hash_t *hs)
i = cfs_hash_with_bigname(hs) ?
CFS_HASH_BIGNAME_LEN : CFS_HASH_NAME_LEN;
LIBCFS_FREE(hs, offsetof(cfs_hash_t, hs_name[i]));
-
- EXIT;
}
cfs_hash_t *cfs_hash_getref(cfs_hash_t *hs)
@@ -1449,7 +1444,6 @@ cfs_hash_for_each_tight(cfs_hash_t *hs, cfs_hash_for_each_cb_t func,
int excl = !!remove_safe;
int loop = 0;
int i;
- ENTRY;
cfs_hash_for_each_enter(hs);
@@ -1489,7 +1483,7 @@ cfs_hash_for_each_tight(cfs_hash_t *hs, cfs_hash_for_each_cb_t func,
cfs_hash_unlock(hs, 0);
cfs_hash_for_each_exit(hs);
- RETURN(count);
+ return count;
}
typedef struct {
@@ -1594,7 +1588,6 @@ cfs_hash_for_each_relax(cfs_hash_t *hs, cfs_hash_for_each_cb_t func, void *data)
int stop_on_change;
int rc;
int i;
- ENTRY;
stop_on_change = cfs_hash_with_rehash_key(hs) ||
!cfs_hash_with_no_itemref(hs) ||
@@ -1649,23 +1642,21 @@ int
cfs_hash_for_each_nolock(cfs_hash_t *hs,
cfs_hash_for_each_cb_t func, void *data)
{
- ENTRY;
-
if (cfs_hash_with_no_lock(hs) ||
cfs_hash_with_rehash_key(hs) ||
!cfs_hash_with_no_itemref(hs))
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
if (CFS_HOP(hs, get) == NULL ||
(CFS_HOP(hs, put) == NULL &&
CFS_HOP(hs, put_locked) == NULL))
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
cfs_hash_for_each_enter(hs);
cfs_hash_for_each_relax(hs, func, data);
cfs_hash_for_each_exit(hs);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(cfs_hash_for_each_nolock);
@@ -1685,7 +1676,6 @@ cfs_hash_for_each_empty(cfs_hash_t *hs,
cfs_hash_for_each_cb_t func, void *data)
{
unsigned i = 0;
- ENTRY;
if (cfs_hash_with_no_lock(hs))
return -EOPNOTSUPP;
@@ -1701,7 +1691,7 @@ cfs_hash_for_each_empty(cfs_hash_t *hs,
hs->hs_name, i++);
}
cfs_hash_for_each_exit(hs);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(cfs_hash_for_each_empty);
diff --git a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
index d6d3b2e0f30..74a0db5c154 100644
--- a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
+++ b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
@@ -246,10 +246,9 @@ EXPORT_SYMBOL(libcfs_kkuc_group_add);
int libcfs_kkuc_group_rem(int uid, int group)
{
struct kkuc_reg *reg, *next;
- ENTRY;
if (kkuc_groups[group].next == NULL)
- RETURN(0);
+ return 0;
if (uid == 0) {
/* Broadcast a shutdown message */
@@ -275,7 +274,7 @@ int libcfs_kkuc_group_rem(int uid, int group)
}
up_write(&kg_sem);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(libcfs_kkuc_group_rem);
@@ -284,7 +283,6 @@ int libcfs_kkuc_group_put(int group, void *payload)
struct kkuc_reg *reg;
int rc = 0;
int one_success = 0;
- ENTRY;
down_read(&kg_sem);
list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
@@ -305,7 +303,7 @@ int libcfs_kkuc_group_put(int group, void *payload)
if (one_success)
rc = 0;
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(libcfs_kkuc_group_put);
@@ -320,16 +318,15 @@ int libcfs_kkuc_group_foreach(int group, libcfs_kkuc_cb_t cb_func,
{
struct kkuc_reg *reg;
int rc = 0;
- ENTRY;
if (group > KUC_GRP_MAX) {
CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* no link for this group */
if (kkuc_groups[group].next == NULL)
- RETURN(0);
+ return 0;
down_read(&kg_sem);
list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
@@ -339,7 +336,7 @@ int libcfs_kkuc_group_foreach(int group, libcfs_kkuc_cb_t cb_func,
}
up_read(&kg_sem);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(libcfs_kkuc_group_foreach);
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c b/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c
index 8e88eb59dd5..1fb37008cda 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c
@@ -33,9 +33,6 @@
* Author: liang@whamcloud.com
*/
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
#define DEBUG_SUBSYSTEM S_LNET
#include <linux/libcfs/libcfs.h>
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c b/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c
index 8d6c4adf2ee..a2ce4c0eb3d 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c
@@ -30,9 +30,6 @@
* Author: liang@whamcloud.com
*/
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
#define DEBUG_SUBSYSTEM S_LNET
#include <linux/libcfs/libcfs.h>
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c b/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c
index 87913730348..feab537c728 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c
@@ -31,9 +31,6 @@
* Author: liang@whamcloud.com
*/
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
#define DEBUG_SUBSYSTEM S_LNET
#include <linux/libcfs/libcfs.h>
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
index 9edccc99683..922debd0a41 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
@@ -69,7 +69,6 @@ int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
const char *debugstr;
char op = 0;
int newmask = minmask, i, len, found = 0;
- ENTRY;
/* <str> must be a list of tokens separated by whitespace
* and optionally an operator ('+' or '-'). If an operator
@@ -132,54 +131,6 @@ int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
}
EXPORT_SYMBOL(cfs_str2mask);
-/* Duplicate a string in a platform-independent way */
-char *cfs_strdup(const char *str, u_int32_t flags)
-{
- size_t lenz; /* length of str + zero byte */
- char *dup_str;
-
- lenz = strlen(str) + 1;
-
- dup_str = kmalloc(lenz, flags);
- if (dup_str == NULL)
- return NULL;
-
- memcpy(dup_str, str, lenz);
-
- return dup_str;
-}
-EXPORT_SYMBOL(cfs_strdup);
-
-/**
- * cfs_{v}snprintf() return the actual size that is printed rather than
- * the size that would be printed in standard functions.
- */
-/* safe vsnprintf */
-int cfs_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
-{
- int i;
-
- LASSERT(size > 0);
- i = vsnprintf(buf, size, fmt, args);
-
- return (i >= size ? size - 1 : i);
-}
-EXPORT_SYMBOL(cfs_vsnprintf);
-
-/* safe snprintf */
-int cfs_snprintf(char *buf, size_t size, const char *fmt, ...)
-{
- va_list args;
- int i;
-
- va_start(args, fmt);
- i = cfs_vsnprintf(buf, size, fmt, args);
- va_end(args);
-
- return i;
-}
-EXPORT_SYMBOL(cfs_snprintf);
-
/* get the first string out of @str */
char *cfs_firststr(char *str, size_t size)
{
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
index 95142d19097..00ab8fdc105 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
@@ -76,62 +76,22 @@ struct cfs_cpt_data {
static struct cfs_cpt_data cpt_data;
-void
-cfs_cpu_core_siblings(int cpu, cpumask_t *mask)
+static void cfs_cpu_core_siblings(int cpu, cpumask_t *mask)
{
/* return cpumask of cores in the same socket */
cpumask_copy(mask, topology_core_cpumask(cpu));
}
-EXPORT_SYMBOL(cfs_cpu_core_siblings);
-
-/* return number of cores in the same socket of \a cpu */
-int
-cfs_cpu_core_nsiblings(int cpu)
-{
- int num;
-
- down(&cpt_data.cpt_mutex);
-
- cfs_cpu_core_siblings(cpu, cpt_data.cpt_cpumask);
- num = cpus_weight(*cpt_data.cpt_cpumask);
-
- up(&cpt_data.cpt_mutex);
-
- return num;
-}
-EXPORT_SYMBOL(cfs_cpu_core_nsiblings);
/* return cpumask of HTs in the same core */
-void
-cfs_cpu_ht_siblings(int cpu, cpumask_t *mask)
+static void cfs_cpu_ht_siblings(int cpu, cpumask_t *mask)
{
cpumask_copy(mask, topology_thread_cpumask(cpu));
}
-EXPORT_SYMBOL(cfs_cpu_ht_siblings);
-/* return number of HTs in the same core of \a cpu */
-int
-cfs_cpu_ht_nsiblings(int cpu)
-{
- int num;
-
- down(&cpt_data.cpt_mutex);
-
- cfs_cpu_ht_siblings(cpu, cpt_data.cpt_cpumask);
- num = cpus_weight(*cpt_data.cpt_cpumask);
-
- up(&cpt_data.cpt_mutex);
-
- return num;
-}
-EXPORT_SYMBOL(cfs_cpu_ht_nsiblings);
-
-void
-cfs_node_to_cpumask(int node, cpumask_t *mask)
+static void cfs_node_to_cpumask(int node, cpumask_t *mask)
{
cpumask_copy(mask, cpumask_of_node(node));
}
-EXPORT_SYMBOL(cfs_node_to_cpumask);
void
cfs_cpt_table_free(struct cfs_cpt_table *cptab)
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c
index 8e35777b4da..b6c79bc177a 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c
@@ -274,6 +274,8 @@ static int adler32;
int cfs_crypto_register(void)
{
+ request_module("crc32c");
+
adler32 = cfs_crypto_adler32_register();
/* check all algorithms and do performance test */
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
index f236510a2f3..ea9e9490031 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
@@ -65,20 +65,6 @@ int cfs_curproc_groups_nr(void)
return nr;
}
-void cfs_curproc_groups_dump(gid_t *array, int size)
-{
- task_lock(current);
- size = min_t(int, size, current_cred()->group_info->ngroups);
- memcpy(array, current_cred()->group_info->blocks[0], size * sizeof(__u32));
- task_unlock(current);
-}
-
-
-int current_is_in_group(gid_t gid)
-{
- return in_group_p(gid);
-}
-
/* Currently all the CFS_CAP_* defines match CAP_* ones. */
#define cfs_cap_pack(cap) (cap)
#define cfs_cap_unpack(cap) (cap)
@@ -226,16 +212,15 @@ int cfs_get_environ(const char *key, char *value, int *val_len)
int key_len = strlen(key);
unsigned long addr;
int rc;
- ENTRY;
buffer = kmalloc(buf_len, GFP_USER);
if (!buffer)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mm = get_task_mm(current);
if (!mm) {
kfree(buffer);
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* Avoid deadlocks on mmap_sem if called from sys_mmap_pgoff(),
@@ -318,8 +303,6 @@ out:
EXPORT_SYMBOL(cfs_get_environ);
EXPORT_SYMBOL(cfs_curproc_groups_nr);
-EXPORT_SYMBOL(cfs_curproc_groups_dump);
-EXPORT_SYMBOL(current_is_in_group);
EXPORT_SYMBOL(cfs_cap_raise);
EXPORT_SYMBOL(cfs_cap_lower);
EXPORT_SYMBOL(cfs_cap_raised);
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c
index e2c195b8dd5..ab1e7316847 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c
@@ -48,14 +48,10 @@
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/interrupt.h>
-#include <asm/uaccess.h>
#include <linux/completion.h>
-
#include <linux/fs.h>
-#include <linux/stat.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
-#include <linux/version.h>
# define DEBUG_SUBSYSTEM S_LNET
@@ -82,7 +78,6 @@ void libcfs_run_debug_log_upcall(char *file)
"HOME=/",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin",
NULL};
- ENTRY;
argv[0] = lnet_debug_log_upcall;
@@ -100,8 +95,6 @@ void libcfs_run_debug_log_upcall(char *file)
CDEBUG(D_HA, "Invoked LNET debug log upcall %s %s\n",
argv[0], argv[1]);
}
-
- EXIT;
}
void libcfs_run_upcall(char **argv)
@@ -112,7 +105,6 @@ void libcfs_run_upcall(char **argv)
"HOME=/",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin",
NULL};
- ENTRY;
argv[0] = lnet_upcall;
argc = 1;
@@ -145,7 +137,6 @@ void libcfs_run_lbug_upcall(struct libcfs_debug_msg_data *msgdata)
char *argv[6];
char buf[32];
- ENTRY;
snprintf (buf, sizeof buf, "%d", msgdata->msg_line);
argv[1] = "LBUG";
@@ -168,7 +159,7 @@ void lbug_with_loc(struct libcfs_debug_msg_data *msgdata)
/* not reached */
}
- libcfs_debug_dumpstack(NULL);
+ dump_stack();
if (!libcfs_panic_on_lbug)
libcfs_debug_dumplog();
libcfs_run_lbug_upcall(msgdata);
@@ -179,54 +170,6 @@ void lbug_with_loc(struct libcfs_debug_msg_data *msgdata)
schedule();
}
-
-#include <linux/nmi.h>
-#include <asm/stacktrace.h>
-
-
-static int print_trace_stack(void *data, char *name)
-{
- printk(" <%s> ", name);
- return 0;
-}
-
-# define RELIABLE reliable
-# define DUMP_TRACE_CONST const
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
- char fmt[32];
- touch_nmi_watchdog();
- sprintf(fmt, " [<%016lx>] %s%%s\n", addr, RELIABLE ? "": "? ");
- __print_symbol(fmt, addr);
-}
-
-static DUMP_TRACE_CONST struct stacktrace_ops print_trace_ops = {
- .stack = print_trace_stack,
- .address = print_trace_address,
- .walk_stack = print_context_stack,
-};
-
-void libcfs_debug_dumpstack(struct task_struct *tsk)
-{
- /* dump_stack() */
- /* show_trace() */
- if (tsk == NULL)
- tsk = current;
- printk("Pid: %d, comm: %.20s\n", tsk->pid, tsk->comm);
- /* show_trace_log_lvl() */
- printk("\nCall Trace:\n");
- dump_trace(tsk, NULL, NULL,
- 0,
- &print_trace_ops, NULL);
- printk("\n");
-}
-
-task_t *libcfs_current(void)
-{
- CWARN("current task struct is %p\n", current);
- return current;
-}
-
static int panic_notifier(struct notifier_block *self, unsigned long unused1,
void *unused2)
{
@@ -240,9 +183,9 @@ static int panic_notifier(struct notifier_block *self, unsigned long unused1,
}
static struct notifier_block libcfs_panic_notifier = {
- notifier_call : panic_notifier,
- next : NULL,
- priority : 10000
+ .notifier_call = panic_notifier,
+ .next = NULL,
+ .priority = 10000,
};
void libcfs_register_panic_notifier(void)
@@ -255,10 +198,6 @@ void libcfs_unregister_panic_notifier(void)
atomic_notifier_chain_unregister(&panic_notifier_list, &libcfs_panic_notifier);
}
-EXPORT_SYMBOL(libcfs_debug_dumpstack);
-EXPORT_SYMBOL(libcfs_current);
-
-
EXPORT_SYMBOL(libcfs_run_upcall);
EXPORT_SYMBOL(libcfs_run_lbug_upcall);
EXPORT_SYMBOL(lbug_with_loc);
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c
index 2c7d4a3d660..55296a3591d 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c
@@ -45,38 +45,37 @@ int libcfs_ioctl_getdata(char *buf, char *end, void *arg)
struct libcfs_ioctl_hdr *hdr;
struct libcfs_ioctl_data *data;
int err;
- ENTRY;
hdr = (struct libcfs_ioctl_hdr *)buf;
data = (struct libcfs_ioctl_data *)buf;
err = copy_from_user(buf, (void *)arg, sizeof(*hdr));
if (err)
- RETURN(err);
+ return err;
if (hdr->ioc_version != LIBCFS_IOCTL_VERSION) {
CERROR("PORTALS: version mismatch kernel vs application\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (hdr->ioc_len + buf >= end) {
CERROR("PORTALS: user buffer exceeds kernel buffer\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (hdr->ioc_len < sizeof(struct libcfs_ioctl_data)) {
CERROR("PORTALS: user buffer too small for ioctl\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
err = copy_from_user(buf, (void *)arg, hdr->ioc_len);
if (err)
- RETURN(err);
+ return err;
if (libcfs_ioctl_is_invalid(data)) {
CERROR("PORTALS: ioctl not correctly formatted\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (data->ioc_inllen1)
@@ -86,7 +85,7 @@ int libcfs_ioctl_getdata(char *buf, char *end, void *arg)
data->ioc_inlbuf2 = &data->ioc_bulk[0] +
cfs_size_round(data->ioc_inllen1);
- RETURN(0);
+ return 0;
}
int libcfs_ioctl_popdata(void *arg, void *data, int size)
@@ -137,7 +136,7 @@ static long libcfs_ioctl(struct file *file,
struct cfs_psdev_file pfile;
int rc = 0;
- if (current_fsuid() != 0)
+ if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if ( _IOC_TYPE(cmd) != IOC_LIBCFS_TYPE ||
@@ -171,13 +170,13 @@ static long libcfs_ioctl(struct file *file,
}
static struct file_operations libcfs_fops = {
- unlocked_ioctl: libcfs_ioctl,
- open : libcfs_psdev_open,
- release : libcfs_psdev_release
+ .unlocked_ioctl = libcfs_ioctl,
+ .open = libcfs_psdev_open,
+ .release = libcfs_psdev_release,
};
-psdev_t libcfs_dev = {
- LNET_MINOR,
- "lnet",
- &libcfs_fops
+struct miscdevice libcfs_dev = {
+ .minor = LNET_MINOR,
+ .name = "lnet",
+ .fops = &libcfs_fops,
};
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c
index b652a79a481..cc9829ffbdc 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c
@@ -81,22 +81,21 @@ add_wait_queue_exclusive_head(wait_queue_head_t *waitq, wait_queue_t *link)
EXPORT_SYMBOL(add_wait_queue_exclusive_head);
void
-waitq_wait(wait_queue_t *link, cfs_task_state_t state)
+waitq_wait(wait_queue_t *link, long state)
{
schedule();
}
EXPORT_SYMBOL(waitq_wait);
int64_t
-waitq_timedwait(wait_queue_t *link, cfs_task_state_t state,
- int64_t timeout)
+waitq_timedwait(wait_queue_t *link, long state, int64_t timeout)
{
return schedule_timeout(timeout);
}
EXPORT_SYMBOL(waitq_timedwait);
void
-schedule_timeout_and_set_state(cfs_task_state_t state, int64_t timeout)
+schedule_timeout_and_set_state(long state, int64_t timeout)
{
set_current_state(state);
schedule_timeout(timeout);
@@ -112,13 +111,13 @@ cfs_pause(cfs_duration_t ticks)
}
EXPORT_SYMBOL(cfs_pause);
-void cfs_init_timer(timer_list_t *t)
+void cfs_init_timer(struct timer_list *t)
{
init_timer(t);
}
EXPORT_SYMBOL(cfs_init_timer);
-void cfs_timer_init(timer_list_t *t, cfs_timer_func_t *func, void *arg)
+void cfs_timer_init(struct timer_list *t, cfs_timer_func_t *func, void *arg)
{
init_timer(t);
t->function = func;
@@ -126,31 +125,31 @@ void cfs_timer_init(timer_list_t *t, cfs_timer_func_t *func, void *arg)
}
EXPORT_SYMBOL(cfs_timer_init);
-void cfs_timer_done(timer_list_t *t)
+void cfs_timer_done(struct timer_list *t)
{
return;
}
EXPORT_SYMBOL(cfs_timer_done);
-void cfs_timer_arm(timer_list_t *t, cfs_time_t deadline)
+void cfs_timer_arm(struct timer_list *t, cfs_time_t deadline)
{
mod_timer(t, deadline);
}
EXPORT_SYMBOL(cfs_timer_arm);
-void cfs_timer_disarm(timer_list_t *t)
+void cfs_timer_disarm(struct timer_list *t)
{
del_timer(t);
}
EXPORT_SYMBOL(cfs_timer_disarm);
-int cfs_timer_is_armed(timer_list_t *t)
+int cfs_timer_is_armed(struct timer_list *t)
{
return timer_pending(t);
}
EXPORT_SYMBOL(cfs_timer_is_armed);
-cfs_time_t cfs_timer_deadline(timer_list_t *t)
+cfs_time_t cfs_timer_deadline(struct timer_list *t)
{
return t->expires;
}
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
index 522b28e99e4..fc6c9774948 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
@@ -54,9 +54,7 @@
#include <linux/fs.h>
#include <linux/file.h>
-#include <linux/stat.h>
#include <linux/list.h>
-#include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
@@ -564,7 +562,7 @@ int insert_proc(void)
{
#ifdef CONFIG_SYSCTL
if (lnet_table_header == NULL)
- lnet_table_header = cfs_register_sysctl_table(top_table, 0);
+ lnet_table_header = register_sysctl_table(top_table);
#endif
return 0;
}
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
index 855c7e87d96..e6069d78af6 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
@@ -36,7 +36,6 @@
#define DEBUG_SUBSYSTEM S_LNET
#include <linux/libcfs/libcfs.h>
-#include <linux/libcfs/libcfs.h>
#include <linux/if.h>
#include <linux/in.h>
@@ -641,8 +640,8 @@ libcfs_sock_connect (struct socket **sockp, int *fatal,
*fatal = !(rc == -EADDRNOTAVAIL);
CDEBUG_LIMIT(*fatal ? D_NETERROR : D_NET,
- "Error %d connecting %u.%u.%u.%u/%d -> %u.%u.%u.%u/%d\n", rc,
- HIPQUAD(local_ip), local_port, HIPQUAD(peer_ip), peer_port);
+ "Error %d connecting %pI4h/%d -> %pI4h/%d\n", rc,
+ &local_ip, local_port, &peer_ip, peer_port);
sock_release(*sockp);
return rc;
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
index 6f563436a25..162beee24a7 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
@@ -51,7 +51,7 @@ char *cfs_trace_console_buffers[NR_CPUS][CFS_TCD_TYPE_MAX];
struct rw_semaphore cfs_tracefile_sem;
-int cfs_tracefile_init_arch()
+int cfs_tracefile_init_arch(void)
{
int i;
int j;
@@ -96,7 +96,7 @@ out:
return -ENOMEM;
}
-void cfs_tracefile_fini_arch()
+void cfs_tracefile_fini_arch(void)
{
int i;
int j;
@@ -116,27 +116,27 @@ void cfs_tracefile_fini_arch()
fini_rwsem(&cfs_tracefile_sem);
}
-void cfs_tracefile_read_lock()
+void cfs_tracefile_read_lock(void)
{
down_read(&cfs_tracefile_sem);
}
-void cfs_tracefile_read_unlock()
+void cfs_tracefile_read_unlock(void)
{
up_read(&cfs_tracefile_sem);
}
-void cfs_tracefile_write_lock()
+void cfs_tracefile_write_lock(void)
{
down_write(&cfs_tracefile_sem);
}
-void cfs_tracefile_write_unlock()
+void cfs_tracefile_write_unlock(void)
{
up_write(&cfs_tracefile_sem);
}
-cfs_trace_buf_type_t cfs_trace_buf_idx_get()
+cfs_trace_buf_type_t cfs_trace_buf_idx_get(void)
{
if (in_irq())
return CFS_TCD_TYPE_IRQ;
@@ -269,7 +269,7 @@ void cfs_print_to_console(struct ptldebug_header *hdr, int mask,
int cfs_trace_max_debug_mb(void)
{
- int total_mb = (num_physpages >> (20 - PAGE_SHIFT));
+ int total_mb = (totalram_pages >> (20 - PAGE_SHIFT));
return MAX(512, (total_mb * 80)/100);
}
diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c
index 3372537c6f3..f3108c7f818 100644
--- a/drivers/staging/lustre/lustre/libcfs/module.c
+++ b/drivers/staging/lustre/lustre/libcfs/module.c
@@ -155,7 +155,6 @@ kportal_memhog_alloc (struct libcfs_device_userstate *ldu, int npages, int flags
static int libcfs_psdev_open(unsigned long flags, void *args)
{
struct libcfs_device_userstate *ldu;
- ENTRY;
try_module_get(THIS_MODULE);
@@ -166,14 +165,13 @@ static int libcfs_psdev_open(unsigned long flags, void *args)
}
*(struct libcfs_device_userstate **)args = ldu;
- RETURN(0);
+ return 0;
}
/* called when closing /dev/device */
static int libcfs_psdev_release(unsigned long flags, void *args)
{
struct libcfs_device_userstate *ldu;
- ENTRY;
ldu = (struct libcfs_device_userstate *)args;
if (ldu != NULL) {
@@ -182,7 +180,7 @@ static int libcfs_psdev_release(unsigned long flags, void *args)
}
module_put(THIS_MODULE);
- RETURN(0);
+ return 0;
}
static struct rw_semaphore ioctl_list_sem;
@@ -222,12 +220,11 @@ static int libcfs_ioctl_int(struct cfs_psdev_file *pfile,unsigned long cmd,
void *arg, struct libcfs_ioctl_data *data)
{
int err = -EINVAL;
- ENTRY;
switch (cmd) {
case IOC_LIBCFS_CLEAR_DEBUG:
libcfs_debug_clear_buffer();
- RETURN(0);
+ return 0;
/*
* case IOC_LIBCFS_PANIC:
* Handled in arch/cfs_module.c
@@ -235,9 +232,9 @@ static int libcfs_ioctl_int(struct cfs_psdev_file *pfile,unsigned long cmd,
case IOC_LIBCFS_MARK_DEBUG:
if (data->ioc_inlbuf1 == NULL ||
data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
- RETURN(-EINVAL);
+ return -EINVAL;
libcfs_debug_mark_buffer(data->ioc_inlbuf1);
- RETURN(0);
+ return 0;
#if LWT_SUPPORT
case IOC_LIBCFS_LWT_CONTROL:
err = lwt_control ((data->ioc_flags & 1) != 0,
@@ -301,7 +298,7 @@ static int libcfs_ioctl_int(struct cfs_psdev_file *pfile,unsigned long cmd,
ping(data);
symbol_put(kping_client);
}
- RETURN(0);
+ return 0;
}
default: {
@@ -322,7 +319,7 @@ static int libcfs_ioctl_int(struct cfs_psdev_file *pfile,unsigned long cmd,
}
}
- RETURN(err);
+ return err;
}
static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *arg)
@@ -330,11 +327,10 @@ static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *a
char *buf;
struct libcfs_ioctl_data *data;
int err = 0;
- ENTRY;
LIBCFS_ALLOC_GFP(buf, 1024, GFP_IOFS);
if (buf == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* 'cmd' and permissions get checked in our arch-specific caller */
if (libcfs_ioctl_getdata(buf, buf + 800, (void *)arg)) {
@@ -347,7 +343,7 @@ static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *a
out:
LIBCFS_FREE(buf, 1024);
- RETURN(err);
+ return err;
}
@@ -365,7 +361,7 @@ MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
MODULE_DESCRIPTION("Portals v3.1");
MODULE_LICENSE("GPL");
-extern psdev_t libcfs_dev;
+extern struct miscdevice libcfs_dev;
extern struct rw_semaphore cfs_tracefile_sem;
extern struct mutex cfs_trace_thread_mutex;
extern struct cfs_wi_sched *cfs_sched_rehash;
@@ -495,4 +491,6 @@ static void exit_libcfs_module(void)
libcfs_arch_cleanup();
}
-cfs_module(libcfs, "1.0.0", init_libcfs_module, exit_libcfs_module);
+MODULE_VERSION("1.0.0");
+module_init(init_libcfs_module);
+module_exit(exit_libcfs_module);
diff --git a/drivers/staging/lustre/lustre/libcfs/nidstrings.c b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
index ccfd1078a90..99c9e9d2493 100644
--- a/drivers/staging/lustre/lustre/libcfs/nidstrings.c
+++ b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
@@ -785,7 +785,6 @@ cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
struct cfs_lstr src;
struct cfs_lstr res;
int rc;
- ENTRY;
src.ls_str = str;
src.ls_len = len;
@@ -794,15 +793,15 @@ cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
rc = cfs_gettok(&src, ' ', &res);
if (rc == 0) {
cfs_free_nidlist(nidlist);
- RETURN(0);
+ return 0;
}
rc = parse_nidrange(&res, nidlist);
if (rc == 0) {
cfs_free_nidlist(nidlist);
- RETURN(0);
+ return 0;
}
}
- RETURN(1);
+ return 1;
}
/*
@@ -834,7 +833,6 @@ int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
{
struct nidrange *nr;
struct addrrange *ar;
- ENTRY;
list_for_each_entry(nr, nidlist, nr_link) {
if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
@@ -842,13 +840,13 @@ int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
continue;
if (nr->nr_all)
- RETURN(1);
+ return 1;
list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
&ar->ar_numaddr_ranges))
- RETURN(1);
+ return 1;
}
- RETURN(0);
+ return 0;
}
diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.c b/drivers/staging/lustre/lustre/libcfs/tracefile.c
index 439e71dfae3..357f40079ae 100644
--- a/drivers/staging/lustre/lustre/libcfs/tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/tracefile.c
@@ -275,12 +275,9 @@ int libcfs_debug_vmsg2(struct libcfs_debug_msg_data *msgdata,
int i;
int remain;
int mask = msgdata->msg_mask;
- char *file = (char *)msgdata->msg_file;
+ const char *file = kbasename(msgdata->msg_file);
cfs_debug_limit_state_t *cdls = msgdata->msg_cdls;
- if (strchr(file, '/'))
- file = strrchr(file, '/') + 1;
-
tcd = cfs_trace_get_tcd();
/* cfs_trace_get_tcd() grabs a lock, which disables preemption and
@@ -529,7 +526,7 @@ static void collect_pages_on_all_cpus(struct page_collection *pc)
int i, cpu;
spin_lock(&pc->pc_lock);
- cfs_for_each_possible_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
cfs_tcd_for_each_type_lock(tcd, i, cpu) {
list_splice_init(&tcd->tcd_pages, &pc->pc_pages);
tcd->tcd_cur_pages = 0;
@@ -562,7 +559,7 @@ static void put_pages_back_on_all_cpus(struct page_collection *pc)
int i, cpu;
spin_lock(&pc->pc_lock);
- cfs_for_each_possible_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
cfs_tcd_for_each_type_lock(tcd, i, cpu) {
cur_head = tcd->tcd_pages.next;
@@ -630,7 +627,7 @@ static void put_pages_on_daemon_list(struct page_collection *pc)
struct cfs_trace_cpu_data *tcd;
int i, cpu;
- cfs_for_each_possible_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
cfs_tcd_for_each_type_lock(tcd, i, cpu)
put_pages_on_tcd_daemon_list(pc, tcd);
}
@@ -1159,7 +1156,7 @@ static void trace_cleanup_on_all_cpus(void)
struct cfs_trace_page *tmp;
int i, cpu;
- cfs_for_each_possible_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
cfs_tcd_for_each_type_lock(tcd, i, cpu) {
tcd->tcd_shutting_down = 1;
diff --git a/drivers/staging/lustre/lustre/libcfs/upcall_cache.c b/drivers/staging/lustre/lustre/libcfs/upcall_cache.c
index 18c68c3493b..245b46f0dd9 100644
--- a/drivers/staging/lustre/lustre/libcfs/upcall_cache.c
+++ b/drivers/staging/lustre/lustre/libcfs/upcall_cache.c
@@ -152,7 +152,6 @@ struct upcall_cache_entry *upcall_cache_get_entry(struct upcall_cache *cache,
struct list_head *head;
wait_queue_t wait;
int rc, found;
- ENTRY;
LASSERT(cache);
@@ -176,7 +175,7 @@ find_again:
new = alloc_entry(cache, key, args);
if (!new) {
CERROR("fail to alloc entry\n");
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
}
goto find_again;
} else {
@@ -266,17 +265,14 @@ find_again:
/* Now we know it's good */
out:
spin_unlock(&cache->uc_lock);
- RETURN(entry);
+ return entry;
}
EXPORT_SYMBOL(upcall_cache_get_entry);
void upcall_cache_put_entry(struct upcall_cache *cache,
struct upcall_cache_entry *entry)
{
- ENTRY;
-
if (!entry) {
- EXIT;
return;
}
@@ -284,7 +280,6 @@ void upcall_cache_put_entry(struct upcall_cache *cache,
spin_lock(&cache->uc_lock);
put_entry(cache, entry);
spin_unlock(&cache->uc_lock);
- EXIT;
}
EXPORT_SYMBOL(upcall_cache_put_entry);
@@ -294,7 +289,6 @@ int upcall_cache_downcall(struct upcall_cache *cache, __u32 err, __u64 key,
struct upcall_cache_entry *entry = NULL;
struct list_head *head;
int found = 0, rc = 0;
- ENTRY;
LASSERT(cache);
@@ -314,7 +308,7 @@ int upcall_cache_downcall(struct upcall_cache *cache, __u32 err, __u64 key,
cache->uc_name, key);
/* haven't found, it's possible */
spin_unlock(&cache->uc_lock);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (err) {
@@ -356,7 +350,7 @@ out:
wake_up_all(&entry->ue_waitq);
put_entry(cache, entry);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(upcall_cache_downcall);
@@ -364,7 +358,6 @@ static void cache_flush(struct upcall_cache *cache, int force)
{
struct upcall_cache_entry *entry, *next;
int i;
- ENTRY;
spin_lock(&cache->uc_lock);
for (i = 0; i < UC_CACHE_HASH_SIZE; i++) {
@@ -379,7 +372,6 @@ static void cache_flush(struct upcall_cache *cache, int force)
}
}
spin_unlock(&cache->uc_lock);
- EXIT;
}
void upcall_cache_flush_idle(struct upcall_cache *cache)
@@ -399,7 +391,6 @@ void upcall_cache_flush_one(struct upcall_cache *cache, __u64 key, void *args)
struct list_head *head;
struct upcall_cache_entry *entry;
int found = 0;
- ENTRY;
head = &cache->uc_hashtable[UC_CACHE_HASH_INDEX(key)];
@@ -431,11 +422,10 @@ struct upcall_cache *upcall_cache_init(const char *name, const char *upcall,
{
struct upcall_cache *cache;
int i;
- ENTRY;
LIBCFS_ALLOC(cache, sizeof(*cache));
if (!cache)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
spin_lock_init(&cache->uc_lock);
rwlock_init(&cache->uc_upcall_rwlock);
@@ -448,7 +438,7 @@ struct upcall_cache *upcall_cache_init(const char *name, const char *upcall,
cache->uc_acquire_expire = 30;
cache->uc_ops = ops;
- RETURN(cache);
+ return cache;
}
EXPORT_SYMBOL(upcall_cache_init);
diff --git a/drivers/staging/lustre/lustre/libcfs/watchdog.c b/drivers/staging/lustre/lustre/libcfs/watchdog.c
deleted file mode 100644
index 7c385ada3e1..00000000000
--- a/drivers/staging/lustre/lustre/libcfs/watchdog.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2012, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * libcfs/libcfs/watchdog.c
- *
- * Author: Jacob Berkman <jacob@clusterfs.com>
- */
-
-#define DEBUG_SUBSYSTEM S_LNET
-
-#include <linux/libcfs/libcfs.h>
-#include "tracefile.h"
-
-struct lc_watchdog {
- spinlock_t lcw_lock; /* check or change lcw_list */
- int lcw_refcount; /* must hold lcw_pending_timers_lock */
- timer_list_t lcw_timer; /* kernel timer */
- struct list_head lcw_list; /* chain on pending list */
- cfs_time_t lcw_last_touched; /* last touched stamp */
- task_t *lcw_task; /* owner task */
- void (*lcw_callback)(pid_t, void *);
- void *lcw_data;
-
- pid_t lcw_pid;
-
- enum {
- LC_WATCHDOG_DISABLED,
- LC_WATCHDOG_ENABLED,
- LC_WATCHDOG_EXPIRED
- } lcw_state;
-};
-
-#ifdef WITH_WATCHDOG
-/*
- * The dispatcher will complete lcw_start_completion when it starts,
- * and lcw_stop_completion when it exits.
- * Wake lcw_event_waitq to signal timer callback dispatches.
- */
-static struct completion lcw_start_completion;
-static struct completion lcw_stop_completion;
-static wait_queue_head_t lcw_event_waitq;
-
-/*
- * Set this and wake lcw_event_waitq to stop the dispatcher.
- */
-enum {
- LCW_FLAG_STOP = 0
-};
-static unsigned long lcw_flags = 0;
-
-/*
- * Number of outstanding watchdogs.
- * When it hits 1, we start the dispatcher.
- * When it hits 0, we stop the dispatcher.
- */
-static __u32 lcw_refcount = 0;
-static DEFINE_MUTEX(lcw_refcount_mutex);
-
-/*
- * List of timers that have fired that need their callbacks run by the
- * dispatcher.
- */
-/* BH lock! */
-static DEFINE_SPINLOCK(lcw_pending_timers_lock);
-static struct list_head lcw_pending_timers = LIST_HEAD_INIT(lcw_pending_timers);
-
-/* Last time a watchdog expired */
-static cfs_time_t lcw_last_watchdog_time;
-static int lcw_recent_watchdog_count;
-
-static void
-lcw_dump(struct lc_watchdog *lcw)
-{
- ENTRY;
- rcu_read_lock();
- if (lcw->lcw_task == NULL) {
- LCONSOLE_WARN("Process " LPPID " was not found in the task "
- "list; watchdog callback may be incomplete\n",
- (int)lcw->lcw_pid);
- } else {
- libcfs_debug_dumpstack(lcw->lcw_task);
- }
-
- rcu_read_unlock();
- EXIT;
-}
-
-static void lcw_cb(ulong_ptr_t data)
-{
- struct lc_watchdog *lcw = (struct lc_watchdog *)data;
- ENTRY;
-
- if (lcw->lcw_state != LC_WATCHDOG_ENABLED) {
- EXIT;
- return;
- }
-
- lcw->lcw_state = LC_WATCHDOG_EXPIRED;
-
- spin_lock_bh(&lcw->lcw_lock);
- LASSERT(list_empty(&lcw->lcw_list));
-
- spin_lock_bh(&lcw_pending_timers_lock);
- lcw->lcw_refcount++; /* +1 for pending list */
- list_add(&lcw->lcw_list, &lcw_pending_timers);
- wake_up(&lcw_event_waitq);
-
- spin_unlock_bh(&lcw_pending_timers_lock);
- spin_unlock_bh(&lcw->lcw_lock);
- EXIT;
-}
-
-static int is_watchdog_fired(void)
-{
- int rc;
-
- if (test_bit(LCW_FLAG_STOP, &lcw_flags))
- return 1;
-
- spin_lock_bh(&lcw_pending_timers_lock);
- rc = !list_empty(&lcw_pending_timers);
- spin_unlock_bh(&lcw_pending_timers_lock);
- return rc;
-}
-
-static void lcw_dump_stack(struct lc_watchdog *lcw)
-{
- cfs_time_t current_time;
- cfs_duration_t delta_time;
- struct timeval timediff;
-
- current_time = cfs_time_current();
- delta_time = cfs_time_sub(current_time, lcw->lcw_last_touched);
- cfs_duration_usec(delta_time, &timediff);
-
- /*
- * Check to see if we should throttle the watchdog timer to avoid
- * too many dumps going to the console thus triggering an NMI.
- */
- delta_time = cfs_duration_sec(cfs_time_sub(current_time,
- lcw_last_watchdog_time));
-
- if (delta_time < libcfs_watchdog_ratelimit &&
- lcw_recent_watchdog_count > 3) {
- LCONSOLE_WARN("Service thread pid %u was inactive for "
- "%lu.%.02lus. Watchdog stack traces are limited "
- "to 3 per %d seconds, skipping this one.\n",
- (int)lcw->lcw_pid,
- timediff.tv_sec,
- timediff.tv_usec / 10000,
- libcfs_watchdog_ratelimit);
- } else {
- if (delta_time < libcfs_watchdog_ratelimit) {
- lcw_recent_watchdog_count++;
- } else {
- memcpy(&lcw_last_watchdog_time, &current_time,
- sizeof(current_time));
- lcw_recent_watchdog_count = 0;
- }
-
- LCONSOLE_WARN("Service thread pid %u was inactive for "
- "%lu.%.02lus. The thread might be hung, or it "
- "might only be slow and will resume later. "
- "Dumping the stack trace for debugging purposes:"
- "\n",
- (int)lcw->lcw_pid,
- timediff.tv_sec,
- timediff.tv_usec / 10000);
- lcw_dump(lcw);
- }
-}
-
-static int lcw_dispatch_main(void *data)
-{
- int rc = 0;
- struct lc_watchdog *lcw;
- LIST_HEAD (zombies);
-
- ENTRY;
-
- complete(&lcw_start_completion);
-
- while (1) {
- int dumplog = 1;
-
- cfs_wait_event_interruptible(lcw_event_waitq,
- is_watchdog_fired(), rc);
- CDEBUG(D_INFO, "Watchdog got woken up...\n");
- if (test_bit(LCW_FLAG_STOP, &lcw_flags)) {
- CDEBUG(D_INFO, "LCW_FLAG_STOP set, shutting down...\n");
-
- spin_lock_bh(&lcw_pending_timers_lock);
- rc = !list_empty(&lcw_pending_timers);
- spin_unlock_bh(&lcw_pending_timers_lock);
- if (rc) {
- CERROR("pending timers list was not empty at "
- "time of watchdog dispatch shutdown\n");
- }
- break;
- }
-
- spin_lock_bh(&lcw_pending_timers_lock);
- while (!list_empty(&lcw_pending_timers)) {
- int is_dumplog;
-
- lcw = list_entry(lcw_pending_timers.next,
- struct lc_watchdog, lcw_list);
- /* +1 ref for callback to make sure lwc wouldn't be
- * deleted after releasing lcw_pending_timers_lock */
- lcw->lcw_refcount++;
- spin_unlock_bh(&lcw_pending_timers_lock);
-
- /* lock ordering */
- spin_lock_bh(&lcw->lcw_lock);
- spin_lock_bh(&lcw_pending_timers_lock);
-
- if (list_empty(&lcw->lcw_list)) {
- /* already removed from pending list */
- lcw->lcw_refcount--; /* -1 ref for callback */
- if (lcw->lcw_refcount == 0)
- list_add(&lcw->lcw_list, &zombies);
- spin_unlock_bh(&lcw->lcw_lock);
- /* still hold lcw_pending_timers_lock */
- continue;
- }
-
- list_del_init(&lcw->lcw_list);
- lcw->lcw_refcount--; /* -1 ref for pending list */
-
- spin_unlock_bh(&lcw_pending_timers_lock);
- spin_unlock_bh(&lcw->lcw_lock);
-
- CDEBUG(D_INFO, "found lcw for pid " LPPID "\n",
- lcw->lcw_pid);
- lcw_dump_stack(lcw);
-
- is_dumplog = lcw->lcw_callback == lc_watchdog_dumplog;
- if (lcw->lcw_state != LC_WATCHDOG_DISABLED &&
- (dumplog || !is_dumplog)) {
- lcw->lcw_callback(lcw->lcw_pid, lcw->lcw_data);
- if (dumplog && is_dumplog)
- dumplog = 0;
- }
-
- spin_lock_bh(&lcw_pending_timers_lock);
- lcw->lcw_refcount--; /* -1 ref for callback */
- if (lcw->lcw_refcount == 0)
- list_add(&lcw->lcw_list, &zombies);
- }
- spin_unlock_bh(&lcw_pending_timers_lock);
-
- while (!list_empty(&zombies)) {
- lcw = list_entry(lcw_pending_timers.next,
- struct lc_watchdog, lcw_list);
- list_del(&lcw->lcw_list);
- LIBCFS_FREE(lcw, sizeof(*lcw));
- }
- }
-
- complete(&lcw_stop_completion);
-
- RETURN(rc);
-}
-
-static void lcw_dispatch_start(void)
-{
- task_t *task;
-
- ENTRY;
- LASSERT(lcw_refcount == 1);
-
- init_completion(&lcw_stop_completion);
- init_completion(&lcw_start_completion);
- init_waitqueue_head(&lcw_event_waitq);
-
- CDEBUG(D_INFO, "starting dispatch thread\n");
- task = kthread_run(lcw_dispatch_main, NULL, "lc_watchdogd");
- if (IS_ERR(task)) {
- CERROR("error spawning watchdog dispatch thread: %ld\n",
- PTR_ERR(task));
- EXIT;
- return;
- }
- wait_for_completion(&lcw_start_completion);
- CDEBUG(D_INFO, "watchdog dispatcher initialization complete.\n");
-
- EXIT;
-}
-
-static void lcw_dispatch_stop(void)
-{
- ENTRY;
- LASSERT(lcw_refcount == 0);
-
- CDEBUG(D_INFO, "trying to stop watchdog dispatcher.\n");
-
- set_bit(LCW_FLAG_STOP, &lcw_flags);
- wake_up(&lcw_event_waitq);
-
- wait_for_completion(&lcw_stop_completion);
-
- CDEBUG(D_INFO, "watchdog dispatcher has shut down.\n");
-
- EXIT;
-}
-
-struct lc_watchdog *lc_watchdog_add(int timeout,
- void (*callback)(pid_t, void *),
- void *data)
-{
- struct lc_watchdog *lcw = NULL;
- ENTRY;
-
- LIBCFS_ALLOC(lcw, sizeof(*lcw));
- if (lcw == NULL) {
- CDEBUG(D_INFO, "Could not allocate new lc_watchdog\n");
- RETURN(ERR_PTR(-ENOMEM));
- }
-
- spin_lock_init(&lcw->lcw_lock);
- lcw->lcw_refcount = 1; /* refcount for owner */
- lcw->lcw_task = current;
- lcw->lcw_pid = current_pid();
- lcw->lcw_callback = (callback != NULL) ? callback : lc_watchdog_dumplog;
- lcw->lcw_data = data;
- lcw->lcw_state = LC_WATCHDOG_DISABLED;
-
- INIT_LIST_HEAD(&lcw->lcw_list);
- cfs_timer_init(&lcw->lcw_timer, lcw_cb, lcw);
-
- mutex_lock(&lcw_refcount_mutex);
- if (++lcw_refcount == 1)
- lcw_dispatch_start();
- mutex_unlock(&lcw_refcount_mutex);
-
- /* Keep this working in case we enable them by default */
- if (lcw->lcw_state == LC_WATCHDOG_ENABLED) {
- lcw->lcw_last_touched = cfs_time_current();
- cfs_timer_arm(&lcw->lcw_timer, cfs_time_seconds(timeout) +
- cfs_time_current());
- }
-
- RETURN(lcw);
-}
-EXPORT_SYMBOL(lc_watchdog_add);
-
-static void lcw_update_time(struct lc_watchdog *lcw, const char *message)
-{
- cfs_time_t newtime = cfs_time_current();;
-
- if (lcw->lcw_state == LC_WATCHDOG_EXPIRED) {
- struct timeval timediff;
- cfs_time_t delta_time = cfs_time_sub(newtime,
- lcw->lcw_last_touched);
- cfs_duration_usec(delta_time, &timediff);
-
- LCONSOLE_WARN("Service thread pid %u %s after %lu.%.02lus. "
- "This indicates the system was overloaded (too "
- "many service threads, or there were not enough "
- "hardware resources).\n",
- lcw->lcw_pid,
- message,
- timediff.tv_sec,
- timediff.tv_usec / 10000);
- }
- lcw->lcw_last_touched = newtime;
-}
-
-static void lc_watchdog_del_pending(struct lc_watchdog *lcw)
-{
- spin_lock_bh(&lcw->lcw_lock);
- if (unlikely(!list_empty(&lcw->lcw_list))) {
- spin_lock_bh(&lcw_pending_timers_lock);
- list_del_init(&lcw->lcw_list);
- lcw->lcw_refcount--; /* -1 ref for pending list */
- spin_unlock_bh(&lcw_pending_timers_lock);
- }
-
- spin_unlock_bh(&lcw->lcw_lock);
-}
-
-void lc_watchdog_touch(struct lc_watchdog *lcw, int timeout)
-{
- ENTRY;
- LASSERT(lcw != NULL);
-
- lc_watchdog_del_pending(lcw);
-
- lcw_update_time(lcw, "resumed");
- lcw->lcw_state = LC_WATCHDOG_ENABLED;
-
- cfs_timer_arm(&lcw->lcw_timer, cfs_time_current() +
- cfs_time_seconds(timeout));
-
- EXIT;
-}
-EXPORT_SYMBOL(lc_watchdog_touch);
-
-void lc_watchdog_disable(struct lc_watchdog *lcw)
-{
- ENTRY;
- LASSERT(lcw != NULL);
-
- lc_watchdog_del_pending(lcw);
-
- lcw_update_time(lcw, "completed");
- lcw->lcw_state = LC_WATCHDOG_DISABLED;
-
- EXIT;
-}
-EXPORT_SYMBOL(lc_watchdog_disable);
-
-void lc_watchdog_delete(struct lc_watchdog *lcw)
-{
- int dead;
-
- ENTRY;
- LASSERT(lcw != NULL);
-
- cfs_timer_disarm(&lcw->lcw_timer);
-
- lcw_update_time(lcw, "stopped");
-
- spin_lock_bh(&lcw->lcw_lock);
- spin_lock_bh(&lcw_pending_timers_lock);
- if (unlikely(!list_empty(&lcw->lcw_list))) {
- list_del_init(&lcw->lcw_list);
- lcw->lcw_refcount--; /* -1 ref for pending list */
- }
-
- lcw->lcw_refcount--; /* -1 ref for owner */
- dead = lcw->lcw_refcount == 0;
- spin_unlock_bh(&lcw_pending_timers_lock);
- spin_unlock_bh(&lcw->lcw_lock);
-
- if (dead)
- LIBCFS_FREE(lcw, sizeof(*lcw));
-
- mutex_lock(&lcw_refcount_mutex);
- if (--lcw_refcount == 0)
- lcw_dispatch_stop();
- mutex_unlock(&lcw_refcount_mutex);
-
- EXIT;
-}
-EXPORT_SYMBOL(lc_watchdog_delete);
-
-/*
- * Provided watchdog handlers
- */
-
-void lc_watchdog_dumplog(pid_t pid, void *data)
-{
- libcfs_debug_dumplog_internal((void *)((long_ptr_t)pid));
-}
-EXPORT_SYMBOL(lc_watchdog_dumplog);
-
-#else /* !defined(WITH_WATCHDOG) */
-
-struct lc_watchdog *lc_watchdog_add(int timeout,
- void (*callback)(pid_t pid, void *),
- void *data)
-{
- static struct lc_watchdog watchdog;
- return &watchdog;
-}
-EXPORT_SYMBOL(lc_watchdog_add);
-
-void lc_watchdog_touch(struct lc_watchdog *lcw, int timeout)
-{
-}
-EXPORT_SYMBOL(lc_watchdog_touch);
-
-void lc_watchdog_disable(struct lc_watchdog *lcw)
-{
-}
-EXPORT_SYMBOL(lc_watchdog_disable);
-
-void lc_watchdog_delete(struct lc_watchdog *lcw)
-{
-}
-EXPORT_SYMBOL(lc_watchdog_delete);
-
-#endif
diff --git a/drivers/staging/lustre/lustre/libcfs/workitem.c b/drivers/staging/lustre/lustre/libcfs/workitem.c
index b533666c190..462172d1a75 100644
--- a/drivers/staging/lustre/lustre/libcfs/workitem.c
+++ b/drivers/staging/lustre/lustre/libcfs/workitem.c
@@ -376,7 +376,8 @@ cfs_wi_sched_create(char *name, struct cfs_cpt_table *cptab,
rc = 0;
while (nthrs > 0) {
char name[16];
- task_t *task;
+ struct task_struct *task;
+
spin_lock(&cfs_wi_data.wi_glock);
while (sched->ws_starting > 0) {
spin_unlock(&cfs_wi_data.wi_glock);
diff --git a/drivers/staging/lustre/lustre/llite/Makefile b/drivers/staging/lustre/lustre/llite/Makefile
index dff0c0486e7..f493e074000 100644
--- a/drivers/staging/lustre/lustre/llite/Makefile
+++ b/drivers/staging/lustre/lustre/llite/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_LUSTRE_FS) += lustre.o
-obj-$(CONFIG_LUSTRE_FS) += llite_lloop.o
+obj-$(CONFIG_LUSTRE_LLITE_LLOOP) += llite_lloop.o
lustre-y := dcache.o dir.o file.o llite_close.o llite_lib.o llite_nfs.o \
rw.o lproc_llite.o namei.o symlink.o llite_mmap.o \
xattr.o remote_perm.o llite_rmtacl.o llite_capa.o \
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c
index ff0d085077c..e7629be3973 100644
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -59,11 +59,11 @@ static void free_dentry_data(struct rcu_head *head)
static void ll_release(struct dentry *de)
{
struct ll_dentry_data *lld;
- ENTRY;
+
LASSERT(de != NULL);
lld = ll_d2d(de);
if (lld == NULL) /* NFS copies the de->d_op methods (bug 4655) */
- RETURN_EXIT;
+ return;
if (lld->lld_it) {
ll_intent_release(lld->lld_it);
@@ -73,8 +73,6 @@ static void ll_release(struct dentry *de)
LASSERT(lld->lld_mnt_count == 0);
de->d_fsdata = NULL;
call_rcu(&lld->lld_rcu_head, free_dentry_data);
-
- EXIT;
}
/* Compare if two dentries are the same. Don't match if the existing dentry
@@ -84,17 +82,14 @@ static void ll_release(struct dentry *de)
* an AST before calling d_revalidate_it(). The dentry still exists (marked
* INVALID) so d_lookup() matches it, but we have no lock on it (so
* lock_match() fails) and we spin around real_lookup(). */
-int ll_dcompare(const struct dentry *parent, const struct inode *pinode,
- const struct dentry *dentry, const struct inode *inode,
+int ll_dcompare(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
- ENTRY;
-
if (len != name->len)
- RETURN(1);
+ return 1;
if (memcmp(str, name->name, len))
- RETURN(1);
+ return 1;
CDEBUG(D_DENTRY, "found name %.*s(%p) flags %#x refc %d\n",
name->len, name->name, dentry, dentry->d_flags,
@@ -102,12 +97,12 @@ int ll_dcompare(const struct dentry *parent, const struct inode *pinode,
/* mountpoint is always valid */
if (d_mountpoint((struct dentry *)dentry))
- RETURN(0);
+ return 0;
if (d_lustre_invalid(dentry))
- RETURN(1);
+ return 1;
- RETURN(0);
+ return 0;
}
static inline int return_if_equal(struct ldlm_lock *lock, void *data)
@@ -128,22 +123,21 @@ static int find_cbdata(struct inode *inode)
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct lov_stripe_md *lsm;
int rc = 0;
- ENTRY;
LASSERT(inode);
rc = md_find_cbdata(sbi->ll_md_exp, ll_inode2fid(inode),
return_if_equal, NULL);
if (rc != 0)
- RETURN(rc);
+ return rc;
lsm = ccc_inode_lsm_get(inode);
if (lsm == NULL)
- RETURN(rc);
+ return rc;
rc = obd_find_cbdata(sbi->ll_dt_exp, lsm, return_if_equal, NULL);
ccc_inode_lsm_put(inode, lsm);
- RETURN(rc);
+ return rc;
}
/**
@@ -155,7 +149,6 @@ static int find_cbdata(struct inode *inode)
*/
static int ll_ddelete(const struct dentry *de)
{
- ENTRY;
LASSERT(de);
CDEBUG(D_DENTRY, "%s dentry %.*s (%p, parent %p, inode %p) %s%s\n",
@@ -179,13 +172,12 @@ static int ll_ddelete(const struct dentry *de)
#endif
if (d_lustre_invalid((struct dentry *)de))
- RETURN(1);
- RETURN(0);
+ return 1;
+ return 0;
}
static int ll_set_dd(struct dentry *de)
{
- ENTRY;
LASSERT(de != NULL);
CDEBUG(D_DENTRY, "ldd on dentry %.*s (%p) parent %p inode %p refc %d\n",
@@ -204,11 +196,11 @@ static int ll_set_dd(struct dentry *de)
OBD_FREE_PTR(lld);
spin_unlock(&de->d_lock);
} else {
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
}
- RETURN(0);
+ return 0;
}
int ll_dops_init(struct dentry *de, int block, int init_sa)
@@ -260,8 +252,6 @@ void ll_intent_drop_lock(struct lookup_intent *it)
void ll_intent_release(struct lookup_intent *it)
{
- ENTRY;
-
CDEBUG(D_INFO, "intent %p released\n", it);
ll_intent_drop_lock(it);
/* We are still holding extra reference on a request, need to free it */
@@ -275,14 +265,12 @@ void ll_intent_release(struct lookup_intent *it)
it->d.lustre.it_disposition = 0;
it->d.lustre.it_data = NULL;
- EXIT;
}
void ll_invalidate_aliases(struct inode *inode)
{
struct dentry *dentry;
struct ll_d_hlist_node *p;
- ENTRY;
LASSERT(inode != NULL);
@@ -296,18 +284,17 @@ void ll_invalidate_aliases(struct inode *inode)
dentry->d_name.name, dentry, dentry->d_parent,
dentry->d_inode, dentry->d_flags);
- if (dentry->d_name.len == 1 && dentry->d_name.name[0] == '/') {
- CERROR("called on root (?) dentry=%p, inode=%p "
- "ino=%lu\n", dentry, inode, inode->i_ino);
+ if (unlikely(dentry == dentry->d_sb->s_root)) {
+ CERROR("%s: called on root dentry=%p, fid="DFID"\n",
+ ll_get_fsname(dentry->d_sb, NULL, 0),
+ dentry, PFID(ll_inode2fid(inode)));
lustre_dump_dentry(dentry, 1);
- libcfs_debug_dumpstack(NULL);
+ dump_stack();
}
d_lustre_invalidate(dentry, 0);
}
ll_unlock_dcache(inode);
-
- EXIT;
}
int ll_revalidate_it_finish(struct ptlrpc_request *request,
@@ -315,17 +302,16 @@ int ll_revalidate_it_finish(struct ptlrpc_request *request,
struct dentry *de)
{
int rc = 0;
- ENTRY;
if (!request)
- RETURN(0);
+ return 0;
if (it_disposition(it, DISP_LOOKUP_NEG))
- RETURN(-ENOENT);
+ return -ENOENT;
rc = ll_prep_inode(&de->d_inode, request, NULL, it);
- RETURN(rc);
+ return rc;
}
void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry)
@@ -370,7 +356,6 @@ int ll_revalidate_it(struct dentry *de, int lookup_flags,
struct inode *parent = de->d_parent->d_inode;
int rc;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%s,intent=%s\n", de->d_name.name,
LL_IT2STR(it));
@@ -383,10 +368,10 @@ int ll_revalidate_it(struct dentry *de, int lookup_flags,
away this negative dentry and actually do the request to
kernel to create whatever needs to be created (if possible)*/
if (it && (it->it_op & IT_CREAT))
- RETURN(0);
+ return 0;
if (d_lustre_invalid(de))
- RETURN(0);
+ return 0;
ibits = MDS_INODELOCK_UPDATE;
rc = ll_have_md_lock(parent, &ibits, LCK_MINMODE);
@@ -413,7 +398,7 @@ int ll_revalidate_it(struct dentry *de, int lookup_flags,
LASSERT(it);
if (it->it_op == IT_LOOKUP && !d_lustre_invalid(de))
- RETURN(1);
+ return 1;
if (it->it_op == IT_OPEN) {
struct inode *inode = de->d_inode;
@@ -460,7 +445,7 @@ int ll_revalidate_it(struct dentry *de, int lookup_flags,
if it would be, we'll reopen the open request to
MDS later during file open path */
mutex_unlock(&lli->lli_och_mutex);
- RETURN(1);
+ return 1;
} else {
mutex_unlock(&lli->lli_och_mutex);
}
@@ -479,7 +464,7 @@ do_lock:
de->d_name.name, de->d_name.len,
0, LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
if (!IS_POSIXACL(parent) || !exp_connect_umask(exp))
it->it_create_mode &= ~current_umask();
@@ -566,7 +551,7 @@ out:
mark:
if (it != NULL && it->it_op == IT_GETATTR && rc > 0)
ll_statahead_mark(parent, de);
- RETURN(rc);
+ return rc;
/*
* This part is here to combat evil-evil race in real_lookup on 2.6
@@ -598,7 +583,7 @@ do_lookup:
LUSTRE_OPC_CREATE :
LUSTRE_OPC_ANY), NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
rc = md_intent_lock(exp, op_data, NULL, 0, it, 0, &req,
ll_md_blocking_ast, 0);
@@ -639,14 +624,13 @@ int ll_revalidate_nd(struct dentry *dentry, unsigned int flags)
struct inode *parent = dentry->d_parent->d_inode;
int unplug = 0;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%s,flags=%u\n",
dentry->d_name.name, flags);
if (!(flags & (LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE)) &&
ll_need_statahead(parent, dentry) > 0) {
if (flags & LOOKUP_RCU)
- RETURN(-ECHILD);
+ return -ECHILD;
if (dentry->d_inode == NULL)
unplug = 1;
@@ -654,7 +638,7 @@ int ll_revalidate_nd(struct dentry *dentry, unsigned int flags)
ll_statahead_mark(parent, dentry);
}
- RETURN(1);
+ return 1;
}
diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c
index 23c61fe8196..09844be5eec 100644
--- a/drivers/staging/lustre/lustre/llite/dir.c
+++ b/drivers/staging/lustre/lustre/llite/dir.c
@@ -41,14 +41,13 @@
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/mm.h>
-#include <linux/version.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h> // for wait_on_buffer
#include <linux/pagevec.h>
+#include <linux/prefetch.h>
#define DEBUG_SUBSYSTEM S_LLITE
-#include <lustre/lustre_idl.h>
#include <obd_support.h>
#include <obd_class.h>
#include <lustre_lib.h>
@@ -158,7 +157,6 @@ static int ll_dir_filler(void *_hash, struct page *page0)
int npages;
int i;
int rc;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p) hash "LPU64"\n",
inode->i_ino, inode->i_generation, inode, hash);
@@ -239,7 +237,6 @@ static int ll_dir_filler(void *_hash, struct page *page0)
if (page_pool != &page0)
OBD_FREE(page_pool, sizeof(struct page *) * max_pages);
- EXIT;
return rc;
}
@@ -355,15 +352,12 @@ struct page *ll_get_dir_page(struct inode *dir, __u64 hash,
rc = md_lock_match(ll_i2sbi(dir)->ll_md_exp, LDLM_FL_BLOCK_GRANTED,
ll_inode2fid(dir), LDLM_IBITS, &policy, mode, &lockh);
if (!rc) {
- struct ldlm_enqueue_info einfo = {.ei_type = LDLM_IBITS,
- .ei_mode = mode,
- .ei_cb_bl =
- ll_md_blocking_ast,
- .ei_cb_cp =
- ldlm_completion_ast,
- .ei_cb_gl = NULL,
- .ei_cb_wg = NULL,
- .ei_cbdata = NULL};
+ struct ldlm_enqueue_info einfo = {
+ .ei_type = LDLM_IBITS,
+ .ei_mode = mode,
+ .ei_cb_bl = ll_md_blocking_ast,
+ .ei_cb_cp = ldlm_completion_ast,
+ };
struct lookup_intent it = { .it_op = IT_READDIR };
struct ptlrpc_request *request;
struct md_op_data *op_data;
@@ -482,19 +476,17 @@ fail:
goto out_unlock;
}
-int ll_dir_read(struct inode *inode, __u64 *_pos, void *cookie,
- filldir_t filldir)
+int ll_dir_read(struct inode *inode, struct dir_context *ctx)
{
struct ll_inode_info *info = ll_i2info(inode);
struct ll_sb_info *sbi = ll_i2sbi(inode);
- __u64 pos = *_pos;
+ __u64 pos = ctx->pos;
int api32 = ll_need_32bit_api(sbi);
int hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH;
struct page *page;
struct ll_dir_chain chain;
int done = 0;
int rc = 0;
- ENTRY;
ll_dir_chain_init(&chain);
@@ -547,12 +539,14 @@ int ll_dir_read(struct inode *inode, __u64 *_pos, void *cookie,
fid_le_to_cpu(&fid, &ent->lde_fid);
ino = cl_fid_build_ino(&fid, api32);
type = ll_dirent_type_get(ent);
+ ctx->pos = lhash;
/* For 'll_nfs_get_name_filldir()', it will try
* to access the 'ent' through its 'lde_name',
- * so the parameter 'name' for 'filldir()' must
- * be part of the 'ent'. */
- done = filldir(cookie, ent->lde_name, namelen,
- lhash, ino, type);
+ * so the parameter 'name' for 'ctx->actor()'
+ * must be part of the 'ent'.
+ */
+ done = !dir_emit(ctx, ent->lde_name,
+ namelen, ino, type);
}
next = le64_to_cpu(dp->ldp_hash_end);
if (!done) {
@@ -593,56 +587,49 @@ int ll_dir_read(struct inode *inode, __u64 *_pos, void *cookie,
}
}
- *_pos = pos;
+ ctx->pos = pos;
ll_dir_chain_fini(&chain);
- RETURN(rc);
+ return rc;
}
-static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
+static int ll_readdir(struct file *filp, struct dir_context *ctx)
{
struct inode *inode = filp->f_dentry->d_inode;
struct ll_file_data *lfd = LUSTRE_FPRIVATE(filp);
struct ll_sb_info *sbi = ll_i2sbi(inode);
- __u64 pos = lfd->lfd_pos;
int hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH;
int api32 = ll_need_32bit_api(sbi);
int rc;
- struct path path;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p) pos %lu/%llu "
" 32bit_api %d\n", inode->i_ino, inode->i_generation,
- inode, (unsigned long)pos, i_size_read(inode), api32);
+ inode, (unsigned long)lfd->lfd_pos, i_size_read(inode), api32);
- if (pos == MDS_DIR_END_OFF)
+ if (lfd->lfd_pos == MDS_DIR_END_OFF)
/*
* end-of-file.
*/
GOTO(out, rc = 0);
- rc = ll_dir_read(inode, &pos, cookie, filldir);
- lfd->lfd_pos = pos;
- if (pos == MDS_DIR_END_OFF) {
+ ctx->pos = lfd->lfd_pos;
+ rc = ll_dir_read(inode, ctx);
+ lfd->lfd_pos = ctx->pos;
+ if (ctx->pos == MDS_DIR_END_OFF) {
if (api32)
- filp->f_pos = LL_DIR_END_OFF_32BIT;
+ ctx->pos = LL_DIR_END_OFF_32BIT;
else
- filp->f_pos = LL_DIR_END_OFF;
+ ctx->pos = LL_DIR_END_OFF;
} else {
if (api32 && hash64)
- filp->f_pos = pos >> 32;
- else
- filp->f_pos = pos;
+ ctx->pos >>= 32;
}
filp->f_version = inode->i_version;
- path.mnt = filp->f_path.mnt;
- path.dentry = filp->f_dentry;
- touch_atime(&path);
out:
if (!rc)
ll_stats_ops_tally(sbi, LPROC_LL_READDIR, 1);
- RETURN(rc);
+ return rc;
}
int ll_send_mgc_param(struct obd_export *mgc, char *string)
@@ -673,8 +660,6 @@ int ll_dir_setdirstripe(struct inode *dir, struct lmv_user_md *lump,
int mode;
int err;
- ENTRY;
-
mode = (0755 & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask) | S_IFDIR;
op_data = ll_prep_md_op_data(NULL, dir, NULL, filename,
strlen(filename), mode, LUSTRE_OPC_MKDIR,
@@ -684,7 +669,8 @@ int ll_dir_setdirstripe(struct inode *dir, struct lmv_user_md *lump,
op_data->op_cli_flags |= CLI_SET_MEA;
err = md_create(sbi->ll_md_exp, op_data, lump, sizeof(*lump), mode,
- current_fsuid(), current_fsgid(),
+ from_kuid(&init_user_ns, current_fsuid()),
+ from_kgid(&init_user_ns, current_fsgid()),
cfs_curproc_cap_pack(), 0, &request);
ll_finish_md_op_data(op_data);
if (err)
@@ -704,7 +690,6 @@ int ll_dir_setstripe(struct inode *inode, struct lov_user_md *lump,
struct lustre_sb_info *lsi = s2lsi(inode->i_sb);
struct obd_device *mgc = lsi->lsi_mgc;
int lum_size;
- ENTRY;
if (lump != NULL) {
/*
@@ -731,7 +716,7 @@ int ll_dir_setstripe(struct inode *inode, struct lov_user_md *lump,
" %#08x != %#08x nor %#08x\n",
lump->lmm_magic, LOV_USER_MAGIC_V1,
LOV_USER_MAGIC_V3);
- RETURN(-EINVAL);
+ return -EINVAL;
}
}
} else {
@@ -741,7 +726,7 @@ int ll_dir_setstripe(struct inode *inode, struct lov_user_md *lump,
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
if (lump != NULL && lump->lmm_magic == cpu_to_le32(LMV_USER_MAGIC))
op_data->op_cli_flags |= CLI_SET_MEA;
@@ -797,7 +782,7 @@ end:
if (param != NULL)
OBD_FREE(param, MGS_PARAM_MAXLEN);
}
- RETURN(rc);
+ return rc;
}
int ll_dir_getstripe(struct inode *inode, struct lov_mds_md **lmmp,
@@ -812,13 +797,13 @@ int ll_dir_getstripe(struct inode *inode, struct lov_mds_md **lmmp,
rc = ll_get_max_mdsize(sbi, &lmmsize);
if (rc)
- RETURN(rc);
+ return rc;
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL,
0, lmmsize, LUSTRE_OPC_ANY,
NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
op_data->op_valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA;
rc = md_getattr(sbi->ll_md_exp, op_data, &req);
@@ -878,12 +863,11 @@ int ll_get_mdt_idx(struct inode *inode)
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct md_op_data *op_data;
int rc, mdtidx;
- ENTRY;
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0,
0, LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
op_data->op_flags |= MF_GET_MDT_IDX;
rc = md_getattr(sbi->ll_md_exp, op_data, NULL);
@@ -891,7 +875,7 @@ int ll_get_mdt_idx(struct inode *inode)
ll_finish_md_op_data(op_data);
if (rc < 0) {
CDEBUG(D_INFO, "md_getattr_name: %d\n", rc);
- RETURN(rc);
+ return rc;
}
return mdtidx;
}
@@ -912,7 +896,6 @@ static int ll_ioc_copy_start(struct super_block *sb, struct hsm_copy *copy)
struct ll_sb_info *sbi = ll_s2sbi(sb);
struct hsm_progress_kernel hpk;
int rc;
- ENTRY;
/* Forge a hsm_progress based on data from copy. */
hpk.hpk_fid = copy->hc_hai.hai_fid;
@@ -962,7 +945,7 @@ progress:
rc = obd_iocontrol(LL_IOC_HSM_PROGRESS, sbi->ll_md_exp, sizeof(hpk),
&hpk, NULL);
- RETURN(rc);
+ return rc;
}
/**
@@ -985,7 +968,6 @@ static int ll_ioc_copy_end(struct super_block *sb, struct hsm_copy *copy)
struct ll_sb_info *sbi = ll_s2sbi(sb);
struct hsm_progress_kernel hpk;
int rc;
- ENTRY;
/* If you modify the logic here, also check llapi_hsm_copy_end(). */
/* Take care: copy->hc_hai.hai_action, len, gid and data are not
@@ -1062,7 +1044,7 @@ progress:
rc = obd_iocontrol(LL_IOC_HSM_PROGRESS, sbi->ll_md_exp, sizeof(hpk),
&hpk, NULL);
- RETURN(rc);
+ return rc;
}
@@ -1090,7 +1072,6 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
int id = qctl->qc_id;
int valid = qctl->qc_valid;
int rc = 0;
- ENTRY;
switch (cmd) {
case LUSTRE_Q_INVALIDATE:
@@ -1101,32 +1082,34 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
case Q_SETINFO:
if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
sbi->ll_flags & LL_SBI_RMT_CLIENT)
- RETURN(-EPERM);
+ return -EPERM;
break;
case Q_GETQUOTA:
- if (((type == USRQUOTA && current_euid() != id) ||
- (type == GRPQUOTA && !in_egroup_p(id))) &&
+ if (((type == USRQUOTA &&
+ uid_eq(current_euid(), make_kuid(&init_user_ns, id))) ||
+ (type == GRPQUOTA &&
+ !in_egroup_p(make_kgid(&init_user_ns, id)))) &&
(!cfs_capable(CFS_CAP_SYS_ADMIN) ||
sbi->ll_flags & LL_SBI_RMT_CLIENT))
- RETURN(-EPERM);
+ return -EPERM;
break;
case Q_GETINFO:
break;
default:
CERROR("unsupported quotactl op: %#x\n", cmd);
- RETURN(-ENOTTY);
+ return -ENOTTY;
}
if (valid != QC_GENERAL) {
if (sbi->ll_flags & LL_SBI_RMT_CLIENT)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
if (cmd == Q_GETINFO)
qctl->qc_cmd = Q_GETOINFO;
else if (cmd == Q_GETQUOTA)
qctl->qc_cmd = Q_GETOQUOTA;
else
- RETURN(-EINVAL);
+ return -EINVAL;
switch (valid) {
case QC_MDTIDX:
@@ -1151,7 +1134,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
}
if (rc)
- RETURN(rc);
+ return rc;
qctl->qc_cmd = cmd;
} else {
@@ -1159,7 +1142,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
OBD_ALLOC_PTR(oqctl);
if (oqctl == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
QCTL_COPY(oqctl, qctl);
rc = obd_quotactl(sbi->ll_md_exp, oqctl);
@@ -1169,7 +1152,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
obd_quotactl(sbi->ll_md_exp, oqctl);
}
OBD_FREE_PTR(oqctl);
- RETURN(rc);
+ return rc;
}
/* If QIF_SPACE is not set, client should collect the
* space usage from OSSs by itself */
@@ -1216,7 +1199,7 @@ out:
OBD_FREE_PTR(oqctl);
}
- RETURN(rc);
+ return rc;
}
static char *
@@ -1249,7 +1232,6 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct obd_ioctl_data *data;
int rc = 0;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), cmd=%#x\n",
inode->i_ino, inode->i_generation, inode, cmd);
@@ -1262,10 +1244,10 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch(cmd) {
case FSFILT_IOC_GETFLAGS:
case FSFILT_IOC_SETFLAGS:
- RETURN(ll_iocontrol(inode, file, cmd, arg));
+ return ll_iocontrol(inode, file, cmd, arg);
case FSFILT_IOC_GETVERSION_OLD:
case FSFILT_IOC_GETVERSION:
- RETURN(put_user(inode->i_generation, (int *)arg));
+ return put_user(inode->i_generation, (int *)arg);
/* We need to special case any other ioctls we want to handle,
* to send them to the MDS/OST as appropriate and to properly
* network encode the arg field.
@@ -1277,10 +1259,10 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
mdtidx = ll_get_mdt_idx(inode);
if (mdtidx < 0)
- RETURN(mdtidx);
+ return mdtidx;
if (put_user((int)mdtidx, (int*)arg))
- RETURN(-EFAULT);
+ return -EFAULT;
return 0;
}
@@ -1293,7 +1275,7 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
rc = obd_ioctl_getdata(&buf, &len, (void *)arg);
if (rc)
- RETURN(rc);
+ return rc;
data = (void *)buf;
filename = data->ioc_inlbuf1;
@@ -1317,7 +1299,6 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
GOTO(out_free, rc);
}
ptlrpc_req_finished(request);
- EXIT;
out_free:
obd_ioctl_freedata(buf, len);
return rc;
@@ -1333,7 +1314,7 @@ out_free:
rc = obd_ioctl_getdata(&buf, &len, (void *)arg);
if (rc)
- RETURN(rc);
+ return rc;
data = (void *)buf;
if (data->ioc_inlbuf1 == NULL || data->ioc_inlbuf2 == NULL ||
@@ -1364,7 +1345,7 @@ out_free:
rc = ll_dir_setdirstripe(inode, lum, filename);
lmv_out_free:
obd_ioctl_freedata(buf, len);
- RETURN(rc);
+ return rc;
}
case LL_IOC_LOV_SETSTRIPE: {
@@ -1380,11 +1361,11 @@ lmv_out_free:
sizeof(lumv3p->lmm_objects[0]));
/* first try with v1 which is smaller than v3 */
if (copy_from_user(lumv1, lumv1p, sizeof(*lumv1)))
- RETURN(-EFAULT);
+ return -EFAULT;
if ((lumv1->lmm_magic == LOV_USER_MAGIC_V3) ) {
if (copy_from_user(&lumv3, lumv3p, sizeof(lumv3)))
- RETURN(-EFAULT);
+ return -EFAULT;
}
if (inode->i_sb->s_root == file->f_dentry)
@@ -1393,7 +1374,7 @@ lmv_out_free:
/* in v1 and v3 cases lumv1 points to data */
rc = ll_dir_setstripe(inode, lumv1, set_default);
- RETURN(rc);
+ return rc;
}
case LL_IOC_LMV_GETSTRIPE: {
struct lmv_user_md *lump = (struct lmv_user_md *)arg;
@@ -1404,10 +1385,10 @@ lmv_out_free:
int mdtindex;
if (copy_from_user(&lum, lump, sizeof(struct lmv_user_md)))
- RETURN(-EFAULT);
+ return -EFAULT;
if (lum.lum_magic != LMV_MAGIC_V1)
- RETURN(-EINVAL);
+ return -EINVAL;
lum_size = lmv_user_md_size(1, LMV_MAGIC_V1);
OBD_ALLOC(tmp, lum_size);
@@ -1430,7 +1411,7 @@ lmv_out_free:
free_lmv:
if (tmp)
OBD_FREE(tmp, lum_size);
- RETURN(rc);
+ return rc;
}
case LL_IOC_REMOVE_ENTRY: {
char *filename = NULL;
@@ -1447,7 +1428,7 @@ free_lmv:
filename = ll_getname((const char *)arg);
if (IS_ERR(filename))
- RETURN(PTR_ERR(filename));
+ return PTR_ERR(filename);
namelen = strlen(filename);
if (namelen < 1)
@@ -1457,12 +1438,12 @@ free_lmv:
out_rmdir:
if (filename)
ll_putname(filename);
- RETURN(rc);
+ return rc;
}
case LL_IOC_LOV_SWAP_LAYOUTS:
- RETURN(-EPERM);
+ return -EPERM;
case LL_IOC_OBD_STATFS:
- RETURN(ll_obd_statfs(inode, (void *)arg));
+ return ll_obd_statfs(inode, (void *)arg);
case LL_IOC_LOV_GETSTRIPE:
case LL_IOC_MDC_GETINFO:
case IOC_MDC_GETFILEINFO:
@@ -1478,7 +1459,7 @@ out_rmdir:
cmd == IOC_MDC_GETFILESTRIPE) {
filename = ll_getname((const char *)arg);
if (IS_ERR(filename))
- RETURN(PTR_ERR(filename));
+ return PTR_ERR(filename);
rc = ll_lov_getstripe_ea_info(inode, filename, &lmm,
&lmmsize, &request);
@@ -1539,7 +1520,6 @@ out_rmdir:
GOTO(out_req, rc = -EFAULT);
}
- EXIT;
out_req:
ptlrpc_req_finished(request);
if (filename)
@@ -1559,9 +1539,11 @@ out_rmdir:
rc = ll_get_max_mdsize(sbi, &lmmsize);
if (rc)
- RETURN(rc);
+ return rc;
OBD_ALLOC_LARGE(lmm, lmmsize);
+ if (lmm == NULL)
+ return -ENOMEM;
if (copy_from_user(lmm, lum, lmmsize))
GOTO(free_lmm, rc = -EFAULT);
@@ -1602,7 +1584,6 @@ out_rmdir:
if (copy_to_user(&lumd->lmd_st, &st, sizeof(st)))
GOTO(free_lsm, rc = -EFAULT);
- EXIT;
free_lsm:
obd_free_memmd(sbi->ll_dt_exp, &lsm);
free_lmm:
@@ -1610,7 +1591,7 @@ out_rmdir:
return rc;
}
case OBD_IOC_LLOG_CATINFO: {
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
}
case OBD_IOC_QUOTACHECK: {
struct obd_quotactl *oqctl;
@@ -1618,11 +1599,11 @@ out_rmdir:
if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
sbi->ll_flags & LL_SBI_RMT_CLIENT)
- RETURN(-EPERM);
+ return -EPERM;
OBD_ALLOC_PTR(oqctl);
if (!oqctl)
- RETURN(-ENOMEM);
+ return -ENOMEM;
oqctl->qc_type = arg;
rc = obd_quotacheck(sbi->ll_md_exp, oqctl);
if (rc < 0) {
@@ -1642,11 +1623,11 @@ out_rmdir:
if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
sbi->ll_flags & LL_SBI_RMT_CLIENT)
- RETURN(-EPERM);
+ return -EPERM;
OBD_ALLOC_PTR(check);
if (!check)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = obd_iocontrol(cmd, sbi->ll_md_exp, 0, (void *)check,
NULL);
@@ -1669,7 +1650,7 @@ out_rmdir:
}
out_poll:
OBD_FREE_PTR(check);
- RETURN(rc);
+ return rc;
}
#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 7, 50, 0)
case LL_IOC_QUOTACTL_18: {
@@ -1680,7 +1661,7 @@ out_rmdir:
OBD_ALLOC_PTR(qctl_18);
if (!qctl_18)
- RETURN(-ENOMEM);
+ return -ENOMEM;
OBD_ALLOC_PTR(qctl_20);
if (!qctl_20)
@@ -1720,7 +1701,7 @@ out_rmdir:
OBD_FREE_PTR(qctl_20);
out_quotactl_18:
OBD_FREE_PTR(qctl_18);
- RETURN(rc);
+ return rc;
}
#else
#warning "remove old LL_IOC_QUOTACTL_18 compatibility code"
@@ -1730,7 +1711,7 @@ out_rmdir:
OBD_ALLOC_PTR(qctl);
if (!qctl)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (copy_from_user(qctl, (void *)arg, sizeof(*qctl)))
GOTO(out_quotactl, rc = -EFAULT);
@@ -1742,13 +1723,13 @@ out_rmdir:
out_quotactl:
OBD_FREE_PTR(qctl);
- RETURN(rc);
+ return rc;
}
case OBD_IOC_GETDTNAME:
case OBD_IOC_GETMDNAME:
- RETURN(ll_get_obd_name(inode, cmd, arg));
+ return ll_get_obd_name(inode, cmd, arg);
case LL_IOC_FLUSHCTX:
- RETURN(ll_flush_ctx(inode));
+ return ll_flush_ctx(inode);
#ifdef CONFIG_FS_POSIX_ACL
case LL_IOC_RMTACL: {
if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
@@ -1759,9 +1740,9 @@ out_rmdir:
rc = rct_add(&sbi->ll_rct, current_pid(), arg);
if (!rc)
fd->fd_flags |= LL_FILE_RMTACL;
- RETURN(rc);
+ return rc;
} else
- RETURN(0);
+ return 0;
}
#endif
case LL_IOC_GETOBDCOUNT: {
@@ -1769,7 +1750,7 @@ out_rmdir:
struct obd_export *exp;
if (copy_from_user(&count, (int *)arg, sizeof(int)))
- RETURN(-EFAULT);
+ return -EFAULT;
/* get ost count when count is zero, get mdt count otherwise */
exp = count ? sbi->ll_md_exp : sbi->ll_dt_exp;
@@ -1778,41 +1759,41 @@ out_rmdir:
KEY_TGT_COUNT, &vallen, &count, NULL);
if (rc) {
CERROR("get target count failed: %d\n", rc);
- RETURN(rc);
+ return rc;
}
if (copy_to_user((int *)arg, &count, sizeof(int)))
- RETURN(-EFAULT);
+ return -EFAULT;
- RETURN(0);
+ return 0;
}
case LL_IOC_PATH2FID:
if (copy_to_user((void *)arg, ll_inode2fid(inode),
sizeof(struct lu_fid)))
- RETURN(-EFAULT);
- RETURN(0);
+ return -EFAULT;
+ return 0;
case LL_IOC_GET_CONNECT_FLAGS: {
- RETURN(obd_iocontrol(cmd, sbi->ll_md_exp, 0, NULL, (void*)arg));
+ return obd_iocontrol(cmd, sbi->ll_md_exp, 0, NULL, (void*)arg);
}
case OBD_IOC_CHANGELOG_SEND:
case OBD_IOC_CHANGELOG_CLEAR:
rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void *)arg,
sizeof(struct ioc_changelog));
- RETURN(rc);
+ return rc;
case OBD_IOC_FID2PATH:
- RETURN(ll_fid2path(inode, (void *)arg));
+ return ll_fid2path(inode, (void *)arg);
case LL_IOC_HSM_REQUEST: {
struct hsm_user_request *hur;
int totalsize;
OBD_ALLOC_PTR(hur);
if (hur == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* We don't know the true size yet; copy the fixed-size part */
if (copy_from_user(hur, (void *)arg, sizeof(*hur))) {
OBD_FREE_PTR(hur);
- RETURN(-EFAULT);
+ return -EFAULT;
}
/* Compute the whole struct size */
@@ -1820,12 +1801,12 @@ out_rmdir:
OBD_FREE_PTR(hur);
OBD_ALLOC_LARGE(hur, totalsize);
if (hur == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* Copy the whole struct */
if (copy_from_user(hur, (void *)arg, totalsize)) {
OBD_FREE_LARGE(hur, totalsize);
- RETURN(-EFAULT);
+ return -EFAULT;
}
rc = obd_iocontrol(cmd, ll_i2mdexp(inode), totalsize,
@@ -1833,14 +1814,14 @@ out_rmdir:
OBD_FREE_LARGE(hur, totalsize);
- RETURN(rc);
+ return rc;
}
case LL_IOC_HSM_PROGRESS: {
struct hsm_progress_kernel hpk;
struct hsm_progress hp;
if (copy_from_user(&hp, (void *)arg, sizeof(hp)))
- RETURN(-EFAULT);
+ return -EFAULT;
hpk.hpk_fid = hp.hp_fid;
hpk.hpk_cookie = hp.hp_cookie;
@@ -1853,12 +1834,12 @@ out_rmdir:
* reported to Lustre root */
rc = obd_iocontrol(cmd, sbi->ll_md_exp, sizeof(hpk), &hpk,
NULL);
- RETURN(rc);
+ return rc;
}
case LL_IOC_HSM_CT_START:
rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void *)arg,
sizeof(struct lustre_kernelcomm));
- RETURN(rc);
+ return rc;
case LL_IOC_HSM_COPY_START: {
struct hsm_copy *copy;
@@ -1866,10 +1847,10 @@ out_rmdir:
OBD_ALLOC_PTR(copy);
if (copy == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (copy_from_user(copy, (char *)arg, sizeof(*copy))) {
OBD_FREE_PTR(copy);
- RETURN(-EFAULT);
+ return -EFAULT;
}
rc = ll_ioc_copy_start(inode->i_sb, copy);
@@ -1877,7 +1858,7 @@ out_rmdir:
rc = -EFAULT;
OBD_FREE_PTR(copy);
- RETURN(rc);
+ return rc;
}
case LL_IOC_HSM_COPY_END: {
struct hsm_copy *copy;
@@ -1885,10 +1866,10 @@ out_rmdir:
OBD_ALLOC_PTR(copy);
if (copy == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (copy_from_user(copy, (char *)arg, sizeof(*copy))) {
OBD_FREE_PTR(copy);
- RETURN(-EFAULT);
+ return -EFAULT;
}
rc = ll_ioc_copy_end(inode->i_sb, copy);
@@ -1896,11 +1877,10 @@ out_rmdir:
rc = -EFAULT;
OBD_FREE_PTR(copy);
- RETURN(rc);
+ return rc;
}
default:
- RETURN(obd_iocontrol(cmd, sbi->ll_dt_exp, 0, NULL,
- (void *)arg));
+ return obd_iocontrol(cmd, sbi->ll_dt_exp, 0, NULL, (void *)arg);
}
}
@@ -1911,7 +1891,6 @@ static loff_t ll_dir_seek(struct file *file, loff_t offset, int origin)
struct ll_sb_info *sbi = ll_i2sbi(inode);
int api32 = ll_need_32bit_api(sbi);
loff_t ret = -EINVAL;
- ENTRY;
mutex_lock(&inode->i_mutex);
switch (origin) {
@@ -1957,14 +1936,12 @@ out:
int ll_dir_open(struct inode *inode, struct file *file)
{
- ENTRY;
- RETURN(ll_file_open(inode, file));
+ return ll_file_open(inode, file);
}
int ll_dir_release(struct inode *inode, struct file *file)
{
- ENTRY;
- RETURN(ll_file_release(inode, file));
+ return ll_file_release(inode, file);
}
struct file_operations ll_dir_operations = {
@@ -1972,7 +1949,7 @@ struct file_operations ll_dir_operations = {
.open = ll_dir_open,
.release = ll_dir_release,
.read = generic_read_dir,
- .readdir = ll_readdir,
+ .iterate = ll_readdir,
.unlocked_ioctl = ll_dir_ioctl,
.fsync = ll_fsync,
};
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index ed1e3f7b4e5..253f02688f4 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -55,6 +55,8 @@ struct ll_file_data *ll_file_data_get(void)
struct ll_file_data *fd;
OBD_SLAB_ALLOC_PTR_GFP(fd, ll_file_data_slab, __GFP_IO);
+ if (fd == NULL)
+ return NULL;
fd->fd_write_failed = false;
return fd;
}
@@ -93,8 +95,6 @@ void ll_pack_inode2opdata(struct inode *inode, struct md_op_data *op_data,
static void ll_prepare_close(struct inode *inode, struct md_op_data *op_data,
struct obd_client_handle *och)
{
- ENTRY;
-
op_data->op_attr.ia_valid = ATTR_MODE | ATTR_ATIME | ATTR_ATIME_SET |
ATTR_MTIME | ATTR_MTIME_SET |
ATTR_CTIME | ATTR_CTIME_SET;
@@ -111,7 +111,6 @@ out:
ll_pack_inode2opdata(inode, op_data, &och->och_fh);
ll_prep_md_op_data(op_data, inode, NULL, NULL,
0, 0, LUSTRE_OPC_ANY, NULL);
- EXIT;
}
static int ll_close_inode_openhandle(struct obd_export *md_exp,
@@ -124,7 +123,6 @@ static int ll_close_inode_openhandle(struct obd_export *md_exp,
struct obd_device *obd = class_exp2obd(exp);
int epoch_close = 1;
int rc;
- ENTRY;
if (obd == NULL) {
/*
@@ -178,9 +176,7 @@ static int ll_close_inode_openhandle(struct obd_export *md_exp,
inode->i_ino, rc);
}
- EXIT;
out:
-
if (exp_connect_som(exp) && !epoch_close &&
S_ISREG(inode->i_mode) && (och->och_flags & FMODE_WRITE)) {
ll_queue_done_writing(inode, LLIF_DONE_WRITING);
@@ -202,7 +198,6 @@ int ll_md_real_close(struct inode *inode, int flags)
struct obd_client_handle *och;
__u64 *och_usecount;
int rc = 0;
- ENTRY;
if (flags & FMODE_WRITE) {
och_p = &lli->lli_mds_write_och;
@@ -220,7 +215,7 @@ int ll_md_real_close(struct inode *inode, int flags)
if (*och_usecount) { /* There are still users of this handle, so
skip freeing it. */
mutex_unlock(&lli->lli_och_mutex);
- RETURN(0);
+ return 0;
}
och=*och_p;
*och_p = NULL;
@@ -232,7 +227,7 @@ int ll_md_real_close(struct inode *inode, int flags)
inode, och);
}
- RETURN(rc);
+ return rc;
}
int ll_md_close(struct obd_export *md_exp, struct inode *inode,
@@ -241,7 +236,6 @@ int ll_md_close(struct obd_export *md_exp, struct inode *inode,
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
struct ll_inode_info *lli = ll_i2info(inode);
int rc = 0;
- ENTRY;
/* clear group lock, if present */
if (unlikely(fd->fd_flags & LL_FILE_GROUP_LOCKED))
@@ -287,7 +281,7 @@ int ll_md_close(struct obd_export *md_exp, struct inode *inode,
ll_file_data_put(fd);
ll_capa_close(inode);
- RETURN(rc);
+ return rc;
}
/* While this returns an error code, fput() the caller does not, so we need
@@ -301,7 +295,6 @@ int ll_file_release(struct inode *inode, struct file *file)
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ll_inode_info *lli = ll_i2info(inode);
int rc;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino,
inode->i_generation, inode);
@@ -335,7 +328,7 @@ int ll_file_release(struct inode *inode, struct file *file)
if (inode->i_sb->s_root == file->f_dentry) {
LUSTRE_FPRIVATE(file) = NULL;
ll_file_data_put(fd);
- RETURN(0);
+ return 0;
}
if (!S_ISDIR(inode->i_mode)) {
@@ -348,7 +341,7 @@ int ll_file_release(struct inode *inode, struct file *file)
if (CFS_FAIL_TIMEOUT_MS(OBD_FAIL_PTLRPC_DUMP_LOG, cfs_fail_val))
libcfs_debug_dumplog();
- RETURN(rc);
+ return rc;
}
static int ll_intent_file_open(struct file *file, void *lmm,
@@ -362,10 +355,9 @@ static int ll_intent_file_open(struct file *file, void *lmm,
struct ptlrpc_request *req;
__u32 opc = LUSTRE_OPC_ANY;
int rc;
- ENTRY;
if (!parent)
- RETURN(-ENOENT);
+ return -ENOENT;
/* Usually we come here only for NFSD, and we want open lock.
But we can also get here with pre 2.6.15 patchless kernels, and in
@@ -386,7 +378,7 @@ static int ll_intent_file_open(struct file *file, void *lmm,
file->f_dentry->d_inode, name, len,
O_RDWR, opc, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
itp->it_flags |= MDS_OPEN_BY_FID;
rc = md_intent_lock(sbi->ll_md_exp, op_data, lmm, lmmsize, itp,
@@ -422,7 +414,7 @@ out:
it_clear_disposition(itp, DISP_ENQ_COMPLETE);
ll_intent_drop_lock(itp);
- RETURN(rc);
+ return rc;
}
/**
@@ -464,7 +456,6 @@ int ll_local_open(struct file *file, struct lookup_intent *it,
{
struct inode *inode = file->f_dentry->d_inode;
struct ll_inode_info *lli = ll_i2info(inode);
- ENTRY;
LASSERT(!LUSTRE_FPRIVATE(file));
@@ -477,7 +468,7 @@ int ll_local_open(struct file *file, struct lookup_intent *it,
rc = ll_och_fill(ll_i2sbi(inode)->ll_md_exp, lli, it, och);
if (rc)
- RETURN(rc);
+ return rc;
body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
if ((it->it_flags & FMODE_WRITE) &&
@@ -489,7 +480,7 @@ int ll_local_open(struct file *file, struct lookup_intent *it,
LUSTRE_FPRIVATE(file) = fd;
ll_readahead_init(inode, &fd->fd_ras);
fd->fd_omode = it->it_flags;
- RETURN(0);
+ return 0;
}
/* Open a file, and (for the very first open) create objects on the OSTs at
@@ -514,7 +505,6 @@ int ll_file_open(struct inode *inode, struct file *file)
__u64 *och_usecount = NULL;
struct ll_file_data *fd;
int rc = 0, opendir_set = 0;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), flags %o\n", inode->i_ino,
inode->i_generation, inode, file->f_flags);
@@ -524,7 +514,7 @@ int ll_file_open(struct inode *inode, struct file *file)
fd = ll_file_data_get();
if (fd == NULL)
- GOTO(out_och_free, rc = -ENOMEM);
+ GOTO(out_openerr, rc = -ENOMEM);
fd->fd_file = file;
if (S_ISDIR(inode->i_mode)) {
@@ -540,7 +530,7 @@ int ll_file_open(struct inode *inode, struct file *file)
if (inode->i_sb->s_root == file->f_dentry) {
LUSTRE_FPRIVATE(file) = fd;
- RETURN(0);
+ return 0;
}
if (!it || !it->d.lustre.it_disposition) {
@@ -700,8 +690,6 @@ static int ll_lsm_getattr(struct lov_stripe_md *lsm, struct obd_export *exp,
struct obd_info oinfo = { { { 0 } } };
int rc;
- ENTRY;
-
LASSERT(lsm != NULL);
oinfo.oi_md = lsm;
@@ -736,7 +724,7 @@ static int ll_lsm_getattr(struct lov_stripe_md *lsm, struct obd_export *exp,
OBD_MD_FLATIME | OBD_MD_FLMTIME |
OBD_MD_FLCTIME | OBD_MD_FLSIZE |
OBD_MD_FLDATAVERSION);
- RETURN(rc);
+ return rc;
}
/**
@@ -749,7 +737,6 @@ int ll_inode_getattr(struct inode *inode, struct obdo *obdo,
struct obd_capa *capa = ll_mdscapa_get(inode);
struct lov_stripe_md *lsm;
int rc;
- ENTRY;
lsm = ccc_inode_lsm_get(inode);
rc = ll_lsm_getattr(lsm, ll_i2dtexp(inode),
@@ -765,7 +752,7 @@ int ll_inode_getattr(struct inode *inode, struct obdo *obdo,
(unsigned long)ll_inode_blksize(inode));
}
ccc_inode_lsm_put(inode, lsm);
- RETURN(rc);
+ return rc;
}
int ll_merge_lvb(const struct lu_env *env, struct inode *inode)
@@ -776,8 +763,6 @@ int ll_merge_lvb(const struct lu_env *env, struct inode *inode)
struct ost_lvb lvb;
int rc = 0;
- ENTRY;
-
ll_inode_size_lock(inode);
/* merge timestamps the most recently obtained from mds with
timestamps obtained from osts */
@@ -810,7 +795,7 @@ int ll_merge_lvb(const struct lu_env *env, struct inode *inode)
}
ll_inode_size_unlock(inode);
- RETURN(rc);
+ return rc;
}
int ll_glimpse_ioctl(struct ll_sb_info *sbi, struct lov_stripe_md *lsm,
@@ -860,7 +845,6 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args,
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
struct cl_io *io;
ssize_t result;
- ENTRY;
restart:
io = ccc_env_thread_io(env);
@@ -986,15 +970,14 @@ static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
size_t count;
ssize_t result;
int refcheck;
- ENTRY;
result = ll_file_get_iov_count(iov, &nr_segs, &count);
if (result)
- RETURN(result);
+ return result;
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
args = vvp_env_args(env, IO_NORMAL);
args->u.normal.via_iov = (struct iovec *)iov;
@@ -1004,7 +987,7 @@ static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ,
&iocb->ki_pos, count);
cl_env_put(env, &refcheck);
- RETURN(result);
+ return result;
}
static ssize_t ll_file_read(struct file *file, char *buf, size_t count,
@@ -1015,11 +998,10 @@ static ssize_t ll_file_read(struct file *file, char *buf, size_t count,
struct kiocb *kiocb;
ssize_t result;
int refcheck;
- ENTRY;
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
local_iov = &vvp_env_info(env)->vti_local_iov;
kiocb = &vvp_env_info(env)->vti_kiocb;
@@ -1033,7 +1015,7 @@ static ssize_t ll_file_read(struct file *file, char *buf, size_t count,
*ppos = kiocb->ki_pos;
cl_env_put(env, &refcheck);
- RETURN(result);
+ return result;
}
/*
@@ -1047,15 +1029,14 @@ static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
size_t count;
ssize_t result;
int refcheck;
- ENTRY;
result = ll_file_get_iov_count(iov, &nr_segs, &count);
if (result)
- RETURN(result);
+ return result;
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
args = vvp_env_args(env, IO_NORMAL);
args->u.normal.via_iov = (struct iovec *)iov;
@@ -1065,7 +1046,7 @@ static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE,
&iocb->ki_pos, count);
cl_env_put(env, &refcheck);
- RETURN(result);
+ return result;
}
static ssize_t ll_file_write(struct file *file, const char *buf, size_t count,
@@ -1076,11 +1057,10 @@ static ssize_t ll_file_write(struct file *file, const char *buf, size_t count,
struct kiocb *kiocb;
ssize_t result;
int refcheck;
- ENTRY;
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
local_iov = &vvp_env_info(env)->vti_local_iov;
kiocb = &vvp_env_info(env)->vti_kiocb;
@@ -1094,7 +1074,7 @@ static ssize_t ll_file_write(struct file *file, const char *buf, size_t count,
*ppos = kiocb->ki_pos;
cl_env_put(env, &refcheck);
- RETURN(result);
+ return result;
}
@@ -1110,11 +1090,10 @@ static ssize_t ll_file_splice_read(struct file *in_file, loff_t *ppos,
struct vvp_io_args *args;
ssize_t result;
int refcheck;
- ENTRY;
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
args = vvp_env_args(env, IO_SPLICE);
args->u.splice.via_pipe = pipe;
@@ -1122,7 +1101,7 @@ static ssize_t ll_file_splice_read(struct file *in_file, loff_t *ppos,
result = ll_file_io_generic(env, args, in_file, CIT_READ, ppos, count);
cl_env_put(env, &refcheck);
- RETURN(result);
+ return result;
}
static int ll_lov_recreate(struct inode *inode, struct ost_id *oi,
@@ -1134,14 +1113,13 @@ static int ll_lov_recreate(struct inode *inode, struct ost_id *oi,
int lsm_size;
int rc = 0;
struct lov_stripe_md *lsm = NULL, *lsm2;
- ENTRY;
OBDO_ALLOC(oa);
if (oa == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lsm = ccc_inode_lsm_get(inode);
- if (lsm == NULL)
+ if (!lsm_has_objects(lsm))
GOTO(out, rc = -ENOENT);
lsm_size = sizeof(*lsm) + (sizeof(struct lov_oinfo) *
@@ -1175,18 +1153,17 @@ static int ll_lov_recreate_obj(struct inode *inode, unsigned long arg)
{
struct ll_recreate_obj ucreat;
struct ost_id oi;
- ENTRY;
if (!cfs_capable(CFS_CAP_SYS_ADMIN))
- RETURN(-EPERM);
+ return -EPERM;
if (copy_from_user(&ucreat, (struct ll_recreate_obj *)arg,
sizeof(ucreat)))
- RETURN(-EFAULT);
+ return -EFAULT;
ostid_set_seq_mdt0(&oi);
ostid_set_id(&oi, ucreat.lrc_id);
- RETURN(ll_lov_recreate(inode, &oi, ucreat.lrc_ost_idx));
+ return ll_lov_recreate(inode, &oi, ucreat.lrc_ost_idx);
}
static int ll_lov_recreate_fid(struct inode *inode, unsigned long arg)
@@ -1194,17 +1171,16 @@ static int ll_lov_recreate_fid(struct inode *inode, unsigned long arg)
struct lu_fid fid;
struct ost_id oi;
obd_count ost_idx;
- ENTRY;
if (!cfs_capable(CFS_CAP_SYS_ADMIN))
- RETURN(-EPERM);
+ return -EPERM;
if (copy_from_user(&fid, (struct lu_fid *)arg, sizeof(fid)))
- RETURN(-EFAULT);
+ return -EFAULT;
fid_to_ostid(&fid, &oi);
ost_idx = (fid_seq(&fid) >> 16) & 0xffff;
- RETURN(ll_lov_recreate(inode, &oi, ost_idx));
+ return ll_lov_recreate(inode, &oi, ost_idx);
}
int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
@@ -1213,14 +1189,13 @@ int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
struct lov_stripe_md *lsm = NULL;
struct lookup_intent oit = {.it_op = IT_OPEN, .it_flags = flags};
int rc = 0;
- ENTRY;
lsm = ccc_inode_lsm_get(inode);
if (lsm != NULL) {
ccc_inode_lsm_put(inode, lsm);
CDEBUG(D_IOCTL, "stripe already exists for ino %lu\n",
inode->i_ino);
- RETURN(-EEXIST);
+ return -EEXIST;
}
ll_inode_size_lock(inode);
@@ -1237,7 +1212,7 @@ int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
ll_inode_size_unlock(inode);
ll_intent_release(&oit);
ccc_inode_lsm_put(inode, lsm);
- RETURN(rc);
+ return rc;
out_req_free:
ptlrpc_req_finished((struct ptlrpc_request *) oit.d.lustre.it_data);
goto out;
@@ -1256,13 +1231,13 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename,
rc = ll_get_max_mdsize(sbi, &lmmsize);
if (rc)
- RETURN(rc);
+ return rc;
op_data = ll_prep_md_op_data(NULL, inode, NULL, filename,
strlen(filename), lmmsize,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
op_data->op_valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA;
rc = md_getattr_name(sbi->ll_md_exp, op_data, &req);
@@ -1297,6 +1272,12 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename,
* passing it to userspace.
*/
if (LOV_MAGIC != cpu_to_le32(LOV_MAGIC)) {
+ int stripe_count;
+
+ stripe_count = le16_to_cpu(lmm->lmm_stripe_count);
+ if (le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED)
+ stripe_count = 0;
+
/* if function called for directory - we should
* avoid swab not existent lsm objects */
if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V1)) {
@@ -1304,13 +1285,13 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename,
if (S_ISREG(body->mode))
lustre_swab_lov_user_md_objects(
((struct lov_user_md_v1 *)lmm)->lmm_objects,
- ((struct lov_user_md_v1 *)lmm)->lmm_stripe_count);
+ stripe_count);
} else if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V3)) {
lustre_swab_lov_user_md_v3((struct lov_user_md_v3 *)lmm);
if (S_ISREG(body->mode))
lustre_swab_lov_user_md_objects(
((struct lov_user_md_v3 *)lmm)->lmm_objects,
- ((struct lov_user_md_v3 *)lmm)->lmm_stripe_count);
+ stripe_count);
}
}
@@ -1329,24 +1310,23 @@ static int ll_lov_setea(struct inode *inode, struct file *file,
int lum_size = sizeof(struct lov_user_md) +
sizeof(struct lov_user_ost_data);
int rc;
- ENTRY;
if (!cfs_capable(CFS_CAP_SYS_ADMIN))
- RETURN(-EPERM);
+ return -EPERM;
OBD_ALLOC_LARGE(lump, lum_size);
if (lump == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (copy_from_user(lump, (struct lov_user_md *)arg, lum_size)) {
OBD_FREE_LARGE(lump, lum_size);
- RETURN(-EFAULT);
+ return -EFAULT;
}
rc = ll_lov_setstripe_ea_info(inode, file, flags, lump, lum_size);
OBD_FREE_LARGE(lump, lum_size);
- RETURN(rc);
+ return rc;
}
static int ll_lov_setstripe(struct inode *inode, struct file *file,
@@ -1358,17 +1338,16 @@ static int ll_lov_setstripe(struct inode *inode, struct file *file,
struct lov_user_md_v3 *lumv3p = (struct lov_user_md_v3 *)arg;
int lum_size, rc;
int flags = FMODE_WRITE;
- ENTRY;
/* first try with v1 which is smaller than v3 */
lum_size = sizeof(struct lov_user_md_v1);
if (copy_from_user(lumv1, lumv1p, lum_size))
- RETURN(-EFAULT);
+ return -EFAULT;
if (lumv1->lmm_magic == LOV_USER_MAGIC_V3) {
lum_size = sizeof(struct lov_user_md_v3);
if (copy_from_user(&lumv3, lumv3p, lum_size))
- RETURN(-EFAULT);
+ return -EFAULT;
}
rc = ll_lov_setstripe_ea_info(inode, file, flags, lumv1, lum_size);
@@ -1384,21 +1363,20 @@ static int ll_lov_setstripe(struct inode *inode, struct file *file,
0, lsm, (void *)arg);
ccc_inode_lsm_put(inode, lsm);
}
- RETURN(rc);
+ return rc;
}
static int ll_lov_getstripe(struct inode *inode, unsigned long arg)
{
struct lov_stripe_md *lsm;
int rc = -ENODATA;
- ENTRY;
lsm = ccc_inode_lsm_get(inode);
if (lsm != NULL)
rc = obd_iocontrol(LL_IOC_LOV_GETSTRIPE, ll_i2dtexp(inode), 0,
lsm, (void *)arg);
ccc_inode_lsm_put(inode, lsm);
- RETURN(rc);
+ return rc;
}
int ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
@@ -1407,17 +1385,16 @@ int ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
struct ccc_grouplock grouplock;
int rc;
- ENTRY;
if (ll_file_nolock(file))
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
spin_lock(&lli->lli_lock);
if (fd->fd_flags & LL_FILE_GROUP_LOCKED) {
CWARN("group lock already existed with gid %lu\n",
fd->fd_grouplock.cg_gid);
spin_unlock(&lli->lli_lock);
- RETURN(-EINVAL);
+ return -EINVAL;
}
LASSERT(fd->fd_grouplock.cg_lock == NULL);
spin_unlock(&lli->lli_lock);
@@ -1425,14 +1402,14 @@ int ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
rc = cl_get_grouplock(cl_i2info(inode)->lli_clob,
arg, (file->f_flags & O_NONBLOCK), &grouplock);
if (rc)
- RETURN(rc);
+ return rc;
spin_lock(&lli->lli_lock);
if (fd->fd_flags & LL_FILE_GROUP_LOCKED) {
spin_unlock(&lli->lli_lock);
CERROR("another thread just won the race\n");
cl_put_grouplock(&grouplock);
- RETURN(-EINVAL);
+ return -EINVAL;
}
fd->fd_flags |= LL_FILE_GROUP_LOCKED;
@@ -1440,7 +1417,7 @@ int ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
spin_unlock(&lli->lli_lock);
CDEBUG(D_INFO, "group lock %lu obtained\n", arg);
- RETURN(0);
+ return 0;
}
int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg)
@@ -1448,13 +1425,12 @@ int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg)
struct ll_inode_info *lli = ll_i2info(inode);
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
struct ccc_grouplock grouplock;
- ENTRY;
spin_lock(&lli->lli_lock);
if (!(fd->fd_flags & LL_FILE_GROUP_LOCKED)) {
spin_unlock(&lli->lli_lock);
CWARN("no group lock held\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
LASSERT(fd->fd_grouplock.cg_lock != NULL);
@@ -1462,7 +1438,7 @@ int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg)
CWARN("group lock %lu doesn't match current id %lu\n",
arg, fd->fd_grouplock.cg_gid);
spin_unlock(&lli->lli_lock);
- RETURN(-EINVAL);
+ return -EINVAL;
}
grouplock = fd->fd_grouplock;
@@ -1472,7 +1448,7 @@ int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg)
cl_put_grouplock(&grouplock);
CDEBUG(D_INFO, "group lock %lu released\n", arg);
- RETURN(0);
+ return 0;
}
/**
@@ -1489,17 +1465,16 @@ int ll_release_openhandle(struct dentry *dentry, struct lookup_intent *it)
struct inode *inode = dentry->d_inode;
struct obd_client_handle *och;
int rc;
- ENTRY;
LASSERT(inode);
/* Root ? Do nothing. */
if (dentry->d_inode->i_sb->s_root == dentry)
- RETURN(0);
+ return 0;
/* No open handle to close? Move away */
if (!it_disposition(it, DISP_OPEN_OPEN))
- RETURN(0);
+ return 0;
LASSERT(it_open_error(DISP_OPEN_OPEN, it) == 0);
@@ -1518,7 +1493,7 @@ int ll_release_openhandle(struct dentry *dentry, struct lookup_intent *it)
ptlrpc_req_finished(it->d.lustre.it_data);
it_clear_disposition(it, DISP_ENQ_OPEN_REF);
}
- RETURN(rc);
+ return rc;
}
/**
@@ -1533,7 +1508,6 @@ int ll_do_fiemap(struct inode *inode, struct ll_user_fiemap *fiemap,
struct ll_fiemap_info_key fm_key = { .name = KEY_FIEMAP, };
int vallen = num_bytes;
int rc;
- ENTRY;
/* Checks for fiemap flags */
if (fiemap->fm_flags & ~LUSTRE_FIEMAP_FLAGS_COMPAT) {
@@ -1579,7 +1553,7 @@ int ll_do_fiemap(struct inode *inode, struct ll_user_fiemap *fiemap,
out:
ccc_inode_lsm_put(inode, lsm);
- RETURN(rc);
+ return rc;
}
int ll_fid2path(struct inode *inode, void *arg)
@@ -1587,26 +1561,25 @@ int ll_fid2path(struct inode *inode, void *arg)
struct obd_export *exp = ll_i2mdexp(inode);
struct getinfo_fid2path *gfout, *gfin;
int outsize, rc;
- ENTRY;
if (!cfs_capable(CFS_CAP_DAC_READ_SEARCH) &&
!(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH))
- RETURN(-EPERM);
+ return -EPERM;
/* Need to get the buflen */
OBD_ALLOC_PTR(gfin);
if (gfin == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (copy_from_user(gfin, arg, sizeof(*gfin))) {
OBD_FREE_PTR(gfin);
- RETURN(-EFAULT);
+ return -EFAULT;
}
outsize = sizeof(*gfout) + gfin->gf_pathlen;
OBD_ALLOC(gfout, outsize);
if (gfout == NULL) {
OBD_FREE_PTR(gfin);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
memcpy(gfout, gfin, sizeof(*gfout));
OBD_FREE_PTR(gfin);
@@ -1621,7 +1594,7 @@ int ll_fid2path(struct inode *inode, void *arg)
gf_free:
OBD_FREE(gfout, outsize);
- RETURN(rc);
+ return rc;
}
static int ll_ioctl_fiemap(struct inode *inode, unsigned long arg)
@@ -1635,13 +1608,13 @@ static int ll_ioctl_fiemap(struct inode *inode, unsigned long arg)
* required fiemap buffer */
if (get_user(extent_count,
&((struct ll_user_fiemap __user *)arg)->fm_extent_count))
- RETURN(-EFAULT);
+ return -EFAULT;
num_bytes = sizeof(*fiemap_s) + (extent_count *
sizeof(struct ll_fiemap_extent));
OBD_ALLOC_LARGE(fiemap_s, num_bytes);
if (fiemap_s == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* get the fiemap value */
if (copy_from_user(fiemap_s, (struct ll_user_fiemap __user *)arg,
@@ -1673,7 +1646,7 @@ static int ll_ioctl_fiemap(struct inode *inode, unsigned long arg)
error:
OBD_FREE_LARGE(fiemap_s, num_bytes);
- RETURN(rc);
+ return rc;
}
/*
@@ -1692,24 +1665,21 @@ int ll_data_version(struct inode *inode, __u64 *data_version,
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct obdo *obdo = NULL;
int rc;
- ENTRY;
/* If no stripe, we consider version is 0. */
lsm = ccc_inode_lsm_get(inode);
- if (lsm == NULL) {
+ if (!lsm_has_objects(lsm)) {
*data_version = 0;
CDEBUG(D_INODE, "No object for inode\n");
- RETURN(0);
+ GOTO(out, rc = 0);
}
OBD_ALLOC_PTR(obdo);
- if (obdo == NULL) {
- ccc_inode_lsm_put(inode, lsm);
- RETURN(-ENOMEM);
- }
+ if (obdo == NULL)
+ GOTO(out, rc = -ENOMEM);
rc = ll_lsm_getattr(lsm, sbi->ll_dt_exp, NULL, obdo, 0, extent_lock);
- if (!rc) {
+ if (rc == 0) {
if (!(obdo->o_valid & OBD_MD_FLDATAVERSION))
rc = -EOPNOTSUPP;
else
@@ -1717,9 +1687,9 @@ int ll_data_version(struct inode *inode, __u64 *data_version,
}
OBD_FREE_PTR(obdo);
+out:
ccc_inode_lsm_put(inode, lsm);
-
- RETURN(rc);
+ return rc;
}
struct ll_swap_stack {
@@ -1741,7 +1711,7 @@ static int ll_swap_layouts(struct file *file1, struct file *file2,
OBD_ALLOC_PTR(llss);
if (llss == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
llss->inode1 = file1->f_dentry->d_inode;
llss->inode2 = file2->f_dentry->d_inode;
@@ -1749,8 +1719,8 @@ static int ll_swap_layouts(struct file *file1, struct file *file2,
if (!S_ISREG(llss->inode2->i_mode))
GOTO(free, rc = -EINVAL);
- if (ll_permission(llss->inode1, MAY_WRITE, NULL) ||
- ll_permission(llss->inode2, MAY_WRITE, NULL))
+ if (inode_permission(llss->inode1, MAY_WRITE) ||
+ inode_permission(llss->inode2, MAY_WRITE))
GOTO(free, rc = -EPERM);
if (llss->inode2->i_sb != llss->inode1->i_sb)
@@ -1830,12 +1800,12 @@ static int ll_swap_layouts(struct file *file1, struct file *file2,
rc = -ENOMEM;
op_data = ll_prep_md_op_data(NULL, llss->inode1, llss->inode2, NULL, 0,
0, LUSTRE_OPC_ANY, &msl);
- if (op_data != NULL) {
- rc = obd_iocontrol(LL_IOC_LOV_SWAP_LAYOUTS,
- ll_i2mdexp(llss->inode1),
- sizeof(*op_data), op_data, NULL);
- ll_finish_md_op_data(op_data);
- }
+ if (IS_ERR(op_data))
+ GOTO(free, rc = PTR_ERR(op_data));
+
+ rc = obd_iocontrol(LL_IOC_LOV_SWAP_LAYOUTS, ll_i2mdexp(llss->inode1),
+ sizeof(*op_data), op_data, NULL);
+ ll_finish_md_op_data(op_data);
putgl:
if (gid != 0) {
@@ -1880,7 +1850,7 @@ free:
if (llss != NULL)
OBD_FREE_PTR(llss);
- RETURN(rc);
+ return rc;
}
long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1888,7 +1858,6 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct inode *inode = file->f_dentry->d_inode;
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
int flags, rc;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p),cmd=%x\n", inode->i_ino,
inode->i_generation, inode, cmd);
@@ -1896,7 +1865,7 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
/* asm-ppc{,64} declares TCGETS, et. al. as type 't' not 'T' */
if (_IOC_TYPE(cmd) == 'T' || _IOC_TYPE(cmd) == 't') /* tty ioctls */
- RETURN(-ENOTTY);
+ return -ENOTTY;
switch(cmd) {
case LL_IOC_GETFLAGS:
@@ -1909,66 +1878,66 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
* not abused, and to handle any flag side effects.
*/
if (get_user(flags, (int *) arg))
- RETURN(-EFAULT);
+ return -EFAULT;
if (cmd == LL_IOC_SETFLAGS) {
if ((flags & LL_FILE_IGNORE_LOCK) &&
!(file->f_flags & O_DIRECT)) {
CERROR("%s: unable to disable locking on "
"non-O_DIRECT file\n", current->comm);
- RETURN(-EINVAL);
+ return -EINVAL;
}
fd->fd_flags |= flags;
} else {
fd->fd_flags &= ~flags;
}
- RETURN(0);
+ return 0;
case LL_IOC_LOV_SETSTRIPE:
- RETURN(ll_lov_setstripe(inode, file, arg));
+ return ll_lov_setstripe(inode, file, arg);
case LL_IOC_LOV_SETEA:
- RETURN(ll_lov_setea(inode, file, arg));
+ return ll_lov_setea(inode, file, arg);
case LL_IOC_LOV_SWAP_LAYOUTS: {
struct file *file2;
struct lustre_swap_layouts lsl;
if (copy_from_user(&lsl, (char *)arg,
sizeof(struct lustre_swap_layouts)))
- RETURN(-EFAULT);
+ return -EFAULT;
if ((file->f_flags & O_ACCMODE) == 0) /* O_RDONLY */
- RETURN(-EPERM);
+ return -EPERM;
file2 = fget(lsl.sl_fd);
if (file2 == NULL)
- RETURN(-EBADF);
+ return -EBADF;
rc = -EPERM;
if ((file2->f_flags & O_ACCMODE) != 0) /* O_WRONLY or O_RDWR */
rc = ll_swap_layouts(file, file2, &lsl);
fput(file2);
- RETURN(rc);
+ return rc;
}
case LL_IOC_LOV_GETSTRIPE:
- RETURN(ll_lov_getstripe(inode, arg));
+ return ll_lov_getstripe(inode, arg);
case LL_IOC_RECREATE_OBJ:
- RETURN(ll_lov_recreate_obj(inode, arg));
+ return ll_lov_recreate_obj(inode, arg);
case LL_IOC_RECREATE_FID:
- RETURN(ll_lov_recreate_fid(inode, arg));
+ return ll_lov_recreate_fid(inode, arg);
case FSFILT_IOC_FIEMAP:
- RETURN(ll_ioctl_fiemap(inode, arg));
+ return ll_ioctl_fiemap(inode, arg);
case FSFILT_IOC_GETFLAGS:
case FSFILT_IOC_SETFLAGS:
- RETURN(ll_iocontrol(inode, file, cmd, arg));
+ return ll_iocontrol(inode, file, cmd, arg);
case FSFILT_IOC_GETVERSION_OLD:
case FSFILT_IOC_GETVERSION:
- RETURN(put_user(inode->i_generation, (int *)arg));
+ return put_user(inode->i_generation, (int *)arg);
case LL_IOC_GROUP_LOCK:
- RETURN(ll_get_grouplock(inode, file, arg));
+ return ll_get_grouplock(inode, file, arg);
case LL_IOC_GROUP_UNLOCK:
- RETURN(ll_put_grouplock(inode, file, arg));
+ return ll_put_grouplock(inode, file, arg);
case IOC_OBD_STATFS:
- RETURN(ll_obd_statfs(inode, (void *)arg));
+ return ll_obd_statfs(inode, (void *)arg);
/* We need to special case any other ioctls we want to handle,
* to send them to the MDS/OST as appropriate and to properly
@@ -1977,30 +1946,30 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case FSFILT_IOC_SETVERSION:
*/
case LL_IOC_FLUSHCTX:
- RETURN(ll_flush_ctx(inode));
+ return ll_flush_ctx(inode);
case LL_IOC_PATH2FID: {
if (copy_to_user((void *)arg, ll_inode2fid(inode),
sizeof(struct lu_fid)))
- RETURN(-EFAULT);
+ return -EFAULT;
- RETURN(0);
+ return 0;
}
case OBD_IOC_FID2PATH:
- RETURN(ll_fid2path(inode, (void *)arg));
+ return ll_fid2path(inode, (void *)arg);
case LL_IOC_DATA_VERSION: {
struct ioc_data_version idv;
int rc;
if (copy_from_user(&idv, (char *)arg, sizeof(idv)))
- RETURN(-EFAULT);
+ return -EFAULT;
rc = ll_data_version(inode, &idv.idv_version,
!(idv.idv_flags & LL_DV_NOFLUSH));
if (rc == 0 && copy_to_user((char *) arg, &idv, sizeof(idv)))
- RETURN(-EFAULT);
+ return -EFAULT;
- RETURN(rc);
+ return rc;
}
case LL_IOC_GET_MDTIDX: {
@@ -2008,16 +1977,16 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
mdtidx = ll_get_mdt_idx(inode);
if (mdtidx < 0)
- RETURN(mdtidx);
+ return mdtidx;
if (put_user((int)mdtidx, (int*)arg))
- RETURN(-EFAULT);
+ return -EFAULT;
- RETURN(0);
+ return 0;
}
case OBD_IOC_GETDTNAME:
case OBD_IOC_GETMDNAME:
- RETURN(ll_get_obd_name(inode, cmd, arg));
+ return ll_get_obd_name(inode, cmd, arg);
case LL_IOC_HSM_STATE_GET: {
struct md_op_data *op_data;
struct hsm_user_state *hus;
@@ -2025,13 +1994,13 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
OBD_ALLOC_PTR(hus);
if (hus == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
LUSTRE_OPC_ANY, hus);
- if (op_data == NULL) {
+ if (IS_ERR(op_data)) {
OBD_FREE_PTR(hus);
- RETURN(-ENOMEM);
+ return PTR_ERR(op_data);
}
rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
@@ -2042,7 +2011,7 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ll_finish_md_op_data(op_data);
OBD_FREE_PTR(hus);
- RETURN(rc);
+ return rc;
}
case LL_IOC_HSM_STATE_SET: {
struct md_op_data *op_data;
@@ -2051,10 +2020,10 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
OBD_ALLOC_PTR(hss);
if (hss == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (copy_from_user(hss, (char *)arg, sizeof(*hss))) {
OBD_FREE_PTR(hss);
- RETURN(-EFAULT);
+ return -EFAULT;
}
/* Non-root users are forbidden to set or clear flags which are
@@ -2062,14 +2031,14 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (((hss->hss_setmask | hss->hss_clearmask) & ~HSM_USER_MASK)
&& !cfs_capable(CFS_CAP_SYS_ADMIN)) {
OBD_FREE_PTR(hss);
- RETURN(-EPERM);
+ return -EPERM;
}
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
LUSTRE_OPC_ANY, hss);
- if (op_data == NULL) {
+ if (IS_ERR(op_data)) {
OBD_FREE_PTR(hss);
- RETURN(-ENOMEM);
+ return PTR_ERR(op_data);
}
rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
@@ -2078,7 +2047,7 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ll_finish_md_op_data(op_data);
OBD_FREE_PTR(hss);
- RETURN(rc);
+ return rc;
}
case LL_IOC_HSM_ACTION: {
struct md_op_data *op_data;
@@ -2087,13 +2056,13 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
OBD_ALLOC_PTR(hca);
if (hca == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
LUSTRE_OPC_ANY, hca);
- if (op_data == NULL) {
+ if (IS_ERR(op_data)) {
OBD_FREE_PTR(hca);
- RETURN(-ENOMEM);
+ return PTR_ERR(op_data);
}
rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
@@ -2104,17 +2073,17 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ll_finish_md_op_data(op_data);
OBD_FREE_PTR(hca);
- RETURN(rc);
+ return rc;
}
default: {
int err;
if (LLIOC_STOP ==
ll_iocontrol_call(inode, file, cmd, arg, &err))
- RETURN(err);
+ return err;
- RETURN(obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL,
- (void *)arg));
+ return obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL,
+ (void *)arg);
}
}
}
@@ -2125,7 +2094,6 @@ loff_t ll_file_seek(struct file *file, loff_t offset, int origin)
struct inode *inode = file->f_dentry->d_inode;
loff_t retval, eof = 0;
- ENTRY;
retval = offset + ((origin == SEEK_END) ? i_size_read(inode) :
(origin == SEEK_CUR) ? file->f_pos : 0);
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), to=%llu=%#llx(%d)\n",
@@ -2136,13 +2104,13 @@ loff_t ll_file_seek(struct file *file, loff_t offset, int origin)
if (origin == SEEK_END || origin == SEEK_HOLE || origin == SEEK_DATA) {
retval = ll_glimpse_size(inode);
if (retval != 0)
- RETURN(retval);
+ return retval;
eof = i_size_read(inode);
}
- retval = ll_generic_file_llseek_size(file, offset, origin,
+ retval = generic_file_llseek_size(file, offset, origin,
ll_file_maxbytes(inode), eof);
- RETURN(retval);
+ return retval;
}
int ll_flush(struct file *file, fl_owner_t id)
@@ -2184,15 +2152,14 @@ int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end,
struct obd_capa *capa = NULL;
struct cl_fsync_io *fio;
int result;
- ENTRY;
if (mode != CL_FSYNC_NONE && mode != CL_FSYNC_LOCAL &&
mode != CL_FSYNC_DISCARD && mode != CL_FSYNC_ALL)
- RETURN(-EINVAL);
+ return -EINVAL;
env = cl_env_nested_get(&nest);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
capa = ll_osscapa_get(inode, CAPA_OPC_OSS_WRITE);
@@ -2220,7 +2187,7 @@ int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end,
capa_put(capa);
- RETURN(result);
+ return result;
}
/*
@@ -2237,7 +2204,6 @@ int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync)
struct ptlrpc_request *req;
struct obd_capa *oc;
int rc, err;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino,
inode->i_generation, inode);
@@ -2281,23 +2247,24 @@ int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync)
}
mutex_unlock(&inode->i_mutex);
- RETURN(rc);
+ return rc;
}
int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
{
struct inode *inode = file->f_dentry->d_inode;
struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct ldlm_enqueue_info einfo = { .ei_type = LDLM_FLOCK,
- .ei_cb_cp =ldlm_flock_completion_ast,
- .ei_cbdata = file_lock };
+ struct ldlm_enqueue_info einfo = {
+ .ei_type = LDLM_FLOCK,
+ .ei_cb_cp = ldlm_flock_completion_ast,
+ .ei_cbdata = file_lock,
+ };
struct md_op_data *op_data;
struct lustre_handle lockh = {0};
ldlm_policy_data_t flock = {{0}};
int flags = 0;
int rc;
int rc2 = 0;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu file_lock=%p\n",
inode->i_ino, file_lock);
@@ -2315,7 +2282,7 @@ int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
flock.l_flock.start = file_lock->fl_start;
flock.l_flock.end = file_lock->fl_end;
} else {
- RETURN(-EINVAL);
+ return -EINVAL;
}
flock.l_flock.pid = file_lock->fl_pid;
@@ -2350,7 +2317,7 @@ int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
default:
CDEBUG(D_INFO, "Unknown fcntl lock type: %d\n",
file_lock->fl_type);
- RETURN (-ENOTSUPP);
+ return -ENOTSUPP;
}
switch (cmd) {
@@ -2377,13 +2344,13 @@ int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
break;
default:
CERROR("unknown fcntl lock command: %d\n", cmd);
- RETURN (-EINVAL);
+ return -EINVAL;
}
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
CDEBUG(D_DLMTRACE, "inode=%lu, pid=%u, flags=%#x, mode=%u, "
"start="LPU64", end="LPU64"\n", inode->i_ino, flock.l_flock.pid,
@@ -2409,14 +2376,12 @@ int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
ll_finish_md_op_data(op_data);
- RETURN(rc);
+ return rc;
}
int ll_file_noflock(struct file *file, int cmd, struct file_lock *file_lock)
{
- ENTRY;
-
- RETURN(-ENOSYS);
+ return -ENOSYS;
}
/**
@@ -2438,17 +2403,16 @@ int ll_have_md_lock(struct inode *inode, __u64 *bits, ldlm_mode_t l_req_mode)
struct lu_fid *fid;
__u64 flags;
int i;
- ENTRY;
if (!inode)
- RETURN(0);
+ return 0;
fid = &ll_i2info(inode)->lli_fid;
CDEBUG(D_INFO, "trying to match res "DFID" mode %s\n", PFID(fid),
ldlm_lockname[mode]);
flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING | LDLM_FL_TEST_LOCK;
- for (i = 0; i < MDS_INODELOCK_MAXSHIFT && *bits != 0; i++) {
+ for (i = 0; i <= MDS_INODELOCK_MAXSHIFT && *bits != 0; i++) {
policy.l_inodebits.bits = *bits & (1 << i);
if (policy.l_inodebits.bits == 0)
continue;
@@ -2467,7 +2431,7 @@ int ll_have_md_lock(struct inode *inode, __u64 *bits, ldlm_mode_t l_req_mode)
}
}
}
- RETURN(*bits == 0);
+ return *bits == 0;
}
ldlm_mode_t ll_take_md_lock(struct inode *inode, __u64 bits,
@@ -2476,7 +2440,6 @@ ldlm_mode_t ll_take_md_lock(struct inode *inode, __u64 bits,
ldlm_policy_data_t policy = { .l_inodebits = {bits}};
struct lu_fid *fid;
ldlm_mode_t rc;
- ENTRY;
fid = &ll_i2info(inode)->lli_fid;
CDEBUG(D_INFO, "trying to match res "DFID"\n", PFID(fid));
@@ -2484,7 +2447,7 @@ ldlm_mode_t ll_take_md_lock(struct inode *inode, __u64 bits,
rc = md_lock_match(ll_i2mdexp(inode), LDLM_FL_BLOCK_GRANTED|flags,
fid, LDLM_IBITS, &policy,
LCK_CR|LCK_CW|LCK_PR|LCK_PW, lockh);
- RETURN(rc);
+ return rc;
}
static int ll_inode_revalidate_fini(struct inode *inode, int rc)
@@ -2513,7 +2476,6 @@ int __ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
struct ptlrpc_request *req = NULL;
struct obd_export *exp;
int rc = 0;
- ENTRY;
LASSERT(inode != NULL);
@@ -2537,7 +2499,7 @@ int __ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
dentry->d_inode, NULL, 0, 0,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
oit.it_create_mode |= M_CHECK_STALE;
rc = md_intent_lock(exp, op_data, NULL, 0,
@@ -2575,7 +2537,7 @@ int __ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
if (S_ISREG(inode->i_mode)) {
rc = ll_get_max_mdsize(sbi, &ealen);
if (rc)
- RETURN(rc);
+ return rc;
valid |= OBD_MD_FLEASIZE | OBD_MD_FLMODEASIZE;
}
@@ -2583,7 +2545,7 @@ int __ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
0, ealen, LUSTRE_OPC_ANY,
NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
op_data->op_valid = valid;
/* Once OBD_CONNECT_ATTRFID is not supported, we can't find one
@@ -2593,7 +2555,7 @@ int __ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
ll_finish_md_op_data(op_data);
if (rc) {
rc = ll_inode_revalidate_fini(inode, rc);
- RETURN(rc);
+ return rc;
}
rc = ll_prep_inode(&inode, req, NULL, NULL);
@@ -2608,11 +2570,10 @@ int ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
{
struct inode *inode = dentry->d_inode;
int rc;
- ENTRY;
rc = __ll_inode_revalidate_it(dentry, it, ibits);
if (rc != 0)
- RETURN(rc);
+ return rc;
/* if object isn't regular file, don't validate size */
if (!S_ISREG(inode->i_mode)) {
@@ -2622,7 +2583,7 @@ int ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
} else {
rc = ll_glimpse_size(inode);
}
- RETURN(rc);
+ return rc;
}
int ll_getattr_it(struct vfsmount *mnt, struct dentry *de,
@@ -2672,21 +2633,19 @@ struct posix_acl * ll_get_acl(struct inode *inode, int type)
{
struct ll_inode_info *lli = ll_i2info(inode);
struct posix_acl *acl = NULL;
- ENTRY;
spin_lock(&lli->lli_lock);
/* VFS' acl_permission_check->check_acl will release the refcount */
acl = posix_acl_dup(lli->lli_posix_acl);
spin_unlock(&lli->lli_lock);
- RETURN(acl);
+ return acl;
}
int ll_inode_permission(struct inode *inode, int mask)
{
int rc = 0;
- ENTRY;
#ifdef MAY_NOT_BLOCK
if (mask & MAY_NOT_BLOCK)
@@ -2702,7 +2661,7 @@ int ll_inode_permission(struct inode *inode, int mask)
rc = __ll_inode_revalidate_it(inode->i_sb->s_root, &it,
MDS_INODELOCK_LOOKUP);
if (rc)
- RETURN(rc);
+ return rc;
}
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), inode mode %x mask %o\n",
@@ -2712,9 +2671,9 @@ int ll_inode_permission(struct inode *inode, int mask)
return lustre_check_remote_perm(inode, mask);
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_INODE_PERM, 1);
- rc = ll_generic_permission(inode, mask, flags, ll_check_acl);
+ rc = generic_permission(inode, mask);
- RETURN(rc);
+ return rc;
}
#define READ_METHOD aio_read
@@ -2806,16 +2765,15 @@ void *ll_iocontrol_register(llioc_callback_t cb, int count, unsigned int *cmd)
{
unsigned int size;
struct llioc_data *in_data = NULL;
- ENTRY;
if (cb == NULL || cmd == NULL ||
count > LLIOC_MAX_CMD || count < 0)
- RETURN(NULL);
+ return NULL;
size = sizeof(*in_data) + count * sizeof(unsigned int);
OBD_ALLOC(in_data, size);
if (in_data == NULL)
- RETURN(NULL);
+ return NULL;
memset(in_data, 0, sizeof(*in_data));
in_data->iocd_size = size;
@@ -2827,7 +2785,7 @@ void *ll_iocontrol_register(llioc_callback_t cb, int count, unsigned int *cmd)
list_add_tail(&in_data->iocd_list, &llioc.ioc_head);
up_write(&llioc.ioc_sem);
- RETURN(in_data);
+ return in_data;
}
void ll_iocontrol_unregister(void *magic)
@@ -2890,14 +2848,13 @@ int ll_layout_conf(struct inode *inode, const struct cl_object_conf *conf)
struct cl_env_nest nest;
struct lu_env *env;
int result;
- ENTRY;
if (lli->lli_clob == NULL)
- RETURN(0);
+ return 0;
env = cl_env_nested_get(&nest);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
result = cl_conf_set(env, lli->lli_clob, conf);
cl_env_nested_put(&nest, env);
@@ -2915,7 +2872,7 @@ int ll_layout_conf(struct inode *inode, const struct cl_object_conf *conf)
ldlm_lock_allow_match(lock);
}
}
- RETURN(result);
+ return result;
}
/* Fetch layout from MDT with getxattr request, if it's not ready yet */
@@ -2930,10 +2887,13 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock)
void *lmm;
int lmmsize;
int rc;
- ENTRY;
- if (lock->l_lvb_data != NULL)
- RETURN(0);
+ CDEBUG(D_INODE, DFID" LVB_READY=%d l_lvb_data=%p l_lvb_len=%d\n",
+ PFID(ll_inode2fid(inode)), !!(lock->l_flags & LDLM_FL_LVB_READY),
+ lock->l_lvb_data, lock->l_lvb_len);
+
+ if ((lock->l_lvb_data != NULL) && (lock->l_flags & LDLM_FL_LVB_READY))
+ return 0;
/* if layout lock was granted right away, the layout is returned
* within DLM_LVB of dlm reply; otherwise if the lock was ever
@@ -2948,7 +2908,7 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock)
lmmsize, 0, &req);
capa_put(oc);
if (rc < 0)
- RETURN(rc);
+ return rc;
body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
if (body == NULL || body->eadatasize > lmmsize)
@@ -2968,16 +2928,12 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock)
memcpy(lvbdata, lmm, lmmsize);
lock_res_and_lock(lock);
- if (lock->l_lvb_data == NULL) {
- lock->l_lvb_data = lvbdata;
- lock->l_lvb_len = lmmsize;
- lvbdata = NULL;
- }
- unlock_res_and_lock(lock);
+ if (lock->l_lvb_data != NULL)
+ OBD_FREE_LARGE(lock->l_lvb_data, lock->l_lvb_len);
- if (lvbdata != NULL)
- OBD_FREE_LARGE(lvbdata, lmmsize);
- EXIT;
+ lock->l_lvb_data = lvbdata;
+ lock->l_lvb_len = lmmsize;
+ unlock_res_and_lock(lock);
out:
ptlrpc_req_finished(req);
@@ -2999,7 +2955,6 @@ static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode,
int rc = 0;
bool lvb_ready;
bool wait_layout = false;
- ENTRY;
LASSERT(lustre_handle_is_used(lockh));
@@ -3008,7 +2963,7 @@ static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode,
LASSERT(ldlm_has_layout(lock));
LDLM_DEBUG(lock, "File %p/"DFID" being reconfigured: %d.\n",
- inode, PFID(&lli->lli_fid), reconf);
+ inode, PFID(&lli->lli_fid), reconf);
/* in case this is a caching lock and reinstate with new inode */
md_set_lock_data(sbi->ll_md_exp, &lockh->cookie, inode, NULL);
@@ -3068,7 +3023,6 @@ static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode,
/* refresh layout failed, need to wait */
wait_layout = rc == -EBUSY;
- EXIT;
out:
LDLM_LOCK_PUT(lock);
@@ -3090,7 +3044,7 @@ out:
CDEBUG(D_INODE, "file: "DFID" waiting layout return: %d.\n",
PFID(&lli->lli_fid), rc);
}
- RETURN(rc);
+ return rc;
}
/**
@@ -3114,17 +3068,17 @@ int ll_layout_refresh(struct inode *inode, __u32 *gen)
struct lookup_intent it;
struct lustre_handle lockh;
ldlm_mode_t mode;
- struct ldlm_enqueue_info einfo = { .ei_type = LDLM_IBITS,
- .ei_mode = LCK_CR,
- .ei_cb_bl = ll_md_blocking_ast,
- .ei_cb_cp = ldlm_completion_ast,
- .ei_cbdata = NULL };
+ struct ldlm_enqueue_info einfo = {
+ .ei_type = LDLM_IBITS,
+ .ei_mode = LCK_CR,
+ .ei_cb_bl = ll_md_blocking_ast,
+ .ei_cb_cp = ldlm_completion_ast,
+ };
int rc;
- ENTRY;
*gen = lli->lli_layout_gen;
if (!(sbi->ll_flags & LL_SBI_LAYOUT_LOCK))
- RETURN(0);
+ return 0;
/* sanity checks */
LASSERT(fid_is_sane(ll_inode2fid(inode)));
@@ -3136,7 +3090,7 @@ int ll_layout_refresh(struct inode *inode, __u32 *gen)
if (mode != 0) { /* hit cached lock */
rc = ll_layout_lock_set(&lockh, mode, inode, gen, false);
if (rc == 0)
- RETURN(0);
+ return 0;
/* better hold lli_layout_mutex to try again otherwise
* it will have starvation problem. */
@@ -3154,14 +3108,14 @@ again:
goto again;
mutex_unlock(&lli->lli_layout_mutex);
- RETURN(rc);
+ return rc;
}
op_data = ll_prep_md_op_data(NULL, inode, inode, NULL,
0, 0, LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data)) {
mutex_unlock(&lli->lli_layout_mutex);
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
}
/* have to enqueue one */
@@ -3194,5 +3148,5 @@ again:
}
mutex_unlock(&lli->lli_layout_mutex);
- RETURN(rc);
+ return rc;
}
diff --git a/drivers/staging/lustre/lustre/llite/llite_capa.c b/drivers/staging/lustre/lustre/llite/llite_capa.c
index b6fd9593325..edd512b20ee 100644
--- a/drivers/staging/lustre/lustre/llite/llite_capa.c
+++ b/drivers/staging/lustre/lustre/llite/llite_capa.c
@@ -41,7 +41,6 @@
#define DEBUG_SUBSYSTEM S_LLITE
#include <linux/fs.h>
-#include <linux/version.h>
#include <asm/uaccess.h>
#include <linux/file.h>
#include <linux/kmod.h>
@@ -171,7 +170,6 @@ static int capa_thread_main(void *unused)
struct inode *inode = NULL;
struct l_wait_info lwi = { 0 };
int rc;
- ENTRY;
thread_set_flags(&ll_capa_thread, SVC_RUNNING);
wake_up(&ll_capa_thread.t_ctl_waitq);
@@ -281,7 +279,7 @@ static int capa_thread_main(void *unused)
thread_set_flags(&ll_capa_thread, SVC_STOPPED);
wake_up(&ll_capa_thread.t_ctl_waitq);
- RETURN(0);
+ return 0;
}
void ll_capa_timer_callback(unsigned long unused)
@@ -291,8 +289,7 @@ void ll_capa_timer_callback(unsigned long unused)
int ll_capa_thread_start(void)
{
- task_t *task;
- ENTRY;
+ struct task_struct *task;
init_waitqueue_head(&ll_capa_thread.t_ctl_waitq);
@@ -300,12 +297,12 @@ int ll_capa_thread_start(void)
if (IS_ERR(task)) {
CERROR("cannot start expired capa thread: rc %ld\n",
PTR_ERR(task));
- RETURN(PTR_ERR(task));
+ return PTR_ERR(task);
}
wait_event(ll_capa_thread.t_ctl_waitq,
thread_is_running(&ll_capa_thread));
- RETURN(0);
+ return 0;
}
void ll_capa_thread_stop(void)
@@ -322,10 +319,8 @@ struct obd_capa *ll_osscapa_get(struct inode *inode, __u64 opc)
struct obd_capa *ocapa;
int found = 0;
- ENTRY;
-
if ((ll_i2sbi(inode)->ll_flags & LL_SBI_OSS_CAPA) == 0)
- RETURN(NULL);
+ return NULL;
LASSERT(opc == CAPA_OPC_OSS_WRITE || opc == CAPA_OPC_OSS_RW ||
opc == CAPA_OPC_OSS_TRUNC);
@@ -369,7 +364,7 @@ struct obd_capa *ll_osscapa_get(struct inode *inode, __u64 opc)
}
spin_unlock(&capa_lock);
- RETURN(ocapa);
+ return ocapa;
}
EXPORT_SYMBOL(ll_osscapa_get);
@@ -377,12 +372,11 @@ struct obd_capa *ll_mdscapa_get(struct inode *inode)
{
struct ll_inode_info *lli = ll_i2info(inode);
struct obd_capa *ocapa;
- ENTRY;
LASSERT(inode != NULL);
if ((ll_i2sbi(inode)->ll_flags & LL_SBI_MDS_CAPA) == 0)
- RETURN(NULL);
+ return NULL;
spin_lock(&capa_lock);
ocapa = capa_get(lli->lli_mds_capa);
@@ -392,7 +386,7 @@ struct obd_capa *ll_mdscapa_get(struct inode *inode)
atomic_set(&ll_capa_debug, 0);
}
- RETURN(ocapa);
+ return ocapa;
}
static struct obd_capa *do_add_mds_capa(struct inode *inode,
@@ -525,7 +519,6 @@ int ll_update_capa(struct obd_capa *ocapa, struct lustre_capa *capa)
{
struct inode *inode = ocapa->u.cli.inode;
int rc = 0;
- ENTRY;
LASSERT(ocapa);
@@ -561,7 +554,7 @@ int ll_update_capa(struct obd_capa *ocapa, struct lustre_capa *capa)
capa_put(ocapa);
iput(inode);
- RETURN(rc);
+ return rc;
}
spin_lock(&ocapa->c_lock);
@@ -575,7 +568,6 @@ int ll_update_capa(struct obd_capa *ocapa, struct lustre_capa *capa)
if (capa_for_oss(capa))
inode_add_oss_capa(inode, ocapa);
DEBUG_CAPA(D_SEC, capa, "renew");
- EXIT;
retry:
list_del_init(&ocapa->c_list);
sort_add_capa(ocapa, ll_capa_list);
diff --git a/drivers/staging/lustre/lustre/llite/llite_close.c b/drivers/staging/lustre/lustre/llite/llite_close.c
index 00b2b38d4c9..1f5825c87a7 100644
--- a/drivers/staging/lustre/lustre/llite/llite_close.c
+++ b/drivers/staging/lustre/lustre/llite/llite_close.c
@@ -50,14 +50,12 @@ void vvp_write_pending(struct ccc_object *club, struct ccc_page *page)
{
struct ll_inode_info *lli = ll_i2info(club->cob_inode);
- ENTRY;
spin_lock(&lli->lli_lock);
lli->lli_flags |= LLIF_SOM_DIRTY;
if (page != NULL && list_empty(&page->cpg_pending_linkage))
list_add(&page->cpg_pending_linkage,
&club->cob_pending_list);
spin_unlock(&lli->lli_lock);
- EXIT;
}
/** records that a write has completed */
@@ -66,7 +64,6 @@ void vvp_write_complete(struct ccc_object *club, struct ccc_page *page)
struct ll_inode_info *lli = ll_i2info(club->cob_inode);
int rc = 0;
- ENTRY;
spin_lock(&lli->lli_lock);
if (page != NULL && !list_empty(&page->cpg_pending_linkage)) {
list_del_init(&page->cpg_pending_linkage);
@@ -75,7 +72,6 @@ void vvp_write_complete(struct ccc_object *club, struct ccc_page *page)
spin_unlock(&lli->lli_lock);
if (rc)
ll_queue_done_writing(club->cob_inode, 0);
- EXIT;
}
/** Queues DONE_WRITING if
@@ -85,7 +81,6 @@ void ll_queue_done_writing(struct inode *inode, unsigned long flags)
{
struct ll_inode_info *lli = ll_i2info(inode);
struct ccc_object *club = cl2ccc(ll_i2info(inode)->lli_clob);
- ENTRY;
spin_lock(&lli->lli_lock);
lli->lli_flags |= flags;
@@ -119,14 +114,12 @@ void ll_queue_done_writing(struct inode *inode, unsigned long flags)
spin_unlock(&lcq->lcq_lock);
}
spin_unlock(&lli->lli_lock);
- EXIT;
}
/** Pack SOM attributes info @opdata for CLOSE, DONE_WRITING rpc. */
void ll_done_writing_attr(struct inode *inode, struct md_op_data *op_data)
{
struct ll_inode_info *lli = ll_i2info(inode);
- ENTRY;
op_data->op_flags |= MF_SOM_CHANGE;
/* Check if Size-on-MDS attributes are valid. */
@@ -140,7 +133,6 @@ void ll_done_writing_attr(struct inode *inode, struct md_op_data *op_data)
op_data->op_attr.ia_valid |= ATTR_MTIME_SET | ATTR_CTIME_SET |
ATTR_ATIME_SET | ATTR_SIZE | ATTR_BLOCKS;
}
- EXIT;
}
/** Closes ioepoch and packs Size-on-MDS attribute if needed into @op_data. */
@@ -149,7 +141,6 @@ void ll_ioepoch_close(struct inode *inode, struct md_op_data *op_data,
{
struct ll_inode_info *lli = ll_i2info(inode);
struct ccc_object *club = cl2ccc(ll_i2info(inode)->lli_clob);
- ENTRY;
spin_lock(&lli->lli_lock);
if (!(list_empty(&club->cob_pending_list))) {
@@ -209,7 +200,6 @@ void ll_ioepoch_close(struct inode *inode, struct md_op_data *op_data,
spin_unlock(&lli->lli_lock);
ll_done_writing_attr(inode, op_data);
- EXIT;
out:
return;
}
@@ -225,7 +215,6 @@ int ll_som_update(struct inode *inode, struct md_op_data *op_data)
__u32 old_flags;
struct obdo *oa;
int rc;
- ENTRY;
LASSERT(op_data != NULL);
if (lli->lli_flags & LLIF_MDS_SIZE_LOCK)
@@ -236,7 +225,7 @@ int ll_som_update(struct inode *inode, struct md_op_data *op_data)
OBDO_ALLOC(oa);
if (!oa) {
CERROR("can't allocate memory for Size-on-MDS update.\n");
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
old_flags = op_data->op_flags;
@@ -266,7 +255,7 @@ int ll_som_update(struct inode *inode, struct md_op_data *op_data)
ptlrpc_req_finished(request);
OBDO_FREE(oa);
- RETURN(rc);
+ return rc;
}
/**
@@ -293,14 +282,12 @@ static void ll_done_writing(struct inode *inode)
struct obd_client_handle *och = NULL;
struct md_op_data *op_data;
int rc;
- ENTRY;
LASSERT(exp_connect_som(ll_i2mdexp(inode)));
OBD_ALLOC_PTR(op_data);
if (op_data == NULL) {
CERROR("can't allocate op_data\n");
- EXIT;
return;
}
@@ -324,7 +311,6 @@ out:
md_clear_open_replay_data(ll_i2sbi(inode)->ll_md_exp, och);
OBD_FREE_PTR(och);
}
- EXIT;
}
static struct ll_inode_info *ll_close_next_lli(struct ll_close_queue *lcq)
@@ -347,7 +333,6 @@ static struct ll_inode_info *ll_close_next_lli(struct ll_close_queue *lcq)
static int ll_close_thread(void *arg)
{
struct ll_close_queue *lcq = arg;
- ENTRY;
complete(&lcq->lcq_comp);
@@ -371,13 +356,13 @@ static int ll_close_thread(void *arg)
CDEBUG(D_INFO, "ll_close exiting\n");
complete(&lcq->lcq_comp);
- RETURN(0);
+ return 0;
}
int ll_close_thread_start(struct ll_close_queue **lcq_ret)
{
struct ll_close_queue *lcq;
- task_t *task;
+ struct task_struct *task;
if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_CLOSE_THREAD))
return -EINTR;
diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h
index 5227c5c4ebe..47e443d90fe 100644
--- a/drivers/staging/lustre/lustre/llite/llite_internal.h
+++ b/drivers/staging/lustre/lustre/llite/llite_internal.h
@@ -90,6 +90,7 @@ extern struct file_operations ll_pgcache_seq_fops;
#define REMOTE_PERM_HASHSIZE 16
struct ll_getname_data {
+ struct dir_context ctx;
char *lgd_name; /* points to a buffer with NAME_MAX+1 size */
struct lu_fid lgd_fid; /* target fid we are looking for */
int lgd_found; /* inode matched? */
@@ -438,14 +439,6 @@ struct rmtacl_ctl_table {
#define EE_HASHES 32
-struct eacl_entry {
- struct list_head ee_list;
- pid_t ee_key; /* hash key */
- struct lu_fid ee_fid;
- int ee_type; /* ACL type for ACCESS or DEFAULT */
- ext_acl_xattr_header *ee_acl;
-};
-
struct eacl_table {
spinlock_t et_lock;
struct list_head et_entries[EE_HASHES];
@@ -512,6 +505,7 @@ struct ll_sb_info {
* clustred nfs */
struct rmtacl_ctl_table ll_rct;
struct eacl_table ll_et;
+ __kernel_fsid_t ll_fsid;
};
#define LL_DEFAULT_MAX_RW_CHUNK (32 * 1024 * 1024)
@@ -687,8 +681,7 @@ extern struct file_operations ll_dir_operations;
extern struct inode_operations ll_dir_inode_operations;
struct page *ll_get_dir_page(struct inode *dir, __u64 hash,
struct ll_dir_chain *chain);
-int ll_dir_read(struct inode *inode, __u64 *_pos, void *cookie,
- filldir_t filldir);
+int ll_dir_read(struct inode *inode, struct dir_context *ctx);
int ll_get_mdt_idx(struct inode *inode);
/* llite/namei.c */
@@ -792,8 +785,7 @@ void ll_intent_release(struct lookup_intent *);
void ll_invalidate_aliases(struct inode *);
void ll_frob_intent(struct lookup_intent **itp, struct lookup_intent *deft);
void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry);
-int ll_dcompare(const struct dentry *parent, const struct inode *pinode,
- const struct dentry *dentry, const struct inode *inode,
+int ll_dcompare(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *d_name);
int ll_revalidate_it_finish(struct ptlrpc_request *request,
struct lookup_intent *it, struct dentry *de);
@@ -842,6 +834,7 @@ char *ll_get_fsname(struct super_block *sb, char *buf, int buflen);
/* llite/llite_nfs.c */
extern struct export_operations lustre_export_operations;
__u32 get_uuid2int(const char *name, int len);
+void get_uuid2fsid(const char *name, int len, __kernel_fsid_t *fsid);
struct inode *search_inode_for_lustre(struct super_block *sb,
const struct lu_fid *fid);
@@ -1129,7 +1122,7 @@ int ll_update_remote_perm(struct inode *inode, struct mdt_remote_perm *perm);
int lustre_check_remote_perm(struct inode *inode, int mask);
/* llite/llite_capa.c */
-extern timer_list_t ll_capa_timer;
+extern struct timer_list ll_capa_timer;
int ll_capa_thread_start(void);
void ll_capa_thread_stop(void);
@@ -1168,6 +1161,14 @@ void ll_ra_stats_inc(struct address_space *mapping, enum ra_stat which);
/* llite/llite_rmtacl.c */
#ifdef CONFIG_FS_POSIX_ACL
+struct eacl_entry {
+ struct list_head ee_list;
+ pid_t ee_key; /* hash key */
+ struct lu_fid ee_fid;
+ int ee_type; /* ACL type for ACCESS or DEFAULT */
+ ext_acl_xattr_header *ee_acl;
+};
+
obd_valid rce_ops2valid(int ops);
struct rmtacl_ctl_entry *rct_search(struct rmtacl_ctl_table *rct, pid_t key);
int rct_add(struct rmtacl_ctl_table *rct, pid_t key, int ops);
@@ -1183,6 +1184,11 @@ struct eacl_entry *et_search_del(struct eacl_table *et, pid_t key,
void et_search_free(struct eacl_table *et, pid_t key);
void et_init(struct eacl_table *et);
void et_fini(struct eacl_table *et);
+#else
+static inline obd_valid rce_ops2valid(int ops)
+{
+ return 0;
+}
#endif
/* statahead.c */
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index afae8010623..b868c2bd58d 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -42,7 +42,6 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <linux/mm.h>
#include <lustre_lite.h>
@@ -79,11 +78,10 @@ static struct ll_sb_info *ll_init_sbi(void)
struct sysinfo si;
class_uuid_t uuid;
int i;
- ENTRY;
OBD_ALLOC(sbi, sizeof(*sbi));
if (!sbi)
- RETURN(NULL);
+ return NULL;
spin_lock_init(&sbi->ll_lock);
mutex_init(&sbi->ll_lco.lco_lock);
@@ -141,13 +139,12 @@ static struct ll_sb_info *ll_init_sbi(void)
atomic_set(&sbi->ll_agl_total, 0);
sbi->ll_flags |= LL_SBI_AGL_ENABLED;
- RETURN(sbi);
+ return sbi;
}
void ll_free_sbi(struct super_block *sb)
{
struct ll_sb_info *sbi = ll_s2sbi(sb);
- ENTRY;
if (sbi != NULL) {
spin_lock(&ll_sb_lock);
@@ -155,7 +152,6 @@ void ll_free_sbi(struct super_block *sb)
spin_unlock(&ll_sb_lock);
OBD_FREE(sbi, sizeof(*sbi));
}
- EXIT;
}
static struct dentry_operations ll_d_root_ops = {
@@ -178,22 +174,21 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
struct lustre_md lmd;
obd_valid valid;
int size, err, checksum;
- ENTRY;
obd = class_name2obd(md);
if (!obd) {
CERROR("MD %s: not setup or attached\n", md);
- RETURN(-EINVAL);
+ return -EINVAL;
}
OBD_ALLOC_PTR(data);
if (data == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
OBD_ALLOC_PTR(osfs);
if (osfs == NULL) {
OBD_FREE_PTR(data);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
if (proc_lustre_fs_root) {
@@ -583,15 +578,17 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
/* s_dev is also used in lt_compare() to compare two fs, but that is
* only a node-local comparison. */
uuid = obd_get_uuid(sbi->ll_md_exp);
- if (uuid != NULL)
+ if (uuid != NULL) {
sb->s_dev = get_uuid2int(uuid->uuid, strlen(uuid->uuid));
+ get_uuid2fsid(uuid->uuid, strlen(uuid->uuid), &sbi->ll_fsid);
+ }
if (data != NULL)
OBD_FREE_PTR(data);
if (osfs != NULL)
OBD_FREE_PTR(osfs);
- RETURN(err);
+ return err;
out_root:
if (root)
iput(root);
@@ -627,7 +624,7 @@ int ll_get_max_mdsize(struct ll_sb_info *sbi, int *lmmsize)
if (rc)
CERROR("Get max mdsize error rc %d \n", rc);
- RETURN(rc);
+ return rc;
}
void ll_dump_inode(struct inode *inode)
@@ -676,7 +673,6 @@ void lustre_dump_dentry(struct dentry *dentry, int recur)
void client_common_put_super(struct super_block *sb)
{
struct ll_sb_info *sbi = ll_s2sbi(sb);
- ENTRY;
#ifdef CONFIG_FS_POSIX_ACL
if (sbi->ll_flags & LL_SBI_RMT_CLIENT) {
@@ -703,16 +699,12 @@ void client_common_put_super(struct super_block *sb)
obd_fid_fini(sbi->ll_md_exp->exp_obd);
obd_disconnect(sbi->ll_md_exp);
sbi->ll_md_exp = NULL;
-
- EXIT;
}
void ll_kill_super(struct super_block *sb)
{
struct ll_sb_info *sbi;
- ENTRY;
-
/* not init sb ?*/
if (!(sb->s_flags & MS_ACTIVE))
return;
@@ -725,31 +717,29 @@ void ll_kill_super(struct super_block *sb)
sb->s_dev = sbi->ll_sdev_orig;
sbi->ll_umounting = 1;
}
- EXIT;
}
char *ll_read_opt(const char *opt, char *data)
{
char *value;
char *retval;
- ENTRY;
CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data);
if (strncmp(opt, data, strlen(opt)))
- RETURN(NULL);
+ return NULL;
if ((value = strchr(data, '=')) == NULL)
- RETURN(NULL);
+ return NULL;
value++;
OBD_ALLOC(retval, strlen(value) + 1);
if (!retval) {
CERROR("out of memory!\n");
- RETURN(NULL);
+ return NULL;
}
memcpy(retval, value, strlen(value)+1);
CDEBUG(D_SUPER, "Assigned option: %s, value %s\n", opt, retval);
- RETURN(retval);
+ return retval;
}
static inline int ll_set_opt(const char *opt, char *data, int fl)
@@ -765,10 +755,9 @@ static int ll_options(char *options, int *flags)
{
int tmp;
char *s1 = options, *s2;
- ENTRY;
if (!options)
- RETURN(0);
+ return 0;
CDEBUG(D_CONFIG, "Parsing opts %s\n", options);
@@ -891,7 +880,7 @@ static int ll_options(char *options, int *flags)
}
LCONSOLE_ERROR_MSG(0x152, "Unknown option '%s', won't mount.\n",
s1);
- RETURN(-EINVAL);
+ return -EINVAL;
next:
/* Find next opt */
@@ -900,7 +889,7 @@ next:
break;
s1 = s2 + 1;
}
- RETURN(0);
+ return 0;
}
void ll_lli_init(struct ll_inode_info *lli)
@@ -977,13 +966,12 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt)
/* %p for void* in printf needs 16+2 characters: 0xffffffffffffffff */
const int instlen = sizeof(cfg->cfg_instance) * 2 + 2;
int err;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op: sb %p\n", sb);
OBD_ALLOC_PTR(cfg);
if (cfg == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
try_module_get(THIS_MODULE);
@@ -992,7 +980,7 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt)
if (!sbi) {
module_put(THIS_MODULE);
OBD_FREE_PTR(cfg);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
err = ll_options(lsi->lsi_lmd->lmd_opts, &sbi->ll_flags);
@@ -1058,7 +1046,7 @@ out_free:
LCONSOLE_WARN("Mounted %s\n", profilenm);
OBD_FREE_PTR(cfg);
- RETURN(err);
+ return err;
} /* ll_fill_super */
void ll_put_super(struct super_block *sb)
@@ -1069,7 +1057,6 @@ void ll_put_super(struct super_block *sb)
struct ll_sb_info *sbi = ll_s2sbi(sb);
char *profilenm = get_profile_name(sb);
int next, force = 1;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op: sb %p - %s\n", sb, profilenm);
@@ -1121,8 +1108,6 @@ void ll_put_super(struct super_block *sb)
lustre_common_put_super(sb);
module_put(THIS_MODULE);
-
- EXIT;
} /* client_put_super */
struct inode *ll_inode_from_resource_lock(struct ldlm_lock *lock)
@@ -1176,7 +1161,6 @@ void ll_clear_inode(struct inode *inode)
{
struct ll_inode_info *lli = ll_i2info(inode);
struct ll_sb_info *sbi = ll_i2sbi(inode);
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino,
inode->i_generation, inode);
@@ -1188,7 +1172,9 @@ void ll_clear_inode(struct inode *inode)
LASSERT(lli->lli_opendir_pid == 0);
}
+ spin_lock(&lli->lli_lock);
ll_i2info(inode)->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
+ spin_unlock(&lli->lli_lock);
md_null_inode(sbi->ll_md_exp, ll_inode2fid(inode));
LASSERT(!lli->lli_open_fd_write_count);
@@ -1235,8 +1221,6 @@ void ll_clear_inode(struct inode *inode)
*/
cl_inode_fini(inode);
lli->lli_has_smd = false;
-
- EXIT;
}
int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data,
@@ -1247,12 +1231,11 @@ int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data,
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ptlrpc_request *request = NULL;
int rc, ia_valid;
- ENTRY;
op_data = ll_prep_md_op_data(op_data, inode, NULL, NULL, 0, 0,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
rc = md_setattr(sbi->ll_md_exp, op_data, NULL, 0, NULL, 0,
&request, mod);
@@ -1272,14 +1255,14 @@ int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data,
} else if (rc != -EPERM && rc != -EACCES && rc != -ETXTBSY) {
CERROR("md_setattr fails: rc = %d\n", rc);
}
- RETURN(rc);
+ return rc;
}
rc = md_get_lustre_md(sbi->ll_md_exp, request, sbi->ll_dt_exp,
sbi->ll_md_exp, &md);
if (rc) {
ptlrpc_req_finished(request);
- RETURN(rc);
+ return rc;
}
ia_valid = op_data->op_attr.ia_valid;
@@ -1296,7 +1279,7 @@ int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data,
ll_update_inode(inode, &md);
ptlrpc_req_finished(request);
- RETURN(rc);
+ return rc;
}
/* Close IO epoch and send Size-on-MDS attribute update. */
@@ -1306,11 +1289,10 @@ static int ll_setattr_done_writing(struct inode *inode,
{
struct ll_inode_info *lli = ll_i2info(inode);
int rc = 0;
- ENTRY;
LASSERT(op_data != NULL);
if (!S_ISREG(inode->i_mode))
- RETURN(0);
+ return 0;
CDEBUG(D_INODE, "Epoch "LPU64" closed on "DFID" for truncate\n",
op_data->op_ioepoch, PFID(&lli->lli_fid));
@@ -1328,7 +1310,7 @@ static int ll_setattr_done_writing(struct inode *inode,
CERROR("inode %lu mdc truncate failed: rc = %d\n",
inode->i_ino, rc);
}
- RETURN(rc);
+ return rc;
}
static int ll_setattr_ost(struct inode *inode, struct iattr *attr)
@@ -1372,7 +1354,6 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr)
struct md_op_data *op_data = NULL;
struct md_open_data *mod = NULL;
int rc = 0, rc1 = 0;
- ENTRY;
CDEBUG(D_VFSTRACE, "%s: setattr inode %p/fid:"DFID" from %llu to %llu, "
"valid %x\n", ll_get_fsname(inode->i_sb, NULL, 0), inode,
@@ -1383,7 +1364,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr)
/* Check new size against VFS/VM file size limit and rlimit */
rc = inode_newsize_ok(inode, attr->ia_size);
if (rc)
- RETURN(rc);
+ return rc;
/* The maximum Lustre file size is variable, based on the
* OST maximum object size and number of stripes. This
@@ -1392,7 +1373,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr)
CDEBUG(D_INODE,"file "DFID" too large %llu > "LPU64"\n",
PFID(&lli->lli_fid), attr->ia_size,
ll_file_maxbytes(inode));
- RETURN(-EFBIG);
+ return -EFBIG;
}
attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
@@ -1400,24 +1381,24 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr)
/* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */
if (attr->ia_valid & TIMES_SET_FLAGS) {
- if (current_fsuid() != inode->i_uid &&
+ if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
!cfs_capable(CFS_CAP_FOWNER))
- RETURN(-EPERM);
+ return -EPERM;
}
/* We mark all of the fields "set" so MDS/OST does not re-set them */
if (attr->ia_valid & ATTR_CTIME) {
- attr->ia_ctime = CFS_CURRENT_TIME;
+ attr->ia_ctime = CURRENT_TIME;
attr->ia_valid |= ATTR_CTIME_SET;
}
if (!(attr->ia_valid & ATTR_ATIME_SET) &&
(attr->ia_valid & ATTR_ATIME)) {
- attr->ia_atime = CFS_CURRENT_TIME;
+ attr->ia_atime = CURRENT_TIME;
attr->ia_valid |= ATTR_ATIME_SET;
}
if (!(attr->ia_valid & ATTR_MTIME_SET) &&
(attr->ia_valid & ATTR_MTIME)) {
- attr->ia_mtime = CFS_CURRENT_TIME;
+ attr->ia_mtime = CURRENT_TIME;
attr->ia_valid |= ATTR_MTIME_SET;
}
@@ -1439,7 +1420,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr)
OBD_ALLOC_PTR(op_data);
if (op_data == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (!S_ISDIR(inode->i_mode)) {
if (attr->ia_valid & ATTR_SIZE)
@@ -1480,7 +1461,6 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr)
* setting times to past, but it is necessary due to possible
* time de-synchronization between MDT inode and OST objects */
rc = ll_setattr_ost(inode, attr);
- EXIT;
out:
if (op_data) {
if (op_data->op_ioepoch) {
@@ -1537,12 +1517,11 @@ int ll_statfs_internal(struct super_block *sb, struct obd_statfs *osfs,
struct ll_sb_info *sbi = ll_s2sbi(sb);
struct obd_statfs obd_osfs;
int rc;
- ENTRY;
rc = obd_statfs(NULL, sbi->ll_md_exp, osfs, max_age, flags);
if (rc) {
CERROR("md_statfs fails: rc = %d\n", rc);
- RETURN(rc);
+ return rc;
}
osfs->os_type = sb->s_magic;
@@ -1556,7 +1535,7 @@ int ll_statfs_internal(struct super_block *sb, struct obd_statfs *osfs,
rc = obd_statfs_rqset(sbi->ll_dt_exp, &obd_osfs, max_age, flags);
if (rc) {
CERROR("obd_statfs fails: rc = %d\n", rc);
- RETURN(rc);
+ return rc;
}
CDEBUG(D_SUPER, "OSC blocks "LPU64"/"LPU64" objects "LPU64"/"LPU64"\n",
@@ -1578,7 +1557,7 @@ int ll_statfs_internal(struct super_block *sb, struct obd_statfs *osfs,
osfs->os_ffree = obd_osfs.os_ffree;
}
- RETURN(rc);
+ return rc;
}
int ll_statfs(struct dentry *de, struct kstatfs *sfs)
{
@@ -1615,7 +1594,7 @@ int ll_statfs(struct dentry *de, struct kstatfs *sfs)
sfs->f_blocks = osfs.os_blocks;
sfs->f_bfree = osfs.os_bfree;
sfs->f_bavail = osfs.os_bavail;
-
+ sfs->f_fsid = ll_s2sbi(sb)->ll_fsid;
return 0;
}
@@ -1707,9 +1686,9 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md)
inode->i_blkbits = inode->i_sb->s_blocksize_bits;
}
if (body->valid & OBD_MD_FLUID)
- inode->i_uid = body->uid;
+ inode->i_uid = make_kuid(&init_user_ns, body->uid);
if (body->valid & OBD_MD_FLGID)
- inode->i_gid = body->gid;
+ inode->i_gid = make_kgid(&init_user_ns, body->gid);
if (body->valid & OBD_MD_FLFLAGS)
inode->i_flags = ll_ext_to_inode_flags(body->flags);
if (body->valid & OBD_MD_FLNLINK)
@@ -1755,7 +1734,9 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md)
/* Use old size assignment to avoid
* deadlock bz14138 & bz14326 */
i_size_write(inode, body->size);
+ spin_lock(&lli->lli_lock);
lli->lli_flags |= LLIF_MDS_SIZE_LOCK;
+ spin_unlock(&lli->lli_lock);
}
ldlm_lock_decref(&lockh, mode);
}
@@ -1786,7 +1767,6 @@ void ll_read_inode2(struct inode *inode, void *opaque)
{
struct lustre_md *md = opaque;
struct ll_inode_info *lli = ll_i2info(inode);
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n",
PFID(&lli->lli_fid), inode);
@@ -1814,28 +1794,22 @@ void ll_read_inode2(struct inode *inode, void *opaque)
inode->i_op = &ll_file_inode_operations;
inode->i_fop = sbi->ll_fop;
inode->i_mapping->a_ops = (struct address_space_operations *)&ll_aops;
- EXIT;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ll_dir_inode_operations;
inode->i_fop = &ll_dir_operations;
- EXIT;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &ll_fast_symlink_inode_operations;
- EXIT;
} else {
inode->i_op = &ll_special_inode_operations;
init_special_inode(inode, inode->i_mode,
inode->i_rdev);
-
- EXIT;
}
}
void ll_delete_inode(struct inode *inode)
{
struct cl_inode_info *lli = cl_i2info(inode);
- ENTRY;
if (S_ISREG(inode->i_mode) && lli->lli_clob != NULL)
/* discard all dirty pages before truncating them, required by
@@ -1859,8 +1833,6 @@ void ll_delete_inode(struct inode *inode)
ll_clear_inode(inode);
clear_inode(inode);
-
- EXIT;
}
int ll_iocontrol(struct inode *inode, struct file *file,
@@ -1869,7 +1841,6 @@ int ll_iocontrol(struct inode *inode, struct file *file,
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ptlrpc_request *req = NULL;
int rc, flags = 0;
- ENTRY;
switch(cmd) {
case FSFILT_IOC_GETFLAGS: {
@@ -1880,14 +1851,14 @@ int ll_iocontrol(struct inode *inode, struct file *file,
0, 0, LUSTRE_OPC_ANY,
NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
op_data->op_valid = OBD_MD_FLFLAGS;
rc = md_getattr(sbi->ll_md_exp, op_data, &req);
ll_finish_md_op_data(op_data);
if (rc) {
CERROR("failure %d inode %lu\n", rc, inode->i_ino);
- RETURN(-abs(rc));
+ return -abs(rc);
}
body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
@@ -1896,7 +1867,7 @@ int ll_iocontrol(struct inode *inode, struct file *file,
ptlrpc_req_finished(req);
- RETURN(put_user(flags, (int *)arg));
+ return put_user(flags, (int *)arg);
}
case FSFILT_IOC_SETFLAGS: {
struct lov_stripe_md *lsm;
@@ -1904,12 +1875,12 @@ int ll_iocontrol(struct inode *inode, struct file *file,
struct md_op_data *op_data;
if (get_user(flags, (int *)arg))
- RETURN(-EFAULT);
+ return -EFAULT;
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
((struct ll_iattr *)&op_data->op_attr)->ia_attr_flags = flags;
op_data->op_attr.ia_valid |= ATTR_ATTR_FLAG;
@@ -1918,18 +1889,20 @@ int ll_iocontrol(struct inode *inode, struct file *file,
ll_finish_md_op_data(op_data);
ptlrpc_req_finished(req);
if (rc)
- RETURN(rc);
+ return rc;
inode->i_flags = ll_ext_to_inode_flags(flags);
lsm = ccc_inode_lsm_get(inode);
- if (lsm == NULL)
- RETURN(0);
+ if (!lsm_has_objects(lsm)) {
+ ccc_inode_lsm_put(inode, lsm);
+ return 0;
+ }
OBDO_ALLOC(oinfo.oi_oa);
if (!oinfo.oi_oa) {
ccc_inode_lsm_put(inode, lsm);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
oinfo.oi_md = lsm;
oinfo.oi_oa->o_oi = lsm->lsm_oi;
@@ -1946,20 +1919,21 @@ int ll_iocontrol(struct inode *inode, struct file *file,
if (rc && rc != -EPERM && rc != -EACCES)
CERROR("osc_setattr_async fails: rc = %d\n", rc);
- RETURN(rc);
+ return rc;
}
default:
- RETURN(-ENOSYS);
+ return -ENOSYS;
}
- RETURN(0);
+ return 0;
}
int ll_flush_ctx(struct inode *inode)
{
struct ll_sb_info *sbi = ll_i2sbi(inode);
- CDEBUG(D_SEC, "flush context for user %d\n", current_uid());
+ CDEBUG(D_SEC, "flush context for user %d\n",
+ from_kuid(&init_user_ns, current_uid()));
obd_set_info_async(NULL, sbi->ll_md_exp,
sizeof(KEY_FLUSH_CTX), KEY_FLUSH_CTX,
@@ -1976,8 +1950,6 @@ void ll_umount_begin(struct super_block *sb)
struct ll_sb_info *sbi = ll_s2sbi(sb);
struct obd_device *obd;
struct obd_ioctl_data *ioc_data;
- ENTRY;
-
CDEBUG(D_VFSTRACE, "VFS Op: superblock %p count %d active %d\n", sb,
sb->s_count, atomic_read(&sb->s_active));
@@ -1986,7 +1958,6 @@ void ll_umount_begin(struct super_block *sb)
if (obd == NULL) {
CERROR("Invalid MDC connection handle "LPX64"\n",
sbi->ll_md_exp->exp_handle.h_cookie);
- EXIT;
return;
}
obd->obd_force = 1;
@@ -1995,7 +1966,6 @@ void ll_umount_begin(struct super_block *sb)
if (obd == NULL) {
CERROR("Invalid LOV connection handle "LPX64"\n",
sbi->ll_dt_exp->exp_handle.h_cookie);
- EXIT;
return;
}
obd->obd_force = 1;
@@ -2016,8 +1986,6 @@ void ll_umount_begin(struct super_block *sb)
* schedule() and sleep one second if needed, and hope.
*/
schedule();
-
- EXIT;
}
int ll_remount_fs(struct super_block *sb, int *flags, char *data)
@@ -2058,14 +2026,13 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
struct ll_sb_info *sbi = NULL;
struct lustre_md md;
int rc;
- ENTRY;
LASSERT(*inode || sb);
sbi = sb ? ll_s2sbi(sb) : ll_i2sbi(*inode);
rc = md_get_lustre_md(sbi->ll_md_exp, req, sbi->ll_dt_exp,
sbi->ll_md_exp, &md);
if (rc)
- RETURN(rc);
+ return rc;
if (*inode) {
ll_update_inode(*inode, &md);
@@ -2127,7 +2094,7 @@ out:
if (md.lsm != NULL)
obd_free_memmd(sbi->ll_dt_exp, &md.lsm);
md_free_lustre_md(sbi->ll_md_exp, &md);
- RETURN(rc);
+ return rc;
}
int ll_obd_statfs(struct inode *inode, void *arg)
@@ -2238,8 +2205,8 @@ struct md_op_data * ll_prep_md_op_data(struct md_op_data *op_data,
op_data->op_namelen = namelen;
op_data->op_mode = mode;
op_data->op_mod_time = cfs_time_current_sec();
- op_data->op_fsuid = current_fsuid();
- op_data->op_fsgid = current_fsgid();
+ op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid());
+ op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid());
op_data->op_cap = cfs_curproc_cap_pack();
op_data->op_bias = 0;
op_data->op_cli_flags = 0;
@@ -2303,7 +2270,7 @@ int ll_show_options(struct seq_file *seq, struct dentry *dentry)
if (sbi->ll_flags & LL_SBI_USER_FID2PATH)
seq_puts(seq, ",user_fid2path");
- RETURN(0);
+ return 0;
}
/**
@@ -2313,23 +2280,22 @@ int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg)
{
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct obd_device *obd;
- ENTRY;
if (cmd == OBD_IOC_GETDTNAME)
obd = class_exp2obd(sbi->ll_dt_exp);
else if (cmd == OBD_IOC_GETMDNAME)
obd = class_exp2obd(sbi->ll_md_exp);
else
- RETURN(-EINVAL);
+ return -EINVAL;
if (!obd)
- RETURN(-ENOENT);
+ return -ENOENT;
if (copy_to_user((void *)arg, obd->obd_name,
strlen(obd->obd_name) + 1))
- RETURN(-EFAULT);
+ return -EFAULT;
- RETURN(0);
+ return 0;
}
/**
diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c
index d9590d85634..caed6423e4e 100644
--- a/drivers/staging/lustre/lustre/llite/llite_mmap.c
+++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c
@@ -40,13 +40,9 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/unistd.h>
-#include <linux/version.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-#include <linux/mm.h>
#include <linux/pagemap.h>
#define DEBUG_SUBSYSTEM S_LLITE
@@ -74,7 +70,6 @@ struct vm_area_struct *our_vma(struct mm_struct *mm, unsigned long addr,
size_t count)
{
struct vm_area_struct *vma, *ret = NULL;
- ENTRY;
/* mmap_sem must have been held by caller. */
LASSERT(!down_write_trylock(&mm->mmap_sem));
@@ -87,7 +82,7 @@ struct vm_area_struct *our_vma(struct mm_struct *mm, unsigned long addr,
break;
}
}
- RETURN(ret);
+ return ret;
}
/**
@@ -107,16 +102,16 @@ struct cl_io *ll_fault_io_init(struct vm_area_struct *vma,
struct cl_env_nest *nest,
pgoff_t index, unsigned long *ra_flags)
{
- struct file *file = vma->vm_file;
- struct inode *inode = file->f_dentry->d_inode;
- struct cl_io *io;
- struct cl_fault_io *fio;
- struct lu_env *env;
- ENTRY;
+ struct file *file = vma->vm_file;
+ struct inode *inode = file->f_dentry->d_inode;
+ struct cl_io *io;
+ struct cl_fault_io *fio;
+ struct lu_env *env;
+ int rc;
*env_ret = NULL;
if (ll_file_nolock(file))
- RETURN(ERR_PTR(-EOPNOTSUPP));
+ return ERR_PTR(-EOPNOTSUPP);
/*
* page fault can be called when lustre IO is
@@ -127,7 +122,7 @@ struct cl_io *ll_fault_io_init(struct vm_area_struct *vma,
*/
env = cl_env_nested_get(nest);
if (IS_ERR(env))
- RETURN(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
*env_ret = env;
@@ -152,17 +147,22 @@ struct cl_io *ll_fault_io_init(struct vm_area_struct *vma,
CDEBUG(D_MMAP, "vm_flags: %lx (%lu %d)\n", vma->vm_flags,
fio->ft_index, fio->ft_executable);
- if (cl_io_init(env, io, CIT_FAULT, io->ci_obj) == 0) {
+ rc = cl_io_init(env, io, CIT_FAULT, io->ci_obj);
+ if (rc == 0) {
struct ccc_io *cio = ccc_env_io(env);
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
LASSERT(cio->cui_cl.cis_io == io);
- /* mmap lock must be MANDATORY
- * it has to cache pages. */
+ /* mmap lock must be MANDATORY it has to cache
+ * pages. */
io->ci_lockreq = CILR_MANDATORY;
-
- cio->cui_fd = fd;
+ cio->cui_fd = fd;
+ } else {
+ LASSERT(rc < 0);
+ cl_io_fini(env, io);
+ cl_env_nested_put(nest, env);
+ io = ERR_PTR(rc);
}
return io;
@@ -180,7 +180,6 @@ static int ll_page_mkwrite0(struct vm_area_struct *vma, struct page *vmpage,
sigset_t set;
struct inode *inode;
struct ll_inode_info *lli;
- ENTRY;
LASSERT(vmpage != NULL);
@@ -190,7 +189,7 @@ static int ll_page_mkwrite0(struct vm_area_struct *vma, struct page *vmpage,
result = io->ci_result;
if (result < 0)
- GOTO(out, result);
+ GOTO(out_io, result);
io->u.ci_fault.ft_mkwrite = 1;
io->u.ci_fault.ft_writable = 1;
@@ -250,16 +249,15 @@ static int ll_page_mkwrite0(struct vm_area_struct *vma, struct page *vmpage,
spin_unlock(&lli->lli_lock);
}
}
- EXIT;
-out:
+out_io:
cl_io_fini(env, io);
cl_env_nested_put(&nest, env);
-
+out:
CDEBUG(D_MMAP, "%s mkwrite with %d\n", current->comm, result);
-
LASSERT(ergo(result == 0, PageLocked(vmpage)));
- return(result);
+
+ return result;
}
@@ -304,11 +302,10 @@ static int ll_fault0(struct vm_area_struct *vma, struct vm_fault *vmf)
struct cl_env_nest nest;
int result;
int fault_ret = 0;
- ENTRY;
io = ll_fault_io_init(vma, &env, &nest, vmf->pgoff, &ra_flags);
if (IS_ERR(io))
- RETURN(to_fault_error(PTR_ERR(io)));
+ return to_fault_error(PTR_ERR(io));
result = io->ci_result;
if (result == 0) {
@@ -335,7 +332,7 @@ static int ll_fault0(struct vm_area_struct *vma, struct vm_fault *vmf)
CDEBUG(D_MMAP, "%s fault %d/%d\n",
current->comm, fault_ret, result);
- RETURN(fault_ret);
+ return fault_ret;
}
static int ll_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -431,11 +428,9 @@ static void ll_vm_open(struct vm_area_struct * vma)
struct inode *inode = vma->vm_file->f_dentry->d_inode;
struct ccc_object *vob = cl_inode2ccc(inode);
- ENTRY;
LASSERT(vma->vm_file);
LASSERT(atomic_read(&vob->cob_mmap_cnt) >= 0);
atomic_inc(&vob->cob_mmap_cnt);
- EXIT;
}
/**
@@ -446,11 +441,9 @@ static void ll_vm_close(struct vm_area_struct *vma)
struct inode *inode = vma->vm_file->f_dentry->d_inode;
struct ccc_object *vob = cl_inode2ccc(inode);
- ENTRY;
LASSERT(vma->vm_file);
atomic_dec(&vob->cob_mmap_cnt);
LASSERT(atomic_read(&vob->cob_mmap_cnt) >= 0);
- EXIT;
}
@@ -466,7 +459,6 @@ static inline unsigned long file_to_user(struct vm_area_struct *vma, __u64 byte)
int ll_teardown_mmaps(struct address_space *mapping, __u64 first, __u64 last)
{
int rc = -ENOENT;
- ENTRY;
LASSERTF(last > first, "last "LPU64" first "LPU64"\n", last, first);
if (mapping_mapped(mapping)) {
@@ -475,7 +467,7 @@ int ll_teardown_mmaps(struct address_space *mapping, __u64 first, __u64 last)
last - first + 1, 0);
}
- RETURN(rc);
+ return rc;
}
static struct vm_operations_struct ll_file_vm_ops = {
@@ -489,10 +481,9 @@ int ll_file_mmap(struct file *file, struct vm_area_struct * vma)
{
struct inode *inode = file->f_dentry->d_inode;
int rc;
- ENTRY;
if (ll_file_nolock(file))
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_MAP, 1);
rc = generic_file_mmap(file, vma);
@@ -503,5 +494,5 @@ int ll_file_mmap(struct file *file, struct vm_area_struct * vma)
rc = ll_glimpse_size(inode);
}
- RETURN(rc);
+ return rc;
}
diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c
index 28cc41e9058..1767c741fb7 100644
--- a/drivers/staging/lustre/lustre/llite/llite_nfs.c
+++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c
@@ -58,6 +58,22 @@ __u32 get_uuid2int(const char *name, int len)
return (key0 << 1);
}
+void get_uuid2fsid(const char *name, int len, __kernel_fsid_t *fsid)
+{
+ __u64 key = 0, key0 = 0x12a3fe2d, key1 = 0x37abe8f9;
+
+ while (len--) {
+ key = key1 + (key0 ^ (*name++ * 7152373));
+ if (key & 0x8000000000000000ULL)
+ key -= 0x7fffffffffffffffULL;
+ key1 = key0;
+ key0 = key;
+ }
+
+ fsid->val[0] = key;
+ fsid->val[1] = key >> 32;
+}
+
static int ll_nfs_test_inode(struct inode *inode, void *opaque)
{
return lu_fid_eq(&ll_i2info(inode)->lli_fid,
@@ -75,17 +91,16 @@ struct inode *search_inode_for_lustre(struct super_block *sb,
ll_need_32bit_api(sbi));
struct md_op_data *op_data;
int rc;
- ENTRY;
CDEBUG(D_INFO, "searching inode for:(%lu,"DFID")\n", hash, PFID(fid));
inode = ilookup5(sb, hash, ll_nfs_test_inode, (void *)fid);
if (inode)
- RETURN(inode);
+ return inode;
rc = ll_get_max_mdsize(sbi, &eadatalen);
if (rc)
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
/* Because inode is NULL, ll_prep_md_op_data can not
* be used here. So we allocate op_data ourselves */
@@ -103,14 +118,14 @@ struct inode *search_inode_for_lustre(struct super_block *sb,
if (rc) {
CERROR("can't get object attrs, fid "DFID", rc %d\n",
PFID(fid), rc);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
rc = ll_prep_inode(&inode, req, sb, NULL);
ptlrpc_req_finished(req);
if (rc)
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
- RETURN(inode);
+ return inode;
}
struct lustre_nfs_fid {
@@ -123,20 +138,19 @@ ll_iget_for_nfs(struct super_block *sb, struct lu_fid *fid, struct lu_fid *paren
{
struct inode *inode;
struct dentry *result;
- ENTRY;
CDEBUG(D_INFO, "Get dentry for fid: "DFID"\n", PFID(fid));
if (!fid_is_sane(fid))
- RETURN(ERR_PTR(-ESTALE));
+ return ERR_PTR(-ESTALE);
inode = search_inode_for_lustre(sb, fid);
if (IS_ERR(inode))
- RETURN(ERR_PTR(PTR_ERR(inode)));
+ return ERR_CAST(inode);
if (is_bad_inode(inode)) {
/* we didn't find the right inode.. */
iput(inode);
- RETURN(ERR_PTR(-ESTALE));
+ return ERR_PTR(-ESTALE);
}
/**
@@ -154,11 +168,11 @@ ll_iget_for_nfs(struct super_block *sb, struct lu_fid *fid, struct lu_fid *paren
result = d_obtain_alias(inode);
if (IS_ERR(result))
- RETURN(result);
+ return result;
ll_dops_init(result, 1, 0);
- RETURN(result);
+ return result;
}
#define LUSTRE_NFS_FID 0x97
@@ -176,20 +190,19 @@ static int ll_encode_fh(struct inode *inode, __u32 *fh, int *plen,
struct inode *parent)
{
struct lustre_nfs_fid *nfs_fid = (void *)fh;
- ENTRY;
CDEBUG(D_INFO, "encoding for (%lu,"DFID") maxlen=%d minlen=%d\n",
inode->i_ino, PFID(ll_inode2fid(inode)), *plen,
(int)sizeof(struct lustre_nfs_fid));
if (*plen < sizeof(struct lustre_nfs_fid) / 4)
- RETURN(255);
+ return 255;
nfs_fid->lnf_child = *ll_inode2fid(inode);
nfs_fid->lnf_parent = *ll_inode2fid(parent);
*plen = sizeof(struct lustre_nfs_fid) / 4;
- RETURN(LUSTRE_NFS_FID);
+ return LUSTRE_NFS_FID;
}
static int ll_nfs_get_name_filldir(void *cookie, const char *name, int namelen,
@@ -214,10 +227,12 @@ static int ll_get_name(struct dentry *dentry, char *name,
struct dentry *child)
{
struct inode *dir = dentry->d_inode;
- struct ll_getname_data lgd;
- __u64 offset = 0;
int rc;
- ENTRY;
+ struct ll_getname_data lgd = {
+ .lgd_name = name,
+ .lgd_fid = ll_i2info(child->d_inode)->lli_fid,
+ .ctx.actor = ll_nfs_get_name_filldir,
+ };
if (!dir || !S_ISDIR(dir->i_mode))
GOTO(out, rc = -ENOTDIR);
@@ -225,17 +240,11 @@ static int ll_get_name(struct dentry *dentry, char *name,
if (!dir->i_fop)
GOTO(out, rc = -EINVAL);
- lgd.lgd_name = name;
- lgd.lgd_fid = ll_i2info(child->d_inode)->lli_fid;
- lgd.lgd_found = 0;
-
mutex_lock(&dir->i_mutex);
- rc = ll_dir_read(dir, &offset, &lgd, ll_nfs_get_name_filldir);
+ rc = ll_dir_read(dir, &lgd.ctx);
mutex_unlock(&dir->i_mutex);
if (!rc && !lgd.lgd_found)
rc = -ENOENT;
- EXIT;
-
out:
return rc;
}
@@ -246,9 +255,9 @@ static struct dentry *ll_fh_to_dentry(struct super_block *sb, struct fid *fid,
struct lustre_nfs_fid *nfs_fid = (struct lustre_nfs_fid *)fid;
if (fh_type != LUSTRE_NFS_FID)
- RETURN(ERR_PTR(-EPROTO));
+ return ERR_PTR(-EPROTO);
- RETURN(ll_iget_for_nfs(sb, &nfs_fid->lnf_child, &nfs_fid->lnf_parent));
+ return ll_iget_for_nfs(sb, &nfs_fid->lnf_child, &nfs_fid->lnf_parent);
}
static struct dentry *ll_fh_to_parent(struct super_block *sb, struct fid *fid,
@@ -257,9 +266,9 @@ static struct dentry *ll_fh_to_parent(struct super_block *sb, struct fid *fid,
struct lustre_nfs_fid *nfs_fid = (struct lustre_nfs_fid *)fid;
if (fh_type != LUSTRE_NFS_FID)
- RETURN(ERR_PTR(-EPROTO));
+ return ERR_PTR(-EPROTO);
- RETURN(ll_iget_for_nfs(sb, &nfs_fid->lnf_parent, NULL));
+ return ll_iget_for_nfs(sb, &nfs_fid->lnf_parent, NULL);
}
static struct dentry *ll_get_parent(struct dentry *dchild)
@@ -273,7 +282,6 @@ static struct dentry *ll_get_parent(struct dentry *dchild)
struct md_op_data *op_data;
int rc;
int lmmsize;
- ENTRY;
LASSERT(dir && S_ISDIR(dir->i_mode));
@@ -284,19 +292,19 @@ static struct dentry *ll_get_parent(struct dentry *dchild)
rc = ll_get_max_mdsize(sbi, &lmmsize);
if (rc != 0)
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
op_data = ll_prep_md_op_data(NULL, dir, NULL, dotdot,
strlen(dotdot), lmmsize,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN((void *)op_data);
+ return (void *)op_data;
rc = md_getattr_name(sbi->ll_md_exp, op_data, &req);
ll_finish_md_op_data(op_data);
if (rc) {
CERROR("failure %d inode %lu get parent\n", rc, dir->i_ino);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
LASSERT(body->valid & OBD_MD_FLID);
@@ -307,7 +315,7 @@ static struct dentry *ll_get_parent(struct dentry *dchild)
result = ll_iget_for_nfs(dir->i_sb, &body->fid1, NULL);
ptlrpc_req_finished(req);
- RETURN(result);
+ return result;
}
struct export_operations lustre_export_operations = {
diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c
index 9d4c17ea880..2340458b8a0 100644
--- a/drivers/staging/lustre/lustre/llite/lloop.c
+++ b/drivers/staging/lustre/lustre/llite/lloop.c
@@ -99,7 +99,6 @@
#include <linux/completion.h>
#include <linux/highmem.h>
#include <linux/gfp.h>
-#include <linux/swap.h>
#include <linux/pagevec.h>
#include <asm/uaccess.h>
@@ -574,7 +573,7 @@ static int loop_clr_fd(struct lloop_device *lo, struct block_device *bdev,
lo->lo_offset = 0;
lo->lo_sizelimit = 0;
lo->lo_flags = 0;
- ll_invalidate_bdev(bdev, 0);
+ invalidate_bdev(bdev);
set_capacity(disks[lo->lo_number], 0);
bd_set_size(bdev, 0);
mapping_set_gfp_mask(filp->f_mapping, gfp);
@@ -618,7 +617,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
case LL_IOC_LLOOP_DETACH: {
err = loop_clr_fd(lo, bdev, 2);
if (err == 0)
- ll_blkdev_put(bdev, 0); /* grabbed in LLOOP_ATTACH */
+ blkdev_put(bdev, 0); /* grabbed in LLOOP_ATTACH */
break;
}
@@ -713,7 +712,7 @@ static enum llioc_iter lloop_ioctl(struct inode *unused, struct file *file,
err = loop_set_fd(lo, NULL, bdev, file);
if (err) {
fput(file);
- ll_blkdev_put(bdev, 0);
+ blkdev_put(bdev, 0);
}
break;
@@ -737,7 +736,7 @@ static enum llioc_iter lloop_ioctl(struct inode *unused, struct file *file,
bdev = lo->lo_device;
err = loop_clr_fd(lo, bdev, 1);
if (err == 0)
- ll_blkdev_put(bdev, 0); /* grabbed in LLOOP_ATTACH */
+ blkdev_put(bdev, 0); /* grabbed in LLOOP_ATTACH */
break;
}
@@ -849,10 +848,8 @@ static void lloop_exit(void)
blk_cleanup_queue(loop_dev[i].lo_queue);
put_disk(disks[i]);
}
- if (ll_unregister_blkdev(lloop_major, "lloop"))
- CWARN("lloop: cannot unregister blkdev\n");
- else
- CDEBUG(D_CONFIG, "unregistered lloop major %d\n", lloop_major);
+
+ unregister_blkdev(lloop_major, "lloop");
OBD_FREE(disks, max_loop * sizeof(*disks));
OBD_FREE(loop_dev, max_loop * sizeof(*loop_dev));
diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c
index 6a82505c793..d4d3c17547c 100644
--- a/drivers/staging/lustre/lustre/llite/lproc_llite.c
+++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c
@@ -35,7 +35,6 @@
*/
#define DEBUG_SUBSYSTEM S_LLITE
-#include <linux/version.h>
#include <lustre_lite.h>
#include <lprocfs_status.h>
#include <linux/seq_file.h>
@@ -243,9 +242,9 @@ static ssize_t ll_max_readahead_mb_seq_write(struct file *file, const char *buff
if (rc)
return rc;
- if (pages_number < 0 || pages_number > num_physpages / 2) {
+ if (pages_number < 0 || pages_number > totalram_pages / 2) {
CERROR("can't set file readahead more than %lu MB\n",
- num_physpages >> (20 - PAGE_CACHE_SHIFT + 1)); /*1/2 of RAM*/
+ totalram_pages >> (20 - PAGE_CACHE_SHIFT + 1)); /*1/2 of RAM*/
return -ERANGE;
}
@@ -380,23 +379,22 @@ static ssize_t ll_max_cached_mb_seq_write(struct file *file, const char *buffer,
int mult, rc, pages_number;
int diff = 0;
int nrpages = 0;
- ENTRY;
mult = 1 << (20 - PAGE_CACHE_SHIFT);
buffer = lprocfs_find_named_value(buffer, "max_cached_mb:", &count);
rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult);
if (rc)
- RETURN(rc);
+ return rc;
- if (pages_number < 0 || pages_number > num_physpages) {
+ if (pages_number < 0 || pages_number > totalram_pages) {
CERROR("%s: can't set max cache more than %lu MB\n",
ll_get_fsname(sb, NULL, 0),
- num_physpages >> (20 - PAGE_CACHE_SHIFT));
- RETURN(-ERANGE);
+ totalram_pages >> (20 - PAGE_CACHE_SHIFT));
+ return -ERANGE;
}
if (sbi->ll_dt_exp == NULL)
- RETURN(-ENODEV);
+ return -ENODEV;
spin_lock(&sbi->ll_lock);
diff = pages_number - cache->ccc_lru_max;
@@ -421,7 +419,7 @@ static ssize_t ll_max_cached_mb_seq_write(struct file *file, const char *buffer,
break;
nv = ov > diff ? ov - diff : 0;
- rc = cfs_atomic_cmpxchg(&cache->ccc_lru_left, ov, nv);
+ rc = atomic_cmpxchg(&cache->ccc_lru_left, ov, nv);
if (likely(ov == rc)) {
diff -= ov - nv;
nrpages += ov - nv;
@@ -822,7 +820,8 @@ void ll_stats_ops_tally(struct ll_sb_info *sbi, int op, int count)
sbi->ll_stats_track_id == current->parent->pid)
lprocfs_counter_add(sbi->ll_stats, op, count);
else if (sbi->ll_stats_track_type == STATS_TRACK_GID &&
- sbi->ll_stats_track_id == current_gid())
+ sbi->ll_stats_track_id ==
+ from_kgid(&init_user_ns, current_gid()))
lprocfs_counter_add(sbi->ll_stats, op, count);
}
EXPORT_SYMBOL(ll_stats_ops_tally);
@@ -852,10 +851,9 @@ int lprocfs_register_mountpoint(struct proc_dir_entry *parent,
struct lustre_sb_info *lsi = s2lsi(sb);
struct ll_sb_info *sbi = ll_s2sbi(sb);
struct obd_device *obd;
- proc_dir_entry_t *dir;
+ struct proc_dir_entry *dir;
char name[MAX_STRING_SIZE + 1], *ptr;
int err, id, len, rc;
- ENTRY;
memset(lvars, 0, sizeof(lvars));
@@ -880,7 +878,7 @@ int lprocfs_register_mountpoint(struct proc_dir_entry *parent,
if (IS_ERR(sbi->ll_proc_root)) {
err = PTR_ERR(sbi->ll_proc_root);
sbi->ll_proc_root = NULL;
- RETURN(err);
+ return err;
}
rc = lprocfs_seq_create(sbi->ll_proc_root, "dump_page_cache", 0444,
@@ -994,7 +992,7 @@ out:
lprocfs_free_stats(&sbi->ll_ra_stats);
lprocfs_free_stats(&sbi->ll_stats);
}
- RETURN(err);
+ return err;
}
void lprocfs_unregister_mountpoint(struct ll_sb_info *sbi)
@@ -1302,8 +1300,9 @@ static int ll_rw_offset_stats_seq_show(struct seq_file *seq, void *v)
/* We stored the discontiguous offsets here; print them first */
for(i = 0; i < LL_OFFSET_HIST_MAX; i++) {
if (offset[i].rw_pid != 0)
- seq_printf(seq,"%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
- offset[i].rw_op ? 'W' : 'R',
+ seq_printf(seq,
+ "%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
+ offset[i].rw_op == READ ? 'R' : 'W',
offset[i].rw_pid,
offset[i].rw_range_start,
offset[i].rw_range_end,
@@ -1314,8 +1313,9 @@ static int ll_rw_offset_stats_seq_show(struct seq_file *seq, void *v)
/* Then print the current offsets for each process */
for(i = 0; i < LL_PROCESS_HIST_MAX; i++) {
if (process[i].rw_pid != 0)
- seq_printf(seq,"%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
- process[i].rw_op ? 'W' : 'R',
+ seq_printf(seq,
+ "%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
+ process[i].rw_op == READ ? 'R' : 'W',
process[i].rw_pid,
process[i].rw_range_start,
process[i].rw_last_file_pos,
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index ff8f63de561..34815b550e7 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -77,11 +77,9 @@ static int ll_d_mountpoint(struct dentry *dparent, struct dentry *dchild,
int ll_unlock(__u32 mode, struct lustre_handle *lockh)
{
- ENTRY;
-
ldlm_lock_decref(lockh, mode);
- RETURN(0);
+ return 0;
}
@@ -139,7 +137,6 @@ struct inode *ll_iget(struct super_block *sb, ino_t hash,
struct lustre_md *md)
{
struct inode *inode;
- ENTRY;
LASSERT(hash != 0);
inode = iget5_locked(sb, hash, ll_test_inode, ll_set_inode, md);
@@ -169,7 +166,7 @@ struct inode *ll_iget(struct super_block *sb, ino_t hash,
CDEBUG(D_VFSTRACE, "got inode: %p for "DFID"\n",
inode, PFID(&md->body->fid1));
}
- RETURN(inode);
+ return inode;
}
static void ll_invalidate_negative_children(struct inode *dir)
@@ -200,7 +197,6 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
{
int rc;
struct lustre_handle lockh;
- ENTRY;
switch (flag) {
case LDLM_CB_BLOCKING:
@@ -208,7 +204,7 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
rc = ldlm_cli_cancel(&lockh, LCF_ASYNC);
if (rc < 0) {
CDEBUG(D_INODE, "ldlm_cli_cancel: %d\n", rc);
- RETURN(rc);
+ return rc;
}
break;
case LDLM_CB_CANCELING: {
@@ -275,8 +271,11 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
CDEBUG(D_INODE, "invaliding layout %d.\n", rc);
}
- if (bits & MDS_INODELOCK_UPDATE)
+ if (bits & MDS_INODELOCK_UPDATE) {
+ spin_lock(&lli->lli_lock);
lli->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
+ spin_unlock(&lli->lli_lock);
+ }
if (S_ISDIR(inode->i_mode) &&
(bits & MDS_INODELOCK_UPDATE)) {
@@ -297,13 +296,13 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
LBUG();
}
- RETURN(0);
+ return 0;
}
__u32 ll_i2suppgid(struct inode *i)
{
- if (current_is_in_group(i->i_gid))
- return (__u32)i->i_gid;
+ if (in_group_p(i->i_gid))
+ return (__u32)from_kgid(&init_user_ns, i->i_gid);
else
return (__u32)(-1);
}
@@ -430,7 +429,6 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
struct inode *inode = NULL;
__u64 bits = 0;
int rc;
- ENTRY;
/* NB 1 request reference will be taken away by ll_intent_lock()
* when I return */
@@ -439,7 +437,7 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
if (!it_disposition(it, DISP_LOOKUP_NEG)) {
rc = ll_prep_inode(&inode, request, (*de)->d_sb, it);
if (rc)
- RETURN(rc);
+ return rc;
ll_set_lock_data(ll_i2sbi(parent)->ll_md_exp, inode, it, &bits);
@@ -480,7 +478,7 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
}
}
- RETURN(0);
+ return 0;
}
static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
@@ -493,10 +491,9 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
struct it_cb_data icbd;
__u32 opc;
int rc;
- ENTRY;
if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen)
- RETURN(ERR_PTR(-ENAMETOOLONG));
+ return ERR_PTR(-ENAMETOOLONG);
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),intent=%s\n",
dentry->d_name.len, dentry->d_name.name, parent->i_ino,
@@ -514,7 +511,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
rc = ll_inode_revalidate_it(parent->i_sb->s_root, it,
MDS_INODELOCK_LOOKUP);
if (rc)
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
if (it->it_op == IT_GETATTR) {
@@ -539,7 +536,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
dentry->d_name.len, lookup_flags, opc,
NULL);
if (IS_ERR(op_data))
- RETURN((void *)op_data);
+ return (void *)op_data;
/* enforce umask if acl disabled or MDS doesn't support umask */
if (!IS_POSIXACL(parent) || !exp_connect_umask(ll_i2mdexp(parent)))
@@ -618,7 +615,6 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
struct dentry *de;
long long lookup_flags = LOOKUP_OPEN;
int rc = 0;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),file %p,"
"open_flags %x,mode %x opened %d\n",
@@ -627,7 +623,7 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
OBD_ALLOC(it, sizeof(*it));
if (!it)
- RETURN(-ENOMEM);
+ return -ENOMEM;
it->it_op = IT_OPEN;
if (mode) {
@@ -686,7 +682,7 @@ out_release:
ll_intent_release(it);
OBD_FREE(it, sizeof(*it));
- RETURN(rc);
+ return rc;
}
@@ -700,7 +696,6 @@ static struct inode *ll_create_node(struct inode *dir, const char *name,
struct ptlrpc_request *request = NULL;
struct ll_sb_info *sbi = ll_i2sbi(dir);
int rc;
- ENTRY;
LASSERT(it && it->d.lustre.it_disposition);
@@ -719,7 +714,6 @@ static struct inode *ll_create_node(struct inode *dir, const char *name,
CDEBUG(D_DLMTRACE, "setting l_ast_data to inode %p (%lu/%u)\n",
inode, inode->i_ino, inode->i_generation);
ll_set_lock_data(sbi->ll_md_exp, inode, it, NULL);
- EXIT;
out:
ptlrpc_req_finished(request);
return inode;
@@ -744,7 +738,6 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry, int mode,
{
struct inode *inode;
int rc = 0;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),intent=%s\n",
dentry->d_name.len, dentry->d_name.name, dir->i_ino,
@@ -752,18 +745,18 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry, int mode,
rc = it_open_error(DISP_OPEN_CREATE, it);
if (rc)
- RETURN(rc);
+ return rc;
inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len,
NULL, 0, mode, 0, it);
if (IS_ERR(inode))
- RETURN(PTR_ERR(inode));
+ return PTR_ERR(inode);
if (filename_is_volatile(dentry->d_name.name, dentry->d_name.len, NULL))
ll_i2info(inode)->lli_volatile = true;
d_instantiate(dentry, inode);
- RETURN(0);
+ return 0;
}
static void ll_update_times(struct ptlrpc_request *request,
@@ -795,7 +788,6 @@ static int ll_new_node(struct inode *dir, struct qstr *name,
int tgt_len = 0;
int err;
- ENTRY;
if (unlikely(tgt != NULL))
tgt_len = strlen(tgt) + 1;
@@ -805,7 +797,8 @@ static int ll_new_node(struct inode *dir, struct qstr *name,
GOTO(err_exit, err = PTR_ERR(op_data));
err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
- current_fsuid(), current_fsgid(),
+ from_kuid(&init_user_ns, current_fsuid()),
+ from_kgid(&init_user_ns, current_fsgid()),
cfs_curproc_cap_pack(), rdev, &request);
ll_finish_md_op_data(op_data);
if (err)
@@ -820,7 +813,6 @@ static int ll_new_node(struct inode *dir, struct qstr *name,
d_instantiate(dchild, inode);
}
- EXIT;
err_exit:
ptlrpc_req_finished(request);
@@ -831,7 +823,6 @@ static int ll_mknod_generic(struct inode *dir, struct qstr *name, int mode,
unsigned rdev, struct dentry *dchild)
{
int err;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p) mode %o dev %x\n",
name->len, name->name, dir->i_ino, dir->i_generation, dir,
@@ -861,7 +852,7 @@ static int ll_mknod_generic(struct inode *dir, struct qstr *name, int mode,
if (!err)
ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_MKNOD, 1);
- RETURN(err);
+ return err;
}
/*
@@ -891,7 +882,6 @@ static int ll_symlink_generic(struct inode *dir, struct qstr *name,
const char *tgt, struct dentry *dchild)
{
int err;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),target=%.*s\n",
name->len, name->name, dir->i_ino, dir->i_generation,
@@ -903,7 +893,7 @@ static int ll_symlink_generic(struct inode *dir, struct qstr *name,
if (!err)
ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_SYMLINK, 1);
- RETURN(err);
+ return err;
}
static int ll_link_generic(struct inode *src, struct inode *dir,
@@ -914,7 +904,6 @@ static int ll_link_generic(struct inode *src, struct inode *dir,
struct md_op_data *op_data;
int err;
- ENTRY;
CDEBUG(D_VFSTRACE,
"VFS Op: inode=%lu/%u(%p), dir=%lu/%u(%p), target=%.*s\n",
src->i_ino, src->i_generation, src, dir->i_ino,
@@ -923,7 +912,7 @@ static int ll_link_generic(struct inode *src, struct inode *dir,
op_data = ll_prep_md_op_data(NULL, src, dir, name->name, name->len,
0, LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
err = md_link(sbi->ll_md_exp, op_data, &request);
ll_finish_md_op_data(op_data);
@@ -932,10 +921,9 @@ static int ll_link_generic(struct inode *src, struct inode *dir,
ll_update_times(request, dir);
ll_stats_ops_tally(sbi, LPROC_LL_LINK, 1);
- EXIT;
out:
ptlrpc_req_finished(request);
- RETURN(err);
+ return err;
}
static int ll_mkdir_generic(struct inode *dir, struct qstr *name,
@@ -943,7 +931,6 @@ static int ll_mkdir_generic(struct inode *dir, struct qstr *name,
{
int err;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
name->len, name->name, dir->i_ino, dir->i_generation, dir);
@@ -956,7 +943,7 @@ static int ll_mkdir_generic(struct inode *dir, struct qstr *name,
if (!err)
ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_MKDIR, 1);
- RETURN(err);
+ return err;
}
/* Try to find the child dentry by its name.
@@ -981,18 +968,17 @@ static int ll_rmdir_generic(struct inode *dir, struct dentry *dparent,
struct ptlrpc_request *request = NULL;
struct md_op_data *op_data;
int rc;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
name->len, name->name, dir->i_ino, dir->i_generation, dir);
if (unlikely(ll_d_mountpoint(dparent, dchild, name)))
- RETURN(-EBUSY);
+ return -EBUSY;
op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name, name->len,
S_IFDIR, LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
ll_get_child_fid(dir, name, &op_data->op_fid3);
op_data->op_fid2 = op_data->op_fid3;
@@ -1004,7 +990,7 @@ static int ll_rmdir_generic(struct inode *dir, struct dentry *dparent,
}
ptlrpc_req_finished(request);
- RETURN(rc);
+ return rc;
}
/**
@@ -1015,7 +1001,6 @@ int ll_rmdir_entry(struct inode *dir, char *name, int namelen)
struct ptlrpc_request *request = NULL;
struct md_op_data *op_data;
int rc;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
namelen, name, dir->i_ino, dir->i_generation, dir);
@@ -1023,7 +1008,7 @@ int ll_rmdir_entry(struct inode *dir, char *name, int namelen)
op_data = ll_prep_md_op_data(NULL, dir, NULL, name, strlen(name),
S_IFDIR, LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
op_data->op_cli_flags |= CLI_RM_ENTRY;
rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
ll_finish_md_op_data(op_data);
@@ -1033,7 +1018,7 @@ int ll_rmdir_entry(struct inode *dir, char *name, int namelen)
}
ptlrpc_req_finished(request);
- RETURN(rc);
+ return rc;
}
int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
@@ -1045,12 +1030,11 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
struct obdo *oa;
struct obd_capa *oc = NULL;
int rc;
- ENTRY;
/* req is swabbed so this is safe */
body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY);
if (!(body->valid & OBD_MD_FLEASIZE))
- RETURN(0);
+ return 0;
if (body->eadatasize == 0) {
CERROR("OBD_MD_FLEASIZE set but eadatasize zero\n");
@@ -1122,7 +1106,6 @@ static int ll_unlink_generic(struct inode *dir, struct dentry *dparent,
struct ptlrpc_request *request = NULL;
struct md_op_data *op_data;
int rc;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
name->len, name->name, dir->i_ino, dir->i_generation, dir);
@@ -1131,12 +1114,12 @@ static int ll_unlink_generic(struct inode *dir, struct dentry *dparent,
* just check it as vfs_unlink does.
*/
if (unlikely(ll_d_mountpoint(dparent, dchild, name)))
- RETURN(-EBUSY);
+ return -EBUSY;
op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name,
name->len, 0, LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
ll_get_child_fid(dir, name, &op_data->op_fid3);
op_data->op_fid2 = op_data->op_fid3;
@@ -1151,7 +1134,7 @@ static int ll_unlink_generic(struct inode *dir, struct dentry *dparent,
rc = ll_objects_destroy(request, dir);
out:
ptlrpc_req_finished(request);
- RETURN(rc);
+ return rc;
}
static int ll_rename_generic(struct inode *src, struct dentry *src_dparent,
@@ -1163,7 +1146,7 @@ static int ll_rename_generic(struct inode *src, struct dentry *src_dparent,
struct ll_sb_info *sbi = ll_i2sbi(src);
struct md_op_data *op_data;
int err;
- ENTRY;
+
CDEBUG(D_VFSTRACE,"VFS Op:oldname=%.*s,src_dir=%lu/%u(%p),newname=%.*s,"
"tgt_dir=%lu/%u(%p)\n", src_name->len, src_name->name,
src->i_ino, src->i_generation, src, tgt_name->len,
@@ -1171,12 +1154,12 @@ static int ll_rename_generic(struct inode *src, struct dentry *src_dparent,
if (unlikely(ll_d_mountpoint(src_dparent, src_dchild, src_name) ||
ll_d_mountpoint(tgt_dparent, tgt_dchild, tgt_name)))
- RETURN(-EBUSY);
+ return -EBUSY;
op_data = ll_prep_md_op_data(NULL, src, tgt, NULL, 0, 0,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
ll_get_child_fid(src, src_name, &op_data->op_fid3);
ll_get_child_fid(tgt, tgt_name, &op_data->op_fid4);
@@ -1193,7 +1176,7 @@ static int ll_rename_generic(struct inode *src, struct dentry *src_dparent,
ptlrpc_req_finished(request);
- RETURN(err);
+ return err;
}
static int ll_mknod(struct inode *dir, struct dentry *dchild, ll_umode_t mode,
diff --git a/drivers/staging/lustre/lustre/llite/remote_perm.c b/drivers/staging/lustre/lustre/llite/remote_perm.c
index 68b2dc4a7b6..dedd56ae1e6 100644
--- a/drivers/staging/lustre/lustre/llite/remote_perm.c
+++ b/drivers/staging/lustre/lustre/llite/remote_perm.c
@@ -45,7 +45,6 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <lustre_lite.h>
#include <lustre_ha.h>
@@ -124,22 +123,22 @@ static int do_check_remote_perm(struct ll_inode_info *lli, int mask)
struct hlist_head *head;
struct ll_remote_perm *lrp;
int found = 0, rc;
- ENTRY;
if (!lli->lli_remote_perms)
- RETURN(-ENOENT);
+ return -ENOENT;
- head = lli->lli_remote_perms + remote_perm_hashfunc(current_uid());
+ head = lli->lli_remote_perms +
+ remote_perm_hashfunc(from_kuid(&init_user_ns, current_uid()));
spin_lock(&lli->lli_lock);
hlist_for_each_entry(lrp, head, lrp_list) {
- if (lrp->lrp_uid != current_uid())
+ if (lrp->lrp_uid != from_kuid(&init_user_ns, current_uid()))
continue;
- if (lrp->lrp_gid != current_gid())
+ if (lrp->lrp_gid != from_kgid(&init_user_ns, current_gid()))
continue;
- if (lrp->lrp_fsuid != current_fsuid())
+ if (lrp->lrp_fsuid != from_kuid(&init_user_ns, current_fsuid()))
continue;
- if (lrp->lrp_fsgid != current_fsgid())
+ if (lrp->lrp_fsgid != from_kgid(&init_user_ns, current_fsgid()))
continue;
found = 1;
break;
@@ -163,7 +162,6 @@ int ll_update_remote_perm(struct inode *inode, struct mdt_remote_perm *perm)
struct ll_inode_info *lli = ll_i2info(inode);
struct ll_remote_perm *lrp = NULL, *tmp = NULL;
struct hlist_head *head, *perm_hash = NULL;
- ENTRY;
LASSERT(ll_i2sbi(inode)->ll_flags & LL_SBI_RMT_CLIENT);
@@ -178,7 +176,7 @@ int ll_update_remote_perm(struct inode *inode, struct mdt_remote_perm *perm)
perm->rp_uid, perm->rp_gid, perm->rp_fsuid,
perm->rp_fsgid, current->uid, current->gid,
current->fsuid, current->fsgid);
- RETURN(-EAGAIN);
+ return -EAGAIN;
}
#endif
@@ -186,7 +184,7 @@ int ll_update_remote_perm(struct inode *inode, struct mdt_remote_perm *perm)
perm_hash = alloc_rmtperm_hash();
if (perm_hash == NULL) {
CERROR("alloc lli_remote_perms failed!\n");
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
}
@@ -220,7 +218,7 @@ again:
lrp = alloc_ll_remote_perm();
if (!lrp) {
CERROR("alloc memory for ll_remote_perm failed!\n");
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
spin_lock(&lli->lli_lock);
goto again;
@@ -241,7 +239,7 @@ again:
lrp, lrp->lrp_uid, lrp->lrp_gid, lrp->lrp_fsuid, lrp->lrp_fsgid,
lrp->lrp_access_perm);
- RETURN(0);
+ return 0;
}
int lustre_check_remote_perm(struct inode *inode, int mask)
@@ -253,7 +251,6 @@ int lustre_check_remote_perm(struct inode *inode, int mask)
struct obd_capa *oc;
cfs_time_t save;
int i = 0, rc;
- ENTRY;
do {
save = lli->lli_rmtperm_time;
@@ -304,7 +301,7 @@ int lustre_check_remote_perm(struct inode *inode, int mask)
req = NULL;
} while (1);
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
#if 0 /* NB: remote perms can't be freed in ll_mdc_blocking_ast of UPDATE lock,
diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c
index fac11788901..ae0dc441d1d 100644
--- a/drivers/staging/lustre/lustre/llite/rw.c
+++ b/drivers/staging/lustre/lustre/llite/rw.c
@@ -48,9 +48,6 @@
#include <asm/uaccess.h>
#include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-#include <linux/mm.h>
#include <linux/pagemap.h>
/* current_is_kswapd() */
#include <linux/swap.h>
@@ -110,7 +107,7 @@ static struct ll_cl_context *ll_cl_init(struct file *file,
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- return ERR_PTR(PTR_ERR(env));
+ return ERR_CAST(env);
lcc = &vvp_env_info(env)->vti_io_ctx;
memset(lcc, 0, sizeof(*lcc));
@@ -132,7 +129,7 @@ static struct ll_cl_context *ll_cl_init(struct file *file,
* add dirty pages into cache during truncate */
CERROR("Proc %s is dirting page w/o inode lock, this"
"will break truncate.\n", current->comm);
- libcfs_debug_dumpstack(NULL);
+ dump_stack();
LBUG();
return ERR_PTR(-EIO);
}
@@ -228,7 +225,6 @@ int ll_prepare_write(struct file *file, struct page *vmpage, unsigned from,
{
struct ll_cl_context *lcc;
int result;
- ENTRY;
lcc = ll_cl_init(file, vmpage, 1);
if (!IS_ERR(lcc)) {
@@ -256,7 +252,7 @@ int ll_prepare_write(struct file *file, struct page *vmpage, unsigned from,
} else {
result = PTR_ERR(lcc);
}
- RETURN(result);
+ return result;
}
int ll_commit_write(struct file *file, struct page *vmpage, unsigned from,
@@ -267,7 +263,6 @@ int ll_commit_write(struct file *file, struct page *vmpage, unsigned from,
struct cl_io *io;
struct cl_page *page;
int result = 0;
- ENTRY;
lcc = ll_cl_get();
env = lcc->lcc_env;
@@ -287,7 +282,7 @@ int ll_commit_write(struct file *file, struct page *vmpage, unsigned from,
lu_ref_del(&page->cp_reference, "prepare_write", current);
cl_page_put(env, page);
ll_cl_fini(lcc);
- RETURN(result);
+ return result;
}
struct obd_capa *cl_capa_lookup(struct inode *inode, enum cl_req_type crt)
@@ -325,7 +320,6 @@ static unsigned long ll_ra_count_get(struct ll_sb_info *sbi,
{
struct ll_ra_info *ra = &sbi->ll_ra_info;
long ret;
- ENTRY;
/* If read-ahead pages left are less than 1M, do not do read-ahead,
* otherwise it will form small read RPC(< 1M), which hurt server
@@ -357,7 +351,7 @@ static unsigned long ll_ra_count_get(struct ll_sb_info *sbi,
}
out:
- RETURN(ret);
+ return ret;
}
void ll_ra_count_put(struct ll_sb_info *sbi, unsigned long len)
@@ -468,8 +462,6 @@ static int cl_read_ahead_page(const struct lu_env *env, struct cl_io *io,
struct ccc_page *cp;
int rc;
- ENTRY;
-
rc = 0;
cl_page_assume(env, io, page);
lu_ref_add(&page->cp_reference, "ra", current);
@@ -491,7 +483,7 @@ static int cl_read_ahead_page(const struct lu_env *env, struct cl_io *io,
}
lu_ref_del(&page->cp_reference, "ra", current);
cl_page_put(env, page);
- RETURN(rc);
+ return rc;
}
/**
@@ -516,8 +508,6 @@ static int ll_read_ahead_page(const struct lu_env *env, struct cl_io *io,
int rc = 0;
const char *msg = NULL;
- ENTRY;
-
gfp_mask = GFP_HIGHUSER & ~__GFP_WAIT;
#ifdef __GFP_NOWARN
gfp_mask |= __GFP_NOWARN;
@@ -554,7 +544,7 @@ static int ll_read_ahead_page(const struct lu_env *env, struct cl_io *io,
ll_ra_stats_inc(mapping, which);
CDEBUG(D_READA, "%s\n", msg);
}
- RETURN(rc);
+ return rc;
}
#define RIA_DEBUG(ria) \
@@ -722,7 +712,6 @@ int ll_readahead(const struct lu_env *env, struct cl_io *io,
struct cl_object *clob;
int ret = 0;
__u64 kms;
- ENTRY;
inode = mapping->host;
lli = ll_i2info(inode);
@@ -735,11 +724,11 @@ int ll_readahead(const struct lu_env *env, struct cl_io *io,
cl_object_attr_unlock(clob);
if (ret != 0)
- RETURN(ret);
+ return ret;
kms = attr->cat_kms;
if (kms == 0) {
ll_ra_stats_inc(mapping, RA_STAT_ZERO_LEN);
- RETURN(0);
+ return 0;
}
spin_lock(&ras->ras_lock);
@@ -797,11 +786,11 @@ int ll_readahead(const struct lu_env *env, struct cl_io *io,
if (end == 0) {
ll_ra_stats_inc(mapping, RA_STAT_ZERO_WINDOW);
- RETURN(0);
+ return 0;
}
len = ria_page_count(ria);
if (len == 0)
- RETURN(0);
+ return 0;
reserved = ll_ra_count_get(ll_i2sbi(inode), ria, len);
if (reserved < len)
@@ -840,7 +829,7 @@ int ll_readahead(const struct lu_env *env, struct cl_io *io,
spin_unlock(&ras->ras_lock);
}
- RETURN(ret);
+ return ret;
}
static void ras_set_start(struct inode *inode, struct ll_readahead_state *ras,
@@ -999,7 +988,6 @@ void ras_update(struct ll_sb_info *sbi, struct inode *inode,
{
struct ll_ra_info *ra = &sbi->ll_ra_info;
int zero = 0, stride_detect = 0, ra_miss = 0;
- ENTRY;
spin_lock(&ras->ras_lock);
@@ -1135,7 +1123,6 @@ void ras_update(struct ll_sb_info *sbi, struct inode *inode,
if ((ras->ras_consecutive_requests > 1 || stride_detect) &&
!ras->ras_request_index)
ras_increase_window(inode, ras, ra);
- EXIT;
out_unlock:
RAS_CDEBUG(ras);
ras->ras_request_index++;
@@ -1155,7 +1142,6 @@ int ll_writepage(struct page *vmpage, struct writeback_control *wbc)
bool redirtied = false;
bool unlocked = false;
int result;
- ENTRY;
LASSERT(PageLocked(vmpage));
LASSERT(!PageWriteback(vmpage));
@@ -1247,7 +1233,6 @@ int ll_writepages(struct address_space *mapping, struct writeback_control *wbc)
int range_whole = 0;
int result;
int ignore_layout = 0;
- ENTRY;
if (wbc->range_cyclic) {
start = mapping->writeback_index << PAGE_CACHE_SHIFT;
@@ -1281,14 +1266,13 @@ int ll_writepages(struct address_space *mapping, struct writeback_control *wbc)
end = i_size_read(inode);
mapping->writeback_index = (end >> PAGE_CACHE_SHIFT) + 1;
}
- RETURN(result);
+ return result;
}
int ll_readpage(struct file *file, struct page *vmpage)
{
struct ll_cl_context *lcc;
int result;
- ENTRY;
lcc = ll_cl_init(file, vmpage, 0);
if (!IS_ERR(lcc)) {
@@ -1310,5 +1294,5 @@ int ll_readpage(struct file *file, struct page *vmpage)
unlock_page(vmpage);
result = PTR_ERR(lcc);
}
- RETURN(result);
+ return result;
}
diff --git a/drivers/staging/lustre/lustre/llite/rw26.c b/drivers/staging/lustre/lustre/llite/rw26.c
index 27e4e64bc1e..96c29ad2fc8 100644
--- a/drivers/staging/lustre/lustre/llite/rw26.c
+++ b/drivers/staging/lustre/lustre/llite/rw26.c
@@ -51,9 +51,6 @@
#include <linux/buffer_head.h>
#include <linux/mpage.h>
#include <linux/writeback.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-#include <linux/mm.h>
#include <linux/pagemap.h>
#define DEBUG_SUBSYSTEM S_LLITE
@@ -72,7 +69,8 @@
* aligned truncate). Lustre leaves partially truncated page in the cache,
* relying on struct inode::i_size to limit further accesses.
*/
-static void ll_invalidatepage(struct page *vmpage, unsigned long offset)
+static void ll_invalidatepage(struct page *vmpage, unsigned int offset,
+ unsigned int length)
{
struct inode *inode;
struct lu_env *env;
@@ -89,7 +87,7 @@ static void ll_invalidatepage(struct page *vmpage, unsigned long offset)
* below because they are run with page locked and all our io is
* happening with locked page too
*/
- if (offset == 0) {
+ if (offset == 0 && length == PAGE_CACHE_SIZE) {
env = cl_env_get(&refcheck);
if (!IS_ERR(env)) {
inode = vmpage->mapping->host;
@@ -182,7 +180,7 @@ static int ll_set_page_dirty(struct page *vmpage)
*/
vvp_write_pending(obj, cpg);
#endif
- RETURN(__set_page_dirty_nobuffers(vmpage));
+ return __set_page_dirty_nobuffers(vmpage);
}
#define MAX_DIRECTIO_SIZE 2*1024*1024*1024UL
@@ -249,7 +247,6 @@ ssize_t ll_direct_rw_pages(const struct lu_env *env, struct cl_io *io,
long page_size = cl_page_size(obj);
bool do_io;
int io_pages = 0;
- ENTRY;
queue = &io->ci_queue;
cl_2queue_init(queue);
@@ -286,11 +283,11 @@ ssize_t ll_direct_rw_pages(const struct lu_env *env, struct cl_io *io,
src_page = (rw == WRITE) ? pages[i] : vmpage;
dst_page = (rw == WRITE) ? vmpage : pages[i];
- src = ll_kmap_atomic(src_page, KM_USER0);
- dst = ll_kmap_atomic(dst_page, KM_USER1);
+ src = kmap_atomic(src_page);
+ dst = kmap_atomic(dst_page);
memcpy(dst, src, min(page_size, size));
- ll_kunmap_atomic(dst, KM_USER1);
- ll_kunmap_atomic(src, KM_USER0);
+ kunmap_atomic(dst);
+ kunmap_atomic(src);
/* make sure page will be added to the transfer by
* cl_io_submit()->...->vvp_page_prep_write(). */
@@ -335,7 +332,7 @@ ssize_t ll_direct_rw_pages(const struct lu_env *env, struct cl_io *io,
cl_2queue_discard(env, io, queue);
cl_2queue_disown(env, io, queue);
cl_2queue_fini(env, queue);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ll_direct_rw_pages);
@@ -383,14 +380,13 @@ static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb,
unsigned long seg = 0;
long size = MAX_DIO_SIZE;
int refcheck;
- ENTRY;
if (!lli->lli_has_smd)
- RETURN(-EBADF);
+ return -EBADF;
/* FIXME: io smaller than PAGE_SIZE is broken on ia64 ??? */
if ((file_offset & ~CFS_PAGE_MASK) || (count & ~CFS_PAGE_MASK))
- RETURN(-EINVAL);
+ return -EINVAL;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), size=%lu (max %lu), "
"offset=%lld=%llx, pages %lu (max %lu)\n",
@@ -402,7 +398,7 @@ static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb,
for (seg = 0; seg < nr_segs; seg++) {
if (((unsigned long)iov[seg].iov_base & ~CFS_PAGE_MASK) ||
(iov[seg].iov_len & ~CFS_PAGE_MASK))
- RETURN(-EINVAL);
+ return -EINVAL;
}
env = cl_env_get(&refcheck);
@@ -495,7 +491,7 @@ out:
}
cl_env_put(env, &refcheck);
- RETURN(tot_bytes ? : result);
+ return tot_bytes ? : result;
}
static int ll_write_begin(struct file *file, struct address_space *mapping,
@@ -506,11 +502,10 @@ static int ll_write_begin(struct file *file, struct address_space *mapping,
struct page *page;
int rc;
unsigned from = pos & (PAGE_CACHE_SIZE - 1);
- ENTRY;
page = grab_cache_page_write_begin(mapping, index, flags);
if (!page)
- RETURN(-ENOMEM);
+ return -ENOMEM;
*pagep = page;
@@ -519,7 +514,7 @@ static int ll_write_begin(struct file *file, struct address_space *mapping,
unlock_page(page);
page_cache_release(page);
}
- RETURN(rc);
+ return rc;
}
static int ll_write_end(struct file *file, struct address_space *mapping,
diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c
index 7747f8f2079..8eaa38e91b9 100644
--- a/drivers/staging/lustre/lustre/llite/statahead.c
+++ b/drivers/staging/lustre/lustre/llite/statahead.c
@@ -200,12 +200,11 @@ ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index,
struct ll_sa_entry *entry;
int entry_size;
char *dname;
- ENTRY;
entry_size = sizeof(struct ll_sa_entry) + (len & ~3) + 4;
OBD_ALLOC(entry, entry_size);
if (unlikely(entry == NULL))
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
CDEBUG(D_READA, "alloc sa entry %.*s(%p) index "LPU64"\n",
len, name, entry, index);
@@ -254,7 +253,7 @@ ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index,
atomic_inc(&sai->sai_cache_count);
- RETURN(entry);
+ return entry;
}
/*
@@ -465,11 +464,10 @@ static struct ll_statahead_info *ll_sai_alloc(void)
{
struct ll_statahead_info *sai;
int i;
- ENTRY;
OBD_ALLOC_PTR(sai);
if (!sai)
- RETURN(NULL);
+ return NULL;
atomic_set(&sai->sai_refcount, 1);
@@ -496,7 +494,7 @@ static struct ll_statahead_info *ll_sai_alloc(void)
}
atomic_set(&sai->sai_cache_count, 0);
- RETURN(sai);
+ return sai;
}
static inline struct ll_statahead_info *
@@ -510,7 +508,6 @@ static void ll_sai_put(struct ll_statahead_info *sai)
{
struct inode *inode = sai->sai_inode;
struct ll_inode_info *lli = ll_i2info(inode);
- ENTRY;
if (atomic_dec_and_lock(&sai->sai_refcount, &lli->lli_sa_lock)) {
struct ll_sa_entry *entry, *next;
@@ -519,7 +516,7 @@ static void ll_sai_put(struct ll_statahead_info *sai)
/* It is race case, the interpret callback just hold
* a reference count */
spin_unlock(&lli->lli_sa_lock);
- RETURN_EXIT;
+ return;
}
LASSERT(lli->lli_opendir_key == NULL);
@@ -550,8 +547,6 @@ static void ll_sai_put(struct ll_statahead_info *sai)
iput(inode);
OBD_FREE_PTR(sai);
}
-
- EXIT;
}
/* Do NOT forget to drop inode refcount when into sai_entries_agl. */
@@ -560,7 +555,6 @@ static void ll_agl_trigger(struct inode *inode, struct ll_statahead_info *sai)
struct ll_inode_info *lli = ll_i2info(inode);
__u64 index = lli->lli_agl_index;
int rc;
- ENTRY;
LASSERT(list_empty(&lli->lli_agl_list));
@@ -568,7 +562,7 @@ static void ll_agl_trigger(struct inode *inode, struct ll_statahead_info *sai)
if (is_omitted_entry(sai, index + 1)) {
lli->lli_agl_index = 0;
iput(inode);
- RETURN_EXIT;
+ return;
}
/* Someone is in glimpse (sync or async), do nothing. */
@@ -576,7 +570,7 @@ static void ll_agl_trigger(struct inode *inode, struct ll_statahead_info *sai)
if (rc == 0) {
lli->lli_agl_index = 0;
iput(inode);
- RETURN_EXIT;
+ return;
}
/*
@@ -597,7 +591,7 @@ static void ll_agl_trigger(struct inode *inode, struct ll_statahead_info *sai)
up_write(&lli->lli_glimpse_sem);
lli->lli_agl_index = 0;
iput(inode);
- RETURN_EXIT;
+ return;
}
CDEBUG(D_READA, "Handling (init) async glimpse: inode = "
@@ -613,8 +607,6 @@ static void ll_agl_trigger(struct inode *inode, struct ll_statahead_info *sai)
PFID(&lli->lli_fid), index, rc);
iput(inode);
-
- EXIT;
}
static void ll_post_statahead(struct ll_statahead_info *sai)
@@ -628,12 +620,11 @@ static void ll_post_statahead(struct ll_statahead_info *sai)
struct ptlrpc_request *req;
struct mdt_body *body;
int rc = 0;
- ENTRY;
spin_lock(&lli->lli_sa_lock);
if (unlikely(sa_received_empty(sai))) {
spin_unlock(&lli->lli_sa_lock);
- RETURN_EXIT;
+ return;
}
entry = sa_first_received_entry(sai);
atomic_inc(&entry->se_refcount);
@@ -690,8 +681,6 @@ static void ll_post_statahead(struct ll_statahead_info *sai)
if (agl_should_run(sai, child))
ll_agl_add(sai, child, entry->se_index);
- EXIT;
-
out:
/* The "ll_sa_entry_to_stated()" will drop related ldlm ibits lock
* reference count by calling "ll_intent_drop_lock()" in spite of the
@@ -713,7 +702,6 @@ static int ll_statahead_interpret(struct ptlrpc_request *req,
struct ll_statahead_info *sai = NULL;
struct ll_sa_entry *entry;
int wakeup;
- ENTRY;
if (it_disposition(it, DISP_LOOKUP_NEG))
rc = -ENOENT;
@@ -763,8 +751,6 @@ static int ll_statahead_interpret(struct ptlrpc_request *req,
wake_up(&sai->sai_thread.t_ctl_waitq);
}
- EXIT;
-
out:
if (rc != 0) {
ll_intent_release(it);
@@ -852,11 +838,10 @@ static int do_sa_lookup(struct inode *dir, struct ll_sa_entry *entry)
struct ldlm_enqueue_info *einfo;
struct obd_capa *capas[2];
int rc;
- ENTRY;
rc = sa_args_init(dir, NULL, entry, &minfo, &einfo, capas);
if (rc)
- RETURN(rc);
+ return rc;
rc = md_intent_getattr_async(ll_i2mdexp(dir), minfo, einfo);
if (!rc) {
@@ -866,7 +851,7 @@ static int do_sa_lookup(struct inode *dir, struct ll_sa_entry *entry)
sa_args_fini(minfo, einfo);
}
- RETURN(rc);
+ return rc;
}
/**
@@ -885,30 +870,29 @@ static int do_sa_revalidate(struct inode *dir, struct ll_sa_entry *entry,
struct ldlm_enqueue_info *einfo;
struct obd_capa *capas[2];
int rc;
- ENTRY;
if (unlikely(inode == NULL))
- RETURN(1);
+ return 1;
if (d_mountpoint(dentry))
- RETURN(1);
+ return 1;
if (unlikely(dentry == dentry->d_sb->s_root))
- RETURN(1);
+ return 1;
entry->se_inode = igrab(inode);
rc = md_revalidate_lock(ll_i2mdexp(dir), &it, ll_inode2fid(inode),NULL);
if (rc == 1) {
entry->se_handle = it.d.lustre.it_lock_handle;
ll_intent_release(&it);
- RETURN(1);
+ return 1;
}
rc = sa_args_init(dir, inode, entry, &minfo, &einfo, capas);
if (rc) {
entry->se_inode = NULL;
iput(inode);
- RETURN(rc);
+ return rc;
}
rc = md_intent_getattr_async(ll_i2mdexp(dir), minfo, einfo);
@@ -921,7 +905,7 @@ static int do_sa_revalidate(struct inode *dir, struct ll_sa_entry *entry,
sa_args_fini(minfo, einfo);
}
- RETURN(rc);
+ return rc;
}
static void ll_statahead_one(struct dentry *parent, const char* entry_name,
@@ -934,12 +918,11 @@ static void ll_statahead_one(struct dentry *parent, const char* entry_name,
struct ll_sa_entry *entry;
int rc;
int rc1;
- ENTRY;
entry = ll_sa_entry_alloc(sai, sai->sai_index, entry_name,
entry_name_len);
if (IS_ERR(entry))
- RETURN_EXIT;
+ return;
dentry = d_lookup(parent, &entry->se_qstr);
if (!dentry) {
@@ -965,8 +948,6 @@ static void ll_statahead_one(struct dentry *parent, const char* entry_name,
sai->sai_index++;
/* drop one refcount on entry by ll_sa_entry_alloc */
ll_sa_entry_put(sai, entry);
-
- EXIT;
}
static int ll_agl_thread(void *arg)
@@ -979,7 +960,6 @@ static int ll_agl_thread(void *arg)
struct ll_statahead_info *sai = ll_sai_get(plli->lli_sai);
struct ptlrpc_thread *thread = &sai->sai_agl_thread;
struct l_wait_info lwi = { 0 };
- ENTRY;
CDEBUG(D_READA, "agl thread started: [pid %d] [parent %.*s]\n",
current_pid(), parent->d_name.len, parent->d_name.name);
@@ -1029,7 +1009,7 @@ static int ll_agl_thread(void *arg)
ll_sai_put(sai);
CDEBUG(D_READA, "agl thread stopped: [pid %d] [parent %.*s]\n",
current_pid(), parent->d_name.len, parent->d_name.name);
- RETURN(0);
+ return 0;
}
static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai)
@@ -1037,8 +1017,7 @@ static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai)
struct ptlrpc_thread *thread = &sai->sai_agl_thread;
struct l_wait_info lwi = { 0 };
struct ll_inode_info *plli;
- task_t *task;
- ENTRY;
+ struct task_struct *task;
CDEBUG(D_READA, "start agl thread: [pid %d] [parent %.*s]\n",
current_pid(), parent->d_name.len, parent->d_name.name);
@@ -1049,13 +1028,12 @@ static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai)
if (IS_ERR(task)) {
CERROR("can't start ll_agl thread, rc: %ld\n", PTR_ERR(task));
thread_set_flags(thread, SVC_STOPPED);
- RETURN_EXIT;
+ return;
}
l_wait_event(thread->t_ctl_waitq,
thread_is_running(thread) || thread_is_stopped(thread),
&lwi);
- EXIT;
}
static int ll_statahead_thread(void *arg)
@@ -1074,7 +1052,6 @@ static int ll_statahead_thread(void *arg)
int rc = 0;
struct ll_dir_chain chain;
struct l_wait_info lwi = { 0 };
- ENTRY;
CDEBUG(D_READA, "statahead thread started: [pid %d] [parent %.*s]\n",
current_pid(), parent->d_name.len, parent->d_name.name);
@@ -1257,7 +1234,6 @@ do_it:
*/
}
}
- EXIT;
out:
if (sai->sai_agl_valid) {
@@ -1369,7 +1345,6 @@ static int is_first_dirent(struct inode *dir, struct dentry *dentry)
__u64 pos = 0;
int dot_de;
int rc = LS_NONE_FIRST_DE;
- ENTRY;
ll_dir_chain_init(&chain);
page = ll_get_dir_page(dir, pos, &chain);
@@ -1468,7 +1443,6 @@ static int is_first_dirent(struct inode *dir, struct dentry *dentry)
ll_release_page(page, 1);
}
}
- EXIT;
out:
ll_dir_chain_fini(&chain);
@@ -1481,7 +1455,6 @@ ll_sai_unplug(struct ll_statahead_info *sai, struct ll_sa_entry *entry)
struct ptlrpc_thread *thread = &sai->sai_thread;
struct ll_sb_info *sbi = ll_i2sbi(sai->sai_inode);
int hit;
- ENTRY;
if (entry != NULL && entry->se_stat == SA_ENTRY_SUCC)
hit = 1;
@@ -1516,8 +1489,6 @@ ll_sai_unplug(struct ll_statahead_info *sai, struct ll_sa_entry *entry)
if (!thread_is_stopped(thread))
wake_up(&thread->t_ctl_waitq);
-
- EXIT;
}
/**
@@ -1540,7 +1511,6 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
struct l_wait_info lwi = { 0 };
int rc = 0;
struct ll_inode_info *plli;
- ENTRY;
LASSERT(lli->lli_opendir_pid == current_pid());
@@ -1550,7 +1520,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
list_empty(&sai->sai_entries_stated))) {
/* to release resource */
ll_stop_statahead(dir, lli->lli_opendir_key);
- RETURN(-EAGAIN);
+ return -EAGAIN;
}
if ((*dentryp)->d_name.name[0] == '.') {
@@ -1576,14 +1546,14 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
* "sai_ls_all" enabled as above.
*/
sai->sai_miss_hidden++;
- RETURN(-EAGAIN);
+ return -EAGAIN;
}
}
entry = ll_sa_entry_get_byname(sai, &(*dentryp)->d_name);
if (entry == NULL || only_unplug) {
ll_sai_unplug(sai, entry);
- RETURN(entry ? 1 : -EAGAIN);
+ return entry ? 1 : -EAGAIN;
}
/* if statahead is busy in readdir, help it do post-work */
@@ -1602,7 +1572,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
&lwi);
if (rc < 0) {
ll_sai_unplug(sai, entry);
- RETURN(-EAGAIN);
+ return -EAGAIN;
}
}
@@ -1632,7 +1602,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
inode->i_ino,
inode->i_generation);
ll_sai_unplug(sai, entry);
- RETURN(-ESTALE);
+ return -ESTALE;
} else {
iput(inode);
}
@@ -1646,7 +1616,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
}
ll_sai_unplug(sai, entry);
- RETURN(rc);
+ return rc;
}
/* I am the "lli_opendir_pid" owner, only me can set "lli_sai". */
@@ -1698,7 +1668,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
thread_set_flags(&sai->sai_agl_thread, SVC_STOPPED);
ll_sai_put(sai);
LASSERT(lli->lli_sai == NULL);
- RETURN(-EAGAIN);
+ return -EAGAIN;
}
l_wait_event(thread->t_ctl_waitq,
@@ -1709,7 +1679,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
* We don't stat-ahead for the first dirent since we are already in
* lookup.
*/
- RETURN(-EAGAIN);
+ return -EAGAIN;
out:
if (sai != NULL)
diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c
index 82c14a993cc..0beaf4e76b4 100644
--- a/drivers/staging/lustre/lustre/llite/super25.c
+++ b/drivers/staging/lustre/lustre/llite/super25.c
@@ -38,7 +38,6 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <lustre_lite.h>
#include <lustre_ha.h>
#include <lustre_dlm.h>
@@ -214,7 +213,7 @@ static void __exit exit_lustre_lite(void)
ll_remote_perm_cachep = NULL;
kmem_cache_destroy(ll_file_data_slab);
- if (proc_lustre_fs_root)
+ if (proc_lustre_fs_root && !IS_ERR(proc_lustre_fs_root))
lprocfs_remove(&proc_lustre_fs_root);
}
diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c
index 5260e989a4e..ab06891f7fc 100644
--- a/drivers/staging/lustre/lustre/llite/symlink.c
+++ b/drivers/staging/lustre/lustre/llite/symlink.c
@@ -37,7 +37,6 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/stat.h>
-#include <linux/version.h>
#define DEBUG_SUBSYSTEM S_LLITE
#include <lustre_lite.h>
@@ -51,7 +50,6 @@ static int ll_readlink_internal(struct inode *inode,
int rc, symlen = i_size_read(inode) + 1;
struct mdt_body *body;
struct md_op_data *op_data;
- ENTRY;
*request = NULL;
@@ -65,13 +63,13 @@ static int ll_readlink_internal(struct inode *inode,
CDEBUG(D_INODE, "using cached symlink %s%.*s, len = %d\n",
print_limit < symlen ? "..." : "", print_limit,
(*symname) + symlen - print_limit, symlen);
- RETURN(0);
+ return 0;
}
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, symlen,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
- RETURN(PTR_ERR(op_data));
+ return PTR_ERR(op_data);
op_data->op_valid = OBD_MD_LINKNAME;
rc = md_getattr(sbi->ll_md_exp, op_data, request);
@@ -111,10 +109,10 @@ static int ll_readlink_internal(struct inode *inode,
memcpy(lli->lli_symlink_name, *symname, symlen);
*symname = lli->lli_symlink_name;
}
- RETURN(0);
+ return 0;
failed:
- RETURN (rc);
+ return rc;
}
static int ll_readlink(struct dentry *dentry, char *buffer, int buflen)
@@ -123,7 +121,6 @@ static int ll_readlink(struct dentry *dentry, char *buffer, int buflen)
struct ptlrpc_request *request;
char *symname;
int rc;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op\n");
@@ -136,7 +133,7 @@ static int ll_readlink(struct dentry *dentry, char *buffer, int buflen)
out:
ptlrpc_req_finished(request);
ll_inode_size_unlock(inode);
- RETURN(rc);
+ return rc;
}
static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
@@ -145,7 +142,6 @@ static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
struct ptlrpc_request *request = NULL;
int rc;
char *symname;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op\n");
/* Limit the recursive symlink depth to 5 instead of default
@@ -170,7 +166,7 @@ static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
/* symname may contain a pointer to the request message buffer,
* we delay request releasing until ll_put_link then.
*/
- RETURN(request);
+ return request;
}
static void ll_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c
index 9254b990d31..be125b98b7f 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_dev.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c
@@ -213,7 +213,7 @@ int cl_sb_init(struct super_block *sb)
cl_env_put(env, &refcheck);
} else
rc = PTR_ERR(env);
- RETURN(rc);
+ return rc;
}
int cl_sb_fini(struct super_block *sb)
@@ -224,7 +224,6 @@ int cl_sb_fini(struct super_block *sb)
int refcheck;
int result;
- ENTRY;
sbi = ll_s2sbi(sb);
env = cl_env_get(&refcheck);
if (!IS_ERR(env)) {
@@ -247,7 +246,7 @@ int cl_sb_fini(struct super_block *sb)
* automatically when last device is destroyed).
*/
lu_types_stop();
- RETURN(result);
+ return result;
}
/****************************************************************************
diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c
index eb964acad45..3ff664ce750 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_io.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_io.c
@@ -176,19 +176,18 @@ static int vvp_mmap_locks(const struct lu_env *env,
unsigned long seg;
ssize_t count;
int result;
- ENTRY;
LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE);
if (!cl_is_normalio(env, io))
- RETURN(0);
+ return 0;
if (vio->cui_iov == NULL) /* nfs or loop back device write */
- RETURN(0);
+ return 0;
/* No MM (e.g. NFS)? No vmas too. */
if (mm == NULL)
- RETURN(0);
+ return 0;
for (seg = 0; seg < vio->cui_nrsegs; seg++) {
const struct iovec *iv = &vio->cui_iov[seg];
@@ -234,7 +233,7 @@ static int vvp_mmap_locks(const struct lu_env *env,
descr->cld_end);
if (result < 0)
- RETURN(result);
+ return result;
if (vma->vm_end - addr >= count)
break;
@@ -244,7 +243,7 @@ static int vvp_mmap_locks(const struct lu_env *env,
}
up_read(&mm->mmap_sem);
}
- RETURN(0);
+ return 0;
}
static int vvp_io_rw_lock(const struct lu_env *env, struct cl_io *io,
@@ -255,7 +254,6 @@ static int vvp_io_rw_lock(const struct lu_env *env, struct cl_io *io,
int ast_flags = 0;
LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE);
- ENTRY;
ccc_io_update_iov(env, cio, io);
@@ -264,7 +262,7 @@ static int vvp_io_rw_lock(const struct lu_env *env, struct cl_io *io,
result = vvp_mmap_locks(env, cio, io);
if (result == 0)
result = ccc_io_one_lock(env, io, ast_flags, mode, start, end);
- RETURN(result);
+ return result;
}
static int vvp_io_read_lock(const struct lu_env *env,
@@ -274,7 +272,6 @@ static int vvp_io_read_lock(const struct lu_env *env,
struct ll_inode_info *lli = ll_i2info(ccc_object_inode(io->ci_obj));
int result;
- ENTRY;
/* XXX: Layer violation, we shouldn't see lsm at llite level. */
if (lli->lli_has_smd) /* lsm-less file doesn't need to lock */
result = vvp_io_rw_lock(env, io, CLM_READ,
@@ -283,7 +280,7 @@ static int vvp_io_read_lock(const struct lu_env *env,
io->u.ci_rd.rd.crw_count - 1);
else
result = 0;
- RETURN(result);
+ return result;
}
static int vvp_io_fault_lock(const struct lu_env *env,
@@ -407,13 +404,15 @@ static int vvp_io_setattr_start(const struct lu_env *env,
{
struct cl_io *io = ios->cis_io;
struct inode *inode = ccc_object_inode(io->ci_obj);
+ int result = 0;
mutex_lock(&inode->i_mutex);
if (cl_io_is_trunc(io))
- return vvp_io_setattr_trunc(env, ios, inode,
- io->u.ci_setattr.sa_attr.lvb_size);
- else
- return vvp_io_setattr_time(env, ios);
+ result = vvp_io_setattr_trunc(env, ios, inode,
+ io->u.ci_setattr.sa_attr.lvb_size);
+ if (result == 0)
+ result = vvp_io_setattr_time(env, ios);
+ return result;
}
static void vvp_io_setattr_end(const struct lu_env *env,
@@ -525,7 +524,7 @@ out:
io->ci_continue = 0;
io->ci_nob += result;
ll_rw_stats_tally(ll_i2sbi(inode), current->pid,
- cio->cui_fd, pos, result, 0);
+ cio->cui_fd, pos, result, READ);
result = 0;
}
return result;
@@ -554,8 +553,6 @@ static int vvp_io_write_start(const struct lu_env *env,
loff_t pos = io->u.ci_wr.wr.crw_pos;
size_t cnt = io->u.ci_wr.wr.crw_count;
- ENTRY;
-
if (!can_populate_pages(env, io, inode))
return 0;
@@ -580,10 +577,10 @@ static int vvp_io_write_start(const struct lu_env *env,
io->ci_continue = 0;
io->ci_nob += result;
ll_rw_stats_tally(ll_i2sbi(inode), current->pid,
- cio->cui_fd, pos, result, 0);
+ cio->cui_fd, pos, result, WRITE);
result = 0;
}
- RETURN(result);
+ return result;
}
static int vvp_io_kernel_fault(struct vvp_fault_io *cfio)
@@ -767,7 +764,6 @@ static int vvp_io_fault_start(const struct lu_env *env,
lu_ref_add(&page->cp_reference, "fault", io);
fio->ft_page = page;
- EXIT;
out:
/* return unlocked vmpage to avoid deadlocking */
@@ -805,8 +801,6 @@ static int vvp_io_read_page(const struct lu_env *env,
CLOBINVRNT(env, obj, ccc_object_invariant(obj));
LASSERT(slice->cpl_obj == obj);
- ENTRY;
-
if (sbi->ll_ra_info.ra_max_pages_per_file &&
sbi->ll_ra_info.ra_max_pages)
ras_update(sbi, inode, ras, page->cp_index,
@@ -819,7 +813,7 @@ static int vvp_io_read_page(const struct lu_env *env,
rc == -ENODATA ? "without a lock" :
"match failed", rc);
if (rc != -ENODATA)
- RETURN(rc);
+ return rc;
}
if (cp->cpg_defer_uptodate) {
@@ -836,7 +830,7 @@ static int vvp_io_read_page(const struct lu_env *env,
ll_readahead(env, io, ras,
vmpage->mapping, &queue->c2_qin, fd->fd_flags);
- RETURN(0);
+ return 0;
}
static int vvp_page_sync_io(const struct lu_env *env, struct cl_io *io,
@@ -887,10 +881,10 @@ static int vvp_io_prepare_partial(const struct lu_env *env, struct cl_io *io,
* purposes here we can treat it like i_size.
*/
if (attr->cat_kms <= offset) {
- char *kaddr = ll_kmap_atomic(cp->cpg_page, KM_USER0);
+ char *kaddr = kmap_atomic(cp->cpg_page);
memset(kaddr, 0, cl_page_size(obj));
- ll_kunmap_atomic(kaddr, KM_USER0);
+ kunmap_atomic(kaddr);
} else if (cp->cpg_defer_uptodate)
cp->cpg_ra_used = 1;
else
@@ -921,8 +915,6 @@ static int vvp_io_prepare_write(const struct lu_env *env,
int result;
- ENTRY;
-
LINVRNT(cl_page_is_vmlocked(env, pg));
LASSERT(vmpage->mapping->host == ccc_object_inode(obj));
@@ -942,7 +934,7 @@ static int vvp_io_prepare_write(const struct lu_env *env,
pg, cp, from, to);
} else
CL_PAGE_HEADER(D_PAGE, env, pg, "uptodate\n");
- RETURN(result);
+ return result;
}
static int vvp_io_commit_write(const struct lu_env *env,
@@ -963,12 +955,10 @@ static int vvp_io_commit_write(const struct lu_env *env,
int tallyop;
loff_t size;
- ENTRY;
-
LINVRNT(cl_page_is_vmlocked(env, pg));
LASSERT(vmpage->mapping->host == inode);
- LU_OBJECT_HEADER(D_INODE, env, &obj->co_lu, "commiting page write\n");
+ LU_OBJECT_HEADER(D_INODE, env, &obj->co_lu, "committing page write\n");
CL_PAGE_HEADER(D_PAGE, env, pg, "committing: [%d, %d]\n", from, to);
/*
@@ -1067,7 +1057,7 @@ static int vvp_io_commit_write(const struct lu_env *env,
cl_page_discard(env, io, pg);
}
ll_inode_size_unlock(inode);
- RETURN(result);
+ return result;
}
static const struct cl_io_operations vvp_io_ops = {
@@ -1120,7 +1110,6 @@ int vvp_io_init(const struct lu_env *env, struct cl_object *obj,
int result;
CLOBINVRNT(env, obj, ccc_object_invariant(obj));
- ENTRY;
CL_IO_SLICE_CLEAN(cio, cui_cl);
cl_io_slice_add(io, &cio->cui_cl, obj, &vvp_io_ops);
@@ -1174,7 +1163,7 @@ int vvp_io_init(const struct lu_env *env, struct cl_object *obj,
PFID(lu_object_fid(&obj->co_lu)), result);
}
- RETURN(result);
+ return result;
}
static struct vvp_io *cl2vvp_io(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/llite/vvp_lock.c b/drivers/staging/lustre/lustre/llite/vvp_lock.c
index 9b8712bccd9..e16b31e4ff7 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_lock.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_lock.c
@@ -63,8 +63,7 @@ static unsigned long vvp_lock_weigh(const struct lu_env *env,
{
struct ccc_object *cob = cl2ccc(slice->cls_obj);
- ENTRY;
- RETURN(atomic_read(&cob->cob_mmap_cnt) > 0 ? ~0UL >> 2 : 0);
+ return atomic_read(&cob->cob_mmap_cnt) > 0 ? ~0UL >> 2 : 0;
}
static const struct cl_lock_operations vvp_lock_ops = {
diff --git a/drivers/staging/lustre/lustre/llite/vvp_object.c b/drivers/staging/lustre/lustre/llite/vvp_object.c
index 01edc5b63e1..33173fce478 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_object.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_object.c
@@ -91,8 +91,8 @@ static int vvp_attr_get(const struct lu_env *env, struct cl_object *obj,
attr->cat_atime = LTIME_S(inode->i_atime);
attr->cat_ctime = LTIME_S(inode->i_ctime);
attr->cat_blocks = inode->i_blocks;
- attr->cat_uid = inode->i_uid;
- attr->cat_gid = inode->i_gid;
+ attr->cat_uid = from_kuid(&init_user_ns, inode->i_uid);
+ attr->cat_gid = from_kgid(&init_user_ns, inode->i_gid);
/* KMS is not known by this layer */
return 0; /* layers below have to fill in the rest */
}
@@ -103,9 +103,9 @@ static int vvp_attr_set(const struct lu_env *env, struct cl_object *obj,
struct inode *inode = ccc_object_inode(obj);
if (valid & CAT_UID)
- inode->i_uid = attr->cat_uid;
+ inode->i_uid = make_kuid(&init_user_ns, attr->cat_uid);
if (valid & CAT_GID)
- inode->i_gid = attr->cat_gid;
+ inode->i_gid = make_kgid(&init_user_ns, attr->cat_gid);
if (valid & CAT_ATIME)
LTIME_S(inode->i_atime) = attr->cat_atime;
if (valid & CAT_MTIME)
diff --git a/drivers/staging/lustre/lustre/llite/vvp_page.c b/drivers/staging/lustre/lustre/llite/vvp_page.c
index 4568e69bb9f..1c02c128e0e 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_page.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_page.c
@@ -218,9 +218,8 @@ static int vvp_page_prep_read(const struct lu_env *env,
const struct cl_page_slice *slice,
struct cl_io *unused)
{
- ENTRY;
/* Skip the page already marked as PG_uptodate. */
- RETURN(PageUptodate(cl2vm_page(slice)) ? -EALREADY : 0);
+ return PageUptodate(cl2vm_page(slice)) ? -EALREADY : 0;
}
static int vvp_page_prep_write(const struct lu_env *env,
@@ -274,7 +273,6 @@ static void vvp_page_completion_read(const struct lu_env *env,
struct page *vmpage = cp->cpg_page;
struct cl_page *page = cl_page_top(slice->cpl_page);
struct inode *inode = ccc_object_inode(page->cp_obj);
- ENTRY;
LASSERT(PageLocked(vmpage));
CL_PAGE_HEADER(D_PAGE, env, page, "completing READ with %d\n", ioret);
@@ -290,8 +288,6 @@ static void vvp_page_completion_read(const struct lu_env *env,
if (page->cp_sync_io == NULL)
unlock_page(vmpage);
-
- EXIT;
}
static void vvp_page_completion_write(const struct lu_env *env,
@@ -301,7 +297,6 @@ static void vvp_page_completion_write(const struct lu_env *env,
struct ccc_page *cp = cl2ccc_page(slice);
struct cl_page *pg = slice->cpl_page;
struct page *vmpage = cp->cpg_page;
- ENTRY;
LASSERT(ergo(pg->cp_sync_io != NULL, PageLocked(vmpage)));
LASSERT(PageWriteback(vmpage));
@@ -329,7 +324,6 @@ static void vvp_page_completion_write(const struct lu_env *env,
vvp_vmpage_error(ccc_object_inode(pg->cp_obj), vmpage, ioret);
end_page_writeback(vmpage);
- EXIT;
}
/**
@@ -372,7 +366,7 @@ static int vvp_page_make_ready(const struct lu_env *env,
LBUG();
}
unlock_page(vmpage);
- RETURN(result);
+ return result;
}
static int vvp_page_print(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c
index 4176264984b..bcf86bac30a 100644
--- a/drivers/staging/lustre/lustre/llite/xattr.c
+++ b/drivers/staging/lustre/lustre/llite/xattr.c
@@ -112,31 +112,32 @@ int ll_setxattr_common(struct inode *inode, const char *name,
struct ptlrpc_request *req;
int xattr_type, rc;
struct obd_capa *oc;
+#ifdef CONFIG_FS_POSIX_ACL
posix_acl_xattr_header *new_value = NULL;
struct rmtacl_ctl_entry *rce = NULL;
ext_acl_xattr_header *acl = NULL;
+#endif
const char *pv = value;
- ENTRY;
xattr_type = get_xattr_type(name);
rc = xattr_type_filter(sbi, xattr_type);
if (rc)
- RETURN(rc);
+ return rc;
/* b10667: ignore lustre special xattr for now */
if ((xattr_type == XATTR_TRUSTED_T && strcmp(name, "trusted.lov") == 0) ||
(xattr_type == XATTR_LUSTRE_T && strcmp(name, "lustre.lov") == 0))
- RETURN(0);
+ return 0;
/* b15587: ignore security.capability xattr for now */
if ((xattr_type == XATTR_SECURITY_T &&
strcmp(name, "security.capability") == 0))
- RETURN(0);
+ return 0;
/* LU-549: Disable security.selinux when selinux is disabled */
if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() &&
strcmp(name, "security.selinux") == 0)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
#ifdef CONFIG_FS_POSIX_ACL
if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
@@ -146,7 +147,7 @@ int ll_setxattr_common(struct inode *inode, const char *name,
if (rce == NULL ||
(rce->rce_ops != RMT_LSETFACL &&
rce->rce_ops != RMT_RSETFACL))
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
if (rce->rce_ops == RMT_LSETFACL) {
struct eacl_entry *ee;
@@ -160,7 +161,7 @@ int ll_setxattr_common(struct inode *inode, const char *name,
size, ee->ee_acl);
if (IS_ERR(acl)) {
ee_free(ee);
- RETURN(PTR_ERR(acl));
+ return PTR_ERR(acl);
}
size = CFS_ACL_XATTR_SIZE(\
le32_to_cpu(acl->a_count), \
@@ -173,11 +174,11 @@ int ll_setxattr_common(struct inode *inode, const char *name,
(posix_acl_xattr_header *)value,
size, &new_value);
if (unlikely(size < 0))
- RETURN(size);
+ return size;
pv = (const char *)new_value;
} else
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
valid |= rce_ops2valid(rce->rce_ops);
}
@@ -199,11 +200,11 @@ int ll_setxattr_common(struct inode *inode, const char *name,
"it is not supported on the server\n");
sbi->ll_flags &= ~LL_SBI_USER_XATTR;
}
- RETURN(rc);
+ return rc;
}
ptlrpc_req_finished(req);
- RETURN(0);
+ return 0;
}
int ll_setxattr(struct dentry *dentry, const char *name,
@@ -285,7 +286,6 @@ int ll_getxattr_common(struct inode *inode, const char *name,
void *xdata;
struct obd_capa *oc;
struct rmtacl_ctl_entry *rce = NULL;
- ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n",
inode->i_ino, inode->i_generation, inode);
@@ -302,17 +302,17 @@ int ll_getxattr_common(struct inode *inode, const char *name,
xattr_type = get_xattr_type(name);
rc = xattr_type_filter(sbi, xattr_type);
if (rc)
- RETURN(rc);
+ return rc;
/* b15587: ignore security.capability xattr for now */
if ((xattr_type == XATTR_SECURITY_T &&
strcmp(name, "security.capability") == 0))
- RETURN(-ENODATA);
+ return -ENODATA;
/* LU-549: Disable security.selinux when selinux is disabled */
if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() &&
strcmp(name, "security.selinux") == 0)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
#ifdef CONFIG_FS_POSIX_ACL
if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
@@ -324,7 +324,7 @@ int ll_getxattr_common(struct inode *inode, const char *name,
rce->rce_ops != RMT_LGETFACL &&
rce->rce_ops != RMT_RSETFACL &&
rce->rce_ops != RMT_RGETFACL))
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
}
/* posix acl is under protection of LOOKUP lock. when calling to this,
@@ -341,14 +341,14 @@ int ll_getxattr_common(struct inode *inode, const char *name,
spin_unlock(&lli->lli_lock);
if (!acl)
- RETURN(-ENODATA);
+ return -ENODATA;
rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
posix_acl_release(acl);
- RETURN(rc);
+ return rc;
}
if (xattr_type == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode))
- RETURN(-ENODATA);
+ return -ENODATA;
#endif
do_getxattr:
@@ -363,7 +363,7 @@ do_getxattr:
"it is not supported on the server\n");
sbi->ll_flags &= ~LL_SBI_USER_XATTR;
}
- RETURN(rc);
+ return rc;
}
body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
@@ -413,7 +413,6 @@ do_getxattr:
memcpy(buffer, xdata, body->eadatasize);
rc = body->eadatasize;
}
- EXIT;
out:
ptlrpc_req_finished(req);
return rc;
@@ -562,7 +561,12 @@ ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size)
const size_t name_len = sizeof("lov") - 1;
const size_t total_len = prefix_len + name_len + 1;
- if (buffer && (rc + total_len) <= size) {
+ if (((rc + total_len) > size) && (buffer != NULL)) {
+ ptlrpc_req_finished(request);
+ return -ERANGE;
+ }
+
+ if (buffer != NULL) {
buffer += rc;
memcpy(buffer, XATTR_LUSTRE_PREFIX, prefix_len);
memcpy(buffer + prefix_len, "lov", name_len);
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_fld.c b/drivers/staging/lustre/lustre/lmv/lmv_fld.c
index a4805aefa68..0b2d38d1362 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_fld.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_fld.c
@@ -38,7 +38,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/pagemap.h>
#include <asm/div64.h>
#include <linux/seq_file.h>
@@ -58,8 +57,6 @@ int lmv_fld_lookup(struct lmv_obd *lmv,
mdsno_t *mds)
{
int rc;
- ENTRY;
-
/* FIXME: Currently ZFS still use local seq for ROOT unfortunately, and
* this fid_is_local check should be removed once LU-2240 is fixed */
@@ -72,7 +69,7 @@ int lmv_fld_lookup(struct lmv_obd *lmv,
if (rc) {
CERROR("Error while looking for mds number. Seq "LPX64
", err = %d\n", fid_seq(fid), rc);
- RETURN(rc);
+ return rc;
}
CDEBUG(D_INODE, "FLD lookup got mds #%x for fid="DFID"\n",
@@ -84,5 +81,5 @@ int lmv_fld_lookup(struct lmv_obd *lmv,
PFID(fid));
rc = -EINVAL;
}
- RETURN(rc);
+ return rc;
}
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c
index 7eefab5ef5d..511b3b4b699 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c
@@ -38,7 +38,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/pagemap.h>
#include <asm/div64.h>
#include <linux/seq_file.h>
@@ -70,11 +69,10 @@ static int lmv_intent_remote(struct obd_export *exp, void *lmm,
struct mdt_body *body;
int pmode;
int rc = 0;
- ENTRY;
body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY);
if (body == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
LASSERT((body->valid & OBD_MD_MDS));
@@ -142,7 +140,6 @@ static int lmv_intent_remote(struct obd_export *exp, void *lmm,
it->d.lustre.it_lock_handle = plock.cookie;
it->d.lustre.it_lock_mode = pmode;
- EXIT;
out_free_op_data:
OBD_FREE_PTR(op_data);
out:
@@ -169,11 +166,10 @@ int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_tgt_desc *tgt;
struct mdt_body *body;
int rc;
- ENTRY;
tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
/* If it is ready to open the file by FID, do not need
* allocate FID at all, otherwise it will confuse MDT */
@@ -186,7 +182,7 @@ int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
op_data->op_fid3 = op_data->op_fid2;
rc = lmv_fid_alloc(exp, &op_data->op_fid2, op_data);
if (rc != 0)
- RETURN(rc);
+ return rc;
}
CDEBUG(D_INODE, "OPEN_INTENT with fid1="DFID", fid2="DFID","
@@ -196,7 +192,7 @@ int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
rc = md_intent_lock(tgt->ltd_exp, op_data, lmm, lmmsize, it, flags,
reqp, cb_blocking, extra_lock_flags);
if (rc != 0)
- RETURN(rc);
+ return rc;
/*
* Nothing is found, do not access body->fid1 as it is zero and thus
* pointless.
@@ -204,16 +200,16 @@ int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
if ((it->d.lustre.it_disposition & DISP_LOOKUP_NEG) &&
!(it->d.lustre.it_disposition & DISP_OPEN_CREATE) &&
!(it->d.lustre.it_disposition & DISP_OPEN_OPEN))
- RETURN(rc);
+ return rc;
body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY);
if (body == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
/*
* Not cross-ref case, just get out of here.
*/
if (likely(!(body->valid & OBD_MD_MDS)))
- RETURN(0);
+ return 0;
/*
* Okay, MDS has returned success. Probably name has been resolved in
@@ -233,10 +229,10 @@ int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
"%*s: %d\n", LL_IT2STR(it), PFID(&op_data->op_fid2),
PFID(&op_data->op_fid1), op_data->op_namelen,
op_data->op_name, rc);
- RETURN(rc);
+ return rc;
}
- RETURN(rc);
+ return rc;
}
/*
@@ -253,11 +249,10 @@ int lmv_intent_lookup(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_tgt_desc *tgt = NULL;
struct mdt_body *body;
int rc = 0;
- ENTRY;
tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
if (!fid_is_sane(&op_data->op_fid2))
fid_zero(&op_data->op_fid2);
@@ -274,7 +269,7 @@ int lmv_intent_lookup(struct obd_export *exp, struct md_op_data *op_data,
flags, reqp, cb_blocking, extra_lock_flags);
if (rc < 0 || *reqp == NULL)
- RETURN(rc);
+ return rc;
/*
* MDS has returned success. Probably name has been resolved in
@@ -282,15 +277,15 @@ int lmv_intent_lookup(struct obd_export *exp, struct md_op_data *op_data,
*/
body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY);
if (body == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
/* Not cross-ref case, just get out of here. */
if (likely(!(body->valid & OBD_MD_MDS)))
- RETURN(0);
+ return 0;
rc = lmv_intent_remote(exp, lmm, lmmsize, it, NULL, flags, reqp,
cb_blocking, extra_lock_flags);
- RETURN(rc);
+ return rc;
}
int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
@@ -301,7 +296,6 @@ int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
{
struct obd_device *obd = exp->exp_obd;
int rc;
- ENTRY;
LASSERT(it != NULL);
LASSERT(fid_is_sane(&op_data->op_fid1));
@@ -312,7 +306,7 @@ int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
if (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_LAYOUT))
rc = lmv_intent_lookup(exp, op_data, lmm, lmmsize, it,
@@ -324,5 +318,5 @@ int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
extra_lock_flags);
else
LBUG();
- RETURN(rc);
+ return rc;
}
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
index 1eebfbf3487..c2866046fc3 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
@@ -38,12 +38,12 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/mm.h>
#include <asm/div64.h>
#include <linux/seq_file.h>
#include <linux/namei.h>
+#include <asm/uaccess.h>
#include <lustre/lustre_idl.h>
#include <obd_support.h>
@@ -80,7 +80,6 @@ static int lmv_set_mdc_active(struct lmv_obd *lmv, struct obd_uuid *uuid,
struct obd_device *obd;
int i;
int rc = 0;
- ENTRY;
CDEBUG(D_INFO, "Searching in lmv %p for uuid %s (activate=%d)\n",
lmv, uuid->uuid, activate);
@@ -119,7 +118,6 @@ static int lmv_set_mdc_active(struct lmv_obd *lmv, struct obd_uuid *uuid,
CDEBUG(D_INFO, "Marking OBD %p %sactive\n", obd,
activate ? "" : "in");
lmv_activate_target(lmv, tgt, activate);
- EXIT;
out_lmv_lock:
spin_unlock(&lmv->lmv_lock);
@@ -140,13 +138,12 @@ static int lmv_notify(struct obd_device *obd, struct obd_device *watched,
struct lmv_obd *lmv = &obd->u.lmv;
struct obd_uuid *uuid;
int rc = 0;
- ENTRY;
if (strcmp(watched->obd_type->typ_name, LUSTRE_MDC_NAME)) {
CERROR("unexpected notification of %s %s!\n",
watched->obd_type->typ_name,
watched->obd_name);
- RETURN(-EINVAL);
+ return -EINVAL;
}
uuid = &watched->u.cli.cl_target_uuid;
@@ -161,7 +158,7 @@ static int lmv_notify(struct obd_device *obd, struct obd_device *watched,
CERROR("%sactivation of %s failed: %d\n",
ev == OBD_NOTIFY_ACTIVE ? "" : "de",
uuid->uuid, rc);
- RETURN(rc);
+ return rc;
}
} else if (ev == OBD_NOTIFY_OCD) {
conn_data = &watched->u.cli.cl_import->imp_connect_data;
@@ -186,7 +183,7 @@ static int lmv_notify(struct obd_device *obd, struct obd_device *watched,
if (obd->obd_observer)
rc = obd_notify(obd->obd_observer, watched, ev, data);
- RETURN(rc);
+ return rc;
}
/**
@@ -202,7 +199,6 @@ static int lmv_connect(const struct lu_env *env,
struct lmv_obd *lmv = &obd->u.lmv;
struct lustre_handle conn = { 0 };
int rc = 0;
- ENTRY;
/*
* We don't want to actually do the underlying connections more than
@@ -211,13 +207,13 @@ static int lmv_connect(const struct lu_env *env,
lmv->refcount++;
if (lmv->refcount > 1) {
*exp = NULL;
- RETURN(0);
+ return 0;
}
rc = class_connect(&conn, obd, cluuid);
if (rc) {
CERROR("class_connection() returned %d\n", rc);
- RETURN(rc);
+ return rc;
}
*exp = class_conn2export(&conn);
@@ -257,7 +253,7 @@ static int lmv_connect(const struct lu_env *env,
obd->obd_proc_private = NULL;
}
- RETURN(rc);
+ return rc;
}
static void lmv_set_timeouts(struct obd_device *obd)
@@ -291,7 +287,6 @@ static int lmv_init_ea_size(struct obd_export *exp, int easize,
int i;
int rc = 0;
int change = 0;
- ENTRY;
if (lmv->max_easize < easize) {
lmv->max_easize = easize;
@@ -306,10 +301,10 @@ static int lmv_init_ea_size(struct obd_export *exp, int easize,
change = 1;
}
if (change == 0)
- RETURN(0);
+ return 0;
if (lmv->connected == 0)
- RETURN(0);
+ return 0;
for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
if (lmv->tgts[i] == NULL ||
@@ -327,7 +322,7 @@ static int lmv_init_ea_size(struct obd_export *exp, int easize,
break;
}
}
- RETURN(rc);
+ return rc;
}
#define MAX_STRING_SIZE 128
@@ -342,13 +337,12 @@ int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
struct obd_export *mdc_exp;
struct lu_fld_target target;
int rc;
- ENTRY;
mdc_obd = class_find_client_obd(&tgt->ltd_uuid, LUSTRE_MDC_NAME,
&obd->obd_uuid);
if (!mdc_obd) {
CERROR("target %s not attached\n", tgt->ltd_uuid.uuid);
- RETURN(-EINVAL);
+ return -EINVAL;
}
CDEBUG(D_CONFIG, "connect to %s(%s) - %s, %s FOR %s\n",
@@ -358,14 +352,14 @@ int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
if (!mdc_obd->obd_set_up) {
CERROR("target %s is not set up\n", tgt->ltd_uuid.uuid);
- RETURN(-EINVAL);
+ return -EINVAL;
}
rc = obd_connect(NULL, &mdc_exp, mdc_obd, &lmv_mdc_uuid,
&lmv->conn_data, NULL);
if (rc) {
CERROR("target %s connect error %d\n", tgt->ltd_uuid.uuid, rc);
- RETURN(rc);
+ return rc;
}
/*
@@ -373,7 +367,7 @@ int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
*/
rc = obd_fid_init(mdc_obd, mdc_exp, LUSTRE_SEQ_METADATA);
if (rc)
- RETURN(rc);
+ return rc;
target.ft_srv = NULL;
target.ft_exp = mdc_exp;
@@ -386,7 +380,7 @@ int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
obd_disconnect(mdc_exp);
CERROR("target %s register_observer error %d\n",
tgt->ltd_uuid.uuid, rc);
- RETURN(rc);
+ return rc;
}
if (obd->obd_observer) {
@@ -398,7 +392,7 @@ int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
(void *)(tgt - lmv->tgts[0]));
if (rc) {
obd_disconnect(mdc_exp);
- RETURN(rc);
+ return rc;
}
}
@@ -433,7 +427,7 @@ int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
obd->obd_proc_private = NULL;
}
}
- RETURN(0);
+ return 0;
}
static void lmv_del_target(struct lmv_obd *lmv, int index)
@@ -452,7 +446,6 @@ static int lmv_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc = 0;
- ENTRY;
CDEBUG(D_CONFIG, "Target uuid: %s. index %d\n", uuidp->uuid, index);
@@ -467,7 +460,7 @@ static int lmv_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
lmv_init_unlock(lmv);
CERROR("%s: Target %s not attached: rc = %d\n",
obd->obd_name, uuidp->uuid, -EINVAL);
- RETURN(-EINVAL);
+ return -EINVAL;
}
}
@@ -477,7 +470,7 @@ static int lmv_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
" rc = %d\n", obd->obd_name,
obd_uuid2str(&tgt->ltd_uuid), index, -EEXIST);
lmv_init_unlock(lmv);
- RETURN(-EEXIST);
+ return -EEXIST;
}
if (index >= lmv->tgts_size) {
@@ -491,7 +484,7 @@ static int lmv_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
OBD_ALLOC(newtgts, sizeof(*newtgts) * newsize);
if (newtgts == NULL) {
lmv_init_unlock(lmv);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
if (lmv->tgts_size) {
@@ -514,7 +507,7 @@ static int lmv_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
OBD_ALLOC_PTR(tgt);
if (!tgt) {
lmv_init_unlock(lmv);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
mutex_init(&tgt->ltd_fid_mutex);
@@ -541,7 +534,7 @@ static int lmv_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
}
lmv_init_unlock(lmv);
- RETURN(rc);
+ return rc;
}
int lmv_check_connect(struct obd_device *obd)
@@ -551,21 +544,20 @@ int lmv_check_connect(struct obd_device *obd)
int i;
int rc;
int easize;
- ENTRY;
if (lmv->connected)
- RETURN(0);
+ return 0;
lmv_init_lock(lmv);
if (lmv->connected) {
lmv_init_unlock(lmv);
- RETURN(0);
+ return 0;
}
if (lmv->desc.ld_tgt_count == 0) {
lmv_init_unlock(lmv);
CERROR("%s: no targets configured.\n", obd->obd_name);
- RETURN(-EINVAL);
+ return -EINVAL;
}
CDEBUG(D_CONFIG, "Time to connect %s to %s\n",
@@ -588,7 +580,7 @@ int lmv_check_connect(struct obd_device *obd)
easize = lmv_get_easize(lmv);
lmv_init_ea_size(obd->obd_self_export, easize, 0, 0);
lmv_init_unlock(lmv);
- RETURN(0);
+ return 0;
out_disc:
while (i-- > 0) {
@@ -609,7 +601,7 @@ int lmv_check_connect(struct obd_device *obd)
}
class_disconnect(lmv->exp);
lmv_init_unlock(lmv);
- RETURN(rc);
+ return rc;
}
static int lmv_disconnect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
@@ -618,7 +610,6 @@ static int lmv_disconnect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
struct lmv_obd *lmv = &obd->u.lmv;
struct obd_device *mdc_obd;
int rc;
- ENTRY;
LASSERT(tgt != NULL);
LASSERT(obd != NULL);
@@ -654,7 +645,7 @@ static int lmv_disconnect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
lmv_activate_target(lmv, tgt, 0);
tgt->ltd_exp = NULL;
- RETURN(0);
+ return 0;
}
static int lmv_disconnect(struct obd_export *exp)
@@ -663,7 +654,6 @@ static int lmv_disconnect(struct obd_export *exp)
struct lmv_obd *lmv = &obd->u.lmv;
int rc;
int i;
- ENTRY;
if (!lmv->tgts)
goto out_local;
@@ -683,7 +673,7 @@ static int lmv_disconnect(struct obd_export *exp)
}
if (obd->obd_proc_private)
- lprocfs_remove((proc_dir_entry_t **)&obd->obd_proc_private);
+ lprocfs_remove((struct proc_dir_entry **)&obd->obd_proc_private);
else
CERROR("/proc/fs/lustre/%s/%s/target_obds missing\n",
obd->obd_type->typ_name, obd->obd_name);
@@ -698,7 +688,7 @@ out_local:
rc = class_disconnect(exp);
if (lmv->refcount == 0)
lmv->connected = 0;
- RETURN(rc);
+ return rc;
}
static int lmv_fid2path(struct obd_export *exp, int len, void *karg, void *uarg)
@@ -714,7 +704,7 @@ static int lmv_fid2path(struct obd_export *exp, int len, void *karg, void *uarg)
gf = (struct getinfo_fid2path *)karg;
tgt = lmv_find_target(lmv, &gf->gf_fid);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
repeat_fid2path:
rc = obd_iocontrol(OBD_IOC_FID2PATH, tgt->ltd_exp, len, gf, uarg);
@@ -780,9 +770,126 @@ repeat_fid2path:
out_fid2path:
if (remote_gf != NULL)
OBD_FREE(remote_gf, remote_gf_size);
- RETURN(rc);
+ return rc;
+}
+
+static int lmv_hsm_req_count(struct lmv_obd *lmv,
+ const struct hsm_user_request *hur,
+ const struct lmv_tgt_desc *tgt_mds)
+{
+ int i, nr = 0;
+ struct lmv_tgt_desc *curr_tgt;
+
+ /* count how many requests must be sent to the given target */
+ for (i = 0; i < hur->hur_request.hr_itemcount; i++) {
+ curr_tgt = lmv_find_target(lmv, &hur->hur_user_item[i].hui_fid);
+ if (obd_uuid_equals(&curr_tgt->ltd_uuid, &tgt_mds->ltd_uuid))
+ nr++;
+ }
+ return nr;
+}
+
+static void lmv_hsm_req_build(struct lmv_obd *lmv,
+ struct hsm_user_request *hur_in,
+ const struct lmv_tgt_desc *tgt_mds,
+ struct hsm_user_request *hur_out)
+{
+ int i, nr_out;
+ struct lmv_tgt_desc *curr_tgt;
+
+ /* build the hsm_user_request for the given target */
+ hur_out->hur_request = hur_in->hur_request;
+ nr_out = 0;
+ for (i = 0; i < hur_in->hur_request.hr_itemcount; i++) {
+ curr_tgt = lmv_find_target(lmv,
+ &hur_in->hur_user_item[i].hui_fid);
+ if (obd_uuid_equals(&curr_tgt->ltd_uuid, &tgt_mds->ltd_uuid)) {
+ hur_out->hur_user_item[nr_out] =
+ hur_in->hur_user_item[i];
+ nr_out++;
+ }
+ }
+ hur_out->hur_request.hr_itemcount = nr_out;
+ memcpy(hur_data(hur_out), hur_data(hur_in),
+ hur_in->hur_request.hr_data_len);
+}
+
+static int lmv_hsm_ct_unregister(struct lmv_obd *lmv, unsigned int cmd, int len,
+ struct lustre_kernelcomm *lk, void *uarg)
+{
+ int i, rc = 0;
+
+ /* unregister request (call from llapi_hsm_copytool_fini) */
+ for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
+ /* best effort: try to clean as much as possible
+ * (continue on error) */
+ obd_iocontrol(cmd, lmv->tgts[i]->ltd_exp, len, lk, uarg);
+ }
+
+ /* Whatever the result, remove copytool from kuc groups.
+ * Unreached coordinators will get EPIPE on next requests
+ * and will unregister automatically.
+ */
+ rc = libcfs_kkuc_group_rem(lk->lk_uid, lk->lk_group);
+ return rc;
}
+static int lmv_hsm_ct_register(struct lmv_obd *lmv, unsigned int cmd, int len,
+ struct lustre_kernelcomm *lk, void *uarg)
+{
+ struct file *filp;
+ int i, j, err;
+ int rc = 0;
+ bool any_set = false;
+
+ /* All or nothing: try to register to all MDS.
+ * In case of failure, unregister from previous MDS,
+ * except if it because of inactive target. */
+ for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
+ err = obd_iocontrol(cmd, lmv->tgts[i]->ltd_exp,
+ len, lk, uarg);
+ if (err) {
+ if (lmv->tgts[i]->ltd_active) {
+ /* permanent error */
+ CERROR("error: iocontrol MDC %s on MDT"
+ "idx %d cmd %x: err = %d\n",
+ lmv->tgts[i]->ltd_uuid.uuid,
+ i, cmd, err);
+ rc = err;
+ lk->lk_flags |= LK_FLG_STOP;
+ /* unregister from previous MDS */
+ for (j = 0; j < i; j++)
+ obd_iocontrol(cmd,
+ lmv->tgts[j]->ltd_exp,
+ len, lk, uarg);
+ return rc;
+ }
+ /* else: transient error.
+ * kuc will register to the missing MDT
+ * when it is back */
+ } else {
+ any_set = true;
+ }
+ }
+
+ if (!any_set)
+ /* no registration done: return error */
+ return -ENOTCONN;
+
+ /* at least one registration done, with no failure */
+ filp = fget(lk->lk_wfd);
+ if (filp == NULL) {
+ return -EBADF;
+ }
+ rc = libcfs_kkuc_group_add(filp, lk->lk_uid, lk->lk_group, lk->lk_data);
+ if (rc != 0 && filp != NULL)
+ fput(filp);
+ return rc;
+}
+
+
+
+
static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
int len, void *karg, void *uarg)
{
@@ -792,10 +899,9 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
int rc = 0;
int set = 0;
int count = lmv->desc.ld_tgt_count;
- ENTRY;
if (count == 0)
- RETURN(-ENOTTY);
+ return -ENOTTY;
switch (cmd) {
case IOC_OBD_STATFS: {
@@ -806,31 +912,31 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
memcpy(&index, data->ioc_inlbuf2, sizeof(__u32));
if ((index >= count))
- RETURN(-ENODEV);
+ return -ENODEV;
if (lmv->tgts[index] == NULL ||
lmv->tgts[index]->ltd_active == 0)
- RETURN(-ENODATA);
+ return -ENODATA;
mdc_obd = class_exp2obd(lmv->tgts[index]->ltd_exp);
if (!mdc_obd)
- RETURN(-EINVAL);
+ return -EINVAL;
/* copy UUID */
if (copy_to_user(data->ioc_pbuf2, obd2cli_tgt(mdc_obd),
min((int) data->ioc_plen2,
(int) sizeof(struct obd_uuid))))
- RETURN(-EFAULT);
+ return -EFAULT;
rc = obd_statfs(NULL, lmv->tgts[index]->ltd_exp, &stat_buf,
cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
0);
if (rc)
- RETURN(rc);
+ return rc;
if (copy_to_user(data->ioc_pbuf1, &stat_buf,
min((int) data->ioc_plen1,
(int) sizeof(stat_buf))))
- RETURN(-EFAULT);
+ return -EFAULT;
break;
}
case OBD_IOC_QUOTACTL: {
@@ -840,11 +946,11 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
if (qctl->qc_valid == QC_MDTIDX) {
if (qctl->qc_idx < 0 || count <= qctl->qc_idx)
- RETURN(-EINVAL);
+ return -EINVAL;
tgt = lmv->tgts[qctl->qc_idx];
if (tgt == NULL || tgt->ltd_exp == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
} else if (qctl->qc_valid == QC_UUID) {
for (i = 0; i < count; i++) {
tgt = lmv->tgts[i];
@@ -855,21 +961,21 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
continue;
if (tgt->ltd_exp == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
break;
}
} else {
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (i >= count)
- RETURN(-EAGAIN);
+ return -EAGAIN;
LASSERT(tgt && tgt->ltd_exp);
OBD_ALLOC_PTR(oqctl);
if (!oqctl)
- RETURN(-ENOMEM);
+ return -ENOMEM;
QCTL_COPY(oqctl, qctl);
rc = obd_quotactl(tgt->ltd_exp, oqctl);
@@ -886,19 +992,19 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
struct ioc_changelog *icc = karg;
if (icc->icc_mdtindex >= count)
- RETURN(-ENODEV);
+ return -ENODEV;
if (lmv->tgts[icc->icc_mdtindex] == NULL ||
lmv->tgts[icc->icc_mdtindex]->ltd_exp == NULL ||
lmv->tgts[icc->icc_mdtindex]->ltd_active == 0)
- RETURN(-ENODEV);
+ return -ENODEV;
rc = obd_iocontrol(cmd, lmv->tgts[icc->icc_mdtindex]->ltd_exp,
sizeof(*icc), icc, NULL);
break;
}
case LL_IOC_GET_CONNECT_FLAGS: {
if (lmv->tgts[0] == NULL)
- RETURN(-ENODATA);
+ return -ENODATA;
rc = obd_iocontrol(cmd, lmv->tgts[0]->ltd_exp, len, karg, uarg);
break;
}
@@ -908,29 +1014,107 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
}
case LL_IOC_HSM_STATE_GET:
case LL_IOC_HSM_STATE_SET:
- case LL_IOC_HSM_ACTION:
+ case LL_IOC_HSM_ACTION: {
+ struct md_op_data *op_data = karg;
+ struct lmv_tgt_desc *tgt;
+
+ tgt = lmv_find_target(lmv, &op_data->op_fid1);
+ if (IS_ERR(tgt))
+ return PTR_ERR(tgt);
+
+ if (tgt->ltd_exp == NULL)
+ return -EINVAL;
+
+ rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg);
+ break;
+ }
+ case LL_IOC_HSM_PROGRESS: {
+ const struct hsm_progress_kernel *hpk = karg;
+ struct lmv_tgt_desc *tgt;
+
+ tgt = lmv_find_target(lmv, &hpk->hpk_fid);
+ if (IS_ERR(tgt))
+ return PTR_ERR(tgt);
+ rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg);
+ break;
+ }
+ case LL_IOC_HSM_REQUEST: {
+ struct hsm_user_request *hur = karg;
+ struct lmv_tgt_desc *tgt;
+ unsigned int reqcount = hur->hur_request.hr_itemcount;
+
+ if (reqcount == 0)
+ return 0;
+
+ /* if the request is about a single fid
+ * or if there is a single MDS, no need to split
+ * the request. */
+ if (reqcount == 1 || count == 1) {
+ tgt = lmv_find_target(lmv,
+ &hur->hur_user_item[0].hui_fid);
+ if (IS_ERR(tgt))
+ return PTR_ERR(tgt);
+ rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg);
+ } else {
+ /* split fid list to their respective MDS */
+ for (i = 0; i < count; i++) {
+ unsigned int nr, reqlen;
+ int rc1;
+ struct hsm_user_request *req;
+
+ nr = lmv_hsm_req_count(lmv, hur, lmv->tgts[i]);
+ if (nr == 0) /* nothing for this MDS */
+ continue;
+
+ /* build a request with fids for this MDS */
+ reqlen = offsetof(typeof(*hur),
+ hur_user_item[nr])
+ + hur->hur_request.hr_data_len;
+ OBD_ALLOC_LARGE(req, reqlen);
+ if (req == NULL)
+ return -ENOMEM;
+
+ lmv_hsm_req_build(lmv, hur, lmv->tgts[i], req);
+
+ rc1 = obd_iocontrol(cmd, lmv->tgts[i]->ltd_exp,
+ reqlen, req, uarg);
+ if (rc1 != 0 && rc == 0)
+ rc = rc1;
+ OBD_FREE_LARGE(req, reqlen);
+ }
+ }
+ break;
+ }
case LL_IOC_LOV_SWAP_LAYOUTS: {
struct md_op_data *op_data = karg;
struct lmv_tgt_desc *tgt1, *tgt2;
tgt1 = lmv_find_target(lmv, &op_data->op_fid1);
if (IS_ERR(tgt1))
- RETURN(PTR_ERR(tgt1));
+ return PTR_ERR(tgt1);
tgt2 = lmv_find_target(lmv, &op_data->op_fid2);
if (IS_ERR(tgt2))
- RETURN(PTR_ERR(tgt2));
+ return PTR_ERR(tgt2);
if ((tgt1->ltd_exp == NULL) || (tgt2->ltd_exp == NULL))
- RETURN(-EINVAL);
+ return -EINVAL;
/* only files on same MDT can have their layouts swapped */
if (tgt1->ltd_idx != tgt2->ltd_idx)
- RETURN(-EPERM);
+ return -EPERM;
rc = obd_iocontrol(cmd, tgt1->ltd_exp, len, karg, uarg);
break;
}
+ case LL_IOC_HSM_CT_START: {
+ struct lustre_kernelcomm *lk = karg;
+ if (lk->lk_flags & LK_FLG_STOP)
+ rc = lmv_hsm_ct_unregister(lmv, cmd, len, lk, uarg);
+ else
+ rc = lmv_hsm_ct_register(lmv, cmd, len, lk, uarg);
+ break;
+ }
default:
for (i = 0; i < count; i++) {
struct obd_device *mdc_obd;
@@ -946,7 +1130,7 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
err = obd_iocontrol(cmd, lmv->tgts[i]->ltd_exp, len,
karg, uarg);
if (err == -ENODATA && cmd == OBD_IOC_POLL_QUOTACHECK) {
- RETURN(err);
+ return err;
} else if (err) {
if (lmv->tgts[i]->ltd_active) {
CERROR("error: iocontrol MDC %s on MDT"
@@ -962,7 +1146,7 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
if (!set && !rc)
rc = -EIO;
}
- RETURN(rc);
+ return rc;
}
#if 0
@@ -1018,13 +1202,12 @@ static int lmv_placement_policy(struct obd_device *obd,
mdsno_t *mds)
{
struct lmv_obd *lmv = &obd->u.lmv;
- ENTRY;
LASSERT(mds != NULL);
if (lmv->desc.ld_tgt_count == 1) {
*mds = 0;
- RETURN(0);
+ return 0;
}
/**
@@ -1042,17 +1225,17 @@ static int lmv_placement_policy(struct obd_device *obd,
" rc = %d\n", obd->obd_name,
lum->lum_stripe_offset,
lmv->desc.ld_tgt_count, -ERANGE);
- RETURN(-ERANGE);
+ return -ERANGE;
}
*mds = lum->lum_stripe_offset;
- RETURN(0);
+ return 0;
}
}
/* Allocate new fid on target according to operation type and parent
* home mds. */
*mds = op_data->op_mds;
- RETURN(0);
+ return 0;
}
int __lmv_fid_alloc(struct lmv_obd *lmv, struct lu_fid *fid,
@@ -1060,11 +1243,10 @@ int __lmv_fid_alloc(struct lmv_obd *lmv, struct lu_fid *fid,
{
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
tgt = lmv_get_target(lmv, mds);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
/*
* New seq alloc and FLD setup should be atomic. Otherwise we may find
@@ -1084,7 +1266,6 @@ int __lmv_fid_alloc(struct lmv_obd *lmv, struct lu_fid *fid,
rc = 0;
}
- EXIT;
out:
mutex_unlock(&tgt->ltd_fid_mutex);
return rc;
@@ -1097,7 +1278,6 @@ int lmv_fid_alloc(struct obd_export *exp, struct lu_fid *fid,
struct lmv_obd *lmv = &obd->u.lmv;
mdsno_t mds = 0;
int rc;
- ENTRY;
LASSERT(op_data != NULL);
LASSERT(fid != NULL);
@@ -1106,16 +1286,16 @@ int lmv_fid_alloc(struct obd_export *exp, struct lu_fid *fid,
if (rc) {
CERROR("Can't get target for allocating fid, "
"rc %d\n", rc);
- RETURN(rc);
+ return rc;
}
rc = __lmv_fid_alloc(lmv, fid, mds);
if (rc) {
CERROR("Can't alloc new fid, rc %d\n", rc);
- RETURN(rc);
+ return rc;
}
- RETURN(rc);
+ return rc;
}
static int lmv_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
@@ -1124,23 +1304,22 @@ static int lmv_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
struct lprocfs_static_vars lvars;
struct lmv_desc *desc;
int rc;
- ENTRY;
if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1) {
CERROR("LMV setup requires a descriptor\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
desc = (struct lmv_desc *)lustre_cfg_buf(lcfg, 1);
if (sizeof(*desc) > LUSTRE_CFG_BUFLEN(lcfg, 1)) {
CERROR("Lmv descriptor size wrong: %d > %d\n",
(int)sizeof(*desc), LUSTRE_CFG_BUFLEN(lcfg, 1));
- RETURN(-EINVAL);
+ return -EINVAL;
}
OBD_ALLOC(lmv->tgts, sizeof(*lmv->tgts) * 32);
if (lmv->tgts == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lmv->tgts_size = 32;
obd_str2uuid(&lmv->desc.ld_uuid, desc->ld_uuid.uuid);
@@ -1173,7 +1352,7 @@ static int lmv_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
GOTO(out, rc);
}
- RETURN(0);
+ return 0;
out:
return rc;
@@ -1182,7 +1361,6 @@ out:
static int lmv_cleanup(struct obd_device *obd)
{
struct lmv_obd *lmv = &obd->u.lmv;
- ENTRY;
fld_client_fini(&lmv->lmv_fld);
if (lmv->tgts != NULL) {
@@ -1195,7 +1373,7 @@ static int lmv_cleanup(struct obd_device *obd)
OBD_FREE(lmv->tgts, sizeof(*lmv->tgts) * lmv->tgts_size);
lmv->tgts_size = 0;
}
- RETURN(0);
+ return 0;
}
static int lmv_process_config(struct obd_device *obd, obd_count len, void *buf)
@@ -1205,7 +1383,6 @@ static int lmv_process_config(struct obd_device *obd, obd_count len, void *buf)
int gen;
__u32 index;
int rc;
- ENTRY;
switch (lcfg->lcfg_command) {
case LCFG_ADD_MDC:
@@ -1227,7 +1404,7 @@ static int lmv_process_config(struct obd_device *obd, obd_count len, void *buf)
GOTO(out, rc = -EINVAL);
}
out:
- RETURN(rc);
+ return rc;
}
static int lmv_statfs(const struct lu_env *env, struct obd_export *exp,
@@ -1238,15 +1415,14 @@ static int lmv_statfs(const struct lu_env *env, struct obd_export *exp,
struct obd_statfs *temp;
int rc = 0;
int i;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
OBD_ALLOC(temp, sizeof(*temp));
if (temp == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
if (lmv->tgts[i] == NULL || lmv->tgts[i]->ltd_exp == NULL)
@@ -1279,7 +1455,6 @@ static int lmv_statfs(const struct lu_env *env, struct obd_export *exp,
}
}
- EXIT;
out_free_temp:
OBD_FREE(temp, sizeof(*temp));
return rc;
@@ -1292,14 +1467,13 @@ static int lmv_getstatus(struct obd_export *exp,
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
rc = md_getstatus(lmv->tgts[0]->ltd_exp, fid, pc);
- RETURN(rc);
+ return rc;
}
static int lmv_getxattr(struct obd_export *exp, const struct lu_fid *fid,
@@ -1311,20 +1485,19 @@ static int lmv_getxattr(struct obd_export *exp, const struct lu_fid *fid,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_find_target(lmv, fid);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = md_getxattr(tgt->ltd_exp, fid, oc, valid, name, input,
input_size, output_size, flags, request);
- RETURN(rc);
+ return rc;
}
static int lmv_setxattr(struct obd_export *exp, const struct lu_fid *fid,
@@ -1337,21 +1510,20 @@ static int lmv_setxattr(struct obd_export *exp, const struct lu_fid *fid,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_find_target(lmv, fid);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = md_setxattr(tgt->ltd_exp, fid, oc, valid, name, input,
input_size, output_size, flags, suppgid,
request);
- RETURN(rc);
+ return rc;
}
static int lmv_getattr(struct obd_export *exp, struct md_op_data *op_data,
@@ -1361,24 +1533,23 @@ static int lmv_getattr(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_find_target(lmv, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
if (op_data->op_flags & MF_GET_MDT_IDX) {
op_data->op_mds = tgt->ltd_idx;
- RETURN(0);
+ return 0;
}
rc = md_getattr(tgt->ltd_exp, op_data, request);
- RETURN(rc);
+ return rc;
}
static int lmv_null_inode(struct obd_export *exp, const struct lu_fid *fid)
@@ -1387,11 +1558,10 @@ static int lmv_null_inode(struct obd_export *exp, const struct lu_fid *fid)
struct lmv_obd *lmv = &obd->u.lmv;
int i;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_INODE, "CBDATA for "DFID"\n", PFID(fid));
@@ -1406,7 +1576,7 @@ static int lmv_null_inode(struct obd_export *exp, const struct lu_fid *fid)
md_null_inode(lmv->tgts[i]->ltd_exp, fid);
}
- RETURN(0);
+ return 0;
}
static int lmv_find_cbdata(struct obd_export *exp, const struct lu_fid *fid,
@@ -1416,11 +1586,10 @@ static int lmv_find_cbdata(struct obd_export *exp, const struct lu_fid *fid,
struct lmv_obd *lmv = &obd->u.lmv;
int i;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_INODE, "CBDATA for "DFID"\n", PFID(fid));
@@ -1434,10 +1603,10 @@ static int lmv_find_cbdata(struct obd_export *exp, const struct lu_fid *fid,
continue;
rc = md_find_cbdata(lmv->tgts[i]->ltd_exp, fid, it, data);
if (rc)
- RETURN(rc);
+ return rc;
}
- RETURN(rc);
+ return rc;
}
@@ -1448,19 +1617,18 @@ static int lmv_close(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_find_target(lmv, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
CDEBUG(D_INODE, "CLOSE "DFID"\n", PFID(&op_data->op_fid1));
rc = md_close(tgt->ltd_exp, op_data, mod, request);
- RETURN(rc);
+ return rc;
}
struct lmv_tgt_desc
@@ -1487,22 +1655,21 @@ int lmv_create(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
if (!lmv->desc.ld_active_tgt_count)
- RETURN(-EIO);
+ return -EIO;
tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = lmv_fid_alloc(exp, &op_data->op_fid2, op_data);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_INODE, "CREATE '%*s' on "DFID" -> mds #%x\n",
op_data->op_namelen, op_data->op_name, PFID(&op_data->op_fid1),
@@ -1514,10 +1681,10 @@ int lmv_create(struct obd_export *exp, struct md_op_data *op_data,
if (rc == 0) {
if (*request == NULL)
- RETURN(rc);
+ return rc;
CDEBUG(D_INODE, "Created - "DFID"\n", PFID(&op_data->op_fid2));
}
- RETURN(rc);
+ return rc;
}
static int lmv_done_writing(struct obd_export *exp,
@@ -1528,18 +1695,17 @@ static int lmv_done_writing(struct obd_export *exp,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_find_target(lmv, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = md_done_writing(tgt->ltd_exp, op_data, mod);
- RETURN(rc);
+ return rc;
}
static int
@@ -1558,13 +1724,12 @@ lmv_enqueue_remote(struct obd_export *exp, struct ldlm_enqueue_info *einfo,
struct mdt_body *body;
int rc = 0;
int pmode;
- ENTRY;
body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
LASSERT(body != NULL);
if (!(body->valid & OBD_MD_MDS))
- RETURN(0);
+ return 0;
CDEBUG(D_INODE, "REMOTE_ENQUEUE '%s' on "DFID" -> "DFID"\n",
LL_IT2STR(it), PFID(&op_data->op_fid1), PFID(&body->fid1));
@@ -1596,7 +1761,6 @@ lmv_enqueue_remote(struct obd_export *exp, struct ldlm_enqueue_info *einfo,
rc = md_enqueue(tgt->ltd_exp, einfo, it, rdata, lockh,
lmm, lmmsize, NULL, extra_lock_flags);
OBD_FREE_PTR(rdata);
- EXIT;
out:
ldlm_lock_decref(&plock, pmode);
return rc;
@@ -1612,18 +1776,17 @@ lmv_enqueue(struct obd_export *exp, struct ldlm_enqueue_info *einfo,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_INODE, "ENQUEUE '%s' on "DFID"\n",
LL_IT2STR(it), PFID(&op_data->op_fid1));
tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
CDEBUG(D_INODE, "ENQUEUE '%s' on "DFID" -> mds #%d\n",
LL_IT2STR(it), PFID(&op_data->op_fid1), tgt->ltd_idx);
@@ -1635,7 +1798,7 @@ lmv_enqueue(struct obd_export *exp, struct ldlm_enqueue_info *einfo,
rc = lmv_enqueue_remote(exp, einfo, it, op_data, lockh,
lmm, lmmsize, extra_lock_flags);
}
- RETURN(rc);
+ return rc;
}
static int
@@ -1648,15 +1811,14 @@ lmv_getattr_name(struct obd_export *exp,struct md_op_data *op_data,
struct lmv_tgt_desc *tgt;
struct mdt_body *body;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
CDEBUG(D_INODE, "GETATTR_NAME for %*s on "DFID" -> mds #%d\n",
op_data->op_namelen, op_data->op_name, PFID(&op_data->op_fid1),
@@ -1664,7 +1826,7 @@ lmv_getattr_name(struct obd_export *exp,struct md_op_data *op_data,
rc = md_getattr_name(tgt->ltd_exp, op_data, request);
if (rc != 0)
- RETURN(rc);
+ return rc;
body = req_capsule_server_get(&(*request)->rq_pill,
&RMF_MDT_BODY);
@@ -1678,7 +1840,7 @@ lmv_getattr_name(struct obd_export *exp,struct md_op_data *op_data,
tgt = lmv_find_target(lmv, &rid);
if (IS_ERR(tgt)) {
ptlrpc_req_finished(*request);
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
}
op_data->op_fid1 = rid;
@@ -1690,7 +1852,7 @@ lmv_getattr_name(struct obd_export *exp,struct md_op_data *op_data,
*request = req;
}
- RETURN(rc);
+ return rc;
}
#define md_op_data_fid(op_data, fl) \
@@ -1709,14 +1871,13 @@ static int lmv_early_cancel(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_tgt_desc *tgt;
ldlm_policy_data_t policy = {{0}};
int rc = 0;
- ENTRY;
if (!fid_is_sane(fid))
- RETURN(0);
+ return 0;
tgt = lmv_find_target(lmv, fid);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
if (tgt->ltd_idx != op_tgt) {
CDEBUG(D_INODE, "EARLY_CANCEL on "DFID"\n", PFID(fid));
@@ -1731,7 +1892,7 @@ static int lmv_early_cancel(struct obd_export *exp, struct md_op_data *op_data,
rc = 0;
}
- RETURN(rc);
+ return rc;
}
/*
@@ -1745,11 +1906,10 @@ static int lmv_link(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
LASSERT(op_data->op_namelen != 0);
@@ -1757,12 +1917,12 @@ static int lmv_link(struct obd_export *exp, struct md_op_data *op_data,
PFID(&op_data->op_fid2), op_data->op_namelen,
op_data->op_name, PFID(&op_data->op_fid1));
- op_data->op_fsuid = current_fsuid();
- op_data->op_fsgid = current_fsgid();
+ op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid());
+ op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid());
op_data->op_cap = cfs_curproc_cap_pack();
tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid2);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
/*
* Cancel UPDATE lock on child (fid1).
@@ -1771,11 +1931,11 @@ static int lmv_link(struct obd_export *exp, struct md_op_data *op_data,
rc = lmv_early_cancel(exp, op_data, tgt->ltd_idx, LCK_EX,
MDS_INODELOCK_UPDATE, MF_MDC_CANCEL_FID1);
if (rc != 0)
- RETURN(rc);
+ return rc;
rc = md_link(tgt->ltd_exp, op_data, request);
- RETURN(rc);
+ return rc;
}
static int lmv_rename(struct obd_export *exp, struct md_op_data *op_data,
@@ -1787,7 +1947,6 @@ static int lmv_rename(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_tgt_desc *src_tgt;
struct lmv_tgt_desc *tgt_tgt;
int rc;
- ENTRY;
LASSERT(oldlen != 0);
@@ -1797,18 +1956,18 @@ static int lmv_rename(struct obd_export *exp, struct md_op_data *op_data,
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
- op_data->op_fsuid = current_fsuid();
- op_data->op_fsgid = current_fsgid();
+ op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid());
+ op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid());
op_data->op_cap = cfs_curproc_cap_pack();
src_tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
if (IS_ERR(src_tgt))
- RETURN(PTR_ERR(src_tgt));
+ return PTR_ERR(src_tgt);
tgt_tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid2);
if (IS_ERR(tgt_tgt))
- RETURN(PTR_ERR(tgt_tgt));
+ return PTR_ERR(tgt_tgt);
/*
* LOOKUP lock on src child (fid3) should also be cancelled for
* src_tgt in mdc_rename.
@@ -1843,7 +2002,7 @@ static int lmv_rename(struct obd_export *exp, struct md_op_data *op_data,
if (rc == 0)
rc = md_rename(src_tgt->ltd_exp, op_data, old, oldlen,
new, newlen, request);
- RETURN(rc);
+ return rc;
}
static int lmv_setattr(struct obd_export *exp, struct md_op_data *op_data,
@@ -1855,11 +2014,10 @@ static int lmv_setattr(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc = 0;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_INODE, "SETATTR for "DFID", valid 0x%x\n",
PFID(&op_data->op_fid1), op_data->op_attr.ia_valid);
@@ -1867,12 +2025,12 @@ static int lmv_setattr(struct obd_export *exp, struct md_op_data *op_data,
op_data->op_flags |= MF_MDC_CANCEL_FID1;
tgt = lmv_find_target(lmv, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = md_setattr(tgt->ltd_exp, op_data, ea, ealen, ea2,
ea2len, request, mod);
- RETURN(rc);
+ return rc;
}
static int lmv_sync(struct obd_export *exp, const struct lu_fid *fid,
@@ -1882,18 +2040,17 @@ static int lmv_sync(struct obd_export *exp, const struct lu_fid *fid,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_find_target(lmv, fid);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = md_sync(tgt->ltd_exp, fid, oc, request);
- RETURN(rc);
+ return rc;
}
/*
@@ -1959,7 +2116,7 @@ static void lmv_adjust_dirpages(struct page **pages, int ncfspgs, int nlupgs)
__u64 hash_end = dp->ldp_hash_end;
__u32 flags = dp->ldp_flags;
- for (; nlupgs > 1; nlupgs--) {
+ while (--nlupgs > 0) {
ent = lu_dirent_start(dp);
for (end_dirent = ent; ent != NULL;
end_dirent = ent, ent = lu_dirent_next(ent));
@@ -1993,6 +2150,7 @@ static void lmv_adjust_dirpages(struct page **pages, int ncfspgs, int nlupgs)
kunmap(pages[i]);
}
+ LASSERTF(nlupgs == 0, "left = %d", nlupgs);
}
#else
#define lmv_adjust_dirpages(pages, ncfspgs, nlupgs) do {} while (0)
@@ -2008,22 +2166,21 @@ static int lmv_readpage(struct obd_export *exp, struct md_op_data *op_data,
int ncfspgs; /* pages read in PAGE_CACHE_SIZE */
int nlupgs; /* pages read in LU_PAGE_SIZE */
struct lmv_tgt_desc *tgt;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_INODE, "READPAGE at "LPX64" from "DFID"\n",
offset, PFID(&op_data->op_fid1));
tgt = lmv_find_target(lmv, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = md_readpage(tgt->ltd_exp, op_data, pages, request);
if (rc != 0)
- RETURN(rc);
+ return rc;
ncfspgs = ((*request)->rq_bulk->bd_nob_transferred + PAGE_CACHE_SIZE - 1)
>> PAGE_CACHE_SHIFT;
@@ -2036,7 +2193,7 @@ static int lmv_readpage(struct obd_export *exp, struct md_op_data *op_data,
lmv_adjust_dirpages(pages, ncfspgs, nlupgs);
- RETURN(rc);
+ return rc;
}
static int lmv_unlink(struct obd_export *exp, struct md_op_data *op_data,
@@ -2047,11 +2204,10 @@ static int lmv_unlink(struct obd_export *exp, struct md_op_data *op_data,
struct lmv_tgt_desc *tgt = NULL;
struct mdt_body *body;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
retry:
/* Send unlink requests to the MDT where the child is located */
if (likely(!fid_is_zero(&op_data->op_fid2)))
@@ -2059,10 +2215,10 @@ retry:
else
tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
- op_data->op_fsuid = current_fsuid();
- op_data->op_fsgid = current_fsgid();
+ op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid());
+ op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid());
op_data->op_cap = cfs_curproc_cap_pack();
/*
@@ -2081,22 +2237,22 @@ retry:
MDS_INODELOCK_FULL, MF_MDC_CANCEL_FID3);
if (rc != 0)
- RETURN(rc);
+ return rc;
CDEBUG(D_INODE, "unlink with fid="DFID"/"DFID" -> mds #%d\n",
PFID(&op_data->op_fid1), PFID(&op_data->op_fid2), tgt->ltd_idx);
rc = md_unlink(tgt->ltd_exp, op_data, request);
if (rc != 0 && rc != -EREMOTE)
- RETURN(rc);
+ return rc;
body = req_capsule_server_get(&(*request)->rq_pill, &RMF_MDT_BODY);
if (body == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
/* Not cross-ref case, just get out of here. */
if (likely(!(body->valid & OBD_MD_MDS)))
- RETURN(0);
+ return 0;
CDEBUG(D_INODE, "%s: try unlink to another MDT for "DFID"\n",
exp->exp_obd->obd_name, PFID(&body->fid1));
@@ -2144,7 +2300,7 @@ static int lmv_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
default:
break;
}
- RETURN(rc);
+ return rc;
}
static int lmv_get_info(const struct lu_env *env, struct obd_export *exp,
@@ -2154,13 +2310,12 @@ static int lmv_get_info(const struct lu_env *env, struct obd_export *exp,
struct obd_device *obd;
struct lmv_obd *lmv;
int rc = 0;
- ENTRY;
obd = class_exp2obd(exp);
if (obd == NULL) {
CDEBUG(D_IOCTL, "Invalid client cookie "LPX64"\n",
exp->exp_handle.h_cookie);
- RETURN(-EINVAL);
+ return -EINVAL;
}
lmv = &obd->u.lmv;
@@ -2170,7 +2325,7 @@ static int lmv_get_info(const struct lu_env *env, struct obd_export *exp,
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
LASSERT(*vallen == sizeof(__u32));
for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
@@ -2183,13 +2338,13 @@ static int lmv_get_info(const struct lu_env *env, struct obd_export *exp,
if (!obd_get_info(env, tgt->ltd_exp, keylen, key,
vallen, val, NULL))
- RETURN(0);
+ return 0;
}
- RETURN(-EINVAL);
+ return -EINVAL;
} else if (KEY_IS(KEY_MAX_EASIZE) || KEY_IS(KEY_CONN_DATA)) {
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
/*
* Forwarding this request to first MDS, it should know LOV
@@ -2199,14 +2354,14 @@ static int lmv_get_info(const struct lu_env *env, struct obd_export *exp,
vallen, val, NULL);
if (!rc && KEY_IS(KEY_CONN_DATA))
exp->exp_connect_data = *(struct obd_connect_data *)val;
- RETURN(rc);
+ return rc;
} else if (KEY_IS(KEY_TGT_COUNT)) {
*((int *)val) = lmv->desc.ld_tgt_count;
- RETURN(0);
+ return 0;
}
CDEBUG(D_IOCTL, "Invalid key\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
int lmv_set_info_async(const struct lu_env *env, struct obd_export *exp,
@@ -2217,13 +2372,12 @@ int lmv_set_info_async(const struct lu_env *env, struct obd_export *exp,
struct obd_device *obd;
struct lmv_obd *lmv;
int rc = 0;
- ENTRY;
obd = class_exp2obd(exp);
if (obd == NULL) {
CDEBUG(D_IOCTL, "Invalid client cookie "LPX64"\n",
exp->exp_handle.h_cookie);
- RETURN(-EINVAL);
+ return -EINVAL;
}
lmv = &obd->u.lmv;
@@ -2242,10 +2396,10 @@ int lmv_set_info_async(const struct lu_env *env, struct obd_export *exp,
rc = err;
}
- RETURN(rc);
+ return rc;
}
- RETURN(-EINVAL);
+ return -EINVAL;
}
int lmv_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
@@ -2257,33 +2411,32 @@ int lmv_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
struct lmv_stripe_md *lsmp;
int mea_size;
int i;
- ENTRY;
mea_size = lmv_get_easize(lmv);
if (!lmmp)
- RETURN(mea_size);
+ return mea_size;
if (*lmmp && !lsm) {
OBD_FREE_LARGE(*lmmp, mea_size);
*lmmp = NULL;
- RETURN(0);
+ return 0;
}
if (*lmmp == NULL) {
OBD_ALLOC_LARGE(*lmmp, mea_size);
if (*lmmp == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
if (!lsm)
- RETURN(mea_size);
+ return mea_size;
lsmp = (struct lmv_stripe_md *)lsm;
meap = (struct lmv_stripe_md *)*lmmp;
if (lsmp->mea_magic != MEA_MAGIC_LAST_CHAR &&
lsmp->mea_magic != MEA_MAGIC_ALL_CHARS)
- RETURN(-EINVAL);
+ return -EINVAL;
meap->mea_magic = cpu_to_le32(lsmp->mea_magic);
meap->mea_count = cpu_to_le32(lsmp->mea_count);
@@ -2294,7 +2447,7 @@ int lmv_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
fid_cpu_to_le(&meap->mea_ids[i], &lsmp->mea_ids[i]);
}
- RETURN(mea_size);
+ return mea_size;
}
int lmv_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
@@ -2307,7 +2460,6 @@ int lmv_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
int mea_size;
int i;
__u32 magic;
- ENTRY;
mea_size = lmv_get_easize(lmv);
if (lsmp == NULL)
@@ -2316,17 +2468,17 @@ int lmv_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
if (*lsmp != NULL && lmm == NULL) {
OBD_FREE_LARGE(*tmea, mea_size);
*lsmp = NULL;
- RETURN(0);
+ return 0;
}
LASSERT(mea_size == lmm_size);
OBD_ALLOC_LARGE(*tmea, mea_size);
if (*tmea == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (!lmm)
- RETURN(mea_size);
+ return mea_size;
if (mea->mea_magic == MEA_MAGIC_LAST_CHAR ||
mea->mea_magic == MEA_MAGIC_ALL_CHARS ||
@@ -2349,7 +2501,7 @@ int lmv_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
(*tmea)->mea_ids[i] = mea->mea_ids[i];
fid_le_to_cpu(&(*tmea)->mea_ids[i], &(*tmea)->mea_ids[i]);
}
- RETURN(mea_size);
+ return mea_size;
}
static int lmv_cancel_unused(struct obd_export *exp, const struct lu_fid *fid,
@@ -2361,7 +2513,6 @@ static int lmv_cancel_unused(struct obd_export *exp, const struct lu_fid *fid,
int rc = 0;
int err;
int i;
- ENTRY;
LASSERT(fid != NULL);
@@ -2375,7 +2526,7 @@ static int lmv_cancel_unused(struct obd_export *exp, const struct lu_fid *fid,
if (!rc)
rc = err;
}
- RETURN(rc);
+ return rc;
}
int lmv_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
@@ -2383,10 +2534,9 @@ int lmv_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
{
struct lmv_obd *lmv = &exp->exp_obd->u.lmv;
int rc;
- ENTRY;
rc = md_set_lock_data(lmv->tgts[0]->ltd_exp, lockh, data, bits);
- RETURN(rc);
+ return rc;
}
ldlm_mode_t lmv_lock_match(struct obd_export *exp, __u64 flags,
@@ -2398,7 +2548,6 @@ ldlm_mode_t lmv_lock_match(struct obd_export *exp, __u64 flags,
struct lmv_obd *lmv = &obd->u.lmv;
ldlm_mode_t rc;
int i;
- ENTRY;
CDEBUG(D_INODE, "Lock match for "DFID"\n", PFID(fid));
@@ -2417,10 +2566,10 @@ ldlm_mode_t lmv_lock_match(struct obd_export *exp, __u64 flags,
rc = md_lock_match(lmv->tgts[i]->ltd_exp, flags, fid,
type, policy, mode, lockh);
if (rc)
- RETURN(rc);
+ return rc;
}
- RETURN(0);
+ return 0;
}
int lmv_get_lustre_md(struct obd_export *exp, struct ptlrpc_request *req,
@@ -2436,11 +2585,10 @@ int lmv_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
- ENTRY;
if (md->mea)
obd_free_memmd(exp, (void *)&md->mea);
- RETURN(md_free_lustre_md(lmv->tgts[0]->ltd_exp, md));
+ return md_free_lustre_md(lmv->tgts[0]->ltd_exp, md);
}
int lmv_set_open_replay_data(struct obd_export *exp,
@@ -2450,13 +2598,12 @@ int lmv_set_open_replay_data(struct obd_export *exp,
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
- ENTRY;
tgt = lmv_find_target(lmv, &och->och_fid);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
- RETURN(md_set_open_replay_data(tgt->ltd_exp, och, open_req));
+ return md_set_open_replay_data(tgt->ltd_exp, och, open_req);
}
int lmv_clear_open_replay_data(struct obd_export *exp,
@@ -2465,13 +2612,12 @@ int lmv_clear_open_replay_data(struct obd_export *exp,
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
- ENTRY;
tgt = lmv_find_target(lmv, &och->och_fid);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
- RETURN(md_clear_open_replay_data(tgt->ltd_exp, och));
+ return md_clear_open_replay_data(tgt->ltd_exp, och);
}
static int lmv_get_remote_perm(struct obd_export *exp,
@@ -2483,18 +2629,17 @@ static int lmv_get_remote_perm(struct obd_export *exp,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_find_target(lmv, fid);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = md_get_remote_perm(tgt->ltd_exp, fid, oc, suppgid, request);
- RETURN(rc);
+ return rc;
}
static int lmv_renew_capa(struct obd_export *exp, struct obd_capa *oc,
@@ -2504,18 +2649,17 @@ static int lmv_renew_capa(struct obd_export *exp, struct obd_capa *oc,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_find_target(lmv, &oc->c_capa.lc_fid);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = md_renew_capa(tgt->ltd_exp, oc, cb);
- RETURN(rc);
+ return rc;
}
int lmv_unpack_capa(struct obd_export *exp, struct ptlrpc_request *req,
@@ -2535,18 +2679,17 @@ int lmv_intent_getattr_async(struct obd_export *exp,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt = NULL;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_find_target(lmv, &op_data->op_fid1);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = md_intent_getattr_async(tgt->ltd_exp, minfo, einfo);
- RETURN(rc);
+ return rc;
}
int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
@@ -2556,18 +2699,17 @@ int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int rc;
- ENTRY;
rc = lmv_check_connect(obd);
if (rc)
- RETURN(rc);
+ return rc;
tgt = lmv_find_target(lmv, fid);
if (IS_ERR(tgt))
- RETURN(PTR_ERR(tgt));
+ return PTR_ERR(tgt);
rc = md_revalidate_lock(tgt->ltd_exp, it, fid, bits);
- RETURN(rc);
+ return rc;
}
/**
@@ -2583,16 +2725,15 @@ int lmv_quotactl(struct obd_device *unused, struct obd_export *exp,
struct lmv_tgt_desc *tgt = lmv->tgts[0];
int rc = 0, i;
__u64 curspace, curinodes;
- ENTRY;
if (!lmv->desc.ld_tgt_count || !tgt->ltd_active) {
CERROR("master lmv inactive\n");
- RETURN(-EIO);
+ return -EIO;
}
if (oqctl->qc_cmd != Q_GETOQUOTA) {
rc = obd_quotactl(tgt->ltd_exp, oqctl);
- RETURN(rc);
+ return rc;
}
curspace = curinodes = 0;
@@ -2620,7 +2761,7 @@ int lmv_quotactl(struct obd_device *unused, struct obd_export *exp,
oqctl->qc_dqblk.dqb_curspace = curspace;
oqctl->qc_dqblk.dqb_curinodes = curinodes;
- RETURN(rc);
+ return rc;
}
int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp,
@@ -2630,14 +2771,13 @@ int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp,
struct lmv_obd *lmv = &obd->u.lmv;
struct lmv_tgt_desc *tgt;
int i, rc = 0;
- ENTRY;
for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
int err;
tgt = lmv->tgts[i];
if (tgt == NULL || tgt->ltd_exp == NULL || !tgt->ltd_active) {
CERROR("lmv idx %d inactive\n", i);
- RETURN(-EIO);
+ return -EIO;
}
err = obd_quotacheck(tgt->ltd_exp, oqctl);
@@ -2645,7 +2785,7 @@ int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp,
rc = err;
}
- RETURN(rc);
+ return rc;
}
struct obd_ops lmv_obd_ops = {
diff --git a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
index d1c45b583cb..edb5a3a99d5 100644
--- a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
+++ b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
@@ -36,7 +36,6 @@
#define DEBUG_SUBSYSTEM S_CLASS
-#include <linux/version.h>
#include <linux/seq_file.h>
#include <asm/statfs.h>
#include <lprocfs_status.h>
diff --git a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h
index 28801b8b5fd..33d9ce68fed 100644
--- a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h
+++ b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h
@@ -162,10 +162,9 @@ struct lov_device {
* Layout type.
*/
enum lov_layout_type {
- /** empty file without body */
- LLT_EMPTY,
- /** striped file */
- LLT_RAID0,
+ LLT_EMPTY, /** empty file without body (mknod + truncate) */
+ LLT_RAID0, /** striped file */
+ LLT_RELEASED, /** file with no objects (data in HSM) */
LLT_NR
};
@@ -255,12 +254,14 @@ struct lov_object {
} raid0;
struct lov_layout_state_empty {
} empty;
+ struct lov_layout_state_released {
+ } released;
} u;
/**
* Thread that acquired lov_object::lo_type_guard in an exclusive
* mode.
*/
- task_t *lo_owner;
+ struct task_struct *lo_owner;
};
/**
@@ -582,6 +583,8 @@ int lov_io_init_raid0 (const struct lu_env *env, struct cl_object *obj,
struct cl_io *io);
int lov_io_init_empty (const struct lu_env *env, struct cl_object *obj,
struct cl_io *io);
+int lov_io_init_released(const struct lu_env *env, struct cl_object *obj,
+ struct cl_io *io);
void lov_lock_unlink (const struct lu_env *env, struct lov_lock_link *link,
struct lovsub_lock *sub);
diff --git a/drivers/staging/lustre/lustre/lov/lov_dev.c b/drivers/staging/lustre/lustre/lov/lov_dev.c
index f94f8d9d33d..a4006ef46ad 100644
--- a/drivers/staging/lustre/lustre/lov/lov_dev.c
+++ b/drivers/staging/lustre/lustre/lov/lov_dev.c
@@ -122,10 +122,8 @@ static void lov_req_completion(const struct lu_env *env,
{
struct lov_req *lr;
- ENTRY;
lr = cl2lov_req(slice);
OBD_SLAB_FREE_PTR(lr, lov_req_kmem);
- EXIT;
}
static const struct cl_req_operations lov_req_ops = {
@@ -200,7 +198,7 @@ static struct lu_device *lov_device_fini(const struct lu_env *env,
LASSERT(ld->ld_lov != NULL);
if (ld->ld_target == NULL)
- RETURN(NULL);
+ return NULL;
lov_foreach_target(ld, i) {
struct lovsub_device *lsd;
@@ -211,7 +209,7 @@ static struct lu_device *lov_device_fini(const struct lu_env *env,
ld->ld_target[i] = NULL;
}
}
- RETURN(NULL);
+ return NULL;
}
static int lov_device_init(const struct lu_env *env, struct lu_device *d,
@@ -223,7 +221,7 @@ static int lov_device_init(const struct lu_env *env, struct lu_device *d,
LASSERT(d->ld_site != NULL);
if (ld->ld_target == NULL)
- RETURN(rc);
+ return rc;
lov_foreach_target(ld, i) {
struct lovsub_device *lsd;
@@ -251,7 +249,7 @@ static int lov_device_init(const struct lu_env *env, struct lu_device *d,
else
ld->ld_flags |= LOV_DEV_INITIALIZED;
- RETURN(rc);
+ return rc;
}
static int lov_req_init(const struct lu_env *env, struct cl_device *dev,
@@ -260,14 +258,13 @@ static int lov_req_init(const struct lu_env *env, struct cl_device *dev,
struct lov_req *lr;
int result;
- ENTRY;
OBD_SLAB_ALLOC_PTR_GFP(lr, lov_req_kmem, __GFP_IO);
if (lr != NULL) {
cl_req_slice_add(req, &lr->lr_cl, dev, &lov_req_ops);
result = 0;
} else
result = -ENOMEM;
- RETURN(result);
+ return result;
}
static const struct cl_device_operations lov_cl_ops = {
@@ -311,13 +308,11 @@ static void lov_cl_del_target(const struct lu_env *env, struct lu_device *dev,
__u32 index)
{
struct lov_device *ld = lu2lov_dev(dev);
- ENTRY;
if (ld->ld_target[index] != NULL) {
cl_stack_fini(env, lovsub2cl_dev(ld->ld_target[index]));
ld->ld_target[index] = NULL;
}
- EXIT;
}
static struct lov_device_emerg **lov_emerg_alloc(int nr)
@@ -360,7 +355,6 @@ static int lov_expand_targets(const struct lu_env *env, struct lov_device *dev)
__u32 tgt_size;
__u32 sub_size;
- ENTRY;
result = 0;
tgt_size = dev->ld_lov->lov_tgt_size;
sub_size = dev->ld_target_nr;
@@ -371,7 +365,7 @@ static int lov_expand_targets(const struct lu_env *env, struct lov_device *dev)
emerg = lov_emerg_alloc(tgt_size);
if (IS_ERR(emerg))
- RETURN(PTR_ERR(emerg));
+ return PTR_ERR(emerg);
OBD_ALLOC(newd, tgt_size * sz);
if (newd != NULL) {
@@ -392,7 +386,7 @@ static int lov_expand_targets(const struct lu_env *env, struct lov_device *dev)
result = -ENOMEM;
}
}
- RETURN(result);
+ return result;
}
static int lov_cl_add_target(const struct lu_env *env, struct lu_device *dev,
@@ -404,7 +398,6 @@ static int lov_cl_add_target(const struct lu_env *env, struct lu_device *dev,
struct lovsub_device *lsd;
struct cl_device *cl;
int rc;
- ENTRY;
obd_getref(obd);
@@ -414,7 +407,7 @@ static int lov_cl_add_target(const struct lu_env *env, struct lu_device *dev,
if (!tgt->ltd_obd->obd_set_up) {
CERROR("Target %s not set up\n", obd_uuid2str(&tgt->ltd_uuid));
- RETURN(-EINVAL);
+ return -EINVAL;
}
rc = lov_expand_targets(env, ld);
@@ -436,7 +429,7 @@ static int lov_cl_add_target(const struct lu_env *env, struct lu_device *dev,
}
}
obd_putref(obd);
- RETURN(rc);
+ return rc;
}
static int lov_process_config(const struct lu_env *env,
@@ -466,7 +459,7 @@ static int lov_process_config(const struct lu_env *env,
}
}
obd_putref(obd);
- RETURN(rc);
+ return rc;
}
static const struct lu_device_operations lov_lu_ops = {
@@ -485,7 +478,7 @@ static struct lu_device *lov_device_alloc(const struct lu_env *env,
OBD_ALLOC_PTR(ld);
if (ld == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
cl_device_init(&ld->ld_cl, t);
d = lov2lu_dev(ld);
@@ -501,11 +494,11 @@ static struct lu_device *lov_device_alloc(const struct lu_env *env,
rc = lov_setup(obd, cfg);
if (rc) {
lov_device_free(env, d);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
ld->ld_lov = &obd->u.lov;
- RETURN(d);
+ return d;
}
static const struct lu_device_type_operations lov_device_type_ops = {
diff --git a/drivers/staging/lustre/lustre/lov/lov_ea.c b/drivers/staging/lustre/lustre/lov/lov_ea.c
index 340dbcf829e..e6c60151dc6 100644
--- a/drivers/staging/lustre/lustre/lov/lov_ea.c
+++ b/drivers/staging/lustre/lustre/lov/lov_ea.c
@@ -57,7 +57,7 @@ struct lovea_unpack_args {
static int lsm_lmm_verify_common(struct lov_mds_md *lmm, int lmm_bytes,
__u16 stripe_count)
{
- if (stripe_count == 0 || stripe_count > LOV_V1_INSANE_STRIPE_COUNT) {
+ if (stripe_count > LOV_V1_INSANE_STRIPE_COUNT) {
CERROR("bad stripe count %d\n", stripe_count);
lov_dump_lmm_common(D_WARNING, lmm);
return -EINVAL;
@@ -69,7 +69,7 @@ static int lsm_lmm_verify_common(struct lov_mds_md *lmm, int lmm_bytes,
return -EINVAL;
}
- if (lmm->lmm_pattern != cpu_to_le32(LOV_PATTERN_RAID0)) {
+ if (lov_pattern(le32_to_cpu(lmm->lmm_pattern)) != LOV_PATTERN_RAID0) {
CERROR("bad striping pattern\n");
lov_dump_lmm_common(D_WARNING, lmm);
return -EINVAL;
@@ -197,6 +197,8 @@ static int lsm_lmm_verify_v1(struct lov_mds_md_v1 *lmm, int lmm_bytes,
}
*stripe_count = le16_to_cpu(lmm->lmm_stripe_count);
+ if (le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED)
+ *stripe_count = 0;
if (lmm_bytes < lov_mds_md_size(*stripe_count, LOV_MAGIC_V1)) {
CERROR("LOV EA V1 too small: %d, need %d\n",
@@ -213,11 +215,14 @@ int lsm_unpackmd_v1(struct lov_obd *lov, struct lov_stripe_md *lsm,
{
struct lov_oinfo *loi;
int i;
+ int stripe_count;
__u64 stripe_maxbytes = OBD_OBJECT_EOF;
lsm_unpackmd_common(lsm, lmm);
- for (i = 0; i < lsm->lsm_stripe_count; i++) {
+ stripe_count = lsm_is_released(lsm) ? 0 : lsm->lsm_stripe_count;
+
+ for (i = 0; i < stripe_count; i++) {
/* XXX LOV STACKING call down to osc_unpackmd() */
loi = lsm->lsm_oinfo[i];
ostid_le_to_cpu(&lmm->lmm_objects[i].l_ost_oi, &loi->loi_oi);
@@ -240,6 +245,8 @@ int lsm_unpackmd_v1(struct lov_obd *lov, struct lov_stripe_md *lsm,
}
lsm->lsm_maxbytes = stripe_maxbytes * lsm->lsm_stripe_count;
+ if (lsm->lsm_stripe_count == 0)
+ lsm->lsm_maxbytes = stripe_maxbytes * lov->desc.ld_tgt_count;
return 0;
}
@@ -267,6 +274,8 @@ static int lsm_lmm_verify_v3(struct lov_mds_md *lmmv1, int lmm_bytes,
}
*stripe_count = le16_to_cpu(lmm->lmm_stripe_count);
+ if (le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED)
+ *stripe_count = 0;
if (lmm_bytes < lov_mds_md_size(*stripe_count, LOV_MAGIC_V3)) {
CERROR("LOV EA V3 too small: %d, need %d\n",
@@ -285,18 +294,22 @@ int lsm_unpackmd_v3(struct lov_obd *lov, struct lov_stripe_md *lsm,
struct lov_mds_md_v3 *lmm;
struct lov_oinfo *loi;
int i;
+ int stripe_count;
__u64 stripe_maxbytes = OBD_OBJECT_EOF;
int cplen = 0;
lmm = (struct lov_mds_md_v3 *)lmmv1;
lsm_unpackmd_common(lsm, (struct lov_mds_md_v1 *)lmm);
+
+ stripe_count = lsm_is_released(lsm) ? 0 : lsm->lsm_stripe_count;
+
cplen = strlcpy(lsm->lsm_pool_name, lmm->lmm_pool_name,
sizeof(lsm->lsm_pool_name));
if (cplen >= sizeof(lsm->lsm_pool_name))
return -E2BIG;
- for (i = 0; i < lsm->lsm_stripe_count; i++) {
+ for (i = 0; i < stripe_count; i++) {
/* XXX LOV STACKING call down to osc_unpackmd() */
loi = lsm->lsm_oinfo[i];
ostid_le_to_cpu(&lmm->lmm_objects[i].l_ost_oi, &loi->loi_oi);
@@ -319,6 +332,8 @@ int lsm_unpackmd_v3(struct lov_obd *lov, struct lov_stripe_md *lsm,
}
lsm->lsm_maxbytes = stripe_maxbytes * lsm->lsm_stripe_count;
+ if (lsm->lsm_stripe_count == 0)
+ lsm->lsm_maxbytes = stripe_maxbytes * lov->desc.ld_tgt_count;
return 0;
}
diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c
index 1a87abdf095..b611aa4e9dc 100644
--- a/drivers/staging/lustre/lustre/lov/lov_io.c
+++ b/drivers/staging/lustre/lustre/lov/lov_io.c
@@ -59,7 +59,6 @@ static inline void lov_sub_exit(struct lov_io_sub *sub)
static void lov_io_sub_fini(const struct lu_env *env, struct lov_io *lio,
struct lov_io_sub *sub)
{
- ENTRY;
if (sub->sub_io != NULL) {
if (sub->sub_io_initialized) {
lov_sub_enter(sub);
@@ -79,7 +78,6 @@ static void lov_io_sub_fini(const struct lu_env *env, struct lov_io *lio,
cl_env_put(sub->sub_env, &sub->sub_refcheck);
sub->sub_env = NULL;
}
- EXIT;
}
static void lov_io_sub_inherit(struct cl_io *io, struct lov_io *lio,
@@ -149,7 +147,6 @@ static int lov_io_sub_init(const struct lu_env *env, struct lov_io *lio,
LASSERT(sub->sub_io == NULL);
LASSERT(sub->sub_env == NULL);
LASSERT(sub->sub_stripe < lio->lis_stripe_count);
- ENTRY;
result = 0;
sub->sub_io_initialized = 0;
@@ -210,7 +207,7 @@ static int lov_io_sub_init(const struct lu_env *env, struct lov_io *lio,
}
if (result != 0)
lov_io_sub_fini(env, lio, sub);
- RETURN(result);
+ return result;
}
struct lov_io_sub *lov_sub_get(const struct lu_env *env,
@@ -220,7 +217,6 @@ struct lov_io_sub *lov_sub_get(const struct lu_env *env,
struct lov_io_sub *sub = &lio->lis_subs[stripe];
LASSERT(stripe < lio->lis_stripe_count);
- ENTRY;
if (!sub->sub_io_initialized) {
sub->sub_stripe = stripe;
@@ -231,7 +227,7 @@ struct lov_io_sub *lov_sub_get(const struct lu_env *env,
lov_sub_enter(sub);
else
sub = ERR_PTR(rc);
- RETURN(sub);
+ return sub;
}
void lov_sub_put(struct lov_io_sub *sub)
@@ -249,12 +245,11 @@ static int lov_page_stripe(const struct cl_page *page)
{
struct lovsub_object *subobj;
- ENTRY;
subobj = lu2lovsub(
lu_object_locate(page->cp_child->cp_obj->co_lu.lo_header,
&lovsub_device_type));
LASSERT(subobj != NULL);
- RETURN(subobj->lso_index);
+ return subobj->lso_index;
}
struct lov_io_sub *lov_page_subio(const struct lu_env *env, struct lov_io *lio,
@@ -268,10 +263,9 @@ struct lov_io_sub *lov_page_subio(const struct lu_env *env, struct lov_io *lio,
LASSERT(cl2lov(slice->cpl_obj) == lio->lis_object);
LASSERT(lsm != NULL);
LASSERT(lio->lis_nr_subios > 0);
- ENTRY;
stripe = lov_page_stripe(page);
- RETURN(lov_sub_get(env, lio, stripe));
+ return lov_sub_get(env, lio, stripe);
}
@@ -282,7 +276,6 @@ static int lov_io_subio_init(const struct lu_env *env, struct lov_io *lio,
int result;
LASSERT(lio->lis_object != NULL);
- ENTRY;
/*
* Need to be optimized, we can't afford to allocate a piece of memory
@@ -297,14 +290,12 @@ static int lov_io_subio_init(const struct lu_env *env, struct lov_io *lio,
result = 0;
} else
result = -ENOMEM;
- RETURN(result);
+ return result;
}
static void lov_io_slice_init(struct lov_io *lio,
struct lov_object *obj, struct cl_io *io)
{
- ENTRY;
-
io->ci_result = 0;
lio->lis_object = obj;
@@ -353,8 +344,6 @@ static void lov_io_slice_init(struct lov_io *lio,
default:
LBUG();
}
-
- EXIT;
}
static void lov_io_fini(const struct lu_env *env, const struct cl_io_slice *ios)
@@ -363,7 +352,6 @@ static void lov_io_fini(const struct lu_env *env, const struct cl_io_slice *ios)
struct lov_object *lov = cl2lov(ios->cis_obj);
int i;
- ENTRY;
if (lio->lis_subs != NULL) {
for (i = 0; i < lio->lis_nr_subios; i++)
lov_io_sub_fini(env, lio, &lio->lis_subs[i]);
@@ -375,7 +363,6 @@ static void lov_io_fini(const struct lu_env *env, const struct cl_io_slice *ios)
LASSERT(atomic_read(&lov->lo_active_ios) > 0);
if (atomic_dec_and_test(&lov->lo_active_ios))
wake_up_all(&lov->lo_waitq);
- EXIT;
}
static obd_off lov_offset_mod(obd_off val, int delta)
@@ -397,7 +384,6 @@ static int lov_io_iter_init(const struct lu_env *env,
int stripe;
int rc = 0;
- ENTRY;
endpos = lov_offset_mod(lio->lis_endpos, -1);
for (stripe = 0; stripe < lio->lis_stripe_count; stripe++) {
if (!lov_stripe_intersects(lsm, stripe, lio->lis_pos,
@@ -421,7 +407,7 @@ static int lov_io_iter_init(const struct lu_env *env,
else
break;
}
- RETURN(rc);
+ return rc;
}
static int lov_io_rw_iter_init(const struct lu_env *env,
@@ -430,12 +416,11 @@ static int lov_io_rw_iter_init(const struct lu_env *env,
struct lov_io *lio = cl2lov_io(env, ios);
struct cl_io *io = ios->cis_io;
struct lov_stripe_md *lsm = lio->lis_object->lo_lsm;
- loff_t start = io->u.ci_rw.crw_pos;
+ __u64 start = io->u.ci_rw.crw_pos;
loff_t next;
unsigned long ssize = lsm->lsm_stripe_size;
LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE);
- ENTRY;
/* fast path for common case. */
if (lio->lis_nr_subios != 1 && !cl_io_is_append(io)) {
@@ -458,7 +443,7 @@ static int lov_io_rw_iter_init(const struct lu_env *env,
* XXX The following call should be optimized: we know, that
* [lio->lis_pos, lio->lis_endpos) intersects with exactly one stripe.
*/
- RETURN(lov_io_iter_init(env, ios));
+ return lov_io_iter_init(env, ios);
}
static int lov_io_call(const struct lu_env *env, struct lov_io *lio,
@@ -468,7 +453,6 @@ static int lov_io_call(const struct lu_env *env, struct lov_io *lio,
struct lov_io_sub *sub;
int rc = 0;
- ENTRY;
list_for_each_entry(sub, &lio->lis_active, sub_linkage) {
lov_sub_enter(sub);
rc = iofunc(sub->sub_env, sub->sub_io);
@@ -479,24 +463,21 @@ static int lov_io_call(const struct lu_env *env, struct lov_io *lio,
if (parent->ci_result == 0)
parent->ci_result = sub->sub_io->ci_result;
}
- RETURN(rc);
+ return rc;
}
static int lov_io_lock(const struct lu_env *env, const struct cl_io_slice *ios)
{
- ENTRY;
- RETURN(lov_io_call(env, cl2lov_io(env, ios), cl_io_lock));
+ return lov_io_call(env, cl2lov_io(env, ios), cl_io_lock);
}
static int lov_io_start(const struct lu_env *env, const struct cl_io_slice *ios)
{
- ENTRY;
- RETURN(lov_io_call(env, cl2lov_io(env, ios), cl_io_start));
+ return lov_io_call(env, cl2lov_io(env, ios), cl_io_start);
}
static int lov_io_end_wrapper(const struct lu_env *env, struct cl_io *io)
{
- ENTRY;
/*
* It's possible that lov_io_start() wasn't called against this
* sub-io, either because previous sub-io failed, or upper layer
@@ -506,19 +487,19 @@ static int lov_io_end_wrapper(const struct lu_env *env, struct cl_io *io)
cl_io_end(env, io);
else
io->ci_state = CIS_IO_FINISHED;
- RETURN(0);
+ return 0;
}
static int lov_io_iter_fini_wrapper(const struct lu_env *env, struct cl_io *io)
{
cl_io_iter_fini(env, io);
- RETURN(0);
+ return 0;
}
static int lov_io_unlock_wrapper(const struct lu_env *env, struct cl_io *io)
{
cl_io_unlock(env, io);
- RETURN(0);
+ return 0;
}
static void lov_io_end(const struct lu_env *env, const struct cl_io_slice *ios)
@@ -535,12 +516,10 @@ static void lov_io_iter_fini(const struct lu_env *env,
struct lov_io *lio = cl2lov_io(env, ios);
int rc;
- ENTRY;
rc = lov_io_call(env, lio, lov_io_iter_fini_wrapper);
LASSERT(rc == 0);
while (!list_empty(&lio->lis_active))
list_del_init(lio->lis_active.next);
- EXIT;
}
static void lov_io_unlock(const struct lu_env *env,
@@ -548,10 +527,8 @@ static void lov_io_unlock(const struct lu_env *env,
{
int rc;
- ENTRY;
rc = lov_io_call(env, cl2lov_io(env, ios), lov_io_unlock_wrapper);
LASSERT(rc == 0);
- EXIT;
}
@@ -596,7 +573,7 @@ static int lov_io_submit(const struct lu_env *env,
int rc = 0;
int alloc =
!(current->flags & PF_MEMALLOC);
- ENTRY;
+
if (lio->lis_active_subios == 1) {
int idx = lio->lis_single_subio_index;
struct lov_io_sub *sub;
@@ -608,7 +585,7 @@ static int lov_io_submit(const struct lu_env *env,
rc = cl_io_submit_rw(sub->sub_env, sub->sub_io,
crt, queue);
lov_sub_put(sub);
- RETURN(rc);
+ return rc;
}
LASSERT(lio->lis_subs != NULL);
@@ -616,7 +593,7 @@ static int lov_io_submit(const struct lu_env *env,
OBD_ALLOC_LARGE(stripes_qin,
sizeof(*stripes_qin) * lio->lis_nr_subios);
if (stripes_qin == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
for (stripe = 0; stripe < lio->lis_nr_subios; stripe++)
cl_page_list_init(&stripes_qin[stripe]);
@@ -682,7 +659,7 @@ static int lov_io_submit(const struct lu_env *env,
mutex_unlock(&ld->ld_mutex);
}
- RETURN(rc);
+ return rc;
#undef QIN
}
@@ -696,7 +673,6 @@ static int lov_io_prepare_write(const struct lu_env *env,
struct lov_io_sub *sub;
int result;
- ENTRY;
sub = lov_page_subio(env, lio, slice);
if (!IS_ERR(sub)) {
result = cl_io_prepare_write(sub->sub_env, sub->sub_io,
@@ -704,7 +680,7 @@ static int lov_io_prepare_write(const struct lu_env *env,
lov_sub_put(sub);
} else
result = PTR_ERR(sub);
- RETURN(result);
+ return result;
}
static int lov_io_commit_write(const struct lu_env *env,
@@ -717,7 +693,6 @@ static int lov_io_commit_write(const struct lu_env *env,
struct lov_io_sub *sub;
int result;
- ENTRY;
sub = lov_page_subio(env, lio, slice);
if (!IS_ERR(sub)) {
result = cl_io_commit_write(sub->sub_env, sub->sub_io,
@@ -725,7 +700,7 @@ static int lov_io_commit_write(const struct lu_env *env,
lov_sub_put(sub);
} else
result = PTR_ERR(sub);
- RETURN(result);
+ return result;
}
static int lov_io_fault_start(const struct lu_env *env,
@@ -735,13 +710,12 @@ static int lov_io_fault_start(const struct lu_env *env,
struct lov_io *lio;
struct lov_io_sub *sub;
- ENTRY;
fio = &ios->cis_io->u.ci_fault;
lio = cl2lov_io(env, ios);
sub = lov_sub_get(env, lio, lov_page_stripe(fio->ft_page));
sub->sub_io->u.ci_fault.ft_nob = fio->ft_nob;
lov_sub_put(sub);
- RETURN(lov_io_start(env, ios));
+ return lov_io_start(env, ios);
}
static void lov_io_fsync_end(const struct lu_env *env,
@@ -750,7 +724,6 @@ static void lov_io_fsync_end(const struct lu_env *env,
struct lov_io *lio = cl2lov_io(env, ios);
struct lov_io_sub *sub;
unsigned int *written = &ios->cis_io->u.ci_fsync.fi_nr_written;
- ENTRY;
*written = 0;
list_for_each_entry(sub, &lio->lis_active, sub_linkage) {
@@ -763,7 +736,6 @@ static void lov_io_fsync_end(const struct lu_env *env,
if (subio->ci_result == 0)
*written += subio->u.ci_fsync.fi_nr_written;
}
- RETURN_EXIT;
}
static const struct cl_io_operations lov_io_ops = {
@@ -839,11 +811,9 @@ static void lov_empty_io_fini(const struct lu_env *env,
const struct cl_io_slice *ios)
{
struct lov_object *lov = cl2lov(ios->cis_obj);
- ENTRY;
if (atomic_dec_and_test(&lov->lo_active_ios))
wake_up_all(&lov->lo_waitq);
- EXIT;
}
static void lov_empty_impossible(const struct lu_env *env,
@@ -913,7 +883,6 @@ int lov_io_init_raid0(const struct lu_env *env, struct cl_object *obj,
struct lov_io *lio = lov_env_io(env);
struct lov_object *lov = cl2lov(obj);
- ENTRY;
INIT_LIST_HEAD(&lio->lis_active);
lov_io_slice_init(lio, lov, io);
if (io->ci_result == 0) {
@@ -923,7 +892,7 @@ int lov_io_init_raid0(const struct lu_env *env, struct cl_object *obj,
atomic_inc(&lov->lo_active_ios);
}
}
- RETURN(io->ci_result);
+ return io->ci_result;
}
int lov_io_init_empty(const struct lu_env *env, struct cl_object *obj,
@@ -932,7 +901,6 @@ int lov_io_init_empty(const struct lu_env *env, struct cl_object *obj,
struct lov_object *lov = cl2lov(obj);
struct lov_io *lio = lov_env_io(env);
int result;
- ENTRY;
lio->lis_object = lov;
switch (io->ci_type) {
@@ -961,7 +929,40 @@ int lov_io_init_empty(const struct lu_env *env, struct cl_object *obj,
}
io->ci_result = result < 0 ? result : 0;
- RETURN(result != 0);
+ return result != 0;
}
+int lov_io_init_released(const struct lu_env *env, struct cl_object *obj,
+ struct cl_io *io)
+{
+ struct lov_object *lov = cl2lov(obj);
+ struct lov_io *lio = lov_env_io(env);
+ int result;
+
+ LASSERT(lov->lo_lsm != NULL);
+ lio->lis_object = lov;
+
+ switch (io->ci_type) {
+ default:
+ LASSERTF(0, "invalid type %d\n", io->ci_type);
+ case CIT_MISC:
+ case CIT_FSYNC:
+ result = +1;
+ break;
+ case CIT_SETATTR:
+ case CIT_READ:
+ case CIT_WRITE:
+ case CIT_FAULT:
+ /* TODO: need to restore the file. */
+ result = -EBADF;
+ break;
+ }
+ if (result == 0) {
+ cl_io_slice_add(io, &lio->lis_cl, obj, &lov_empty_io_ops);
+ atomic_inc(&lov->lo_active_ios);
+ }
+
+ io->ci_result = result < 0 ? result : 0;
+ return result != 0;
+}
/** @} lov */
diff --git a/drivers/staging/lustre/lustre/lov/lov_lock.c b/drivers/staging/lustre/lustre/lov/lov_lock.c
index bdf3334e0c9..ec297e87c2a 100644
--- a/drivers/staging/lustre/lustre/lov/lov_lock.c
+++ b/drivers/staging/lustre/lustre/lov/lov_lock.c
@@ -110,7 +110,6 @@ static void lov_sublock_adopt(const struct lu_env *env, struct lov_lock *lck,
LASSERT(cl_lock_is_mutexed(parent));
LASSERT(cl_lock_is_mutexed(sublock));
- ENTRY;
lsl = cl2sub_lock(sublock);
/*
@@ -132,7 +131,6 @@ static void lov_sublock_adopt(const struct lu_env *env, struct lov_lock *lck,
rc = lov_sublock_modify(env, lck, lsl, &sublock->cll_descr, idx);
LASSERT(rc == 0); /* there is no way this can fail, currently */
- EXIT;
}
static struct cl_lock *lov_sublock_alloc(const struct lu_env *env,
@@ -145,7 +143,6 @@ static struct cl_lock *lov_sublock_alloc(const struct lu_env *env,
struct lov_lock_link *link;
LASSERT(idx < lck->lls_nr);
- ENTRY;
OBD_SLAB_ALLOC_PTR_GFP(link, lov_lock_link_kmem, __GFP_IO);
if (link != NULL) {
@@ -179,7 +176,7 @@ static struct cl_lock *lov_sublock_alloc(const struct lu_env *env,
OBD_SLAB_FREE_PTR(link, lov_lock_link_kmem);
} else
sublock = ERR_PTR(-ENOMEM);
- RETURN(sublock);
+ return sublock;
}
static void lov_sublock_unlock(const struct lu_env *env,
@@ -187,11 +184,9 @@ static void lov_sublock_unlock(const struct lu_env *env,
struct cl_lock_closure *closure,
struct lov_sublock_env *subenv)
{
- ENTRY;
lov_sublock_env_put(subenv);
lsl->lss_active = NULL;
cl_lock_disclosure(env, closure);
- EXIT;
}
static int lov_sublock_lock(const struct lu_env *env,
@@ -203,7 +198,6 @@ static int lov_sublock_lock(const struct lu_env *env,
struct lovsub_lock *sublock;
struct cl_lock *child;
int result = 0;
- ENTRY;
LASSERT(list_empty(&closure->clc_list));
@@ -243,7 +237,7 @@ static int lov_sublock_lock(const struct lu_env *env,
}
}
}
- RETURN(result);
+ return result;
}
/**
@@ -267,8 +261,6 @@ static int lov_subresult(int result, int rc)
int result_rank;
int rc_rank;
- ENTRY;
-
LASSERTF(result <= 0 || result == CLO_REPEAT || result == CLO_WAIT,
"result = %d", result);
LASSERTF(rc <= 0 || rc == CLO_REPEAT || rc == CLO_WAIT,
@@ -281,7 +273,7 @@ static int lov_subresult(int result, int rc)
if (result_rank < rc_rank)
result = rc;
- RETURN(result);
+ return result;
}
/**
@@ -307,8 +299,6 @@ static int lov_lock_sub_init(const struct lu_env *env,
struct lov_layout_raid0 *r0 = lov_r0(loo);
struct cl_lock *parent = lck->lls_cl.cls_lock;
- ENTRY;
-
lck->lls_orig = parent->cll_descr;
file_start = cl_offset(lov2cl(loo), parent->cll_descr.cld_start);
file_end = cl_offset(lov2cl(loo), parent->cll_descr.cld_end + 1) - 1;
@@ -325,7 +315,7 @@ static int lov_lock_sub_init(const struct lu_env *env,
LASSERT(nr > 0);
OBD_ALLOC_LARGE(lck->lls_sub, nr * sizeof lck->lls_sub[0]);
if (lck->lls_sub == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lck->lls_nr = nr;
/*
@@ -396,7 +386,7 @@ static int lov_lock_sub_init(const struct lu_env *env,
* because enqueue will create them anyway. Main duty of this function
* is to fill in sub-lock descriptions in a race free manner.
*/
- RETURN(result);
+ return result;
}
static int lov_sublock_release(const struct lu_env *env, struct lov_lock *lck,
@@ -405,7 +395,6 @@ static int lov_sublock_release(const struct lu_env *env, struct lov_lock *lck,
struct cl_lock *parent = lck->lls_cl.cls_lock;
LASSERT(cl_lock_is_mutexed(parent));
- ENTRY;
if (lck->lls_sub[i].sub_flags & LSF_HELD) {
struct cl_lock *sublock;
@@ -442,7 +431,7 @@ static int lov_sublock_release(const struct lu_env *env, struct lov_lock *lck,
* sub-lock is destroyed.
*/
}
- RETURN(rc);
+ return rc;
}
static void lov_sublock_hold(const struct lu_env *env, struct lov_lock *lck,
@@ -451,7 +440,6 @@ static void lov_sublock_hold(const struct lu_env *env, struct lov_lock *lck,
struct cl_lock *parent = lck->lls_cl.cls_lock;
LASSERT(cl_lock_is_mutexed(parent));
- ENTRY;
if (!(lck->lls_sub[i].sub_flags & LSF_HELD)) {
struct cl_lock *sublock;
@@ -468,7 +456,6 @@ static void lov_sublock_hold(const struct lu_env *env, struct lov_lock *lck,
cl_lock_user_add(env, sublock);
cl_lock_put(env, sublock);
}
- EXIT;
}
static void lov_lock_fini(const struct lu_env *env,
@@ -477,7 +464,6 @@ static void lov_lock_fini(const struct lu_env *env,
struct lov_lock *lck;
int i;
- ENTRY;
lck = cl2lov_lock(slice);
LASSERT(lck->lls_nr_filled == 0);
if (lck->lls_sub != NULL) {
@@ -491,7 +477,6 @@ static void lov_lock_fini(const struct lu_env *env,
lck->lls_nr * sizeof lck->lls_sub[0]);
}
OBD_SLAB_FREE_PTR(lck, lov_lock_kmem);
- EXIT;
}
static int lov_lock_enqueue_wait(const struct lu_env *env,
@@ -500,14 +485,13 @@ static int lov_lock_enqueue_wait(const struct lu_env *env,
{
struct cl_lock *lock = lck->lls_cl.cls_lock;
int result;
- ENTRY;
LASSERT(cl_lock_is_mutexed(lock));
cl_lock_mutex_put(env, lock);
result = cl_lock_enqueue_wait(env, sublock, 0);
cl_lock_mutex_get(env, lock);
- RETURN(result ?: CLO_REPEAT);
+ return result ?: CLO_REPEAT;
}
/**
@@ -522,7 +506,6 @@ static int lov_lock_enqueue_one(const struct lu_env *env, struct lov_lock *lck,
struct cl_io *io, __u32 enqflags, int last)
{
int result;
- ENTRY;
/* first, try to enqueue a sub-lock ... */
result = cl_enqueue_try(env, sublock, io, enqflags);
@@ -541,7 +524,7 @@ static int lov_lock_enqueue_one(const struct lu_env *env, struct lov_lock *lck,
if ((result == CLO_WAIT) && (sublock->cll_state <= CLS_HELD) &&
(enqflags & CEF_ASYNC) && (!last || (enqflags & CEF_AGL)))
result = 0;
- RETURN(result);
+ return result;
}
/**
@@ -600,8 +583,6 @@ static int lov_lock_enqueue(const struct lu_env *env,
int result;
enum cl_lock_state minstate;
- ENTRY;
-
for (result = 0, minstate = CLS_FREEING, i = 0; i < lck->lls_nr; ++i) {
int rc;
struct lovsub_lock *sub;
@@ -680,7 +661,7 @@ static int lov_lock_enqueue(const struct lu_env *env,
break;
}
cl_lock_closure_fini(closure);
- RETURN(result ?: minstate >= CLS_ENQUEUED ? 0 : CLO_WAIT);
+ return result ?: minstate >= CLS_ENQUEUED ? 0 : CLO_WAIT;
}
static int lov_lock_unuse(const struct lu_env *env,
@@ -691,8 +672,6 @@ static int lov_lock_unuse(const struct lu_env *env,
int i;
int result;
- ENTRY;
-
for (result = 0, i = 0; i < lck->lls_nr; ++i) {
int rc;
struct lovsub_lock *sub;
@@ -728,7 +707,7 @@ static int lov_lock_unuse(const struct lu_env *env,
result = -ESTALE;
}
cl_lock_closure_fini(closure);
- RETURN(result);
+ return result;
}
@@ -740,8 +719,6 @@ static void lov_lock_cancel(const struct lu_env *env,
int i;
int result;
- ENTRY;
-
for (result = 0, i = 0; i < lck->lls_nr; ++i) {
int rc;
struct lovsub_lock *sub;
@@ -802,8 +779,6 @@ static int lov_lock_wait(const struct lu_env *env,
int result;
int i;
- ENTRY;
-
again:
for (result = 0, minstate = CLS_FREEING, i = 0, reenqueued = 0;
i < lck->lls_nr; ++i) {
@@ -839,7 +814,7 @@ again:
if (result == 0 && reenqueued != 0)
goto again;
cl_lock_closure_fini(closure);
- RETURN(result ?: minstate >= CLS_HELD ? 0 : CLO_WAIT);
+ return result ?: minstate >= CLS_HELD ? 0 : CLO_WAIT;
}
static int lov_lock_use(const struct lu_env *env,
@@ -851,7 +826,6 @@ static int lov_lock_use(const struct lu_env *env,
int i;
LASSERT(slice->cls_lock->cll_state == CLS_INTRANSIT);
- ENTRY;
for (result = 0, i = 0; i < lck->lls_nr; ++i) {
int rc;
@@ -908,7 +882,7 @@ static int lov_lock_use(const struct lu_env *env,
result = -ESTALE;
}
cl_lock_closure_fini(closure);
- RETURN(result);
+ return result;
}
#if 0
@@ -1016,8 +990,6 @@ static int lov_lock_fits_into(const struct lu_env *env,
LASSERT(cl_object_same(need->cld_obj, slice->cls_obj));
LASSERT(lov->lls_nr > 0);
- ENTRY;
-
/* for top lock, it's necessary to match enq flags otherwise it will
* run into problem if a sublock is missing and reenqueue. */
if (need->cld_enq_flags != lov->lls_orig.cld_enq_flags)
@@ -1055,7 +1027,7 @@ static int lov_lock_fits_into(const struct lu_env *env,
PDESCR(&lov->lls_orig), PDESCR(&lov->lls_sub[0].sub_got),
lov->lls_sub[0].sub_stripe, lov->lls_nr, lov_r0(obj)->lo_nr,
result);
- RETURN(result);
+ return result;
}
void lov_lock_unlink(const struct lu_env *env,
@@ -1066,7 +1038,6 @@ void lov_lock_unlink(const struct lu_env *env,
LASSERT(cl_lock_is_mutexed(parent));
LASSERT(cl_lock_is_mutexed(sub->lss_cl.cls_lock));
- ENTRY;
list_del_init(&link->lll_list);
LASSERT(lck->lls_sub[link->lll_idx].sub_lock == sub);
@@ -1077,7 +1048,6 @@ void lov_lock_unlink(const struct lu_env *env,
lu_ref_del(&parent->cll_reference, "lov-child", sub->lss_cl.cls_lock);
cl_lock_put(env, parent);
OBD_SLAB_FREE_PTR(link, lov_lock_link_kmem);
- EXIT;
}
struct lov_lock_link *lov_lock_link_find(const struct lu_env *env,
@@ -1087,13 +1057,12 @@ struct lov_lock_link *lov_lock_link_find(const struct lu_env *env,
struct lov_lock_link *scan;
LASSERT(cl_lock_is_mutexed(sub->lss_cl.cls_lock));
- ENTRY;
list_for_each_entry(scan, &sub->lss_parents, lll_list) {
if (scan->lll_super == lck)
- RETURN(scan);
+ return scan;
}
- RETURN(NULL);
+ return NULL;
}
/**
@@ -1120,7 +1089,6 @@ static void lov_lock_delete(const struct lu_env *env,
int i;
LASSERT(slice->cls_lock->cll_state == CLS_FREEING);
- ENTRY;
for (i = 0; i < lck->lls_nr; ++i) {
struct lov_lock_sub *lls = &lck->lls_sub[i];
@@ -1150,7 +1118,6 @@ static void lov_lock_delete(const struct lu_env *env,
}
cl_lock_closure_fini(closure);
- EXIT;
}
static int lov_lock_print(const struct lu_env *env, void *cookie,
@@ -1192,14 +1159,13 @@ int lov_lock_init_raid0(const struct lu_env *env, struct cl_object *obj,
struct lov_lock *lck;
int result;
- ENTRY;
OBD_SLAB_ALLOC_PTR_GFP(lck, lov_lock_kmem, __GFP_IO);
if (lck != NULL) {
cl_lock_slice_add(lock, &lck->lls_cl, obj, &lov_lock_ops);
result = lov_lock_sub_init(env, lck, io);
} else
result = -ENOMEM;
- RETURN(result);
+ return result;
}
static void lov_empty_lock_fini(const struct lu_env *env,
@@ -1228,14 +1194,13 @@ int lov_lock_init_empty(const struct lu_env *env, struct cl_object *obj,
struct lov_lock *lck;
int result = -ENOMEM;
- ENTRY;
OBD_SLAB_ALLOC_PTR_GFP(lck, lov_lock_kmem, __GFP_IO);
if (lck != NULL) {
cl_lock_slice_add(lock, &lck->lls_cl, obj, &lov_empty_lock_ops);
lck->lls_orig = lock->cll_descr;
result = 0;
}
- RETURN(result);
+ return result;
}
static struct cl_lock_closure *lov_closure_get(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/lov/lov_log.c b/drivers/staging/lustre/lustre/lov/lov_log.c
index 63b7f8d3182..3eedd935d1b 100644
--- a/drivers/staging/lustre/lustre/lov/lov_log.c
+++ b/drivers/staging/lustre/lustre/lov/lov_log.c
@@ -71,7 +71,6 @@ static int lov_llog_origin_add(const struct lu_env *env,
struct obd_device *obd = ctxt->loc_obd;
struct lov_obd *lov = &obd->u.lov;
int i, rc = 0, cookies = 0;
- ENTRY;
LASSERTF(logcookies && numcookies >= lsm->lsm_stripe_count,
"logcookies %p, numcookies %d lsm->lsm_stripe_count %d \n",
@@ -118,7 +117,7 @@ static int lov_llog_origin_add(const struct lu_env *env,
/* Note that rc is always 1 if llog_obd_add was successful */
cookies += rc;
}
- RETURN(cookies);
+ return cookies;
}
static int lov_llog_origin_connect(struct llog_ctxt *ctxt,
@@ -129,7 +128,6 @@ static int lov_llog_origin_connect(struct llog_ctxt *ctxt,
struct obd_device *obd = ctxt->loc_obd;
struct lov_obd *lov = &obd->u.lov;
int i, rc = 0, err = 0;
- ENTRY;
obd_getref(obd);
for (i = 0; i < lov->desc.ld_tgt_count; i++) {
@@ -154,7 +152,7 @@ static int lov_llog_origin_connect(struct llog_ctxt *ctxt,
}
obd_putref(obd);
- RETURN(err);
+ return err;
}
/* the replicators commit callback */
@@ -167,7 +165,6 @@ static int lov_llog_repl_cancel(const struct lu_env *env,
struct lov_obd *lov;
struct obd_device *obd = ctxt->loc_obd;
int rc = 0, i;
- ENTRY;
LASSERT(lsm != NULL);
LASSERT(count == lsm->lsm_stripe_count);
@@ -194,7 +191,7 @@ static int lov_llog_repl_cancel(const struct lu_env *env,
}
}
obd_putref(obd);
- RETURN(rc);
+ return rc;
}
static struct llog_operations lov_mds_ost_orig_logops = {
@@ -212,13 +209,12 @@ int lov_llog_init(struct obd_device *obd, struct obd_llog_group *olg,
struct lov_obd *lov = &obd->u.lov;
struct obd_device *child;
int i, rc = 0;
- ENTRY;
LASSERT(olg == &obd->obd_olg);
rc = llog_setup(NULL, obd, olg, LLOG_MDS_OST_ORIG_CTXT, disk_obd,
&lov_mds_ost_orig_logops);
if (rc)
- RETURN(rc);
+ return rc;
rc = llog_setup(NULL, obd, olg, LLOG_SIZE_REPL_CTXT, disk_obd,
&lov_size_repl_logops);
@@ -261,8 +257,6 @@ int lov_llog_finish(struct obd_device *obd, int count)
{
struct llog_ctxt *ctxt;
- ENTRY;
-
/* cleanup our llogs only if the ctxts have been setup
* (client lov doesn't setup, mds lov does). */
ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT);
@@ -274,5 +268,5 @@ int lov_llog_finish(struct obd_device *obd, int count)
llog_cleanup(NULL, ctxt);
/* lov->tgt llogs are cleaned during osc_cleanup. */
- RETURN(0);
+ return 0;
}
diff --git a/drivers/staging/lustre/lustre/lov/lov_merge.c b/drivers/staging/lustre/lustre/lov/lov_merge.c
index ddbac122026..d204fedea34 100644
--- a/drivers/staging/lustre/lustre/lov/lov_merge.c
+++ b/drivers/staging/lustre/lustre/lov/lov_merge.c
@@ -109,7 +109,7 @@ int lov_merge_lvb_kms(struct lov_stripe_md *lsm,
lvb->lvb_mtime = current_mtime;
lvb->lvb_atime = current_atime;
lvb->lvb_ctime = current_ctime;
- RETURN(rc);
+ return rc;
}
/** Merge the lock value block(&lvb) attributes from each of the stripes in a
@@ -127,7 +127,6 @@ int lov_merge_lvb(struct obd_export *exp,
int rc;
__u64 kms;
- ENTRY;
lov_stripe_lock(lsm);
rc = lov_merge_lvb_kms(lsm, lvb, &kms);
lov_stripe_unlock(lsm);
@@ -137,7 +136,7 @@ int lov_merge_lvb(struct obd_export *exp,
CDEBUG(D_INODE, "merged for ID "DOSTID" s="LPU64" m="LPU64" a="LPU64
" c="LPU64" b="LPU64"\n", POSTID(&lsm->lsm_oi), lvb->lvb_size,
lvb->lvb_mtime, lvb->lvb_atime, lvb->lvb_ctime, lvb->lvb_blocks);
- RETURN(rc);
+ return rc;
}
/* Must be called under the lov_stripe_lock() */
@@ -147,7 +146,6 @@ int lov_adjust_kms(struct obd_export *exp, struct lov_stripe_md *lsm,
struct lov_oinfo *loi;
int stripe = 0;
__u64 kms;
- ENTRY;
LASSERT(spin_is_locked(&lsm->lsm_lock));
LASSERT(lsm->lsm_lock_owner == current_pid());
@@ -162,7 +160,7 @@ int lov_adjust_kms(struct obd_export *exp, struct lov_stripe_md *lsm,
loi->loi_kms, kms);
loi_kms_set(loi, loi->loi_lvb.lvb_size = kms);
}
- RETURN(0);
+ return 0;
}
if (size > 0)
@@ -175,7 +173,7 @@ int lov_adjust_kms(struct obd_export *exp, struct lov_stripe_md *lsm,
if (kms > loi->loi_kms)
loi_kms_set(loi, kms);
- RETURN(0);
+ return 0;
}
void lov_merge_attrs(struct obdo *tgt, struct obdo *src, obd_valid valid,
diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c
index ef7ff091f04..0b47aba1332 100644
--- a/drivers/staging/lustre/lustre/lov/lov_obd.c
+++ b/drivers/staging/lustre/lustre/lov/lov_obd.c
@@ -131,19 +131,18 @@ int lov_connect_obd(struct obd_device *obd, __u32 index, int activate,
struct obd_device *tgt_obd;
static struct obd_uuid lov_osc_uuid = { "LOV_OSC_UUID" };
struct obd_import *imp;
- proc_dir_entry_t *lov_proc_dir;
+ struct proc_dir_entry *lov_proc_dir;
int rc;
- ENTRY;
if (!lov->lov_tgts[index])
- RETURN(-EINVAL);
+ return -EINVAL;
tgt_uuid = &lov->lov_tgts[index]->ltd_uuid;
tgt_obd = lov->lov_tgts[index]->ltd_obd;
if (!tgt_obd->obd_set_up) {
CERROR("Target %s not set up\n", obd_uuid2str(tgt_uuid));
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* override the sp_me from lov */
@@ -168,14 +167,14 @@ int lov_connect_obd(struct obd_device *obd, __u32 index, int activate,
if (rc) {
CERROR("Target %s register_observer error %d\n",
obd_uuid2str(tgt_uuid), rc);
- RETURN(rc);
+ return rc;
}
if (imp->imp_invalid) {
CDEBUG(D_CONFIG, "not connecting OSC %s; administratively "
"disabled\n", obd_uuid2str(tgt_uuid));
- RETURN(0);
+ return 0;
}
rc = obd_connect(NULL, &lov->lov_tgts[index]->ltd_exp, tgt_obd,
@@ -183,7 +182,7 @@ int lov_connect_obd(struct obd_device *obd, __u32 index, int activate,
if (rc || !lov->lov_tgts[index]->ltd_exp) {
CERROR("Target %s connect error %d\n",
obd_uuid2str(tgt_uuid), rc);
- RETURN(-ENODEV);
+ return -ENODEV;
}
lov->lov_tgts[index]->ltd_reap = 0;
@@ -194,7 +193,7 @@ int lov_connect_obd(struct obd_device *obd, __u32 index, int activate,
lov_proc_dir = obd->obd_proc_private;
if (lov_proc_dir) {
struct obd_device *osc_obd = lov->lov_tgts[index]->ltd_exp->exp_obd;
- proc_dir_entry_t *osc_symlink;
+ struct proc_dir_entry *osc_symlink;
LASSERT(osc_obd != NULL);
LASSERT(osc_obd->obd_magic == OBD_DEVICE_MAGIC);
@@ -215,7 +214,7 @@ int lov_connect_obd(struct obd_device *obd, __u32 index, int activate,
}
}
- RETURN(0);
+ return 0;
}
static int lov_connect(const struct lu_env *env,
@@ -227,13 +226,12 @@ static int lov_connect(const struct lu_env *env,
struct lov_tgt_desc *tgt;
struct lustre_handle conn;
int i, rc;
- ENTRY;
CDEBUG(D_CONFIG, "connect #%d\n", lov->lov_connects);
rc = class_connect(&conn, obd, cluuid);
if (rc)
- RETURN(rc);
+ return rc;
*exp = class_conn2export(&conn);
@@ -270,16 +268,15 @@ static int lov_connect(const struct lu_env *env,
}
obd_putref(obd);
- RETURN(0);
+ return 0;
}
static int lov_disconnect_obd(struct obd_device *obd, struct lov_tgt_desc *tgt)
{
- proc_dir_entry_t *lov_proc_dir;
+ struct proc_dir_entry *lov_proc_dir;
struct lov_obd *lov = &obd->u.lov;
struct obd_device *osc_obd;
int rc;
- ENTRY;
osc_obd = class_exp2obd(tgt->ltd_exp);
CDEBUG(D_CONFIG, "%s: disconnecting target %s\n",
@@ -315,7 +312,7 @@ static int lov_disconnect_obd(struct obd_device *obd, struct lov_tgt_desc *tgt)
}
tgt->ltd_exp = NULL;
- RETURN(0);
+ return 0;
}
static int lov_disconnect(struct obd_export *exp)
@@ -323,7 +320,6 @@ static int lov_disconnect(struct obd_export *exp)
struct obd_device *obd = class_exp2obd(exp);
struct lov_obd *lov = &obd->u.lov;
int i, rc;
- ENTRY;
if (!lov->lov_tgts)
goto out;
@@ -350,7 +346,7 @@ static int lov_disconnect(struct obd_export *exp)
out:
rc = class_disconnect(exp); /* bz 9811 */
- RETURN(rc);
+ return rc;
}
/* Error codes:
@@ -366,7 +362,6 @@ static int lov_set_osc_active(struct obd_device *obd, struct obd_uuid *uuid,
struct lov_obd *lov = &obd->u.lov;
struct lov_tgt_desc *tgt;
int index, activate, active;
- ENTRY;
CDEBUG(D_INFO, "Searching in lov %p for uuid %s event(%d)\n",
lov, uuid->uuid, ev);
@@ -438,7 +433,7 @@ static int lov_set_osc_active(struct obd_device *obd, struct obd_uuid *uuid,
out:
obd_putref(obd);
- RETURN(index);
+ return index;
}
static int lov_notify(struct obd_device *obd, struct obd_device *watched,
@@ -446,12 +441,11 @@ static int lov_notify(struct obd_device *obd, struct obd_device *watched,
{
int rc = 0;
struct lov_obd *lov = &obd->u.lov;
- ENTRY;
down_read(&lov->lov_notify_lock);
if (!lov->lov_connects) {
up_read(&lov->lov_notify_lock);
- RETURN(rc);
+ return rc;
}
if (ev == OBD_NOTIFY_ACTIVE || ev == OBD_NOTIFY_INACTIVE ||
@@ -465,7 +459,7 @@ static int lov_notify(struct obd_device *obd, struct obd_device *watched,
CERROR("unexpected notification of %s %s!\n",
watched->obd_type->typ_name,
watched->obd_name);
- RETURN(-EINVAL);
+ return -EINVAL;
}
uuid = &watched->u.cli.cl_target_uuid;
@@ -477,7 +471,7 @@ static int lov_notify(struct obd_device *obd, struct obd_device *watched,
up_read(&lov->lov_notify_lock);
CERROR("event(%d) of %s failed: %d\n", ev,
obd_uuid2str(uuid), rc);
- RETURN(rc);
+ return rc;
}
/* active event should be pass lov target index as data */
data = &rc;
@@ -520,7 +514,7 @@ static int lov_notify(struct obd_device *obd, struct obd_device *watched,
}
up_read(&lov->lov_notify_lock);
- RETURN(rc);
+ return rc;
}
static int lov_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
@@ -530,7 +524,6 @@ static int lov_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
struct lov_tgt_desc *tgt;
struct obd_device *tgt_obd;
int rc;
- ENTRY;
CDEBUG(D_CONFIG, "uuid:%s idx:%d gen:%d active:%d\n",
uuidp->uuid, index, gen, active);
@@ -538,13 +531,13 @@ static int lov_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
if (gen <= 0) {
CERROR("request to add OBD %s with invalid generation: %d\n",
uuidp->uuid, gen);
- RETURN(-EINVAL);
+ return -EINVAL;
}
tgt_obd = class_find_client_obd(uuidp, LUSTRE_OSC_NAME,
&obd->obd_uuid);
if (tgt_obd == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
mutex_lock(&lov->lov_lock);
@@ -553,7 +546,7 @@ static int lov_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
CERROR("UUID %s already assigned at LOV target index %d\n",
obd_uuid2str(&tgt->ltd_uuid), index);
mutex_unlock(&lov->lov_lock);
- RETURN(-EEXIST);
+ return -EEXIST;
}
if (index >= lov->lov_tgt_size) {
@@ -567,7 +560,7 @@ static int lov_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
OBD_ALLOC(newtgts, sizeof(*newtgts) * newsize);
if (newtgts == NULL) {
mutex_unlock(&lov->lov_lock);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
if (lov->lov_tgt_size) {
@@ -590,14 +583,14 @@ static int lov_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
OBD_ALLOC_PTR(tgt);
if (!tgt) {
mutex_unlock(&lov->lov_lock);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
rc = lov_ost_pool_add(&lov->lov_packed, index, lov->lov_tgt_size);
if (rc) {
mutex_unlock(&lov->lov_lock);
OBD_FREE_PTR(tgt);
- RETURN(rc);
+ return rc;
}
tgt->ltd_uuid = *uuidp;
@@ -621,7 +614,7 @@ static int lov_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
/* lov_connect hasn't been called yet. We'll do the
lov_connect_obd on this target when that fn first runs,
because we don't know the connect flags yet. */
- RETURN(0);
+ return 0;
}
obd_getref(obd);
@@ -654,7 +647,7 @@ out:
lov_del_target(obd, index, 0, 0);
}
obd_putref(obd);
- RETURN(rc);
+ return rc;
}
/* Schedule a target for deletion */
@@ -664,12 +657,11 @@ int lov_del_target(struct obd_device *obd, __u32 index,
struct lov_obd *lov = &obd->u.lov;
int count = lov->desc.ld_tgt_count;
int rc = 0;
- ENTRY;
if (index >= count) {
CERROR("LOV target index %d >= number of LOV OBDs %d.\n",
index, count);
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* to make sure there's no ongoing lov_notify() now */
@@ -700,7 +692,7 @@ out:
obd_putref(obd);
up_write(&lov->lov_notify_lock);
- RETURN(rc);
+ return rc;
}
static void __lov_del_obd(struct obd_device *obd, struct lov_tgt_desc *tgt)
@@ -780,11 +772,10 @@ int lov_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
struct lov_desc *desc;
struct lov_obd *lov = &obd->u.lov;
int rc;
- ENTRY;
if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1) {
CERROR("LOV setup requires a descriptor\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
desc = (struct lov_desc *)lustre_cfg_buf(lcfg, 1);
@@ -792,7 +783,7 @@ int lov_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
if (sizeof(*desc) > LUSTRE_CFG_BUFLEN(lcfg, 1)) {
CERROR("descriptor size wrong: %d > %d\n",
(int)sizeof(*desc), LUSTRE_CFG_BUFLEN(lcfg, 1));
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (desc->ld_magic != LOV_DESC_MAGIC) {
@@ -803,7 +794,7 @@ int lov_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
} else {
CERROR("%s: Bad lov desc magic: %#x\n",
obd->obd_name, desc->ld_magic);
- RETURN(-EINVAL);
+ return -EINVAL;
}
}
@@ -836,11 +827,11 @@ int lov_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
lprocfs_obd_setup(obd, lvars.obd_vars);
#ifdef LPROCFS
{
- int rc;
+ int rc1;
- rc = lprocfs_seq_create(obd->obd_proc_entry, "target_obd",
+ rc1 = lprocfs_seq_create(obd->obd_proc_entry, "target_obd",
0444, &lov_proc_target_fops, obd);
- if (rc)
+ if (rc1)
CWARN("Error adding the target_obd file\n");
}
#endif
@@ -848,7 +839,7 @@ int lov_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
obd->obd_proc_entry,
NULL, NULL);
- RETURN(0);
+ return 0;
out:
return rc;
@@ -859,8 +850,6 @@ static int lov_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
int rc = 0;
struct lov_obd *lov = &obd->u.lov;
- ENTRY;
-
switch (stage) {
case OBD_CLEANUP_EARLY: {
int i;
@@ -878,7 +867,7 @@ static int lov_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
CERROR("failed to cleanup llogging subsystems\n");
break;
}
- RETURN(rc);
+ return rc;
}
static int lov_cleanup(struct obd_device *obd)
@@ -886,7 +875,6 @@ static int lov_cleanup(struct obd_device *obd)
struct lov_obd *lov = &obd->u.lov;
struct list_head *pos, *tmp;
struct pool_desc *pool;
- ENTRY;
list_for_each_safe(pos, tmp, &lov->lov_pool_list) {
pool = list_entry(pos, struct pool_desc, pool_list);
@@ -925,7 +913,7 @@ static int lov_cleanup(struct obd_device *obd)
lov->lov_tgt_size);
lov->lov_tgt_size = 0;
}
- RETURN(0);
+ return 0;
}
int lov_process_config_base(struct obd_device *obd, struct lustre_cfg *lcfg,
@@ -934,7 +922,6 @@ int lov_process_config_base(struct obd_device *obd, struct lustre_cfg *lcfg,
struct obd_uuid obd_uuid;
int cmd;
int rc = 0;
- ENTRY;
switch(cmd = lcfg->lcfg_command) {
case LCFG_LOV_ADD_OBD:
@@ -990,7 +977,7 @@ int lov_process_config_base(struct obd_device *obd, struct lustre_cfg *lcfg,
}
}
out:
- RETURN(rc);
+ return rc;
}
static int lov_recreate(struct obd_export *exp, struct obdo *src_oa,
@@ -1000,14 +987,13 @@ static int lov_recreate(struct obd_export *exp, struct obdo *src_oa,
struct lov_obd *lov = &exp->exp_obd->u.lov;
unsigned ost_idx;
int rc, i;
- ENTRY;
LASSERT(src_oa->o_valid & OBD_MD_FLFLAGS &&
src_oa->o_flags & OBD_FL_RECREATE_OBJS);
OBD_ALLOC(obj_mdp, sizeof(*obj_mdp));
if (obj_mdp == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
ost_idx = src_oa->o_nlink;
lsm = *ea;
@@ -1032,7 +1018,7 @@ static int lov_recreate(struct obd_export *exp, struct obdo *src_oa,
src_oa, &obj_mdp, oti);
out:
OBD_FREE(obj_mdp, sizeof(*obj_mdp));
- RETURN(rc);
+ return rc;
}
/* the LOV expects oa->o_id to be set to the LOV object id */
@@ -1042,11 +1028,10 @@ static int lov_create(const struct lu_env *env, struct obd_export *exp,
{
struct lov_obd *lov;
int rc = 0;
- ENTRY;
LASSERT(ea != NULL);
if (exp == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
if ((src_oa->o_valid & OBD_MD_FLFLAGS) &&
src_oa->o_flags == OBD_FL_DELORPHAN) {
@@ -1056,7 +1041,7 @@ static int lov_create(const struct lu_env *env, struct obd_export *exp,
lov = &exp->exp_obd->u.lov;
if (!lov->desc.ld_active_tgt_count)
- RETURN(-EIO);
+ return -EIO;
obd_getref(exp->exp_obd);
/* Recreate a specific object id at the given OST index */
@@ -1066,7 +1051,7 @@ static int lov_create(const struct lu_env *env, struct obd_export *exp,
}
obd_putref(exp->exp_obd);
- RETURN(rc);
+ return rc;
}
#define ASSERT_LSM_MAGIC(lsmp) \
@@ -1088,12 +1073,11 @@ static int lov_destroy(const struct lu_env *env, struct obd_export *exp,
struct list_head *pos;
struct lov_obd *lov;
int rc = 0, err = 0;
- ENTRY;
ASSERT_LSM_MAGIC(lsm);
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
if (oa->o_valid & OBD_MD_FLCOOKIE) {
LASSERT(oti);
@@ -1133,7 +1117,7 @@ static int lov_destroy(const struct lu_env *env, struct obd_export *exp,
err = lov_fini_destroy_set(set);
out:
obd_putref(exp->exp_obd);
- RETURN(rc ? rc : err);
+ return rc ? rc : err;
}
static int lov_getattr(const struct lu_env *env, struct obd_export *exp,
@@ -1144,19 +1128,18 @@ static int lov_getattr(const struct lu_env *env, struct obd_export *exp,
struct list_head *pos;
struct lov_obd *lov;
int err = 0, rc = 0;
- ENTRY;
LASSERT(oinfo);
ASSERT_LSM_MAGIC(oinfo->oi_md);
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
lov = &exp->exp_obd->u.lov;
rc = lov_prep_getattr_set(exp, oinfo, &set);
if (rc)
- RETURN(rc);
+ return rc;
list_for_each (pos, &set->set_list) {
req = list_entry(pos, struct lov_request, rq_link);
@@ -1182,7 +1165,7 @@ static int lov_getattr(const struct lu_env *env, struct obd_export *exp,
rc = lov_fini_getattr_set(set);
if (err)
rc = err;
- RETURN(rc);
+ return rc;
}
static int lov_getattr_interpret(struct ptlrpc_request_set *rqset,
@@ -1190,13 +1173,12 @@ static int lov_getattr_interpret(struct ptlrpc_request_set *rqset,
{
struct lov_request_set *lovset = (struct lov_request_set *)data;
int err;
- ENTRY;
/* don't do attribute merge if this aysnc op failed */
if (rc)
atomic_set(&lovset->set_completes, 0);
err = lov_fini_getattr_set(lovset);
- RETURN(rc ? rc : err);
+ return rc ? rc : err;
}
static int lov_getattr_async(struct obd_export *exp, struct obd_info *oinfo,
@@ -1207,19 +1189,18 @@ static int lov_getattr_async(struct obd_export *exp, struct obd_info *oinfo,
struct list_head *pos;
struct lov_request *req;
int rc = 0, err;
- ENTRY;
LASSERT(oinfo);
ASSERT_LSM_MAGIC(oinfo->oi_md);
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
lov = &exp->exp_obd->u.lov;
rc = lov_prep_getattr_set(exp, oinfo, &lovset);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_INFO, "objid "DOSTID": %ux%u byte stripes\n",
POSTID(&oinfo->oi_md->lsm_oi), oinfo->oi_md->lsm_stripe_count,
@@ -1249,13 +1230,13 @@ static int lov_getattr_async(struct obd_export *exp, struct obd_info *oinfo,
LASSERT (rqset->set_interpret == NULL);
rqset->set_interpret = lov_getattr_interpret;
rqset->set_arg = (void *)lovset;
- RETURN(rc);
+ return rc;
}
out:
if (rc)
atomic_set(&lovset->set_completes, 0);
err = lov_fini_getattr_set(lovset);
- RETURN(rc ? rc : err);
+ return rc ? rc : err;
}
static int lov_setattr(const struct lu_env *env, struct obd_export *exp,
@@ -1266,13 +1247,12 @@ static int lov_setattr(const struct lu_env *env, struct obd_export *exp,
struct list_head *pos;
struct lov_request *req;
int err = 0, rc = 0;
- ENTRY;
LASSERT(oinfo);
ASSERT_LSM_MAGIC(oinfo->oi_md);
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
/* for now, we only expect the following updates here */
LASSERT(!(oinfo->oi_oa->o_valid & ~(OBD_MD_FLID | OBD_MD_FLTYPE |
@@ -1285,7 +1265,7 @@ static int lov_setattr(const struct lu_env *env, struct obd_export *exp,
lov = &exp->exp_obd->u.lov;
rc = lov_prep_setattr_set(exp, oinfo, oti, &set);
if (rc)
- RETURN(rc);
+ return rc;
list_for_each (pos, &set->set_list) {
req = list_entry(pos, struct lov_request, rq_link);
@@ -1307,7 +1287,7 @@ static int lov_setattr(const struct lu_env *env, struct obd_export *exp,
err = lov_fini_setattr_set(set);
if (!rc)
rc = err;
- RETURN(rc);
+ return rc;
}
static int lov_setattr_interpret(struct ptlrpc_request_set *rqset,
@@ -1315,12 +1295,11 @@ static int lov_setattr_interpret(struct ptlrpc_request_set *rqset,
{
struct lov_request_set *lovset = (struct lov_request_set *)data;
int err;
- ENTRY;
if (rc)
atomic_set(&lovset->set_completes, 0);
err = lov_fini_setattr_set(lovset);
- RETURN(rc ? rc : err);
+ return rc ? rc : err;
}
/* If @oti is given, the request goes from MDS and responses from OSTs are not
@@ -1334,7 +1313,6 @@ static int lov_setattr_async(struct obd_export *exp, struct obd_info *oinfo,
struct list_head *pos;
struct lov_obd *lov;
int rc = 0;
- ENTRY;
LASSERT(oinfo);
ASSERT_LSM_MAGIC(oinfo->oi_md);
@@ -1344,12 +1322,12 @@ static int lov_setattr_async(struct obd_export *exp, struct obd_info *oinfo,
}
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
lov = &exp->exp_obd->u.lov;
rc = lov_prep_setattr_set(exp, oinfo, oti, &set);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_INFO, "objid "DOSTID": %ux%u byte stripes\n",
POSTID(&oinfo->oi_md->lsm_oi),
@@ -1384,14 +1362,14 @@ static int lov_setattr_async(struct obd_export *exp, struct obd_info *oinfo,
if (rc)
atomic_set(&set->set_completes, 0);
err = lov_fini_setattr_set(set);
- RETURN(rc ? rc : err);
+ return rc ? rc : err;
}
LASSERT(rqset->set_interpret == NULL);
rqset->set_interpret = lov_setattr_interpret;
rqset->set_arg = (void *)set;
- RETURN(0);
+ return 0;
}
static int lov_punch_interpret(struct ptlrpc_request_set *rqset,
@@ -1399,12 +1377,11 @@ static int lov_punch_interpret(struct ptlrpc_request_set *rqset,
{
struct lov_request_set *lovset = (struct lov_request_set *)data;
int err;
- ENTRY;
if (rc)
atomic_set(&lovset->set_completes, 0);
err = lov_fini_punch_set(lovset);
- RETURN(rc ? rc : err);
+ return rc ? rc : err;
}
/* FIXME: maybe we'll just make one node the authoritative attribute node, then
@@ -1419,18 +1396,17 @@ static int lov_punch(const struct lu_env *env, struct obd_export *exp,
struct list_head *pos;
struct lov_request *req;
int rc = 0;
- ENTRY;
LASSERT(oinfo);
ASSERT_LSM_MAGIC(oinfo->oi_md);
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
lov = &exp->exp_obd->u.lov;
rc = lov_prep_punch_set(exp, oinfo, oti, &set);
if (rc)
- RETURN(rc);
+ return rc;
list_for_each (pos, &set->set_list) {
req = list_entry(pos, struct lov_request, rq_link);
@@ -1450,14 +1426,14 @@ static int lov_punch(const struct lu_env *env, struct obd_export *exp,
if (rc || list_empty(&rqset->set_requests)) {
int err;
err = lov_fini_punch_set(set);
- RETURN(rc ? rc : err);
+ return rc ? rc : err;
}
LASSERT(rqset->set_interpret == NULL);
rqset->set_interpret = lov_punch_interpret;
rqset->set_arg = (void *)set;
- RETURN(0);
+ return 0;
}
static int lov_sync_interpret(struct ptlrpc_request_set *rqset,
@@ -1465,12 +1441,11 @@ static int lov_sync_interpret(struct ptlrpc_request_set *rqset,
{
struct lov_request_set *lovset = data;
int err;
- ENTRY;
if (rc)
atomic_set(&lovset->set_completes, 0);
err = lov_fini_sync_set(lovset);
- RETURN(rc ?: err);
+ return rc ?: err;
}
static int lov_sync(const struct lu_env *env, struct obd_export *exp,
@@ -1482,18 +1457,17 @@ static int lov_sync(const struct lu_env *env, struct obd_export *exp,
struct list_head *pos;
struct lov_request *req;
int rc = 0;
- ENTRY;
ASSERT_LSM_MAGIC(oinfo->oi_md);
LASSERT(rqset != NULL);
if (!exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
lov = &exp->exp_obd->u.lov;
rc = lov_prep_sync_set(exp, oinfo, start, end, &set);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_INFO, "fsync objid "DOSTID" ["LPX64", "LPX64"]\n",
POSTID(&set->set_oi->oi_oa->o_oi), start, end);
@@ -1519,14 +1493,14 @@ static int lov_sync(const struct lu_env *env, struct obd_export *exp,
if (rc || list_empty(&rqset->set_requests)) {
int err = lov_fini_sync_set(set);
- RETURN(rc ?: err);
+ return rc ?: err;
}
LASSERT(rqset->set_interpret == NULL);
rqset->set_interpret = lov_sync_interpret;
rqset->set_arg = (void *)set;
- RETURN(0);
+ return 0;
}
static int lov_brw_check(struct lov_obd *lov, struct obd_info *lov_oinfo,
@@ -1571,18 +1545,17 @@ static int lov_brw(int cmd, struct obd_export *exp, struct obd_info *oinfo,
struct list_head *pos;
struct lov_obd *lov = &exp->exp_obd->u.lov;
int err, rc = 0;
- ENTRY;
ASSERT_LSM_MAGIC(oinfo->oi_md);
if (cmd == OBD_BRW_CHECK) {
rc = lov_brw_check(lov, oinfo, oa_bufs, pga);
- RETURN(rc);
+ return rc;
}
rc = lov_prep_brw_set(exp, oinfo, oa_bufs, pga, oti, &set);
if (rc)
- RETURN(rc);
+ return rc;
list_for_each (pos, &set->set_list) {
struct obd_export *sub_exp;
@@ -1601,16 +1574,16 @@ static int lov_brw(int cmd, struct obd_export *exp, struct obd_info *oinfo,
err = lov_fini_brw_set(set);
if (!rc)
rc = err;
- RETURN(rc);
+ return rc;
}
static int lov_enqueue_interpret(struct ptlrpc_request_set *rqset,
void *data, int rc)
{
struct lov_request_set *lovset = (struct lov_request_set *)data;
- ENTRY;
+
rc = lov_fini_enqueue_set(lovset, lovset->set_ei->ei_mode, rc, rqset);
- RETURN(rc);
+ return rc;
}
static int lov_enqueue(struct obd_export *exp, struct obd_info *oinfo,
@@ -1623,7 +1596,6 @@ static int lov_enqueue(struct obd_export *exp, struct obd_info *oinfo,
struct list_head *pos;
struct lov_obd *lov;
ldlm_error_t rc;
- ENTRY;
LASSERT(oinfo);
ASSERT_LSM_MAGIC(oinfo->oi_md);
@@ -1633,12 +1605,12 @@ static int lov_enqueue(struct obd_export *exp, struct obd_info *oinfo,
LASSERT((oinfo->oi_flags & LDLM_FL_REPLAY) == 0);
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
lov = &exp->exp_obd->u.lov;
rc = lov_prep_enqueue_set(exp, oinfo, einfo, &set);
if (rc)
- RETURN(rc);
+ return rc;
list_for_each (pos, &set->set_list) {
req = list_entry(pos, struct lov_request, rq_link);
@@ -1654,11 +1626,11 @@ static int lov_enqueue(struct obd_export *exp, struct obd_info *oinfo,
LASSERT(rqset->set_interpret == NULL);
rqset->set_interpret = lov_enqueue_interpret;
rqset->set_arg = (void *)set;
- RETURN(rc);
+ return rc;
}
out:
rc = lov_fini_enqueue_set(set, mode, rc, rqset);
- RETURN(rc);
+ return rc;
}
static int lov_change_cbdata(struct obd_export *exp,
@@ -1667,12 +1639,11 @@ static int lov_change_cbdata(struct obd_export *exp,
{
struct lov_obd *lov;
int rc = 0, i;
- ENTRY;
ASSERT_LSM_MAGIC(lsm);
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
lov = &exp->exp_obd->u.lov;
for (i = 0; i < lsm->lsm_stripe_count; i++) {
@@ -1689,7 +1660,7 @@ static int lov_change_cbdata(struct obd_export *exp,
rc = obd_change_cbdata(lov->lov_tgts[loi->loi_ost_idx]->ltd_exp,
&submd, it, data);
}
- RETURN(rc);
+ return rc;
}
/* find any ldlm lock of the inode in lov
@@ -1702,12 +1673,11 @@ static int lov_find_cbdata(struct obd_export *exp,
{
struct lov_obd *lov;
int rc = 0, i;
- ENTRY;
ASSERT_LSM_MAGIC(lsm);
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
lov = &exp->exp_obd->u.lov;
for (i = 0; i < lsm->lsm_stripe_count; i++) {
@@ -1723,9 +1693,9 @@ static int lov_find_cbdata(struct obd_export *exp,
rc = obd_find_cbdata(lov->lov_tgts[loi->loi_ost_idx]->ltd_exp,
&submd, it, data);
if (rc != 0)
- RETURN(rc);
+ return rc;
}
- RETURN(rc);
+ return rc;
}
static int lov_cancel(struct obd_export *exp, struct lov_stripe_md *lsm,
@@ -1738,18 +1708,17 @@ static int lov_cancel(struct obd_export *exp, struct lov_stripe_md *lsm,
struct lov_obd *lov;
struct lustre_handle *lov_lockhp;
int err = 0, rc = 0;
- ENTRY;
ASSERT_LSM_MAGIC(lsm);
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
LASSERT(lockh);
lov = &exp->exp_obd->u.lov;
rc = lov_prep_cancel_set(exp, &oinfo, lsm, mode, lockh, &set);
if (rc)
- RETURN(rc);
+ return rc;
list_for_each(pos, &set->set_list) {
req = list_entry(pos, struct lov_request, rq_link);
@@ -1769,7 +1738,7 @@ static int lov_cancel(struct obd_export *exp, struct lov_stripe_md *lsm,
}
lov_fini_cancel_set(set);
- RETURN(err);
+ return err;
}
static int lov_cancel_unused(struct obd_export *exp,
@@ -1778,10 +1747,9 @@ static int lov_cancel_unused(struct obd_export *exp,
{
struct lov_obd *lov;
int rc = 0, i;
- ENTRY;
if (!exp || !exp->exp_obd)
- RETURN(-ENODEV);
+ return -ENODEV;
lov = &exp->exp_obd->u.lov;
if (lsm == NULL) {
@@ -1795,7 +1763,7 @@ static int lov_cancel_unused(struct obd_export *exp,
if (!rc)
rc = err;
}
- RETURN(rc);
+ return rc;
}
ASSERT_LSM_MAGIC(lsm);
@@ -1827,20 +1795,19 @@ static int lov_cancel_unused(struct obd_export *exp,
rc = err;
}
}
- RETURN(rc);
+ return rc;
}
int lov_statfs_interpret(struct ptlrpc_request_set *rqset, void *data, int rc)
{
struct lov_request_set *lovset = (struct lov_request_set *)data;
int err;
- ENTRY;
if (rc)
atomic_set(&lovset->set_completes, 0);
err = lov_fini_statfs_set(lovset);
- RETURN(rc ? rc : err);
+ return rc ? rc : err;
}
static int lov_statfs_async(struct obd_export *exp, struct obd_info *oinfo,
@@ -1852,7 +1819,6 @@ static int lov_statfs_async(struct obd_export *exp, struct obd_info *oinfo,
struct list_head *pos;
struct lov_obd *lov;
int rc = 0;
- ENTRY;
LASSERT(oinfo != NULL);
LASSERT(oinfo->oi_osfs != NULL);
@@ -1860,7 +1826,7 @@ static int lov_statfs_async(struct obd_export *exp, struct obd_info *oinfo,
lov = &obd->u.lov;
rc = lov_prep_statfs_set(obd, oinfo, &set);
if (rc)
- RETURN(rc);
+ return rc;
list_for_each (pos, &set->set_list) {
req = list_entry(pos, struct lov_request, rq_link);
@@ -1875,13 +1841,13 @@ static int lov_statfs_async(struct obd_export *exp, struct obd_info *oinfo,
if (rc)
atomic_set(&set->set_completes, 0);
err = lov_fini_statfs_set(set);
- RETURN(rc ? rc : err);
+ return rc ? rc : err;
}
LASSERT(rqset->set_interpret == NULL);
rqset->set_interpret = lov_statfs_interpret;
rqset->set_arg = (void *)set;
- RETURN(0);
+ return 0;
}
static int lov_statfs(const struct lu_env *env, struct obd_export *exp,
@@ -1890,14 +1856,12 @@ static int lov_statfs(const struct lu_env *env, struct obd_export *exp,
struct ptlrpc_request_set *set = NULL;
struct obd_info oinfo = { { { 0 } } };
int rc = 0;
- ENTRY;
-
/* for obdclass we forbid using obd_statfs_rqset, but prefer using async
* statfs requests */
set = ptlrpc_prep_set();
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
oinfo.oi_osfs = osfs;
oinfo.oi_flags = flags;
@@ -1906,7 +1870,7 @@ static int lov_statfs(const struct lu_env *env, struct obd_export *exp,
rc = ptlrpc_set_wait(set);
ptlrpc_set_destroy(set);
- RETURN(rc);
+ return rc;
}
static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
@@ -1916,7 +1880,6 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
struct lov_obd *lov = &obddev->u.lov;
int i = 0, rc = 0, count = lov->desc.ld_tgt_count;
struct obd_uuid *uuidp;
- ENTRY;
switch (cmd) {
case IOC_OBD_STATFS: {
@@ -1928,23 +1891,23 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
memcpy(&index, data->ioc_inlbuf2, sizeof(__u32));
if ((index >= count))
- RETURN(-ENODEV);
+ return -ENODEV;
if (!lov->lov_tgts[index])
/* Try again with the next index */
- RETURN(-EAGAIN);
+ return -EAGAIN;
if (!lov->lov_tgts[index]->ltd_active)
- RETURN(-ENODATA);
+ return -ENODATA;
osc_obd = class_exp2obd(lov->lov_tgts[index]->ltd_exp);
if (!osc_obd)
- RETURN(-EINVAL);
+ return -EINVAL;
/* copy UUID */
if (copy_to_user(data->ioc_pbuf2, obd2cli_tgt(osc_obd),
min((int) data->ioc_plen2,
(int) sizeof(struct obd_uuid))))
- RETURN(-EFAULT);
+ return -EFAULT;
flags = uarg ? *(__u32*)uarg : 0;
/* got statfs data */
@@ -1952,11 +1915,11 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
flags);
if (rc)
- RETURN(rc);
+ return rc;
if (copy_to_user(data->ioc_pbuf1, &stat_buf,
min((int) data->ioc_plen1,
(int) sizeof(stat_buf))))
- RETURN(-EFAULT);
+ return -EFAULT;
break;
}
case OBD_IOC_LOV_GET_CONFIG: {
@@ -1967,23 +1930,23 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
len = 0;
if (obd_ioctl_getdata(&buf, &len, (void *)uarg))
- RETURN(-EINVAL);
+ return -EINVAL;
data = (struct obd_ioctl_data *)buf;
if (sizeof(*desc) > data->ioc_inllen1) {
obd_ioctl_freedata(buf, len);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (sizeof(uuidp->uuid) * count > data->ioc_inllen2) {
obd_ioctl_freedata(buf, len);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (sizeof(__u32) * count > data->ioc_inllen3) {
obd_ioctl_freedata(buf, len);
- RETURN(-EINVAL);
+ return -EINVAL;
}
desc = (struct lov_desc *)data->ioc_inlbuf1;
@@ -2020,11 +1983,11 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
if (qctl->qc_valid == QC_OSTIDX) {
if (qctl->qc_idx < 0 || count <= qctl->qc_idx)
- RETURN(-EINVAL);
+ return -EINVAL;
tgt = lov->lov_tgts[qctl->qc_idx];
if (!tgt || !tgt->ltd_exp)
- RETURN(-EINVAL);
+ return -EINVAL;
} else if (qctl->qc_valid == QC_UUID) {
for (i = 0; i < count; i++) {
tgt = lov->lov_tgts[i];
@@ -2034,21 +1997,21 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
continue;
if (tgt->ltd_exp == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
break;
}
} else {
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (i >= count)
- RETURN(-EAGAIN);
+ return -EAGAIN;
LASSERT(tgt && tgt->ltd_exp);
OBD_ALLOC_PTR(oqctl);
if (!oqctl)
- RETURN(-ENOMEM);
+ return -ENOMEM;
QCTL_COPY(oqctl, qctl);
rc = obd_quotactl(tgt->ltd_exp, oqctl);
@@ -2064,7 +2027,7 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
int set = 0;
if (count == 0)
- RETURN(-ENOTTY);
+ return -ENOTTY;
for (i = 0; i < count; i++) {
int err;
@@ -2081,7 +2044,7 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
err = obd_iocontrol(cmd, lov->lov_tgts[i]->ltd_exp,
len, karg, uarg);
if (err == -ENODATA && cmd == OBD_IOC_POLL_QUOTACHECK) {
- RETURN(err);
+ return err;
} else if (err) {
if (lov->lov_tgts[i]->ltd_active) {
CDEBUG(err == -ENOTTY ?
@@ -2102,7 +2065,7 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
}
}
- RETURN(rc);
+ return rc;
}
#define FIEMAP_BUFFER_SIZE 4096
@@ -2259,7 +2222,7 @@ static int lov_fiemap(struct lov_obd *lov, __u32 keylen, void *key,
int cur_stripe = 0, cur_stripe_wrap = 0, stripe_count;
unsigned int buffer_size = FIEMAP_BUFFER_SIZE;
- if (lsm == NULL)
+ if (!lsm_has_objects(lsm))
GOTO(out, rc = 0);
if (fiemap_count_to_size(fm_key->fiemap.fm_extent_count) < buffer_size)
@@ -2469,10 +2432,9 @@ static int lov_get_info(const struct lu_env *env, struct obd_export *exp,
struct obd_device *obddev = class_exp2obd(exp);
struct lov_obd *lov = &obddev->u.lov;
int i, rc;
- ENTRY;
if (!vallen || !val)
- RETURN(-EFAULT);
+ return -EFAULT;
obd_getref(obddev);
@@ -2553,7 +2515,7 @@ static int lov_get_info(const struct lu_env *env, struct obd_export *exp,
out:
obd_putref(obddev);
- RETURN(rc);
+ return rc;
}
static int lov_set_info_async(const struct lu_env *env, struct obd_export *exp,
@@ -2568,14 +2530,13 @@ static int lov_set_info_async(const struct lu_env *env, struct obd_export *exp,
unsigned incr, check_uuid,
do_inactive, no_set;
unsigned next_id = 0, mds_con = 0, capa = 0;
- ENTRY;
incr = check_uuid = do_inactive = no_set = 0;
if (set == NULL) {
no_set = 1;
set = ptlrpc_prep_set();
if (!set)
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
obd_getref(obddev);
@@ -2667,7 +2628,7 @@ static int lov_set_info_async(const struct lu_env *env, struct obd_export *exp,
rc = err;
ptlrpc_set_destroy(set);
}
- RETURN(rc);
+ return rc;
}
static int lov_extent_calc(struct obd_export *exp, struct lov_stripe_md *lsm,
@@ -2691,7 +2652,7 @@ static int lov_extent_calc(struct obd_export *exp, struct lov_stripe_md *lsm,
LBUG();
}
- RETURN(0);
+ return 0;
}
void lov_stripe_lock(struct lov_stripe_md *md)
@@ -2719,7 +2680,6 @@ static int lov_quotactl(struct obd_device *obd, struct obd_export *exp,
__u64 curspace = 0;
__u64 bhardlimit = 0;
int i, rc = 0;
- ENTRY;
if (oqctl->qc_cmd != LUSTRE_Q_QUOTAON &&
oqctl->qc_cmd != LUSTRE_Q_QUOTAOFF &&
@@ -2728,7 +2688,7 @@ static int lov_quotactl(struct obd_device *obd, struct obd_export *exp,
oqctl->qc_cmd != LUSTRE_Q_SETQUOTA &&
oqctl->qc_cmd != Q_FINVALIDATE) {
CERROR("bad quota opc %x for lov obd", oqctl->qc_cmd);
- RETURN(-EFAULT);
+ return -EFAULT;
}
/* for lov tgt */
@@ -2770,7 +2730,7 @@ static int lov_quotactl(struct obd_device *obd, struct obd_export *exp,
oqctl->qc_dqblk.dqb_curspace = curspace;
oqctl->qc_dqblk.dqb_bhardlimit = bhardlimit;
}
- RETURN(rc);
+ return rc;
}
static int lov_quotacheck(struct obd_device *obd, struct obd_export *exp,
@@ -2778,7 +2738,6 @@ static int lov_quotacheck(struct obd_device *obd, struct obd_export *exp,
{
struct lov_obd *lov = &obd->u.lov;
int i, rc = 0;
- ENTRY;
obd_getref(obd);
@@ -2814,7 +2773,7 @@ static int lov_quotacheck(struct obd_device *obd, struct obd_export *exp,
out:
obd_putref(obd);
- RETURN(rc);
+ return rc;
}
struct obd_ops lov_obd_ops = {
@@ -2870,7 +2829,6 @@ int __init lov_init(void)
{
struct lprocfs_static_vars lvars = { 0 };
int rc;
- ENTRY;
/* print an address of _any_ initialized kernel symbol from this
* module, to allow debugging with gdb that doesn't support data
@@ -2898,7 +2856,7 @@ int __init lov_init(void)
lu_kmem_fini(lov_caches);
}
- RETURN(rc);
+ return rc;
}
static void /*__exit*/ lov_exit(void)
@@ -2912,5 +2870,7 @@ static void /*__exit*/ lov_exit(void)
MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Logical Object Volume OBD driver");
MODULE_LICENSE("GPL");
+MODULE_VERSION(LUSTRE_VERSION_STRING);
-cfs_module(lov, LUSTRE_VERSION_STRING, lov_init, lov_exit);
+module_init(lov_init);
+module_exit(lov_exit);
diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c
index aa8ae80e812..84e55ce3ccd 100644
--- a/drivers/staging/lustre/lustre/lov/lov_object.c
+++ b/drivers/staging/lustre/lustre/lov/lov_object.c
@@ -116,10 +116,9 @@ static struct cl_object *lov_sub_find(const struct lu_env *env,
{
struct lu_object *o;
- ENTRY;
o = lu_object_find_at(env, cl2lu_dev(dev), fid, &conf->coc_lu);
LASSERT(ergo(!IS_ERR(o), o->lo_dev->ld_type == &lovsub_device_type));
- RETURN(lu2cl(o));
+ return lu2cl(o);
}
static int lov_init_sub(const struct lu_env *env, struct lov_object *lov,
@@ -204,8 +203,6 @@ static int lov_init_raid0(const struct lu_env *env,
struct lu_fid *ofid = &lti->lti_fid;
struct lov_layout_raid0 *r0 = &state->raid0;
- ENTRY;
-
if (lsm->lsm_magic != LOV_MAGIC_V1 && lsm->lsm_magic != LOV_MAGIC_V3) {
dump_lsm(D_ERROR, lsm);
LASSERTF(0, "magic mismatch, expected %d/%d, actual %d.\n",
@@ -255,13 +252,28 @@ static int lov_init_raid0(const struct lu_env *env,
} else
result = -ENOMEM;
out:
- RETURN(result);
+ return result;
+}
+
+static int lov_init_released(const struct lu_env *env,
+ struct lov_device *dev, struct lov_object *lov,
+ const struct cl_object_conf *conf,
+ union lov_layout_state *state)
+{
+ struct lov_stripe_md *lsm = conf->u.coc_md->lsm;
+
+ LASSERT(lsm != NULL);
+ LASSERT(lsm_is_released(lsm));
+ LASSERT(lov->lo_lsm == NULL);
+
+ lov->lo_lsm = lsm_addref(lsm);
+ return 0;
}
static int lov_delete_empty(const struct lu_env *env, struct lov_object *lov,
union lov_layout_state *state)
{
- LASSERT(lov->lo_type == LLT_EMPTY);
+ LASSERT(lov->lo_type == LLT_EMPTY || lov->lo_type == LLT_RELEASED);
lov_layout_wait(env, lov);
@@ -323,8 +335,6 @@ static int lov_delete_raid0(const struct lu_env *env, struct lov_object *lov,
struct lov_stripe_md *lsm = lov->lo_lsm;
int i;
- ENTRY;
-
dump_lsm(D_INODE, lsm);
lov_layout_wait(env, lov);
@@ -343,20 +353,19 @@ static int lov_delete_raid0(const struct lu_env *env, struct lov_object *lov,
}
}
cl_object_prune(env, &lov->lo_cl);
- RETURN(0);
+ return 0;
}
static void lov_fini_empty(const struct lu_env *env, struct lov_object *lov,
union lov_layout_state *state)
{
- LASSERT(lov->lo_type == LLT_EMPTY);
+ LASSERT(lov->lo_type == LLT_EMPTY || lov->lo_type == LLT_RELEASED);
}
static void lov_fini_raid0(const struct lu_env *env, struct lov_object *lov,
union lov_layout_state *state)
{
struct lov_layout_raid0 *r0 = &state->raid0;
- ENTRY;
if (r0->lo_sub != NULL) {
OBD_FREE_LARGE(r0->lo_sub, r0->lo_nr * sizeof r0->lo_sub[0]);
@@ -365,8 +374,13 @@ static void lov_fini_raid0(const struct lu_env *env, struct lov_object *lov,
dump_lsm(D_INODE, lov->lo_lsm);
lov_free_memmd(&lov->lo_lsm);
+}
- EXIT;
+static void lov_fini_released(const struct lu_env *env, struct lov_object *lov,
+ union lov_layout_state *state)
+{
+ dump_lsm(D_INODE, lov->lo_lsm);
+ lov_free_memmd(&lov->lo_lsm);
}
static int lov_print_empty(const struct lu_env *env, void *cookie,
@@ -400,6 +414,13 @@ static int lov_print_raid0(const struct lu_env *env, void *cookie,
return 0;
}
+static int lov_print_released(const struct lu_env *env, void *cookie,
+ lu_printer_t p, const struct lu_object *o)
+{
+ (*p)(env, cookie, "released\n");
+ return 0;
+}
+
/**
* Implements cl_object_operations::coo_attr_get() method for an object
* without stripes (LLT_EMPTY layout type).
@@ -422,8 +443,6 @@ static int lov_attr_get_raid0(const struct lu_env *env, struct cl_object *obj,
struct cl_attr *lov_attr = &r0->lo_attr;
int result = 0;
- ENTRY;
-
/* this is called w/o holding type guard mutex, so it must be inside
* an on going IO otherwise lsm may be replaced.
* LU-2117: it turns out there exists one exception. For mmaped files,
@@ -478,7 +497,7 @@ static int lov_attr_get_raid0(const struct lu_env *env, struct cl_object *obj,
if (attr->cat_mtime < lov_attr->cat_mtime)
attr->cat_mtime = lov_attr->cat_mtime;
}
- RETURN(result);
+ return result;
}
const static struct lov_layout_operations lov_dispatch[] = {
@@ -503,10 +522,20 @@ const static struct lov_layout_operations lov_dispatch[] = {
.llo_lock_init = lov_lock_init_raid0,
.llo_io_init = lov_io_init_raid0,
.llo_getattr = lov_attr_get_raid0
+ },
+ [LLT_RELEASED] = {
+ .llo_init = lov_init_released,
+ .llo_delete = lov_delete_empty,
+ .llo_fini = lov_fini_released,
+ .llo_install = lov_install_empty,
+ .llo_print = lov_print_released,
+ .llo_page_init = lov_page_init_empty,
+ .llo_lock_init = lov_lock_init_empty,
+ .llo_io_init = lov_io_init_released,
+ .llo_getattr = lov_attr_get_empty
}
};
-
/**
* Performs a double-dispatch based on the layout type of an object.
*/
@@ -520,6 +549,18 @@ const static struct lov_layout_operations lov_dispatch[] = {
lov_dispatch[__llt].op(__VA_ARGS__); \
})
+/**
+ * Return lov_layout_type associated with a given lsm
+ */
+enum lov_layout_type lov_type(struct lov_stripe_md *lsm)
+{
+ if (lsm == NULL)
+ return LLT_EMPTY;
+ if (lsm_is_released(lsm))
+ return LLT_RELEASED;
+ return LLT_RAID0;
+}
+
static inline void lov_conf_freeze(struct lov_object *lov)
{
if (lov->lo_owner != current)
@@ -581,7 +622,6 @@ static void lov_conf_unlock(struct lov_object *lov)
static int lov_layout_wait(const struct lu_env *env, struct lov_object *lov)
{
struct l_wait_info lwi = { 0 };
- ENTRY;
while (atomic_read(&lov->lo_active_ios) > 0) {
CDEBUG(D_INODE, "file:"DFID" wait for active IO, now: %d.\n",
@@ -591,7 +631,7 @@ static int lov_layout_wait(const struct lu_env *env, struct lov_object *lov)
l_wait_event(lov->lo_waitq,
atomic_read(&lov->lo_active_ios) == 0, &lwi);
}
- RETURN(0);
+ return 0;
}
static int lov_layout_change(const struct lu_env *unused,
@@ -608,19 +648,18 @@ static int lov_layout_change(const struct lu_env *unused,
void *cookie;
struct lu_env *env;
int refcheck;
- ENTRY;
LASSERT(0 <= lov->lo_type && lov->lo_type < ARRAY_SIZE(lov_dispatch));
- if (conf->u.coc_md != NULL && conf->u.coc_md->lsm != NULL)
- llt = LLT_RAID0; /* only raid0 is supported. */
+ if (conf->u.coc_md != NULL)
+ llt = lov_type(conf->u.coc_md->lsm);
LASSERT(0 <= llt && llt < ARRAY_SIZE(lov_dispatch));
cookie = cl_env_reenter();
env = cl_env_get(&refcheck);
if (IS_ERR(env)) {
cl_env_reexit(cookie);
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
}
old_ops = &lov_dispatch[lov->lo_type];
@@ -650,7 +689,7 @@ static int lov_layout_change(const struct lu_env *unused,
cl_env_put(env, &refcheck);
cl_env_reexit(cookie);
- RETURN(result);
+ return result;
}
/*****************************************************************************
@@ -658,7 +697,6 @@ static int lov_layout_change(const struct lu_env *unused,
* Lov object operations.
*
*/
-
int lov_object_init(const struct lu_env *env, struct lu_object *obj,
const struct lu_object_conf *conf)
{
@@ -669,7 +707,6 @@ int lov_object_init(const struct lu_env *env, struct lu_object *obj,
const struct lov_layout_operations *ops;
int result;
- ENTRY;
init_rwsem(&lov->lo_type_guard);
atomic_set(&lov->lo_active_ios, 0);
init_waitqueue_head(&lov->lo_waitq);
@@ -677,21 +714,20 @@ int lov_object_init(const struct lu_env *env, struct lu_object *obj,
cl_object_page_init(lu2cl(obj), sizeof(struct lov_page));
/* no locking is necessary, as object is being created */
- lov->lo_type = cconf->u.coc_md->lsm != NULL ? LLT_RAID0 : LLT_EMPTY;
+ lov->lo_type = lov_type(cconf->u.coc_md->lsm);
ops = &lov_dispatch[lov->lo_type];
result = ops->llo_init(env, dev, lov, cconf, set);
if (result == 0)
ops->llo_install(env, lov, set);
- RETURN(result);
+ return result;
}
static int lov_conf_set(const struct lu_env *env, struct cl_object *obj,
const struct cl_object_conf *conf)
{
- struct lov_stripe_md *lsm = NULL;
- struct lov_object *lov = cl2lov(obj);
- int result = 0;
- ENTRY;
+ struct lov_stripe_md *lsm = NULL;
+ struct lov_object *lov = cl2lov(obj);
+ int result = 0;
lov_conf_lock(lov);
if (conf->coc_opc == OBJECT_CONF_INVALIDATE) {
@@ -728,31 +764,26 @@ static int lov_conf_set(const struct lu_env *env, struct cl_object *obj,
}
lov->lo_layout_invalid = lov_layout_change(env, lov, conf);
- EXIT;
out:
lov_conf_unlock(lov);
- RETURN(result);
+ return result;
}
static void lov_object_delete(const struct lu_env *env, struct lu_object *obj)
{
struct lov_object *lov = lu2lov(obj);
- ENTRY;
LOV_2DISPATCH_VOID(lov, llo_delete, env, lov, &lov->u);
- EXIT;
}
static void lov_object_free(const struct lu_env *env, struct lu_object *obj)
{
struct lov_object *lov = lu2lov(obj);
- ENTRY;
LOV_2DISPATCH_VOID(lov, llo_fini, env, lov, &lov->u);
lu_object_fini(obj);
OBD_SLAB_FREE_PTR(lov, lov_object_kmem);
- EXIT;
}
static int lov_object_print(const struct lu_env *env, void *cookie,
@@ -835,7 +866,6 @@ struct lu_object *lov_object_alloc(const struct lu_env *env,
struct lov_object *lov;
struct lu_object *obj;
- ENTRY;
OBD_SLAB_ALLOC_PTR_GFP(lov, lov_object_kmem, __GFP_IO);
if (lov != NULL) {
obj = lov2lu(lov);
@@ -850,7 +880,7 @@ struct lu_object *lov_object_alloc(const struct lu_env *env,
obj->lo_ops = &lov_lu_obj_ops;
} else
obj = NULL;
- RETURN(obj);
+ return obj;
}
struct lov_stripe_md *lov_lsm_addref(struct lov_object *lov)
@@ -906,7 +936,6 @@ int lov_read_and_clear_async_rc(struct cl_object *clob)
{
struct lu_object *luobj;
int rc = 0;
- ENTRY;
luobj = lu_object_locate(&cl_object_header(clob)->coh_lu,
&lov_device_type);
@@ -928,6 +957,7 @@ int lov_read_and_clear_async_rc(struct cl_object *clob)
loi->loi_ar.ar_rc = 0;
}
}
+ case LLT_RELEASED:
case LLT_EMPTY:
break;
default:
@@ -935,7 +965,7 @@ int lov_read_and_clear_async_rc(struct cl_object *clob)
}
lov_conf_thaw(lov);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(lov_read_and_clear_async_rc);
diff --git a/drivers/staging/lustre/lustre/lov/lov_offset.c b/drivers/staging/lustre/lustre/lov/lov_offset.c
index f62b7e53b66..04863a7c5e0 100644
--- a/drivers/staging/lustre/lustre/lov/lov_offset.c
+++ b/drivers/staging/lustre/lustre/lov/lov_offset.c
@@ -52,10 +52,9 @@ obd_size lov_stripe_size(struct lov_stripe_md *lsm, obd_size ost_size,
obd_off swidth;
obd_size lov_size;
int magic = lsm->lsm_magic;
- ENTRY;
if (ost_size == 0)
- RETURN(0);
+ return 0;
LASSERT(lsm_op_find(magic) != NULL);
lsm_op_find(magic)->lsm_stripe_by_index(lsm, &stripeno, NULL, &swidth);
@@ -67,7 +66,7 @@ obd_size lov_stripe_size(struct lov_stripe_md *lsm, obd_size ost_size,
else
lov_size = (ost_size - 1) * swidth + (stripeno + 1) * ssize;
- RETURN(lov_size);
+ return lov_size;
}
/* we have an offset in file backed by an lov and want to find out where
diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c
index 492948aad68..55ec26778f8 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pack.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pack.c
@@ -143,7 +143,6 @@ int lov_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
int lmm_size, lmm_magic;
int i;
int cplen = 0;
- ENTRY;
if (lsm) {
lmm_magic = lsm->lsm_magic;
@@ -159,7 +158,7 @@ int lov_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
(lmm_magic != LOV_MAGIC_V3)) {
CERROR("bad mem LOV MAGIC: 0x%08X != 0x%08X nor 0x%08X\n",
lmm_magic, LOV_MAGIC_V1, LOV_MAGIC_V3);
- RETURN(-EINVAL);
+ return -EINVAL;
}
@@ -168,10 +167,12 @@ int lov_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
* to the actual number of OSTs in this filesystem. */
if (!lmmp) {
stripe_count = lov_get_stripecnt(lov, lmm_magic,
- lsm->lsm_stripe_count);
+ lsm->lsm_stripe_count);
lsm->lsm_stripe_count = stripe_count;
- } else {
+ } else if (!lsm_is_released(lsm)) {
stripe_count = lsm->lsm_stripe_count;
+ } else {
+ stripe_count = 0;
}
} else {
/* No need to allocate more than maximum supported stripes.
@@ -188,20 +189,20 @@ int lov_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
lmm_size = lov_mds_md_size(stripe_count, lmm_magic);
if (!lmmp)
- RETURN(lmm_size);
+ return lmm_size;
if (*lmmp && !lsm) {
stripe_count = le16_to_cpu((*lmmp)->lmm_stripe_count);
lmm_size = lov_mds_md_size(stripe_count, lmm_magic);
OBD_FREE_LARGE(*lmmp, lmm_size);
*lmmp = NULL;
- RETURN(0);
+ return 0;
}
if (!*lmmp) {
OBD_ALLOC_LARGE(*lmmp, lmm_size);
if (!*lmmp)
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
CDEBUG(D_INFO, "lov_packmd: LOV_MAGIC 0x%08X, lmm_size = %d \n",
@@ -215,7 +216,7 @@ int lov_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
lmmv1->lmm_magic = cpu_to_le32(LOV_MAGIC_V1);
if (!lsm)
- RETURN(lmm_size);
+ return lmm_size;
/* lmmv1 and lmmv3 point to the same struct and have the
* same first fields
@@ -229,7 +230,7 @@ int lov_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
cplen = strlcpy(lmmv3->lmm_pool_name, lsm->lsm_pool_name,
sizeof(lmmv3->lmm_pool_name));
if (cplen >= sizeof(lmmv3->lmm_pool_name))
- RETURN(-E2BIG);
+ return -E2BIG;
lmm_objects = lmmv3->lmm_objects;
} else {
lmm_objects = lmmv1->lmm_objects;
@@ -246,7 +247,7 @@ int lov_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
lmm_objects[i].l_ost_idx = cpu_to_le32(loi->loi_ost_idx);
}
- RETURN(lmm_size);
+ return lmm_size;
}
/* Find the max stripecount we should use */
@@ -307,14 +308,13 @@ int lov_alloc_memmd(struct lov_stripe_md **lsmp, __u16 stripe_count,
int pattern, int magic)
{
int i, lsm_size;
- ENTRY;
CDEBUG(D_INFO, "alloc lsm, stripe_count %d\n", stripe_count);
*lsmp = lsm_alloc_plain(stripe_count, &lsm_size);
if (!*lsmp) {
CERROR("can't allocate lsmp stripe_count %d\n", stripe_count);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
atomic_set(&(*lsmp)->lsm_refc, 1);
@@ -325,12 +325,13 @@ int lov_alloc_memmd(struct lov_stripe_md **lsmp, __u16 stripe_count,
(*lsmp)->lsm_pattern = pattern;
(*lsmp)->lsm_pool_name[0] = '\0';
(*lsmp)->lsm_layout_gen = 0;
- (*lsmp)->lsm_oinfo[0]->loi_ost_idx = ~0;
+ if (stripe_count > 0)
+ (*lsmp)->lsm_oinfo[0]->loi_ost_idx = ~0;
for (i = 0; i < stripe_count; i++)
loi_init((*lsmp)->lsm_oinfo[i]);
- RETURN(lsm_size);
+ return lsm_size;
}
int lov_free_memmd(struct lov_stripe_md **lsmp)
@@ -359,13 +360,13 @@ int lov_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
int rc = 0, lsm_size;
__u16 stripe_count;
__u32 magic;
- ENTRY;
+ __u32 pattern;
/* If passed an MDS struct use values from there, otherwise defaults */
if (lmm) {
rc = lov_verify_lmm(lmm, lmm_bytes, &stripe_count);
if (rc)
- RETURN(rc);
+ return rc;
magic = le32_to_cpu(lmm->lmm_magic);
} else {
magic = LOV_MAGIC;
@@ -376,31 +377,31 @@ int lov_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
if (!lsmp) {
/* XXX LOV STACKING call into osc for sizes */
LBUG();
- RETURN(lov_stripe_md_size(stripe_count));
+ return lov_stripe_md_size(stripe_count);
}
/* If we are passed an allocated struct but nothing to unpack, free */
if (*lsmp && !lmm) {
lov_free_memmd(lsmp);
- RETURN(0);
+ return 0;
}
- lsm_size = lov_alloc_memmd(lsmp, stripe_count, LOV_PATTERN_RAID0,
- magic);
+ pattern = le32_to_cpu(lmm->lmm_pattern);
+ lsm_size = lov_alloc_memmd(lsmp, stripe_count, pattern, magic);
if (lsm_size < 0)
- RETURN(lsm_size);
+ return lsm_size;
/* If we are passed a pointer but nothing to unpack, we only alloc */
if (!lmm)
- RETURN(lsm_size);
+ return lsm_size;
LASSERT(lsm_op_find(magic) != NULL);
rc = lsm_op_find(magic)->lsm_unpackmd(lov, *lsmp, lmm);
if (rc) {
lov_free_memmd(lsmp);
- RETURN(rc);
+ return rc;
}
- RETURN(lsm_size);
+ return lsm_size;
}
static int __lov_setstripe(struct obd_export *exp, int max_lmm_size,
@@ -416,11 +417,10 @@ static int __lov_setstripe(struct obd_export *exp, int max_lmm_size,
__u16 stripe_count;
int rc;
int cplen = 0;
- ENTRY;
rc = lov_lum_swab_if_needed(lumv3, &lmm_magic, lump);
if (rc)
- RETURN(rc);
+ return rc;
/* in the rest of the tests, as *lumv1 and lumv3 have the same
* fields, we use lumv1 to avoid code duplication */
@@ -430,10 +430,10 @@ static int __lov_setstripe(struct obd_export *exp, int max_lmm_size,
lov->desc.ld_pattern : LOV_PATTERN_RAID0;
}
- if (lumv1->lmm_pattern != LOV_PATTERN_RAID0) {
+ if (lov_pattern(lumv1->lmm_pattern) != LOV_PATTERN_RAID0) {
CDEBUG(D_IOCTL, "bad userland stripe pattern: %#x\n",
lumv1->lmm_pattern);
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* 64kB is the largest common page size we see (ia64), and matches the
@@ -449,7 +449,7 @@ static int __lov_setstripe(struct obd_export *exp, int max_lmm_size,
(typeof(lumv1->lmm_stripe_offset))(-1))) {
CDEBUG(D_IOCTL, "stripe offset %u > number of OSTs %u\n",
lumv1->lmm_stripe_offset, lov->desc.ld_tgt_count);
- RETURN(-EINVAL);
+ return -EINVAL;
}
stripe_count = lov_get_stripecnt(lov, lmm_magic,
lumv1->lmm_stripe_count);
@@ -479,7 +479,7 @@ static int __lov_setstripe(struct obd_export *exp, int max_lmm_size,
lumv3->lmm_stripe_offset, pool);
if (rc < 0) {
lov_pool_putref(pool);
- RETURN(-EINVAL);
+ return -EINVAL;
}
}
@@ -490,6 +490,9 @@ static int __lov_setstripe(struct obd_export *exp, int max_lmm_size,
}
}
+ if (lumv1->lmm_pattern & LOV_PATTERN_F_RELEASED)
+ stripe_count = 0;
+
rc = lov_alloc_memmd(lsmp, stripe_count, lumv1->lmm_pattern, lmm_magic);
if (rc >= 0) {
@@ -505,7 +508,7 @@ static int __lov_setstripe(struct obd_export *exp, int max_lmm_size,
rc = 0;
}
- RETURN(rc);
+ return rc;
}
/* Configure object striping information on a new file.
@@ -526,7 +529,7 @@ int lov_setstripe(struct obd_export *exp, int max_lmm_size,
rc = __lov_setstripe(exp, max_lmm_size, lsmp, lump);
set_fs(seg);
- RETURN(rc);
+ return rc;
}
int lov_setea(struct obd_export *exp, struct lov_stripe_md **lsmp,
@@ -539,8 +542,6 @@ int lov_setea(struct obd_export *exp, struct lov_stripe_md **lsmp,
obd_id last_id = 0;
struct lov_user_ost_data_v1 *lmm_objects;
- ENTRY;
-
if (lump->lmm_magic == LOV_USER_MAGIC_V3)
lmm_objects = ((struct lov_user_md_v3 *)lump)->lmm_objects;
else
@@ -552,26 +553,26 @@ int lov_setea(struct obd_export *exp, struct lov_stripe_md **lsmp,
rc = obd_get_info(NULL, oexp, sizeof(KEY_LAST_ID), KEY_LAST_ID,
&len, &last_id, NULL);
if (rc)
- RETURN(rc);
+ return rc;
if (ostid_id(&lmm_objects[i].l_ost_oi) > last_id) {
CERROR("Setting EA for object > than last id on"
" ost idx %d "DOSTID" > "LPD64" \n",
lmm_objects[i].l_ost_idx,
POSTID(&lmm_objects[i].l_ost_oi), last_id);
- RETURN(-EINVAL);
+ return -EINVAL;
}
}
rc = lov_setstripe(exp, 0, lsmp, lump);
if (rc)
- RETURN(rc);
+ return rc;
for (i = 0; i < lump->lmm_stripe_count; i++) {
(*lsmp)->lsm_oinfo[i]->loi_ost_idx =
lmm_objects[i].l_ost_idx;
(*lsmp)->lsm_oinfo[i]->loi_oi = lmm_objects[i].l_ost_oi;
}
- RETURN(0);
+ return 0;
}
@@ -593,10 +594,9 @@ int lov_getstripe(struct obd_export *exp, struct lov_stripe_md *lsm,
int rc, lmm_size;
int lum_size;
mm_segment_t seg;
- ENTRY;
if (!lsm)
- RETURN(-ENODATA);
+ return -ENODATA;
/*
* "Switch to kernel segment" to allow copying from kernel space by
@@ -674,5 +674,5 @@ int lov_getstripe(struct obd_export *exp, struct lov_stripe_md *lsm,
obd_free_diskmd(exp, &lmmk);
out_set:
set_fs(seg);
- RETURN(rc);
+ return rc;
}
diff --git a/drivers/staging/lustre/lustre/lov/lov_page.c b/drivers/staging/lustre/lustre/lov/lov_page.c
index 65790d68472..674e61781c2 100644
--- a/drivers/staging/lustre/lustre/lov/lov_page.c
+++ b/drivers/staging/lustre/lustre/lov/lov_page.c
@@ -69,7 +69,6 @@ static void lov_page_fini(const struct lu_env *env,
struct cl_page *sub = lov_sub_page(slice);
LINVRNT(lov_page_invariant(slice));
- ENTRY;
if (sub != NULL) {
LASSERT(sub->cp_state == CPS_FREEING);
@@ -78,7 +77,6 @@ static void lov_page_fini(const struct lu_env *env,
slice->cpl_page->cp_child = NULL;
cl_page_put(env, sub);
}
- EXIT;
}
static int lov_page_own(const struct lu_env *env,
@@ -90,7 +88,6 @@ static int lov_page_own(const struct lu_env *env,
LINVRNT(lov_page_invariant(slice));
LINVRNT(!cl2lov_page(slice)->lps_invalid);
- ENTRY;
sub = lov_page_subio(env, lio, slice);
if (!IS_ERR(sub)) {
@@ -98,7 +95,7 @@ static int lov_page_own(const struct lu_env *env,
lov_sub_put(sub);
} else
LBUG(); /* Arrgh */
- RETURN(0);
+ return 0;
}
static void lov_page_assume(const struct lu_env *env,
@@ -117,7 +114,6 @@ static int lov_page_cache_add(const struct lu_env *env,
LINVRNT(lov_page_invariant(slice));
LINVRNT(!cl2lov_page(slice)->lps_invalid);
- ENTRY;
sub = lov_page_subio(env, lio, slice);
if (!IS_ERR(sub)) {
@@ -128,7 +124,7 @@ static int lov_page_cache_add(const struct lu_env *env,
rc = PTR_ERR(sub);
CL_PAGE_DEBUG(D_ERROR, env, slice->cpl_page, "rc = %d\n", rc);
}
- RETURN(rc);
+ return rc;
}
static int lov_page_print(const struct lu_env *env,
@@ -172,7 +168,6 @@ int lov_page_init_raid0(const struct lu_env *env, struct cl_object *obj,
obd_off suboff;
int stripe;
int rc;
- ENTRY;
offset = cl_offset(obj, page->cp_index);
stripe = lov_stripe_number(loo->lo_lsm, offset);
@@ -205,7 +200,6 @@ int lov_page_init_raid0(const struct lu_env *env, struct cl_object *obj,
LASSERT(0);
}
- EXIT;
out:
return rc;
}
@@ -221,14 +215,13 @@ int lov_page_init_empty(const struct lu_env *env, struct cl_object *obj,
{
struct lov_page *lpg = cl_object_page_slice(obj, page);
void *addr;
- ENTRY;
cl_page_slice_add(page, &lpg->lps_cl, obj, &lov_empty_page_ops);
addr = kmap(vmpage);
memset(addr, 0, cl_page_size(obj));
kunmap(vmpage);
cl_page_export(env, page, 1);
- RETURN(0);
+ return 0;
}
diff --git a/drivers/staging/lustre/lustre/lov/lov_pool.c b/drivers/staging/lustre/lustre/lov/lov_pool.c
index a96f90880c6..dd3c07d5c4d 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pool.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pool.c
@@ -68,7 +68,6 @@ void lov_pool_putref(struct pool_desc *pool)
lov_ost_pool_free(&(pool->pool_rr.lqr_pool));
lov_ost_pool_free(&(pool->pool_obds));
OBD_FREE_PTR(pool);
- EXIT;
}
}
@@ -322,8 +321,6 @@ void lov_dump_pool(int level, struct pool_desc *pool)
#define LOV_POOL_INIT_COUNT 2
int lov_ost_pool_init(struct ost_pool *op, unsigned int count)
{
- ENTRY;
-
if (count == 0)
count = LOV_POOL_INIT_COUNT;
op->op_array = NULL;
@@ -333,9 +330,8 @@ int lov_ost_pool_init(struct ost_pool *op, unsigned int count)
OBD_ALLOC(op->op_array, op->op_size * sizeof(op->op_array[0]));
if (op->op_array == NULL) {
op->op_size = 0;
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
- EXIT;
return 0;
}
@@ -366,7 +362,6 @@ int lov_ost_pool_extend(struct ost_pool *op, unsigned int min_count)
int lov_ost_pool_add(struct ost_pool *op, __u32 idx, unsigned int min_count)
{
int rc = 0, i;
- ENTRY;
down_write(&op->op_rw_sem);
@@ -382,7 +377,6 @@ int lov_ost_pool_add(struct ost_pool *op, __u32 idx, unsigned int min_count)
/* ost not found we add it */
op->op_array[op->op_count] = idx;
op->op_count++;
- EXIT;
out:
up_write(&op->op_rw_sem);
return rc;
@@ -391,7 +385,6 @@ out:
int lov_ost_pool_remove(struct ost_pool *op, __u32 idx)
{
int i;
- ENTRY;
down_write(&op->op_rw_sem);
@@ -401,21 +394,18 @@ int lov_ost_pool_remove(struct ost_pool *op, __u32 idx)
(op->op_count - i - 1) * sizeof(op->op_array[0]));
op->op_count--;
up_write(&op->op_rw_sem);
- EXIT;
return 0;
}
}
up_write(&op->op_rw_sem);
- RETURN(-EINVAL);
+ return -EINVAL;
}
int lov_ost_pool_free(struct ost_pool *op)
{
- ENTRY;
-
if (op->op_size == 0)
- RETURN(0);
+ return 0;
down_write(&op->op_rw_sem);
@@ -425,7 +415,7 @@ int lov_ost_pool_free(struct ost_pool *op)
op->op_size = 0;
up_write(&op->op_rw_sem);
- RETURN(0);
+ return 0;
}
@@ -434,16 +424,15 @@ int lov_pool_new(struct obd_device *obd, char *poolname)
struct lov_obd *lov;
struct pool_desc *new_pool;
int rc;
- ENTRY;
lov = &(obd->u.lov);
if (strlen(poolname) > LOV_MAXPOOLNAME)
- RETURN(-ENAMETOOLONG);
+ return -ENAMETOOLONG;
OBD_ALLOC_PTR(new_pool);
if (new_pool == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
strncpy(new_pool->pool_name, poolname, LOV_MAXPOOLNAME);
new_pool->pool_name[LOV_MAXPOOLNAME] = '\0';
@@ -492,7 +481,7 @@ int lov_pool_new(struct obd_device *obd, char *poolname)
CDEBUG(D_CONFIG, LOV_POOLNAMEF" is pool #%d\n",
poolname, lov->lov_pool_count);
- RETURN(0);
+ return 0;
out_err:
spin_lock(&obd->obd_dev_lock);
@@ -513,14 +502,13 @@ int lov_pool_del(struct obd_device *obd, char *poolname)
{
struct lov_obd *lov;
struct pool_desc *pool;
- ENTRY;
lov = &(obd->u.lov);
/* lookup and kill hash reference */
pool = cfs_hash_del_key(lov->lov_pools_hash_body, poolname);
if (pool == NULL)
- RETURN(-ENOENT);
+ return -ENOENT;
if (pool->pool_proc_entry != NULL) {
CDEBUG(D_INFO, "proc entry %p\n", pool->pool_proc_entry);
@@ -536,7 +524,7 @@ int lov_pool_del(struct obd_device *obd, char *poolname)
/* release last reference */
lov_pool_putref(pool);
- RETURN(0);
+ return 0;
}
@@ -547,13 +535,12 @@ int lov_pool_add(struct obd_device *obd, char *poolname, char *ostname)
struct pool_desc *pool;
unsigned int lov_idx;
int rc;
- ENTRY;
lov = &(obd->u.lov);
pool = cfs_hash_lookup(lov->lov_pools_hash_body, poolname);
if (pool == NULL)
- RETURN(-ENOENT);
+ return -ENOENT;
obd_str2uuid(&ost_uuid, ostname);
@@ -580,7 +567,6 @@ int lov_pool_add(struct obd_device *obd, char *poolname, char *ostname)
CDEBUG(D_CONFIG, "Added %s to "LOV_POOLNAMEF" as member %d\n",
ostname, poolname, pool_tgt_count(pool));
- EXIT;
out:
obd_putref(obd);
lov_pool_putref(pool);
@@ -594,13 +580,12 @@ int lov_pool_remove(struct obd_device *obd, char *poolname, char *ostname)
struct pool_desc *pool;
unsigned int lov_idx;
int rc = 0;
- ENTRY;
lov = &(obd->u.lov);
pool = cfs_hash_lookup(lov->lov_pools_hash_body, poolname);
if (pool == NULL)
- RETURN(-ENOENT);
+ return -ENOENT;
obd_str2uuid(&ost_uuid, ostname);
@@ -626,7 +611,6 @@ int lov_pool_remove(struct obd_device *obd, char *poolname, char *ostname)
CDEBUG(D_CONFIG, "%s removed from "LOV_POOLNAMEF"\n", ostname,
poolname);
- EXIT;
out:
obd_putref(obd);
lov_pool_putref(pool);
@@ -636,7 +620,6 @@ out:
int lov_check_index_in_pool(__u32 idx, struct pool_desc *pool)
{
int i, rc;
- ENTRY;
/* caller may no have a ref on pool if it got the pool
* without calling lov_find_pool() (e.g. go through the lov pool
@@ -651,7 +634,6 @@ int lov_check_index_in_pool(__u32 idx, struct pool_desc *pool)
GOTO(out, rc = 0);
}
rc = -ENOENT;
- EXIT;
out:
up_read(&pool_tgt_rw_sem(pool));
diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c
index 13f1637bc70..61e6d0b46c9 100644
--- a/drivers/staging/lustre/lustre/lov/lov_request.c
+++ b/drivers/staging/lustre/lustre/lov/lov_request.c
@@ -60,7 +60,6 @@ static void lov_init_set(struct lov_request_set *set)
void lov_finish_set(struct lov_request_set *set)
{
struct list_head *pos, *n;
- ENTRY;
LASSERT(set);
list_for_each_safe(pos, n, &set->set_list) {
@@ -87,7 +86,6 @@ void lov_finish_set(struct lov_request_set *set)
lov_llh_put(set->set_lockh);
OBD_FREE(set, sizeof(*set));
- EXIT;
}
int lov_set_finished(struct lov_request_set *set, int idempotent)
@@ -122,7 +120,6 @@ int lov_update_common_set(struct lov_request_set *set,
struct lov_request *req, int rc)
{
struct lov_obd *lov = &set->set_exp->exp_obd->u.lov;
- ENTRY;
lov_update_set(set, req, rc);
@@ -132,7 +129,7 @@ int lov_update_common_set(struct lov_request_set *set,
rc = 0;
/* FIXME in raid1 regime, should return 0 */
- RETURN(rc);
+ return rc;
}
void lov_set_add_req(struct lov_request *req, struct lov_request_set *set)
@@ -232,7 +229,6 @@ int lov_update_enqueue_set(struct lov_request *req, __u32 mode, int rc)
struct lustre_handle *lov_lockhp;
struct obd_info *oi = set->set_oi;
struct lov_oinfo *loi;
- ENTRY;
LASSERT(oi != NULL);
@@ -254,7 +250,7 @@ int lov_update_enqueue_set(struct lov_request *req, __u32 mode, int rc)
req->rq_idx, &oi->oi_md->lsm_oi, rc);
lov_stripe_unlock(oi->oi_md);
lov_update_set(set, req, rc);
- RETURN(rc);
+ return rc;
}
/* The callback for osc_enqueue that updates lov info for every OSC request. */
@@ -275,11 +271,10 @@ static int enqueue_done(struct lov_request_set *set, __u32 mode)
struct lov_obd *lov = &set->set_exp->exp_obd->u.lov;
int completes = atomic_read(&set->set_completes);
int rc = 0;
- ENTRY;
/* enqueue/match success, just return */
if (completes && completes == atomic_read(&set->set_success))
- RETURN(0);
+ return 0;
/* cancel enqueued/matched locks */
list_for_each_entry(req, &set->set_list, rq_link) {
@@ -305,17 +300,16 @@ static int enqueue_done(struct lov_request_set *set, __u32 mode)
}
if (set->set_lockh)
lov_llh_put(set->set_lockh);
- RETURN(rc);
+ return rc;
}
int lov_fini_enqueue_set(struct lov_request_set *set, __u32 mode, int rc,
struct ptlrpc_request_set *rqset)
{
int ret = 0;
- ENTRY;
if (set == NULL)
- RETURN(0);
+ return 0;
LASSERT(set->set_exp);
/* Do enqueue_done only for sync requests and if any request
* succeeded. */
@@ -328,7 +322,7 @@ int lov_fini_enqueue_set(struct lov_request_set *set, __u32 mode, int rc,
lov_put_reqset(set);
- RETURN(rc ? rc : ret);
+ return rc ? rc : ret;
}
static void lov_llh_addref(void *llhp)
@@ -369,11 +363,10 @@ int lov_prep_enqueue_set(struct obd_export *exp, struct obd_info *oinfo,
struct lov_obd *lov = &exp->exp_obd->u.lov;
struct lov_request_set *set;
int i, rc = 0;
- ENTRY;
OBD_ALLOC(set, sizeof(*set));
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lov_init_set(set);
set->set_exp = exp;
@@ -445,19 +438,18 @@ int lov_prep_enqueue_set(struct obd_export *exp, struct obd_info *oinfo,
if (!set->set_count)
GOTO(out_set, rc = -EIO);
*reqset = set;
- RETURN(0);
+ return 0;
out_set:
lov_fini_enqueue_set(set, einfo->ei_mode, rc, NULL);
- RETURN(rc);
+ return rc;
}
int lov_fini_match_set(struct lov_request_set *set, __u32 mode, int flags)
{
int rc = 0;
- ENTRY;
if (set == NULL)
- RETURN(0);
+ return 0;
LASSERT(set->set_exp);
rc = enqueue_done(set, mode);
if ((set->set_count == atomic_read(&set->set_success)) &&
@@ -466,7 +458,7 @@ int lov_fini_match_set(struct lov_request_set *set, __u32 mode, int flags)
lov_put_reqset(set);
- RETURN(rc);
+ return rc;
}
int lov_prep_match_set(struct obd_export *exp, struct obd_info *oinfo,
@@ -477,11 +469,10 @@ int lov_prep_match_set(struct obd_export *exp, struct obd_info *oinfo,
struct lov_obd *lov = &exp->exp_obd->u.lov;
struct lov_request_set *set;
int i, rc = 0;
- ENTRY;
OBD_ALLOC(set, sizeof(*set));
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lov_init_set(set);
set->set_exp = exp;
@@ -535,19 +526,18 @@ int lov_prep_match_set(struct obd_export *exp, struct obd_info *oinfo,
if (!set->set_count)
GOTO(out_set, rc = -EIO);
*reqset = set;
- RETURN(rc);
+ return rc;
out_set:
lov_fini_match_set(set, mode, 0);
- RETURN(rc);
+ return rc;
}
int lov_fini_cancel_set(struct lov_request_set *set)
{
int rc = 0;
- ENTRY;
if (set == NULL)
- RETURN(0);
+ return 0;
LASSERT(set->set_exp);
if (set->set_lockh)
@@ -555,7 +545,7 @@ int lov_fini_cancel_set(struct lov_request_set *set)
lov_put_reqset(set);
- RETURN(rc);
+ return rc;
}
int lov_prep_cancel_set(struct obd_export *exp, struct obd_info *oinfo,
@@ -565,11 +555,10 @@ int lov_prep_cancel_set(struct obd_export *exp, struct obd_info *oinfo,
{
struct lov_request_set *set;
int i, rc = 0;
- ENTRY;
OBD_ALLOC(set, sizeof(*set));
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lov_init_set(set);
set->set_exp = exp;
@@ -617,10 +606,10 @@ int lov_prep_cancel_set(struct obd_export *exp, struct obd_info *oinfo,
if (!set->set_count)
GOTO(out_set, rc = -EIO);
*reqset = set;
- RETURN(rc);
+ return rc;
out_set:
lov_fini_cancel_set(set);
- RETURN(rc);
+ return rc;
}
static int common_attr_done(struct lov_request_set *set)
{
@@ -628,15 +617,14 @@ static int common_attr_done(struct lov_request_set *set)
struct lov_request *req;
struct obdo *tmp_oa;
int rc = 0, attrset = 0;
- ENTRY;
LASSERT(set->set_oi != NULL);
if (set->set_oi->oi_oa == NULL)
- RETURN(0);
+ return 0;
if (!atomic_read(&set->set_success))
- RETURN(-EIO);
+ return -EIO;
OBDO_ALLOC(tmp_oa);
if (tmp_oa == NULL)
@@ -670,7 +658,7 @@ static int common_attr_done(struct lov_request_set *set)
out:
if (tmp_oa)
OBDO_FREE(tmp_oa);
- RETURN(rc);
+ return rc;
}
@@ -680,7 +668,6 @@ static int brw_done(struct lov_request_set *set)
struct lov_oinfo *loi = NULL;
struct list_head *pos;
struct lov_request *req;
- ENTRY;
list_for_each (pos, &set->set_list) {
req = list_entry(pos, struct lov_request, rq_link);
@@ -694,16 +681,15 @@ static int brw_done(struct lov_request_set *set)
loi->loi_lvb.lvb_blocks = req->rq_oi.oi_oa->o_blocks;
}
- RETURN(0);
+ return 0;
}
int lov_fini_brw_set(struct lov_request_set *set)
{
int rc = 0;
- ENTRY;
if (set == NULL)
- RETURN(0);
+ return 0;
LASSERT(set->set_exp);
if (atomic_read(&set->set_completes)) {
rc = brw_done(set);
@@ -711,7 +697,7 @@ int lov_fini_brw_set(struct lov_request_set *set)
}
lov_put_reqset(set);
- RETURN(rc);
+ return rc;
}
int lov_prep_brw_set(struct obd_export *exp, struct obd_info *oinfo,
@@ -727,11 +713,10 @@ int lov_prep_brw_set(struct obd_export *exp, struct obd_info *oinfo,
struct lov_request_set *set;
struct lov_obd *lov = &exp->exp_obd->u.lov;
int rc = 0, i, shift;
- ENTRY;
OBD_ALLOC(set, sizeof(*set));
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lov_init_set(set);
set->set_exp = exp;
@@ -832,23 +817,22 @@ out:
else
lov_fini_brw_set(set);
- RETURN(rc);
+ return rc;
}
int lov_fini_getattr_set(struct lov_request_set *set)
{
int rc = 0;
- ENTRY;
if (set == NULL)
- RETURN(0);
+ return 0;
LASSERT(set->set_exp);
if (atomic_read(&set->set_completes))
rc = common_attr_done(set);
lov_put_reqset(set);
- RETURN(rc);
+ return rc;
}
/* The callback for osc_getattr_async that finilizes a request info when a
@@ -867,11 +851,10 @@ int lov_prep_getattr_set(struct obd_export *exp, struct obd_info *oinfo,
struct lov_request_set *set;
struct lov_obd *lov = &exp->exp_obd->u.lov;
int rc = 0, i;
- ENTRY;
OBD_ALLOC(set, sizeof(*set));
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lov_init_set(set);
set->set_exp = exp;
@@ -913,18 +896,16 @@ int lov_prep_getattr_set(struct obd_export *exp, struct obd_info *oinfo,
if (!set->set_count)
GOTO(out_set, rc = -EIO);
*reqset = set;
- RETURN(rc);
+ return rc;
out_set:
lov_fini_getattr_set(set);
- RETURN(rc);
+ return rc;
}
int lov_fini_destroy_set(struct lov_request_set *set)
{
- ENTRY;
-
if (set == NULL)
- RETURN(0);
+ return 0;
LASSERT(set->set_exp);
if (atomic_read(&set->set_completes)) {
/* FIXME update qos data here */
@@ -932,7 +913,7 @@ int lov_fini_destroy_set(struct lov_request_set *set)
lov_put_reqset(set);
- RETURN(0);
+ return 0;
}
int lov_prep_destroy_set(struct obd_export *exp, struct obd_info *oinfo,
@@ -943,11 +924,10 @@ int lov_prep_destroy_set(struct obd_export *exp, struct obd_info *oinfo,
struct lov_request_set *set;
struct lov_obd *lov = &exp->exp_obd->u.lov;
int rc = 0, i;
- ENTRY;
OBD_ALLOC(set, sizeof(*set));
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lov_init_set(set);
set->set_exp = exp;
@@ -987,19 +967,18 @@ int lov_prep_destroy_set(struct obd_export *exp, struct obd_info *oinfo,
if (!set->set_count)
GOTO(out_set, rc = -EIO);
*reqset = set;
- RETURN(rc);
+ return rc;
out_set:
lov_fini_destroy_set(set);
- RETURN(rc);
+ return rc;
}
int lov_fini_setattr_set(struct lov_request_set *set)
{
int rc = 0;
- ENTRY;
if (set == NULL)
- RETURN(0);
+ return 0;
LASSERT(set->set_exp);
if (atomic_read(&set->set_completes)) {
rc = common_attr_done(set);
@@ -1007,7 +986,7 @@ int lov_fini_setattr_set(struct lov_request_set *set)
}
lov_put_reqset(set);
- RETURN(rc);
+ return rc;
}
int lov_update_setattr_set(struct lov_request_set *set,
@@ -1015,7 +994,6 @@ int lov_update_setattr_set(struct lov_request_set *set,
{
struct lov_obd *lov = &req->rq_rqset->set_exp->exp_obd->u.lov;
struct lov_stripe_md *lsm = req->rq_rqset->set_oi->oi_md;
- ENTRY;
lov_update_set(set, req, rc);
@@ -1036,7 +1014,7 @@ int lov_update_setattr_set(struct lov_request_set *set,
req->rq_oi.oi_oa->o_atime;
}
- RETURN(rc);
+ return rc;
}
/* The callback for osc_setattr_async that finilizes a request info when a
@@ -1056,11 +1034,10 @@ int lov_prep_setattr_set(struct obd_export *exp, struct obd_info *oinfo,
struct lov_request_set *set;
struct lov_obd *lov = &exp->exp_obd->u.lov;
int rc = 0, i;
- ENTRY;
OBD_ALLOC(set, sizeof(*set));
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lov_init_set(set);
set->set_exp = exp;
@@ -1113,19 +1090,18 @@ int lov_prep_setattr_set(struct obd_export *exp, struct obd_info *oinfo,
if (!set->set_count)
GOTO(out_set, rc = -EIO);
*reqset = set;
- RETURN(rc);
+ return rc;
out_set:
lov_fini_setattr_set(set);
- RETURN(rc);
+ return rc;
}
int lov_fini_punch_set(struct lov_request_set *set)
{
int rc = 0;
- ENTRY;
if (set == NULL)
- RETURN(0);
+ return 0;
LASSERT(set->set_exp);
if (atomic_read(&set->set_completes)) {
rc = -EIO;
@@ -1136,7 +1112,7 @@ int lov_fini_punch_set(struct lov_request_set *set)
lov_put_reqset(set);
- RETURN(rc);
+ return rc;
}
int lov_update_punch_set(struct lov_request_set *set,
@@ -1144,7 +1120,6 @@ int lov_update_punch_set(struct lov_request_set *set,
{
struct lov_obd *lov = &req->rq_rqset->set_exp->exp_obd->u.lov;
struct lov_stripe_md *lsm = req->rq_rqset->set_oi->oi_md;
- ENTRY;
lov_update_set(set, req, rc);
@@ -1162,7 +1137,7 @@ int lov_update_punch_set(struct lov_request_set *set,
lov_stripe_unlock(lsm);
}
- RETURN(rc);
+ return rc;
}
/* The callback for osc_punch that finilizes a request info when a response
@@ -1182,11 +1157,10 @@ int lov_prep_punch_set(struct obd_export *exp, struct obd_info *oinfo,
struct lov_request_set *set;
struct lov_obd *lov = &exp->exp_obd->u.lov;
int rc = 0, i;
- ENTRY;
OBD_ALLOC(set, sizeof(*set));
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lov_init_set(set);
set->set_oi = oinfo;
@@ -1238,19 +1212,18 @@ int lov_prep_punch_set(struct obd_export *exp, struct obd_info *oinfo,
if (!set->set_count)
GOTO(out_set, rc = -EIO);
*reqset = set;
- RETURN(rc);
+ return rc;
out_set:
lov_fini_punch_set(set);
- RETURN(rc);
+ return rc;
}
int lov_fini_sync_set(struct lov_request_set *set)
{
int rc = 0;
- ENTRY;
if (set == NULL)
- RETURN(0);
+ return 0;
LASSERT(set->set_exp);
if (atomic_read(&set->set_completes)) {
if (!atomic_read(&set->set_success))
@@ -1260,7 +1233,7 @@ int lov_fini_sync_set(struct lov_request_set *set)
lov_put_reqset(set);
- RETURN(rc);
+ return rc;
}
/* The callback for osc_sync that finilizes a request info when a
@@ -1281,11 +1254,10 @@ int lov_prep_sync_set(struct obd_export *exp, struct obd_info *oinfo,
struct lov_request_set *set;
struct lov_obd *lov = &exp->exp_obd->u.lov;
int rc = 0, i;
- ENTRY;
OBD_ALLOC_PTR(set);
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lov_init_set(set);
set->set_exp = exp;
@@ -1330,10 +1302,10 @@ int lov_prep_sync_set(struct obd_export *exp, struct obd_info *oinfo,
if (!set->set_count)
GOTO(out_set, rc = -EIO);
*reqset = set;
- RETURN(rc);
+ return rc;
out_set:
lov_fini_sync_set(set);
- RETURN(rc);
+ return rc;
}
#define LOV_U64_MAX ((__u64)~0ULL)
@@ -1347,8 +1319,6 @@ out_set:
int lov_fini_statfs(struct obd_device *obd, struct obd_statfs *osfs,int success)
{
- ENTRY;
-
if (success) {
__u32 expected_stripes = lov_get_stripecnt(&obd->u.lov,
LOV_MAGIC, 0);
@@ -1361,26 +1331,25 @@ int lov_fini_statfs(struct obd_device *obd, struct obd_statfs *osfs,int success)
memcpy(&obd->obd_osfs, osfs, sizeof(*osfs));
obd->obd_osfs_age = cfs_time_current_64();
spin_unlock(&obd->obd_osfs_lock);
- RETURN(0);
+ return 0;
}
- RETURN(-EIO);
+ return -EIO;
}
int lov_fini_statfs_set(struct lov_request_set *set)
{
int rc = 0;
- ENTRY;
if (set == NULL)
- RETURN(0);
+ return 0;
if (atomic_read(&set->set_completes)) {
rc = lov_fini_statfs(set->set_obd, set->set_oi->oi_osfs,
atomic_read(&set->set_success));
}
lov_put_reqset(set);
- RETURN(rc);
+ return rc;
}
void lov_update_statfs(struct obd_statfs *osfs, struct obd_statfs *lov_sfs,
@@ -1450,7 +1419,6 @@ static int cb_statfs_update(void *cookie, int rc)
struct lov_tgt_desc *tgt;
struct obd_device *lovobd, *tgtobd;
int success;
- ENTRY;
lovreq = container_of(oinfo, struct lov_request, rq_oi);
set = lovreq->rq_rqset;
@@ -1488,7 +1456,7 @@ out:
atomic_read(&set->set_success));
}
- RETURN(0);
+ return 0;
}
int lov_prep_statfs_set(struct obd_device *obd, struct obd_info *oinfo,
@@ -1497,11 +1465,10 @@ int lov_prep_statfs_set(struct obd_device *obd, struct obd_info *oinfo,
struct lov_request_set *set;
struct lov_obd *lov = &obd->u.lov;
int rc = 0, i;
- ENTRY;
OBD_ALLOC(set, sizeof(*set));
if (set == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lov_init_set(set);
set->set_obd = obd;
@@ -1544,8 +1511,8 @@ int lov_prep_statfs_set(struct obd_device *obd, struct obd_info *oinfo,
if (!set->set_count)
GOTO(out_set, rc = -EIO);
*reqset = set;
- RETURN(rc);
+ return rc;
out_set:
lov_fini_statfs_set(set);
- RETURN(rc);
+ return rc;
}
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_dev.c b/drivers/staging/lustre/lustre/lov/lovsub_dev.c
index 204ecd0b863..998ea1cbc7b 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_dev.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_dev.c
@@ -55,10 +55,8 @@ static void lovsub_req_completion(const struct lu_env *env,
{
struct lovsub_req *lsr;
- ENTRY;
lsr = cl2lovsub_req(slice);
OBD_SLAB_FREE_PTR(lsr, lovsub_req_kmem);
- EXIT;
}
/**
@@ -73,14 +71,12 @@ static void lovsub_req_attr_set(const struct lu_env *env,
{
struct lovsub_object *subobj;
- ENTRY;
subobj = cl2lovsub(obj);
/*
* There is no OBD_MD_* flag for obdo::o_stripe_idx, so set it
* unconditionally. It never changes anyway.
*/
attr->cra_oa->o_stripe_idx = subobj->lso_index;
- EXIT;
}
static const struct cl_req_operations lovsub_req_ops = {
@@ -101,20 +97,19 @@ static int lovsub_device_init(const struct lu_env *env, struct lu_device *d,
struct lu_device_type *ldt;
int rc;
- ENTRY;
next->ld_site = d->ld_site;
ldt = next->ld_type;
LASSERT(ldt != NULL);
rc = ldt->ldt_ops->ldto_device_init(env, next, ldt->ldt_name, NULL);
if (rc) {
next->ld_site = NULL;
- RETURN(rc);
+ return rc;
}
lu_device_get(next);
lu_ref_add(&next->ld_reference, "lu-stack", &lu_site_init);
lsd->acid_next = lu2cl_dev(next);
- RETURN(rc);
+ return rc;
}
static struct lu_device *lovsub_device_fini(const struct lu_env *env,
@@ -123,12 +118,11 @@ static struct lu_device *lovsub_device_fini(const struct lu_env *env,
struct lu_device *next;
struct lovsub_device *lsd;
- ENTRY;
lsd = lu2lovsub_dev(d);
next = cl2lu_dev(lsd->acid_next);
lsd->acid_super = NULL;
lsd->acid_next = NULL;
- RETURN(next);
+ return next;
}
static struct lu_device *lovsub_device_free(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_lock.c b/drivers/staging/lustre/lustre/lov/lovsub_lock.c
index 03bab17ccc6..80305aa6171 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_lock.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_lock.c
@@ -57,35 +57,29 @@ static void lovsub_lock_fini(const struct lu_env *env,
{
struct lovsub_lock *lsl;
- ENTRY;
lsl = cl2lovsub_lock(slice);
LASSERT(list_empty(&lsl->lss_parents));
OBD_SLAB_FREE_PTR(lsl, lovsub_lock_kmem);
- EXIT;
}
static void lovsub_parent_lock(const struct lu_env *env, struct lov_lock *lov)
{
struct cl_lock *parent;
- ENTRY;
parent = lov->lls_cl.cls_lock;
cl_lock_get(parent);
lu_ref_add(&parent->cll_reference, "lovsub-parent", current);
cl_lock_mutex_get(env, parent);
- EXIT;
}
static void lovsub_parent_unlock(const struct lu_env *env, struct lov_lock *lov)
{
struct cl_lock *parent;
- ENTRY;
parent = lov->lls_cl.cls_lock;
cl_lock_mutex_put(env, lov->lls_cl.cls_lock);
lu_ref_del(&parent->cll_reference, "lovsub-parent", current);
cl_lock_put(env, parent);
- EXIT;
}
/**
@@ -101,7 +95,6 @@ static void lovsub_lock_state(const struct lu_env *env,
struct lov_lock_link *scan;
LASSERT(cl_lock_is_mutexed(slice->cls_lock));
- ENTRY;
list_for_each_entry(scan, &sub->lss_parents, lll_list) {
struct lov_lock *lov = scan->lll_super;
@@ -113,7 +106,6 @@ static void lovsub_lock_state(const struct lu_env *env,
lovsub_parent_unlock(env, lov);
}
}
- EXIT;
}
/**
@@ -127,8 +119,6 @@ static unsigned long lovsub_lock_weigh(const struct lu_env *env,
struct lov_lock *lov;
unsigned long dumbbell;
- ENTRY;
-
LASSERT(cl_lock_is_mutexed(slice->cls_lock));
if (!list_empty(&lock->lss_parents)) {
@@ -146,7 +136,7 @@ static unsigned long lovsub_lock_weigh(const struct lu_env *env,
} else
dumbbell = 0;
- RETURN(dumbbell);
+ return dumbbell;
}
/**
@@ -162,7 +152,6 @@ static void lovsub_lock_descr_map(const struct cl_lock_descr *in,
pgoff_t start;
pgoff_t end;
- ENTRY;
start = in->cld_start;
end = in->cld_end;
@@ -184,7 +173,6 @@ static void lovsub_lock_descr_map(const struct cl_lock_descr *in,
}
out->cld_start = start;
out->cld_end = end;
- EXIT;
}
/**
@@ -241,8 +229,6 @@ static int lovsub_lock_modify(const struct lu_env *env,
struct lov_lock *lov;
int result = 0;
- ENTRY;
-
LASSERT(cl_lock_mode_match(d->cld_mode,
s->cls_lock->cll_descr.cld_mode));
list_for_each_entry(scan, &lock->lss_parents, lll_list) {
@@ -254,7 +240,7 @@ static int lovsub_lock_modify(const struct lu_env *env,
lovsub_parent_unlock(env, lov);
result = result ?: rc;
}
- RETURN(result);
+ return result;
}
static int lovsub_lock_closure(const struct lu_env *env,
@@ -267,7 +253,6 @@ static int lovsub_lock_closure(const struct lu_env *env,
int result;
LASSERT(cl_lock_is_mutexed(slice->cls_lock));
- ENTRY;
sub = cl2lovsub_lock(slice);
result = 0;
@@ -278,7 +263,7 @@ static int lovsub_lock_closure(const struct lu_env *env,
if (result != 0)
break;
}
- RETURN(result);
+ return result;
}
/**
@@ -290,11 +275,10 @@ static int lovsub_lock_delete_one(const struct lu_env *env,
{
struct cl_lock *parent;
int result;
- ENTRY;
parent = lov->lls_cl.cls_lock;
if (parent->cll_error)
- RETURN(0);
+ return 0;
result = 0;
switch (parent->cll_state) {
@@ -386,7 +370,7 @@ static int lovsub_lock_delete_one(const struct lu_env *env,
break;
}
- RETURN(result);
+ return result;
}
/**
@@ -403,7 +387,6 @@ static void lovsub_lock_delete(const struct lu_env *env,
LASSERT(cl_lock_is_mutexed(child));
- ENTRY;
/*
* Destruction of a sub-lock might take multiple iterations, because
* when the last sub-lock of a given top-lock is deleted, top-lock is
@@ -434,7 +417,6 @@ static void lovsub_lock_delete(const struct lu_env *env,
}
}
} while (restart);
- EXIT;
}
static int lovsub_lock_print(const struct lu_env *env, void *cookie,
@@ -471,7 +453,6 @@ int lovsub_lock_init(const struct lu_env *env, struct cl_object *obj,
struct lovsub_lock *lsk;
int result;
- ENTRY;
OBD_SLAB_ALLOC_PTR_GFP(lsk, lovsub_lock_kmem, __GFP_IO);
if (lsk != NULL) {
INIT_LIST_HEAD(&lsk->lss_parents);
@@ -479,7 +460,7 @@ int lovsub_lock_init(const struct lu_env *env, struct cl_object *obj,
result = 0;
} else
result = -ENOMEM;
- RETURN(result);
+ return result;
}
/** @} lov */
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_object.c b/drivers/staging/lustre/lustre/lov/lovsub_object.c
index 1b83d9081c4..89760b3bf3f 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_object.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_object.c
@@ -61,7 +61,6 @@ int lovsub_object_init(const struct lu_env *env, struct lu_object *obj,
int result;
- ENTRY;
under = &dev->acid_next->cd_lu_dev;
below = under->ld_ops->ldo_object_alloc(env, obj->lo_header, under);
if (below != NULL) {
@@ -70,7 +69,7 @@ int lovsub_object_init(const struct lu_env *env, struct lu_object *obj,
result = 0;
} else
result = -ENOMEM;
- RETURN(result);
+ return result;
}
@@ -78,7 +77,6 @@ static void lovsub_object_free(const struct lu_env *env, struct lu_object *obj)
{
struct lovsub_object *los = lu2lovsub(obj);
struct lov_object *lov = los->lso_super;
- ENTRY;
/* We can't assume lov was assigned here, because of the shadow
* object handling in lu_object_find.
@@ -94,7 +92,6 @@ static void lovsub_object_free(const struct lu_env *env, struct lu_object *obj)
lu_object_fini(obj);
lu_object_header_fini(&los->lso_header.coh_lu);
OBD_SLAB_FREE_PTR(los, lovsub_object_kmem);
- EXIT;
}
static int lovsub_object_print(const struct lu_env *env, void *cookie,
@@ -110,9 +107,8 @@ static int lovsub_attr_set(const struct lu_env *env, struct cl_object *obj,
{
struct lov_object *lov = cl2lovsub(obj)->lso_super;
- ENTRY;
lov_r0(lov)->lo_attr_valid = 0;
- RETURN(0);
+ return 0;
}
static int lovsub_object_glimpse(const struct lu_env *env,
@@ -121,8 +117,7 @@ static int lovsub_object_glimpse(const struct lu_env *env,
{
struct lovsub_object *los = cl2lovsub(obj);
- ENTRY;
- RETURN(cl_object_glimpse(env, &los->lso_super->lo_cl, lvb));
+ return cl_object_glimpse(env, &los->lso_super->lo_cl, lvb);
}
@@ -150,7 +145,6 @@ struct lu_object *lovsub_object_alloc(const struct lu_env *env,
struct lovsub_object *los;
struct lu_object *obj;
- ENTRY;
OBD_SLAB_ALLOC_PTR_GFP(los, lovsub_object_kmem, __GFP_IO);
if (los != NULL) {
struct cl_object_header *hdr;
@@ -164,7 +158,7 @@ struct lu_object *lovsub_object_alloc(const struct lu_env *env,
obj->lo_ops = &lovsub_lu_obj_ops;
} else
obj = NULL;
- RETURN(obj);
+ return obj;
}
/** @} lov */
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_page.c b/drivers/staging/lustre/lustre/lov/lovsub_page.c
index bc9e683968d..3f00ce9677b 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_page.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_page.c
@@ -63,10 +63,9 @@ int lovsub_page_init(const struct lu_env *env, struct cl_object *obj,
struct cl_page *page, struct page *unused)
{
struct lovsub_page *lsb = cl_object_page_slice(obj, page);
- ENTRY;
cl_page_slice_add(page, &lsb->lsb_cl, obj, &lovsub_page_ops);
- RETURN(0);
+ return 0;
}
/** @} lov */
diff --git a/drivers/staging/lustre/lustre/lov/lproc_lov.c b/drivers/staging/lustre/lustre/lov/lproc_lov.c
index 5b2c0d88add..15744e13a3f 100644
--- a/drivers/staging/lustre/lustre/lov/lproc_lov.c
+++ b/drivers/staging/lustre/lustre/lov/lproc_lov.c
@@ -35,7 +35,6 @@
*/
#define DEBUG_SUBSYSTEM S_CLASS
-#include <linux/version.h>
#include <asm/statfs.h>
#include <lprocfs_status.h>
#include <obd_class.h>
diff --git a/drivers/staging/lustre/lustre/lvfs/fsfilt.c b/drivers/staging/lustre/lustre/lvfs/fsfilt.c
index 064445cbdb5..e86df7356cb 100644
--- a/drivers/staging/lustre/lustre/lvfs/fsfilt.c
+++ b/drivers/staging/lustre/lustre/lvfs/fsfilt.c
@@ -35,7 +35,6 @@
#define DEBUG_SUBSYSTEM S_FILTER
#include <linux/fs.h>
-#include <linux/jbd.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/slab.h>
@@ -68,7 +67,7 @@ int fsfilt_register_ops(struct fsfilt_operations *fs_ops)
CERROR("different operations for type %s\n",
fs_ops->fs_type);
/* unlock fsfilt_types list */
- RETURN(-EEXIST);
+ return -EEXIST;
}
} else {
try_module_get(THIS_MODULE);
@@ -120,7 +119,7 @@ struct fsfilt_operations *fsfilt_get_ops(const char *type)
if (rc) {
CERROR("Can't find %s interface\n", name);
- RETURN(ERR_PTR(rc < 0 ? rc : -rc));
+ return ERR_PTR(rc < 0 ? rc : -rc);
/* unlock fsfilt_types list */
}
}
diff --git a/drivers/staging/lustre/lustre/lvfs/fsfilt_ext3.c b/drivers/staging/lustre/lustre/lvfs/fsfilt_ext3.c
index c1e99b37572..ee75994003e 100644
--- a/drivers/staging/lustre/lustre/lvfs/fsfilt_ext3.c
+++ b/drivers/staging/lustre/lustre/lvfs/fsfilt_ext3.c
@@ -48,7 +48,6 @@
#include <ldiskfs/ldiskfs_config.h>
#include <ext4/ext4.h>
#include <ext4/ext4_jbd2.h>
-#include <linux/version.h>
#include <linux/bitops.h>
#include <linux/quota.h>
diff --git a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
index e70d8fe9988..18e1b47a1d6 100644
--- a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
+++ b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
@@ -40,16 +40,12 @@
#define DEBUG_SUBSYSTEM S_FILTER
-#include <linux/version.h>
#include <linux/fs.h>
#include <asm/unistd.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
-#include <linux/version.h>
#include <linux/libcfs/libcfs.h>
-#include <lustre_fsfilt.h>
-#include <obd.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/lustre_compat25.h>
@@ -207,7 +203,6 @@ int lustre_rename(struct dentry *dir, struct vfsmount *mnt,
{
struct dentry *dchild_old, *dchild_new;
int err = 0;
- ENTRY;
ASSERT_KERNEL_CTXT("kernel doing rename outside kernel context\n");
CDEBUG(D_INODE, "renaming file %.*s to %.*s\n",
@@ -215,7 +210,7 @@ int lustre_rename(struct dentry *dir, struct vfsmount *mnt,
dchild_old = ll_lookup_one_len(oldname, dir, strlen(oldname));
if (IS_ERR(dchild_old))
- RETURN(PTR_ERR(dchild_old));
+ return PTR_ERR(dchild_old);
if (!dchild_old->d_inode)
GOTO(put_old, err = -ENOENT);
@@ -230,7 +225,7 @@ int lustre_rename(struct dentry *dir, struct vfsmount *mnt,
dput(dchild_new);
put_old:
dput(dchild_old);
- RETURN(err);
+ return err;
}
EXPORT_SYMBOL(lustre_rename);
@@ -242,7 +237,7 @@ struct l_file *l_dentry_open(struct lvfs_run_ctxt *ctxt, struct l_dentry *de,
.dentry = de,
.mnt = ctxt->pwdmnt,
};
- return ll_dentry_open(&path, flags, current_cred());
+ return dentry_open(&path, flags, current_cred());
}
EXPORT_SYMBOL(l_dentry_open);
@@ -255,7 +250,7 @@ __s64 lprocfs_read_helper(struct lprocfs_counter *lc,
__s64 ret = 0;
if (lc == NULL || header == NULL)
- RETURN(0);
+ return 0;
switch (field) {
case LPROCFS_FIELDS_FLAGS_CONFIG:
@@ -285,7 +280,7 @@ __s64 lprocfs_read_helper(struct lprocfs_counter *lc,
break;
};
- RETURN(ret);
+ return ret;
}
EXPORT_SYMBOL(lprocfs_read_helper);
#endif /* LPROCFS */
diff --git a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
index 6592478e9b6..e0b8f186625 100644
--- a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
+++ b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
@@ -35,7 +35,6 @@
*/
#define DEBUG_SUBSYSTEM S_CLASS
-#include <linux/version.h>
#include <linux/vfs.h>
#include <obd_class.h>
#include <lprocfs_status.h>
@@ -93,14 +92,13 @@ static ssize_t mdc_kuc_write(struct file *file, const char *buffer,
struct hsm_action_item *hai;
int len;
int fd, rc;
- ENTRY;
rc = lprocfs_write_helper(buffer, count, &fd);
if (rc)
- RETURN(rc);
+ return rc;
if (fd < 0)
- RETURN(-ERANGE);
+ return -ERANGE;
CWARN("message to fd %d\n", fd);
len = sizeof(*lh) + sizeof(*hal) + MTI_NAME_MAXLEN +
@@ -141,8 +139,8 @@ static ssize_t mdc_kuc_write(struct file *file, const char *buffer,
}
OBD_FREE(lh, len);
if (rc < 0)
- RETURN(rc);
- RETURN(count);
+ return rc;
+ return count;
}
struct file_operations mdc_kuc_fops = {
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
index e789aed98de..b2de4780367 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
@@ -45,10 +45,10 @@ static void __mdc_pack_body(struct mdt_body *b, __u32 suppgid)
LASSERT (b != NULL);
b->suppgid = suppgid;
- b->uid = current_uid();
- b->gid = current_gid();
- b->fsuid = current_fsuid();
- b->fsgid = current_fsgid();
+ b->uid = from_kuid(&init_user_ns, current_uid());
+ b->gid = from_kgid(&init_user_ns, current_gid());
+ b->fsuid = from_kuid(&init_user_ns, current_fsuid());
+ b->fsgid = from_kgid(&init_user_ns, current_fsgid());
b->capability = cfs_curproc_cap_pack();
}
@@ -219,8 +219,8 @@ void mdc_open_pack(struct ptlrpc_request *req, struct md_op_data *op_data,
/* XXX do something about time, uid, gid */
rec->cr_opcode = REINT_OPEN;
- rec->cr_fsuid = current_fsuid();
- rec->cr_fsgid = current_fsgid();
+ rec->cr_fsuid = from_kuid(&init_user_ns, current_fsuid());
+ rec->cr_fsgid = from_kgid(&init_user_ns, current_fsgid());
rec->cr_cap = cfs_curproc_cap_pack();
if (op_data != NULL) {
rec->cr_fid1 = op_data->op_fid1;
@@ -299,16 +299,16 @@ static void mdc_setattr_pack_rec(struct mdt_rec_setattr *rec,
struct md_op_data *op_data)
{
rec->sa_opcode = REINT_SETATTR;
- rec->sa_fsuid = current_fsuid();
- rec->sa_fsgid = current_fsgid();
+ rec->sa_fsuid = from_kuid(&init_user_ns, current_fsuid());
+ rec->sa_fsgid = from_kgid(&init_user_ns, current_fsgid());
rec->sa_cap = cfs_curproc_cap_pack();
rec->sa_suppgid = -1;
rec->sa_fid = op_data->op_fid1;
rec->sa_valid = attr_pack(op_data->op_attr.ia_valid);
rec->sa_mode = op_data->op_attr.ia_mode;
- rec->sa_uid = op_data->op_attr.ia_uid;
- rec->sa_gid = op_data->op_attr.ia_gid;
+ rec->sa_uid = from_kuid(&init_user_ns, op_data->op_attr.ia_uid);
+ rec->sa_gid = from_kgid(&init_user_ns, op_data->op_attr.ia_gid);
rec->sa_size = op_data->op_attr.ia_size;
rec->sa_blocks = op_data->op_attr_blocks;
rec->sa_atime = LTIME_S(op_data->op_attr.ia_atime);
@@ -316,8 +316,9 @@ static void mdc_setattr_pack_rec(struct mdt_rec_setattr *rec,
rec->sa_ctime = LTIME_S(op_data->op_attr.ia_ctime);
rec->sa_attr_flags = ((struct ll_iattr *)&op_data->op_attr)->ia_attr_flags;
if ((op_data->op_attr.ia_valid & ATTR_GID) &&
- current_is_in_group(op_data->op_attr.ia_gid))
- rec->sa_suppgid = op_data->op_attr.ia_gid;
+ in_group_p(op_data->op_attr.ia_gid))
+ rec->sa_suppgid =
+ from_kgid(&init_user_ns, op_data->op_attr.ia_gid);
else
rec->sa_suppgid = op_data->op_suppgids[0];
@@ -504,11 +505,11 @@ void mdc_close_pack(struct ptlrpc_request *req, struct md_op_data *op_data)
static int mdc_req_avail(struct client_obd *cli, struct mdc_cache_waiter *mcw)
{
int rc;
- ENTRY;
+
client_obd_list_lock(&cli->cl_loi_list_lock);
rc = list_empty(&mcw->mcw_entry);
client_obd_list_unlock(&cli->cl_loi_list_lock);
- RETURN(rc);
+ return rc;
};
/* We record requests in flight in cli->cl_r_in_flight here.
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
index 1cc90b635fb..fb5a9959bf7 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
@@ -115,13 +115,12 @@ int mdc_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
{
struct ldlm_lock *lock;
struct inode *new_inode = data;
- ENTRY;
if(bits)
*bits = 0;
if (!*lockh)
- RETURN(0);
+ return 0;
lock = ldlm_handle2lock((struct lustre_handle *)lockh);
@@ -144,7 +143,7 @@ int mdc_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
unlock_res_and_lock(lock);
LDLM_LOCK_PUT(lock);
- RETURN(0);
+ return 0;
}
ldlm_mode_t mdc_lock_match(struct obd_export *exp, __u64 flags,
@@ -154,12 +153,11 @@ ldlm_mode_t mdc_lock_match(struct obd_export *exp, __u64 flags,
{
struct ldlm_res_id res_id;
ldlm_mode_t rc;
- ENTRY;
fid_build_reg_res_name(fid, &res_id);
rc = ldlm_lock_match(class_exp2obd(exp)->obd_namespace, flags,
&res_id, type, policy, mode, lockh, 0);
- RETURN(rc);
+ return rc;
}
int mdc_cancel_unused(struct obd_export *exp,
@@ -173,12 +171,10 @@ int mdc_cancel_unused(struct obd_export *exp,
struct obd_device *obd = class_exp2obd(exp);
int rc;
- ENTRY;
-
fid_build_reg_res_name(fid, &res_id);
rc = ldlm_cli_cancel_unused_resource(obd->obd_namespace, &res_id,
policy, mode, flags, opaque);
- RETURN(rc);
+ return rc;
}
int mdc_null_inode(struct obd_export *exp,
@@ -187,7 +183,6 @@ int mdc_null_inode(struct obd_export *exp,
struct ldlm_res_id res_id;
struct ldlm_resource *res;
struct ldlm_namespace *ns = class_exp2obd(exp)->obd_namespace;
- ENTRY;
LASSERTF(ns != NULL, "no namespace passed\n");
@@ -195,14 +190,14 @@ int mdc_null_inode(struct obd_export *exp,
res = ldlm_resource_get(ns, NULL, &res_id, 0, 0);
if(res == NULL)
- RETURN(0);
+ return 0;
lock_res(res);
res->lr_lvb_inode = NULL;
unlock_res(res);
ldlm_resource_putref(res);
- RETURN(0);
+ return 0;
}
/* find any ldlm lock of the inode in mdc
@@ -215,16 +210,15 @@ int mdc_find_cbdata(struct obd_export *exp,
{
struct ldlm_res_id res_id;
int rc = 0;
- ENTRY;
fid_build_reg_res_name((struct lu_fid*)fid, &res_id);
rc = ldlm_resource_iterate(class_exp2obd(exp)->obd_namespace, &res_id,
it, data);
if (rc == LDLM_ITER_STOP)
- RETURN(1);
+ return 1;
else if (rc == LDLM_ITER_CONTINUE)
- RETURN(0);
- RETURN(rc);
+ return 0;
+ return rc;
}
static inline void mdc_clear_replay_flag(struct ptlrpc_request *req, int rc)
@@ -281,7 +275,6 @@ static struct ptlrpc_request *mdc_intent_open_pack(struct obd_export *exp,
int count = 0;
int mode;
int rc;
- ENTRY;
it->it_create_mode = (it->it_create_mode & ~S_IFMT) | S_IFREG;
@@ -314,7 +307,7 @@ static struct ptlrpc_request *mdc_intent_open_pack(struct obd_export *exp,
&RQF_LDLM_INTENT_OPEN);
if (req == NULL) {
ldlm_lock_list_put(&cancels, l_bl_ast, count);
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
}
/* parent capability */
@@ -362,12 +355,11 @@ static struct ptlrpc_request *mdc_intent_unlink_pack(struct obd_export *exp,
struct obd_device *obddev = class_exp2obd(exp);
struct ldlm_intent *lit;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_LDLM_INTENT_UNLINK);
if (req == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
@@ -376,7 +368,7 @@ static struct ptlrpc_request *mdc_intent_unlink_pack(struct obd_export *exp,
rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
if (rc) {
ptlrpc_request_free(req);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
/* pack the intent */
@@ -391,7 +383,7 @@ static struct ptlrpc_request *mdc_intent_unlink_pack(struct obd_export *exp,
req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER,
obddev->u.cli.cl_max_mds_cookiesize);
ptlrpc_request_set_replen(req);
- RETURN(req);
+ return req;
}
static struct ptlrpc_request *mdc_intent_getattr_pack(struct obd_export *exp,
@@ -407,12 +399,11 @@ static struct ptlrpc_request *mdc_intent_getattr_pack(struct obd_export *exp,
OBD_MD_FLRMTPERM : OBD_MD_FLACL);
struct ldlm_intent *lit;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_LDLM_INTENT_GETATTR);
if (req == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
@@ -421,7 +412,7 @@ static struct ptlrpc_request *mdc_intent_getattr_pack(struct obd_export *exp,
rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
if (rc) {
ptlrpc_request_free(req);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
/* pack the intent */
@@ -438,7 +429,7 @@ static struct ptlrpc_request *mdc_intent_getattr_pack(struct obd_export *exp,
req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER,
sizeof(struct mdt_remote_perm));
ptlrpc_request_set_replen(req);
- RETURN(req);
+ return req;
}
static struct ptlrpc_request *mdc_intent_layout_pack(struct obd_export *exp,
@@ -450,18 +441,17 @@ static struct ptlrpc_request *mdc_intent_layout_pack(struct obd_export *exp,
struct ldlm_intent *lit;
struct layout_intent *layout;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_LDLM_INTENT_LAYOUT);
if (req == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_CLIENT, 0);
rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
if (rc) {
ptlrpc_request_free(req);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
/* pack the intent */
@@ -477,7 +467,7 @@ static struct ptlrpc_request *mdc_intent_layout_pack(struct obd_export *exp,
req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER,
obd->u.cli.cl_max_mds_easize);
ptlrpc_request_set_replen(req);
- RETURN(req);
+ return req;
}
static struct ptlrpc_request *
@@ -485,21 +475,20 @@ mdc_enqueue_pack(struct obd_export *exp, int lvb_len)
{
struct ptlrpc_request *req;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_LDLM_ENQUEUE);
if (req == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
if (rc) {
ptlrpc_request_free(req);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER, lvb_len);
ptlrpc_request_set_replen(req);
- RETURN(req);
+ return req;
}
static int mdc_finish_enqueue(struct obd_export *exp,
@@ -516,7 +505,6 @@ static int mdc_finish_enqueue(struct obd_export *exp,
struct ldlm_lock *lock;
void *lvb_data = NULL;
int lvb_len = 0;
- ENTRY;
LASSERT(rc >= 0);
/* Similarly, if we're going to replay this request, we don't want to
@@ -579,7 +567,7 @@ static int mdc_finish_enqueue(struct obd_export *exp,
body = req_capsule_server_get(pill, &RMF_MDT_BODY);
if (body == NULL) {
CERROR ("Can't swab mdt_body\n");
- RETURN (-EPROTO);
+ return -EPROTO;
}
if (it_disposition(it, DISP_OPEN_OPEN) &&
@@ -605,7 +593,7 @@ static int mdc_finish_enqueue(struct obd_export *exp,
eadata = req_capsule_server_sized_get(pill, &RMF_MDT_MD,
body->eadatasize);
if (eadata == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
/* save lvb data and length in case this is for layout
* lock */
@@ -649,14 +637,14 @@ static int mdc_finish_enqueue(struct obd_export *exp,
perm = req_capsule_server_swab_get(pill, &RMF_ACL,
lustre_swab_mdt_remote_perm);
if (perm == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (body->valid & OBD_MD_FLMDSCAPA) {
struct lustre_capa *capa, *p;
capa = req_capsule_server_get(pill, &RMF_CAPA1);
if (capa == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
if (it->it_op & IT_OPEN) {
/* client fid capa will be checked in replay */
@@ -670,7 +658,7 @@ static int mdc_finish_enqueue(struct obd_export *exp,
capa = req_capsule_server_get(pill, &RMF_CAPA2);
if (capa == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
}
} else if (it->it_op & IT_LAYOUT) {
/* maybe the lock was granted right away and layout
@@ -680,7 +668,7 @@ static int mdc_finish_enqueue(struct obd_export *exp,
lvb_data = req_capsule_server_sized_get(pill,
&RMF_DLM_LVB, lvb_len);
if (lvb_data == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
}
}
@@ -695,7 +683,7 @@ static int mdc_finish_enqueue(struct obd_export *exp,
OBD_ALLOC_LARGE(lmm, lvb_len);
if (lmm == NULL) {
LDLM_LOCK_PUT(lock);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
memcpy(lmm, lvb_data, lvb_len);
@@ -713,7 +701,7 @@ static int mdc_finish_enqueue(struct obd_export *exp,
if (lock != NULL)
LDLM_LOCK_PUT(lock);
- RETURN(rc);
+ return rc;
}
/* We always reserve enough space in the reply packet for a stripe MD, because
@@ -738,7 +726,6 @@ int mdc_enqueue(struct obd_export *exp, struct ldlm_enqueue_info *einfo,
int generation, resends = 0;
struct ldlm_reply *lockrep;
enum lvb_type lvb_type = 0;
- ENTRY;
LASSERTF(!it || einfo->ei_type == LDLM_IBITS, "lock type %d\n",
einfo->ei_type);
@@ -780,17 +767,17 @@ resend:
req = mdc_enqueue_pack(exp, 0);
} else if (it->it_op & IT_LAYOUT) {
if (!imp_connect_lvb_type(class_exp2cliimp(exp)))
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
req = mdc_intent_layout_pack(exp, it, op_data);
lvb_type = LVB_T_LAYOUT;
} else {
LBUG();
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (IS_ERR(req))
- RETURN(PTR_ERR(req));
+ return PTR_ERR(req);
if (req != NULL && it && it->it_op & IT_CREAT)
/* ask ptlrpc not to resend on EINPROGRESS since we have our own
@@ -813,7 +800,7 @@ resend:
mdc_put_rpc_lock(obddev->u.cli.cl_rpc_lock, it);
mdc_clear_replay_flag(req, 0);
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
}
@@ -823,8 +810,14 @@ resend:
/* For flock requests we immediatelly return without further
delay and let caller deal with the rest, since rest of
this function metadata processing makes no sense for flock
- requests anyway */
- RETURN(rc);
+ requests anyway. But in case of problem during comms with
+ Server (ETIMEDOUT) or any signal/kill attempt (EINTR), we
+ can not rely on caller and this mainly for F_UNLCKs
+ (explicits or automatically generated by Kernel to clean
+ current FLocks upon exit) that can't be trashed */
+ if ((rc == -EINTR) || (rc == -ETIMEDOUT))
+ goto resend;
+ return rc;
}
mdc_exit_request(&obddev->u.cli);
@@ -834,12 +827,15 @@ resend:
CERROR("ldlm_cli_enqueue: %d\n", rc);
mdc_clear_replay_flag(req, rc);
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
lockrep = req_capsule_server_get(&req->rq_pill, &RMF_DLM_REP);
LASSERT(lockrep != NULL);
+ lockrep->lock_policy_res2 =
+ ptlrpc_status_ntoh(lockrep->lock_policy_res2);
+
/* Retry the create infinitely when we get -EINPROGRESS from
* server. This is required by the new quota design. */
if (it && it->it_op & IT_CREAT &&
@@ -856,7 +852,7 @@ resend:
goto resend;
} else {
CDEBUG(D_HA, "resend cross eviction\n");
- RETURN(-EIO);
+ return -EIO;
}
}
@@ -868,7 +864,7 @@ resend:
}
ptlrpc_req_finished(req);
}
- RETURN(rc);
+ return rc;
}
static int mdc_finish_intent_lock(struct obd_export *exp,
@@ -882,7 +878,6 @@ static int mdc_finish_intent_lock(struct obd_export *exp,
struct ldlm_lock *lock;
int rc;
-
LASSERT(request != NULL);
LASSERT(request != LP_POISON);
LASSERT(request->rq_repmsg != LP_POISON);
@@ -891,11 +886,11 @@ static int mdc_finish_intent_lock(struct obd_export *exp,
/* The server failed before it even started executing the
* intent, i.e. because it couldn't unpack the request. */
LASSERT(it->d.lustre.it_status != 0);
- RETURN(it->d.lustre.it_status);
+ return it->d.lustre.it_status;
}
rc = it_open_error(DISP_IT_EXECD, it);
if (rc)
- RETURN(rc);
+ return rc;
mdt_body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY);
LASSERT(mdt_body != NULL); /* mdc_enqueue checked */
@@ -917,13 +912,13 @@ static int mdc_finish_intent_lock(struct obd_export *exp,
CDEBUG(D_DENTRY, "Found stale data "DFID"("DFID")/"DFID
"\n", PFID(&op_data->op_fid2),
PFID(&op_data->op_fid2), PFID(&mdt_body->fid1));
- RETURN(-ESTALE);
+ return -ESTALE;
}
}
rc = it_open_error(DISP_LOOKUP_EXECD, it);
if (rc)
- RETURN(rc);
+ return rc;
/* keep requests around for the multiple phases of the call
* this shows the DISP_XX must guarantee we make it into the call
@@ -984,7 +979,7 @@ static int mdc_finish_intent_lock(struct obd_export *exp,
CDEBUG(D_DENTRY,"D_IT dentry %.*s intent: %s status %d disp %x rc %d\n",
op_data->op_namelen, op_data->op_name, ldlm_it2str(it->it_op),
it->d.lustre.it_status, it->d.lustre.it_disposition, rc);
- RETURN(rc);
+ return rc;
}
int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
@@ -997,7 +992,6 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
struct lustre_handle lockh;
ldlm_policy_data_t policy;
ldlm_mode_t mode;
- ENTRY;
if (it->d.lustre.it_lock_handle) {
lockh.cookie = it->d.lustre.it_lock_handle;
@@ -1029,7 +1023,7 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
it->d.lustre.it_lock_mode = 0;
}
- RETURN(!!mode);
+ return !!mode;
}
/*
@@ -1067,7 +1061,7 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
{
struct lustre_handle lockh;
int rc = 0;
- ENTRY;
+
LASSERT(it);
CDEBUG(D_DLMTRACE, "(name: %.*s,"DFID") in obj "DFID
@@ -1087,7 +1081,7 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
/* Only return failure if it was not GETATTR by cfid
(from inode_revalidate) */
if (rc || op_data->op_namelen != 0)
- RETURN(rc);
+ return rc;
}
/* lookup_it may be called only after revalidate_it has run, because
@@ -1099,22 +1093,25 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
* this and use the request from revalidate. In this case, revalidate
* never dropped its reference, so the refcounts are all OK */
if (!it_disposition(it, DISP_ENQ_COMPLETE)) {
- struct ldlm_enqueue_info einfo =
- { LDLM_IBITS, it_to_lock_mode(it), cb_blocking,
- ldlm_completion_ast, NULL, NULL, NULL };
+ struct ldlm_enqueue_info einfo = {
+ .ei_type = LDLM_IBITS,
+ .ei_mode = it_to_lock_mode(it),
+ .ei_cb_bl = cb_blocking,
+ .ei_cb_cp = ldlm_completion_ast,
+ };
/* For case if upper layer did not alloc fid, do it now. */
if (!fid_is_sane(&op_data->op_fid2) && it->it_op & IT_CREAT) {
rc = mdc_fid_alloc(exp, &op_data->op_fid2, op_data);
if (rc < 0) {
CERROR("Can't alloc new fid, rc %d\n", rc);
- RETURN(rc);
+ return rc;
}
}
rc = mdc_enqueue(exp, &einfo, it, op_data, &lockh,
lmm, lmmsize, NULL, extra_lock_flags);
if (rc < 0)
- RETURN(rc);
+ return rc;
} else if (!fid_is_sane(&op_data->op_fid2) ||
!(it->it_create_mode & M_CHECK_STALE)) {
/* DISP_ENQ_COMPLETE set means there is extra reference on
@@ -1125,7 +1122,7 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
}
*reqp = it->d.lustre.it_data;
rc = mdc_finish_intent_lock(exp, *reqp, op_data, it, &lockh);
- RETURN(rc);
+ return rc;
}
static int mdc_intent_getattr_async_interpret(const struct lu_env *env,
@@ -1139,8 +1136,8 @@ static int mdc_intent_getattr_async_interpret(const struct lu_env *env,
struct lookup_intent *it;
struct lustre_handle *lockh;
struct obd_device *obddev;
+ struct ldlm_reply *lockrep;
__u64 flags = LDLM_FL_HAS_INTENT;
- ENTRY;
it = &minfo->mi_it;
lockh = &minfo->mi_lockh;
@@ -1159,12 +1156,17 @@ static int mdc_intent_getattr_async_interpret(const struct lu_env *env,
GOTO(out, rc);
}
+ lockrep = req_capsule_server_get(&req->rq_pill, &RMF_DLM_REP);
+ LASSERT(lockrep != NULL);
+
+ lockrep->lock_policy_res2 =
+ ptlrpc_status_ntoh(lockrep->lock_policy_res2);
+
rc = mdc_finish_enqueue(exp, req, einfo, it, lockh, rc);
if (rc)
GOTO(out, rc);
rc = mdc_finish_intent_lock(exp, req, &minfo->mi_data, it, lockh);
- EXIT;
out:
OBD_FREE_PTR(einfo);
@@ -1191,7 +1193,6 @@ int mdc_intent_getattr_async(struct obd_export *exp,
};
int rc = 0;
__u64 flags = LDLM_FL_HAS_INTENT;
- ENTRY;
CDEBUG(D_DLMTRACE,"name: %.*s in inode "DFID", intent: %s flags %#o\n",
op_data->op_namelen, op_data->op_name, PFID(&op_data->op_fid1),
@@ -1200,12 +1201,12 @@ int mdc_intent_getattr_async(struct obd_export *exp,
fid_build_reg_res_name(&op_data->op_fid1, &res_id);
req = mdc_intent_getattr_pack(exp, it, op_data);
if (!req)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = mdc_enter_request(&obddev->u.cli);
if (rc != 0) {
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
rc = ldlm_cli_enqueue(exp, &req, einfo, &res_id, &policy, &flags, NULL,
@@ -1213,7 +1214,7 @@ int mdc_intent_getattr_async(struct obd_export *exp,
if (rc < 0) {
mdc_exit_request(&obddev->u.cli);
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
CLASSERT(sizeof(*ga) <= sizeof(req->rq_async_args));
@@ -1225,5 +1226,5 @@ int mdc_intent_getattr_async(struct obd_export *exp,
req->rq_interpret_reply = mdc_intent_getattr_async_interpret;
ptlrpcd_add_req(req, PDL_POLICY_LOCAL, -1);
- RETURN(0);
+ return 0;
}
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_reint.c b/drivers/staging/lustre/lustre/mdc/mdc_reint.c
index 5e25a07c52b..9f3a345f34e 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_reint.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_reint.c
@@ -75,7 +75,6 @@ int mdc_resource_get_unused(struct obd_export *exp, struct lu_fid *fid,
struct ldlm_res_id res_id;
struct ldlm_resource *res;
int count;
- ENTRY;
/* Return, i.e. cancel nothing, only if ELC is supported (flag in
* export) but disabled through procfs (flag in NS).
@@ -84,13 +83,13 @@ int mdc_resource_get_unused(struct obd_export *exp, struct lu_fid *fid,
* when we still want to cancel locks in advance and just cancel them
* locally, without sending any RPC. */
if (exp_connect_cancelset(exp) && !ns_connect_cancelset(ns))
- RETURN(0);
+ return 0;
fid_build_reg_res_name(fid, &res_id);
res = ldlm_resource_get(exp->exp_obd->obd_namespace,
NULL, &res_id, 0, 0);
if (res == NULL)
- RETURN(0);
+ return 0;
LDLM_RESOURCE_ADDREF(res);
/* Initialize ibits lock policy. */
policy.l_inodebits.bits = bits;
@@ -98,7 +97,7 @@ int mdc_resource_get_unused(struct obd_export *exp, struct lu_fid *fid,
mode, 0, 0, NULL);
LDLM_RESOURCE_DELREF(res);
ldlm_resource_putref(res);
- RETURN(count);
+ return count;
}
int mdc_setattr(struct obd_export *exp, struct md_op_data *op_data,
@@ -111,7 +110,6 @@ int mdc_setattr(struct obd_export *exp, struct md_op_data *op_data,
struct obd_device *obd = exp->exp_obd;
int count = 0, rc;
__u64 bits;
- ENTRY;
LASSERT(op_data != NULL);
@@ -127,7 +125,7 @@ int mdc_setattr(struct obd_export *exp, struct md_op_data *op_data,
&RQF_MDS_REINT_SETATTR);
if (req == NULL) {
ldlm_lock_list_put(&cancels, l_bl_ast, count);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
if ((op_data->op_flags & (MF_SOM_CHANGE | MF_EPOCH_OPEN)) == 0)
@@ -140,7 +138,7 @@ int mdc_setattr(struct obd_export *exp, struct md_op_data *op_data,
rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
rpc_lock = obd->u.cli.cl_rpc_lock;
@@ -203,7 +201,7 @@ int mdc_setattr(struct obd_export *exp, struct md_op_data *op_data,
obd_mod_put(*mod);
req->rq_commit_cb(req);
}
- RETURN(rc);
+ return rc;
}
int mdc_create(struct obd_export *exp, struct md_op_data *op_data,
@@ -217,7 +215,6 @@ int mdc_create(struct obd_export *exp, struct md_op_data *op_data,
struct obd_import *import = exp->exp_obd->u.cli.cl_import;
int generation = import->imp_generation;
LIST_HEAD(cancels);
- ENTRY;
/* For case if upper layer did not alloc fid, do it now. */
if (!fid_is_sane(&op_data->op_fid2)) {
@@ -228,7 +225,7 @@ int mdc_create(struct obd_export *exp, struct md_op_data *op_data,
rc = mdc_fid_alloc(exp, &op_data->op_fid2, op_data);
if (rc < 0) {
CERROR("Can't alloc new fid, rc %d\n", rc);
- RETURN(rc);
+ return rc;
}
}
@@ -244,7 +241,7 @@ rebuild:
&RQF_MDS_REINT_CREATE_RMT_ACL);
if (req == NULL) {
ldlm_lock_list_put(&cancels, l_bl_ast, count);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
@@ -255,7 +252,7 @@ rebuild:
rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
/*
@@ -298,7 +295,7 @@ rebuild:
goto rebuild;
} else {
CDEBUG(D_HA, "resend cross eviction\n");
- RETURN(-EIO);
+ return -EIO;
}
} else if (rc == 0) {
struct mdt_body *body;
@@ -315,7 +312,7 @@ rebuild:
}
*request = req;
- RETURN(rc);
+ return rc;
}
int mdc_unlink(struct obd_export *exp, struct md_op_data *op_data,
@@ -325,7 +322,6 @@ int mdc_unlink(struct obd_export *exp, struct md_op_data *op_data,
struct obd_device *obd = class_exp2obd(exp);
struct ptlrpc_request *req = *request;
int count = 0, rc;
- ENTRY;
LASSERT(req == NULL);
@@ -345,7 +341,7 @@ int mdc_unlink(struct obd_export *exp, struct md_op_data *op_data,
&RQF_MDS_REINT_UNLINK);
if (req == NULL) {
ldlm_lock_list_put(&cancels, l_bl_ast, count);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
@@ -354,7 +350,7 @@ int mdc_unlink(struct obd_export *exp, struct md_op_data *op_data,
rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_unlink_pack(req, op_data);
@@ -370,7 +366,7 @@ int mdc_unlink(struct obd_export *exp, struct md_op_data *op_data,
rc = mdc_reint(req, obd->u.cli.cl_rpc_lock, LUSTRE_IMP_FULL);
if (rc == -ERESTARTSYS)
rc = 0;
- RETURN(rc);
+ return rc;
}
int mdc_link(struct obd_export *exp, struct md_op_data *op_data,
@@ -380,7 +376,6 @@ int mdc_link(struct obd_export *exp, struct md_op_data *op_data,
struct obd_device *obd = exp->exp_obd;
struct ptlrpc_request *req;
int count = 0, rc;
- ENTRY;
if ((op_data->op_flags & MF_MDC_CANCEL_FID2) &&
(fid_is_sane(&op_data->op_fid2)))
@@ -396,7 +391,7 @@ int mdc_link(struct obd_export *exp, struct md_op_data *op_data,
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_REINT_LINK);
if (req == NULL) {
ldlm_lock_list_put(&cancels, l_bl_ast, count);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
mdc_set_capa_size(req, &RMF_CAPA2, op_data->op_capa2);
@@ -406,7 +401,7 @@ int mdc_link(struct obd_export *exp, struct md_op_data *op_data,
rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_link_pack(req, op_data);
@@ -417,7 +412,7 @@ int mdc_link(struct obd_export *exp, struct md_op_data *op_data,
if (rc == -ERESTARTSYS)
rc = 0;
- RETURN(rc);
+ return rc;
}
int mdc_rename(struct obd_export *exp, struct md_op_data *op_data,
@@ -428,7 +423,6 @@ int mdc_rename(struct obd_export *exp, struct md_op_data *op_data,
struct obd_device *obd = exp->exp_obd;
struct ptlrpc_request *req;
int count = 0, rc;
- ENTRY;
if ((op_data->op_flags & MF_MDC_CANCEL_FID1) &&
(fid_is_sane(&op_data->op_fid1)))
@@ -455,7 +449,7 @@ int mdc_rename(struct obd_export *exp, struct md_op_data *op_data,
&RQF_MDS_REINT_RENAME);
if (req == NULL) {
ldlm_lock_list_put(&cancels, l_bl_ast, count);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
@@ -466,7 +460,7 @@ int mdc_rename(struct obd_export *exp, struct md_op_data *op_data,
rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
if (exp_connect_cancelset(exp) && req)
@@ -485,5 +479,5 @@ int mdc_rename(struct obd_export *exp, struct md_op_data *op_data,
if (rc == -ERESTARTSYS)
rc = 0;
- RETURN(rc);
+ return rc;
}
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c
index 3cf9d8d3f2e..ed3a7a05557 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_request.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c
@@ -65,21 +65,20 @@ int mdc_unpack_capa(struct obd_export *exp, struct ptlrpc_request *req,
{
struct lustre_capa *capa;
struct obd_capa *c;
- ENTRY;
/* swabbed already in mdc_enqueue */
capa = req_capsule_server_get(&req->rq_pill, field);
if (capa == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
c = alloc_capa(CAPA_SITE_CLIENT);
if (IS_ERR(c)) {
CDEBUG(D_INFO, "alloc capa failed!\n");
- RETURN(PTR_ERR(c));
+ return PTR_ERR(c);
} else {
c->c_capa = *capa;
*oc = c;
- RETURN(0);
+ return 0;
}
}
@@ -109,12 +108,11 @@ static int send_getstatus(struct obd_import *imp, struct lu_fid *rootfid,
struct ptlrpc_request *req;
struct mdt_body *body;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_GETSTATUS,
LUSTRE_MDS_VERSION, MDS_GETSTATUS);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_pack_body(req, NULL, NULL, 0, 0, -1, 0);
lustre_msg_add_flags(req->rq_reqmsg, msg_flags);
@@ -141,7 +139,6 @@ static int send_getstatus(struct obd_import *imp, struct lu_fid *rootfid,
"root fid="DFID", last_committed="LPU64"\n",
PFID(rootfid),
lustre_msg_get_last_committed(req->rq_repmsg));
- EXIT;
out:
ptlrpc_req_finished(req);
return rc;
@@ -172,17 +169,16 @@ static int mdc_getattr_common(struct obd_export *exp,
struct mdt_body *body;
void *eadata;
int rc;
- ENTRY;
/* Request message already built. */
rc = ptlrpc_queue_wait(req);
if (rc != 0)
- RETURN(rc);
+ return rc;
/* sanity check for the reply */
body = req_capsule_server_get(pill, &RMF_MDT_BODY);
if (body == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
CDEBUG(D_NET, "mode: %o\n", body->mode);
@@ -192,7 +188,7 @@ static int mdc_getattr_common(struct obd_export *exp,
eadata = req_capsule_server_sized_get(pill, &RMF_MDT_MD,
body->eadatasize);
if (eadata == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (body->valid & OBD_MD_FLRMTPERM) {
@@ -202,17 +198,17 @@ static int mdc_getattr_common(struct obd_export *exp,
perm = req_capsule_server_swab_get(pill, &RMF_ACL,
lustre_swab_mdt_remote_perm);
if (perm == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (body->valid & OBD_MD_FLMDSCAPA) {
struct lustre_capa *capa;
capa = req_capsule_server_get(pill, &RMF_CAPA1);
if (capa == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
}
- RETURN(0);
+ return 0;
}
int mdc_getattr(struct obd_export *exp, struct md_op_data *op_data,
@@ -220,24 +216,23 @@ int mdc_getattr(struct obd_export *exp, struct md_op_data *op_data,
{
struct ptlrpc_request *req;
int rc;
- ENTRY;
/* Single MDS without an LMV case */
if (op_data->op_flags & MF_GET_MDT_IDX) {
op_data->op_mds = 0;
- RETURN(0);
+ return 0;
}
*request = NULL;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_GETATTR);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_GETATTR);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
@@ -257,7 +252,7 @@ int mdc_getattr(struct obd_export *exp, struct md_op_data *op_data,
ptlrpc_req_finished(req);
else
*request = req;
- RETURN(rc);
+ return rc;
}
int mdc_getattr_name(struct obd_export *exp, struct md_op_data *op_data,
@@ -265,13 +260,12 @@ int mdc_getattr_name(struct obd_export *exp, struct md_op_data *op_data,
{
struct ptlrpc_request *req;
int rc;
- ENTRY;
*request = NULL;
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_MDS_GETATTR_NAME);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
@@ -280,7 +274,7 @@ int mdc_getattr_name(struct obd_export *exp, struct md_op_data *op_data,
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_GETATTR_NAME);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
@@ -303,7 +297,7 @@ int mdc_getattr_name(struct obd_export *exp, struct md_op_data *op_data,
ptlrpc_req_finished(req);
else
*request = req;
- RETURN(rc);
+ return rc;
}
static int mdc_is_subdir(struct obd_export *exp,
@@ -314,14 +308,12 @@ static int mdc_is_subdir(struct obd_export *exp,
struct ptlrpc_request *req;
int rc;
- ENTRY;
-
*request = NULL;
req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
&RQF_MDS_IS_SUBDIR, LUSTRE_MDS_VERSION,
MDS_IS_SUBDIR);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_is_subdir_pack(req, pfid, cfid, 0);
ptlrpc_request_set_replen(req);
@@ -331,7 +323,7 @@ static int mdc_is_subdir(struct obd_export *exp,
ptlrpc_req_finished(req);
else
*request = req;
- RETURN(rc);
+ return rc;
}
static int mdc_xattr_common(struct obd_export *exp,const struct req_format *fmt,
@@ -345,12 +337,11 @@ static int mdc_xattr_common(struct obd_export *exp,const struct req_format *fmt,
int xattr_namelen = 0;
char *tmp;
int rc;
- ENTRY;
*request = NULL;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), fmt);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, oc);
if (xattr_name) {
@@ -367,7 +358,7 @@ static int mdc_xattr_common(struct obd_export *exp,const struct req_format *fmt,
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, opcode);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
if (opcode == MDS_REINT) {
@@ -377,12 +368,8 @@ static int mdc_xattr_common(struct obd_export *exp,const struct req_format *fmt,
sizeof(struct mdt_rec_reint));
rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT);
rec->sx_opcode = REINT_SETXATTR;
- /* TODO:
- * cfs_curproc_fs{u,g}id() should replace
- * current->fs{u,g}id for portability.
- */
- rec->sx_fsuid = current_fsuid();
- rec->sx_fsgid = current_fsgid();
+ rec->sx_fsuid = from_kuid(&init_user_ns, current_fsuid());
+ rec->sx_fsgid = from_kgid(&init_user_ns, current_fsgid());
rec->sx_cap = cfs_curproc_cap_pack();
rec->sx_suppgid1 = suppgid;
rec->sx_suppgid2 = -1;
@@ -424,7 +411,7 @@ static int mdc_xattr_common(struct obd_export *exp,const struct req_format *fmt,
ptlrpc_req_finished(req);
else
*request = req;
- RETURN(rc);
+ return rc;
}
int mdc_setxattr(struct obd_export *exp, const struct lu_fid *fid,
@@ -457,32 +444,31 @@ static int mdc_unpack_acl(struct ptlrpc_request *req, struct lustre_md *md)
struct posix_acl *acl;
void *buf;
int rc;
- ENTRY;
if (!body->aclsize)
- RETURN(0);
+ return 0;
buf = req_capsule_server_sized_get(pill, &RMF_ACL, body->aclsize);
if (!buf)
- RETURN(-EPROTO);
+ return -EPROTO;
acl = posix_acl_from_xattr(&init_user_ns, buf, body->aclsize);
if (IS_ERR(acl)) {
rc = PTR_ERR(acl);
CERROR("convert xattr to acl: %d\n", rc);
- RETURN(rc);
+ return rc;
}
rc = posix_acl_valid(acl);
if (rc) {
CERROR("validate acl: %d\n", rc);
posix_acl_release(acl);
- RETURN(rc);
+ return rc;
}
md->posix_acl = acl;
- RETURN(0);
+ return 0;
}
#else
#define mdc_unpack_acl(req, md) 0
@@ -494,7 +480,6 @@ int mdc_get_lustre_md(struct obd_export *exp, struct ptlrpc_request *req,
{
struct req_capsule *pill = &req->rq_pill;
int rc;
- ENTRY;
LASSERT(md);
memset(md, 0, sizeof(*md));
@@ -546,7 +531,7 @@ int mdc_get_lustre_md(struct obd_export *exp, struct ptlrpc_request *req,
if (md->body->eadatasize == 0) {
CDEBUG(D_INFO, "OBD_MD_FLDIREA is set, "
"but eadatasize 0\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (md->body->valid & OBD_MD_MEA) {
lmvsize = md->body->eadatasize;
@@ -611,7 +596,6 @@ int mdc_get_lustre_md(struct obd_export *exp, struct ptlrpc_request *req,
md->oss_capa = oc;
}
- EXIT;
out:
if (rc) {
if (md->oss_capa) {
@@ -633,8 +617,7 @@ out:
int mdc_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
{
- ENTRY;
- RETURN(0);
+ return 0;
}
/**
@@ -648,12 +631,10 @@ void mdc_replay_open(struct ptlrpc_request *req)
struct obd_client_handle *och;
struct lustre_handle old;
struct mdt_body *body;
- ENTRY;
if (mod == NULL) {
DEBUG_REQ(D_ERROR, req,
"Can't properly replay without open data.");
- EXIT;
return;
}
@@ -687,7 +668,6 @@ void mdc_replay_open(struct ptlrpc_request *req)
DEBUG_REQ(D_HA, close_req, "updating close body with new fh");
epoch->handle = body->handle;
}
- EXIT;
}
void mdc_commit_open(struct ptlrpc_request *req)
@@ -726,10 +706,9 @@ int mdc_set_open_replay_data(struct obd_export *exp,
struct mdt_rec_create *rec;
struct mdt_body *body;
struct obd_import *imp = open_req->rq_import;
- ENTRY;
if (!open_req->rq_replay)
- RETURN(0);
+ return 0;
rec = req_capsule_client_get(&open_req->rq_pill, &RMF_REC_REINT);
body = req_capsule_server_get(&open_req->rq_pill, &RMF_MDT_BODY);
@@ -744,7 +723,7 @@ int mdc_set_open_replay_data(struct obd_export *exp,
if (mod == NULL) {
DEBUG_REQ(D_ERROR, open_req,
"Can't allocate md_open_data");
- RETURN(0);
+ return 0;
}
/**
@@ -776,21 +755,20 @@ int mdc_set_open_replay_data(struct obd_export *exp,
}
DEBUG_REQ(D_RPCTRACE, open_req, "Set up open replay data");
- RETURN(0);
+ return 0;
}
int mdc_clear_open_replay_data(struct obd_export *exp,
struct obd_client_handle *och)
{
struct md_open_data *mod = och->och_mod;
- ENTRY;
/**
* It is possible to not have \var mod in a case of eviction between
* lookup and ll_file_open().
**/
if (mod == NULL)
- RETURN(0);
+ return 0;
LASSERT(mod != LP_POISON);
@@ -798,7 +776,7 @@ int mdc_clear_open_replay_data(struct obd_export *exp,
och->och_mod = NULL;
obd_mod_put(mod);
- RETURN(0);
+ return 0;
}
/* Prepares the request for the replay by the given reply */
@@ -823,19 +801,18 @@ int mdc_close(struct obd_export *exp, struct md_op_data *op_data,
struct obd_device *obd = class_exp2obd(exp);
struct ptlrpc_request *req;
int rc;
- ENTRY;
*request = NULL;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_CLOSE);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_CLOSE);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
/* To avoid a livelock (bug 7034), we need to send CLOSE RPCs to a
@@ -916,7 +893,7 @@ int mdc_close(struct obd_export *exp, struct md_op_data *op_data,
}
*request = req;
mdc_close_handle_reply(req, op_data, rc);
- RETURN(rc);
+ return rc;
}
int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data,
@@ -925,18 +902,17 @@ int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data,
struct obd_device *obd = class_exp2obd(exp);
struct ptlrpc_request *req;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_MDS_DONE_WRITING);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_DONE_WRITING);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
if (mod != NULL) {
@@ -983,7 +959,7 @@ int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data,
mdc_close_handle_reply(req, op_data, rc);
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
@@ -997,7 +973,6 @@ int mdc_readpage(struct obd_export *exp, struct md_op_data *op_data,
int resends = 0;
struct l_wait_info lwi;
int rc;
- ENTRY;
*request = NULL;
init_waitqueue_head(&waitq);
@@ -1005,14 +980,14 @@ int mdc_readpage(struct obd_export *exp, struct md_op_data *op_data,
restart_bulk:
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_READPAGE);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_READPAGE);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
req->rq_request_portal = MDS_READPAGE_PORTAL;
@@ -1022,7 +997,7 @@ restart_bulk:
MDS_BULK_PORTAL);
if (desc == NULL) {
ptlrpc_request_free(req);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
/* NB req now owns desc and will free it when it gets freed */
@@ -1038,12 +1013,12 @@ restart_bulk:
if (rc) {
ptlrpc_req_finished(req);
if (rc != -ETIMEDOUT)
- RETURN(rc);
+ return rc;
resends++;
if (!client_should_resend(resends, &exp->exp_obd->u.cli)) {
CERROR("too many resend retries, returning error\n");
- RETURN(-EIO);
+ return -EIO;
}
lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(resends), NULL, NULL, NULL);
l_wait_event(waitq, 0, &lwi);
@@ -1055,7 +1030,7 @@ restart_bulk:
req->rq_bulk->bd_nob_transferred);
if (rc < 0) {
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
if (req->rq_bulk->bd_nob_transferred & ~LU_PAGE_MASK) {
@@ -1063,11 +1038,11 @@ restart_bulk:
req->rq_bulk->bd_nob_transferred,
PAGE_CACHE_SIZE * op_data->op_npages);
ptlrpc_req_finished(req);
- RETURN(-EPROTO);
+ return -EPROTO;
}
*request = req;
- RETURN(0);
+ return 0;
}
static int mdc_statfs(const struct lu_env *env,
@@ -1079,7 +1054,6 @@ static int mdc_statfs(const struct lu_env *env,
struct obd_statfs *msfs;
struct obd_import *imp = NULL;
int rc;
- ENTRY;
/*
* Since the request might also come from lprocfs, so we need
@@ -1090,7 +1064,7 @@ static int mdc_statfs(const struct lu_env *env,
imp = class_import_get(obd->u.cli.cl_import);
up_read(&obd->u.cli.cl_sem);
if (!imp)
- RETURN(-ENODEV);
+ return -ENODEV;
req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_STATFS,
LUSTRE_MDS_VERSION, MDS_STATFS);
@@ -1118,7 +1092,6 @@ static int mdc_statfs(const struct lu_env *env,
GOTO(out, rc = -EPROTO);
*osfs = *msfs;
- EXIT;
out:
ptlrpc_req_finished(req);
output:
@@ -1133,15 +1106,15 @@ static int mdc_ioc_fid2path(struct obd_export *exp, struct getinfo_fid2path *gf)
int rc;
if (gf->gf_pathlen > PATH_MAX)
- RETURN(-ENAMETOOLONG);
+ return -ENAMETOOLONG;
if (gf->gf_pathlen < 2)
- RETURN(-EOVERFLOW);
+ return -EOVERFLOW;
/* Key is KEY_FID2PATH + getinfo_fid2path description */
keylen = cfs_size_round(sizeof(KEY_FID2PATH)) + sizeof(*gf);
OBD_ALLOC(key, keylen);
if (key == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
memcpy(key, KEY_FID2PATH, sizeof(KEY_FID2PATH));
memcpy(key + cfs_size_round(sizeof(KEY_FID2PATH)), gf, sizeof(*gf));
@@ -1178,7 +1151,6 @@ static int mdc_ioc_hsm_progress(struct obd_export *exp,
struct hsm_progress_kernel *req_hpk;
struct ptlrpc_request *req;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_HSM_PROGRESS,
LUSTRE_MDS_VERSION, MDS_HSM_PROGRESS);
@@ -1193,6 +1165,7 @@ static int mdc_ioc_hsm_progress(struct obd_export *exp,
GOTO(out, rc = -EPROTO);
*req_hpk = *hpk;
+ req_hpk->hpk_errval = lustre_errno_hton(hpk->hpk_errval);
ptlrpc_request_set_replen(req);
@@ -1208,7 +1181,6 @@ static int mdc_ioc_hsm_ct_register(struct obd_import *imp, __u32 archives)
__u32 *archive_mask;
struct ptlrpc_request *req;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_HSM_CT_REGISTER,
LUSTRE_MDS_VERSION,
@@ -1242,19 +1214,18 @@ static int mdc_ioc_hsm_current_action(struct obd_export *exp,
struct hsm_current_action *req_hca;
struct ptlrpc_request *req;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_MDS_HSM_ACTION);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_ACTION);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
@@ -1273,7 +1244,6 @@ static int mdc_ioc_hsm_current_action(struct obd_export *exp,
*hca = *req_hca;
- EXIT;
out:
ptlrpc_req_finished(req);
return rc;
@@ -1283,7 +1253,6 @@ static int mdc_ioc_hsm_ct_unregister(struct obd_import *imp)
{
struct ptlrpc_request *req;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_HSM_CT_UNREGISTER,
LUSTRE_MDS_VERSION,
@@ -1309,19 +1278,18 @@ static int mdc_ioc_hsm_state_get(struct obd_export *exp,
struct hsm_user_state *req_hus;
struct ptlrpc_request *req;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_MDS_HSM_STATE_GET);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_STATE_GET);
if (rc != 0) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
@@ -1339,7 +1307,6 @@ static int mdc_ioc_hsm_state_get(struct obd_export *exp,
*hus = *req_hus;
- EXIT;
out:
ptlrpc_req_finished(req);
return rc;
@@ -1352,19 +1319,18 @@ static int mdc_ioc_hsm_state_set(struct obd_export *exp,
struct hsm_state_set *req_hss;
struct ptlrpc_request *req;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_MDS_HSM_STATE_SET);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_STATE_SET);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
@@ -1381,7 +1347,6 @@ static int mdc_ioc_hsm_state_set(struct obd_export *exp,
rc = mdc_queue_wait(req);
GOTO(out, rc);
- EXIT;
out:
ptlrpc_req_finished(req);
return rc;
@@ -1396,7 +1361,6 @@ static int mdc_ioc_hsm_request(struct obd_export *exp,
struct hsm_user_item *req_hui;
char *req_opaque;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(imp, &RQF_MDS_HSM_REQUEST);
if (req == NULL)
@@ -1411,7 +1375,7 @@ static int mdc_ioc_hsm_request(struct obd_export *exp,
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_REQUEST);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_pack_body(req, NULL, NULL, OBD_MD_FLRMTPERM, 0, 0, 0);
@@ -1476,21 +1440,20 @@ static int changelog_kkuc_cb(const struct lu_env *env, struct llog_handle *llh,
struct llog_changelog_rec *rec = (struct llog_changelog_rec *)hdr;
struct kuc_hdr *lh;
int len, rc;
- ENTRY;
if (rec->cr_hdr.lrh_type != CHANGELOG_REC) {
rc = -EINVAL;
CERROR("%s: not a changelog rec %x/%d: rc = %d\n",
cs->cs_obd->obd_name, rec->cr_hdr.lrh_type,
rec->cr.cr_type, rc);
- RETURN(rc);
+ return rc;
}
if (rec->cr.cr_index < cs->cs_startrec) {
/* Skip entries earlier than what we are interested in */
CDEBUG(D_CHANGELOG, "rec="LPU64" start="LPU64"\n",
rec->cr.cr_index, cs->cs_startrec);
- RETURN(0);
+ return 0;
}
CDEBUG(D_CHANGELOG, LPU64" %02d%-5s "LPU64" 0x%x t="DFID" p="DFID
@@ -1509,7 +1472,7 @@ static int changelog_kkuc_cb(const struct lu_env *env, struct llog_handle *llh,
rc = libcfs_kkuc_msg_put(cs->cs_fp, lh);
CDEBUG(D_CHANGELOG, "kucmsg fp %p len %d rc %d\n", cs->cs_fp, len,rc);
- RETURN(rc);
+ return rc;
}
static int mdc_changelog_send_thread(void *csdata)
@@ -1608,13 +1571,12 @@ static int mdc_quotacheck(struct obd_device *unused, struct obd_export *exp,
struct ptlrpc_request *req;
struct obd_quotactl *body;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
&RQF_MDS_QUOTACHECK, LUSTRE_MDS_VERSION,
MDS_QUOTACHECK);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
body = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
*body = *oqctl;
@@ -1628,7 +1590,7 @@ static int mdc_quotacheck(struct obd_device *unused, struct obd_export *exp,
if (rc)
cli->cl_qchk_stat = rc;
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
static int mdc_quota_poll_check(struct obd_export *exp,
@@ -1636,7 +1598,6 @@ static int mdc_quota_poll_check(struct obd_export *exp,
{
struct client_obd *cli = &exp->exp_obd->u.cli;
int rc;
- ENTRY;
qchk->obd_uuid = cli->cl_target_uuid;
memcpy(qchk->obd_type, LUSTRE_MDS_NAME, strlen(LUSTRE_MDS_NAME));
@@ -1645,7 +1606,7 @@ static int mdc_quota_poll_check(struct obd_export *exp,
/* the client is not the previous one */
if (rc == CL_NOT_QUOTACHECKED)
rc = -EINTR;
- RETURN(rc);
+ return rc;
}
static int mdc_quotactl(struct obd_device *unused, struct obd_export *exp,
@@ -1654,13 +1615,12 @@ static int mdc_quotactl(struct obd_device *unused, struct obd_export *exp,
struct ptlrpc_request *req;
struct obd_quotactl *oqc;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
&RQF_MDS_QUOTACTL, LUSTRE_MDS_VERSION,
MDS_QUOTACTL);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
oqc = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
*oqc = *oqctl;
@@ -1682,7 +1642,7 @@ static int mdc_quotactl(struct obd_device *unused, struct obd_export *exp,
}
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
static int mdc_ioc_swap_layouts(struct obd_export *exp,
@@ -1692,7 +1652,6 @@ static int mdc_ioc_swap_layouts(struct obd_export *exp,
struct ptlrpc_request *req;
int rc, count;
struct mdc_swap_layouts *msl, *payload;
- ENTRY;
msl = op_data->op_data;
@@ -1711,7 +1670,7 @@ static int mdc_ioc_swap_layouts(struct obd_export *exp,
&RQF_MDS_SWAP_LAYOUTS);
if (req == NULL) {
ldlm_lock_list_put(&cancels, l_bl_ast, count);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
@@ -1720,7 +1679,7 @@ static int mdc_ioc_swap_layouts(struct obd_export *exp,
rc = mdc_prep_elc_req(exp, req, MDS_SWAP_LAYOUTS, &cancels, count);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_swap_layouts_pack(req, op_data);
@@ -1735,7 +1694,6 @@ static int mdc_ioc_swap_layouts(struct obd_export *exp,
rc = ptlrpc_queue_wait(req);
if (rc)
GOTO(out, rc);
- EXIT;
out:
ptlrpc_req_finished(req);
@@ -1750,7 +1708,6 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
struct obd_import *imp = obd->u.cli.cl_import;
struct llog_ctxt *ctxt;
int rc;
- ENTRY;
if (!try_module_get(THIS_MODULE)) {
CERROR("Can't get module. Is it alive?");
@@ -1774,6 +1731,9 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
GOTO(out, rc);
case LL_IOC_HSM_CT_START:
rc = mdc_ioc_hsm_ct_start(exp, karg);
+ /* ignore if it was already registered on this MDS. */
+ if (rc == -EEXIST)
+ rc = 0;
GOTO(out, rc);
case LL_IOC_HSM_PROGRESS:
rc = mdc_ioc_hsm_progress(exp, karg);
@@ -1855,7 +1815,7 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
OBD_ALLOC_PTR(oqctl);
if (!oqctl)
- RETURN(-ENOMEM);
+ return -ENOMEM;
QCTL_COPY(oqctl, qctl);
rc = obd_quotactl(exp, oqctl);
@@ -1897,11 +1857,10 @@ int mdc_get_info_rpc(struct obd_export *exp,
struct ptlrpc_request *req;
char *tmp;
int rc = -EINVAL;
- ENTRY;
req = ptlrpc_request_alloc(imp, &RQF_MDS_GET_INFO);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req_capsule_set_size(&req->rq_pill, &RMF_GETINFO_KEY,
RCL_CLIENT, keylen);
@@ -1911,7 +1870,7 @@ int mdc_get_info_rpc(struct obd_export *exp,
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_GET_INFO);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
tmp = req_capsule_client_get(&req->rq_pill, &RMF_GETINFO_KEY);
@@ -1936,7 +1895,7 @@ int mdc_get_info_rpc(struct obd_export *exp,
}
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
static void lustre_swab_hai(struct hsm_action_item *h)
@@ -1991,19 +1950,10 @@ static int mdc_ioc_hsm_ct_start(struct obd_export *exp,
lk->lk_uid, lk->lk_group, lk->lk_flags);
if (lk->lk_flags & LK_FLG_STOP) {
- rc = libcfs_kkuc_group_rem(lk->lk_uid, lk->lk_group);
/* Unregister with the coordinator */
- if (rc == 0)
- rc = mdc_ioc_hsm_ct_unregister(imp);
+ rc = mdc_ioc_hsm_ct_unregister(imp);
} else {
- struct file *fp = fget(lk->lk_wfd);
-
- rc = libcfs_kkuc_group_add(fp, lk->lk_uid, lk->lk_group,
- lk->lk_data);
- if (rc && fp)
- fput(fp);
- if (rc == 0)
- rc = mdc_ioc_hsm_ct_register(imp, archive);
+ rc = mdc_ioc_hsm_ct_register(imp, archive);
}
return rc;
@@ -2019,19 +1969,18 @@ static int mdc_hsm_copytool_send(int len, void *val)
struct kuc_hdr *lh = (struct kuc_hdr *)val;
struct hsm_action_list *hal = (struct hsm_action_list *)(lh + 1);
int rc;
- ENTRY;
if (len < sizeof(*lh) + sizeof(*hal)) {
CERROR("Short HSM message %d < %d\n", len,
(int) (sizeof(*lh) + sizeof(*hal)));
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (lh->kuc_magic == __swab16(KUC_MAGIC)) {
lustre_swab_kuch(lh);
lustre_swab_hal(hal);
} else if (lh->kuc_magic != KUC_MAGIC) {
CERROR("Bad magic %x!=%x\n", lh->kuc_magic, KUC_MAGIC);
- RETURN(-EPROTO);
+ return -EPROTO;
}
CDEBUG(D_HSM, " Received message mg=%x t=%d m=%d l=%d actions=%d "
@@ -2042,7 +1991,7 @@ static int mdc_hsm_copytool_send(int len, void *val)
/* Broadcast to HSM listeners */
rc = libcfs_kkuc_group_put(KUC_GRP_HSM, lh);
- RETURN(rc);
+ return rc;
}
/**
@@ -2084,11 +2033,10 @@ int mdc_set_info_async(const struct lu_env *env,
{
struct obd_import *imp = class_exp2cliimp(exp);
int rc;
- ENTRY;
if (KEY_IS(KEY_READ_ONLY)) {
if (vallen != sizeof(int))
- RETURN(-EINVAL);
+ return -EINVAL;
spin_lock(&imp->imp_lock);
if (*((int *)val)) {
@@ -2104,15 +2052,15 @@ int mdc_set_info_async(const struct lu_env *env,
rc = do_set_info_async(imp, MDS_SET_INFO, LUSTRE_MDS_VERSION,
keylen, key, vallen, val, set);
- RETURN(rc);
+ return rc;
}
if (KEY_IS(KEY_SPTLRPC_CONF)) {
sptlrpc_conf_client_adapt(exp->exp_obd);
- RETURN(0);
+ return 0;
}
if (KEY_IS(KEY_FLUSH_CTX)) {
sptlrpc_import_flush_my_ctx(imp);
- RETURN(0);
+ return 0;
}
if (KEY_IS(KEY_MDS_CONN)) {
/* mds-mds import */
@@ -2121,20 +2069,20 @@ int mdc_set_info_async(const struct lu_env *env,
spin_unlock(&imp->imp_lock);
imp->imp_client->cli_request_portal = MDS_MDS_PORTAL;
CDEBUG(D_OTHER, "%s: timeout / 2\n", exp->exp_obd->obd_name);
- RETURN(0);
+ return 0;
}
if (KEY_IS(KEY_CHANGELOG_CLEAR)) {
rc = do_set_info_async(imp, MDS_SET_INFO, LUSTRE_MDS_VERSION,
keylen, key, vallen, val, set);
- RETURN(rc);
+ return rc;
}
if (KEY_IS(KEY_HSM_COPYTOOL_SEND)) {
rc = mdc_hsm_copytool_send(vallen, val);
- RETURN(rc);
+ return rc;
}
CERROR("Unknown key %s\n", (char *)key);
- RETURN(-EINVAL);
+ return -EINVAL;
}
int mdc_get_info(const struct lu_env *env, struct obd_export *exp,
@@ -2147,30 +2095,30 @@ int mdc_get_info(const struct lu_env *env, struct obd_export *exp,
int mdsize, *max_easize;
if (*vallen != sizeof(int))
- RETURN(-EINVAL);
+ return -EINVAL;
mdsize = *(int*)val;
if (mdsize > exp->exp_obd->u.cli.cl_max_mds_easize)
exp->exp_obd->u.cli.cl_max_mds_easize = mdsize;
max_easize = val;
*max_easize = exp->exp_obd->u.cli.cl_max_mds_easize;
- RETURN(0);
+ return 0;
} else if (KEY_IS(KEY_CONN_DATA)) {
struct obd_import *imp = class_exp2cliimp(exp);
struct obd_connect_data *data = val;
if (*vallen != sizeof(*data))
- RETURN(-EINVAL);
+ return -EINVAL;
*data = imp->imp_connect_data;
- RETURN(0);
+ return 0;
} else if (KEY_IS(KEY_TGT_COUNT)) {
*((int *)val) = 1;
- RETURN(0);
+ return 0;
}
rc = mdc_get_info_rpc(exp, keylen, key, *vallen, val);
- RETURN(rc);
+ return rc;
}
static int mdc_pin(struct obd_export *exp, const struct lu_fid *fid,
@@ -2180,18 +2128,17 @@ static int mdc_pin(struct obd_export *exp, const struct lu_fid *fid,
struct ptlrpc_request *req;
struct mdt_body *body;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_PIN);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, oc);
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_PIN);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_pack_body(req, fid, oc, 0, 0, -1, flags);
@@ -2220,11 +2167,11 @@ static int mdc_pin(struct obd_export *exp, const struct lu_fid *fid,
}
handle->och_mod->mod_open_req = req; /* will be dropped by unpin */
- RETURN(0);
+ return 0;
err_out:
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
static int mdc_unpin(struct obd_export *exp, struct obd_client_handle *handle,
@@ -2233,12 +2180,11 @@ static int mdc_unpin(struct obd_export *exp, struct obd_client_handle *handle,
struct ptlrpc_request *req;
struct mdt_body *body;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp), &RQF_MDS_UNPIN,
LUSTRE_MDS_VERSION, MDS_UNPIN);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
body = req_capsule_client_get(&req->rq_pill, &RMF_MDT_BODY);
body->handle = handle->och_fh;
@@ -2257,7 +2203,7 @@ static int mdc_unpin(struct obd_export *exp, struct obd_client_handle *handle,
ptlrpc_req_finished(handle->och_mod->mod_open_req);
obd_mod_put(handle->och_mod);
- RETURN(rc);
+ return rc;
}
int mdc_sync(struct obd_export *exp, const struct lu_fid *fid,
@@ -2265,19 +2211,18 @@ int mdc_sync(struct obd_export *exp, const struct lu_fid *fid,
{
struct ptlrpc_request *req;
int rc;
- ENTRY;
*request = NULL;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_SYNC);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, oc);
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_SYNC);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_pack_body(req, fid, oc, 0, 0, -1, 0);
@@ -2289,7 +2234,7 @@ int mdc_sync(struct obd_export *exp, const struct lu_fid *fid,
ptlrpc_req_finished(req);
else
*request = req;
- RETURN(rc);
+ return rc;
}
static int mdc_import_event(struct obd_device *obd, struct obd_import *imp,
@@ -2328,7 +2273,7 @@ static int mdc_import_event(struct obd_device *obd, struct obd_import *imp,
}
case IMP_EVENT_ACTIVE:
rc = obd_notify_observer(obd, obd, OBD_NOTIFY_ACTIVE, NULL);
- /* restore re-establish kuc registration after reconnecting */
+ /* redo the kuc registration after reconnecting */
if (rc == 0)
rc = mdc_kuc_reregister(imp);
break;
@@ -2342,7 +2287,7 @@ static int mdc_import_event(struct obd_device *obd, struct obd_import *imp,
CERROR("Unknown import event %x\n", event);
LBUG();
}
- RETURN(rc);
+ return rc;
}
int mdc_fid_alloc(struct obd_export *exp, struct lu_fid *fid,
@@ -2350,8 +2295,8 @@ int mdc_fid_alloc(struct obd_export *exp, struct lu_fid *fid,
{
struct client_obd *cli = &exp->exp_obd->u.cli;
struct lu_client_seq *seq = cli->cl_seq;
- ENTRY;
- RETURN(seq_client_alloc_fid(NULL, seq, fid));
+
+ return seq_client_alloc_fid(NULL, seq, fid);
}
struct obd_uuid *mdc_get_uuid(struct obd_export *exp) {
@@ -2367,15 +2312,15 @@ struct obd_uuid *mdc_get_uuid(struct obd_export *exp) {
static int mdc_cancel_for_recovery(struct ldlm_lock *lock)
{
if (lock->l_resource->lr_type != LDLM_IBITS)
- RETURN(0);
+ return 0;
/* FIXME: if we ever get into a situation where there are too many
* opened files with open locks on a single node, then we really
* should replay these open locks to reget it */
if (lock->l_policy_data.l_inodebits.bits & MDS_INODELOCK_OPEN)
- RETURN(0);
+ return 0;
- RETURN(1);
+ return 1;
}
static int mdc_resource_inode_free(struct ldlm_resource *res)
@@ -2387,7 +2332,7 @@ static int mdc_resource_inode_free(struct ldlm_resource *res)
}
struct ldlm_valblock_ops inode_lvbo = {
- lvbo_free: mdc_resource_inode_free
+ .lvbo_free = mdc_resource_inode_free,
};
static int mdc_setup(struct obd_device *obd, struct lustre_cfg *cfg)
@@ -2395,11 +2340,10 @@ static int mdc_setup(struct obd_device *obd, struct lustre_cfg *cfg)
struct client_obd *cli = &obd->u.cli;
struct lprocfs_static_vars lvars = { 0 };
int rc;
- ENTRY;
OBD_ALLOC(cli->cl_rpc_lock, sizeof (*cli->cl_rpc_lock));
if (!cli->cl_rpc_lock)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_init_rpc_lock(cli->cl_rpc_lock);
ptlrpcd_addref();
@@ -2427,14 +2371,14 @@ static int mdc_setup(struct obd_device *obd, struct lustre_cfg *cfg)
CERROR("failed to setup llogging subsystems\n");
}
- RETURN(rc);
+ return rc;
err_close_lock:
OBD_FREE(cli->cl_close_lock, sizeof (*cli->cl_close_lock));
err_rpc_lock:
OBD_FREE(cli->cl_rpc_lock, sizeof (*cli->cl_rpc_lock));
ptlrpcd_decref();
- RETURN(rc);
+ return rc;
}
/* Initialize the default and maximum LOV EA and cookie sizes. This allows
@@ -2446,7 +2390,6 @@ static int mdc_init_ea_size(struct obd_export *exp, int easize,
{
struct obd_device *obd = exp->exp_obd;
struct client_obd *cli = &obd->u.cli;
- ENTRY;
if (cli->cl_max_mds_easize < easize)
cli->cl_max_mds_easize = easize;
@@ -2457,13 +2400,12 @@ static int mdc_init_ea_size(struct obd_export *exp, int easize,
if (cli->cl_max_mds_cookiesize < cookiesize)
cli->cl_max_mds_cookiesize = cookiesize;
- RETURN(0);
+ return 0;
}
static int mdc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
{
int rc = 0;
- ENTRY;
switch (stage) {
case OBD_CLEANUP_EARLY:
@@ -2482,7 +2424,7 @@ static int mdc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
CERROR("failed to cleanup llogging subsystems\n");
break;
}
- RETURN(rc);
+ return rc;
}
static int mdc_cleanup(struct obd_device *obd)
@@ -2504,33 +2446,29 @@ static int mdc_llog_init(struct obd_device *obd, struct obd_llog_group *olg,
struct llog_ctxt *ctxt;
int rc;
- ENTRY;
-
LASSERT(olg == &obd->obd_olg);
rc = llog_setup(NULL, obd, olg, LLOG_CHANGELOG_REPL_CTXT, tgt,
&llog_client_ops);
if (rc)
- RETURN(rc);
+ return rc;
ctxt = llog_group_get_ctxt(olg, LLOG_CHANGELOG_REPL_CTXT);
llog_initiator_connect(ctxt);
llog_ctxt_put(ctxt);
- RETURN(0);
+ return 0;
}
static int mdc_llog_finish(struct obd_device *obd, int count)
{
struct llog_ctxt *ctxt;
- ENTRY;
-
ctxt = llog_get_context(obd, LLOG_CHANGELOG_REPL_CTXT);
if (ctxt)
llog_cleanup(NULL, ctxt);
- RETURN(0);
+ return 0;
}
static int mdc_process_config(struct obd_device *obd, obd_count len, void *buf)
@@ -2559,21 +2497,20 @@ int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid,
{
struct ptlrpc_request *req;
int rc;
- ENTRY;
LASSERT(client_is_remote(exp));
*request = NULL;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_GETATTR);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
mdc_set_capa_size(req, &RMF_CAPA1, oc);
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_GETATTR);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
mdc_pack_body(req, fid, oc, OBD_MD_FLRMTPERM, 0, suppgid, 0);
@@ -2588,7 +2525,7 @@ int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid,
ptlrpc_req_finished(req);
else
*request = req;
- RETURN(rc);
+ return rc;
}
static int mdc_interpret_renew_capa(const struct lu_env *env,
@@ -2598,7 +2535,6 @@ static int mdc_interpret_renew_capa(const struct lu_env *env,
struct mdc_renew_capa_args *ra = args;
struct mdt_body *body = NULL;
struct lustre_capa *capa;
- ENTRY;
if (status)
GOTO(out, capa = ERR_PTR(status));
@@ -2613,7 +2549,6 @@ static int mdc_interpret_renew_capa(const struct lu_env *env,
capa = req_capsule_server_get(&req->rq_pill, &RMF_CAPA2);
if (!capa)
GOTO(out, capa = ERR_PTR(-EFAULT));
- EXIT;
out:
ra->ra_cb(ra->ra_oc, capa);
return 0;
@@ -2624,12 +2559,11 @@ static int mdc_renew_capa(struct obd_export *exp, struct obd_capa *oc,
{
struct ptlrpc_request *req;
struct mdc_renew_capa_args *ra;
- ENTRY;
req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp), &RQF_MDS_GETATTR,
LUSTRE_MDS_VERSION, MDS_GETATTR);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* NB, OBD_MD_FLOSSCAPA is set here, but it doesn't necessarily mean the
* capa to renew is oss capa.
@@ -2643,7 +2577,7 @@ static int mdc_renew_capa(struct obd_export *exp, struct obd_capa *oc,
ra->ra_cb = cb;
req->rq_interpret_reply = mdc_interpret_renew_capa;
ptlrpcd_add_req(req, PDL_POLICY_LOCAL, -1);
- RETURN(0);
+ return 0;
}
static int mdc_connect(const struct lu_env *env,
@@ -2737,7 +2671,7 @@ int __init mdc_init(void)
rc = class_register_type(&mdc_obd_ops, &mdc_md_ops, lvars.module_vars,
LUSTRE_MDC_NAME, NULL);
- RETURN(rc);
+ return rc;
}
static void /*__exit*/ mdc_exit(void)
diff --git a/drivers/staging/lustre/lustre/mgc/libmgc.c b/drivers/staging/lustre/lustre/mgc/libmgc.c
index 442146cc7e6..7b4947cec3a 100644
--- a/drivers/staging/lustre/lustre/mgc/libmgc.c
+++ b/drivers/staging/lustre/lustre/mgc/libmgc.c
@@ -56,7 +56,6 @@
static int mgc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
{
int rc;
- ENTRY;
ptlrpcd_addref();
@@ -73,19 +72,18 @@ static int mgc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
GOTO(err_cleanup, rc);
}
- RETURN(rc);
+ return rc;
err_cleanup:
client_obd_cleanup(obd);
err_decref:
ptlrpcd_decref();
- RETURN(rc);
+ return rc;
}
static int mgc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
{
int rc = 0;
- ENTRY;
switch (stage) {
case OBD_CLEANUP_EARLY:
@@ -96,21 +94,20 @@ static int mgc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
CERROR("failed to cleanup llogging subsystems\n");
break;
}
- RETURN(rc);
+ return rc;
}
static int mgc_cleanup(struct obd_device *obd)
{
struct client_obd *cli = &obd->u.cli;
int rc;
- ENTRY;
LASSERT(cli->cl_mgc_vfsmnt == NULL);
ptlrpcd_decref();
rc = client_obd_cleanup(obd);
- RETURN(rc);
+ return rc;
}
static int mgc_llog_init(struct obd_device *obd, struct obd_llog_group *olg,
@@ -118,32 +115,30 @@ static int mgc_llog_init(struct obd_device *obd, struct obd_llog_group *olg,
{
struct llog_ctxt *ctxt;
int rc;
- ENTRY;
LASSERT(olg == &obd->obd_olg);
rc = llog_setup(NULL, obd, olg, LLOG_CONFIG_REPL_CTXT, tgt,
&llog_client_ops);
if (rc < 0)
- RETURN(rc);
+ return rc;
ctxt = llog_group_get_ctxt(olg, LLOG_CONFIG_REPL_CTXT);
llog_initiator_connect(ctxt);
llog_ctxt_put(ctxt);
- RETURN(rc);
+ return rc;
}
static int mgc_llog_finish(struct obd_device *obd, int count)
{
struct llog_ctxt *ctxt;
- ENTRY;
ctxt = llog_get_context(obd, LLOG_CONFIG_REPL_CTXT);
if (ctxt)
llog_cleanup(NULL, ctxt);
- RETURN(0);
+ return 0;
}
struct obd_ops mgc_obd_ops = {
diff --git a/drivers/staging/lustre/lustre/mgc/lproc_mgc.c b/drivers/staging/lustre/lustre/mgc/lproc_mgc.c
index 1105eaa2431..ebecec2b007 100644
--- a/drivers/staging/lustre/lustre/mgc/lproc_mgc.c
+++ b/drivers/staging/lustre/lustre/mgc/lproc_mgc.c
@@ -35,7 +35,6 @@
*/
#define DEBUG_SUBSYSTEM S_CLASS
-#include <linux/version.h>
#include <linux/vfs.h>
#include <obd_class.h>
#include <lprocfs_status.h>
diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c
index c6c84d97ce4..12a9ede21a8 100644
--- a/drivers/staging/lustre/lustre/mgc/mgc_request.c
+++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c
@@ -118,19 +118,16 @@ static DEFINE_SPINLOCK(config_list_lock);
/* Take a reference to a config log */
static int config_log_get(struct config_llog_data *cld)
{
- ENTRY;
atomic_inc(&cld->cld_refcount);
CDEBUG(D_INFO, "log %s refs %d\n", cld->cld_logname,
atomic_read(&cld->cld_refcount));
- RETURN(0);
+ return 0;
}
/* Drop a reference to a config log. When no longer referenced,
we can free the config log data */
static void config_log_put(struct config_llog_data *cld)
{
- ENTRY;
-
CDEBUG(D_INFO, "log %s refs %d\n", cld->cld_logname,
atomic_read(&cld->cld_refcount));
LASSERT(atomic_read(&cld->cld_refcount) > 0);
@@ -152,8 +149,6 @@ static void config_log_put(struct config_llog_data *cld)
class_export_put(cld->cld_mgcexp);
OBD_FREE(cld, sizeof(*cld) + strlen(cld->cld_logname) + 1);
}
-
- EXIT;
}
/* Find a config log by name */
@@ -164,7 +159,6 @@ struct config_llog_data *config_log_find(char *logname,
struct config_llog_data *cld;
struct config_llog_data *found = NULL;
void * instance;
- ENTRY;
LASSERT(logname != NULL);
@@ -186,7 +180,7 @@ struct config_llog_data *config_log_find(char *logname,
LASSERT(found->cld_stopping == 0 || cld_is_sptlrpc(found) == 0);
}
spin_unlock(&config_list_lock);
- RETURN(found);
+ return found;
}
static
@@ -198,14 +192,13 @@ struct config_llog_data *do_config_log_add(struct obd_device *obd,
{
struct config_llog_data *cld;
int rc;
- ENTRY;
CDEBUG(D_MGC, "do adding config log %s:%p\n", logname,
cfg ? cfg->cfg_instance : 0);
OBD_ALLOC(cld, sizeof(*cld) + strlen(logname) + 1);
if (!cld)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
strcpy(cld->cld_logname, logname);
if (cfg)
@@ -235,7 +228,7 @@ struct config_llog_data *do_config_log_add(struct obd_device *obd,
if (rc) {
config_log_put(cld);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
if (cld_is_sptlrpc(cld)) {
@@ -244,7 +237,7 @@ struct config_llog_data *do_config_log_add(struct obd_device *obd,
CERROR("failed processing sptlrpc log: %d\n", rc);
}
- RETURN(cld);
+ return cld;
}
static struct config_llog_data *config_recover_log_add(struct obd_device *obd,
@@ -296,7 +289,6 @@ static int config_log_add(struct obd_device *obd, char *logname,
struct config_llog_data *sptlrpc_cld;
char seclogname[32];
char *ptr;
- ENTRY;
CDEBUG(D_MGC, "adding config log %s:%p\n", logname, cfg->cfg_instance);
@@ -307,7 +299,7 @@ static int config_log_add(struct obd_device *obd, char *logname,
ptr = strrchr(logname, '-');
if (ptr == NULL || ptr - logname > 8) {
CERROR("logname %s is too long\n", logname);
- RETURN(-EINVAL);
+ return -EINVAL;
}
memcpy(seclogname, logname, ptr - logname);
@@ -319,7 +311,7 @@ static int config_log_add(struct obd_device *obd, char *logname,
CONFIG_T_SPTLRPC, NULL, NULL);
if (IS_ERR(sptlrpc_cld)) {
CERROR("can't create sptlrpc log: %s\n", seclogname);
- RETURN(PTR_ERR(sptlrpc_cld));
+ return PTR_ERR(sptlrpc_cld);
}
}
@@ -327,7 +319,7 @@ static int config_log_add(struct obd_device *obd, char *logname,
if (IS_ERR(cld)) {
CERROR("can't create log: %s\n", logname);
config_log_put(sptlrpc_cld);
- RETURN(PTR_ERR(cld));
+ return PTR_ERR(cld);
}
cld->cld_sptlrpc = sptlrpc_cld;
@@ -339,12 +331,12 @@ static int config_log_add(struct obd_device *obd, char *logname,
recover_cld = config_recover_log_add(obd, seclogname, cfg, sb);
if (IS_ERR(recover_cld)) {
config_log_put(cld);
- RETURN(PTR_ERR(recover_cld));
+ return PTR_ERR(recover_cld);
}
cld->cld_recover = recover_cld;
}
- RETURN(0);
+ return 0;
}
DEFINE_MUTEX(llog_process_lock);
@@ -357,11 +349,10 @@ static int config_log_end(char *logname, struct config_llog_instance *cfg)
struct config_llog_data *cld_sptlrpc = NULL;
struct config_llog_data *cld_recover = NULL;
int rc = 0;
- ENTRY;
cld = config_log_find(logname, cfg);
if (cld == NULL)
- RETURN(-ENOENT);
+ return -ENOENT;
mutex_lock(&cld->cld_lock);
/*
@@ -375,7 +366,7 @@ static int config_log_end(char *logname, struct config_llog_instance *cfg)
mutex_unlock(&cld->cld_lock);
/* drop the ref from the find */
config_log_put(cld);
- RETURN(rc);
+ return rc;
}
cld->cld_stopping = 1;
@@ -406,7 +397,7 @@ static int config_log_end(char *logname, struct config_llog_instance *cfg)
CDEBUG(D_MGC, "end config log %s (%d)\n", logname ? logname : "client",
rc);
- RETURN(rc);
+ return rc;
}
int lprocfs_mgc_rd_ir_state(struct seq_file *m, void *data)
@@ -415,7 +406,6 @@ int lprocfs_mgc_rd_ir_state(struct seq_file *m, void *data)
struct obd_import *imp = obd->u.cli.cl_import;
struct obd_connect_data *ocd = &imp->imp_connect_data;
struct config_llog_data *cld;
- ENTRY;
seq_printf(m, "imperative_recovery: %s\n",
OCD_HAS_FLAG(ocd, IMP_RECOV) ? "ENABLED" : "DISABLED");
@@ -431,7 +421,7 @@ int lprocfs_mgc_rd_ir_state(struct seq_file *m, void *data)
}
spin_unlock(&config_list_lock);
- RETURN(0);
+ return 0;
}
/* reenqueue any lost locks */
@@ -445,7 +435,6 @@ static DECLARE_COMPLETION(rq_exit);
static void do_requeue(struct config_llog_data *cld)
{
- ENTRY;
LASSERT(atomic_read(&cld->cld_refcount) > 0);
/* Do not run mgc_process_log on a disconnected export or an
@@ -460,8 +449,6 @@ static void do_requeue(struct config_llog_data *cld)
cld->cld_logname);
}
up_read(&cld->cld_mgcexp->exp_obd->u.cli.cl_sem);
-
- EXIT;
}
/* this timeout represents how many seconds MGC should wait before
@@ -474,7 +461,6 @@ static void do_requeue(struct config_llog_data *cld)
static int mgc_requeue_thread(void *data)
{
int rc = 0;
- ENTRY;
CDEBUG(D_MGC, "Starting requeue thread\n");
@@ -556,15 +542,13 @@ static int mgc_requeue_thread(void *data)
complete(&rq_exit);
CDEBUG(D_MGC, "Ending requeue thread\n");
- RETURN(rc);
+ return rc;
}
/* Add a cld to the list to requeue. Start the requeue thread if needed.
We are responsible for dropping the config log reference from here on out. */
static void mgc_requeue_add(struct config_llog_data *cld)
{
- ENTRY;
-
CDEBUG(D_INFO, "log %s: requeue (r=%d sp=%d st=%x)\n",
cld->cld_logname, atomic_read(&cld->cld_refcount),
cld->cld_stopping, rq_state);
@@ -573,7 +557,7 @@ static void mgc_requeue_add(struct config_llog_data *cld)
mutex_lock(&cld->cld_lock);
if (cld->cld_stopping || cld->cld_lostlock) {
mutex_unlock(&cld->cld_lock);
- RETURN_EXIT;
+ return;
}
/* this refcount will be released in mgc_requeue_thread. */
config_log_get(cld);
@@ -591,7 +575,6 @@ static void mgc_requeue_add(struct config_llog_data *cld)
spin_unlock(&config_list_lock);
wake_up(&rq_waitq);
}
- EXIT;
}
/********************** class fns **********************/
@@ -605,7 +588,6 @@ static int mgc_fs_setup(struct obd_device *obd, struct super_block *sb,
struct dentry *dentry;
char *label;
int err = 0;
- ENTRY;
LASSERT(lsi);
LASSERT(lsi->lsi_srv_mnt == mnt);
@@ -620,7 +602,7 @@ static int mgc_fs_setup(struct obd_device *obd, struct super_block *sb,
up(&cli->cl_mgc_sem);
CERROR("%s: No fstype %s: rc = %ld\n", lsi->lsi_fstype,
obd->obd_name, PTR_ERR(obd->obd_fsops));
- RETURN(PTR_ERR(obd->obd_fsops));
+ return PTR_ERR(obd->obd_fsops);
}
cli->cl_mgc_vfsmnt = mnt;
@@ -654,21 +636,20 @@ static int mgc_fs_setup(struct obd_device *obd, struct super_block *sb,
CDEBUG(D_MGC, "MGC using disk labelled=%s\n", label);
/* We keep the cl_mgc_sem until mgc_fs_cleanup */
- RETURN(0);
+ return 0;
err_ops:
fsfilt_put_ops(obd->obd_fsops);
obd->obd_fsops = NULL;
cli->cl_mgc_vfsmnt = NULL;
up(&cli->cl_mgc_sem);
- RETURN(err);
+ return err;
}
static int mgc_fs_cleanup(struct obd_device *obd)
{
struct client_obd *cli = &obd->u.cli;
int rc = 0;
- ENTRY;
LASSERT(cli->cl_mgc_vfsmnt != NULL);
@@ -687,14 +668,13 @@ static int mgc_fs_cleanup(struct obd_device *obd)
up(&cli->cl_mgc_sem);
- RETURN(rc);
+ return rc;
}
static atomic_t mgc_count = ATOMIC_INIT(0);
static int mgc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
{
int rc = 0;
- ENTRY;
switch (stage) {
case OBD_CLEANUP_EARLY:
@@ -719,14 +699,13 @@ static int mgc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
CERROR("failed to cleanup llogging subsystems\n");
break;
}
- RETURN(rc);
+ return rc;
}
static int mgc_cleanup(struct obd_device *obd)
{
struct client_obd *cli = &obd->u.cli;
int rc;
- ENTRY;
LASSERT(cli->cl_mgc_vfsmnt == NULL);
@@ -740,14 +719,13 @@ static int mgc_cleanup(struct obd_device *obd)
ptlrpcd_decref();
rc = client_obd_cleanup(obd);
- RETURN(rc);
+ return rc;
}
static int mgc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
{
struct lprocfs_static_vars lvars;
int rc;
- ENTRY;
ptlrpcd_addref();
@@ -782,13 +760,13 @@ static int mgc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
rc = 0;
}
- RETURN(rc);
+ return rc;
err_cleanup:
client_obd_cleanup(obd);
err_decref:
ptlrpcd_decref();
- RETURN(rc);
+ return rc;
}
/* based on ll_mdc_blocking_ast */
@@ -798,7 +776,6 @@ static int mgc_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
struct lustre_handle lockh;
struct config_llog_data *cld = (struct config_llog_data *)data;
int rc = 0;
- ENTRY;
switch (flag) {
case LDLM_CB_BLOCKING:
@@ -847,7 +824,7 @@ static int mgc_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
LBUG();
}
- RETURN(rc);
+ return rc;
}
/* Not sure where this should go... */
@@ -862,18 +839,17 @@ static int mgc_set_mgs_param(struct obd_export *exp,
struct ptlrpc_request *req;
struct mgs_send_param *req_msp, *rep_msp;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
&RQF_MGS_SET_INFO, LUSTRE_MGS_VERSION,
MGS_SET_INFO);
if (!req)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req_msp = req_capsule_client_get(&req->rq_pill, &RMF_MGS_SEND_PARAM);
if (!req_msp) {
ptlrpc_req_finished(req);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
memcpy(req_msp, msp, sizeof(*req_msp));
@@ -889,7 +865,7 @@ static int mgc_set_mgs_param(struct obd_export *exp,
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
/* Take a config lock so we can get cancel notifications */
@@ -900,12 +876,15 @@ static int mgc_enqueue(struct obd_export *exp, struct lov_stripe_md *lsm,
struct lustre_handle *lockh)
{
struct config_llog_data *cld = (struct config_llog_data *)data;
- struct ldlm_enqueue_info einfo = { type, mode, mgc_blocking_ast,
- ldlm_completion_ast, NULL, NULL, NULL };
+ struct ldlm_enqueue_info einfo = {
+ .ei_type = type,
+ .ei_mode = mode,
+ .ei_cb_bl = mgc_blocking_ast,
+ .ei_cb_cp = ldlm_completion_ast,
+ };
struct ptlrpc_request *req;
int short_limit = cld_is_sptlrpc(cld);
int rc;
- ENTRY;
CDEBUG(D_MGC, "Enqueue for %s (res "LPX64")\n", cld->cld_logname,
cld->cld_resid.name[0]);
@@ -916,7 +895,7 @@ static int mgc_enqueue(struct obd_export *exp, struct lov_stripe_md *lsm,
&RQF_LDLM_ENQUEUE, LUSTRE_DLM_VERSION,
LDLM_ENQUEUE);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER, 0);
ptlrpc_request_set_replen(req);
@@ -934,17 +913,15 @@ static int mgc_enqueue(struct obd_export *exp, struct lov_stripe_md *lsm,
/* A failed enqueue should still call the mgc_blocking_ast,
where it will be requeued if needed ("grant failed"). */
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
static int mgc_cancel(struct obd_export *exp, struct lov_stripe_md *md,
__u32 mode, struct lustre_handle *lockh)
{
- ENTRY;
-
ldlm_lock_decref(lockh, mode);
- RETURN(0);
+ return 0;
}
static void mgc_notify_active(struct obd_device *unused)
@@ -965,18 +942,17 @@ static int mgc_target_register(struct obd_export *exp,
struct ptlrpc_request *req;
struct mgs_target_info *req_mti, *rep_mti;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
&RQF_MGS_TARGET_REG, LUSTRE_MGS_VERSION,
MGS_TARGET_REG);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req_mti = req_capsule_client_get(&req->rq_pill, &RMF_MGS_TARGET_INFO);
if (!req_mti) {
ptlrpc_req_finished(req);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
memcpy(req_mti, mti, sizeof(*req_mti));
@@ -995,7 +971,7 @@ static int mgc_target_register(struct obd_export *exp,
}
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
int mgc_set_info_async(const struct lu_env *env, struct obd_export *exp,
@@ -1003,14 +979,13 @@ int mgc_set_info_async(const struct lu_env *env, struct obd_export *exp,
void *val, struct ptlrpc_request_set *set)
{
int rc = -EINVAL;
- ENTRY;
/* Turn off initial_recov after we try all backup servers once */
if (KEY_IS(KEY_INIT_RECOV_BACKUP)) {
struct obd_import *imp = class_exp2cliimp(exp);
int value;
if (vallen != sizeof(int))
- RETURN(-EINVAL);
+ return -EINVAL;
value = *(int *)val;
CDEBUG(D_MGC, "InitRecov %s %d/d%d:i%d:r%d:or%d:%s\n",
imp->imp_obd->obd_name, value,
@@ -1021,46 +996,46 @@ int mgc_set_info_async(const struct lu_env *env, struct obd_export *exp,
if ((imp->imp_state != LUSTRE_IMP_FULL &&
imp->imp_state != LUSTRE_IMP_NEW) || value > 1)
ptlrpc_reconnect_import(imp);
- RETURN(0);
+ return 0;
}
/* FIXME move this to mgc_process_config */
if (KEY_IS(KEY_REGISTER_TARGET)) {
struct mgs_target_info *mti;
if (vallen != sizeof(struct mgs_target_info))
- RETURN(-EINVAL);
+ return -EINVAL;
mti = (struct mgs_target_info *)val;
CDEBUG(D_MGC, "register_target %s %#x\n",
mti->mti_svname, mti->mti_flags);
rc = mgc_target_register(exp, mti);
- RETURN(rc);
+ return rc;
}
if (KEY_IS(KEY_SET_FS)) {
struct super_block *sb = (struct super_block *)val;
struct lustre_sb_info *lsi;
if (vallen != sizeof(struct super_block))
- RETURN(-EINVAL);
+ return -EINVAL;
lsi = s2lsi(sb);
rc = mgc_fs_setup(exp->exp_obd, sb, lsi->lsi_srv_mnt);
if (rc) {
CERROR("set_fs got %d\n", rc);
}
- RETURN(rc);
+ return rc;
}
if (KEY_IS(KEY_CLEAR_FS)) {
if (vallen != 0)
- RETURN(-EINVAL);
+ return -EINVAL;
rc = mgc_fs_cleanup(exp->exp_obd);
if (rc) {
CERROR("clear_fs got %d\n", rc);
}
- RETURN(rc);
+ return rc;
}
if (KEY_IS(KEY_SET_INFO)) {
struct mgs_send_param *msp;
msp = (struct mgs_send_param *)val;
rc = mgc_set_mgs_param(exp, msp);
- RETURN(rc);
+ return rc;
}
if (KEY_IS(KEY_MGSSEC)) {
struct client_obd *cli = &exp->exp_obd->u.cli;
@@ -1075,7 +1050,7 @@ int mgc_set_info_async(const struct lu_env *env, struct obd_export *exp,
*/
if (vallen == 0) {
if (cli->cl_flvr_mgc.sf_rpc != SPTLRPC_FLVR_INVALID)
- RETURN(0);
+ return 0;
val = "null";
vallen = 4;
}
@@ -1084,7 +1059,7 @@ int mgc_set_info_async(const struct lu_env *env, struct obd_export *exp,
if (rc) {
CERROR("invalid sptlrpc flavor %s to MGS\n",
(char *) val);
- RETURN(rc);
+ return rc;
}
/*
@@ -1103,10 +1078,10 @@ int mgc_set_info_async(const struct lu_env *env, struct obd_export *exp,
(char *) val, str);
rc = -EPERM;
}
- RETURN(rc);
+ return rc;
}
- RETURN(rc);
+ return rc;
}
static int mgc_get_info(const struct lu_env *env, struct obd_export *exp,
@@ -1167,7 +1142,7 @@ static int mgc_import_event(struct obd_device *obd,
CERROR("Unknown import event %#x\n", event);
LBUG();
}
- RETURN(rc);
+ return rc;
}
static int mgc_llog_init(struct obd_device *obd, struct obd_llog_group *olg,
@@ -1175,7 +1150,6 @@ static int mgc_llog_init(struct obd_device *obd, struct obd_llog_group *olg,
{
struct llog_ctxt *ctxt;
int rc;
- ENTRY;
LASSERT(olg == &obd->obd_olg);
@@ -1192,20 +1166,18 @@ static int mgc_llog_init(struct obd_device *obd, struct obd_llog_group *olg,
llog_initiator_connect(ctxt);
llog_ctxt_put(ctxt);
- RETURN(0);
+ return 0;
out:
ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
if (ctxt)
llog_cleanup(NULL, ctxt);
- RETURN(rc);
+ return rc;
}
static int mgc_llog_finish(struct obd_device *obd, int count)
{
struct llog_ctxt *ctxt;
- ENTRY;
-
ctxt = llog_get_context(obd, LLOG_CONFIG_REPL_CTXT);
if (ctxt)
llog_cleanup(NULL, ctxt);
@@ -1213,7 +1185,7 @@ static int mgc_llog_finish(struct obd_device *obd, int count)
ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
if (ctxt)
llog_cleanup(NULL, ctxt);
- RETURN(0);
+ return 0;
}
enum {
@@ -1238,14 +1210,13 @@ static int mgc_apply_recover_logs(struct obd_device *mgc,
int pos;
int rc = 0;
int off = 0;
- ENTRY;
LASSERT(cfg->cfg_instance != NULL);
LASSERT(cfg->cfg_sb == cfg->cfg_instance);
OBD_ALLOC(inst, PAGE_CACHE_SIZE);
if (inst == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (!IS_SERVER(lsi)) {
pos = snprintf(inst, PAGE_CACHE_SIZE, "%p", cfg->cfg_instance);
@@ -1259,7 +1230,7 @@ static int mgc_apply_recover_logs(struct obd_device *mgc,
PAGE_CACHE_SIZE);
if (rc) {
OBD_FREE(inst, PAGE_CACHE_SIZE);
- RETURN(-EINVAL);
+ return -EINVAL;
}
pos = strlen(inst);
}
@@ -1417,7 +1388,7 @@ static int mgc_apply_recover_logs(struct obd_device *mgc,
}
OBD_FREE(inst, PAGE_CACHE_SIZE);
- RETURN(rc);
+ return rc;
}
/**
@@ -1439,7 +1410,6 @@ static int mgc_process_recover_log(struct obd_device *obd,
int i;
int ealen;
int rc;
- ENTRY;
/* allocate buffer for bulk transfer.
* if this is the first time for this mgs to read logs,
@@ -1582,8 +1552,6 @@ static int mgc_process_cfg_log(struct obd_device *mgc,
int rc = 0, must_pop = 0;
bool sptlrpc_started = false;
- ENTRY;
-
LASSERT(cld);
LASSERT(mutex_is_locked(&cld->cld_lock));
@@ -1592,7 +1560,7 @@ static int mgc_process_cfg_log(struct obd_device *mgc,
* read it up here.
*/
if (cld_is_sptlrpc(cld) && local_only)
- RETURN(0);
+ return 0;
if (cld->cld_cfg.cfg_sb)
lsi = s2lsi(cld->cld_cfg.cfg_sb);
@@ -1600,12 +1568,12 @@ static int mgc_process_cfg_log(struct obd_device *mgc,
ctxt = llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT);
if (!ctxt) {
CERROR("missing llog context\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
OBD_ALLOC_PTR(saved_ctxt);
if (saved_ctxt == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lctxt = llog_get_context(mgc, LLOG_CONFIG_ORIG_CTXT);
@@ -1623,7 +1591,6 @@ static int mgc_process_cfg_log(struct obd_device *mgc,
be updated here. */
rc = class_config_parse_llog(NULL, ctxt, cld->cld_logname,
&cld->cld_cfg);
- EXIT;
out_pop:
llog_ctxt_put(ctxt);
@@ -1647,7 +1614,7 @@ out_pop:
strlen("-sptlrpc"));
}
- RETURN(rc);
+ return rc;
}
/** Get a config log from the MGS and process it.
@@ -1659,7 +1626,6 @@ int mgc_process_log(struct obd_device *mgc, struct config_llog_data *cld)
struct lustre_handle lockh = { 0 };
__u64 flags = LDLM_FL_NO_LRU;
int rc = 0, rcl;
- ENTRY;
LASSERT(cld);
@@ -1670,7 +1636,7 @@ int mgc_process_log(struct obd_device *mgc, struct config_llog_data *cld)
mutex_lock(&cld->cld_lock);
if (cld->cld_stopping) {
mutex_unlock(&cld->cld_lock);
- RETURN(0);
+ return 0;
}
OBD_FAIL_TIMEOUT(OBD_FAIL_MGC_PAUSE_PROCESS_LOG, 20);
@@ -1719,7 +1685,7 @@ int mgc_process_log(struct obd_device *mgc, struct config_llog_data *cld)
CERROR("Can't drop cfg lock: %d\n", rcl);
}
- RETURN(rc);
+ return rc;
}
@@ -1733,7 +1699,6 @@ static int mgc_process_config(struct obd_device *obd, obd_count len, void *buf)
struct config_llog_instance *cfg = NULL;
char *logname;
int rc = 0;
- ENTRY;
switch(lcfg->lcfg_command) {
case LCFG_LOV_ADD_OBD: {
@@ -1818,7 +1783,7 @@ static int mgc_process_config(struct obd_device *obd, obd_count len, void *buf)
}
}
out:
- RETURN(rc);
+ return rc;
}
struct obd_ops mgc_obd_ops = {
diff --git a/drivers/staging/lustre/lustre/obdclass/Makefile b/drivers/staging/lustre/lustre/obdclass/Makefile
index b80c13c6f5d..8a0e08ced45 100644
--- a/drivers/staging/lustre/lustre/obdclass/Makefile
+++ b/drivers/staging/lustre/lustre/obdclass/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_LUSTRE_FS) += obdclass.o llog_test.o
obdclass-y := linux/linux-module.o linux/linux-obdo.o linux/linux-sysctl.o \
llog.o llog_cat.o llog_obd.o llog_swab.o class_obd.o debug.o \
genops.o uuid.o llog_ioctl.o lprocfs_status.o \
- lprocfs_jobstats.o lustre_handles.o lustre_peer.o llog_osd.o \
+ lustre_handles.o lustre_peer.o llog_osd.o \
local_storage.o statfs_pack.o obdo.o obd_config.o obd_mount.o\
mea.o lu_object.o dt_object.o capa.o cl_object.o \
cl_page.o cl_lock.o cl_io.o lu_ref.o acl.o idmap.o \
diff --git a/drivers/staging/lustre/lustre/obdclass/acl.c b/drivers/staging/lustre/lustre/obdclass/acl.c
index c2a6702c9f2..f0bb632a70a 100644
--- a/drivers/staging/lustre/lustre/obdclass/acl.c
+++ b/drivers/staging/lustre/lustre/obdclass/acl.c
@@ -144,10 +144,9 @@ lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
{
int count, i, esize;
ext_acl_xattr_header *new;
- ENTRY;
if (unlikely(size < 0))
- RETURN(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
else if (!size)
count = 0;
else
@@ -155,7 +154,7 @@ lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
OBD_ALLOC(new, esize);
if (unlikely(new == NULL))
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
new->a_count = cpu_to_le32(count);
for (i = 0; i < count; i++) {
@@ -165,7 +164,7 @@ lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
}
- RETURN(new);
+ return new;
}
EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
@@ -178,16 +177,15 @@ int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
int count, i, j, rc = 0;
__u32 id;
posix_acl_xattr_header *new;
- ENTRY;
if (unlikely(size < 0))
- RETURN(-EINVAL);
+ return -EINVAL;
else if (!size)
- RETURN(0);
+ return 0;
OBD_ALLOC(new, size);
if (unlikely(new == NULL))
- RETURN(-ENOMEM);
+ return -ENOMEM;
new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
@@ -228,7 +226,6 @@ int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
*out = new;
rc = 0;
}
- EXIT;
_out:
if (rc) {
@@ -302,7 +299,6 @@ int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
posix_acl_xattr_header *new;
ext_acl_xattr_entry *ee, ae;
- ENTRY;
lustre_posix_acl_cpu_to_le(&pe, &pe);
ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
@@ -312,7 +308,7 @@ int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
OBD_ALLOC(new, posix_size);
if (unlikely(new == NULL))
- RETURN(-ENOMEM);
+ return -ENOMEM;
new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
for (i = 0, j = 0; i < ext_count; i++) {
@@ -349,7 +345,7 @@ int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
int ori_posix_count;
if (unlikely(size < 0))
- RETURN(-EINVAL);
+ return -EINVAL;
else if (!size)
ori_posix_count = 0;
else
@@ -360,7 +356,7 @@ int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
OBD_ALLOC(new, posix_size);
if (unlikely(new == NULL))
- RETURN(-ENOMEM);
+ return -ENOMEM;
new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
/* 1. process the unchanged ACL entries
@@ -397,7 +393,6 @@ int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
*out = new;
rc = 0;
}
- EXIT;
_out:
if (rc) {
@@ -420,10 +415,9 @@ lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
posix_acl_xattr_entry pae;
ext_acl_xattr_header *new;
ext_acl_xattr_entry *ee, eae;
- ENTRY;
if (unlikely(size < 0))
- RETURN(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
else if (!size)
posix_count = 0;
else
@@ -434,7 +428,7 @@ lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
OBD_ALLOC(new, ext_size);
if (unlikely(new == NULL))
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
for (i = 0, j = 0; i < posix_count; i++) {
lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
@@ -532,7 +526,6 @@ lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
new->a_count = cpu_to_le32(j);
/* free unused space. */
rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
- EXIT;
out:
if (rc) {
diff --git a/drivers/staging/lustre/lustre/obdclass/capa.c b/drivers/staging/lustre/lustre/obdclass/capa.c
index 3e532f5106e..68d797ba8ae 100644
--- a/drivers/staging/lustre/lustre/obdclass/capa.c
+++ b/drivers/staging/lustre/lustre/obdclass/capa.c
@@ -42,12 +42,12 @@
#define DEBUG_SUBSYSTEM S_SEC
-#include <linux/version.h>
#include <linux/fs.h>
#include <asm/unistd.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/crypto.h>
#include <obd_class.h>
#include <lustre_debug.h>
@@ -77,6 +77,12 @@ EXPORT_SYMBOL(capa_list);
EXPORT_SYMBOL(capa_lock);
EXPORT_SYMBOL(capa_count);
+static inline
+unsigned int ll_crypto_tfm_alg_min_keysize(struct crypto_blkcipher *tfm)
+{
+ return crypto_blkcipher_tfm(tfm)->__crt_alg->cra_blkcipher.min_keysize;
+}
+
struct hlist_head *init_capa_hash(void)
{
struct hlist_head *hash;
@@ -235,9 +241,26 @@ struct obd_capa *capa_lookup(struct hlist_head *hash, struct lustre_capa *capa,
}
EXPORT_SYMBOL(capa_lookup);
+static inline int ll_crypto_hmac(struct crypto_hash *tfm,
+ u8 *key, unsigned int *keylen,
+ struct scatterlist *sg,
+ unsigned int size, u8 *result)
+{
+ struct hash_desc desc;
+ int rv;
+ desc.tfm = tfm;
+ desc.flags = 0;
+ rv = crypto_hash_setkey(desc.tfm, key, *keylen);
+ if (rv) {
+ CERROR("failed to hash setkey: %d\n", rv);
+ return rv;
+ }
+ return crypto_hash_digest(&desc, sg, size, result);
+}
+
int capa_hmac(__u8 *hmac, struct lustre_capa *capa, __u8 *key)
{
- struct ll_crypto_hash *tfm;
+ struct crypto_hash *tfm;
struct capa_hmac_alg *alg;
int keylen;
struct scatterlist sl;
@@ -249,7 +272,7 @@ int capa_hmac(__u8 *hmac, struct lustre_capa *capa, __u8 *key)
alg = &capa_hmac_algs[capa_alg(capa)];
- tfm = ll_crypto_alloc_hash(alg->ha_name, 0, 0);
+ tfm = crypto_alloc_hash(alg->ha_name, 0, 0);
if (!tfm) {
CERROR("crypto_alloc_tfm failed, check whether your kernel"
"has crypto support!\n");
@@ -262,7 +285,7 @@ int capa_hmac(__u8 *hmac, struct lustre_capa *capa, __u8 *key)
(unsigned long)(capa) % PAGE_CACHE_SIZE);
ll_crypto_hmac(tfm, key, &keylen, &sl, sl.length, hmac);
- ll_crypto_free_hash(tfm);
+ crypto_free_hash(tfm);
return 0;
}
@@ -270,21 +293,20 @@ EXPORT_SYMBOL(capa_hmac);
int capa_encrypt_id(__u32 *d, __u32 *s, __u8 *key, int keylen)
{
- struct ll_crypto_cipher *tfm;
+ struct crypto_blkcipher *tfm;
struct scatterlist sd;
struct scatterlist ss;
struct blkcipher_desc desc;
unsigned int min;
int rc;
char alg[CRYPTO_MAX_ALG_NAME+1] = "aes";
- ENTRY;
/* passing "aes" in a variable instead of a constant string keeps gcc
* 4.3.2 happy */
- tfm = ll_crypto_alloc_blkcipher(alg, 0, 0 );
+ tfm = crypto_alloc_blkcipher(alg, 0, 0 );
if (IS_ERR(tfm)) {
CERROR("failed to load transform for aes\n");
- RETURN(PTR_ERR(tfm));
+ return PTR_ERR(tfm);
}
min = ll_crypto_tfm_alg_min_keysize(tfm);
@@ -293,7 +315,7 @@ int capa_encrypt_id(__u32 *d, __u32 *s, __u8 *key, int keylen)
GOTO(out, rc = -EINVAL);
}
- rc = ll_crypto_blkcipher_setkey(tfm, key, min);
+ rc = crypto_blkcipher_setkey(tfm, key, min);
if (rc) {
CERROR("failed to setting key for aes\n");
GOTO(out, rc);
@@ -307,37 +329,34 @@ int capa_encrypt_id(__u32 *d, __u32 *s, __u8 *key, int keylen)
desc.tfm = tfm;
desc.info = NULL;
desc.flags = 0;
- rc = ll_crypto_blkcipher_encrypt(&desc, &sd, &ss, 16);
+ rc = crypto_blkcipher_encrypt(&desc, &sd, &ss, 16);
if (rc) {
CERROR("failed to encrypt for aes\n");
GOTO(out, rc);
}
- EXIT;
-
out:
- ll_crypto_free_blkcipher(tfm);
+ crypto_free_blkcipher(tfm);
return rc;
}
EXPORT_SYMBOL(capa_encrypt_id);
int capa_decrypt_id(__u32 *d, __u32 *s, __u8 *key, int keylen)
{
- struct ll_crypto_cipher *tfm;
+ struct crypto_blkcipher *tfm;
struct scatterlist sd;
struct scatterlist ss;
struct blkcipher_desc desc;
unsigned int min;
int rc;
char alg[CRYPTO_MAX_ALG_NAME+1] = "aes";
- ENTRY;
/* passing "aes" in a variable instead of a constant string keeps gcc
* 4.3.2 happy */
- tfm = ll_crypto_alloc_blkcipher(alg, 0, 0 );
+ tfm = crypto_alloc_blkcipher(alg, 0, 0 );
if (IS_ERR(tfm)) {
CERROR("failed to load transform for aes\n");
- RETURN(PTR_ERR(tfm));
+ return PTR_ERR(tfm);
}
min = ll_crypto_tfm_alg_min_keysize(tfm);
@@ -346,7 +365,7 @@ int capa_decrypt_id(__u32 *d, __u32 *s, __u8 *key, int keylen)
GOTO(out, rc = -EINVAL);
}
- rc = ll_crypto_blkcipher_setkey(tfm, key, min);
+ rc = crypto_blkcipher_setkey(tfm, key, min);
if (rc) {
CERROR("failed to setting key for aes\n");
GOTO(out, rc);
@@ -361,16 +380,14 @@ int capa_decrypt_id(__u32 *d, __u32 *s, __u8 *key, int keylen)
desc.tfm = tfm;
desc.info = NULL;
desc.flags = 0;
- rc = ll_crypto_blkcipher_decrypt(&desc, &sd, &ss, 16);
+ rc = crypto_blkcipher_decrypt(&desc, &sd, &ss, 16);
if (rc) {
CERROR("failed to decrypt for aes\n");
GOTO(out, rc);
}
- EXIT;
-
out:
- ll_crypto_free_blkcipher(tfm);
+ crypto_free_blkcipher(tfm);
return rc;
}
EXPORT_SYMBOL(capa_decrypt_id);
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c
index 75c9be8875e..42697934155 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_io.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c
@@ -106,7 +106,6 @@ void cl_io_fini(const struct lu_env *env, struct cl_io *io)
LINVRNT(cl_io_type_is_valid(io->ci_type));
LINVRNT(cl_io_invariant(io));
- ENTRY;
while (!list_empty(&io->ci_layers)) {
slice = container_of(io->ci_layers.prev, struct cl_io_slice,
@@ -144,7 +143,6 @@ void cl_io_fini(const struct lu_env *env, struct cl_io *io)
default:
LBUG();
}
- EXIT;
}
EXPORT_SYMBOL(cl_io_fini);
@@ -157,7 +155,6 @@ static int cl_io_init0(const struct lu_env *env, struct cl_io *io,
LINVRNT(io->ci_state == CIS_ZERO || io->ci_state == CIS_FINI);
LINVRNT(cl_io_type_is_valid(iot));
LINVRNT(cl_io_invariant(io));
- ENTRY;
io->ci_type = iot;
INIT_LIST_HEAD(&io->ci_lockset.cls_todo);
@@ -175,7 +172,7 @@ static int cl_io_init0(const struct lu_env *env, struct cl_io *io,
}
if (result == 0)
io->ci_state = CIS_INIT;
- RETURN(result);
+ return result;
}
/**
@@ -228,7 +225,6 @@ int cl_io_rw_init(const struct lu_env *env, struct cl_io *io,
{
LINVRNT(iot == CIT_READ || iot == CIT_WRITE);
LINVRNT(io->ci_obj != NULL);
- ENTRY;
LU_OBJECT_HEADER(D_VFSTRACE, env, &io->ci_obj->co_lu,
"io range: %u ["LPU64", "LPU64") %u %u\n",
@@ -236,7 +232,7 @@ int cl_io_rw_init(const struct lu_env *env, struct cl_io *io,
io->u.ci_rw.crw_nonblock, io->u.ci_wr.wr_append);
io->u.ci_rw.crw_pos = pos;
io->u.ci_rw.crw_count = count;
- RETURN(cl_io_init(env, io, iot, io->ci_obj));
+ return cl_io_init(env, io, iot, io->ci_obj);
}
EXPORT_SYMBOL(cl_io_rw_init);
@@ -288,7 +284,6 @@ static void cl_io_locks_sort(struct cl_io *io)
{
int done = 0;
- ENTRY;
/* hidden treasure: bubble sort for now. */
do {
struct cl_io_lock_link *curr;
@@ -325,7 +320,6 @@ static void cl_io_locks_sort(struct cl_io *io)
prev = curr;
}
} while (!done);
- EXIT;
}
/**
@@ -339,12 +333,11 @@ int cl_queue_match(const struct list_head *queue,
{
struct cl_io_lock_link *scan;
- ENTRY;
list_for_each_entry(scan, queue, cill_linkage) {
if (cl_lock_descr_match(&scan->cill_descr, need))
- RETURN(+1);
+ return +1;
}
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(cl_queue_match);
@@ -353,7 +346,6 @@ static int cl_queue_merge(const struct list_head *queue,
{
struct cl_io_lock_link *scan;
- ENTRY;
list_for_each_entry(scan, queue, cill_linkage) {
if (cl_lock_descr_cmp(&scan->cill_descr, need))
continue;
@@ -361,9 +353,9 @@ static int cl_queue_merge(const struct list_head *queue,
CDEBUG(D_VFSTRACE, "lock: %d: [%lu, %lu]\n",
scan->cill_descr.cld_mode, scan->cill_descr.cld_start,
scan->cill_descr.cld_end);
- RETURN(+1);
+ return +1;
}
- RETURN(0);
+ return 0;
}
@@ -388,8 +380,6 @@ static int cl_lockset_lock_one(const struct lu_env *env,
struct cl_lock *lock;
int result;
- ENTRY;
-
lock = cl_lock_request(env, io, &link->cill_descr, "io", io);
if (!IS_ERR(lock)) {
@@ -404,7 +394,7 @@ static int cl_lockset_lock_one(const struct lu_env *env,
result = 0;
} else
result = PTR_ERR(lock);
- RETURN(result);
+ return result;
}
static void cl_lock_link_fini(const struct lu_env *env, struct cl_io *io,
@@ -412,7 +402,6 @@ static void cl_lock_link_fini(const struct lu_env *env, struct cl_io *io,
{
struct cl_lock *lock = link->cill_lock;
- ENTRY;
list_del_init(&link->cill_linkage);
if (lock != NULL) {
cl_lock_release(env, lock, "io", io);
@@ -420,7 +409,6 @@ static void cl_lock_link_fini(const struct lu_env *env, struct cl_io *io,
}
if (link->cill_fini != NULL)
link->cill_fini(env, link);
- EXIT;
}
static int cl_lockset_lock(const struct lu_env *env, struct cl_io *io,
@@ -431,7 +419,6 @@ static int cl_lockset_lock(const struct lu_env *env, struct cl_io *io,
struct cl_lock *lock;
int result;
- ENTRY;
result = 0;
list_for_each_entry_safe(link, temp, &set->cls_todo, cill_linkage) {
if (!cl_lockset_match(set, &link->cill_descr)) {
@@ -455,7 +442,7 @@ static int cl_lockset_lock(const struct lu_env *env, struct cl_io *io,
break;
}
}
- RETURN(result);
+ return result;
}
/**
@@ -474,7 +461,6 @@ int cl_io_lock(const struct lu_env *env, struct cl_io *io)
LINVRNT(io->ci_state == CIS_IT_STARTED);
LINVRNT(cl_io_invariant(io));
- ENTRY;
cl_io_for_each(scan, io) {
if (scan->cis_iop->op[io->ci_type].cio_lock == NULL)
continue;
@@ -490,7 +476,7 @@ int cl_io_lock(const struct lu_env *env, struct cl_io *io)
cl_io_unlock(env, io);
else
io->ci_state = CIS_LOCKED;
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_io_lock);
@@ -508,7 +494,6 @@ void cl_io_unlock(const struct lu_env *env, struct cl_io *io)
LASSERT(CIS_IT_STARTED <= io->ci_state && io->ci_state < CIS_UNLOCKED);
LINVRNT(cl_io_invariant(io));
- ENTRY;
set = &io->ci_lockset;
list_for_each_entry_safe(link, temp, &set->cls_todo, cill_linkage)
@@ -527,7 +512,6 @@ void cl_io_unlock(const struct lu_env *env, struct cl_io *io)
}
io->ci_state = CIS_UNLOCKED;
LASSERT(!cl_env_info(env)->clt_counters[CNL_TOP].ctc_nr_locks_acquired);
- EXIT;
}
EXPORT_SYMBOL(cl_io_unlock);
@@ -547,7 +531,6 @@ int cl_io_iter_init(const struct lu_env *env, struct cl_io *io)
LINVRNT(io->ci_state == CIS_INIT || io->ci_state == CIS_IT_ENDED);
LINVRNT(cl_io_invariant(io));
- ENTRY;
result = 0;
cl_io_for_each(scan, io) {
if (scan->cis_iop->op[io->ci_type].cio_iter_init == NULL)
@@ -559,7 +542,7 @@ int cl_io_iter_init(const struct lu_env *env, struct cl_io *io)
}
if (result == 0)
io->ci_state = CIS_IT_STARTED;
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_io_iter_init);
@@ -576,13 +559,11 @@ void cl_io_iter_fini(const struct lu_env *env, struct cl_io *io)
LINVRNT(io->ci_state == CIS_UNLOCKED);
LINVRNT(cl_io_invariant(io));
- ENTRY;
cl_io_for_each_reverse(scan, io) {
if (scan->cis_iop->op[io->ci_type].cio_iter_fini != NULL)
scan->cis_iop->op[io->ci_type].cio_iter_fini(env, scan);
}
io->ci_state = CIS_IT_ENDED;
- EXIT;
}
EXPORT_SYMBOL(cl_io_iter_fini);
@@ -598,8 +579,6 @@ void cl_io_rw_advance(const struct lu_env *env, struct cl_io *io, size_t nob)
LINVRNT(cl_io_is_loopable(io));
LINVRNT(cl_io_invariant(io));
- ENTRY;
-
io->u.ci_rw.crw_pos += nob;
io->u.ci_rw.crw_count -= nob;
@@ -609,7 +588,6 @@ void cl_io_rw_advance(const struct lu_env *env, struct cl_io *io, size_t nob)
scan->cis_iop->op[io->ci_type].cio_advance(env, scan,
nob);
}
- EXIT;
}
EXPORT_SYMBOL(cl_io_rw_advance);
@@ -621,14 +599,13 @@ int cl_io_lock_add(const struct lu_env *env, struct cl_io *io,
{
int result;
- ENTRY;
if (cl_lockset_merge(&io->ci_lockset, &link->cill_descr))
result = +1;
else {
list_add(&link->cill_linkage, &io->ci_lockset.cls_todo);
result = 0;
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_io_lock_add);
@@ -647,7 +624,6 @@ int cl_io_lock_alloc_add(const struct lu_env *env, struct cl_io *io,
struct cl_io_lock_link *link;
int result;
- ENTRY;
OBD_ALLOC_PTR(link);
if (link != NULL) {
link->cill_descr = *descr;
@@ -658,7 +634,7 @@ int cl_io_lock_alloc_add(const struct lu_env *env, struct cl_io *io,
} else
result = -ENOMEM;
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_io_lock_alloc_add);
@@ -673,7 +649,6 @@ int cl_io_start(const struct lu_env *env, struct cl_io *io)
LINVRNT(cl_io_is_loopable(io));
LINVRNT(io->ci_state == CIS_LOCKED);
LINVRNT(cl_io_invariant(io));
- ENTRY;
io->ci_state = CIS_IO_GOING;
cl_io_for_each(scan, io) {
@@ -685,7 +660,7 @@ int cl_io_start(const struct lu_env *env, struct cl_io *io)
}
if (result >= 0)
result = 0;
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_io_start);
@@ -700,7 +675,6 @@ void cl_io_end(const struct lu_env *env, struct cl_io *io)
LINVRNT(cl_io_is_loopable(io));
LINVRNT(io->ci_state == CIS_IO_GOING);
LINVRNT(cl_io_invariant(io));
- ENTRY;
cl_io_for_each_reverse(scan, io) {
if (scan->cis_iop->op[io->ci_type].cio_end != NULL)
@@ -708,7 +682,6 @@ void cl_io_end(const struct lu_env *env, struct cl_io *io)
/* TODO: error handling. */
}
io->ci_state = CIS_IO_FINISHED;
- EXIT;
}
EXPORT_SYMBOL(cl_io_end);
@@ -774,7 +747,6 @@ int cl_io_read_page(const struct lu_env *env, struct cl_io *io,
LINVRNT(io->ci_state == CIS_IO_GOING || io->ci_state == CIS_LOCKED);
LINVRNT(cl_page_in_io(page, io));
LINVRNT(cl_io_invariant(io));
- ENTRY;
queue = &io->ci_queue;
@@ -807,7 +779,7 @@ int cl_io_read_page(const struct lu_env *env, struct cl_io *io,
*/
cl_page_list_disown(env, io, &queue->c2_qin);
cl_2queue_fini(env, queue);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_io_read_page);
@@ -827,7 +799,6 @@ int cl_io_prepare_write(const struct lu_env *env, struct cl_io *io,
LINVRNT(io->ci_state == CIS_IO_GOING || io->ci_state == CIS_LOCKED);
LINVRNT(cl_io_invariant(io));
LASSERT(cl_page_in_io(page, io));
- ENTRY;
cl_io_for_each_reverse(scan, io) {
if (scan->cis_iop->cio_prepare_write != NULL) {
@@ -841,7 +812,7 @@ int cl_io_prepare_write(const struct lu_env *env, struct cl_io *io,
break;
}
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_io_prepare_write);
@@ -867,7 +838,6 @@ int cl_io_commit_write(const struct lu_env *env, struct cl_io *io,
*/
LASSERT(cl_page_is_owned(page, io) || page->cp_parent != NULL);
LASSERT(cl_page_in_io(page, io));
- ENTRY;
cl_io_for_each(scan, io) {
if (scan->cis_iop->cio_commit_write != NULL) {
@@ -882,7 +852,7 @@ int cl_io_commit_write(const struct lu_env *env, struct cl_io *io,
}
}
LINVRNT(result <= 0);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_io_commit_write);
@@ -903,7 +873,6 @@ int cl_io_submit_rw(const struct lu_env *env, struct cl_io *io,
int result = 0;
LINVRNT(crt < ARRAY_SIZE(scan->cis_iop->req_op));
- ENTRY;
cl_io_for_each(scan, io) {
if (scan->cis_iop->req_op[crt].cio_submit == NULL)
@@ -917,7 +886,7 @@ int cl_io_submit_rw(const struct lu_env *env, struct cl_io *io,
* If ->cio_submit() failed, no pages were sent.
*/
LASSERT(ergo(result != 0, list_empty(&queue->c2_qout.pl_pages)));
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_io_submit_rw);
@@ -1009,7 +978,6 @@ int cl_io_loop(const struct lu_env *env, struct cl_io *io)
int result = 0;
LINVRNT(cl_io_is_loopable(io));
- ENTRY;
do {
size_t nob;
@@ -1043,7 +1011,7 @@ int cl_io_loop(const struct lu_env *env, struct cl_io *io)
} while (result == 0 && io->ci_continue);
if (result == 0)
result = io->ci_result;
- RETURN(result < 0 ? result : 0);
+ return result < 0 ? result : 0;
}
EXPORT_SYMBOL(cl_io_loop);
@@ -1064,13 +1032,11 @@ void cl_io_slice_add(struct cl_io *io, struct cl_io_slice *slice,
LASSERT((linkage->prev == NULL && linkage->next == NULL) ||
list_empty(linkage));
- ENTRY;
list_add_tail(linkage, &io->ci_layers);
slice->cis_io = io;
slice->cis_obj = obj;
slice->cis_iop = ops;
- EXIT;
}
EXPORT_SYMBOL(cl_io_slice_add);
@@ -1080,11 +1046,9 @@ EXPORT_SYMBOL(cl_io_slice_add);
*/
void cl_page_list_init(struct cl_page_list *plist)
{
- ENTRY;
plist->pl_nr = 0;
INIT_LIST_HEAD(&plist->pl_pages);
plist->pl_owner = current;
- EXIT;
}
EXPORT_SYMBOL(cl_page_list_init);
@@ -1093,7 +1057,6 @@ EXPORT_SYMBOL(cl_page_list_init);
*/
void cl_page_list_add(struct cl_page_list *plist, struct cl_page *page)
{
- ENTRY;
/* it would be better to check that page is owned by "current" io, but
* it is not passed here. */
LASSERT(page->cp_owner != NULL);
@@ -1105,9 +1068,8 @@ void cl_page_list_add(struct cl_page_list *plist, struct cl_page *page)
LASSERT(list_empty(&page->cp_batch));
list_add_tail(&page->cp_batch, &plist->pl_pages);
++plist->pl_nr;
- page->cp_queue_ref = lu_ref_add(&page->cp_reference, "queue", plist);
+ lu_ref_add_at(&page->cp_reference, &page->cp_queue_ref, "queue", plist);
cl_page_get(page);
- EXIT;
}
EXPORT_SYMBOL(cl_page_list_add);
@@ -1120,15 +1082,13 @@ void cl_page_list_del(const struct lu_env *env,
LASSERT(plist->pl_nr > 0);
LINVRNT(plist->pl_owner == current);
- ENTRY;
list_del_init(&page->cp_batch);
lockdep_off();
mutex_unlock(&page->cp_mutex);
lockdep_on();
--plist->pl_nr;
- lu_ref_del_at(&page->cp_reference, page->cp_queue_ref, "queue", plist);
+ lu_ref_del_at(&page->cp_reference, &page->cp_queue_ref, "queue", plist);
cl_page_put(env, page);
- EXIT;
}
EXPORT_SYMBOL(cl_page_list_del);
@@ -1142,13 +1102,11 @@ void cl_page_list_move(struct cl_page_list *dst, struct cl_page_list *src,
LINVRNT(dst->pl_owner == current);
LINVRNT(src->pl_owner == current);
- ENTRY;
list_move_tail(&page->cp_batch, &dst->pl_pages);
--src->pl_nr;
++dst->pl_nr;
- lu_ref_set_at(&page->cp_reference,
- page->cp_queue_ref, "queue", src, dst);
- EXIT;
+ lu_ref_set_at(&page->cp_reference, &page->cp_queue_ref, "queue",
+ src, dst);
}
EXPORT_SYMBOL(cl_page_list_move);
@@ -1163,10 +1121,8 @@ void cl_page_list_splice(struct cl_page_list *list, struct cl_page_list *head)
LINVRNT(list->pl_owner == current);
LINVRNT(head->pl_owner == current);
- ENTRY;
cl_page_list_for_each_safe(page, tmp, list)
cl_page_list_move(head, list, page);
- EXIT;
}
EXPORT_SYMBOL(cl_page_list_splice);
@@ -1184,7 +1140,6 @@ void cl_page_list_disown(const struct lu_env *env,
LINVRNT(plist->pl_owner == current);
- ENTRY;
cl_page_list_for_each_safe(page, temp, plist) {
LASSERT(plist->pl_nr > 0);
@@ -1202,10 +1157,10 @@ void cl_page_list_disown(const struct lu_env *env,
* XXX cl_page_disown0() will fail if page is not locked.
*/
cl_page_disown0(env, io, page);
- lu_ref_del(&page->cp_reference, "queue", plist);
+ lu_ref_del_at(&page->cp_reference, &page->cp_queue_ref, "queue",
+ plist);
cl_page_put(env, page);
}
- EXIT;
}
EXPORT_SYMBOL(cl_page_list_disown);
@@ -1219,11 +1174,9 @@ void cl_page_list_fini(const struct lu_env *env, struct cl_page_list *plist)
LINVRNT(plist->pl_owner == current);
- ENTRY;
cl_page_list_for_each_safe(page, temp, plist)
cl_page_list_del(env, plist, page);
LASSERT(plist->pl_nr == 0);
- EXIT;
}
EXPORT_SYMBOL(cl_page_list_fini);
@@ -1240,7 +1193,6 @@ int cl_page_list_own(const struct lu_env *env,
LINVRNT(plist->pl_owner == current);
- ENTRY;
result = 0;
cl_page_list_for_each_safe(page, temp, plist) {
LASSERT(index <= page->cp_index);
@@ -1250,7 +1202,7 @@ int cl_page_list_own(const struct lu_env *env,
else
cl_page_list_del(env, plist, page);
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_page_list_own);
@@ -1278,10 +1230,8 @@ void cl_page_list_discard(const struct lu_env *env, struct cl_io *io,
struct cl_page *page;
LINVRNT(plist->pl_owner == current);
- ENTRY;
cl_page_list_for_each(page, plist)
cl_page_discard(env, io, page);
- EXIT;
}
EXPORT_SYMBOL(cl_page_list_discard);
@@ -1295,14 +1245,13 @@ int cl_page_list_unmap(const struct lu_env *env, struct cl_io *io,
int result;
LINVRNT(plist->pl_owner == current);
- ENTRY;
result = 0;
cl_page_list_for_each(page, plist) {
result = cl_page_unmap(env, io, page);
if (result != 0)
break;
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_page_list_unmap);
@@ -1311,10 +1260,8 @@ EXPORT_SYMBOL(cl_page_list_unmap);
*/
void cl_2queue_init(struct cl_2queue *queue)
{
- ENTRY;
cl_page_list_init(&queue->c2_qin);
cl_page_list_init(&queue->c2_qout);
- EXIT;
}
EXPORT_SYMBOL(cl_2queue_init);
@@ -1323,9 +1270,7 @@ EXPORT_SYMBOL(cl_2queue_init);
*/
void cl_2queue_add(struct cl_2queue *queue, struct cl_page *page)
{
- ENTRY;
cl_page_list_add(&queue->c2_qin, page);
- EXIT;
}
EXPORT_SYMBOL(cl_2queue_add);
@@ -1335,10 +1280,8 @@ EXPORT_SYMBOL(cl_2queue_add);
void cl_2queue_disown(const struct lu_env *env,
struct cl_io *io, struct cl_2queue *queue)
{
- ENTRY;
cl_page_list_disown(env, io, &queue->c2_qin);
cl_page_list_disown(env, io, &queue->c2_qout);
- EXIT;
}
EXPORT_SYMBOL(cl_2queue_disown);
@@ -1348,10 +1291,8 @@ EXPORT_SYMBOL(cl_2queue_disown);
void cl_2queue_discard(const struct lu_env *env,
struct cl_io *io, struct cl_2queue *queue)
{
- ENTRY;
cl_page_list_discard(env, io, &queue->c2_qin);
cl_page_list_discard(env, io, &queue->c2_qout);
- EXIT;
}
EXPORT_SYMBOL(cl_2queue_discard);
@@ -1371,10 +1312,8 @@ EXPORT_SYMBOL(cl_2queue_assume);
*/
void cl_2queue_fini(const struct lu_env *env, struct cl_2queue *queue)
{
- ENTRY;
cl_page_list_fini(env, &queue->c2_qout);
cl_page_list_fini(env, &queue->c2_qin);
- EXIT;
}
EXPORT_SYMBOL(cl_2queue_fini);
@@ -1383,10 +1322,8 @@ EXPORT_SYMBOL(cl_2queue_fini);
*/
void cl_2queue_init_page(struct cl_2queue *queue, struct cl_page *page)
{
- ENTRY;
cl_2queue_init(queue);
cl_2queue_add(queue, page);
- EXIT;
}
EXPORT_SYMBOL(cl_2queue_init_page);
@@ -1397,10 +1334,9 @@ EXPORT_SYMBOL(cl_2queue_init_page);
*/
struct cl_io *cl_io_top(struct cl_io *io)
{
- ENTRY;
while (io->ci_parent != NULL)
io = io->ci_parent;
- RETURN(io);
+ return io;
}
EXPORT_SYMBOL(cl_io_top);
@@ -1425,12 +1361,10 @@ void cl_req_slice_add(struct cl_req *req, struct cl_req_slice *slice,
struct cl_device *dev,
const struct cl_req_operations *ops)
{
- ENTRY;
list_add_tail(&slice->crs_linkage, &req->crq_layers);
slice->crs_dev = dev;
slice->crs_ops = ops;
slice->crs_req = req;
- EXIT;
}
EXPORT_SYMBOL(cl_req_slice_add);
@@ -1442,14 +1376,13 @@ static void cl_req_free(const struct lu_env *env, struct cl_req *req)
LASSERT(req->crq_nrpages == 0);
LINVRNT(list_empty(&req->crq_layers));
LINVRNT(equi(req->crq_nrobjs > 0, req->crq_o != NULL));
- ENTRY;
if (req->crq_o != NULL) {
for (i = 0; i < req->crq_nrobjs; ++i) {
struct cl_object *obj = req->crq_o[i].ro_obj;
if (obj != NULL) {
lu_object_ref_del_at(&obj->co_lu,
- req->crq_o[i].ro_obj_ref,
+ &req->crq_o[i].ro_obj_ref,
"cl_req", req);
cl_object_put(env, obj);
}
@@ -1457,7 +1390,6 @@ static void cl_req_free(const struct lu_env *env, struct cl_req *req)
OBD_FREE(req->crq_o, req->crq_nrobjs * sizeof req->crq_o[0]);
}
OBD_FREE_PTR(req);
- EXIT;
}
static int cl_req_init(const struct lu_env *env, struct cl_req *req,
@@ -1467,7 +1399,6 @@ static int cl_req_init(const struct lu_env *env, struct cl_req *req,
struct cl_page_slice *slice;
int result;
- ENTRY;
result = 0;
page = cl_page_top(page);
do {
@@ -1482,7 +1413,7 @@ static int cl_req_init(const struct lu_env *env, struct cl_req *req,
}
page = page->cp_child;
} while (page != NULL && result == 0);
- RETURN(result);
+ return result;
}
/**
@@ -1493,7 +1424,6 @@ void cl_req_completion(const struct lu_env *env, struct cl_req *req, int rc)
{
struct cl_req_slice *slice;
- ENTRY;
/*
* for the lack of list_for_each_entry_reverse_safe()...
*/
@@ -1505,7 +1435,6 @@ void cl_req_completion(const struct lu_env *env, struct cl_req *req, int rc)
slice->crs_ops->cro_completion(env, slice, rc);
}
cl_req_free(env, req);
- EXIT;
}
EXPORT_SYMBOL(cl_req_completion);
@@ -1518,7 +1447,6 @@ struct cl_req *cl_req_alloc(const struct lu_env *env, struct cl_page *page,
struct cl_req *req;
LINVRNT(nr_objects > 0);
- ENTRY;
OBD_ALLOC_PTR(req);
if (req != NULL) {
@@ -1539,7 +1467,7 @@ struct cl_req *cl_req_alloc(const struct lu_env *env, struct cl_page *page,
}
} else
req = ERR_PTR(-ENOMEM);
- RETURN(req);
+ return req;
}
EXPORT_SYMBOL(cl_req_alloc);
@@ -1553,7 +1481,6 @@ void cl_req_page_add(const struct lu_env *env,
struct cl_req_obj *rqo;
int i;
- ENTRY;
page = cl_page_top(page);
LASSERT(list_empty(&page->cp_flight));
@@ -1570,13 +1497,12 @@ void cl_req_page_add(const struct lu_env *env,
if (rqo->ro_obj == NULL) {
rqo->ro_obj = obj;
cl_object_get(obj);
- rqo->ro_obj_ref = lu_object_ref_add(&obj->co_lu,
- "cl_req", req);
+ lu_object_ref_add_at(&obj->co_lu, &rqo->ro_obj_ref,
+ "cl_req", req);
break;
}
}
LASSERT(i < req->crq_nrobjs);
- EXIT;
}
EXPORT_SYMBOL(cl_req_page_add);
@@ -1587,7 +1513,6 @@ void cl_req_page_done(const struct lu_env *env, struct cl_page *page)
{
struct cl_req *req = page->cp_req;
- ENTRY;
page = cl_page_top(page);
LASSERT(!list_empty(&page->cp_flight));
@@ -1596,7 +1521,6 @@ void cl_req_page_done(const struct lu_env *env, struct cl_page *page)
list_del_init(&page->cp_flight);
--req->crq_nrpages;
page->cp_req = NULL;
- EXIT;
}
EXPORT_SYMBOL(cl_req_page_done);
@@ -1610,7 +1534,6 @@ int cl_req_prep(const struct lu_env *env, struct cl_req *req)
int result;
const struct cl_req_slice *slice;
- ENTRY;
/*
* Check that the caller of cl_req_alloc() didn't lie about the number
* of objects.
@@ -1626,7 +1549,7 @@ int cl_req_prep(const struct lu_env *env, struct cl_req *req)
break;
}
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_req_prep);
@@ -1643,7 +1566,6 @@ void cl_req_attr_set(const struct lu_env *env, struct cl_req *req,
int i;
LASSERT(!list_empty(&req->crq_pages));
- ENTRY;
/* Take any page to use as a model. */
page = list_entry(req->crq_pages.next, struct cl_page, cp_flight);
@@ -1662,7 +1584,6 @@ void cl_req_attr_set(const struct lu_env *env, struct cl_req *req,
attr + i, flags);
}
}
- EXIT;
}
EXPORT_SYMBOL(cl_req_attr_set);
@@ -1675,12 +1596,10 @@ EXPORT_SYMBOL(cl_req_attr_set);
*/
void cl_sync_io_init(struct cl_sync_io *anchor, int nrpages)
{
- ENTRY;
init_waitqueue_head(&anchor->csi_waitq);
atomic_set(&anchor->csi_sync_nr, nrpages);
atomic_set(&anchor->csi_barrier, nrpages > 0);
anchor->csi_sync_rc = 0;
- EXIT;
}
EXPORT_SYMBOL(cl_sync_io_init);
@@ -1695,7 +1614,6 @@ int cl_sync_io_wait(const struct lu_env *env, struct cl_io *io,
struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(timeout),
NULL, NULL, NULL);
int rc;
- ENTRY;
LASSERT(timeout >= 0);
@@ -1725,7 +1643,7 @@ int cl_sync_io_wait(const struct lu_env *env, struct cl_io *io,
}
POISON(anchor, 0x5a, sizeof *anchor);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(cl_sync_io_wait);
@@ -1734,7 +1652,6 @@ EXPORT_SYMBOL(cl_sync_io_wait);
*/
void cl_sync_io_note(struct cl_sync_io *anchor, int ioret)
{
- ENTRY;
if (anchor->csi_sync_rc == 0 && ioret < 0)
anchor->csi_sync_rc = ioret;
/*
@@ -1748,6 +1665,5 @@ void cl_sync_io_note(struct cl_sync_io *anchor, int ioret)
/* it's safe to nuke or reuse anchor now */
atomic_set(&anchor->csi_barrier, 0);
}
- EXIT;
}
EXPORT_SYMBOL(cl_sync_io_note);
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c
index d34e044fc85..749eb082f97 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_lock.c
@@ -191,12 +191,10 @@ void cl_lock_slice_add(struct cl_lock *lock, struct cl_lock_slice *slice,
struct cl_object *obj,
const struct cl_lock_operations *ops)
{
- ENTRY;
slice->cls_lock = lock;
list_add_tail(&slice->cls_linkage, &lock->cll_layers);
slice->cls_obj = obj;
slice->cls_ops = ops;
- EXIT;
}
EXPORT_SYMBOL(cl_lock_slice_add);
@@ -254,7 +252,6 @@ static void cl_lock_free(const struct lu_env *env, struct cl_lock *lock)
LINVRNT(!cl_lock_is_mutexed(lock));
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "free lock", lock);
might_sleep();
while (!list_empty(&lock->cll_layers)) {
@@ -267,13 +264,12 @@ static void cl_lock_free(const struct lu_env *env, struct cl_lock *lock)
}
CS_LOCK_DEC(obj, total);
CS_LOCKSTATE_DEC(obj, lock->cll_state);
- lu_object_ref_del_at(&obj->co_lu, lock->cll_obj_ref, "cl_lock", lock);
+ lu_object_ref_del_at(&obj->co_lu, &lock->cll_obj_ref, "cl_lock", lock);
cl_object_put(env, obj);
lu_ref_fini(&lock->cll_reference);
lu_ref_fini(&lock->cll_holders);
mutex_destroy(&lock->cll_guard);
OBD_SLAB_FREE_PTR(lock, cl_lock_kmem);
- EXIT;
}
/**
@@ -290,7 +286,6 @@ void cl_lock_put(const struct lu_env *env, struct cl_lock *lock)
struct cl_object *obj;
LINVRNT(cl_lock_invariant(env, lock));
- ENTRY;
obj = lock->cll_descr.cld_obj;
LINVRNT(obj != NULL);
@@ -304,7 +299,6 @@ void cl_lock_put(const struct lu_env *env, struct cl_lock *lock)
}
CS_LOCK_DEC(obj, busy);
}
- EXIT;
}
EXPORT_SYMBOL(cl_lock_put);
@@ -366,15 +360,14 @@ static struct cl_lock *cl_lock_alloc(const struct lu_env *env,
struct cl_lock *lock;
struct lu_object_header *head;
- ENTRY;
OBD_SLAB_ALLOC_PTR_GFP(lock, cl_lock_kmem, __GFP_IO);
if (lock != NULL) {
atomic_set(&lock->cll_ref, 1);
lock->cll_descr = *descr;
lock->cll_state = CLS_NEW;
cl_object_get(obj);
- lock->cll_obj_ref = lu_object_ref_add(&obj->co_lu,
- "cl_lock", lock);
+ lu_object_ref_add_at(&obj->co_lu, &lock->cll_obj_ref, "cl_lock",
+ lock);
INIT_LIST_HEAD(&lock->cll_layers);
INIT_LIST_HEAD(&lock->cll_linkage);
INIT_LIST_HEAD(&lock->cll_inclosure);
@@ -401,7 +394,7 @@ static struct cl_lock *cl_lock_alloc(const struct lu_env *env,
}
} else
lock = ERR_PTR(-ENOMEM);
- RETURN(lock);
+ return lock;
}
/**
@@ -468,13 +461,12 @@ static int cl_lock_fits_into(const struct lu_env *env,
const struct cl_lock_slice *slice;
LINVRNT(cl_lock_invariant_trusted(env, lock));
- ENTRY;
list_for_each_entry(slice, &lock->cll_layers, cls_linkage) {
if (slice->cls_ops->clo_fits_into != NULL &&
!slice->cls_ops->clo_fits_into(env, slice, need, io))
- RETURN(0);
+ return 0;
}
- RETURN(1);
+ return 1;
}
static struct cl_lock *cl_lock_lookup(const struct lu_env *env,
@@ -485,8 +477,6 @@ static struct cl_lock *cl_lock_lookup(const struct lu_env *env,
struct cl_lock *lock;
struct cl_object_header *head;
- ENTRY;
-
head = cl_object_header(obj);
LINVRNT(spin_is_locked(&head->coh_lock_guard));
CS_LOCK_INC(obj, lookup);
@@ -504,10 +494,10 @@ static struct cl_lock *cl_lock_lookup(const struct lu_env *env,
if (matched) {
cl_lock_get_trust(lock);
CS_LOCK_INC(obj, hit);
- RETURN(lock);
+ return lock;
}
}
- RETURN(NULL);
+ return NULL;
}
/**
@@ -528,8 +518,6 @@ static struct cl_lock *cl_lock_find(const struct lu_env *env,
struct cl_object *obj;
struct cl_lock *lock;
- ENTRY;
-
obj = need->cld_obj;
head = cl_object_header(obj);
@@ -561,7 +549,7 @@ static struct cl_lock *cl_lock_find(const struct lu_env *env,
}
}
}
- RETURN(lock);
+ return lock;
}
/**
@@ -630,13 +618,12 @@ const struct cl_lock_slice *cl_lock_at(const struct cl_lock *lock,
const struct cl_lock_slice *slice;
LINVRNT(cl_lock_invariant_trusted(NULL, lock));
- ENTRY;
list_for_each_entry(slice, &lock->cll_layers, cls_linkage) {
if (slice->cls_obj->co_lu.lo_dev->ld_type == dtype)
- RETURN(slice);
+ return slice;
}
- RETURN(NULL);
+ return NULL;
}
EXPORT_SYMBOL(cl_lock_at);
@@ -705,7 +692,6 @@ int cl_lock_mutex_try(const struct lu_env *env, struct cl_lock *lock)
int result;
LINVRNT(cl_lock_invariant_trusted(env, lock));
- ENTRY;
result = 0;
if (lock->cll_guarder == current) {
@@ -717,7 +703,7 @@ int cl_lock_mutex_try(const struct lu_env *env, struct cl_lock *lock)
cl_lock_mutex_tail(env, lock);
} else
result = -EBUSY;
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_lock_mutex_try);
@@ -784,7 +770,6 @@ static void cl_lock_cancel0(const struct lu_env *env, struct cl_lock *lock)
{
LINVRNT(cl_lock_is_mutexed(lock));
LINVRNT(cl_lock_invariant(env, lock));
- ENTRY;
if (!(lock->cll_flags & CLF_CANCELLED)) {
const struct cl_lock_slice *slice;
@@ -795,7 +780,6 @@ static void cl_lock_cancel0(const struct lu_env *env, struct cl_lock *lock)
slice->cls_ops->clo_cancel(env, slice);
}
}
- EXIT;
}
static void cl_lock_delete0(const struct lu_env *env, struct cl_lock *lock)
@@ -806,7 +790,6 @@ static void cl_lock_delete0(const struct lu_env *env, struct cl_lock *lock)
LINVRNT(cl_lock_is_mutexed(lock));
LINVRNT(cl_lock_invariant(env, lock));
- ENTRY;
if (lock->cll_state < CLS_FREEING) {
LASSERT(lock->cll_state != CLS_INTRANSIT);
cl_lock_state_set(env, lock, CLS_FREEING);
@@ -836,7 +819,6 @@ static void cl_lock_delete0(const struct lu_env *env, struct cl_lock *lock)
* existing references goes away.
*/
}
- EXIT;
}
/**
@@ -886,7 +868,6 @@ void cl_lock_hold_release(const struct lu_env *env, struct cl_lock *lock,
LINVRNT(cl_lock_invariant(env, lock));
LASSERT(lock->cll_holds > 0);
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "hold release lock", lock);
lu_ref_del(&lock->cll_holders, scope, source);
cl_lock_hold_mod(env, lock, -1);
@@ -910,7 +891,6 @@ void cl_lock_hold_release(const struct lu_env *env, struct cl_lock *lock,
cl_lock_delete0(env, lock);
}
}
- EXIT;
}
EXPORT_SYMBOL(cl_lock_hold_release);
@@ -939,7 +919,6 @@ int cl_lock_state_wait(const struct lu_env *env, struct cl_lock *lock)
sigset_t blocked;
int result;
- ENTRY;
LINVRNT(cl_lock_is_mutexed(lock));
LINVRNT(cl_lock_invariant(env, lock));
LASSERT(lock->cll_depth == 1);
@@ -976,7 +955,7 @@ int cl_lock_state_wait(const struct lu_env *env, struct cl_lock *lock)
/* Restore old blocked signals */
cfs_restore_sigs(blocked);
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_lock_state_wait);
@@ -985,7 +964,6 @@ static void cl_lock_state_signal(const struct lu_env *env, struct cl_lock *lock,
{
const struct cl_lock_slice *slice;
- ENTRY;
LINVRNT(cl_lock_is_mutexed(lock));
LINVRNT(cl_lock_invariant(env, lock));
@@ -993,7 +971,6 @@ static void cl_lock_state_signal(const struct lu_env *env, struct cl_lock *lock,
if (slice->cls_ops->clo_state != NULL)
slice->cls_ops->clo_state(env, slice, state);
wake_up_all(&lock->cll_wq);
- EXIT;
}
/**
@@ -1005,10 +982,8 @@ static void cl_lock_state_signal(const struct lu_env *env, struct cl_lock *lock,
*/
void cl_lock_signal(const struct lu_env *env, struct cl_lock *lock)
{
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "state signal lock", lock);
cl_lock_state_signal(env, lock, lock->cll_state);
- EXIT;
}
EXPORT_SYMBOL(cl_lock_signal);
@@ -1025,7 +1000,6 @@ EXPORT_SYMBOL(cl_lock_signal);
void cl_lock_state_set(const struct lu_env *env, struct cl_lock *lock,
enum cl_lock_state state)
{
- ENTRY;
LASSERT(lock->cll_state <= state ||
(lock->cll_state == CLS_CACHED &&
(state == CLS_HELD || /* lock found in cache */
@@ -1041,7 +1015,6 @@ void cl_lock_state_set(const struct lu_env *env, struct cl_lock *lock,
cl_lock_state_signal(env, lock, state);
lock->cll_state = state;
}
- EXIT;
}
EXPORT_SYMBOL(cl_lock_state_set);
@@ -1084,12 +1057,11 @@ int cl_use_try(const struct lu_env *env, struct cl_lock *lock, int atomic)
int result;
enum cl_lock_state state;
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "use lock", lock);
LASSERT(lock->cll_state == CLS_CACHED);
if (lock->cll_error)
- RETURN(lock->cll_error);
+ return lock->cll_error;
result = -ENOSYS;
state = cl_lock_intransit(env, lock);
@@ -1129,7 +1101,7 @@ int cl_use_try(const struct lu_env *env, struct cl_lock *lock, int atomic)
}
cl_lock_extransit(env, lock, state);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_use_try);
@@ -1144,7 +1116,6 @@ static int cl_enqueue_kick(const struct lu_env *env,
int result;
const struct cl_lock_slice *slice;
- ENTRY;
result = -ENOSYS;
list_for_each_entry(slice, &lock->cll_layers, cls_linkage) {
if (slice->cls_ops->clo_enqueue != NULL) {
@@ -1155,7 +1126,7 @@ static int cl_enqueue_kick(const struct lu_env *env,
}
}
LASSERT(result != -ENOSYS);
- RETURN(result);
+ return result;
}
/**
@@ -1176,7 +1147,6 @@ int cl_enqueue_try(const struct lu_env *env, struct cl_lock *lock,
{
int result;
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "enqueue lock", lock);
do {
LINVRNT(cl_lock_is_mutexed(lock));
@@ -1219,7 +1189,7 @@ int cl_enqueue_try(const struct lu_env *env, struct cl_lock *lock,
LBUG();
}
} while (result == CLO_REPEAT);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_enqueue_try);
@@ -1235,7 +1205,6 @@ int cl_lock_enqueue_wait(const struct lu_env *env,
{
struct cl_lock *conflict;
int rc = 0;
- ENTRY;
LASSERT(cl_lock_is_mutexed(lock));
LASSERT(lock->cll_state == CLS_QUEUING);
@@ -1265,7 +1234,7 @@ int cl_lock_enqueue_wait(const struct lu_env *env,
cl_lock_mutex_get(env, lock);
LASSERT(rc <= 0);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(cl_lock_enqueue_wait);
@@ -1274,8 +1243,6 @@ static int cl_enqueue_locked(const struct lu_env *env, struct cl_lock *lock,
{
int result;
- ENTRY;
-
LINVRNT(cl_lock_is_mutexed(lock));
LINVRNT(cl_lock_invariant(env, lock));
LASSERT(lock->cll_holds > 0);
@@ -1298,7 +1265,7 @@ static int cl_enqueue_locked(const struct lu_env *env, struct cl_lock *lock,
LASSERT(ergo(result == 0 && !(enqflags & CEF_AGL),
lock->cll_state == CLS_ENQUEUED ||
lock->cll_state == CLS_HELD));
- RETURN(result);
+ return result;
}
/**
@@ -1315,8 +1282,6 @@ int cl_enqueue(const struct lu_env *env, struct cl_lock *lock,
{
int result;
- ENTRY;
-
cl_lock_lockdep_acquire(env, lock, enqflags);
cl_lock_mutex_get(env, lock);
result = cl_enqueue_locked(env, lock, io, enqflags);
@@ -1325,7 +1290,7 @@ int cl_enqueue(const struct lu_env *env, struct cl_lock *lock,
cl_lock_lockdep_release(env, lock);
LASSERT(ergo(result == 0, lock->cll_state == CLS_ENQUEUED ||
lock->cll_state == CLS_HELD));
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_enqueue);
@@ -1346,19 +1311,18 @@ int cl_unuse_try(const struct lu_env *env, struct cl_lock *lock)
int result;
enum cl_lock_state state = CLS_NEW;
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "unuse lock", lock);
if (lock->cll_users > 1) {
cl_lock_user_del(env, lock);
- RETURN(0);
+ return 0;
}
/* Only if the lock is in CLS_HELD or CLS_ENQUEUED state, it can hold
* underlying resources. */
if (!(lock->cll_state == CLS_HELD || lock->cll_state == CLS_ENQUEUED)) {
cl_lock_user_del(env, lock);
- RETURN(0);
+ return 0;
}
/*
@@ -1404,20 +1368,17 @@ int cl_unuse_try(const struct lu_env *env, struct cl_lock *lock)
state = CLS_NEW;
cl_lock_extransit(env, lock, state);
}
- RETURN(result ?: lock->cll_error);
+ return result ?: lock->cll_error;
}
EXPORT_SYMBOL(cl_unuse_try);
static void cl_unuse_locked(const struct lu_env *env, struct cl_lock *lock)
{
int result;
- ENTRY;
result = cl_unuse_try(env, lock);
if (result)
CL_LOCK_DEBUG(D_ERROR, env, lock, "unuse return %d\n", result);
-
- EXIT;
}
/**
@@ -1425,12 +1386,10 @@ static void cl_unuse_locked(const struct lu_env *env, struct cl_lock *lock)
*/
void cl_unuse(const struct lu_env *env, struct cl_lock *lock)
{
- ENTRY;
cl_lock_mutex_get(env, lock);
cl_unuse_locked(env, lock);
cl_lock_mutex_put(env, lock);
cl_lock_lockdep_release(env, lock);
- EXIT;
}
EXPORT_SYMBOL(cl_unuse);
@@ -1449,7 +1408,6 @@ int cl_wait_try(const struct lu_env *env, struct cl_lock *lock)
const struct cl_lock_slice *slice;
int result;
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "wait lock try", lock);
do {
LINVRNT(cl_lock_is_mutexed(lock));
@@ -1489,7 +1447,7 @@ int cl_wait_try(const struct lu_env *env, struct cl_lock *lock)
cl_lock_state_set(env, lock, CLS_HELD);
}
} while (result == CLO_REPEAT);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_wait_try);
@@ -1506,7 +1464,6 @@ int cl_wait(const struct lu_env *env, struct cl_lock *lock)
{
int result;
- ENTRY;
cl_lock_mutex_get(env, lock);
LINVRNT(cl_lock_invariant(env, lock));
@@ -1530,7 +1487,7 @@ int cl_wait(const struct lu_env *env, struct cl_lock *lock)
cl_lock_trace(D_DLMTRACE, env, "wait lock", lock);
cl_lock_mutex_put(env, lock);
LASSERT(ergo(result == 0, lock->cll_state == CLS_HELD));
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_wait);
@@ -1544,7 +1501,6 @@ unsigned long cl_lock_weigh(const struct lu_env *env, struct cl_lock *lock)
unsigned long pound;
unsigned long ounce;
- ENTRY;
LINVRNT(cl_lock_is_mutexed(lock));
LINVRNT(cl_lock_invariant(env, lock));
@@ -1557,7 +1513,7 @@ unsigned long cl_lock_weigh(const struct lu_env *env, struct cl_lock *lock)
pound = ~0UL;
}
}
- RETURN(pound);
+ return pound;
}
EXPORT_SYMBOL(cl_lock_weigh);
@@ -1579,7 +1535,6 @@ int cl_lock_modify(const struct lu_env *env, struct cl_lock *lock,
struct cl_object_header *hdr = cl_object_header(obj);
int result;
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "modify lock", lock);
/* don't allow object to change */
LASSERT(obj == desc->cld_obj);
@@ -1590,7 +1545,7 @@ int cl_lock_modify(const struct lu_env *env, struct cl_lock *lock,
if (slice->cls_ops->clo_modify != NULL) {
result = slice->cls_ops->clo_modify(env, slice, desc);
if (result != 0)
- RETURN(result);
+ return result;
}
}
CL_LOCK_DEBUG(D_DLMTRACE, env, lock, " -> "DDESCR"@"DFID"\n",
@@ -1603,7 +1558,7 @@ int cl_lock_modify(const struct lu_env *env, struct cl_lock *lock,
spin_lock(&hdr->coh_lock_guard);
lock->cll_descr = *desc;
spin_unlock(&hdr->coh_lock_guard);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(cl_lock_modify);
@@ -1642,7 +1597,6 @@ int cl_lock_closure_build(const struct lu_env *env, struct cl_lock *lock,
const struct cl_lock_slice *slice;
int result;
- ENTRY;
LINVRNT(cl_lock_is_mutexed(closure->clc_origin));
LINVRNT(cl_lock_invariant(env, closure->clc_origin));
@@ -1659,7 +1613,7 @@ int cl_lock_closure_build(const struct lu_env *env, struct cl_lock *lock,
}
if (result != 0)
cl_lock_disclosure(env, closure);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_lock_closure_build);
@@ -1674,7 +1628,7 @@ int cl_lock_enclosure(const struct lu_env *env, struct cl_lock *lock,
struct cl_lock_closure *closure)
{
int result = 0;
- ENTRY;
+
cl_lock_trace(D_DLMTRACE, env, "enclosure lock", lock);
if (!cl_lock_mutex_try(env, lock)) {
/*
@@ -1706,7 +1660,7 @@ int cl_lock_enclosure(const struct lu_env *env, struct cl_lock *lock,
}
result = CLO_REPEAT;
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_lock_enclosure);
@@ -1766,13 +1720,11 @@ void cl_lock_delete(const struct lu_env *env, struct cl_lock *lock)
LASSERT(ergo(cl_lock_nesting(lock) == CNL_TOP,
cl_lock_nr_mutexed(env) == 1));
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "delete lock", lock);
if (lock->cll_holds == 0)
cl_lock_delete0(env, lock);
else
lock->cll_flags |= CLF_DOOMED;
- EXIT;
}
EXPORT_SYMBOL(cl_lock_delete);
@@ -1791,7 +1743,6 @@ void cl_lock_error(const struct lu_env *env, struct cl_lock *lock, int error)
LINVRNT(cl_lock_is_mutexed(lock));
LINVRNT(cl_lock_invariant(env, lock));
- ENTRY;
if (lock->cll_error == 0 && error != 0) {
cl_lock_trace(D_DLMTRACE, env, "set lock error", lock);
lock->cll_error = error;
@@ -1799,7 +1750,6 @@ void cl_lock_error(const struct lu_env *env, struct cl_lock *lock, int error)
cl_lock_cancel(env, lock);
cl_lock_delete(env, lock);
}
- EXIT;
}
EXPORT_SYMBOL(cl_lock_error);
@@ -1819,13 +1769,11 @@ void cl_lock_cancel(const struct lu_env *env, struct cl_lock *lock)
LINVRNT(cl_lock_is_mutexed(lock));
LINVRNT(cl_lock_invariant(env, lock));
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "cancel lock", lock);
if (lock->cll_holds == 0)
cl_lock_cancel0(env, lock);
else
lock->cll_flags |= CLF_CANCELPEND;
- EXIT;
}
EXPORT_SYMBOL(cl_lock_cancel);
@@ -1843,8 +1791,6 @@ struct cl_lock *cl_lock_at_pgoff(const struct lu_env *env,
struct cl_lock *lock;
struct cl_lock_descr *need;
- ENTRY;
-
head = cl_object_header(obj);
need = &cl_env_info(env)->clt_descr;
lock = NULL;
@@ -1878,7 +1824,7 @@ struct cl_lock *cl_lock_at_pgoff(const struct lu_env *env,
}
}
spin_unlock(&head->coh_lock_guard);
- RETURN(lock);
+ return lock;
}
EXPORT_SYMBOL(cl_lock_at_pgoff);
@@ -1979,7 +1925,6 @@ int cl_lock_discard_pages(const struct lu_env *env, struct cl_lock *lock)
int result;
LINVRNT(cl_lock_invariant(env, lock));
- ENTRY;
io->ci_obj = cl_object_top(descr->cld_obj);
io->ci_ignore_layout = 1;
@@ -2001,7 +1946,7 @@ int cl_lock_discard_pages(const struct lu_env *env, struct cl_lock *lock)
} while (res != CLP_GANG_OKAY);
out:
cl_io_fini(env, io);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_lock_discard_pages);
@@ -2018,7 +1963,6 @@ void cl_locks_prune(const struct lu_env *env, struct cl_object *obj, int cancel)
struct cl_object_header *head;
struct cl_lock *lock;
- ENTRY;
head = cl_object_header(obj);
/*
* If locks are destroyed without cancellation, all pages must be
@@ -2059,7 +2003,6 @@ again:
spin_lock(&head->coh_lock_guard);
}
spin_unlock(&head->coh_lock_guard);
- EXIT;
}
EXPORT_SYMBOL(cl_locks_prune);
@@ -2070,8 +2013,6 @@ static struct cl_lock *cl_lock_hold_mutex(const struct lu_env *env,
{
struct cl_lock *lock;
- ENTRY;
-
while (1) {
lock = cl_lock_find(env, io, need);
if (IS_ERR(lock))
@@ -2087,7 +2028,7 @@ static struct cl_lock *cl_lock_hold_mutex(const struct lu_env *env,
cl_lock_mutex_put(env, lock);
cl_lock_put(env, lock);
}
- RETURN(lock);
+ return lock;
}
/**
@@ -2103,12 +2044,10 @@ struct cl_lock *cl_lock_hold(const struct lu_env *env, const struct cl_io *io,
{
struct cl_lock *lock;
- ENTRY;
-
lock = cl_lock_hold_mutex(env, io, need, scope, source);
if (!IS_ERR(lock))
cl_lock_mutex_put(env, lock);
- RETURN(lock);
+ return lock;
}
EXPORT_SYMBOL(cl_lock_hold);
@@ -2124,7 +2063,6 @@ struct cl_lock *cl_lock_request(const struct lu_env *env, struct cl_io *io,
int rc;
__u32 enqflags = need->cld_enq_flags;
- ENTRY;
do {
lock = cl_lock_hold_mutex(env, io, need, scope, source);
if (IS_ERR(lock))
@@ -2156,7 +2094,7 @@ struct cl_lock *cl_lock_request(const struct lu_env *env, struct cl_io *io,
lock = ERR_PTR(rc);
}
} while (rc == 0);
- RETURN(lock);
+ return lock;
}
EXPORT_SYMBOL(cl_lock_request);
@@ -2170,12 +2108,10 @@ void cl_lock_hold_add(const struct lu_env *env, struct cl_lock *lock,
LINVRNT(cl_lock_invariant(env, lock));
LASSERT(lock->cll_state != CLS_FREEING);
- ENTRY;
cl_lock_hold_mod(env, lock, +1);
cl_lock_get(lock);
lu_ref_add(&lock->cll_holders, scope, source);
lu_ref_add(&lock->cll_reference, scope, source);
- EXIT;
}
EXPORT_SYMBOL(cl_lock_hold_add);
@@ -2187,11 +2123,9 @@ void cl_lock_unhold(const struct lu_env *env, struct cl_lock *lock,
const char *scope, const void *source)
{
LINVRNT(cl_lock_invariant(env, lock));
- ENTRY;
cl_lock_hold_release(env, lock, scope, source);
lu_ref_del(&lock->cll_reference, scope, source);
cl_lock_put(env, lock);
- EXIT;
}
EXPORT_SYMBOL(cl_lock_unhold);
@@ -2202,14 +2136,12 @@ void cl_lock_release(const struct lu_env *env, struct cl_lock *lock,
const char *scope, const void *source)
{
LINVRNT(cl_lock_invariant(env, lock));
- ENTRY;
cl_lock_trace(D_DLMTRACE, env, "release lock", lock);
cl_lock_mutex_get(env, lock);
cl_lock_hold_release(env, lock, scope, source);
cl_lock_mutex_put(env, lock);
lu_ref_del(&lock->cll_reference, scope, source);
cl_lock_put(env, lock);
- EXIT;
}
EXPORT_SYMBOL(cl_lock_release);
@@ -2218,9 +2150,7 @@ void cl_lock_user_add(const struct lu_env *env, struct cl_lock *lock)
LINVRNT(cl_lock_is_mutexed(lock));
LINVRNT(cl_lock_invariant(env, lock));
- ENTRY;
cl_lock_used_mod(env, lock, +1);
- EXIT;
}
EXPORT_SYMBOL(cl_lock_user_add);
@@ -2230,11 +2160,9 @@ void cl_lock_user_del(const struct lu_env *env, struct cl_lock *lock)
LINVRNT(cl_lock_invariant(env, lock));
LASSERT(lock->cll_users > 0);
- ENTRY;
cl_lock_used_mod(env, lock, -1);
if (lock->cll_users == 0)
wake_up_all(&lock->cll_wq);
- EXIT;
}
EXPORT_SYMBOL(cl_lock_user_del);
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c
index cdb5fba0459..7b0e9d26b6c 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c
@@ -79,7 +79,6 @@ int cl_object_header_init(struct cl_object_header *h)
{
int result;
- ENTRY;
result = lu_object_header_init(&h->coh_lu);
if (result == 0) {
spin_lock_init(&h->coh_page_guard);
@@ -94,7 +93,7 @@ int cl_object_header_init(struct cl_object_header *h)
INIT_LIST_HEAD(&h->coh_locks);
h->coh_page_bufsize = ALIGN(sizeof(struct cl_page), 8);
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_object_header_init);
@@ -222,7 +221,6 @@ int cl_object_attr_get(const struct lu_env *env, struct cl_object *obj,
int result;
LASSERT(spin_is_locked(cl_object_attr_guard(obj)));
- ENTRY;
top = obj->co_lu.lo_header;
result = 0;
@@ -236,7 +234,7 @@ int cl_object_attr_get(const struct lu_env *env, struct cl_object *obj,
}
}
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_object_attr_get);
@@ -254,7 +252,6 @@ int cl_object_attr_set(const struct lu_env *env, struct cl_object *obj,
int result;
LASSERT(spin_is_locked(cl_object_attr_guard(obj)));
- ENTRY;
top = obj->co_lu.lo_header;
result = 0;
@@ -269,7 +266,7 @@ int cl_object_attr_set(const struct lu_env *env, struct cl_object *obj,
}
}
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_object_attr_set);
@@ -287,7 +284,6 @@ int cl_object_glimpse(const struct lu_env *env, struct cl_object *obj,
struct lu_object_header *top;
int result;
- ENTRY;
top = obj->co_lu.lo_header;
result = 0;
list_for_each_entry_reverse(obj, &top->loh_layers,
@@ -303,7 +299,7 @@ int cl_object_glimpse(const struct lu_env *env, struct cl_object *obj,
"ctime: "LPU64" blocks: "LPU64"\n",
lvb->lvb_size, lvb->lvb_mtime, lvb->lvb_atime,
lvb->lvb_ctime, lvb->lvb_blocks);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_object_glimpse);
@@ -316,7 +312,6 @@ int cl_conf_set(const struct lu_env *env, struct cl_object *obj,
struct lu_object_header *top;
int result;
- ENTRY;
top = obj->co_lu.lo_header;
result = 0;
list_for_each_entry(obj, &top->loh_layers, co_lu.lo_linkage) {
@@ -326,7 +321,7 @@ int cl_conf_set(const struct lu_env *env, struct cl_object *obj,
break;
}
}
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_conf_set);
@@ -362,10 +357,8 @@ EXPORT_SYMBOL(cl_object_kill);
*/
void cl_object_prune(const struct lu_env *env, struct cl_object *obj)
{
- ENTRY;
cl_pages_prune(env, obj);
cl_locks_prune(env, obj, 1);
- EXIT;
}
EXPORT_SYMBOL(cl_object_prune);
@@ -941,13 +934,11 @@ EXPORT_SYMBOL(cl_env_nested_put);
*/
void cl_attr2lvb(struct ost_lvb *lvb, const struct cl_attr *attr)
{
- ENTRY;
lvb->lvb_size = attr->cat_size;
lvb->lvb_mtime = attr->cat_mtime;
lvb->lvb_atime = attr->cat_atime;
lvb->lvb_ctime = attr->cat_ctime;
lvb->lvb_blocks = attr->cat_blocks;
- EXIT;
}
EXPORT_SYMBOL(cl_attr2lvb);
@@ -958,13 +949,11 @@ EXPORT_SYMBOL(cl_attr2lvb);
*/
void cl_lvb2attr(struct cl_attr *attr, const struct ost_lvb *lvb)
{
- ENTRY;
attr->cat_size = lvb->lvb_size;
attr->cat_mtime = lvb->lvb_mtime;
attr->cat_atime = lvb->lvb_atime;
attr->cat_ctime = lvb->lvb_ctime;
attr->cat_blocks = lvb->lvb_blocks;
- EXIT;
}
EXPORT_SYMBOL(cl_lvb2attr);
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c
index bb9335911c3..2a5ce376e57 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_page.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c
@@ -108,17 +108,16 @@ cl_page_at_trusted(const struct cl_page *page,
const struct lu_device_type *dtype)
{
const struct cl_page_slice *slice;
- ENTRY;
page = cl_page_top_trusted((struct cl_page *)page);
do {
list_for_each_entry(slice, &page->cp_layers, cpl_linkage) {
if (slice->cpl_obj->co_lu.lo_dev->ld_type == dtype)
- RETURN(slice);
+ return slice;
}
page = page->cp_child;
} while (page != NULL);
- RETURN(NULL);
+ return NULL;
}
/**
@@ -167,7 +166,6 @@ int cl_page_gang_lookup(const struct lu_env *env, struct cl_object *obj,
unsigned int j;
int res = CLP_GANG_OKAY;
int tree_lock = 1;
- ENTRY;
idx = start;
hdr = cl_object_header(obj);
@@ -243,7 +241,7 @@ int cl_page_gang_lookup(const struct lu_env *env, struct cl_object *obj,
}
if (tree_lock)
spin_unlock(&hdr->coh_page_guard);
- RETURN(res);
+ return res;
}
EXPORT_SYMBOL(cl_page_gang_lookup);
@@ -258,7 +256,6 @@ static void cl_page_free(const struct lu_env *env, struct cl_page *page)
PASSERT(env, page, page->cp_parent == NULL);
PASSERT(env, page, page->cp_state == CPS_FREEING);
- ENTRY;
might_sleep();
while (!list_empty(&page->cp_layers)) {
struct cl_page_slice *slice;
@@ -270,11 +267,10 @@ static void cl_page_free(const struct lu_env *env, struct cl_page *page)
}
CS_PAGE_DEC(obj, total);
CS_PAGESTATE_DEC(obj, page->cp_state);
- lu_object_ref_del_at(&obj->co_lu, page->cp_obj_ref, "cl_page", page);
+ lu_object_ref_del_at(&obj->co_lu, &page->cp_obj_ref, "cl_page", page);
cl_object_put(env, obj);
lu_ref_fini(&page->cp_reference);
OBD_FREE(page, pagesize);
- EXIT;
}
/**
@@ -295,7 +291,6 @@ static struct cl_page *cl_page_alloc(const struct lu_env *env,
struct cl_page *page;
struct lu_object_header *head;
- ENTRY;
OBD_ALLOC_GFP(page, cl_object_header(o)->coh_page_bufsize,
__GFP_IO);
if (page != NULL) {
@@ -305,7 +300,8 @@ static struct cl_page *cl_page_alloc(const struct lu_env *env,
atomic_inc(&page->cp_ref);
page->cp_obj = o;
cl_object_get(o);
- page->cp_obj_ref = lu_object_ref_add(&o->co_lu, "cl_page",page);
+ lu_object_ref_add_at(&o->co_lu, &page->cp_obj_ref, "cl_page",
+ page);
page->cp_index = ind;
cl_page_state_set_trust(page, CPS_CACHED);
page->cp_type = type;
@@ -336,7 +332,7 @@ static struct cl_page *cl_page_alloc(const struct lu_env *env,
} else {
page = ERR_PTR(-ENOMEM);
}
- RETURN(page);
+ return page;
}
/**
@@ -364,8 +360,6 @@ static struct cl_page *cl_page_find0(const struct lu_env *env,
LASSERT(type == CPT_CACHEABLE || type == CPT_TRANSIENT);
might_sleep();
- ENTRY;
-
hdr = cl_object_header(o);
CS_PAGE_INC(o, lookup);
@@ -395,13 +389,13 @@ static struct cl_page *cl_page_find0(const struct lu_env *env,
if (page != NULL) {
CS_PAGE_INC(o, hit);
- RETURN(page);
+ return page;
}
/* allocate and initialize cl_page */
page = cl_page_alloc(env, o, idx, vmpage, type);
if (IS_ERR(page))
- RETURN(page);
+ return page;
if (type == CPT_TRANSIENT) {
if (parent) {
@@ -409,7 +403,7 @@ static struct cl_page *cl_page_find0(const struct lu_env *env,
page->cp_parent = parent;
parent->cp_child = page;
}
- RETURN(page);
+ return page;
}
/*
@@ -450,7 +444,7 @@ static struct cl_page *cl_page_find0(const struct lu_env *env,
cl_page_delete0(env, ghost, 0);
cl_page_free(env, ghost);
}
- RETURN(page);
+ return page;
}
struct cl_page *cl_page_find(const struct lu_env *env, struct cl_object *o,
@@ -553,7 +547,6 @@ static void cl_page_state_set0(const struct lu_env *env,
}
};
- ENTRY;
old = page->cp_state;
PASSERT(env, page, allowed_transitions[old][state]);
CL_PAGE_HEADER(D_TRACE, env, page, "%d -> %d\n", old, state);
@@ -566,7 +559,6 @@ static void cl_page_state_set0(const struct lu_env *env,
CS_PAGESTATE_INC(page->cp_obj, state);
cl_page_state_set_trust(page, state);
}
- EXIT;
}
static void cl_page_state_set(const struct lu_env *env,
@@ -585,9 +577,7 @@ static void cl_page_state_set(const struct lu_env *env,
*/
void cl_page_get(struct cl_page *page)
{
- ENTRY;
cl_page_get_trust(page);
- EXIT;
}
EXPORT_SYMBOL(cl_page_get);
@@ -604,7 +594,6 @@ void cl_page_put(const struct lu_env *env, struct cl_page *page)
{
PASSERT(env, page, atomic_read(&page->cp_ref) > !!page->cp_parent);
- ENTRY;
CL_PAGE_HEADER(D_TRACE, env, page, "%d\n",
atomic_read(&page->cp_ref));
@@ -620,8 +609,6 @@ void cl_page_put(const struct lu_env *env, struct cl_page *page)
*/
cl_page_free(env, page);
}
-
- EXIT;
}
EXPORT_SYMBOL(cl_page_put);
@@ -640,7 +627,7 @@ struct page *cl_page_vmpage(const struct lu_env *env, struct cl_page *page)
do {
list_for_each_entry(slice, &page->cp_layers, cpl_linkage) {
if (slice->cpl_ops->cpo_vmpage != NULL)
- RETURN(slice->cpl_ops->cpo_vmpage(env, slice));
+ return slice->cpl_ops->cpo_vmpage(env, slice);
}
page = page->cp_child;
} while (page != NULL);
@@ -656,7 +643,6 @@ struct cl_page *cl_vmpage_page(struct page *vmpage, struct cl_object *obj)
struct cl_page *top;
struct cl_page *page;
- ENTRY;
KLASSERT(PageLocked(vmpage));
/*
@@ -671,7 +657,7 @@ struct cl_page *cl_vmpage_page(struct page *vmpage, struct cl_object *obj)
*/
top = (struct cl_page *)vmpage->private;
if (top == NULL)
- RETURN(NULL);
+ return NULL;
for (page = top; page != NULL; page = page->cp_child) {
if (cl_object_same(page->cp_obj, obj)) {
@@ -680,7 +666,7 @@ struct cl_page *cl_vmpage_page(struct page *vmpage, struct cl_object *obj)
}
}
LASSERT(ergo(page, page->cp_type == CPT_CACHEABLE));
- RETURN(page);
+ return page;
}
EXPORT_SYMBOL(cl_vmpage_page);
@@ -785,11 +771,10 @@ static int cl_page_invoke(const struct lu_env *env,
{
PINVRNT(env, page, cl_object_same(page->cp_obj, io->ci_obj));
- ENTRY;
- RETURN(CL_PAGE_INVOKE(env, page, op,
+ return CL_PAGE_INVOKE(env, page, op,
(const struct lu_env *,
const struct cl_page_slice *, struct cl_io *),
- io));
+ io);
}
static void cl_page_invoid(const struct lu_env *env,
@@ -797,16 +782,13 @@ static void cl_page_invoid(const struct lu_env *env,
{
PINVRNT(env, page, cl_object_same(page->cp_obj, io->ci_obj));
- ENTRY;
CL_PAGE_INVOID(env, page, op,
(const struct lu_env *,
const struct cl_page_slice *, struct cl_io *), io);
- EXIT;
}
static void cl_page_owner_clear(struct cl_page *page)
{
- ENTRY;
for (page = cl_page_top(page); page != NULL; page = page->cp_child) {
if (page->cp_owner != NULL) {
LASSERT(page->cp_owner->ci_owned_nr > 0);
@@ -815,17 +797,14 @@ static void cl_page_owner_clear(struct cl_page *page)
page->cp_task = NULL;
}
}
- EXIT;
}
static void cl_page_owner_set(struct cl_page *page)
{
- ENTRY;
for (page = cl_page_top(page); page != NULL; page = page->cp_child) {
LASSERT(page->cp_owner != NULL);
page->cp_owner->ci_owned_nr++;
}
- EXIT;
}
void cl_page_disown0(const struct lu_env *env,
@@ -833,7 +812,6 @@ void cl_page_disown0(const struct lu_env *env,
{
enum cl_page_state state;
- ENTRY;
state = pg->cp_state;
PINVRNT(env, pg, state == CPS_OWNED || state == CPS_FREEING);
PINVRNT(env, pg, cl_page_invariant(pg));
@@ -850,7 +828,6 @@ void cl_page_disown0(const struct lu_env *env,
(const struct lu_env *,
const struct cl_page_slice *, struct cl_io *),
io);
- EXIT;
}
/**
@@ -859,8 +836,7 @@ void cl_page_disown0(const struct lu_env *env,
int cl_page_is_owned(const struct cl_page *pg, const struct cl_io *io)
{
LINVRNT(cl_object_same(pg->cp_obj, io->ci_obj));
- ENTRY;
- RETURN(pg->cp_state == CPS_OWNED && pg->cp_owner == io);
+ return pg->cp_state == CPS_OWNED && pg->cp_owner == io;
}
EXPORT_SYMBOL(cl_page_is_owned);
@@ -891,7 +867,6 @@ static int cl_page_own0(const struct lu_env *env, struct cl_io *io,
PINVRNT(env, pg, !cl_page_is_owned(pg, io));
- ENTRY;
pg = cl_page_top(pg);
io = cl_io_top(io);
@@ -918,7 +893,7 @@ static int cl_page_own0(const struct lu_env *env, struct cl_io *io,
}
}
PINVRNT(env, pg, ergo(result == 0, cl_page_invariant(pg)));
- RETURN(result);
+ return result;
}
/**
@@ -960,7 +935,6 @@ void cl_page_assume(const struct lu_env *env,
{
PINVRNT(env, pg, cl_object_same(pg->cp_obj, io->ci_obj));
- ENTRY;
pg = cl_page_top(pg);
io = cl_io_top(io);
@@ -970,7 +944,6 @@ void cl_page_assume(const struct lu_env *env,
pg->cp_task = current;
cl_page_owner_set(pg);
cl_page_state_set(env, pg, CPS_OWNED);
- EXIT;
}
EXPORT_SYMBOL(cl_page_assume);
@@ -991,7 +964,6 @@ void cl_page_unassume(const struct lu_env *env,
PINVRNT(env, pg, cl_page_is_owned(pg, io));
PINVRNT(env, pg, cl_page_invariant(pg));
- ENTRY;
pg = cl_page_top(pg);
io = cl_io_top(io);
cl_page_owner_clear(pg);
@@ -1000,7 +972,6 @@ void cl_page_unassume(const struct lu_env *env,
(const struct lu_env *,
const struct cl_page_slice *, struct cl_io *),
io);
- EXIT;
}
EXPORT_SYMBOL(cl_page_unassume);
@@ -1020,11 +991,9 @@ void cl_page_disown(const struct lu_env *env,
{
PINVRNT(env, pg, cl_page_is_owned(pg, io));
- ENTRY;
pg = cl_page_top(pg);
io = cl_io_top(io);
cl_page_disown0(env, io, pg);
- EXIT;
}
EXPORT_SYMBOL(cl_page_disown);
@@ -1057,7 +1026,6 @@ static void cl_page_delete0(const struct lu_env *env, struct cl_page *pg,
int radix)
{
struct cl_page *tmp = pg;
- ENTRY;
PASSERT(env, pg, pg == cl_page_top(pg));
PASSERT(env, pg, pg->cp_state != CPS_FREEING);
@@ -1102,8 +1070,6 @@ static void cl_page_delete0(const struct lu_env *env, struct cl_page *pg,
cl_page_put(env, tmp);
}
}
-
- EXIT;
}
/**
@@ -1134,9 +1100,7 @@ static void cl_page_delete0(const struct lu_env *env, struct cl_page *pg,
void cl_page_delete(const struct lu_env *env, struct cl_page *pg)
{
PINVRNT(env, pg, cl_page_invariant(pg));
- ENTRY;
cl_page_delete0(env, pg, 1);
- EXIT;
}
EXPORT_SYMBOL(cl_page_delete);
@@ -1186,7 +1150,6 @@ int cl_page_is_vmlocked(const struct lu_env *env, const struct cl_page *pg)
int result;
const struct cl_page_slice *slice;
- ENTRY;
pg = cl_page_top_trusted((struct cl_page *)pg);
slice = container_of(pg->cp_layers.next,
const struct cl_page_slice, cpl_linkage);
@@ -1198,14 +1161,13 @@ int cl_page_is_vmlocked(const struct lu_env *env, const struct cl_page *pg)
*/
result = slice->cpl_ops->cpo_is_vmlocked(env, slice);
PASSERT(env, pg, result == -EBUSY || result == -ENODATA);
- RETURN(result == -EBUSY);
+ return result == -EBUSY;
}
EXPORT_SYMBOL(cl_page_is_vmlocked);
static enum cl_page_state cl_req_type_state(enum cl_req_type crt)
{
- ENTRY;
- RETURN(crt == CRT_WRITE ? CPS_PAGEOUT : CPS_PAGEIN);
+ return crt == CRT_WRITE ? CPS_PAGEOUT : CPS_PAGEIN;
}
static void cl_page_io_start(const struct lu_env *env,
@@ -1214,10 +1176,8 @@ static void cl_page_io_start(const struct lu_env *env,
/*
* Page is queued for IO, change its state.
*/
- ENTRY;
cl_page_owner_clear(pg);
cl_page_state_set(env, pg, cl_req_type_state(crt));
- EXIT;
}
/**
@@ -1280,7 +1240,6 @@ void cl_page_completion(const struct lu_env *env,
PASSERT(env, pg, pg->cp_req == NULL);
PASSERT(env, pg, pg->cp_state == cl_req_type_state(crt));
- ENTRY;
CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", crt, ioret);
if (crt == CRT_READ && ioret == 0) {
PASSERT(env, pg, !(pg->cp_flags & CPF_READ_COMPLETED));
@@ -1307,8 +1266,6 @@ void cl_page_completion(const struct lu_env *env,
if (anchor)
cl_sync_io_note(anchor, ioret);
-
- EXIT;
}
EXPORT_SYMBOL(cl_page_completion);
@@ -1328,9 +1285,8 @@ int cl_page_make_ready(const struct lu_env *env, struct cl_page *pg,
PINVRNT(env, pg, crt < CRT_NR);
- ENTRY;
if (crt >= CRT_NR)
- RETURN(-EINVAL);
+ return -EINVAL;
result = CL_PAGE_INVOKE(env, pg, CL_PAGE_OP(io[crt].cpo_make_ready),
(const struct lu_env *,
const struct cl_page_slice *));
@@ -1339,7 +1295,7 @@ int cl_page_make_ready(const struct lu_env *env, struct cl_page *pg,
cl_page_io_start(env, pg, crt);
}
CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", crt, result);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_page_make_ready);
@@ -1365,10 +1321,8 @@ int cl_page_cache_add(const struct lu_env *env, struct cl_io *io,
PINVRNT(env, pg, cl_page_is_owned(pg, io));
PINVRNT(env, pg, cl_page_invariant(pg));
- ENTRY;
-
if (crt >= CRT_NR)
- RETURN(-EINVAL);
+ return -EINVAL;
list_for_each_entry(scan, &pg->cp_layers, cpl_linkage) {
if (scan->cpl_ops->io[crt].cpo_cache_add == NULL)
@@ -1379,7 +1333,7 @@ int cl_page_cache_add(const struct lu_env *env, struct cl_io *io,
break;
}
CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", crt, result);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_page_cache_add);
@@ -1399,12 +1353,10 @@ int cl_page_flush(const struct lu_env *env, struct cl_io *io,
PINVRNT(env, pg, cl_page_is_owned(pg, io));
PINVRNT(env, pg, cl_page_invariant(pg));
- ENTRY;
-
result = cl_page_invoke(env, io, pg, CL_PAGE_OP(cpo_flush));
CL_PAGE_HEADER(D_TRACE, env, pg, "%d\n", result);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_page_flush);
@@ -1422,13 +1374,12 @@ int cl_page_is_under_lock(const struct lu_env *env, struct cl_io *io,
PINVRNT(env, page, cl_page_invariant(page));
- ENTRY;
rc = CL_PAGE_INVOKE(env, page, CL_PAGE_OP(cpo_is_under_lock),
(const struct lu_env *,
const struct cl_page_slice *, struct cl_io *),
io);
PASSERT(env, page, rc != 0);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(cl_page_is_under_lock);
@@ -1452,7 +1403,6 @@ int cl_pages_prune(const struct lu_env *env, struct cl_object *clobj)
struct cl_io *io;
int result;
- ENTRY;
info = cl_env_info(env);
io = &info->clt_io;
@@ -1465,7 +1415,7 @@ int cl_pages_prune(const struct lu_env *env, struct cl_object *clobj)
result = cl_io_init(env, io, CIT_MISC, obj);
if (result != 0) {
cl_io_fini(env, io);
- RETURN(io->ci_result);
+ return io->ci_result;
}
do {
@@ -1476,7 +1426,7 @@ int cl_pages_prune(const struct lu_env *env, struct cl_object *clobj)
} while (result != CLP_GANG_OKAY);
cl_io_fini(env, io);
- RETURN(result);
+ return result;
}
EXPORT_SYMBOL(cl_pages_prune);
@@ -1586,12 +1536,10 @@ void cl_page_slice_add(struct cl_page *page, struct cl_page_slice *slice,
struct cl_object *obj,
const struct cl_page_operations *ops)
{
- ENTRY;
list_add_tail(&slice->cpl_linkage, &page->cp_layers);
slice->cpl_obj = obj;
slice->cpl_ops = ops;
slice->cpl_page = page;
- EXIT;
}
EXPORT_SYMBOL(cl_page_slice_add);
diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c
index af1c2d09c47..b1024a6d37d 100644
--- a/drivers/staging/lustre/lustre/obdclass/class_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c
@@ -112,18 +112,18 @@ int lustre_get_jobid(char *jobid)
{
int jobid_len = JOBSTATS_JOBID_SIZE;
int rc = 0;
- ENTRY;
memset(jobid, 0, JOBSTATS_JOBID_SIZE);
/* Jobstats isn't enabled */
if (strcmp(obd_jobid_var, JOBSTATS_DISABLE) == 0)
- RETURN(0);
+ return 0;
/* Use process name + fsuid as jobid */
if (strcmp(obd_jobid_var, JOBSTATS_PROCNAME_UID) == 0) {
snprintf(jobid, JOBSTATS_JOBID_SIZE, "%s.%u",
- current_comm(), current_fsuid());
- RETURN(0);
+ current_comm(),
+ from_kuid(&init_user_ns, current_fsuid()));
+ return 0;
}
rc = cfs_get_environ(obd_jobid_var, jobid, &jobid_len);
@@ -150,7 +150,7 @@ int lustre_get_jobid(char *jobid)
obd_jobid_var, rc);
}
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(lustre_get_jobid);
@@ -193,7 +193,6 @@ int class_resolve_dev_name(__u32 len, const char *name)
int rc;
int dev;
- ENTRY;
if (!len || !name) {
CERROR("No name passed,!\n");
GOTO(out, rc = -EINVAL);
@@ -214,7 +213,7 @@ int class_resolve_dev_name(__u32 len, const char *name)
rc = dev;
out:
- RETURN(rc);
+ return rc;
}
int class_handle_ioctl(unsigned int cmd, unsigned long arg)
@@ -224,7 +223,6 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg)
struct libcfs_debug_ioctl_data *debug_data;
struct obd_device *obd = NULL;
int err = 0, len = 0;
- ENTRY;
/* only for debugging */
if (cmd == LIBCFS_IOC_DEBUG_MASK) {
@@ -237,7 +235,7 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg)
CDEBUG(D_IOCTL, "cmd = %x\n", cmd);
if (obd_ioctl_getdata(&buf, &len, (void *)arg)) {
CERROR("OBD ioctl: data error\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
data = (struct obd_ioctl_data *)buf;
@@ -428,10 +426,10 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg)
out:
if (buf)
obd_ioctl_freedata(buf, len);
- RETURN(err);
+ return err;
} /* class_handle_ioctl */
-extern psdev_t obd_psdev;
+extern struct miscdevice obd_psdev;
#define OBD_INIT_CHECK
int obd_init_checks(void)
@@ -524,7 +522,7 @@ static int __init init_obdclass(void)
LPROCFS_STATS_FLAG_IRQ_SAFE);
if (obd_memory == NULL) {
CERROR("kmalloc of 'obd_memory' failed\n");
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
lprocfs_counter_init(obd_memory, OBD_MEMORY_STAT,
@@ -558,10 +556,10 @@ static int __init init_obdclass(void)
/* Default the dirty page cache cap to 1/2 of system memory.
* For clients with less memory, a larger fraction is needed
* for other purposes (mostly for BGL). */
- if (num_physpages <= 512 << (20 - PAGE_CACHE_SHIFT))
- obd_max_dirty_pages = num_physpages / 4;
+ if (totalram_pages <= 512 << (20 - PAGE_CACHE_SHIFT))
+ obd_max_dirty_pages = totalram_pages / 4;
else
- obd_max_dirty_pages = num_physpages / 2;
+ obd_max_dirty_pages = totalram_pages / 2;
err = obd_init_caches();
if (err)
@@ -638,7 +636,6 @@ static void cleanup_obdclass(void)
int lustre_unregister_fs(void);
__u64 memory_leaked, pages_leaked;
__u64 memory_max, pages_max;
- ENTRY;
lustre_unregister_fs();
@@ -678,12 +675,12 @@ static void cleanup_obdclass(void)
CDEBUG((pages_leaked) ? D_ERROR : D_INFO,
"obd_memory_pages max: "LPU64", leaked: "LPU64"\n",
pages_max, pages_leaked);
-
- EXIT;
}
MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Class Driver Build Version: " BUILD_VERSION);
MODULE_LICENSE("GPL");
+MODULE_VERSION(LUSTRE_VERSION_STRING);
-cfs_module(obdclass, LUSTRE_VERSION_STRING, init_obdclass, cleanup_obdclass);
+module_init(init_obdclass);
+module_exit(cleanup_obdclass);
diff --git a/drivers/staging/lustre/lustre/obdclass/dt_object.c b/drivers/staging/lustre/lustre/obdclass/dt_object.c
index 1c962dd3bd2..1b164c7027b 100644
--- a/drivers/staging/lustre/lustre/obdclass/dt_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/dt_object.c
@@ -219,7 +219,6 @@ struct dt_object *dt_locate_at(const struct lu_env *env,
struct lu_device *top_dev)
{
struct lu_object *lo, *n;
- ENTRY;
lo = lu_object_find_at(env, top_dev, fid, NULL);
if (IS_ERR(lo))
@@ -376,15 +375,13 @@ struct dt_object *dt_find_or_create(const struct lu_env *env,
struct thandle *th;
int rc;
- ENTRY;
-
dto = dt_locate(env, dt, fid);
if (IS_ERR(dto))
- RETURN(dto);
+ return dto;
LASSERT(dto != NULL);
if (dt_object_exists(dto))
- RETURN(dto);
+ return dto;
th = dt_trans_create(env, dt);
if (IS_ERR(th))
@@ -415,9 +412,9 @@ trans_stop:
out:
if (rc) {
lu_object_put(env, &dto->do_lu);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
- RETURN(dto);
+ return dto;
}
EXPORT_SYMBOL(dt_find_or_create);
@@ -659,7 +656,6 @@ static int dt_index_page_build(const struct lu_env *env, union lu_page *lp,
struct lu_idxpage *lip = &lp->lp_idx;
char *entry;
int rc, size;
- ENTRY;
/* no support for variable key & record size for now */
LASSERT((ii->ii_flags & II_FL_VARKEY) == 0);
@@ -763,21 +759,20 @@ int dt_index_walk(const struct lu_env *env, struct dt_object *obj,
const struct dt_it_ops *iops;
unsigned int pageidx, nob, nlupgs = 0;
int rc;
- ENTRY;
LASSERT(rdpg->rp_pages != NULL);
LASSERT(obj->do_index_ops != NULL);
nob = rdpg->rp_count;
if (nob <= 0)
- RETURN(-EFAULT);
+ return -EFAULT;
/* Iterate through index and fill containers from @rdpg */
iops = &obj->do_index_ops->dio_it;
LASSERT(iops != NULL);
it = iops->init(env, obj, rdpg->rp_attrs, BYPASS_CAPA);
if (IS_ERR(it))
- RETURN(PTR_ERR(it));
+ return PTR_ERR(it);
rc = iops->load(env, it, rdpg->rp_hash);
if (rc == 0) {
@@ -831,7 +826,7 @@ int dt_index_walk(const struct lu_env *env, struct dt_object *obj,
if (rc >= 0)
rc = min_t(unsigned int, nlupgs * LU_PAGE_SIZE, rdpg->rp_count);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(dt_index_walk);
@@ -855,26 +850,25 @@ int dt_index_read(const struct lu_env *env, struct dt_device *dev,
const struct dt_index_features *feat;
struct dt_object *obj;
int rc;
- ENTRY;
/* rp_count shouldn't be null and should be a multiple of the container
* size */
if (rdpg->rp_count <= 0 && (rdpg->rp_count & (LU_PAGE_SIZE - 1)) != 0)
- RETURN(-EFAULT);
+ return -EFAULT;
if (fid_seq(&ii->ii_fid) >= FID_SEQ_NORMAL)
/* we don't support directory transfer via OBD_IDX_READ for the
* time being */
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
if (!fid_is_quota(&ii->ii_fid))
/* block access to all local files except quota files */
- RETURN(-EPERM);
+ return -EPERM;
/* lookup index object subject to the transfer */
obj = dt_locate(env, dev, &ii->ii_fid);
if (IS_ERR(obj))
- RETURN(PTR_ERR(obj));
+ return PTR_ERR(obj);
if (dt_object_exists(obj) == 0)
GOTO(out, rc = -ENOENT);
diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c
index d96876e0bc6..68fe71c8a2a 100644
--- a/drivers/staging/lustre/lustre/obdclass/genops.c
+++ b/drivers/staging/lustre/lustre/obdclass/genops.c
@@ -163,20 +163,19 @@ int class_register_type(struct obd_ops *dt_ops, struct md_ops *md_ops,
{
struct obd_type *type;
int rc = 0;
- ENTRY;
/* sanity check */
LASSERT(strnlen(name, CLASS_MAX_NAME) < CLASS_MAX_NAME);
if (class_search_type(name)) {
CDEBUG(D_IOCTL, "Type %s already registered\n", name);
- RETURN(-EEXIST);
+ return -EEXIST;
}
rc = -ENOMEM;
OBD_ALLOC(type, sizeof(*type));
if (type == NULL)
- RETURN(rc);
+ return rc;
OBD_ALLOC_PTR(type->typ_dt_ops);
OBD_ALLOC_PTR(type->typ_md_ops);
@@ -214,7 +213,7 @@ int class_register_type(struct obd_ops *dt_ops, struct md_ops *md_ops,
list_add(&type->typ_chain, &obd_types);
spin_unlock(&obd_types_lock);
- RETURN (0);
+ return 0;
failed:
if (type->typ_name != NULL)
@@ -224,18 +223,17 @@ int class_register_type(struct obd_ops *dt_ops, struct md_ops *md_ops,
if (type->typ_dt_ops != NULL)
OBD_FREE_PTR(type->typ_dt_ops);
OBD_FREE(type, sizeof(*type));
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(class_register_type);
int class_unregister_type(const char *name)
{
struct obd_type *type = class_search_type(name);
- ENTRY;
if (!type) {
CERROR("unknown obd type\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (type->typ_refcnt) {
@@ -244,7 +242,7 @@ int class_unregister_type(const char *name)
/* Remove ops, but leave the name for debugging */
OBD_FREE_PTR(type->typ_dt_ops);
OBD_FREE_PTR(type->typ_md_ops);
- RETURN(-EBUSY);
+ return -EBUSY;
}
if (type->typ_procroot) {
@@ -263,7 +261,7 @@ int class_unregister_type(const char *name)
if (type->typ_md_ops != NULL)
OBD_FREE_PTR(type->typ_md_ops);
OBD_FREE(type, sizeof(*type));
- RETURN(0);
+ return 0;
} /* class_unregister_type */
EXPORT_SYMBOL(class_unregister_type);
@@ -285,17 +283,16 @@ struct obd_device *class_newdev(const char *type_name, const char *name)
struct obd_type *type = NULL;
int i;
int new_obd_minor = 0;
- ENTRY;
if (strlen(name) >= MAX_OBD_NAME) {
CERROR("name/uuid must be < %u bytes long\n", MAX_OBD_NAME);
- RETURN(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
}
type = class_get_type(type_name);
if (type == NULL){
CERROR("OBD: unknown type: %s\n", type_name);
- RETURN(ERR_PTR(-ENODEV));
+ return ERR_PTR(-ENODEV);
}
newdev = obd_device_alloc();
@@ -349,7 +346,7 @@ struct obd_device *class_newdev(const char *type_name, const char *name)
CDEBUG(D_IOCTL, "Adding new device %s (%p)\n",
result->obd_name, result);
- RETURN(result);
+ return result;
out:
obd_device_free(newdev);
out_type:
@@ -635,7 +632,6 @@ EXPORT_SYMBOL(class_notify_sptlrpc_conf);
void obd_cleanup_caches(void)
{
- ENTRY;
if (obd_device_cachep) {
kmem_cache_destroy(obd_device_cachep);
obd_device_cachep = NULL;
@@ -652,13 +648,10 @@ void obd_cleanup_caches(void)
kmem_cache_destroy(capa_cachep);
capa_cachep = NULL;
}
- EXIT;
}
int obd_init_caches(void)
{
- ENTRY;
-
LASSERT(obd_device_cachep == NULL);
obd_device_cachep = kmem_cache_create("ll_obd_dev_cache",
sizeof(struct obd_device),
@@ -685,10 +678,10 @@ int obd_init_caches(void)
if (!capa_cachep)
GOTO(out, -ENOMEM);
- RETURN(0);
+ return 0;
out:
obd_cleanup_caches();
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
@@ -696,21 +689,20 @@ int obd_init_caches(void)
struct obd_export *class_conn2export(struct lustre_handle *conn)
{
struct obd_export *export;
- ENTRY;
if (!conn) {
CDEBUG(D_CACHE, "looking for null handle\n");
- RETURN(NULL);
+ return NULL;
}
if (conn->cookie == -1) { /* this means assign a new connection */
CDEBUG(D_CACHE, "want a new connection\n");
- RETURN(NULL);
+ return NULL;
}
CDEBUG(D_INFO, "looking for export cookie "LPX64"\n", conn->cookie);
export = class_handle2object(conn->cookie);
- RETURN(export);
+ return export;
}
EXPORT_SYMBOL(class_conn2export);
@@ -757,7 +749,6 @@ EXPORT_SYMBOL(class_conn2cliimp);
static void class_export_destroy(struct obd_export *exp)
{
struct obd_device *obd = exp->exp_obd;
- ENTRY;
LASSERT_ATOMIC_ZERO(&exp->exp_refcount);
LASSERT(obd != NULL);
@@ -777,7 +768,6 @@ static void class_export_destroy(struct obd_export *exp)
class_decref(obd, "export", exp);
OBD_FREE_RCU(exp, sizeof(*exp), &exp->exp_handle);
- EXIT;
}
static void export_handle_addref(void *export)
@@ -828,7 +818,6 @@ struct obd_export *class_new_export(struct obd_device *obd,
struct obd_export *export;
cfs_hash_t *hash = NULL;
int rc = 0;
- ENTRY;
OBD_ALLOC_PTR(export);
if (!export)
@@ -899,7 +888,7 @@ struct obd_export *class_new_export(struct obd_device *obd,
export->exp_obd->obd_num_exports++;
spin_unlock(&obd->obd_dev_lock);
cfs_hash_putref(hash);
- RETURN(export);
+ return export;
exit_unlock:
spin_unlock(&obd->obd_dev_lock);
@@ -936,8 +925,6 @@ EXPORT_SYMBOL(class_unlink_export);
/* Import management functions */
void class_import_destroy(struct obd_import *imp)
{
- ENTRY;
-
CDEBUG(D_IOCTL, "destroying import %p for %s\n", imp,
imp->imp_obd->obd_name);
@@ -958,7 +945,6 @@ void class_import_destroy(struct obd_import *imp)
LASSERT(imp->imp_sec == NULL);
class_decref(imp->imp_obd, "import", imp);
OBD_FREE_RCU(imp, sizeof(*imp), &imp->imp_handle);
- EXIT;
}
static void import_handle_addref(void *import)
@@ -983,8 +969,6 @@ EXPORT_SYMBOL(class_import_get);
void class_import_put(struct obd_import *imp)
{
- ENTRY;
-
LASSERT(list_empty(&imp->imp_zombie_chain));
LASSERT_ATOMIC_GT_LT(&imp->imp_refcount, 0, LI_POISON);
@@ -999,7 +983,6 @@ void class_import_put(struct obd_import *imp)
/* catch possible import put race */
LASSERT_ATOMIC_GE_LT(&imp->imp_refcount, 0, LI_POISON);
- EXIT;
}
EXPORT_SYMBOL(class_import_put);
@@ -1121,18 +1104,17 @@ int class_connect(struct lustre_handle *conn, struct obd_device *obd,
LASSERT(conn != NULL);
LASSERT(obd != NULL);
LASSERT(cluuid != NULL);
- ENTRY;
export = class_new_export(obd, cluuid);
if (IS_ERR(export))
- RETURN(PTR_ERR(export));
+ return PTR_ERR(export);
conn->cookie = export->exp_handle.h_cookie;
class_export_put(export);
CDEBUG(D_IOCTL, "connect: client %s, cookie "LPX64"\n",
cluuid->uuid, conn->cookie);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(class_connect);
@@ -1188,11 +1170,10 @@ void class_export_recovery_cleanup(struct obd_export *exp)
int class_disconnect(struct obd_export *export)
{
int already_disconnected;
- ENTRY;
if (export == NULL) {
CWARN("attempting to free NULL export %p\n", export);
- RETURN(-EINVAL);
+ return -EINVAL;
}
spin_lock(&export->exp_lock);
@@ -1220,7 +1201,7 @@ int class_disconnect(struct obd_export *export)
class_unlink_export(export);
no_disconn:
class_export_put(export);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(class_disconnect);
@@ -1243,7 +1224,6 @@ static void class_disconnect_export_list(struct list_head *list,
{
int rc;
struct obd_export *exp;
- ENTRY;
/* It's possible that an export may disconnect itself, but
* nothing else will be added to this list. */
@@ -1281,13 +1261,11 @@ static void class_disconnect_export_list(struct list_head *list,
obd_export_nid2str(exp), exp, rc);
class_export_put(exp);
}
- EXIT;
}
void class_disconnect_exports(struct obd_device *obd)
{
struct list_head work_list;
- ENTRY;
/* Move all of the exports from obd_exports to a work list, en masse. */
INIT_LIST_HEAD(&work_list);
@@ -1304,7 +1282,6 @@ void class_disconnect_exports(struct obd_device *obd)
} else
CDEBUG(D_HA, "OBD device %d (%p) has no exports\n",
obd->obd_minor, obd);
- EXIT;
}
EXPORT_SYMBOL(class_disconnect_exports);
@@ -1316,7 +1293,6 @@ void class_disconnect_stale_exports(struct obd_device *obd,
struct list_head work_list;
struct obd_export *exp, *n;
int evicted = 0;
- ENTRY;
INIT_LIST_HEAD(&work_list);
spin_lock(&obd->obd_dev_lock);
@@ -1356,7 +1332,6 @@ void class_disconnect_stale_exports(struct obd_device *obd,
class_disconnect_export_list(&work_list, exp_flags_from_obd(obd) |
OBD_OPT_ABORT_RECOV);
- EXIT;
}
EXPORT_SYMBOL(class_disconnect_stale_exports);
@@ -1484,7 +1459,7 @@ int obd_export_evict_by_uuid(struct obd_device *obd, const char *uuid)
CERROR("%s: can't disconnect %s: no exports found\n",
obd->obd_name, uuid);
} else {
- CWARN("%s: evicting %s at adminstrative request\n",
+ CWARN("%s: evicting %s at administrative request\n",
obd->obd_name, doomed_exp->exp_client_uuid.uuid);
class_fail_export(doomed_exp);
class_export_put(doomed_exp);
@@ -1585,7 +1560,6 @@ void obd_zombie_impexp_cull(void)
{
struct obd_import *import;
struct obd_export *export;
- ENTRY;
do {
spin_lock(&obd_zombie_impexp_lock);
@@ -1624,7 +1598,6 @@ void obd_zombie_impexp_cull(void)
cond_resched();
} while (import != NULL || export != NULL);
- EXIT;
}
static struct completion obd_zombie_start;
@@ -1649,7 +1622,7 @@ static int obd_zombie_impexp_check(void *arg)
!test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags);
spin_unlock(&obd_zombie_impexp_lock);
- RETURN(rc);
+ return rc;
}
/**
@@ -1751,7 +1724,7 @@ static int obd_zombie_impexp_thread(void *unused)
complete(&obd_zombie_stop);
- RETURN(0);
+ return 0;
}
@@ -1760,7 +1733,7 @@ static int obd_zombie_impexp_thread(void *unused)
*/
int obd_zombie_impexp_init(void)
{
- task_t *task;
+ struct task_struct *task;
INIT_LIST_HEAD(&obd_zombie_imports);
INIT_LIST_HEAD(&obd_zombie_exports);
@@ -1772,10 +1745,10 @@ int obd_zombie_impexp_init(void)
task = kthread_run(obd_zombie_impexp_thread, NULL, "obd_zombid");
if (IS_ERR(task))
- RETURN(PTR_ERR(task));
+ return PTR_ERR(task);
wait_for_completion(&obd_zombie_start);
- RETURN(0);
+ return 0;
}
/**
* stop destroy zombie import/export thread
diff --git a/drivers/staging/lustre/lustre/obdclass/idmap.c b/drivers/staging/lustre/lustre/obdclass/idmap.c
index 622f8d16527..ec2590f5cfe 100644
--- a/drivers/staging/lustre/lustre/obdclass/idmap.c
+++ b/drivers/staging/lustre/lustre/obdclass/idmap.c
@@ -59,8 +59,7 @@
* groups_search() is copied from linux kernel!
* A simple bsearch.
*/
-static int lustre_groups_search(group_info_t *group_info,
- gid_t grp)
+static int lustre_groups_search(const struct group_info *group_info, gid_t grp)
{
int left, right;
@@ -71,7 +70,8 @@ static int lustre_groups_search(group_info_t *group_info,
right = group_info->ngroups;
while (left < right) {
int mid = (left + right) / 2;
- int cmp = grp - CFS_GROUP_AT(group_info, mid);
+ int cmp = grp -
+ from_kgid(&init_user_ns, CFS_GROUP_AT(group_info, mid));
if (cmp > 0)
left = mid + 1;
@@ -83,7 +83,7 @@ static int lustre_groups_search(group_info_t *group_info,
return 0;
}
-void lustre_groups_from_list(group_info_t *ginfo, gid_t *glist)
+void lustre_groups_from_list(struct group_info *ginfo, gid_t *glist)
{
int i;
int count = ginfo->ngroups;
@@ -102,7 +102,7 @@ EXPORT_SYMBOL(lustre_groups_from_list);
/* groups_sort() is copied from linux kernel! */
/* a simple shell-metzner sort */
-void lustre_groups_sort(group_info_t *group_info)
+void lustre_groups_sort(struct group_info *group_info)
{
int base, max, stride;
int gidsetsize = group_info->ngroups;
@@ -116,16 +116,19 @@ void lustre_groups_sort(group_info_t *group_info)
for (base = 0; base < max; base++) {
int left = base;
int right = left + stride;
- gid_t tmp = CFS_GROUP_AT(group_info, right);
+ gid_t tmp = from_kgid(&init_user_ns,
+ CFS_GROUP_AT(group_info, right));
while (left >= 0 &&
- CFS_GROUP_AT(group_info, left) > tmp) {
+ tmp < from_kgid(&init_user_ns,
+ CFS_GROUP_AT(group_info, left))) {
CFS_GROUP_AT(group_info, right) =
CFS_GROUP_AT(group_info, left);
right = left;
left -= stride;
}
- CFS_GROUP_AT(group_info, right) = tmp;
+ CFS_GROUP_AT(group_info, right) =
+ make_kgid(&init_user_ns, tmp);
}
stride /= 3;
}
@@ -137,7 +140,7 @@ int lustre_in_group_p(struct lu_ucred *mu, gid_t grp)
int rc = 1;
if (grp != mu->uc_fsgid) {
- group_info_t *group_info = NULL;
+ struct group_info *group_info = NULL;
if (mu->uc_ginfo || !mu->uc_identity ||
mu->uc_valid == UCRED_OLD)
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
index d2c3072541d..d1a57ebfda9 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
@@ -83,27 +83,26 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg)
struct obd_ioctl_data *data;
int err;
int offset = 0;
- ENTRY;
err = copy_from_user(&hdr, (void *)arg, sizeof(hdr));
if ( err )
- RETURN(err);
+ return err;
if (hdr.ioc_version != OBD_IOCTL_VERSION) {
CERROR("Version mismatch kernel (%x) vs application (%x)\n",
OBD_IOCTL_VERSION, hdr.ioc_version);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (hdr.ioc_len > OBD_MAX_IOCTL_BUFFER) {
CERROR("User buffer len %d exceeds %d max buffer\n",
hdr.ioc_len, OBD_MAX_IOCTL_BUFFER);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (hdr.ioc_len < sizeof(struct obd_ioctl_data)) {
CERROR("User buffer too small for ioctl (%d)\n", hdr.ioc_len);
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* When there are lots of processes calling vmalloc on multi-core
@@ -114,7 +113,7 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg)
if (*buf == NULL) {
CERROR("Cannot allocate control buffer of len %d\n",
hdr.ioc_len);
- RETURN(-EINVAL);
+ return -EINVAL;
}
*len = hdr.ioc_len;
data = (struct obd_ioctl_data *)*buf;
@@ -122,13 +121,13 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg)
err = copy_from_user(*buf, (void *)arg, hdr.ioc_len);
if ( err ) {
OBD_FREE_LARGE(*buf, hdr.ioc_len);
- RETURN(err);
+ return err;
}
if (obd_ioctl_is_invalid(data)) {
CERROR("ioctl not correctly formatted\n");
OBD_FREE_LARGE(*buf, hdr.ioc_len);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (data->ioc_inllen1) {
@@ -150,7 +149,6 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg)
data->ioc_inlbuf4 = &data->ioc_bulk[0] + offset;
}
- EXIT;
return 0;
}
EXPORT_SYMBOL(obd_ioctl_getdata);
@@ -169,19 +167,15 @@ EXPORT_SYMBOL(obd_ioctl_popdata);
/* opening /dev/obd */
static int obd_class_open(struct inode * inode, struct file * file)
{
- ENTRY;
-
try_module_get(THIS_MODULE);
- RETURN(0);
+ return 0;
}
/* closing /dev/obd */
static int obd_class_release(struct inode * inode, struct file * file)
{
- ENTRY;
-
module_put(THIS_MODULE);
- RETURN(0);
+ return 0;
}
/* to control /dev/obd */
@@ -189,17 +183,16 @@ static long obd_class_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int err = 0;
- ENTRY;
/* Allow non-root access for OBD_IOC_PING_TARGET - used by lfs check */
if (!cfs_capable(CFS_CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET))
- RETURN(err = -EACCES);
+ return err = -EACCES;
if ((cmd & 0xffffff00) == ((int)'T') << 8) /* ignore all tty ioctls */
- RETURN(err = -ENOTTY);
+ return err = -ENOTTY;
err = class_handle_ioctl(cmd, (unsigned long)arg);
- RETURN(err);
+ return err;
}
/* declare character device */
@@ -211,7 +204,7 @@ static struct file_operations obd_psdev_fops = {
};
/* modules setup */
-psdev_t obd_psdev = {
+struct miscdevice obd_psdev = {
.minor = OBD_DEV_MINOR,
.name = OBD_DEV_NAME,
.fops = &obd_psdev_fops,
@@ -385,24 +378,29 @@ struct file_operations obd_device_list_fops = {
int class_procfs_init(void)
{
- int rc;
- ENTRY;
+ int rc = 0;
obd_sysctl_init();
proc_lustre_root = lprocfs_register("fs/lustre", NULL,
lprocfs_base, NULL);
+ if (IS_ERR(proc_lustre_root)) {
+ rc = PTR_ERR(proc_lustre_root);
+ proc_lustre_root = NULL;
+ goto out;
+ }
+
rc = lprocfs_seq_create(proc_lustre_root, "devices", 0444,
&obd_device_list_fops, NULL);
+out:
if (rc)
CERROR("error adding /proc/fs/lustre/devices file\n");
- RETURN(0);
+ return 0;
}
int class_procfs_clean(void)
{
- ENTRY;
if (proc_lustre_root) {
lprocfs_remove(&proc_lustre_root);
}
- RETURN(0);
+ return 0;
}
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c
index 6ee347153a1..d3bb5ffc564 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c
@@ -213,9 +213,9 @@ void obdo_to_inode(struct inode *dst, struct obdo *src, obd_flag valid)
if (valid & OBD_MD_FLMODE)
dst->i_mode = (dst->i_mode & S_IFMT) | (src->o_mode & ~S_IFMT);
if (valid & OBD_MD_FLUID)
- dst->i_uid = src->o_uid;
+ dst->i_uid = make_kuid(&init_user_ns, src->o_uid);
if (valid & OBD_MD_FLGID)
- dst->i_gid = src->o_gid;
+ dst->i_gid = make_kgid(&init_user_ns, src->o_gid);
if (valid & OBD_MD_FLFLAGS)
dst->i_flags = src->o_flags;
}
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c
index 46aad6813ca..acd2619227d 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c
@@ -38,8 +38,6 @@
#include <linux/sysctl.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <linux/sysctl.h>
-#include <linux/version.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/stat.h>
@@ -202,12 +200,12 @@ int LL_PROC_PROTO(proc_max_dirty_pages_in_mb)
1 << (20 - PAGE_CACHE_SHIFT));
/* Don't allow them to let dirty pages exceed 90% of system
* memory and set a hard minimum of 4MB. */
- if (obd_max_dirty_pages > ((num_physpages / 10) * 9)) {
+ if (obd_max_dirty_pages > ((totalram_pages / 10) * 9)) {
CERROR("Refusing to set max dirty pages to %u, which "
"is more than 90%% of available RAM; setting "
"to %lu\n", obd_max_dirty_pages,
- ((num_physpages / 10) * 9));
- obd_max_dirty_pages = ((num_physpages / 10) * 9);
+ ((totalram_pages / 10) * 9));
+ obd_max_dirty_pages = ((totalram_pages / 10) * 9);
} else if (obd_max_dirty_pages < 4 << (20 - PAGE_CACHE_SHIFT)) {
obd_max_dirty_pages = 4 << (20 - PAGE_CACHE_SHIFT);
}
@@ -431,7 +429,7 @@ void obd_sysctl_init (void)
{
#ifdef CONFIG_SYSCTL
if ( !obd_table_header )
- obd_table_header = cfs_register_sysctl_table(parent_table, 0);
+ obd_table_header = register_sysctl_table(parent_table);
#endif
}
diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c
index b1d215e5699..0cb44287502 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog.c
@@ -111,21 +111,20 @@ int llog_cancel_rec(const struct lu_env *env, struct llog_handle *loghandle,
{
struct llog_log_hdr *llh = loghandle->lgh_hdr;
int rc = 0;
- ENTRY;
CDEBUG(D_RPCTRACE, "Canceling %d in log "DOSTID"\n",
index, POSTID(&loghandle->lgh_id.lgl_oi));
if (index == 0) {
CERROR("Can't cancel index 0 which is header\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
spin_lock(&loghandle->lgh_hdr_lock);
if (!ext2_clear_bit(index, llh->llh_bitmap)) {
spin_unlock(&loghandle->lgh_hdr_lock);
CDEBUG(D_RPCTRACE, "Catalog index %u already clear?\n", index);
- RETURN(-ENOENT);
+ return -ENOENT;
}
llh->llh_count--;
@@ -143,7 +142,7 @@ int llog_cancel_rec(const struct lu_env *env, struct llog_handle *loghandle,
loghandle->lgh_id.lgl_ogen, rc);
GOTO(out_err, rc);
}
- RETURN(1);
+ return 1;
}
spin_unlock(&loghandle->lgh_hdr_lock);
@@ -156,7 +155,7 @@ int llog_cancel_rec(const struct lu_env *env, struct llog_handle *loghandle,
loghandle->lgh_id.lgl_ogen, rc);
GOTO(out_err, rc);
}
- RETURN(0);
+ return 0;
out_err:
spin_lock(&loghandle->lgh_hdr_lock);
ext2_set_bit(index, llh->llh_bitmap);
@@ -175,10 +174,10 @@ static int llog_read_header(const struct lu_env *env,
rc = llog_handle2ops(handle, &lop);
if (rc)
- RETURN(rc);
+ return rc;
if (lop->lop_read_header == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
rc = lop->lop_read_header(env, handle);
if (rc == LLOG_EEMPTY) {
@@ -206,12 +205,11 @@ int llog_init_handle(const struct lu_env *env, struct llog_handle *handle,
struct llog_log_hdr *llh;
int rc;
- ENTRY;
LASSERT(handle->lgh_hdr == NULL);
OBD_ALLOC_PTR(llh);
if (llh == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
handle->lgh_hdr = llh;
/* first assign flags to use llog_client_ops */
llh->llh_flags = flags;
@@ -263,7 +261,7 @@ out:
OBD_FREE_PTR(llh);
handle->lgh_hdr = NULL;
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_init_handle);
@@ -277,7 +275,6 @@ int llog_copy_handler(const struct lu_env *env,
char *cfg_buf = (char*) (rec + 1);
struct lustre_cfg *lcfg;
int rc = 0;
- ENTRY;
/* Append all records */
local_rec.lrh_len -= sizeof(*rec) + sizeof(struct llog_rec_tail);
@@ -289,7 +286,7 @@ int llog_copy_handler(const struct lu_env *env,
rec->lrh_index, rc, rec->lrh_len, lcfg->lcfg_command,
lustre_cfg_string(lcfg, 0), lustre_cfg_string(lcfg, 1));
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_copy_handler);
@@ -306,14 +303,12 @@ static int llog_process_thread(void *arg)
int saved_index = 0;
int last_called_index = 0;
- ENTRY;
-
LASSERT(llh);
OBD_ALLOC(buf, LLOG_CHUNK_SIZE);
if (!buf) {
lpi->lpi_rc = -ENOMEM;
- RETURN(0);
+ return 0;
}
if (cd != NULL) {
@@ -457,12 +452,10 @@ int llog_process_or_fork(const struct lu_env *env,
struct llog_process_info *lpi;
int rc;
- ENTRY;
-
OBD_ALLOC_PTR(lpi);
if (lpi == NULL) {
CERROR("cannot alloc pointer\n");
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
lpi->lpi_loghandle = loghandle;
lpi->lpi_cb = cb;
@@ -480,7 +473,7 @@ int llog_process_or_fork(const struct lu_env *env,
CERROR("%s: cannot start thread: rc = %d\n",
loghandle->lgh_ctxt->loc_obd->obd_name, rc);
OBD_FREE_PTR(lpi);
- RETURN(rc);
+ return rc;
}
wait_for_completion(&lpi->lpi_completion);
} else {
@@ -489,7 +482,7 @@ int llog_process_or_fork(const struct lu_env *env,
}
rc = lpi->lpi_rc;
OBD_FREE_PTR(lpi);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_process_or_fork);
@@ -516,11 +509,10 @@ int llog_reverse_process(const struct lu_env *env,
struct llog_process_cat_data *cd = catdata;
void *buf;
int rc = 0, first_index = 1, index, idx;
- ENTRY;
OBD_ALLOC(buf, LLOG_CHUNK_SIZE);
if (!buf)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (cd != NULL)
first_index = cd->lpcd_first_idx + 1;
@@ -594,7 +586,7 @@ int llog_reverse_process(const struct lu_env *env,
out:
if (buf)
OBD_FREE(buf, LLOG_CHUNK_SIZE);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_reverse_process);
@@ -617,16 +609,14 @@ int llog_exist(struct llog_handle *loghandle)
struct llog_operations *lop;
int rc;
- ENTRY;
-
rc = llog_handle2ops(loghandle, &lop);
if (rc)
- RETURN(rc);
+ return rc;
if (lop->lop_exist == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
rc = lop->lop_exist(loghandle);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_exist);
@@ -636,13 +626,11 @@ int llog_declare_create(const struct lu_env *env,
struct llog_operations *lop;
int raised, rc;
- ENTRY;
-
rc = llog_handle2ops(loghandle, &lop);
if (rc)
- RETURN(rc);
+ return rc;
if (lop->lop_declare_create == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
if (!raised)
@@ -650,7 +638,7 @@ int llog_declare_create(const struct lu_env *env,
rc = lop->lop_declare_create(env, loghandle, th);
if (!raised)
cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_declare_create);
@@ -660,13 +648,11 @@ int llog_create(const struct lu_env *env, struct llog_handle *handle,
struct llog_operations *lop;
int raised, rc;
- ENTRY;
-
rc = llog_handle2ops(handle, &lop);
if (rc)
- RETURN(rc);
+ return rc;
if (lop->lop_create == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
if (!raised)
@@ -674,7 +660,7 @@ int llog_create(const struct lu_env *env, struct llog_handle *handle,
rc = lop->lop_create(env, handle, th);
if (!raised)
cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_create);
@@ -686,14 +672,12 @@ int llog_declare_write_rec(const struct lu_env *env,
struct llog_operations *lop;
int raised, rc;
- ENTRY;
-
rc = llog_handle2ops(handle, &lop);
if (rc)
- RETURN(rc);
+ return rc;
LASSERT(lop);
if (lop->lop_declare_write_rec == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
if (!raised)
@@ -701,7 +685,7 @@ int llog_declare_write_rec(const struct lu_env *env,
rc = lop->lop_declare_write_rec(env, handle, rec, idx, th);
if (!raised)
cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_declare_write_rec);
@@ -712,15 +696,13 @@ int llog_write_rec(const struct lu_env *env, struct llog_handle *handle,
struct llog_operations *lop;
int raised, rc, buflen;
- ENTRY;
-
rc = llog_handle2ops(handle, &lop);
if (rc)
- RETURN(rc);
+ return rc;
LASSERT(lop);
if (lop->lop_write_rec == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
if (buf)
buflen = rec->lrh_len + sizeof(struct llog_rec_hdr) +
@@ -736,7 +718,7 @@ int llog_write_rec(const struct lu_env *env, struct llog_handle *handle,
buf, idx, th);
if (!raised)
cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_write_rec);
@@ -746,10 +728,8 @@ int llog_add(const struct lu_env *env, struct llog_handle *lgh,
{
int raised, rc;
- ENTRY;
-
if (lgh->lgh_logops->lop_add == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
if (!raised)
@@ -757,7 +737,7 @@ int llog_add(const struct lu_env *env, struct llog_handle *lgh,
rc = lgh->lgh_logops->lop_add(env, lgh, rec, logcookies, buf, th);
if (!raised)
cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_add);
@@ -766,10 +746,8 @@ int llog_declare_add(const struct lu_env *env, struct llog_handle *lgh,
{
int raised, rc;
- ENTRY;
-
if (lgh->lgh_logops->lop_declare_add == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
if (!raised)
@@ -777,7 +755,7 @@ int llog_declare_add(const struct lu_env *env, struct llog_handle *lgh,
rc = lgh->lgh_logops->lop_declare_add(env, lgh, rec, th);
if (!raised)
cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_declare_add);
@@ -792,14 +770,12 @@ int llog_open_create(const struct lu_env *env, struct llog_ctxt *ctxt,
struct thandle *th;
int rc;
- ENTRY;
-
rc = llog_open(env, ctxt, res, logid, name, LLOG_OPEN_NEW);
if (rc)
- RETURN(rc);
+ return rc;
if (llog_exist(*res))
- RETURN(0);
+ return 0;
if ((*res)->lgh_obj != NULL) {
struct dt_device *d;
@@ -825,7 +801,7 @@ int llog_open_create(const struct lu_env *env, struct llog_ctxt *ctxt,
out:
if (rc)
llog_close(env, *res);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_open_create);
@@ -838,15 +814,13 @@ int llog_erase(const struct lu_env *env, struct llog_ctxt *ctxt,
struct llog_handle *handle;
int rc = 0, rc2;
- ENTRY;
-
/* nothing to erase */
if (name == NULL && logid == NULL)
- RETURN(0);
+ return 0;
rc = llog_open(env, ctxt, &handle, logid, name, LLOG_OPEN_EXISTS);
if (rc < 0)
- RETURN(rc);
+ return rc;
rc = llog_init_handle(env, handle, LLOG_F_IS_PLAIN, NULL);
if (rc == 0)
@@ -855,7 +829,7 @@ int llog_erase(const struct lu_env *env, struct llog_ctxt *ctxt,
rc2 = llog_close(env, handle);
if (rc == 0)
rc = rc2;
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_erase);
@@ -870,8 +844,6 @@ int llog_write(const struct lu_env *env, struct llog_handle *loghandle,
{
int rc;
- ENTRY;
-
LASSERT(loghandle);
LASSERT(loghandle->lgh_ctxt);
@@ -883,7 +855,7 @@ int llog_write(const struct lu_env *env, struct llog_handle *loghandle,
th = dt_trans_create(env, dt);
if (IS_ERR(th))
- RETURN(PTR_ERR(th));
+ return PTR_ERR(th);
rc = llog_declare_write_rec(env, loghandle, rec, idx, th);
if (rc)
@@ -905,7 +877,7 @@ out_trans:
cookiecount, buf, idx, NULL);
up_write(&loghandle->lgh_lock);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_write);
@@ -916,19 +888,17 @@ int llog_open(const struct lu_env *env, struct llog_ctxt *ctxt,
int raised;
int rc;
- ENTRY;
-
LASSERT(ctxt);
LASSERT(ctxt->loc_logops);
if (ctxt->loc_logops->lop_open == NULL) {
*lgh = NULL;
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
}
*lgh = llog_alloc_handle();
if (*lgh == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
(*lgh)->lgh_ctxt = ctxt;
(*lgh)->lgh_logops = ctxt->loc_logops;
@@ -942,7 +912,7 @@ int llog_open(const struct lu_env *env, struct llog_ctxt *ctxt,
llog_free_handle(*lgh);
*lgh = NULL;
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_open);
@@ -951,8 +921,6 @@ int llog_close(const struct lu_env *env, struct llog_handle *loghandle)
struct llog_operations *lop;
int rc;
- ENTRY;
-
rc = llog_handle2ops(loghandle, &lop);
if (rc)
GOTO(out, rc);
@@ -961,6 +929,6 @@ int llog_close(const struct lu_env *env, struct llog_handle *loghandle)
rc = lop->lop_close(env, loghandle);
out:
llog_handle_put(loghandle);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_close);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_cat.c b/drivers/staging/lustre/lustre/obdclass/llog_cat.c
index cf00b2f550a..c0f3af72574 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_cat.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_cat.c
@@ -67,7 +67,6 @@ static int llog_cat_new_log(const struct lu_env *env,
struct llog_log_hdr *llh;
struct llog_logid_rec rec = { { 0 }, };
int rc, index, bitmap_size;
- ENTRY;
llh = cathandle->lgh_hdr;
bitmap_size = LLOG_BITMAP_SIZE(llh);
@@ -77,20 +76,20 @@ static int llog_cat_new_log(const struct lu_env *env,
/* maximum number of available slots in catlog is bitmap_size - 2 */
if (llh->llh_cat_idx == index) {
CERROR("no free catalog slots for log...\n");
- RETURN(-ENOSPC);
+ return -ENOSPC;
}
if (OBD_FAIL_CHECK(OBD_FAIL_MDS_LLOG_CREATE_FAILED))
- RETURN(-ENOSPC);
+ return -ENOSPC;
rc = llog_create(env, loghandle, th);
/* if llog is already created, no need to initialize it */
if (rc == -EEXIST) {
- RETURN(0);
+ return 0;
} else if (rc != 0) {
CERROR("%s: can't create new plain llog in catalog: rc = %d\n",
loghandle->lgh_ctxt->loc_obd->obd_name, rc);
- RETURN(rc);
+ return rc;
}
rc = llog_init_handle(env, loghandle,
@@ -134,10 +133,10 @@ static int llog_cat_new_log(const struct lu_env *env,
GOTO(out_destroy, rc);
loghandle->lgh_hdr->llh_cat_idx = index;
- RETURN(0);
+ return 0;
out_destroy:
llog_destroy(env, loghandle);
- RETURN(rc);
+ return rc;
}
/* Open an existent log handle and add it to the open list.
@@ -155,10 +154,8 @@ int llog_cat_id2handle(const struct lu_env *env, struct llog_handle *cathandle,
struct llog_handle *loghandle;
int rc = 0;
- ENTRY;
-
if (cathandle == NULL)
- RETURN(-EBADF);
+ return -EBADF;
down_write(&cathandle->lgh_lock);
list_for_each_entry(loghandle, &cathandle->u.chd.chd_head,
@@ -187,14 +184,14 @@ int llog_cat_id2handle(const struct lu_env *env, struct llog_handle *cathandle,
CERROR("%s: error opening log id "DOSTID":%x: rc = %d\n",
cathandle->lgh_ctxt->loc_obd->obd_name,
POSTID(&logid->lgl_oi), logid->lgl_ogen, rc);
- RETURN(rc);
+ return rc;
}
rc = llog_init_handle(env, loghandle, LLOG_F_IS_PLAIN, NULL);
if (rc < 0) {
llog_close(env, loghandle);
loghandle = NULL;
- RETURN(rc);
+ return rc;
}
down_write(&cathandle->lgh_lock);
@@ -205,7 +202,6 @@ int llog_cat_id2handle(const struct lu_env *env, struct llog_handle *cathandle,
loghandle->u.phd.phd_cookie.lgc_lgl = cathandle->lgh_id;
loghandle->u.phd.phd_cookie.lgc_index =
loghandle->lgh_hdr->llh_cat_idx;
- EXIT;
out:
llog_handle_get(loghandle);
*res = loghandle;
@@ -217,8 +213,6 @@ int llog_cat_close(const struct lu_env *env, struct llog_handle *cathandle)
struct llog_handle *loghandle, *n;
int rc;
- ENTRY;
-
list_for_each_entry_safe(loghandle, n, &cathandle->u.chd.chd_head,
u.phd.phd_entry) {
struct llog_log_hdr *llh = loghandle->lgh_hdr;
@@ -246,7 +240,7 @@ int llog_cat_close(const struct lu_env *env, struct llog_handle *cathandle)
if (cathandle->lgh_ctxt->loc_handle == cathandle)
cathandle->lgh_ctxt->loc_handle = NULL;
rc = llog_close(env, cathandle);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_cat_close);
@@ -272,7 +266,6 @@ static struct llog_handle *llog_cat_current_log(struct llog_handle *cathandle,
struct thandle *th)
{
struct llog_handle *loghandle = NULL;
- ENTRY;
down_read_nested(&cathandle->lgh_lock, LLOGH_CAT);
loghandle = cathandle->u.chd.chd_current_log;
@@ -284,7 +277,7 @@ static struct llog_handle *llog_cat_current_log(struct llog_handle *cathandle,
if (llh == NULL ||
loghandle->lgh_last_idx < LLOG_BITMAP_SIZE(llh) - 1) {
up_read(&cathandle->lgh_lock);
- RETURN(loghandle);
+ return loghandle;
} else {
up_write(&loghandle->lgh_lock);
}
@@ -304,7 +297,7 @@ static struct llog_handle *llog_cat_current_log(struct llog_handle *cathandle,
LASSERT(llh);
if (loghandle->lgh_last_idx < LLOG_BITMAP_SIZE(llh) - 1) {
up_write(&cathandle->lgh_lock);
- RETURN(loghandle);
+ return loghandle;
} else {
up_write(&loghandle->lgh_lock);
}
@@ -318,7 +311,7 @@ static struct llog_handle *llog_cat_current_log(struct llog_handle *cathandle,
down_write_nested(&loghandle->lgh_lock, LLOGH_LOG);
up_write(&cathandle->lgh_lock);
LASSERT(loghandle);
- RETURN(loghandle);
+ return loghandle;
}
/* Add a single record to the recovery log(s) using a catalog
@@ -332,7 +325,6 @@ int llog_cat_add_rec(const struct lu_env *env, struct llog_handle *cathandle,
{
struct llog_handle *loghandle;
int rc;
- ENTRY;
LASSERT(rec->lrh_len <= LLOG_CHUNK_SIZE);
loghandle = llog_cat_current_log(cathandle, th);
@@ -343,7 +335,7 @@ int llog_cat_add_rec(const struct lu_env *env, struct llog_handle *cathandle,
rc = llog_cat_new_log(env, cathandle, loghandle, th);
if (rc < 0) {
up_write(&loghandle->lgh_lock);
- RETURN(rc);
+ return rc;
}
}
/* now let's try to add the record */
@@ -361,7 +353,7 @@ int llog_cat_add_rec(const struct lu_env *env, struct llog_handle *cathandle,
rc = llog_cat_new_log(env, cathandle, loghandle, th);
if (rc < 0) {
up_write(&loghandle->lgh_lock);
- RETURN(rc);
+ return rc;
}
}
/* now let's try to add the record */
@@ -372,7 +364,7 @@ int llog_cat_add_rec(const struct lu_env *env, struct llog_handle *cathandle,
up_write(&loghandle->lgh_lock);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_cat_add_rec);
@@ -383,8 +375,6 @@ int llog_cat_declare_add_rec(const struct lu_env *env,
struct llog_handle *loghandle, *next;
int rc = 0;
- ENTRY;
-
if (cathandle->u.chd.chd_current_log == NULL) {
/* declare new plain llog */
down_write(&cathandle->lgh_lock);
@@ -437,7 +427,7 @@ int llog_cat_declare_add_rec(const struct lu_env *env,
llog_declare_write_rec(env, next, rec, -1, th);
}
out:
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_cat_declare_add_rec);
@@ -460,7 +450,7 @@ int llog_cat_add(const struct lu_env *env, struct llog_handle *cathandle,
th = dt_trans_create(env, dt);
if (IS_ERR(th))
- RETURN(PTR_ERR(th));
+ return PTR_ERR(th);
rc = llog_cat_declare_add_rec(env, cathandle, rec, th);
if (rc)
@@ -479,7 +469,7 @@ out_trans:
rc = llog_cat_add_rec(env, cathandle, rec, reccookie,
buf, th);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_cat_add);
@@ -498,8 +488,6 @@ int llog_cat_cancel_records(const struct lu_env *env,
{
int i, index, rc = 0, failed = 0;
- ENTRY;
-
for (i = 0; i < count; i++, cookies++) {
struct llog_handle *loghandle;
struct llog_logid *lgl = &cookies->lgc_lgl;
@@ -533,7 +521,7 @@ int llog_cat_cancel_records(const struct lu_env *env,
cathandle->lgh_ctxt->loc_obd->obd_name, failed, count,
rc);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_cat_cancel_records);
@@ -545,10 +533,9 @@ int llog_cat_process_cb(const struct lu_env *env, struct llog_handle *cat_llh,
struct llog_handle *llh;
int rc;
- ENTRY;
if (rec->lrh_type != LLOG_LOGID_MAGIC) {
CERROR("invalid record in catalog\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
CDEBUG(D_HA, "processing log "DOSTID":%x at index %u of catalog "
DOSTID"\n", POSTID(&lir->lid_id.lgl_oi), lir->lid_id.lgl_ogen,
@@ -559,12 +546,12 @@ int llog_cat_process_cb(const struct lu_env *env, struct llog_handle *cat_llh,
CERROR("%s: cannot find handle for llog "DOSTID": %d\n",
cat_llh->lgh_ctxt->loc_obd->obd_name,
POSTID(&lir->lid_id.lgl_oi), rc);
- RETURN(rc);
+ return rc;
}
if (rec->lrh_index < d->lpd_startcat)
/* Skip processing of the logs until startcat */
- RETURN(0);
+ return 0;
if (d->lpd_startidx > 0) {
struct llog_process_cat_data cd;
@@ -581,7 +568,7 @@ int llog_cat_process_cb(const struct lu_env *env, struct llog_handle *cat_llh,
}
llog_handle_put(llh);
- RETURN(rc);
+ return rc;
}
int llog_cat_process_or_fork(const struct lu_env *env,
@@ -592,7 +579,6 @@ int llog_cat_process_or_fork(const struct lu_env *env,
struct llog_process_data d;
struct llog_log_hdr *llh = cat_llh->lgh_hdr;
int rc;
- ENTRY;
LASSERT(llh->llh_flags & LLOG_F_IS_CAT);
d.lpd_data = data;
@@ -611,7 +597,7 @@ int llog_cat_process_or_fork(const struct lu_env *env,
rc = llog_process_or_fork(env, cat_llh, llog_cat_process_cb,
&d, &cd, fork);
if (rc != 0)
- RETURN(rc);
+ return rc;
cd.lpcd_first_idx = 0;
cd.lpcd_last_idx = cat_llh->lgh_last_idx;
@@ -622,7 +608,7 @@ int llog_cat_process_or_fork(const struct lu_env *env,
&d, NULL, fork);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_cat_process_or_fork);
@@ -645,7 +631,7 @@ static int llog_cat_reverse_process_cb(const struct lu_env *env,
if (le32_to_cpu(rec->lrh_type) != LLOG_LOGID_MAGIC) {
CERROR("invalid record in catalog\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
CDEBUG(D_HA, "processing log "DOSTID":%x at index %u of catalog "
DOSTID"\n", POSTID(&lir->lid_id.lgl_oi), lir->lid_id.lgl_ogen,
@@ -656,12 +642,12 @@ static int llog_cat_reverse_process_cb(const struct lu_env *env,
CERROR("%s: cannot find handle for llog "DOSTID": %d\n",
cat_llh->lgh_ctxt->loc_obd->obd_name,
POSTID(&lir->lid_id.lgl_oi), rc);
- RETURN(rc);
+ return rc;
}
rc = llog_reverse_process(env, llh, d->lpd_cb, d->lpd_data, NULL);
llog_handle_put(llh);
- RETURN(rc);
+ return rc;
}
int llog_cat_reverse_process(const struct lu_env *env,
@@ -672,7 +658,6 @@ int llog_cat_reverse_process(const struct lu_env *env,
struct llog_process_cat_data cd;
struct llog_log_hdr *llh = cat_llh->lgh_hdr;
int rc;
- ENTRY;
LASSERT(llh->llh_flags & LLOG_F_IS_CAT);
d.lpd_data = data;
@@ -688,7 +673,7 @@ int llog_cat_reverse_process(const struct lu_env *env,
llog_cat_reverse_process_cb,
&d, &cd);
if (rc != 0)
- RETURN(rc);
+ return rc;
cd.lpcd_first_idx = le32_to_cpu(llh->llh_cat_idx);
cd.lpcd_last_idx = 0;
@@ -701,7 +686,7 @@ int llog_cat_reverse_process(const struct lu_env *env,
&d, NULL);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_cat_reverse_process);
@@ -709,7 +694,6 @@ int llog_cat_set_first_idx(struct llog_handle *cathandle, int index)
{
struct llog_log_hdr *llh = cathandle->lgh_hdr;
int i, bitmap_size, idx;
- ENTRY;
bitmap_size = LLOG_BITMAP_SIZE(llh);
if (llh->llh_cat_idx == (index - 1)) {
@@ -734,7 +718,7 @@ out:
POSTID(&cathandle->lgh_id.lgl_oi), llh->llh_cat_idx);
}
- RETURN(0);
+ return 0;
}
/* Cleanup deleted plain llog traces from catalog */
@@ -774,11 +758,9 @@ int cat_cancel_cb(const struct lu_env *env, struct llog_handle *cathandle,
struct llog_log_hdr *llh;
int rc;
- ENTRY;
-
if (rec->lrh_type != LLOG_LOGID_MAGIC) {
CERROR("invalid record in catalog\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
CDEBUG(D_HA, "processing log "DOSTID":%x at index %u of catalog "
@@ -794,7 +776,7 @@ int cat_cancel_cb(const struct lu_env *env, struct llog_handle *cathandle,
/* remove index from catalog */
llog_cat_cleanup(env, cathandle, NULL, rec->lrh_index);
}
- RETURN(rc);
+ return rc;
}
llh = loghandle->lgh_hdr;
@@ -810,7 +792,7 @@ int cat_cancel_cb(const struct lu_env *env, struct llog_handle *cathandle,
}
llog_handle_put(loghandle);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(cat_cancel_cb);
@@ -822,12 +804,12 @@ int llog_cat_init_and_process(const struct lu_env *env,
rc = llog_init_handle(env, llh, LLOG_F_IS_CAT, NULL);
if (rc)
- RETURN(rc);
+ return rc;
rc = llog_process_or_fork(env, llh, cat_cancel_cb, NULL, NULL, false);
if (rc)
CERROR("%s: llog_process() with cat_cancel_cb failed: rc = "
"%d\n", llh->lgh_ctxt->loc_obd->obd_name, rc);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(llog_cat_init_and_process);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_ioctl.c b/drivers/staging/lustre/lustre/obdclass/llog_ioctl.c
index 0732874e26c..da558a5dc92 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_ioctl.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_ioctl.c
@@ -45,46 +45,45 @@ static int str2logid(struct llog_logid *logid, char *str, int len)
char *start, *end, *endp;
__u64 id, seq;
- ENTRY;
start = str;
if (*start != '#')
- RETURN(-EINVAL);
+ return -EINVAL;
start++;
if (start - str >= len - 1)
- RETURN(-EINVAL);
+ return -EINVAL;
end = strchr(start, '#');
if (end == NULL || end == start)
- RETURN(-EINVAL);
+ return -EINVAL;
*end = '\0';
id = simple_strtoull(start, &endp, 0);
if (endp != end)
- RETURN(-EINVAL);
+ return -EINVAL;
start = ++end;
if (start - str >= len - 1)
- RETURN(-EINVAL);
+ return -EINVAL;
end = strchr(start, '#');
if (end == NULL || end == start)
- RETURN(-EINVAL);
+ return -EINVAL;
*end = '\0';
seq = simple_strtoull(start, &endp, 0);
if (endp != end)
- RETURN(-EINVAL);
+ return -EINVAL;
ostid_set_seq(&logid->lgl_oi, seq);
ostid_set_id(&logid->lgl_oi, id);
start = ++end;
if (start - str >= len - 1)
- RETURN(-EINVAL);
+ return -EINVAL;
logid->lgl_ogen = simple_strtoul(start, &endp, 16);
if (*endp != '\0')
- RETURN(-EINVAL);
+ return -EINVAL;
- RETURN(0);
+ return 0;
}
static int llog_check_cb(const struct lu_env *env, struct llog_handle *handle,
@@ -96,8 +95,6 @@ static int llog_check_cb(const struct lu_env *env, struct llog_handle *handle,
char *endp;
int cur_index, rc = 0;
- ENTRY;
-
if (ioc_data && ioc_data->ioc_inllen1 > 0) {
l = 0;
remains = ioc_data->ioc_inllen4 +
@@ -106,19 +103,19 @@ static int llog_check_cb(const struct lu_env *env, struct llog_handle *handle,
cfs_size_round(ioc_data->ioc_inllen3);
from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
if (*endp != '\0')
- RETURN(-EINVAL);
+ return -EINVAL;
to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
if (*endp != '\0')
- RETURN(-EINVAL);
+ return -EINVAL;
ioc_data->ioc_inllen1 = 0;
out = ioc_data->ioc_bulk;
}
cur_index = rec->lrh_index;
if (cur_index < from)
- RETURN(0);
+ return 0;
if (to > 0 && cur_index > to)
- RETURN(-LLOG_EEMPTY);
+ return -LLOG_EEMPTY;
if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
@@ -131,13 +128,13 @@ static int llog_check_cb(const struct lu_env *env, struct llog_handle *handle,
rec->lrh_len);
}
if (handle->lgh_ctxt == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
rc = llog_cat_id2handle(env, handle, &loghandle, &lir->lid_id);
if (rc) {
CDEBUG(D_IOCTL, "cannot find log #"DOSTID"#%08x\n",
POSTID(&lir->lid_id.lgl_oi),
lir->lid_id.lgl_ogen);
- RETURN(rc);
+ return rc;
}
rc = llog_process(env, loghandle, llog_check_cb, NULL, NULL);
llog_handle_put(loghandle);
@@ -167,10 +164,10 @@ static int llog_check_cb(const struct lu_env *env, struct llog_handle *handle,
if (remains <= 0) {
CERROR("%s: no space to print log records\n",
handle->lgh_ctxt->loc_obd->obd_name);
- RETURN(-LLOG_EEMPTY);
+ return -LLOG_EEMPTY;
}
}
- RETURN(rc);
+ return rc;
}
static int llog_print_cb(const struct lu_env *env, struct llog_handle *handle,
@@ -182,7 +179,6 @@ static int llog_print_cb(const struct lu_env *env, struct llog_handle *handle,
char *endp;
int cur_index;
- ENTRY;
if (ioc_data != NULL && ioc_data->ioc_inllen1 > 0) {
l = 0;
remains = ioc_data->ioc_inllen4 +
@@ -191,26 +187,26 @@ static int llog_print_cb(const struct lu_env *env, struct llog_handle *handle,
cfs_size_round(ioc_data->ioc_inllen3);
from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
if (*endp != '\0')
- RETURN(-EINVAL);
+ return -EINVAL;
to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
if (*endp != '\0')
- RETURN(-EINVAL);
+ return -EINVAL;
out = ioc_data->ioc_bulk;
ioc_data->ioc_inllen1 = 0;
}
cur_index = rec->lrh_index;
if (cur_index < from)
- RETURN(0);
+ return 0;
if (to > 0 && cur_index > to)
- RETURN(-LLOG_EEMPTY);
+ return -LLOG_EEMPTY;
if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
if (rec->lrh_type != LLOG_LOGID_MAGIC) {
CERROR("invalid record in catalog\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
l = snprintf(out, remains,
@@ -222,7 +218,7 @@ static int llog_print_cb(const struct lu_env *env, struct llog_handle *handle,
rc = class_config_parse_rec(rec, out, remains);
if (rc < 0)
- RETURN(rc);
+ return rc;
l = rc;
} else {
l = snprintf(out, remains,
@@ -233,10 +229,10 @@ static int llog_print_cb(const struct lu_env *env, struct llog_handle *handle,
remains -= l;
if (remains <= 0) {
CERROR("not enough space for print log records\n");
- RETURN(-LLOG_EEMPTY);
+ return -LLOG_EEMPTY;
}
- RETURN(0);
+ return 0;
}
static int llog_remove_log(const struct lu_env *env, struct llog_handle *cat,
struct llog_logid *logid)
@@ -244,13 +240,11 @@ static int llog_remove_log(const struct lu_env *env, struct llog_handle *cat,
struct llog_handle *log;
int rc;
- ENTRY;
-
rc = llog_cat_id2handle(env, cat, &log, logid);
if (rc) {
CDEBUG(D_IOCTL, "cannot find log #"DOSTID"#%08x\n",
POSTID(&logid->lgl_oi), logid->lgl_ogen);
- RETURN(-ENOENT);
+ return -ENOENT;
}
rc = llog_destroy(env, log);
@@ -261,7 +255,7 @@ static int llog_remove_log(const struct lu_env *env, struct llog_handle *cat,
llog_cat_cleanup(env, cat, log, log->u.phd.phd_cookie.lgc_index);
out:
llog_handle_put(log);
- RETURN(rc);
+ return rc;
}
@@ -271,12 +265,11 @@ static int llog_delete_cb(const struct lu_env *env, struct llog_handle *handle,
struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
int rc;
- ENTRY;
if (rec->lrh_type != LLOG_LOGID_MAGIC)
- RETURN(-EINVAL);
+ return -EINVAL;
rc = llog_remove_log(env, handle, &lir->lid_id);
- RETURN(rc);
+ return rc;
}
@@ -287,25 +280,23 @@ int llog_ioctl(const struct lu_env *env, struct llog_ctxt *ctxt, int cmd,
int rc = 0;
struct llog_handle *handle = NULL;
- ENTRY;
-
if (*data->ioc_inlbuf1 == '#') {
rc = str2logid(&logid, data->ioc_inlbuf1, data->ioc_inllen1);
if (rc)
- RETURN(rc);
+ return rc;
rc = llog_open(env, ctxt, &handle, &logid, NULL,
LLOG_OPEN_EXISTS);
if (rc)
- RETURN(rc);
+ return rc;
} else if (*data->ioc_inlbuf1 == '$') {
char *name = data->ioc_inlbuf1 + 1;
rc = llog_open(env, ctxt, &handle, NULL, name,
LLOG_OPEN_EXISTS);
if (rc)
- RETURN(rc);
+ return rc;
} else {
- RETURN(-EINVAL);
+ return -EINVAL;
}
rc = llog_init_handle(env, handle, 0, NULL);
@@ -422,6 +413,6 @@ out_close:
llog_cat_close(env, handle);
else
llog_close(env, handle);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_ioctl);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c b/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c
index 7e12dc62141..5385d8e658c 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c
@@ -64,7 +64,6 @@ static int llog_lvfs_pad(struct obd_device *obd, struct l_file *file,
struct llog_rec_hdr rec = { 0 };
struct llog_rec_tail tail;
int rc;
- ENTRY;
LASSERT(len >= LLOG_MIN_REC_SIZE && (len & 0x7) == 0);
@@ -86,7 +85,7 @@ static int llog_lvfs_pad(struct obd_device *obd, struct l_file *file,
}
out:
- RETURN(rc);
+ return rc;
}
static int llog_lvfs_write_blob(struct obd_device *obd, struct l_file *file,
@@ -97,8 +96,6 @@ static int llog_lvfs_write_blob(struct obd_device *obd, struct l_file *file,
loff_t saved_off = file->f_pos;
int buflen = rec->lrh_len;
- ENTRY;
-
file->f_pos = off;
if (buflen == 0)
@@ -140,7 +137,7 @@ static int llog_lvfs_write_blob(struct obd_device *obd, struct l_file *file,
if (saved_off > file->f_pos)
file->f_pos = saved_off;
LASSERT(rc <= 0);
- RETURN(rc);
+ return rc;
}
static int llog_lvfs_read_blob(struct obd_device *obd, struct l_file *file,
@@ -148,14 +145,13 @@ static int llog_lvfs_read_blob(struct obd_device *obd, struct l_file *file,
{
loff_t offset = off;
int rc;
- ENTRY;
rc = fsfilt_read_record(obd, file, buf, size, &offset);
if (rc) {
CERROR("error reading log record: rc %d\n", rc);
- RETURN(rc);
+ return rc;
}
- RETURN(0);
+ return 0;
}
static int llog_lvfs_read_header(const struct lu_env *env,
@@ -163,7 +159,6 @@ static int llog_lvfs_read_header(const struct lu_env *env,
{
struct obd_device *obd;
int rc;
- ENTRY;
LASSERT(sizeof(*handle->lgh_hdr) == LLOG_CHUNK_SIZE);
@@ -171,7 +166,7 @@ static int llog_lvfs_read_header(const struct lu_env *env,
if (i_size_read(handle->lgh_file->f_dentry->d_inode) == 0) {
CDEBUG(D_HA, "not reading header from 0-byte log\n");
- RETURN(LLOG_EEMPTY);
+ return LLOG_EEMPTY;
}
rc = llog_lvfs_read_blob(obd, handle->lgh_file, handle->lgh_hdr,
@@ -206,7 +201,7 @@ static int llog_lvfs_read_header(const struct lu_env *env,
handle->lgh_last_idx = handle->lgh_hdr->llh_tail.lrt_index;
handle->lgh_file->f_pos = i_size_read(handle->lgh_file->f_dentry->d_inode);
- RETURN(rc);
+ return rc;
}
/* returns negative in on error; 0 if success && reccookie == 0; 1 otherwise */
@@ -223,7 +218,6 @@ static int llog_lvfs_write_rec(const struct lu_env *env,
struct obd_device *obd;
struct file *file;
size_t left;
- ENTRY;
llh = loghandle->lgh_hdr;
file = loghandle->lgh_file;
@@ -236,7 +230,7 @@ static int llog_lvfs_write_rec(const struct lu_env *env,
else
rc = (reclen > LLOG_CHUNK_SIZE) ? -E2BIG : 0;
if (rc)
- RETURN(rc);
+ return rc;
if (buf)
/* write_blob adds header and tail to lrh_len. */
@@ -253,7 +247,7 @@ static int llog_lvfs_write_rec(const struct lu_env *env,
}
if (idx && llh->llh_size && llh->llh_size != rec->lrh_len)
- RETURN(-EINVAL);
+ return -EINVAL;
if (!ext2_test_bit(idx, llh->llh_bitmap))
CERROR("Modify unset record %u\n", idx);
@@ -263,7 +257,7 @@ static int llog_lvfs_write_rec(const struct lu_env *env,
rc = llog_lvfs_write_blob(obd, file, &llh->llh_hdr, NULL, 0);
/* we are done if we only write the header or on error */
if (rc || idx == 0)
- RETURN(rc);
+ return rc;
if (buf) {
/* We assume that caller has set lgh_cur_* */
@@ -277,7 +271,7 @@ static int llog_lvfs_write_rec(const struct lu_env *env,
if (rec->lrh_index != loghandle->lgh_cur_idx) {
CERROR("modify idx mismatch %u/%d\n",
idx, loghandle->lgh_cur_idx);
- RETURN(-EFAULT);
+ return -EFAULT;
}
} else {
/* Assumes constant lrh_len */
@@ -290,7 +284,7 @@ static int llog_lvfs_write_rec(const struct lu_env *env,
reccookie->lgc_index = idx;
rc = 1;
}
- RETURN(rc);
+ return rc;
}
/* Make sure that records don't cross a chunk boundary, so we can
@@ -308,12 +302,12 @@ static int llog_lvfs_write_rec(const struct lu_env *env,
index = loghandle->lgh_last_idx + 1;
rc = llog_lvfs_pad(obd, file, left, index);
if (rc)
- RETURN(rc);
+ return rc;
loghandle->lgh_last_idx++; /*for pad rec*/
}
/* if it's the last idx in log file, then return -ENOSPC */
if (loghandle->lgh_last_idx >= LLOG_BITMAP_SIZE(llh) - 1)
- RETURN(-ENOSPC);
+ return -ENOSPC;
loghandle->lgh_last_idx++;
index = loghandle->lgh_last_idx;
LASSERT(index < LLOG_BITMAP_SIZE(llh));
@@ -339,11 +333,11 @@ static int llog_lvfs_write_rec(const struct lu_env *env,
rc = llog_lvfs_write_blob(obd, file, &llh->llh_hdr, NULL, 0);
if (rc)
- RETURN(rc);
+ return rc;
rc = llog_lvfs_write_blob(obd, file, rec, buf, file->f_pos);
if (rc)
- RETURN(rc);
+ return rc;
CDEBUG(D_RPCTRACE, "added record "DOSTID": idx: %u, %u \n",
POSTID(&loghandle->lgh_id.lgl_oi), index, rec->lrh_len);
@@ -362,7 +356,7 @@ static int llog_lvfs_write_rec(const struct lu_env *env,
if (rc == 0 && rec->lrh_type == LLOG_GEN_REC)
rc = 1;
- RETURN(rc);
+ return rc;
}
/* We can skip reading at least as many log blocks as the number of
@@ -391,10 +385,9 @@ static int llog_lvfs_next_block(const struct lu_env *env,
int len)
{
int rc;
- ENTRY;
if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
- RETURN(-EINVAL);
+ return -EINVAL;
CDEBUG(D_OTHER, "looking for log index %u (cur idx %u off "LPU64")\n",
next_idx, *cur_idx, *cur_offset);
@@ -419,7 +412,7 @@ static int llog_lvfs_next_block(const struct lu_env *env,
POSTID(&loghandle->lgh_id.lgl_oi),
loghandle->lgh_id.lgl_ogen,
*cur_offset);
- RETURN(rc);
+ return rc;
}
/* put number of bytes read into rc to make code simpler */
@@ -430,13 +423,13 @@ static int llog_lvfs_next_block(const struct lu_env *env,
}
if (rc == 0) /* end of file, nothing to do */
- RETURN(0);
+ return 0;
if (rc < sizeof(*tail)) {
CERROR("Invalid llog block at log id "DOSTID"/%u offset"
LPU64"\n", POSTID(&loghandle->lgh_id.lgl_oi),
loghandle->lgh_id.lgl_ogen, *cur_offset);
- RETURN(-EINVAL);
+ return -EINVAL;
}
rec = buf;
@@ -461,7 +454,7 @@ static int llog_lvfs_next_block(const struct lu_env *env,
CERROR("Invalid llog tail at log id "DOSTID"/%u offset "
LPU64"\n", POSTID(&loghandle->lgh_id.lgl_oi),
loghandle->lgh_id.lgl_ogen, *cur_offset);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (tail->lrt_index < next_idx)
continue;
@@ -471,11 +464,11 @@ static int llog_lvfs_next_block(const struct lu_env *env,
if (rec->lrh_index > next_idx) {
CERROR("missed desired record? %u > %u\n",
rec->lrh_index, next_idx);
- RETURN(-ENOENT);
+ return -ENOENT;
}
- RETURN(0);
+ return 0;
}
- RETURN(-EIO);
+ return -EIO;
}
static int llog_lvfs_prev_block(const struct lu_env *env,
@@ -484,10 +477,9 @@ static int llog_lvfs_prev_block(const struct lu_env *env,
{
__u64 cur_offset;
int rc;
- ENTRY;
if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
- RETURN(-EINVAL);
+ return -EINVAL;
CDEBUG(D_OTHER, "looking for log index %u\n", prev_idx);
@@ -508,20 +500,20 @@ static int llog_lvfs_prev_block(const struct lu_env *env,
POSTID(&loghandle->lgh_id.lgl_oi),
loghandle->lgh_id.lgl_ogen,
cur_offset);
- RETURN(rc);
+ return rc;
}
/* put number of bytes read into rc to make code simpler */
rc = cur_offset - ppos;
if (rc == 0) /* end of file, nothing to do */
- RETURN(0);
+ return 0;
if (rc < sizeof(*tail)) {
CERROR("Invalid llog block at log id "DOSTID"/%u offset"
LPU64"\n", POSTID(&loghandle->lgh_id.lgl_oi),
loghandle->lgh_id.lgl_ogen, cur_offset);
- RETURN(-EINVAL);
+ return -EINVAL;
}
rec = buf;
@@ -544,7 +536,7 @@ static int llog_lvfs_prev_block(const struct lu_env *env,
CERROR("Invalid llog tail at log id "DOSTID"/%u offset"
LPU64"\n", POSTID(&loghandle->lgh_id.lgl_oi),
loghandle->lgh_id.lgl_ogen, cur_offset);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (tail->lrt_index < prev_idx)
continue;
@@ -554,11 +546,11 @@ static int llog_lvfs_prev_block(const struct lu_env *env,
if (rec->lrh_index > prev_idx) {
CERROR("missed desired record? %u > %u\n",
rec->lrh_index, prev_idx);
- RETURN(-ENOENT);
+ return -ENOENT;
}
- RETURN(0);
+ return 0;
}
- RETURN(-EIO);
+ return -EIO;
}
static struct file *llog_filp_open(char *dir, char *name, int flags, int mode)
@@ -593,8 +585,6 @@ static int llog_lvfs_open(const struct lu_env *env, struct llog_handle *handle,
struct obd_device *obd;
int rc = 0;
- ENTRY;
-
LASSERT(ctxt);
LASSERT(ctxt->loc_exp);
LASSERT(ctxt->loc_exp->exp_obd);
@@ -661,12 +651,12 @@ static int llog_lvfs_open(const struct lu_env *env, struct llog_handle *handle,
if (open_param != LLOG_OPEN_NEW && handle->lgh_file == NULL)
GOTO(out_name, rc = -ENOENT);
- RETURN(0);
+ return 0;
out_name:
if (handle->lgh_name != NULL)
OBD_FREE(handle->lgh_name, strlen(name) + 1);
out:
- RETURN(rc);
+ return rc;
}
static int llog_lvfs_exist(struct llog_handle *handle)
@@ -688,8 +678,6 @@ static int llog_lvfs_create(const struct lu_env *env,
int rc = 0;
int open_flags = O_RDWR | O_CREAT | O_LARGEFILE;
- ENTRY;
-
LASSERT(ctxt);
LASSERT(ctxt->loc_exp);
obd = ctxt->loc_exp->exp_obd;
@@ -699,7 +687,7 @@ static int llog_lvfs_create(const struct lu_env *env,
file = llog_filp_open(MOUNT_CONFIGS_DIR, handle->lgh_name,
open_flags, 0644);
if (IS_ERR(file))
- RETURN(PTR_ERR(file));
+ return PTR_ERR(file);
lustre_build_llog_lvfs_oid(&handle->lgh_id,
file->f_dentry->d_inode->i_ino,
@@ -708,7 +696,7 @@ static int llog_lvfs_create(const struct lu_env *env,
} else {
OBDO_ALLOC(oa);
if (oa == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
ostid_set_seq_llog(&oa->o_oi);
oa->o_valid = OBD_MD_FLGENER | OBD_MD_FLGROUP;
@@ -736,7 +724,7 @@ static int llog_lvfs_create(const struct lu_env *env,
out:
OBDO_FREE(oa);
}
- RETURN(rc);
+ return rc;
}
static int llog_lvfs_close(const struct lu_env *env,
@@ -744,10 +732,8 @@ static int llog_lvfs_close(const struct lu_env *env,
{
int rc;
- ENTRY;
-
if (handle->lgh_file == NULL)
- RETURN(0);
+ return 0;
rc = filp_close(handle->lgh_file, 0);
if (rc)
CERROR("%s: error closing llog #"DOSTID"#%08x: "
@@ -759,7 +745,7 @@ static int llog_lvfs_close(const struct lu_env *env,
OBD_FREE(handle->lgh_name, strlen(handle->lgh_name) + 1);
handle->lgh_name = NULL;
}
- RETURN(rc);
+ return rc;
}
static int llog_lvfs_destroy(const struct lu_env *env,
@@ -772,7 +758,6 @@ static int llog_lvfs_destroy(const struct lu_env *env,
void *th;
struct inode *inode;
int rc, rc1;
- ENTRY;
dir = MOUNT_CONFIGS_DIR;
@@ -795,12 +780,12 @@ static int llog_lvfs_destroy(const struct lu_env *env,
dput(fdentry);
pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
- RETURN(rc);
+ return rc;
}
OBDO_ALLOC(oa);
if (oa == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
oa->o_oi = handle->lgh_id.lgl_oi;
oa->o_generation = handle->lgh_id.lgl_ogen;
@@ -825,7 +810,7 @@ static int llog_lvfs_destroy(const struct lu_env *env,
rc = rc1;
out:
OBDO_FREE(oa);
- RETURN(rc);
+ return rc;
}
static int llog_lvfs_declare_create(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c
index 7e229079631..71817af7539 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_obd.c
@@ -110,7 +110,6 @@ int llog_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt)
struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
struct obd_llog_group *olg;
int rc, idx;
- ENTRY;
LASSERT(ctxt != NULL);
LASSERT(ctxt != LP_POISON);
@@ -139,7 +138,7 @@ int llog_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt)
l_wait_event(olg->olg_waitq,
llog_group_ctxt_null(olg, idx), &lwi);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_cleanup);
@@ -149,16 +148,15 @@ int llog_setup(const struct lu_env *env, struct obd_device *obd,
{
struct llog_ctxt *ctxt;
int rc = 0;
- ENTRY;
if (index < 0 || index >= LLOG_MAX_CTXTS)
- RETURN(-EINVAL);
+ return -EINVAL;
LASSERT(olg != NULL);
ctxt = llog_new_ctxt(obd);
if (!ctxt)
- RETURN(-ENOMEM);
+ return -ENOMEM;
ctxt->loc_obd = obd;
ctxt->loc_olg = olg;
@@ -189,7 +187,7 @@ int llog_setup(const struct lu_env *env, struct obd_device *obd,
}
rc = 0;
}
- RETURN(rc);
+ return rc;
}
if (op->lop_setup) {
@@ -210,22 +208,21 @@ int llog_setup(const struct lu_env *env, struct obd_device *obd,
ctxt->loc_flags &= ~LLOG_CTXT_FLAG_UNINITIALIZED;
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_setup);
int llog_sync(struct llog_ctxt *ctxt, struct obd_export *exp, int flags)
{
int rc = 0;
- ENTRY;
if (!ctxt)
- RETURN(0);
+ return 0;
if (CTXTP(ctxt, sync))
rc = CTXTP(ctxt, sync)(ctxt, exp, flags);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_sync);
@@ -234,15 +231,14 @@ int llog_obd_add(const struct lu_env *env, struct llog_ctxt *ctxt,
struct llog_cookie *logcookies, int numcookies)
{
int raised, rc;
- ENTRY;
if (!ctxt) {
CERROR("No ctxt\n");
- RETURN(-ENODEV);
+ return -ENODEV;
}
if (ctxt->loc_flags & LLOG_CTXT_FLAG_UNINITIALIZED)
- RETURN(-ENXIO);
+ return -ENXIO;
CTXT_CHECK_OP(ctxt, obd_add, -EOPNOTSUPP);
raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
@@ -252,7 +248,7 @@ int llog_obd_add(const struct lu_env *env, struct llog_ctxt *ctxt,
numcookies);
if (!raised)
cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_obd_add);
@@ -261,16 +257,15 @@ int llog_cancel(const struct lu_env *env, struct llog_ctxt *ctxt,
struct llog_cookie *cookies, int flags)
{
int rc;
- ENTRY;
if (!ctxt) {
CERROR("No ctxt\n");
- RETURN(-ENODEV);
+ return -ENODEV;
}
CTXT_CHECK_OP(ctxt, cancel, -EOPNOTSUPP);
rc = CTXTP(ctxt, cancel)(env, ctxt, lsm, count, cookies, flags);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_cancel);
@@ -278,24 +273,24 @@ int obd_llog_init(struct obd_device *obd, struct obd_llog_group *olg,
struct obd_device *disk_obd, int *index)
{
int rc;
- ENTRY;
+
OBD_CHECK_DT_OP(obd, llog_init, 0);
OBD_COUNTER_INCREMENT(obd, llog_init);
rc = OBP(obd, llog_init)(obd, olg, disk_obd, index);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(obd_llog_init);
int obd_llog_finish(struct obd_device *obd, int count)
{
int rc;
- ENTRY;
+
OBD_CHECK_DT_OP(obd, llog_finish, 0);
OBD_COUNTER_INCREMENT(obd, llog_finish);
rc = OBP(obd, llog_finish)(obd, count);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(obd_llog_finish);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_osd.c b/drivers/staging/lustre/lustre/obdclass/llog_osd.c
index 6dbd21a863c..654c8e18965 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_osd.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_osd.c
@@ -41,10 +41,6 @@
#define DEBUG_SUBSYSTEM S_LOG
-#ifndef EXPORT_SYMTAB
-#define EXPORT_SYMTAB
-#endif
-
#include <obd.h>
#include <obd_class.h>
#include <lustre_fid.h>
@@ -97,8 +93,6 @@ static int llog_osd_pad(const struct lu_env *env, struct dt_object *o,
struct llog_thread_info *lgi = llog_info(env);
int rc;
- ENTRY;
-
LASSERT(th);
LASSERT(off);
LASSERT(len >= LLOG_MIN_REC_SIZE && (len & 0x7) == 0);
@@ -126,7 +120,7 @@ static int llog_osd_pad(const struct lu_env *env, struct dt_object *o,
o->do_lu.lo_dev->ld_obd->obd_name, rc);
out:
dt_write_unlock(env, o);
- RETURN(rc);
+ return rc;
}
static int llog_osd_write_blob(const struct lu_env *env, struct dt_object *o,
@@ -137,8 +131,6 @@ static int llog_osd_write_blob(const struct lu_env *env, struct dt_object *o,
int buflen = rec->lrh_len;
int rc;
- ENTRY;
-
LASSERT(env);
LASSERT(o);
@@ -203,7 +195,7 @@ out:
dt_attr_set(env, o, &lgi->lgi_attr, th, BYPASS_CAPA);
}
- RETURN(rc);
+ return rc;
}
static int llog_osd_read_header(const struct lu_env *env,
@@ -214,8 +206,6 @@ static int llog_osd_read_header(const struct lu_env *env,
struct llog_thread_info *lgi;
int rc;
- ENTRY;
-
LASSERT(sizeof(*handle->lgh_hdr) == LLOG_CHUNK_SIZE);
o = handle->lgh_obj;
@@ -225,13 +215,13 @@ static int llog_osd_read_header(const struct lu_env *env,
rc = dt_attr_get(env, o, &lgi->lgi_attr, NULL);
if (rc)
- RETURN(rc);
+ return rc;
LASSERT(lgi->lgi_attr.la_valid & LA_SIZE);
if (lgi->lgi_attr.la_size == 0) {
CDEBUG(D_HA, "not reading header from 0-byte log\n");
- RETURN(LLOG_EEMPTY);
+ return LLOG_EEMPTY;
}
lgi->lgi_off = 0;
@@ -243,7 +233,7 @@ static int llog_osd_read_header(const struct lu_env *env,
CERROR("%s: error reading log header from "DFID": rc = %d\n",
o->do_lu.lo_dev->ld_obd->obd_name,
PFID(lu_object_fid(&o->do_lu)), rc);
- RETURN(rc);
+ return rc;
}
llh_hdr = &handle->lgh_hdr->llh_hdr;
@@ -256,7 +246,7 @@ static int llog_osd_read_header(const struct lu_env *env,
handle->lgh_name ? handle->lgh_name : "",
PFID(lu_object_fid(&o->do_lu)),
llh_hdr->lrh_type, LLOG_HDR_MAGIC);
- RETURN(-EIO);
+ return -EIO;
} else if (llh_hdr->lrh_len != LLOG_CHUNK_SIZE) {
CERROR("%s: incorrectly sized log %s "DFID" header: "
"%#x (expected %#x)\n"
@@ -265,12 +255,12 @@ static int llog_osd_read_header(const struct lu_env *env,
handle->lgh_name ? handle->lgh_name : "",
PFID(lu_object_fid(&o->do_lu)),
llh_hdr->lrh_len, LLOG_CHUNK_SIZE);
- RETURN(-EIO);
+ return -EIO;
}
handle->lgh_last_idx = handle->lgh_hdr->llh_tail.lrt_index;
- RETURN(0);
+ return 0;
}
static int llog_osd_declare_write_rec(const struct lu_env *env,
@@ -282,8 +272,6 @@ static int llog_osd_declare_write_rec(const struct lu_env *env,
struct dt_object *o;
int rc;
- ENTRY;
-
LASSERT(env);
LASSERT(th);
LASSERT(loghandle);
@@ -295,18 +283,18 @@ static int llog_osd_declare_write_rec(const struct lu_env *env,
rc = dt_declare_record_write(env, o, sizeof(struct llog_log_hdr), 0,
th);
if (rc || idx == 0) /* if error or just header */
- RETURN(rc);
+ return rc;
if (dt_object_exists(o)) {
rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA);
lgi->lgi_off = lgi->lgi_attr.la_size;
LASSERT(ergo(rc == 0, lgi->lgi_attr.la_valid & LA_SIZE));
if (rc)
- RETURN(rc);
+ return rc;
rc = dt_declare_punch(env, o, lgi->lgi_off, OBD_OBJECT_EOF, th);
if (rc)
- RETURN(rc);
+ return rc;
} else {
lgi->lgi_off = 0;
}
@@ -314,7 +302,7 @@ static int llog_osd_declare_write_rec(const struct lu_env *env,
/* XXX: implement declared window or multi-chunks approach */
rc = dt_declare_record_write(env, o, 32 * 1024, lgi->lgi_off, th);
- RETURN(rc);
+ return rc;
}
/* returns negative in on error; 0 if success && reccookie == 0; 1 otherwise */
@@ -333,8 +321,6 @@ static int llog_osd_write_rec(const struct lu_env *env,
struct dt_object *o;
size_t left;
- ENTRY;
-
LASSERT(env);
llh = loghandle->lgh_hdr;
LASSERT(llh);
@@ -352,11 +338,11 @@ static int llog_osd_write_rec(const struct lu_env *env,
else
rc = (reclen > LLOG_CHUNK_SIZE) ? -E2BIG : 0;
if (rc)
- RETURN(rc);
+ return rc;
rc = dt_attr_get(env, o, &lgi->lgi_attr, NULL);
if (rc)
- RETURN(rc);
+ return rc;
if (buf)
/* write_blob adds header and tail to lrh_len. */
@@ -369,7 +355,7 @@ static int llog_osd_write_rec(const struct lu_env *env,
LBUG();
if (idx && llh->llh_size && llh->llh_size != rec->lrh_len)
- RETURN(-EINVAL);
+ return -EINVAL;
if (!ext2_test_bit(idx, llh->llh_bitmap))
CERROR("%s: modify unset record %u\n",
@@ -384,7 +370,7 @@ static int llog_osd_write_rec(const struct lu_env *env,
&lgi->lgi_off, th);
/* we are done if we only write the header or on error */
if (rc || idx == 0)
- RETURN(rc);
+ return rc;
if (buf) {
/* We assume that caller has set lgh_cur_* */
@@ -400,7 +386,7 @@ static int llog_osd_write_rec(const struct lu_env *env,
CERROR("%s: modify idx mismatch %u/%d\n",
o->do_lu.lo_dev->ld_obd->obd_name, idx,
loghandle->lgh_cur_idx);
- RETURN(-EFAULT);
+ return -EFAULT;
}
} else {
/* Assumes constant lrh_len */
@@ -413,7 +399,7 @@ static int llog_osd_write_rec(const struct lu_env *env,
reccookie->lgc_index = idx;
rc = 1;
}
- RETURN(rc);
+ return rc;
}
/* Make sure that records don't cross a chunk boundary, so we can
@@ -432,12 +418,12 @@ static int llog_osd_write_rec(const struct lu_env *env,
index = loghandle->lgh_last_idx + 1;
rc = llog_osd_pad(env, o, &lgi->lgi_off, left, index, th);
if (rc)
- RETURN(rc);
+ return rc;
loghandle->lgh_last_idx++; /*for pad rec*/
}
/* if it's the last idx in log file, then return -ENOSPC */
if (loghandle->lgh_last_idx >= LLOG_BITMAP_SIZE(llh) - 1)
- RETURN(-ENOSPC);
+ return -ENOSPC;
loghandle->lgh_last_idx++;
index = loghandle->lgh_last_idx;
@@ -509,7 +495,7 @@ out:
reccookie->lgc_subsys = -1;
rc = 1;
}
- RETURN(rc);
+ return rc;
}
/* We can skip reading at least as many log blocks as the number of
@@ -541,13 +527,11 @@ static int llog_osd_next_block(const struct lu_env *env,
struct dt_device *dt;
int rc;
- ENTRY;
-
LASSERT(env);
LASSERT(lgi);
if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
- RETURN(-EINVAL);
+ return -EINVAL;
CDEBUG(D_OTHER, "looking for log index %u (cur idx %u off "LPU64")\n",
next_idx, *cur_idx, *cur_offset);
@@ -668,10 +652,8 @@ static int llog_osd_prev_block(const struct lu_env *env,
loff_t cur_offset;
int rc;
- ENTRY;
-
if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
- RETURN(-EINVAL);
+ return -EINVAL;
CDEBUG(D_OTHER, "looking for log index %u\n", prev_idx);
@@ -798,8 +780,6 @@ static int llog_osd_open(const struct lu_env *env, struct llog_handle *handle,
struct local_oid_storage *los;
int rc = 0;
- ENTRY;
-
LASSERT(env);
LASSERT(ctxt);
LASSERT(ctxt->loc_exp);
@@ -809,7 +789,7 @@ static int llog_osd_open(const struct lu_env *env, struct llog_handle *handle,
ls = ls_device_get(dt);
if (IS_ERR(ls))
- RETURN(PTR_ERR(ls));
+ return PTR_ERR(ls);
mutex_lock(&ls->ls_los_mutex);
los = dt_los_find(ls, name != NULL ? FID_SEQ_LLOG_NAME : FID_SEQ_LLOG);
@@ -864,7 +844,7 @@ static int llog_osd_open(const struct lu_env *env, struct llog_handle *handle,
handle->private_data = los;
LASSERT(handle->lgh_ctxt);
- RETURN(rc);
+ return rc;
out_put:
lu_object_put(env, &o->do_lu);
@@ -873,7 +853,7 @@ out_name:
OBD_FREE(handle->lgh_name, strlen(name) + 1);
out:
dt_los_put(los);
- RETURN(rc);
+ return rc;
}
static int llog_osd_exist(struct llog_handle *handle)
@@ -891,33 +871,31 @@ static int llog_osd_declare_create(const struct lu_env *env,
struct dt_object *o;
int rc;
- ENTRY;
-
LASSERT(res->lgh_obj);
LASSERT(th);
/* object can be created by another thread */
o = res->lgh_obj;
if (dt_object_exists(o))
- RETURN(0);
+ return 0;
los = res->private_data;
LASSERT(los);
rc = llog_osd_declare_new_object(env, los, o, th);
if (rc)
- RETURN(rc);
+ return rc;
rc = dt_declare_record_write(env, o, LLOG_CHUNK_SIZE, 0, th);
if (rc)
- RETURN(rc);
+ return rc;
if (res->lgh_name) {
struct dt_object *llog_dir;
llog_dir = llog_osd_dir_get(env, res->lgh_ctxt);
if (IS_ERR(llog_dir))
- RETURN(PTR_ERR(llog_dir));
+ return PTR_ERR(llog_dir);
logid_to_fid(&res->lgh_id, &lgi->lgi_fid);
rc = dt_declare_insert(env, llog_dir,
(struct dt_rec *)&lgi->lgi_fid,
@@ -928,7 +906,7 @@ static int llog_osd_declare_create(const struct lu_env *env,
o->do_lu.lo_dev->ld_obd->obd_name,
res->lgh_name, rc);
}
- RETURN(rc);
+ return rc;
}
/* This is a callback from the llog_* functions.
@@ -941,15 +919,13 @@ static int llog_osd_create(const struct lu_env *env, struct llog_handle *res,
struct dt_object *o;
int rc = 0;
- ENTRY;
-
LASSERT(env);
o = res->lgh_obj;
LASSERT(o);
/* llog can be already created */
if (dt_object_exists(o))
- RETURN(-EEXIST);
+ return -EEXIST;
los = res->private_data;
LASSERT(los);
@@ -962,14 +938,14 @@ static int llog_osd_create(const struct lu_env *env, struct llog_handle *res,
dt_write_unlock(env, o);
if (rc)
- RETURN(rc);
+ return rc;
if (res->lgh_name) {
struct dt_object *llog_dir;
llog_dir = llog_osd_dir_get(env, res->lgh_ctxt);
if (IS_ERR(llog_dir))
- RETURN(PTR_ERR(llog_dir));
+ return PTR_ERR(llog_dir);
logid_to_fid(&res->lgh_id, &lgi->lgi_fid);
dt_read_lock(env, llog_dir, 0);
@@ -984,7 +960,7 @@ static int llog_osd_create(const struct lu_env *env, struct llog_handle *res,
o->do_lu.lo_dev->ld_obd->obd_name,
res->lgh_name, rc);
}
- RETURN(rc);
+ return rc;
}
static int llog_osd_close(const struct lu_env *env, struct llog_handle *handle)
@@ -992,8 +968,6 @@ static int llog_osd_close(const struct lu_env *env, struct llog_handle *handle)
struct local_oid_storage *los;
int rc = 0;
- ENTRY;
-
LASSERT(handle->lgh_obj);
lu_object_put(env, &handle->lgh_obj->do_lu);
@@ -1005,7 +979,7 @@ static int llog_osd_close(const struct lu_env *env, struct llog_handle *handle)
if (handle->lgh_name)
OBD_FREE(handle->lgh_name, strlen(handle->lgh_name) + 1);
- RETURN(rc);
+ return rc;
}
static int llog_osd_destroy(const struct lu_env *env,
@@ -1018,8 +992,6 @@ static int llog_osd_destroy(const struct lu_env *env,
char *name = NULL;
int rc;
- ENTRY;
-
ctxt = loghandle->lgh_ctxt;
LASSERT(ctxt);
@@ -1032,7 +1004,7 @@ static int llog_osd_destroy(const struct lu_env *env,
th = dt_trans_create(env, d);
if (IS_ERR(th))
- RETURN(PTR_ERR(th));
+ return PTR_ERR(th);
if (loghandle->lgh_name) {
llog_dir = llog_osd_dir_get(env, ctxt);
@@ -1082,7 +1054,7 @@ out_trans:
dt_trans_stop(env, d, th);
if (llog_dir != NULL)
lu_object_put(env, &llog_dir->do_lu);
- RETURN(rc);
+ return rc;
}
static int llog_osd_setup(const struct lu_env *env, struct obd_device *obd,
@@ -1094,8 +1066,6 @@ static int llog_osd_setup(const struct lu_env *env, struct obd_device *obd,
struct llog_ctxt *ctxt;
int rc = 0;
- ENTRY;
-
LASSERT(obd);
LASSERT(olg->olg_ctxts[ctxt_idx]);
@@ -1131,7 +1101,7 @@ static int llog_osd_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt)
dt = ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt;
ls = ls_device_get(dt);
if (IS_ERR(ls))
- RETURN(PTR_ERR(ls));
+ return PTR_ERR(ls);
mutex_lock(&ls->ls_los_mutex);
los = dt_los_find(ls, FID_SEQ_LLOG);
@@ -1175,8 +1145,6 @@ int llog_osd_get_cat_list(const struct lu_env *env, struct dt_device *d,
struct thandle *th;
int rc, size;
- ENTRY;
-
LASSERT(d);
size = sizeof(*idarray) * count;
@@ -1186,7 +1154,7 @@ int llog_osd_get_cat_list(const struct lu_env *env, struct dt_device *d,
o = dt_locate(env, d, &lgi->lgi_fid);
if (IS_ERR(o))
- RETURN(PTR_ERR(o));
+ return PTR_ERR(o);
if (!dt_object_exists(o)) {
th = dt_trans_create(env, d);
@@ -1253,10 +1221,9 @@ out_trans:
GOTO(out, rc);
}
- EXIT;
out:
lu_object_put(env, &o->do_lu);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_osd_get_cat_list);
@@ -1270,7 +1237,7 @@ int llog_osd_put_cat_list(const struct lu_env *env, struct dt_device *d,
int rc, size;
if (!count)
- RETURN(0);
+ return 0;
LASSERT(d);
@@ -1281,7 +1248,7 @@ int llog_osd_put_cat_list(const struct lu_env *env, struct dt_device *d,
o = dt_locate(env, d, &lgi->lgi_fid);
if (IS_ERR(o))
- RETURN(PTR_ERR(o));
+ return PTR_ERR(o);
if (!dt_object_exists(o))
GOTO(out, rc = -ENOENT);
@@ -1318,6 +1285,6 @@ out_trans:
dt_trans_stop(env, d, th);
out:
lu_object_put(env, &o->do_lu);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_osd_put_cat_list);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_swab.c b/drivers/staging/lustre/lustre/obdclass/llog_swab.c
index dedfecff95b..24ca099b01d 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_swab.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_swab.c
@@ -88,7 +88,6 @@ EXPORT_SYMBOL(lustre_swab_llog_id);
void lustre_swab_llogd_body (struct llogd_body *d)
{
- ENTRY;
print_llogd_body(d);
lustre_swab_llog_id(&d->lgd_logid);
__swab32s (&d->lgd_ctxt_idx);
@@ -98,7 +97,6 @@ void lustre_swab_llogd_body (struct llogd_body *d)
__swab32s (&d->lgd_len);
__swab64s (&d->lgd_cur_offset);
print_llogd_body(d);
- EXIT;
}
EXPORT_SYMBOL(lustre_swab_llogd_body);
@@ -203,6 +201,23 @@ void lustre_swab_llog_rec(struct llog_rec_hdr *rec)
break;
}
+ case HSM_AGENT_REC: {
+ struct llog_agent_req_rec *arr =
+ (struct llog_agent_req_rec *)rec;
+
+ __swab32s(&arr->arr_hai.hai_len);
+ __swab32s(&arr->arr_hai.hai_action);
+ lustre_swab_lu_fid(&arr->arr_hai.hai_fid);
+ lustre_swab_lu_fid(&arr->arr_hai.hai_dfid);
+ __swab64s(&arr->arr_hai.hai_cookie);
+ __swab64s(&arr->arr_hai.hai_extent.offset);
+ __swab64s(&arr->arr_hai.hai_extent.length);
+ __swab64s(&arr->arr_hai.hai_gid);
+ /* no swabing for opaque data */
+ /* hai_data[0]; */
+ break;
+ }
+
case MDS_SETATTR64_REC:
{
struct llog_setattr64_rec *lsr =
@@ -281,20 +296,17 @@ static void print_llog_hdr(struct llog_log_hdr *h)
void lustre_swab_llog_hdr (struct llog_log_hdr *h)
{
- ENTRY;
print_llog_hdr(h);
lustre_swab_llog_rec(&h->llh_hdr);
print_llog_hdr(h);
- EXIT;
}
EXPORT_SYMBOL(lustre_swab_llog_hdr);
static void print_lustre_cfg(struct lustre_cfg *lcfg)
{
int i;
- ENTRY;
if (!(libcfs_debug & D_OTHER)) /* don't loop on nothing */
return;
@@ -311,20 +323,17 @@ static void print_lustre_cfg(struct lustre_cfg *lcfg)
for (i = 0; i < lcfg->lcfg_bufcount; i++)
CDEBUG(D_OTHER, "\tlcfg->lcfg_buflens[%d]: %d\n",
i, lcfg->lcfg_buflens[i]);
- EXIT;
}
void lustre_swab_lustre_cfg(struct lustre_cfg *lcfg)
{
int i;
- ENTRY;
__swab32s(&lcfg->lcfg_version);
if (lcfg->lcfg_version != LUSTRE_CFG_VERSION) {
CERROR("not swabbing lustre_cfg version %#x (expecting %#x)\n",
lcfg->lcfg_version, LUSTRE_CFG_VERSION);
- EXIT;
return;
}
@@ -337,7 +346,6 @@ void lustre_swab_lustre_cfg(struct lustre_cfg *lcfg)
__swab32s(&lcfg->lcfg_buflens[i]);
print_lustre_cfg(lcfg);
- EXIT;
return;
}
EXPORT_SYMBOL(lustre_swab_lustre_cfg);
@@ -360,7 +368,6 @@ struct cfg_marker32 {
void lustre_swab_cfg_marker(struct cfg_marker *marker, int swab, int size)
{
struct cfg_marker32 *cm32 = (struct cfg_marker32*)marker;
- ENTRY;
if (swab) {
__swab32s(&marker->cm_step);
@@ -401,7 +408,6 @@ void lustre_swab_cfg_marker(struct cfg_marker *marker, int swab, int size)
__swab64s(&marker->cm_canceltime);
}
- EXIT;
return;
}
EXPORT_SYMBOL(lustre_swab_cfg_marker);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_test.c b/drivers/staging/lustre/lustre/obdclass/llog_test.c
index d397f781ec4..d9e6d12215f 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_test.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_test.c
@@ -78,22 +78,22 @@ static int verify_handle(char *test, struct llog_handle *llh, int num_recs)
if (active_recs != num_recs) {
CERROR("%s: expected %d active recs after write, found %d\n",
test, num_recs, active_recs);
- RETURN(-ERANGE);
+ return -ERANGE;
}
if (llh->lgh_hdr->llh_count != num_recs) {
CERROR("%s: handle->count is %d, expected %d after write\n",
test, llh->lgh_hdr->llh_count, num_recs);
- RETURN(-ERANGE);
+ return -ERANGE;
}
if (llh->lgh_last_idx < last_idx) {
CERROR("%s: handle->last_idx is %d, expected %d after write\n",
test, llh->lgh_last_idx, last_idx);
- RETURN(-ERANGE);
+ return -ERANGE;
}
- RETURN(0);
+ return 0;
}
/* Test named-log create/open, close */
@@ -105,8 +105,6 @@ static int llog_test_1(const struct lu_env *env,
int rc;
int rc2;
- ENTRY;
-
CWARN("1a: create a log with name: %s\n", name);
ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
LASSERT(ctxt);
@@ -134,7 +132,7 @@ out_close:
}
out:
llog_ctxt_put(ctxt);
- RETURN(rc);
+ return rc;
}
/* Test named-log reopen; returns opened log on success */
@@ -146,8 +144,6 @@ static int llog_test_2(const struct lu_env *env, struct obd_device *obd,
struct llog_logid logid;
int rc;
- ENTRY;
-
CWARN("2a: re-open a log with name: %s\n", name);
ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
LASSERT(ctxt);
@@ -213,7 +209,7 @@ out_close_llh:
out_put:
llog_ctxt_put(ctxt);
- RETURN(rc);
+ return rc;
}
/* Test record writing, single and in bulk */
@@ -224,8 +220,6 @@ static int llog_test_3(const struct lu_env *env, struct obd_device *obd,
int rc, i;
int num_recs = 1; /* 1 for the header */
- ENTRY;
-
lgr.lgr_hdr.lrh_len = lgr.lgr_tail.lrt_len = sizeof(lgr);
lgr.lgr_hdr.lrh_type = LLOG_GEN_REC;
@@ -234,12 +228,12 @@ static int llog_test_3(const struct lu_env *env, struct obd_device *obd,
num_recs++;
if (rc < 0) {
CERROR("3a: write one log record failed: %d\n", rc);
- RETURN(rc);
+ return rc;
}
rc = verify_handle("3a", llh, num_recs);
if (rc)
- RETURN(rc);
+ return rc;
CWARN("3b: write 10 cfg log records with 8 bytes bufs\n");
for (i = 0; i < 10; i++) {
@@ -253,14 +247,14 @@ static int llog_test_3(const struct lu_env *env, struct obd_device *obd,
if (rc < 0) {
CERROR("3b: write 10 records failed at #%d: %d\n",
i + 1, rc);
- RETURN(rc);
+ return rc;
}
num_recs++;
}
rc = verify_handle("3b", llh, num_recs);
if (rc)
- RETURN(rc);
+ return rc;
CWARN("3c: write 1000 more log records\n");
for (i = 0; i < 1000; i++) {
@@ -268,14 +262,14 @@ static int llog_test_3(const struct lu_env *env, struct obd_device *obd,
if (rc < 0) {
CERROR("3c: write 1000 records failed at #%d: %d\n",
i + 1, rc);
- RETURN(rc);
+ return rc;
}
num_recs++;
}
rc = verify_handle("3c", llh, num_recs);
if (rc)
- RETURN(rc);
+ return rc;
CWARN("3d: write log more than BITMAP_SIZE, return -ENOSPC\n");
for (i = 0; i < LLOG_BITMAP_SIZE(llh->lgh_hdr) + 1; i++) {
@@ -299,20 +293,20 @@ static int llog_test_3(const struct lu_env *env, struct obd_device *obd,
} else if (rc < 0) {
CERROR("3d: write recs failed at #%d: %d\n",
i + 1, rc);
- RETURN(rc);
+ return rc;
}
num_recs++;
}
if (rc != -ENOSPC) {
CWARN("3d: write record more than BITMAP size!\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
CWARN("3d: wrote %d more records before end of llog is reached\n",
num_recs);
rc = verify_handle("3d", llh, num_recs);
- RETURN(rc);
+ return rc;
}
/* Test catalogue additions */
@@ -328,8 +322,6 @@ static int llog_test_4(const struct lu_env *env, struct obd_device *obd)
char *buf;
struct llog_rec_hdr rec;
- ENTRY;
-
ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
LASSERT(ctxt);
@@ -424,7 +416,7 @@ out:
}
ctxt_release:
llog_ctxt_put(ctxt);
- RETURN(rc);
+ return rc;
}
static int cat_counter;
@@ -437,7 +429,7 @@ static int cat_print_cb(const struct lu_env *env, struct llog_handle *llh,
if (rec->lrh_type != LLOG_LOGID_MAGIC) {
CERROR("invalid record in catalog\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
logid_to_fid(&lir->lid_id, &fid);
@@ -448,7 +440,7 @@ static int cat_print_cb(const struct lu_env *env, struct llog_handle *llh,
cat_counter++;
- RETURN(0);
+ return 0;
}
static int plain_counter;
@@ -460,7 +452,7 @@ static int plain_print_cb(const struct lu_env *env, struct llog_handle *llh,
if (!(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN)) {
CERROR("log is not plain\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
logid_to_fid(&llh->lgh_id, &fid);
@@ -470,7 +462,7 @@ static int plain_print_cb(const struct lu_env *env, struct llog_handle *llh,
plain_counter++;
- RETURN(0);
+ return 0;
}
static int cancel_count;
@@ -483,7 +475,7 @@ static int llog_cancel_rec_cb(const struct lu_env *env,
if (!(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN)) {
CERROR("log is not plain\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
cookie.lgc_lgl = llh->lgh_id;
@@ -492,8 +484,8 @@ static int llog_cancel_rec_cb(const struct lu_env *env,
llog_cat_cancel_records(env, llh->u.phd.phd_cat_handle, 1, &cookie);
cancel_count++;
if (cancel_count == LLOG_TEST_RECNUM)
- RETURN(-LLOG_EEMPTY);
- RETURN(0);
+ return -LLOG_EEMPTY;
+ return 0;
}
/* Test log and catalogue processing */
@@ -505,8 +497,6 @@ static int llog_test_5(const struct lu_env *env, struct obd_device *obd)
struct llog_mini_rec lmr;
struct llog_ctxt *ctxt;
- ENTRY;
-
ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
LASSERT(ctxt);
@@ -602,7 +592,7 @@ out:
out_put:
llog_ctxt_put(ctxt);
- RETURN(rc);
+ return rc;
}
/* Test client api; open log by name and process */
@@ -686,7 +676,7 @@ nctxt_put:
llog_ctxt_put(nctxt);
ctxt_release:
llog_ctxt_put(ctxt);
- RETURN(rc);
+ return rc;
}
static union {
@@ -728,12 +718,10 @@ static int llog_test_7_sub(const struct lu_env *env, struct llog_ctxt *ctxt)
int rc = 0, i, process_count;
int num_recs = 0;
- ENTRY;
-
rc = llog_open_create(env, ctxt, &llh, NULL, NULL);
if (rc) {
CERROR("7_sub: create log failed\n");
- RETURN(rc);
+ return rc;
}
rc = llog_init_handle(env, llh,
@@ -804,7 +792,7 @@ out_close:
if (rc)
llog_destroy(env, llh);
llog_close(env, llh);
- RETURN(rc);
+ return rc;
}
/* Test all llog records writing and processing */
@@ -813,8 +801,6 @@ static int llog_test_7(const struct lu_env *env, struct obd_device *obd)
struct llog_ctxt *ctxt;
int rc;
- ENTRY;
-
ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
CWARN("7a: test llog_logid_rec\n");
@@ -895,7 +881,7 @@ static int llog_test_7(const struct lu_env *env, struct obd_device *obd)
}
out:
llog_ctxt_put(ctxt);
- RETURN(rc);
+ return rc;
}
/* -------------------------------------------------------------------------
@@ -908,7 +894,6 @@ static int llog_run_tests(const struct lu_env *env, struct obd_device *obd)
int rc, err;
char name[10];
- ENTRY;
ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
LASSERT(ctxt);
@@ -970,18 +955,16 @@ static int llog_test_cleanup(struct obd_device *obd)
struct lu_env env;
int rc;
- ENTRY;
-
rc = lu_env_init(&env, LCT_LOCAL | LCT_MG_THREAD);
if (rc)
- RETURN(rc);
+ return rc;
tgt = obd->obd_lvfs_ctxt.dt->dd_lu_dev.ld_obd;
rc = llog_cleanup(&env, llog_get_context(tgt, LLOG_TEST_ORIG_CTXT));
if (rc)
CERROR("failed to llog_test_llog_finish: %d\n", rc);
lu_env_fini(&env);
- RETURN(rc);
+ return rc;
}
static int llog_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
@@ -993,16 +976,14 @@ static int llog_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
struct lu_context test_session;
int rc;
- ENTRY;
-
if (lcfg->lcfg_bufcount < 2) {
CERROR("requires a TARGET OBD name\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (lcfg->lcfg_buflens[1] < 1) {
CERROR("requires a TARGET OBD name\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* disk obd */
@@ -1010,12 +991,12 @@ static int llog_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
CERROR("target device not attached or not set up (%s)\n",
lustre_cfg_string(lcfg, 1));
- RETURN(-EINVAL);
+ return -EINVAL;
}
rc = lu_env_init(&env, LCT_LOCAL | LCT_MG_THREAD);
if (rc)
- RETURN(rc);
+ return rc;
rc = lu_context_init(&test_session, LCT_SESSION);
if (rc)
@@ -1056,7 +1037,7 @@ cleanup_session:
lu_context_fini(&test_session);
cleanup_env:
lu_env_fini(&env);
- RETURN(rc);
+ return rc;
}
static struct obd_ops llog_obd_ops = {
diff --git a/drivers/staging/lustre/lustre/obdclass/local_storage.c b/drivers/staging/lustre/lustre/obdclass/local_storage.c
index 3be35a83a49..cc19fbab020 100644
--- a/drivers/staging/lustre/lustre/obdclass/local_storage.c
+++ b/drivers/staging/lustre/lustre/obdclass/local_storage.c
@@ -45,17 +45,15 @@ static int ls_object_init(const struct lu_env *env, struct lu_object *o,
struct lu_object *below;
struct lu_device *under;
- ENTRY;
-
ls = container_of0(o->lo_dev, struct ls_device, ls_top_dev.dd_lu_dev);
under = &ls->ls_osd->dd_lu_dev;
below = under->ld_ops->ldo_object_alloc(env, o->lo_header, under);
if (below == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lu_object_add(o, below);
- RETURN(0);
+ return 0;
}
static void ls_object_free(const struct lu_env *env, struct lu_object *o)
@@ -143,8 +141,6 @@ struct ls_device *ls_device_get(struct dt_device *dev)
{
struct ls_device *ls;
- ENTRY;
-
mutex_lock(&ls_list_mutex);
ls = __ls_find_dev(dev);
if (ls)
@@ -170,7 +166,7 @@ struct ls_device *ls_device_get(struct dt_device *dev)
list_add(&ls->ls_linkage, &ls_list_head);
out_ls:
mutex_unlock(&ls_list_mutex);
- RETURN(ls);
+ return ls;
}
void ls_device_put(const struct lu_env *env, struct ls_device *ls)
@@ -224,26 +220,24 @@ int local_object_declare_create(const struct lu_env *env,
struct dt_thread_info *dti = dt_info(env);
int rc;
- ENTRY;
-
/* update fid generation file */
if (los != NULL) {
LASSERT(dt_object_exists(los->los_obj));
rc = dt_declare_record_write(env, los->los_obj,
sizeof(struct los_ondisk), 0, th);
if (rc)
- RETURN(rc);
+ return rc;
}
rc = dt_declare_create(env, o, attr, NULL, dof, th);
if (rc)
- RETURN(rc);
+ return rc;
dti->dti_lb.lb_buf = NULL;
dti->dti_lb.lb_len = sizeof(dti->dti_lma);
rc = dt_declare_xattr_set(env, o, &dti->dti_lb, XATTR_NAME_LMA, 0, th);
- RETURN(rc);
+ return rc;
}
int local_object_create(const struct lu_env *env,
@@ -255,14 +249,12 @@ int local_object_create(const struct lu_env *env,
obd_id lastid;
int rc;
- ENTRY;
-
rc = dt_create(env, o, attr, NULL, dof, th);
if (rc)
- RETURN(rc);
+ return rc;
if (los == NULL)
- RETURN(rc);
+ return rc;
LASSERT(los->los_obj);
LASSERT(dt_object_exists(los->los_obj));
@@ -283,7 +275,7 @@ int local_object_create(const struct lu_env *env,
th);
mutex_unlock(&los->los_id_lock);
- RETURN(rc);
+ return rc;
}
/*
@@ -304,7 +296,7 @@ struct dt_object *__local_file_create(const struct lu_env *env,
dto = ls_locate(env, ls, fid);
if (unlikely(IS_ERR(dto)))
- RETURN(dto);
+ return dto;
LASSERT(dto != NULL);
if (dt_object_exists(dto))
@@ -377,7 +369,7 @@ out:
lu_object_put_nocache(env, &dto->do_lu);
dto = ERR_PTR(rc);
}
- RETURN(dto);
+ return dto;
}
/*
@@ -443,7 +435,7 @@ struct dt_object *local_file_find_or_create_with_fid(const struct lu_env *env,
ls = ls_device_get(dt);
if (IS_ERR(ls)) {
- dto = ERR_PTR(PTR_ERR(ls));
+ dto = ERR_CAST(ls);
} else {
/* create the object */
dti->dti_attr.la_valid = LA_MODE;
@@ -537,7 +529,7 @@ local_index_find_or_create_with_fid(const struct lu_env *env,
ls = ls_device_get(dt);
if (IS_ERR(ls)) {
- dto = ERR_PTR(PTR_ERR(ls));
+ dto = ERR_CAST(ls);
} else {
/* create the object */
dti->dti_attr.la_valid = LA_MODE;
@@ -588,17 +580,15 @@ int local_object_unlink(const struct lu_env *env, struct dt_device *dt,
struct thandle *th;
int rc;
- ENTRY;
-
rc = dt_lookup_dir(env, parent, name, &dti->dti_fid);
if (rc == -ENOENT)
- RETURN(0);
+ return 0;
else if (rc < 0)
- RETURN(rc);
+ return rc;
dto = dt_locate(env, dt, &dti->dti_fid);
if (unlikely(IS_ERR(dto)))
- RETURN(PTR_ERR(dto));
+ return PTR_ERR(dto);
th = dt_trans_create(env, dt);
if (IS_ERR(th))
@@ -761,11 +751,9 @@ int local_oid_storage_init(const struct lu_env *env, struct dt_device *dev,
__u32 first_oid = fid_oid(first_fid);
int rc = 0;
- ENTRY;
-
ls = ls_device_get(dev);
if (IS_ERR(ls))
- RETURN(PTR_ERR(ls));
+ return PTR_ERR(ls);
mutex_lock(&ls->ls_los_mutex);
*los = dt_los_find(ls, fid_seq(first_fid));
diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_jobstats.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_jobstats.c
deleted file mode 100644
index e2d57fef0da..00000000000
--- a/drivers/staging/lustre/lustre/obdclass/lprocfs_jobstats.c
+++ /dev/null
@@ -1,562 +0,0 @@
-/* GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2011, 2012, Intel Corporation.
- * Use is subject to license terms.
- *
- * Author: Niu Yawei <niu@whamcloud.com>
- */
-/*
- * lustre/obdclass/lprocfs_jobstats.c
- */
-
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
-#define DEBUG_SUBSYSTEM S_CLASS
-
-
-#include <obd_class.h>
-#include <lprocfs_status.h>
-#include <lustre/lustre_idl.h>
-
-#if defined(LPROCFS)
-
-/*
- * JobID formats & JobID environment variable names for supported
- * job schedulers:
- *
- * SLURM:
- * JobID format: 32 bit integer.
- * JobID env var: SLURM_JOB_ID.
- * SGE:
- * JobID format: Decimal integer range to 99999.
- * JobID env var: JOB_ID.
- * LSF:
- * JobID format: 6 digit integer by default (up to 999999), can be
- * increased to 10 digit (up to 2147483646).
- * JobID env var: LSB_JOBID.
- * Loadleveler:
- * JobID format: String of machine_name.cluster_id.process_id, for
- * example: fr2n02.32.0
- * JobID env var: LOADL_STEP_ID.
- * PBS:
- * JobID format: String of sequence_number[.server_name][@server].
- * JobID env var: PBS_JOBID.
- * Maui/MOAB:
- * JobID format: Same as PBS.
- * JobID env var: Same as PBS.
- */
-
-struct job_stat {
- struct hlist_node js_hash;
- struct list_head js_list;
- atomic_t js_refcount;
- char js_jobid[JOBSTATS_JOBID_SIZE];
- time_t js_timestamp; /* seconds */
- struct lprocfs_stats *js_stats;
- struct obd_job_stats *js_jobstats;
-};
-
-static unsigned job_stat_hash(cfs_hash_t *hs, const void *key, unsigned mask)
-{
- return cfs_hash_djb2_hash(key, strlen(key), mask);
-}
-
-static void *job_stat_key(struct hlist_node *hnode)
-{
- struct job_stat *job;
- job = hlist_entry(hnode, struct job_stat, js_hash);
- return job->js_jobid;
-}
-
-static int job_stat_keycmp(const void *key, struct hlist_node *hnode)
-{
- struct job_stat *job;
- job = hlist_entry(hnode, struct job_stat, js_hash);
- return (strlen(job->js_jobid) == strlen(key)) &&
- !strncmp(job->js_jobid, key, strlen(key));
-}
-
-static void *job_stat_object(struct hlist_node *hnode)
-{
- return hlist_entry(hnode, struct job_stat, js_hash);
-}
-
-static void job_stat_get(cfs_hash_t *hs, struct hlist_node *hnode)
-{
- struct job_stat *job;
- job = hlist_entry(hnode, struct job_stat, js_hash);
- atomic_inc(&job->js_refcount);
-}
-
-static void job_free(struct job_stat *job)
-{
- LASSERT(atomic_read(&job->js_refcount) == 0);
- LASSERT(job->js_jobstats);
-
- write_lock(&job->js_jobstats->ojs_lock);
- list_del_init(&job->js_list);
- write_unlock(&job->js_jobstats->ojs_lock);
-
- lprocfs_free_stats(&job->js_stats);
- OBD_FREE_PTR(job);
-}
-
-static void job_putref(struct job_stat *job)
-{
- LASSERT(atomic_read(&job->js_refcount) > 0);
- if (atomic_dec_and_test(&job->js_refcount))
- job_free(job);
-}
-
-static void job_stat_put_locked(cfs_hash_t *hs, struct hlist_node *hnode)
-{
- struct job_stat *job;
- job = hlist_entry(hnode, struct job_stat, js_hash);
- job_putref(job);
-}
-
-static void job_stat_exit(cfs_hash_t *hs, struct hlist_node *hnode)
-{
- CERROR("Should not have any items!");
-}
-
-static cfs_hash_ops_t job_stats_hash_ops = {
- .hs_hash = job_stat_hash,
- .hs_key = job_stat_key,
- .hs_keycmp = job_stat_keycmp,
- .hs_object = job_stat_object,
- .hs_get = job_stat_get,
- .hs_put_locked = job_stat_put_locked,
- .hs_exit = job_stat_exit,
-};
-
-static int job_iter_callback(cfs_hash_t *hs, cfs_hash_bd_t *bd,
- struct hlist_node *hnode, void *data)
-{
- time_t oldest = *((time_t *)data);
- struct job_stat *job;
-
- job = hlist_entry(hnode, struct job_stat, js_hash);
- if (!oldest || job->js_timestamp < oldest)
- cfs_hash_bd_del_locked(hs, bd, hnode);
-
- return 0;
-}
-
-static void lprocfs_job_cleanup(struct obd_job_stats *stats, bool force)
-{
- time_t oldest, now;
-
- if (stats->ojs_cleanup_interval == 0)
- return;
-
- now = cfs_time_current_sec();
- if (!force && now < stats->ojs_last_cleanup +
- stats->ojs_cleanup_interval)
- return;
-
- oldest = now - stats->ojs_cleanup_interval;
- cfs_hash_for_each_safe(stats->ojs_hash, job_iter_callback,
- &oldest);
- stats->ojs_last_cleanup = cfs_time_current_sec();
-}
-
-static struct job_stat *job_alloc(char *jobid, struct obd_job_stats *jobs)
-{
- struct job_stat *job;
-
- LASSERT(jobs->ojs_cntr_num && jobs->ojs_cntr_init_fn);
-
- OBD_ALLOC_PTR(job);
- if (job == NULL)
- return NULL;
-
- job->js_stats = lprocfs_alloc_stats(jobs->ojs_cntr_num, 0);
- if (job->js_stats == NULL) {
- OBD_FREE_PTR(job);
- return NULL;
- }
-
- jobs->ojs_cntr_init_fn(job->js_stats);
-
- memcpy(job->js_jobid, jobid, JOBSTATS_JOBID_SIZE);
- job->js_timestamp = cfs_time_current_sec();
- job->js_jobstats = jobs;
- INIT_HLIST_NODE(&job->js_hash);
- INIT_LIST_HEAD(&job->js_list);
- atomic_set(&job->js_refcount, 1);
-
- return job;
-}
-
-int lprocfs_job_stats_log(struct obd_device *obd, char *jobid,
- int event, long amount)
-{
- struct obd_job_stats *stats = &obd->u.obt.obt_jobstats;
- struct job_stat *job, *job2;
- ENTRY;
-
- LASSERT(stats && stats->ojs_hash);
-
- lprocfs_job_cleanup(stats, false);
-
- if (!jobid || !strlen(jobid))
- RETURN(-EINVAL);
-
- if (strlen(jobid) >= JOBSTATS_JOBID_SIZE) {
- CERROR("Invalid jobid size (%lu), expect(%d)\n",
- (unsigned long)strlen(jobid) + 1, JOBSTATS_JOBID_SIZE);
- RETURN(-EINVAL);
- }
-
- job = cfs_hash_lookup(stats->ojs_hash, jobid);
- if (job)
- goto found;
-
- job = job_alloc(jobid, stats);
- if (job == NULL)
- RETURN(-ENOMEM);
-
- job2 = cfs_hash_findadd_unique(stats->ojs_hash, job->js_jobid,
- &job->js_hash);
- if (job2 != job) {
- job_putref(job);
- job = job2;
- /* We cannot LASSERT(!list_empty(&job->js_list)) here,
- * since we just lost the race for inserting "job" into the
- * ojs_list, and some other thread is doing it _right_now_.
- * Instead, be content the other thread is doing this, since
- * "job2" was initialized in job_alloc() already. LU-2163 */
- } else {
- LASSERT(list_empty(&job->js_list));
- write_lock(&stats->ojs_lock);
- list_add_tail(&job->js_list, &stats->ojs_list);
- write_unlock(&stats->ojs_lock);
- }
-
-found:
- LASSERT(stats == job->js_jobstats);
- LASSERT(stats->ojs_cntr_num > event);
- job->js_timestamp = cfs_time_current_sec();
- lprocfs_counter_add(job->js_stats, event, amount);
-
- job_putref(job);
- RETURN(0);
-}
-EXPORT_SYMBOL(lprocfs_job_stats_log);
-
-void lprocfs_job_stats_fini(struct obd_device *obd)
-{
- struct obd_job_stats *stats = &obd->u.obt.obt_jobstats;
- time_t oldest = 0;
-
- if (stats->ojs_hash == NULL)
- return;
- cfs_hash_for_each_safe(stats->ojs_hash, job_iter_callback, &oldest);
- cfs_hash_putref(stats->ojs_hash);
- stats->ojs_hash = NULL;
- LASSERT(list_empty(&stats->ojs_list));
-}
-EXPORT_SYMBOL(lprocfs_job_stats_fini);
-
-static void *lprocfs_jobstats_seq_start(struct seq_file *p, loff_t *pos)
-{
- struct obd_job_stats *stats = p->private;
- loff_t off = *pos;
- struct job_stat *job;
-
- read_lock(&stats->ojs_lock);
- if (off == 0)
- return SEQ_START_TOKEN;
- off--;
- list_for_each_entry(job, &stats->ojs_list, js_list) {
- if (!off--)
- return job;
- }
- return NULL;
-}
-
-static void lprocfs_jobstats_seq_stop(struct seq_file *p, void *v)
-{
- struct obd_job_stats *stats = p->private;
-
- read_unlock(&stats->ojs_lock);
-}
-
-static void *lprocfs_jobstats_seq_next(struct seq_file *p, void *v, loff_t *pos)
-{
- struct obd_job_stats *stats = p->private;
- struct job_stat *job;
- struct list_head *next;
-
- ++*pos;
- if (v == SEQ_START_TOKEN) {
- next = stats->ojs_list.next;
- } else {
- job = (struct job_stat *)v;
- next = job->js_list.next;
- }
-
- return next == &stats->ojs_list ? NULL :
- list_entry(next, struct job_stat, js_list);
-}
-
-/*
- * Example of output on MDT:
- *
- * job_stats:
- * - job_id: test_id.222.25844
- * snapshot_time: 1322494486
- * open: { samples: 3, unit: reqs }
- * close: { samples: 3, unit: reqs }
- * mknod: { samples: 0, unit: reqs }
- * link: { samples: 0, unit: reqs }
- * unlink: { samples: 0, unit: reqs }
- * mkdir: { samples: 0, unit: reqs }
- * rmdir: { samples: 0, unit: reqs }
- * rename: { samples: 1, unit: reqs }
- * getattr: { samples: 7, unit: reqs }
- * setattr: { samples: 0, unit: reqs }
- * getxattr: { samples: 0, unit: reqs }
- * setxattr: { samples: 0, unit: reqs }
- * statfs: { samples: 0, unit: reqs }
- * sync: { samples: 0, unit: reqs }
- *
- * Example of output on OST:
- *
- * job_stats:
- * - job_id 4854
- * snapshot_time: 1322494602
- * read: { samples: 0, unit: bytes, min: 0, max: 0, sum: 0 }
- * write: { samples: 1, unit: bytes, min: 10, max: 10, sum: 10 }
- * setattr: { samples: 0, unit: reqs }
- * punch: { samples: 0, unit: reqs }
- * sync: { samples: 0, unit: reqs }
- */
-
-static const char spaces[] = " ";
-
-static int inline width(const char *str, int len)
-{
- return len - min((int)strlen(str), 15);
-}
-
-static int lprocfs_jobstats_seq_show(struct seq_file *p, void *v)
-{
- struct job_stat *job = v;
- struct lprocfs_stats *s;
- struct lprocfs_counter ret;
- struct lprocfs_counter *cntr;
- struct lprocfs_counter_header *cntr_header;
- int i;
-
- if (v == SEQ_START_TOKEN) {
- seq_printf(p, "job_stats:\n");
- return 0;
- }
-
- seq_printf(p, "- %-16s %s\n", "job_id:", job->js_jobid);
- seq_printf(p, " %-16s %ld\n", "snapshot_time:", job->js_timestamp);
-
- s = job->js_stats;
- for (i = 0; i < s->ls_num; i++) {
- cntr = lprocfs_stats_counter_get(s, 0, i);
- cntr_header = &s->ls_cnt_header[i];
- lprocfs_stats_collect(s, i, &ret);
-
- seq_printf(p, " %s:%.*s { samples: %11"LPF64"u",
- cntr_header->lc_name,
- width(cntr_header->lc_name, 15), spaces,
- ret.lc_count);
- if (cntr_header->lc_units[0] != '\0')
- seq_printf(p, ", unit: %5s", cntr_header->lc_units);
-
- if (cntr_header->lc_config & LPROCFS_CNTR_AVGMINMAX) {
- seq_printf(p, ", min:%8"LPF64"u, max:%8"LPF64"u,"
- " sum:%16"LPF64"u",
- ret.lc_count ? ret.lc_min : 0,
- ret.lc_count ? ret.lc_max : 0,
- ret.lc_count ? ret.lc_sum : 0);
- }
- if (cntr_header->lc_config & LPROCFS_CNTR_STDDEV) {
- seq_printf(p, ", sumsq: %18"LPF64"u",
- ret.lc_count ? ret.lc_sumsquare : 0);
- }
-
- seq_printf(p, " }\n");
-
- }
- return 0;
-}
-
-struct seq_operations lprocfs_jobstats_seq_sops = {
- start: lprocfs_jobstats_seq_start,
- stop: lprocfs_jobstats_seq_stop,
- next: lprocfs_jobstats_seq_next,
- show: lprocfs_jobstats_seq_show,
-};
-
-static int lprocfs_jobstats_seq_open(struct inode *inode, struct file *file)
-{
- struct seq_file *seq;
- int rc;
-
- rc = seq_open(file, &lprocfs_jobstats_seq_sops);
- if (rc)
- return rc;
- seq = file->private_data;
- seq->private = PDE_DATA(inode);
- return 0;
-}
-
-static ssize_t lprocfs_jobstats_seq_write(struct file *file, const char *buf,
- size_t len, loff_t *off)
-{
- struct seq_file *seq = file->private_data;
- struct obd_job_stats *stats = seq->private;
- char jobid[JOBSTATS_JOBID_SIZE];
- int all = 0;
- struct job_stat *job;
-
- if (!memcmp(buf, "clear", strlen("clear"))) {
- all = 1;
- } else if (len < JOBSTATS_JOBID_SIZE) {
- memset(jobid, 0, JOBSTATS_JOBID_SIZE);
- /* Trim '\n' if any */
- if (buf[len - 1] == '\n')
- memcpy(jobid, buf, len - 1);
- else
- memcpy(jobid, buf, len);
- } else {
- return -EINVAL;
- }
-
- LASSERT(stats->ojs_hash);
- if (all) {
- time_t oldest = 0;
- cfs_hash_for_each_safe(stats->ojs_hash, job_iter_callback,
- &oldest);
- return len;
- }
-
- if (!strlen(jobid))
- return -EINVAL;
-
- job = cfs_hash_lookup(stats->ojs_hash, jobid);
- if (!job)
- return -EINVAL;
-
- cfs_hash_del_key(stats->ojs_hash, jobid);
-
- job_putref(job);
- return len;
-}
-
-struct file_operations lprocfs_jobstats_seq_fops = {
- .owner = THIS_MODULE,
- .open = lprocfs_jobstats_seq_open,
- .read = seq_read,
- .write = lprocfs_jobstats_seq_write,
- .llseek = seq_lseek,
- .release = lprocfs_seq_release,
-};
-
-int lprocfs_job_stats_init(struct obd_device *obd, int cntr_num,
- cntr_init_callback init_fn)
-{
- struct proc_dir_entry *entry;
- struct obd_job_stats *stats;
- ENTRY;
-
- LASSERT(obd->obd_proc_entry != NULL);
- LASSERT(obd->obd_type->typ_name);
-
- if (strcmp(obd->obd_type->typ_name, LUSTRE_MDT_NAME) &&
- strcmp(obd->obd_type->typ_name, LUSTRE_OST_NAME)) {
- CERROR("Invalid obd device type.\n");
- RETURN(-EINVAL);
- }
- stats = &obd->u.obt.obt_jobstats;
-
- LASSERT(stats->ojs_hash == NULL);
- stats->ojs_hash = cfs_hash_create("JOB_STATS",
- HASH_JOB_STATS_CUR_BITS,
- HASH_JOB_STATS_MAX_BITS,
- HASH_JOB_STATS_BKT_BITS, 0,
- CFS_HASH_MIN_THETA,
- CFS_HASH_MAX_THETA,
- &job_stats_hash_ops,
- CFS_HASH_DEFAULT);
- if (stats->ojs_hash == NULL)
- RETURN(-ENOMEM);
-
- INIT_LIST_HEAD(&stats->ojs_list);
- rwlock_init(&stats->ojs_lock);
- stats->ojs_cntr_num = cntr_num;
- stats->ojs_cntr_init_fn = init_fn;
- stats->ojs_cleanup_interval = 600; /* 10 mins by default */
- stats->ojs_last_cleanup = cfs_time_current_sec();
-
- entry = proc_create_data("job_stats", 0644, obd->obd_proc_entry,
- &lprocfs_jobstats_seq_fops, stats);
- if (entry)
- RETURN(0);
- else
- RETURN(-ENOMEM);
-}
-EXPORT_SYMBOL(lprocfs_job_stats_init);
-
-int lprocfs_rd_job_interval(struct seq_file *m, void *data)
-{
- struct obd_device *obd = (struct obd_device *)data;
- struct obd_job_stats *stats;
-
- LASSERT(obd != NULL);
- stats = &obd->u.obt.obt_jobstats;
- return seq_printf(m, "%d\n", stats->ojs_cleanup_interval);
-}
-EXPORT_SYMBOL(lprocfs_rd_job_interval);
-
-int lprocfs_wr_job_interval(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- struct obd_device *obd = (struct obd_device *)data;
- struct obd_job_stats *stats;
- int val, rc;
-
- LASSERT(obd != NULL);
- stats = &obd->u.obt.obt_jobstats;
-
- rc = lprocfs_write_helper(buffer, count, &val);
- if (rc)
- return rc;
-
- stats->ojs_cleanup_interval = val;
- lprocfs_job_cleanup(stats, true);
-
- return count;
-
-}
-EXPORT_SYMBOL(lprocfs_wr_job_interval);
-
-#endif /* LPROCFS*/
diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
index f7af3d6a4ef..a95f60a4f90 100644
--- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
+++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
@@ -68,11 +68,11 @@ EXPORT_SYMBOL(lprocfs_seq_release);
/* lprocfs API calls */
-proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
+struct proc_dir_entry *lprocfs_add_simple(struct proc_dir_entry *root,
char *name, void *data,
struct file_operations *fops)
{
- proc_dir_entry_t *proc;
+ struct proc_dir_entry *proc;
umode_t mode = 0;
if (root == NULL || name == NULL || fops == NULL)
@@ -179,17 +179,21 @@ struct proc_dir_entry *lprocfs_register(const char *name,
struct proc_dir_entry *parent,
struct lprocfs_vars *list, void *data)
{
- struct proc_dir_entry *newchild;
+ struct proc_dir_entry *entry;
+
+ entry = proc_mkdir(name, parent);
+ if (entry == NULL)
+ GOTO(out, entry = ERR_PTR(-ENOMEM));
- newchild = proc_mkdir(name, parent);
- if (newchild != NULL && list != NULL) {
- int rc = lprocfs_add_vars(newchild, list, data);
- if (rc) {
- lprocfs_remove(&newchild);
- return ERR_PTR(rc);
+ if (list != NULL) {
+ int rc = lprocfs_add_vars(entry, list, data);
+ if (rc != 0) {
+ lprocfs_remove(&entry);
+ entry = ERR_PTR(rc);
}
}
- return newchild;
+out:
+ return entry;
}
EXPORT_SYMBOL(lprocfs_register);
@@ -896,7 +900,6 @@ void lprocfs_free_per_client_stats(struct obd_device *obd)
{
cfs_hash_t *hash = obd->obd_nid_stats_hash;
struct nid_stat *stat;
- ENTRY;
/* we need extra list - because hash_exit called to early */
/* not need locking because all clients is died */
@@ -907,7 +910,6 @@ void lprocfs_free_per_client_stats(struct obd_device *obd)
cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
lprocfs_free_client_stats(stat);
}
- EXIT;
}
EXPORT_SYMBOL(lprocfs_free_per_client_stats);
@@ -1494,7 +1496,6 @@ EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
{
struct nid_stat *stat = obj;
- ENTRY;
CDEBUG(D_INFO,"refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
if (atomic_read(&stat->nid_exp_ref_count) == 1) {
@@ -1502,13 +1503,13 @@ static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
spin_lock(&stat->nid_obd->obd_nid_lock);
list_move(&stat->nid_list, data);
spin_unlock(&stat->nid_obd->obd_nid_lock);
- RETURN(1);
+ return 1;
}
/* we has reference to object - only clear data*/
if (stat->nid_stats)
lprocfs_clear_stats(stat->nid_stats);
- RETURN(0);
+ return 0;
}
int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
@@ -1536,22 +1537,21 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
{
struct nid_stat *new_stat, *old_stat;
struct obd_device *obd = NULL;
- proc_dir_entry_t *entry;
+ struct proc_dir_entry *entry;
char *buffer = NULL;
int rc = 0;
- ENTRY;
*newnid = 0;
if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
!exp->exp_obd->obd_nid_stats_hash)
- RETURN(-EINVAL);
+ return -EINVAL;
/* not test against zero because eric say:
* You may only test nid against another nid, or LNET_NID_ANY.
* Anything else is nonsense.*/
if (!nid || *nid == LNET_NID_ANY)
- RETURN(0);
+ return 0;
obd = exp->exp_obd;
@@ -1559,7 +1559,7 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
OBD_ALLOC_PTR(new_stat);
if (new_stat == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
new_stat->nid = *nid;
new_stat->nid_obd = exp->exp_obd;
@@ -1596,10 +1596,12 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
NULL, NULL);
OBD_FREE(buffer, LNET_NIDSTR_SIZE);
- if (new_stat->nid_proc == NULL) {
+ if (IS_ERR(new_stat->nid_proc)) {
CERROR("Error making export directory for nid %s\n",
libcfs_nid2str(*nid));
- GOTO(destroy_new_ns, rc = -ENOMEM);
+ rc = PTR_ERR(new_stat->nid_proc);
+ new_stat->nid_proc = NULL;
+ GOTO(destroy_new_ns, rc);
}
entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
@@ -1625,7 +1627,7 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
list_add(&new_stat->nid_list, &obd->obd_nid_stats);
spin_unlock(&obd->obd_nid_lock);
- RETURN(rc);
+ return rc;
destroy_new_ns:
if (new_stat->nid_proc != NULL)
@@ -1635,7 +1637,7 @@ destroy_new_ns:
destroy_new:
nidstat_putref(new_stat);
OBD_FREE_PTR(new_stat);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(lprocfs_exp_setup);
@@ -1644,7 +1646,7 @@ int lprocfs_exp_cleanup(struct obd_export *exp)
struct nid_stat *stat = exp->exp_nid_stats;
if(!stat || !exp->exp_obd)
- RETURN(0);
+ return 0;
nidstat_putref(exp->exp_nid_stats);
exp->exp_nid_stats = NULL;
@@ -1873,7 +1875,7 @@ static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len)
* If \a name is not found the original \a buffer is returned.
*/
char *lprocfs_find_named_value(const char *buffer, const char *name,
- unsigned long *count)
+ size_t *count)
{
char *val;
size_t buflen = *count;
@@ -1897,23 +1899,22 @@ char *lprocfs_find_named_value(const char *buffer, const char *name,
}
EXPORT_SYMBOL(lprocfs_find_named_value);
-int lprocfs_seq_create(proc_dir_entry_t *parent,
+int lprocfs_seq_create(struct proc_dir_entry *parent,
const char *name,
umode_t mode,
const struct file_operations *seq_fops,
void *data)
{
struct proc_dir_entry *entry;
- ENTRY;
/* Disallow secretly (un)writable entries. */
LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
entry = proc_create_data(name, mode, parent, seq_fops, data);
if (entry == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(lprocfs_seq_create);
diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c
index fdf0ed36769..c29ac1c2def 100644
--- a/drivers/staging/lustre/lustre/obdclass/lu_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c
@@ -202,7 +202,6 @@ static struct lu_object *lu_object_alloc(const struct lu_env *env,
struct list_head *layers;
int clean;
int result;
- ENTRY;
/*
* Create top-level object slice. This will also create
@@ -210,9 +209,9 @@ static struct lu_object *lu_object_alloc(const struct lu_env *env,
*/
top = dev->ld_ops->ldo_object_alloc(env, NULL, dev);
if (top == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
if (IS_ERR(top))
- RETURN(top);
+ return top;
/*
* This is the only place where object fid is assigned. It's constant
* after this point.
@@ -233,7 +232,7 @@ static struct lu_object *lu_object_alloc(const struct lu_env *env,
result = scan->lo_ops->loo_object_init(env, scan, conf);
if (result != 0) {
lu_object_free(env, top);
- RETURN(ERR_PTR(result));
+ return ERR_PTR(result);
}
scan->lo_flags |= LU_OBJECT_ALLOCATED;
}
@@ -244,13 +243,13 @@ static struct lu_object *lu_object_alloc(const struct lu_env *env,
result = scan->lo_ops->loo_object_start(env, scan);
if (result != 0) {
lu_object_free(env, top);
- RETURN(ERR_PTR(result));
+ return ERR_PTR(result);
}
}
}
lprocfs_counter_incr(dev->ld_site->ls_stats, LU_SS_CREATED);
- RETURN(top);
+ return top;
}
/**
@@ -317,7 +316,7 @@ int lu_site_purge(const struct lu_env *env, struct lu_site *s, int nr)
int i;
if (OBD_FAIL_CHECK(OBD_FAIL_OBD_NO_LRU))
- RETURN(0);
+ return 0;
INIT_LIST_HEAD(&dispose);
/*
@@ -538,7 +537,7 @@ static struct lu_object *htable_lookup(struct lu_site *s,
__u64 ver = cfs_hash_bd_version_get(bd);
if (*version == ver)
- return NULL;
+ return ERR_PTR(-ENOENT);
*version = ver;
bkt = cfs_hash_bd_extra_get(s->ls_obj_hash, bd);
@@ -547,7 +546,7 @@ static struct lu_object *htable_lookup(struct lu_site *s,
hnode = cfs_hash_bd_peek_locked(s->ls_obj_hash, bd, (void *)f);
if (hnode == NULL) {
lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_MISS);
- return NULL;
+ return ERR_PTR(-ENOENT);
}
h = container_of0(hnode, struct lu_object_header, loh_hash);
@@ -651,7 +650,7 @@ static struct lu_object *lu_object_find_try(const struct lu_env *env,
cfs_hash_bd_get_and_lock(hs, (void *)f, &bd, 1);
o = htable_lookup(s, &bd, f, waiter, &version);
cfs_hash_bd_unlock(hs, &bd, 1);
- if (o != NULL)
+ if (!IS_ERR(o) || PTR_ERR(o) != -ENOENT)
return o;
/*
@@ -667,7 +666,7 @@ static struct lu_object *lu_object_find_try(const struct lu_env *env,
cfs_hash_bd_lock(hs, &bd, 1);
shadow = htable_lookup(s, &bd, f, waiter, &version);
- if (likely(shadow == NULL)) {
+ if (likely(IS_ERR(shadow) && PTR_ERR(shadow) == -ENOENT)) {
struct lu_site_bkt_data *bkt;
bkt = cfs_hash_bd_extra_get(hs, &bd);
@@ -849,7 +848,7 @@ static int lu_htable_order(void)
*
* Size of lu_object is (arbitrary) taken as 1K (together with inode).
*/
- cache_size = num_physpages;
+ cache_size = totalram_pages;
#if BITS_PER_LONG == 32
/* limit hashtable size for lowmem systems to low RAM */
@@ -980,7 +979,6 @@ int lu_site_init(struct lu_site *s, struct lu_device *top)
char name[16];
int bits;
int i;
- ENTRY;
memset(s, 0, sizeof *s);
bits = lu_htable_order();
@@ -1041,7 +1039,7 @@ int lu_site_init(struct lu_site *s, struct lu_device *top)
lu_dev_add_linkage(s, top);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(lu_site_init);
@@ -1147,15 +1145,16 @@ EXPORT_SYMBOL(lu_device_fini);
* Initialize object \a o that is part of compound object \a h and was created
* by device \a d.
*/
-int lu_object_init(struct lu_object *o,
- struct lu_object_header *h, struct lu_device *d)
+int lu_object_init(struct lu_object *o, struct lu_object_header *h,
+ struct lu_device *d)
{
- memset(o, 0, sizeof *o);
+ memset(o, 0, sizeof(*o));
o->lo_header = h;
- o->lo_dev = d;
+ o->lo_dev = d;
lu_device_get(d);
- o->lo_dev_ref = lu_ref_add(&d->ld_reference, "lu_object", o);
+ lu_ref_add_at(&d->ld_reference, &o->lo_dev_ref, "lu_object", o);
INIT_LIST_HEAD(&o->lo_linkage);
+
return 0;
}
EXPORT_SYMBOL(lu_object_init);
@@ -1170,8 +1169,8 @@ void lu_object_fini(struct lu_object *o)
LASSERT(list_empty(&o->lo_linkage));
if (dev != NULL) {
- lu_ref_del_at(&dev->ld_reference,
- o->lo_dev_ref , "lu_object", o);
+ lu_ref_del_at(&dev->ld_reference, &o->lo_dev_ref,
+ "lu_object", o);
lu_device_put(dev);
o->lo_dev = NULL;
}
@@ -1315,7 +1314,6 @@ int lu_context_key_register(struct lu_context_key *key)
LASSERT(key->lct_init != NULL);
LASSERT(key->lct_fini != NULL);
LASSERT(key->lct_tags != 0);
- LASSERT(key->lct_owner != NULL);
result = -ENFILE;
spin_lock(&lu_keys_guard);
@@ -1349,7 +1347,6 @@ static void key_fini(struct lu_context *ctx, int index)
lu_ref_del(&key->lct_reference, "ctx", ctx);
atomic_dec(&key->lct_used);
- LASSERT(key->lct_owner != NULL);
if ((ctx->lc_tags & LCT_NOREF) == 0) {
#ifdef CONFIG_MODULE_UNLOAD
LINVRNT(module_refcount(key->lct_owner) > 0);
@@ -1557,7 +1554,6 @@ static int keys_fill(struct lu_context *ctx)
if (unlikely(IS_ERR(value)))
return PTR_ERR(value);
- LASSERT(key->lct_owner != NULL);
if (!(ctx->lc_tags & LCT_NOREF))
try_module_get(key->lct_owner);
lu_ref_add_atomic(&key->lct_reference, "ctx", ctx);
@@ -2079,7 +2075,7 @@ void lu_object_assign_fid(const struct lu_env *env, struct lu_object *o,
cfs_hash_bd_get_and_lock(hs, (void *)fid, &bd, 1);
shadow = htable_lookup(s, &bd, fid, &waiter, &version);
/* supposed to be unique */
- LASSERT(shadow == NULL);
+ LASSERT(IS_ERR(shadow) && PTR_ERR(shadow) == -ENOENT);
*old = *fid;
bkt = cfs_hash_bd_extra_get(hs, &bd);
cfs_hash_bd_add_locked(hs, &bd, &o->lo_header->loh_hash);
diff --git a/drivers/staging/lustre/lustre/obdclass/lu_ucred.c b/drivers/staging/lustre/lustre/obdclass/lu_ucred.c
index 229db6c39b7..e23e545b0d6 100644
--- a/drivers/staging/lustre/lustre/obdclass/lu_ucred.c
+++ b/drivers/staging/lustre/lustre/obdclass/lu_ucred.c
@@ -33,13 +33,13 @@
* This file is part of Lustre, http://www.lustre.org/
* Lustre is a trademark of Sun Microsystems, Inc.
*
- * lustre/obdclass/lu_object.c
+ * lustre/obdclass/lu_ucred.c
*
- * Lustre Object.
- * These are the only exported functions, they provide some generic
- * infrastructure for managing object devices
+ * Lustre user credentials context infrastructure.
*
* Author: Nikita Danilov <nikita.danilov@sun.com>
+ * Author: Fan Yong <fan.yong@intel.com>
+ * Author: Vitaly Fertman <vitaly_fertman@xyratex.com>
*/
#define DEBUG_SUBSYSTEM S_CLASS
diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c
index 69d6499ef73..be31d32b82c 100644
--- a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c
+++ b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c
@@ -65,7 +65,6 @@ void class_handle_hash(struct portals_handle *h,
struct portals_handle_ops *ops)
{
struct handle_bucket *bucket;
- ENTRY;
LASSERT(h != NULL);
LASSERT(list_empty(&h->h_link));
@@ -100,7 +99,6 @@ void class_handle_hash(struct portals_handle *h,
CDEBUG(D_INFO, "added object %p with handle "LPX64" to hash\n",
h, h->h_cookie);
- EXIT;
}
EXPORT_SYMBOL(class_handle_hash);
@@ -139,7 +137,6 @@ EXPORT_SYMBOL(class_handle_unhash);
void class_handle_hash_back(struct portals_handle *h)
{
struct handle_bucket *bucket;
- ENTRY;
bucket = handle_hash + (h->h_cookie & HANDLE_HASH_MASK);
@@ -147,8 +144,6 @@ void class_handle_hash_back(struct portals_handle *h)
list_add_rcu(&h->h_link, &bucket->head);
h->h_in = 1;
spin_unlock(&bucket->lock);
-
- EXIT;
}
EXPORT_SYMBOL(class_handle_hash_back);
@@ -157,7 +152,6 @@ void *class_handle2object(__u64 cookie)
struct handle_bucket *bucket;
struct portals_handle *h;
void *retval = NULL;
- ENTRY;
LASSERT(handle_hash != NULL);
@@ -180,7 +174,7 @@ void *class_handle2object(__u64 cookie)
}
rcu_read_unlock();
- RETURN(retval);
+ return retval;
}
EXPORT_SYMBOL(class_handle2object);
diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c
index 2fa2589dc8e..df4936ad237 100644
--- a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c
+++ b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c
@@ -191,7 +191,6 @@ int class_check_uuid(struct obd_uuid *uuid, __u64 nid)
{
struct uuid_nid_data *entry;
int found = 0;
- ENTRY;
CDEBUG(D_INFO, "check if uuid %s has %s.\n",
obd_uuid2str(uuid), libcfs_nid2str(nid));
@@ -213,6 +212,6 @@ int class_check_uuid(struct obd_uuid *uuid, __u64 nid)
break;
}
spin_unlock(&g_uuid_lock);
- RETURN(found);
+ return found;
}
EXPORT_SYMBOL(class_check_uuid);
diff --git a/drivers/staging/lustre/lustre/obdclass/md_attrs.c b/drivers/staging/lustre/lustre/obdclass/md_attrs.c
index b71344a04c7..f7187829e27 100644
--- a/drivers/staging/lustre/lustre/obdclass/md_attrs.c
+++ b/drivers/staging/lustre/lustre/obdclass/md_attrs.c
@@ -99,19 +99,18 @@ EXPORT_SYMBOL(lustre_som_swab);
int lustre_buf2som(void *buf, int rc, struct md_som_data *msd)
{
struct som_attrs *attrs = (struct som_attrs *)buf;
- ENTRY;
if (rc == 0 || rc == -ENODATA)
/* no SOM attributes */
- RETURN(-ENODATA);
+ return -ENODATA;
if (rc < 0)
/* error hit while fetching xattr */
- RETURN(rc);
+ return rc;
/* check SOM compatibility */
if (attrs->som_incompat & ~cpu_to_le32(SOM_INCOMPAT_SUPP))
- RETURN(-ENODATA);
+ return -ENODATA;
/* unpack SOM attributes */
lustre_som_swab(attrs);
@@ -124,7 +123,7 @@ int lustre_buf2som(void *buf, int rc, struct md_som_data *msd)
msd->msd_blocks = attrs->som_blocks;
msd->msd_mountid = attrs->som_mountid;
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(lustre_buf2som);
@@ -156,15 +155,14 @@ EXPORT_SYMBOL(lustre_hsm_swab);
int lustre_buf2hsm(void *buf, int rc, struct md_hsm *mh)
{
struct hsm_attrs *attrs = (struct hsm_attrs *)buf;
- ENTRY;
if (rc == 0 || rc == -ENODATA)
/* no HSM attributes */
- RETURN(-ENODATA);
+ return -ENODATA;
if (rc < 0)
/* error hit while fetching xattr */
- RETURN(rc);
+ return rc;
/* unpack HSM attributes */
lustre_hsm_swab(attrs);
@@ -175,7 +173,7 @@ int lustre_buf2hsm(void *buf, int rc, struct md_hsm *mh)
mh->mh_arch_id = attrs->hsm_arch_id;
mh->mh_arch_ver = attrs->hsm_arch_ver;
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(lustre_buf2hsm);
@@ -188,7 +186,6 @@ EXPORT_SYMBOL(lustre_buf2hsm);
void lustre_hsm2buf(void *buf, struct md_hsm *mh)
{
struct hsm_attrs *attrs = (struct hsm_attrs *)buf;
- ENTRY;
/* copy HSM attributes */
attrs->hsm_compat = mh->mh_compat;
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c
index bbf06d009fd..d0a64ff5358 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_config.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c
@@ -93,7 +93,7 @@ struct cfg_interop_param *class_find_old_param(const char *param,
int name_len = 0;
if (param == NULL || ptr == NULL)
- RETURN(NULL);
+ return NULL;
value = strchr(param, '=');
if (value == NULL)
@@ -104,11 +104,11 @@ struct cfg_interop_param *class_find_old_param(const char *param,
while (ptr->old_param != NULL) {
if (strncmp(param, ptr->old_param, name_len) == 0 &&
name_len == strlen(ptr->old_param))
- RETURN(ptr);
+ return ptr;
ptr++;
}
- RETURN(NULL);
+ return NULL;
}
EXPORT_SYMBOL(class_find_old_param);
@@ -335,23 +335,22 @@ int class_attach(struct lustre_cfg *lcfg)
struct obd_device *obd = NULL;
char *typename, *name, *uuid;
int rc, len;
- ENTRY;
if (!LUSTRE_CFG_BUFLEN(lcfg, 1)) {
CERROR("No type passed!\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
typename = lustre_cfg_string(lcfg, 1);
if (!LUSTRE_CFG_BUFLEN(lcfg, 0)) {
CERROR("No name passed!\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
name = lustre_cfg_string(lcfg, 0);
if (!LUSTRE_CFG_BUFLEN(lcfg, 2)) {
CERROR("No UUID passed!\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
uuid = lustre_cfg_string(lcfg, 2);
@@ -433,7 +432,7 @@ int class_attach(struct lustre_cfg *lcfg)
obd->obd_attached = 1;
CDEBUG(D_IOCTL, "OBD: dev %d attached type %s with refcount %d\n",
obd->obd_minor, typename, atomic_read(&obd->obd_refcount));
- RETURN(0);
+ return 0;
out:
if (obd != NULL) {
class_release_dev(obd);
@@ -449,7 +448,6 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
{
int err = 0;
struct obd_export *exp;
- ENTRY;
LASSERT(obd != NULL);
LASSERTF(obd == class_num2obd(obd->obd_minor),
@@ -462,13 +460,13 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
/* have we attached a type to this device? */
if (!obd->obd_attached) {
CERROR("Device %d not attached\n", obd->obd_minor);
- RETURN(-ENODEV);
+ return -ENODEV;
}
if (obd->obd_set_up) {
CERROR("Device %d already setup (type %s)\n",
obd->obd_minor, obd->obd_type->typ_name);
- RETURN(-EEXIST);
+ return -EEXIST;
}
/* is someone else setting us up right now? (attach inits spinlock) */
@@ -477,7 +475,7 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
spin_unlock(&obd->obd_dev_lock);
CERROR("Device %d setup in progress (type %s)\n",
obd->obd_minor, obd->obd_type->typ_name);
- RETURN(-EEXIST);
+ return -EEXIST;
}
/* just leave this on forever. I can't use obd_set_up here because
other fns check that status, and we're not actually set up yet. */
@@ -542,7 +540,7 @@ int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
CDEBUG(D_IOCTL, "finished setup of obd %s (uuid %s)\n",
obd->obd_name, obd->obd_uuid.uuid);
- RETURN(0);
+ return 0;
err_exp:
if (obd->obd_self_export) {
class_unlink_export(obd->obd_self_export);
@@ -572,18 +570,16 @@ EXPORT_SYMBOL(class_setup);
*/
int class_detach(struct obd_device *obd, struct lustre_cfg *lcfg)
{
- ENTRY;
-
if (obd->obd_set_up) {
CERROR("OBD device %d still set up\n", obd->obd_minor);
- RETURN(-EBUSY);
+ return -EBUSY;
}
spin_lock(&obd->obd_dev_lock);
if (!obd->obd_attached) {
spin_unlock(&obd->obd_dev_lock);
CERROR("OBD device %d not attached\n", obd->obd_minor);
- RETURN(-ENODEV);
+ return -ENODEV;
}
obd->obd_attached = 0;
spin_unlock(&obd->obd_dev_lock);
@@ -592,7 +588,7 @@ int class_detach(struct obd_device *obd, struct lustre_cfg *lcfg)
obd->obd_name, obd->obd_uuid.uuid);
class_decref(obd, "attach", obd);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(class_detach);
@@ -604,20 +600,19 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
{
int err = 0;
char *flag;
- ENTRY;
OBD_RACE(OBD_FAIL_LDLM_RECOV_CLIENTS);
if (!obd->obd_set_up) {
CERROR("Device %d not setup\n", obd->obd_minor);
- RETURN(-ENODEV);
+ return -ENODEV;
}
spin_lock(&obd->obd_dev_lock);
if (obd->obd_stopping) {
spin_unlock(&obd->obd_dev_lock);
CERROR("OBD %d already stopping\n", obd->obd_minor);
- RETURN(-ENODEV);
+ return -ENODEV;
}
/* Leave this on forever */
obd->obd_stopping = 1;
@@ -696,7 +691,7 @@ int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
class_decref(obd, "setup", obd);
obd->obd_set_up = 0;
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(class_cleanup);
@@ -767,12 +762,11 @@ int class_add_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
struct obd_import *imp;
struct obd_uuid uuid;
int rc;
- ENTRY;
if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1 ||
LUSTRE_CFG_BUFLEN(lcfg, 1) > sizeof(struct obd_uuid)) {
CERROR("invalid conn_uuid\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) &&
@@ -780,19 +774,19 @@ int class_add_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
strcmp(obd->obd_type->typ_name, LUSTRE_LWP_NAME) &&
strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME)) {
CERROR("can't add connection on non-client dev\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
imp = obd->u.cli.cl_import;
if (!imp) {
CERROR("try to add conn on immature client dev\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
obd_str2uuid(&uuid, lustre_cfg_string(lcfg, 1));
rc = obd_add_conn(imp, &uuid, lcfg->lcfg_num);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(class_add_conn);
@@ -803,29 +797,28 @@ int class_del_conn(struct obd_device *obd, struct lustre_cfg *lcfg)
struct obd_import *imp;
struct obd_uuid uuid;
int rc;
- ENTRY;
if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1 ||
LUSTRE_CFG_BUFLEN(lcfg, 1) > sizeof(struct obd_uuid)) {
CERROR("invalid conn_uuid\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME)) {
CERROR("can't del connection on non-client dev\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
imp = obd->u.cli.cl_import;
if (!imp) {
CERROR("try to del conn on immature client dev\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
obd_str2uuid(&uuid, lustre_cfg_string(lcfg, 1));
rc = obd_del_conn(imp, &uuid);
- RETURN(rc);
+ return rc;
}
LIST_HEAD(lustre_profile_list);
@@ -834,13 +827,12 @@ struct lustre_profile *class_get_profile(const char * prof)
{
struct lustre_profile *lprof;
- ENTRY;
list_for_each_entry(lprof, &lustre_profile_list, lp_list) {
if (!strcmp(lprof->lp_profile, prof)) {
- RETURN(lprof);
+ return lprof;
}
}
- RETURN(NULL);
+ return NULL;
}
EXPORT_SYMBOL(class_get_profile);
@@ -853,13 +845,12 @@ int class_add_profile(int proflen, char *prof, int osclen, char *osc,
{
struct lustre_profile *lprof;
int err = 0;
- ENTRY;
CDEBUG(D_CONFIG, "Add profile %s\n", prof);
OBD_ALLOC(lprof, sizeof(*lprof));
if (lprof == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
INIT_LIST_HEAD(&lprof->lp_list);
LASSERT(proflen == (strlen(prof) + 1));
@@ -883,7 +874,7 @@ int class_add_profile(int proflen, char *prof, int osclen, char *osc,
}
list_add(&lprof->lp_list, &lustre_profile_list);
- RETURN(err);
+ return err;
out:
if (lprof->lp_md)
@@ -893,13 +884,12 @@ out:
if (lprof->lp_profile)
OBD_FREE(lprof->lp_profile, proflen);
OBD_FREE(lprof, sizeof(*lprof));
- RETURN(err);
+ return err;
}
void class_del_profile(const char *prof)
{
struct lustre_profile *lprof;
- ENTRY;
CDEBUG(D_CONFIG, "Del profile %s\n", prof);
@@ -912,7 +902,6 @@ void class_del_profile(const char *prof)
OBD_FREE(lprof->lp_md, strlen(lprof->lp_md) + 1);
OBD_FREE(lprof, sizeof *lprof);
}
- EXIT;
}
EXPORT_SYMBOL(class_del_profile);
@@ -920,7 +909,6 @@ EXPORT_SYMBOL(class_del_profile);
void class_del_profiles(void)
{
struct lustre_profile *lprof, *n;
- ENTRY;
list_for_each_entry_safe(lprof, n, &lustre_profile_list, lp_list) {
list_del(&lprof->lp_list);
@@ -930,13 +918,11 @@ void class_del_profiles(void)
OBD_FREE(lprof->lp_md, strlen(lprof->lp_md) + 1);
OBD_FREE(lprof, sizeof *lprof);
}
- EXIT;
}
EXPORT_SYMBOL(class_del_profiles);
static int class_set_global(char *ptr, int val, struct lustre_cfg *lcfg)
{
- ENTRY;
if (class_match_param(ptr, PARAM_AT_MIN, NULL) == 0)
at_min = val;
else if (class_match_param(ptr, PARAM_AT_MAX, NULL) == 0)
@@ -951,10 +937,10 @@ static int class_set_global(char *ptr, int val, struct lustre_cfg *lcfg)
strlcpy(obd_jobid_var, lustre_cfg_string(lcfg, 2),
JOBSTATS_JOBID_VAR_MAX_LEN + 1);
else
- RETURN(-EINVAL);
+ return -EINVAL;
CDEBUG(D_IOCTL, "global %s = %d\n", ptr, val);
- RETURN(0);
+ return 0;
}
@@ -991,14 +977,13 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg,
char *value = NULL;
int name_len = 0;
int new_len = 0;
- ENTRY;
if (cfg == NULL || new_name == NULL)
- RETURN(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
param = lustre_cfg_string(cfg, 1);
if (param == NULL)
- RETURN(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
value = strchr(param, '=');
if (value == NULL)
@@ -1010,7 +995,7 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg,
OBD_ALLOC(new_param, new_len);
if (new_param == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
strcpy(new_param, new_name);
if (value != NULL)
@@ -1019,7 +1004,7 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg,
OBD_ALLOC_PTR(bufs);
if (bufs == NULL) {
OBD_FREE(new_param, new_len);
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
}
lustre_cfg_bufs_reset(bufs, NULL);
@@ -1031,14 +1016,14 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg,
OBD_FREE(new_param, new_len);
OBD_FREE_PTR(bufs);
if (new_cfg == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
new_cfg->lcfg_num = cfg->lcfg_num;
new_cfg->lcfg_flags = cfg->lcfg_flags;
new_cfg->lcfg_nid = cfg->lcfg_nid;
new_cfg->lcfg_nal = cfg->lcfg_nal;
- RETURN(new_cfg);
+ return new_cfg;
}
EXPORT_SYMBOL(lustre_cfg_rename);
@@ -1244,11 +1229,10 @@ int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars,
int matched = 0, j = 0;
int rc = 0;
int skip = 0;
- ENTRY;
if (lcfg->lcfg_command != LCFG_PARAM) {
CERROR("Unknown command: %d\n", lcfg->lcfg_command);
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* fake a seq file so that var->fops->write can work... */
@@ -1295,7 +1279,7 @@ int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars,
/* If the prefix doesn't match, return error so we
can pass it down the stack */
if (strnchr(key, keylen, '.'))
- RETURN(-ENOSYS);
+ return -ENOSYS;
CERROR("%s: unknown param %s\n",
(char *)lustre_cfg_string(lcfg, 0), key);
/* rc = -EINVAL; continue parsing other params */
@@ -1316,7 +1300,7 @@ int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars,
rc = 0;
if (!rc && skip)
rc = skip;
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(class_process_proc_param);
@@ -1335,7 +1319,6 @@ int class_config_llog_handler(const struct lu_env *env,
int cfg_len = rec->lrh_len;
char *cfg_buf = (char*) (rec + 1);
int rc = 0;
- ENTRY;
//class_config_dump_handler(handle, rec, data);
@@ -1426,10 +1409,13 @@ int class_config_llog_handler(const struct lu_env *env,
}
- if ((clli->cfg_flags & CFG_F_EXCLUDE) &&
- (lcfg->lcfg_command == LCFG_LOV_ADD_OBD))
- /* Add inactive instead */
- lcfg->lcfg_command = LCFG_LOV_ADD_INA;
+ if (clli->cfg_flags & CFG_F_EXCLUDE) {
+ CDEBUG(D_CONFIG, "cmd: %x marked EXCLUDED\n",
+ lcfg->lcfg_command);
+ if (lcfg->lcfg_command == LCFG_LOV_ADD_OBD)
+ /* Add inactive instead */
+ lcfg->lcfg_command = LCFG_LOV_ADD_INA;
+ }
lustre_cfg_bufs_init(&bufs, lcfg);
@@ -1513,7 +1499,7 @@ out:
handle->lgh_ctxt->loc_obd->obd_name, rc);
class_config_dump_handler(NULL, handle, rec, data);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(class_config_llog_handler);
@@ -1524,12 +1510,11 @@ int class_config_parse_llog(const struct lu_env *env, struct llog_ctxt *ctxt,
struct llog_handle *llh;
llog_cb_t callback;
int rc;
- ENTRY;
CDEBUG(D_INFO, "looking up llog %s\n", name);
rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS);
if (rc)
- RETURN(rc);
+ return rc;
rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL);
if (rc)
@@ -1555,7 +1540,7 @@ int class_config_parse_llog(const struct lu_env *env, struct llog_ctxt *ctxt,
parse_out:
llog_close(env, llh);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(class_config_parse_llog);
@@ -1571,12 +1556,10 @@ int class_config_parse_rec(struct llog_rec_hdr *rec, char *buf, int size)
char *end = buf + size;
int rc = 0;
- ENTRY;
-
LASSERT(rec->lrh_type == OBD_CFG_REC);
rc = lustre_cfg_sanity_check(lcfg, rec->lrh_len);
if (rc < 0)
- RETURN(rc);
+ return rc;
ptr += snprintf(ptr, end-ptr, "cmd=%05x ", lcfg->lcfg_command);
if (lcfg->lcfg_flags)
@@ -1607,7 +1590,7 @@ int class_config_parse_rec(struct llog_rec_hdr *rec, char *buf, int size)
}
/* return consumed bytes */
rc = ptr - buf;
- RETURN(rc);
+ return rc;
}
int class_config_dump_handler(const struct lu_env *env,
@@ -1617,11 +1600,9 @@ int class_config_dump_handler(const struct lu_env *env,
char *outstr;
int rc = 0;
- ENTRY;
-
OBD_ALLOC(outstr, 256);
if (outstr == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (rec->lrh_type == OBD_CFG_REC) {
class_config_parse_rec(rec, outstr, 256);
@@ -1632,7 +1613,7 @@ int class_config_dump_handler(const struct lu_env *env,
}
OBD_FREE(outstr, 256);
- RETURN(rc);
+ return rc;
}
int class_config_dump_llog(const struct lu_env *env, struct llog_ctxt *ctxt,
@@ -1641,13 +1622,11 @@ int class_config_dump_llog(const struct lu_env *env, struct llog_ctxt *ctxt,
struct llog_handle *llh;
int rc;
- ENTRY;
-
LCONSOLE_INFO("Dumping config log %s\n", name);
rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS);
if (rc)
- RETURN(rc);
+ return rc;
rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL);
if (rc)
@@ -1658,7 +1637,7 @@ parse_out:
llog_close(env, llh);
LCONSOLE_INFO("End config log %s\n", name);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(class_config_dump_llog);
@@ -1671,11 +1650,10 @@ int class_manual_cleanup(struct obd_device *obd)
struct lustre_cfg *lcfg;
struct lustre_cfg_bufs bufs;
int rc;
- ENTRY;
if (!obd) {
CERROR("empty cleanup\n");
- RETURN(-EALREADY);
+ return -EALREADY;
}
if (obd->obd_force)
@@ -1690,7 +1668,7 @@ int class_manual_cleanup(struct obd_device *obd)
lustre_cfg_bufs_set_string(&bufs, 1, flags);
lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
if (!lcfg)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = class_process_config(lcfg);
if (rc) {
@@ -1705,7 +1683,7 @@ int class_manual_cleanup(struct obd_device *obd)
CERROR("detach failed %d: %s\n", rc, obd->obd_name);
out:
lustre_cfg_free(lcfg);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(class_manual_cleanup);
@@ -1797,7 +1775,7 @@ nid_key(struct hlist_node *hnode)
exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
- RETURN(&exp->exp_connection->c_peer.nid);
+ return &exp->exp_connection->c_peer.nid;
}
/*
@@ -1812,8 +1790,8 @@ nid_kepcmp(const void *key, struct hlist_node *hnode)
LASSERT(key);
exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
- RETURN(exp->exp_connection->c_peer.nid == *(lnet_nid_t *)key &&
- !exp->exp_failed);
+ return exp->exp_connection->c_peer.nid == *(lnet_nid_t *)key &&
+ !exp->exp_failed;
}
static void *
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
index 99adad9793c..68a4d6a0eb0 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
@@ -47,10 +47,8 @@
#include <obd.h>
#include <lvfs.h>
-#include <lustre_fsfilt.h>
#include <obd_class.h>
#include <lustre/lustre_user.h>
-#include <linux/version.h>
#include <lustre_log.h>
#include <lustre_disk.h>
#include <lustre_param.h>
@@ -82,14 +80,13 @@ int lustre_process_log(struct super_block *sb, char *logname,
struct lustre_sb_info *lsi = s2lsi(sb);
struct obd_device *mgc = lsi->lsi_mgc;
int rc;
- ENTRY;
LASSERT(mgc);
LASSERT(cfg);
OBD_ALLOC_PTR(bufs);
if (bufs == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* mgc_process_config */
lustre_cfg_bufs_reset(bufs, mgc->obd_name);
@@ -119,7 +116,7 @@ int lustre_process_log(struct super_block *sb, char *logname,
rc);
/* class_obd_list(); */
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(lustre_process_log);
@@ -132,10 +129,9 @@ int lustre_end_log(struct super_block *sb, char *logname,
struct lustre_sb_info *lsi = s2lsi(sb);
struct obd_device *mgc = lsi->lsi_mgc;
int rc;
- ENTRY;
if (!mgc)
- RETURN(-ENOENT);
+ return -ENOENT;
/* mgc_process_config */
lustre_cfg_bufs_reset(&bufs, mgc->obd_name);
@@ -145,7 +141,7 @@ int lustre_end_log(struct super_block *sb, char *logname,
lcfg = lustre_cfg_new(LCFG_LOG_END, &bufs);
rc = obd_process_config(mgc, sizeof(*lcfg), lcfg);
lustre_cfg_free(lcfg);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(lustre_end_log);
@@ -225,7 +221,6 @@ int lustre_start_mgc(struct super_block *sb)
char *ptr;
int recov_bk;
int rc = 0, i = 0, j, len;
- ENTRY;
LASSERT(lsi->lsi_lmd);
@@ -254,7 +249,7 @@ int lustre_start_mgc(struct super_block *sb)
}
if (i == 0) {
CERROR("No valid MGS nids found.\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
mutex_lock(&mgc_start_lock);
@@ -478,7 +473,7 @@ out_free:
OBD_FREE(mgcname, len);
if (niduuid)
OBD_FREE(niduuid, len + 2);
- RETURN(rc);
+ return rc;
}
static int lustre_stop_mgc(struct super_block *sb)
@@ -487,13 +482,12 @@ static int lustre_stop_mgc(struct super_block *sb)
struct obd_device *obd;
char *niduuid = 0, *ptr = 0;
int i, rc = 0, len = 0;
- ENTRY;
if (!lsi)
- RETURN(-ENOENT);
+ return -ENOENT;
obd = lsi->lsi_mgc;
if (!obd)
- RETURN(-ENOENT);
+ return -ENOENT;
lsi->lsi_mgc = NULL;
mutex_lock(&mgc_start_lock);
@@ -549,7 +543,7 @@ out:
/* class_import_put will get rid of the additional connections */
mutex_unlock(&mgc_start_lock);
- RETURN(rc);
+ return rc;
}
/***************** lustre superblock **************/
@@ -557,15 +551,14 @@ out:
struct lustre_sb_info *lustre_init_lsi(struct super_block *sb)
{
struct lustre_sb_info *lsi;
- ENTRY;
OBD_ALLOC_PTR(lsi);
if (!lsi)
- RETURN(NULL);
+ return NULL;
OBD_ALLOC_PTR(lsi->lsi_lmd);
if (!lsi->lsi_lmd) {
OBD_FREE_PTR(lsi);
- RETURN(NULL);
+ return NULL;
}
lsi->lsi_lmd->lmd_exclude_count = 0;
@@ -578,13 +571,12 @@ struct lustre_sb_info *lustre_init_lsi(struct super_block *sb)
/* Default umount style */
lsi->lsi_flags = LSI_UMOUNT_FAILOVER;
- RETURN(lsi);
+ return lsi;
}
static int lustre_free_lsi(struct super_block *sb)
{
struct lustre_sb_info *lsi = s2lsi(sb);
- ENTRY;
LASSERT(lsi != NULL);
CDEBUG(D_MOUNT, "Freeing lsi %p\n", lsi);
@@ -625,7 +617,7 @@ static int lustre_free_lsi(struct super_block *sb)
OBD_FREE(lsi, sizeof(*lsi));
s2lsi_nocast(sb) = NULL;
- RETURN(0);
+ return 0;
}
/* The lsi has one reference for every server that is using the disk -
@@ -633,7 +625,6 @@ static int lustre_free_lsi(struct super_block *sb)
int lustre_put_lsi(struct super_block *sb)
{
struct lustre_sb_info *lsi = s2lsi(sb);
- ENTRY;
LASSERT(lsi != NULL);
@@ -645,11 +636,20 @@ int lustre_put_lsi(struct super_block *sb)
obd_zombie_barrier();
}
lustre_free_lsi(sb);
- RETURN(1);
+ return 1;
}
- RETURN(0);
+ return 0;
}
+/*** SERVER NAME ***
+ * <FSNAME><SEPERATOR><TYPE><INDEX>
+ * FSNAME is between 1 and 8 characters (inclusive).
+ * Excluded characters are '/' and ':'
+ * SEPERATOR is either ':' or '-'
+ * TYPE: "OST", "MDT", etc.
+ * INDEX: Hex representation of the index
+ */
+
/** Get the fsname ("lustre") from the server name ("lustre-OST003F").
* @param [in] svname server name including type and index
* @param [out] fsname Buffer to copy filesystem name prefix into.
@@ -659,22 +659,13 @@ int lustre_put_lsi(struct super_block *sb)
*/
int server_name2fsname(const char *svname, char *fsname, const char **endptr)
{
- const char *dash = strrchr(svname, '-');
- if (!dash) {
- dash = strrchr(svname, ':');
- if (!dash)
- return -EINVAL;
- }
+ const char *dash;
- /* interpret <fsname>-MDTXXXXX-mdc as mdt, the better way is to pass
- * in the fsname, then determine the server index */
- if (!strcmp(LUSTRE_MDC_NAME, dash + 1)) {
- dash--;
- for (; dash > svname && *dash != '-' && *dash != ':'; dash--)
- ;
- if (dash == svname)
- return -EINVAL;
- }
+ dash = svname + strnlen(svname, 8); /* max fsname length is 8 */
+ for (; dash > svname && *dash != '-' && *dash != ':'; dash--)
+ ;
+ if (dash == svname)
+ return -EINVAL;
if (fsname != NULL) {
strncpy(fsname, svname, dash - svname);
@@ -697,15 +688,15 @@ int server_name2svname(const char *label, char *svname, const char **endptr,
size_t svsize)
{
int rc;
- const const char *dash;
+ const char *dash;
/* We use server_name2fsname() just for parsing */
rc = server_name2fsname(label, NULL, &dash);
if (rc != 0)
return rc;
- if (*dash != '-')
- return -1;
+ if (endptr != NULL)
+ *endptr = dash;
if (strlcpy(svname, dash + 1, svsize) >= svsize)
return -E2BIG;
@@ -730,9 +721,6 @@ int server_name2index(const char *svname, __u32 *idx, const char **endptr)
if (rc != 0)
return rc;
- if (*dash != '-')
- return -EINVAL;
-
dash++;
if (strncmp(dash, "MDT", 3) == 0)
@@ -744,11 +732,20 @@ int server_name2index(const char *svname, __u32 *idx, const char **endptr)
dash += 3;
- if (strcmp(dash, "all") == 0)
+ if (strncmp(dash, "all", 3) == 0) {
+ if (endptr != NULL)
+ *endptr = dash + 3;
return rc | LDD_F_SV_ALL;
+ }
index = simple_strtoul(dash, (char **)endptr, 16);
- *idx = index;
+ if (idx != NULL)
+ *idx = index;
+
+ /* Account for -mdc after index that is possible when specifying mdt */
+ if (endptr != NULL && strncmp(LUSTRE_MDC_NAME, *endptr + 1,
+ sizeof(LUSTRE_MDC_NAME)-1) == 0)
+ *endptr += sizeof(LUSTRE_MDC_NAME);
return rc;
}
@@ -760,7 +757,6 @@ EXPORT_SYMBOL(server_name2index);
int lustre_common_put_super(struct super_block *sb)
{
int rc;
- ENTRY;
CDEBUG(D_MOUNT, "dropping sb %p\n", sb);
@@ -769,7 +765,7 @@ int lustre_common_put_super(struct super_block *sb)
if (rc && (rc != -ENOENT)) {
if (rc != -EBUSY) {
CERROR("Can't stop MGC: %d\n", rc);
- RETURN(rc);
+ return rc;
}
/* BUSY just means that there's some other obd that
needs the mgc. Let him clean it up. */
@@ -778,7 +774,7 @@ int lustre_common_put_super(struct super_block *sb)
/* Drop a ref to the mounted disk */
lustre_put_lsi(sb);
lu_types_stop();
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(lustre_common_put_super);
@@ -816,12 +812,11 @@ int lustre_check_exclusion(struct super_block *sb, char *svname)
struct lustre_mount_data *lmd = lsi->lsi_lmd;
__u32 index;
int i, rc;
- ENTRY;
rc = server_name2index(svname, &index, NULL);
if (rc != LDD_F_SV_TYPE_OST)
/* Only exclude OSTs */
- RETURN(0);
+ return 0;
CDEBUG(D_MOUNT, "Check exclusion %s (%d) in %d of %s\n", svname,
index, lmd->lmd_exclude_count, lmd->lmd_dev);
@@ -829,10 +824,10 @@ int lustre_check_exclusion(struct super_block *sb, char *svname)
for(i = 0; i < lmd->lmd_exclude_count; i++) {
if (index == lmd->lmd_exclude[i]) {
CWARN("Excluding %s (on exclusion list)\n", svname);
- RETURN(1);
+ return 1;
}
}
- RETURN(0);
+ return 0;
}
/* mount -v -o exclude=lustre-OST0001:lustre-OST0002 -t lustre ... */
@@ -841,7 +836,6 @@ static int lmd_make_exclusion(struct lustre_mount_data *lmd, const char *ptr)
const char *s1 = ptr, *s2;
__u32 index, *exclude_list;
int rc = 0, devmax;
- ENTRY;
/* The shortest an ost name can be is 8 chars: -OST0000.
We don't actually know the fsname at this time, so in fact
@@ -851,20 +845,22 @@ static int lmd_make_exclusion(struct lustre_mount_data *lmd, const char *ptr)
/* temp storage until we figure out how many we have */
OBD_ALLOC(exclude_list, sizeof(index) * devmax);
if (!exclude_list)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* we enter this fn pointing at the '=' */
while (*s1 && *s1 != ' ' && *s1 != ',') {
s1++;
rc = server_name2index(s1, &index, &s2);
if (rc < 0) {
- CERROR("Can't parse server name '%s'\n", s1);
+ CERROR("Can't parse server name '%s': rc = %d\n",
+ s1, rc);
break;
}
if (rc == LDD_F_SV_TYPE_OST)
exclude_list[lmd->lmd_exclude_count++] = index;
else
- CDEBUG(D_MOUNT, "ignoring exclude %.7s\n", s1);
+ CDEBUG(D_MOUNT, "ignoring exclude %.*s: type = %#x\n",
+ (uint)(s2-s1), s1, rc);
s1 = s2;
/* now we are pointing at ':' (next exclude)
or ',' (end of excludes) */
@@ -887,7 +883,7 @@ static int lmd_make_exclusion(struct lustre_mount_data *lmd, const char *ptr)
}
}
OBD_FREE(exclude_list, sizeof(index) * devmax);
- RETURN(rc);
+ return rc;
}
static int lmd_parse_mgssec(struct lustre_mount_data *lmd, char *ptr)
@@ -991,13 +987,12 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
char *s1, *s2, *devname = NULL;
struct lustre_mount_data *raw = (struct lustre_mount_data *)options;
int rc = 0;
- ENTRY;
LASSERT(lmd);
if (!options) {
LCONSOLE_ERROR_MSG(0x162, "Missing mount data: check that "
"/sbin/mount.lustre is installed.\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* Options should be a string - try to detect old lmd data */
@@ -1005,13 +1000,13 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
LCONSOLE_ERROR_MSG(0x163, "You're using an old version of "
"/sbin/mount.lustre. Please install "
"version %s\n", LUSTRE_VERSION_STRING);
- RETURN(-EINVAL);
+ return -EINVAL;
}
lmd->lmd_magic = LMD_MAGIC;
OBD_ALLOC(lmd->lmd_params, 4096);
if (lmd->lmd_params == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lmd->lmd_params[0] = '\0';
/* Set default flags here */
@@ -1150,14 +1145,14 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
/* Freed in lustre_free_lsi */
OBD_ALLOC(lmd->lmd_profile, strlen(s1) + 8);
if (!lmd->lmd_profile)
- RETURN(-ENOMEM);
+ return -ENOMEM;
sprintf(lmd->lmd_profile, "%s-client", s1);
}
/* Freed in lustre_free_lsi */
OBD_ALLOC(lmd->lmd_dev, strlen(devname) + 1);
if (!lmd->lmd_dev)
- RETURN(-ENOMEM);
+ return -ENOMEM;
strcpy(lmd->lmd_dev, devname);
/* Save mount options */
@@ -1168,18 +1163,18 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
/* Freed in lustre_free_lsi */
OBD_ALLOC(lmd->lmd_opts, strlen(options) + 1);
if (!lmd->lmd_opts)
- RETURN(-ENOMEM);
+ return -ENOMEM;
strcpy(lmd->lmd_opts, options);
}
lmd_print(lmd);
lmd->lmd_magic = LMD_MAGIC;
- RETURN(rc);
+ return rc;
invalid:
CERROR("Bad mount options %s\n", options);
- RETURN(-EINVAL);
+ return -EINVAL;
}
struct lustre_mount_data2 {
@@ -1198,13 +1193,12 @@ int lustre_fill_super(struct super_block *sb, void *data, int silent)
struct lustre_mount_data2 *lmd2 = data;
struct lustre_sb_info *lsi;
int rc;
- ENTRY;
CDEBUG(D_MOUNT|D_VFSTRACE, "VFS Op: sb %p\n", sb);
lsi = lustre_init_lsi(sb);
if (!lsi)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lmd = lsi->lsi_lmd;
/*
diff --git a/drivers/staging/lustre/lustre/obdclass/obdo.c b/drivers/staging/lustre/lustre/obdclass/obdo.c
index 01a0e1f83a6..70997648a4f 100644
--- a/drivers/staging/lustre/lustre/obdclass/obdo.c
+++ b/drivers/staging/lustre/lustre/obdclass/obdo.c
@@ -100,11 +100,11 @@ void obdo_from_inode(struct obdo *dst, struct inode *src, obd_flag valid)
newvalid |= OBD_MD_FLMODE;
}
if (valid & OBD_MD_FLUID) {
- dst->o_uid = src->i_uid;
+ dst->o_uid = from_kuid(&init_user_ns, src->i_uid);
newvalid |= OBD_MD_FLUID;
}
if (valid & OBD_MD_FLGID) {
- dst->o_gid = src->i_gid;
+ dst->o_gid = from_kgid(&init_user_ns, src->i_gid);
newvalid |= OBD_MD_FLGID;
}
if (valid & OBD_MD_FLFLAGS) {
@@ -232,16 +232,16 @@ void obdo_from_iattr(struct obdo *oa, struct iattr *attr, unsigned int ia_valid)
if (ia_valid & ATTR_MODE) {
oa->o_mode = attr->ia_mode;
oa->o_valid |= OBD_MD_FLTYPE | OBD_MD_FLMODE;
- if (!current_is_in_group(oa->o_gid) &&
+ if (!in_group_p(make_kgid(&init_user_ns, oa->o_gid)) &&
!cfs_capable(CFS_CAP_FSETID))
oa->o_mode &= ~S_ISGID;
}
if (ia_valid & ATTR_UID) {
- oa->o_uid = attr->ia_uid;
+ oa->o_uid = from_kuid(&init_user_ns, attr->ia_uid);
oa->o_valid |= OBD_MD_FLUID;
}
if (ia_valid & ATTR_GID) {
- oa->o_gid = attr->ia_gid;
+ oa->o_gid = from_kgid(&init_user_ns, attr->ia_gid);
oa->o_valid |= OBD_MD_FLGID;
}
}
@@ -281,16 +281,16 @@ void iattr_from_obdo(struct iattr *attr, struct obdo *oa, obd_flag valid)
if (valid & OBD_MD_FLMODE) {
attr->ia_mode = (attr->ia_mode & S_IFMT)|(oa->o_mode & ~S_IFMT);
attr->ia_valid |= ATTR_MODE;
- if (!current_is_in_group(oa->o_gid) &&
+ if (!in_group_p(make_kgid(&init_user_ns, oa->o_gid)) &&
!cfs_capable(CFS_CAP_FSETID))
attr->ia_mode &= ~S_ISGID;
}
if (valid & OBD_MD_FLUID) {
- attr->ia_uid = oa->o_uid;
+ attr->ia_uid = make_kuid(&init_user_ns, oa->o_uid);
attr->ia_valid |= ATTR_UID;
}
if (valid & OBD_MD_FLGID) {
- attr->ia_gid = oa->o_gid;
+ attr->ia_gid = make_kgid(&init_user_ns, oa->o_gid);
attr->ia_valid |= ATTR_GID;
}
}
diff --git a/drivers/staging/lustre/lustre/obdecho/echo.c b/drivers/staging/lustre/lustre/obdecho/echo.c
index 9e64939af9d..debb9cec490 100644
--- a/drivers/staging/lustre/lustre/obdecho/echo.c
+++ b/drivers/staging/lustre/lustre/obdecho/echo.c
@@ -96,12 +96,10 @@ static int echo_init_export(struct obd_export *exp)
static int echo_destroy_export(struct obd_export *exp)
{
- ENTRY;
-
target_destroy_export(exp);
ldlm_destroy_export(exp);
- RETURN(0);
+ return 0;
}
static __u64 echo_next_id(struct obd_device *obddev)
@@ -151,25 +149,24 @@ static int echo_destroy(const struct lu_env *env, struct obd_export *exp,
{
struct obd_device *obd = class_exp2obd(exp);
- ENTRY;
if (!obd) {
CERROR("invalid client cookie "LPX64"\n",
exp->exp_handle.h_cookie);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (!(oa->o_valid & OBD_MD_FLID)) {
CERROR("obdo missing FLID valid flag: "LPX64"\n", oa->o_valid);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (ostid_id(&oa->o_oi) > obd->u.echo.eo_lastino ||
ostid_id(&oa->o_oi) < ECHO_INIT_OID) {
CERROR("bad destroy objid: "DOSTID"\n", POSTID(&oa->o_oi));
- RETURN(-EINVAL);
+ return -EINVAL;
}
- RETURN(0);
+ return 0;
}
static int echo_getattr(const struct lu_env *env, struct obd_export *exp,
@@ -178,24 +175,23 @@ static int echo_getattr(const struct lu_env *env, struct obd_export *exp,
struct obd_device *obd = class_exp2obd(exp);
obd_id id = ostid_id(&oinfo->oi_oa->o_oi);
- ENTRY;
if (!obd) {
CERROR("invalid client cookie "LPX64"\n",
exp->exp_handle.h_cookie);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (!(oinfo->oi_oa->o_valid & OBD_MD_FLID)) {
CERROR("obdo missing FLID valid flag: "LPX64"\n",
oinfo->oi_oa->o_valid);
- RETURN(-EINVAL);
+ return -EINVAL;
}
obdo_cpy_md(oinfo->oi_oa, &obd->u.echo.eo_oa, oinfo->oi_oa->o_valid);
ostid_set_seq_echo(&oinfo->oi_oa->o_oi);
ostid_set_id(&oinfo->oi_oa->o_oi, id);
- RETURN(0);
+ return 0;
}
static int echo_setattr(const struct lu_env *env, struct obd_export *exp,
@@ -203,17 +199,16 @@ static int echo_setattr(const struct lu_env *env, struct obd_export *exp,
{
struct obd_device *obd = class_exp2obd(exp);
- ENTRY;
if (!obd) {
CERROR("invalid client cookie "LPX64"\n",
exp->exp_handle.h_cookie);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (!(oinfo->oi_oa->o_valid & OBD_MD_FLID)) {
CERROR("obdo missing FLID valid flag: "LPX64"\n",
oinfo->oi_oa->o_valid);
- RETURN(-EINVAL);
+ return -EINVAL;
}
memcpy(&obd->u.echo.eo_oa, oinfo->oi_oa, sizeof(*oinfo->oi_oa));
@@ -225,7 +220,7 @@ static int echo_setattr(const struct lu_env *env, struct obd_export *exp,
oti->oti_ack_locks[0].lock = obd->u.echo.eo_nl_lock;
}
- RETURN(0);
+ return 0;
}
static void
@@ -410,11 +405,10 @@ static int echo_preprw(const struct lu_env *env, int cmd,
int tot_bytes = 0;
int rc = 0;
int i, left;
- ENTRY;
obd = export->exp_obd;
if (obd == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
/* Temp fix to stop falling foul of osc_announce_cached() */
oa->o_valid &= ~(OBD_MD_FLBLOCKS | OBD_MD_FLGRANT);
@@ -456,7 +450,7 @@ static int echo_preprw(const struct lu_env *env, int cmd,
CDEBUG(D_PAGE, "%d pages allocated after prep\n",
atomic_read(&obd->u.echo.eo_prep));
- RETURN(0);
+ return 0;
preprw_cleanup:
/* It is possible that we would rather handle errors by allow
@@ -487,11 +481,10 @@ static int echo_commitrw(const struct lu_env *env, int cmd,
struct obd_device *obd;
int pgs = 0;
int i;
- ENTRY;
obd = export->exp_obd;
if (obd == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
if (rc)
GOTO(commitrw_cleanup, rc);
@@ -506,7 +499,7 @@ static int echo_commitrw(const struct lu_env *env, int cmd,
if (niocount && res == NULL) {
CERROR("NULL res niobuf with niocount %d\n", niocount);
- RETURN(-EINVAL);
+ return -EINVAL;
}
LASSERT(oti == NULL || oti->oti_handle == (void *)DESC_PRIV);
@@ -537,7 +530,7 @@ static int echo_commitrw(const struct lu_env *env, int cmd,
CDEBUG(D_PAGE, "%d pages remain after commit\n",
atomic_read(&obd->u.echo.eo_prep));
- RETURN(rc);
+ return rc;
commitrw_cleanup:
atomic_sub(pgs, &obd->u.echo.eo_prep);
@@ -565,7 +558,6 @@ static int echo_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
__u64 lock_flags = 0;
struct ldlm_res_id res_id = {.name = {1}};
char ns_name[48];
- ENTRY;
obd->u.echo.eo_obt.obt_magic = OBT_MAGIC;
spin_lock_init(&obd->u.echo.eo_lock);
@@ -578,7 +570,7 @@ static int echo_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
LDLM_NS_TYPE_OST);
if (obd->obd_namespace == NULL) {
LBUG();
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
rc = ldlm_cli_enqueue_local(obd->obd_namespace, &res_id, LDLM_PLAIN,
@@ -600,13 +592,12 @@ static int echo_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
ptlrpc_init_client (LDLM_CB_REQUEST_PORTAL, LDLM_CB_REPLY_PORTAL,
"echo_ldlm_cb_client", &obd->obd_ldlm_client);
- RETURN(0);
+ return 0;
}
static int echo_cleanup(struct obd_device *obd)
{
int leaked;
- ENTRY;
lprocfs_obd_cleanup(obd);
lprocfs_free_obd_stats(obd);
@@ -624,7 +615,7 @@ static int echo_cleanup(struct obd_device *obd)
if (leaked != 0)
CERROR("%d prep/commitrw pages leaked\n", leaked);
- RETURN(0);
+ return 0;
}
struct obd_ops echo_obd_ops = {
diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c
index 184195fde62..2644edf438c 100644
--- a/drivers/staging/lustre/lustre/obdecho/echo_client.c
+++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c
@@ -43,6 +43,7 @@
#include <lustre_debug.h>
#include <lprocfs_status.h>
#include <cl_object.h>
+#include <md_object.h>
#include <lustre_fid.h>
#include <lustre_acl.h>
#include <lustre_net.h>
@@ -312,11 +313,9 @@ static void echo_page_fini(const struct lu_env *env,
struct echo_page *ep = cl2echo_page(slice);
struct echo_object *eco = cl2echo_obj(slice->cpl_obj);
struct page *vmpage = ep->ep_vmpage;
- ENTRY;
atomic_dec(&eco->eo_npages);
page_cache_release(vmpage);
- EXIT;
}
static int echo_page_prep(const struct lu_env *env,
@@ -408,14 +407,13 @@ static int echo_page_init(const struct lu_env *env, struct cl_object *obj,
{
struct echo_page *ep = cl_object_page_slice(obj, page);
struct echo_object *eco = cl2echo_obj(obj);
- ENTRY;
ep->ep_vmpage = vmpage;
page_cache_get(vmpage);
mutex_init(&ep->ep_lock);
cl_page_slice_add(page, &ep->ep_cl, obj, &echo_page_ops);
atomic_inc(&eco->eo_npages);
- RETURN(0);
+ return 0;
}
static int echo_io_init(const struct lu_env *env, struct cl_object *obj,
@@ -429,7 +427,6 @@ static int echo_lock_init(const struct lu_env *env,
const struct cl_io *unused)
{
struct echo_lock *el;
- ENTRY;
OBD_SLAB_ALLOC_PTR_GFP(el, echo_lock_kmem, __GFP_IO);
if (el != NULL) {
@@ -438,7 +435,7 @@ static int echo_lock_init(const struct lu_env *env,
INIT_LIST_HEAD(&el->el_chain);
atomic_set(&el->el_refcount, 0);
}
- RETURN(el == NULL ? -ENOMEM : 0);
+ return el == NULL ? -ENOMEM : 0;
}
static int echo_conf_set(const struct lu_env *env, struct cl_object *obj,
@@ -467,7 +464,6 @@ static int echo_object_init(const struct lu_env *env, struct lu_object *obj,
struct echo_device *ed = cl2echo_dev(lu2cl_dev(obj->lo_dev));
struct echo_client_obd *ec = ed->ed_ec;
struct echo_object *eco = cl2echo_obj(lu2cl(obj));
- ENTRY;
if (ed->ed_next) {
struct lu_object *below;
@@ -477,7 +473,7 @@ static int echo_object_init(const struct lu_env *env, struct lu_object *obj,
below = under->ld_ops->ldo_object_alloc(env, obj->lo_header,
under);
if (below == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
lu_object_add(obj, below);
}
@@ -501,7 +497,7 @@ static int echo_object_init(const struct lu_env *env, struct lu_object *obj,
list_add_tail(&eco->eo_obj_chain, &ec->ec_objects);
spin_unlock(&ec->ec_lock);
- RETURN(0);
+ return 0;
}
/* taken from osc_unpackmd() */
@@ -510,8 +506,6 @@ static int echo_alloc_memmd(struct echo_device *ed,
{
int lsm_size;
- ENTRY;
-
/* If export is lov/osc then use their obd method */
if (ed->ed_next != NULL)
return obd_alloc_memmd(ed->ed_ec->ec_exp, lsmp);
@@ -521,27 +515,25 @@ static int echo_alloc_memmd(struct echo_device *ed,
LASSERT(*lsmp == NULL);
OBD_ALLOC(*lsmp, lsm_size);
if (*lsmp == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
OBD_ALLOC((*lsmp)->lsm_oinfo[0], sizeof(struct lov_oinfo));
if ((*lsmp)->lsm_oinfo[0] == NULL) {
OBD_FREE(*lsmp, lsm_size);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
loi_init((*lsmp)->lsm_oinfo[0]);
(*lsmp)->lsm_maxbytes = LUSTRE_STRIPE_MAXBYTES;
ostid_set_seq_echo(&(*lsmp)->lsm_oi);
- RETURN(lsm_size);
+ return lsm_size;
}
static int echo_free_memmd(struct echo_device *ed, struct lov_stripe_md **lsmp)
{
int lsm_size;
- ENTRY;
-
/* If export is lov/osc then use their obd method */
if (ed->ed_next != NULL)
return obd_free_memmd(ed->ed_ec->ec_exp, lsmp);
@@ -552,14 +544,13 @@ static int echo_free_memmd(struct echo_device *ed, struct lov_stripe_md **lsmp)
OBD_FREE((*lsmp)->lsm_oinfo[0], sizeof(struct lov_oinfo));
OBD_FREE(*lsmp, lsm_size);
*lsmp = NULL;
- RETURN(0);
+ return 0;
}
static void echo_object_free(const struct lu_env *env, struct lu_object *obj)
{
struct echo_object *eco = cl2echo_obj(lu2cl(obj));
struct echo_client_obd *ec = eco->eo_dev->ed_ec;
- ENTRY;
LASSERT(atomic_read(&eco->eo_npages) == 0);
@@ -573,7 +564,6 @@ static void echo_object_free(const struct lu_env *env, struct lu_object *obj)
if (eco->eo_lsm)
echo_free_memmd(eco->eo_dev, &eco->eo_lsm);
OBD_SLAB_FREE_PTR(eco, echo_object_kmem);
- EXIT;
}
static int echo_object_print(const struct lu_env *env, void *cookie,
@@ -606,7 +596,6 @@ static struct lu_object *echo_object_alloc(const struct lu_env *env,
{
struct echo_object *eco;
struct lu_object *obj = NULL;
- ENTRY;
/* we're the top dev. */
LASSERT(hdr == NULL);
@@ -622,7 +611,7 @@ static struct lu_object *echo_object_alloc(const struct lu_env *env,
eco->eo_cl.co_ops = &echo_cl_obj_ops;
obj->lo_ops = &echo_lu_obj_ops;
}
- RETURN(obj);
+ return obj;
}
static struct lu_device_operations echo_device_lu_ops = {
@@ -648,7 +637,7 @@ static int echo_site_init(const struct lu_env *env, struct echo_device *ed)
/* initialize site */
rc = cl_site_init(site, &ed->ed_cl);
if (rc) {
- CERROR("Cannot initilize site for echo client(%d)\n", rc);
+ CERROR("Cannot initialize site for echo client(%d)\n", rc);
return rc;
}
@@ -737,11 +726,10 @@ static int echo_fid_init(struct echo_device *ed, char *obd_name,
{
char *prefix;
int rc;
- ENTRY;
OBD_ALLOC_PTR(ed->ed_cl_seq);
if (ed->ed_cl_seq == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
OBD_ALLOC(prefix, MAX_OBD_NAME + 5);
if (prefix == NULL)
@@ -758,18 +746,17 @@ static int echo_fid_init(struct echo_device *ed, char *obd_name,
if (rc)
GOTO(out_free_seq, rc);
- RETURN(0);
+ return 0;
out_free_seq:
OBD_FREE_PTR(ed->ed_cl_seq);
ed->ed_cl_seq = NULL;
- RETURN(rc);
+ return rc;
}
static int echo_fid_fini(struct obd_device *obddev)
{
struct echo_device *ed = obd2echo_dev(obddev);
- ENTRY;
if (ed->ed_cl_seq != NULL) {
seq_client_fini(ed->ed_cl_seq);
@@ -777,7 +764,7 @@ static int echo_fid_fini(struct obd_device *obddev)
ed->ed_cl_seq = NULL;
}
- RETURN(0);
+ return 0;
}
static struct lu_device *echo_device_alloc(const struct lu_env *env,
@@ -792,7 +779,6 @@ static struct lu_device *echo_device_alloc(const struct lu_env *env,
const char *tgt_type_name;
int rc;
int cleanup = 0;
- ENTRY;
OBD_ALLOC_PTR(ed);
if (ed == NULL)
@@ -916,7 +902,7 @@ static struct lu_device *echo_device_alloc(const struct lu_env *env,
}
ed->ed_next = next;
- RETURN(&cd->cd_lu_dev);
+ return &cd->cd_lu_dev;
out:
switch(cleanup) {
case 4: {
@@ -1076,7 +1062,6 @@ static struct echo_object *cl_echo_object_find(struct echo_device *d,
struct lu_fid *fid;
int refcheck;
int rc;
- ENTRY;
LASSERT(lsmp);
lsm = *lsmp;
@@ -1087,11 +1072,11 @@ static struct echo_object *cl_echo_object_find(struct echo_device *d,
/* Never return an object if the obd is to be freed. */
if (echo_dev2cl(d)->cd_lu_dev.ld_obd->obd_stopping)
- RETURN(ERR_PTR(-ENODEV));
+ return ERR_PTR(-ENODEV);
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN((void *)env);
+ return (void *)env;
info = echo_env_info(env);
conf = &info->eti_conf;
@@ -1131,7 +1116,7 @@ static struct echo_object *cl_echo_object_find(struct echo_device *d,
out:
cl_env_put(env, &refcheck);
- RETURN(eco);
+ return eco;
}
static int cl_echo_object_put(struct echo_object *eco)
@@ -1139,11 +1124,10 @@ static int cl_echo_object_put(struct echo_object *eco)
struct lu_env *env;
struct cl_object *obj = echo_obj2cl(eco);
int refcheck;
- ENTRY;
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
/* an external function to kill an object? */
if (eco->eo_deleted) {
@@ -1154,7 +1138,7 @@ static int cl_echo_object_put(struct echo_object *eco)
cl_object_put(env, obj);
cl_env_put(env, &refcheck);
- RETURN(0);
+ return 0;
}
static int cl_echo_enqueue0(struct lu_env *env, struct echo_object *eco,
@@ -1167,7 +1151,6 @@ static int cl_echo_enqueue0(struct lu_env *env, struct echo_object *eco,
struct cl_lock_descr *descr;
struct echo_thread_info *info;
int rc = -ENOMEM;
- ENTRY;
info = echo_env_info(env);
io = &info->eti_io;
@@ -1201,7 +1184,7 @@ static int cl_echo_enqueue0(struct lu_env *env, struct echo_object *eco,
cl_lock_release(env, lck, "ec enqueue", current);
}
}
- RETURN(rc);
+ return rc;
}
static int cl_echo_enqueue(struct echo_object *eco, obd_off start, obd_off end,
@@ -1212,11 +1195,10 @@ static int cl_echo_enqueue(struct echo_object *eco, obd_off start, obd_off end,
struct cl_io *io;
int refcheck;
int result;
- ENTRY;
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
info = echo_env_info(env);
io = &info->eti_io;
@@ -1230,7 +1212,6 @@ static int cl_echo_enqueue(struct echo_object *eco, obd_off start, obd_off end,
result = cl_echo_enqueue0(env, eco, start, end, mode, cookie, 0);
cl_io_fini(env, io);
- EXIT;
out:
cl_env_put(env, &refcheck);
return result;
@@ -1243,7 +1224,6 @@ static int cl_echo_cancel0(struct lu_env *env, struct echo_device *ed,
struct echo_lock *ecl = NULL;
struct list_head *el;
int found = 0, still_used = 0;
- ENTRY;
LASSERT(ec != NULL);
spin_lock(&ec->ec_lock);
@@ -1262,10 +1242,10 @@ static int cl_echo_cancel0(struct lu_env *env, struct echo_device *ed,
spin_unlock(&ec->ec_lock);
if (!found)
- RETURN(-ENOENT);
+ return -ENOENT;
echo_lock_release(env, ecl, still_used);
- RETURN(0);
+ return 0;
}
static int cl_echo_cancel(struct echo_device *ed, __u64 cookie)
@@ -1273,16 +1253,15 @@ static int cl_echo_cancel(struct echo_device *ed, __u64 cookie)
struct lu_env *env;
int refcheck;
int rc;
- ENTRY;
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
rc = cl_echo_cancel0(env, ed, cookie);
cl_env_put(env, &refcheck);
- RETURN(rc);
+ return rc;
}
static int cl_echo_async_brw(const struct lu_env *env, struct cl_io *io,
@@ -1291,7 +1270,6 @@ static int cl_echo_async_brw(const struct lu_env *env, struct cl_io *io,
struct cl_page *clp;
struct cl_page *temp;
int result = 0;
- ENTRY;
cl_page_list_for_each_safe(clp, temp, &queue->c2_qin) {
int rc;
@@ -1300,7 +1278,7 @@ static int cl_echo_async_brw(const struct lu_env *env, struct cl_io *io,
continue;
result = result ?: rc;
}
- RETURN(result);
+ return result;
}
static int cl_echo_object_brw(struct echo_object *eco, int rw, obd_off offset,
@@ -1318,13 +1296,12 @@ static int cl_echo_object_brw(struct echo_object *eco, int rw, obd_off offset,
int refcheck;
int rc;
int i;
- ENTRY;
LASSERT((offset & ~CFS_PAGE_MASK) == 0);
LASSERT(ed->ed_next != NULL);
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
info = echo_env_info(env);
io = &info->eti_io;
@@ -1386,7 +1363,6 @@ static int cl_echo_object_brw(struct echo_object *eco, int rw, obd_off offset,
}
cl_echo_cancel0(env, ed, lh.cookie);
- EXIT;
error_lock:
cl_2queue_discard(env, io, queue);
cl_2queue_disown(env, io, queue);
@@ -1467,13 +1443,11 @@ static int echo_big_lmm_get(const struct lu_env *env, struct md_object *o,
struct echo_thread_info *info = echo_env_info(env);
int rc;
- ENTRY;
-
LASSERT(ma->ma_lmm_size > 0);
rc = mo_xattr_get(env, o, &LU_BUF_NULL, XATTR_NAME_LOV);
if (rc < 0)
- RETURN(rc);
+ return rc;
/* big_lmm may need to be grown */
if (info->eti_big_lmmsize < rc) {
@@ -1490,7 +1464,7 @@ static int echo_big_lmm_get(const struct lu_env *env, struct md_object *o,
OBD_ALLOC_LARGE(info->eti_big_lmm, size);
if (info->eti_big_lmm == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
info->eti_big_lmmsize = size;
}
LASSERT(info->eti_big_lmmsize >= rc);
@@ -1499,13 +1473,13 @@ static int echo_big_lmm_get(const struct lu_env *env, struct md_object *o,
info->eti_buf.lb_len = info->eti_big_lmmsize;
rc = mo_xattr_get(env, o, &info->eti_buf, XATTR_NAME_LOV);
if (rc < 0)
- RETURN(rc);
+ return rc;
ma->ma_valid |= MA_LOV;
ma->ma_lmm = info->eti_big_lmm;
ma->ma_lmm_size = rc;
- RETURN(0);
+ return 0;
}
int echo_attr_get_complex(const struct lu_env *env, struct md_object *next,
@@ -1517,8 +1491,6 @@ int echo_attr_get_complex(const struct lu_env *env, struct md_object *next,
int need = ma->ma_need;
int rc = 0, rc2;
- ENTRY;
-
ma->ma_valid = 0;
if (need & MA_INODE) {
@@ -1571,7 +1543,7 @@ out:
ma->ma_need = need;
CDEBUG(D_INODE, "after getattr rc = %d, ma_valid = "LPX64" ma_lmm=%p\n",
rc, ma->ma_valid, ma->ma_lmm);
- RETURN(rc);
+ return rc;
}
static int
@@ -1587,8 +1559,6 @@ echo_md_create_internal(const struct lu_env *env, struct echo_device *ed,
struct lu_object_conf conf = { .loc_flags = LOC_F_NEW };
int rc;
- ENTRY;
-
rc = mdo_lookup(env, parent, lname, fid2, spec);
if (rc == 0)
return -EEXIST;
@@ -1600,7 +1570,7 @@ echo_md_create_internal(const struct lu_env *env, struct echo_device *ed,
if (IS_ERR(ec_child)) {
CERROR("Can not find the child "DFID": rc = %ld\n", PFID(fid),
PTR_ERR(ec_child));
- RETURN(PTR_ERR(ec_child));
+ return PTR_ERR(ec_child);
}
child = lu_object_locate(ec_child->lo_header, ld->ld_type);
@@ -1623,7 +1593,6 @@ echo_md_create_internal(const struct lu_env *env, struct echo_device *ed,
}
CDEBUG(D_RPCTRACE, "End creating object "DFID" %s %p rc = %d\n",
PFID(lu_object_fid(&parent->mo_lu)), lname->ln_name, parent, rc);
- EXIT;
out_put:
lu_object_put(env, ec_child);
return rc;
@@ -1663,13 +1632,11 @@ static int echo_create_md_object(const struct lu_env *env,
int rc = 0;
int i;
- ENTRY;
-
if (ec_parent == NULL)
return -1;
parent = lu_object_locate(ec_parent->lo_header, ld->ld_type);
if (parent == NULL)
- RETURN(-ENXIO);
+ return -ENXIO;
memset(ma, 0, sizeof(*ma));
memset(spec, 0, sizeof(*spec));
@@ -1699,7 +1666,7 @@ static int echo_create_md_object(const struct lu_env *env,
/* If name is specified, only create one object by name */
rc = echo_md_create_internal(env, ed, lu2md(parent), fid, lname,
spec, ma);
- RETURN(rc);
+ return rc;
}
/* Create multiple object sequenced by id */
@@ -1719,7 +1686,7 @@ static int echo_create_md_object(const struct lu_env *env,
fid->f_oid++;
}
- RETURN(rc);
+ return rc;
}
static struct lu_object *echo_md_lookup(const struct lu_env *env,
@@ -1731,14 +1698,13 @@ static struct lu_object *echo_md_lookup(const struct lu_env *env,
struct lu_fid *fid = &info->eti_fid;
struct lu_object *child;
int rc;
- ENTRY;
CDEBUG(D_INFO, "lookup %s in parent "DFID" %p\n", lname->ln_name,
PFID(fid), parent);
rc = mdo_lookup(env, parent, lname, fid, NULL);
if (rc) {
CERROR("lookup %s: rc = %d\n", lname->ln_name, rc);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
/* In the function below, .hs_keycmp resolves to
@@ -1746,7 +1712,7 @@ static struct lu_object *echo_md_lookup(const struct lu_env *env,
/* coverity[overrun-buffer-val] */
child = lu_object_find_at(env, &ed->ed_cl.cd_lu_dev, fid, NULL);
- RETURN(child);
+ return child;
}
static int echo_setattr_object(const struct lu_env *env,
@@ -1763,13 +1729,11 @@ static int echo_setattr_object(const struct lu_env *env,
int rc = 0;
int i;
- ENTRY;
-
if (ec_parent == NULL)
return -1;
parent = lu_object_locate(ec_parent->lo_header, ld->ld_type);
if (parent == NULL)
- RETURN(-ENXIO);
+ return -ENXIO;
for (i = 0; i < count; i++) {
struct lu_object *ec_child, *child;
@@ -1780,7 +1744,7 @@ static int echo_setattr_object(const struct lu_env *env,
if (IS_ERR(ec_child)) {
CERROR("Can't find child %s: rc = %ld\n",
lname->ln_name, PTR_ERR(ec_child));
- RETURN(PTR_ERR(ec_child));
+ return PTR_ERR(ec_child);
}
child = lu_object_locate(ec_child->lo_header, ld->ld_type);
@@ -1811,7 +1775,7 @@ static int echo_setattr_object(const struct lu_env *env,
id++;
lu_object_put(env, ec_child);
}
- RETURN(rc);
+ return rc;
}
static int echo_getattr_object(const struct lu_env *env,
@@ -1828,13 +1792,11 @@ static int echo_getattr_object(const struct lu_env *env,
int rc = 0;
int i;
- ENTRY;
-
if (ec_parent == NULL)
return -1;
parent = lu_object_locate(ec_parent->lo_header, ld->ld_type);
if (parent == NULL)
- RETURN(-ENXIO);
+ return -ENXIO;
memset(ma, 0, sizeof(*ma));
ma->ma_need |= MA_INODE | MA_LOV | MA_PFID | MA_HSM | MA_ACL_DEF;
@@ -1852,14 +1814,14 @@ static int echo_getattr_object(const struct lu_env *env,
if (IS_ERR(ec_child)) {
CERROR("Can't find child %s: rc = %ld\n",
lname->ln_name, PTR_ERR(ec_child));
- RETURN(PTR_ERR(ec_child));
+ return PTR_ERR(ec_child);
}
child = lu_object_locate(ec_child->lo_header, ld->ld_type);
if (child == NULL) {
CERROR("Can not locate the child %s\n", lname->ln_name);
lu_object_put(env, ec_child);
- RETURN(-EINVAL);
+ return -EINVAL;
}
CDEBUG(D_RPCTRACE, "Start getattr object "DFID"\n",
@@ -1877,7 +1839,7 @@ static int echo_getattr_object(const struct lu_env *env,
lu_object_put(env, ec_child);
}
- RETURN(rc);
+ return rc;
}
static int echo_lookup_object(const struct lu_env *env,
@@ -1931,13 +1893,11 @@ static int echo_md_destroy_internal(const struct lu_env *env,
struct lu_object *child;
int rc;
- ENTRY;
-
ec_child = echo_md_lookup(env, ed, parent, lname);
if (IS_ERR(ec_child)) {
CERROR("Can't find child %s: rc = %ld\n", lname->ln_name,
PTR_ERR(ec_child));
- RETURN(PTR_ERR(ec_child));
+ return PTR_ERR(ec_child);
}
child = lu_object_locate(ec_child->lo_header, ld->ld_type);
@@ -1976,11 +1936,10 @@ static int echo_destroy_object(const struct lu_env *env,
struct lu_object *parent;
int rc = 0;
int i;
- ENTRY;
parent = lu_object_locate(ec_parent->lo_header, ld->ld_type);
if (parent == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
memset(ma, 0, sizeof(*ma));
ma->ma_attr.la_mode = mode;
@@ -1994,7 +1953,7 @@ static int echo_destroy_object(const struct lu_env *env,
lname->ln_namelen = namelen;
rc = echo_md_destroy_internal(env, ed, lu2md(parent), lname,
ma);
- RETURN(rc);
+ return rc;
}
/*prepare the requests*/
@@ -2013,7 +1972,7 @@ static int echo_destroy_object(const struct lu_env *env,
id++;
}
- RETURN(rc);
+ return rc;
}
static struct lu_object *echo_resolve_path(const struct lu_env *env,
@@ -2028,13 +1987,12 @@ static struct lu_object *echo_resolve_path(const struct lu_env *env,
struct lu_object *parent = NULL;
struct lu_object *child = NULL;
int rc = 0;
- ENTRY;
/*Only support MDD layer right now*/
rc = md->md_ops->mdo_root_get(env, md, fid);
if (rc) {
CERROR("get root error: rc = %d\n", rc);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
/* In the function below, .hs_keycmp resolves to
@@ -2044,7 +2002,7 @@ static struct lu_object *echo_resolve_path(const struct lu_env *env,
if (IS_ERR(parent)) {
CERROR("Can not find the parent "DFID": rc = %ld\n",
PFID(fid), PTR_ERR(parent));
- RETURN(parent);
+ return parent;
}
while (1) {
@@ -2083,9 +2041,9 @@ static struct lu_object *echo_resolve_path(const struct lu_env *env,
parent = child;
}
if (rc)
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
- RETURN(parent);
+ return parent;
}
static void echo_ucred_init(struct lu_env *env)
@@ -2097,10 +2055,14 @@ static void echo_ucred_init(struct lu_env *env)
ucred->uc_suppgids[0] = -1;
ucred->uc_suppgids[1] = -1;
- ucred->uc_uid = ucred->uc_o_uid = current_uid();
- ucred->uc_gid = ucred->uc_o_gid = current_gid();
- ucred->uc_fsuid = ucred->uc_o_fsuid = current_fsuid();
- ucred->uc_fsgid = ucred->uc_o_fsgid = current_fsgid();
+ ucred->uc_uid = ucred->uc_o_uid =
+ from_kuid(&init_user_ns, current_uid());
+ ucred->uc_gid = ucred->uc_o_gid =
+ from_kgid(&init_user_ns, current_gid());
+ ucred->uc_fsuid = ucred->uc_o_fsuid =
+ from_kuid(&init_user_ns, current_fsuid());
+ ucred->uc_fsgid = ucred->uc_o_fsgid =
+ from_kgid(&init_user_ns, current_fsgid());
ucred->uc_cap = cfs_curproc_cap_pack();
/* remove fs privilege for non-root user. */
@@ -2129,21 +2091,20 @@ static int echo_md_handler(struct echo_device *ed, int command,
char *name = NULL;
int namelen = data->ioc_plen2;
int rc = 0;
- ENTRY;
if (ld == NULL) {
CERROR("MD echo client is not being initialized properly\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (strcmp(ld->ld_type->ldt_name, LUSTRE_MDD_NAME)) {
CERROR("Only support MDD layer right now!\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
env = cl_env_get(&refcheck);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
rc = lu_env_refill_by_tags(env, ECHO_MD_CTX_TAG, ECHO_MD_SES_TAG);
if (rc != 0)
@@ -2243,13 +2204,12 @@ static int echo_create_object(const struct lu_env *env, struct echo_device *ed,
struct lov_stripe_md *lsm = NULL;
int rc;
int created = 0;
- ENTRY;
if ((oa->o_valid & OBD_MD_FLID) == 0 && /* no obj id */
(on_target || /* set_stripe */
ec->ec_nstripes != 0)) { /* LOV */
CERROR ("No valid oid\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
rc = echo_alloc_memmd(ed, &lsm);
@@ -2315,7 +2275,6 @@ static int echo_create_object(const struct lu_env *env, struct echo_device *ed,
cl_echo_object_put(eco);
CDEBUG(D_INFO, "oa oid "DOSTID"\n", POSTID(&oa->o_oi));
- EXIT;
failed:
if (created && rc)
@@ -2333,17 +2292,16 @@ static int echo_get_object(struct echo_object **ecop, struct echo_device *ed,
struct lov_stripe_md *lsm = NULL;
struct echo_object *eco;
int rc;
- ENTRY;
if ((oa->o_valid & OBD_MD_FLID) == 0 || ostid_id(&oa->o_oi) == 0) {
/* disallow use of object id 0 */
CERROR ("No valid oid\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
rc = echo_alloc_memmd(ed, &lsm);
if (rc < 0)
- RETURN(rc);
+ return rc;
lsm->lsm_oi = oa->o_oi;
if (!(oa->o_valid & OBD_MD_FLGROUP))
@@ -2357,7 +2315,7 @@ static int echo_get_object(struct echo_object **ecop, struct echo_device *ed,
rc = PTR_ERR(eco);
if (lsm)
echo_free_memmd(ed, &lsm);
- RETURN(rc);
+ return rc;
}
static void echo_put_object(struct echo_object *eco)
@@ -2476,7 +2434,6 @@ static int echo_client_kbrw(struct echo_device *ed, int rw, struct obdo *oa,
int verify;
int gfp_mask;
int brw_flags = 0;
- ENTRY;
verify = (ostid_id(&oa->o_oi) != ECHO_PERSISTENT_OBJID &&
(oa->o_valid & OBD_MD_FLFLAGS) != 0 &&
@@ -2490,7 +2447,7 @@ static int echo_client_kbrw(struct echo_device *ed, int rw, struct obdo *oa,
if (count <= 0 ||
(count & (~CFS_PAGE_MASK)) != 0)
- RETURN(-EINVAL);
+ return -EINVAL;
/* XXX think again with misaligned I/O */
npages = count >> PAGE_CACHE_SHIFT;
@@ -2500,12 +2457,12 @@ static int echo_client_kbrw(struct echo_device *ed, int rw, struct obdo *oa,
OBD_ALLOC(pga, npages * sizeof(*pga));
if (pga == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
OBD_ALLOC(pages, npages * sizeof(*pages));
if (pages == NULL) {
OBD_FREE(pga, npages * sizeof(*pga));
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
for (i = 0, pgp = pga, off = offset;
@@ -2554,7 +2511,7 @@ static int echo_client_kbrw(struct echo_device *ed, int rw, struct obdo *oa,
}
OBD_FREE(pga, npages * sizeof(*pga));
OBD_FREE(pages, npages * sizeof(*pages));
- RETURN(rc);
+ return rc;
}
static int echo_client_prep_commit(const struct lu_env *env,
@@ -2572,11 +2529,9 @@ static int echo_client_prep_commit(const struct lu_env *env,
obd_size npages, tot_pages;
int i, ret = 0, brw_flags = 0;
- ENTRY;
-
if (count <= 0 || (count & (~CFS_PAGE_MASK)) != 0 ||
(lsm != NULL && ostid_id(&lsm->lsm_oi) != ostid_id(&oa->o_oi)))
- RETURN(-EINVAL);
+ return -EINVAL;
npages = batch >> PAGE_CACHE_SHIFT;
tot_pages = count >> PAGE_CACHE_SHIFT;
@@ -2661,7 +2616,7 @@ out:
OBD_FREE(lnb, npages * sizeof(struct niobuf_local));
if (rnb)
OBD_FREE(rnb, npages * sizeof(struct niobuf_remote));
- RETURN(ret);
+ return ret;
}
static int echo_client_brw_ioctl(const struct lu_env *env, int rw,
@@ -2677,13 +2632,12 @@ static int echo_client_brw_ioctl(const struct lu_env *env, int rw,
int rc;
int async = 1;
long test_mode;
- ENTRY;
LASSERT(oa->o_valid & OBD_MD_FLGROUP);
rc = echo_get_object(&eco, ed, oa);
if (rc)
- RETURN(rc);
+ return rc;
oa->o_valid &= ~OBD_MD_FLHANDLE;
@@ -2719,7 +2673,7 @@ static int echo_client_brw_ioctl(const struct lu_env *env, int rw,
rc = -EINVAL;
}
echo_put_object(eco);
- RETURN(rc);
+ return rc;
}
static int
@@ -2731,21 +2685,20 @@ echo_client_enqueue(struct obd_export *exp, struct obdo *oa,
struct echo_object *eco;
obd_off end;
int rc;
- ENTRY;
if (ed->ed_next == NULL)
- RETURN(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
if (!(mode == LCK_PR || mode == LCK_PW))
- RETURN(-EINVAL);
+ return -EINVAL;
if ((offset & (~CFS_PAGE_MASK)) != 0 ||
(nob & (~CFS_PAGE_MASK)) != 0)
- RETURN(-EINVAL);
+ return -EINVAL;
rc = echo_get_object (&eco, ed, oa);
if (rc != 0)
- RETURN(rc);
+ return rc;
end = (nob == 0) ? ((obd_off) -1) : (offset + nob - 1);
rc = cl_echo_enqueue(eco, offset, end, mode, &ulh->cookie);
@@ -2754,7 +2707,7 @@ echo_client_enqueue(struct obd_export *exp, struct obdo *oa,
CDEBUG(D_INFO, "Cookie is "LPX64"\n", ulh->cookie);
}
echo_put_object(eco);
- RETURN(rc);
+ return rc;
}
static int
@@ -2787,7 +2740,6 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
int rw = OBD_BRW_READ;
int rc = 0;
int i;
- ENTRY;
memset(&dummy_oti, 0, sizeof(dummy_oti));
@@ -2800,11 +2752,11 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
/* This FID is unpacked just for validation at this point */
rc = ostid_to_fid(&fid, &oa->o_oi, 0);
if (rc < 0)
- RETURN(rc);
+ return rc;
OBD_ALLOC_PTR(env);
if (env == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = lu_env_init(env, LCT_DT_THREAD);
if (rc)
@@ -2980,7 +2932,6 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
GOTO (out, rc = -ENOTTY);
}
- EXIT;
out:
lu_env_fini(env);
OBD_FREE_PTR(env);
@@ -3004,18 +2955,17 @@ static int echo_client_setup(const struct lu_env *env,
struct obd_uuid echo_uuid = { "ECHO_UUID" };
struct obd_connect_data *ocd = NULL;
int rc;
- ENTRY;
if (lcfg->lcfg_bufcount < 2 || LUSTRE_CFG_BUFLEN(lcfg, 1) < 1) {
CERROR("requires a TARGET OBD name\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
tgt = class_name2obd(lustre_cfg_string(lcfg, 1));
if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
CERROR("device not attached or not set up (%s)\n",
lustre_cfg_string(lcfg, 1));
- RETURN(-EINVAL);
+ return -EINVAL;
}
spin_lock_init(&ec->ec_lock);
@@ -3027,7 +2977,7 @@ static int echo_client_setup(const struct lu_env *env,
if (!strcmp(tgt->obd_type->typ_name, LUSTRE_MDT_NAME)) {
lu_context_tags_update(ECHO_MD_CTX_TAG);
lu_session_tags_update(ECHO_MD_SES_TAG);
- RETURN(0);
+ return 0;
}
OBD_ALLOC(ocd, sizeof(*ocd));
@@ -3062,7 +3012,7 @@ static int echo_client_setup(const struct lu_env *env,
return (rc);
}
- RETURN(rc);
+ return rc;
}
static int echo_client_cleanup(struct obd_device *obddev)
@@ -3070,21 +3020,20 @@ static int echo_client_cleanup(struct obd_device *obddev)
struct echo_device *ed = obd2echo_dev(obddev);
struct echo_client_obd *ec = &obddev->u.echo_client;
int rc;
- ENTRY;
/*Do nothing for Metadata echo client*/
if (ed == NULL )
- RETURN(0);
+ return 0;
if (ed->ed_next_ismd) {
lu_context_tags_clear(ECHO_MD_CTX_TAG);
lu_session_tags_clear(ECHO_MD_SES_TAG);
- RETURN(0);
+ return 0;
}
if (!list_empty(&obddev->obd_exports)) {
CERROR("still has clients!\n");
- RETURN(-EBUSY);
+ return -EBUSY;
}
LASSERT(atomic_read(&ec->ec_exp->exp_refcount) > 0);
@@ -3092,7 +3041,7 @@ static int echo_client_cleanup(struct obd_device *obddev)
if (rc != 0)
CERROR("fail to disconnect device: %d\n", rc);
- RETURN(rc);
+ return rc;
}
static int echo_client_connect(const struct lu_env *env,
@@ -3103,13 +3052,12 @@ static int echo_client_connect(const struct lu_env *env,
int rc;
struct lustre_handle conn = { 0 };
- ENTRY;
rc = class_connect(&conn, src, cluuid);
if (rc == 0) {
*exp = class_conn2export(&conn);
}
- RETURN (rc);
+ return rc;
}
static int echo_client_disconnect(struct obd_export *exp)
@@ -3120,7 +3068,6 @@ static int echo_client_disconnect(struct obd_export *exp)
struct ec_lock *ecl;
#endif
int rc;
- ENTRY;
if (exp == NULL)
GOTO(out, rc = -EINVAL);
@@ -3195,7 +3142,6 @@ static int __init obdecho_init(void)
struct lprocfs_static_vars lvars;
int rc;
- ENTRY;
LCONSOLE_INFO("Echo OBD driver; http://www.lustre.org/\n");
LASSERT(PAGE_CACHE_SIZE % OBD_ECHO_BLOCK_SIZE == 0);
@@ -3205,7 +3151,7 @@ static int __init obdecho_init(void)
rc = echo_client_init();
- RETURN(rc);
+ return rc;
}
static void /*__exit*/ obdecho_exit(void)
@@ -3217,7 +3163,9 @@ static void /*__exit*/ obdecho_exit(void)
MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Testing Echo OBD driver");
MODULE_LICENSE("GPL");
+MODULE_VERSION(LUSTRE_VERSION_STRING);
-cfs_module(obdecho, LUSTRE_VERSION_STRING, obdecho_init, obdecho_exit);
+module_init(obdecho_init);
+module_exit(obdecho_exit);
/** @} echo_client */
diff --git a/drivers/staging/lustre/lustre/osc/lproc_osc.c b/drivers/staging/lustre/lustre/osc/lproc_osc.c
index 198cf3ba137..90d24d8dea2 100644
--- a/drivers/staging/lustre/lustre/osc/lproc_osc.c
+++ b/drivers/staging/lustre/lustre/osc/lproc_osc.c
@@ -35,7 +35,6 @@
*/
#define DEBUG_SUBSYSTEM S_CLASS
-#include <linux/version.h>
#include <asm/statfs.h>
#include <obd_cksum.h>
#include <obd_class.h>
@@ -146,7 +145,7 @@ static ssize_t osc_max_dirty_mb_seq_write(struct file *file, const char *buffer,
if (pages_number <= 0 ||
pages_number > OSC_MAX_DIRTY_MB_MAX << (20 - PAGE_CACHE_SHIFT) ||
- pages_number > num_physpages / 4) /* 1/4 of RAM */
+ pages_number > totalram_pages / 4) /* 1/4 of RAM */
return -ERANGE;
client_obd_list_lock(&cli->cl_loi_list_lock);
diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c
index 0a0ec6f7d2d..00295da4ab3 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cache.c
+++ b/drivers/staging/lustre/lustre/osc/osc_cache.c
@@ -540,7 +540,6 @@ int osc_extent_release(const struct lu_env *env, struct osc_extent *ext)
{
struct osc_object *obj = ext->oe_obj;
int rc = 0;
- ENTRY;
LASSERT(atomic_read(&ext->oe_users) > 0);
LASSERT(sanity_check(ext) == 0);
@@ -572,7 +571,7 @@ int osc_extent_release(const struct lu_env *env, struct osc_extent *ext)
osc_io_unplug_async(env, osc_cli(obj), obj);
}
osc_extent_put(env, ext);
- RETURN(rc);
+ return rc;
}
static inline int overlapped(struct osc_extent *ex1, struct osc_extent *ex2)
@@ -602,11 +601,10 @@ struct osc_extent *osc_extent_find(const struct lu_env *env,
int ppc_bits; /* pages per chunk bits */
int chunk_mask;
int rc;
- ENTRY;
cur = osc_extent_alloc(obj);
if (cur == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
lock = cl_lock_at_pgoff(env, osc2cl(obj), index, NULL, 1, 0);
LASSERT(lock != NULL);
@@ -783,7 +781,6 @@ restart:
goto restart;
}
- EXIT;
out:
osc_extent_put(env, cur);
@@ -805,7 +802,6 @@ int osc_extent_finish(const struct lu_env *env, struct osc_extent *ext,
int blocksize = cli->cl_import->imp_obd->obd_osfs.os_bsize ? : 4096;
__u64 last_off = 0;
int last_count = -1;
- ENTRY;
OSC_EXTENT_DUMP(D_CACHE, ext, "extent finished.\n");
@@ -846,7 +842,7 @@ int osc_extent_finish(const struct lu_env *env, struct osc_extent *ext,
osc_extent_remove(ext);
/* put the refcount for RPC */
osc_extent_put(env, ext);
- RETURN(0);
+ return 0;
}
static int extent_wait_cb(struct osc_extent *ext, int state)
@@ -870,7 +866,6 @@ static int osc_extent_wait(const struct lu_env *env, struct osc_extent *ext,
struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(600), NULL,
LWI_ON_SIGNAL_NOOP, NULL);
int rc = 0;
- ENTRY;
osc_object_lock(obj);
LASSERT(sanity_check_nolock(ext) == 0);
@@ -902,7 +897,7 @@ static int osc_extent_wait(const struct lu_env *env, struct osc_extent *ext,
}
if (rc == 0 && ext->oe_rc < 0)
rc = ext->oe_rc;
- RETURN(rc);
+ return rc;
}
/**
@@ -925,7 +920,6 @@ static int osc_extent_truncate(struct osc_extent *ext, pgoff_t trunc_index,
int grants = 0;
int nr_pages = 0;
int rc = 0;
- ENTRY;
LASSERT(sanity_check(ext) == 0);
LASSERT(ext->oe_state == OES_TRUNC);
@@ -1021,7 +1015,7 @@ static int osc_extent_truncate(struct osc_extent *ext, pgoff_t trunc_index,
out:
cl_io_fini(env, io);
cl_env_nested_put(&nest, env);
- RETURN(rc);
+ return rc;
}
/**
@@ -1036,7 +1030,6 @@ static int osc_extent_make_ready(const struct lu_env *env,
struct osc_object *obj = ext->oe_obj;
int page_count = 0;
int rc;
- ENTRY;
/* we're going to grab page lock, so object lock must not be taken. */
LASSERT(sanity_check(ext) == 0);
@@ -1096,7 +1089,7 @@ static int osc_extent_make_ready(const struct lu_env *env,
/* get a refcount for RPC. */
osc_extent_get(ext);
- RETURN(0);
+ return 0;
}
/**
@@ -1115,7 +1108,6 @@ static int osc_extent_expand(struct osc_extent *ext, pgoff_t index, int *grants)
pgoff_t end_index;
int chunksize = 1 << cli->cl_chunkbits;
int rc = 0;
- ENTRY;
LASSERT(ext->oe_max_end >= index && ext->oe_start <= index);
osc_object_lock(obj);
@@ -1143,11 +1135,10 @@ static int osc_extent_expand(struct osc_extent *ext, pgoff_t index, int *grants)
LASSERT(*grants >= 0);
EASSERTF(osc_extent_is_overlapped(obj, ext) == 0, ext,
"overlapped after expanding for %lu.\n", index);
- EXIT;
out:
osc_object_unlock(obj);
- RETURN(rc);
+ return rc;
}
static void osc_extent_tree_dump0(int level, struct osc_object *obj,
@@ -1207,11 +1198,10 @@ static int osc_make_ready(const struct lu_env *env, struct osc_async_page *oap,
LASSERT(cmd == OBD_BRW_WRITE); /* no cached reads */
- ENTRY;
result = cl_page_make_ready(env, page, CRT_WRITE);
if (result == 0)
opg->ops_submit_time = cfs_time_current();
- RETURN(result);
+ return result;
}
static int osc_refresh_count(const struct lu_env *env,
@@ -1255,8 +1245,6 @@ static int osc_completion(const struct lu_env *env, struct osc_async_page *oap,
enum cl_req_type crt;
int srvlock;
- ENTRY;
-
cmd &= ~OBD_BRW_NOQUOTA;
LASSERT(equi(page->cp_state == CPS_PAGEIN, cmd == OBD_BRW_READ));
LASSERT(equi(page->cp_state == CPS_PAGEOUT, cmd == OBD_BRW_WRITE));
@@ -1305,7 +1293,7 @@ static int osc_completion(const struct lu_env *env, struct osc_async_page *oap,
cl_page_completion(env, page, crt, rc);
- RETURN(0);
+ return 0;
}
#define OSC_DUMP_GRANT(cli, fmt, args...) do { \
@@ -1338,11 +1326,8 @@ static void osc_consume_write_grant(struct client_obd *cli,
static void osc_release_write_grant(struct client_obd *cli,
struct brw_page *pga)
{
- ENTRY;
-
LASSERT(spin_is_locked(&cli->cl_loi_list_lock.lock));
if (!(pga->flag & OBD_BRW_FROM_GRANT)) {
- EXIT;
return;
}
@@ -1354,7 +1339,6 @@ static void osc_release_write_grant(struct client_obd *cli,
atomic_dec(&obd_dirty_transit_pages);
cli->cl_dirty_transit -= PAGE_CACHE_SIZE;
}
- EXIT;
}
/**
@@ -1503,7 +1487,6 @@ static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli,
struct osc_cache_waiter ocw;
struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
int rc = -EDQUOT;
- ENTRY;
OSC_DUMP_GRANT(cli, "need:%d.\n", bytes);
@@ -1557,11 +1540,10 @@ static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli,
if (osc_enter_cache_try(cli, oap, bytes, 0))
GOTO(out, rc = 0);
}
- EXIT;
out:
client_obd_list_unlock(&cli->cl_loi_list_lock);
OSC_DUMP_GRANT(cli, "returned %d.\n", rc);
- RETURN(rc);
+ return rc;
}
/* caller must hold loi_list_lock */
@@ -1570,7 +1552,6 @@ void osc_wake_cache_waiters(struct client_obd *cli)
struct list_head *l, *tmp;
struct osc_cache_waiter *ocw;
- ENTRY;
list_for_each_safe(l, tmp, &cli->cl_cache_waiters) {
ocw = list_entry(l, struct osc_cache_waiter, ocw_entry);
list_del_init(&ocw->ocw_entry);
@@ -1596,8 +1577,6 @@ wakeup:
wake_up(&ocw->ocw_waitq);
}
-
- EXIT;
}
static int osc_max_rpc_in_flight(struct client_obd *cli, struct osc_object *osc)
@@ -1613,7 +1592,6 @@ static int osc_makes_rpc(struct client_obd *cli, struct osc_object *osc,
int cmd)
{
int invalid_import = 0;
- ENTRY;
/* if we have an invalid import we want to drain the queued pages
* by forcing them through rpcs that immediately fail and complete
@@ -1624,42 +1602,42 @@ static int osc_makes_rpc(struct client_obd *cli, struct osc_object *osc,
if (cmd & OBD_BRW_WRITE) {
if (atomic_read(&osc->oo_nr_writes) == 0)
- RETURN(0);
+ return 0;
if (invalid_import) {
CDEBUG(D_CACHE, "invalid import forcing RPC\n");
- RETURN(1);
+ return 1;
}
if (!list_empty(&osc->oo_hp_exts)) {
CDEBUG(D_CACHE, "high prio request forcing RPC\n");
- RETURN(1);
+ return 1;
}
if (!list_empty(&osc->oo_urgent_exts)) {
CDEBUG(D_CACHE, "urgent request forcing RPC\n");
- RETURN(1);
+ return 1;
}
/* trigger a write rpc stream as long as there are dirtiers
* waiting for space. as they're waiting, they're not going to
* create more pages to coalesce with what's waiting.. */
if (!list_empty(&cli->cl_cache_waiters)) {
CDEBUG(D_CACHE, "cache waiters forcing RPC\n");
- RETURN(1);
+ return 1;
}
if (atomic_read(&osc->oo_nr_writes) >=
cli->cl_max_pages_per_rpc)
- RETURN(1);
+ return 1;
} else {
if (atomic_read(&osc->oo_nr_reads) == 0)
- RETURN(0);
+ return 0;
if (invalid_import) {
CDEBUG(D_CACHE, "invalid import forcing RPC\n");
- RETURN(1);
+ return 1;
}
/* all read are urgent. */
if (!list_empty(&osc->oo_reading_exts))
- RETURN(1);
+ return 1;
}
- RETURN(0);
+ return 0;
}
static void osc_update_pending(struct osc_object *obj, int cmd, int delta)
@@ -1757,7 +1735,6 @@ static void osc_ap_completion(const struct lu_env *env, struct client_obd *cli,
struct lov_oinfo *loi = osc->oo_oinfo;
__u64 xid = 0;
- ENTRY;
if (oap->oap_request != NULL) {
xid = ptlrpc_req_xid(oap->oap_request);
ptlrpc_req_finished(oap->oap_request);
@@ -1781,8 +1758,6 @@ static void osc_ap_completion(const struct lu_env *env, struct client_obd *cli,
if (rc)
CERROR("completion on oap %p obj %p returns %d.\n",
oap, osc, rc);
-
- EXIT;
}
/**
@@ -1795,14 +1770,13 @@ static int try_to_add_extent_for_io(struct client_obd *cli,
int *pc, unsigned int *max_pages)
{
struct osc_extent *tmp;
- ENTRY;
EASSERT((ext->oe_state == OES_CACHE || ext->oe_state == OES_LOCK_DONE),
ext);
*max_pages = max(ext->oe_mppr, *max_pages);
if (*pc + ext->oe_nr_pages > *max_pages)
- RETURN(0);
+ return 0;
list_for_each_entry(tmp, rpclist, oe_link) {
EASSERT(tmp->oe_owner == current, tmp);
@@ -1815,7 +1789,7 @@ static int try_to_add_extent_for_io(struct client_obd *cli,
if (tmp->oe_srvlock != ext->oe_srvlock ||
!tmp->oe_grants != !ext->oe_grants)
- RETURN(0);
+ return 0;
/* remove break for strict check */
break;
@@ -1824,7 +1798,7 @@ static int try_to_add_extent_for_io(struct client_obd *cli,
*pc += ext->oe_nr_pages;
list_move_tail(&ext->oe_link, rpclist);
ext->oe_owner = current;
- RETURN(1);
+ return 1;
}
/**
@@ -1913,7 +1887,6 @@ osc_send_write_rpc(const struct lu_env *env, struct client_obd *cli,
obd_count page_count = 0;
int srvlock = 0;
int rc = 0;
- ENTRY;
LASSERT(osc_object_is_locked(osc));
@@ -1921,7 +1894,7 @@ osc_send_write_rpc(const struct lu_env *env, struct client_obd *cli,
LASSERT(equi(page_count == 0, list_empty(&rpclist)));
if (list_empty(&rpclist))
- RETURN(0);
+ return 0;
osc_update_pending(osc, OBD_BRW_WRITE, -page_count);
@@ -1962,7 +1935,7 @@ osc_send_write_rpc(const struct lu_env *env, struct client_obd *cli,
}
osc_object_lock(osc);
- RETURN(rc);
+ return rc;
}
/**
@@ -1985,7 +1958,6 @@ osc_send_read_rpc(const struct lu_env *env, struct client_obd *cli,
int page_count = 0;
unsigned int max_pages = cli->cl_max_pages_per_rpc;
int rc = 0;
- ENTRY;
LASSERT(osc_object_is_locked(osc));
list_for_each_entry_safe(ext, next,
@@ -2010,7 +1982,7 @@ osc_send_read_rpc(const struct lu_env *env, struct client_obd *cli,
osc_object_lock(osc);
}
- RETURN(rc);
+ return rc;
}
#define list_to_obj(list, item) ({ \
@@ -2023,15 +1995,13 @@ osc_send_read_rpc(const struct lu_env *env, struct client_obd *cli,
* we could be sending. These lists are maintained by osc_makes_rpc(). */
static struct osc_object *osc_next_obj(struct client_obd *cli)
{
- ENTRY;
-
/* First return objects that have blocked locks so that they
* will be flushed quickly and other clients can get the lock,
* then objects which have pages ready to be stuffed into RPCs */
if (!list_empty(&cli->cl_loi_hp_ready_list))
- RETURN(list_to_obj(&cli->cl_loi_hp_ready_list, hp_ready_item));
+ return list_to_obj(&cli->cl_loi_hp_ready_list, hp_ready_item);
if (!list_empty(&cli->cl_loi_ready_list))
- RETURN(list_to_obj(&cli->cl_loi_ready_list, ready_item));
+ return list_to_obj(&cli->cl_loi_ready_list, ready_item);
/* then if we have cache waiters, return all objects with queued
* writes. This is especially important when many small files
@@ -2039,19 +2009,17 @@ static struct osc_object *osc_next_obj(struct client_obd *cli)
* they don't pass the nr_pending/object threshhold */
if (!list_empty(&cli->cl_cache_waiters) &&
!list_empty(&cli->cl_loi_write_list))
- RETURN(list_to_obj(&cli->cl_loi_write_list, write_item));
+ return list_to_obj(&cli->cl_loi_write_list, write_item);
/* then return all queued objects when we have an invalid import
* so that they get flushed */
if (cli->cl_import == NULL || cli->cl_import->imp_invalid) {
if (!list_empty(&cli->cl_loi_write_list))
- RETURN(list_to_obj(&cli->cl_loi_write_list,
- write_item));
+ return list_to_obj(&cli->cl_loi_write_list, write_item);
if (!list_empty(&cli->cl_loi_read_list))
- RETURN(list_to_obj(&cli->cl_loi_read_list,
- read_item));
+ return list_to_obj(&cli->cl_loi_read_list, read_item);
}
- RETURN(NULL);
+ return NULL;
}
/* called with the loi list lock held */
@@ -2060,11 +2028,10 @@ static void osc_check_rpcs(const struct lu_env *env, struct client_obd *cli,
{
struct osc_object *osc;
int rc = 0;
- ENTRY;
while ((osc = osc_next_obj(cli)) != NULL) {
struct cl_object *obj = osc2cl(osc);
- struct lu_ref_link *link;
+ struct lu_ref_link link;
OSC_IO_DEBUG(osc, "%lu in flight\n", rpcs_in_flight(cli));
@@ -2075,7 +2042,8 @@ static void osc_check_rpcs(const struct lu_env *env, struct client_obd *cli,
cl_object_get(obj);
client_obd_list_unlock(&cli->cl_loi_list_lock);
- link = lu_object_ref_add(&obj->co_lu, "check", current);
+ lu_object_ref_add_at(&obj->co_lu, &link, "check",
+ current);
/* attempt some read/write balancing by alternating between
* reads and writes in an object. The makes_rpc checks here
@@ -2116,7 +2084,8 @@ static void osc_check_rpcs(const struct lu_env *env, struct client_obd *cli,
osc_object_unlock(osc);
osc_list_maint(cli, osc);
- lu_object_ref_del_at(&obj->co_lu, link, "check", current);
+ lu_object_ref_del_at(&obj->co_lu, &link, "check",
+ current);
cl_object_put(env, obj);
client_obd_list_lock(&cli->cl_loi_list_lock);
@@ -2165,7 +2134,6 @@ int osc_prep_async_page(struct osc_object *osc, struct osc_page *ops,
{
struct obd_export *exp = osc_export(osc);
struct osc_async_page *oap = &ops->ops_oap;
- ENTRY;
if (!page)
return cfs_size_round(sizeof(*oap));
@@ -2187,7 +2155,7 @@ int osc_prep_async_page(struct osc_object *osc, struct osc_page *ops,
spin_lock_init(&oap->oap_lock);
CDEBUG(D_INFO, "oap %p page %p obj off "LPU64"\n",
oap, page, oap->oap_obj_off);
- RETURN(0);
+ return 0;
}
int osc_queue_async_io(const struct lu_env *env, struct cl_io *io,
@@ -2204,17 +2172,16 @@ int osc_queue_async_io(const struct lu_env *env, struct cl_io *io,
int cmd = OBD_BRW_WRITE;
int need_release = 0;
int rc = 0;
- ENTRY;
if (oap->oap_magic != OAP_MAGIC)
- RETURN(-EINVAL);
+ return -EINVAL;
if (cli->cl_import == NULL || cli->cl_import->imp_invalid)
- RETURN(-EIO);
+ return -EIO;
if (!list_empty(&oap->oap_pending_item) ||
!list_empty(&oap->oap_rpc_item))
- RETURN(-EBUSY);
+ return -EBUSY;
/* Set the OBD_BRW_SRVLOCK before the page is queued. */
brw_flags |= ops->ops_srvlock ? OBD_BRW_SRVLOCK : 0;
@@ -2242,7 +2209,7 @@ int osc_queue_async_io(const struct lu_env *env, struct cl_io *io,
if (rc == 0 && osc_quota_chkdq(cli, qid) == NO_QUOTA)
rc = -EDQUOT;
if (rc)
- RETURN(rc);
+ return rc;
}
oap->oap_cmd = cmd;
@@ -2350,7 +2317,7 @@ int osc_queue_async_io(const struct lu_env *env, struct cl_io *io,
list_add_tail(&oap->oap_pending_item, &ext->oe_pages);
osc_object_unlock(osc);
}
- RETURN(rc);
+ return rc;
}
int osc_teardown_async_page(const struct lu_env *env,
@@ -2359,7 +2326,6 @@ int osc_teardown_async_page(const struct lu_env *env,
struct osc_async_page *oap = &ops->ops_oap;
struct osc_extent *ext = NULL;
int rc = 0;
- ENTRY;
LASSERT(oap->oap_magic == OAP_MAGIC);
@@ -2384,7 +2350,7 @@ int osc_teardown_async_page(const struct lu_env *env,
osc_object_unlock(obj);
if (ext != NULL)
osc_extent_put(env, ext);
- RETURN(rc);
+ return rc;
}
/**
@@ -2404,7 +2370,6 @@ int osc_flush_async_page(const struct lu_env *env, struct cl_io *io,
struct osc_async_page *oap = &ops->ops_oap;
bool unplug = false;
int rc = 0;
- ENTRY;
osc_object_lock(obj);
ext = osc_extent_lookup(obj, index);
@@ -2454,7 +2419,6 @@ int osc_flush_async_page(const struct lu_env *env, struct cl_io *io,
unplug = true;
}
rc = 0;
- EXIT;
out:
osc_object_unlock(obj);
@@ -2482,7 +2446,6 @@ int osc_cancel_async_page(const struct lu_env *env, struct osc_page *ops)
pgoff_t index = oap2cl_page(oap)->cp_index;
int rc = -EBUSY;
int cmd;
- ENTRY;
LASSERT(!oap->oap_interrupted);
oap->oap_interrupted = 1;
@@ -2526,7 +2489,7 @@ int osc_cancel_async_page(const struct lu_env *env, struct osc_page *ops)
}
osc_list_maint(cli, obj);
- RETURN(rc);
+ return rc;
}
int osc_queue_sync_pages(const struct lu_env *env, struct osc_object *obj,
@@ -2539,7 +2502,6 @@ int osc_queue_sync_pages(const struct lu_env *env, struct osc_object *obj,
int mppr = cli->cl_max_pages_per_rpc;
pgoff_t start = CL_PAGE_EOF;
pgoff_t end = 0;
- ENTRY;
list_for_each_entry(oap, list, oap_pending_item) {
struct cl_page *cp = oap2cl_page(oap);
@@ -2557,7 +2519,7 @@ int osc_queue_sync_pages(const struct lu_env *env, struct osc_object *obj,
list_del_init(&oap->oap_pending_item);
osc_ap_completion(env, cli, oap, 0, -ENOMEM);
}
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
ext->oe_rw = !!(cmd & OBD_BRW_READ);
@@ -2583,7 +2545,7 @@ int osc_queue_sync_pages(const struct lu_env *env, struct osc_object *obj,
osc_object_unlock(obj);
osc_io_unplug(env, cli, obj, PDL_POLICY_ROUND);
- RETURN(0);
+ return 0;
}
/**
@@ -2599,7 +2561,6 @@ int osc_cache_truncate_start(const struct lu_env *env, struct osc_io *oio,
LIST_HEAD(list);
int result = 0;
bool partial;
- ENTRY;
/* pages with index greater or equal to index will be truncated. */
index = cl_index(osc2cl(obj), size);
@@ -2705,7 +2666,7 @@ again:
waiting = NULL;
goto again;
}
- RETURN(result);
+ return result;
}
/**
@@ -2756,7 +2717,6 @@ int osc_cache_wait_range(const struct lu_env *env, struct osc_object *obj,
struct osc_extent *ext;
pgoff_t index = start;
int result = 0;
- ENTRY;
again:
osc_object_lock(obj);
@@ -2794,7 +2754,7 @@ again:
osc_object_unlock(obj);
OSC_IO_DEBUG(obj, "sync file range.\n");
- RETURN(result);
+ return result;
}
/**
@@ -2813,7 +2773,6 @@ int osc_cache_writeback_range(const struct lu_env *env, struct osc_object *obj,
LIST_HEAD(discard_list);
bool unplug = false;
int result = 0;
- ENTRY;
osc_object_lock(obj);
ext = osc_extent_search(obj, start);
@@ -2910,7 +2869,7 @@ int osc_cache_writeback_range(const struct lu_env *env, struct osc_object *obj,
}
OSC_IO_DEBUG(obj, "cache page out.\n");
- RETURN(result);
+ return result;
}
/** @} osc */
diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h
index 158e8fff838..a3aa9b6596e 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h
+++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h
@@ -374,7 +374,7 @@ struct osc_page {
/**
* Thread that submitted this page for transfer. For debugging.
*/
- task_t *ops_submitter;
+ struct task_struct *ops_submitter;
/**
* Submit time - the time when the page is starting RPC. For debugging.
*/
@@ -660,7 +660,7 @@ struct osc_extent {
/** lock covering this extent */
struct cl_lock *oe_osclock;
/** terminator of this extent. Must be true if this extent is in IO. */
- task_t *oe_owner;
+ struct task_struct *oe_owner;
/** return value of writeback. If somebody is waiting for this extent,
* this value can be known by outside world. */
int oe_rc;
diff --git a/drivers/staging/lustre/lustre/osc/osc_dev.c b/drivers/staging/lustre/lustre/osc/osc_dev.c
index 4208ddfd73b..35f25786763 100644
--- a/drivers/staging/lustre/lustre/osc/osc_dev.c
+++ b/drivers/staging/lustre/lustre/osc/osc_dev.c
@@ -171,8 +171,7 @@ LU_TYPE_INIT_FINI(osc, &osc_key, &osc_session_key);
static int osc_cl_process_config(const struct lu_env *env,
struct lu_device *d, struct lustre_cfg *cfg)
{
- ENTRY;
- RETURN(osc_process_config_base(d->ld_obd, cfg));
+ return osc_process_config_base(d->ld_obd, cfg);
}
static const struct lu_device_operations osc_lu_ops = {
@@ -188,7 +187,7 @@ static const struct cl_device_operations osc_cl_ops = {
static int osc_device_init(const struct lu_env *env, struct lu_device *d,
const char *name, struct lu_device *next)
{
- RETURN(0);
+ return 0;
}
static struct lu_device *osc_device_fini(const struct lu_env *env,
@@ -218,7 +217,7 @@ static struct lu_device *osc_device_alloc(const struct lu_env *env,
OBD_ALLOC_PTR(od);
if (od == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
cl_device_init(&od->od_cl, t);
d = osc2lu_dev(od);
@@ -231,10 +230,10 @@ static struct lu_device *osc_device_alloc(const struct lu_env *env,
rc = osc_setup(obd, cfg);
if (rc) {
osc_device_free(env, d);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
od->od_exp = obd->obd_self_export;
- RETURN(d);
+ return d;
}
static const struct lu_device_type_operations osc_device_type_ops = {
diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c
index 1b277045b3e..3aeaf845cf2 100644
--- a/drivers/staging/lustre/lustre/osc/osc_io.c
+++ b/drivers/staging/lustre/lustre/osc/osc_io.c
@@ -261,7 +261,6 @@ static int osc_io_prepare_write(const struct lu_env *env,
struct obd_import *imp = class_exp2cliimp(dev->od_exp);
struct osc_io *oio = cl2osc_io(env, ios);
int result = 0;
- ENTRY;
/*
* This implements OBD_BRW_CHECK logic from old client.
@@ -276,7 +275,7 @@ static int osc_io_prepare_write(const struct lu_env *env,
* [from, to) bytes of this page to OST. -jay */
cl_page_export(env, slice->cpl_page, 1);
- RETURN(result);
+ return result;
}
static int osc_io_commit_write(const struct lu_env *env,
@@ -288,7 +287,6 @@ static int osc_io_commit_write(const struct lu_env *env,
struct osc_page *opg = cl2osc_page(slice);
struct osc_object *obj = cl2osc(opg->ops_cl.cpl_obj);
struct osc_async_page *oap = &opg->ops_oap;
- ENTRY;
LASSERT(to > 0);
/*
@@ -306,7 +304,7 @@ static int osc_io_commit_write(const struct lu_env *env,
/* see osc_io_prepare_write() for lockless io handling. */
cl_page_clip(env, slice->cpl_page, from, to);
- RETURN(0);
+ return 0;
}
static int osc_io_fault_start(const struct lu_env *env,
@@ -315,8 +313,6 @@ static int osc_io_fault_start(const struct lu_env *env,
struct cl_io *io;
struct cl_fault_io *fio;
- ENTRY;
-
io = ios->cis_io;
fio = &io->u.ci_fault;
CDEBUG(D_INFO, "%lu %d %d\n",
@@ -329,7 +325,7 @@ static int osc_io_fault_start(const struct lu_env *env,
if (fio->ft_writable)
osc_page_touch_at(env, ios->cis_obj,
fio->ft_index, fio->ft_nob);
- RETURN(0);
+ return 0;
}
static int osc_async_upcall(void *a, int rc)
@@ -517,19 +513,18 @@ static int osc_io_read_start(const struct lu_env *env,
struct cl_object *obj = slice->cis_obj;
struct cl_attr *attr = &osc_env_info(env)->oti_attr;
int result = 0;
- ENTRY;
if (oio->oi_lockless == 0) {
cl_object_attr_lock(obj);
result = cl_object_attr_get(env, obj, attr);
if (result == 0) {
- attr->cat_atime = LTIME_S(CFS_CURRENT_TIME);
+ attr->cat_atime = LTIME_S(CURRENT_TIME);
result = cl_object_attr_set(env, obj, attr,
CAT_ATIME);
}
cl_object_attr_unlock(obj);
}
- RETURN(result);
+ return result;
}
static int osc_io_write_start(const struct lu_env *env,
@@ -539,7 +534,6 @@ static int osc_io_write_start(const struct lu_env *env,
struct cl_object *obj = slice->cis_obj;
struct cl_attr *attr = &osc_env_info(env)->oti_attr;
int result = 0;
- ENTRY;
if (oio->oi_lockless == 0) {
OBD_FAIL_TIMEOUT(OBD_FAIL_OSC_DELAY_SETTIME, 1);
@@ -547,13 +541,13 @@ static int osc_io_write_start(const struct lu_env *env,
result = cl_object_attr_get(env, obj, attr);
if (result == 0) {
attr->cat_mtime = attr->cat_ctime =
- LTIME_S(CFS_CURRENT_TIME);
+ LTIME_S(CURRENT_TIME);
result = cl_object_attr_set(env, obj, attr,
CAT_MTIME | CAT_CTIME);
}
cl_object_attr_unlock(obj);
}
- RETURN(result);
+ return result;
}
static int osc_fsync_ost(const struct lu_env *env, struct osc_object *obj,
@@ -565,7 +559,6 @@ static int osc_fsync_ost(const struct lu_env *env, struct osc_object *obj,
struct lov_oinfo *loi = obj->oo_oinfo;
struct osc_async_cbargs *cbargs = &oio->oi_cbarg;
int rc = 0;
- ENTRY;
memset(oa, 0, sizeof(*oa));
oa->o_oi = loi->loi_oi;
@@ -585,7 +578,7 @@ static int osc_fsync_ost(const struct lu_env *env, struct osc_object *obj,
rc = osc_sync_base(osc_export(obj), oinfo, osc_async_upcall, cbargs,
PTLRPCD_SET);
- RETURN(rc);
+ return rc;
}
static int osc_io_fsync_start(const struct lu_env *env,
@@ -598,7 +591,6 @@ static int osc_io_fsync_start(const struct lu_env *env,
pgoff_t start = cl_index(obj, fio->fi_start);
pgoff_t end = cl_index(obj, fio->fi_end);
int result = 0;
- ENTRY;
if (fio->fi_end == OBD_OBJECT_EOF)
end = CL_PAGE_EOF;
@@ -625,7 +617,7 @@ static int osc_io_fsync_start(const struct lu_env *env,
result = rc;
}
- RETURN(result);
+ return result;
}
static void osc_io_fsync_end(const struct lu_env *env,
@@ -785,7 +777,7 @@ static void osc_req_attr_set(const struct lu_env *env,
"no cover page!\n");
CL_PAGE_DEBUG(D_ERROR, env, apage,
"dump uncover page!\n");
- libcfs_debug_dumpstack(NULL);
+ dump_stack();
LBUG();
}
diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c
index 640bc3d3470..5d7bdbfc871 100644
--- a/drivers/staging/lustre/lustre/osc/osc_lock.c
+++ b/drivers/staging/lustre/lustre/osc/osc_lock.c
@@ -89,35 +89,49 @@ static struct ldlm_lock *osc_handle_ptr(struct lustre_handle *handle)
*/
static int osc_lock_invariant(struct osc_lock *ols)
{
- struct ldlm_lock *lock = osc_handle_ptr(&ols->ols_handle);
- struct ldlm_lock *olock = ols->ols_lock;
- int handle_used = lustre_handle_is_used(&ols->ols_handle);
-
- return
- ergo(osc_lock_is_lockless(ols),
- ols->ols_locklessable && ols->ols_lock == NULL) ||
- (ergo(olock != NULL, handle_used) &&
- ergo(olock != NULL,
- olock->l_handle.h_cookie == ols->ols_handle.cookie) &&
- /*
- * Check that ->ols_handle and ->ols_lock are consistent, but
- * take into account that they are set at the different time.
- */
- ergo(handle_used,
- ergo(lock != NULL && olock != NULL, lock == olock) &&
- ergo(lock == NULL, olock == NULL)) &&
- ergo(ols->ols_state == OLS_CANCELLED,
- olock == NULL && !handle_used) &&
- /*
- * DLM lock is destroyed only after we have seen cancellation
- * ast.
- */
- ergo(olock != NULL && ols->ols_state < OLS_CANCELLED,
- !olock->l_destroyed) &&
- ergo(ols->ols_state == OLS_GRANTED,
- olock != NULL &&
- olock->l_req_mode == olock->l_granted_mode &&
- ols->ols_hold));
+ struct ldlm_lock *lock = osc_handle_ptr(&ols->ols_handle);
+ struct ldlm_lock *olock = ols->ols_lock;
+ int handle_used = lustre_handle_is_used(&ols->ols_handle);
+
+ if (ergo(osc_lock_is_lockless(ols),
+ ols->ols_locklessable && ols->ols_lock == NULL))
+ return 1;
+
+ /*
+ * If all the following "ergo"s are true, return 1, otherwise 0
+ */
+ if (! ergo(olock != NULL, handle_used))
+ return 0;
+
+ if (! ergo(olock != NULL,
+ olock->l_handle.h_cookie == ols->ols_handle.cookie))
+ return 0;
+
+ if (! ergo(handle_used,
+ ergo(lock != NULL && olock != NULL, lock == olock) &&
+ ergo(lock == NULL, olock == NULL)))
+ return 0;
+ /*
+ * Check that ->ols_handle and ->ols_lock are consistent, but
+ * take into account that they are set at the different time.
+ */
+ if (! ergo(ols->ols_state == OLS_CANCELLED,
+ olock == NULL && !handle_used))
+ return 0;
+ /*
+ * DLM lock is destroyed only after we have seen cancellation
+ * ast.
+ */
+ if (! ergo(olock != NULL && ols->ols_state < OLS_CANCELLED,
+ ((olock->l_flags & LDLM_FL_DESTROYED) == 0)))
+ return 0;
+
+ if (! ergo(ols->ols_state == OLS_GRANTED,
+ olock != NULL &&
+ olock->l_req_mode == olock->l_granted_mode &&
+ ols->ols_hold))
+ return 0;
+ return 1;
}
/*****************************************************************************
@@ -261,7 +275,7 @@ static __u64 osc_enq2ldlm_flags(__u32 enqflags)
if (enqflags & CEF_ASYNC)
result |= LDLM_FL_HAS_INTENT;
if (enqflags & CEF_DISCARD_DATA)
- result |= LDLM_AST_DISCARD_DATA;
+ result |= LDLM_FL_AST_DISCARD_DATA;
return result;
}
@@ -329,10 +343,8 @@ static void osc_lock_lvb_update(const struct lu_env *env, struct osc_lock *olck,
struct cl_attr *attr;
unsigned valid;
- ENTRY;
-
if (!(olck->ols_flags & LDLM_FL_LVB_READY))
- RETURN_EXIT;
+ return;
lvb = &olck->ols_lvb;
obj = olck->ols_cl.cls_obj;
@@ -378,8 +390,6 @@ static void osc_lock_lvb_update(const struct lu_env *env, struct osc_lock *olck,
cl_object_attr_set(env, obj, attr, valid);
cl_object_attr_unlock(obj);
-
- EXIT;
}
/**
@@ -398,7 +408,6 @@ static void osc_lock_granted(const struct lu_env *env, struct osc_lock *olck,
LASSERT(dlmlock->l_granted_mode == dlmlock->l_req_mode);
- ENTRY;
if (olck->ols_state < OLS_GRANTED) {
lock = olck->ols_cl.cls_lock;
ext = &dlmlock->l_policy_data.l_extent;
@@ -428,7 +437,6 @@ static void osc_lock_granted(const struct lu_env *env, struct osc_lock *olck,
LINVRNT(osc_lock_invariant(olck));
lock_res_and_lock(dlmlock);
}
- EXIT;
}
static void osc_lock_upcall0(const struct lu_env *env, struct osc_lock *olck)
@@ -436,8 +444,6 @@ static void osc_lock_upcall0(const struct lu_env *env, struct osc_lock *olck)
{
struct ldlm_lock *dlmlock;
- ENTRY;
-
dlmlock = ldlm_handle2lock_long(&olck->ols_handle, 0);
LASSERT(dlmlock != NULL);
@@ -483,7 +489,6 @@ static int osc_lock_upcall(void *cookie, int errcode)
struct lu_env *env;
struct cl_env_nest nest;
- ENTRY;
env = cl_env_nested_get(&nest);
if (!IS_ERR(env)) {
int rc;
@@ -575,7 +580,7 @@ static int osc_lock_upcall(void *cookie, int errcode)
/* should never happen, similar to osc_ldlm_blocking_ast(). */
LBUG();
}
- RETURN(errcode);
+ return errcode;
}
/**
@@ -896,55 +901,6 @@ static unsigned long osc_lock_weigh(const struct lu_env *env,
return cl_object_header(slice->cls_obj)->coh_pages;
}
-/**
- * Get the weight of dlm lock for early cancellation.
- *
- * XXX: it should return the pages covered by this \a dlmlock.
- */
-static unsigned long osc_ldlm_weigh_ast(struct ldlm_lock *dlmlock)
-{
- struct cl_env_nest nest;
- struct lu_env *env;
- struct osc_lock *lock;
- struct cl_lock *cll;
- unsigned long weight;
- ENTRY;
-
- might_sleep();
- /*
- * osc_ldlm_weigh_ast has a complex context since it might be called
- * because of lock canceling, or from user's input. We have to make
- * a new environment for it. Probably it is implementation safe to use
- * the upper context because cl_lock_put don't modify environment
- * variables. But in case of ..
- */
- env = cl_env_nested_get(&nest);
- if (IS_ERR(env))
- /* Mostly because lack of memory, tend to eliminate this lock*/
- RETURN(0);
-
- LASSERT(dlmlock->l_resource->lr_type == LDLM_EXTENT);
- lock = osc_ast_data_get(dlmlock);
- if (lock == NULL) {
- /* cl_lock was destroyed because of memory pressure.
- * It is much reasonable to assign this type of lock
- * a lower cost.
- */
- GOTO(out, weight = 0);
- }
-
- cll = lock->ols_cl.cls_lock;
- cl_lock_mutex_get(env, cll);
- weight = cl_lock_weigh(env, cll);
- cl_lock_mutex_put(env, cll);
- osc_ast_data_put(env, lock);
- EXIT;
-
-out:
- cl_env_nested_put(&nest, env);
- return weight;
-}
-
static void osc_lock_build_einfo(const struct lu_env *env,
const struct cl_lock *clock,
struct osc_lock *lock,
@@ -966,7 +922,6 @@ static void osc_lock_build_einfo(const struct lu_env *env,
einfo->ei_cb_bl = osc_ldlm_blocking_ast;
einfo->ei_cb_cp = osc_ldlm_completion_ast;
einfo->ei_cb_gl = osc_ldlm_glimpse_ast;
- einfo->ei_cb_wg = osc_ldlm_weigh_ast;
einfo->ei_cbdata = lock; /* value to be put into ->l_ast_data */
}
@@ -1059,7 +1014,6 @@ static int osc_lock_enqueue_wait(const struct lu_env *env,
struct cl_lock *conflict= NULL;
int lockless = osc_lock_is_lockless(olck);
int rc = 0;
- ENTRY;
LASSERT(cl_lock_is_mutexed(lock));
@@ -1130,7 +1084,7 @@ static int osc_lock_enqueue_wait(const struct lu_env *env,
rc = CLO_WAIT;
}
}
- RETURN(rc);
+ return rc;
}
/**
@@ -1154,7 +1108,6 @@ static int osc_lock_enqueue(const struct lu_env *env,
struct osc_lock *ols = cl2osc_lock(slice);
struct cl_lock *lock = ols->ols_cl.cls_lock;
int result;
- ENTRY;
LASSERT(cl_lock_is_mutexed(lock));
LASSERTF(ols->ols_state == OLS_NEW,
@@ -1207,7 +1160,7 @@ static int osc_lock_enqueue(const struct lu_env *env,
}
}
LASSERT(ergo(ols->ols_glimpse, !osc_lock_is_lockless(ols)));
- RETURN(result);
+ return result;
}
static int osc_lock_wait(const struct lu_env *env,
@@ -1298,7 +1251,6 @@ static int osc_lock_flush(struct osc_lock *ols, int discard)
struct cl_env_nest nest;
struct lu_env *env;
int result = 0;
- ENTRY;
env = cl_env_nested_get(&nest);
if (!IS_ERR(env)) {
@@ -1328,7 +1280,7 @@ static int osc_lock_flush(struct osc_lock *ols, int discard)
ols->ols_flush = 1;
LINVRNT(!osc_lock_has_pages(ols));
}
- RETURN(result);
+ return result;
}
/**
diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c
index ca94e633138..9d34de873fa 100644
--- a/drivers/staging/lustre/lustre/osc/osc_object.c
+++ b/drivers/staging/lustre/lustre/osc/osc_object.c
@@ -191,10 +191,9 @@ static int osc_object_glimpse(const struct lu_env *env,
{
struct lov_oinfo *oinfo = cl2osc(obj)->oo_oinfo;
- ENTRY;
lvb->lvb_size = oinfo->loi_kms;
lvb->lvb_blocks = oinfo->loi_lvb.lvb_blocks;
- RETURN(0);
+ return 0;
}
diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c
index baba959a745..d272322b29b 100644
--- a/drivers/staging/lustre/lustre/osc/osc_page.c
+++ b/drivers/staging/lustre/lustre/osc/osc_page.c
@@ -219,7 +219,6 @@ static int osc_page_cache_add(const struct lu_env *env,
struct osc_io *oio = osc_env_io(env);
struct osc_page *opg = cl2osc_page(slice);
int result;
- ENTRY;
LINVRNT(osc_page_protected(env, opg, CLM_WRITE, 0));
@@ -240,7 +239,7 @@ static int osc_page_cache_add(const struct lu_env *env,
}
}
- RETURN(result);
+ return result;
}
void osc_index2policy(ldlm_policy_data_t *policy, const struct cl_object *obj,
@@ -294,7 +293,6 @@ static int osc_page_is_under_lock(const struct lu_env *env,
struct cl_lock *lock;
int result = -ENODATA;
- ENTRY;
lock = cl_lock_at_page(env, slice->cpl_obj, slice->cpl_page,
NULL, 1, 0);
if (lock != NULL) {
@@ -302,7 +300,7 @@ static int osc_page_is_under_lock(const struct lu_env *env,
result = -EBUSY;
cl_lock_put(env, lock);
}
- RETURN(result);
+ return result;
}
static void osc_page_disown(const struct lu_env *env,
@@ -421,7 +419,6 @@ static void osc_page_delete(const struct lu_env *env,
LINVRNT(opg->ops_temp || osc_page_protected(env, opg, CLM_READ, 1));
- ENTRY;
CDEBUG(D_TRACE, "%p\n", opg);
osc_page_transfer_put(env, opg);
rc = osc_teardown_async_page(env, obj, opg);
@@ -440,7 +437,6 @@ static void osc_page_delete(const struct lu_env *env,
spin_unlock(&obj->oo_seatbelt);
osc_lru_del(osc_cli(obj), opg, true);
- EXIT;
}
void osc_page_clip(const struct lu_env *env, const struct cl_page_slice *slice,
@@ -481,9 +477,9 @@ static int osc_page_flush(const struct lu_env *env,
{
struct osc_page *opg = cl2osc_page(slice);
int rc = 0;
- ENTRY;
+
rc = osc_flush_async_page(env, io, opg);
- RETURN(rc);
+ return rc;
}
static const struct cl_page_operations osc_page_ops = {
@@ -586,7 +582,7 @@ void osc_page_submit(const struct lu_env *env, struct osc_page *opg,
* at any time.
*/
-static CFS_DECL_WAITQ(osc_lru_waitq);
+static DECLARE_WAIT_QUEUE_HEAD(osc_lru_waitq);
static atomic_t osc_lru_waiters = ATOMIC_INIT(0);
/* LRU pages are freed in batch mode. OSC should at least free this
* number of pages to avoid running out of LRU budget, and.. */
@@ -666,15 +662,14 @@ int osc_lru_shrink(struct client_obd *cli, int target)
int count = 0;
int index = 0;
int rc = 0;
- ENTRY;
LASSERT(atomic_read(&cli->cl_lru_in_list) >= 0);
if (atomic_read(&cli->cl_lru_in_list) == 0 || target <= 0)
- RETURN(0);
+ return 0;
env = cl_env_nested_get(&nest);
if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ return PTR_ERR(env);
pvec = osc_env_info(env)->oti_pvec;
io = &osc_env_info(env)->oti_io;
@@ -757,7 +752,7 @@ int osc_lru_shrink(struct client_obd *cli, int target)
cl_env_nested_put(&nest, env);
atomic_dec(&cli->cl_lru_shrinkers);
- RETURN(count > 0 ? count : rc);
+ return count > 0 ? count : rc;
}
static void osc_lru_add(struct client_obd *cli, struct osc_page *opg)
@@ -881,13 +876,12 @@ static int osc_lru_reserve(const struct lu_env *env, struct osc_object *obj,
struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
struct client_obd *cli = osc_cli(obj);
int rc = 0;
- ENTRY;
if (cli->cl_cache == NULL) /* shall not be in LRU */
- RETURN(0);
+ return 0;
LASSERT(atomic_read(cli->cl_lru_left) >= 0);
- while (!cfs_atomic_add_unless(cli->cl_lru_left, -1, 0)) {
+ while (!atomic_add_unless(cli->cl_lru_left, -1, 0)) {
int gen;
/* run out of LRU spaces, try to drop some by itself */
@@ -921,7 +915,7 @@ static int osc_lru_reserve(const struct lu_env *env, struct osc_object *obj,
rc = 0;
}
- RETURN(rc);
+ return rc;
}
/** @} osc */
diff --git a/drivers/staging/lustre/lustre/osc/osc_quota.c b/drivers/staging/lustre/lustre/osc/osc_quota.c
index 69caab76ced..9720c0e865c 100644
--- a/drivers/staging/lustre/lustre/osc/osc_quota.c
+++ b/drivers/staging/lustre/lustre/osc/osc_quota.c
@@ -45,7 +45,6 @@ static inline struct osc_quota_info *osc_oqi_alloc(obd_uid id)
int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[])
{
int type;
- ENTRY;
for (type = 0; type < MAXQUOTAS; type++) {
struct osc_quota_info *oqi;
@@ -62,11 +61,11 @@ int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[])
* quota space on this OST */
CDEBUG(D_QUOTA, "chkdq found noquota for %s %d\n",
type == USRQUOTA ? "user" : "grout", qid[type]);
- RETURN(NO_QUOTA);
+ return NO_QUOTA;
}
}
- RETURN(QUOTA_OK);
+ return QUOTA_OK;
}
#define MD_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_MD_FLUSRQUOTA \
@@ -79,10 +78,9 @@ int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[],
{
int type;
int rc = 0;
- ENTRY;
if ((valid & (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA)) == 0)
- RETURN(0);
+ return 0;
for (type = 0; type < MAXQUOTAS; type++) {
struct osc_quota_info *oqi;
@@ -134,7 +132,7 @@ int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[],
}
}
- RETURN(rc);
+ return rc;
}
/*
@@ -211,7 +209,6 @@ int osc_quota_setup(struct obd_device *obd)
{
struct client_obd *cli = &obd->u.cli;
int i, type;
- ENTRY;
for (type = 0; type < MAXQUOTAS; type++) {
cli->cl_quota_hash[type] = cfs_hash_create("QUOTA_HASH",
@@ -228,24 +225,23 @@ int osc_quota_setup(struct obd_device *obd)
}
if (type == MAXQUOTAS)
- RETURN(0);
+ return 0;
for (i = 0; i < type; i++)
cfs_hash_putref(cli->cl_quota_hash[i]);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
int osc_quota_cleanup(struct obd_device *obd)
{
struct client_obd *cli = &obd->u.cli;
int type;
- ENTRY;
for (type = 0; type < MAXQUOTAS; type++)
cfs_hash_putref(cli->cl_quota_hash[type]);
- RETURN(0);
+ return 0;
}
int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
@@ -254,13 +250,12 @@ int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
struct ptlrpc_request *req;
struct obd_quotactl *oqc;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
&RQF_OST_QUOTACTL, LUSTRE_OST_VERSION,
OST_QUOTACTL);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
oqc = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
*oqc = *oqctl;
@@ -282,7 +277,7 @@ int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
}
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
int osc_quotacheck(struct obd_device *unused, struct obd_export *exp,
@@ -292,13 +287,12 @@ int osc_quotacheck(struct obd_device *unused, struct obd_export *exp,
struct ptlrpc_request *req;
struct obd_quotactl *body;
int rc;
- ENTRY;
req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
&RQF_OST_QUOTACHECK, LUSTRE_OST_VERSION,
OST_QUOTACHECK);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
body = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
*body = *oqctl;
@@ -312,14 +306,13 @@ int osc_quotacheck(struct obd_device *unused, struct obd_export *exp,
if (rc)
cli->cl_qchk_stat = rc;
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
int osc_quota_poll_check(struct obd_export *exp, struct if_quotacheck *qchk)
{
struct client_obd *cli = &exp->exp_obd->u.cli;
int rc;
- ENTRY;
qchk->obd_uuid = cli->cl_target_uuid;
memcpy(qchk->obd_type, LUSTRE_OST_NAME, strlen(LUSTRE_OST_NAME));
@@ -328,5 +321,5 @@ int osc_quota_poll_check(struct obd_export *exp, struct if_quotacheck *qchk)
/* the client is not the previous one */
if (rc == CL_NOT_QUOTACHECKED)
rc = -EINTR;
- RETURN(rc);
+ return rc;
}
diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c
index 53d6a35c80b..ee6707a5ea9 100644
--- a/drivers/staging/lustre/lustre/osc/osc_request.c
+++ b/drivers/staging/lustre/lustre/osc/osc_request.c
@@ -69,30 +69,29 @@ static int osc_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
struct lov_stripe_md *lsm)
{
int lmm_size;
- ENTRY;
lmm_size = sizeof(**lmmp);
if (lmmp == NULL)
- RETURN(lmm_size);
+ return lmm_size;
if (*lmmp != NULL && lsm == NULL) {
OBD_FREE(*lmmp, lmm_size);
*lmmp = NULL;
- RETURN(0);
+ return 0;
} else if (unlikely(lsm != NULL && ostid_id(&lsm->lsm_oi) == 0)) {
- RETURN(-EBADF);
+ return -EBADF;
}
if (*lmmp == NULL) {
OBD_ALLOC(*lmmp, lmm_size);
if (*lmmp == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
if (lsm)
ostid_cpu_to_le(&lsm->lsm_oi, &(*lmmp)->lmm_oi);
- RETURN(lmm_size);
+ return lmm_size;
}
/* Unpack OSC object metadata from disk storage (LE byte order). */
@@ -101,47 +100,46 @@ static int osc_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
{
int lsm_size;
struct obd_import *imp = class_exp2cliimp(exp);
- ENTRY;
if (lmm != NULL) {
if (lmm_bytes < sizeof(*lmm)) {
CERROR("%s: lov_mds_md too small: %d, need %d\n",
exp->exp_obd->obd_name, lmm_bytes,
(int)sizeof(*lmm));
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* XXX LOV_MAGIC etc check? */
if (unlikely(ostid_id(&lmm->lmm_oi) == 0)) {
CERROR("%s: zero lmm_object_id: rc = %d\n",
exp->exp_obd->obd_name, -EINVAL);
- RETURN(-EINVAL);
+ return -EINVAL;
}
}
lsm_size = lov_stripe_md_size(1);
if (lsmp == NULL)
- RETURN(lsm_size);
+ return lsm_size;
if (*lsmp != NULL && lmm == NULL) {
OBD_FREE((*lsmp)->lsm_oinfo[0], sizeof(struct lov_oinfo));
OBD_FREE(*lsmp, lsm_size);
*lsmp = NULL;
- RETURN(0);
+ return 0;
}
if (*lsmp == NULL) {
OBD_ALLOC(*lsmp, lsm_size);
if (unlikely(*lsmp == NULL))
- RETURN(-ENOMEM);
+ return -ENOMEM;
OBD_ALLOC((*lsmp)->lsm_oinfo[0], sizeof(struct lov_oinfo));
if (unlikely((*lsmp)->lsm_oinfo[0] == NULL)) {
OBD_FREE(*lsmp, lsm_size);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
loi_init((*lsmp)->lsm_oinfo[0]);
} else if (unlikely(ostid_id(&(*lsmp)->lsm_oi) == 0)) {
- RETURN(-EBADF);
+ return -EBADF;
}
if (lmm != NULL)
@@ -154,7 +152,7 @@ static int osc_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
else
(*lsmp)->lsm_maxbytes = LUSTRE_STRIPE_MAXBYTES;
- RETURN(lsm_size);
+ return lsm_size;
}
static inline void osc_pack_capa(struct ptlrpc_request *req,
@@ -202,7 +200,6 @@ static int osc_getattr_interpret(const struct lu_env *env,
struct osc_async_args *aa, int rc)
{
struct ost_body *body;
- ENTRY;
if (rc != 0)
GOTO(out, rc);
@@ -223,7 +220,7 @@ static int osc_getattr_interpret(const struct lu_env *env,
}
out:
rc = aa->aa_oi->oi_cb_up(aa->aa_oi, rc);
- RETURN(rc);
+ return rc;
}
static int osc_getattr_async(struct obd_export *exp, struct obd_info *oinfo,
@@ -232,17 +229,16 @@ static int osc_getattr_async(struct obd_export *exp, struct obd_info *oinfo,
struct ptlrpc_request *req;
struct osc_async_args *aa;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_GETATTR);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_GETATTR);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
osc_pack_req_body(req, oinfo);
@@ -255,7 +251,7 @@ static int osc_getattr_async(struct obd_export *exp, struct obd_info *oinfo,
aa->aa_oi = oinfo;
ptlrpc_set_add_req(set, req);
- RETURN(0);
+ return 0;
}
static int osc_getattr(const struct lu_env *env, struct obd_export *exp,
@@ -264,17 +260,16 @@ static int osc_getattr(const struct lu_env *env, struct obd_export *exp,
struct ptlrpc_request *req;
struct ost_body *body;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_GETATTR);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_GETATTR);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
osc_pack_req_body(req, oinfo);
@@ -296,7 +291,6 @@ static int osc_getattr(const struct lu_env *env, struct obd_export *exp,
oinfo->oi_oa->o_blksize = cli_brw_size(exp->exp_obd);
oinfo->oi_oa->o_valid |= OBD_MD_FLBLKSZ;
- EXIT;
out:
ptlrpc_req_finished(req);
return rc;
@@ -308,19 +302,18 @@ static int osc_setattr(const struct lu_env *env, struct obd_export *exp,
struct ptlrpc_request *req;
struct ost_body *body;
int rc;
- ENTRY;
LASSERT(oinfo->oi_oa->o_valid & OBD_MD_FLGROUP);
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_SETATTR);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_SETATTR);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
osc_pack_req_body(req, oinfo);
@@ -338,10 +331,9 @@ static int osc_setattr(const struct lu_env *env, struct obd_export *exp,
lustre_get_wire_obdo(&req->rq_import->imp_connect_data, oinfo->oi_oa,
&body->oa);
- EXIT;
out:
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
static int osc_setattr_interpret(const struct lu_env *env,
@@ -349,7 +341,6 @@ static int osc_setattr_interpret(const struct lu_env *env,
struct osc_setattr_args *sa, int rc)
{
struct ost_body *body;
- ENTRY;
if (rc != 0)
GOTO(out, rc);
@@ -362,7 +353,7 @@ static int osc_setattr_interpret(const struct lu_env *env,
&body->oa);
out:
rc = sa->sa_upcall(sa->sa_cookie, rc);
- RETURN(rc);
+ return rc;
}
int osc_setattr_async_base(struct obd_export *exp, struct obd_info *oinfo,
@@ -373,17 +364,16 @@ int osc_setattr_async_base(struct obd_export *exp, struct obd_info *oinfo,
struct ptlrpc_request *req;
struct osc_setattr_args *sa;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_SETATTR);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_SETATTR);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
if (oti && oinfo->oi_oa->o_valid & OBD_MD_FLCOOKIE)
@@ -413,7 +403,7 @@ int osc_setattr_async_base(struct obd_export *exp, struct obd_info *oinfo,
ptlrpc_set_add_req(rqset, req);
}
- RETURN(0);
+ return 0;
}
static int osc_setattr_async(struct obd_export *exp, struct obd_info *oinfo,
@@ -431,7 +421,6 @@ int osc_real_create(struct obd_export *exp, struct obdo *oa,
struct ost_body *body;
struct lov_stripe_md *lsm;
int rc;
- ENTRY;
LASSERT(oa);
LASSERT(ea);
@@ -440,7 +429,7 @@ int osc_real_create(struct obd_export *exp, struct obdo *oa,
if (!lsm) {
rc = obd_alloc_memmd(exp, &lsm);
if (rc < 0)
- RETURN(rc);
+ return rc;
}
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_CREATE);
@@ -506,7 +495,7 @@ out_req:
out:
if (rc && !*ea)
obd_free_memmd(exp, &lsm);
- RETURN(rc);
+ return rc;
}
int osc_punch_base(struct obd_export *exp, struct obd_info *oinfo,
@@ -517,17 +506,16 @@ int osc_punch_base(struct obd_export *exp, struct obd_info *oinfo,
struct osc_setattr_args *sa;
struct ost_body *body;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_PUNCH);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_PUNCH);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
req->rq_request_portal = OST_IO_PORTAL; /* bug 7198 */
ptlrpc_at_set_req_timeout(req);
@@ -551,7 +539,7 @@ int osc_punch_base(struct obd_export *exp, struct obd_info *oinfo,
else
ptlrpc_set_add_req(rqset, req);
- RETURN(0);
+ return 0;
}
static int osc_punch(const struct lu_env *env, struct obd_export *exp,
@@ -571,7 +559,6 @@ static int osc_sync_interpret(const struct lu_env *env,
{
struct osc_fsync_args *fa = arg;
struct ost_body *body;
- ENTRY;
if (rc)
GOTO(out, rc);
@@ -585,7 +572,7 @@ static int osc_sync_interpret(const struct lu_env *env,
*fa->fa_oi->oi_oa = body->oa;
out:
rc = fa->fa_upcall(fa->fa_cookie, rc);
- RETURN(rc);
+ return rc;
}
int osc_sync_base(struct obd_export *exp, struct obd_info *oinfo,
@@ -596,17 +583,16 @@ int osc_sync_base(struct obd_export *exp, struct obd_info *oinfo,
struct ost_body *body;
struct osc_fsync_args *fa;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_SYNC);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_SYNC);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
/* overload the size and blocks fields in the oa with start/end */
@@ -630,25 +616,23 @@ int osc_sync_base(struct obd_export *exp, struct obd_info *oinfo,
else
ptlrpc_set_add_req(rqset, req);
- RETURN (0);
+ return 0;
}
static int osc_sync(const struct lu_env *env, struct obd_export *exp,
struct obd_info *oinfo, obd_size start, obd_size end,
struct ptlrpc_request_set *set)
{
- ENTRY;
-
if (!oinfo->oi_oa) {
CDEBUG(D_INFO, "oa NULL\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
oinfo->oi_oa->o_size = start;
oinfo->oi_oa->o_blocks = end;
oinfo->oi_oa->o_valid |= (OBD_MD_FLSIZE | OBD_MD_FLBLOCKS);
- RETURN(osc_sync_base(exp, oinfo, oinfo->oi_cb_up, oinfo, set));
+ return osc_sync_base(exp, oinfo, oinfo->oi_cb_up, oinfo, set);
}
/* Find and cancel locally locks matched by @mode in the resource found by
@@ -662,7 +646,6 @@ static int osc_resource_get_unused(struct obd_export *exp, struct obdo *oa,
struct ldlm_res_id res_id;
struct ldlm_resource *res;
int count;
- ENTRY;
/* Return, i.e. cancel nothing, only if ELC is supported (flag in
* export) but disabled through procfs (flag in NS).
@@ -671,19 +654,19 @@ static int osc_resource_get_unused(struct obd_export *exp, struct obdo *oa,
* when we still want to cancel locks in advance and just cancel them
* locally, without sending any RPC. */
if (exp_connect_cancelset(exp) && !ns_connect_cancelset(ns))
- RETURN(0);
+ return 0;
ostid_build_res_name(&oa->o_oi, &res_id);
res = ldlm_resource_get(ns, NULL, &res_id, 0, 0);
if (res == NULL)
- RETURN(0);
+ return 0;
LDLM_RESOURCE_ADDREF(res);
count = ldlm_cancel_resource_local(res, cancels, NULL, mode,
lock_flags, 0, NULL);
LDLM_RESOURCE_DELREF(res);
ldlm_resource_putref(res);
- RETURN(count);
+ return count;
}
static int osc_destroy_interpret(const struct lu_env *env,
@@ -720,7 +703,6 @@ int osc_create(const struct lu_env *env, struct obd_export *exp,
struct obd_trans_info *oti)
{
int rc = 0;
- ENTRY;
LASSERT(oa);
LASSERT(ea);
@@ -728,16 +710,16 @@ int osc_create(const struct lu_env *env, struct obd_export *exp,
if ((oa->o_valid & OBD_MD_FLFLAGS) &&
oa->o_flags == OBD_FL_RECREATE_OBJS) {
- RETURN(osc_real_create(exp, oa, ea, oti));
+ return osc_real_create(exp, oa, ea, oti);
}
if (!fid_seq_is_mdt(ostid_seq(&oa->o_oi)))
- RETURN(osc_real_create(exp, oa, ea, oti));
+ return osc_real_create(exp, oa, ea, oti);
/* we should not get here anymore */
LBUG();
- RETURN(rc);
+ return rc;
}
/* Destroy requests can be async always on the client, and we don't even really
@@ -760,11 +742,10 @@ static int osc_destroy(const struct lu_env *env, struct obd_export *exp,
struct ost_body *body;
LIST_HEAD(cancels);
int rc, count;
- ENTRY;
if (!oa) {
CDEBUG(D_INFO, "oa NULL\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
count = osc_resource_get_unused(exp, oa, &cancels, LCK_PW,
@@ -773,7 +754,7 @@ static int osc_destroy(const struct lu_env *env, struct obd_export *exp,
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_DESTROY);
if (req == NULL) {
ldlm_lock_list_put(&cancels, l_bl_ast, count);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
osc_set_capa_size(req, &RMF_CAPA1, (struct obd_capa *)capa);
@@ -781,7 +762,7 @@ static int osc_destroy(const struct lu_env *env, struct obd_export *exp,
0, &cancels, count);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
req->rq_request_portal = OST_IO_PORTAL; /* bug 7198 */
@@ -817,7 +798,7 @@ static int osc_destroy(const struct lu_env *env, struct obd_export *exp,
/* Do not wait for response */
ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1);
- RETURN(0);
+ return 0;
}
static void osc_announce_cached(struct client_obd *cli, struct obdo *oa,
@@ -948,7 +929,6 @@ int osc_shrink_grant_to_target(struct client_obd *cli, __u64 target_bytes)
{
int rc = 0;
struct ost_body *body;
- ENTRY;
client_obd_list_lock(&cli->cl_loi_list_lock);
/* Don't shrink if we are already above or below the desired limit
@@ -959,13 +939,13 @@ int osc_shrink_grant_to_target(struct client_obd *cli, __u64 target_bytes)
if (target_bytes >= cli->cl_avail_grant) {
client_obd_list_unlock(&cli->cl_loi_list_lock);
- RETURN(0);
+ return 0;
}
client_obd_list_unlock(&cli->cl_loi_list_lock);
OBD_ALLOC_PTR(body);
if (!body)
- RETURN(-ENOMEM);
+ return -ENOMEM;
osc_announce_cached(cli, &body->oa, 0);
@@ -986,7 +966,7 @@ int osc_shrink_grant_to_target(struct client_obd *cli, __u64 target_bytes)
if (rc != 0)
__osc_update_grant(cli, body->oa.o_grant);
OBD_FREE_PTR(body);
- RETURN(rc);
+ return rc;
}
static int osc_should_shrink_grant(struct client_obd *client)
@@ -1256,11 +1236,10 @@ static int osc_brw_prep_request(int cmd, struct client_obd *cli,struct obdo *oa,
struct req_capsule *pill;
struct brw_page *pg_prev;
- ENTRY;
if (OBD_FAIL_CHECK(OBD_FAIL_OSC_BRW_PREP_REQ))
- RETURN(-ENOMEM); /* Recoverable */
+ return -ENOMEM; /* Recoverable */
if (OBD_FAIL_CHECK(OBD_FAIL_OSC_BRW_PREP_REQ2))
- RETURN(-EINVAL); /* Fatal */
+ return -EINVAL; /* Fatal */
if ((cmd & OBD_BRW_WRITE) != 0) {
opc = OST_WRITE;
@@ -1272,7 +1251,7 @@ static int osc_brw_prep_request(int cmd, struct client_obd *cli,struct obdo *oa,
req = ptlrpc_request_alloc(cli->cl_import, &RQF_OST_BRW_READ);
}
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
for (niocount = i = 1; i < page_count; i++) {
if (!can_merge_pages(pga[i - 1], pga[i]))
@@ -1289,7 +1268,7 @@ static int osc_brw_prep_request(int cmd, struct client_obd *cli,struct obdo *oa,
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, opc);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
req->rq_request_portal = OST_IO_PORTAL; /* bug 7198 */
ptlrpc_at_set_req_timeout(req);
@@ -1435,11 +1414,11 @@ static int osc_brw_prep_request(int cmd, struct client_obd *cli,struct obdo *oa,
aa->aa_ocapa = capa_get(ocapa);
*reqp = req;
- RETURN(0);
+ return 0;
out:
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
static int check_write_checksum(struct obdo *oa, const lnet_process_id_t *peer,
@@ -1496,18 +1475,17 @@ static int osc_brw_fini_request(struct ptlrpc_request *req, int rc)
struct client_obd *cli = aa->aa_cli;
struct ost_body *body;
__u32 client_cksum = 0;
- ENTRY;
if (rc < 0 && rc != -EDQUOT) {
DEBUG_REQ(D_INFO, req, "Failed request with rc = %d\n", rc);
- RETURN(rc);
+ return rc;
}
LASSERTF(req->rq_repmsg != NULL, "rc = %d\n", rc);
body = req_capsule_server_get(&req->rq_pill, &RMF_OST_BODY);
if (body == NULL) {
DEBUG_REQ(D_INFO, req, "Can't unpack body\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
/* set/clear over quota flag for a uid/gid */
@@ -1524,7 +1502,7 @@ static int osc_brw_fini_request(struct ptlrpc_request *req, int rc)
osc_update_grant(cli, body);
if (rc < 0)
- RETURN(rc);
+ return rc;
if (aa->aa_oa->o_valid & OBD_MD_FLCKSUM)
client_cksum = aa->aa_oa->o_cksum; /* save for later */
@@ -1532,19 +1510,19 @@ static int osc_brw_fini_request(struct ptlrpc_request *req, int rc)
if (lustre_msg_get_opc(req->rq_reqmsg) == OST_WRITE) {
if (rc > 0) {
CERROR("Unexpected +ve rc %d\n", rc);
- RETURN(-EPROTO);
+ return -EPROTO;
}
LASSERT(req->rq_bulk->bd_nob == aa->aa_requested_nob);
if (sptlrpc_cli_unwrap_bulk_write(req, req->rq_bulk))
- RETURN(-EAGAIN);
+ return -EAGAIN;
if ((aa->aa_oa->o_valid & OBD_MD_FLCKSUM) && client_cksum &&
check_write_checksum(&body->oa, peer, client_cksum,
body->oa.o_cksum, aa->aa_requested_nob,
aa->aa_page_count, aa->aa_ppga,
cksum_type_unpack(aa->aa_oa->o_flags)))
- RETURN(-EAGAIN);
+ return -EAGAIN;
rc = check_write_rcs(req, aa->aa_requested_nob,aa->aa_nio_count,
aa->aa_page_count, aa->aa_ppga);
@@ -1561,7 +1539,7 @@ static int osc_brw_fini_request(struct ptlrpc_request *req, int rc)
if (rc > aa->aa_requested_nob) {
CERROR("Unexpected rc %d (%d requested)\n", rc,
aa->aa_requested_nob);
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (rc != req->rq_bulk->bd_nob_transferred) {
@@ -1641,7 +1619,7 @@ out:
lustre_get_wire_obdo(&req->rq_import->imp_connect_data,
aa->aa_oa, &body->oa);
- RETURN(rc);
+ return rc;
}
static int osc_brw_internal(int cmd, struct obd_export *exp, struct obdo *oa,
@@ -1655,8 +1633,6 @@ static int osc_brw_internal(int cmd, struct obd_export *exp, struct obdo *oa,
int generation, resends = 0;
struct l_wait_info lwi;
- ENTRY;
-
init_waitqueue_head(&waitq);
generation = exp->exp_obd->u.cli.cl_import->imp_generation;
@@ -1711,7 +1687,7 @@ restart_bulk:
out:
if (rc == -EAGAIN || rc == -EINPROGRESS)
rc = -EIO;
- RETURN (rc);
+ return rc;
}
static int osc_brw_redo_request(struct ptlrpc_request *request,
@@ -1720,7 +1696,6 @@ static int osc_brw_redo_request(struct ptlrpc_request *request,
struct ptlrpc_request *new_req;
struct osc_brw_async_args *new_aa;
struct osc_async_page *oap;
- ENTRY;
DEBUG_REQ(rc == -EINPROGRESS ? D_RPCTRACE : D_ERROR, request,
"redo for recoverable error %d", rc);
@@ -1732,7 +1707,7 @@ static int osc_brw_redo_request(struct ptlrpc_request *request,
aa->aa_page_count, aa->aa_ppga,
&new_req, aa->aa_ocapa, 0, 1);
if (rc)
- RETURN(rc);
+ return rc;
list_for_each_entry(oap, &aa->aa_oaps, oap_rpc_item) {
if (oap->oap_request != NULL) {
@@ -1741,7 +1716,7 @@ static int osc_brw_redo_request(struct ptlrpc_request *request,
request, oap->oap_request);
if (oap->oap_interrupted) {
ptlrpc_req_finished(new_req);
- RETURN(-EINTR);
+ return -EINTR;
}
}
}
@@ -1784,7 +1759,7 @@ static int osc_brw_redo_request(struct ptlrpc_request *request,
ptlrpcd_add_req(new_req, PDL_POLICY_SAME, -1);
DEBUG_REQ(D_INFO, new_req, "new request");
- RETURN(0);
+ return 0;
}
/*
@@ -1873,7 +1848,6 @@ static int osc_brw(int cmd, struct obd_export *exp, struct obd_info *oinfo,
struct obd_import *imp = class_exp2cliimp(exp);
struct client_obd *cli;
int rc, page_count_orig;
- ENTRY;
LASSERT((imp != NULL) && (imp->imp_obd != NULL));
cli = &imp->imp_obd->u.cli;
@@ -1883,8 +1857,8 @@ static int osc_brw(int cmd, struct obd_export *exp, struct obd_info *oinfo,
* I/O can succeed */
if (imp->imp_invalid)
- RETURN(-EIO);
- RETURN(0);
+ return -EIO;
+ return 0;
}
/* test_brw with a failed create can trip this, maybe others. */
@@ -1894,7 +1868,7 @@ static int osc_brw(int cmd, struct obd_export *exp, struct obd_info *oinfo,
orig = ppga = osc_build_ppga(pga, page_count);
if (ppga == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
page_count_orig = page_count;
sort_brw_pages(ppga, page_count);
@@ -1935,7 +1909,7 @@ out:
if (saved_oa != NULL)
OBDO_FREE(saved_oa);
- RETURN(rc);
+ return rc;
}
static int brw_interpret(const struct lu_env *env,
@@ -1946,7 +1920,6 @@ static int brw_interpret(const struct lu_env *env,
struct osc_extent *tmp;
struct cl_object *obj = NULL;
struct client_obd *cli = aa->aa_cli;
- ENTRY;
rc = osc_brw_fini_request(req, rc);
CDEBUG(D_INODE, "request %p aa %p rc %d\n", req, aa, rc);
@@ -1970,7 +1943,7 @@ static int brw_interpret(const struct lu_env *env,
}
if (rc == 0)
- RETURN(0);
+ return 0;
else if (rc == -EAGAIN || rc == -EINPROGRESS)
rc = -EIO;
}
@@ -2040,7 +2013,7 @@ static int brw_interpret(const struct lu_env *env,
client_obd_list_unlock(&cli->cl_loi_list_lock);
osc_io_unplug(env, cli, NULL, PDL_POLICY_SAME);
- RETURN(rc);
+ return rc;
}
/**
@@ -2072,7 +2045,6 @@ int osc_build_rpc(const struct lu_env *env, struct client_obd *cli,
int rc;
LIST_HEAD(rpc_list);
- ENTRY;
LASSERT(!list_empty(ext_list));
/* add pages into rpc_list to build BRW rpc */
@@ -2228,7 +2200,6 @@ int osc_build_rpc(const struct lu_env *env, struct client_obd *cli,
*/
ptlrpcd_add_req(req, pol, -1);
rc = 0;
- EXIT;
out:
if (mem_tight != 0)
@@ -2257,7 +2228,7 @@ out:
if (clerq && !IS_ERR(clerq))
cl_req_completion(env, clerq, rc);
}
- RETURN(rc);
+ return rc;
}
static int osc_set_lock_data_with_check(struct ldlm_lock *lock,
@@ -2337,7 +2308,6 @@ static int osc_enqueue_fini(struct ptlrpc_request *req, struct ost_lvb *lvb,
__u64 *flags, int agl, int rc)
{
int intent = *flags & LDLM_FL_HAS_INTENT;
- ENTRY;
if (intent) {
/* The request was created before ldlm_cli_enqueue call. */
@@ -2347,6 +2317,8 @@ static int osc_enqueue_fini(struct ptlrpc_request *req, struct ost_lvb *lvb,
&RMF_DLM_REP);
LASSERT(rep != NULL);
+ rep->lock_policy_res1 =
+ ptlrpc_status_ntoh(rep->lock_policy_res1);
if (rep->lock_policy_res1)
rc = rep->lock_policy_res1;
}
@@ -2361,7 +2333,7 @@ static int osc_enqueue_fini(struct ptlrpc_request *req, struct ost_lvb *lvb,
/* Call the update callback. */
rc = (*upcall)(cookie, rc);
- RETURN(rc);
+ return rc;
}
static int osc_enqueue_interpret(const struct lu_env *env,
@@ -2494,7 +2466,6 @@ int osc_enqueue_base(struct obd_export *exp, struct ldlm_res_id *res_id,
int match_lvb = (agl != 0 ? 0 : LDLM_FL_LVB_READY);
ldlm_mode_t mode;
int rc;
- ENTRY;
/* Filesystem lock extents are extended to page boundaries so that
* dealing with the page cache is a little smoother. */
@@ -2536,7 +2507,7 @@ int osc_enqueue_base(struct obd_export *exp, struct ldlm_res_id *res_id,
* Return -ECANCELED to tell the caller. */
ldlm_lock_decref(lockh, mode);
LDLM_LOCK_PUT(matched);
- RETURN(-ECANCELED);
+ return -ECANCELED;
} else if (osc_set_lock_data_with_check(matched, einfo)) {
*flags |= LDLM_FL_LVB_READY;
/* addref the lock only if not async requests and PW
@@ -2561,7 +2532,7 @@ int osc_enqueue_base(struct obd_export *exp, struct ldlm_res_id *res_id,
/* For async requests, decref the lock. */
ldlm_lock_decref(lockh, einfo->ei_mode);
LDLM_LOCK_PUT(matched);
- RETURN(ELDLM_OK);
+ return ELDLM_OK;
} else {
ldlm_lock_decref(lockh, mode);
LDLM_LOCK_PUT(matched);
@@ -2574,12 +2545,12 @@ int osc_enqueue_base(struct obd_export *exp, struct ldlm_res_id *res_id,
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_LDLM_ENQUEUE_LVB);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = ldlm_prep_enqueue_req(exp, req, &cancels, 0);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER,
@@ -2615,14 +2586,14 @@ int osc_enqueue_base(struct obd_export *exp, struct ldlm_res_id *res_id,
} else if (intent) {
ptlrpc_req_finished(req);
}
- RETURN(rc);
+ return rc;
}
rc = osc_enqueue_fini(req, lvb, upcall, cookie, flags, agl, rc);
if (intent)
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
static int osc_enqueue(struct obd_export *exp, struct obd_info *oinfo,
@@ -2631,7 +2602,6 @@ static int osc_enqueue(struct obd_export *exp, struct obd_info *oinfo,
{
struct ldlm_res_id res_id;
int rc;
- ENTRY;
ostid_build_res_name(&oinfo->oi_md->lsm_oi, &res_id);
rc = osc_enqueue_base(exp, &res_id, &oinfo->oi_flags, &oinfo->oi_policy,
@@ -2639,7 +2609,7 @@ static int osc_enqueue(struct obd_export *exp, struct obd_info *oinfo,
oinfo->oi_md->lsm_oinfo[0]->loi_kms_valid,
oinfo->oi_cb_up, oinfo, einfo, oinfo->oi_lockh,
rqset, rqset != NULL, 0);
- RETURN(rc);
+ return rc;
}
int osc_match_base(struct obd_export *exp, struct ldlm_res_id *res_id,
@@ -2650,10 +2620,9 @@ int osc_match_base(struct obd_export *exp, struct ldlm_res_id *res_id,
struct obd_device *obd = exp->exp_obd;
int lflags = *flags;
ldlm_mode_t rc;
- ENTRY;
if (OBD_FAIL_CHECK(OBD_FAIL_OSC_MATCH))
- RETURN(-EIO);
+ return -EIO;
/* Filesystem lock extents are extended to page boundaries so that
* dealing with the page cache is a little smoother */
@@ -2674,35 +2643,32 @@ int osc_match_base(struct obd_export *exp, struct ldlm_res_id *res_id,
if (!osc_set_data_with_check(lockh, data)) {
if (!(lflags & LDLM_FL_TEST_LOCK))
ldlm_lock_decref(lockh, rc);
- RETURN(0);
+ return 0;
}
}
if (!(lflags & LDLM_FL_TEST_LOCK) && mode != rc) {
ldlm_lock_addref(lockh, LCK_PR);
ldlm_lock_decref(lockh, LCK_PW);
}
- RETURN(rc);
+ return rc;
}
- RETURN(rc);
+ return rc;
}
int osc_cancel_base(struct lustre_handle *lockh, __u32 mode)
{
- ENTRY;
-
if (unlikely(mode == LCK_GROUP))
ldlm_lock_decref_and_cancel(lockh, mode);
else
ldlm_lock_decref(lockh, mode);
- RETURN(0);
+ return 0;
}
static int osc_cancel(struct obd_export *exp, struct lov_stripe_md *md,
__u32 mode, struct lustre_handle *lockh)
{
- ENTRY;
- RETURN(osc_cancel_base(lockh, mode));
+ return osc_cancel_base(lockh, mode);
}
static int osc_cancel_unused(struct obd_export *exp,
@@ -2726,7 +2692,6 @@ static int osc_statfs_interpret(const struct lu_env *env,
struct osc_async_args *aa, int rc)
{
struct obd_statfs *msfs;
- ENTRY;
if (rc == -EBADR)
/* The request has in fact never been sent
@@ -2734,7 +2699,7 @@ static int osc_statfs_interpret(const struct lu_env *env,
* Exit immediately since the caller is
* aware of the problem and takes care
* of the clean up */
- RETURN(rc);
+ return rc;
if ((rc == -ENOTCONN || rc == -EAGAIN) &&
(aa->aa_oi->oi_flags & OBD_STATFS_NODELAY))
@@ -2751,7 +2716,7 @@ static int osc_statfs_interpret(const struct lu_env *env,
*aa->aa_oi->oi_osfs = *msfs;
out:
rc = aa->aa_oi->oi_cb_up(aa->aa_oi, rc);
- RETURN(rc);
+ return rc;
}
static int osc_statfs_async(struct obd_export *exp,
@@ -2762,7 +2727,6 @@ static int osc_statfs_async(struct obd_export *exp,
struct ptlrpc_request *req;
struct osc_async_args *aa;
int rc;
- ENTRY;
/* We could possibly pass max_age in the request (as an absolute
* timestamp or a "seconds.usec ago") so the target can avoid doing
@@ -2772,12 +2736,12 @@ static int osc_statfs_async(struct obd_export *exp,
* timestamps are not ideal because they need time synchronization. */
req = ptlrpc_request_alloc(obd->u.cli.cl_import, &RQF_OST_STATFS);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_STATFS);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
ptlrpc_request_set_replen(req);
req->rq_request_portal = OST_CREATE_PORTAL;
@@ -2795,7 +2759,7 @@ static int osc_statfs_async(struct obd_export *exp,
aa->aa_oi = oinfo;
ptlrpc_set_add_req(rqset, req);
- RETURN(0);
+ return 0;
}
static int osc_statfs(const struct lu_env *env, struct obd_export *exp,
@@ -2806,7 +2770,6 @@ static int osc_statfs(const struct lu_env *env, struct obd_export *exp,
struct ptlrpc_request *req;
struct obd_import *imp = NULL;
int rc;
- ENTRY;
/*Since the request might also come from lprocfs, so we need
*sync this with client_disconnect_export Bug15684*/
@@ -2815,7 +2778,7 @@ static int osc_statfs(const struct lu_env *env, struct obd_export *exp,
imp = class_import_get(obd->u.cli.cl_import);
up_read(&obd->u.cli.cl_sem);
if (!imp)
- RETURN(-ENODEV);
+ return -ENODEV;
/* We could possibly pass max_age in the request (as an absolute
* timestamp or a "seconds.usec ago") so the target can avoid doing
@@ -2828,12 +2791,12 @@ static int osc_statfs(const struct lu_env *env, struct obd_export *exp,
class_import_put(imp);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_STATFS);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
ptlrpc_request_set_replen(req);
req->rq_request_portal = OST_CREATE_PORTAL;
@@ -2856,7 +2819,6 @@ static int osc_statfs(const struct lu_env *env, struct obd_export *exp,
*osfs = *msfs;
- EXIT;
out:
ptlrpc_req_finished(req);
return rc;
@@ -2874,20 +2836,19 @@ static int osc_getstripe(struct lov_stripe_md *lsm, struct lov_user_md *lump)
struct lov_user_md_v3 lum, *lumk;
struct lov_user_ost_data_v1 *lmm_objects;
int rc = 0, lum_size;
- ENTRY;
if (!lsm)
- RETURN(-ENODATA);
+ return -ENODATA;
/* we only need the header part from user space to get lmm_magic and
* lmm_stripe_count, (the header part is common to v1 and v3) */
lum_size = sizeof(struct lov_user_md_v1);
if (copy_from_user(&lum, lump, lum_size))
- RETURN(-EFAULT);
+ return -EFAULT;
if ((lum.lmm_magic != LOV_USER_MAGIC_V1) &&
(lum.lmm_magic != LOV_USER_MAGIC_V3))
- RETURN(-EINVAL);
+ return -EINVAL;
/* lov_user_md_vX and lov_mds_md_vX must have the same size */
LASSERT(sizeof(struct lov_user_md_v1) == sizeof(struct lov_mds_md_v1));
@@ -2900,7 +2861,7 @@ static int osc_getstripe(struct lov_stripe_md *lsm, struct lov_user_md *lump)
lum_size = lov_mds_md_size(lum.lmm_stripe_count, lum.lmm_magic);
OBD_ALLOC(lumk, lum_size);
if (!lumk)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (lum.lmm_magic == LOV_USER_MAGIC_V1)
lmm_objects =
@@ -2922,7 +2883,7 @@ static int osc_getstripe(struct lov_stripe_md *lsm, struct lov_user_md *lump)
if (lumk != &lum)
OBD_FREE(lumk, lum_size);
- RETURN(rc);
+ return rc;
}
@@ -2932,7 +2893,6 @@ static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
struct obd_device *obd = exp->exp_obd;
struct obd_ioctl_data *data = karg;
int err = 0;
- ENTRY;
if (!try_module_get(THIS_MODULE)) {
CERROR("Can't get module. Is it alive?");
@@ -3016,15 +2976,14 @@ static int osc_get_info(const struct lu_env *env, struct obd_export *exp,
obd_count keylen, void *key, __u32 *vallen, void *val,
struct lov_stripe_md *lsm)
{
- ENTRY;
if (!vallen || !val)
- RETURN(-EFAULT);
+ return -EFAULT;
if (KEY_IS(KEY_LOCK_TO_STRIPE)) {
__u32 *stripe = val;
*vallen = sizeof(*stripe);
*stripe = 0;
- RETURN(0);
+ return 0;
} else if (KEY_IS(KEY_LAST_ID)) {
struct ptlrpc_request *req;
obd_id *reply;
@@ -3034,14 +2993,14 @@ static int osc_get_info(const struct lu_env *env, struct obd_export *exp,
req = ptlrpc_request_alloc(class_exp2cliimp(exp),
&RQF_OST_GET_INFO_LAST_ID);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req_capsule_set_size(&req->rq_pill, &RMF_SETINFO_KEY,
RCL_CLIENT, keylen);
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_GET_INFO);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
tmp = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_KEY);
@@ -3060,7 +3019,7 @@ static int osc_get_info(const struct lu_env *env, struct obd_export *exp,
*((obd_id *)val) = *reply;
out:
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
} else if (KEY_IS(KEY_FIEMAP)) {
struct ll_fiemap_info_key *fm_key =
(struct ll_fiemap_info_key *)key;
@@ -3142,10 +3101,10 @@ fini_req:
drop_lock:
if (mode)
ldlm_lock_decref(&lockh, LCK_PR);
- RETURN(rc);
+ return rc;
}
- RETURN(-EINVAL);
+ return -EINVAL;
}
static int osc_set_info_async(const struct lu_env *env, struct obd_export *exp,
@@ -3157,25 +3116,24 @@ static int osc_set_info_async(const struct lu_env *env, struct obd_export *exp,
struct obd_import *imp = class_exp2cliimp(exp);
char *tmp;
int rc;
- ENTRY;
OBD_FAIL_TIMEOUT(OBD_FAIL_OSC_SHUTDOWN, 10);
if (KEY_IS(KEY_CHECKSUM)) {
if (vallen != sizeof(int))
- RETURN(-EINVAL);
+ return -EINVAL;
exp->exp_obd->u.cli.cl_checksum = (*(int *)val) ? 1 : 0;
- RETURN(0);
+ return 0;
}
if (KEY_IS(KEY_SPTLRPC_CONF)) {
sptlrpc_conf_client_adapt(obd);
- RETURN(0);
+ return 0;
}
if (KEY_IS(KEY_FLUSH_CTX)) {
sptlrpc_import_flush_my_ctx(imp);
- RETURN(0);
+ return 0;
}
if (KEY_IS(KEY_CACHE_SET)) {
@@ -3192,7 +3150,7 @@ static int osc_set_info_async(const struct lu_env *env, struct obd_export *exp,
list_add(&cli->cl_lru_osc, &cli->cl_cache->ccc_lru);
spin_unlock(&cli->cl_cache->ccc_lru_lock);
- RETURN(0);
+ return 0;
}
if (KEY_IS(KEY_CACHE_LRU_SHRINK)) {
@@ -3202,11 +3160,11 @@ static int osc_set_info_async(const struct lu_env *env, struct obd_export *exp,
nr = osc_lru_shrink(cli, min(nr, target));
*(int *)val -= nr;
- RETURN(0);
+ return 0;
}
if (!set && !KEY_IS(KEY_GRANT_SHRINK))
- RETURN(-EINVAL);
+ return -EINVAL;
/* We pass all other commands directly to OST. Since nobody calls osc
methods directly and everybody is supposed to go through LOV, we
@@ -3219,7 +3177,7 @@ static int osc_set_info_async(const struct lu_env *env, struct obd_export *exp,
&RQF_OST_SET_GRANT_INFO :
&RQF_OBD_SET_INFO);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req_capsule_set_size(&req->rq_pill, &RMF_SETINFO_KEY,
RCL_CLIENT, keylen);
@@ -3229,7 +3187,7 @@ static int osc_set_info_async(const struct lu_env *env, struct obd_export *exp,
rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_SET_INFO);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
tmp = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_KEY);
@@ -3248,7 +3206,7 @@ static int osc_set_info_async(const struct lu_env *env, struct obd_export *exp,
OBDO_ALLOC(oa);
if (!oa) {
ptlrpc_req_finished(req);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
*oa = ((struct ost_body *)val)->oa;
aa->aa_oa = oa;
@@ -3263,7 +3221,7 @@ static int osc_set_info_async(const struct lu_env *env, struct obd_export *exp,
} else
ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1);
- RETURN(0);
+ return 0;
}
@@ -3280,8 +3238,6 @@ static int osc_llog_finish(struct obd_device *obd, int count)
{
struct llog_ctxt *ctxt;
- ENTRY;
-
ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT);
if (ctxt) {
llog_cat_close(NULL, ctxt->loc_handle);
@@ -3291,7 +3247,7 @@ static int osc_llog_finish(struct obd_device *obd, int count)
ctxt = llog_get_context(obd, LLOG_SIZE_REPL_CTXT);
if (ctxt)
llog_cleanup(NULL, ctxt);
- RETURN(0);
+ return 0;
}
static int osc_reconnect(const struct lu_env *env,
@@ -3317,7 +3273,7 @@ static int osc_reconnect(const struct lu_env *env,
data->ocd_version, data->ocd_grant, lost_grant);
}
- RETURN(0);
+ return 0;
}
static int osc_disconnect(struct obd_export *exp)
@@ -3369,7 +3325,6 @@ static int osc_import_event(struct obd_device *obd,
struct client_obd *cli;
int rc = 0;
- ENTRY;
LASSERT(imp->imp_obd == obd);
switch (event) {
@@ -3433,7 +3388,7 @@ static int osc_import_event(struct obd_device *obd,
CERROR("Unknown import event %d\n", event);
LBUG();
}
- RETURN(rc);
+ return rc;
}
/**
@@ -3457,9 +3412,9 @@ static int osc_cancel_for_recovery(struct ldlm_lock *lock)
(lock->l_granted_mode == LCK_PR ||
lock->l_granted_mode == LCK_CR) &&
(osc_dlm_lock_pageref(lock) == 0))
- RETURN(1);
+ return 1;
- RETURN(0);
+ return 0;
}
static int brw_queue_work(const struct lu_env *env, void *data)
@@ -3469,7 +3424,7 @@ static int brw_queue_work(const struct lu_env *env, void *data)
CDEBUG(D_CACHE, "Run writeback work for client obd %p.\n", cli);
osc_io_unplug(env, cli, NULL, PDL_POLICY_SAME);
- RETURN(0);
+ return 0;
}
int osc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
@@ -3478,11 +3433,10 @@ int osc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
struct client_obd *cli = &obd->u.cli;
void *handler;
int rc;
- ENTRY;
rc = ptlrpcd_addref();
if (rc)
- RETURN(rc);
+ return rc;
rc = client_obd_setup(obd, lcfg);
if (rc)
@@ -3517,7 +3471,7 @@ int osc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
INIT_LIST_HEAD(&cli->cl_grant_shrink_list);
ns_register_cancel(obd->obd_namespace, osc_cancel_for_recovery);
- RETURN(rc);
+ return rc;
out_ptlrpcd_work:
ptlrpcd_destroy_work(handler);
@@ -3525,13 +3479,12 @@ out_client_setup:
client_obd_cleanup(obd);
out_ptlrpcd:
ptlrpcd_decref();
- RETURN(rc);
+ return rc;
}
static int osc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
{
int rc = 0;
- ENTRY;
switch (stage) {
case OBD_CLEANUP_EARLY: {
@@ -3570,7 +3523,7 @@ static int osc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
break;
}
}
- RETURN(rc);
+ return rc;
}
int osc_cleanup(struct obd_device *obd)
@@ -3578,8 +3531,6 @@ int osc_cleanup(struct obd_device *obd)
struct client_obd *cli = &obd->u.cli;
int rc;
- ENTRY;
-
/* lru cleanup */
if (cli->cl_cache != NULL) {
LASSERT(atomic_read(&cli->cl_cache->ccc_users) > 0);
@@ -3597,7 +3548,7 @@ int osc_cleanup(struct obd_device *obd)
rc = client_obd_cleanup(obd);
ptlrpcd_decref();
- RETURN(rc);
+ return rc;
}
int osc_process_config_base(struct obd_device *obd, struct lustre_cfg *lcfg)
@@ -3671,7 +3622,6 @@ int __init osc_init(void)
{
struct lprocfs_static_vars lvars = { 0 };
int rc;
- ENTRY;
/* print an address of _any_ initialized kernel symbol from this
* module, to allow debugging with gdb that doesn't support data
@@ -3679,6 +3629,8 @@ int __init osc_init(void)
CDEBUG(D_INFO, "Lustre OSC module (%p).\n", &osc_caches);
rc = lu_kmem_init(osc_caches);
+ if (rc)
+ return rc;
lprocfs_osc_init_vars(&lvars);
@@ -3686,13 +3638,13 @@ int __init osc_init(void)
LUSTRE_OSC_NAME, &osc_device_type);
if (rc) {
lu_kmem_fini(osc_caches);
- RETURN(rc);
+ return rc;
}
spin_lock_init(&osc_ast_guard);
lockdep_set_class(&osc_ast_guard, &osc_ast_guard_class);
- RETURN(rc);
+ return rc;
}
static void /*__exit*/ osc_exit(void)
@@ -3704,5 +3656,7 @@ static void /*__exit*/ osc_exit(void)
MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Object Storage Client (OSC)");
MODULE_LICENSE("GPL");
+MODULE_VERSION(LUSTRE_VERSION_STRING);
-cfs_module(osc, LUSTRE_VERSION_STRING, osc_init, osc_exit);
+module_init(osc_init);
+module_exit(osc_exit);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/Makefile b/drivers/staging/lustre/lustre/ptlrpc/Makefile
index 983eb66a554..6d78b80487f 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/Makefile
+++ b/drivers/staging/lustre/lustre/ptlrpc/Makefile
@@ -16,6 +16,7 @@ ptlrpc_objs += sec.o sec_bulk.o sec_gc.o sec_config.o sec_lproc.o
ptlrpc_objs += sec_null.o sec_plain.o nrs.o nrs_fifo.o
ptlrpc-y := $(ldlm_objs) $(ptlrpc_objs)
+ptlrpc-$(CONFIG_LUSTRE_TRANSLATE_ERRNOS) += errno.o
obj-$(CONFIG_PTLRPC_GSS) += gss/
diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c
index 22f7e654c9d..810a458caed 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/client.c
@@ -137,11 +137,10 @@ struct ptlrpc_bulk_desc *ptlrpc_prep_bulk_imp(struct ptlrpc_request *req,
struct obd_import *imp = req->rq_import;
struct ptlrpc_bulk_desc *desc;
- ENTRY;
LASSERT(type == BULK_PUT_SINK || type == BULK_GET_SOURCE);
desc = ptlrpc_new_bulk(npages, max_brw, type, portal);
if (desc == NULL)
- RETURN(NULL);
+ return NULL;
desc->bd_import_generation = req->rq_import_generation;
desc->bd_import = class_import_get(imp);
@@ -187,7 +186,6 @@ EXPORT_SYMBOL(__ptlrpc_prep_bulk_page);
void __ptlrpc_free_bulk(struct ptlrpc_bulk_desc *desc, int unpin)
{
int i;
- ENTRY;
LASSERT(desc != NULL);
LASSERT(desc->bd_iov_count != LI_POISON); /* not freed already */
@@ -208,7 +206,6 @@ void __ptlrpc_free_bulk(struct ptlrpc_bulk_desc *desc, int unpin)
OBD_FREE(desc, offsetof(struct ptlrpc_bulk_desc,
bd_iov[desc->bd_max_iov]));
- EXIT;
}
EXPORT_SYMBOL(__ptlrpc_free_bulk);
@@ -336,7 +333,6 @@ static int ptlrpc_at_recv_early_reply(struct ptlrpc_request *req)
struct ptlrpc_request *early_req;
time_t olddl;
int rc;
- ENTRY;
req->rq_early = 0;
spin_unlock(&req->rq_lock);
@@ -344,7 +340,7 @@ static int ptlrpc_at_recv_early_reply(struct ptlrpc_request *req)
rc = sptlrpc_cli_unwrap_early_reply(req, &early_req);
if (rc) {
spin_lock(&req->rq_lock);
- RETURN(rc);
+ return rc;
}
rc = unpack_reply(early_req);
@@ -360,7 +356,7 @@ static int ptlrpc_at_recv_early_reply(struct ptlrpc_request *req)
if (rc != 0) {
spin_lock(&req->rq_lock);
- RETURN(rc);
+ return rc;
}
/* Adjust the local timeout for this req */
@@ -379,7 +375,7 @@ static int ptlrpc_at_recv_early_reply(struct ptlrpc_request *req)
cfs_time_sub(req->rq_deadline, cfs_time_current_sec()),
cfs_time_sub(req->rq_deadline, olddl));
- RETURN(rc);
+ return rc;
}
/**
@@ -547,7 +543,6 @@ static int __ptlrpc_request_bufs_pack(struct ptlrpc_request *request,
{
struct obd_import *imp = request->rq_import;
int rc;
- ENTRY;
if (unlikely(ctx))
request->rq_cli_ctx = sptlrpc_cli_ctx_get(ctx);
@@ -601,7 +596,7 @@ static int __ptlrpc_request_bufs_pack(struct ptlrpc_request *request,
lustre_msg_set_opc(request->rq_reqmsg, opcode);
- RETURN(0);
+ return 0;
out_ctx:
sptlrpc_cli_ctx_put(request->rq_cli_ctx, 1);
out_free:
@@ -822,10 +817,9 @@ struct ptlrpc_request_set *ptlrpc_prep_set(void)
{
struct ptlrpc_request_set *set;
- ENTRY;
OBD_ALLOC(set, sizeof *set);
if (!set)
- RETURN(NULL);
+ return NULL;
atomic_set(&set->set_refcount, 1);
INIT_LIST_HEAD(&set->set_requests);
init_waitqueue_head(&set->set_waitq);
@@ -839,7 +833,7 @@ struct ptlrpc_request_set *ptlrpc_prep_set(void)
set->set_producer_arg = NULL;
set->set_rc = 0;
- RETURN(set);
+ return set;
}
EXPORT_SYMBOL(ptlrpc_prep_set);
@@ -859,13 +853,13 @@ struct ptlrpc_request_set *ptlrpc_prep_fcset(int max, set_producer_func func,
set = ptlrpc_prep_set();
if (!set)
- RETURN(NULL);
+ return NULL;
set->set_max_inflight = max;
set->set_producer = func;
set->set_producer_arg = arg;
- RETURN(set);
+ return set;
}
EXPORT_SYMBOL(ptlrpc_prep_fcset);
@@ -883,7 +877,6 @@ void ptlrpc_set_destroy(struct ptlrpc_request_set *set)
struct list_head *next;
int expected_phase;
int n = 0;
- ENTRY;
/* Requests on the set should either all be completed, or all be new */
expected_phase = (atomic_read(&set->set_remaining) == 0) ?
@@ -925,7 +918,6 @@ void ptlrpc_set_destroy(struct ptlrpc_request_set *set)
LASSERT(atomic_read(&set->set_remaining) == 0);
ptlrpc_reqset_put(set);
- EXIT;
}
EXPORT_SYMBOL(ptlrpc_set_destroy);
@@ -941,13 +933,13 @@ int ptlrpc_set_add_cb(struct ptlrpc_request_set *set,
OBD_ALLOC_PTR(cbdata);
if (cbdata == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
cbdata->psc_interpret = fn;
cbdata->psc_data = data;
list_add_tail(&cbdata->psc_item, &set->set_cblist);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ptlrpc_set_add_cb);
@@ -1027,7 +1019,6 @@ static int ptlrpc_import_delay_req(struct obd_import *imp,
struct ptlrpc_request *req, int *status)
{
int delay = 0;
- ENTRY;
LASSERT (status != NULL);
*status = 0;
@@ -1078,7 +1069,7 @@ static int ptlrpc_import_delay_req(struct obd_import *imp,
}
}
- RETURN(delay);
+ return delay;
}
/**
@@ -1120,7 +1111,6 @@ static int ptlrpc_console_allow(struct ptlrpc_request *req)
static int ptlrpc_check_status(struct ptlrpc_request *req)
{
int err;
- ENTRY;
err = lustre_msg_get_status(req->rq_repmsg);
if (lustre_msg_get_type(req->rq_repmsg) == PTL_RPC_MSG_ERR) {
@@ -1133,7 +1123,7 @@ static int ptlrpc_check_status(struct ptlrpc_request *req)
libcfs_nid2str(
imp->imp_connection->c_peer.nid),
ll_opcode2str(opc), err);
- RETURN(err < 0 ? err : -EINVAL);
+ return err < 0 ? err : -EINVAL;
}
if (err < 0) {
@@ -1143,7 +1133,7 @@ static int ptlrpc_check_status(struct ptlrpc_request *req)
DEBUG_REQ(D_INFO, req, "status is %d", err);
}
- RETURN(err);
+ return err;
}
/**
@@ -1156,7 +1146,6 @@ static void ptlrpc_save_versions(struct ptlrpc_request *req)
struct lustre_msg *repmsg = req->rq_repmsg;
struct lustre_msg *reqmsg = req->rq_reqmsg;
__u64 *versions = lustre_msg_get_versions(repmsg);
- ENTRY;
if (lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY)
return;
@@ -1165,8 +1154,6 @@ static void ptlrpc_save_versions(struct ptlrpc_request *req)
lustre_msg_set_versions(reqmsg, versions);
CDEBUG(D_INFO, "Client save versions ["LPX64"/"LPX64"]\n",
versions[0], versions[1]);
-
- EXIT;
}
/**
@@ -1183,7 +1170,6 @@ static int after_reply(struct ptlrpc_request *req)
int rc;
struct timeval work_start;
long timediff;
- ENTRY;
LASSERT(obd != NULL);
/* repbuf must be unlinked */
@@ -1194,7 +1180,7 @@ static int after_reply(struct ptlrpc_request *req)
DEBUG_REQ(D_ERROR, req, "reply buffer overflow,"
" expected: %d, actual size: %d",
req->rq_nob_received, req->rq_repbuf_len);
- RETURN(-EOVERFLOW);
+ return -EOVERFLOW;
}
sptlrpc_cli_free_repbuf(req);
@@ -1205,7 +1191,7 @@ static int after_reply(struct ptlrpc_request *req)
req->rq_replen = req->rq_nob_received;
req->rq_nob_received = 0;
req->rq_resend = 1;
- RETURN(0);
+ return 0;
}
/*
@@ -1215,18 +1201,18 @@ static int after_reply(struct ptlrpc_request *req)
rc = sptlrpc_cli_unwrap_reply(req);
if (rc) {
DEBUG_REQ(D_ERROR, req, "unwrap reply failed (%d):", rc);
- RETURN(rc);
+ return rc;
}
/*
* Security layer unwrap might ask resend this request.
*/
if (req->rq_resend)
- RETURN(0);
+ return 0;
rc = unpack_reply(req);
if (rc)
- RETURN(rc);
+ return rc;
/* retry indefinitely on EINPROGRESS */
if (lustre_msg_get_status(req->rq_repmsg) == -EINPROGRESS &&
@@ -1257,7 +1243,7 @@ static int after_reply(struct ptlrpc_request *req)
else
req->rq_sent = now + req->rq_nr_resend;
- RETURN(0);
+ return 0;
}
do_gettimeofday(&work_start);
@@ -1272,7 +1258,7 @@ static int after_reply(struct ptlrpc_request *req)
lustre_msg_get_type(req->rq_repmsg) != PTL_RPC_MSG_ERR) {
DEBUG_REQ(D_ERROR, req, "invalid packet received (type=%u)",
lustre_msg_get_type(req->rq_repmsg));
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (lustre_msg_get_opc(req->rq_reqmsg) != OBD_PING)
@@ -1293,10 +1279,10 @@ static int after_reply(struct ptlrpc_request *req)
if (ll_rpc_recoverable_error(rc)) {
if (req->rq_send_state != LUSTRE_IMP_FULL ||
imp->imp_obd->obd_no_recov || imp->imp_dlm_fake) {
- RETURN(rc);
+ return rc;
}
ptlrpc_request_handle_notconn(req);
- RETURN(rc);
+ return rc;
}
} else {
/*
@@ -1360,7 +1346,7 @@ static int after_reply(struct ptlrpc_request *req)
spin_unlock(&imp->imp_lock);
}
- RETURN(rc);
+ return rc;
}
/**
@@ -1372,13 +1358,12 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req)
{
struct obd_import *imp = req->rq_import;
int rc;
- ENTRY;
LASSERT(req->rq_phase == RQ_PHASE_NEW);
if (req->rq_sent && (req->rq_sent > cfs_time_current_sec()) &&
(!req->rq_generation_set ||
req->rq_import_generation == imp->imp_generation))
- RETURN (0);
+ return 0;
ptlrpc_rqphase_move(req, RQ_PHASE_RPC);
@@ -1400,14 +1385,14 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req)
list_add_tail(&req->rq_list, &imp->imp_delayed_list);
atomic_inc(&req->rq_import->imp_inflight);
spin_unlock(&imp->imp_lock);
- RETURN(0);
+ return 0;
}
if (rc != 0) {
spin_unlock(&imp->imp_lock);
req->rq_status = rc;
ptlrpc_rqphase_move(req, RQ_PHASE_INTERPRET);
- RETURN(rc);
+ return rc;
}
LASSERT(list_empty(&req->rq_list));
@@ -1421,10 +1406,10 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req)
if (rc) {
if (req->rq_err) {
req->rq_status = rc;
- RETURN(1);
+ return 1;
} else {
req->rq_wait_ctx = 1;
- RETURN(0);
+ return 0;
}
}
@@ -1439,15 +1424,14 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req)
if (rc) {
DEBUG_REQ(D_HA, req, "send failed (%d); expect timeout", rc);
req->rq_net_err = 1;
- RETURN(rc);
+ return rc;
}
- RETURN(0);
+ return 0;
}
static inline int ptlrpc_set_producer(struct ptlrpc_request_set *set)
{
int remaining, rc;
- ENTRY;
LASSERT(set->set_producer != NULL);
@@ -1461,11 +1445,11 @@ static inline int ptlrpc_set_producer(struct ptlrpc_request_set *set)
/* no more RPC to produce */
set->set_producer = NULL;
set->set_producer_arg = NULL;
- RETURN(0);
+ return 0;
}
}
- RETURN((atomic_read(&set->set_remaining) - remaining));
+ return (atomic_read(&set->set_remaining) - remaining);
}
/**
@@ -1478,10 +1462,9 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
{
struct list_head *tmp, *next;
int force_timer_recalc = 0;
- ENTRY;
if (atomic_read(&set->set_remaining) == 0)
- RETURN(1);
+ return 1;
list_for_each_safe(tmp, next, &set->set_requests) {
struct ptlrpc_request *req =
@@ -1834,7 +1817,7 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
}
/* If we hit an error, we want to recover promptly. */
- RETURN(atomic_read(&set->set_remaining) == 0 || force_timer_recalc);
+ return atomic_read(&set->set_remaining) == 0 || force_timer_recalc;
}
EXPORT_SYMBOL(ptlrpc_check_set);
@@ -1847,7 +1830,6 @@ int ptlrpc_expire_one_request(struct ptlrpc_request *req, int async_unlink)
{
struct obd_import *imp = req->rq_import;
int rc = 0;
- ENTRY;
spin_lock(&req->rq_lock);
req->rq_timedout = 1;
@@ -1873,14 +1855,14 @@ int ptlrpc_expire_one_request(struct ptlrpc_request *req, int async_unlink)
if (imp == NULL) {
DEBUG_REQ(D_HA, req, "NULL import: already cleaned up?");
- RETURN(1);
+ return 1;
}
atomic_inc(&imp->imp_timeouts);
/* The DLM server doesn't want recovery run on its imports. */
if (imp->imp_dlm_fake)
- RETURN(1);
+ return 1;
/* If this request is for recovery or other primordial tasks,
* then error it out here. */
@@ -1894,7 +1876,7 @@ int ptlrpc_expire_one_request(struct ptlrpc_request *req, int async_unlink)
req->rq_status = -ETIMEDOUT;
req->rq_err = 1;
spin_unlock(&req->rq_lock);
- RETURN(1);
+ return 1;
}
/* if a request can't be resent we can't wait for an answer after
@@ -1906,7 +1888,7 @@ int ptlrpc_expire_one_request(struct ptlrpc_request *req, int async_unlink)
ptlrpc_fail_import(imp, lustre_msg_get_conn_cnt(req->rq_reqmsg));
- RETURN(rc);
+ return rc;
}
/**
@@ -1919,7 +1901,6 @@ int ptlrpc_expired_set(void *data)
struct ptlrpc_request_set *set = data;
struct list_head *tmp;
time_t now = cfs_time_current_sec();
- ENTRY;
LASSERT(set != NULL);
@@ -1955,7 +1936,7 @@ int ptlrpc_expired_set(void *data)
* sleep so we can recalculate the timeout, or enable interrupts
* if everyone's timed out.
*/
- RETURN(1);
+ return 1;
}
EXPORT_SYMBOL(ptlrpc_expired_set);
@@ -2006,7 +1987,6 @@ int ptlrpc_set_next_timeout(struct ptlrpc_request_set *set)
int timeout = 0;
struct ptlrpc_request *req;
int deadline;
- ENTRY;
SIGNAL_MASK_ASSERT(); /* XXX BUG 1511 */
@@ -2045,7 +2025,7 @@ int ptlrpc_set_next_timeout(struct ptlrpc_request_set *set)
else if (timeout == 0 || timeout > deadline - now)
timeout = deadline - now;
}
- RETURN(timeout);
+ return timeout;
}
EXPORT_SYMBOL(ptlrpc_set_next_timeout);
@@ -2061,7 +2041,6 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
struct ptlrpc_request *req;
struct l_wait_info lwi;
int rc, timeout;
- ENTRY;
if (set->set_producer)
(void)ptlrpc_set_producer(set);
@@ -2074,7 +2053,7 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
}
if (list_empty(&set->set_requests))
- RETURN(0);
+ return 0;
do {
timeout = ptlrpc_set_next_timeout(set);
@@ -2171,7 +2150,7 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
}
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_set_wait);
@@ -2185,9 +2164,7 @@ EXPORT_SYMBOL(ptlrpc_set_wait);
*/
static void __ptlrpc_free_req(struct ptlrpc_request *request, int locked)
{
- ENTRY;
if (request == NULL) {
- EXIT;
return;
}
@@ -2240,7 +2217,6 @@ static void __ptlrpc_free_req(struct ptlrpc_request *request, int locked)
__ptlrpc_free_req_to_pool(request);
else
OBD_FREE(request, sizeof(*request));
- EXIT;
}
static int __ptlrpc_req_finished(struct ptlrpc_request *request, int locked);
@@ -2263,15 +2239,14 @@ EXPORT_SYMBOL(ptlrpc_req_finished_with_imp_lock);
*/
static int __ptlrpc_req_finished(struct ptlrpc_request *request, int locked)
{
- ENTRY;
if (request == NULL)
- RETURN(1);
+ return 1;
if (request == LP_POISON ||
request->rq_reqmsg == LP_POISON) {
CERROR("dereferencing freed request (bug 575)\n");
LBUG();
- RETURN(1);
+ return 1;
}
DEBUG_REQ(D_INFO, request, "refcount now %u",
@@ -2279,10 +2254,10 @@ static int __ptlrpc_req_finished(struct ptlrpc_request *request, int locked)
if (atomic_dec_and_test(&request->rq_refcount)) {
__ptlrpc_free_req(request, locked);
- RETURN(1);
+ return 1;
}
- RETURN(0);
+ return 0;
}
/**
@@ -2332,7 +2307,7 @@ int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
* Nothing left to do.
*/
if (!ptlrpc_client_recv_or_unlink(request))
- RETURN(1);
+ return 1;
LNetMDUnlink(request->rq_reply_md_h);
@@ -2340,7 +2315,7 @@ int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
* Let's check it once again.
*/
if (!ptlrpc_client_recv_or_unlink(request))
- RETURN(1);
+ return 1;
/*
* Move to "Unregistering" phase as reply was not unlinked yet.
@@ -2351,7 +2326,7 @@ int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
* Do not wait for unlink to finish.
*/
if (async)
- RETURN(0);
+ return 0;
/*
* We have to l_wait_event() whatever the result, to give liblustre
@@ -2372,7 +2347,7 @@ int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
&lwi);
if (rc == 0) {
ptlrpc_rqphase_move(request, request->rq_next_phase);
- RETURN(1);
+ return 1;
}
LASSERT(rc == -ETIMEDOUT);
@@ -2380,7 +2355,7 @@ int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
"rvcng=%d unlnk=%d", request->rq_receiving_reply,
request->rq_must_unlink);
}
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ptlrpc_unregister_reply);
@@ -2397,7 +2372,6 @@ void ptlrpc_free_committed(struct obd_import *imp)
struct list_head *tmp, *saved;
struct ptlrpc_request *req;
struct ptlrpc_request *last_req = NULL; /* temporary fire escape */
- ENTRY;
LASSERT(imp != NULL);
@@ -2408,7 +2382,6 @@ void ptlrpc_free_committed(struct obd_import *imp)
imp->imp_generation == imp->imp_last_generation_checked) {
CDEBUG(D_INFO, "%s: skip recheck: last_committed "LPU64"\n",
imp->imp_obd->obd_name, imp->imp_peer_committed_transno);
- EXIT;
return;
}
CDEBUG(D_RPCTRACE, "%s: committing for last_committed "LPU64" gen %d\n",
@@ -2456,16 +2429,10 @@ free_req:
list_del_init(&req->rq_replay_list);
__ptlrpc_req_finished(req, 1);
}
-
- EXIT;
- return;
}
void ptlrpc_cleanup_client(struct obd_import *imp)
{
- ENTRY;
- EXIT;
- return;
}
EXPORT_SYMBOL(ptlrpc_cleanup_client);
@@ -2517,9 +2484,8 @@ EXPORT_SYMBOL(ptlrpc_restart_req);
*/
struct ptlrpc_request *ptlrpc_request_addref(struct ptlrpc_request *req)
{
- ENTRY;
atomic_inc(&req->rq_refcount);
- RETURN(req);
+ return req;
}
EXPORT_SYMBOL(ptlrpc_request_addref);
@@ -2588,7 +2554,6 @@ int ptlrpc_queue_wait(struct ptlrpc_request *req)
{
struct ptlrpc_request_set *set;
int rc;
- ENTRY;
LASSERT(req->rq_set == NULL);
LASSERT(!req->rq_receiving_reply);
@@ -2596,7 +2561,7 @@ int ptlrpc_queue_wait(struct ptlrpc_request *req)
set = ptlrpc_prep_set();
if (set == NULL) {
CERROR("Unable to allocate ptlrpc set.");
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
/* for distributed debugging */
@@ -2608,7 +2573,7 @@ int ptlrpc_queue_wait(struct ptlrpc_request *req)
rc = ptlrpc_set_wait(set);
ptlrpc_set_destroy(set);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_queue_wait);
@@ -2629,7 +2594,6 @@ static int ptlrpc_replay_interpret(const struct lu_env *env,
struct ptlrpc_replay_async_args *aa = data;
struct obd_import *imp = req->rq_import;
- ENTRY;
atomic_dec(&imp->imp_replay_inflight);
if (!ptlrpc_client_replied(req)) {
@@ -2710,7 +2674,7 @@ static int ptlrpc_replay_interpret(const struct lu_env *env,
/* this replay failed, so restart recovery */
ptlrpc_connect_import(imp);
- RETURN(rc);
+ return rc;
}
/**
@@ -2721,7 +2685,6 @@ static int ptlrpc_replay_interpret(const struct lu_env *env,
int ptlrpc_replay_req(struct ptlrpc_request *req)
{
struct ptlrpc_replay_async_args *aa;
- ENTRY;
LASSERT(req->rq_import->imp_state == LUSTRE_IMP_REPLAY);
@@ -2751,7 +2714,7 @@ int ptlrpc_replay_req(struct ptlrpc_request *req)
ptlrpc_request_addref(req); /* ptlrpcd needs a ref */
ptlrpcd_add_req(req, PDL_POLICY_LOCAL, -1);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ptlrpc_replay_req);
@@ -2761,7 +2724,6 @@ EXPORT_SYMBOL(ptlrpc_replay_req);
void ptlrpc_abort_inflight(struct obd_import *imp)
{
struct list_head *tmp, *n;
- ENTRY;
/* Make sure that no new requests get processed for this import.
* ptlrpc_{queue,set}_wait must (and does) hold imp_lock while testing
@@ -2809,8 +2771,6 @@ void ptlrpc_abort_inflight(struct obd_import *imp)
ptlrpc_free_committed(imp);
spin_unlock(&imp->imp_lock);
-
- EXIT;
}
EXPORT_SYMBOL(ptlrpc_abort_inflight);
@@ -2969,18 +2929,17 @@ void *ptlrpcd_alloc_work(struct obd_import *imp,
{
struct ptlrpc_request *req = NULL;
struct ptlrpc_work_async_args *args;
- ENTRY;
might_sleep();
if (cb == NULL)
- RETURN(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
/* copy some code from deprecated fakereq. */
OBD_ALLOC_PTR(req);
if (req == NULL) {
CERROR("ptlrpc: run out of memory!\n");
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
}
req->rq_send_state = LUSTRE_IMP_FULL;
@@ -3009,7 +2968,7 @@ void *ptlrpcd_alloc_work(struct obd_import *imp,
args->cb = cb;
args->cbdata = cbdata;
- RETURN(req);
+ return req;
}
EXPORT_SYMBOL(ptlrpcd_alloc_work);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/connection.c b/drivers/staging/lustre/lustre/ptlrpc/connection.c
index a0757f372be..17ca8420887 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/connection.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/connection.c
@@ -49,7 +49,6 @@ ptlrpc_connection_get(lnet_process_id_t peer, lnet_nid_t self,
struct obd_uuid *uuid)
{
struct ptlrpc_connection *conn, *conn2;
- ENTRY;
conn = cfs_hash_lookup(conn_hash, &peer);
if (conn)
@@ -57,7 +56,7 @@ ptlrpc_connection_get(lnet_process_id_t peer, lnet_nid_t self,
OBD_ALLOC_PTR(conn);
if (!conn)
- RETURN(NULL);
+ return NULL;
conn->c_peer = peer;
conn->c_self = self;
@@ -80,7 +79,6 @@ ptlrpc_connection_get(lnet_process_id_t peer, lnet_nid_t self,
OBD_FREE_PTR(conn);
conn = conn2;
}
- EXIT;
out:
CDEBUG(D_INFO, "conn=%p refcount %d to %s\n",
conn, atomic_read(&conn->c_refcount),
@@ -92,10 +90,9 @@ EXPORT_SYMBOL(ptlrpc_connection_get);
int ptlrpc_connection_put(struct ptlrpc_connection *conn)
{
int rc = 0;
- ENTRY;
if (!conn)
- RETURN(rc);
+ return rc;
LASSERT(atomic_read(&conn->c_refcount) > 1);
@@ -122,28 +119,24 @@ int ptlrpc_connection_put(struct ptlrpc_connection *conn)
conn, atomic_read(&conn->c_refcount),
libcfs_nid2str(conn->c_peer.nid));
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_connection_put);
struct ptlrpc_connection *
ptlrpc_connection_addref(struct ptlrpc_connection *conn)
{
- ENTRY;
-
atomic_inc(&conn->c_refcount);
CDEBUG(D_INFO, "conn=%p refcount %d to %s\n",
conn, atomic_read(&conn->c_refcount),
libcfs_nid2str(conn->c_peer.nid));
- RETURN(conn);
+ return conn;
}
EXPORT_SYMBOL(ptlrpc_connection_addref);
int ptlrpc_connection_init(void)
{
- ENTRY;
-
conn_hash = cfs_hash_create("CONN_HASH",
HASH_CONN_CUR_BITS,
HASH_CONN_MAX_BITS,
@@ -152,16 +145,15 @@ int ptlrpc_connection_init(void)
CFS_HASH_MAX_THETA,
&conn_hash_ops, CFS_HASH_DEFAULT);
if (!conn_hash)
- RETURN(-ENOMEM);
+ return -ENOMEM;
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ptlrpc_connection_init);
-void ptlrpc_connection_fini(void) {
- ENTRY;
+void ptlrpc_connection_fini(void)
+{
cfs_hash_putref(conn_hash);
- EXIT;
}
EXPORT_SYMBOL(ptlrpc_connection_fini);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/errno.c b/drivers/staging/lustre/lustre/ptlrpc/errno.c
new file mode 100644
index 00000000000..1c100633396
--- /dev/null
+++ b/drivers/staging/lustre/lustre/ptlrpc/errno.c
@@ -0,0 +1,380 @@
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.txt
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (C) 2011 FUJITSU LIMITED. All rights reserved.
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ */
+
+#include <linux/libcfs/libcfs.h>
+#include <lustre/lustre_errno.h>
+
+/*
+ * The two translation tables below must define a one-to-one mapping between
+ * host and network errnos.
+ *
+ * EWOULDBLOCK is equal to EAGAIN on all architectures except for parisc, which
+ * appears irrelevant. Thus, existing references to EWOULDBLOCK are fine.
+ *
+ * EDEADLOCK is equal to EDEADLK on x86 but not on sparc, at least. A sparc
+ * host has no context-free way to determine if a LUSTRE_EDEADLK represents an
+ * EDEADLK or an EDEADLOCK. Therefore, all existing references to EDEADLOCK
+ * that need to be transferred on wire have been replaced with EDEADLK.
+ */
+static int lustre_errno_hton_mapping[] = {
+ [EPERM] = LUSTRE_EPERM,
+ [ENOENT] = LUSTRE_ENOENT,
+ [ESRCH] = LUSTRE_ESRCH,
+ [EINTR] = LUSTRE_EINTR,
+ [EIO] = LUSTRE_EIO,
+ [ENXIO] = LUSTRE_ENXIO,
+ [E2BIG] = LUSTRE_E2BIG,
+ [ENOEXEC] = LUSTRE_ENOEXEC,
+ [EBADF] = LUSTRE_EBADF,
+ [ECHILD] = LUSTRE_ECHILD,
+ [EAGAIN] = LUSTRE_EAGAIN,
+ [ENOMEM] = LUSTRE_ENOMEM,
+ [EACCES] = LUSTRE_EACCES,
+ [EFAULT] = LUSTRE_EFAULT,
+ [ENOTBLK] = LUSTRE_ENOTBLK,
+ [EBUSY] = LUSTRE_EBUSY,
+ [EEXIST] = LUSTRE_EEXIST,
+ [EXDEV] = LUSTRE_EXDEV,
+ [ENODEV] = LUSTRE_ENODEV,
+ [ENOTDIR] = LUSTRE_ENOTDIR,
+ [EISDIR] = LUSTRE_EISDIR,
+ [EINVAL] = LUSTRE_EINVAL,
+ [ENFILE] = LUSTRE_ENFILE,
+ [EMFILE] = LUSTRE_EMFILE,
+ [ENOTTY] = LUSTRE_ENOTTY,
+ [ETXTBSY] = LUSTRE_ETXTBSY,
+ [EFBIG] = LUSTRE_EFBIG,
+ [ENOSPC] = LUSTRE_ENOSPC,
+ [ESPIPE] = LUSTRE_ESPIPE,
+ [EROFS] = LUSTRE_EROFS,
+ [EMLINK] = LUSTRE_EMLINK,
+ [EPIPE] = LUSTRE_EPIPE,
+ [EDOM] = LUSTRE_EDOM,
+ [ERANGE] = LUSTRE_ERANGE,
+ [EDEADLK] = LUSTRE_EDEADLK,
+ [ENAMETOOLONG] = LUSTRE_ENAMETOOLONG,
+ [ENOLCK] = LUSTRE_ENOLCK,
+ [ENOSYS] = LUSTRE_ENOSYS,
+ [ENOTEMPTY] = LUSTRE_ENOTEMPTY,
+ [ELOOP] = LUSTRE_ELOOP,
+ [ENOMSG] = LUSTRE_ENOMSG,
+ [EIDRM] = LUSTRE_EIDRM,
+ [ECHRNG] = LUSTRE_ECHRNG,
+ [EL2NSYNC] = LUSTRE_EL2NSYNC,
+ [EL3HLT] = LUSTRE_EL3HLT,
+ [EL3RST] = LUSTRE_EL3RST,
+ [ELNRNG] = LUSTRE_ELNRNG,
+ [EUNATCH] = LUSTRE_EUNATCH,
+ [ENOCSI] = LUSTRE_ENOCSI,
+ [EL2HLT] = LUSTRE_EL2HLT,
+ [EBADE] = LUSTRE_EBADE,
+ [EBADR] = LUSTRE_EBADR,
+ [EXFULL] = LUSTRE_EXFULL,
+ [ENOANO] = LUSTRE_ENOANO,
+ [EBADRQC] = LUSTRE_EBADRQC,
+ [EBADSLT] = LUSTRE_EBADSLT,
+ [EBFONT] = LUSTRE_EBFONT,
+ [ENOSTR] = LUSTRE_ENOSTR,
+ [ENODATA] = LUSTRE_ENODATA,
+ [ETIME] = LUSTRE_ETIME,
+ [ENOSR] = LUSTRE_ENOSR,
+ [ENONET] = LUSTRE_ENONET,
+ [ENOPKG] = LUSTRE_ENOPKG,
+ [EREMOTE] = LUSTRE_EREMOTE,
+ [ENOLINK] = LUSTRE_ENOLINK,
+ [EADV] = LUSTRE_EADV,
+ [ESRMNT] = LUSTRE_ESRMNT,
+ [ECOMM] = LUSTRE_ECOMM,
+ [EPROTO] = LUSTRE_EPROTO,
+ [EMULTIHOP] = LUSTRE_EMULTIHOP,
+ [EDOTDOT] = LUSTRE_EDOTDOT,
+ [EBADMSG] = LUSTRE_EBADMSG,
+ [EOVERFLOW] = LUSTRE_EOVERFLOW,
+ [ENOTUNIQ] = LUSTRE_ENOTUNIQ,
+ [EBADFD] = LUSTRE_EBADFD,
+ [EREMCHG] = LUSTRE_EREMCHG,
+ [ELIBACC] = LUSTRE_ELIBACC,
+ [ELIBBAD] = LUSTRE_ELIBBAD,
+ [ELIBSCN] = LUSTRE_ELIBSCN,
+ [ELIBMAX] = LUSTRE_ELIBMAX,
+ [ELIBEXEC] = LUSTRE_ELIBEXEC,
+ [EILSEQ] = LUSTRE_EILSEQ,
+ [ERESTART] = LUSTRE_ERESTART,
+ [ESTRPIPE] = LUSTRE_ESTRPIPE,
+ [EUSERS] = LUSTRE_EUSERS,
+ [ENOTSOCK] = LUSTRE_ENOTSOCK,
+ [EDESTADDRREQ] = LUSTRE_EDESTADDRREQ,
+ [EMSGSIZE] = LUSTRE_EMSGSIZE,
+ [EPROTOTYPE] = LUSTRE_EPROTOTYPE,
+ [ENOPROTOOPT] = LUSTRE_ENOPROTOOPT,
+ [EPROTONOSUPPORT] = LUSTRE_EPROTONOSUPPORT,
+ [ESOCKTNOSUPPORT] = LUSTRE_ESOCKTNOSUPPORT,
+ [EOPNOTSUPP] = LUSTRE_EOPNOTSUPP,
+ [EPFNOSUPPORT] = LUSTRE_EPFNOSUPPORT,
+ [EAFNOSUPPORT] = LUSTRE_EAFNOSUPPORT,
+ [EADDRINUSE] = LUSTRE_EADDRINUSE,
+ [EADDRNOTAVAIL] = LUSTRE_EADDRNOTAVAIL,
+ [ENETDOWN] = LUSTRE_ENETDOWN,
+ [ENETUNREACH] = LUSTRE_ENETUNREACH,
+ [ENETRESET] = LUSTRE_ENETRESET,
+ [ECONNABORTED] = LUSTRE_ECONNABORTED,
+ [ECONNRESET] = LUSTRE_ECONNRESET,
+ [ENOBUFS] = LUSTRE_ENOBUFS,
+ [EISCONN] = LUSTRE_EISCONN,
+ [ENOTCONN] = LUSTRE_ENOTCONN,
+ [ESHUTDOWN] = LUSTRE_ESHUTDOWN,
+ [ETOOMANYREFS] = LUSTRE_ETOOMANYREFS,
+ [ETIMEDOUT] = LUSTRE_ETIMEDOUT,
+ [ECONNREFUSED] = LUSTRE_ECONNREFUSED,
+ [EHOSTDOWN] = LUSTRE_EHOSTDOWN,
+ [EHOSTUNREACH] = LUSTRE_EHOSTUNREACH,
+ [EALREADY] = LUSTRE_EALREADY,
+ [EINPROGRESS] = LUSTRE_EINPROGRESS,
+ [ESTALE] = LUSTRE_ESTALE,
+ [EUCLEAN] = LUSTRE_EUCLEAN,
+ [ENOTNAM] = LUSTRE_ENOTNAM,
+ [ENAVAIL] = LUSTRE_ENAVAIL,
+ [EISNAM] = LUSTRE_EISNAM,
+ [EREMOTEIO] = LUSTRE_EREMOTEIO,
+ [EDQUOT] = LUSTRE_EDQUOT,
+ [ENOMEDIUM] = LUSTRE_ENOMEDIUM,
+ [EMEDIUMTYPE] = LUSTRE_EMEDIUMTYPE,
+ [ECANCELED] = LUSTRE_ECANCELED,
+ [ENOKEY] = LUSTRE_ENOKEY,
+ [EKEYEXPIRED] = LUSTRE_EKEYEXPIRED,
+ [EKEYREVOKED] = LUSTRE_EKEYREVOKED,
+ [EKEYREJECTED] = LUSTRE_EKEYREJECTED,
+ [EOWNERDEAD] = LUSTRE_EOWNERDEAD,
+ [ENOTRECOVERABLE] = LUSTRE_ENOTRECOVERABLE,
+ [ERESTARTSYS] = LUSTRE_ERESTARTSYS,
+ [ERESTARTNOINTR] = LUSTRE_ERESTARTNOINTR,
+ [ERESTARTNOHAND] = LUSTRE_ERESTARTNOHAND,
+ [ENOIOCTLCMD] = LUSTRE_ENOIOCTLCMD,
+ [ERESTART_RESTARTBLOCK] = LUSTRE_ERESTART_RESTARTBLOCK,
+ [EBADHANDLE] = LUSTRE_EBADHANDLE,
+ [ENOTSYNC] = LUSTRE_ENOTSYNC,
+ [EBADCOOKIE] = LUSTRE_EBADCOOKIE,
+ [ENOTSUPP] = LUSTRE_ENOTSUPP,
+ [ETOOSMALL] = LUSTRE_ETOOSMALL,
+ [ESERVERFAULT] = LUSTRE_ESERVERFAULT,
+ [EBADTYPE] = LUSTRE_EBADTYPE,
+ [EJUKEBOX] = LUSTRE_EJUKEBOX,
+ [EIOCBQUEUED] = LUSTRE_EIOCBQUEUED,
+};
+
+static int lustre_errno_ntoh_mapping[] = {
+ [LUSTRE_EPERM] = EPERM,
+ [LUSTRE_ENOENT] = ENOENT,
+ [LUSTRE_ESRCH] = ESRCH,
+ [LUSTRE_EINTR] = EINTR,
+ [LUSTRE_EIO] = EIO,
+ [LUSTRE_ENXIO] = ENXIO,
+ [LUSTRE_E2BIG] = E2BIG,
+ [LUSTRE_ENOEXEC] = ENOEXEC,
+ [LUSTRE_EBADF] = EBADF,
+ [LUSTRE_ECHILD] = ECHILD,
+ [LUSTRE_EAGAIN] = EAGAIN,
+ [LUSTRE_ENOMEM] = ENOMEM,
+ [LUSTRE_EACCES] = EACCES,
+ [LUSTRE_EFAULT] = EFAULT,
+ [LUSTRE_ENOTBLK] = ENOTBLK,
+ [LUSTRE_EBUSY] = EBUSY,
+ [LUSTRE_EEXIST] = EEXIST,
+ [LUSTRE_EXDEV] = EXDEV,
+ [LUSTRE_ENODEV] = ENODEV,
+ [LUSTRE_ENOTDIR] = ENOTDIR,
+ [LUSTRE_EISDIR] = EISDIR,
+ [LUSTRE_EINVAL] = EINVAL,
+ [LUSTRE_ENFILE] = ENFILE,
+ [LUSTRE_EMFILE] = EMFILE,
+ [LUSTRE_ENOTTY] = ENOTTY,
+ [LUSTRE_ETXTBSY] = ETXTBSY,
+ [LUSTRE_EFBIG] = EFBIG,
+ [LUSTRE_ENOSPC] = ENOSPC,
+ [LUSTRE_ESPIPE] = ESPIPE,
+ [LUSTRE_EROFS] = EROFS,
+ [LUSTRE_EMLINK] = EMLINK,
+ [LUSTRE_EPIPE] = EPIPE,
+ [LUSTRE_EDOM] = EDOM,
+ [LUSTRE_ERANGE] = ERANGE,
+ [LUSTRE_EDEADLK] = EDEADLK,
+ [LUSTRE_ENAMETOOLONG] = ENAMETOOLONG,
+ [LUSTRE_ENOLCK] = ENOLCK,
+ [LUSTRE_ENOSYS] = ENOSYS,
+ [LUSTRE_ENOTEMPTY] = ENOTEMPTY,
+ [LUSTRE_ELOOP] = ELOOP,
+ [LUSTRE_ENOMSG] = ENOMSG,
+ [LUSTRE_EIDRM] = EIDRM,
+ [LUSTRE_ECHRNG] = ECHRNG,
+ [LUSTRE_EL2NSYNC] = EL2NSYNC,
+ [LUSTRE_EL3HLT] = EL3HLT,
+ [LUSTRE_EL3RST] = EL3RST,
+ [LUSTRE_ELNRNG] = ELNRNG,
+ [LUSTRE_EUNATCH] = EUNATCH,
+ [LUSTRE_ENOCSI] = ENOCSI,
+ [LUSTRE_EL2HLT] = EL2HLT,
+ [LUSTRE_EBADE] = EBADE,
+ [LUSTRE_EBADR] = EBADR,
+ [LUSTRE_EXFULL] = EXFULL,
+ [LUSTRE_ENOANO] = ENOANO,
+ [LUSTRE_EBADRQC] = EBADRQC,
+ [LUSTRE_EBADSLT] = EBADSLT,
+ [LUSTRE_EBFONT] = EBFONT,
+ [LUSTRE_ENOSTR] = ENOSTR,
+ [LUSTRE_ENODATA] = ENODATA,
+ [LUSTRE_ETIME] = ETIME,
+ [LUSTRE_ENOSR] = ENOSR,
+ [LUSTRE_ENONET] = ENONET,
+ [LUSTRE_ENOPKG] = ENOPKG,
+ [LUSTRE_EREMOTE] = EREMOTE,
+ [LUSTRE_ENOLINK] = ENOLINK,
+ [LUSTRE_EADV] = EADV,
+ [LUSTRE_ESRMNT] = ESRMNT,
+ [LUSTRE_ECOMM] = ECOMM,
+ [LUSTRE_EPROTO] = EPROTO,
+ [LUSTRE_EMULTIHOP] = EMULTIHOP,
+ [LUSTRE_EDOTDOT] = EDOTDOT,
+ [LUSTRE_EBADMSG] = EBADMSG,
+ [LUSTRE_EOVERFLOW] = EOVERFLOW,
+ [LUSTRE_ENOTUNIQ] = ENOTUNIQ,
+ [LUSTRE_EBADFD] = EBADFD,
+ [LUSTRE_EREMCHG] = EREMCHG,
+ [LUSTRE_ELIBACC] = ELIBACC,
+ [LUSTRE_ELIBBAD] = ELIBBAD,
+ [LUSTRE_ELIBSCN] = ELIBSCN,
+ [LUSTRE_ELIBMAX] = ELIBMAX,
+ [LUSTRE_ELIBEXEC] = ELIBEXEC,
+ [LUSTRE_EILSEQ] = EILSEQ,
+ [LUSTRE_ERESTART] = ERESTART,
+ [LUSTRE_ESTRPIPE] = ESTRPIPE,
+ [LUSTRE_EUSERS] = EUSERS,
+ [LUSTRE_ENOTSOCK] = ENOTSOCK,
+ [LUSTRE_EDESTADDRREQ] = EDESTADDRREQ,
+ [LUSTRE_EMSGSIZE] = EMSGSIZE,
+ [LUSTRE_EPROTOTYPE] = EPROTOTYPE,
+ [LUSTRE_ENOPROTOOPT] = ENOPROTOOPT,
+ [LUSTRE_EPROTONOSUPPORT] = EPROTONOSUPPORT,
+ [LUSTRE_ESOCKTNOSUPPORT] = ESOCKTNOSUPPORT,
+ [LUSTRE_EOPNOTSUPP] = EOPNOTSUPP,
+ [LUSTRE_EPFNOSUPPORT] = EPFNOSUPPORT,
+ [LUSTRE_EAFNOSUPPORT] = EAFNOSUPPORT,
+ [LUSTRE_EADDRINUSE] = EADDRINUSE,
+ [LUSTRE_EADDRNOTAVAIL] = EADDRNOTAVAIL,
+ [LUSTRE_ENETDOWN] = ENETDOWN,
+ [LUSTRE_ENETUNREACH] = ENETUNREACH,
+ [LUSTRE_ENETRESET] = ENETRESET,
+ [LUSTRE_ECONNABORTED] = ECONNABORTED,
+ [LUSTRE_ECONNRESET] = ECONNRESET,
+ [LUSTRE_ENOBUFS] = ENOBUFS,
+ [LUSTRE_EISCONN] = EISCONN,
+ [LUSTRE_ENOTCONN] = ENOTCONN,
+ [LUSTRE_ESHUTDOWN] = ESHUTDOWN,
+ [LUSTRE_ETOOMANYREFS] = ETOOMANYREFS,
+ [LUSTRE_ETIMEDOUT] = ETIMEDOUT,
+ [LUSTRE_ECONNREFUSED] = ECONNREFUSED,
+ [LUSTRE_EHOSTDOWN] = EHOSTDOWN,
+ [LUSTRE_EHOSTUNREACH] = EHOSTUNREACH,
+ [LUSTRE_EALREADY] = EALREADY,
+ [LUSTRE_EINPROGRESS] = EINPROGRESS,
+ [LUSTRE_ESTALE] = ESTALE,
+ [LUSTRE_EUCLEAN] = EUCLEAN,
+ [LUSTRE_ENOTNAM] = ENOTNAM,
+ [LUSTRE_ENAVAIL] = ENAVAIL,
+ [LUSTRE_EISNAM] = EISNAM,
+ [LUSTRE_EREMOTEIO] = EREMOTEIO,
+ [LUSTRE_EDQUOT] = EDQUOT,
+ [LUSTRE_ENOMEDIUM] = ENOMEDIUM,
+ [LUSTRE_EMEDIUMTYPE] = EMEDIUMTYPE,
+ [LUSTRE_ECANCELED] = ECANCELED,
+ [LUSTRE_ENOKEY] = ENOKEY,
+ [LUSTRE_EKEYEXPIRED] = EKEYEXPIRED,
+ [LUSTRE_EKEYREVOKED] = EKEYREVOKED,
+ [LUSTRE_EKEYREJECTED] = EKEYREJECTED,
+ [LUSTRE_EOWNERDEAD] = EOWNERDEAD,
+ [LUSTRE_ENOTRECOVERABLE] = ENOTRECOVERABLE,
+ [LUSTRE_ERESTARTSYS] = ERESTARTSYS,
+ [LUSTRE_ERESTARTNOINTR] = ERESTARTNOINTR,
+ [LUSTRE_ERESTARTNOHAND] = ERESTARTNOHAND,
+ [LUSTRE_ENOIOCTLCMD] = ENOIOCTLCMD,
+ [LUSTRE_ERESTART_RESTARTBLOCK] = ERESTART_RESTARTBLOCK,
+ [LUSTRE_EBADHANDLE] = EBADHANDLE,
+ [LUSTRE_ENOTSYNC] = ENOTSYNC,
+ [LUSTRE_EBADCOOKIE] = EBADCOOKIE,
+ [LUSTRE_ENOTSUPP] = ENOTSUPP,
+ [LUSTRE_ETOOSMALL] = ETOOSMALL,
+ [LUSTRE_ESERVERFAULT] = ESERVERFAULT,
+ [LUSTRE_EBADTYPE] = EBADTYPE,
+ [LUSTRE_EJUKEBOX] = EJUKEBOX,
+ [LUSTRE_EIOCBQUEUED] = EIOCBQUEUED,
+};
+
+unsigned int lustre_errno_hton(unsigned int h)
+{
+ unsigned int n;
+
+ if (h == 0) {
+ n = 0;
+ } else if (h < ARRAY_SIZE(lustre_errno_hton_mapping)) {
+ n = lustre_errno_hton_mapping[h];
+ if (n == 0)
+ goto generic;
+ } else {
+generic:
+ /*
+ * A generic errno is better than the unknown one that could
+ * mean anything to a different host.
+ */
+ n = LUSTRE_EIO;
+ }
+
+ return n;
+}
+EXPORT_SYMBOL(lustre_errno_hton);
+
+unsigned int lustre_errno_ntoh(unsigned int n)
+{
+ unsigned int h;
+
+ if (n == 0) {
+ h = 0;
+ } else if (n < ARRAY_SIZE(lustre_errno_ntoh_mapping)) {
+ h = lustre_errno_ntoh_mapping[n];
+ if (h == 0)
+ goto generic;
+ } else {
+generic:
+ /*
+ * Similar to the situation in lustre_errno_hton(), an unknown
+ * network errno could coincide with anything. Hence, it is
+ * better to return a generic errno.
+ */
+ h = EIO;
+ }
+
+ return h;
+}
+EXPORT_SYMBOL(lustre_errno_ntoh);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c
index 0264c102cb3..58d089c3fef 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/events.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/events.c
@@ -55,7 +55,6 @@ void request_out_callback(lnet_event_t *ev)
{
struct ptlrpc_cb_id *cbid = ev->md.user_ptr;
struct ptlrpc_request *req = cbid->cbid_arg;
- ENTRY;
LASSERT (ev->type == LNET_EVENT_SEND ||
ev->type == LNET_EVENT_UNLINK);
@@ -79,8 +78,6 @@ void request_out_callback(lnet_event_t *ev)
}
ptlrpc_req_finished(req);
-
- EXIT;
}
/*
@@ -90,7 +87,6 @@ void reply_in_callback(lnet_event_t *ev)
{
struct ptlrpc_cb_id *cbid = ev->md.user_ptr;
struct ptlrpc_request *req = cbid->cbid_arg;
- ENTRY;
DEBUG_REQ(D_NET, req, "type %d, status %d", ev->type, ev->status);
@@ -166,7 +162,6 @@ out_wake:
* since we don't have our own ref */
ptlrpc_client_wake_req(req);
spin_unlock(&req->rq_lock);
- EXIT;
}
/*
@@ -177,7 +172,6 @@ void client_bulk_callback (lnet_event_t *ev)
struct ptlrpc_cb_id *cbid = ev->md.user_ptr;
struct ptlrpc_bulk_desc *desc = cbid->cbid_arg;
struct ptlrpc_request *req;
- ENTRY;
LASSERT ((desc->bd_type == BULK_PUT_SINK &&
ev->type == LNET_EVENT_PUT) ||
@@ -220,7 +214,6 @@ void client_bulk_callback (lnet_event_t *ev)
ptlrpc_client_wake_req(desc->bd_req);
spin_unlock(&desc->bd_lock);
- EXIT;
}
/*
@@ -289,7 +282,6 @@ void request_in_callback(lnet_event_t *ev)
struct ptlrpc_service_part *svcpt = rqbd->rqbd_svcpt;
struct ptlrpc_service *service = svcpt->scp_service;
struct ptlrpc_request *req;
- ENTRY;
LASSERT (ev->type == LNET_EVENT_PUT ||
ev->type == LNET_EVENT_UNLINK);
@@ -378,7 +370,6 @@ void request_in_callback(lnet_event_t *ev)
wake_up(&svcpt->scp_waitq);
spin_unlock(&svcpt->scp_lock);
- EXIT;
}
/*
@@ -389,7 +380,6 @@ void reply_out_callback(lnet_event_t *ev)
struct ptlrpc_cb_id *cbid = ev->md.user_ptr;
struct ptlrpc_reply_state *rs = cbid->cbid_arg;
struct ptlrpc_service_part *svcpt = rs->rs_svcpt;
- ENTRY;
LASSERT (ev->type == LNET_EVENT_SEND ||
ev->type == LNET_EVENT_ACK ||
@@ -400,7 +390,6 @@ void reply_out_callback(lnet_event_t *ev)
* net's ref on 'rs' */
LASSERT (ev->unlinked);
ptlrpc_rs_decref(rs);
- EXIT;
return;
}
@@ -421,7 +410,6 @@ void reply_out_callback(lnet_event_t *ev)
spin_unlock(&rs->rs_lock);
spin_unlock(&svcpt->scp_rep_lock);
}
- EXIT;
}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_api.h b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_api.h
index feac60482c9..0e9f6c472a3 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_api.h
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_api.h
@@ -100,7 +100,7 @@ struct subflavor_desc {
/* Each mechanism is described by the following struct: */
struct gss_api_mech {
struct list_head gm_list;
- module_t *gm_owner;
+ struct module *gm_owner;
char *gm_name;
rawobj_t gm_oid;
atomic_t gm_count;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c
index ed95bbba95c..b518d8a0aab 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c
@@ -68,7 +68,6 @@ int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx,
__u32 maj;
int offset;
int rc;
- ENTRY;
LASSERT(req->rq_pack_bulk);
LASSERT(req->rq_bulk_read || req->rq_bulk_write);
@@ -104,7 +103,7 @@ int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx,
bsd->bsd_svc = SPTLRPC_FLVR_BULK_SVC(req->rq_flvr.sf_rpc);
if (bsd->bsd_svc == SPTLRPC_BULK_SVC_NULL)
- RETURN(0);
+ return 0;
LASSERT(bsd->bsd_svc == SPTLRPC_BULK_SVC_INTG ||
bsd->bsd_svc == SPTLRPC_BULK_SVC_PRIV);
@@ -132,18 +131,18 @@ int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx,
&token);
if (maj != GSS_S_COMPLETE) {
CWARN("failed to sign bulk data: %x\n", maj);
- RETURN(-EACCES);
+ return -EACCES;
}
} else {
/* privacy mode */
if (desc->bd_iov_count == 0)
- RETURN(0);
+ return 0;
rc = sptlrpc_enc_pool_get_pages(desc);
if (rc) {
CERROR("bulk write: failed to allocate "
"encryption pages: %d\n", rc);
- RETURN(rc);
+ return rc;
}
token.data = bsd->bsd_data;
@@ -153,12 +152,12 @@ int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx,
maj = lgss_wrap_bulk(gctx->gc_mechctx, desc, &token, 0);
if (maj != GSS_S_COMPLETE) {
CWARN("fail to encrypt bulk data: %x\n", maj);
- RETURN(-EACCES);
+ return -EACCES;
}
}
}
- RETURN(0);
+ return 0;
}
int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx,
@@ -171,7 +170,6 @@ int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx,
rawobj_t token;
__u32 maj;
int roff, voff;
- ENTRY;
LASSERT(req->rq_pack_bulk);
LASSERT(req->rq_bulk_read || req->rq_bulk_write);
@@ -220,7 +218,7 @@ int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx,
"(%u,%u,%u) != (%u,%u,%u)\n",
bsdr->bsd_version, bsdr->bsd_type, bsdr->bsd_svc,
bsdv->bsd_version, bsdv->bsd_type, bsdv->bsd_svc);
- RETURN(-EPROTO);
+ return -EPROTO;
}
LASSERT(bsdv->bsd_svc == SPTLRPC_BULK_SVC_NULL ||
@@ -235,7 +233,7 @@ int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx,
if (req->rq_bulk_write) {
if (bsdv->bsd_flags & BSD_FL_ERR) {
CERROR("server reported bulk i/o failure\n");
- RETURN(-EIO);
+ return -EIO;
}
if (bsdv->bsd_svc == SPTLRPC_BULK_SVC_PRIV)
@@ -270,12 +268,12 @@ int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx,
&token);
if (maj != GSS_S_COMPLETE) {
CERROR("failed to verify bulk read: %x\n", maj);
- RETURN(-EACCES);
+ return -EACCES;
}
} else if (bsdv->bsd_svc == SPTLRPC_BULK_SVC_PRIV) {
desc->bd_nob = bsdv->bsd_nob;
if (desc->bd_nob == 0)
- RETURN(0);
+ return 0;
token.data = bsdv->bsd_data;
token.len = lustre_msg_buflen(vmsg, voff) -
@@ -286,14 +284,14 @@ int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx,
if (maj != GSS_S_COMPLETE) {
CERROR("failed to decrypt bulk read: %x\n",
maj);
- RETURN(-EACCES);
+ return -EACCES;
}
desc->bd_nob_transferred = desc->bd_nob;
}
}
- RETURN(0);
+ return 0;
}
static int gss_prep_bulk(struct ptlrpc_bulk_desc *desc,
@@ -318,21 +316,20 @@ int gss_cli_prep_bulk(struct ptlrpc_request *req,
struct ptlrpc_bulk_desc *desc)
{
int rc;
- ENTRY;
LASSERT(req->rq_cli_ctx);
LASSERT(req->rq_pack_bulk);
LASSERT(req->rq_bulk_read);
if (SPTLRPC_FLVR_BULK_SVC(req->rq_flvr.sf_rpc) != SPTLRPC_BULK_SVC_PRIV)
- RETURN(0);
+ return 0;
rc = gss_prep_bulk(desc, ctx2gctx(req->rq_cli_ctx)->gc_mechctx);
if (rc)
CERROR("bulk read: failed to prepare encryption "
"pages: %d\n", rc);
- RETURN(rc);
+ return rc;
}
int gss_svc_prep_bulk(struct ptlrpc_request *req,
@@ -341,7 +338,6 @@ int gss_svc_prep_bulk(struct ptlrpc_request *req,
struct gss_svc_reqctx *grctx;
struct ptlrpc_bulk_sec_desc *bsd;
int rc;
- ENTRY;
LASSERT(req->rq_svc_ctx);
LASSERT(req->rq_pack_bulk);
@@ -355,14 +351,14 @@ int gss_svc_prep_bulk(struct ptlrpc_request *req,
bsd = grctx->src_reqbsd;
if (bsd->bsd_svc != SPTLRPC_BULK_SVC_PRIV)
- RETURN(0);
+ return 0;
rc = gss_prep_bulk(desc, grctx->src_ctx->gsc_mechctx);
if (rc)
CERROR("bulk write: failed to prepare encryption "
"pages: %d\n", rc);
- RETURN(rc);
+ return rc;
}
int gss_svc_unwrap_bulk(struct ptlrpc_request *req,
@@ -372,7 +368,6 @@ int gss_svc_unwrap_bulk(struct ptlrpc_request *req,
struct ptlrpc_bulk_sec_desc *bsdr, *bsdv;
rawobj_t token;
__u32 maj;
- ENTRY;
LASSERT(req->rq_svc_ctx);
LASSERT(req->rq_pack_bulk);
@@ -404,7 +399,7 @@ int gss_svc_unwrap_bulk(struct ptlrpc_request *req,
if (maj != GSS_S_COMPLETE) {
bsdv->bsd_flags |= BSD_FL_ERR;
CERROR("failed to verify bulk signature: %x\n", maj);
- RETURN(-EACCES);
+ return -EACCES;
}
break;
case SPTLRPC_BULK_SVC_PRIV:
@@ -412,7 +407,7 @@ int gss_svc_unwrap_bulk(struct ptlrpc_request *req,
bsdv->bsd_flags |= BSD_FL_ERR;
CERROR("prepared nob %d doesn't match the actual "
"nob %d\n", desc->bd_nob, bsdr->bsd_nob);
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (desc->bd_iov_count == 0) {
@@ -428,12 +423,12 @@ int gss_svc_unwrap_bulk(struct ptlrpc_request *req,
if (maj != GSS_S_COMPLETE) {
bsdv->bsd_flags |= BSD_FL_ERR;
CERROR("failed decrypt bulk data: %x\n", maj);
- RETURN(-EACCES);
+ return -EACCES;
}
break;
}
- RETURN(0);
+ return 0;
}
int gss_svc_wrap_bulk(struct ptlrpc_request *req,
@@ -444,7 +439,6 @@ int gss_svc_wrap_bulk(struct ptlrpc_request *req,
rawobj_t token;
__u32 maj;
int rc;
- ENTRY;
LASSERT(req->rq_svc_ctx);
LASSERT(req->rq_pack_bulk);
@@ -476,7 +470,7 @@ int gss_svc_wrap_bulk(struct ptlrpc_request *req,
if (maj != GSS_S_COMPLETE) {
bsdv->bsd_flags |= BSD_FL_ERR;
CERROR("failed to sign bulk data: %x\n", maj);
- RETURN(-EACCES);
+ return -EACCES;
}
break;
case SPTLRPC_BULK_SVC_PRIV:
@@ -492,7 +486,7 @@ int gss_svc_wrap_bulk(struct ptlrpc_request *req,
bsdv->bsd_flags |= BSD_FL_ERR;
CERROR("bulk read: failed to allocate encryption "
"pages: %d\n", rc);
- RETURN(rc);
+ return rc;
}
token.data = bsdv->bsd_data;
@@ -503,10 +497,10 @@ int gss_svc_wrap_bulk(struct ptlrpc_request *req,
if (maj != GSS_S_COMPLETE) {
bsdv->bsd_flags |= BSD_FL_ERR;
CERROR("failed to encrypt bulk data: %x\n", maj);
- RETURN(-EACCES);
+ return -EACCES;
}
break;
}
- RETURN(0);
+ return 0;
}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c
index 142c789b1bc..55247af3910 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c
@@ -243,41 +243,41 @@ int gss_do_ctx_init_rpc(__user char *buffer, unsigned long count)
if (count != sizeof(param)) {
CERROR("ioctl size %lu, expect %lu, please check lgss_keyring "
"version\n", count, (unsigned long) sizeof(param));
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (copy_from_user(&param, buffer, sizeof(param))) {
CERROR("failed copy data from lgssd\n");
- RETURN(-EFAULT);
+ return -EFAULT;
}
if (param.version != GSSD_INTERFACE_VERSION) {
CERROR("gssd interface version %d (expect %d)\n",
param.version, GSSD_INTERFACE_VERSION);
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* take name */
if (strncpy_from_user(obdname, param.uuid, sizeof(obdname)) <= 0) {
CERROR("Invalid obdname pointer\n");
- RETURN(-EFAULT);
+ return -EFAULT;
}
obd = class_name2obd(obdname);
if (!obd) {
CERROR("no such obd %s\n", obdname);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (unlikely(!obd->obd_set_up)) {
CERROR("obd %s not setup\n", obdname);
- RETURN(-EINVAL);
+ return -EINVAL;
}
spin_lock(&obd->obd_dev_lock);
if (obd->obd_stopping) {
CERROR("obd %s has stopped\n", obdname);
spin_unlock(&obd->obd_dev_lock);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
@@ -285,7 +285,7 @@ int gss_do_ctx_init_rpc(__user char *buffer, unsigned long count)
strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME)) {
CERROR("obd %s is not a client device\n", obdname);
spin_unlock(&obd->obd_dev_lock);
- RETURN(-EINVAL);
+ return -EINVAL;
}
spin_unlock(&obd->obd_dev_lock);
@@ -293,7 +293,7 @@ int gss_do_ctx_init_rpc(__user char *buffer, unsigned long count)
if (obd->u.cli.cl_import == NULL) {
CERROR("obd %s: import has gone\n", obd->obd_name);
up_read(&obd->u.cli.cl_sem);
- RETURN(-EINVAL);
+ return -EINVAL;
}
imp = class_import_get(obd->u.cli.cl_import);
up_read(&obd->u.cli.cl_sem);
@@ -301,7 +301,7 @@ int gss_do_ctx_init_rpc(__user char *buffer, unsigned long count)
if (imp->imp_deactive) {
CERROR("import has been deactivated\n");
class_import_put(imp);
- RETURN(-EINVAL);
+ return -EINVAL;
}
req = ptlrpc_request_alloc_pack(imp, &RQF_SEC_CTX, LUSTRE_OBD_VERSION,
@@ -368,7 +368,7 @@ out_copy:
class_import_put(imp);
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx)
@@ -378,7 +378,6 @@ int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx)
struct ptlrpc_request *req;
struct ptlrpc_user_desc *pud;
int rc;
- ENTRY;
LASSERT(atomic_read(&ctx->cc_refcount) > 0);
@@ -386,7 +385,7 @@ int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx)
CDEBUG(D_SEC, "ctx %p(%u->%s) not uptodate, "
"don't send destroy rpc\n", ctx,
ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
- RETURN(0);
+ return 0;
}
might_sleep();
@@ -434,7 +433,7 @@ int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx)
out_ref:
ptlrpc_req_finished(req);
out:
- RETURN(rc);
+ return rc;
}
int __init gss_init_cli_upcall(void)
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c
index bb571ae5105..188dbbfbd2f 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c
@@ -524,7 +524,6 @@ void rvs_sec_install_root_ctx_kr(struct ptlrpc_sec *sec,
struct gss_sec_keyring *gsec_kr = sec2gsec_keyring(sec);
struct ptlrpc_cli_ctx *ctx;
cfs_time_t now;
- ENTRY;
LASSERT(sec_is_reverse(sec));
@@ -569,11 +568,10 @@ struct ptlrpc_sec * gss_sec_create_kr(struct obd_import *imp,
struct sptlrpc_flavor *sf)
{
struct gss_sec_keyring *gsec_kr;
- ENTRY;
OBD_ALLOC(gsec_kr, sizeof(*gsec_kr));
if (gsec_kr == NULL)
- RETURN(NULL);
+ return NULL;
INIT_HLIST_HEAD(&gsec_kr->gsk_clist);
gsec_kr->gsk_root_ctx = NULL;
@@ -592,11 +590,11 @@ struct ptlrpc_sec * gss_sec_create_kr(struct obd_import *imp,
goto err_free;
}
- RETURN(&gsec_kr->gsk_base.gs_base);
+ return &gsec_kr->gsk_base.gs_base;
err_free:
OBD_FREE(gsec_kr, sizeof(*gsec_kr));
- RETURN(NULL);
+ return NULL;
}
static
@@ -683,7 +681,6 @@ struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_kr(struct ptlrpc_sec *sec,
char *coinfo;
int coinfo_size;
char *co_flags = "";
- ENTRY;
LASSERT(imp != NULL);
@@ -697,7 +694,7 @@ struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_kr(struct ptlrpc_sec *sec,
* always succeed.
*/
if (ctx || sec_is_reverse(sec))
- RETURN(ctx);
+ return ctx;
}
LASSERT(create != 0);
@@ -821,7 +818,7 @@ struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_kr(struct ptlrpc_sec *sec,
out:
if (is_root)
mutex_unlock(&gsec_kr->gsk_root_uc_lock);
- RETURN(ctx);
+ return ctx;
}
static
@@ -891,7 +888,6 @@ void flush_spec_ctx_cache_kr(struct ptlrpc_sec *sec,
struct hlist_head freelist = HLIST_HEAD_INIT;
struct hlist_node *next;
struct ptlrpc_cli_ctx *ctx;
- ENTRY;
gsec_kr = sec2gsec_keyring(sec);
@@ -930,15 +926,12 @@ void flush_spec_ctx_cache_kr(struct ptlrpc_sec *sec,
spin_unlock(&sec->ps_lock);
dispose_ctx_list_kr(&freelist);
- EXIT;
}
static
int gss_sec_flush_ctx_cache_kr(struct ptlrpc_sec *sec,
uid_t uid, int grace, int force)
{
- ENTRY;
-
CDEBUG(D_SEC, "sec %p(%d, nctx %d), uid %d, grace %d, force %d\n",
sec, atomic_read(&sec->ps_refcount),
atomic_read(&sec->ps_nctx),
@@ -949,7 +942,7 @@ int gss_sec_flush_ctx_cache_kr(struct ptlrpc_sec *sec,
else
flush_spec_ctx_cache_kr(sec, uid, grace, force);
- RETURN(0);
+ return 0;
}
static
@@ -959,7 +952,6 @@ void gss_sec_gc_ctx_kr(struct ptlrpc_sec *sec)
struct hlist_head freelist = HLIST_HEAD_INIT;
struct hlist_node *next;
struct ptlrpc_cli_ctx *ctx;
- ENTRY;
CWARN("running gc\n");
@@ -981,8 +973,6 @@ void gss_sec_gc_ctx_kr(struct ptlrpc_sec *sec)
spin_unlock(&sec->ps_lock);
dispose_ctx_list_kr(&freelist);
- EXIT;
- return;
}
static
@@ -993,7 +983,6 @@ int gss_sec_display_kr(struct ptlrpc_sec *sec, struct seq_file *seq)
struct ptlrpc_cli_ctx *ctx;
struct gss_cli_ctx *gctx;
time_t now = cfs_time_current_sec();
- ENTRY;
spin_lock(&sec->ps_lock);
hlist_for_each_entry_safe(ctx, next,
@@ -1032,7 +1021,7 @@ int gss_sec_display_kr(struct ptlrpc_sec *sec, struct seq_file *seq)
}
spin_unlock(&sec->ps_lock);
- RETURN(0);
+ return 0;
}
/****************************************
@@ -1148,16 +1137,15 @@ static
int gss_kt_instantiate(struct key *key, const void *data, size_t datalen)
{
int rc;
- ENTRY;
if (data != NULL || datalen != 0) {
CERROR("invalid: data %p, len %lu\n", data, (long)datalen);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (key->payload.data != 0) {
CERROR("key already have payload\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* link the key to session keyring, so following context negotiation
@@ -1179,11 +1167,11 @@ int gss_kt_instantiate(struct key *key, const void *data, size_t datalen)
CERROR("failed to link key %08x to keyring %08x: %d\n",
key->serial,
key_tgcred(current)->session_keyring->serial, rc);
- RETURN(rc);
+ return rc;
}
CDEBUG(D_SEC, "key %p instantiated, ctx %p\n", key, key->payload.data);
- RETURN(0);
+ return 0;
}
/*
@@ -1198,11 +1186,10 @@ int gss_kt_update(struct key *key, const void *data, size_t datalen)
rawobj_t tmpobj = RAWOBJ_EMPTY;
__u32 datalen32 = (__u32) datalen;
int rc;
- ENTRY;
if (data == NULL || datalen == 0) {
CWARN("invalid: data %p, len %lu\n", data, (long)datalen);
- RETURN(-EINVAL);
+ return -EINVAL;
}
/* if upcall finished negotiation too fast (mostly likely because
@@ -1216,9 +1203,9 @@ int gss_kt_update(struct key *key, const void *data, size_t datalen)
rc = key_validate(key);
if (rc == 0)
- RETURN(-EAGAIN);
+ return -EAGAIN;
else
- RETURN(rc);
+ return rc;
}
LASSERT(atomic_read(&ctx->cc_refcount) > 0);
@@ -1229,7 +1216,7 @@ int gss_kt_update(struct key *key, const void *data, size_t datalen)
/* don't proceed if already refreshed */
if (cli_ctx_is_refreshed(ctx)) {
CWARN("ctx already done refresh\n");
- RETURN(0);
+ return 0;
}
sptlrpc_cli_ctx_get(ctx);
@@ -1304,7 +1291,7 @@ out:
/* let user space think it's a success */
sptlrpc_cli_ctx_put(ctx, 1);
- RETURN(0);
+ return 0;
}
static
@@ -1316,10 +1303,8 @@ int gss_kt_match(const struct key *key, const void *desc)
static
void gss_kt_destroy(struct key *key)
{
- ENTRY;
LASSERT(key->payload.data == NULL);
CDEBUG(D_SEC, "destroy key %p\n", key);
- EXIT;
}
static
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c
index 4b28931bbc9..c106a9e049a 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c
@@ -54,6 +54,7 @@
#include <linux/slab.h>
#include <linux/crypto.h>
#include <linux/mutex.h>
+#include <linux/crypto.h>
#include <obd.h>
#include <obd_class.h>
@@ -147,14 +148,14 @@ static const char * enctype2str(__u32 enctype)
static
int keyblock_init(struct krb5_keyblock *kb, char *alg_name, int alg_mode)
{
- kb->kb_tfm = ll_crypto_alloc_blkcipher(alg_name, alg_mode, 0);
+ kb->kb_tfm = crypto_alloc_blkcipher(alg_name, alg_mode, 0);
if (IS_ERR(kb->kb_tfm)) {
CERROR("failed to alloc tfm: %s, mode %d\n",
alg_name, alg_mode);
return -1;
}
- if (ll_crypto_blkcipher_setkey(kb->kb_tfm, kb->kb_key.data, kb->kb_key.len)) {
+ if (crypto_blkcipher_setkey(kb->kb_tfm, kb->kb_key.data, kb->kb_key.len)) {
CERROR("failed to set %s key, len %d\n",
alg_name, kb->kb_key.len);
return -1;
@@ -197,7 +198,7 @@ void keyblock_free(struct krb5_keyblock *kb)
{
rawobj_free(&kb->kb_key);
if (kb->kb_tfm)
- ll_crypto_free_blkcipher(kb->kb_tfm);
+ crypto_free_blkcipher(kb->kb_tfm);
}
static
@@ -341,7 +342,7 @@ __u32 import_context_rfc1964(struct krb5_ctx *kctx, char *p, char *end)
if (p != end)
goto out_err;
- CDEBUG(D_SEC, "succesfully imported rfc1964 context\n");
+ CDEBUG(D_SEC, "successfully imported rfc1964 context\n");
return 0;
out_err:
return GSS_S_FAILURE;
@@ -403,7 +404,7 @@ __u32 import_context_rfc4121(struct krb5_ctx *kctx, char *p, char *end)
if (get_keyblock(&p, end, &kctx->kc_keyc, keysize))
goto out_err;
- CDEBUG(D_SEC, "succesfully imported v2 context\n");
+ CDEBUG(D_SEC, "successfully imported v2 context\n");
return 0;
out_err:
return GSS_S_FAILURE;
@@ -494,7 +495,7 @@ __u32 gss_copy_reverse_context_kerberos(struct gss_ctx *gctx,
goto out_err;
gctx_new->internal_ctx_id = knew;
- CDEBUG(D_SEC, "succesfully copied reverse context\n");
+ CDEBUG(D_SEC, "successfully copied reverse context\n");
return GSS_S_COMPLETE;
out_err:
@@ -529,7 +530,7 @@ void buf_to_sg(struct scatterlist *sg, void *ptr, int len)
}
static
-__u32 krb5_encrypt(struct ll_crypto_cipher *tfm,
+__u32 krb5_encrypt(struct crypto_blkcipher *tfm,
int decrypt,
void * iv,
void * in,
@@ -546,27 +547,27 @@ __u32 krb5_encrypt(struct ll_crypto_cipher *tfm,
desc.info = local_iv;
desc.flags= 0;
- if (length % ll_crypto_blkcipher_blocksize(tfm) != 0) {
+ if (length % crypto_blkcipher_blocksize(tfm) != 0) {
CERROR("output length %d mismatch blocksize %d\n",
- length, ll_crypto_blkcipher_blocksize(tfm));
+ length, crypto_blkcipher_blocksize(tfm));
goto out;
}
- if (ll_crypto_blkcipher_ivsize(tfm) > 16) {
- CERROR("iv size too large %d\n", ll_crypto_blkcipher_ivsize(tfm));
+ if (crypto_blkcipher_ivsize(tfm) > 16) {
+ CERROR("iv size too large %d\n", crypto_blkcipher_ivsize(tfm));
goto out;
}
if (iv)
- memcpy(local_iv, iv, ll_crypto_blkcipher_ivsize(tfm));
+ memcpy(local_iv, iv, crypto_blkcipher_ivsize(tfm));
memcpy(out, in, length);
buf_to_sg(&sg, out, length);
if (decrypt)
- ret = ll_crypto_blkcipher_decrypt_iv(&desc, &sg, &sg, length);
+ ret = crypto_blkcipher_decrypt_iv(&desc, &sg, &sg, length);
else
- ret = ll_crypto_blkcipher_encrypt_iv(&desc, &sg, &sg, length);
+ ret = crypto_blkcipher_encrypt_iv(&desc, &sg, &sg, length);
out:
return(ret);
@@ -574,7 +575,7 @@ out:
static inline
-int krb5_digest_hmac(struct ll_crypto_hash *tfm,
+int krb5_digest_hmac(struct crypto_hash *tfm,
rawobj_t *key,
struct krb5_header *khdr,
int msgcnt, rawobj_t *msgs,
@@ -585,17 +586,17 @@ int krb5_digest_hmac(struct ll_crypto_hash *tfm,
struct scatterlist sg[1];
int i;
- ll_crypto_hash_setkey(tfm, key->data, key->len);
+ crypto_hash_setkey(tfm, key->data, key->len);
desc.tfm = tfm;
desc.flags= 0;
- ll_crypto_hash_init(&desc);
+ crypto_hash_init(&desc);
for (i = 0; i < msgcnt; i++) {
if (msgs[i].len == 0)
continue;
buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
- ll_crypto_hash_update(&desc, sg, msgs[i].len);
+ crypto_hash_update(&desc, sg, msgs[i].len);
}
for (i = 0; i < iovcnt; i++) {
@@ -604,20 +605,20 @@ int krb5_digest_hmac(struct ll_crypto_hash *tfm,
sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
iovs[i].kiov_offset);
- ll_crypto_hash_update(&desc, sg, iovs[i].kiov_len);
+ crypto_hash_update(&desc, sg, iovs[i].kiov_len);
}
if (khdr) {
buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
- ll_crypto_hash_update(&desc, sg, sizeof(*khdr));
+ crypto_hash_update(&desc, sg, sizeof(*khdr));
}
- return ll_crypto_hash_final(&desc, cksum->data);
+ return crypto_hash_final(&desc, cksum->data);
}
static inline
-int krb5_digest_norm(struct ll_crypto_hash *tfm,
+int krb5_digest_norm(struct crypto_hash *tfm,
struct krb5_keyblock *kb,
struct krb5_header *khdr,
int msgcnt, rawobj_t *msgs,
@@ -632,13 +633,13 @@ int krb5_digest_norm(struct ll_crypto_hash *tfm,
desc.tfm = tfm;
desc.flags= 0;
- ll_crypto_hash_init(&desc);
+ crypto_hash_init(&desc);
for (i = 0; i < msgcnt; i++) {
if (msgs[i].len == 0)
continue;
buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
- ll_crypto_hash_update(&desc, sg, msgs[i].len);
+ crypto_hash_update(&desc, sg, msgs[i].len);
}
for (i = 0; i < iovcnt; i++) {
@@ -647,15 +648,15 @@ int krb5_digest_norm(struct ll_crypto_hash *tfm,
sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
iovs[i].kiov_offset);
- ll_crypto_hash_update(&desc, sg, iovs[i].kiov_len);
+ crypto_hash_update(&desc, sg, iovs[i].kiov_len);
}
if (khdr) {
buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
- ll_crypto_hash_update(&desc, sg, sizeof(*khdr));
+ crypto_hash_update(&desc, sg, sizeof(*khdr));
}
- ll_crypto_hash_final(&desc, cksum->data);
+ crypto_hash_final(&desc, cksum->data);
return krb5_encrypt(kb->kb_tfm, 0, NULL, cksum->data,
cksum->data, cksum->len);
@@ -674,7 +675,7 @@ __s32 krb5_make_checksum(__u32 enctype,
rawobj_t *cksum)
{
struct krb5_enctype *ke = &enctypes[enctype];
- struct ll_crypto_hash *tfm;
+ struct crypto_hash *tfm;
__u32 code = GSS_S_FAILURE;
int rc;
@@ -683,7 +684,7 @@ __s32 krb5_make_checksum(__u32 enctype,
return GSS_S_FAILURE;
}
- cksum->len = ll_crypto_hash_digestsize(tfm);
+ cksum->len = crypto_hash_digestsize(tfm);
OBD_ALLOC_LARGE(cksum->data, cksum->len);
if (!cksum->data) {
cksum->len = 0;
@@ -700,7 +701,7 @@ __s32 krb5_make_checksum(__u32 enctype,
if (rc == 0)
code = GSS_S_COMPLETE;
out_tfm:
- ll_crypto_free_hash(tfm);
+ crypto_free_hash(tfm);
return code;
}
@@ -878,7 +879,7 @@ int add_padding(rawobj_t *msg, int msg_buflen, int blocksize)
}
static
-int krb5_encrypt_rawobjs(struct ll_crypto_cipher *tfm,
+int krb5_encrypt_rawobjs(struct crypto_blkcipher *tfm,
int mode_ecb,
int inobj_cnt,
rawobj_t *inobjs,
@@ -890,7 +891,6 @@ int krb5_encrypt_rawobjs(struct ll_crypto_cipher *tfm,
__u8 local_iv[16] = {0}, *buf;
__u32 datalen = 0;
int i, rc;
- ENTRY;
buf = outobj->data;
desc.tfm = tfm;
@@ -905,23 +905,23 @@ int krb5_encrypt_rawobjs(struct ll_crypto_cipher *tfm,
if (mode_ecb) {
if (enc)
- rc = ll_crypto_blkcipher_encrypt(
+ rc = crypto_blkcipher_encrypt(
&desc, &dst, &src, src.length);
else
- rc = ll_crypto_blkcipher_decrypt(
+ rc = crypto_blkcipher_decrypt(
&desc, &dst, &src, src.length);
} else {
if (enc)
- rc = ll_crypto_blkcipher_encrypt_iv(
+ rc = crypto_blkcipher_encrypt_iv(
&desc, &dst, &src, src.length);
else
- rc = ll_crypto_blkcipher_decrypt_iv(
+ rc = crypto_blkcipher_decrypt_iv(
&desc, &dst, &src, src.length);
}
if (rc) {
CERROR("encrypt error %d\n", rc);
- RETURN(rc);
+ return rc;
}
datalen += inobjs[i].len;
@@ -929,14 +929,14 @@ int krb5_encrypt_rawobjs(struct ll_crypto_cipher *tfm,
}
outobj->len = datalen;
- RETURN(0);
+ return 0;
}
/*
* if adj_nob != 0, we adjust desc->bd_nob to the actual cipher text size.
*/
static
-int krb5_encrypt_bulk(struct ll_crypto_cipher *tfm,
+int krb5_encrypt_bulk(struct crypto_blkcipher *tfm,
struct krb5_header *khdr,
char *confounder,
struct ptlrpc_bulk_desc *desc,
@@ -951,7 +951,7 @@ int krb5_encrypt_bulk(struct ll_crypto_cipher *tfm,
LASSERT(desc->bd_iov_count);
LASSERT(desc->bd_enc_iov);
- blocksize = ll_crypto_blkcipher_blocksize(tfm);
+ blocksize = crypto_blkcipher_blocksize(tfm);
LASSERT(blocksize > 1);
LASSERT(cipher->len == blocksize + sizeof(*khdr));
@@ -963,7 +963,7 @@ int krb5_encrypt_bulk(struct ll_crypto_cipher *tfm,
buf_to_sg(&src, confounder, blocksize);
buf_to_sg(&dst, cipher->data, blocksize);
- rc = ll_crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src, blocksize);
+ rc = crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src, blocksize);
if (rc) {
CERROR("error to encrypt confounder: %d\n", rc);
return rc;
@@ -983,7 +983,7 @@ int krb5_encrypt_bulk(struct ll_crypto_cipher *tfm,
desc->bd_enc_iov[i].kiov_offset = dst.offset;
desc->bd_enc_iov[i].kiov_len = dst.length;
- rc = ll_crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src,
+ rc = crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src,
src.length);
if (rc) {
CERROR("error to encrypt page: %d\n", rc);
@@ -995,7 +995,7 @@ int krb5_encrypt_bulk(struct ll_crypto_cipher *tfm,
buf_to_sg(&src, khdr, sizeof(*khdr));
buf_to_sg(&dst, cipher->data + blocksize, sizeof(*khdr));
- rc = ll_crypto_blkcipher_encrypt_iv(&ciph_desc,
+ rc = crypto_blkcipher_encrypt_iv(&ciph_desc,
&dst, &src, sizeof(*khdr));
if (rc) {
CERROR("error to encrypt krb5 header: %d\n", rc);
@@ -1025,7 +1025,7 @@ int krb5_encrypt_bulk(struct ll_crypto_cipher *tfm,
* should have been done by prep_bulk().
*/
static
-int krb5_decrypt_bulk(struct ll_crypto_cipher *tfm,
+int krb5_decrypt_bulk(struct crypto_blkcipher *tfm,
struct krb5_header *khdr,
struct ptlrpc_bulk_desc *desc,
rawobj_t *cipher,
@@ -1042,7 +1042,7 @@ int krb5_decrypt_bulk(struct ll_crypto_cipher *tfm,
LASSERT(desc->bd_enc_iov);
LASSERT(desc->bd_nob_transferred);
- blocksize = ll_crypto_blkcipher_blocksize(tfm);
+ blocksize = crypto_blkcipher_blocksize(tfm);
LASSERT(blocksize > 1);
LASSERT(cipher->len == blocksize + sizeof(*khdr));
@@ -1059,7 +1059,7 @@ int krb5_decrypt_bulk(struct ll_crypto_cipher *tfm,
buf_to_sg(&src, cipher->data, blocksize);
buf_to_sg(&dst, plain->data, blocksize);
- rc = ll_crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src, blocksize);
+ rc = crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src, blocksize);
if (rc) {
CERROR("error to decrypt confounder: %d\n", rc);
return rc;
@@ -1102,7 +1102,7 @@ int krb5_decrypt_bulk(struct ll_crypto_cipher *tfm,
if (desc->bd_iov[i].kiov_len % blocksize == 0)
sg_assign_page(&dst, desc->bd_iov[i].kiov_page);
- rc = ll_crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src,
+ rc = crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src,
src.length);
if (rc) {
CERROR("error to decrypt page: %d\n", rc);
@@ -1142,7 +1142,7 @@ int krb5_decrypt_bulk(struct ll_crypto_cipher *tfm,
buf_to_sg(&src, cipher->data + blocksize, sizeof(*khdr));
buf_to_sg(&dst, cipher->data + blocksize, sizeof(*khdr));
- rc = ll_crypto_blkcipher_decrypt_iv(&ciph_desc,
+ rc = crypto_blkcipher_decrypt_iv(&ciph_desc,
&dst, &src, sizeof(*khdr));
if (rc) {
CERROR("error to decrypt tail: %d\n", rc);
@@ -1177,7 +1177,7 @@ __u32 gss_wrap_kerberos(struct gss_ctx *gctx,
LASSERT(ke->ke_conf_size <= GSS_MAX_CIPHER_BLOCK);
LASSERT(kctx->kc_keye.kb_tfm == NULL ||
ke->ke_conf_size >=
- ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm));
+ crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm));
/*
* final token format:
@@ -1201,7 +1201,7 @@ __u32 gss_wrap_kerberos(struct gss_ctx *gctx,
blocksize = 1;
} else {
LASSERT(kctx->kc_keye.kb_tfm);
- blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
+ blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
}
LASSERT(blocksize <= ke->ke_conf_size);
@@ -1248,7 +1248,7 @@ __u32 gss_wrap_kerberos(struct gss_ctx *gctx,
if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
rawobj_t arc4_keye;
- struct ll_crypto_cipher *arc4_tfm;
+ struct crypto_blkcipher *arc4_tfm;
if (krb5_make_checksum(ENCTYPE_ARCFOUR_HMAC, &kctx->kc_keyi,
NULL, 1, &cksum, 0, NULL, &arc4_keye)) {
@@ -1256,13 +1256,13 @@ __u32 gss_wrap_kerberos(struct gss_ctx *gctx,
GOTO(arc4_out, rc = -EACCES);
}
- arc4_tfm = ll_crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
+ arc4_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
if (IS_ERR(arc4_tfm)) {
CERROR("failed to alloc tfm arc4 in ECB mode\n");
GOTO(arc4_out_key, rc = -EACCES);
}
- if (ll_crypto_blkcipher_setkey(arc4_tfm, arc4_keye.data,
+ if (crypto_blkcipher_setkey(arc4_tfm, arc4_keye.data,
arc4_keye.len)) {
CERROR("failed to set arc4 key, len %d\n",
arc4_keye.len);
@@ -1272,7 +1272,7 @@ __u32 gss_wrap_kerberos(struct gss_ctx *gctx,
rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
3, data_desc, &cipher, 1);
arc4_out_tfm:
- ll_crypto_free_blkcipher(arc4_tfm);
+ crypto_free_blkcipher(arc4_tfm);
arc4_out_key:
rawobj_free(&arc4_keye);
arc4_out:
@@ -1310,7 +1310,7 @@ __u32 gss_prep_bulk_kerberos(struct gss_ctx *gctx,
LASSERT(desc->bd_enc_iov);
LASSERT(kctx->kc_keye.kb_tfm);
- blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
+ blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
for (i = 0; i < desc->bd_iov_count; i++) {
LASSERT(desc->bd_enc_iov[i].kiov_page);
@@ -1371,7 +1371,7 @@ __u32 gss_wrap_bulk_kerberos(struct gss_ctx *gctx,
blocksize = 1;
} else {
LASSERT(kctx->kc_keye.kb_tfm);
- blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
+ blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
}
/*
@@ -1481,7 +1481,7 @@ __u32 gss_unwrap_kerberos(struct gss_ctx *gctx,
blocksize = 1;
} else {
LASSERT(kctx->kc_keye.kb_tfm);
- blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
+ blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
}
/* expected token layout:
@@ -1521,7 +1521,7 @@ __u32 gss_unwrap_kerberos(struct gss_ctx *gctx,
if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
rawobj_t arc4_keye;
- struct ll_crypto_cipher *arc4_tfm;
+ struct crypto_blkcipher *arc4_tfm;
cksum.data = token->data + token->len - ke->ke_hash_size;
cksum.len = ke->ke_hash_size;
@@ -1532,13 +1532,13 @@ __u32 gss_unwrap_kerberos(struct gss_ctx *gctx,
GOTO(arc4_out, rc = -EACCES);
}
- arc4_tfm = ll_crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
+ arc4_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
if (IS_ERR(arc4_tfm)) {
CERROR("failed to alloc tfm arc4 in ECB mode\n");
GOTO(arc4_out_key, rc = -EACCES);
}
- if (ll_crypto_blkcipher_setkey(arc4_tfm,
+ if (crypto_blkcipher_setkey(arc4_tfm,
arc4_keye.data, arc4_keye.len)) {
CERROR("failed to set arc4 key, len %d\n",
arc4_keye.len);
@@ -1548,7 +1548,7 @@ __u32 gss_unwrap_kerberos(struct gss_ctx *gctx,
rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
1, &cipher_in, &plain_out, 0);
arc4_out_tfm:
- ll_crypto_free_blkcipher(arc4_tfm);
+ crypto_free_blkcipher(arc4_tfm);
arc4_out_key:
rawobj_free(&arc4_keye);
arc4_out:
@@ -1647,7 +1647,7 @@ __u32 gss_unwrap_bulk_kerberos(struct gss_ctx *gctx,
LBUG();
} else {
LASSERT(kctx->kc_keye.kb_tfm);
- blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
+ blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
}
LASSERT(sizeof(*khdr) >= blocksize && sizeof(*khdr) % blocksize == 0);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c
index 3df7257b7fa..c624518c181 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c
@@ -262,7 +262,6 @@ void gss_sec_ctx_replace_pf(struct gss_sec *gsec,
struct hlist_node *next;
HLIST_HEAD(freelist);
unsigned int hash;
- ENTRY;
gsec_pf = container_of(gsec, struct gss_sec_pipefs, gsp_base);
@@ -287,7 +286,6 @@ void gss_sec_ctx_replace_pf(struct gss_sec *gsec,
spin_unlock(&gsec->gs_base.ps_lock);
ctx_list_destroy_pf(&freelist);
- EXIT;
}
static
@@ -297,23 +295,22 @@ int gss_install_rvs_cli_ctx_pf(struct gss_sec *gsec,
struct vfs_cred vcred;
struct ptlrpc_cli_ctx *cli_ctx;
int rc;
- ENTRY;
vcred.vc_uid = 0;
vcred.vc_gid = 0;
cli_ctx = ctx_create_pf(&gsec->gs_base, &vcred);
if (!cli_ctx)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rc = gss_copy_rvc_cli_ctx(cli_ctx, svc_ctx);
if (rc) {
ctx_destroy_pf(cli_ctx->cc_sec, cli_ctx);
- RETURN(rc);
+ return rc;
}
gss_sec_ctx_replace_pf(gsec, cli_ctx);
- RETURN(0);
+ return 0;
}
static
@@ -324,7 +321,6 @@ void gss_ctx_cache_gc_pf(struct gss_sec_pipefs *gsec_pf,
struct ptlrpc_cli_ctx *ctx;
struct hlist_node *next;
int i;
- ENTRY;
sec = &gsec_pf->gsp_base.gs_base;
@@ -337,7 +333,6 @@ void gss_ctx_cache_gc_pf(struct gss_sec_pipefs *gsec_pf,
}
sec->ps_gc_next = cfs_time_current_sec() + sec->ps_gc_interval;
- EXIT;
}
static
@@ -347,7 +342,6 @@ struct ptlrpc_sec* gss_sec_create_pf(struct obd_import *imp,
{
struct gss_sec_pipefs *gsec_pf;
int alloc_size, hash_size, i;
- ENTRY;
#define GSS_SEC_PIPEFS_CTX_HASH_SIZE (32)
@@ -362,7 +356,7 @@ struct ptlrpc_sec* gss_sec_create_pf(struct obd_import *imp,
OBD_ALLOC(gsec_pf, alloc_size);
if (!gsec_pf)
- RETURN(NULL);
+ return NULL;
gsec_pf->gsp_chash_size = hash_size;
for (i = 0; i < hash_size; i++)
@@ -380,13 +374,13 @@ struct ptlrpc_sec* gss_sec_create_pf(struct obd_import *imp,
goto err_destroy;
}
- RETURN(&gsec_pf->gsp_base.gs_base);
+ return &gsec_pf->gsp_base.gs_base;
err_destroy:
gss_sec_destroy_common(&gsec_pf->gsp_base);
err_free:
OBD_FREE(gsec_pf, alloc_size);
- RETURN(NULL);
+ return NULL;
}
static
@@ -423,7 +417,6 @@ struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_pf(struct ptlrpc_sec *sec,
struct hlist_node *next;
HLIST_HEAD(freelist);
unsigned int hash, gc = 0, found = 0;
- ENTRY;
might_sleep();
@@ -473,7 +466,7 @@ retry:
/* don't allocate for reverse sec */
if (sec_is_reverse(sec)) {
spin_unlock(&sec->ps_lock);
- RETURN(NULL);
+ return NULL;
}
if (new) {
@@ -504,7 +497,7 @@ retry:
}
ctx_list_destroy_pf(&freelist);
- RETURN(ctx);
+ return ctx;
}
static
@@ -545,7 +538,6 @@ int gss_sec_flush_ctx_cache_pf(struct ptlrpc_sec *sec,
struct hlist_node *next;
HLIST_HEAD(freelist);
int i, busy = 0;
- ENTRY;
might_sleep_if(grace);
@@ -584,7 +576,7 @@ int gss_sec_flush_ctx_cache_pf(struct ptlrpc_sec *sec,
spin_unlock(&sec->ps_lock);
ctx_list_destroy_pf(&freelist);
- RETURN(busy);
+ return busy;
}
/****************************************
@@ -704,11 +696,9 @@ void upcall_msg_delist(struct gss_upcall_msg *msg)
static
void gss_release_msg(struct gss_upcall_msg *gmsg)
{
- ENTRY;
LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
if (!atomic_dec_and_test(&gmsg->gum_refcount)) {
- EXIT;
return;
}
@@ -721,7 +711,6 @@ void gss_release_msg(struct gss_upcall_msg *gmsg)
LASSERT(list_empty(&gmsg->gum_list));
LASSERT(list_empty(&gmsg->gum_base.list));
OBD_FREE_PTR(gmsg);
- EXIT;
}
static
@@ -809,19 +798,18 @@ ssize_t gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
char *data = (char *)msg->data + msg->copied;
ssize_t mlen = msg->len;
ssize_t left;
- ENTRY;
if (mlen > buflen)
mlen = buflen;
left = copy_to_user(dst, data, mlen);
if (left < 0) {
msg->errno = left;
- RETURN(left);
+ return left;
}
mlen -= left;
msg->copied += mlen;
msg->errno = 0;
- RETURN(mlen);
+ return mlen;
}
static
@@ -835,14 +823,13 @@ ssize_t gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
int datalen;
int timeout, rc;
__u32 mechidx, seq, gss_err;
- ENTRY;
mechidx = (__u32) (long) rpci->private;
LASSERT(mechidx < MECH_MAX);
OBD_ALLOC(buf, mlen);
if (!buf)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (copy_from_user(buf, src, mlen)) {
CERROR("failed copy user space data\n");
@@ -940,7 +927,7 @@ out_free:
* hack pipefs: always return asked length unless all following
* downcalls might be messed up. */
rc = mlen;
- RETURN(rc);
+ return rc;
}
static
@@ -949,13 +936,11 @@ void gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
struct gss_upcall_msg *gmsg;
struct gss_upcall_msg_data *gumd;
static cfs_time_t ratelimit = 0;
- ENTRY;
LASSERT(list_empty(&msg->list));
/* normally errno is >= 0 */
if (msg->errno >= 0) {
- EXIT;
return;
}
@@ -980,7 +965,6 @@ void gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
}
gss_msg_fail_ctx(gmsg);
gss_release_msg(gmsg);
- EXIT;
}
static
@@ -988,7 +972,6 @@ void gss_pipe_release(struct inode *inode)
{
struct rpc_inode *rpci = RPC_I(inode);
__u32 idx;
- ENTRY;
idx = (__u32) (long) rpci->private;
LASSERT(idx < MECH_MAX);
@@ -1020,7 +1003,6 @@ void gss_pipe_release(struct inode *inode)
upcall_list_lock(idx);
}
upcall_list_unlock(idx);
- EXIT;
}
static struct rpc_pipe_ops gss_upcall_ops = {
@@ -1041,7 +1023,6 @@ int gss_ctx_refresh_pf(struct ptlrpc_cli_ctx *ctx)
struct gss_sec *gsec;
struct gss_upcall_msg *gmsg;
int rc = 0;
- ENTRY;
might_sleep();
@@ -1052,14 +1033,14 @@ int gss_ctx_refresh_pf(struct ptlrpc_cli_ctx *ctx)
imp = ctx->cc_sec->ps_import;
if (!imp->imp_connection) {
CERROR("import has no connection set\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
gsec = container_of(ctx->cc_sec, struct gss_sec, gs_base);
OBD_ALLOC_PTR(gmsg);
if (!gmsg)
- RETURN(-ENOMEM);
+ return -ENOMEM;
/* initialize pipefs base msg */
INIT_LIST_HEAD(&gmsg->gum_base.list);
@@ -1107,10 +1088,10 @@ int gss_ctx_refresh_pf(struct ptlrpc_cli_ctx *ctx)
goto err_free;
}
- RETURN(0);
+ return 0;
err_free:
OBD_FREE_PTR(gmsg);
- RETURN(rc);
+ return rc;
}
static
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_rawobj.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_rawobj.c
index 474ecf80530..fb298aef66e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_rawobj.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_rawobj.c
@@ -65,7 +65,7 @@ int rawobj_alloc(rawobj_t *obj, char *buf, int len)
OBD_ALLOC_LARGE(obj->data, len);
if (!obj->data) {
obj->len = 0;
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
memcpy(obj->data, buf, len);
} else
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c
index 31b50ea19c2..5b5365b4629 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c
@@ -259,8 +259,6 @@ static int rsi_parse(struct cache_detail *cd, char *mesg, int mlen)
struct rsi rsii, *rsip = NULL;
time_t expiry;
int status = -EINVAL;
- ENTRY;
-
memset(&rsii, 0, sizeof(rsii));
@@ -341,7 +339,7 @@ out:
if (status)
CERROR("rsi parse error %d\n", status);
- RETURN(status);
+ return status;
}
static struct cache_detail rsi_cache = {
@@ -662,7 +660,6 @@ static void rsc_flush(rsc_entry_match *match, long data)
struct cache_head **ch;
struct rsc *rscp;
int n;
- ENTRY;
write_lock(&rsc_cache.hash_lock);
for (n = 0; n < RSC_HASHMAX; n++) {
@@ -684,7 +681,6 @@ static void rsc_flush(rsc_entry_match *match, long data)
}
}
write_unlock(&rsc_cache.hash_lock);
- EXIT;
}
static int match_uid(struct rsc *rscp, long uid)
@@ -744,7 +740,6 @@ int gss_svc_upcall_install_rvs_ctx(struct obd_import *imp,
unsigned long ctx_expiry;
__u32 major;
int rc;
- ENTRY;
memset(&rsci, 0, sizeof(rsci));
@@ -792,7 +787,7 @@ out:
if (rc)
CERROR("create reverse svc ctx: idx "LPX64", rc %d\n",
gsec->gs_rvs_hdl, rc);
- RETURN(rc);
+ return rc;
}
int gss_svc_upcall_expire_rvs_ctx(rawobj_t *handle)
@@ -855,7 +850,6 @@ int gss_svc_upcall_handle_init(struct ptlrpc_request *req,
struct gss_rep_header *rephdr;
int first_check = 1;
int rc = SECSVC_DROP;
- ENTRY;
memset(&rsikey, 0, sizeof(rsikey));
rsikey.lustre_svc = lustre_svc;
@@ -1016,7 +1010,7 @@ out:
COMPAT_RSC_PUT(&rsci->h, &rsc_cache);
}
- RETURN(rc);
+ return rc;
}
struct gss_svc_ctx *gss_svc_upcall_get_ctx(struct ptlrpc_request *req,
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/lproc_gss.c b/drivers/staging/lustre/lustre/ptlrpc/gss/lproc_gss.c
index 340400089a5..de100a14ab5 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/lproc_gss.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/lproc_gss.c
@@ -199,15 +199,17 @@ int gss_init_lproc(void)
gss_proc_root = lprocfs_register("gss", sptlrpc_proc_root,
gss_lprocfs_vars, NULL);
if (IS_ERR(gss_proc_root)) {
+ rc = PTR_ERR(gss_proc_root);
gss_proc_root = NULL;
- GOTO(err_out, rc = PTR_ERR(gss_proc_root));
+ GOTO(err_out, rc);
}
gss_proc_lk = lprocfs_register("lgss_keyring", gss_proc_root,
gss_lk_lprocfs_vars, NULL);
if (IS_ERR(gss_proc_lk)) {
+ rc = PTR_ERR(gss_proc_lk);
gss_proc_lk = NULL;
- GOTO(err_out, rc = PTR_ERR(gss_proc_root));
+ GOTO(err_out, rc);
}
return 0;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c b/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c
index ebca858ca18..b42ddda9ee2 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c
@@ -280,11 +280,10 @@ __u32 gss_unseal_msg(struct gss_ctx *mechctx,
__u8 *clear_buf;
int clear_buflen;
__u32 major;
- ENTRY;
if (msgbuf->lm_bufcount != 2) {
CERROR("invalid bufcount %d\n", msgbuf->lm_bufcount);
- RETURN(GSS_S_FAILURE);
+ return GSS_S_FAILURE;
}
/* allocate a temporary clear text buffer, same sized as token,
@@ -292,7 +291,7 @@ __u32 gss_unseal_msg(struct gss_ctx *mechctx,
clear_buflen = lustre_msg_buflen(msgbuf, 1);
OBD_ALLOC_LARGE(clear_buf, clear_buflen);
if (!clear_buf)
- RETURN(GSS_S_FAILURE);
+ return GSS_S_FAILURE;
/* buffer objects */
hdrobj.len = lustre_msg_buflen(msgbuf, 0);
@@ -317,7 +316,7 @@ __u32 gss_unseal_msg(struct gss_ctx *mechctx,
major = GSS_S_COMPLETE;
out_free:
OBD_FREE_LARGE(clear_buf, clear_buflen);
- RETURN(major);
+ return major;
}
/********************************************
@@ -646,7 +645,6 @@ int gss_cli_ctx_sign(struct ptlrpc_cli_ctx *ctx,
struct gss_cli_ctx *gctx = ctx2gctx(ctx);
__u32 flags = 0, seq, svc;
int rc;
- ENTRY;
LASSERT(req->rq_reqbuf);
LASSERT(req->rq_reqbuf->lm_bufcount >= 2);
@@ -654,7 +652,7 @@ int gss_cli_ctx_sign(struct ptlrpc_cli_ctx *ctx,
/* nothing to do for context negotiation RPCs */
if (req->rq_ctx_init)
- RETURN(0);
+ return 0;
svc = SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc);
if (req->rq_pack_bulk)
@@ -670,7 +668,7 @@ redo:
flags, gctx->gc_proc, seq, svc,
&gctx->gc_handle);
if (rc < 0)
- RETURN(rc);
+ return rc;
/* gss_sign_msg() msg might take long time to finish, in which period
* more rpcs could be wrapped up and sent out. if we found too many
@@ -689,7 +687,7 @@ redo:
}
req->rq_reqdata_len = rc;
- RETURN(0);
+ return 0;
}
static
@@ -765,7 +763,6 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx,
struct lustre_msg *msg = req->rq_repdata;
__u32 major;
int pack_bulk, swabbed, rc = 0;
- ENTRY;
LASSERT(req->rq_cli_ctx == ctx);
LASSERT(msg);
@@ -777,12 +774,12 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx,
if (req->rq_ctx_init && !req->rq_early) {
req->rq_repmsg = lustre_msg_buf(msg, 1, 0);
req->rq_replen = msg->lm_buflens[1];
- RETURN(0);
+ return 0;
}
if (msg->lm_bufcount < 2 || msg->lm_bufcount > 4) {
CERROR("unexpected bufcount %u\n", msg->lm_bufcount);
- RETURN(-EPROTO);
+ return -EPROTO;
}
swabbed = ptlrpc_rep_need_swab(req);
@@ -790,7 +787,7 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx,
ghdr = gss_swab_header(msg, 0, swabbed);
if (ghdr == NULL) {
CERROR("can't decode gss header\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
/* sanity checks */
@@ -800,7 +797,7 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx,
if (ghdr->gh_version != reqhdr->gh_version) {
CERROR("gss version %u mismatch, expect %u\n",
ghdr->gh_version, reqhdr->gh_version);
- RETURN(-EPROTO);
+ return -EPROTO;
}
switch (ghdr->gh_proc) {
@@ -810,19 +807,19 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx,
if (!req->rq_early && !equi(req->rq_pack_bulk == 1, pack_bulk)){
CERROR("%s bulk flag in reply\n",
req->rq_pack_bulk ? "missing" : "unexpected");
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (ghdr->gh_seq != reqhdr->gh_seq) {
CERROR("seqnum %u mismatch, expect %u\n",
ghdr->gh_seq, reqhdr->gh_seq);
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (ghdr->gh_svc != reqhdr->gh_svc) {
CERROR("svc %u mismatch, expect %u\n",
ghdr->gh_svc, reqhdr->gh_svc);
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (swabbed)
@@ -831,7 +828,7 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx,
major = gss_verify_msg(msg, gctx->gc_mechctx, reqhdr->gh_svc);
if (major != GSS_S_COMPLETE) {
CERROR("failed to verify reply: %x\n", major);
- RETURN(-EPERM);
+ return -EPERM;
}
if (req->rq_early && reqhdr->gh_svc == SPTLRPC_SVC_NULL) {
@@ -843,7 +840,7 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx,
if (cksum != msg->lm_cksum) {
CWARN("early reply checksum mismatch: "
"%08x != %08x\n", cksum, msg->lm_cksum);
- RETURN(-EPROTO);
+ return -EPROTO;
}
}
@@ -852,13 +849,13 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx,
if (msg->lm_bufcount < 3) {
CERROR("Invalid reply bufcount %u\n",
msg->lm_bufcount);
- RETURN(-EPROTO);
+ return -EPROTO;
}
rc = bulk_sec_desc_unpack(msg, 2, swabbed);
if (rc) {
CERROR("unpack bulk desc: %d\n", rc);
- RETURN(rc);
+ return rc;
}
}
@@ -878,7 +875,7 @@ int gss_cli_ctx_verify(struct ptlrpc_cli_ctx *ctx,
rc = -EPROTO;
}
- RETURN(rc);
+ return rc;
}
int gss_cli_ctx_seal(struct ptlrpc_cli_ctx *ctx,
@@ -889,7 +886,6 @@ int gss_cli_ctx_seal(struct ptlrpc_cli_ctx *ctx,
struct gss_header *ghdr;
__u32 buflens[2], major;
int wiresize, rc;
- ENTRY;
LASSERT(req->rq_clrbuf);
LASSERT(req->rq_cli_ctx == ctx);
@@ -915,7 +911,7 @@ int gss_cli_ctx_seal(struct ptlrpc_cli_ctx *ctx,
} else {
OBD_ALLOC_LARGE(req->rq_reqbuf, wiresize);
if (!req->rq_reqbuf)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req->rq_reqbuf_len = wiresize;
}
@@ -969,7 +965,7 @@ redo:
/* now set the final wire data length */
req->rq_reqdata_len = lustre_shrink_msg(req->rq_reqbuf, 1, token.len,0);
- RETURN(0);
+ return 0;
err_free:
if (!req->rq_pool) {
@@ -977,7 +973,7 @@ err_free:
req->rq_reqbuf = NULL;
req->rq_reqbuf_len = 0;
}
- RETURN(rc);
+ return rc;
}
int gss_cli_ctx_unseal(struct ptlrpc_cli_ctx *ctx,
@@ -988,7 +984,6 @@ int gss_cli_ctx_unseal(struct ptlrpc_cli_ctx *ctx,
struct lustre_msg *msg = req->rq_repdata;
int msglen, pack_bulk, swabbed, rc;
__u32 major;
- ENTRY;
LASSERT(req->rq_cli_ctx == ctx);
LASSERT(req->rq_ctx_init == 0);
@@ -1000,14 +995,14 @@ int gss_cli_ctx_unseal(struct ptlrpc_cli_ctx *ctx,
ghdr = gss_swab_header(msg, 0, swabbed);
if (ghdr == NULL) {
CERROR("can't decode gss header\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
/* sanity checks */
if (ghdr->gh_version != PTLRPC_GSS_VERSION) {
CERROR("gss version %u mismatch, expect %u\n",
ghdr->gh_version, PTLRPC_GSS_VERSION);
- RETURN(-EPROTO);
+ return -EPROTO;
}
switch (ghdr->gh_proc) {
@@ -1017,7 +1012,7 @@ int gss_cli_ctx_unseal(struct ptlrpc_cli_ctx *ctx,
if (!req->rq_early && !equi(req->rq_pack_bulk == 1, pack_bulk)){
CERROR("%s bulk flag in reply\n",
req->rq_pack_bulk ? "missing" : "unexpected");
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (swabbed)
@@ -1038,25 +1033,25 @@ int gss_cli_ctx_unseal(struct ptlrpc_cli_ctx *ctx,
swabbed = __lustre_unpack_msg(msg, msglen);
if (swabbed < 0) {
CERROR("Failed to unpack after decryption\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (msg->lm_bufcount < 1) {
CERROR("Invalid reply buffer: empty\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (pack_bulk) {
if (msg->lm_bufcount < 2) {
CERROR("bufcount %u: missing bulk sec desc\n",
msg->lm_bufcount);
- RETURN(-EPROTO);
+ return -EPROTO;
}
/* bulk checksum is the last segment */
if (bulk_sec_desc_unpack(msg, msg->lm_bufcount - 1,
swabbed))
- RETURN(-EPROTO);
+ return -EPROTO;
}
req->rq_repmsg = lustre_msg_buf(msg, 0, 0);
@@ -1077,7 +1072,7 @@ int gss_cli_ctx_unseal(struct ptlrpc_cli_ctx *ctx,
rc = -EPERM;
}
- RETURN(rc);
+ return rc;
}
/*********************************************
@@ -1148,7 +1143,6 @@ int gss_sec_create_common(struct gss_sec *gsec,
void gss_sec_destroy_common(struct gss_sec *gsec)
{
struct ptlrpc_sec *sec = &gsec->gs_base;
- ENTRY;
LASSERT(sec->ps_import);
LASSERT(atomic_read(&sec->ps_refcount) == 0);
@@ -1163,8 +1157,6 @@ void gss_sec_destroy_common(struct gss_sec *gsec)
if (SPTLRPC_FLVR_BULK_SVC(sec->ps_flvr.sf_rpc) == SPTLRPC_BULK_SVC_PRIV)
sptlrpc_enc_pool_del_user();
-
- EXIT;
}
void gss_sec_kill(struct ptlrpc_sec *sec)
@@ -1260,7 +1252,6 @@ int gss_alloc_reqbuf_intg(struct ptlrpc_sec *sec,
int bufsize, txtsize;
int bufcnt = 2;
__u32 buflens[5];
- ENTRY;
/*
* on-wire data layout:
@@ -1312,7 +1303,7 @@ int gss_alloc_reqbuf_intg(struct ptlrpc_sec *sec,
OBD_ALLOC_LARGE(req->rq_reqbuf, bufsize);
if (!req->rq_reqbuf)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req->rq_reqbuf_len = bufsize;
} else {
@@ -1331,7 +1322,7 @@ int gss_alloc_reqbuf_intg(struct ptlrpc_sec *sec,
if (req->rq_pack_udesc)
sptlrpc_pack_user_desc(req->rq_reqbuf, 2);
- RETURN(0);
+ return 0;
}
static
@@ -1342,7 +1333,6 @@ int gss_alloc_reqbuf_priv(struct ptlrpc_sec *sec,
__u32 ibuflens[3], wbuflens[2];
int ibufcnt;
int clearsize, wiresize;
- ENTRY;
LASSERT(req->rq_clrbuf == NULL);
LASSERT(req->rq_clrbuf_len == 0);
@@ -1399,7 +1389,7 @@ int gss_alloc_reqbuf_priv(struct ptlrpc_sec *sec,
OBD_ALLOC_LARGE(req->rq_clrbuf, clearsize);
if (!req->rq_clrbuf)
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
req->rq_clrbuf_len = clearsize;
@@ -1409,7 +1399,7 @@ int gss_alloc_reqbuf_priv(struct ptlrpc_sec *sec,
if (req->rq_pack_udesc)
sptlrpc_pack_user_desc(req->rq_clrbuf, 1);
- RETURN(0);
+ return 0;
}
/*
@@ -1442,7 +1432,6 @@ void gss_free_reqbuf(struct ptlrpc_sec *sec,
struct ptlrpc_request *req)
{
int privacy;
- ENTRY;
LASSERT(!req->rq_pool || req->rq_reqbuf);
privacy = SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc) == SPTLRPC_SVC_PRIV;
@@ -1471,8 +1460,6 @@ release_reqbuf:
req->rq_reqbuf = NULL;
req->rq_reqbuf_len = 0;
}
-
- EXIT;
}
static int do_alloc_repbuf(struct ptlrpc_request *req, int bufsize)
@@ -1578,7 +1565,6 @@ int gss_alloc_repbuf(struct ptlrpc_sec *sec,
int msgsize)
{
int svc = SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc);
- ENTRY;
LASSERT(!req->rq_pack_bulk ||
(req->rq_bulk_read || req->rq_bulk_write));
@@ -1697,7 +1683,7 @@ int gss_enlarge_reqbuf_intg(struct ptlrpc_sec *sec,
OBD_ALLOC_LARGE(newbuf, newbuf_size);
if (newbuf == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
memcpy(newbuf, req->rq_reqbuf, req->rq_reqbuf_len);
@@ -1717,7 +1703,7 @@ int gss_enlarge_reqbuf_intg(struct ptlrpc_sec *sec,
_sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize);
req->rq_reqlen = newmsg_size;
- RETURN(0);
+ return 0;
}
static
@@ -1786,7 +1772,7 @@ int gss_enlarge_reqbuf_priv(struct ptlrpc_sec *sec,
OBD_ALLOC_LARGE(newclrbuf, newclrbuf_size);
if (newclrbuf == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
memcpy(newclrbuf, req->rq_clrbuf, req->rq_clrbuf_len);
@@ -1806,7 +1792,7 @@ int gss_enlarge_reqbuf_priv(struct ptlrpc_sec *sec,
_sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize);
req->rq_reqlen = newmsg_size;
- RETURN(0);
+ return 0;
}
int gss_enlarge_reqbuf(struct ptlrpc_sec *sec,
@@ -1891,7 +1877,6 @@ int gss_svc_sign(struct ptlrpc_request *req,
{
__u32 flags = 0;
int rc;
- ENTRY;
LASSERT(rs->rs_msg == lustre_msg_buf(rs->rs_repbuf, 1, 0));
@@ -1906,7 +1891,7 @@ int gss_svc_sign(struct ptlrpc_request *req,
LUSTRE_SP_ANY, flags, PTLRPC_GSS_PROC_DATA,
grctx->src_wirectx.gw_seq, svc, NULL);
if (rc < 0)
- RETURN(rc);
+ return rc;
rs->rs_repdata_len = rc;
@@ -1923,7 +1908,7 @@ int gss_svc_sign(struct ptlrpc_request *req,
req->rq_reply_off = 0;
}
- RETURN(0);
+ return 0;
}
int gss_pack_err_notify(struct ptlrpc_request *req, __u32 major, __u32 minor)
@@ -1933,10 +1918,9 @@ int gss_pack_err_notify(struct ptlrpc_request *req, __u32 major, __u32 minor)
struct gss_err_header *ghdr;
int replen = sizeof(struct ptlrpc_body);
int rc;
- ENTRY;
//if (OBD_FAIL_CHECK_ORSET(OBD_FAIL_SVCGSS_ERR_NOTIFY, OBD_FAIL_ONCE))
- // RETURN(-EINVAL);
+ // return -EINVAL;
grctx->src_err_notify = 1;
grctx->src_reserve_len = 0;
@@ -1944,7 +1928,7 @@ int gss_pack_err_notify(struct ptlrpc_request *req, __u32 major, __u32 minor)
rc = lustre_pack_reply_v2(req, 1, &replen, NULL, 0);
if (rc) {
CERROR("could not pack reply, err %d\n", rc);
- RETURN(rc);
+ return rc;
}
/* gss hdr */
@@ -1963,7 +1947,7 @@ int gss_pack_err_notify(struct ptlrpc_request *req, __u32 major, __u32 minor)
CDEBUG(D_SEC, "prepare gss error notify(0x%x/0x%x) to %s\n",
major, minor, libcfs_nid2str(req->rq_peer.nid));
- RETURN(0);
+ return 0;
}
static
@@ -1978,7 +1962,6 @@ int gss_svc_handle_init(struct ptlrpc_request *req,
__u32 lustre_svc;
__u32 *secdata, seclen;
int swabbed, rc;
- ENTRY;
CDEBUG(D_SEC, "processing gss init(%d) request from %s\n", gw->gw_proc,
libcfs_nid2str(req->rq_peer.nid));
@@ -1987,18 +1970,18 @@ int gss_svc_handle_init(struct ptlrpc_request *req,
if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) {
CERROR("unexpected bulk flag\n");
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
if (gw->gw_proc == PTLRPC_GSS_PROC_INIT && gw->gw_handle.len != 0) {
CERROR("proc %u: invalid handle length %u\n",
gw->gw_proc, gw->gw_handle.len);
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
if (reqbuf->lm_bufcount < 3 || reqbuf->lm_bufcount > 4){
CERROR("Invalid bufcount %d\n", reqbuf->lm_bufcount);
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
swabbed = ptlrpc_req_need_swab(req);
@@ -2009,7 +1992,7 @@ int gss_svc_handle_init(struct ptlrpc_request *req,
if (seclen < 4 + 4) {
CERROR("sec size %d too small\n", seclen);
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
/* lustre svc type */
@@ -2020,7 +2003,7 @@ int gss_svc_handle_init(struct ptlrpc_request *req,
* because touched internal structure of obd_uuid */
if (rawobj_extract(&uuid_obj, &secdata, &seclen)) {
CERROR("failed to extract target uuid\n");
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
uuid_obj.data[uuid_obj.len - 1] = '\0';
@@ -2030,25 +2013,25 @@ int gss_svc_handle_init(struct ptlrpc_request *req,
CERROR("target '%s' is not available for context init (%s)\n",
uuid->uuid, target == NULL ? "no target" :
(target->obd_stopping ? "stopping" : "not set up"));
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
/* extract reverse handle */
if (rawobj_extract(&rvs_hdl, &secdata, &seclen)) {
CERROR("failed extract reverse handle\n");
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
/* extract token */
if (rawobj_extract(&in_token, &secdata, &seclen)) {
CERROR("can't extract token\n");
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
rc = gss_svc_upcall_handle_init(req, grctx, gw, target, lustre_svc,
&rvs_hdl, &in_token);
if (rc != SECSVC_OK)
- RETURN(rc);
+ return rc;
if (grctx->src_ctx->gsc_usr_mds || grctx->src_ctx->gsc_usr_oss ||
grctx->src_ctx->gsc_usr_root)
@@ -2064,11 +2047,11 @@ int gss_svc_handle_init(struct ptlrpc_request *req,
if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
if (reqbuf->lm_bufcount < 4) {
CERROR("missing user descriptor\n");
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
if (sptlrpc_unpack_user_desc(reqbuf, 2, swabbed)) {
CERROR("Mal-formed user descriptor\n");
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
req->rq_pack_udesc = 1;
@@ -2078,7 +2061,7 @@ int gss_svc_handle_init(struct ptlrpc_request *req,
req->rq_reqmsg = lustre_msg_buf(reqbuf, 1, 0);
req->rq_reqlen = lustre_msg_buflen(reqbuf, 1);
- RETURN(rc);
+ return rc;
}
/*
@@ -2094,13 +2077,12 @@ int gss_svc_verify_request(struct ptlrpc_request *req,
struct lustre_msg *msg = req->rq_reqbuf;
int offset = 2;
int swabbed;
- ENTRY;
*major = GSS_S_COMPLETE;
if (msg->lm_bufcount < 2) {
CERROR("Too few segments (%u) in request\n", msg->lm_bufcount);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (gw->gw_svc == SPTLRPC_SVC_NULL)
@@ -2109,20 +2091,20 @@ int gss_svc_verify_request(struct ptlrpc_request *req,
if (gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 0)) {
CERROR("phase 0: discard replayed req: seq %u\n", gw->gw_seq);
*major = GSS_S_DUPLICATE_TOKEN;
- RETURN(-EACCES);
+ return -EACCES;
}
*major = gss_verify_msg(msg, gctx->gsc_mechctx, gw->gw_svc);
if (*major != GSS_S_COMPLETE) {
CERROR("failed to verify request: %x\n", *major);
- RETURN(-EACCES);
+ return -EACCES;
}
if (gctx->gsc_reverse == 0 &&
gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 1)) {
CERROR("phase 1+: discard replayed req: seq %u\n", gw->gw_seq);
*major = GSS_S_DUPLICATE_TOKEN;
- RETURN(-EACCES);
+ return -EACCES;
}
verified:
@@ -2132,12 +2114,12 @@ verified:
if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
if (msg->lm_bufcount < (offset + 1)) {
CERROR("no user desc included\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (sptlrpc_unpack_user_desc(msg, offset, swabbed)) {
CERROR("Mal-formed user descriptor\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
req->rq_pack_udesc = 1;
@@ -2149,11 +2131,11 @@ verified:
if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) {
if (msg->lm_bufcount < (offset + 1)) {
CERROR("missing bulk sec descriptor\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (bulk_sec_desc_unpack(msg, offset, swabbed))
- RETURN(-EINVAL);
+ return -EINVAL;
req->rq_pack_bulk = 1;
grctx->src_reqbsd = lustre_msg_buf(msg, offset, 0);
@@ -2162,7 +2144,7 @@ verified:
req->rq_reqmsg = lustre_msg_buf(msg, 1, 0);
req->rq_reqlen = msg->lm_buflens[1];
- RETURN(0);
+ return 0;
}
static
@@ -2174,48 +2156,47 @@ int gss_svc_unseal_request(struct ptlrpc_request *req,
struct gss_svc_ctx *gctx = grctx->src_ctx;
struct lustre_msg *msg = req->rq_reqbuf;
int swabbed, msglen, offset = 1;
- ENTRY;
if (gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 0)) {
CERROR("phase 0: discard replayed req: seq %u\n", gw->gw_seq);
*major = GSS_S_DUPLICATE_TOKEN;
- RETURN(-EACCES);
+ return -EACCES;
}
*major = gss_unseal_msg(gctx->gsc_mechctx, msg,
&msglen, req->rq_reqdata_len);
if (*major != GSS_S_COMPLETE) {
CERROR("failed to unwrap request: %x\n", *major);
- RETURN(-EACCES);
+ return -EACCES;
}
if (gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 1)) {
CERROR("phase 1+: discard replayed req: seq %u\n", gw->gw_seq);
*major = GSS_S_DUPLICATE_TOKEN;
- RETURN(-EACCES);
+ return -EACCES;
}
swabbed = __lustre_unpack_msg(msg, msglen);
if (swabbed < 0) {
CERROR("Failed to unpack after decryption\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
req->rq_reqdata_len = msglen;
if (msg->lm_bufcount < 1) {
CERROR("Invalid buffer: is empty\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
if (msg->lm_bufcount < offset + 1) {
CERROR("no user descriptor included\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (sptlrpc_unpack_user_desc(msg, offset, swabbed)) {
CERROR("Mal-formed user descriptor\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
req->rq_pack_udesc = 1;
@@ -2226,11 +2207,11 @@ int gss_svc_unseal_request(struct ptlrpc_request *req,
if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) {
if (msg->lm_bufcount < offset + 1) {
CERROR("no bulk checksum included\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (bulk_sec_desc_unpack(msg, offset, swabbed))
- RETURN(-EINVAL);
+ return -EINVAL;
req->rq_pack_bulk = 1;
grctx->src_reqbsd = lustre_msg_buf(msg, offset, 0);
@@ -2239,7 +2220,7 @@ int gss_svc_unseal_request(struct ptlrpc_request *req,
req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf, 0, 0);
req->rq_reqlen = req->rq_reqbuf->lm_buflens[0];
- RETURN(0);
+ return 0;
}
static
@@ -2249,7 +2230,6 @@ int gss_svc_handle_data(struct ptlrpc_request *req,
struct gss_svc_reqctx *grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
__u32 major = 0;
int rc = 0;
- ENTRY;
grctx->src_ctx = gss_svc_upcall_get_ctx(req, gw);
if (!grctx->src_ctx) {
@@ -2272,7 +2252,7 @@ int gss_svc_handle_data(struct ptlrpc_request *req,
}
if (rc == 0)
- RETURN(SECSVC_OK);
+ return SECSVC_OK;
CERROR("svc %u failed: major 0x%08x: req xid "LPU64" ctx %p idx "
LPX64"(%u->%s)\n", gw->gw_svc, major, req->rq_xid,
@@ -2283,9 +2263,9 @@ error:
* might happen after server reboot, to allow recovery. */
if ((major == GSS_S_NO_CONTEXT || major == GSS_S_BAD_SIG) &&
gss_pack_err_notify(req, major, 0) == 0)
- RETURN(SECSVC_COMPLETE);
+ return SECSVC_COMPLETE;
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
static
@@ -2294,7 +2274,6 @@ int gss_svc_handle_destroy(struct ptlrpc_request *req,
{
struct gss_svc_reqctx *grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
__u32 major;
- ENTRY;
req->rq_ctx_fini = 1;
req->rq_no_reply = 1;
@@ -2302,16 +2281,16 @@ int gss_svc_handle_destroy(struct ptlrpc_request *req,
grctx->src_ctx = gss_svc_upcall_get_ctx(req, gw);
if (!grctx->src_ctx) {
CDEBUG(D_SEC, "invalid gss context handle for destroy.\n");
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
if (gw->gw_svc != SPTLRPC_SVC_INTG) {
CERROR("svc %u is not supported in destroy.\n", gw->gw_svc);
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
if (gss_svc_verify_request(req, grctx, gw, &major))
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
CWARN("destroy svc ctx %p idx "LPX64" (%u->%s)\n",
grctx->src_ctx, gss_handle_to_u64(&gw->gw_handle),
@@ -2322,19 +2301,19 @@ int gss_svc_handle_destroy(struct ptlrpc_request *req,
if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
if (req->rq_reqbuf->lm_bufcount < 4) {
CERROR("missing user descriptor, ignore it\n");
- RETURN(SECSVC_OK);
+ return SECSVC_OK;
}
if (sptlrpc_unpack_user_desc(req->rq_reqbuf, 2,
ptlrpc_req_need_swab(req))) {
CERROR("Mal-formed user descriptor, ignore it\n");
- RETURN(SECSVC_OK);
+ return SECSVC_OK;
}
req->rq_pack_udesc = 1;
req->rq_user_desc = lustre_msg_buf(req->rq_reqbuf, 2, 0);
}
- RETURN(SECSVC_OK);
+ return SECSVC_OK;
}
int gss_svc_accept(struct ptlrpc_sec_policy *policy, struct ptlrpc_request *req)
@@ -2343,14 +2322,13 @@ int gss_svc_accept(struct ptlrpc_sec_policy *policy, struct ptlrpc_request *req)
struct gss_svc_reqctx *grctx;
struct gss_wire_ctx *gw;
int swabbed, rc;
- ENTRY;
LASSERT(req->rq_reqbuf);
LASSERT(req->rq_svc_ctx == NULL);
if (req->rq_reqbuf->lm_bufcount < 2) {
CERROR("buf count only %d\n", req->rq_reqbuf->lm_bufcount);
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
swabbed = ptlrpc_req_need_swab(req);
@@ -2358,14 +2336,14 @@ int gss_svc_accept(struct ptlrpc_sec_policy *policy, struct ptlrpc_request *req)
ghdr = gss_swab_header(req->rq_reqbuf, 0, swabbed);
if (ghdr == NULL) {
CERROR("can't decode gss header\n");
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
/* sanity checks */
if (ghdr->gh_version != PTLRPC_GSS_VERSION) {
CERROR("gss version %u, expect %u\n", ghdr->gh_version,
PTLRPC_GSS_VERSION);
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
req->rq_sp_from = ghdr->gh_sp;
@@ -2373,7 +2351,7 @@ int gss_svc_accept(struct ptlrpc_sec_policy *policy, struct ptlrpc_request *req)
/* alloc grctx data */
OBD_ALLOC_PTR(grctx);
if (!grctx)
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
grctx->src_base.sc_policy = sptlrpc_policy_get(policy);
atomic_set(&grctx->src_base.sc_refcount, 1);
@@ -2428,16 +2406,14 @@ int gss_svc_accept(struct ptlrpc_sec_policy *policy, struct ptlrpc_request *req)
break;
}
- RETURN(rc);
+ return rc;
}
void gss_svc_invalidate_ctx(struct ptlrpc_svc_ctx *svc_ctx)
{
struct gss_svc_reqctx *grctx;
- ENTRY;
if (svc_ctx == NULL) {
- EXIT;
return;
}
@@ -2446,8 +2422,6 @@ void gss_svc_invalidate_ctx(struct ptlrpc_svc_ctx *svc_ctx)
CWARN("gss svc invalidate ctx %p(%u)\n",
grctx->src_ctx, grctx->src_ctx->gsc_uid);
gss_svc_upcall_destroy_ctx(grctx->src_ctx);
-
- EXIT;
}
static inline
@@ -2496,13 +2470,12 @@ int gss_svc_alloc_rs(struct ptlrpc_request *req, int msglen)
__u32 ibuflens[2], buflens[4];
int ibufcnt = 0, bufcnt;
int txtsize, wmsg_size, rs_size;
- ENTRY;
LASSERT(msglen % 8 == 0);
if (req->rq_pack_bulk && !req->rq_bulk_read && !req->rq_bulk_write) {
CERROR("client request bulk sec on non-bulk rpc\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
svc = SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc);
@@ -2575,7 +2548,7 @@ int gss_svc_alloc_rs(struct ptlrpc_request *req, int msglen)
} else {
OBD_ALLOC_LARGE(rs, rs_size);
if (rs == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rs->rs_size = rs_size;
}
@@ -2605,7 +2578,7 @@ int gss_svc_alloc_rs(struct ptlrpc_request *req, int msglen)
LASSERT(rs->rs_msg);
req->rq_reply_state = rs;
- RETURN(0);
+ return 0;
}
static int gss_svc_seal(struct ptlrpc_request *req,
@@ -2619,7 +2592,6 @@ static int gss_svc_seal(struct ptlrpc_request *req,
int token_buflen;
__u32 buflens[2], major;
int msglen, rc;
- ENTRY;
/* get clear data length. note embedded lustre_msg might
* have been shrinked */
@@ -2647,7 +2619,7 @@ static int gss_svc_seal(struct ptlrpc_request *req,
token_buflen = gss_mech_payload(gctx->gsc_mechctx, msglen, 1);
OBD_ALLOC_LARGE(token_buf, token_buflen);
if (token_buf == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
hdrobj.len = PTLRPC_GSS_HEADER_SIZE;
hdrobj.data = (__u8 *) ghdr;
@@ -2703,7 +2675,7 @@ static int gss_svc_seal(struct ptlrpc_request *req,
rc = 0;
out_free:
OBD_FREE_LARGE(token_buf, token_buflen);
- RETURN(rc);
+ return rc;
}
int gss_svc_authorize(struct ptlrpc_request *req)
@@ -2712,7 +2684,6 @@ int gss_svc_authorize(struct ptlrpc_request *req)
struct gss_svc_reqctx *grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
struct gss_wire_ctx *gw = &grctx->src_wirectx;
int early, rc;
- ENTRY;
early = (req->rq_packed_final == 0);
@@ -2720,7 +2691,7 @@ int gss_svc_authorize(struct ptlrpc_request *req)
LASSERT(rs->rs_repdata_len != 0);
req->rq_reply_off = gss_at_reply_off_integ;
- RETURN(0);
+ return 0;
}
/* early reply could happen in many cases */
@@ -2728,7 +2699,7 @@ int gss_svc_authorize(struct ptlrpc_request *req)
gw->gw_proc != PTLRPC_GSS_PROC_DATA &&
gw->gw_proc != PTLRPC_GSS_PROC_DESTROY) {
CERROR("proc %d not support\n", gw->gw_proc);
- RETURN(-EINVAL);
+ return -EINVAL;
}
LASSERT(grctx->src_ctx);
@@ -2749,7 +2720,7 @@ int gss_svc_authorize(struct ptlrpc_request *req)
rc = 0;
out:
- RETURN(rc);
+ return rc;
}
void gss_svc_free_rs(struct ptlrpc_reply_state *rs)
diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c
index 47a3c051273..5ca69aec72e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/import.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/import.c
@@ -195,7 +195,6 @@ int ptlrpc_set_import_discon(struct obd_import *imp, __u32 conn_cnt)
/* Must be called with imp_lock held! */
static void ptlrpc_deactivate_and_unlock_import(struct obd_import *imp)
{
- ENTRY;
LASSERT(spin_is_locked(&imp->imp_lock));
CDEBUG(D_HA, "setting import %s INVALID\n", obd2cli_tgt(imp->imp_obd));
@@ -205,8 +204,6 @@ static void ptlrpc_deactivate_and_unlock_import(struct obd_import *imp)
ptlrpc_abort_inflight(imp);
obd_import_event(imp->imp_obd, imp, IMP_EVENT_INACTIVE);
-
- EXIT;
}
/*
@@ -394,8 +391,6 @@ EXPORT_SYMBOL(ptlrpc_activate_import);
void ptlrpc_fail_import(struct obd_import *imp, __u32 conn_cnt)
{
- ENTRY;
-
LASSERT(!imp->imp_dlm_fake);
if (ptlrpc_set_import_discon(imp, conn_cnt)) {
@@ -417,7 +412,6 @@ void ptlrpc_fail_import(struct obd_import *imp, __u32 conn_cnt)
ptlrpc_pinger_wake_up();
}
- EXIT;
}
EXPORT_SYMBOL(ptlrpc_fail_import);
@@ -461,7 +455,6 @@ static int import_select_connection(struct obd_import *imp)
struct obd_export *dlmexp;
char *target_start;
int target_len, tried_all = 1;
- ENTRY;
spin_lock(&imp->imp_lock);
@@ -469,7 +462,7 @@ static int import_select_connection(struct obd_import *imp)
CERROR("%s: no connections available\n",
imp->imp_obd->obd_name);
spin_unlock(&imp->imp_lock);
- RETURN(-EINVAL);
+ return -EINVAL;
}
list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
@@ -558,7 +551,7 @@ static int import_select_connection(struct obd_import *imp)
spin_unlock(&imp->imp_lock);
- RETURN(0);
+ return 0;
}
/*
@@ -602,21 +595,20 @@ int ptlrpc_connect_import(struct obd_import *imp)
(char *)&imp->imp_connect_data };
struct ptlrpc_connect_async_args *aa;
int rc;
- ENTRY;
spin_lock(&imp->imp_lock);
if (imp->imp_state == LUSTRE_IMP_CLOSED) {
spin_unlock(&imp->imp_lock);
CERROR("can't connect to a closed import\n");
- RETURN(-EINVAL);
+ return -EINVAL;
} else if (imp->imp_state == LUSTRE_IMP_FULL) {
spin_unlock(&imp->imp_lock);
CERROR("already connected\n");
- RETURN(0);
+ return 0;
} else if (imp->imp_state == LUSTRE_IMP_CONNECTING) {
spin_unlock(&imp->imp_lock);
CERROR("already connecting\n");
- RETURN(-EALREADY);
+ return -EALREADY;
}
IMPORT_SET_STATE_NOLOCK(imp, LUSTRE_IMP_CONNECTING);
@@ -716,7 +708,7 @@ out:
IMPORT_SET_STATE(imp, LUSTRE_IMP_DISCON);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_connect_import);
@@ -756,13 +748,12 @@ static int ptlrpc_connect_interpret(const struct lu_env *env,
struct obd_connect_data *ocd;
struct obd_export *exp;
int ret;
- ENTRY;
spin_lock(&imp->imp_lock);
if (imp->imp_state == LUSTRE_IMP_CLOSED) {
imp->imp_connect_tried = 1;
spin_unlock(&imp->imp_lock);
- RETURN(0);
+ return 0;
}
if (rc) {
@@ -984,7 +975,7 @@ finish:
imp->imp_connection->c_remote_uuid.uuid);
ptlrpc_connect_import(imp);
imp->imp_connect_tried = 1;
- RETURN(0);
+ return 0;
}
} else {
@@ -1137,7 +1128,7 @@ out:
/* reply message might not be ready */
if (request->rq_repmsg == NULL)
- RETURN(-EPROTO);
+ return -EPROTO;
ocd = req_capsule_server_get(&request->rq_pill,
&RMF_CONNECT_DATA);
@@ -1161,7 +1152,7 @@ out:
ptlrpc_deactivate_import(imp);
IMPORT_SET_STATE(imp, LUSTRE_IMP_CLOSED);
}
- RETURN(-EPROTO);
+ return -EPROTO;
}
ptlrpc_maybe_ping_import_soon(imp);
@@ -1172,7 +1163,7 @@ out:
}
wake_up_all(&imp->imp_recovery_waitq);
- RETURN(rc);
+ return rc;
}
/**
@@ -1183,7 +1174,6 @@ static int completed_replay_interpret(const struct lu_env *env,
struct ptlrpc_request *req,
void * data, int rc)
{
- ENTRY;
atomic_dec(&req->rq_import->imp_replay_inflight);
if (req->rq_status == 0 &&
!req->rq_import->imp_vbr_failed) {
@@ -1202,7 +1192,7 @@ static int completed_replay_interpret(const struct lu_env *env,
ptlrpc_connect_import(req->rq_import);
}
- RETURN(0);
+ return 0;
}
/**
@@ -1212,10 +1202,9 @@ static int completed_replay_interpret(const struct lu_env *env,
static int signal_completed_replay(struct obd_import *imp)
{
struct ptlrpc_request *req;
- ENTRY;
if (unlikely(OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_FINISH_REPLAY)))
- RETURN(0);
+ return 0;
LASSERT(atomic_read(&imp->imp_replay_inflight) == 0);
atomic_inc(&imp->imp_replay_inflight);
@@ -1224,7 +1213,7 @@ static int signal_completed_replay(struct obd_import *imp)
OBD_PING);
if (req == NULL) {
atomic_dec(&imp->imp_replay_inflight);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
ptlrpc_request_set_replen(req);
@@ -1236,7 +1225,7 @@ static int signal_completed_replay(struct obd_import *imp)
req->rq_interpret_reply = completed_replay_interpret;
ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1);
- RETURN(0);
+ return 0;
}
/**
@@ -1248,8 +1237,6 @@ static int ptlrpc_invalidate_import_thread(void *data)
{
struct obd_import *imp = data;
- ENTRY;
-
unshare_fs_struct();
CDEBUG(D_HA, "thread invalidate import %s to %s@%s\n",
@@ -1267,7 +1254,7 @@ static int ptlrpc_invalidate_import_thread(void *data)
ptlrpc_import_recovery_state_machine(imp);
class_import_put(imp);
- RETURN(0);
+ return 0;
}
/**
@@ -1297,7 +1284,6 @@ int ptlrpc_import_recovery_state_machine(struct obd_import *imp)
char *target_start;
int target_len;
- ENTRY;
if (imp->imp_state == LUSTRE_IMP_EVICTED) {
deuuidify(obd2cli_tgt(imp->imp_obd), NULL,
&target_start, &target_len);
@@ -1319,7 +1305,7 @@ int ptlrpc_import_recovery_state_machine(struct obd_import *imp)
spin_unlock(&imp->imp_lock);
{
- task_t *task;
+ struct task_struct *task;
/* bug 17802: XXX client_disconnect_export vs connect request
* race. if client will evicted at this time, we start
* invalidate thread without reference to import and import can
@@ -1334,7 +1320,7 @@ int ptlrpc_import_recovery_state_machine(struct obd_import *imp)
} else {
rc = 0;
}
- RETURN(rc);
+ return rc;
}
}
@@ -1393,7 +1379,7 @@ int ptlrpc_import_recovery_state_machine(struct obd_import *imp)
}
out:
- RETURN(rc);
+ return rc;
}
int ptlrpc_disconnect_import(struct obd_import *imp, int noclose)
@@ -1401,7 +1387,6 @@ int ptlrpc_disconnect_import(struct obd_import *imp, int noclose)
struct ptlrpc_request *req;
int rq_opc, rc = 0;
int nowait = imp->imp_obd->obd_force;
- ENTRY;
if (nowait)
GOTO(set_state, rc);
@@ -1413,7 +1398,7 @@ int ptlrpc_disconnect_import(struct obd_import *imp, int noclose)
default:
CERROR("don't know how to disconnect from %s (connect_op %d)\n",
obd2cli_tgt(imp->imp_obd), imp->imp_connect_op);
- RETURN(-EINVAL);
+ return -EINVAL;
}
if (ptlrpc_import_in_recovery(imp)) {
@@ -1476,21 +1461,17 @@ out:
memset(&imp->imp_remote_handle, 0, sizeof(imp->imp_remote_handle));
spin_unlock(&imp->imp_lock);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_disconnect_import);
void ptlrpc_cleanup_imp(struct obd_import *imp)
{
- ENTRY;
-
spin_lock(&imp->imp_lock);
IMPORT_SET_STATE_NOLOCK(imp, LUSTRE_IMP_CLOSED);
imp->imp_generation++;
spin_unlock(&imp->imp_lock);
ptlrpc_abort_inflight(imp);
-
- EXIT;
}
EXPORT_SYMBOL(ptlrpc_cleanup_imp);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c
index 367ca8ef7d6..379e59477ea 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c
@@ -85,7 +85,6 @@ static int llog_client_open(const struct lu_env *env,
struct llog_ctxt *ctxt = lgh->lgh_ctxt;
struct ptlrpc_request *req = NULL;
int rc;
- ENTRY;
LLOG_CLIENT_ENTRY(ctxt, imp);
@@ -133,7 +132,6 @@ static int llog_client_open(const struct lu_env *env,
lgh->lgh_id = body->lgd_logid;
lgh->lgh_ctxt = ctxt;
- EXIT;
out:
LLOG_CLIENT_EXIT(ctxt, imp);
ptlrpc_req_finished(req);
@@ -147,7 +145,6 @@ static int llog_client_destroy(const struct lu_env *env,
struct ptlrpc_request *req = NULL;
struct llogd_body *body;
int rc;
- ENTRY;
LLOG_CLIENT_ENTRY(loghandle->lgh_ctxt, imp);
req = ptlrpc_request_alloc_pack(imp, &RQF_LLOG_ORIGIN_HANDLE_DESTROY,
@@ -170,7 +167,7 @@ static int llog_client_destroy(const struct lu_env *env,
ptlrpc_req_finished(req);
err_exit:
LLOG_CLIENT_EXIT(loghandle->lgh_ctxt, imp);
- RETURN(rc);
+ return rc;
}
@@ -184,7 +181,6 @@ static int llog_client_next_block(const struct lu_env *env,
struct llogd_body *body;
void *ptr;
int rc;
- ENTRY;
LLOG_CLIENT_ENTRY(loghandle->lgh_ctxt, imp);
req = ptlrpc_request_alloc_pack(imp, &RQF_LLOG_ORIGIN_HANDLE_NEXT_BLOCK,
@@ -221,7 +217,6 @@ static int llog_client_next_block(const struct lu_env *env,
*cur_offset = body->lgd_cur_offset;
memcpy(buf, ptr, len);
- EXIT;
out:
ptlrpc_req_finished(req);
err_exit:
@@ -238,7 +233,6 @@ static int llog_client_prev_block(const struct lu_env *env,
struct llogd_body *body;
void *ptr;
int rc;
- ENTRY;
LLOG_CLIENT_ENTRY(loghandle->lgh_ctxt, imp);
req = ptlrpc_request_alloc_pack(imp, &RQF_LLOG_ORIGIN_HANDLE_PREV_BLOCK,
@@ -270,7 +264,6 @@ static int llog_client_prev_block(const struct lu_env *env,
GOTO(out, rc =-EFAULT);
memcpy(buf, ptr, len);
- EXIT;
out:
ptlrpc_req_finished(req);
err_exit:
@@ -287,7 +280,6 @@ static int llog_client_read_header(const struct lu_env *env,
struct llog_log_hdr *hdr;
struct llog_rec_hdr *llh_hdr;
int rc;
- ENTRY;
LLOG_CLIENT_ENTRY(handle->lgh_ctxt, imp);
req = ptlrpc_request_alloc_pack(imp,&RQF_LLOG_ORIGIN_HANDLE_READ_HEADER,
@@ -326,7 +318,6 @@ static int llog_client_read_header(const struct lu_env *env,
CERROR("you may need to re-run lconf --write_conf.\n");
rc = -EIO;
}
- EXIT;
out:
ptlrpc_req_finished(req);
err_exit:
diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_net.c b/drivers/staging/lustre/lustre/ptlrpc/llog_net.c
index a81f557d779..17c06a32df6 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/llog_net.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/llog_net.c
@@ -57,7 +57,6 @@
int llog_initiator_connect(struct llog_ctxt *ctxt)
{
struct obd_import *new_imp;
- ENTRY;
LASSERT(ctxt);
new_imp = ctxt->loc_obd->u.cli.cl_import;
@@ -70,6 +69,6 @@ int llog_initiator_connect(struct llog_ctxt *ctxt)
ctxt->loc_imp = class_import_get(new_imp);
}
mutex_unlock(&ctxt->loc_mutex);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(llog_initiator_connect);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_server.c b/drivers/staging/lustre/lustre/ptlrpc/llog_server.c
index bc1fcd8c7e7..af9d2ac391e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/llog_server.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/llog_server.c
@@ -71,11 +71,9 @@ int llog_origin_handle_open(struct ptlrpc_request *req)
char *name = NULL;
int rc;
- ENTRY;
-
body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
if (body == NULL)
- RETURN(-EFAULT);
+ return -EFAULT;
if (ostid_id(&body->lgd_logid.lgl_oi) > 0)
logid = &body->lgd_logid;
@@ -83,7 +81,7 @@ int llog_origin_handle_open(struct ptlrpc_request *req)
if (req_capsule_field_present(&req->rq_pill, &RMF_NAME, RCL_CLIENT)) {
name = req_capsule_client_get(&req->rq_pill, &RMF_NAME);
if (name == NULL)
- RETURN(-EFAULT);
+ return -EFAULT;
CDEBUG(D_INFO, "%s: opening log %s\n", obd->obd_name, name);
}
@@ -91,7 +89,7 @@ int llog_origin_handle_open(struct ptlrpc_request *req)
if (ctxt == NULL) {
CDEBUG(D_WARNING, "%s: no ctxt. group=%p idx=%d name=%s\n",
obd->obd_name, &obd->obd_olg, body->lgd_ctxt_idx, name);
- RETURN(-ENODEV);
+ return -ENODEV;
}
disk_obd = ctxt->loc_exp->exp_obd;
push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
@@ -108,7 +106,6 @@ int llog_origin_handle_open(struct ptlrpc_request *req)
body = req_capsule_server_get(&req->rq_pill, &RMF_LLOGD_BODY);
body->lgd_logid = loghandle->lgh_id;
- EXIT;
out_close:
llog_origin_close(req->rq_svc_thread->t_env, loghandle);
out_pop:
@@ -127,11 +124,9 @@ int llog_origin_handle_destroy(struct ptlrpc_request *req)
struct llog_ctxt *ctxt;
int rc;
- ENTRY;
-
body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
if (body == NULL)
- RETURN(-EFAULT);
+ return -EFAULT;
if (ostid_id(&body->lgd_logid.lgl_oi) > 0)
logid = &body->lgd_logid;
@@ -142,7 +137,7 @@ int llog_origin_handle_destroy(struct ptlrpc_request *req)
ctxt = llog_get_context(req->rq_export->exp_obd, body->lgd_ctxt_idx);
if (ctxt == NULL)
- RETURN(-ENODEV);
+ return -ENODEV;
disk_obd = ctxt->loc_exp->exp_obd;
push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
@@ -153,7 +148,7 @@ int llog_origin_handle_destroy(struct ptlrpc_request *req)
rc = llog_erase(req->rq_svc_thread->t_env, ctxt, logid, NULL);
pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
llog_ctxt_put(ctxt);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(llog_origin_handle_destroy);
@@ -169,15 +164,13 @@ int llog_origin_handle_next_block(struct ptlrpc_request *req)
void *ptr;
int rc;
- ENTRY;
-
body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
if (body == NULL)
- RETURN(-EFAULT);
+ return -EFAULT;
ctxt = llog_get_context(req->rq_export->exp_obd, body->lgd_ctxt_idx);
if (ctxt == NULL)
- RETURN(-ENODEV);
+ return -ENODEV;
disk_obd = ctxt->loc_exp->exp_obd;
push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
@@ -208,7 +201,6 @@ int llog_origin_handle_next_block(struct ptlrpc_request *req)
&repbody->lgd_cur_offset, ptr, LLOG_CHUNK_SIZE);
if (rc)
GOTO(out_close, rc);
- EXIT;
out_close:
llog_origin_close(req->rq_svc_thread->t_env, loghandle);
out_pop:
@@ -230,15 +222,13 @@ int llog_origin_handle_prev_block(struct ptlrpc_request *req)
void *ptr;
int rc;
- ENTRY;
-
body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
if (body == NULL)
- RETURN(-EFAULT);
+ return -EFAULT;
ctxt = llog_get_context(req->rq_export->exp_obd, body->lgd_ctxt_idx);
if (ctxt == NULL)
- RETURN(-ENODEV);
+ return -ENODEV;
disk_obd = ctxt->loc_exp->exp_obd;
push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
@@ -269,7 +259,6 @@ int llog_origin_handle_prev_block(struct ptlrpc_request *req)
if (rc)
GOTO(out_close, rc);
- EXIT;
out_close:
llog_origin_close(req->rq_svc_thread->t_env, loghandle);
out_pop:
@@ -290,15 +279,13 @@ int llog_origin_handle_read_header(struct ptlrpc_request *req)
__u32 flags;
int rc;
- ENTRY;
-
body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
if (body == NULL)
- RETURN(-EFAULT);
+ return -EFAULT;
ctxt = llog_get_context(req->rq_export->exp_obd, body->lgd_ctxt_idx);
if (ctxt == NULL)
- RETURN(-ENODEV);
+ return -ENODEV;
disk_obd = ctxt->loc_exp->exp_obd;
push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
@@ -324,7 +311,6 @@ int llog_origin_handle_read_header(struct ptlrpc_request *req)
hdr = req_capsule_server_get(&req->rq_pill, &RMF_LLOG_LOG_HDR);
*hdr = *loghandle->lgh_hdr;
- EXIT;
out_close:
llog_origin_close(req->rq_svc_thread->t_env, loghandle);
out_pop:
@@ -336,9 +322,8 @@ EXPORT_SYMBOL(llog_origin_handle_read_header);
int llog_origin_handle_close(struct ptlrpc_request *req)
{
- ENTRY;
/* Nothing to do */
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(llog_origin_handle_close);
@@ -352,20 +337,19 @@ int llog_origin_handle_cancel(struct ptlrpc_request *req)
struct llog_handle *cathandle;
struct inode *inode;
void *handle;
- ENTRY;
logcookies = req_capsule_client_get(&req->rq_pill, &RMF_LOGCOOKIES);
num_cookies = req_capsule_get_size(&req->rq_pill, &RMF_LOGCOOKIES,
RCL_CLIENT) / sizeof(*logcookies);
if (logcookies == NULL || num_cookies == 0) {
DEBUG_REQ(D_HA, req, "No llog cookies sent");
- RETURN(-EFAULT);
+ return -EFAULT;
}
ctxt = llog_get_context(req->rq_export->exp_obd,
logcookies->lgc_subsys);
if (ctxt == NULL)
- RETURN(-ENODEV);
+ return -ENODEV;
disk_obd = ctxt->loc_exp->exp_obd;
push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
index 3e7325499d0..bea44a3d4a2 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
@@ -302,7 +302,7 @@ ptlrpc_lprocfs_req_history_max_seq_write(struct file *file, const char *buffer,
* hose a kernel by allowing the request history to grow too
* far. */
bufpages = (svc->srv_buf_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- if (val > num_physpages/(2 * bufpages))
+ if (val > totalram_pages / (2 * bufpages))
return -ERANGE;
spin_lock(&svc->srv_lock);
@@ -480,7 +480,6 @@ static int ptlrpc_lprocfs_nrs_seq_show(struct seq_file *m, void *n)
bool hp = false;
int i;
int rc = 0;
- ENTRY;
/**
* Serialize NRS core lprocfs operations with policy registration/
@@ -613,7 +612,7 @@ out:
mutex_unlock(&nrs_core.nrs_mutex);
- RETURN(rc);
+ return rc;
}
/**
@@ -638,7 +637,6 @@ static ssize_t ptlrpc_lprocfs_nrs_seq_write(struct file *file, const char *buffe
char *cmd_copy = NULL;
char *token;
int rc = 0;
- ENTRY;
if (count >= LPROCFS_NRS_WR_MAX_CMD)
GOTO(out, rc = -EINVAL);
@@ -698,7 +696,7 @@ out:
if (cmd_copy)
OBD_FREE(cmd_copy, LPROCFS_NRS_WR_MAX_CMD);
- RETURN(rc < 0 ? rc : count);
+ return rc < 0 ? rc : count;
}
LPROC_SEQ_FOPS(ptlrpc_lprocfs_nrs);
@@ -1217,13 +1215,12 @@ int lprocfs_wr_ping(struct file *file, const char *buffer,
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
struct ptlrpc_request *req;
int rc;
- ENTRY;
LPROCFS_CLIMP_CHECK(obd);
req = ptlrpc_prep_ping(obd->u.cli.cl_import);
LPROCFS_CLIMP_EXIT(obd);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req->rq_send_state = LUSTRE_IMP_FULL;
@@ -1231,8 +1228,8 @@ int lprocfs_wr_ping(struct file *file, const char *buffer,
ptlrpc_req_finished(req);
if (rc >= 0)
- RETURN(count);
- RETURN(rc);
+ return count;
+ return rc;
}
EXPORT_SYMBOL(lprocfs_wr_ping);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
index de3f0db0ba4..a0e009717a5 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
@@ -54,7 +54,6 @@ static int ptl_send_buf (lnet_handle_md_t *mdh, void *base, int len,
{
int rc;
lnet_md_t md;
- ENTRY;
LASSERT (portal != 0);
LASSERT (conn != NULL);
@@ -76,7 +75,7 @@ static int ptl_send_buf (lnet_handle_md_t *mdh, void *base, int len,
if (unlikely(rc != 0)) {
CERROR ("LNetMDBind failed: %d\n", rc);
LASSERT (rc == -ENOMEM);
- RETURN (-ENOMEM);
+ return -ENOMEM;
}
CDEBUG(D_NET, "Sending %d bytes to portal %d, xid "LPD64", offset %u\n",
@@ -95,7 +94,7 @@ static int ptl_send_buf (lnet_handle_md_t *mdh, void *base, int len,
LASSERTF(rc2 == 0, "rc2 = %d\n", rc2);
}
- RETURN (0);
+ return 0;
}
static void mdunlink_iterate_helper(lnet_handle_md_t *bd_mds, int count)
@@ -122,10 +121,9 @@ int ptlrpc_register_bulk(struct ptlrpc_request *req)
__u64 xid;
lnet_handle_me_t me_h;
lnet_md_t md;
- ENTRY;
if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_BULK_GET_NET))
- RETURN(0);
+ return 0;
/* NB no locking required until desc is on the network */
LASSERT(desc->bd_nob > 0);
@@ -207,7 +205,7 @@ int ptlrpc_register_bulk(struct ptlrpc_request *req)
LASSERT(desc->bd_md_count >= 0);
mdunlink_iterate_helper(desc->bd_mds, desc->bd_md_max_brw);
req->rq_status = -ENOMEM;
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
/* Set rq_xid to matchbits of the final bulk so that server can
@@ -231,7 +229,7 @@ int ptlrpc_register_bulk(struct ptlrpc_request *req)
desc->bd_iov_count, desc->bd_nob,
desc->bd_last_xid, req->rq_xid, desc->bd_portal);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ptlrpc_register_bulk);
@@ -247,7 +245,6 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async)
wait_queue_head_t *wq;
struct l_wait_info lwi;
int rc;
- ENTRY;
LASSERT(!in_interrupt()); /* might sleep */
@@ -257,7 +254,7 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async)
req->rq_bulk_deadline = cfs_time_current_sec() + LONG_UNLINK;
if (ptlrpc_client_bulk_active(req) == 0) /* completed or */
- RETURN(1); /* never registered */
+ return 1; /* never registered */
LASSERT(desc->bd_req == req); /* bd_req NULL until registered */
@@ -268,14 +265,14 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async)
mdunlink_iterate_helper(desc->bd_mds, desc->bd_md_max_brw);
if (ptlrpc_client_bulk_active(req) == 0) /* completed or */
- RETURN(1); /* never registered */
+ return 1; /* never registered */
/* Move to "Unregistering" phase as bulk was not unlinked yet. */
ptlrpc_rqphase_move(req, RQ_PHASE_UNREGISTERING);
/* Do not wait for unlink to finish. */
if (async)
- RETURN(0);
+ return 0;
if (req->rq_set != NULL)
wq = &req->rq_set->set_waitq;
@@ -290,14 +287,14 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async)
rc = l_wait_event(*wq, !ptlrpc_client_bulk_active(req), &lwi);
if (rc == 0) {
ptlrpc_rqphase_move(req, req->rq_next_phase);
- RETURN(1);
+ return 1;
}
LASSERT(rc == -ETIMEDOUT);
DEBUG_REQ(D_WARNING, req, "Unexpectedly long timeout: desc %p",
desc);
}
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ptlrpc_unregister_bulk);
@@ -400,7 +397,8 @@ int ptlrpc_send_reply(struct ptlrpc_request *req, int flags)
req->rq_type = PTL_RPC_MSG_REPLY;
lustre_msg_set_type(req->rq_repmsg, req->rq_type);
- lustre_msg_set_status(req->rq_repmsg, req->rq_status);
+ lustre_msg_set_status(req->rq_repmsg,
+ ptlrpc_status_hton(req->rq_status));
lustre_msg_set_opc(req->rq_repmsg,
req->rq_reqmsg ? lustre_msg_get_opc(req->rq_reqmsg) : 0);
@@ -455,15 +453,14 @@ EXPORT_SYMBOL(ptlrpc_reply);
int ptlrpc_send_error(struct ptlrpc_request *req, int may_be_difficult)
{
int rc;
- ENTRY;
if (req->rq_no_reply)
- RETURN(0);
+ return 0;
if (!req->rq_repmsg) {
rc = lustre_pack_reply(req, 1, NULL, NULL);
if (rc)
- RETURN(rc);
+ return rc;
}
if (req->rq_status != -ENOSPC && req->rq_status != -EACCES &&
@@ -472,7 +469,7 @@ int ptlrpc_send_error(struct ptlrpc_request *req, int may_be_difficult)
req->rq_type = PTL_RPC_MSG_ERR;
rc = ptlrpc_send_reply(req, may_be_difficult);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_send_error);
@@ -497,10 +494,9 @@ int ptl_send_rpc(struct ptlrpc_request *request, int noreply)
lnet_handle_me_t reply_me_h;
lnet_md_t reply_md;
struct obd_device *obd = request->rq_import->imp_obd;
- ENTRY;
if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_DROP_RPC))
- RETURN(0);
+ return 0;
LASSERT(request->rq_type == PTL_RPC_MSG_REQUEST);
LASSERT(request->rq_wait_ctx == 0);
@@ -516,7 +512,7 @@ int ptl_send_rpc(struct ptlrpc_request *request, int noreply)
/* this prevents us from waiting in ptlrpc_queue_wait */
request->rq_err = 1;
request->rq_status = -ENODEV;
- RETURN(-ENODEV);
+ return -ENODEV;
}
connection = request->rq_import->imp_connection;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/nrs.c b/drivers/staging/lustre/lustre/ptlrpc/nrs.c
index 1996431e35f..0abcd6d8227 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/nrs.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/nrs.c
@@ -81,17 +81,16 @@ static int nrs_policy_ctl_locked(struct ptlrpc_nrs_policy *policy,
* policy->pol_private will be NULL in such a case.
*/
if (policy->pol_state == NRS_POL_STATE_STOPPED)
- RETURN(-ENODEV);
+ return -ENODEV;
- RETURN(policy->pol_desc->pd_ops->op_policy_ctl != NULL ?
+ return policy->pol_desc->pd_ops->op_policy_ctl != NULL ?
policy->pol_desc->pd_ops->op_policy_ctl(policy, opc, arg) :
- -ENOSYS);
+ -ENOSYS;
}
static void nrs_policy_stop0(struct ptlrpc_nrs_policy *policy)
{
struct ptlrpc_nrs *nrs = policy->pol_nrs;
- ENTRY;
if (policy->pol_desc->pd_ops->op_policy_stop != NULL) {
spin_unlock(&nrs->nrs_lock);
@@ -111,24 +110,21 @@ static void nrs_policy_stop0(struct ptlrpc_nrs_policy *policy)
if (atomic_dec_and_test(&policy->pol_desc->pd_refs))
module_put(policy->pol_desc->pd_owner);
-
- EXIT;
}
static int nrs_policy_stop_locked(struct ptlrpc_nrs_policy *policy)
{
struct ptlrpc_nrs *nrs = policy->pol_nrs;
- ENTRY;
if (nrs->nrs_policy_fallback == policy && !nrs->nrs_stopping)
- RETURN(-EPERM);
+ return -EPERM;
if (policy->pol_state == NRS_POL_STATE_STARTING)
- RETURN(-EAGAIN);
+ return -EAGAIN;
/* In progress or already stopped */
if (policy->pol_state != NRS_POL_STATE_STARTED)
- RETURN(0);
+ return 0;
policy->pol_state = NRS_POL_STATE_STOPPING;
@@ -145,7 +141,7 @@ static int nrs_policy_stop_locked(struct ptlrpc_nrs_policy *policy)
if (policy->pol_ref == 1)
nrs_policy_stop0(policy);
- RETURN(0);
+ return 0;
}
/**
@@ -158,15 +154,8 @@ static int nrs_policy_stop_locked(struct ptlrpc_nrs_policy *policy)
static void nrs_policy_stop_primary(struct ptlrpc_nrs *nrs)
{
struct ptlrpc_nrs_policy *tmp = nrs->nrs_policy_primary;
- ENTRY;
if (tmp == NULL) {
- /**
- * XXX: This should really be RETURN_EXIT, but the latter does
- * not currently print anything out, and possibly should be
- * fixed to do so.
- */
- EXIT;
return;
}
@@ -177,7 +166,6 @@ static void nrs_policy_stop_primary(struct ptlrpc_nrs *nrs)
if (tmp->pol_ref == 0)
nrs_policy_stop0(tmp);
- EXIT;
}
/**
@@ -203,19 +191,18 @@ static int nrs_policy_start_locked(struct ptlrpc_nrs_policy *policy)
{
struct ptlrpc_nrs *nrs = policy->pol_nrs;
int rc = 0;
- ENTRY;
/**
* Don't allow multiple starting which is too complex, and has no real
* benefit.
*/
if (nrs->nrs_policy_starting)
- RETURN(-EAGAIN);
+ return -EAGAIN;
LASSERT(policy->pol_state != NRS_POL_STATE_STARTING);
if (policy->pol_state == NRS_POL_STATE_STOPPING)
- RETURN(-EAGAIN);
+ return -EAGAIN;
if (policy->pol_flags & PTLRPC_NRS_FL_FALLBACK) {
/**
@@ -226,7 +213,7 @@ static int nrs_policy_start_locked(struct ptlrpc_nrs_policy *policy)
*/
if (policy == nrs->nrs_policy_fallback) {
nrs_policy_stop_primary(nrs);
- RETURN(0);
+ return 0;
}
/**
@@ -241,10 +228,10 @@ static int nrs_policy_start_locked(struct ptlrpc_nrs_policy *policy)
* Shouldn't start primary policy if w/o fallback policy.
*/
if (nrs->nrs_policy_fallback == NULL)
- RETURN(-EPERM);
+ return -EPERM;
if (policy->pol_state == NRS_POL_STATE_STARTED)
- RETURN(0);
+ return 0;
}
/**
@@ -256,7 +243,7 @@ static int nrs_policy_start_locked(struct ptlrpc_nrs_policy *policy)
atomic_dec(&policy->pol_desc->pd_refs);
CERROR("NRS: cannot get module for policy %s; is it alive?\n",
policy->pol_desc->pd_name);
- RETURN(-ENODEV);
+ return -ENODEV;
}
/**
@@ -303,7 +290,7 @@ static int nrs_policy_start_locked(struct ptlrpc_nrs_policy *policy)
out:
nrs->nrs_policy_starting = 0;
- RETURN(rc);
+ return rc;
}
/**
@@ -644,7 +631,6 @@ static int nrs_policy_ctl(struct ptlrpc_nrs *nrs, char *name,
{
struct ptlrpc_nrs_policy *policy;
int rc = 0;
- ENTRY;
spin_lock(&nrs->nrs_lock);
@@ -674,7 +660,7 @@ out:
spin_unlock(&nrs->nrs_lock);
- RETURN(rc);
+ return rc;
}
/**
@@ -690,7 +676,6 @@ out:
static int nrs_policy_unregister(struct ptlrpc_nrs *nrs, char *name)
{
struct ptlrpc_nrs_policy *policy = NULL;
- ENTRY;
spin_lock(&nrs->nrs_lock);
@@ -699,7 +684,7 @@ static int nrs_policy_unregister(struct ptlrpc_nrs *nrs, char *name)
spin_unlock(&nrs->nrs_lock);
CERROR("Can't find NRS policy %s\n", name);
- RETURN(-ENOENT);
+ return -ENOENT;
}
if (policy->pol_ref > 1) {
@@ -708,7 +693,7 @@ static int nrs_policy_unregister(struct ptlrpc_nrs *nrs, char *name)
nrs_policy_put_locked(policy);
spin_unlock(&nrs->nrs_lock);
- RETURN(-EBUSY);
+ return -EBUSY;
}
LASSERT(policy->pol_req_queued == 0);
@@ -731,7 +716,7 @@ static int nrs_policy_unregister(struct ptlrpc_nrs *nrs, char *name)
LASSERT(policy->pol_private == NULL);
OBD_FREE_PTR(policy);
- RETURN(0);
+ return 0;
}
/**
@@ -751,7 +736,6 @@ static int nrs_policy_register(struct ptlrpc_nrs *nrs,
struct ptlrpc_nrs_policy *tmp;
struct ptlrpc_service_part *svcpt = nrs->nrs_svcpt;
int rc;
- ENTRY;
LASSERT(svcpt != NULL);
LASSERT(desc->pd_ops != NULL);
@@ -764,7 +748,7 @@ static int nrs_policy_register(struct ptlrpc_nrs *nrs,
OBD_CPT_ALLOC_GFP(policy, svcpt->scp_service->srv_cptable,
svcpt->scp_cpt, sizeof(*policy), __GFP_IO);
if (policy == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
policy->pol_nrs = nrs;
policy->pol_desc = desc;
@@ -777,7 +761,7 @@ static int nrs_policy_register(struct ptlrpc_nrs *nrs,
rc = nrs_policy_init(policy);
if (rc != 0) {
OBD_FREE_PTR(policy);
- RETURN(rc);
+ return rc;
}
spin_lock(&nrs->nrs_lock);
@@ -793,7 +777,7 @@ static int nrs_policy_register(struct ptlrpc_nrs *nrs,
nrs_policy_fini(policy);
OBD_FREE_PTR(policy);
- RETURN(-EEXIST);
+ return -EEXIST;
}
list_add_tail(&policy->pol_list, &nrs->nrs_policy_list);
@@ -807,7 +791,7 @@ static int nrs_policy_register(struct ptlrpc_nrs *nrs,
if (rc != 0)
(void) nrs_policy_unregister(nrs, policy->pol_desc->pd_name);
- RETURN(rc);
+ return rc;
}
/**
@@ -844,7 +828,6 @@ static void ptlrpc_nrs_req_add_nolock(struct ptlrpc_request *req)
static void ptlrpc_nrs_hpreq_add_nolock(struct ptlrpc_request *req)
{
int opc = lustre_msg_get_opc(req->rq_reqmsg);
- ENTRY;
spin_lock(&req->rq_lock);
req->rq_hp = 1;
@@ -852,7 +835,6 @@ static void ptlrpc_nrs_hpreq_add_nolock(struct ptlrpc_request *req)
if (opc != OBD_PING)
DEBUG_REQ(D_NET, req, "high priority req");
spin_unlock(&req->rq_lock);
- EXIT;
}
/**
@@ -891,7 +873,6 @@ static int nrs_register_policies_locked(struct ptlrpc_nrs *nrs)
struct ptlrpc_service_part *svcpt = nrs->nrs_svcpt;
struct ptlrpc_service *svc = svcpt->scp_service;
int rc = -EINVAL;
- ENTRY;
LASSERT(mutex_is_locked(&nrs_core.nrs_mutex));
@@ -912,7 +893,7 @@ static int nrs_register_policies_locked(struct ptlrpc_nrs *nrs)
}
}
- RETURN(rc);
+ return rc;
}
/**
@@ -950,7 +931,7 @@ static int nrs_svcpt_setup_locked0(struct ptlrpc_nrs *nrs,
rc = nrs_register_policies_locked(nrs);
- RETURN(rc);
+ return rc;
}
/**
@@ -966,7 +947,6 @@ static int nrs_svcpt_setup_locked(struct ptlrpc_service_part *svcpt)
{
struct ptlrpc_nrs *nrs;
int rc;
- ENTRY;
LASSERT(mutex_is_locked(&nrs_core.nrs_mutex));
@@ -994,7 +974,7 @@ static int nrs_svcpt_setup_locked(struct ptlrpc_service_part *svcpt)
rc = nrs_svcpt_setup_locked0(nrs, svcpt);
out:
- RETURN(rc);
+ return rc;
}
/**
@@ -1012,7 +992,6 @@ static void nrs_svcpt_cleanup_locked(struct ptlrpc_service_part *svcpt)
struct ptlrpc_nrs_policy *tmp;
int rc;
bool hp = false;
- ENTRY;
LASSERT(mutex_is_locked(&nrs_core.nrs_mutex));
@@ -1036,8 +1015,6 @@ again:
if (hp)
OBD_FREE_PTR(nrs);
-
- EXIT;
}
/**
@@ -1051,13 +1028,12 @@ again:
static struct ptlrpc_nrs_pol_desc *nrs_policy_find_desc_locked(const char *name)
{
struct ptlrpc_nrs_pol_desc *tmp;
- ENTRY;
list_for_each_entry(tmp, &nrs_core.nrs_policies, pd_list) {
if (strncmp(tmp->pd_name, name, NRS_POL_NAME_MAX) == 0)
- RETURN(tmp);
+ return tmp;
}
- RETURN(NULL);
+ return NULL;
}
/**
@@ -1079,7 +1055,6 @@ static int nrs_policy_unregister_locked(struct ptlrpc_nrs_pol_desc *desc)
struct ptlrpc_service_part *svcpt;
int i;
int rc = 0;
- ENTRY;
LASSERT(mutex_is_locked(&nrs_core.nrs_mutex));
LASSERT(mutex_is_locked(&ptlrpc_all_services_mutex));
@@ -1107,7 +1082,7 @@ again:
"partition %d of service %s: %d\n",
desc->pd_name, svcpt->scp_cpt,
svcpt->scp_service->srv_name, rc);
- RETURN(rc);
+ return rc;
}
if (!hp && nrs_svc_has_hp(svc)) {
@@ -1120,7 +1095,7 @@ again:
desc->pd_ops->op_lprocfs_fini(svc);
}
- RETURN(rc);
+ return rc;
}
/**
@@ -1143,7 +1118,6 @@ int ptlrpc_nrs_policy_register(struct ptlrpc_nrs_pol_conf *conf)
struct ptlrpc_service *svc;
struct ptlrpc_nrs_pol_desc *desc;
int rc = 0;
- ENTRY;
LASSERT(conf != NULL);
LASSERT(conf->nc_ops != NULL);
@@ -1171,7 +1145,7 @@ int ptlrpc_nrs_policy_register(struct ptlrpc_nrs_pol_conf *conf)
"policy flags; external policies cannot act as fallback "
"policies, or be started immediately upon registration "
"without interaction with lprocfs\n", conf->nc_name);
- RETURN(-EINVAL);
+ return -EINVAL;
}
mutex_lock(&nrs_core.nrs_mutex);
@@ -1274,7 +1248,7 @@ internal:
fail:
mutex_unlock(&nrs_core.nrs_mutex);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_nrs_policy_register);
@@ -1296,14 +1270,13 @@ int ptlrpc_nrs_policy_unregister(struct ptlrpc_nrs_pol_conf *conf)
{
struct ptlrpc_nrs_pol_desc *desc;
int rc;
- ENTRY;
LASSERT(conf != NULL);
if (conf->nc_flags & PTLRPC_NRS_FL_FALLBACK) {
CERROR("Unable to unregister a fallback policy, unless the "
"PTLRPC service is stopping.\n");
- RETURN(-EPERM);
+ return -EPERM;
}
conf->nc_name[NRS_POL_NAME_MAX - 1] = '\0';
@@ -1341,7 +1314,7 @@ fail:
not_exist:
mutex_unlock(&nrs_core.nrs_mutex);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_nrs_policy_unregister);
@@ -1396,7 +1369,7 @@ failed:
mutex_unlock(&nrs_core.nrs_mutex);
- RETURN(rc);
+ return rc;
}
/**
@@ -1630,7 +1603,6 @@ void ptlrpc_nrs_req_hp_move(struct ptlrpc_request *req)
struct ptlrpc_nrs_request *nrq = &req->rq_nrq;
struct ptlrpc_nrs_resource *res1[NRS_RES_MAX];
struct ptlrpc_nrs_resource *res2[NRS_RES_MAX];
- ENTRY;
/**
* Obtain the high-priority NRS head resources.
@@ -1660,7 +1632,6 @@ out:
* returned false.
*/
nrs_resource_put_safe(res1);
- EXIT;
}
/**
@@ -1696,7 +1667,6 @@ int ptlrpc_nrs_policy_control(const struct ptlrpc_service *svc,
struct ptlrpc_service_part *svcpt;
int i;
int rc = 0;
- ENTRY;
LASSERT(opc != PTLRPC_NRS_CTL_INVALID);
@@ -1728,7 +1698,7 @@ int ptlrpc_nrs_policy_control(const struct ptlrpc_service *svc,
}
}
out:
- RETURN(rc);
+ return rc;
}
@@ -1745,7 +1715,6 @@ extern struct ptlrpc_nrs_pol_conf nrs_conf_fifo;
int ptlrpc_nrs_init(void)
{
int rc;
- ENTRY;
mutex_init(&nrs_core.nrs_mutex);
INIT_LIST_HEAD(&nrs_core.nrs_policies);
@@ -1755,7 +1724,7 @@ int ptlrpc_nrs_init(void)
GOTO(fail, rc);
- RETURN(rc);
+ return rc;
fail:
/**
* Since no PTLRPC services have been started at this point, all we need
@@ -1763,7 +1732,7 @@ fail:
*/
ptlrpc_nrs_fini();
- RETURN(rc);
+ return rc;
}
/**
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
index 1437636dfe2..cd2611a3b53 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
@@ -115,7 +115,7 @@ int lustre_msg_check_version(struct lustre_msg *msg, __u32 version)
EXPORT_SYMBOL(lustre_msg_check_version);
/* early reply size */
-int lustre_msg_early_size()
+int lustre_msg_early_size(void)
{
static int size = 0;
if (!size) {
@@ -329,7 +329,6 @@ int lustre_pack_reply_v2(struct ptlrpc_request *req, int count,
{
struct ptlrpc_reply_state *rs;
int msg_len, rc;
- ENTRY;
LASSERT(req->rq_reply_state == NULL);
@@ -342,7 +341,7 @@ int lustre_pack_reply_v2(struct ptlrpc_request *req, int count,
msg_len = lustre_msg_size_v2(count, lens);
rc = sptlrpc_svc_alloc_rs(req, msg_len);
if (rc)
- RETURN(rc);
+ return rc;
rs = req->rq_reply_state;
atomic_set(&rs->rs_refcount, 1); /* 1 ref for rq_reply_state */
@@ -363,7 +362,7 @@ int lustre_pack_reply_v2(struct ptlrpc_request *req, int count,
PTLRPC_RS_DEBUG_LRU_ADD(rs);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(lustre_pack_reply_v2);
@@ -574,7 +573,6 @@ static int lustre_unpack_msg_v2(struct lustre_msg_v2 *m, int len)
int __lustre_unpack_msg(struct lustre_msg *m, int len)
{
int required_len, rc;
- ENTRY;
/* We can provide a slightly better error log, if we check the
* message magic and version first. In the future, struct
@@ -588,12 +586,12 @@ int __lustre_unpack_msg(struct lustre_msg *m, int len)
/* can't even look inside the message */
CERROR("message length %d too small for magic/version check\n",
len);
- RETURN(-EINVAL);
+ return -EINVAL;
}
rc = lustre_unpack_msg_v2(m, len);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(__lustre_unpack_msg);
@@ -642,6 +640,9 @@ static inline int lustre_unpack_ptlrpc_body_v2(struct ptlrpc_request *req,
return -EINVAL;
}
+ if (!inout)
+ pb->pb_status = ptlrpc_status_ntoh(pb->pb_status);
+
return 0;
}
@@ -1613,11 +1614,10 @@ int do_set_info_async(struct obd_import *imp,
struct ptlrpc_request *req;
char *tmp;
int rc;
- ENTRY;
req = ptlrpc_request_alloc(imp, &RQF_OBD_SET_INFO);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req_capsule_set_size(&req->rq_pill, &RMF_SETINFO_KEY,
RCL_CLIENT, keylen);
@@ -1626,7 +1626,7 @@ int do_set_info_async(struct obd_import *imp,
rc = ptlrpc_request_pack(req, version, opcode);
if (rc) {
ptlrpc_request_free(req);
- RETURN(rc);
+ return rc;
}
tmp = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_KEY);
@@ -1644,7 +1644,7 @@ int do_set_info_async(struct obd_import *imp,
ptlrpc_req_finished(req);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(do_set_info_async);
@@ -2163,7 +2163,6 @@ static void lustre_swab_lmm_oi(struct ost_id *oi)
static void lustre_swab_lov_user_md_common(struct lov_user_md_v1 *lum)
{
- ENTRY;
__swab32s(&lum->lmm_magic);
__swab32s(&lum->lmm_pattern);
lustre_swab_lmm_oi(&lum->lmm_oi);
@@ -2171,31 +2170,25 @@ static void lustre_swab_lov_user_md_common(struct lov_user_md_v1 *lum)
__swab16s(&lum->lmm_stripe_count);
__swab16s(&lum->lmm_stripe_offset);
print_lum(lum);
- EXIT;
}
void lustre_swab_lov_user_md_v1(struct lov_user_md_v1 *lum)
{
- ENTRY;
CDEBUG(D_IOCTL, "swabbing lov_user_md v1\n");
lustre_swab_lov_user_md_common(lum);
- EXIT;
}
EXPORT_SYMBOL(lustre_swab_lov_user_md_v1);
void lustre_swab_lov_user_md_v3(struct lov_user_md_v3 *lum)
{
- ENTRY;
CDEBUG(D_IOCTL, "swabbing lov_user_md v3\n");
lustre_swab_lov_user_md_common((struct lov_user_md_v1 *)lum);
/* lmm_pool_name nothing to do with char */
- EXIT;
}
EXPORT_SYMBOL(lustre_swab_lov_user_md_v3);
void lustre_swab_lov_mds_md(struct lov_mds_md *lmm)
{
- ENTRY;
CDEBUG(D_IOCTL, "swabbing lov_mds_md\n");
__swab32s(&lmm->lmm_magic);
__swab32s(&lmm->lmm_pattern);
@@ -2203,7 +2196,6 @@ void lustre_swab_lov_mds_md(struct lov_mds_md *lmm)
__swab32s(&lmm->lmm_stripe_size);
__swab16s(&lmm->lmm_stripe_count);
__swab16s(&lmm->lmm_layout_gen);
- EXIT;
}
EXPORT_SYMBOL(lustre_swab_lov_mds_md);
@@ -2211,13 +2203,12 @@ void lustre_swab_lov_user_md_objects(struct lov_user_ost_data *lod,
int stripe_count)
{
int i;
- ENTRY;
+
for (i = 0; i < stripe_count; i++) {
lustre_swab_ost_id(&(lod[i].l_ost_oi));
__swab32s(&(lod[i].l_ost_gen));
__swab32s(&(lod[i].l_ost_idx));
}
- EXIT;
}
EXPORT_SYMBOL(lustre_swab_lov_user_md_objects);
@@ -2459,6 +2450,7 @@ void _debug_req(struct ptlrpc_request *req,
rep_ok ? lustre_msg_get_flags(req->rq_repmsg) : -1,
req->rq_status,
rep_ok ? lustre_msg_get_status(req->rq_repmsg) : -1);
+ va_end(args);
}
EXPORT_SYMBOL(_debug_req);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
index ef5269aee0d..227a0ae9593 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
@@ -51,7 +51,7 @@ struct mutex pinger_mutex;
static LIST_HEAD(pinger_imports);
static struct list_head timeout_list = LIST_HEAD_INIT(timeout_list);
-int ptlrpc_pinger_suppress_pings()
+int ptlrpc_pinger_suppress_pings(void)
{
return suppress_pings;
}
@@ -75,11 +75,10 @@ int ptlrpc_obd_ping(struct obd_device *obd)
{
int rc;
struct ptlrpc_request *req;
- ENTRY;
req = ptlrpc_prep_ping(obd->u.cli.cl_import);
if (req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req->rq_send_state = LUSTRE_IMP_FULL;
@@ -87,28 +86,27 @@ int ptlrpc_obd_ping(struct obd_device *obd)
ptlrpc_req_finished(req);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_obd_ping);
int ptlrpc_ping(struct obd_import *imp)
{
struct ptlrpc_request *req;
- ENTRY;
req = ptlrpc_prep_ping(imp);
if (req == NULL) {
CERROR("OOM trying to ping %s->%s\n",
imp->imp_obd->obd_uuid.uuid,
obd2cli_tgt(imp->imp_obd));
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
DEBUG_REQ(D_INFO, req, "pinging %s->%s",
imp->imp_obd->obd_uuid.uuid, obd2cli_tgt(imp->imp_obd));
ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1);
- RETURN(0);
+ return 0;
}
void ptlrpc_update_next_ping(struct obd_import *imp, int soon)
@@ -297,7 +295,6 @@ static void ptlrpc_pinger_process_import(struct obd_import *imp,
static int ptlrpc_pinger_main(void *arg)
{
struct ptlrpc_thread *thread = (struct ptlrpc_thread *)arg;
- ENTRY;
/* Record that the thread is running */
thread_set_flags(thread, SVC_RUNNING);
@@ -353,7 +350,6 @@ static int ptlrpc_pinger_main(void *arg)
thread_is_event(thread),
&lwi);
if (thread_test_and_clear_flags(thread, SVC_STOPPING)) {
- EXIT;
break;
} else {
/* woken after adding import to reset timer */
@@ -369,37 +365,32 @@ static int ptlrpc_pinger_main(void *arg)
return 0;
}
-static struct ptlrpc_thread *pinger_thread = NULL;
+static struct ptlrpc_thread pinger_thread;
int ptlrpc_start_pinger(void)
{
struct l_wait_info lwi = { 0 };
int rc;
- ENTRY;
- if (pinger_thread != NULL)
- RETURN(-EALREADY);
+ if (!thread_is_init(&pinger_thread) &&
+ !thread_is_stopped(&pinger_thread))
+ return -EALREADY;
- OBD_ALLOC_PTR(pinger_thread);
- if (pinger_thread == NULL)
- RETURN(-ENOMEM);
- init_waitqueue_head(&pinger_thread->t_ctl_waitq);
+ init_waitqueue_head(&pinger_thread.t_ctl_waitq);
init_waitqueue_head(&suspend_timeouts_waitq);
- strcpy(pinger_thread->t_name, "ll_ping");
+ strcpy(pinger_thread.t_name, "ll_ping");
/* CLONE_VM and CLONE_FILES just avoid a needless copy, because we
* just drop the VM and FILES in cfs_daemonize_ctxt() right away. */
rc = PTR_ERR(kthread_run(ptlrpc_pinger_main,
- pinger_thread, pinger_thread->t_name));
+ &pinger_thread, pinger_thread.t_name));
if (IS_ERR_VALUE(rc)) {
CERROR("cannot start thread: %d\n", rc);
- OBD_FREE(pinger_thread, sizeof(*pinger_thread));
- pinger_thread = NULL;
- RETURN(rc);
+ return rc;
}
- l_wait_event(pinger_thread->t_ctl_waitq,
- thread_is_running(pinger_thread), &lwi);
+ l_wait_event(pinger_thread.t_ctl_waitq,
+ thread_is_running(&pinger_thread), &lwi);
if (suppress_pings)
CWARN("Pings will be suppressed at the request of the "
@@ -408,7 +399,7 @@ int ptlrpc_start_pinger(void)
"(Search for the \"suppress_pings\" kernel module "
"parameter.)\n");
- RETURN(0);
+ return 0;
}
int ptlrpc_pinger_remove_timeouts(void);
@@ -417,23 +408,19 @@ int ptlrpc_stop_pinger(void)
{
struct l_wait_info lwi = { 0 };
int rc = 0;
- ENTRY;
- if (pinger_thread == NULL)
- RETURN(-EALREADY);
+ if (!thread_is_init(&pinger_thread) &&
+ !thread_is_stopped(&pinger_thread))
+ return -EALREADY;
ptlrpc_pinger_remove_timeouts();
- mutex_lock(&pinger_mutex);
- thread_set_flags(pinger_thread, SVC_STOPPING);
- wake_up(&pinger_thread->t_ctl_waitq);
- mutex_unlock(&pinger_mutex);
+ thread_set_flags(&pinger_thread, SVC_STOPPING);
+ wake_up(&pinger_thread.t_ctl_waitq);
- l_wait_event(pinger_thread->t_ctl_waitq,
- thread_is_stopped(pinger_thread), &lwi);
+ l_wait_event(pinger_thread.t_ctl_waitq,
+ thread_is_stopped(&pinger_thread), &lwi);
- OBD_FREE_PTR(pinger_thread);
- pinger_thread = NULL;
- RETURN(rc);
+ return rc;
}
void ptlrpc_pinger_sending_on_import(struct obd_import *imp)
@@ -459,9 +446,8 @@ void ptlrpc_pinger_commit_expected(struct obd_import *imp)
int ptlrpc_pinger_add_import(struct obd_import *imp)
{
- ENTRY;
if (!list_empty(&imp->imp_pinger_chain))
- RETURN(-EALREADY);
+ return -EALREADY;
mutex_lock(&pinger_mutex);
CDEBUG(D_HA, "adding pingable import %s->%s\n",
@@ -476,15 +462,14 @@ int ptlrpc_pinger_add_import(struct obd_import *imp)
ptlrpc_pinger_wake_up();
mutex_unlock(&pinger_mutex);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ptlrpc_pinger_add_import);
int ptlrpc_pinger_del_import(struct obd_import *imp)
{
- ENTRY;
if (list_empty(&imp->imp_pinger_chain))
- RETURN(-ENOENT);
+ return -ENOENT;
mutex_lock(&pinger_mutex);
list_del_init(&imp->imp_pinger_chain);
@@ -494,7 +479,7 @@ int ptlrpc_pinger_del_import(struct obd_import *imp)
imp->imp_obd->obd_no_recov = 1;
class_import_put(imp);
mutex_unlock(&pinger_mutex);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ptlrpc_pinger_del_import);
@@ -615,10 +600,10 @@ int ptlrpc_pinger_remove_timeouts(void)
return 0;
}
-void ptlrpc_pinger_wake_up()
+void ptlrpc_pinger_wake_up(void)
{
- thread_add_flags(pinger_thread, SVC_EVENT);
- wake_up(&pinger_thread->t_ctl_waitq);
+ thread_add_flags(&pinger_thread, SVC_EVENT);
+ wake_up(&pinger_thread.t_ctl_waitq);
}
/* Ping evictor thread */
@@ -659,7 +644,6 @@ static int ping_evictor_main(void *arg)
struct obd_export *exp;
struct l_wait_info lwi = { 0 };
time_t expire_time;
- ENTRY;
unshare_fs_struct();
@@ -731,12 +715,12 @@ static int ping_evictor_main(void *arg)
}
CDEBUG(D_HA, "Exiting Ping Evictor\n");
- RETURN(0);
+ return 0;
}
void ping_evictor_start(void)
{
- task_t *task;
+ struct task_struct *task;
if (++pet_refcount > 1)
return;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
index f6ea80f0b10..419e634854d 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
@@ -54,7 +54,6 @@ extern struct mutex ptlrpcd_mutex;
__init int ptlrpc_init(void)
{
int rc, cleanup_phase = 0;
- ENTRY;
lustre_assert_wire_constants();
#if RS_DEBUG
@@ -67,11 +66,11 @@ __init int ptlrpc_init(void)
rc = req_layout_init();
if (rc)
- RETURN(rc);
+ return rc;
rc = ptlrpc_hr_init();
if (rc)
- RETURN(rc);
+ return rc;
cleanup_phase = 1;
@@ -110,7 +109,7 @@ __init int ptlrpc_init(void)
rc = tgt_mod_init();
if (rc)
GOTO(cleanup, rc);
- RETURN(0);
+ return 0;
cleanup:
switch(cleanup_phase) {
@@ -150,5 +149,7 @@ static void __exit ptlrpc_exit(void)
MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
MODULE_DESCRIPTION("Lustre Request Processor and Lock Management");
MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
-cfs_module(ptlrpc, "1.0.0", ptlrpc_init, ptlrpc_exit);
+module_init(ptlrpc_init);
+module_exit(ptlrpc_exit);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
index 5a66a1be422..fbdeff65d05 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
@@ -268,7 +268,6 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc)
struct ptlrpc_request_set *set = pc->pc_set;
int rc = 0;
int rc2;
- ENTRY;
if (atomic_read(&set->set_new_count)) {
spin_lock(&set->set_new_req_lock);
@@ -302,7 +301,7 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc)
* new modules are loaded, i.e., early during boot up.
*/
CERROR("Failure to refill session: %d\n", rc2);
- RETURN(rc);
+ return rc;
}
if (atomic_read(&set->set_remaining))
@@ -368,7 +367,7 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc)
}
}
- RETURN(rc);
+ return rc;
}
/**
@@ -383,7 +382,6 @@ static int ptlrpcd(void *arg)
struct ptlrpc_request_set *set = pc->pc_set;
struct lu_env env = { .le_ses = NULL };
int rc, exit = 0;
- ENTRY;
unshare_fs_struct();
#if defined(CONFIG_SMP)
@@ -410,7 +408,7 @@ static int ptlrpcd(void *arg)
complete(&pc->pc_starting);
if (rc != 0)
- RETURN(rc);
+ return rc;
/*
* This mainloop strongly resembles ptlrpc_set_wait() except that our
@@ -501,7 +499,6 @@ static int ptlrpcd_bind(int index, int max)
#if defined(CONFIG_NUMA)
cpumask_t mask;
#endif
- ENTRY;
LASSERT(index <= max - 1);
pc = &ptlrpcds->pd_threads[index];
@@ -596,7 +593,7 @@ static int ptlrpcd_bind(int index, int max)
}
}
- RETURN(rc);
+ return rc;
}
@@ -604,7 +601,6 @@ int ptlrpcd_start(int index, int max, const char *name, struct ptlrpcd_ctl *pc)
{
int rc;
int env = 0;
- ENTRY;
/*
* Do not allow start second thread for one pc.
@@ -612,7 +608,7 @@ int ptlrpcd_start(int index, int max, const char *name, struct ptlrpcd_ctl *pc)
if (test_and_set_bit(LIOD_START, &pc->pc_flags)) {
CWARN("Starting second thread (%s) for same pc %p\n",
name, pc);
- RETURN(0);
+ return 0;
}
pc->pc_index = index;
@@ -634,7 +630,8 @@ int ptlrpcd_start(int index, int max, const char *name, struct ptlrpcd_ctl *pc)
env = 1;
{
- task_t *task;
+ struct task_struct *task;
+
if (index >= 0) {
rc = ptlrpcd_bind(index, max);
if (rc < 0)
@@ -663,31 +660,25 @@ out:
clear_bit(LIOD_BIND, &pc->pc_flags);
clear_bit(LIOD_START, &pc->pc_flags);
}
- RETURN(rc);
+ return rc;
}
void ptlrpcd_stop(struct ptlrpcd_ctl *pc, int force)
{
- ENTRY;
-
if (!test_bit(LIOD_START, &pc->pc_flags)) {
CWARN("Thread for pc %p was not started\n", pc);
- goto out;
+ return;
}
set_bit(LIOD_STOP, &pc->pc_flags);
if (force)
set_bit(LIOD_FORCE, &pc->pc_flags);
wake_up(&pc->pc_set->set_waitq);
-
-out:
- EXIT;
}
void ptlrpcd_free(struct ptlrpcd_ctl *pc)
{
struct ptlrpc_request_set *set = pc->pc_set;
- ENTRY;
if (!test_bit(LIOD_START, &pc->pc_flags)) {
CWARN("Thread for pc %p was not started\n", pc);
@@ -716,13 +707,11 @@ out:
pc->pc_partners = NULL;
}
pc->pc_npartners = 0;
- EXIT;
}
static void ptlrpcd_fini(void)
{
int i;
- ENTRY;
if (ptlrpcds != NULL) {
for (i = 0; i < ptlrpcds->pd_nthreads; i++)
@@ -734,8 +723,6 @@ static void ptlrpcd_fini(void)
OBD_FREE(ptlrpcds, ptlrpcds->pd_size);
ptlrpcds = NULL;
}
-
- EXIT;
}
static int ptlrpcd_init(void)
@@ -743,7 +730,6 @@ static int ptlrpcd_init(void)
int nthreads = num_online_cpus();
char name[16];
int size, i = -1, j, rc = 0;
- ENTRY;
if (max_ptlrpcds > 0 && max_ptlrpcds < nthreads)
nthreads = max_ptlrpcds;
@@ -800,19 +786,18 @@ out:
ptlrpcds = NULL;
}
- RETURN(0);
+ return 0;
}
int ptlrpcd_addref(void)
{
int rc = 0;
- ENTRY;
mutex_lock(&ptlrpcd_mutex);
if (++ptlrpcd_users == 1)
rc = ptlrpcd_init();
mutex_unlock(&ptlrpcd_mutex);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpcd_addref);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c
index 2960889834a..84c39e083ea 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/recover.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c
@@ -60,12 +60,8 @@
*/
void ptlrpc_initiate_recovery(struct obd_import *imp)
{
- ENTRY;
-
CDEBUG(D_HA, "%s: starting recovery\n", obd2cli_tgt(imp->imp_obd));
ptlrpc_connect_import(imp);
-
- EXIT;
}
/**
@@ -78,7 +74,6 @@ int ptlrpc_replay_next(struct obd_import *imp, int *inflight)
struct list_head *tmp, *pos;
struct ptlrpc_request *req = NULL;
__u64 last_transno;
- ENTRY;
*inflight = 0;
@@ -137,11 +132,11 @@ int ptlrpc_replay_next(struct obd_import *imp, int *inflight)
if (rc) {
CERROR("recovery replay error %d for req "
LPU64"\n", rc, req->rq_xid);
- RETURN(rc);
+ return rc;
}
*inflight = 1;
}
- RETURN(rc);
+ return rc;
}
/**
@@ -152,8 +147,6 @@ int ptlrpc_resend(struct obd_import *imp)
{
struct ptlrpc_request *req, *next;
- ENTRY;
-
/* As long as we're in recovery, nothing should be added to the sending
* list, so we don't need to hold the lock during this iteration and
* resend process.
@@ -163,7 +156,7 @@ int ptlrpc_resend(struct obd_import *imp)
spin_lock(&imp->imp_lock);
if (imp->imp_state != LUSTRE_IMP_RECOVER) {
spin_unlock(&imp->imp_lock);
- RETURN(-1);
+ return -1;
}
list_for_each_entry_safe(req, next, &imp->imp_sending_list,
@@ -176,7 +169,7 @@ int ptlrpc_resend(struct obd_import *imp)
}
spin_unlock(&imp->imp_lock);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ptlrpc_resend);
@@ -203,7 +196,6 @@ EXPORT_SYMBOL(ptlrpc_wake_delayed);
void ptlrpc_request_handle_notconn(struct ptlrpc_request *failed_req)
{
struct obd_import *imp = failed_req->rq_import;
- ENTRY;
CDEBUG(D_HA, "import %s of %s@%s abruptly disconnected: reconnecting\n",
imp->imp_obd->obd_name, obd2cli_tgt(imp->imp_obd),
@@ -230,8 +222,6 @@ void ptlrpc_request_handle_notconn(struct ptlrpc_request *failed_req)
if (!failed_req->rq_no_resend)
failed_req->rq_resend = 1;
spin_unlock(&failed_req->rq_lock);
-
- EXIT;
}
/**
@@ -246,7 +236,6 @@ int ptlrpc_set_import_active(struct obd_import *imp, int active)
struct obd_device *obd = imp->imp_obd;
int rc = 0;
- ENTRY;
LASSERT(obd);
/* When deactivating, mark import invalid, and abort in-flight
@@ -279,7 +268,7 @@ int ptlrpc_set_import_active(struct obd_import *imp, int active)
rc = ptlrpc_recover_import(imp, NULL, 0);
}
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_set_import_active);
@@ -287,7 +276,6 @@ EXPORT_SYMBOL(ptlrpc_set_import_active);
int ptlrpc_recover_import(struct obd_import *imp, char *new_uuid, int async)
{
int rc = 0;
- ENTRY;
spin_lock(&imp->imp_lock);
if (imp->imp_state == LUSTRE_IMP_NEW || imp->imp_deactive ||
@@ -337,7 +325,6 @@ int ptlrpc_recover_import(struct obd_import *imp, char *new_uuid, int async)
CDEBUG(D_HA, "%s: recovery finished\n",
obd2cli_tgt(imp->imp_obd));
}
- EXIT;
out:
return rc;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c
index 36e8bed5458..962b31d163d 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c
@@ -269,8 +269,8 @@ struct ptlrpc_cli_ctx *get_my_ctx(struct ptlrpc_sec *sec)
remove_dead = 0;
}
} else {
- vcred.vc_uid = current_uid();
- vcred.vc_gid = current_gid();
+ vcred.vc_uid = from_kuid(&init_user_ns, current_uid());
+ vcred.vc_gid = from_kgid(&init_user_ns, current_gid());
}
return sec->ps_policy->sp_cops->lookup_ctx(sec, &vcred,
@@ -396,14 +396,13 @@ int sptlrpc_req_get_ctx(struct ptlrpc_request *req)
struct obd_import *imp = req->rq_import;
struct ptlrpc_sec *sec;
int rc;
- ENTRY;
LASSERT(!req->rq_cli_ctx);
LASSERT(imp);
rc = import_sec_validate_get(imp, &sec);
if (rc)
- RETURN(rc);
+ return rc;
req->rq_cli_ctx = get_my_ctx(sec);
@@ -411,10 +410,10 @@ int sptlrpc_req_get_ctx(struct ptlrpc_request *req)
if (!req->rq_cli_ctx) {
CERROR("req %p: fail to get context\n", req);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
- RETURN(0);
+ return 0;
}
/**
@@ -428,8 +427,6 @@ int sptlrpc_req_get_ctx(struct ptlrpc_request *req)
*/
void sptlrpc_req_put_ctx(struct ptlrpc_request *req, int sync)
{
- ENTRY;
-
LASSERT(req);
LASSERT(req->rq_cli_ctx);
@@ -444,7 +441,6 @@ void sptlrpc_req_put_ctx(struct ptlrpc_request *req, int sync)
sptlrpc_cli_ctx_put(req->rq_cli_ctx, sync);
req->rq_cli_ctx = NULL;
- EXIT;
}
static
@@ -520,7 +516,6 @@ int sptlrpc_req_replace_dead_ctx(struct ptlrpc_request *req)
struct ptlrpc_cli_ctx *oldctx = req->rq_cli_ctx;
struct ptlrpc_cli_ctx *newctx;
int rc;
- ENTRY;
LASSERT(oldctx);
@@ -533,7 +528,7 @@ int sptlrpc_req_replace_dead_ctx(struct ptlrpc_request *req)
/* restore old ctx */
req->rq_cli_ctx = oldctx;
- RETURN(rc);
+ return rc;
}
newctx = req->rq_cli_ctx;
@@ -560,14 +555,14 @@ int sptlrpc_req_replace_dead_ctx(struct ptlrpc_request *req)
/* restore old ctx */
sptlrpc_req_put_ctx(req, 0);
req->rq_cli_ctx = oldctx;
- RETURN(rc);
+ return rc;
}
LASSERT(req->rq_cli_ctx == newctx);
}
sptlrpc_cli_ctx_put(oldctx, 1);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(sptlrpc_req_replace_dead_ctx);
@@ -639,12 +634,11 @@ int sptlrpc_req_refresh_ctx(struct ptlrpc_request *req, long timeout)
struct ptlrpc_sec *sec;
struct l_wait_info lwi;
int rc;
- ENTRY;
LASSERT(ctx);
if (req->rq_ctx_init || req->rq_ctx_fini)
- RETURN(0);
+ return 0;
/*
* during the process a request's context might change type even
@@ -654,7 +648,7 @@ int sptlrpc_req_refresh_ctx(struct ptlrpc_request *req, long timeout)
again:
rc = import_sec_validate_get(req->rq_import, &sec);
if (rc)
- RETURN(rc);
+ return rc;
if (sec->ps_flvr.sf_rpc != req->rq_flvr.sf_rpc) {
CDEBUG(D_SEC, "req %p: flavor has changed %x -> %x\n",
@@ -666,7 +660,7 @@ again:
sptlrpc_sec_put(sec);
if (cli_ctx_is_eternal(ctx))
- RETURN(0);
+ return 0;
if (unlikely(test_bit(PTLRPC_CTX_NEW_BIT, &ctx->cc_flags))) {
LASSERT(ctx->cc_ops->refresh);
@@ -677,7 +671,7 @@ again:
LASSERT(ctx->cc_ops->validate);
if (ctx->cc_ops->validate(ctx) == 0) {
req_off_ctx_list(req, ctx);
- RETURN(0);
+ return 0;
}
if (unlikely(test_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags))) {
@@ -685,7 +679,7 @@ again:
req->rq_err = 1;
spin_unlock(&req->rq_lock);
req_off_ctx_list(req, ctx);
- RETURN(-EPERM);
+ return -EPERM;
}
/*
@@ -719,7 +713,7 @@ again:
unlikely(req->rq_reqmsg) &&
lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT) {
req_off_ctx_list(req, ctx);
- RETURN(0);
+ return 0;
}
if (unlikely(test_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags))) {
@@ -731,7 +725,7 @@ again:
spin_lock(&req->rq_lock);
req->rq_err = 1;
spin_unlock(&req->rq_lock);
- RETURN(-EINTR);
+ return -EINTR;
}
rc = sptlrpc_req_replace_dead_ctx(req);
@@ -742,7 +736,7 @@ again:
spin_lock(&req->rq_lock);
req->rq_err = 1;
spin_unlock(&req->rq_lock);
- RETURN(rc);
+ return rc;
}
ctx = req->rq_cli_ctx;
@@ -759,7 +753,7 @@ again:
spin_unlock(&ctx->cc_lock);
if (timeout < 0)
- RETURN(-EWOULDBLOCK);
+ return -EWOULDBLOCK;
/* Clear any flags that may be present from previous sends */
LASSERT(req->rq_receiving_reply == 0);
@@ -789,7 +783,7 @@ again:
req_off_ctx_list(req, ctx);
LASSERT(rc != 0);
- RETURN(rc);
+ return rc;
}
goto again;
@@ -889,7 +883,6 @@ int sptlrpc_import_check_ctx(struct obd_import *imp)
struct ptlrpc_cli_ctx *ctx;
struct ptlrpc_request *req = NULL;
int rc;
- ENTRY;
might_sleep();
@@ -898,22 +891,22 @@ int sptlrpc_import_check_ctx(struct obd_import *imp)
sptlrpc_sec_put(sec);
if (!ctx)
- RETURN(-ENOMEM);
+ return -ENOMEM;
if (cli_ctx_is_eternal(ctx) ||
ctx->cc_ops->validate(ctx) == 0) {
sptlrpc_cli_ctx_put(ctx, 1);
- RETURN(0);
+ return 0;
}
if (cli_ctx_is_error(ctx)) {
sptlrpc_cli_ctx_put(ctx, 1);
- RETURN(-EACCES);
+ return -EACCES;
}
OBD_ALLOC_PTR(req);
if (!req)
- RETURN(-ENOMEM);
+ return -ENOMEM;
spin_lock_init(&req->rq_lock);
atomic_set(&req->rq_refcount, 10000);
@@ -929,7 +922,7 @@ int sptlrpc_import_check_ctx(struct obd_import *imp)
sptlrpc_cli_ctx_put(req->rq_cli_ctx, 1);
OBD_FREE_PTR(req);
- RETURN(rc);
+ return rc;
}
/**
@@ -941,7 +934,6 @@ int sptlrpc_cli_wrap_request(struct ptlrpc_request *req)
{
struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
int rc = 0;
- ENTRY;
LASSERT(ctx);
LASSERT(ctx->cc_sec);
@@ -953,7 +945,7 @@ int sptlrpc_cli_wrap_request(struct ptlrpc_request *req)
if (req->rq_bulk) {
rc = sptlrpc_cli_wrap_bulk(req, req->rq_bulk);
if (rc)
- RETURN(rc);
+ return rc;
}
switch (SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc)) {
@@ -977,14 +969,13 @@ int sptlrpc_cli_wrap_request(struct ptlrpc_request *req)
LASSERT(req->rq_reqdata_len <= req->rq_reqbuf_len);
}
- RETURN(rc);
+ return rc;
}
static int do_cli_unwrap_reply(struct ptlrpc_request *req)
{
struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
int rc;
- ENTRY;
LASSERT(ctx);
LASSERT(ctx->cc_sec);
@@ -1002,13 +993,13 @@ static int do_cli_unwrap_reply(struct ptlrpc_request *req)
break;
default:
CERROR("failed unpack reply: x"LPU64"\n", req->rq_xid);
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (req->rq_repdata_len < sizeof(struct lustre_msg)) {
CERROR("replied data length %d too small\n",
req->rq_repdata_len);
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (SPTLRPC_FLVR_POLICY(req->rq_repdata->lm_secflvr) !=
@@ -1016,7 +1007,7 @@ static int do_cli_unwrap_reply(struct ptlrpc_request *req)
CERROR("reply policy %u doesn't match request policy %u\n",
SPTLRPC_FLVR_POLICY(req->rq_repdata->lm_secflvr),
SPTLRPC_FLVR_POLICY(req->rq_flvr.sf_rpc));
- RETURN(-EPROTO);
+ return -EPROTO;
}
switch (SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc)) {
@@ -1038,7 +1029,7 @@ static int do_cli_unwrap_reply(struct ptlrpc_request *req)
if (SPTLRPC_FLVR_POLICY(req->rq_flvr.sf_rpc) != SPTLRPC_POLICY_NULL &&
!req->rq_ctx_init)
req->rq_rep_swab_mask = 0;
- RETURN(rc);
+ return rc;
}
/**
@@ -1096,11 +1087,10 @@ int sptlrpc_cli_unwrap_early_reply(struct ptlrpc_request *req,
char *early_buf;
int early_bufsz, early_size;
int rc;
- ENTRY;
OBD_ALLOC_PTR(early_req);
if (early_req == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
early_size = req->rq_nob_received;
early_bufsz = size_roundup_power2(early_size);
@@ -1163,7 +1153,7 @@ int sptlrpc_cli_unwrap_early_reply(struct ptlrpc_request *req,
LASSERT(early_req->rq_repmsg);
*req_ret = early_req;
- RETURN(0);
+ return 0;
err_ctx:
sptlrpc_cli_ctx_put(early_req->rq_cli_ctx, 1);
@@ -1171,7 +1161,7 @@ err_buf:
OBD_FREE_LARGE(early_buf, early_bufsz);
err_req:
OBD_FREE_PTR(early_req);
- RETURN(rc);
+ return rc;
}
/**
@@ -1285,7 +1275,6 @@ struct ptlrpc_sec * sptlrpc_sec_create(struct obd_import *imp,
struct ptlrpc_sec_policy *policy;
struct ptlrpc_sec *sec;
char str[32];
- ENTRY;
if (svc_ctx) {
LASSERT(imp->imp_dlm_fake == 1);
@@ -1308,7 +1297,7 @@ struct ptlrpc_sec * sptlrpc_sec_create(struct obd_import *imp,
policy = sptlrpc_wireflavor2policy(sf->sf_rpc);
if (!policy) {
CERROR("invalid flavor 0x%x\n", sf->sf_rpc);
- RETURN(NULL);
+ return NULL;
}
}
@@ -1324,7 +1313,7 @@ struct ptlrpc_sec * sptlrpc_sec_create(struct obd_import *imp,
sptlrpc_policy_put(policy);
}
- RETURN(sec);
+ return sec;
}
struct ptlrpc_sec *sptlrpc_import_sec_ref(struct obd_import *imp)
@@ -1406,12 +1395,11 @@ int sptlrpc_import_sec_adapt(struct obd_import *imp,
enum lustre_sec_part sp;
char str[24];
int rc = 0;
- ENTRY;
might_sleep();
if (imp == NULL)
- RETURN(0);
+ return 0;
conn = imp->imp_connection;
@@ -1485,7 +1473,7 @@ int sptlrpc_import_sec_adapt(struct obd_import *imp,
mutex_unlock(&imp->imp_sec_mutex);
out:
sptlrpc_sec_put(sec);
- RETURN(rc);
+ return rc;
}
void sptlrpc_import_sec_put(struct obd_import *imp)
@@ -1523,7 +1511,8 @@ void sptlrpc_import_flush_root_ctx(struct obd_import *imp)
void sptlrpc_import_flush_my_ctx(struct obd_import *imp)
{
- import_flush_ctx_common(imp, current_uid(), 1, 1);
+ import_flush_ctx_common(imp, from_kuid(&init_user_ns, current_uid()),
+ 1, 1);
}
EXPORT_SYMBOL(sptlrpc_import_flush_my_ctx);
@@ -1668,17 +1657,16 @@ int sptlrpc_cli_alloc_repbuf(struct ptlrpc_request *req, int msgsize)
{
struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
struct ptlrpc_sec_policy *policy;
- ENTRY;
LASSERT(ctx);
LASSERT(ctx->cc_sec);
LASSERT(ctx->cc_sec->ps_policy);
if (req->rq_repbuf)
- RETURN(0);
+ return 0;
policy = ctx->cc_sec->ps_policy;
- RETURN(policy->sp_cops->alloc_repbuf(ctx->cc_sec, req, msgsize));
+ return policy->sp_cops->alloc_repbuf(ctx->cc_sec, req, msgsize);
}
/**
@@ -1689,7 +1677,6 @@ void sptlrpc_cli_free_repbuf(struct ptlrpc_request *req)
{
struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
struct ptlrpc_sec_policy *policy;
- ENTRY;
LASSERT(ctx);
LASSERT(ctx->cc_sec);
@@ -1703,7 +1690,6 @@ void sptlrpc_cli_free_repbuf(struct ptlrpc_request *req)
policy = ctx->cc_sec->ps_policy;
policy->sp_cops->free_repbuf(ctx->cc_sec, req);
req->rq_repmsg = NULL;
- EXIT;
}
int sptlrpc_cli_install_rvs_ctx(struct obd_import *imp,
@@ -2032,7 +2018,6 @@ int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req)
struct ptlrpc_sec_policy *policy;
struct lustre_msg *msg = req->rq_reqbuf;
int rc;
- ENTRY;
LASSERT(msg);
LASSERT(req->rq_reqmsg == NULL);
@@ -2050,18 +2035,18 @@ int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req)
default:
CERROR("error unpacking request from %s x"LPU64"\n",
libcfs_id2str(req->rq_peer), req->rq_xid);
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
req->rq_flvr.sf_rpc = WIRE_FLVR(msg->lm_secflvr);
req->rq_sp_from = LUSTRE_SP_ANY;
- req->rq_auth_uid = INVALID_UID;
- req->rq_auth_mapped_uid = INVALID_UID;
+ req->rq_auth_uid = -1;
+ req->rq_auth_mapped_uid = -1;
policy = sptlrpc_wireflavor2policy(req->rq_flvr.sf_rpc);
if (!policy) {
CERROR("unsupported rpc flavor %x\n", req->rq_flvr.sf_rpc);
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
LASSERT(policy->sp_sops->accept);
@@ -2079,7 +2064,7 @@ int sptlrpc_svc_unwrap_request(struct ptlrpc_request *req)
/* sanity check for the request source */
rc = sptlrpc_svc_check_from(req, rc);
- RETURN(rc);
+ return rc;
}
/**
@@ -2092,7 +2077,6 @@ int sptlrpc_svc_alloc_rs(struct ptlrpc_request *req, int msglen)
struct ptlrpc_sec_policy *policy;
struct ptlrpc_reply_state *rs;
int rc;
- ENTRY;
LASSERT(req->rq_svc_ctx);
LASSERT(req->rq_svc_ctx->sc_policy);
@@ -2105,7 +2089,7 @@ int sptlrpc_svc_alloc_rs(struct ptlrpc_request *req, int msglen)
/* failed alloc, try emergency pool */
rs = lustre_get_emerg_rs(req->rq_rqbd->rqbd_svcpt);
if (rs == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req->rq_reply_state = rs;
rc = policy->sp_sops->alloc_rs(req, msglen);
@@ -2118,7 +2102,7 @@ int sptlrpc_svc_alloc_rs(struct ptlrpc_request *req, int msglen)
LASSERT(rc != 0 ||
(req->rq_reply_state && req->rq_reply_state->rs_msg));
- RETURN(rc);
+ return rc;
}
/**
@@ -2131,7 +2115,6 @@ int sptlrpc_svc_wrap_reply(struct ptlrpc_request *req)
{
struct ptlrpc_sec_policy *policy;
int rc;
- ENTRY;
LASSERT(req->rq_svc_ctx);
LASSERT(req->rq_svc_ctx->sc_policy);
@@ -2142,7 +2125,7 @@ int sptlrpc_svc_wrap_reply(struct ptlrpc_request *req)
rc = policy->sp_sops->authorize(req);
LASSERT(rc || req->rq_reply_state->rs_repdata_len);
- RETURN(rc);
+ return rc;
}
/**
@@ -2152,7 +2135,6 @@ void sptlrpc_svc_free_rs(struct ptlrpc_reply_state *rs)
{
struct ptlrpc_sec_policy *policy;
unsigned int prealloc;
- ENTRY;
LASSERT(rs->rs_svc_ctx);
LASSERT(rs->rs_svc_ctx->sc_policy);
@@ -2165,7 +2147,6 @@ void sptlrpc_svc_free_rs(struct ptlrpc_reply_state *rs)
if (prealloc)
lustre_put_emerg_rs(rs);
- EXIT;
}
void sptlrpc_svc_ctx_addref(struct ptlrpc_request *req)
@@ -2314,10 +2295,10 @@ int sptlrpc_pack_user_desc(struct lustre_msg *msg, int offset)
pud = lustre_msg_buf(msg, offset, 0);
- pud->pud_uid = current_uid();
- pud->pud_gid = current_gid();
- pud->pud_fsuid = current_fsuid();
- pud->pud_fsgid = current_fsgid();
+ pud->pud_uid = from_kuid(&init_user_ns, current_uid());
+ pud->pud_gid = from_kgid(&init_user_ns, current_gid());
+ pud->pud_fsuid = from_kuid(&init_user_ns, current_fsuid());
+ pud->pud_fsgid = from_kgid(&init_user_ns, current_fsgid());
pud->pud_cap = cfs_curproc_cap_pack();
pud->pud_ngroups = (msg->lm_buflens[offset] - sizeof(*pud)) / 4;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
index bf53f1bc174..9013745ab10 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
@@ -156,7 +156,7 @@ int sptlrpc_proc_enc_pool_seq_show(struct seq_file *m, void *v)
"max waitqueue depth: %u\n"
"max wait time: "CFS_TIME_T"/%u\n"
,
- num_physpages,
+ totalram_pages,
PAGES_PER_POOL,
page_pools.epp_max_pages,
page_pools.epp_max_pools,
@@ -705,7 +705,7 @@ int sptlrpc_enc_pool_init(void)
* maximum capacity is 1/8 of total physical memory.
* is the 1/8 a good number?
*/
- page_pools.epp_max_pages = num_physpages / 8;
+ page_pools.epp_max_pages = totalram_pages / 8;
page_pools.epp_max_pools = npages_to_npools(page_pools.epp_max_pages);
init_waitqueue_head(&page_pools.epp_waitq);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
index a45a3929b59..6cc3f23c27c 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
@@ -195,7 +195,7 @@ int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
flavor = strchr(param, '=');
if (flavor == NULL) {
CERROR("invalid param, no '='\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
*flavor++ = '\0';
@@ -208,7 +208,7 @@ int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
rule->sr_netid = libcfs_str2net(param);
if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
CERROR("invalid network name: %s\n", param);
- RETURN(-EINVAL);
+ return -EINVAL;
}
}
@@ -228,16 +228,16 @@ int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
rule->sr_to = LUSTRE_SP_MDT;
} else {
CERROR("invalid rule dir segment: %s\n", dir);
- RETURN(-EINVAL);
+ return -EINVAL;
}
}
/* 2.1 flavor */
rc = sptlrpc_parse_flavor(flavor, &rule->sr_flvr);
if (rc)
- RETURN(-EINVAL);
+ return -EINVAL;
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(sptlrpc_parse_rule);
@@ -661,18 +661,17 @@ static int __sptlrpc_process_config(struct lustre_cfg *lcfg,
char fsname[MTI_NAME_MAXLEN];
struct sptlrpc_rule rule;
int rc;
- ENTRY;
target = lustre_cfg_string(lcfg, 1);
if (target == NULL) {
CERROR("missing target name\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
param = lustre_cfg_string(lcfg, 2);
if (param == NULL) {
CERROR("missing parameter\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
CDEBUG(D_SEC, "processing rule: %s.%s\n", target, param);
@@ -680,13 +679,13 @@ static int __sptlrpc_process_config(struct lustre_cfg *lcfg,
/* parse rule to make sure the format is correct */
if (strncmp(param, PARAM_SRPC_FLVR, sizeof(PARAM_SRPC_FLVR) - 1) != 0) {
CERROR("Invalid sptlrpc parameter: %s\n", param);
- RETURN(-EINVAL);
+ return -EINVAL;
}
param += sizeof(PARAM_SRPC_FLVR) - 1;
rc = sptlrpc_parse_rule(param, &rule);
if (rc)
- RETURN(-EINVAL);
+ return -EINVAL;
if (conf == NULL) {
target2fsname(target, fsname, sizeof(fsname));
@@ -708,7 +707,7 @@ static int __sptlrpc_process_config(struct lustre_cfg *lcfg,
if (rc == 0)
conf->sc_modified++;
- RETURN(rc);
+ return rc;
}
int sptlrpc_process_config(struct lustre_cfg *lcfg)
@@ -905,7 +904,6 @@ EXPORT_SYMBOL(sptlrpc_target_choose_flavor);
void sptlrpc_conf_client_adapt(struct obd_device *obd)
{
struct obd_import *imp;
- ENTRY;
LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 ||
strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) ==0);
@@ -924,7 +922,6 @@ void sptlrpc_conf_client_adapt(struct obd_device *obd)
}
up_read(&obd->u.cli.cl_sem);
- EXIT;
}
EXPORT_SYMBOL(sptlrpc_conf_client_adapt);
@@ -1011,11 +1008,10 @@ int sptlrpc_target_local_copy_conf(struct obd_device *obd,
struct lvfs_run_ctxt saved;
struct dentry *dentry;
int rc;
- ENTRY;
ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
if (ctxt == NULL)
- RETURN(-EINVAL);
+ return -EINVAL;
push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
@@ -1058,7 +1054,7 @@ out_ctx:
llog_ctxt_put(ctxt);
CDEBUG(D_SEC, "target %s: write local sptlrpc conf: rc = %d\n",
obd->obd_name, rc);
- RETURN(rc);
+ return rc;
}
static int local_read_handler(const struct lu_env *env,
@@ -1068,11 +1064,10 @@ static int local_read_handler(const struct lu_env *env,
struct sptlrpc_conf *conf = (struct sptlrpc_conf *) data;
struct lustre_cfg *lcfg = (struct lustre_cfg *)(rec + 1);
int cfg_len, rc;
- ENTRY;
if (rec->lrh_type != OBD_CFG_REC) {
CERROR("unhandled lrh_type: %#x\n", rec->lrh_type);
- RETURN(-EINVAL);
+ return -EINVAL;
}
cfg_len = rec->lrh_len - sizeof(struct llog_rec_hdr) -
@@ -1081,15 +1076,15 @@ static int local_read_handler(const struct lu_env *env,
rc = lustre_cfg_sanity_check(lcfg, cfg_len);
if (rc) {
CERROR("Insane cfg\n");
- RETURN(rc);
+ return rc;
}
if (lcfg->lcfg_command != LCFG_SPTLRPC_CONF) {
CERROR("invalid command (%x)\n", lcfg->lcfg_command);
- RETURN(-EINVAL);
+ return -EINVAL;
}
- RETURN(__sptlrpc_process_config(lcfg, conf));
+ return __sptlrpc_process_config(lcfg, conf);
}
static
@@ -1100,14 +1095,13 @@ int sptlrpc_target_local_read_conf(struct obd_device *obd,
struct llog_ctxt *ctxt;
struct lvfs_run_ctxt saved;
int rc;
- ENTRY;
LASSERT(conf->sc_updated == 0 && conf->sc_local == 0);
ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
if (ctxt == NULL) {
CERROR("missing llog context\n");
- RETURN(-EINVAL);
+ return -EINVAL;
}
push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
@@ -1143,7 +1137,7 @@ out_pop:
llog_ctxt_put(ctxt);
CDEBUG(D_SEC, "target %s: read local sptlrpc conf: rc = %d\n",
obd->obd_name, rc);
- RETURN(rc);
+ return rc;
}
@@ -1160,7 +1154,6 @@ int sptlrpc_conf_target_get_rules(struct obd_device *obd,
enum lustre_sec_part sp_dst;
char fsname[MTI_NAME_MAXLEN];
int rc = 0;
- ENTRY;
if (strcmp(obd->obd_type->typ_name, LUSTRE_MDT_NAME) == 0) {
sp_dst = LUSTRE_SP_MDT;
@@ -1168,7 +1161,7 @@ int sptlrpc_conf_target_get_rules(struct obd_device *obd,
sp_dst = LUSTRE_SP_OST;
} else {
CERROR("unexpected obd type %s\n", obd->obd_type->typ_name);
- RETURN(-EINVAL);
+ return -EINVAL;
}
CDEBUG(D_SEC, "get rules for target %s\n", obd->obd_uuid.uuid);
@@ -1210,7 +1203,7 @@ int sptlrpc_conf_target_get_rules(struct obd_device *obd,
LUSTRE_SP_ANY, sp_dst, rset);
out:
mutex_unlock(&sptlrpc_conf_lock);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(sptlrpc_conf_target_get_rules);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
index 4c96a14a1bb..d2eb20eb56d 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
@@ -217,7 +217,7 @@ again:
int sptlrpc_gc_init(void)
{
struct l_wait_info lwi = { 0 };
- task_t *task;
+ struct task_struct *task;
mutex_init(&sec_gc_mutex);
spin_lock_init(&sec_gc_list_lock);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
index f552d2f182b..416401be6d4 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
@@ -192,7 +192,6 @@ int plain_ctx_sign(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
{
struct lustre_msg *msg = req->rq_reqbuf;
struct plain_header *phdr;
- ENTRY;
msg->lm_secflvr = req->rq_flvr.sf_rpc;
@@ -209,7 +208,7 @@ int plain_ctx_sign(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
req->rq_reqdata_len = lustre_msg_size_v2(msg->lm_bufcount,
msg->lm_buflens);
- RETURN(0);
+ return 0;
}
static
@@ -219,11 +218,10 @@ int plain_ctx_verify(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
struct plain_header *phdr;
__u32 cksum;
int swabbed;
- ENTRY;
if (msg->lm_bufcount != PLAIN_PACK_SEGMENTS) {
CERROR("unexpected reply buf count %u\n", msg->lm_bufcount);
- RETURN(-EPROTO);
+ return -EPROTO;
}
swabbed = ptlrpc_rep_need_swab(req);
@@ -231,24 +229,24 @@ int plain_ctx_verify(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
phdr = lustre_msg_buf(msg, PLAIN_PACK_HDR_OFF, sizeof(*phdr));
if (phdr == NULL) {
CERROR("missing plain header\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (phdr->ph_ver != 0) {
CERROR("Invalid header version\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
/* expect no user desc in reply */
if (phdr->ph_flags & PLAIN_FL_USER) {
CERROR("Unexpected udesc flag in reply\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (phdr->ph_bulk_hash_alg != req->rq_flvr.u_bulk.hash.hash_alg) {
CERROR("reply bulk flavor %u != %u\n", phdr->ph_bulk_hash_alg,
req->rq_flvr.u_bulk.hash.hash_alg);
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (unlikely(req->rq_early)) {
@@ -262,7 +260,7 @@ int plain_ctx_verify(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
CDEBUG(D_SEC,
"early reply checksum mismatch: %08x != %08x\n",
cpu_to_le32(cksum), msg->lm_cksum);
- RETURN(-EINVAL);
+ return -EINVAL;
}
} else {
/* whether we sent with bulk or not, we expect the same
@@ -272,18 +270,18 @@ int plain_ctx_verify(struct ptlrpc_cli_ctx *ctx, struct ptlrpc_request *req)
phdr->ph_flags & PLAIN_FL_BULK)) {
CERROR("%s bulk checksum in reply\n",
req->rq_pack_bulk ? "Missing" : "Unexpected");
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (phdr->ph_flags & PLAIN_FL_BULK) {
if (plain_unpack_bsd(msg, swabbed))
- RETURN(-EPROTO);
+ return -EPROTO;
}
}
req->rq_repmsg = lustre_msg_buf(msg, PLAIN_PACK_MSG_OFF, 0);
req->rq_replen = lustre_msg_buflen(msg, PLAIN_PACK_MSG_OFF);
- RETURN(0);
+ return 0;
}
static
@@ -307,10 +305,10 @@ int plain_cli_wrap_bulk(struct ptlrpc_cli_ctx *ctx,
bsd->bsd_svc = SPTLRPC_FLVR_BULK_SVC(req->rq_flvr.sf_rpc);
if (bsd->bsd_svc == SPTLRPC_BULK_SVC_NULL)
- RETURN(0);
+ return 0;
if (req->rq_bulk_read)
- RETURN(0);
+ return 0;
rc = plain_generate_bulk_csum(desc, req->rq_flvr.u_bulk.hash.hash_alg,
token);
@@ -417,7 +415,6 @@ static
void plain_destroy_sec(struct ptlrpc_sec *sec)
{
struct plain_sec *plsec = sec2plsec(sec);
- ENTRY;
LASSERT(sec->ps_policy == &plain_policy);
LASSERT(sec->ps_import);
@@ -428,7 +425,6 @@ void plain_destroy_sec(struct ptlrpc_sec *sec)
class_import_put(sec->ps_import);
OBD_FREE_PTR(plsec);
- EXIT;
}
static
@@ -445,13 +441,12 @@ struct ptlrpc_sec *plain_create_sec(struct obd_import *imp,
struct plain_sec *plsec;
struct ptlrpc_sec *sec;
struct ptlrpc_cli_ctx *ctx;
- ENTRY;
LASSERT(SPTLRPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_PLAIN);
OBD_ALLOC_PTR(plsec);
if (plsec == NULL)
- RETURN(NULL);
+ return NULL;
/*
* initialize plain_sec
@@ -476,12 +471,12 @@ struct ptlrpc_sec *plain_create_sec(struct obd_import *imp,
ctx = plain_sec_install_ctx(plsec);
if (ctx == NULL) {
plain_destroy_sec(sec);
- RETURN(NULL);
+ return NULL;
}
sptlrpc_cli_ctx_put(ctx, 1);
}
- RETURN(sec);
+ return sec;
}
static
@@ -491,7 +486,6 @@ struct ptlrpc_cli_ctx *plain_lookup_ctx(struct ptlrpc_sec *sec,
{
struct plain_sec *plsec = sec2plsec(sec);
struct ptlrpc_cli_ctx *ctx;
- ENTRY;
read_lock(&plsec->pls_lock);
ctx = plsec->pls_ctx;
@@ -502,7 +496,7 @@ struct ptlrpc_cli_ctx *plain_lookup_ctx(struct ptlrpc_sec *sec,
if (unlikely(ctx == NULL))
ctx = plain_sec_install_ctx(plsec);
- RETURN(ctx);
+ return ctx;
}
static
@@ -526,11 +520,10 @@ int plain_flush_ctx_cache(struct ptlrpc_sec *sec,
{
struct plain_sec *plsec = sec2plsec(sec);
struct ptlrpc_cli_ctx *ctx;
- ENTRY;
/* do nothing unless caller want to flush for 'all' */
if (uid != -1)
- RETURN(0);
+ return 0;
write_lock(&plsec->pls_lock);
ctx = plsec->pls_ctx;
@@ -539,7 +532,7 @@ int plain_flush_ctx_cache(struct ptlrpc_sec *sec,
if (ctx)
sptlrpc_cli_ctx_put(ctx, 1);
- RETURN(0);
+ return 0;
}
static
@@ -549,7 +542,6 @@ int plain_alloc_reqbuf(struct ptlrpc_sec *sec,
{
__u32 buflens[PLAIN_PACK_SEGMENTS] = { 0, };
int alloc_len;
- ENTRY;
buflens[PLAIN_PACK_HDR_OFF] = sizeof(struct plain_header);
buflens[PLAIN_PACK_MSG_OFF] = msgsize;
@@ -570,7 +562,7 @@ int plain_alloc_reqbuf(struct ptlrpc_sec *sec,
alloc_len = size_roundup_power2(alloc_len);
OBD_ALLOC_LARGE(req->rq_reqbuf, alloc_len);
if (!req->rq_reqbuf)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req->rq_reqbuf_len = alloc_len;
} else {
@@ -585,20 +577,18 @@ int plain_alloc_reqbuf(struct ptlrpc_sec *sec,
if (req->rq_pack_udesc)
sptlrpc_pack_user_desc(req->rq_reqbuf, PLAIN_PACK_USER_OFF);
- RETURN(0);
+ return 0;
}
static
void plain_free_reqbuf(struct ptlrpc_sec *sec,
struct ptlrpc_request *req)
{
- ENTRY;
if (!req->rq_pool) {
OBD_FREE_LARGE(req->rq_reqbuf, req->rq_reqbuf_len);
req->rq_reqbuf = NULL;
req->rq_reqbuf_len = 0;
}
- EXIT;
}
static
@@ -608,7 +598,6 @@ int plain_alloc_repbuf(struct ptlrpc_sec *sec,
{
__u32 buflens[PLAIN_PACK_SEGMENTS] = { 0, };
int alloc_len;
- ENTRY;
buflens[PLAIN_PACK_HDR_OFF] = sizeof(struct plain_header);
buflens[PLAIN_PACK_MSG_OFF] = msgsize;
@@ -627,21 +616,19 @@ int plain_alloc_repbuf(struct ptlrpc_sec *sec,
OBD_ALLOC_LARGE(req->rq_repbuf, alloc_len);
if (!req->rq_repbuf)
- RETURN(-ENOMEM);
+ return -ENOMEM;
req->rq_repbuf_len = alloc_len;
- RETURN(0);
+ return 0;
}
static
void plain_free_repbuf(struct ptlrpc_sec *sec,
struct ptlrpc_request *req)
{
- ENTRY;
OBD_FREE_LARGE(req->rq_repbuf, req->rq_repbuf_len);
req->rq_repbuf = NULL;
req->rq_repbuf_len = 0;
- EXIT;
}
static
@@ -652,7 +639,6 @@ int plain_enlarge_reqbuf(struct ptlrpc_sec *sec,
struct lustre_msg *newbuf;
int oldsize;
int newmsg_size, newbuf_size;
- ENTRY;
LASSERT(req->rq_reqbuf);
LASSERT(req->rq_reqbuf_len >= req->rq_reqlen);
@@ -681,7 +667,7 @@ int plain_enlarge_reqbuf(struct ptlrpc_sec *sec,
OBD_ALLOC_LARGE(newbuf, newbuf_size);
if (newbuf == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
memcpy(newbuf, req->rq_reqbuf, req->rq_reqbuf_len);
@@ -697,7 +683,7 @@ int plain_enlarge_reqbuf(struct ptlrpc_sec *sec,
_sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize);
req->rq_reqlen = newmsg_size;
- RETURN(0);
+ return 0;
}
/****************************************
@@ -715,7 +701,6 @@ int plain_accept(struct ptlrpc_request *req)
struct lustre_msg *msg = req->rq_reqbuf;
struct plain_header *phdr;
int swabbed;
- ENTRY;
LASSERT(SPTLRPC_FLVR_POLICY(req->rq_flvr.sf_rpc) ==
SPTLRPC_POLICY_PLAIN);
@@ -725,12 +710,12 @@ int plain_accept(struct ptlrpc_request *req)
SPTLRPC_FLVR_BULK_TYPE(req->rq_flvr.sf_rpc) !=
SPTLRPC_FLVR_BULK_TYPE(SPTLRPC_FLVR_PLAIN)) {
CERROR("Invalid rpc flavor %x\n", req->rq_flvr.sf_rpc);
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
if (msg->lm_bufcount < PLAIN_PACK_SEGMENTS) {
CERROR("unexpected request buf count %u\n", msg->lm_bufcount);
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
swabbed = ptlrpc_req_need_swab(req);
@@ -738,17 +723,17 @@ int plain_accept(struct ptlrpc_request *req)
phdr = lustre_msg_buf(msg, PLAIN_PACK_HDR_OFF, sizeof(*phdr));
if (phdr == NULL) {
CERROR("missing plain header\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (phdr->ph_ver != 0) {
CERROR("Invalid header version\n");
- RETURN(-EPROTO);
+ return -EPROTO;
}
if (phdr->ph_bulk_hash_alg >= BULK_HASH_ALG_MAX) {
CERROR("invalid hash algorithm: %u\n", phdr->ph_bulk_hash_alg);
- RETURN(-EPROTO);
+ return -EPROTO;
}
req->rq_sp_from = phdr->ph_sp;
@@ -758,7 +743,7 @@ int plain_accept(struct ptlrpc_request *req)
if (sptlrpc_unpack_user_desc(msg, PLAIN_PACK_USER_OFF,
swabbed)) {
CERROR("Mal-formed user descriptor\n");
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
}
req->rq_pack_udesc = 1;
@@ -767,7 +752,7 @@ int plain_accept(struct ptlrpc_request *req)
if (phdr->ph_flags & PLAIN_FL_BULK) {
if (plain_unpack_bsd(msg, swabbed))
- RETURN(SECSVC_DROP);
+ return SECSVC_DROP;
req->rq_pack_bulk = 1;
}
@@ -778,7 +763,7 @@ int plain_accept(struct ptlrpc_request *req)
req->rq_svc_ctx = &plain_svc_ctx;
atomic_inc(&req->rq_svc_ctx->sc_refcount);
- RETURN(SECSVC_OK);
+ return SECSVC_OK;
}
static
@@ -787,7 +772,6 @@ int plain_alloc_rs(struct ptlrpc_request *req, int msgsize)
struct ptlrpc_reply_state *rs;
__u32 buflens[PLAIN_PACK_SEGMENTS] = { 0, };
int rs_size = sizeof(*rs);
- ENTRY;
LASSERT(msgsize % 8 == 0);
@@ -807,7 +791,7 @@ int plain_alloc_rs(struct ptlrpc_request *req, int msgsize)
} else {
OBD_ALLOC_LARGE(rs, rs_size);
if (rs == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
rs->rs_size = rs_size;
}
@@ -821,20 +805,17 @@ int plain_alloc_rs(struct ptlrpc_request *req, int msgsize)
rs->rs_msg = lustre_msg_buf_v2(rs->rs_repbuf, PLAIN_PACK_MSG_OFF, 0);
req->rq_reply_state = rs;
- RETURN(0);
+ return 0;
}
static
void plain_free_rs(struct ptlrpc_reply_state *rs)
{
- ENTRY;
-
LASSERT(atomic_read(&rs->rs_svc_ctx->sc_refcount) > 1);
atomic_dec(&rs->rs_svc_ctx->sc_refcount);
if (!rs->rs_prealloc)
OBD_FREE_LARGE(rs, rs->rs_size);
- EXIT;
}
static
@@ -844,7 +825,6 @@ int plain_authorize(struct ptlrpc_request *req)
struct lustre_msg_v2 *msg = rs->rs_repbuf;
struct plain_header *phdr;
int len;
- ENTRY;
LASSERT(rs);
LASSERT(msg);
@@ -882,7 +862,7 @@ int plain_authorize(struct ptlrpc_request *req)
req->rq_reply_off = 0;
}
- RETURN(0);
+ return 0;
}
static
diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c
index 1667b8e8601..ac8b5fd2300 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/service.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/service.c
@@ -369,7 +369,6 @@ static void rs_batch_fini(struct rs_batch *b)
void ptlrpc_dispatch_difficult_reply(struct ptlrpc_reply_state *rs)
{
struct ptlrpc_hr_thread *hrt;
- ENTRY;
LASSERT(list_empty(&rs->rs_list));
@@ -380,28 +379,23 @@ void ptlrpc_dispatch_difficult_reply(struct ptlrpc_reply_state *rs)
spin_unlock(&hrt->hrt_lock);
wake_up(&hrt->hrt_waitq);
- EXIT;
}
void
ptlrpc_schedule_difficult_reply(struct ptlrpc_reply_state *rs)
{
- ENTRY;
-
LASSERT(spin_is_locked(&rs->rs_svcpt->scp_rep_lock));
LASSERT(spin_is_locked(&rs->rs_lock));
LASSERT (rs->rs_difficult);
rs->rs_scheduled_ever = 1; /* flag any notification attempt */
if (rs->rs_scheduled) { /* being set up or already notified */
- EXIT;
return;
}
rs->rs_scheduled = 1;
list_del_init(&rs->rs_list);
ptlrpc_dispatch_difficult_reply(rs);
- EXIT;
}
EXPORT_SYMBOL(ptlrpc_schedule_difficult_reply);
@@ -409,7 +403,6 @@ void ptlrpc_commit_replies(struct obd_export *exp)
{
struct ptlrpc_reply_state *rs, *nxt;
DECLARE_RS_BATCH(batch);
- ENTRY;
rs_batch_init(&batch);
/* Find any replies that have been committed and get their service
@@ -429,7 +422,6 @@ void ptlrpc_commit_replies(struct obd_export *exp)
}
spin_unlock(&exp->exp_uncommitted_replies_lock);
rs_batch_fini(&batch);
- EXIT;
}
EXPORT_SYMBOL(ptlrpc_commit_replies);
@@ -551,6 +543,7 @@ ptlrpc_server_nthreads_check(struct ptlrpc_service *svc,
if (tc->tc_thr_factor != 0) {
int factor = tc->tc_thr_factor;
const int fade = 4;
+ cpumask_t mask;
/*
* User wants to increase number of threads with for
@@ -564,7 +557,8 @@ ptlrpc_server_nthreads_check(struct ptlrpc_service *svc,
* have too many threads no matter how many cores/HTs
* there are.
*/
- if (cfs_cpu_ht_nsiblings(0) > 1) { /* weight is # of HTs */
+ cpumask_copy(&mask, topology_thread_cpumask(0));
+ if (cpus_weight(mask) > 1) { /* weight is # of HTs */
/* depress thread factor for hyper-thread */
factor = factor - (factor >> 1) + (factor >> 3);
}
@@ -689,7 +683,7 @@ ptlrpc_service_part_init(struct ptlrpc_service *svc,
*/
struct ptlrpc_service *
ptlrpc_register_service(struct ptlrpc_service_conf *conf,
- proc_dir_entry_t *proc_entry)
+ struct proc_dir_entry *proc_entry)
{
struct ptlrpc_service_cpt_conf *cconf = &conf->psc_cpt;
struct ptlrpc_service *service;
@@ -700,7 +694,6 @@ ptlrpc_register_service(struct ptlrpc_service_conf *conf,
int cpt;
int rc;
int i;
- ENTRY;
LASSERT(conf->psc_buf.bc_nbufs > 0);
LASSERT(conf->psc_buf.bc_buf_size >=
@@ -724,7 +717,7 @@ ptlrpc_register_service(struct ptlrpc_service_conf *conf,
if (rc != 0) {
CERROR("%s: invalid CPT pattern string: %s",
conf->psc_name, cconf->cc_pattern);
- RETURN(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
}
rc = cfs_expr_list_values(el, ncpts, &cpts);
@@ -734,7 +727,7 @@ ptlrpc_register_service(struct ptlrpc_service_conf *conf,
conf->psc_name, cconf->cc_pattern, rc);
if (cpts != NULL)
OBD_FREE(cpts, sizeof(*cpts) * ncpts);
- RETURN(ERR_PTR(rc < 0 ? rc : -EINVAL));
+ return ERR_PTR(rc < 0 ? rc : -EINVAL);
}
ncpts = rc;
}
@@ -744,7 +737,7 @@ ptlrpc_register_service(struct ptlrpc_service_conf *conf,
if (service == NULL) {
if (cpts != NULL)
OBD_FREE(cpts, sizeof(*cpts) * ncpts);
- RETURN(ERR_PTR(-ENOMEM));
+ return ERR_PTR(-ENOMEM);
}
service->srv_cptable = cptable;
@@ -823,10 +816,10 @@ ptlrpc_register_service(struct ptlrpc_service_conf *conf,
GOTO(failed, rc);
}
- RETURN(service);
+ return service;
failed:
ptlrpc_unregister_service(service);
- RETURN(ERR_PTR(rc));
+ return ERR_PTR(rc);
}
EXPORT_SYMBOL(ptlrpc_register_service);
@@ -1035,8 +1028,6 @@ static void ptlrpc_update_export_timer(struct obd_export *exp, long extra_delay)
struct obd_export *oldest_exp;
time_t oldest_time, new_time;
- ENTRY;
-
LASSERT(exp);
/* Compensate for slow machines, etc, by faking our request time
@@ -1048,7 +1039,7 @@ static void ptlrpc_update_export_timer(struct obd_export *exp, long extra_delay)
/* Do not pay attention on 1sec or smaller renewals. */
new_time = cfs_time_current_sec() + extra_delay;
if (exp->exp_last_request_time + 1 /*second */ >= new_time)
- RETURN_EXIT;
+ return;
exp->exp_last_request_time = new_time;
CDEBUG(D_HA, "updating export %s at "CFS_TIME_T" exp %p\n",
@@ -1063,7 +1054,7 @@ static void ptlrpc_update_export_timer(struct obd_export *exp, long extra_delay)
if (list_empty(&exp->exp_obd_chain_timed)) {
/* this one is not timed */
spin_unlock(&exp->exp_obd->obd_dev_lock);
- RETURN_EXIT;
+ return;
}
list_move_tail(&exp->exp_obd_chain_timed,
@@ -1076,7 +1067,6 @@ static void ptlrpc_update_export_timer(struct obd_export *exp, long extra_delay)
if (exp->exp_obd->obd_recovering) {
/* be nice to everyone during recovery */
- EXIT;
return;
}
@@ -1105,8 +1095,6 @@ static void ptlrpc_update_export_timer(struct obd_export *exp, long extra_delay)
exp->exp_obd->obd_eviction_timer = 0;
}
}
-
- EXIT;
}
/**
@@ -1259,7 +1247,6 @@ static int ptlrpc_at_send_early_reply(struct ptlrpc_request *req)
cfs_duration_t olddl = req->rq_deadline - cfs_time_current_sec();
time_t newdl;
int rc;
- ENTRY;
/* deadline is when the client expects us to reply, margin is the
difference between clients' and servers' expectations */
@@ -1270,7 +1257,7 @@ static int ptlrpc_at_send_early_reply(struct ptlrpc_request *req)
at_get(&svcpt->scp_at_estimate), at_extra);
if (AT_OFF)
- RETURN(0);
+ return 0;
if (olddl < 0) {
DEBUG_REQ(D_WARNING, req, "Already past deadline (%+lds), "
@@ -1278,13 +1265,13 @@ static int ptlrpc_at_send_early_reply(struct ptlrpc_request *req)
"at_early_margin (%d)?", olddl, at_early_margin);
/* Return an error so we're not re-added to the timed list. */
- RETURN(-ETIMEDOUT);
+ return -ETIMEDOUT;
}
if ((lustre_msghdr_get_flags(req->rq_reqmsg) & MSGHDR_AT_SUPPORT) == 0){
DEBUG_REQ(D_INFO, req, "Wanted to ask client for more time, "
"but no AT support");
- RETURN(-ENOSYS);
+ return -ENOSYS;
}
if (req->rq_export &&
@@ -1314,18 +1301,18 @@ static int ptlrpc_at_send_early_reply(struct ptlrpc_request *req)
olddl, req->rq_arrival_time.tv_sec +
at_get(&svcpt->scp_at_estimate) -
cfs_time_current_sec());
- RETURN(-ETIMEDOUT);
+ return -ETIMEDOUT;
}
}
newdl = cfs_time_current_sec() + at_get(&svcpt->scp_at_estimate);
OBD_ALLOC(reqcopy, sizeof *reqcopy);
if (reqcopy == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
OBD_ALLOC_LARGE(reqmsg, req->rq_reqlen);
if (!reqmsg) {
OBD_FREE(reqcopy, sizeof *reqcopy);
- RETURN(-ENOMEM);
+ return -ENOMEM;
}
*reqcopy = *req;
@@ -1384,7 +1371,7 @@ out:
sptlrpc_svc_ctx_decref(reqcopy);
OBD_FREE_LARGE(reqmsg, req->rq_reqlen);
OBD_FREE(reqcopy, sizeof *reqcopy);
- RETURN(rc);
+ return rc;
}
/* Send early replies to everybody expiring within at_early_margin
@@ -1399,19 +1386,18 @@ static int ptlrpc_at_check_timed(struct ptlrpc_service_part *svcpt)
time_t now = cfs_time_current_sec();
cfs_duration_t delay;
int first, counter = 0;
- ENTRY;
spin_lock(&svcpt->scp_at_lock);
if (svcpt->scp_at_check == 0) {
spin_unlock(&svcpt->scp_at_lock);
- RETURN(0);
+ return 0;
}
delay = cfs_time_sub(cfs_time_current(), svcpt->scp_at_checktime);
svcpt->scp_at_check = 0;
if (array->paa_count == 0) {
spin_unlock(&svcpt->scp_at_lock);
- RETURN(0);
+ return 0;
}
/* The timer went off, but maybe the nearest rpc already completed. */
@@ -1420,7 +1406,7 @@ static int ptlrpc_at_check_timed(struct ptlrpc_service_part *svcpt)
/* We've still got plenty of time. Reset the timer. */
ptlrpc_at_set_timer(svcpt);
spin_unlock(&svcpt->scp_at_lock);
- RETURN(0);
+ return 0;
}
/* We're close to a timeout, and we don't know how much longer the
@@ -1490,7 +1476,7 @@ static int ptlrpc_at_check_timed(struct ptlrpc_service_part *svcpt)
ptlrpc_server_drop_request(rq);
}
- RETURN(1); /* return "did_something" for liblustre */
+ return 1; /* return "did_something" for liblustre */
}
/**
@@ -1501,12 +1487,11 @@ static int ptlrpc_server_hpreq_init(struct ptlrpc_service_part *svcpt,
struct ptlrpc_request *req)
{
int rc = 0;
- ENTRY;
if (svcpt->scp_service->srv_ops.so_hpreq_handler) {
rc = svcpt->scp_service->srv_ops.so_hpreq_handler(req);
if (rc < 0)
- RETURN(rc);
+ return rc;
LASSERT(rc == 0);
}
if (req->rq_export && req->rq_ops) {
@@ -1527,7 +1512,7 @@ static int ptlrpc_server_hpreq_init(struct ptlrpc_service_part *svcpt,
* ost_brw_write().
*/
if (rc < 0)
- RETURN(rc);
+ return rc;
LASSERT(rc == 0 || rc == 1);
}
@@ -1539,13 +1524,12 @@ static int ptlrpc_server_hpreq_init(struct ptlrpc_service_part *svcpt,
ptlrpc_nrs_req_initialize(svcpt, req, rc);
- RETURN(rc);
+ return rc;
}
/** Remove the request from the export list. */
static void ptlrpc_server_hpreq_fini(struct ptlrpc_request *req)
{
- ENTRY;
if (req->rq_export && req->rq_ops) {
/* refresh lock timeout again so that client has more
* room to send lock cancel RPC. */
@@ -1556,7 +1540,6 @@ static void ptlrpc_server_hpreq_fini(struct ptlrpc_request *req)
list_del_init(&req->rq_exp_list);
spin_unlock_bh(&req->rq_export->exp_rpc_lock);
}
- EXIT;
}
static int ptlrpc_hpreq_check(struct ptlrpc_request *req)
@@ -1587,15 +1570,14 @@ static int ptlrpc_server_request_add(struct ptlrpc_service_part *svcpt,
struct ptlrpc_request *req)
{
int rc;
- ENTRY;
rc = ptlrpc_server_hpreq_init(svcpt, req);
if (rc < 0)
- RETURN(rc);
+ return rc;
ptlrpc_nrs_req_add(svcpt, req, !!rc);
- RETURN(0);
+ return 0;
}
/**
@@ -1701,7 +1683,6 @@ static struct ptlrpc_request *
ptlrpc_server_request_get(struct ptlrpc_service_part *svcpt, bool force)
{
struct ptlrpc_request *req = NULL;
- ENTRY;
spin_lock(&svcpt->scp_req_lock);
@@ -1722,7 +1703,7 @@ ptlrpc_server_request_get(struct ptlrpc_service_part *svcpt, bool force)
}
spin_unlock(&svcpt->scp_req_lock);
- RETURN(NULL);
+ return NULL;
got_request:
svcpt->scp_nreqs_active++;
@@ -1734,7 +1715,7 @@ got_request:
if (likely(req->rq_export))
class_export_rpc_inc(req->rq_export);
- RETURN(req);
+ return req;
}
/**
@@ -1751,12 +1732,11 @@ ptlrpc_server_handle_req_in(struct ptlrpc_service_part *svcpt,
struct ptlrpc_request *req;
__u32 deadline;
int rc;
- ENTRY;
spin_lock(&svcpt->scp_lock);
if (list_empty(&svcpt->scp_req_incoming)) {
spin_unlock(&svcpt->scp_lock);
- RETURN(0);
+ return 0;
}
req = list_entry(svcpt->scp_req_incoming.next,
@@ -1875,12 +1855,12 @@ ptlrpc_server_handle_req_in(struct ptlrpc_service_part *svcpt,
GOTO(err_req, rc);
wake_up(&svcpt->scp_waitq);
- RETURN(1);
+ return 1;
err_req:
ptlrpc_server_finish_request(svcpt, req);
- RETURN(1);
+ return 1;
}
/**
@@ -1898,11 +1878,10 @@ ptlrpc_server_handle_request(struct ptlrpc_service_part *svcpt,
long timediff;
int rc;
int fail_opc = 0;
- ENTRY;
request = ptlrpc_server_request_get(svcpt, false);
if (request == NULL)
- RETURN(0);
+ return 0;
if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_HPREQ_NOTIMEOUT))
fail_opc = OBD_FAIL_PTLRPC_HPREQ_NOTIMEOUT;
@@ -2041,7 +2020,7 @@ put_conn:
out_req:
ptlrpc_server_finish_active_request(svcpt, request);
- RETURN(1);
+ return 1;
}
/**
@@ -2055,7 +2034,6 @@ ptlrpc_handle_rs(struct ptlrpc_reply_state *rs)
struct obd_export *exp;
int nlocks;
int been_handled;
- ENTRY;
exp = rs->rs_export;
@@ -2141,12 +2119,12 @@ ptlrpc_handle_rs(struct ptlrpc_reply_state *rs)
if (atomic_dec_and_test(&svcpt->scp_nreps_difficult) &&
svc->srv_is_stopping)
wake_up_all(&svcpt->scp_waitq);
- RETURN(1);
+ return 1;
}
/* still on the net; callback will schedule */
spin_unlock(&rs->rs_lock);
- RETURN(1);
+ return 1;
}
@@ -2252,7 +2230,9 @@ ptlrpc_wait_event(struct ptlrpc_service_part *svcpt,
struct l_wait_info lwi = LWI_TIMEOUT(svcpt->scp_rqbd_timeout,
ptlrpc_retry_rqbds, svcpt);
+ /* XXX: Add this back when libcfs watchdog is merged upstream
lc_watchdog_disable(thread->t_watchdog);
+ */
cond_resched();
@@ -2266,8 +2246,10 @@ ptlrpc_wait_event(struct ptlrpc_service_part *svcpt,
if (ptlrpc_thread_stopping(thread))
return -EINTR;
+ /*
lc_watchdog_touch(thread->t_watchdog,
ptlrpc_server_get_timeout(svcpt));
+ */
return 0;
}
@@ -2284,11 +2266,10 @@ static int ptlrpc_main(void *arg)
struct ptlrpc_service *svc = svcpt->scp_service;
struct ptlrpc_reply_state *rs;
#ifdef WITH_GROUP_INFO
- group_info_t *ginfo = NULL;
+ struct group_info *ginfo = NULL;
#endif
struct lu_env *env;
int counter = 0, rc = 0;
- ENTRY;
thread->t_pid = current_pid();
unshare_fs_struct();
@@ -2370,8 +2351,10 @@ static int ptlrpc_main(void *arg)
/* wake up our creator in case he's still waiting. */
wake_up(&thread->t_ctl_waitq);
+ /*
thread->t_watchdog = lc_watchdog_add(ptlrpc_server_get_timeout(svcpt),
NULL, NULL);
+ */
spin_lock(&svcpt->scp_rep_lock);
list_add(&rs->rs_list, &svcpt->scp_rep_idle);
@@ -2426,8 +2409,10 @@ static int ptlrpc_main(void *arg)
}
}
+ /*
lc_watchdog_delete(thread->t_watchdog);
thread->t_watchdog = NULL;
+ */
out_srv_fini:
/*
@@ -2550,7 +2535,6 @@ static int ptlrpc_start_hr_threads(void)
struct ptlrpc_hr_partition *hrp;
int i;
int j;
- ENTRY;
cfs_percpt_for_each(hrp, i, ptlrpc_hr.hr_partitions) {
int rc = 0;
@@ -2573,9 +2557,9 @@ static int ptlrpc_start_hr_threads(void)
CERROR("Reply handling thread %d:%d Failed on starting: "
"rc = %d\n", i, j, rc);
ptlrpc_stop_hr_threads();
- RETURN(rc);
+ return rc;
}
- RETURN(0);
+ return 0;
}
static void ptlrpc_svcpt_stop_threads(struct ptlrpc_service_part *svcpt)
@@ -2584,8 +2568,6 @@ static void ptlrpc_svcpt_stop_threads(struct ptlrpc_service_part *svcpt)
struct ptlrpc_thread *thread;
LIST_HEAD (zombie);
- ENTRY;
-
CDEBUG(D_INFO, "Stopping threads for service %s\n",
svcpt->scp_service->srv_name);
@@ -2625,7 +2607,6 @@ static void ptlrpc_svcpt_stop_threads(struct ptlrpc_service_part *svcpt)
list_del(&thread->t_link);
OBD_FREE_PTR(thread);
}
- EXIT;
}
/**
@@ -2635,14 +2616,11 @@ void ptlrpc_stop_all_threads(struct ptlrpc_service *svc)
{
struct ptlrpc_service_part *svcpt;
int i;
- ENTRY;
ptlrpc_service_for_each_part(svcpt, i, svc) {
if (svcpt->scp_service != NULL)
ptlrpc_svcpt_stop_threads(svcpt);
}
-
- EXIT;
}
EXPORT_SYMBOL(ptlrpc_stop_all_threads);
@@ -2651,7 +2629,6 @@ int ptlrpc_start_threads(struct ptlrpc_service *svc)
int rc = 0;
int i;
int j;
- ENTRY;
/* We require 2 threads min, see note in ptlrpc_server_handle_request */
LASSERT(svc->srv_nthrs_cpt_init >= PTLRPC_NTHRS_INIT);
@@ -2669,12 +2646,12 @@ int ptlrpc_start_threads(struct ptlrpc_service *svc)
}
}
- RETURN(0);
+ return 0;
failed:
CERROR("cannot start %s thread #%d_%d: rc %d\n",
svc->srv_thread_name, i, j, rc);
ptlrpc_stop_all_threads(svc);
- RETURN(rc);
+ return rc;
}
EXPORT_SYMBOL(ptlrpc_start_threads);
@@ -2684,7 +2661,6 @@ int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
struct ptlrpc_thread *thread;
struct ptlrpc_service *svc;
int rc;
- ENTRY;
LASSERT(svcpt != NULL);
@@ -2696,23 +2672,23 @@ int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
again:
if (unlikely(svc->srv_is_stopping))
- RETURN(-ESRCH);
+ return -ESRCH;
if (!ptlrpc_threads_increasable(svcpt) ||
(OBD_FAIL_CHECK(OBD_FAIL_TGT_TOOMANY_THREADS) &&
svcpt->scp_nthrs_running == svc->srv_nthrs_cpt_init - 1))
- RETURN(-EMFILE);
+ return -EMFILE;
OBD_CPT_ALLOC_PTR(thread, svc->srv_cptable, svcpt->scp_cpt);
if (thread == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
init_waitqueue_head(&thread->t_ctl_waitq);
spin_lock(&svcpt->scp_lock);
if (!ptlrpc_threads_increasable(svcpt)) {
spin_unlock(&svcpt->scp_lock);
OBD_FREE_PTR(thread);
- RETURN(-EMFILE);
+ return -EMFILE;
}
if (svcpt->scp_nthrs_starting != 0) {
@@ -2730,7 +2706,7 @@ int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
CDEBUG(D_INFO, "Creating thread %s #%d race, retry later\n",
svc->srv_thread_name, svcpt->scp_thr_nextid);
- RETURN(-EAGAIN);
+ return -EAGAIN;
}
svcpt->scp_nthrs_starting++;
@@ -2755,33 +2731,42 @@ int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
CERROR("cannot start thread '%s': rc %d\n",
thread->t_name, rc);
spin_lock(&svcpt->scp_lock);
- list_del(&thread->t_link);
--svcpt->scp_nthrs_starting;
- spin_unlock(&svcpt->scp_lock);
-
- OBD_FREE(thread, sizeof(*thread));
- RETURN(rc);
+ if (thread_is_stopping(thread)) {
+ /* this ptlrpc_thread is being hanled
+ * by ptlrpc_svcpt_stop_threads now
+ */
+ thread_add_flags(thread, SVC_STOPPED);
+ wake_up(&thread->t_ctl_waitq);
+ spin_unlock(&svcpt->scp_lock);
+ } else {
+ list_del(&thread->t_link);
+ spin_unlock(&svcpt->scp_lock);
+ OBD_FREE_PTR(thread);
+ }
+ return rc;
}
if (!wait)
- RETURN(0);
+ return 0;
l_wait_event(thread->t_ctl_waitq,
thread_is_running(thread) || thread_is_stopped(thread),
&lwi);
rc = thread_is_stopped(thread) ? thread->t_id : 0;
- RETURN(rc);
+ return rc;
}
int ptlrpc_hr_init(void)
{
+ cpumask_t mask;
struct ptlrpc_hr_partition *hrp;
struct ptlrpc_hr_thread *hrt;
int rc;
int i;
int j;
- ENTRY;
+ int weight;
memset(&ptlrpc_hr, 0, sizeof(ptlrpc_hr));
ptlrpc_hr.hr_cpt_table = cfs_cpt_table;
@@ -2789,10 +2774,13 @@ int ptlrpc_hr_init(void)
ptlrpc_hr.hr_partitions = cfs_percpt_alloc(ptlrpc_hr.hr_cpt_table,
sizeof(*hrp));
if (ptlrpc_hr.hr_partitions == NULL)
- RETURN(-ENOMEM);
+ return -ENOMEM;
init_waitqueue_head(&ptlrpc_hr.hr_waitq);
+ cpumask_copy(&mask, topology_thread_cpumask(0));
+ weight = cpus_weight(mask);
+
cfs_percpt_for_each(hrp, i, ptlrpc_hr.hr_partitions) {
hrp->hrp_cpt = i;
@@ -2800,7 +2788,7 @@ int ptlrpc_hr_init(void)
atomic_set(&hrp->hrp_nstopped, 0);
hrp->hrp_nthrs = cfs_cpt_weight(ptlrpc_hr.hr_cpt_table, i);
- hrp->hrp_nthrs /= cfs_cpu_ht_nsiblings(0);
+ hrp->hrp_nthrs /= weight;
LASSERT(hrp->hrp_nthrs > 0);
OBD_CPT_ALLOC(hrp->hrp_thrs, ptlrpc_hr.hr_cpt_table, i,
@@ -2823,7 +2811,7 @@ int ptlrpc_hr_init(void)
out:
if (rc != 0)
ptlrpc_hr_fini();
- RETURN(rc);
+ return rc;
}
void ptlrpc_hr_fini(void)
@@ -3045,8 +3033,6 @@ ptlrpc_service_free(struct ptlrpc_service *svc)
int ptlrpc_unregister_service(struct ptlrpc_service *service)
{
- ENTRY;
-
CDEBUG(D_NET, "%s: tearing down\n", service->srv_name);
service->srv_is_stopping = 1;
@@ -3066,7 +3052,7 @@ int ptlrpc_unregister_service(struct ptlrpc_service *service)
ptlrpc_service_free(service);
- RETURN(0);
+ return 0;
}
EXPORT_SYMBOL(ptlrpc_unregister_service);
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 10393da315d..5a5c6397e74 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -750,8 +750,6 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec)
writel(0, nvec->base + I2C_SL_ADDR2);
enable_irq(nvec->irq);
-
- clk_disable_unprepare(nvec->i2c_clk);
}
#ifdef CONFIG_PM_SLEEP
@@ -872,9 +870,6 @@ static int tegra_nvec_probe(struct platform_device *pdev)
tegra_init_i2c_slave(nvec);
- clk_prepare_enable(i2c_clk);
-
-
/* enable event reporting */
nvec_toggle_global_events(nvec, true);
diff --git a/drivers/staging/octeon-usb/Kconfig b/drivers/staging/octeon-usb/Kconfig
index 018af6db08c..16ea17ff3fd 100644
--- a/drivers/staging/octeon-usb/Kconfig
+++ b/drivers/staging/octeon-usb/Kconfig
@@ -1,6 +1,6 @@
config OCTEON_USB
tristate "Cavium Networks Octeon USB support"
- depends on CPU_CAVIUM_OCTEON && USB
+ depends on CAVIUM_OCTEON_SOC && USB
help
This driver supports USB host controller on some Cavium
Networks' products in the Octeon family.
diff --git a/drivers/staging/octeon-usb/cvmx-usb.c b/drivers/staging/octeon-usb/cvmx-usb.c
index bf366495fdd..d7b3c82b5ea 100644
--- a/drivers/staging/octeon-usb/cvmx-usb.c
+++ b/drivers/staging/octeon-usb/cvmx-usb.c
@@ -46,8 +46,6 @@
* systems. These functions provide a generic API to the Octeon
* USB blocks, hiding the internal hardware specific
* operations.
- *
- * <hr>$Revision: 32636 $<hr>
*/
#include <linux/delay.h>
#include <asm/octeon/cvmx.h>
@@ -68,30 +66,27 @@
#define CVMX_PREFETCH_PREF0(address, offset) CVMX_PREFETCH_PREFX(0, address, offset)
#define CVMX_CLZ(result, input) asm ("clz %[rd],%[rs]" : [rd] "=d" (result) : [rs] "d" (input))
-#define cvmx_likely likely
-#define cvmx_wait_usec udelay
-#define cvmx_unlikely unlikely
-#define cvmx_le16_to_cpu le16_to_cpu
-
-#define MAX_RETRIES 3 /* Maximum number of times to retry failed transactions */
-#define MAX_PIPES 32 /* Maximum number of pipes that can be open at once */
-#define MAX_TRANSACTIONS 256 /* Maximum number of outstanding transactions across all pipes */
-#define MAX_CHANNELS 8 /* Maximum number of hardware channels supported by the USB block */
-#define MAX_USB_ADDRESS 127 /* The highest valid USB device address */
-#define MAX_USB_ENDPOINT 15 /* The highest valid USB endpoint number */
-#define MAX_USB_HUB_PORT 15 /* The highest valid port number on a hub */
-#define MAX_TRANSFER_BYTES ((1<<19)-1) /* The low level hardware can transfer a maximum of this number of bytes in each transfer. The field is 19 bits wide */
-#define MAX_TRANSFER_PACKETS ((1<<10)-1) /* The low level hardware can transfer a maximum of this number of packets in each transfer. The field is 10 bits wide */
-
-/* These defines disable the normal read and write csr. This is so I can add
- extra debug stuff to the usb specific version and I won't use the normal
- version by mistake */
+#define MAX_RETRIES 3 /* Maximum number of times to retry failed transactions */
+#define MAX_PIPES 32 /* Maximum number of pipes that can be open at once */
+#define MAX_TRANSACTIONS 256 /* Maximum number of outstanding transactions across all pipes */
+#define MAX_CHANNELS 8 /* Maximum number of hardware channels supported by the USB block */
+#define MAX_USB_ADDRESS 127 /* The highest valid USB device address */
+#define MAX_USB_ENDPOINT 15 /* The highest valid USB endpoint number */
+#define MAX_USB_HUB_PORT 15 /* The highest valid port number on a hub */
+#define MAX_TRANSFER_BYTES ((1<<19)-1) /* The low level hardware can transfer a maximum of this number of bytes in each transfer. The field is 19 bits wide */
+#define MAX_TRANSFER_PACKETS ((1<<10)-1) /* The low level hardware can transfer a maximum of this number of packets in each transfer. The field is 10 bits wide */
+
+/*
+ * These defines disable the normal read and write csr. This is so I can add
+ * extra debug stuff to the usb specific version and I won't use the normal
+ * version by mistake
+ */
#define cvmx_read_csr use_cvmx_usb_read_csr64_instead_of_cvmx_read_csr
#define cvmx_write_csr use_cvmx_usb_write_csr64_instead_of_cvmx_write_csr
-typedef enum {
- __CVMX_USB_TRANSACTION_FLAGS_IN_USE = 1<<16,
-} cvmx_usb_transaction_flags_t;
+enum cvmx_usb_transaction_flags {
+ __CVMX_USB_TRANSACTION_FLAGS_IN_USE = 1<<16,
+};
enum {
USB_CLOCK_TYPE_REF_12,
@@ -108,167 +103,208 @@ enum {
* the NAK handler can backup to the previous low level
* transaction with a simple clearing of bit 0.
*/
-typedef enum {
- CVMX_USB_STAGE_NON_CONTROL,
- CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE,
- CVMX_USB_STAGE_SETUP,
- CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE,
- CVMX_USB_STAGE_DATA,
- CVMX_USB_STAGE_DATA_SPLIT_COMPLETE,
- CVMX_USB_STAGE_STATUS,
- CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE,
-} cvmx_usb_stage_t;
+enum cvmx_usb_stage {
+ CVMX_USB_STAGE_NON_CONTROL,
+ CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE,
+ CVMX_USB_STAGE_SETUP,
+ CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE,
+ CVMX_USB_STAGE_DATA,
+ CVMX_USB_STAGE_DATA_SPLIT_COMPLETE,
+ CVMX_USB_STAGE_STATUS,
+ CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE,
+};
+
+/**
+ * struct cvmx_usb_transaction - describes each pending USB transaction
+ * regardless of type. These are linked together
+ * to form a list of pending requests for a pipe.
+ *
+ * @prev: Transaction before this one in the pipe.
+ * @next: Transaction after this one in the pipe.
+ * @type: Type of transaction, duplicated of the pipe.
+ * @flags: State flags for this transaction.
+ * @buffer: User's physical buffer address to read/write.
+ * @buffer_length: Size of the user's buffer in bytes.
+ * @control_header: For control transactions, physical address of the 8
+ * byte standard header.
+ * @iso_start_frame: For ISO transactions, the starting frame number.
+ * @iso_number_packets: For ISO transactions, the number of packets in the
+ * request.
+ * @iso_packets: For ISO transactions, the sub packets in the request.
+ * @actual_bytes: Actual bytes transfer for this transaction.
+ * @stage: For control transactions, the current stage.
+ * @callback: User's callback function when complete.
+ * @callback_data: User's data.
+ */
+struct cvmx_usb_transaction {
+ struct cvmx_usb_transaction *prev;
+ struct cvmx_usb_transaction *next;
+ enum cvmx_usb_transfer type;
+ enum cvmx_usb_transaction_flags flags;
+ uint64_t buffer;
+ int buffer_length;
+ uint64_t control_header;
+ int iso_start_frame;
+ int iso_number_packets;
+ struct cvmx_usb_iso_packet *iso_packets;
+ int xfersize;
+ int pktcnt;
+ int retries;
+ int actual_bytes;
+ enum cvmx_usb_stage stage;
+ cvmx_usb_callback_func_t callback;
+ void *callback_data;
+};
/**
- * This structure describes each pending USB transaction
- * regardless of type. These are linked together to form a list
- * of pending requests for a pipe.
+ * struct cvmx_usb_pipe - a pipe represents a virtual connection between Octeon
+ * and some USB device. It contains a list of pending
+ * request to the device.
+ *
+ * @prev: Pipe before this one in the list
+ * @next: Pipe after this one in the list
+ * @head: The first pending transaction
+ * @tail: The last pending transaction
+ * @interval: For periodic pipes, the interval between packets in
+ * frames
+ * @next_tx_frame: The next frame this pipe is allowed to transmit on
+ * @flags: State flags for this pipe
+ * @device_speed: Speed of device connected to this pipe
+ * @transfer_type: Type of transaction supported by this pipe
+ * @transfer_dir: IN or OUT. Ignored for Control
+ * @multi_count: Max packet in a row for the device
+ * @max_packet: The device's maximum packet size in bytes
+ * @device_addr: USB device address at other end of pipe
+ * @endpoint_num: USB endpoint number at other end of pipe
+ * @hub_device_addr: Hub address this device is connected to
+ * @hub_port: Hub port this device is connected to
+ * @pid_toggle: This toggles between 0/1 on every packet send to track
+ * the data pid needed
+ * @channel: Hardware DMA channel for this pipe
+ * @split_sc_frame: The low order bits of the frame number the split
+ * complete should be sent on
*/
-typedef struct cvmx_usb_transaction {
- struct cvmx_usb_transaction *prev; /**< Transaction before this one in the pipe */
- struct cvmx_usb_transaction *next; /**< Transaction after this one in the pipe */
- cvmx_usb_transfer_t type; /**< Type of transaction, duplicated of the pipe */
- cvmx_usb_transaction_flags_t flags; /**< State flags for this transaction */
- uint64_t buffer; /**< User's physical buffer address to read/write */
- int buffer_length; /**< Size of the user's buffer in bytes */
- uint64_t control_header; /**< For control transactions, physical address of the 8 byte standard header */
- int iso_start_frame; /**< For ISO transactions, the starting frame number */
- int iso_number_packets; /**< For ISO transactions, the number of packets in the request */
- cvmx_usb_iso_packet_t *iso_packets; /**< For ISO transactions, the sub packets in the request */
- int xfersize;
- int pktcnt;
- int retries;
- int actual_bytes; /**< Actual bytes transfer for this transaction */
- cvmx_usb_stage_t stage; /**< For control transactions, the current stage */
- cvmx_usb_callback_func_t callback; /**< User's callback function when complete */
- void *callback_data; /**< User's data */
-} cvmx_usb_transaction_t;
+struct cvmx_usb_pipe {
+ struct cvmx_usb_pipe *prev;
+ struct cvmx_usb_pipe *next;
+ struct cvmx_usb_transaction *head;
+ struct cvmx_usb_transaction *tail;
+ uint64_t interval;
+ uint64_t next_tx_frame;
+ enum cvmx_usb_pipe_flags flags;
+ enum cvmx_usb_speed device_speed;
+ enum cvmx_usb_transfer transfer_type;
+ enum cvmx_usb_direction transfer_dir;
+ int multi_count;
+ uint16_t max_packet;
+ uint8_t device_addr;
+ uint8_t endpoint_num;
+ uint8_t hub_device_addr;
+ uint8_t hub_port;
+ uint8_t pid_toggle;
+ uint8_t channel;
+ int8_t split_sc_frame;
+};
/**
- * A pipe represents a virtual connection between Octeon and some
- * USB device. It contains a list of pending request to the device.
+ * struct cvmx_usb_pipe_list
+ *
+ * @head: Head of the list, or NULL if empty.
+ * @tail: Tail if the list, or NULL if empty.
*/
-typedef struct cvmx_usb_pipe {
- struct cvmx_usb_pipe *prev; /**< Pipe before this one in the list */
- struct cvmx_usb_pipe *next; /**< Pipe after this one in the list */
- cvmx_usb_transaction_t *head; /**< The first pending transaction */
- cvmx_usb_transaction_t *tail; /**< The last pending transaction */
- uint64_t interval; /**< For periodic pipes, the interval between packets in frames */
- uint64_t next_tx_frame; /**< The next frame this pipe is allowed to transmit on */
- cvmx_usb_pipe_flags_t flags; /**< State flags for this pipe */
- cvmx_usb_speed_t device_speed; /**< Speed of device connected to this pipe */
- cvmx_usb_transfer_t transfer_type; /**< Type of transaction supported by this pipe */
- cvmx_usb_direction_t transfer_dir; /**< IN or OUT. Ignored for Control */
- int multi_count; /**< Max packet in a row for the device */
- uint16_t max_packet; /**< The device's maximum packet size in bytes */
- uint8_t device_addr; /**< USB device address at other end of pipe */
- uint8_t endpoint_num; /**< USB endpoint number at other end of pipe */
- uint8_t hub_device_addr; /**< Hub address this device is connected to */
- uint8_t hub_port; /**< Hub port this device is connected to */
- uint8_t pid_toggle; /**< This toggles between 0/1 on every packet send to track the data pid needed */
- uint8_t channel; /**< Hardware DMA channel for this pipe */
- int8_t split_sc_frame; /**< The low order bits of the frame number the split complete should be sent on */
-} cvmx_usb_pipe_t;
-
-typedef struct {
- cvmx_usb_pipe_t *head; /**< Head of the list, or NULL if empty */
- cvmx_usb_pipe_t *tail; /**< Tail if the list, or NULL if empty */
-} cvmx_usb_pipe_list_t;
-
-typedef struct {
- struct {
- int channel;
- int size;
- uint64_t address;
- } entry[MAX_CHANNELS+1];
- int head;
- int tail;
-} cvmx_usb_tx_fifo_t;
+struct cvmx_usb_pipe_list {
+ struct cvmx_usb_pipe *head;
+ struct cvmx_usb_pipe *tail;
+};
+
+struct cvmx_usb_tx_fifo {
+ struct {
+ int channel;
+ int size;
+ uint64_t address;
+ } entry[MAX_CHANNELS+1];
+ int head;
+ int tail;
+};
/**
- * The state of the USB block is stored in this structure
+ * struct cvmx_usb_internal_state - the state of the USB block
+ *
+ * init_flags: Flags passed to initialize.
+ * index: Which USB block this is for.
+ * idle_hardware_channels: Bit set for every idle hardware channel.
+ * usbcx_hprt: Stored port status so we don't need to read a CSR to
+ * determine splits.
+ * pipe_for_channel: Map channels to pipes.
+ * free_transaction_head: List of free transactions head.
+ * free_transaction_tail: List of free transactions tail.
+ * pipe: Storage for pipes.
+ * transaction: Storage for transactions.
+ * callback: User global callbacks.
+ * callback_data: User data for each callback.
+ * indent: Used by debug output to indent functions.
+ * port_status: Last port status used for change notification.
+ * free_pipes: List of all pipes that are currently closed.
+ * idle_pipes: List of open pipes that have no transactions.
+ * active_pipes: Active pipes indexed by transfer type.
+ * frame_number: Increments every SOF interrupt for time keeping.
+ * active_split: Points to the current active split, or NULL.
*/
-typedef struct {
- int init_flags; /**< Flags passed to initialize */
- int index; /**< Which USB block this is for */
- int idle_hardware_channels; /**< Bit set for every idle hardware channel */
- cvmx_usbcx_hprt_t usbcx_hprt; /**< Stored port status so we don't need to read a CSR to determine splits */
- cvmx_usb_pipe_t *pipe_for_channel[MAX_CHANNELS]; /**< Map channels to pipes */
- cvmx_usb_transaction_t *free_transaction_head; /**< List of free transactions head */
- cvmx_usb_transaction_t *free_transaction_tail; /**< List of free transactions tail */
- cvmx_usb_pipe_t pipe[MAX_PIPES]; /**< Storage for pipes */
- cvmx_usb_transaction_t transaction[MAX_TRANSACTIONS]; /**< Storage for transactions */
- cvmx_usb_callback_func_t callback[__CVMX_USB_CALLBACK_END]; /**< User global callbacks */
- void *callback_data[__CVMX_USB_CALLBACK_END]; /**< User data for each callback */
- int indent; /**< Used by debug output to indent functions */
- cvmx_usb_port_status_t port_status; /**< Last port status used for change notification */
- cvmx_usb_pipe_list_t free_pipes; /**< List of all pipes that are currently closed */
- cvmx_usb_pipe_list_t idle_pipes; /**< List of open pipes that have no transactions */
- cvmx_usb_pipe_list_t active_pipes[4]; /**< Active pipes indexed by transfer type */
- uint64_t frame_number; /**< Increments every SOF interrupt for time keeping */
- cvmx_usb_transaction_t *active_split; /**< Points to the current active split, or NULL */
- cvmx_usb_tx_fifo_t periodic;
- cvmx_usb_tx_fifo_t nonperiodic;
-} cvmx_usb_internal_state_t;
-
-/* This macro logs out whenever a function is called if debugging is on */
-#define CVMX_USB_LOG_CALLED() \
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS)) \
- cvmx_dprintf("%*s%s: called\n", 2*usb->indent++, "", __FUNCTION__);
-
-/* This macro logs out each function parameter if debugging is on */
-#define CVMX_USB_LOG_PARAM(format, param) \
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS)) \
- cvmx_dprintf("%*s%s: param %s = " format "\n", 2*usb->indent, "", __FUNCTION__, #param, param);
-
-/* This macro logs out when a function returns a value */
-#define CVMX_USB_RETURN(v) \
- do { \
- typeof(v) r = v; \
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS)) \
- cvmx_dprintf("%*s%s: returned %s(%d)\n", 2*--usb->indent, "", __FUNCTION__, #v, r); \
- return r; \
- } while (0);
-
-/* This macro logs out when a function doesn't return a value */
-#define CVMX_USB_RETURN_NOTHING() \
- do { \
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS)) \
- cvmx_dprintf("%*s%s: returned\n", 2*--usb->indent, "", __FUNCTION__); \
- return; \
- } while (0);
+struct cvmx_usb_internal_state {
+ int init_flags;
+ int index;
+ int idle_hardware_channels;
+ union cvmx_usbcx_hprt usbcx_hprt;
+ struct cvmx_usb_pipe *pipe_for_channel[MAX_CHANNELS];
+ struct cvmx_usb_transaction *free_transaction_head;
+ struct cvmx_usb_transaction *free_transaction_tail;
+ struct cvmx_usb_pipe pipe[MAX_PIPES];
+ struct cvmx_usb_transaction transaction[MAX_TRANSACTIONS];
+ cvmx_usb_callback_func_t callback[__CVMX_USB_CALLBACK_END];
+ void *callback_data[__CVMX_USB_CALLBACK_END];
+ int indent;
+ struct cvmx_usb_port_status port_status;
+ struct cvmx_usb_pipe_list free_pipes;
+ struct cvmx_usb_pipe_list idle_pipes;
+ struct cvmx_usb_pipe_list active_pipes[4];
+ uint64_t frame_number;
+ struct cvmx_usb_transaction *active_split;
+ struct cvmx_usb_tx_fifo periodic;
+ struct cvmx_usb_tx_fifo nonperiodic;
+};
/* This macro spins on a field waiting for it to reach a value */
#define CVMX_WAIT_FOR_FIELD32(address, type, field, op, value, timeout_usec)\
- ({int result; \
- do { \
- uint64_t done = cvmx_get_cycle() + (uint64_t)timeout_usec * \
- octeon_get_clock_rate() / 1000000; \
- type c; \
- while (1) \
- { \
- c.u32 = __cvmx_usb_read_csr32(usb, address); \
- if (c.s.field op (value)) { \
- result = 0; \
- break; \
- } else if (cvmx_get_cycle() > done) { \
- result = -1; \
- break; \
- } else \
- cvmx_wait(100); \
- } \
- } while (0); \
- result;})
-
-/* This macro logically sets a single field in a CSR. It does the sequence
- read, modify, and write */
-#define USB_SET_FIELD32(address, type, field, value)\
- do { \
- type c; \
- c.u32 = __cvmx_usb_read_csr32(usb, address);\
- c.s.field = value; \
- __cvmx_usb_write_csr32(usb, address, c.u32);\
- } while (0)
+ ({int result; \
+ do { \
+ uint64_t done = cvmx_get_cycle() + (uint64_t)timeout_usec * \
+ octeon_get_clock_rate() / 1000000; \
+ type c; \
+ while (1) { \
+ c.u32 = __cvmx_usb_read_csr32(usb, address); \
+ if (c.s.field op (value)) { \
+ result = 0; \
+ break; \
+ } else if (cvmx_get_cycle() > done) { \
+ result = -1; \
+ break; \
+ } else \
+ cvmx_wait(100); \
+ } \
+ } while (0); \
+ result; })
+
+/*
+ * This macro logically sets a single field in a CSR. It does the sequence
+ * read, modify, and write
+ */
+#define USB_SET_FIELD32(address, type, field, value) \
+ do { \
+ type c; \
+ c.u32 = __cvmx_usb_read_csr32(usb, address); \
+ c.s.field = value; \
+ __cvmx_usb_write_csr32(usb, address, c.u32); \
+ } while (0)
/* Returns the IO address to push/pop stuff data from the FIFOs */
#define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000)
@@ -280,145 +316,106 @@ static int octeon_usb_get_clock_type(void)
case CVMX_BOARD_TYPE_LANAI2_A:
case CVMX_BOARD_TYPE_LANAI2_U:
case CVMX_BOARD_TYPE_LANAI2_G:
+ case CVMX_BOARD_TYPE_UBNT_E100:
return USB_CLOCK_TYPE_CRYSTAL_12;
}
-
- /* FIXME: This should use CVMX_BOARD_TYPE_UBNT_E100 */
- if (OCTEON_IS_MODEL(OCTEON_CN50XX) &&
- cvmx_sysinfo_get()->board_type == 20002)
- return USB_CLOCK_TYPE_CRYSTAL_12;
-
return USB_CLOCK_TYPE_REF_48;
}
/**
- * @INTERNAL
* Read a USB 32bit CSR. It performs the necessary address swizzle
* for 32bit CSRs and logs the value in a readable format if
* debugging is on.
*
- * @param usb USB block this access is for
- * @param address 64bit address to read
+ * @usb: USB block this access is for
+ * @address: 64bit address to read
*
- * @return Result of the read
+ * Returns: Result of the read
*/
-static inline uint32_t __cvmx_usb_read_csr32(cvmx_usb_internal_state_t *usb,
- uint64_t address)
+static inline uint32_t __cvmx_usb_read_csr32(struct cvmx_usb_internal_state *usb,
+ uint64_t address)
{
- uint32_t result = cvmx_read64_uint32(address ^ 4);
- return result;
+ uint32_t result = cvmx_read64_uint32(address ^ 4);
+ return result;
}
/**
- * @INTERNAL
* Write a USB 32bit CSR. It performs the necessary address
* swizzle for 32bit CSRs and logs the value in a readable format
* if debugging is on.
*
- * @param usb USB block this access is for
- * @param address 64bit address to write
- * @param value Value to write
+ * @usb: USB block this access is for
+ * @address: 64bit address to write
+ * @value: Value to write
*/
-static inline void __cvmx_usb_write_csr32(cvmx_usb_internal_state_t *usb,
- uint64_t address, uint32_t value)
+static inline void __cvmx_usb_write_csr32(struct cvmx_usb_internal_state *usb,
+ uint64_t address, uint32_t value)
{
- cvmx_write64_uint32(address ^ 4, value);
- cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
+ cvmx_write64_uint32(address ^ 4, value);
+ cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
}
/**
- * @INTERNAL
* Read a USB 64bit CSR. It logs the value in a readable format if
* debugging is on.
*
- * @param usb USB block this access is for
- * @param address 64bit address to read
+ * @usb: USB block this access is for
+ * @address: 64bit address to read
*
- * @return Result of the read
+ * Returns: Result of the read
*/
-static inline uint64_t __cvmx_usb_read_csr64(cvmx_usb_internal_state_t *usb,
- uint64_t address)
+static inline uint64_t __cvmx_usb_read_csr64(struct cvmx_usb_internal_state *usb,
+ uint64_t address)
{
- uint64_t result = cvmx_read64_uint64(address);
- return result;
+ uint64_t result = cvmx_read64_uint64(address);
+ return result;
}
/**
- * @INTERNAL
* Write a USB 64bit CSR. It logs the value in a readable format
* if debugging is on.
*
- * @param usb USB block this access is for
- * @param address 64bit address to write
- * @param value Value to write
- */
-static inline void __cvmx_usb_write_csr64(cvmx_usb_internal_state_t *usb,
- uint64_t address, uint64_t value)
-{
- cvmx_write64_uint64(address, value);
-}
-
-
-/**
- * @INTERNAL
- * Utility function to convert complete codes into strings
- *
- * @param complete_code
- * Code to convert
- *
- * @return Human readable string
+ * @usb: USB block this access is for
+ * @address: 64bit address to write
+ * @value: Value to write
*/
-static const char *__cvmx_usb_complete_to_string(cvmx_usb_complete_t complete_code)
+static inline void __cvmx_usb_write_csr64(struct cvmx_usb_internal_state *usb,
+ uint64_t address, uint64_t value)
{
- switch (complete_code)
- {
- case CVMX_USB_COMPLETE_SUCCESS: return "SUCCESS";
- case CVMX_USB_COMPLETE_SHORT: return "SHORT";
- case CVMX_USB_COMPLETE_CANCEL: return "CANCEL";
- case CVMX_USB_COMPLETE_ERROR: return "ERROR";
- case CVMX_USB_COMPLETE_STALL: return "STALL";
- case CVMX_USB_COMPLETE_XACTERR: return "XACTERR";
- case CVMX_USB_COMPLETE_DATATGLERR: return "DATATGLERR";
- case CVMX_USB_COMPLETE_BABBLEERR: return "BABBLEERR";
- case CVMX_USB_COMPLETE_FRAMEERR: return "FRAMEERR";
- }
- return "Update __cvmx_usb_complete_to_string";
+ cvmx_write64_uint64(address, value);
}
-
/**
- * @INTERNAL
* Return non zero if this pipe connects to a non HIGH speed
* device through a high speed hub.
*
- * @param usb USB block this access is for
- * @param pipe Pipe to check
+ * @usb: USB block this access is for
+ * @pipe: Pipe to check
*
- * @return Non zero if we need to do split transactions
+ * Returns: Non zero if we need to do split transactions
*/
-static inline int __cvmx_usb_pipe_needs_split(cvmx_usb_internal_state_t *usb, cvmx_usb_pipe_t *pipe)
+static inline int __cvmx_usb_pipe_needs_split(struct cvmx_usb_internal_state *usb, struct cvmx_usb_pipe *pipe)
{
- return ((pipe->device_speed != CVMX_USB_SPEED_HIGH) && (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH));
+ return ((pipe->device_speed != CVMX_USB_SPEED_HIGH) && (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH));
}
/**
- * @INTERNAL
* Trivial utility function to return the correct PID for a pipe
*
- * @param pipe pipe to check
+ * @pipe: pipe to check
*
- * @return PID for pipe
+ * Returns: PID for pipe
*/
-static inline int __cvmx_usb_get_data_pid(cvmx_usb_pipe_t *pipe)
+static inline int __cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe)
{
- if (pipe->pid_toggle)
- return 2; /* Data1 */
- else
- return 0; /* Data0 */
+ if (pipe->pid_toggle)
+ return 2; /* Data1 */
+ else
+ return 0; /* Data0 */
}
@@ -428,127 +425,119 @@ static inline int __cvmx_usb_get_data_pid(cvmx_usb_pipe_t *pipe)
* by this API, a zero will be returned. Most Octeon chips
* support one usb port, but some support two ports.
* cvmx_usb_initialize() must be called on independent
- * cvmx_usb_state_t structures.
+ * struct cvmx_usb_state.
*
- * @return Number of port, zero if usb isn't supported
+ * Returns: Number of port, zero if usb isn't supported
*/
int cvmx_usb_get_num_ports(void)
{
- int arch_ports = 0;
-
- if (OCTEON_IS_MODEL(OCTEON_CN56XX))
- arch_ports = 1;
- else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
- arch_ports = 2;
- else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
- arch_ports = 1;
- else if (OCTEON_IS_MODEL(OCTEON_CN31XX))
- arch_ports = 1;
- else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
- arch_ports = 1;
- else
- arch_ports = 0;
-
- return arch_ports;
+ int arch_ports = 0;
+
+ if (OCTEON_IS_MODEL(OCTEON_CN56XX))
+ arch_ports = 1;
+ else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
+ arch_ports = 2;
+ else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
+ arch_ports = 1;
+ else if (OCTEON_IS_MODEL(OCTEON_CN31XX))
+ arch_ports = 1;
+ else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
+ arch_ports = 1;
+ else
+ arch_ports = 0;
+
+ return arch_ports;
}
/**
- * @INTERNAL
* Allocate a usb transaction for use
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
*
- * @return Transaction or NULL
+ * Returns: Transaction or NULL
*/
-static inline cvmx_usb_transaction_t *__cvmx_usb_alloc_transaction(cvmx_usb_internal_state_t *usb)
+static inline struct cvmx_usb_transaction *__cvmx_usb_alloc_transaction(struct cvmx_usb_internal_state *usb)
{
- cvmx_usb_transaction_t *t;
- t = usb->free_transaction_head;
- if (t) {
- usb->free_transaction_head = t->next;
- if (!usb->free_transaction_head)
- usb->free_transaction_tail = NULL;
- }
- else if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
- cvmx_dprintf("%s: Failed to allocate a transaction\n", __FUNCTION__);
- if (t) {
- memset(t, 0, sizeof(*t));
- t->flags = __CVMX_USB_TRANSACTION_FLAGS_IN_USE;
- }
- return t;
+ struct cvmx_usb_transaction *t;
+ t = usb->free_transaction_head;
+ if (t) {
+ usb->free_transaction_head = t->next;
+ if (!usb->free_transaction_head)
+ usb->free_transaction_tail = NULL;
+ }
+ if (t) {
+ memset(t, 0, sizeof(*t));
+ t->flags = __CVMX_USB_TRANSACTION_FLAGS_IN_USE;
+ }
+ return t;
}
/**
- * @INTERNAL
* Free a usb transaction
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param transaction
- * Transaction to free
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @transaction:
+ * Transaction to free
*/
-static inline void __cvmx_usb_free_transaction(cvmx_usb_internal_state_t *usb,
- cvmx_usb_transaction_t *transaction)
+static inline void __cvmx_usb_free_transaction(struct cvmx_usb_internal_state *usb,
+ struct cvmx_usb_transaction *transaction)
{
- transaction->flags = 0;
- transaction->prev = NULL;
- transaction->next = NULL;
- if (usb->free_transaction_tail)
- usb->free_transaction_tail->next = transaction;
- else
- usb->free_transaction_head = transaction;
- usb->free_transaction_tail = transaction;
+ transaction->flags = 0;
+ transaction->prev = NULL;
+ transaction->next = NULL;
+ if (usb->free_transaction_tail)
+ usb->free_transaction_tail->next = transaction;
+ else
+ usb->free_transaction_head = transaction;
+ usb->free_transaction_tail = transaction;
}
/**
- * @INTERNAL
* Add a pipe to the tail of a list
- * @param list List to add pipe to
- * @param pipe Pipe to add
+ * @list: List to add pipe to
+ * @pipe: Pipe to add
*/
-static inline void __cvmx_usb_append_pipe(cvmx_usb_pipe_list_t *list, cvmx_usb_pipe_t *pipe)
+static inline void __cvmx_usb_append_pipe(struct cvmx_usb_pipe_list *list, struct cvmx_usb_pipe *pipe)
{
- pipe->next = NULL;
- pipe->prev = list->tail;
- if (list->tail)
- list->tail->next = pipe;
- else
- list->head = pipe;
- list->tail = pipe;
+ pipe->next = NULL;
+ pipe->prev = list->tail;
+ if (list->tail)
+ list->tail->next = pipe;
+ else
+ list->head = pipe;
+ list->tail = pipe;
}
/**
- * @INTERNAL
* Remove a pipe from a list
- * @param list List to remove pipe from
- * @param pipe Pipe to remove
+ * @list: List to remove pipe from
+ * @pipe: Pipe to remove
*/
-static inline void __cvmx_usb_remove_pipe(cvmx_usb_pipe_list_t *list, cvmx_usb_pipe_t *pipe)
+static inline void __cvmx_usb_remove_pipe(struct cvmx_usb_pipe_list *list, struct cvmx_usb_pipe *pipe)
{
- if (list->head == pipe) {
- list->head = pipe->next;
- pipe->next = NULL;
- if (list->head)
- list->head->prev = NULL;
- else
- list->tail = NULL;
- }
- else if (list->tail == pipe) {
- list->tail = pipe->prev;
- list->tail->next = NULL;
- pipe->prev = NULL;
- }
- else {
- pipe->prev->next = pipe->next;
- pipe->next->prev = pipe->prev;
- pipe->prev = NULL;
- pipe->next = NULL;
- }
+ if (list->head == pipe) {
+ list->head = pipe->next;
+ pipe->next = NULL;
+ if (list->head)
+ list->head->prev = NULL;
+ else
+ list->tail = NULL;
+ } else if (list->tail == pipe) {
+ list->tail = pipe->prev;
+ list->tail->next = NULL;
+ pipe->prev = NULL;
+ } else {
+ pipe->prev->next = pipe->next;
+ pipe->next->prev = pipe->prev;
+ pipe->prev = NULL;
+ pipe->next = NULL;
+ }
}
@@ -557,302 +546,332 @@ static inline void __cvmx_usb_remove_pipe(cvmx_usb_pipe_list_t *list, cvmx_usb_p
* other access to the Octeon USB port is made. The port starts
* off in the disabled state.
*
- * @param state Pointer to an empty cvmx_usb_state_t structure
- * that will be populated by the initialize call.
- * This structure is then passed to all other USB
- * functions.
- * @param usb_port_number
- * Which Octeon USB port to initialize.
- * @param flags Flags to control hardware initialization. See
- * cvmx_usb_initialize_flags_t for the flag
- * definitions. Some flags are mandatory.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
+ * @state: Pointer to an empty struct cvmx_usb_state
+ * that will be populated by the initialize call.
+ * This structure is then passed to all other USB
+ * functions.
+ * @usb_port_number:
+ * Which Octeon USB port to initialize.
+ * @flags: Flags to control hardware initialization. See
+ * enum cvmx_usb_initialize_flags for the flag
+ * definitions. Some flags are mandatory.
+ *
+ * Returns: 0 or a negative error code.
*/
-cvmx_usb_status_t cvmx_usb_initialize(cvmx_usb_state_t *state,
- int usb_port_number,
- cvmx_usb_initialize_flags_t flags)
+int cvmx_usb_initialize(struct cvmx_usb_state *state, int usb_port_number,
+ enum cvmx_usb_initialize_flags flags)
{
- cvmx_usbnx_clk_ctl_t usbn_clk_ctl;
- cvmx_usbnx_usbp_ctl_status_t usbn_usbp_ctl_status;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-
- usb->init_flags = flags;
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- CVMX_USB_LOG_PARAM("%d", usb_port_number);
- CVMX_USB_LOG_PARAM("0x%x", flags);
-
- /* Make sure that state is large enough to store the internal state */
- if (sizeof(*state) < sizeof(*usb))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- /* At first allow 0-1 for the usb port number */
- if ((usb_port_number < 0) || (usb_port_number > 1))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- /* For all chips except 52XX there is only one port */
- if (!OCTEON_IS_MODEL(OCTEON_CN52XX) && (usb_port_number > 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- /* Try to determine clock type automatically */
- if ((flags & (CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI |
- CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND)) == 0) {
- if (octeon_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12)
- flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI; /* Only 12 MHZ crystals are supported */
- else
- flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;
- }
-
- if (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
- /* Check for auto ref clock frequency */
- if (!(flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK))
- switch (octeon_usb_get_clock_type()) {
- case USB_CLOCK_TYPE_REF_12:
- flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ;
- break;
- case USB_CLOCK_TYPE_REF_24:
- flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ;
- break;
- case USB_CLOCK_TYPE_REF_48:
- flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
- break;
- default:
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- break;
- }
- }
-
- memset(usb, 0, sizeof(usb));
- usb->init_flags = flags;
-
- /* Initialize the USB state structure */
- {
- int i;
- usb->index = usb_port_number;
-
- /* Initialize the transaction double linked list */
- usb->free_transaction_head = NULL;
- usb->free_transaction_tail = NULL;
- for (i=0; i<MAX_TRANSACTIONS; i++)
- __cvmx_usb_free_transaction(usb, usb->transaction + i);
- for (i=0; i<MAX_PIPES; i++)
- __cvmx_usb_append_pipe(&usb->free_pipes, usb->pipe + i);
- }
-
- /* Power On Reset and PHY Initialization */
-
- /* 1. Wait for DCOK to assert (nothing to do) */
- /* 2a. Write USBN0/1_CLK_CTL[POR] = 1 and
- USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0 */
- usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
- usbn_clk_ctl.s.por = 1;
- usbn_clk_ctl.s.hrst = 0;
- usbn_clk_ctl.s.prst = 0;
- usbn_clk_ctl.s.hclk_rst = 0;
- usbn_clk_ctl.s.enable = 0;
- /* 2b. Select the USB reference clock/crystal parameters by writing
- appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON] */
- if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
- /* The USB port uses 12/24/48MHz 2.5V board clock
- source at USB_XO. USB_XI should be tied to GND.
- Most Octeon evaluation boards require this setting */
- if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
- usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */
- usbn_clk_ctl.cn31xx.p_xenbn = 0;
- }
- else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
- usbn_clk_ctl.cn56xx.p_rtype = 2; /* From CN56XX,CN50XX manual */
- else
- usbn_clk_ctl.cn52xx.p_rtype = 1; /* From CN52XX manual */
-
- switch (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) {
- case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:
- usbn_clk_ctl.s.p_c_sel = 0;
- break;
- case CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ:
- usbn_clk_ctl.s.p_c_sel = 1;
- break;
- case CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ:
- usbn_clk_ctl.s.p_c_sel = 2;
- break;
- }
- }
- else {
- /* The USB port uses a 12MHz crystal as clock source
- at USB_XO and USB_XI */
- if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
- usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */
- usbn_clk_ctl.cn31xx.p_xenbn = 1;
- }
- else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
- usbn_clk_ctl.cn56xx.p_rtype = 0; /* From CN56XX,CN50XX manual */
- else
- usbn_clk_ctl.cn52xx.p_rtype = 0; /* From CN52XX manual */
-
- usbn_clk_ctl.s.p_c_sel = 0;
- }
- /* 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and
- setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down such
- that USB is as close as possible to 125Mhz */
- {
- int divisor = (octeon_get_clock_rate()+125000000-1)/125000000;
- if (divisor < 4) /* Lower than 4 doesn't seem to work properly */
- divisor = 4;
- usbn_clk_ctl.s.divide = divisor;
- usbn_clk_ctl.s.divide2 = 0;
- }
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
- usbn_clk_ctl.u64);
- /* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */
- usbn_clk_ctl.s.hclk_rst = 1;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
- usbn_clk_ctl.u64);
- /* 2e. Wait 64 core-clock cycles for HCLK to stabilize */
- cvmx_wait(64);
- /* 3. Program the power-on reset field in the USBN clock-control register:
- USBN_CLK_CTL[POR] = 0 */
- usbn_clk_ctl.s.por = 0;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
- usbn_clk_ctl.u64);
- /* 4. Wait 1 ms for PHY clock to start */
- cvmx_wait_usec(1000);
- /* 5. Program the Reset input from automatic test equipment field in the
- USBP control and status register: USBN_USBP_CTL_STATUS[ATE_RESET] = 1 */
- usbn_usbp_ctl_status.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index));
- usbn_usbp_ctl_status.s.ate_reset = 1;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
- usbn_usbp_ctl_status.u64);
- /* 6. Wait 10 cycles */
- cvmx_wait(10);
- /* 7. Clear ATE_RESET field in the USBN clock-control register:
- USBN_USBP_CTL_STATUS[ATE_RESET] = 0 */
- usbn_usbp_ctl_status.s.ate_reset = 0;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
- usbn_usbp_ctl_status.u64);
- /* 8. Program the PHY reset field in the USBN clock-control register:
- USBN_CLK_CTL[PRST] = 1 */
- usbn_clk_ctl.s.prst = 1;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
- usbn_clk_ctl.u64);
- /* 9. Program the USBP control and status register to select host or
- device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for
- device */
- usbn_usbp_ctl_status.s.hst_mode = 0;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
- usbn_usbp_ctl_status.u64);
- /* 10. Wait 1 us */
- cvmx_wait_usec(1);
- /* 11. Program the hreset_n field in the USBN clock-control register:
- USBN_CLK_CTL[HRST] = 1 */
- usbn_clk_ctl.s.hrst = 1;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
- usbn_clk_ctl.u64);
- /* 12. Proceed to USB core initialization */
- usbn_clk_ctl.s.enable = 1;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
- usbn_clk_ctl.u64);
- cvmx_wait_usec(1);
-
- /* USB Core Initialization */
-
- /* 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to
- determine USB core configuration parameters. */
- /* Nothing needed */
- /* 2. Program the following fields in the global AHB configuration
- register (USBC_GAHBCFG)
- DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode
- Burst length, USBC_GAHBCFG[HBSTLEN] = 0
- Nonperiodic TxFIFO empty level (slave mode only),
- USBC_GAHBCFG[NPTXFEMPLVL]
- Periodic TxFIFO empty level (slave mode only),
- USBC_GAHBCFG[PTXFEMPLVL]
- Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1 */
- {
- cvmx_usbcx_gahbcfg_t usbcx_gahbcfg;
- /* Due to an errata, CN31XX doesn't support DMA */
- if (OCTEON_IS_MODEL(OCTEON_CN31XX))
- usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA;
- usbcx_gahbcfg.u32 = 0;
- usbcx_gahbcfg.s.dmaen = !(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA);
- if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
- usb->idle_hardware_channels = 0x1; /* Only use one channel with non DMA */
- else if (OCTEON_IS_MODEL(OCTEON_CN5XXX))
- usb->idle_hardware_channels = 0xf7; /* CN5XXX have an errata with channel 3 */
- else
- usb->idle_hardware_channels = 0xff;
- usbcx_gahbcfg.s.hbstlen = 0;
- usbcx_gahbcfg.s.nptxfemplvl = 1;
- usbcx_gahbcfg.s.ptxfemplvl = 1;
- usbcx_gahbcfg.s.glblintrmsk = 1;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index),
- usbcx_gahbcfg.u32);
- }
- /* 3. Program the following fields in USBC_GUSBCFG register.
- HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0
- ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0
- USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5
- PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0 */
- {
- cvmx_usbcx_gusbcfg_t usbcx_gusbcfg;
- usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index));
- usbcx_gusbcfg.s.toutcal = 0;
- usbcx_gusbcfg.s.ddrsel = 0;
- usbcx_gusbcfg.s.usbtrdtim = 0x5;
- usbcx_gusbcfg.s.phylpwrclksel = 0;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index),
- usbcx_gusbcfg.u32);
- }
- /* 4. The software must unmask the following bits in the USBC_GINTMSK
- register.
- OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1
- Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1 */
- {
- cvmx_usbcx_gintmsk_t usbcx_gintmsk;
- int channel;
-
- usbcx_gintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index));
- usbcx_gintmsk.s.otgintmsk = 1;
- usbcx_gintmsk.s.modemismsk = 1;
- usbcx_gintmsk.s.hchintmsk = 1;
- usbcx_gintmsk.s.sofmsk = 0;
- /* We need RX FIFO interrupts if we don't have DMA */
- if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
- usbcx_gintmsk.s.rxflvlmsk = 1;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index),
- usbcx_gintmsk.u32);
-
- /* Disable all channel interrupts. We'll enable them per channel later */
- for (channel=0; channel<8; channel++)
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
- }
-
- {
- /* Host Port Initialization */
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
- cvmx_dprintf("%s: USB%d is in host mode\n", __FUNCTION__, usb->index);
-
- /* 1. Program the host-port interrupt-mask field to unmask,
- USBC_GINTMSK[PRTINT] = 1 */
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t,
- prtintmsk, 1);
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t,
- disconnintmsk, 1);
- /* 2. Program the USBC_HCFG register to select full-speed host or
- high-speed host. */
- {
- cvmx_usbcx_hcfg_t usbcx_hcfg;
- usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index));
- usbcx_hcfg.s.fslssupp = 0;
- usbcx_hcfg.s.fslspclksel = 0;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32);
- }
- /* 3. Program the port power bit to drive VBUS on the USB,
- USBC_HPRT[PRTPWR] = 1 */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtpwr, 1);
-
- /* Steps 4-15 from the manual are done later in the port enable */
- }
-
- CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+ union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+ union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+
+ usb->init_flags = flags;
+
+ /* Make sure that state is large enough to store the internal state */
+ if (sizeof(*state) < sizeof(*usb))
+ return -EINVAL;
+ /* At first allow 0-1 for the usb port number */
+ if ((usb_port_number < 0) || (usb_port_number > 1))
+ return -EINVAL;
+ /* For all chips except 52XX there is only one port */
+ if (!OCTEON_IS_MODEL(OCTEON_CN52XX) && (usb_port_number > 0))
+ return -EINVAL;
+ /* Try to determine clock type automatically */
+ if ((flags & (CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI |
+ CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND)) == 0) {
+ if (octeon_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12)
+ flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI; /* Only 12 MHZ crystals are supported */
+ else
+ flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;
+ }
+
+ if (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
+ /* Check for auto ref clock frequency */
+ if (!(flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK))
+ switch (octeon_usb_get_clock_type()) {
+ case USB_CLOCK_TYPE_REF_12:
+ flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ;
+ break;
+ case USB_CLOCK_TYPE_REF_24:
+ flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ;
+ break;
+ case USB_CLOCK_TYPE_REF_48:
+ flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ }
+
+ memset(usb, 0, sizeof(usb));
+ usb->init_flags = flags;
+
+ /* Initialize the USB state structure */
+ {
+ int i;
+ usb->index = usb_port_number;
+
+ /* Initialize the transaction double linked list */
+ usb->free_transaction_head = NULL;
+ usb->free_transaction_tail = NULL;
+ for (i = 0; i < MAX_TRANSACTIONS; i++)
+ __cvmx_usb_free_transaction(usb, usb->transaction + i);
+ for (i = 0; i < MAX_PIPES; i++)
+ __cvmx_usb_append_pipe(&usb->free_pipes, usb->pipe + i);
+ }
+
+ /*
+ * Power On Reset and PHY Initialization
+ *
+ * 1. Wait for DCOK to assert (nothing to do)
+ *
+ * 2a. Write USBN0/1_CLK_CTL[POR] = 1 and
+ * USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0
+ */
+ usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
+ usbn_clk_ctl.s.por = 1;
+ usbn_clk_ctl.s.hrst = 0;
+ usbn_clk_ctl.s.prst = 0;
+ usbn_clk_ctl.s.hclk_rst = 0;
+ usbn_clk_ctl.s.enable = 0;
+ /*
+ * 2b. Select the USB reference clock/crystal parameters by writing
+ * appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON]
+ */
+ if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
+ /*
+ * The USB port uses 12/24/48MHz 2.5V board clock
+ * source at USB_XO. USB_XI should be tied to GND.
+ * Most Octeon evaluation boards require this setting
+ */
+ if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
+ usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */
+ usbn_clk_ctl.cn31xx.p_xenbn = 0;
+ } else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
+ usbn_clk_ctl.cn56xx.p_rtype = 2; /* From CN56XX,CN50XX manual */
+ else
+ usbn_clk_ctl.cn52xx.p_rtype = 1; /* From CN52XX manual */
+
+ switch (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) {
+ case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:
+ usbn_clk_ctl.s.p_c_sel = 0;
+ break;
+ case CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ:
+ usbn_clk_ctl.s.p_c_sel = 1;
+ break;
+ case CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ:
+ usbn_clk_ctl.s.p_c_sel = 2;
+ break;
+ }
+ } else {
+ /*
+ * The USB port uses a 12MHz crystal as clock source
+ * at USB_XO and USB_XI
+ */
+ if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
+ usbn_clk_ctl.cn31xx.p_rclk = 1; /* From CN31XX,CN30XX manual */
+ usbn_clk_ctl.cn31xx.p_xenbn = 1;
+ } else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
+ usbn_clk_ctl.cn56xx.p_rtype = 0; /* From CN56XX,CN50XX manual */
+ else
+ usbn_clk_ctl.cn52xx.p_rtype = 0; /* From CN52XX manual */
+
+ usbn_clk_ctl.s.p_c_sel = 0;
+ }
+ /*
+ * 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and
+ * setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down
+ * such that USB is as close as possible to 125Mhz
+ */
+ {
+ int divisor = (octeon_get_clock_rate()+125000000-1)/125000000;
+ if (divisor < 4) /* Lower than 4 doesn't seem to work properly */
+ divisor = 4;
+ usbn_clk_ctl.s.divide = divisor;
+ usbn_clk_ctl.s.divide2 = 0;
+ }
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+ usbn_clk_ctl.u64);
+ /* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */
+ usbn_clk_ctl.s.hclk_rst = 1;
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+ usbn_clk_ctl.u64);
+ /* 2e. Wait 64 core-clock cycles for HCLK to stabilize */
+ cvmx_wait(64);
+ /*
+ * 3. Program the power-on reset field in the USBN clock-control
+ * register:
+ * USBN_CLK_CTL[POR] = 0
+ */
+ usbn_clk_ctl.s.por = 0;
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+ usbn_clk_ctl.u64);
+ /* 4. Wait 1 ms for PHY clock to start */
+ mdelay(1);
+ /*
+ * 5. Program the Reset input from automatic test equipment field in the
+ * USBP control and status register:
+ * USBN_USBP_CTL_STATUS[ATE_RESET] = 1
+ */
+ usbn_usbp_ctl_status.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index));
+ usbn_usbp_ctl_status.s.ate_reset = 1;
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
+ usbn_usbp_ctl_status.u64);
+ /* 6. Wait 10 cycles */
+ cvmx_wait(10);
+ /*
+ * 7. Clear ATE_RESET field in the USBN clock-control register:
+ * USBN_USBP_CTL_STATUS[ATE_RESET] = 0
+ */
+ usbn_usbp_ctl_status.s.ate_reset = 0;
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
+ usbn_usbp_ctl_status.u64);
+ /*
+ * 8. Program the PHY reset field in the USBN clock-control register:
+ * USBN_CLK_CTL[PRST] = 1
+ */
+ usbn_clk_ctl.s.prst = 1;
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+ usbn_clk_ctl.u64);
+ /*
+ * 9. Program the USBP control and status register to select host or
+ * device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for
+ * device
+ */
+ usbn_usbp_ctl_status.s.hst_mode = 0;
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
+ usbn_usbp_ctl_status.u64);
+ /* 10. Wait 1 us */
+ udelay(1);
+ /*
+ * 11. Program the hreset_n field in the USBN clock-control register:
+ * USBN_CLK_CTL[HRST] = 1
+ */
+ usbn_clk_ctl.s.hrst = 1;
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+ usbn_clk_ctl.u64);
+ /* 12. Proceed to USB core initialization */
+ usbn_clk_ctl.s.enable = 1;
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+ usbn_clk_ctl.u64);
+ udelay(1);
+
+ /*
+ * USB Core Initialization
+ *
+ * 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to
+ * determine USB core configuration parameters.
+ *
+ * Nothing needed
+ *
+ * 2. Program the following fields in the global AHB configuration
+ * register (USBC_GAHBCFG)
+ * DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode
+ * Burst length, USBC_GAHBCFG[HBSTLEN] = 0
+ * Nonperiodic TxFIFO empty level (slave mode only),
+ * USBC_GAHBCFG[NPTXFEMPLVL]
+ * Periodic TxFIFO empty level (slave mode only),
+ * USBC_GAHBCFG[PTXFEMPLVL]
+ * Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1
+ */
+ {
+ union cvmx_usbcx_gahbcfg usbcx_gahbcfg;
+ /* Due to an errata, CN31XX doesn't support DMA */
+ if (OCTEON_IS_MODEL(OCTEON_CN31XX))
+ usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA;
+ usbcx_gahbcfg.u32 = 0;
+ usbcx_gahbcfg.s.dmaen = !(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA);
+ if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+ usb->idle_hardware_channels = 0x1; /* Only use one channel with non DMA */
+ else if (OCTEON_IS_MODEL(OCTEON_CN5XXX))
+ usb->idle_hardware_channels = 0xf7; /* CN5XXX have an errata with channel 3 */
+ else
+ usb->idle_hardware_channels = 0xff;
+ usbcx_gahbcfg.s.hbstlen = 0;
+ usbcx_gahbcfg.s.nptxfemplvl = 1;
+ usbcx_gahbcfg.s.ptxfemplvl = 1;
+ usbcx_gahbcfg.s.glblintrmsk = 1;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index),
+ usbcx_gahbcfg.u32);
+ }
+ /*
+ * 3. Program the following fields in USBC_GUSBCFG register.
+ * HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0
+ * ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0
+ * USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5
+ * PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0
+ */
+ {
+ union cvmx_usbcx_gusbcfg usbcx_gusbcfg;
+ usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index));
+ usbcx_gusbcfg.s.toutcal = 0;
+ usbcx_gusbcfg.s.ddrsel = 0;
+ usbcx_gusbcfg.s.usbtrdtim = 0x5;
+ usbcx_gusbcfg.s.phylpwrclksel = 0;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index),
+ usbcx_gusbcfg.u32);
+ }
+ /*
+ * 4. The software must unmask the following bits in the USBC_GINTMSK
+ * register.
+ * OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1
+ * Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1
+ */
+ {
+ union cvmx_usbcx_gintmsk usbcx_gintmsk;
+ int channel;
+
+ usbcx_gintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index));
+ usbcx_gintmsk.s.otgintmsk = 1;
+ usbcx_gintmsk.s.modemismsk = 1;
+ usbcx_gintmsk.s.hchintmsk = 1;
+ usbcx_gintmsk.s.sofmsk = 0;
+ /* We need RX FIFO interrupts if we don't have DMA */
+ if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+ usbcx_gintmsk.s.rxflvlmsk = 1;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index),
+ usbcx_gintmsk.u32);
+
+ /* Disable all channel interrupts. We'll enable them per channel later */
+ for (channel = 0; channel < 8; channel++)
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
+ }
+
+ {
+ /*
+ * Host Port Initialization
+ *
+ * 1. Program the host-port interrupt-mask field to unmask,
+ * USBC_GINTMSK[PRTINT] = 1
+ */
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk,
+ prtintmsk, 1);
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk,
+ disconnintmsk, 1);
+ /*
+ * 2. Program the USBC_HCFG register to select full-speed host
+ * or high-speed host.
+ */
+ {
+ union cvmx_usbcx_hcfg usbcx_hcfg;
+ usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index));
+ usbcx_hcfg.s.fslssupp = 0;
+ usbcx_hcfg.s.fslspclksel = 0;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32);
+ }
+ /*
+ * 3. Program the port power bit to drive VBUS on the USB,
+ * USBC_HPRT[PRTPWR] = 1
+ */
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtpwr, 1);
+
+ /*
+ * Steps 4-15 from the manual are done later in the port enable
+ */
+ }
+
+ return 0;
}
@@ -861,38 +880,34 @@ cvmx_usb_status_t cvmx_usb_initialize(cvmx_usb_state_t *state,
* The port should be disabled with all pipes closed when this
* function is called.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
*
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
*/
-cvmx_usb_status_t cvmx_usb_shutdown(cvmx_usb_state_t *state)
+int cvmx_usb_shutdown(struct cvmx_usb_state *state)
{
- cvmx_usbnx_clk_ctl_t usbn_clk_ctl;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
-
- /* Make sure all pipes are closed */
- if (usb->idle_pipes.head ||
- usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS].head ||
- usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT].head ||
- usb->active_pipes[CVMX_USB_TRANSFER_CONTROL].head ||
- usb->active_pipes[CVMX_USB_TRANSFER_BULK].head)
- CVMX_USB_RETURN(CVMX_USB_BUSY);
-
- /* Disable the clocks and put them in power on reset */
- usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
- usbn_clk_ctl.s.enable = 1;
- usbn_clk_ctl.s.por = 1;
- usbn_clk_ctl.s.hclk_rst = 1;
- usbn_clk_ctl.s.prst = 0;
- usbn_clk_ctl.s.hrst = 0;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
- usbn_clk_ctl.u64);
- CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+ union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+
+ /* Make sure all pipes are closed */
+ if (usb->idle_pipes.head ||
+ usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS].head ||
+ usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT].head ||
+ usb->active_pipes[CVMX_USB_TRANSFER_CONTROL].head ||
+ usb->active_pipes[CVMX_USB_TRANSFER_BULK].head)
+ return -EBUSY;
+
+ /* Disable the clocks and put them in power on reset */
+ usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
+ usbn_clk_ctl.s.enable = 1;
+ usbn_clk_ctl.s.por = 1;
+ usbn_clk_ctl.s.hclk_rst = 1;
+ usbn_clk_ctl.s.prst = 0;
+ usbn_clk_ctl.s.hrst = 0;
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+ usbn_clk_ctl.u64);
+ return 0;
}
@@ -900,96 +915,91 @@ cvmx_usb_status_t cvmx_usb_shutdown(cvmx_usb_state_t *state)
* Enable a USB port. After this call succeeds, the USB port is
* online and servicing requests.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
*
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
*/
-cvmx_usb_status_t cvmx_usb_enable(cvmx_usb_state_t *state)
+int cvmx_usb_enable(struct cvmx_usb_state *state)
{
- cvmx_usbcx_ghwcfg3_t usbcx_ghwcfg3;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
-
- usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
-
- /* If the port is already enabled the just return. We don't need to do
- anything */
- if (usb->usbcx_hprt.s.prtena)
- CVMX_USB_RETURN(CVMX_USB_SUCCESS);
-
- /* If there is nothing plugged into the port then fail immediately */
- if (!usb->usbcx_hprt.s.prtconnsts) {
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
- cvmx_dprintf("%s: USB%d Nothing plugged into the port\n", __FUNCTION__, usb->index);
- CVMX_USB_RETURN(CVMX_USB_TIMEOUT);
- }
-
- /* Program the port reset bit to start the reset process */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtrst, 1);
-
- /* Wait at least 50ms (high speed), or 10ms (full speed) for the reset
- process to complete. */
- cvmx_wait_usec(50000);
-
- /* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtrst, 0);
-
- /* Wait for the USBC_HPRT[PRTENA]. */
- if (CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t,
- prtena, ==, 1, 100000)) {
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
- cvmx_dprintf("%s: Timeout waiting for the port to finish reset\n",
- __FUNCTION__);
- CVMX_USB_RETURN(CVMX_USB_TIMEOUT);
- }
-
- /* Read the port speed field to get the enumerated speed, USBC_HPRT[PRTSPD]. */
- usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
- cvmx_dprintf("%s: USB%d is in %s speed mode\n", __FUNCTION__, usb->index,
- (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH) ? "high" :
- (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_FULL) ? "full" :
- "low");
-
- usbcx_ghwcfg3.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index));
-
- /* 13. Program the USBC_GRXFSIZ register to select the size of the receive
- FIFO (25%). */
- USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), cvmx_usbcx_grxfsiz_t,
- rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4);
- /* 14. Program the USBC_GNPTXFSIZ register to select the size and the
- start address of the non- periodic transmit FIFO for nonperiodic
- transactions (50%). */
- {
- cvmx_usbcx_gnptxfsiz_t siz;
- siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index));
- siz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2;
- siz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), siz.u32);
- }
- /* 15. Program the USBC_HPTXFSIZ register to select the size and start
- address of the periodic transmit FIFO for periodic transactions (25%). */
- {
- cvmx_usbcx_hptxfsiz_t siz;
- siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index));
- siz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4;
- siz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), siz.u32);
- }
- /* Flush all FIFOs */
- USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), cvmx_usbcx_grstctl_t, txfnum, 0x10);
- USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), cvmx_usbcx_grstctl_t, txfflsh, 1);
- CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), cvmx_usbcx_grstctl_t,
- txfflsh, ==, 0, 100);
- USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), cvmx_usbcx_grstctl_t, rxfflsh, 1);
- CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), cvmx_usbcx_grstctl_t,
- rxfflsh, ==, 0, 100);
-
- CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+ union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+
+ usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+
+ /*
+ * If the port is already enabled the just return. We don't need to do
+ * anything
+ */
+ if (usb->usbcx_hprt.s.prtena)
+ return 0;
+
+ /* If there is nothing plugged into the port then fail immediately */
+ if (!usb->usbcx_hprt.s.prtconnsts) {
+ return -ETIMEDOUT;
+ }
+
+ /* Program the port reset bit to start the reset process */
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtrst, 1);
+
+ /*
+ * Wait at least 50ms (high speed), or 10ms (full speed) for the reset
+ * process to complete.
+ */
+ mdelay(50);
+
+ /* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtrst, 0);
+
+ /* Wait for the USBC_HPRT[PRTENA]. */
+ if (CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt,
+ prtena, ==, 1, 100000))
+ return -ETIMEDOUT;
+
+ /* Read the port speed field to get the enumerated speed, USBC_HPRT[PRTSPD]. */
+ usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+ usbcx_ghwcfg3.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index));
+
+ /*
+ * 13. Program the USBC_GRXFSIZ register to select the size of the
+ * receive FIFO (25%).
+ */
+ USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), union cvmx_usbcx_grxfsiz,
+ rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4);
+ /*
+ * 14. Program the USBC_GNPTXFSIZ register to select the size and the
+ * start address of the non- periodic transmit FIFO for nonperiodic
+ * transactions (50%).
+ */
+ {
+ union cvmx_usbcx_gnptxfsiz siz;
+ siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index));
+ siz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2;
+ siz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), siz.u32);
+ }
+ /*
+ * 15. Program the USBC_HPTXFSIZ register to select the size and start
+ * address of the periodic transmit FIFO for periodic transactions
+ * (25%).
+ */
+ {
+ union cvmx_usbcx_hptxfsiz siz;
+ siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index));
+ siz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4;
+ siz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), siz.u32);
+ }
+ /* Flush all FIFOs */
+ USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, txfnum, 0x10);
+ USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, txfflsh, 1);
+ CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl,
+ txfflsh, ==, 0, 100);
+ USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, rxfflsh, 1);
+ CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl,
+ rxfflsh, ==, 0, 100);
+
+ return 0;
}
@@ -999,22 +1009,18 @@ cvmx_usb_status_t cvmx_usb_enable(cvmx_usb_state_t *state)
* Transactions in process will fail and call their
* associated callbacks.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
*
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
*/
-cvmx_usb_status_t cvmx_usb_disable(cvmx_usb_state_t *state)
+int cvmx_usb_disable(struct cvmx_usb_state *state)
{
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
-
- /* Disable the port */
- USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtena, 1);
- CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+ /* Disable the port */
+ USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtena, 1);
+ return 0;
}
@@ -1027,40 +1033,28 @@ cvmx_usb_status_t cvmx_usb_disable(cvmx_usb_state_t *state)
* on the last call to cvmx_usb_set_status(). In order to clear
* them, you must update the status through cvmx_usb_set_status().
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
*
- * @return Port status information
+ * Returns: Port status information
*/
-cvmx_usb_port_status_t cvmx_usb_get_status(cvmx_usb_state_t *state)
+struct cvmx_usb_port_status cvmx_usb_get_status(struct cvmx_usb_state *state)
{
- cvmx_usbcx_hprt_t usbc_hprt;
- cvmx_usb_port_status_t result;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-
- memset(&result, 0, sizeof(result));
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
-
- usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
- result.port_enabled = usbc_hprt.s.prtena;
- result.port_over_current = usbc_hprt.s.prtovrcurract;
- result.port_powered = usbc_hprt.s.prtpwr;
- result.port_speed = usbc_hprt.s.prtspd;
- result.connected = usbc_hprt.s.prtconnsts;
- result.connect_change = (result.connected != usb->port_status.connected);
-
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS))
- cvmx_dprintf("%*s%s: returned port enabled=%d, over_current=%d, powered=%d, speed=%d, connected=%d, connect_change=%d\n",
- 2*(--usb->indent), "", __FUNCTION__,
- result.port_enabled,
- result.port_over_current,
- result.port_powered,
- result.port_speed,
- result.connected,
- result.connect_change);
- return result;
+ union cvmx_usbcx_hprt usbc_hprt;
+ struct cvmx_usb_port_status result;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+
+ memset(&result, 0, sizeof(result));
+
+ usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+ result.port_enabled = usbc_hprt.s.prtena;
+ result.port_over_current = usbc_hprt.s.prtovrcurract;
+ result.port_powered = usbc_hprt.s.prtpwr;
+ result.port_speed = usbc_hprt.s.prtspd;
+ result.connected = usbc_hprt.s.prtconnsts;
+ result.connect_change = (result.connected != usb->port_status.connected);
+
+ return result;
}
@@ -1071,54 +1065,50 @@ cvmx_usb_port_status_t cvmx_usb_get_status(cvmx_usb_state_t *state)
* status passed to this function is not used. No fields can be
* changed through this call.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param port_status
- * Port status to set, most like returned by cvmx_usb_get_status()
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
+ * @port_status:
+ * Port status to set, most like returned by cvmx_usb_get_status()
*/
-void cvmx_usb_set_status(cvmx_usb_state_t *state, cvmx_usb_port_status_t port_status)
+void cvmx_usb_set_status(struct cvmx_usb_state *state, struct cvmx_usb_port_status port_status)
{
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- usb->port_status = port_status;
- CVMX_USB_RETURN_NOTHING();
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+ usb->port_status = port_status;
+ return;
}
/**
- * @INTERNAL
* Convert a USB transaction into a handle
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param transaction
- * Transaction to get handle for
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @transaction:
+ * Transaction to get handle for
*
- * @return Handle
+ * Returns: Handle
*/
-static inline int __cvmx_usb_get_submit_handle(cvmx_usb_internal_state_t *usb,
- cvmx_usb_transaction_t *transaction)
+static inline int __cvmx_usb_get_submit_handle(struct cvmx_usb_internal_state *usb,
+ struct cvmx_usb_transaction *transaction)
{
- return ((unsigned long)transaction - (unsigned long)usb->transaction) /
- sizeof(*transaction);
+ return ((unsigned long)transaction - (unsigned long)usb->transaction) /
+ sizeof(*transaction);
}
/**
- * @INTERNAL
* Convert a USB pipe into a handle
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe Pipe to get handle for
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @pipe: Pipe to get handle for
*
- * @return Handle
+ * Returns: Handle
*/
-static inline int __cvmx_usb_get_pipe_handle(cvmx_usb_internal_state_t *usb,
- cvmx_usb_pipe_t *pipe)
+static inline int __cvmx_usb_get_pipe_handle(struct cvmx_usb_internal_state *usb,
+ struct cvmx_usb_pipe *pipe)
{
- return ((unsigned long)pipe - (unsigned long)usb->pipe) / sizeof(*pipe);
+ return ((unsigned long)pipe - (unsigned long)usb->pipe) / sizeof(*pipe);
}
@@ -1127,197 +1117,182 @@ static inline int __cvmx_usb_get_pipe_handle(cvmx_usb_internal_state_t *usb,
* must be opened before data can be transferred between a device
* and Octeon.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param flags Optional pipe flags defined in
- * cvmx_usb_pipe_flags_t.
- * @param device_addr
- * USB device address to open the pipe to
- * (0-127).
- * @param endpoint_num
- * USB endpoint number to open the pipe to
- * (0-15).
- * @param device_speed
- * The speed of the device the pipe is going
- * to. This must match the device's speed,
- * which may be different than the port speed.
- * @param max_packet The maximum packet length the device can
- * transmit/receive (low speed=0-8, full
- * speed=0-1023, high speed=0-1024). This value
- * comes from the standard endpoint descriptor
- * field wMaxPacketSize bits <10:0>.
- * @param transfer_type
- * The type of transfer this pipe is for.
- * @param transfer_dir
- * The direction the pipe is in. This is not
- * used for control pipes.
- * @param interval For ISOCHRONOUS and INTERRUPT transfers,
- * this is how often the transfer is scheduled
- * for. All other transfers should specify
- * zero. The units are in frames (8000/sec at
- * high speed, 1000/sec for full speed).
- * @param multi_count
- * For high speed devices, this is the maximum
- * allowed number of packet per microframe.
- * Specify zero for non high speed devices. This
- * value comes from the standard endpoint descriptor
- * field wMaxPacketSize bits <12:11>.
- * @param hub_device_addr
- * Hub device address this device is connected
- * to. Devices connected directly to Octeon
- * use zero. This is only used when the device
- * is full/low speed behind a high speed hub.
- * The address will be of the high speed hub,
- * not and full speed hubs after it.
- * @param hub_port Which port on the hub the device is
- * connected. Use zero for devices connected
- * directly to Octeon. Like hub_device_addr,
- * this is only used for full/low speed
- * devices behind a high speed hub.
- *
- * @return A non negative value is a pipe handle. Negative
- * values are failure codes from cvmx_usb_status_t.
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
+ * @flags: Optional pipe flags defined in
+ * enum cvmx_usb_pipe_flags.
+ * @device_addr:
+ * USB device address to open the pipe to
+ * (0-127).
+ * @endpoint_num:
+ * USB endpoint number to open the pipe to
+ * (0-15).
+ * @device_speed:
+ * The speed of the device the pipe is going
+ * to. This must match the device's speed,
+ * which may be different than the port speed.
+ * @max_packet: The maximum packet length the device can
+ * transmit/receive (low speed=0-8, full
+ * speed=0-1023, high speed=0-1024). This value
+ * comes from the standard endpoint descriptor
+ * field wMaxPacketSize bits <10:0>.
+ * @transfer_type:
+ * The type of transfer this pipe is for.
+ * @transfer_dir:
+ * The direction the pipe is in. This is not
+ * used for control pipes.
+ * @interval: For ISOCHRONOUS and INTERRUPT transfers,
+ * this is how often the transfer is scheduled
+ * for. All other transfers should specify
+ * zero. The units are in frames (8000/sec at
+ * high speed, 1000/sec for full speed).
+ * @multi_count:
+ * For high speed devices, this is the maximum
+ * allowed number of packet per microframe.
+ * Specify zero for non high speed devices. This
+ * value comes from the standard endpoint descriptor
+ * field wMaxPacketSize bits <12:11>.
+ * @hub_device_addr:
+ * Hub device address this device is connected
+ * to. Devices connected directly to Octeon
+ * use zero. This is only used when the device
+ * is full/low speed behind a high speed hub.
+ * The address will be of the high speed hub,
+ * not and full speed hubs after it.
+ * @hub_port: Which port on the hub the device is
+ * connected. Use zero for devices connected
+ * directly to Octeon. Like hub_device_addr,
+ * this is only used for full/low speed
+ * devices behind a high speed hub.
+ *
+ * Returns: A non negative value is a pipe handle. Negative
+ * values are error codes.
*/
-int cvmx_usb_open_pipe(cvmx_usb_state_t *state, cvmx_usb_pipe_flags_t flags,
- int device_addr, int endpoint_num,
- cvmx_usb_speed_t device_speed, int max_packet,
- cvmx_usb_transfer_t transfer_type,
- cvmx_usb_direction_t transfer_dir, int interval,
- int multi_count, int hub_device_addr, int hub_port)
+int cvmx_usb_open_pipe(struct cvmx_usb_state *state, enum cvmx_usb_pipe_flags flags,
+ int device_addr, int endpoint_num,
+ enum cvmx_usb_speed device_speed, int max_packet,
+ enum cvmx_usb_transfer transfer_type,
+ enum cvmx_usb_direction transfer_dir, int interval,
+ int multi_count, int hub_device_addr, int hub_port)
{
- cvmx_usb_pipe_t *pipe;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- CVMX_USB_LOG_PARAM("0x%x", flags);
- CVMX_USB_LOG_PARAM("%d", device_addr);
- CVMX_USB_LOG_PARAM("%d", endpoint_num);
- CVMX_USB_LOG_PARAM("%d", device_speed);
- CVMX_USB_LOG_PARAM("%d", max_packet);
- CVMX_USB_LOG_PARAM("%d", transfer_type);
- CVMX_USB_LOG_PARAM("%d", transfer_dir);
- CVMX_USB_LOG_PARAM("%d", interval);
- CVMX_USB_LOG_PARAM("%d", multi_count);
- CVMX_USB_LOG_PARAM("%d", hub_device_addr);
- CVMX_USB_LOG_PARAM("%d", hub_port);
-
- if (cvmx_unlikely((device_addr < 0) || (device_addr > MAX_USB_ADDRESS)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely((endpoint_num < 0) || (endpoint_num > MAX_USB_ENDPOINT)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(device_speed > CVMX_USB_SPEED_LOW))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely((max_packet <= 0) || (max_packet > 1024)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(transfer_type > CVMX_USB_TRANSFER_INTERRUPT))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely((transfer_dir != CVMX_USB_DIRECTION_OUT) &&
- (transfer_dir != CVMX_USB_DIRECTION_IN)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(interval < 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely((transfer_type == CVMX_USB_TRANSFER_CONTROL) && interval))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(multi_count < 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely((device_speed != CVMX_USB_SPEED_HIGH) &&
- (multi_count != 0)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely((hub_device_addr < 0) || (hub_device_addr > MAX_USB_ADDRESS)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely((hub_port < 0) || (hub_port > MAX_USB_HUB_PORT)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- /* Find a free pipe */
- pipe = usb->free_pipes.head;
- if (!pipe)
- CVMX_USB_RETURN(CVMX_USB_NO_MEMORY);
- __cvmx_usb_remove_pipe(&usb->free_pipes, pipe);
- pipe->flags = flags | __CVMX_USB_PIPE_FLAGS_OPEN;
- if ((device_speed == CVMX_USB_SPEED_HIGH) &&
- (transfer_dir == CVMX_USB_DIRECTION_OUT) &&
- (transfer_type == CVMX_USB_TRANSFER_BULK))
- pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
- pipe->device_addr = device_addr;
- pipe->endpoint_num = endpoint_num;
- pipe->device_speed = device_speed;
- pipe->max_packet = max_packet;
- pipe->transfer_type = transfer_type;
- pipe->transfer_dir = transfer_dir;
- /* All pipes use interval to rate limit NAK processing. Force an interval
- if one wasn't supplied */
- if (!interval)
- interval = 1;
- if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
- pipe->interval = interval*8;
- /* Force start splits to be schedule on uFrame 0 */
- pipe->next_tx_frame = ((usb->frame_number+7)&~7) + pipe->interval;
- }
- else {
- pipe->interval = interval;
- pipe->next_tx_frame = usb->frame_number + pipe->interval;
- }
- pipe->multi_count = multi_count;
- pipe->hub_device_addr = hub_device_addr;
- pipe->hub_port = hub_port;
- pipe->pid_toggle = 0;
- pipe->split_sc_frame = -1;
- __cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
-
- /* We don't need to tell the hardware about this pipe yet since
- it doesn't have any submitted requests */
-
- CVMX_USB_RETURN(__cvmx_usb_get_pipe_handle(usb, pipe));
+ struct cvmx_usb_pipe *pipe;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+
+ if (unlikely((device_addr < 0) || (device_addr > MAX_USB_ADDRESS)))
+ return -EINVAL;
+ if (unlikely((endpoint_num < 0) || (endpoint_num > MAX_USB_ENDPOINT)))
+ return -EINVAL;
+ if (unlikely(device_speed > CVMX_USB_SPEED_LOW))
+ return -EINVAL;
+ if (unlikely((max_packet <= 0) || (max_packet > 1024)))
+ return -EINVAL;
+ if (unlikely(transfer_type > CVMX_USB_TRANSFER_INTERRUPT))
+ return -EINVAL;
+ if (unlikely((transfer_dir != CVMX_USB_DIRECTION_OUT) &&
+ (transfer_dir != CVMX_USB_DIRECTION_IN)))
+ return -EINVAL;
+ if (unlikely(interval < 0))
+ return -EINVAL;
+ if (unlikely((transfer_type == CVMX_USB_TRANSFER_CONTROL) && interval))
+ return -EINVAL;
+ if (unlikely(multi_count < 0))
+ return -EINVAL;
+ if (unlikely((device_speed != CVMX_USB_SPEED_HIGH) &&
+ (multi_count != 0)))
+ return -EINVAL;
+ if (unlikely((hub_device_addr < 0) || (hub_device_addr > MAX_USB_ADDRESS)))
+ return -EINVAL;
+ if (unlikely((hub_port < 0) || (hub_port > MAX_USB_HUB_PORT)))
+ return -EINVAL;
+
+ /* Find a free pipe */
+ pipe = usb->free_pipes.head;
+ if (!pipe)
+ return -ENOMEM;
+ __cvmx_usb_remove_pipe(&usb->free_pipes, pipe);
+ pipe->flags = flags | __CVMX_USB_PIPE_FLAGS_OPEN;
+ if ((device_speed == CVMX_USB_SPEED_HIGH) &&
+ (transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+ (transfer_type == CVMX_USB_TRANSFER_BULK))
+ pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
+ pipe->device_addr = device_addr;
+ pipe->endpoint_num = endpoint_num;
+ pipe->device_speed = device_speed;
+ pipe->max_packet = max_packet;
+ pipe->transfer_type = transfer_type;
+ pipe->transfer_dir = transfer_dir;
+ /*
+ * All pipes use interval to rate limit NAK processing. Force an
+ * interval if one wasn't supplied
+ */
+ if (!interval)
+ interval = 1;
+ if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+ pipe->interval = interval*8;
+ /* Force start splits to be schedule on uFrame 0 */
+ pipe->next_tx_frame = ((usb->frame_number+7)&~7) + pipe->interval;
+ } else {
+ pipe->interval = interval;
+ pipe->next_tx_frame = usb->frame_number + pipe->interval;
+ }
+ pipe->multi_count = multi_count;
+ pipe->hub_device_addr = hub_device_addr;
+ pipe->hub_port = hub_port;
+ pipe->pid_toggle = 0;
+ pipe->split_sc_frame = -1;
+ __cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
+
+ /*
+ * We don't need to tell the hardware about this pipe yet since
+ * it doesn't have any submitted requests
+ */
+
+ return __cvmx_usb_get_pipe_handle(usb, pipe);
}
/**
- * @INTERNAL
* Poll the RX FIFOs and remove data as needed. This function is only used
* in non DMA mode. It is very important that this function be called quickly
* enough to prevent FIFO overflow.
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
*/
-static void __cvmx_usb_poll_rx_fifo(cvmx_usb_internal_state_t *usb)
+static void __cvmx_usb_poll_rx_fifo(struct cvmx_usb_internal_state *usb)
{
- cvmx_usbcx_grxstsph_t rx_status;
- int channel;
- int bytes;
- uint64_t address;
- uint32_t *ptr;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", usb);
-
- rx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GRXSTSPH(usb->index));
- /* Only read data if IN data is there */
- if (rx_status.s.pktsts != 2)
- CVMX_USB_RETURN_NOTHING();
- /* Check if no data is available */
- if (!rx_status.s.bcnt)
- CVMX_USB_RETURN_NOTHING();
-
- channel = rx_status.s.chnum;
- bytes = rx_status.s.bcnt;
- if (!bytes)
- CVMX_USB_RETURN_NOTHING();
-
- /* Get where the DMA engine would have written this data */
- address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8);
- ptr = cvmx_phys_to_ptr(address);
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, address + bytes);
-
- /* Loop writing the FIFO data for this packet into memory */
- while (bytes > 0) {
- *ptr++ = __cvmx_usb_read_csr32(usb, USB_FIFO_ADDRESS(channel, usb->index));
- bytes -= 4;
- }
- CVMX_SYNCW;
-
- CVMX_USB_RETURN_NOTHING();
+ union cvmx_usbcx_grxstsph rx_status;
+ int channel;
+ int bytes;
+ uint64_t address;
+ uint32_t *ptr;
+
+ rx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GRXSTSPH(usb->index));
+ /* Only read data if IN data is there */
+ if (rx_status.s.pktsts != 2)
+ return;
+ /* Check if no data is available */
+ if (!rx_status.s.bcnt)
+ return;
+
+ channel = rx_status.s.chnum;
+ bytes = rx_status.s.bcnt;
+ if (!bytes)
+ return;
+
+ /* Get where the DMA engine would have written this data */
+ address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8);
+ ptr = cvmx_phys_to_ptr(address);
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, address + bytes);
+
+ /* Loop writing the FIFO data for this packet into memory */
+ while (bytes > 0) {
+ *ptr++ = __cvmx_usb_read_csr32(usb, USB_FIFO_ADDRESS(channel, usb->index));
+ bytes -= 4;
+ }
+ CVMX_SYNCW;
+
+ return;
}
@@ -1325,1196 +1300,1136 @@ static void __cvmx_usb_poll_rx_fifo(cvmx_usb_internal_state_t *usb)
* Fill the TX hardware fifo with data out of the software
* fifos
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param fifo Software fifo to use
- * @param available Amount of space in the hardware fifo
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @fifo: Software fifo to use
+ * @available: Amount of space in the hardware fifo
*
- * @return Non zero if the hardware fifo was too small and needs
- * to be serviced again.
+ * Returns: Non zero if the hardware fifo was too small and needs
+ * to be serviced again.
*/
-static int __cvmx_usb_fill_tx_hw(cvmx_usb_internal_state_t *usb, cvmx_usb_tx_fifo_t *fifo, int available)
+static int __cvmx_usb_fill_tx_hw(struct cvmx_usb_internal_state *usb, struct cvmx_usb_tx_fifo *fifo, int available)
{
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", usb);
- CVMX_USB_LOG_PARAM("%p", fifo);
- CVMX_USB_LOG_PARAM("%d", available);
-
- /* We're done either when there isn't anymore space or the software FIFO
- is empty */
- while (available && (fifo->head != fifo->tail)) {
- int i = fifo->tail;
- const uint32_t *ptr = cvmx_phys_to_ptr(fifo->entry[i].address);
- uint64_t csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel, usb->index) ^ 4;
- int words = available;
-
- /* Limit the amount of data to waht the SW fifo has */
- if (fifo->entry[i].size <= available) {
- words = fifo->entry[i].size;
- fifo->tail++;
- if (fifo->tail > MAX_CHANNELS)
- fifo->tail = 0;
- }
-
- /* Update the next locations and counts */
- available -= words;
- fifo->entry[i].address += words * 4;
- fifo->entry[i].size -= words;
-
- /* Write the HW fifo data. The read every three writes is due
- to an errata on CN3XXX chips */
- while (words > 3) {
- cvmx_write64_uint32(csr_address, *ptr++);
- cvmx_write64_uint32(csr_address, *ptr++);
- cvmx_write64_uint32(csr_address, *ptr++);
- cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
- words -= 3;
- }
- cvmx_write64_uint32(csr_address, *ptr++);
- if (--words) {
- cvmx_write64_uint32(csr_address, *ptr++);
- if (--words)
- cvmx_write64_uint32(csr_address, *ptr++);
- }
- cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
- }
- CVMX_USB_RETURN(fifo->head != fifo->tail);
+ /*
+ * We're done either when there isn't anymore space or the software FIFO
+ * is empty
+ */
+ while (available && (fifo->head != fifo->tail)) {
+ int i = fifo->tail;
+ const uint32_t *ptr = cvmx_phys_to_ptr(fifo->entry[i].address);
+ uint64_t csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel, usb->index) ^ 4;
+ int words = available;
+
+ /* Limit the amount of data to waht the SW fifo has */
+ if (fifo->entry[i].size <= available) {
+ words = fifo->entry[i].size;
+ fifo->tail++;
+ if (fifo->tail > MAX_CHANNELS)
+ fifo->tail = 0;
+ }
+
+ /* Update the next locations and counts */
+ available -= words;
+ fifo->entry[i].address += words * 4;
+ fifo->entry[i].size -= words;
+
+ /*
+ * Write the HW fifo data. The read every three writes is due
+ * to an errata on CN3XXX chips
+ */
+ while (words > 3) {
+ cvmx_write64_uint32(csr_address, *ptr++);
+ cvmx_write64_uint32(csr_address, *ptr++);
+ cvmx_write64_uint32(csr_address, *ptr++);
+ cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
+ words -= 3;
+ }
+ cvmx_write64_uint32(csr_address, *ptr++);
+ if (--words) {
+ cvmx_write64_uint32(csr_address, *ptr++);
+ if (--words)
+ cvmx_write64_uint32(csr_address, *ptr++);
+ }
+ cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
+ }
+ return fifo->head != fifo->tail;
}
/**
* Check the hardware FIFOs and fill them as needed
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
*/
-static void __cvmx_usb_poll_tx_fifo(cvmx_usb_internal_state_t *usb)
+static void __cvmx_usb_poll_tx_fifo(struct cvmx_usb_internal_state *usb)
{
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", usb);
-
- if (usb->periodic.head != usb->periodic.tail) {
- cvmx_usbcx_hptxsts_t tx_status;
- tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXSTS(usb->index));
- if (__cvmx_usb_fill_tx_hw(usb, &usb->periodic, tx_status.s.ptxfspcavail))
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, ptxfempmsk, 1);
- else
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, ptxfempmsk, 0);
- }
-
- if (usb->nonperiodic.head != usb->nonperiodic.tail) {
- cvmx_usbcx_gnptxsts_t tx_status;
- tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXSTS(usb->index));
- if (__cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic, tx_status.s.nptxfspcavail))
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, nptxfempmsk, 1);
- else
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, nptxfempmsk, 0);
- }
-
- CVMX_USB_RETURN_NOTHING();
+ if (usb->periodic.head != usb->periodic.tail) {
+ union cvmx_usbcx_hptxsts tx_status;
+ tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXSTS(usb->index));
+ if (__cvmx_usb_fill_tx_hw(usb, &usb->periodic, tx_status.s.ptxfspcavail))
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, ptxfempmsk, 1);
+ else
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, ptxfempmsk, 0);
+ }
+
+ if (usb->nonperiodic.head != usb->nonperiodic.tail) {
+ union cvmx_usbcx_gnptxsts tx_status;
+ tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXSTS(usb->index));
+ if (__cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic, tx_status.s.nptxfspcavail))
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, nptxfempmsk, 1);
+ else
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, nptxfempmsk, 0);
+ }
+
+ return;
}
/**
- * @INTERNAL
* Fill the TX FIFO with an outgoing packet
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param channel Channel number to get packet from
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @channel: Channel number to get packet from
*/
-static void __cvmx_usb_fill_tx_fifo(cvmx_usb_internal_state_t *usb, int channel)
+static void __cvmx_usb_fill_tx_fifo(struct cvmx_usb_internal_state *usb, int channel)
{
- cvmx_usbcx_hccharx_t hcchar;
- cvmx_usbcx_hcspltx_t usbc_hcsplt;
- cvmx_usbcx_hctsizx_t usbc_hctsiz;
- cvmx_usb_tx_fifo_t *fifo;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", usb);
- CVMX_USB_LOG_PARAM("%d", channel);
-
- /* We only need to fill data on outbound channels */
- hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
- if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT)
- CVMX_USB_RETURN_NOTHING();
-
- /* OUT Splits only have data on the start and not the complete */
- usbc_hcsplt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index));
- if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt)
- CVMX_USB_RETURN_NOTHING();
-
- /* Find out how many bytes we need to fill and convert it into 32bit words */
- usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
- if (!usbc_hctsiz.s.xfersize)
- CVMX_USB_RETURN_NOTHING();
-
- if ((hcchar.s.eptype == CVMX_USB_TRANSFER_INTERRUPT) ||
- (hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS))
- fifo = &usb->periodic;
- else
- fifo = &usb->nonperiodic;
-
- fifo->entry[fifo->head].channel = channel;
- fifo->entry[fifo->head].address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8);
- fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize+3)>>2;
- fifo->head++;
- if (fifo->head > MAX_CHANNELS)
- fifo->head = 0;
-
- __cvmx_usb_poll_tx_fifo(usb);
-
- CVMX_USB_RETURN_NOTHING();
+ union cvmx_usbcx_hccharx hcchar;
+ union cvmx_usbcx_hcspltx usbc_hcsplt;
+ union cvmx_usbcx_hctsizx usbc_hctsiz;
+ struct cvmx_usb_tx_fifo *fifo;
+
+ /* We only need to fill data on outbound channels */
+ hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
+ if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT)
+ return;
+
+ /* OUT Splits only have data on the start and not the complete */
+ usbc_hcsplt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index));
+ if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt)
+ return;
+
+ /* Find out how many bytes we need to fill and convert it into 32bit words */
+ usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
+ if (!usbc_hctsiz.s.xfersize)
+ return;
+
+ if ((hcchar.s.eptype == CVMX_USB_TRANSFER_INTERRUPT) ||
+ (hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS))
+ fifo = &usb->periodic;
+ else
+ fifo = &usb->nonperiodic;
+
+ fifo->entry[fifo->head].channel = channel;
+ fifo->entry[fifo->head].address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8);
+ fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize+3)>>2;
+ fifo->head++;
+ if (fifo->head > MAX_CHANNELS)
+ fifo->head = 0;
+
+ __cvmx_usb_poll_tx_fifo(usb);
+
+ return;
}
/**
- * @INTERNAL
* Perform channel specific setup for Control transactions. All
* the generic stuff will already have been done in
* __cvmx_usb_start_channel()
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param channel Channel to setup
- * @param pipe Pipe for control transaction
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @channel: Channel to setup
+ * @pipe: Pipe for control transaction
*/
-static void __cvmx_usb_start_channel_control(cvmx_usb_internal_state_t *usb,
- int channel,
- cvmx_usb_pipe_t *pipe)
+static void __cvmx_usb_start_channel_control(struct cvmx_usb_internal_state *usb,
+ int channel,
+ struct cvmx_usb_pipe *pipe)
{
- cvmx_usb_transaction_t *transaction = pipe->head;
- cvmx_usb_control_header_t *header = cvmx_phys_to_ptr(transaction->control_header);
- int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
- int packets_to_transfer;
- cvmx_usbcx_hctsizx_t usbc_hctsiz;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", usb);
- CVMX_USB_LOG_PARAM("%d", channel);
- CVMX_USB_LOG_PARAM("%p", pipe);
-
- usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
-
- switch (transaction->stage) {
- case CVMX_USB_STAGE_NON_CONTROL:
- case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
- cvmx_dprintf("%s: ERROR - Non control stage\n", __FUNCTION__);
- break;
- case CVMX_USB_STAGE_SETUP:
- usbc_hctsiz.s.pid = 3; /* Setup */
- bytes_to_transfer = sizeof(*header);
- /* All Control operations start with a setup going OUT */
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, epdir, CVMX_USB_DIRECTION_OUT);
- /* Setup send the control header instead of the buffer data. The
- buffer data will be used in the next stage */
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, transaction->control_header);
- break;
- case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
- usbc_hctsiz.s.pid = 3; /* Setup */
- bytes_to_transfer = 0;
- /* All Control operations start with a setup going OUT */
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, epdir, CVMX_USB_DIRECTION_OUT);
- USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), cvmx_usbcx_hcspltx_t, compsplt, 1);
- break;
- case CVMX_USB_STAGE_DATA:
- usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
- if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
- if (header->s.request_type & 0x80)
- bytes_to_transfer = 0;
- else if (bytes_to_transfer > pipe->max_packet)
- bytes_to_transfer = pipe->max_packet;
- }
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
- cvmx_usbcx_hccharx_t, epdir,
- ((header->s.request_type & 0x80) ?
- CVMX_USB_DIRECTION_IN :
- CVMX_USB_DIRECTION_OUT));
- break;
- case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
- usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
- if (!(header->s.request_type & 0x80))
- bytes_to_transfer = 0;
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
- cvmx_usbcx_hccharx_t, epdir,
- ((header->s.request_type & 0x80) ?
- CVMX_USB_DIRECTION_IN :
- CVMX_USB_DIRECTION_OUT));
- USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), cvmx_usbcx_hcspltx_t, compsplt, 1);
- break;
- case CVMX_USB_STAGE_STATUS:
- usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
- bytes_to_transfer = 0;
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, epdir,
- ((header->s.request_type & 0x80) ?
- CVMX_USB_DIRECTION_OUT :
- CVMX_USB_DIRECTION_IN));
- break;
- case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
- usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
- bytes_to_transfer = 0;
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, epdir,
- ((header->s.request_type & 0x80) ?
- CVMX_USB_DIRECTION_OUT :
- CVMX_USB_DIRECTION_IN));
- USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), cvmx_usbcx_hcspltx_t, compsplt, 1);
- break;
- }
-
- /* Make sure the transfer never exceeds the byte limit of the hardware.
- Further bytes will be sent as continued transactions */
- if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
- /* Round MAX_TRANSFER_BYTES to a multiple of out packet size */
- bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
- bytes_to_transfer *= pipe->max_packet;
- }
-
- /* Calculate the number of packets to transfer. If the length is zero
- we still need to transfer one packet */
- packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
- if (packets_to_transfer == 0)
- packets_to_transfer = 1;
- else if ((packets_to_transfer>1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
- /* Limit to one packet when not using DMA. Channels must be restarted
- between every packet for IN transactions, so there is no reason to
- do multiple packets in a row */
- packets_to_transfer = 1;
- bytes_to_transfer = packets_to_transfer * pipe->max_packet;
- }
- else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
- /* Limit the number of packet and data transferred to what the
- hardware can handle */
- packets_to_transfer = MAX_TRANSFER_PACKETS;
- bytes_to_transfer = packets_to_transfer * pipe->max_packet;
- }
-
- usbc_hctsiz.s.xfersize = bytes_to_transfer;
- usbc_hctsiz.s.pktcnt = packets_to_transfer;
-
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32);
- CVMX_USB_RETURN_NOTHING();
+ struct cvmx_usb_transaction *transaction = pipe->head;
+ union cvmx_usb_control_header *header =
+ cvmx_phys_to_ptr(transaction->control_header);
+ int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
+ int packets_to_transfer;
+ union cvmx_usbcx_hctsizx usbc_hctsiz;
+
+ usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
+
+ switch (transaction->stage) {
+ case CVMX_USB_STAGE_NON_CONTROL:
+ case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
+ cvmx_dprintf("%s: ERROR - Non control stage\n", __FUNCTION__);
+ break;
+ case CVMX_USB_STAGE_SETUP:
+ usbc_hctsiz.s.pid = 3; /* Setup */
+ bytes_to_transfer = sizeof(*header);
+ /* All Control operations start with a setup going OUT */
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, CVMX_USB_DIRECTION_OUT);
+ /*
+ * Setup send the control header instead of the buffer data. The
+ * buffer data will be used in the next stage
+ */
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, transaction->control_header);
+ break;
+ case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
+ usbc_hctsiz.s.pid = 3; /* Setup */
+ bytes_to_transfer = 0;
+ /* All Control operations start with a setup going OUT */
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, CVMX_USB_DIRECTION_OUT);
+ USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1);
+ break;
+ case CVMX_USB_STAGE_DATA:
+ usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
+ if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+ if (header->s.request_type & 0x80)
+ bytes_to_transfer = 0;
+ else if (bytes_to_transfer > pipe->max_packet)
+ bytes_to_transfer = pipe->max_packet;
+ }
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+ union cvmx_usbcx_hccharx, epdir,
+ ((header->s.request_type & 0x80) ?
+ CVMX_USB_DIRECTION_IN :
+ CVMX_USB_DIRECTION_OUT));
+ break;
+ case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
+ usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
+ if (!(header->s.request_type & 0x80))
+ bytes_to_transfer = 0;
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+ union cvmx_usbcx_hccharx, epdir,
+ ((header->s.request_type & 0x80) ?
+ CVMX_USB_DIRECTION_IN :
+ CVMX_USB_DIRECTION_OUT));
+ USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1);
+ break;
+ case CVMX_USB_STAGE_STATUS:
+ usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
+ bytes_to_transfer = 0;
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir,
+ ((header->s.request_type & 0x80) ?
+ CVMX_USB_DIRECTION_OUT :
+ CVMX_USB_DIRECTION_IN));
+ break;
+ case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
+ usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
+ bytes_to_transfer = 0;
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir,
+ ((header->s.request_type & 0x80) ?
+ CVMX_USB_DIRECTION_OUT :
+ CVMX_USB_DIRECTION_IN));
+ USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1);
+ break;
+ }
+
+ /*
+ * Make sure the transfer never exceeds the byte limit of the hardware.
+ * Further bytes will be sent as continued transactions
+ */
+ if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
+ /* Round MAX_TRANSFER_BYTES to a multiple of out packet size */
+ bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
+ bytes_to_transfer *= pipe->max_packet;
+ }
+
+ /*
+ * Calculate the number of packets to transfer. If the length is zero
+ * we still need to transfer one packet
+ */
+ packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
+ if (packets_to_transfer == 0)
+ packets_to_transfer = 1;
+ else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
+ /*
+ * Limit to one packet when not using DMA. Channels must be
+ * restarted between every packet for IN transactions, so there
+ * is no reason to do multiple packets in a row
+ */
+ packets_to_transfer = 1;
+ bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+ } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
+ /*
+ * Limit the number of packet and data transferred to what the
+ * hardware can handle
+ */
+ packets_to_transfer = MAX_TRANSFER_PACKETS;
+ bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+ }
+
+ usbc_hctsiz.s.xfersize = bytes_to_transfer;
+ usbc_hctsiz.s.pktcnt = packets_to_transfer;
+
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32);
+ return;
}
/**
- * @INTERNAL
* Start a channel to perform the pipe's head transaction
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param channel Channel to setup
- * @param pipe Pipe to start
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @channel: Channel to setup
+ * @pipe: Pipe to start
*/
-static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb,
- int channel,
- cvmx_usb_pipe_t *pipe)
+static void __cvmx_usb_start_channel(struct cvmx_usb_internal_state *usb,
+ int channel,
+ struct cvmx_usb_pipe *pipe)
{
- cvmx_usb_transaction_t *transaction = pipe->head;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", usb);
- CVMX_USB_LOG_PARAM("%d", channel);
- CVMX_USB_LOG_PARAM("%p", pipe);
-
- if (cvmx_unlikely((usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS) ||
- (pipe->flags & CVMX_USB_PIPE_FLAGS_DEBUG_TRANSFERS)))
- cvmx_dprintf("%s: Channel %d started. Pipe %d transaction %d stage %d\n",
- __FUNCTION__, channel, __cvmx_usb_get_pipe_handle(usb, pipe),
- __cvmx_usb_get_submit_handle(usb, transaction),
- transaction->stage);
-
- /* Make sure all writes to the DMA region get flushed */
- CVMX_SYNCW;
-
- /* Attach the channel to the pipe */
- usb->pipe_for_channel[channel] = pipe;
- pipe->channel = channel;
- pipe->flags |= __CVMX_USB_PIPE_FLAGS_SCHEDULED;
-
- /* Mark this channel as in use */
- usb->idle_hardware_channels &= ~(1<<channel);
-
- /* Enable the channel interrupt bits */
- {
- cvmx_usbcx_hcintx_t usbc_hcint;
- cvmx_usbcx_hcintmskx_t usbc_hcintmsk;
- cvmx_usbcx_haintmsk_t usbc_haintmsk;
-
- /* Clear all channel status bits */
- usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index));
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index), usbc_hcint.u32);
-
- usbc_hcintmsk.u32 = 0;
- usbc_hcintmsk.s.chhltdmsk = 1;
- if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
- /* Channels need these extra interrupts when we aren't in DMA mode */
- usbc_hcintmsk.s.datatglerrmsk = 1;
- usbc_hcintmsk.s.frmovrunmsk = 1;
- usbc_hcintmsk.s.bblerrmsk = 1;
- usbc_hcintmsk.s.xacterrmsk = 1;
- if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
- /* Splits don't generate xfercompl, so we need ACK and NYET */
- usbc_hcintmsk.s.nyetmsk = 1;
- usbc_hcintmsk.s.ackmsk = 1;
- }
- usbc_hcintmsk.s.nakmsk = 1;
- usbc_hcintmsk.s.stallmsk = 1;
- usbc_hcintmsk.s.xfercomplmsk = 1;
- }
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), usbc_hcintmsk.u32);
-
- /* Enable the channel interrupt to propagate */
- usbc_haintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index));
- usbc_haintmsk.s.haintmsk |= 1<<channel;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index), usbc_haintmsk.u32);
- }
-
- /* Setup the locations the DMA engines use */
- {
- uint64_t dma_address = transaction->buffer + transaction->actual_bytes;
- if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
- dma_address = transaction->buffer + transaction->iso_packets[0].offset + transaction->actual_bytes;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, dma_address);
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, dma_address);
- }
-
- /* Setup both the size of the transfer and the SPLIT characteristics */
- {
- cvmx_usbcx_hcspltx_t usbc_hcsplt = {.u32 = 0};
- cvmx_usbcx_hctsizx_t usbc_hctsiz = {.u32 = 0};
- int packets_to_transfer;
- int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
-
- /* ISOCHRONOUS transactions store each individual transfer size in the
- packet structure, not the global buffer_length */
- if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
- bytes_to_transfer = transaction->iso_packets[0].length - transaction->actual_bytes;
-
- /* We need to do split transactions when we are talking to non high
- speed devices that are behind a high speed hub */
- if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
- /* On the start split phase (stage is even) record the frame number we
- will need to send the split complete. We only store the lower two bits
- since the time ahead can only be two frames */
- if ((transaction->stage&1) == 0) {
- if (transaction->type == CVMX_USB_TRANSFER_BULK)
- pipe->split_sc_frame = (usb->frame_number + 1) & 0x7f;
- else
- pipe->split_sc_frame = (usb->frame_number + 2) & 0x7f;
- }
- else
- pipe->split_sc_frame = -1;
-
- usbc_hcsplt.s.spltena = 1;
- usbc_hcsplt.s.hubaddr = pipe->hub_device_addr;
- usbc_hcsplt.s.prtaddr = pipe->hub_port;
- usbc_hcsplt.s.compsplt = (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE);
-
- /* SPLIT transactions can only ever transmit one data packet so
- limit the transfer size to the max packet size */
- if (bytes_to_transfer > pipe->max_packet)
- bytes_to_transfer = pipe->max_packet;
-
- /* ISOCHRONOUS OUT splits are unique in that they limit
- data transfers to 188 byte chunks representing the
- begin/middle/end of the data or all */
- if (!usbc_hcsplt.s.compsplt &&
- (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
- (pipe->transfer_type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
- /* Clear the split complete frame number as there isn't going
- to be a split complete */
- pipe->split_sc_frame = -1;
- /* See if we've started this transfer and sent data */
- if (transaction->actual_bytes == 0) {
- /* Nothing sent yet, this is either a begin or the
- entire payload */
- if (bytes_to_transfer <= 188)
- usbc_hcsplt.s.xactpos = 3; /* Entire payload in one go */
- else
- usbc_hcsplt.s.xactpos = 2; /* First part of payload */
- }
- else {
- /* Continuing the previous data, we must either be
- in the middle or at the end */
- if (bytes_to_transfer <= 188)
- usbc_hcsplt.s.xactpos = 1; /* End of payload */
- else
- usbc_hcsplt.s.xactpos = 0; /* Middle of payload */
- }
- /* Again, the transfer size is limited to 188 bytes */
- if (bytes_to_transfer > 188)
- bytes_to_transfer = 188;
- }
- }
-
- /* Make sure the transfer never exceeds the byte limit of the hardware.
- Further bytes will be sent as continued transactions */
- if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
- /* Round MAX_TRANSFER_BYTES to a multiple of out packet size */
- bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
- bytes_to_transfer *= pipe->max_packet;
- }
-
- /* Calculate the number of packets to transfer. If the length is zero
- we still need to transfer one packet */
- packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
- if (packets_to_transfer == 0)
- packets_to_transfer = 1;
- else if ((packets_to_transfer>1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
- /* Limit to one packet when not using DMA. Channels must be restarted
- between every packet for IN transactions, so there is no reason to
- do multiple packets in a row */
- packets_to_transfer = 1;
- bytes_to_transfer = packets_to_transfer * pipe->max_packet;
- }
- else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
- /* Limit the number of packet and data transferred to what the
- hardware can handle */
- packets_to_transfer = MAX_TRANSFER_PACKETS;
- bytes_to_transfer = packets_to_transfer * pipe->max_packet;
- }
-
- usbc_hctsiz.s.xfersize = bytes_to_transfer;
- usbc_hctsiz.s.pktcnt = packets_to_transfer;
-
- /* Update the DATA0/DATA1 toggle */
- usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
- /* High speed pipes may need a hardware ping before they start */
- if (pipe->flags & __CVMX_USB_PIPE_FLAGS_NEED_PING)
- usbc_hctsiz.s.dopng = 1;
-
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index), usbc_hcsplt.u32);
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32);
- }
-
- /* Setup the Host Channel Characteristics Register */
- {
- cvmx_usbcx_hccharx_t usbc_hcchar = {.u32 = 0};
-
- /* Set the startframe odd/even properly. This is only used for periodic */
- usbc_hcchar.s.oddfrm = usb->frame_number&1;
-
- /* Set the number of back to back packets allowed by this endpoint.
- Split transactions interpret "ec" as the number of immediate
- retries of failure. These retries happen too quickly, so we
- disable these entirely for splits */
- if (__cvmx_usb_pipe_needs_split(usb, pipe))
- usbc_hcchar.s.ec = 1;
- else if (pipe->multi_count < 1)
- usbc_hcchar.s.ec = 1;
- else if (pipe->multi_count > 3)
- usbc_hcchar.s.ec = 3;
- else
- usbc_hcchar.s.ec = pipe->multi_count;
-
- /* Set the rest of the endpoint specific settings */
- usbc_hcchar.s.devaddr = pipe->device_addr;
- usbc_hcchar.s.eptype = transaction->type;
- usbc_hcchar.s.lspddev = (pipe->device_speed == CVMX_USB_SPEED_LOW);
- usbc_hcchar.s.epdir = pipe->transfer_dir;
- usbc_hcchar.s.epnum = pipe->endpoint_num;
- usbc_hcchar.s.mps = pipe->max_packet;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
- }
-
- /* Do transaction type specific fixups as needed */
- switch (transaction->type) {
- case CVMX_USB_TRANSFER_CONTROL:
- __cvmx_usb_start_channel_control(usb, channel, pipe);
- break;
- case CVMX_USB_TRANSFER_BULK:
- case CVMX_USB_TRANSFER_INTERRUPT:
- break;
- case CVMX_USB_TRANSFER_ISOCHRONOUS:
- if (!__cvmx_usb_pipe_needs_split(usb, pipe)) {
- /* ISO transactions require different PIDs depending on direction
- and how many packets are needed */
- if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
- if (pipe->multi_count < 2) /* Need DATA0 */
- USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), cvmx_usbcx_hctsizx_t, pid, 0);
- else /* Need MDATA */
- USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), cvmx_usbcx_hctsizx_t, pid, 3);
- }
- }
- break;
- }
- {
- cvmx_usbcx_hctsizx_t usbc_hctsiz = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index))};
- transaction->xfersize = usbc_hctsiz.s.xfersize;
- transaction->pktcnt = usbc_hctsiz.s.pktcnt;
- }
- /* Remeber when we start a split transaction */
- if (__cvmx_usb_pipe_needs_split(usb, pipe))
- usb->active_split = transaction;
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, chena, 1);
- if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
- __cvmx_usb_fill_tx_fifo(usb, channel);
- CVMX_USB_RETURN_NOTHING();
+ struct cvmx_usb_transaction *transaction = pipe->head;
+
+ /* Make sure all writes to the DMA region get flushed */
+ CVMX_SYNCW;
+
+ /* Attach the channel to the pipe */
+ usb->pipe_for_channel[channel] = pipe;
+ pipe->channel = channel;
+ pipe->flags |= __CVMX_USB_PIPE_FLAGS_SCHEDULED;
+
+ /* Mark this channel as in use */
+ usb->idle_hardware_channels &= ~(1<<channel);
+
+ /* Enable the channel interrupt bits */
+ {
+ union cvmx_usbcx_hcintx usbc_hcint;
+ union cvmx_usbcx_hcintmskx usbc_hcintmsk;
+ union cvmx_usbcx_haintmsk usbc_haintmsk;
+
+ /* Clear all channel status bits */
+ usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index));
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index), usbc_hcint.u32);
+
+ usbc_hcintmsk.u32 = 0;
+ usbc_hcintmsk.s.chhltdmsk = 1;
+ if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
+ /* Channels need these extra interrupts when we aren't in DMA mode */
+ usbc_hcintmsk.s.datatglerrmsk = 1;
+ usbc_hcintmsk.s.frmovrunmsk = 1;
+ usbc_hcintmsk.s.bblerrmsk = 1;
+ usbc_hcintmsk.s.xacterrmsk = 1;
+ if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+ /* Splits don't generate xfercompl, so we need ACK and NYET */
+ usbc_hcintmsk.s.nyetmsk = 1;
+ usbc_hcintmsk.s.ackmsk = 1;
+ }
+ usbc_hcintmsk.s.nakmsk = 1;
+ usbc_hcintmsk.s.stallmsk = 1;
+ usbc_hcintmsk.s.xfercomplmsk = 1;
+ }
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), usbc_hcintmsk.u32);
+
+ /* Enable the channel interrupt to propagate */
+ usbc_haintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index));
+ usbc_haintmsk.s.haintmsk |= 1<<channel;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index), usbc_haintmsk.u32);
+ }
+
+ /* Setup the locations the DMA engines use */
+ {
+ uint64_t dma_address = transaction->buffer + transaction->actual_bytes;
+ if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
+ dma_address = transaction->buffer + transaction->iso_packets[0].offset + transaction->actual_bytes;
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, dma_address);
+ __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, dma_address);
+ }
+
+ /* Setup both the size of the transfer and the SPLIT characteristics */
+ {
+ union cvmx_usbcx_hcspltx usbc_hcsplt = {.u32 = 0};
+ union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = 0};
+ int packets_to_transfer;
+ int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
+
+ /*
+ * ISOCHRONOUS transactions store each individual transfer size
+ * in the packet structure, not the global buffer_length
+ */
+ if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
+ bytes_to_transfer = transaction->iso_packets[0].length - transaction->actual_bytes;
+
+ /*
+ * We need to do split transactions when we are talking to non
+ * high speed devices that are behind a high speed hub
+ */
+ if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+ /*
+ * On the start split phase (stage is even) record the
+ * frame number we will need to send the split complete.
+ * We only store the lower two bits since the time ahead
+ * can only be two frames
+ */
+ if ((transaction->stage&1) == 0) {
+ if (transaction->type == CVMX_USB_TRANSFER_BULK)
+ pipe->split_sc_frame = (usb->frame_number + 1) & 0x7f;
+ else
+ pipe->split_sc_frame = (usb->frame_number + 2) & 0x7f;
+ } else
+ pipe->split_sc_frame = -1;
+
+ usbc_hcsplt.s.spltena = 1;
+ usbc_hcsplt.s.hubaddr = pipe->hub_device_addr;
+ usbc_hcsplt.s.prtaddr = pipe->hub_port;
+ usbc_hcsplt.s.compsplt = (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE);
+
+ /*
+ * SPLIT transactions can only ever transmit one data
+ * packet so limit the transfer size to the max packet
+ * size
+ */
+ if (bytes_to_transfer > pipe->max_packet)
+ bytes_to_transfer = pipe->max_packet;
+
+ /*
+ * ISOCHRONOUS OUT splits are unique in that they limit
+ * data transfers to 188 byte chunks representing the
+ * begin/middle/end of the data or all
+ */
+ if (!usbc_hcsplt.s.compsplt &&
+ (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+ (pipe->transfer_type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
+ /*
+ * Clear the split complete frame number as
+ * there isn't going to be a split complete
+ */
+ pipe->split_sc_frame = -1;
+ /*
+ * See if we've started this transfer and sent
+ * data
+ */
+ if (transaction->actual_bytes == 0) {
+ /*
+ * Nothing sent yet, this is either a
+ * begin or the entire payload
+ */
+ if (bytes_to_transfer <= 188)
+ usbc_hcsplt.s.xactpos = 3; /* Entire payload in one go */
+ else
+ usbc_hcsplt.s.xactpos = 2; /* First part of payload */
+ } else {
+ /*
+ * Continuing the previous data, we must
+ * either be in the middle or at the end
+ */
+ if (bytes_to_transfer <= 188)
+ usbc_hcsplt.s.xactpos = 1; /* End of payload */
+ else
+ usbc_hcsplt.s.xactpos = 0; /* Middle of payload */
+ }
+ /*
+ * Again, the transfer size is limited to 188
+ * bytes
+ */
+ if (bytes_to_transfer > 188)
+ bytes_to_transfer = 188;
+ }
+ }
+
+ /*
+ * Make sure the transfer never exceeds the byte limit of the
+ * hardware. Further bytes will be sent as continued
+ * transactions
+ */
+ if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
+ /*
+ * Round MAX_TRANSFER_BYTES to a multiple of out packet
+ * size
+ */
+ bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
+ bytes_to_transfer *= pipe->max_packet;
+ }
+
+ /*
+ * Calculate the number of packets to transfer. If the length is
+ * zero we still need to transfer one packet
+ */
+ packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
+ if (packets_to_transfer == 0)
+ packets_to_transfer = 1;
+ else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
+ /*
+ * Limit to one packet when not using DMA. Channels must
+ * be restarted between every packet for IN
+ * transactions, so there is no reason to do multiple
+ * packets in a row
+ */
+ packets_to_transfer = 1;
+ bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+ } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
+ /*
+ * Limit the number of packet and data transferred to
+ * what the hardware can handle
+ */
+ packets_to_transfer = MAX_TRANSFER_PACKETS;
+ bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+ }
+
+ usbc_hctsiz.s.xfersize = bytes_to_transfer;
+ usbc_hctsiz.s.pktcnt = packets_to_transfer;
+
+ /* Update the DATA0/DATA1 toggle */
+ usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
+ /*
+ * High speed pipes may need a hardware ping before they start
+ */
+ if (pipe->flags & __CVMX_USB_PIPE_FLAGS_NEED_PING)
+ usbc_hctsiz.s.dopng = 1;
+
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index), usbc_hcsplt.u32);
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32);
+ }
+
+ /* Setup the Host Channel Characteristics Register */
+ {
+ union cvmx_usbcx_hccharx usbc_hcchar = {.u32 = 0};
+
+ /*
+ * Set the startframe odd/even properly. This is only used for
+ * periodic
+ */
+ usbc_hcchar.s.oddfrm = usb->frame_number&1;
+
+ /*
+ * Set the number of back to back packets allowed by this
+ * endpoint. Split transactions interpret "ec" as the number of
+ * immediate retries of failure. These retries happen too
+ * quickly, so we disable these entirely for splits
+ */
+ if (__cvmx_usb_pipe_needs_split(usb, pipe))
+ usbc_hcchar.s.ec = 1;
+ else if (pipe->multi_count < 1)
+ usbc_hcchar.s.ec = 1;
+ else if (pipe->multi_count > 3)
+ usbc_hcchar.s.ec = 3;
+ else
+ usbc_hcchar.s.ec = pipe->multi_count;
+
+ /* Set the rest of the endpoint specific settings */
+ usbc_hcchar.s.devaddr = pipe->device_addr;
+ usbc_hcchar.s.eptype = transaction->type;
+ usbc_hcchar.s.lspddev = (pipe->device_speed == CVMX_USB_SPEED_LOW);
+ usbc_hcchar.s.epdir = pipe->transfer_dir;
+ usbc_hcchar.s.epnum = pipe->endpoint_num;
+ usbc_hcchar.s.mps = pipe->max_packet;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
+ }
+
+ /* Do transaction type specific fixups as needed */
+ switch (transaction->type) {
+ case CVMX_USB_TRANSFER_CONTROL:
+ __cvmx_usb_start_channel_control(usb, channel, pipe);
+ break;
+ case CVMX_USB_TRANSFER_BULK:
+ case CVMX_USB_TRANSFER_INTERRUPT:
+ break;
+ case CVMX_USB_TRANSFER_ISOCHRONOUS:
+ if (!__cvmx_usb_pipe_needs_split(usb, pipe)) {
+ /*
+ * ISO transactions require different PIDs depending on
+ * direction and how many packets are needed
+ */
+ if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
+ if (pipe->multi_count < 2) /* Need DATA0 */
+ USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), union cvmx_usbcx_hctsizx, pid, 0);
+ else /* Need MDATA */
+ USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), union cvmx_usbcx_hctsizx, pid, 3);
+ }
+ }
+ break;
+ }
+ {
+ union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index))};
+ transaction->xfersize = usbc_hctsiz.s.xfersize;
+ transaction->pktcnt = usbc_hctsiz.s.pktcnt;
+ }
+ /* Remeber when we start a split transaction */
+ if (__cvmx_usb_pipe_needs_split(usb, pipe))
+ usb->active_split = transaction;
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, chena, 1);
+ if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+ __cvmx_usb_fill_tx_fifo(usb, channel);
+ return;
}
/**
- * @INTERNAL
* Find a pipe that is ready to be scheduled to hardware.
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param list Pipe list to search
- * @param current_frame
- * Frame counter to use as a time reference.
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @list: Pipe list to search
+ * @current_frame:
+ * Frame counter to use as a time reference.
*
- * @return Pipe or NULL if none are ready
+ * Returns: Pipe or NULL if none are ready
*/
-static cvmx_usb_pipe_t *__cvmx_usb_find_ready_pipe(cvmx_usb_internal_state_t *usb, cvmx_usb_pipe_list_t *list, uint64_t current_frame)
+static struct cvmx_usb_pipe *__cvmx_usb_find_ready_pipe(struct cvmx_usb_internal_state *usb, struct cvmx_usb_pipe_list *list, uint64_t current_frame)
{
- cvmx_usb_pipe_t *pipe = list->head;
- while (pipe) {
- if (!(pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED) && pipe->head &&
- (pipe->next_tx_frame <= current_frame) &&
- ((pipe->split_sc_frame == -1) || ((((int)current_frame - (int)pipe->split_sc_frame) & 0x7f) < 0x40)) &&
- (!usb->active_split || (usb->active_split == pipe->head))) {
- CVMX_PREFETCH(pipe, 128);
- CVMX_PREFETCH(pipe->head, 0);
- return pipe;
- }
- pipe = pipe->next;
- }
- return NULL;
+ struct cvmx_usb_pipe *pipe = list->head;
+ while (pipe) {
+ if (!(pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED) && pipe->head &&
+ (pipe->next_tx_frame <= current_frame) &&
+ ((pipe->split_sc_frame == -1) || ((((int)current_frame - (int)pipe->split_sc_frame) & 0x7f) < 0x40)) &&
+ (!usb->active_split || (usb->active_split == pipe->head))) {
+ CVMX_PREFETCH(pipe, 128);
+ CVMX_PREFETCH(pipe->head, 0);
+ return pipe;
+ }
+ pipe = pipe->next;
+ }
+ return NULL;
}
/**
- * @INTERNAL
* Called whenever a pipe might need to be scheduled to the
* hardware.
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param is_sof True if this schedule was called on a SOF interrupt.
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @is_sof: True if this schedule was called on a SOF interrupt.
*/
-static void __cvmx_usb_schedule(cvmx_usb_internal_state_t *usb, int is_sof)
+static void __cvmx_usb_schedule(struct cvmx_usb_internal_state *usb, int is_sof)
{
- int channel;
- cvmx_usb_pipe_t *pipe;
- int need_sof;
- cvmx_usb_transfer_t ttype;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", usb);
-
- if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
- /* Without DMA we need to be careful to not schedule something at the end of a frame and cause an overrun */
- cvmx_usbcx_hfnum_t hfnum = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index))};
- cvmx_usbcx_hfir_t hfir = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFIR(usb->index))};
- if (hfnum.s.frrem < hfir.s.frint/4)
- goto done;
- }
-
- while (usb->idle_hardware_channels) {
- /* Find an idle channel */
- CVMX_CLZ(channel, usb->idle_hardware_channels);
- channel = 31 - channel;
- if (cvmx_unlikely(channel > 7)) {
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
- cvmx_dprintf("%s: Idle hardware channels has a channel higher than 7. This is wrong\n", __FUNCTION__);
- break;
- }
-
- /* Find a pipe needing service */
- pipe = NULL;
- if (is_sof) {
- /* Only process periodic pipes on SOF interrupts. This way we are
- sure that the periodic data is sent in the beginning of the
- frame */
- pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_ISOCHRONOUS, usb->frame_number);
- if (cvmx_likely(!pipe))
- pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_INTERRUPT, usb->frame_number);
- }
- if (cvmx_likely(!pipe)) {
- pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_CONTROL, usb->frame_number);
- if (cvmx_likely(!pipe))
- pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_BULK, usb->frame_number);
- }
- if (!pipe)
- break;
-
- CVMX_USB_LOG_PARAM("%d", channel);
- CVMX_USB_LOG_PARAM("%p", pipe);
-
- if (cvmx_unlikely((usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS) ||
- (pipe->flags & CVMX_USB_PIPE_FLAGS_DEBUG_TRANSFERS))) {
- cvmx_usb_transaction_t *transaction = pipe->head;
- const cvmx_usb_control_header_t *header = (transaction->control_header) ? cvmx_phys_to_ptr(transaction->control_header) : NULL;
- const char *dir = (pipe->transfer_dir == CVMX_USB_DIRECTION_IN) ? "IN" : "OUT";
- const char *type;
- switch (pipe->transfer_type) {
- case CVMX_USB_TRANSFER_CONTROL:
- type = "SETUP";
- dir = (header->s.request_type & 0x80) ? "IN" : "OUT";
- break;
- case CVMX_USB_TRANSFER_ISOCHRONOUS:
- type = "ISOCHRONOUS";
- break;
- case CVMX_USB_TRANSFER_BULK:
- type = "BULK";
- break;
- default: /* CVMX_USB_TRANSFER_INTERRUPT */
- type = "INTERRUPT";
- break;
- }
- cvmx_dprintf("%s: Starting pipe %d, transaction %d on channel %d. %s %s len=%d header=0x%llx\n",
- __FUNCTION__, __cvmx_usb_get_pipe_handle(usb, pipe),
- __cvmx_usb_get_submit_handle(usb, transaction),
- channel, type, dir,
- transaction->buffer_length,
- (header) ? (unsigned long long)header->u64 : 0ull);
- }
- __cvmx_usb_start_channel(usb, channel, pipe);
- }
+ int channel;
+ struct cvmx_usb_pipe *pipe;
+ int need_sof;
+ enum cvmx_usb_transfer ttype;
+
+ if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
+ /* Without DMA we need to be careful to not schedule something at the end of a frame and cause an overrun */
+ union cvmx_usbcx_hfnum hfnum = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index))};
+ union cvmx_usbcx_hfir hfir = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFIR(usb->index))};
+ if (hfnum.s.frrem < hfir.s.frint/4)
+ goto done;
+ }
+
+ while (usb->idle_hardware_channels) {
+ /* Find an idle channel */
+ CVMX_CLZ(channel, usb->idle_hardware_channels);
+ channel = 31 - channel;
+ if (unlikely(channel > 7))
+ break;
+
+ /* Find a pipe needing service */
+ pipe = NULL;
+ if (is_sof) {
+ /*
+ * Only process periodic pipes on SOF interrupts. This
+ * way we are sure that the periodic data is sent in the
+ * beginning of the frame
+ */
+ pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_ISOCHRONOUS, usb->frame_number);
+ if (likely(!pipe))
+ pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_INTERRUPT, usb->frame_number);
+ }
+ if (likely(!pipe)) {
+ pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_CONTROL, usb->frame_number);
+ if (likely(!pipe))
+ pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_BULK, usb->frame_number);
+ }
+ if (!pipe)
+ break;
+
+ __cvmx_usb_start_channel(usb, channel, pipe);
+ }
done:
- /* Only enable SOF interrupts when we have transactions pending in the
- future that might need to be scheduled */
- need_sof = 0;
- for (ttype=CVMX_USB_TRANSFER_CONTROL; ttype<=CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
- pipe = usb->active_pipes[ttype].head;
- while (pipe) {
- if (pipe->next_tx_frame > usb->frame_number) {
- need_sof = 1;
- break;
- }
- pipe=pipe->next;
- }
- }
- USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, sofmsk, need_sof);
- CVMX_USB_RETURN_NOTHING();
+ /*
+ * Only enable SOF interrupts when we have transactions pending in the
+ * future that might need to be scheduled
+ */
+ need_sof = 0;
+ for (ttype = CVMX_USB_TRANSFER_CONTROL; ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
+ pipe = usb->active_pipes[ttype].head;
+ while (pipe) {
+ if (pipe->next_tx_frame > usb->frame_number) {
+ need_sof = 1;
+ break;
+ }
+ pipe = pipe->next;
+ }
+ }
+ USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, sofmsk, need_sof);
+ return;
}
/**
- * @INTERNAL
* Call a user's callback for a specific reason.
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe Pipe the callback is for or NULL
- * @param transaction
- * Transaction the callback is for or NULL
- * @param reason Reason this callback is being called
- * @param complete_code
- * Completion code for the transaction, if any
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @pipe: Pipe the callback is for or NULL
+ * @transaction:
+ * Transaction the callback is for or NULL
+ * @reason: Reason this callback is being called
+ * @complete_code:
+ * Completion code for the transaction, if any
*/
-static void __cvmx_usb_perform_callback(cvmx_usb_internal_state_t *usb,
- cvmx_usb_pipe_t *pipe,
- cvmx_usb_transaction_t *transaction,
- cvmx_usb_callback_t reason,
- cvmx_usb_complete_t complete_code)
+static void __cvmx_usb_perform_callback(struct cvmx_usb_internal_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct cvmx_usb_transaction *transaction,
+ enum cvmx_usb_callback reason,
+ enum cvmx_usb_complete complete_code)
{
- cvmx_usb_callback_func_t callback = usb->callback[reason];
- void *user_data = usb->callback_data[reason];
- int submit_handle = -1;
- int pipe_handle = -1;
- int bytes_transferred = 0;
-
- if (pipe)
- pipe_handle = __cvmx_usb_get_pipe_handle(usb, pipe);
-
- if (transaction) {
- submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
- bytes_transferred = transaction->actual_bytes;
- /* Transactions are allowed to override the default callback */
- if ((reason == CVMX_USB_CALLBACK_TRANSFER_COMPLETE) && transaction->callback) {
- callback = transaction->callback;
- user_data = transaction->callback_data;
- }
- }
-
- if (!callback)
- return;
-
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLBACKS))
- cvmx_dprintf("%*s%s: calling callback %p(usb=%p, complete_code=%s, "
- "pipe_handle=%d, submit_handle=%d, bytes_transferred=%d, user_data=%p);\n",
- 2*usb->indent, "", __FUNCTION__, callback, usb,
- __cvmx_usb_complete_to_string(complete_code),
- pipe_handle, submit_handle, bytes_transferred, user_data);
-
- callback((cvmx_usb_state_t *)usb, reason, complete_code, pipe_handle, submit_handle,
- bytes_transferred, user_data);
-
- if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLBACKS))
- cvmx_dprintf("%*s%s: callback %p complete\n", 2*usb->indent, "",
- __FUNCTION__, callback);
+ cvmx_usb_callback_func_t callback = usb->callback[reason];
+ void *user_data = usb->callback_data[reason];
+ int submit_handle = -1;
+ int pipe_handle = -1;
+ int bytes_transferred = 0;
+
+ if (pipe)
+ pipe_handle = __cvmx_usb_get_pipe_handle(usb, pipe);
+
+ if (transaction) {
+ submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
+ bytes_transferred = transaction->actual_bytes;
+ /* Transactions are allowed to override the default callback */
+ if ((reason == CVMX_USB_CALLBACK_TRANSFER_COMPLETE) && transaction->callback) {
+ callback = transaction->callback;
+ user_data = transaction->callback_data;
+ }
+ }
+
+ if (!callback)
+ return;
+
+ callback((struct cvmx_usb_state *)usb, reason, complete_code, pipe_handle, submit_handle,
+ bytes_transferred, user_data);
}
/**
- * @INTERNAL
* Signal the completion of a transaction and free it. The
* transaction will be removed from the pipe transaction list.
*
- * @param usb USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe Pipe the transaction is on
- * @param transaction
- * Transaction that completed
- * @param complete_code
- * Completion code
+ * @usb: USB device state populated by
+ * cvmx_usb_initialize().
+ * @pipe: Pipe the transaction is on
+ * @transaction:
+ * Transaction that completed
+ * @complete_code:
+ * Completion code
*/
-static void __cvmx_usb_perform_complete(cvmx_usb_internal_state_t * usb,
- cvmx_usb_pipe_t *pipe,
- cvmx_usb_transaction_t *transaction,
- cvmx_usb_complete_t complete_code)
+static void __cvmx_usb_perform_complete(struct cvmx_usb_internal_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct cvmx_usb_transaction *transaction,
+ enum cvmx_usb_complete complete_code)
{
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", usb);
- CVMX_USB_LOG_PARAM("%p", pipe);
- CVMX_USB_LOG_PARAM("%p", transaction);
- CVMX_USB_LOG_PARAM("%d", complete_code);
-
- /* If this was a split then clear our split in progress marker */
- if (usb->active_split == transaction)
- usb->active_split = NULL;
-
- /* Isochronous transactions need extra processing as they might not be done
- after a single data transfer */
- if (cvmx_unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
- /* Update the number of bytes transferred in this ISO packet */
- transaction->iso_packets[0].length = transaction->actual_bytes;
- transaction->iso_packets[0].status = complete_code;
-
- /* If there are more ISOs pending and we succeeded, schedule the next
- one */
- if ((transaction->iso_number_packets > 1) && (complete_code == CVMX_USB_COMPLETE_SUCCESS)) {
- transaction->actual_bytes = 0; /* No bytes transferred for this packet as of yet */
- transaction->iso_number_packets--; /* One less ISO waiting to transfer */
- transaction->iso_packets++; /* Increment to the next location in our packet array */
- transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
- goto done;
- }
- }
-
- /* Remove the transaction from the pipe list */
- if (transaction->next)
- transaction->next->prev = transaction->prev;
- else
- pipe->tail = transaction->prev;
- if (transaction->prev)
- transaction->prev->next = transaction->next;
- else
- pipe->head = transaction->next;
- if (!pipe->head) {
- __cvmx_usb_remove_pipe(usb->active_pipes + pipe->transfer_type, pipe);
- __cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
-
- }
- __cvmx_usb_perform_callback(usb, pipe, transaction,
- CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
- complete_code);
- __cvmx_usb_free_transaction(usb, transaction);
+ /* If this was a split then clear our split in progress marker */
+ if (usb->active_split == transaction)
+ usb->active_split = NULL;
+
+ /*
+ * Isochronous transactions need extra processing as they might not be
+ * done after a single data transfer
+ */
+ if (unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
+ /* Update the number of bytes transferred in this ISO packet */
+ transaction->iso_packets[0].length = transaction->actual_bytes;
+ transaction->iso_packets[0].status = complete_code;
+
+ /*
+ * If there are more ISOs pending and we succeeded, schedule the
+ * next one
+ */
+ if ((transaction->iso_number_packets > 1) && (complete_code == CVMX_USB_COMPLETE_SUCCESS)) {
+ transaction->actual_bytes = 0; /* No bytes transferred for this packet as of yet */
+ transaction->iso_number_packets--; /* One less ISO waiting to transfer */
+ transaction->iso_packets++; /* Increment to the next location in our packet array */
+ transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+ goto done;
+ }
+ }
+
+ /* Remove the transaction from the pipe list */
+ if (transaction->next)
+ transaction->next->prev = transaction->prev;
+ else
+ pipe->tail = transaction->prev;
+ if (transaction->prev)
+ transaction->prev->next = transaction->next;
+ else
+ pipe->head = transaction->next;
+ if (!pipe->head) {
+ __cvmx_usb_remove_pipe(usb->active_pipes + pipe->transfer_type, pipe);
+ __cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
+
+ }
+ __cvmx_usb_perform_callback(usb, pipe, transaction,
+ CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
+ complete_code);
+ __cvmx_usb_free_transaction(usb, transaction);
done:
- CVMX_USB_RETURN_NOTHING();
+ return;
}
/**
- * @INTERNAL
* Submit a usb transaction to a pipe. Called for all types
* of transactions.
*
- * @param usb
- * @param pipe_handle
- * Which pipe to submit to. Will be validated in this function.
- * @param type Transaction type
- * @param flags Flags for the transaction
- * @param buffer User buffer for the transaction
- * @param buffer_length
- * User buffer's length in bytes
- * @param control_header
- * For control transactions, the 8 byte standard header
- * @param iso_start_frame
- * For ISO transactions, the start frame
- * @param iso_number_packets
- * For ISO, the number of packet in the transaction.
- * @param iso_packets
- * A description of each ISO packet
- * @param callback User callback to call when the transaction completes
- * @param user_data User's data for the callback
- *
- * @return Submit handle or negative on failure. Matches the result
- * in the external API.
+ * @usb:
+ * @pipe_handle:
+ * Which pipe to submit to. Will be validated in this function.
+ * @type: Transaction type
+ * @flags: Flags for the transaction
+ * @buffer: User buffer for the transaction
+ * @buffer_length:
+ * User buffer's length in bytes
+ * @control_header:
+ * For control transactions, the 8 byte standard header
+ * @iso_start_frame:
+ * For ISO transactions, the start frame
+ * @iso_number_packets:
+ * For ISO, the number of packet in the transaction.
+ * @iso_packets:
+ * A description of each ISO packet
+ * @callback: User callback to call when the transaction completes
+ * @user_data: User's data for the callback
+ *
+ * Returns: Submit handle or negative on failure. Matches the result
+ * in the external API.
*/
-static int __cvmx_usb_submit_transaction(cvmx_usb_internal_state_t *usb,
- int pipe_handle,
- cvmx_usb_transfer_t type,
- int flags,
- uint64_t buffer,
- int buffer_length,
- uint64_t control_header,
- int iso_start_frame,
- int iso_number_packets,
- cvmx_usb_iso_packet_t *iso_packets,
- cvmx_usb_callback_func_t callback,
- void *user_data)
+static int __cvmx_usb_submit_transaction(struct cvmx_usb_internal_state *usb,
+ int pipe_handle,
+ enum cvmx_usb_transfer type,
+ int flags,
+ uint64_t buffer,
+ int buffer_length,
+ uint64_t control_header,
+ int iso_start_frame,
+ int iso_number_packets,
+ struct cvmx_usb_iso_packet *iso_packets,
+ cvmx_usb_callback_func_t callback,
+ void *user_data)
{
- int submit_handle;
- cvmx_usb_transaction_t *transaction;
- cvmx_usb_pipe_t *pipe = usb->pipe + pipe_handle;
-
- CVMX_USB_LOG_CALLED();
- if (cvmx_unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- /* Fail if the pipe isn't open */
- if (cvmx_unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(pipe->transfer_type != type))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- transaction = __cvmx_usb_alloc_transaction(usb);
- if (cvmx_unlikely(!transaction))
- CVMX_USB_RETURN(CVMX_USB_NO_MEMORY);
-
- transaction->type = type;
- transaction->flags |= flags;
- transaction->buffer = buffer;
- transaction->buffer_length = buffer_length;
- transaction->control_header = control_header;
- transaction->iso_start_frame = iso_start_frame; // FIXME: This is not used, implement it
- transaction->iso_number_packets = iso_number_packets;
- transaction->iso_packets = iso_packets;
- transaction->callback = callback;
- transaction->callback_data = user_data;
- if (transaction->type == CVMX_USB_TRANSFER_CONTROL)
- transaction->stage = CVMX_USB_STAGE_SETUP;
- else
- transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
-
- transaction->next = NULL;
- if (pipe->tail) {
- transaction->prev = pipe->tail;
- transaction->prev->next = transaction;
- }
- else {
- if (pipe->next_tx_frame < usb->frame_number)
- pipe->next_tx_frame = usb->frame_number + pipe->interval -
- (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
- transaction->prev = NULL;
- pipe->head = transaction;
- __cvmx_usb_remove_pipe(&usb->idle_pipes, pipe);
- __cvmx_usb_append_pipe(usb->active_pipes + pipe->transfer_type, pipe);
- }
- pipe->tail = transaction;
-
- submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
-
- /* We may need to schedule the pipe if this was the head of the pipe */
- if (!transaction->prev)
- __cvmx_usb_schedule(usb, 0);
-
- CVMX_USB_RETURN(submit_handle);
+ int submit_handle;
+ struct cvmx_usb_transaction *transaction;
+ struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
+
+ if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
+ return -EINVAL;
+ /* Fail if the pipe isn't open */
+ if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
+ return -EINVAL;
+ if (unlikely(pipe->transfer_type != type))
+ return -EINVAL;
+
+ transaction = __cvmx_usb_alloc_transaction(usb);
+ if (unlikely(!transaction))
+ return -ENOMEM;
+
+ transaction->type = type;
+ transaction->flags |= flags;
+ transaction->buffer = buffer;
+ transaction->buffer_length = buffer_length;
+ transaction->control_header = control_header;
+ transaction->iso_start_frame = iso_start_frame; // FIXME: This is not used, implement it
+ transaction->iso_number_packets = iso_number_packets;
+ transaction->iso_packets = iso_packets;
+ transaction->callback = callback;
+ transaction->callback_data = user_data;
+ if (transaction->type == CVMX_USB_TRANSFER_CONTROL)
+ transaction->stage = CVMX_USB_STAGE_SETUP;
+ else
+ transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+
+ transaction->next = NULL;
+ if (pipe->tail) {
+ transaction->prev = pipe->tail;
+ transaction->prev->next = transaction;
+ } else {
+ if (pipe->next_tx_frame < usb->frame_number)
+ pipe->next_tx_frame = usb->frame_number + pipe->interval -
+ (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
+ transaction->prev = NULL;
+ pipe->head = transaction;
+ __cvmx_usb_remove_pipe(&usb->idle_pipes, pipe);
+ __cvmx_usb_append_pipe(usb->active_pipes + pipe->transfer_type, pipe);
+ }
+ pipe->tail = transaction;
+
+ submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
+
+ /* We may need to schedule the pipe if this was the head of the pipe */
+ if (!transaction->prev)
+ __cvmx_usb_schedule(usb, 0);
+
+ return submit_handle;
}
/**
* Call to submit a USB Bulk transfer to a pipe.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Handle to the pipe for the transfer.
- * @param buffer Physical address of the data buffer in
- * memory. Note that this is NOT A POINTER, but
- * the full 64bit physical address of the
- * buffer. This may be zero if buffer_length is
- * zero.
- * @param buffer_length
- * Length of buffer in bytes.
- * @param callback Function to call when this transaction
- * completes. If the return value of this
- * function isn't an error, then this function
- * is guaranteed to be called when the
- * transaction completes. If this parameter is
- * NULL, then the generic callback registered
- * through cvmx_usb_register_callback is
- * called. If both are NULL, then there is no
- * way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- * callback is called. This is only used if
- * callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- * failure. Negative values are failure codes from
- * cvmx_usb_status_t.
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
+ * @pipe_handle:
+ * Handle to the pipe for the transfer.
+ * @buffer: Physical address of the data buffer in
+ * memory. Note that this is NOT A POINTER, but
+ * the full 64bit physical address of the
+ * buffer. This may be zero if buffer_length is
+ * zero.
+ * @buffer_length:
+ * Length of buffer in bytes.
+ * @callback: Function to call when this transaction
+ * completes. If the return value of this
+ * function isn't an error, then this function
+ * is guaranteed to be called when the
+ * transaction completes. If this parameter is
+ * NULL, then the generic callback registered
+ * through cvmx_usb_register_callback is
+ * called. If both are NULL, then there is no
+ * way to know when a transaction completes.
+ * @user_data: User supplied data returned when the
+ * callback is called. This is only used if
+ * callback in not NULL.
+ *
+ * Returns: A submitted transaction handle or negative on
+ * failure. Negative values are error codes.
*/
-int cvmx_usb_submit_bulk(cvmx_usb_state_t *state, int pipe_handle,
- uint64_t buffer, int buffer_length,
- cvmx_usb_callback_func_t callback,
- void *user_data)
+int cvmx_usb_submit_bulk(struct cvmx_usb_state *state, int pipe_handle,
+ uint64_t buffer, int buffer_length,
+ cvmx_usb_callback_func_t callback,
+ void *user_data)
{
- int submit_handle;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- CVMX_USB_LOG_PARAM("%d", pipe_handle);
- CVMX_USB_LOG_PARAM("0x%llx", (unsigned long long)buffer);
- CVMX_USB_LOG_PARAM("%d", buffer_length);
-
- /* Pipe handle checking is done later in a common place */
- if (cvmx_unlikely(!buffer))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(buffer_length < 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
- CVMX_USB_TRANSFER_BULK,
- 0, /* flags */
- buffer,
- buffer_length,
- 0, /* control_header */
- 0, /* iso_start_frame */
- 0, /* iso_number_packets */
- NULL, /* iso_packets */
- callback,
- user_data);
- CVMX_USB_RETURN(submit_handle);
+ int submit_handle;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+
+ /* Pipe handle checking is done later in a common place */
+ if (unlikely(!buffer))
+ return -EINVAL;
+ if (unlikely(buffer_length < 0))
+ return -EINVAL;
+
+ submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
+ CVMX_USB_TRANSFER_BULK,
+ 0, /* flags */
+ buffer,
+ buffer_length,
+ 0, /* control_header */
+ 0, /* iso_start_frame */
+ 0, /* iso_number_packets */
+ NULL, /* iso_packets */
+ callback,
+ user_data);
+ return submit_handle;
}
/**
* Call to submit a USB Interrupt transfer to a pipe.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Handle to the pipe for the transfer.
- * @param buffer Physical address of the data buffer in
- * memory. Note that this is NOT A POINTER, but
- * the full 64bit physical address of the
- * buffer. This may be zero if buffer_length is
- * zero.
- * @param buffer_length
- * Length of buffer in bytes.
- * @param callback Function to call when this transaction
- * completes. If the return value of this
- * function isn't an error, then this function
- * is guaranteed to be called when the
- * transaction completes. If this parameter is
- * NULL, then the generic callback registered
- * through cvmx_usb_register_callback is
- * called. If both are NULL, then there is no
- * way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- * callback is called. This is only used if
- * callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- * failure. Negative values are failure codes from
- * cvmx_usb_status_t.
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
+ * @pipe_handle:
+ * Handle to the pipe for the transfer.
+ * @buffer: Physical address of the data buffer in
+ * memory. Note that this is NOT A POINTER, but
+ * the full 64bit physical address of the
+ * buffer. This may be zero if buffer_length is
+ * zero.
+ * @buffer_length:
+ * Length of buffer in bytes.
+ * @callback: Function to call when this transaction
+ * completes. If the return value of this
+ * function isn't an error, then this function
+ * is guaranteed to be called when the
+ * transaction completes. If this parameter is
+ * NULL, then the generic callback registered
+ * through cvmx_usb_register_callback is
+ * called. If both are NULL, then there is no
+ * way to know when a transaction completes.
+ * @user_data: User supplied data returned when the
+ * callback is called. This is only used if
+ * callback in not NULL.
+ *
+ * Returns: A submitted transaction handle or negative on
+ * failure. Negative values are error codes.
*/
-int cvmx_usb_submit_interrupt(cvmx_usb_state_t *state, int pipe_handle,
- uint64_t buffer, int buffer_length,
- cvmx_usb_callback_func_t callback,
- void *user_data)
+int cvmx_usb_submit_interrupt(struct cvmx_usb_state *state, int pipe_handle,
+ uint64_t buffer, int buffer_length,
+ cvmx_usb_callback_func_t callback,
+ void *user_data)
{
- int submit_handle;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- CVMX_USB_LOG_PARAM("%d", pipe_handle);
- CVMX_USB_LOG_PARAM("0x%llx", (unsigned long long)buffer);
- CVMX_USB_LOG_PARAM("%d", buffer_length);
-
- /* Pipe handle checking is done later in a common place */
- if (cvmx_unlikely(!buffer))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(buffer_length < 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
- CVMX_USB_TRANSFER_INTERRUPT,
- 0, /* flags */
- buffer,
- buffer_length,
- 0, /* control_header */
- 0, /* iso_start_frame */
- 0, /* iso_number_packets */
- NULL, /* iso_packets */
- callback,
- user_data);
- CVMX_USB_RETURN(submit_handle);
+ int submit_handle;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+
+ /* Pipe handle checking is done later in a common place */
+ if (unlikely(!buffer))
+ return -EINVAL;
+ if (unlikely(buffer_length < 0))
+ return -EINVAL;
+
+ submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
+ CVMX_USB_TRANSFER_INTERRUPT,
+ 0, /* flags */
+ buffer,
+ buffer_length,
+ 0, /* control_header */
+ 0, /* iso_start_frame */
+ 0, /* iso_number_packets */
+ NULL, /* iso_packets */
+ callback,
+ user_data);
+ return submit_handle;
}
/**
* Call to submit a USB Control transfer to a pipe.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Handle to the pipe for the transfer.
- * @param control_header
- * USB 8 byte control header physical address.
- * Note that this is NOT A POINTER, but the
- * full 64bit physical address of the buffer.
- * @param buffer Physical address of the data buffer in
- * memory. Note that this is NOT A POINTER, but
- * the full 64bit physical address of the
- * buffer. This may be zero if buffer_length is
- * zero.
- * @param buffer_length
- * Length of buffer in bytes.
- * @param callback Function to call when this transaction
- * completes. If the return value of this
- * function isn't an error, then this function
- * is guaranteed to be called when the
- * transaction completes. If this parameter is
- * NULL, then the generic callback registered
- * through cvmx_usb_register_callback is
- * called. If both are NULL, then there is no
- * way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- * callback is called. This is only used if
- * callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- * failure. Negative values are failure codes from
- * cvmx_usb_status_t.
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
+ * @pipe_handle:
+ * Handle to the pipe for the transfer.
+ * @control_header:
+ * USB 8 byte control header physical address.
+ * Note that this is NOT A POINTER, but the
+ * full 64bit physical address of the buffer.
+ * @buffer: Physical address of the data buffer in
+ * memory. Note that this is NOT A POINTER, but
+ * the full 64bit physical address of the
+ * buffer. This may be zero if buffer_length is
+ * zero.
+ * @buffer_length:
+ * Length of buffer in bytes.
+ * @callback: Function to call when this transaction
+ * completes. If the return value of this
+ * function isn't an error, then this function
+ * is guaranteed to be called when the
+ * transaction completes. If this parameter is
+ * NULL, then the generic callback registered
+ * through cvmx_usb_register_callback is
+ * called. If both are NULL, then there is no
+ * way to know when a transaction completes.
+ * @user_data: User supplied data returned when the
+ * callback is called. This is only used if
+ * callback in not NULL.
+ *
+ * Returns: A submitted transaction handle or negative on
+ * failure. Negative values are error codes.
*/
-int cvmx_usb_submit_control(cvmx_usb_state_t *state, int pipe_handle,
- uint64_t control_header,
- uint64_t buffer, int buffer_length,
- cvmx_usb_callback_func_t callback,
- void *user_data)
+int cvmx_usb_submit_control(struct cvmx_usb_state *state, int pipe_handle,
+ uint64_t control_header,
+ uint64_t buffer, int buffer_length,
+ cvmx_usb_callback_func_t callback,
+ void *user_data)
{
- int submit_handle;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
- cvmx_usb_control_header_t *header = cvmx_phys_to_ptr(control_header);
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- CVMX_USB_LOG_PARAM("%d", pipe_handle);
- CVMX_USB_LOG_PARAM("0x%llx", (unsigned long long)control_header);
- CVMX_USB_LOG_PARAM("0x%llx", (unsigned long long)buffer);
- CVMX_USB_LOG_PARAM("%d", buffer_length);
-
- /* Pipe handle checking is done later in a common place */
- if (cvmx_unlikely(!control_header))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- /* Some drivers send a buffer with a zero length. God only knows why */
- if (cvmx_unlikely(buffer && (buffer_length < 0)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(!buffer && (buffer_length != 0)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if ((header->s.request_type & 0x80) == 0)
- buffer_length = cvmx_le16_to_cpu(header->s.length);
-
- submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
- CVMX_USB_TRANSFER_CONTROL,
- 0, /* flags */
- buffer,
- buffer_length,
- control_header,
- 0, /* iso_start_frame */
- 0, /* iso_number_packets */
- NULL, /* iso_packets */
- callback,
- user_data);
- CVMX_USB_RETURN(submit_handle);
+ int submit_handle;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+ union cvmx_usb_control_header *header =
+ cvmx_phys_to_ptr(control_header);
+
+ /* Pipe handle checking is done later in a common place */
+ if (unlikely(!control_header))
+ return -EINVAL;
+ /* Some drivers send a buffer with a zero length. God only knows why */
+ if (unlikely(buffer && (buffer_length < 0)))
+ return -EINVAL;
+ if (unlikely(!buffer && (buffer_length != 0)))
+ return -EINVAL;
+ if ((header->s.request_type & 0x80) == 0)
+ buffer_length = le16_to_cpu(header->s.length);
+
+ submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
+ CVMX_USB_TRANSFER_CONTROL,
+ 0, /* flags */
+ buffer,
+ buffer_length,
+ control_header,
+ 0, /* iso_start_frame */
+ 0, /* iso_number_packets */
+ NULL, /* iso_packets */
+ callback,
+ user_data);
+ return submit_handle;
}
/**
* Call to submit a USB Isochronous transfer to a pipe.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Handle to the pipe for the transfer.
- * @param start_frame
- * Number of frames into the future to schedule
- * this transaction.
- * @param flags Flags to control the transfer. See
- * cvmx_usb_isochronous_flags_t for the flag
- * definitions.
- * @param number_packets
- * Number of sequential packets to transfer.
- * "packets" is a pointer to an array of this
- * many packet structures.
- * @param packets Description of each transfer packet as
- * defined by cvmx_usb_iso_packet_t. The array
- * pointed to here must stay valid until the
- * complete callback is called.
- * @param buffer Physical address of the data buffer in
- * memory. Note that this is NOT A POINTER, but
- * the full 64bit physical address of the
- * buffer. This may be zero if buffer_length is
- * zero.
- * @param buffer_length
- * Length of buffer in bytes.
- * @param callback Function to call when this transaction
- * completes. If the return value of this
- * function isn't an error, then this function
- * is guaranteed to be called when the
- * transaction completes. If this parameter is
- * NULL, then the generic callback registered
- * through cvmx_usb_register_callback is
- * called. If both are NULL, then there is no
- * way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- * callback is called. This is only used if
- * callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- * failure. Negative values are failure codes from
- * cvmx_usb_status_t.
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
+ * @pipe_handle:
+ * Handle to the pipe for the transfer.
+ * @start_frame:
+ * Number of frames into the future to schedule
+ * this transaction.
+ * @flags: Flags to control the transfer. See
+ * enum cvmx_usb_isochronous_flags for the flag
+ * definitions.
+ * @number_packets:
+ * Number of sequential packets to transfer.
+ * "packets" is a pointer to an array of this
+ * many packet structures.
+ * @packets: Description of each transfer packet as
+ * defined by struct cvmx_usb_iso_packet. The array
+ * pointed to here must stay valid until the
+ * complete callback is called.
+ * @buffer: Physical address of the data buffer in
+ * memory. Note that this is NOT A POINTER, but
+ * the full 64bit physical address of the
+ * buffer. This may be zero if buffer_length is
+ * zero.
+ * @buffer_length:
+ * Length of buffer in bytes.
+ * @callback: Function to call when this transaction
+ * completes. If the return value of this
+ * function isn't an error, then this function
+ * is guaranteed to be called when the
+ * transaction completes. If this parameter is
+ * NULL, then the generic callback registered
+ * through cvmx_usb_register_callback is
+ * called. If both are NULL, then there is no
+ * way to know when a transaction completes.
+ * @user_data: User supplied data returned when the
+ * callback is called. This is only used if
+ * callback in not NULL.
+ *
+ * Returns: A submitted transaction handle or negative on
+ * failure. Negative values are error codes.
*/
-int cvmx_usb_submit_isochronous(cvmx_usb_state_t *state, int pipe_handle,
- int start_frame, int flags,
- int number_packets,
- cvmx_usb_iso_packet_t packets[],
- uint64_t buffer, int buffer_length,
- cvmx_usb_callback_func_t callback,
- void *user_data)
+int cvmx_usb_submit_isochronous(struct cvmx_usb_state *state, int pipe_handle,
+ int start_frame, int flags,
+ int number_packets,
+ struct cvmx_usb_iso_packet packets[],
+ uint64_t buffer, int buffer_length,
+ cvmx_usb_callback_func_t callback,
+ void *user_data)
{
- int submit_handle;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- CVMX_USB_LOG_PARAM("%d", pipe_handle);
- CVMX_USB_LOG_PARAM("%d", start_frame);
- CVMX_USB_LOG_PARAM("0x%x", flags);
- CVMX_USB_LOG_PARAM("%d", number_packets);
- CVMX_USB_LOG_PARAM("%p", packets);
- CVMX_USB_LOG_PARAM("0x%llx", (unsigned long long)buffer);
- CVMX_USB_LOG_PARAM("%d", buffer_length);
-
- /* Pipe handle checking is done later in a common place */
- if (cvmx_unlikely(start_frame < 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(flags & ~(CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT | CVMX_USB_ISOCHRONOUS_FLAGS_ASAP)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(number_packets < 1))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(!packets))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(!buffer))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(buffer_length < 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
- CVMX_USB_TRANSFER_ISOCHRONOUS,
- flags,
- buffer,
- buffer_length,
- 0, /* control_header */
- start_frame,
- number_packets,
- packets,
- callback,
- user_data);
- CVMX_USB_RETURN(submit_handle);
+ int submit_handle;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+
+ /* Pipe handle checking is done later in a common place */
+ if (unlikely(start_frame < 0))
+ return -EINVAL;
+ if (unlikely(flags & ~(CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT | CVMX_USB_ISOCHRONOUS_FLAGS_ASAP)))
+ return -EINVAL;
+ if (unlikely(number_packets < 1))
+ return -EINVAL;
+ if (unlikely(!packets))
+ return -EINVAL;
+ if (unlikely(!buffer))
+ return -EINVAL;
+ if (unlikely(buffer_length < 0))
+ return -EINVAL;
+
+ submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
+ CVMX_USB_TRANSFER_ISOCHRONOUS,
+ flags,
+ buffer,
+ buffer_length,
+ 0, /* control_header */
+ start_frame,
+ number_packets,
+ packets,
+ callback,
+ user_data);
+ return submit_handle;
}
@@ -2525,63 +2440,58 @@ int cvmx_usb_submit_isochronous(cvmx_usb_state_t *state, int pipe_handle,
* a frame or two for the cvmx_usb_poll() function to call the
* associated callback.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Pipe handle to cancel requests in.
- * @param submit_handle
- * Handle to transaction to cancel, returned by the submit function.
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
+ * @pipe_handle:
+ * Pipe handle to cancel requests in.
+ * @submit_handle:
+ * Handle to transaction to cancel, returned by the submit function.
*
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
*/
-cvmx_usb_status_t cvmx_usb_cancel(cvmx_usb_state_t *state, int pipe_handle,
- int submit_handle)
+int cvmx_usb_cancel(struct cvmx_usb_state *state, int pipe_handle, int submit_handle)
{
- cvmx_usb_transaction_t *transaction;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
- cvmx_usb_pipe_t *pipe = usb->pipe + pipe_handle;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- CVMX_USB_LOG_PARAM("%d", pipe_handle);
- CVMX_USB_LOG_PARAM("%d", submit_handle);
-
- if (cvmx_unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely((submit_handle < 0) || (submit_handle >= MAX_TRANSACTIONS)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- /* Fail if the pipe isn't open */
- if (cvmx_unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- transaction = usb->transaction + submit_handle;
-
- /* Fail if this transaction already completed */
- if (cvmx_unlikely((transaction->flags & __CVMX_USB_TRANSACTION_FLAGS_IN_USE) == 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- /* If the transaction is the HEAD of the queue and scheduled. We need to
- treat it special */
- if ((pipe->head == transaction) &&
- (pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED)) {
- cvmx_usbcx_hccharx_t usbc_hcchar;
-
- usb->pipe_for_channel[pipe->channel] = NULL;
- pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED;
-
- CVMX_SYNCW;
-
- usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index));
- /* If the channel isn't enabled then the transaction already completed */
- if (usbc_hcchar.s.chena) {
- usbc_hcchar.s.chdis = 1;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index), usbc_hcchar.u32);
- }
- }
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_CANCEL);
- CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+ struct cvmx_usb_transaction *transaction;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+ struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
+
+ if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
+ return -EINVAL;
+ if (unlikely((submit_handle < 0) || (submit_handle >= MAX_TRANSACTIONS)))
+ return -EINVAL;
+
+ /* Fail if the pipe isn't open */
+ if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
+ return -EINVAL;
+
+ transaction = usb->transaction + submit_handle;
+
+ /* Fail if this transaction already completed */
+ if (unlikely((transaction->flags & __CVMX_USB_TRANSACTION_FLAGS_IN_USE) == 0))
+ return -EINVAL;
+
+ /*
+ * If the transaction is the HEAD of the queue and scheduled. We need to
+ * treat it special
+ */
+ if ((pipe->head == transaction) &&
+ (pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED)) {
+ union cvmx_usbcx_hccharx usbc_hcchar;
+
+ usb->pipe_for_channel[pipe->channel] = NULL;
+ pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED;
+
+ CVMX_SYNCW;
+
+ usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index));
+ /* If the channel isn't enabled then the transaction already completed */
+ if (usbc_hcchar.s.chena) {
+ usbc_hcchar.s.chdis = 1;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index), usbc_hcchar.u32);
+ }
+ }
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_CANCEL);
+ return 0;
}
@@ -2589,112 +2499,98 @@ cvmx_usb_status_t cvmx_usb_cancel(cvmx_usb_state_t *state, int pipe_handle,
* Cancel all outstanding requests in a pipe. Logically all this
* does is call cvmx_usb_cancel() in a loop.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Pipe handle to cancel requests in.
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
+ * @pipe_handle:
+ * Pipe handle to cancel requests in.
*
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
*/
-cvmx_usb_status_t cvmx_usb_cancel_all(cvmx_usb_state_t *state, int pipe_handle)
+int cvmx_usb_cancel_all(struct cvmx_usb_state *state, int pipe_handle)
{
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
- cvmx_usb_pipe_t *pipe = usb->pipe + pipe_handle;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- CVMX_USB_LOG_PARAM("%d", pipe_handle);
- if (cvmx_unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- /* Fail if the pipe isn't open */
- if (cvmx_unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- /* Simply loop through and attempt to cancel each transaction */
- while (pipe->head) {
- cvmx_usb_status_t result = cvmx_usb_cancel(state, pipe_handle,
- __cvmx_usb_get_submit_handle(usb, pipe->head));
- if (cvmx_unlikely(result != CVMX_USB_SUCCESS))
- CVMX_USB_RETURN(result);
- }
- CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+ struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
+
+ if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
+ return -EINVAL;
+
+ /* Fail if the pipe isn't open */
+ if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
+ return -EINVAL;
+
+ /* Simply loop through and attempt to cancel each transaction */
+ while (pipe->head) {
+ int result = cvmx_usb_cancel(state, pipe_handle,
+ __cvmx_usb_get_submit_handle(usb, pipe->head));
+ if (unlikely(result != 0))
+ return result;
+ }
+ return 0;
}
/**
* Close a pipe created with cvmx_usb_open_pipe().
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Pipe handle to close.
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
+ * @pipe_handle:
+ * Pipe handle to close.
*
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t. CVMX_USB_BUSY is returned if the
- * pipe has outstanding transfers.
+ * Returns: 0 or a negative error code. EBUSY is returned if the pipe has
+ * outstanding transfers.
*/
-cvmx_usb_status_t cvmx_usb_close_pipe(cvmx_usb_state_t *state, int pipe_handle)
+int cvmx_usb_close_pipe(struct cvmx_usb_state *state, int pipe_handle)
{
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
- cvmx_usb_pipe_t *pipe = usb->pipe + pipe_handle;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+ struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- CVMX_USB_LOG_PARAM("%d", pipe_handle);
- if (cvmx_unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+ if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
+ return -EINVAL;
- /* Fail if the pipe isn't open */
- if (cvmx_unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+ /* Fail if the pipe isn't open */
+ if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
+ return -EINVAL;
- /* Fail if the pipe has pending transactions */
- if (cvmx_unlikely(pipe->head))
- CVMX_USB_RETURN(CVMX_USB_BUSY);
+ /* Fail if the pipe has pending transactions */
+ if (unlikely(pipe->head))
+ return -EBUSY;
- pipe->flags = 0;
- __cvmx_usb_remove_pipe(&usb->idle_pipes, pipe);
- __cvmx_usb_append_pipe(&usb->free_pipes, pipe);
+ pipe->flags = 0;
+ __cvmx_usb_remove_pipe(&usb->idle_pipes, pipe);
+ __cvmx_usb_append_pipe(&usb->free_pipes, pipe);
- CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+ return 0;
}
/**
* Register a function to be called when various USB events occur.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param reason Which event to register for.
- * @param callback Function to call when the event occurs.
- * @param user_data User data parameter to the function.
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
+ * @reason: Which event to register for.
+ * @callback: Function to call when the event occurs.
+ * @user_data: User data parameter to the function.
*
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
*/
-cvmx_usb_status_t cvmx_usb_register_callback(cvmx_usb_state_t *state,
- cvmx_usb_callback_t reason,
- cvmx_usb_callback_func_t callback,
- void *user_data)
+int cvmx_usb_register_callback(struct cvmx_usb_state *state,
+ enum cvmx_usb_callback reason,
+ cvmx_usb_callback_func_t callback,
+ void *user_data)
{
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
- CVMX_USB_LOG_PARAM("%d", reason);
- CVMX_USB_LOG_PARAM("%p", callback);
- CVMX_USB_LOG_PARAM("%p", user_data);
- if (cvmx_unlikely(reason >= __CVMX_USB_CALLBACK_END))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
- if (cvmx_unlikely(!callback))
- CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
- usb->callback[reason] = callback;
- usb->callback_data[reason] = user_data;
-
- CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+
+ if (unlikely(reason >= __CVMX_USB_CALLBACK_END))
+ return -EINVAL;
+ if (unlikely(!callback))
+ return -EINVAL;
+
+ usb->callback[reason] = callback;
+ usb->callback_data[reason] = user_data;
+
+ return 0;
}
@@ -2702,428 +2598,457 @@ cvmx_usb_status_t cvmx_usb_register_callback(cvmx_usb_state_t *state,
* Get the current USB protocol level frame number. The frame
* number is always in the range of 0-0x7ff.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
*
- * @return USB frame number
+ * Returns: USB frame number
*/
-int cvmx_usb_get_frame_number(cvmx_usb_state_t *state)
+int cvmx_usb_get_frame_number(struct cvmx_usb_state *state)
{
- int frame_number;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
- cvmx_usbcx_hfnum_t usbc_hfnum;
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
+ int frame_number;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+ union cvmx_usbcx_hfnum usbc_hfnum;
- usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
- frame_number = usbc_hfnum.s.frnum;
+ usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
+ frame_number = usbc_hfnum.s.frnum;
- CVMX_USB_RETURN(frame_number);
+ return frame_number;
}
/**
- * @INTERNAL
* Poll a channel for status
*
- * @param usb USB device
- * @param channel Channel to poll
+ * @usb: USB device
+ * @channel: Channel to poll
*
- * @return Zero on success
+ * Returns: Zero on success
*/
-static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
+static int __cvmx_usb_poll_channel(struct cvmx_usb_internal_state *usb, int channel)
{
- cvmx_usbcx_hcintx_t usbc_hcint;
- cvmx_usbcx_hctsizx_t usbc_hctsiz;
- cvmx_usbcx_hccharx_t usbc_hcchar;
- cvmx_usb_pipe_t *pipe;
- cvmx_usb_transaction_t *transaction;
- int bytes_this_transfer;
- int bytes_in_last_packet;
- int packets_processed;
- int buffer_space_left;
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", usb);
- CVMX_USB_LOG_PARAM("%d", channel);
-
- /* Read the interrupt status bits for the channel */
- usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index));
-
- if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
- usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
-
- if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) {
- /* There seems to be a bug in CN31XX which can cause interrupt
- IN transfers to get stuck until we do a write of HCCHARX
- without changing things */
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
- CVMX_USB_RETURN(0);
- }
-
- /* In non DMA mode the channels don't halt themselves. We need to
- manually disable channels that are left running */
- if (!usbc_hcint.s.chhltd) {
- if (usbc_hcchar.s.chena) {
- cvmx_usbcx_hcintmskx_t hcintmsk;
- /* Disable all interrupts except CHHLTD */
- hcintmsk.u32 = 0;
- hcintmsk.s.chhltdmsk = 1;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), hcintmsk.u32);
- usbc_hcchar.s.chdis = 1;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
- CVMX_USB_RETURN(0);
- }
- else if (usbc_hcint.s.xfercompl) {
- /* Successful IN/OUT with transfer complete. Channel halt isn't needed */
- }
- else {
- cvmx_dprintf("USB%d: Channel %d interrupt without halt\n", usb->index, channel);
- CVMX_USB_RETURN(0);
- }
- }
- }
- else {
- /* There is are no interrupts that we need to process when the channel is
- still running */
- if (!usbc_hcint.s.chhltd)
- CVMX_USB_RETURN(0);
- }
-
- /* Disable the channel interrupts now that it is done */
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
- usb->idle_hardware_channels |= (1<<channel);
-
- /* Make sure this channel is tied to a valid pipe */
- pipe = usb->pipe_for_channel[channel];
- CVMX_PREFETCH(pipe, 0);
- CVMX_PREFETCH(pipe, 128);
- if (!pipe)
- CVMX_USB_RETURN(0);
- transaction = pipe->head;
- CVMX_PREFETCH0(transaction);
-
- /* Disconnect this pipe from the HW channel. Later the schedule function will
- figure out which pipe needs to go */
- usb->pipe_for_channel[channel] = NULL;
- pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED;
-
- /* Read the channel config info so we can figure out how much data
- transfered */
- usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
- usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
-
- /* Calculating the number of bytes successfully transferred is dependent on
- the transfer direction */
- packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt;
- if (usbc_hcchar.s.epdir) {
- /* IN transactions are easy. For every byte received the hardware
- decrements xfersize. All we need to do is subtract the current
- value of xfersize from its starting value and we know how many
- bytes were written to the buffer */
- bytes_this_transfer = transaction->xfersize - usbc_hctsiz.s.xfersize;
- }
- else {
- /* OUT transaction don't decrement xfersize. Instead pktcnt is
- decremented on every successful packet send. The hardware does
- this when it receives an ACK, or NYET. If it doesn't
- receive one of these responses pktcnt doesn't change */
- bytes_this_transfer = packets_processed * usbc_hcchar.s.mps;
- /* The last packet may not be a full transfer if we didn't have
- enough data */
- if (bytes_this_transfer > transaction->xfersize)
- bytes_this_transfer = transaction->xfersize;
- }
- /* Figure out how many bytes were in the last packet of the transfer */
- if (packets_processed)
- bytes_in_last_packet = bytes_this_transfer - (packets_processed-1) * usbc_hcchar.s.mps;
- else
- bytes_in_last_packet = bytes_this_transfer;
-
- /* As a special case, setup transactions output the setup header, not
- the user's data. For this reason we don't count setup data as bytes
- transferred */
- if ((transaction->stage == CVMX_USB_STAGE_SETUP) ||
- (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE))
- bytes_this_transfer = 0;
-
- /* Optional debug output */
- if (cvmx_unlikely((usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS) ||
- (pipe->flags & CVMX_USB_PIPE_FLAGS_DEBUG_TRANSFERS)))
- cvmx_dprintf("%s: Channel %d halted. Pipe %d transaction %d stage %d bytes=%d\n",
- __FUNCTION__, channel,
- __cvmx_usb_get_pipe_handle(usb, pipe),
- __cvmx_usb_get_submit_handle(usb, transaction),
- transaction->stage, bytes_this_transfer);
-
- /* Add the bytes transferred to the running total. It is important that
- bytes_this_transfer doesn't count any data that needs to be
- retransmitted */
- transaction->actual_bytes += bytes_this_transfer;
- if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
- buffer_space_left = transaction->iso_packets[0].length - transaction->actual_bytes;
- else
- buffer_space_left = transaction->buffer_length - transaction->actual_bytes;
-
- /* We need to remember the PID toggle state for the next transaction. The
- hardware already updated it for the next transaction */
- pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0);
-
- /* For high speed bulk out, assume the next transaction will need to do a
- ping before proceeding. If this isn't true the ACK processing below
- will clear this flag */
- if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
- (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
- (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
- pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
-
- if (usbc_hcint.s.stall) {
- /* STALL as a response means this transaction cannot be completed
- because the device can't process transactions. Tell the user. Any
- data that was transferred will be counted on the actual bytes
- transferred */
- pipe->pid_toggle = 0;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_STALL);
- }
- else if (usbc_hcint.s.xacterr) {
- /* We know at least one packet worked if we get a ACK or NAK. Reset the retry counter */
- if (usbc_hcint.s.nak || usbc_hcint.s.ack)
- transaction->retries = 0;
- transaction->retries++;
- if (transaction->retries > MAX_RETRIES) {
- /* XactErr as a response means the device signaled something wrong with
- the transfer. For example, PID toggle errors cause these */
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_XACTERR);
- }
- else {
- /* If this was a split then clear our split in progress marker */
- if (usb->active_split == transaction)
- usb->active_split = NULL;
- /* Rewind to the beginning of the transaction by anding off the
- split complete bit */
- transaction->stage &= ~1;
- pipe->split_sc_frame = -1;
- pipe->next_tx_frame += pipe->interval;
- if (pipe->next_tx_frame < usb->frame_number)
- pipe->next_tx_frame = usb->frame_number + pipe->interval -
- (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
- }
- }
- else if (usbc_hcint.s.bblerr)
- {
- /* Babble Error (BblErr) */
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_BABBLEERR);
- }
- else if (usbc_hcint.s.datatglerr)
- {
- /* We'll retry the exact same transaction again */
- transaction->retries++;
- }
- else if (usbc_hcint.s.nyet) {
- /* NYET as a response is only allowed in three cases: as a response to
- a ping, as a response to a split transaction, and as a response to
- a bulk out. The ping case is handled by hardware, so we only have
- splits and bulk out */
- if (!__cvmx_usb_pipe_needs_split(usb, pipe)) {
- transaction->retries = 0;
- /* If there is more data to go then we need to try again. Otherwise
- this transaction is complete */
- if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet))
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
- }
- else {
- /* Split transactions retry the split complete 4 times then rewind
- to the start split and do the entire transactions again */
- transaction->retries++;
- if ((transaction->retries & 0x3) == 0) {
- /* Rewind to the beginning of the transaction by anding off the
- split complete bit */
- transaction->stage &= ~1;
- pipe->split_sc_frame = -1;
- }
- }
- }
- else if (usbc_hcint.s.ack) {
- transaction->retries = 0;
- /* The ACK bit can only be checked after the other error bits. This is
- because a multi packet transfer may succeed in a number of packets
- and then get a different response on the last packet. In this case
- both ACK and the last response bit will be set. If none of the
- other response bits is set, then the last packet must have been an
- ACK */
-
- /* Since we got an ACK, we know we don't need to do a ping on this
- pipe */
- pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_NEED_PING;
-
- switch (transaction->type)
- {
- case CVMX_USB_TRANSFER_CONTROL:
- switch (transaction->stage)
- {
- case CVMX_USB_STAGE_NON_CONTROL:
- case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
- /* This should be impossible */
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
- break;
- case CVMX_USB_STAGE_SETUP:
- pipe->pid_toggle = 1;
- if (__cvmx_usb_pipe_needs_split(usb, pipe))
- transaction->stage = CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE;
- else {
- cvmx_usb_control_header_t *header = cvmx_phys_to_ptr(transaction->control_header);
- if (header->s.length)
- transaction->stage = CVMX_USB_STAGE_DATA;
- else
- transaction->stage = CVMX_USB_STAGE_STATUS;
- }
- break;
- case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
- {
- cvmx_usb_control_header_t *header = cvmx_phys_to_ptr(transaction->control_header);
- if (header->s.length)
- transaction->stage = CVMX_USB_STAGE_DATA;
- else
- transaction->stage = CVMX_USB_STAGE_STATUS;
- }
- break;
- case CVMX_USB_STAGE_DATA:
- if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
- transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
- /* For setup OUT data that are splits, the hardware
- doesn't appear to count transferred data. Here
- we manually update the data transferred */
- if (!usbc_hcchar.s.epdir) {
- if (buffer_space_left < pipe->max_packet)
- transaction->actual_bytes += buffer_space_left;
- else
- transaction->actual_bytes += pipe->max_packet;
- }
- }
- else if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
- pipe->pid_toggle = 1;
- transaction->stage = CVMX_USB_STAGE_STATUS;
- }
- break;
- case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
- if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
- pipe->pid_toggle = 1;
- transaction->stage = CVMX_USB_STAGE_STATUS;
- }
- else {
- transaction->stage = CVMX_USB_STAGE_DATA;
- }
- break;
- case CVMX_USB_STAGE_STATUS:
- if (__cvmx_usb_pipe_needs_split(usb, pipe))
- transaction->stage = CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE;
- else
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
- break;
- case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
- break;
- }
- break;
- case CVMX_USB_TRANSFER_BULK:
- case CVMX_USB_TRANSFER_INTERRUPT:
- /* The only time a bulk transfer isn't complete when
- it finishes with an ACK is during a split transaction. For
- splits we need to continue the transfer if more data is
- needed */
- if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
- if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL)
- transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
- else {
- if (buffer_space_left && (bytes_in_last_packet == pipe->max_packet))
- transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
- else {
- if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT)
- pipe->next_tx_frame += pipe->interval;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
- }
- }
- }
- else {
- if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
- (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
- (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
- (usbc_hcint.s.nak))
- pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
- if (!buffer_space_left || (bytes_in_last_packet < pipe->max_packet)) {
- if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT)
- pipe->next_tx_frame += pipe->interval;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
- }
- }
- break;
- case CVMX_USB_TRANSFER_ISOCHRONOUS:
- if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
- /* ISOCHRONOUS OUT splits don't require a complete split stage.
- Instead they use a sequence of begin OUT splits to transfer
- the data 188 bytes at a time. Once the transfer is complete,
- the pipe sleeps until the next schedule interval */
- if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
- /* If no space left or this wasn't a max size packet then
- this transfer is complete. Otherwise start it again
- to send the next 188 bytes */
- if (!buffer_space_left || (bytes_this_transfer < 188)) {
- pipe->next_tx_frame += pipe->interval;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
- }
- }
- else {
- if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
- /* We are in the incoming data phase. Keep getting
- data until we run out of space or get a small
- packet */
- if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
- pipe->next_tx_frame += pipe->interval;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
- }
- }
- else
- transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
- }
- }
- else {
- pipe->next_tx_frame += pipe->interval;
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
- }
- break;
- }
- }
- else if (usbc_hcint.s.nak) {
- /* If this was a split then clear our split in progress marker */
- if (usb->active_split == transaction)
- usb->active_split = NULL;
- /* NAK as a response means the device couldn't accept the transaction,
- but it should be retried in the future. Rewind to the beginning of
- the transaction by anding off the split complete bit. Retry in the
- next interval */
- transaction->retries = 0;
- transaction->stage &= ~1;
- pipe->next_tx_frame += pipe->interval;
- if (pipe->next_tx_frame < usb->frame_number)
- pipe->next_tx_frame = usb->frame_number + pipe->interval -
- (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
- }
- else {
- cvmx_usb_port_status_t port;
- port = cvmx_usb_get_status((cvmx_usb_state_t *)usb);
- if (port.port_enabled)
- {
- /* We'll retry the exact same transaction again */
- transaction->retries++;
- }
- else
- {
- /* We get channel halted interrupts with no result bits sets when the
- cable is unplugged */
- __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
- }
- }
- CVMX_USB_RETURN(0);
+ union cvmx_usbcx_hcintx usbc_hcint;
+ union cvmx_usbcx_hctsizx usbc_hctsiz;
+ union cvmx_usbcx_hccharx usbc_hcchar;
+ struct cvmx_usb_pipe *pipe;
+ struct cvmx_usb_transaction *transaction;
+ int bytes_this_transfer;
+ int bytes_in_last_packet;
+ int packets_processed;
+ int buffer_space_left;
+
+ /* Read the interrupt status bits for the channel */
+ usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index));
+
+ if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
+ usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
+
+ if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) {
+ /*
+ * There seems to be a bug in CN31XX which can cause
+ * interrupt IN transfers to get stuck until we do a
+ * write of HCCHARX without changing things
+ */
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
+ return 0;
+ }
+
+ /*
+ * In non DMA mode the channels don't halt themselves. We need
+ * to manually disable channels that are left running
+ */
+ if (!usbc_hcint.s.chhltd) {
+ if (usbc_hcchar.s.chena) {
+ union cvmx_usbcx_hcintmskx hcintmsk;
+ /* Disable all interrupts except CHHLTD */
+ hcintmsk.u32 = 0;
+ hcintmsk.s.chhltdmsk = 1;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), hcintmsk.u32);
+ usbc_hcchar.s.chdis = 1;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
+ return 0;
+ } else if (usbc_hcint.s.xfercompl) {
+ /* Successful IN/OUT with transfer complete. Channel halt isn't needed */
+ } else {
+ cvmx_dprintf("USB%d: Channel %d interrupt without halt\n", usb->index, channel);
+ return 0;
+ }
+ }
+ } else {
+ /*
+ * There is are no interrupts that we need to process when the
+ * channel is still running
+ */
+ if (!usbc_hcint.s.chhltd)
+ return 0;
+ }
+
+ /* Disable the channel interrupts now that it is done */
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
+ usb->idle_hardware_channels |= (1<<channel);
+
+ /* Make sure this channel is tied to a valid pipe */
+ pipe = usb->pipe_for_channel[channel];
+ CVMX_PREFETCH(pipe, 0);
+ CVMX_PREFETCH(pipe, 128);
+ if (!pipe)
+ return 0;
+ transaction = pipe->head;
+ CVMX_PREFETCH0(transaction);
+
+ /*
+ * Disconnect this pipe from the HW channel. Later the schedule
+ * function will figure out which pipe needs to go
+ */
+ usb->pipe_for_channel[channel] = NULL;
+ pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED;
+
+ /*
+ * Read the channel config info so we can figure out how much data
+ * transfered
+ */
+ usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
+ usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
+
+ /*
+ * Calculating the number of bytes successfully transferred is dependent
+ * on the transfer direction
+ */
+ packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt;
+ if (usbc_hcchar.s.epdir) {
+ /*
+ * IN transactions are easy. For every byte received the
+ * hardware decrements xfersize. All we need to do is subtract
+ * the current value of xfersize from its starting value and we
+ * know how many bytes were written to the buffer
+ */
+ bytes_this_transfer = transaction->xfersize - usbc_hctsiz.s.xfersize;
+ } else {
+ /*
+ * OUT transaction don't decrement xfersize. Instead pktcnt is
+ * decremented on every successful packet send. The hardware
+ * does this when it receives an ACK, or NYET. If it doesn't
+ * receive one of these responses pktcnt doesn't change
+ */
+ bytes_this_transfer = packets_processed * usbc_hcchar.s.mps;
+ /*
+ * The last packet may not be a full transfer if we didn't have
+ * enough data
+ */
+ if (bytes_this_transfer > transaction->xfersize)
+ bytes_this_transfer = transaction->xfersize;
+ }
+ /* Figure out how many bytes were in the last packet of the transfer */
+ if (packets_processed)
+ bytes_in_last_packet = bytes_this_transfer - (packets_processed-1) * usbc_hcchar.s.mps;
+ else
+ bytes_in_last_packet = bytes_this_transfer;
+
+ /*
+ * As a special case, setup transactions output the setup header, not
+ * the user's data. For this reason we don't count setup data as bytes
+ * transferred
+ */
+ if ((transaction->stage == CVMX_USB_STAGE_SETUP) ||
+ (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE))
+ bytes_this_transfer = 0;
+
+ /*
+ * Add the bytes transferred to the running total. It is important that
+ * bytes_this_transfer doesn't count any data that needs to be
+ * retransmitted
+ */
+ transaction->actual_bytes += bytes_this_transfer;
+ if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
+ buffer_space_left = transaction->iso_packets[0].length - transaction->actual_bytes;
+ else
+ buffer_space_left = transaction->buffer_length - transaction->actual_bytes;
+
+ /*
+ * We need to remember the PID toggle state for the next transaction.
+ * The hardware already updated it for the next transaction
+ */
+ pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0);
+
+ /*
+ * For high speed bulk out, assume the next transaction will need to do
+ * a ping before proceeding. If this isn't true the ACK processing below
+ * will clear this flag
+ */
+ if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
+ (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
+ (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
+ pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
+
+ if (usbc_hcint.s.stall) {
+ /*
+ * STALL as a response means this transaction cannot be
+ * completed because the device can't process transactions. Tell
+ * the user. Any data that was transferred will be counted on
+ * the actual bytes transferred
+ */
+ pipe->pid_toggle = 0;
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_STALL);
+ } else if (usbc_hcint.s.xacterr) {
+ /*
+ * We know at least one packet worked if we get a ACK or NAK.
+ * Reset the retry counter
+ */
+ if (usbc_hcint.s.nak || usbc_hcint.s.ack)
+ transaction->retries = 0;
+ transaction->retries++;
+ if (transaction->retries > MAX_RETRIES) {
+ /*
+ * XactErr as a response means the device signaled
+ * something wrong with the transfer. For example, PID
+ * toggle errors cause these
+ */
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_XACTERR);
+ } else {
+ /*
+ * If this was a split then clear our split in progress
+ * marker
+ */
+ if (usb->active_split == transaction)
+ usb->active_split = NULL;
+ /*
+ * Rewind to the beginning of the transaction by anding
+ * off the split complete bit
+ */
+ transaction->stage &= ~1;
+ pipe->split_sc_frame = -1;
+ pipe->next_tx_frame += pipe->interval;
+ if (pipe->next_tx_frame < usb->frame_number)
+ pipe->next_tx_frame = usb->frame_number + pipe->interval -
+ (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
+ }
+ } else if (usbc_hcint.s.bblerr) {
+ /* Babble Error (BblErr) */
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_BABBLEERR);
+ } else if (usbc_hcint.s.datatglerr) {
+ /* We'll retry the exact same transaction again */
+ transaction->retries++;
+ } else if (usbc_hcint.s.nyet) {
+ /*
+ * NYET as a response is only allowed in three cases: as a
+ * response to a ping, as a response to a split transaction, and
+ * as a response to a bulk out. The ping case is handled by
+ * hardware, so we only have splits and bulk out
+ */
+ if (!__cvmx_usb_pipe_needs_split(usb, pipe)) {
+ transaction->retries = 0;
+ /*
+ * If there is more data to go then we need to try
+ * again. Otherwise this transaction is complete
+ */
+ if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet))
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ } else {
+ /*
+ * Split transactions retry the split complete 4 times
+ * then rewind to the start split and do the entire
+ * transactions again
+ */
+ transaction->retries++;
+ if ((transaction->retries & 0x3) == 0) {
+ /*
+ * Rewind to the beginning of the transaction by
+ * anding off the split complete bit
+ */
+ transaction->stage &= ~1;
+ pipe->split_sc_frame = -1;
+ }
+ }
+ } else if (usbc_hcint.s.ack) {
+ transaction->retries = 0;
+ /*
+ * The ACK bit can only be checked after the other error bits.
+ * This is because a multi packet transfer may succeed in a
+ * number of packets and then get a different response on the
+ * last packet. In this case both ACK and the last response bit
+ * will be set. If none of the other response bits is set, then
+ * the last packet must have been an ACK
+ *
+ * Since we got an ACK, we know we don't need to do a ping on
+ * this pipe
+ */
+ pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_NEED_PING;
+
+ switch (transaction->type) {
+ case CVMX_USB_TRANSFER_CONTROL:
+ switch (transaction->stage) {
+ case CVMX_USB_STAGE_NON_CONTROL:
+ case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
+ /* This should be impossible */
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
+ break;
+ case CVMX_USB_STAGE_SETUP:
+ pipe->pid_toggle = 1;
+ if (__cvmx_usb_pipe_needs_split(usb, pipe))
+ transaction->stage = CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE;
+ else {
+ union cvmx_usb_control_header *header =
+ cvmx_phys_to_ptr(transaction->control_header);
+ if (header->s.length)
+ transaction->stage = CVMX_USB_STAGE_DATA;
+ else
+ transaction->stage = CVMX_USB_STAGE_STATUS;
+ }
+ break;
+ case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
+ {
+ union cvmx_usb_control_header *header =
+ cvmx_phys_to_ptr(transaction->control_header);
+ if (header->s.length)
+ transaction->stage = CVMX_USB_STAGE_DATA;
+ else
+ transaction->stage = CVMX_USB_STAGE_STATUS;
+ }
+ break;
+ case CVMX_USB_STAGE_DATA:
+ if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+ transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
+ /*
+ * For setup OUT data that are splits,
+ * the hardware doesn't appear to count
+ * transferred data. Here we manually
+ * update the data transferred
+ */
+ if (!usbc_hcchar.s.epdir) {
+ if (buffer_space_left < pipe->max_packet)
+ transaction->actual_bytes += buffer_space_left;
+ else
+ transaction->actual_bytes += pipe->max_packet;
+ }
+ } else if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
+ pipe->pid_toggle = 1;
+ transaction->stage = CVMX_USB_STAGE_STATUS;
+ }
+ break;
+ case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
+ if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
+ pipe->pid_toggle = 1;
+ transaction->stage = CVMX_USB_STAGE_STATUS;
+ } else {
+ transaction->stage = CVMX_USB_STAGE_DATA;
+ }
+ break;
+ case CVMX_USB_STAGE_STATUS:
+ if (__cvmx_usb_pipe_needs_split(usb, pipe))
+ transaction->stage = CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE;
+ else
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ break;
+ case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ break;
+ }
+ break;
+ case CVMX_USB_TRANSFER_BULK:
+ case CVMX_USB_TRANSFER_INTERRUPT:
+ /*
+ * The only time a bulk transfer isn't complete when it
+ * finishes with an ACK is during a split transaction.
+ * For splits we need to continue the transfer if more
+ * data is needed
+ */
+ if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+ if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL)
+ transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+ else {
+ if (buffer_space_left && (bytes_in_last_packet == pipe->max_packet))
+ transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+ else {
+ if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT)
+ pipe->next_tx_frame += pipe->interval;
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ }
+ }
+ } else {
+ if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
+ (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
+ (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+ (usbc_hcint.s.nak))
+ pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
+ if (!buffer_space_left || (bytes_in_last_packet < pipe->max_packet)) {
+ if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT)
+ pipe->next_tx_frame += pipe->interval;
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ }
+ }
+ break;
+ case CVMX_USB_TRANSFER_ISOCHRONOUS:
+ if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+ /*
+ * ISOCHRONOUS OUT splits don't require a
+ * complete split stage. Instead they use a
+ * sequence of begin OUT splits to transfer the
+ * data 188 bytes at a time. Once the transfer
+ * is complete, the pipe sleeps until the next
+ * schedule interval
+ */
+ if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
+ /*
+ * If no space left or this wasn't a max
+ * size packet then this transfer is
+ * complete. Otherwise start it again to
+ * send the next 188 bytes
+ */
+ if (!buffer_space_left || (bytes_this_transfer < 188)) {
+ pipe->next_tx_frame += pipe->interval;
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ }
+ } else {
+ if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
+ /*
+ * We are in the incoming data
+ * phase. Keep getting data
+ * until we run out of space or
+ * get a small packet
+ */
+ if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
+ pipe->next_tx_frame += pipe->interval;
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ }
+ } else
+ transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+ }
+ } else {
+ pipe->next_tx_frame += pipe->interval;
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+ }
+ break;
+ }
+ } else if (usbc_hcint.s.nak) {
+ /* If this was a split then clear our split in progress marker */
+ if (usb->active_split == transaction)
+ usb->active_split = NULL;
+ /*
+ * NAK as a response means the device couldn't accept the
+ * transaction, but it should be retried in the future. Rewind
+ * to the beginning of the transaction by anding off the split
+ * complete bit. Retry in the next interval
+ */
+ transaction->retries = 0;
+ transaction->stage &= ~1;
+ pipe->next_tx_frame += pipe->interval;
+ if (pipe->next_tx_frame < usb->frame_number)
+ pipe->next_tx_frame = usb->frame_number + pipe->interval -
+ (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
+ } else {
+ struct cvmx_usb_port_status port;
+ port = cvmx_usb_get_status((struct cvmx_usb_state *)usb);
+ if (port.port_enabled) {
+ /* We'll retry the exact same transaction again */
+ transaction->retries++;
+ } else {
+ /*
+ * We get channel halted interrupts with no result bits
+ * sets when the cable is unplugged
+ */
+ __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
+ }
+ }
+ return 0;
}
@@ -3133,97 +3058,101 @@ static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
* handler for the USB controller. It can also be called
* periodically in a loop for non-interrupt based operation.
*
- * @param state USB device state populated by
- * cvmx_usb_initialize().
+ * @state: USB device state populated by
+ * cvmx_usb_initialize().
*
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
*/
-cvmx_usb_status_t cvmx_usb_poll(cvmx_usb_state_t *state)
+int cvmx_usb_poll(struct cvmx_usb_state *state)
{
- cvmx_usbcx_hfnum_t usbc_hfnum;
- cvmx_usbcx_gintsts_t usbc_gintsts;
- cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-
- CVMX_PREFETCH(usb, 0);
- CVMX_PREFETCH(usb, 1*128);
- CVMX_PREFETCH(usb, 2*128);
- CVMX_PREFETCH(usb, 3*128);
- CVMX_PREFETCH(usb, 4*128);
-
- CVMX_USB_LOG_CALLED();
- CVMX_USB_LOG_PARAM("%p", state);
-
- /* Update the frame counter */
- usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
- if ((usb->frame_number&0x3fff) > usbc_hfnum.s.frnum)
- usb->frame_number += 0x4000;
- usb->frame_number &= ~0x3fffull;
- usb->frame_number |= usbc_hfnum.s.frnum;
-
- /* Read the pending interrupts */
- usbc_gintsts.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTSTS(usb->index));
-
- /* Clear the interrupts now that we know about them */
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32);
-
- if (usbc_gintsts.s.rxflvl) {
- /* RxFIFO Non-Empty (RxFLvl)
- Indicates that there is at least one packet pending to be read
- from the RxFIFO. */
- /* In DMA mode this is handled by hardware */
- if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
- __cvmx_usb_poll_rx_fifo(usb);
- }
- if (usbc_gintsts.s.ptxfemp || usbc_gintsts.s.nptxfemp) {
- /* Fill the Tx FIFOs when not in DMA mode */
- if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
- __cvmx_usb_poll_tx_fifo(usb);
- }
- if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) {
- cvmx_usbcx_hprt_t usbc_hprt;
- /* Disconnect Detected Interrupt (DisconnInt)
- Asserted when a device disconnect is detected. */
-
- /* Host Port Interrupt (PrtInt)
- The core sets this bit to indicate a change in port status of one
- of the O2P USB core ports in Host mode. The application must
- read the Host Port Control and Status (HPRT) register to
- determine the exact event that caused this interrupt. The
- application must clear the appropriate status bit in the Host Port
- Control and Status register to clear this bit. */
-
- /* Call the user's port callback */
- __cvmx_usb_perform_callback(usb, NULL, NULL,
- CVMX_USB_CALLBACK_PORT_CHANGED,
- CVMX_USB_COMPLETE_SUCCESS);
- /* Clear the port change bits */
- usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
- usbc_hprt.s.prtena = 0;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index), usbc_hprt.u32);
- }
- if (usbc_gintsts.s.hchint) {
- /* Host Channels Interrupt (HChInt)
- The core sets this bit to indicate that an interrupt is pending on
- one of the channels of the core (in Host mode). The application
- must read the Host All Channels Interrupt (HAINT) register to
- determine the exact number of the channel on which the
- interrupt occurred, and then read the corresponding Host
- Channel-n Interrupt (HCINTn) register to determine the exact
- cause of the interrupt. The application must clear the
- appropriate status bit in the HCINTn register to clear this bit. */
- cvmx_usbcx_haint_t usbc_haint;
- usbc_haint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINT(usb->index));
- while (usbc_haint.u32) {
- int channel;
- CVMX_CLZ(channel, usbc_haint.u32);
- channel = 31 - channel;
- __cvmx_usb_poll_channel(usb, channel);
- usbc_haint.u32 ^= 1<<channel;
- }
- }
-
- __cvmx_usb_schedule(usb, usbc_gintsts.s.sof);
-
- CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+ union cvmx_usbcx_hfnum usbc_hfnum;
+ union cvmx_usbcx_gintsts usbc_gintsts;
+ struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+
+ CVMX_PREFETCH(usb, 0);
+ CVMX_PREFETCH(usb, 1*128);
+ CVMX_PREFETCH(usb, 2*128);
+ CVMX_PREFETCH(usb, 3*128);
+ CVMX_PREFETCH(usb, 4*128);
+
+ /* Update the frame counter */
+ usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
+ if ((usb->frame_number&0x3fff) > usbc_hfnum.s.frnum)
+ usb->frame_number += 0x4000;
+ usb->frame_number &= ~0x3fffull;
+ usb->frame_number |= usbc_hfnum.s.frnum;
+
+ /* Read the pending interrupts */
+ usbc_gintsts.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTSTS(usb->index));
+
+ /* Clear the interrupts now that we know about them */
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32);
+
+ if (usbc_gintsts.s.rxflvl) {
+ /*
+ * RxFIFO Non-Empty (RxFLvl)
+ * Indicates that there is at least one packet pending to be
+ * read from the RxFIFO.
+ *
+ * In DMA mode this is handled by hardware
+ */
+ if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+ __cvmx_usb_poll_rx_fifo(usb);
+ }
+ if (usbc_gintsts.s.ptxfemp || usbc_gintsts.s.nptxfemp) {
+ /* Fill the Tx FIFOs when not in DMA mode */
+ if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+ __cvmx_usb_poll_tx_fifo(usb);
+ }
+ if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) {
+ union cvmx_usbcx_hprt usbc_hprt;
+ /*
+ * Disconnect Detected Interrupt (DisconnInt)
+ * Asserted when a device disconnect is detected.
+ *
+ * Host Port Interrupt (PrtInt)
+ * The core sets this bit to indicate a change in port status of
+ * one of the O2P USB core ports in Host mode. The application
+ * must read the Host Port Control and Status (HPRT) register to
+ * determine the exact event that caused this interrupt. The
+ * application must clear the appropriate status bit in the Host
+ * Port Control and Status register to clear this bit.
+ *
+ * Call the user's port callback
+ */
+ __cvmx_usb_perform_callback(usb, NULL, NULL,
+ CVMX_USB_CALLBACK_PORT_CHANGED,
+ CVMX_USB_COMPLETE_SUCCESS);
+ /* Clear the port change bits */
+ usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+ usbc_hprt.s.prtena = 0;
+ __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index), usbc_hprt.u32);
+ }
+ if (usbc_gintsts.s.hchint) {
+ /*
+ * Host Channels Interrupt (HChInt)
+ * The core sets this bit to indicate that an interrupt is
+ * pending on one of the channels of the core (in Host mode).
+ * The application must read the Host All Channels Interrupt
+ * (HAINT) register to determine the exact number of the channel
+ * on which the interrupt occurred, and then read the
+ * corresponding Host Channel-n Interrupt (HCINTn) register to
+ * determine the exact cause of the interrupt. The application
+ * must clear the appropriate status bit in the HCINTn register
+ * to clear this bit.
+ */
+ union cvmx_usbcx_haint usbc_haint;
+ usbc_haint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINT(usb->index));
+ while (usbc_haint.u32) {
+ int channel;
+ CVMX_CLZ(channel, usbc_haint.u32);
+ channel = 31 - channel;
+ __cvmx_usb_poll_channel(usb, channel);
+ usbc_haint.u32 ^= 1<<channel;
+ }
+ }
+
+ __cvmx_usb_schedule(usb, usbc_gintsts.s.sof);
+
+ return 0;
}
diff --git a/drivers/staging/octeon-usb/cvmx-usb.h b/drivers/staging/octeon-usb/cvmx-usb.h
index db9cc05e5d3..8bf36966ef1 100644
--- a/drivers/staging/octeon-usb/cvmx-usb.h
+++ b/drivers/staging/octeon-usb/cvmx-usb.h
@@ -39,8 +39,6 @@
/**
- * @file
- *
* "cvmx-usb.h" defines a set of low level USB functions to help
* developers create Octeon USB drivers for various operating
* systems. These functions provide a generic API to the Octeon
@@ -49,24 +47,24 @@
*
* At a high level the device driver needs to:
*
- * -# Call cvmx_usb_get_num_ports() to get the number of
- * supported ports.
- * -# Call cvmx_usb_initialize() for each Octeon USB port.
- * -# Enable the port using cvmx_usb_enable().
- * -# Either periodically, or in an interrupt handler, call
- * cvmx_usb_poll() to service USB events.
- * -# Manage pipes using cvmx_usb_open_pipe() and
- * cvmx_usb_close_pipe().
- * -# Manage transfers using cvmx_usb_submit_*() and
- * cvmx_usb_cancel*().
- * -# Shutdown USB on unload using cvmx_usb_shutdown().
+ * - Call cvmx_usb_get_num_ports() to get the number of
+ * supported ports.
+ * - Call cvmx_usb_initialize() for each Octeon USB port.
+ * - Enable the port using cvmx_usb_enable().
+ * - Either periodically, or in an interrupt handler, call
+ * cvmx_usb_poll() to service USB events.
+ * - Manage pipes using cvmx_usb_open_pipe() and
+ * cvmx_usb_close_pipe().
+ * - Manage transfers using cvmx_usb_submit_*() and
+ * cvmx_usb_cancel*().
+ * - Shutdown USB on unload using cvmx_usb_shutdown().
*
* To monitor USB status changes, the device driver must use
* cvmx_usb_register_callback() to register for events that it
* is interested in. Below are a few hints on successfully
* implementing a driver on top of this API.
*
- * <h2>Initialization</h2>
+ * == Initialization ==
*
* When a driver is first loaded, it is normally not necessary
* to bring up the USB port completely. Most operating systems
@@ -75,24 +73,24 @@
* initialize anything found, and then enable the hardware.
*
* In the probe phase you should:
- * -# Use cvmx_usb_get_num_ports() to determine the number of
- * USB port to be supported.
- * -# Allocate space for a cvmx_usb_state_t structure for each
- * port.
- * -# Tell the operating system about each port
+ * - Use cvmx_usb_get_num_ports() to determine the number of
+ * USB port to be supported.
+ * - Allocate space for a struct cvmx_usb_state for each
+ * port.
+ * - Tell the operating system about each port
*
* In the initialization phase you should:
- * -# Use cvmx_usb_initialize() on each port.
- * -# Do not call cvmx_usb_enable(). This leaves the USB port in
- * the disabled state until the operating system is ready.
+ * - Use cvmx_usb_initialize() on each port.
+ * - Do not call cvmx_usb_enable(). This leaves the USB port in
+ * the disabled state until the operating system is ready.
*
* Finally, in the enable phase you should:
- * -# Call cvmx_usb_enable() on the appropriate port.
- * -# Note that some operating system use a RESET instead of an
- * enable call. To implement RESET, you should call
- * cvmx_usb_disable() followed by cvmx_usb_enable().
+ * - Call cvmx_usb_enable() on the appropriate port.
+ * - Note that some operating system use a RESET instead of an
+ * enable call. To implement RESET, you should call
+ * cvmx_usb_disable() followed by cvmx_usb_enable().
*
- * <h2>Locking</h2>
+ * == Locking ==
*
* All of the functions in the cvmx-usb API assume exclusive
* access to the USB hardware and internal data structures. This
@@ -112,25 +110,24 @@
* take a lock to make sure that another core cannot call
* cvmx-usb.
*
- * <h2>Port callback</h2>
+ * == Port callback ==
*
* The port callback prototype needs to look as follows:
*
- * void port_callback(cvmx_usb_state_t *usb,
- * cvmx_usb_callback_t reason,
- * cvmx_usb_complete_t status,
+ * void port_callback(struct cvmx_usb_state *usb,
+ * enum cvmx_usb_callback reason,
+ * enum cvmx_usb_complete status,
* int pipe_handle,
* int submit_handle,
* int bytes_transferred,
* void *user_data);
- * - @b usb is the cvmx_usb_state_t for the port.
- * - @b reason will always be
- * CVMX_USB_CALLBACK_PORT_CHANGED.
- * - @b status will always be CVMX_USB_COMPLETE_SUCCESS.
- * - @b pipe_handle will always be -1.
- * - @b submit_handle will always be -1.
- * - @b bytes_transferred will always be 0.
- * - @b user_data is the void pointer originally passed along
+ * - "usb" is the struct cvmx_usb_state for the port.
+ * - "reason" will always be CVMX_USB_CALLBACK_PORT_CHANGED.
+ * - "status" will always be CVMX_USB_COMPLETE_SUCCESS.
+ * - "pipe_handle" will always be -1.
+ * - "submit_handle" will always be -1.
+ * - "bytes_transferred" will always be 0.
+ * - "user_data" is the void pointer originally passed along
* with the callback. Use this for any state information you
* need.
*
@@ -140,45 +137,43 @@
* root port. Normally all the callback needs to do is tell the
* operating system to poll the root hub for status. Under
* Linux, this is performed by calling usb_hcd_poll_rh_status().
- * In the Linux driver we use @b user_data. to pass around the
+ * In the Linux driver we use "user_data". to pass around the
* Linux "hcd" structure. Once the port callback completes,
* Linux automatically calls octeon_usb_hub_status_data() which
* uses cvmx_usb_get_status() to determine the root port status.
*
- * <h2>Complete callback</h2>
+ * == Complete callback ==
*
* The completion callback prototype needs to look as follows:
*
- * void complete_callback(cvmx_usb_state_t *usb,
- * cvmx_usb_callback_t reason,
- * cvmx_usb_complete_t status,
+ * void complete_callback(struct cvmx_usb_state *usb,
+ * enum cvmx_usb_callback reason,
+ * enum cvmx_usb_complete status,
* int pipe_handle,
* int submit_handle,
* int bytes_transferred,
* void *user_data);
- * - @b usb is the cvmx_usb_state_t for the port.
- * - @b reason will always be
- * CVMX_USB_CALLBACK_TRANSFER_COMPLETE.
- * - @b status will be one of the cvmx_usb_complete_t
- * enumerations.
- * - @b pipe_handle is the handle to the pipe the transaction
+ * - "usb" is the struct cvmx_usb_state for the port.
+ * - "reason" will always be CVMX_USB_CALLBACK_TRANSFER_COMPLETE.
+ * - "status" will be one of the cvmx_usb_complete enumerations.
+ * - "pipe_handle" is the handle to the pipe the transaction
* was originally submitted on.
- * - @b submit_handle is the handle returned by the original
+ * - "submit_handle" is the handle returned by the original
* cvmx_usb_submit_* call.
- * - @b bytes_transferred is the number of bytes successfully
+ * - "bytes_transferred" is the number of bytes successfully
* transferred in the transaction. This will be zero on most
* error conditions.
- * - @b user_data is the void pointer originally passed along
+ * - "user_data" is the void pointer originally passed along
* with the callback. Use this for any state information you
* need. For example, the Linux "urb" is stored in here in the
* Linux driver.
*
- * In general your callback handler should use @b status and @b
- * bytes_transferred to tell the operating system the how the
+ * In general your callback handler should use "status" and
+ * "bytes_transferred" to tell the operating system the how the
* transaction completed. Normally the pipe is not changed in
* this callback.
*
- * <h2>Canceling transactions</h2>
+ * == Canceling transactions ==
*
* When a transaction is cancelled using cvmx_usb_cancel*(), the
* actual length of time until the complete callback is called
@@ -188,7 +183,7 @@
* these cases, the complete handler will receive
* CVMX_USB_COMPLETE_CANCEL.
*
- * <h2>Handling pipes</h2>
+ * == Handling pipes ==
*
* USB "pipes" is a software construct created by this API to
* enable the ordering of usb transactions to a device endpoint.
@@ -210,223 +205,16 @@
* destroy a pipe for every transaction. A sequence of
* transaction to the same endpoint must use the same pipe.
*
- * <h2>Root Hub</h2>
+ * == Root Hub ==
*
* Some operating systems view the usb root port as a normal usb
* hub. These systems attempt to control the root hub with
* messages similar to the usb 2.0 spec for hub control and
* status. For these systems it may be necessary to write
* function to decode standard usb control messages into
- * equivalent cvmx-usb API calls. As an example, the following
- * code is used under Linux for some of the basic hub control
- * messages.
- *
- * @code
- * static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
- * {
- * cvmx_usb_state_t *usb = (cvmx_usb_state_t *)hcd->hcd_priv;
- * cvmx_usb_port_status_t usb_port_status;
- * int port_status;
- * struct usb_hub_descriptor *desc;
- * unsigned long flags;
- *
- * switch (typeReq)
- * {
- * case ClearHubFeature:
- * DEBUG_ROOT_HUB("OcteonUSB: ClearHubFeature\n");
- * switch (wValue)
- * {
- * case C_HUB_LOCAL_POWER:
- * case C_HUB_OVER_CURRENT:
- * // Nothing required here
- * break;
- * default:
- * return -EINVAL;
- * }
- * break;
- * case ClearPortFeature:
- * DEBUG_ROOT_HUB("OcteonUSB: ClearPortFeature");
- * if (wIndex != 1)
- * {
- * DEBUG_ROOT_HUB(" INVALID\n");
- * return -EINVAL;
- * }
- *
- * switch (wValue)
- * {
- * case USB_PORT_FEAT_ENABLE:
- * DEBUG_ROOT_HUB(" ENABLE");
- * local_irq_save(flags);
- * cvmx_usb_disable(usb);
- * local_irq_restore(flags);
- * break;
- * case USB_PORT_FEAT_SUSPEND:
- * DEBUG_ROOT_HUB(" SUSPEND");
- * // Not supported on Octeon
- * break;
- * case USB_PORT_FEAT_POWER:
- * DEBUG_ROOT_HUB(" POWER");
- * // Not supported on Octeon
- * break;
- * case USB_PORT_FEAT_INDICATOR:
- * DEBUG_ROOT_HUB(" INDICATOR");
- * // Port inidicator not supported
- * break;
- * case USB_PORT_FEAT_C_CONNECTION:
- * DEBUG_ROOT_HUB(" C_CONNECTION");
- * // Clears drivers internal connect status change flag
- * cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
- * break;
- * case USB_PORT_FEAT_C_RESET:
- * DEBUG_ROOT_HUB(" C_RESET");
- * // Clears the driver's internal Port Reset Change flag
- * cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
- * break;
- * case USB_PORT_FEAT_C_ENABLE:
- * DEBUG_ROOT_HUB(" C_ENABLE");
- * // Clears the driver's internal Port Enable/Disable Change flag
- * cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
- * break;
- * case USB_PORT_FEAT_C_SUSPEND:
- * DEBUG_ROOT_HUB(" C_SUSPEND");
- * // Clears the driver's internal Port Suspend Change flag,
- * which is set when resume signaling on the host port is
- * complete
- * break;
- * case USB_PORT_FEAT_C_OVER_CURRENT:
- * DEBUG_ROOT_HUB(" C_OVER_CURRENT");
- * // Clears the driver's overcurrent Change flag
- * cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
- * break;
- * default:
- * DEBUG_ROOT_HUB(" UNKNOWN\n");
- * return -EINVAL;
- * }
- * DEBUG_ROOT_HUB("\n");
- * break;
- * case GetHubDescriptor:
- * DEBUG_ROOT_HUB("OcteonUSB: GetHubDescriptor\n");
- * desc = (struct usb_hub_descriptor *)buf;
- * desc->bDescLength = 9;
- * desc->bDescriptorType = 0x29;
- * desc->bNbrPorts = 1;
- * desc->wHubCharacteristics = 0x08;
- * desc->bPwrOn2PwrGood = 1;
- * desc->bHubContrCurrent = 0;
- * desc->bitmap[0] = 0;
- * desc->bitmap[1] = 0xff;
- * break;
- * case GetHubStatus:
- * DEBUG_ROOT_HUB("OcteonUSB: GetHubStatus\n");
- * *(__le32 *)buf = 0;
- * break;
- * case GetPortStatus:
- * DEBUG_ROOT_HUB("OcteonUSB: GetPortStatus");
- * if (wIndex != 1)
- * {
- * DEBUG_ROOT_HUB(" INVALID\n");
- * return -EINVAL;
- * }
- *
- * usb_port_status = cvmx_usb_get_status(usb);
- * port_status = 0;
- *
- * if (usb_port_status.connect_change)
- * {
- * port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
- * DEBUG_ROOT_HUB(" C_CONNECTION");
- * }
- *
- * if (usb_port_status.port_enabled)
- * {
- * port_status |= (1 << USB_PORT_FEAT_C_ENABLE);
- * DEBUG_ROOT_HUB(" C_ENABLE");
- * }
- *
- * if (usb_port_status.connected)
- * {
- * port_status |= (1 << USB_PORT_FEAT_CONNECTION);
- * DEBUG_ROOT_HUB(" CONNECTION");
- * }
- *
- * if (usb_port_status.port_enabled)
- * {
- * port_status |= (1 << USB_PORT_FEAT_ENABLE);
- * DEBUG_ROOT_HUB(" ENABLE");
- * }
+ * equivalent cvmx-usb API calls.
*
- * if (usb_port_status.port_over_current)
- * {
- * port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT);
- * DEBUG_ROOT_HUB(" OVER_CURRENT");
- * }
- *
- * if (usb_port_status.port_powered)
- * {
- * port_status |= (1 << USB_PORT_FEAT_POWER);
- * DEBUG_ROOT_HUB(" POWER");
- * }
- *
- * if (usb_port_status.port_speed == CVMX_USB_SPEED_HIGH)
- * {
- * port_status |= (1 << USB_PORT_FEAT_HIGHSPEED);
- * DEBUG_ROOT_HUB(" HIGHSPEED");
- * }
- * else if (usb_port_status.port_speed == CVMX_USB_SPEED_LOW)
- * {
- * port_status |= (1 << USB_PORT_FEAT_LOWSPEED);
- * DEBUG_ROOT_HUB(" LOWSPEED");
- * }
- *
- * *((__le32 *)buf) = cpu_to_le32(port_status);
- * DEBUG_ROOT_HUB("\n");
- * break;
- * case SetHubFeature:
- * DEBUG_ROOT_HUB("OcteonUSB: SetHubFeature\n");
- * // No HUB features supported
- * break;
- * case SetPortFeature:
- * DEBUG_ROOT_HUB("OcteonUSB: SetPortFeature");
- * if (wIndex != 1)
- * {
- * DEBUG_ROOT_HUB(" INVALID\n");
- * return -EINVAL;
- * }
- *
- * switch (wValue)
- * {
- * case USB_PORT_FEAT_SUSPEND:
- * DEBUG_ROOT_HUB(" SUSPEND\n");
- * return -EINVAL;
- * case USB_PORT_FEAT_POWER:
- * DEBUG_ROOT_HUB(" POWER\n");
- * return -EINVAL;
- * case USB_PORT_FEAT_RESET:
- * DEBUG_ROOT_HUB(" RESET\n");
- * local_irq_save(flags);
- * cvmx_usb_disable(usb);
- * if (cvmx_usb_enable(usb))
- * DEBUG_ERROR("Failed to enable the port\n");
- * local_irq_restore(flags);
- * return 0;
- * case USB_PORT_FEAT_INDICATOR:
- * DEBUG_ROOT_HUB(" INDICATOR\n");
- * // Not supported
- * break;
- * default:
- * DEBUG_ROOT_HUB(" UNKNOWN\n");
- * return -EINVAL;
- * }
- * break;
- * default:
- * DEBUG_ROOT_HUB("OcteonUSB: Unknown root hub request\n");
- * return -EINVAL;
- * }
- * return 0;
- * }
- * @endcode
- *
- * <h2>Interrupts</h2>
+ * == Interrupts ==
*
* If you plan on using usb interrupts, cvmx_usb_poll() must be
* called on every usb interrupt. It will read the usb state,
@@ -441,154 +229,187 @@
*
* If you aren't using interrupts, simple call cvmx_usb_poll()
* in your main processing loop.
- *
- * <hr>$Revision: 32636 $<hr>
*/
#ifndef __CVMX_USB_H__
#define __CVMX_USB_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Enumerations representing the status of function calls.
- */
-typedef enum
-{
- CVMX_USB_SUCCESS = 0, /**< There were no errors */
- CVMX_USB_INVALID_PARAM = -1, /**< A parameter to the function was invalid */
- CVMX_USB_NO_MEMORY = -2, /**< Insufficient resources were available for the request */
- CVMX_USB_BUSY = -3, /**< The resource is busy and cannot service the request */
- CVMX_USB_TIMEOUT = -4, /**< Waiting for an action timed out */
- CVMX_USB_INCORRECT_MODE = -5, /**< The function call doesn't work in the current USB
- mode. This happens when host only functions are
- called in device mode or vice versa */
-} cvmx_usb_status_t;
-
-/**
- * Enumerations representing the possible USB device speeds
- */
-typedef enum
-{
- CVMX_USB_SPEED_HIGH = 0, /**< Device is operation at 480Mbps */
- CVMX_USB_SPEED_FULL = 1, /**< Device is operation at 12Mbps */
- CVMX_USB_SPEED_LOW = 2, /**< Device is operation at 1.5Mbps */
-} cvmx_usb_speed_t;
-
/**
- * Enumeration representing the possible USB transfer types.
- */
-typedef enum
-{
- CVMX_USB_TRANSFER_CONTROL = 0, /**< USB transfer type control for hub and status transfers */
- CVMX_USB_TRANSFER_ISOCHRONOUS = 1, /**< USB transfer type isochronous for low priority periodic transfers */
- CVMX_USB_TRANSFER_BULK = 2, /**< USB transfer type bulk for large low priority transfers */
- CVMX_USB_TRANSFER_INTERRUPT = 3, /**< USB transfer type interrupt for high priority periodic transfers */
-} cvmx_usb_transfer_t;
-
-/**
- * Enumeration of the transfer directions
- */
-typedef enum
-{
- CVMX_USB_DIRECTION_OUT, /**< Data is transferring from Octeon to the device/host */
- CVMX_USB_DIRECTION_IN, /**< Data is transferring from the device/host to Octeon */
-} cvmx_usb_direction_t;
-
-/**
- * Enumeration of all possible status codes passed to callback
- * functions.
- */
-typedef enum
-{
- CVMX_USB_COMPLETE_SUCCESS, /**< The transaction / operation finished without any errors */
- CVMX_USB_COMPLETE_SHORT, /**< FIXME: This is currently not implemented */
- CVMX_USB_COMPLETE_CANCEL, /**< The transaction was canceled while in flight by a user call to cvmx_usb_cancel* */
- CVMX_USB_COMPLETE_ERROR, /**< The transaction aborted with an unexpected error status */
- CVMX_USB_COMPLETE_STALL, /**< The transaction received a USB STALL response from the device */
- CVMX_USB_COMPLETE_XACTERR, /**< The transaction failed with an error from the device even after a number of retries */
- CVMX_USB_COMPLETE_DATATGLERR, /**< The transaction failed with a data toggle error even after a number of retries */
- CVMX_USB_COMPLETE_BABBLEERR, /**< The transaction failed with a babble error */
- CVMX_USB_COMPLETE_FRAMEERR, /**< The transaction failed with a frame error even after a number of retries */
-} cvmx_usb_complete_t;
-
-/**
- * Structure returned containing the USB port status information.
- */
-typedef struct
-{
- uint32_t reserved : 25;
- uint32_t port_enabled : 1; /**< 1 = Usb port is enabled, 0 = disabled */
- uint32_t port_over_current : 1; /**< 1 = Over current detected, 0 = Over current not detected. Octeon doesn't support over current detection */
- uint32_t port_powered : 1; /**< 1 = Port power is being supplied to the device, 0 = power is off. Octeon doesn't support turning port power off */
- cvmx_usb_speed_t port_speed : 2; /**< Current port speed */
- uint32_t connected : 1; /**< 1 = A device is connected to the port, 0 = No device is connected */
- uint32_t connect_change : 1; /**< 1 = Device connected state changed since the last set status call */
-} cvmx_usb_port_status_t;
-
-/**
- * This is the structure of a Control packet header
- */
-typedef union
-{
- uint64_t u64;
- struct
- {
- uint64_t request_type : 8; /**< Bit 7 tells the direction: 1=IN, 0=OUT */
- uint64_t request : 8; /**< The standard usb request to make */
- uint64_t value : 16; /**< Value parameter for the request in little endian format */
- uint64_t index : 16; /**< Index for the request in little endian format */
- uint64_t length : 16; /**< Length of the data associated with this request in little endian format */
- } s;
-} cvmx_usb_control_header_t;
-
-/**
- * Descriptor for Isochronous packets
- */
-typedef struct
-{
- int offset; /**< This is the offset in bytes into the main buffer where this data is stored */
- int length; /**< This is the length in bytes of the data */
- cvmx_usb_complete_t status; /**< This is the status of this individual packet transfer */
-} cvmx_usb_iso_packet_t;
-
-/**
- * Possible callback reasons for the USB API.
- */
-typedef enum
-{
- CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
- /**< A callback of this type is called when a submitted transfer
- completes. The completion callback will be called even if the
- transfer fails or is canceled. The status parameter will
- contain details of why he callback was called. */
- CVMX_USB_CALLBACK_PORT_CHANGED, /**< The status of the port changed. For example, someone may have
- plugged a device in. The status parameter contains
- CVMX_USB_COMPLETE_SUCCESS. Use cvmx_usb_get_status() to get
- the new port status. */
- __CVMX_USB_CALLBACK_END /**< Do not use. Used internally for array bounds */
-} cvmx_usb_callback_t;
+ * enum cvmx_usb_speed - the possible USB device speeds
+ *
+ * @CVMX_USB_SPEED_HIGH: Device is operation at 480Mbps
+ * @CVMX_USB_SPEED_FULL: Device is operation at 12Mbps
+ * @CVMX_USB_SPEED_LOW: Device is operation at 1.5Mbps
+ */
+enum cvmx_usb_speed {
+ CVMX_USB_SPEED_HIGH = 0,
+ CVMX_USB_SPEED_FULL = 1,
+ CVMX_USB_SPEED_LOW = 2,
+};
+
+/**
+ * enum cvmx_usb_transfer - the possible USB transfer types
+ *
+ * @CVMX_USB_TRANSFER_CONTROL: USB transfer type control for hub and status
+ * transfers
+ * @CVMX_USB_TRANSFER_ISOCHRONOUS: USB transfer type isochronous for low
+ * priority periodic transfers
+ * @CVMX_USB_TRANSFER_BULK: USB transfer type bulk for large low priority
+ * transfers
+ * @CVMX_USB_TRANSFER_INTERRUPT: USB transfer type interrupt for high priority
+ * periodic transfers
+ */
+enum cvmx_usb_transfer {
+ CVMX_USB_TRANSFER_CONTROL = 0,
+ CVMX_USB_TRANSFER_ISOCHRONOUS = 1,
+ CVMX_USB_TRANSFER_BULK = 2,
+ CVMX_USB_TRANSFER_INTERRUPT = 3,
+};
+
+/**
+ * enum cvmx_usb_direction - the transfer directions
+ *
+ * @CVMX_USB_DIRECTION_OUT: Data is transferring from Octeon to the device/host
+ * @CVMX_USB_DIRECTION_IN: Data is transferring from the device/host to Octeon
+ */
+enum cvmx_usb_direction {
+ CVMX_USB_DIRECTION_OUT,
+ CVMX_USB_DIRECTION_IN,
+};
+
+/**
+ * enum cvmx_usb_complete - possible callback function status codes
+ *
+ * @CVMX_USB_COMPLETE_SUCCESS: The transaction / operation finished without
+ * any errors
+ * @CVMX_USB_COMPLETE_SHORT: FIXME: This is currently not implemented
+ * @CVMX_USB_COMPLETE_CANCEL: The transaction was canceled while in flight by
+ * a user call to cvmx_usb_cancel
+ * @CVMX_USB_COMPLETE_ERROR: The transaction aborted with an unexpected
+ * error status
+ * @CVMX_USB_COMPLETE_STALL: The transaction received a USB STALL response
+ * from the device
+ * @CVMX_USB_COMPLETE_XACTERR: The transaction failed with an error from the
+ * device even after a number of retries
+ * @CVMX_USB_COMPLETE_DATATGLERR: The transaction failed with a data toggle
+ * error even after a number of retries
+ * @CVMX_USB_COMPLETE_BABBLEERR: The transaction failed with a babble error
+ * @CVMX_USB_COMPLETE_FRAMEERR: The transaction failed with a frame error
+ * even after a number of retries
+ */
+enum cvmx_usb_complete {
+ CVMX_USB_COMPLETE_SUCCESS,
+ CVMX_USB_COMPLETE_SHORT,
+ CVMX_USB_COMPLETE_CANCEL,
+ CVMX_USB_COMPLETE_ERROR,
+ CVMX_USB_COMPLETE_STALL,
+ CVMX_USB_COMPLETE_XACTERR,
+ CVMX_USB_COMPLETE_DATATGLERR,
+ CVMX_USB_COMPLETE_BABBLEERR,
+ CVMX_USB_COMPLETE_FRAMEERR,
+};
+
+/**
+ * struct cvmx_usb_port_status - the USB port status information
+ *
+ * @port_enabled: 1 = Usb port is enabled, 0 = disabled
+ * @port_over_current: 1 = Over current detected, 0 = Over current not
+ * detected. Octeon doesn't support over current detection.
+ * @port_powered: 1 = Port power is being supplied to the device, 0 =
+ * power is off. Octeon doesn't support turning port power
+ * off.
+ * @port_speed: Current port speed.
+ * @connected: 1 = A device is connected to the port, 0 = No device is
+ * connected.
+ * @connect_change: 1 = Device connected state changed since the last set
+ * status call.
+ */
+struct cvmx_usb_port_status {
+ uint32_t reserved : 25;
+ uint32_t port_enabled : 1;
+ uint32_t port_over_current : 1;
+ uint32_t port_powered : 1;
+ enum cvmx_usb_speed port_speed : 2;
+ uint32_t connected : 1;
+ uint32_t connect_change : 1;
+};
+
+/**
+ * union cvmx_usb_control_header - the structure of a Control packet header
+ *
+ * @s.request_type: Bit 7 tells the direction: 1=IN, 0=OUT
+ * @s.request The standard usb request to make
+ * @s.value Value parameter for the request in little endian format
+ * @s.index Index for the request in little endian format
+ * @s.length Length of the data associated with this request in
+ * little endian format
+ */
+union cvmx_usb_control_header {
+ uint64_t u64;
+ struct {
+ uint64_t request_type : 8;
+ uint64_t request : 8;
+ uint64_t value : 16;
+ uint64_t index : 16;
+ uint64_t length : 16;
+ } s;
+};
+
+/**
+ * struct cvmx_usb_iso_packet - descriptor for Isochronous packets
+ *
+ * @offset: This is the offset in bytes into the main buffer where this data
+ * is stored.
+ * @length: This is the length in bytes of the data.
+ * @status: This is the status of this individual packet transfer.
+ */
+struct cvmx_usb_iso_packet {
+ int offset;
+ int length;
+ enum cvmx_usb_complete status;
+};
+
+/**
+ * enum cvmx_usb_callback - possible callback reasons for the USB API
+ *
+ * @CVMX_USB_CALLBACK_TRANSFER_COMPLETE: A callback of this type is called when
+ * a submitted transfer completes. The
+ * completion callback will be called even
+ * if the transfer fails or is canceled.
+ * The status parameter will contain
+ * details of why he callback was called.
+ * @CVMX_USB_CALLBACK_PORT_CHANGED: The status of the port changed. For
+ * example, someone may have plugged a
+ * device in. The status parameter
+ * contains CVMX_USB_COMPLETE_SUCCESS. Use
+ * cvmx_usb_get_status() to get the new
+ * port status.
+ * @__CVMX_USB_CALLBACK_END: Do not use. Used internally for array
+ * bounds.
+ */
+enum cvmx_usb_callback {
+ CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
+ CVMX_USB_CALLBACK_PORT_CHANGED,
+ __CVMX_USB_CALLBACK_END
+};
/**
* USB state internal data. The contents of this structure
* may change in future SDKs. No data in it should be referenced
* by user's of this API.
*/
-typedef struct
-{
- char data[65536];
-} cvmx_usb_state_t;
+struct cvmx_usb_state {
+ char data[65536];
+};
/**
* USB callback functions are always of the following type.
* The parameters are as follows:
* - state = USB device state populated by
* cvmx_usb_initialize().
- * - reason = The cvmx_usb_callback_t used to register
+ * - reason = The enum cvmx_usb_callback used to register
* the callback.
- * - status = The cvmx_usb_complete_t representing the
+ * - status = The enum cvmx_usb_complete representing the
* status code of a transaction.
* - pipe_handle = The Pipe that caused this callback, or
* -1 if this callback wasn't associated with a pipe.
@@ -599,487 +420,123 @@ typedef struct
* - user_data = The user pointer supplied to the
* function cvmx_usb_submit() or
* cvmx_usb_register_callback() */
-typedef void (*cvmx_usb_callback_func_t)(cvmx_usb_state_t *state,
- cvmx_usb_callback_t reason,
- cvmx_usb_complete_t status,
+typedef void (*cvmx_usb_callback_func_t)(struct cvmx_usb_state *state,
+ enum cvmx_usb_callback reason,
+ enum cvmx_usb_complete status,
int pipe_handle, int submit_handle,
int bytes_transferred, void *user_data);
/**
- * Flags to pass the initialization function.
- */
-typedef enum
-{
- CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI = 1<<0, /**< The USB port uses a 12MHz crystal as clock source
- at USB_XO and USB_XI. */
- CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND = 1<<1, /**< The USB port uses 12/24/48MHz 2.5V board clock
- source at USB_XO. USB_XI should be tied to GND.*/
- CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO = 0, /**< Automatically determine clock type based on function
- in cvmx-helper-board.c. */
- CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK = 3<<3, /**< Mask for clock speed field */
- CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ = 1<<3, /**< Speed of reference clock or crystal */
- CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ = 2<<3, /**< Speed of reference clock */
- CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ = 3<<3, /**< Speed of reference clock */
- /* Bits 3-4 used to encode the clock frequency */
- CVMX_USB_INITIALIZE_FLAGS_NO_DMA = 1<<5, /**< Disable DMA and used polled IO for data transfer use for the USB */
- CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS = 1<<16, /**< Enable extra console output for debugging USB transfers */
- CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLBACKS = 1<<17, /**< Enable extra console output for debugging USB callbacks */
- CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO = 1<<18, /**< Enable extra console output for USB informational data */
- CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS = 1<<19, /**< Enable extra console output for every function call */
- CVMX_USB_INITIALIZE_FLAGS_DEBUG_CSRS = 1<<20, /**< Enable extra console output for every CSR access */
- CVMX_USB_INITIALIZE_FLAGS_DEBUG_ALL = ((CVMX_USB_INITIALIZE_FLAGS_DEBUG_CSRS<<1)-1) - (CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS-1),
-} cvmx_usb_initialize_flags_t;
+ * enum cvmx_usb_initialize_flags - flags to pass the initialization function
+ *
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI: The USB port uses a 12MHz crystal
+ * as clock source at USB_XO and
+ * USB_XI.
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND: The USB port uses 12/24/48MHz 2.5V
+ * board clock source at USB_XO.
+ * USB_XI should be tied to GND.
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO: Automatically determine clock type
+ * based on function in
+ * cvmx-helper-board.c.
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK: Mask for clock speed field
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ: Speed of reference clock or
+ * crystal
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ: Speed of reference clock
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ: Speed of reference clock
+ * @CVMX_USB_INITIALIZE_FLAGS_NO_DMA: Disable DMA and used polled IO for
+ * data transfer use for the USB
+ */
+enum cvmx_usb_initialize_flags {
+ CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI = 1 << 0,
+ CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND = 1 << 1,
+ CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO = 0,
+ CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK = 3 << 3,
+ CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ = 1 << 3,
+ CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ = 2 << 3,
+ CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ = 3 << 3,
+ /* Bits 3-4 used to encode the clock frequency */
+ CVMX_USB_INITIALIZE_FLAGS_NO_DMA = 1 << 5,
+};
+
+/**
+ * enum cvmx_usb_pipe_flags - flags for passing when a pipe is created.
+ * Currently no flags need to be passed.
+ *
+ * @__CVMX_USB_PIPE_FLAGS_OPEN: Used internally to determine if a pipe is
+ * open. Do not use.
+ * @__CVMX_USB_PIPE_FLAGS_SCHEDULED: Used internally to determine if a pipe is
+ * actively using hardware. Do not use.
+ * @__CVMX_USB_PIPE_FLAGS_NEED_PING: Used internally to determine if a high
+ * speed pipe is in the ping state. Do not
+ * use.
+ */
+enum cvmx_usb_pipe_flags {
+ __CVMX_USB_PIPE_FLAGS_OPEN = 1 << 16,
+ __CVMX_USB_PIPE_FLAGS_SCHEDULED = 1 << 17,
+ __CVMX_USB_PIPE_FLAGS_NEED_PING = 1 << 18,
+};
-/**
- * Flags for passing when a pipe is created. Currently no flags
- * need to be passed.
- */
-typedef enum
-{
- CVMX_USB_PIPE_FLAGS_DEBUG_TRANSFERS = 1<<15,/**< Used to display CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS for a specific pipe only */
- __CVMX_USB_PIPE_FLAGS_OPEN = 1<<16, /**< Used internally to determine if a pipe is open. Do not use */
- __CVMX_USB_PIPE_FLAGS_SCHEDULED = 1<<17, /**< Used internally to determine if a pipe is actively using hardware. Do not use */
- __CVMX_USB_PIPE_FLAGS_NEED_PING = 1<<18, /**< Used internally to determine if a high speed pipe is in the ping state. Do not use */
-} cvmx_usb_pipe_flags_t;
-
-/**
- * Return the number of USB ports supported by this Octeon
- * chip. If the chip doesn't support USB, or is not supported
- * by this API, a zero will be returned. Most Octeon chips
- * support one usb port, but some support two ports.
- * cvmx_usb_initialize() must be called on independent
- * cvmx_usb_state_t structures.
- *
- * @return Number of port, zero if usb isn't supported
- */
extern int cvmx_usb_get_num_ports(void);
-
-/**
- * Initialize a USB port for use. This must be called before any
- * other access to the Octeon USB port is made. The port starts
- * off in the disabled state.
- *
- * @param state Pointer to an empty cvmx_usb_state_t structure
- * that will be populated by the initialize call.
- * This structure is then passed to all other USB
- * functions.
- * @param usb_port_number
- * Which Octeon USB port to initialize.
- * @param flags Flags to control hardware initialization. See
- * cvmx_usb_initialize_flags_t for the flag
- * definitions. Some flags are mandatory.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_initialize(cvmx_usb_state_t *state,
- int usb_port_number,
- cvmx_usb_initialize_flags_t flags);
-
-/**
- * Shutdown a USB port after a call to cvmx_usb_initialize().
- * The port should be disabled with all pipes closed when this
- * function is called.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_shutdown(cvmx_usb_state_t *state);
-
-/**
- * Enable a USB port. After this call succeeds, the USB port is
- * online and servicing requests.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_enable(cvmx_usb_state_t *state);
-
-/**
- * Disable a USB port. After this call the USB port will not
- * generate data transfers and will not generate events.
- * Transactions in process will fail and call their
- * associated callbacks.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_disable(cvmx_usb_state_t *state);
-
-/**
- * Get the current state of the USB port. Use this call to
- * determine if the usb port has anything connected, is enabled,
- * or has some sort of error condition. The return value of this
- * call has "changed" bits to signal of the value of some fields
- * have changed between calls. These "changed" fields are based
- * on the last call to cvmx_usb_set_status(). In order to clear
- * them, you must update the status through cvmx_usb_set_status().
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- *
- * @return Port status information
- */
-extern cvmx_usb_port_status_t cvmx_usb_get_status(cvmx_usb_state_t *state);
-
-/**
- * Set the current state of the USB port. The status is used as
- * a reference for the "changed" bits returned by
- * cvmx_usb_get_status(). Other than serving as a reference, the
- * status passed to this function is not used. No fields can be
- * changed through this call.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param port_status
- * Port status to set, most like returned by cvmx_usb_get_status()
- */
-extern void cvmx_usb_set_status(cvmx_usb_state_t *state, cvmx_usb_port_status_t port_status);
-
-/**
- * Open a virtual pipe between the host and a USB device. A pipe
- * must be opened before data can be transferred between a device
- * and Octeon.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param flags Optional pipe flags defined in
- * cvmx_usb_pipe_flags_t.
- * @param device_addr
- * USB device address to open the pipe to
- * (0-127).
- * @param endpoint_num
- * USB endpoint number to open the pipe to
- * (0-15).
- * @param device_speed
- * The speed of the device the pipe is going
- * to. This must match the device's speed,
- * which may be different than the port speed.
- * @param max_packet The maximum packet length the device can
- * transmit/receive (low speed=0-8, full
- * speed=0-1023, high speed=0-1024). This value
- * comes from the standard endpoint descriptor
- * field wMaxPacketSize bits <10:0>.
- * @param transfer_type
- * The type of transfer this pipe is for.
- * @param transfer_dir
- * The direction the pipe is in. This is not
- * used for control pipes.
- * @param interval For ISOCHRONOUS and INTERRUPT transfers,
- * this is how often the transfer is scheduled
- * for. All other transfers should specify
- * zero. The units are in frames (8000/sec at
- * high speed, 1000/sec for full speed).
- * @param multi_count
- * For high speed devices, this is the maximum
- * allowed number of packet per microframe.
- * Specify zero for non high speed devices. This
- * value comes from the standard endpoint descriptor
- * field wMaxPacketSize bits <12:11>.
- * @param hub_device_addr
- * Hub device address this device is connected
- * to. Devices connected directly to Octeon
- * use zero. This is only used when the device
- * is full/low speed behind a high speed hub.
- * The address will be of the high speed hub,
- * not and full speed hubs after it.
- * @param hub_port Which port on the hub the device is
- * connected. Use zero for devices connected
- * directly to Octeon. Like hub_device_addr,
- * this is only used for full/low speed
- * devices behind a high speed hub.
- *
- * @return A non negative value is a pipe handle. Negative
- * values are failure codes from cvmx_usb_status_t.
- */
-extern int cvmx_usb_open_pipe(cvmx_usb_state_t *state,
- cvmx_usb_pipe_flags_t flags,
+extern int cvmx_usb_initialize(struct cvmx_usb_state *state, int usb_port_number,
+ enum cvmx_usb_initialize_flags flags);
+extern int cvmx_usb_shutdown(struct cvmx_usb_state *state);
+extern int cvmx_usb_enable(struct cvmx_usb_state *state);
+extern int cvmx_usb_disable(struct cvmx_usb_state *state);
+extern struct cvmx_usb_port_status cvmx_usb_get_status(struct cvmx_usb_state *state);
+extern void cvmx_usb_set_status(struct cvmx_usb_state *state, struct cvmx_usb_port_status port_status);
+extern int cvmx_usb_open_pipe(struct cvmx_usb_state *state,
+ enum cvmx_usb_pipe_flags flags,
int device_addr, int endpoint_num,
- cvmx_usb_speed_t device_speed, int max_packet,
- cvmx_usb_transfer_t transfer_type,
- cvmx_usb_direction_t transfer_dir, int interval,
+ enum cvmx_usb_speed device_speed, int max_packet,
+ enum cvmx_usb_transfer transfer_type,
+ enum cvmx_usb_direction transfer_dir, int interval,
int multi_count, int hub_device_addr,
int hub_port);
-
-/**
- * Call to submit a USB Bulk transfer to a pipe.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Handle to the pipe for the transfer.
- * @param buffer Physical address of the data buffer in
- * memory. Note that this is NOT A POINTER, but
- * the full 64bit physical address of the
- * buffer. This may be zero if buffer_length is
- * zero.
- * @param buffer_length
- * Length of buffer in bytes.
- * @param callback Function to call when this transaction
- * completes. If the return value of this
- * function isn't an error, then this function
- * is guaranteed to be called when the
- * transaction completes. If this parameter is
- * NULL, then the generic callback registered
- * through cvmx_usb_register_callback is
- * called. If both are NULL, then there is no
- * way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- * callback is called. This is only used if
- * callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- * failure. Negative values are failure codes from
- * cvmx_usb_status_t.
- */
-extern int cvmx_usb_submit_bulk(cvmx_usb_state_t *state, int pipe_handle,
+extern int cvmx_usb_submit_bulk(struct cvmx_usb_state *state, int pipe_handle,
uint64_t buffer, int buffer_length,
cvmx_usb_callback_func_t callback,
void *user_data);
-
-/**
- * Call to submit a USB Interrupt transfer to a pipe.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Handle to the pipe for the transfer.
- * @param buffer Physical address of the data buffer in
- * memory. Note that this is NOT A POINTER, but
- * the full 64bit physical address of the
- * buffer. This may be zero if buffer_length is
- * zero.
- * @param buffer_length
- * Length of buffer in bytes.
- * @param callback Function to call when this transaction
- * completes. If the return value of this
- * function isn't an error, then this function
- * is guaranteed to be called when the
- * transaction completes. If this parameter is
- * NULL, then the generic callback registered
- * through cvmx_usb_register_callback is
- * called. If both are NULL, then there is no
- * way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- * callback is called. This is only used if
- * callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- * failure. Negative values are failure codes from
- * cvmx_usb_status_t.
- */
-extern int cvmx_usb_submit_interrupt(cvmx_usb_state_t *state, int pipe_handle,
+extern int cvmx_usb_submit_interrupt(struct cvmx_usb_state *state, int pipe_handle,
uint64_t buffer, int buffer_length,
cvmx_usb_callback_func_t callback,
void *user_data);
-
-/**
- * Call to submit a USB Control transfer to a pipe.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Handle to the pipe for the transfer.
- * @param control_header
- * USB 8 byte control header physical address.
- * Note that this is NOT A POINTER, but the
- * full 64bit physical address of the buffer.
- * @param buffer Physical address of the data buffer in
- * memory. Note that this is NOT A POINTER, but
- * the full 64bit physical address of the
- * buffer. This may be zero if buffer_length is
- * zero.
- * @param buffer_length
- * Length of buffer in bytes.
- * @param callback Function to call when this transaction
- * completes. If the return value of this
- * function isn't an error, then this function
- * is guaranteed to be called when the
- * transaction completes. If this parameter is
- * NULL, then the generic callback registered
- * through cvmx_usb_register_callback is
- * called. If both are NULL, then there is no
- * way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- * callback is called. This is only used if
- * callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- * failure. Negative values are failure codes from
- * cvmx_usb_status_t.
- */
-extern int cvmx_usb_submit_control(cvmx_usb_state_t *state, int pipe_handle,
+extern int cvmx_usb_submit_control(struct cvmx_usb_state *state, int pipe_handle,
uint64_t control_header,
uint64_t buffer, int buffer_length,
cvmx_usb_callback_func_t callback,
void *user_data);
/**
- * Flags to pass the cvmx_usb_submit_isochronous() function.
- */
-typedef enum
-{
- CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT = 1<<0, /**< Do not return an error if a transfer is less than the maximum packet size of the device */
- CVMX_USB_ISOCHRONOUS_FLAGS_ASAP = 1<<1, /**< Schedule the transaction as soon as possible */
-} cvmx_usb_isochronous_flags_t;
-
-/**
- * Call to submit a USB Isochronous transfer to a pipe.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Handle to the pipe for the transfer.
- * @param start_frame
- * Number of frames into the future to schedule
- * this transaction.
- * @param flags Flags to control the transfer. See
- * cvmx_usb_isochronous_flags_t for the flag
- * definitions.
- * @param number_packets
- * Number of sequential packets to transfer.
- * "packets" is a pointer to an array of this
- * many packet structures.
- * @param packets Description of each transfer packet as
- * defined by cvmx_usb_iso_packet_t. The array
- * pointed to here must stay valid until the
- * complete callback is called.
- * @param buffer Physical address of the data buffer in
- * memory. Note that this is NOT A POINTER, but
- * the full 64bit physical address of the
- * buffer. This may be zero if buffer_length is
- * zero.
- * @param buffer_length
- * Length of buffer in bytes.
- * @param callback Function to call when this transaction
- * completes. If the return value of this
- * function isn't an error, then this function
- * is guaranteed to be called when the
- * transaction completes. If this parameter is
- * NULL, then the generic callback registered
- * through cvmx_usb_register_callback is
- * called. If both are NULL, then there is no
- * way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- * callback is called. This is only used if
- * callback in not NULL.
+ * enum cvmx_usb_isochronous_flags - flags to pass the
+ * cvmx_usb_submit_isochronous() function.
*
- * @return A submitted transaction handle or negative on
- * failure. Negative values are failure codes from
- * cvmx_usb_status_t.
+ * @CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT: Do not return an error if a transfer
+ * is less than the maximum packet size
+ * of the device.
+ * @CVMX_USB_ISOCHRONOUS_FLAGS_ASAP: Schedule the transaction as soon as
+ * possible.
*/
-extern int cvmx_usb_submit_isochronous(cvmx_usb_state_t *state, int pipe_handle,
+enum cvmx_usb_isochronous_flags {
+ CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT = 1 << 0,
+ CVMX_USB_ISOCHRONOUS_FLAGS_ASAP = 1 << 1,
+};
+
+extern int cvmx_usb_submit_isochronous(struct cvmx_usb_state *state, int pipe_handle,
int start_frame, int flags,
int number_packets,
- cvmx_usb_iso_packet_t packets[],
+ struct cvmx_usb_iso_packet packets[],
uint64_t buffer, int buffer_length,
cvmx_usb_callback_func_t callback,
void *user_data);
-
-/**
- * Cancel one outstanding request in a pipe. Canceling a request
- * can fail if the transaction has already completed before cancel
- * is called. Even after a successful cancel call, it may take
- * a frame or two for the cvmx_usb_poll() function to call the
- * associated callback.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Pipe handle to cancel requests in.
- * @param submit_handle
- * Handle to transaction to cancel, returned by the submit function.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_cancel(cvmx_usb_state_t *state,
- int pipe_handle, int submit_handle);
-
-
-/**
- * Cancel all outstanding requests in a pipe. Logically all this
- * does is call cvmx_usb_cancel() in a loop.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Pipe handle to cancel requests in.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_cancel_all(cvmx_usb_state_t *state,
- int pipe_handle);
-
-/**
- * Close a pipe created with cvmx_usb_open_pipe().
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param pipe_handle
- * Pipe handle to close.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t. CVMX_USB_BUSY is returned if the
- * pipe has outstanding transfers.
- */
-extern cvmx_usb_status_t cvmx_usb_close_pipe(cvmx_usb_state_t *state,
- int pipe_handle);
-
-/**
- * Register a function to be called when various USB events occur.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- * @param reason Which event to register for.
- * @param callback Function to call when the event occurs.
- * @param user_data User data parameter to the function.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_register_callback(cvmx_usb_state_t *state,
- cvmx_usb_callback_t reason,
- cvmx_usb_callback_func_t callback,
- void *user_data);
-
-/**
- * Get the current USB protocol level frame number. The frame
- * number is always in the range of 0-0x7ff.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- *
- * @return USB frame number
- */
-extern int cvmx_usb_get_frame_number(cvmx_usb_state_t *state);
-
-/**
- * Poll the USB block for status and call all needed callback
- * handlers. This function is meant to be called in the interrupt
- * handler for the USB controller. It can also be called
- * periodically in a loop for non-interrupt based operation.
- *
- * @param state USB device state populated by
- * cvmx_usb_initialize().
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- * cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_poll(cvmx_usb_state_t *state);
-
-#ifdef __cplusplus
-}
-#endif
+extern int cvmx_usb_cancel(struct cvmx_usb_state *state, int pipe_handle,
+ int submit_handle);
+extern int cvmx_usb_cancel_all(struct cvmx_usb_state *state, int pipe_handle);
+extern int cvmx_usb_close_pipe(struct cvmx_usb_state *state, int pipe_handle);
+extern int cvmx_usb_register_callback(struct cvmx_usb_state *state,
+ enum cvmx_usb_callback reason,
+ cvmx_usb_callback_func_t callback,
+ void *user_data);
+extern int cvmx_usb_get_frame_number(struct cvmx_usb_state *state);
+extern int cvmx_usb_poll(struct cvmx_usb_state *state);
#endif /* __CVMX_USB_H__ */
diff --git a/drivers/staging/octeon-usb/cvmx-usbcx-defs.h b/drivers/staging/octeon-usb/cvmx-usbcx-defs.h
index 394e84662ce..d349d77bc35 100644
--- a/drivers/staging/octeon-usb/cvmx-usbcx-defs.h
+++ b/drivers/staging/octeon-usb/cvmx-usbcx-defs.h
@@ -140,7 +140,6 @@ union cvmx_usbcx_gahbcfg {
uint32_t glblintrmsk : 1;
} s;
};
-typedef union cvmx_usbcx_gahbcfg cvmx_usbcx_gahbcfg_t;
/**
* cvmx_usbc#_ghwcfg3
@@ -210,7 +209,6 @@ union cvmx_usbcx_ghwcfg3 {
uint32_t xfersizewidth : 4;
} s;
};
-typedef union cvmx_usbcx_ghwcfg3 cvmx_usbcx_ghwcfg3_t;
/**
* cvmx_usbc#_gintmsk
@@ -299,7 +297,6 @@ union cvmx_usbcx_gintmsk {
uint32_t reserved_0_0 : 1;
} s;
};
-typedef union cvmx_usbcx_gintmsk cvmx_usbcx_gintmsk_t;
/**
* cvmx_usbc#_gintsts
@@ -529,7 +526,6 @@ union cvmx_usbcx_gintsts {
uint32_t curmod : 1;
} s;
};
-typedef union cvmx_usbcx_gintsts cvmx_usbcx_gintsts_t;
/**
* cvmx_usbc#_gnptxfsiz
@@ -556,7 +552,6 @@ union cvmx_usbcx_gnptxfsiz {
uint32_t nptxfstaddr : 16;
} s;
};
-typedef union cvmx_usbcx_gnptxfsiz cvmx_usbcx_gnptxfsiz_t;
/**
* cvmx_usbc#_gnptxsts
@@ -609,7 +604,6 @@ union cvmx_usbcx_gnptxsts {
uint32_t nptxfspcavail : 16;
} s;
};
-typedef union cvmx_usbcx_gnptxsts cvmx_usbcx_gnptxsts_t;
/**
* cvmx_usbc#_grstctl
@@ -737,7 +731,6 @@ union cvmx_usbcx_grstctl {
uint32_t csftrst : 1;
} s;
};
-typedef union cvmx_usbcx_grstctl cvmx_usbcx_grstctl_t;
/**
* cvmx_usbc#_grxfsiz
@@ -761,7 +754,6 @@ union cvmx_usbcx_grxfsiz {
uint32_t rxfdep : 16;
} s;
};
-typedef union cvmx_usbcx_grxfsiz cvmx_usbcx_grxfsiz_t;
/**
* cvmx_usbc#_grxstsph
@@ -807,7 +799,6 @@ union cvmx_usbcx_grxstsph {
uint32_t chnum : 4;
} s;
};
-typedef union cvmx_usbcx_grxstsph cvmx_usbcx_grxstsph_t;
/**
* cvmx_usbc#_gusbcfg
@@ -896,7 +887,6 @@ union cvmx_usbcx_gusbcfg {
uint32_t toutcal : 3;
} s;
};
-typedef union cvmx_usbcx_gusbcfg cvmx_usbcx_gusbcfg_t;
/**
* cvmx_usbc#_haint
@@ -922,7 +912,6 @@ union cvmx_usbcx_haint {
uint32_t haint : 16;
} s;
};
-typedef union cvmx_usbcx_haint cvmx_usbcx_haint_t;
/**
* cvmx_usbc#_haintmsk
@@ -947,7 +936,6 @@ union cvmx_usbcx_haintmsk {
uint32_t haintmsk : 16;
} s;
};
-typedef union cvmx_usbcx_haintmsk cvmx_usbcx_haintmsk_t;
/**
* cvmx_usbc#_hcchar#
@@ -1027,7 +1015,6 @@ union cvmx_usbcx_hccharx {
uint32_t mps : 11;
} s;
};
-typedef union cvmx_usbcx_hccharx cvmx_usbcx_hccharx_t;
/**
* cvmx_usbc#_hcfg
@@ -1075,7 +1062,6 @@ union cvmx_usbcx_hcfg {
uint32_t fslspclksel : 2;
} s;
};
-typedef union cvmx_usbcx_hcfg cvmx_usbcx_hcfg_t;
/**
* cvmx_usbc#_hcint#
@@ -1126,7 +1112,6 @@ union cvmx_usbcx_hcintx {
uint32_t xfercompl : 1;
} s;
};
-typedef union cvmx_usbcx_hcintx cvmx_usbcx_hcintx_t;
/**
* cvmx_usbc#_hcintmsk#
@@ -1168,7 +1153,6 @@ union cvmx_usbcx_hcintmskx {
uint32_t xfercomplmsk : 1;
} s;
};
-typedef union cvmx_usbcx_hcintmskx cvmx_usbcx_hcintmskx_t;
/**
* cvmx_usbc#_hcsplt#
@@ -1213,7 +1197,6 @@ union cvmx_usbcx_hcspltx {
uint32_t prtaddr : 7;
} s;
};
-typedef union cvmx_usbcx_hcspltx cvmx_usbcx_hcspltx_t;
/**
* cvmx_usbc#_hctsiz#
@@ -1257,7 +1240,6 @@ union cvmx_usbcx_hctsizx {
uint32_t xfersize : 19;
} s;
};
-typedef union cvmx_usbcx_hctsizx cvmx_usbcx_hctsizx_t;
/**
* cvmx_usbc#_hfir
@@ -1293,7 +1275,6 @@ union cvmx_usbcx_hfir {
uint32_t frint : 16;
} s;
};
-typedef union cvmx_usbcx_hfir cvmx_usbcx_hfir_t;
/**
* cvmx_usbc#_hfnum
@@ -1323,7 +1304,6 @@ union cvmx_usbcx_hfnum {
uint32_t frnum : 16;
} s;
};
-typedef union cvmx_usbcx_hfnum cvmx_usbcx_hfnum_t;
/**
* cvmx_usbc#_hprt
@@ -1464,7 +1444,6 @@ union cvmx_usbcx_hprt {
uint32_t prtconnsts : 1;
} s;
};
-typedef union cvmx_usbcx_hprt cvmx_usbcx_hprt_t;
/**
* cvmx_usbc#_hptxfsiz
@@ -1489,7 +1468,6 @@ union cvmx_usbcx_hptxfsiz {
uint32_t ptxfstaddr : 16;
} s;
};
-typedef union cvmx_usbcx_hptxfsiz cvmx_usbcx_hptxfsiz_t;
/**
* cvmx_usbc#_hptxsts
@@ -1546,6 +1524,5 @@ union cvmx_usbcx_hptxsts {
uint32_t ptxfspcavail : 16;
} s;
};
-typedef union cvmx_usbcx_hptxsts cvmx_usbcx_hptxsts_t;
#endif
diff --git a/drivers/staging/octeon-usb/cvmx-usbnx-defs.h b/drivers/staging/octeon-usb/cvmx-usbnx-defs.h
index 96d706770fc..e06aafa5726 100644
--- a/drivers/staging/octeon-usb/cvmx-usbnx-defs.h
+++ b/drivers/staging/octeon-usb/cvmx-usbnx-defs.h
@@ -337,7 +337,6 @@ union cvmx_usbnx_clk_ctl {
struct cvmx_usbnx_clk_ctl_cn50xx cn52xx;
struct cvmx_usbnx_clk_ctl_cn50xx cn56xx;
};
-typedef union cvmx_usbnx_clk_ctl cvmx_usbnx_clk_ctl_t;
/**
* cvmx_usbn#_usbp_ctl_status
@@ -882,6 +881,5 @@ union cvmx_usbnx_usbp_ctl_status {
uint64_t ate_reset : 1;
} cn52xx;
};
-typedef union cvmx_usbnx_usbp_ctl_status cvmx_usbnx_usbp_ctl_status_t;
#endif
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index d156b603ae6..5dbbd14ec61 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -26,7 +26,7 @@
struct octeon_hcd {
spinlock_t lock;
- cvmx_usb_state_t usb;
+ struct cvmx_usb_state usb;
struct tasklet_struct dequeue_tasklet;
struct list_head dequeue_list;
};
@@ -42,7 +42,7 @@ static inline struct usb_hcd *octeon_to_hcd(struct octeon_hcd *p)
return container_of((void *)p, struct usb_hcd, hcd_priv);
}
-static inline struct octeon_hcd *cvmx_usb_to_octeon(cvmx_usb_state_t *p)
+static inline struct octeon_hcd *cvmx_usb_to_octeon(struct cvmx_usb_state *p)
{
return container_of(p, struct octeon_hcd, usb);
}
@@ -58,9 +58,9 @@ static irqreturn_t octeon_usb_irq(struct usb_hcd *hcd)
return IRQ_HANDLED;
}
-static void octeon_usb_port_callback(cvmx_usb_state_t *usb,
- cvmx_usb_callback_t reason,
- cvmx_usb_complete_t status,
+static void octeon_usb_port_callback(struct cvmx_usb_state *usb,
+ enum cvmx_usb_callback reason,
+ enum cvmx_usb_complete status,
int pipe_handle,
int submit_handle,
int bytes_transferred,
@@ -105,9 +105,9 @@ static int octeon_usb_get_frame_number(struct usb_hcd *hcd)
return cvmx_usb_get_frame_number(&priv->usb);
}
-static void octeon_usb_urb_complete_callback(cvmx_usb_state_t *usb,
- cvmx_usb_callback_t reason,
- cvmx_usb_complete_t status,
+static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
+ enum cvmx_usb_callback reason,
+ enum cvmx_usb_complete status,
int pipe_handle,
int submit_handle,
int bytes_transferred,
@@ -141,7 +141,8 @@ static void octeon_usb_urb_complete_callback(cvmx_usb_state_t *usb,
* The pointer to the private list is stored in the setup_packet
* field.
*/
- cvmx_usb_iso_packet_t *iso_packet = (cvmx_usb_iso_packet_t *) urb->setup_packet;
+ struct cvmx_usb_iso_packet *iso_packet =
+ (struct cvmx_usb_iso_packet *) urb->setup_packet;
/* Recalculate the transfer size by adding up each packet */
urb->actual_length = 0;
for (i = 0; i < urb->number_of_packets; i++) {
@@ -208,7 +209,7 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
int submit_handle = -1;
int pipe_handle;
unsigned long flags;
- cvmx_usb_iso_packet_t *iso_packet;
+ struct cvmx_usb_iso_packet *iso_packet;
struct usb_host_endpoint *ep = urb->ep;
urb->status = 0;
@@ -216,8 +217,8 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
spin_lock_irqsave(&priv->lock, flags);
if (!ep->hcpriv) {
- cvmx_usb_transfer_t transfer_type;
- cvmx_usb_speed_t speed;
+ enum cvmx_usb_transfer transfer_type;
+ enum cvmx_usb_speed speed;
int split_device = 0;
int split_port = 0;
switch (usb_pipetype(urb->pipe)) {
@@ -305,7 +306,9 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
* Allocate a structure to use for our private list of
* isochronous packets.
*/
- iso_packet = kmalloc(urb->number_of_packets * sizeof(cvmx_usb_iso_packet_t), GFP_ATOMIC);
+ iso_packet = kmalloc(urb->number_of_packets *
+ sizeof(struct cvmx_usb_iso_packet),
+ GFP_ATOMIC);
if (iso_packet) {
int i;
/* Fill the list with the data from the URB */
@@ -440,7 +443,7 @@ static void octeon_usb_endpoint_disable(struct usb_hcd *hcd, struct usb_host_end
static int octeon_usb_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct octeon_hcd *priv = hcd_to_octeon(hcd);
- cvmx_usb_port_status_t port_status;
+ struct cvmx_usb_port_status port_status;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -456,7 +459,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
{
struct octeon_hcd *priv = hcd_to_octeon(hcd);
struct device *dev = hcd->self.controller;
- cvmx_usb_port_status_t usb_port_status;
+ struct cvmx_usb_port_status usb_port_status;
int port_status;
struct usb_hub_descriptor *desc;
unsigned long flags;
diff --git a/drivers/staging/olpc_dcon/Kconfig b/drivers/staging/olpc_dcon/Kconfig
index fe40e0b6f67..2ff015d8450 100644
--- a/drivers/staging/olpc_dcon/Kconfig
+++ b/drivers/staging/olpc_dcon/Kconfig
@@ -4,9 +4,14 @@ config FB_OLPC_DCON
select I2C
select BACKLIGHT_CLASS_DEVICE
---help---
- Add support for the OLPC XO DCON controller. This controller is
- only available on OLPC platforms. Unless you have one of these
- platforms, you will want to say 'N'.
+ In order to support very low power operation, the XO laptop uses a
+ secondary Display CONtroller, or DCON. This secondary controller
+ is present in the video pipeline between the primary display
+ controller (integrate into the processor or chipset) and the LCD
+ panel. It allows the main processor/display controller to be
+ completely powered off while still retaining an image on the display.
+ This controller is only available on OLPC platforms. Unless you have
+ one of these platforms, you will want to say 'N'.
config FB_OLPC_DCON_1
bool "OLPC XO-1 DCON support"
diff --git a/drivers/staging/olpc_dcon/TODO b/drivers/staging/olpc_dcon/TODO
index 35f9cda7be1..61c2e65ac35 100644
--- a/drivers/staging/olpc_dcon/TODO
+++ b/drivers/staging/olpc_dcon/TODO
@@ -1,16 +1,9 @@
TODO:
- - checkpatch.pl cleanups
- see if vx855 gpio API can be made similar enough to cs5535 so we can
share more code
- allow simultaneous XO-1 and XO-1.5 support
- - console event notifier support
- - drop global variables, use a proper olpc_dcon_priv struct
- - audit code for unnecessary code; old unsupported prototype
- workarounds, ancient variables (noaa?), etc
- - verify sane i2c API usage, update to new stuff if necessary
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
copy:
- Andres Salomon <dilinger@queued.net>
- Chris Ball <cjb@laptop.org>
- Jon Nettleton <jon.nettleton@gmail.com>
+ Daniel Drake <dsd@laptop.org>
+ Jens Frederich <jfrederich@gmail.com>
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 193e1c68bb4..198595e8d74 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -90,9 +90,10 @@ static int dcon_hw_init(struct dcon_priv *dcon, int is_init)
/* SDRAM setup/hold time */
dcon_write(dcon, 0x3a, 0xc040);
- dcon_write(dcon, 0x41, 0x0000);
- dcon_write(dcon, 0x41, 0x0101);
- dcon_write(dcon, 0x42, 0x0101);
+ dcon_write(dcon, DCON_REG_MEM_OPT_A, 0x0000); /* clear option bits */
+ dcon_write(dcon, DCON_REG_MEM_OPT_A,
+ MEM_DLL_CLOCK_DELAY | MEM_POWER_DOWN);
+ dcon_write(dcon, DCON_REG_MEM_OPT_B, MEM_SOFT_RESET);
/* Colour swizzle, AA, no passthrough, backlight */
if (is_init) {
@@ -121,30 +122,31 @@ err:
static int dcon_bus_stabilize(struct dcon_priv *dcon, int is_powered_down)
{
unsigned long timeout;
+ u8 pm;
int x;
power_up:
if (is_powered_down) {
- x = 1;
- x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
+ pm = 1;
+ x = olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0);
if (x) {
pr_warn("unable to force dcon to power up: %d!\n", x);
return x;
}
- msleep(10); /* we'll be conservative */
+ usleep_range(10000, 11000); /* we'll be conservative */
}
pdata->bus_stabilize_wiggle();
for (x = -1, timeout = 50; timeout && x < 0; timeout--) {
- msleep(1);
+ usleep_range(1000, 1100);
x = dcon_read(dcon, DCON_REG_ID);
}
if (x < 0) {
pr_err("unable to stabilize dcon's smbus, reasserting power and praying.\n");
BUG_ON(olpc_board_at_least(olpc_board(0xc2)));
- x = 0;
- olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
+ pm = 0;
+ olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0);
msleep(100);
is_powered_down = 1;
goto power_up; /* argh, stupid hardware.. */
@@ -207,8 +209,8 @@ static void dcon_sleep(struct dcon_priv *dcon, bool sleep)
return;
if (sleep) {
- x = 0;
- x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
+ u8 pm = 0;
+ x = olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0);
if (x)
pr_warn("unable to force dcon to power down: %d!\n", x);
else
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.h b/drivers/staging/olpc_dcon/olpc_dcon.h
index 997bded2949..e2663b189c6 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.h
+++ b/drivers/staging/olpc_dcon/olpc_dcon.h
@@ -22,15 +22,24 @@
#define MODE_DEBUG (1<<14)
#define MODE_SELFTEST (1<<15)
-#define DCON_REG_HRES 2
-#define DCON_REG_HTOTAL 3
-#define DCON_REG_HSYNC_WIDTH 4
-#define DCON_REG_VRES 5
-#define DCON_REG_VTOTAL 6
-#define DCON_REG_VSYNC_WIDTH 7
-#define DCON_REG_TIMEOUT 8
-#define DCON_REG_SCAN_INT 9
-#define DCON_REG_BRIGHT 10
+#define DCON_REG_HRES 0x2
+#define DCON_REG_HTOTAL 0x3
+#define DCON_REG_HSYNC_WIDTH 0x4
+#define DCON_REG_VRES 0x5
+#define DCON_REG_VTOTAL 0x6
+#define DCON_REG_VSYNC_WIDTH 0x7
+#define DCON_REG_TIMEOUT 0x8
+#define DCON_REG_SCAN_INT 0x9
+#define DCON_REG_BRIGHT 0xa
+#define DCON_REG_MEM_OPT_A 0x41
+#define DCON_REG_MEM_OPT_B 0x42
+
+/* Load Delay Locked Loop (DLL) settings for clock delay */
+#define MEM_DLL_CLOCK_DELAY (1<<0)
+/* Memory controller power down function */
+#define MEM_POWER_DOWN (1<<8)
+/* Memory controller software reset */
+#define MEM_SOFT_RESET (1<<0)
/* Status values */
diff --git a/drivers/staging/ozwpan/Kbuild b/drivers/staging/ozwpan/Makefile
index 1766a268d5f..29529c1a8e3 100644
--- a/drivers/staging/ozwpan/Kbuild
+++ b/drivers/staging/ozwpan/Makefile
@@ -2,6 +2,7 @@
# Copyright (c) 2011 Ozmo Inc
# Released under the GNU General Public License Version 2 (GPLv2).
# -----------------------------------------------------------------------------
+
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan.o
ozwpan-y := \
ozmain.o \
@@ -12,7 +13,4 @@ ozwpan-y := \
ozeltbuf.o \
ozproto.o \
ozcdev.o \
- ozurbparanoia.o \
- oztrace.o
-
-
+ ozurbparanoia.o
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index 374fdc39864..6ccb64fb078 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -11,16 +11,14 @@
#include <linux/etherdevice.h>
#include <linux/poll.h>
#include <linux/sched.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
#include "ozprotocol.h"
-#include "oztrace.h"
#include "ozappif.h"
#include "ozeltbuf.h"
#include "ozpd.h"
#include "ozproto.h"
#include "ozcdev.h"
-/*------------------------------------------------------------------------------
- */
+
#define OZ_RD_BUF_SZ 256
struct oz_cdev {
dev_t devnum;
@@ -40,16 +38,17 @@ struct oz_serial_ctx {
int rd_in;
int rd_out;
};
-/*------------------------------------------------------------------------------
- */
+
static struct oz_cdev g_cdev;
static struct class *g_oz_class;
-/*------------------------------------------------------------------------------
+
+/*
* Context: process and softirq
*/
static struct oz_serial_ctx *oz_cdev_claim_ctx(struct oz_pd *pd)
{
struct oz_serial_ctx *ctx;
+
spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
ctx = (struct oz_serial_ctx *)pd->app_ctx[OZ_APPID_SERIAL-1];
if (ctx)
@@ -57,37 +56,40 @@ static struct oz_serial_ctx *oz_cdev_claim_ctx(struct oz_pd *pd)
spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
return ctx;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
static void oz_cdev_release_ctx(struct oz_serial_ctx *ctx)
{
if (atomic_dec_and_test(&ctx->ref_count)) {
- oz_trace("Dealloc serial context.\n");
+ oz_dbg(ON, "Dealloc serial context\n");
kfree(ctx);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_cdev_open(struct inode *inode, struct file *filp)
{
- struct oz_cdev *dev;
- oz_trace("oz_cdev_open()\n");
- oz_trace("major = %d minor = %d\n", imajor(inode), iminor(inode));
- dev = container_of(inode->i_cdev, struct oz_cdev, cdev);
+ struct oz_cdev *dev = container_of(inode->i_cdev, struct oz_cdev, cdev);
+
+ oz_dbg(ON, "major = %d minor = %d\n", imajor(inode), iminor(inode));
+
filp->private_data = dev;
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_cdev_release(struct inode *inode, struct file *filp)
{
- oz_trace("oz_cdev_release()\n");
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count,
@@ -139,7 +141,8 @@ out2:
oz_pd_put(pd);
return count;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static ssize_t oz_cdev_write(struct file *filp, const char __user *buf,
@@ -158,7 +161,9 @@ static ssize_t oz_cdev_write(struct file *filp, const char __user *buf,
oz_pd_get(pd);
spin_unlock_bh(&g_cdev.lock);
if (pd == NULL)
- return -1;
+ return -ENXIO;
+ if (!(pd->state & OZ_PD_S_CONNECTED))
+ return -EAGAIN;
eb = &pd->elt_buff;
ei = oz_elt_info_alloc(eb);
if (ei == NULL) {
@@ -196,7 +201,8 @@ out:
oz_pd_put(pd);
return count;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_set_active_pd(const u8 *addr)
@@ -204,6 +210,7 @@ static int oz_set_active_pd(const u8 *addr)
int rc = 0;
struct oz_pd *pd;
struct oz_pd *old_pd;
+
pd = oz_pd_find(addr);
if (pd) {
spin_lock_bh(&g_cdev.lock);
@@ -229,13 +236,15 @@ static int oz_set_active_pd(const u8 *addr)
}
return rc;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static long oz_cdev_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int rc = 0;
+
if (_IOC_TYPE(cmd) != OZ_IOCTL_MAGIC)
return -ENOTTY;
if (_IOC_NR(cmd) > OZ_IOCTL_MAX)
@@ -251,7 +260,7 @@ static long oz_cdev_ioctl(struct file *filp, unsigned int cmd,
switch (cmd) {
case OZ_IOCTL_GET_PD_LIST: {
struct oz_pd_list list;
- oz_trace("OZ_IOCTL_GET_PD_LIST\n");
+ oz_dbg(ON, "OZ_IOCTL_GET_PD_LIST\n");
memset(&list, 0, sizeof(list));
list.count = oz_get_pd_list(list.addr, OZ_MAX_PDS);
if (copy_to_user((void __user *)arg, &list,
@@ -261,7 +270,7 @@ static long oz_cdev_ioctl(struct file *filp, unsigned int cmd,
break;
case OZ_IOCTL_SET_ACTIVE_PD: {
u8 addr[ETH_ALEN];
- oz_trace("OZ_IOCTL_SET_ACTIVE_PD\n");
+ oz_dbg(ON, "OZ_IOCTL_SET_ACTIVE_PD\n");
if (copy_from_user(addr, (void __user *)arg, ETH_ALEN))
return -EFAULT;
rc = oz_set_active_pd(addr);
@@ -269,7 +278,7 @@ static long oz_cdev_ioctl(struct file *filp, unsigned int cmd,
break;
case OZ_IOCTL_GET_ACTIVE_PD: {
u8 addr[ETH_ALEN];
- oz_trace("OZ_IOCTL_GET_ACTIVE_PD\n");
+ oz_dbg(ON, "OZ_IOCTL_GET_ACTIVE_PD\n");
spin_lock_bh(&g_cdev.lock);
memcpy(addr, g_cdev.active_addr, ETH_ALEN);
spin_unlock_bh(&g_cdev.lock);
@@ -295,14 +304,16 @@ static long oz_cdev_ioctl(struct file *filp, unsigned int cmd,
}
return rc;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static unsigned int oz_cdev_poll(struct file *filp, poll_table *wait)
{
unsigned int ret = 0;
struct oz_cdev *dev = filp->private_data;
- oz_trace("Poll called wait = %p\n", wait);
+
+ oz_dbg(ON, "Poll called wait = %p\n", wait);
spin_lock_bh(&dev->lock);
if (dev->active_pd) {
struct oz_serial_ctx *ctx = oz_cdev_claim_ctx(dev->active_pd);
@@ -317,7 +328,8 @@ static unsigned int oz_cdev_poll(struct file *filp, poll_table *wait)
poll_wait(filp, &dev->rdq, wait);
return ret;
}
-/*------------------------------------------------------------------------------
+
+/*
*/
static const struct file_operations oz_fops = {
.owner = THIS_MODULE,
@@ -328,19 +340,21 @@ static const struct file_operations oz_fops = {
.unlocked_ioctl = oz_cdev_ioctl,
.poll = oz_cdev_poll
};
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
int oz_cdev_register(void)
{
int err;
struct device *dev;
+
memset(&g_cdev, 0, sizeof(g_cdev));
err = alloc_chrdev_region(&g_cdev.devnum, 0, 1, "ozwpan");
if (err < 0)
- goto out3;
- oz_trace("Alloc dev number %d:%d\n", MAJOR(g_cdev.devnum),
- MINOR(g_cdev.devnum));
+ return err;
+ oz_dbg(ON, "Alloc dev number %d:%d\n",
+ MAJOR(g_cdev.devnum), MINOR(g_cdev.devnum));
cdev_init(&g_cdev.cdev, &oz_fops);
g_cdev.cdev.owner = THIS_MODULE;
g_cdev.cdev.ops = &oz_fops;
@@ -348,30 +362,31 @@ int oz_cdev_register(void)
init_waitqueue_head(&g_cdev.rdq);
err = cdev_add(&g_cdev.cdev, g_cdev.devnum, 1);
if (err < 0) {
- oz_trace("Failed to add cdev\n");
- goto out2;
+ oz_dbg(ON, "Failed to add cdev\n");
+ goto unregister;
}
g_oz_class = class_create(THIS_MODULE, "ozmo_wpan");
if (IS_ERR(g_oz_class)) {
- oz_trace("Failed to register ozmo_wpan class\n");
+ oz_dbg(ON, "Failed to register ozmo_wpan class\n");
err = PTR_ERR(g_oz_class);
- goto out1;
+ goto delete;
}
dev = device_create(g_oz_class, NULL, g_cdev.devnum, NULL, "ozwpan");
if (IS_ERR(dev)) {
- oz_trace("Failed to create sysfs entry for cdev\n");
+ oz_dbg(ON, "Failed to create sysfs entry for cdev\n");
err = PTR_ERR(dev);
- goto out1;
+ goto delete;
}
return 0;
-out1:
+
+delete:
cdev_del(&g_cdev.cdev);
-out2:
+unregister:
unregister_chrdev_region(g_cdev.devnum, 1);
-out3:
return err;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
int oz_cdev_deregister(void)
@@ -384,7 +399,8 @@ int oz_cdev_deregister(void)
}
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
int oz_cdev_init(void)
@@ -392,22 +408,25 @@ int oz_cdev_init(void)
oz_app_enable(OZ_APPID_SERIAL, 1);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
void oz_cdev_term(void)
{
oz_app_enable(OZ_APPID_SERIAL, 0);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
int oz_cdev_start(struct oz_pd *pd, int resume)
{
struct oz_serial_ctx *ctx;
struct oz_serial_ctx *old_ctx;
+
if (resume) {
- oz_trace("Serial service resumed.\n");
+ oz_dbg(ON, "Serial service resumed\n");
return 0;
}
ctx = kzalloc(sizeof(struct oz_serial_ctx), GFP_ATOMIC);
@@ -429,20 +448,22 @@ int oz_cdev_start(struct oz_pd *pd, int resume)
(memcmp(pd->mac_addr, g_cdev.active_addr, ETH_ALEN) == 0)) {
oz_pd_get(pd);
g_cdev.active_pd = pd;
- oz_trace("Active PD arrived.\n");
+ oz_dbg(ON, "Active PD arrived\n");
}
spin_unlock(&g_cdev.lock);
- oz_trace("Serial service started.\n");
+ oz_dbg(ON, "Serial service started\n");
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
void oz_cdev_stop(struct oz_pd *pd, int pause)
{
struct oz_serial_ctx *ctx;
+
if (pause) {
- oz_trace("Serial service paused.\n");
+ oz_dbg(ON, "Serial service paused\n");
return;
}
spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
@@ -459,11 +480,12 @@ void oz_cdev_stop(struct oz_pd *pd, int pause)
spin_unlock(&g_cdev.lock);
if (pd) {
oz_pd_put(pd);
- oz_trace("Active PD departed.\n");
+ oz_dbg(ON, "Active PD departed\n");
}
- oz_trace("Serial service stopped.\n");
+ oz_dbg(ON, "Serial service stopped\n");
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt)
@@ -478,7 +500,7 @@ void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt)
ctx = oz_cdev_claim_ctx(pd);
if (ctx == NULL) {
- oz_trace("Cannot claim serial context.\n");
+ oz_dbg(ON, "Cannot claim serial context\n");
return;
}
@@ -488,8 +510,8 @@ void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt)
if (app_hdr->elt_seq_num != 0) {
if (((ctx->rx_seq_num - app_hdr->elt_seq_num) & 0x80) == 0) {
/* Reject duplicate element. */
- oz_trace("Duplicate element:%02x %02x\n",
- app_hdr->elt_seq_num, ctx->rx_seq_num);
+ oz_dbg(ON, "Duplicate element:%02x %02x\n",
+ app_hdr->elt_seq_num, ctx->rx_seq_num);
goto out;
}
}
@@ -502,7 +524,7 @@ void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt)
if (space < 0)
space += OZ_RD_BUF_SZ;
if (len > space) {
- oz_trace("Not enough space:%d %d\n", len, space);
+ oz_dbg(ON, "Not enough space:%d %d\n", len, space);
len = space;
}
ix = ctx->rd_in;
diff --git a/drivers/staging/ozwpan/ozconfig.h b/drivers/staging/ozwpan/ozconfig.h
deleted file mode 100644
index 087c322d2de..00000000000
--- a/drivers/staging/ozwpan/ozconfig.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -----------------------------------------------------------------------------
- * Copyright (c) 2011 Ozmo Inc
- * Released under the GNU General Public License Version 2 (GPLv2).
- * ---------------------------------------------------------------------------*/
-#ifndef _OZCONFIG_H
-#define _OZCONFIG_H
-
-/* #define WANT_TRACE */
-#ifdef WANT_TRACE
-#define WANT_VERBOSE_TRACE
-#endif /* #ifdef WANT_TRACE */
-/* #define WANT_URB_PARANOIA */
-
-/* #define WANT_PRE_2_6_39 */
-
-/* These defines determine what verbose trace is displayed. */
-#ifdef WANT_VERBOSE_TRACE
-/* #define WANT_TRACE_STREAM */
-/* #define WANT_TRACE_URB */
-/* #define WANT_TRACE_CTRL_DETAIL */
-#define WANT_TRACE_HUB
-/* #define WANT_TRACE_RX_FRAMES */
-/* #define WANT_TRACE_TX_FRAMES */
-#endif /* WANT_VERBOSE_TRACE */
-
-#endif /* _OZCONFIG_H */
diff --git a/drivers/staging/ozwpan/ozdbg.h b/drivers/staging/ozwpan/ozdbg.h
new file mode 100644
index 00000000000..b86a2b7e017
--- /dev/null
+++ b/drivers/staging/ozwpan/ozdbg.h
@@ -0,0 +1,54 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * ---------------------------------------------------------------------------*/
+
+#ifndef _OZDBG_H
+#define _OZDBG_H
+
+#define OZ_WANT_DBG 0
+#define OZ_WANT_VERBOSE_DBG 1
+
+#define OZ_DBG_ON 0x0
+#define OZ_DBG_STREAM 0x1
+#define OZ_DBG_URB 0x2
+#define OZ_DBG_CTRL_DETAIL 0x4
+#define OZ_DBG_HUB 0x8
+#define OZ_DBG_RX_FRAMES 0x10
+#define OZ_DBG_TX_FRAMES 0x20
+
+#define OZ_DEFAULT_DBG_MASK \
+ ( \
+ /* OZ_DBG_STREAM | */ \
+ /* OZ_DBG_URB | */ \
+ /* OZ_DBG_CTRL_DETAIL | */ \
+ OZ_DBG_HUB | \
+ /* OZ_DBG_RX_FRAMES | */ \
+ /* OZ_DBG_TX_FRAMES | */ \
+ 0)
+
+extern unsigned int oz_dbg_mask;
+
+#define oz_want_dbg(mask) \
+ ((OZ_WANT_DBG && (OZ_DBG_##mask == OZ_DBG_ON)) || \
+ (OZ_WANT_VERBOSE_DBG && (OZ_DBG_##mask & oz_dbg_mask)))
+
+#define oz_dbg(mask, fmt, ...) \
+do { \
+ if (oz_want_dbg(mask)) \
+ pr_debug(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define oz_cdev_dbg(cdev, mask, fmt, ...) \
+do { \
+ if (oz_want_dbg(mask)) \
+ netdev_dbg((cdev)->dev, fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define oz_pd_dbg(pd, mask, fmt, ...) \
+do { \
+ if (oz_want_dbg(mask)) \
+ pr_debug(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#endif /* _OZDBG_H */
diff --git a/drivers/staging/ozwpan/ozeltbuf.c b/drivers/staging/ozwpan/ozeltbuf.c
index ac90fc7f544..9b86486c6b1 100644
--- a/drivers/staging/ozwpan/ozeltbuf.c
+++ b/drivers/staging/ozwpan/ozeltbuf.c
@@ -6,16 +6,15 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netdevice.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
#include "ozprotocol.h"
#include "ozeltbuf.h"
#include "ozpd.h"
-#include "oztrace.h"
-/*------------------------------------------------------------------------------
- */
+
#define OZ_ELT_INFO_MAGIC_USED 0x35791057
#define OZ_ELT_INFO_MAGIC_FREE 0x78940102
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
int oz_elt_buf_init(struct oz_elt_buf *buf)
@@ -28,13 +27,15 @@ int oz_elt_buf_init(struct oz_elt_buf *buf)
spin_lock_init(&buf->lock);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
void oz_elt_buf_term(struct oz_elt_buf *buf)
{
struct list_head *e;
int i;
+
/* Free any elements in the order or isoc lists. */
for (i = 0; i < 2; i++) {
struct list_head *list;
@@ -59,12 +60,14 @@ void oz_elt_buf_term(struct oz_elt_buf *buf)
}
buf->free_elts = 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
struct oz_elt_info *oz_elt_info_alloc(struct oz_elt_buf *buf)
{
- struct oz_elt_info *ei = NULL;
+ struct oz_elt_info *ei;
+
spin_lock_bh(&buf->lock);
if (buf->free_elts && buf->elt_pool) {
ei = container_of(buf->elt_pool, struct oz_elt_info, link);
@@ -72,8 +75,8 @@ struct oz_elt_info *oz_elt_info_alloc(struct oz_elt_buf *buf)
buf->free_elts--;
spin_unlock_bh(&buf->lock);
if (ei->magic != OZ_ELT_INFO_MAGIC_FREE) {
- oz_trace("oz_elt_info_alloc: ei with bad magic: 0x%x\n",
- ei->magic);
+ oz_dbg(ON, "%s: ei with bad magic: 0x%x\n",
+ __func__, ei->magic);
}
} else {
spin_unlock_bh(&buf->lock);
@@ -91,7 +94,8 @@ struct oz_elt_info *oz_elt_info_alloc(struct oz_elt_buf *buf)
}
return ei;
}
-/*------------------------------------------------------------------------------
+
+/*
* Precondition: oz_elt_buf.lock must be held.
* Context: softirq or process
*/
@@ -104,18 +108,19 @@ void oz_elt_info_free(struct oz_elt_buf *buf, struct oz_elt_info *ei)
buf->elt_pool = &ei->link;
ei->magic = OZ_ELT_INFO_MAGIC_FREE;
} else {
- oz_trace("oz_elt_info_free: bad magic ei: %p"
- " magic: 0x%x\n",
- ei, ei->magic);
+ oz_dbg(ON, "%s: bad magic ei: %p magic: 0x%x\n",
+ __func__, ei, ei->magic);
}
}
}
+
/*------------------------------------------------------------------------------
* Context: softirq
*/
void oz_elt_info_free_chain(struct oz_elt_buf *buf, struct list_head *list)
{
struct list_head *e;
+
e = list->next;
spin_lock_bh(&buf->lock);
while (e != list) {
@@ -126,13 +131,12 @@ void oz_elt_info_free_chain(struct oz_elt_buf *buf, struct list_head *list)
}
spin_unlock_bh(&buf->lock);
}
-/*------------------------------------------------------------------------------
- */
+
int oz_elt_stream_create(struct oz_elt_buf *buf, u8 id, int max_buf_count)
{
struct oz_elt_stream *st;
- oz_trace("oz_elt_stream_create(0x%x)\n", id);
+ oz_dbg(ON, "%s: (0x%x)\n", __func__, id);
st = kzalloc(sizeof(struct oz_elt_stream), GFP_ATOMIC | __GFP_ZERO);
if (st == NULL)
@@ -146,13 +150,13 @@ int oz_elt_stream_create(struct oz_elt_buf *buf, u8 id, int max_buf_count)
spin_unlock_bh(&buf->lock);
return 0;
}
-/*------------------------------------------------------------------------------
- */
+
int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id)
{
struct list_head *e;
struct oz_elt_stream *st = NULL;
- oz_trace("oz_elt_stream_delete(0x%x)\n", id);
+
+ oz_dbg(ON, "%s: (0x%x)\n", __func__, id);
spin_lock_bh(&buf->lock);
e = buf->stream_list.next;
while (e != &buf->stream_list) {
@@ -175,9 +179,8 @@ int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id)
list_del_init(&ei->link);
list_del_init(&ei->link_order);
st->buf_count -= ei->length;
- oz_trace2(OZ_TRACE_STREAM, "Stream down: %d %d %d\n",
- st->buf_count,
- ei->length, atomic_read(&st->ref_count));
+ oz_dbg(STREAM, "Stream down: %d %d %d\n",
+ st->buf_count, ei->length, atomic_read(&st->ref_count));
oz_elt_stream_put(st);
oz_elt_info_free(buf, ei);
}
@@ -185,22 +188,21 @@ int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id)
oz_elt_stream_put(st);
return 0;
}
-/*------------------------------------------------------------------------------
- */
+
void oz_elt_stream_get(struct oz_elt_stream *st)
{
atomic_inc(&st->ref_count);
}
-/*------------------------------------------------------------------------------
- */
+
void oz_elt_stream_put(struct oz_elt_stream *st)
{
if (atomic_dec_and_test(&st->ref_count)) {
- oz_trace("Stream destroyed\n");
+ oz_dbg(ON, "Stream destroyed\n");
kfree(st);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Precondition: Element buffer lock must be held.
* If this function fails the caller is responsible for deallocating the elt
* info structure.
@@ -210,6 +212,7 @@ int oz_queue_elt_info(struct oz_elt_buf *buf, u8 isoc, u8 id,
{
struct oz_elt_stream *st = NULL;
struct list_head *e;
+
if (id) {
list_for_each(e, &buf->stream_list) {
st = container_of(e, struct oz_elt_stream, link);
@@ -242,8 +245,7 @@ int oz_queue_elt_info(struct oz_elt_buf *buf, u8 isoc, u8 id,
st->buf_count += ei->length;
/* Add to list in stream. */
list_add_tail(&ei->link, &st->elt_list);
- oz_trace2(OZ_TRACE_STREAM, "Stream up: %d %d\n",
- st->buf_count, ei->length);
+ oz_dbg(STREAM, "Stream up: %d %d\n", st->buf_count, ei->length);
/* Check if we have too much buffered for this stream. If so
* start dropping elements until we are back in bounds.
*/
@@ -263,8 +265,7 @@ int oz_queue_elt_info(struct oz_elt_buf *buf, u8 isoc, u8 id,
&buf->isoc_list : &buf->order_list);
return 0;
}
-/*------------------------------------------------------------------------------
- */
+
int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len,
unsigned max_len, struct list_head *list)
{
@@ -272,6 +273,7 @@ int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len,
struct list_head *e;
struct list_head *el;
struct oz_elt_info *ei;
+
spin_lock_bh(&buf->lock);
if (isoc)
el = &buf->isoc_list;
@@ -293,9 +295,8 @@ int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len,
list_del(&ei->link_order);
if (ei->stream) {
ei->stream->buf_count -= ei->length;
- oz_trace2(OZ_TRACE_STREAM,
- "Stream down: %d %d\n",
- ei->stream->buf_count, ei->length);
+ oz_dbg(STREAM, "Stream down: %d %d\n",
+ ei->stream->buf_count, ei->length);
oz_elt_stream_put(ei->stream);
ei->stream = NULL;
}
@@ -309,18 +310,17 @@ int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len,
spin_unlock_bh(&buf->lock);
return count;
}
-/*------------------------------------------------------------------------------
- */
+
int oz_are_elts_available(struct oz_elt_buf *buf)
{
return buf->order_list.next != &buf->order_list;
}
-/*------------------------------------------------------------------------------
- */
+
void oz_trim_elt_pool(struct oz_elt_buf *buf)
{
struct list_head *free = NULL;
struct list_head *e;
+
spin_lock_bh(&buf->lock);
while (buf->free_elts > buf->max_free_elts) {
e = buf->elt_pool;
diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c
index d68d63a2e68..d9c43c3282e 100644
--- a/drivers/staging/ozwpan/ozhcd.c
+++ b/drivers/staging/ozwpan/ozhcd.c
@@ -26,31 +26,42 @@
*/
#include <linux/platform_device.h>
#include <linux/usb.h>
-#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/export.h>
#include "linux/usb/hcd.h"
#include <asm/unaligned.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
#include "ozusbif.h"
-#include "oztrace.h"
#include "ozurbparanoia.h"
#include "ozhcd.h"
-/*------------------------------------------------------------------------------
+
+/*
* Number of units of buffering to capture for an isochronous IN endpoint before
* allowing data to be indicated up.
*/
-#define OZ_IN_BUFFERING_UNITS 50
+#define OZ_IN_BUFFERING_UNITS 100
+
/* Name of our platform device.
*/
#define OZ_PLAT_DEV_NAME "ozwpan"
+
/* Maximum number of free urb links that can be kept in the pool.
*/
#define OZ_MAX_LINK_POOL_SIZE 16
+
/* Get endpoint object from the containing link.
*/
#define ep_from_link(__e) container_of((__e), struct oz_endpoint, link)
-/*------------------------------------------------------------------------------
+
+/*EP0 timeout before ep0 request is again added to TX queue. (13*8 = 98mSec)
+ */
+#define EP0_TIMEOUT_COUNTER 13
+
+/* Debounce time HCD driver should wait before unregistering.
+ */
+#define OZ_HUB_DEBOUNCE_TIMEOUT 1500
+
+/*
* Used to link urbs together and also store some status information for each
* urb.
* A cache of these are kept in a pool to reduce number of calls to kmalloc.
@@ -61,16 +72,18 @@ struct oz_urb_link {
struct oz_port *port;
u8 req_id;
u8 ep_num;
- unsigned long submit_jiffies;
+ unsigned submit_counter;
};
/* Holds state information about a USB endpoint.
*/
+#define OZ_EP_BUFFER_SIZE_ISOC (1024 * 24)
+#define OZ_EP_BUFFER_SIZE_INT 512
struct oz_endpoint {
struct list_head urb_list; /* List of oz_urb_link items. */
struct list_head link; /* For isoc ep, links in to isoc
lists of oz_port. */
- unsigned long last_jiffies;
+ struct timespec timestamp;
int credit;
int credit_ceiling;
u8 ep_num;
@@ -83,6 +96,7 @@ struct oz_endpoint {
unsigned flags;
int start_frame;
};
+
/* Bits in the flags field. */
#define OZ_F_EP_BUFFERING 0x1
#define OZ_F_EP_HAVE_STREAM 0x2
@@ -113,6 +127,7 @@ struct oz_port {
struct list_head isoc_out_ep;
struct list_head isoc_in_ep;
};
+
#define OZ_PORT_F_PRESENT 0x1
#define OZ_PORT_F_CHANGED 0x2
#define OZ_PORT_F_DYING 0x4
@@ -130,11 +145,12 @@ struct oz_hcd {
uint flags;
struct usb_hcd *hcd;
};
+
/* Bits in flags field.
*/
#define OZ_HDC_F_SUSPENDED 0x1
-/*------------------------------------------------------------------------------
+/*
* Static function prototypes.
*/
static int oz_hcd_start(struct usb_hcd *hcd);
@@ -174,7 +190,8 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
static struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep,
struct urb *urb);
static void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status);
-/*------------------------------------------------------------------------------
+
+/*
* Static external variables.
*/
static struct platform_device *g_plat_dev;
@@ -188,6 +205,7 @@ static DEFINE_SPINLOCK(g_tasklet_lock);
static struct tasklet_struct g_urb_process_tasklet;
static struct tasklet_struct g_urb_cancel_tasklet;
static atomic_t g_pending_urbs = ATOMIC_INIT(0);
+static atomic_t g_usb_frame_number = ATOMIC_INIT(0);
static const struct hc_driver g_oz_hc_drv = {
.description = g_hcd_name,
.product_desc = "Ozmo Devices WPAN",
@@ -218,7 +236,8 @@ static struct platform_driver g_oz_plat_drv = {
.owner = THIS_MODULE,
},
};
-/*------------------------------------------------------------------------------
+
+/*
* Gets our private context area (which is of type struct oz_hcd) from the
* usb_hcd structure.
* Context: any
@@ -227,7 +246,8 @@ static inline struct oz_hcd *oz_hcd_private(struct usb_hcd *hcd)
{
return (struct oz_hcd *)hcd->hcd_priv;
}
-/*------------------------------------------------------------------------------
+
+/*
* Searches list of ports to find the index of the one with a specified USB
* bus address. If none of the ports has the bus address then the connection
* port is returned, if there is one or -1 otherwise.
@@ -236,13 +256,15 @@ static inline struct oz_hcd *oz_hcd_private(struct usb_hcd *hcd)
static int oz_get_port_from_addr(struct oz_hcd *ozhcd, u8 bus_addr)
{
int i;
+
for (i = 0; i < OZ_NB_PORTS; i++) {
if (ozhcd->ports[i].bus_addr == bus_addr)
return i;
}
return ozhcd->conn_port;
}
-/*------------------------------------------------------------------------------
+
+/*
* Allocates an urb link, first trying the pool but going to heap if empty.
* Context: any
*/
@@ -250,6 +272,7 @@ static struct oz_urb_link *oz_alloc_urb_link(void)
{
struct oz_urb_link *urbl = NULL;
unsigned long irq_state;
+
spin_lock_irqsave(&g_link_lock, irq_state);
if (g_link_pool) {
urbl = container_of(g_link_pool, struct oz_urb_link, link);
@@ -261,7 +284,8 @@ static struct oz_urb_link *oz_alloc_urb_link(void)
urbl = kmalloc(sizeof(struct oz_urb_link), GFP_ATOMIC);
return urbl;
}
-/*------------------------------------------------------------------------------
+
+/*
* Frees an urb link by putting it in the pool if there is enough space or
* deallocating it to heap otherwise.
* Context: any
@@ -281,7 +305,8 @@ static void oz_free_urb_link(struct oz_urb_link *urbl)
kfree(urbl);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Deallocates all the urb links in the pool.
* Context: unknown
*/
@@ -289,6 +314,7 @@ static void oz_empty_link_pool(void)
{
struct list_head *e;
unsigned long irq_state;
+
spin_lock_irqsave(&g_link_lock, irq_state);
e = g_link_pool;
g_link_pool = NULL;
@@ -301,12 +327,13 @@ static void oz_empty_link_pool(void)
kfree(urbl);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Allocates endpoint structure and optionally a buffer. If a buffer is
* allocated it immediately follows the endpoint structure.
* Context: softirq
*/
-static struct oz_endpoint *oz_ep_alloc(gfp_t mem_flags, int buffer_size)
+static struct oz_endpoint *oz_ep_alloc(int buffer_size, gfp_t mem_flags)
{
struct oz_endpoint *ep =
kzalloc(sizeof(struct oz_endpoint)+buffer_size, mem_flags);
@@ -321,7 +348,8 @@ static struct oz_endpoint *oz_ep_alloc(gfp_t mem_flags, int buffer_size)
}
return ep;
}
-/*------------------------------------------------------------------------------
+
+/*
* Pre-condition: Must be called with g_tasklet_lock held and interrupts
* disabled.
* Context: softirq or process
@@ -330,6 +358,7 @@ static struct oz_urb_link *oz_uncancel_urb(struct oz_hcd *ozhcd, struct urb *urb
{
struct oz_urb_link *urbl;
struct list_head *e;
+
list_for_each(e, &ozhcd->urb_cancel_list) {
urbl = container_of(e, struct oz_urb_link, link);
if (urb == urbl->urb) {
@@ -339,17 +368,19 @@ static struct oz_urb_link *oz_uncancel_urb(struct oz_hcd *ozhcd, struct urb *urb
}
return NULL;
}
-/*------------------------------------------------------------------------------
+
+/*
* This is called when we have finished processing an urb. It unlinks it from
* the ep and returns it to the core.
* Context: softirq or process
*/
static void oz_complete_urb(struct usb_hcd *hcd, struct urb *urb,
- int status, unsigned long submit_jiffies)
+ int status)
{
struct oz_hcd *ozhcd = oz_hcd_private(hcd);
unsigned long irq_state;
- struct oz_urb_link *cancel_urbl = NULL;
+ struct oz_urb_link *cancel_urbl;
+
spin_lock_irqsave(&g_tasklet_lock, irq_state);
usb_hcd_unlink_urb_from_ep(hcd, urb);
/* Clear hcpriv which will prevent it being put in the cancel list
@@ -371,15 +402,9 @@ static void oz_complete_urb(struct usb_hcd *hcd, struct urb *urb,
*/
spin_unlock(&g_tasklet_lock);
if (oz_forget_urb(urb)) {
- oz_trace("OZWPAN: ERROR Unknown URB %p\n", urb);
+ oz_dbg(ON, "ERROR Unknown URB %p\n", urb);
} else {
- static unsigned long last_time;
atomic_dec(&g_pending_urbs);
- oz_trace2(OZ_TRACE_URB,
- "%lu: giveback_urb(%p,%x) %lu %lu pending:%d\n",
- jiffies, urb, status, jiffies-submit_jiffies,
- jiffies-last_time, atomic_read(&g_pending_urbs));
- last_time = jiffies;
usb_hcd_giveback_urb(hcd, urb, status);
}
spin_lock(&g_tasklet_lock);
@@ -387,14 +412,14 @@ static void oz_complete_urb(struct usb_hcd *hcd, struct urb *urb,
if (cancel_urbl)
oz_free_urb_link(cancel_urbl);
}
-/*------------------------------------------------------------------------------
+
+/*
* Deallocates an endpoint including deallocating any associated stream and
* returning any queued urbs to the core.
* Context: softirq
*/
static void oz_ep_free(struct oz_port *port, struct oz_endpoint *ep)
{
- oz_trace("oz_ep_free()\n");
if (port) {
struct list_head list;
struct oz_hcd *ozhcd = port->ozhcd;
@@ -409,19 +434,20 @@ static void oz_ep_free(struct oz_port *port, struct oz_endpoint *ep)
list_splice_tail(&list, &ozhcd->orphanage);
spin_unlock_bh(&ozhcd->hcd_lock);
}
- oz_trace("Freeing endpoint memory\n");
+ oz_dbg(ON, "Freeing endpoint memory\n");
kfree(ep);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static void oz_complete_buffered_urb(struct oz_port *port,
struct oz_endpoint *ep,
struct urb *urb)
{
- u8 data_len, available_space, copy_len;
+ int data_len, available_space, copy_len;
- memcpy(&data_len, &ep->buffer[ep->out_ix], sizeof(u8));
+ data_len = ep->buffer[ep->out_ix];
if (data_len <= urb->transfer_buffer_length)
available_space = data_len;
else
@@ -446,28 +472,29 @@ static void oz_complete_buffered_urb(struct oz_port *port,
ep->out_ix = 0;
ep->buffered_units--;
- oz_trace("Trying to give back buffered frame of size=%d\n",
- available_space);
- oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+ oz_dbg(ON, "Trying to give back buffered frame of size=%d\n",
+ available_space);
+ oz_complete_urb(port->ozhcd->hcd, urb, 0);
}
-/*------------------------------------------------------------------------------
+/*
* Context: softirq
*/
static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
struct urb *urb, u8 req_id)
{
struct oz_urb_link *urbl;
- struct oz_endpoint *ep;
+ struct oz_endpoint *ep = NULL;
int err = 0;
+
if (ep_addr >= OZ_NB_ENDPOINTS) {
- oz_trace("Invalid endpoint number in oz_enqueue_ep_urb().\n");
+ oz_dbg(ON, "%s: Invalid endpoint number\n", __func__);
return -EINVAL;
}
urbl = oz_alloc_urb_link();
if (!urbl)
return -ENOMEM;
- urbl->submit_jiffies = jiffies;
+ urbl->submit_counter = 0;
urbl->urb = urb;
urbl->req_id = req_id;
urbl->ep_num = ep_addr;
@@ -480,15 +507,20 @@ static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
*/
if (urb->unlinked) {
spin_unlock_bh(&port->ozhcd->hcd_lock);
- oz_trace("urb %p unlinked so complete immediately\n", urb);
- oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+ oz_dbg(ON, "urb %p unlinked so complete immediately\n", urb);
+ oz_complete_urb(port->ozhcd->hcd, urb, 0);
oz_free_urb_link(urbl);
return 0;
}
+
if (in_dir)
ep = port->in_ep[ep_addr];
else
ep = port->out_ep[ep_addr];
+ if (!ep) {
+ err = -ENOMEM;
+ goto out;
+ }
/*For interrupt endpoint check for buffered data
* & complete urb
@@ -501,21 +533,23 @@ static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
return 0;
}
- if (ep && port->hpd) {
+ if (port->hpd) {
list_add_tail(&urbl->link, &ep->urb_list);
if (!in_dir && ep_addr && (ep->credit < 0)) {
- ep->last_jiffies = jiffies;
+ getrawmonotonic(&ep->timestamp);
ep->credit = 0;
}
} else {
err = -EPIPE;
}
+out:
spin_unlock_bh(&port->ozhcd->hcd_lock);
if (err)
oz_free_urb_link(urbl);
return err;
}
-/*------------------------------------------------------------------------------
+
+/*
* Removes an urb from the queue in the endpoint.
* Returns 0 if it is found and -EIDRM otherwise.
* Context: softirq
@@ -525,6 +559,7 @@ static int oz_dequeue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
{
struct oz_urb_link *urbl = NULL;
struct oz_endpoint *ep;
+
spin_lock_bh(&port->ozhcd->hcd_lock);
if (in_dir)
ep = port->in_ep[ep_addr];
@@ -546,7 +581,8 @@ static int oz_dequeue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
oz_free_urb_link(urbl);
return urbl ? 0 : -EIDRM;
}
-/*------------------------------------------------------------------------------
+
+/*
* Finds an urb given its request id.
* Context: softirq
*/
@@ -555,7 +591,7 @@ static struct urb *oz_find_urb_by_id(struct oz_port *port, int ep_ix,
{
struct oz_hcd *ozhcd = port->ozhcd;
struct urb *urb = NULL;
- struct oz_urb_link *urbl = NULL;
+ struct oz_urb_link *urbl;
struct oz_endpoint *ep;
spin_lock_bh(&ozhcd->hcd_lock);
@@ -578,7 +614,8 @@ static struct urb *oz_find_urb_by_id(struct oz_port *port, int ep_ix,
oz_free_urb_link(urbl);
return urb;
}
-/*------------------------------------------------------------------------------
+
+/*
* Pre-condition: Port lock must be held.
* Context: softirq
*/
@@ -592,12 +629,14 @@ static void oz_acquire_port(struct oz_port *port, void *hpd)
oz_usb_get(hpd);
port->hpd = hpd;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static struct oz_hcd *oz_hcd_claim(void)
{
struct oz_hcd *ozhcd;
+
spin_lock_bh(&g_hcdlock);
ozhcd = g_ozhcd;
if (ozhcd)
@@ -605,7 +644,8 @@ static struct oz_hcd *oz_hcd_claim(void)
spin_unlock_bh(&g_hcdlock);
return ozhcd;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static inline void oz_hcd_put(struct oz_hcd *ozhcd)
@@ -613,7 +653,8 @@ static inline void oz_hcd_put(struct oz_hcd *ozhcd)
if (ozhcd)
usb_put_hcd(ozhcd->hcd);
}
-/*------------------------------------------------------------------------------
+
+/*
* This is called by the protocol handler to notify that a PD has arrived.
* We allocate a port to associate with the PD and create a structure for
* endpoint 0. This port is made the connection port.
@@ -625,75 +666,74 @@ static inline void oz_hcd_put(struct oz_hcd *ozhcd)
* probably very rare indeed.
* Context: softirq
*/
-void *oz_hcd_pd_arrived(void *hpd)
+struct oz_port *oz_hcd_pd_arrived(void *hpd)
{
int i;
- void *hport = NULL;
- struct oz_hcd *ozhcd = NULL;
+ struct oz_port *hport;
+ struct oz_hcd *ozhcd;
struct oz_endpoint *ep;
- oz_trace("oz_hcd_pd_arrived()\n");
+
ozhcd = oz_hcd_claim();
- if (ozhcd == NULL)
+ if (!ozhcd)
return NULL;
/* Allocate an endpoint object in advance (before holding hcd lock) to
* use for out endpoint 0.
*/
- ep = oz_ep_alloc(GFP_ATOMIC, 0);
+ ep = oz_ep_alloc(0, GFP_ATOMIC);
+ if (!ep)
+ goto err_put;
+
spin_lock_bh(&ozhcd->hcd_lock);
- if (ozhcd->conn_port >= 0) {
- spin_unlock_bh(&ozhcd->hcd_lock);
- oz_trace("conn_port >= 0\n");
- goto out;
- }
+ if (ozhcd->conn_port >= 0)
+ goto err_unlock;
+
for (i = 0; i < OZ_NB_PORTS; i++) {
struct oz_port *port = &ozhcd->ports[i];
+
spin_lock(&port->port_lock);
- if ((port->flags & OZ_PORT_F_PRESENT) == 0) {
+ if (!(port->flags & (OZ_PORT_F_PRESENT | OZ_PORT_F_CHANGED))) {
oz_acquire_port(port, hpd);
spin_unlock(&port->port_lock);
break;
}
spin_unlock(&port->port_lock);
}
- if (i < OZ_NB_PORTS) {
- oz_trace("Setting conn_port = %d\n", i);
- ozhcd->conn_port = i;
- /* Attach out endpoint 0.
- */
- ozhcd->ports[i].out_ep[0] = ep;
- ep = NULL;
- hport = &ozhcd->ports[i];
- spin_unlock_bh(&ozhcd->hcd_lock);
- if (ozhcd->flags & OZ_HDC_F_SUSPENDED) {
- oz_trace("Resuming root hub\n");
- usb_hcd_resume_root_hub(ozhcd->hcd);
- }
- usb_hcd_poll_rh_status(ozhcd->hcd);
- } else {
- spin_unlock_bh(&ozhcd->hcd_lock);
- }
-out:
- if (ep) /* ep is non-null if not used. */
- oz_ep_free(NULL, ep);
+ if (i == OZ_NB_PORTS)
+ goto err_unlock;
+
+ ozhcd->conn_port = i;
+ hport = &ozhcd->ports[i];
+ hport->out_ep[0] = ep;
+ spin_unlock_bh(&ozhcd->hcd_lock);
+ if (ozhcd->flags & OZ_HDC_F_SUSPENDED)
+ usb_hcd_resume_root_hub(ozhcd->hcd);
+ usb_hcd_poll_rh_status(ozhcd->hcd);
oz_hcd_put(ozhcd);
+
return hport;
+
+err_unlock:
+ spin_unlock_bh(&ozhcd->hcd_lock);
+ oz_ep_free(NULL, ep);
+err_put:
+ oz_hcd_put(ozhcd);
+ return NULL;
}
-/*------------------------------------------------------------------------------
+
+/*
* This is called by the protocol handler to notify that the PD has gone away.
* We need to deallocate all resources and then request that the root hub is
* polled. We release the reference we hold on the PD.
* Context: softirq
*/
-void oz_hcd_pd_departed(void *hport)
+void oz_hcd_pd_departed(struct oz_port *port)
{
- struct oz_port *port = (struct oz_port *)hport;
struct oz_hcd *ozhcd;
void *hpd;
struct oz_endpoint *ep = NULL;
- oz_trace("oz_hcd_pd_departed()\n");
if (port == NULL) {
- oz_trace("oz_hcd_pd_departed() port = 0\n");
+ oz_dbg(ON, "%s: port = 0\n", __func__);
return;
}
ozhcd = port->ozhcd;
@@ -704,7 +744,7 @@ void oz_hcd_pd_departed(void *hport)
spin_lock_bh(&ozhcd->hcd_lock);
if ((ozhcd->conn_port >= 0) &&
(port == &ozhcd->ports[ozhcd->conn_port])) {
- oz_trace("Clearing conn_port\n");
+ oz_dbg(ON, "Clearing conn_port\n");
ozhcd->conn_port = -1;
}
spin_lock(&port->port_lock);
@@ -717,9 +757,10 @@ void oz_hcd_pd_departed(void *hport)
hpd = port->hpd;
port->hpd = NULL;
port->bus_addr = 0xff;
+ port->config_num = 0;
port->flags &= ~(OZ_PORT_F_PRESENT | OZ_PORT_F_DYING);
port->flags |= OZ_PORT_F_CHANGED;
- port->status &= ~USB_PORT_STAT_CONNECTION;
+ port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
port->status |= (USB_PORT_STAT_C_CONNECTION << 16);
/* If there is an endpont 0 then clear the pointer while we hold
* the spinlock be we deallocate it after releasing the lock.
@@ -734,7 +775,8 @@ void oz_hcd_pd_departed(void *hport)
usb_hcd_poll_rh_status(ozhcd->hcd);
oz_usb_put(hpd);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
void oz_hcd_pd_reset(void *hpd, void *hport)
@@ -743,7 +785,8 @@ void oz_hcd_pd_reset(void *hpd, void *hport)
*/
struct oz_port *port = (struct oz_port *)hport;
struct oz_hcd *ozhcd = port->ozhcd;
- oz_trace("PD Reset\n");
+
+ oz_dbg(ON, "PD Reset\n");
spin_lock_bh(&port->port_lock);
port->flags |= OZ_PORT_F_CHANGED;
port->status |= USB_PORT_STAT_RESET;
@@ -752,7 +795,8 @@ void oz_hcd_pd_reset(void *hpd, void *hport)
oz_clean_endpoints_for_config(ozhcd->hcd, port);
usb_hcd_poll_rh_status(ozhcd->hcd);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, const u8 *desc,
@@ -762,8 +806,8 @@ void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, const u8 *desc,
struct urb *urb;
int err = 0;
- oz_trace("oz_hcd_get_desc_cnf length = %d offs = %d tot_size = %d\n",
- length, offset, total_size);
+ oz_dbg(ON, "oz_hcd_get_desc_cnf length = %d offs = %d tot_size = %d\n",
+ length, offset, total_size);
urb = oz_find_urb_by_id(port, 0, req_id);
if (!urb)
return;
@@ -795,54 +839,52 @@ void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, const u8 *desc,
}
}
urb->actual_length = total_size;
- oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+ oz_complete_urb(port->ozhcd->hcd, urb, 0);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
-#ifdef WANT_TRACE
static void oz_display_conf_type(u8 t)
{
switch (t) {
case USB_REQ_GET_STATUS:
- oz_trace("USB_REQ_GET_STATUS - cnf\n");
+ oz_dbg(ON, "USB_REQ_GET_STATUS - cnf\n");
break;
case USB_REQ_CLEAR_FEATURE:
- oz_trace("USB_REQ_CLEAR_FEATURE - cnf\n");
+ oz_dbg(ON, "USB_REQ_CLEAR_FEATURE - cnf\n");
break;
case USB_REQ_SET_FEATURE:
- oz_trace("USB_REQ_SET_FEATURE - cnf\n");
+ oz_dbg(ON, "USB_REQ_SET_FEATURE - cnf\n");
break;
case USB_REQ_SET_ADDRESS:
- oz_trace("USB_REQ_SET_ADDRESS - cnf\n");
+ oz_dbg(ON, "USB_REQ_SET_ADDRESS - cnf\n");
break;
case USB_REQ_GET_DESCRIPTOR:
- oz_trace("USB_REQ_GET_DESCRIPTOR - cnf\n");
+ oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - cnf\n");
break;
case USB_REQ_SET_DESCRIPTOR:
- oz_trace("USB_REQ_SET_DESCRIPTOR - cnf\n");
+ oz_dbg(ON, "USB_REQ_SET_DESCRIPTOR - cnf\n");
break;
case USB_REQ_GET_CONFIGURATION:
- oz_trace("USB_REQ_GET_CONFIGURATION - cnf\n");
+ oz_dbg(ON, "USB_REQ_GET_CONFIGURATION - cnf\n");
break;
case USB_REQ_SET_CONFIGURATION:
- oz_trace("USB_REQ_SET_CONFIGURATION - cnf\n");
+ oz_dbg(ON, "USB_REQ_SET_CONFIGURATION - cnf\n");
break;
case USB_REQ_GET_INTERFACE:
- oz_trace("USB_REQ_GET_INTERFACE - cnf\n");
+ oz_dbg(ON, "USB_REQ_GET_INTERFACE - cnf\n");
break;
case USB_REQ_SET_INTERFACE:
- oz_trace("USB_REQ_SET_INTERFACE - cnf\n");
+ oz_dbg(ON, "USB_REQ_SET_INTERFACE - cnf\n");
break;
case USB_REQ_SYNCH_FRAME:
- oz_trace("USB_REQ_SYNCH_FRAME - cnf\n");
+ oz_dbg(ON, "USB_REQ_SYNCH_FRAME - cnf\n");
break;
}
}
-#else
-#define oz_display_conf_type(__x)
-#endif /* WANT_TRACE */
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static void oz_hcd_complete_set_config(struct oz_port *port, struct urb *urb,
@@ -850,6 +892,7 @@ static void oz_hcd_complete_set_config(struct oz_port *port, struct urb *urb,
{
int rc = 0;
struct usb_hcd *hcd = port->ozhcd->hcd;
+
if (rcode == 0) {
port->config_num = config_num;
oz_clean_endpoints_for_config(hcd, port);
@@ -860,9 +903,10 @@ static void oz_hcd_complete_set_config(struct oz_port *port, struct urb *urb,
} else {
rc = -ENOMEM;
}
- oz_complete_urb(hcd, urb, rc, 0);
+ oz_complete_urb(hcd, urb, rc);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static void oz_hcd_complete_set_interface(struct oz_port *port, struct urb *urb,
@@ -870,10 +914,11 @@ static void oz_hcd_complete_set_interface(struct oz_port *port, struct urb *urb,
{
struct usb_hcd *hcd = port->ozhcd->hcd;
int rc = 0;
- if (rcode == 0) {
+
+ if ((rcode == 0) && (port->config_num > 0)) {
struct usb_host_config *config;
struct usb_host_interface *intf;
- oz_trace("Set interface %d alt %d\n", if_num, alt);
+ oz_dbg(ON, "Set interface %d alt %d\n", if_num, alt);
oz_clean_endpoints_for_interface(hcd, port, if_num);
config = &urb->dev->config[port->config_num-1];
intf = &config->intf_cache[if_num]->altsetting[alt];
@@ -885,9 +930,10 @@ static void oz_hcd_complete_set_interface(struct oz_port *port, struct urb *urb,
} else {
rc = -ENOMEM;
}
- oz_complete_urb(hcd, urb, rc, 0);
+ oz_complete_urb(hcd, urb, rc);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, const u8 *data,
@@ -900,10 +946,10 @@ void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, const u8 *data,
unsigned windex;
unsigned wvalue;
- oz_trace("oz_hcd_control_cnf rcode=%u len=%d\n", rcode, data_len);
+ oz_dbg(ON, "oz_hcd_control_cnf rcode=%u len=%d\n", rcode, data_len);
urb = oz_find_urb_by_id(port, 0, req_id);
if (!urb) {
- oz_trace("URB not found\n");
+ oz_dbg(ON, "URB not found\n");
return;
}
setup = (struct usb_ctrlrequest *)urb->setup_packet;
@@ -922,12 +968,12 @@ void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, const u8 *data,
(u8)windex, (u8)wvalue);
break;
default:
- oz_complete_urb(hcd, urb, 0, 0);
+ oz_complete_urb(hcd, urb, 0);
}
} else {
int copy_len;
- oz_trace("VENDOR-CLASS - cnf\n");
+ oz_dbg(ON, "VENDOR-CLASS - cnf\n");
if (data_len) {
if (data_len <= urb->transfer_buffer_length)
copy_len = data_len;
@@ -936,10 +982,11 @@ void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, const u8 *data,
memcpy(urb->transfer_buffer, data, copy_len);
urb->actual_length = copy_len;
}
- oz_complete_urb(hcd, urb, 0, 0);
+ oz_complete_urb(hcd, urb, 0);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static int oz_hcd_buffer_data(struct oz_endpoint *ep, const u8 *data,
@@ -947,13 +994,14 @@ static int oz_hcd_buffer_data(struct oz_endpoint *ep, const u8 *data,
{
int space;
int copy_len;
+
if (!ep->buffer)
return -1;
space = ep->out_ix-ep->in_ix-1;
if (space < 0)
space += ep->buffer_size;
if (space < (data_len+1)) {
- oz_trace("Buffer full\n");
+ oz_dbg(ON, "Buffer full\n");
return -1;
}
ep->buffer[ep->in_ix] = (u8)data_len;
@@ -975,7 +1023,8 @@ static int oz_hcd_buffer_data(struct oz_endpoint *ep, const u8 *data,
ep->buffered_units++;
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
void oz_hcd_data_ind(void *hport, u8 endpoint, const u8 *data, int data_len)
@@ -983,6 +1032,7 @@ void oz_hcd_data_ind(void *hport, u8 endpoint, const u8 *data, int data_len)
struct oz_port *port = (struct oz_port *)hport;
struct oz_endpoint *ep;
struct oz_hcd *ozhcd = port->ozhcd;
+
spin_lock_bh(&ozhcd->hcd_lock);
ep = port->in_ep[endpoint & USB_ENDPOINT_NUMBER_MASK];
if (ep == NULL)
@@ -1006,10 +1056,10 @@ void oz_hcd_data_ind(void *hport, u8 endpoint, const u8 *data, int data_len)
copy_len = urb->transfer_buffer_length;
memcpy(urb->transfer_buffer, data, copy_len);
urb->actual_length = copy_len;
- oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+ oz_complete_urb(port->ozhcd->hcd, urb, 0);
return;
} else {
- oz_trace("buffering frame as URB is not available\n");
+ oz_dbg(ON, "buffering frame as URB is not available\n");
oz_hcd_buffer_data(ep, data, data_len);
}
break;
@@ -1020,14 +1070,16 @@ void oz_hcd_data_ind(void *hport, u8 endpoint, const u8 *data, int data_len)
done:
spin_unlock_bh(&ozhcd->hcd_lock);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: unknown
*/
static inline int oz_usb_get_frame_number(void)
{
- return jiffies_to_msecs(get_jiffies_64());
+ return atomic_inc_return(&g_usb_frame_number);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_hcd_heartbeat(void *hport)
@@ -1041,7 +1093,9 @@ int oz_hcd_heartbeat(void *hport)
struct list_head *n;
struct urb *urb;
struct oz_endpoint *ep;
- unsigned long now = jiffies;
+ struct timespec ts, delta;
+
+ getrawmonotonic(&ts);
INIT_LIST_HEAD(&xfr_list);
/* Check the OUT isoc endpoints to see if any URB data can be sent.
*/
@@ -1050,10 +1104,11 @@ int oz_hcd_heartbeat(void *hport)
ep = ep_from_link(e);
if (ep->credit < 0)
continue;
- ep->credit += jiffies_to_msecs(now - ep->last_jiffies);
+ delta = timespec_sub(ts, ep->timestamp);
+ ep->credit += div_u64(timespec_to_ns(&delta), NSEC_PER_MSEC);
if (ep->credit > ep->credit_ceiling)
ep->credit = ep->credit_ceiling;
- ep->last_jiffies = now;
+ ep->timestamp = ts;
while (ep->credit && !list_empty(&ep->urb_list)) {
urbl = list_first_entry(&ep->urb_list,
struct oz_urb_link, link);
@@ -1061,6 +1116,8 @@ int oz_hcd_heartbeat(void *hport)
if ((ep->credit + 1) < urb->number_of_packets)
break;
ep->credit -= urb->number_of_packets;
+ if (ep->credit < 0)
+ ep->credit = 0;
list_move_tail(&urbl->link, &xfr_list);
}
}
@@ -1068,16 +1125,14 @@ int oz_hcd_heartbeat(void *hport)
/* Send to PD and complete URBs.
*/
list_for_each_safe(e, n, &xfr_list) {
- unsigned long t;
urbl = container_of(e, struct oz_urb_link, link);
urb = urbl->urb;
- t = urbl->submit_jiffies;
list_del_init(e);
urb->error_count = 0;
urb->start_frame = oz_usb_get_frame_number();
oz_usb_send_isoc(port->hpd, urbl->ep_num, urb);
oz_free_urb_link(urbl);
- oz_complete_urb(port->ozhcd->hcd, urb, 0, t);
+ oz_complete_urb(port->ozhcd->hcd, urb, 0);
}
/* Check the IN isoc endpoints to see if any URBs can be completed.
*/
@@ -1088,13 +1143,14 @@ int oz_hcd_heartbeat(void *hport)
if (ep->buffered_units >= OZ_IN_BUFFERING_UNITS) {
ep->flags &= ~OZ_F_EP_BUFFERING;
ep->credit = 0;
- ep->last_jiffies = now;
+ ep->timestamp = ts;
ep->start_frame = 0;
}
continue;
}
- ep->credit += jiffies_to_msecs(now - ep->last_jiffies);
- ep->last_jiffies = now;
+ delta = timespec_sub(ts, ep->timestamp);
+ ep->credit += div_u64(timespec_to_ns(&delta), NSEC_PER_MSEC);
+ ep->timestamp = ts;
while (!list_empty(&ep->urb_list)) {
struct oz_urb_link *urbl =
list_first_entry(&ep->urb_list,
@@ -1103,7 +1159,7 @@ int oz_hcd_heartbeat(void *hport)
int len = 0;
int copy_len;
int i;
- if ((ep->credit + 1) < urb->number_of_packets)
+ if (ep->credit < urb->number_of_packets)
break;
if (ep->buffered_units < urb->number_of_packets)
break;
@@ -1149,7 +1205,7 @@ int oz_hcd_heartbeat(void *hport)
urb = urbl->urb;
list_del_init(e);
oz_free_urb_link(urbl);
- oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+ oz_complete_urb(port->ozhcd->hcd, urb, 0);
}
/* Check if there are any ep0 requests that have timed out.
* If so resent to PD.
@@ -1161,11 +1217,12 @@ int oz_hcd_heartbeat(void *hport)
spin_lock_bh(&ozhcd->hcd_lock);
list_for_each_safe(e, n, &ep->urb_list) {
urbl = container_of(e, struct oz_urb_link, link);
- if (time_after(now, urbl->submit_jiffies+HZ/2)) {
- oz_trace("%ld: Request 0x%p timeout\n",
- now, urbl->urb);
- urbl->submit_jiffies = now;
+ if (urbl->submit_counter > EP0_TIMEOUT_COUNTER) {
+ oz_dbg(ON, "Request 0x%p timeout\n", urbl->urb);
list_move_tail(e, &xfr_list);
+ urbl->submit_counter = 0;
+ } else {
+ urbl->submit_counter++;
}
}
if (!list_empty(&ep->urb_list))
@@ -1175,14 +1232,15 @@ int oz_hcd_heartbeat(void *hport)
while (e != &xfr_list) {
urbl = container_of(e, struct oz_urb_link, link);
e = e->next;
- oz_trace("Resending request to PD.\n");
+ oz_dbg(ON, "Resending request to PD\n");
oz_process_ep0_urb(ozhcd, urbl->urb, GFP_ATOMIC);
oz_free_urb_link(urbl);
}
}
return rc;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static int oz_build_endpoints_for_interface(struct usb_hcd *hcd,
@@ -1193,7 +1251,10 @@ static int oz_build_endpoints_for_interface(struct usb_hcd *hcd,
int i;
int if_ix = intf->desc.bInterfaceNumber;
int request_heartbeat = 0;
- oz_trace("interface[%d] = %p\n", if_ix, intf);
+
+ oz_dbg(ON, "interface[%d] = %p\n", if_ix, intf);
+ if (if_ix >= port->num_iface || port->iface == NULL)
+ return -ENOMEM;
for (i = 0; i < intf->desc.bNumEndpoints; i++) {
struct usb_host_endpoint *hep = &intf->endpoint[i];
u8 ep_addr = hep->desc.bEndpointAddress;
@@ -1201,20 +1262,20 @@ static int oz_build_endpoints_for_interface(struct usb_hcd *hcd,
struct oz_endpoint *ep;
int buffer_size = 0;
- oz_trace("%d bEndpointAddress = %x\n", i, ep_addr);
+ oz_dbg(ON, "%d bEndpointAddress = %x\n", i, ep_addr);
if (ep_addr & USB_ENDPOINT_DIR_MASK) {
switch (hep->desc.bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_ISOC:
- buffer_size = 24*1024;
+ buffer_size = OZ_EP_BUFFER_SIZE_ISOC;
break;
case USB_ENDPOINT_XFER_INT:
- buffer_size = 128;
+ buffer_size = OZ_EP_BUFFER_SIZE_INT;
break;
}
}
- ep = oz_ep_alloc(mem_flags, buffer_size);
+ ep = oz_ep_alloc(buffer_size, mem_flags);
if (!ep) {
oz_clean_endpoints_for_interface(hcd, port, if_ix);
return -ENOMEM;
@@ -1223,8 +1284,8 @@ static int oz_build_endpoints_for_interface(struct usb_hcd *hcd,
ep->ep_num = ep_num;
if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_ISOC) {
- oz_trace("wMaxPacketSize = %d\n",
- usb_endpoint_maxp(&hep->desc));
+ oz_dbg(ON, "wMaxPacketSize = %d\n",
+ usb_endpoint_maxp(&hep->desc));
ep->credit_ceiling = 200;
if (ep_addr & USB_ENDPOINT_DIR_MASK) {
ep->flags |= OZ_F_EP_BUFFERING;
@@ -1259,7 +1320,8 @@ static int oz_build_endpoints_for_interface(struct usb_hcd *hcd,
}
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static void oz_clean_endpoints_for_interface(struct usb_hcd *hcd,
@@ -1270,7 +1332,7 @@ static void oz_clean_endpoints_for_interface(struct usb_hcd *hcd,
int i;
struct list_head ep_list;
- oz_trace("Deleting endpoints for interface %d\n", if_ix);
+ oz_dbg(ON, "Deleting endpoints for interface %d\n", if_ix);
if (if_ix >= port->num_iface)
return;
INIT_LIST_HEAD(&ep_list);
@@ -1304,7 +1366,8 @@ static void oz_clean_endpoints_for_interface(struct usb_hcd *hcd,
oz_ep_free(port, ep);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static int oz_build_endpoints_for_config(struct usb_hcd *hcd,
@@ -1314,6 +1377,7 @@ static int oz_build_endpoints_for_config(struct usb_hcd *hcd,
struct oz_hcd *ozhcd = port->ozhcd;
int i;
int num_iface = config->desc.bNumInterfaces;
+
if (num_iface) {
struct oz_interface *iface;
@@ -1338,7 +1402,8 @@ fail:
oz_clean_endpoints_for_config(hcd, port);
return -1;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static void oz_clean_endpoints_for_config(struct usb_hcd *hcd,
@@ -1346,25 +1411,28 @@ static void oz_clean_endpoints_for_config(struct usb_hcd *hcd,
{
struct oz_hcd *ozhcd = port->ozhcd;
int i;
- oz_trace("Deleting endpoints for configuration.\n");
+
+ oz_dbg(ON, "Deleting endpoints for configuration\n");
for (i = 0; i < port->num_iface; i++)
oz_clean_endpoints_for_interface(hcd, port, i);
spin_lock_bh(&ozhcd->hcd_lock);
if (port->iface) {
- oz_trace("Freeing interfaces object.\n");
+ oz_dbg(ON, "Freeing interfaces object\n");
kfree(port->iface);
port->iface = NULL;
}
port->num_iface = 0;
spin_unlock_bh(&ozhcd->hcd_lock);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
static void *oz_claim_hpd(struct oz_port *port)
{
- void *hpd = NULL;
+ void *hpd;
struct oz_hcd *ozhcd = port->ozhcd;
+
spin_lock_bh(&ozhcd->hcd_lock);
hpd = port->hpd;
if (hpd)
@@ -1372,7 +1440,8 @@ static void *oz_claim_hpd(struct oz_port *port)
spin_unlock_bh(&ozhcd->hcd_lock);
return hpd;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
@@ -1382,7 +1451,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
unsigned windex;
unsigned wvalue;
unsigned wlength;
- void *hpd = NULL;
+ void *hpd;
u8 req_id;
int rc = 0;
unsigned complete = 0;
@@ -1390,7 +1459,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
int port_ix = -1;
struct oz_port *port = NULL;
- oz_trace2(OZ_TRACE_URB, "%lu: oz_process_ep0_urb(%p)\n", jiffies, urb);
+ oz_dbg(URB, "[%s]:(%p)\n", __func__, urb);
port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum);
if (port_ix < 0) {
rc = -EPIPE;
@@ -1399,8 +1468,8 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
port = &ozhcd->ports[port_ix];
if (((port->flags & OZ_PORT_F_PRESENT) == 0)
|| (port->flags & OZ_PORT_F_DYING)) {
- oz_trace("Refusing URB port_ix = %d devnum = %d\n",
- port_ix, urb->dev->devnum);
+ oz_dbg(ON, "Refusing URB port_ix = %d devnum = %d\n",
+ port_ix, urb->dev->devnum);
rc = -EPIPE;
goto out;
}
@@ -1411,17 +1480,16 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
windex = le16_to_cpu(setup->wIndex);
wvalue = le16_to_cpu(setup->wValue);
wlength = le16_to_cpu(setup->wLength);
- oz_trace2(OZ_TRACE_CTRL_DETAIL, "bRequestType = %x\n",
- setup->bRequestType);
- oz_trace2(OZ_TRACE_CTRL_DETAIL, "bRequest = %x\n", setup->bRequest);
- oz_trace2(OZ_TRACE_CTRL_DETAIL, "wValue = %x\n", wvalue);
- oz_trace2(OZ_TRACE_CTRL_DETAIL, "wIndex = %x\n", windex);
- oz_trace2(OZ_TRACE_CTRL_DETAIL, "wLength = %x\n", wlength);
+ oz_dbg(CTRL_DETAIL, "bRequestType = %x\n", setup->bRequestType);
+ oz_dbg(CTRL_DETAIL, "bRequest = %x\n", setup->bRequest);
+ oz_dbg(CTRL_DETAIL, "wValue = %x\n", wvalue);
+ oz_dbg(CTRL_DETAIL, "wIndex = %x\n", windex);
+ oz_dbg(CTRL_DETAIL, "wLength = %x\n", wlength);
req_id = port->next_req_id++;
hpd = oz_claim_hpd(port);
if (hpd == NULL) {
- oz_trace("Cannot claim port\n");
+ oz_dbg(ON, "Cannot claim port\n");
rc = -EPIPE;
goto out;
}
@@ -1431,30 +1499,31 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
*/
switch (setup->bRequest) {
case USB_REQ_GET_DESCRIPTOR:
- oz_trace("USB_REQ_GET_DESCRIPTOR - req\n");
+ oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - req\n");
break;
case USB_REQ_SET_ADDRESS:
- oz_trace("USB_REQ_SET_ADDRESS - req\n");
- oz_trace("Port %d address is 0x%x\n", ozhcd->conn_port,
- (u8)le16_to_cpu(setup->wValue));
+ oz_dbg(ON, "USB_REQ_SET_ADDRESS - req\n");
+ oz_dbg(ON, "Port %d address is 0x%x\n",
+ ozhcd->conn_port,
+ (u8)le16_to_cpu(setup->wValue));
spin_lock_bh(&ozhcd->hcd_lock);
if (ozhcd->conn_port >= 0) {
ozhcd->ports[ozhcd->conn_port].bus_addr =
(u8)le16_to_cpu(setup->wValue);
- oz_trace("Clearing conn_port\n");
+ oz_dbg(ON, "Clearing conn_port\n");
ozhcd->conn_port = -1;
}
spin_unlock_bh(&ozhcd->hcd_lock);
complete = 1;
break;
case USB_REQ_SET_CONFIGURATION:
- oz_trace("USB_REQ_SET_CONFIGURATION - req\n");
+ oz_dbg(ON, "USB_REQ_SET_CONFIGURATION - req\n");
break;
case USB_REQ_GET_CONFIGURATION:
/* We short circuit this case and reply directly since
* we have the selected configuration number cached.
*/
- oz_trace("USB_REQ_GET_CONFIGURATION - reply now\n");
+ oz_dbg(ON, "USB_REQ_GET_CONFIGURATION - reply now\n");
if (urb->transfer_buffer_length >= 1) {
urb->actual_length = 1;
*((u8 *)urb->transfer_buffer) =
@@ -1468,20 +1537,20 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
/* We short circuit this case and reply directly since
* we have the selected interface alternative cached.
*/
- oz_trace("USB_REQ_GET_INTERFACE - reply now\n");
+ oz_dbg(ON, "USB_REQ_GET_INTERFACE - reply now\n");
if (urb->transfer_buffer_length >= 1) {
urb->actual_length = 1;
*((u8 *)urb->transfer_buffer) =
port->iface[(u8)windex].alt;
- oz_trace("interface = %d alt = %d\n",
- windex, port->iface[(u8)windex].alt);
+ oz_dbg(ON, "interface = %d alt = %d\n",
+ windex, port->iface[(u8)windex].alt);
complete = 1;
} else {
rc = -EPIPE;
}
break;
case USB_REQ_SET_INTERFACE:
- oz_trace("USB_REQ_SET_INTERFACE - req\n");
+ oz_dbg(ON, "USB_REQ_SET_INTERFACE - req\n");
break;
}
}
@@ -1512,13 +1581,14 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
oz_usb_put(hpd);
out:
if (rc || complete) {
- oz_trace("Completing request locally\n");
- oz_complete_urb(ozhcd->hcd, urb, rc, 0);
+ oz_dbg(ON, "Completing request locally\n");
+ oz_complete_urb(ozhcd->hcd, urb, rc);
} else {
oz_usb_request_heartbeat(port->hpd);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
static int oz_urb_process(struct oz_hcd *ozhcd, struct urb *urb)
@@ -1526,6 +1596,7 @@ static int oz_urb_process(struct oz_hcd *ozhcd, struct urb *urb)
int rc = 0;
struct oz_port *port = urb->hcpriv;
u8 ep_addr;
+
/* When we are paranoid we keep a list of urbs which we check against
* before handing one back. This is just for debugging during
* development and should be turned off in the released driver.
@@ -1551,7 +1622,8 @@ static int oz_urb_process(struct oz_hcd *ozhcd, struct urb *urb)
}
return rc;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
static void oz_urb_process_tasklet(unsigned long unused)
@@ -1560,6 +1632,7 @@ static void oz_urb_process_tasklet(unsigned long unused)
struct urb *urb;
struct oz_hcd *ozhcd = oz_hcd_claim();
int rc = 0;
+
if (ozhcd == NULL)
return;
/* This is called from a tasklet so is in softirq context but the urb
@@ -1577,13 +1650,14 @@ static void oz_urb_process_tasklet(unsigned long unused)
oz_free_urb_link(urbl);
rc = oz_urb_process(ozhcd, urb);
if (rc)
- oz_complete_urb(ozhcd->hcd, urb, rc, 0);
+ oz_complete_urb(ozhcd->hcd, urb, rc);
spin_lock_irqsave(&g_tasklet_lock, irq_state);
}
spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
oz_hcd_put(ozhcd);
}
-/*------------------------------------------------------------------------------
+
+/*
* This function searches for the urb in any of the lists it could be in.
* If it is found it is removed from the list and completed. If the urb is
* being processed then it won't be in a list so won't be found. However, the
@@ -1599,13 +1673,14 @@ static void oz_urb_cancel(struct oz_port *port, u8 ep_num, struct urb *urb)
struct oz_hcd *ozhcd;
unsigned long irq_state;
u8 ix;
+
if (port == NULL) {
- oz_trace("ERRORERROR: oz_urb_cancel(%p) port is null\n", urb);
+ oz_dbg(ON, "%s: ERROR: (%p) port is null\n", __func__, urb);
return;
}
ozhcd = port->ozhcd;
if (ozhcd == NULL) {
- oz_trace("ERRORERROR: oz_urb_cancel(%p) ozhcd is null\n", urb);
+ oz_dbg(ON, "%s; ERROR: (%p) ozhcd is null\n", __func__, urb);
return;
}
@@ -1630,7 +1705,7 @@ static void oz_urb_cancel(struct oz_port *port, u8 ep_num, struct urb *urb)
urbl = container_of(e, struct oz_urb_link, link);
if (urbl->urb == urb) {
list_del(e);
- oz_trace("Found urb in orphanage\n");
+ oz_dbg(ON, "Found urb in orphanage\n");
goto out;
}
}
@@ -1646,10 +1721,11 @@ out2:
if (urbl) {
urb->actual_length = 0;
oz_free_urb_link(urbl);
- oz_complete_urb(ozhcd->hcd, urb, -EPIPE, 0);
+ oz_complete_urb(ozhcd->hcd, urb, -EPIPE);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
static void oz_urb_cancel_tasklet(unsigned long unused)
@@ -1657,6 +1733,7 @@ static void oz_urb_cancel_tasklet(unsigned long unused)
unsigned long irq_state;
struct urb *urb;
struct oz_hcd *ozhcd = oz_hcd_claim();
+
if (ozhcd == NULL)
return;
spin_lock_irqsave(&g_tasklet_lock, irq_state);
@@ -1675,7 +1752,8 @@ static void oz_urb_cancel_tasklet(unsigned long unused)
spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
oz_hcd_put(ozhcd);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: unknown
*/
static void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status)
@@ -1686,37 +1764,38 @@ static void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status)
urbl = list_first_entry(&ozhcd->orphanage,
struct oz_urb_link, link);
list_del(&urbl->link);
- oz_complete_urb(ozhcd->hcd, urbl->urb, status, 0);
+ oz_complete_urb(ozhcd->hcd, urbl->urb, status);
oz_free_urb_link(urbl);
}
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: unknown
*/
static int oz_hcd_start(struct usb_hcd *hcd)
{
- oz_trace("oz_hcd_start()\n");
hcd->power_budget = 200;
hcd->state = HC_STATE_RUNNING;
hcd->uses_new_polling = 1;
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: unknown
*/
static void oz_hcd_stop(struct usb_hcd *hcd)
{
- oz_trace("oz_hcd_stop()\n");
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: unknown
*/
static void oz_hcd_shutdown(struct usb_hcd *hcd)
{
- oz_trace("oz_hcd_shutdown()\n");
}
-/*------------------------------------------------------------------------------
+
+/*
* Called to queue an urb for the device.
* This function should return a non-zero error code if it fails the urb but
* should not call usb_hcd_giveback_urb().
@@ -1726,21 +1805,19 @@ static int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
struct oz_hcd *ozhcd = oz_hcd_private(hcd);
- int rc = 0;
+ int rc;
int port_ix;
struct oz_port *port;
unsigned long irq_state;
struct oz_urb_link *urbl;
- oz_trace2(OZ_TRACE_URB, "%lu: oz_hcd_urb_enqueue(%p)\n",
- jiffies, urb);
+
+ oz_dbg(URB, "%s: (%p)\n", __func__, urb);
if (unlikely(ozhcd == NULL)) {
- oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not ozhcd.\n",
- jiffies, urb);
+ oz_dbg(URB, "Refused urb(%p) not ozhcd\n", urb);
return -EPIPE;
}
if (unlikely(hcd->state != HC_STATE_RUNNING)) {
- oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not running.\n",
- jiffies, urb);
+ oz_dbg(URB, "Refused urb(%p) not running\n", urb);
return -EPIPE;
}
port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum);
@@ -1749,9 +1826,10 @@ static int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
port = &ozhcd->ports[port_ix];
if (port == NULL)
return -EPIPE;
- if ((port->flags & OZ_PORT_F_PRESENT) == 0) {
- oz_trace("Refusing URB port_ix = %d devnum = %d\n",
- port_ix, urb->dev->devnum);
+ if (!(port->flags & OZ_PORT_F_PRESENT) ||
+ (port->flags & OZ_PORT_F_CHANGED)) {
+ oz_dbg(ON, "Refusing URB port_ix = %d devnum = %d\n",
+ port_ix, urb->dev->devnum);
return -EPIPE;
}
urb->hcpriv = port;
@@ -1774,14 +1852,16 @@ static int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
atomic_inc(&g_pending_urbs);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
static struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep,
struct urb *urb)
{
- struct oz_urb_link *urbl = NULL;
+ struct oz_urb_link *urbl;
struct list_head *e;
+
if (unlikely(ep == NULL))
return NULL;
list_for_each(e, &ep->urb_list) {
@@ -1798,17 +1878,19 @@ static struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep,
}
return NULL;
}
-/*------------------------------------------------------------------------------
+
+/*
* Called to dequeue a previously submitted urb for the device.
* Context: any
*/
static int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct oz_hcd *ozhcd = oz_hcd_private(hcd);
- struct oz_urb_link *urbl = NULL;
+ struct oz_urb_link *urbl;
int rc;
unsigned long irq_state;
- oz_trace2(OZ_TRACE_URB, "%lu: oz_hcd_urb_dequeue(%p)\n", jiffies, urb);
+
+ oz_dbg(URB, "%s: (%p)\n", __func__, urb);
urbl = oz_alloc_urb_link();
if (unlikely(urbl == NULL))
return -ENOMEM;
@@ -1838,31 +1920,33 @@ static int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
}
return rc;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: unknown
*/
static void oz_hcd_endpoint_disable(struct usb_hcd *hcd,
struct usb_host_endpoint *ep)
{
- oz_trace("oz_hcd_endpoint_disable\n");
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: unknown
*/
static void oz_hcd_endpoint_reset(struct usb_hcd *hcd,
struct usb_host_endpoint *ep)
{
- oz_trace("oz_hcd_endpoint_reset\n");
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: unknown
*/
static int oz_hcd_get_frame_number(struct usb_hcd *hcd)
{
- oz_trace("oz_hcd_get_frame_number\n");
+ oz_dbg(ON, "oz_hcd_get_frame_number\n");
return oz_usb_get_frame_number();
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
* This is called as a consquence of us calling usb_hcd_poll_rh_status() and we
* always do that in softirq context.
@@ -1872,27 +1956,33 @@ static int oz_hcd_hub_status_data(struct usb_hcd *hcd, char *buf)
struct oz_hcd *ozhcd = oz_hcd_private(hcd);
int i;
- oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_status_data()\n");
buf[0] = 0;
+ buf[1] = 0;
spin_lock_bh(&ozhcd->hcd_lock);
for (i = 0; i < OZ_NB_PORTS; i++) {
if (ozhcd->ports[i].flags & OZ_PORT_F_CHANGED) {
- oz_trace2(OZ_TRACE_HUB, "Port %d changed\n", i);
+ oz_dbg(HUB, "Port %d changed\n", i);
ozhcd->ports[i].flags &= ~OZ_PORT_F_CHANGED;
- buf[0] |= 1<<(i+1);
+ if (i < 7)
+ buf[0] |= 1 << (i + 1);
+ else
+ buf[1] |= 1 << (i - 7);
}
}
spin_unlock_bh(&ozhcd->hcd_lock);
- return buf[0] ? 1 : 0;
+ if (buf[0] != 0 || buf[1] != 0)
+ return 2;
+ else
+ return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static void oz_get_hub_descriptor(struct usb_hcd *hcd,
struct usb_hub_descriptor *desc)
{
- oz_trace2(OZ_TRACE_HUB, "GetHubDescriptor\n");
memset(desc, 0, sizeof(*desc));
desc->bDescriptorType = 0x29;
desc->bDescLength = 9;
@@ -1900,7 +1990,8 @@ static void oz_get_hub_descriptor(struct usb_hcd *hcd,
__constant_cpu_to_le16(0x0001);
desc->bNbrPorts = OZ_NB_PORTS;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_set_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex)
@@ -1911,59 +2002,59 @@ static int oz_set_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex)
struct oz_hcd *ozhcd = oz_hcd_private(hcd);
unsigned set_bits = 0;
unsigned clear_bits = 0;
- oz_trace2(OZ_TRACE_HUB, "SetPortFeature\n");
+
if ((port_id < 1) || (port_id > OZ_NB_PORTS))
return -EPIPE;
port = &ozhcd->ports[port_id-1];
switch (wvalue) {
case USB_PORT_FEAT_CONNECTION:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_CONNECTION\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_CONNECTION\n");
break;
case USB_PORT_FEAT_ENABLE:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_ENABLE\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_ENABLE\n");
break;
case USB_PORT_FEAT_SUSPEND:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_SUSPEND\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_SUSPEND\n");
break;
case USB_PORT_FEAT_OVER_CURRENT:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
break;
case USB_PORT_FEAT_RESET:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_RESET\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_RESET\n");
set_bits = USB_PORT_STAT_ENABLE | (USB_PORT_STAT_C_RESET<<16);
clear_bits = USB_PORT_STAT_RESET;
ozhcd->ports[port_id-1].bus_addr = 0;
break;
case USB_PORT_FEAT_POWER:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_POWER\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_POWER\n");
set_bits |= USB_PORT_STAT_POWER;
break;
case USB_PORT_FEAT_LOWSPEED:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_LOWSPEED\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_LOWSPEED\n");
break;
case USB_PORT_FEAT_C_CONNECTION:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_CONNECTION\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_C_CONNECTION\n");
break;
case USB_PORT_FEAT_C_ENABLE:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_ENABLE\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_C_ENABLE\n");
break;
case USB_PORT_FEAT_C_SUSPEND:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_SUSPEND\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_C_SUSPEND\n");
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n");
break;
case USB_PORT_FEAT_C_RESET:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_RESET\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_C_RESET\n");
break;
case USB_PORT_FEAT_TEST:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_TEST\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_TEST\n");
break;
case USB_PORT_FEAT_INDICATOR:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_INDICATOR\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_INDICATOR\n");
break;
default:
- oz_trace2(OZ_TRACE_HUB, "Other %d\n", wvalue);
+ oz_dbg(HUB, "Other %d\n", wvalue);
break;
}
if (set_bits || clear_bits) {
@@ -1972,11 +2063,11 @@ static int oz_set_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex)
port->status |= set_bits;
spin_unlock_bh(&port->port_lock);
}
- oz_trace2(OZ_TRACE_HUB, "Port[%d] status = 0x%x\n", port_id,
- port->status);
+ oz_dbg(HUB, "Port[%d] status = 0x%x\n", port_id, port->status);
return err;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_clear_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex)
@@ -1986,60 +2077,60 @@ static int oz_clear_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex)
u8 port_id = (u8)windex;
struct oz_hcd *ozhcd = oz_hcd_private(hcd);
unsigned clear_bits = 0;
- oz_trace2(OZ_TRACE_HUB, "ClearPortFeature\n");
+
if ((port_id < 1) || (port_id > OZ_NB_PORTS))
return -EPIPE;
port = &ozhcd->ports[port_id-1];
switch (wvalue) {
case USB_PORT_FEAT_CONNECTION:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_CONNECTION\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_CONNECTION\n");
break;
case USB_PORT_FEAT_ENABLE:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_ENABLE\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_ENABLE\n");
clear_bits = USB_PORT_STAT_ENABLE;
break;
case USB_PORT_FEAT_SUSPEND:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_SUSPEND\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_SUSPEND\n");
break;
case USB_PORT_FEAT_OVER_CURRENT:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
break;
case USB_PORT_FEAT_RESET:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_RESET\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_RESET\n");
break;
case USB_PORT_FEAT_POWER:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_POWER\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_POWER\n");
clear_bits |= USB_PORT_STAT_POWER;
break;
case USB_PORT_FEAT_LOWSPEED:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_LOWSPEED\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_LOWSPEED\n");
break;
case USB_PORT_FEAT_C_CONNECTION:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_CONNECTION\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_C_CONNECTION\n");
clear_bits = (USB_PORT_STAT_C_CONNECTION << 16);
break;
case USB_PORT_FEAT_C_ENABLE:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_ENABLE\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_C_ENABLE\n");
clear_bits = (USB_PORT_STAT_C_ENABLE << 16);
break;
case USB_PORT_FEAT_C_SUSPEND:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_SUSPEND\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_C_SUSPEND\n");
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n");
break;
case USB_PORT_FEAT_C_RESET:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_RESET\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_C_RESET\n");
clear_bits = (USB_PORT_FEAT_C_RESET << 16);
break;
case USB_PORT_FEAT_TEST:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_TEST\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_TEST\n");
break;
case USB_PORT_FEAT_INDICATOR:
- oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_INDICATOR\n");
+ oz_dbg(HUB, "USB_PORT_FEAT_INDICATOR\n");
break;
default:
- oz_trace2(OZ_TRACE_HUB, "Other %d\n", wvalue);
+ oz_dbg(HUB, "Other %d\n", wvalue);
break;
}
if (clear_bits) {
@@ -2047,37 +2138,40 @@ static int oz_clear_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex)
port->status &= ~clear_bits;
spin_unlock_bh(&port->port_lock);
}
- oz_trace2(OZ_TRACE_HUB, "Port[%d] status = 0x%x\n", port_id,
- ozhcd->ports[port_id-1].status);
+ oz_dbg(HUB, "Port[%d] status = 0x%x\n",
+ port_id, ozhcd->ports[port_id-1].status);
return err;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_get_port_status(struct usb_hcd *hcd, u16 windex, char *buf)
{
struct oz_hcd *ozhcd;
- u32 status = 0;
+ u32 status;
+
if ((windex < 1) || (windex > OZ_NB_PORTS))
return -EPIPE;
ozhcd = oz_hcd_private(hcd);
- oz_trace2(OZ_TRACE_HUB, "GetPortStatus windex = %d\n", windex);
+ oz_dbg(HUB, "GetPortStatus windex = %d\n", windex);
status = ozhcd->ports[windex-1].status;
put_unaligned(cpu_to_le32(status), (__le32 *)buf);
- oz_trace2(OZ_TRACE_HUB, "Port[%d] status = %x\n", windex, status);
+ oz_dbg(HUB, "Port[%d] status = %x\n", windex, status);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue,
u16 windex, char *buf, u16 wlength)
{
int err = 0;
- oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_control()\n");
+
switch (req_type) {
case ClearHubFeature:
- oz_trace2(OZ_TRACE_HUB, "ClearHubFeature: %d\n", req_type);
+ oz_dbg(HUB, "ClearHubFeature: %d\n", req_type);
break;
case ClearPortFeature:
err = oz_clear_port_feature(hcd, wvalue, windex);
@@ -2086,32 +2180,32 @@ static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue,
oz_get_hub_descriptor(hcd, (struct usb_hub_descriptor *)buf);
break;
case GetHubStatus:
- oz_trace2(OZ_TRACE_HUB, "GetHubStatus: req_type = 0x%x\n",
- req_type);
+ oz_dbg(HUB, "GetHubStatus: req_type = 0x%x\n", req_type);
put_unaligned(__constant_cpu_to_le32(0), (__le32 *)buf);
break;
case GetPortStatus:
err = oz_get_port_status(hcd, windex, buf);
break;
case SetHubFeature:
- oz_trace2(OZ_TRACE_HUB, "SetHubFeature: %d\n", req_type);
+ oz_dbg(HUB, "SetHubFeature: %d\n", req_type);
break;
case SetPortFeature:
err = oz_set_port_feature(hcd, wvalue, windex);
break;
default:
- oz_trace2(OZ_TRACE_HUB, "Other: %d\n", req_type);
+ oz_dbg(HUB, "Other: %d\n", req_type);
break;
}
return err;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_hcd_bus_suspend(struct usb_hcd *hcd)
{
struct oz_hcd *ozhcd;
- oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_suspend()\n");
+
ozhcd = oz_hcd_private(hcd);
spin_lock_bh(&ozhcd->hcd_lock);
hcd->state = HC_STATE_SUSPENDED;
@@ -2119,13 +2213,14 @@ static int oz_hcd_bus_suspend(struct usb_hcd *hcd)
spin_unlock_bh(&ozhcd->hcd_lock);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_hcd_bus_resume(struct usb_hcd *hcd)
{
struct oz_hcd *ozhcd;
- oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_resume()\n");
+
ozhcd = oz_hcd_private(hcd);
spin_lock_bh(&ozhcd->hcd_lock);
ozhcd->flags &= ~OZ_HDC_F_SUSPENDED;
@@ -2133,13 +2228,12 @@ static int oz_hcd_bus_resume(struct usb_hcd *hcd)
spin_unlock_bh(&ozhcd->hcd_lock);
return 0;
}
-/*------------------------------------------------------------------------------
- */
+
static void oz_plat_shutdown(struct platform_device *dev)
{
- oz_trace("oz_plat_shutdown()\n");
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_plat_probe(struct platform_device *dev)
@@ -2148,10 +2242,10 @@ static int oz_plat_probe(struct platform_device *dev)
int err;
struct usb_hcd *hcd;
struct oz_hcd *ozhcd;
- oz_trace("oz_plat_probe()\n");
+
hcd = usb_create_hcd(&g_oz_hc_drv, &dev->dev, dev_name(&dev->dev));
if (hcd == NULL) {
- oz_trace("Failed to created hcd object OK\n");
+ oz_dbg(ON, "Failed to created hcd object OK\n");
return -ENOMEM;
}
ozhcd = oz_hcd_private(hcd);
@@ -2172,7 +2266,7 @@ static int oz_plat_probe(struct platform_device *dev)
}
err = usb_add_hcd(hcd, 0, 0);
if (err) {
- oz_trace("Failed to add hcd object OK\n");
+ oz_dbg(ON, "Failed to add hcd object OK\n");
usb_put_hcd(hcd);
return -1;
}
@@ -2181,14 +2275,15 @@ static int oz_plat_probe(struct platform_device *dev)
spin_unlock_bh(&g_hcdlock);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: unknown
*/
static int oz_plat_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct oz_hcd *ozhcd;
- oz_trace("oz_plat_remove()\n");
+
if (hcd == NULL)
return -1;
ozhcd = oz_hcd_private(hcd);
@@ -2196,42 +2291,45 @@ static int oz_plat_remove(struct platform_device *dev)
if (ozhcd == g_ozhcd)
g_ozhcd = NULL;
spin_unlock_bh(&g_hcdlock);
- oz_trace("Clearing orphanage\n");
+ oz_dbg(ON, "Clearing orphanage\n");
oz_hcd_clear_orphanage(ozhcd, -EPIPE);
- oz_trace("Removing hcd\n");
+ oz_dbg(ON, "Removing hcd\n");
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
oz_empty_link_pool();
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: unknown
*/
static int oz_plat_suspend(struct platform_device *dev, pm_message_t msg)
{
- oz_trace("oz_plat_suspend()\n");
return 0;
}
-/*------------------------------------------------------------------------------
+
+
+/*
* Context: unknown
*/
static int oz_plat_resume(struct platform_device *dev)
{
- oz_trace("oz_plat_resume()\n");
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
int oz_hcd_init(void)
{
int err;
+
if (usb_disabled())
return -ENODEV;
tasklet_init(&g_urb_process_tasklet, oz_urb_process_tasklet, 0);
tasklet_init(&g_urb_cancel_tasklet, oz_urb_cancel_tasklet, 0);
err = platform_driver_register(&g_oz_plat_drv);
- oz_trace("platform_driver_register() returned %d\n", err);
+ oz_dbg(ON, "platform_driver_register() returned %d\n", err);
if (err)
goto error;
g_plat_dev = platform_device_alloc(OZ_PLAT_DEV_NAME, -1);
@@ -2239,11 +2337,11 @@ int oz_hcd_init(void)
err = -ENOMEM;
goto error1;
}
- oz_trace("platform_device_alloc() succeeded\n");
+ oz_dbg(ON, "platform_device_alloc() succeeded\n");
err = platform_device_add(g_plat_dev);
if (err)
goto error2;
- oz_trace("platform_device_add() succeeded\n");
+ oz_dbg(ON, "platform_device_add() succeeded\n");
return 0;
error2:
platform_device_put(g_plat_dev);
@@ -2252,17 +2350,19 @@ error1:
error:
tasklet_disable(&g_urb_process_tasklet);
tasklet_disable(&g_urb_cancel_tasklet);
- oz_trace("oz_hcd_init() failed %d\n", err);
+ oz_dbg(ON, "oz_hcd_init() failed %d\n", err);
return err;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
void oz_hcd_term(void)
{
+ msleep(OZ_HUB_DEBOUNCE_TIMEOUT);
tasklet_kill(&g_urb_process_tasklet);
tasklet_kill(&g_urb_cancel_tasklet);
platform_device_unregister(g_plat_dev);
platform_driver_unregister(&g_oz_plat_drv);
- oz_trace("Pending urbs:%d\n", atomic_read(&g_pending_urbs));
+ oz_dbg(ON, "Pending urbs:%d\n", atomic_read(&g_pending_urbs));
}
diff --git a/drivers/staging/ozwpan/ozhcd.h b/drivers/staging/ozwpan/ozhcd.h
index 9b30dfd0997..55e97b1c707 100644
--- a/drivers/staging/ozwpan/ozhcd.h
+++ b/drivers/staging/ozwpan/ozhcd.h
@@ -7,8 +7,8 @@
int oz_hcd_init(void);
void oz_hcd_term(void);
-void *oz_hcd_pd_arrived(void *ctx);
-void oz_hcd_pd_departed(void *ctx);
+struct oz_port *oz_hcd_pd_arrived(void *ctx);
+void oz_hcd_pd_departed(struct oz_port *hport);
void oz_hcd_pd_reset(void *hpd, void *hport);
#endif /* _OZHCD_H */
diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c
index 51fe9e98c35..d1a5b7a2c16 100644
--- a/drivers/staging/ozwpan/ozmain.c
+++ b/drivers/staging/ozwpan/ozmain.c
@@ -3,6 +3,7 @@
* Released under the GNU General Public License Version 2 (GPLv2).
* -----------------------------------------------------------------------------
*/
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
@@ -10,19 +11,22 @@
#include <linux/netdevice.h>
#include <linux/errno.h>
#include <linux/ieee80211.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
#include "ozpd.h"
#include "ozproto.h"
#include "ozcdev.h"
-#include "oztrace.h"
-/*------------------------------------------------------------------------------
+
+unsigned int oz_dbg_mask = OZ_DEFAULT_DBG_MASK;
+
+/*
* The name of the 802.11 mac device. Empty string is the default value but a
* value can be supplied as a parameter to the module. An empty string means
* bind to nothing. '*' means bind to all netcards - this includes non-802.11
* netcards. Bindings can be added later using an IOCTL.
*/
static char *g_net_dev = "";
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int __init ozwpan_init(void)
@@ -33,7 +37,8 @@ static int __init ozwpan_init(void)
oz_apps_init();
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static void __exit ozwpan_exit(void)
@@ -42,8 +47,7 @@ static void __exit ozwpan_exit(void)
oz_apps_term();
oz_cdev_deregister();
}
-/*------------------------------------------------------------------------------
- */
+
module_param(g_net_dev, charp, S_IRUGO);
module_init(ozwpan_init);
module_exit(ozwpan_exit);
diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c
index d67dff2430a..ab85a724a0e 100644
--- a/drivers/staging/ozwpan/ozpd.c
+++ b/drivers/staging/ozwpan/ozpd.c
@@ -3,28 +3,26 @@
* Released under the GNU General Public License Version 2 (GPLv2).
* -----------------------------------------------------------------------------
*/
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/netdevice.h>
#include <linux/errno.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
#include "ozprotocol.h"
#include "ozeltbuf.h"
#include "ozpd.h"
#include "ozproto.h"
-#include "oztrace.h"
#include "ozcdev.h"
#include "ozusbsvc.h"
#include <asm/unaligned.h>
#include <linux/uaccess.h>
#include <net/psnap.h>
-/*------------------------------------------------------------------------------
- */
+
#define OZ_MAX_TX_POOL_SIZE 6
-/*------------------------------------------------------------------------------
- */
+
static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f);
static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f);
@@ -39,10 +37,12 @@ static void oz_def_app_term(void);
static int oz_def_app_start(struct oz_pd *pd, int resume);
static void oz_def_app_stop(struct oz_pd *pd, int pause);
static void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt);
-/*------------------------------------------------------------------------------
+
+/*
* Counts the uncompleted isoc frames submitted to netcard.
*/
static atomic_t g_submitted_isoc = ATOMIC_INIT(0);
+
/* Application handler functions.
*/
static const struct oz_app_if g_app_if[OZ_APPID_MAX] = {
@@ -82,69 +82,75 @@ static const struct oz_app_if g_app_if[OZ_APPID_MAX] = {
NULL,
OZ_APPID_SERIAL},
};
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static int oz_def_app_init(void)
{
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static void oz_def_app_term(void)
{
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static int oz_def_app_start(struct oz_pd *pd, int resume)
{
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static void oz_def_app_stop(struct oz_pd *pd, int pause)
{
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt)
{
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
void oz_pd_set_state(struct oz_pd *pd, unsigned state)
{
pd->state = state;
-#ifdef WANT_TRACE
switch (state) {
case OZ_PD_S_IDLE:
- oz_trace("PD State: OZ_PD_S_IDLE\n");
+ oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_IDLE\n");
break;
case OZ_PD_S_CONNECTED:
- oz_trace("PD State: OZ_PD_S_CONNECTED\n");
+ oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_CONNECTED\n");
break;
case OZ_PD_S_STOPPED:
- oz_trace("PD State: OZ_PD_S_STOPPED\n");
+ oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_STOPPED\n");
break;
case OZ_PD_S_SLEEP:
- oz_trace("PD State: OZ_PD_S_SLEEP\n");
+ oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_SLEEP\n");
break;
}
-#endif /* WANT_TRACE */
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
void oz_pd_get(struct oz_pd *pd)
{
atomic_inc(&pd->ref_count);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
void oz_pd_put(struct oz_pd *pd)
@@ -152,12 +158,14 @@ void oz_pd_put(struct oz_pd *pd)
if (atomic_dec_and_test(&pd->ref_count))
oz_pd_destroy(pd);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
struct oz_pd *oz_pd_alloc(const u8 *mac_addr)
{
struct oz_pd *pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC);
+
if (pd) {
int i;
atomic_set(&pd->ref_count, 2);
@@ -177,19 +185,34 @@ struct oz_pd *oz_pd_alloc(const u8 *mac_addr)
pd->last_sent_frame = &pd->tx_queue;
spin_lock_init(&pd->stream_lock);
INIT_LIST_HEAD(&pd->stream_list);
+ tasklet_init(&pd->heartbeat_tasklet, oz_pd_heartbeat_handler,
+ (unsigned long)pd);
+ tasklet_init(&pd->timeout_tasklet, oz_pd_timeout_handler,
+ (unsigned long)pd);
+ hrtimer_init(&pd->heartbeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer_init(&pd->timeout, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ pd->heartbeat.function = oz_pd_heartbeat_event;
+ pd->timeout.function = oz_pd_timeout_event;
}
return pd;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
-void oz_pd_destroy(struct oz_pd *pd)
+static void oz_pd_free(struct work_struct *work)
{
struct list_head *e;
struct oz_tx_frame *f;
struct oz_isoc_stream *st;
struct oz_farewell *fwell;
- oz_trace("Destroying PD\n");
+ struct oz_pd *pd;
+
+ oz_pd_dbg(pd, ON, "Destroying PD\n");
+ pd = container_of(work, struct oz_pd, workitem);
+ /*Disable timer tasklets*/
+ tasklet_kill(&pd->heartbeat_tasklet);
+ tasklet_kill(&pd->timeout_tasklet);
/* Delete any streams.
*/
e = pd->stream_list.next;
@@ -228,20 +251,38 @@ void oz_pd_destroy(struct oz_pd *pd)
dev_put(pd->net_dev);
kfree(pd);
}
-/*------------------------------------------------------------------------------
+
+/*
+ * Context: softirq or Process
+ */
+void oz_pd_destroy(struct oz_pd *pd)
+{
+ if (hrtimer_active(&pd->timeout))
+ hrtimer_cancel(&pd->timeout);
+ if (hrtimer_active(&pd->heartbeat))
+ hrtimer_cancel(&pd->heartbeat);
+
+ INIT_WORK(&pd->workitem, oz_pd_free);
+ if (!schedule_work(&pd->workitem))
+ oz_pd_dbg(pd, ON, "failed to schedule workitem\n");
+}
+
+/*
* Context: softirq-serialized
*/
int oz_services_start(struct oz_pd *pd, u16 apps, int resume)
{
const struct oz_app_if *ai;
int rc = 0;
- oz_trace("oz_services_start(0x%x) resume(%d)\n", apps, resume);
+
+ oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, apps, resume);
for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
if (apps & (1<<ai->app_id)) {
if (ai->start(pd, resume)) {
rc = -1;
- oz_trace("Unabled to start service %d\n",
- ai->app_id);
+ oz_pd_dbg(pd, ON,
+ "Unable to start service %d\n",
+ ai->app_id);
break;
}
oz_polling_lock_bh();
@@ -253,13 +294,15 @@ int oz_services_start(struct oz_pd *pd, u16 apps, int resume)
}
return rc;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
void oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
{
const struct oz_app_if *ai;
- oz_trace("oz_stop_services(0x%x) pause(%d)\n", apps, pause);
+
+ oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause);
for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
if (apps & (1<<ai->app_id)) {
oz_polling_lock_bh();
@@ -274,34 +317,38 @@ void oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
}
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
void oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
{
const struct oz_app_if *ai;
int more = 0;
+
for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
if (ai->heartbeat && (apps & (1<<ai->app_id))) {
if (ai->heartbeat(pd))
more = 1;
}
}
- if (more)
- oz_pd_request_heartbeat(pd);
+ if ((!more) && (hrtimer_active(&pd->heartbeat)))
+ hrtimer_cancel(&pd->heartbeat);
if (pd->mode & OZ_F_ISOC_ANYTIME) {
int count = 8;
while (count-- && (oz_send_isoc_frame(pd) >= 0))
;
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
void oz_pd_stop(struct oz_pd *pd)
{
- u16 stop_apps = 0;
- oz_trace("oz_pd_stop() State = 0x%x\n", pd->state);
+ u16 stop_apps;
+
+ oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state);
oz_pd_indicate_farewells(pd);
oz_polling_lock_bh();
stop_apps = pd->total_apps;
@@ -314,46 +361,46 @@ void oz_pd_stop(struct oz_pd *pd)
/* Remove from PD list.*/
list_del(&pd->link);
oz_polling_unlock_bh();
- oz_trace("pd ref count = %d\n", atomic_read(&pd->ref_count));
- oz_timer_delete(pd, 0);
+ oz_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count));
oz_pd_put(pd);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_pd_sleep(struct oz_pd *pd)
{
int do_stop = 0;
- u16 stop_apps = 0;
+ u16 stop_apps;
+
oz_polling_lock_bh();
if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) {
oz_polling_unlock_bh();
return 0;
}
- if (pd->keep_alive_j && pd->session_id) {
+ if (pd->keep_alive && pd->session_id)
oz_pd_set_state(pd, OZ_PD_S_SLEEP);
- pd->pulse_time_j = jiffies + pd->keep_alive_j;
- oz_trace("Sleep Now %lu until %lu\n",
- jiffies, pd->pulse_time_j);
- } else {
+ else
do_stop = 1;
- }
+
stop_apps = pd->total_apps;
oz_polling_unlock_bh();
if (do_stop) {
oz_pd_stop(pd);
} else {
oz_services_stop(pd, stop_apps, 1);
- oz_timer_add(pd, OZ_TIMER_STOP, jiffies + pd->keep_alive_j, 1);
+ oz_timer_add(pd, OZ_TIMER_STOP, pd->keep_alive);
}
return do_stop;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
{
struct oz_tx_frame *f = NULL;
+
spin_lock_bh(&pd->tx_frame_lock);
if (pd->tx_pool) {
f = container_of(pd->tx_pool, struct oz_tx_frame, link);
@@ -370,7 +417,8 @@ static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
}
return f;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
@@ -384,10 +432,11 @@ static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
} else {
kfree(f);
}
- oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
- pd->nb_queued_isoc_frames);
+ oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
+ pd->nb_queued_isoc_frames);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
@@ -402,28 +451,34 @@ static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
spin_unlock_bh(&pd->tx_frame_lock);
kfree(f);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static void oz_set_more_bit(struct sk_buff *skb)
{
struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+
oz_hdr->control |= OZ_F_MORE_DATA;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
{
struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+
oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_prepare_frame(struct oz_pd *pd, int empty)
{
struct oz_tx_frame *f;
+
if ((pd->mode & OZ_MODE_MASK) != OZ_MODE_TRIGGERED)
return -1;
if (pd->nb_queued_frames >= OZ_MAX_QUEUED_FRAMES)
@@ -448,7 +503,8 @@ int oz_prepare_frame(struct oz_pd *pd, int empty)
spin_unlock(&pd->tx_frame_lock);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
@@ -458,6 +514,7 @@ static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
struct oz_hdr *oz_hdr;
struct oz_elt *elt;
struct list_head *e;
+
/* Allocate skb with enough space for the lower layers as well
* as the space we need.
*/
@@ -492,13 +549,15 @@ fail:
kfree_skb(skb);
return NULL;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
{
struct list_head *e;
struct oz_elt_info *ei;
+
e = f->elt_list.next;
while (e != &f->elt_list) {
ei = container_of(e, struct oz_elt_info, link);
@@ -514,7 +573,8 @@ static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
if (pd->elt_buff.free_elts > pd->elt_buff.max_free_elts)
oz_trim_elt_pool(&pd->elt_buff);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
@@ -522,6 +582,7 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
struct sk_buff *skb;
struct oz_tx_frame *f;
struct list_head *e;
+
spin_lock(&pd->tx_frame_lock);
e = pd->last_sent_frame->next;
if (e == &pd->tx_queue) {
@@ -540,18 +601,16 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
if ((int)atomic_read(&g_submitted_isoc) <
OZ_MAX_SUBMITTED_ISOC) {
if (dev_queue_xmit(skb) < 0) {
- oz_trace2(OZ_TRACE_TX_FRAMES,
- "Dropping ISOC Frame\n");
+ oz_dbg(TX_FRAMES, "Dropping ISOC Frame\n");
return -1;
}
atomic_inc(&g_submitted_isoc);
- oz_trace2(OZ_TRACE_TX_FRAMES,
- "Sending ISOC Frame, nb_isoc= %d\n",
- pd->nb_queued_isoc_frames);
+ oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n",
+ pd->nb_queued_isoc_frames);
return 0;
} else {
kfree_skb(skb);
- oz_trace2(OZ_TRACE_TX_FRAMES, "Dropping ISOC Frame>\n");
+ oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n");
return -1;
}
}
@@ -559,17 +618,18 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
pd->last_sent_frame = e;
skb = oz_build_frame(pd, f);
spin_unlock(&pd->tx_frame_lock);
+ if (!skb)
+ return -1;
if (more_data)
oz_set_more_bit(skb);
- oz_trace2(OZ_TRACE_TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
- if (skb) {
- if (dev_queue_xmit(skb) < 0)
- return -1;
+ oz_dbg(TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
+ if (dev_queue_xmit(skb) < 0)
+ return -1;
- }
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
void oz_send_queued_frames(struct oz_pd *pd, int backlog)
@@ -607,7 +667,8 @@ void oz_send_queued_frames(struct oz_pd *pd, int backlog)
out: oz_prepare_frame(pd, 1);
oz_send_next_queued_frame(pd, 0);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static int oz_send_isoc_frame(struct oz_pd *pd)
@@ -619,6 +680,7 @@ static int oz_send_isoc_frame(struct oz_pd *pd)
struct list_head *e;
struct list_head list;
int total_size = sizeof(struct oz_hdr);
+
INIT_LIST_HEAD(&list);
oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size,
@@ -627,7 +689,7 @@ static int oz_send_isoc_frame(struct oz_pd *pd)
return 0;
skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
if (skb == NULL) {
- oz_trace("Cannot alloc skb\n");
+ oz_dbg(ON, "Cannot alloc skb\n");
oz_elt_info_free_chain(&pd->elt_buff, &list);
return -1;
}
@@ -655,7 +717,8 @@ static int oz_send_isoc_frame(struct oz_pd *pd)
oz_elt_info_free_chain(&pd->elt_buff, &list);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
@@ -675,8 +738,8 @@ void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
break;
- oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
- pkt_num, pd->nb_queued_frames);
+ oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
+ pkt_num, pd->nb_queued_frames);
if (first == NULL)
first = e;
last = e;
@@ -696,7 +759,8 @@ void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
oz_retire_frame(pd, f);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Precondition: stream_lock must be held.
* Context: softirq
*/
@@ -704,6 +768,7 @@ static struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
{
struct list_head *e;
struct oz_isoc_stream *st;
+
list_for_each(e, &pd->stream_list) {
st = container_of(e, struct oz_isoc_stream, link);
if (st->ep_num == ep_num)
@@ -711,7 +776,8 @@ static struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num)
}
return NULL;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
@@ -730,7 +796,8 @@ int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
kfree(st);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
static void oz_isoc_stream_free(struct oz_isoc_stream *st)
@@ -738,12 +805,14 @@ static void oz_isoc_stream_free(struct oz_isoc_stream *st)
kfree_skb(st->skb);
kfree(st);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
{
struct oz_isoc_stream *st;
+
spin_lock_bh(&pd->stream_lock);
st = pd_stream_find(pd, ep_num);
if (st)
@@ -753,14 +822,16 @@ int oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num)
oz_isoc_stream_free(st);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: any
*/
static void oz_isoc_destructor(struct sk_buff *skb)
{
atomic_dec(&g_submitted_isoc);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
@@ -771,6 +842,7 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
struct sk_buff *skb = NULL;
struct oz_hdr *oz_hdr = NULL;
int size = 0;
+
spin_lock_bh(&pd->stream_lock);
st = pd_stream_find(pd, ep_num);
if (st) {
@@ -835,10 +907,20 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
struct oz_tx_frame *isoc_unit = NULL;
int nb = pd->nb_queued_isoc_frames;
if (nb >= pd->isoc_latency) {
- oz_trace2(OZ_TRACE_TX_FRAMES,
- "Dropping ISOC Unit nb= %d\n",
- nb);
- goto out;
+ struct list_head *e;
+ struct oz_tx_frame *f;
+ oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n",
+ nb);
+ spin_lock(&pd->tx_frame_lock);
+ list_for_each(e, &pd->tx_queue) {
+ f = container_of(e, struct oz_tx_frame,
+ link);
+ if (f->skb != NULL) {
+ oz_tx_isoc_free(pd, f);
+ break;
+ }
+ }
+ spin_unlock(&pd->tx_frame_lock);
}
isoc_unit = oz_tx_frame_alloc(pd);
if (isoc_unit == NULL)
@@ -849,9 +931,9 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
list_add_tail(&isoc_unit->link, &pd->tx_queue);
pd->nb_queued_isoc_frames++;
spin_unlock_bh(&pd->tx_frame_lock);
- oz_trace2(OZ_TRACE_TX_FRAMES,
- "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
- pd->nb_queued_isoc_frames, pd->nb_queued_frames);
+ oz_dbg(TX_FRAMES,
+ "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
+ pd->nb_queued_isoc_frames, pd->nb_queued_frames);
return 0;
}
@@ -870,45 +952,53 @@ out: kfree_skb(skb);
}
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
void oz_apps_init(void)
{
int i;
+
for (i = 0; i < OZ_APPID_MAX; i++)
if (g_app_if[i].init)
g_app_if[i].init();
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
void oz_apps_term(void)
{
int i;
+
/* Terminate all the apps. */
for (i = 0; i < OZ_APPID_MAX; i++)
if (g_app_if[i].term)
g_app_if[i].term();
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
void oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
{
const struct oz_app_if *ai;
+
if (app_id == 0 || app_id > OZ_APPID_MAX)
return;
ai = &g_app_if[app_id-1];
ai->rx(pd, elt);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
void oz_pd_indicate_farewells(struct oz_pd *pd)
{
struct oz_farewell *f;
const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1];
+
while (1) {
oz_polling_lock_bh();
if (list_empty(&pd->farewell_list)) {
diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h
index fbf47cbab8a..12c71295688 100644
--- a/drivers/staging/ozwpan/ozpd.h
+++ b/drivers/staging/ozwpan/ozpd.h
@@ -6,6 +6,7 @@
#ifndef _OZPD_H_
#define _OZPD_H_
+#include <linux/interrupt.h>
#include "ozeltbuf.h"
/* PD state
@@ -47,8 +48,8 @@ struct oz_farewell {
struct list_head link;
u8 ep_num;
u8 index;
- u8 report[1];
u8 len;
+ u8 report[0];
};
/* Data structure that holds information on a specific peripheral device (PD).
@@ -68,18 +69,16 @@ struct oz_pd {
u8 isoc_sent;
u32 last_rx_pkt_num;
u32 last_tx_pkt_num;
+ struct timespec last_rx_timestamp;
u32 trigger_pkt_num;
- unsigned long pulse_time_j;
- unsigned long timeout_time_j;
- unsigned long pulse_period_j;
- unsigned long presleep_j;
- unsigned long keep_alive_j;
- unsigned long last_rx_time_j;
+ unsigned long pulse_time;
+ unsigned long pulse_period;
+ unsigned long presleep;
+ unsigned long keep_alive;
struct oz_elt_buf elt_buff;
void *app_ctx[OZ_APPID_MAX];
spinlock_t app_lock[OZ_APPID_MAX];
int max_tx_size;
- u8 heartbeat_requested;
u8 mode;
u8 ms_per_isoc;
unsigned isoc_latency;
@@ -95,6 +94,12 @@ struct oz_pd {
spinlock_t stream_lock;
struct list_head stream_list;
struct net_device *net_dev;
+ struct hrtimer heartbeat;
+ struct hrtimer timeout;
+ u8 timeout_type;
+ struct tasklet_struct heartbeat_tasklet;
+ struct tasklet_struct timeout_tasklet;
+ struct work_struct workitem;
};
#define OZ_MAX_QUEUED_FRAMES 4
diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c
index 79ac7b51d5b..88714ec8570 100644
--- a/drivers/staging/ozwpan/ozproto.c
+++ b/drivers/staging/ozwpan/ozproto.c
@@ -3,6 +3,7 @@
* Released under the GNU General Public License Version 2 (GPLv2).
* -----------------------------------------------------------------------------
*/
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
@@ -10,68 +11,45 @@
#include <linux/netdevice.h>
#include <linux/errno.h>
#include <linux/ieee80211.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
#include "ozprotocol.h"
#include "ozeltbuf.h"
#include "ozpd.h"
#include "ozproto.h"
#include "ozusbsvc.h"
-#include "oztrace.h"
+
#include "ozappif.h"
#include <asm/unaligned.h>
#include <linux/uaccess.h>
#include <net/psnap.h>
-/*------------------------------------------------------------------------------
- */
+
#define OZ_CF_CONN_SUCCESS 1
#define OZ_CF_CONN_FAILURE 2
#define OZ_DO_STOP 1
#define OZ_DO_SLEEP 2
-/* States of the timer.
- */
-#define OZ_TIMER_IDLE 0
-#define OZ_TIMER_SET 1
-#define OZ_TIMER_IN_HANDLER 2
-
#define OZ_MAX_TIMER_POOL_SIZE 16
-/*------------------------------------------------------------------------------
- */
struct oz_binding {
struct packet_type ptype;
char name[OZ_MAX_BINDING_LEN];
- struct oz_binding *next;
-};
-
-struct oz_timer {
struct list_head link;
- struct oz_pd *pd;
- unsigned long due_time;
- int type;
};
-/*------------------------------------------------------------------------------
+
+/*
* Static external variables.
*/
static DEFINE_SPINLOCK(g_polling_lock);
static LIST_HEAD(g_pd_list);
-static struct oz_binding *g_binding ;
+static LIST_HEAD(g_binding);
static DEFINE_SPINLOCK(g_binding_lock);
static struct sk_buff_head g_rx_queue;
static u8 g_session_id;
static u16 g_apps = 0x1;
static int g_processing_rx;
-static struct timer_list g_timer;
-static struct oz_timer *g_cur_timer;
-static struct list_head *g_timer_pool;
-static int g_timer_pool_count;
-static int g_timer_state = OZ_TIMER_IDLE;
-static LIST_HEAD(g_timer_list);
-/*------------------------------------------------------------------------------
- */
-static void oz_protocol_timer_start(void);
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static u8 oz_get_new_session_id(u8 exclude)
@@ -84,7 +62,8 @@ static u8 oz_get_new_session_id(u8 exclude)
}
return g_session_id;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static void oz_send_conn_rsp(struct oz_pd *pd, u8 status)
@@ -94,6 +73,7 @@ static void oz_send_conn_rsp(struct oz_pd *pd, u8 status)
struct oz_hdr *oz_hdr;
struct oz_elt *elt;
struct oz_elt_connect_rsp *body;
+
int sz = sizeof(struct oz_hdr) + sizeof(struct oz_elt) +
sizeof(struct oz_elt_connect_rsp);
skb = alloc_skb(sz + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
@@ -124,11 +104,12 @@ static void oz_send_conn_rsp(struct oz_pd *pd, u8 status)
body->session_id = pd->session_id;
put_unaligned(cpu_to_le16(pd->total_apps), &body->apps);
}
- oz_trace("TX: OZ_ELT_CONNECT_RSP %d", status);
+ oz_dbg(ON, "TX: OZ_ELT_CONNECT_RSP %d", status);
dev_queue_xmit(skb);
return;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static void pd_set_keepalive(struct oz_pd *pd, u8 kalive)
@@ -137,35 +118,41 @@ static void pd_set_keepalive(struct oz_pd *pd, u8 kalive)
switch (kalive & OZ_KALIVE_TYPE_MASK) {
case OZ_KALIVE_SPECIAL:
- pd->keep_alive_j =
- oz_ms_to_jiffies(keep_alive * 1000*60*60*24*20);
+ pd->keep_alive = keep_alive * 1000*60*60*24*20;
break;
case OZ_KALIVE_SECS:
- pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000);
+ pd->keep_alive = keep_alive*1000;
break;
case OZ_KALIVE_MINS:
- pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60);
+ pd->keep_alive = keep_alive*1000*60;
break;
case OZ_KALIVE_HOURS:
- pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60*60);
+ pd->keep_alive = keep_alive*1000*60*60;
break;
default:
- pd->keep_alive_j = 0;
+ pd->keep_alive = 0;
}
- oz_trace("Keepalive = %lu jiffies\n", pd->keep_alive_j);
+ oz_dbg(ON, "Keepalive = %lu mSec\n", pd->keep_alive);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
-static void pd_set_presleep(struct oz_pd *pd, u8 presleep)
+static void pd_set_presleep(struct oz_pd *pd, u8 presleep, u8 start_timer)
{
if (presleep)
- pd->presleep_j = oz_ms_to_jiffies(presleep*100);
+ pd->presleep = presleep*100;
else
- pd->presleep_j = OZ_PRESLEEP_TOUT_J;
- oz_trace("Presleep time = %lu jiffies\n", pd->presleep_j);
+ pd->presleep = OZ_PRESLEEP_TOUT;
+ if (start_timer) {
+ spin_unlock(&g_polling_lock);
+ oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep);
+ spin_lock(&g_polling_lock);
+ }
+ oz_dbg(ON, "Presleep time = %lu mSec\n", pd->presleep);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
@@ -179,6 +166,7 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
u16 new_apps = g_apps;
struct net_device *old_net_dev = NULL;
struct oz_pd *free_pd = NULL;
+
if (cur_pd) {
pd = cur_pd;
spin_lock_bh(&g_polling_lock);
@@ -188,7 +176,7 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
pd = oz_pd_alloc(pd_addr);
if (pd == NULL)
return NULL;
- pd->last_rx_time_j = jiffies;
+ getnstimeofday(&pd->last_rx_timestamp);
spin_lock_bh(&g_polling_lock);
list_for_each(e, &g_pd_list) {
pd2 = container_of(e, struct oz_pd, link);
@@ -210,7 +198,7 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
dev_hold(net_dev);
pd->net_dev = net_dev;
}
- oz_trace("Host vendor: %d\n", body->host_vendor);
+ oz_dbg(ON, "Host vendor: %d\n", body->host_vendor);
pd->max_tx_size = OZ_MAX_TX_SIZE;
pd->mode = body->mode;
pd->pd_info = body->pd_info;
@@ -234,12 +222,11 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
}
if (body->max_len_div16)
pd->max_tx_size = ((u16)body->max_len_div16)<<4;
- oz_trace("Max frame:%u Ms per isoc:%u\n",
- pd->max_tx_size, pd->ms_per_isoc);
+ oz_dbg(ON, "Max frame:%u Ms per isoc:%u\n",
+ pd->max_tx_size, pd->ms_per_isoc);
pd->max_stream_buffering = 3*1024;
- pd->timeout_time_j = jiffies + OZ_CONNECTION_TOUT_J;
- pd->pulse_period_j = OZ_QUANTUM_J;
- pd_set_presleep(pd, body->presleep);
+ pd->pulse_period = OZ_QUANTUM;
+ pd_set_presleep(pd, body->presleep, 0);
pd_set_keepalive(pd, body->keep_alive);
new_apps &= le16_to_cpu(get_unaligned(&body->apps));
@@ -271,9 +258,8 @@ done:
u16 resume_apps = new_apps & pd->paused_apps & ~0x1;
spin_unlock_bh(&g_polling_lock);
oz_pd_set_state(pd, OZ_PD_S_CONNECTED);
- oz_timer_delete(pd, OZ_TIMER_STOP);
- oz_trace("new_apps=0x%x total_apps=0x%x paused_apps=0x%x\n",
- new_apps, pd->total_apps, pd->paused_apps);
+ oz_dbg(ON, "new_apps=0x%x total_apps=0x%x paused_apps=0x%x\n",
+ new_apps, pd->total_apps, pd->paused_apps);
if (start_apps) {
if (oz_services_start(pd, start_apps, 0))
rsp_status = OZ_STATUS_TOO_MANY_PDS;
@@ -300,7 +286,8 @@ done:
oz_pd_destroy(free_pd);
return pd;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static void oz_add_farewell(struct oz_pd *pd, u8 ep_num, u8 index,
@@ -309,13 +296,15 @@ static void oz_add_farewell(struct oz_pd *pd, u8 ep_num, u8 index,
struct oz_farewell *f;
struct oz_farewell *f2;
int found = 0;
- f = kmalloc(sizeof(struct oz_farewell) + len - 1, GFP_ATOMIC);
+
+ f = kmalloc(sizeof(struct oz_farewell) + len, GFP_ATOMIC);
if (!f)
return;
f->ep_num = ep_num;
f->index = index;
+ f->len = len;
memcpy(f->report, report, len);
- oz_trace("RX: Adding farewell report\n");
+ oz_dbg(ON, "RX: Adding farewell report\n");
spin_lock(&g_polling_lock);
list_for_each_entry(f2, &pd->farewell_list, link) {
if ((f2->ep_num == ep_num) && (f2->index == index)) {
@@ -329,7 +318,8 @@ static void oz_add_farewell(struct oz_pd *pd, u8 ep_num, u8 index,
if (found)
kfree(f2);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static void oz_rx_frame(struct sk_buff *skb)
@@ -340,20 +330,20 @@ static void oz_rx_frame(struct sk_buff *skb)
int length;
struct oz_pd *pd = NULL;
struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+ struct timespec current_time;
int dup = 0;
u32 pkt_num;
- oz_trace2(OZ_TRACE_RX_FRAMES,
- "RX frame PN=0x%x LPN=0x%x control=0x%x\n",
- oz_hdr->pkt_num, oz_hdr->last_pkt_num, oz_hdr->control);
+ oz_dbg(RX_FRAMES, "RX frame PN=0x%x LPN=0x%x control=0x%x\n",
+ oz_hdr->pkt_num, oz_hdr->last_pkt_num, oz_hdr->control);
mac_hdr = skb_mac_header(skb);
src_addr = &mac_hdr[ETH_ALEN] ;
length = skb->len;
/* Check the version field */
if (oz_get_prot_ver(oz_hdr->control) != OZ_PROTOCOL_VERSION) {
- oz_trace("Incorrect protocol version: %d\n",
- oz_get_prot_ver(oz_hdr->control));
+ oz_dbg(ON, "Incorrect protocol version: %d\n",
+ oz_get_prot_ver(oz_hdr->control));
goto done;
}
@@ -361,19 +351,24 @@ static void oz_rx_frame(struct sk_buff *skb)
pd = oz_pd_find(src_addr);
if (pd) {
- pd->last_rx_time_j = jiffies;
- oz_timer_add(pd, OZ_TIMER_TOUT,
- pd->last_rx_time_j + pd->presleep_j, 1);
+ if (!(pd->state & OZ_PD_S_CONNECTED))
+ oz_pd_set_state(pd, OZ_PD_S_CONNECTED);
+ getnstimeofday(&current_time);
+ if ((current_time.tv_sec != pd->last_rx_timestamp.tv_sec) ||
+ (pd->presleep < MSEC_PER_SEC)) {
+ oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep);
+ pd->last_rx_timestamp = current_time;
+ }
if (pkt_num != pd->last_rx_pkt_num) {
pd->last_rx_pkt_num = pkt_num;
} else {
dup = 1;
- oz_trace("Duplicate frame\n");
+ oz_dbg(ON, "Duplicate frame\n");
}
}
if (pd && !dup && ((pd->mode & OZ_MODE_MASK) == OZ_MODE_TRIGGERED)) {
- oz_trace2(OZ_TRACE_RX_FRAMES, "Received TRIGGER Frame\n");
+ oz_dbg(RX_FRAMES, "Received TRIGGER Frame\n");
pd->last_sent_frame = &pd->tx_queue;
if (oz_hdr->control & OZ_F_ACK) {
/* Retire completed frames */
@@ -397,22 +392,22 @@ static void oz_rx_frame(struct sk_buff *skb)
break;
switch (elt->type) {
case OZ_ELT_CONNECT_REQ:
- oz_trace("RX: OZ_ELT_CONNECT_REQ\n");
+ oz_dbg(ON, "RX: OZ_ELT_CONNECT_REQ\n");
pd = oz_connect_req(pd, elt, src_addr, skb->dev);
break;
case OZ_ELT_DISCONNECT:
- oz_trace("RX: OZ_ELT_DISCONNECT\n");
+ oz_dbg(ON, "RX: OZ_ELT_DISCONNECT\n");
if (pd)
oz_pd_sleep(pd);
break;
case OZ_ELT_UPDATE_PARAM_REQ: {
struct oz_elt_update_param *body =
(struct oz_elt_update_param *)(elt + 1);
- oz_trace("RX: OZ_ELT_UPDATE_PARAM_REQ\n");
+ oz_dbg(ON, "RX: OZ_ELT_UPDATE_PARAM_REQ\n");
if (pd && (pd->state & OZ_PD_S_CONNECTED)) {
spin_lock(&g_polling_lock);
pd_set_keepalive(pd, body->keepalive);
- pd_set_presleep(pd, body->presleep);
+ pd_set_presleep(pd, body->presleep, 1);
spin_unlock(&g_polling_lock);
}
}
@@ -420,7 +415,7 @@ static void oz_rx_frame(struct sk_buff *skb)
case OZ_ELT_FAREWELL_REQ: {
struct oz_elt_farewell *body =
(struct oz_elt_farewell *)(elt + 1);
- oz_trace("RX: OZ_ELT_FAREWELL_REQ\n");
+ oz_dbg(ON, "RX: OZ_ELT_FAREWELL_REQ\n");
oz_add_farewell(pd, body->ep_num,
body->index, body->report,
elt->length + 1 - sizeof(*body));
@@ -436,7 +431,7 @@ static void oz_rx_frame(struct sk_buff *skb)
}
break;
default:
- oz_trace("RX: Unknown elt %02x\n", elt->type);
+ oz_dbg(ON, "RX: Unknown elt %02x\n", elt->type);
}
elt = oz_next_elt(elt);
}
@@ -445,19 +440,19 @@ done:
oz_pd_put(pd);
consume_skb(skb);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
void oz_protocol_term(void)
{
- struct list_head *chain;
- del_timer_sync(&g_timer);
+ struct oz_binding *b, *t;
+
/* Walk the list of bindings and remove each one.
*/
spin_lock_bh(&g_binding_lock);
- while (g_binding) {
- struct oz_binding *b = g_binding;
- g_binding = b->next;
+ list_for_each_entry_safe(b, t, &g_binding, link) {
+ list_del(&b->link);
spin_unlock_bh(&g_binding_lock);
dev_remove_pack(&b->ptype);
if (b->ptype.dev)
@@ -480,21 +475,38 @@ void oz_protocol_term(void)
oz_pd_put(pd);
spin_lock_bh(&g_polling_lock);
}
- chain = g_timer_pool;
- g_timer_pool = NULL;
spin_unlock_bh(&g_polling_lock);
- while (chain) {
- struct oz_timer *t = container_of(chain, struct oz_timer, link);
- chain = chain->next;
- kfree(t);
- }
- oz_trace("Protocol stopped\n");
+ oz_dbg(ON, "Protocol stopped\n");
+}
+
+/*
+ * Context: softirq
+ */
+void oz_pd_heartbeat_handler(unsigned long data)
+{
+ struct oz_pd *pd = (struct oz_pd *)data;
+ u16 apps = 0;
+
+ spin_lock_bh(&g_polling_lock);
+ if (pd->state & OZ_PD_S_CONNECTED)
+ apps = pd->total_apps;
+ spin_unlock_bh(&g_polling_lock);
+ if (apps)
+ oz_pd_heartbeat(pd, apps);
+ oz_pd_put(pd);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
-static void oz_pd_handle_timer(struct oz_pd *pd, int type)
+void oz_pd_timeout_handler(unsigned long data)
{
+ int type;
+ struct oz_pd *pd = (struct oz_pd *)data;
+
+ spin_lock_bh(&g_polling_lock);
+ type = pd->timeout_type;
+ spin_unlock_bh(&g_polling_lock);
switch (type) {
case OZ_TIMER_TOUT:
oz_pd_sleep(pd);
@@ -502,226 +514,86 @@ static void oz_pd_handle_timer(struct oz_pd *pd, int type)
case OZ_TIMER_STOP:
oz_pd_stop(pd);
break;
- case OZ_TIMER_HEARTBEAT: {
- u16 apps = 0;
- spin_lock_bh(&g_polling_lock);
- pd->heartbeat_requested = 0;
- if (pd->state & OZ_PD_S_CONNECTED)
- apps = pd->total_apps;
- spin_unlock_bh(&g_polling_lock);
- if (apps)
- oz_pd_heartbeat(pd, apps);
- }
- break;
}
+ oz_pd_put(pd);
}
-/*------------------------------------------------------------------------------
- * Context: softirq
+
+/*
+ * Context: Interrupt
*/
-static void oz_protocol_timer(unsigned long arg)
+enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer)
{
- struct oz_timer *t;
- struct oz_timer *t2;
struct oz_pd *pd;
- spin_lock_bh(&g_polling_lock);
- if (!g_cur_timer) {
- /* This happens if we remove the current timer but can't stop
- * the timer from firing. In this case just get out.
- */
- spin_unlock_bh(&g_polling_lock);
- return;
- }
- g_timer_state = OZ_TIMER_IN_HANDLER;
- t = g_cur_timer;
- g_cur_timer = NULL;
- list_del(&t->link);
- spin_unlock_bh(&g_polling_lock);
- do {
- pd = t->pd;
- oz_pd_handle_timer(pd, t->type);
- spin_lock_bh(&g_polling_lock);
- if (g_timer_pool_count < OZ_MAX_TIMER_POOL_SIZE) {
- t->link.next = g_timer_pool;
- g_timer_pool = &t->link;
- g_timer_pool_count++;
- t = NULL;
- }
- if (!list_empty(&g_timer_list)) {
- t2 = container_of(g_timer_list.next,
- struct oz_timer, link);
- if (time_before_eq(t2->due_time, jiffies))
- list_del(&t2->link);
- else
- t2 = NULL;
- } else {
- t2 = NULL;
- }
- spin_unlock_bh(&g_polling_lock);
- oz_pd_put(pd);
- kfree(t);
- t = t2;
- } while (t);
- g_timer_state = OZ_TIMER_IDLE;
- oz_protocol_timer_start();
+
+ pd = container_of(timer, struct oz_pd, heartbeat);
+ hrtimer_forward_now(timer, ktime_set(pd->pulse_period /
+ MSEC_PER_SEC, (pd->pulse_period % MSEC_PER_SEC) * NSEC_PER_MSEC));
+ oz_pd_get(pd);
+ tasklet_schedule(&pd->heartbeat_tasklet);
+ return HRTIMER_RESTART;
}
-/*------------------------------------------------------------------------------
- * Context: softirq
+
+/*
+ * Context: Interrupt
*/
-static void oz_protocol_timer_start(void)
+enum hrtimer_restart oz_pd_timeout_event(struct hrtimer *timer)
{
- spin_lock_bh(&g_polling_lock);
- if (!list_empty(&g_timer_list)) {
- g_cur_timer =
- container_of(g_timer_list.next, struct oz_timer, link);
- if (g_timer_state == OZ_TIMER_SET) {
- mod_timer(&g_timer, g_cur_timer->due_time);
- } else {
- g_timer.expires = g_cur_timer->due_time;
- g_timer.function = oz_protocol_timer;
- g_timer.data = 0;
- add_timer(&g_timer);
- }
- g_timer_state = OZ_TIMER_SET;
- } else {
- oz_trace("No queued timers\n");
- }
- spin_unlock_bh(&g_polling_lock);
+ struct oz_pd *pd;
+
+ pd = container_of(timer, struct oz_pd, timeout);
+ oz_pd_get(pd);
+ tasklet_schedule(&pd->timeout_tasklet);
+ return HRTIMER_NORESTART;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
-void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time,
- int remove)
+void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time)
{
- struct list_head *e;
- struct oz_timer *t = NULL;
- int restart_needed = 0;
- spin_lock(&g_polling_lock);
- if (remove) {
- list_for_each(e, &g_timer_list) {
- t = container_of(e, struct oz_timer, link);
- if ((t->pd == pd) && (t->type == type)) {
- if (g_cur_timer == t) {
- restart_needed = 1;
- g_cur_timer = NULL;
- }
- list_del(e);
- break;
- }
- t = NULL;
- }
- }
- if (!t) {
- if (g_timer_pool) {
- t = container_of(g_timer_pool, struct oz_timer, link);
- g_timer_pool = g_timer_pool->next;
- g_timer_pool_count--;
+ spin_lock_bh(&g_polling_lock);
+ switch (type) {
+ case OZ_TIMER_TOUT:
+ case OZ_TIMER_STOP:
+ if (hrtimer_active(&pd->timeout)) {
+ hrtimer_set_expires(&pd->timeout, ktime_set(due_time /
+ MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
+ NSEC_PER_MSEC));
+ hrtimer_start_expires(&pd->timeout, HRTIMER_MODE_REL);
} else {
- t = kmalloc(sizeof(struct oz_timer), GFP_ATOMIC);
- }
- if (t) {
- t->pd = pd;
- t->type = type;
- oz_pd_get(pd);
- }
- }
- if (t) {
- struct oz_timer *t2;
- t->due_time = due_time;
- list_for_each(e, &g_timer_list) {
- t2 = container_of(e, struct oz_timer, link);
- if (time_before(due_time, t2->due_time)) {
- if (t2 == g_cur_timer) {
- g_cur_timer = NULL;
- restart_needed = 1;
- }
- break;
- }
+ hrtimer_start(&pd->timeout, ktime_set(due_time /
+ MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
+ NSEC_PER_MSEC), HRTIMER_MODE_REL);
}
- list_add_tail(&t->link, e);
- }
- if (g_timer_state == OZ_TIMER_IDLE)
- restart_needed = 1;
- else if (g_timer_state == OZ_TIMER_IN_HANDLER)
- restart_needed = 0;
- spin_unlock(&g_polling_lock);
- if (restart_needed)
- oz_protocol_timer_start();
-}
-/*------------------------------------------------------------------------------
- * Context: softirq or process
- */
-void oz_timer_delete(struct oz_pd *pd, int type)
-{
- struct list_head *chain = NULL;
- struct oz_timer *t;
- struct oz_timer *n;
- int restart_needed = 0;
- int release = 0;
- spin_lock(&g_polling_lock);
- list_for_each_entry_safe(t, n, &g_timer_list, link) {
- if ((t->pd == pd) && ((type == 0) || (t->type == type))) {
- if (g_cur_timer == t) {
- restart_needed = 1;
- g_cur_timer = NULL;
- del_timer(&g_timer);
- }
- list_del(&t->link);
- release++;
- if (g_timer_pool_count < OZ_MAX_TIMER_POOL_SIZE) {
- t->link.next = g_timer_pool;
- g_timer_pool = &t->link;
- g_timer_pool_count++;
- } else {
- t->link.next = chain;
- chain = &t->link;
- }
- if (type)
- break;
- }
- }
- if (g_timer_state == OZ_TIMER_IN_HANDLER)
- restart_needed = 0;
- else if (restart_needed)
- g_timer_state = OZ_TIMER_IDLE;
- spin_unlock(&g_polling_lock);
- if (restart_needed)
- oz_protocol_timer_start();
- while (release--)
- oz_pd_put(pd);
- while (chain) {
- t = container_of(chain, struct oz_timer, link);
- chain = chain->next;
- kfree(t);
+ pd->timeout_type = type;
+ break;
+ case OZ_TIMER_HEARTBEAT:
+ if (!hrtimer_active(&pd->heartbeat))
+ hrtimer_start(&pd->heartbeat, ktime_set(due_time /
+ MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
+ NSEC_PER_MSEC), HRTIMER_MODE_REL);
+ break;
}
+ spin_unlock_bh(&g_polling_lock);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
void oz_pd_request_heartbeat(struct oz_pd *pd)
{
- unsigned long now = jiffies;
- unsigned long t;
- spin_lock(&g_polling_lock);
- if (pd->heartbeat_requested) {
- spin_unlock(&g_polling_lock);
- return;
- }
- if (pd->pulse_period_j)
- t = ((now / pd->pulse_period_j) + 1) * pd->pulse_period_j;
- else
- t = now + 1;
- pd->heartbeat_requested = 1;
- spin_unlock(&g_polling_lock);
- oz_timer_add(pd, OZ_TIMER_HEARTBEAT, t, 0);
+ oz_timer_add(pd, OZ_TIMER_HEARTBEAT, pd->pulse_period > 0 ?
+ pd->pulse_period : OZ_QUANTUM);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
struct oz_pd *oz_pd_find(const u8 *mac_addr)
{
struct oz_pd *pd;
struct list_head *e;
+
spin_lock_bh(&g_polling_lock);
list_for_each(e, &g_pd_list) {
pd = container_of(e, struct oz_pd, link);
@@ -734,7 +606,8 @@ struct oz_pd *oz_pd_find(const u8 *mac_addr)
spin_unlock_bh(&g_polling_lock);
return NULL;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
void oz_app_enable(int app_id, int enable)
@@ -748,7 +621,8 @@ void oz_app_enable(int app_id, int enable)
spin_unlock_bh(&g_polling_lock);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static int oz_pkt_recv(struct sk_buff *skb, struct net_device *dev,
@@ -782,10 +656,11 @@ static int oz_pkt_recv(struct sk_buff *skb, struct net_device *dev,
}
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
-void oz_binding_add(char *net_dev)
+void oz_binding_add(const char *net_dev)
{
struct oz_binding *binding;
@@ -795,43 +670,28 @@ void oz_binding_add(char *net_dev)
binding->ptype.func = oz_pkt_recv;
memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN);
if (net_dev && *net_dev) {
- oz_trace("Adding binding: %s\n", net_dev);
+ oz_dbg(ON, "Adding binding: %s\n", net_dev);
binding->ptype.dev =
dev_get_by_name(&init_net, net_dev);
if (binding->ptype.dev == NULL) {
- oz_trace("Netdev %s not found\n", net_dev);
+ oz_dbg(ON, "Netdev %s not found\n", net_dev);
kfree(binding);
binding = NULL;
}
} else {
- oz_trace("Binding to all netcards\n");
+ oz_dbg(ON, "Binding to all netcards\n");
binding->ptype.dev = NULL;
}
if (binding) {
dev_add_pack(&binding->ptype);
spin_lock_bh(&g_binding_lock);
- binding->next = g_binding;
- g_binding = binding;
+ list_add_tail(&binding->link, &g_binding);
spin_unlock_bh(&g_binding_lock);
}
}
}
-/*------------------------------------------------------------------------------
- * Context: process
- */
-static int compare_binding_name(char *s1, char *s2)
-{
- int i;
- for (i = 0; i < OZ_MAX_BINDING_LEN; i++) {
- if (*s1 != *s2)
- return 0;
- if (!*s1++)
- return 1;
- s2++;
- }
- return 1;
-}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static void pd_stop_all_for_device(struct net_device *net_dev)
@@ -839,6 +699,7 @@ static void pd_stop_all_for_device(struct net_device *net_dev)
struct list_head h;
struct oz_pd *pd;
struct oz_pd *n;
+
INIT_LIST_HEAD(&h);
spin_lock_bh(&g_polling_lock);
list_for_each_entry_safe(pd, n, &g_pd_list, link) {
@@ -854,38 +715,37 @@ static void pd_stop_all_for_device(struct net_device *net_dev)
oz_pd_put(pd);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
-void oz_binding_remove(char *net_dev)
+void oz_binding_remove(const char *net_dev)
{
struct oz_binding *binding;
- struct oz_binding **link;
- oz_trace("Removing binding: %s\n", net_dev);
+ int found = 0;
+
+ oz_dbg(ON, "Removing binding: %s\n", net_dev);
spin_lock_bh(&g_binding_lock);
- binding = g_binding;
- link = &g_binding;
- while (binding) {
- if (compare_binding_name(binding->name, net_dev)) {
- oz_trace("Binding '%s' found\n", net_dev);
- *link = binding->next;
+ list_for_each_entry(binding, &g_binding, link) {
+ if (strncmp(binding->name, net_dev, OZ_MAX_BINDING_LEN) == 0) {
+ oz_dbg(ON, "Binding '%s' found\n", net_dev);
+ found = 1;
break;
- } else {
- link = &binding;
- binding = binding->next;
}
}
spin_unlock_bh(&g_binding_lock);
- if (binding) {
+ if (found) {
dev_remove_pack(&binding->ptype);
if (binding->ptype.dev) {
dev_put(binding->ptype.dev);
pd_stop_all_for_device(binding->ptype.dev);
}
+ list_del(&binding->link);
kfree(binding);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
static char *oz_get_next_device_name(char *s, char *dname, int max_size)
@@ -899,7 +759,8 @@ static char *oz_get_next_device_name(char *s, char *dname, int max_size)
*dname = 0;
return s;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
int oz_protocol_init(char *devs)
@@ -915,10 +776,10 @@ int oz_protocol_init(char *devs)
oz_binding_add(d);
}
}
- init_timer(&g_timer);
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: process
*/
int oz_get_pd_list(struct oz_mac_addr *addr, int max_count)
@@ -926,6 +787,7 @@ int oz_get_pd_list(struct oz_mac_addr *addr, int max_count)
struct oz_pd *pd;
struct list_head *e;
int count = 0;
+
spin_lock_bh(&g_polling_lock);
list_for_each(e, &g_pd_list) {
if (count >= max_count)
@@ -936,14 +798,12 @@ int oz_get_pd_list(struct oz_mac_addr *addr, int max_count)
spin_unlock_bh(&g_polling_lock);
return count;
}
-/*------------------------------------------------------------------------------
-*/
+
void oz_polling_lock_bh(void)
{
spin_lock_bh(&g_polling_lock);
}
-/*------------------------------------------------------------------------------
-*/
+
void oz_polling_unlock_bh(void)
{
spin_unlock_bh(&g_polling_lock);
diff --git a/drivers/staging/ozwpan/ozproto.h b/drivers/staging/ozwpan/ozproto.h
index 93bb4c0172e..0c49c8a0e81 100644
--- a/drivers/staging/ozwpan/ozproto.h
+++ b/drivers/staging/ozwpan/ozproto.h
@@ -7,28 +7,19 @@
#define _OZPROTO_H
#include <asm/byteorder.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
#include "ozappif.h"
#define OZ_ALLOCATED_SPACE(__x) (LL_RESERVED_SPACE(__x)+(__x)->needed_tailroom)
-/* Converts millisecs to jiffies.
- */
-#define oz_ms_to_jiffies(__x) msecs_to_jiffies(__x)
-
-/* Quantum milliseconds.
- */
-#define OZ_QUANTUM_MS 8
-/* Quantum jiffies
- */
-#define OZ_QUANTUM_J (oz_ms_to_jiffies(OZ_QUANTUM_MS))
+/* Quantum in MS */
+#define OZ_QUANTUM 8
/* Default timeouts.
*/
-#define OZ_CONNECTION_TOUT_J (2*HZ)
-#define OZ_PRESLEEP_TOUT_J (11*HZ)
+#define OZ_PRESLEEP_TOUT 11
/* Maximun sizes of tx frames. */
-#define OZ_MAX_TX_SIZE 1514
+#define OZ_MAX_TX_SIZE 760
/* Maximum number of uncompleted isoc frames that can be pending in network. */
#define OZ_MAX_SUBMITTED_ISOC 16
@@ -63,13 +54,18 @@ void oz_protocol_term(void);
int oz_get_pd_list(struct oz_mac_addr *addr, int max_count);
void oz_app_enable(int app_id, int enable);
struct oz_pd *oz_pd_find(const u8 *mac_addr);
-void oz_binding_add(char *net_dev);
-void oz_binding_remove(char *net_dev);
-void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time,
- int remove);
+void oz_binding_add(const char *net_dev);
+void oz_binding_remove(const char *net_dev);
+void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time);
void oz_timer_delete(struct oz_pd *pd, int type);
void oz_pd_request_heartbeat(struct oz_pd *pd);
void oz_polling_lock_bh(void);
void oz_polling_unlock_bh(void);
+void oz_pd_heartbeat_handler(unsigned long data);
+void oz_pd_timeout_handler(unsigned long data);
+enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer);
+enum hrtimer_restart oz_pd_timeout_event(struct hrtimer *timer);
+int oz_get_pd_status_list(char *pd_list, int max_count);
+int oz_get_binding_list(char *buf, int max_if);
#endif /* _OZPROTO_H */
diff --git a/drivers/staging/ozwpan/oztrace.c b/drivers/staging/ozwpan/oztrace.c
deleted file mode 100644
index 353ead24fd7..00000000000
--- a/drivers/staging/ozwpan/oztrace.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -----------------------------------------------------------------------------
- * Copyright (c) 2011 Ozmo Inc
- * Released under the GNU General Public License Version 2 (GPLv2).
- * -----------------------------------------------------------------------------
- */
-#include "ozconfig.h"
-#include "oztrace.h"
-
-#ifdef WANT_VERBOSE_TRACE
-unsigned long trace_flags =
- 0
-#ifdef WANT_TRACE_STREAM
- | OZ_TRACE_STREAM
-#endif /* WANT_TRACE_STREAM */
-#ifdef WANT_TRACE_URB
- | OZ_TRACE_URB
-#endif /* WANT_TRACE_URB */
-
-#ifdef WANT_TRACE_CTRL_DETAIL
- | OZ_TRACE_CTRL_DETAIL
-#endif /* WANT_TRACE_CTRL_DETAIL */
-
-#ifdef WANT_TRACE_HUB
- | OZ_TRACE_HUB
-#endif /* WANT_TRACE_HUB */
-
-#ifdef WANT_TRACE_RX_FRAMES
- | OZ_TRACE_RX_FRAMES
-#endif /* WANT_TRACE_RX_FRAMES */
-
-#ifdef WANT_TRACE_TX_FRAMES
- | OZ_TRACE_TX_FRAMES
-#endif /* WANT_TRACE_TX_FRAMES */
- ;
-#endif /* WANT_VERBOSE_TRACE */
-
diff --git a/drivers/staging/ozwpan/oztrace.h b/drivers/staging/ozwpan/oztrace.h
deleted file mode 100644
index 8293b24c5a7..00000000000
--- a/drivers/staging/ozwpan/oztrace.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -----------------------------------------------------------------------------
- * Copyright (c) 2011 Ozmo Inc
- * Released under the GNU General Public License Version 2 (GPLv2).
- * -----------------------------------------------------------------------------
- */
-#ifndef _OZTRACE_H_
-#define _OZTRACE_H_
-#include "ozconfig.h"
-
-#define TRACE_PREFIX KERN_ALERT "OZWPAN: "
-
-#ifdef WANT_TRACE
-#define oz_trace(...) printk(TRACE_PREFIX __VA_ARGS__)
-#ifdef WANT_VERBOSE_TRACE
-extern unsigned long trace_flags;
-#define oz_trace2(_flag, ...) \
- do { if (trace_flags & _flag) printk(TRACE_PREFIX __VA_ARGS__); \
- } while (0)
-#else
-#define oz_trace2(...)
-#endif /* #ifdef WANT_VERBOSE_TRACE */
-#else
-#define oz_trace(...)
-#define oz_trace2(...)
-#endif /* #ifdef WANT_TRACE */
-
-#define OZ_TRACE_STREAM 0x1
-#define OZ_TRACE_URB 0x2
-#define OZ_TRACE_CTRL_DETAIL 0x4
-#define OZ_TRACE_HUB 0x8
-#define OZ_TRACE_RX_FRAMES 0x10
-#define OZ_TRACE_TX_FRAMES 0x20
-
-#endif /* Sentry */
-
diff --git a/drivers/staging/ozwpan/ozurbparanoia.c b/drivers/staging/ozwpan/ozurbparanoia.c
index 55b9afbbe47..cf6278a198a 100644
--- a/drivers/staging/ozwpan/ozurbparanoia.c
+++ b/drivers/staging/ozwpan/ozurbparanoia.c
@@ -4,37 +4,39 @@
* -----------------------------------------------------------------------------
*/
#include <linux/usb.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
+
#ifdef WANT_URB_PARANOIA
+
#include "ozurbparanoia.h"
-#include "oztrace.h"
-/*-----------------------------------------------------------------------------
- */
+
#define OZ_MAX_URBS 1000
struct urb *g_urb_memory[OZ_MAX_URBS];
int g_nb_urbs;
DEFINE_SPINLOCK(g_urb_mem_lock);
-/*-----------------------------------------------------------------------------
- */
+
void oz_remember_urb(struct urb *urb)
{
unsigned long irq_state;
+
spin_lock_irqsave(&g_urb_mem_lock, irq_state);
if (g_nb_urbs < OZ_MAX_URBS) {
g_urb_memory[g_nb_urbs++] = urb;
- oz_trace("%lu: urb up = %d %p\n", jiffies, g_nb_urbs, urb);
+ oz_dbg(ON, "urb up = %d %p\n", g_nb_urbs, urb);
} else {
- oz_trace("ERROR urb buffer full\n");
+ oz_dbg(ON, "ERROR urb buffer full\n");
}
spin_unlock_irqrestore(&g_urb_mem_lock, irq_state);
}
-/*------------------------------------------------------------------------------
+
+/*
*/
int oz_forget_urb(struct urb *urb)
{
unsigned long irq_state;
int i;
int rc = -1;
+
spin_lock_irqsave(&g_urb_mem_lock, irq_state);
for (i = 0; i < g_nb_urbs; i++) {
if (g_urb_memory[i] == urb) {
@@ -42,8 +44,7 @@ int oz_forget_urb(struct urb *urb)
if (--g_nb_urbs > i)
memcpy(&g_urb_memory[i], &g_urb_memory[i+1],
(g_nb_urbs - i) * sizeof(struct urb *));
- oz_trace("%lu: urb down = %d %p\n",
- jiffies, g_nb_urbs, urb);
+ oz_dbg(ON, "urb down = %d %p\n", g_nb_urbs, urb);
}
}
spin_unlock_irqrestore(&g_urb_mem_lock, irq_state);
diff --git a/drivers/staging/ozwpan/ozurbparanoia.h b/drivers/staging/ozwpan/ozurbparanoia.h
index 00f5a3a81bc..5080ea76f50 100644
--- a/drivers/staging/ozwpan/ozurbparanoia.h
+++ b/drivers/staging/ozwpan/ozurbparanoia.h
@@ -10,8 +10,8 @@
void oz_remember_urb(struct urb *urb);
int oz_forget_urb(struct urb *urb);
#else
-#define oz_remember_urb(__x)
-#define oz_forget_urb(__x) 0
+static inline void oz_remember_urb(struct urb *urb) {}
+static inline int oz_forget_urb(struct urb *urb) { return 0; }
#endif /* WANT_URB_PARANOIA */
diff --git a/drivers/staging/ozwpan/ozusbsvc.c b/drivers/staging/ozwpan/ozusbsvc.c
index 16763287824..cf263791cb3 100644
--- a/drivers/staging/ozwpan/ozusbsvc.c
+++ b/drivers/staging/ozwpan/ozusbsvc.c
@@ -10,6 +10,7 @@
* The implementation of this service uses ozhcd.c to implement a USB HCD.
* -----------------------------------------------------------------------------
*/
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
@@ -18,16 +19,16 @@
#include <linux/errno.h>
#include <linux/input.h>
#include <asm/unaligned.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
#include "ozprotocol.h"
#include "ozeltbuf.h"
#include "ozpd.h"
#include "ozproto.h"
#include "ozusbif.h"
#include "ozhcd.h"
-#include "oztrace.h"
#include "ozusbsvc.h"
-/*------------------------------------------------------------------------------
+
+/*
* This is called once when the driver is loaded to initialise the USB service.
* Context: process
*/
@@ -35,7 +36,8 @@ int oz_usb_init(void)
{
return oz_hcd_init();
}
-/*------------------------------------------------------------------------------
+
+/*
* This is called once when the driver is unloaded to terminate the USB service.
* Context: process
*/
@@ -43,7 +45,8 @@ void oz_usb_term(void)
{
oz_hcd_term();
}
-/*------------------------------------------------------------------------------
+
+/*
* This is called when the USB service is started or resumed for a PD.
* Context: softirq
*/
@@ -52,11 +55,12 @@ int oz_usb_start(struct oz_pd *pd, int resume)
int rc = 0;
struct oz_usb_ctx *usb_ctx;
struct oz_usb_ctx *old_ctx;
+
if (resume) {
- oz_trace("USB service resumed.\n");
+ oz_dbg(ON, "USB service resumed\n");
return 0;
}
- oz_trace("USB service started.\n");
+ oz_dbg(ON, "USB service started\n");
/* Create a USB context in case we need one. If we find the PD already
* has a USB context then we will destroy it.
*/
@@ -77,7 +81,7 @@ int oz_usb_start(struct oz_pd *pd, int resume)
oz_usb_get(pd->app_ctx[OZ_APPID_USB-1]);
spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
if (old_ctx) {
- oz_trace("Already have USB context.\n");
+ oz_dbg(ON, "Already have USB context\n");
kfree(usb_ctx);
usb_ctx = old_ctx;
} else if (usb_ctx) {
@@ -95,7 +99,7 @@ int oz_usb_start(struct oz_pd *pd, int resume)
} else {
usb_ctx->hport = oz_hcd_pd_arrived(usb_ctx);
if (usb_ctx->hport == NULL) {
- oz_trace("USB hub returned null port.\n");
+ oz_dbg(ON, "USB hub returned null port\n");
spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
pd->app_ctx[OZ_APPID_USB-1] = NULL;
spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
@@ -106,15 +110,17 @@ int oz_usb_start(struct oz_pd *pd, int resume)
oz_usb_put(usb_ctx);
return rc;
}
-/*------------------------------------------------------------------------------
+
+/*
* This is called when the USB service is stopped or paused for a PD.
* Context: softirq or process
*/
void oz_usb_stop(struct oz_pd *pd, int pause)
{
struct oz_usb_ctx *usb_ctx;
+
if (pause) {
- oz_trace("USB service paused.\n");
+ oz_dbg(ON, "USB service paused\n");
return;
}
spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
@@ -122,8 +128,9 @@ void oz_usb_stop(struct oz_pd *pd, int pause)
pd->app_ctx[OZ_APPID_USB-1] = NULL;
spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
if (usb_ctx) {
- unsigned long tout = jiffies + HZ;
- oz_trace("USB service stopping...\n");
+ struct timespec ts, now;
+ getnstimeofday(&ts);
+ oz_dbg(ON, "USB service stopping...\n");
usb_ctx->stopped = 1;
/* At this point the reference count on the usb context should
* be 2 - one from when we created it and one from the hcd
@@ -131,17 +138,21 @@ void oz_usb_stop(struct oz_pd *pd, int pause)
* should get in but someone may already be in. So wait
* until they leave but timeout after 1 second.
*/
- while ((atomic_read(&usb_ctx->ref_count) > 2) &&
- time_before(jiffies, tout))
- ;
- oz_trace("USB service stopped.\n");
+ while ((atomic_read(&usb_ctx->ref_count) > 2)) {
+ getnstimeofday(&now);
+ /*Approx 1 Sec. this is not perfect calculation*/
+ if (now.tv_sec != ts.tv_sec)
+ break;
+ }
+ oz_dbg(ON, "USB service stopped\n");
oz_hcd_pd_departed(usb_ctx->hport);
/* Release the reference taken in oz_usb_start.
*/
oz_usb_put(usb_ctx);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* This increments the reference count of the context area for a specific PD.
* This ensures this context area does not disappear while still in use.
* Context: softirq
@@ -149,29 +160,34 @@ void oz_usb_stop(struct oz_pd *pd, int pause)
void oz_usb_get(void *hpd)
{
struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+
atomic_inc(&usb_ctx->ref_count);
}
-/*------------------------------------------------------------------------------
+
+/*
* This decrements the reference count of the context area for a specific PD
* and destroys the context area if the reference count becomes zero.
- * Context: softirq or process
+ * Context: irq or process
*/
void oz_usb_put(void *hpd)
{
struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+
if (atomic_dec_and_test(&usb_ctx->ref_count)) {
- oz_trace("Dealloc USB context.\n");
+ oz_dbg(ON, "Dealloc USB context\n");
oz_pd_put(usb_ctx->pd);
kfree(usb_ctx);
}
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_usb_heartbeat(struct oz_pd *pd)
{
struct oz_usb_ctx *usb_ctx;
int rc = 0;
+
spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1];
if (usb_ctx)
@@ -188,14 +204,16 @@ done:
oz_usb_put(usb_ctx);
return rc;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_usb_stream_create(void *hpd, u8 ep_num)
{
struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
struct oz_pd *pd = usb_ctx->pd;
- oz_trace("oz_usb_stream_create(0x%x)\n", ep_num);
+
+ oz_dbg(ON, "%s: (0x%x)\n", __func__, ep_num);
if (pd->mode & OZ_F_ISOC_NO_ELTS) {
oz_isoc_stream_create(pd, ep_num);
} else {
@@ -208,16 +226,18 @@ int oz_usb_stream_create(void *hpd, u8 ep_num)
}
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_usb_stream_delete(void *hpd, u8 ep_num)
{
struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+
if (usb_ctx) {
struct oz_pd *pd = usb_ctx->pd;
if (pd) {
- oz_trace("oz_usb_stream_delete(0x%x)\n", ep_num);
+ oz_dbg(ON, "%s: (0x%x)\n", __func__, ep_num);
if (pd->mode & OZ_F_ISOC_NO_ELTS) {
oz_isoc_stream_delete(pd, ep_num);
} else {
@@ -229,12 +249,14 @@ int oz_usb_stream_delete(void *hpd, u8 ep_num)
}
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq or process
*/
void oz_usb_request_heartbeat(void *hpd)
{
struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
+
if (usb_ctx && usb_ctx->pd)
oz_pd_request_heartbeat(usb_ctx->pd);
}
diff --git a/drivers/staging/ozwpan/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c
index 16e607875c3..228bffaa69c 100644
--- a/drivers/staging/ozwpan/ozusbsvc1.c
+++ b/drivers/staging/ozwpan/ozusbsvc1.c
@@ -13,19 +13,18 @@
#include <linux/errno.h>
#include <linux/input.h>
#include <asm/unaligned.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
#include "ozprotocol.h"
#include "ozeltbuf.h"
#include "ozpd.h"
#include "ozproto.h"
#include "ozusbif.h"
#include "ozhcd.h"
-#include "oztrace.h"
#include "ozusbsvc.h"
-/*------------------------------------------------------------------------------
- */
+
#define MAX_ISOC_FIXED_DATA (253-sizeof(struct oz_isoc_fixed))
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
static int oz_usb_submit_elt(struct oz_elt_buf *eb, struct oz_elt_info *ei,
@@ -34,6 +33,7 @@ static int oz_usb_submit_elt(struct oz_elt_buf *eb, struct oz_elt_info *ei,
int ret;
struct oz_elt *elt = (struct oz_elt *)ei->data;
struct oz_app_hdr *app_hdr = (struct oz_app_hdr *)(elt+1);
+
elt->type = OZ_ELT_APP_DATA;
ei->app_id = OZ_APPID_USB;
ei->length = elt->length + sizeof(struct oz_elt);
@@ -50,7 +50,8 @@ static int oz_usb_submit_elt(struct oz_elt_buf *eb, struct oz_elt_info *ei,
spin_unlock_bh(&eb->lock);
return ret;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type,
@@ -62,12 +63,13 @@ int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type,
struct oz_get_desc_req *body;
struct oz_elt_buf *eb = &pd->elt_buff;
struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
- oz_trace(" req_type = 0x%x\n", req_type);
- oz_trace(" desc_type = 0x%x\n", desc_type);
- oz_trace(" index = 0x%x\n", index);
- oz_trace(" windex = 0x%x\n", windex);
- oz_trace(" offset = 0x%x\n", offset);
- oz_trace(" len = 0x%x\n", len);
+
+ oz_dbg(ON, " req_type = 0x%x\n", req_type);
+ oz_dbg(ON, " desc_type = 0x%x\n", desc_type);
+ oz_dbg(ON, " index = 0x%x\n", index);
+ oz_dbg(ON, " windex = 0x%x\n", windex);
+ oz_dbg(ON, " offset = 0x%x\n", offset);
+ oz_dbg(ON, " len = 0x%x\n", len);
if (len > 200)
len = 200;
if (ei == NULL)
@@ -85,7 +87,8 @@ int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type,
body->index = index;
return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
static int oz_usb_set_config_req(void *hpd, u8 req_id, u8 index)
@@ -96,6 +99,7 @@ static int oz_usb_set_config_req(void *hpd, u8 req_id, u8 index)
struct oz_elt_buf *eb = &pd->elt_buff;
struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
struct oz_set_config_req *body;
+
if (ei == NULL)
return -1;
elt = (struct oz_elt *)ei->data;
@@ -106,7 +110,8 @@ static int oz_usb_set_config_req(void *hpd, u8 req_id, u8 index)
body->index = index;
return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
static int oz_usb_set_interface_req(void *hpd, u8 req_id, u8 index, u8 alt)
@@ -117,6 +122,7 @@ static int oz_usb_set_interface_req(void *hpd, u8 req_id, u8 index, u8 alt)
struct oz_elt_buf *eb = &pd->elt_buff;
struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
struct oz_set_interface_req *body;
+
if (ei == NULL)
return -1;
elt = (struct oz_elt *)ei->data;
@@ -128,7 +134,8 @@ static int oz_usb_set_interface_req(void *hpd, u8 req_id, u8 index, u8 alt)
body->alternative = alt;
return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
static int oz_usb_set_clear_feature_req(void *hpd, u8 req_id, u8 type,
@@ -140,6 +147,7 @@ static int oz_usb_set_clear_feature_req(void *hpd, u8 req_id, u8 type,
struct oz_elt_buf *eb = &pd->elt_buff;
struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
struct oz_feature_req *body;
+
if (ei == NULL)
return -1;
elt = (struct oz_elt *)ei->data;
@@ -152,7 +160,8 @@ static int oz_usb_set_clear_feature_req(void *hpd, u8 req_id, u8 type,
put_unaligned(feature, &body->feature);
return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
static int oz_usb_vendor_class_req(void *hpd, u8 req_id, u8 req_type,
@@ -164,6 +173,7 @@ static int oz_usb_vendor_class_req(void *hpd, u8 req_id, u8 req_type,
struct oz_elt_buf *eb = &pd->elt_buff;
struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
struct oz_vendor_class_req *body;
+
if (ei == NULL)
return -1;
elt = (struct oz_elt *)ei->data;
@@ -179,7 +189,8 @@ static int oz_usb_vendor_class_req(void *hpd, u8 req_id, u8 req_type,
memcpy(body->data, data, data_len);
return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: tasklet
*/
int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup,
@@ -189,6 +200,7 @@ int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup,
unsigned windex = le16_to_cpu(setup->wIndex);
unsigned wlength = le16_to_cpu(setup->wLength);
int rc = 0;
+
if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
switch (setup->bRequest) {
case USB_REQ_GET_DESCRIPTOR:
@@ -226,7 +238,8 @@ int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup,
}
return rc;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq
*/
int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb)
@@ -297,13 +310,15 @@ int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb)
}
return 0;
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq-serialized
*/
static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx,
struct oz_usb_hdr *usb_hdr, int len)
{
struct oz_data *data_hdr = (struct oz_data *)usb_hdr;
+
switch (data_hdr->format) {
case OZ_DATA_F_MULTIPLE_FIXED: {
struct oz_multiple_fixed *body =
@@ -339,7 +354,8 @@ static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx,
}
}
-/*------------------------------------------------------------------------------
+
+/*
* This is called when the PD has received a USB element. The type of element
* is determined and is then passed to an appropriate handler function.
* Context: softirq-serialized
@@ -376,7 +392,7 @@ void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt)
u16 offs = le16_to_cpu(get_unaligned(&body->offset));
u16 total_size =
le16_to_cpu(get_unaligned(&body->total_size));
- oz_trace("USB_REQ_GET_DESCRIPTOR - cnf\n");
+ oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - cnf\n");
oz_hcd_get_desc_cnf(usb_ctx->hport, body->req_id,
body->rcode, body->data,
data_len, offs, total_size);
@@ -411,12 +427,14 @@ void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt)
done:
oz_usb_put(usb_ctx);
}
-/*------------------------------------------------------------------------------
+
+/*
* Context: softirq, process
*/
void oz_usb_farewell(struct oz_pd *pd, u8 ep_num, u8 *data, u8 len)
{
struct oz_usb_ctx *usb_ctx;
+
spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1];
if (usb_ctx)
@@ -425,7 +443,7 @@ void oz_usb_farewell(struct oz_pd *pd, u8 ep_num, u8 *data, u8 len)
if (usb_ctx == NULL)
return; /* Context has gone so nothing to do. */
if (!usb_ctx->stopped) {
- oz_trace("Farewell indicated ep = 0x%x\n", ep_num);
+ oz_dbg(ON, "Farewell indicated ep = 0x%x\n", ep_num);
oz_hcd_data_ind(usb_ctx->hport, ep_num, data, len);
}
oz_usb_put(usb_ctx);
diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c
index adb8da564cf..4247d60c918 100644
--- a/drivers/staging/quickstart/quickstart.c
+++ b/drivers/staging/quickstart/quickstart.c
@@ -71,9 +71,8 @@ static struct quickstart_button *pressed;
static struct input_dev *quickstart_input;
/* Platform driver functions */
-static ssize_t quickstart_buttons_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t buttons_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
int count = 0;
struct quickstart_button *b;
@@ -94,18 +93,17 @@ static ssize_t quickstart_buttons_show(struct device *dev,
return count;
}
-static ssize_t quickstart_pressed_button_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t pressed_button_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%s\n",
(pressed ? pressed->name : "none"));
}
-static ssize_t quickstart_pressed_button_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t pressed_button_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
if (count < 2)
return -EINVAL;
@@ -319,9 +317,8 @@ static int quickstart_acpi_remove(struct acpi_device *device)
}
/* Platform driver structs */
-static DEVICE_ATTR(pressed_button, 0666, quickstart_pressed_button_show,
- quickstart_pressed_button_store);
-static DEVICE_ATTR(buttons, 0444, quickstart_buttons_show, NULL);
+static DEVICE_ATTR_RW(pressed_button);
+static DEVICE_ATTR_RO(buttons);
static struct platform_device *pf_device;
static struct platform_driver pf_driver = {
.driver = {
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
index 8fc9f588b05..7f015499cfa 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -14,7 +14,7 @@
* Copyright (c) 2004, Intel Corporation
*
* Modified for Realtek's wi-fi cards by Andrea Merello
- * <andreamrl@tiscali.it>
+ * <andrea.merello@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
index d5df0d691fc..10b22100dd3 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
@@ -14,7 +14,7 @@
******************************************************************************
Few modifications for Realtek's Wi-Fi drivers by
- Andrea Merello <andreamrl@tiscali.it>
+ Andrea Merello <andrea.merello@gmail.com>
A special thanks goes to Realtek for their support !
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
index 00f9af06aca..b65db542e1a 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -1,5 +1,5 @@
/* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
*
* Mostly extracted from the rtl8180-sa2400 driver for the
* in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
index d9add5305e2..e5282068e3d 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
@@ -1,5 +1,5 @@
/* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
*
* Mostly extracted from the rtl8180-sa2400 driver for the
* in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
index 89ed86ef0d1..b3466530cf9 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
@@ -25,7 +25,7 @@
******************************************************************************
Few modifications for Realtek's Wi-Fi drivers by
- Andrea Merello <andreamrl@tiscali.it>
+ Andrea Merello <andrea.merello@gmail.com>
A special thanks goes to Realtek for their support !
diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h
index edacc800164..d052f4a9a83 100644
--- a/drivers/staging/rtl8187se/r8180.h
+++ b/drivers/staging/rtl8187se/r8180.h
@@ -1,6 +1,6 @@
/*
This is part of rtl8180 OpenSource driver.
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the
diff --git a/drivers/staging/rtl8187se/r8180_93cx6.h b/drivers/staging/rtl8187se/r8180_93cx6.h
index 79e7391ac88..b52b5b0610a 100644
--- a/drivers/staging/rtl8187se/r8180_93cx6.h
+++ b/drivers/staging/rtl8187se/r8180_93cx6.h
@@ -1,6 +1,6 @@
/*
This is part of rtl8180 OpenSource driver
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the official realtek driver
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index ca691550436..5947a6f8e16 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -1,6 +1,6 @@
/*
This is part of rtl818x pci OpenSource driver - v 0.1
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public License)
Parts of this driver are based on the GPL part of the official
@@ -70,7 +70,7 @@ static int hwwep;
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl);
-MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
+MODULE_AUTHOR("Andrea Merello <andrea.merello@gmail.com>");
MODULE_DESCRIPTION("Linux driver for Realtek RTL8187SE WiFi cards");
module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
@@ -197,7 +197,7 @@ inline void force_pci_posting(struct net_device *dev)
mb();
}
-irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs);
+static irqreturn_t rtl8180_interrupt(int irq, void *netdev);
void set_nic_rxring(struct net_device *dev);
void set_nic_txring(struct net_device *dev);
static struct net_device_stats *rtl8180_stats(struct net_device *dev);
@@ -2666,7 +2666,7 @@ short rtl8180_init(struct net_device *dev)
TX_BEACON_RING_ADDR))
return -ENOMEM;
- if (request_irq(dev->irq, (void *)rtl8180_interrupt, IRQF_SHARED, dev->name, dev)) {
+ if (request_irq(dev->irq, rtl8180_interrupt, IRQF_SHARED, dev->name, dev)) {
DMESGE("Error allocating IRQ %d", dev->irq);
return -1;
} else {
@@ -3537,7 +3537,7 @@ void rtl8180_tx_isr(struct net_device *dev, int pri, short error)
spin_unlock_irqrestore(&priv->tx_lock, flag);
}
-irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs)
+irqreturn_t rtl8180_interrupt(int irq, void *netdev)
{
struct net_device *dev = (struct net_device *) netdev;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8187se/r8180_hw.h b/drivers/staging/rtl8187se/r8180_hw.h
index 533938123a9..92c05af557c 100644
--- a/drivers/staging/rtl8187se/r8180_hw.h
+++ b/drivers/staging/rtl8187se/r8180_hw.h
@@ -1,6 +1,6 @@
/*
This is part of rtl8180 OpenSource driver.
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225.h b/drivers/staging/rtl8187se/r8180_rtl8225.h
index c6f2128e755..c94ca0794a5 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225.h
+++ b/drivers/staging/rtl8187se/r8180_rtl8225.h
@@ -1,7 +1,7 @@
/*
This is part of the rtl8180-sa2400 driver
released under the GPL (See file COPYING for details).
- Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
This files contains programming code for the rtl8225
radio frontend.
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
index c592f7936dd..9ae96b7852f 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c
+++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
@@ -1,7 +1,7 @@
/*
* This is part of the rtl8180-sa2400 driver
* released under the GPL (See file COPYING for details).
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
*
* This files contains programming code for the rtl8225
* radio frontend.
diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c
index 156b7588229..dab787542c4 100644
--- a/drivers/staging/rtl8187se/r8180_wx.c
+++ b/drivers/staging/rtl8187se/r8180_wx.c
@@ -2,7 +2,7 @@
This file contains wireless extension handlers.
This is part of rtl8180 OpenSource driver.
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part
diff --git a/drivers/staging/rtl8187se/r8180_wx.h b/drivers/staging/rtl8187se/r8180_wx.h
index 40819140311..d471520ac77 100644
--- a/drivers/staging/rtl8187se/r8180_wx.h
+++ b/drivers/staging/rtl8187se/r8180_wx.h
@@ -1,6 +1,6 @@
/*
This is part of rtl8180 OpenSource driver - v 0.3
- Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the official realtek driver
diff --git a/drivers/staging/rtl8188eu/Kconfig b/drivers/staging/rtl8188eu/Kconfig
new file mode 100644
index 00000000000..c9c548f1749
--- /dev/null
+++ b/drivers/staging/rtl8188eu/Kconfig
@@ -0,0 +1,29 @@
+config R8188EU
+ tristate "Realtek RTL8188EU Wireless LAN NIC driver"
+ depends on WLAN && USB
+ select WIRELESS_EXT
+ select WEXT_PRIV
+ default N
+ ---help---
+ This option adds the Realtek RTL8188EU USB device such as TP-Link TL-WN725N.
+ If built as a module, it will be called r8188eu.
+
+if R8188EU
+
+config 88EU_AP_MODE
+ bool "Realtek RTL8188EU AP mode"
+ default Y
+ ---help---
+ This option enables Access Point mode. Unless you know that your system
+ will never be used as an AP, or the target system has limited memory,
+ "Y" should be selected.
+
+config 88EU_P2P
+ bool "Realtek RTL8188EU Peer-to-peer mode"
+ default Y
+ ---help---
+ This option enables peer-to-peer mode for the r8188eu driver. Unless you
+ know that peer-to-peer (P2P) mode will never be used, or the target system has
+ limited memory, "Y" should be selected.
+
+endif
diff --git a/drivers/staging/rtl8188eu/Makefile b/drivers/staging/rtl8188eu/Makefile
new file mode 100644
index 00000000000..1639a45da94
--- /dev/null
+++ b/drivers/staging/rtl8188eu/Makefile
@@ -0,0 +1,70 @@
+EXTRA_CFLAGS += -I$(src)/include
+
+r8188eu-y := \
+ core/rtw_ap.o \
+ core/rtw_br_ext.o \
+ core/rtw_cmd.o \
+ core/rtw_debug.o \
+ core/rtw_efuse.o \
+ core/rtw_ieee80211.o \
+ core/rtw_io.o \
+ core/rtw_ioctl_set.o \
+ core/rtw_iol.o \
+ core/rtw_led.o \
+ core/rtw_mlme.o \
+ core/rtw_mlme_ext.o \
+ core/rtw_mp.o \
+ core/rtw_mp_ioctl.o \
+ core/rtw_pwrctrl.o \
+ core/rtw_p2p.o \
+ core/rtw_recv.o \
+ core/rtw_rf.o \
+ core/rtw_security.o \
+ core/rtw_sreset.o \
+ core/rtw_sta_mgt.o \
+ core/rtw_wlan_util.o \
+ core/rtw_xmit.o \
+ hal/HalHWImg8188E_MAC.o \
+ hal/HalHWImg8188E_BB.o \
+ hal/HalHWImg8188E_RF.o \
+ hal/HalPhyRf.o \
+ hal/HalPhyRf_8188e.o \
+ hal/HalPwrSeqCmd.o \
+ hal/Hal8188EFWImg_CE.o \
+ hal/Hal8188EPwrSeq.o \
+ hal/Hal8188ERateAdaptive.o\
+ hal/hal_intf.o \
+ hal/hal_com.o \
+ hal/odm.o \
+ hal/odm_debug.o \
+ hal/odm_interface.o \
+ hal/odm_HWConfig.o \
+ hal/odm_RegConfig8188E.o\
+ hal/odm_RTL8188E.o \
+ hal/rtl8188e_cmd.o \
+ hal/rtl8188e_dm.o \
+ hal/rtl8188e_hal_init.o \
+ hal/rtl8188e_mp.o \
+ hal/rtl8188e_phycfg.o \
+ hal/rtl8188e_rf6052.o \
+ hal/rtl8188e_rxdesc.o \
+ hal/rtl8188e_sreset.o \
+ hal/rtl8188e_xmit.o \
+ hal/rtl8188eu_led.o \
+ hal/rtl8188eu_recv.o \
+ hal/rtl8188eu_xmit.o \
+ hal/usb_halinit.o \
+ hal/usb_ops_linux.o \
+ os_dep/ioctl_linux.o \
+ os_dep/mlme_linux.o \
+ os_dep/os_intfs.o \
+ os_dep/osdep_service.o \
+ os_dep/recv_linux.o \
+ os_dep/rtw_android.o \
+ os_dep/usb_intf.o \
+ os_dep/usb_ops_linux.o \
+ os_dep/xmit_linux.o
+
+obj-$(CONFIG_R8188EU) := r8188eu.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/staging/rtl8188eu/TODO b/drivers/staging/rtl8188eu/TODO
new file mode 100644
index 00000000000..e50aa50bdb4
--- /dev/null
+++ b/drivers/staging/rtl8188eu/TODO
@@ -0,0 +1,15 @@
+TODO:
+- find and remove remaining code valid only for 5 HGz. Most of the obvious
+ ones have been removed, but things like channel > 14 still exist.
+- find and remove any code for other chips that is left over
+- convert to external firmware
+- convert any remaining unusual variable types
+- find codes that can use %pM and %Nph formatting
+- checkpatch.pl fixes - most of the remaining ones are lines too long. Many
+ of them will require refactoring
+- merge Realtek's bugfixes and new features into the driver
+- switch to use LIB80211
+- switch to use MAC80211
+
+Please send any patches to Greg Kroah-Hartman <gregkh@linux.com>,
+and Larry Finger <Larry.Finger@lwfinger.net>.
diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c
new file mode 100644
index 00000000000..2c73823d224
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_ap.c
@@ -0,0 +1,1988 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_AP_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <ieee80211.h>
+
+#ifdef CONFIG_88EU_AP_MODE
+
+void init_mlme_ap_info(struct adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+
+ _rtw_spinlock_init(&pmlmepriv->bcn_update_lock);
+
+ /* for ACL */
+ _rtw_init_queue(&pacl_list->acl_node_q);
+
+ start_ap_mode(padapter);
+}
+
+void free_mlme_ap_info(struct adapter *padapter)
+{
+ unsigned long irqL;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ pmlmepriv->update_bcn = false;
+ pmlmeext->bstart_bss = false;
+
+ rtw_sta_flush(padapter);
+
+ pmlmeinfo->state = _HW_STATE_NOLINK_;
+
+ /* free_assoc_sta_resources */
+ rtw_free_all_stainfo(padapter);
+
+ /* free bc/mc sta_info */
+ psta = rtw_get_bcmc_stainfo(padapter);
+ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+ rtw_free_stainfo(padapter, psta);
+ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+
+ _rtw_spinlock_free(&pmlmepriv->bcn_update_lock);
+}
+
+static void update_BCNTIM(struct adapter *padapter)
+{
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network);
+ unsigned char *pie = pnetwork_mlmeext->IEs;
+
+ /* update TIM IE */
+ if (true) {
+ u8 *p, *dst_ie, *premainder_ie = NULL;
+ u8 *pbackup_remainder_ie = NULL;
+ __le16 tim_bitmap_le;
+ uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen;
+
+ tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap);
+
+ p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_);
+ if (p != NULL && tim_ielen > 0) {
+ tim_ielen += 2;
+ premainder_ie = p+tim_ielen;
+ tim_ie_offset = (int)(p - pie);
+ remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen;
+ /* append TIM IE from dst_ie offset */
+ dst_ie = p;
+ } else {
+ tim_ielen = 0;
+
+ /* calucate head_len */
+ offset = _FIXED_IE_LENGTH_;
+ offset += pnetwork_mlmeext->Ssid.SsidLength + 2;
+
+ /* get supported rates len */
+ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));
+ if (p != NULL)
+ offset += tmp_len+2;
+
+ /* DS Parameter Set IE, len = 3 */
+ offset += 3;
+
+ premainder_ie = pie + offset;
+
+ remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen;
+
+ /* append TIM IE from offset */
+ dst_ie = pie + offset;
+ }
+
+ if (remainder_ielen > 0) {
+ pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+ if (pbackup_remainder_ie && premainder_ie)
+ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+ }
+ *dst_ie++ = _TIM_IE_;
+
+ if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fc))
+ tim_ielen = 5;
+ else
+ tim_ielen = 4;
+
+ *dst_ie++ = tim_ielen;
+
+ *dst_ie++ = 0;/* DTIM count */
+ *dst_ie++ = 1;/* DTIM peroid */
+
+ if (pstapriv->tim_bitmap&BIT(0))/* for bc/mc frames */
+ *dst_ie++ = BIT(0);/* bitmap ctrl */
+ else
+ *dst_ie++ = 0;
+
+ if (tim_ielen == 4) {
+ *dst_ie++ = *(u8 *)&tim_bitmap_le;
+ } else if (tim_ielen == 5) {
+ memcpy(dst_ie, &tim_bitmap_le, 2);
+ dst_ie += 2;
+ }
+
+ /* copy remainder IE */
+ if (pbackup_remainder_ie) {
+ memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+ kfree(pbackup_remainder_ie);
+ }
+ offset = (uint)(dst_ie - pie);
+ pnetwork_mlmeext->IELength = offset + remainder_ielen;
+ }
+
+ set_tx_beacon_cmd(padapter);
+}
+
+void rtw_add_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index, u8 *data, u8 len)
+{
+ struct ndis_802_11_var_ie *pIE;
+ u8 bmatch = false;
+ u8 *pie = pnetwork->IEs;
+ u8 *p = NULL, *dst_ie = NULL, *premainder_ie = NULL;
+ u8 *pbackup_remainder_ie = NULL;
+ u32 i, offset, ielen = 0, ie_offset, remainder_ielen = 0;
+
+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pnetwork->IELength;) {
+ pIE = (struct ndis_802_11_var_ie *)(pnetwork->IEs + i);
+
+ if (pIE->ElementID > index) {
+ break;
+ } else if (pIE->ElementID == index) { /* already exist the same IE */
+ p = (u8 *)pIE;
+ ielen = pIE->Length;
+ bmatch = true;
+ break;
+ }
+ p = (u8 *)pIE;
+ ielen = pIE->Length;
+ i += (pIE->Length + 2);
+ }
+
+ if (p != NULL && ielen > 0) {
+ ielen += 2;
+
+ premainder_ie = p+ielen;
+
+ ie_offset = (int)(p - pie);
+
+ remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+ if (bmatch)
+ dst_ie = p;
+ else
+ dst_ie = (p+ielen);
+ }
+
+ if (remainder_ielen > 0) {
+ pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+ if (pbackup_remainder_ie && premainder_ie)
+ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+ }
+
+ *dst_ie++ = index;
+ *dst_ie++ = len;
+
+ memcpy(dst_ie, data, len);
+ dst_ie += len;
+
+ /* copy remainder IE */
+ if (pbackup_remainder_ie) {
+ memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+ kfree(pbackup_remainder_ie);
+ }
+
+ offset = (uint)(dst_ie - pie);
+ pnetwork->IELength = offset + remainder_ielen;
+}
+
+void rtw_remove_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index)
+{
+ u8 *p, *dst_ie = NULL, *premainder_ie = NULL;
+ u8 *pbackup_remainder_ie = NULL;
+ uint offset, ielen, ie_offset, remainder_ielen = 0;
+ u8 *pie = pnetwork->IEs;
+
+ p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, index, &ielen,
+ pnetwork->IELength - _FIXED_IE_LENGTH_);
+ if (p != NULL && ielen > 0) {
+ ielen += 2;
+
+ premainder_ie = p+ielen;
+
+ ie_offset = (int)(p - pie);
+
+ remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+ dst_ie = p;
+ }
+
+ if (remainder_ielen > 0) {
+ pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+ if (pbackup_remainder_ie && premainder_ie)
+ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+ }
+
+ /* copy remainder IE */
+ if (pbackup_remainder_ie) {
+ memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+ kfree(pbackup_remainder_ie);
+ }
+
+ offset = (uint)(dst_ie - pie);
+ pnetwork->IELength = offset + remainder_ielen;
+}
+
+static u8 chk_sta_is_alive(struct sta_info *psta)
+{
+ u8 ret = false;
+
+ if ((psta->sta_stats.last_rx_data_pkts + psta->sta_stats.last_rx_ctrl_pkts) ==
+ (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts))
+ ;
+ else
+ ret = true;
+
+ sta_update_last_rx_pkts(psta);
+
+ return ret;
+}
+
+void expire_timeout_chk(struct adapter *padapter)
+{
+ unsigned long irqL;
+ struct list_head *phead, *plist;
+ u8 updated = 0;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ u8 chk_alive_num = 0;
+ char chk_alive_list[NUM_STA];
+ int i;
+
+ _enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+ phead = &pstapriv->auth_list;
+ plist = get_next(phead);
+
+ /* check auth_queue */
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, auth_list);
+ plist = get_next(plist);
+
+ if (psta->expire_to > 0) {
+ psta->expire_to--;
+ if (psta->expire_to == 0) {
+ rtw_list_delete(&psta->auth_list);
+ pstapriv->auth_list_cnt--;
+
+ DBG_88E("auth expire %6ph\n",
+ psta->hwaddr);
+
+ _exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+ rtw_free_stainfo(padapter, psta);
+ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+
+ _enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+ }
+ }
+
+ }
+ _exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+ psta = NULL;
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ phead = &pstapriv->asoc_list;
+ plist = get_next(phead);
+
+ /* check asoc_queue */
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+ plist = get_next(plist);
+
+ if (chk_sta_is_alive(psta) || !psta->expire_to) {
+ psta->expire_to = pstapriv->expire_to;
+ psta->keep_alive_trycnt = 0;
+ psta->under_exist_checking = 0;
+ } else {
+ psta->expire_to--;
+ }
+
+ if (psta->expire_to <= 0) {
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ if (padapter->registrypriv.wifi_spec == 1) {
+ psta->expire_to = pstapriv->expire_to;
+ continue;
+ }
+
+ if (psta->state & WIFI_SLEEP_STATE) {
+ if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) {
+ /* to check if alive by another methods if staion is at ps mode. */
+ psta->expire_to = pstapriv->expire_to;
+ psta->state |= WIFI_STA_ALIVE_CHK_STATE;
+
+ /* to update bcn with tim_bitmap for this station */
+ pstapriv->tim_bitmap |= BIT(psta->aid);
+ update_beacon(padapter, _TIM_IE_, NULL, false);
+
+ if (!pmlmeext->active_keep_alive_check)
+ continue;
+ }
+ }
+ if (pmlmeext->active_keep_alive_check) {
+ int stainfo_offset;
+
+ stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+ if (stainfo_offset_valid(stainfo_offset))
+ chk_alive_list[chk_alive_num++] = stainfo_offset;
+ continue;
+ }
+
+ rtw_list_delete(&psta->asoc_list);
+ pstapriv->asoc_list_cnt--;
+
+ DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state);
+ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+ } else {
+ /* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */
+ if (psta->sleepq_len > (NR_XMITFRAME/pstapriv->asoc_list_cnt) &&
+ padapter->xmitpriv.free_xmitframe_cnt < (NR_XMITFRAME/pstapriv->asoc_list_cnt/2)) {
+ DBG_88E("%s sta:%pM, sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__,
+ (psta->hwaddr), psta->sleepq_len,
+ padapter->xmitpriv.free_xmitframe_cnt,
+ pstapriv->asoc_list_cnt);
+ wakeup_sta_to_xmit(padapter, psta);
+ }
+ }
+ }
+
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ if (chk_alive_num) {
+ u8 backup_oper_channel = 0;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ /* switch to correct channel of current network before issue keep-alive frames */
+ if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) {
+ backup_oper_channel = rtw_get_oper_ch(padapter);
+ SelectChannel(padapter, pmlmeext->cur_channel);
+ }
+
+ /* issue null data to check sta alive*/
+ for (i = 0; i < chk_alive_num; i++) {
+ int ret = _FAIL;
+
+ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
+
+ if (psta->state & WIFI_SLEEP_STATE)
+ ret = issue_nulldata(padapter, psta->hwaddr, 0, 1, 50);
+ else
+ ret = issue_nulldata(padapter, psta->hwaddr, 0, 3, 50);
+
+ psta->keep_alive_trycnt++;
+ if (ret == _SUCCESS) {
+ DBG_88E("asoc check, sta(%pM) is alive\n", (psta->hwaddr));
+ psta->expire_to = pstapriv->expire_to;
+ psta->keep_alive_trycnt = 0;
+ continue;
+ } else if (psta->keep_alive_trycnt <= 3) {
+ DBG_88E("ack check for asoc expire, keep_alive_trycnt =%d\n", psta->keep_alive_trycnt);
+ psta->expire_to = 1;
+ continue;
+ }
+
+ psta->keep_alive_trycnt = 0;
+
+ DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state);
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ rtw_list_delete(&psta->asoc_list);
+ pstapriv->asoc_list_cnt--;
+ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ }
+
+ if (backup_oper_channel > 0) /* back to the original operation channel */
+ SelectChannel(padapter, backup_oper_channel);
+ }
+
+ associated_clients_update(padapter, updated);
+}
+
+void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
+{
+ int i;
+ u8 rf_type;
+ u32 init_rate = 0;
+ unsigned char sta_band = 0, raid, shortGIrate = false;
+ unsigned char limit;
+ unsigned int tx_ra_bitmap = 0;
+ struct ht_priv *psta_ht = NULL;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+
+ if (psta)
+ psta_ht = &psta->htpriv;
+ else
+ return;
+
+ if (!(psta->state & _FW_LINKED))
+ return;
+
+ /* b/g mode ra_bitmap */
+ for (i = 0; i < sizeof(psta->bssrateset); i++) {
+ if (psta->bssrateset[i])
+ tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f);
+ }
+ /* n mode ra_bitmap */
+ if (psta_ht->ht_option) {
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+ if (rf_type == RF_2T2R)
+ limit = 16;/* 2R */
+ else
+ limit = 8;/* 1R */
+
+ for (i = 0; i < limit; i++) {
+ if (psta_ht->ht_cap.supp_mcs_set[i/8] & BIT(i%8))
+ tx_ra_bitmap |= BIT(i+12);
+ }
+
+ /* max short GI rate */
+ shortGIrate = psta_ht->sgi;
+ }
+
+ if (pcur_network->Configuration.DSConfig > 14) {
+ /* 5G band */
+ if (tx_ra_bitmap & 0xffff000)
+ sta_band |= WIRELESS_11_5N | WIRELESS_11A;
+ else
+ sta_band |= WIRELESS_11A;
+ } else {
+ if (tx_ra_bitmap & 0xffff000)
+ sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B;
+ else if (tx_ra_bitmap & 0xff0)
+ sta_band |= WIRELESS_11G | WIRELESS_11B;
+ else
+ sta_band |= WIRELESS_11B;
+ }
+
+ psta->wireless_mode = sta_band;
+
+ raid = networktype_to_raid(sta_band);
+ init_rate = get_highest_rate_idx(tx_ra_bitmap&0x0fffffff)&0x3f;
+
+ if (psta->aid < NUM_STA) {
+ u8 arg = 0;
+
+ arg = psta->mac_id&0x1f;
+
+ arg |= BIT(7);/* support entry 2~31 */
+
+ if (shortGIrate)
+ arg |= BIT(5);
+
+ tx_ra_bitmap |= ((raid<<28)&0xf0000000);
+
+ DBG_88E("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = 0x%x\n",
+ __func__ , psta->mac_id, raid , tx_ra_bitmap, arg);
+
+ /* bitmap[0:27] = tx_rate_bitmap */
+ /* bitmap[28:31]= Rate Adaptive id */
+ /* arg[0:4] = macid */
+ /* arg[5] = Short GI */
+ rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, rssi_level);
+
+ if (shortGIrate)
+ init_rate |= BIT(6);
+
+ /* set ra_id, init_rate */
+ psta->raid = raid;
+ psta->init_rate = init_rate;
+
+ } else {
+ DBG_88E("station aid %d exceed the max number\n", psta->aid);
+ }
+}
+
+static void update_bmc_sta(struct adapter *padapter)
+{
+ unsigned long irqL;
+ u32 init_rate = 0;
+ unsigned char network_type, raid;
+ int i, supportRateNum = 0;
+ unsigned int tx_ra_bitmap = 0;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+ struct sta_info *psta = rtw_get_bcmc_stainfo(padapter);
+
+ if (psta) {
+ psta->aid = 0;/* default set to 0 */
+ psta->mac_id = psta->aid + 1;
+
+ psta->qos_option = 0;
+ psta->htpriv.ht_option = false;
+
+ psta->ieee8021x_blocked = 0;
+
+ _rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+ /* prepare for add_RATid */
+ supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates);
+ network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, supportRateNum, 1);
+
+ memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum);
+ psta->bssratelen = supportRateNum;
+
+ /* b/g mode ra_bitmap */
+ for (i = 0; i < supportRateNum; i++) {
+ if (psta->bssrateset[i])
+ tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f);
+ }
+
+ if (pcur_network->Configuration.DSConfig > 14) {
+ /* force to A mode. 5G doesn't support CCK rates */
+ network_type = WIRELESS_11A;
+ tx_ra_bitmap = 0x150; /* 6, 12, 24 Mbps */
+ } else {
+ /* force to b mode */
+ network_type = WIRELESS_11B;
+ tx_ra_bitmap = 0xf;
+ }
+
+ raid = networktype_to_raid(network_type);
+ init_rate = get_highest_rate_idx(tx_ra_bitmap&0x0fffffff)&0x3f;
+
+ /* ap mode */
+ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
+
+ {
+ u8 arg = 0;
+
+ arg = psta->mac_id&0x1f;
+ arg |= BIT(7);
+ tx_ra_bitmap |= ((raid<<28)&0xf0000000);
+ DBG_88E("update_bmc_sta, mask = 0x%x, arg = 0x%x\n", tx_ra_bitmap, arg);
+
+ /* bitmap[0:27] = tx_rate_bitmap */
+ /* bitmap[28:31]= Rate Adaptive id */
+ /* arg[0:4] = macid */
+ /* arg[5] = Short GI */
+ rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, 0);
+ }
+ /* set ra_id, init_rate */
+ psta->raid = raid;
+ psta->init_rate = init_rate;
+
+ rtw_stassoc_hw_rpt(padapter, psta);
+
+ _enter_critical_bh(&psta->lock, &irqL);
+ psta->state = _FW_LINKED;
+ _exit_critical_bh(&psta->lock, &irqL);
+
+ } else {
+ DBG_88E("add_RATid_bmc_sta error!\n");
+ }
+}
+
+/* notes: */
+/* AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode */
+/* MAC_ID = AID+1 for sta in ap/adhoc mode */
+/* MAC_ID = 1 for bc/mc for sta/ap/adhoc */
+/* MAC_ID = 0 for bssid for sta/ap/adhoc */
+/* CAM_ID = 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */
+
+void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta)
+{
+ unsigned long irqL;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv;
+ struct ht_priv *phtpriv_sta = &psta->htpriv;
+
+ psta->mac_id = psta->aid+1;
+ DBG_88E("%s\n", __func__);
+
+ /* ap mode */
+ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
+
+ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
+ psta->ieee8021x_blocked = true;
+ else
+ psta->ieee8021x_blocked = false;
+
+
+ /* update sta's cap */
+
+ /* ERP */
+ VCS_update(padapter, psta);
+ /* HT related cap */
+ if (phtpriv_sta->ht_option) {
+ /* check if sta supports rx ampdu */
+ phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable;
+
+ /* check if sta support s Short GI */
+ if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40))
+ phtpriv_sta->sgi = true;
+
+ /* bwmode */
+ if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & IEEE80211_HT_CAP_SUP_WIDTH) {
+ phtpriv_sta->bwmode = pmlmeext->cur_bwmode;
+ phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
+ }
+ psta->qos_option = true;
+ } else {
+ phtpriv_sta->ampdu_enable = false;
+ phtpriv_sta->sgi = false;
+ phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20;
+ phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ }
+
+ /* Rx AMPDU */
+ send_delba(padapter, 0, psta->hwaddr);/* recipient */
+
+ /* TX AMPDU */
+ send_delba(padapter, 1, psta->hwaddr);/* originator */
+ phtpriv_sta->agg_enable_bitmap = 0x0;/* reset */
+ phtpriv_sta->candidate_tid_bitmap = 0x0;/* reset */
+
+ /* todo: init other variables */
+
+ _rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+ _enter_critical_bh(&psta->lock, &irqL);
+ psta->state |= _FW_LINKED;
+ _exit_critical_bh(&psta->lock, &irqL);
+}
+
+static void update_hw_ht_param(struct adapter *padapter)
+{
+ unsigned char max_AMPDU_len;
+ unsigned char min_MPDU_spacing;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ DBG_88E("%s\n", __func__);
+
+ /* handle A-MPDU parameter field */
+ /*
+ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+ AMPDU_para [4:2]:Min MPDU Start Spacing
+ */
+ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;
+
+ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2;
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing));
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len));
+
+ /* */
+ /* Config SM Power Save setting */
+ /* */
+ pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2;
+ if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
+ DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
+}
+
+static void start_bss_network(struct adapter *padapter, u8 *pbuf)
+{
+ u8 *p;
+ u8 val8, cur_channel, cur_bwmode, cur_ch_offset;
+ u16 bcn_interval;
+ u32 acparm;
+ int ie_len;
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct security_priv *psecuritypriv = &(padapter->securitypriv);
+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network);
+ struct HT_info_element *pht_info = NULL;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+ bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod;
+ cur_channel = pnetwork->Configuration.DSConfig;
+ cur_bwmode = HT_CHANNEL_WIDTH_20;
+ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+
+ /* check if there is wps ie, */
+ /* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */
+ /* and at first time the security ie (RSN/WPA IE) will not include in beacon. */
+ if (!rtw_get_wps_ie(pnetwork->IEs+_FIXED_IE_LENGTH_, pnetwork->IELength-_FIXED_IE_LENGTH_, NULL, NULL))
+ pmlmeext->bstart_bss = true;
+
+ /* todo: update wmm, ht cap */
+ if (pmlmepriv->qospriv.qos_option)
+ pmlmeinfo->WMM_enable = true;
+ if (pmlmepriv->htpriv.ht_option) {
+ pmlmeinfo->WMM_enable = true;
+ pmlmeinfo->HT_enable = true;
+
+ update_hw_ht_param(padapter);
+ }
+
+ if (pmlmepriv->cur_network.join_res != true) { /* setting only at first time */
+ /* WEP Key will be set before this function, do not clear CAM. */
+ if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) &&
+ (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_))
+ flush_all_cam_entry(padapter); /* clear CAM */
+ }
+
+ /* set MSR to AP_Mode */
+ Set_MSR(padapter, _HW_STATE_AP_);
+
+ /* Set BSSID REG */
+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pnetwork->MacAddress);
+
+ /* Set EDCA param reg */
+ acparm = 0x002F3217; /* VO */
+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm));
+ acparm = 0x005E4317; /* VI */
+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm));
+ acparm = 0x005ea42b;
+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm));
+ acparm = 0x0000A444; /* BK */
+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm));
+
+ /* Set Security */
+ val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf;
+ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+ /* Beacon Control related register */
+ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval));
+
+ UpdateBrateTbl(padapter, pnetwork->SupportedRates);
+ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates);
+
+ if (!pmlmepriv->cur_network.join_res) { /* setting only at first time */
+ /* turn on all dynamic functions */
+ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true);
+ }
+ /* set channel, bwmode */
+ p = rtw_get_ie((pnetwork->IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - sizeof(struct ndis_802_11_fixed_ie)));
+ if (p && ie_len) {
+ pht_info = (struct HT_info_element *)(p+2);
+
+ if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) {
+ /* switch to the 40M Hz mode */
+ cur_bwmode = HT_CHANNEL_WIDTH_40;
+ switch (pht_info->infos[0] & 0x3) {
+ case 1:
+ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+ break;
+ case 3:
+ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+ break;
+ default:
+ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ }
+ }
+ }
+ /* TODO: need to judge the phy parameters on concurrent mode for single phy */
+ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode);
+
+ DBG_88E("CH =%d, BW =%d, offset =%d\n", cur_channel, cur_bwmode, cur_ch_offset);
+
+ /* */
+ pmlmeext->cur_channel = cur_channel;
+ pmlmeext->cur_bwmode = cur_bwmode;
+ pmlmeext->cur_ch_offset = cur_ch_offset;
+ pmlmeext->cur_wireless_mode = pmlmepriv->cur_network.network_type;
+
+ /* update cur_wireless_mode */
+ update_wireless_mode(padapter);
+
+ /* udpate capability after cur_wireless_mode updated */
+ update_capinfo(padapter, rtw_get_capability((struct wlan_bssid_ex *)pnetwork));
+
+ /* let pnetwork_mlmeext == pnetwork_mlme. */
+ memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length);
+
+#ifdef CONFIG_88EU_P2P
+ memcpy(pwdinfo->p2p_group_ssid, pnetwork->Ssid.Ssid, pnetwork->Ssid.SsidLength);
+ pwdinfo->p2p_group_ssid_len = pnetwork->Ssid.SsidLength;
+#endif /* CONFIG_88EU_P2P */
+
+ if (pmlmeext->bstart_bss) {
+ update_beacon(padapter, _TIM_IE_, NULL, false);
+
+ /* issue beacon frame */
+ if (send_beacon(padapter) == _FAIL)
+ DBG_88E("issue_beacon, fail!\n");
+ }
+
+ /* update bc/mc sta_info */
+ update_bmc_sta(padapter);
+}
+
+int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
+{
+ int ret = _SUCCESS;
+ u8 *p;
+ u8 *pHT_caps_ie = NULL;
+ u8 *pHT_info_ie = NULL;
+ struct sta_info *psta = NULL;
+ u16 cap, ht_cap = false;
+ uint ie_len = 0;
+ int group_cipher, pairwise_cipher;
+ u8 channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX];
+ int supportRateNum = 0;
+ u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01};
+ u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_bssid_ex *pbss_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+ u8 *ie = pbss_network->IEs;
+
+ /* SSID */
+ /* Supported rates */
+ /* DS Params */
+ /* WLAN_EID_COUNTRY */
+ /* ERP Information element */
+ /* Extended supported rates */
+ /* WPA/WPA2 */
+ /* Wi-Fi Wireless Multimedia Extensions */
+ /* ht_capab, ht_oper */
+ /* WPS IE */
+
+ DBG_88E("%s, len =%d\n", __func__, len);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return _FAIL;
+
+
+ if (len > MAX_IE_SZ)
+ return _FAIL;
+
+ pbss_network->IELength = len;
+
+ _rtw_memset(ie, 0, MAX_IE_SZ);
+
+ memcpy(ie, pbuf, pbss_network->IELength);
+
+
+ if (pbss_network->InfrastructureMode != Ndis802_11APMode)
+ return _FAIL;
+
+ pbss_network->Rssi = 0;
+
+ memcpy(pbss_network->MacAddress, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+ /* beacon interval */
+ p = rtw_get_beacon_interval_from_ie(ie);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */
+ pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p);
+
+ /* capability */
+ cap = RTW_GET_LE16(ie);
+
+ /* SSID */
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+ if (p && ie_len > 0) {
+ _rtw_memset(&pbss_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
+ memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len);
+ pbss_network->Ssid.SsidLength = ie_len;
+ }
+
+ /* channel */
+ channel = 0;
+ pbss_network->Configuration.Length = 0;
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+ if (p && ie_len > 0)
+ channel = *(p + 2);
+
+ pbss_network->Configuration.DSConfig = channel;
+
+ _rtw_memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX);
+ /* get supported rates */
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+ if (p != NULL) {
+ memcpy(supportRate, p+2, ie_len);
+ supportRateNum = ie_len;
+ }
+
+ /* get ext_supported rates */
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_);
+ if (p != NULL) {
+ memcpy(supportRate+supportRateNum, p+2, ie_len);
+ supportRateNum += ie_len;
+ }
+
+ network_type = rtw_check_network_type(supportRate, supportRateNum, channel);
+
+ rtw_set_supported_rate(pbss_network->SupportedRates, network_type);
+
+ /* parsing ERP_IE */
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+ if (p && ie_len > 0)
+ ERP_IE_handler(padapter, (struct ndis_802_11_var_ie *)p);
+
+ /* update privacy/security */
+ if (cap & BIT(4))
+ pbss_network->Privacy = 1;
+ else
+ pbss_network->Privacy = 0;
+
+ psecuritypriv->wpa_psk = 0;
+
+ /* wpa2 */
+ group_cipher = 0;
+ pairwise_cipher = 0;
+ psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_;
+ psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_;
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+ if (p && ie_len > 0) {
+ if (rtw_parse_wpa2_ie(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+ psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */
+ psecuritypriv->wpa_psk |= BIT(1);
+
+ psecuritypriv->wpa2_group_cipher = group_cipher;
+ psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher;
+ }
+ }
+ /* wpa */
+ ie_len = 0;
+ group_cipher = 0;
+ pairwise_cipher = 0;
+ psecuritypriv->wpa_group_cipher = _NO_PRIVACY_;
+ psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_;
+ for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) {
+ p = rtw_get_ie(p, _SSN_IE_1_, &ie_len,
+ (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
+ if ((p) && (_rtw_memcmp(p+2, OUI1, 4))) {
+ if (rtw_parse_wpa_ie(p, ie_len+2, &group_cipher,
+ &pairwise_cipher, NULL) == _SUCCESS) {
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+ psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */
+
+ psecuritypriv->wpa_psk |= BIT(0);
+
+ psecuritypriv->wpa_group_cipher = group_cipher;
+ psecuritypriv->wpa_pairwise_cipher = pairwise_cipher;
+ }
+ break;
+ }
+ if ((p == NULL) || (ie_len == 0))
+ break;
+ }
+
+ /* wmm */
+ ie_len = 0;
+ pmlmepriv->qospriv.qos_option = 0;
+ if (pregistrypriv->wmm_enable) {
+ for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) {
+ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len,
+ (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
+ if ((p) && _rtw_memcmp(p+2, WMM_PARA_IE, 6)) {
+ pmlmepriv->qospriv.qos_option = 1;
+
+ *(p+8) |= BIT(7);/* QoS Info, support U-APSD */
+
+ /* disable all ACM bits since the WMM admission control is not supported */
+ *(p + 10) &= ~BIT(4); /* BE */
+ *(p + 14) &= ~BIT(4); /* BK */
+ *(p + 18) &= ~BIT(4); /* VI */
+ *(p + 22) &= ~BIT(4); /* VO */
+ break;
+ }
+
+ if ((p == NULL) || (ie_len == 0))
+ break;
+ }
+ }
+ /* parsing HT_CAP_IE */
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len,
+ (pbss_network->IELength - _BEACON_IE_OFFSET_));
+ if (p && ie_len > 0) {
+ u8 rf_type;
+ struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p+2);
+
+ pHT_caps_ie = p;
+ ht_cap = true;
+ network_type |= WIRELESS_11_24N;
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+ if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) ||
+ (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP))
+ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2));
+ else
+ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00);
+
+ /* set Max Rx AMPDU size to 64K */
+ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & 0x03);
+
+ if (rf_type == RF_1T1R) {
+ pht_cap->supp_mcs_set[0] = 0xff;
+ pht_cap->supp_mcs_set[1] = 0x0;
+ }
+ memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len);
+ }
+
+ /* parsing HT_INFO_IE */
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len,
+ (pbss_network->IELength - _BEACON_IE_OFFSET_));
+ if (p && ie_len > 0)
+ pHT_info_ie = p;
+ switch (network_type) {
+ case WIRELESS_11B:
+ pbss_network->NetworkTypeInUse = Ndis802_11DS;
+ break;
+ case WIRELESS_11G:
+ case WIRELESS_11BG:
+ case WIRELESS_11G_24N:
+ case WIRELESS_11BG_24N:
+ pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+ break;
+ case WIRELESS_11A:
+ pbss_network->NetworkTypeInUse = Ndis802_11OFDM5;
+ break;
+ default:
+ pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+ break;
+ }
+
+ pmlmepriv->cur_network.network_type = network_type;
+
+ pmlmepriv->htpriv.ht_option = false;
+
+ if ((psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) ||
+ (psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) {
+ /* todo: */
+ /* ht_cap = false; */
+ }
+
+ /* ht_cap */
+ if (pregistrypriv->ht_enable && ht_cap) {
+ pmlmepriv->htpriv.ht_option = true;
+ pmlmepriv->qospriv.qos_option = 1;
+
+ if (pregistrypriv->ampdu_enable == 1)
+ pmlmepriv->htpriv.ampdu_enable = true;
+ HT_caps_handler(padapter, (struct ndis_802_11_var_ie *)pHT_caps_ie);
+
+ HT_info_handler(padapter, (struct ndis_802_11_var_ie *)pHT_info_ie);
+ }
+
+ pbss_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pbss_network);
+
+ /* issue beacon to start bss network */
+ start_bss_network(padapter, (u8 *)pbss_network);
+
+ /* alloc sta_info for ap itself */
+ psta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+ if (!psta) {
+ psta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+ if (psta == NULL)
+ return _FAIL;
+ }
+
+ pmlmepriv->cur_network.join_res = true;/* for check if already set beacon */
+ return ret;
+}
+
+void rtw_set_macaddr_acl(struct adapter *padapter, int mode)
+{
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+ DBG_88E("%s, mode =%d\n", __func__, mode);
+
+ pacl_list->mode = mode;
+}
+
+int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
+{
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ u8 added = false;
+ int i, ret = 0;
+ struct rtw_wlan_acl_node *paclnode;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+ struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+ DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
+
+ if ((NUM_ACL-1) < pacl_list->num)
+ return -1;
+
+ _enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+ phead = get_list_head(pacl_node_q);
+ plist = get_next(phead);
+
+ while (!rtw_end_of_queue_search(phead, plist)) {
+ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+ plist = get_next(plist);
+
+ if (_rtw_memcmp(paclnode->addr, addr, ETH_ALEN)) {
+ if (paclnode->valid) {
+ added = true;
+ DBG_88E("%s, sta has been added\n", __func__);
+ break;
+ }
+ }
+ }
+
+ _exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+ if (added)
+ return ret;
+
+ _enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+ for (i = 0; i < NUM_ACL; i++) {
+ paclnode = &pacl_list->aclnode[i];
+
+ if (!paclnode->valid) {
+ _rtw_init_listhead(&paclnode->list);
+
+ memcpy(paclnode->addr, addr, ETH_ALEN);
+
+ paclnode->valid = true;
+
+ rtw_list_insert_tail(&paclnode->list, get_list_head(pacl_node_q));
+
+ pacl_list->num++;
+
+ break;
+ }
+ }
+
+ DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
+
+ _exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+ return ret;
+}
+
+int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
+{
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ int ret = 0;
+ struct rtw_wlan_acl_node *paclnode;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+ struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+ DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
+
+ _enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+ phead = get_list_head(pacl_node_q);
+ plist = get_next(phead);
+
+ while (!rtw_end_of_queue_search(phead, plist)) {
+ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+ plist = get_next(plist);
+
+ if (_rtw_memcmp(paclnode->addr, addr, ETH_ALEN)) {
+ if (paclnode->valid) {
+ paclnode->valid = false;
+
+ rtw_list_delete(&paclnode->list);
+
+ pacl_list->num--;
+ }
+ }
+ }
+
+ _exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+ DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
+ return ret;
+}
+
+static void update_bcn_fixed_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_erpinfo_ie(struct adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
+ unsigned char *p, *ie = pnetwork->IEs;
+ u32 len = 0;
+
+ DBG_88E("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable);
+
+ if (!pmlmeinfo->ERP_enable)
+ return;
+
+ /* parsing ERP_IE */
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len,
+ (pnetwork->IELength - _BEACON_IE_OFFSET_));
+ if (p && len > 0) {
+ struct ndis_802_11_var_ie *pIE = (struct ndis_802_11_var_ie *)p;
+
+ if (pmlmepriv->num_sta_non_erp == 1)
+ pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION;
+ else
+ pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION);
+
+ if (pmlmepriv->num_sta_no_short_preamble > 0)
+ pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE;
+ else
+ pIE->data[0] &= ~(RTW_ERP_INFO_BARKER_PREAMBLE_MODE);
+
+ ERP_IE_handler(padapter, pIE);
+ }
+}
+
+static void update_bcn_htcap_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_htinfo_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_rsn_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wpa_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wmm_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wps_ie(struct adapter *padapter)
+{
+ u8 *pwps_ie = NULL, *pwps_ie_src;
+ u8 *premainder_ie, *pbackup_remainder_ie = NULL;
+ uint wps_ielen = 0, wps_offset, remainder_ielen;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
+ unsigned char *ie = pnetwork->IEs;
+ u32 ielen = pnetwork->IELength;
+
+ DBG_88E("%s\n", __func__);
+
+ pwps_ie = rtw_get_wps_ie(ie+_FIXED_IE_LENGTH_, ielen-_FIXED_IE_LENGTH_, NULL, &wps_ielen);
+
+ if (pwps_ie == NULL || wps_ielen == 0)
+ return;
+
+ wps_offset = (uint)(pwps_ie-ie);
+
+ premainder_ie = pwps_ie + wps_ielen;
+
+ remainder_ielen = ielen - wps_offset - wps_ielen;
+
+ if (remainder_ielen > 0) {
+ pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+ if (pbackup_remainder_ie)
+ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+ }
+
+ pwps_ie_src = pmlmepriv->wps_beacon_ie;
+ if (pwps_ie_src == NULL)
+ return;
+
+ wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */
+ if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) {
+ memcpy(pwps_ie, pwps_ie_src, wps_ielen+2);
+ pwps_ie += (wps_ielen+2);
+
+ if (pbackup_remainder_ie)
+ memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen);
+
+ /* update IELength */
+ pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen;
+ }
+
+ if (pbackup_remainder_ie)
+ kfree(pbackup_remainder_ie);
+}
+
+static void update_bcn_p2p_ie(struct adapter *padapter)
+{
+}
+
+static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui)
+{
+ DBG_88E("%s\n", __func__);
+
+ if (_rtw_memcmp(RTW_WPA_OUI, oui, 4))
+ update_bcn_wpa_ie(padapter);
+ else if (_rtw_memcmp(WMM_OUI, oui, 4))
+ update_bcn_wmm_ie(padapter);
+ else if (_rtw_memcmp(WPS_OUI, oui, 4))
+ update_bcn_wps_ie(padapter);
+ else if (_rtw_memcmp(P2P_OUI, oui, 4))
+ update_bcn_p2p_ie(padapter);
+ else
+ DBG_88E("unknown OUI type!\n");
+}
+
+void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
+{
+ unsigned long irqL;
+ struct mlme_priv *pmlmepriv;
+ struct mlme_ext_priv *pmlmeext;
+
+ if (!padapter)
+ return;
+
+ pmlmepriv = &(padapter->mlmepriv);
+ pmlmeext = &(padapter->mlmeextpriv);
+
+ if (!pmlmeext->bstart_bss)
+ return;
+
+ _enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+
+ switch (ie_id) {
+ case 0xFF:
+ update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */
+ break;
+ case _TIM_IE_:
+ update_BCNTIM(padapter);
+ break;
+ case _ERPINFO_IE_:
+ update_bcn_erpinfo_ie(padapter);
+ break;
+ case _HT_CAPABILITY_IE_:
+ update_bcn_htcap_ie(padapter);
+ break;
+ case _RSN_IE_2_:
+ update_bcn_rsn_ie(padapter);
+ break;
+ case _HT_ADD_INFO_IE_:
+ update_bcn_htinfo_ie(padapter);
+ break;
+ case _VENDOR_SPECIFIC_IE_:
+ update_bcn_vendor_spec_ie(padapter, oui);
+ break;
+ default:
+ break;
+ }
+
+ pmlmepriv->update_bcn = true;
+
+ _exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+
+ if (tx)
+ set_tx_beacon_cmd(padapter);
+}
+
+/*
+op_mode
+Set to 0 (HT pure) under the followign conditions
+ - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+ - all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+ in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+ however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+ (currently non-GF HT station is considered as non-HT STA also)
+*/
+static int rtw_ht_operation_update(struct adapter *padapter)
+{
+ u16 cur_op_mode, new_op_mode;
+ int op_mode_changes = 0;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv;
+
+ if (pmlmepriv->htpriv.ht_option)
+ return 0;
+
+ DBG_88E("%s current operation mode = 0x%X\n",
+ __func__, pmlmepriv->ht_op_mode);
+
+ if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+ pmlmepriv->num_sta_ht_no_gf) {
+ pmlmepriv->ht_op_mode |=
+ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+ op_mode_changes++;
+ } else if ((pmlmepriv->ht_op_mode &
+ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+ pmlmepriv->num_sta_ht_no_gf == 0) {
+ pmlmepriv->ht_op_mode &=
+ ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+ op_mode_changes++;
+ }
+
+ if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+ (pmlmepriv->num_sta_no_ht || pmlmepriv->olbc_ht)) {
+ pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+ op_mode_changes++;
+ } else if ((pmlmepriv->ht_op_mode &
+ HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+ (pmlmepriv->num_sta_no_ht == 0 && !pmlmepriv->olbc_ht)) {
+ pmlmepriv->ht_op_mode &=
+ ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+ op_mode_changes++;
+ }
+
+ /* Note: currently we switch to the MIXED op mode if HT non-greenfield
+ * station is associated. Probably it's a theoretical case, since
+ * it looks like all known HT STAs support greenfield.
+ */
+ new_op_mode = 0;
+ if (pmlmepriv->num_sta_no_ht ||
+ (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT))
+ new_op_mode = OP_MODE_MIXED;
+ else if ((phtpriv_ap->ht_cap.cap_info & IEEE80211_HT_CAP_SUP_WIDTH) &&
+ pmlmepriv->num_sta_ht_20mhz)
+ new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+ else if (pmlmepriv->olbc_ht)
+ new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+ else
+ new_op_mode = OP_MODE_PURE;
+
+ cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+ if (cur_op_mode != new_op_mode) {
+ pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+ pmlmepriv->ht_op_mode |= new_op_mode;
+ op_mode_changes++;
+ }
+
+ DBG_88E("%s new operation mode = 0x%X changes =%d\n",
+ __func__, pmlmepriv->ht_op_mode, op_mode_changes);
+
+ return op_mode_changes;
+}
+
+void associated_clients_update(struct adapter *padapter, u8 updated)
+{
+ /* update associcated stations cap. */
+ if (updated) {
+ unsigned long irqL;
+ struct list_head *phead, *plist;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ phead = &pstapriv->asoc_list;
+ plist = get_next(phead);
+
+ /* check asoc_queue */
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+ plist = get_next(plist);
+
+ VCS_update(padapter, psta);
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ }
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
+{
+ u8 beacon_updated = false;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+ if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) {
+ if (!psta->no_short_preamble_set) {
+ psta->no_short_preamble_set = 1;
+
+ pmlmepriv->num_sta_no_short_preamble++;
+
+ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+ (pmlmepriv->num_sta_no_short_preamble == 1)) {
+ beacon_updated = true;
+ update_beacon(padapter, 0xFF, NULL, true);
+ }
+ }
+ } else {
+ if (psta->no_short_preamble_set) {
+ psta->no_short_preamble_set = 0;
+
+ pmlmepriv->num_sta_no_short_preamble--;
+
+ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+ (pmlmepriv->num_sta_no_short_preamble == 0)) {
+ beacon_updated = true;
+ update_beacon(padapter, 0xFF, NULL, true);
+ }
+ }
+ }
+
+ if (psta->flags & WLAN_STA_NONERP) {
+ if (!psta->nonerp_set) {
+ psta->nonerp_set = 1;
+
+ pmlmepriv->num_sta_non_erp++;
+
+ if (pmlmepriv->num_sta_non_erp == 1) {
+ beacon_updated = true;
+ update_beacon(padapter, _ERPINFO_IE_, NULL, true);
+ }
+ }
+ } else {
+ if (psta->nonerp_set) {
+ psta->nonerp_set = 0;
+
+ pmlmepriv->num_sta_non_erp--;
+
+ if (pmlmepriv->num_sta_non_erp == 0) {
+ beacon_updated = true;
+ update_beacon(padapter, _ERPINFO_IE_, NULL, true);
+ }
+ }
+ }
+
+ if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) {
+ if (!psta->no_short_slot_time_set) {
+ psta->no_short_slot_time_set = 1;
+
+ pmlmepriv->num_sta_no_short_slot_time++;
+
+ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+ (pmlmepriv->num_sta_no_short_slot_time == 1)) {
+ beacon_updated = true;
+ update_beacon(padapter, 0xFF, NULL, true);
+ }
+ }
+ } else {
+ if (psta->no_short_slot_time_set) {
+ psta->no_short_slot_time_set = 0;
+
+ pmlmepriv->num_sta_no_short_slot_time--;
+
+ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+ (pmlmepriv->num_sta_no_short_slot_time == 0)) {
+ beacon_updated = true;
+ update_beacon(padapter, 0xFF, NULL, true);
+ }
+ }
+ }
+
+ if (psta->flags & WLAN_STA_HT) {
+ u16 ht_capab = psta->htpriv.ht_cap.cap_info;
+
+ DBG_88E("HT: STA %pM HT Capabilities Info: 0x%04x\n",
+ (psta->hwaddr), ht_capab);
+
+ if (psta->no_ht_set) {
+ psta->no_ht_set = 0;
+ pmlmepriv->num_sta_no_ht--;
+ }
+
+ if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) {
+ if (!psta->no_ht_gf_set) {
+ psta->no_ht_gf_set = 1;
+ pmlmepriv->num_sta_ht_no_gf++;
+ }
+ DBG_88E("%s STA %pM - no greenfield, num of non-gf stations %d\n",
+ __func__, (psta->hwaddr),
+ pmlmepriv->num_sta_ht_no_gf);
+ }
+
+ if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) {
+ if (!psta->ht_20mhz_set) {
+ psta->ht_20mhz_set = 1;
+ pmlmepriv->num_sta_ht_20mhz++;
+ }
+ DBG_88E("%s STA %pM - 20 MHz HT, num of 20MHz HT STAs %d\n",
+ __func__, (psta->hwaddr),
+ pmlmepriv->num_sta_ht_20mhz);
+ }
+ } else {
+ if (!psta->no_ht_set) {
+ psta->no_ht_set = 1;
+ pmlmepriv->num_sta_no_ht++;
+ }
+ if (pmlmepriv->htpriv.ht_option) {
+ DBG_88E("%s STA %pM - no HT, num of non-HT stations %d\n",
+ __func__, (psta->hwaddr),
+ pmlmepriv->num_sta_no_ht);
+ }
+ }
+
+ if (rtw_ht_operation_update(padapter) > 0) {
+ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false);
+ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
+ }
+
+ /* update associcated stations cap. */
+ associated_clients_update(padapter, beacon_updated);
+
+ DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
+}
+
+u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
+{
+ u8 beacon_updated = false;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+ if (!psta)
+ return beacon_updated;
+
+ if (psta->no_short_preamble_set) {
+ psta->no_short_preamble_set = 0;
+ pmlmepriv->num_sta_no_short_preamble--;
+ if (pmlmeext->cur_wireless_mode > WIRELESS_11B &&
+ pmlmepriv->num_sta_no_short_preamble == 0) {
+ beacon_updated = true;
+ update_beacon(padapter, 0xFF, NULL, true);
+ }
+ }
+
+ if (psta->nonerp_set) {
+ psta->nonerp_set = 0;
+ pmlmepriv->num_sta_non_erp--;
+ if (pmlmepriv->num_sta_non_erp == 0) {
+ beacon_updated = true;
+ update_beacon(padapter, _ERPINFO_IE_, NULL, true);
+ }
+ }
+
+ if (psta->no_short_slot_time_set) {
+ psta->no_short_slot_time_set = 0;
+ pmlmepriv->num_sta_no_short_slot_time--;
+ if (pmlmeext->cur_wireless_mode > WIRELESS_11B &&
+ pmlmepriv->num_sta_no_short_slot_time == 0) {
+ beacon_updated = true;
+ update_beacon(padapter, 0xFF, NULL, true);
+ }
+ }
+
+ if (psta->no_ht_gf_set) {
+ psta->no_ht_gf_set = 0;
+ pmlmepriv->num_sta_ht_no_gf--;
+ }
+
+ if (psta->no_ht_set) {
+ psta->no_ht_set = 0;
+ pmlmepriv->num_sta_no_ht--;
+ }
+
+ if (psta->ht_20mhz_set) {
+ psta->ht_20mhz_set = 0;
+ pmlmepriv->num_sta_ht_20mhz--;
+ }
+
+ if (rtw_ht_operation_update(padapter) > 0) {
+ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false);
+ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
+ }
+
+ /* update associcated stations cap. */
+
+ DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
+
+ return beacon_updated;
+}
+
+u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta,
+ bool active, u16 reason)
+{
+ unsigned long irqL;
+ u8 beacon_updated = false;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ if (!psta)
+ return beacon_updated;
+
+ /* tear down Rx AMPDU */
+ send_delba(padapter, 0, psta->hwaddr);/* recipient */
+
+ /* tear down TX AMPDU */
+ send_delba(padapter, 1, psta->hwaddr);/* originator */
+ psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+ psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+
+ if (active)
+ issue_deauth(padapter, psta->hwaddr, reason);
+
+ /* clear cam entry / key */
+ rtw_clearstakey_cmd(padapter, (u8 *)psta, (u8)(psta->mac_id + 3), true);
+
+
+ _enter_critical_bh(&psta->lock, &irqL);
+ psta->state &= ~_FW_LINKED;
+ _exit_critical_bh(&psta->lock, &irqL);
+
+ rtw_indicate_sta_disassoc_event(padapter, psta);
+
+ report_del_sta_event(padapter, psta->hwaddr, reason);
+
+ beacon_updated = bss_cap_update_on_sta_leave(padapter, psta);
+
+ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+ rtw_free_stainfo(padapter, psta);
+ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+
+ return beacon_updated;
+}
+
+int rtw_ap_inform_ch_switch(struct adapter *padapter, u8 new_ch, u8 ch_offset)
+{
+ unsigned long irqL;
+ struct list_head *phead, *plist;
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+ return ret;
+
+ DBG_88E(FUNC_NDEV_FMT" with ch:%u, offset:%u\n",
+ FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset);
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ phead = &pstapriv->asoc_list;
+ plist = get_next(phead);
+
+ /* for each sta in asoc_queue */
+ while (!rtw_end_of_queue_search(phead, plist)) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+ plist = get_next(plist);
+
+ issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset);
+ psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2);
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset);
+
+ return ret;
+}
+
+int rtw_sta_flush(struct adapter *padapter)
+{
+ unsigned long irqL;
+ struct list_head *phead, *plist;
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+ return ret;
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ phead = &pstapriv->asoc_list;
+ plist = get_next(phead);
+
+ /* free sta asoc_queue */
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+ plist = get_next(plist);
+
+ rtw_list_delete(&psta->asoc_list);
+ pstapriv->asoc_list_cnt--;
+
+ ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+
+ issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING);
+
+ associated_clients_update(padapter, true);
+
+ return ret;
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void sta_info_update(struct adapter *padapter, struct sta_info *psta)
+{
+ int flags = psta->flags;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ /* update wmm cap. */
+ if (WLAN_STA_WME&flags)
+ psta->qos_option = 1;
+ else
+ psta->qos_option = 0;
+
+ if (pmlmepriv->qospriv.qos_option == 0)
+ psta->qos_option = 0;
+
+ /* update 802.11n ht cap. */
+ if (WLAN_STA_HT&flags) {
+ psta->htpriv.ht_option = true;
+ psta->qos_option = 1;
+ } else {
+ psta->htpriv.ht_option = false;
+ }
+
+ if (!pmlmepriv->htpriv.ht_option)
+ psta->htpriv.ht_option = false;
+
+ update_sta_info_apmode(padapter, psta);
+}
+
+/* called >= TSR LEVEL for USB or SDIO Interface*/
+void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta)
+{
+ if (psta->state & _FW_LINKED) {
+ /* add ratid */
+ add_RATid(padapter, psta, 0);/* DM_RATR_STA_INIT */
+ }
+}
+
+void start_ap_mode(struct adapter *padapter)
+{
+ int i;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+ pmlmepriv->update_bcn = false;
+
+ pmlmeext->bstart_bss = false;
+
+ pmlmepriv->num_sta_non_erp = 0;
+
+ pmlmepriv->num_sta_no_short_slot_time = 0;
+
+ pmlmepriv->num_sta_no_short_preamble = 0;
+
+ pmlmepriv->num_sta_ht_no_gf = 0;
+ pmlmepriv->num_sta_no_ht = 0;
+ pmlmepriv->num_sta_ht_20mhz = 0;
+
+ pmlmepriv->olbc = false;
+
+ pmlmepriv->olbc_ht = false;
+
+ pmlmepriv->ht_op_mode = 0;
+
+ for (i = 0; i < NUM_STA; i++)
+ pstapriv->sta_aid[i] = NULL;
+
+ pmlmepriv->wps_beacon_ie = NULL;
+ pmlmepriv->wps_probe_resp_ie = NULL;
+ pmlmepriv->wps_assoc_resp_ie = NULL;
+
+ pmlmepriv->p2p_beacon_ie = NULL;
+ pmlmepriv->p2p_probe_resp_ie = NULL;
+
+ /* for ACL */
+ _rtw_init_listhead(&(pacl_list->acl_node_q.queue));
+ pacl_list->num = 0;
+ pacl_list->mode = 0;
+ for (i = 0; i < NUM_ACL; i++) {
+ _rtw_init_listhead(&pacl_list->aclnode[i].list);
+ pacl_list->aclnode[i].valid = false;
+ }
+}
+
+void stop_ap_mode(struct adapter *padapter)
+{
+ unsigned long irqL;
+ struct list_head *phead, *plist;
+ struct rtw_wlan_acl_node *paclnode;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+ struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+ pmlmepriv->update_bcn = false;
+ pmlmeext->bstart_bss = false;
+
+ /* reset and init security priv , this can refine with rtw_reset_securitypriv */
+ _rtw_memset((unsigned char *)&padapter->securitypriv, 0, sizeof(struct security_priv));
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+
+ /* for ACL */
+ _enter_critical_bh(&(pacl_node_q->lock), &irqL);
+ phead = get_list_head(pacl_node_q);
+ plist = get_next(phead);
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+ plist = get_next(plist);
+
+ if (paclnode->valid) {
+ paclnode->valid = false;
+
+ rtw_list_delete(&paclnode->list);
+
+ pacl_list->num--;
+ }
+ }
+ _exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+ DBG_88E("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num);
+
+ rtw_sta_flush(padapter);
+
+ /* free_assoc_sta_resources */
+ rtw_free_all_stainfo(padapter);
+
+ psta = rtw_get_bcmc_stainfo(padapter);
+ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+ rtw_free_stainfo(padapter, psta);
+ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+
+ rtw_init_bcmc_stainfo(padapter);
+
+ rtw_free_mlme_priv_ie_data(pmlmepriv);
+}
+
+#endif /* CONFIG_88EU_AP_MODE */
diff --git a/drivers/staging/rtl8188eu/core/rtw_br_ext.c b/drivers/staging/rtl8188eu/core/rtw_br_ext.c
new file mode 100644
index 00000000000..fbca394cf4f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_br_ext.c
@@ -0,0 +1,1199 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_BR_EXT_C_
+
+#include <linux/if_arp.h>
+#include <net/ip.h>
+#include <net/ipx.h>
+#include <linux/atalk.h>
+#include <linux/udp.h>
+#include <linux/if_pppox.h>
+
+#include <drv_types.h>
+#include "rtw_br_ext.h"
+#include <usb_osintf.h>
+#include <recv_osdep.h>
+
+#ifndef csum_ipv6_magic
+#include <net/ip6_checksum.h>
+#endif
+
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <net/ndisc.h>
+#include <net/checksum.h>
+
+#define NAT25_IPV4 01
+#define NAT25_IPV6 02
+#define NAT25_IPX 03
+#define NAT25_APPLE 04
+#define NAT25_PPPOE 05
+
+#define RTL_RELAY_TAG_LEN (ETH_ALEN)
+#define TAG_HDR_LEN 4
+
+#define MAGIC_CODE 0x8186
+#define MAGIC_CODE_LEN 2
+#define WAIT_TIME_PPPOE 5 /* waiting time for pppoe server in sec */
+
+/*-----------------------------------------------------------------
+ How database records network address:
+ 0 1 2 3 4 5 6 7 8 9 10
+ |----|----|----|----|----|----|----|----|----|----|----|
+ IPv4 |type| | IP addr |
+ IPX |type| Net addr | Node addr |
+ IPX |type| Net addr |Sckt addr|
+ Apple |type| Network |node|
+ PPPoE |type| SID | AC MAC |
+-----------------------------------------------------------------*/
+
+
+/* Find a tag in pppoe frame and return the pointer */
+static inline unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type)
+{
+ unsigned char *cur_ptr, *start_ptr;
+ unsigned short tagLen, tagType;
+
+ start_ptr = cur_ptr = (unsigned char *)ph->tag;
+ while ((cur_ptr - start_ptr) < ntohs(ph->length)) {
+ /* prevent un-alignment access */
+ tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]);
+ tagLen = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]);
+ if (tagType == type)
+ return cur_ptr;
+ cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen;
+ }
+ return NULL;
+}
+
+
+static inline int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag)
+{
+ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+ int data_len;
+
+ data_len = tag->tag_len + TAG_HDR_LEN;
+ if (skb_tailroom(skb) < data_len) {
+ _DEBUG_ERR("skb_tailroom() failed in add SID tag!\n");
+ return -1;
+ }
+
+ skb_put(skb, data_len);
+ /* have a room for new tag */
+ memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length));
+ ph->length = htons(ntohs(ph->length) + data_len);
+ memcpy((unsigned char *)ph->tag, tag, data_len);
+ return data_len;
+}
+
+static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len)
+{
+ int tail_len;
+ unsigned long end, tail;
+
+ if ((src+len) > skb_tail_pointer(skb) || skb->len < len)
+ return -1;
+
+ tail = (unsigned long)skb_tail_pointer(skb);
+ end = (unsigned long)src+len;
+ if (tail < end)
+ return -1;
+
+ tail_len = (int)(tail-end);
+ if (tail_len > 0)
+ memmove(src, src+len, tail_len);
+
+ skb_trim(skb, skb->len-len);
+ return 0;
+}
+
+static inline unsigned long __nat25_timeout(struct adapter *priv)
+{
+ unsigned long timeout;
+
+ timeout = jiffies - NAT25_AGEING_TIME*HZ;
+
+ return timeout;
+}
+
+
+static inline int __nat25_has_expired(struct adapter *priv,
+ struct nat25_network_db_entry *fdb)
+{
+ if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv)))
+ return 1;
+
+ return 0;
+}
+
+
+static inline void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr,
+ unsigned int *ipAddr)
+{
+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+ networkAddr[0] = NAT25_IPV4;
+ memcpy(networkAddr+7, (unsigned char *)ipAddr, 4);
+}
+
+
+static inline void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr,
+ unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr)
+{
+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+ networkAddr[0] = NAT25_IPX;
+ memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4);
+ memcpy(networkAddr+5, ipxNodeAddr, 6);
+}
+
+
+static inline void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr,
+ unsigned int *ipxNetAddr, unsigned short *ipxSocketAddr)
+{
+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+ networkAddr[0] = NAT25_IPX;
+ memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4);
+ memcpy(networkAddr+5, (unsigned char *)ipxSocketAddr, 2);
+}
+
+
+static inline void __nat25_generate_apple_network_addr(unsigned char *networkAddr,
+ unsigned short *network, unsigned char *node)
+{
+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+ networkAddr[0] = NAT25_APPLE;
+ memcpy(networkAddr+1, (unsigned char *)network, 2);
+ networkAddr[3] = *node;
+}
+
+static inline void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr,
+ unsigned char *ac_mac, unsigned short *sid)
+{
+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+ networkAddr[0] = NAT25_PPPOE;
+ memcpy(networkAddr+1, (unsigned char *)sid, 2);
+ memcpy(networkAddr+3, (unsigned char *)ac_mac, 6);
+}
+
+static void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr,
+ unsigned int *ipAddr)
+{
+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+ networkAddr[0] = NAT25_IPV6;
+ memcpy(networkAddr+1, (unsigned char *)ipAddr, 16);
+}
+
+static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b)
+{
+ while (len > 0) {
+ if (*data == tag && *(data+1) == len8b && len >= len8b*8)
+ return data+2;
+
+ len -= (*(data+1))*8;
+ data += (*(data+1))*8;
+ }
+ return NULL;
+}
+
+static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac)
+{
+ struct icmp6hdr *icmphdr = (struct icmp6hdr *)data;
+ unsigned char *mac;
+
+ if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) {
+ if (len >= 8) {
+ mac = scan_tlv(&data[8], len-8, 1, 1);
+ if (mac) {
+ _DEBUG_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+ memcpy(mac, replace_mac, 6);
+ return 1;
+ }
+ }
+ } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) {
+ if (len >= 16) {
+ mac = scan_tlv(&data[16], len-16, 1, 1);
+ if (mac) {
+ _DEBUG_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+ memcpy(mac, replace_mac, 6);
+ return 1;
+ }
+ }
+ } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
+ if (len >= 24) {
+ mac = scan_tlv(&data[24], len-24, 1, 1);
+ if (mac) {
+ _DEBUG_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+ memcpy(mac, replace_mac, 6);
+ return 1;
+ }
+ }
+ } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) {
+ if (len >= 24) {
+ mac = scan_tlv(&data[24], len-24, 2, 1);
+ if (mac) {
+ _DEBUG_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+ memcpy(mac, replace_mac, 6);
+ return 1;
+ }
+ }
+ } else if (icmphdr->icmp6_type == NDISC_REDIRECT) {
+ if (len >= 40) {
+ mac = scan_tlv(&data[40], len-40, 2, 1);
+ if (mac) {
+ _DEBUG_INFO("Redirect, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+ memcpy(mac, replace_mac, 6);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static inline int __nat25_network_hash(unsigned char *networkAddr)
+{
+ if (networkAddr[0] == NAT25_IPV4) {
+ unsigned long x;
+
+ x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ } else if (networkAddr[0] == NAT25_IPX) {
+ unsigned long x;
+
+ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ } else if (networkAddr[0] == NAT25_APPLE) {
+ unsigned long x;
+
+ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ } else if (networkAddr[0] == NAT25_PPPOE) {
+ unsigned long x;
+
+ x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ } else if (networkAddr[0] == NAT25_IPV6) {
+ unsigned long x;
+
+ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^
+ networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^
+ networkAddr[16];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ } else {
+ unsigned long x = 0;
+ int i;
+
+ for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++)
+ x ^= networkAddr[i];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ }
+}
+
+static inline void __network_hash_link(struct adapter *priv,
+ struct nat25_network_db_entry *ent, int hash)
+{
+ /* Caller must _enter_critical_bh already! */
+ ent->next_hash = priv->nethash[hash];
+ if (ent->next_hash != NULL)
+ ent->next_hash->pprev_hash = &ent->next_hash;
+ priv->nethash[hash] = ent;
+ ent->pprev_hash = &priv->nethash[hash];
+}
+
+static inline void __network_hash_unlink(struct nat25_network_db_entry *ent)
+{
+ /* Caller must _enter_critical_bh already! */
+ *(ent->pprev_hash) = ent->next_hash;
+ if (ent->next_hash != NULL)
+ ent->next_hash->pprev_hash = ent->pprev_hash;
+ ent->next_hash = NULL;
+ ent->pprev_hash = NULL;
+}
+
+static int __nat25_db_network_lookup_and_replace(struct adapter *priv,
+ struct sk_buff *skb, unsigned char *networkAddr)
+{
+ struct nat25_network_db_entry *db;
+ unsigned long irqL;
+ _enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+ db = priv->nethash[__nat25_network_hash(networkAddr)];
+ while (db != NULL) {
+ if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+ if (!__nat25_has_expired(priv, db)) {
+ /* replace the destination mac address */
+ memcpy(skb->data, db->macAddr, ETH_ALEN);
+ atomic_inc(&db->use_count);
+
+ DEBUG_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+ "%02x%02x%02x%02x%02x%02x\n",
+ db->macAddr[0],
+ db->macAddr[1],
+ db->macAddr[2],
+ db->macAddr[3],
+ db->macAddr[4],
+ db->macAddr[5],
+ db->networkAddr[0],
+ db->networkAddr[1],
+ db->networkAddr[2],
+ db->networkAddr[3],
+ db->networkAddr[4],
+ db->networkAddr[5],
+ db->networkAddr[6],
+ db->networkAddr[7],
+ db->networkAddr[8],
+ db->networkAddr[9],
+ db->networkAddr[10],
+ db->networkAddr[11],
+ db->networkAddr[12],
+ db->networkAddr[13],
+ db->networkAddr[14],
+ db->networkAddr[15],
+ db->networkAddr[16]);
+ }
+ _exit_critical_bh(&priv->br_ext_lock, &irqL);
+ return 1;
+ }
+ db = db->next_hash;
+ }
+ _exit_critical_bh(&priv->br_ext_lock, &irqL);
+ return 0;
+}
+
+static void __nat25_db_network_insert(struct adapter *priv,
+ unsigned char *macAddr, unsigned char *networkAddr)
+{
+ struct nat25_network_db_entry *db;
+ int hash;
+ unsigned long irqL;
+
+ _enter_critical_bh(&priv->br_ext_lock, &irqL);
+ hash = __nat25_network_hash(networkAddr);
+ db = priv->nethash[hash];
+ while (db != NULL) {
+ if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+ memcpy(db->macAddr, macAddr, ETH_ALEN);
+ db->ageing_timer = jiffies;
+ _exit_critical_bh(&priv->br_ext_lock, &irqL);
+ return;
+ }
+ db = db->next_hash;
+ }
+ db = (struct nat25_network_db_entry *) rtw_malloc(sizeof(*db));
+ if (db == NULL) {
+ _exit_critical_bh(&priv->br_ext_lock, &irqL);
+ return;
+ }
+ memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN);
+ memcpy(db->macAddr, macAddr, ETH_ALEN);
+ atomic_set(&db->use_count, 1);
+ db->ageing_timer = jiffies;
+
+ __network_hash_link(priv, db, hash);
+
+ _exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+static void __nat25_db_print(struct adapter *priv)
+{
+}
+
+/*
+ * NAT2.5 interface
+ */
+
+void nat25_db_cleanup(struct adapter *priv)
+{
+ int i;
+ unsigned long irqL;
+ _enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+ for (i = 0; i < NAT25_HASH_SIZE; i++) {
+ struct nat25_network_db_entry *f;
+ f = priv->nethash[i];
+ while (f != NULL) {
+ struct nat25_network_db_entry *g;
+
+ g = f->next_hash;
+ if (priv->scdb_entry == f) {
+ memset(priv->scdb_mac, 0, ETH_ALEN);
+ memset(priv->scdb_ip, 0, 4);
+ priv->scdb_entry = NULL;
+ }
+ __network_hash_unlink(f);
+ kfree(f);
+ f = g;
+ }
+ }
+ _exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+void nat25_db_expire(struct adapter *priv)
+{
+ int i;
+ unsigned long irqL;
+ _enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+ for (i = 0; i < NAT25_HASH_SIZE; i++) {
+ struct nat25_network_db_entry *f;
+ f = priv->nethash[i];
+
+ while (f != NULL) {
+ struct nat25_network_db_entry *g;
+ g = f->next_hash;
+
+ if (__nat25_has_expired(priv, f)) {
+ if (atomic_dec_and_test(&f->use_count)) {
+ if (priv->scdb_entry == f) {
+ memset(priv->scdb_mac, 0, ETH_ALEN);
+ memset(priv->scdb_ip, 0, 4);
+ priv->scdb_entry = NULL;
+ }
+ __network_hash_unlink(f);
+ kfree(f);
+ }
+ }
+ f = g;
+ }
+ }
+ _exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method)
+{
+ unsigned short protocol;
+ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+ unsigned int tmp;
+
+ if (skb == NULL)
+ return -1;
+
+ if ((method <= NAT25_MIN) || (method >= NAT25_MAX))
+ return -1;
+
+ protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
+
+ /*---------------------------------------------------*/
+ /* Handle IP frame */
+ /*---------------------------------------------------*/
+ if (protocol == ETH_P_IP) {
+ struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+ if (((unsigned char *)(iph) + (iph->ihl<<2)) >= (skb->data + ETH_HLEN + skb->len)) {
+ DEBUG_WARN("NAT25: malformed IP packet !\n");
+ return -1;
+ }
+
+ switch (method) {
+ case NAT25_CHECK:
+ return -1;
+ case NAT25_INSERT:
+ /* some muticast with source IP is all zero, maybe other case is illegal */
+ /* in class A, B, C, host address is all zero or all one is illegal */
+ if (iph->saddr == 0)
+ return 0;
+ tmp = be32_to_cpu(iph->saddr);
+ DEBUG_INFO("NAT25: Insert IP, SA =%08x, DA =%08x\n", tmp, iph->daddr);
+ __nat25_generate_ipv4_network_addr(networkAddr, &tmp);
+ /* record source IP address and , source mac address into db */
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+ __nat25_db_print(priv);
+ return 0;
+ case NAT25_LOOKUP:
+ DEBUG_INFO("NAT25: Lookup IP, SA =%08x, DA =%08x\n", iph->saddr, iph->daddr);
+ tmp = be32_to_cpu(iph->daddr);
+ __nat25_generate_ipv4_network_addr(networkAddr, &tmp);
+
+ if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) {
+ if (*((unsigned char *)&iph->daddr + 3) == 0xff) {
+ /* L2 is unicast but L3 is broadcast, make L2 bacome broadcast */
+ DEBUG_INFO("NAT25: Set DA as boardcast\n");
+ memset(skb->data, 0xff, ETH_ALEN);
+ } else {
+ /* forward unknow IP packet to upper TCP/IP */
+ DEBUG_INFO("NAT25: Replace DA with BR's MAC\n");
+ if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac+4)) == 0) {
+ printk("Re-init netdev_br_init() due to br_mac == 0!\n");
+ netdev_br_init(priv->pnetdev);
+ }
+ memcpy(skb->data, priv->br_mac, ETH_ALEN);
+ }
+ }
+ return 0;
+ default:
+ return -1;
+ }
+ } else if (protocol == ETH_P_ARP) {
+ /*---------------------------------------------------*/
+ /* Handle ARP frame */
+ /*---------------------------------------------------*/
+ struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN);
+ unsigned char *arp_ptr = (unsigned char *)(arp + 1);
+ unsigned int *sender, *target;
+
+ if (arp->ar_pro != __constant_htons(ETH_P_IP)) {
+ DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", be16_to_cpu(arp->ar_pro));
+ return -1;
+ }
+
+ switch (method) {
+ case NAT25_CHECK:
+ return 0; /* skb_copy for all ARP frame */
+ case NAT25_INSERT:
+ DEBUG_INFO("NAT25: Insert ARP, MAC =%02x%02x%02x%02x%02x%02x\n", arp_ptr[0],
+ arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]);
+
+ /* change to ARP sender mac address to wlan STA address */
+ memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN);
+ arp_ptr += arp->ar_hln;
+ sender = (unsigned int *)arp_ptr;
+ __nat25_generate_ipv4_network_addr(networkAddr, sender);
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+ __nat25_db_print(priv);
+ return 0;
+ case NAT25_LOOKUP:
+ DEBUG_INFO("NAT25: Lookup ARP\n");
+
+ arp_ptr += arp->ar_hln;
+ sender = (unsigned int *)arp_ptr;
+ arp_ptr += (arp->ar_hln + arp->ar_pln);
+ target = (unsigned int *)arp_ptr;
+ __nat25_generate_ipv4_network_addr(networkAddr, target);
+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+ /* change to ARP target mac address to Lookup result */
+ arp_ptr = (unsigned char *)(arp + 1);
+ arp_ptr += (arp->ar_hln + arp->ar_pln);
+ memcpy(arp_ptr, skb->data, ETH_ALEN);
+ return 0;
+ default:
+ return -1;
+ }
+ } else if ((protocol == ETH_P_IPX) ||
+ (protocol <= ETH_FRAME_LEN)) {
+ /*---------------------------------------------------*/
+ /* Handle IPX and Apple Talk frame */
+ /*---------------------------------------------------*/
+ unsigned char ipx_header[2] = {0xFF, 0xFF};
+ struct ipxhdr *ipx = NULL;
+ struct elapaarp *ea = NULL;
+ struct ddpehdr *ddp = NULL;
+ unsigned char *framePtr = skb->data + ETH_HLEN;
+
+ if (protocol == ETH_P_IPX) {
+ DEBUG_INFO("NAT25: Protocol = IPX (Ethernet II)\n");
+ ipx = (struct ipxhdr *)framePtr;
+ } else if (protocol <= ETH_FRAME_LEN) {
+ if (!memcmp(ipx_header, framePtr, 2)) {
+ DEBUG_INFO("NAT25: Protocol = IPX (Ethernet 802.3)\n");
+ ipx = (struct ipxhdr *)framePtr;
+ } else {
+ unsigned char ipx_8022_type = 0xE0;
+ unsigned char snap_8022_type = 0xAA;
+
+ if (*framePtr == snap_8022_type) {
+ unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37}; /* IPX SNAP ID */
+ unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3}; /* Apple Talk AARP SNAP ID */
+ unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B}; /* Apple Talk DDP SNAP ID */
+
+ framePtr += 3; /* eliminate the 802.2 header */
+
+ if (!memcmp(ipx_snap_id, framePtr, 5)) {
+ framePtr += 5; /* eliminate the SNAP header */
+
+ DEBUG_INFO("NAT25: Protocol = IPX (Ethernet SNAP)\n");
+ ipx = (struct ipxhdr *)framePtr;
+ } else if (!memcmp(aarp_snap_id, framePtr, 5)) {
+ framePtr += 5; /* eliminate the SNAP header */
+
+ ea = (struct elapaarp *)framePtr;
+ } else if (!memcmp(ddp_snap_id, framePtr, 5)) {
+ framePtr += 5; /* eliminate the SNAP header */
+
+ ddp = (struct ddpehdr *)framePtr;
+ } else {
+ DEBUG_WARN("NAT25: Protocol = Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0],
+ framePtr[1], framePtr[2], framePtr[3], framePtr[4]);
+ return -1;
+ }
+ } else if (*framePtr == ipx_8022_type) {
+ framePtr += 3; /* eliminate the 802.2 header */
+
+ if (!memcmp(ipx_header, framePtr, 2)) {
+ DEBUG_INFO("NAT25: Protocol = IPX (Ethernet 802.2)\n");
+ ipx = (struct ipxhdr *)framePtr;
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ } else {
+ return -1;
+ }
+
+ /* IPX */
+ if (ipx != NULL) {
+ switch (method) {
+ case NAT25_CHECK:
+ if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN))
+ DEBUG_INFO("NAT25: Check IPX skb_copy\n");
+ return 0;
+ return -1;
+ case NAT25_INSERT:
+ DEBUG_INFO("NAT25: Insert IPX, Dest =%08x,%02x%02x%02x%02x%02x%02x,%04x Source =%08x,%02x%02x%02x%02x%02x%02x,%04x\n",
+ ipx->ipx_dest.net,
+ ipx->ipx_dest.node[0],
+ ipx->ipx_dest.node[1],
+ ipx->ipx_dest.node[2],
+ ipx->ipx_dest.node[3],
+ ipx->ipx_dest.node[4],
+ ipx->ipx_dest.node[5],
+ ipx->ipx_dest.sock,
+ ipx->ipx_source.net,
+ ipx->ipx_source.node[0],
+ ipx->ipx_source.node[1],
+ ipx->ipx_source.node[2],
+ ipx->ipx_source.node[3],
+ ipx->ipx_source.node[4],
+ ipx->ipx_source.node[5],
+ ipx->ipx_source.sock);
+
+ if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) {
+ DEBUG_INFO("NAT25: Use IPX Net, and Socket as network addr\n");
+
+ __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock);
+
+ /* change IPX source node addr to wlan STA address */
+ memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN);
+ } else {
+ __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node);
+ }
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+ __nat25_db_print(priv);
+ return 0;
+ case NAT25_LOOKUP:
+ if (!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN)) {
+ DEBUG_INFO("NAT25: Lookup IPX, Modify Destination IPX Node addr\n");
+
+ __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock);
+
+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+ /* replace IPX destination node addr with Lookup destination MAC addr */
+ memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN);
+ } else {
+ __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node);
+
+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+ }
+ return 0;
+ default:
+ return -1;
+ }
+ } else if (ea != NULL) {
+ /* Sanity check fields. */
+ if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) {
+ DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n");
+ return -1;
+ }
+
+ switch (method) {
+ case NAT25_CHECK:
+ return 0;
+ case NAT25_INSERT:
+ /* change to AARP source mac address to wlan STA address */
+ memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN);
+
+ DEBUG_INFO("NAT25: Insert AARP, Source =%d,%d Destination =%d,%d\n",
+ ea->pa_src_net,
+ ea->pa_src_node,
+ ea->pa_dst_net,
+ ea->pa_dst_node);
+
+ __nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node);
+
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+ __nat25_db_print(priv);
+ return 0;
+ case NAT25_LOOKUP:
+ DEBUG_INFO("NAT25: Lookup AARP, Source =%d,%d Destination =%d,%d\n",
+ ea->pa_src_net,
+ ea->pa_src_node,
+ ea->pa_dst_net,
+ ea->pa_dst_node);
+
+ __nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node);
+
+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+ /* change to AARP destination mac address to Lookup result */
+ memcpy(ea->hw_dst, skb->data, ETH_ALEN);
+ return 0;
+ default:
+ return -1;
+ }
+ } else if (ddp != NULL) {
+ switch (method) {
+ case NAT25_CHECK:
+ return -1;
+ case NAT25_INSERT:
+ DEBUG_INFO("NAT25: Insert DDP, Source =%d,%d Destination =%d,%d\n",
+ ddp->deh_snet,
+ ddp->deh_snode,
+ ddp->deh_dnet,
+ ddp->deh_dnode);
+
+ __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode);
+
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+ __nat25_db_print(priv);
+ return 0;
+ case NAT25_LOOKUP:
+ DEBUG_INFO("NAT25: Lookup DDP, Source =%d,%d Destination =%d,%d\n",
+ ddp->deh_snet,
+ ddp->deh_snode,
+ ddp->deh_dnet,
+ ddp->deh_dnode);
+ __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode);
+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+ return 0;
+ default:
+ return -1;
+ }
+ }
+
+ return -1;
+ } else if ((protocol == ETH_P_PPP_DISC) ||
+ (protocol == ETH_P_PPP_SES)) {
+ /*---------------------------------------------------*/
+ /* Handle PPPoE frame */
+ /*---------------------------------------------------*/
+ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+ unsigned short *pMagic;
+
+ switch (method) {
+ case NAT25_CHECK:
+ if (ph->sid == 0)
+ return 0;
+ return 1;
+ case NAT25_INSERT:
+ if (ph->sid == 0) { /* Discovery phase according to tag */
+ if (ph->code == PADI_CODE || ph->code == PADR_CODE) {
+ if (priv->ethBrExtInfo.addPPPoETag) {
+ struct pppoe_tag *tag, *pOldTag;
+ unsigned char tag_buf[40];
+ int old_tag_len = 0;
+
+ tag = (struct pppoe_tag *)tag_buf;
+ pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
+ if (pOldTag) { /* if SID existed, copy old value and delete it */
+ old_tag_len = ntohs(pOldTag->tag_len);
+ if (old_tag_len+TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN > sizeof(tag_buf)) {
+ DEBUG_ERR("SID tag length too long!\n");
+ return -1;
+ }
+
+ memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN,
+ pOldTag->tag_data, old_tag_len);
+
+ if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0) {
+ DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n");
+ return -1;
+ }
+ ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len);
+ }
+
+ tag->tag_type = PTT_RELAY_SID;
+ tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len);
+
+ /* insert the magic_code+client mac in relay tag */
+ pMagic = (unsigned short *)tag->tag_data;
+ *pMagic = htons(MAGIC_CODE);
+ memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN);
+
+ /* Add relay tag */
+ if (__nat25_add_pppoe_tag(skb, tag) < 0)
+ return -1;
+
+ DEBUG_INFO("NAT25: Insert PPPoE, forward %s packet\n",
+ (ph->code == PADI_CODE ? "PADI" : "PADR"));
+ } else { /* not add relay tag */
+ if (priv->pppoe_connection_in_progress &&
+ memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) {
+ DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n");
+ return -2;
+ }
+
+ if (priv->pppoe_connection_in_progress == 0)
+ memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN);
+
+ priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+ }
+ } else {
+ return -1;
+ }
+ } else { /* session phase */
+ DEBUG_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name);
+
+ __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid));
+
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+ __nat25_db_print(priv);
+
+ if (!priv->ethBrExtInfo.addPPPoETag &&
+ priv->pppoe_connection_in_progress &&
+ !memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))
+ priv->pppoe_connection_in_progress = 0;
+ }
+ return 0;
+ case NAT25_LOOKUP:
+ if (ph->code == PADO_CODE || ph->code == PADS_CODE) {
+ if (priv->ethBrExtInfo.addPPPoETag) {
+ struct pppoe_tag *tag;
+ unsigned char *ptr;
+ unsigned short tagType, tagLen;
+ int offset = 0;
+
+ ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
+ if (ptr == NULL) {
+ DEBUG_ERR("Fail to find PTT_RELAY_SID in FADO!\n");
+ return -1;
+ }
+
+ tag = (struct pppoe_tag *)ptr;
+ tagType = (unsigned short)((ptr[0] << 8) + ptr[1]);
+ tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]);
+
+ if ((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN))) {
+ DEBUG_ERR("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen);
+ return -1;
+ }
+
+ pMagic = (unsigned short *)tag->tag_data;
+ if (ntohs(*pMagic) != MAGIC_CODE) {
+ DEBUG_ERR("Can't find MAGIC_CODE in %s packet!\n",
+ (ph->code == PADO_CODE ? "PADO" : "PADS"));
+ return -1;
+ }
+
+ memcpy(skb->data, tag->tag_data+MAGIC_CODE_LEN, ETH_ALEN);
+
+ if (tagLen > MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN)
+ offset = TAG_HDR_LEN;
+
+ if (skb_pull_and_merge(skb, ptr+offset, TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset) < 0) {
+ DEBUG_ERR("call skb_pull_and_merge() failed in PADO packet!\n");
+ return -1;
+ }
+ ph->length = htons(ntohs(ph->length)-(TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset));
+ if (offset > 0)
+ tag->tag_len = htons(tagLen-MAGIC_CODE_LEN-RTL_RELAY_TAG_LEN);
+
+ DEBUG_INFO("NAT25: Lookup PPPoE, forward %s Packet from %s\n",
+ (ph->code == PADO_CODE ? "PADO" : "PADS"), skb->dev->name);
+ } else { /* not add relay tag */
+ if (!priv->pppoe_connection_in_progress) {
+ DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n");
+ return -1;
+ }
+ memcpy(skb->data, priv->pppoe_addr, ETH_ALEN);
+ priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+ }
+ } else {
+ if (ph->sid != 0) {
+ DEBUG_INFO("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name);
+ __nat25_generate_pppoe_network_addr(networkAddr, skb->data+ETH_ALEN, &(ph->sid));
+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+ __nat25_db_print(priv);
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+ default:
+ return -1;
+ }
+ } else if (protocol == 0x888e) {
+ /*---------------------------------------------------*/
+ /* Handle EAP frame */
+ /*---------------------------------------------------*/
+ switch (method) {
+ case NAT25_CHECK:
+ return -1;
+ case NAT25_INSERT:
+ return 0;
+ case NAT25_LOOKUP:
+ return 0;
+ default:
+ return -1;
+ }
+ } else if ((protocol == 0xe2ae) || (protocol == 0xe2af)) {
+ /*---------------------------------------------------*/
+ /* Handle C-Media proprietary frame */
+ /*---------------------------------------------------*/
+ switch (method) {
+ case NAT25_CHECK:
+ return -1;
+ case NAT25_INSERT:
+ return 0;
+ case NAT25_LOOKUP:
+ return 0;
+ default:
+ return -1;
+ }
+ } else if (protocol == ETH_P_IPV6) {
+ /*------------------------------------------------*/
+ /* Handle IPV6 frame */
+ /*------------------------------------------------*/
+ struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
+
+ if (sizeof(*iph) >= (skb->len - ETH_HLEN)) {
+ DEBUG_WARN("NAT25: malformed IPv6 packet !\n");
+ return -1;
+ }
+
+ switch (method) {
+ case NAT25_CHECK:
+ if (skb->data[0] & 1)
+ return 0;
+ return -1;
+ case NAT25_INSERT:
+ DEBUG_INFO("NAT25: Insert IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x,"
+ " DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
+ iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
+ iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
+ iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
+ iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
+
+ if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) {
+ __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr);
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+ __nat25_db_print(priv);
+
+ if (iph->nexthdr == IPPROTO_ICMPV6 &&
+ skb->len > (ETH_HLEN + sizeof(*iph) + 4)) {
+ if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph),
+ skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) {
+ struct icmp6hdr *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph));
+ hdr->icmp6_cksum = 0;
+ hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr,
+ iph->payload_len,
+ IPPROTO_ICMPV6,
+ csum_partial((__u8 *)hdr, iph->payload_len, 0));
+ }
+ }
+ }
+ return 0;
+ case NAT25_LOOKUP:
+ DEBUG_INFO("NAT25: Lookup IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x, DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
+ iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
+ iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
+ iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
+ iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
+ __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->daddr);
+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+ return 0;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+int nat25_handle_frame(struct adapter *priv, struct sk_buff *skb)
+{
+ if (!(skb->data[0] & 1)) {
+ int is_vlan_tag = 0, i, retval = 0;
+ unsigned short vlan_hdr = 0;
+ unsigned short protocol;
+
+ protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
+ if (protocol == ETH_P_8021Q) {
+ is_vlan_tag = 1;
+ vlan_hdr = *((unsigned short *)(skb->data+ETH_ALEN*2+2));
+ for (i = 0; i < 6; i++)
+ *((unsigned short *)(skb->data+ETH_ALEN*2+2-i*2)) = *((unsigned short *)(skb->data+ETH_ALEN*2-2-i*2));
+ skb_pull(skb, 4);
+ }
+
+ if (!priv->ethBrExtInfo.nat25_disable) {
+ unsigned long irqL;
+ _enter_critical_bh(&priv->br_ext_lock, &irqL);
+ /*
+ * This function look up the destination network address from
+ * the NAT2.5 database. Return value = -1 means that the
+ * corresponding network protocol is NOT support.
+ */
+ if (!priv->ethBrExtInfo.nat25sc_disable &&
+ (be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_IP) &&
+ !memcmp(priv->scdb_ip, skb->data+ETH_HLEN+16, 4)) {
+ memcpy(skb->data, priv->scdb_mac, ETH_ALEN);
+
+ _exit_critical_bh(&priv->br_ext_lock, &irqL);
+ } else {
+ _exit_critical_bh(&priv->br_ext_lock, &irqL);
+
+ retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
+ }
+ } else {
+ if (((be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_IP) &&
+ !memcmp(priv->br_ip, skb->data+ETH_HLEN+16, 4)) ||
+ ((be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_ARP) &&
+ !memcmp(priv->br_ip, skb->data+ETH_HLEN+24, 4))) {
+ /* for traffic to upper TCP/IP */
+ retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
+ }
+ }
+
+ if (is_vlan_tag) {
+ skb_push(skb, 4);
+ for (i = 0; i < 6; i++)
+ *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2));
+ *((__be16 *)(skb->data+ETH_ALEN*2)) = __constant_htons(ETH_P_8021Q);
+ *((unsigned short *)(skb->data+ETH_ALEN*2+2)) = vlan_hdr;
+ }
+
+ if (retval == -1) {
+ /* DEBUG_ERR("NAT25: Lookup fail!\n"); */
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#define SERVER_PORT 67
+#define CLIENT_PORT 68
+#define DHCP_MAGIC 0x63825363
+#define BROADCAST_FLAG 0x8000
+
+struct dhcpMessage {
+ u_int8_t op;
+ u_int8_t htype;
+ u_int8_t hlen;
+ u_int8_t hops;
+ u_int32_t xid;
+ u_int16_t secs;
+ u_int16_t flags;
+ u_int32_t ciaddr;
+ u_int32_t yiaddr;
+ u_int32_t siaddr;
+ u_int32_t giaddr;
+ u_int8_t chaddr[16];
+ u_int8_t sname[64];
+ u_int8_t file[128];
+ u_int32_t cookie;
+ u_int8_t options[308]; /* 312 - cookie */
+};
+
+void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb)
+{
+ if (skb == NULL)
+ return;
+
+ if (!priv->ethBrExtInfo.dhcp_bcst_disable) {
+ __be16 protocol = *((__be16 *)(skb->data + 2 * ETH_ALEN));
+
+ if (protocol == __constant_htons(ETH_P_IP)) { /* IP */
+ struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+ if (iph->protocol == IPPROTO_UDP) { /* UDP */
+ struct udphdr *udph = (struct udphdr *)((size_t)iph + (iph->ihl << 2));
+
+ if ((udph->source == __constant_htons(CLIENT_PORT)) &&
+ (udph->dest == __constant_htons(SERVER_PORT))) { /* DHCP request */
+ struct dhcpMessage *dhcph =
+ (struct dhcpMessage *)((size_t)udph + sizeof(struct udphdr));
+ u32 cookie = be32_to_cpu((__be32)dhcph->cookie);
+
+ if (cookie == DHCP_MAGIC) { /* match magic word */
+ if (!(dhcph->flags & htons(BROADCAST_FLAG))) {
+ /* if not broadcast */
+ register int sum = 0;
+
+ DEBUG_INFO("DHCP: change flag of DHCP request to broadcast.\n");
+ /* or BROADCAST flag */
+ dhcph->flags |= htons(BROADCAST_FLAG);
+ /* recalculate checksum */
+ sum = ~(udph->check) & 0xffff;
+ sum += be16_to_cpu(dhcph->flags);
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+ udph->check = ~sum;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr,
+ unsigned char *ipAddr)
+{
+ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+ struct nat25_network_db_entry *db;
+ int hash;
+ /* unsigned long irqL; */
+ /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */
+
+ __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr);
+ hash = __nat25_network_hash(networkAddr);
+ db = priv->nethash[hash];
+ while (db != NULL) {
+ if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+ /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+ return (void *)db;
+ }
+
+ db = db->next_hash;
+ }
+
+ /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+ return NULL;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c
new file mode 100644
index 00000000000..9632ef48fbc
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c
@@ -0,0 +1,2364 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_CMD_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <cmd_osdep.h>
+#include <mlme_osdep.h>
+#include <rtw_br_ext.h>
+#include <rtw_mlme_ext.h>
+
+/*
+Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
+No irqsave is necessary.
+*/
+
+int _rtw_init_cmd_priv (struct cmd_priv *pcmdpriv)
+{
+ int res = _SUCCESS;
+
+_func_enter_;
+
+ _rtw_init_sema(&(pcmdpriv->cmd_queue_sema), 0);
+ /* _rtw_init_sema(&(pcmdpriv->cmd_done_sema), 0); */
+ _rtw_init_sema(&(pcmdpriv->terminate_cmdthread_sema), 0);
+
+
+ _rtw_init_queue(&(pcmdpriv->cmd_queue));
+
+ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+
+ pcmdpriv->cmd_seq = 1;
+
+ pcmdpriv->cmd_allocated_buf = rtw_zmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ);
+
+ if (pcmdpriv->cmd_allocated_buf == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - ((size_t)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ-1));
+
+ pcmdpriv->rsp_allocated_buf = rtw_zmalloc(MAX_RSPSZ + 4);
+
+ if (pcmdpriv->rsp_allocated_buf == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - ((size_t)(pcmdpriv->rsp_allocated_buf) & 3);
+
+ pcmdpriv->cmd_issued_cnt = 0;
+ pcmdpriv->cmd_done_cnt = 0;
+ pcmdpriv->rsp_cnt = 0;
+exit:
+_func_exit_;
+ return res;
+}
+
+static void c2h_wk_callback(struct work_struct *work);
+
+int _rtw_init_evt_priv(struct evt_priv *pevtpriv)
+{
+ int res = _SUCCESS;
+
+_func_enter_;
+
+ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+ ATOMIC_SET(&pevtpriv->event_seq, 0);
+ pevtpriv->evt_done_cnt = 0;
+
+ _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL);
+ pevtpriv->c2h_wk_alive = false;
+ pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN+1);
+
+_func_exit_;
+
+ return res;
+}
+
+void rtw_free_evt_priv(struct evt_priv *pevtpriv)
+{
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+rtw_free_evt_priv\n"));
+
+ _cancel_workitem_sync(&pevtpriv->c2h_wk);
+ while (pevtpriv->c2h_wk_alive)
+ rtw_msleep_os(10);
+
+ while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) {
+ void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue);
+ if (c2h != NULL && c2h != (void *)pevtpriv)
+ kfree(c2h);
+ }
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("-rtw_free_evt_priv\n"));
+
+_func_exit_;
+}
+
+void _rtw_free_cmd_priv (struct cmd_priv *pcmdpriv)
+{
+_func_enter_;
+
+ if (pcmdpriv) {
+ _rtw_spinlock_free(&(pcmdpriv->cmd_queue.lock));
+ _rtw_free_sema(&(pcmdpriv->cmd_queue_sema));
+ _rtw_free_sema(&(pcmdpriv->terminate_cmdthread_sema));
+
+ if (pcmdpriv->cmd_allocated_buf)
+ kfree(pcmdpriv->cmd_allocated_buf);
+
+ if (pcmdpriv->rsp_allocated_buf)
+ kfree(pcmdpriv->rsp_allocated_buf);
+ }
+_func_exit_;
+}
+
+/*
+Calling Context:
+
+rtw_enqueue_cmd can only be called between kernel thread,
+since only spin_lock is used.
+
+ISR/Call-Back functions can't call this sub-function.
+
+*/
+
+int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
+{
+ unsigned long irqL;
+
+_func_enter_;
+
+ if (obj == NULL)
+ goto exit;
+
+ /* _enter_critical_bh(&queue->lock, &irqL); */
+ _enter_critical(&queue->lock, &irqL);
+
+ rtw_list_insert_tail(&obj->list, &queue->queue);
+
+ /* _exit_critical_bh(&queue->lock, &irqL); */
+ _exit_critical(&queue->lock, &irqL);
+
+exit:
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue)
+{
+ unsigned long irqL;
+ struct cmd_obj *obj;
+
+_func_enter_;
+
+ /* _enter_critical_bh(&(queue->lock), &irqL); */
+ _enter_critical(&queue->lock, &irqL);
+ if (rtw_is_list_empty(&(queue->queue))) {
+ obj = NULL;
+ } else {
+ obj = LIST_CONTAINOR(get_next(&(queue->queue)), struct cmd_obj, list);
+ rtw_list_delete(&obj->list);
+ }
+
+ /* _exit_critical_bh(&(queue->lock), &irqL); */
+ _exit_critical(&queue->lock, &irqL);
+
+_func_exit_;
+
+ return obj;
+}
+
+u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
+{
+ u32 res;
+_func_enter_;
+ res = _rtw_init_cmd_priv (pcmdpriv);
+_func_exit_;
+ return res;
+}
+
+u32 rtw_init_evt_priv (struct evt_priv *pevtpriv)
+{
+ int res;
+_func_enter_;
+ res = _rtw_init_evt_priv(pevtpriv);
+_func_exit_;
+ return res;
+}
+
+void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv)
+{
+_func_enter_;
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("rtw_free_cmd_priv\n"));
+ _rtw_free_cmd_priv(pcmdpriv);
+_func_exit_;
+}
+
+int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+ u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
+
+ /* To decide allow or not */
+ if ((pcmdpriv->padapter->pwrctrlpriv.bHWPwrPindetect) &&
+ (!pcmdpriv->padapter->registrypriv.usbss_enable)) {
+ if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf;
+ if (pdrvextra_cmd_parm->ec_id == POWER_SAVING_CTRL_WK_CID)
+ bAllow = true;
+ }
+ }
+
+ if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
+ bAllow = true;
+
+ if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) ||
+ !pcmdpriv->cmdthd_running) /* com_thread not running */
+ return _FAIL;
+ return _SUCCESS;
+}
+
+u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+ int res = _FAIL;
+ struct adapter *padapter = pcmdpriv->padapter;
+
+_func_enter_;
+
+ if (cmd_obj == NULL)
+ goto exit;
+
+ cmd_obj->padapter = padapter;
+
+ res = rtw_cmd_filter(pcmdpriv, cmd_obj);
+ if (_FAIL == res) {
+ rtw_free_cmd_obj(cmd_obj);
+ goto exit;
+ }
+
+ res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj);
+
+ if (res == _SUCCESS)
+ _rtw_up_sema(&pcmdpriv->cmd_queue_sema);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
+{
+ struct cmd_obj *cmd_obj;
+
+_func_enter_;
+
+ cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
+
+_func_exit_;
+ return cmd_obj;
+}
+
+void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv)
+{
+_func_enter_;
+ pcmdpriv->cmd_done_cnt++;
+ /* _rtw_up_sema(&(pcmdpriv->cmd_done_sema)); */
+_func_exit_;
+}
+
+void rtw_free_cmd_obj(struct cmd_obj *pcmd)
+{
+_func_enter_;
+
+ if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) {
+ /* free parmbuf in cmd_obj */
+ kfree(pcmd->parmbuf);
+ }
+
+ if (pcmd->rsp != NULL) {
+ if (pcmd->rspsz != 0) {
+ /* free rsp in cmd_obj */
+ kfree(pcmd->rsp);
+ }
+ }
+
+ /* free cmd_obj */
+ kfree(pcmd);
+
+_func_exit_;
+}
+
+int rtw_cmd_thread(void *context)
+{
+ u8 ret;
+ struct cmd_obj *pcmd;
+ u8 *pcmdbuf;
+ u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf);
+ void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd);
+ struct adapter *padapter = (struct adapter *)context;
+ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
+
+_func_enter_;
+
+ thread_enter("RTW_CMD_THREAD");
+
+ pcmdbuf = pcmdpriv->cmd_buf;
+
+ pcmdpriv->cmdthd_running = true;
+ _rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema);
+
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("start r871x rtw_cmd_thread !!!!\n"));
+
+ while (1) {
+ if (_rtw_down_sema(&pcmdpriv->cmd_queue_sema) == _FAIL)
+ break;
+
+ if (padapter->bDriverStopped ||
+ padapter->bSurpriseRemoved) {
+ DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
+ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__);
+ break;
+ }
+_next:
+ if (padapter->bDriverStopped ||
+ padapter->bSurpriseRemoved) {
+ DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
+ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__);
+ break;
+ }
+
+ pcmd = rtw_dequeue_cmd(pcmdpriv);
+ if (!pcmd)
+ continue;
+
+ if (_FAIL == rtw_cmd_filter(pcmdpriv, pcmd)) {
+ pcmd->res = H2C_DROPPED;
+ goto post_process;
+ }
+
+ pcmdpriv->cmd_issued_cnt++;
+
+ pcmd->cmdsz = _RND4((pcmd->cmdsz));/* _RND4 */
+
+ memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
+
+ if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) {
+ cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
+
+ if (cmd_hdl) {
+ ret = cmd_hdl(pcmd->padapter, pcmdbuf);
+ pcmd->res = ret;
+ }
+
+ pcmdpriv->cmd_seq++;
+ } else {
+ pcmd->res = H2C_PARAMETERS_ERROR;
+ }
+
+ cmd_hdl = NULL;
+
+post_process:
+
+ /* call callback function for post-processed */
+ if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) {
+ pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
+ if (pcmd_callback == NULL) {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("mlme_cmd_hdl(): pcmd_callback = 0x%p, cmdcode = 0x%x\n", pcmd_callback, pcmd->cmdcode));
+ rtw_free_cmd_obj(pcmd);
+ } else {
+ /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
+ pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */
+ }
+ } else {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("%s: cmdcode = 0x%x callback not defined!\n", __func__, pcmd->cmdcode));
+ rtw_free_cmd_obj(pcmd);
+ }
+
+ flush_signals_thread();
+
+ goto _next;
+ }
+ pcmdpriv->cmdthd_running = false;
+
+ /* free all cmd_obj resources */
+ do {
+ pcmd = rtw_dequeue_cmd(pcmdpriv);
+ if (pcmd == NULL)
+ break;
+
+ /* DBG_88E("%s: leaving... drop cmdcode:%u\n", __func__, pcmd->cmdcode); */
+
+ rtw_free_cmd_obj(pcmd);
+ } while (1);
+
+ _rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema);
+
+_func_exit_;
+
+ thread_exit();
+}
+
+u8 rtw_setstandby_cmd(struct adapter *padapter, uint action)
+{
+ struct cmd_obj *ph2c;
+ struct usb_suspend_parm *psetusbsuspend;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 ret = _SUCCESS;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ psetusbsuspend = (struct usb_suspend_parm *)rtw_zmalloc(sizeof(struct usb_suspend_parm));
+ if (psetusbsuspend == NULL) {
+ kfree(ph2c);
+ ret = _FAIL;
+ goto exit;
+ }
+
+ psetusbsuspend->action = action;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetusbsuspend, GEN_CMD_CODE(_SetUsbSuspend));
+
+ ret = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+ return ret;
+}
+
+/*
+rtw_sitesurvey_cmd(~)
+ ### NOTE:#### (!!!!)
+ MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
+*/
+u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, int ssid_num,
+ struct rtw_ieee80211_channel *ch, int ch_num)
+{
+ u8 res = _FAIL;
+ struct cmd_obj *ph2c;
+ struct sitesurvey_parm *psurveyPara;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
+ }
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+ p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1);
+ }
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL)
+ return _FAIL;
+
+ psurveyPara = (struct sitesurvey_parm *)rtw_zmalloc(sizeof(struct sitesurvey_parm));
+ if (psurveyPara == NULL) {
+ kfree(ph2c);
+ return _FAIL;
+ }
+
+ rtw_free_network_queue(padapter, false);
+
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __func__));
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+
+ /* psurveyPara->bsslimit = 48; */
+ psurveyPara->scan_mode = pmlmepriv->scan_mode;
+
+ /* prepare ssid list */
+ if (ssid) {
+ int i;
+ for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) {
+ if (ssid[i].SsidLength) {
+ memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid));
+ psurveyPara->ssid_num++;
+ if (0)
+ DBG_88E(FUNC_ADPT_FMT" ssid:(%s, %d)\n", FUNC_ADPT_ARG(padapter),
+ psurveyPara->ssid[i].Ssid, psurveyPara->ssid[i].SsidLength);
+ }
+ }
+ }
+
+ /* prepare channel list */
+ if (ch) {
+ int i;
+ for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
+ if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
+ memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
+ psurveyPara->ch_num++;
+ if (0)
+ DBG_88E(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter),
+ psurveyPara->ch[i].hw_value);
+ }
+ }
+ }
+
+ set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+ if (res == _SUCCESS) {
+ pmlmepriv->scan_start_time = rtw_get_current_time();
+
+ _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT);
+
+ rtw_led_control(padapter, LED_CTL_SITE_SURVEY);
+
+ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */
+ } else {
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+ }
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset)
+{
+ struct cmd_obj *ph2c;
+ struct setdatarate_parm *pbsetdataratepara;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pbsetdataratepara = (struct setdatarate_parm *)rtw_zmalloc(sizeof(struct setdatarate_parm));
+ if (pbsetdataratepara == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate));
+ pbsetdataratepara->mac_id = 5;
+ memcpy(pbsetdataratepara->datarates, rateset, NumRates);
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_setbasicrate_cmd(struct adapter *padapter, u8 *rateset)
+{
+ struct cmd_obj *ph2c;
+ struct setbasicrate_parm *pssetbasicratepara;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ pssetbasicratepara = (struct setbasicrate_parm *)rtw_zmalloc(sizeof(struct setbasicrate_parm));
+
+ if (pssetbasicratepara == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, _SetBasicRate_CMD_);
+
+ memcpy(pssetbasicratepara->basicrates, rateset, NumRates);
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+
+/*
+unsigned char rtw_setphy_cmd(unsigned char *adapter)
+
+1. be called only after rtw_update_registrypriv_dev_network(~) or mp testing program
+2. for AdHoc/Ap mode or mp mode?
+
+*/
+u8 rtw_setphy_cmd(struct adapter *padapter, u8 modem, u8 ch)
+{
+ struct cmd_obj *ph2c;
+ struct setphy_parm *psetphypara;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ psetphypara = (struct setphy_parm *)rtw_zmalloc(sizeof(struct setphy_parm));
+
+ if (psetphypara == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetphypara, _SetPhy_CMD_);
+
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("CH =%d, modem =%d", ch, modem));
+
+ psetphypara->modem = modem;
+ psetphypara->rfchannel = ch;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+ return res;
+}
+
+u8 rtw_setbbreg_cmd(struct adapter *padapter, u8 offset, u8 val)
+{
+ struct cmd_obj *ph2c;
+ struct writeBB_parm *pwritebbparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ pwritebbparm = (struct writeBB_parm *)rtw_zmalloc(sizeof(struct writeBB_parm));
+
+ if (pwritebbparm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pwritebbparm, GEN_CMD_CODE(_SetBBReg));
+
+ pwritebbparm->offset = offset;
+ pwritebbparm->value = val;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+ return res;
+}
+
+u8 rtw_getbbreg_cmd(struct adapter *padapter, u8 offset, u8 *pval)
+{
+ struct cmd_obj *ph2c;
+ struct readBB_parm *prdbbparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ prdbbparm = (struct readBB_parm *)rtw_zmalloc(sizeof(struct readBB_parm));
+
+ if (prdbbparm == NULL) {
+ kfree(ph2c);
+ return _FAIL;
+ }
+
+ _rtw_init_listhead(&ph2c->list);
+ ph2c->cmdcode = GEN_CMD_CODE(_GetBBReg);
+ ph2c->parmbuf = (unsigned char *)prdbbparm;
+ ph2c->cmdsz = sizeof(struct readBB_parm);
+ ph2c->rsp = pval;
+ ph2c->rspsz = sizeof(struct readBB_rsp);
+
+ prdbbparm->offset = offset;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+ return res;
+}
+
+u8 rtw_setrfreg_cmd(struct adapter *padapter, u8 offset, u32 val)
+{
+ struct cmd_obj *ph2c;
+ struct writeRF_parm *pwriterfparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+_func_enter_;
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ pwriterfparm = (struct writeRF_parm *)rtw_zmalloc(sizeof(struct writeRF_parm));
+
+ if (pwriterfparm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg));
+
+ pwriterfparm->offset = offset;
+ pwriterfparm->value = val;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+ return res;
+}
+
+u8 rtw_getrfreg_cmd(struct adapter *padapter, u8 offset, u8 *pval)
+{
+ struct cmd_obj *ph2c;
+ struct readRF_parm *prdrfparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ prdrfparm = (struct readRF_parm *)rtw_zmalloc(sizeof(struct readRF_parm));
+ if (prdrfparm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ _rtw_init_listhead(&ph2c->list);
+ ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg);
+ ph2c->parmbuf = (unsigned char *)prdrfparm;
+ ph2c->cmdsz = sizeof(struct readRF_parm);
+ ph2c->rsp = pval;
+ ph2c->rspsz = sizeof(struct readRF_rsp);
+
+ prdrfparm->offset = offset;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ _func_enter_;
+
+ kfree(pcmd->parmbuf);
+ kfree(pcmd);
+
+ if (padapter->registrypriv.mp_mode == 1)
+ padapter->mppriv.workparam.bcompleted = true;
+_func_exit_;
+}
+
+void rtw_readtssi_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ _func_enter_;
+
+ kfree(pcmd->parmbuf);
+ kfree(pcmd);
+
+ if (padapter->registrypriv.mp_mode == 1)
+ padapter->mppriv.workparam.bcompleted = true;
+_func_exit_;
+}
+
+u8 rtw_createbss_cmd(struct adapter *padapter)
+{
+ struct cmd_obj *pcmd;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+ if (pmlmepriv->assoc_ssid.SsidLength == 0)
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for Any SSid:%s\n", pmlmepriv->assoc_ssid.Ssid));
+ else
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid));
+
+ pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ _rtw_init_listhead(&pcmd->list);
+ pcmd->cmdcode = _CreateBss_CMD_;
+ pcmd->parmbuf = (unsigned char *)pdev_network;
+ pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network);
+ pcmd->rsp = NULL;
+ pcmd->rspsz = 0;
+ pdev_network->Length = pcmd->cmdsz;
+ res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_createbss_cmd_ex(struct adapter *padapter, unsigned char *pbss, unsigned int sz)
+{
+ struct cmd_obj *pcmd;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ _rtw_init_listhead(&pcmd->list);
+ pcmd->cmdcode = GEN_CMD_CODE(_CreateBss);
+ pcmd->parmbuf = pbss;
+ pcmd->cmdsz = sz;
+ pcmd->rsp = NULL;
+ pcmd->rspsz = 0;
+
+ res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
+{
+ u8 res = _SUCCESS;
+ uint t_len = 0;
+ struct wlan_bssid_ex *psecnetwork;
+ struct cmd_obj *pcmd;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct qos_priv *pqospriv = &pmlmepriv->qospriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+ enum ndis_802_11_network_infra ndis_network_mode = pnetwork->network.InfrastructureMode;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+_func_enter_;
+
+ rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+ if (pmlmepriv->assoc_ssid.SsidLength == 0) {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n"));
+ } else {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid));
+ }
+
+ pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd == NULL) {
+ res = _FAIL;
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n"));
+ goto exit;
+ }
+ /* for IEs is fix buf size */
+ t_len = sizeof(struct wlan_bssid_ex);
+
+
+ /* for hidden ap to set fw_state here */
+ if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE)) {
+ switch (ndis_network_mode) {
+ case Ndis802_11IBSS:
+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+ break;
+ case Ndis802_11Infrastructure:
+ set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+ break;
+ case Ndis802_11APMode:
+ case Ndis802_11AutoUnknown:
+ case Ndis802_11InfrastructureMax:
+ break;
+ }
+ }
+
+ psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss;
+ if (psecnetwork == NULL) {
+ if (pcmd != NULL)
+ kfree(pcmd);
+
+ res = _FAIL;
+
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd :psecnetwork == NULL!!!\n"));
+
+ goto exit;
+ }
+
+ _rtw_memset(psecnetwork, 0, t_len);
+
+ memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network));
+
+ psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength;
+
+ if ((psecnetwork->IELength-12) < (256-1)) {
+ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength-12);
+ } else {
+ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256-1));
+ }
+
+ psecnetwork->IELength = 0;
+ /* Added by Albert 2009/02/18 */
+ /* If the the driver wants to use the bssid to create the connection. */
+ /* If not, we have to copy the connecting AP's MAC address to it so that */
+ /* the driver just has the bssid information for PMKIDList searching. */
+
+ if (!pmlmepriv->assoc_by_bssid)
+ memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN);
+
+ psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength);
+
+
+ pqospriv->qos_option = 0;
+
+ if (pregistrypriv->wmm_enable) {
+ u32 tmp_len;
+
+ tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength);
+
+ if (psecnetwork->IELength != tmp_len) {
+ psecnetwork->IELength = tmp_len;
+ pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */
+ } else {
+ pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */
+ }
+ }
+
+ phtpriv->ht_option = false;
+ if (pregistrypriv->ht_enable) {
+ /* Added by Albert 2010/06/23 */
+ /* For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */
+ /* Especially for Realtek 8192u SoftAP. */
+ if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) &&
+ (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) &&
+ (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) {
+ /* rtw_restructure_ht_ie */
+ rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0],
+ pnetwork->network.IELength, &psecnetwork->IELength);
+ }
+ }
+
+ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength);
+
+ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA)
+ padapter->pwrctrlpriv.smart_ps = 0;
+ else
+ padapter->pwrctrlpriv.smart_ps = padapter->registrypriv.smart_ps;
+
+ DBG_88E("%s: smart_ps =%d\n", __func__, padapter->pwrctrlpriv.smart_ps);
+
+ pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */
+
+ _rtw_init_listhead(&pcmd->list);
+ pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */
+ pcmd->parmbuf = (unsigned char *)psecnetwork;
+ pcmd->rsp = NULL;
+ pcmd->rspsz = 0;
+
+ res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */
+{
+ struct cmd_obj *cmdobj = NULL;
+ struct disconnect_parm *param = NULL;
+ struct cmd_priv *cmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_disassoc_cmd\n"));
+
+ /* prepare cmd parameter */
+ param = (struct disconnect_parm *)rtw_zmalloc(sizeof(*param));
+ if (param == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ param->deauth_timeout_ms = deauth_timeout_ms;
+
+ if (enqueue) {
+ /* need enqueue, prepare cmd_obj and enqueue */
+ cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj));
+ if (cmdobj == NULL) {
+ res = _FAIL;
+ kfree(param);
+ goto exit;
+ }
+ init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
+ res = rtw_enqueue_cmd(cmdpriv, cmdobj);
+ } else {
+ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+ if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param))
+ res = _FAIL;
+ kfree(param);
+ }
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infra networktype)
+{
+ struct cmd_obj *ph2c;
+ struct setopmode_parm *psetop;
+
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = false;
+ goto exit;
+ }
+ psetop = (struct setopmode_parm *)rtw_zmalloc(sizeof(struct setopmode_parm));
+
+ if (psetop == NULL) {
+ kfree(ph2c);
+ res = false;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
+ psetop->mode = (u8)networktype;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
+{
+ struct cmd_obj *ph2c;
+ struct set_stakey_parm *psetstakey_para;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct set_stakey_rsp *psetstakey_rsp = NULL;
+
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct sta_info *sta = (struct sta_info *)psta;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm));
+ if (psetstakey_para == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetstakey_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_stakey_rsp));
+ if (psetstakey_rsp == NULL) {
+ kfree(ph2c);
+ kfree(psetstakey_para);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+ ph2c->rsp = (u8 *)psetstakey_rsp;
+ ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+ psetstakey_para->algorithm = (unsigned char) psecuritypriv->dot11PrivacyAlgrthm;
+ else
+ GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false);
+
+ if (unicast_key)
+ memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
+ else
+ memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
+
+ /* jeff: set this becasue at least sw key is ready */
+ padapter->securitypriv.busetkipkey = true;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue)
+{
+ struct cmd_obj *ph2c;
+ struct set_stakey_parm *psetstakey_para;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct set_stakey_rsp *psetstakey_rsp = NULL;
+ struct sta_info *sta = (struct sta_info *)psta;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ if (!enqueue) {
+ clear_cam_entry(padapter, entry);
+ } else {
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm));
+ if (psetstakey_para == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetstakey_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_stakey_rsp));
+ if (psetstakey_rsp == NULL) {
+ kfree(ph2c);
+ kfree(psetstakey_para);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+ ph2c->rsp = (u8 *)psetstakey_rsp;
+ ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+
+ psetstakey_para->algorithm = _NO_PRIVACY_;
+
+ psetstakey_para->id = entry;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+ }
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_setrttbl_cmd(struct adapter *padapter, struct setratable_parm *prate_table)
+{
+ struct cmd_obj *ph2c;
+ struct setratable_parm *psetrttblparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ psetrttblparm = (struct setratable_parm *)rtw_zmalloc(sizeof(struct setratable_parm));
+
+ if (psetrttblparm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable));
+
+ memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+ return res;
+}
+
+u8 rtw_getrttbl_cmd(struct adapter *padapter, struct getratable_rsp *pval)
+{
+ struct cmd_obj *ph2c;
+ struct getratable_parm *pgetrttblparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ pgetrttblparm = (struct getratable_parm *)rtw_zmalloc(sizeof(struct getratable_parm));
+
+ if (pgetrttblparm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+/* init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); */
+
+ _rtw_init_listhead(&ph2c->list);
+ ph2c->cmdcode = GEN_CMD_CODE(_GetRaTable);
+ ph2c->parmbuf = (unsigned char *)pgetrttblparm;
+ ph2c->cmdsz = sizeof(struct getratable_parm);
+ ph2c->rsp = (u8 *)pval;
+ ph2c->rspsz = sizeof(struct getratable_rsp);
+
+ pgetrttblparm->rsvd = 0x0;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+ return res;
+}
+
+u8 rtw_setassocsta_cmd(struct adapter *padapter, u8 *mac_addr)
+{
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct cmd_obj *ph2c;
+ struct set_assocsta_parm *psetassocsta_para;
+ struct set_stakey_rsp *psetassocsta_rsp = NULL;
+
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetassocsta_para = (struct set_assocsta_parm *)rtw_zmalloc(sizeof(struct set_assocsta_parm));
+ if (psetassocsta_para == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetassocsta_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_assocsta_rsp));
+ if (psetassocsta_rsp == NULL) {
+ kfree(ph2c);
+ kfree(psetassocsta_para);
+ return _FAIL;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_);
+ ph2c->rsp = (u8 *)psetassocsta_rsp;
+ ph2c->rspsz = sizeof(struct set_assocsta_rsp);
+
+ memcpy(psetassocsta_para->addr, mac_addr, ETH_ALEN);
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+ return res;
+ }
+
+u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
+{
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct cmd_obj *ph2c;
+ struct addBaReq_parm *paddbareq_parm;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ paddbareq_parm = (struct addBaReq_parm *)rtw_zmalloc(sizeof(struct addBaReq_parm));
+ if (paddbareq_parm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ paddbareq_parm->tid = tid;
+ memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
+
+ /* DBG_88E("rtw_addbareq_cmd, tid =%d\n", tid); */
+
+ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+ if (pdrvextra_cmd_parm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
+ pdrvextra_cmd_parm->type_size = 0;
+ pdrvextra_cmd_parm->pbuf = (u8 *)padapter;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+
+ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+ return res;
+}
+
+u8 rtw_set_ch_cmd(struct adapter *padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue)
+{
+ struct cmd_obj *pcmdobj;
+ struct set_ch_parm *set_ch_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
+ FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset);
+
+ /* check input parameter */
+
+ /* prepare cmd parameter */
+ set_ch_parm = (struct set_ch_parm *)rtw_zmalloc(sizeof(*set_ch_parm));
+ if (set_ch_parm == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ set_ch_parm->ch = ch;
+ set_ch_parm->bw = bw;
+ set_ch_parm->ch_offset = ch_offset;
+
+ if (enqueue) {
+ /* need enqueue, prepare cmd_obj and enqueue */
+ pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmdobj == NULL) {
+ kfree(set_ch_parm);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, GEN_CMD_CODE(_SetChannel));
+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+ } else {
+ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+ if (H2C_SUCCESS != set_ch_hdl(padapter, (u8 *)set_ch_parm))
+ res = _FAIL;
+
+ kfree(set_ch_parm);
+ }
+
+ /* do something based on res... */
+
+exit:
+
+ DBG_88E(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res);
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue)
+{
+ struct cmd_obj *pcmdobj;
+ struct SetChannelPlan_param *setChannelPlan_param;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_chplan_cmd\n"));
+
+ /* check input parameter */
+ if (!rtw_is_channel_plan_valid(chplan)) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ /* prepare cmd parameter */
+ setChannelPlan_param = (struct SetChannelPlan_param *)rtw_zmalloc(sizeof(struct SetChannelPlan_param));
+ if (setChannelPlan_param == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ setChannelPlan_param->channel_plan = chplan;
+
+ if (enqueue) {
+ /* need enqueue, prepare cmd_obj and enqueue */
+ pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmdobj == NULL) {
+ kfree(setChannelPlan_param);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan));
+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+ } else {
+ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+ if (H2C_SUCCESS != set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param))
+ res = _FAIL;
+
+ kfree(setChannelPlan_param);
+ }
+
+ /* do something based on res... */
+ if (res == _SUCCESS)
+ padapter->mlmepriv.ChannelPlan = chplan;
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_led_blink_cmd(struct adapter *padapter, struct LED_871x *pLed)
+{
+ struct cmd_obj *pcmdobj;
+ struct LedBlink_param *ledBlink_param;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_led_blink_cmd\n"));
+
+ pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmdobj == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ ledBlink_param = (struct LedBlink_param *)rtw_zmalloc(sizeof(struct LedBlink_param));
+ if (ledBlink_param == NULL) {
+ kfree(pcmdobj);
+ res = _FAIL;
+ goto exit;
+ }
+
+ ledBlink_param->pLed = pLed;
+
+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink));
+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_set_csa_cmd(struct adapter *padapter, u8 new_ch_no)
+{
+ struct cmd_obj *pcmdobj;
+ struct SetChannelSwitch_param *setChannelSwitch_param;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_csa_cmd\n"));
+
+ pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmdobj == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ setChannelSwitch_param = (struct SetChannelSwitch_param *)rtw_zmalloc(sizeof(struct SetChannelSwitch_param));
+ if (setChannelSwitch_param == NULL) {
+ kfree(pcmdobj);
+ res = _FAIL;
+ goto exit;
+ }
+
+ setChannelSwitch_param->new_ch_no = new_ch_no;
+
+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelSwitch_param, GEN_CMD_CODE(_SetChannelSwitch));
+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_tdls_cmd(struct adapter *padapter, u8 *addr, u8 option)
+{
+ return _SUCCESS;
+}
+
+static void traffic_status_watchdog(struct adapter *padapter)
+{
+ u8 bEnterPS;
+ u8 bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false;
+ u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ /* */
+ /* Determine if our traffic is busy now */
+ /* */
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 100 ||
+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 100) {
+ bBusyTraffic = true;
+
+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+ bRxBusyTraffic = true;
+ else
+ bTxBusyTraffic = true;
+ }
+
+ /* Higher Tx/Rx data. */
+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 ||
+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) {
+ bHigherBusyTraffic = true;
+
+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+ bHigherBusyRxTraffic = true;
+ else
+ bHigherBusyTxTraffic = true;
+ }
+
+ /* check traffic for powersaving. */
+ if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) ||
+ (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2))
+ bEnterPS = false;
+ else
+ bEnterPS = true;
+
+ /* LeisurePS only work in infra mode. */
+ if (bEnterPS)
+ LPS_Enter(padapter);
+ else
+ LPS_Leave(padapter);
+ } else {
+ LPS_Leave(padapter);
+ }
+
+ pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0;
+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0;
+ pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
+ pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
+ pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic;
+ pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic;
+ pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic;
+ pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
+ pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic;
+}
+
+void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz)
+{
+ struct mlme_priv *pmlmepriv;
+
+ padapter = (struct adapter *)pbuf;
+ pmlmepriv = &(padapter->mlmepriv);
+
+#ifdef CONFIG_88EU_AP_MODE
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
+ expire_timeout_chk(padapter);
+#endif
+
+ rtw_hal_sreset_xmit_status_check(padapter);
+
+ linked_status_chk(padapter);
+ traffic_status_watchdog(padapter);
+
+ rtw_hal_dm_watchdog(padapter);
+}
+
+static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u8 mstatus;
+
+_func_enter_;
+
+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
+ return;
+
+ switch (lps_ctrl_type) {
+ case LPS_CTRL_SCAN:
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+ /* connect */
+ LPS_Leave(padapter);
+ }
+ break;
+ case LPS_CTRL_JOINBSS:
+ LPS_Leave(padapter);
+ break;
+ case LPS_CTRL_CONNECT:
+ mstatus = 1;/* connect */
+ /* Reset LPS Setting */
+ padapter->pwrctrlpriv.LpsIdleCount = 0;
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+ break;
+ case LPS_CTRL_DISCONNECT:
+ mstatus = 0;/* disconnect */
+ LPS_Leave(padapter);
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+ break;
+ case LPS_CTRL_SPECIAL_PACKET:
+ /* DBG_88E("LPS_CTRL_SPECIAL_PACKET\n"); */
+ pwrpriv->DelayLPSLastTimeStamp = rtw_get_current_time();
+ LPS_Leave(padapter);
+ break;
+ case LPS_CTRL_LEAVE:
+ LPS_Leave(padapter);
+ break;
+ default:
+ break;
+ }
+
+_func_exit_;
+}
+
+u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ /* struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; */
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ /* if (!pwrctrlpriv->bLeisurePs) */
+ /* return res; */
+
+ if (enqueue) {
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+ if (pdrvextra_cmd_parm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
+ pdrvextra_cmd_parm->type_size = lps_ctrl_type;
+ pdrvextra_cmd_parm->pbuf = NULL;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+ } else {
+ lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
+ }
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+static void rpt_timer_setting_wk_hdl(struct adapter *padapter, u16 min_time)
+{
+ rtw_hal_set_hwreg(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&min_time));
+}
+
+u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+_func_enter_;
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+ if (pdrvextra_cmd_parm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID;
+ pdrvextra_cmd_parm->type_size = min_time;
+ pdrvextra_cmd_parm->pbuf = NULL;
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+static void antenna_select_wk_hdl(struct adapter *padapter, u8 antenna)
+{
+ rtw_hal_set_hwreg(padapter, HW_VAR_ANTENNA_DIVERSITY_SELECT, (u8 *)(&antenna));
+}
+
+u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 support_ant_div;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+ rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &support_ant_div);
+ if (!support_ant_div)
+ return res;
+
+ if (enqueue) {
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+ if (pdrvextra_cmd_parm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID;
+ pdrvextra_cmd_parm->type_size = antenna;
+ pdrvextra_cmd_parm->pbuf = NULL;
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+ } else {
+ antenna_select_wk_hdl(padapter, antenna);
+ }
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+static void power_saving_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz)
+{
+ rtw_ps_processor(padapter);
+}
+
+#ifdef CONFIG_88EU_P2P
+u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ return res;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+ if (pdrvextra_cmd_parm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID;
+ pdrvextra_cmd_parm->type_size = intCmdType; /* As the command tppe. */
+ pdrvextra_cmd_parm->pbuf = NULL; /* Must be NULL here */
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+#endif /* CONFIG_88EU_P2P */
+
+u8 rtw_ps_cmd(struct adapter *padapter)
+{
+ struct cmd_obj *ppscmd;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+_func_enter_;
+
+ ppscmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ppscmd == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+ if (pdrvextra_cmd_parm == NULL) {
+ kfree(ppscmd);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
+ pdrvextra_cmd_parm->pbuf = NULL;
+ init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ppscmd);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
+{
+ int cnt = 0;
+ struct sta_info *psta_bmc;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ psta_bmc = rtw_get_bcmc_stainfo(padapter);
+ if (!psta_bmc)
+ return;
+
+ if (psta_bmc->sleepq_len == 0) {
+ u8 val = 0;
+
+ /* while ((rtw_read32(padapter, 0x414)&0x00ffff00)!= 0) */
+ /* while ((rtw_read32(padapter, 0x414)&0x0000ff00)!= 0) */
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
+
+ while (!val) {
+ rtw_msleep_os(100);
+
+ cnt++;
+
+ if (cnt > 10)
+ break;
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
+ }
+
+ if (cnt <= 10) {
+ pstapriv->tim_bitmap &= ~BIT(0);
+ pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+ update_beacon(padapter, _TIM_IE_, NULL, false);
+ } else { /* re check again */
+ rtw_chk_hi_queue_cmd(padapter);
+ }
+ }
+}
+
+u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+ if (pdrvextra_cmd_parm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
+ pdrvextra_cmd_parm->type_size = 0;
+ pdrvextra_cmd_parm->pbuf = NULL;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+ return res;
+}
+#endif
+
+u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+ if (pdrvextra_cmd_parm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
+ pdrvextra_cmd_parm->type_size = c2h_evt ? 16 : 0;
+ pdrvextra_cmd_parm->pbuf = c2h_evt;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+ return res;
+}
+
+static s32 c2h_evt_hdl(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter)
+{
+ s32 ret = _FAIL;
+ u8 buf[16];
+
+ if (!c2h_evt) {
+ /* No c2h event in cmd_obj, read c2h event before handling*/
+ if (c2h_evt_read(adapter, buf) == _SUCCESS) {
+ c2h_evt = (struct c2h_evt_hdr *)buf;
+
+ if (filter && filter(c2h_evt->id) == false)
+ goto exit;
+
+ ret = rtw_hal_c2h_handler(adapter, c2h_evt);
+ }
+ } else {
+ if (filter && filter(c2h_evt->id) == false)
+ goto exit;
+
+ ret = rtw_hal_c2h_handler(adapter, c2h_evt);
+ }
+exit:
+ return ret;
+}
+
+static void c2h_wk_callback(struct work_struct *work)
+{
+ struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk);
+ struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv);
+ struct c2h_evt_hdr *c2h_evt;
+ c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter);
+
+ evtpriv->c2h_wk_alive = true;
+
+ while (!rtw_cbuf_empty(evtpriv->c2h_queue)) {
+ if ((c2h_evt = (struct c2h_evt_hdr *)rtw_cbuf_pop(evtpriv->c2h_queue)) != NULL) {
+ /* This C2H event is read, clear it */
+ c2h_evt_clear(adapter);
+ } else if ((c2h_evt = (struct c2h_evt_hdr *)rtw_malloc(16)) != NULL) {
+ /* This C2H event is not read, read & clear now */
+ if (c2h_evt_read(adapter, (u8 *)c2h_evt) != _SUCCESS)
+ continue;
+ }
+
+ /* Special pointer to trigger c2h_evt_clear only */
+ if ((void *)c2h_evt == (void *)evtpriv)
+ continue;
+
+ if (!c2h_evt_exist(c2h_evt)) {
+ kfree(c2h_evt);
+ continue;
+ }
+
+ if (ccx_id_filter(c2h_evt->id) == true) {
+ /* Handle CCX report here */
+ rtw_hal_c2h_handler(adapter, c2h_evt);
+ kfree(c2h_evt);
+ } else {
+#ifdef CONFIG_88EU_P2P
+ /* Enqueue into cmd_thread for others */
+ rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt);
+#endif
+ }
+ }
+
+ evtpriv->c2h_wk_alive = false;
+}
+
+u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ struct drvextra_cmd_parm *pdrvextra_cmd;
+
+ if (!pbuf)
+ return H2C_PARAMETERS_ERROR;
+
+ pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf;
+
+ switch (pdrvextra_cmd->ec_id) {
+ case DYNAMIC_CHK_WK_CID:
+ dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size);
+ break;
+ case POWER_SAVING_CTRL_WK_CID:
+ power_saving_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size);
+ break;
+ case LPS_CTRL_WK_CID:
+ lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size);
+ break;
+ case RTP_TIMER_CFG_WK_CID:
+ rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type_size);
+ break;
+ case ANT_SELECT_WK_CID:
+ antenna_select_wk_hdl(padapter, pdrvextra_cmd->type_size);
+ break;
+#ifdef CONFIG_88EU_P2P
+ case P2P_PS_WK_CID:
+ p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type_size);
+ break;
+ case P2P_PROTO_WK_CID:
+ /* Commented by Albert 2011/07/01 */
+ /* I used the type_size as the type command */
+ p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type_size);
+ break;
+#endif
+#ifdef CONFIG_88EU_AP_MODE
+ case CHECK_HIQ_WK_CID:
+ rtw_chk_hi_queue_hdl(padapter);
+ break;
+#endif /* CONFIG_88EU_AP_MODE */
+ case C2H_WK_CID:
+ c2h_evt_hdl(padapter, (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL);
+ break;
+ default:
+ break;
+ }
+
+ if (pdrvextra_cmd->pbuf && pdrvextra_cmd->type_size > 0)
+ kfree(pdrvextra_cmd->pbuf);
+
+ return H2C_SUCCESS;
+}
+
+void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+ if (pcmd->res == H2C_DROPPED) {
+ /* TODO: cancel timer and do timeout handler directly... */
+ /* need to make timeout handlerOS independent */
+ _set_timer(&pmlmepriv->scan_to_timer, 1);
+ } else if (pcmd->res != H2C_SUCCESS) {
+ _set_timer(&pmlmepriv->scan_to_timer, 1);
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n."));
+ }
+
+ /* free cmd */
+ rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
+void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ unsigned long irqL;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+ if (pcmd->res != H2C_SUCCESS) {
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+ set_fwstate(pmlmepriv, _FW_LINKED);
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ***Error: disconnect_cmd_callback Fail ***\n."));
+
+ goto exit;
+ } else /* clear bridge database */
+ nat25_db_cleanup(padapter);
+
+ /* free cmd */
+ rtw_free_cmd_obj(pcmd);
+
+exit:
+
+_func_exit_;
+}
+
+void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+ if (pcmd->res == H2C_DROPPED) {
+ /* TODO: cancel timer and do timeout handler directly... */
+ /* need to make timeout handlerOS independent */
+ _set_timer(&pmlmepriv->assoc_timer, 1);
+ } else if (pcmd->res != H2C_SUCCESS) {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("********Error:rtw_select_and_join_from_scanned_queue Wait Sema Fail ************\n"));
+ _set_timer(&pmlmepriv->assoc_timer, 1);
+ }
+
+ rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
+
+void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ unsigned long irqL;
+ u8 timer_cancelled;
+ struct sta_info *psta = NULL;
+ struct wlan_network *pwlan = NULL;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
+ struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
+
+_func_enter_;
+
+ if ((pcmd->res != H2C_SUCCESS)) {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: rtw_createbss_cmd_callback Fail ************\n\n."));
+ _set_timer(&pmlmepriv->assoc_timer, 1);
+ }
+
+ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled);
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress);
+ if (!psta) {
+ psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
+ if (psta == NULL) {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nCan't alloc sta_info when createbss_cmd_callback\n"));
+ goto createbss_cmd_fail ;
+ }
+ }
+
+ rtw_indicate_connect(padapter);
+ } else {
+ unsigned long irqL;
+
+ pwlan = _rtw_alloc_network(pmlmepriv);
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+ if (pwlan == NULL) {
+ pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
+ if (pwlan == NULL) {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n Error: can't get pwlan in rtw_joinbss_event_callback\n"));
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+ goto createbss_cmd_fail;
+ }
+ pwlan->last_scanned = rtw_get_current_time();
+ } else {
+ rtw_list_insert_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue);
+ }
+
+ pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork);
+ memcpy(&(pwlan->network), pnetwork, pnetwork->Length);
+
+ memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork)));
+
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+ /* we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */
+ }
+
+createbss_cmd_fail:
+
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+ rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
+
+void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp);
+ struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
+
+_func_enter_;
+
+ if (psta == NULL) {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: rtw_setstaKey_cmdrsp_callback => can't get sta_info\n\n"));
+ goto exit;
+ }
+exit:
+ rtw_free_cmd_obj(pcmd);
+_func_exit_;
+}
+
+void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ unsigned long irqL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf);
+ struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp);
+ struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr);
+
+_func_enter_;
+
+ if (psta == NULL) {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: setassocsta_cmdrsp_callbac => can't get sta_info\n\n"));
+ goto exit;
+ }
+
+ psta->aid = passocsta_rsp->cam_id;
+ psta->mac_id = passocsta_rsp->cam_id;
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+ if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true))
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+ set_fwstate(pmlmepriv, _FW_LINKED);
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+exit:
+ rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_debug.c b/drivers/staging/rtl8188eu/core/rtw_debug.c
new file mode 100644
index 00000000000..0fe5f5de54a
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_debug.c
@@ -0,0 +1,948 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_DEBUG_C_
+
+#include <rtw_debug.h>
+#include <rtw_version.h>
+
+int proc_get_drv_version(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "%s\n", DRIVERVERSION);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_write_reg(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ *eof = 1;
+ return 0;
+}
+
+int proc_set_write_reg(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u32 addr, val, len;
+
+ if (count < 3) {
+ DBG_88E("argument size is less than 3\n");
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ int num = sscanf(tmp, "%x %x %x", &addr, &val, &len);
+
+ if (num != 3) {
+ DBG_88E("invalid write_reg parameter!\n");
+ return count;
+ }
+ switch (len) {
+ case 1:
+ rtw_write8(padapter, addr, (u8)val);
+ break;
+ case 2:
+ rtw_write16(padapter, addr, (u16)val);
+ break;
+ case 4:
+ rtw_write32(padapter, addr, val);
+ break;
+ default:
+ DBG_88E("error write length =%d", len);
+ break;
+ }
+ }
+ return count;
+}
+
+static u32 proc_get_read_addr = 0xeeeeeeee;
+static u32 proc_get_read_len = 0x4;
+
+int proc_get_read_reg(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ int len = 0;
+
+ if (proc_get_read_addr == 0xeeeeeeee) {
+ *eof = 1;
+ return len;
+ }
+
+ switch (proc_get_read_len) {
+ case 1:
+ len += snprintf(page + len, count - len, "rtw_read8(0x%x)=0x%x\n", proc_get_read_addr, rtw_read8(padapter, proc_get_read_addr));
+ break;
+ case 2:
+ len += snprintf(page + len, count - len, "rtw_read16(0x%x)=0x%x\n", proc_get_read_addr, rtw_read16(padapter, proc_get_read_addr));
+ break;
+ case 4:
+ len += snprintf(page + len, count - len, "rtw_read32(0x%x)=0x%x\n", proc_get_read_addr, rtw_read32(padapter, proc_get_read_addr));
+ break;
+ default:
+ len += snprintf(page + len, count - len, "error read length=%d\n", proc_get_read_len);
+ break;
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_set_read_reg(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char tmp[16];
+ u32 addr, len;
+
+ if (count < 2) {
+ DBG_88E("argument size is less than 2\n");
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ int num = sscanf(tmp, "%x %x", &addr, &len);
+
+ if (num != 2) {
+ DBG_88E("invalid read_reg parameter!\n");
+ return count;
+ }
+
+ proc_get_read_addr = addr;
+
+ proc_get_read_len = len;
+ }
+
+ return count;
+}
+
+int proc_get_fwstate(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "fwstate=0x%x\n", get_fwstate(pmlmepriv));
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_sec_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n",
+ psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm,
+ psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_mlmext_state(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "pmlmeinfo->state=0x%x\n", pmlmeinfo->state);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_qos_option(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "qos_option=%d\n", pmlmepriv->qospriv.qos_option);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_ht_option(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ int len = 0;
+ len += snprintf(page + len, count - len, "ht_option=%d\n", pmlmepriv->htpriv.ht_option);
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rf_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "cur_ch=%d, cur_bw=%d, cur_ch_offet=%d\n",
+ pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
+ *eof = 1;
+ return len;
+}
+
+int proc_get_ap_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct sta_info *psta;
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ int len = 0;
+
+ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
+ if (psta) {
+ int i;
+ struct recv_reorder_ctrl *preorder_ctrl;
+
+ len += snprintf(page + len, count - len, "SSID=%s\n", cur_network->network.Ssid.Ssid);
+ len += snprintf(page + len, count - len, "sta's macaddr:%pM\n", psta->hwaddr);
+ len += snprintf(page + len, count - len, "cur_channel=%d, cur_bwmode=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
+ len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self);
+ len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+ len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+ len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi);
+ len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+ len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+
+ for (i = 0; i < 16; i++) {
+ preorder_ctrl = &psta->recvreorder_ctrl[i];
+ if (preorder_ctrl->enable)
+ len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", i, preorder_ctrl->indicate_seq);
+ }
+ } else {
+ len += snprintf(page + len, count - len, "can't get sta's macaddr, cur_network's macaddr: %pM\n", cur_network->network.MacAddress);
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_adapter_state(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "bSurpriseRemoved=%d, bDriverStopped=%d\n",
+ padapter->bSurpriseRemoved, padapter->bDriverStopped);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_trx_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "free_xmitbuf_cnt=%d, free_xmitframe_cnt=%d, free_ext_xmitbuf_cnt=%d, free_recvframe_cnt=%d\n",
+ pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmit_extbuf_cnt, precvpriv->free_recvframe_cnt);
+ len += snprintf(page + len, count - len, "rx_urb_pending_cn=%d\n", precvpriv->rx_pending_cnt);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_mac_reg_dump1(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n");
+
+ for (i = 0x0; i < 0x300; i += 4) {
+ if (j%4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_mac_reg_dump2(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n");
+ memset(page, 0, count);
+ for (i = 0x300; i < 0x600; i += 4) {
+ if (j%4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_mac_reg_dump3(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n");
+
+ for (i = 0x600; i < 0x800; i += 4) {
+ if (j%4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_bb_reg_dump1(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= BB REG =======\n");
+ for (i = 0x800; i < 0xB00; i += 4) {
+ if (j%4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_bb_reg_dump2(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= BB REG =======\n");
+ for (i = 0xB00; i < 0xE00; i += 4) {
+ if (j%4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_bb_reg_dump3(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= BB REG =======\n");
+ for (i = 0xE00; i < 0x1000; i += 4) {
+ if (j%4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rf_reg_dump1(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1, path;
+ u32 value;
+
+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+ path = 1;
+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+ for (i = 0; i < 0xC0; i++) {
+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+ if (j%4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x ", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", value);
+ if ((j++)%4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rf_reg_dump2(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1, path;
+ u32 value;
+
+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+ path = 1;
+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+ for (i = 0xC0; i < 0x100; i++) {
+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+ if (j%4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x ", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", value);
+ if ((j++)%4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rf_reg_dump3(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1, path;
+ u32 value;
+
+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+ path = 2;
+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+ for (i = 0; i < 0xC0; i++) {
+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+ if (j%4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x ", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", value);
+ if ((j++)%4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+
+ *eof = 1;
+ return len;
+}
+
+
+int proc_get_rf_reg_dump4(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1, path;
+ u32 value;
+
+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+ path = 2;
+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+ for (i = 0xC0; i < 0x100; i++) {
+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+ if (j%4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x ", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", value);
+ if ((j++)%4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+
+
+int proc_get_rx_signal(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+
+ len = snprintf(page + len, count,
+ "rssi:%d\n"
+ "rxpwdb:%d\n"
+ "signal_strength:%u\n"
+ "signal_qual:%u\n"
+ "noise:%u\n",
+ padapter->recvpriv.rssi,
+ padapter->recvpriv.rxpwdb,
+ padapter->recvpriv.signal_strength,
+ padapter->recvpriv.signal_qual,
+ padapter->recvpriv.noise
+ );
+
+ *eof = 1;
+ return len;
+}
+
+int proc_set_rx_signal(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u32 is_signal_dbg;
+ s32 signal_strength;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength);
+ is_signal_dbg = is_signal_dbg == 0 ? 0 : 1;
+ if (is_signal_dbg && num != 2)
+ return count;
+
+ signal_strength = signal_strength > 100 ? 100 : signal_strength;
+ signal_strength = signal_strength < 0 ? 0 : signal_strength;
+
+ padapter->recvpriv.is_signal_dbg = is_signal_dbg;
+ padapter->recvpriv.signal_strength_dbg = signal_strength;
+
+ if (is_signal_dbg)
+ DBG_88E("set %s %u\n", "DBG_SIGNAL_STRENGTH", signal_strength);
+ else
+ DBG_88E("set %s\n", "HW_SIGNAL_STRENGTH");
+ }
+ return count;
+}
+
+int proc_get_ht_enable(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ int len = 0;
+
+ if (pregpriv)
+ len += snprintf(page + len, count - len,
+ "%d\n",
+ pregpriv->ht_enable
+ );
+ *eof = 1;
+ return len;
+}
+
+int proc_set_ht_enable(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ char tmp[32];
+ s32 mode = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ if (pregpriv) {
+ pregpriv->ht_enable = mode;
+ pr_info("ht_enable=%d\n", pregpriv->ht_enable);
+ }
+ }
+
+ return count;
+}
+
+int proc_get_cbw40_enable(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+
+ int len = 0;
+
+ if (pregpriv)
+ len += snprintf(page + len, count - len,
+ "%d\n",
+ pregpriv->cbw40_enable
+ );
+
+ *eof = 1;
+ return len;
+}
+
+int proc_set_cbw40_enable(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ char tmp[32];
+ s32 mode = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ if (pregpriv) {
+ pregpriv->cbw40_enable = mode;
+ pr_info("cbw40_enable=%d\n", mode);
+ }
+ }
+ return count;
+}
+
+int proc_get_ampdu_enable(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+
+ int len = 0;
+
+ if (pregpriv)
+ len += snprintf(page + len, count - len,
+ "%d\n",
+ pregpriv->ampdu_enable
+ );
+
+ *eof = 1;
+ return len;
+}
+
+int proc_set_ampdu_enable(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ char tmp[32];
+ s32 mode = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ if (pregpriv) {
+ pregpriv->ampdu_enable = mode;
+ pr_info("ampdu_enable=%d\n", mode);
+ }
+ }
+ return count;
+}
+
+int proc_get_two_path_rssi(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ int len = 0;
+
+ if (padapter)
+ len += snprintf(page + len, count - len,
+ "%d %d\n",
+ padapter->recvpriv.RxRssi[0],
+ padapter->recvpriv.RxRssi[1]
+ );
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rx_stbc(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+
+ int len = 0;
+
+ if (pregpriv)
+ len += snprintf(page + len, count - len,
+ "%d\n",
+ pregpriv->rx_stbc
+ );
+
+ *eof = 1;
+ return len;
+}
+
+int proc_set_rx_stbc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ char tmp[32];
+ u32 mode = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ if (pregpriv) {
+ pregpriv->rx_stbc = mode;
+ printk("rx_stbc=%d\n", mode);
+ }
+ }
+ return count;
+}
+
+int proc_get_rssi_disp(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ *eof = 1;
+ return 0;
+}
+
+int proc_set_rssi_disp(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u32 enable = 0;
+
+ if (count < 1) {
+ DBG_88E("argument size is less than 1\n");
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ int num = sscanf(tmp, "%x", &enable);
+
+ if (num != 1) {
+ DBG_88E("invalid set_rssi_disp parameter!\n");
+ return count;
+ }
+
+ if (enable) {
+ DBG_88E("Turn On Rx RSSI Display Function\n");
+ padapter->bRxRSSIDisplay = enable ;
+ } else {
+ DBG_88E("Turn Off Rx RSSI Display Function\n");
+ padapter->bRxRSSIDisplay = 0;
+ }
+ }
+ return count;
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+int proc_get_all_sta_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ unsigned long irqL;
+ struct sta_info *psta;
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ int i, j;
+ struct list_head *plist, *phead;
+ struct recv_reorder_ctrl *preorder_ctrl;
+ int len = 0;
+
+
+ len += snprintf(page + len, count - len, "sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap);
+
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+ for (i = 0; i < NUM_STA; i++) {
+ phead = &(pstapriv->sta_hash[i]);
+ plist = get_next(phead);
+
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+ plist = get_next(plist);
+
+ len += snprintf(page + len, count - len, "sta's macaddr: %pM\n", psta->hwaddr);
+ len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self);
+ len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+ len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+ len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi);
+ len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+ len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+ len += snprintf(page + len, count - len, "sleepq_len=%d\n", psta->sleepq_len);
+ len += snprintf(page + len, count - len, "capability=0x%x\n", psta->capability);
+ len += snprintf(page + len, count - len, "flags=0x%x\n", psta->flags);
+ len += snprintf(page + len, count - len, "wpa_psk=0x%x\n", psta->wpa_psk);
+ len += snprintf(page + len, count - len, "wpa2_group_cipher=0x%x\n", psta->wpa2_group_cipher);
+ len += snprintf(page + len, count - len, "wpa2_pairwise_cipher=0x%x\n", psta->wpa2_pairwise_cipher);
+ len += snprintf(page + len, count - len, "qos_info=0x%x\n", psta->qos_info);
+ len += snprintf(page + len, count - len, "dot118021XPrivacy=0x%x\n", psta->dot118021XPrivacy);
+
+ for (j = 0; j < 16; j++) {
+ preorder_ctrl = &psta->recvreorder_ctrl[j];
+ if (preorder_ctrl->enable)
+ len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", j, preorder_ctrl->indicate_seq);
+ }
+ }
+ }
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+ *eof = 1;
+ return len;
+}
+#endif
+
+int proc_get_best_channel(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ int len = 0;
+ u32 i, best_channel_24G = 1, best_channel_5G = 36, index_24G = 0, index_5G = 0;
+
+ for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
+ if (pmlmeext->channel_set[i].ChannelNum == 1)
+ index_24G = i;
+ if (pmlmeext->channel_set[i].ChannelNum == 36)
+ index_5G = i;
+ }
+
+ for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
+ /* 2.4G */
+ if (pmlmeext->channel_set[i].ChannelNum == 6) {
+ if (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_24G].rx_count) {
+ index_24G = i;
+ best_channel_24G = pmlmeext->channel_set[i].ChannelNum;
+ }
+ }
+
+ /* 5G */
+ if (pmlmeext->channel_set[i].ChannelNum >= 36 &&
+ pmlmeext->channel_set[i].ChannelNum < 140) {
+ /* Find primary channel */
+ if (((pmlmeext->channel_set[i].ChannelNum - 36) % 8 == 0) &&
+ (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) {
+ index_5G = i;
+ best_channel_5G = pmlmeext->channel_set[i].ChannelNum;
+ }
+ }
+
+ if (pmlmeext->channel_set[i].ChannelNum >= 149 &&
+ pmlmeext->channel_set[i].ChannelNum < 165) {
+ /* find primary channel */
+ if (((pmlmeext->channel_set[i].ChannelNum - 149) % 8 == 0) &&
+ (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) {
+ index_5G = i;
+ best_channel_5G = pmlmeext->channel_set[i].ChannelNum;
+ }
+ }
+ /* debug */
+ len += snprintf(page + len, count - len, "The rx cnt of channel %3d = %d\n",
+ pmlmeext->channel_set[i].ChannelNum, pmlmeext->channel_set[i].rx_count);
+ }
+
+ len += snprintf(page + len, count - len, "best_channel_5G = %d\n", best_channel_5G);
+ len += snprintf(page + len, count - len, "best_channel_24G = %d\n", best_channel_24G);
+
+ *eof = 1;
+ return len;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c
new file mode 100644
index 00000000000..869434c4cf6
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c
@@ -0,0 +1,875 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_EFUSE_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_efuse.h>
+
+
+
+/*------------------------Define local variable------------------------------*/
+u8 fakeEfuseBank;
+u32 fakeEfuseUsedBytes;
+u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0};
+u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0};
+u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0};
+
+u32 BTEfuseUsedBytes;
+u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+
+u32 fakeBTEfuseUsedBytes;
+u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+/*------------------------Define local variable------------------------------*/
+
+/* */
+#define REG_EFUSE_CTRL 0x0030
+#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */
+/* */
+
+bool
+Efuse_Read1ByteFromFakeContent(
+ struct adapter *pAdapter,
+ u16 Offset,
+ u8 *Value);
+bool
+Efuse_Read1ByteFromFakeContent(
+ struct adapter *pAdapter,
+ u16 Offset,
+ u8 *Value)
+{
+ if (Offset >= EFUSE_MAX_HW_SIZE)
+ return false;
+ if (fakeEfuseBank == 0)
+ *Value = fakeEfuseContent[Offset];
+ else
+ *Value = fakeBTEfuseContent[fakeEfuseBank-1][Offset];
+ return true;
+}
+
+static bool
+Efuse_Write1ByteToFakeContent(
+ struct adapter *pAdapter,
+ u16 Offset,
+ u8 Value)
+{
+ if (Offset >= EFUSE_MAX_HW_SIZE)
+ return false;
+ if (fakeEfuseBank == 0) {
+ fakeEfuseContent[Offset] = Value;
+ } else {
+ fakeBTEfuseContent[fakeEfuseBank-1][Offset] = Value;
+ }
+ return true;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: Efuse_PowerSwitch
+ *
+ * Overview: When we want to enable write operation, we should change to
+ * pwr on state. When we stop write, we should switch to 500k mode
+ * and disable LDO 2.5V.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/17/2008 MHC Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void
+Efuse_PowerSwitch(
+ struct adapter *pAdapter,
+ u8 write,
+ u8 PwrState)
+{
+ pAdapter->HalFunc.EfusePowerSwitch(pAdapter, write, PwrState);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: efuse_GetCurrentSize
+ *
+ * Overview: Get current efuse size!!!
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/16/2008 MHC Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+u16
+Efuse_GetCurrentSize(
+ struct adapter *pAdapter,
+ u8 efuseType,
+ bool pseudo)
+{
+ u16 ret = 0;
+
+ ret = pAdapter->HalFunc.EfuseGetCurrentSize(pAdapter, efuseType, pseudo);
+
+ return ret;
+}
+
+/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */
+u8
+Efuse_CalculateWordCnts(u8 word_en)
+{
+ u8 word_cnts = 0;
+ if (!(word_en & BIT(0)))
+ word_cnts++; /* 0 : write enable */
+ if (!(word_en & BIT(1)))
+ word_cnts++;
+ if (!(word_en & BIT(2)))
+ word_cnts++;
+ if (!(word_en & BIT(3)))
+ word_cnts++;
+ return word_cnts;
+}
+
+/* */
+/* Description: */
+/* Execute E-Fuse read byte operation. */
+/* Refered from SD1 Richard. */
+/* */
+/* Assumption: */
+/* 1. Boot from E-Fuse and successfully auto-load. */
+/* 2. PASSIVE_LEVEL (USB interface) */
+/* */
+/* Created by Roger, 2008.10.21. */
+/* */
+void
+ReadEFuseByte(
+ struct adapter *Adapter,
+ u16 _offset,
+ u8 *pbuf,
+ bool pseudo)
+{
+ u32 value32;
+ u8 readbyte;
+ u16 retry;
+
+ if (pseudo) {
+ Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf);
+ return;
+ }
+
+ /* Write Address */
+ rtw_write8(Adapter, EFUSE_CTRL+1, (_offset & 0xff));
+ readbyte = rtw_read8(Adapter, EFUSE_CTRL+2);
+ rtw_write8(Adapter, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc));
+
+ /* Write bit 32 0 */
+ readbyte = rtw_read8(Adapter, EFUSE_CTRL+3);
+ rtw_write8(Adapter, EFUSE_CTRL+3, (readbyte & 0x7f));
+
+ /* Check bit 32 read-ready */
+ retry = 0;
+ value32 = rtw_read32(Adapter, EFUSE_CTRL);
+ while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) {
+ value32 = rtw_read32(Adapter, EFUSE_CTRL);
+ retry++;
+ }
+
+ /* 20100205 Joseph: Add delay suggested by SD1 Victor. */
+ /* This fix the problem that Efuse read error in high temperature condition. */
+ /* Designer says that there shall be some delay after ready bit is set, or the */
+ /* result will always stay on last data we read. */
+ rtw_udelay_os(50);
+ value32 = rtw_read32(Adapter, EFUSE_CTRL);
+
+ *pbuf = (u8)(value32 & 0xff);
+}
+
+/* */
+/* Description: */
+/* 1. Execute E-Fuse read byte operation according as map offset and */
+/* save to E-Fuse table. */
+/* 2. Refered from SD1 Richard. */
+/* */
+/* Assumption: */
+/* 1. Boot from E-Fuse and successfully auto-load. */
+/* 2. PASSIVE_LEVEL (USB interface) */
+/* */
+/* Created by Roger, 2008.10.21. */
+/* */
+/* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */
+/* 2. Add efuse utilization collect. */
+/* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */
+/* write addr must be after sec5. */
+/* */
+
+static void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool pseudo)
+{
+ Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, pseudo);
+}
+
+void EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut, bool pseudo
+ )
+{
+ pAdapter->HalFunc.EFUSEGetEfuseDefinition(pAdapter, efuseType, type, pOut, pseudo);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: EFUSE_Read1Byte
+ *
+ * Overview: Copy from WMAC fot EFUSE read 1 byte.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 09/23/2008 MHC Copy from WMAC.
+ *
+ *---------------------------------------------------------------------------*/
+u8 EFUSE_Read1Byte(struct adapter *Adapter, u16 Address)
+{
+ u8 data;
+ u8 Bytetemp = {0x00};
+ u8 temp = {0x00};
+ u32 k = 0;
+ u16 contentLen = 0;
+
+ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI , TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false);
+
+ if (Address < contentLen) { /* E-fuse 512Byte */
+ /* Write E-fuse Register address bit0~7 */
+ temp = Address & 0xFF;
+ rtw_write8(Adapter, EFUSE_CTRL+1, temp);
+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2);
+ /* Write E-fuse Register address bit8~9 */
+ temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC);
+ rtw_write8(Adapter, EFUSE_CTRL+2, temp);
+
+ /* Write 0x30[31]= 0 */
+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+ temp = Bytetemp & 0x7F;
+ rtw_write8(Adapter, EFUSE_CTRL+3, temp);
+
+ /* Wait Write-ready (0x30[31]= 1) */
+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+ while (!(Bytetemp & 0x80)) {
+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+ k++;
+ if (k == 1000) {
+ k = 0;
+ break;
+ }
+ }
+ data = rtw_read8(Adapter, EFUSE_CTRL);
+ return data;
+ } else {
+ return 0xFF;
+ }
+
+} /* EFUSE_Read1Byte */
+
+/* 11/16/2008 MH Read one byte from real Efuse. */
+u8 efuse_OneByteRead(struct adapter *pAdapter, u16 addr, u8 *data, bool pseudo)
+{
+ u8 tmpidx = 0;
+ u8 result;
+
+ if (pseudo) {
+ result = Efuse_Read1ByteFromFakeContent(pAdapter, addr, data);
+ return result;
+ }
+ /* -----------------e-fuse reg ctrl --------------------------------- */
+ /* address */
+ rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr & 0xff));
+ rtw_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) & 0x03)) |
+ (rtw_read8(pAdapter, EFUSE_CTRL+2) & 0xFC));
+
+ rtw_write8(pAdapter, EFUSE_CTRL+3, 0x72);/* read cmd */
+
+ while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100))
+ tmpidx++;
+ if (tmpidx < 100) {
+ *data = rtw_read8(pAdapter, EFUSE_CTRL);
+ result = true;
+ } else {
+ *data = 0xff;
+ result = false;
+ }
+ return result;
+}
+
+/* 11/16/2008 MH Write one byte to reald Efuse. */
+u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data, bool pseudo)
+{
+ u8 tmpidx = 0;
+ u8 result;
+
+ if (pseudo) {
+ result = Efuse_Write1ByteToFakeContent(pAdapter, addr, data);
+ return result;
+ }
+
+ /* -----------------e-fuse reg ctrl --------------------------------- */
+ /* address */
+ rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff));
+ rtw_write8(pAdapter, EFUSE_CTRL+2,
+ (rtw_read8(pAdapter, EFUSE_CTRL+2) & 0xFC) |
+ (u8)((addr>>8) & 0x03));
+ rtw_write8(pAdapter, EFUSE_CTRL, data);/* data */
+
+ rtw_write8(pAdapter, EFUSE_CTRL+3, 0xF2);/* write cmd */
+
+ while ((0x80 & rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100))
+ tmpidx++;
+
+ if (tmpidx < 100)
+ result = true;
+ else
+ result = false;
+
+ return result;
+}
+
+int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool pseudo)
+{
+ int ret = 0;
+
+ ret = pAdapter->HalFunc.Efuse_PgPacketRead(pAdapter, offset, data, pseudo);
+
+ return ret;
+}
+
+int Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool pseudo)
+{
+ int ret;
+
+ ret = pAdapter->HalFunc.Efuse_PgPacketWrite(pAdapter, offset, word_en, data, pseudo);
+
+ return ret;
+}
+
+
+static int Efuse_PgPacketWrite_BT(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool pseudo)
+{
+ int ret;
+
+ ret = pAdapter->HalFunc.Efuse_PgPacketWrite_BT(pAdapter, offset, word_en, data, pseudo);
+
+ return ret;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: efuse_WordEnableDataRead
+ *
+ * Overview: Read allowed word in current efuse section data.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/16/2008 MHC Create Version 0.
+ * 11/21/2008 MHC Fix Write bug when we only enable late word.
+ *
+ *---------------------------------------------------------------------------*/
+void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata)
+{
+ if (!(word_en&BIT(0))) {
+ targetdata[0] = sourdata[0];
+ targetdata[1] = sourdata[1];
+ }
+ if (!(word_en&BIT(1))) {
+ targetdata[2] = sourdata[2];
+ targetdata[3] = sourdata[3];
+ }
+ if (!(word_en&BIT(2))) {
+ targetdata[4] = sourdata[4];
+ targetdata[5] = sourdata[5];
+ }
+ if (!(word_en&BIT(3))) {
+ targetdata[6] = sourdata[6];
+ targetdata[7] = sourdata[7];
+ }
+}
+
+u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool pseudo)
+{
+ u8 ret = 0;
+
+ ret = pAdapter->HalFunc.Efuse_WordEnableDataWrite(pAdapter, efuse_addr, word_en, data, pseudo);
+
+ return ret;
+}
+
+static u8 efuse_read8(struct adapter *padapter, u16 address, u8 *value)
+{
+ return efuse_OneByteRead(padapter, address, value, false);
+}
+
+static u8 efuse_write8(struct adapter *padapter, u16 address, u8 *value)
+{
+ return efuse_OneByteWrite(padapter, address, *value, false);
+}
+
+/*
+ * read/wirte raw efuse data
+ */
+u8 rtw_efuse_access(struct adapter *padapter, u8 write, u16 start_addr, u16 cnts, u8 *data)
+{
+ int i = 0;
+ u16 real_content_len = 0, max_available_size = 0;
+ u8 res = _FAIL ;
+ u8 (*rw8)(struct adapter *, u16, u8*);
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&real_content_len, false);
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+
+ if (start_addr > real_content_len)
+ return _FAIL;
+
+ if (write) {
+ if ((start_addr + cnts) > max_available_size)
+ return _FAIL;
+ rw8 = &efuse_write8;
+ } else {
+ rw8 = &efuse_read8;
+ }
+
+ Efuse_PowerSwitch(padapter, write, true);
+
+ /* e-fuse one byte read / write */
+ for (i = 0; i < cnts; i++) {
+ if (start_addr >= real_content_len) {
+ res = _FAIL;
+ break;
+ }
+
+ res = rw8(padapter, start_addr++, data++);
+ if (_FAIL == res)
+ break;
+ }
+
+ Efuse_PowerSwitch(padapter, write, false);
+
+ return res;
+}
+/* */
+u16 efuse_GetMaxSize(struct adapter *padapter)
+{
+ u16 max_size;
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_size, false);
+ return max_size;
+}
+/* */
+u8 efuse_GetCurrentSize(struct adapter *padapter, u16 *size)
+{
+ Efuse_PowerSwitch(padapter, false, true);
+ *size = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, false);
+ Efuse_PowerSwitch(padapter, false, false);
+
+ return _SUCCESS;
+}
+/* */
+u8 rtw_efuse_map_read(struct adapter *padapter, u16 addr, u16 cnts, u8 *data)
+{
+ u16 mapLen = 0;
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false);
+
+ if ((addr + cnts) > mapLen)
+ return _FAIL;
+
+ Efuse_PowerSwitch(padapter, false, true);
+
+ efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data, false);
+
+ Efuse_PowerSwitch(padapter, false, false);
+
+ return _SUCCESS;
+}
+
+u8 rtw_BT_efuse_map_read(struct adapter *padapter, u16 addr, u16 cnts, u8 *data)
+{
+ u16 mapLen = 0;
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false);
+
+ if ((addr + cnts) > mapLen)
+ return _FAIL;
+
+ Efuse_PowerSwitch(padapter, false, true);
+
+ efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data, false);
+
+ Efuse_PowerSwitch(padapter, false, false);
+
+ return _SUCCESS;
+}
+/* */
+u8 rtw_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data)
+{
+ u8 offset, word_en;
+ u8 *map;
+ u8 newdata[PGPKT_DATA_SIZE];
+ s32 i, idx;
+ u8 ret = _SUCCESS;
+ u16 mapLen = 0;
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false);
+
+ if ((addr + cnts) > mapLen)
+ return _FAIL;
+
+ map = rtw_zmalloc(mapLen);
+ if (map == NULL)
+ return _FAIL;
+
+ ret = rtw_efuse_map_read(padapter, 0, mapLen, map);
+ if (ret == _FAIL)
+ goto exit;
+
+ Efuse_PowerSwitch(padapter, true, true);
+
+ offset = (addr >> 3);
+ word_en = 0xF;
+ _rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE);
+ i = addr & 0x7; /* index of one package */
+ idx = 0; /* data index */
+
+ if (i & 0x1) {
+ /* odd start */
+ if (data[idx] != map[addr+idx]) {
+ word_en &= ~BIT(i >> 1);
+ newdata[i-1] = map[addr+idx-1];
+ newdata[i] = data[idx];
+ }
+ i++;
+ idx++;
+ }
+ do {
+ for (; i < PGPKT_DATA_SIZE; i += 2) {
+ if (cnts == idx)
+ break;
+ if ((cnts - idx) == 1) {
+ if (data[idx] != map[addr+idx]) {
+ word_en &= ~BIT(i >> 1);
+ newdata[i] = data[idx];
+ newdata[i+1] = map[addr+idx+1];
+ }
+ idx++;
+ break;
+ } else {
+ if ((data[idx] != map[addr+idx]) ||
+ (data[idx+1] != map[addr+idx+1])) {
+ word_en &= ~BIT(i >> 1);
+ newdata[i] = data[idx];
+ newdata[i+1] = data[idx + 1];
+ }
+ idx += 2;
+ }
+ if (idx == cnts)
+ break;
+ }
+
+ if (word_en != 0xF) {
+ ret = Efuse_PgPacketWrite(padapter, offset, word_en, newdata, false);
+ DBG_88E("offset=%x\n", offset);
+ DBG_88E("word_en=%x\n", word_en);
+
+ for (i = 0; i < PGPKT_DATA_SIZE; i++)
+ DBG_88E("data=%x \t", newdata[i]);
+ if (ret == _FAIL)
+ break;
+ }
+
+ if (idx == cnts)
+ break;
+
+ offset++;
+ i = 0;
+ word_en = 0xF;
+ _rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE);
+ } while (1);
+
+ Efuse_PowerSwitch(padapter, true, false);
+exit:
+ kfree(map);
+ return ret;
+}
+
+/* */
+u8 rtw_BT_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data)
+{
+ u8 offset, word_en;
+ u8 *map;
+ u8 newdata[PGPKT_DATA_SIZE];
+ s32 i, idx;
+ u8 ret = _SUCCESS;
+ u16 mapLen = 0;
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false);
+
+ if ((addr + cnts) > mapLen)
+ return _FAIL;
+
+ map = rtw_zmalloc(mapLen);
+ if (map == NULL)
+ return _FAIL;
+
+ ret = rtw_BT_efuse_map_read(padapter, 0, mapLen, map);
+ if (ret == _FAIL)
+ goto exit;
+
+ Efuse_PowerSwitch(padapter, true, true);
+
+ offset = (addr >> 3);
+ word_en = 0xF;
+ _rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE);
+ i = addr & 0x7; /* index of one package */
+ idx = 0; /* data index */
+
+ if (i & 0x1) {
+ /* odd start */
+ if (data[idx] != map[addr+idx]) {
+ word_en &= ~BIT(i >> 1);
+ newdata[i-1] = map[addr+idx-1];
+ newdata[i] = data[idx];
+ }
+ i++;
+ idx++;
+ }
+ do {
+ for (; i < PGPKT_DATA_SIZE; i += 2) {
+ if (cnts == idx)
+ break;
+ if ((cnts - idx) == 1) {
+ if (data[idx] != map[addr+idx]) {
+ word_en &= ~BIT(i >> 1);
+ newdata[i] = data[idx];
+ newdata[i+1] = map[addr+idx+1];
+ }
+ idx++;
+ break;
+ } else {
+ if ((data[idx] != map[addr+idx]) ||
+ (data[idx+1] != map[addr+idx+1])) {
+ word_en &= ~BIT(i >> 1);
+ newdata[i] = data[idx];
+ newdata[i+1] = data[idx + 1];
+ }
+ idx += 2;
+ }
+ if (idx == cnts)
+ break;
+ }
+
+ if (word_en != 0xF) {
+ DBG_88E("%s: offset=%#X\n", __func__, offset);
+ DBG_88E("%s: word_en=%#X\n", __func__, word_en);
+ DBG_88E("%s: data=", __func__);
+ for (i = 0; i < PGPKT_DATA_SIZE; i++)
+ DBG_88E("0x%02X ", newdata[i]);
+ DBG_88E("\n");
+
+ ret = Efuse_PgPacketWrite_BT(padapter, offset, word_en, newdata, false);
+ if (ret == _FAIL)
+ break;
+ }
+
+ if (idx == cnts)
+ break;
+
+ offset++;
+ i = 0;
+ word_en = 0xF;
+ _rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE);
+ } while (1);
+
+ Efuse_PowerSwitch(padapter, true, false);
+
+exit:
+
+ kfree(map);
+
+ return ret;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: efuse_ShadowRead1Byte
+ * efuse_ShadowRead2Byte
+ * efuse_ShadowRead4Byte
+ *
+ * Overview: Read from efuse init map by one/two/four bytes !!!!!
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/12/2008 MHC Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+static void
+efuse_ShadowRead1Byte(
+ struct adapter *pAdapter,
+ u16 Offset,
+ u8 *Value)
+{
+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+
+ *Value = pEEPROM->efuse_eeprom_data[Offset];
+
+} /* EFUSE_ShadowRead1Byte */
+
+/* Read Two Bytes */
+static void
+efuse_ShadowRead2Byte(
+ struct adapter *pAdapter,
+ u16 Offset,
+ u16 *Value)
+{
+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+
+ *Value = pEEPROM->efuse_eeprom_data[Offset];
+ *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8;
+
+} /* EFUSE_ShadowRead2Byte */
+
+/* Read Four Bytes */
+static void
+efuse_ShadowRead4Byte(
+ struct adapter *pAdapter,
+ u16 Offset,
+ u32 *Value)
+{
+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+
+ *Value = pEEPROM->efuse_eeprom_data[Offset];
+ *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8;
+ *Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16;
+ *Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24;
+
+} /* efuse_ShadowRead4Byte */
+
+/*-----------------------------------------------------------------------------
+ * Function: Efuse_ReadAllMap
+ *
+ * Overview: Read All Efuse content
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/11/2008 MHC Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse, bool pseudo)
+{
+ u16 mapLen = 0;
+
+ Efuse_PowerSwitch(pAdapter, false, true);
+
+ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, pseudo);
+
+ efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse, pseudo);
+
+ Efuse_PowerSwitch(pAdapter, false, false);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: EFUSE_ShadowMapUpdate
+ *
+ * Overview: Transfer current EFUSE content to shadow init and modify map.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/13/2008 MHC Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void EFUSE_ShadowMapUpdate(
+ struct adapter *pAdapter,
+ u8 efuseType,
+ bool pseudo)
+{
+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+ u16 mapLen = 0;
+
+ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, pseudo);
+
+ if (pEEPROM->bautoload_fail_flag)
+ _rtw_memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen);
+ else
+ Efuse_ReadAllMap(pAdapter, efuseType, pEEPROM->efuse_eeprom_data, pseudo);
+} /* EFUSE_ShadowMapUpdate */
+
+/*-----------------------------------------------------------------------------
+ * Function: EFUSE_ShadowRead
+ *
+ * Overview: Read from efuse init map !!!!!
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/12/2008 MHC Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void EFUSE_ShadowRead(struct adapter *pAdapter, u8 Type, u16 Offset, u32 *Value)
+{
+ if (Type == 1)
+ efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value);
+ else if (Type == 2)
+ efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value);
+ else if (Type == 4)
+ efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value);
+
+} /* EFUSE_ShadowRead */
diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
new file mode 100644
index 00000000000..3605c5da822
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
@@ -0,0 +1,1640 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _IEEE80211_C
+
+#include <drv_types.h>
+#include <ieee80211.h>
+#include <wifi.h>
+#include <osdep_service.h>
+#include <wlan_bssdef.h>
+#include <usb_osintf.h>
+
+u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
+u16 RTW_WPA_VERSION = 1;
+u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 };
+u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 };
+u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };
+u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };
+u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };
+u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };
+u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
+u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
+u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
+
+u16 RSN_VERSION_BSD = 1;
+u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 };
+u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };
+u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };
+u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };
+u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };
+u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };
+u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };
+u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
+/* */
+/* for adhoc-master to generate ie and provide supported-rate to fw */
+/* */
+
+static u8 WIFI_CCKRATES[] = {
+ (IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK),
+ (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK),
+ (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK),
+ (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK)
+ };
+
+static u8 WIFI_OFDMRATES[] = {
+ (IEEE80211_OFDM_RATE_6MB),
+ (IEEE80211_OFDM_RATE_9MB),
+ (IEEE80211_OFDM_RATE_12MB),
+ (IEEE80211_OFDM_RATE_18MB),
+ (IEEE80211_OFDM_RATE_24MB),
+ IEEE80211_OFDM_RATE_36MB,
+ IEEE80211_OFDM_RATE_48MB,
+ IEEE80211_OFDM_RATE_54MB
+ };
+
+
+int rtw_get_bit_value_from_ieee_value(u8 val)
+{
+ unsigned char dot11_rate_table[] = {
+ 2, 4, 11, 22, 12, 18, 24, 36, 48,
+ 72, 96, 108, 0}; /* last element must be zero!! */
+
+ int i = 0;
+ while (dot11_rate_table[i] != 0) {
+ if (dot11_rate_table[i] == val)
+ return BIT(i);
+ i++;
+ }
+ return 0;
+}
+
+uint rtw_is_cckrates_included(u8 *rate)
+{
+ u32 i = 0;
+
+ while (rate[i] != 0) {
+ if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) ||
+ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22))
+ return true;
+ i++;
+ }
+ return false;
+}
+
+uint rtw_is_cckratesonly_included(u8 *rate)
+{
+ u32 i = 0;
+
+ while (rate[i] != 0) {
+ if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
+ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22))
+ return false;
+ i++;
+ }
+
+ return true;
+}
+
+int rtw_check_network_type(unsigned char *rate, int ratelen, int channel)
+{
+ if (channel > 14) {
+ if ((rtw_is_cckrates_included(rate)) == true)
+ return WIRELESS_INVALID;
+ else
+ return WIRELESS_11A;
+ } else { /* could be pure B, pure G, or B/G */
+ if ((rtw_is_cckratesonly_included(rate)) == true)
+ return WIRELESS_11B;
+ else if ((rtw_is_cckrates_included(rate)) == true)
+ return WIRELESS_11BG;
+ else
+ return WIRELESS_11G;
+ }
+}
+
+u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source,
+ unsigned int *frlen)
+{
+ memcpy((void *)pbuf, (void *)source, len);
+ *frlen = *frlen + len;
+ return pbuf + len;
+}
+
+/* rtw_set_ie will update frame length */
+u8 *rtw_set_ie
+(
+ u8 *pbuf,
+ int index,
+ uint len,
+ u8 *source,
+ uint *frlen /* frame length */
+)
+{
+_func_enter_;
+ *pbuf = (u8)index;
+
+ *(pbuf + 1) = (u8)len;
+
+ if (len > 0)
+ memcpy((void *)(pbuf + 2), (void *)source, len);
+
+ *frlen = *frlen + (len + 2);
+
+ return pbuf + len + 2;
+_func_exit_;
+}
+
+inline u8 *rtw_set_ie_ch_switch (u8 *buf, u32 *buf_len, u8 ch_switch_mode,
+ u8 new_ch, u8 ch_switch_cnt)
+{
+ u8 ie_data[3];
+
+ ie_data[0] = ch_switch_mode;
+ ie_data[1] = new_ch;
+ ie_data[2] = ch_switch_cnt;
+ return rtw_set_ie(buf, WLAN_EID_CHANNEL_SWITCH, 3, ie_data, buf_len);
+}
+
+inline u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset)
+{
+ if (ch_offset == SCN)
+ return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ else if (ch_offset == SCA)
+ return HAL_PRIME_CHNL_OFFSET_UPPER;
+ else if (ch_offset == SCB)
+ return HAL_PRIME_CHNL_OFFSET_LOWER;
+
+ return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+}
+
+inline u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset)
+{
+ if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
+ return SCN;
+ else if (ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+ return SCB;
+ else if (ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+ return SCA;
+
+ return SCN;
+}
+
+inline u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset)
+{
+ return rtw_set_ie(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET, 1, &secondary_ch_offset, buf_len);
+}
+
+inline u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl,
+ u8 flags, u16 reason, u16 precedence)
+{
+ u8 ie_data[6];
+
+ ie_data[0] = ttl;
+ ie_data[1] = flags;
+ RTW_PUT_LE16((u8 *)&ie_data[2], reason);
+ RTW_PUT_LE16((u8 *)&ie_data[4], precedence);
+
+ return rtw_set_ie(buf, 0x118, 6, ie_data, buf_len);
+}
+
+/*----------------------------------------------------------------------------
+index: the information element id index, limit is the limit for search
+-----------------------------------------------------------------------------*/
+u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit)
+{
+ int tmp, i;
+ u8 *p;
+_func_enter_;
+ if (limit < 1) {
+ _func_exit_;
+ return NULL;
+ }
+
+ p = pbuf;
+ i = 0;
+ *len = 0;
+ while (1) {
+ if (*p == index) {
+ *len = *(p + 1);
+ return p;
+ } else {
+ tmp = *(p + 1);
+ p += (tmp + 2);
+ i += (tmp + 2);
+ }
+ if (i >= limit)
+ break;
+ }
+_func_exit_;
+ return NULL;
+}
+
+/**
+ * rtw_get_ie_ex - Search specific IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @eid: Element ID to match
+ * @oui: OUI to match
+ * @oui_len: OUI length
+ * @ie: If not NULL and the specific IE is found, the IE will be copied to the buf starting from the specific IE
+ * @ielen: If not NULL and the specific IE is found, will set to the length of the entire IE
+ *
+ * Returns: The address of the specific IE found, or NULL
+ */
+u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen)
+{
+ uint cnt;
+ u8 *target_ie = NULL;
+
+
+ if (ielen)
+ *ielen = 0;
+
+ if (!in_ie || in_len <= 0)
+ return target_ie;
+
+ cnt = 0;
+
+ while (cnt < in_len) {
+ if (eid == in_ie[cnt] && (!oui || _rtw_memcmp(&in_ie[cnt+2], oui, oui_len))) {
+ target_ie = &in_ie[cnt];
+
+ if (ie)
+ memcpy(ie, &in_ie[cnt], in_ie[cnt+1]+2);
+
+ if (ielen)
+ *ielen = in_ie[cnt+1]+2;
+
+ break;
+ } else {
+ cnt += in_ie[cnt+1]+2; /* goto next */
+ }
+ }
+ return target_ie;
+}
+
+/**
+ * rtw_ies_remove_ie - Find matching IEs and remove
+ * @ies: Address of IEs to search
+ * @ies_len: Pointer of length of ies, will update to new length
+ * @offset: The offset to start scarch
+ * @eid: Element ID to match
+ * @oui: OUI to match
+ * @oui_len: OUI length
+ *
+ * Returns: _SUCCESS: ies is updated, _FAIL: not updated
+ */
+int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len)
+{
+ int ret = _FAIL;
+ u8 *target_ie;
+ u32 target_ielen;
+ u8 *start;
+ uint search_len;
+
+ if (!ies || !ies_len || *ies_len <= offset)
+ goto exit;
+
+ start = ies + offset;
+ search_len = *ies_len - offset;
+
+ while (1) {
+ target_ie = rtw_get_ie_ex(start, search_len, eid, oui, oui_len, NULL, &target_ielen);
+ if (target_ie && target_ielen) {
+ u8 buf[MAX_IE_SZ] = {0};
+ u8 *remain_ies = target_ie + target_ielen;
+ uint remain_len = search_len - (remain_ies - start);
+
+ memcpy(buf, remain_ies, remain_len);
+ memcpy(target_ie, buf, remain_len);
+ *ies_len = *ies_len - target_ielen;
+ ret = _SUCCESS;
+
+ start = target_ie;
+ search_len = remain_len;
+ } else {
+ break;
+ }
+ }
+exit:
+ return ret;
+}
+
+void rtw_set_supported_rate(u8 *SupportedRates, uint mode)
+{
+_func_enter_;
+
+ _rtw_memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
+
+ switch (mode) {
+ case WIRELESS_11B:
+ memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
+ break;
+ case WIRELESS_11G:
+ case WIRELESS_11A:
+ case WIRELESS_11_5N:
+ case WIRELESS_11A_5N:/* Todo: no basic rate for ofdm ? */
+ memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
+ break;
+ case WIRELESS_11BG:
+ case WIRELESS_11G_24N:
+ case WIRELESS_11_24N:
+ case WIRELESS_11BG_24N:
+ memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
+ memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
+ break;
+ }
+_func_exit_;
+}
+
+uint rtw_get_rateset_len(u8 *rateset)
+{
+ uint i = 0;
+_func_enter_;
+ while (1) {
+ if ((rateset[i]) == 0)
+ break;
+ if (i > 12)
+ break;
+ i++;
+ }
+_func_exit_;
+ return i;
+}
+
+int rtw_generate_ie(struct registry_priv *pregistrypriv)
+{
+ u8 wireless_mode;
+ int sz = 0, rateLen;
+ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
+ u8 *ie = pdev_network->IEs;
+
+_func_enter_;
+
+ /* timestamp will be inserted by hardware */
+ sz += 8;
+ ie += sz;
+
+ /* beacon interval : 2bytes */
+ *(__le16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);/* BCN_INTERVAL; */
+ sz += 2;
+ ie += 2;
+
+ /* capability info */
+ *(u16 *)ie = 0;
+
+ *(__le16 *)ie |= cpu_to_le16(cap_IBSS);
+
+ if (pregistrypriv->preamble == PREAMBLE_SHORT)
+ *(__le16 *)ie |= cpu_to_le16(cap_ShortPremble);
+
+ if (pdev_network->Privacy)
+ *(__le16 *)ie |= cpu_to_le16(cap_Privacy);
+
+ sz += 2;
+ ie += 2;
+
+ /* SSID */
+ ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz);
+
+ /* supported rates */
+ if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) {
+ if (pdev_network->Configuration.DSConfig > 14)
+ wireless_mode = WIRELESS_11A_5N;
+ else
+ wireless_mode = WIRELESS_11BG_24N;
+ } else {
+ wireless_mode = pregistrypriv->wireless_mode;
+ }
+
+ rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode);
+
+ rateLen = rtw_get_rateset_len(pdev_network->SupportedRates);
+
+ if (rateLen > 8) {
+ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz);
+ /* ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */
+ } else {
+ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz);
+ }
+
+ /* DS parameter set */
+ ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&(pdev_network->Configuration.DSConfig), &sz);
+
+ /* IBSS Parameter Set */
+
+ ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz);
+
+ if (rateLen > 8)
+ ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz);
+_func_exit_;
+
+ return sz;
+}
+
+unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit)
+{
+ int len;
+ u16 val16;
+ __le16 le_tmp;
+ unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
+ u8 *pbuf = pie;
+ int limit_new = limit;
+
+ while (1) {
+ pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new);
+
+ if (pbuf) {
+ /* check if oui matches... */
+ if (_rtw_memcmp((pbuf + 2), wpa_oui_type, sizeof (wpa_oui_type)) == false)
+ goto check_next_ie;
+
+ /* check version... */
+ memcpy((u8 *)&le_tmp, (pbuf + 6), sizeof(val16));
+
+ val16 = le16_to_cpu(le_tmp);
+ if (val16 != 0x0001)
+ goto check_next_ie;
+ *wpa_ie_len = *(pbuf + 1);
+ return pbuf;
+ } else {
+ *wpa_ie_len = 0;
+ return NULL;
+ }
+
+check_next_ie:
+ limit_new = limit - (pbuf - pie) - 2 - len;
+ if (limit_new <= 0)
+ break;
+ pbuf += (2 + len);
+ }
+ *wpa_ie_len = 0;
+ return NULL;
+}
+
+unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit)
+{
+
+ return rtw_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit);
+}
+
+int rtw_get_wpa_cipher_suite(u8 *s)
+{
+ if (_rtw_memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == true)
+ return WPA_CIPHER_NONE;
+ if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == true)
+ return WPA_CIPHER_WEP40;
+ if (_rtw_memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == true)
+ return WPA_CIPHER_TKIP;
+ if (_rtw_memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == true)
+ return WPA_CIPHER_CCMP;
+ if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == true)
+ return WPA_CIPHER_WEP104;
+
+ return 0;
+}
+
+int rtw_get_wpa2_cipher_suite(u8 *s)
+{
+ if (_rtw_memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == true)
+ return WPA_CIPHER_NONE;
+ if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == true)
+ return WPA_CIPHER_WEP40;
+ if (_rtw_memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == true)
+ return WPA_CIPHER_TKIP;
+ if (_rtw_memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == true)
+ return WPA_CIPHER_CCMP;
+ if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == true)
+ return WPA_CIPHER_WEP104;
+
+ return 0;
+}
+
+
+int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
+{
+ int i, ret = _SUCCESS;
+ int left, count;
+ u8 *pos;
+ u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1};
+
+ if (wpa_ie_len <= 0) {
+ /* No WPA IE - fail silently */
+ return _FAIL;
+ }
+
+
+ if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) ||
+ (_rtw_memcmp(wpa_ie+2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN) != true))
+ return _FAIL;
+
+ pos = wpa_ie;
+
+ pos += 8;
+ left = wpa_ie_len - 8;
+
+
+ /* group_cipher */
+ if (left >= WPA_SELECTOR_LEN) {
+ *group_cipher = rtw_get_wpa_cipher_suite(pos);
+ pos += WPA_SELECTOR_LEN;
+ left -= WPA_SELECTOR_LEN;
+ } else if (left > 0) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left));
+ return _FAIL;
+ }
+
+ /* pairwise_cipher */
+ if (left >= 2) {
+ count = RTW_GET_LE16(pos);
+ pos += 2;
+ left -= 2;
+
+ if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), "
+ "count %u left %u", __func__, count, left));
+ return _FAIL;
+ }
+
+ for (i = 0; i < count; i++) {
+ *pairwise_cipher |= rtw_get_wpa_cipher_suite(pos);
+
+ pos += WPA_SELECTOR_LEN;
+ left -= WPA_SELECTOR_LEN;
+ }
+ } else if (left == 1) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__));
+ return _FAIL;
+ }
+
+ if (is_8021x) {
+ if (left >= 6) {
+ pos += 2;
+ if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s : there has 802.1x auth\n", __func__));
+ *is_8021x = 1;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
+{
+ int i, ret = _SUCCESS;
+ int left, count;
+ u8 *pos;
+ u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01};
+
+ if (rsn_ie_len <= 0) {
+ /* No RSN IE - fail silently */
+ return _FAIL;
+ }
+
+
+ if ((*rsn_ie != _WPA2_IE_ID_) || (*(rsn_ie+1) != (u8)(rsn_ie_len - 2)))
+ return _FAIL;
+
+ pos = rsn_ie;
+ pos += 4;
+ left = rsn_ie_len - 4;
+
+ /* group_cipher */
+ if (left >= RSN_SELECTOR_LEN) {
+ *group_cipher = rtw_get_wpa2_cipher_suite(pos);
+
+ pos += RSN_SELECTOR_LEN;
+ left -= RSN_SELECTOR_LEN;
+
+ } else if (left > 0) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left));
+ return _FAIL;
+ }
+
+ /* pairwise_cipher */
+ if (left >= 2) {
+ count = RTW_GET_LE16(pos);
+ pos += 2;
+ left -= 2;
+
+ if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), "
+ "count %u left %u", __func__, count, left));
+ return _FAIL;
+ }
+
+ for (i = 0; i < count; i++) {
+ *pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos);
+
+ pos += RSN_SELECTOR_LEN;
+ left -= RSN_SELECTOR_LEN;
+ }
+
+ } else if (left == 1) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__));
+
+ return _FAIL;
+ }
+
+ if (is_8021x) {
+ if (left >= 6) {
+ pos += 2;
+ if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s (): there has 802.1x auth\n", __func__));
+ *is_8021x = 1;
+ }
+ }
+ }
+ return ret;
+}
+
+int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
+{
+ u8 authmode, sec_idx, i;
+ u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
+ uint cnt;
+
+_func_enter_;
+
+ /* Search required WPA or WPA2 IE and copy to sec_ie[] */
+
+ cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_);
+
+ sec_idx = 0;
+
+ while (cnt < in_len) {
+ authmode = in_ie[cnt];
+
+ if ((authmode == _WPA_IE_ID_) && (_rtw_memcmp(&in_ie[cnt+2], &wpa_oui[0], 4))) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("\n rtw_get_wpa_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n",
+ sec_idx, in_ie[cnt+1]+2));
+
+ if (wpa_ie) {
+ memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt+1]+2);
+
+ for (i = 0; i < (in_ie[cnt+1]+2); i += 8) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
+ wpa_ie[i], wpa_ie[i+1], wpa_ie[i+2], wpa_ie[i+3], wpa_ie[i+4],
+ wpa_ie[i+5], wpa_ie[i+6], wpa_ie[i+7]));
+ }
+ }
+
+ *wpa_len = in_ie[cnt+1]+2;
+ cnt += in_ie[cnt+1]+2; /* get next */
+ } else {
+ if (authmode == _WPA2_IE_ID_) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("\n get_rsn_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n",
+ sec_idx, in_ie[cnt+1]+2));
+
+ if (rsn_ie) {
+ memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt+1]+2);
+
+ for (i = 0; i < (in_ie[cnt+1]+2); i += 8) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
+ rsn_ie[i], rsn_ie[i+1], rsn_ie[i+2], rsn_ie[i+3], rsn_ie[i+4],
+ rsn_ie[i+5], rsn_ie[i+6], rsn_ie[i+7]));
+ }
+ }
+
+ *rsn_len = in_ie[cnt+1]+2;
+ cnt += in_ie[cnt+1]+2; /* get next */
+ } else {
+ cnt += in_ie[cnt+1]+2; /* get next */
+ }
+ }
+ }
+
+_func_exit_;
+
+ return *rsn_len + *wpa_len;
+}
+
+u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
+{
+ u8 match = false;
+ u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+ if (ie_ptr == NULL)
+ return match;
+
+ eid = ie_ptr[0];
+
+ if ((eid == _WPA_IE_ID_) && (_rtw_memcmp(&ie_ptr[2], wps_oui, 4))) {
+ *wps_ielen = ie_ptr[1]+2;
+ match = true;
+ }
+ return match;
+}
+
+/**
+ * rtw_get_wps_ie - Search WPS IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie
+ * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE
+ *
+ * Returns: The address of the WPS IE found, or NULL
+ */
+u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
+{
+ uint cnt;
+ u8 *wpsie_ptr = NULL;
+ u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+ if (wps_ielen)
+ *wps_ielen = 0;
+
+ if (!in_ie || in_len <= 0)
+ return wpsie_ptr;
+
+ cnt = 0;
+
+ while (cnt < in_len) {
+ eid = in_ie[cnt];
+
+ if ((eid == _WPA_IE_ID_) && (_rtw_memcmp(&in_ie[cnt+2], wps_oui, 4))) {
+ wpsie_ptr = &in_ie[cnt];
+
+ if (wps_ie)
+ memcpy(wps_ie, &in_ie[cnt], in_ie[cnt+1]+2);
+
+ if (wps_ielen)
+ *wps_ielen = in_ie[cnt+1]+2;
+
+ cnt += in_ie[cnt+1]+2;
+
+ break;
+ } else {
+ cnt += in_ie[cnt+1]+2; /* goto next */
+ }
+ }
+ return wpsie_ptr;
+}
+
+/**
+ * rtw_get_wps_attr - Search a specific WPS attribute from a given WPS IE
+ * @wps_ie: Address of WPS IE to search
+ * @wps_ielen: Length limit from wps_ie
+ * @target_attr_id: The attribute ID of WPS attribute to search
+ * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute will be copied to the buf starting from buf_attr
+ * @len_attr: If not NULL and the WPS attribute is found, will set to the length of the entire WPS attribute
+ *
+ * Returns: the address of the specific WPS attribute found, or NULL
+ */
+u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_attr, u32 *len_attr)
+{
+ u8 *attr_ptr = NULL;
+ u8 *target_attr_ptr = NULL;
+ u8 wps_oui[4] = {0x00, 0x50, 0xF2, 0x04};
+
+ if (len_attr)
+ *len_attr = 0;
+
+ if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) ||
+ (_rtw_memcmp(wps_ie + 2, wps_oui , 4) != true))
+ return attr_ptr;
+
+ /* 6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */
+ attr_ptr = wps_ie + 6; /* goto first attr */
+
+ while (attr_ptr - wps_ie < wps_ielen) {
+ /* 4 = 2(Attribute ID) + 2(Length) */
+ u16 attr_id = RTW_GET_BE16(attr_ptr);
+ u16 attr_data_len = RTW_GET_BE16(attr_ptr + 2);
+ u16 attr_len = attr_data_len + 4;
+
+ if (attr_id == target_attr_id) {
+ target_attr_ptr = attr_ptr;
+ if (buf_attr)
+ memcpy(buf_attr, attr_ptr, attr_len);
+ if (len_attr)
+ *len_attr = attr_len;
+ break;
+ } else {
+ attr_ptr += attr_len; /* goto next */
+ }
+ }
+ return target_attr_ptr;
+}
+
+/**
+ * rtw_get_wps_attr_content - Search a specific WPS attribute content from a given WPS IE
+ * @wps_ie: Address of WPS IE to search
+ * @wps_ielen: Length limit from wps_ie
+ * @target_attr_id: The attribute ID of WPS attribute to search
+ * @buf_content: If not NULL and the WPS attribute is found, WPS attribute content will be copied to the buf starting from buf_content
+ * @len_content: If not NULL and the WPS attribute is found, will set to the length of the WPS attribute content
+ *
+ * Returns: the address of the specific WPS attribute content found, or NULL
+ */
+u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_content, uint *len_content)
+{
+ u8 *attr_ptr;
+ u32 attr_len;
+
+ if (len_content)
+ *len_content = 0;
+
+ attr_ptr = rtw_get_wps_attr(wps_ie, wps_ielen, target_attr_id, NULL, &attr_len);
+
+ if (attr_ptr && attr_len) {
+ if (buf_content)
+ memcpy(buf_content, attr_ptr+4, attr_len-4);
+
+ if (len_content)
+ *len_content = attr_len-4;
+
+ return attr_ptr+4;
+ }
+
+ return NULL;
+}
+
+static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
+ struct rtw_ieee802_11_elems *elems,
+ int show_errors)
+{
+ unsigned int oui;
+
+ /* first 3 bytes in vendor specific information element are the IEEE
+ * OUI of the vendor. The following byte is used a vendor specific
+ * sub-type. */
+ if (elen < 4) {
+ if (show_errors) {
+ DBG_88E("short vendor specific information element ignored (len=%lu)\n",
+ (unsigned long) elen);
+ }
+ return -1;
+ }
+
+ oui = RTW_GET_BE24(pos);
+ switch (oui) {
+ case OUI_MICROSOFT:
+ /* Microsoft/Wi-Fi information elements are further typed and
+ * subtyped */
+ switch (pos[3]) {
+ case 1:
+ /* Microsoft OUI (00:50:F2) with OUI Type 1:
+ * real WPA information element */
+ elems->wpa_ie = pos;
+ elems->wpa_ie_len = elen;
+ break;
+ case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
+ if (elen < 5) {
+ DBG_88E("short WME information element ignored (len=%lu)\n",
+ (unsigned long) elen);
+ return -1;
+ }
+ switch (pos[4]) {
+ case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
+ case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
+ elems->wme = pos;
+ elems->wme_len = elen;
+ break;
+ case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
+ elems->wme_tspec = pos;
+ elems->wme_tspec_len = elen;
+ break;
+ default:
+ DBG_88E("unknown WME information element ignored (subtype=%d len=%lu)\n",
+ pos[4], (unsigned long) elen);
+ return -1;
+ }
+ break;
+ case 4:
+ /* Wi-Fi Protected Setup (WPS) IE */
+ elems->wps_ie = pos;
+ elems->wps_ie_len = elen;
+ break;
+ default:
+ DBG_88E("Unknown Microsoft information element ignored (type=%d len=%lu)\n",
+ pos[3], (unsigned long) elen);
+ return -1;
+ }
+ break;
+
+ case OUI_BROADCOM:
+ switch (pos[3]) {
+ case VENDOR_HT_CAPAB_OUI_TYPE:
+ elems->vendor_ht_cap = pos;
+ elems->vendor_ht_cap_len = elen;
+ break;
+ default:
+ DBG_88E("Unknown Broadcom information element ignored (type=%d len=%lu)\n",
+ pos[3], (unsigned long) elen);
+ return -1;
+ }
+ break;
+ default:
+ DBG_88E("unknown vendor specific information element ignored (vendor OUI %02x:%02x:%02x len=%lu)\n",
+ pos[0], pos[1], pos[2], (unsigned long) elen);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * ieee802_11_parse_elems - Parse information elements in management frames
+ * @start: Pointer to the start of IEs
+ * @len: Length of IE buffer in octets
+ * @elems: Data structure for parsed elements
+ * @show_errors: Whether to show parsing errors in debug log
+ * Returns: Parsing result
+ */
+enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len,
+ struct rtw_ieee802_11_elems *elems,
+ int show_errors)
+{
+ uint left = len;
+ u8 *pos = start;
+ int unknown = 0;
+
+ _rtw_memset(elems, 0, sizeof(*elems));
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ left -= 2;
+
+ if (elen > left) {
+ if (show_errors) {
+ DBG_88E("IEEE 802.11 element parse failed (id=%d elen=%d left=%lu)\n",
+ id, elen, (unsigned long) left);
+ }
+ return ParseFailed;
+ }
+
+ switch (id) {
+ case WLAN_EID_SSID:
+ elems->ssid = pos;
+ elems->ssid_len = elen;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ elems->supp_rates = pos;
+ elems->supp_rates_len = elen;
+ break;
+ case WLAN_EID_FH_PARAMS:
+ elems->fh_params = pos;
+ elems->fh_params_len = elen;
+ break;
+ case WLAN_EID_DS_PARAMS:
+ elems->ds_params = pos;
+ elems->ds_params_len = elen;
+ break;
+ case WLAN_EID_CF_PARAMS:
+ elems->cf_params = pos;
+ elems->cf_params_len = elen;
+ break;
+ case WLAN_EID_TIM:
+ elems->tim = pos;
+ elems->tim_len = elen;
+ break;
+ case WLAN_EID_IBSS_PARAMS:
+ elems->ibss_params = pos;
+ elems->ibss_params_len = elen;
+ break;
+ case WLAN_EID_CHALLENGE:
+ elems->challenge = pos;
+ elems->challenge_len = elen;
+ break;
+ case WLAN_EID_ERP_INFO:
+ elems->erp_info = pos;
+ elems->erp_info_len = elen;
+ break;
+ case WLAN_EID_EXT_SUPP_RATES:
+ elems->ext_supp_rates = pos;
+ elems->ext_supp_rates_len = elen;
+ break;
+ case WLAN_EID_VENDOR_SPECIFIC:
+ if (rtw_ieee802_11_parse_vendor_specific(pos, elen, elems, show_errors))
+ unknown++;
+ break;
+ case WLAN_EID_RSN:
+ elems->rsn_ie = pos;
+ elems->rsn_ie_len = elen;
+ break;
+ case WLAN_EID_PWR_CAPABILITY:
+ elems->power_cap = pos;
+ elems->power_cap_len = elen;
+ break;
+ case WLAN_EID_SUPPORTED_CHANNELS:
+ elems->supp_channels = pos;
+ elems->supp_channels_len = elen;
+ break;
+ case WLAN_EID_MOBILITY_DOMAIN:
+ elems->mdie = pos;
+ elems->mdie_len = elen;
+ break;
+ case WLAN_EID_FAST_BSS_TRANSITION:
+ elems->ftie = pos;
+ elems->ftie_len = elen;
+ break;
+ case WLAN_EID_TIMEOUT_INTERVAL:
+ elems->timeout_int = pos;
+ elems->timeout_int_len = elen;
+ break;
+ case WLAN_EID_HT_CAP:
+ elems->ht_capabilities = pos;
+ elems->ht_capabilities_len = elen;
+ break;
+ case WLAN_EID_HT_OPERATION:
+ elems->ht_operation = pos;
+ elems->ht_operation_len = elen;
+ break;
+ default:
+ unknown++;
+ if (!show_errors)
+ break;
+ DBG_88E("IEEE 802.11 element parse ignored unknown element (id=%d elen=%d)\n",
+ id, elen);
+ break;
+ }
+ left -= elen;
+ pos += elen;
+ }
+ if (left)
+ return ParseFailed;
+ return unknown ? ParseUnknown : ParseOK;
+}
+
+u8 key_char2num(u8 ch)
+{
+ if ((ch >= '0') && (ch <= '9'))
+ return ch - '0';
+ else if ((ch >= 'a') && (ch <= 'f'))
+ return ch - 'a' + 10;
+ else if ((ch >= 'A') && (ch <= 'F'))
+ return ch - 'A' + 10;
+ else
+ return 0xff;
+}
+
+u8 str_2char2num(u8 hch, u8 lch)
+{
+ return (key_char2num(hch) * 10) + key_char2num(lch);
+}
+
+u8 key_2char2num(u8 hch, u8 lch)
+{
+ return (key_char2num(hch) << 4) | key_char2num(lch);
+}
+
+void rtw_macaddr_cfg(u8 *mac_addr)
+{
+ u8 mac[ETH_ALEN];
+ if (mac_addr == NULL)
+ return;
+
+ if (rtw_initmac) { /* Users specify the mac address */
+ int jj, kk;
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ mac[jj] = key_2char2num(rtw_initmac[kk], rtw_initmac[kk + 1]);
+ memcpy(mac_addr, mac, ETH_ALEN);
+ } else { /* Use the mac address stored in the Efuse */
+ memcpy(mac, mac_addr, ETH_ALEN);
+ }
+
+ if (((mac[0] == 0xff) && (mac[1] == 0xff) && (mac[2] == 0xff) &&
+ (mac[3] == 0xff) && (mac[4] == 0xff) && (mac[5] == 0xff)) ||
+ ((mac[0] == 0x0) && (mac[1] == 0x0) && (mac[2] == 0x0) &&
+ (mac[3] == 0x0) && (mac[4] == 0x0) && (mac[5] == 0x0))) {
+ mac[0] = 0x00;
+ mac[1] = 0xe0;
+ mac[2] = 0x4c;
+ mac[3] = 0x87;
+ mac[4] = 0x00;
+ mac[5] = 0x00;
+ /* use default mac addresss */
+ memcpy(mac_addr, mac, ETH_ALEN);
+ DBG_88E("MAC Address from efuse error, assign default one !!!\n");
+ }
+
+ DBG_88E("rtw_macaddr_cfg MAC Address = %pM\n", (mac_addr));
+}
+
+void dump_ies(u8 *buf, u32 buf_len)
+{
+ u8 *pos = (u8 *)buf;
+ u8 id, len;
+
+ while (pos-buf <= buf_len) {
+ id = *pos;
+ len = *(pos+1);
+
+ DBG_88E("%s ID:%u, LEN:%u\n", __func__, id, len);
+ #ifdef CONFIG_88EU_P2P
+ dump_p2p_ie(pos, len);
+ #endif
+ dump_wps_ie(pos, len);
+
+ pos += (2 + len);
+ }
+}
+
+void dump_wps_ie(u8 *ie, u32 ie_len)
+{
+ u8 *pos = (u8 *)ie;
+ u16 id;
+ u16 len;
+ u8 *wps_ie;
+ uint wps_ielen;
+
+ wps_ie = rtw_get_wps_ie(ie, ie_len, NULL, &wps_ielen);
+ if (wps_ie != ie || wps_ielen == 0)
+ return;
+
+ pos += 6;
+ while (pos-ie < ie_len) {
+ id = RTW_GET_BE16(pos);
+ len = RTW_GET_BE16(pos + 2);
+ DBG_88E("%s ID:0x%04x, LEN:%u\n", __func__, id, len);
+ pos += (4+len);
+ }
+}
+
+#ifdef CONFIG_88EU_P2P
+void dump_p2p_ie(u8 *ie, u32 ie_len)
+{
+ u8 *pos = (u8 *)ie;
+ u8 id;
+ u16 len;
+ u8 *p2p_ie;
+ uint p2p_ielen;
+
+ p2p_ie = rtw_get_p2p_ie(ie, ie_len, NULL, &p2p_ielen);
+ if (p2p_ie != ie || p2p_ielen == 0)
+ return;
+
+ pos += 6;
+ while (pos-ie < ie_len) {
+ id = *pos;
+ len = RTW_GET_LE16(pos+1);
+ DBG_88E("%s ID:%u, LEN:%u\n", __func__, id, len);
+ pos += (3+len);
+ }
+}
+
+/**
+ * rtw_get_p2p_ie - Search P2P IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the buf starting from p2p_ie
+ * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of the entire P2P IE
+ *
+ * Returns: The address of the P2P IE found, or NULL
+ */
+u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen)
+{
+ uint cnt = 0;
+ u8 *p2p_ie_ptr;
+ u8 eid, p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09};
+
+ if (p2p_ielen != NULL)
+ *p2p_ielen = 0;
+
+ while (cnt < in_len) {
+ eid = in_ie[cnt];
+ if ((in_len < 0) || (cnt > MAX_IE_SZ)) {
+ dump_stack();
+ return NULL;
+ }
+ if ((eid == _VENDOR_SPECIFIC_IE_) && (_rtw_memcmp(&in_ie[cnt+2], p2p_oui, 4) == true)) {
+ p2p_ie_ptr = in_ie + cnt;
+
+ if (p2p_ie != NULL)
+ memcpy(p2p_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
+ if (p2p_ielen != NULL)
+ *p2p_ielen = in_ie[cnt + 1] + 2;
+ return p2p_ie_ptr;
+ } else {
+ cnt += in_ie[cnt + 1] + 2; /* goto next */
+ }
+ }
+ return NULL;
+}
+
+/**
+ * rtw_get_p2p_attr - Search a specific P2P attribute from a given P2P IE
+ * @p2p_ie: Address of P2P IE to search
+ * @p2p_ielen: Length limit from p2p_ie
+ * @target_attr_id: The attribute ID of P2P attribute to search
+ * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will be copied to the buf starting from buf_attr
+ * @len_attr: If not NULL and the P2P attribute is found, will set to the length of the entire P2P attribute
+ *
+ * Returns: the address of the specific WPS attribute found, or NULL
+ */
+u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id , u8 *buf_attr, u32 *len_attr)
+{
+ u8 *attr_ptr = NULL;
+ u8 *target_attr_ptr = NULL;
+ u8 p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09};
+
+ if (len_attr)
+ *len_attr = 0;
+
+ if (!p2p_ie || (p2p_ie[0] != _VENDOR_SPECIFIC_IE_) ||
+ (_rtw_memcmp(p2p_ie + 2, p2p_oui , 4) != true))
+ return attr_ptr;
+
+ /* 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */
+ attr_ptr = p2p_ie + 6; /* goto first attr */
+
+ while (attr_ptr - p2p_ie < p2p_ielen) {
+ /* 3 = 1(Attribute ID) + 2(Length) */
+ u8 attr_id = *attr_ptr;
+ u16 attr_data_len = RTW_GET_LE16(attr_ptr + 1);
+ u16 attr_len = attr_data_len + 3;
+
+ if (attr_id == target_attr_id) {
+ target_attr_ptr = attr_ptr;
+
+ if (buf_attr)
+ memcpy(buf_attr, attr_ptr, attr_len);
+ if (len_attr)
+ *len_attr = attr_len;
+ break;
+ } else {
+ attr_ptr += attr_len; /* goto next */
+ }
+ }
+ return target_attr_ptr;
+}
+
+/**
+ * rtw_get_p2p_attr_content - Search a specific P2P attribute content from a given P2P IE
+ * @p2p_ie: Address of P2P IE to search
+ * @p2p_ielen: Length limit from p2p_ie
+ * @target_attr_id: The attribute ID of P2P attribute to search
+ * @buf_content: If not NULL and the P2P attribute is found, P2P attribute content will be copied to the buf starting from buf_content
+ * @len_content: If not NULL and the P2P attribute is found, will set to the length of the P2P attribute content
+ *
+ * Returns: the address of the specific P2P attribute content found, or NULL
+ */
+u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id , u8 *buf_content, uint *len_content)
+{
+ u8 *attr_ptr;
+ u32 attr_len;
+
+ if (len_content)
+ *len_content = 0;
+
+ attr_ptr = rtw_get_p2p_attr(p2p_ie, p2p_ielen, target_attr_id, NULL, &attr_len);
+
+ if (attr_ptr && attr_len) {
+ if (buf_content)
+ memcpy(buf_content, attr_ptr+3, attr_len-3);
+
+ if (len_content)
+ *len_content = attr_len-3;
+
+ return attr_ptr+3;
+ }
+
+ return NULL;
+}
+
+u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr)
+{
+ u32 a_len;
+
+ *pbuf = attr_id;
+
+ /* u16*)(pbuf + 1) = cpu_to_le16(attr_len); */
+ RTW_PUT_LE16(pbuf + 1, attr_len);
+
+ if (pdata_attr)
+ memcpy(pbuf + 3, pdata_attr, attr_len);
+
+ a_len = attr_len + 3;
+
+ return a_len;
+}
+
+static uint rtw_p2p_attr_remove(u8 *ie, uint ielen_ori, u8 attr_id)
+{
+ u8 *target_attr;
+ u32 target_attr_len;
+ uint ielen = ielen_ori;
+
+ while (1) {
+ target_attr = rtw_get_p2p_attr(ie, ielen, attr_id, NULL, &target_attr_len);
+ if (target_attr && target_attr_len) {
+ u8 *next_attr = target_attr+target_attr_len;
+ uint remain_len = ielen-(next_attr-ie);
+
+ _rtw_memset(target_attr, 0, target_attr_len);
+ memcpy(target_attr, next_attr, remain_len);
+ _rtw_memset(target_attr+remain_len, 0, target_attr_len);
+ *(ie+1) -= target_attr_len;
+ ielen -= target_attr_len;
+ } else {
+ break;
+ }
+ }
+ return ielen;
+}
+
+void rtw_wlan_bssid_ex_remove_p2p_attr(struct wlan_bssid_ex *bss_ex, u8 attr_id)
+{
+ u8 *p2p_ie;
+ uint p2p_ielen, p2p_ielen_ori;
+
+ p2p_ie = rtw_get_p2p_ie(bss_ex->IEs+_FIXED_IE_LENGTH_, bss_ex->IELength-_FIXED_IE_LENGTH_, NULL, &p2p_ielen_ori);
+ if (p2p_ie) {
+ p2p_ielen = rtw_p2p_attr_remove(p2p_ie, p2p_ielen_ori, attr_id);
+ if (p2p_ielen != p2p_ielen_ori) {
+ u8 *next_ie_ori = p2p_ie+p2p_ielen_ori;
+ u8 *next_ie = p2p_ie+p2p_ielen;
+ uint remain_len = bss_ex->IELength-(next_ie_ori-bss_ex->IEs);
+
+ memcpy(next_ie, next_ie_ori, remain_len);
+ _rtw_memset(next_ie+remain_len, 0, p2p_ielen_ori-p2p_ielen);
+ bss_ex->IELength -= p2p_ielen_ori-p2p_ielen;
+ }
+ }
+}
+
+#endif /* CONFIG_88EU_P2P */
+
+/* Baron adds to avoid FreeBSD warning */
+int ieee80211_is_empty_essid(const char *essid, int essid_len)
+{
+ /* Single white space is for Linksys APs */
+ if (essid_len == 1 && essid[0] == ' ')
+ return 1;
+
+ /* Otherwise, if the entire essid is 0, we assume it is hidden */
+ while (essid_len) {
+ essid_len--;
+ if (essid[essid_len] != '\0')
+ return 0;
+ }
+
+ return 1;
+}
+
+int ieee80211_get_hdrlen(u16 fc)
+{
+ int hdrlen = 24;
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case RTW_IEEE80211_FTYPE_DATA:
+ if (fc & RTW_IEEE80211_STYPE_QOS_DATA)
+ hdrlen += 2;
+ if ((fc & RTW_IEEE80211_FCTL_FROMDS) && (fc & RTW_IEEE80211_FCTL_TODS))
+ hdrlen += 6; /* Addr4 */
+ break;
+ case RTW_IEEE80211_FTYPE_CTL:
+ switch (WLAN_FC_GET_STYPE(fc)) {
+ case RTW_IEEE80211_STYPE_CTS:
+ case RTW_IEEE80211_STYPE_ACK:
+ hdrlen = 10;
+ break;
+ default:
+ hdrlen = 16;
+ break;
+ }
+ break;
+ }
+
+ return hdrlen;
+}
+
+static int rtw_get_cipher_info(struct wlan_network *pnetwork)
+{
+ u32 wpa_ielen;
+ unsigned char *pbuf;
+ int group_cipher = 0, pairwise_cipher = 0, is8021x = 0;
+ int ret = _FAIL;
+ pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
+
+ if (pbuf && (wpa_ielen > 0)) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen));
+ if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) {
+ pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
+ pnetwork->BcnInfo.group_cipher = group_cipher;
+ pnetwork->BcnInfo.is_8021x = is8021x;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d, is_8021x is %d",
+ __func__, pnetwork->BcnInfo.pairwise_cipher, pnetwork->BcnInfo.is_8021x));
+ ret = _SUCCESS;
+ }
+ } else {
+ pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
+
+ if (pbuf && (wpa_ielen > 0)) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE\n"));
+ if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE OK!!!\n"));
+ pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
+ pnetwork->BcnInfo.group_cipher = group_cipher;
+ pnetwork->BcnInfo.is_8021x = is8021x;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d,"
+ "pnetwork->group_cipher is %d, is_8021x is %d", __func__, pnetwork->BcnInfo.pairwise_cipher,
+ pnetwork->BcnInfo.group_cipher, pnetwork->BcnInfo.is_8021x));
+ ret = _SUCCESS;
+ }
+ }
+ }
+
+ return ret;
+}
+
+void rtw_get_bcn_info(struct wlan_network *pnetwork)
+{
+ unsigned short cap = 0;
+ u8 bencrypt = 0;
+ __le16 le_tmp;
+ u16 wpa_len = 0, rsn_len = 0;
+ struct HT_info_element *pht_info = NULL;
+ struct rtw_ieee80211_ht_cap *pht_cap = NULL;
+ unsigned int len;
+ unsigned char *p;
+
+ memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);
+ cap = le16_to_cpu(le_tmp);
+ if (cap & WLAN_CAPABILITY_PRIVACY) {
+ bencrypt = 1;
+ pnetwork->network.Privacy = 1;
+ } else {
+ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS;
+ }
+ rtw_get_sec_ie(pnetwork->network.IEs , pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len);
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
+
+ if (rsn_len > 0) {
+ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2;
+ } else if (wpa_len > 0) {
+ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA;
+ } else {
+ if (bencrypt)
+ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP;
+ }
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n",
+ pnetwork->BcnInfo.encryp_protocol));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n",
+ pnetwork->BcnInfo.encryp_protocol));
+ rtw_get_cipher_info(pnetwork);
+
+ /* get bwmode and ch_offset */
+ /* parsing HT_CAP_IE */
+ p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_);
+ if (p && len > 0) {
+ pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2);
+ pnetwork->BcnInfo.ht_cap_info = pht_cap->cap_info;
+ } else {
+ pnetwork->BcnInfo.ht_cap_info = 0;
+ }
+ /* parsing HT_INFO_IE */
+ p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_);
+ if (p && len > 0) {
+ pht_info = (struct HT_info_element *)(p + 2);
+ pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0];
+ } else {
+ pnetwork->BcnInfo.ht_info_infos_0 = 0;
+ }
+}
+
+/* show MCS rate, unit: 100Kbps */
+u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char *MCS_rate)
+{
+ u16 max_rate = 0;
+
+ if (rf_type == RF_1T1R) {
+ if (MCS_rate[0] & BIT(7))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650);
+ else if (MCS_rate[0] & BIT(6))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585);
+ else if (MCS_rate[0] & BIT(5))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
+ else if (MCS_rate[0] & BIT(4))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
+ else if (MCS_rate[0] & BIT(3))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
+ else if (MCS_rate[0] & BIT(2))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195);
+ else if (MCS_rate[0] & BIT(1))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
+ else if (MCS_rate[0] & BIT(0))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65);
+ } else {
+ if (MCS_rate[1]) {
+ if (MCS_rate[1] & BIT(7))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 3000 : 2700) : ((short_GI_20) ? 1444 : 1300);
+ else if (MCS_rate[1] & BIT(6))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 2700 : 2430) : ((short_GI_20) ? 1300 : 1170);
+ else if (MCS_rate[1] & BIT(5))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 2400 : 2160) : ((short_GI_20) ? 1156 : 1040);
+ else if (MCS_rate[1] & BIT(4))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1800 : 1620) : ((short_GI_20) ? 867 : 780);
+ else if (MCS_rate[1] & BIT(3))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
+ else if (MCS_rate[1] & BIT(2))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
+ else if (MCS_rate[1] & BIT(1))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
+ else if (MCS_rate[1] & BIT(0))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
+ } else {
+ if (MCS_rate[0] & BIT(7))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650);
+ else if (MCS_rate[0] & BIT(6))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585);
+ else if (MCS_rate[0] & BIT(5))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
+ else if (MCS_rate[0] & BIT(4))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
+ else if (MCS_rate[0] & BIT(3))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
+ else if (MCS_rate[0] & BIT(2))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195);
+ else if (MCS_rate[0] & BIT(1))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
+ else if (MCS_rate[0] & BIT(0))
+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65);
+ }
+ }
+ return max_rate;
+}
+
+int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *action)
+{
+ const u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr);
+ u16 fc;
+ u8 c, a = 0;
+
+ fc = le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)frame)->frame_ctl);
+
+ if ((fc & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)) !=
+ (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION))
+ return false;
+
+ c = frame_body[0];
+
+ switch (c) {
+ case RTW_WLAN_CATEGORY_P2P: /* vendor-specific */
+ break;
+ default:
+ a = frame_body[1];
+ }
+
+ if (category)
+ *category = c;
+ if (action)
+ *action = a;
+
+ return true;
+}
+
+static const char *_action_public_str[] = {
+ "ACT_PUB_BSSCOEXIST",
+ "ACT_PUB_DSE_ENABLE",
+ "ACT_PUB_DSE_DEENABLE",
+ "ACT_PUB_DSE_REG_LOCATION",
+ "ACT_PUB_EXT_CHL_SWITCH",
+ "ACT_PUB_DSE_MSR_REQ",
+ "ACT_PUB_DSE_MSR_RPRT",
+ "ACT_PUB_MP",
+ "ACT_PUB_DSE_PWR_CONSTRAINT",
+ "ACT_PUB_VENDOR",
+ "ACT_PUB_GAS_INITIAL_REQ",
+ "ACT_PUB_GAS_INITIAL_RSP",
+ "ACT_PUB_GAS_COMEBACK_REQ",
+ "ACT_PUB_GAS_COMEBACK_RSP",
+ "ACT_PUB_TDLS_DISCOVERY_RSP",
+ "ACT_PUB_LOCATION_TRACK",
+ "ACT_PUB_RSVD",
+};
+
+const char *action_public_str(u8 action)
+{
+ action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action;
+ return _action_public_str[action];
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_io.c b/drivers/staging/rtl8188eu/core/rtw_io.c
new file mode 100644
index 00000000000..10c9c6560b2
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_io.c
@@ -0,0 +1,329 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+/*
+
+The purpose of rtw_io.c
+
+a. provides the API
+
+b. provides the protocol engine
+
+c. provides the software interface between caller and the hardware interface
+
+
+Compiler Flag Option:
+
+USB:
+ a. USE_ASYNC_IRP: Both sync/async operations are provided.
+
+Only sync read/rtw_write_mem operations are provided.
+
+jackson@realtek.com.tw
+
+*/
+
+#define _RTW_IO_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_io.h>
+#include <osdep_intf.h>
+#include <usb_ops.h>
+
+#define rtw_le16_to_cpu(val) le16_to_cpu(val)
+#define rtw_le32_to_cpu(val) le32_to_cpu(val)
+#define rtw_cpu_to_le16(val) cpu_to_le16(val)
+#define rtw_cpu_to_le32(val) cpu_to_le32(val)
+
+
+u8 _rtw_read8(struct adapter *adapter, u32 addr)
+{
+ u8 r_val;
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+ u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr);
+
+ _func_enter_;
+ _read8 = pintfhdl->io_ops._read8;
+ r_val = _read8(pintfhdl, addr);
+ _func_exit_;
+ return r_val;
+}
+
+u16 _rtw_read16(struct adapter *adapter, u32 addr)
+{
+ u16 r_val;
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+ u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr);
+_func_enter_;
+ _read16 = pintfhdl->io_ops._read16;
+
+ r_val = _read16(pintfhdl, addr);
+_func_exit_;
+ return r_val;
+}
+
+u32 _rtw_read32(struct adapter *adapter, u32 addr)
+{
+ u32 r_val;
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+ u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr);
+_func_enter_;
+ _read32 = pintfhdl->io_ops._read32;
+
+ r_val = _read32(pintfhdl, addr);
+_func_exit_;
+ return r_val;
+}
+
+int _rtw_write8(struct adapter *adapter, u32 addr, u8 val)
+{
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+ int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
+ int ret;
+ _func_enter_;
+ _write8 = pintfhdl->io_ops._write8;
+
+ ret = _write8(pintfhdl, addr, val);
+ _func_exit_;
+
+ return RTW_STATUS_CODE(ret);
+}
+
+int _rtw_write16(struct adapter *adapter, u32 addr, u16 val)
+{
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+ int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
+ int ret;
+ _func_enter_;
+ _write16 = pintfhdl->io_ops._write16;
+
+ ret = _write16(pintfhdl, addr, val);
+ _func_exit_;
+
+ return RTW_STATUS_CODE(ret);
+}
+int _rtw_write32(struct adapter *adapter, u32 addr, u32 val)
+{
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+ int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
+ int ret;
+ _func_enter_;
+ _write32 = pintfhdl->io_ops._write32;
+
+ ret = _write32(pintfhdl, addr, val);
+ _func_exit_;
+
+ return RTW_STATUS_CODE(ret);
+}
+
+int _rtw_writeN(struct adapter *adapter, u32 addr , u32 length , u8 *pdata)
+{
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = (struct intf_hdl *)(&(pio_priv->intf));
+ int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata);
+ int ret;
+ _func_enter_;
+ _writeN = pintfhdl->io_ops._writeN;
+
+ ret = _writeN(pintfhdl, addr, length, pdata);
+ _func_exit_;
+
+ return RTW_STATUS_CODE(ret);
+}
+int _rtw_write8_async(struct adapter *adapter, u32 addr, u8 val)
+{
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+ int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
+ int ret;
+ _func_enter_;
+ _write8_async = pintfhdl->io_ops._write8_async;
+
+ ret = _write8_async(pintfhdl, addr, val);
+ _func_exit_;
+
+ return RTW_STATUS_CODE(ret);
+}
+
+int _rtw_write16_async(struct adapter *adapter, u32 addr, u16 val)
+{
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+ int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
+ int ret;
+
+_func_enter_;
+ _write16_async = pintfhdl->io_ops._write16_async;
+ ret = _write16_async(pintfhdl, addr, val);
+_func_exit_;
+
+ return RTW_STATUS_CODE(ret);
+}
+
+int _rtw_write32_async(struct adapter *adapter, u32 addr, u32 val)
+{
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+ int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
+ int ret;
+
+_func_enter_;
+ _write32_async = pintfhdl->io_ops._write32_async;
+ ret = _write32_async(pintfhdl, addr, val);
+_func_exit_;
+
+ return RTW_STATUS_CODE(ret);
+}
+
+void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+ void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+
+ _func_enter_;
+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) {
+ RT_TRACE(_module_rtl871x_io_c_, _drv_info_,
+ ("rtw_read_mem:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
+ adapter->bDriverStopped, adapter->bSurpriseRemoved));
+ return;
+ }
+ _read_mem = pintfhdl->io_ops._read_mem;
+ _read_mem(pintfhdl, addr, cnt, pmem);
+ _func_exit_;
+}
+
+void _rtw_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+ void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+
+ _func_enter_;
+
+ _write_mem = pintfhdl->io_ops._write_mem;
+
+ _write_mem(pintfhdl, addr, cnt, pmem);
+
+ _func_exit_;
+}
+
+void _rtw_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+
+ _func_enter_;
+
+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) {
+ RT_TRACE(_module_rtl871x_io_c_, _drv_info_,
+ ("rtw_read_port:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
+ adapter->bDriverStopped, adapter->bSurpriseRemoved));
+ return;
+ }
+
+ _read_port = pintfhdl->io_ops._read_port;
+
+ _read_port(pintfhdl, addr, cnt, pmem);
+
+ _func_exit_;
+}
+
+void _rtw_read_port_cancel(struct adapter *adapter)
+{
+ void (*_read_port_cancel)(struct intf_hdl *pintfhdl);
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+
+ _read_port_cancel = pintfhdl->io_ops._read_port_cancel;
+
+ if (_read_port_cancel)
+ _read_port_cancel(pintfhdl);
+}
+
+u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+ u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+ u32 ret = _SUCCESS;
+
+ _func_enter_;
+
+ _write_port = pintfhdl->io_ops._write_port;
+
+ ret = _write_port(pintfhdl, addr, cnt, pmem);
+
+ _func_exit_;
+
+ return ret;
+}
+
+u32 _rtw_write_port_and_wait(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem, int timeout_ms)
+{
+ int ret = _SUCCESS;
+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pmem;
+ struct submit_ctx sctx;
+
+ rtw_sctx_init(&sctx, timeout_ms);
+ pxmitbuf->sctx = &sctx;
+
+ ret = _rtw_write_port(adapter, addr, cnt, pmem);
+
+ if (ret == _SUCCESS)
+ ret = rtw_sctx_wait(&sctx);
+
+ return ret;
+}
+
+void _rtw_write_port_cancel(struct adapter *adapter)
+{
+ void (*_write_port_cancel)(struct intf_hdl *pintfhdl);
+ struct io_priv *pio_priv = &adapter->iopriv;
+ struct intf_hdl *pintfhdl = &(pio_priv->intf);
+
+ _write_port_cancel = pintfhdl->io_ops._write_port_cancel;
+
+ if (_write_port_cancel)
+ _write_port_cancel(pintfhdl);
+}
+
+int rtw_init_io_priv(struct adapter *padapter, void (*set_intf_ops)(struct _io_ops *pops))
+{
+ struct io_priv *piopriv = &padapter->iopriv;
+ struct intf_hdl *pintf = &piopriv->intf;
+
+ if (set_intf_ops == NULL)
+ return _FAIL;
+
+ piopriv->padapter = padapter;
+ pintf->padapter = padapter;
+ pintf->pintf_dev = adapter_to_dvobj(padapter);
+
+ set_intf_ops(&pintf->io_ops);
+
+ return _SUCCESS;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
new file mode 100644
index 00000000000..193f641bd0d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
@@ -0,0 +1,1169 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_IOCTL_SET_C_
+
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_ioctl_set.h>
+#include <hal_intf.h>
+
+#include <usb_osintf.h>
+#include <usb_ops.h>
+
+extern void indicate_wx_scan_complete_event(struct adapter *padapter);
+
+#define IS_MAC_ADDRESS_BROADCAST(addr) \
+(\
+ ((addr[0] == 0xff) && (addr[1] == 0xff) && \
+ (addr[2] == 0xff) && (addr[3] == 0xff) && \
+ (addr[4] == 0xff) && (addr[5] == 0xff)) ? true : false \
+)
+
+u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid)
+{
+ u8 i;
+ u8 ret = true;
+
+_func_enter_;
+
+ if (ssid->SsidLength > 32) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid length >32\n"));
+ ret = false;
+ goto exit;
+ }
+
+ for (i = 0; i < ssid->SsidLength; i++) {
+ /* wifi, printable ascii code must be supported */
+ if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid has nonprintabl ascii\n"));
+ ret = false;
+ break;
+ }
+ }
+
+exit:
+
+_func_exit_;
+
+ return ret;
+}
+
+u8 rtw_do_join(struct adapter *padapter)
+{
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ u8 *pibss = NULL;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ u8 ret = _SUCCESS;
+
+_func_enter_;
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("\n rtw_do_join: phead = %p; plist = %p\n\n\n", phead, plist));
+
+ pmlmepriv->cur_network.join_res = -2;
+
+ set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+
+ pmlmepriv->pscanned = plist;
+
+ pmlmepriv->to_join = true;
+
+ if (_rtw_queue_empty(queue)) {
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+ /* when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty */
+ /* we try to issue sitesurvey firstly */
+
+ if (!pmlmepriv->LinkDetectInfo.bBusyTraffic ||
+ pmlmepriv->to_roaming > 0) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_do_join(): site survey if scanned_queue is empty\n."));
+ /* submit site_survey_cmd */
+ ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
+ if (_SUCCESS != ret) {
+ pmlmepriv->to_join = false;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_do_join(): site survey return error\n."));
+ }
+ } else {
+ pmlmepriv->to_join = false;
+ ret = _FAIL;
+ }
+
+ goto exit;
+ } else {
+ int select_ret;
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+ select_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
+ if (select_ret == _SUCCESS) {
+ pmlmepriv->to_join = false;
+ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
+ } else {
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) {
+ /* submit createbss_cmd to change to a ADHOC_MASTER */
+
+ /* pmlmepriv->lock has been acquired by caller... */
+ struct wlan_bssid_ex *pdev_network = &(padapter->registrypriv.dev_network);
+
+ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
+
+ pibss = padapter->registrypriv.dev_network.MacAddress;
+
+ _rtw_memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
+ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid));
+
+ rtw_update_registrypriv_dev_network(padapter);
+
+ rtw_generate_random_ibss(pibss);
+
+ if (rtw_createbss_cmd(padapter) != _SUCCESS) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>do_goin: rtw_createbss_cmd status FAIL***\n "));
+ ret = false;
+ goto exit;
+ }
+ pmlmepriv->to_join = false;
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+ ("***Error => rtw_select_and_join_from_scanned_queue FAIL under STA_Mode***\n "));
+ } else {
+ /* can't associate ; reset under-linking */
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+ /* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */
+ /* we try to issue sitesurvey firstly */
+ if (!pmlmepriv->LinkDetectInfo.bBusyTraffic ||
+ pmlmepriv->to_roaming > 0) {
+ ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
+ if (_SUCCESS != ret) {
+ pmlmepriv->to_join = false;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("do_join(): site survey return error\n."));
+ }
+ } else {
+ ret = _FAIL;
+ pmlmepriv->to_join = false;
+ }
+ }
+ }
+ }
+
+exit:
+
+_func_exit_;
+
+ return ret;
+}
+
+u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid)
+{
+ unsigned long irqL;
+ u8 status = _SUCCESS;
+ u32 cur_time = 0;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+ DBG_88E_LEVEL(_drv_info_, "set bssid:%pM\n", bssid);
+
+ if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 &&
+ bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) ||
+ (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF &&
+ bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) {
+ status = _FAIL;
+ goto exit;
+ }
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+
+ DBG_88E("Set BSSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true)
+ goto handle_tkip_countermeasure;
+ else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
+ goto release_mlme_lock;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
+
+ if (_rtw_memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) {
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)
+ goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
+ } else {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set BSSID not the same bssid\n"));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid =%pM\n", (bssid)));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("cur_bssid =%pM\n", (pmlmepriv->cur_network.network.MacAddress)));
+
+ rtw_disassoc_cmd(padapter, 0, true);
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+ rtw_indicate_disconnect(padapter);
+
+ rtw_free_assoc_resources(padapter, 1);
+
+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
+ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+ }
+ }
+ }
+
+handle_tkip_countermeasure:
+ /* should we add something here...? */
+
+ if (padapter->securitypriv.btkip_countermeasure) {
+ cur_time = rtw_get_current_time();
+
+ if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) {
+ padapter->securitypriv.btkip_countermeasure = false;
+ padapter->securitypriv.btkip_countermeasure_time = 0;
+ } else {
+ status = _FAIL;
+ goto release_mlme_lock;
+ }
+ }
+
+ memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN);
+ pmlmepriv->assoc_by_bssid = true;
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
+ pmlmepriv->to_join = true;
+ else
+ status = rtw_do_join(padapter);
+
+release_mlme_lock:
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+exit:
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("rtw_set_802_11_bssid: status=%d\n", status));
+
+_func_exit_;
+
+ return status;
+}
+
+u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
+{
+ unsigned long irqL;
+ u8 status = _SUCCESS;
+ u32 cur_time = 0;
+
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_network *pnetwork = &pmlmepriv->cur_network;
+
+_func_enter_;
+
+ DBG_88E_LEVEL(_drv_info_, "set ssid [%s] fw_state=0x%08x\n",
+ ssid->Ssid, get_fwstate(pmlmepriv));
+
+ if (!padapter->hw_init_completed) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("set_ssid: hw_init_completed == false =>exit!!!\n"));
+ status = _FAIL;
+ goto exit;
+ }
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+ DBG_88E("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
+ goto handle_tkip_countermeasure;
+ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) {
+ goto release_mlme_lock;
+ }
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+ ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
+
+ if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) &&
+ (_rtw_memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength))) {
+ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("Set SSID is the same ssid, fw_state = 0x%08x\n",
+ get_fwstate(pmlmepriv)));
+
+ if (!rtw_is_same_ibss(padapter, pnetwork)) {
+ /* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */
+ rtw_disassoc_cmd(padapter, 0, true);
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+ rtw_indicate_disconnect(padapter);
+
+ rtw_free_assoc_resources(padapter, 1);
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
+ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+ }
+ } else {
+ goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
+ }
+ } else {
+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1);
+ }
+ } else {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set SSID not the same ssid\n"));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_ssid =[%s] len = 0x%x\n", ssid->Ssid, (unsigned int)ssid->SsidLength));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("assoc_ssid =[%s] len = 0x%x\n", pmlmepriv->assoc_ssid.Ssid, (unsigned int)pmlmepriv->assoc_ssid.SsidLength));
+
+ rtw_disassoc_cmd(padapter, 0, true);
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+ rtw_indicate_disconnect(padapter);
+
+ rtw_free_assoc_resources(padapter, 1);
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
+ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+ }
+ }
+ }
+
+handle_tkip_countermeasure:
+
+ if (padapter->securitypriv.btkip_countermeasure) {
+ cur_time = rtw_get_current_time();
+
+ if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) {
+ padapter->securitypriv.btkip_countermeasure = false;
+ padapter->securitypriv.btkip_countermeasure_time = 0;
+ } else {
+ status = _FAIL;
+ goto release_mlme_lock;
+ }
+ }
+
+ memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid));
+ pmlmepriv->assoc_by_bssid = false;
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
+ pmlmepriv->to_join = true;
+ } else {
+ status = rtw_do_join(padapter);
+ }
+
+release_mlme_lock:
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+exit:
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("-rtw_set_802_11_ssid: status =%d\n", status));
+_func_exit_;
+ return status;
+}
+
+u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter,
+ enum ndis_802_11_network_infra networktype)
+{
+ unsigned long irqL;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_network *cur_network = &pmlmepriv->cur_network;
+ enum ndis_802_11_network_infra *pold_state = &(cur_network->network.InfrastructureMode);
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_,
+ ("+rtw_set_802_11_infrastructure_mode: old =%d new =%d fw_state = 0x%08x\n",
+ *pold_state, networktype, get_fwstate(pmlmepriv)));
+
+ if (*pold_state != networktype) {
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, (" change mode!"));
+ /* DBG_88E("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */
+
+ if (*pold_state == Ndis802_11APMode) {
+ /* change to other mode from Ndis802_11APMode */
+ cur_network->join_res = -1;
+
+#ifdef CONFIG_88EU_AP_MODE
+ stop_ap_mode(padapter);
+#endif
+ }
+
+ if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
+ (*pold_state == Ndis802_11IBSS))
+ rtw_disassoc_cmd(padapter, 0, true);
+
+ if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
+ rtw_free_assoc_resources(padapter, 1);
+
+ if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) {
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+ rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have chked whether issue dis-assoc_cmd or not */
+ }
+
+ *pold_state = networktype;
+
+ _clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE);
+
+ switch (networktype) {
+ case Ndis802_11IBSS:
+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+ break;
+ case Ndis802_11Infrastructure:
+ set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+ break;
+ case Ndis802_11APMode:
+ set_fwstate(pmlmepriv, WIFI_AP_STATE);
+#ifdef CONFIG_88EU_AP_MODE
+ start_ap_mode(padapter);
+#endif
+ break;
+ case Ndis802_11AutoUnknown:
+ case Ndis802_11InfrastructureMax:
+ break;
+ }
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+ }
+
+_func_exit_;
+
+ return true;
+}
+
+
+u8 rtw_set_802_11_disassociate(struct adapter *padapter)
+{
+ unsigned long irqL;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+ ("MgntActrtw_set_802_11_disassociate: rtw_indicate_disconnect\n"));
+
+ rtw_disassoc_cmd(padapter, 0, true);
+ rtw_indicate_disconnect(padapter);
+ rtw_free_assoc_resources(padapter, 1);
+ rtw_pwr_wakeup(padapter);
+ }
+
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+_func_exit_;
+
+ return true;
+}
+
+u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num)
+{
+ unsigned long irqL;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ u8 res = true;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+rtw_set_802_11_bssid_list_scan(), fw_state =%x\n", get_fwstate(pmlmepriv)));
+
+ if (padapter == NULL) {
+ res = false;
+ goto exit;
+ }
+ if (!padapter->hw_init_completed) {
+ res = false;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n === rtw_set_802_11_bssid_list_scan:hw_init_completed == false ===\n"));
+ goto exit;
+ }
+
+ if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) ||
+ (pmlmepriv->LinkDetectInfo.bBusyTraffic)) {
+ /* Scan or linking is in progress, do nothing. */
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_set_802_11_bssid_list_scan fail since fw_state = %x\n", get_fwstate(pmlmepriv)));
+ res = true;
+
+ if (check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)) == true) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n\n"));
+ } else {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###pmlmepriv->sitesurveyctrl.traffic_busy == true\n\n"));
+ }
+ } else {
+ if (rtw_is_scan_deny(padapter)) {
+ DBG_88E(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter));
+ indicate_wx_scan_complete_event(padapter);
+ return _SUCCESS;
+ }
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+ res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0);
+
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+ }
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11_auth_mode authmode)
+{
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ int res;
+ u8 ret;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_802_11_auth.mode(): mode =%x\n", authmode));
+
+ psecuritypriv->ndisauthtype = authmode;
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+ ("rtw_set_802_11_authentication_mode:psecuritypriv->ndisauthtype=%d",
+ psecuritypriv->ndisauthtype));
+
+ if (psecuritypriv->ndisauthtype > 3)
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+ res = rtw_set_auth(padapter, psecuritypriv);
+
+ if (res == _SUCCESS)
+ ret = true;
+ else
+ ret = false;
+
+_func_exit_;
+
+ return ret;
+}
+
+u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
+{
+ int keyid, res;
+ struct security_priv *psecuritypriv = &(padapter->securitypriv);
+ u8 ret = _SUCCESS;
+
+_func_enter_;
+
+ keyid = wep->KeyIndex & 0x3fffffff;
+
+ if (keyid >= 4) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("MgntActrtw_set_802_11_add_wep:keyid>4 =>fail\n"));
+ ret = false;
+ goto exit;
+ }
+
+ switch (wep->KeyLength) {
+ case 5:
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength = 5\n"));
+ break;
+ case 13:
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength = 13\n"));
+ break;
+ default:
+ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength!= 5 or 13\n"));
+ break;
+ }
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+ ("rtw_set_802_11_add_wep:befor memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x keyid =%x\n",
+ wep->KeyLength, wep->KeyIndex, keyid));
+
+ memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]), &(wep->KeyMaterial), wep->KeyLength);
+
+ psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength;
+
+ psecuritypriv->dot11PrivacyKeyIndex = keyid;
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+ ("rtw_set_802_11_add_wep:security key material : %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
+ psecuritypriv->dot11DefKey[keyid].skey[0],
+ psecuritypriv->dot11DefKey[keyid].skey[1],
+ psecuritypriv->dot11DefKey[keyid].skey[2],
+ psecuritypriv->dot11DefKey[keyid].skey[3],
+ psecuritypriv->dot11DefKey[keyid].skey[4],
+ psecuritypriv->dot11DefKey[keyid].skey[5],
+ psecuritypriv->dot11DefKey[keyid].skey[6],
+ psecuritypriv->dot11DefKey[keyid].skey[7],
+ psecuritypriv->dot11DefKey[keyid].skey[8],
+ psecuritypriv->dot11DefKey[keyid].skey[9],
+ psecuritypriv->dot11DefKey[keyid].skey[10],
+ psecuritypriv->dot11DefKey[keyid].skey[11],
+ psecuritypriv->dot11DefKey[keyid].skey[12]));
+
+ res = rtw_set_key(padapter, psecuritypriv, keyid, 1);
+
+ if (res == _FAIL)
+ ret = false;
+exit:
+_func_exit_;
+ return ret;
+}
+
+u8 rtw_set_802_11_remove_wep(struct adapter *padapter, u32 keyindex)
+{
+ u8 ret = _SUCCESS;
+
+_func_enter_;
+ if (keyindex >= 0x80000000 || padapter == NULL) {
+ ret = false;
+ goto exit;
+ } else {
+ int res;
+ struct security_priv *psecuritypriv = &(padapter->securitypriv);
+ if (keyindex < 4) {
+ _rtw_memset(&psecuritypriv->dot11DefKey[keyindex], 0, 16);
+ res = rtw_set_key(padapter, psecuritypriv, keyindex, 0);
+ psecuritypriv->dot11DefKeylen[keyindex] = 0;
+ if (res == _FAIL)
+ ret = _FAIL;
+ } else {
+ ret = _FAIL;
+ }
+ }
+exit:
+
+_func_exit_;
+ return ret;
+}
+
+u8 rtw_set_802_11_add_key(struct adapter *padapter, struct ndis_802_11_key *key)
+{
+ uint encryptionalgo;
+ u8 *pbssid;
+ struct sta_info *stainfo;
+ u8 bgroup = false;
+ u8 bgrouptkey = false;/* can be removed later */
+ u8 ret = _SUCCESS;
+
+_func_enter_;
+
+ if (((key->KeyIndex & 0x80000000) == 0) && ((key->KeyIndex & 0x40000000) > 0)) {
+ /* It is invalid to clear bit 31 and set bit 30. If the miniport driver encounters this combination, */
+ /* it must fail the request and return NDIS_STATUS_INVALID_DATA. */
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+ ("rtw_set_802_11_add_key: ((key->KeyIndex & 0x80000000)==0)[=%d]",
+ (int)(key->KeyIndex & 0x80000000) == 0));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+ ("rtw_set_802_11_add_key:((key->KeyIndex & 0x40000000)>0)[=%d]",
+ (int)(key->KeyIndex & 0x40000000) > 0));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+ ("rtw_set_802_11_add_key: key->KeyIndex=%d\n",
+ (int)key->KeyIndex));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ if (key->KeyIndex & 0x40000000) {
+ /* Pairwise key */
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ Pairwise key +++++\n"));
+
+ pbssid = get_bssid(&padapter->mlmepriv);
+ stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid);
+
+ if ((stainfo != NULL) && (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("OID_802_11_ADD_KEY:(stainfo!=NULL)&&(Adapter->securitypriv.dot11AuthAlgrthm==dot11AuthAlgrthm_8021X)\n"));
+ encryptionalgo = stainfo->dot118021XPrivacy;
+ } else {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: stainfo == NULL)||(Adapter->securitypriv.dot11AuthAlgrthm!= dot11AuthAlgrthm_8021X)\n"));
+ encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm;
+ }
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("rtw_set_802_11_add_key: (encryptionalgo==%d)!\n",
+ encryptionalgo));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("rtw_set_802_11_add_key: (Adapter->securitypriv.dot11PrivacyAlgrthm==%d)!\n",
+ padapter->securitypriv.dot11PrivacyAlgrthm));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("rtw_set_802_11_add_key: (Adapter->securitypriv.dot11AuthAlgrthm==%d)!\n",
+ padapter->securitypriv.dot11AuthAlgrthm));
+
+ if ((stainfo != NULL))
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("rtw_set_802_11_add_key: (stainfo->dot118021XPrivacy==%d)!\n",
+ stainfo->dot118021XPrivacy));
+
+ if (key->KeyIndex & 0x000000FF) {
+ /* The key index is specified in the lower 8 bits by values of zero to 255. */
+ /* The key index should be set to zero for a Pairwise key, and the driver should fail with */
+ /* NDIS_STATUS_INVALID_DATA if the lower 8 bits is not zero */
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, (" key->KeyIndex & 0x000000FF.\n"));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* check BSSID */
+ if (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == true) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("MacAddr_isBcst(key->BSSID)\n"));
+ ret = false;
+ goto exit;
+ }
+
+ /* Check key length for TKIP. */
+ if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("TKIP KeyLength:0x%x != 32\n", key->KeyLength));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* Check key length for AES. */
+ if ((encryptionalgo == _AES_) && (key->KeyLength != 16)) {
+ /* For our supplicant, EAPPkt9x.vxd, cannot differentiate TKIP and AES case. */
+ if (key->KeyLength == 32) {
+ key->KeyLength = 16;
+ } else {
+ ret = _FAIL;
+ goto exit;
+ }
+ }
+
+ /* Check key length for WEP. For NDTEST, 2005.01.27, by rcnjko. */
+ if ((encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_) &&
+ (key->KeyLength != 5 && key->KeyLength != 13)) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("WEP KeyLength:0x%x != 5 or 13\n", key->KeyLength));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ bgroup = false;
+
+ /* Check the pairwise key. Added by Annie, 2005-07-06. */
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n"));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("[Pairwise Key set]\n"));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n"));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key index: 0x%8x(0x%8x)\n", key->KeyIndex, (key->KeyIndex&0x3)));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key Length: %d\n", key->KeyLength));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n"));
+
+ } else {
+ /* Group key - KeyIndex(BIT30 == 0) */
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ Group key +++++\n"));
+
+
+ /* when add wep key through add key and didn't assigned encryption type before */
+ if ((padapter->securitypriv.ndisauthtype <= 3) &&
+ (padapter->securitypriv.dot118021XGrpPrivacy == 0)) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("keylen =%d(Adapter->securitypriv.dot11PrivacyAlgrthm=%x )padapter->securitypriv.dot118021XGrpPrivacy(%x)\n",
+ key->KeyLength, padapter->securitypriv.dot11PrivacyAlgrthm,
+ padapter->securitypriv.dot118021XGrpPrivacy));
+ switch (key->KeyLength) {
+ case 5:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("Adapter->securitypriv.dot11PrivacyAlgrthm=%x key->KeyLength=%u\n",
+ padapter->securitypriv.dot11PrivacyAlgrthm, key->KeyLength));
+ break;
+ case 13:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("Adapter->securitypriv.dot11PrivacyAlgrthm=%x key->KeyLength=%u\n",
+ padapter->securitypriv.dot11PrivacyAlgrthm, key->KeyLength));
+ break;
+ default:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("Adapter->securitypriv.dot11PrivacyAlgrthm=%x key->KeyLength=%u\n",
+ padapter->securitypriv.dot11PrivacyAlgrthm, key->KeyLength));
+ break;
+ }
+
+ encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm;
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ (" Adapter->securitypriv.dot11PrivacyAlgrthm=%x\n",
+ padapter->securitypriv.dot11PrivacyAlgrthm));
+
+ } else {
+ encryptionalgo = padapter->securitypriv.dot118021XGrpPrivacy;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("(Adapter->securitypriv.dot11PrivacyAlgrthm=%x)encryptionalgo(%x)=padapter->securitypriv.dot118021XGrpPrivacy(%x)keylen=%d\n",
+ padapter->securitypriv.dot11PrivacyAlgrthm, encryptionalgo,
+ padapter->securitypriv.dot118021XGrpPrivacy, key->KeyLength));
+ }
+
+ if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE) == true) && (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == false)) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ (" IBSS but BSSID is not Broadcast Address.\n"));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* Check key length for TKIP */
+ if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) {
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ (" TKIP GTK KeyLength:%u != 32\n", key->KeyLength));
+ ret = _FAIL;
+ goto exit;
+ } else if (encryptionalgo == _AES_ && (key->KeyLength != 16 && key->KeyLength != 32)) {
+ /* Check key length for AES */
+ /* For NDTEST, we allow keylen = 32 in this case. 2005.01.27, by rcnjko. */
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("<=== SetInfo, OID_802_11_ADD_KEY: AES GTK KeyLength:%u != 16 or 32\n",
+ key->KeyLength));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* Change the key length for EAPPkt9x.vxd. Added by Annie, 2005-11-03. */
+ if ((encryptionalgo == _AES_) && (key->KeyLength == 32)) {
+ key->KeyLength = 16;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("AES key length changed: %u\n", key->KeyLength));
+ }
+
+ if (key->KeyIndex & 0x8000000) {/* error ??? 0x8000_0000 */
+ bgrouptkey = true;
+ }
+
+ if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE)) &&
+ (check_fwstate(&padapter->mlmepriv, _FW_LINKED)))
+ bgrouptkey = true;
+ bgroup = true;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n"));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("[Group Key set]\n"));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n")) ;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key index: 0x%8x(0x%8x)\n", key->KeyIndex, (key->KeyIndex&0x3)));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key Length: %d\n", key->KeyLength)) ;
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n"));
+ }
+
+ /* If WEP encryption algorithm, just call rtw_set_802_11_add_wep(). */
+ if ((padapter->securitypriv.dot11AuthAlgrthm != dot11AuthAlgrthm_8021X) &&
+ (encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_)) {
+ u32 keyindex;
+ u32 len = FIELD_OFFSET(struct ndis_802_11_key, KeyMaterial) + key->KeyLength;
+ struct ndis_802_11_wep *wep = &padapter->securitypriv.ndiswep;
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ WEP key +++++\n"));
+
+ wep->Length = len;
+ keyindex = key->KeyIndex&0x7fffffff;
+ wep->KeyIndex = keyindex ;
+ wep->KeyLength = key->KeyLength;
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY:Before memcpy\n"));
+
+ memcpy(wep->KeyMaterial, key->KeyMaterial, key->KeyLength);
+ memcpy(&(padapter->securitypriv.dot11DefKey[keyindex].skey[0]), key->KeyMaterial, key->KeyLength);
+
+ padapter->securitypriv.dot11DefKeylen[keyindex] = key->KeyLength;
+ padapter->securitypriv.dot11PrivacyKeyIndex = keyindex;
+
+ ret = rtw_set_802_11_add_wep(padapter, wep);
+ goto exit;
+ }
+ if (key->KeyIndex & 0x20000000) {
+ /* SetRSC */
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ SetRSC+++++\n"));
+ if (bgroup) {
+ unsigned long long keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL;
+ memcpy(&padapter->securitypriv.dot11Grprxpn, &keysrc, 8);
+ } else {
+ unsigned long long keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL;
+ memcpy(&padapter->securitypriv.dot11Grptxpn, &keysrc, 8);
+ }
+ }
+
+ /* Indicate this key idx is used for TX */
+ /* Save the key in KeyMaterial */
+ if (bgroup) { /* Group transmit key */
+ int res;
+
+ if (bgrouptkey)
+ padapter->securitypriv.dot118021XGrpKeyid = (u8)key->KeyIndex;
+ if ((key->KeyIndex&0x3) == 0) {
+ ret = _FAIL;
+ goto exit;
+ }
+ _rtw_memset(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
+ _rtw_memset(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
+ _rtw_memset(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
+
+ if ((key->KeyIndex & 0x10000000)) {
+ memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8);
+ memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8);
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("\n rtw_set_802_11_add_key:rx mic :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[0],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[1],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[2],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[3],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[4],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[5],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[6],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[7]));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n rtw_set_802_11_add_key:set Group mic key!!!!!!!!\n"));
+ } else {
+ memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8);
+ memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8);
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("\n rtw_set_802_11_add_key:rx mic :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[0],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[1],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[2],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[3],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[4],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[5],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[6],
+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[7]));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+ ("\n rtw_set_802_11_add_key:set Group mic key!!!!!!!!\n"));
+ }
+
+ /* set group key by index */
+ memcpy(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial, key->KeyLength);
+
+ key->KeyIndex = key->KeyIndex & 0x03;
+
+ padapter->securitypriv.binstallGrpkey = true;
+
+ padapter->securitypriv.bcheck_grpkey = false;
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("reset group key"));
+
+ res = rtw_set_key(padapter, &padapter->securitypriv, key->KeyIndex, 1);
+
+ if (res == _FAIL)
+ ret = _FAIL;
+
+ goto exit;
+
+ } else { /* Pairwise Key */
+ u8 res;
+
+ pbssid = get_bssid(&padapter->mlmepriv);
+ stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid);
+
+ if (stainfo != NULL) {
+ _rtw_memset(&stainfo->dot118021x_UncstKey, 0, 16);/* clear keybuffer */
+
+ memcpy(&stainfo->dot118021x_UncstKey, key->KeyMaterial, 16);
+
+ if (encryptionalgo == _TKIP_) {
+ padapter->securitypriv.busetkipkey = false;
+
+ /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */
+
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n========== _set_timer\n"));
+
+ /* if TKIP, save the Receive/Transmit MIC key in KeyMaterial[128-255] */
+ if ((key->KeyIndex & 0x10000000)) {
+ memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 16, 8);
+ memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 24, 8);
+
+ } else {
+ memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 24, 8);
+ memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 16, 8);
+ }
+ }
+
+
+ /* Set key to CAM through H2C command */
+ if (bgrouptkey) { /* never go to here */
+ res = rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, false);
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n rtw_set_802_11_add_key:rtw_setstakey_cmd(group)\n"));
+ } else {
+ res = rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, true);
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n rtw_set_802_11_add_key:rtw_setstakey_cmd(unicast)\n"));
+ }
+ if (!res)
+ ret = _FAIL;
+ }
+ }
+exit:
+
+_func_exit_;
+ return ret;
+}
+
+u8 rtw_set_802_11_remove_key(struct adapter *padapter, struct ndis_802_11_remove_key *key)
+{
+ u8 *pbssid;
+ struct sta_info *stainfo;
+ u8 bgroup = (key->KeyIndex & 0x4000000) > 0 ? false : true;
+ u8 keyIndex = (u8)key->KeyIndex & 0x03;
+ u8 ret = _SUCCESS;
+
+_func_enter_;
+
+ if ((key->KeyIndex & 0xbffffffc) > 0) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ if (bgroup) {
+ /* clear group key by index */
+
+ _rtw_memset(&padapter->securitypriv.dot118021XGrpKey[keyIndex], 0, 16);
+
+ /* \todo Send a H2C Command to Firmware for removing this Key in CAM Entry. */
+ } else {
+ pbssid = get_bssid(&padapter->mlmepriv);
+ stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid);
+ if (stainfo) {
+ /* clear key by BSSID */
+ _rtw_memset(&stainfo->dot118021x_UncstKey, 0, 16);
+
+ /* \todo Send a H2C Command to Firmware for disable this Key in CAM Entry. */
+ } else {
+ ret = _FAIL;
+ goto exit;
+ }
+ }
+exit:
+
+_func_exit_;
+ return ret;
+}
+
+/*
+* rtw_get_cur_max_rate -
+* @adapter: pointer to struct adapter structure
+*
+* Return 0 or 100Kbps
+*/
+u16 rtw_get_cur_max_rate(struct adapter *adapter)
+{
+ int i = 0;
+ u8 *p;
+ u16 rate = 0, max_rate = 0;
+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct registry_priv *pregistrypriv = &adapter->registrypriv;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
+ struct rtw_ieee80211_ht_cap *pht_capie;
+ u8 rf_type = 0;
+ u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0;
+ u16 mcs_rate = 0;
+ u32 ht_ielen = 0;
+
+ if (adapter->registrypriv.mp_mode == 1) {
+ if (check_fwstate(pmlmepriv, WIFI_MP_STATE))
+ return 0;
+ }
+
+ if ((!check_fwstate(pmlmepriv, _FW_LINKED)) &&
+ (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
+ return 0;
+
+ if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N|WIRELESS_11_5N)) {
+ p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12);
+ if (p && ht_ielen > 0) {
+ pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2);
+
+ memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
+
+ /* cur_bwmod is updated by beacon, pmlmeinfo is updated by association response */
+ bw_40MHz = (pmlmeext->cur_bwmode && (HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH & pmlmeinfo->HT_info.infos[0])) ? 1 : 0;
+
+ short_GI_20 = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & IEEE80211_HT_CAP_SGI_20) ? 1 : 0;
+ short_GI_40 = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & IEEE80211_HT_CAP_SGI_40) ? 1 : 0;
+
+ rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+ max_rate = rtw_mcs_rate(
+ rf_type,
+ bw_40MHz & (pregistrypriv->cbw40_enable),
+ short_GI_20,
+ short_GI_40,
+ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate
+ );
+ }
+ } else {
+ while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) {
+ rate = pcur_bss->SupportedRates[i]&0x7F;
+ if (rate > max_rate)
+ max_rate = rate;
+ i++;
+ }
+
+ max_rate = max_rate*10/2;
+ }
+
+ return max_rate;
+}
+
+/*
+* rtw_set_scan_mode -
+* @adapter: pointer to struct adapter structure
+* @scan_mode:
+*
+* Return _SUCCESS or _FAIL
+*/
+int rtw_set_scan_mode(struct adapter *adapter, enum rt_scan_type scan_mode)
+{
+ if (scan_mode != SCAN_ACTIVE && scan_mode != SCAN_PASSIVE)
+ return _FAIL;
+
+ adapter->mlmepriv.scan_mode = scan_mode;
+
+ return _SUCCESS;
+}
+
+/*
+* rtw_set_channel_plan -
+* @adapter: pointer to struct adapter structure
+* @channel_plan:
+*
+* Return _SUCCESS or _FAIL
+*/
+int rtw_set_channel_plan(struct adapter *adapter, u8 channel_plan)
+{
+ /* handle by cmd_thread to sync with scan operation */
+ return rtw_set_chplan_cmd(adapter, channel_plan, 1);
+}
+
+/*
+* rtw_set_country -
+* @adapter: pointer to struct adapter structure
+* @country_code: string of country code
+*
+* Return _SUCCESS or _FAIL
+*/
+int rtw_set_country(struct adapter *adapter, const char *country_code)
+{
+ int channel_plan = RT_CHANNEL_DOMAIN_WORLD_WIDE_5G;
+
+ DBG_88E("%s country_code:%s\n", __func__, country_code);
+
+ /* TODO: should have a table to match country code and RT_CHANNEL_DOMAIN */
+ /* TODO: should consider 2-character and 3-character country code */
+ if (0 == strcmp(country_code, "US"))
+ channel_plan = RT_CHANNEL_DOMAIN_FCC;
+ else if (0 == strcmp(country_code, "EU"))
+ channel_plan = RT_CHANNEL_DOMAIN_ETSI;
+ else if (0 == strcmp(country_code, "JP"))
+ channel_plan = RT_CHANNEL_DOMAIN_MKK;
+ else if (0 == strcmp(country_code, "CN"))
+ channel_plan = RT_CHANNEL_DOMAIN_CHINA;
+ else
+ DBG_88E("%s unknown country_code:%s\n", __func__, country_code);
+
+ return rtw_set_channel_plan(adapter, channel_plan);
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_iol.c b/drivers/staging/rtl8188eu/core/rtw_iol.c
new file mode 100644
index 00000000000..e6fdd32f9a3
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_iol.c
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#include<rtw_iol.h>
+
+struct xmit_frame *rtw_IOL_accquire_xmit_frame(struct adapter *adapter)
+{
+ struct xmit_frame *xmit_frame;
+ struct xmit_buf *xmitbuf;
+ struct pkt_attrib *pattrib;
+ struct xmit_priv *pxmitpriv = &(adapter->xmitpriv);
+
+ xmit_frame = rtw_alloc_xmitframe(pxmitpriv);
+ if (xmit_frame == NULL) {
+ DBG_88E("%s rtw_alloc_xmitframe return null\n", __func__);
+ goto exit;
+ }
+
+ xmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+ if (xmitbuf == NULL) {
+ DBG_88E("%s rtw_alloc_xmitbuf return null\n", __func__);
+ rtw_free_xmitframe(pxmitpriv, xmit_frame);
+ xmit_frame = NULL;
+ goto exit;
+ }
+
+ xmit_frame->frame_tag = MGNT_FRAMETAG;
+ xmit_frame->pxmitbuf = xmitbuf;
+ xmit_frame->buf_addr = xmitbuf->pbuf;
+ xmitbuf->priv_data = xmit_frame;
+
+ pattrib = &xmit_frame->attrib;
+ update_mgntframe_attrib(adapter, pattrib);
+ pattrib->qsel = 0x10;/* Beacon */
+ pattrib->subtype = WIFI_BEACON;
+ pattrib->pktlen = 0;
+ pattrib->last_txcmdsz = 0;
+exit:
+ return xmit_frame;
+}
+
+int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds, u32 cmd_len)
+{
+ struct pkt_attrib *pattrib = &xmit_frame->attrib;
+ u16 buf_offset;
+ u32 ori_len;
+
+ buf_offset = TXDESC_OFFSET;
+ ori_len = buf_offset+pattrib->pktlen;
+
+ /* check if the io_buf can accommodate new cmds */
+ if (ori_len + cmd_len + 8 > MAX_XMITBUF_SZ) {
+ DBG_88E("%s %u is large than MAX_XMITBUF_SZ:%u, can't accommodate new cmds\n",
+ __func__ , ori_len + cmd_len + 8, MAX_XMITBUF_SZ);
+ return _FAIL;
+ }
+
+ memcpy(xmit_frame->buf_addr + buf_offset + pattrib->pktlen, IOL_cmds, cmd_len);
+ pattrib->pktlen += cmd_len;
+ pattrib->last_txcmdsz += cmd_len;
+
+ return _SUCCESS;
+}
+
+bool rtw_IOL_applied(struct adapter *adapter)
+{
+ if (1 == adapter->registrypriv.fw_iol)
+ return true;
+
+ if ((2 == adapter->registrypriv.fw_iol) && (!adapter_to_dvobj(adapter)->ishighspeed))
+ return true;
+ return false;
+}
+
+int rtw_IOL_exec_cmds_sync(struct adapter *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt)
+{
+ return rtw_hal_iol_cmd(adapter, xmit_frame, max_wating_ms, bndy_cnt);
+}
+
+int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary)
+{
+ return _SUCCESS;
+}
+
+int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask)
+{
+ struct ioreg_cfg cmd = {8, IOREG_CMD_WB_REG, 0x0, 0x0, 0x0};
+
+ cmd.address = cpu_to_le16(addr);
+ cmd.data = cpu_to_le32(value);
+
+ if (mask != 0xFF) {
+ cmd.length = 12;
+ cmd.mask = cpu_to_le32(mask);
+ }
+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length);
+}
+
+int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask)
+{
+ struct ioreg_cfg cmd = {8, IOREG_CMD_WW_REG, 0x0, 0x0, 0x0};
+
+ cmd.address = cpu_to_le16(addr);
+ cmd.data = cpu_to_le32(value);
+
+ if (mask != 0xFFFF) {
+ cmd.length = 12;
+ cmd.mask = cpu_to_le32(mask);
+ }
+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length);
+}
+
+int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask)
+{
+ struct ioreg_cfg cmd = {8, IOREG_CMD_WD_REG, 0x0, 0x0, 0x0};
+
+ cmd.address = cpu_to_le16(addr);
+ cmd.data = cpu_to_le32(value);
+
+ if (mask != 0xFFFFFFFF) {
+ cmd.length = 12;
+ cmd.mask = cpu_to_le32(mask);
+ }
+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length);
+}
+
+int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask)
+{
+ struct ioreg_cfg cmd = {8, IOREG_CMD_W_RF, 0x0, 0x0, 0x0};
+
+ cmd.address = cpu_to_le16((rf_path<<8) | ((addr) & 0xFF));
+ cmd.data = cpu_to_le32(value);
+
+ if (mask != 0x000FFFFF) {
+ cmd.length = 12;
+ cmd.mask = cpu_to_le32(mask);
+ }
+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length);
+}
+
+int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us)
+{
+ struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0};
+ cmd.address = cpu_to_le16(us);
+
+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4);
+}
+
+int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms)
+{
+ struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0};
+
+ cmd.address = cpu_to_le16(ms);
+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4);
+}
+
+int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame)
+{
+ struct ioreg_cfg cmd = {4, IOREG_CMD_END, cpu_to_le16(0xFFFF), cpu_to_le32(0xFF), 0x0};
+
+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4);
+}
+
+u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame)
+{
+ u8 is_cmd_bndy = false;
+ if (((pxmit_frame->attrib.pktlen+32)%256) + 8 >= 256) {
+ rtw_IOL_append_END_cmd(pxmit_frame);
+ pxmit_frame->attrib.pktlen = ((((pxmit_frame->attrib.pktlen+32)/256)+1)*256);
+
+ pxmit_frame->attrib.last_txcmdsz = pxmit_frame->attrib.pktlen;
+ is_cmd_bndy = true;
+ }
+ return is_cmd_bndy;
+}
+
+void rtw_IOL_cmd_buf_dump(struct adapter *Adapter, int buf_len, u8 *pbuf)
+{
+ int i;
+ int j = 1;
+
+ pr_info("###### %s ######\n", __func__);
+ for (i = 0; i < buf_len; i++) {
+ printk("%02x-", *(pbuf+i));
+
+ if (j%32 == 0)
+ printk("\n");
+ j++;
+ }
+ printk("\n");
+ pr_info("=============ioreg_cmd len=%d===============\n", buf_len);
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_led.c b/drivers/staging/rtl8188eu/core/rtw_led.c
new file mode 100644
index 00000000000..afac5370984
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_led.c
@@ -0,0 +1,1692 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#include <drv_types.h>
+#include "rtw_led.h"
+
+/* */
+/* Description: */
+/* Callback function of LED BlinkTimer, */
+/* it just schedules to corresponding BlinkWorkItem/led_blink_hdl */
+/* */
+void BlinkTimerCallback(void *data)
+{
+ struct LED_871x *pLed = (struct LED_871x *)data;
+ struct adapter *padapter = pLed->padapter;
+
+ if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
+ return;
+
+ _set_workitem(&(pLed->BlinkWorkItem));
+}
+
+/* */
+/* Description: */
+/* Callback function of LED BlinkWorkItem. */
+/* We dispatch acture LED blink action according to LedStrategy. */
+/* */
+void BlinkWorkItemCallback(struct work_struct *work)
+{
+ struct LED_871x *pLed = container_of(work, struct LED_871x, BlinkWorkItem);
+ BlinkHandler(pLed);
+}
+
+/* */
+/* Description: */
+/* Reset status of LED_871x object. */
+/* */
+void ResetLedStatus(struct LED_871x *pLed)
+{
+ pLed->CurrLedState = RTW_LED_OFF; /* Current LED state. */
+ pLed->bLedOn = false; /* true if LED is ON, false if LED is OFF. */
+
+ pLed->bLedBlinkInProgress = false; /* true if it is blinking, false o.w.. */
+ pLed->bLedWPSBlinkInProgress = false;
+
+ pLed->BlinkTimes = 0; /* Number of times to toggle led state for blinking. */
+ pLed->BlinkingLedState = LED_UNKNOWN; /* Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */
+
+ pLed->bLedNoLinkBlinkInProgress = false;
+ pLed->bLedLinkBlinkInProgress = false;
+ pLed->bLedStartToLinkBlinkInProgress = false;
+ pLed->bLedScanBlinkInProgress = false;
+}
+
+/*Description: */
+/* Initialize an LED_871x object. */
+void InitLed871x(struct adapter *padapter, struct LED_871x *pLed, enum LED_PIN_871x LedPin)
+{
+ pLed->padapter = padapter;
+ pLed->LedPin = LedPin;
+
+ ResetLedStatus(pLed);
+
+ _init_timer(&(pLed->BlinkTimer), padapter->pnetdev, BlinkTimerCallback, pLed);
+
+ _init_workitem(&(pLed->BlinkWorkItem), BlinkWorkItemCallback, pLed);
+}
+
+
+/* */
+/* Description: */
+/* DeInitialize an LED_871x object. */
+/* */
+void DeInitLed871x(struct LED_871x *pLed)
+{
+ _cancel_workitem_sync(&(pLed->BlinkWorkItem));
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ ResetLedStatus(pLed);
+}
+
+/* */
+/* Description: */
+/* Implementation of LED blinking behavior. */
+/* It toggle off LED and schedule corresponding timer if necessary. */
+/* */
+
+static void SwLedBlink(struct LED_871x *pLed)
+{
+ struct adapter *padapter = pLed->padapter;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u8 bStopBlinking = false;
+
+ /* Change LED according to BlinkingLedState specified. */
+ if (pLed->BlinkingLedState == RTW_LED_ON) {
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+ } else {
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+ }
+
+ /* Determine if we shall change LED state again. */
+ pLed->BlinkTimes--;
+ switch (pLed->CurrLedState) {
+ case LED_BLINK_NORMAL:
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+ break;
+ case LED_BLINK_StartToBlink:
+ if (check_fwstate(pmlmepriv, _FW_LINKED) && check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+ bStopBlinking = true;
+ if (check_fwstate(pmlmepriv, _FW_LINKED) &&
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
+ bStopBlinking = true;
+ else if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+ break;
+ case LED_BLINK_WPS:
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+ break;
+ default:
+ bStopBlinking = true;
+ break;
+ }
+
+ if (bStopBlinking) {
+ /* if (padapter->pwrctrlpriv.cpwm >= PS_STATE_S2) */
+ if (0) {
+ SwLedOff(padapter, pLed);
+ } else if ((check_fwstate(pmlmepriv, _FW_LINKED)) && (!pLed->bLedOn)) {
+ SwLedOn(padapter, pLed);
+ } else if ((check_fwstate(pmlmepriv, _FW_LINKED)) && pLed->bLedOn) {
+ SwLedOff(padapter, pLed);
+ }
+ pLed->BlinkTimes = 0;
+ pLed->bLedBlinkInProgress = false;
+ } else {
+ /* Assign LED state to toggle. */
+ if (pLed->BlinkingLedState == RTW_LED_ON)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+
+ /* Schedule a timer to toggle LED state. */
+ switch (pLed->CurrLedState) {
+ case LED_BLINK_NORMAL:
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+ break;
+ case LED_BLINK_SLOWLY:
+ case LED_BLINK_StartToBlink:
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+ break;
+ case LED_BLINK_WPS:
+ if (pLed->BlinkingLedState == RTW_LED_ON)
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL);
+ else
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL);
+ break;
+ default:
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+ break;
+ }
+ }
+}
+
+static void SwLedBlink1(struct LED_871x *pLed)
+{
+ struct adapter *padapter = pLed->padapter;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u8 bStopBlinking = false;
+
+ /* Change LED according to BlinkingLedState specified. */
+ if (pLed->BlinkingLedState == RTW_LED_ON) {
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+ } else {
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+ }
+
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ ResetLedStatus(pLed);
+ return;
+ }
+
+ switch (pLed->CurrLedState) {
+ case LED_BLINK_SLOWLY:
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+ break;
+ case LED_BLINK_NORMAL:
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+ break;
+ case LED_BLINK_SCAN:
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+ if (bStopBlinking) {
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->bLedLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_NORMAL;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->bLedNoLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ }
+ pLed->bLedScanBlinkInProgress = false;
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_BLINK_TXRX:
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+ if (bStopBlinking) {
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->bLedLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_NORMAL;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->bLedNoLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ }
+ pLed->BlinkTimes = 0;
+ pLed->bLedBlinkInProgress = false;
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_BLINK_WPS:
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ break;
+ case LED_BLINK_WPS_STOP: /* WPS success */
+ if (pLed->BlinkingLedState == RTW_LED_ON)
+ bStopBlinking = false;
+ else
+ bStopBlinking = true;
+
+ if (bStopBlinking) {
+ pLed->bLedLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_NORMAL;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+
+ pLed->bLedWPSBlinkInProgress = false;
+ } else {
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void SwLedBlink2(struct LED_871x *pLed)
+{
+ struct adapter *padapter = pLed->padapter;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u8 bStopBlinking = false;
+
+ /* Change LED according to BlinkingLedState specified. */
+ if (pLed->BlinkingLedState == RTW_LED_ON) {
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+ } else {
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+ }
+
+ switch (pLed->CurrLedState) {
+ case LED_BLINK_SCAN:
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+ if (bStopBlinking) {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop scan blink CurrLedState %d\n", pLed->CurrLedState));
+
+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop scan blink CurrLedState %d\n", pLed->CurrLedState));
+ }
+ pLed->bLedScanBlinkInProgress = false;
+ } else {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ }
+ break;
+ case LED_BLINK_TXRX:
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+ if (bStopBlinking) {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop CurrLedState %d\n", pLed->CurrLedState));
+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop CurrLedState %d\n", pLed->CurrLedState));
+ }
+ pLed->bLedBlinkInProgress = false;
+ } else {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void SwLedBlink3(struct LED_871x *pLed)
+{
+ struct adapter *padapter = pLed->padapter;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u8 bStopBlinking = false;
+
+ /* Change LED according to BlinkingLedState specified. */
+ if (pLed->BlinkingLedState == RTW_LED_ON) {
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+ } else {
+ if (pLed->CurrLedState != LED_BLINK_WPS_STOP)
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+ }
+
+ switch (pLed->CurrLedState) {
+ case LED_BLINK_SCAN:
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+ if (bStopBlinking) {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ if (!pLed->bLedOn)
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ if (pLed->bLedOn)
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ }
+ pLed->bLedScanBlinkInProgress = false;
+ } else {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ }
+ break;
+ case LED_BLINK_TXRX:
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+ if (bStopBlinking) {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ if (!pLed->bLedOn)
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+
+ if (pLed->bLedOn)
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ }
+ pLed->bLedBlinkInProgress = false;
+ } else {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+ }
+ break;
+ case LED_BLINK_WPS:
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ break;
+ case LED_BLINK_WPS_STOP: /* WPS success */
+ if (pLed->BlinkingLedState == RTW_LED_ON) {
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA);
+ bStopBlinking = false;
+ } else {
+ bStopBlinking = true;
+ }
+ if (bStopBlinking) {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else {
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ }
+ pLed->bLedWPSBlinkInProgress = false;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void SwLedBlink4(struct LED_871x *pLed)
+{
+ struct adapter *padapter = pLed->padapter;
+ struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct LED_871x *pLed1 = &(ledpriv->SwLed1);
+ u8 bStopBlinking = false;
+
+ /* Change LED according to BlinkingLedState specified. */
+ if (pLed->BlinkingLedState == RTW_LED_ON) {
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+ } else {
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+ }
+
+ if (!pLed1->bLedWPSBlinkInProgress && pLed1->BlinkingLedState == LED_UNKNOWN) {
+ pLed1->BlinkingLedState = RTW_LED_OFF;
+ pLed1->CurrLedState = RTW_LED_OFF;
+ SwLedOff(padapter, pLed1);
+ }
+
+ switch (pLed->CurrLedState) {
+ case LED_BLINK_SLOWLY:
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+ break;
+ case LED_BLINK_StartToBlink:
+ if (pLed->bLedOn) {
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+ } else {
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+ }
+ break;
+ case LED_BLINK_SCAN:
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = false;
+ if (bStopBlinking) {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+ SwLedOff(padapter, pLed);
+ } else {
+ pLed->bLedNoLinkBlinkInProgress = false;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+ }
+ pLed->bLedScanBlinkInProgress = false;
+ } else {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+ SwLedOff(padapter, pLed);
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ }
+ break;
+ case LED_BLINK_TXRX:
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+ if (bStopBlinking) {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+ SwLedOff(padapter, pLed);
+ } else {
+ pLed->bLedNoLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+ }
+ pLed->bLedBlinkInProgress = false;
+ } else {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+ SwLedOff(padapter, pLed);
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+ }
+ break;
+ case LED_BLINK_WPS:
+ if (pLed->bLedOn) {
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+ } else {
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+ }
+ break;
+ case LED_BLINK_WPS_STOP: /* WPS authentication fail */
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+ break;
+ case LED_BLINK_WPS_STOP_OVERLAP: /* WPS session overlap */
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0) {
+ if (pLed->bLedOn)
+ pLed->BlinkTimes = 1;
+ else
+ bStopBlinking = true;
+ }
+
+ if (bStopBlinking) {
+ pLed->BlinkTimes = 10;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+ }
+ break;
+ default:
+ break;
+ }
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink4 CurrLedState %d\n", pLed->CurrLedState));
+}
+
+static void SwLedBlink5(struct LED_871x *pLed)
+{
+ struct adapter *padapter = pLed->padapter;
+ u8 bStopBlinking = false;
+
+ /* Change LED according to BlinkingLedState specified. */
+ if (pLed->BlinkingLedState == RTW_LED_ON) {
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+ } else {
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+ }
+
+ switch (pLed->CurrLedState) {
+ case LED_BLINK_SCAN:
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+
+ if (bStopBlinking) {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ if (pLed->bLedOn)
+ SwLedOff(padapter, pLed);
+ } else {
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ if (!pLed->bLedOn)
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+
+ pLed->bLedScanBlinkInProgress = false;
+ } else {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+ SwLedOff(padapter, pLed);
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ }
+ break;
+ case LED_BLINK_TXRX:
+ pLed->BlinkTimes--;
+ if (pLed->BlinkTimes == 0)
+ bStopBlinking = true;
+
+ if (bStopBlinking) {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ if (pLed->bLedOn)
+ SwLedOff(padapter, pLed);
+ } else {
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ if (!pLed->bLedOn)
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+
+ pLed->bLedBlinkInProgress = false;
+ } else {
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+ SwLedOff(padapter, pLed);
+ } else {
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink5 CurrLedState %d\n", pLed->CurrLedState));
+}
+
+static void SwLedBlink6(struct LED_871x *pLed)
+{
+ struct adapter *padapter = pLed->padapter;
+
+ /* Change LED according to BlinkingLedState specified. */
+ if (pLed->BlinkingLedState == RTW_LED_ON) {
+ SwLedOn(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+ } else {
+ SwLedOff(padapter, pLed);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+ }
+
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("<==== blink6\n"));
+}
+
+ /* ALPHA, added by chiyoko, 20090106 */
+static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction)
+{
+ struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct LED_871x *pLed = &(ledpriv->SwLed0);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ switch (LedAction) {
+ case LED_CTL_POWER_ON:
+ case LED_CTL_START_TO_LINK:
+ case LED_CTL_NO_LINK:
+ if (!pLed->bLedNoLinkBlinkInProgress) {
+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+
+ pLed->bLedNoLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_LINK:
+ if (!pLed->bLedLinkBlinkInProgress) {
+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ pLed->bLedLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_NORMAL;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_SITE_SURVEY:
+ if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
+ ;
+ } else if (!pLed->bLedScanBlinkInProgress) {
+ if (IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ pLed->bLedScanBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SCAN;
+ pLed->BlinkTimes = 24;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_TX:
+ case LED_CTL_RX:
+ if (!pLed->bLedBlinkInProgress) {
+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedLinkBlinkInProgress = false;
+ }
+ pLed->bLedBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_TXRX;
+ pLed->BlinkTimes = 2;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_START_WPS: /* wait until xinpin finish */
+ case LED_CTL_START_WPS_BOTTON:
+ if (!pLed->bLedWPSBlinkInProgress) {
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ pLed->bLedWPSBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_WPS;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_STOP_WPS:
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ if (pLed->bLedWPSBlinkInProgress)
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ else
+ pLed->bLedWPSBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_WPS_STOP;
+ if (pLed->bLedOn) {
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA);
+ } else {
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), 0);
+ }
+ break;
+ case LED_CTL_STOP_WPS_FAIL:
+ if (pLed->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedWPSBlinkInProgress = false;
+ }
+ pLed->bLedNoLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+ break;
+ case LED_CTL_POWER_OFF:
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedWPSBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ SwLedOff(padapter, pLed);
+ break;
+ default:
+ break;
+ }
+
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
+}
+
+ /* Arcadyan/Sitecom , added by chiyoko, 20090216 */
+static void SwLedControlMode2(struct adapter *padapter, enum LED_CTL_MODE LedAction)
+{
+ struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct LED_871x *pLed = &(ledpriv->SwLed0);
+
+ switch (LedAction) {
+ case LED_CTL_SITE_SURVEY:
+ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) {
+ } else if (!pLed->bLedScanBlinkInProgress) {
+ if (IS_LED_WPS_BLINKING(pLed))
+ return;
+
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ pLed->bLedScanBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SCAN;
+ pLed->BlinkTimes = 24;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_TX:
+ case LED_CTL_RX:
+ if ((!pLed->bLedBlinkInProgress) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+ return;
+ pLed->bLedBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_TXRX;
+ pLed->BlinkTimes = 2;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_LINK:
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ _set_timer(&(pLed->BlinkTimer), 0);
+ break;
+ case LED_CTL_START_WPS: /* wait until xinpin finish */
+ case LED_CTL_START_WPS_BOTTON:
+ if (!pLed->bLedWPSBlinkInProgress) {
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ pLed->bLedWPSBlinkInProgress = true;
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), 0);
+ }
+ break;
+ case LED_CTL_STOP_WPS:
+ pLed->bLedWPSBlinkInProgress = false;
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else {
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), 0);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ }
+ break;
+ case LED_CTL_STOP_WPS_FAIL:
+ pLed->bLedWPSBlinkInProgress = false;
+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+ SwLedOff(padapter, pLed);
+ } else {
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), 0);
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+ }
+ break;
+ case LED_CTL_START_TO_LINK:
+ case LED_CTL_NO_LINK:
+ if (!IS_LED_BLINKING(pLed)) {
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), 0);
+ }
+ break;
+ case LED_CTL_POWER_OFF:
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ if (pLed->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedWPSBlinkInProgress = false;
+ }
+
+ _set_timer(&(pLed->BlinkTimer), 0);
+ break;
+ default:
+ break;
+ }
+
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+}
+
+ /* COREGA, added by chiyoko, 20090316 */
+ static void SwLedControlMode3(struct adapter *padapter, enum LED_CTL_MODE LedAction)
+{
+ struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct LED_871x *pLed = &(ledpriv->SwLed0);
+
+ switch (LedAction) {
+ case LED_CTL_SITE_SURVEY:
+ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) {
+ } else if (!pLed->bLedScanBlinkInProgress) {
+ if (IS_LED_WPS_BLINKING(pLed))
+ return;
+
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ pLed->bLedScanBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SCAN;
+ pLed->BlinkTimes = 24;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_TX:
+ case LED_CTL_RX:
+ if ((!pLed->bLedBlinkInProgress) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+ return;
+ pLed->bLedBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_TXRX;
+ pLed->BlinkTimes = 2;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_LINK:
+ if (IS_LED_WPS_BLINKING(pLed))
+ return;
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+
+ _set_timer(&(pLed->BlinkTimer), 0);
+ break;
+ case LED_CTL_START_WPS: /* wait until xinpin finish */
+ case LED_CTL_START_WPS_BOTTON:
+ if (!pLed->bLedWPSBlinkInProgress) {
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ pLed->bLedWPSBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_WPS;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_STOP_WPS:
+ if (pLed->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedWPSBlinkInProgress = false;
+ } else {
+ pLed->bLedWPSBlinkInProgress = true;
+ }
+
+ pLed->CurrLedState = LED_BLINK_WPS_STOP;
+ if (pLed->bLedOn) {
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA);
+ } else {
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), 0);
+ }
+ break;
+ case LED_CTL_STOP_WPS_FAIL:
+ if (pLed->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedWPSBlinkInProgress = false;
+ }
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), 0);
+ break;
+ case LED_CTL_START_TO_LINK:
+ case LED_CTL_NO_LINK:
+ if (!IS_LED_BLINKING(pLed)) {
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), 0);
+ }
+ break;
+ case LED_CTL_POWER_OFF:
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ if (pLed->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedWPSBlinkInProgress = false;
+ }
+
+ _set_timer(&(pLed->BlinkTimer), 0);
+ break;
+ default:
+ break;
+ }
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+ ("CurrLedState %d\n", pLed->CurrLedState));
+}
+
+ /* Edimax-Belkin, added by chiyoko, 20090413 */
+static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAction)
+{
+ struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct LED_871x *pLed = &(ledpriv->SwLed0);
+ struct LED_871x *pLed1 = &(ledpriv->SwLed1);
+
+ switch (LedAction) {
+ case LED_CTL_START_TO_LINK:
+ if (pLed1->bLedWPSBlinkInProgress) {
+ pLed1->bLedWPSBlinkInProgress = false;
+ _cancel_timer_ex(&(pLed1->BlinkTimer));
+
+ pLed1->BlinkingLedState = RTW_LED_OFF;
+ pLed1->CurrLedState = RTW_LED_OFF;
+
+ if (pLed1->bLedOn)
+ _set_timer(&(pLed->BlinkTimer), 0);
+ }
+
+ if (!pLed->bLedStartToLinkBlinkInProgress) {
+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+
+ pLed->bLedStartToLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_StartToBlink;
+ if (pLed->bLedOn) {
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+ } else {
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+ }
+ }
+ break;
+ case LED_CTL_LINK:
+ case LED_CTL_NO_LINK:
+ /* LED1 settings */
+ if (LedAction == LED_CTL_LINK) {
+ if (pLed1->bLedWPSBlinkInProgress) {
+ pLed1->bLedWPSBlinkInProgress = false;
+ _cancel_timer_ex(&(pLed1->BlinkTimer));
+
+ pLed1->BlinkingLedState = RTW_LED_OFF;
+ pLed1->CurrLedState = RTW_LED_OFF;
+
+ if (pLed1->bLedOn)
+ _set_timer(&(pLed->BlinkTimer), 0);
+ }
+ }
+
+ if (!pLed->bLedNoLinkBlinkInProgress) {
+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+
+ pLed->bLedNoLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_SITE_SURVEY:
+ if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
+ } else if (!pLed->bLedScanBlinkInProgress) {
+ if (IS_LED_WPS_BLINKING(pLed))
+ return;
+
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ pLed->bLedScanBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SCAN;
+ pLed->BlinkTimes = 24;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_TX:
+ case LED_CTL_RX:
+ if (!pLed->bLedBlinkInProgress) {
+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ pLed->bLedBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_TXRX;
+ pLed->BlinkTimes = 2;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_START_WPS: /* wait until xinpin finish */
+ case LED_CTL_START_WPS_BOTTON:
+ if (pLed1->bLedWPSBlinkInProgress) {
+ pLed1->bLedWPSBlinkInProgress = false;
+ _cancel_timer_ex(&(pLed1->BlinkTimer));
+
+ pLed1->BlinkingLedState = RTW_LED_OFF;
+ pLed1->CurrLedState = RTW_LED_OFF;
+
+ if (pLed1->bLedOn)
+ _set_timer(&(pLed->BlinkTimer), 0);
+ }
+
+ if (!pLed->bLedWPSBlinkInProgress) {
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ pLed->bLedWPSBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_WPS;
+ if (pLed->bLedOn) {
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+ } else {
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+ }
+ }
+ break;
+ case LED_CTL_STOP_WPS: /* WPS connect success */
+ if (pLed->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedWPSBlinkInProgress = false;
+ }
+
+ pLed->bLedNoLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+
+ break;
+ case LED_CTL_STOP_WPS_FAIL: /* WPS authentication fail */
+ if (pLed->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedWPSBlinkInProgress = false;
+ }
+ pLed->bLedNoLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+
+ /* LED1 settings */
+ if (pLed1->bLedWPSBlinkInProgress)
+ _cancel_timer_ex(&(pLed1->BlinkTimer));
+ else
+ pLed1->bLedWPSBlinkInProgress = true;
+ pLed1->CurrLedState = LED_BLINK_WPS_STOP;
+ if (pLed1->bLedOn)
+ pLed1->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed1->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+ break;
+ case LED_CTL_STOP_WPS_FAIL_OVERLAP: /* WPS session overlap */
+ if (pLed->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedWPSBlinkInProgress = false;
+ }
+ pLed->bLedNoLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+
+ /* LED1 settings */
+ if (pLed1->bLedWPSBlinkInProgress)
+ _cancel_timer_ex(&(pLed1->BlinkTimer));
+ else
+ pLed1->bLedWPSBlinkInProgress = true;
+ pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP;
+ pLed1->BlinkTimes = 10;
+ if (pLed1->bLedOn)
+ pLed1->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed1->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+ break;
+ case LED_CTL_POWER_OFF:
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedWPSBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ if (pLed->bLedStartToLinkBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedStartToLinkBlinkInProgress = false;
+ }
+ if (pLed1->bLedWPSBlinkInProgress) {
+ _cancel_timer_ex(&(pLed1->BlinkTimer));
+ pLed1->bLedWPSBlinkInProgress = false;
+ }
+ pLed1->BlinkingLedState = LED_UNKNOWN;
+ SwLedOff(padapter, pLed);
+ SwLedOff(padapter, pLed1);
+ break;
+ default:
+ break;
+ }
+
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
+}
+
+
+
+ /* Sercomm-Belkin, added by chiyoko, 20090415 */
+static void
+SwLedControlMode5(
+ struct adapter *padapter,
+ enum LED_CTL_MODE LedAction
+)
+{
+ struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct LED_871x *pLed = &(ledpriv->SwLed0);
+
+ switch (LedAction) {
+ case LED_CTL_POWER_ON:
+ case LED_CTL_NO_LINK:
+ case LED_CTL_LINK: /* solid blue */
+ pLed->CurrLedState = RTW_LED_ON;
+ pLed->BlinkingLedState = RTW_LED_ON;
+
+ _set_timer(&(pLed->BlinkTimer), 0);
+ break;
+ case LED_CTL_SITE_SURVEY:
+ if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
+ } else if (!pLed->bLedScanBlinkInProgress) {
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ pLed->bLedScanBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SCAN;
+ pLed->BlinkTimes = 24;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_TX:
+ case LED_CTL_RX:
+ if (!pLed->bLedBlinkInProgress) {
+ if (pLed->CurrLedState == LED_BLINK_SCAN)
+ return;
+ pLed->bLedBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_TXRX;
+ pLed->BlinkTimes = 2;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+ }
+ break;
+ case LED_CTL_POWER_OFF:
+ pLed->CurrLedState = RTW_LED_OFF;
+ pLed->BlinkingLedState = RTW_LED_OFF;
+
+ if (pLed->bLedBlinkInProgress) {
+ _cancel_timer_ex(&(pLed->BlinkTimer));
+ pLed->bLedBlinkInProgress = false;
+ }
+ SwLedOff(padapter, pLed);
+ break;
+ default:
+ break;
+ }
+
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
+}
+
+ /* WNC-Corega, added by chiyoko, 20090902 */
+static void
+SwLedControlMode6(
+ struct adapter *padapter,
+ enum LED_CTL_MODE LedAction
+)
+{
+ struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct LED_871x *pLed0 = &(ledpriv->SwLed0);
+
+ switch (LedAction) {
+ case LED_CTL_POWER_ON:
+ case LED_CTL_LINK:
+ case LED_CTL_NO_LINK:
+ _cancel_timer_ex(&(pLed0->BlinkTimer));
+ pLed0->CurrLedState = RTW_LED_ON;
+ pLed0->BlinkingLedState = RTW_LED_ON;
+ _set_timer(&(pLed0->BlinkTimer), 0);
+ break;
+ case LED_CTL_POWER_OFF:
+ SwLedOff(padapter, pLed0);
+ break;
+ default:
+ break;
+ }
+
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("ledcontrol 6 Led %d\n", pLed0->CurrLedState));
+}
+
+/* */
+/* Description: */
+/* Handler function of LED Blinking. */
+/* We dispatch acture LED blink action according to LedStrategy. */
+/* */
+void BlinkHandler(struct LED_871x *pLed)
+{
+ struct adapter *padapter = pLed->padapter;
+ struct led_priv *ledpriv = &(padapter->ledpriv);
+
+ if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
+ return;
+
+ switch (ledpriv->LedStrategy) {
+ case SW_LED_MODE0:
+ SwLedBlink(pLed);
+ break;
+ case SW_LED_MODE1:
+ SwLedBlink1(pLed);
+ break;
+ case SW_LED_MODE2:
+ SwLedBlink2(pLed);
+ break;
+ case SW_LED_MODE3:
+ SwLedBlink3(pLed);
+ break;
+ case SW_LED_MODE4:
+ SwLedBlink4(pLed);
+ break;
+ case SW_LED_MODE5:
+ SwLedBlink5(pLed);
+ break;
+ case SW_LED_MODE6:
+ SwLedBlink6(pLed);
+ break;
+ default:
+ break;
+ }
+}
+
+void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction)
+{
+ struct led_priv *ledpriv = &(padapter->ledpriv);
+
+ if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) ||
+ (!padapter->hw_init_completed))
+ return;
+
+ if (!ledpriv->bRegUseLed)
+ return;
+
+ if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on &&
+ padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) &&
+ (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX ||
+ LedAction == LED_CTL_SITE_SURVEY ||
+ LedAction == LED_CTL_LINK ||
+ LedAction == LED_CTL_NO_LINK ||
+ LedAction == LED_CTL_POWER_ON))
+ return;
+
+ switch (ledpriv->LedStrategy) {
+ case SW_LED_MODE0:
+ break;
+ case SW_LED_MODE1:
+ SwLedControlMode1(padapter, LedAction);
+ break;
+ case SW_LED_MODE2:
+ SwLedControlMode2(padapter, LedAction);
+ break;
+ case SW_LED_MODE3:
+ SwLedControlMode3(padapter, LedAction);
+ break;
+ case SW_LED_MODE4:
+ SwLedControlMode4(padapter, LedAction);
+ break;
+ case SW_LED_MODE5:
+ SwLedControlMode5(padapter, LedAction);
+ break;
+ case SW_LED_MODE6:
+ SwLedControlMode6(padapter, LedAction);
+ break;
+ default:
+ break;
+ }
+
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+ ("LedStrategy:%d, LedAction %d\n",
+ ledpriv->LedStrategy, LedAction));
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c
new file mode 100644
index 00000000000..ea6607196d8
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c
@@ -0,0 +1,2442 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_MLME_C_
+
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+#include <hal_intf.h>
+#include <mlme_osdep.h>
+#include <sta_info.h>
+#include <wifi.h>
+#include <wlan_bssdef.h>
+#include <rtw_ioctl_set.h>
+#include <usb_osintf.h>
+
+extern unsigned char MCS_rate_2R[16];
+extern unsigned char MCS_rate_1R[16];
+
+int _rtw_init_mlme_priv (struct adapter *padapter)
+{
+ int i;
+ u8 *pbuf;
+ struct wlan_network *pnetwork;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ int res = _SUCCESS;
+
+_func_enter_;
+
+ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
+
+ pmlmepriv->nic_hdl = (u8 *)padapter;
+
+ pmlmepriv->pscanned = NULL;
+ pmlmepriv->fw_state = 0;
+ pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown;
+ pmlmepriv->scan_mode = SCAN_ACTIVE;/* 1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */
+
+ _rtw_spinlock_init(&(pmlmepriv->lock));
+ _rtw_init_queue(&(pmlmepriv->free_bss_pool));
+ _rtw_init_queue(&(pmlmepriv->scanned_queue));
+
+ set_scanned_network_val(pmlmepriv, 0);
+
+ _rtw_memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid));
+
+ pbuf = rtw_zvmalloc(MAX_BSS_CNT * (sizeof(struct wlan_network)));
+
+ if (pbuf == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ pmlmepriv->free_bss_buf = pbuf;
+
+ pnetwork = (struct wlan_network *)pbuf;
+
+ for (i = 0; i < MAX_BSS_CNT; i++) {
+ _rtw_init_listhead(&(pnetwork->list));
+
+ rtw_list_insert_tail(&(pnetwork->list), &(pmlmepriv->free_bss_pool.queue));
+
+ pnetwork++;
+ }
+
+ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+
+ rtw_clear_scan_deny(padapter);
+
+ rtw_init_mlme_timer(padapter);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+static void rtw_mfree_mlme_priv_lock (struct mlme_priv *pmlmepriv)
+{
+ _rtw_spinlock_free(&pmlmepriv->lock);
+ _rtw_spinlock_free(&(pmlmepriv->free_bss_pool.lock));
+ _rtw_spinlock_free(&(pmlmepriv->scanned_queue.lock));
+}
+
+#if defined (CONFIG_88EU_AP_MODE)
+static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen)
+{
+ kfree(*ppie);
+ *plen = 0;
+ *ppie = NULL;
+}
+
+void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv)
+{
+ rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len);
+ rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len);
+ rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len);
+ rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len);
+ rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len);
+ rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len);
+
+ rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len);
+ rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len);
+ rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len);
+ rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len);
+ rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len);
+}
+#else
+void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv)
+{
+}
+#endif
+
+void _rtw_free_mlme_priv (struct mlme_priv *pmlmepriv)
+{
+_func_enter_;
+
+ rtw_free_mlme_priv_ie_data(pmlmepriv);
+
+ if (pmlmepriv) {
+ rtw_mfree_mlme_priv_lock (pmlmepriv);
+
+ if (pmlmepriv->free_bss_buf) {
+ rtw_vmfree(pmlmepriv->free_bss_buf, MAX_BSS_CNT * sizeof(struct wlan_network));
+ }
+ }
+_func_exit_;
+}
+
+int _rtw_enqueue_network(struct __queue *queue, struct wlan_network *pnetwork)
+{
+ unsigned long irql;
+
+_func_enter_;
+
+ if (pnetwork == NULL)
+ goto exit;
+
+ _enter_critical_bh(&queue->lock, &irql);
+
+ rtw_list_insert_tail(&pnetwork->list, &queue->queue);
+
+ _exit_critical_bh(&queue->lock, &irql);
+
+exit:
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+struct wlan_network *_rtw_dequeue_network(struct __queue *queue)
+{
+ unsigned long irql;
+
+ struct wlan_network *pnetwork;
+
+_func_enter_;
+
+ _enter_critical_bh(&queue->lock, &irql);
+
+ if (_rtw_queue_empty(queue)) {
+ pnetwork = NULL;
+ } else {
+ pnetwork = LIST_CONTAINOR(get_next(&queue->queue), struct wlan_network, list);
+
+ rtw_list_delete(&(pnetwork->list));
+ }
+
+ _exit_critical_bh(&queue->lock, &irql);
+
+_func_exit_;
+
+ return pnetwork;
+}
+
+struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv)/* _queue *free_queue) */
+{
+ unsigned long irql;
+ struct wlan_network *pnetwork;
+ struct __queue *free_queue = &pmlmepriv->free_bss_pool;
+ struct list_head *plist = NULL;
+
+_func_enter_;
+
+ _enter_critical_bh(&free_queue->lock, &irql);
+
+ if (_rtw_queue_empty(free_queue) == true) {
+ pnetwork = NULL;
+ goto exit;
+ }
+ plist = get_next(&(free_queue->queue));
+
+ pnetwork = LIST_CONTAINOR(plist , struct wlan_network, list);
+
+ rtw_list_delete(&pnetwork->list);
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("_rtw_alloc_network: ptr=%p\n", plist));
+ pnetwork->network_type = 0;
+ pnetwork->fixed = false;
+ pnetwork->last_scanned = rtw_get_current_time();
+ pnetwork->aid = 0;
+ pnetwork->join_res = 0;
+
+ pmlmepriv->num_of_scanned++;
+
+exit:
+ _exit_critical_bh(&free_queue->lock, &irql);
+
+_func_exit_;
+
+ return pnetwork;
+}
+
+void _rtw_free_network(struct mlme_priv *pmlmepriv , struct wlan_network *pnetwork, u8 isfreeall)
+{
+ u32 curr_time, delta_time;
+ u32 lifetime = SCANQUEUE_LIFETIME;
+ unsigned long irql;
+ struct __queue *free_queue = &(pmlmepriv->free_bss_pool);
+
+_func_enter_;
+
+ if (pnetwork == NULL)
+ goto exit;
+
+ if (pnetwork->fixed)
+ goto exit;
+ curr_time = rtw_get_current_time();
+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)))
+ lifetime = 1;
+ if (!isfreeall) {
+ delta_time = (curr_time - pnetwork->last_scanned)/HZ;
+ if (delta_time < lifetime)/* unit:sec */
+ goto exit;
+ }
+ _enter_critical_bh(&free_queue->lock, &irql);
+ rtw_list_delete(&(pnetwork->list));
+ rtw_list_insert_tail(&(pnetwork->list), &(free_queue->queue));
+ pmlmepriv->num_of_scanned--;
+ _exit_critical_bh(&free_queue->lock, &irql);
+
+exit:
+_func_exit_;
+}
+
+void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork)
+{
+ struct __queue *free_queue = &(pmlmepriv->free_bss_pool);
+
+_func_enter_;
+ if (pnetwork == NULL)
+ goto exit;
+ if (pnetwork->fixed)
+ goto exit;
+ rtw_list_delete(&(pnetwork->list));
+ rtw_list_insert_tail(&(pnetwork->list), get_list_head(free_queue));
+ pmlmepriv->num_of_scanned--;
+exit:
+
+_func_exit_;
+}
+
+/*
+ return the wlan_network with the matching addr
+
+ Shall be calle under atomic context... to avoid possible racing condition...
+*/
+struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr)
+{
+ struct list_head *phead, *plist;
+ struct wlan_network *pnetwork = NULL;
+ u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+
+_func_enter_;
+ if (_rtw_memcmp(zero_addr, addr, ETH_ALEN)) {
+ pnetwork = NULL;
+ goto exit;
+ }
+ phead = get_list_head(scanned_queue);
+ plist = get_next(phead);
+
+ while (plist != phead) {
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network , list);
+ if (_rtw_memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN) == true)
+ break;
+ plist = get_next(plist);
+ }
+ if (plist == phead)
+ pnetwork = NULL;
+exit:
+_func_exit_;
+ return pnetwork;
+}
+
+
+void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall)
+{
+ unsigned long irql;
+ struct list_head *phead, *plist;
+ struct wlan_network *pnetwork;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct __queue *scanned_queue = &pmlmepriv->scanned_queue;
+
+_func_enter_;
+
+
+ _enter_critical_bh(&scanned_queue->lock, &irql);
+
+ phead = get_list_head(scanned_queue);
+ plist = get_next(phead);
+
+ while (rtw_end_of_queue_search(phead, plist) == false) {
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ plist = get_next(plist);
+
+ _rtw_free_network(pmlmepriv, pnetwork, isfreeall);
+ }
+ _exit_critical_bh(&scanned_queue->lock, &irql);
+_func_exit_;
+}
+
+int rtw_if_up(struct adapter *padapter)
+{
+ int res;
+_func_enter_;
+
+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved ||
+ (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == false)) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("rtw_if_up:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
+ padapter->bDriverStopped, padapter->bSurpriseRemoved));
+ res = false;
+ } else {
+ res = true;
+ }
+
+_func_exit_;
+ return res;
+}
+
+void rtw_generate_random_ibss(u8 *pibss)
+{
+ u32 curtime = rtw_get_current_time();
+
+_func_enter_;
+ pibss[0] = 0x02; /* in ad-hoc mode bit1 must set to 1 */
+ pibss[1] = 0x11;
+ pibss[2] = 0x87;
+ pibss[3] = (u8)(curtime & 0xff);/* p[0]; */
+ pibss[4] = (u8)((curtime>>8) & 0xff);/* p[1]; */
+ pibss[5] = (u8)((curtime>>16) & 0xff);/* p[2]; */
+_func_exit_;
+ return;
+}
+
+u8 *rtw_get_capability_from_ie(u8 *ie)
+{
+ return ie + 8 + 2;
+}
+
+
+u16 rtw_get_capability(struct wlan_bssid_ex *bss)
+{
+ __le16 val;
+_func_enter_;
+
+ memcpy((u8 *)&val, rtw_get_capability_from_ie(bss->IEs), 2);
+
+_func_exit_;
+ return le16_to_cpu(val);
+}
+
+u8 *rtw_get_timestampe_from_ie(u8 *ie)
+{
+ return ie + 0;
+}
+
+u8 *rtw_get_beacon_interval_from_ie(u8 *ie)
+{
+ return ie + 8;
+}
+
+int rtw_init_mlme_priv (struct adapter *padapter)/* struct mlme_priv *pmlmepriv) */
+{
+ int res;
+_func_enter_;
+ res = _rtw_init_mlme_priv(padapter);/* (pmlmepriv); */
+_func_exit_;
+ return res;
+}
+
+void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv)
+{
+_func_enter_;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_mlme_priv\n"));
+ _rtw_free_mlme_priv (pmlmepriv);
+_func_exit_;
+}
+
+static struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv)
+{
+ struct wlan_network *pnetwork;
+_func_enter_;
+ pnetwork = _rtw_alloc_network(pmlmepriv);
+_func_exit_;
+ return pnetwork;
+}
+
+static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
+ struct wlan_network *pnetwork)
+{
+_func_enter_;
+ _rtw_free_network_nolock(pmlmepriv, pnetwork);
+_func_exit_;
+}
+
+
+void rtw_free_network_queue(struct adapter *dev, u8 isfreeall)
+{
+_func_enter_;
+ _rtw_free_network_queue(dev, isfreeall);
+_func_exit_;
+}
+
+/*
+ return the wlan_network with the matching addr
+
+ Shall be calle under atomic context... to avoid possible racing condition...
+*/
+struct wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr)
+{
+ struct wlan_network *pnetwork = _rtw_find_network(scanned_queue, addr);
+
+ return pnetwork;
+}
+
+int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork)
+{
+ int ret = true;
+ struct security_priv *psecuritypriv = &adapter->securitypriv;
+
+ if ((psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) &&
+ (pnetwork->network.Privacy == 0))
+ ret = false;
+ else if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) &&
+ (pnetwork->network.Privacy == 1))
+ ret = false;
+ else
+ ret = true;
+ return ret;
+}
+
+static int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b)
+{
+ return (a->Ssid.SsidLength == b->Ssid.SsidLength) &&
+ _rtw_memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength);
+}
+
+int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst)
+{
+ u16 s_cap, d_cap;
+ __le16 le_scap, le_dcap;
+
+_func_enter_;
+ memcpy((u8 *)&le_scap, rtw_get_capability_from_ie(src->IEs), 2);
+ memcpy((u8 *)&le_dcap, rtw_get_capability_from_ie(dst->IEs), 2);
+
+
+ s_cap = le16_to_cpu(le_scap);
+ d_cap = le16_to_cpu(le_dcap);
+
+_func_exit_;
+
+ return ((src->Ssid.SsidLength == dst->Ssid.SsidLength) &&
+ ((_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN)) == true) &&
+ ((_rtw_memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength)) == true) &&
+ ((s_cap & WLAN_CAPABILITY_IBSS) ==
+ (d_cap & WLAN_CAPABILITY_IBSS)) &&
+ ((s_cap & WLAN_CAPABILITY_BSS) ==
+ (d_cap & WLAN_CAPABILITY_BSS)));
+}
+
+struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue)
+{
+ struct list_head *plist, *phead;
+ struct wlan_network *pwlan = NULL;
+ struct wlan_network *oldest = NULL;
+
+_func_enter_;
+ phead = get_list_head(scanned_queue);
+
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ pwlan = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ if (!pwlan->fixed) {
+ if (oldest == NULL || time_after(oldest->last_scanned, pwlan->last_scanned))
+ oldest = pwlan;
+ }
+
+ plist = get_next(plist);
+ }
+_func_exit_;
+ return oldest;
+}
+
+void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
+ struct adapter *padapter, bool update_ie)
+{
+ long rssi_ori = dst->Rssi;
+ u8 sq_smp = src->PhyInfo.SignalQuality;
+ u8 ss_final;
+ u8 sq_final;
+ long rssi_final;
+
+_func_enter_;
+ rtw_hal_antdiv_rssi_compared(padapter, dst, src); /* this will update src.Rssi, need consider again */
+
+ /* The rule below is 1/5 for sample value, 4/5 for history value */
+ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src)) {
+ /* Take the recvpriv's value for the connected AP*/
+ ss_final = padapter->recvpriv.signal_strength;
+ sq_final = padapter->recvpriv.signal_qual;
+ /* the rssi value here is undecorated, and will be used for antenna diversity */
+ if (sq_smp != 101) /* from the right channel */
+ rssi_final = (src->Rssi+dst->Rssi*4)/5;
+ else
+ rssi_final = rssi_ori;
+ } else {
+ if (sq_smp != 101) { /* from the right channel */
+ ss_final = ((u32)(src->PhyInfo.SignalStrength)+(u32)(dst->PhyInfo.SignalStrength)*4)/5;
+ sq_final = ((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5;
+ rssi_final = (src->Rssi+dst->Rssi*4)/5;
+ } else {
+ /* bss info not receving from the right channel, use the original RX signal infos */
+ ss_final = dst->PhyInfo.SignalStrength;
+ sq_final = dst->PhyInfo.SignalQuality;
+ rssi_final = dst->Rssi;
+ }
+ }
+ if (update_ie)
+ memcpy((u8 *)dst, (u8 *)src, get_wlan_bssid_ex_sz(src));
+ dst->PhyInfo.SignalStrength = ss_final;
+ dst->PhyInfo.SignalQuality = sq_final;
+ dst->Rssi = rssi_final;
+
+_func_exit_;
+}
+
+static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork)
+{
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+
+_func_enter_;
+
+ if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) &&
+ (is_same_network(&(pmlmepriv->cur_network.network), pnetwork))) {
+ update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, true);
+ rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof(struct ndis_802_11_fixed_ie),
+ pmlmepriv->cur_network.network.IELength);
+ }
+_func_exit_;
+}
+
+/*
+Caller must hold pmlmepriv->lock first.
+*/
+void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *target)
+{
+ unsigned long irql;
+ struct list_head *plist, *phead;
+ u32 bssid_ex_sz;
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ struct wlan_network *oldest = NULL;
+
+_func_enter_;
+
+ _enter_critical_bh(&queue->lock, &irql);
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ if (is_same_network(&(pnetwork->network), target))
+ break;
+ if ((oldest == ((struct wlan_network *)0)) ||
+ time_after(oldest->last_scanned, pnetwork->last_scanned))
+ oldest = pnetwork;
+ plist = get_next(plist);
+ }
+ /* If we didn't find a match, then get a new network slot to initialize
+ * with this beacon's information */
+ if (rtw_end_of_queue_search(phead, plist) == true) {
+ if (_rtw_queue_empty(&(pmlmepriv->free_bss_pool)) == true) {
+ /* If there are no more slots, expire the oldest */
+ pnetwork = oldest;
+
+ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(target->PhyInfo.Optimum_antenna));
+ memcpy(&(pnetwork->network), target, get_wlan_bssid_ex_sz(target));
+ /* variable initialize */
+ pnetwork->fixed = false;
+ pnetwork->last_scanned = rtw_get_current_time();
+
+ pnetwork->network_type = 0;
+ pnetwork->aid = 0;
+ pnetwork->join_res = 0;
+
+ /* bss info not receving from the right channel */
+ if (pnetwork->network.PhyInfo.SignalQuality == 101)
+ pnetwork->network.PhyInfo.SignalQuality = 0;
+ } else {
+ /* Otherwise just pull from the free list */
+
+ pnetwork = rtw_alloc_network(pmlmepriv); /* will update scan_time */
+
+ if (pnetwork == NULL) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n\nsomething wrong here\n\n\n"));
+ goto exit;
+ }
+
+ bssid_ex_sz = get_wlan_bssid_ex_sz(target);
+ target->Length = bssid_ex_sz;
+ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(target->PhyInfo.Optimum_antenna));
+ memcpy(&(pnetwork->network), target, bssid_ex_sz);
+
+ pnetwork->last_scanned = rtw_get_current_time();
+
+ /* bss info not receving from the right channel */
+ if (pnetwork->network.PhyInfo.SignalQuality == 101)
+ pnetwork->network.PhyInfo.SignalQuality = 0;
+ rtw_list_insert_tail(&(pnetwork->list), &(queue->queue));
+ }
+ } else {
+ /* we have an entry and we are going to update it. But this entry may
+ * be already expired. In this case we do the same as we found a new
+ * net and call the new_net handler
+ */
+ bool update_ie = true;
+
+ pnetwork->last_scanned = rtw_get_current_time();
+
+ /* target.Reserved[0]== 1, means that scaned network is a bcn frame. */
+ if ((pnetwork->network.IELength > target->IELength) && (target->Reserved[0] == 1))
+ update_ie = false;
+
+ update_network(&(pnetwork->network), target, adapter, update_ie);
+ }
+
+exit:
+ _exit_critical_bh(&queue->lock, &irql);
+
+_func_exit_;
+}
+
+static void rtw_add_network(struct adapter *adapter,
+ struct wlan_bssid_ex *pnetwork)
+{
+_func_enter_;
+#if defined(CONFIG_88EU_P2P)
+ rtw_wlan_bssid_ex_remove_p2p_attr(pnetwork, P2P_ATTR_GROUP_INFO);
+#endif
+ update_current_network(adapter, pnetwork);
+ rtw_update_scanned_network(adapter, pnetwork);
+_func_exit_;
+}
+
+/* select the desired network based on the capability of the (i)bss. */
+/* check items: (1) security */
+/* (2) network_type */
+/* (3) WMM */
+/* (4) HT */
+/* (5) others */
+static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwork)
+{
+ struct security_priv *psecuritypriv = &adapter->securitypriv;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ u32 desired_encmode;
+ u32 privacy;
+
+ /* u8 wps_ie[512]; */
+ uint wps_ielen;
+
+ int bselected = true;
+
+ desired_encmode = psecuritypriv->ndisencryptstatus;
+ privacy = pnetwork->network.Privacy;
+
+ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
+ if (rtw_get_wps_ie(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen) != NULL)
+ return true;
+ else
+ return false;
+ }
+ if (adapter->registrypriv.wifi_spec == 1) { /* for correct flow of 8021X to do.... */
+ if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0))
+ bselected = false;
+ }
+
+
+ if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) {
+ DBG_88E("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy);
+ bselected = false;
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) {
+ if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode)
+ bselected = false;
+ }
+
+
+ return bselected;
+}
+
+/* TODO: Perry: For Power Management */
+void rtw_atimdone_event_callback(struct adapter *adapter , u8 *pbuf)
+{
+_func_enter_;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_evet\n"));
+_func_exit_;
+ return;
+}
+
+
+void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf)
+{
+ unsigned long irql;
+ u32 len;
+ struct wlan_bssid_ex *pnetwork;
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+
+_func_enter_;
+
+ pnetwork = (struct wlan_bssid_ex *)pbuf;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_survey_event_callback, ssid=%s\n", pnetwork->Ssid.Ssid));
+
+ len = get_wlan_bssid_ex_sz(pnetwork);
+ if (len > (sizeof(struct wlan_bssid_ex))) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n****rtw_survey_event_callback: return a wrong bss ***\n"));
+ return;
+ }
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+
+ /* update IBSS_network 's timestamp */
+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) {
+ if (_rtw_memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) {
+ struct wlan_network *ibss_wlan = NULL;
+ unsigned long irql;
+
+ memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8);
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ ibss_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->MacAddress);
+ if (ibss_wlan) {
+ memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8);
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ goto exit;
+ }
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ }
+ }
+
+ /* lock pmlmepriv->lock when you accessing network_q */
+ if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == false) {
+ if (pnetwork->Ssid.Ssid[0] == 0)
+ pnetwork->Ssid.SsidLength = 0;
+ rtw_add_network(adapter, pnetwork);
+ }
+
+exit:
+
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+
+_func_exit_;
+
+ return;
+}
+
+
+
+void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf)
+{
+ unsigned long irql;
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext;
+
+_func_enter_;
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+
+ if (pmlmepriv->wps_probe_req_ie) {
+ pmlmepriv->wps_probe_req_ie_len = 0;
+ kfree(pmlmepriv->wps_probe_req_ie);
+ pmlmepriv->wps_probe_req_ie = NULL;
+ }
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_surveydone_event_callback: fw_state:%x\n\n", get_fwstate(pmlmepriv)));
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
+ u8 timer_cancelled;
+
+ _cancel_timer(&pmlmepriv->scan_to_timer, &timer_cancelled);
+
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+ } else {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("nic status=%x, survey done event comes too late!\n", get_fwstate(pmlmepriv)));
+ }
+
+ rtw_set_signal_stat_timer(&adapter->recvpriv);
+
+ if (pmlmepriv->to_join) {
+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) {
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == false) {
+ set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+
+ if (rtw_select_and_join_from_scanned_queue(pmlmepriv) == _SUCCESS) {
+ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
+ } else {
+ struct wlan_bssid_ex *pdev_network = &(adapter->registrypriv.dev_network);
+ u8 *pibss = adapter->registrypriv.dev_network.MacAddress;
+
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n"));
+
+ _rtw_memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
+ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid));
+
+ rtw_update_registrypriv_dev_network(adapter);
+ rtw_generate_random_ibss(pibss);
+
+ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
+
+ if (rtw_createbss_cmd(adapter) != _SUCCESS)
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error=>rtw_createbss_cmd status FAIL\n"));
+ pmlmepriv->to_join = false;
+ }
+ }
+ } else {
+ int s_ret;
+ set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+ pmlmepriv->to_join = false;
+ s_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
+ if (_SUCCESS == s_ret) {
+ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
+ } else if (s_ret == 2) { /* there is no need to wait for join */
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+ rtw_indicate_connect(adapter);
+ } else {
+ DBG_88E("try_to_join, but select scanning queue fail, to_roaming:%d\n", pmlmepriv->to_roaming);
+ if (pmlmepriv->to_roaming != 0) {
+ if (--pmlmepriv->to_roaming == 0 ||
+ _SUCCESS != rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0)) {
+ pmlmepriv->to_roaming = 0;
+ rtw_free_assoc_resources(adapter, 1);
+ rtw_indicate_disconnect(adapter);
+ } else {
+ pmlmepriv->to_join = true;
+ }
+ }
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+ }
+ }
+ }
+
+ indicate_wx_scan_complete_event(adapter);
+
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+ p2p_ps_wk_cmd(adapter, P2P_PS_SCAN_DONE, 0);
+
+ rtw_os_xmit_schedule(adapter);
+
+ pmlmeext = &adapter->mlmeextpriv;
+ if (pmlmeext->sitesurvey_res.bss_cnt == 0)
+ rtw_hal_sreset_reset(adapter);
+_func_exit_;
+}
+
+void rtw_dummy_event_callback(struct adapter *adapter , u8 *pbuf)
+{
+}
+
+void rtw_fwdbg_event_callback(struct adapter *adapter , u8 *pbuf)
+{
+}
+
+static void free_scanqueue(struct mlme_priv *pmlmepriv)
+{
+ unsigned long irql, irql0;
+ struct __queue *free_queue = &pmlmepriv->free_bss_pool;
+ struct __queue *scan_queue = &pmlmepriv->scanned_queue;
+ struct list_head *plist, *phead, *ptemp;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+free_scanqueue\n"));
+ _enter_critical_bh(&scan_queue->lock, &irql0);
+ _enter_critical_bh(&free_queue->lock, &irql);
+
+ phead = get_list_head(scan_queue);
+ plist = get_next(phead);
+
+ while (plist != phead) {
+ ptemp = get_next(plist);
+ rtw_list_delete(plist);
+ rtw_list_insert_tail(plist, &free_queue->queue);
+ plist = ptemp;
+ pmlmepriv->num_of_scanned--;
+ }
+
+ _exit_critical_bh(&free_queue->lock, &irql);
+ _exit_critical_bh(&scan_queue->lock, &irql0);
+
+_func_exit_;
+}
+
+/*
+*rtw_free_assoc_resources: the caller has to lock pmlmepriv->lock
+*/
+void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue)
+{
+ unsigned long irql;
+ struct wlan_network *pwlan = NULL;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ struct sta_priv *pstapriv = &adapter->stapriv;
+ struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources\n"));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("tgt_network->network.MacAddress=%pM ssid=%s\n",
+ tgt_network->network.MacAddress, tgt_network->network.Ssid.Ssid));
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE)) {
+ struct sta_info *psta;
+
+ psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress);
+
+ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+ rtw_free_stainfo(adapter, psta);
+ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE)) {
+ struct sta_info *psta;
+
+ rtw_free_all_stainfo(adapter);
+
+ psta = rtw_get_bcmc_stainfo(adapter);
+ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+ rtw_free_stainfo(adapter, psta);
+ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+
+ rtw_init_bcmc_stainfo(adapter);
+ }
+
+ if (lock_scanned_queue)
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+
+ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+ if (pwlan)
+ pwlan->fixed = false;
+ else
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_assoc_resources:pwlan==NULL\n\n"));
+
+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1)))
+ rtw_free_network_nolock(pmlmepriv, pwlan);
+
+ if (lock_scanned_queue)
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ pmlmepriv->key_mask = 0;
+_func_exit_;
+}
+
+/*
+*rtw_indicate_connect: the caller has to lock pmlmepriv->lock
+*/
+void rtw_indicate_connect(struct adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect\n"));
+
+ pmlmepriv->to_join = false;
+
+ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+ set_fwstate(pmlmepriv, _FW_LINKED);
+
+ rtw_led_control(padapter, LED_CTL_LINK);
+
+ rtw_os_indicate_connect(padapter);
+ }
+
+ pmlmepriv->to_roaming = 0;
+
+ rtw_set_scan_deny(padapter, 3000);
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect: fw_state=0x%08x\n", get_fwstate(pmlmepriv)));
+_func_exit_;
+}
+
+/*
+*rtw_indicate_disconnect: the caller has to lock pmlmepriv->lock
+*/
+void rtw_indicate_disconnect(struct adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_disconnect\n"));
+
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS);
+
+
+ if (pmlmepriv->to_roaming > 0)
+ _clr_fwstate_(pmlmepriv, _FW_LINKED);
+
+ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) ||
+ (pmlmepriv->to_roaming <= 0)) {
+ rtw_os_indicate_disconnect(padapter);
+
+ _clr_fwstate_(pmlmepriv, _FW_LINKED);
+ rtw_led_control(padapter, LED_CTL_NO_LINK);
+ rtw_clear_scan_deny(padapter);
+ }
+ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
+
+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 1);
+
+_func_exit_;
+}
+
+inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted)
+{
+ rtw_os_indicate_scan_done(padapter, aborted);
+}
+
+void rtw_scan_abort(struct adapter *adapter)
+{
+ u32 start;
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
+
+ start = rtw_get_current_time();
+ pmlmeext->scan_abort = true;
+ while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) &&
+ rtw_get_passing_time_ms(start) <= 200) {
+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
+ break;
+ DBG_88E(FUNC_NDEV_FMT"fw_state=_FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev));
+ rtw_msleep_os(20);
+ }
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
+ if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved)
+ DBG_88E(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev));
+ rtw_indicate_scan_done(adapter, true);
+ }
+ pmlmeext->scan_abort = false;
+}
+
+static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, struct wlan_network *pnetwork)
+{
+ int i;
+ struct sta_info *bmc_sta, *psta = NULL;
+ struct recv_reorder_ctrl *preorder_ctrl;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ psta = rtw_get_stainfo(pstapriv, pnetwork->network.MacAddress);
+ if (psta == NULL)
+ psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress);
+
+ if (psta) { /* update ptarget_sta */
+ DBG_88E("%s\n", __func__);
+ psta->aid = pnetwork->join_res;
+ psta->mac_id = 0;
+ /* sta mode */
+ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
+ /* security related */
+ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+ padapter->securitypriv.binstallGrpkey = false;
+ padapter->securitypriv.busetkipkey = false;
+ padapter->securitypriv.bgrpkey_handshake = false;
+ psta->ieee8021x_blocked = true;
+ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+ _rtw_memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof(union Keytype));
+ _rtw_memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof(union Keytype));
+ _rtw_memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof(union Keytype));
+ _rtw_memset((u8 *)&psta->dot11txpn, 0, sizeof(union pn48));
+ _rtw_memset((u8 *)&psta->dot11rxpn, 0, sizeof(union pn48));
+ }
+ /* Commented by Albert 2012/07/21 */
+ /* When doing the WPS, the wps_ie_len won't equal to 0 */
+ /* And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */
+ if (padapter->securitypriv.wps_ie_len != 0) {
+ psta->ieee8021x_blocked = true;
+ padapter->securitypriv.wps_ie_len = 0;
+ }
+ /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */
+ /* if A-MPDU Rx is enabled, reseting rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */
+ /* todo: check if AP can send A-MPDU packets */
+ for (i = 0; i < 16; i++) {
+ /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */
+ preorder_ctrl = &psta->recvreorder_ctrl[i];
+ preorder_ctrl->enable = false;
+ preorder_ctrl->indicate_seq = 0xffff;
+ preorder_ctrl->wend_b = 0xffff;
+ preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */
+ }
+ bmc_sta = rtw_get_bcmc_stainfo(padapter);
+ if (bmc_sta) {
+ for (i = 0; i < 16; i++) {
+ /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */
+ preorder_ctrl = &bmc_sta->recvreorder_ctrl[i];
+ preorder_ctrl->enable = false;
+ preorder_ctrl->indicate_seq = 0xffff;
+ preorder_ctrl->wend_b = 0xffff;
+ preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */
+ }
+ }
+ /* misc. */
+ update_sta_info(padapter, psta);
+ }
+ return psta;
+}
+
+/* pnetwork: returns from rtw_joinbss_event_callback */
+/* ptarget_wlan: found from scanned_queue */
+static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network *pnetwork)
+{
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+
+ DBG_88E("%s\n", __func__);
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("\nfw_state:%x, BSSID:%pM\n",
+ get_fwstate(pmlmepriv), pnetwork->network.MacAddress));
+
+
+ /* why not use ptarget_wlan?? */
+ memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length);
+ /* some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */
+ cur_network->network.IELength = ptarget_wlan->network.IELength;
+ memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ);
+
+ cur_network->aid = pnetwork->join_res;
+
+
+ rtw_set_signal_stat_timer(&padapter->recvpriv);
+ padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength;
+ padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality;
+ /* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */
+ padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength);
+ rtw_set_signal_stat_timer(&padapter->recvpriv);
+
+ /* update fw_state will clr _FW_UNDER_LINKING here indirectly */
+ switch (pnetwork->network.InfrastructureMode) {
+ case Ndis802_11Infrastructure:
+ if (pmlmepriv->fw_state&WIFI_UNDER_WPS)
+ pmlmepriv->fw_state = WIFI_STATION_STATE|WIFI_UNDER_WPS;
+ else
+ pmlmepriv->fw_state = WIFI_STATION_STATE;
+ break;
+ case Ndis802_11IBSS:
+ pmlmepriv->fw_state = WIFI_ADHOC_STATE;
+ break;
+ default:
+ pmlmepriv->fw_state = WIFI_NULL_STATE;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Invalid network_mode\n"));
+ break;
+ }
+
+ rtw_update_protection(padapter, (cur_network->network.IEs) +
+ sizeof(struct ndis_802_11_fixed_ie),
+ (cur_network->network.IELength));
+ rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength);
+}
+
+/* Notes: the fucntion could be > passive_level (the same context as Rx tasklet) */
+/* pnetwork: returns from rtw_joinbss_event_callback */
+/* ptarget_wlan: found from scanned_queue */
+/* if join_res > 0, for (fw_state == WIFI_STATION_STATE), we check if "ptarget_sta" & "ptarget_wlan" exist. */
+/* if join_res > 0, for (fw_state == WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist. */
+/* if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan != NULL). */
+
+void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
+{
+ unsigned long irql, irql2;
+ u8 timer_cancelled;
+ struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL;
+ struct sta_priv *pstapriv = &adapter->stapriv;
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+ struct wlan_network *pnetwork = (struct wlan_network *)pbuf;
+ struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+ struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL;
+ unsigned int the_same_macaddr = false;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("joinbss event call back received with res=%d\n", pnetwork->join_res));
+
+ rtw_get_encrypt_decrypt_from_registrypriv(adapter);
+
+
+ if (pmlmepriv->assoc_ssid.SsidLength == 0)
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ joinbss event call back for Any SSid\n"));
+ else
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid));
+
+ the_same_macaddr = _rtw_memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN);
+
+ pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network);
+ if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n"));
+ goto ignore_nolock;
+ }
+
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nrtw_joinbss_event_callback!! _enter_critical\n"));
+
+ if (pnetwork->join_res > 0) {
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
+ /* s1. find ptarget_wlan */
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ if (the_same_macaddr) {
+ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
+ } else {
+ pcur_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
+ if (pcur_wlan)
+ pcur_wlan->fixed = false;
+
+ pcur_sta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
+ if (pcur_sta) {
+ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irql2);
+ rtw_free_stainfo(adapter, pcur_sta);
+ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irql2);
+ }
+
+ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress);
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+ if (ptarget_wlan)
+ ptarget_wlan->fixed = true;
+ }
+ }
+ } else {
+ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress);
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+ if (ptarget_wlan)
+ ptarget_wlan->fixed = true;
+ }
+ }
+
+ /* s2. update cur_network */
+ if (ptarget_wlan) {
+ rtw_joinbss_update_network(adapter, ptarget_wlan, pnetwork);
+ } else {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't find ptarget_wlan when joinbss_event callback\n"));
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ goto ignore_joinbss_callback;
+ }
+
+
+ /* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+ ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork);
+ if (ptarget_sta == NULL) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't update stainfo when joinbss_event callback\n"));
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ goto ignore_joinbss_callback;
+ }
+ }
+
+ /* s4. indicate connect */
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+ rtw_indicate_connect(adapter);
+ } else {
+ /* adhoc mode will rtw_indicate_connect when rtw_stassoc_event_callback */
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv)));
+ }
+
+ /* s5. Cancle assoc_timer */
+ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled);
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("Cancle assoc_timer\n"));
+
+ } else {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_joinbss_event_callback err: fw_state:%x", get_fwstate(pmlmepriv)));
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ goto ignore_joinbss_callback;
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+
+ } else if (pnetwork->join_res == -4) {
+ rtw_reset_securitypriv(adapter);
+ _set_timer(&pmlmepriv->assoc_timer, 1);
+
+ if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == true) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("fail! clear _FW_UNDER_LINKING ^^^fw_state=%x\n", get_fwstate(pmlmepriv)));
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+ }
+ } else { /* if join_res < 0 (join fails), then try again */
+ _set_timer(&pmlmepriv->assoc_timer, 1);
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+ }
+
+ignore_joinbss_callback:
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+ignore_nolock:
+_func_exit_;
+}
+
+void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf)
+{
+ struct wlan_network *pnetwork = (struct wlan_network *)pbuf;
+
+_func_enter_;
+
+ mlmeext_joinbss_event_callback(adapter, pnetwork->join_res);
+
+ rtw_os_xmit_schedule(adapter);
+
+_func_exit_;
+}
+
+static u8 search_max_mac_id(struct adapter *padapter)
+{
+ u8 mac_id;
+#if defined (CONFIG_88EU_AP_MODE)
+ u8 aid;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+#endif
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+#if defined (CONFIG_88EU_AP_MODE)
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ for (aid = (pstapriv->max_num_sta); aid > 0; aid--) {
+ if (pstapriv->sta_aid[aid-1] != NULL)
+ break;
+ }
+ mac_id = aid + 1;
+ } else
+#endif
+ {/* adhoc id = 31~2 */
+ for (mac_id = (NUM_STA-1); mac_id >= IBSS_START_MAC_ID; mac_id--) {
+ if (pmlmeinfo->FW_sta_info[mac_id].status == 1)
+ break;
+ }
+ }
+ return mac_id;
+}
+
+/* FOR AP , AD-HOC mode */
+void rtw_stassoc_hw_rpt(struct adapter *adapter, struct sta_info *psta)
+{
+ u16 media_status;
+ u8 macid;
+
+ if (psta == NULL)
+ return;
+
+ macid = search_max_mac_id(adapter);
+ rtw_hal_set_hwreg(adapter, HW_VAR_TX_RPT_MAX_MACID, (u8 *)&macid);
+ media_status = (psta->mac_id<<8)|1; /* MACID|OPMODE:1 connect */
+ rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
+}
+
+void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf)
+{
+ unsigned long irql;
+ struct sta_info *psta;
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+ struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf;
+ struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+ struct wlan_network *ptarget_wlan = NULL;
+
+_func_enter_;
+
+ if (rtw_access_ctrl(adapter, pstassoc->macaddr) == false)
+ return;
+
+#if defined (CONFIG_88EU_AP_MODE)
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr);
+ if (psta) {
+ ap_sta_info_defer_update(adapter, psta);
+ rtw_stassoc_hw_rpt(adapter, psta);
+ }
+ goto exit;
+ }
+#endif
+ /* for AD-HOC mode */
+ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr);
+ if (psta != NULL) {
+ /* the sta have been in sta_info_queue => do nothing */
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error: rtw_stassoc_event_callback: sta has been in sta_hash_queue\n"));
+ goto exit; /* between drv has received this event before and fw have not yet to set key to CAM_ENTRY) */
+ }
+ psta = rtw_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr);
+ if (psta == NULL) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't alloc sta_info when rtw_stassoc_event_callback\n"));
+ goto exit;
+ }
+ /* to do: init sta_info variable */
+ psta->qos_option = 0;
+ psta->mac_id = (uint)pstassoc->cam_id;
+ DBG_88E("%s\n", __func__);
+ /* for ad-hoc mode */
+ rtw_hal_set_odm_var(adapter, HAL_ODM_STA_INFO, psta, true);
+ rtw_stassoc_hw_rpt(adapter, psta);
+ if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
+ psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm;
+ psta->ieee8021x_blocked = false;
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))) {
+ if (adapter->stapriv.asoc_sta_count == 2) {
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
+ if (ptarget_wlan)
+ ptarget_wlan->fixed = true;
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ /* a sta + bc/mc_stainfo (not Ibss_stainfo) */
+ rtw_indicate_connect(adapter);
+ }
+ }
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+ mlmeext_sta_add_event_callback(adapter, psta);
+exit:
+_func_exit_;
+}
+
+void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf)
+{
+ unsigned long irql, irql2;
+ int mac_id = -1;
+ struct sta_info *psta;
+ struct wlan_network *pwlan = NULL;
+ struct wlan_bssid_ex *pdev_network = NULL;
+ u8 *pibss = NULL;
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+ struct stadel_event *pstadel = (struct stadel_event *)pbuf;
+ struct sta_priv *pstapriv = &adapter->stapriv;
+ struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
+
+_func_enter_;
+
+ psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr);
+ if (psta)
+ mac_id = psta->mac_id;
+ else
+ mac_id = pstadel->mac_id;
+
+ DBG_88E("%s(mac_id=%d)=%pM\n", __func__, mac_id, pstadel->macaddr);
+
+ if (mac_id >= 0) {
+ u16 media_status;
+ media_status = (mac_id<<8)|0; /* MACID|OPMODE:0 means disconnect */
+ /* for STA, AP, ADHOC mode, report disconnect stauts to FW */
+ rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+ return;
+
+ mlmeext_sta_del_event_callback(adapter);
+
+ _enter_critical_bh(&pmlmepriv->lock, &irql2);
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+ if (pmlmepriv->to_roaming > 0)
+ pmlmepriv->to_roaming--; /* this stadel_event is caused by roaming, decrease to_roaming */
+ else if (pmlmepriv->to_roaming == 0)
+ pmlmepriv->to_roaming = adapter->registrypriv.max_roaming_times;
+
+ if (*((unsigned short *)(pstadel->rsvd)) != WLAN_REASON_EXPIRATION_CHK)
+ pmlmepriv->to_roaming = 0; /* don't roam */
+
+ rtw_free_uc_swdec_pending_queue(adapter);
+
+ rtw_free_assoc_resources(adapter, 1);
+ rtw_indicate_disconnect(adapter);
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ /* remove the network entry in scanned_queue */
+ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+ if (pwlan) {
+ pwlan->fixed = false;
+ rtw_free_network_nolock(pmlmepriv, pwlan);
+ }
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ _rtw_roaming(adapter, tgt_network);
+ }
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
+ check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
+ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+ rtw_free_stainfo(adapter, psta);
+ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+
+ if (adapter->stapriv.asoc_sta_count == 1) { /* a sta + bc/mc_stainfo (not Ibss_stainfo) */
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ /* free old ibss network */
+ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+ if (pwlan) {
+ pwlan->fixed = false;
+ rtw_free_network_nolock(pmlmepriv, pwlan);
+ }
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ /* re-create ibss */
+ pdev_network = &(adapter->registrypriv.dev_network);
+ pibss = adapter->registrypriv.dev_network.MacAddress;
+
+ memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network));
+
+ _rtw_memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
+ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid));
+
+ rtw_update_registrypriv_dev_network(adapter);
+
+ rtw_generate_random_ibss(pibss);
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
+ set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE);
+ }
+
+ if (rtw_createbss_cmd(adapter) != _SUCCESS)
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error=>stadel_event_callback: rtw_createbss_cmd status FAIL***\n "));
+ }
+ }
+ _exit_critical_bh(&pmlmepriv->lock, &irql2);
+_func_exit_;
+}
+
+void rtw_cpwm_event_callback(struct adapter *padapter, u8 *pbuf)
+{
+_func_enter_;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_cpwm_event_callback !!!\n"));
+_func_exit_;
+}
+
+/*
+* _rtw_join_timeout_handler - Timeout/faliure handler for CMD JoinBss
+* @adapter: pointer to struct adapter structure
+*/
+void _rtw_join_timeout_handler (struct adapter *adapter)
+{
+ unsigned long irql;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ int do_join_r;
+
+_func_enter_;
+
+ DBG_88E("%s, fw_state=%x\n", __func__, get_fwstate(pmlmepriv));
+
+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
+ return;
+
+
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+
+ if (pmlmepriv->to_roaming > 0) { /* join timeout caused by roaming */
+ while (1) {
+ pmlmepriv->to_roaming--;
+ if (pmlmepriv->to_roaming != 0) { /* try another , */
+ DBG_88E("%s try another roaming\n", __func__);
+ do_join_r = rtw_do_join(adapter);
+ if (_SUCCESS != do_join_r) {
+ DBG_88E("%s roaming do_join return %d\n", __func__ , do_join_r);
+ continue;
+ }
+ break;
+ } else {
+ DBG_88E("%s We've try roaming but fail\n", __func__);
+ rtw_indicate_disconnect(adapter);
+ break;
+ }
+ }
+ } else {
+ rtw_indicate_disconnect(adapter);
+ free_scanqueue(pmlmepriv);/* */
+ }
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+_func_exit_;
+}
+
+/*
+* rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey
+* @adapter: pointer to struct adapter structure
+*/
+void rtw_scan_timeout_handler (struct adapter *adapter)
+{
+ unsigned long irql;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+ DBG_88E(FUNC_ADPT_FMT" fw_state=%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv));
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+ rtw_indicate_scan_done(adapter, true);
+}
+
+static void rtw_auto_scan_handler(struct adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ /* auto site survey per 60sec */
+ if (pmlmepriv->scan_interval > 0) {
+ pmlmepriv->scan_interval--;
+ if (pmlmepriv->scan_interval == 0) {
+ DBG_88E("%s\n", __func__);
+ rtw_set_802_11_bssid_list_scan(padapter, NULL, 0);
+ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */
+ }
+ }
+}
+
+void rtw_dynamic_check_timer_handlder(struct adapter *adapter)
+{
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ struct registry_priv *pregistrypriv = &adapter->registrypriv;
+
+ if (!adapter)
+ return;
+ if (!adapter->hw_init_completed)
+ return;
+ if ((adapter->bDriverStopped) || (adapter->bSurpriseRemoved))
+ return;
+ if (adapter->net_closed)
+ return;
+ rtw_dynamic_chk_wk_cmd(adapter);
+
+ if (pregistrypriv->wifi_spec == 1) {
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+#endif
+ {
+ /* auto site survey */
+ rtw_auto_scan_handler(adapter);
+ }
+ }
+
+ rcu_read_lock();
+
+ if (rcu_dereference(adapter->pnetdev->rx_handler_data) &&
+ (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == true)) {
+ /* expire NAT2.5 entry */
+ nat25_db_expire(adapter);
+
+ if (adapter->pppoe_connection_in_progress > 0) {
+ adapter->pppoe_connection_in_progress--;
+ }
+
+ /* due to rtw_dynamic_check_timer_handlder() is called every 2 seconds */
+ if (adapter->pppoe_connection_in_progress > 0) {
+ adapter->pppoe_connection_in_progress--;
+ }
+ }
+
+ rcu_read_unlock();
+}
+
+#define RTW_SCAN_RESULT_EXPIRE 2000
+
+/*
+* Select a new join candidate from the original @param candidate and @param competitor
+* @return true: candidate is updated
+* @return false: candidate is not updated
+*/
+static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv
+ , struct wlan_network **candidate, struct wlan_network *competitor)
+{
+ int updated = false;
+ struct adapter *adapter = container_of(pmlmepriv, struct adapter, mlmepriv);
+
+
+ /* check bssid, if needed */
+ if (pmlmepriv->assoc_by_bssid) {
+ if (!_rtw_memcmp(competitor->network.MacAddress, pmlmepriv->assoc_bssid, ETH_ALEN))
+ goto exit;
+ }
+
+ /* check ssid, if needed */
+ if (pmlmepriv->assoc_ssid.Ssid && pmlmepriv->assoc_ssid.SsidLength) {
+ if (competitor->network.Ssid.SsidLength != pmlmepriv->assoc_ssid.SsidLength ||
+ _rtw_memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength) == false)
+ goto exit;
+ }
+
+ if (rtw_is_desired_network(adapter, competitor) == false)
+ goto exit;
+
+ if (pmlmepriv->to_roaming) {
+ if (rtw_get_passing_time_ms((u32)competitor->last_scanned) >= RTW_SCAN_RESULT_EXPIRE ||
+ is_same_ess(&competitor->network, &pmlmepriv->cur_network.network) == false)
+ goto exit;
+ }
+
+ if (*candidate == NULL || (*candidate)->network.Rssi < competitor->network.Rssi) {
+ *candidate = competitor;
+ updated = true;
+ }
+ if (updated) {
+ DBG_88E("[by_bssid:%u][assoc_ssid:%s]new candidate: %s(%pM rssi:%d\n",
+ pmlmepriv->assoc_by_bssid,
+ pmlmepriv->assoc_ssid.Ssid,
+ (*candidate)->network.Ssid.Ssid,
+ (*candidate)->network.MacAddress,
+ (int)(*candidate)->network.Rssi);
+ DBG_88E("[to_roaming:%u]\n", pmlmepriv->to_roaming);
+ }
+
+exit:
+ return updated;
+}
+
+/*
+Calling context:
+The caller of the sub-routine will be in critical section...
+The caller must hold the following spinlock
+pmlmepriv->lock
+*/
+
+int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv)
+{
+ unsigned long irql;
+ int ret;
+ struct list_head *phead;
+ struct adapter *adapter;
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ struct wlan_network *candidate = NULL;
+ u8 supp_ant_div = false;
+
+_func_enter_;
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+ phead = get_list_head(queue);
+ adapter = (struct adapter *)pmlmepriv->nic_hdl;
+ pmlmepriv->pscanned = get_next(phead);
+ while (!rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) {
+ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+ if (pnetwork == NULL) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork==NULL)\n", __func__));
+ ret = _FAIL;
+ goto exit;
+ }
+ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+ rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork);
+ }
+ if (candidate == NULL) {
+ DBG_88E("%s: return _FAIL(candidate==NULL)\n", __func__);
+ ret = _FAIL;
+ goto exit;
+ } else {
+ DBG_88E("%s: candidate: %s(%pM ch:%u)\n", __func__,
+ candidate->network.Ssid.Ssid, candidate->network.MacAddress,
+ candidate->network.Configuration.DSConfig);
+ }
+
+
+ /* check for situation of _FW_LINKED */
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+ DBG_88E("%s: _FW_LINKED while ask_for_joinbss!!!\n", __func__);
+
+ rtw_disassoc_cmd(adapter, 0, true);
+ rtw_indicate_disconnect(adapter);
+ rtw_free_assoc_resources(adapter, 0);
+ }
+
+ rtw_hal_get_def_var(adapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(supp_ant_div));
+ if (supp_ant_div) {
+ u8 cur_ant;
+ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(cur_ant));
+ DBG_88E("#### Opt_Ant_(%s), cur_Ant(%s)\n",
+ (2 == candidate->network.PhyInfo.Optimum_antenna) ? "A" : "B",
+ (2 == cur_ant) ? "A" : "B"
+ );
+ }
+
+ ret = rtw_joinbss_cmd(adapter, candidate);
+
+exit:
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+
+_func_exit_;
+
+ return ret;
+}
+
+int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv)
+{
+ struct cmd_obj *pcmd;
+ struct setauth_parm *psetauthparm;
+ struct cmd_priv *pcmdpriv = &(adapter->cmdpriv);
+ int res = _SUCCESS;
+
+_func_enter_;
+
+ pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd == NULL) {
+ res = _FAIL; /* try again */
+ goto exit;
+ }
+
+ psetauthparm = (struct setauth_parm *)rtw_zmalloc(sizeof(struct setauth_parm));
+ if (psetauthparm == NULL) {
+ kfree(pcmd);
+ res = _FAIL;
+ goto exit;
+ }
+ _rtw_memset(psetauthparm, 0, sizeof(struct setauth_parm));
+ psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm;
+ pcmd->cmdcode = _SetAuth_CMD_;
+ pcmd->parmbuf = (unsigned char *)psetauthparm;
+ pcmd->cmdsz = (sizeof(struct setauth_parm));
+ pcmd->rsp = NULL;
+ pcmd->rspsz = 0;
+ _rtw_init_listhead(&pcmd->list);
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+ ("after enqueue set_auth_cmd, auth_mode=%x\n",
+ psecuritypriv->dot11AuthAlgrthm));
+ res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+exit:
+_func_exit_;
+ return res;
+}
+
+int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, int keyid, u8 set_tx)
+{
+ u8 keylen;
+ struct cmd_obj *pcmd;
+ struct setkey_parm *psetkeyparm;
+ struct cmd_priv *pcmdpriv = &(adapter->cmdpriv);
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+ int res = _SUCCESS;
+
+_func_enter_;
+ pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd == NULL) {
+ res = _FAIL; /* try again */
+ goto exit;
+ }
+ psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm));
+ if (psetkeyparm == NULL) {
+ kfree(pcmd);
+ res = _FAIL;
+ goto exit;
+ }
+
+ _rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm));
+
+ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+ psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+ ("\n rtw_set_key: psetkeyparm->algorithm=(unsigned char)psecuritypriv->dot118021XGrpPrivacy=%d\n",
+ psetkeyparm->algorithm));
+ } else {
+ psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+ ("\n rtw_set_key: psetkeyparm->algorithm=(u8)psecuritypriv->dot11PrivacyAlgrthm=%d\n",
+ psetkeyparm->algorithm));
+ }
+ psetkeyparm->keyid = (u8)keyid;/* 0~3 */
+ psetkeyparm->set_tx = set_tx;
+ pmlmepriv->key_mask |= BIT(psetkeyparm->keyid);
+ DBG_88E("==> rtw_set_key algorithm(%x), keyid(%x), key_mask(%x)\n",
+ psetkeyparm->algorithm, psetkeyparm->keyid, pmlmepriv->key_mask);
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+ ("\n rtw_set_key: psetkeyparm->algorithm=%d psetkeyparm->keyid=(u8)keyid=%d\n",
+ psetkeyparm->algorithm, keyid));
+
+ switch (psetkeyparm->algorithm) {
+ case _WEP40_:
+ keylen = 5;
+ memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen);
+ break;
+ case _WEP104_:
+ keylen = 13;
+ memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen);
+ break;
+ case _TKIP_:
+ keylen = 16;
+ memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen);
+ psetkeyparm->grpkey = 1;
+ break;
+ case _AES_:
+ keylen = 16;
+ memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen);
+ psetkeyparm->grpkey = 1;
+ break;
+ default:
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+ ("\n rtw_set_key:psecuritypriv->dot11PrivacyAlgrthm=%x (must be 1 or 2 or 4 or 5)\n",
+ psecuritypriv->dot11PrivacyAlgrthm));
+ res = _FAIL;
+ goto exit;
+ }
+ pcmd->cmdcode = _SetKey_CMD_;
+ pcmd->parmbuf = (u8 *)psetkeyparm;
+ pcmd->cmdsz = (sizeof(struct setkey_parm));
+ pcmd->rsp = NULL;
+ pcmd->rspsz = 0;
+ _rtw_init_listhead(&pcmd->list);
+ res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+exit:
+_func_exit_;
+ return res;
+}
+
+/* adjust IEs for rtw_joinbss_cmd in WMM */
+int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len, uint initial_out_len)
+{
+ unsigned int ielength = 0;
+ unsigned int i, j;
+
+ i = 12; /* after the fixed IE */
+ while (i < in_len) {
+ ielength = initial_out_len;
+
+ if (in_ie[i] == 0xDD && in_ie[i+2] == 0x00 && in_ie[i+3] == 0x50 && in_ie[i+4] == 0xF2 && in_ie[i+5] == 0x02 && i+5 < in_len) {
+ /* WMM element ID and OUI */
+ /* Append WMM IE to the last index of out_ie */
+
+ for (j = i; j < i + 9; j++) {
+ out_ie[ielength] = in_ie[j];
+ ielength++;
+ }
+ out_ie[initial_out_len + 1] = 0x07;
+ out_ie[initial_out_len + 6] = 0x00;
+ out_ie[initial_out_len + 8] = 0x00;
+ break;
+ }
+ i += (in_ie[i+1]+2); /* to the next IE element */
+ }
+ return ielength;
+}
+
+/* */
+/* Ported from 8185: IsInPreAuthKeyList(). (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) */
+/* Added by Annie, 2006-05-07. */
+/* */
+/* Search by BSSID, */
+/* Return Value: */
+/* -1 :if there is no pre-auth key in the table */
+/* >= 0 :if there is pre-auth key, and return the entry id */
+/* */
+/* */
+
+static int SecIsInPMKIDList(struct adapter *Adapter, u8 *bssid)
+{
+ struct security_priv *psecuritypriv = &Adapter->securitypriv;
+ int i = 0;
+
+ do {
+ if ((psecuritypriv->PMKIDList[i].bUsed) &&
+ (_rtw_memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN) == true)) {
+ break;
+ } else {
+ i++;
+ /* continue; */
+ }
+
+ } while (i < NUM_PMKID_CACHE);
+
+ if (i == NUM_PMKID_CACHE) {
+ i = -1;/* Could not find. */
+ } else {
+ /* There is one Pre-Authentication Key for the specific BSSID. */
+ }
+ return i;
+}
+
+/* */
+/* Check the RSN IE length */
+/* If the RSN IE length <= 20, the RSN IE didn't include the PMKID information */
+/* 0-11th element in the array are the fixed IE */
+/* 12th element in the array is the IE */
+/* 13th element in the array is the IE length */
+/* */
+
+static int rtw_append_pmkid(struct adapter *Adapter, int iEntry, u8 *ie, uint ie_len)
+{
+ struct security_priv *psecuritypriv = &Adapter->securitypriv;
+
+ if (ie[13] <= 20) {
+ /* The RSN IE didn't include the PMK ID, append the PMK information */
+ ie[ie_len] = 1;
+ ie_len++;
+ ie[ie_len] = 0; /* PMKID count = 0x0100 */
+ ie_len++;
+ memcpy(&ie[ie_len], &psecuritypriv->PMKIDList[iEntry].PMKID, 16);
+
+ ie_len += 16;
+ ie[13] += 18;/* PMKID length = 2+16 */
+ }
+ return ie_len;
+}
+
+int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len)
+{
+ u8 authmode;
+ uint ielength;
+ int iEntry;
+
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ struct security_priv *psecuritypriv = &adapter->securitypriv;
+ uint ndisauthmode = psecuritypriv->ndisauthtype;
+ uint ndissecuritytype = psecuritypriv->ndisencryptstatus;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+ ("+rtw_restruct_sec_ie: ndisauthmode=%d ndissecuritytype=%d\n",
+ ndisauthmode, ndissecuritytype));
+
+ /* copy fixed ie only */
+ memcpy(out_ie, in_ie, 12);
+ ielength = 12;
+ if ((ndisauthmode == Ndis802_11AuthModeWPA) ||
+ (ndisauthmode == Ndis802_11AuthModeWPAPSK))
+ authmode = _WPA_IE_ID_;
+ if ((ndisauthmode == Ndis802_11AuthModeWPA2) ||
+ (ndisauthmode == Ndis802_11AuthModeWPA2PSK))
+ authmode = _WPA2_IE_ID_;
+
+ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
+ memcpy(out_ie+ielength, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len);
+
+ ielength += psecuritypriv->wps_ie_len;
+ } else if ((authmode == _WPA_IE_ID_) || (authmode == _WPA2_IE_ID_)) {
+ /* copy RSN or SSN */
+ memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1]+2);
+ ielength += psecuritypriv->supplicant_ie[1]+2;
+ rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie);
+ }
+
+ iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid);
+ if (iEntry < 0) {
+ return ielength;
+ } else {
+ if (authmode == _WPA2_IE_ID_)
+ ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength);
+ }
+
+_func_exit_;
+
+ return ielength;
+}
+
+void rtw_init_registrypriv_dev_network(struct adapter *adapter)
+{
+ struct registry_priv *pregistrypriv = &adapter->registrypriv;
+ struct eeprom_priv *peepriv = &adapter->eeprompriv;
+ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
+ u8 *myhwaddr = myid(peepriv);
+
+_func_enter_;
+
+ memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN);
+
+ memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(struct ndis_802_11_ssid));
+
+ pdev_network->Configuration.Length = sizeof(struct ndis_802_11_config);
+ pdev_network->Configuration.BeaconPeriod = 100;
+ pdev_network->Configuration.FHConfig.Length = 0;
+ pdev_network->Configuration.FHConfig.HopPattern = 0;
+ pdev_network->Configuration.FHConfig.HopSet = 0;
+ pdev_network->Configuration.FHConfig.DwellTime = 0;
+
+_func_exit_;
+}
+
+void rtw_update_registrypriv_dev_network(struct adapter *adapter)
+{
+ int sz = 0;
+ struct registry_priv *pregistrypriv = &adapter->registrypriv;
+ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
+ struct security_priv *psecuritypriv = &adapter->securitypriv;
+ struct wlan_network *cur_network = &adapter->mlmepriv.cur_network;
+
+_func_enter_;
+
+ pdev_network->Privacy = (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0); /* adhoc no 802.1x */
+
+ pdev_network->Rssi = 0;
+
+ switch (pregistrypriv->wireless_mode) {
+ case WIRELESS_11B:
+ pdev_network->NetworkTypeInUse = (Ndis802_11DS);
+ break;
+ case WIRELESS_11G:
+ case WIRELESS_11BG:
+ case WIRELESS_11_24N:
+ case WIRELESS_11G_24N:
+ case WIRELESS_11BG_24N:
+ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24);
+ break;
+ case WIRELESS_11A:
+ case WIRELESS_11A_5N:
+ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5);
+ break;
+ case WIRELESS_11ABGN:
+ if (pregistrypriv->channel > 14)
+ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5);
+ else
+ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24);
+ break;
+ default:
+ /* TODO */
+ break;
+ }
+
+ pdev_network->Configuration.DSConfig = (pregistrypriv->channel);
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("pregistrypriv->channel=%d, pdev_network->Configuration.DSConfig=0x%x\n",
+ pregistrypriv->channel, pdev_network->Configuration.DSConfig));
+
+ if (cur_network->network.InfrastructureMode == Ndis802_11IBSS)
+ pdev_network->Configuration.ATIMWindow = (0);
+
+ pdev_network->InfrastructureMode = (cur_network->network.InfrastructureMode);
+
+ /* 1. Supported rates */
+ /* 2. IE */
+
+ sz = rtw_generate_ie(pregistrypriv);
+ pdev_network->IELength = sz;
+ pdev_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network);
+
+ /* notes: translate IELength & Length after assign the Length to cmdsz in createbss_cmd(); */
+ /* pdev_network->IELength = cpu_to_le32(sz); */
+_func_exit_;
+}
+
+void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter)
+{
+_func_enter_;
+_func_exit_;
+}
+
+/* the fucntion is at passive_level */
+void rtw_joinbss_reset(struct adapter *padapter)
+{
+ u8 threshold;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+
+ /* todo: if you want to do something io/reg/hw setting before join_bss, please add code here */
+ pmlmepriv->num_FortyMHzIntolerant = 0;
+
+ pmlmepriv->num_sta_no_ht = 0;
+
+ phtpriv->ampdu_enable = false;/* reset to disabled */
+
+ /* TH = 1 => means that invalidate usb rx aggregation */
+ /* TH = 0 => means that validate usb rx aggregation, use init value. */
+ if (phtpriv->ht_option) {
+ if (padapter->registrypriv.wifi_spec == 1)
+ threshold = 1;
+ else
+ threshold = 0;
+ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
+ } else {
+ threshold = 1;
+ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
+ }
+}
+
+/* the fucntion is >= passive_level */
+unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len)
+{
+ u32 ielen, out_len;
+ enum ht_cap_ampdu_factor max_rx_ampdu_factor;
+ unsigned char *p;
+ struct rtw_ieee80211_ht_cap ht_capie;
+ unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00};
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct qos_priv *pqospriv = &pmlmepriv->qospriv;
+ struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+ u32 rx_packet_offset, max_recvbuf_sz;
+
+
+ phtpriv->ht_option = false;
+
+ p = rtw_get_ie(in_ie+12, _HT_CAPABILITY_IE_, &ielen, in_len-12);
+
+ if (p && ielen > 0) {
+ if (pqospriv->qos_option == 0) {
+ out_len = *pout_len;
+ rtw_set_ie(out_ie+out_len, _VENDOR_SPECIFIC_IE_,
+ _WMM_IE_Length_, WMM_IE, pout_len);
+
+ pqospriv->qos_option = 1;
+ }
+
+ out_len = *pout_len;
+
+ _rtw_memset(&ht_capie, 0, sizeof(struct rtw_ieee80211_ht_cap));
+
+ ht_capie.cap_info = IEEE80211_HT_CAP_SUP_WIDTH |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_TX_STBC |
+ IEEE80211_HT_CAP_DSSSCCK40;
+
+ rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset);
+ rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz);
+
+ /*
+ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+ AMPDU_para [4:2]:Min MPDU Start Spacing
+ */
+
+ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
+ ht_capie.ampdu_params_info = (max_rx_ampdu_factor&0x03);
+
+ if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)
+ ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2));
+ else
+ ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00);
+
+
+ rtw_set_ie(out_ie+out_len, _HT_CAPABILITY_IE_,
+ sizeof(struct rtw_ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len);
+
+ phtpriv->ht_option = true;
+
+ p = rtw_get_ie(in_ie+12, _HT_ADD_INFO_IE_, &ielen, in_len-12);
+ if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) {
+ out_len = *pout_len;
+ rtw_set_ie(out_ie+out_len, _HT_ADD_INFO_IE_, ielen, p+2 , pout_len);
+ }
+ }
+ return phtpriv->ht_option;
+}
+
+/* the fucntion is > passive_level (in critical_section) */
+void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len)
+{
+ u8 *p, max_ampdu_sz;
+ int len;
+ struct rtw_ieee80211_ht_cap *pht_capie;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if (!phtpriv->ht_option)
+ return;
+
+ if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable))
+ return;
+
+ DBG_88E("+rtw_update_ht_cap()\n");
+
+ /* maybe needs check if ap supports rx ampdu. */
+ if ((!phtpriv->ampdu_enable) && (pregistrypriv->ampdu_enable == 1)) {
+ if (pregistrypriv->wifi_spec == 1)
+ phtpriv->ampdu_enable = false;
+ else
+ phtpriv->ampdu_enable = true;
+ } else if (pregistrypriv->ampdu_enable == 2) {
+ phtpriv->ampdu_enable = true;
+ }
+
+
+ /* check Max Rx A-MPDU Size */
+ len = 0;
+ p = rtw_get_ie(pie+sizeof(struct ndis_802_11_fixed_ie), _HT_CAPABILITY_IE_, &len, ie_len-sizeof(struct ndis_802_11_fixed_ie));
+ if (p && len > 0) {
+ pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2);
+ max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_CAP_AMPDU_FACTOR);
+ max_ampdu_sz = 1 << (max_ampdu_sz+3); /* max_ampdu_sz (kbytes); */
+ phtpriv->rx_ampdu_maxlen = max_ampdu_sz;
+ }
+ len = 0;
+ p = rtw_get_ie(pie+sizeof(struct ndis_802_11_fixed_ie), _HT_ADD_INFO_IE_, &len, ie_len-sizeof(struct ndis_802_11_fixed_ie));
+
+ /* update cur_bwmode & cur_ch_offset */
+ if ((pregistrypriv->cbw40_enable) &&
+ (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & BIT(1)) &&
+ (pmlmeinfo->HT_info.infos[0] & BIT(2))) {
+ int i;
+ u8 rf_type;
+
+ padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+ /* update the MCS rates */
+ for (i = 0; i < 16; i++) {
+ if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R))
+ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i];
+ else
+ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i];
+ }
+ /* switch to the 40M Hz mode accoring to the AP */
+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40;
+ switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) {
+ case HT_EXTCHNL_OFFSET_UPPER:
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+ break;
+ case HT_EXTCHNL_OFFSET_LOWER:
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+ break;
+ default:
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ }
+ }
+
+ /* Config SM Power Save setting */
+ pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2;
+ if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
+ DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
+
+ /* Config current HT Protection mode. */
+ pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3;
+}
+
+void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+ u8 issued;
+ int priority;
+ struct sta_info *psta = NULL;
+ struct ht_priv *phtpriv;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+ s32 bmcst = IS_MCAST(pattrib->ra);
+
+ if (bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod < 100))
+ return;
+
+ priority = pattrib->priority;
+
+ if (pattrib->psta)
+ psta = pattrib->psta;
+ else
+ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
+
+ if (psta == NULL)
+ return;
+
+ phtpriv = &psta->htpriv;
+
+ if ((phtpriv->ht_option) && (phtpriv->ampdu_enable)) {
+ issued = (phtpriv->agg_enable_bitmap>>priority)&0x1;
+ issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1;
+
+ if (0 == issued) {
+ DBG_88E("rtw_issue_addbareq_cmd, p=%d\n", priority);
+ psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority);
+ rtw_addbareq_cmd(padapter, (u8) priority, pattrib->ra);
+ }
+ }
+}
+
+void rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network)
+{
+ unsigned long irql;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+ _rtw_roaming(padapter, tgt_network);
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ int do_join_r;
+
+ struct wlan_network *pnetwork;
+
+ if (tgt_network != NULL)
+ pnetwork = tgt_network;
+ else
+ pnetwork = &pmlmepriv->cur_network;
+
+ if (0 < pmlmepriv->to_roaming) {
+ DBG_88E("roaming from %s(%pM length:%d\n",
+ pnetwork->network.Ssid.Ssid, pnetwork->network.MacAddress,
+ pnetwork->network.Ssid.SsidLength);
+ memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid, sizeof(struct ndis_802_11_ssid));
+
+ pmlmepriv->assoc_by_bssid = false;
+
+ while (1) {
+ do_join_r = rtw_do_join(padapter);
+ if (_SUCCESS == do_join_r) {
+ break;
+ } else {
+ DBG_88E("roaming do_join return %d\n", do_join_r);
+ pmlmepriv->to_roaming--;
+
+ if (0 < pmlmepriv->to_roaming) {
+ continue;
+ } else {
+ DBG_88E("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__);
+ rtw_indicate_disconnect(padapter);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
new file mode 100644
index 00000000000..8b2ba26ba38
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -0,0 +1,8481 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_MLME_EXT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <rtw_mlme_ext.h>
+#include <wlan_bssdef.h>
+#include <mlme_osdep.h>
+#include <recv_osdep.h>
+
+static struct mlme_handler mlme_sta_tbl[] = {
+ {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq},
+ {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp},
+ {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq},
+ {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp},
+ {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq},
+ {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp},
+
+ /*----------------------------------------------------------
+ below 2 are reserved
+ -----------------------------------------------------------*/
+ {0, "DoReserved", &DoReserved},
+ {0, "DoReserved", &DoReserved},
+ {WIFI_BEACON, "OnBeacon", &OnBeacon},
+ {WIFI_ATIM, "OnATIM", &OnAtim},
+ {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc},
+ {WIFI_AUTH, "OnAuth", &OnAuthClient},
+ {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth},
+ {WIFI_ACTION, "OnAction", &OnAction},
+};
+
+static struct action_handler OnAction_tbl[] = {
+ {RTW_WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct},
+ {RTW_WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction_qos},
+ {RTW_WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction_dls},
+ {RTW_WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction_back},
+ {RTW_WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public},
+ {RTW_WLAN_CATEGORY_RADIO_MEASUREMENT, "ACTION_RADIO_MEASUREMENT", &DoReserved},
+ {RTW_WLAN_CATEGORY_FT, "ACTION_FT", &DoReserved},
+ {RTW_WLAN_CATEGORY_HT, "ACTION_HT", &OnAction_ht},
+ {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved},
+ {RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction_wmm},
+ {RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &OnAction_p2p},
+};
+
+
+static u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+
+/**************************************************
+OUI definitions for the vendor specific IE
+***************************************************/
+unsigned char RTW_WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01};
+unsigned char WMM_OUI[] = {0x00, 0x50, 0xf2, 0x02};
+unsigned char WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04};
+unsigned char P2P_OUI[] = {0x50, 0x6F, 0x9A, 0x09};
+unsigned char WFD_OUI[] = {0x50, 0x6F, 0x9A, 0x0A};
+
+unsigned char WMM_INFO_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
+unsigned char WMM_PARA_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
+
+unsigned char WPA_TKIP_CIPHER[4] = {0x00, 0x50, 0xf2, 0x02};
+unsigned char RSN_TKIP_CIPHER[4] = {0x00, 0x0f, 0xac, 0x02};
+
+extern unsigned char REALTEK_96B_IE[];
+
+/********************************************************
+MCS rate definitions
+*********************************************************/
+unsigned char MCS_rate_2R[16] = {0xff, 0xff, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+unsigned char MCS_rate_1R[16] = {0xff, 0x00, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+
+/********************************************************
+ChannelPlan definitions
+*********************************************************/
+static struct rt_channel_plan_2g RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = {
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, /* 0x02, RT_CHANNEL_DOMAIN_2G_FCC1 */
+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, /* 0x03, RT_CHANNEL_DOMAIN_2G_MIKK1 */
+ {{10, 11, 12, 13}, 4}, /* 0x04, RT_CHANNEL_DOMAIN_2G_ETSI2 */
+ {{}, 0}, /* 0x05, RT_CHANNEL_DOMAIN_2G_NULL */
+};
+
+static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = {
+ /* 0x00 ~ 0x1F , Old Define ===== */
+ {0x02}, /* 0x00, RT_CHANNEL_DOMAIN_FCC */
+ {0x02}, /* 0x01, RT_CHANNEL_DOMAIN_IC */
+ {0x01}, /* 0x02, RT_CHANNEL_DOMAIN_ETSI */
+ {0x01}, /* 0x03, RT_CHANNEL_DOMAIN_SPAIN */
+ {0x01}, /* 0x04, RT_CHANNEL_DOMAIN_FRANCE */
+ {0x03}, /* 0x05, RT_CHANNEL_DOMAIN_MKK */
+ {0x03}, /* 0x06, RT_CHANNEL_DOMAIN_MKK1 */
+ {0x01}, /* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */
+ {0x03}, /* 0x08, RT_CHANNEL_DOMAIN_TELEC */
+ {0x03}, /* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */
+ {0x00}, /* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */
+ {0x02}, /* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */
+ {0x01}, /* 0x0C, RT_CHANNEL_DOMAIN_CHINA */
+ {0x02}, /* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */
+ {0x02}, /* 0x0E, RT_CHANNEL_DOMAIN_KOREA */
+ {0x02}, /* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */
+ {0x01}, /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */
+ {0x02}, /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */
+ {0x01}, /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
+ {0x00}, /* 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G */
+ {0x02}, /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */
+ {0x00}, /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */
+ {0x00}, /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */
+ {0x03}, /* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
+ {0x05}, /* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */
+ {0x02}, /* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */
+ {0x00}, /* 0x1A, */
+ {0x00}, /* 0x1B, */
+ {0x00}, /* 0x1C, */
+ {0x00}, /* 0x1D, */
+ {0x00}, /* 0x1E, */
+ {0x05}, /* 0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G */
+ /* 0x20 ~ 0x7F , New Define ===== */
+ {0x00}, /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */
+ {0x01}, /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */
+ {0x02}, /* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */
+ {0x03}, /* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */
+ {0x04}, /* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */
+ {0x02}, /* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */
+ {0x00}, /* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */
+ {0x03}, /* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */
+ {0x00}, /* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */
+ {0x00}, /* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */
+ {0x00}, /* 0x2A, */
+ {0x00}, /* 0x2B, */
+ {0x00}, /* 0x2C, */
+ {0x00}, /* 0x2D, */
+ {0x00}, /* 0x2E, */
+ {0x00}, /* 0x2F, */
+ {0x00}, /* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */
+ {0x00}, /* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */
+ {0x00}, /* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */
+ {0x00}, /* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */
+ {0x02}, /* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */
+ {0x00}, /* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */
+ {0x00}, /* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */
+ {0x03}, /* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */
+ {0x03}, /* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */
+ {0x02}, /* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */
+ {0x00}, /* 0x3A, */
+ {0x00}, /* 0x3B, */
+ {0x00}, /* 0x3C, */
+ {0x00}, /* 0x3D, */
+ {0x00}, /* 0x3E, */
+ {0x00}, /* 0x3F, */
+ {0x02}, /* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */
+ {0x03}, /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G */
+};
+
+static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03}; /* use the conbination for max channel numbers */
+
+/*
+ * Search the @param channel_num in given @param channel_set
+ * @ch_set: the given channel set
+ * @ch: the given channel number
+ *
+ * return the index of channel_num in channel_set, -1 if not found
+ */
+int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch)
+{
+ int i;
+ for (i = 0; ch_set[i].ChannelNum != 0; i++) {
+ if (ch == ch_set[i].ChannelNum)
+ break;
+ }
+
+ if (i >= ch_set[i].ChannelNum)
+ return -1;
+ return i;
+}
+
+/****************************************************************************
+
+Following are the initialization functions for WiFi MLME
+
+*****************************************************************************/
+
+int init_hw_mlme_ext(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+ return _SUCCESS;
+}
+
+static void init_mlme_ext_priv_value(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ unsigned char mixed_datarate[NumRates] = {
+ _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_,
+ _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_,
+ _48M_RATE_, _54M_RATE_, 0xff
+ };
+ unsigned char mixed_basicrate[NumRates] = {
+ _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_,
+ _12M_RATE_, _24M_RATE_, 0xff,
+ };
+
+ ATOMIC_SET(&pmlmeext->event_seq, 0);
+ pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */
+
+ pmlmeext->cur_channel = padapter->registrypriv.channel;
+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ pmlmeext->oper_channel = pmlmeext->cur_channel ;
+ pmlmeext->oper_bwmode = pmlmeext->cur_bwmode;
+ pmlmeext->oper_ch_offset = pmlmeext->cur_ch_offset;
+ pmlmeext->retry = 0;
+
+ pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode;
+
+ memcpy(pmlmeext->datarate, mixed_datarate, NumRates);
+ memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates);
+
+ pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB;
+
+ pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
+ pmlmeext->sitesurvey_res.channel_idx = 0;
+ pmlmeext->sitesurvey_res.bss_cnt = 0;
+ pmlmeext->scan_abort = false;
+
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+ pmlmeinfo->reauth_count = 0;
+ pmlmeinfo->reassoc_count = 0;
+ pmlmeinfo->link_count = 0;
+ pmlmeinfo->auth_seq = 0;
+ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open;
+ pmlmeinfo->key_index = 0;
+ pmlmeinfo->iv = 0;
+
+ pmlmeinfo->enc_algo = _NO_PRIVACY_;
+ pmlmeinfo->authModeToggle = 0;
+
+ _rtw_memset(pmlmeinfo->chg_txt, 0, 128);
+
+ pmlmeinfo->slotTime = SHORT_SLOT_TIME;
+ pmlmeinfo->preamble_mode = PREAMBLE_AUTO;
+
+ pmlmeinfo->dialogToken = 0;
+
+ pmlmeext->action_public_rxseq = 0xffff;
+ pmlmeext->action_public_dialog_token = 0xff;
+}
+
+static int has_channel(struct rt_channel_info *channel_set,
+ u8 chanset_size,
+ u8 chan) {
+ int i;
+
+ for (i = 0; i < chanset_size; i++) {
+ if (channel_set[i].ChannelNum == chan)
+ return 1;
+ }
+ return 0;
+}
+
+static void init_channel_list(struct adapter *padapter, struct rt_channel_info *channel_set,
+ u8 chanset_size,
+ struct p2p_channels *channel_list) {
+ struct p2p_oper_class_map op_class[] = {
+ { IEEE80211G, 81, 1, 13, 1, BW20 },
+ { IEEE80211G, 82, 14, 14, 1, BW20 },
+ { -1, 0, 0, 0, 0, BW20 }
+ };
+
+ int cla, op;
+
+ cla = 0;
+
+ for (op = 0; op_class[op].op_class; op++) {
+ u8 ch;
+ struct p2p_oper_class_map *o = &op_class[op];
+ struct p2p_reg_class *reg = NULL;
+
+ for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+ if (!has_channel(channel_set, chanset_size, ch)) {
+ continue;
+ }
+
+ if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc))
+ continue;
+
+ if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) &&
+ ((BW40MINUS == o->bw) || (BW40PLUS == o->bw)))
+ continue;
+
+ if (reg == NULL) {
+ reg = &channel_list->reg_class[cla];
+ cla++;
+ reg->reg_class = o->op_class;
+ reg->channels = 0;
+ }
+ reg->channel[reg->channels] = ch;
+ reg->channels++;
+ }
+ }
+ channel_list->reg_classes = cla;
+}
+
+static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_channel_info *channel_set)
+{
+ u8 index, chanset_size = 0;
+ u8 b2_4GBand = false;
+ u8 Index2G = 0;
+
+ _rtw_memset(channel_set, 0, sizeof(struct rt_channel_info) * MAX_CHANNEL_NUM);
+
+ if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) {
+ DBG_88E("ChannelPlan ID %x error !!!!!\n", ChannelPlan);
+ return chanset_size;
+ }
+
+ if (padapter->registrypriv.wireless_mode & WIRELESS_11G) {
+ b2_4GBand = true;
+ if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan)
+ Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G;
+ else
+ Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G;
+ }
+
+ if (b2_4GBand) {
+ for (index = 0; index < RTW_ChannelPlan2G[Index2G].Len; index++) {
+ channel_set[chanset_size].ChannelNum = RTW_ChannelPlan2G[Index2G].Channel[index];
+
+ if ((RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN == ChannelPlan) ||/* Channel 1~11 is active, and 12~14 is passive */
+ (RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G == ChannelPlan)) {
+ if (channel_set[chanset_size].ChannelNum >= 1 && channel_set[chanset_size].ChannelNum <= 11)
+ channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+ else if ((channel_set[chanset_size].ChannelNum >= 12 && channel_set[chanset_size].ChannelNum <= 14))
+ channel_set[chanset_size].ScanType = SCAN_PASSIVE;
+ } else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == ChannelPlan ||
+ RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) {/* channel 12~13, passive scan */
+ if (channel_set[chanset_size].ChannelNum <= 11)
+ channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+ else
+ channel_set[chanset_size].ScanType = SCAN_PASSIVE;
+ } else {
+ channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+ }
+
+ chanset_size++;
+ }
+ }
+ return chanset_size;
+}
+
+int init_mlme_ext_priv(struct adapter *padapter)
+{
+ int res = _SUCCESS;
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ pmlmeext->padapter = padapter;
+
+ init_mlme_ext_priv_value(padapter);
+ pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq;
+
+ init_mlme_ext_timer(padapter);
+
+#ifdef CONFIG_88EU_AP_MODE
+ init_mlme_ap_info(padapter);
+#endif
+
+ pmlmeext->max_chan_nums = init_channel_set(padapter, pmlmepriv->ChannelPlan, pmlmeext->channel_set);
+ init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list);
+
+ pmlmeext->chan_scan_time = SURVEY_TO;
+ pmlmeext->mlmeext_init = true;
+
+
+ pmlmeext->active_keep_alive_check = true;
+
+ return res;
+}
+
+void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext)
+{
+ struct adapter *padapter = pmlmeext->padapter;
+
+ if (!padapter)
+ return;
+
+ if (padapter->bDriverStopped) {
+ _cancel_timer_ex(&pmlmeext->survey_timer);
+ _cancel_timer_ex(&pmlmeext->link_timer);
+ /* _cancel_timer_ex(&pmlmeext->ADDBA_timer); */
+ }
+}
+
+static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, union recv_frame *precv_frame)
+{
+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+
+ if (ptable->func) {
+ /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
+ if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) &&
+ !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
+ return;
+ ptable->func(padapter, precv_frame);
+ }
+}
+
+void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ int index;
+ struct mlme_handler *ptable;
+#ifdef CONFIG_88EU_AP_MODE
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#endif /* CONFIG_88EU_AP_MODE */
+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe));
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("+mgt_dispatcher: type(0x%x) subtype(0x%x)\n",
+ GetFrameType(pframe), GetFrameSubType(pframe)));
+
+ if (GetFrameType(pframe) != WIFI_MGT_TYPE) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("mgt_dispatcher: type(0x%x) error!\n", GetFrameType(pframe)));
+ return;
+ }
+
+ /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
+ if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) &&
+ !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
+ return;
+
+ ptable = mlme_sta_tbl;
+
+ index = GetFrameSubType(pframe) >> 4;
+
+ if (index > 13) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Currently we do not support reserved sub-fr-type=%d\n", index));
+ return;
+ }
+ ptable += index;
+
+ if (psta != NULL) {
+ if (GetRetry(pframe)) {
+ if (precv_frame->u.hdr.attrib.seq_num == psta->RxMgmtFrameSeqNum) {
+ /* drop the duplicate management frame */
+ DBG_88E("Drop duplicate management frame with seq_num=%d.\n", precv_frame->u.hdr.attrib.seq_num);
+ return;
+ }
+ }
+ psta->RxMgmtFrameSeqNum = precv_frame->u.hdr.attrib.seq_num;
+ }
+
+#ifdef CONFIG_88EU_AP_MODE
+ switch (GetFrameSubType(pframe)) {
+ case WIFI_AUTH:
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+ ptable->func = &OnAuth;
+ else
+ ptable->func = &OnAuthClient;
+ /* fall through */
+ case WIFI_ASSOCREQ:
+ case WIFI_REASSOCREQ:
+ _mgt_dispatcher(padapter, ptable, precv_frame);
+ break;
+ case WIFI_PROBEREQ:
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+ _mgt_dispatcher(padapter, ptable, precv_frame);
+ else
+ _mgt_dispatcher(padapter, ptable, precv_frame);
+ break;
+ case WIFI_BEACON:
+ _mgt_dispatcher(padapter, ptable, precv_frame);
+ break;
+ case WIFI_ACTION:
+ _mgt_dispatcher(padapter, ptable, precv_frame);
+ break;
+ default:
+ _mgt_dispatcher(padapter, ptable, precv_frame);
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+ rtw_hostapd_mlme_rx(padapter, precv_frame);
+ break;
+ }
+#else
+ _mgt_dispatcher(padapter, ptable, precv_frame);
+#endif
+}
+
+#ifdef CONFIG_88EU_P2P
+static u32 p2p_listen_state_process(struct adapter *padapter, unsigned char *da)
+{
+ bool response = true;
+
+ /* do nothing if the device name is empty */
+ if (!padapter->wdinfo.device_name_len)
+ response = false;
+
+ if (response)
+ issue_probersp_p2p(padapter, da);
+
+ return _SUCCESS;
+}
+#endif /* CONFIG_88EU_P2P */
+
+
+/****************************************************************************
+
+Following are the callback functions for each subtype of the management frames
+
+*****************************************************************************/
+
+unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ unsigned int ielen;
+ unsigned char *p;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur = &(pmlmeinfo->network);
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ uint len = precv_frame->u.hdr.len;
+ u8 is_valid_p2p_probereq = false;
+
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 wifi_test_chk_rate = 1;
+
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) &&
+ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) &&
+ !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) &&
+ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) &&
+ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN)) {
+ /* mcs_rate = 0 -> CCK 1M rate */
+ /* mcs_rate = 1 -> CCK 2M rate */
+ /* mcs_rate = 2 -> CCK 5.5M rate */
+ /* mcs_rate = 3 -> CCK 11M rate */
+ /* In the P2P mode, the driver should not support the CCK rate */
+
+ /* Commented by Kurt 2012/10/16 */
+ /* IOT issue: Google Nexus7 use 1M rate to send p2p_probe_req after GO nego completed and Nexus7 is client */
+ if (wifi_test_chk_rate == 1) {
+ is_valid_p2p_probereq = process_probe_req_p2p_ie(pwdinfo, pframe, len);
+ if (is_valid_p2p_probereq) {
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
+ /* FIXME */
+ report_survey_event(padapter, precv_frame);
+ p2p_listen_state_process(padapter, get_sa(pframe));
+
+ return _SUCCESS;
+ }
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+ goto _continue;
+ }
+ }
+ }
+
+_continue:
+#endif /* CONFIG_88EU_P2P */
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+ return _SUCCESS;
+
+ if (!check_fwstate(pmlmepriv, _FW_LINKED) &&
+ !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE))
+ return _SUCCESS;
+
+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen,
+ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_);
+
+ /* check (wildcard) SSID */
+ if (p != NULL) {
+ if (is_valid_p2p_probereq)
+ goto _issue_probersp;
+
+ if ((ielen != 0 && !_rtw_memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) ||
+ (ielen == 0 && pmlmeinfo->hidden_ssid_mode))
+ return _SUCCESS;
+
+_issue_probersp:
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) &&
+ pmlmepriv->cur_network.join_res)
+ issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq);
+ }
+ return _SUCCESS;
+}
+
+unsigned int OnProbeRsp(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+#endif
+
+#ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
+ if (pwdinfo->tx_prov_disc_info.benable) {
+ if (_rtw_memcmp(pwdinfo->tx_prov_disc_info.peerIFAddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+ pwdinfo->tx_prov_disc_info.benable = false;
+ issue_p2p_provision_request(padapter,
+ pwdinfo->tx_prov_disc_info.ssid.Ssid,
+ pwdinfo->tx_prov_disc_info.ssid.SsidLength,
+ pwdinfo->tx_prov_disc_info.peerDevAddr);
+ } else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ pwdinfo->tx_prov_disc_info.benable = false;
+ issue_p2p_provision_request(padapter, NULL, 0,
+ pwdinfo->tx_prov_disc_info.peerDevAddr);
+ }
+ }
+ }
+ return _SUCCESS;
+ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
+ if (pwdinfo->nego_req_info.benable) {
+ DBG_88E("[%s] P2P State is GONEGO ING!\n", __func__);
+ if (_rtw_memcmp(pwdinfo->nego_req_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
+ pwdinfo->nego_req_info.benable = false;
+ issue_p2p_GO_request(padapter, pwdinfo->nego_req_info.peerDevAddr);
+ }
+ }
+ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) {
+ if (pwdinfo->invitereq_info.benable) {
+ DBG_88E("[%s] P2P_STATE_TX_INVITE_REQ!\n", __func__);
+ if (_rtw_memcmp(pwdinfo->invitereq_info.peer_macaddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
+ pwdinfo->invitereq_info.benable = false;
+ issue_p2p_invitation_request(padapter, pwdinfo->invitereq_info.peer_macaddr);
+ }
+ }
+ }
+#endif
+
+
+ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+ report_survey_event(padapter, precv_frame);
+ return _SUCCESS;
+ }
+
+ return _SUCCESS;
+}
+
+unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ int cam_idx;
+ struct sta_info *psta;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ uint len = precv_frame->u.hdr.len;
+ struct wlan_bssid_ex *pbss;
+ int ret = _SUCCESS;
+
+ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+ report_survey_event(padapter, precv_frame);
+ return _SUCCESS;
+ }
+
+ if (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) {
+ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
+ /* we should update current network before auth, or some IE is wrong */
+ pbss = (struct wlan_bssid_ex *)rtw_malloc(sizeof(struct wlan_bssid_ex));
+ if (pbss) {
+ if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) {
+ update_network(&(pmlmepriv->cur_network.network), pbss, padapter, true);
+ rtw_get_bcn_info(&(pmlmepriv->cur_network));
+ }
+ kfree(pbss);
+ }
+
+ /* check the vendor of the assoc AP */
+ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe+sizeof(struct rtw_ieee80211_hdr_3addr), len-sizeof(struct rtw_ieee80211_hdr_3addr));
+
+ /* update TSF Value */
+ update_TSF(pmlmeext, pframe, len);
+
+ /* start auth */
+ start_clnt_auth(padapter);
+
+ return _SUCCESS;
+ }
+
+ if (((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) {
+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+ if (psta != NULL) {
+ ret = rtw_check_bcn_info(padapter, pframe, len);
+ if (!ret) {
+ DBG_88E_LEVEL(_drv_info_, "ap has changed, disconnect now\n ");
+ receive_disconnect(padapter, pmlmeinfo->network.MacAddress , 65535);
+ return _SUCCESS;
+ }
+ /* update WMM, ERP in the beacon */
+ /* todo: the timer is used instead of the number of the beacon received */
+ if ((sta_rx_pkts(psta) & 0xf) == 0)
+ update_beacon_info(padapter, pframe, len, psta);
+ process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN));
+ }
+ } else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+ if (psta != NULL) {
+ /* update WMM, ERP in the beacon */
+ /* todo: the timer is used instead of the number of the beacon received */
+ if ((sta_rx_pkts(psta) & 0xf) == 0)
+ update_beacon_info(padapter, pframe, len, psta);
+ } else {
+ /* allocate a new CAM entry for IBSS station */
+ cam_idx = allocate_fw_sta_entry(padapter);
+ if (cam_idx == NUM_STA)
+ goto _END_ONBEACON_;
+
+ /* get supported rate */
+ if (update_sta_support_rate(padapter, (pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_), (len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) {
+ pmlmeinfo->FW_sta_info[cam_idx].status = 0;
+ goto _END_ONBEACON_;
+ }
+
+ /* update TSF Value */
+ update_TSF(pmlmeext, pframe, len);
+
+ /* report sta add event */
+ report_add_sta_event(padapter, GetAddr2Ptr(pframe), cam_idx);
+ }
+ }
+ }
+
+_END_ONBEACON_:
+
+ return _SUCCESS;
+}
+
+unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_AP_MODE
+ unsigned long irqL;
+ unsigned int auth_mode, ie_len;
+ u16 seq;
+ unsigned char *sa, *p;
+ u16 algorithm;
+ int status;
+ static struct sta_info stat;
+ struct sta_info *pstat = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ uint len = precv_frame->u.hdr.len;
+
+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+ return _FAIL;
+
+ DBG_88E("+OnAuth\n");
+
+ sa = GetAddr2Ptr(pframe);
+
+ auth_mode = psecuritypriv->dot11AuthAlgrthm;
+ seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + 2));
+ algorithm = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN));
+
+ DBG_88E("auth alg=%x, seq=%X\n", algorithm, seq);
+
+ if (auth_mode == 2 && psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ &&
+ psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)
+ auth_mode = 0;
+
+ if ((algorithm > 0 && auth_mode == 0) || /* rx a shared-key auth but shared not enabled */
+ (algorithm == 0 && auth_mode == 1)) { /* rx a open-system auth but shared-key is enabled */
+ DBG_88E("auth rejected due to bad alg [alg=%d, auth_mib=%d] %02X%02X%02X%02X%02X%02X\n",
+ algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]);
+
+ status = _STATS_NO_SUPP_ALG_;
+
+ goto auth_fail;
+ }
+
+ if (!rtw_access_ctrl(padapter, sa)) {
+ status = _STATS_UNABLE_HANDLE_STA_;
+ goto auth_fail;
+ }
+
+ pstat = rtw_get_stainfo(pstapriv, sa);
+ if (pstat == NULL) {
+ /* allocate a new one */
+ DBG_88E("going to alloc stainfo for sa=%pM\n", sa);
+ pstat = rtw_alloc_stainfo(pstapriv, sa);
+ if (pstat == NULL) {
+ DBG_88E(" Exceed the upper limit of supported clients...\n");
+ status = _STATS_UNABLE_HANDLE_STA_;
+ goto auth_fail;
+ }
+
+ pstat->state = WIFI_FW_AUTH_NULL;
+ pstat->auth_seq = 0;
+ } else {
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ if (!rtw_is_list_empty(&pstat->asoc_list)) {
+ rtw_list_delete(&pstat->asoc_list);
+ pstapriv->asoc_list_cnt--;
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ if (seq == 1) {
+ /* TODO: STA re_auth and auth timeout */
+ }
+ }
+
+ _enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+ if (rtw_is_list_empty(&pstat->auth_list)) {
+ rtw_list_insert_tail(&pstat->auth_list, &pstapriv->auth_list);
+ pstapriv->auth_list_cnt++;
+ }
+ _exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+ if (pstat->auth_seq == 0)
+ pstat->expire_to = pstapriv->auth_to;
+
+ if ((pstat->auth_seq + 1) != seq) {
+ DBG_88E("(1)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
+ seq, pstat->auth_seq+1);
+ status = _STATS_OUT_OF_AUTH_SEQ_;
+ goto auth_fail;
+ }
+
+ if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2)) {
+ if (seq == 1) {
+ pstat->state &= ~WIFI_FW_AUTH_NULL;
+ pstat->state |= WIFI_FW_AUTH_SUCCESS;
+ pstat->expire_to = pstapriv->assoc_to;
+ pstat->authalg = algorithm;
+ } else {
+ DBG_88E("(2)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
+ seq, pstat->auth_seq+1);
+ status = _STATS_OUT_OF_AUTH_SEQ_;
+ goto auth_fail;
+ }
+ } else { /* shared system or auto authentication */
+ if (seq == 1) {
+ /* prepare for the challenging txt... */
+
+ pstat->state &= ~WIFI_FW_AUTH_NULL;
+ pstat->state |= WIFI_FW_AUTH_STATE;
+ pstat->authalg = algorithm;
+ pstat->auth_seq = 2;
+ } else if (seq == 3) {
+ /* checking for challenging txt... */
+ DBG_88E("checking for challenging txt...\n");
+
+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_ , _CHLGETXT_IE_, (int *)&ie_len,
+ len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4);
+
+ if ((p == NULL) || (ie_len <= 0)) {
+ DBG_88E("auth rejected because challenge failure!(1)\n");
+ status = _STATS_CHALLENGE_FAIL_;
+ goto auth_fail;
+ }
+
+ if (_rtw_memcmp((void *)(p + 2), pstat->chg_txt, 128)) {
+ pstat->state &= (~WIFI_FW_AUTH_STATE);
+ pstat->state |= WIFI_FW_AUTH_SUCCESS;
+ /* challenging txt is correct... */
+ pstat->expire_to = pstapriv->assoc_to;
+ } else {
+ DBG_88E("auth rejected because challenge failure!\n");
+ status = _STATS_CHALLENGE_FAIL_;
+ goto auth_fail;
+ }
+ } else {
+ DBG_88E("(3)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
+ seq, pstat->auth_seq+1);
+ status = _STATS_OUT_OF_AUTH_SEQ_;
+ goto auth_fail;
+ }
+ }
+
+ /* Now, we are going to issue_auth... */
+ pstat->auth_seq = seq + 1;
+
+#ifdef CONFIG_88EU_AP_MODE
+ issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_));
+#endif
+
+ if (pstat->state & WIFI_FW_AUTH_SUCCESS)
+ pstat->auth_seq = 0;
+
+ return _SUCCESS;
+
+auth_fail:
+
+ if (pstat)
+ rtw_free_stainfo(padapter , pstat);
+
+ pstat = &stat;
+ _rtw_memset((char *)pstat, '\0', sizeof(stat));
+ pstat->auth_seq = 2;
+ memcpy(pstat->hwaddr, sa, 6);
+
+#ifdef CONFIG_88EU_AP_MODE
+ issue_auth(padapter, pstat, (unsigned short)status);
+#endif
+
+#endif
+ return _FAIL;
+}
+
+unsigned int OnAuthClient(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ unsigned int seq, len, status, offset;
+ unsigned char *p;
+ unsigned int go2asoc = 0;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ uint pkt_len = precv_frame->u.hdr.len;
+
+ DBG_88E("%s\n", __func__);
+
+ /* check A1 matches or not */
+ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN))
+ return _SUCCESS;
+
+ if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE))
+ return _SUCCESS;
+
+ offset = (GetPrivacy(pframe)) ? 4 : 0;
+
+ seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 2));
+ status = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 4));
+
+ if (status != 0) {
+ DBG_88E("clnt auth fail, status: %d\n", status);
+ if (status == 13) { /* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */
+ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
+ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open;
+ else
+ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared;
+ }
+
+ set_link_timer(pmlmeext, 1);
+ goto authclnt_fail;
+ }
+
+ if (seq == 2) {
+ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) {
+ /* legendary shared system */
+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len,
+ pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_);
+
+ if (p == NULL)
+ goto authclnt_fail;
+
+ memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len);
+ pmlmeinfo->auth_seq = 3;
+ issue_auth(padapter, NULL, 0);
+ set_link_timer(pmlmeext, REAUTH_TO);
+
+ return _SUCCESS;
+ } else {
+ /* open system */
+ go2asoc = 1;
+ }
+ } else if (seq == 4) {
+ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
+ go2asoc = 1;
+ else
+ goto authclnt_fail;
+ } else {
+ /* this is also illegal */
+ goto authclnt_fail;
+ }
+
+ if (go2asoc) {
+ DBG_88E_LEVEL(_drv_info_, "auth success, start assoc\n");
+ start_clnt_assoc(padapter);
+ return _SUCCESS;
+ }
+authclnt_fail:
+ return _FAIL;
+}
+
+unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_AP_MODE
+ unsigned long irqL;
+ u16 capab_info;
+ struct rtw_ieee802_11_elems elems;
+ struct sta_info *pstat;
+ unsigned char reassoc, *p, *pos, *wpa_ie;
+ unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
+ int i, ie_len, wpa_ie_len, left;
+ unsigned char supportRate[16];
+ int supportRateNum;
+ unsigned short status = _STATS_SUCCESSFUL_;
+ unsigned short frame_type, ie_offset = 0;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur = &(pmlmeinfo->network);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ uint pkt_len = precv_frame->u.hdr.len;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 p2p_status_code = P2P_STATUS_SUCCESS;
+ u8 *p2pie;
+ u32 p2pielen = 0;
+#endif /* CONFIG_88EU_P2P */
+
+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+ return _FAIL;
+
+ frame_type = GetFrameSubType(pframe);
+ if (frame_type == WIFI_ASSOCREQ) {
+ reassoc = 0;
+ ie_offset = _ASOCREQ_IE_OFFSET_;
+ } else { /* WIFI_REASSOCREQ */
+ reassoc = 1;
+ ie_offset = _REASOCREQ_IE_OFFSET_;
+ }
+
+
+ if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) {
+ DBG_88E("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
+ "\n", reassoc, (unsigned long)pkt_len);
+ return _FAIL;
+ }
+
+ pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+ if (pstat == (struct sta_info *)NULL) {
+ status = _RSON_CLS2_;
+ goto asoc_class2_error;
+ }
+
+ capab_info = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN);
+
+ left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset);
+ pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset);
+
+
+ DBG_88E("%s\n", __func__);
+
+ /* check if this stat has been successfully authenticated/assocated */
+ if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) {
+ if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) {
+ status = _RSON_CLS2_;
+ goto asoc_class2_error;
+ } else {
+ pstat->state &= (~WIFI_FW_ASSOC_SUCCESS);
+ pstat->state |= WIFI_FW_ASSOC_STATE;
+ }
+ } else {
+ pstat->state &= (~WIFI_FW_AUTH_SUCCESS);
+ pstat->state |= WIFI_FW_ASSOC_STATE;
+ }
+ pstat->capability = capab_info;
+ /* now parse all ieee802_11 ie to point to elems */
+ if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed ||
+ !elems.ssid) {
+ DBG_88E("STA %pM sent invalid association request\n",
+ pstat->hwaddr);
+ status = _STATS_FAILURE_;
+ goto OnAssocReqFail;
+ }
+
+
+ /* now we should check all the fields... */
+ /* checking SSID */
+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len,
+ pkt_len - WLAN_HDR_A3_LEN - ie_offset);
+ if (p == NULL)
+ status = _STATS_FAILURE_;
+
+ if (ie_len == 0) { /* broadcast ssid, however it is not allowed in assocreq */
+ status = _STATS_FAILURE_;
+ } else {
+ /* check if ssid match */
+ if (!_rtw_memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength))
+ status = _STATS_FAILURE_;
+
+ if (ie_len != cur->Ssid.SsidLength)
+ status = _STATS_FAILURE_;
+ }
+
+ if (_STATS_SUCCESSFUL_ != status)
+ goto OnAssocReqFail;
+
+ /* check if the supported rate is ok */
+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset);
+ if (p == NULL) {
+ DBG_88E("Rx a sta assoc-req which supported rate is empty!\n");
+ /* use our own rate set as statoin used */
+ /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */
+ /* supportRateNum = AP_BSSRATE_LEN; */
+
+ status = _STATS_FAILURE_;
+ goto OnAssocReqFail;
+ } else {
+ memcpy(supportRate, p+2, ie_len);
+ supportRateNum = ie_len;
+
+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _EXT_SUPPORTEDRATES_IE_ , &ie_len,
+ pkt_len - WLAN_HDR_A3_LEN - ie_offset);
+ if (p != NULL) {
+ if (supportRateNum <= sizeof(supportRate)) {
+ memcpy(supportRate+supportRateNum, p+2, ie_len);
+ supportRateNum += ie_len;
+ }
+ }
+ }
+
+ /* todo: mask supportRate between AP & STA -> move to update raid */
+ /* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */
+
+ /* update station supportRate */
+ pstat->bssratelen = supportRateNum;
+ memcpy(pstat->bssrateset, supportRate, supportRateNum);
+ UpdateBrateTblForSoftAP(pstat->bssrateset, pstat->bssratelen);
+
+ /* check RSN/WPA/WPS */
+ pstat->dot8021xalg = 0;
+ pstat->wpa_psk = 0;
+ pstat->wpa_group_cipher = 0;
+ pstat->wpa2_group_cipher = 0;
+ pstat->wpa_pairwise_cipher = 0;
+ pstat->wpa2_pairwise_cipher = 0;
+ _rtw_memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie));
+ if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) {
+ int group_cipher = 0, pairwise_cipher = 0;
+
+ wpa_ie = elems.rsn_ie;
+ wpa_ie_len = elems.rsn_ie_len;
+
+ if (rtw_parse_wpa2_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+ pstat->dot8021xalg = 1;/* psk, todo:802.1x */
+ pstat->wpa_psk |= BIT(1);
+
+ pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher;
+ pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher;
+
+ if (!pstat->wpa2_group_cipher)
+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+
+ if (!pstat->wpa2_pairwise_cipher)
+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ } else {
+ status = WLAN_STATUS_INVALID_IE;
+ }
+ } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) {
+ int group_cipher = 0, pairwise_cipher = 0;
+
+ wpa_ie = elems.wpa_ie;
+ wpa_ie_len = elems.wpa_ie_len;
+
+ if (rtw_parse_wpa_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+ pstat->dot8021xalg = 1;/* psk, todo:802.1x */
+ pstat->wpa_psk |= BIT(0);
+
+ pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher;
+ pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher;
+
+ if (!pstat->wpa_group_cipher)
+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+
+ if (!pstat->wpa_pairwise_cipher)
+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ } else {
+ status = WLAN_STATUS_INVALID_IE;
+ }
+ } else {
+ wpa_ie = NULL;
+ wpa_ie_len = 0;
+ }
+
+ if (_STATS_SUCCESSFUL_ != status)
+ goto OnAssocReqFail;
+
+ pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+ if (wpa_ie == NULL) {
+ if (elems.wps_ie) {
+ DBG_88E("STA included WPS IE in "
+ "(Re)Association Request - assume WPS is "
+ "used\n");
+ pstat->flags |= WLAN_STA_WPS;
+ /* wpabuf_free(sta->wps_ie); */
+ /* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */
+ /* elems.wps_ie_len - 4); */
+ } else {
+ DBG_88E("STA did not include WPA/RSN IE "
+ "in (Re)Association Request - possible WPS "
+ "use\n");
+ pstat->flags |= WLAN_STA_MAYBE_WPS;
+ }
+
+
+ /* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */
+ /* that the selected registrar of AP is _FLASE */
+ if ((psecuritypriv->wpa_psk > 0) && (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) {
+ if (pmlmepriv->wps_beacon_ie) {
+ u8 selected_registrar = 0;
+
+ rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR , &selected_registrar, NULL);
+
+ if (!selected_registrar) {
+ DBG_88E("selected_registrar is false , or AP is not ready to do WPS\n");
+
+ status = _STATS_UNABLE_HANDLE_STA_;
+
+ goto OnAssocReqFail;
+ }
+ }
+ }
+ } else {
+ int copy_len;
+
+ if (psecuritypriv->wpa_psk == 0) {
+ DBG_88E("STA %pM: WPA/RSN IE in association "
+ "request, but AP don't support WPA/RSN\n", pstat->hwaddr);
+
+ status = WLAN_STATUS_INVALID_IE;
+
+ goto OnAssocReqFail;
+ }
+
+ if (elems.wps_ie) {
+ DBG_88E("STA included WPS IE in "
+ "(Re)Association Request - WPS is "
+ "used\n");
+ pstat->flags |= WLAN_STA_WPS;
+ copy_len = 0;
+ } else {
+ copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)) : (wpa_ie_len+2);
+ }
+ if (copy_len > 0)
+ memcpy(pstat->wpa_ie, wpa_ie-2, copy_len);
+ }
+ /* check if there is WMM IE & support WWM-PS */
+ pstat->flags &= ~WLAN_STA_WME;
+ pstat->qos_option = 0;
+ pstat->qos_info = 0;
+ pstat->has_legacy_ac = true;
+ pstat->uapsd_vo = 0;
+ pstat->uapsd_vi = 0;
+ pstat->uapsd_be = 0;
+ pstat->uapsd_bk = 0;
+ if (pmlmepriv->qospriv.qos_option) {
+ p = pframe + WLAN_HDR_A3_LEN + ie_offset; ie_len = 0;
+ for (;;) {
+ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset);
+ if (p != NULL) {
+ if (_rtw_memcmp(p+2, WMM_IE, 6)) {
+ pstat->flags |= WLAN_STA_WME;
+
+ pstat->qos_option = 1;
+ pstat->qos_info = *(p+8);
+
+ pstat->max_sp_len = (pstat->qos_info>>5)&0x3;
+
+ if ((pstat->qos_info&0xf) != 0xf)
+ pstat->has_legacy_ac = true;
+ else
+ pstat->has_legacy_ac = false;
+
+ if (pstat->qos_info&0xf) {
+ if (pstat->qos_info&BIT(0))
+ pstat->uapsd_vo = BIT(0)|BIT(1);
+ else
+ pstat->uapsd_vo = 0;
+
+ if (pstat->qos_info&BIT(1))
+ pstat->uapsd_vi = BIT(0)|BIT(1);
+ else
+ pstat->uapsd_vi = 0;
+
+ if (pstat->qos_info&BIT(2))
+ pstat->uapsd_bk = BIT(0)|BIT(1);
+ else
+ pstat->uapsd_bk = 0;
+
+ if (pstat->qos_info&BIT(3))
+ pstat->uapsd_be = BIT(0)|BIT(1);
+ else
+ pstat->uapsd_be = 0;
+ }
+ break;
+ }
+ } else {
+ break;
+ }
+ p = p + ie_len + 2;
+ }
+ }
+
+ /* save HT capabilities in the sta object */
+ _rtw_memset(&pstat->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap));
+ if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct rtw_ieee80211_ht_cap)) {
+ pstat->flags |= WLAN_STA_HT;
+
+ pstat->flags |= WLAN_STA_WME;
+
+ memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct rtw_ieee80211_ht_cap));
+ } else {
+ pstat->flags &= ~WLAN_STA_HT;
+ }
+ if ((!pmlmepriv->htpriv.ht_option) && (pstat->flags&WLAN_STA_HT)) {
+ status = _STATS_FAILURE_;
+ goto OnAssocReqFail;
+ }
+
+ if ((pstat->flags & WLAN_STA_HT) &&
+ ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) ||
+ (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) {
+ DBG_88E("HT: %pM tried to "
+ "use TKIP with HT association\n", pstat->hwaddr);
+
+ /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */
+ /* goto OnAssocReqFail; */
+ }
+
+ pstat->flags |= WLAN_STA_NONERP;
+ for (i = 0; i < pstat->bssratelen; i++) {
+ if ((pstat->bssrateset[i] & 0x7f) > 22) {
+ pstat->flags &= ~WLAN_STA_NONERP;
+ break;
+ }
+ }
+
+ if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ pstat->flags |= WLAN_STA_SHORT_PREAMBLE;
+ else
+ pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+
+
+
+ if (status != _STATS_SUCCESSFUL_)
+ goto OnAssocReqFail;
+
+#ifdef CONFIG_88EU_P2P
+ pstat->is_p2p_device = false;
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + ie_offset , pkt_len - WLAN_HDR_A3_LEN - ie_offset , NULL, &p2pielen);
+ if (p2pie) {
+ pstat->is_p2p_device = true;
+ p2p_status_code = (u8)process_assoc_req_p2p_ie(pwdinfo, pframe, pkt_len, pstat);
+ if (p2p_status_code > 0) {
+ pstat->p2p_status_code = p2p_status_code;
+ status = _STATS_CAP_FAIL_;
+ goto OnAssocReqFail;
+ }
+ }
+ }
+ pstat->p2p_status_code = p2p_status_code;
+#endif /* CONFIG_88EU_P2P */
+
+ /* TODO: identify_proprietary_vendor_ie(); */
+ /* Realtek proprietary IE */
+ /* identify if this is Broadcom sta */
+ /* identify if this is ralink sta */
+ /* Customer proprietary IE */
+
+ /* get a unique AID */
+ if (pstat->aid > 0) {
+ DBG_88E(" old AID %d\n", pstat->aid);
+ } else {
+ for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++)
+ if (pstapriv->sta_aid[pstat->aid - 1] == NULL)
+ break;
+
+ /* if (pstat->aid > NUM_STA) { */
+ if (pstat->aid > pstapriv->max_num_sta) {
+ pstat->aid = 0;
+
+ DBG_88E(" no room for more AIDs\n");
+
+ status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+ goto OnAssocReqFail;
+ } else {
+ pstapriv->sta_aid[pstat->aid - 1] = pstat;
+ DBG_88E("allocate new AID=(%d)\n", pstat->aid);
+ }
+ }
+
+ pstat->state &= (~WIFI_FW_ASSOC_STATE);
+ pstat->state |= WIFI_FW_ASSOC_SUCCESS;
+
+ _enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+ if (!rtw_is_list_empty(&pstat->auth_list)) {
+ rtw_list_delete(&pstat->auth_list);
+ pstapriv->auth_list_cnt--;
+ }
+ _exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ if (rtw_is_list_empty(&pstat->asoc_list)) {
+ pstat->expire_to = pstapriv->expire_to;
+ rtw_list_insert_tail(&pstat->asoc_list, &pstapriv->asoc_list);
+ pstapriv->asoc_list_cnt++;
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ /* now the station is qualified to join our BSS... */
+ if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_ == status)) {
+#ifdef CONFIG_88EU_AP_MODE
+ /* 1 bss_cap_update & sta_info_update */
+ bss_cap_update_on_sta_join(padapter, pstat);
+ sta_info_update(padapter, pstat);
+
+ /* issue assoc rsp before notify station join event. */
+ if (frame_type == WIFI_ASSOCREQ)
+ issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP);
+ else
+ issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP);
+
+ /* 2 - report to upper layer */
+ DBG_88E("indicate_sta_join_event to upper layer - hostapd\n");
+ rtw_indicate_sta_assoc_event(padapter, pstat);
+
+ /* 3-(1) report sta add event */
+ report_add_sta_event(padapter, pstat->hwaddr, pstat->aid);
+#endif
+ }
+
+ return _SUCCESS;
+
+asoc_class2_error:
+
+#ifdef CONFIG_88EU_AP_MODE
+ issue_deauth(padapter, (void *)GetAddr2Ptr(pframe), status);
+#endif
+
+ return _FAIL;
+
+OnAssocReqFail:
+
+
+#ifdef CONFIG_88EU_AP_MODE
+ pstat->aid = 0;
+ if (frame_type == WIFI_ASSOCREQ)
+ issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP);
+ else
+ issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP);
+#endif
+
+
+#endif /* CONFIG_88EU_AP_MODE */
+
+ return _FAIL;
+}
+
+unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ uint i;
+ int res;
+ unsigned short status;
+ struct ndis_802_11_var_ie *pIE;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ /* struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); */
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ uint pkt_len = precv_frame->u.hdr.len;
+
+ DBG_88E("%s\n", __func__);
+
+ /* check A1 matches or not */
+ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN))
+ return _SUCCESS;
+
+ if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE)))
+ return _SUCCESS;
+
+ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
+ return _SUCCESS;
+
+ _cancel_timer_ex(&pmlmeext->link_timer);
+
+ /* status */
+ status = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 2));
+ if (status > 0) {
+ DBG_88E("assoc reject, status code: %d\n", status);
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+ res = -4;
+ goto report_assoc_result;
+ }
+
+ /* get capabilities */
+ pmlmeinfo->capability = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
+
+ /* set slot time */
+ pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10)) ? 9 : 20;
+
+ /* AID */
+ pmlmeinfo->aid = (int)(le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 4))&0x3fff);
+ res = pmlmeinfo->aid;
+
+ /* following are moved to join event callback function */
+ /* to handle HT, WMM, rate adaptive, update MAC reg */
+ /* for not to handle the synchronous IO in the tasklet */
+ for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) {
+ pIE = (struct ndis_802_11_var_ie *)(pframe + i);
+
+ switch (pIE->ElementID) {
+ case _VENDOR_SPECIFIC_IE_:
+ if (_rtw_memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */
+ WMM_param_handler(padapter, pIE);
+ break;
+ case _HT_CAPABILITY_IE_: /* HT caps */
+ HT_caps_handler(padapter, pIE);
+ break;
+ case _HT_EXTRA_INFO_IE_: /* HT info */
+ HT_info_handler(padapter, pIE);
+ break;
+ case _ERPINFO_IE_:
+ ERP_IE_handler(padapter, pIE);
+ default:
+ break;
+ }
+
+ i += (pIE->Length + 2);
+ }
+
+ pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE);
+ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
+
+ /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */
+ UpdateBrateTbl(padapter, pmlmeinfo->network.SupportedRates);
+
+report_assoc_result:
+ if (res > 0) {
+ rtw_buf_update(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len, pframe, pkt_len);
+ } else {
+ rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len);
+ }
+
+ report_join_res(padapter, res);
+
+ return _SUCCESS;
+}
+
+unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ unsigned short reason;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+ /* check A3 */
+ if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+ return _SUCCESS;
+
+#ifdef CONFIG_88EU_P2P
+ if (pwdinfo->rx_invitereq_info.scan_op_ch_only) {
+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+ _set_timer(&pwdinfo->reset_ch_sitesurvey, 10);
+ }
+#endif /* CONFIG_88EU_P2P */
+
+ reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
+
+ DBG_88E("%s Reason code(%d)\n", __func__, reason);
+
+#ifdef CONFIG_88EU_AP_MODE
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ unsigned long irqL;
+ struct sta_info *psta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ DBG_88E_LEVEL(_drv_always_, "ap recv deauth reason code(%d) sta:%pM\n",
+ reason, GetAddr2Ptr(pframe));
+
+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+ if (psta) {
+ u8 updated = 0;
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ if (!rtw_is_list_empty(&psta->asoc_list)) {
+ rtw_list_delete(&psta->asoc_list);
+ pstapriv->asoc_list_cnt--;
+ updated = ap_free_sta(padapter, psta, false, reason);
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ associated_clients_update(padapter, updated);
+ }
+
+
+ return _SUCCESS;
+ } else
+#endif
+ {
+ DBG_88E_LEVEL(_drv_always_, "sta recv deauth reason code(%d) sta:%pM\n",
+ reason, GetAddr3Ptr(pframe));
+
+ receive_disconnect(padapter, GetAddr3Ptr(pframe) , reason);
+ }
+ pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+ return _SUCCESS;
+}
+
+unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ u16 reason;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+ /* check A3 */
+ if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+ return _SUCCESS;
+
+#ifdef CONFIG_88EU_P2P
+ if (pwdinfo->rx_invitereq_info.scan_op_ch_only) {
+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+ _set_timer(&pwdinfo->reset_ch_sitesurvey, 10);
+ }
+#endif /* CONFIG_88EU_P2P */
+
+ reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
+
+ DBG_88E("%s Reason code(%d)\n", __func__, reason);
+
+#ifdef CONFIG_88EU_AP_MODE
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ unsigned long irqL;
+ struct sta_info *psta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
+ /* rtw_free_stainfo(padapter, psta); */
+ /* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
+
+ DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n",
+ reason, GetAddr2Ptr(pframe));
+
+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+ if (psta) {
+ u8 updated = 0;
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ if (!rtw_is_list_empty(&psta->asoc_list)) {
+ rtw_list_delete(&psta->asoc_list);
+ pstapriv->asoc_list_cnt--;
+ updated = ap_free_sta(padapter, psta, false, reason);
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ associated_clients_update(padapter, updated);
+ }
+
+ return _SUCCESS;
+ } else
+#endif
+ {
+ DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n",
+ reason, GetAddr3Ptr(pframe));
+
+ receive_disconnect(padapter, GetAddr3Ptr(pframe), reason);
+ }
+ pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+ return _SUCCESS;
+}
+
+unsigned int OnAtim(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ DBG_88E("%s\n", __func__);
+ return _SUCCESS;
+}
+
+unsigned int on_action_spct(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ unsigned int ret = _FAIL;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+ u8 category;
+ u8 action;
+
+ DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+
+ if (!psta)
+ goto exit;
+
+ category = frame_body[0];
+ if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT)
+ goto exit;
+
+ action = frame_body[1];
+ switch (action) {
+ case RTW_WLAN_ACTION_SPCT_MSR_REQ:
+ case RTW_WLAN_ACTION_SPCT_MSR_RPRT:
+ case RTW_WLAN_ACTION_SPCT_TPC_REQ:
+ case RTW_WLAN_ACTION_SPCT_TPC_RPRT:
+ break;
+ case RTW_WLAN_ACTION_SPCT_CHL_SWITCH:
+ break;
+ default:
+ break;
+ }
+
+exit:
+ return ret;
+}
+
+unsigned int OnAction_qos(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ return _SUCCESS;
+}
+
+unsigned int OnAction_dls(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ return _SUCCESS;
+}
+
+unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ u8 *addr;
+ struct sta_info *psta = NULL;
+ struct recv_reorder_ctrl *preorder_ctrl;
+ unsigned char *frame_body;
+ unsigned char category, action;
+ unsigned short tid, status, reason_code = 0;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ /* check RA matches or not */
+ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */
+ return _SUCCESS;
+
+ DBG_88E("%s\n", __func__);
+
+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
+ return _SUCCESS;
+
+ addr = GetAddr2Ptr(pframe);
+ psta = rtw_get_stainfo(pstapriv, addr);
+
+ if (psta == NULL)
+ return _SUCCESS;
+
+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+ category = frame_body[0];
+ if (category == RTW_WLAN_CATEGORY_BACK) { /* representing Block Ack */
+ if (!pmlmeinfo->HT_enable)
+ return _SUCCESS;
+ action = frame_body[1];
+ DBG_88E("%s, action=%d\n", __func__, action);
+ switch (action) {
+ case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */
+ memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request));
+ process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), addr);
+
+ if (pmlmeinfo->bAcceptAddbaReq)
+ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 0);
+ else
+ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 37);/* reject ADDBA Req */
+ break;
+ case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */
+ status = RTW_GET_LE16(&frame_body[3]);
+ tid = ((frame_body[5] >> 2) & 0x7);
+ if (status == 0) { /* successful */
+ DBG_88E("agg_enable for TID=%d\n", tid);
+ psta->htpriv.agg_enable_bitmap |= 1 << tid;
+ psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
+ } else {
+ psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
+ }
+ break;
+ case RTW_WLAN_ACTION_DELBA: /* DELBA */
+ if ((frame_body[3] & BIT(3)) == 0) {
+ psta->htpriv.agg_enable_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf));
+ psta->htpriv.candidate_tid_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf));
+ reason_code = RTW_GET_LE16(&frame_body[4]);
+ } else if ((frame_body[3] & BIT(3)) == BIT(3)) {
+ tid = (frame_body[3] >> 4) & 0x0F;
+ preorder_ctrl = &psta->recvreorder_ctrl[tid];
+ preorder_ctrl->enable = false;
+ preorder_ctrl->indicate_seq = 0xffff;
+ }
+ DBG_88E("%s(): DELBA: %x(%x)\n", __func__, pmlmeinfo->agg_enable_bitmap, reason_code);
+ /* todo: how to notify the host while receiving DELETE BA */
+ break;
+ default:
+ break;
+ }
+ }
+ return _SUCCESS;
+}
+
+#ifdef CONFIG_88EU_P2P
+
+static int get_reg_classes_full_count(struct p2p_channels channel_list)
+{
+ int cnt = 0;
+ int i;
+
+ for (i = 0; i < channel_list.reg_classes; i++) {
+ cnt += channel_list.reg_class[i].channels;
+ }
+
+ return cnt;
+}
+
+void issue_p2p_GO_request(struct adapter *padapter, u8 *raddr)
+{
+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+ u8 action = P2P_PUB_ACTION_ACTION;
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u8 oui_subtype = P2P_GO_NEGO_REQ;
+ u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
+ u8 wpsielen = 0, p2pielen = 0;
+ u16 len_channellist_attr = 0;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ DBG_88E("[%s] In\n", __func__);
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pwdinfo->negotiation_dialog_token = 1; /* Initialize the dialog value */
+ pframe = rtw_set_fixed_ie(pframe, 1, &pwdinfo->negotiation_dialog_token, &(pattrib->pktlen));
+
+
+
+ /* WPS Section */
+ wpsielen = 0;
+ /* WPS OUI */
+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+ wpsielen += 4;
+
+ /* WPS version */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+ wpsielen += 2;
+
+ /* Value: */
+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */
+
+ /* Device Password ID */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+ wpsielen += 2;
+
+ /* Value: */
+
+ if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN)
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC);
+ else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN)
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);
+ else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC)
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC);
+
+ wpsielen += 2;
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+
+ /* P2P IE Section. */
+
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Commented by Albert 20110306 */
+ /* According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */
+ /* 1. P2P Capability */
+ /* 2. Group Owner Intent */
+ /* 3. Configuration Timeout */
+ /* 4. Listen Channel */
+ /* 5. Extended Listen Timing */
+ /* 6. Intended P2P Interface Address */
+ /* 7. Channel List */
+ /* 8. P2P Device Info */
+ /* 9. Operating Channel */
+
+
+ /* P2P Capability */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Device Capability Bitmap, 1 byte */
+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+ /* Group Capability Bitmap, 1 byte */
+ if (pwdinfo->persistent_supported)
+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP;
+ else
+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN;
+
+ /* Group Owner Intent */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_GO_INTENT;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Todo the tie breaker bit. */
+ p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0));
+
+ /* Configuration Timeout */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */
+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */
+
+
+ /* Listen Channel */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Operating Class */
+ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */
+
+ /* Channel Number */
+ p2pie[p2pielen++] = pwdinfo->listen_channel; /* listening channel number */
+
+
+ /* Extended Listen Timing ATTR */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Availability Period */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+ p2pielen += 2;
+
+ /* Availability Interval */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+ p2pielen += 2;
+
+
+ /* Intended P2P Interface Address */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+
+ /* Channel List */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+ /* Length: */
+ /* Country String(3) */
+ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */
+ /* + number of channels in all classes */
+ len_channellist_attr = 3
+ + (1 + 1) * (u16)(pmlmeext->channel_list.reg_classes)
+ + get_reg_classes_full_count(pmlmeext->channel_list);
+
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Channel Entry List */
+
+ {
+ int i, j;
+ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+ /* Operating Class */
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class;
+
+ /* Number of Channels */
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels;
+
+ /* Channel List */
+ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i];
+ }
+ }
+ }
+
+ /* Device Info */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+ /* Length: */
+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ /* P2P Device Address */
+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ /* Config Method */
+ /* This field should be big endian. Noted by P2P specification. */
+
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+
+ p2pielen += 2;
+
+ /* Primary Device Type */
+ /* Category ID */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+ p2pielen += 2;
+
+ /* OUI */
+ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+ p2pielen += 4;
+
+ /* Sub Category ID */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+ p2pielen += 2;
+
+ /* Number of Secondary Device Types */
+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */
+
+ /* Device Name */
+ /* Type: */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+ p2pielen += 2;
+
+ /* Length: */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len);
+ p2pielen += pwdinfo->device_name_len;
+
+
+ /* Operating Channel */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Operating Class */
+ p2pie[p2pielen++] = 0x51;
+
+ /* Channel Number */
+ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+
+ return;
+}
+
+static void issue_p2p_GO_response(struct adapter *padapter, u8 *raddr, u8 *frame_body, uint len, u8 result)
+{
+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+ u8 action = P2P_PUB_ACTION_ACTION;
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u8 oui_subtype = P2P_GO_NEGO_RESP;
+ u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
+ u8 p2pielen = 0;
+ uint wpsielen = 0;
+ u16 wps_devicepassword_id = 0x0000;
+ __be16 be_tmp;
+ uint wps_devicepassword_id_len = 0;
+ u16 len_channellist_attr = 0;
+
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ DBG_88E("[%s] In, result=%d\n", __func__, result);
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pwdinfo->negotiation_dialog_token = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */
+ pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen));
+
+ /* Commented by Albert 20110328 */
+ /* Try to get the device password ID from the WPS IE of group negotiation request frame */
+ /* WiFi Direct test plan 5.1.15 */
+ rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen);
+ rtw_get_wps_attr_content(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, (u8 *)&be_tmp, &wps_devicepassword_id_len);
+ wps_devicepassword_id = be16_to_cpu(be_tmp);
+
+ _rtw_memset(wpsie, 0x00, 255);
+ wpsielen = 0;
+
+ /* WPS Section */
+ wpsielen = 0;
+ /* WPS OUI */
+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+ wpsielen += 4;
+
+ /* WPS version */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+ wpsielen += 2;
+
+ /* Value: */
+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */
+
+ /* Device Password ID */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+ wpsielen += 2;
+
+ /* Value: */
+ if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);
+ else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC);
+ else
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC);
+ wpsielen += 2;
+
+ /* Commented by Kurt 20120113 */
+ /* If some device wants to do p2p handshake without sending prov_disc_req */
+ /* We have to get peer_req_cm from here. */
+ if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
+ if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
+ else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
+ else
+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
+ }
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+
+ /* P2P IE Section. */
+
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Commented by Albert 20100908 */
+ /* According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes */
+ /* 1. Status */
+ /* 2. P2P Capability */
+ /* 3. Group Owner Intent */
+ /* 4. Configuration Timeout */
+ /* 5. Operating Channel */
+ /* 6. Intended P2P Interface Address */
+ /* 7. Channel List */
+ /* 8. Device Info */
+ /* 9. Group ID (Only GO) */
+
+
+ /* ToDo: */
+
+ /* P2P Status */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_STATUS;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+ p2pielen += 2;
+
+ /* Value: */
+ p2pie[p2pielen++] = result;
+
+ /* P2P Capability */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Device Capability Bitmap, 1 byte */
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+ /* Commented by Albert 2011/03/08 */
+ /* According to the P2P specification */
+ /* if the sending device will be client, the P2P Capability should be reserved of group negotation response frame */
+ p2pie[p2pielen++] = 0;
+ } else {
+ /* Be group owner or meet the error case */
+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+ }
+
+ /* Group Capability Bitmap, 1 byte */
+ if (pwdinfo->persistent_supported) {
+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP;
+ } else {
+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN;
+ }
+
+ /* Group Owner Intent */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_GO_INTENT;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+ p2pielen += 2;
+
+ /* Value: */
+ if (pwdinfo->peer_intent & 0x01) {
+ /* Peer's tie breaker bit is 1, our tie breaker bit should be 0 */
+ p2pie[p2pielen++] = (pwdinfo->intent << 1);
+ } else {
+ /* Peer's tie breaker bit is 0, our tie breaker bit should be 1 */
+ p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0));
+ }
+
+
+ /* Configuration Timeout */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */
+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */
+
+ /* Operating Channel */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Operating Class */
+ p2pie[p2pielen++] = 0x51;
+
+ /* Channel Number */
+ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */
+
+ /* Intended P2P Interface Address */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ /* Channel List */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+ /* Country String(3) */
+ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */
+ /* + number of channels in all classes */
+ len_channellist_attr = 3
+ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes
+ + get_reg_classes_full_count(pmlmeext->channel_list);
+
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Channel Entry List */
+
+ {
+ int i, j;
+ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+ /* Operating Class */
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class;
+
+ /* Number of Channels */
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels;
+
+ /* Channel List */
+ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i];
+ }
+ }
+ }
+
+ /* Device Info */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+ /* Length: */
+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ /* P2P Device Address */
+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ /* Config Method */
+ /* This field should be big endian. Noted by P2P specification. */
+
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+
+ p2pielen += 2;
+
+ /* Primary Device Type */
+ /* Category ID */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+ p2pielen += 2;
+
+ /* OUI */
+ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+ p2pielen += 4;
+
+ /* Sub Category ID */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+ p2pielen += 2;
+
+ /* Number of Secondary Device Types */
+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */
+
+ /* Device Name */
+ /* Type: */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+ p2pielen += 2;
+
+ /* Length: */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len);
+ p2pielen += pwdinfo->device_name_len;
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ /* Group ID Attribute */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen);
+ p2pielen += 2;
+
+ /* Value: */
+ /* p2P Device Address */
+ memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ /* SSID */
+ memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
+ p2pielen += pwdinfo->nego_ssidlen;
+ }
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+ return;
+}
+
+static void issue_p2p_GO_confirm(struct adapter *padapter, u8 *raddr, u8 result)
+{
+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+ u8 action = P2P_PUB_ACTION_ACTION;
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u8 oui_subtype = P2P_GO_NEGO_CONF;
+ u8 p2pie[255] = { 0x00 };
+ u8 p2pielen = 0;
+
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ DBG_88E("[%s] In\n", __func__);
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen));
+
+
+
+ /* P2P IE Section. */
+
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Commented by Albert 20110306 */
+ /* According to the P2P Specification, the group negoitation request frame should contain 5 P2P attributes */
+ /* 1. Status */
+ /* 2. P2P Capability */
+ /* 3. Operating Channel */
+ /* 4. Channel List */
+ /* 5. Group ID (if this WiFi is GO) */
+
+ /* P2P Status */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_STATUS;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+ p2pielen += 2;
+
+ /* Value: */
+ p2pie[p2pielen++] = result;
+
+ /* P2P Capability */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Device Capability Bitmap, 1 byte */
+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+ /* Group Capability Bitmap, 1 byte */
+ if (pwdinfo->persistent_supported)
+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP;
+ else
+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN;
+
+ /* Operating Channel */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+ /* Operating Class */
+ p2pie[p2pielen++] = 0x51;
+ p2pie[p2pielen++] = pwdinfo->peer_operating_ch;
+ } else {
+ /* Operating Class */
+ p2pie[p2pielen++] = 0x51;
+
+ /* Channel Number */
+ p2pie[p2pielen++] = pwdinfo->operating_channel; /* Use the listen channel as the operating channel */
+ }
+
+
+ /* Channel List */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(pwdinfo->channel_list_attr_len);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len);
+ p2pielen += pwdinfo->channel_list_attr_len;
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ /* Group ID Attribute */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen);
+ p2pielen += 2;
+
+ /* Value: */
+ /* p2P Device Address */
+ memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ /* SSID */
+ memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
+ p2pielen += pwdinfo->nego_ssidlen;
+ }
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+ pattrib->last_txcmdsz = pattrib->pktlen;
+ dump_mgntframe(padapter, pmgntframe);
+ return;
+}
+
+void issue_p2p_invitation_request(struct adapter *padapter, u8 *raddr)
+{
+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+ u8 action = P2P_PUB_ACTION_ACTION;
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u8 oui_subtype = P2P_INVIT_REQ;
+ u8 p2pie[255] = { 0x00 };
+ u8 p2pielen = 0;
+ u8 dialogToken = 3;
+ u16 len_channellist_attr = 0;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, raddr, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+ /* P2P IE Section. */
+
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Commented by Albert 20101011 */
+ /* According to the P2P Specification, the P2P Invitation request frame should contain 7 P2P attributes */
+ /* 1. Configuration Timeout */
+ /* 2. Invitation Flags */
+ /* 3. Operating Channel (Only GO) */
+ /* 4. P2P Group BSSID (Should be included if I am the GO) */
+ /* 5. Channel List */
+ /* 6. P2P Group ID */
+ /* 7. P2P Device Info */
+
+ /* Configuration Timeout */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */
+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */
+
+ /* Invitation Flags */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_INVITATION_FLAGS;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+ p2pielen += 2;
+
+ /* Value: */
+ p2pie[p2pielen++] = P2P_INVITATION_FLAGS_PERSISTENT;
+
+
+ /* Operating Channel */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Operating Class */
+ p2pie[p2pielen++] = 0x51;
+
+ /* Channel Number */
+ p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch; /* operating channel number */
+
+ if (_rtw_memcmp(myid(&padapter->eeprompriv), pwdinfo->invitereq_info.go_bssid, ETH_ALEN)) {
+ /* P2P Group BSSID */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+ p2pielen += 2;
+
+ /* Value: */
+ /* P2P Device Address for GO */
+ memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN);
+ p2pielen += ETH_ALEN;
+ }
+
+ /* Channel List */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+
+ /* Length: */
+ /* Country String(3) */
+ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */
+ /* + number of channels in all classes */
+ len_channellist_attr = 3
+ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes
+ + get_reg_classes_full_count(pmlmeext->channel_list);
+
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Channel Entry List */
+ {
+ int i, j;
+ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+ /* Operating Class */
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class;
+
+ /* Number of Channels */
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels;
+
+ /* Channel List */
+ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i];
+ }
+ }
+ }
+
+
+ /* P2P Group ID */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(6 + pwdinfo->invitereq_info.ssidlen);
+ p2pielen += 2;
+
+ /* Value: */
+ /* P2P Device Address for GO */
+ memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ /* SSID */
+ memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_ssid, pwdinfo->invitereq_info.ssidlen);
+ p2pielen += pwdinfo->invitereq_info.ssidlen;
+
+
+ /* Device Info */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+ /* Length: */
+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ /* P2P Device Address */
+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ /* Config Method */
+ /* This field should be big endian. Noted by P2P specification. */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY);
+ p2pielen += 2;
+
+ /* Primary Device Type */
+ /* Category ID */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+ p2pielen += 2;
+
+ /* OUI */
+ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+ p2pielen += 4;
+
+ /* Sub Category ID */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+ p2pielen += 2;
+
+ /* Number of Secondary Device Types */
+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */
+
+ /* Device Name */
+ /* Type: */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+ p2pielen += 2;
+
+ /* Length: */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+ p2pielen += pwdinfo->device_name_len;
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+
+ return;
+}
+
+void issue_p2p_invitation_response(struct adapter *padapter, u8 *raddr, u8 dialogToken, u8 status_code)
+{
+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+ u8 action = P2P_PUB_ACTION_ACTION;
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u8 oui_subtype = P2P_INVIT_RESP;
+ u8 p2pie[255] = { 0x00 };
+ u8 p2pielen = 0;
+ u16 len_channellist_attr = 0;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, raddr, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+ /* P2P IE Section. */
+
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Commented by Albert 20101005 */
+ /* According to the P2P Specification, the P2P Invitation response frame should contain 5 P2P attributes */
+ /* 1. Status */
+ /* 2. Configuration Timeout */
+ /* 3. Operating Channel (Only GO) */
+ /* 4. P2P Group BSSID (Only GO) */
+ /* 5. Channel List */
+
+ /* P2P Status */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_STATUS;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+ p2pielen += 2;
+
+ /* Value: */
+ /* When status code is P2P_STATUS_FAIL_INFO_UNAVAILABLE. */
+ /* Sent the event receiving the P2P Invitation Req frame to DMP UI. */
+ /* DMP had to compare the MAC address to find out the profile. */
+ /* So, the WiFi driver will send the P2P_STATUS_FAIL_INFO_UNAVAILABLE to NB. */
+ /* If the UI found the corresponding profile, the WiFi driver sends the P2P Invitation Req */
+ /* to NB to rebuild the persistent group. */
+ p2pie[p2pielen++] = status_code;
+
+ /* Configuration Timeout */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */
+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */
+
+ if (status_code == P2P_STATUS_SUCCESS) {
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ /* The P2P Invitation request frame asks this Wi-Fi device to be the P2P GO */
+ /* In this case, the P2P Invitation response frame should carry the two more P2P attributes. */
+ /* First one is operating channel attribute. */
+ /* Second one is P2P Group BSSID attribute. */
+
+ /* Operating Channel */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Operating Class */
+ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */
+
+ /* Channel Number */
+ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */
+
+
+ /* P2P Group BSSID */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+ p2pielen += 2;
+
+ /* Value: */
+ /* P2P Device Address for GO */
+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+ p2pielen += ETH_ALEN;
+ }
+
+ /* Channel List */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+ /* Length: */
+ /* Country String(3) */
+ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */
+ /* + number of channels in all classes */
+ len_channellist_attr = 3
+ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes
+ + get_reg_classes_full_count(pmlmeext->channel_list);
+
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Channel Entry List */
+ {
+ int i, j;
+ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+ /* Operating Class */
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class;
+
+ /* Number of Channels */
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels;
+
+ /* Channel List */
+ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i];
+ }
+ }
+ }
+ }
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+
+ return;
+}
+
+void issue_p2p_provision_request(struct adapter *padapter, u8 *pssid, u8 ussidlen, u8 *pdev_raddr)
+{
+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+ u8 action = P2P_PUB_ACTION_ACTION;
+ u8 dialogToken = 1;
+ u8 oui_subtype = P2P_PROVISION_DISC_REQ;
+ u8 wpsie[100] = { 0x00 };
+ u8 wpsielen = 0;
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u32 p2pielen = 0;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ DBG_88E("[%s] In\n", __func__);
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, pdev_raddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pdev_raddr, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+ p2pielen = build_prov_disc_request_p2p_ie(pwdinfo, pframe, pssid, ussidlen, pdev_raddr);
+
+ pframe += p2pielen;
+ pattrib->pktlen += p2pielen;
+
+ wpsielen = 0;
+ /* WPS OUI */
+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+ wpsielen += 4;
+
+ /* WPS version */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+ wpsielen += 2;
+
+ /* Value: */
+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */
+
+ /* Config Method */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+ wpsielen += 2;
+
+ /* Value: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request);
+ wpsielen += 2;
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+
+ return;
+}
+
+static u8 is_matched_in_profilelist(u8 *peermacaddr, struct profile_info *profileinfo)
+{
+ u8 i, match_result = 0;
+
+ DBG_88E("[%s] peermac=%.2X %.2X %.2X %.2X %.2X %.2X\n", __func__,
+ peermacaddr[0], peermacaddr[1], peermacaddr[2], peermacaddr[3], peermacaddr[4], peermacaddr[5]);
+
+ for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) {
+ DBG_88E("[%s] profileinfo_mac=%.2X %.2X %.2X %.2X %.2X %.2X\n", __func__,
+ profileinfo->peermac[0], profileinfo->peermac[1], profileinfo->peermac[2], profileinfo->peermac[3], profileinfo->peermac[4], profileinfo->peermac[5]);
+ if (_rtw_memcmp(peermacaddr, profileinfo->peermac, ETH_ALEN)) {
+ match_result = 1;
+ DBG_88E("[%s] Match!\n", __func__);
+ break;
+ }
+ }
+ return match_result;
+}
+
+void issue_probersp_p2p(struct adapter *padapter, unsigned char *da)
+{
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ unsigned char *mac;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ u16 beacon_interval = 100;
+ u16 capInfo = 0;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 wpsie[255] = { 0x00 };
+ u32 wpsielen = 0, p2pielen = 0;
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ mac = myid(&(padapter->eeprompriv));
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+ memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+
+ /* Use the device address for BSSID field. */
+ memcpy(pwlanhdr->addr3, mac, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(fctrl, WIFI_PROBERSP);
+
+ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = pattrib->hdrlen;
+ pframe += pattrib->hdrlen;
+
+ /* timestamp will be inserted by hardware */
+ pframe += 8;
+ pattrib->pktlen += 8;
+
+ /* beacon interval: 2 bytes */
+ memcpy(pframe, (unsigned char *)&beacon_interval, 2);
+ pframe += 2;
+ pattrib->pktlen += 2;
+
+ /* capability info: 2 bytes */
+ /* ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of WiFi Direct Spec) */
+ capInfo |= cap_ShortPremble;
+ capInfo |= cap_ShortSlot;
+
+ memcpy(pframe, (unsigned char *)&capInfo, 2);
+ pframe += 2;
+ pattrib->pktlen += 2;
+
+
+ /* SSID */
+ pframe = rtw_set_ie(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, &pattrib->pktlen);
+
+ /* supported rates... */
+ /* Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen);
+
+ /* DS parameter set */
+ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&pwdinfo->listen_channel, &pattrib->pktlen);
+
+ /* Todo: WPS IE */
+ /* Noted by Albert 20100907 */
+ /* According to the WPS specification, all the WPS attribute is presented by Big Endian. */
+
+ wpsielen = 0;
+ /* WPS OUI */
+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+ wpsielen += 4;
+
+ /* WPS version */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+ wpsielen += 2;
+
+ /* Value: */
+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */
+
+ /* WiFi Simple Config State */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+ wpsielen += 2;
+
+ /* Value: */
+ wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG; /* Not Configured. */
+
+ /* Response Type */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+ wpsielen += 2;
+
+ /* Value: */
+ wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X;
+
+ /* UUID-E */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010);
+ wpsielen += 2;
+
+ /* Value: */
+ memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN);
+ wpsielen += 0x10;
+
+ /* Manufacturer */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0007);
+ wpsielen += 2;
+
+ /* Value: */
+ memcpy(wpsie + wpsielen, "Realtek", 7);
+ wpsielen += 7;
+
+ /* Model Name */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0006);
+ wpsielen += 2;
+
+ /* Value: */
+ memcpy(wpsie + wpsielen, "8188EU", 6);
+ wpsielen += 6;
+
+ /* Model Number */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+ wpsielen += 2;
+
+ /* Value: */
+ wpsie[wpsielen++] = 0x31; /* character 1 */
+
+ /* Serial Number */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SERIAL_NUMBER);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(ETH_ALEN);
+ wpsielen += 2;
+
+ /* Value: */
+ memcpy(wpsie + wpsielen, "123456" , ETH_ALEN);
+ wpsielen += ETH_ALEN;
+
+ /* Primary Device Type */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008);
+ wpsielen += 2;
+
+ /* Value: */
+ /* Category ID */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+ wpsielen += 2;
+
+ /* OUI */
+ *(__be32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI);
+ wpsielen += 4;
+
+ /* Sub Category ID */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+ wpsielen += 2;
+
+ /* Device Name */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len);
+ wpsielen += 2;
+
+ /* Value: */
+ if (pwdinfo->device_name_len) {
+ memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len);
+ wpsielen += pwdinfo->device_name_len;
+ }
+
+ /* Config Method */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+ wpsielen += 2;
+
+ /* Value: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+ wpsielen += 2;
+
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+
+ p2pielen = build_probe_resp_p2p_ie(pwdinfo, pframe);
+ pframe += p2pielen;
+ pattrib->pktlen += p2pielen;
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+
+ return;
+}
+
+static int _issue_probereq_p2p(struct adapter *padapter, u8 *da, int wait_ack)
+{
+ int ret = _FAIL;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ unsigned char *mac;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
+ u16 wpsielen = 0, p2pielen = 0;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ goto exit;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ mac = myid(&(padapter->eeprompriv));
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ if (da) {
+ memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, da, ETH_ALEN);
+ } else {
+ if ((pwdinfo->p2p_info.scan_op_ch_only) || (pwdinfo->rx_invitereq_info.scan_op_ch_only)) {
+ /* This two flags will be set when this is only the P2P client mode. */
+ memcpy(pwlanhdr->addr1, pwdinfo->p2p_peer_interface_addr, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pwdinfo->p2p_peer_interface_addr, ETH_ALEN);
+ } else {
+ /* broadcast probe request frame */
+ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN);
+ }
+ }
+ memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_PROBEREQ);
+
+ pframe += sizeof (struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr);
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ))
+ pframe = rtw_set_ie(pframe, _SSID_IE_, pwdinfo->tx_prov_disc_info.ssid.SsidLength, pwdinfo->tx_prov_disc_info.ssid.Ssid, &(pattrib->pktlen));
+ else
+ pframe = rtw_set_ie(pframe, _SSID_IE_, P2P_WILDCARD_SSID_LEN, pwdinfo->p2p_wildcard_ssid, &(pattrib->pktlen));
+
+ /* Use the OFDM rate in the P2P probe request frame. (6(B), 9(B), 12(B), 24(B), 36, 48, 54) */
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen);
+
+
+ /* WPS IE */
+ /* Noted by Albert 20110221 */
+ /* According to the WPS specification, all the WPS attribute is presented by Big Endian. */
+
+ wpsielen = 0;
+ /* WPS OUI */
+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+ wpsielen += 4;
+
+ /* WPS version */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+ wpsielen += 2;
+
+ /* Value: */
+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */
+
+ if (pmlmepriv->wps_probe_req_ie == NULL) {
+ /* UUID-E */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010);
+ wpsielen += 2;
+
+ /* Value: */
+ memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN);
+ wpsielen += 0x10;
+
+ /* Config Method */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+ wpsielen += 2;
+
+ /* Value: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+ wpsielen += 2;
+ }
+
+ /* Device Name */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len);
+ wpsielen += 2;
+
+ /* Value: */
+ memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len);
+ wpsielen += pwdinfo->device_name_len;
+
+ /* Primary Device Type */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008);
+ wpsielen += 2;
+
+ /* Value: */
+ /* Category ID */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_RTK_WIDI);
+ wpsielen += 2;
+
+ /* OUI */
+ *(__be32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI);
+ wpsielen += 4;
+
+ /* Sub Category ID */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_RTK_DMP);
+ wpsielen += 2;
+
+ /* Device Password ID */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+ wpsielen += 2;
+
+ /* Value: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); /* Registrar-specified */
+ wpsielen += 2;
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Commented by Albert 20110221 */
+ /* According to the P2P Specification, the probe request frame should contain 5 P2P attributes */
+ /* 1. P2P Capability */
+ /* 2. P2P Device ID if this probe request wants to find the specific P2P device */
+ /* 3. Listen Channel */
+ /* 4. Extended Listen Timing */
+ /* 5. Operating Channel if this WiFi is working as the group owner now */
+
+ /* P2P Capability */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Device Capability Bitmap, 1 byte */
+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+ /* Group Capability Bitmap, 1 byte */
+ if (pwdinfo->persistent_supported)
+ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
+ else
+ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
+
+ /* Listen Channel */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Operating Class */
+ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */
+
+ /* Channel Number */
+ p2pie[p2pielen++] = pwdinfo->listen_channel; /* listen channel */
+
+
+ /* Extended Listen Timing */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Availability Period */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+ p2pielen += 2;
+
+ /* Availability Interval */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+ p2pielen += 2;
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ /* Operating Channel (if this WiFi is working as the group owner now) */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Country String */
+ p2pie[p2pielen++] = 'X';
+ p2pie[p2pielen++] = 'X';
+
+ /* The third byte should be set to 0x04. */
+ /* Described in the "Operating Channel Attribute" section. */
+ p2pie[p2pielen++] = 0x04;
+
+ /* Operating Class */
+ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */
+
+ /* Channel Number */
+ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */
+ }
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+
+ if (pmlmepriv->wps_probe_req_ie != NULL) {
+ /* WPS IE */
+ memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len);
+ pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len;
+ pframe += pmlmepriv->wps_probe_req_ie_len;
+ }
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz));
+
+ if (wait_ack) {
+ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
+ } else {
+ dump_mgntframe(padapter, pmgntframe);
+ ret = _SUCCESS;
+ }
+
+exit:
+ return ret;
+}
+
+inline void issue_probereq_p2p(struct adapter *adapter, u8 *da)
+{
+ _issue_probereq_p2p(adapter, da, false);
+}
+
+int issue_probereq_p2p_ex(struct adapter *adapter, u8 *da, int try_cnt, int wait_ms)
+{
+ int ret;
+ int i = 0;
+ u32 start = rtw_get_current_time();
+
+ do {
+ ret = _issue_probereq_p2p(adapter, da, wait_ms > 0 ? true : false);
+
+ i++;
+
+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
+ break;
+
+ if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+ rtw_msleep_os(wait_ms);
+ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+ if (ret != _FAIL) {
+ ret = _SUCCESS;
+ goto exit;
+ }
+
+ if (try_cnt && wait_ms) {
+ if (da)
+ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
+ FUNC_ADPT_ARG(adapter), da, rtw_get_oper_ch(adapter),
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ else
+ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+ FUNC_ADPT_ARG(adapter), rtw_get_oper_ch(adapter),
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ }
+exit:
+ return ret;
+}
+
+#endif /* CONFIG_88EU_P2P */
+
+static s32 rtw_action_public_decache(union recv_frame *recv_frame, s32 token)
+{
+ struct adapter *adapter = recv_frame->u.hdr.adapter;
+ struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
+ u8 *frame = recv_frame->u.hdr.rx_data;
+ u16 seq_ctrl = ((recv_frame->u.hdr.attrib.seq_num&0xffff) << 4) |
+ (recv_frame->u.hdr.attrib.frag_num & 0xf);
+
+ if (GetRetry(frame)) {
+ if (token >= 0) {
+ if ((seq_ctrl == mlmeext->action_public_rxseq) && (token == mlmeext->action_public_dialog_token)) {
+ DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x, token:%d\n",
+ FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token);
+ return _FAIL;
+ }
+ } else {
+ if (seq_ctrl == mlmeext->action_public_rxseq) {
+ DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x\n",
+ FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq);
+ return _FAIL;
+ }
+ }
+ }
+
+ mlmeext->action_public_rxseq = seq_ctrl;
+
+ if (token >= 0)
+ mlmeext->action_public_dialog_token = token;
+
+ return _SUCCESS;
+}
+
+static unsigned int on_action_public_p2p(union recv_frame *precv_frame)
+{
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *frame_body;
+ u8 dialogToken = 0;
+#ifdef CONFIG_88EU_P2P
+ struct adapter *padapter = precv_frame->u.hdr.adapter;
+ uint len = precv_frame->u.hdr.len;
+ u8 *p2p_ie;
+ u32 p2p_ielen;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 result = P2P_STATUS_SUCCESS;
+ u8 empty_addr[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+#endif /* CONFIG_88EU_P2P */
+
+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+ dialogToken = frame_body[7];
+
+ if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL)
+ return _FAIL;
+
+#ifdef CONFIG_88EU_P2P
+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+ /* Do nothing if the driver doesn't enable the P2P function. */
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE))
+ return _SUCCESS;
+
+ len -= sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ switch (frame_body[6]) { /* OUI Subtype */
+ case P2P_GO_NEGO_REQ:
+ DBG_88E("[%s] Got GO Nego Req Frame\n", __func__);
+ _rtw_memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ))
+ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) {
+ /* Commented by Albert 20110526 */
+ /* In this case, this means the previous nego fail doesn't be reset yet. */
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ /* Restore the previous p2p state */
+ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+ DBG_88E("[%s] Restore the previous p2p state to %d\n", __func__, rtw_p2p_state(pwdinfo));
+ }
+
+ /* Commented by Kurt 20110902 */
+ /* Add if statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING))
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+
+ /* Commented by Kurt 20120113 */
+ /* Get peer_dev_addr here if peer doesn't issue prov_disc frame. */
+ if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.peerDevAddr, empty_addr, ETH_ALEN))
+ memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN);
+
+ result = process_p2p_group_negotation_req(pwdinfo, frame_body, len);
+ issue_p2p_GO_response(padapter, GetAddr2Ptr(pframe), frame_body, len, result);
+
+ /* Commented by Albert 20110718 */
+ /* No matter negotiating or negotiation failure, the driver should set up the restore P2P state timer. */
+ _set_timer(&pwdinfo->restore_p2p_state_timer, 5000);
+ break;
+ case P2P_GO_NEGO_RESP:
+ DBG_88E("[%s] Got GO Nego Resp Frame\n", __func__);
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
+ /* Commented by Albert 20110425 */
+ /* The restore timer is enabled when issuing the nego request frame of rtw_p2p_connect function. */
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ pwdinfo->nego_req_info.benable = false;
+ result = process_p2p_group_negotation_resp(pwdinfo, frame_body, len);
+ issue_p2p_GO_confirm(pwdinfo->padapter, GetAddr2Ptr(pframe), result);
+ if (P2P_STATUS_SUCCESS == result) {
+ if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) {
+ pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch;
+ pwdinfo->p2p_info.scan_op_ch_only = 1;
+ _set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH);
+ }
+ }
+ /* Reset the dialog token for group negotiation frames. */
+ pwdinfo->negotiation_dialog_token = 1;
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
+ _set_timer(&pwdinfo->restore_p2p_state_timer, 5000);
+ } else {
+ DBG_88E("[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __func__);
+ }
+ break;
+ case P2P_GO_NEGO_CONF:
+ DBG_88E("[%s] Got GO Nego Confirm Frame\n", __func__);
+ result = process_p2p_group_negotation_confirm(pwdinfo, frame_body, len);
+ if (P2P_STATUS_SUCCESS == result) {
+ if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) {
+ pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch;
+ pwdinfo->p2p_info.scan_op_ch_only = 1;
+ _set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH);
+ }
+ }
+ break;
+ case P2P_INVIT_REQ:
+ /* Added by Albert 2010/10/05 */
+ /* Received the P2P Invite Request frame. */
+
+ DBG_88E("[%s] Got invite request frame!\n", __func__);
+ p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen);
+ if (p2p_ie) {
+ /* Parse the necessary information from the P2P Invitation Request frame. */
+ /* For example: The MAC address of sending this P2P Invitation Request frame. */
+ u32 attr_contentlen = 0;
+ u8 status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+ struct group_id_info group_id;
+ u8 invitation_flag = 0;
+
+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen);
+ if (attr_contentlen) {
+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, pwdinfo->p2p_peer_interface_addr, &attr_contentlen);
+ /* Commented by Albert 20120510 */
+ /* Copy to the pwdinfo->p2p_peer_interface_addr. */
+ /* So that the WFD UI (or Sigma) can get the peer interface address by using the following command. */
+ /* #> iwpriv wlan0 p2p_get peer_ifa */
+ /* After having the peer interface address, the sigma can find the correct conf file for wpa_supplicant. */
+
+ if (attr_contentlen) {
+ DBG_88E("[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __func__,
+ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1],
+ pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3],
+ pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+ }
+
+ if (invitation_flag & P2P_INVITATION_FLAGS_PERSISTENT) {
+ /* Re-invoke the persistent group. */
+
+ _rtw_memset(&group_id, 0x00, sizeof(struct group_id_info));
+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *)&group_id, &attr_contentlen);
+ if (attr_contentlen) {
+ if (_rtw_memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) {
+ /* The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. */
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO);
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ status_code = P2P_STATUS_SUCCESS;
+ } else {
+ /* The p2p device sending this p2p invitation request wants to be the persistent GO. */
+ if (is_matched_in_profilelist(pwdinfo->p2p_peer_interface_addr, &pwdinfo->profileinfo[0])) {
+ u8 operatingch_info[5] = { 0x00 };
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) {
+ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, (u32)operatingch_info[4])) {
+ /* The operating channel is acceptable for this device. */
+ pwdinfo->rx_invitereq_info.operation_ch[0] = operatingch_info[4];
+ pwdinfo->rx_invitereq_info.scan_op_ch_only = 1;
+ _set_timer(&pwdinfo->reset_ch_sitesurvey, P2P_RESET_SCAN_CH);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH);
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ status_code = P2P_STATUS_SUCCESS;
+ } else {
+ /* The operating channel isn't supported by this device. */
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ status_code = P2P_STATUS_FAIL_NO_COMMON_CH;
+ _set_timer(&pwdinfo->restore_p2p_state_timer, 3000);
+ }
+ } else {
+ /* Commented by Albert 20121130 */
+ /* Intel will use the different P2P IE to store the operating channel information */
+ /* Workaround for Intel WiDi 3.5 */
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH);
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ status_code = P2P_STATUS_SUCCESS;
+ }
+ } else {
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
+ status_code = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP;
+ }
+ }
+ } else {
+ DBG_88E("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__);
+ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+ }
+ } else {
+ /* Received the invitation to join a P2P group. */
+
+ _rtw_memset(&group_id, 0x00, sizeof(struct group_id_info));
+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *)&group_id, &attr_contentlen);
+ if (attr_contentlen) {
+ if (_rtw_memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) {
+ /* In this case, the GO can't be myself. */
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
+ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+ } else {
+ /* The p2p device sending this p2p invitation request wants to join an existing P2P group */
+ /* Commented by Albert 2012/06/28 */
+ /* In this case, this Wi-Fi device should use the iwpriv command to get the peer device address. */
+ /* The peer device address should be the destination address for the provisioning discovery request. */
+ /* Then, this Wi-Fi device should use the iwpriv command to get the peer interface address. */
+ /* The peer interface address should be the address for WPS mac address */
+ memcpy(pwdinfo->p2p_peer_device_addr, group_id.go_device_addr , ETH_ALEN);
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_JOIN);
+ status_code = P2P_STATUS_SUCCESS;
+ }
+ } else {
+ DBG_88E("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__);
+ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+ }
+ }
+ } else {
+ DBG_88E("[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __func__);
+ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+ }
+
+ DBG_88E("[%s] status_code = %d\n", __func__, status_code);
+
+ pwdinfo->inviteresp_info.token = frame_body[7];
+ issue_p2p_invitation_response(padapter, GetAddr2Ptr(pframe), pwdinfo->inviteresp_info.token, status_code);
+ }
+ break;
+ case P2P_INVIT_RESP: {
+ u8 attr_content = 0x00;
+ u32 attr_contentlen = 0;
+
+ DBG_88E("[%s] Got invite response frame!\n", __func__);
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen);
+ if (p2p_ie) {
+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
+
+ if (attr_contentlen == 1) {
+ DBG_88E("[%s] Status = %d\n", __func__, attr_content);
+ pwdinfo->invitereq_info.benable = false;
+
+ if (attr_content == P2P_STATUS_SUCCESS) {
+ if (_rtw_memcmp(pwdinfo->invitereq_info.go_bssid, myid(&padapter->eeprompriv), ETH_ALEN)) {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ } else {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ }
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_OK);
+ } else {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL);
+ }
+ } else {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL);
+ }
+ } else {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL);
+ }
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL))
+ _set_timer(&pwdinfo->restore_p2p_state_timer, 5000);
+ break;
+ }
+ case P2P_DEVDISC_REQ:
+ process_p2p_devdisc_req(pwdinfo, pframe, len);
+ break;
+ case P2P_DEVDISC_RESP:
+ process_p2p_devdisc_resp(pwdinfo, pframe, len);
+ break;
+ case P2P_PROVISION_DISC_REQ:
+ DBG_88E("[%s] Got Provisioning Discovery Request Frame\n", __func__);
+ process_p2p_provdisc_req(pwdinfo, pframe, len);
+ memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN);
+
+ /* 20110902 Kurt */
+ /* Add the following statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ))
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ);
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT);
+ break;
+ case P2P_PROVISION_DISC_RESP:
+ /* Commented by Albert 20110707 */
+ /* Should we check the pwdinfo->tx_prov_disc_info.bsent flag here?? */
+ DBG_88E("[%s] Got Provisioning Discovery Response Frame\n", __func__);
+ /* Commented by Albert 20110426 */
+ /* The restore timer is enabled when issuing the provisioing request frame in rtw_p2p_prov_disc function. */
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP);
+ process_p2p_provdisc_resp(pwdinfo, pframe);
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT);
+ break;
+ }
+#endif /* CONFIG_88EU_P2P */
+
+ return _SUCCESS;
+}
+
+static unsigned int on_action_public_vendor(union recv_frame *precv_frame)
+{
+ unsigned int ret = _FAIL;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ if (_rtw_memcmp(frame_body + 2, P2P_OUI, 4) == true) {
+ ret = on_action_public_p2p(precv_frame);
+ }
+
+ return ret;
+}
+
+static unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action)
+{
+ unsigned int ret = _FAIL;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+ u8 token;
+
+ token = frame_body[2];
+
+ if (rtw_action_public_decache(precv_frame, token) == _FAIL)
+ goto exit;
+
+ ret = _SUCCESS;
+
+exit:
+ return ret;
+}
+
+unsigned int on_action_public(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ unsigned int ret = _FAIL;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+ u8 category, action;
+
+ /* check RA matches or not */
+ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))
+ goto exit;
+
+ category = frame_body[0];
+ if (category != RTW_WLAN_CATEGORY_PUBLIC)
+ goto exit;
+
+ action = frame_body[1];
+ switch (action) {
+ case ACT_PUBLIC_VENDOR:
+ ret = on_action_public_vendor(precv_frame);
+ break;
+ default:
+ ret = on_action_public_default(precv_frame, action);
+ break;
+ }
+
+exit:
+ return ret;
+}
+
+unsigned int OnAction_ht(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ return _SUCCESS;
+}
+
+unsigned int OnAction_wmm(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ return _SUCCESS;
+}
+
+unsigned int OnAction_p2p(struct adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_P2P
+ u8 *frame_body;
+ u8 category, OUI_Subtype;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ uint len = precv_frame->u.hdr.len;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+
+ DBG_88E("%s\n", __func__);
+
+ /* check RA matches or not */
+ if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */
+ return _SUCCESS;
+
+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+ category = frame_body[0];
+ if (category != RTW_WLAN_CATEGORY_P2P)
+ return _SUCCESS;
+
+ if (be32_to_cpu(*((__be32 *)(frame_body + 1))) != P2POUI)
+ return _SUCCESS;
+
+ len -= sizeof(struct rtw_ieee80211_hdr_3addr);
+ OUI_Subtype = frame_body[5];
+
+ switch (OUI_Subtype) {
+ case P2P_NOTICE_OF_ABSENCE:
+ break;
+ case P2P_PRESENCE_REQUEST:
+ process_p2p_presence_req(pwdinfo, pframe, len);
+ break;
+ case P2P_PRESENCE_RESPONSE:
+ break;
+ case P2P_GO_DISC_REQUEST:
+ break;
+ default:
+ break;
+ }
+#endif /* CONFIG_88EU_P2P */
+ return _SUCCESS;
+}
+
+unsigned int OnAction(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ int i;
+ unsigned char category;
+ struct action_handler *ptable;
+ unsigned char *frame_body;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+
+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+ category = frame_body[0];
+
+ for (i = 0; i < sizeof(OnAction_tbl)/sizeof(struct action_handler); i++) {
+ ptable = &OnAction_tbl[i];
+ if (category == ptable->num)
+ ptable->func(padapter, precv_frame);
+ }
+ return _SUCCESS;
+}
+
+unsigned int DoReserved(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ return _SUCCESS;
+}
+
+struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv)
+{
+ struct xmit_frame *pmgntframe;
+ struct xmit_buf *pxmitbuf;
+
+ pmgntframe = rtw_alloc_xmitframe(pxmitpriv);
+ if (pmgntframe == NULL) {
+ DBG_88E("%s, alloc xmitframe fail\n", __func__);
+ return NULL;
+ }
+
+ pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv);
+ if (pxmitbuf == NULL) {
+ DBG_88E("%s, alloc xmitbuf fail\n", __func__);
+ rtw_free_xmitframe(pxmitpriv, pmgntframe);
+ return NULL;
+ }
+ pmgntframe->frame_tag = MGNT_FRAMETAG;
+ pmgntframe->pxmitbuf = pxmitbuf;
+ pmgntframe->buf_addr = pxmitbuf->pbuf;
+ pxmitbuf->priv_data = pmgntframe;
+ return pmgntframe;
+}
+
+/****************************************************************************
+
+Following are some TX fuctions for WiFi MLME
+
+*****************************************************************************/
+
+void update_mgnt_tx_rate(struct adapter *padapter, u8 rate)
+{
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+ pmlmeext->tx_rate = rate;
+ DBG_88E("%s(): rate = %x\n", __func__, rate);
+}
+
+void update_mgntframe_attrib(struct adapter *padapter, struct pkt_attrib *pattrib)
+{
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+ _rtw_memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib));
+
+ pattrib->hdrlen = 24;
+ pattrib->nr_frags = 1;
+ pattrib->priority = 7;
+ pattrib->mac_id = 0;
+ pattrib->qsel = 0x12;
+
+ pattrib->pktlen = 0;
+
+ if (pmlmeext->cur_wireless_mode & WIRELESS_11B)
+ pattrib->raid = 6;/* b mode */
+ else
+ pattrib->raid = 5;/* a/g mode */
+
+ pattrib->encrypt = _NO_PRIVACY_;
+ pattrib->bswenc = false;
+
+ pattrib->qos_en = false;
+ pattrib->ht_en = false;
+ pattrib->bwmode = HT_CHANNEL_WIDTH_20;
+ pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ pattrib->sgi = false;
+
+ pattrib->seqnum = pmlmeext->mgnt_seq;
+
+ pattrib->retry_ctrl = true;
+}
+
+void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe)
+{
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+ return;
+
+ rtw_hal_mgnt_xmit(padapter, pmgntframe);
+}
+
+s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms)
+{
+ s32 ret = _FAIL;
+ struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf;
+ struct submit_ctx sctx;
+
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+ return ret;
+
+ rtw_sctx_init(&sctx, timeout_ms);
+ pxmitbuf->sctx = &sctx;
+
+ ret = rtw_hal_mgnt_xmit(padapter, pmgntframe);
+
+ if (ret == _SUCCESS)
+ ret = rtw_sctx_wait(&sctx);
+
+ return ret;
+}
+
+s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmgntframe)
+{
+ s32 ret = _FAIL;
+ u32 timeout_ms = 500;/* 500ms */
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+ return -1;
+
+ _enter_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL);
+ pxmitpriv->ack_tx = true;
+
+ pmgntframe->ack_report = 1;
+ if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) {
+ ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms);
+ }
+
+ pxmitpriv->ack_tx = false;
+ _exit_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL);
+
+ return ret;
+}
+
+static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode)
+{
+ u8 *ssid_ie;
+ int ssid_len_ori;
+ int len_diff = 0;
+
+ ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len);
+
+ if (ssid_ie && ssid_len_ori > 0) {
+ switch (hidden_ssid_mode) {
+ case 1: {
+ u8 *next_ie = ssid_ie + 2 + ssid_len_ori;
+ u32 remain_len = 0;
+
+ remain_len = ies_len - (next_ie - ies);
+
+ ssid_ie[1] = 0;
+ memcpy(ssid_ie+2, next_ie, remain_len);
+ len_diff -= ssid_len_ori;
+
+ break;
+ }
+ case 2:
+ _rtw_memset(&ssid_ie[2], 0, ssid_len_ori);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return len_diff;
+}
+
+void issue_beacon(struct adapter *padapter, int timeout_ms)
+{
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ unsigned int rate_len;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+#if defined(CONFIG_88EU_AP_MODE)
+ unsigned long irqL;
+#endif /* if defined (CONFIG_88EU_AP_MODE) */
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL) {
+ DBG_88E("%s, alloc mgnt frame fail\n", __func__);
+ return;
+ }
+#if defined (CONFIG_88EU_AP_MODE)
+ _enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+#endif /* if defined (CONFIG_88EU_AP_MODE) */
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+ pattrib->qsel = 0x10;
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
+ /* pmlmeext->mgnt_seq++; */
+ SetFrameSubType(pframe, WIFI_BEACON);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr);
+
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+#ifdef CONFIG_88EU_P2P
+ /* for P2P : Primary Device Type & Device Name */
+ u32 wpsielen = 0, insert_len = 0;
+ u8 *wpsie = NULL;
+ wpsie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wpsielen);
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wpsie && wpsielen > 0) {
+ uint wps_offset, remainder_ielen;
+ u8 *premainder_ie, *pframe_wscie;
+
+ wps_offset = (uint)(wpsie - cur_network->IEs);
+ premainder_ie = wpsie + wpsielen;
+ remainder_ielen = cur_network->IELength - wps_offset - wpsielen;
+ pframe_wscie = pframe + wps_offset;
+ memcpy(pframe, cur_network->IEs, wps_offset+wpsielen);
+ pframe += (wps_offset + wpsielen);
+ pattrib->pktlen += (wps_offset + wpsielen);
+
+ /* now pframe is end of wsc ie, insert Primary Device Type & Device Name */
+ /* Primary Device Type */
+ /* Type: */
+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+ insert_len += 2;
+
+ /* Length: */
+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(0x0008);
+ insert_len += 2;
+
+ /* Value: */
+ /* Category ID */
+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+ insert_len += 2;
+
+ /* OUI */
+ *(__be32 *)(pframe + insert_len) = cpu_to_be32(WPSOUI);
+ insert_len += 4;
+
+ /* Sub Category ID */
+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+ insert_len += 2;
+
+ /* Device Name */
+ /* Type: */
+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+ insert_len += 2;
+
+ /* Length: */
+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(pwdinfo->device_name_len);
+ insert_len += 2;
+
+ /* Value: */
+ memcpy(pframe + insert_len, pwdinfo->device_name, pwdinfo->device_name_len);
+ insert_len += pwdinfo->device_name_len;
+
+ /* update wsc ie length */
+ *(pframe_wscie+1) = (wpsielen-2) + insert_len;
+
+ /* pframe move to end */
+ pframe += insert_len;
+ pattrib->pktlen += insert_len;
+
+ /* copy remainder_ie to pframe */
+ memcpy(pframe, premainder_ie, remainder_ielen);
+ pframe += remainder_ielen;
+ pattrib->pktlen += remainder_ielen;
+ } else
+#endif /* CONFIG_88EU_P2P */
+ {
+ int len_diff;
+ memcpy(pframe, cur_network->IEs, cur_network->IELength);
+ len_diff = update_hidden_ssid(
+ pframe+_BEACON_IE_OFFSET_
+ , cur_network->IELength-_BEACON_IE_OFFSET_
+ , pmlmeinfo->hidden_ssid_mode
+ );
+ pframe += (cur_network->IELength+len_diff);
+ pattrib->pktlen += (cur_network->IELength+len_diff);
+ }
+
+ {
+ u8 *wps_ie;
+ uint wps_ielen;
+ u8 sr = 0;
+ wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr+TXDESC_OFFSET+sizeof (struct rtw_ieee80211_hdr_3addr)+_BEACON_IE_OFFSET_,
+ pattrib->pktlen-sizeof (struct rtw_ieee80211_hdr_3addr)-_BEACON_IE_OFFSET_, NULL, &wps_ielen);
+ if (wps_ie && wps_ielen > 0)
+ rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL);
+ if (sr != 0)
+ set_fwstate(pmlmepriv, WIFI_UNDER_WPS);
+ else
+ _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS);
+ }
+
+#ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ u32 len;
+ len = build_beacon_p2p_ie(pwdinfo, pframe);
+
+ pframe += len;
+ pattrib->pktlen += len;
+ }
+#endif /* CONFIG_88EU_P2P */
+
+ goto _issue_bcn;
+ }
+
+ /* below for ad-hoc mode */
+
+ /* timestamp will be inserted by hardware */
+ pframe += 8;
+ pattrib->pktlen += 8;
+
+ /* beacon interval: 2 bytes */
+
+ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
+
+ pframe += 2;
+ pattrib->pktlen += 2;
+
+ /* capability info: 2 bytes */
+
+ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2);
+
+ pframe += 2;
+ pattrib->pktlen += 2;
+
+ /* SSID */
+ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen);
+
+ /* supported rates... */
+ rate_len = rtw_get_rateset_len(cur_network->SupportedRates);
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen);
+
+ /* DS parameter set */
+ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen);
+
+ {
+ u8 erpinfo = 0;
+ u32 ATIMWindow;
+ /* IBSS Parameter Set... */
+ ATIMWindow = 0;
+ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen);
+
+ /* ERP IE */
+ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen);
+ }
+
+ /* EXTERNDED SUPPORTED RATE */
+ if (rate_len > 8)
+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen);
+ /* todo:HT for adhoc */
+_issue_bcn:
+
+#if defined (CONFIG_88EU_AP_MODE)
+ pmlmepriv->update_bcn = false;
+
+ _exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+#endif /* if defined (CONFIG_88EU_AP_MODE) */
+
+ if ((pattrib->pktlen + TXDESC_SIZE) > 512) {
+ DBG_88E("beacon frame too large\n");
+ return;
+ }
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ /* DBG_88E("issue bcn_sz=%d\n", pattrib->last_txcmdsz); */
+ if (timeout_ms > 0)
+ dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms);
+ else
+ dump_mgntframe(padapter, pmgntframe);
+}
+
+void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq)
+{
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ unsigned char *mac, *bssid;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+#if defined (CONFIG_88EU_AP_MODE)
+ u8 *pwps_ie;
+ uint wps_ielen;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#endif /* if defined (CONFIG_88EU_AP_MODE) */
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+ unsigned int rate_len;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL) {
+ DBG_88E("%s, alloc mgnt frame fail\n", __func__);
+ return;
+ }
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ mac = myid(&(padapter->eeprompriv));
+ bssid = cur_network->MacAddress;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+ memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, bssid, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(fctrl, WIFI_PROBERSP);
+
+ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = pattrib->hdrlen;
+ pframe += pattrib->hdrlen;
+
+ if (cur_network->IELength > MAX_IE_SZ)
+ return;
+
+#if defined(CONFIG_88EU_AP_MODE)
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+ pwps_ie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen);
+
+ /* inerset & update wps_probe_resp_ie */
+ if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && (wps_ielen > 0)) {
+ uint wps_offset, remainder_ielen;
+ u8 *premainder_ie;
+
+ wps_offset = (uint)(pwps_ie - cur_network->IEs);
+
+ premainder_ie = pwps_ie + wps_ielen;
+
+ remainder_ielen = cur_network->IELength - wps_offset - wps_ielen;
+
+ memcpy(pframe, cur_network->IEs, wps_offset);
+ pframe += wps_offset;
+ pattrib->pktlen += wps_offset;
+
+ wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */
+ if ((wps_offset+wps_ielen+2) <= MAX_IE_SZ) {
+ memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2);
+ pframe += wps_ielen+2;
+ pattrib->pktlen += wps_ielen+2;
+ }
+
+ if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) {
+ memcpy(pframe, premainder_ie, remainder_ielen);
+ pframe += remainder_ielen;
+ pattrib->pktlen += remainder_ielen;
+ }
+ } else {
+ memcpy(pframe, cur_network->IEs, cur_network->IELength);
+ pframe += cur_network->IELength;
+ pattrib->pktlen += cur_network->IELength;
+ }
+ } else
+#endif
+ {
+ /* timestamp will be inserted by hardware */
+ pframe += 8;
+ pattrib->pktlen += 8;
+
+ /* beacon interval: 2 bytes */
+
+ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
+
+ pframe += 2;
+ pattrib->pktlen += 2;
+
+ /* capability info: 2 bytes */
+
+ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2);
+
+ pframe += 2;
+ pattrib->pktlen += 2;
+
+ /* below for ad-hoc mode */
+
+ /* SSID */
+ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen);
+
+ /* supported rates... */
+ rate_len = rtw_get_rateset_len(cur_network->SupportedRates);
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen);
+
+ /* DS parameter set */
+ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen);
+
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+ u8 erpinfo = 0;
+ u32 ATIMWindow;
+ /* IBSS Parameter Set... */
+ /* ATIMWindow = cur->Configuration.ATIMWindow; */
+ ATIMWindow = 0;
+ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen);
+
+ /* ERP IE */
+ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen);
+ }
+
+
+ /* EXTERNDED SUPPORTED RATE */
+ if (rate_len > 8)
+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen);
+ /* todo:HT for adhoc */
+ }
+
+#ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && is_valid_p2p_probereq) {
+ u32 len;
+ len = build_probe_resp_p2p_ie(pwdinfo, pframe);
+
+ pframe += len;
+ pattrib->pktlen += len;
+ }
+#endif /* CONFIG_88EU_P2P */
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+
+ return;
+}
+
+static int _issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, int wait_ack)
+{
+ int ret = _FAIL;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ unsigned char *mac;
+ unsigned char bssrate[NumRates];
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ int bssrate_len = 0;
+ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n"));
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ goto exit;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ mac = myid(&(padapter->eeprompriv));
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ if (da) {
+ /* unicast probe request frame */
+ memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, da, ETH_ALEN);
+ } else {
+ /* broadcast probe request frame */
+ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN);
+ }
+
+ memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_PROBEREQ);
+
+ pframe += sizeof (struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr);
+
+ if (pssid)
+ pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &(pattrib->pktlen));
+ else
+ pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &(pattrib->pktlen));
+
+ get_rate_set(padapter, bssrate, &bssrate_len);
+
+ if (bssrate_len > 8) {
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen));
+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen));
+ } else {
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen));
+ }
+
+ /* add wps_ie for wps2.0 */
+ if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) {
+ memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len);
+ pframe += pmlmepriv->wps_probe_req_ie_len;
+ pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len;
+ }
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+ ("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz));
+
+ if (wait_ack) {
+ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
+ } else {
+ dump_mgntframe(padapter, pmgntframe);
+ ret = _SUCCESS;
+ }
+
+exit:
+ return ret;
+}
+
+inline void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da)
+{
+ _issue_probereq(padapter, pssid, da, false);
+}
+
+int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da,
+ int try_cnt, int wait_ms)
+{
+ int ret;
+ int i = 0;
+ u32 start = rtw_get_current_time();
+
+ do {
+ ret = _issue_probereq(padapter, pssid, da, wait_ms > 0 ? true : false);
+
+ i++;
+
+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+ break;
+
+ if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+ rtw_msleep_os(wait_ms);
+
+ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+ if (ret != _FAIL) {
+ ret = _SUCCESS;
+ goto exit;
+ }
+
+ if (try_cnt && wait_ms) {
+ if (da)
+ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
+ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ else
+ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ }
+exit:
+ return ret;
+}
+
+/* if psta == NULL, indiate we are station(client) now... */
+void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short status)
+{
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ unsigned int val32;
+ u16 val16;
+#ifdef CONFIG_88EU_AP_MODE
+ __le16 le_val16;
+#endif
+ int use_shared_key = 0;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_AUTH);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+
+ if (psta) {/* for AP mode */
+#ifdef CONFIG_88EU_AP_MODE
+
+ memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+
+ /* setting auth algo number */
+ val16 = (u16)psta->authalg;
+
+ if (status != _STATS_SUCCESSFUL_)
+ val16 = 0;
+
+ if (val16) {
+ le_val16 = cpu_to_le16(val16);
+ use_shared_key = 1;
+ } else {
+ le_val16 = 0;
+ }
+
+ pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_val16, &(pattrib->pktlen));
+
+ /* setting auth seq number */
+ val16 = (u16)psta->auth_seq;
+ le_val16 = cpu_to_le16(val16);
+ pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_val16, &(pattrib->pktlen));
+
+ /* setting status code... */
+ val16 = status;
+ le_val16 = cpu_to_le16(val16);
+ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_val16, &(pattrib->pktlen));
+
+ /* added challenging text... */
+ if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1))
+ pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, psta->chg_txt, &(pattrib->pktlen));
+#endif
+ } else {
+ __le32 le_tmp32;
+ __le16 le_tmp16;
+ memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
+
+ /* setting auth algo number */
+ val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0;/* 0:OPEN System, 1:Shared key */
+ if (val16)
+ use_shared_key = 1;
+
+ /* setting IV for auth seq #3 */
+ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) {
+ val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30));
+ le_tmp32 = cpu_to_le32(val32);
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&le_tmp32, &(pattrib->pktlen));
+
+ pattrib->iv_len = 4;
+ }
+
+ le_tmp16 = cpu_to_le16(val16);
+ pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_tmp16, &(pattrib->pktlen));
+
+ /* setting auth seq number */
+ val16 = pmlmeinfo->auth_seq;
+ le_tmp16 = cpu_to_le16(val16);
+ pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_tmp16, &(pattrib->pktlen));
+
+
+ /* setting status code... */
+ le_tmp16 = cpu_to_le16(status);
+ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_tmp16, &(pattrib->pktlen));
+
+ /* then checking to see if sending challenging text... */
+ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) {
+ pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, pmlmeinfo->chg_txt, &(pattrib->pktlen));
+
+ SetPrivacy(fctrl);
+
+ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pattrib->encrypt = _WEP40_;
+
+ pattrib->icv_len = 4;
+
+ pattrib->pktlen += pattrib->icv_len;
+ }
+ }
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ rtw_wep_encrypt(padapter, (u8 *)pmgntframe);
+ DBG_88E("%s\n", __func__);
+ dump_mgntframe(padapter, pmgntframe);
+
+ return;
+}
+
+
+void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type)
+{
+#ifdef CONFIG_88EU_AP_MODE
+ struct xmit_frame *pmgntframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ struct pkt_attrib *pattrib;
+ unsigned char *pbuf, *pframe;
+ unsigned short val;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
+ u8 *ie = pnetwork->IEs;
+ __le16 lestatus, leval;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+ DBG_88E("%s\n", __func__);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN);
+ memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP))
+ SetFrameSubType(pwlanhdr, pkt_type);
+ else
+ return;
+
+ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen += pattrib->hdrlen;
+ pframe += pattrib->hdrlen;
+
+ /* capability */
+ val = *(unsigned short *)rtw_get_capability_from_ie(ie);
+
+ pframe = rtw_set_fixed_ie(pframe, _CAPABILITY_ , (unsigned char *)&val, &(pattrib->pktlen));
+
+ lestatus = cpu_to_le16(status);
+ pframe = rtw_set_fixed_ie(pframe , _STATUS_CODE_ , (unsigned char *)&lestatus, &(pattrib->pktlen));
+
+ leval = cpu_to_le16(pstat->aid | BIT(14) | BIT(15));
+ pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_ , (unsigned char *)&leval, &(pattrib->pktlen));
+
+ if (pstat->bssratelen <= 8) {
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, pstat->bssratelen, pstat->bssrateset, &(pattrib->pktlen));
+ } else {
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pstat->bssrateset, &(pattrib->pktlen));
+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (pstat->bssratelen-8), pstat->bssrateset+8, &(pattrib->pktlen));
+ }
+
+ if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) {
+ uint ie_len = 0;
+
+ /* FILL HT CAP INFO IE */
+ pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+ if (pbuf && ie_len > 0) {
+ memcpy(pframe, pbuf, ie_len+2);
+ pframe += (ie_len+2);
+ pattrib->pktlen += (ie_len+2);
+ }
+
+ /* FILL HT ADD INFO IE */
+ pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+ if (pbuf && ie_len > 0) {
+ memcpy(pframe, pbuf, ie_len+2);
+ pframe += (ie_len+2);
+ pattrib->pktlen += (ie_len+2);
+ }
+ }
+
+ /* FILL WMM IE */
+ if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) {
+ uint ie_len = 0;
+ unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
+
+ for (pbuf = ie + _BEACON_IE_OFFSET_;; pbuf += (ie_len + 2)) {
+ pbuf = rtw_get_ie(pbuf, _VENDOR_SPECIFIC_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
+ if (pbuf && _rtw_memcmp(pbuf+2, WMM_PARA_IE, 6)) {
+ memcpy(pframe, pbuf, ie_len+2);
+ pframe += (ie_len+2);
+ pattrib->pktlen += (ie_len+2);
+ break;
+ }
+
+ if ((pbuf == NULL) || (ie_len == 0))
+ break;
+ }
+ }
+
+ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK)
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen));
+
+ /* add WPS IE ie for wps 2.0 */
+ if (pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len > 0) {
+ memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len);
+
+ pframe += pmlmepriv->wps_assoc_resp_ie_len;
+ pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len;
+ }
+
+#ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && (pstat->is_p2p_device)) {
+ u32 len;
+
+ len = build_assoc_resp_p2p_ie(pwdinfo, pframe, pstat->p2p_status_code);
+
+ pframe += len;
+ pattrib->pktlen += len;
+ }
+#endif /* CONFIG_88EU_P2P */
+ pattrib->last_txcmdsz = pattrib->pktlen;
+ dump_mgntframe(padapter, pmgntframe);
+#endif
+}
+
+void issue_assocreq(struct adapter *padapter)
+{
+ int ret = _FAIL;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe, *p;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ __le16 le_tmp;
+ unsigned int i, j, ie_len, index = 0;
+ unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates];
+ struct ndis_802_11_var_ie *pIE;
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ int bssrate_len = 0, sta_bssrate_len = 0;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 p2pie[255] = { 0x00 };
+ u16 p2pielen = 0;
+#endif /* CONFIG_88EU_P2P */
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ goto exit;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ASSOCREQ);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ /* caps */
+
+ memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2);
+
+ pframe += 2;
+ pattrib->pktlen += 2;
+
+ /* listen interval */
+ /* todo: listen interval for power saving */
+ le_tmp = cpu_to_le16(3);
+ memcpy(pframe , (unsigned char *)&le_tmp, 2);
+ pframe += 2;
+ pattrib->pktlen += 2;
+
+ /* SSID */
+ pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &(pattrib->pktlen));
+
+ /* supported rate & extended supported rate */
+
+ /* Check if the AP's supported rates are also supported by STA. */
+ get_rate_set(padapter, sta_bssrate, &sta_bssrate_len);
+
+ if (pmlmeext->cur_channel == 14)/* for JAPAN, channel 14 can only uses B Mode(CCK) */
+ sta_bssrate_len = 4;
+
+ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+ if (pmlmeinfo->network.SupportedRates[i] == 0)
+ break;
+ DBG_88E("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]);
+ }
+
+ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+ if (pmlmeinfo->network.SupportedRates[i] == 0)
+ break;
+
+ /* Check if the AP's supported rates are also supported by STA. */
+ for (j = 0; j < sta_bssrate_len; j++) {
+ /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */
+ if ((pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK)
+ == (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK))
+ break;
+ }
+
+ if (j == sta_bssrate_len) {
+ /* the rate is not supported by STA */
+ DBG_88E("%s(): the rate[%d]=%02X is not supported by STA!\n", __func__, i, pmlmeinfo->network.SupportedRates[i]);
+ } else {
+ /* the rate is supported by STA */
+ bssrate[index++] = pmlmeinfo->network.SupportedRates[i];
+ }
+ }
+
+ bssrate_len = index;
+ DBG_88E("bssrate_len=%d\n", bssrate_len);
+
+ if (bssrate_len == 0) {
+ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf);
+ rtw_free_xmitframe(pxmitpriv, pmgntframe);
+ goto exit; /* don't connect to AP if no joint supported rate */
+ }
+
+
+ if (bssrate_len > 8) {
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen));
+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen));
+ } else {
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen));
+ }
+
+ /* RSN */
+ p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _RSN_IE_2_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie)));
+ if (p != NULL)
+ pframe = rtw_set_ie(pframe, _RSN_IE_2_, ie_len, (p + 2), &(pattrib->pktlen));
+
+ /* HT caps */
+ if (padapter->mlmepriv.htpriv.ht_option) {
+ p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_CAPABILITY_IE_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie)));
+ if ((p != NULL) && (!(is_ap_in_tkip(padapter)))) {
+ memcpy(&(pmlmeinfo->HT_caps), (p + 2), sizeof(struct HT_caps_element));
+
+ /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */
+ if (pregpriv->cbw40_enable == 0)
+ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info &= cpu_to_le16(~(BIT(6) | BIT(1)));
+ else
+ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(BIT(1));
+
+ /* todo: disable SM power save mode */
+ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x000c);
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+ switch (rf_type) {
+ case RF_1T1R:
+ if (pregpriv->rx_stbc)
+ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);/* RX STBC One spatial stream */
+ memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R, 16);
+ break;
+ case RF_2T2R:
+ case RF_1T2R:
+ default:
+ if ((pregpriv->rx_stbc == 0x3) ||/* enable for 2.4/5 GHz */
+ ((pmlmeext->cur_wireless_mode & WIRELESS_11_24N) && (pregpriv->rx_stbc == 0x1)) || /* enable for 2.4GHz */
+ (pregpriv->wifi_spec == 1)) {
+ DBG_88E("declare supporting RX STBC\n");
+ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0200);/* RX STBC two spatial stream */
+ }
+ memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R, 16);
+ break;
+ }
+ pframe = rtw_set_ie(pframe, _HT_CAPABILITY_IE_, ie_len , (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen));
+ }
+ }
+
+ /* vendor specific IE, such as WPA, WMM, WPS */
+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) {
+ pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i);
+
+ switch (pIE->ElementID) {
+ case _VENDOR_SPECIFIC_IE_:
+ if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) ||
+ (_rtw_memcmp(pIE->data, WMM_OUI, 4)) ||
+ (_rtw_memcmp(pIE->data, WPS_OUI, 4))) {
+ if (!padapter->registrypriv.wifi_spec) {
+ /* Commented by Kurt 20110629 */
+ /* In some older APs, WPS handshake */
+ /* would be fail if we append vender extensions informations to AP */
+ if (_rtw_memcmp(pIE->data, WPS_OUI, 4))
+ pIE->Length = 14;
+ }
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, pIE->Length, pIE->data, &(pattrib->pktlen));
+ }
+ break;
+ default:
+ break;
+ }
+ i += (pIE->Length + 2);
+ }
+
+ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK)
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen));
+
+#ifdef CONFIG_88EU_P2P
+
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) {
+ /* Should add the P2P IE in the association request frame. */
+ /* P2P OUI */
+
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Commented by Albert 20101109 */
+ /* According to the P2P Specification, the association request frame should contain 3 P2P attributes */
+ /* 1. P2P Capability */
+ /* 2. Extended Listen Timing */
+ /* 3. Device Info */
+ /* Commented by Albert 20110516 */
+ /* 4. P2P Interface */
+
+ /* P2P Capability */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Device Capability Bitmap, 1 byte */
+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+ /* Group Capability Bitmap, 1 byte */
+ if (pwdinfo->persistent_supported)
+ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
+ else
+ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
+
+ /* Extended Listen Timing */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Availability Period */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+ p2pielen += 2;
+
+ /* Availability Interval */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+ p2pielen += 2;
+
+ /* Device Info */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+ /* Length: */
+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ /* P2P Device Address */
+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ /* Config Method */
+ /* This field should be big endian. Noted by P2P specification. */
+ if ((pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) ||
+ (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN))
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY);
+ else
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC);
+
+ p2pielen += 2;
+
+ /* Primary Device Type */
+ /* Category ID */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+ p2pielen += 2;
+
+ /* OUI */
+ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+ p2pielen += 4;
+
+ /* Sub Category ID */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+ p2pielen += 2;
+
+ /* Number of Secondary Device Types */
+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */
+
+ /* Device Name */
+ /* Type: */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+ p2pielen += 2;
+
+ /* Length: */
+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+ p2pielen += pwdinfo->device_name_len;
+
+ /* P2P Interface */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_INTERFACE;
+
+ /* Length: */
+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x000D);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); /* P2P Device Address */
+ p2pielen += ETH_ALEN;
+
+ p2pie[p2pielen++] = 1; /* P2P Interface Address Count */
+
+ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); /* P2P Interface Address List */
+ p2pielen += ETH_ALEN;
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+ }
+
+#endif /* CONFIG_88EU_P2P */
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+ dump_mgntframe(padapter, pmgntframe);
+
+ ret = _SUCCESS;
+
+exit:
+ if (ret == _SUCCESS)
+ rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen);
+ else
+ rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len);
+
+ return;
+}
+
+/* when wait_ack is ture, this function shoule be called at process context */
+static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack)
+{
+ int ret = _FAIL;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv;
+ struct mlme_ext_priv *pmlmeext;
+ struct mlme_ext_info *pmlmeinfo;
+
+ if (!padapter)
+ goto exit;
+
+ pxmitpriv = &(padapter->xmitpriv);
+ pmlmeext = &(padapter->mlmeextpriv);
+ pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ goto exit;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+ pattrib->retry_ctrl = false;
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)
+ SetFrDs(fctrl);
+ else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+ SetToDs(fctrl);
+
+ if (power_mode)
+ SetPwrMgt(fctrl);
+
+ memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_DATA_NULL);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ if (wait_ack) {
+ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
+ } else {
+ dump_mgntframe(padapter, pmgntframe);
+ ret = _SUCCESS;
+ }
+
+exit:
+ return ret;
+}
+
+
+/* when wait_ms > 0 , this function shoule be called at process context */
+/* da == NULL for station mode */
+int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms)
+{
+ int ret;
+ int i = 0;
+ u32 start = rtw_get_current_time();
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ /* da == NULL, assum it's null data for sta to ap*/
+ if (da == NULL)
+ da = get_my_bssid(&(pmlmeinfo->network));
+
+ do {
+ ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0 ? true : false);
+
+ i++;
+
+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+ break;
+
+ if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+ rtw_msleep_os(wait_ms);
+ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+ if (ret != _FAIL) {
+ ret = _SUCCESS;
+ goto exit;
+ }
+
+ if (try_cnt && wait_ms) {
+ if (da)
+ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
+ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ else
+ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ }
+exit:
+ return ret;
+}
+
+/* when wait_ack is ture, this function shoule be called at process context */
+static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int wait_ack)
+{
+ int ret = _FAIL;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl, *qc;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ DBG_88E("%s\n", __func__);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ goto exit;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ pattrib->hdrlen += 2;
+ pattrib->qos_en = true;
+ pattrib->eosp = 1;
+ pattrib->ack_policy = 0;
+ pattrib->mdata = 0;
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)
+ SetFrDs(fctrl);
+ else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+ SetToDs(fctrl);
+
+ if (pattrib->mdata)
+ SetMData(fctrl);
+
+ qc = (unsigned short *)(pframe + pattrib->hdrlen - 2);
+
+ SetPriority(qc, tid);
+
+ SetEOSP(qc, pattrib->eosp);
+
+ SetAckpolicy(qc, pattrib->ack_policy);
+
+ memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr_qos);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos);
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ if (wait_ack) {
+ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
+ } else {
+ dump_mgntframe(padapter, pmgntframe);
+ ret = _SUCCESS;
+ }
+
+exit:
+ return ret;
+}
+
+/* when wait_ms > 0 , this function shoule be called at process context */
+/* da == NULL for station mode */
+int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms)
+{
+ int ret;
+ int i = 0;
+ u32 start = rtw_get_current_time();
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ /* da == NULL, assum it's null data for sta to ap*/
+ if (da == NULL)
+ da = get_my_bssid(&(pmlmeinfo->network));
+
+ do {
+ ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0 ? true : false);
+
+ i++;
+
+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+ break;
+
+ if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+ rtw_msleep_os(wait_ms);
+ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+ if (ret != _FAIL) {
+ ret = _SUCCESS;
+ goto exit;
+ }
+
+ if (try_cnt && wait_ms) {
+ if (da)
+ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
+ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ else
+ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ }
+exit:
+ return ret;
+}
+
+static int _issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason, u8 wait_ack)
+{
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ int ret = _FAIL;
+ __le16 le_tmp;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+#ifdef CONFIG_88EU_P2P
+ if (!(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) && (pwdinfo->rx_invitereq_info.scan_op_ch_only)) {
+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+ _set_timer(&pwdinfo->reset_ch_sitesurvey, 10);
+ }
+#endif /* CONFIG_88EU_P2P */
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ goto exit;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+ pattrib->retry_ctrl = false;
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_DEAUTH);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ le_tmp = cpu_to_le16(reason);
+ pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ , (unsigned char *)&le_tmp, &(pattrib->pktlen));
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+
+ if (wait_ack) {
+ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
+ } else {
+ dump_mgntframe(padapter, pmgntframe);
+ ret = _SUCCESS;
+ }
+
+exit:
+ return ret;
+}
+
+int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason)
+{
+ DBG_88E("%s to %pM\n", __func__, da);
+ return _issue_deauth(padapter, da, reason, false);
+}
+
+int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int try_cnt,
+ int wait_ms)
+{
+ int ret;
+ int i = 0;
+ u32 start = rtw_get_current_time();
+
+ do {
+ ret = _issue_deauth(padapter, da, reason, wait_ms > 0 ? true : false);
+
+ i++;
+
+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+ break;
+
+ if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+ rtw_msleep_os(wait_ms);
+ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+ if (ret != _FAIL) {
+ ret = _SUCCESS;
+ goto exit;
+ }
+
+ if (try_cnt && wait_ms) {
+ if (da)
+ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
+ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ else
+ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+ }
+exit:
+ return ret;
+}
+
+void issue_action_spct_ch_switch (struct adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset)
+{
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+
+ DBG_88E(FUNC_NDEV_FMT" ra =%pM, ch:%u, offset:%u\n",
+ FUNC_NDEV_ARG(padapter->pnetdev), ra, new_ch, ch_offset);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, ra, ETH_ALEN); /* RA */
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); /* TA */
+ memcpy(pwlanhdr->addr3, ra, ETH_ALEN); /* DA = RA */
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ /* category, action */
+ {
+ u8 category, action;
+ category = RTW_WLAN_CATEGORY_SPECTRUM_MGMT;
+ action = RTW_WLAN_ACTION_SPCT_CHL_SWITCH;
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+ }
+
+ pframe = rtw_set_ie_ch_switch (pframe, &(pattrib->pktlen), 0, new_ch, 0);
+ pframe = rtw_set_ie_secondary_ch_offset(pframe, &(pattrib->pktlen),
+ hal_ch_offset_to_secondary_ch_offset(ch_offset));
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+}
+
+void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status)
+{
+ u8 category = RTW_WLAN_CATEGORY_BACK;
+ u16 start_seq;
+ u16 BA_para_set;
+ u16 reason_code;
+ u16 BA_timeout_value;
+ __le16 le_tmp;
+ u16 BA_starting_seqctrl = 0;
+ enum ht_cap_ampdu_factor max_rx_ampdu_factor;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ u8 *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ u16 *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct sta_info *psta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+
+ DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ /* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */
+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+
+ if (category == 3) {
+ switch (action) {
+ case 0: /* ADDBA req */
+ do {
+ pmlmeinfo->dialogToken++;
+ } while (pmlmeinfo->dialogToken == 0);
+ pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen));
+
+ BA_para_set = (0x1002 | ((status & 0xf) << 2)); /* immediate ack & 64 buffer size */
+ le_tmp = cpu_to_le16(BA_para_set);
+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+
+ BA_timeout_value = 5000;/* 5ms */
+ le_tmp = cpu_to_le16(BA_timeout_value);
+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+
+ psta = rtw_get_stainfo(pstapriv, raddr);
+ if (psta != NULL) {
+ start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1;
+
+ DBG_88E("BA_starting_seqctrl=%d for TID=%d\n", start_seq, status & 0x07);
+
+ psta->BA_starting_seqctrl[status & 0x07] = start_seq;
+
+ BA_starting_seqctrl = start_seq << 4;
+ }
+ le_tmp = cpu_to_le16(BA_starting_seqctrl);
+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+ break;
+ case 1: /* ADDBA rsp */
+ pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen));
+ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
+ if (MAX_AMPDU_FACTOR_64K == max_rx_ampdu_factor)
+ BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */
+ else if (MAX_AMPDU_FACTOR_32K == max_rx_ampdu_factor)
+ BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0800); /* 32 buffer size */
+ else if (MAX_AMPDU_FACTOR_16K == max_rx_ampdu_factor)
+ BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0400); /* 16 buffer size */
+ else if (MAX_AMPDU_FACTOR_8K == max_rx_ampdu_factor)
+ BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0200); /* 8 buffer size */
+ else
+ BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */
+
+ if (pregpriv->ampdu_amsdu == 0)/* disabled */
+ BA_para_set = BA_para_set & ~BIT(0);
+ else if (pregpriv->ampdu_amsdu == 1)/* enabled */
+ BA_para_set = BA_para_set | BIT(0);
+ le_tmp = cpu_to_le16(BA_para_set);
+
+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), &(pattrib->pktlen));
+ break;
+ case 2:/* DELBA */
+ BA_para_set = (status & 0x1F) << 3;
+ le_tmp = cpu_to_le16(BA_para_set);
+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+
+ reason_code = 37;/* Requested from peer STA as it does not want to use the mechanism */
+ le_tmp = cpu_to_le16(reason_code);
+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+ break;
+ default:
+ break;
+ }
+ }
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+}
+
+static void issue_action_BSSCoexistPacket(struct adapter *padapter)
+{
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ unsigned char category, action;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct wlan_network *pnetwork = NULL;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ u8 InfoContent[16] = {0};
+ u8 ICS[8][15];
+ if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0))
+ return;
+
+ if (pmlmeinfo->bwmode_updated)
+ return;
+
+
+ DBG_88E("%s\n", __func__);
+
+
+ category = RTW_WLAN_CATEGORY_PUBLIC;
+ action = ACT_PUBLIC_BSSCOEXIST;
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+
+
+ /* */
+ if (pmlmepriv->num_FortyMHzIntolerant > 0) {
+ u8 iedata = 0;
+
+ iedata |= BIT(2);/* 20 MHz BSS Width Request */
+
+ pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen));
+ }
+
+
+ /* */
+ _rtw_memset(ICS, 0, sizeof(ICS));
+ if (pmlmepriv->num_sta_no_ht > 0) {
+ int i;
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ int len;
+ u8 *p;
+ struct wlan_bssid_ex *pbss_network;
+
+ if (rtw_end_of_queue_search(phead, plist))
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ plist = get_next(plist);
+
+ pbss_network = (struct wlan_bssid_ex *)&pnetwork->network;
+
+ p = rtw_get_ie(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_);
+ if ((p == NULL) || (len == 0)) { /* non-HT */
+ if ((pbss_network->Configuration.DSConfig <= 0) || (pbss_network->Configuration.DSConfig > 14))
+ continue;
+
+ ICS[0][pbss_network->Configuration.DSConfig] = 1;
+
+ if (ICS[0][0] == 0)
+ ICS[0][0] = 1;
+ }
+ }
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ for (i = 0; i < 8; i++) {
+ if (ICS[i][0] == 1) {
+ int j, k = 0;
+
+ InfoContent[k] = i;
+ /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */
+ k++;
+
+ for (j = 1; j <= 14; j++) {
+ if (ICS[i][j] == 1) {
+ if (k < 16) {
+ InfoContent[k] = j; /* channel number */
+ /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */
+ k++;
+ }
+ }
+ }
+
+ pframe = rtw_set_ie(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &(pattrib->pktlen));
+ }
+ }
+ }
+
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+}
+
+unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr)
+{
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct sta_info *psta = NULL;
+ /* struct recv_reorder_ctrl *preorder_ctrl; */
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u16 tid;
+
+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
+ return _SUCCESS;
+
+ psta = rtw_get_stainfo(pstapriv, addr);
+ if (psta == NULL)
+ return _SUCCESS;
+
+ if (initiator == 0) { /* recipient */
+ for (tid = 0; tid < MAXTID; tid++) {
+ if (psta->recvreorder_ctrl[tid].enable) {
+ DBG_88E("rx agg disable tid(%d)\n", tid);
+ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F));
+ psta->recvreorder_ctrl[tid].enable = false;
+ psta->recvreorder_ctrl[tid].indicate_seq = 0xffff;
+ }
+ }
+ } else if (initiator == 1) { /* originator */
+ for (tid = 0; tid < MAXTID; tid++) {
+ if (psta->htpriv.agg_enable_bitmap & BIT(tid)) {
+ DBG_88E("tx agg disable tid(%d)\n", tid);
+ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F));
+ psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
+ psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
+ }
+ }
+ }
+
+ return _SUCCESS;
+}
+
+unsigned int send_beacon(struct adapter *padapter)
+{
+ u8 bxmitok = false;
+ int issue = 0;
+ int poll = 0;
+
+ u32 start = rtw_get_current_time();
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
+ do {
+ issue_beacon(padapter, 100);
+ issue++;
+ do {
+ rtw_yield_os();
+ rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok));
+ poll++;
+ } while ((poll%10) != 0 && !bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
+ } while (!bxmitok && issue < 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
+
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+ return _FAIL;
+ if (!bxmitok) {
+ DBG_88E("%s fail! %u ms\n", __func__, rtw_get_passing_time_ms(start));
+ return _FAIL;
+ } else {
+ u32 passing_time = rtw_get_passing_time_ms(start);
+
+ if (passing_time > 100 || issue > 3)
+ DBG_88E("%s success, issue:%d, poll:%d, %u ms\n", __func__, issue, poll, rtw_get_passing_time_ms(start));
+ return _SUCCESS;
+ }
+}
+
+/****************************************************************************
+
+Following are some utitity fuctions for WiFi MLME
+
+*****************************************************************************/
+
+void site_survey(struct adapter *padapter)
+{
+ unsigned char survey_channel = 0, val8;
+ enum rt_scan_type ScanType = SCAN_PASSIVE;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u32 initialgain = 0;
+
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only)) {
+ if (pwdinfo->rx_invitereq_info.scan_op_ch_only) {
+ survey_channel = pwdinfo->rx_invitereq_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx];
+ } else {
+ survey_channel = pwdinfo->p2p_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx];
+ }
+ ScanType = SCAN_ACTIVE;
+ } else if (rtw_p2p_findphase_ex_is_social(pwdinfo)) {
+ /* Commented by Albert 2011/06/03 */
+ /* The driver is in the find phase, it should go through the social channel. */
+ int ch_set_idx;
+ survey_channel = pwdinfo->social_chan[pmlmeext->sitesurvey_res.channel_idx];
+ ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, survey_channel);
+ if (ch_set_idx >= 0)
+ ScanType = pmlmeext->channel_set[ch_set_idx].ScanType;
+ else
+ ScanType = SCAN_ACTIVE;
+ } else
+#endif /* CONFIG_88EU_P2P */
+ {
+ struct rtw_ieee80211_channel *ch;
+ if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) {
+ ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx];
+ survey_channel = ch->hw_value;
+ ScanType = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE;
+ }
+ }
+
+ if (survey_channel != 0) {
+ /* PAUSE 4-AC Queue when site_survey */
+ /* rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */
+ /* val8 |= 0x0f; */
+ /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */
+ if (pmlmeext->sitesurvey_res.channel_idx == 0)
+ set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+ else
+ SelectChannel(padapter, survey_channel);
+
+ if (ScanType == SCAN_ACTIVE) { /* obey the channel plan setting... */
+ #ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) ||
+ rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) {
+ issue_probereq_p2p(padapter, NULL);
+ issue_probereq_p2p(padapter, NULL);
+ issue_probereq_p2p(padapter, NULL);
+ } else
+ #endif /* CONFIG_88EU_P2P */
+ {
+ int i;
+ for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
+ if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) {
+ /* todo: to issue two probe req??? */
+ issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL);
+ /* rtw_msleep_os(SURVEY_TO>>1); */
+ issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL);
+ }
+ }
+
+ if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) {
+ /* todo: to issue two probe req??? */
+ issue_probereq(padapter, NULL, NULL);
+ /* rtw_msleep_os(SURVEY_TO>>1); */
+ issue_probereq(padapter, NULL, NULL);
+ }
+ }
+ }
+
+ set_survey_timer(pmlmeext, pmlmeext->chan_scan_time);
+ } else {
+ /* channel number is 0 or this channel is not valid. */
+
+#ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) {
+ if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only)) {
+ /* Set the find_phase_state_exchange_cnt to P2P_FINDPHASE_EX_CNT. */
+ /* This will let the following flow to run the scanning end. */
+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX);
+ }
+ }
+
+ if (rtw_p2p_findphase_ex_is_needed(pwdinfo)) {
+ /* Set the P2P State to the listen state of find phase and set the current channel to the listen channel */
+ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN);
+ pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
+
+ initialgain = 0xff; /* restore RX GAIN */
+ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain));
+ /* turn on dynamic functions */
+ Restore_DM_Func_Flag(padapter);
+ /* Switch_DM_Func(padapter, DYNAMIC_FUNC_DIG|DYNAMIC_FUNC_HP|DYNAMIC_FUNC_SS, true); */
+
+ _set_timer(&pwdinfo->find_phase_timer, (u32)((u32)(pwdinfo->listen_dwell) * 100));
+ } else
+#endif /* CONFIG_88EU_P2P */
+ {
+ /* 20100721:Interrupt scan operation here. */
+ /* For SW antenna diversity before link, it needs to switch to another antenna and scan again. */
+ /* It compares the scan result and select beter one to do connection. */
+ if (rtw_hal_antdiv_before_linked(padapter)) {
+ pmlmeext->sitesurvey_res.bss_cnt = 0;
+ pmlmeext->sitesurvey_res.channel_idx = -1;
+ pmlmeext->chan_scan_time = SURVEY_TO / 2;
+ set_survey_timer(pmlmeext, pmlmeext->chan_scan_time);
+ return;
+ }
+#ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH))
+ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
+#endif /* CONFIG_88EU_P2P */
+
+ pmlmeext->sitesurvey_res.state = SCAN_COMPLETE;
+
+ /* switch back to the original channel */
+
+#ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN))
+ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+ else
+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+#endif /* CONFIG_88EU_P2P */
+
+ /* flush 4-AC Queue after site_survey */
+ /* val8 = 0; */
+ /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */
+
+ /* config MSR */
+ Set_MSR(padapter, (pmlmeinfo->state & 0x3));
+
+ initialgain = 0xff; /* restore RX GAIN */
+ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain));
+ /* turn on dynamic functions */
+ Restore_DM_Func_Flag(padapter);
+ /* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */
+
+ if (is_client_associated_to_ap(padapter))
+ issue_nulldata(padapter, NULL, 0, 3, 500);
+
+ val8 = 0; /* survey done */
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+
+ report_surveydone_event(padapter);
+
+ pmlmeext->chan_scan_time = SURVEY_TO;
+ pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
+
+ issue_action_BSSCoexistPacket(padapter);
+ issue_action_BSSCoexistPacket(padapter);
+ issue_action_BSSCoexistPacket(padapter);
+ }
+ }
+ return;
+}
+
+/* collect bss info from Beacon and Probe request/response frames. */
+u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, struct wlan_bssid_ex *bssid)
+{
+ int i;
+ u32 len;
+ u8 *p;
+ u16 val16, subtype;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ u32 packet_len = precv_frame->u.hdr.len;
+ u8 ie_offset;
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ __le32 le32_tmp;
+
+ len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ if (len > MAX_IE_SZ)
+ return _FAIL;
+
+ _rtw_memset(bssid, 0, sizeof(struct wlan_bssid_ex));
+
+ subtype = GetFrameSubType(pframe);
+
+ if (subtype == WIFI_BEACON) {
+ bssid->Reserved[0] = 1;
+ ie_offset = _BEACON_IE_OFFSET_;
+ } else {
+ /* FIXME : more type */
+ if (subtype == WIFI_PROBEREQ) {
+ ie_offset = _PROBEREQ_IE_OFFSET_;
+ bssid->Reserved[0] = 2;
+ } else if (subtype == WIFI_PROBERSP) {
+ ie_offset = _PROBERSP_IE_OFFSET_;
+ bssid->Reserved[0] = 3;
+ } else {
+ bssid->Reserved[0] = 0;
+ ie_offset = _FIXED_IE_LENGTH_;
+ }
+ }
+
+ bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len;
+
+ /* below is to copy the information element */
+ bssid->IELength = len;
+ memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength);
+
+ /* get the signal strength */
+ bssid->Rssi = precv_frame->u.hdr.attrib.phy_info.recvpower; /* in dBM.raw data */
+ bssid->PhyInfo.SignalQuality = precv_frame->u.hdr.attrib.phy_info.SignalQuality;/* in percentage */
+ bssid->PhyInfo.SignalStrength = precv_frame->u.hdr.attrib.phy_info.SignalStrength;/* in percentage */
+ rtw_hal_get_def_var(padapter, HAL_DEF_CURRENT_ANTENNA, &bssid->PhyInfo.Optimum_antenna);
+
+ /* checking SSID */
+ p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset);
+ if (p == NULL) {
+ DBG_88E("marc: cannot find SSID for survey event\n");
+ return _FAIL;
+ }
+
+ if (*(p + 1)) {
+ if (len > NDIS_802_11_LENGTH_SSID) {
+ DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+ return _FAIL;
+ }
+ memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1));
+ bssid->Ssid.SsidLength = *(p + 1);
+ } else {
+ bssid->Ssid.SsidLength = 0;
+ }
+
+ _rtw_memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
+
+ /* checking rate info... */
+ i = 0;
+ p = rtw_get_ie(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset);
+ if (p != NULL) {
+ if (len > NDIS_802_11_LENGTH_RATES_EX) {
+ DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+ return _FAIL;
+ }
+ memcpy(bssid->SupportedRates, (p + 2), len);
+ i = len;
+ }
+
+ p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset);
+ if (p != NULL) {
+ if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) {
+ DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+ return _FAIL;
+ }
+ memcpy(bssid->SupportedRates + i, (p + 2), len);
+ }
+
+ /* todo: */
+ bssid->NetworkTypeInUse = Ndis802_11OFDM24;
+
+ if (bssid->IELength < 12)
+ return _FAIL;
+
+ /* Checking for DSConfig */
+ p = rtw_get_ie(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset);
+
+ bssid->Configuration.DSConfig = 0;
+ bssid->Configuration.Length = 0;
+
+ if (p) {
+ bssid->Configuration.DSConfig = *(p + 2);
+ } else {/* In 5G, some ap do not have DSSET IE */
+ /* checking HT info for channel */
+ p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset);
+ if (p) {
+ struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2);
+ bssid->Configuration.DSConfig = HT_info->primary_channel;
+ } else { /* use current channel */
+ bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter);
+ }
+ }
+
+ if (subtype == WIFI_PROBEREQ) {
+ /* FIXME */
+ bssid->InfrastructureMode = Ndis802_11Infrastructure;
+ memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN);
+ bssid->Privacy = 1;
+ return _SUCCESS;
+ }
+
+ memcpy(&le32_tmp, rtw_get_beacon_interval_from_ie(bssid->IEs), 2);
+ bssid->Configuration.BeaconPeriod = le32_to_cpu(le32_tmp);
+
+ val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid);
+
+ if (val16 & BIT(0)) {
+ bssid->InfrastructureMode = Ndis802_11Infrastructure;
+ memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN);
+ } else {
+ bssid->InfrastructureMode = Ndis802_11IBSS;
+ memcpy(bssid->MacAddress, GetAddr3Ptr(pframe), ETH_ALEN);
+ }
+
+ if (val16 & BIT(4))
+ bssid->Privacy = 1;
+ else
+ bssid->Privacy = 0;
+
+ bssid->Configuration.ATIMWindow = 0;
+
+ /* 20/40 BSS Coexistence check */
+ if ((pregistrypriv->wifi_spec == 1) && (!pmlmeinfo->bwmode_updated)) {
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset);
+ if (p && len > 0) {
+ struct HT_caps_element *pHT_caps;
+ pHT_caps = (struct HT_caps_element *)(p + 2);
+
+ if (le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info)&BIT(14))
+ pmlmepriv->num_FortyMHzIntolerant++;
+ } else {
+ pmlmepriv->num_sta_no_ht++;
+ }
+ }
+
+ /* mark bss info receving from nearby channel as SignalQuality 101 */
+ if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter))
+ bssid->PhyInfo.SignalQuality = 101;
+ return _SUCCESS;
+}
+
+void start_create_ibss(struct adapter *padapter)
+{
+ unsigned short caps;
+ u8 val8;
+ u8 join_type;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+ pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig;
+ pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork);
+
+ /* update wireless mode */
+ update_wireless_mode(padapter);
+
+ /* udpate capability */
+ caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork);
+ update_capinfo(padapter, caps);
+ if (caps&cap_IBSS) {/* adhoc master */
+ val8 = 0xcf;
+ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+ /* switch channel */
+ /* SelectChannel(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */
+ set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+
+ beacon_timing_control(padapter);
+
+ /* set msr to WIFI_FW_ADHOC_STATE */
+ pmlmeinfo->state = WIFI_FW_ADHOC_STATE;
+ Set_MSR(padapter, (pmlmeinfo->state & 0x3));
+
+ /* issue beacon */
+ if (send_beacon(padapter) == _FAIL) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("issuing beacon frame fail....\n"));
+
+ report_join_res(padapter, -1);
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+ } else {
+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress);
+ join_type = 0;
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+
+ report_join_res(padapter, 1);
+ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
+ }
+ } else {
+ DBG_88E("start_create_ibss, invalid cap:%x\n", caps);
+ return;
+ }
+}
+
+void start_clnt_join(struct adapter *padapter)
+{
+ unsigned short caps;
+ u8 val8;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+ int beacon_timeout;
+
+ pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig;
+ pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork);
+
+ /* update wireless mode */
+ update_wireless_mode(padapter);
+
+ /* udpate capability */
+ caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork);
+ update_capinfo(padapter, caps);
+ if (caps&cap_ESS) {
+ Set_MSR(padapter, WIFI_FW_STATION_STATE);
+
+ val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf;
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+ /* switch channel */
+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+ /* here wait for receiving the beacon to start auth */
+ /* and enable a timer */
+ beacon_timeout = decide_wait_for_beacon_timeout(pmlmeinfo->bcn_interval);
+ set_link_timer(pmlmeext, beacon_timeout);
+ _set_timer(&padapter->mlmepriv.assoc_timer,
+ (REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO*REASSOC_LIMIT) + beacon_timeout);
+
+ pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE;
+ } else if (caps&cap_IBSS) { /* adhoc client */
+ Set_MSR(padapter, WIFI_FW_ADHOC_STATE);
+
+ val8 = 0xcf;
+ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+ /* switch channel */
+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+ beacon_timing_control(padapter);
+
+ pmlmeinfo->state = WIFI_FW_ADHOC_STATE;
+
+ report_join_res(padapter, 1);
+ } else {
+ return;
+ }
+}
+
+void start_clnt_auth(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ _cancel_timer_ex(&pmlmeext->link_timer);
+
+ pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL);
+ pmlmeinfo->state |= WIFI_FW_AUTH_STATE;
+
+ pmlmeinfo->auth_seq = 1;
+ pmlmeinfo->reauth_count = 0;
+ pmlmeinfo->reassoc_count = 0;
+ pmlmeinfo->link_count = 0;
+ pmlmeext->retry = 0;
+
+
+ /* Because of AP's not receiving deauth before */
+ /* AP may: 1)not response auth or 2)deauth us after link is complete */
+ /* issue deauth before issuing auth to deal with the situation */
+ /* Commented by Albert 2012/07/21 */
+ /* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */
+ issue_deauth(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_DEAUTH_LEAVING);
+
+ DBG_88E_LEVEL(_drv_info_, "start auth\n");
+ issue_auth(padapter, NULL, 0);
+
+ set_link_timer(pmlmeext, REAUTH_TO);
+}
+
+
+void start_clnt_assoc(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ _cancel_timer_ex(&pmlmeext->link_timer);
+
+ pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE));
+ pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE);
+
+ issue_assocreq(padapter);
+
+ set_link_timer(pmlmeext, REASSOC_TO);
+}
+
+unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ /* check A3 */
+ if (!(_rtw_memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+ return _SUCCESS;
+
+ DBG_88E("%s\n", __func__);
+
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) {
+ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+ report_del_sta_event(padapter, MacAddr, reason);
+ } else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) {
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+ report_join_res(padapter, -2);
+ }
+ }
+ return _SUCCESS;
+}
+
+static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid)
+{
+ struct registry_priv *pregistrypriv;
+ struct mlme_ext_priv *pmlmeext;
+ struct rt_channel_info *chplan_new;
+ u8 channel;
+ u8 i;
+
+ pregistrypriv = &padapter->registrypriv;
+ pmlmeext = &padapter->mlmeextpriv;
+
+ /* Adjust channel plan by AP Country IE */
+ if (pregistrypriv->enable80211d &&
+ (!pmlmeext->update_channel_plan_by_ap_done)) {
+ u8 *ie, *p;
+ u32 len;
+ struct rt_channel_plan chplan_ap;
+ struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM];
+ u8 country[4];
+ u8 fcn; /* first channel number */
+ u8 noc; /* number of channel */
+ u8 j, k;
+
+ ie = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+ if (!ie)
+ return;
+ if (len < 6)
+ return;
+ ie += 2;
+ p = ie;
+ ie += len;
+
+ _rtw_memset(country, 0, 4);
+ memcpy(country, p, 3);
+ p += 3;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+ ("%s: 802.11d country =%s\n", __func__, country));
+
+ i = 0;
+ while ((ie - p) >= 3) {
+ fcn = *(p++);
+ noc = *(p++);
+ p++;
+
+ for (j = 0; j < noc; j++) {
+ if (fcn <= 14)
+ channel = fcn + j; /* 2.4 GHz */
+ else
+ channel = fcn + j*4; /* 5 GHz */
+
+ chplan_ap.Channel[i++] = channel;
+ }
+ }
+ chplan_ap.Len = i;
+
+ memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta));
+
+ _rtw_memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set));
+ chplan_new = pmlmeext->channel_set;
+
+ i = 0;
+ j = 0;
+ k = 0;
+ if (pregistrypriv->wireless_mode & WIRELESS_11G) {
+ do {
+ if ((i == MAX_CHANNEL_NUM) ||
+ (chplan_sta[i].ChannelNum == 0) ||
+ (chplan_sta[i].ChannelNum > 14))
+ break;
+
+ if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14))
+ break;
+
+ if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) {
+ chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+ chplan_new[k].ScanType = SCAN_ACTIVE;
+ i++;
+ j++;
+ k++;
+ } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) {
+ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+ chplan_new[k].ScanType = SCAN_PASSIVE;
+ i++;
+ k++;
+ } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) {
+ chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+ chplan_new[k].ScanType = SCAN_ACTIVE;
+ j++;
+ k++;
+ }
+ } while (1);
+
+ /* change AP not support channel to Passive scan */
+ while ((i < MAX_CHANNEL_NUM) &&
+ (chplan_sta[i].ChannelNum != 0) &&
+ (chplan_sta[i].ChannelNum <= 14)) {
+ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+ chplan_new[k].ScanType = SCAN_PASSIVE;
+ i++;
+ k++;
+ }
+
+ /* add channel AP supported */
+ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) {
+ chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+ chplan_new[k].ScanType = SCAN_ACTIVE;
+ j++;
+ k++;
+ }
+ } else {
+ /* keep original STA 2.4G channel plan */
+ while ((i < MAX_CHANNEL_NUM) &&
+ (chplan_sta[i].ChannelNum != 0) &&
+ (chplan_sta[i].ChannelNum <= 14)) {
+ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+ chplan_new[k].ScanType = chplan_sta[i].ScanType;
+ i++;
+ k++;
+ }
+
+ /* skip AP 2.4G channel plan */
+ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14))
+ j++;
+ }
+
+ /* keep original STA 5G channel plan */
+ while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) {
+ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+ chplan_new[k].ScanType = chplan_sta[i].ScanType;
+ i++;
+ k++;
+ }
+
+ pmlmeext->update_channel_plan_by_ap_done = 1;
+ }
+
+ /* If channel is used by AP, set channel scan type to active */
+ channel = bssid->Configuration.DSConfig;
+ chplan_new = pmlmeext->channel_set;
+ i = 0;
+ while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) {
+ if (chplan_new[i].ChannelNum == channel) {
+ if (chplan_new[i].ScanType == SCAN_PASSIVE) {
+ chplan_new[i].ScanType = SCAN_ACTIVE;
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+ ("%s: change channel %d scan type from passive to active\n",
+ __func__, channel));
+ }
+ break;
+ }
+ i++;
+ }
+}
+
+/****************************************************************************
+
+Following are the functions to report events
+
+*****************************************************************************/
+
+void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ struct cmd_obj *pcmd_obj;
+ u8 *pevtcmd;
+ u32 cmdsz;
+ struct survey_event *psurvey_evt;
+ struct C2HEvent_Header *pc2h_evt_hdr;
+ struct mlme_ext_priv *pmlmeext;
+ struct cmd_priv *pcmdpriv;
+ /* u8 *pframe = precv_frame->u.hdr.rx_data; */
+ /* uint len = precv_frame->u.hdr.len; */
+
+ if (!padapter)
+ return;
+
+ pmlmeext = &padapter->mlmeextpriv;
+ pcmdpriv = &padapter->cmdpriv;
+
+
+ pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd_obj == NULL)
+ return;
+
+ cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header));
+ pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+ if (pevtcmd == NULL) {
+ kfree(pcmd_obj);
+ return;
+ }
+
+ _rtw_init_listhead(&pcmd_obj->list);
+
+ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdsz = cmdsz;
+ pcmd_obj->parmbuf = pevtcmd;
+
+ pcmd_obj->rsp = NULL;
+ pcmd_obj->rspsz = 0;
+
+ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
+ pc2h_evt_hdr->len = sizeof(struct survey_event);
+ pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey);
+ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+ psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+
+ if (collect_bss_info(padapter, precv_frame, (struct wlan_bssid_ex *)&psurvey_evt->bss) == _FAIL) {
+ kfree(pcmd_obj);
+ kfree(pevtcmd);
+ return;
+ }
+
+ process_80211d(padapter, &psurvey_evt->bss);
+
+ rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+ pmlmeext->sitesurvey_res.bss_cnt++;
+
+ return;
+}
+
+void report_surveydone_event(struct adapter *padapter)
+{
+ struct cmd_obj *pcmd_obj;
+ u8 *pevtcmd;
+ u32 cmdsz;
+ struct surveydone_event *psurveydone_evt;
+ struct C2HEvent_Header *pc2h_evt_hdr;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd_obj == NULL)
+ return;
+
+ cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header));
+ pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+ if (pevtcmd == NULL) {
+ kfree(pcmd_obj);
+ return;
+ }
+
+ _rtw_init_listhead(&pcmd_obj->list);
+
+ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdsz = cmdsz;
+ pcmd_obj->parmbuf = pevtcmd;
+
+ pcmd_obj->rsp = NULL;
+ pcmd_obj->rspsz = 0;
+
+ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
+ pc2h_evt_hdr->len = sizeof(struct surveydone_event);
+ pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone);
+ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+ psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+ psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt;
+
+ DBG_88E("survey done event(%x)\n", psurveydone_evt->bss_cnt);
+
+ rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+ return;
+}
+
+void report_join_res(struct adapter *padapter, int res)
+{
+ struct cmd_obj *pcmd_obj;
+ u8 *pevtcmd;
+ u32 cmdsz;
+ struct joinbss_event *pjoinbss_evt;
+ struct C2HEvent_Header *pc2h_evt_hdr;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd_obj == NULL)
+ return;
+
+ cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header));
+ pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+ if (pevtcmd == NULL) {
+ kfree(pcmd_obj);
+ return;
+ }
+
+ _rtw_init_listhead(&pcmd_obj->list);
+
+ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdsz = cmdsz;
+ pcmd_obj->parmbuf = pevtcmd;
+
+ pcmd_obj->rsp = NULL;
+ pcmd_obj->rspsz = 0;
+
+ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
+ pc2h_evt_hdr->len = sizeof(struct joinbss_event);
+ pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss);
+ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+ pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+ memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex));
+ pjoinbss_evt->network.join_res = res;
+ pjoinbss_evt->network.aid = res;
+
+ DBG_88E("report_join_res(%d)\n", res);
+
+
+ rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network);
+
+
+ rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+ return;
+}
+
+void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason)
+{
+ struct cmd_obj *pcmd_obj;
+ u8 *pevtcmd;
+ u32 cmdsz;
+ struct sta_info *psta;
+ int mac_id;
+ struct stadel_event *pdel_sta_evt;
+ struct C2HEvent_Header *pc2h_evt_hdr;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd_obj == NULL)
+ return;
+
+ cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header));
+ pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+ if (pevtcmd == NULL) {
+ kfree(pcmd_obj);
+ return;
+ }
+
+ _rtw_init_listhead(&pcmd_obj->list);
+
+ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdsz = cmdsz;
+ pcmd_obj->parmbuf = pevtcmd;
+
+ pcmd_obj->rsp = NULL;
+ pcmd_obj->rspsz = 0;
+
+ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
+ pc2h_evt_hdr->len = sizeof(struct stadel_event);
+ pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA);
+ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+ pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+ memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN);
+ memcpy((unsigned char *)(pdel_sta_evt->rsvd), (unsigned char *)(&reason), 2);
+
+
+ psta = rtw_get_stainfo(&padapter->stapriv, MacAddr);
+ if (psta)
+ mac_id = (int)psta->mac_id;
+ else
+ mac_id = (-1);
+
+ pdel_sta_evt->mac_id = mac_id;
+
+ DBG_88E("report_del_sta_event: delete STA, mac_id =%d\n", mac_id);
+
+ rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+ return;
+}
+
+void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int cam_idx)
+{
+ struct cmd_obj *pcmd_obj;
+ u8 *pevtcmd;
+ u32 cmdsz;
+ struct stassoc_event *padd_sta_evt;
+ struct C2HEvent_Header *pc2h_evt_hdr;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd_obj == NULL)
+ return;
+
+ cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header));
+ pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+ if (pevtcmd == NULL) {
+ kfree(pcmd_obj);
+ return;
+ }
+
+ _rtw_init_listhead(&pcmd_obj->list);
+
+ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+ pcmd_obj->cmdsz = cmdsz;
+ pcmd_obj->parmbuf = pevtcmd;
+
+ pcmd_obj->rsp = NULL;
+ pcmd_obj->rspsz = 0;
+
+ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
+ pc2h_evt_hdr->len = sizeof(struct stassoc_event);
+ pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA);
+ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+ padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+ memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN);
+ padd_sta_evt->cam_id = cam_idx;
+
+ DBG_88E("report_add_sta_event: add STA\n");
+
+ rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+ return;
+}
+
+
+/****************************************************************************
+
+Following are the event callback functions
+
+*****************************************************************************/
+
+/* for sta/adhoc mode */
+void update_sta_info(struct adapter *padapter, struct sta_info *psta)
+{
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ /* ERP */
+ VCS_update(padapter, psta);
+
+ /* HT */
+ if (pmlmepriv->htpriv.ht_option) {
+ psta->htpriv.ht_option = true;
+
+ psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable;
+
+ if (support_short_GI(padapter, &(pmlmeinfo->HT_caps)))
+ psta->htpriv.sgi = true;
+
+ psta->qos_option = true;
+ } else {
+ psta->htpriv.ht_option = false;
+
+ psta->htpriv.ampdu_enable = false;
+
+ psta->htpriv.sgi = false;
+ psta->qos_option = false;
+ }
+ psta->htpriv.bwmode = pmlmeext->cur_bwmode;
+ psta->htpriv.ch_offset = pmlmeext->cur_ch_offset;
+
+ psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+ psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+
+ /* QoS */
+ if (pmlmepriv->qospriv.qos_option)
+ psta->qos_option = true;
+
+
+ psta->state = _FW_LINKED;
+}
+
+void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res)
+{
+ struct sta_info *psta, *psta_bmc;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ u8 join_type;
+ u16 media_status;
+
+ if (join_res < 0) {
+ join_type = 1;
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr);
+
+ /* restore to initial setting. */
+ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode);
+
+ goto exit_mlmeext_joinbss_event_callback;
+ }
+
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+ /* for bc/mc */
+ psta_bmc = rtw_get_bcmc_stainfo(padapter);
+ if (psta_bmc) {
+ pmlmeinfo->FW_sta_info[psta_bmc->mac_id].psta = psta_bmc;
+ update_bmc_sta_support_rate(padapter, psta_bmc->mac_id);
+ Update_RA_Entry(padapter, psta_bmc->mac_id);
+ }
+ }
+
+
+ /* turn on dynamic functions */
+ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true);
+
+ /* update IOT-releated issue */
+ update_IOT_info(padapter);
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates);
+
+ /* BCN interval */
+ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval));
+
+ /* udpate capability */
+ update_capinfo(padapter, pmlmeinfo->capability);
+
+ /* WMM, Update EDCA param */
+ WMMOnAssocRsp(padapter);
+
+ /* HT */
+ HTOnAssocRsp(padapter);
+
+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+ psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress);
+ if (psta) { /* only for infra. mode */
+ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta;
+
+ psta->wireless_mode = pmlmeext->cur_wireless_mode;
+
+ /* set per sta rate after updating HT cap. */
+ set_sta_rate(padapter, psta);
+ rtw_hal_set_hwreg(padapter, HW_VAR_TX_RPT_MAX_MACID, (u8 *)&psta->mac_id);
+ media_status = (psta->mac_id<<8)|1; /* MACID|OPMODE: 1 means connect */
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
+ }
+
+ join_type = 2;
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) {
+ /* correcting TSF */
+ correct_TSF(padapter, pmlmeext);
+ }
+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0);
+
+exit_mlmeext_joinbss_event_callback:
+
+ DBG_88E("=>%s\n", __func__);
+}
+
+void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *psta)
+{
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u8 join_type;
+
+ DBG_88E("%s\n", __func__);
+
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {/* adhoc master or sta_count>1 */
+ /* nothing to do */
+ } else { /* adhoc client */
+ /* correcting TSF */
+ correct_TSF(padapter, pmlmeext);
+
+ /* start beacon */
+ if (send_beacon(padapter) == _FAIL) {
+ pmlmeinfo->FW_sta_info[psta->mac_id].status = 0;
+ pmlmeinfo->state ^= WIFI_FW_ADHOC_STATE;
+ return;
+ }
+ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
+ }
+
+ join_type = 2;
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+ }
+
+ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta;
+
+ /* rate radaptive */
+ Update_RA_Entry(padapter, psta->mac_id);
+
+ /* update adhoc sta_info */
+ update_sta_info(padapter, psta);
+}
+
+void mlmeext_sta_del_event_callback(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if (is_client_associated_to_ap(padapter) || is_IBSS_empty(padapter)) {
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL);
+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr);
+
+ /* restore to initial setting. */
+ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode);
+
+ /* switch to the 20M Hz mode after disconnect */
+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+ /* SelectChannel(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); */
+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+
+ flush_all_cam_entry(padapter);
+
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+ /* set MSR to no link state -> infra. mode */
+ Set_MSR(padapter, _HW_STATE_STATION_);
+
+ _cancel_timer_ex(&pmlmeext->link_timer);
+ }
+}
+
+/****************************************************************************
+
+Following are the functions for the timer handlers
+
+*****************************************************************************/
+void _linked_rx_signal_strehgth_display(struct adapter *padapter);
+void _linked_rx_signal_strehgth_display(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u8 mac_id;
+ int UndecoratedSmoothedPWDB;
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+ mac_id = 0;
+ else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_)
+ mac_id = 2;
+
+ rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP, &mac_id);
+
+ rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB);
+ DBG_88E("UndecoratedSmoothedPWDB:%d\n", UndecoratedSmoothedPWDB);
+}
+
+static u8 chk_ap_is_alive(struct adapter *padapter, struct sta_info *psta)
+{
+ u8 ret = false;
+
+ if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) &&
+ sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) &&
+ sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta))
+ ret = false;
+ else
+ ret = true;
+
+ sta_update_last_rx_pkts(psta);
+
+ return ret;
+}
+
+void linked_status_chk(struct adapter *padapter)
+{
+ u32 i;
+ struct sta_info *psta;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ if (padapter->bRxRSSIDisplay)
+ _linked_rx_signal_strehgth_display(padapter);
+
+ rtw_hal_sreset_linked_status_check(padapter);
+
+ if (is_client_associated_to_ap(padapter)) {
+ /* linked infrastructure client mode */
+
+ int tx_chk = _SUCCESS, rx_chk = _SUCCESS;
+ int rx_chk_limit;
+
+ rx_chk_limit = 4;
+ psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress);
+ if (psta != NULL) {
+ bool is_p2p_enable = false;
+ #ifdef CONFIG_88EU_P2P
+ is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE);
+ #endif
+
+ if (!chk_ap_is_alive(padapter, psta))
+ rx_chk = _FAIL;
+
+ if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts)
+ tx_chk = _FAIL;
+
+ if (pmlmeext->active_keep_alive_check && (rx_chk == _FAIL || tx_chk == _FAIL)) {
+ u8 backup_oper_channel = 0;
+
+ /* switch to correct channel of current network before issue keep-alive frames */
+ if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) {
+ backup_oper_channel = rtw_get_oper_ch(padapter);
+ SelectChannel(padapter, pmlmeext->cur_channel);
+ }
+
+ if (rx_chk != _SUCCESS)
+ issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 3, 1);
+
+ if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) || rx_chk != _SUCCESS) {
+ tx_chk = issue_nulldata(padapter, psta->hwaddr, 0, 3, 1);
+ /* if tx acked and p2p disabled, set rx_chk _SUCCESS to reset retry count */
+ if (tx_chk == _SUCCESS && !is_p2p_enable)
+ rx_chk = _SUCCESS;
+ }
+
+ /* back to the original operation channel */
+ if (backup_oper_channel > 0)
+ SelectChannel(padapter, backup_oper_channel);
+ } else {
+ if (rx_chk != _SUCCESS) {
+ if (pmlmeext->retry == 0) {
+ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
+ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
+ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
+ }
+ }
+
+ if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) {
+ tx_chk = issue_nulldata(padapter, NULL, 0, 1, 0);
+ }
+ }
+
+ if (rx_chk == _FAIL) {
+ pmlmeext->retry++;
+ if (pmlmeext->retry > rx_chk_limit) {
+ DBG_88E_LEVEL(_drv_always_, FUNC_ADPT_FMT" disconnect or roaming\n",
+ FUNC_ADPT_ARG(padapter));
+ receive_disconnect(padapter, pmlmeinfo->network.MacAddress,
+ WLAN_REASON_EXPIRATION_CHK);
+ return;
+ }
+ } else {
+ pmlmeext->retry = 0;
+ }
+
+ if (tx_chk == _FAIL) {
+ pmlmeinfo->link_count &= 0xf;
+ } else {
+ pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts;
+ pmlmeinfo->link_count = 0;
+ }
+ } /* end of if ((psta = rtw_get_stainfo(pstapriv, passoc_res->network.MacAddress)) != NULL) */
+ } else if (is_client_associated_to_ibss(padapter)) {
+ /* linked IBSS mode */
+ /* for each assoc list entry to check the rx pkt counter */
+ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) {
+ if (pmlmeinfo->FW_sta_info[i].status == 1) {
+ psta = pmlmeinfo->FW_sta_info[i].psta;
+
+ if (NULL == psta)
+ continue;
+ if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta)) {
+ if (pmlmeinfo->FW_sta_info[i].retry < 3) {
+ pmlmeinfo->FW_sta_info[i].retry++;
+ } else {
+ pmlmeinfo->FW_sta_info[i].retry = 0;
+ pmlmeinfo->FW_sta_info[i].status = 0;
+ report_del_sta_event(padapter, psta->hwaddr
+ , 65535/* indicate disconnect caused by no rx */
+ );
+ }
+ } else {
+ pmlmeinfo->FW_sta_info[i].retry = 0;
+ pmlmeinfo->FW_sta_info[i].rx_pkt = (u32)sta_rx_pkts(psta);
+ }
+ }
+ }
+ }
+}
+
+void survey_timer_hdl(struct adapter *padapter)
+{
+ struct cmd_obj *ph2c;
+ struct sitesurvey_parm *psurveyPara;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif
+
+ /* issue rtw_sitesurvey_cmd */
+ if (pmlmeext->sitesurvey_res.state > SCAN_START) {
+ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS)
+ pmlmeext->sitesurvey_res.channel_idx++;
+
+ if (pmlmeext->scan_abort) {
+ #ifdef CONFIG_88EU_P2P
+ if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) {
+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX);
+ pmlmeext->sitesurvey_res.channel_idx = 3;
+ DBG_88E("%s idx:%d, cnt:%u\n", __func__
+ , pmlmeext->sitesurvey_res.channel_idx
+ , pwdinfo->find_phase_state_exchange_cnt
+ );
+ } else
+ #endif
+ {
+ pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num;
+ DBG_88E("%s idx:%d\n", __func__
+ , pmlmeext->sitesurvey_res.channel_idx
+ );
+ }
+
+ pmlmeext->scan_abort = false;/* reset */
+ }
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL)
+ goto exit_survey_timer_hdl;
+
+ psurveyPara = (struct sitesurvey_parm *)rtw_zmalloc(sizeof(struct sitesurvey_parm));
+ if (psurveyPara == NULL) {
+ kfree(ph2c);
+ goto exit_survey_timer_hdl;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+ rtw_enqueue_cmd(pcmdpriv, ph2c);
+ }
+
+
+exit_survey_timer_hdl:
+ return;
+}
+
+void link_timer_hdl(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
+ DBG_88E("link_timer_hdl:no beacon while connecting\n");
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+ report_join_res(padapter, -3);
+ } else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) {
+ /* re-auth timer */
+ if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) {
+ pmlmeinfo->state = 0;
+ report_join_res(padapter, -1);
+ return;
+ }
+
+ DBG_88E("link_timer_hdl: auth timeout and try again\n");
+ pmlmeinfo->auth_seq = 1;
+ issue_auth(padapter, NULL, 0);
+ set_link_timer(pmlmeext, REAUTH_TO);
+ } else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) {
+ /* re-assoc timer */
+ if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) {
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+ report_join_res(padapter, -2);
+ return;
+ }
+
+ DBG_88E("link_timer_hdl: assoc timeout and try again\n");
+ issue_assocreq(padapter);
+ set_link_timer(pmlmeext, REASSOC_TO);
+ }
+ return;
+}
+
+void addba_timer_hdl(struct sta_info *psta)
+{
+ struct ht_priv *phtpriv;
+
+ if (!psta)
+ return;
+
+ phtpriv = &psta->htpriv;
+
+ if ((phtpriv->ht_option) && (phtpriv->ampdu_enable)) {
+ if (phtpriv->candidate_tid_bitmap)
+ phtpriv->candidate_tid_bitmap = 0x0;
+ }
+}
+
+u8 NULL_hdl(struct adapter *padapter, u8 *pbuf)
+{
+ return H2C_SUCCESS;
+}
+
+u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf)
+{
+ u8 type;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf;
+
+ if (psetop->mode == Ndis802_11APMode) {
+ pmlmeinfo->state = WIFI_FW_AP_STATE;
+ type = _HW_STATE_AP_;
+ } else if (psetop->mode == Ndis802_11Infrastructure) {
+ pmlmeinfo->state &= ~(BIT(0)|BIT(1));/* clear state */
+ pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to STATION_STATE */
+ type = _HW_STATE_STATION_;
+ } else if (psetop->mode == Ndis802_11IBSS) {
+ type = _HW_STATE_ADHOC_;
+ } else {
+ type = _HW_STATE_NOLINK_;
+ }
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type));
+ /* Set_NETYPE0_MSR(padapter, type); */
+
+ return H2C_SUCCESS;
+}
+
+u8 createbss_hdl(struct adapter *padapter, u8 *pbuf)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+ struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf;
+ /* u32 initialgain; */
+
+
+ if (pparm->network.InfrastructureMode == Ndis802_11APMode) {
+#ifdef CONFIG_88EU_AP_MODE
+
+ if (pmlmeinfo->state == WIFI_FW_AP_STATE) {
+ /* todo: */
+ return H2C_SUCCESS;
+ }
+#endif
+ }
+
+ /* below is for ad-hoc master */
+ if (pparm->network.InfrastructureMode == Ndis802_11IBSS) {
+ rtw_joinbss_reset(padapter);
+
+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ pmlmeinfo->ERP_enable = 0;
+ pmlmeinfo->WMM_enable = 0;
+ pmlmeinfo->HT_enable = 0;
+ pmlmeinfo->HT_caps_enable = 0;
+ pmlmeinfo->HT_info_enable = 0;
+ pmlmeinfo->agg_enable_bitmap = 0;
+ pmlmeinfo->candidate_tid_bitmap = 0;
+
+ /* disable dynamic functions, such as high power, DIG */
+ Save_DM_Func_Flag(padapter);
+ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false);
+
+ /* config the initial gain under linking, need to write the BB registers */
+ /* initialgain = 0x1E; */
+ /* rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */
+
+ /* cancel link timer */
+ _cancel_timer_ex(&pmlmeext->link_timer);
+
+ /* clear CAM */
+ flush_all_cam_entry(padapter);
+
+ memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength));
+ pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength;
+
+ if (pnetwork->IELength > MAX_IE_SZ)/* Check pbuf->IELength */
+ return H2C_PARAMETERS_ERROR;
+
+ memcpy(pnetwork->IEs, ((struct wlan_bssid_ex *)pbuf)->IEs, pnetwork->IELength);
+
+ start_create_ibss(padapter);
+ }
+
+ return H2C_SUCCESS;
+}
+
+u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf)
+{
+ u8 join_type;
+ struct ndis_802_11_var_ie *pIE;
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+ struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf;
+ u32 i;
+
+ /* check already connecting to AP or not */
+ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {
+ if (pmlmeinfo->state & WIFI_FW_STATION_STATE)
+ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 5, 100);
+
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+ /* clear CAM */
+ flush_all_cam_entry(padapter);
+
+ _cancel_timer_ex(&pmlmeext->link_timer);
+
+ /* set MSR to nolink -> infra. mode */
+ Set_MSR(padapter, _HW_STATE_STATION_);
+
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL);
+ }
+
+ rtw_antenna_select_cmd(padapter, pparm->network.PhyInfo.Optimum_antenna, false);
+
+ rtw_joinbss_reset(padapter);
+
+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ pmlmeinfo->ERP_enable = 0;
+ pmlmeinfo->WMM_enable = 0;
+ pmlmeinfo->HT_enable = 0;
+ pmlmeinfo->HT_caps_enable = 0;
+ pmlmeinfo->HT_info_enable = 0;
+ pmlmeinfo->agg_enable_bitmap = 0;
+ pmlmeinfo->candidate_tid_bitmap = 0;
+ pmlmeinfo->bwmode_updated = false;
+
+ memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength));
+ pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength;
+
+ if (pnetwork->IELength > MAX_IE_SZ)/* Check pbuf->IELength */
+ return H2C_PARAMETERS_ERROR;
+
+ memcpy(pnetwork->IEs, ((struct wlan_bssid_ex *)pbuf)->IEs, pnetwork->IELength);
+
+ /* Check AP vendor to move rtw_joinbss_cmd() */
+
+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pnetwork->IELength;) {
+ pIE = (struct ndis_802_11_var_ie *)(pnetwork->IEs + i);
+
+ switch (pIE->ElementID) {
+ case _VENDOR_SPECIFIC_IE_:/* Get WMM IE. */
+ if (_rtw_memcmp(pIE->data, WMM_OUI, 4))
+ pmlmeinfo->WMM_enable = 1;
+ break;
+ case _HT_CAPABILITY_IE_: /* Get HT Cap IE. */
+ pmlmeinfo->HT_caps_enable = 1;
+ break;
+ case _HT_EXTRA_INFO_IE_: /* Get HT Info IE. */
+ pmlmeinfo->HT_info_enable = 1;
+
+ /* spec case only for cisco's ap because cisco's ap issue assoc rsp using mcs rate @40MHz or @20MHz */
+ {
+ struct HT_info_element *pht_info = (struct HT_info_element *)(pIE->data);
+
+ if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) {
+ /* switch to the 40M Hz mode according to the AP */
+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40;
+ switch (pht_info->infos[0] & 0x3) {
+ case 1:
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+ break;
+ case 3:
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+ break;
+ default:
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ }
+
+ DBG_88E("set ch/bw before connected\n");
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ i += (pIE->Length + 2);
+ }
+ /* disable dynamic functions, such as high power, DIG */
+
+ /* config the initial gain under linking, need to write the BB registers */
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress);
+ join_type = 0;
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+
+ /* cancel link timer */
+ _cancel_timer_ex(&pmlmeext->link_timer);
+
+ start_clnt_join(padapter);
+
+ return H2C_SUCCESS;
+}
+
+u8 disconnect_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ struct disconnect_parm *param = (struct disconnect_parm *)pbuf;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+ u8 val8;
+
+ if (is_client_associated_to_ap(padapter))
+ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms/100, 100);
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL);
+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr);
+
+ /* restore to initial setting. */
+ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode);
+
+ if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) {
+ /* Stop BCN */
+ val8 = 0;
+ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8));
+ }
+
+
+ /* set MSR to no link state -> infra. mode */
+ Set_MSR(padapter, _HW_STATE_STATION_);
+
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+ /* switch to the 20M Hz mode after disconnect */
+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+ flush_all_cam_entry(padapter);
+
+ _cancel_timer_ex(&pmlmeext->link_timer);
+
+ rtw_free_uc_swdec_pending_queue(padapter);
+
+ return H2C_SUCCESS;
+}
+
+static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_channel *out,
+ u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num)
+{
+ int i, j;
+ int set_idx;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ /* clear out first */
+ _rtw_memset(out, 0, sizeof(struct rtw_ieee80211_channel)*out_num);
+
+ /* acquire channels from in */
+ j = 0;
+ for (i = 0; i < in_num; i++) {
+ set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, in[i].hw_value);
+ if (in[i].hw_value && !(in[i].flags & RTW_IEEE80211_CHAN_DISABLED) &&
+ set_idx >= 0) {
+ memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel));
+
+ if (pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE)
+ out[j].flags &= RTW_IEEE80211_CHAN_PASSIVE_SCAN;
+
+ j++;
+ }
+ if (j >= out_num)
+ break;
+ }
+
+ /* if out is empty, use channel_set as default */
+ if (j == 0) {
+ for (i = 0; i < pmlmeext->max_chan_nums; i++) {
+ out[i].hw_value = pmlmeext->channel_set[i].ChannelNum;
+
+ if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE)
+ out[i].flags &= RTW_IEEE80211_CHAN_PASSIVE_SCAN;
+
+ j++;
+ }
+ }
+
+ return j;
+}
+
+u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf;
+ u8 bdelayscan = false;
+ u8 val8;
+ u32 initialgain;
+ u32 i;
+
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif
+
+ if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) {
+ /* for first time sitesurvey_cmd */
+ rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, NULL);
+
+ pmlmeext->sitesurvey_res.state = SCAN_START;
+ pmlmeext->sitesurvey_res.bss_cnt = 0;
+ pmlmeext->sitesurvey_res.channel_idx = 0;
+
+ for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
+ if (pparm->ssid[i].SsidLength) {
+ memcpy(pmlmeext->sitesurvey_res.ssid[i].Ssid, pparm->ssid[i].Ssid, IW_ESSID_MAX_SIZE);
+ pmlmeext->sitesurvey_res.ssid[i].SsidLength = pparm->ssid[i].SsidLength;
+ } else {
+ pmlmeext->sitesurvey_res.ssid[i].SsidLength = 0;
+ }
+ }
+
+ pmlmeext->sitesurvey_res.ch_num = rtw_scan_ch_decision(padapter
+ , pmlmeext->sitesurvey_res.ch, RTW_CHANNEL_SCAN_AMOUNT
+ , pparm->ch, pparm->ch_num
+ );
+
+ pmlmeext->sitesurvey_res.scan_mode = pparm->scan_mode;
+
+ /* issue null data if associating to the AP */
+ if (is_client_associated_to_ap(padapter)) {
+ pmlmeext->sitesurvey_res.state = SCAN_TXNULL;
+
+ issue_nulldata(padapter, NULL, 1, 3, 500);
+
+ bdelayscan = true;
+ }
+ if (bdelayscan) {
+ /* delay 50ms to protect nulldata(1). */
+ set_survey_timer(pmlmeext, 50);
+ return H2C_SUCCESS;
+ }
+ }
+
+ if ((pmlmeext->sitesurvey_res.state == SCAN_START) || (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) {
+ /* disable dynamic functions, such as high power, DIG */
+ Save_DM_Func_Flag(padapter);
+ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false);
+
+ /* config the initial gain under scaning, need to write the BB registers */
+#ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ initialgain = 0x1E;
+ else
+ initialgain = 0x28;
+#else /* CONFIG_88EU_P2P */
+ initialgain = 0x1E;
+#endif /* CONFIG_88EU_P2P */
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain));
+
+ /* set MSR to no link state */
+ Set_MSR(padapter, _HW_STATE_NOLINK_);
+
+ val8 = 1; /* under site survey */
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+
+ pmlmeext->sitesurvey_res.state = SCAN_PROCESS;
+ }
+
+ site_survey(padapter);
+
+ return H2C_SUCCESS;
+}
+
+u8 setauth_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ struct setauth_parm *pparm = (struct setauth_parm *)pbuf;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if (pparm->mode < 4)
+ pmlmeinfo->auth_algo = pparm->mode;
+ return H2C_SUCCESS;
+}
+
+u8 setkey_hdl(struct adapter *padapter, u8 *pbuf)
+{
+ unsigned short ctrl;
+ struct setkey_parm *pparm = (struct setkey_parm *)pbuf;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ /* main tx key for wep. */
+ if (pparm->set_tx)
+ pmlmeinfo->key_index = pparm->keyid;
+
+ /* write cam */
+ ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid;
+
+ DBG_88E_LEVEL(_drv_info_, "set group key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) "
+ "keyid:%d\n", pparm->algorithm, pparm->keyid);
+ write_cam(padapter, pparm->keyid, ctrl, null_sta, pparm->key);
+
+ return H2C_SUCCESS;
+}
+
+u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf)
+{
+ u16 ctrl = 0;
+ u8 cam_id;/* cam_entry */
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf;
+
+ /* cam_entry: */
+ /* 0~3 for default key */
+
+ /* for concurrent mode (ap+sta): */
+ /* default key is disable, using sw encrypt/decrypt */
+ /* cam_entry = 4 for sta mode (macid = 0) */
+ /* cam_entry(macid+3) = 5 ~ N for ap mode (aid = 1~N, macid = 2 ~N) */
+
+ /* for concurrent mode (sta+sta): */
+ /* default key is disable, using sw encrypt/decrypt */
+ /* cam_entry = 4 mapping to macid = 0 */
+ /* cam_entry = 5 mapping to macid = 2 */
+
+ cam_id = 4;
+
+ DBG_88E_LEVEL(_drv_info_, "set pairwise key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) camid:%d\n",
+ pparm->algorithm, cam_id);
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+ struct sta_info *psta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ if (pparm->algorithm == _NO_PRIVACY_) /* clear cam entry */ {
+ clear_cam_entry(padapter, pparm->id);
+ return H2C_SUCCESS_RSP;
+ }
+
+ psta = rtw_get_stainfo(pstapriv, pparm->addr);
+ if (psta) {
+ ctrl = (BIT(15) | ((pparm->algorithm) << 2));
+
+ DBG_88E("r871x_set_stakey_hdl(): enc_algorithm=%d\n", pparm->algorithm);
+
+ if ((psta->mac_id < 1) || (psta->mac_id > (NUM_STA-4))) {
+ DBG_88E("r871x_set_stakey_hdl():set_stakey failed, mac_id(aid)=%d\n", psta->mac_id);
+ return H2C_REJECTED;
+ }
+
+ cam_id = (psta->mac_id + 3);/* 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */
+
+ DBG_88E("Write CAM, mac_addr =%x:%x:%x:%x:%x:%x, cam_entry=%d\n", pparm->addr[0],
+ pparm->addr[1], pparm->addr[2], pparm->addr[3], pparm->addr[4],
+ pparm->addr[5], cam_id);
+
+ write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key);
+
+ return H2C_SUCCESS_RSP;
+ } else {
+ DBG_88E("r871x_set_stakey_hdl(): sta has been free\n");
+ return H2C_REJECTED;
+ }
+ }
+
+ /* below for sta mode */
+
+ if (pparm->algorithm == _NO_PRIVACY_) { /* clear cam entry */
+ clear_cam_entry(padapter, pparm->id);
+ return H2C_SUCCESS;
+ }
+ ctrl = BIT(15) | ((pparm->algorithm) << 2);
+ write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key);
+ pmlmeinfo->enc_algo = pparm->algorithm;
+ return H2C_SUCCESS;
+}
+
+u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, pparm->addr);
+
+ if (!psta)
+ return H2C_SUCCESS;
+
+ if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) ||
+ ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) {
+ issue_action_BA(padapter, pparm->addr, RTW_WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid);
+ _set_timer(&psta->addba_retry_timer, ADDBA_TO);
+ } else {
+ psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid);
+ }
+ return H2C_SUCCESS;
+}
+
+u8 set_tx_beacon_cmd(struct adapter *padapter)
+{
+ struct cmd_obj *ph2c;
+ struct Tx_Beacon_param *ptxBeacon_parm;
+ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u8 res = _SUCCESS;
+ int len_diff = 0;
+
+_func_enter_;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ ptxBeacon_parm = (struct Tx_Beacon_param *)rtw_zmalloc(sizeof(struct Tx_Beacon_param));
+ if (ptxBeacon_parm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ memcpy(&(ptxBeacon_parm->network), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex));
+
+ len_diff = update_hidden_ssid(ptxBeacon_parm->network.IEs+_BEACON_IE_OFFSET_,
+ ptxBeacon_parm->network.IELength-_BEACON_IE_OFFSET_,
+ pmlmeinfo->hidden_ssid_mode);
+ ptxBeacon_parm->network.IELength += len_diff;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ u8 evt_code;
+ u16 evt_sz;
+ uint *peventbuf;
+ void (*event_callback)(struct adapter *dev, u8 *pbuf);
+ struct evt_priv *pevt_priv = &(padapter->evtpriv);
+
+ peventbuf = (uint *)pbuf;
+ evt_sz = (u16)(*peventbuf&0xffff);
+ evt_code = (u8)((*peventbuf>>16)&0xff);
+
+ /* checking if event code is valid */
+ if (evt_code >= MAX_C2HEVT) {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent Code(%d) mismatch!\n", evt_code));
+ goto _abort_event_;
+ }
+
+ /* checking if event size match the event parm size */
+ if ((wlanevents[evt_code].parmsize != 0) &&
+ (wlanevents[evt_code].parmsize != evt_sz)) {
+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+ ("\nEvent(%d) Parm Size mismatch (%d vs %d)!\n",
+ evt_code, wlanevents[evt_code].parmsize, evt_sz));
+ goto _abort_event_;
+ }
+
+ ATOMIC_INC(&pevt_priv->event_seq);
+
+ peventbuf += 2;
+
+ if (peventbuf) {
+ event_callback = wlanevents[evt_code].event_callback;
+ event_callback(padapter, (u8 *)peventbuf);
+
+ pevt_priv->evt_done_cnt++;
+ }
+
+_abort_event_:
+ return H2C_SUCCESS;
+}
+
+u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ if (!pbuf)
+ return H2C_PARAMETERS_ERROR;
+
+ return H2C_SUCCESS;
+}
+
+u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ if (send_beacon(padapter) == _FAIL) {
+ DBG_88E("issue_beacon, fail!\n");
+ return H2C_PARAMETERS_ERROR;
+ }
+#ifdef CONFIG_88EU_AP_MODE
+ else { /* tx bc/mc frames after update TIM */
+ unsigned long irqL;
+ struct sta_info *psta_bmc;
+ struct list_head *xmitframe_plist, *xmitframe_phead;
+ struct xmit_frame *pxmitframe = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ /* for BC/MC Frames */
+ psta_bmc = rtw_get_bcmc_stainfo(padapter);
+ if (!psta_bmc)
+ return H2C_SUCCESS;
+
+ if ((pstapriv->tim_bitmap&BIT(0)) && (psta_bmc->sleepq_len > 0)) {
+ rtw_msleep_os(10);/* 10ms, ATIM(HIQ) Windows */
+ _enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL);
+
+ xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
+ xmitframe_plist = get_next(xmitframe_phead);
+
+ while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+ xmitframe_plist = get_next(xmitframe_plist);
+
+ rtw_list_delete(&pxmitframe->list);
+
+ psta_bmc->sleepq_len--;
+ if (psta_bmc->sleepq_len > 0)
+ pxmitframe->attrib.mdata = 1;
+ else
+ pxmitframe->attrib.mdata = 0;
+
+ pxmitframe->attrib.triggered = 1;
+
+ pxmitframe->attrib.qsel = 0x11;/* HIQ */
+
+ _exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL);
+ if (rtw_hal_xmit(padapter, pxmitframe))
+ rtw_os_xmit_complete(padapter, pxmitframe);
+ _enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL);
+ }
+ _exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL);
+ }
+ }
+#endif
+ return H2C_SUCCESS;
+}
+
+u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf)
+{
+ struct set_ch_parm *set_ch_parm;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ if (!pbuf)
+ return H2C_PARAMETERS_ERROR;
+
+ set_ch_parm = (struct set_ch_parm *)pbuf;
+
+ DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
+ FUNC_NDEV_ARG(padapter->pnetdev),
+ set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset);
+
+ pmlmeext->cur_channel = set_ch_parm->ch;
+ pmlmeext->cur_ch_offset = set_ch_parm->ch_offset;
+ pmlmeext->cur_bwmode = set_ch_parm->bw;
+
+ set_channel_bwmode(padapter, set_ch_parm->ch, set_ch_parm->ch_offset, set_ch_parm->bw);
+
+ return H2C_SUCCESS;
+}
+
+u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ struct SetChannelPlan_param *setChannelPlan_param;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ if (!pbuf)
+ return H2C_PARAMETERS_ERROR;
+
+ setChannelPlan_param = (struct SetChannelPlan_param *)pbuf;
+
+ pmlmeext->max_chan_nums = init_channel_set(padapter, setChannelPlan_param->channel_plan, pmlmeext->channel_set);
+ init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list);
+
+ return H2C_SUCCESS;
+}
+
+u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ if (!pbuf)
+ return H2C_PARAMETERS_ERROR;
+ return H2C_SUCCESS;
+}
+
+u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ return H2C_REJECTED;
+}
+
+/* TDLS_WRCR : write RCR DATA BIT */
+/* TDLS_SD_PTI : issue peer traffic indication */
+/* TDLS_CS_OFF : go back to the channel linked with AP, terminating channel switch procedure */
+/* TDLS_INIT_CH_SEN : init channel sensing, receive all data and mgnt frame */
+/* TDLS_DONE_CH_SEN: channel sensing and report candidate channel */
+/* TDLS_OFF_CH : first time set channel to off channel */
+/* TDLS_BASE_CH : go back tp the channel linked with AP when set base channel as target channel */
+/* TDLS_P_OFF_CH : periodically go to off channel */
+/* TDLS_P_BASE_CH : periodically go back to base channel */
+/* TDLS_RS_RCR : restore RCR */
+/* TDLS_CKALV_PH1 : check alive timer phase1 */
+/* TDLS_CKALV_PH2 : check alive timer phase2 */
+/* TDLS_FREE_STA : free tdls sta */
+u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ return H2C_REJECTED;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mp.c b/drivers/staging/rtl8188eu/core/rtw_mp.c
new file mode 100644
index 00000000000..c7ff2e4d1f2
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_mp.c
@@ -0,0 +1,997 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ *published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_MP_C_
+
+#include <drv_types.h>
+
+#include "odm_precomp.h"
+#include "rtl8188e_hal.h"
+
+u32 read_macreg(struct adapter *padapter, u32 addr, u32 sz)
+{
+ u32 val = 0;
+
+ switch (sz) {
+ case 1:
+ val = rtw_read8(padapter, addr);
+ break;
+ case 2:
+ val = rtw_read16(padapter, addr);
+ break;
+ case 4:
+ val = rtw_read32(padapter, addr);
+ break;
+ default:
+ val = 0xffffffff;
+ break;
+ }
+
+ return val;
+}
+
+void write_macreg(struct adapter *padapter, u32 addr, u32 val, u32 sz)
+{
+ switch (sz) {
+ case 1:
+ rtw_write8(padapter, addr, (u8)val);
+ break;
+ case 2:
+ rtw_write16(padapter, addr, (u16)val);
+ break;
+ case 4:
+ rtw_write32(padapter, addr, val);
+ break;
+ default:
+ break;
+ }
+}
+
+u32 read_bbreg(struct adapter *padapter, u32 addr, u32 bitmask)
+{
+ return rtw_hal_read_bbreg(padapter, addr, bitmask);
+}
+
+void write_bbreg(struct adapter *padapter, u32 addr, u32 bitmask, u32 val)
+{
+ rtw_hal_write_bbreg(padapter, addr, bitmask, val);
+}
+
+u32 _read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask)
+{
+ return rtw_hal_read_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bitmask);
+}
+
+void _write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val)
+{
+ rtw_hal_write_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bitmask, val);
+}
+
+u32 read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr)
+{
+ return _read_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bRFRegOffsetMask);
+}
+
+void write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 val)
+{
+ _write_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bRFRegOffsetMask, val);
+}
+
+static void _init_mp_priv_(struct mp_priv *pmp_priv)
+{
+ struct wlan_bssid_ex *pnetwork;
+
+ _rtw_memset(pmp_priv, 0, sizeof(struct mp_priv));
+
+ pmp_priv->mode = MP_OFF;
+
+ pmp_priv->channel = 1;
+ pmp_priv->bandwidth = HT_CHANNEL_WIDTH_20;
+ pmp_priv->prime_channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ pmp_priv->rateidx = MPT_RATE_1M;
+ pmp_priv->txpoweridx = 0x2A;
+
+ pmp_priv->antenna_tx = ANTENNA_A;
+ pmp_priv->antenna_rx = ANTENNA_AB;
+
+ pmp_priv->check_mp_pkt = 0;
+
+ pmp_priv->tx_pktcount = 0;
+
+ pmp_priv->rx_pktcount = 0;
+ pmp_priv->rx_crcerrpktcount = 0;
+
+ pmp_priv->network_macaddr[0] = 0x00;
+ pmp_priv->network_macaddr[1] = 0xE0;
+ pmp_priv->network_macaddr[2] = 0x4C;
+ pmp_priv->network_macaddr[3] = 0x87;
+ pmp_priv->network_macaddr[4] = 0x66;
+ pmp_priv->network_macaddr[5] = 0x55;
+
+ pnetwork = &pmp_priv->mp_network.network;
+ memcpy(pnetwork->MacAddress, pmp_priv->network_macaddr, ETH_ALEN);
+
+ pnetwork->Ssid.SsidLength = 8;
+ memcpy(pnetwork->Ssid.Ssid, "mp_871x", pnetwork->Ssid.SsidLength);
+}
+
+static void mp_init_xmit_attrib(struct mp_tx *pmptx, struct adapter *padapter)
+{
+ struct pkt_attrib *pattrib;
+ struct tx_desc *desc;
+
+ /* init xmitframe attribute */
+ pattrib = &pmptx->attrib;
+ _rtw_memset(pattrib, 0, sizeof(struct pkt_attrib));
+ desc = &pmptx->desc;
+ _rtw_memset(desc, 0, TXDESC_SIZE);
+
+ pattrib->ether_type = 0x8712;
+ _rtw_memset(pattrib->dst, 0xFF, ETH_ALEN);
+ pattrib->ack_policy = 0;
+ pattrib->hdrlen = WLAN_HDR_A3_LEN;
+ pattrib->subtype = WIFI_DATA;
+ pattrib->priority = 0;
+ pattrib->qsel = pattrib->priority;
+ pattrib->nr_frags = 1;
+ pattrib->encrypt = 0;
+ pattrib->bswenc = false;
+ pattrib->qos_en = false;
+}
+
+s32 init_mp_priv(struct adapter *padapter)
+{
+ struct mp_priv *pmppriv = &padapter->mppriv;
+
+ _init_mp_priv_(pmppriv);
+ pmppriv->papdater = padapter;
+
+ pmppriv->tx.stop = 1;
+ mp_init_xmit_attrib(&pmppriv->tx, padapter);
+
+ switch (padapter->registrypriv.rf_config) {
+ case RF_1T1R:
+ pmppriv->antenna_tx = ANTENNA_A;
+ pmppriv->antenna_rx = ANTENNA_A;
+ break;
+ case RF_1T2R:
+ default:
+ pmppriv->antenna_tx = ANTENNA_A;
+ pmppriv->antenna_rx = ANTENNA_AB;
+ break;
+ case RF_2T2R:
+ case RF_2T2R_GREEN:
+ pmppriv->antenna_tx = ANTENNA_AB;
+ pmppriv->antenna_rx = ANTENNA_AB;
+ break;
+ case RF_2T4R:
+ pmppriv->antenna_tx = ANTENNA_AB;
+ pmppriv->antenna_rx = ANTENNA_ABCD;
+ break;
+ }
+
+ return _SUCCESS;
+}
+
+void free_mp_priv(struct mp_priv *pmp_priv)
+{
+ kfree(pmp_priv->pallocated_mp_xmitframe_buf);
+ pmp_priv->pallocated_mp_xmitframe_buf = NULL;
+ pmp_priv->pmp_xmtframe_buf = NULL;
+}
+
+#define PHY_IQCalibrate(a, b) PHY_IQCalibrate_8188E(a, b)
+#define PHY_LCCalibrate(a) PHY_LCCalibrate_8188E(a)
+#define PHY_SetRFPathSwitch(a, b) PHY_SetRFPathSwitch_8188E(a, b)
+
+s32 MPT_InitializeAdapter(struct adapter *pAdapter, u8 Channel)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+ s32 rtStatus = _SUCCESS;
+ struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx;
+ struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv;
+
+ /* HW Initialization for 8190 MPT. */
+ /* SW Initialization for 8190 MP. */
+ pMptCtx->bMptDrvUnload = false;
+ pMptCtx->bMassProdTest = false;
+ pMptCtx->bMptIndexEven = true; /* default gain index is -6.0db */
+ pMptCtx->h2cReqNum = 0x0;
+ /* Init mpt event. */
+ /* init for BT MP */
+
+ pMptCtx->bMptWorkItemInProgress = false;
+ pMptCtx->CurrMptAct = NULL;
+ /* */
+
+ /* Don't accept any packets */
+ rtw_write32(pAdapter, REG_RCR, 0);
+
+ PHY_IQCalibrate(pAdapter, false);
+ dm_CheckTXPowerTracking(&pHalData->odmpriv); /* trigger thermal meter */
+ PHY_LCCalibrate(pAdapter);
+
+ pMptCtx->backup0xc50 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_XAAGCCore1, bMaskByte0);
+ pMptCtx->backup0xc58 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_XBAGCCore1, bMaskByte0);
+ pMptCtx->backup0xc30 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_RxDetector1, bMaskByte0);
+ pMptCtx->backup0x52_RF_A = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0);
+ pMptCtx->backup0x52_RF_B = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0);
+
+ /* set ant to wifi side in mp mode */
+ rtw_write16(pAdapter, 0x870, 0x300);
+ rtw_write16(pAdapter, 0x860, 0x110);
+
+ if (pAdapter->registrypriv.mp_mode == 1)
+ pmlmepriv->fw_state = WIFI_MP_STATE;
+
+ return rtStatus;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: MPT_DeInitAdapter()
+ *
+ * Overview: Extra DeInitialization for Mass Production Test.
+ *
+ * Input: struct adapter * pAdapter
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 05/08/2007 MHC Create Version 0.
+ * 05/18/2007 MHC Add normal driver MPHalt code.
+ *
+ *---------------------------------------------------------------------------*/
+void MPT_DeInitAdapter(struct adapter *pAdapter)
+{
+ struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx;
+
+ pMptCtx->bMptDrvUnload = true;
+}
+
+static u8 mpt_ProStartTest(struct adapter *padapter)
+{
+ struct mpt_context *pMptCtx = &padapter->mppriv.MptCtx;
+
+ pMptCtx->bMassProdTest = true;
+ pMptCtx->bStartContTx = false;
+ pMptCtx->bCckContTx = false;
+ pMptCtx->bOfdmContTx = false;
+ pMptCtx->bSingleCarrier = false;
+ pMptCtx->bCarrierSuppression = false;
+ pMptCtx->bSingleTone = false;
+
+ return _SUCCESS;
+}
+
+/*
+ * General use
+ */
+s32 SetPowerTracking(struct adapter *padapter, u8 enable)
+{
+ Hal_SetPowerTracking(padapter, enable);
+ return 0;
+}
+
+void GetPowerTracking(struct adapter *padapter, u8 *enable)
+{
+ Hal_GetPowerTracking(padapter, enable);
+}
+
+static void disable_dm(struct adapter *padapter)
+{
+ u8 v8;
+
+ /* 3 1. disable firmware dynamic mechanism */
+ /* disable Power Training, Rate Adaptive */
+ v8 = rtw_read8(padapter, REG_BCN_CTRL);
+ v8 &= ~EN_BCN_FUNCTION;
+ rtw_write8(padapter, REG_BCN_CTRL, v8);
+
+ /* 3 2. disable driver dynamic mechanism */
+ /* disable Dynamic Initial Gain */
+ /* disable High Power */
+ /* disable Power Tracking */
+ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false);
+
+ /* enable APK, LCK and IQK but disable power tracking */
+ Switch_DM_Func(padapter, DYNAMIC_RF_CALIBRATION, true);
+}
+
+/* This function initializes the DUT to the MP test mode */
+s32 mp_start_test(struct adapter *padapter)
+{
+ struct wlan_bssid_ex bssid;
+ struct sta_info *psta;
+ u32 length;
+ u8 val8;
+
+ unsigned long irqL;
+ s32 res = _SUCCESS;
+
+ struct mp_priv *pmppriv = &padapter->mppriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+
+ padapter->registrypriv.mp_mode = 1;
+ pmppriv->bSetTxPower = 0; /* for manually set tx power */
+
+ /* 3 disable dynamic mechanism */
+ disable_dm(padapter);
+
+ /* 3 0. update mp_priv */
+
+ if (padapter->registrypriv.rf_config == RF_819X_MAX_TYPE) {
+ switch (GET_RF_TYPE(padapter)) {
+ case RF_1T1R:
+ pmppriv->antenna_tx = ANTENNA_A;
+ pmppriv->antenna_rx = ANTENNA_A;
+ break;
+ case RF_1T2R:
+ default:
+ pmppriv->antenna_tx = ANTENNA_A;
+ pmppriv->antenna_rx = ANTENNA_AB;
+ break;
+ case RF_2T2R:
+ case RF_2T2R_GREEN:
+ pmppriv->antenna_tx = ANTENNA_AB;
+ pmppriv->antenna_rx = ANTENNA_AB;
+ break;
+ case RF_2T4R:
+ pmppriv->antenna_tx = ANTENNA_AB;
+ pmppriv->antenna_rx = ANTENNA_ABCD;
+ break;
+ }
+ }
+
+ mpt_ProStartTest(padapter);
+
+ /* 3 1. initialize a new struct wlan_bssid_ex */
+/* _rtw_memset(&bssid, 0, sizeof(struct wlan_bssid_ex)); */
+ memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN);
+ bssid.Ssid.SsidLength = strlen("mp_pseudo_adhoc");
+ memcpy(bssid.Ssid.Ssid, (u8 *)"mp_pseudo_adhoc", bssid.Ssid.SsidLength);
+ bssid.InfrastructureMode = Ndis802_11IBSS;
+ bssid.NetworkTypeInUse = Ndis802_11DS;
+ bssid.IELength = 0;
+
+ length = get_wlan_bssid_ex_sz(&bssid);
+ if (length % 4)
+ bssid.Length = ((length >> 2) + 1) << 2; /* round up to multiple of 4 bytes. */
+ else
+ bssid.Length = length;
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)
+ goto end_of_mp_start_test;
+
+ /* init mp_start_test status */
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+ rtw_disassoc_cmd(padapter, 500, true);
+ rtw_indicate_disconnect(padapter);
+ rtw_free_assoc_resources(padapter, 1);
+ }
+ pmppriv->prev_fw_state = get_fwstate(pmlmepriv);
+ if (padapter->registrypriv.mp_mode == 1)
+ pmlmepriv->fw_state = WIFI_MP_STATE;
+ set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+
+ /* 3 2. create a new psta for mp driver */
+ /* clear psta in the cur_network, if any */
+ psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress);
+ if (psta)
+ rtw_free_stainfo(padapter, psta);
+
+ psta = rtw_alloc_stainfo(&padapter->stapriv, bssid.MacAddress);
+ if (psta == NULL) {
+ RT_TRACE(_module_mp_, _drv_err_, ("mp_start_test: Can't alloc sta_info!\n"));
+ pmlmepriv->fw_state = pmppriv->prev_fw_state;
+ res = _FAIL;
+ goto end_of_mp_start_test;
+ }
+
+ /* 3 3. join psudo AdHoc */
+ tgt_network->join_res = 1;
+ tgt_network->aid = 1;
+ psta->aid = 1;
+ memcpy(&tgt_network->network, &bssid, length);
+
+ rtw_indicate_connect(padapter);
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+end_of_mp_start_test:
+
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+ if (res == _SUCCESS) {
+ /* set MSR to WIFI_FW_ADHOC_STATE */
+ val8 = rtw_read8(padapter, MSR) & 0xFC; /* 0x0102 */
+ val8 |= WIFI_FW_ADHOC_STATE;
+ rtw_write8(padapter, MSR, val8); /* Link in ad hoc network */
+ }
+ return res;
+}
+/* */
+/* This function change the DUT from the MP test mode into normal mode */
+void mp_stop_test(struct adapter *padapter)
+{
+ struct mp_priv *pmppriv = &padapter->mppriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+ struct sta_info *psta;
+
+ unsigned long irqL;
+
+ if (pmppriv->mode == MP_ON) {
+ pmppriv->bSetTxPower = 0;
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)
+ goto end_of_mp_stop_test;
+
+ /* 3 1. disconnect psudo AdHoc */
+ rtw_indicate_disconnect(padapter);
+
+ /* 3 2. clear psta used in mp test mode. */
+ psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress);
+ if (psta)
+ rtw_free_stainfo(padapter, psta);
+
+ /* 3 3. return to normal state (default:station mode) */
+ pmlmepriv->fw_state = pmppriv->prev_fw_state; /* WIFI_STATION_STATE; */
+
+ /* flush the cur_network */
+ _rtw_memset(tgt_network, 0, sizeof(struct wlan_network));
+
+ _clr_fwstate_(pmlmepriv, WIFI_MP_STATE);
+
+end_of_mp_stop_test:
+
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+ }
+}
+
+/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/
+/*
+ * SetChannel
+ * Description
+ * Use H2C command to change channel,
+ * not only modify rf register, but also other setting need to be done.
+ */
+void SetChannel(struct adapter *pAdapter)
+{
+ Hal_SetChannel(pAdapter);
+}
+
+/*
+ * Notice
+ * Switch bandwitdth may change center frequency(channel)
+ */
+void SetBandwidth(struct adapter *pAdapter)
+{
+ Hal_SetBandwidth(pAdapter);
+}
+
+void SetAntenna(struct adapter *pAdapter)
+{
+ Hal_SetAntenna(pAdapter);
+}
+
+void SetAntennaPathPower(struct adapter *pAdapter)
+{
+ Hal_SetAntennaPathPower(pAdapter);
+}
+
+void SetTxPower(struct adapter *pAdapter)
+{
+ Hal_SetTxPower(pAdapter);
+ }
+
+void SetDataRate(struct adapter *pAdapter)
+{
+ Hal_SetDataRate(pAdapter);
+}
+
+void MP_PHY_SetRFPathSwitch(struct adapter *pAdapter , bool bMain)
+{
+ PHY_SetRFPathSwitch(pAdapter, bMain);
+}
+
+s32 SetThermalMeter(struct adapter *pAdapter, u8 target_ther)
+{
+ return Hal_SetThermalMeter(pAdapter, target_ther);
+}
+
+void GetThermalMeter(struct adapter *pAdapter, u8 *value)
+{
+ Hal_GetThermalMeter(pAdapter, value);
+}
+
+void SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart)
+{
+ PhySetTxPowerLevel(pAdapter);
+ Hal_SetSingleCarrierTx(pAdapter, bStart);
+}
+
+void SetSingleToneTx(struct adapter *pAdapter, u8 bStart)
+{
+ PhySetTxPowerLevel(pAdapter);
+ Hal_SetSingleToneTx(pAdapter, bStart);
+}
+
+void SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart)
+{
+ PhySetTxPowerLevel(pAdapter);
+ Hal_SetCarrierSuppressionTx(pAdapter, bStart);
+}
+
+void SetContinuousTx(struct adapter *pAdapter, u8 bStart)
+{
+ PhySetTxPowerLevel(pAdapter);
+ Hal_SetContinuousTx(pAdapter, bStart);
+}
+
+
+void PhySetTxPowerLevel(struct adapter *pAdapter)
+{
+ struct mp_priv *pmp_priv = &pAdapter->mppriv;
+
+ if (pmp_priv->bSetTxPower == 0) /* for NO manually set power index */
+ PHY_SetTxPowerLevel8188E(pAdapter, pmp_priv->channel);
+}
+
+/* */
+static void dump_mpframe(struct adapter *padapter, struct xmit_frame *pmpframe)
+{
+ rtw_hal_mgnt_xmit(padapter, pmpframe);
+}
+
+static struct xmit_frame *alloc_mp_xmitframe(struct xmit_priv *pxmitpriv)
+{
+ struct xmit_frame *pmpframe;
+ struct xmit_buf *pxmitbuf;
+
+ pmpframe = rtw_alloc_xmitframe(pxmitpriv);
+ if (pmpframe == NULL)
+ return NULL;
+
+ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+ if (pxmitbuf == NULL) {
+ rtw_free_xmitframe(pxmitpriv, pmpframe);
+ return NULL;
+ }
+
+ pmpframe->frame_tag = MP_FRAMETAG;
+
+ pmpframe->pxmitbuf = pxmitbuf;
+
+ pmpframe->buf_addr = pxmitbuf->pbuf;
+
+ pxmitbuf->priv_data = pmpframe;
+
+ return pmpframe;
+}
+
+static int mp_xmit_packet_thread(void *context)
+{
+ struct xmit_frame *pxmitframe;
+ struct mp_tx *pmptx;
+ struct mp_priv *pmp_priv;
+ struct xmit_priv *pxmitpriv;
+ struct adapter *padapter;
+
+ pmp_priv = (struct mp_priv *)context;
+ pmptx = &pmp_priv->tx;
+ padapter = pmp_priv->papdater;
+ pxmitpriv = &(padapter->xmitpriv);
+
+ thread_enter("RTW_MP_THREAD");
+
+ /* DBG_88E("%s:pkTx Start\n", __func__); */
+ while (1) {
+ pxmitframe = alloc_mp_xmitframe(pxmitpriv);
+ if (pxmitframe == NULL) {
+ if (pmptx->stop ||
+ padapter->bSurpriseRemoved ||
+ padapter->bDriverStopped) {
+ goto exit;
+ } else {
+ rtw_msleep_os(1);
+ continue;
+ }
+ }
+
+ memcpy((u8 *)(pxmitframe->buf_addr+TXDESC_OFFSET), pmptx->buf, pmptx->write_size);
+ memcpy(&(pxmitframe->attrib), &(pmptx->attrib), sizeof(struct pkt_attrib));
+
+ dump_mpframe(padapter, pxmitframe);
+
+ pmptx->sended++;
+ pmp_priv->tx_pktcount++;
+
+ if (pmptx->stop ||
+ padapter->bSurpriseRemoved ||
+ padapter->bDriverStopped)
+ goto exit;
+ if ((pmptx->count != 0) &&
+ (pmptx->count == pmptx->sended))
+ goto exit;
+
+ flush_signals_thread();
+ }
+
+exit:
+ kfree(pmptx->pallocated_buf);
+ pmptx->pallocated_buf = NULL;
+ pmptx->stop = 1;
+
+ thread_exit();
+}
+
+void fill_txdesc_for_mp(struct adapter *padapter, struct tx_desc *ptxdesc)
+{
+ struct mp_priv *pmp_priv = &padapter->mppriv;
+ memcpy(ptxdesc, &(pmp_priv->tx.desc), TXDESC_SIZE);
+}
+
+void SetPacketTx(struct adapter *padapter)
+{
+ u8 *ptr, *pkt_start, *pkt_end;
+ u32 pkt_size;
+ struct tx_desc *desc;
+ struct rtw_ieee80211_hdr *hdr;
+ u8 payload;
+ s32 bmcast;
+ struct pkt_attrib *pattrib;
+ struct mp_priv *pmp_priv;
+
+
+ pmp_priv = &padapter->mppriv;
+ if (pmp_priv->tx.stop)
+ return;
+ pmp_priv->tx.sended = 0;
+ pmp_priv->tx.stop = 0;
+ pmp_priv->tx_pktcount = 0;
+
+ /* 3 1. update_attrib() */
+ pattrib = &pmp_priv->tx.attrib;
+ memcpy(pattrib->src, padapter->eeprompriv.mac_addr, ETH_ALEN);
+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+ bmcast = IS_MCAST(pattrib->ra);
+ if (bmcast) {
+ pattrib->mac_id = 1;
+ pattrib->psta = rtw_get_bcmc_stainfo(padapter);
+ } else {
+ pattrib->mac_id = 0;
+ pattrib->psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv));
+ }
+
+ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->pktlen;
+
+ /* 3 2. allocate xmit buffer */
+ pkt_size = pattrib->last_txcmdsz;
+
+ kfree(pmp_priv->tx.pallocated_buf);
+ pmp_priv->tx.write_size = pkt_size;
+ pmp_priv->tx.buf_size = pkt_size + XMITBUF_ALIGN_SZ;
+ pmp_priv->tx.pallocated_buf = rtw_zmalloc(pmp_priv->tx.buf_size);
+ if (pmp_priv->tx.pallocated_buf == NULL) {
+ DBG_88E("%s: malloc(%d) fail!!\n", __func__, pmp_priv->tx.buf_size);
+ return;
+ }
+ pmp_priv->tx.buf = (u8 *)N_BYTE_ALIGMENT((size_t)(pmp_priv->tx.pallocated_buf), XMITBUF_ALIGN_SZ);
+ ptr = pmp_priv->tx.buf;
+
+ desc = &(pmp_priv->tx.desc);
+ _rtw_memset(desc, 0, TXDESC_SIZE);
+ pkt_start = ptr;
+ pkt_end = pkt_start + pkt_size;
+
+ /* 3 3. init TX descriptor */
+ /* offset 0 */
+ desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
+ desc->txdw0 |= cpu_to_le32(pkt_size & 0x0000FFFF); /* packet size */
+ desc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00FF0000); /* 32 bytes for TX Desc */
+ if (bmcast)
+ desc->txdw0 |= cpu_to_le32(BMC); /* broadcast packet */
+
+ desc->txdw1 |= cpu_to_le32((0x01 << 26) & 0xff000000);
+ /* offset 4 */
+ desc->txdw1 |= cpu_to_le32((pattrib->mac_id) & 0x3F); /* CAM_ID(MAC_ID) */
+ desc->txdw1 |= cpu_to_le32((pattrib->qsel << QSEL_SHT) & 0x00001F00); /* Queue Select, TID */
+
+ desc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000F0000); /* Rate Adaptive ID */
+ /* offset 8 */
+ /* offset 12 */
+
+ desc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0x0fff0000);
+
+ /* offset 16 */
+ desc->txdw4 |= cpu_to_le32(HW_SSN);
+ desc->txdw4 |= cpu_to_le32(USERATE);
+ desc->txdw4 |= cpu_to_le32(DISDATAFB);
+
+ if (pmp_priv->preamble) {
+ if (pmp_priv->rateidx <= MPT_RATE_54M)
+ desc->txdw4 |= cpu_to_le32(DATA_SHORT); /* CCK Short Preamble */
+ }
+ if (pmp_priv->bandwidth == HT_CHANNEL_WIDTH_40)
+ desc->txdw4 |= cpu_to_le32(DATA_BW);
+
+ /* offset 20 */
+ desc->txdw5 |= cpu_to_le32(pmp_priv->rateidx & 0x0000001F);
+
+ if (pmp_priv->preamble) {
+ if (pmp_priv->rateidx > MPT_RATE_54M)
+ desc->txdw5 |= cpu_to_le32(SGI); /* MCS Short Guard Interval */
+ }
+ desc->txdw5 |= cpu_to_le32(RTY_LMT_EN); /* retry limit enable */
+ desc->txdw5 |= cpu_to_le32(0x00180000); /* DATA/RTS Rate Fallback Limit */
+
+ /* 3 4. make wlan header, make_wlanhdr() */
+ hdr = (struct rtw_ieee80211_hdr *)pkt_start;
+ SetFrameSubType(&hdr->frame_ctl, pattrib->subtype);
+ memcpy(hdr->addr1, pattrib->dst, ETH_ALEN); /* DA */
+ memcpy(hdr->addr2, pattrib->src, ETH_ALEN); /* SA */
+ memcpy(hdr->addr3, get_bssid(&padapter->mlmepriv), ETH_ALEN); /* RA, BSSID */
+
+ /* 3 5. make payload */
+ ptr = pkt_start + pattrib->hdrlen;
+
+ switch (pmp_priv->tx.payload) {
+ case 0:
+ payload = 0x00;
+ break;
+ case 1:
+ payload = 0x5a;
+ break;
+ case 2:
+ payload = 0xa5;
+ break;
+ case 3:
+ payload = 0xff;
+ break;
+ default:
+ payload = 0x00;
+ break;
+ }
+
+ _rtw_memset(ptr, payload, pkt_end - ptr);
+
+ /* 3 6. start thread */
+ pmp_priv->tx.PktTxThread = kthread_run(mp_xmit_packet_thread, pmp_priv, "RTW_MP_THREAD");
+ if (IS_ERR(pmp_priv->tx.PktTxThread))
+ DBG_88E("Create PktTx Thread Fail !!!!!\n");
+}
+
+void SetPacketRx(struct adapter *pAdapter, u8 bStartRx)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+
+ if (bStartRx) {
+ /* Accept CRC error and destination address */
+ pHalData->ReceiveConfig = AAP | APM | AM | AB | APP_ICV | ADF | AMF | HTC_LOC_CTRL | APP_MIC | APP_PHYSTS;
+
+ pHalData->ReceiveConfig |= ACRC32;
+
+ rtw_write32(pAdapter, REG_RCR, pHalData->ReceiveConfig);
+
+ /* Accept all data frames */
+ rtw_write16(pAdapter, REG_RXFLTMAP2, 0xFFFF);
+ } else {
+ rtw_write32(pAdapter, REG_RCR, 0);
+ }
+}
+
+void ResetPhyRxPktCount(struct adapter *pAdapter)
+{
+ u32 i, phyrx_set = 0;
+
+ for (i = 0; i <= 0xF; i++) {
+ phyrx_set = 0;
+ phyrx_set |= _RXERR_RPT_SEL(i); /* select */
+ phyrx_set |= RXERR_RPT_RST; /* set counter to zero */
+ rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set);
+ }
+}
+
+static u32 GetPhyRxPktCounts(struct adapter *pAdapter, u32 selbit)
+{
+ /* selection */
+ u32 phyrx_set = 0, count = 0;
+
+ phyrx_set = _RXERR_RPT_SEL(selbit & 0xF);
+ rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set);
+
+ /* Read packet count */
+ count = rtw_read32(pAdapter, REG_RXERR_RPT) & RXERR_COUNTER_MASK;
+
+ return count;
+}
+
+u32 GetPhyRxPktReceived(struct adapter *pAdapter)
+{
+ u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0;
+
+ OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_OK);
+ CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_OK);
+ HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_OK);
+
+ return OFDM_cnt + CCK_cnt + HT_cnt;
+}
+
+u32 GetPhyRxPktCRC32Error(struct adapter *pAdapter)
+{
+ u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0;
+
+ OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_FAIL);
+ CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_FAIL);
+ HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_FAIL);
+
+ return OFDM_cnt + CCK_cnt + HT_cnt;
+}
+
+/* reg 0x808[9:0]: FFT data x */
+/* reg 0x808[22]: 0 --> 1 to get 1 FFT data y */
+/* reg 0x8B4[15:0]: FFT data y report */
+static u32 rtw_GetPSDData(struct adapter *pAdapter, u32 point)
+{
+ int psd_val;
+
+
+ psd_val = rtw_read32(pAdapter, 0x808);
+ psd_val &= 0xFFBFFC00;
+ psd_val |= point;
+
+ rtw_write32(pAdapter, 0x808, psd_val);
+ rtw_mdelay_os(1);
+ psd_val |= 0x00400000;
+
+ rtw_write32(pAdapter, 0x808, psd_val);
+ rtw_mdelay_os(1);
+ psd_val = rtw_read32(pAdapter, 0x8B4);
+
+ psd_val &= 0x0000FFFF;
+
+ return psd_val;
+}
+
+/*
+ *pts start_point_min stop_point_max
+ * 128 64 64 + 128 = 192
+ * 256 128 128 + 256 = 384
+ * 512 256 256 + 512 = 768
+ * 1024 512 512 + 1024 = 1536
+ *
+ */
+u32 mp_query_psd(struct adapter *pAdapter, u8 *data)
+{
+ u32 i, psd_pts = 0, psd_start = 0, psd_stop = 0;
+ u32 psd_data = 0;
+
+
+ if (!netif_running(pAdapter->pnetdev)) {
+ RT_TRACE(_module_mp_, _drv_warning_, ("mp_query_psd: Fail! interface not opened!\n"));
+ return 0;
+ }
+
+ if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == false) {
+ RT_TRACE(_module_mp_, _drv_warning_, ("mp_query_psd: Fail! not in MP mode!\n"));
+ return 0;
+ }
+
+ if (strlen(data) == 0) { /* default value */
+ psd_pts = 128;
+ psd_start = 64;
+ psd_stop = 128;
+ } else {
+ sscanf(data, "pts =%d, start =%d, stop =%d", &psd_pts, &psd_start, &psd_stop);
+ }
+
+ _rtw_memset(data, '\0', sizeof(data));
+
+ i = psd_start;
+ while (i < psd_stop) {
+ if (i >= psd_pts) {
+ psd_data = rtw_GetPSDData(pAdapter, i-psd_pts);
+ } else {
+ psd_data = rtw_GetPSDData(pAdapter, i);
+ }
+ sprintf(data, "%s%x ", data, psd_data);
+ i++;
+ }
+
+ rtw_msleep_os(100);
+ return strlen(data)+1;
+}
+
+void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv)
+{
+ int i, res;
+ struct adapter *padapter = pxmitpriv->adapter;
+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
+
+ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
+ if (padapter->registrypriv.mp_mode == 0) {
+ max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+ num_xmit_extbuf = NR_XMIT_EXTBUFF;
+ } else {
+ max_xmit_extbuf_size = 20000;
+ num_xmit_extbuf = 1;
+ }
+
+ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
+ for (i = 0; i < num_xmit_extbuf; i++) {
+ rtw_os_xmit_resource_free(padapter, pxmitbuf, (max_xmit_extbuf_size + XMITBUF_ALIGN_SZ));
+
+ pxmitbuf++;
+ }
+
+ if (pxmitpriv->pallocated_xmit_extbuf)
+ rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+
+ if (padapter->registrypriv.mp_mode == 0) {
+ max_xmit_extbuf_size = 20000;
+ num_xmit_extbuf = 1;
+ } else {
+ max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+ num_xmit_extbuf = NR_XMIT_EXTBUFF;
+ }
+
+ /* Init xmit extension buff */
+ _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue);
+
+ pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+
+ if (pxmitpriv->pallocated_xmit_extbuf == NULL) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n"));
+ res = _FAIL;
+ goto exit;
+ }
+
+ pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmit_extbuf), 4);
+
+ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
+
+ for (i = 0; i < num_xmit_extbuf; i++) {
+ _rtw_init_listhead(&pxmitbuf->list);
+
+ pxmitbuf->priv_data = NULL;
+ pxmitbuf->padapter = padapter;
+ pxmitbuf->ext_tag = true;
+
+ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, max_xmit_extbuf_size + XMITBUF_ALIGN_SZ);
+ if (res == _FAIL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue));
+ pxmitbuf++;
+ }
+
+ pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf;
+
+exit:
+ ;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c b/drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c
new file mode 100644
index 00000000000..f06312c4158
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c
@@ -0,0 +1,1508 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_MP_IOCTL_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <mlme_osdep.h>
+
+/* include <rtw_mp.h> */
+#include <rtw_mp_ioctl.h>
+
+
+/* rtl8188eu_oid_rtl_seg_81_85 section start **************** */
+int rtl8188eu_oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ if (poid_par_priv->information_buf_len < sizeof(u8))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ if (poid_par_priv->type_of_oid == SET_OID) {
+ Adapter->registrypriv.wireless_mode = *(u8 *)poid_par_priv->information_buf;
+ } else if (poid_par_priv->type_of_oid == QUERY_OID) {
+ *(u8 *)poid_par_priv->information_buf = Adapter->registrypriv.wireless_mode;
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+ RT_TRACE(_module_mp_, _drv_info_, ("-query Wireless Mode=%d\n", Adapter->registrypriv.wireless_mode));
+ } else {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+_func_exit_;
+
+ return status;
+}
+/* rtl8188eu_oid_rtl_seg_81_87_80 section start **************** */
+int rtl8188eu_oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct bb_reg_param *pbbreg;
+ u16 offset;
+ u32 value;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_write_bb_reg_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf);
+
+ offset = (u16)(pbbreg->offset) & 0xFFF; /* 0ffset :0x800~0xfff */
+ if (offset < BB_REG_BASE_ADDR)
+ offset |= BB_REG_BASE_ADDR;
+
+ value = pbbreg->value;
+
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("rtl8188eu_oid_rt_pro_write_bb_reg_hdl: offset=0x%03X value=0x%08X\n",
+ offset, value));
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ write_bbreg(Adapter, offset, 0xFFFFFFFF, value);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct bb_reg_param *pbbreg;
+ u16 offset;
+ u32 value;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_read_bb_reg_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != QUERY_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf);
+
+ offset = (u16)(pbbreg->offset) & 0xFFF; /* 0ffset :0x800~0xfff */
+ if (offset < BB_REG_BASE_ADDR)
+ offset |= BB_REG_BASE_ADDR;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ value = read_bbreg(Adapter, offset, 0xFFFFFFFF);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ pbbreg->value = value;
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("-rtl8188eu_oid_rt_pro_read_bb_reg_hdl: offset=0x%03X value:0x%08X\n",
+ offset, value));
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct rf_reg_param *pbbreg;
+ u8 path;
+ u8 offset;
+ u32 value;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_write_rf_reg_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf);
+
+ if (pbbreg->path >= MAX_RF_PATH_NUMS)
+ return NDIS_STATUS_NOT_ACCEPTED;
+ if (pbbreg->offset > 0xFF)
+ return NDIS_STATUS_NOT_ACCEPTED;
+ if (pbbreg->value > 0xFFFFF)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ path = (u8)pbbreg->path;
+ offset = (u8)pbbreg->offset;
+ value = pbbreg->value;
+
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("rtl8188eu_oid_rt_pro_write_rf_reg_hdl: path=%d offset=0x%02X value=0x%05X\n",
+ path, offset, value));
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ write_rfreg(Adapter, path, offset, value);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct rf_reg_param *pbbreg;
+ u8 path;
+ u8 offset;
+ u32 value;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+ int status = NDIS_STATUS_SUCCESS;
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_read_rf_reg_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != QUERY_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf);
+
+ if (pbbreg->path >= MAX_RF_PATH_NUMS)
+ return NDIS_STATUS_NOT_ACCEPTED;
+ if (pbbreg->offset > 0xFF)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ path = (u8)pbbreg->path;
+ offset = (u8)pbbreg->offset;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ value = read_rfreg(Adapter, path, offset);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ pbbreg->value = value;
+
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("-rtl8188eu_oid_rt_pro_read_rf_reg_hdl: path=%d offset=0x%02X value=0x%05X\n",
+ path, offset, value));
+
+_func_exit_;
+
+ return status;
+}
+/* rtl8188eu_oid_rtl_seg_81_87_00 section end**************** */
+/* */
+
+/* rtl8188eu_oid_rtl_seg_81_80_00 section start **************** */
+/* */
+int rtl8188eu_oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u32 ratevalue;/* 4 */
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("+rtl8188eu_oid_rt_pro_set_data_rate_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len != sizeof(u32))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ ratevalue = *((u32 *)poid_par_priv->information_buf);/* 4 */
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("rtl8188eu_oid_rt_pro_set_data_rate_hdl: data rate idx=%d\n", ratevalue));
+ if (ratevalue >= MPT_RATE_LAST)
+ return NDIS_STATUS_INVALID_DATA;
+
+ Adapter->mppriv.rateidx = ratevalue;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ SetDataRate(Adapter);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u32 mode;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_start_test_hdl\n"));
+
+ if (Adapter->registrypriv.mp_mode == 0)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+
+ /* IQCalibrateBcut(Adapter); */
+
+ mode = *((u32 *)poid_par_priv->information_buf);
+ Adapter->mppriv.mode = mode;/* 1 for loopback */
+
+ if (mp_start_test(Adapter) == _FAIL) {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ goto exit;
+ }
+
+exit:
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("-rtl8188eu_oid_rt_pro_start_test_hdl: mp_mode=%d\n", Adapter->mppriv.mode));
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+Set OID_RT_PRO_STOP_TEST\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ mp_stop_test(Adapter);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("-Set OID_RT_PRO_STOP_TEST\n"));
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u32 Channel;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl\n"));
+
+ if (poid_par_priv->information_buf_len != sizeof(u32))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ if (poid_par_priv->type_of_oid == QUERY_OID) {
+ *((u32 *)poid_par_priv->information_buf) = Adapter->mppriv.channel;
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ Channel = *((u32 *)poid_par_priv->information_buf);
+ RT_TRACE(_module_mp_, _drv_notice_, ("rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl: Channel=%d\n", Channel));
+ if (Channel > 14)
+ return NDIS_STATUS_NOT_ACCEPTED;
+ Adapter->mppriv.channel = Channel;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ SetChannel(Adapter);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u16 bandwidth;
+ u16 channel_offset;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *padapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("+rtl8188eu_oid_rt_set_bandwidth_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len < sizeof(u32))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ bandwidth = *((u32 *)poid_par_priv->information_buf);/* 4 */
+ channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+ if (bandwidth != HT_CHANNEL_WIDTH_40)
+ bandwidth = HT_CHANNEL_WIDTH_20;
+ padapter->mppriv.bandwidth = (u8)bandwidth;
+ padapter->mppriv.prime_channel_offset = (u8)channel_offset;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ SetBandwidth(padapter);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("-rtl8188eu_oid_rt_set_bandwidth_hdl: bandwidth=%d channel_offset=%d\n",
+ bandwidth, channel_offset));
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u32 antenna;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_antenna_bb_hdl\n"));
+
+ if (poid_par_priv->information_buf_len != sizeof(u32))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ if (poid_par_priv->type_of_oid == SET_OID) {
+ antenna = *(u32 *)poid_par_priv->information_buf;
+
+ Adapter->mppriv.antenna_tx = (u16)((antenna & 0xFFFF0000) >> 16);
+ Adapter->mppriv.antenna_rx = (u16)(antenna & 0x0000FFFF);
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("rtl8188eu_oid_rt_pro_set_antenna_bb_hdl: tx_ant=0x%04x rx_ant=0x%04x\n",
+ Adapter->mppriv.antenna_tx, Adapter->mppriv.antenna_rx));
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ SetAntenna(Adapter);
+ _irqlevel_changed_(&oldirql, RAISE);
+ } else {
+ antenna = (Adapter->mppriv.antenna_tx << 16)|Adapter->mppriv.antenna_rx;
+ *(u32 *)poid_par_priv->information_buf = antenna;
+ }
+
+_func_exit_;
+
+ return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u32 tx_pwr_idx;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_pro_set_tx_power_control_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len != sizeof(u32))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ tx_pwr_idx = *((u32 *)poid_par_priv->information_buf);
+ if (tx_pwr_idx > MAX_TX_PWR_INDEX_N_MODE)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ Adapter->mppriv.txpoweridx = (u8)tx_pwr_idx;
+
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("rtl8188eu_oid_rt_pro_set_tx_power_control_hdl: idx=0x%2x\n",
+ Adapter->mppriv.txpoweridx));
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ SetTxPower(Adapter);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+
+/* */
+/* rtl8188eu_oid_rtl_seg_81_80_20 section start **************** */
+/* */
+int rtl8188eu_oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != QUERY_OID) {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ return status;
+ }
+
+ if (poid_par_priv->information_buf_len == sizeof(u32)) {
+ *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.tx_pktcount;
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+ } else {
+ status = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != QUERY_OID) {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ return status;
+ }
+ RT_TRACE(_module_mp_, _drv_alert_, ("===> rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl.\n"));
+ if (poid_par_priv->information_buf_len == sizeof(u32)) {
+ *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.rx_pktcount;
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+ RT_TRACE(_module_mp_, _drv_alert_, ("recv_ok:%d\n", Adapter->mppriv.rx_pktcount));
+ } else {
+ status = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != QUERY_OID) {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ return status;
+ }
+ RT_TRACE(_module_mp_, _drv_alert_, ("===> rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl.\n"));
+ if (poid_par_priv->information_buf_len == sizeof(u32)) {
+ *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.rx_crcerrpktcount;
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+ RT_TRACE(_module_mp_, _drv_alert_, ("recv_err:%d\n", Adapter->mppriv.rx_crcerrpktcount));
+ } else {
+ status = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+_func_exit_;
+
+ return status;
+}
+/* */
+
+int rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != SET_OID) {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ return status;
+ }
+
+ RT_TRACE(_module_mp_, _drv_alert_, ("===> rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl.\n"));
+ Adapter->mppriv.tx_pktcount = 0;
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != SET_OID) {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ return status;
+ }
+
+ if (poid_par_priv->information_buf_len == sizeof(u32)) {
+ Adapter->mppriv.rx_pktcount = 0;
+ Adapter->mppriv.rx_crcerrpktcount = 0;
+ } else {
+ status = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != SET_OID) {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ return status;
+ }
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ ResetPhyRxPktCount(Adapter);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != QUERY_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len != sizeof(u32))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ *(u32 *)poid_par_priv->information_buf = GetPhyRxPktReceived(Adapter);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("-rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl: recv_ok=%d\n", *(u32 *)poid_par_priv->information_buf));
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != QUERY_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+
+ if (poid_par_priv->information_buf_len != sizeof(u32))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ *(u32 *)poid_par_priv->information_buf = GetPhyRxPktCRC32Error(Adapter);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("-rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl: recv_err =%d\n",
+ *(u32 *)poid_par_priv->information_buf));
+
+_func_exit_;
+
+ return status;
+}
+/* rtl8188eu_oid_rtl_seg_81_80_20 section end **************** */
+int rtl8188eu_oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u32 bStartTest;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_continuous_tx_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ bStartTest = *((u32 *)poid_par_priv->information_buf);
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ SetContinuousTx(Adapter, (u8)bStartTest);
+ if (bStartTest) {
+ struct mp_priv *pmp_priv = &Adapter->mppriv;
+ if (pmp_priv->tx.stop == 0) {
+ pmp_priv->tx.stop = 1;
+ DBG_88E("%s: pkt tx is running...\n", __func__);
+ rtw_msleep_os(5);
+ }
+ pmp_priv->tx.stop = 0;
+ pmp_priv->tx.count = 1;
+ SetPacketTx(Adapter);
+ }
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u32 bStartTest;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_alert_, ("+rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ bStartTest = *((u32 *)poid_par_priv->information_buf);
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ SetSingleCarrierTx(Adapter, (u8)bStartTest);
+ if (bStartTest) {
+ struct mp_priv *pmp_priv = &Adapter->mppriv;
+ if (pmp_priv->tx.stop == 0) {
+ pmp_priv->tx.stop = 1;
+ DBG_88E("%s: pkt tx is running...\n", __func__);
+ rtw_msleep_os(5);
+ }
+ pmp_priv->tx.stop = 0;
+ pmp_priv->tx.count = 1;
+ SetPacketTx(Adapter);
+ }
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u32 bStartTest;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ bStartTest = *((u32 *)poid_par_priv->information_buf);
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ SetCarrierSuppressionTx(Adapter, (u8)bStartTest);
+ if (bStartTest) {
+ struct mp_priv *pmp_priv = &Adapter->mppriv;
+ if (pmp_priv->tx.stop == 0) {
+ pmp_priv->tx.stop = 1;
+ DBG_88E("%s: pkt tx is running...\n", __func__);
+ rtw_msleep_os(5);
+ }
+ pmp_priv->tx.stop = 0;
+ pmp_priv->tx.count = 1;
+ SetPacketTx(Adapter);
+ }
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u32 bStartTest;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_alert_, ("+rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ bStartTest = *((u32 *)poid_par_priv->information_buf);
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ SetSingleToneTx(Adapter, (u8)bStartTest);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+
+int rtl8188eu_oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+ int status = NDIS_STATUS_SUCCESS;
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ rtw_hal_set_hwreg(Adapter, HW_VAR_TRIGGER_GPIO_0, NULL);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* rtl8188eu_oid_rtl_seg_81_80_00 section end **************** */
+/* */
+int rtl8188eu_oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct mp_rw_reg *RegRWStruct;
+ u32 offset, width;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("+rtl8188eu_oid_rt_pro_read_register_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != QUERY_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf;
+ offset = RegRWStruct->offset;
+ width = RegRWStruct->width;
+
+ if (offset > 0xFFF)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+
+ switch (width) {
+ case 1:
+ RegRWStruct->value = rtw_read8(Adapter, offset);
+ break;
+ case 2:
+ RegRWStruct->value = rtw_read16(Adapter, offset);
+ break;
+ default:
+ width = 4;
+ RegRWStruct->value = rtw_read32(Adapter, offset);
+ break;
+ }
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("rtl8188eu_oid_rt_pro_read_register_hdl: offset:0x%04X value:0x%X\n",
+ offset, RegRWStruct->value));
+
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ *poid_par_priv->bytes_rw = width;
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct mp_rw_reg *RegRWStruct;
+ u32 offset, width, value;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *padapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("+rtl8188eu_oid_rt_pro_write_register_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf;
+ offset = RegRWStruct->offset;
+ width = RegRWStruct->width;
+ value = RegRWStruct->value;
+
+ if (offset > 0xFFF)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+
+ switch (RegRWStruct->width) {
+ case 1:
+ if (value > 0xFF) {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+ rtw_write8(padapter, offset, (u8)value);
+ break;
+ case 2:
+ if (value > 0xFFFF) {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+ rtw_write16(padapter, offset, (u16)value);
+ break;
+ case 4:
+ rtw_write32(padapter, offset, value);
+ break;
+ default:
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("-rtl8188eu_oid_rt_pro_write_register_hdl: offset=0x%08X width=%d value=0x%X\n",
+ offset, width, value));
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_burst_read_register_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_burst_write_register_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+
+/* */
+int rtl8188eu_oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+
+/* */
+int rtl8188eu_oid_rt_pro_write16_eeprom_hdl (struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_wr_attrib_mem_hdl (struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+ int status = NDIS_STATUS_SUCCESS;
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+OID_RT_PRO_SET_DATA_RATE_EX\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+
+ if (rtw_setdatarate_cmd(Adapter, poid_par_priv->information_buf) != _SUCCESS)
+ status = NDIS_STATUS_NOT_ACCEPTED;
+
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ u8 thermal = 0;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_get_thermal_meter_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != QUERY_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len < sizeof(u32))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ GetThermalMeter(Adapter, &thermal);
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ *(u32 *)poid_par_priv->information_buf = (u32)thermal;
+ *poid_par_priv->bytes_rw = sizeof(u32);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_read_tssi_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+
+_func_enter_;
+
+ if (poid_par_priv->information_buf_len < sizeof(u8))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ if (poid_par_priv->type_of_oid == SET_OID) {
+ u8 enable;
+
+ enable = *(u8 *)poid_par_priv->information_buf;
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("+rtl8188eu_oid_rt_pro_set_power_tracking_hdl: enable =%d\n", enable));
+
+ SetPowerTracking(Adapter, enable);
+ } else {
+ GetPowerTracking(Adapter, (u8 *)poid_par_priv->information_buf);
+ }
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+/* */
+int rtl8188eu_oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+
+/* rtl8188eu_oid_rtl_seg_87_12_00 section start **************** */
+int rtl8188eu_oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+
+int rtl8188eu_oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+
+int rtl8188eu_oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+
+int rtl8188eu_oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+
+int rtl8188eu_oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return NDIS_STATUS_SUCCESS;
+}
+/* */
+int rtl8188eu_oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct efuse_access_struct *pefuse;
+ u8 *data;
+ u16 addr = 0, cnts = 0, max_available_size = 0;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != QUERY_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len < sizeof(struct efuse_access_struct))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ pefuse = (struct efuse_access_struct *)poid_par_priv->information_buf;
+ addr = pefuse->start_addr;
+ cnts = pefuse->cnts;
+ data = pefuse->data;
+
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("+rtl8188eu_oid_rt_pro_read_efuse_hd: buf_len=%d addr=%d cnts=%d\n",
+ poid_par_priv->information_buf_len, addr, cnts));
+
+ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+
+ if ((addr + cnts) > max_available_size) {
+ RT_TRACE(_module_mp_, _drv_err_, ("!rtl8188eu_oid_rt_pro_read_efuse_hdl: parameter error!\n"));
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ if (rtw_efuse_access(Adapter, false, addr, cnts, data) == _FAIL) {
+ RT_TRACE(_module_mp_, _drv_err_, ("!rtl8188eu_oid_rt_pro_read_efuse_hdl: rtw_efuse_access FAIL!\n"));
+ status = NDIS_STATUS_FAILURE;
+ } else {
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+ }
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct efuse_access_struct *pefuse;
+ u8 *data;
+ u16 addr = 0, cnts = 0, max_available_size = 0;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ pefuse = (struct efuse_access_struct *)poid_par_priv->information_buf;
+ addr = pefuse->start_addr;
+ cnts = pefuse->cnts;
+ data = pefuse->data;
+
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("+rtl8188eu_oid_rt_pro_write_efuse_hdl: buf_len=%d addr=0x%04x cnts=%d\n",
+ poid_par_priv->information_buf_len, addr, cnts));
+
+ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+
+ if ((addr + cnts) > max_available_size) {
+ RT_TRACE(_module_mp_, _drv_err_, ("!rtl8188eu_oid_rt_pro_write_efuse_hdl: parameter error"));
+ return NDIS_STATUS_NOT_ACCEPTED;
+ }
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ if (rtw_efuse_access(Adapter, true, addr, cnts, data) == _FAIL)
+ status = NDIS_STATUS_FAILURE;
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct pgpkt *ppgpkt;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ *poid_par_priv->bytes_rw = 0;
+
+ if (poid_par_priv->information_buf_len < sizeof(struct pgpkt *))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ ppgpkt = (struct pgpkt *)poid_par_priv->information_buf;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+
+ if (poid_par_priv->type_of_oid == QUERY_OID) {
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl: Read offset=0x%x\n",\
+ ppgpkt->offset));
+
+ Efuse_PowerSwitch(Adapter, false, true);
+ if (Efuse_PgPacketRead(Adapter, ppgpkt->offset, ppgpkt->data, false) == true)
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+ else
+ status = NDIS_STATUS_FAILURE;
+ Efuse_PowerSwitch(Adapter, false, false);
+ } else {
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl: Write offset=0x%x word_en=0x%x\n",\
+ ppgpkt->offset, ppgpkt->word_en));
+
+ Efuse_PowerSwitch(Adapter, true, true);
+ if (Efuse_PgPacketWrite(Adapter, ppgpkt->offset, ppgpkt->word_en, ppgpkt->data, false) == true)
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+ else
+ status = NDIS_STATUS_FAILURE;
+ Efuse_PowerSwitch(Adapter, true, false);
+ }
+
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("-rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl: status=0x%08X\n", status));
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u16 size;
+ u8 ret;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != QUERY_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len < sizeof(u32))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+ ret = efuse_GetCurrentSize(Adapter, &size);
+ _irqlevel_changed_(&oldirql, RAISE);
+ if (ret == _SUCCESS) {
+ *(u32 *)poid_par_priv->information_buf = size;
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+ } else {
+ status = NDIS_STATUS_FAILURE;
+ }
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != QUERY_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len < sizeof(u32))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ *(u32 *)poid_par_priv->information_buf = efuse_GetMaxSize(Adapter);
+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("-rtl8188eu_oid_rt_get_efuse_max_size_hdl: size=%d status=0x%08X\n",
+ *(int *)poid_par_priv->information_buf, status));
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status;
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_pro_efuse_hdl\n"));
+
+ if (poid_par_priv->type_of_oid == QUERY_OID)
+ status = rtl8188eu_oid_rt_pro_read_efuse_hdl(poid_par_priv);
+ else
+ status = rtl8188eu_oid_rt_pro_write_efuse_hdl(poid_par_priv);
+
+ RT_TRACE(_module_mp_, _drv_info_, ("-rtl8188eu_oid_rt_pro_efuse_hdl: status=0x%08X\n", status));
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u8 *data;
+ int status = NDIS_STATUS_SUCCESS;
+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+ u16 maplen = 0;
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_efuse_map_hdl\n"));
+
+ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&maplen, false);
+
+ *poid_par_priv->bytes_rw = 0;
+
+ if (poid_par_priv->information_buf_len < maplen)
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ data = (u8 *)poid_par_priv->information_buf;
+
+ _irqlevel_changed_(&oldirql, LOWER);
+
+ if (poid_par_priv->type_of_oid == QUERY_OID) {
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("rtl8188eu_oid_rt_pro_efuse_map_hdl: READ\n"));
+
+ if (rtw_efuse_map_read(Adapter, 0, maplen, data) == _SUCCESS) {
+ *poid_par_priv->bytes_rw = maplen;
+ } else {
+ RT_TRACE(_module_mp_, _drv_err_,
+ ("rtl8188eu_oid_rt_pro_efuse_map_hdl: READ fail\n"));
+ status = NDIS_STATUS_FAILURE;
+ }
+ } else {
+ /* SET_OID */
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("rtl8188eu_oid_rt_pro_efuse_map_hdl: WRITE\n"));
+
+ if (rtw_efuse_map_write(Adapter, 0, maplen, data) == _SUCCESS) {
+ *poid_par_priv->bytes_rw = maplen;
+ } else {
+ RT_TRACE(_module_mp_, _drv_err_,
+ ("rtl8188eu_oid_rt_pro_efuse_map_hdl: WRITE fail\n"));
+ status = NDIS_STATUS_FAILURE;
+ }
+ }
+
+ _irqlevel_changed_(&oldirql, RAISE);
+
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("-rtl8188eu_oid_rt_pro_efuse_map_hdl: status=0x%08X\n", status));
+
+_func_exit_;
+
+ return status;
+}
+
+int rtl8188eu_oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+ return status;
+}
+
+int rtl8188eu_oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv)
+{
+ u8 rx_pkt_type;
+ int status = NDIS_STATUS_SUCCESS;
+
+_func_enter_;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_set_rx_packet_type_hdl\n"));
+
+ if (poid_par_priv->type_of_oid != SET_OID)
+ return NDIS_STATUS_NOT_ACCEPTED;
+
+ if (poid_par_priv->information_buf_len < sizeof(u8))
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ rx_pkt_type = *((u8 *)poid_par_priv->information_buf);/* 4 */
+
+ RT_TRACE(_module_mp_, _drv_info_, ("rx_pkt_type: %x\n", rx_pkt_type));
+_func_exit_;
+
+ return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+
+int rtl8188eu_oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
+
+int rtl8188eu_mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv)
+{
+ struct mp_xmit_parm *pparm;
+ struct adapter *padapter;
+ struct mp_priv *pmp_priv;
+ struct pkt_attrib *pattrib;
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("+%s\n", __func__));
+
+ pparm = (struct mp_xmit_parm *)poid_par_priv->information_buf;
+ padapter = (struct adapter *)poid_par_priv->adapter_context;
+ pmp_priv = &padapter->mppriv;
+
+ if (poid_par_priv->type_of_oid == QUERY_OID) {
+ pparm->enable = !pmp_priv->tx.stop;
+ pparm->count = pmp_priv->tx.sended;
+ } else {
+ if (pparm->enable == 0) {
+ pmp_priv->tx.stop = 1;
+ } else if (pmp_priv->tx.stop == 1) {
+ pmp_priv->tx.stop = 0;
+ pmp_priv->tx.count = pparm->count;
+ pmp_priv->tx.payload = pparm->payload_type;
+ pattrib = &pmp_priv->tx.attrib;
+ pattrib->pktlen = pparm->length;
+ memcpy(pattrib->dst, pparm->da, ETH_ALEN);
+ SetPacketTx(padapter);
+ } else {
+ return NDIS_STATUS_FAILURE;
+ }
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+/* */
+int rtl8188eu_oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv)
+{
+ int status = NDIS_STATUS_SUCCESS;
+
+_func_enter_;
+
+ if (poid_par_priv->type_of_oid != SET_OID) {
+ status = NDIS_STATUS_NOT_ACCEPTED;
+ return status;
+ }
+
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("\n ===> Setrtl8188eu_oid_rt_set_power_down_hdl.\n"));
+
+ _irqlevel_changed_(&oldirql, LOWER);
+
+ /* CALL the power_down function */
+ _irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+ return status;
+}
+/* */
+int rtl8188eu_oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv)
+{
+ return 0;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_p2p.c b/drivers/staging/rtl8188eu/core/rtw_p2p.c
new file mode 100644
index 00000000000..8cf915f4cf9
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_p2p.c
@@ -0,0 +1,2064 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_P2P_C_
+
+#include <drv_types.h>
+#include <rtw_p2p.h>
+#include <wifi.h>
+
+#ifdef CONFIG_88EU_P2P
+
+static int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8 *ch_list, u8 ch_cnt)
+{
+ int found = 0, i = 0;
+
+ for (i = 0; i < ch_cnt; i++) {
+ if (ch_list[i] == desired_ch) {
+ found = 1;
+ break;
+ }
+ }
+ return found;
+}
+
+static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+ unsigned long irqL;
+ struct list_head *phead, *plist;
+ u32 len = 0;
+ u16 attr_len = 0;
+ u8 tmplen, *pdata_attr, *pstart, *pcur;
+ struct sta_info *psta = NULL;
+ struct adapter *padapter = pwdinfo->padapter;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ DBG_88E("%s\n", __func__);
+
+ pdata_attr = rtw_zmalloc(MAX_P2P_IE_LEN);
+
+ pstart = pdata_attr;
+ pcur = pdata_attr;
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ phead = &pstapriv->asoc_list;
+ plist = get_next(phead);
+
+ /* look up sta asoc_queue */
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+ plist = get_next(plist);
+
+
+ if (psta->is_p2p_device) {
+ tmplen = 0;
+
+ pcur++;
+
+ /* P2P device address */
+ memcpy(pcur, psta->dev_addr, ETH_ALEN);
+ pcur += ETH_ALEN;
+
+ /* P2P interface address */
+ memcpy(pcur, psta->hwaddr, ETH_ALEN);
+ pcur += ETH_ALEN;
+
+ *pcur = psta->dev_cap;
+ pcur++;
+
+ /* u16*)(pcur) = cpu_to_be16(psta->config_methods); */
+ RTW_PUT_BE16(pcur, psta->config_methods);
+ pcur += 2;
+
+ memcpy(pcur, psta->primary_dev_type, 8);
+ pcur += 8;
+
+ *pcur = psta->num_of_secdev_type;
+ pcur++;
+
+ memcpy(pcur, psta->secdev_types_list, psta->num_of_secdev_type*8);
+ pcur += psta->num_of_secdev_type*8;
+
+ if (psta->dev_name_len > 0) {
+ /* u16*)(pcur) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */
+ RTW_PUT_BE16(pcur, WPS_ATTR_DEVICE_NAME);
+ pcur += 2;
+
+ /* u16*)(pcur) = cpu_to_be16(psta->dev_name_len); */
+ RTW_PUT_BE16(pcur, psta->dev_name_len);
+ pcur += 2;
+
+ memcpy(pcur, psta->dev_name, psta->dev_name_len);
+ pcur += psta->dev_name_len;
+ }
+
+
+ tmplen = (u8)(pcur-pstart);
+
+ *pstart = (tmplen-1);
+
+ attr_len += tmplen;
+
+ /* pstart += tmplen; */
+ pstart = pcur;
+ }
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ if (attr_len > 0)
+ len = rtw_set_p2p_attr_content(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr);
+
+ kfree(pdata_attr);
+ return len;
+}
+
+static void issue_group_disc_req(struct wifidirect_info *pwdinfo, u8 *da)
+{
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct adapter *padapter = pwdinfo->padapter;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u8 oui_subtype = P2P_GO_DISC_REQUEST;
+ u8 dialogToken = 0;
+
+ DBG_88E("[%s]\n", __func__);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ /* Build P2P action frame header */
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+ /* there is no IE in this P2P action frame */
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+}
+
+static void issue_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken)
+{
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct adapter *padapter = pwdinfo->padapter;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+ u8 action = P2P_PUB_ACTION_ACTION;
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u8 oui_subtype = P2P_DEVDISC_RESP;
+ u8 p2pie[8] = { 0x00 };
+ u32 p2pielen = 0;
+
+ DBG_88E("[%s]\n", __func__);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ /* Build P2P public action frame header */
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+
+ /* Build P2P IE */
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* P2P_ATTR_STATUS */
+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status);
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen);
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+}
+
+static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8 *raddr, u8 *frame_body, u16 config_method)
+{
+ struct adapter *padapter = pwdinfo->padapter;
+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+ u8 action = P2P_PUB_ACTION_ACTION;
+ u8 dialogToken = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u8 oui_subtype = P2P_PROVISION_DISC_RESP;
+ u8 wpsie[100] = { 0x00 };
+ u8 wpsielen = 0;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+ wpsielen = 0;
+ /* WPS OUI */
+ RTW_PUT_BE32(wpsie, WPSOUI);
+ wpsielen += 4;
+
+ /* Config Method */
+ /* Type: */
+ RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD);
+ wpsielen += 2;
+
+ /* Length: */
+ RTW_PUT_BE16(wpsie + wpsielen, 0x0002);
+ wpsielen += 2;
+
+ /* Value: */
+ RTW_PUT_BE16(wpsie + wpsielen, config_method);
+ wpsielen += 2;
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+
+ return;
+}
+
+static void issue_p2p_presence_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken)
+{
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ struct adapter *padapter = pwdinfo->padapter;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u8 oui_subtype = P2P_PRESENCE_RESPONSE;
+ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
+ u8 noa_attr_content[32] = { 0x00 };
+ u32 p2pielen = 0;
+
+ DBG_88E("[%s]\n", __func__);
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ SetFrameSubType(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ /* Build P2P action frame header */
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+
+ /* Add P2P IE header */
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Add Status attribute in P2P IE */
+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status);
+
+ /* Add NoA attribute in P2P IE */
+ noa_attr_content[0] = 0x1;/* index */
+ noa_attr_content[1] = 0x0;/* CTWindow and OppPS Parameters */
+
+ /* todo: Notice of Absence Descriptor(s) */
+
+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_NOA, 2, noa_attr_content);
+
+
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &(pattrib->pktlen));
+
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+}
+
+u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
+ u16 capability = 0;
+ u32 len = 0, p2pielen = 0;
+ __le16 le_tmp;
+
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+
+ /* According to the P2P Specification, the beacon frame should contain 3 P2P attributes */
+ /* 1. P2P Capability */
+ /* 2. P2P Device ID */
+ /* 3. Notice of Absence (NOA) */
+
+ /* P2P Capability ATTR */
+ /* Type: */
+ /* Length: */
+ /* Value: */
+ /* Device Capability Bitmap, 1 byte */
+ /* Be able to participate in additional P2P Groups and */
+ /* support the P2P Invitation Procedure */
+ /* Group Capability Bitmap, 1 byte */
+ capability = P2P_DEVCAP_INVITATION_PROC|P2P_DEVCAP_CLIENT_DISCOVERABILITY;
+ capability |= ((P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS) << 8);
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
+ capability |= (P2P_GRPCAP_GROUP_FORMATION<<8);
+
+ le_tmp = cpu_to_le16(capability);
+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8 *)&le_tmp);
+
+ /* P2P Device ID ATTR */
+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_DEVICE_ID, ETH_ALEN, pwdinfo->device_addr);
+
+ /* Notice of Absence ATTR */
+ /* Type: */
+ /* Length: */
+ /* Value: */
+
+ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len);
+ return len;
+}
+
+u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
+ u32 len = 0, p2pielen = 0;
+
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Commented by Albert 20100907 */
+ /* According to the P2P Specification, the probe response frame should contain 5 P2P attributes */
+ /* 1. P2P Capability */
+ /* 2. Extended Listen Timing */
+ /* 3. Notice of Absence (NOA) (Only GO needs this) */
+ /* 4. Device Info */
+ /* 5. Group Info (Only GO need this) */
+
+ /* P2P Capability ATTR */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+ /* Length: */
+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */
+ RTW_PUT_LE16(p2pie + p2pielen, 0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Device Capability Bitmap, 1 byte */
+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+ /* Group Capability Bitmap, 1 byte */
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ p2pie[p2pielen] = (P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS);
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
+ p2pie[p2pielen] |= P2P_GRPCAP_GROUP_FORMATION;
+
+ p2pielen++;
+ } else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
+ /* Group Capability Bitmap, 1 byte */
+ if (pwdinfo->persistent_supported)
+ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
+ else
+ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
+ }
+
+ /* Extended Listen Timing ATTR */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+ /* Length: */
+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); */
+ RTW_PUT_LE16(p2pie + p2pielen, 0x0004);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Availability Period */
+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */
+ RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF);
+ p2pielen += 2;
+
+ /* Availability Interval */
+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */
+ RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF);
+ p2pielen += 2;
+
+
+ /* Notice of Absence ATTR */
+ /* Type: */
+ /* Length: */
+ /* Value: */
+
+ /* Device Info ATTR */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+ /* Length: */
+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */
+ RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ /* P2P Device Address */
+ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ /* Config Method */
+ /* This field should be big endian. Noted by P2P specification. */
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); */
+ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->supported_wps_cm);
+ p2pielen += 2;
+
+ /* Primary Device Type */
+ /* Category ID */
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */
+ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA);
+ p2pielen += 2;
+
+ /* OUI */
+ /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */
+ RTW_PUT_BE32(p2pie + p2pielen, WPSOUI);
+ p2pielen += 4;
+
+ /* Sub Category ID */
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */
+ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER);
+ p2pielen += 2;
+
+ /* Number of Secondary Device Types */
+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */
+
+ /* Device Name */
+ /* Type: */
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */
+ RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME);
+ p2pielen += 2;
+
+ /* Length: */
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */
+ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+ p2pielen += pwdinfo->device_name_len;
+
+ /* Group Info ATTR */
+ /* Type: */
+ /* Length: */
+ /* Value: */
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+ p2pielen += go_add_group_info_attr(pwdinfo, p2pie + p2pielen);
+
+
+ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len);
+
+
+ return len;
+}
+
+u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 *pssid, u8 ussidlen, u8 *pdev_raddr)
+{
+ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
+ u32 len = 0, p2pielen = 0;
+
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Commented by Albert 20110301 */
+ /* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */
+ /* 1. P2P Capability */
+ /* 2. Device Info */
+ /* 3. Group ID (When joining an operating P2P Group) */
+
+ /* P2P Capability ATTR */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+ /* Length: */
+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */
+ RTW_PUT_LE16(p2pie + p2pielen, 0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Device Capability Bitmap, 1 byte */
+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+ /* Group Capability Bitmap, 1 byte */
+ if (pwdinfo->persistent_supported)
+ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
+ else
+ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
+
+
+ /* Device Info ATTR */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+ /* Length: */
+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */
+ RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ /* P2P Device Address */
+ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ /* Config Method */
+ /* This field should be big endian. Noted by P2P specification. */
+ if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) {
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); */
+ RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_PBC);
+ } else {
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); */
+ RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_DISPLAY);
+ }
+
+ p2pielen += 2;
+
+ /* Primary Device Type */
+ /* Category ID */
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */
+ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA);
+ p2pielen += 2;
+
+ /* OUI */
+ /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */
+ RTW_PUT_BE32(p2pie + p2pielen, WPSOUI);
+ p2pielen += 4;
+
+ /* Sub Category ID */
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */
+ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER);
+ p2pielen += 2;
+
+ /* Number of Secondary Device Types */
+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */
+
+ /* Device Name */
+ /* Type: */
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */
+ RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME);
+ p2pielen += 2;
+
+ /* Length: */
+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */
+ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+ p2pielen += pwdinfo->device_name_len;
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+ /* Added by Albert 2011/05/19 */
+ /* In this case, the pdev_raddr is the device address of the group owner. */
+
+ /* P2P Group ID ATTR */
+ /* Type: */
+ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+ /* Length: */
+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + ussidlen); */
+ RTW_PUT_LE16(p2pie + p2pielen, ETH_ALEN + ussidlen);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2pie + p2pielen, pdev_raddr, ETH_ALEN);
+ p2pielen += ETH_ALEN;
+
+ memcpy(p2pie + p2pielen, pssid, ussidlen);
+ p2pielen += ussidlen;
+ }
+
+ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len);
+
+
+ return len;
+}
+
+
+u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code)
+{
+ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
+ u32 len = 0, p2pielen = 0;
+
+ /* P2P OUI */
+ p2pielen = 0;
+ p2pie[p2pielen++] = 0x50;
+ p2pie[p2pielen++] = 0x6F;
+ p2pie[p2pielen++] = 0x9A;
+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* According to the P2P Specification, the Association response frame should contain 2 P2P attributes */
+ /* 1. Status */
+ /* 2. Extended Listen Timing (optional) */
+
+
+ /* Status ATTR */
+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status_code);
+
+
+ /* Extended Listen Timing ATTR */
+ /* Type: */
+ /* Length: */
+ /* Value: */
+
+ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len);
+
+ return len;
+}
+
+u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+ u32 len = 0;
+
+ return len;
+}
+
+u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+ u8 *p;
+ u32 ret = false;
+ u8 *p2pie;
+ u32 p2pielen = 0;
+ int ssid_len = 0, rate_cnt = 0;
+
+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SUPPORTEDRATES_IE_, (int *)&rate_cnt,
+ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_);
+
+ if (rate_cnt <= 4) {
+ int i, g_rate = 0;
+
+ for (i = 0; i < rate_cnt; i++) {
+ if (((*(p + 2 + i) & 0xff) != 0x02) &&
+ ((*(p + 2 + i) & 0xff) != 0x04) &&
+ ((*(p + 2 + i) & 0xff) != 0x0B) &&
+ ((*(p + 2 + i) & 0xff) != 0x16))
+ g_rate = 1;
+ }
+
+ if (g_rate == 0) {
+ /* There is no OFDM rate included in SupportedRates IE of this probe request frame */
+ /* The driver should response this probe request. */
+ return ret;
+ }
+ } else {
+ /* rate_cnt > 4 means the SupportRates IE contains the OFDM rate because the count of CCK rates are 4. */
+ /* We should proceed the following check for this probe request. */
+ }
+
+ /* Added comments by Albert 20100906 */
+ /* There are several items we should check here. */
+ /* 1. This probe request frame must contain the P2P IE. (Done) */
+ /* 2. This probe request frame must contain the wildcard SSID. (Done) */
+ /* 3. Wildcard BSSID. (Todo) */
+ /* 4. Destination Address. (Done in mgt_dispatcher function) */
+ /* 5. Requested Device Type in WSC IE. (Todo) */
+ /* 6. Device ID attribute in P2P IE. (Todo) */
+
+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ssid_len,
+ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_);
+
+ ssid_len &= 0xff; /* Just last 1 byte is valid for ssid len of the probe request */
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_ , len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_ , NULL, &p2pielen);
+ if (p2pie) {
+ if ((p != NULL) && _rtw_memcmp((void *)(p+2), (void *)pwdinfo->p2p_wildcard_ssid , 7)) {
+ /* todo: */
+ /* Check Requested Device Type attributes in WSC IE. */
+ /* Check Device ID attribute in P2P IE */
+
+ ret = true;
+ } else if ((p != NULL) && (ssid_len == 0)) {
+ ret = true;
+ }
+ } else {
+ /* non -p2p device */
+ }
+ }
+
+
+ return ret;
+}
+
+u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta)
+{
+ u8 status_code = P2P_STATUS_SUCCESS;
+ u8 *pbuf, *pattr_content = NULL;
+ u32 attr_contentlen = 0;
+ u16 cap_attr = 0;
+ unsigned short frame_type, ie_offset = 0;
+ u8 *ies;
+ u32 ies_len;
+ u8 *p2p_ie;
+ u32 p2p_ielen = 0;
+ __be16 be_tmp;
+ __le16 le_tmp;
+
+ if (!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+ return P2P_STATUS_FAIL_REQUEST_UNABLE;
+
+ frame_type = GetFrameSubType(pframe);
+ if (frame_type == WIFI_ASSOCREQ)
+ ie_offset = _ASOCREQ_IE_OFFSET_;
+ else /* WIFI_REASSOCREQ */
+ ie_offset = _REASOCREQ_IE_OFFSET_;
+
+ ies = pframe + WLAN_HDR_A3_LEN + ie_offset;
+ ies_len = len - WLAN_HDR_A3_LEN - ie_offset;
+
+ p2p_ie = rtw_get_p2p_ie(ies , ies_len , NULL, &p2p_ielen);
+
+ if (!p2p_ie) {
+ DBG_88E("[%s] P2P IE not Found!!\n", __func__);
+ status_code = P2P_STATUS_FAIL_INVALID_PARAM;
+ } else {
+ DBG_88E("[%s] P2P IE Found!!\n", __func__);
+ }
+
+ while (p2p_ie) {
+ /* Check P2P Capability ATTR */
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&le_tmp, (uint *)&attr_contentlen)) {
+ DBG_88E("[%s] Got P2P Capability Attr!!\n", __func__);
+ cap_attr = le16_to_cpu(le_tmp);
+ psta->dev_cap = cap_attr&0xff;
+ }
+
+ /* Check Extended Listen Timing ATTR */
+
+
+ /* Check P2P Device Info ATTR */
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, NULL, (uint *)&attr_contentlen)) {
+ DBG_88E("[%s] Got P2P DEVICE INFO Attr!!\n", __func__);
+ pattr_content = rtw_zmalloc(attr_contentlen);
+ pbuf = pattr_content;
+ if (pattr_content) {
+ u8 num_of_secdev_type;
+ u16 dev_name_len;
+
+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO , pattr_content, (uint *)&attr_contentlen);
+
+ memcpy(psta->dev_addr, pattr_content, ETH_ALEN);/* P2P Device Address */
+
+ pattr_content += ETH_ALEN;
+
+ memcpy(&be_tmp, pattr_content, 2);/* Config Methods */
+ psta->config_methods = be16_to_cpu(be_tmp);
+
+ pattr_content += 2;
+
+ memcpy(psta->primary_dev_type, pattr_content, 8);
+
+ pattr_content += 8;
+
+ num_of_secdev_type = *pattr_content;
+ pattr_content += 1;
+
+ if (num_of_secdev_type == 0) {
+ psta->num_of_secdev_type = 0;
+ } else {
+ u32 len;
+
+ psta->num_of_secdev_type = num_of_secdev_type;
+
+ len = (sizeof(psta->secdev_types_list) < (num_of_secdev_type*8)) ?
+ (sizeof(psta->secdev_types_list)) : (num_of_secdev_type*8);
+
+ memcpy(psta->secdev_types_list, pattr_content, len);
+
+ pattr_content += (num_of_secdev_type*8);
+ }
+
+
+ psta->dev_name_len = 0;
+ if (WPS_ATTR_DEVICE_NAME == be16_to_cpu(*(__be16 *)pattr_content)) {
+ dev_name_len = be16_to_cpu(*(__be16 *)(pattr_content+2));
+
+ psta->dev_name_len = (sizeof(psta->dev_name) < dev_name_len) ? sizeof(psta->dev_name) : dev_name_len;
+
+ memcpy(psta->dev_name, pattr_content+4, psta->dev_name_len);
+ }
+ kfree(pbuf);
+ }
+ }
+
+ /* Get the next P2P IE */
+ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
+ }
+
+ return status_code;
+}
+
+u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+ u8 *frame_body;
+ u8 status, dialogToken;
+ struct sta_info *psta = NULL;
+ struct adapter *padapter = pwdinfo->padapter;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ u8 *p2p_ie;
+ u32 p2p_ielen = 0;
+
+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+ dialogToken = frame_body[7];
+ status = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP;
+
+ p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen);
+ if (p2p_ie) {
+ u8 groupid[38] = { 0x00 };
+ u8 dev_addr[ETH_ALEN] = { 0x00 };
+ u32 attr_contentlen = 0;
+
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) {
+ if (_rtw_memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) &&
+ _rtw_memcmp(pwdinfo->p2p_group_ssid, groupid+ETH_ALEN, pwdinfo->p2p_group_ssid_len)) {
+ attr_contentlen = 0;
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_ID, dev_addr, &attr_contentlen)) {
+ unsigned long irqL;
+ struct list_head *phead, *plist;
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ phead = &pstapriv->asoc_list;
+ plist = get_next(phead);
+
+ /* look up sta asoc_queue */
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+ plist = get_next(plist);
+
+ if (psta->is_p2p_device && (psta->dev_cap&P2P_DEVCAP_CLIENT_DISCOVERABILITY) &&
+ _rtw_memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) {
+ /* issue GO Discoverability Request */
+ issue_group_disc_req(pwdinfo, psta->hwaddr);
+ status = P2P_STATUS_SUCCESS;
+ break;
+ } else {
+ status = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+ }
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ } else {
+ status = P2P_STATUS_FAIL_INVALID_PARAM;
+ }
+ } else {
+ status = P2P_STATUS_FAIL_INVALID_PARAM;
+ }
+ }
+ }
+
+
+ /* issue Device Discoverability Response */
+ issue_p2p_devdisc_resp(pwdinfo, GetAddr2Ptr(pframe), status, dialogToken);
+
+ return (status == P2P_STATUS_SUCCESS) ? true : false;
+}
+
+u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+ return true;
+}
+
+u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+ u8 *frame_body;
+ u8 *wpsie;
+ uint wps_ielen = 0, attr_contentlen = 0;
+ u16 uconfig_method = 0;
+ __be16 be_tmp;
+
+ frame_body = (pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+ wpsie = rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen);
+ if (wpsie) {
+ if (rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_CONF_METHOD, (u8 *)&be_tmp, &attr_contentlen)) {
+ uconfig_method = be16_to_cpu(be_tmp);
+ switch (uconfig_method) {
+ case WPS_CM_DISPLYA:
+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
+ break;
+ case WPS_CM_LABEL:
+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "lab", 3);
+ break;
+ case WPS_CM_PUSH_BUTTON:
+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
+ break;
+ case WPS_CM_KEYPAD:
+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
+ break;
+ }
+ issue_p2p_provision_resp(pwdinfo, GetAddr2Ptr(pframe), frame_body, uconfig_method);
+ }
+ }
+ DBG_88E("[%s] config method = %s\n", __func__, pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req);
+ return true;
+}
+
+u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe)
+{
+ return true;
+}
+
+static u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list)
+{
+ u8 i = 0, j = 0;
+ u8 temp = 0;
+ u8 ch_no = 0;
+ ch_content += 3;
+ ch_cnt -= 3;
+
+ while (ch_cnt > 0) {
+ ch_content += 1;
+ ch_cnt -= 1;
+ temp = *ch_content;
+ for (i = 0 ; i < temp ; i++, j++)
+ peer_ch_list[j] = *(ch_content + 1 + i);
+ ch_content += (temp + 1);
+ ch_cnt -= (temp + 1);
+ ch_no += temp ;
+ }
+
+ return ch_no;
+}
+
+static u8 rtw_p2p_ch_inclusion(struct mlme_ext_priv *pmlmeext, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned)
+{
+ int i = 0, j = 0, temp = 0;
+ u8 ch_no = 0;
+
+ for (i = 0; i < peer_ch_num; i++) {
+ for (j = temp; j < pmlmeext->max_chan_nums; j++) {
+ if (*(peer_ch_list + i) == pmlmeext->channel_set[j].ChannelNum) {
+ ch_list_inclusioned[ch_no++] = *(peer_ch_list + i);
+ temp = j;
+ break;
+ }
+ }
+ }
+
+ return ch_no;
+}
+
+u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+ struct adapter *padapter = pwdinfo->padapter;
+ u8 result = P2P_STATUS_SUCCESS;
+ u32 p2p_ielen = 0, wps_ielen = 0;
+ u8 *ies;
+ u32 ies_len;
+ u8 *p2p_ie;
+ u8 *wpsie;
+ u16 wps_devicepassword_id = 0x0000;
+ uint wps_devicepassword_id_len = 0;
+ __be16 be_tmp;
+
+ wpsie = rtw_get_wps_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen);
+ if (wpsie) {
+ /* Commented by Kurt 20120113 */
+ /* If some device wants to do p2p handshake without sending prov_disc_req */
+ /* We have to get peer_req_cm from here. */
+ if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
+ rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8 *)&be_tmp, &wps_devicepassword_id_len);
+ wps_devicepassword_id = be16_to_cpu(be_tmp);
+
+ if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
+ else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
+ else
+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
+ }
+ } else {
+ DBG_88E("[%s] WPS IE not Found!!\n", __func__);
+ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+ return result;
+ }
+
+ if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO) {
+ result = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INFOR_NOREADY);
+ return result;
+ }
+
+ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
+ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
+
+ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
+
+ if (!p2p_ie) {
+ DBG_88E("[%s] P2P IE not Found!!\n", __func__);
+ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+ }
+
+ while (p2p_ie) {
+ u8 attr_content = 0x00;
+ u32 attr_contentlen = 0;
+ u8 ch_content[50] = { 0x00 };
+ uint ch_cnt = 0;
+ u8 peer_ch_list[50] = { 0x00 };
+ u8 peer_ch_num = 0;
+ u8 ch_list_inclusioned[50] = { 0x00 };
+ u8 ch_num_inclusioned = 0;
+
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING);
+
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen)) {
+ DBG_88E("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01);
+ pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */
+
+ if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) {
+ /* Try to match the tie breaker value */
+ if (pwdinfo->intent == P2P_MAX_INTENT) {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ result = P2P_STATUS_FAIL_BOTH_GOINTENT_15;
+ } else {
+ if (attr_content & 0x01)
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ else
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ }
+ } else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ } else {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ }
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ /* Store the group id information. */
+ memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN);
+ memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
+ }
+ }
+
+
+ attr_contentlen = 0;
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) {
+ if (attr_contentlen != ETH_ALEN)
+ _rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
+ }
+
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt)) {
+ peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list);
+ ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned);
+
+ if (ch_num_inclusioned == 0) {
+ DBG_88E("[%s] No common channel in channel list!\n", __func__);
+ result = P2P_STATUS_FAIL_NO_COMMON_CH;
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+ break;
+ }
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel,
+ ch_list_inclusioned, ch_num_inclusioned)) {
+ u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0;
+ attr_contentlen = 0;
+
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
+ peer_operating_ch = operatingch_info[4];
+
+ if (rtw_p2p_is_channel_list_ok(peer_operating_ch,
+ ch_list_inclusioned, ch_num_inclusioned)) {
+ /**
+ * Change our operating channel as peer's for compatibility.
+ */
+ pwdinfo->operating_channel = peer_operating_ch;
+ DBG_88E("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel);
+ } else {
+ /* Take first channel of ch_list_inclusioned as operating channel */
+ pwdinfo->operating_channel = ch_list_inclusioned[0];
+ DBG_88E("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel);
+ }
+ }
+ }
+ }
+
+ /* Get the next P2P IE */
+ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
+ }
+ return result;
+}
+
+u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+ struct adapter *padapter = pwdinfo->padapter;
+ u8 result = P2P_STATUS_SUCCESS;
+ u32 p2p_ielen, wps_ielen;
+ u8 *ies;
+ u32 ies_len;
+ u8 *p2p_ie;
+
+ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
+ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
+
+ /* Be able to know which one is the P2P GO and which one is P2P client. */
+
+ if (rtw_get_wps_ie(ies, ies_len, NULL, &wps_ielen)) {
+ } else {
+ DBG_88E("[%s] WPS IE not Found!!\n", __func__);
+ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+ }
+
+ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
+ if (!p2p_ie) {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+ } else {
+ u8 attr_content = 0x00;
+ u32 attr_contentlen = 0;
+ u8 operatingch_info[5] = { 0x00 };
+ u8 groupid[38];
+ u8 peer_ch_list[50] = { 0x00 };
+ u8 peer_ch_num = 0;
+ u8 ch_list_inclusioned[50] = { 0x00 };
+ u8 ch_num_inclusioned = 0;
+
+ while (p2p_ie) { /* Found the P2P IE. */
+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
+ if (attr_contentlen == 1) {
+ DBG_88E("[%s] Status = %d\n", __func__, attr_content);
+ if (attr_content == P2P_STATUS_SUCCESS) {
+ /* Do nothing. */
+ } else {
+ if (P2P_STATUS_FAIL_INFO_UNAVAILABLE == attr_content) {
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INFOR_NOREADY);
+ } else {
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+ }
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ result = attr_content;
+ break;
+ }
+ }
+
+ /* Try to get the peer's interface address */
+ attr_contentlen = 0;
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) {
+ if (attr_contentlen != ETH_ALEN)
+ _rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
+ }
+
+ /* Try to get the peer's intent and tie breaker value. */
+ attr_content = 0x00;
+ attr_contentlen = 0;
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen)) {
+ DBG_88E("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01);
+ pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */
+
+ if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) {
+ /* Try to match the tie breaker value */
+ if (pwdinfo->intent == P2P_MAX_INTENT) {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ result = P2P_STATUS_FAIL_BOTH_GOINTENT_15;
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+ } else {
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ if (attr_content & 0x01)
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ else
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ }
+ } else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) {
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ } else {
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ }
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ /* Store the group id information. */
+ memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN);
+ memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
+ }
+ }
+
+ /* Try to get the operation channel information */
+
+ attr_contentlen = 0;
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) {
+ DBG_88E("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]);
+ pwdinfo->peer_operating_ch = operatingch_info[4];
+ }
+
+ /* Try to get the channel list information */
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, pwdinfo->channel_list_attr, &pwdinfo->channel_list_attr_len)) {
+ DBG_88E("[%s] channel list attribute found, len = %d\n", __func__, pwdinfo->channel_list_attr_len);
+
+ peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list);
+ ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned);
+
+ if (ch_num_inclusioned == 0) {
+ DBG_88E("[%s] No common channel in channel list!\n", __func__);
+ result = P2P_STATUS_FAIL_NO_COMMON_CH;
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+ break;
+ }
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel,
+ ch_list_inclusioned, ch_num_inclusioned)) {
+ u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0;
+ attr_contentlen = 0;
+
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
+ peer_operating_ch = operatingch_info[4];
+
+ if (rtw_p2p_is_channel_list_ok(peer_operating_ch,
+ ch_list_inclusioned, ch_num_inclusioned)) {
+ /**
+ * Change our operating channel as peer's for compatibility.
+ */
+ pwdinfo->operating_channel = peer_operating_ch;
+ DBG_88E("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel);
+ } else {
+ /* Take first channel of ch_list_inclusioned as operating channel */
+ pwdinfo->operating_channel = ch_list_inclusioned[0];
+ DBG_88E("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel);
+ }
+ }
+ }
+ } else {
+ DBG_88E("[%s] channel list attribute not found!\n", __func__);
+ }
+
+ /* Try to get the group id information if peer is GO */
+ attr_contentlen = 0;
+ _rtw_memset(groupid, 0x00, 38);
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) {
+ memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN);
+ memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN);
+ }
+
+ /* Get the next P2P IE */
+ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
+ }
+ }
+ return result;
+}
+
+u8 process_p2p_group_negotation_confirm(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+ u8 *ies;
+ u32 ies_len;
+ u8 *p2p_ie;
+ u32 p2p_ielen = 0;
+ u8 result = P2P_STATUS_SUCCESS;
+ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
+ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
+
+ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
+ while (p2p_ie) { /* Found the P2P IE. */
+ u8 attr_content = 0x00, operatingch_info[5] = { 0x00 };
+ u8 groupid[38] = { 0x00 };
+ u32 attr_contentlen = 0;
+
+ pwdinfo->negotiation_dialog_token = 1;
+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
+ if (attr_contentlen == 1) {
+ DBG_88E("[%s] Status = %d\n", __func__, attr_content);
+ result = attr_content;
+
+ if (attr_content == P2P_STATUS_SUCCESS) {
+ u8 bcancelled = 0;
+
+ _cancel_timer(&pwdinfo->restore_p2p_state_timer, &bcancelled);
+
+ /* Commented by Albert 20100911 */
+ /* Todo: Need to handle the case which both Intents are the same. */
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ if ((pwdinfo->intent) > (pwdinfo->peer_intent >> 1)) {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ } else if ((pwdinfo->intent) < (pwdinfo->peer_intent >> 1)) {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ } else {
+ /* Have to compare the Tie Breaker */
+ if (pwdinfo->peer_intent & 0x01)
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ else
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ }
+ } else {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+ break;
+ }
+ }
+
+ /* Try to get the group id information */
+ attr_contentlen = 0;
+ _rtw_memset(groupid, 0x00, 38);
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) {
+ DBG_88E("[%s] Ssid = %s, ssidlen = %zu\n", __func__, &groupid[ETH_ALEN], strlen(&groupid[ETH_ALEN]));
+ memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN);
+ memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN);
+ }
+
+ attr_contentlen = 0;
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) {
+ DBG_88E("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]);
+ pwdinfo->peer_operating_ch = operatingch_info[4];
+ }
+
+ /* Get the next P2P IE */
+ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
+ }
+ return result;
+}
+
+u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+ u8 *frame_body;
+ u8 dialogToken = 0;
+ u8 status = P2P_STATUS_SUCCESS;
+
+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+ dialogToken = frame_body[6];
+
+ /* todo: check NoA attribute */
+
+ issue_p2p_presence_resp(pwdinfo, GetAddr2Ptr(pframe), status, dialogToken);
+
+ return true;
+}
+
+static void find_phase_handler(struct adapter *padapter)
+{
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct ndis_802_11_ssid ssid;
+ unsigned long irqL;
+
+_func_enter_;
+
+ _rtw_memset((unsigned char *)&ssid, 0, sizeof(struct ndis_802_11_ssid));
+ memcpy(ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN);
+ ssid.SsidLength = P2P_WILDCARD_SSID_LEN;
+
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+
+_func_exit_;
+}
+
+void p2p_concurrent_handler(struct adapter *padapter);
+
+static void restore_p2p_state_handler(struct adapter *padapter)
+{
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+_func_enter_;
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
+ /* In the P2P client mode, the driver should not switch back to its listen channel */
+ /* because this P2P client should stay at the operating channel of P2P GO. */
+ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+ }
+_func_exit_;
+}
+
+static void pre_tx_invitereq_handler(struct adapter *padapter)
+{
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+ u8 val8 = 1;
+_func_enter_;
+
+ set_channel_bwmode(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+ issue_probereq_p2p(padapter, NULL);
+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+_func_exit_;
+}
+
+static void pre_tx_provdisc_handler(struct adapter *padapter)
+{
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+ u8 val8 = 1;
+_func_enter_;
+
+ set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+ issue_probereq_p2p(padapter, NULL);
+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+_func_exit_;
+}
+
+static void pre_tx_negoreq_handler(struct adapter *padapter)
+{
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+ u8 val8 = 1;
+_func_enter_;
+
+ set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+ issue_probereq_p2p(padapter, NULL);
+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+_func_exit_;
+}
+
+void p2p_protocol_wk_hdl(struct adapter *padapter, int intCmdType)
+{
+_func_enter_;
+ switch (intCmdType) {
+ case P2P_FIND_PHASE_WK:
+ find_phase_handler(padapter);
+ break;
+ case P2P_RESTORE_STATE_WK:
+ restore_p2p_state_handler(padapter);
+ break;
+ case P2P_PRE_TX_PROVDISC_PROCESS_WK:
+ pre_tx_provdisc_handler(padapter);
+ break;
+ case P2P_PRE_TX_INVITEREQ_PROCESS_WK:
+ pre_tx_invitereq_handler(padapter);
+ break;
+ case P2P_PRE_TX_NEGOREQ_PROCESS_WK:
+ pre_tx_negoreq_handler(padapter);
+ break;
+ }
+
+_func_exit_;
+}
+
+void process_p2p_ps_ie(struct adapter *padapter, u8 *IEs, u32 IELength)
+{
+ u8 *ies;
+ u32 ies_len;
+ u8 *p2p_ie;
+ u32 p2p_ielen = 0;
+ u8 noa_attr[MAX_P2P_IE_LEN] = { 0x00 };/* NoA length should be n*(13) + 2 */
+ u32 attr_contentlen = 0;
+
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 find_p2p = false, find_p2p_ps = false;
+ u8 noa_offset, noa_num, noa_index;
+
+_func_enter_;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ return;
+ if (IELength <= _BEACON_IE_OFFSET_)
+ return;
+
+ ies = IEs + _BEACON_IE_OFFSET_;
+ ies_len = IELength - _BEACON_IE_OFFSET_;
+
+ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
+
+ while (p2p_ie) {
+ find_p2p = true;
+ /* Get Notice of Absence IE. */
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_NOA, noa_attr, &attr_contentlen)) {
+ find_p2p_ps = true;
+ noa_index = noa_attr[0];
+
+ if ((pwdinfo->p2p_ps_mode == P2P_PS_NONE) ||
+ (noa_index != pwdinfo->noa_index)) { /* if index change, driver should reconfigure related setting. */
+ pwdinfo->noa_index = noa_index;
+ pwdinfo->opp_ps = noa_attr[1] >> 7;
+ pwdinfo->ctwindow = noa_attr[1] & 0x7F;
+
+ noa_offset = 2;
+ noa_num = 0;
+ /* NoA length should be n*(13) + 2 */
+ if (attr_contentlen > 2) {
+ while (noa_offset < attr_contentlen) {
+ /* memcpy(&wifidirect_info->noa_count[noa_num], &noa_attr[noa_offset], 1); */
+ pwdinfo->noa_count[noa_num] = noa_attr[noa_offset];
+ noa_offset += 1;
+
+ memcpy(&pwdinfo->noa_duration[noa_num], &noa_attr[noa_offset], 4);
+ noa_offset += 4;
+
+ memcpy(&pwdinfo->noa_interval[noa_num], &noa_attr[noa_offset], 4);
+ noa_offset += 4;
+
+ memcpy(&pwdinfo->noa_start_time[noa_num], &noa_attr[noa_offset], 4);
+ noa_offset += 4;
+
+ noa_num++;
+ }
+ }
+ pwdinfo->noa_num = noa_num;
+
+ if (pwdinfo->opp_ps == 1) {
+ pwdinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
+ /* driver should wait LPS for entering CTWindow */
+ if (padapter->pwrctrlpriv.bFwCurrentInPSMode)
+ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1);
+ } else if (pwdinfo->noa_num > 0) {
+ pwdinfo->p2p_ps_mode = P2P_PS_NOA;
+ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1);
+ } else if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
+ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
+ }
+ }
+
+ break; /* find target, just break. */
+ }
+
+ /* Get the next P2P IE */
+ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
+ }
+
+ if (find_p2p) {
+ if ((pwdinfo->p2p_ps_mode > P2P_PS_NONE) && !find_p2p_ps)
+ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
+ }
+
+_func_exit_;
+}
+
+void p2p_ps_wk_hdl(struct adapter *padapter, u8 p2p_ps_state)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+_func_enter_;
+
+ /* Pre action for p2p state */
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ pwdinfo->p2p_ps_state = p2p_ps_state;
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
+
+ pwdinfo->noa_index = 0;
+ pwdinfo->ctwindow = 0;
+ pwdinfo->opp_ps = 0;
+ pwdinfo->noa_num = 0;
+ pwdinfo->p2p_ps_mode = P2P_PS_NONE;
+ if (padapter->pwrctrlpriv.bFwCurrentInPSMode) {
+ if (pwrpriv->smart_ps == 0) {
+ pwrpriv->smart_ps = 2;
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(padapter->pwrctrlpriv.pwr_mode)));
+ }
+ }
+ break;
+ case P2P_PS_ENABLE:
+ if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
+ pwdinfo->p2p_ps_state = p2p_ps_state;
+
+ if (pwdinfo->ctwindow > 0) {
+ if (pwrpriv->smart_ps != 0) {
+ pwrpriv->smart_ps = 0;
+ DBG_88E("%s(): Enter CTW, change SmartPS\n", __func__);
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(padapter->pwrctrlpriv.pwr_mode)));
+ }
+ }
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
+ }
+ break;
+ case P2P_PS_SCAN:
+ case P2P_PS_SCAN_DONE:
+ case P2P_PS_ALLSTASLEEP:
+ if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
+ pwdinfo->p2p_ps_state = p2p_ps_state;
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
+ }
+ break;
+ default:
+ break;
+ }
+
+_func_exit_;
+}
+
+u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+_func_enter_;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ return res;
+
+ if (enqueue) {
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+ if (pdrvextra_cmd_parm == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = P2P_PS_WK_CID;
+ pdrvextra_cmd_parm->type_size = p2p_ps_state;
+ pdrvextra_cmd_parm->pbuf = NULL;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+ } else {
+ p2p_ps_wk_hdl(padapter, p2p_ps_state);
+ }
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+static void reset_ch_sitesurvey_timer_process (void *FunctionContext)
+{
+ struct adapter *adapter = (struct adapter *)FunctionContext;
+ struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ return;
+
+ DBG_88E("[%s] In\n", __func__);
+ /* Reset the operation channel information */
+ pwdinfo->rx_invitereq_info.operation_ch[0] = 0;
+ pwdinfo->rx_invitereq_info.scan_op_ch_only = 0;
+}
+
+static void reset_ch_sitesurvey_timer_process2 (void *FunctionContext)
+{
+ struct adapter *adapter = (struct adapter *)FunctionContext;
+ struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ return;
+
+ DBG_88E("[%s] In\n", __func__);
+ /* Reset the operation channel information */
+ pwdinfo->p2p_info.operation_ch[0] = 0;
+ pwdinfo->p2p_info.scan_op_ch_only = 0;
+}
+
+static void restore_p2p_state_timer_process (void *FunctionContext)
+{
+ struct adapter *adapter = (struct adapter *)FunctionContext;
+ struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ return;
+
+ p2p_protocol_wk_cmd(adapter, P2P_RESTORE_STATE_WK);
+}
+
+static void pre_tx_scan_timer_process(void *FunctionContext)
+{
+ struct adapter *adapter = (struct adapter *)FunctionContext;
+ struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+ unsigned long irqL;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ return;
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
+ if (pwdinfo->tx_prov_disc_info.benable) { /* the provision discovery request frame is trigger to send or not */
+ p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_PROVDISC_PROCESS_WK);
+ /* issue_probereq_p2p(adapter, NULL); */
+ /* _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); */
+ }
+ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
+ if (pwdinfo->nego_req_info.benable)
+ p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_NEGOREQ_PROCESS_WK);
+ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) {
+ if (pwdinfo->invitereq_info.benable)
+ p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_INVITEREQ_PROCESS_WK);
+ } else {
+ DBG_88E("[%s] p2p_state is %d, ignore!!\n", __func__, rtw_p2p_state(pwdinfo));
+ }
+
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+}
+
+static void find_phase_timer_process(void *FunctionContext)
+{
+ struct adapter *adapter = (struct adapter *)FunctionContext;
+ struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ return;
+
+ adapter->wdinfo.find_phase_state_exchange_cnt++;
+
+ p2p_protocol_wk_cmd(adapter, P2P_FIND_PHASE_WK);
+}
+
+void reset_global_wifidirect_info(struct adapter *padapter)
+{
+ struct wifidirect_info *pwdinfo;
+
+ pwdinfo = &padapter->wdinfo;
+ pwdinfo->persistent_supported = 0;
+ pwdinfo->session_available = true;
+ pwdinfo->wfd_tdls_enable = 0;
+ pwdinfo->wfd_tdls_weaksec = 0;
+}
+
+void rtw_init_wifidirect_timers(struct adapter *padapter)
+{
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+ _init_timer(&pwdinfo->find_phase_timer, padapter->pnetdev, find_phase_timer_process, padapter);
+ _init_timer(&pwdinfo->restore_p2p_state_timer, padapter->pnetdev, restore_p2p_state_timer_process, padapter);
+ _init_timer(&pwdinfo->pre_tx_scan_timer, padapter->pnetdev, pre_tx_scan_timer_process, padapter);
+ _init_timer(&pwdinfo->reset_ch_sitesurvey, padapter->pnetdev, reset_ch_sitesurvey_timer_process, padapter);
+ _init_timer(&pwdinfo->reset_ch_sitesurvey2, padapter->pnetdev, reset_ch_sitesurvey_timer_process2, padapter);
+}
+
+void rtw_init_wifidirect_addrs(struct adapter *padapter, u8 *dev_addr, u8 *iface_addr)
+{
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+ /*init device&interface address */
+ if (dev_addr)
+ memcpy(pwdinfo->device_addr, dev_addr, ETH_ALEN);
+ if (iface_addr)
+ memcpy(pwdinfo->interface_addr, iface_addr, ETH_ALEN);
+#endif
+}
+
+void init_wifidirect_info(struct adapter *padapter, enum P2P_ROLE role)
+{
+ struct wifidirect_info *pwdinfo;
+
+ pwdinfo = &padapter->wdinfo;
+ pwdinfo->padapter = padapter;
+
+ /* 1, 6, 11 are the social channel defined in the WiFi Direct specification. */
+ pwdinfo->social_chan[0] = 1;
+ pwdinfo->social_chan[1] = 6;
+ pwdinfo->social_chan[2] = 11;
+ pwdinfo->social_chan[3] = 0; /* channel 0 for scanning ending in site survey function. */
+
+ /* Use the channel 11 as the listen channel */
+ pwdinfo->listen_channel = 11;
+
+ if (role == P2P_ROLE_DEVICE) {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
+ pwdinfo->intent = 1;
+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_LISTEN);
+ } else if (role == P2P_ROLE_CLIENT) {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ pwdinfo->intent = 1;
+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ } else if (role == P2P_ROLE_GO) {
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ pwdinfo->intent = 15;
+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ }
+
+/* Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */
+ pwdinfo->support_rate[0] = 0x8c; /* 6(B) */
+ pwdinfo->support_rate[1] = 0x92; /* 9(B) */
+ pwdinfo->support_rate[2] = 0x18; /* 12 */
+ pwdinfo->support_rate[3] = 0x24; /* 18 */
+ pwdinfo->support_rate[4] = 0x30; /* 24 */
+ pwdinfo->support_rate[5] = 0x48; /* 36 */
+ pwdinfo->support_rate[6] = 0x60; /* 48 */
+ pwdinfo->support_rate[7] = 0x6c; /* 54 */
+
+ memcpy(pwdinfo->p2p_wildcard_ssid, "DIRECT-", 7);
+
+ _rtw_memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN);
+ pwdinfo->device_name_len = 0;
+
+ _rtw_memset(&pwdinfo->invitereq_info, 0x00, sizeof(struct tx_invite_req_info));
+ pwdinfo->invitereq_info.token = 3; /* Token used for P2P invitation request frame. */
+
+ _rtw_memset(&pwdinfo->inviteresp_info, 0x00, sizeof(struct tx_invite_resp_info));
+ pwdinfo->inviteresp_info.token = 0;
+
+ pwdinfo->profileindex = 0;
+ _rtw_memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM);
+
+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
+
+ pwdinfo->listen_dwell = (u8) ((rtw_get_current_time() % 3) + 1);
+
+ _rtw_memset(&pwdinfo->tx_prov_disc_info, 0x00, sizeof(struct tx_provdisc_req_info));
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_NONE;
+
+ _rtw_memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info));
+
+ pwdinfo->device_password_id_for_nego = WPS_DPID_PBC;
+ pwdinfo->negotiation_dialog_token = 1;
+
+ _rtw_memset(pwdinfo->nego_ssid, 0x00, WLAN_SSID_MAXLEN);
+ pwdinfo->nego_ssidlen = 0;
+
+ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO;
+ pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC | WPS_CONFIG_METHOD_KEYPAD;
+ pwdinfo->channel_list_attr_len = 0;
+ _rtw_memset(pwdinfo->channel_list_attr, 0x00, 100);
+
+ _rtw_memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, 0x00, 4);
+ _rtw_memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, '0', 3);
+ _rtw_memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
+ pwdinfo->wfd_tdls_enable = 0;
+ _rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
+ _rtw_memset(pwdinfo->p2p_peer_device_addr, 0x00, ETH_ALEN);
+
+ pwdinfo->rx_invitereq_info.operation_ch[0] = 0;
+ pwdinfo->rx_invitereq_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */
+ pwdinfo->rx_invitereq_info.scan_op_ch_only = 0;
+ pwdinfo->p2p_info.operation_ch[0] = 0;
+ pwdinfo->p2p_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */
+ pwdinfo->p2p_info.scan_op_ch_only = 0;
+}
+
+int rtw_p2p_enable(struct adapter *padapter, enum P2P_ROLE role)
+{
+ int ret = _SUCCESS;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT || role == P2P_ROLE_GO) {
+ /* leave IPS/Autosuspend */
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* Added by Albert 2011/03/22 */
+ /* In the P2P mode, the driver should not support the b mode. */
+ /* So, the Tx packet shouldn't use the CCK rate */
+ update_tx_basic_rate(padapter, WIRELESS_11AGN);
+
+ /* Enable P2P function */
+ init_wifidirect_info(padapter, role);
+
+ rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, true);
+ } else if (role == P2P_ROLE_DISABLE) {
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* Disable P2P function */
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ _cancel_timer_ex(&pwdinfo->find_phase_timer);
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ _cancel_timer_ex(&pwdinfo->pre_tx_scan_timer);
+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey2);
+ reset_ch_sitesurvey_timer_process(padapter);
+ reset_ch_sitesurvey_timer_process2(padapter);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE);
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DISABLE);
+ _rtw_memset(&pwdinfo->rx_prov_disc_info, 0x00, sizeof(struct rx_provdisc_req_info));
+ }
+
+ rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, false);
+
+ /* Restore to initial setting. */
+ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode);
+ }
+
+exit:
+ return ret;
+}
+
+#else
+u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue)
+{
+ return _FAIL;
+}
+
+void process_p2p_ps_ie(struct adapter *padapter, u8 *IEs, u32 IELength)
+{
+}
+
+#endif /* CONFIG_88EU_P2P */
diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
new file mode 100644
index 00000000000..58a1661f5a8
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
@@ -0,0 +1,662 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_PWRCTRL_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <osdep_intf.h>
+#include <linux/usb.h>
+
+void ips_enter(struct adapter *padapter)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct xmit_priv *pxmit_priv = &padapter->xmitpriv;
+
+ if (padapter->registrypriv.mp_mode == 1)
+ return;
+
+ if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF ||
+ pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) {
+ DBG_88E_LEVEL(_drv_info_, "There are some pkts to transmit\n");
+ DBG_88E_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n",
+ pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt);
+ return;
+ }
+
+ _enter_pwrlock(&pwrpriv->lock);
+
+ pwrpriv->bips_processing = true;
+
+ /* syn ips_mode with request */
+ pwrpriv->ips_mode = pwrpriv->ips_mode_req;
+
+ pwrpriv->ips_enter_cnts++;
+ DBG_88E("==>ips_enter cnts:%d\n", pwrpriv->ips_enter_cnts);
+ if (rf_off == pwrpriv->change_rfpwrstate) {
+ pwrpriv->bpower_saving = true;
+ DBG_88E_LEVEL(_drv_info_, "nolinked power save enter\n");
+
+ if (pwrpriv->ips_mode == IPS_LEVEL_2)
+ pwrpriv->bkeepfwalive = true;
+
+ rtw_ips_pwr_down(padapter);
+ pwrpriv->rf_pwrstate = rf_off;
+ }
+ pwrpriv->bips_processing = false;
+
+ _exit_pwrlock(&pwrpriv->lock);
+}
+
+int ips_leave(struct adapter *padapter)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct security_priv *psecuritypriv = &(padapter->securitypriv);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ int result = _SUCCESS;
+ int keyid;
+
+
+ _enter_pwrlock(&pwrpriv->lock);
+
+ if ((pwrpriv->rf_pwrstate == rf_off) && (!pwrpriv->bips_processing)) {
+ pwrpriv->bips_processing = true;
+ pwrpriv->change_rfpwrstate = rf_on;
+ pwrpriv->ips_leave_cnts++;
+ DBG_88E("==>ips_leave cnts:%d\n", pwrpriv->ips_leave_cnts);
+
+ result = rtw_ips_pwr_up(padapter);
+ if (result == _SUCCESS) {
+ pwrpriv->rf_pwrstate = rf_on;
+ }
+ DBG_88E_LEVEL(_drv_info_, "nolinked power save leave\n");
+
+ if ((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) || (_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm)) {
+ DBG_88E("==>%s, channel(%d), processing(%x)\n", __func__, padapter->mlmeextpriv.cur_channel, pwrpriv->bips_processing);
+ set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+ for (keyid = 0; keyid < 4; keyid++) {
+ if (pmlmepriv->key_mask & BIT(keyid)) {
+ if (keyid == psecuritypriv->dot11PrivacyKeyIndex)
+ result = rtw_set_key(padapter, psecuritypriv, keyid, 1);
+ else
+ result = rtw_set_key(padapter, psecuritypriv, keyid, 0);
+ }
+ }
+ }
+
+ DBG_88E("==> ips_leave.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c));
+ pwrpriv->bips_processing = false;
+
+ pwrpriv->bkeepfwalive = false;
+ pwrpriv->bpower_saving = false;
+ }
+
+ _exit_pwrlock(&pwrpriv->lock);
+
+ return result;
+}
+
+static bool rtw_pwr_unassociated_idle(struct adapter *adapter)
+{
+ struct adapter *buddy = adapter->pbuddy_adapter;
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(adapter->wdinfo);
+#endif
+
+ bool ret = false;
+
+ if (adapter->pwrctrlpriv.ips_deny_time >= rtw_get_current_time())
+ goto exit;
+
+ if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) ||
+ check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) ||
+ check_fwstate(pmlmepriv, WIFI_AP_STATE) ||
+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) ||
+#if defined(CONFIG_88EU_P2P)
+ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+#else
+ 0)
+#endif
+ goto exit;
+
+ /* consider buddy, if exist */
+ if (buddy) {
+ struct mlme_priv *b_pmlmepriv = &(buddy->mlmepriv);
+ #ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *b_pwdinfo = &(buddy->wdinfo);
+ #endif
+
+ if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) ||
+ check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) ||
+ check_fwstate(b_pmlmepriv, WIFI_AP_STATE) ||
+ check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) ||
+#if defined(CONFIG_88EU_P2P)
+ !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE))
+#else
+ 0)
+#endif
+ goto exit;
+ }
+ ret = true;
+
+exit:
+ return ret;
+}
+
+void rtw_ps_processor(struct adapter *padapter)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ enum rt_rf_power_state rfpwrstate;
+
+ pwrpriv->ps_processing = true;
+
+ if (pwrpriv->bips_processing)
+ goto exit;
+
+ if (padapter->pwrctrlpriv.bHWPwrPindetect) {
+ rfpwrstate = RfOnOffDetect(padapter);
+ DBG_88E("@@@@- #2 %s==> rfstate:%s\n", __func__, (rfpwrstate == rf_on) ? "rf_on" : "rf_off");
+
+ if (rfpwrstate != pwrpriv->rf_pwrstate) {
+ if (rfpwrstate == rf_off) {
+ pwrpriv->change_rfpwrstate = rf_off;
+ pwrpriv->brfoffbyhw = true;
+ padapter->bCardDisableWOHSM = true;
+ rtw_hw_suspend(padapter);
+ } else {
+ pwrpriv->change_rfpwrstate = rf_on;
+ rtw_hw_resume(padapter);
+ }
+ DBG_88E("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off) ? "rf_off" : "rf_on");
+ }
+ pwrpriv->pwr_state_check_cnts++;
+ }
+
+ if (pwrpriv->ips_mode_req == IPS_NONE)
+ goto exit;
+
+ if (rtw_pwr_unassociated_idle(padapter) == false)
+ goto exit;
+
+ if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) {
+ DBG_88E("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv));
+ pwrpriv->change_rfpwrstate = rf_off;
+
+ ips_enter(padapter);
+ }
+exit:
+ rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+ pwrpriv->ps_processing = false;
+ return;
+}
+
+static void pwr_state_check_handler(void *FunctionContext)
+{
+ struct adapter *padapter = (struct adapter *)FunctionContext;
+ rtw_ps_cmd(padapter);
+}
+
+/*
+ *
+ * Parameters
+ * padapter
+ * pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4
+ *
+ */
+void rtw_set_rpwm(struct adapter *padapter, u8 pslv)
+{
+ u8 rpwm;
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+
+_func_enter_;
+
+ pslv = PS_STATE(pslv);
+
+
+ if (pwrpriv->btcoex_rfon) {
+ if (pslv < PS_STATE_S4)
+ pslv = PS_STATE_S3;
+ }
+
+ if ((pwrpriv->rpwm == pslv)) {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+ ("%s: Already set rpwm[0x%02X], new=0x%02X!\n", __func__, pwrpriv->rpwm, pslv));
+ return;
+ }
+
+ if ((padapter->bSurpriseRemoved) ||
+ (!padapter->hw_init_completed)) {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+ ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n",
+ __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed));
+
+ pwrpriv->cpwm = PS_STATE_S4;
+
+ return;
+ }
+
+ if (padapter->bDriverStopped) {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+ ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv));
+
+ if (pslv < PS_STATE_S2) {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+ ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv));
+ return;
+ }
+ }
+
+ rpwm = pslv | pwrpriv->tog;
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("rtw_set_rpwm: rpwm=0x%02x cpwm=0x%02x\n", rpwm, pwrpriv->cpwm));
+
+ pwrpriv->rpwm = pslv;
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm));
+
+ pwrpriv->tog += 0x80;
+ pwrpriv->cpwm = pslv;
+
+_func_exit_;
+}
+
+static u8 PS_RDY_CHECK(struct adapter *padapter)
+{
+ u32 curr_time, delta_time;
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+
+ curr_time = rtw_get_current_time();
+ delta_time = curr_time - pwrpriv->DelayLPSLastTimeStamp;
+
+ if (delta_time < LPS_DELAY_TIME)
+ return false;
+
+ if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) ||
+ (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ||
+ (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)))
+ return false;
+ if (pwrpriv->bInSuspend)
+ return false;
+ if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false)) {
+ DBG_88E("Group handshake still in progress !!!\n");
+ return false;
+ }
+ return true;
+}
+
+void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+ ("%s: PowerMode=%d Smart_PS=%d\n",
+ __func__, ps_mode, smart_ps));
+
+ if (ps_mode > PM_Card_Disable) {
+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode));
+ return;
+ }
+
+ if (pwrpriv->pwr_mode == ps_mode) {
+ if (PS_MODE_ACTIVE == ps_mode)
+ return;
+
+ if ((pwrpriv->smart_ps == smart_ps) &&
+ (pwrpriv->bcn_ant_mode == bcn_ant_mode))
+ return;
+ }
+
+ /* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */
+ if (ps_mode == PS_MODE_ACTIVE) {
+#ifdef CONFIG_88EU_P2P
+ if (pwdinfo->opp_ps == 0) {
+ DBG_88E("rtw_set_ps_mode: Leave 802.11 power save\n");
+ pwrpriv->pwr_mode = ps_mode;
+ rtw_set_rpwm(padapter, PS_STATE_S4);
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
+ pwrpriv->bFwCurrentInPSMode = false;
+ }
+ } else {
+#endif /* CONFIG_88EU_P2P */
+ if (PS_RDY_CHECK(padapter)) {
+ DBG_88E("%s: Enter 802.11 power save\n", __func__);
+ pwrpriv->bFwCurrentInPSMode = true;
+ pwrpriv->pwr_mode = ps_mode;
+ pwrpriv->smart_ps = smart_ps;
+ pwrpriv->bcn_ant_mode = bcn_ant_mode;
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
+
+#ifdef CONFIG_88EU_P2P
+ /* Set CTWindow after LPS */
+ if (pwdinfo->opp_ps == 1)
+ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 0);
+#endif /* CONFIG_88EU_P2P */
+
+ rtw_set_rpwm(padapter, PS_STATE_S2);
+ }
+ }
+
+_func_exit_;
+}
+
+/*
+ * Return:
+ * 0: Leave OK
+ * -1: Timeout
+ * -2: Other error
+ */
+s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms)
+{
+ u32 start_time;
+ u8 bAwake = false;
+ s32 err = 0;
+
+
+ start_time = rtw_get_current_time();
+ while (1) {
+ rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake);
+ if (bAwake)
+ break;
+
+ if (padapter->bSurpriseRemoved) {
+ err = -2;
+ DBG_88E("%s: device surprise removed!!\n", __func__);
+ break;
+ }
+
+ if (rtw_get_passing_time_ms(start_time) > delay_ms) {
+ err = -1;
+ DBG_88E("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms);
+ break;
+ }
+ rtw_usleep_os(100);
+ }
+
+ return err;
+}
+
+/* */
+/* Description: */
+/* Enter the leisure power save mode. */
+/* */
+void LPS_Enter(struct adapter *padapter)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+
+_func_enter_;
+
+ if (PS_RDY_CHECK(padapter) == false)
+ return;
+
+ if (pwrpriv->bLeisurePs) {
+ /* Idle for a while if we connect to AP a while ago. */
+ if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */
+ if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) {
+ pwrpriv->bpower_saving = true;
+ DBG_88E("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps);
+ /* For Tenda W311R IOT issue */
+ rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, pwrpriv->smart_ps, 0);
+ }
+ } else {
+ pwrpriv->LpsIdleCount++;
+ }
+ }
+
+_func_exit_;
+}
+
+#define LPS_LEAVE_TIMEOUT_MS 100
+
+/* Description: */
+/* Leave the leisure power save mode. */
+void LPS_Leave(struct adapter *padapter)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+
+_func_enter_;
+
+ if (pwrpriv->bLeisurePs) {
+ if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) {
+ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0);
+
+ if (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
+ LPS_RF_ON_check(padapter, LPS_LEAVE_TIMEOUT_MS);
+ }
+ }
+
+ pwrpriv->bpower_saving = false;
+
+_func_exit_;
+}
+
+/* */
+/* Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */
+/* Move code to function by tynli. 2010.03.26. */
+/* */
+void LeaveAllPowerSaveMode(struct adapter *Adapter)
+{
+ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
+ u8 enqueue = 0;
+
+_func_enter_;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) { /* connect */
+ p2p_ps_wk_cmd(Adapter, P2P_PS_DISABLE, enqueue);
+
+ rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue);
+ }
+
+_func_exit_;
+}
+
+void rtw_init_pwrctrl_priv(struct adapter *padapter)
+{
+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+_func_enter_;
+
+ _init_pwrlock(&pwrctrlpriv->lock);
+ pwrctrlpriv->rf_pwrstate = rf_on;
+ pwrctrlpriv->ips_enter_cnts = 0;
+ pwrctrlpriv->ips_leave_cnts = 0;
+ pwrctrlpriv->bips_processing = false;
+
+ pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode;
+ pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode;
+
+ pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL;
+ pwrctrlpriv->pwr_state_check_cnts = 0;
+ pwrctrlpriv->bInternalAutoSuspend = false;
+ pwrctrlpriv->bInSuspend = false;
+ pwrctrlpriv->bkeepfwalive = false;
+
+ pwrctrlpriv->LpsIdleCount = 0;
+ if (padapter->registrypriv.mp_mode == 1)
+ pwrctrlpriv->power_mgnt = PS_MODE_ACTIVE ;
+ else
+ pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */
+ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false;
+
+ pwrctrlpriv->bFwCurrentInPSMode = false;
+
+ pwrctrlpriv->rpwm = 0;
+ pwrctrlpriv->cpwm = PS_STATE_S4;
+
+ pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE;
+ pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps;
+ pwrctrlpriv->bcn_ant_mode = 0;
+
+ pwrctrlpriv->tog = 0x80;
+
+ pwrctrlpriv->btcoex_rfon = false;
+
+ _init_timer(&(pwrctrlpriv->pwr_state_check_timer), padapter->pnetdev, pwr_state_check_handler, (u8 *)padapter);
+
+_func_exit_;
+}
+
+void rtw_free_pwrctrl_priv(struct adapter *adapter)
+{
+ struct pwrctrl_priv *pwrctrlpriv = &adapter->pwrctrlpriv;
+
+_func_enter_;
+
+ _free_pwrlock(&pwrctrlpriv->lock);
+
+_func_exit_;
+}
+
+u8 rtw_interface_ps_func(struct adapter *padapter, enum hal_intf_ps_func efunc_id, u8 *val)
+{
+ u8 bResult = true;
+ rtw_hal_intf_ps_func(padapter, efunc_id, val);
+
+ return bResult;
+}
+
+
+inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ms);
+}
+
+/*
+* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend
+* @adapter: pointer to struct adapter structure
+* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup
+* Return _SUCCESS or _FAIL
+*/
+
+int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *caller)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ int ret = _SUCCESS;
+
+ if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms))
+ pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms);
+
+{
+ u32 start = rtw_get_current_time();
+ if (pwrpriv->ps_processing) {
+ DBG_88E("%s wait ps_processing...\n", __func__);
+ while (pwrpriv->ps_processing && rtw_get_passing_time_ms(start) <= 3000)
+ rtw_msleep_os(10);
+ if (pwrpriv->ps_processing)
+ DBG_88E("%s wait ps_processing timeout\n", __func__);
+ else
+ DBG_88E("%s wait ps_processing done\n", __func__);
+ }
+}
+
+ /* System suspend is not allowed to wakeup */
+ if ((!pwrpriv->bInternalAutoSuspend) && (pwrpriv->bInSuspend)) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* block??? */
+ if ((pwrpriv->bInternalAutoSuspend) && (padapter->net_closed)) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* I think this should be check in IPS, LPS, autosuspend functions... */
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ ret = _SUCCESS;
+ goto exit;
+ }
+ if (rf_off == pwrpriv->rf_pwrstate) {
+ DBG_88E("%s call ips_leave....\n", __func__);
+ if (_FAIL == ips_leave(padapter)) {
+ DBG_88E("======> ips_leave fail.............\n");
+ ret = _FAIL;
+ goto exit;
+ }
+ }
+
+ /* TODO: the following checking need to be merged... */
+ if (padapter->bDriverStopped || !padapter->bup ||
+ !padapter->hw_init_completed) {
+ DBG_88E("%s: bDriverStopped=%d, bup=%d, hw_init_completed =%u\n"
+ , caller
+ , padapter->bDriverStopped
+ , padapter->bup
+ , padapter->hw_init_completed);
+ ret = false;
+ goto exit;
+ }
+
+exit:
+ if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms))
+ pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms);
+ return ret;
+}
+
+int rtw_pm_set_lps(struct adapter *padapter, u8 mode)
+{
+ int ret = 0;
+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+ if (mode < PS_MODE_NUM) {
+ if (pwrctrlpriv->power_mgnt != mode) {
+ if (PS_MODE_ACTIVE == mode)
+ LeaveAllPowerSaveMode(padapter);
+ else
+ pwrctrlpriv->LpsIdleCount = 2;
+ pwrctrlpriv->power_mgnt = mode;
+ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int rtw_pm_set_ips(struct adapter *padapter, u8 mode)
+{
+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+ if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) {
+ rtw_ips_mode_req(pwrctrlpriv, mode);
+ DBG_88E("%s %s\n", __func__, mode == IPS_NORMAL ? "IPS_NORMAL" : "IPS_LEVEL_2");
+ return 0;
+ } else if (mode == IPS_NONE) {
+ rtw_ips_mode_req(pwrctrlpriv, mode);
+ DBG_88E("%s %s\n", __func__, "IPS_NONE");
+ if ((padapter->bSurpriseRemoved == 0) && (_FAIL == rtw_pwr_wakeup(padapter)))
+ return -EFAULT;
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c
new file mode 100644
index 00000000000..20116578736
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_recv.c
@@ -0,0 +1,2299 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_RECV_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <mlme_osdep.h>
+#include <ip.h>
+#include <if_ether.h>
+#include <ethernet.h>
+#include <usb_ops.h>
+#include <wifi.h>
+
+static u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37};
+static u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3};
+
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static u8 rtw_bridge_tunnel_header[] = {
+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8
+};
+
+static u8 rtw_rfc1042_header[] = {
+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00
+};
+
+void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS);
+
+void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv)
+{
+_func_enter_;
+
+ _rtw_memset((u8 *)psta_recvpriv, 0, sizeof (struct sta_recv_priv));
+
+ _rtw_spinlock_init(&psta_recvpriv->lock);
+
+ _rtw_init_queue(&psta_recvpriv->defrag_q);
+
+_func_exit_;
+}
+
+int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter)
+{
+ int i;
+
+ union recv_frame *precvframe;
+
+ int res = _SUCCESS;
+
+_func_enter_;
+ _rtw_spinlock_init(&precvpriv->lock);
+
+ _rtw_init_queue(&precvpriv->free_recv_queue);
+ _rtw_init_queue(&precvpriv->recv_pending_queue);
+ _rtw_init_queue(&precvpriv->uc_swdec_pending_queue);
+
+ precvpriv->adapter = padapter;
+
+ precvpriv->free_recvframe_cnt = NR_RECVFRAME;
+
+ rtw_os_recv_resource_init(precvpriv, padapter);
+
+ precvpriv->pallocated_frame_buf = rtw_zvmalloc(NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ);
+
+ if (precvpriv->pallocated_frame_buf == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ);
+
+ precvframe = (union recv_frame *)precvpriv->precv_frame_buf;
+
+ for (i = 0; i < NR_RECVFRAME; i++) {
+ _rtw_init_listhead(&(precvframe->u.list));
+
+ rtw_list_insert_tail(&(precvframe->u.list), &(precvpriv->free_recv_queue.queue));
+
+ res = rtw_os_recv_resource_alloc(padapter, precvframe);
+
+ precvframe->u.hdr.len = 0;
+
+ precvframe->u.hdr.adapter = padapter;
+ precvframe++;
+ }
+ precvpriv->rx_pending_cnt = 1;
+
+ _rtw_init_sema(&precvpriv->allrxreturnevt, 0);
+
+ res = rtw_hal_init_recv_priv(padapter);
+
+ _init_timer(&precvpriv->signal_stat_timer, padapter->pnetdev, RTW_TIMER_HDL_NAME(signal_stat), padapter);
+
+ precvpriv->signal_stat_sampling_interval = 1000; /* ms */
+
+ rtw_set_signal_stat_timer(precvpriv);
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+static void rtw_mfree_recv_priv_lock(struct recv_priv *precvpriv)
+{
+ _rtw_spinlock_free(&precvpriv->lock);
+ _rtw_spinlock_free(&precvpriv->free_recv_queue.lock);
+ _rtw_spinlock_free(&precvpriv->recv_pending_queue.lock);
+
+ _rtw_spinlock_free(&precvpriv->free_recv_buf_queue.lock);
+}
+
+void _rtw_free_recv_priv (struct recv_priv *precvpriv)
+{
+ struct adapter *padapter = precvpriv->adapter;
+
+_func_enter_;
+
+ rtw_free_uc_swdec_pending_queue(padapter);
+
+ rtw_mfree_recv_priv_lock(precvpriv);
+
+ rtw_os_recv_resource_free(precvpriv);
+
+ if (precvpriv->pallocated_frame_buf) {
+ rtw_vmfree(precvpriv->pallocated_frame_buf, NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ);
+ }
+
+ rtw_hal_free_recv_priv(padapter);
+
+_func_exit_;
+}
+
+union recv_frame *_rtw_alloc_recvframe (struct __queue *pfree_recv_queue)
+{
+ union recv_frame *precvframe;
+ struct list_head *plist, *phead;
+ struct adapter *padapter;
+ struct recv_priv *precvpriv;
+_func_enter_;
+
+ if (_rtw_queue_empty(pfree_recv_queue)) {
+ precvframe = NULL;
+ } else {
+ phead = get_list_head(pfree_recv_queue);
+
+ plist = get_next(phead);
+
+ precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
+
+ rtw_list_delete(&precvframe->u.hdr.list);
+ padapter = precvframe->u.hdr.adapter;
+ if (padapter != NULL) {
+ precvpriv = &padapter->recvpriv;
+ if (pfree_recv_queue == &precvpriv->free_recv_queue)
+ precvpriv->free_recvframe_cnt--;
+ }
+ }
+
+_func_exit_;
+
+ return precvframe;
+}
+
+union recv_frame *rtw_alloc_recvframe (struct __queue *pfree_recv_queue)
+{
+ unsigned long irqL;
+ union recv_frame *precvframe;
+
+ _enter_critical_bh(&pfree_recv_queue->lock, &irqL);
+
+ precvframe = _rtw_alloc_recvframe(pfree_recv_queue);
+
+ _exit_critical_bh(&pfree_recv_queue->lock, &irqL);
+
+ return precvframe;
+}
+
+void rtw_init_recvframe(union recv_frame *precvframe, struct recv_priv *precvpriv)
+{
+ /* Perry: This can be removed */
+ _rtw_init_listhead(&precvframe->u.hdr.list);
+
+ precvframe->u.hdr.len = 0;
+}
+
+int rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_queue)
+{
+ unsigned long irqL;
+ struct adapter *padapter = precvframe->u.hdr.adapter;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+_func_enter_;
+
+ if (precvframe->u.hdr.pkt) {
+ dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */
+ precvframe->u.hdr.pkt = NULL;
+ }
+
+ _enter_critical_bh(&pfree_recv_queue->lock, &irqL);
+
+ rtw_list_delete(&(precvframe->u.hdr.list));
+
+ precvframe->u.hdr.len = 0;
+
+ rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(pfree_recv_queue));
+
+ if (padapter != NULL) {
+ if (pfree_recv_queue == &precvpriv->free_recv_queue)
+ precvpriv->free_recvframe_cnt++;
+ }
+
+ _exit_critical_bh(&pfree_recv_queue->lock, &irqL);
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+int _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue)
+{
+ struct adapter *padapter = precvframe->u.hdr.adapter;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+_func_enter_;
+
+ rtw_list_delete(&(precvframe->u.hdr.list));
+ rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(queue));
+
+ if (padapter != NULL) {
+ if (queue == &precvpriv->free_recv_queue)
+ precvpriv->free_recvframe_cnt++;
+ }
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+int rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue)
+{
+ int ret;
+ unsigned long irqL;
+
+ _enter_critical_bh(&queue->lock, &irqL);
+ ret = _rtw_enqueue_recvframe(precvframe, queue);
+ _exit_critical_bh(&queue->lock, &irqL);
+
+ return ret;
+}
+
+/*
+caller : defrag ; recvframe_chk_defrag in recv_thread (passive)
+pframequeue: defrag_queue : will be accessed in recv_thread (passive)
+
+using spinlock to protect
+
+*/
+
+void rtw_free_recvframe_queue(struct __queue *pframequeue, struct __queue *pfree_recv_queue)
+{
+ union recv_frame *precvframe;
+ struct list_head *plist, *phead;
+
+_func_enter_;
+ spin_lock(&pframequeue->lock);
+
+ phead = get_list_head(pframequeue);
+ plist = get_next(phead);
+
+ while (rtw_end_of_queue_search(phead, plist) == false) {
+ precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
+
+ plist = get_next(plist);
+
+ rtw_free_recvframe(precvframe, pfree_recv_queue);
+ }
+
+ spin_unlock(&pframequeue->lock);
+
+_func_exit_;
+}
+
+u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter)
+{
+ u32 cnt = 0;
+ union recv_frame *pending_frame;
+ while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) {
+ rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue);
+ DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__);
+ cnt++;
+ }
+
+ return cnt;
+}
+
+int rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue)
+{
+ unsigned long irqL;
+
+ _enter_critical_bh(&queue->lock, &irqL);
+
+ rtw_list_delete(&precvbuf->list);
+ rtw_list_insert_head(&precvbuf->list, get_list_head(queue));
+
+ _exit_critical_bh(&queue->lock, &irqL);
+
+ return _SUCCESS;
+}
+
+int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue)
+{
+ unsigned long irqL;
+ _enter_critical_ex(&queue->lock, &irqL);
+
+ rtw_list_delete(&precvbuf->list);
+
+ rtw_list_insert_tail(&precvbuf->list, get_list_head(queue));
+ _exit_critical_ex(&queue->lock, &irqL);
+ return _SUCCESS;
+}
+
+struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue)
+{
+ unsigned long irqL;
+ struct recv_buf *precvbuf;
+ struct list_head *plist, *phead;
+
+ _enter_critical_ex(&queue->lock, &irqL);
+
+ if (_rtw_queue_empty(queue)) {
+ precvbuf = NULL;
+ } else {
+ phead = get_list_head(queue);
+
+ plist = get_next(phead);
+
+ precvbuf = LIST_CONTAINOR(plist, struct recv_buf, list);
+
+ rtw_list_delete(&precvbuf->list);
+ }
+
+ _exit_critical_ex(&queue->lock, &irqL);
+
+ return precvbuf;
+}
+
+static int recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe)
+{
+ int i, res = _SUCCESS;
+ u32 datalen;
+ u8 miccode[8];
+ u8 bmic_err = false, brpt_micerror = true;
+ u8 *pframe, *payload, *pframemic;
+ u8 *mickey;
+ struct sta_info *stainfo;
+ struct rx_pkt_attrib *prxattrib = &precvframe->u.hdr.attrib;
+ struct security_priv *psecuritypriv = &adapter->securitypriv;
+
+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+_func_enter_;
+
+ stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]);
+
+ if (prxattrib->encrypt == _TKIP_) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:prxattrib->encrypt==_TKIP_\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:da=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+ prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5]));
+
+ /* calculate mic code */
+ if (stainfo != NULL) {
+ if (IS_MCAST(prxattrib->ra)) {
+ mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0];
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic: bcmc key\n"));
+
+ if (!psecuritypriv) {
+ res = _FAIL;
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n"));
+ DBG_88E("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n");
+ goto exit;
+ }
+ } else {
+ mickey = &stainfo->dot11tkiprxmickey.skey[0];
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic: unicast key\n"));
+ }
+
+ datalen = precvframe->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len-prxattrib->icv_len-8;/* icv_len included the mic code */
+ pframe = precvframe->u.hdr.rx_data;
+ payload = pframe+prxattrib->hdrlen+prxattrib->iv_len;
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len));
+ rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0],
+ (unsigned char)prxattrib->priority); /* care the length of the data */
+
+ pframemic = payload+datalen;
+
+ bmic_err = false;
+
+ for (i = 0; i < 8; i++) {
+ if (miccode[i] != *(pframemic+i)) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+ ("recvframe_chkmic:miccode[%d](%02x)!=*(pframemic+%d)(%02x) ",
+ i, miccode[i], i, *(pframemic+i)));
+ bmic_err = true;
+ }
+ }
+
+ if (bmic_err) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+ ("\n *(pframemic-8)-*(pframemic-1)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+ *(pframemic-8), *(pframemic-7), *(pframemic-6),
+ *(pframemic-5), *(pframemic-4), *(pframemic-3),
+ *(pframemic-2), *(pframemic-1)));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+ ("\n *(pframemic-16)-*(pframemic-9)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+ *(pframemic-16), *(pframemic-15), *(pframemic-14),
+ *(pframemic-13), *(pframemic-12), *(pframemic-11),
+ *(pframemic-10), *(pframemic-9)));
+ {
+ uint i;
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ======demp packet (len=%d)======\n", precvframe->u.hdr.len));
+ for (i = 0; i < precvframe->u.hdr.len; i = i+8) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x",
+ *(precvframe->u.hdr.rx_data+i), *(precvframe->u.hdr.rx_data+i+1),
+ *(precvframe->u.hdr.rx_data+i+2), *(precvframe->u.hdr.rx_data+i+3),
+ *(precvframe->u.hdr.rx_data+i+4), *(precvframe->u.hdr.rx_data+i+5),
+ *(precvframe->u.hdr.rx_data+i+6), *(precvframe->u.hdr.rx_data+i+7)));
+ }
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ====== demp packet end [len=%d]======\n", precvframe->u.hdr.len));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n hrdlen=%d,\n", prxattrib->hdrlen));
+ }
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+ ("ra=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey=%d ",
+ prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2],
+ prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5], psecuritypriv->binstallGrpkey));
+
+ /* double check key_index for some timing issue , */
+ /* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */
+ if ((IS_MCAST(prxattrib->ra) == true) && (prxattrib->key_index != pmlmeinfo->key_index))
+ brpt_micerror = false;
+
+ if ((prxattrib->bdecrypted) && (brpt_micerror)) {
+ rtw_handle_tkip_mic_err(adapter, (u8)IS_MCAST(prxattrib->ra));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted));
+ DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted);
+ } else {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted));
+ DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted);
+ }
+ res = _FAIL;
+ } else {
+ /* mic checked ok */
+ if ((!psecuritypriv->bcheck_grpkey) && (IS_MCAST(prxattrib->ra))) {
+ psecuritypriv->bcheck_grpkey = true;
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("psecuritypriv->bcheck_grpkey = true"));
+ }
+ }
+ } else {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic: rtw_get_stainfo==NULL!!!\n"));
+ }
+
+ recvframe_pull_tail(precvframe, 8);
+ }
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+/* decrypt and set the ivlen, icvlen of the recv_frame */
+static union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ union recv_frame *return_packet = precv_frame;
+ u32 res = _SUCCESS;
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("prxstat->decrypted=%x prxattrib->encrypt=0x%03x\n", prxattrib->bdecrypted, prxattrib->encrypt));
+
+ if (prxattrib->encrypt > 0) {
+ u8 *iv = precv_frame->u.hdr.rx_data+prxattrib->hdrlen;
+ prxattrib->key_index = (((iv[3])>>6)&0x3);
+
+ if (prxattrib->key_index > WEP_KEYS) {
+ DBG_88E("prxattrib->key_index(%d)>WEP_KEYS\n", prxattrib->key_index);
+
+ switch (prxattrib->encrypt) {
+ case _WEP40_:
+ case _WEP104_:
+ prxattrib->key_index = psecuritypriv->dot11PrivacyKeyIndex;
+ break;
+ case _TKIP_:
+ case _AES_:
+ default:
+ prxattrib->key_index = psecuritypriv->dot118021XGrpKeyid;
+ break;
+ }
+ }
+ }
+
+ if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0) || (psecuritypriv->sw_decrypt))) {
+ psecuritypriv->hw_decrypted = false;
+
+ switch (prxattrib->encrypt) {
+ case _WEP40_:
+ case _WEP104_:
+ rtw_wep_decrypt(padapter, (u8 *)precv_frame);
+ break;
+ case _TKIP_:
+ res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame);
+ break;
+ case _AES_:
+ res = rtw_aes_decrypt(padapter, (u8 *)precv_frame);
+ break;
+ default:
+ break;
+ }
+ } else if (prxattrib->bdecrypted == 1 && prxattrib->encrypt > 0 &&
+ (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_))
+ psecuritypriv->hw_decrypted = true;
+
+ if (res == _FAIL) {
+ rtw_free_recvframe(return_packet, &padapter->recvpriv.free_recv_queue);
+ return_packet = NULL;
+ }
+
+_func_exit_;
+
+ return return_packet;
+}
+
+/* set the security information in the recv_frame */
+static union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_frame)
+{
+ u8 *psta_addr = NULL, *ptr;
+ uint auth_alg;
+ struct recv_frame_hdr *pfhdr;
+ struct sta_info *psta;
+ struct sta_priv *pstapriv;
+ union recv_frame *prtnframe;
+ u16 ether_type = 0;
+ u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */
+ struct rx_pkt_attrib *pattrib;
+ __be16 be_tmp;
+
+_func_enter_;
+
+ pstapriv = &adapter->stapriv;
+ psta = rtw_get_stainfo(pstapriv, psta_addr);
+
+ auth_alg = adapter->securitypriv.dot11AuthAlgrthm;
+
+ ptr = get_recvframe_data(precv_frame);
+ pfhdr = &precv_frame->u.hdr;
+ pattrib = &pfhdr->attrib;
+ psta_addr = pattrib->ta;
+
+ prtnframe = NULL;
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm=%d\n", adapter->securitypriv.dot11AuthAlgrthm));
+
+ if (auth_alg == 2) {
+ if ((psta != NULL) && (psta->ieee8021x_blocked)) {
+ /* blocked */
+ /* only accept EAPOL frame */
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==1\n"));
+
+ prtnframe = precv_frame;
+
+ /* get ether_type */
+ ptr = ptr+pfhdr->attrib.hdrlen+pfhdr->attrib.iv_len+LLC_HEADER_SIZE;
+ memcpy(&be_tmp, ptr, 2);
+ ether_type = ntohs(be_tmp);
+
+ if (ether_type == eapol_type) {
+ prtnframe = precv_frame;
+ } else {
+ /* free this frame */
+ rtw_free_recvframe(precv_frame, &adapter->recvpriv.free_recv_queue);
+ prtnframe = NULL;
+ }
+ } else {
+ /* allowed */
+ /* check decryption status, and decrypt the frame if needed */
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==0\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:precv_frame->hdr.attrib.privacy=%x\n", precv_frame->u.hdr.attrib.privacy));
+
+ if (pattrib->bdecrypted == 0)
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:prxstat->decrypted=%x\n", pattrib->bdecrypted));
+
+ prtnframe = precv_frame;
+ /* check is the EAPOL frame or not (Rekey) */
+ if (ether_type == eapol_type) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########portctrl:ether_type==0x888e\n"));
+ /* check Rekey */
+
+ prtnframe = precv_frame;
+ } else {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:ether_type=0x%04x\n", ether_type));
+ }
+ }
+ } else {
+ prtnframe = precv_frame;
+ }
+
+_func_exit_;
+
+ return prtnframe;
+}
+
+static int recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache)
+{
+ int tid = precv_frame->u.hdr.attrib.priority;
+
+ u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num&0xffff) << 4) |
+ (precv_frame->u.hdr.attrib.frag_num & 0xf);
+
+_func_enter_;
+
+ if (tid > 15) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", seq_ctrl, tid));
+
+ return _FAIL;
+ }
+
+ if (1) {/* if (bretry) */
+ if (seq_ctrl == prxcache->tid_rxseq[tid]) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, seq_ctrl=0x%x, tid=0x%x, tid_rxseq=0x%x\n", seq_ctrl, tid, prxcache->tid_rxseq[tid]));
+
+ return _FAIL;
+ }
+ }
+
+ prxcache->tid_rxseq[tid] = seq_ctrl;
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame);
+void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_AP_MODE
+ unsigned char pwrbit;
+ u8 *ptr = precv_frame->u.hdr.rx_data;
+ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct sta_info *psta = NULL;
+
+ psta = rtw_get_stainfo(pstapriv, pattrib->src);
+
+ pwrbit = GetPwrMgt(ptr);
+
+ if (psta) {
+ if (pwrbit) {
+ if (!(psta->state & WIFI_SLEEP_STATE))
+ stop_sta_xmit(padapter, psta);
+ } else {
+ if (psta->state & WIFI_SLEEP_STATE)
+ wakeup_sta_to_xmit(padapter, psta);
+ }
+ }
+
+#endif
+}
+
+static void process_wmmps_data(struct adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_AP_MODE
+ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct sta_info *psta = NULL;
+
+ psta = rtw_get_stainfo(pstapriv, pattrib->src);
+
+ if (!psta)
+ return;
+
+ if (!psta->qos_option)
+ return;
+
+ if (!(psta->qos_info&0xf))
+ return;
+
+ if (psta->state&WIFI_SLEEP_STATE) {
+ u8 wmmps_ac = 0;
+
+ switch (pattrib->priority) {
+ case 1:
+ case 2:
+ wmmps_ac = psta->uapsd_bk&BIT(1);
+ break;
+ case 4:
+ case 5:
+ wmmps_ac = psta->uapsd_vi&BIT(1);
+ break;
+ case 6:
+ case 7:
+ wmmps_ac = psta->uapsd_vo&BIT(1);
+ break;
+ case 0:
+ case 3:
+ default:
+ wmmps_ac = psta->uapsd_be&BIT(1);
+ break;
+ }
+
+ if (wmmps_ac) {
+ if (psta->sleepq_ac_len > 0) {
+ /* process received triggered frame */
+ xmit_delivery_enabled_frames(padapter, psta);
+ } else {
+ /* issue one qos null frame with More data bit = 0 and the EOSP bit set (= 1) */
+ issue_qos_nulldata(padapter, psta->hwaddr, (u16)pattrib->priority, 0, 0);
+ }
+ }
+ }
+
+#endif
+}
+
+static void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct sta_info *sta)
+{
+ int sz;
+ struct sta_info *psta = NULL;
+ struct stainfo_stats *pstats = NULL;
+ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+ sz = get_recvframe_len(prframe);
+ precvpriv->rx_bytes += sz;
+
+ padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++;
+
+ if ((!MacAddr_isBcst(pattrib->dst)) && (!IS_MCAST(pattrib->dst)))
+ padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++;
+
+ if (sta)
+ psta = sta;
+ else
+ psta = prframe->u.hdr.psta;
+
+ if (psta) {
+ pstats = &psta->sta_stats;
+
+ pstats->rx_data_pkts++;
+ pstats->rx_bytes += sz;
+ }
+}
+
+int sta2sta_data_frame(
+ struct adapter *adapter,
+ union recv_frame *precv_frame,
+ struct sta_info **psta
+);
+
+int sta2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, struct sta_info **psta)
+{
+ u8 *ptr = precv_frame->u.hdr.rx_data;
+ int ret = _SUCCESS;
+ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct sta_priv *pstapriv = &adapter->stapriv;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ u8 *mybssid = get_bssid(pmlmepriv);
+ u8 *myhwaddr = myid(&adapter->eeprompriv);
+ u8 *sta_addr = NULL;
+ int bmcast = IS_MCAST(pattrib->dst);
+
+_func_enter_;
+
+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
+ /* filter packets that SA is myself or multicast or broadcast */
+ if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n"));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+ _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+ !_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ sta_addr = pattrib->src;
+ } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+ /* For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */
+ if (!_rtw_memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("bssid!=TA under STATION_MODE; drop pkt\n"));
+ ret = _FAIL;
+ goto exit;
+ }
+ sta_addr = pattrib->bssid;
+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ if (bmcast) {
+ /* For AP mode, if DA == MCAST, then BSSID should be also MCAST */
+ if (!IS_MCAST(pattrib->bssid)) {
+ ret = _FAIL;
+ goto exit;
+ }
+ } else { /* not mc-frame */
+ /* For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID */
+ if (!_rtw_memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ sta_addr = pattrib->src;
+ }
+ } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
+ memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
+ memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN);
+ memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+
+ sta_addr = mybssid;
+ } else {
+ ret = _FAIL;
+ }
+
+ if (bmcast)
+ *psta = rtw_get_bcmc_stainfo(adapter);
+ else
+ *psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */
+
+ if (*psta == NULL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n"));
+ if (adapter->registrypriv.mp_mode == 1) {
+ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)
+ adapter->mppriv.rx_pktloss++;
+ }
+ ret = _FAIL;
+ goto exit;
+ }
+
+exit:
+_func_exit_;
+ return ret;
+}
+
+static int ap2sta_data_frame (
+ struct adapter *adapter,
+ union recv_frame *precv_frame,
+ struct sta_info **psta)
+{
+ u8 *ptr = precv_frame->u.hdr.rx_data;
+ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ int ret = _SUCCESS;
+ struct sta_priv *pstapriv = &adapter->stapriv;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ u8 *mybssid = get_bssid(pmlmepriv);
+ u8 *myhwaddr = myid(&adapter->eeprompriv);
+ int bmcast = IS_MCAST(pattrib->dst);
+
+_func_enter_;
+
+ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) &&
+ (check_fwstate(pmlmepriv, _FW_LINKED) == true ||
+ check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) {
+ /* filter packets that SA is myself or multicast or broadcast */
+ if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n"));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* da should be for me */
+ if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+ (" ap2sta_data_frame: compare DA fail; DA=%pM\n", (pattrib->dst)));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* check BSSID */
+ if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+ _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+ (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN))) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+ (" ap2sta_data_frame: compare BSSID fail ; BSSID=%pM\n", (pattrib->bssid)));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid=%pM\n", (mybssid)));
+
+ if (!bmcast) {
+ DBG_88E("issue_deauth to the nonassociated ap=%pM for the reason(7)\n", (pattrib->bssid));
+ issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ }
+
+ ret = _FAIL;
+ goto exit;
+ }
+
+ if (bmcast)
+ *psta = rtw_get_bcmc_stainfo(adapter);
+ else
+ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */
+
+ if (*psta == NULL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ap2sta: can't get psta under STATION_MODE ; drop pkt\n"));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { */
+ /* */
+
+ if (GetFrameSubType(ptr) & BIT(6)) {
+ /* No data, will not indicate to upper layer, temporily count it here */
+ count_rx_stats(adapter, precv_frame, *psta);
+ ret = RTW_RX_HANDLED;
+ goto exit;
+ }
+ } else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) &&
+ (check_fwstate(pmlmepriv, _FW_LINKED) == true)) {
+ memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
+ memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN);
+ memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+
+ /* */
+ memcpy(pattrib->bssid, mybssid, ETH_ALEN);
+
+ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
+ if (*psta == NULL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under MP_MODE ; drop pkt\n"));
+ ret = _FAIL;
+ goto exit;
+ }
+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ /* Special case */
+ ret = RTW_RX_HANDLED;
+ goto exit;
+ } else {
+ if (_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) {
+ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
+ if (*psta == NULL) {
+ DBG_88E("issue_deauth to the ap =%pM for the reason(7)\n", (pattrib->bssid));
+
+ issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ }
+ }
+
+ ret = _FAIL;
+ }
+
+exit:
+
+_func_exit_;
+
+ return ret;
+}
+
+static int sta2ap_data_frame(struct adapter *adapter,
+ union recv_frame *precv_frame,
+ struct sta_info **psta)
+{
+ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct sta_priv *pstapriv = &adapter->stapriv;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ u8 *ptr = precv_frame->u.hdr.rx_data;
+ unsigned char *mybssid = get_bssid(pmlmepriv);
+ int ret = _SUCCESS;
+
+_func_enter_;
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
+ /* For AP mode, RA = BSSID, TX = STA(SRC_ADDR), A3 = DST_ADDR */
+ if (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ *psta = rtw_get_stainfo(pstapriv, pattrib->src);
+ if (*psta == NULL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n"));
+ DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src));
+
+ issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+
+ ret = RTW_RX_HANDLED;
+ goto exit;
+ }
+
+ process_pwrbit_data(adapter, precv_frame);
+
+ if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) {
+ process_wmmps_data(adapter, precv_frame);
+ }
+
+ if (GetFrameSubType(ptr) & BIT(6)) {
+ /* No data, will not indicate to upper layer, temporily count it here */
+ count_rx_stats(adapter, precv_frame, *psta);
+ ret = RTW_RX_HANDLED;
+ goto exit;
+ }
+ } else {
+ u8 *myhwaddr = myid(&adapter->eeprompriv);
+ if (!_rtw_memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) {
+ ret = RTW_RX_HANDLED;
+ goto exit;
+ }
+ DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src));
+ issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ ret = RTW_RX_HANDLED;
+ goto exit;
+ }
+
+exit:
+
+_func_exit_;
+
+ return ret;
+}
+
+static int validate_recv_ctrl_frame(struct adapter *padapter,
+ union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_AP_MODE
+ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ u8 *pframe = precv_frame->u.hdr.rx_data;
+ /* uint len = precv_frame->u.hdr.len; */
+
+ if (GetFrameType(pframe) != WIFI_CTRL_TYPE)
+ return _FAIL;
+
+ /* receive the frames that ra(a1) is my address */
+ if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN))
+ return _FAIL;
+
+ /* only handle ps-poll */
+ if (GetFrameSubType(pframe) == WIFI_PSPOLL) {
+ u16 aid;
+ u8 wmmps_ac = 0;
+ struct sta_info *psta = NULL;
+
+ aid = GetAid(pframe);
+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+
+ if ((psta == NULL) || (psta->aid != aid))
+ return _FAIL;
+
+ /* for rx pkt statistics */
+ psta->sta_stats.rx_ctrl_pkts++;
+
+ switch (pattrib->priority) {
+ case 1:
+ case 2:
+ wmmps_ac = psta->uapsd_bk&BIT(0);
+ break;
+ case 4:
+ case 5:
+ wmmps_ac = psta->uapsd_vi&BIT(0);
+ break;
+ case 6:
+ case 7:
+ wmmps_ac = psta->uapsd_vo&BIT(0);
+ break;
+ case 0:
+ case 3:
+ default:
+ wmmps_ac = psta->uapsd_be&BIT(0);
+ break;
+ }
+
+ if (wmmps_ac)
+ return _FAIL;
+
+ if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
+ DBG_88E("%s alive check-rx ps-poll\n", __func__);
+ psta->expire_to = pstapriv->expire_to;
+ psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+ }
+
+ if ((psta->state&WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap&BIT(psta->aid))) {
+ unsigned long irqL;
+ struct list_head *xmitframe_plist, *xmitframe_phead;
+ struct xmit_frame *pxmitframe = NULL;
+
+ _enter_critical_bh(&psta->sleep_q.lock, &irqL);
+
+ xmitframe_phead = get_list_head(&psta->sleep_q);
+ xmitframe_plist = get_next(xmitframe_phead);
+
+ if ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == false) {
+ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+ xmitframe_plist = get_next(xmitframe_plist);
+
+ rtw_list_delete(&pxmitframe->list);
+
+ psta->sleepq_len--;
+
+ if (psta->sleepq_len > 0)
+ pxmitframe->attrib.mdata = 1;
+ else
+ pxmitframe->attrib.mdata = 0;
+
+ pxmitframe->attrib.triggered = 1;
+
+ _exit_critical_bh(&psta->sleep_q.lock, &irqL);
+ if (rtw_hal_xmit(padapter, pxmitframe) == true)
+ rtw_os_xmit_complete(padapter, pxmitframe);
+ _enter_critical_bh(&psta->sleep_q.lock, &irqL);
+
+ if (psta->sleepq_len == 0) {
+ pstapriv->tim_bitmap &= ~BIT(psta->aid);
+
+ /* upate BCN for TIM IE */
+ /* update_BCNTIM(padapter); */
+ update_beacon(padapter, _TIM_IE_, NULL, false);
+ }
+ } else {
+ if (pstapriv->tim_bitmap&BIT(psta->aid)) {
+ if (psta->sleepq_len == 0) {
+ DBG_88E("no buffered packets to xmit\n");
+
+ /* issue nulldata with More data bit = 0 to indicate we have no buffered packets */
+ issue_nulldata(padapter, psta->hwaddr, 0, 0, 0);
+ } else {
+ DBG_88E("error!psta->sleepq_len=%d\n", psta->sleepq_len);
+ psta->sleepq_len = 0;
+ }
+
+ pstapriv->tim_bitmap &= ~BIT(psta->aid);
+
+ /* upate BCN for TIM IE */
+ /* update_BCNTIM(padapter); */
+ update_beacon(padapter, _TIM_IE_, NULL, false);
+ }
+ }
+
+ _exit_critical_bh(&psta->sleep_q.lock, &irqL);
+ }
+ }
+
+#endif
+
+ return _FAIL;
+}
+
+union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_frame *precv_frame);
+
+static int validate_recv_mgnt_frame(struct adapter *padapter,
+ union recv_frame *precv_frame)
+{
+ struct sta_info *psta;
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n"));
+
+ precv_frame = recvframe_chk_defrag(padapter, precv_frame);
+ if (precv_frame == NULL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s: fragment packet\n", __func__));
+ return _SUCCESS;
+ }
+
+ /* for rx pkt statistics */
+ psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(precv_frame->u.hdr.rx_data));
+ if (psta) {
+ psta->sta_stats.rx_mgnt_pkts++;
+ if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_BEACON) {
+ psta->sta_stats.rx_beacon_pkts++;
+ } else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBEREQ) {
+ psta->sta_stats.rx_probereq_pkts++;
+ } else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBERSP) {
+ if (_rtw_memcmp(padapter->eeprompriv.mac_addr, GetAddr1Ptr(precv_frame->u.hdr.rx_data), ETH_ALEN) == true)
+ psta->sta_stats.rx_probersp_pkts++;
+ else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)) ||
+ is_multicast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)))
+ psta->sta_stats.rx_probersp_bm_pkts++;
+ else
+ psta->sta_stats.rx_probersp_uo_pkts++;
+ }
+ }
+
+ mgt_dispatcher(padapter, precv_frame);
+
+ return _SUCCESS;
+}
+
+static int validate_recv_data_frame(struct adapter *adapter,
+ union recv_frame *precv_frame)
+{
+ u8 bretry;
+ u8 *psa, *pda, *pbssid;
+ struct sta_info *psta = NULL;
+ u8 *ptr = precv_frame->u.hdr.rx_data;
+ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct security_priv *psecuritypriv = &adapter->securitypriv;
+ int ret = _SUCCESS;
+
+_func_enter_;
+
+ bretry = GetRetry(ptr);
+ pda = get_da(ptr);
+ psa = get_sa(ptr);
+ pbssid = get_hdr_bssid(ptr);
+
+ if (pbssid == NULL) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ memcpy(pattrib->dst, pda, ETH_ALEN);
+ memcpy(pattrib->src, psa, ETH_ALEN);
+
+ memcpy(pattrib->bssid, pbssid, ETH_ALEN);
+
+ switch (pattrib->to_fr_ds) {
+ case 0:
+ memcpy(pattrib->ra, pda, ETH_ALEN);
+ memcpy(pattrib->ta, psa, ETH_ALEN);
+ ret = sta2sta_data_frame(adapter, precv_frame, &psta);
+ break;
+ case 1:
+ memcpy(pattrib->ra, pda, ETH_ALEN);
+ memcpy(pattrib->ta, pbssid, ETH_ALEN);
+ ret = ap2sta_data_frame(adapter, precv_frame, &psta);
+ break;
+ case 2:
+ memcpy(pattrib->ra, pbssid, ETH_ALEN);
+ memcpy(pattrib->ta, psa, ETH_ALEN);
+ ret = sta2ap_data_frame(adapter, precv_frame, &psta);
+ break;
+ case 3:
+ memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
+ memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN);
+ ret = _FAIL;
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" case 3\n"));
+ break;
+ default:
+ ret = _FAIL;
+ break;
+ }
+
+ if (ret == _FAIL) {
+ goto exit;
+ } else if (ret == RTW_RX_HANDLED) {
+ goto exit;
+ }
+
+ if (psta == NULL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta==NULL\n"));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* psta->rssi = prxcmd->rssi; */
+ /* psta->signal_quality = prxcmd->sq; */
+ precv_frame->u.hdr.psta = psta;
+
+ pattrib->amsdu = 0;
+ pattrib->ack_policy = 0;
+ /* parsing QC field */
+ if (pattrib->qos == 1) {
+ pattrib->priority = GetPriority((ptr + 24));
+ pattrib->ack_policy = GetAckpolicy((ptr + 24));
+ pattrib->amsdu = GetAMsdu((ptr + 24));
+ pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26;
+
+ if (pattrib->priority != 0 && pattrib->priority != 3)
+ adapter->recvpriv.bIsAnyNonBEPkts = true;
+ } else {
+ pattrib->priority = 0;
+ pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 30 : 24;
+ }
+
+ if (pattrib->order)/* HT-CTRL 11n */
+ pattrib->hdrlen += 4;
+
+ precv_frame->u.hdr.preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority];
+
+ /* decache, drop duplicate recv packets */
+ if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decache : drop pkt\n"));
+ ret = _FAIL;
+ goto exit;
+ }
+
+ if (pattrib->privacy) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("validate_recv_data_frame:pattrib->privacy=%x\n", pattrib->privacy));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ^^^^^^^^^^^IS_MCAST(pattrib->ra(0x%02x))=%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], IS_MCAST(pattrib->ra)));
+
+ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra));
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n pattrib->encrypt=%d\n", pattrib->encrypt));
+
+ SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt);
+ } else {
+ pattrib->encrypt = 0;
+ pattrib->iv_len = 0;
+ pattrib->icv_len = 0;
+ }
+
+exit:
+
+_func_exit_;
+
+ return ret;
+}
+
+static int validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame)
+{
+ /* shall check frame subtype, to / from ds, da, bssid */
+
+ /* then call check if rx seq/frag. duplicated. */
+
+ u8 type;
+ u8 subtype;
+ int retval = _SUCCESS;
+ u8 bDumpRxPkt;
+ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ u8 *ptr = precv_frame->u.hdr.rx_data;
+ u8 ver = (unsigned char) (*ptr)&0x3;
+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+
+_func_enter_;
+
+ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+ int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter));
+ if (ch_set_idx >= 0)
+ pmlmeext->channel_set[ch_set_idx].rx_count++;
+ }
+
+ /* add version chk */
+ if (ver != 0) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! (ver!=0)\n"));
+ retval = _FAIL;
+ goto exit;
+ }
+
+ type = GetFrameType(ptr);
+ subtype = GetFrameSubType(ptr); /* bit(7)~bit(2) */
+
+ pattrib->to_fr_ds = get_tofr_ds(ptr);
+
+ pattrib->frag_num = GetFragNum(ptr);
+ pattrib->seq_num = GetSequence(ptr);
+
+ pattrib->pw_save = GetPwrMgt(ptr);
+ pattrib->mfrag = GetMFrag(ptr);
+ pattrib->mdata = GetMData(ptr);
+ pattrib->privacy = GetPrivacy(ptr);
+ pattrib->order = GetOrder(ptr);
+
+ /* Dump rx packets */
+ rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt));
+ if (bDumpRxPkt == 1) {/* dump all rx packets */
+ int i;
+ DBG_88E("#############################\n");
+
+ for (i = 0; i < 64; i = i+8)
+ DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i),
+ *(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7));
+ DBG_88E("#############################\n");
+ } else if (bDumpRxPkt == 2) {
+ if (type == WIFI_MGT_TYPE) {
+ int i;
+ DBG_88E("#############################\n");
+
+ for (i = 0; i < 64; i = i+8)
+ DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i),
+ *(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7));
+ DBG_88E("#############################\n");
+ }
+ } else if (bDumpRxPkt == 3) {
+ if (type == WIFI_DATA_TYPE) {
+ int i;
+ DBG_88E("#############################\n");
+
+ for (i = 0; i < 64; i = i+8)
+ DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i),
+ *(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7));
+ DBG_88E("#############################\n");
+ }
+ }
+ switch (type) {
+ case WIFI_MGT_TYPE: /* mgnt */
+ retval = validate_recv_mgnt_frame(adapter, precv_frame);
+ if (retval == _FAIL)
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_mgnt_frame fail\n"));
+ retval = _FAIL; /* only data frame return _SUCCESS */
+ break;
+ case WIFI_CTRL_TYPE: /* ctrl */
+ retval = validate_recv_ctrl_frame(adapter, precv_frame);
+ if (retval == _FAIL)
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_ctrl_frame fail\n"));
+ retval = _FAIL; /* only data frame return _SUCCESS */
+ break;
+ case WIFI_DATA_TYPE: /* data */
+ rtw_led_control(adapter, LED_CTL_RX);
+ pattrib->qos = (subtype & BIT(7)) ? 1 : 0;
+ retval = validate_recv_data_frame(adapter, precv_frame);
+ if (retval == _FAIL) {
+ struct recv_priv *precvpriv = &adapter->recvpriv;
+ precvpriv->rx_drop++;
+ }
+ break;
+ default:
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! type= 0x%x\n", type));
+ retval = _FAIL;
+ break;
+ }
+
+exit:
+
+_func_exit_;
+
+ return retval;
+}
+
+/* remove the wlanhdr and add the eth_hdr */
+
+static int wlanhdr_to_ethhdr (union recv_frame *precvframe)
+{
+ int rmv_len;
+ u16 eth_type, len;
+ __be16 be_tmp;
+ u8 bsnaphdr;
+ u8 *psnap_type;
+ struct ieee80211_snap_hdr *psnap;
+
+ int ret = _SUCCESS;
+ struct adapter *adapter = precvframe->u.hdr.adapter;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+ u8 *ptr = get_recvframe_data(precvframe); /* point to frame_ctrl field */
+ struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
+
+_func_enter_;
+
+ if (pattrib->encrypt)
+ recvframe_pull_tail(precvframe, pattrib->icv_len);
+
+ psnap = (struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len);
+ psnap_type = ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE;
+ /* convert hdr + possible LLC headers into Ethernet header */
+ if ((_rtw_memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) &&
+ (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == false) &&
+ (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2) == false)) ||
+ _rtw_memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) {
+ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
+ bsnaphdr = true;
+ } else {
+ /* Leave Ethernet header part of hdr and full payload */
+ bsnaphdr = false;
+ }
+
+ rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0);
+ len = precvframe->u.hdr.len - rmv_len;
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+ ("\n===pattrib->hdrlen: %x, pattrib->iv_len:%x===\n\n", pattrib->hdrlen, pattrib->iv_len));
+
+ memcpy(&be_tmp, ptr+rmv_len, 2);
+ eth_type = ntohs(be_tmp); /* pattrib->ether_type */
+ pattrib->eth_type = eth_type;
+
+ if ((check_fwstate(pmlmepriv, WIFI_MP_STATE))) {
+ ptr += rmv_len;
+ *ptr = 0x87;
+ *(ptr+1) = 0x12;
+
+ eth_type = 0x8712;
+ /* append rx status for mp test packets */
+ ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr)+2)-24);
+ memcpy(ptr, get_rxmem(precvframe), 24);
+ ptr += 24;
+ } else {
+ ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
+ }
+
+ memcpy(ptr, pattrib->dst, ETH_ALEN);
+ memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN);
+
+ if (!bsnaphdr) {
+ be_tmp = htons(len);
+ memcpy(ptr+12, &be_tmp, 2);
+ }
+
+_func_exit_;
+ return ret;
+}
+
+/* perform defrag */
+static union recv_frame *recvframe_defrag(struct adapter *adapter, struct __queue *defrag_q)
+{
+ struct list_head *plist, *phead;
+ u8 wlanhdr_offset;
+ u8 curfragnum;
+ struct recv_frame_hdr *pfhdr, *pnfhdr;
+ union recv_frame *prframe, *pnextrframe;
+ struct __queue *pfree_recv_queue;
+
+_func_enter_;
+
+ curfragnum = 0;
+ pfree_recv_queue = &adapter->recvpriv.free_recv_queue;
+
+ phead = get_list_head(defrag_q);
+ plist = get_next(phead);
+ prframe = LIST_CONTAINOR(plist, union recv_frame, u);
+ pfhdr = &prframe->u.hdr;
+ rtw_list_delete(&(prframe->u.list));
+
+ if (curfragnum != pfhdr->attrib.frag_num) {
+ /* the first fragment number must be 0 */
+ /* free the whole queue */
+ rtw_free_recvframe(prframe, pfree_recv_queue);
+ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
+
+ return NULL;
+ }
+
+ curfragnum++;
+
+ plist = get_list_head(defrag_q);
+
+ plist = get_next(plist);
+
+ while (rtw_end_of_queue_search(phead, plist) == false) {
+ pnextrframe = LIST_CONTAINOR(plist, union recv_frame , u);
+ pnfhdr = &pnextrframe->u.hdr;
+
+ /* check the fragment sequence (2nd ~n fragment frame) */
+
+ if (curfragnum != pnfhdr->attrib.frag_num) {
+ /* the fragment number must be increasing (after decache) */
+ /* release the defrag_q & prframe */
+ rtw_free_recvframe(prframe, pfree_recv_queue);
+ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
+ return NULL;
+ }
+
+ curfragnum++;
+
+ /* copy the 2nd~n fragment frame's payload to the first fragment */
+ /* get the 2nd~last fragment frame's payload */
+
+ wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len;
+
+ recvframe_pull(pnextrframe, wlanhdr_offset);
+
+ /* append to first fragment frame's tail (if privacy frame, pull the ICV) */
+ recvframe_pull_tail(prframe, pfhdr->attrib.icv_len);
+
+ /* memcpy */
+ memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len);
+
+ recvframe_put(prframe, pnfhdr->len);
+
+ pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len;
+ plist = get_next(plist);
+ };
+
+ /* free the defrag_q queue and return the prframe */
+ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Performance defrag!!!!!\n"));
+
+_func_exit_;
+
+ return prframe;
+}
+
+/* check if need to defrag, if needed queue the frame to defrag_q */
+union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_frame *precv_frame)
+{
+ u8 ismfrag;
+ u8 fragnum;
+ u8 *psta_addr;
+ struct recv_frame_hdr *pfhdr;
+ struct sta_info *psta;
+ struct sta_priv *pstapriv;
+ struct list_head *phead;
+ union recv_frame *prtnframe = NULL;
+ struct __queue *pfree_recv_queue, *pdefrag_q;
+
+_func_enter_;
+
+ pstapriv = &padapter->stapriv;
+
+ pfhdr = &precv_frame->u.hdr;
+
+ pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+
+ /* need to define struct of wlan header frame ctrl */
+ ismfrag = pfhdr->attrib.mfrag;
+ fragnum = pfhdr->attrib.frag_num;
+
+ psta_addr = pfhdr->attrib.ta;
+ psta = rtw_get_stainfo(pstapriv, psta_addr);
+ if (psta == NULL) {
+ u8 type = GetFrameType(pfhdr->rx_data);
+ if (type != WIFI_DATA_TYPE) {
+ psta = rtw_get_bcmc_stainfo(padapter);
+ pdefrag_q = &psta->sta_recvpriv.defrag_q;
+ } else {
+ pdefrag_q = NULL;
+ }
+ } else {
+ pdefrag_q = &psta->sta_recvpriv.defrag_q;
+ }
+
+ if ((ismfrag == 0) && (fragnum == 0))
+ prtnframe = precv_frame;/* isn't a fragment frame */
+
+ if (ismfrag == 1) {
+ /* 0~(n-1) fragment frame */
+ /* enqueue to defraf_g */
+ if (pdefrag_q != NULL) {
+ if (fragnum == 0) {
+ /* the first fragment */
+ if (_rtw_queue_empty(pdefrag_q) == false) {
+ /* free current defrag_q */
+ rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue);
+ }
+ }
+
+ /* Then enqueue the 0~(n-1) fragment into the defrag_q */
+
+ phead = get_list_head(pdefrag_q);
+ rtw_list_insert_tail(&pfhdr->list, phead);
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Enqueuq: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
+
+ prtnframe = NULL;
+ } else {
+ /* can't find this ta's defrag_queue, so free this recv_frame */
+ rtw_free_recvframe(precv_frame, pfree_recv_queue);
+ prtnframe = NULL;
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q==NULL: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
+ }
+ }
+
+ if ((ismfrag == 0) && (fragnum != 0)) {
+ /* the last fragment frame */
+ /* enqueue the last fragment */
+ if (pdefrag_q != NULL) {
+ phead = get_list_head(pdefrag_q);
+ rtw_list_insert_tail(&pfhdr->list, phead);
+
+ /* call recvframe_defrag to defrag */
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("defrag: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
+ precv_frame = recvframe_defrag(padapter, pdefrag_q);
+ prtnframe = precv_frame;
+ } else {
+ /* can't find this ta's defrag_queue, so free this recv_frame */
+ rtw_free_recvframe(precv_frame, pfree_recv_queue);
+ prtnframe = NULL;
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q==NULL: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
+ }
+ }
+
+ if ((prtnframe != NULL) && (prtnframe->u.hdr.attrib.privacy)) {
+ /* after defrag we must check tkip mic code */
+ if (recvframe_chkmic(padapter, prtnframe) == _FAIL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic(padapter, prtnframe)==_FAIL\n"));
+ rtw_free_recvframe(prtnframe, pfree_recv_queue);
+ prtnframe = NULL;
+ }
+ }
+
+_func_exit_;
+
+ return prtnframe;
+}
+
+static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
+{
+ int a_len, padding_len;
+ u16 eth_type, nSubframe_Length;
+ u8 nr_subframes, i;
+ unsigned char *pdata;
+ struct rx_pkt_attrib *pattrib;
+ unsigned char *data_ptr;
+ struct sk_buff *sub_skb, *subframes[MAX_SUBFRAME_COUNT];
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+ struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue);
+ int ret = _SUCCESS;
+ nr_subframes = 0;
+
+ pattrib = &prframe->u.hdr.attrib;
+
+ recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen);
+
+ if (prframe->u.hdr.attrib.iv_len > 0)
+ recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len);
+
+ a_len = prframe->u.hdr.len;
+
+ pdata = prframe->u.hdr.rx_data;
+
+ while (a_len > ETH_HLEN) {
+ /* Offset 12 denote 2 mac address */
+ nSubframe_Length = RTW_GET_BE16(pdata + 12);
+
+ if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) {
+ DBG_88E("nRemain_Length is %d and nSubframe_Length is : %d\n", a_len, nSubframe_Length);
+ goto exit;
+ }
+
+ /* move the data point to data content */
+ pdata += ETH_HLEN;
+ a_len -= ETH_HLEN;
+
+ /* Allocate new skb for releasing to upper layer */
+ sub_skb = dev_alloc_skb(nSubframe_Length + 12);
+ if (sub_skb) {
+ skb_reserve(sub_skb, 12);
+ data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length);
+ memcpy(data_ptr, pdata, nSubframe_Length);
+ } else {
+ sub_skb = skb_clone(prframe->u.hdr.pkt, GFP_ATOMIC);
+ if (sub_skb) {
+ sub_skb->data = pdata;
+ sub_skb->len = nSubframe_Length;
+ skb_set_tail_pointer(sub_skb, nSubframe_Length);
+ } else {
+ DBG_88E("skb_clone() Fail!!! , nr_subframes=%d\n", nr_subframes);
+ break;
+ }
+ }
+
+ subframes[nr_subframes++] = sub_skb;
+
+ if (nr_subframes >= MAX_SUBFRAME_COUNT) {
+ DBG_88E("ParseSubframe(): Too many Subframes! Packets dropped!\n");
+ break;
+ }
+
+ pdata += nSubframe_Length;
+ a_len -= nSubframe_Length;
+ if (a_len != 0) {
+ padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4-1));
+ if (padding_len == 4) {
+ padding_len = 0;
+ }
+
+ if (a_len < padding_len) {
+ goto exit;
+ }
+ pdata += padding_len;
+ a_len -= padding_len;
+ }
+ }
+
+ for (i = 0; i < nr_subframes; i++) {
+ sub_skb = subframes[i];
+ /* convert hdr + possible LLC headers into Ethernet header */
+ eth_type = RTW_GET_BE16(&sub_skb->data[6]);
+ if (sub_skb->len >= 8 &&
+ ((_rtw_memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) &&
+ eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) ||
+ _rtw_memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE))) {
+ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
+ skb_pull(sub_skb, SNAP_SIZE);
+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN);
+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN);
+ } else {
+ __be16 len;
+ /* Leave Ethernet header part of hdr and full payload */
+ len = htons(sub_skb->len);
+ memcpy(skb_push(sub_skb, 2), &len, 2);
+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN);
+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN);
+ }
+
+ /* Indicat the packets to upper layer */
+ if (sub_skb) {
+ /* Insert NAT2.5 RX here! */
+ sub_skb->protocol = eth_type_trans(sub_skb, padapter->pnetdev);
+ sub_skb->dev = padapter->pnetdev;
+
+ sub_skb->ip_summed = CHECKSUM_NONE;
+
+ netif_rx(sub_skb);
+ }
+ }
+
+exit:
+
+ prframe->u.hdr.len = 0;
+ rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */
+
+ return ret;
+}
+
+static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num)
+{
+ u8 wsize = preorder_ctrl->wsize_b;
+ u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) & 0xFFF;/* 4096; */
+
+ /* Rx Reorder initialize condition. */
+ if (preorder_ctrl->indicate_seq == 0xFFFF)
+ preorder_ctrl->indicate_seq = seq_num;
+
+ /* Drop out the packet which SeqNum is smaller than WinStart */
+ if (SN_LESS(seq_num, preorder_ctrl->indicate_seq))
+ return false;
+
+ /* */
+ /* Sliding window manipulation. Conditions includes: */
+ /* 1. Incoming SeqNum is equal to WinStart =>Window shift 1 */
+ /* 2. Incoming SeqNum is larger than the WinEnd => Window shift N */
+ /* */
+ if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) {
+ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF;
+ } else if (SN_LESS(wend, seq_num)) {
+ if (seq_num >= (wsize - 1))
+ preorder_ctrl->indicate_seq = seq_num + 1 - wsize;
+ else
+ preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1;
+ }
+
+ return true;
+}
+
+int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe);
+int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe)
+{
+ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
+ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+ struct list_head *phead, *plist;
+ union recv_frame *pnextrframe;
+ struct rx_pkt_attrib *pnextattrib;
+
+ phead = get_list_head(ppending_recvframe_queue);
+ plist = get_next(phead);
+
+ while (rtw_end_of_queue_search(phead, plist) == false) {
+ pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u);
+ pnextattrib = &pnextrframe->u.hdr.attrib;
+
+ if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num))
+ plist = get_next(plist);
+ else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num))
+ return false;
+ else
+ break;
+ }
+
+ rtw_list_delete(&(prframe->u.hdr.list));
+
+ rtw_list_insert_tail(&(prframe->u.hdr.list), plist);
+ return true;
+}
+
+static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced)
+{
+ struct list_head *phead, *plist;
+ union recv_frame *prframe;
+ struct rx_pkt_attrib *pattrib;
+ int bPktInBuf = false;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+ phead = get_list_head(ppending_recvframe_queue);
+ plist = get_next(phead);
+
+ /* Handling some condition for forced indicate case. */
+ if (bforced) {
+ if (rtw_is_list_empty(phead))
+ return true;
+
+ prframe = LIST_CONTAINOR(plist, union recv_frame, u);
+ pattrib = &prframe->u.hdr.attrib;
+ preorder_ctrl->indicate_seq = pattrib->seq_num;
+ }
+
+ /* Prepare indication list and indication. */
+ /* Check if there is any packet need indicate. */
+ while (!rtw_is_list_empty(phead)) {
+ prframe = LIST_CONTAINOR(plist, union recv_frame, u);
+ pattrib = &prframe->u.hdr.attrib;
+
+ if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+ ("recv_indicatepkts_in_order: indicate=%d seq=%d amsdu=%d\n",
+ preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu));
+ plist = get_next(plist);
+ rtw_list_delete(&(prframe->u.hdr.list));
+
+ if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num))
+ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF;
+
+ /* Set this as a lock to make sure that only one thread is indicating packet. */
+
+ /* indicate this recv_frame */
+ if (!pattrib->amsdu) {
+ if ((!padapter->bDriverStopped) &&
+ (!padapter->bSurpriseRemoved))
+ rtw_recv_indicatepkt(padapter, prframe);/* indicate this recv_frame */
+ } else if (pattrib->amsdu == 1) {
+ if (amsdu_to_msdu(padapter, prframe) != _SUCCESS)
+ rtw_free_recvframe(prframe, &precvpriv->free_recv_queue);
+ } else {
+ /* error condition; */
+ }
+
+ /* Update local variables. */
+ bPktInBuf = false;
+ } else {
+ bPktInBuf = true;
+ break;
+ }
+ }
+ return bPktInBuf;
+}
+
+static int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe)
+{
+ unsigned long irql;
+ int retval = _SUCCESS;
+ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
+ struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl;
+ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+ if (!pattrib->amsdu) {
+ /* s1. */
+ wlanhdr_to_ethhdr(prframe);
+
+ if ((pattrib->qos != 1) || (pattrib->eth_type == 0x0806) ||
+ (pattrib->ack_policy != 0)) {
+ if ((!padapter->bDriverStopped) &&
+ (!padapter->bSurpriseRemoved)) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ recv_indicatepkt_reorder -recv_func recv_indicatepkt\n"));
+
+ rtw_recv_indicatepkt(padapter, prframe);
+ return _SUCCESS;
+ }
+
+ return _FAIL;
+ }
+
+ if (!preorder_ctrl->enable) {
+ /* indicate this recv_frame */
+ preorder_ctrl->indicate_seq = pattrib->seq_num;
+ rtw_recv_indicatepkt(padapter, prframe);
+
+ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096;
+ return _SUCCESS;
+ }
+ } else if (pattrib->amsdu == 1) { /* temp filter -> means didn't support A-MSDUs in a A-MPDU */
+ if (!preorder_ctrl->enable) {
+ preorder_ctrl->indicate_seq = pattrib->seq_num;
+ retval = amsdu_to_msdu(padapter, prframe);
+
+ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096;
+ return retval;
+ }
+ }
+
+ _enter_critical_bh(&ppending_recvframe_queue->lock, &irql);
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+ ("recv_indicatepkt_reorder: indicate=%d seq=%d\n",
+ preorder_ctrl->indicate_seq, pattrib->seq_num));
+
+ /* s2. check if winstart_b(indicate_seq) needs to been updated */
+ if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) {
+ rtw_recv_indicatepkt(padapter, prframe);
+
+ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+
+ goto _success_exit;
+ }
+
+ /* s3. Insert all packet into Reorder Queue to maintain its ordering. */
+ if (!enqueue_reorder_recvframe(preorder_ctrl, prframe))
+ goto _err_exit;
+
+ /* s4. */
+ /* Indication process. */
+ /* After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets */
+ /* with the SeqNum smaller than latest WinStart and buffer other packets. */
+ /* */
+ /* For Rx Reorder condition: */
+ /* 1. All packets with SeqNum smaller than WinStart => Indicate */
+ /* 2. All packets with SeqNum larger than or equal to WinStart => Buffer it. */
+ /* */
+
+ /* recv_indicatepkts_in_order(padapter, preorder_ctrl, true); */
+ if (recv_indicatepkts_in_order(padapter, preorder_ctrl, false)) {
+ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME);
+ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+ } else {
+ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
+ }
+
+_success_exit:
+
+ return _SUCCESS;
+
+_err_exit:
+
+ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+
+ return _FAIL;
+}
+
+void rtw_reordering_ctrl_timeout_handler(void *pcontext)
+{
+ unsigned long irql;
+ struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext;
+ struct adapter *padapter = preorder_ctrl->padapter;
+ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+ return;
+
+ _enter_critical_bh(&ppending_recvframe_queue->lock, &irql);
+
+ if (recv_indicatepkts_in_order(padapter, preorder_ctrl, true) == true)
+ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME);
+
+ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+}
+
+static int process_recv_indicatepkts(struct adapter *padapter, union recv_frame *prframe)
+{
+ int retval = _SUCCESS;
+ /* struct recv_priv *precvpriv = &padapter->recvpriv; */
+ /* struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; */
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+
+ if (phtpriv->ht_option) { /* B/G/N Mode */
+ /* prframe->u.hdr.preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */
+
+ if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) {
+ /* including perform A-MPDU Rx Ordering Buffer Control */
+ if ((!padapter->bDriverStopped) &&
+ (!padapter->bSurpriseRemoved)) {
+ retval = _FAIL;
+ return retval;
+ }
+ }
+ } else { /* B/G mode */
+ retval = wlanhdr_to_ethhdr (prframe);
+ if (retval != _SUCCESS) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("wlanhdr_to_ethhdr: drop pkt\n"));
+ return retval;
+ }
+
+ if ((!padapter->bDriverStopped) &&
+ (!padapter->bSurpriseRemoved)) {
+ /* indicate this recv_frame */
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func recv_indicatepkt\n"));
+ rtw_recv_indicatepkt(padapter, prframe);
+ } else {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func free_indicatepkt\n"));
+
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved));
+ retval = _FAIL;
+ return retval;
+ }
+ }
+
+ return retval;
+}
+
+static int recv_func_prehandle(struct adapter *padapter, union recv_frame *rframe)
+{
+ int ret = _SUCCESS;
+ struct rx_pkt_attrib *pattrib = &rframe->u.hdr.attrib;
+ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ if (padapter->registrypriv.mp_mode == 1) {
+ if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)) { /* padapter->mppriv.check_mp_pkt == 0)) */
+ if (pattrib->crc_err == 1)
+ padapter->mppriv.rx_crcerrpktcount++;
+ else
+ padapter->mppriv.rx_pktcount++;
+
+ if (check_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE) == false) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_alert_, ("MP - Not in loopback mode , drop pkt\n"));
+ ret = _FAIL;
+ rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
+ goto exit;
+ }
+ }
+ }
+
+ /* check the frame crtl field and decache */
+ ret = validate_recv_frame(padapter, rframe);
+ if (ret != _SUCCESS) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recv_func: validate_recv_frame fail! drop pkt\n"));
+ rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
+static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prframe)
+{
+ int ret = _SUCCESS;
+ union recv_frame *orig_prframe = prframe;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+
+ /* DATA FRAME */
+ rtw_led_control(padapter, LED_CTL_RX);
+
+ prframe = decryptor(padapter, prframe);
+ if (prframe == NULL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n"));
+ ret = _FAIL;
+ goto _recv_data_drop;
+ }
+
+ prframe = recvframe_chk_defrag(padapter, prframe);
+ if (prframe == NULL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n"));
+ goto _recv_data_drop;
+ }
+
+ prframe = portctrl(padapter, prframe);
+ if (prframe == NULL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n"));
+ ret = _FAIL;
+ goto _recv_data_drop;
+ }
+
+ count_rx_stats(padapter, prframe, NULL);
+
+ ret = process_recv_indicatepkts(padapter, prframe);
+ if (ret != _SUCCESS) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recv_func: process_recv_indicatepkts fail!\n"));
+ rtw_free_recvframe(orig_prframe, pfree_recv_queue);/* free this recv_frame */
+ goto _recv_data_drop;
+ }
+ return ret;
+
+_recv_data_drop:
+ precvpriv->rx_drop++;
+ return ret;
+}
+
+static int recv_func(struct adapter *padapter, union recv_frame *rframe)
+{
+ int ret;
+ struct rx_pkt_attrib *prxattrib = &rframe->u.hdr.attrib;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct mlme_priv *mlmepriv = &padapter->mlmepriv;
+
+ /* check if need to handle uc_swdec_pending_queue*/
+ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && psecuritypriv->busetkipkey) {
+ union recv_frame *pending_frame;
+
+ while ((pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue))) {
+ if (recv_func_posthandle(padapter, pending_frame) == _SUCCESS)
+ DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__);
+ }
+ }
+
+ ret = recv_func_prehandle(padapter, rframe);
+
+ if (ret == _SUCCESS) {
+ /* check if need to enqueue into uc_swdec_pending_queue*/
+ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) &&
+ !IS_MCAST(prxattrib->ra) && prxattrib->encrypt > 0 &&
+ (prxattrib->bdecrypted == 0 || psecuritypriv->sw_decrypt) &&
+ !is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm) &&
+ !psecuritypriv->busetkipkey) {
+ rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue);
+ DBG_88E("%s: no key, enqueue uc_swdec_pending_queue\n", __func__);
+ goto exit;
+ }
+
+ ret = recv_func_posthandle(padapter, rframe);
+ }
+
+exit:
+ return ret;
+}
+
+s32 rtw_recv_entry(union recv_frame *precvframe)
+{
+ struct adapter *padapter;
+ struct recv_priv *precvpriv;
+ s32 ret = _SUCCESS;
+
+_func_enter_;
+
+ padapter = precvframe->u.hdr.adapter;
+
+ precvpriv = &padapter->recvpriv;
+
+ ret = recv_func(padapter, precvframe);
+ if (ret == _FAIL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("rtw_recv_entry: recv_func return fail!!!\n"));
+ goto _recv_entry_drop;
+ }
+
+ precvpriv->rx_pkts++;
+
+_func_exit_;
+
+ return ret;
+
+_recv_entry_drop:
+
+ if (padapter->registrypriv.mp_mode == 1)
+ padapter->mppriv.rx_pktloss = precvpriv->rx_drop;
+
+_func_exit_;
+
+ return ret;
+}
+
+void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS)
+{
+ struct adapter *adapter = (struct adapter *)FunctionContext;
+ struct recv_priv *recvpriv = &adapter->recvpriv;
+
+ u32 tmp_s, tmp_q;
+ u8 avg_signal_strength = 0;
+ u8 avg_signal_qual = 0;
+ u8 _alpha = 3; /* this value is based on converging_constant = 5000 and sampling_interval = 1000 */
+
+ if (adapter->recvpriv.is_signal_dbg) {
+ /* update the user specific value, signal_strength_dbg, to signal_strength, rssi */
+ adapter->recvpriv.signal_strength = adapter->recvpriv.signal_strength_dbg;
+ adapter->recvpriv.rssi = (s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg);
+ } else {
+ if (recvpriv->signal_strength_data.update_req == 0) {/* update_req is clear, means we got rx */
+ avg_signal_strength = recvpriv->signal_strength_data.avg_val;
+ /* after avg_vals are accquired, we can re-stat the signal values */
+ recvpriv->signal_strength_data.update_req = 1;
+ }
+
+ if (recvpriv->signal_qual_data.update_req == 0) {/* update_req is clear, means we got rx */
+ avg_signal_qual = recvpriv->signal_qual_data.avg_val;
+ /* after avg_vals are accquired, we can re-stat the signal values */
+ recvpriv->signal_qual_data.update_req = 1;
+ }
+
+ /* update value of signal_strength, rssi, signal_qual */
+ if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == false) {
+ tmp_s = (avg_signal_strength+(_alpha-1)*recvpriv->signal_strength);
+ if (tmp_s % _alpha)
+ tmp_s = tmp_s/_alpha + 1;
+ else
+ tmp_s = tmp_s/_alpha;
+ if (tmp_s > 100)
+ tmp_s = 100;
+
+ tmp_q = (avg_signal_qual+(_alpha-1)*recvpriv->signal_qual);
+ if (tmp_q % _alpha)
+ tmp_q = tmp_q/_alpha + 1;
+ else
+ tmp_q = tmp_q/_alpha;
+ if (tmp_q > 100)
+ tmp_q = 100;
+
+ recvpriv->signal_strength = tmp_s;
+ recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s);
+ recvpriv->signal_qual = tmp_q;
+ }
+ }
+ rtw_set_signal_stat_timer(recvpriv);
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_rf.c b/drivers/staging/rtl8188eu/core/rtw_rf.c
new file mode 100644
index 00000000000..1170dd001c1
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_rf.c
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_RF_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+
+
+struct ch_freq {
+ u32 channel;
+ u32 frequency;
+};
+
+static struct ch_freq ch_freq_map[] = {
+ {1, 2412}, {2, 2417}, {3, 2422}, {4, 2427}, {5, 2432},
+ {6, 2437}, {7, 2442}, {8, 2447}, {9, 2452}, {10, 2457},
+ {11, 2462}, {12, 2467}, {13, 2472}, {14, 2484},
+ /* UNII */
+ {36, 5180}, {40, 5200}, {44, 5220}, {48, 5240}, {52, 5260},
+ {56, 5280}, {60, 5300}, {64, 5320}, {149, 5745}, {153, 5765},
+ {157, 5785}, {161, 5805}, {165, 5825}, {167, 5835}, {169, 5845},
+ {171, 5855}, {173, 5865},
+ /* HiperLAN2 */
+ {100, 5500}, {104, 5520}, {108, 5540}, {112, 5560}, {116, 5580},
+ {120, 5600}, {124, 5620}, {128, 5640}, {132, 5660}, {136, 5680},
+ {140, 5700},
+ /* Japan MMAC */
+ {34, 5170}, {38, 5190}, {42, 5210}, {46, 5230},
+ /* Japan */
+ {184, 4920}, {188, 4940}, {192, 4960}, {196, 4980},
+ {208, 5040},/* Japan, means J08 */
+ {212, 5060},/* Japan, means J12 */
+ {216, 5080},/* Japan, means J16 */
+};
+
+static int ch_freq_map_num = (sizeof(ch_freq_map) / sizeof(struct ch_freq));
+
+u32 rtw_ch2freq(u32 channel)
+{
+ u8 i;
+ u32 freq = 0;
+
+ for (i = 0; i < ch_freq_map_num; i++) {
+ if (channel == ch_freq_map[i].channel) {
+ freq = ch_freq_map[i].frequency;
+ break;
+ }
+ }
+ if (i == ch_freq_map_num)
+ freq = 2412;
+
+ return freq;
+}
+
+u32 rtw_freq2ch(u32 freq)
+{
+ u8 i;
+ u32 ch = 0;
+
+ for (i = 0; i < ch_freq_map_num; i++) {
+ if (freq == ch_freq_map[i].frequency) {
+ ch = ch_freq_map[i].channel;
+ break;
+ }
+ }
+ if (i == ch_freq_map_num)
+ ch = 1;
+
+ return ch;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c
new file mode 100644
index 00000000000..0f076d0cb5f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_security.c
@@ -0,0 +1,1779 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_SECURITY_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <osdep_intf.h>
+
+/* WEP related ===== */
+
+#define CRC32_POLY 0x04c11db7
+
+struct arc4context {
+ u32 x;
+ u32 y;
+ u8 state[256];
+};
+
+static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32 key_len)
+{
+ u32 t, u;
+ u32 keyindex;
+ u32 stateindex;
+ u8 *state;
+ u32 counter;
+_func_enter_;
+ state = parc4ctx->state;
+ parc4ctx->x = 0;
+ parc4ctx->y = 0;
+ for (counter = 0; counter < 256; counter++)
+ state[counter] = (u8)counter;
+ keyindex = 0;
+ stateindex = 0;
+ for (counter = 0; counter < 256; counter++) {
+ t = state[counter];
+ stateindex = (stateindex + key[keyindex] + t) & 0xff;
+ u = state[stateindex];
+ state[stateindex] = (u8)t;
+ state[counter] = (u8)u;
+ if (++keyindex >= key_len)
+ keyindex = 0;
+ }
+_func_exit_;
+}
+
+static u32 arcfour_byte(struct arc4context *parc4ctx)
+{
+ u32 x;
+ u32 y;
+ u32 sx, sy;
+ u8 *state;
+_func_enter_;
+ state = parc4ctx->state;
+ x = (parc4ctx->x + 1) & 0xff;
+ sx = state[x];
+ y = (sx + parc4ctx->y) & 0xff;
+ sy = state[y];
+ parc4ctx->x = x;
+ parc4ctx->y = y;
+ state[y] = (u8)sx;
+ state[x] = (u8)sy;
+_func_exit_;
+ return state[(sx + sy) & 0xff];
+}
+
+static void arcfour_encrypt(struct arc4context *parc4ctx, u8 *dest, u8 *src, u32 len)
+{
+ u32 i;
+_func_enter_;
+ for (i = 0; i < len; i++)
+ dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx);
+_func_exit_;
+}
+
+static int bcrc32initialized;
+static u32 crc32_table[256];
+
+static u8 crc32_reverseBit(u8 data)
+{
+ return (u8)((data<<7)&0x80) | ((data<<5)&0x40) | ((data<<3)&0x20) |
+ ((data<<1)&0x10) | ((data>>1)&0x08) | ((data>>3)&0x04) |
+ ((data>>5)&0x02) | ((data>>7)&0x01);
+}
+
+static void crc32_init(void)
+{
+_func_enter_;
+ if (bcrc32initialized == 1) {
+ goto exit;
+ } else {
+ int i, j;
+ u32 c;
+ u8 *p = (u8 *)&c, *p1;
+ u8 k;
+
+ c = 0x12340000;
+
+ for (i = 0; i < 256; ++i) {
+ k = crc32_reverseBit((u8)i);
+ for (c = ((u32)k) << 24, j = 8; j > 0; --j)
+ c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1);
+ p1 = (u8 *)&crc32_table[i];
+
+ p1[0] = crc32_reverseBit(p[3]);
+ p1[1] = crc32_reverseBit(p[2]);
+ p1[2] = crc32_reverseBit(p[1]);
+ p1[3] = crc32_reverseBit(p[0]);
+ }
+ bcrc32initialized = 1;
+ }
+exit:
+_func_exit_;
+}
+
+static __le32 getcrc32(u8 *buf, int len)
+{
+ u8 *p;
+ u32 crc;
+_func_enter_;
+ if (bcrc32initialized == 0)
+ crc32_init();
+
+ crc = 0xffffffff; /* preload shift register, per CRC-32 spec */
+
+ for (p = buf; len > 0; ++p, --len)
+ crc = crc32_table[(crc ^ *p) & 0xff] ^ (crc >> 8);
+_func_exit_;
+ return cpu_to_le32(~crc); /* transmit complement, per CRC-32 spec */
+}
+
+/*
+ Need to consider the fragment situation
+*/
+void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe)
+{ /* exclude ICV */
+
+ unsigned char crc[4];
+ struct arc4context mycontext;
+
+ int curfragnum, length;
+ u32 keylength;
+
+ u8 *pframe, *payload, *iv; /* wepkey */
+ u8 wepkey[16];
+ u8 hw_hdr_offset = 0;
+ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+_func_enter_;
+
+ if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
+ return;
+
+ hw_hdr_offset = TXDESC_SIZE +
+ (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ);
+
+ pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset;
+
+ /* start to encrypt each fragment */
+ if ((pattrib->encrypt == _WEP40_) || (pattrib->encrypt == _WEP104_)) {
+ keylength = psecuritypriv->dot11DefKeylen[psecuritypriv->dot11PrivacyKeyIndex];
+
+ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
+ iv = pframe+pattrib->hdrlen;
+ memcpy(&wepkey[0], iv, 3);
+ memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength);
+ payload = pframe+pattrib->iv_len+pattrib->hdrlen;
+
+ if ((curfragnum+1) == pattrib->nr_frags) { /* the last fragment */
+ length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
+
+ *((__le32 *)crc) = getcrc32(payload, length);
+
+ arcfour_init(&mycontext, wepkey, 3+keylength);
+ arcfour_encrypt(&mycontext, payload, payload, length);
+ arcfour_encrypt(&mycontext, payload+length, crc, 4);
+ } else {
+ length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
+ *((__le32 *)crc) = getcrc32(payload, length);
+ arcfour_init(&mycontext, wepkey, 3+keylength);
+ arcfour_encrypt(&mycontext, payload, payload, length);
+ arcfour_encrypt(&mycontext, payload+length, crc, 4);
+
+ pframe += pxmitpriv->frag_len;
+ pframe = (u8 *)RND4((size_t)(pframe));
+ }
+ }
+ }
+
+_func_exit_;
+}
+
+void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe)
+{
+ /* exclude ICV */
+ u8 crc[4];
+ struct arc4context mycontext;
+ int length;
+ u32 keylength;
+ u8 *pframe, *payload, *iv, wepkey[16];
+ u8 keyindex;
+ struct rx_pkt_attrib *prxattrib = &(((union recv_frame *)precvframe)->u.hdr.attrib);
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+_func_enter_;
+
+ pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
+
+ /* start to decrypt recvframe */
+ if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) {
+ iv = pframe+prxattrib->hdrlen;
+ keyindex = prxattrib->key_index;
+ keylength = psecuritypriv->dot11DefKeylen[keyindex];
+ memcpy(&wepkey[0], iv, 3);
+ memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength);
+ length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
+
+ payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
+
+ /* decrypt payload include icv */
+ arcfour_init(&mycontext, wepkey, 3+keylength);
+ arcfour_encrypt(&mycontext, payload, payload, length);
+
+ /* calculate icv and compare the icv */
+ *((__le32 *)crc) = getcrc32(payload, length - 4);
+
+ if (crc[3] != payload[length-1] ||
+ crc[2] != payload[length-2] ||
+ crc[1] != payload[length-3] ||
+ crc[0] != payload[length-4]) {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+ ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n",
+ &crc, &payload[length-4]));
+ }
+ }
+_func_exit_;
+ return;
+}
+
+/* 3 ===== TKIP related ===== */
+
+static u32 secmicgetuint32(u8 *p)
+/* Convert from Byte[] to Us3232 in a portable way */
+{
+ s32 i;
+ u32 res = 0;
+_func_enter_;
+ for (i = 0; i < 4; i++)
+ res |= ((u32)(*p++)) << (8*i);
+_func_exit_;
+ return res;
+}
+
+static void secmicputuint32(u8 *p, u32 val)
+/* Convert from Us3232 to Byte[] in a portable way */
+{
+ long i;
+_func_enter_;
+ for (i = 0; i < 4; i++) {
+ *p++ = (u8) (val & 0xff);
+ val >>= 8;
+ }
+_func_exit_;
+}
+
+static void secmicclear(struct mic_data *pmicdata)
+{
+/* Reset the state to the empty message. */
+_func_enter_;
+ pmicdata->L = pmicdata->K0;
+ pmicdata->R = pmicdata->K1;
+ pmicdata->nBytesInM = 0;
+ pmicdata->M = 0;
+_func_exit_;
+}
+
+void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key)
+{
+ /* Set the key */
+_func_enter_;
+ pmicdata->K0 = secmicgetuint32(key);
+ pmicdata->K1 = secmicgetuint32(key + 4);
+ /* and reset the message */
+ secmicclear(pmicdata);
+_func_exit_;
+}
+
+void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b)
+{
+_func_enter_;
+ /* Append the byte to our word-sized buffer */
+ pmicdata->M |= ((unsigned long)b) << (8*pmicdata->nBytesInM);
+ pmicdata->nBytesInM++;
+ /* Process the word if it is full. */
+ if (pmicdata->nBytesInM >= 4) {
+ pmicdata->L ^= pmicdata->M;
+ pmicdata->R ^= ROL32(pmicdata->L, 17);
+ pmicdata->L += pmicdata->R;
+ pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | ((pmicdata->L & 0x00ff00ff) << 8);
+ pmicdata->L += pmicdata->R;
+ pmicdata->R ^= ROL32(pmicdata->L, 3);
+ pmicdata->L += pmicdata->R;
+ pmicdata->R ^= ROR32(pmicdata->L, 2);
+ pmicdata->L += pmicdata->R;
+ /* Clear the buffer */
+ pmicdata->M = 0;
+ pmicdata->nBytesInM = 0;
+ }
+_func_exit_;
+}
+
+void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes)
+{
+_func_enter_;
+ /* This is simple */
+ while (nbytes > 0) {
+ rtw_secmicappendbyte(pmicdata, *src++);
+ nbytes--;
+ }
+_func_exit_;
+}
+
+void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst)
+{
+_func_enter_;
+ /* Append the minimum padding */
+ rtw_secmicappendbyte(pmicdata, 0x5a);
+ rtw_secmicappendbyte(pmicdata, 0);
+ rtw_secmicappendbyte(pmicdata, 0);
+ rtw_secmicappendbyte(pmicdata, 0);
+ rtw_secmicappendbyte(pmicdata, 0);
+ /* and then zeroes until the length is a multiple of 4 */
+ while (pmicdata->nBytesInM != 0)
+ rtw_secmicappendbyte(pmicdata, 0);
+ /* The appendByte function has already computed the result. */
+ secmicputuint32(dst, pmicdata->L);
+ secmicputuint32(dst+4, pmicdata->R);
+ /* Reset to the empty message. */
+ secmicclear(pmicdata);
+_func_exit_;
+}
+
+void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, u8 pri)
+{
+ struct mic_data micdata;
+ u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
+_func_enter_;
+ rtw_secmicsetkey(&micdata, key);
+ priority[0] = pri;
+
+ /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
+ if (header[1]&1) { /* ToDS == 1 */
+ rtw_secmicappend(&micdata, &header[16], 6); /* DA */
+ if (header[1]&2) /* From Ds == 1 */
+ rtw_secmicappend(&micdata, &header[24], 6);
+ else
+ rtw_secmicappend(&micdata, &header[10], 6);
+ } else { /* ToDS == 0 */
+ rtw_secmicappend(&micdata, &header[4], 6); /* DA */
+ if (header[1]&2) /* From Ds == 1 */
+ rtw_secmicappend(&micdata, &header[16], 6);
+ else
+ rtw_secmicappend(&micdata, &header[10], 6);
+ }
+ rtw_secmicappend(&micdata, &priority[0], 4);
+
+ rtw_secmicappend(&micdata, data, data_len);
+
+ rtw_secgetmic(&micdata, mic_code);
+_func_exit_;
+}
+
+
+
+/* macros for extraction/creation of unsigned char/unsigned short values */
+#define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15))
+#define Lo8(v16) ((u8)((v16) & 0x00FF))
+#define Hi8(v16) ((u8)(((v16) >> 8) & 0x00FF))
+#define Lo16(v32) ((u16)((v32) & 0xFFFF))
+#define Hi16(v32) ((u16)(((v32) >> 16) & 0xFFFF))
+#define Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8))
+
+/* select the Nth 16-bit word of the temporal key unsigned char array TK[] */
+#define TK16(N) Mk16(tk[2*(N)+1], tk[2*(N)])
+
+/* S-box lookup: 16 bits --> 16 bits */
+#define _S_(v16) (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)])
+
+/* fixed algorithm "parameters" */
+#define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */
+#define TA_SIZE 6 /* 48-bit transmitter address */
+#define TK_SIZE 16 /* 128-bit temporal key */
+#define P1K_SIZE 10 /* 80-bit Phase1 key */
+#define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */
+
+/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */
+static const unsigned short Sbox1[2][256] = { /* Sbox for hash (can be in ROM) */
+{
+ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+ },
+
+ { /* second half of table is unsigned char-reversed version of first! */
+ 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491,
+ 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC,
+ 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB,
+ 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B,
+ 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83,
+ 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A,
+ 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F,
+ 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA,
+ 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B,
+ 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713,
+ 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6,
+ 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85,
+ 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411,
+ 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B,
+ 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1,
+ 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF,
+ 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E,
+ 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6,
+ 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B,
+ 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD,
+ 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8,
+ 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2,
+ 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049,
+ 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810,
+ 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197,
+ 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F,
+ 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C,
+ 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927,
+ 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733,
+ 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5,
+ 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0,
+ 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C,
+ }
+};
+
+ /*
+**********************************************************************
+* Routine: Phase 1 -- generate P1K, given TA, TK, IV32
+*
+* Inputs:
+* tk[] = temporal key [128 bits]
+* ta[] = transmitter's MAC address [ 48 bits]
+* iv32 = upper 32 bits of IV [ 32 bits]
+* Output:
+* p1k[] = Phase 1 key [ 80 bits]
+*
+* Note:
+* This function only needs to be called every 2**16 packets,
+* although in theory it could be called every packet.
+*
+**********************************************************************
+*/
+static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32)
+{
+ int i;
+_func_enter_;
+ /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */
+ p1k[0] = Lo16(iv32);
+ p1k[1] = Hi16(iv32);
+ p1k[2] = Mk16(ta[1], ta[0]); /* use TA[] as little-endian */
+ p1k[3] = Mk16(ta[3], ta[2]);
+ p1k[4] = Mk16(ta[5], ta[4]);
+
+ /* Now compute an unbalanced Feistel cipher with 80-bit block */
+ /* size on the 80-bit block P1K[], using the 128-bit key TK[] */
+ for (i = 0; i < PHASE1_LOOP_CNT; i++) { /* Each add operation here is mod 2**16 */
+ p1k[0] += _S_(p1k[4] ^ TK16((i&1)+0));
+ p1k[1] += _S_(p1k[0] ^ TK16((i&1)+2));
+ p1k[2] += _S_(p1k[1] ^ TK16((i&1)+4));
+ p1k[3] += _S_(p1k[2] ^ TK16((i&1)+6));
+ p1k[4] += _S_(p1k[3] ^ TK16((i&1)+0));
+ p1k[4] += (unsigned short)i; /* avoid "slide attacks" */
+ }
+_func_exit_;
+}
+
+/*
+**********************************************************************
+* Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16
+*
+* Inputs:
+* tk[] = Temporal key [128 bits]
+* p1k[] = Phase 1 output key [ 80 bits]
+* iv16 = low 16 bits of IV counter [ 16 bits]
+* Output:
+* rc4key[] = the key used to encrypt the packet [128 bits]
+*
+* Note:
+* The value {TA, IV32, IV16} for Phase1/Phase2 must be unique
+* across all packets using the same key TK value. Then, for a
+* given value of TK[], this TKIP48 construction guarantees that
+* the final RC4KEY value is unique across all packets.
+*
+* Suggested implementation optimization: if PPK[] is "overlaid"
+* appropriately on RC4KEY[], there is no need for the final
+* for loop below that copies the PPK[] result into RC4KEY[].
+*
+**********************************************************************
+*/
+static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16)
+{
+ int i;
+ u16 PPK[6]; /* temporary key for mixing */
+_func_enter_;
+ /* Note: all adds in the PPK[] equations below are mod 2**16 */
+ for (i = 0; i < 5; i++)
+ PPK[i] = p1k[i]; /* first, copy P1K to PPK */
+ PPK[5] = p1k[4] + iv16; /* next, add in IV16 */
+
+ /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */
+ PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */
+ PPK[1] += _S_(PPK[0] ^ TK16(1));
+ PPK[2] += _S_(PPK[1] ^ TK16(2));
+ PPK[3] += _S_(PPK[2] ^ TK16(3));
+ PPK[4] += _S_(PPK[3] ^ TK16(4));
+ PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */
+
+ /* Final sweep: bijective, "linear". Rotates kill LSB correlations */
+ PPK[0] += RotR1(PPK[5] ^ TK16(6));
+ PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */
+ PPK[2] += RotR1(PPK[1]);
+ PPK[3] += RotR1(PPK[2]);
+ PPK[4] += RotR1(PPK[3]);
+ PPK[5] += RotR1(PPK[4]);
+ /* Note: At this point, for a given key TK[0..15], the 96-bit output */
+ /* value PPK[0..5] is guaranteed to be unique, as a function */
+ /* of the 96-bit "input" value {TA, IV32, IV16}. That is, P1K */
+ /* is now a keyed permutation of {TA, IV32, IV16}. */
+
+ /* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key */
+ rc4key[0] = Hi8(iv16); /* RC4KEY[0..2] is the WEP IV */
+ rc4key[1] = (Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys */
+ rc4key[2] = Lo8(iv16);
+ rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1);
+
+ /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */
+ for (i = 0; i < 6; i++) {
+ rc4key[4+2*i] = Lo8(PPK[i]);
+ rc4key[5+2*i] = Hi8(PPK[i]);
+ }
+_func_exit_;
+}
+
+/* The hlen isn't include the IV */
+u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
+{ /* exclude ICV */
+ u16 pnl;
+ u32 pnh;
+ u8 rc4key[16];
+ u8 ttkey[16];
+ u8 crc[4];
+ u8 hw_hdr_offset = 0;
+ struct arc4context mycontext;
+ int curfragnum, length;
+
+ u8 *pframe, *payload, *iv, *prwskey;
+ union pn48 dot11txpn;
+ struct sta_info *stainfo;
+ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ u32 res = _SUCCESS;
+_func_enter_;
+
+ if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
+ return _FAIL;
+
+ hw_hdr_offset = TXDESC_SIZE +
+ (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ);
+ pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset;
+ /* 4 start to encrypt each fragment */
+ if (pattrib->encrypt == _TKIP_) {
+ if (pattrib->psta)
+ stainfo = pattrib->psta;
+ else
+ stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]);
+
+ if (stainfo != NULL) {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo!= NULL!!!\n"));
+
+ if (IS_MCAST(pattrib->ra))
+ prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
+ else
+ prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+
+ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
+ iv = pframe+pattrib->hdrlen;
+ payload = pframe+pattrib->iv_len+pattrib->hdrlen;
+
+ GET_TKIP_PN(iv, dot11txpn);
+
+ pnl = (u16)(dot11txpn.val);
+ pnh = (u32)(dot11txpn.val>>16);
+ phase1((u16 *)&ttkey[0], prwskey, &pattrib->ta[0], pnh);
+ phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], pnl);
+
+ if ((curfragnum+1) == pattrib->nr_frags) { /* 4 the last fragment */
+ length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
+ RT_TRACE(_module_rtl871x_security_c_, _drv_info_,
+ ("pattrib->iv_len=%x, pattrib->icv_len=%x\n",
+ pattrib->iv_len, pattrib->icv_len));
+ *((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/
+
+ arcfour_init(&mycontext, rc4key, 16);
+ arcfour_encrypt(&mycontext, payload, payload, length);
+ arcfour_encrypt(&mycontext, payload+length, crc, 4);
+ } else {
+ length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ;
+ *((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/
+ arcfour_init(&mycontext, rc4key, 16);
+ arcfour_encrypt(&mycontext, payload, payload, length);
+ arcfour_encrypt(&mycontext, payload+length, crc, 4);
+
+ pframe += pxmitpriv->frag_len;
+ pframe = (u8 *)RND4((size_t)(pframe));
+ }
+ }
+ } else {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo==NULL!!!\n"));
+ res = _FAIL;
+ }
+ }
+_func_exit_;
+ return res;
+}
+
+/* The hlen isn't include the IV */
+u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe)
+{ /* exclude ICV */
+ u16 pnl;
+ u32 pnh;
+ u8 rc4key[16];
+ u8 ttkey[16];
+ u8 crc[4];
+ struct arc4context mycontext;
+ int length;
+
+ u8 *pframe, *payload, *iv, *prwskey;
+ union pn48 dot11txpn;
+ struct sta_info *stainfo;
+ struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ u32 res = _SUCCESS;
+
+_func_enter_;
+
+ pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
+
+ /* 4 start to decrypt recvframe */
+ if (prxattrib->encrypt == _TKIP_) {
+ stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
+ if (stainfo != NULL) {
+ if (IS_MCAST(prxattrib->ra)) {
+ if (!psecuritypriv->binstallGrpkey) {
+ res = _FAIL;
+ DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__);
+ goto exit;
+ }
+ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
+ } else {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo!= NULL!!!\n"));
+ prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+ }
+
+ iv = pframe+prxattrib->hdrlen;
+ payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
+ length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
+
+ GET_TKIP_PN(iv, dot11txpn);
+
+ pnl = (u16)(dot11txpn.val);
+ pnh = (u32)(dot11txpn.val>>16);
+
+ phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], pnh);
+ phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl);
+
+ /* 4 decrypt payload include icv */
+
+ arcfour_init(&mycontext, rc4key, 16);
+ arcfour_encrypt(&mycontext, payload, payload, length);
+
+ *((__le32 *)crc) = getcrc32(payload, length-4);
+
+ if (crc[3] != payload[length-1] ||
+ crc[2] != payload[length-2] ||
+ crc[1] != payload[length-3] ||
+ crc[0] != payload[length-4]) {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+ ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n",
+ &crc, &payload[length-4]));
+ res = _FAIL;
+ }
+ } else {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo==NULL!!!\n"));
+ res = _FAIL;
+ }
+ }
+_func_exit_;
+exit:
+ return res;
+}
+
+/* 3 ===== AES related ===== */
+
+
+#define MAX_MSG_SIZE 2048
+/*****************************/
+/******** SBOX Table *********/
+/*****************************/
+
+static u8 sbox_table[256] = {
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+
+/*****************************/
+/**** Function Prototypes ****/
+/*****************************/
+
+static void bitwise_xor(u8 *ina, u8 *inb, u8 *out);
+static void construct_mic_iv(u8 *mic_header1, int qc_exists, int a4_exists, u8 *mpdu, uint payload_length, u8 *pn_vector);
+static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu);
+static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, int qc_exists);
+static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, u8 *mpdu, u8 *pn_vector, int c);
+static void xor_128(u8 *a, u8 *b, u8 *out);
+static void xor_32(u8 *a, u8 *b, u8 *out);
+static u8 sbox(u8 a);
+static void next_key(u8 *key, int round);
+static void byte_sub(u8 *in, u8 *out);
+static void shift_row(u8 *in, u8 *out);
+static void mix_column(u8 *in, u8 *out);
+static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext);
+
+/****************************************/
+/* aes128k128d() */
+/* Performs a 128 bit AES encrypt with */
+/* 128 bit data. */
+/****************************************/
+static void xor_128(u8 *a, u8 *b, u8 *out)
+{
+ int i;
+_func_enter_;
+ for (i = 0; i < 16; i++)
+ out[i] = a[i] ^ b[i];
+_func_exit_;
+}
+
+static void xor_32(u8 *a, u8 *b, u8 *out)
+{
+ int i;
+_func_enter_;
+ for (i = 0; i < 4; i++)
+ out[i] = a[i] ^ b[i];
+_func_exit_;
+}
+
+static u8 sbox(u8 a)
+{
+ return sbox_table[(int)a];
+}
+
+static void next_key(u8 *key, int round)
+{
+ u8 rcon;
+ u8 sbox_key[4];
+ u8 rcon_table[12] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+ 0x1b, 0x36, 0x36, 0x36
+ };
+_func_enter_;
+ sbox_key[0] = sbox(key[13]);
+ sbox_key[1] = sbox(key[14]);
+ sbox_key[2] = sbox(key[15]);
+ sbox_key[3] = sbox(key[12]);
+
+ rcon = rcon_table[round];
+
+ xor_32(&key[0], sbox_key, &key[0]);
+ key[0] = key[0] ^ rcon;
+
+ xor_32(&key[4], &key[0], &key[4]);
+ xor_32(&key[8], &key[4], &key[8]);
+ xor_32(&key[12], &key[8], &key[12]);
+_func_exit_;
+}
+
+static void byte_sub(u8 *in, u8 *out)
+{
+ int i;
+_func_enter_;
+ for (i = 0; i < 16; i++)
+ out[i] = sbox(in[i]);
+_func_exit_;
+}
+
+static void shift_row(u8 *in, u8 *out)
+{
+_func_enter_;
+ out[0] = in[0];
+ out[1] = in[5];
+ out[2] = in[10];
+ out[3] = in[15];
+ out[4] = in[4];
+ out[5] = in[9];
+ out[6] = in[14];
+ out[7] = in[3];
+ out[8] = in[8];
+ out[9] = in[13];
+ out[10] = in[2];
+ out[11] = in[7];
+ out[12] = in[12];
+ out[13] = in[1];
+ out[14] = in[6];
+ out[15] = in[11];
+_func_exit_;
+}
+
+static void mix_column(u8 *in, u8 *out)
+{
+ int i;
+ u8 add1b[4];
+ u8 add1bf7[4];
+ u8 rotl[4];
+ u8 swap_halfs[4];
+ u8 andf7[4];
+ u8 rotr[4];
+ u8 temp[4];
+ u8 tempb[4];
+_func_enter_;
+ for (i = 0 ; i < 4; i++) {
+ if ((in[i] & 0x80) == 0x80)
+ add1b[i] = 0x1b;
+ else
+ add1b[i] = 0x00;
+ }
+
+ swap_halfs[0] = in[2]; /* Swap halfs */
+ swap_halfs[1] = in[3];
+ swap_halfs[2] = in[0];
+ swap_halfs[3] = in[1];
+
+ rotl[0] = in[3]; /* Rotate left 8 bits */
+ rotl[1] = in[0];
+ rotl[2] = in[1];
+ rotl[3] = in[2];
+
+ andf7[0] = in[0] & 0x7f;
+ andf7[1] = in[1] & 0x7f;
+ andf7[2] = in[2] & 0x7f;
+ andf7[3] = in[3] & 0x7f;
+
+ for (i = 3; i > 0; i--) { /* logical shift left 1 bit */
+ andf7[i] = andf7[i] << 1;
+ if ((andf7[i-1] & 0x80) == 0x80)
+ andf7[i] = (andf7[i] | 0x01);
+ }
+ andf7[0] = andf7[0] << 1;
+ andf7[0] = andf7[0] & 0xfe;
+
+ xor_32(add1b, andf7, add1bf7);
+
+ xor_32(in, add1bf7, rotr);
+
+ temp[0] = rotr[0]; /* Rotate right 8 bits */
+ rotr[0] = rotr[1];
+ rotr[1] = rotr[2];
+ rotr[2] = rotr[3];
+ rotr[3] = temp[0];
+
+ xor_32(add1bf7, rotr, temp);
+ xor_32(swap_halfs, rotl, tempb);
+ xor_32(temp, tempb, out);
+_func_exit_;
+}
+
+static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext)
+{
+ int round;
+ int i;
+ u8 intermediatea[16];
+ u8 intermediateb[16];
+ u8 round_key[16];
+_func_enter_;
+ for (i = 0; i < 16; i++)
+ round_key[i] = key[i];
+ for (round = 0; round < 11; round++) {
+ if (round == 0) {
+ xor_128(round_key, data, ciphertext);
+ next_key(round_key, round);
+ } else if (round == 10) {
+ byte_sub(ciphertext, intermediatea);
+ shift_row(intermediatea, intermediateb);
+ xor_128(intermediateb, round_key, ciphertext);
+ } else { /* 1 - 9 */
+ byte_sub(ciphertext, intermediatea);
+ shift_row(intermediatea, intermediateb);
+ mix_column(&intermediateb[0], &intermediatea[0]);
+ mix_column(&intermediateb[4], &intermediatea[4]);
+ mix_column(&intermediateb[8], &intermediatea[8]);
+ mix_column(&intermediateb[12], &intermediatea[12]);
+ xor_128(intermediatea, round_key, ciphertext);
+ next_key(round_key, round);
+ }
+ }
+_func_exit_;
+}
+
+/************************************************/
+/* construct_mic_iv() */
+/* Builds the MIC IV from header fields and PN */
+/************************************************/
+static void construct_mic_iv(u8 *mic_iv, int qc_exists, int a4_exists, u8 *mpdu,
+ uint payload_length, u8 *pn_vector)
+{
+ int i;
+_func_enter_;
+ mic_iv[0] = 0x59;
+ if (qc_exists && a4_exists)
+ mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */
+ if (qc_exists && !a4_exists)
+ mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */
+ if (!qc_exists)
+ mic_iv[1] = 0x00;
+ for (i = 2; i < 8; i++)
+ mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */
+ for (i = 8; i < 14; i++)
+ mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */
+ mic_iv[14] = (unsigned char) (payload_length / 256);
+ mic_iv[15] = (unsigned char) (payload_length % 256);
+_func_exit_;
+}
+
+/************************************************/
+/* construct_mic_header1() */
+/* Builds the first MIC header block from */
+/* header fields. */
+/************************************************/
+static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu)
+{
+_func_enter_;
+ mic_header1[0] = (u8)((header_length - 2) / 256);
+ mic_header1[1] = (u8)((header_length - 2) % 256);
+ mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */
+ mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */
+ mic_header1[4] = mpdu[4]; /* A1 */
+ mic_header1[5] = mpdu[5];
+ mic_header1[6] = mpdu[6];
+ mic_header1[7] = mpdu[7];
+ mic_header1[8] = mpdu[8];
+ mic_header1[9] = mpdu[9];
+ mic_header1[10] = mpdu[10]; /* A2 */
+ mic_header1[11] = mpdu[11];
+ mic_header1[12] = mpdu[12];
+ mic_header1[13] = mpdu[13];
+ mic_header1[14] = mpdu[14];
+ mic_header1[15] = mpdu[15];
+_func_exit_;
+}
+
+/************************************************/
+/* construct_mic_header2() */
+/* Builds the last MIC header block from */
+/* header fields. */
+/************************************************/
+static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, int qc_exists)
+{
+ int i;
+_func_enter_;
+ for (i = 0; i < 16; i++)
+ mic_header2[i] = 0x00;
+
+ mic_header2[0] = mpdu[16]; /* A3 */
+ mic_header2[1] = mpdu[17];
+ mic_header2[2] = mpdu[18];
+ mic_header2[3] = mpdu[19];
+ mic_header2[4] = mpdu[20];
+ mic_header2[5] = mpdu[21];
+
+ mic_header2[6] = 0x00;
+ mic_header2[7] = 0x00; /* mpdu[23]; */
+
+ if (!qc_exists && a4_exists) {
+ for (i = 0; i < 6; i++)
+ mic_header2[8+i] = mpdu[24+i]; /* A4 */
+ }
+
+ if (qc_exists && !a4_exists) {
+ mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */
+ mic_header2[9] = mpdu[25] & 0x00;
+ }
+
+ if (qc_exists && a4_exists) {
+ for (i = 0; i < 6; i++)
+ mic_header2[8+i] = mpdu[24+i]; /* A4 */
+
+ mic_header2[14] = mpdu[30] & 0x0f;
+ mic_header2[15] = mpdu[31] & 0x00;
+ }
+
+_func_exit_;
+}
+
+/************************************************/
+/* construct_mic_header2() */
+/* Builds the last MIC header block from */
+/* header fields. */
+/************************************************/
+static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, u8 *mpdu, u8 *pn_vector, int c)
+{
+ int i;
+_func_enter_;
+ for (i = 0; i < 16; i++)
+ ctr_preload[i] = 0x00;
+ i = 0;
+
+ ctr_preload[0] = 0x01; /* flag */
+ if (qc_exists && a4_exists)
+ ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */
+ if (qc_exists && !a4_exists)
+ ctr_preload[1] = mpdu[24] & 0x0f;
+
+ for (i = 2; i < 8; i++)
+ ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */
+ for (i = 8; i < 14; i++)
+ ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */
+ ctr_preload[14] = (unsigned char) (c / 256); /* Ctr */
+ ctr_preload[15] = (unsigned char) (c % 256);
+_func_exit_;
+}
+
+/************************************/
+/* bitwise_xor() */
+/* A 128 bit, bitwise exclusive or */
+/************************************/
+static void bitwise_xor(u8 *ina, u8 *inb, u8 *out)
+{
+ int i;
+_func_enter_;
+ for (i = 0; i < 16; i++)
+ out[i] = ina[i] ^ inb[i];
+_func_exit_;
+}
+
+static int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen)
+{
+ uint qc_exists, a4_exists, i, j, payload_remainder,
+ num_blocks, payload_index;
+
+ u8 pn_vector[6];
+ u8 mic_iv[16];
+ u8 mic_header1[16];
+ u8 mic_header2[16];
+ u8 ctr_preload[16];
+
+ /* Intermediate Buffers */
+ u8 chain_buffer[16];
+ u8 aes_out[16];
+ u8 padded_buffer[16];
+ u8 mic[8];
+ uint frtype = GetFrameType(pframe);
+ uint frsubtype = GetFrameSubType(pframe);
+
+_func_enter_;
+ frsubtype = frsubtype>>4;
+
+ _rtw_memset((void *)mic_iv, 0, 16);
+ _rtw_memset((void *)mic_header1, 0, 16);
+ _rtw_memset((void *)mic_header2, 0, 16);
+ _rtw_memset((void *)ctr_preload, 0, 16);
+ _rtw_memset((void *)chain_buffer, 0, 16);
+ _rtw_memset((void *)aes_out, 0, 16);
+ _rtw_memset((void *)padded_buffer, 0, 16);
+
+ if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN))
+ a4_exists = 0;
+ else
+ a4_exists = 1;
+
+ if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) || (frtype == WIFI_DATA_CFACKPOLL)) {
+ qc_exists = 1;
+ if (hdrlen != WLAN_HDR_A3_QOS_LEN)
+ hdrlen += 2;
+ } else if ((frsubtype == 0x08) || (frsubtype == 0x09) || (frsubtype == 0x0a) || (frsubtype == 0x0b)) {
+ if (hdrlen != WLAN_HDR_A3_QOS_LEN)
+ hdrlen += 2;
+ qc_exists = 1;
+ } else {
+ qc_exists = 0;
+ }
+
+ pn_vector[0] = pframe[hdrlen];
+ pn_vector[1] = pframe[hdrlen+1];
+ pn_vector[2] = pframe[hdrlen+4];
+ pn_vector[3] = pframe[hdrlen+5];
+ pn_vector[4] = pframe[hdrlen+6];
+ pn_vector[5] = pframe[hdrlen+7];
+
+ construct_mic_iv(mic_iv, qc_exists, a4_exists, pframe, plen, pn_vector);
+
+ construct_mic_header1(mic_header1, hdrlen, pframe);
+ construct_mic_header2(mic_header2, pframe, a4_exists, qc_exists);
+
+ payload_remainder = plen % 16;
+ num_blocks = plen / 16;
+
+ /* Find start of payload */
+ payload_index = (hdrlen + 8);
+
+ /* Calculate MIC */
+ aes128k128d(key, mic_iv, aes_out);
+ bitwise_xor(aes_out, mic_header1, chain_buffer);
+ aes128k128d(key, chain_buffer, aes_out);
+ bitwise_xor(aes_out, mic_header2, chain_buffer);
+ aes128k128d(key, chain_buffer, aes_out);
+
+ for (i = 0; i < num_blocks; i++) {
+ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);/* bitwise_xor(aes_out, &message[payload_index], chain_buffer); */
+
+ payload_index += 16;
+ aes128k128d(key, chain_buffer, aes_out);
+ }
+
+ /* Add on the final payload block if it needs padding */
+ if (payload_remainder > 0) {
+ for (j = 0; j < 16; j++)
+ padded_buffer[j] = 0x00;
+ for (j = 0; j < payload_remainder; j++)
+ padded_buffer[j] = pframe[payload_index++];/* padded_buffer[j] = message[payload_index++]; */
+ bitwise_xor(aes_out, padded_buffer, chain_buffer);
+ aes128k128d(key, chain_buffer, aes_out);
+ }
+
+ for (j = 0; j < 8; j++)
+ mic[j] = aes_out[j];
+
+ /* Insert MIC into payload */
+ for (j = 0; j < 8; j++)
+ pframe[payload_index+j] = mic[j]; /* message[payload_index+j] = mic[j]; */
+
+ payload_index = hdrlen + 8;
+ for (i = 0; i < num_blocks; i++) {
+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i+1);
+ aes128k128d(key, ctr_preload, aes_out);
+ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
+ for (j = 0; j < 16; j++)
+ pframe[payload_index++] = chain_buffer[j];
+ }
+
+ if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/
+ /* encrypt it and copy the unpadded part back */
+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks+1);
+
+ for (j = 0; j < 16; j++)
+ padded_buffer[j] = 0x00;
+ for (j = 0; j < payload_remainder; j++)
+ padded_buffer[j] = pframe[payload_index+j];
+ aes128k128d(key, ctr_preload, aes_out);
+ bitwise_xor(aes_out, padded_buffer, chain_buffer);
+ for (j = 0; j < payload_remainder; j++)
+ pframe[payload_index++] = chain_buffer[j];
+ }
+ /* Encrypt the MIC */
+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, 0);
+
+ for (j = 0; j < 16; j++)
+ padded_buffer[j] = 0x00;
+ for (j = 0; j < 8; j++)
+ padded_buffer[j] = pframe[j+hdrlen+8+plen];
+
+ aes128k128d(key, ctr_preload, aes_out);
+ bitwise_xor(aes_out, padded_buffer, chain_buffer);
+ for (j = 0; j < 8; j++)
+ pframe[payload_index++] = chain_buffer[j];
+_func_exit_;
+ return _SUCCESS;
+}
+
+u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe)
+{ /* exclude ICV */
+
+ /*static*/
+/* unsigned char message[MAX_MSG_SIZE]; */
+
+ /* Intermediate Buffers */
+ int curfragnum, length;
+ u8 *pframe, *prwskey; /* *payload,*iv */
+ u8 hw_hdr_offset = 0;
+ struct sta_info *stainfo;
+ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+/* uint offset = 0; */
+ u32 res = _SUCCESS;
+_func_enter_;
+
+ if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
+ return _FAIL;
+
+ hw_hdr_offset = TXDESC_SIZE +
+ (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ);
+
+ pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset;
+
+ /* 4 start to encrypt each fragment */
+ if ((pattrib->encrypt == _AES_)) {
+ if (pattrib->psta)
+ stainfo = pattrib->psta;
+ else
+ stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]);
+
+ if (stainfo != NULL) {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo!= NULL!!!\n"));
+
+ if (IS_MCAST(pattrib->ra))
+ prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
+ else
+ prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
+ if ((curfragnum+1) == pattrib->nr_frags) { /* 4 the last fragment */
+ length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
+
+ aes_cipher(prwskey, pattrib->hdrlen, pframe, length);
+ } else{
+ length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ;
+
+ aes_cipher(prwskey, pattrib->hdrlen, pframe, length);
+ pframe += pxmitpriv->frag_len;
+ pframe = (u8 *)RND4((size_t)(pframe));
+ }
+ }
+ } else{
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n"));
+ res = _FAIL;
+ }
+ }
+
+
+_func_exit_;
+ return res;
+}
+
+static int aes_decipher(u8 *key, uint hdrlen,
+ u8 *pframe, uint plen)
+{
+ static u8 message[MAX_MSG_SIZE];
+ uint qc_exists, a4_exists, i, j, payload_remainder,
+ num_blocks, payload_index;
+ int res = _SUCCESS;
+ u8 pn_vector[6];
+ u8 mic_iv[16];
+ u8 mic_header1[16];
+ u8 mic_header2[16];
+ u8 ctr_preload[16];
+
+ /* Intermediate Buffers */
+ u8 chain_buffer[16];
+ u8 aes_out[16];
+ u8 padded_buffer[16];
+ u8 mic[8];
+
+/* uint offset = 0; */
+ uint frtype = GetFrameType(pframe);
+ uint frsubtype = GetFrameSubType(pframe);
+_func_enter_;
+ frsubtype = frsubtype>>4;
+
+ _rtw_memset((void *)mic_iv, 0, 16);
+ _rtw_memset((void *)mic_header1, 0, 16);
+ _rtw_memset((void *)mic_header2, 0, 16);
+ _rtw_memset((void *)ctr_preload, 0, 16);
+ _rtw_memset((void *)chain_buffer, 0, 16);
+ _rtw_memset((void *)aes_out, 0, 16);
+ _rtw_memset((void *)padded_buffer, 0, 16);
+
+ /* start to decrypt the payload */
+
+ num_blocks = (plen-8) / 16; /* plen including llc, payload_length and mic) */
+
+ payload_remainder = (plen-8) % 16;
+
+ pn_vector[0] = pframe[hdrlen];
+ pn_vector[1] = pframe[hdrlen+1];
+ pn_vector[2] = pframe[hdrlen+4];
+ pn_vector[3] = pframe[hdrlen+5];
+ pn_vector[4] = pframe[hdrlen+6];
+ pn_vector[5] = pframe[hdrlen+7];
+
+ if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN))
+ a4_exists = 0;
+ else
+ a4_exists = 1;
+
+ if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) ||
+ (frtype == WIFI_DATA_CFACKPOLL)) {
+ qc_exists = 1;
+ if (hdrlen != WLAN_HDR_A3_QOS_LEN)
+ hdrlen += 2;
+ } else if ((frsubtype == 0x08) || (frsubtype == 0x09) ||
+ (frsubtype == 0x0a) || (frsubtype == 0x0b)) {
+ if (hdrlen != WLAN_HDR_A3_QOS_LEN)
+ hdrlen += 2;
+ qc_exists = 1;
+ } else {
+ qc_exists = 0;
+ }
+
+ /* now, decrypt pframe with hdrlen offset and plen long */
+
+ payload_index = hdrlen + 8; /* 8 is for extiv */
+
+ for (i = 0; i < num_blocks; i++) {
+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i+1);
+
+ aes128k128d(key, ctr_preload, aes_out);
+ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
+
+ for (j = 0; j < 16; j++)
+ pframe[payload_index++] = chain_buffer[j];
+ }
+
+ if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/
+ /* encrypt it and copy the unpadded part back */
+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks+1);
+
+ for (j = 0; j < 16; j++)
+ padded_buffer[j] = 0x00;
+ for (j = 0; j < payload_remainder; j++)
+ padded_buffer[j] = pframe[payload_index+j];
+ aes128k128d(key, ctr_preload, aes_out);
+ bitwise_xor(aes_out, padded_buffer, chain_buffer);
+ for (j = 0; j < payload_remainder; j++)
+ pframe[payload_index++] = chain_buffer[j];
+ }
+
+ /* start to calculate the mic */
+ if ((hdrlen+plen+8) <= MAX_MSG_SIZE)
+ memcpy(message, pframe, (hdrlen + plen+8)); /* 8 is for ext iv len */
+
+ pn_vector[0] = pframe[hdrlen];
+ pn_vector[1] = pframe[hdrlen+1];
+ pn_vector[2] = pframe[hdrlen+4];
+ pn_vector[3] = pframe[hdrlen+5];
+ pn_vector[4] = pframe[hdrlen+6];
+ pn_vector[5] = pframe[hdrlen+7];
+ construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen-8, pn_vector);
+
+ construct_mic_header1(mic_header1, hdrlen, message);
+ construct_mic_header2(mic_header2, message, a4_exists, qc_exists);
+
+ payload_remainder = (plen-8) % 16;
+ num_blocks = (plen-8) / 16;
+
+ /* Find start of payload */
+ payload_index = (hdrlen + 8);
+
+ /* Calculate MIC */
+ aes128k128d(key, mic_iv, aes_out);
+ bitwise_xor(aes_out, mic_header1, chain_buffer);
+ aes128k128d(key, chain_buffer, aes_out);
+ bitwise_xor(aes_out, mic_header2, chain_buffer);
+ aes128k128d(key, chain_buffer, aes_out);
+
+ for (i = 0; i < num_blocks; i++) {
+ bitwise_xor(aes_out, &message[payload_index], chain_buffer);
+
+ payload_index += 16;
+ aes128k128d(key, chain_buffer, aes_out);
+ }
+
+ /* Add on the final payload block if it needs padding */
+ if (payload_remainder > 0) {
+ for (j = 0; j < 16; j++)
+ padded_buffer[j] = 0x00;
+ for (j = 0; j < payload_remainder; j++)
+ padded_buffer[j] = message[payload_index++];
+ bitwise_xor(aes_out, padded_buffer, chain_buffer);
+ aes128k128d(key, chain_buffer, aes_out);
+ }
+
+ for (j = 0 ; j < 8; j++)
+ mic[j] = aes_out[j];
+
+ /* Insert MIC into payload */
+ for (j = 0; j < 8; j++)
+ message[payload_index+j] = mic[j];
+
+ payload_index = hdrlen + 8;
+ for (i = 0; i < num_blocks; i++) {
+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, i+1);
+ aes128k128d(key, ctr_preload, aes_out);
+ bitwise_xor(aes_out, &message[payload_index], chain_buffer);
+ for (j = 0; j < 16; j++)
+ message[payload_index++] = chain_buffer[j];
+ }
+
+ if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/
+ /* encrypt it and copy the unpadded part back */
+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, num_blocks+1);
+
+ for (j = 0; j < 16; j++)
+ padded_buffer[j] = 0x00;
+ for (j = 0; j < payload_remainder; j++)
+ padded_buffer[j] = message[payload_index+j];
+ aes128k128d(key, ctr_preload, aes_out);
+ bitwise_xor(aes_out, padded_buffer, chain_buffer);
+ for (j = 0; j < payload_remainder; j++)
+ message[payload_index++] = chain_buffer[j];
+ }
+
+ /* Encrypt the MIC */
+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, 0);
+
+ for (j = 0; j < 16; j++)
+ padded_buffer[j] = 0x00;
+ for (j = 0; j < 8; j++)
+ padded_buffer[j] = message[j+hdrlen+8+plen-8];
+
+ aes128k128d(key, ctr_preload, aes_out);
+ bitwise_xor(aes_out, padded_buffer, chain_buffer);
+ for (j = 0; j < 8; j++)
+ message[payload_index++] = chain_buffer[j];
+
+ /* compare the mic */
+ for (i = 0; i < 8; i++) {
+ if (pframe[hdrlen+8+plen-8+i] != message[hdrlen+8+plen-8+i]) {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+ ("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n",
+ i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]));
+ DBG_88E("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n",
+ i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]);
+ res = _FAIL;
+ }
+ }
+_func_exit_;
+ return res;
+}
+
+u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe)
+{ /* exclude ICV */
+ /* Intermediate Buffers */
+ int length;
+ u8 *pframe, *prwskey; /* *payload,*iv */
+ struct sta_info *stainfo;
+ struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ u32 res = _SUCCESS;
+_func_enter_;
+ pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
+ /* 4 start to encrypt each fragment */
+ if ((prxattrib->encrypt == _AES_)) {
+ stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
+ if (stainfo != NULL) {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo!= NULL!!!\n"));
+
+ if (IS_MCAST(prxattrib->ra)) {
+ /* in concurrent we should use sw descrypt in group key, so we remove this message */
+ if (!psecuritypriv->binstallGrpkey) {
+ res = _FAIL;
+ DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__);
+ goto exit;
+ }
+ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
+ if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) {
+ DBG_88E("not match packet_index=%d, install_index=%d\n",
+ prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid);
+ res = _FAIL;
+ goto exit;
+ }
+ } else {
+ prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+ }
+ length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
+ res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length);
+ } else {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n"));
+ res = _FAIL;
+ }
+ }
+_func_exit_;
+exit:
+ return res;
+}
+
+/* AES tables*/
+const u32 Te0[256] = {
+ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+ 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+ 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+ 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+ 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+ 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+ 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+ 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+ 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+ 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+ 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+ 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+ 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+ 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+ 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+ 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+ 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+ 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+ 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+ 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+ 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+ 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+ 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+ 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+ 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+ 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+ 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+ 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+ 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+ 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+ 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+ 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+ 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+ 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+ 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+ 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+ 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+ 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+ 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+ 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+ 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+ 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+ 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+ 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+ 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+ 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+ 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+ 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+ 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+ 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+ 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+ 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+
+const u32 Td0[256] = {
+ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+ 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+ 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+ 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+ 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+ 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+ 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+ 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+ 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+ 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+ 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+ 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+ 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+ 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+ 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+ 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+ 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+ 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+ 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+ 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+ 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+ 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+ 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+ 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+ 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+ 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+ 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+ 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+ 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+ 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+ 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+ 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+ 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+ 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+ 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+ 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+ 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+ 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+ 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+ 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+ 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+ 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+ 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+ 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+ 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+ 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+ 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+ 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+ 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+ 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+ 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+ 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+
+const u8 Td4s[256] = {
+ 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
+ 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
+ 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
+ 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
+ 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
+ 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
+ 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
+ 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
+ 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
+ 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
+ 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
+ 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
+ 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
+ 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
+ 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
+ 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
+ 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
+ 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
+ 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
+ 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
+ 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
+ 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
+ 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
+ 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
+ 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
+ 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
+ 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
+ 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
+ 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
+ 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
+ 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
+ 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
+};
+const u8 rcons[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+ /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+#define ROUND(i, d, s) \
+do { \
+ d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
+ d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
+ d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
+ d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]; \
+} while (0);
+
+/**
+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * @key: 128-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+void rtw_use_tkipkey_handler(void *FunctionContext)
+{
+ struct adapter *padapter = (struct adapter *)FunctionContext;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("^^^rtw_use_tkipkey_handler ^^^\n"));
+
+ padapter->securitypriv.busetkipkey = true;
+
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("^^^rtw_use_tkipkey_handler padapter->securitypriv.busetkipkey=%d^^^\n", padapter->securitypriv.busetkipkey));
+
+_func_exit_;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_sreset.c b/drivers/staging/rtl8188eu/core/rtw_sreset.c
new file mode 100644
index 00000000000..298f75400c8
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_sreset.c
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#include <rtw_sreset.h>
+
+void sreset_init_value(struct adapter *padapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+ struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+ _rtw_mutex_init(&psrtpriv->silentreset_mutex);
+ psrtpriv->silent_reset_inprogress = false;
+ psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
+ psrtpriv->last_tx_time = 0;
+ psrtpriv->last_tx_complete_time = 0;
+}
+void sreset_reset_value(struct adapter *padapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+ struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+ psrtpriv->silent_reset_inprogress = false;
+ psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
+ psrtpriv->last_tx_time = 0;
+ psrtpriv->last_tx_complete_time = 0;
+}
+
+u8 sreset_get_wifi_status(struct adapter *padapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+ struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+ u8 status = WIFI_STATUS_SUCCESS;
+ u32 val32 = 0;
+
+ if (psrtpriv->silent_reset_inprogress)
+ return status;
+ val32 = rtw_read32(padapter, REG_TXDMA_STATUS);
+ if (val32 == 0xeaeaeaea) {
+ psrtpriv->Wifi_Error_Status = WIFI_IF_NOT_EXIST;
+ } else if (val32 != 0) {
+ DBG_88E("txdmastatu(%x)\n", val32);
+ psrtpriv->Wifi_Error_Status = WIFI_MAC_TXDMA_ERROR;
+ }
+
+ if (WIFI_STATUS_SUCCESS != psrtpriv->Wifi_Error_Status) {
+ DBG_88E("==>%s error_status(0x%x)\n", __func__, psrtpriv->Wifi_Error_Status);
+ status = (psrtpriv->Wifi_Error_Status & (~(USB_READ_PORT_FAIL|USB_WRITE_PORT_FAIL)));
+ }
+ DBG_88E("==> %s wifi_status(0x%x)\n", __func__, status);
+
+ /* status restore */
+ psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
+
+ return status;
+}
+
+void sreset_set_wifi_error_status(struct adapter *padapter, u32 status)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+ pHalData->srestpriv.Wifi_Error_Status = status;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
new file mode 100644
index 00000000000..c2977be92fb
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
@@ -0,0 +1,655 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_STA_MGT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+#include <mlme_osdep.h>
+#include <sta_info.h>
+
+static void _rtw_init_stainfo(struct sta_info *psta)
+{
+_func_enter_;
+ _rtw_memset((u8 *)psta, 0, sizeof (struct sta_info));
+
+ _rtw_spinlock_init(&psta->lock);
+ _rtw_init_listhead(&psta->list);
+ _rtw_init_listhead(&psta->hash_list);
+ _rtw_init_queue(&psta->sleep_q);
+ psta->sleepq_len = 0;
+
+ _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv);
+ _rtw_init_sta_recv_priv(&psta->sta_recvpriv);
+
+#ifdef CONFIG_88EU_AP_MODE
+
+ _rtw_init_listhead(&psta->asoc_list);
+
+ _rtw_init_listhead(&psta->auth_list);
+
+ psta->expire_to = 0;
+
+ psta->flags = 0;
+
+ psta->capability = 0;
+
+ psta->bpairwise_key_installed = false;
+
+#ifdef CONFIG_88EU_AP_MODE
+ psta->nonerp_set = 0;
+ psta->no_short_slot_time_set = 0;
+ psta->no_short_preamble_set = 0;
+ psta->no_ht_gf_set = 0;
+ psta->no_ht_set = 0;
+ psta->ht_20mhz_set = 0;
+#endif
+
+ psta->under_exist_checking = 0;
+
+ psta->keep_alive_trycnt = 0;
+
+#endif /* CONFIG_88EU_AP_MODE */
+
+_func_exit_;
+}
+
+u32 _rtw_init_sta_priv(struct sta_priv *pstapriv)
+{
+ struct sta_info *psta;
+ s32 i;
+
+_func_enter_;
+
+ pstapriv->pallocated_stainfo_buf = rtw_zvmalloc(sizeof(struct sta_info) * NUM_STA + 4);
+
+ if (!pstapriv->pallocated_stainfo_buf)
+ return _FAIL;
+
+ pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 -
+ ((size_t)(pstapriv->pallocated_stainfo_buf) & 3);
+
+ _rtw_init_queue(&pstapriv->free_sta_queue);
+
+ _rtw_spinlock_init(&pstapriv->sta_hash_lock);
+
+ pstapriv->asoc_sta_count = 0;
+ _rtw_init_queue(&pstapriv->sleep_q);
+ _rtw_init_queue(&pstapriv->wakeup_q);
+
+ psta = (struct sta_info *)(pstapriv->pstainfo_buf);
+
+ for (i = 0; i < NUM_STA; i++) {
+ _rtw_init_stainfo(psta);
+
+ _rtw_init_listhead(&(pstapriv->sta_hash[i]));
+
+ rtw_list_insert_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue));
+
+ psta++;
+ }
+
+#ifdef CONFIG_88EU_AP_MODE
+
+ pstapriv->sta_dz_bitmap = 0;
+ pstapriv->tim_bitmap = 0;
+
+ _rtw_init_listhead(&pstapriv->asoc_list);
+ _rtw_init_listhead(&pstapriv->auth_list);
+ _rtw_spinlock_init(&pstapriv->asoc_list_lock);
+ _rtw_spinlock_init(&pstapriv->auth_list_lock);
+ pstapriv->asoc_list_cnt = 0;
+ pstapriv->auth_list_cnt = 0;
+
+ pstapriv->auth_to = 3; /* 3*2 = 6 sec */
+ pstapriv->assoc_to = 3;
+ pstapriv->expire_to = 3; /* 3*2 = 6 sec */
+ pstapriv->max_num_sta = NUM_STA;
+#endif
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta)
+{
+ int offset = (((u8 *)sta) - stapriv->pstainfo_buf)/sizeof(struct sta_info);
+
+ if (!stainfo_offset_valid(offset))
+ DBG_88E("%s invalid offset(%d), out of range!!!", __func__, offset);
+
+ return offset;
+}
+
+inline struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset)
+{
+ if (!stainfo_offset_valid(offset))
+ DBG_88E("%s invalid offset(%d), out of range!!!", __func__, offset);
+
+ return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info));
+}
+
+void _rtw_free_sta_xmit_priv_lock(struct sta_xmit_priv *psta_xmitpriv);
+void _rtw_free_sta_xmit_priv_lock(struct sta_xmit_priv *psta_xmitpriv)
+{
+_func_enter_;
+
+ _rtw_spinlock_free(&psta_xmitpriv->lock);
+
+ _rtw_spinlock_free(&(psta_xmitpriv->be_q.sta_pending.lock));
+ _rtw_spinlock_free(&(psta_xmitpriv->bk_q.sta_pending.lock));
+ _rtw_spinlock_free(&(psta_xmitpriv->vi_q.sta_pending.lock));
+ _rtw_spinlock_free(&(psta_xmitpriv->vo_q.sta_pending.lock));
+_func_exit_;
+}
+
+static void _rtw_free_sta_recv_priv_lock(struct sta_recv_priv *psta_recvpriv)
+{
+_func_enter_;
+
+ _rtw_spinlock_free(&psta_recvpriv->lock);
+
+ _rtw_spinlock_free(&(psta_recvpriv->defrag_q.lock));
+
+_func_exit_;
+}
+
+void rtw_mfree_stainfo(struct sta_info *psta);
+void rtw_mfree_stainfo(struct sta_info *psta)
+{
+_func_enter_;
+
+ if (&psta->lock != NULL)
+ _rtw_spinlock_free(&psta->lock);
+
+ _rtw_free_sta_xmit_priv_lock(&psta->sta_xmitpriv);
+ _rtw_free_sta_recv_priv_lock(&psta->sta_recvpriv);
+
+_func_exit_;
+}
+
+/* this function is used to free the memory of lock || sema for all stainfos */
+void rtw_mfree_all_stainfo(struct sta_priv *pstapriv);
+void rtw_mfree_all_stainfo(struct sta_priv *pstapriv)
+{
+ unsigned long irql;
+ struct list_head *plist, *phead;
+ struct sta_info *psta = NULL;
+
+_func_enter_;
+
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irql);
+
+ phead = get_list_head(&pstapriv->free_sta_queue);
+ plist = get_next(phead);
+
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info , list);
+ plist = get_next(plist);
+
+ rtw_mfree_stainfo(psta);
+ }
+
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irql);
+
+_func_exit_;
+}
+
+static void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv)
+{
+#ifdef CONFIG_88EU_AP_MODE
+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+#endif
+
+ rtw_mfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */
+
+ _rtw_spinlock_free(&pstapriv->free_sta_queue.lock);
+
+ _rtw_spinlock_free(&pstapriv->sta_hash_lock);
+ _rtw_spinlock_free(&pstapriv->wakeup_q.lock);
+ _rtw_spinlock_free(&pstapriv->sleep_q.lock);
+
+#ifdef CONFIG_88EU_AP_MODE
+ _rtw_spinlock_free(&pstapriv->asoc_list_lock);
+ _rtw_spinlock_free(&pstapriv->auth_list_lock);
+ _rtw_spinlock_free(&pacl_list->acl_node_q.lock);
+#endif
+}
+
+u32 _rtw_free_sta_priv(struct sta_priv *pstapriv)
+{
+ unsigned long irql;
+ struct list_head *phead, *plist;
+ struct sta_info *psta = NULL;
+ struct recv_reorder_ctrl *preorder_ctrl;
+ int index;
+
+_func_enter_;
+ if (pstapriv) {
+ /* delete all reordering_ctrl_timer */
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irql);
+ for (index = 0; index < NUM_STA; index++) {
+ phead = &(pstapriv->sta_hash[index]);
+ plist = get_next(phead);
+
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ int i;
+ psta = LIST_CONTAINOR(plist, struct sta_info , hash_list);
+ plist = get_next(plist);
+
+ for (i = 0; i < 16; i++) {
+ preorder_ctrl = &psta->recvreorder_ctrl[i];
+ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
+ }
+ }
+ }
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irql);
+ /*===============================*/
+
+ rtw_mfree_sta_priv_lock(pstapriv);
+
+ if (pstapriv->pallocated_stainfo_buf) {
+ rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info)*NUM_STA+4);
+ }
+ }
+
+_func_exit_;
+ return _SUCCESS;
+}
+
+struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
+{
+ unsigned long irql, irql2;
+ s32 index;
+ struct list_head *phash_list;
+ struct sta_info *psta;
+ struct __queue *pfree_sta_queue;
+ struct recv_reorder_ctrl *preorder_ctrl;
+ int i = 0;
+ u16 wRxSeqInitialValue = 0xffff;
+
+_func_enter_;
+
+ pfree_sta_queue = &pstapriv->free_sta_queue;
+
+ _enter_critical_bh(&(pfree_sta_queue->lock), &irql);
+
+ if (_rtw_queue_empty(pfree_sta_queue) == true) {
+ _exit_critical_bh(&(pfree_sta_queue->lock), &irql);
+ psta = NULL;
+ } else {
+ psta = LIST_CONTAINOR(get_next(&pfree_sta_queue->queue), struct sta_info, list);
+ rtw_list_delete(&(psta->list));
+ _exit_critical_bh(&(pfree_sta_queue->lock), &irql);
+ _rtw_init_stainfo(psta);
+ memcpy(psta->hwaddr, hwaddr, ETH_ALEN);
+ index = wifi_mac_hash(hwaddr);
+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("rtw_alloc_stainfo: index=%x", index));
+ if (index >= NUM_STA) {
+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("ERROR => rtw_alloc_stainfo: index >= NUM_STA"));
+ psta = NULL;
+ goto exit;
+ }
+ phash_list = &(pstapriv->sta_hash[index]);
+
+ _enter_critical_bh(&(pstapriv->sta_hash_lock), &irql2);
+
+ rtw_list_insert_tail(&psta->hash_list, phash_list);
+
+ pstapriv->asoc_sta_count++ ;
+
+ _exit_critical_bh(&(pstapriv->sta_hash_lock), &irql2);
+
+/* Commented by Albert 2009/08/13 */
+/* For the SMC router, the sequence number of first packet of WPS handshake will be 0. */
+/* In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */
+/* So, we initialize the tid_rxseq variable as the 0xffff. */
+
+ for (i = 0; i < 16; i++)
+ memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2);
+
+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_,
+ ("alloc number_%d stainfo with hwaddr = %pM\n",
+ pstapriv->asoc_sta_count , hwaddr));
+
+ init_addba_retry_timer(pstapriv->padapter, psta);
+
+ /* for A-MPDU Rx reordering buffer control */
+ for (i = 0; i < 16; i++) {
+ preorder_ctrl = &psta->recvreorder_ctrl[i];
+
+ preorder_ctrl->padapter = pstapriv->padapter;
+
+ preorder_ctrl->enable = false;
+
+ preorder_ctrl->indicate_seq = 0xffff;
+ preorder_ctrl->wend_b = 0xffff;
+ preorder_ctrl->wsize_b = 64;/* 64; */
+
+ _rtw_init_queue(&preorder_ctrl->pending_recvframe_queue);
+
+ rtw_init_recv_timer(preorder_ctrl);
+ }
+
+ /* init for DM */
+ psta->rssi_stat.UndecoratedSmoothedPWDB = (-1);
+ psta->rssi_stat.UndecoratedSmoothedCCK = (-1);
+
+ /* init for the sequence number of received management frame */
+ psta->RxMgmtFrameSeqNum = 0xffff;
+ }
+
+exit:
+
+_func_exit_;
+
+ return psta;
+}
+
+/* using pstapriv->sta_hash_lock to protect */
+u32 rtw_free_stainfo(struct adapter *padapter , struct sta_info *psta)
+{
+ int i;
+ unsigned long irql0;
+ struct __queue *pfree_sta_queue;
+ struct recv_reorder_ctrl *preorder_ctrl;
+ struct sta_xmit_priv *pstaxmitpriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+_func_enter_;
+
+ if (psta == NULL)
+ goto exit;
+
+ pfree_sta_queue = &pstapriv->free_sta_queue;
+
+ pstaxmitpriv = &psta->sta_xmitpriv;
+
+ _enter_critical_bh(&pxmitpriv->lock, &irql0);
+
+ rtw_free_xmitframe_queue(pxmitpriv, &psta->sleep_q);
+ psta->sleepq_len = 0;
+
+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending);
+
+ rtw_list_delete(&(pstaxmitpriv->vo_q.tx_pending));
+
+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending);
+
+ rtw_list_delete(&(pstaxmitpriv->vi_q.tx_pending));
+
+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending);
+
+ rtw_list_delete(&(pstaxmitpriv->bk_q.tx_pending));
+
+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending);
+
+ rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending));
+
+ _exit_critical_bh(&pxmitpriv->lock, &irql0);
+
+ rtw_list_delete(&psta->hash_list);
+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("\n free number_%d stainfo with hwaddr=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", pstapriv->asoc_sta_count , psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4], psta->hwaddr[5]));
+ pstapriv->asoc_sta_count--;
+
+ /* re-init sta_info; 20061114 */
+ _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv);
+ _rtw_init_sta_recv_priv(&psta->sta_recvpriv);
+
+ _cancel_timer_ex(&psta->addba_retry_timer);
+
+ /* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */
+ for (i = 0; i < 16 ; i++) {
+ unsigned long irql;
+ struct list_head *phead, *plist;
+ union recv_frame *prframe;
+ struct __queue *ppending_recvframe_queue;
+ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+
+ preorder_ctrl = &psta->recvreorder_ctrl[i];
+
+ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
+
+ ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+ _enter_critical_bh(&ppending_recvframe_queue->lock, &irql);
+
+ phead = get_list_head(ppending_recvframe_queue);
+ plist = get_next(phead);
+
+ while (!rtw_is_list_empty(phead)) {
+ prframe = LIST_CONTAINOR(plist, union recv_frame, u);
+
+ plist = get_next(plist);
+
+ rtw_list_delete(&(prframe->u.hdr.list));
+
+ rtw_free_recvframe(prframe, pfree_recv_queue);
+ }
+
+ _exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+ }
+
+ if (!(psta->state & WIFI_AP_STATE))
+ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, false);
+
+#ifdef CONFIG_88EU_AP_MODE
+
+ _enter_critical_bh(&pstapriv->auth_list_lock, &irql0);
+ if (!rtw_is_list_empty(&psta->auth_list)) {
+ rtw_list_delete(&psta->auth_list);
+ pstapriv->auth_list_cnt--;
+ }
+ _exit_critical_bh(&pstapriv->auth_list_lock, &irql0);
+
+ psta->expire_to = 0;
+
+ psta->sleepq_ac_len = 0;
+ psta->qos_info = 0;
+
+ psta->max_sp_len = 0;
+ psta->uapsd_bk = 0;
+ psta->uapsd_be = 0;
+ psta->uapsd_vi = 0;
+ psta->uapsd_vo = 0;
+ psta->has_legacy_ac = 0;
+
+ pstapriv->sta_dz_bitmap &= ~BIT(psta->aid);
+ pstapriv->tim_bitmap &= ~BIT(psta->aid);
+
+ if ((psta->aid > 0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) {
+ pstapriv->sta_aid[psta->aid - 1] = NULL;
+ psta->aid = 0;
+ }
+
+ psta->under_exist_checking = 0;
+
+#endif /* CONFIG_88EU_AP_MODE */
+
+ _enter_critical_bh(&(pfree_sta_queue->lock), &irql0);
+ rtw_list_insert_tail(&psta->list, get_list_head(pfree_sta_queue));
+ _exit_critical_bh(&(pfree_sta_queue->lock), &irql0);
+
+exit:
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+/* free all stainfo which in sta_hash[all] */
+void rtw_free_all_stainfo(struct adapter *padapter)
+{
+ unsigned long irql;
+ struct list_head *plist, *phead;
+ s32 index;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct sta_info *pbcmc_stainfo = rtw_get_bcmc_stainfo(padapter);
+
+_func_enter_;
+
+ if (pstapriv->asoc_sta_count == 1)
+ goto exit;
+
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irql);
+
+ for (index = 0; index < NUM_STA; index++) {
+ phead = &(pstapriv->sta_hash[index]);
+ plist = get_next(phead);
+
+ while ((!rtw_end_of_queue_search(phead, plist))) {
+ psta = LIST_CONTAINOR(plist, struct sta_info , hash_list);
+
+ plist = get_next(plist);
+
+ if (pbcmc_stainfo != psta)
+ rtw_free_stainfo(padapter , psta);
+ }
+ }
+
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irql);
+
+exit:
+
+_func_exit_;
+}
+
+/* any station allocated can be searched by hash list */
+struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
+{
+ unsigned long irql;
+ struct list_head *plist, *phead;
+ struct sta_info *psta = NULL;
+ u32 index;
+ u8 *addr;
+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+_func_enter_;
+
+ if (hwaddr == NULL)
+ return NULL;
+
+ if (IS_MCAST(hwaddr))
+ addr = bc_addr;
+ else
+ addr = hwaddr;
+
+ index = wifi_mac_hash(addr);
+
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irql);
+
+ phead = &(pstapriv->sta_hash[index]);
+ plist = get_next(phead);
+
+ while ((!rtw_end_of_queue_search(phead, plist))) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+ if ((_rtw_memcmp(psta->hwaddr, addr, ETH_ALEN)) == true) {
+ /* if found the matched address */
+ break;
+ }
+ psta = NULL;
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irql);
+_func_exit_;
+ return psta;
+}
+
+u32 rtw_init_bcmc_stainfo(struct adapter *padapter)
+{
+ struct sta_info *psta;
+ u32 res = _SUCCESS;
+ unsigned char bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+_func_enter_;
+
+ psta = rtw_alloc_stainfo(pstapriv, bcast_addr);
+
+ if (psta == NULL) {
+ res = _FAIL;
+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("rtw_alloc_stainfo fail"));
+ goto exit;
+ }
+
+ /* default broadcast & multicast use macid 1 */
+ psta->mac_id = 1;
+
+exit:
+_func_exit_;
+ return res;
+}
+
+struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter)
+{
+ struct sta_info *psta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+_func_enter_;
+ psta = rtw_get_stainfo(pstapriv, bc_addr);
+_func_exit_;
+ return psta;
+}
+
+u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr)
+{
+ u8 res = true;
+#ifdef CONFIG_88EU_AP_MODE
+ unsigned long irql;
+ struct list_head *plist, *phead;
+ struct rtw_wlan_acl_node *paclnode;
+ u8 match = false;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+ struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+ _enter_critical_bh(&(pacl_node_q->lock), &irql);
+ phead = get_list_head(pacl_node_q);
+ plist = get_next(phead);
+ while ((!rtw_end_of_queue_search(phead, plist))) {
+ paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+ plist = get_next(plist);
+
+ if (_rtw_memcmp(paclnode->addr, mac_addr, ETH_ALEN)) {
+ if (paclnode->valid) {
+ match = true;
+ break;
+ }
+ }
+ }
+ _exit_critical_bh(&(pacl_node_q->lock), &irql);
+
+ if (pacl_list->mode == 1)/* accept unless in deny list */
+ res = (match) ? false : true;
+ else if (pacl_list->mode == 2)/* deny unless in accept list */
+ res = (match) ? true : false;
+ else
+ res = true;
+
+#endif
+
+ return res;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
new file mode 100644
index 00000000000..013ea487e7a
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
@@ -0,0 +1,1689 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_WLAN_UTIL_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+
+static unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f};
+static unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74};
+
+static unsigned char BROADCOM_OUI1[] = {0x00, 0x10, 0x18};
+static unsigned char BROADCOM_OUI2[] = {0x00, 0x0a, 0xf7};
+
+static unsigned char CISCO_OUI[] = {0x00, 0x40, 0x96};
+static unsigned char MARVELL_OUI[] = {0x00, 0x50, 0x43};
+static unsigned char RALINK_OUI[] = {0x00, 0x0c, 0x43};
+static unsigned char REALTEK_OUI[] = {0x00, 0xe0, 0x4c};
+static unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5};
+static unsigned char EPIGRAM_OUI[] = {0x00, 0x90, 0x4c};
+
+unsigned char REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20};
+
+#define R2T_PHY_DELAY (0)
+
+/* define WAIT_FOR_BCN_TO_M (3000) */
+#define WAIT_FOR_BCN_TO_MIN (6000)
+#define WAIT_FOR_BCN_TO_MAX (20000)
+
+static u8 rtw_basic_rate_cck[4] = {
+ IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK,
+ IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK
+};
+
+static u8 rtw_basic_rate_ofdm[3] = {
+ IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK,
+ IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK
+};
+
+static u8 rtw_basic_rate_mix[7] = {
+ IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK,
+ IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK,
+ IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK,
+ IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK
+};
+
+int cckrates_included(unsigned char *rate, int ratelen)
+{
+ int i;
+
+ for (i = 0; i < ratelen; i++) {
+ if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) ||
+ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22))
+ return true;
+ }
+ return false;
+}
+
+int cckratesonly_included(unsigned char *rate, int ratelen)
+{
+ int i;
+
+ for (i = 0; i < ratelen; i++) {
+ if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
+ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22))
+ return false;
+ }
+
+ return true;
+}
+
+unsigned char networktype_to_raid(unsigned char network_type)
+{
+ unsigned char raid;
+
+ switch (network_type) {
+ case WIRELESS_11B:
+ raid = RATR_INX_WIRELESS_B;
+ break;
+ case WIRELESS_11A:
+ case WIRELESS_11G:
+ raid = RATR_INX_WIRELESS_G;
+ break;
+ case WIRELESS_11BG:
+ raid = RATR_INX_WIRELESS_GB;
+ break;
+ case WIRELESS_11_24N:
+ case WIRELESS_11_5N:
+ raid = RATR_INX_WIRELESS_N;
+ break;
+ case WIRELESS_11A_5N:
+ case WIRELESS_11G_24N:
+ raid = RATR_INX_WIRELESS_NG;
+ break;
+ case WIRELESS_11BG_24N:
+ raid = RATR_INX_WIRELESS_NGB;
+ break;
+ default:
+ raid = RATR_INX_WIRELESS_GB;
+ break;
+ }
+ return raid;
+}
+
+u8 judge_network_type(struct adapter *padapter, unsigned char *rate, int ratelen)
+{
+ u8 network_type = 0;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if (pmlmeext->cur_channel > 14) {
+ if (pmlmeinfo->HT_enable)
+ network_type = WIRELESS_11_5N;
+
+ network_type |= WIRELESS_11A;
+ } else {
+ if (pmlmeinfo->HT_enable)
+ network_type = WIRELESS_11_24N;
+
+ if ((cckratesonly_included(rate, ratelen)) == true)
+ network_type |= WIRELESS_11B;
+ else if ((cckrates_included(rate, ratelen)) == true)
+ network_type |= WIRELESS_11BG;
+ else
+ network_type |= WIRELESS_11G;
+ }
+ return network_type;
+}
+
+static unsigned char ratetbl_val_2wifirate(unsigned char rate)
+{
+ unsigned char val = 0;
+
+ switch (rate & 0x7f) {
+ case 0:
+ val = IEEE80211_CCK_RATE_1MB;
+ break;
+ case 1:
+ val = IEEE80211_CCK_RATE_2MB;
+ break;
+ case 2:
+ val = IEEE80211_CCK_RATE_5MB;
+ break;
+ case 3:
+ val = IEEE80211_CCK_RATE_11MB;
+ break;
+ case 4:
+ val = IEEE80211_OFDM_RATE_6MB;
+ break;
+ case 5:
+ val = IEEE80211_OFDM_RATE_9MB;
+ break;
+ case 6:
+ val = IEEE80211_OFDM_RATE_12MB;
+ break;
+ case 7:
+ val = IEEE80211_OFDM_RATE_18MB;
+ break;
+ case 8:
+ val = IEEE80211_OFDM_RATE_24MB;
+ break;
+ case 9:
+ val = IEEE80211_OFDM_RATE_36MB;
+ break;
+ case 10:
+ val = IEEE80211_OFDM_RATE_48MB;
+ break;
+ case 11:
+ val = IEEE80211_OFDM_RATE_54MB;
+ break;
+ }
+ return val;
+}
+
+static int is_basicrate(struct adapter *padapter, unsigned char rate)
+{
+ int i;
+ unsigned char val;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ for (i = 0; i < NumRates; i++) {
+ val = pmlmeext->basicrate[i];
+
+ if ((val != 0xff) && (val != 0xfe)) {
+ if (rate == ratetbl_val_2wifirate(val))
+ return true;
+ }
+ }
+ return false;
+}
+
+static unsigned int ratetbl2rateset(struct adapter *padapter, unsigned char *rateset)
+{
+ int i;
+ unsigned char rate;
+ unsigned int len = 0;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ for (i = 0; i < NumRates; i++) {
+ rate = pmlmeext->datarate[i];
+
+ switch (rate) {
+ case 0xff:
+ return len;
+ case 0xfe:
+ continue;
+ default:
+ rate = ratetbl_val_2wifirate(rate);
+
+ if (is_basicrate(padapter, rate) == true)
+ rate |= IEEE80211_BASIC_RATE_MASK;
+
+ rateset[len] = rate;
+ len++;
+ break;
+ }
+ }
+ return len;
+}
+
+void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *bssrate_len)
+{
+ unsigned char supportedrates[NumRates];
+
+ _rtw_memset(supportedrates, 0, NumRates);
+ *bssrate_len = ratetbl2rateset(padapter, supportedrates);
+ memcpy(pbssrate, supportedrates, *bssrate_len);
+}
+
+void UpdateBrateTbl(struct adapter *Adapter, u8 *mbrate)
+{
+ u8 i;
+ u8 rate;
+
+ /* 1M, 2M, 5.5M, 11M, 6M, 12M, 24M are mandatory. */
+ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+ rate = mbrate[i] & 0x7f;
+ switch (rate) {
+ case IEEE80211_CCK_RATE_1MB:
+ case IEEE80211_CCK_RATE_2MB:
+ case IEEE80211_CCK_RATE_5MB:
+ case IEEE80211_CCK_RATE_11MB:
+ case IEEE80211_OFDM_RATE_6MB:
+ case IEEE80211_OFDM_RATE_12MB:
+ case IEEE80211_OFDM_RATE_24MB:
+ mbrate[i] |= IEEE80211_BASIC_RATE_MASK;
+ break;
+ }
+ }
+}
+
+void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen)
+{
+ u8 i;
+ u8 rate;
+
+ for (i = 0; i < bssratelen; i++) {
+ rate = bssrateset[i] & 0x7f;
+ switch (rate) {
+ case IEEE80211_CCK_RATE_1MB:
+ case IEEE80211_CCK_RATE_2MB:
+ case IEEE80211_CCK_RATE_5MB:
+ case IEEE80211_CCK_RATE_11MB:
+ bssrateset[i] |= IEEE80211_BASIC_RATE_MASK;
+ break;
+ }
+ }
+}
+
+void Save_DM_Func_Flag(struct adapter *padapter)
+{
+ u8 saveflag = true;
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&saveflag));
+}
+
+void Restore_DM_Func_Flag(struct adapter *padapter)
+{
+ u8 saveflag = false;
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&saveflag));
+}
+
+void Switch_DM_Func(struct adapter *padapter, u32 mode, u8 enable)
+{
+ if (enable)
+ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_SET, (u8 *)(&mode));
+ else
+ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_CLR, (u8 *)(&mode));
+}
+
+static void Set_NETYPE0_MSR(struct adapter *padapter, u8 type)
+{
+ rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type));
+}
+
+void Set_MSR(struct adapter *padapter, u8 type)
+{
+ Set_NETYPE0_MSR(padapter, type);
+}
+
+inline u8 rtw_get_oper_ch(struct adapter *adapter)
+{
+ return adapter->mlmeextpriv.oper_channel;
+}
+
+inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch)
+{
+ adapter->mlmeextpriv.oper_channel = ch;
+}
+
+inline u8 rtw_get_oper_bw(struct adapter *adapter)
+{
+ return adapter->mlmeextpriv.oper_bwmode;
+}
+
+inline void rtw_set_oper_bw(struct adapter *adapter, u8 bw)
+{
+ adapter->mlmeextpriv.oper_bwmode = bw;
+}
+
+inline u8 rtw_get_oper_choffset(struct adapter *adapter)
+{
+ return adapter->mlmeextpriv.oper_ch_offset;
+}
+
+inline void rtw_set_oper_choffset(struct adapter *adapter, u8 offset)
+{
+ adapter->mlmeextpriv.oper_ch_offset = offset;
+}
+
+void SelectChannel(struct adapter *padapter, unsigned char channel)
+{
+ /* saved channel info */
+ rtw_set_oper_ch(padapter, channel);
+ rtw_hal_set_chan(padapter, channel);
+}
+
+void SetBWMode(struct adapter *padapter, unsigned short bwmode,
+ unsigned char channel_offset)
+{
+ /* saved bw info */
+ rtw_set_oper_bw(padapter, bwmode);
+ rtw_set_oper_choffset(padapter, channel_offset);
+
+ rtw_hal_set_bwmode(padapter, (enum ht_channel_width)bwmode, channel_offset);
+}
+
+void set_channel_bwmode(struct adapter *padapter, unsigned char channel, unsigned char channel_offset, unsigned short bwmode)
+{
+ u8 center_ch;
+
+ if (padapter->bNotifyChannelChange)
+ DBG_88E("[%s] ch = %d, offset = %d, bwmode = %d\n", __func__, channel, channel_offset, bwmode);
+
+ if ((bwmode == HT_CHANNEL_WIDTH_20) ||
+ (channel_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)) {
+ /* SelectChannel(padapter, channel); */
+ center_ch = channel;
+ } else {
+ /* switch to the proper channel */
+ if (channel_offset == HAL_PRIME_CHNL_OFFSET_LOWER) {
+ /* SelectChannel(padapter, channel + 2); */
+ center_ch = channel + 2;
+ } else {
+ /* SelectChannel(padapter, channel - 2); */
+ center_ch = channel - 2;
+ }
+ }
+
+ /* set Channel */
+ /* saved channel/bw info */
+ rtw_set_oper_ch(padapter, channel);
+ rtw_set_oper_bw(padapter, bwmode);
+ rtw_set_oper_choffset(padapter, channel_offset);
+
+ rtw_hal_set_chan(padapter, center_ch); /* set center channel */
+ SetBWMode(padapter, bwmode, channel_offset);
+}
+
+int get_bsstype(unsigned short capability)
+{
+ if (capability & BIT(0))
+ return WIFI_FW_AP_STATE;
+ else if (capability & BIT(1))
+ return WIFI_FW_ADHOC_STATE;
+ else
+ return 0;
+}
+
+__inline u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork)
+{
+ return pnetwork->MacAddress;
+}
+
+u16 get_beacon_interval(struct wlan_bssid_ex *bss)
+{
+ __le16 val;
+ memcpy((unsigned char *)&val, rtw_get_beacon_interval_from_ie(bss->IEs), 2);
+
+ return le16_to_cpu(val);
+}
+
+int is_client_associated_to_ap(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext;
+ struct mlme_ext_info *pmlmeinfo;
+
+ if (!padapter)
+ return _FAIL;
+
+ pmlmeext = &padapter->mlmeextpriv;
+ pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE))
+ return true;
+ else
+ return _FAIL;
+}
+
+int is_client_associated_to_ibss(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE))
+ return true;
+ else
+ return _FAIL;
+}
+
+int is_IBSS_empty(struct adapter *padapter)
+{
+ unsigned int i;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) {
+ if (pmlmeinfo->FW_sta_info[i].status == 1)
+ return _FAIL;
+ }
+ return true;
+}
+
+unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval)
+{
+ if ((bcn_interval << 2) < WAIT_FOR_BCN_TO_MIN)
+ return WAIT_FOR_BCN_TO_MIN;
+ else if ((bcn_interval << 2) > WAIT_FOR_BCN_TO_MAX)
+ return WAIT_FOR_BCN_TO_MAX;
+ else
+ return bcn_interval << 2;
+}
+
+void CAM_empty_entry(struct adapter *Adapter, u8 ucIndex)
+{
+ rtw_hal_set_hwreg(Adapter, HW_VAR_CAM_EMPTY_ENTRY, (u8 *)(&ucIndex));
+}
+
+void invalidate_cam_all(struct adapter *padapter)
+{
+ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, NULL);
+}
+
+void write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key)
+{
+ unsigned int i, val, addr;
+ int j;
+ u32 cam_val[2];
+
+ addr = entry << 3;
+
+ for (j = 5; j >= 0; j--) {
+ switch (j) {
+ case 0:
+ val = (ctrl | (mac[0] << 16) | (mac[1] << 24));
+ break;
+ case 1:
+ val = (mac[2] | (mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24));
+ break;
+ default:
+ i = (j - 2) << 2;
+ val = (key[i] | (key[i+1] << 8) | (key[i+2] << 16) | (key[i+3] << 24));
+ break;
+ }
+
+ cam_val[0] = val;
+ cam_val[1] = addr + (unsigned int)j;
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val);
+ }
+}
+
+void clear_cam_entry(struct adapter *padapter, u8 entry)
+{
+ unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ write_cam(padapter, entry, 0, null_sta, null_key);
+}
+
+int allocate_fw_sta_entry(struct adapter *padapter)
+{
+ unsigned int mac_id;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ for (mac_id = IBSS_START_MAC_ID; mac_id < NUM_STA; mac_id++) {
+ if (pmlmeinfo->FW_sta_info[mac_id].status == 0) {
+ pmlmeinfo->FW_sta_info[mac_id].status = 1;
+ pmlmeinfo->FW_sta_info[mac_id].retry = 0;
+ break;
+ }
+ }
+
+ return mac_id;
+}
+
+void flush_all_cam_entry(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, NULL);
+
+ _rtw_memset((u8 *)(pmlmeinfo->FW_sta_info), 0, sizeof(pmlmeinfo->FW_sta_info));
+}
+
+int WMM_param_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
+{
+ /* struct registry_priv *pregpriv = &padapter->registrypriv; */
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if (pmlmepriv->qospriv.qos_option == 0) {
+ pmlmeinfo->WMM_enable = 0;
+ return _FAIL;
+ }
+
+ pmlmeinfo->WMM_enable = 1;
+ memcpy(&(pmlmeinfo->WMM_param), (pIE->data + 6), sizeof(struct WMM_para_element));
+ return true;
+}
+
+void WMMOnAssocRsp(struct adapter *padapter)
+{
+ u8 ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime;
+ u8 acm_mask;
+ u16 TXOP;
+ u32 acParm, i;
+ u32 edca[4], inx[4];
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+
+ if (pmlmeinfo->WMM_enable == 0) {
+ padapter->mlmepriv.acm_mask = 0;
+ return;
+ }
+
+ acm_mask = 0;
+
+ if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
+ aSifsTime = 10;
+ else
+ aSifsTime = 16;
+
+ for (i = 0; i < 4; i++) {
+ ACI = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 5) & 0x03;
+ ACM = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 4) & 0x01;
+
+ /* AIFS = AIFSN * slot time + SIFS - r2t phy delay */
+ AIFS = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN & 0x0f) * pmlmeinfo->slotTime + aSifsTime;
+
+ ECWMin = (pmlmeinfo->WMM_param.ac_param[i].CW & 0x0f);
+ ECWMax = (pmlmeinfo->WMM_param.ac_param[i].CW & 0xf0) >> 4;
+ TXOP = le16_to_cpu(pmlmeinfo->WMM_param.ac_param[i].TXOP_limit);
+
+ acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+
+ switch (ACI) {
+ case 0x0:
+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm));
+ acm_mask |= (ACM ? BIT(1) : 0);
+ edca[XMIT_BE_QUEUE] = acParm;
+ break;
+ case 0x1:
+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm));
+ edca[XMIT_BK_QUEUE] = acParm;
+ break;
+ case 0x2:
+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm));
+ acm_mask |= (ACM ? BIT(2) : 0);
+ edca[XMIT_VI_QUEUE] = acParm;
+ break;
+ case 0x3:
+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm));
+ acm_mask |= (ACM ? BIT(3) : 0);
+ edca[XMIT_VO_QUEUE] = acParm;
+ break;
+ }
+
+ DBG_88E("WMM(%x): %x, %x\n", ACI, ACM, acParm);
+ }
+
+ if (padapter->registrypriv.acm_method == 1)
+ rtw_hal_set_hwreg(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask));
+ else
+ padapter->mlmepriv.acm_mask = acm_mask;
+
+ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
+
+ if (pregpriv->wifi_spec == 1) {
+ u32 j, tmp, change_inx;
+
+ /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */
+ for (i = 0; i < 4; i++) {
+ for (j = i+1; j < 4; j++) {
+ /* compare CW and AIFS */
+ if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) {
+ change_inx = true;
+ } else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) {
+ /* compare TXOP */
+ if ((edca[j] >> 16) > (edca[i] >> 16))
+ change_inx = true;
+ }
+
+ if (change_inx) {
+ tmp = edca[i];
+ edca[i] = edca[j];
+ edca[j] = tmp;
+
+ tmp = inx[i];
+ inx[i] = inx[j];
+ inx[j] = tmp;
+
+ change_inx = false;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ pxmitpriv->wmm_para_seq[i] = inx[i];
+ DBG_88E("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]);
+ }
+
+ return;
+}
+
+static void bwmode_update_check(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
+{
+ unsigned char new_bwmode;
+ unsigned char new_ch_offset;
+ struct HT_info_element *pHT_info;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+
+ if (!pIE)
+ return;
+
+ if (!phtpriv)
+ return;
+
+ if (pIE->Length > sizeof(struct HT_info_element))
+ return;
+
+ pHT_info = (struct HT_info_element *)pIE->data;
+
+ if ((pHT_info->infos[0] & BIT(2)) && pregistrypriv->cbw40_enable) {
+ new_bwmode = HT_CHANNEL_WIDTH_40;
+
+ switch (pHT_info->infos[0] & 0x3) {
+ case 1:
+ new_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+ break;
+ case 3:
+ new_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+ break;
+ default:
+ new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ }
+ } else {
+ new_bwmode = HT_CHANNEL_WIDTH_20;
+ new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ }
+
+ if ((new_bwmode != pmlmeext->cur_bwmode) ||
+ (new_ch_offset != pmlmeext->cur_ch_offset)) {
+ pmlmeinfo->bwmode_updated = true;
+
+ pmlmeext->cur_bwmode = new_bwmode;
+ pmlmeext->cur_ch_offset = new_ch_offset;
+
+ /* update HT info also */
+ HT_info_handler(padapter, pIE);
+ } else {
+ pmlmeinfo->bwmode_updated = false;
+ }
+
+ if (pmlmeinfo->bwmode_updated) {
+ struct sta_info *psta;
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ /* set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */
+
+ /* update ap's stainfo */
+ psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress);
+ if (psta) {
+ struct ht_priv *phtpriv_sta = &psta->htpriv;
+
+ if (phtpriv_sta->ht_option) {
+ /* bwmode */
+ phtpriv_sta->bwmode = pmlmeext->cur_bwmode;
+ phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
+ } else {
+ phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20;
+ phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ }
+ }
+ }
+}
+
+void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
+{
+ unsigned int i;
+ u8 rf_type;
+ u8 max_AMPDU_len, min_MPDU_spacing;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+
+ if (pIE == NULL)
+ return;
+
+ if (!phtpriv->ht_option)
+ return;
+
+ pmlmeinfo->HT_caps_enable = 1;
+
+ for (i = 0; i < (pIE->Length); i++) {
+ if (i != 2) {
+ /* Got the endian issue here. */
+ pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]);
+ } else {
+ /* modify from fw by Thomas 2010/11/17 */
+ if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3) > (pIE->data[i] & 0x3))
+ max_AMPDU_len = (pIE->data[i] & 0x3);
+ else
+ max_AMPDU_len = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3);
+
+ if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) > (pIE->data[i] & 0x1c))
+ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c);
+ else
+ min_MPDU_spacing = (pIE->data[i] & 0x1c);
+
+ pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para = max_AMPDU_len | min_MPDU_spacing;
+ }
+ }
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+ /* update the MCS rates */
+ for (i = 0; i < 16; i++) {
+ if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R))
+ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i];
+ else
+ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i];
+ }
+ return;
+}
+
+void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+
+ if (pIE == NULL)
+ return;
+
+ if (!phtpriv->ht_option)
+ return;
+
+ if (pIE->Length > sizeof(struct HT_info_element))
+ return;
+
+ pmlmeinfo->HT_info_enable = 1;
+ memcpy(&(pmlmeinfo->HT_info), pIE->data, pIE->Length);
+ return;
+}
+
+void HTOnAssocRsp(struct adapter *padapter)
+{
+ unsigned char max_AMPDU_len;
+ unsigned char min_MPDU_spacing;
+ /* struct registry_priv *pregpriv = &padapter->registrypriv; */
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ DBG_88E("%s\n", __func__);
+
+ if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) {
+ pmlmeinfo->HT_enable = 1;
+ } else {
+ pmlmeinfo->HT_enable = 0;
+ return;
+ }
+
+ /* handle A-MPDU parameter field */
+ /*
+ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+ AMPDU_para [4:2]:Min MPDU Start Spacing
+ */
+ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;
+
+ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2;
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing));
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len));
+}
+
+void ERP_IE_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if (pIE->Length > 1)
+ return;
+
+ pmlmeinfo->ERP_enable = 1;
+ memcpy(&(pmlmeinfo->ERP_IE), pIE->data, pIE->Length);
+}
+
+void VCS_update(struct adapter *padapter, struct sta_info *psta)
+{
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ switch (pregpriv->vrtl_carrier_sense) { /* 0:off 1:on 2:auto */
+ case 0: /* off */
+ psta->rtsen = 0;
+ psta->cts2self = 0;
+ break;
+ case 1: /* on */
+ if (pregpriv->vcs_type == 1) { /* 1:RTS/CTS 2:CTS to self */
+ psta->rtsen = 1;
+ psta->cts2self = 0;
+ } else {
+ psta->rtsen = 0;
+ psta->cts2self = 1;
+ }
+ break;
+ case 2: /* auto */
+ default:
+ if ((pmlmeinfo->ERP_enable) && (pmlmeinfo->ERP_IE & BIT(1))) {
+ if (pregpriv->vcs_type == 1) {
+ psta->rtsen = 1;
+ psta->cts2self = 0;
+ } else {
+ psta->rtsen = 0;
+ psta->cts2self = 1;
+ }
+ } else {
+ psta->rtsen = 0;
+ psta->cts2self = 0;
+ }
+ break;
+ }
+}
+
+int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
+{
+ unsigned int len;
+ unsigned char *p;
+ unsigned short val16, subtype;
+ struct wlan_network *cur_network = &(Adapter->mlmepriv.cur_network);
+ /* u8 wpa_ie[255], rsn_ie[255]; */
+ u16 wpa_len = 0, rsn_len = 0;
+ u8 encryp_protocol = 0;
+ struct wlan_bssid_ex *bssid;
+ int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0;
+ unsigned char *pbuf;
+ u32 wpa_ielen = 0;
+ u8 *pbssid = GetAddr3Ptr(pframe);
+ u32 hidden_ssid = 0;
+ struct HT_info_element *pht_info = NULL;
+ struct rtw_ieee80211_ht_cap *pht_cap = NULL;
+ u32 bcn_channel;
+ unsigned short ht_cap_info;
+ unsigned char ht_info_infos_0;
+
+ if (is_client_associated_to_ap(Adapter) == false)
+ return true;
+
+ len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ if (len > MAX_IE_SZ) {
+ DBG_88E("%s IE too long for survey event\n", __func__);
+ return _FAIL;
+ }
+
+ if (_rtw_memcmp(cur_network->network.MacAddress, pbssid, 6) == false) {
+ DBG_88E("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n%pM %pM\n",
+ (pbssid), (cur_network->network.MacAddress));
+ return true;
+ }
+
+ bssid = (struct wlan_bssid_ex *)rtw_zmalloc(sizeof(struct wlan_bssid_ex));
+
+ subtype = GetFrameSubType(pframe) >> 4;
+
+ if (subtype == WIFI_BEACON)
+ bssid->Reserved[0] = 1;
+
+ bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len;
+
+ /* below is to copy the information element */
+ bssid->IELength = len;
+ memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength);
+
+ /* check bw and channel offset */
+ /* parsing HT_CAP_IE */
+ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+ if (p && len > 0) {
+ pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2);
+ ht_cap_info = pht_cap->cap_info;
+ } else {
+ ht_cap_info = 0;
+ }
+ /* parsing HT_INFO_IE */
+ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+ if (p && len > 0) {
+ pht_info = (struct HT_info_element *)(p + 2);
+ ht_info_infos_0 = pht_info->infos[0];
+ } else {
+ ht_info_infos_0 = 0;
+ }
+ if (ht_cap_info != cur_network->BcnInfo.ht_cap_info ||
+ ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) {
+ DBG_88E("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__,
+ ht_cap_info, ht_info_infos_0);
+ DBG_88E("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__,
+ cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0);
+ DBG_88E("%s bw mode change, disconnect\n", __func__);
+ /* bcn_info_update */
+ cur_network->BcnInfo.ht_cap_info = ht_cap_info;
+ cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0;
+ /* to do : need to check that whether modify related register of BB or not */
+ /* goto _mismatch; */
+ }
+
+ /* Checking for channel */
+ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _DSSET_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+ if (p) {
+ bcn_channel = *(p + 2);
+ } else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */
+ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+ if (pht_info) {
+ bcn_channel = pht_info->primary_channel;
+ } else { /* we don't find channel IE, so don't check it */
+ DBG_88E("Oops: %s we don't find channel IE, so don't check it\n", __func__);
+ bcn_channel = Adapter->mlmeextpriv.cur_channel;
+ }
+ }
+ if (bcn_channel != Adapter->mlmeextpriv.cur_channel) {
+ DBG_88E("%s beacon channel:%d cur channel:%d disconnect\n", __func__,
+ bcn_channel, Adapter->mlmeextpriv.cur_channel);
+ goto _mismatch;
+ }
+
+ /* checking SSID */
+ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+ if (p == NULL) {
+ DBG_88E("%s marc: cannot find SSID for survey event\n", __func__);
+ hidden_ssid = true;
+ } else {
+ hidden_ssid = false;
+ }
+
+ if ((NULL != p) && (false == hidden_ssid && (*(p + 1)))) {
+ memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1));
+ bssid->Ssid.SsidLength = *(p + 1);
+ } else {
+ bssid->Ssid.SsidLength = 0;
+ bssid->Ssid.Ssid[0] = '\0';
+ }
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d "
+ "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, bssid->Ssid.Ssid,
+ bssid->Ssid.SsidLength, cur_network->network.Ssid.Ssid,
+ cur_network->network.Ssid.SsidLength));
+
+ if (!_rtw_memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) ||
+ bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) {
+ if (bssid->Ssid.Ssid[0] != '\0' && bssid->Ssid.SsidLength != 0) { /* not hidden ssid */
+ DBG_88E("%s(), SSID is not match return FAIL\n", __func__);
+ goto _mismatch;
+ }
+ }
+
+ /* check encryption info */
+ val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid);
+
+ if (val16 & BIT(4))
+ bssid->Privacy = 1;
+ else
+ bssid->Privacy = 0;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("%s(): cur_network->network.Privacy is %d, bssid.Privacy is %d\n",
+ __func__, cur_network->network.Privacy, bssid->Privacy));
+ if (cur_network->network.Privacy != bssid->Privacy) {
+ DBG_88E("%s(), privacy is not match return FAIL\n", __func__);
+ goto _mismatch;
+ }
+
+ rtw_get_sec_ie(bssid->IEs, bssid->IELength, NULL, &rsn_len, NULL, &wpa_len);
+
+ if (rsn_len > 0) {
+ encryp_protocol = ENCRYP_PROTOCOL_WPA2;
+ } else if (wpa_len > 0) {
+ encryp_protocol = ENCRYP_PROTOCOL_WPA;
+ } else {
+ if (bssid->Privacy)
+ encryp_protocol = ENCRYP_PROTOCOL_WEP;
+ }
+
+ if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) {
+ DBG_88E("%s(): enctyp is not match , return FAIL\n", __func__);
+ goto _mismatch;
+ }
+
+ if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) {
+ pbuf = rtw_get_wpa_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12);
+ if (pbuf && (wpa_ielen > 0)) {
+ if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("%s pnetwork->pairwise_cipher: %d, group_cipher is %d, is_8021x is %d\n", __func__,
+ pairwise_cipher, group_cipher, is_8021x));
+ }
+ } else {
+ pbuf = rtw_get_wpa2_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12);
+
+ if (pbuf && (wpa_ielen > 0)) {
+ if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) {
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+ ("%s pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_802x is %d\n",
+ __func__, pairwise_cipher, group_cipher, is_8021x));
+ }
+ }
+ }
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+ ("%s cur_network->group_cipher is %d: %d\n", __func__, cur_network->BcnInfo.group_cipher, group_cipher));
+ if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) {
+ DBG_88E("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match , return FAIL\n", __func__,
+ pairwise_cipher, cur_network->BcnInfo.pairwise_cipher,
+ group_cipher, cur_network->BcnInfo.group_cipher);
+ goto _mismatch;
+ }
+
+ if (is_8021x != cur_network->BcnInfo.is_8021x) {
+ DBG_88E("%s authentication is not match , return FAIL\n", __func__);
+ goto _mismatch;
+ }
+ }
+
+ kfree(bssid);
+ return _SUCCESS;
+
+_mismatch:
+ kfree(bssid);
+ return _FAIL;
+
+ _func_exit_;
+}
+
+void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, struct sta_info *psta)
+{
+ unsigned int i;
+ unsigned int len;
+ struct ndis_802_11_var_ie *pIE;
+
+ len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN);
+
+ for (i = 0; i < len;) {
+ pIE = (struct ndis_802_11_var_ie *)(pframe + (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN) + i);
+
+ switch (pIE->ElementID) {
+ case _HT_EXTRA_INFO_IE_: /* HT info */
+ /* HT_info_handler(padapter, pIE); */
+ bwmode_update_check(padapter, pIE);
+ break;
+ case _ERPINFO_IE_:
+ ERP_IE_handler(padapter, pIE);
+ VCS_update(padapter, psta);
+ break;
+ default:
+ break;
+ }
+
+ i += (pIE->Length + 2);
+ }
+}
+
+unsigned int is_ap_in_tkip(struct adapter *padapter)
+{
+ u32 i;
+ struct ndis_802_11_var_ie *pIE;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+
+ if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) {
+ pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i);
+
+ switch (pIE->ElementID) {
+ case _VENDOR_SPECIFIC_IE_:
+ if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) && (_rtw_memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4)))
+ return true;
+ break;
+ case _RSN_IE_2_:
+ if (_rtw_memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4))
+ return true;
+ default:
+ break;
+ }
+
+ i += (pIE->Length + 2);
+ }
+ return false;
+ } else {
+ return false;
+ }
+}
+
+unsigned int should_forbid_n_rate(struct adapter *padapter)
+{
+ u32 i;
+ struct ndis_802_11_var_ie *pIE;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_bssid_ex *cur_network = &pmlmepriv->cur_network.network;
+
+ if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < cur_network->IELength;) {
+ pIE = (struct ndis_802_11_var_ie *)(cur_network->IEs + i);
+
+ switch (pIE->ElementID) {
+ case _VENDOR_SPECIFIC_IE_:
+ if (_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4) &&
+ ((_rtw_memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP, 4)) ||
+ (_rtw_memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP, 4))))
+ return false;
+ break;
+ case _RSN_IE_2_:
+ if ((_rtw_memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP, 4)) ||
+ (_rtw_memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP, 4)))
+ return false;
+ default:
+ break;
+ }
+
+ i += (pIE->Length + 2);
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+unsigned int is_ap_in_wep(struct adapter *padapter)
+{
+ u32 i;
+ struct ndis_802_11_var_ie *pIE;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+
+ if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) {
+ pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i);
+
+ switch (pIE->ElementID) {
+ case _VENDOR_SPECIFIC_IE_:
+ if (_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4))
+ return false;
+ break;
+ case _RSN_IE_2_:
+ return false;
+ default:
+ break;
+ }
+ i += (pIE->Length + 2);
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int wifirate2_ratetbl_inx(unsigned char rate)
+{
+ int inx = 0;
+ rate = rate & 0x7f;
+
+ switch (rate) {
+ case 54*2:
+ inx = 11;
+ break;
+ case 48*2:
+ inx = 10;
+ break;
+ case 36*2:
+ inx = 9;
+ break;
+ case 24*2:
+ inx = 8;
+ break;
+ case 18*2:
+ inx = 7;
+ break;
+ case 12*2:
+ inx = 6;
+ break;
+ case 9*2:
+ inx = 5;
+ break;
+ case 6*2:
+ inx = 4;
+ break;
+ case 11*2:
+ inx = 3;
+ break;
+ case 11:
+ inx = 2;
+ break;
+ case 2*2:
+ inx = 1;
+ break;
+ case 1*2:
+ inx = 0;
+ break;
+ }
+ return inx;
+}
+
+unsigned int update_basic_rate(unsigned char *ptn, unsigned int ptn_sz)
+{
+ unsigned int i, num_of_rate;
+ unsigned int mask = 0;
+
+ num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz;
+
+ for (i = 0; i < num_of_rate; i++) {
+ if ((*(ptn + i)) & 0x80)
+ mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i));
+ }
+ return mask;
+}
+
+unsigned int update_supported_rate(unsigned char *ptn, unsigned int ptn_sz)
+{
+ unsigned int i, num_of_rate;
+ unsigned int mask = 0;
+
+ num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz;
+
+ for (i = 0; i < num_of_rate; i++)
+ mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i));
+ return mask;
+}
+
+unsigned int update_MSC_rate(struct HT_caps_element *pHT_caps)
+{
+ unsigned int mask = 0;
+
+ mask = ((pHT_caps->u.HT_cap_element.MCS_rate[0] << 12) | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 20));
+
+ return mask;
+}
+
+int support_short_GI(struct adapter *padapter, struct HT_caps_element *pHT_caps)
+{
+ unsigned char bit_offset;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if (!(pmlmeinfo->HT_enable))
+ return _FAIL;
+
+ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK))
+ return _FAIL;
+
+ bit_offset = (pmlmeext->cur_bwmode & HT_CHANNEL_WIDTH_40) ? 6 : 5;
+
+ if (__le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info) & (0x1 << bit_offset))
+ return _SUCCESS;
+ else
+ return _FAIL;
+}
+
+unsigned char get_highest_rate_idx(u32 mask)
+{
+ int i;
+ unsigned char rate_idx = 0;
+
+ for (i = 27; i >= 0; i--) {
+ if (mask & BIT(i)) {
+ rate_idx = i;
+ break;
+ }
+ }
+ return rate_idx;
+}
+
+void Update_RA_Entry(struct adapter *padapter, u32 mac_id)
+{
+ rtw_hal_update_ra_mask(padapter, mac_id, 0);
+}
+
+static void enable_rate_adaptive(struct adapter *padapter, u32 mac_id)
+{
+ Update_RA_Entry(padapter, mac_id);
+}
+
+void set_sta_rate(struct adapter *padapter, struct sta_info *psta)
+{
+ /* rate adaptive */
+ enable_rate_adaptive(padapter, psta->mac_id);
+}
+
+/* Update RRSR and Rate for USERATE */
+void update_tx_basic_rate(struct adapter *padapter, u8 wirelessmode)
+{
+ unsigned char supported_rates[NDIS_802_11_LENGTH_RATES_EX];
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+ /* Added by Albert 2011/03/22 */
+ /* In the P2P mode, the driver should not support the b mode. */
+ /* So, the Tx packet shouldn't use the CCK rate */
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ return;
+#endif /* CONFIG_88EU_P2P */
+ _rtw_memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX);
+
+ if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B)) {
+ memcpy(supported_rates, rtw_basic_rate_cck, 4);
+ } else if (wirelessmode & WIRELESS_11B) {
+ memcpy(supported_rates, rtw_basic_rate_mix, 7);
+ } else {
+ memcpy(supported_rates, rtw_basic_rate_ofdm, 3);
+ }
+
+ if (wirelessmode & WIRELESS_11B)
+ update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB);
+ else
+ update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB);
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, supported_rates);
+}
+
+unsigned char check_assoc_AP(u8 *pframe, uint len)
+{
+ unsigned int i;
+ struct ndis_802_11_var_ie *pIE;
+ u8 epigram_vendor_flag;
+ u8 ralink_vendor_flag;
+ epigram_vendor_flag = 0;
+ ralink_vendor_flag = 0;
+
+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < len;) {
+ pIE = (struct ndis_802_11_var_ie *)(pframe + i);
+
+ switch (pIE->ElementID) {
+ case _VENDOR_SPECIFIC_IE_:
+ if ((_rtw_memcmp(pIE->data, ARTHEROS_OUI1, 3)) ||
+ (_rtw_memcmp(pIE->data, ARTHEROS_OUI2, 3))) {
+ DBG_88E("link to Artheros AP\n");
+ return HT_IOT_PEER_ATHEROS;
+ } else if ((_rtw_memcmp(pIE->data, BROADCOM_OUI1, 3)) ||
+ (_rtw_memcmp(pIE->data, BROADCOM_OUI2, 3)) ||
+ (_rtw_memcmp(pIE->data, BROADCOM_OUI2, 3))) {
+ DBG_88E("link to Broadcom AP\n");
+ return HT_IOT_PEER_BROADCOM;
+ } else if (_rtw_memcmp(pIE->data, MARVELL_OUI, 3)) {
+ DBG_88E("link to Marvell AP\n");
+ return HT_IOT_PEER_MARVELL;
+ } else if (_rtw_memcmp(pIE->data, RALINK_OUI, 3)) {
+ if (!ralink_vendor_flag) {
+ ralink_vendor_flag = 1;
+ } else {
+ DBG_88E("link to Ralink AP\n");
+ return HT_IOT_PEER_RALINK;
+ }
+ } else if (_rtw_memcmp(pIE->data, CISCO_OUI, 3)) {
+ DBG_88E("link to Cisco AP\n");
+ return HT_IOT_PEER_CISCO;
+ } else if (_rtw_memcmp(pIE->data, REALTEK_OUI, 3)) {
+ DBG_88E("link to Realtek 96B\n");
+ return HT_IOT_PEER_REALTEK;
+ } else if (_rtw_memcmp(pIE->data, AIRGOCAP_OUI, 3)) {
+ DBG_88E("link to Airgo Cap\n");
+ return HT_IOT_PEER_AIRGO;
+ } else if (_rtw_memcmp(pIE->data, EPIGRAM_OUI, 3)) {
+ epigram_vendor_flag = 1;
+ if (ralink_vendor_flag) {
+ DBG_88E("link to Tenda W311R AP\n");
+ return HT_IOT_PEER_TENDA;
+ } else {
+ DBG_88E("Capture EPIGRAM_OUI\n");
+ }
+ } else {
+ break;
+ }
+
+ default:
+ break;
+ }
+ i += (pIE->Length + 2);
+ }
+
+ if (ralink_vendor_flag && !epigram_vendor_flag) {
+ DBG_88E("link to Ralink AP\n");
+ return HT_IOT_PEER_RALINK;
+ } else if (ralink_vendor_flag && epigram_vendor_flag) {
+ DBG_88E("link to Tenda W311R AP\n");
+ return HT_IOT_PEER_TENDA;
+ } else {
+ DBG_88E("link to new AP\n");
+ return HT_IOT_PEER_UNKNOWN;
+ }
+}
+
+void update_IOT_info(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ switch (pmlmeinfo->assoc_AP_vendor) {
+ case HT_IOT_PEER_MARVELL:
+ pmlmeinfo->turboMode_cts2self = 1;
+ pmlmeinfo->turboMode_rtsen = 0;
+ break;
+ case HT_IOT_PEER_RALINK:
+ pmlmeinfo->turboMode_cts2self = 0;
+ pmlmeinfo->turboMode_rtsen = 1;
+ /* disable high power */
+ Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), false);
+ break;
+ case HT_IOT_PEER_REALTEK:
+ /* rtw_write16(padapter, 0x4cc, 0xffff); */
+ /* rtw_write16(padapter, 0x546, 0x01c0); */
+ /* disable high power */
+ Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), false);
+ break;
+ default:
+ pmlmeinfo->turboMode_cts2self = 0;
+ pmlmeinfo->turboMode_rtsen = 1;
+ break;
+ }
+}
+
+void update_capinfo(struct adapter *Adapter, u16 updateCap)
+{
+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ bool ShortPreamble;
+
+ /* Check preamble mode, 2005.01.06, by rcnjko. */
+ /* Mark to update preamble value forever, 2008.03.18 by lanhsin */
+
+ if (updateCap & cShortPreamble) { /* Short Preamble */
+ if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) { /* PREAMBLE_LONG or PREAMBLE_AUTO */
+ ShortPreamble = true;
+ pmlmeinfo->preamble_mode = PREAMBLE_SHORT;
+ rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble);
+ }
+ } else { /* Long Preamble */
+ if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) { /* PREAMBLE_SHORT or PREAMBLE_AUTO */
+ ShortPreamble = false;
+ pmlmeinfo->preamble_mode = PREAMBLE_LONG;
+ rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble);
+ }
+ }
+
+ if (updateCap & cIBSS) {
+ /* Filen: See 802.11-2007 p.91 */
+ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME;
+ } else { /* Filen: See 802.11-2007 p.90 */
+ if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11_24N)) {
+ if (updateCap & cShortSlotTime) { /* Short Slot Time */
+ if (pmlmeinfo->slotTime != SHORT_SLOT_TIME)
+ pmlmeinfo->slotTime = SHORT_SLOT_TIME;
+ } else { /* Long Slot Time */
+ if (pmlmeinfo->slotTime != NON_SHORT_SLOT_TIME)
+ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME;
+ }
+ } else if (pmlmeext->cur_wireless_mode & (WIRELESS_11A | WIRELESS_11_5N)) {
+ pmlmeinfo->slotTime = SHORT_SLOT_TIME;
+ } else {
+ /* B Mode */
+ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME;
+ }
+ }
+
+ rtw_hal_set_hwreg(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime);
+}
+
+void update_wireless_mode(struct adapter *padapter)
+{
+ int ratelen, network_type = 0;
+ u32 SIFS_Timer;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+ unsigned char *rate = cur_network->SupportedRates;
+
+ ratelen = rtw_get_rateset_len(cur_network->SupportedRates);
+
+ if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable))
+ pmlmeinfo->HT_enable = 1;
+
+ if (pmlmeext->cur_channel > 14) {
+ if (pmlmeinfo->HT_enable)
+ network_type = WIRELESS_11_5N;
+
+ network_type |= WIRELESS_11A;
+ } else {
+ if (pmlmeinfo->HT_enable)
+ network_type = WIRELESS_11_24N;
+
+ if ((cckratesonly_included(rate, ratelen)) == true)
+ network_type |= WIRELESS_11B;
+ else if ((cckrates_included(rate, ratelen)) == true)
+ network_type |= WIRELESS_11BG;
+ else
+ network_type |= WIRELESS_11G;
+ }
+
+ pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode;
+
+ SIFS_Timer = 0x0a0a0808;/* 0x0808 -> for CCK, 0x0a0a -> for OFDM */
+ /* change this value if having IOT issues. */
+
+ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_RESP_SIFS, (u8 *)&SIFS_Timer);
+
+ if (pmlmeext->cur_wireless_mode & WIRELESS_11B)
+ update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB);
+ else
+ update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB);
+}
+
+void update_bmc_sta_support_rate(struct adapter *padapter, u32 mac_id)
+{
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) {
+ /* Only B, B/G, and B/G/N AP could use CCK rate */
+ memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_cck, 4);
+ } else {
+ memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_ofdm, 3);
+ }
+}
+
+int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_len, int cam_idx)
+{
+ unsigned int ie_len;
+ struct ndis_802_11_var_ie *pIE;
+ int supportRateNum = 0;
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len);
+ if (pIE == NULL)
+ return _FAIL;
+
+ memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, pIE->data, ie_len);
+ supportRateNum = ie_len;
+
+ pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _EXT_SUPPORTEDRATES_IE_, &ie_len, var_ie_len);
+ if (pIE)
+ memcpy((pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + supportRateNum), pIE->data, ie_len);
+
+ return _SUCCESS;
+}
+
+void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr)
+{
+ struct sta_info *psta;
+ u16 tid;
+ u16 param;
+ struct recv_reorder_ctrl *preorder_ctrl;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct ADDBA_request *preq = (struct ADDBA_request *)paddba_req;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ psta = rtw_get_stainfo(pstapriv, addr);
+
+ if (psta) {
+ param = le16_to_cpu(preq->BA_para_set);
+ tid = (param>>2)&0x0f;
+ preorder_ctrl = &psta->recvreorder_ctrl[tid];
+ preorder_ctrl->indicate_seq = 0xffff;
+ preorder_ctrl->enable = (pmlmeinfo->bAcceptAddbaReq) ? true : false;
+ }
+}
+
+void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len)
+{
+ u8 *pIE;
+ __le32 *pbuf;
+
+ pIE = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+ pbuf = (__le32 *)pIE;
+
+ pmlmeext->TSFValue = le32_to_cpu(*(pbuf+1));
+
+ pmlmeext->TSFValue = pmlmeext->TSFValue << 32;
+
+ pmlmeext->TSFValue |= le32_to_cpu(*pbuf);
+}
+
+void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext)
+{
+ rtw_hal_set_hwreg(padapter, HW_VAR_CORRECT_TSF, NULL);
+}
+
+void beacon_timing_control(struct adapter *padapter)
+{
+ rtw_hal_bcn_related_reg_setting(padapter);
+}
+
+static struct adapter *pbuddy_padapter;
+
+int rtw_handle_dualmac(struct adapter *adapter, bool init)
+{
+ int status = _SUCCESS;
+
+ if (init) {
+ if (pbuddy_padapter == NULL) {
+ pbuddy_padapter = adapter;
+ DBG_88E("%s(): pbuddy_padapter == NULL, Set pbuddy_padapter\n", __func__);
+ } else {
+ adapter->pbuddy_adapter = pbuddy_padapter;
+ pbuddy_padapter->pbuddy_adapter = adapter;
+ /* clear global value */
+ pbuddy_padapter = NULL;
+ DBG_88E("%s(): pbuddy_padapter exist, Exchange Information\n", __func__);
+ }
+ } else {
+ pbuddy_padapter = NULL;
+ }
+ return status;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c
new file mode 100644
index 00000000000..bb5cd95c564
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c
@@ -0,0 +1,2447 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTW_XMIT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <osdep_intf.h>
+#include <ip.h>
+#include <usb_ops.h>
+#include <usb_osintf.h>
+
+static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
+static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
+
+static void _init_txservq(struct tx_servq *ptxservq)
+{
+_func_enter_;
+ _rtw_init_listhead(&ptxservq->tx_pending);
+ _rtw_init_queue(&ptxservq->sta_pending);
+ ptxservq->qcnt = 0;
+_func_exit_;
+}
+
+void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv)
+{
+_func_enter_;
+ _rtw_memset((unsigned char *)psta_xmitpriv, 0, sizeof (struct sta_xmit_priv));
+ _rtw_spinlock_init(&psta_xmitpriv->lock);
+ _init_txservq(&psta_xmitpriv->be_q);
+ _init_txservq(&psta_xmitpriv->bk_q);
+ _init_txservq(&psta_xmitpriv->vi_q);
+ _init_txservq(&psta_xmitpriv->vo_q);
+ _rtw_init_listhead(&psta_xmitpriv->legacy_dz);
+ _rtw_init_listhead(&psta_xmitpriv->apsd);
+
+_func_exit_;
+}
+
+s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
+{
+ int i;
+ struct xmit_buf *pxmitbuf;
+ struct xmit_frame *pxframe;
+ int res = _SUCCESS;
+ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
+
+_func_enter_;
+
+ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
+
+ _rtw_spinlock_init(&pxmitpriv->lock);
+ _rtw_init_sema(&pxmitpriv->xmit_sema, 0);
+ _rtw_init_sema(&pxmitpriv->terminate_xmitthread_sema, 0);
+
+ /*
+ Please insert all the queue initializaiton using _rtw_init_queue below
+ */
+
+ pxmitpriv->adapter = padapter;
+
+ _rtw_init_queue(&pxmitpriv->be_pending);
+ _rtw_init_queue(&pxmitpriv->bk_pending);
+ _rtw_init_queue(&pxmitpriv->vi_pending);
+ _rtw_init_queue(&pxmitpriv->vo_pending);
+ _rtw_init_queue(&pxmitpriv->bm_pending);
+
+ _rtw_init_queue(&pxmitpriv->free_xmit_queue);
+
+ /*
+ Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME,
+ and initialize free_xmit_frame below.
+ Please also apply free_txobj to link_up all the xmit_frames...
+ */
+
+ pxmitpriv->pallocated_frame_buf = rtw_zvmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
+
+ if (pxmitpriv->pallocated_frame_buf == NULL) {
+ pxmitpriv->pxmit_frame_buf = NULL;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_frame fail!\n"));
+ res = _FAIL;
+ goto exit;
+ }
+ pxmitpriv->pxmit_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_frame_buf), 4);
+ /* pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - */
+ /* ((size_t) (pxmitpriv->pallocated_frame_buf) &3); */
+
+ pxframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf;
+
+ for (i = 0; i < NR_XMITFRAME; i++) {
+ _rtw_init_listhead(&(pxframe->list));
+
+ pxframe->padapter = padapter;
+ pxframe->frame_tag = NULL_FRAMETAG;
+
+ pxframe->pkt = NULL;
+
+ pxframe->buf_addr = NULL;
+ pxframe->pxmitbuf = NULL;
+
+ rtw_list_insert_tail(&(pxframe->list), &(pxmitpriv->free_xmit_queue.queue));
+
+ pxframe++;
+ }
+
+ pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME;
+
+ pxmitpriv->frag_len = MAX_FRAG_THRESHOLD;
+
+ /* init xmit_buf */
+ _rtw_init_queue(&pxmitpriv->free_xmitbuf_queue);
+ _rtw_init_queue(&pxmitpriv->pending_xmitbuf_queue);
+
+ pxmitpriv->pallocated_xmitbuf = rtw_zvmalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4);
+
+ if (pxmitpriv->pallocated_xmitbuf == NULL) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_buf fail!\n"));
+ res = _FAIL;
+ goto exit;
+ }
+
+ pxmitpriv->pxmitbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmitbuf), 4);
+ /* pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - */
+ /* ((size_t) (pxmitpriv->pallocated_xmitbuf) &3); */
+
+ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
+
+ for (i = 0; i < NR_XMITBUFF; i++) {
+ _rtw_init_listhead(&pxmitbuf->list);
+
+ pxmitbuf->priv_data = NULL;
+ pxmitbuf->padapter = padapter;
+ pxmitbuf->ext_tag = false;
+
+ /* Tx buf allocation may fail sometimes, so sleep and retry. */
+ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ));
+ if (res == _FAIL) {
+ rtw_msleep_os(10);
+ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ));
+ if (res == _FAIL) {
+ goto exit;
+ }
+ }
+
+ pxmitbuf->flags = XMIT_VO_QUEUE;
+
+ rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmitbuf_queue.queue));
+ pxmitbuf++;
+ }
+
+ pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF;
+
+ /* Init xmit extension buff */
+ _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue);
+
+ pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+
+ if (pxmitpriv->pallocated_xmit_extbuf == NULL) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n"));
+ res = _FAIL;
+ goto exit;
+ }
+
+ pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmit_extbuf), 4);
+
+ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
+
+ for (i = 0; i < num_xmit_extbuf; i++) {
+ _rtw_init_listhead(&pxmitbuf->list);
+
+ pxmitbuf->priv_data = NULL;
+ pxmitbuf->padapter = padapter;
+ pxmitbuf->ext_tag = true;
+
+ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, max_xmit_extbuf_size + XMITBUF_ALIGN_SZ);
+ if (res == _FAIL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue));
+ pxmitbuf++;
+ }
+
+ pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf;
+
+ rtw_alloc_hwxmits(padapter);
+ rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+
+ for (i = 0; i < 4; i++)
+ pxmitpriv->wmm_para_seq[i] = i;
+
+ pxmitpriv->txirp_cnt = 1;
+
+ _rtw_init_sema(&(pxmitpriv->tx_retevt), 0);
+
+ /* per AC pending irp */
+ pxmitpriv->beq_cnt = 0;
+ pxmitpriv->bkq_cnt = 0;
+ pxmitpriv->viq_cnt = 0;
+ pxmitpriv->voq_cnt = 0;
+
+ pxmitpriv->ack_tx = false;
+ _rtw_mutex_init(&pxmitpriv->ack_tx_mutex);
+ rtw_sctx_init(&pxmitpriv->ack_tx_ops, 0);
+
+ rtw_hal_init_xmit_priv(padapter);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+static void rtw_mfree_xmit_priv_lock (struct xmit_priv *pxmitpriv)
+{
+ _rtw_spinlock_free(&pxmitpriv->lock);
+ _rtw_free_sema(&pxmitpriv->xmit_sema);
+ _rtw_free_sema(&pxmitpriv->terminate_xmitthread_sema);
+
+ _rtw_spinlock_free(&pxmitpriv->be_pending.lock);
+ _rtw_spinlock_free(&pxmitpriv->bk_pending.lock);
+ _rtw_spinlock_free(&pxmitpriv->vi_pending.lock);
+ _rtw_spinlock_free(&pxmitpriv->vo_pending.lock);
+ _rtw_spinlock_free(&pxmitpriv->bm_pending.lock);
+
+ _rtw_spinlock_free(&pxmitpriv->free_xmit_queue.lock);
+ _rtw_spinlock_free(&pxmitpriv->free_xmitbuf_queue.lock);
+ _rtw_spinlock_free(&pxmitpriv->pending_xmitbuf_queue.lock);
+}
+
+void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv)
+{
+ int i;
+ struct adapter *padapter = pxmitpriv->adapter;
+ struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf;
+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
+ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
+
+ _func_enter_;
+
+ rtw_hal_free_xmit_priv(padapter);
+
+ rtw_mfree_xmit_priv_lock(pxmitpriv);
+
+ if (pxmitpriv->pxmit_frame_buf == NULL)
+ goto out;
+
+ for (i = 0; i < NR_XMITFRAME; i++) {
+ rtw_os_xmit_complete(padapter, pxmitframe);
+
+ pxmitframe++;
+ }
+
+ for (i = 0; i < NR_XMITBUFF; i++) {
+ rtw_os_xmit_resource_free(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ));
+ pxmitbuf++;
+ }
+
+ if (pxmitpriv->pallocated_frame_buf)
+ rtw_vmfree(pxmitpriv->pallocated_frame_buf, NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
+
+ if (pxmitpriv->pallocated_xmitbuf)
+ rtw_vmfree(pxmitpriv->pallocated_xmitbuf, NR_XMITBUFF * sizeof(struct xmit_buf) + 4);
+
+ /* free xmit extension buff */
+ _rtw_spinlock_free(&pxmitpriv->free_xmit_extbuf_queue.lock);
+
+ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
+ for (i = 0; i < num_xmit_extbuf; i++) {
+ rtw_os_xmit_resource_free(padapter, pxmitbuf, (max_xmit_extbuf_size + XMITBUF_ALIGN_SZ));
+ pxmitbuf++;
+ }
+
+ if (pxmitpriv->pallocated_xmit_extbuf) {
+ rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+ }
+
+ rtw_free_hwxmits(padapter);
+
+ _rtw_mutex_free(&pxmitpriv->ack_tx_mutex);
+
+out:
+
+_func_exit_;
+}
+
+static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+ u32 sz;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+ struct sta_info *psta = pattrib->psta;
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if (pattrib->nr_frags != 1)
+ sz = padapter->xmitpriv.frag_len;
+ else /* no frag */
+ sz = pattrib->last_txcmdsz;
+
+ /* (1) RTS_Threshold is compared to the MPDU, not MSDU. */
+ /* (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. */
+ /* Other fragments are protected by previous fragment. */
+ /* So we only need to check the length of first fragment. */
+ if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) {
+ if (sz > padapter->registrypriv.rts_thresh) {
+ pattrib->vcs_mode = RTS_CTS;
+ } else {
+ if (psta->rtsen)
+ pattrib->vcs_mode = RTS_CTS;
+ else if (psta->cts2self)
+ pattrib->vcs_mode = CTS_TO_SELF;
+ else
+ pattrib->vcs_mode = NONE_VCS;
+ }
+ } else {
+ while (true) {
+ /* IOT action */
+ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && pattrib->ampdu_en &&
+ (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) {
+ pattrib->vcs_mode = CTS_TO_SELF;
+ break;
+ }
+
+ /* check ERP protection */
+ if (psta->rtsen || psta->cts2self) {
+ if (psta->rtsen)
+ pattrib->vcs_mode = RTS_CTS;
+ else if (psta->cts2self)
+ pattrib->vcs_mode = CTS_TO_SELF;
+
+ break;
+ }
+
+ /* check HT op mode */
+ if (pattrib->ht_en) {
+ u8 htopmode = pmlmeinfo->HT_protection;
+ if ((pmlmeext->cur_bwmode && (htopmode == 2 || htopmode == 3)) ||
+ (!pmlmeext->cur_bwmode && htopmode == 3)) {
+ pattrib->vcs_mode = RTS_CTS;
+ break;
+ }
+ }
+
+ /* check rts */
+ if (sz > padapter->registrypriv.rts_thresh) {
+ pattrib->vcs_mode = RTS_CTS;
+ break;
+ }
+
+ /* to do list: check MIMO power save condition. */
+
+ /* check AMPDU aggregation for TXOP */
+ if (pattrib->ampdu_en) {
+ pattrib->vcs_mode = RTS_CTS;
+ break;
+ }
+
+ pattrib->vcs_mode = NONE_VCS;
+ break;
+ }
+ }
+}
+
+static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *psta)
+{
+ /*if (psta->rtsen)
+ pattrib->vcs_mode = RTS_CTS;
+ else if (psta->cts2self)
+ pattrib->vcs_mode = CTS_TO_SELF;
+ else
+ pattrib->vcs_mode = NONE_VCS;*/
+
+ pattrib->mdata = 0;
+ pattrib->eosp = 0;
+ pattrib->triggered = 0;
+
+ /* qos_en, ht_en, init rate, , bw, ch_offset, sgi */
+ pattrib->qos_en = psta->qos_option;
+
+ pattrib->raid = psta->raid;
+ pattrib->ht_en = psta->htpriv.ht_option;
+ pattrib->bwmode = psta->htpriv.bwmode;
+ pattrib->ch_offset = psta->htpriv.ch_offset;
+ pattrib->sgi = psta->htpriv.sgi;
+ pattrib->ampdu_en = false;
+ pattrib->retry_ctrl = false;
+}
+
+u8 qos_acm(u8 acm_mask, u8 priority)
+{
+ u8 change_priority = priority;
+
+ switch (priority) {
+ case 0:
+ case 3:
+ if (acm_mask & BIT(1))
+ change_priority = 1;
+ break;
+ case 1:
+ case 2:
+ break;
+ case 4:
+ case 5:
+ if (acm_mask & BIT(2))
+ change_priority = 0;
+ break;
+ case 6:
+ case 7:
+ if (acm_mask & BIT(3))
+ change_priority = 5;
+ break;
+ default:
+ DBG_88E("qos_acm(): invalid pattrib->priority: %d!!!\n", priority);
+ break;
+ }
+
+ return change_priority;
+}
+
+static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib)
+{
+ struct ethhdr etherhdr;
+ struct iphdr ip_hdr;
+ s32 user_prio = 0;
+
+ _rtw_open_pktfile(ppktfile->pkt, ppktfile);
+ _rtw_pktfile_read(ppktfile, (unsigned char *)&etherhdr, ETH_HLEN);
+
+ /* get user_prio from IP hdr */
+ if (pattrib->ether_type == 0x0800) {
+ _rtw_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr));
+/* user_prio = (ntohs(ip_hdr.tos) >> 5) & 0x3; */
+ user_prio = ip_hdr.tos >> 5;
+ } else if (pattrib->ether_type == 0x888e) {
+ /* "When priority processing of data frames is supported, */
+ /* a STA's SME should send EAPOL-Key frames at the highest priority." */
+ user_prio = 7;
+ }
+
+ pattrib->priority = user_prio;
+ pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN;
+ pattrib->subtype = WIFI_QOS_DATA_TYPE;
+}
+
+static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct pkt_attrib *pattrib)
+{
+ struct pkt_file pktfile;
+ struct sta_info *psta = NULL;
+ struct ethhdr etherhdr;
+
+ int bmcast;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct qos_priv *pqospriv = &pmlmepriv->qospriv;
+ int res = _SUCCESS;
+
+ _func_enter_;
+
+ _rtw_open_pktfile(pkt, &pktfile);
+ _rtw_pktfile_read(&pktfile, (u8 *)&etherhdr, ETH_HLEN);
+
+ pattrib->ether_type = ntohs(etherhdr.h_proto);
+
+ memcpy(pattrib->dst, &etherhdr.h_dest, ETH_ALEN);
+ memcpy(pattrib->src, &etherhdr.h_source, ETH_ALEN);
+
+ pattrib->pctrl = 0;
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+ } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+ memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN);
+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+ memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN);
+ }
+
+ pattrib->pktlen = pktfile.pkt_len;
+
+ if (ETH_P_IP == pattrib->ether_type) {
+ /* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */
+ /* to prevent DHCP protocol fail */
+ u8 tmp[24];
+ _rtw_pktfile_read(&pktfile, &tmp[0], 24);
+ pattrib->dhcp_pkt = 0;
+ if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */
+ if (ETH_P_IP == pattrib->ether_type) {/* IP header */
+ if (((tmp[21] == 68) && (tmp[23] == 67)) ||
+ ((tmp[21] == 67) && (tmp[23] == 68))) {
+ /* 68 : UDP BOOTP client */
+ /* 67 : UDP BOOTP server */
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====================== update_attrib: get DHCP Packet\n"));
+ /* Use low rate to send DHCP packet. */
+ pattrib->dhcp_pkt = 1;
+ }
+ }
+ }
+ } else if (0x888e == pattrib->ether_type) {
+ DBG_88E_LEVEL(_drv_info_, "send eapol packet\n");
+ }
+
+ if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1))
+ rtw_set_scan_deny(padapter, 3000);
+
+ /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */
+ if ((pattrib->ether_type == 0x0806) || (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1))
+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SPECIAL_PACKET, 1);
+
+ bmcast = IS_MCAST(pattrib->ra);
+
+ /* get sta_info */
+ if (bmcast) {
+ psta = rtw_get_bcmc_stainfo(padapter);
+ } else {
+ psta = rtw_get_stainfo(pstapriv, pattrib->ra);
+ if (psta == NULL) { /* if we cannot get psta => drrp the pkt */
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra: %pM\n", (pattrib->ra)));
+ res = _FAIL;
+ goto exit;
+ } else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) && (!(psta->state & _FW_LINKED))) {
+ res = _FAIL;
+ goto exit;
+ }
+ }
+
+ if (psta) {
+ pattrib->mac_id = psta->mac_id;
+ /* DBG_88E("%s ==> mac_id(%d)\n", __func__, pattrib->mac_id); */
+ pattrib->psta = psta;
+ } else {
+ /* if we cannot get psta => drop the pkt */
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:%pM\n", (pattrib->ra)));
+ res = _FAIL;
+ goto exit;
+ }
+
+ pattrib->ack_policy = 0;
+ /* get ether_hdr_len */
+ pattrib->pkt_hdrlen = ETH_HLEN;/* pattrib->ether_type == 0x8100) ? (14 + 4): 14; vlan tag */
+
+ pattrib->hdrlen = WLAN_HDR_A3_LEN;
+ pattrib->subtype = WIFI_DATA_TYPE;
+ pattrib->priority = 0;
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) {
+ if (psta->qos_option)
+ set_qos(&pktfile, pattrib);
+ } else {
+ if (pqospriv->qos_option) {
+ set_qos(&pktfile, pattrib);
+
+ if (pmlmepriv->acm_mask != 0)
+ pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority);
+ }
+ }
+
+ if (psta->ieee8021x_blocked) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\n psta->ieee8021x_blocked == true\n"));
+
+ pattrib->encrypt = 0;
+
+ if ((pattrib->ether_type != 0x888e) && !check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\npsta->ieee8021x_blocked == true, pattrib->ether_type(%.4x) != 0x888e\n", pattrib->ether_type));
+ res = _FAIL;
+ goto exit;
+ }
+ } else {
+ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast);
+
+ switch (psecuritypriv->dot11AuthAlgrthm) {
+ case dot11AuthAlgrthm_Open:
+ case dot11AuthAlgrthm_Shared:
+ case dot11AuthAlgrthm_Auto:
+ pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex;
+ break;
+ case dot11AuthAlgrthm_8021X:
+ if (bmcast)
+ pattrib->key_idx = (u8)psecuritypriv->dot118021XGrpKeyid;
+ else
+ pattrib->key_idx = 0;
+ break;
+ default:
+ pattrib->key_idx = 0;
+ break;
+ }
+ }
+
+ switch (pattrib->encrypt) {
+ case _WEP40_:
+ case _WEP104_:
+ pattrib->iv_len = 4;
+ pattrib->icv_len = 4;
+ break;
+ case _TKIP_:
+ pattrib->iv_len = 8;
+ pattrib->icv_len = 4;
+
+ if (padapter->securitypriv.busetkipkey == _FAIL) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+ ("\npadapter->securitypriv.busetkipkey(%d) == _FAIL drop packet\n",
+ padapter->securitypriv.busetkipkey));
+ res = _FAIL;
+ goto exit;
+ }
+ break;
+ case _AES_:
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("pattrib->encrypt=%d (_AES_)\n", pattrib->encrypt));
+ pattrib->iv_len = 8;
+ pattrib->icv_len = 8;
+ break;
+ default:
+ pattrib->iv_len = 0;
+ pattrib->icv_len = 0;
+ break;
+ }
+
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+ ("update_attrib: encrypt=%d securitypriv.sw_encrypt=%d\n",
+ pattrib->encrypt, padapter->securitypriv.sw_encrypt));
+
+ if (pattrib->encrypt &&
+ (padapter->securitypriv.sw_encrypt || !psecuritypriv->hw_decrypted)) {
+ pattrib->bswenc = true;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+ ("update_attrib: encrypt=%d securitypriv.hw_decrypted=%d bswenc = true\n",
+ pattrib->encrypt, padapter->securitypriv.sw_encrypt));
+ } else {
+ pattrib->bswenc = false;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("update_attrib: bswenc = false\n"));
+ }
+
+ rtw_set_tx_chksum_offload(pkt, pattrib);
+
+ update_attrib_phy_info(pattrib, psta);
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+ int curfragnum, length;
+ u8 *pframe, *payload, mic[8];
+ struct mic_data micdata;
+ struct sta_info *stainfo;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
+ u8 hw_hdr_offset = 0;
+ int bmcst = IS_MCAST(pattrib->ra);
+
+ if (pattrib->psta)
+ stainfo = pattrib->psta;
+ else
+ stainfo = rtw_get_stainfo(&padapter->stapriv , &pattrib->ra[0]);
+
+_func_enter_;
+
+ hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);;
+
+ if (pattrib->encrypt == _TKIP_) {/* if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_PRIVACY_) */
+ /* encode mic code */
+ if (stainfo != NULL) {
+ u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0};
+
+ pframe = pxmitframe->buf_addr + hw_hdr_offset;
+
+ if (bmcst) {
+ if (_rtw_memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16))
+ return _FAIL;
+ /* start to calculate the mic code */
+ rtw_secmicsetkey(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey);
+ } else {
+ if (_rtw_memcmp(&stainfo->dot11tkiptxmickey.skey[0], null_key, 16) == true) {
+ /* DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey == 0\n"); */
+ /* rtw_msleep_os(10); */
+ return _FAIL;
+ }
+ /* start to calculate the mic code */
+ rtw_secmicsetkey(&micdata, &stainfo->dot11tkiptxmickey.skey[0]);
+ }
+
+ if (pframe[1]&1) { /* ToDS == 1 */
+ rtw_secmicappend(&micdata, &pframe[16], 6); /* DA */
+ if (pframe[1]&2) /* From Ds == 1 */
+ rtw_secmicappend(&micdata, &pframe[24], 6);
+ else
+ rtw_secmicappend(&micdata, &pframe[10], 6);
+ } else { /* ToDS == 0 */
+ rtw_secmicappend(&micdata, &pframe[4], 6); /* DA */
+ if (pframe[1]&2) /* From Ds == 1 */
+ rtw_secmicappend(&micdata, &pframe[16], 6);
+ else
+ rtw_secmicappend(&micdata, &pframe[10], 6);
+ }
+
+ if (pattrib->qos_en)
+ priority[0] = (u8)pxmitframe->attrib.priority;
+
+ rtw_secmicappend(&micdata, &priority[0], 4);
+
+ payload = pframe;
+
+ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
+ payload = (u8 *)RND4((size_t)(payload));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+ ("=== curfragnum=%d, pframe = 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x,!!!\n",
+ curfragnum, *payload, *(payload+1),
+ *(payload+2), *(payload+3),
+ *(payload+4), *(payload+5),
+ *(payload+6), *(payload+7)));
+
+ payload = payload+pattrib->hdrlen+pattrib->iv_len;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+ ("curfragnum=%d pattrib->hdrlen=%d pattrib->iv_len=%d",
+ curfragnum, pattrib->hdrlen, pattrib->iv_len));
+ if ((curfragnum+1) == pattrib->nr_frags) {
+ length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0);
+ rtw_secmicappend(&micdata, payload, length);
+ payload = payload+length;
+ } else {
+ length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0);
+ rtw_secmicappend(&micdata, payload, length);
+ payload = payload+length+pattrib->icv_len;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("curfragnum=%d length=%d pattrib->icv_len=%d", curfragnum, length, pattrib->icv_len));
+ }
+ }
+ rtw_secgetmic(&micdata, &(mic[0]));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: before add mic code!!!\n"));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: pattrib->last_txcmdsz=%d!!!\n", pattrib->last_txcmdsz));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: mic[0]=0x%.2x , mic[1]=0x%.2x , mic[2]= 0x%.2x, mic[3]=0x%.2x\n\
+ mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x , mic[7]= 0x%.2x !!!!\n",
+ mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7]));
+ /* add mic code and add the mic code length in last_txcmdsz */
+
+ memcpy(payload, &(mic[0]), 8);
+ pattrib->last_txcmdsz += 8;
+
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("\n ======== last pkt ========\n"));
+ payload = payload-pattrib->last_txcmdsz+8;
+ for (curfragnum = 0; curfragnum < pattrib->last_txcmdsz; curfragnum = curfragnum+8)
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+ (" %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x ",
+ *(payload+curfragnum), *(payload+curfragnum+1),
+ *(payload+curfragnum+2), *(payload+curfragnum+3),
+ *(payload+curfragnum+4), *(payload+curfragnum+5),
+ *(payload+curfragnum+6), *(payload+curfragnum+7)));
+ } else {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: rtw_get_stainfo==NULL!!!\n"));
+ }
+ }
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+
+_func_enter_;
+
+ if (pattrib->bswenc) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### xmitframe_swencrypt\n"));
+ switch (pattrib->encrypt) {
+ case _WEP40_:
+ case _WEP104_:
+ rtw_wep_encrypt(padapter, (u8 *)pxmitframe);
+ break;
+ case _TKIP_:
+ rtw_tkip_encrypt(padapter, (u8 *)pxmitframe);
+ break;
+ case _AES_:
+ rtw_aes_encrypt(padapter, (u8 *)pxmitframe);
+ break;
+ default:
+ break;
+ }
+ } else {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ("### xmitframe_hwencrypt\n"));
+ }
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+s32 rtw_make_wlanhdr (struct adapter *padapter , u8 *hdr, struct pkt_attrib *pattrib)
+{
+ u16 *qc;
+
+ struct rtw_ieee80211_hdr *pwlanhdr = (struct rtw_ieee80211_hdr *)hdr;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct qos_priv *pqospriv = &pmlmepriv->qospriv;
+ u8 qos_option = false;
+
+ int res = _SUCCESS;
+ u16 *fctrl = &pwlanhdr->frame_ctl;
+
+ struct sta_info *psta;
+
+ int bmcst = IS_MCAST(pattrib->ra);
+
+_func_enter_;
+
+ if (pattrib->psta) {
+ psta = pattrib->psta;
+ } else {
+ if (bmcst) {
+ psta = rtw_get_bcmc_stainfo(padapter);
+ } else {
+ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
+ }
+ }
+
+ _rtw_memset(hdr, 0, WLANHDR_OFFSET);
+
+ SetFrameSubType(fctrl, pattrib->subtype);
+
+ if (pattrib->subtype & WIFI_DATA_TYPE) {
+ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)) {
+ /* to_ds = 1, fr_ds = 0; */
+ /* Data transfer to AP */
+ SetToDs(fctrl);
+ memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN);
+ memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN);
+
+ if (pqospriv->qos_option)
+ qos_option = true;
+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ /* to_ds = 0, fr_ds = 1; */
+ SetFrDs(fctrl);
+ memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN);
+
+ if (psta->qos_option)
+ qos_option = true;
+ } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
+ memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN);
+
+ if (psta->qos_option)
+ qos_option = true;
+ } else {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv)));
+ res = _FAIL;
+ goto exit;
+ }
+
+ if (pattrib->mdata)
+ SetMData(fctrl);
+
+ if (pattrib->encrypt)
+ SetPrivacy(fctrl);
+
+ if (qos_option) {
+ qc = (unsigned short *)(hdr + pattrib->hdrlen - 2);
+
+ if (pattrib->priority)
+ SetPriority(qc, pattrib->priority);
+
+ SetEOSP(qc, pattrib->eosp);
+
+ SetAckpolicy(qc, pattrib->ack_policy);
+ }
+
+ /* TODO: fill HT Control Field */
+
+ /* Update Seq Num will be handled by f/w */
+ if (psta) {
+ psta->sta_xmitpriv.txseq_tid[pattrib->priority]++;
+ psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF;
+
+ pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority];
+
+ SetSeqNum(hdr, pattrib->seqnum);
+
+ /* check if enable ampdu */
+ if (pattrib->ht_en && psta->htpriv.ampdu_enable) {
+ if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority))
+ pattrib->ampdu_en = true;
+ }
+
+ /* re-check if enable ampdu by BA_starting_seqctrl */
+ if (pattrib->ampdu_en) {
+ u16 tx_seq;
+
+ tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f];
+
+ /* check BA_starting_seqctrl */
+ if (SN_LESS(pattrib->seqnum, tx_seq)) {
+ pattrib->ampdu_en = false;/* AGG BK */
+ } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) {
+ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff;
+
+ pattrib->ampdu_en = true;/* AGG EN */
+ } else {
+ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff;
+ pattrib->ampdu_en = true;/* AGG EN */
+ }
+ }
+ }
+ }
+exit:
+
+_func_exit_;
+ return res;
+}
+
+s32 rtw_txframes_pending(struct adapter *padapter)
+{
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+ return ((_rtw_queue_empty(&pxmitpriv->be_pending) == false) ||
+ (_rtw_queue_empty(&pxmitpriv->bk_pending) == false) ||
+ (_rtw_queue_empty(&pxmitpriv->vi_pending) == false) ||
+ (_rtw_queue_empty(&pxmitpriv->vo_pending) == false));
+}
+
+s32 rtw_txframes_sta_ac_pending(struct adapter *padapter, struct pkt_attrib *pattrib)
+{
+ struct sta_info *psta;
+ struct tx_servq *ptxservq;
+ int priority = pattrib->priority;
+
+ psta = pattrib->psta;
+
+ switch (priority) {
+ case 1:
+ case 2:
+ ptxservq = &(psta->sta_xmitpriv.bk_q);
+ break;
+ case 4:
+ case 5:
+ ptxservq = &(psta->sta_xmitpriv.vi_q);
+ break;
+ case 6:
+ case 7:
+ ptxservq = &(psta->sta_xmitpriv.vo_q);
+ break;
+ case 0:
+ case 3:
+ default:
+ ptxservq = &(psta->sta_xmitpriv.be_q);
+ break;
+ }
+
+ return ptxservq->qcnt;
+}
+
+/*
+ * Calculate wlan 802.11 packet MAX size from pkt_attrib
+ * This function doesn't consider fragment case
+ */
+u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib)
+{
+ u32 len = 0;
+
+ len = pattrib->hdrlen + pattrib->iv_len; /* WLAN Header and IV */
+ len += SNAP_SIZE + sizeof(u16); /* LLC */
+ len += pattrib->pktlen;
+ if (pattrib->encrypt == _TKIP_)
+ len += 8; /* MIC */
+ len += ((pattrib->bswenc) ? pattrib->icv_len : 0); /* ICV */
+
+ return len;
+}
+
+/*
+
+This sub-routine will perform all the following:
+
+1. remove 802.3 header.
+2. create wlan_header, based on the info in pxmitframe
+3. append sta's iv/ext-iv
+4. append LLC
+5. move frag chunk from pframe to pxmitframe->mem
+6. apply sw-encrypt, if necessary.
+
+*/
+s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe)
+{
+ struct pkt_file pktfile;
+ s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz;
+ size_t addr;
+ u8 *pframe, *mem_start;
+ u8 hw_hdr_offset;
+ struct sta_info *psta;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+ u8 *pbuf_start;
+ s32 bmcst = IS_MCAST(pattrib->ra);
+ s32 res = _SUCCESS;
+
+_func_enter_;
+
+ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
+
+ if (psta == NULL)
+ return _FAIL;
+
+ if (pxmitframe->buf_addr == NULL) {
+ DBG_88E("==> %s buf_addr == NULL\n", __func__);
+ return _FAIL;
+ }
+
+ pbuf_start = pxmitframe->buf_addr;
+
+ hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);
+
+ mem_start = pbuf_start + hw_hdr_offset;
+
+ if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"));
+ DBG_88E("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n");
+ res = _FAIL;
+ goto exit;
+ }
+
+ _rtw_open_pktfile(pkt, &pktfile);
+ _rtw_pktfile_read(&pktfile, NULL, pattrib->pkt_hdrlen);
+
+ frg_inx = 0;
+ frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */
+
+ while (1) {
+ llc_sz = 0;
+
+ mpdu_len = frg_len;
+
+ pframe = mem_start;
+
+ SetMFrag(mem_start);
+
+ pframe += pattrib->hdrlen;
+ mpdu_len -= pattrib->hdrlen;
+
+ /* adding icv, if necessary... */
+ if (pattrib->iv_len) {
+ if (psta != NULL) {
+ switch (pattrib->encrypt) {
+ case _WEP40_:
+ case _WEP104_:
+ WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+ break;
+ case _TKIP_:
+ if (bmcst)
+ TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+ else
+ TKIP_IV(pattrib->iv, psta->dot11txpn, 0);
+ break;
+ case _AES_:
+ if (bmcst)
+ AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+ else
+ AES_IV(pattrib->iv, psta->dot11txpn, 0);
+ break;
+ }
+ }
+
+ memcpy(pframe, pattrib->iv, pattrib->iv_len);
+
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_,
+ ("rtw_xmitframe_coalesce: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n",
+ padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe+1), *(pframe+2), *(pframe+3)));
+
+ pframe += pattrib->iv_len;
+
+ mpdu_len -= pattrib->iv_len;
+ }
+
+ if (frg_inx == 0) {
+ llc_sz = rtw_put_snap(pframe, pattrib->ether_type);
+ pframe += llc_sz;
+ mpdu_len -= llc_sz;
+ }
+
+ if ((pattrib->icv_len > 0) && (pattrib->bswenc)) {
+ mpdu_len -= pattrib->icv_len;
+ }
+
+ if (bmcst) {
+ /* don't do fragment to broadcat/multicast packets */
+ mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen);
+ } else {
+ mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len);
+ }
+
+ pframe += mem_sz;
+
+ if ((pattrib->icv_len > 0) && (pattrib->bswenc)) {
+ memcpy(pframe, pattrib->icv, pattrib->icv_len);
+ pframe += pattrib->icv_len;
+ }
+
+ frg_inx++;
+
+ if (bmcst || rtw_endofpktfile(&pktfile)) {
+ pattrib->nr_frags = frg_inx;
+
+ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz : 0) +
+ ((pattrib->bswenc) ? pattrib->icv_len : 0) + mem_sz;
+
+ ClearMFrag(mem_start);
+
+ break;
+ } else {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__));
+ }
+
+ addr = (size_t)(pframe);
+
+ mem_start = (unsigned char *)RND4(addr) + hw_hdr_offset;
+ memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen);
+ }
+
+ if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"));
+ DBG_88E("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n");
+ res = _FAIL;
+ goto exit;
+ }
+
+ xmitframe_swencrypt(padapter, pxmitframe);
+
+ if (!bmcst)
+ update_attrib_vcs_info(padapter, pxmitframe);
+ else
+ pattrib->vcs_mode = NONE_VCS;
+
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+/* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header
+ * IEEE LLC/SNAP header contains 8 octets
+ * First 3 octets comprise the LLC portion
+ * SNAP portion, 5 octets, is divided into two fields:
+ * Organizationally Unique Identifier(OUI), 3 octets,
+ * type, defined by that organization, 2 octets.
+ */
+s32 rtw_put_snap(u8 *data, u16 h_proto)
+{
+ struct ieee80211_snap_hdr *snap;
+ u8 *oui;
+
+_func_enter_;
+
+ snap = (struct ieee80211_snap_hdr *)data;
+ snap->dsap = 0xaa;
+ snap->ssap = 0xaa;
+ snap->ctrl = 0x03;
+
+ if (h_proto == 0x8137 || h_proto == 0x80f3)
+ oui = P802_1H_OUI;
+ else
+ oui = RFC1042_OUI;
+
+ snap->oui[0] = oui[0];
+ snap->oui[1] = oui[1];
+ snap->oui[2] = oui[2];
+
+ *(__be16 *)(data + SNAP_SIZE) = htons(h_proto);
+
+_func_exit_;
+
+ return SNAP_SIZE + sizeof(u16);
+}
+
+void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len)
+{
+ uint protection;
+ u8 *perp;
+ int erp_len;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+
+_func_enter_;
+
+ switch (pxmitpriv->vcs_setting) {
+ case DISABLE_VCS:
+ pxmitpriv->vcs = NONE_VCS;
+ break;
+ case ENABLE_VCS:
+ break;
+ case AUTO_VCS:
+ default:
+ perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len);
+ if (perp == NULL) {
+ pxmitpriv->vcs = NONE_VCS;
+ } else {
+ protection = (*(perp + 2)) & BIT(1);
+ if (protection) {
+ if (pregistrypriv->vcs_type == RTS_CTS)
+ pxmitpriv->vcs = RTS_CTS;
+ else
+ pxmitpriv->vcs = CTS_TO_SELF;
+ } else {
+ pxmitpriv->vcs = NONE_VCS;
+ }
+ }
+ break;
+ }
+
+_func_exit_;
+}
+
+void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz)
+{
+ struct sta_info *psta = NULL;
+ struct stainfo_stats *pstats = NULL;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) {
+ pxmitpriv->tx_bytes += sz;
+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod += pxmitframe->agg_num;
+
+ psta = pxmitframe->attrib.psta;
+ if (psta) {
+ pstats = &psta->sta_stats;
+ pstats->tx_pkts += pxmitframe->agg_num;
+ pstats->tx_bytes += sz;
+ }
+ }
+}
+
+struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv)
+{
+ unsigned long irql;
+ struct xmit_buf *pxmitbuf = NULL;
+ struct list_head *plist, *phead;
+ struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
+
+_func_enter_;
+
+ _enter_critical(&pfree_queue->lock, &irql);
+
+ if (_rtw_queue_empty(pfree_queue) == true) {
+ pxmitbuf = NULL;
+ } else {
+ phead = get_list_head(pfree_queue);
+
+ plist = get_next(phead);
+
+ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
+
+ rtw_list_delete(&(pxmitbuf->list));
+ }
+
+ if (pxmitbuf != NULL) {
+ pxmitpriv->free_xmit_extbuf_cnt--;
+
+ pxmitbuf->priv_data = NULL;
+ /* pxmitbuf->ext_tag = true; */
+
+ if (pxmitbuf->sctx) {
+ DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__);
+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
+ }
+ }
+
+ _exit_critical(&pfree_queue->lock, &irql);
+
+_func_exit_;
+
+ return pxmitbuf;
+}
+
+s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+{
+ unsigned long irql;
+ struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
+
+_func_enter_;
+
+ if (pxmitbuf == NULL)
+ return _FAIL;
+
+ _enter_critical(&pfree_queue->lock, &irql);
+
+ rtw_list_delete(&pxmitbuf->list);
+
+ rtw_list_insert_tail(&(pxmitbuf->list), get_list_head(pfree_queue));
+ pxmitpriv->free_xmit_extbuf_cnt++;
+
+ _exit_critical(&pfree_queue->lock, &irql);
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv)
+{
+ unsigned long irql;
+ struct xmit_buf *pxmitbuf = NULL;
+ struct list_head *plist, *phead;
+ struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
+
+_func_enter_;
+
+ /* DBG_88E("+rtw_alloc_xmitbuf\n"); */
+
+ _enter_critical(&pfree_xmitbuf_queue->lock, &irql);
+
+ if (_rtw_queue_empty(pfree_xmitbuf_queue) == true) {
+ pxmitbuf = NULL;
+ } else {
+ phead = get_list_head(pfree_xmitbuf_queue);
+
+ plist = get_next(phead);
+
+ pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
+
+ rtw_list_delete(&(pxmitbuf->list));
+ }
+
+ if (pxmitbuf != NULL) {
+ pxmitpriv->free_xmitbuf_cnt--;
+ pxmitbuf->priv_data = NULL;
+ if (pxmitbuf->sctx) {
+ DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__);
+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
+ }
+ }
+ _exit_critical(&pfree_xmitbuf_queue->lock, &irql);
+
+_func_exit_;
+
+ return pxmitbuf;
+}
+
+s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+{
+ unsigned long irql;
+ struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
+
+_func_enter_;
+ if (pxmitbuf == NULL)
+ return _FAIL;
+
+ if (pxmitbuf->sctx) {
+ DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__);
+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE);
+ }
+
+ if (pxmitbuf->ext_tag) {
+ rtw_free_xmitbuf_ext(pxmitpriv, pxmitbuf);
+ } else {
+ _enter_critical(&pfree_xmitbuf_queue->lock, &irql);
+
+ rtw_list_delete(&pxmitbuf->list);
+
+ rtw_list_insert_tail(&(pxmitbuf->list), get_list_head(pfree_xmitbuf_queue));
+
+ pxmitpriv->free_xmitbuf_cnt++;
+ _exit_critical(&pfree_xmitbuf_queue->lock, &irql);
+ }
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+/*
+Calling context:
+1. OS_TXENTRY
+2. RXENTRY (rx_thread or RX_ISR/RX_CallBack)
+
+If we turn on USE_RXTHREAD, then, no need for critical section.
+Otherwise, we must use _enter/_exit critical to protect free_xmit_queue...
+
+Must be very very cautious...
+
+*/
+
+struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pfree_xmit_queue) */
+{
+ /*
+ Please remember to use all the osdep_service api,
+ and lock/unlock or _enter/_exit critical to protect
+ pfree_xmit_queue
+ */
+
+ unsigned long irql;
+ struct xmit_frame *pxframe = NULL;
+ struct list_head *plist, *phead;
+ struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue;
+
+_func_enter_;
+
+ _enter_critical_bh(&pfree_xmit_queue->lock, &irql);
+
+ if (_rtw_queue_empty(pfree_xmit_queue) == true) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe:%d\n", pxmitpriv->free_xmitframe_cnt));
+ pxframe = NULL;
+ } else {
+ phead = get_list_head(pfree_xmit_queue);
+
+ plist = get_next(phead);
+
+ pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
+
+ rtw_list_delete(&(pxframe->list));
+ }
+
+ if (pxframe != NULL) { /* default value setting */
+ pxmitpriv->free_xmitframe_cnt--;
+
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe():free_xmitframe_cnt=%d\n", pxmitpriv->free_xmitframe_cnt));
+
+ pxframe->buf_addr = NULL;
+ pxframe->pxmitbuf = NULL;
+
+ _rtw_memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib));
+ /* pxframe->attrib.psta = NULL; */
+
+ pxframe->frame_tag = DATA_FRAMETAG;
+
+ pxframe->pkt = NULL;
+ pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */
+
+ pxframe->agg_num = 1;
+ pxframe->ack_report = 0;
+ }
+
+ _exit_critical_bh(&pfree_xmit_queue->lock, &irql);
+
+_func_exit_;
+
+ return pxframe;
+}
+
+s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe)
+{
+ unsigned long irql;
+ struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue;
+ struct adapter *padapter = pxmitpriv->adapter;
+ struct sk_buff *pndis_pkt = NULL;
+
+_func_enter_;
+
+ if (pxmitframe == NULL) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== rtw_free_xmitframe():pxmitframe == NULL!!!!!!!!!!\n"));
+ goto exit;
+ }
+
+ _enter_critical_bh(&pfree_xmit_queue->lock, &irql);
+
+ rtw_list_delete(&pxmitframe->list);
+
+ if (pxmitframe->pkt) {
+ pndis_pkt = pxmitframe->pkt;
+ pxmitframe->pkt = NULL;
+ }
+
+ rtw_list_insert_tail(&pxmitframe->list, get_list_head(pfree_xmit_queue));
+
+ pxmitpriv->free_xmitframe_cnt++;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xmitframe_cnt=%d\n", pxmitpriv->free_xmitframe_cnt));
+
+ _exit_critical_bh(&pfree_xmit_queue->lock, &irql);
+
+ if (pndis_pkt)
+ rtw_os_pkt_complete(padapter, pndis_pkt);
+
+exit:
+
+_func_exit_;
+
+ return _SUCCESS;
+}
+
+void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue)
+{
+ unsigned long irql;
+ struct list_head *plist, *phead;
+ struct xmit_frame *pxmitframe;
+
+_func_enter_;
+
+ _enter_critical_bh(&(pframequeue->lock), &irql);
+
+ phead = get_list_head(pframequeue);
+ plist = get_next(phead);
+
+ while (!rtw_end_of_queue_search(phead, plist)) {
+ pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
+
+ plist = get_next(plist);
+
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
+ }
+ _exit_critical_bh(&(pframequeue->lock), &irql);
+
+_func_exit_;
+}
+
+s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+ if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+ ("rtw_xmitframe_enqueue: drop xmit pkt for classifier fail\n"));
+/* pxmitframe->pkt = NULL; */
+ return _FAIL;
+ }
+
+ return _SUCCESS;
+}
+
+static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit, struct tx_servq *ptxservq, struct __queue *pframe_queue)
+{
+ struct list_head *xmitframe_plist, *xmitframe_phead;
+ struct xmit_frame *pxmitframe = NULL;
+
+ xmitframe_phead = get_list_head(pframe_queue);
+ xmitframe_plist = get_next(xmitframe_phead);
+
+ while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+ xmitframe_plist = get_next(xmitframe_plist);
+
+ rtw_list_delete(&pxmitframe->list);
+
+ ptxservq->qcnt--;
+
+ break;
+
+ pxmitframe = NULL;
+ }
+
+ return pxmitframe;
+}
+
+struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i, int entry)
+{
+ unsigned long irql0;
+ struct list_head *sta_plist, *sta_phead;
+ struct hw_xmit *phwxmit;
+ struct tx_servq *ptxservq = NULL;
+ struct __queue *pframe_queue = NULL;
+ struct xmit_frame *pxmitframe = NULL;
+ struct adapter *padapter = pxmitpriv->adapter;
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ int i, inx[4];
+
+_func_enter_;
+
+ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
+
+ if (pregpriv->wifi_spec == 1) {
+ int j;
+
+ for (j = 0; j < 4; j++)
+ inx[j] = pxmitpriv->wmm_para_seq[j];
+ }
+
+ _enter_critical_bh(&pxmitpriv->lock, &irql0);
+
+ for (i = 0; i < entry; i++) {
+ phwxmit = phwxmit_i + inx[i];
+
+ sta_phead = get_list_head(phwxmit->sta_queue);
+ sta_plist = get_next(sta_phead);
+
+ while (!rtw_end_of_queue_search(sta_phead, sta_plist)) {
+ ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
+
+ pframe_queue = &ptxservq->sta_pending;
+
+ pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue);
+
+ if (pxmitframe) {
+ phwxmit->accnt--;
+
+ /* Remove sta node when there are no pending packets. */
+ if (_rtw_queue_empty(pframe_queue)) /* must be done after get_next and before break */
+ rtw_list_delete(&ptxservq->tx_pending);
+ goto exit;
+ }
+
+ sta_plist = get_next(sta_plist);
+ }
+ }
+exit:
+ _exit_critical_bh(&pxmitpriv->lock, &irql0);
+_func_exit_;
+ return pxmitframe;
+}
+
+struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, int up, u8 *ac)
+{
+ struct tx_servq *ptxservq;
+
+_func_enter_;
+ switch (up) {
+ case 1:
+ case 2:
+ ptxservq = &(psta->sta_xmitpriv.bk_q);
+ *(ac) = 3;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BK\n"));
+ break;
+ case 4:
+ case 5:
+ ptxservq = &(psta->sta_xmitpriv.vi_q);
+ *(ac) = 1;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VI\n"));
+ break;
+ case 6:
+ case 7:
+ ptxservq = &(psta->sta_xmitpriv.vo_q);
+ *(ac) = 0;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VO\n"));
+ break;
+ case 0:
+ case 3:
+ default:
+ ptxservq = &(psta->sta_xmitpriv.be_q);
+ *(ac) = 2;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BE\n"));
+ break;
+ }
+
+_func_exit_;
+
+ return ptxservq;
+}
+
+/*
+ * Will enqueue pxmitframe to the proper queue,
+ * and indicate it to xx_pending list.....
+ */
+s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+ /* unsigned long irql0; */
+ u8 ac_index;
+ struct sta_info *psta;
+ struct tx_servq *ptxservq;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
+ int res = _SUCCESS;
+
+_func_enter_;
+
+ if (pattrib->psta) {
+ psta = pattrib->psta;
+ } else {
+ psta = rtw_get_stainfo(pstapriv, pattrib->ra);
+ }
+
+ if (psta == NULL) {
+ res = _FAIL;
+ DBG_88E("rtw_xmit_classifier: psta == NULL\n");
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmit_classifier: psta == NULL\n"));
+ goto exit;
+ }
+
+ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index));
+
+ if (rtw_is_list_empty(&ptxservq->tx_pending))
+ rtw_list_insert_tail(&ptxservq->tx_pending, get_list_head(phwxmits[ac_index].sta_queue));
+
+ rtw_list_insert_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending));
+ ptxservq->qcnt++;
+ phwxmits[ac_index].accnt++;
+exit:
+
+_func_exit_;
+
+ return res;
+}
+
+void rtw_alloc_hwxmits(struct adapter *padapter)
+{
+ struct hw_xmit *hwxmits;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+ pxmitpriv->hwxmit_entry = HWXMIT_ENTRY;
+
+ pxmitpriv->hwxmits = (struct hw_xmit *)rtw_zmalloc(sizeof(struct hw_xmit) * pxmitpriv->hwxmit_entry);
+
+ hwxmits = pxmitpriv->hwxmits;
+
+ if (pxmitpriv->hwxmit_entry == 5) {
+ hwxmits[0] .sta_queue = &pxmitpriv->bm_pending;
+ hwxmits[1] .sta_queue = &pxmitpriv->vo_pending;
+ hwxmits[2] .sta_queue = &pxmitpriv->vi_pending;
+ hwxmits[3] .sta_queue = &pxmitpriv->bk_pending;
+ hwxmits[4] .sta_queue = &pxmitpriv->be_pending;
+ } else if (pxmitpriv->hwxmit_entry == 4) {
+ hwxmits[0] .sta_queue = &pxmitpriv->vo_pending;
+ hwxmits[1] .sta_queue = &pxmitpriv->vi_pending;
+ hwxmits[2] .sta_queue = &pxmitpriv->be_pending;
+ hwxmits[3] .sta_queue = &pxmitpriv->bk_pending;
+ } else {
+ }
+}
+
+void rtw_free_hwxmits(struct adapter *padapter)
+{
+ struct hw_xmit *hwxmits;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+ hwxmits = pxmitpriv->hwxmits;
+ kfree(hwxmits);
+}
+
+void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry)
+{
+ int i;
+_func_enter_;
+ for (i = 0; i < entry; i++, phwxmit++)
+ phwxmit->accnt = 0;
+_func_exit_;
+}
+
+static int rtw_br_client_tx(struct adapter *padapter, struct sk_buff **pskb)
+{
+ struct sk_buff *skb = *pskb;
+ unsigned long irql;
+ int res, is_vlan_tag = 0, i, do_nat25 = 1;
+ unsigned short vlan_hdr = 0;
+ void *br_port = NULL;
+
+ rcu_read_lock();
+ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data);
+ rcu_read_unlock();
+ _enter_critical_bh(&padapter->br_ext_lock, &irql);
+ if (!(skb->data[0] & 1) && br_port &&
+ memcmp(skb->data+MACADDRLEN, padapter->br_mac, MACADDRLEN) &&
+ *((__be16 *)(skb->data+MACADDRLEN*2)) != __constant_htons(ETH_P_8021Q) &&
+ *((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP) &&
+ !memcmp(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN) && padapter->scdb_entry) {
+ memcpy(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN);
+ padapter->scdb_entry->ageing_timer = jiffies;
+ _exit_critical_bh(&padapter->br_ext_lock, &irql);
+ } else {
+ if (*((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_8021Q)) {
+ is_vlan_tag = 1;
+ vlan_hdr = *((unsigned short *)(skb->data+MACADDRLEN*2+2));
+ for (i = 0; i < 6; i++)
+ *((unsigned short *)(skb->data+MACADDRLEN*2+2-i*2)) = *((unsigned short *)(skb->data+MACADDRLEN*2-2-i*2));
+ skb_pull(skb, 4);
+ }
+ if (!memcmp(skb->data+MACADDRLEN, padapter->br_mac, MACADDRLEN) &&
+ (*((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP)))
+ memcpy(padapter->br_ip, skb->data+WLAN_ETHHDR_LEN+12, 4);
+
+ if (*((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP)) {
+ if (memcmp(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN)) {
+ padapter->scdb_entry = (struct nat25_network_db_entry *)scdb_findEntry(padapter,
+ skb->data+MACADDRLEN, skb->data+WLAN_ETHHDR_LEN+12);
+ if (padapter->scdb_entry) {
+ memcpy(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN);
+ memcpy(padapter->scdb_ip, skb->data+WLAN_ETHHDR_LEN+12, 4);
+ padapter->scdb_entry->ageing_timer = jiffies;
+ do_nat25 = 0;
+ }
+ } else {
+ if (padapter->scdb_entry) {
+ padapter->scdb_entry->ageing_timer = jiffies;
+ do_nat25 = 0;
+ } else {
+ memset(padapter->scdb_mac, 0, MACADDRLEN);
+ memset(padapter->scdb_ip, 0, 4);
+ }
+ }
+ }
+ _exit_critical_bh(&padapter->br_ext_lock, &irql);
+ if (do_nat25) {
+ if (nat25_db_handle(padapter, skb, NAT25_CHECK) == 0) {
+ struct sk_buff *newskb;
+
+ if (is_vlan_tag) {
+ skb_push(skb, 4);
+ for (i = 0; i < 6; i++)
+ *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2));
+ *((__be16 *)(skb->data+MACADDRLEN*2)) = __constant_htons(ETH_P_8021Q);
+ *((unsigned short *)(skb->data+MACADDRLEN*2+2)) = vlan_hdr;
+ }
+
+ newskb = skb_copy(skb, GFP_ATOMIC);
+ if (newskb == NULL) {
+ DEBUG_ERR("TX DROP: skb_copy fail!\n");
+ return -1;
+ }
+ dev_kfree_skb_any(skb);
+
+ *pskb = skb = newskb;
+ if (is_vlan_tag) {
+ vlan_hdr = *((unsigned short *)(skb->data+MACADDRLEN*2+2));
+ for (i = 0; i < 6; i++)
+ *((unsigned short *)(skb->data+MACADDRLEN*2+2-i*2)) = *((unsigned short *)(skb->data+MACADDRLEN*2-2-i*2));
+ skb_pull(skb, 4);
+ }
+ }
+
+ if (skb_is_nonlinear(skb))
+ DEBUG_ERR("%s(): skb_is_nonlinear!!\n", __func__);
+
+ res = skb_linearize(skb);
+ if (res < 0) {
+ DEBUG_ERR("TX DROP: skb_linearize fail!\n");
+ return -1;
+ }
+
+ res = nat25_db_handle(padapter, skb, NAT25_INSERT);
+ if (res < 0) {
+ if (res == -2) {
+ DEBUG_ERR("TX DROP: nat25_db_handle fail!\n");
+ return -1;
+ }
+ return 0;
+ }
+ }
+
+ memcpy(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN);
+
+ dhcp_flag_bcast(padapter, skb);
+
+ if (is_vlan_tag) {
+ skb_push(skb, 4);
+ for (i = 0; i < 6; i++)
+ *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2));
+ *((__be16 *)(skb->data+MACADDRLEN*2)) = __constant_htons(ETH_P_8021Q);
+ *((unsigned short *)(skb->data+MACADDRLEN*2+2)) = vlan_hdr;
+ }
+ }
+
+ /* check if SA is equal to our MAC */
+ if (memcmp(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN)) {
+ DEBUG_ERR("TX DROP: untransformed frame SA:%02X%02X%02X%02X%02X%02X!\n",
+ skb->data[6], skb->data[7], skb->data[8], skb->data[9], skb->data[10], skb->data[11]);
+ return -1;
+ }
+ return 0;
+}
+
+u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe)
+{
+ u32 addr;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+
+ switch (pattrib->qsel) {
+ case 0:
+ case 3:
+ addr = BE_QUEUE_INX;
+ break;
+ case 1:
+ case 2:
+ addr = BK_QUEUE_INX;
+ break;
+ case 4:
+ case 5:
+ addr = VI_QUEUE_INX;
+ break;
+ case 6:
+ case 7:
+ addr = VO_QUEUE_INX;
+ break;
+ case 0x10:
+ addr = BCN_QUEUE_INX;
+ break;
+ case 0x11:/* BC/MC in PS (HIQ) */
+ addr = HIGH_QUEUE_INX;
+ break;
+ case 0x12:
+ default:
+ addr = MGT_QUEUE_INX;
+ break;
+ }
+
+ return addr;
+}
+
+static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib)
+{
+ u8 qsel;
+
+ qsel = pattrib->priority;
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("### do_queue_select priority=%d , qsel = %d\n", pattrib->priority , qsel));
+
+ pattrib->qsel = qsel;
+}
+
+/*
+ * The main transmit(tx) entry
+ *
+ * Return
+ * 1 enqueue
+ * 0 success, hardware will handle this xmit frame(packet)
+ * <0 fail
+ */
+s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt)
+{
+#ifdef CONFIG_88EU_AP_MODE
+ unsigned long irql0;
+#endif
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct xmit_frame *pxmitframe = NULL;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ void *br_port = NULL;
+ s32 res;
+
+ pxmitframe = rtw_alloc_xmitframe(pxmitpriv);
+ if (pxmitframe == NULL) {
+ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: no more pxmitframe\n"));
+ DBG_88E("DBG_TX_DROP_FRAME %s no more pxmitframe\n", __func__);
+ return -1;
+ }
+
+ rcu_read_lock();
+ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data);
+ rcu_read_unlock();
+
+ if (br_port && check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE)) {
+ res = rtw_br_client_tx(padapter, ppkt);
+ if (res == -1) {
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
+ return -1;
+ }
+ }
+
+ res = update_attrib(padapter, *ppkt, &pxmitframe->attrib);
+
+ if (res == _FAIL) {
+ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: update attrib fail\n"));
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
+ return -1;
+ }
+ pxmitframe->pkt = *ppkt;
+
+ rtw_led_control(padapter, LED_CTL_TX);
+
+ do_queue_select(padapter, &pxmitframe->attrib);
+
+#ifdef CONFIG_88EU_AP_MODE
+ _enter_critical_bh(&pxmitpriv->lock, &irql0);
+ if (xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe)) {
+ _exit_critical_bh(&pxmitpriv->lock, &irql0);
+ return 1;
+ }
+ _exit_critical_bh(&pxmitpriv->lock, &irql0);
+#endif
+
+ if (rtw_hal_xmit(padapter, pxmitframe) == false)
+ return 1;
+
+ return 0;
+}
+
+#if defined(CONFIG_88EU_AP_MODE)
+
+int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+ unsigned long irql;
+ int ret = false;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ int bmcst = IS_MCAST(pattrib->ra);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false)
+ return ret;
+
+ if (pattrib->psta)
+ psta = pattrib->psta;
+ else
+ psta = rtw_get_stainfo(pstapriv, pattrib->ra);
+
+ if (psta == NULL)
+ return ret;
+
+ if (pattrib->triggered == 1) {
+ if (bmcst)
+ pattrib->qsel = 0x11;/* HIQ */
+ return ret;
+ }
+
+ if (bmcst) {
+ _enter_critical_bh(&psta->sleep_q.lock, &irql);
+
+ if (pstapriv->sta_dz_bitmap) {/* if any one sta is in ps mode */
+ rtw_list_delete(&pxmitframe->list);
+
+ rtw_list_insert_tail(&pxmitframe->list, get_list_head(&psta->sleep_q));
+
+ psta->sleepq_len++;
+
+ pstapriv->tim_bitmap |= BIT(0);/* */
+ pstapriv->sta_dz_bitmap |= BIT(0);
+
+ update_beacon(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after upate bcn */
+
+ ret = true;
+ }
+
+ _exit_critical_bh(&psta->sleep_q.lock, &irql);
+
+ return ret;
+ }
+
+ _enter_critical_bh(&psta->sleep_q.lock, &irql);
+
+ if (psta->state&WIFI_SLEEP_STATE) {
+ u8 wmmps_ac = 0;
+
+ if (pstapriv->sta_dz_bitmap&BIT(psta->aid)) {
+ rtw_list_delete(&pxmitframe->list);
+
+ rtw_list_insert_tail(&pxmitframe->list, get_list_head(&psta->sleep_q));
+
+ psta->sleepq_len++;
+
+ switch (pattrib->priority) {
+ case 1:
+ case 2:
+ wmmps_ac = psta->uapsd_bk&BIT(0);
+ break;
+ case 4:
+ case 5:
+ wmmps_ac = psta->uapsd_vi&BIT(0);
+ break;
+ case 6:
+ case 7:
+ wmmps_ac = psta->uapsd_vo&BIT(0);
+ break;
+ case 0:
+ case 3:
+ default:
+ wmmps_ac = psta->uapsd_be&BIT(0);
+ break;
+ }
+
+ if (wmmps_ac)
+ psta->sleepq_ac_len++;
+
+ if (((psta->has_legacy_ac) && (!wmmps_ac)) ||
+ ((!psta->has_legacy_ac) && (wmmps_ac))) {
+ pstapriv->tim_bitmap |= BIT(psta->aid);
+
+ if (psta->sleepq_len == 1) {
+ /* upate BCN for TIM IE */
+ update_beacon(padapter, _TIM_IE_, NULL, false);
+ }
+ }
+ ret = true;
+ }
+ }
+
+ _exit_critical_bh(&psta->sleep_q.lock, &irql);
+
+ return ret;
+}
+
+static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue)
+{
+ struct list_head *plist, *phead;
+ u8 ac_index;
+ struct tx_servq *ptxservq;
+ struct pkt_attrib *pattrib;
+ struct xmit_frame *pxmitframe;
+ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
+
+ phead = get_list_head(pframequeue);
+ plist = get_next(phead);
+
+ while (!rtw_end_of_queue_search(phead, plist)) {
+ pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
+
+ plist = get_next(plist);
+
+ xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe);
+
+ pattrib = &pxmitframe->attrib;
+
+ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index));
+
+ ptxservq->qcnt--;
+ phwxmits[ac_index].accnt--;
+ }
+}
+
+void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta)
+{
+ unsigned long irql0;
+ struct sta_info *psta_bmc;
+ struct sta_xmit_priv *pstaxmitpriv;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+ pstaxmitpriv = &psta->sta_xmitpriv;
+
+ /* for BC/MC Frames */
+ psta_bmc = rtw_get_bcmc_stainfo(padapter);
+
+ _enter_critical_bh(&pxmitpriv->lock, &irql0);
+
+ psta->state |= WIFI_SLEEP_STATE;
+
+ pstapriv->sta_dz_bitmap |= BIT(psta->aid);
+
+ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending);
+ rtw_list_delete(&(pstaxmitpriv->vo_q.tx_pending));
+
+ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending);
+ rtw_list_delete(&(pstaxmitpriv->vi_q.tx_pending));
+
+ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->be_q.sta_pending);
+ rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending));
+
+ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->bk_q.sta_pending);
+ rtw_list_delete(&(pstaxmitpriv->bk_q.tx_pending));
+
+ /* for BC/MC Frames */
+ pstaxmitpriv = &psta_bmc->sta_xmitpriv;
+ dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, &pstaxmitpriv->be_q.sta_pending);
+ rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending));
+
+ _exit_critical_bh(&pxmitpriv->lock, &irql0);
+}
+
+void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
+{
+ unsigned long irql;
+ u8 update_mask = 0, wmmps_ac = 0;
+ struct sta_info *psta_bmc;
+ struct list_head *xmitframe_plist, *xmitframe_phead;
+ struct xmit_frame *pxmitframe = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ _enter_critical_bh(&psta->sleep_q.lock, &irql);
+
+ xmitframe_phead = get_list_head(&psta->sleep_q);
+ xmitframe_plist = get_next(xmitframe_phead);
+
+ while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+ xmitframe_plist = get_next(xmitframe_plist);
+
+ rtw_list_delete(&pxmitframe->list);
+
+ switch (pxmitframe->attrib.priority) {
+ case 1:
+ case 2:
+ wmmps_ac = psta->uapsd_bk&BIT(1);
+ break;
+ case 4:
+ case 5:
+ wmmps_ac = psta->uapsd_vi&BIT(1);
+ break;
+ case 6:
+ case 7:
+ wmmps_ac = psta->uapsd_vo&BIT(1);
+ break;
+ case 0:
+ case 3:
+ default:
+ wmmps_ac = psta->uapsd_be&BIT(1);
+ break;
+ }
+
+ psta->sleepq_len--;
+ if (psta->sleepq_len > 0)
+ pxmitframe->attrib.mdata = 1;
+ else
+ pxmitframe->attrib.mdata = 0;
+
+ if (wmmps_ac) {
+ psta->sleepq_ac_len--;
+ if (psta->sleepq_ac_len > 0) {
+ pxmitframe->attrib.mdata = 1;
+ pxmitframe->attrib.eosp = 0;
+ } else {
+ pxmitframe->attrib.mdata = 0;
+ pxmitframe->attrib.eosp = 1;
+ }
+ }
+
+ pxmitframe->attrib.triggered = 1;
+
+ _exit_critical_bh(&psta->sleep_q.lock, &irql);
+ if (rtw_hal_xmit(padapter, pxmitframe))
+ rtw_os_xmit_complete(padapter, pxmitframe);
+ _enter_critical_bh(&psta->sleep_q.lock, &irql);
+ }
+
+ if (psta->sleepq_len == 0) {
+ pstapriv->tim_bitmap &= ~BIT(psta->aid);
+
+ update_mask = BIT(0);
+
+ if (psta->state&WIFI_SLEEP_STATE)
+ psta->state ^= WIFI_SLEEP_STATE;
+
+ if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
+ psta->expire_to = pstapriv->expire_to;
+ psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+ }
+
+ pstapriv->sta_dz_bitmap &= ~BIT(psta->aid);
+ }
+
+ _exit_critical_bh(&psta->sleep_q.lock, &irql);
+
+ /* for BC/MC Frames */
+ psta_bmc = rtw_get_bcmc_stainfo(padapter);
+ if (!psta_bmc)
+ return;
+
+ if ((pstapriv->sta_dz_bitmap&0xfffe) == 0x0) { /* no any sta in ps mode */
+ _enter_critical_bh(&psta_bmc->sleep_q.lock, &irql);
+
+ xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
+ xmitframe_plist = get_next(xmitframe_phead);
+
+ while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+ xmitframe_plist = get_next(xmitframe_plist);
+
+ rtw_list_delete(&pxmitframe->list);
+
+ psta_bmc->sleepq_len--;
+ if (psta_bmc->sleepq_len > 0)
+ pxmitframe->attrib.mdata = 1;
+ else
+ pxmitframe->attrib.mdata = 0;
+
+ pxmitframe->attrib.triggered = 1;
+
+ _exit_critical_bh(&psta_bmc->sleep_q.lock, &irql);
+ if (rtw_hal_xmit(padapter, pxmitframe))
+ rtw_os_xmit_complete(padapter, pxmitframe);
+ _enter_critical_bh(&psta_bmc->sleep_q.lock, &irql);
+ }
+
+ if (psta_bmc->sleepq_len == 0) {
+ pstapriv->tim_bitmap &= ~BIT(0);
+ pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+ update_mask |= BIT(1);
+ }
+
+ _exit_critical_bh(&psta_bmc->sleep_q.lock, &irql);
+ }
+
+ if (update_mask)
+ update_beacon(padapter, _TIM_IE_, NULL, false);
+}
+
+void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta)
+{
+ unsigned long irql;
+ u8 wmmps_ac = 0;
+ struct list_head *xmitframe_plist, *xmitframe_phead;
+ struct xmit_frame *pxmitframe = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ _enter_critical_bh(&psta->sleep_q.lock, &irql);
+
+ xmitframe_phead = get_list_head(&psta->sleep_q);
+ xmitframe_plist = get_next(xmitframe_phead);
+
+ while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+ xmitframe_plist = get_next(xmitframe_plist);
+
+ switch (pxmitframe->attrib.priority) {
+ case 1:
+ case 2:
+ wmmps_ac = psta->uapsd_bk&BIT(1);
+ break;
+ case 4:
+ case 5:
+ wmmps_ac = psta->uapsd_vi&BIT(1);
+ break;
+ case 6:
+ case 7:
+ wmmps_ac = psta->uapsd_vo&BIT(1);
+ break;
+ case 0:
+ case 3:
+ default:
+ wmmps_ac = psta->uapsd_be&BIT(1);
+ break;
+ }
+
+ if (!wmmps_ac)
+ continue;
+
+ rtw_list_delete(&pxmitframe->list);
+
+ psta->sleepq_len--;
+ psta->sleepq_ac_len--;
+
+ if (psta->sleepq_ac_len > 0) {
+ pxmitframe->attrib.mdata = 1;
+ pxmitframe->attrib.eosp = 0;
+ } else {
+ pxmitframe->attrib.mdata = 0;
+ pxmitframe->attrib.eosp = 1;
+ }
+
+ pxmitframe->attrib.triggered = 1;
+
+ if (rtw_hal_xmit(padapter, pxmitframe) == true)
+ rtw_os_xmit_complete(padapter, pxmitframe);
+
+ if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) {
+ pstapriv->tim_bitmap &= ~BIT(psta->aid);
+
+ /* upate BCN for TIM IE */
+ update_beacon(padapter, _TIM_IE_, NULL, false);
+ }
+ }
+
+ _exit_critical_bh(&psta->sleep_q.lock, &irql);
+}
+
+#endif
+
+void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms)
+{
+ sctx->timeout_ms = timeout_ms;
+ sctx->submit_time = rtw_get_current_time();
+ init_completion(&sctx->done);
+ sctx->status = RTW_SCTX_SUBMITTED;
+}
+
+int rtw_sctx_wait(struct submit_ctx *sctx)
+{
+ int ret = _FAIL;
+ unsigned long expire;
+ int status = 0;
+
+ expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) : MAX_SCHEDULE_TIMEOUT;
+ if (!wait_for_completion_timeout(&sctx->done, expire)) {
+ /* timeout, do something?? */
+ status = RTW_SCTX_DONE_TIMEOUT;
+ DBG_88E("%s timeout\n", __func__);
+ } else {
+ status = sctx->status;
+ }
+
+ if (status == RTW_SCTX_DONE_SUCCESS)
+ ret = _SUCCESS;
+
+ return ret;
+}
+
+static bool rtw_sctx_chk_waring_status(int status)
+{
+ switch (status) {
+ case RTW_SCTX_DONE_UNKNOWN:
+ case RTW_SCTX_DONE_BUF_ALLOC:
+ case RTW_SCTX_DONE_BUF_FREE:
+
+ case RTW_SCTX_DONE_DRV_STOP:
+ case RTW_SCTX_DONE_DEV_REMOVE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void rtw_sctx_done_err(struct submit_ctx **sctx, int status)
+{
+ if (*sctx) {
+ if (rtw_sctx_chk_waring_status(status))
+ DBG_88E("%s status:%d\n", __func__, status);
+ (*sctx)->status = status;
+ complete(&((*sctx)->done));
+ *sctx = NULL;
+ }
+}
+
+void rtw_sctx_done(struct submit_ctx **sctx)
+{
+ rtw_sctx_done_err(sctx, RTW_SCTX_DONE_SUCCESS);
+}
+
+int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms)
+{
+ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
+
+ pack_tx_ops->submit_time = rtw_get_current_time();
+ pack_tx_ops->timeout_ms = timeout_ms;
+ pack_tx_ops->status = RTW_SCTX_SUBMITTED;
+
+ return rtw_sctx_wait(pack_tx_ops);
+}
+
+void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status)
+{
+ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
+
+ if (pxmitpriv->ack_tx)
+ rtw_sctx_done_err(&pack_tx_ops, status);
+ else
+ DBG_88E("%s ack_tx not set\n", __func__);
+}
diff --git a/drivers/staging/rtl8188eu/hal/Hal8188EFWImg_CE.c b/drivers/staging/rtl8188eu/hal/Hal8188EFWImg_CE.c
new file mode 100644
index 00000000000..95759bed541
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/Hal8188EFWImg_CE.c
@@ -0,0 +1,1761 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+*
+*
+******************************************************************************/
+#include "odm_precomp.h"
+
+const u8 Rtl8188EFwImgArray[Rtl8188EFWImgArrayLength] = {
+ 0xE1, 0x88, 0x10, 0x00, 0x0B, 0x00, 0x01, 0x00,
+ 0x01, 0x21, 0x11, 0x27, 0x30, 0x36, 0x00, 0x00,
+ 0x2D, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x45, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xC1, 0x6F, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xA1, 0xE6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x56, 0xF7, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC2, 0xAF, 0x80, 0xFE, 0x32, 0x12, 0x42, 0x04,
+ 0x85, 0xD0, 0x0B, 0x75, 0xD0, 0x08, 0xAA, 0xE0,
+ 0xC2, 0x8C, 0xE5, 0x8A, 0x24, 0x67, 0xF5, 0x8A,
+ 0xE5, 0x8C, 0x34, 0x79, 0xF5, 0x8C, 0xD2, 0x8C,
+ 0xEC, 0x24, 0x89, 0xF8, 0xE6, 0xBC, 0x03, 0x02,
+ 0x74, 0xFF, 0xC3, 0x95, 0x81, 0xB4, 0x40, 0x00,
+ 0x40, 0xCE, 0x79, 0x04, 0x78, 0x80, 0x16, 0xE6,
+ 0x08, 0x70, 0x0B, 0xC2, 0xAF, 0xE6, 0x30, 0xE1,
+ 0x03, 0x44, 0x18, 0xF6, 0xD2, 0xAF, 0x08, 0xD9,
+ 0xED, 0xEA, 0x8B, 0xD0, 0x22, 0xE5, 0x0C, 0xFF,
+ 0x23, 0x24, 0x81, 0xF8, 0x0F, 0x08, 0x08, 0xBF,
+ 0x04, 0x04, 0x7F, 0x00, 0x78, 0x81, 0xE6, 0x30,
+ 0xE4, 0xF2, 0x00, 0xE5, 0x0C, 0xC3, 0x9F, 0x50,
+ 0x20, 0x05, 0x0C, 0x74, 0x88, 0x25, 0x0C, 0xF8,
+ 0xE6, 0xFD, 0xA6, 0x81, 0x08, 0xE6, 0xAE, 0x0C,
+ 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xCD, 0xF8, 0xE8,
+ 0x6D, 0x60, 0xE0, 0x08, 0xE6, 0xC0, 0xE0, 0x80,
+ 0xF6, 0xE5, 0x0C, 0xD3, 0x9F, 0x40, 0x27, 0xE5,
+ 0x0C, 0x24, 0x89, 0xF8, 0xE6, 0xAE, 0x0C, 0xBE,
+ 0x03, 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xCD,
+ 0xF8, 0xE5, 0x81, 0x6D, 0x60, 0x06, 0xD0, 0xE0,
+ 0xF6, 0x18, 0x80, 0xF5, 0xE5, 0x0C, 0x24, 0x88,
+ 0xC8, 0xF6, 0x15, 0x0C, 0x80, 0xD3, 0xE5, 0x0C,
+ 0x23, 0x24, 0x81, 0xF8, 0x7F, 0x04, 0xC2, 0xAF,
+ 0xE6, 0x30, 0xE0, 0x03, 0x10, 0xE2, 0x0C, 0x7F,
+ 0x00, 0x30, 0xE1, 0x07, 0x30, 0xE3, 0x04, 0x7F,
+ 0x08, 0x54, 0xF4, 0x54, 0x7C, 0xC6, 0xD2, 0xAF,
+ 0x54, 0x80, 0x42, 0x07, 0x22, 0x78, 0x88, 0xA6,
+ 0x81, 0x74, 0x03, 0x60, 0x06, 0xFF, 0x08, 0x76,
+ 0xFF, 0xDF, 0xFB, 0x7F, 0x04, 0xE4, 0x78, 0x80,
+ 0xF6, 0x08, 0xF6, 0x08, 0xDF, 0xFA, 0x78, 0x81,
+ 0x76, 0x30, 0x90, 0x45, 0xDE, 0x74, 0x01, 0x93,
+ 0xC0, 0xE0, 0xE4, 0x93, 0xC0, 0xE0, 0x43, 0x89,
+ 0x01, 0x75, 0x8A, 0x60, 0x75, 0x8C, 0x79, 0xD2,
+ 0x8C, 0xD2, 0xAF, 0x22, 0x03, 0xEF, 0xD3, 0x94,
+ 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0x74, 0x81,
+ 0x2F, 0x2F, 0xF8, 0xE6, 0x20, 0xE5, 0xF4, 0xC2,
+ 0xAF, 0xE6, 0x44, 0x30, 0xF6, 0xD2, 0xAF, 0xAE,
+ 0x0C, 0xEE, 0xC3, 0x9F, 0x50, 0x21, 0x0E, 0x74,
+ 0x88, 0x2E, 0xF8, 0xE6, 0xF9, 0x08, 0xE6, 0x18,
+ 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0xED, 0x69,
+ 0x60, 0x09, 0x09, 0xE7, 0x19, 0x19, 0xF7, 0x09,
+ 0x09, 0x80, 0xF3, 0x16, 0x16, 0x80, 0xDA, 0xEE,
+ 0xD3, 0x9F, 0x40, 0x04, 0x05, 0x81, 0x05, 0x81,
+ 0xEE, 0xD3, 0x9F, 0x40, 0x22, 0x74, 0x88, 0x2E,
+ 0xF8, 0x08, 0xE6, 0xF9, 0xEE, 0xB5, 0x0C, 0x02,
+ 0xA9, 0x81, 0x18, 0x06, 0x06, 0xE6, 0xFD, 0xED,
+ 0x69, 0x60, 0x09, 0x19, 0x19, 0xE7, 0x09, 0x09,
+ 0xF7, 0x19, 0x80, 0xF3, 0x1E, 0x80, 0xD9, 0xEF,
+ 0x24, 0x88, 0xF8, 0xE6, 0x04, 0xF8, 0xEF, 0x2F,
+ 0x04, 0x90, 0x45, 0xDE, 0x93, 0xF6, 0x08, 0xEF,
+ 0x2F, 0x93, 0xF6, 0x7F, 0x00, 0x22, 0xEF, 0xD3,
+ 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF,
+ 0x23, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE5, 0xF4,
+ 0xC2, 0xAF, 0xE6, 0x54, 0x8C, 0xF6, 0xD2, 0xAF,
+ 0xE5, 0x0C, 0xB5, 0x07, 0x0A, 0x74, 0x88, 0x2F,
+ 0xF8, 0xE6, 0xF5, 0x81, 0x02, 0x42, 0x4D, 0x50,
+ 0x2E, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xBF, 0x03,
+ 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xF9, 0x74,
+ 0x88, 0x2F, 0xF8, 0xFB, 0xE6, 0xFC, 0xE9, 0x6C,
+ 0x60, 0x08, 0xA8, 0x05, 0xE7, 0xF6, 0x1D, 0x19,
+ 0x80, 0xF4, 0xA8, 0x03, 0xA6, 0x05, 0x1F, 0xE5,
+ 0x0C, 0xB5, 0x07, 0xE3, 0x7F, 0x00, 0x22, 0x74,
+ 0x89, 0x2F, 0xF8, 0xE6, 0xFD, 0x18, 0x86, 0x01,
+ 0x0F, 0x74, 0x88, 0x2F, 0xF8, 0xA6, 0x01, 0x08,
+ 0x86, 0x04, 0xE5, 0x0C, 0xB5, 0x07, 0x02, 0xAC,
+ 0x81, 0xED, 0x6C, 0x60, 0x08, 0x0D, 0x09, 0xA8,
+ 0x05, 0xE6, 0xF7, 0x80, 0xF4, 0xE5, 0x0C, 0xB5,
+ 0x07, 0xDE, 0x89, 0x81, 0x7F, 0x00, 0x22, 0xEF,
+ 0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22,
+ 0xEF, 0x23, 0x24, 0x81, 0xF8, 0xC2, 0xAF, 0xE6,
+ 0x30, 0xE5, 0x05, 0x30, 0xE0, 0x02, 0xD2, 0xE4,
+ 0xD2, 0xE2, 0xC6, 0xD2, 0xAF, 0x7F, 0x00, 0x30,
+ 0xE2, 0x01, 0x0F, 0x02, 0x42, 0x4C, 0x8F, 0xF0,
+ 0xE4, 0xFF, 0xFE, 0xE5, 0x0C, 0x23, 0x24, 0x80,
+ 0xF8, 0xC2, 0xA9, 0x30, 0xF7, 0x0D, 0x7F, 0x08,
+ 0xE6, 0x60, 0x0B, 0x2D, 0xF6, 0x60, 0x30, 0x50,
+ 0x2E, 0x80, 0x07, 0x30, 0xF1, 0x06, 0xED, 0xF6,
+ 0x60, 0x25, 0x7E, 0x02, 0x08, 0x30, 0xF0, 0x10,
+ 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x23, 0x0E, 0x30,
+ 0xE2, 0x0C, 0xD2, 0xAF, 0x7F, 0x04, 0x80, 0x12,
+ 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x13, 0x54, 0xEC,
+ 0x4E, 0xF6, 0xD2, 0xAF, 0x02, 0x42, 0x4D, 0x7F,
+ 0x08, 0x08, 0xEF, 0x44, 0x83, 0xF4, 0xC2, 0xAF,
+ 0x56, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x4F, 0xFF,
+ 0x22, 0xC5, 0xF0, 0xF8, 0xA3, 0xE0, 0x28, 0xF0,
+ 0xC5, 0xF0, 0xF8, 0xE5, 0x82, 0x15, 0x82, 0x70,
+ 0x02, 0x15, 0x83, 0xE0, 0x38, 0xF0, 0x22, 0xEF,
+ 0x5B, 0xFF, 0xEE, 0x5A, 0xFE, 0xED, 0x59, 0xFD,
+ 0xEC, 0x58, 0xFC, 0x22, 0xEF, 0x4B, 0xFF, 0xEE,
+ 0x4A, 0xFE, 0xED, 0x49, 0xFD, 0xEC, 0x48, 0xFC,
+ 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xA3, 0xE0,
+ 0xFE, 0xA3, 0xE0, 0xFF, 0x22, 0xE2, 0xFC, 0x08,
+ 0xE2, 0xFD, 0x08, 0xE2, 0xFE, 0x08, 0xE2, 0xFF,
+ 0x22, 0xE2, 0xFB, 0x08, 0xE2, 0xF9, 0x08, 0xE2,
+ 0xFA, 0x08, 0xE2, 0xCB, 0xF8, 0x22, 0xEC, 0xF2,
+ 0x08, 0xED, 0xF2, 0x08, 0xEE, 0xF2, 0x08, 0xEF,
+ 0xF2, 0x22, 0xA4, 0x25, 0x82, 0xF5, 0x82, 0xE5,
+ 0xF0, 0x35, 0x83, 0xF5, 0x83, 0x22, 0xE0, 0xFB,
+ 0xA3, 0xE0, 0xFA, 0xA3, 0xE0, 0xF9, 0x22, 0xEB,
+ 0xF0, 0xA3, 0xEA, 0xF0, 0xA3, 0xE9, 0xF0, 0x22,
+ 0xD0, 0x83, 0xD0, 0x82, 0xF8, 0xE4, 0x93, 0x70,
+ 0x12, 0x74, 0x01, 0x93, 0x70, 0x0D, 0xA3, 0xA3,
+ 0x93, 0xF8, 0x74, 0x01, 0x93, 0xF5, 0x82, 0x88,
+ 0x83, 0xE4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60,
+ 0xEF, 0xA3, 0xA3, 0xA3, 0x80, 0xDF, 0x02, 0x45,
+ 0x8C, 0x02, 0x42, 0xDD, 0xE4, 0x93, 0xA3, 0xF8,
+ 0xE4, 0x93, 0xA3, 0x40, 0x03, 0xF6, 0x80, 0x01,
+ 0xF2, 0x08, 0xDF, 0xF4, 0x80, 0x29, 0xE4, 0x93,
+ 0xA3, 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3,
+ 0x33, 0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83,
+ 0x40, 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6,
+ 0xDF, 0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08,
+ 0x10, 0x20, 0x40, 0x80, 0x90, 0x45, 0xD1, 0xE4,
+ 0x7E, 0x01, 0x93, 0x60, 0xBC, 0xA3, 0xFF, 0x54,
+ 0x3F, 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4,
+ 0x93, 0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0,
+ 0x25, 0xE0, 0x60, 0xA8, 0x40, 0xB8, 0xE4, 0x93,
+ 0xA3, 0xFA, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93,
+ 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83,
+ 0xCA, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA,
+ 0xC5, 0x83, 0xCA, 0xDF, 0xE9, 0xDE, 0xE7, 0x80,
+ 0xBE, 0x00, 0x41, 0x82, 0x09, 0x00, 0x41, 0x82,
+ 0x0A, 0x00, 0x41, 0x82, 0x17, 0x00, 0x59, 0xE2,
+ 0x5C, 0x24, 0x5E, 0x5D, 0x5F, 0xA1, 0xC0, 0xE0,
+ 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0,
+ 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0,
+ 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0,
+ 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xE6,
+ 0xF0, 0x74, 0x45, 0xA3, 0xF0, 0xD1, 0x35, 0x74,
+ 0xE6, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x45,
+ 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05,
+ 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01,
+ 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83,
+ 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x00, 0x54,
+ 0xE0, 0x55, 0x35, 0xF5, 0x39, 0xA3, 0xE0, 0x55,
+ 0x36, 0xF5, 0x3A, 0xA3, 0xE0, 0x55, 0x37, 0xF5,
+ 0x3B, 0xA3, 0xE0, 0x55, 0x38, 0xF5, 0x3C, 0xAD,
+ 0x39, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0xAD, 0x3A,
+ 0x7F, 0x55, 0x12, 0x32, 0x1E, 0xAD, 0x3B, 0x7F,
+ 0x56, 0x12, 0x32, 0x1E, 0xAD, 0x3C, 0x7F, 0x57,
+ 0x12, 0x32, 0x1E, 0x53, 0x91, 0xEF, 0x22, 0xC0,
+ 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0,
+ 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01,
+ 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05,
+ 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74,
+ 0x6F, 0xF0, 0x74, 0x46, 0xA3, 0xF0, 0x12, 0x6C,
+ 0x78, 0xE5, 0x41, 0x30, 0xE4, 0x04, 0x7F, 0x02,
+ 0x91, 0x27, 0xE5, 0x41, 0x30, 0xE6, 0x03, 0x12,
+ 0x6C, 0xD5, 0xE5, 0x43, 0x30, 0xE0, 0x03, 0x12,
+ 0x51, 0xC2, 0xE5, 0x43, 0x30, 0xE1, 0x03, 0x12,
+ 0x4D, 0x0C, 0xE5, 0x43, 0x30, 0xE2, 0x03, 0x12,
+ 0x4C, 0xC1, 0xE5, 0x43, 0x30, 0xE3, 0x03, 0x12,
+ 0x6C, 0xE2, 0xE5, 0x43, 0x30, 0xE4, 0x03, 0x12,
+ 0x6D, 0x04, 0xE5, 0x43, 0x30, 0xE5, 0x03, 0x12,
+ 0x6D, 0x33, 0xE5, 0x43, 0x30, 0xE6, 0x02, 0xF1,
+ 0x0F, 0xE5, 0x44, 0x30, 0xE1, 0x03, 0x12, 0x51,
+ 0x7F, 0x74, 0x6F, 0x04, 0x90, 0x01, 0xC4, 0xF0,
+ 0x74, 0x46, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06,
+ 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02,
+ 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82,
+ 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90,
+ 0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x13, 0x90, 0x81,
+ 0x27, 0xE0, 0x60, 0x0D, 0x90, 0x81, 0x2B, 0xE0,
+ 0x54, 0xFE, 0xF0, 0x54, 0x07, 0x70, 0x02, 0xF1,
+ 0x2A, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x90, 0x81,
+ 0x29, 0x30, 0xE0, 0x05, 0xE0, 0xFF, 0x02, 0x74,
+ 0x8F, 0xE0, 0xFF, 0x7D, 0x01, 0xD3, 0x10, 0xAF,
+ 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0x13, 0xED,
+ 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x90, 0x82, 0x14,
+ 0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFE, 0xC4, 0x13,
+ 0x13, 0x54, 0x03, 0x30, 0xE0, 0x03, 0x02, 0x48,
+ 0xA0, 0xEE, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01,
+ 0x30, 0xE0, 0x03, 0x02, 0x48, 0xA0, 0x90, 0x82,
+ 0x14, 0xE0, 0xFE, 0x6F, 0x70, 0x03, 0x02, 0x48,
+ 0xA0, 0xEF, 0x70, 0x03, 0x02, 0x48, 0x17, 0x24,
+ 0xFE, 0x70, 0x03, 0x02, 0x48, 0x50, 0x24, 0xFE,
+ 0x60, 0x51, 0x24, 0xFC, 0x70, 0x03, 0x02, 0x48,
+ 0x8B, 0x24, 0xFC, 0x60, 0x03, 0x02, 0x48, 0xA0,
+ 0xEE, 0xB4, 0x0E, 0x03, 0x12, 0x49, 0x5E, 0x90,
+ 0x82, 0x14, 0xE0, 0x70, 0x05, 0x7F, 0x01, 0x12,
+ 0x49, 0x93, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x06,
+ 0x03, 0x12, 0x49, 0x34, 0x90, 0x82, 0x14, 0xE0,
+ 0xB4, 0x04, 0x0F, 0x90, 0x82, 0x13, 0xE0, 0xFF,
+ 0x60, 0x05, 0x12, 0x73, 0x75, 0x80, 0x03, 0x12,
+ 0x66, 0x26, 0x90, 0x82, 0x14, 0xE0, 0x64, 0x08,
+ 0x60, 0x03, 0x02, 0x48, 0xA0, 0x12, 0x73, 0xD3,
+ 0x02, 0x48, 0xA0, 0x90, 0x82, 0x14, 0xE0, 0x70,
+ 0x05, 0x7F, 0x01, 0x12, 0x49, 0x93, 0x90, 0x82,
+ 0x14, 0xE0, 0xB4, 0x06, 0x03, 0x12, 0x49, 0x34,
+ 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x09, 0x12,
+ 0x48, 0xA5, 0xBF, 0x01, 0x03, 0x12, 0x49, 0x5E,
+ 0x90, 0x82, 0x14, 0xE0, 0x64, 0x0C, 0x60, 0x02,
+ 0x01, 0xA0, 0x11, 0xA5, 0xEF, 0x64, 0x01, 0x60,
+ 0x02, 0x01, 0xA0, 0x11, 0xFA, 0x01, 0xA0, 0x90,
+ 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x07, 0x11, 0xA5,
+ 0xBF, 0x01, 0x02, 0x31, 0x5E, 0x90, 0x82, 0x14,
+ 0xE0, 0xB4, 0x06, 0x02, 0x31, 0x34, 0x90, 0x82,
+ 0x14, 0xE0, 0xB4, 0x0C, 0x07, 0x11, 0xA5, 0xBF,
+ 0x01, 0x02, 0x11, 0xFA, 0x90, 0x82, 0x14, 0xE0,
+ 0x64, 0x04, 0x70, 0x5C, 0x12, 0x72, 0xF5, 0xEF,
+ 0x64, 0x01, 0x70, 0x54, 0x31, 0xBE, 0x80, 0x50,
+ 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x07, 0x11,
+ 0xA5, 0xBF, 0x01, 0x02, 0x31, 0x5E, 0x90, 0x82,
+ 0x14, 0xE0, 0xB4, 0x06, 0x02, 0x31, 0x34, 0x90,
+ 0x82, 0x14, 0xE0, 0xB4, 0x0C, 0x07, 0x11, 0xA5,
+ 0xBF, 0x01, 0x02, 0x11, 0xFA, 0x90, 0x82, 0x14,
+ 0xE0, 0x70, 0x04, 0x7F, 0x01, 0x31, 0x93, 0x90,
+ 0x82, 0x14, 0xE0, 0xB4, 0x04, 0x1A, 0x12, 0x73,
+ 0xBB, 0x80, 0x15, 0x90, 0x82, 0x14, 0xE0, 0xB4,
+ 0x0C, 0x0E, 0x90, 0x81, 0x25, 0xE0, 0xFF, 0x13,
+ 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x02, 0x31, 0xB1,
+ 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD1, 0xAB, 0xEF,
+ 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74,
+ 0x01, 0xF0, 0x80, 0x3D, 0x90, 0x81, 0x24, 0xE0,
+ 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0,
+ 0x08, 0x90, 0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80,
+ 0x28, 0xEF, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x08,
+ 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x19,
+ 0x90, 0x81, 0x29, 0xE0, 0xD3, 0x94, 0x04, 0x40,
+ 0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80,
+ 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01,
+ 0x22, 0x90, 0x01, 0xB9, 0x74, 0x02, 0xF0, 0x7F,
+ 0x00, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01,
+ 0x70, 0x31, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFD,
+ 0xF0, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x7F,
+ 0x01, 0xF1, 0x0D, 0xBF, 0x01, 0x12, 0x90, 0x81,
+ 0x24, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x2A,
+ 0x74, 0x0E, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22,
+ 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01,
+ 0xB8, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x25, 0xE0,
+ 0x90, 0x06, 0x04, 0x20, 0xE0, 0x0C, 0xE0, 0x44,
+ 0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0,
+ 0x80, 0x0E, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x81,
+ 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0,
+ 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, 0x81,
+ 0x25, 0xE0, 0xC3, 0x13, 0x20, 0xE0, 0x08, 0x90,
+ 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x80, 0x1E, 0x90,
+ 0x06, 0x04, 0xE0, 0x44, 0x40, 0xF0, 0xE0, 0x44,
+ 0x80, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0,
+ 0x90, 0x05, 0x27, 0xE0, 0x44, 0x80, 0xF0, 0x90,
+ 0x81, 0x23, 0x74, 0x04, 0xF0, 0x90, 0x05, 0x22,
+ 0xE4, 0xF0, 0x22, 0x90, 0x82, 0x15, 0xEF, 0xF0,
+ 0x12, 0x54, 0x65, 0x90, 0x82, 0x15, 0xE0, 0x60,
+ 0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81,
+ 0x2A, 0x74, 0x04, 0xF0, 0x90, 0x81, 0x23, 0xF0,
+ 0x22, 0x31, 0xE3, 0x90, 0x81, 0x2A, 0x74, 0x08,
+ 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x05,
+ 0x22, 0x74, 0xFF, 0xF0, 0xF1, 0x3A, 0x90, 0x01,
+ 0x37, 0x74, 0x02, 0xF0, 0xFD, 0x7F, 0x03, 0x51,
+ 0x57, 0x31, 0xE3, 0xE4, 0x90, 0x81, 0x2A, 0xF0,
+ 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x05, 0x22,
+ 0x74, 0xFF, 0xF0, 0xF1, 0x3A, 0x90, 0x85, 0xBB,
+ 0x12, 0x20, 0xDA, 0xCC, 0xF0, 0x00, 0xC0, 0x7F,
+ 0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85,
+ 0xBB, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x14,
+ 0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, 0x90,
+ 0x81, 0xF9, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00,
+ 0x00, 0xE4, 0xFD, 0xFF, 0x12, 0x55, 0x1C, 0x7F,
+ 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x44,
+ 0x80, 0xFC, 0x90, 0x82, 0x05, 0x12, 0x20, 0xCE,
+ 0x90, 0x82, 0x05, 0x12, 0x44, 0xD9, 0x90, 0x85,
+ 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08,
+ 0x12, 0x2E, 0xA2, 0x90, 0x01, 0x00, 0x74, 0x3F,
+ 0xF0, 0xA3, 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x05,
+ 0x53, 0xE0, 0x44, 0x20, 0xF0, 0x22, 0x90, 0x01,
+ 0x34, 0x74, 0x40, 0xF0, 0xFD, 0xE4, 0xFF, 0x74,
+ 0x3D, 0x2F, 0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74,
+ 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5,
+ 0x83, 0xEE, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01,
+ 0xC3, 0xC0, 0xD0, 0xE4, 0x90, 0x81, 0xCB, 0xF0,
+ 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90,
+ 0x81, 0x1F, 0xE0, 0x54, 0xFE, 0x4E, 0xFE, 0xF0,
+ 0xEF, 0x54, 0x02, 0xFF, 0xEE, 0x54, 0xFD, 0x4F,
+ 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x04,
+ 0xFD, 0xEF, 0x54, 0xFB, 0x4D, 0xFF, 0x90, 0x81,
+ 0x1F, 0xF0, 0xEE, 0x54, 0x08, 0xFE, 0xEF, 0x54,
+ 0xF7, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE,
+ 0x54, 0x10, 0xFD, 0xEF, 0x54, 0xEF, 0x4D, 0xFF,
+ 0x90, 0x81, 0x1F, 0xF0, 0xEE, 0x54, 0x20, 0xFE,
+ 0xEF, 0x54, 0xDF, 0x4E, 0xF0, 0x12, 0x1F, 0xA4,
+ 0xC3, 0x13, 0x20, 0xE0, 0x02, 0x61, 0x5E, 0x90,
+ 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x6D, 0x90,
+ 0x81, 0xCB, 0x74, 0x21, 0xF0, 0xEF, 0x13, 0x13,
+ 0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x51, 0x4E, 0x90,
+ 0x81, 0xCB, 0xE0, 0x44, 0x08, 0xF0, 0x80, 0x0C,
+ 0xE4, 0x90, 0x81, 0x20, 0xF0, 0xA3, 0xF0, 0x7D,
+ 0x40, 0xFF, 0x91, 0x26, 0x90, 0x81, 0x1F, 0xE0,
+ 0xFD, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0,
+ 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x12, 0xF0,
+ 0xED, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x07, 0x90,
+ 0x81, 0xCB, 0xE0, 0x44, 0x14, 0xF0, 0x90, 0x81,
+ 0x1F, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0x30, 0xE0,
+ 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x80, 0xF0,
+ 0x90, 0x81, 0xCB, 0xE0, 0x90, 0x05, 0x27, 0xF0,
+ 0x90, 0x81, 0x22, 0xE0, 0x60, 0x02, 0x81, 0x17,
+ 0x7F, 0x01, 0x80, 0x15, 0x90, 0x81, 0xCB, 0x74,
+ 0x01, 0xF0, 0x90, 0x05, 0x27, 0xF0, 0x90, 0x81,
+ 0x22, 0xE0, 0x64, 0x04, 0x60, 0x02, 0x81, 0x17,
+ 0xFF, 0x12, 0x53, 0x0E, 0x81, 0x17, 0x90, 0x81,
+ 0x1F, 0xE0, 0xFF, 0x20, 0xE0, 0x02, 0x61, 0xE7,
+ 0x90, 0x81, 0xCB, 0x74, 0x31, 0xF0, 0xEF, 0x13,
+ 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x51, 0x4E,
+ 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x08, 0xF0, 0x80,
+ 0x06, 0x7D, 0x40, 0xE4, 0xFF, 0x91, 0x26, 0x90,
+ 0x81, 0x1F, 0xE0, 0xFD, 0x13, 0x13, 0x13, 0x54,
+ 0x1F, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0,
+ 0x44, 0x02, 0xF0, 0xED, 0xC4, 0x54, 0x0F, 0x30,
+ 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x04,
+ 0xF0, 0x90, 0x81, 0xCB, 0xE0, 0x90, 0x05, 0x27,
+ 0xF0, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x70,
+ 0x1D, 0xFD, 0x7F, 0x04, 0x12, 0x47, 0x3D, 0x12,
+ 0x51, 0x73, 0xBF, 0x01, 0x09, 0x90, 0x81, 0x29,
+ 0xE0, 0xFF, 0x7D, 0x01, 0x80, 0x03, 0xE4, 0xFD,
+ 0xFF, 0x12, 0x47, 0x3D, 0x80, 0x41, 0x90, 0x81,
+ 0x2A, 0xE0, 0x90, 0x81, 0x23, 0xF0, 0x90, 0x05,
+ 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x80, 0x30, 0x90,
+ 0x81, 0xCB, 0x74, 0x01, 0xF0, 0x90, 0x05, 0x27,
+ 0xF0, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x06,
+ 0x7D, 0x01, 0x7F, 0x04, 0x80, 0x0B, 0x90, 0x81,
+ 0x23, 0xE0, 0xB4, 0x08, 0x07, 0x7D, 0x01, 0x7F,
+ 0x0C, 0x12, 0x47, 0x3D, 0xD1, 0x34, 0x90, 0x81,
+ 0x29, 0x12, 0x47, 0x39, 0x12, 0x5A, 0xA7, 0xD0,
+ 0xD0, 0x92, 0xAF, 0x22, 0x7D, 0x02, 0x7F, 0x02,
+ 0x91, 0x26, 0x7D, 0x01, 0x7F, 0x02, 0x74, 0x3D,
+ 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE,
+ 0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34,
+ 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xEF, 0x70,
+ 0x37, 0x7D, 0x78, 0x7F, 0x02, 0x91, 0x26, 0x7D,
+ 0x02, 0x7F, 0x03, 0x91, 0x26, 0x7D, 0xC8, 0x7F,
+ 0x02, 0x12, 0x71, 0x8F, 0x90, 0x01, 0x57, 0xE4,
+ 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x7D,
+ 0x01, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0x90, 0x81,
+ 0x24, 0xE0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0,
+ 0x90, 0x06, 0x0A, 0xE0, 0x54, 0xF8, 0xF0, 0x22,
+ 0x90, 0x01, 0x36, 0x74, 0x78, 0xF0, 0xA3, 0x74,
+ 0x02, 0xF0, 0x7D, 0x78, 0xFF, 0x51, 0x57, 0x7D,
+ 0x02, 0x7F, 0x03, 0x51, 0x57, 0x90, 0x06, 0x0A,
+ 0xE0, 0x44, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xA3,
+ 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x80, 0xDE,
+ 0xE0, 0xB4, 0x01, 0x15, 0x90, 0x81, 0x25, 0xE0,
+ 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20,
+ 0xE2, 0x0E, 0x7D, 0x01, 0x7F, 0x04, 0x02, 0x47,
+ 0x3D, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x04, 0xF0,
+ 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0,
+ 0x08, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x60,
+ 0x3A, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x04, 0xEF,
+ 0x30, 0xE0, 0x0A, 0x90, 0x81, 0x2A, 0xE0, 0x64,
+ 0x02, 0x60, 0x28, 0xB1, 0x83, 0x90, 0x81, 0x25,
+ 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0,
+ 0x14, 0x90, 0x81, 0x2D, 0xE0, 0xFF, 0xA3, 0xE0,
+ 0x6F, 0x70, 0x0A, 0xF1, 0xCD, 0x91, 0x1C, 0x90,
+ 0x81, 0x2E, 0xE0, 0x14, 0xF0, 0x90, 0x01, 0xE6,
+ 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x1F, 0xE0,
+ 0x30, 0xE0, 0x06, 0x90, 0x81, 0x21, 0x74, 0x01,
+ 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x45, 0x90,
+ 0x81, 0x25, 0xE0, 0xFF, 0x13, 0x13, 0x13, 0x54,
+ 0x1F, 0x30, 0xE0, 0x12, 0x90, 0x01, 0x3B, 0xE0,
+ 0x30, 0xE4, 0x0B, 0x91, 0x1C, 0x90, 0x81, 0x2D,
+ 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x90, 0x82,
+ 0x0B, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9,
+ 0xC3, 0x90, 0x82, 0x0C, 0xE0, 0x94, 0x80, 0x90,
+ 0x82, 0x0B, 0xE0, 0x64, 0x80, 0x94, 0x80, 0x40,
+ 0x0B, 0x90, 0x01, 0x98, 0xE0, 0x54, 0xFE, 0xF0,
+ 0xE0, 0x44, 0x01, 0xF0, 0x12, 0x75, 0xF8, 0xD1,
+ 0xD6, 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x0C,
+ 0xE4, 0xF5, 0x1D, 0xA3, 0xF1, 0xFB, 0x90, 0x01,
+ 0x57, 0x74, 0x05, 0xF0, 0x90, 0x01, 0xBE, 0xE0,
+ 0x04, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64,
+ 0x01, 0x60, 0x02, 0xC1, 0x23, 0x90, 0x81, 0x27,
+ 0xE0, 0x70, 0x02, 0xC1, 0x23, 0x90, 0x81, 0x26,
+ 0xE0, 0xC4, 0x54, 0x0F, 0x64, 0x01, 0x70, 0x22,
+ 0x90, 0x06, 0xAB, 0xE0, 0x90, 0x81, 0x2E, 0xF0,
+ 0x90, 0x06, 0xAA, 0xE0, 0x90, 0x81, 0x2D, 0xF0,
+ 0xA3, 0xE0, 0xFF, 0x70, 0x08, 0x90, 0x81, 0x2D,
+ 0xE0, 0xFE, 0xFF, 0x80, 0x00, 0x90, 0x81, 0x2E,
+ 0xEF, 0xF0, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x04,
+ 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81,
+ 0x32, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90,
+ 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74,
+ 0x02, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD,
+ 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x26, 0xE0,
+ 0xFF, 0xC4, 0x54, 0x0F, 0x24, 0xFD, 0x50, 0x02,
+ 0x80, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0,
+ 0x05, 0x12, 0x6D, 0xF2, 0x80, 0x03, 0x12, 0x6E,
+ 0xC9, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, 0x13,
+ 0x54, 0x1F, 0x30, 0xE0, 0x0E, 0x90, 0x81, 0x2D,
+ 0xE0, 0xFF, 0xA3, 0xE0, 0xB5, 0x07, 0x04, 0xF1,
+ 0xCD, 0x91, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xC3,
+ 0x13, 0x20, 0xE0, 0x07, 0x90, 0x81, 0x25, 0xE0,
+ 0x44, 0x04, 0xF0, 0x22, 0xD1, 0xAB, 0xEF, 0x70,
+ 0x02, 0xD1, 0x3C, 0x22, 0x90, 0x81, 0x27, 0xE0,
+ 0x64, 0x01, 0x70, 0x66, 0x90, 0x81, 0x26, 0xE0,
+ 0x54, 0x0F, 0x60, 0x51, 0x90, 0x81, 0x2A, 0xE0,
+ 0x70, 0x03, 0xFF, 0x31, 0x93, 0x90, 0x81, 0x2A,
+ 0xE0, 0x64, 0x0C, 0x60, 0x03, 0x12, 0x66, 0x26,
+ 0x90, 0x01, 0x5B, 0xE4, 0xF0, 0x90, 0x01, 0x3C,
+ 0x74, 0x04, 0xF0, 0xD1, 0xAB, 0xEF, 0x64, 0x01,
+ 0x60, 0x38, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A,
+ 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4,
+ 0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x12, 0x50,
+ 0x05, 0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90,
+ 0x06, 0x92, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x24,
+ 0xE0, 0x44, 0x08, 0xF0, 0x22, 0x90, 0x81, 0x2A,
+ 0xE0, 0x70, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12,
+ 0x47, 0x3D, 0x22, 0x90, 0x04, 0x1A, 0xE0, 0xF4,
+ 0x60, 0x03, 0x7F, 0x00, 0x22, 0x90, 0x04, 0x1B,
+ 0xE0, 0x54, 0x07, 0x64, 0x07, 0x7F, 0x01, 0x60,
+ 0x02, 0x7F, 0x00, 0x22, 0x12, 0x50, 0x60, 0x90,
+ 0x81, 0x2D, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0,
+ 0x7D, 0x02, 0x7F, 0x02, 0x51, 0x57, 0x90, 0x81,
+ 0x42, 0xE0, 0x30, 0xE0, 0x2D, 0x90, 0x80, 0xDE,
+ 0xE0, 0xB4, 0x01, 0x26, 0x90, 0x82, 0x17, 0xE0,
+ 0x04, 0xF0, 0xE0, 0xB4, 0x0A, 0x0B, 0x90, 0x81,
+ 0x44, 0xE0, 0x04, 0xF0, 0xE4, 0x90, 0x82, 0x17,
+ 0xF0, 0x90, 0x81, 0x44, 0xE0, 0xFF, 0x90, 0x81,
+ 0x43, 0xE0, 0xB5, 0x07, 0x05, 0xE4, 0xA3, 0xF0,
+ 0xF1, 0x0B, 0x22, 0xE4, 0xFF, 0x8F, 0x53, 0x90,
+ 0x04, 0x1D, 0xE0, 0x60, 0x19, 0x90, 0x05, 0x22,
+ 0xE0, 0xF5, 0x56, 0x74, 0xFF, 0xF0, 0xF1, 0x3A,
+ 0xBF, 0x01, 0x03, 0x12, 0x74, 0xFB, 0x90, 0x05,
+ 0x22, 0xE5, 0x56, 0xF0, 0x80, 0x03, 0x12, 0x74,
+ 0xFB, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x7F,
+ 0x01, 0x22, 0xE4, 0x90, 0x82, 0x0F, 0xF0, 0xA3,
+ 0xF0, 0x90, 0x05, 0xF8, 0xE0, 0x70, 0x0F, 0xA3,
+ 0xE0, 0x70, 0x0B, 0xA3, 0xE0, 0x70, 0x07, 0xA3,
+ 0xE0, 0x70, 0x03, 0x7F, 0x01, 0x22, 0xD3, 0x90,
+ 0x82, 0x10, 0xE0, 0x94, 0xE8, 0x90, 0x82, 0x0F,
+ 0xE0, 0x94, 0x03, 0x40, 0x0A, 0x90, 0x01, 0xC0,
+ 0xE0, 0x44, 0x20, 0xF0, 0x7F, 0x00, 0x22, 0x7F,
+ 0x32, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x82,
+ 0x0F, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9,
+ 0x80, 0xBF, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4,
+ 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0x3F, 0xF0,
+ 0xEF, 0x60, 0x1D, 0x74, 0x21, 0x2D, 0xF5, 0x82,
+ 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x10,
+ 0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34,
+ 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x22,
+ 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC,
+ 0xF5, 0x83, 0xE0, 0x54, 0xEF, 0xF0, 0x74, 0x1F,
+ 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83,
+ 0xE0, 0x44, 0x40, 0xF0, 0x22, 0xEF, 0x14, 0x90,
+ 0x05, 0x73, 0xF0, 0x90, 0x01, 0x3F, 0x74, 0x10,
+ 0xF0, 0xFD, 0x7F, 0x03, 0x74, 0x45, 0x2F, 0xF8,
+ 0xE6, 0x4D, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5,
+ 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0,
+ 0x22, 0xE0, 0x44, 0x02, 0xF0, 0xE4, 0xF5, 0x1D,
+ 0x90, 0x81, 0x39, 0xE0, 0xF5, 0x1E, 0xE4, 0xFB,
+ 0xFD, 0x7F, 0x54, 0x7E, 0x01, 0x8E, 0x19, 0x8F,
+ 0x1A, 0xE5, 0x1E, 0x54, 0x07, 0xC4, 0x33, 0x54,
+ 0xE0, 0x85, 0x19, 0x83, 0x85, 0x1A, 0x82, 0xF0,
+ 0xE5, 0x1D, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0,
+ 0xFF, 0xE5, 0x1E, 0x13, 0x13, 0x13, 0x54, 0x1F,
+ 0x4F, 0xA3, 0xF0, 0xEB, 0x54, 0x07, 0xC4, 0x33,
+ 0x54, 0xE0, 0xFF, 0xE5, 0x1D, 0x13, 0x13, 0x13,
+ 0x54, 0x1F, 0x4F, 0x85, 0x1A, 0x82, 0x85, 0x19,
+ 0x83, 0xA3, 0xA3, 0xF0, 0xBD, 0x01, 0x0C, 0x85,
+ 0x1A, 0x82, 0x8E, 0x83, 0xA3, 0xA3, 0xA3, 0x74,
+ 0x03, 0xF0, 0x22, 0x85, 0x1A, 0x82, 0x85, 0x19,
+ 0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x01, 0xF0, 0x22,
+ 0xE4, 0x90, 0x81, 0x4D, 0xF0, 0x90, 0x81, 0x27,
+ 0xE0, 0x60, 0x58, 0x90, 0x80, 0xDE, 0xE0, 0x64,
+ 0x01, 0x70, 0x50, 0x90, 0x81, 0x4D, 0x04, 0xF0,
+ 0xE4, 0x90, 0x81, 0x2E, 0xF0, 0x90, 0x81, 0x1F,
+ 0xE0, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x23, 0xE0,
+ 0xB4, 0x02, 0x05, 0xE4, 0x90, 0x81, 0x4D, 0xF0,
+ 0x31, 0x73, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x4D,
+ 0xF0, 0x90, 0x81, 0x4D, 0xE0, 0x60, 0x24, 0x90,
+ 0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0xE4, 0xF5,
+ 0x1D, 0x90, 0x81, 0x2F, 0x12, 0x4F, 0xFB, 0x90,
+ 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A,
+ 0xE0, 0x20, 0xE2, 0x07, 0x7D, 0x01, 0x7F, 0x04,
+ 0x12, 0x47, 0x3D, 0x22, 0xE4, 0x90, 0x81, 0x4C,
+ 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x02, 0x21,
+ 0x72, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x60,
+ 0x02, 0x21, 0x72, 0x90, 0x81, 0x26, 0xE0, 0xFF,
+ 0xC4, 0x54, 0x0F, 0x60, 0x22, 0x24, 0xFE, 0x60,
+ 0x03, 0x04, 0x70, 0x21, 0x90, 0x81, 0x2E, 0xE0,
+ 0x14, 0xF0, 0xE0, 0xFF, 0x60, 0x06, 0x90, 0x81,
+ 0x30, 0xE0, 0x60, 0x11, 0xEF, 0x70, 0x08, 0x90,
+ 0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x80, 0x00, 0x90,
+ 0x81, 0x4C, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x1F,
+ 0xE0, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x23, 0xE0,
+ 0xB4, 0x02, 0x05, 0xE4, 0x90, 0x81, 0x4C, 0xF0,
+ 0x31, 0x73, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x4C,
+ 0xF0, 0x90, 0x81, 0x4C, 0xE0, 0x60, 0x43, 0x90,
+ 0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81,
+ 0x30, 0xE0, 0x60, 0x03, 0xB4, 0x01, 0x09, 0xE4,
+ 0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x80, 0x0D,
+ 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x75,
+ 0xF0, 0x03, 0xA4, 0x24, 0xFE, 0xFF, 0x90, 0x81,
+ 0x2F, 0xE0, 0x2F, 0x12, 0x4F, 0xFC, 0x90, 0x01,
+ 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A, 0xE0,
+ 0x20, 0xE2, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12,
+ 0x47, 0x3D, 0x22, 0x90, 0x05, 0x43, 0xE0, 0x7F,
+ 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0x22, 0x90,
+ 0x81, 0x27, 0xE0, 0x70, 0x07, 0x90, 0x81, 0x1F,
+ 0xE0, 0x30, 0xE0, 0x11, 0x90, 0x81, 0x1F, 0xE0,
+ 0x30, 0xE0, 0x07, 0x31, 0x73, 0xBF, 0x01, 0x05,
+ 0x41, 0x5B, 0x12, 0x4E, 0x3C, 0x22, 0xD3, 0x10,
+ 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x1E,
+ 0xE0, 0xB4, 0x01, 0x04, 0x7F, 0x04, 0x80, 0x0B,
+ 0x31, 0x73, 0xBF, 0x01, 0x04, 0x7F, 0x01, 0x80,
+ 0x02, 0x7F, 0x02, 0x71, 0x0E, 0xD0, 0xD0, 0x92,
+ 0xAF, 0x22, 0x90, 0x81, 0x4B, 0xE0, 0x60, 0x0F,
+ 0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x02,
+ 0xF0, 0x90, 0x05, 0xFC, 0xE0, 0x04, 0xF0, 0x90,
+ 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x10, 0xA3, 0x74,
+ 0x01, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0xC3,
+ 0x13, 0x30, 0xE0, 0x02, 0x31, 0x9E, 0x11, 0xC4,
+ 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x07, 0x91,
+ 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90,
+ 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3D, 0x90,
+ 0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02, 0x02,
+ 0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D, 0x00,
+ 0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E, 0x70,
+ 0x23, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02, 0x21,
+ 0x9E, 0x51, 0x45, 0x90, 0x81, 0x23, 0xE0, 0xB4,
+ 0x08, 0x06, 0xE4, 0xFD, 0x7F, 0x0C, 0x80, 0x09,
+ 0x90, 0x81, 0x23, 0xE0, 0x70, 0x06, 0xFD, 0x7F,
+ 0x04, 0x12, 0x47, 0x3D, 0x22, 0x90, 0x81, 0x1E,
+ 0xE0, 0xB4, 0x01, 0x0F, 0x90, 0x81, 0x23, 0xE0,
+ 0x64, 0x02, 0x60, 0x07, 0x7D, 0x01, 0x7F, 0x02,
+ 0x12, 0x47, 0x3D, 0x90, 0x81, 0x27, 0xE0, 0x64,
+ 0x02, 0x60, 0x14, 0x90, 0x81, 0x26, 0xE0, 0x54,
+ 0x0F, 0x60, 0x0C, 0x12, 0x4E, 0xAB, 0xEF, 0x70,
+ 0x06, 0xFD, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0x22,
+ 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3F,
+ 0x90, 0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02,
+ 0x02, 0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D,
+ 0x00, 0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E,
+ 0x70, 0x25, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02,
+ 0x21, 0x9E, 0x12, 0x74, 0xAC, 0x90, 0x81, 0x23,
+ 0xE0, 0xB4, 0x0C, 0x06, 0xE4, 0xFD, 0x7F, 0x08,
+ 0x80, 0x0A, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x04,
+ 0x06, 0xE4, 0xFD, 0xFF, 0x12, 0x47, 0x3D, 0x22,
+ 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90,
+ 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x12, 0x1F, 0xA4,
+ 0xFF, 0x90, 0x81, 0x1E, 0xF0, 0xBF, 0x01, 0x12,
+ 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x90, 0x00,
+ 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, 0x60, 0x21,
+ 0x80, 0x1D, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16,
+ 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01,
+ 0x60, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x20, 0xE0,
+ 0x06, 0xE4, 0xFF, 0x71, 0x0E, 0x80, 0x02, 0x31,
+ 0x9E, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10,
+ 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x22,
+ 0xE0, 0x90, 0x82, 0x16, 0xF0, 0x6F, 0x70, 0x02,
+ 0x81, 0x04, 0xEF, 0x14, 0x60, 0x3E, 0x14, 0x60,
+ 0x62, 0x14, 0x70, 0x02, 0x61, 0xB8, 0x14, 0x70,
+ 0x02, 0x61, 0xDF, 0x24, 0x04, 0x60, 0x02, 0x81,
+ 0x04, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04,
+ 0x04, 0x91, 0x41, 0x81, 0x04, 0xEF, 0xB4, 0x02,
+ 0x04, 0x91, 0x50, 0x81, 0x04, 0x90, 0x82, 0x16,
+ 0xE0, 0xFF, 0xB4, 0x03, 0x04, 0x91, 0x54, 0x81,
+ 0x04, 0xEF, 0x64, 0x01, 0x60, 0x02, 0x81, 0x04,
+ 0x91, 0x43, 0x81, 0x04, 0x90, 0x82, 0x16, 0xE0,
+ 0xFF, 0xB4, 0x04, 0x04, 0x91, 0xF3, 0x81, 0x04,
+ 0xEF, 0xB4, 0x02, 0x04, 0x91, 0x58, 0x81, 0x04,
+ 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x03, 0x04,
+ 0x91, 0xE8, 0x81, 0x04, 0xEF, 0x70, 0x7D, 0x91,
+ 0x2B, 0x80, 0x79, 0x90, 0x82, 0x16, 0xE0, 0xB4,
+ 0x04, 0x05, 0x12, 0x74, 0x60, 0x80, 0x6D, 0x90,
+ 0x82, 0x16, 0xE0, 0xB4, 0x01, 0x04, 0x91, 0x21,
+ 0x80, 0x62, 0x90, 0x82, 0x16, 0xE0, 0xB4, 0x03,
+ 0x05, 0x12, 0x74, 0x71, 0x80, 0x56, 0x90, 0x82,
+ 0x16, 0xE0, 0x70, 0x50, 0x91, 0x1F, 0x80, 0x4C,
+ 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04, 0x05,
+ 0x12, 0x74, 0x4C, 0x80, 0x3F, 0xEF, 0xB4, 0x01,
+ 0x04, 0x91, 0x34, 0x80, 0x37, 0xEF, 0xB4, 0x02,
+ 0x04, 0x91, 0xDF, 0x80, 0x2F, 0x90, 0x82, 0x16,
+ 0xE0, 0x70, 0x29, 0x91, 0x32, 0x80, 0x25, 0x90,
+ 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x03, 0x05, 0x12,
+ 0x74, 0x7B, 0x80, 0x18, 0xEF, 0xB4, 0x01, 0x04,
+ 0x91, 0x0B, 0x80, 0x10, 0xEF, 0xB4, 0x02, 0x04,
+ 0xB1, 0x06, 0x80, 0x08, 0x90, 0x82, 0x16, 0xE0,
+ 0x70, 0x02, 0x91, 0x09, 0xD0, 0xD0, 0x92, 0xAF,
+ 0x22, 0x91, 0x2B, 0x90, 0x05, 0x22, 0x74, 0x6F,
+ 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0,
+ 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0x91,
+ 0x2B, 0x12, 0x49, 0xDD, 0x90, 0x81, 0x22, 0x74,
+ 0x02, 0xF0, 0x22, 0x90, 0x81, 0x22, 0x74, 0x01,
+ 0xF0, 0x22, 0x91, 0x2B, 0x90, 0x05, 0x22, 0x74,
+ 0xFF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0,
+ 0x22, 0x91, 0xF3, 0x90, 0x05, 0x27, 0xE0, 0x54,
+ 0xBF, 0xF0, 0xE4, 0x90, 0x81, 0x22, 0xF0, 0x22,
+ 0x91, 0x58, 0x80, 0xEF, 0x91, 0xE8, 0x80, 0xEB,
+ 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90,
+ 0x81, 0x22, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF,
+ 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, 0x01, 0xE0,
+ 0x44, 0x02, 0xF0, 0x90, 0x01, 0x00, 0x74, 0xFF,
+ 0xF0, 0x90, 0x06, 0xB7, 0x74, 0x09, 0xF0, 0x90,
+ 0x06, 0xB4, 0x74, 0x86, 0xF0, 0x7F, 0x7C, 0x7E,
+ 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x54, 0x7F, 0xFC,
+ 0x90, 0x82, 0x01, 0x12, 0x20, 0xCE, 0x90, 0x82,
+ 0x01, 0x12, 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12,
+ 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E,
+ 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC,
+ 0xC0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12,
+ 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA,
+ 0x00, 0xC0, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E,
+ 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xF9, 0x12, 0x20,
+ 0xDA, 0x00, 0x03, 0x3E, 0x60, 0xE4, 0xFD, 0xFF,
+ 0xB1, 0x1C, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x91,
+ 0x65, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22,
+ 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x22,
+ 0x04, 0xF0, 0x22, 0x90, 0x05, 0x22, 0xE4, 0xF0,
+ 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90,
+ 0x81, 0x22, 0x74, 0x01, 0xF0, 0x22, 0x91, 0x65,
+ 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, 0x05,
+ 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22,
+ 0x74, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01,
+ 0xC3, 0xC0, 0xD0, 0xC0, 0x07, 0xC0, 0x05, 0x90,
+ 0x81, 0xF9, 0x12, 0x44, 0xD9, 0x90, 0x81, 0xE5,
+ 0x12, 0x20, 0xCE, 0xD0, 0x05, 0xD0, 0x07, 0x12,
+ 0x60, 0xF5, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90,
+ 0x81, 0xC8, 0x12, 0x45, 0x1F, 0xEF, 0x12, 0x45,
+ 0x28, 0x55, 0x71, 0x00, 0x55, 0x7A, 0x01, 0x55,
+ 0x83, 0x02, 0x55, 0x8B, 0x03, 0x55, 0x94, 0x04,
+ 0x55, 0x9C, 0x20, 0x55, 0xA4, 0x21, 0x55, 0xAD,
+ 0x23, 0x55, 0xB5, 0x24, 0x55, 0xBE, 0x25, 0x55,
+ 0xC7, 0x26, 0x55, 0xCF, 0xC0, 0x00, 0x00, 0x55,
+ 0xD8, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02,
+ 0x6A, 0xB0, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16,
+ 0x02, 0x65, 0x81, 0x90, 0x81, 0xC8, 0x12, 0x45,
+ 0x16, 0x41, 0xC0, 0x90, 0x81, 0xC8, 0x12, 0x45,
+ 0x16, 0x02, 0x75, 0xD8, 0x90, 0x81, 0xC8, 0x12,
+ 0x45, 0x16, 0x80, 0x44, 0x90, 0x81, 0xC8, 0x12,
+ 0x45, 0x16, 0xC1, 0x4B, 0x90, 0x81, 0xC8, 0x12,
+ 0x45, 0x16, 0x02, 0x6A, 0xF8, 0x90, 0x81, 0xC8,
+ 0x12, 0x45, 0x16, 0xE1, 0xE1, 0x90, 0x81, 0xC8,
+ 0x12, 0x45, 0x16, 0x02, 0x4A, 0x6C, 0x90, 0x81,
+ 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6B, 0x3E, 0x90,
+ 0x81, 0xC8, 0x12, 0x45, 0x16, 0x80, 0x3E, 0x90,
+ 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6B, 0x4E,
+ 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x01, 0xF0, 0x22,
+ 0x12, 0x5A, 0x4B, 0x12, 0x1F, 0xA4, 0xFF, 0x54,
+ 0x01, 0xFE, 0x90, 0x81, 0x45, 0xE0, 0x54, 0xFE,
+ 0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x14,
+ 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81,
+ 0x46, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD,
+ 0x90, 0x81, 0x47, 0xF0, 0x22, 0x12, 0x1F, 0xA4,
+ 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x3F, 0xE0,
+ 0x54, 0xFE, 0x4E, 0xF0, 0x90, 0x00, 0x01, 0x12,
+ 0x1F, 0xBD, 0xFE, 0x90, 0x05, 0x54, 0xE0, 0xC3,
+ 0x9E, 0x90, 0x81, 0x40, 0xF0, 0xEF, 0x20, 0xE0,
+ 0x07, 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0,
+ 0x90, 0x81, 0x3F, 0xE0, 0x54, 0x01, 0x90, 0x01,
+ 0xBC, 0xF0, 0x90, 0x81, 0x40, 0xE0, 0x90, 0x01,
+ 0xBD, 0xF0, 0x22, 0x12, 0x1F, 0xA4, 0xFF, 0x54,
+ 0x7F, 0x90, 0x81, 0x27, 0xF0, 0xEF, 0xC4, 0x13,
+ 0x13, 0x13, 0x54, 0x01, 0xA3, 0xF0, 0x90, 0x00,
+ 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0x54, 0xF0, 0xC4,
+ 0x54, 0x0F, 0xFE, 0x90, 0x81, 0x26, 0xE0, 0x54,
+ 0xF0, 0x4E, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F,
+ 0xBD, 0x54, 0x01, 0x25, 0xE0, 0xFE, 0x90, 0x81,
+ 0x24, 0xE0, 0x54, 0xFD, 0x4E, 0xF0, 0xEF, 0x54,
+ 0x0F, 0xC4, 0x54, 0xF0, 0xFF, 0x90, 0x81, 0x26,
+ 0xE0, 0x54, 0x0F, 0x4F, 0xF0, 0x90, 0x00, 0x04,
+ 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x29, 0xF0, 0xD1,
+ 0xC6, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90,
+ 0x01, 0xB8, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x90,
+ 0x01, 0xBA, 0xF0, 0x90, 0x81, 0x29, 0xE0, 0x90,
+ 0x01, 0xBB, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54,
+ 0x0F, 0x90, 0x01, 0xBE, 0xF0, 0x22, 0x90, 0x81,
+ 0xCB, 0x12, 0x45, 0x1F, 0x12, 0x72, 0xB3, 0x90,
+ 0x81, 0x27, 0xE0, 0xFF, 0x12, 0x4C, 0x3E, 0x90,
+ 0x81, 0x27, 0xE0, 0x60, 0x19, 0x90, 0x81, 0xCB,
+ 0x12, 0x45, 0x16, 0x90, 0x00, 0x01, 0x12, 0x1F,
+ 0xBD, 0x54, 0x0F, 0xFF, 0x90, 0x00, 0x02, 0x12,
+ 0x1F, 0xBD, 0xFD, 0x12, 0x72, 0xC4, 0x22, 0xC0,
+ 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0,
+ 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01,
+ 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05,
+ 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74,
+ 0xF7, 0xF0, 0x74, 0x56, 0xA3, 0xF0, 0x12, 0x6C,
+ 0xA5, 0xE5, 0x49, 0x30, 0xE1, 0x03, 0x12, 0x6F,
+ 0x79, 0xE5, 0x49, 0x30, 0xE2, 0x02, 0xF1, 0xA5,
+ 0xE5, 0x49, 0x30, 0xE3, 0x03, 0x12, 0x6F, 0x8D,
+ 0xE5, 0x4A, 0x30, 0xE0, 0x03, 0x12, 0x6F, 0xC9,
+ 0xE5, 0x4A, 0x30, 0xE4, 0x03, 0x12, 0x70, 0x22,
+ 0xE5, 0x4B, 0x30, 0xE1, 0x02, 0x51, 0x78, 0xE5,
+ 0x4B, 0x30, 0xE0, 0x02, 0x31, 0xFF, 0xE5, 0x4B,
+ 0x30, 0xE3, 0x02, 0xF1, 0xE0, 0xE5, 0x4C, 0x30,
+ 0xE1, 0x05, 0x7F, 0x03, 0x12, 0x44, 0x27, 0xE5,
+ 0x4C, 0x30, 0xE4, 0x03, 0x12, 0x4E, 0xC4, 0xE5,
+ 0x4C, 0x30, 0xE5, 0x03, 0x12, 0x70, 0x38, 0xE5,
+ 0x4C, 0x30, 0xE6, 0x03, 0x12, 0x70, 0xCE, 0x74,
+ 0xF7, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x56,
+ 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05,
+ 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01,
+ 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83,
+ 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x81, 0x27,
+ 0xE0, 0x60, 0x34, 0x90, 0x06, 0x92, 0xE0, 0x30,
+ 0xE0, 0x23, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A,
+ 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4,
+ 0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x11, 0x05,
+ 0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90, 0x06,
+ 0x92, 0x74, 0x01, 0xF0, 0x22, 0x90, 0x81, 0x24,
+ 0xE0, 0x54, 0xF7, 0xF0, 0x12, 0x47, 0x2A, 0x22,
+ 0x22, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x31, 0xF0,
+ 0x22, 0x90, 0x01, 0xC8, 0xE4, 0xF0, 0xA3, 0xF0,
+ 0xA3, 0xF0, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x51,
+ 0x7F, 0xFF, 0xFE, 0x12, 0x2B, 0x27, 0xBF, 0x01,
+ 0x09, 0x90, 0x81, 0x51, 0xE0, 0x64, 0x03, 0x60,
+ 0x03, 0x22, 0x01, 0xAB, 0xE4, 0x90, 0x81, 0x56,
+ 0xF0, 0x90, 0x81, 0x56, 0xE0, 0xFF, 0xC3, 0x94,
+ 0x02, 0x40, 0x02, 0x01, 0xE6, 0xC3, 0x74, 0xFE,
+ 0x9F, 0xFF, 0xE4, 0x94, 0x00, 0xFE, 0x7B, 0x01,
+ 0x7A, 0x81, 0x79, 0x52, 0x12, 0x2B, 0x27, 0xEF,
+ 0x64, 0x01, 0x70, 0x77, 0x90, 0x81, 0x52, 0xE0,
+ 0xFF, 0x54, 0xC0, 0xFE, 0x60, 0x05, 0xEF, 0x54,
+ 0x0C, 0x70, 0x16, 0x90, 0x81, 0x52, 0xE0, 0xFF,
+ 0x54, 0x30, 0x60, 0x67, 0xEF, 0x54, 0x03, 0x60,
+ 0x62, 0x90, 0x81, 0x53, 0x74, 0x01, 0xF0, 0x80,
+ 0x05, 0xE4, 0x90, 0x81, 0x53, 0xF0, 0x90, 0x81,
+ 0x53, 0xE0, 0x90, 0x81, 0x52, 0x70, 0x16, 0xE0,
+ 0xFF, 0xEE, 0x13, 0x13, 0x54, 0x3F, 0x90, 0x81,
+ 0x54, 0xF0, 0xEF, 0x54, 0x0C, 0x13, 0x13, 0x54,
+ 0x3F, 0xA3, 0xF0, 0x80, 0x0D, 0xE0, 0xFE, 0x54,
+ 0x30, 0x90, 0x81, 0x54, 0xF0, 0xEE, 0x54, 0x03,
+ 0xA3, 0xF0, 0x90, 0x81, 0x54, 0xE0, 0x64, 0x30,
+ 0x70, 0x54, 0xA3, 0xE0, 0x64, 0x02, 0x70, 0x4E,
+ 0x90, 0x00, 0xF5, 0xE0, 0x54, 0x40, 0x90, 0x81,
+ 0x57, 0xF0, 0xE0, 0x70, 0x41, 0xA3, 0x74, 0x02,
+ 0xF0, 0x80, 0x10, 0x90, 0x81, 0x58, 0x74, 0x01,
+ 0xF0, 0x80, 0x08, 0x90, 0x81, 0x56, 0xE0, 0x04,
+ 0xF0, 0x01, 0x11, 0x90, 0x01, 0xC4, 0x74, 0xE9,
+ 0xF0, 0x74, 0x57, 0xA3, 0xF0, 0x90, 0x81, 0x58,
+ 0xE0, 0x90, 0x01, 0xC8, 0xF0, 0x90, 0x81, 0x52,
+ 0xE0, 0x90, 0x01, 0xC9, 0xF0, 0x90, 0x81, 0x53,
+ 0xE0, 0x90, 0x01, 0xCA, 0xF0, 0xE4, 0xFD, 0x7F,
+ 0x1F, 0x12, 0x32, 0x1E, 0x80, 0xD5, 0x22, 0x90,
+ 0x00, 0xF7, 0xE0, 0x20, 0xE7, 0x09, 0xE0, 0x7F,
+ 0x01, 0x20, 0xE6, 0x0C, 0x7F, 0x02, 0x22, 0x90,
+ 0x00, 0xF7, 0xE0, 0x30, 0xE6, 0x02, 0x7F, 0x03,
+ 0x22, 0x11, 0xE7, 0x90, 0x80, 0x3C, 0xEF, 0xF0,
+ 0x31, 0x13, 0x90, 0x01, 0x64, 0x74, 0x01, 0xF0,
+ 0x02, 0x2D, 0xA7, 0x31, 0x81, 0x31, 0xB1, 0x31,
+ 0x40, 0x31, 0x5F, 0xE4, 0xF5, 0x35, 0xF5, 0x36,
+ 0xF5, 0x37, 0xF5, 0x38, 0xAD, 0x35, 0x7F, 0x50,
+ 0x12, 0x32, 0x1E, 0xAD, 0x36, 0x7F, 0x51, 0x12,
+ 0x32, 0x1E, 0xAD, 0x37, 0x7F, 0x52, 0x12, 0x32,
+ 0x1E, 0xAD, 0x38, 0x7F, 0x53, 0x02, 0x32, 0x1E,
+ 0x75, 0x3D, 0x10, 0xE4, 0xF5, 0x3E, 0x75, 0x3F,
+ 0x07, 0x75, 0x40, 0x02, 0x90, 0x01, 0x30, 0xE5,
+ 0x3D, 0xF0, 0xA3, 0xE5, 0x3E, 0xF0, 0xA3, 0xE5,
+ 0x3F, 0xF0, 0xA3, 0xE5, 0x40, 0xF0, 0x22, 0x75,
+ 0x45, 0x0E, 0x75, 0x46, 0x01, 0x43, 0x46, 0x10,
+ 0x75, 0x47, 0x03, 0x75, 0x48, 0x62, 0x90, 0x01,
+ 0x38, 0xE5, 0x45, 0xF0, 0xA3, 0xE5, 0x46, 0xF0,
+ 0xA3, 0xE5, 0x47, 0xF0, 0xA3, 0xE5, 0x48, 0xF0,
+ 0x22, 0x90, 0x01, 0x30, 0xE4, 0xF0, 0xA3, 0xF0,
+ 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x38, 0xF0,
+ 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F,
+ 0x50, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x51,
+ 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x52, 0x12,
+ 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x53, 0x02, 0x32,
+ 0x1E, 0x90, 0x01, 0x34, 0x74, 0xFF, 0xF0, 0xA3,
+ 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x3C,
+ 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD,
+ 0x7F, 0x54, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F,
+ 0x55, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x56,
+ 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x57, 0x02,
+ 0x32, 0x1E, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x80,
+ 0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, 0x90, 0xFD,
+ 0x00, 0xE0, 0x54, 0xBF, 0xF0, 0x12, 0x57, 0xE9,
+ 0x51, 0x77, 0x12, 0x32, 0x77, 0x51, 0xC9, 0x51,
+ 0x5E, 0x7F, 0x01, 0x12, 0x43, 0x15, 0x90, 0x81,
+ 0x41, 0x74, 0x02, 0xF0, 0xFF, 0x12, 0x43, 0x15,
+ 0x90, 0x81, 0x41, 0xE0, 0x04, 0xF0, 0x7F, 0x03,
+ 0x12, 0x43, 0x15, 0x90, 0x81, 0x41, 0xE0, 0x04,
+ 0xF0, 0x31, 0x01, 0x51, 0x3F, 0x90, 0x00, 0x80,
+ 0xE0, 0x44, 0x40, 0xFD, 0x7F, 0x80, 0x12, 0x32,
+ 0x1E, 0x75, 0x20, 0xFF, 0x51, 0x68, 0x51, 0xF9,
+ 0x51, 0x7F, 0xE4, 0xFF, 0x02, 0x43, 0x9E, 0x51,
+ 0x62, 0x51, 0x6F, 0x51, 0xA7, 0x71, 0x4F, 0x51,
+ 0x8A, 0x51, 0x95, 0x90, 0x81, 0x45, 0xE0, 0x54,
+ 0xFE, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xA3, 0xF0,
+ 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0xE4, 0xF5,
+ 0x4D, 0x22, 0xE4, 0x90, 0x80, 0xDE, 0xF0, 0x22,
+ 0x75, 0xE8, 0x03, 0x75, 0xA8, 0x84, 0x22, 0xE4,
+ 0x90, 0x80, 0xD8, 0xF0, 0xA3, 0xF0, 0x22, 0x90,
+ 0x01, 0x94, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90,
+ 0x01, 0xE4, 0x74, 0x0B, 0xF0, 0xA3, 0x74, 0x01,
+ 0xF0, 0x22, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFE,
+ 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x81, 0x42,
+ 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0x7F, 0xF0, 0xA3,
+ 0x74, 0x0A, 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90,
+ 0x81, 0x1F, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD,
+ 0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54,
+ 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0xE4, 0xA3, 0xF0,
+ 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0x74, 0x0C, 0xF0,
+ 0x22, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x04, 0xF0,
+ 0x90, 0x01, 0x9C, 0x74, 0x7E, 0xF0, 0xA3, 0x74,
+ 0x92, 0xF0, 0xA3, 0x74, 0xA0, 0xF0, 0xA3, 0x74,
+ 0x24, 0xF0, 0x90, 0x01, 0x9B, 0x74, 0x49, 0xF0,
+ 0x90, 0x01, 0x9A, 0x74, 0xE0, 0xF0, 0x90, 0x01,
+ 0x99, 0xE4, 0xF0, 0x90, 0x01, 0x98, 0x04, 0xF0,
+ 0x22, 0xE4, 0x90, 0x81, 0x51, 0xF0, 0xA3, 0xF0,
+ 0x90, 0x01, 0x98, 0xE0, 0x7F, 0x00, 0x30, 0xE4,
+ 0x02, 0x7F, 0x01, 0xEF, 0x64, 0x01, 0x60, 0x3E,
+ 0xC3, 0x90, 0x81, 0x52, 0xE0, 0x94, 0x88, 0x90,
+ 0x81, 0x51, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90,
+ 0x01, 0xC1, 0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90,
+ 0x81, 0x51, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44,
+ 0xA9, 0x7F, 0x14, 0x7E, 0x00, 0x12, 0x32, 0xAA,
+ 0xD3, 0x90, 0x81, 0x52, 0xE0, 0x94, 0x32, 0x90,
+ 0x81, 0x51, 0xE0, 0x94, 0x00, 0x40, 0xB9, 0x90,
+ 0x01, 0xC6, 0xE0, 0x30, 0xE3, 0xB2, 0x22, 0xE4,
+ 0x90, 0x81, 0x27, 0xF0, 0xA3, 0xF0, 0x90, 0x81,
+ 0x26, 0xE0, 0x54, 0x0F, 0xF0, 0x54, 0xF0, 0xF0,
+ 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFD, 0xF0, 0x54,
+ 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x2D,
+ 0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x24,
+ 0xE0, 0x54, 0xFB, 0xF0, 0xA3, 0xE0, 0x54, 0xFB,
+ 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81,
+ 0x2F, 0x74, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xE4,
+ 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0xE4, 0x90, 0x81,
+ 0x2B, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFE,
+ 0xF0, 0x90, 0x81, 0x29, 0x74, 0x0C, 0xF0, 0x90,
+ 0x81, 0x24, 0xE0, 0x54, 0xDF, 0xF0, 0x90, 0x81,
+ 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x24, 0xE0,
+ 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0xE0,
+ 0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xF7,
+ 0xF0, 0x90, 0x81, 0x34, 0x12, 0x20, 0xDA, 0x00,
+ 0x00, 0x00, 0x00, 0x90, 0x80, 0x3C, 0xE0, 0xB4,
+ 0x01, 0x08, 0x90, 0x81, 0x31, 0x74, 0x99, 0xF0,
+ 0x80, 0x12, 0x90, 0x80, 0x3C, 0xE0, 0x90, 0x81,
+ 0x31, 0xB4, 0x03, 0x05, 0x74, 0x90, 0xF0, 0x80,
+ 0x03, 0x74, 0x40, 0xF0, 0x90, 0x81, 0x38, 0x74,
+ 0x01, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0xA3, 0xE0,
+ 0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05,
+ 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xE0, 0x54, 0xFD,
+ 0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54,
+ 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xBF, 0xF0,
+ 0xE4, 0xA3, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x59,
+ 0xF0, 0x90, 0x81, 0x59, 0xE0, 0x64, 0x01, 0xF0,
+ 0x24, 0x24, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5C,
+ 0xA3, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0xFF, 0x90,
+ 0x81, 0x29, 0xE0, 0x6F, 0x60, 0x03, 0x12, 0x47,
+ 0x2A, 0xD1, 0x08, 0xBF, 0x01, 0x02, 0x91, 0x5F,
+ 0xB1, 0xF2, 0x12, 0x32, 0x9E, 0xBF, 0x01, 0x02,
+ 0xB1, 0x67, 0x12, 0x42, 0x4D, 0x80, 0xCA, 0xD3,
+ 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81,
+ 0x24, 0xE0, 0x30, 0xE0, 0x24, 0x90, 0x81, 0x1F,
+ 0xE0, 0xFF, 0x30, 0xE0, 0x1A, 0xC3, 0x13, 0x30,
+ 0xE0, 0x07, 0xB1, 0xFB, 0xBF, 0x01, 0x12, 0x80,
+ 0x0A, 0x90, 0x81, 0x23, 0xE0, 0xFF, 0x60, 0x03,
+ 0xB4, 0x08, 0x06, 0x91, 0x96, 0x80, 0x02, 0x91,
+ 0xA6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10,
+ 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xB1, 0x22, 0x91,
+ 0xBA, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81,
+ 0x2A, 0xE0, 0x70, 0x0D, 0xD1, 0x2F, 0xBF, 0x01,
+ 0x08, 0x91, 0x96, 0x90, 0x01, 0xE5, 0xE0, 0x04,
+ 0xF0, 0x22, 0xB1, 0xF3, 0x90, 0x00, 0x08, 0xE0,
+ 0x54, 0xEF, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E,
+ 0xE4, 0xFF, 0x8F, 0x50, 0xE4, 0x90, 0x81, 0x5A,
+ 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x09, 0xE0, 0x7F,
+ 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0xEF, 0x65,
+ 0x50, 0x60, 0x3E, 0xC3, 0x90, 0x81, 0x5B, 0xE0,
+ 0x94, 0x88, 0x90, 0x81, 0x5A, 0xE0, 0x94, 0x13,
+ 0x40, 0x08, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x10,
+ 0xF0, 0x22, 0x90, 0x81, 0x5A, 0xE4, 0x75, 0xF0,
+ 0x01, 0x12, 0x44, 0xA9, 0x7F, 0x14, 0x7E, 0x00,
+ 0x12, 0x32, 0xAA, 0xD3, 0x90, 0x81, 0x5B, 0xE0,
+ 0x94, 0x32, 0x90, 0x81, 0x5A, 0xE0, 0x94, 0x00,
+ 0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE0,
+ 0xB2, 0x22, 0x90, 0x81, 0x31, 0xE0, 0xFD, 0x7F,
+ 0x93, 0x12, 0x32, 0x1E, 0x90, 0x81, 0x28, 0xE0,
+ 0x60, 0x12, 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7,
+ 0x05, 0x74, 0x10, 0xF0, 0x80, 0x06, 0x90, 0x01,
+ 0x2F, 0x74, 0x90, 0xF0, 0x90, 0x00, 0x08, 0xE0,
+ 0x44, 0x10, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E,
+ 0x7F, 0x01, 0x91, 0xCA, 0x90, 0x00, 0x90, 0xE0,
+ 0x44, 0x01, 0xFD, 0x7F, 0x90, 0x12, 0x32, 0x1E,
+ 0x7F, 0x14, 0x7E, 0x00, 0x02, 0x32, 0xAA, 0xD3,
+ 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x2D,
+ 0xA7, 0xE4, 0xF5, 0x52, 0x12, 0x32, 0x9E, 0xEF,
+ 0x60, 0x73, 0x63, 0x52, 0x01, 0xE5, 0x52, 0x24,
+ 0x67, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5D, 0xA3,
+ 0xF0, 0x90, 0x00, 0x88, 0xE0, 0xF5, 0x50, 0xF5,
+ 0x51, 0x54, 0x0F, 0x60, 0xDF, 0xE5, 0x50, 0x30,
+ 0xE0, 0x0B, 0x20, 0xE4, 0x03, 0x12, 0x29, 0xC5,
+ 0x53, 0x51, 0xEE, 0x80, 0x3F, 0xE5, 0x50, 0x30,
+ 0xE1, 0x16, 0x20, 0xE5, 0x0E, 0x12, 0x11, 0xBD,
+ 0xEF, 0x70, 0x03, 0x43, 0x51, 0x20, 0x90, 0x01,
+ 0x06, 0xE4, 0xF0, 0x53, 0x51, 0xFD, 0x80, 0x24,
+ 0xE5, 0x50, 0x30, 0xE2, 0x0B, 0x20, 0xE6, 0x03,
+ 0x12, 0x67, 0x06, 0x53, 0x51, 0xFB, 0x80, 0x14,
+ 0xE5, 0x50, 0x30, 0xE3, 0x0F, 0x20, 0xE7, 0x09,
+ 0x12, 0x61, 0x6E, 0xEF, 0x70, 0x03, 0x43, 0x51,
+ 0x80, 0x53, 0x51, 0xF7, 0xAD, 0x51, 0x7F, 0x88,
+ 0x12, 0x32, 0x1E, 0x80, 0x87, 0xD0, 0xD0, 0x92,
+ 0xAF, 0x22, 0x22, 0x90, 0x00, 0x90, 0xE0, 0x20,
+ 0xE0, 0xF9, 0x22, 0x90, 0x81, 0x22, 0xE0, 0x64,
+ 0x02, 0x7F, 0x01, 0x60, 0x02, 0x7F, 0x00, 0x22,
+ 0x7F, 0x02, 0x90, 0x81, 0x41, 0xE0, 0xFE, 0xEF,
+ 0xC3, 0x9E, 0x50, 0x18, 0xEF, 0x25, 0xE0, 0x24,
+ 0x81, 0xF8, 0xE6, 0x30, 0xE4, 0x0B, 0x90, 0x01,
+ 0xB8, 0x74, 0x08, 0xF0, 0xA3, 0xF0, 0x7F, 0x00,
+ 0x22, 0x0F, 0x80, 0xDE, 0x7F, 0x01, 0x22, 0x90,
+ 0x02, 0x87, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8,
+ 0x74, 0x01, 0xF0, 0x80, 0x17, 0x90, 0x02, 0x86,
+ 0xE0, 0x20, 0xE1, 0x08, 0x90, 0x01, 0xB8, 0x74,
+ 0x04, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4,
+ 0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74,
+ 0x08, 0xF0, 0x7F, 0x00, 0x22, 0xE4, 0xFB, 0xFA,
+ 0xFD, 0x7F, 0x01, 0x12, 0x44, 0x4E, 0x90, 0x81,
+ 0xBD, 0xEF, 0xF0, 0x60, 0xF0, 0xD1, 0x71, 0x80,
+ 0xEC, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0,
+ 0x90, 0x01, 0xCC, 0xE0, 0x54, 0x0F, 0x90, 0x81,
+ 0xBE, 0xF0, 0x90, 0x81, 0xBE, 0xE0, 0xFD, 0x70,
+ 0x02, 0xE1, 0x9C, 0x90, 0x82, 0x09, 0xE0, 0xFF,
+ 0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80,
+ 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9,
+ 0xFF, 0xEF, 0x5D, 0x70, 0x02, 0xE1, 0x95, 0x90,
+ 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01,
+ 0xD0, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xBF,
+ 0xF0, 0x75, 0x13, 0x01, 0x75, 0x14, 0x81, 0x75,
+ 0x15, 0xBF, 0x75, 0x16, 0x01, 0x7B, 0x01, 0x7A,
+ 0x81, 0x79, 0xC0, 0x12, 0x2B, 0xED, 0x90, 0x82,
+ 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD1,
+ 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC1, 0xF0,
+ 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90,
+ 0x01, 0xD2, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81,
+ 0xC2, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0,
+ 0x04, 0x90, 0x01, 0xD3, 0x12, 0x45, 0x0A, 0xE0,
+ 0x90, 0x81, 0xC3, 0xF0, 0x90, 0x82, 0x09, 0xE0,
+ 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF0, 0x12, 0x45,
+ 0x0A, 0xE0, 0x90, 0x81, 0xC4, 0xF0, 0x90, 0x82,
+ 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF1,
+ 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC5, 0xF0,
+ 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90,
+ 0x01, 0xF2, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81,
+ 0xC6, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0,
+ 0x04, 0x90, 0x01, 0xF3, 0x12, 0x45, 0x0A, 0xE0,
+ 0x90, 0x81, 0xC7, 0xF0, 0x90, 0x81, 0xBE, 0xE0,
+ 0xFF, 0x90, 0x82, 0x09, 0xE0, 0xFE, 0x74, 0x01,
+ 0xA8, 0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8,
+ 0xFC, 0xF4, 0x5F, 0x90, 0x81, 0xBE, 0xF0, 0x90,
+ 0x82, 0x09, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07,
+ 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0x90,
+ 0x01, 0xCC, 0xF0, 0x90, 0x81, 0xC0, 0xE0, 0xFF,
+ 0x7B, 0x01, 0x7A, 0x81, 0x79, 0xC1, 0x12, 0x55,
+ 0x3F, 0x90, 0x82, 0x09, 0xE0, 0x04, 0xF0, 0xE0,
+ 0x54, 0x03, 0xF0, 0xC1, 0x82, 0x90, 0x01, 0xC0,
+ 0xE0, 0x44, 0x02, 0xF0, 0xD0, 0xD0, 0x92, 0xAF,
+ 0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12,
+ 0x44, 0x4E, 0x90, 0x81, 0xD0, 0xEF, 0xF0, 0x60,
+ 0xF0, 0x12, 0x6C, 0x19, 0x80, 0xEB, 0x90, 0x81,
+ 0xD4, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xA3, 0x12,
+ 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x90,
+ 0x81, 0xE2, 0xF0, 0x7F, 0x24, 0x7E, 0x08, 0x12,
+ 0x2D, 0x5C, 0x90, 0x81, 0xDA, 0x12, 0x20, 0xCE,
+ 0x90, 0x81, 0xD4, 0xE0, 0xFB, 0x70, 0x08, 0x90,
+ 0x81, 0xDA, 0x12, 0x44, 0xD9, 0x80, 0x16, 0xEB,
+ 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82,
+ 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3,
+ 0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0x90, 0x81, 0xDE,
+ 0x12, 0x20, 0xCE, 0x90, 0x81, 0xD5, 0xE0, 0xFF,
+ 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x17, 0x12, 0x20,
+ 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB,
+ 0x07, 0x90, 0x81, 0xDE, 0x12, 0x44, 0xD9, 0xED,
+ 0x54, 0x7F, 0xFD, 0xEC, 0x54, 0x80, 0xFC, 0x12,
+ 0x44, 0xCC, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x81,
+ 0xDE, 0x12, 0x20, 0xCE, 0x90, 0x81, 0xDA, 0x12,
+ 0x44, 0xD9, 0xEC, 0x54, 0x7F, 0xFC, 0x90, 0x85,
+ 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08,
+ 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xD4, 0xE0, 0x75,
+ 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, 0xE4,
+ 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0,
+ 0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xDE,
+ 0x12, 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20,
+ 0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x12, 0x2E, 0xA2,
+ 0x90, 0x81, 0xDA, 0x12, 0x44, 0xD9, 0xEC, 0x44,
+ 0x80, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE,
+ 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90,
+ 0x81, 0xD4, 0xE0, 0x70, 0x04, 0x7F, 0x20, 0x80,
+ 0x09, 0x90, 0x81, 0xD4, 0xE0, 0xB4, 0x01, 0x16,
+ 0x7F, 0x28, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0x78,
+ 0x08, 0x12, 0x20, 0xA8, 0xEF, 0x54, 0x01, 0xFF,
+ 0xE4, 0x90, 0x81, 0xE2, 0xEF, 0xF0, 0x90, 0x81,
+ 0xE2, 0xE0, 0x90, 0x81, 0xD4, 0x60, 0x0E, 0xE0,
+ 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x66, 0xF5, 0x82,
+ 0xE4, 0x34, 0x87, 0x80, 0x0C, 0xE0, 0x75, 0xF0,
+ 0x08, 0xA4, 0x24, 0x64, 0xF5, 0x82, 0xE4, 0x34,
+ 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF,
+ 0x12, 0x2D, 0x5C, 0xED, 0x54, 0x0F, 0xFD, 0xE4,
+ 0xFC, 0x90, 0x81, 0xD6, 0x12, 0x20, 0xCE, 0x90,
+ 0x81, 0xD6, 0x02, 0x44, 0xD9, 0x90, 0x81, 0xE3,
+ 0xEF, 0xF0, 0xAB, 0x05, 0x90, 0x81, 0xE9, 0x12,
+ 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x03,
+ 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x14, 0x12, 0x20,
+ 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB,
+ 0x07, 0x90, 0x81, 0xE5, 0x12, 0x44, 0xD9, 0xED,
+ 0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x12, 0x44, 0xCC,
+ 0xEC, 0x54, 0x0F, 0xFC, 0x90, 0x81, 0xE9, 0x12,
+ 0x20, 0xCE, 0x90, 0x81, 0xE3, 0xE0, 0x75, 0xF0,
+ 0x08, 0xA4, 0x24, 0x60, 0xF5, 0x82, 0xE4, 0x34,
+ 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF,
+ 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xE9, 0x12,
+ 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE,
+ 0xD0, 0x07, 0xD0, 0x06, 0x02, 0x2E, 0xA2, 0xD3,
+ 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x5F,
+ 0xB6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x78, 0x10,
+ 0x74, 0x01, 0xF2, 0x90, 0x02, 0x09, 0xE0, 0x78,
+ 0x00, 0xF2, 0x08, 0x74, 0x20, 0xF2, 0x18, 0xE2,
+ 0xFF, 0x30, 0xE0, 0x05, 0x08, 0xE2, 0x24, 0x80,
+ 0xF2, 0xEF, 0xC3, 0x13, 0x90, 0xFD, 0x10, 0xF0,
+ 0x78, 0x01, 0xE2, 0x24, 0x00, 0xF5, 0x82, 0xE4,
+ 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x78, 0x03, 0xF2,
+ 0x64, 0x04, 0x60, 0x0D, 0xE2, 0xFF, 0x64, 0x08,
+ 0x60, 0x07, 0xEF, 0x64, 0x0C, 0x60, 0x02, 0x61,
+ 0xDE, 0xE4, 0x78, 0x02, 0xF2, 0x78, 0x03, 0xE2,
+ 0xFF, 0x18, 0xE2, 0xC3, 0x9F, 0x50, 0x2D, 0xE2,
+ 0xFD, 0x18, 0xE2, 0x2D, 0x90, 0x81, 0x5A, 0xF0,
+ 0xE0, 0xFF, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34,
+ 0xFC, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x04, 0x2D,
+ 0xF8, 0xEE, 0xF2, 0xEF, 0xB4, 0xFF, 0x06, 0x90,
+ 0xFD, 0x10, 0xE0, 0x04, 0xF0, 0x78, 0x02, 0xE2,
+ 0x04, 0xF2, 0x80, 0xC9, 0x78, 0x04, 0xE2, 0x78,
+ 0x12, 0xF2, 0xFF, 0x78, 0x05, 0xE2, 0x78, 0x11,
+ 0xF2, 0x78, 0x06, 0xE2, 0x78, 0x13, 0xF2, 0x78,
+ 0x07, 0xE2, 0x78, 0x14, 0xF2, 0x78, 0x08, 0xE2,
+ 0x78, 0x33, 0xF2, 0x78, 0x09, 0xE2, 0x78, 0x34,
+ 0xF2, 0x78, 0x0A, 0xE2, 0x78, 0x35, 0xF2, 0x78,
+ 0x0B, 0xE2, 0x78, 0x36, 0xF2, 0x78, 0x0C, 0xE2,
+ 0x78, 0x37, 0xF2, 0x78, 0x0D, 0xE2, 0x78, 0x38,
+ 0xF2, 0x78, 0x0E, 0xE2, 0x78, 0x39, 0xF2, 0x78,
+ 0x0F, 0xE2, 0x78, 0x3A, 0xF2, 0xE4, 0x78, 0x15,
+ 0xF2, 0xEF, 0x24, 0xF8, 0x60, 0x75, 0x24, 0xFC,
+ 0x60, 0x6C, 0x24, 0x08, 0x60, 0x02, 0x61, 0xC0,
+ 0x78, 0x11, 0xE2, 0xB4, 0x01, 0x05, 0x12, 0x29,
+ 0xC5, 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xB4, 0x02,
+ 0x05, 0x12, 0x11, 0xBD, 0x61, 0xC5, 0x78, 0x11,
+ 0xE2, 0xB4, 0x03, 0x04, 0xF1, 0x06, 0x61, 0xC5,
+ 0x78, 0x11, 0xE2, 0xB4, 0x10, 0x17, 0x78, 0x14,
+ 0xE2, 0xFE, 0x18, 0xE2, 0xFD, 0xED, 0xFF, 0x78,
+ 0x16, 0xEE, 0xF2, 0xFE, 0x08, 0xEF, 0xF2, 0xFF,
+ 0x12, 0x32, 0xAA, 0x61, 0xC5, 0x78, 0x11, 0xE2,
+ 0xB4, 0x11, 0x17, 0x78, 0x14, 0xE2, 0xFE, 0x18,
+ 0xE2, 0xFD, 0xED, 0xFF, 0x78, 0x16, 0xEE, 0xF2,
+ 0xFE, 0x08, 0xEF, 0xF2, 0xFF, 0x12, 0x32, 0x06,
+ 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xF4, 0x60, 0x02,
+ 0x61, 0xC5, 0x18, 0xF2, 0x61, 0xC5, 0x78, 0x15,
+ 0x74, 0x01, 0xF2, 0x78, 0x11, 0xE2, 0x64, 0x07,
+ 0x60, 0x02, 0x61, 0xAA, 0x78, 0x34, 0xE2, 0xFF,
+ 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20,
+ 0xBB, 0xC0, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB,
+ 0x07, 0x78, 0x33, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD,
+ 0xFE, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0xC0, 0x04,
+ 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x35,
+ 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10,
+ 0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0,
+ 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x18,
+ 0x12, 0x44, 0xFE, 0x78, 0x15, 0xE2, 0x70, 0x02,
+ 0x61, 0x93, 0x18, 0xE2, 0xFF, 0x18, 0xE2, 0xFD,
+ 0x31, 0x5F, 0x78, 0x1C, 0x12, 0x44, 0xFE, 0x78,
+ 0x38, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78,
+ 0x08, 0x12, 0x20, 0xBB, 0xC0, 0x04, 0xA9, 0x05,
+ 0xAA, 0x06, 0xAB, 0x07, 0x78, 0x37, 0xE2, 0xFF,
+ 0xE4, 0xFC, 0xFD, 0xFE, 0xD0, 0x00, 0x12, 0x44,
+ 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0,
+ 0x07, 0x78, 0x39, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD,
+ 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, 0xD0, 0x03,
+ 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44,
+ 0xCC, 0x78, 0x20, 0x12, 0x44, 0xFE, 0x78, 0x20,
+ 0x12, 0x44, 0xE5, 0x12, 0x20, 0x9B, 0x78, 0x1C,
+ 0x12, 0x44, 0xF1, 0x12, 0x44, 0xBF, 0xC0, 0x04,
+ 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x18,
+ 0x12, 0x44, 0xE5, 0x78, 0x20, 0x12, 0x44, 0xF1,
+ 0x12, 0x44, 0xBF, 0xD0, 0x03, 0xD0, 0x02, 0xD0,
+ 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x18,
+ 0x12, 0x44, 0xFE, 0x78, 0x18, 0x12, 0x44, 0xE5,
+ 0x90, 0x81, 0xF9, 0x12, 0x20, 0xCE, 0x78, 0x13,
+ 0xE2, 0xFD, 0x08, 0xE2, 0xFF, 0x12, 0x55, 0x1C,
+ 0x80, 0x1B, 0x78, 0x13, 0xE2, 0xFF, 0x08, 0xE2,
+ 0xFD, 0x78, 0x11, 0xE2, 0xFB, 0x78, 0x15, 0xE2,
+ 0x90, 0x81, 0xBC, 0xF0, 0x71, 0xE1, 0x80, 0x05,
+ 0x78, 0x10, 0x74, 0x02, 0xF2, 0x78, 0x10, 0xE2,
+ 0xFF, 0xC3, 0x94, 0x02, 0x50, 0x10, 0xEF, 0x60,
+ 0x0A, 0x78, 0x02, 0xE2, 0xFF, 0x18, 0xE2, 0x2F,
+ 0xF2, 0x21, 0x90, 0x7F, 0x01, 0x22, 0x7F, 0x00,
+ 0x22, 0xAC, 0x07, 0xED, 0xAD, 0x04, 0x78, 0x24,
+ 0xF2, 0xED, 0x08, 0xF2, 0xEB, 0xB4, 0x04, 0x07,
+ 0x78, 0x27, 0x74, 0x01, 0xF2, 0x80, 0x0E, 0xEB,
+ 0x78, 0x27, 0xB4, 0x05, 0x05, 0x74, 0x02, 0xF2,
+ 0x80, 0x03, 0x74, 0x04, 0xF2, 0xD3, 0x78, 0x25,
+ 0xE2, 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x00, 0x50,
+ 0x63, 0xE4, 0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2,
+ 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02,
+ 0xA1, 0x7F, 0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78,
+ 0x28, 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2D,
+ 0x74, 0x37, 0x2E, 0xF8, 0xE2, 0x78, 0x32, 0xF2,
+ 0xEE, 0xFF, 0x78, 0x25, 0xE2, 0x2F, 0xFF, 0x18,
+ 0xE2, 0x34, 0x00, 0x8F, 0x82, 0xF5, 0x83, 0xE0,
+ 0x78, 0x29, 0xF2, 0x78, 0x32, 0xE2, 0xFF, 0xF4,
+ 0xFE, 0x78, 0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2,
+ 0xFD, 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x24, 0x08,
+ 0xE2, 0xFF, 0x08, 0xE2, 0x2F, 0xFF, 0x78, 0x28,
+ 0xE2, 0xFD, 0x12, 0x32, 0x1E, 0x78, 0x26, 0xE2,
+ 0x04, 0xF2, 0x80, 0xA1, 0xD3, 0x78, 0x25, 0xE2,
+ 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x07, 0x50, 0x69,
+ 0xE4, 0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF,
+ 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02, 0xA1,
+ 0x7F, 0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78, 0x28,
+ 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2D, 0x78,
+ 0x26, 0xE2, 0xFF, 0xFD, 0x18, 0xE2, 0x2D, 0xFD,
+ 0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83,
+ 0xE0, 0x78, 0x29, 0xF2, 0x74, 0x37, 0x2F, 0xF8,
+ 0xE2, 0x78, 0x32, 0xF2, 0xE2, 0xFF, 0xF4, 0xFE,
+ 0x78, 0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2, 0xFD,
+ 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x28, 0xE2, 0xFF,
+ 0x78, 0x26, 0xE2, 0xFD, 0x18, 0xE2, 0x2D, 0xFD,
+ 0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83,
+ 0xEF, 0xF0, 0x78, 0x26, 0xE2, 0x04, 0xF2, 0x80,
+ 0x9B, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x0F, 0x78,
+ 0x24, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2D,
+ 0x5C, 0x78, 0x2E, 0x12, 0x44, 0xFE, 0xE4, 0x78,
+ 0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2,
+ 0xFE, 0xC3, 0x9F, 0x50, 0x5D, 0x74, 0x33, 0x2E,
+ 0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xBC,
+ 0xE0, 0x60, 0x2B, 0x78, 0x2E, 0x12, 0x44, 0xE5,
+ 0x78, 0x26, 0xE2, 0xFB, 0x75, 0xF0, 0x08, 0xA4,
+ 0xF9, 0xF8, 0x12, 0x20, 0xA8, 0x78, 0x29, 0xEF,
+ 0xF2, 0x74, 0x37, 0x2B, 0xF8, 0xE2, 0x78, 0x32,
+ 0xF2, 0xE2, 0xFE, 0xF4, 0x5F, 0xFF, 0x78, 0x28,
+ 0xE2, 0xFD, 0xEE, 0x5D, 0x4F, 0xF2, 0x78, 0x28,
+ 0xE2, 0xFF, 0x78, 0x26, 0xE2, 0xFD, 0xC3, 0x74,
+ 0x03, 0x9D, 0xFD, 0xE4, 0x94, 0x00, 0xFC, 0x7B,
+ 0xFE, 0x74, 0x2A, 0x2D, 0xF9, 0x74, 0x80, 0x3C,
+ 0xFA, 0xEF, 0x12, 0x1F, 0xEA, 0xE2, 0x04, 0xF2,
+ 0x80, 0x98, 0x78, 0x2A, 0x12, 0x44, 0xE5, 0x90,
+ 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x78, 0x24, 0xE2,
+ 0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2E, 0xA2, 0x22,
+ 0x22, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x90,
+ 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xFE, 0x12,
+ 0x1F, 0xA4, 0xFD, 0xC3, 0x13, 0x30, 0xE0, 0x12,
+ 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x90, 0x00,
+ 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0xCF, 0xF0,
+ 0x80, 0x05, 0x90, 0x81, 0xCF, 0xEF, 0xF0, 0x90,
+ 0x81, 0xCE, 0xEE, 0xF0, 0x90, 0x81, 0xCF, 0xE0,
+ 0xFE, 0x90, 0x81, 0xCE, 0xE0, 0xFF, 0xD3, 0x9E,
+ 0x50, 0x38, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16,
+ 0x12, 0x1F, 0xA4, 0x54, 0x01, 0xFE, 0x74, 0xDE,
+ 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83,
+ 0xEE, 0xF0, 0x74, 0xDE, 0x2F, 0xF5, 0x82, 0xE4,
+ 0x34, 0x80, 0xF5, 0x83, 0xE0, 0x70, 0x04, 0xD1,
+ 0x25, 0x80, 0x07, 0x90, 0x81, 0xCE, 0xE0, 0xFF,
+ 0xB1, 0x80, 0x90, 0x81, 0xCE, 0xE0, 0x04, 0xF0,
+ 0x80, 0xBA, 0x90, 0x80, 0xDE, 0xE0, 0x70, 0x24,
+ 0x90, 0x81, 0x2A, 0xE0, 0x70, 0x04, 0xFF, 0x12,
+ 0x49, 0x93, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x0C,
+ 0x60, 0x02, 0xD1, 0x26, 0x90, 0x81, 0x24, 0xE0,
+ 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xBF,
+ 0xF0, 0x54, 0x7F, 0xF0, 0x22, 0x22, 0x90, 0x06,
+ 0x04, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x05, 0x22,
+ 0xE4, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0,
+ 0x22, 0x90, 0x81, 0xED, 0xEF, 0xF0, 0xA3, 0xED,
+ 0xF0, 0xAD, 0x03, 0xAC, 0x02, 0xE4, 0x90, 0x81,
+ 0xF5, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0xC4, 0x74,
+ 0x39, 0xF0, 0x74, 0x66, 0xA3, 0xF0, 0xEC, 0x54,
+ 0x3F, 0xFC, 0x90, 0x01, 0x40, 0xED, 0xF0, 0xAE,
+ 0x04, 0xEE, 0xA3, 0xF0, 0x90, 0x81, 0xED, 0xE0,
+ 0x24, 0x81, 0x60, 0x34, 0x24, 0xDA, 0x60, 0x1C,
+ 0x24, 0x3C, 0x70, 0x41, 0x90, 0x81, 0xEE, 0xE0,
+ 0xC4, 0x33, 0x33, 0x33, 0x54, 0x80, 0x90, 0x81,
+ 0xF2, 0xF0, 0xA3, 0x74, 0x69, 0xF0, 0xA3, 0x74,
+ 0x80, 0xF0, 0x80, 0x2C, 0x90, 0x81, 0xEE, 0xE0,
+ 0x54, 0x01, 0x90, 0x81, 0xF2, 0xF0, 0xA3, 0x74,
+ 0xA5, 0xF0, 0xA3, 0x74, 0x01, 0xF0, 0x80, 0x18,
+ 0x90, 0x81, 0xEE, 0xE0, 0xC4, 0x54, 0x10, 0x90,
+ 0x81, 0xF2, 0xF0, 0xA3, 0x74, 0x7F, 0xF0, 0xA3,
+ 0x74, 0x10, 0xF0, 0x80, 0x03, 0x7F, 0x00, 0x22,
+ 0x90, 0x81, 0xF3, 0xE0, 0x90, 0x01, 0x06, 0xF0,
+ 0x90, 0x81, 0xF2, 0xE0, 0x60, 0x0E, 0x90, 0x01,
+ 0x42, 0xF0, 0x90, 0x81, 0xF1, 0xE0, 0x90, 0x01,
+ 0x43, 0xF0, 0x80, 0x0D, 0x90, 0x01, 0x43, 0xE4,
+ 0xF0, 0x90, 0x81, 0xF2, 0xE0, 0x90, 0x01, 0x42,
+ 0xF0, 0x90, 0x81, 0xF4, 0xE0, 0xFF, 0x90, 0x01,
+ 0x42, 0xE0, 0x5F, 0xFF, 0x90, 0x81, 0xF2, 0xE0,
+ 0x6F, 0x60, 0xEE, 0x74, 0x39, 0x04, 0x90, 0x01,
+ 0xC4, 0xF0, 0x74, 0x66, 0xA3, 0xF0, 0x90, 0x01,
+ 0x43, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0xE4, 0x90,
+ 0x81, 0x6A, 0xF0, 0x90, 0x87, 0x5F, 0xE0, 0x90,
+ 0x81, 0x69, 0xF0, 0xE4, 0x90, 0x81, 0x76, 0xF0,
+ 0x90, 0x81, 0x66, 0xF0, 0x90, 0x81, 0x66, 0xE0,
+ 0xFF, 0xC3, 0x94, 0x40, 0x50, 0x15, 0x74, 0x79,
+ 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83,
+ 0x74, 0xFF, 0xF0, 0x90, 0x81, 0x66, 0xE0, 0x04,
+ 0xF0, 0x80, 0xE1, 0xE4, 0x90, 0x81, 0x66, 0xF0,
+ 0x90, 0x81, 0x69, 0xE0, 0xFF, 0x90, 0x81, 0x66,
+ 0xE0, 0xFE, 0xC3, 0x9F, 0x40, 0x03, 0x02, 0x68,
+ 0x12, 0x74, 0xDF, 0x2E, 0xF9, 0xE4, 0x34, 0x86,
+ 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75,
+ 0x16, 0x0A, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x5B,
+ 0x12, 0x2B, 0xED, 0x90, 0x81, 0x5C, 0xE0, 0xFF,
+ 0x12, 0x2F, 0x27, 0xEF, 0x04, 0x90, 0x81, 0x76,
+ 0xF0, 0x90, 0x81, 0x5B, 0xE0, 0xFF, 0xA3, 0xE0,
+ 0xFD, 0x12, 0x31, 0xEA, 0xEF, 0x24, 0xC8, 0x90,
+ 0x81, 0x78, 0xF0, 0x75, 0xF0, 0x08, 0xA4, 0xF0,
+ 0x90, 0x81, 0x5C, 0xE0, 0x54, 0x0F, 0x90, 0x81,
+ 0x77, 0xF0, 0xE4, 0x90, 0x81, 0x65, 0xF0, 0x90,
+ 0x81, 0x67, 0xF0, 0x90, 0x81, 0x67, 0xE0, 0xFF,
+ 0xC3, 0x94, 0x04, 0x50, 0x57, 0x90, 0x81, 0x77,
+ 0xE0, 0xFE, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3,
+ 0x13, 0xD8, 0xFC, 0x20, 0xE0, 0x3E, 0x90, 0x81,
+ 0x67, 0xE0, 0x25, 0xE0, 0xFF, 0x90, 0x81, 0x78,
+ 0xE0, 0x2F, 0x24, 0x79, 0xF9, 0xE4, 0x34, 0x81,
+ 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x01, 0x90,
+ 0x81, 0x65, 0xE0, 0x75, 0xF0, 0x02, 0xA4, 0x24,
+ 0x5D, 0xF9, 0x74, 0x81, 0x35, 0xF0, 0x8B, 0x13,
+ 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x02, 0xD0,
+ 0x01, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x81,
+ 0x65, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x67, 0xE0,
+ 0x04, 0xF0, 0x80, 0x9F, 0x90, 0x81, 0x76, 0xE0,
+ 0xFF, 0x90, 0x81, 0x66, 0xE0, 0x2F, 0xF0, 0x02,
+ 0x67, 0x40, 0xE4, 0x90, 0x81, 0x6A, 0xF0, 0x90,
+ 0x81, 0x6A, 0xE0, 0xC3, 0x94, 0x40, 0x40, 0x02,
+ 0x41, 0xAF, 0xE0, 0xFF, 0x24, 0x79, 0xF5, 0x82,
+ 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90, 0x81,
+ 0x6C, 0xF0, 0xE0, 0xFE, 0x54, 0xF0, 0xC4, 0x54,
+ 0x0F, 0xFD, 0x90, 0x81, 0x6B, 0xF0, 0xEE, 0x54,
+ 0x0F, 0xFE, 0xA3, 0xF0, 0x74, 0x7A, 0x2F, 0xF5,
+ 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90,
+ 0x81, 0x6D, 0xF0, 0xFC, 0xEE, 0xFE, 0xEC, 0xFB,
+ 0xEB, 0xFF, 0x90, 0x81, 0x72, 0xEE, 0xF0, 0xA3,
+ 0xEF, 0xF0, 0xED, 0x12, 0x45, 0x28, 0x68, 0x8B,
+ 0x00, 0x68, 0xC2, 0x01, 0x69, 0x73, 0x02, 0x6A,
+ 0xA0, 0x03, 0x69, 0x8E, 0x04, 0x69, 0xAF, 0x05,
+ 0x69, 0xAF, 0x06, 0x69, 0xAF, 0x07, 0x69, 0xAF,
+ 0x08, 0x6A, 0x33, 0x09, 0x6A, 0x69, 0x0A, 0x00,
+ 0x00, 0x6A, 0xAF, 0x90, 0x81, 0x6A, 0xE0, 0xFD,
+ 0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5,
+ 0x83, 0xE0, 0xFE, 0x74, 0x7B, 0x2D, 0xF5, 0x82,
+ 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFD, 0xED,
+ 0xFF, 0x90, 0x81, 0x74, 0xEE, 0xF0, 0xFC, 0xA3,
+ 0xEF, 0xF0, 0x90, 0x81, 0x6D, 0xE0, 0xFF, 0x12,
+ 0x2F, 0x96, 0x90, 0x81, 0x68, 0x74, 0x02, 0xF0,
+ 0x41, 0xA0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7C,
+ 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0,
+ 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12,
+ 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06,
+ 0xAB, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B,
+ 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0,
+ 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x12, 0x44, 0xCC,
+ 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07,
+ 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7D, 0xF5, 0x82,
+ 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4,
+ 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB,
+ 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00,
+ 0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0,
+ 0x06, 0xC0, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24,
+ 0x7E, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83,
+ 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x18,
+ 0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0,
+ 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x90, 0x81,
+ 0x6E, 0x12, 0x20, 0xCE, 0x90, 0x81, 0x6E, 0x12,
+ 0x44, 0xD9, 0x90, 0x85, 0x96, 0x12, 0x20, 0xCE,
+ 0x90, 0x81, 0x72, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF,
+ 0x12, 0x2E, 0xE4, 0x90, 0x81, 0x68, 0x74, 0x04,
+ 0xF0, 0x41, 0xA0, 0x90, 0x81, 0x6D, 0xE0, 0xFD,
+ 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82,
+ 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFB, 0xE4,
+ 0xFF, 0x12, 0x30, 0xC7, 0x80, 0x19, 0x90, 0x81,
+ 0x6D, 0xE0, 0xFD, 0x90, 0x81, 0x6A, 0xE0, 0x24,
+ 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83,
+ 0xE0, 0xFB, 0xE4, 0xFF, 0x12, 0x30, 0x6A, 0x90,
+ 0x81, 0x68, 0x74, 0x01, 0xF0, 0x41, 0xA0, 0x90,
+ 0x81, 0x68, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x6A,
+ 0xE0, 0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81,
+ 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE,
+ 0x78, 0x08, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9,
+ 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0x6A,
+ 0xE0, 0x24, 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81,
+ 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE,
+ 0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0,
+ 0x06, 0xC0, 0x07, 0x90, 0x81, 0x6C, 0xE0, 0xFF,
+ 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20,
+ 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0,
+ 0x00, 0x12, 0x44, 0xCC, 0x90, 0x81, 0x6E, 0x12,
+ 0x20, 0xCE, 0x90, 0x81, 0x6B, 0xE0, 0x24, 0xFB,
+ 0xFF, 0xC0, 0x07, 0x90, 0x81, 0x6E, 0x12, 0x44,
+ 0xD9, 0x90, 0x81, 0xF9, 0x12, 0x20, 0xCE, 0x90,
+ 0x81, 0x6D, 0xE0, 0xFD, 0xD0, 0x07, 0x12, 0x55,
+ 0x1C, 0x80, 0x6D, 0x90, 0x81, 0x68, 0x74, 0x01,
+ 0xF0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF9,
+ 0xE4, 0x34, 0x81, 0x75, 0x13, 0x01, 0xF5, 0x14,
+ 0x89, 0x15, 0x75, 0x16, 0x01, 0x7B, 0xFE, 0x7A,
+ 0x80, 0x79, 0x33, 0x12, 0x2B, 0xED, 0x90, 0x81,
+ 0x6D, 0xE0, 0xFF, 0x90, 0x81, 0x6C, 0xE0, 0xFD,
+ 0xE4, 0x90, 0x81, 0xBC, 0xF0, 0x7B, 0x04, 0x80,
+ 0x34, 0x90, 0x81, 0x68, 0x74, 0x04, 0xF0, 0x90,
+ 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF9, 0xE4, 0x34,
+ 0x81, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15,
+ 0x75, 0x16, 0x04, 0x7B, 0xFE, 0x7A, 0x80, 0x79,
+ 0x33, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x6D, 0xE0,
+ 0xFF, 0x90, 0x81, 0x6C, 0xE0, 0xFD, 0xE4, 0x90,
+ 0x81, 0xBC, 0xF0, 0x7B, 0x06, 0x12, 0x63, 0xE1,
+ 0x90, 0x81, 0x68, 0xE0, 0x24, 0x02, 0xFF, 0x90,
+ 0x81, 0x6A, 0xE0, 0x2F, 0xF0, 0x01, 0x17, 0x22,
+ 0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4,
+ 0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x80, 0x3D,
+ 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF,
+ 0xED, 0x2F, 0x90, 0x80, 0x3E, 0xF0, 0x90, 0x00,
+ 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90,
+ 0x80, 0x3F, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F,
+ 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x40, 0xF0,
+ 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xAE,
+ 0x05, 0xED, 0x2F, 0x90, 0x80, 0x41, 0xF0, 0x22,
+ 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0x30,
+ 0xE0, 0x26, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x38,
+ 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90,
+ 0x81, 0x39, 0xF0, 0xEF, 0x54, 0xFE, 0xFF, 0xA3,
+ 0xE0, 0x54, 0x01, 0x4F, 0xF0, 0x90, 0x00, 0x03,
+ 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x3B, 0xF0, 0x22,
+ 0x90, 0x81, 0x38, 0x74, 0x01, 0xF0, 0xA3, 0x74,
+ 0x05, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28,
+ 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0x22, 0x12, 0x1F,
+ 0xA4, 0x90, 0x81, 0x3E, 0xF0, 0x90, 0x81, 0x3E,
+ 0xE0, 0x90, 0x01, 0xE7, 0xF0, 0x22, 0x12, 0x1F,
+ 0xA4, 0x90, 0x81, 0x4A, 0xF0, 0x90, 0x00, 0x01,
+ 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x4B, 0xF0, 0x22,
+ 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90,
+ 0x81, 0xFD, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xE4,
+ 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0xFD, 0xE0,
+ 0xFE, 0xA3, 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0xE0,
+ 0x60, 0x2D, 0xC3, 0x90, 0x82, 0x00, 0xE0, 0x94,
+ 0xE8, 0x90, 0x81, 0xFF, 0xE0, 0x94, 0x03, 0x40,
+ 0x0B, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x80, 0xF0,
+ 0x7F, 0x00, 0x80, 0x15, 0x90, 0x81, 0xFF, 0xE4,
+ 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, 0x7F, 0x0A,
+ 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x80, 0xC5, 0x7F,
+ 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10,
+ 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xD1,
+ 0x12, 0x45, 0x1F, 0x90, 0x82, 0x0A, 0xE0, 0xFF,
+ 0x04, 0xF0, 0x90, 0x00, 0x01, 0xEF, 0x12, 0x1F,
+ 0xFC, 0x7F, 0xAF, 0x7E, 0x01, 0x71, 0x60, 0xEF,
+ 0x60, 0x3A, 0x90, 0x81, 0xD1, 0x12, 0x45, 0x16,
+ 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x90, 0x00,
+ 0x0E, 0x12, 0x1F, 0xBD, 0x24, 0x02, 0xF5, 0x16,
+ 0x7B, 0x01, 0x7A, 0x01, 0x79, 0xA0, 0x12, 0x2B,
+ 0xED, 0x90, 0x81, 0xD1, 0x12, 0x45, 0x16, 0x90,
+ 0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x90, 0x01, 0xAE,
+ 0xF0, 0xA3, 0x74, 0xFF, 0xF0, 0x90, 0x01, 0xCB,
+ 0xE0, 0x64, 0x80, 0xF0, 0xD0, 0xD0, 0x92, 0xAF,
+ 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0,
+ 0xE4, 0xFF, 0x90, 0x80, 0xD9, 0xE0, 0xFE, 0x90,
+ 0x80, 0xD8, 0xE0, 0xFD, 0xB5, 0x06, 0x04, 0x7E,
+ 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x64, 0x01,
+ 0x60, 0x32, 0x90, 0x01, 0xAF, 0xE0, 0x70, 0x13,
+ 0xED, 0x75, 0xF0, 0x0F, 0xA4, 0x24, 0x42, 0xF9,
+ 0x74, 0x80, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0x71,
+ 0xB6, 0x7F, 0x01, 0xEF, 0x60, 0x16, 0x90, 0x80,
+ 0xD8, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4,
+ 0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4,
+ 0x90, 0x80, 0xD8, 0xF0, 0xD0, 0xD0, 0x92, 0xAF,
+ 0x22, 0x8F, 0x0D, 0x22, 0x8F, 0x0E, 0x22, 0x22,
+ 0x90, 0x01, 0x34, 0xE0, 0x55, 0x3D, 0xF5, 0x41,
+ 0xA3, 0xE0, 0x55, 0x3E, 0xF5, 0x42, 0xA3, 0xE0,
+ 0x55, 0x3F, 0xF5, 0x43, 0xA3, 0xE0, 0x55, 0x40,
+ 0xF5, 0x44, 0x90, 0x01, 0x34, 0xE5, 0x41, 0xF0,
+ 0xA3, 0xE5, 0x42, 0xF0, 0xA3, 0xE5, 0x43, 0xF0,
+ 0xA3, 0xE5, 0x44, 0xF0, 0x22, 0x90, 0x01, 0x3C,
+ 0xE0, 0x55, 0x45, 0xF5, 0x49, 0xA3, 0xE0, 0x55,
+ 0x46, 0xF5, 0x4A, 0xA3, 0xE0, 0x55, 0x47, 0xF5,
+ 0x4B, 0xA3, 0xE0, 0x55, 0x48, 0xF5, 0x4C, 0x90,
+ 0x01, 0x3C, 0xE5, 0x49, 0xF0, 0xA3, 0xE5, 0x4A,
+ 0xF0, 0xA3, 0xE5, 0x4B, 0xF0, 0xA3, 0xE5, 0x4C,
+ 0xF0, 0x53, 0x91, 0xDF, 0x22, 0x90, 0x81, 0x1F,
+ 0xE0, 0x30, 0xE0, 0x05, 0xE4, 0xA3, 0xF0, 0xA3,
+ 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01,
+ 0x70, 0x19, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x13,
+ 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C,
+ 0x74, 0x02, 0x12, 0x4F, 0xF4, 0x90, 0x01, 0x57,
+ 0x74, 0x05, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0,
+ 0x64, 0x01, 0x70, 0x26, 0x90, 0x81, 0x27, 0xE0,
+ 0x60, 0x20, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90,
+ 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24,
+ 0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0,
+ 0x54, 0xFD, 0xF0, 0x54, 0x07, 0x70, 0x03, 0x12,
+ 0x47, 0x2A, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0xB4,
+ 0x01, 0x14, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x0E,
+ 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02,
+ 0x60, 0x02, 0x80, 0x03, 0xD1, 0x7F, 0x22, 0x90,
+ 0x04, 0x1D, 0xE0, 0x70, 0x13, 0x90, 0x80, 0x3E,
+ 0xE0, 0xFF, 0xE4, 0xFD, 0xB1, 0x69, 0x8E, 0x4E,
+ 0x8F, 0x4F, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0,
+ 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0,
+ 0x90, 0x82, 0x0E, 0xED, 0xF0, 0x90, 0x82, 0x0D,
+ 0xEF, 0xF0, 0xE4, 0xFD, 0xFC, 0xF1, 0x37, 0x7C,
+ 0x00, 0xAD, 0x07, 0x90, 0x82, 0x0D, 0xE0, 0x90,
+ 0x04, 0x25, 0xF0, 0x90, 0x82, 0x0E, 0xE0, 0x60,
+ 0x0E, 0x74, 0x0F, 0x2F, 0xF5, 0x82, 0xE4, 0x34,
+ 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0xAF,
+ 0x05, 0x74, 0x08, 0x2F, 0xF5, 0x82, 0xE4, 0x34,
+ 0xFC, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x09, 0x2F,
+ 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0,
+ 0x54, 0xF0, 0xF0, 0x74, 0x21, 0x2D, 0xF5, 0x82,
+ 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF7,
+ 0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xD0, 0xD0, 0x92,
+ 0xAF, 0x22, 0x8F, 0x4E, 0xF1, 0x4B, 0xBF, 0x01,
+ 0x18, 0x90, 0x80, 0x40, 0xE0, 0xFF, 0x7D, 0x01,
+ 0xB1, 0x69, 0xAD, 0x07, 0xAC, 0x06, 0xAF, 0x4E,
+ 0x12, 0x4F, 0x82, 0x90, 0x04, 0x1F, 0x74, 0x20,
+ 0xF0, 0x22, 0x90, 0x06, 0xA9, 0xE0, 0x90, 0x81,
+ 0x4C, 0xF0, 0xE0, 0xFD, 0x54, 0xC0, 0x70, 0x09,
+ 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x80,
+ 0x72, 0xED, 0x30, 0xE6, 0x4B, 0x90, 0x81, 0x27,
+ 0xE0, 0x64, 0x02, 0x70, 0x2A, 0x90, 0x81, 0x24,
+ 0xE0, 0xFF, 0xC3, 0x13, 0x20, 0xE0, 0x09, 0x90,
+ 0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x28,
+ 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x01,
+ 0x70, 0x2D, 0x90, 0x81, 0x2B, 0xE0, 0x44, 0x04,
+ 0xF0, 0x7F, 0x01, 0xB1, 0xD2, 0x80, 0x20, 0x90,
+ 0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81,
+ 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04,
+ 0xB1, 0x4F, 0x80, 0x0B, 0xD1, 0x7F, 0x80, 0x07,
+ 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90,
+ 0x81, 0x4C, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7,
+ 0x11, 0x12, 0x4F, 0xF1, 0x90, 0x01, 0x57, 0x74,
+ 0x05, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x04,
+ 0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90,
+ 0x01, 0x5F, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74,
+ 0x08, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A,
+ 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4,
+ 0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x50,
+ 0x05, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90,
+ 0x06, 0x92, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24,
+ 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81, 0x2A, 0xE0,
+ 0x64, 0x0C, 0x60, 0x0C, 0xE4, 0xFD, 0x7F, 0x0C,
+ 0x12, 0x47, 0x3D, 0xE4, 0xFF, 0x12, 0x4F, 0x0D,
+ 0x22, 0xE4, 0x90, 0x81, 0x4C, 0xF0, 0x90, 0x06,
+ 0xA9, 0xE0, 0x90, 0x81, 0x4C, 0xF0, 0xE0, 0x54,
+ 0xC0, 0x70, 0x0D, 0x90, 0x81, 0x2B, 0xE0, 0x54,
+ 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x02, 0x47, 0x2A,
+ 0x90, 0x81, 0x4C, 0xE0, 0x30, 0xE6, 0x21, 0x90,
+ 0x81, 0x27, 0xE0, 0x64, 0x01, 0x70, 0x20, 0x90,
+ 0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81,
+ 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04,
+ 0xB1, 0x4F, 0x80, 0x0B, 0xD1, 0x7F, 0x80, 0x07,
+ 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90,
+ 0x81, 0x4C, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7,
+ 0x11, 0x12, 0x4F, 0xF1, 0x90, 0x01, 0x57, 0x74,
+ 0x05, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x04,
+ 0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0xE4,
+ 0xFE, 0xEF, 0xC3, 0x13, 0xFD, 0xEF, 0x30, 0xE0,
+ 0x02, 0x7E, 0x80, 0x90, 0xFD, 0x10, 0xED, 0xF0,
+ 0xAF, 0x06, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3,
+ 0xC0, 0xD0, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x1A,
+ 0x90, 0x05, 0x22, 0xE0, 0x54, 0x90, 0x60, 0x07,
+ 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x08, 0xF0, 0x90,
+ 0x01, 0xC6, 0xE0, 0x30, 0xE1, 0xE4, 0x7F, 0x00,
+ 0x80, 0x02, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF,
+ 0x22, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x03, 0x12,
+ 0x73, 0xE1, 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0,
+ 0x03, 0x12, 0x49, 0xDD, 0x22, 0x90, 0x81, 0x27,
+ 0xE0, 0x60, 0x35, 0x90, 0x06, 0x92, 0xE0, 0x30,
+ 0xE1, 0x24, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A,
+ 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4,
+ 0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x50,
+ 0x05, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90,
+ 0x06, 0x92, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x81,
+ 0x24, 0xE0, 0x54, 0xEF, 0xF0, 0x12, 0x47, 0x2A,
+ 0x22, 0x12, 0x71, 0x48, 0x90, 0x81, 0x4D, 0xEF,
+ 0xF0, 0x90, 0x81, 0x24, 0x30, 0xE0, 0x06, 0xE0,
+ 0x44, 0x01, 0xF0, 0x80, 0x04, 0xE0, 0x54, 0xFE,
+ 0xF0, 0x90, 0x81, 0x4D, 0xE0, 0x30, 0xE6, 0x11,
+ 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x04, 0xE4,
+ 0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, 0x80,
+ 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x30, 0xE0, 0x1A,
+ 0x90, 0x81, 0x32, 0xE4, 0xF0, 0xA3, 0x74, 0x07,
+ 0xF0, 0x90, 0x81, 0x32, 0xA3, 0xE0, 0x90, 0x05,
+ 0x58, 0xF0, 0x90, 0x04, 0xEC, 0xE0, 0x54, 0xDD,
+ 0xF0, 0x22, 0x90, 0x04, 0xEC, 0xE0, 0x44, 0x22,
+ 0xF0, 0x22, 0x90, 0x81, 0x4A, 0xE0, 0x60, 0x0F,
+ 0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x01,
+ 0xF0, 0x90, 0x05, 0xFD, 0xE0, 0x04, 0xF0, 0x22,
+ 0x90, 0x81, 0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13,
+ 0x54, 0x03, 0x30, 0xE0, 0x27, 0xEF, 0x54, 0xBF,
+ 0xF0, 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25,
+ 0x30, 0xE0, 0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80,
+ 0x10, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x01, 0xB9,
+ 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x04,
+ 0xF0, 0x12, 0x47, 0x2A, 0xE4, 0xFF, 0x90, 0x81,
+ 0x45, 0xE0, 0x30, 0xE0, 0x48, 0x90, 0x81, 0x49,
+ 0xE0, 0xFD, 0x60, 0x41, 0x74, 0x01, 0x7E, 0x00,
+ 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE,
+ 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x04, 0xE0,
+ 0xE0, 0xFB, 0xEF, 0x5B, 0x60, 0x06, 0xE4, 0x90,
+ 0x81, 0x49, 0xF0, 0x22, 0x90, 0x81, 0x47, 0xE0,
+ 0xD3, 0x9D, 0x50, 0x10, 0x90, 0x01, 0xC7, 0x74,
+ 0x10, 0xF0, 0x11, 0xBE, 0x90, 0x81, 0x45, 0xE0,
+ 0x54, 0xFE, 0xF0, 0x22, 0x12, 0x4F, 0x0B, 0x90,
+ 0x81, 0x49, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x80,
+ 0x3C, 0xE0, 0x64, 0x02, 0x60, 0x07, 0x90, 0x06,
+ 0x90, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x81,
+ 0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54,
+ 0x01, 0x30, 0xE0, 0x2C, 0xEF, 0x54, 0x7F, 0xF0,
+ 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25, 0x30,
+ 0xE1, 0x06, 0xE0, 0x44, 0x02, 0xF0, 0x80, 0x0F,
+ 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x01, 0xB9, 0x74,
+ 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x04, 0xF0, 0x90,
+ 0x81, 0x27, 0xE0, 0x60, 0x03, 0x12, 0x47, 0x2A,
+ 0x7F, 0x01, 0x01, 0x6E, 0xC3, 0xEE, 0x94, 0x01,
+ 0x40, 0x0A, 0x0D, 0xED, 0x13, 0x90, 0xFD, 0x10,
+ 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xC3, 0xEE, 0x94,
+ 0x01, 0x40, 0x24, 0x90, 0xFD, 0x11, 0xE0, 0x6D,
+ 0x70, 0x1A, 0x90, 0x01, 0x17, 0xE0, 0xB5, 0x05,
+ 0x0D, 0x90, 0x01, 0xE4, 0x74, 0x77, 0xF0, 0x90,
+ 0xFD, 0x11, 0xE4, 0xF0, 0x80, 0x06, 0xED, 0x04,
+ 0x90, 0xFD, 0x11, 0xF0, 0xE4, 0x2F, 0xFF, 0x22,
+ 0xE4, 0x90, 0x81, 0x4E, 0xF0, 0xA3, 0xF0, 0xA3,
+ 0xF0, 0x90, 0x00, 0x83, 0xE0, 0x90, 0x81, 0x4E,
+ 0xF0, 0x90, 0x00, 0x83, 0xE0, 0xFE, 0x90, 0x81,
+ 0x4E, 0xE0, 0xFF, 0xB5, 0x06, 0x01, 0x22, 0xC3,
+ 0x90, 0x81, 0x50, 0xE0, 0x94, 0x64, 0x90, 0x81,
+ 0x4F, 0xE0, 0x94, 0x00, 0x40, 0x0D, 0x90, 0x01,
+ 0xC0, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x4E,
+ 0xE0, 0xFF, 0x22, 0x90, 0x81, 0x4F, 0xE4, 0x75,
+ 0xF0, 0x01, 0x12, 0x44, 0xA9, 0x80, 0xC2, 0x74,
+ 0x45, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E,
+ 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4,
+ 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xD3,
+ 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82,
+ 0x12, 0xED, 0xF0, 0x90, 0x82, 0x11, 0xEF, 0xF0,
+ 0xD3, 0x94, 0x07, 0x50, 0x70, 0xE0, 0xFF, 0x74,
+ 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33,
+ 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x47, 0xE0,
+ 0x5F, 0xFD, 0x7F, 0x47, 0x12, 0x32, 0x1E, 0x90,
+ 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07,
+ 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF,
+ 0x90, 0x00, 0x46, 0xE0, 0x4F, 0xFD, 0x7F, 0x46,
+ 0x12, 0x32, 0x1E, 0x90, 0x82, 0x12, 0xE0, 0x60,
+ 0x18, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01,
+ 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8,
+ 0xFC, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x4F, 0x80,
+ 0x17, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01,
+ 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8,
+ 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x5F,
+ 0xFD, 0x7F, 0x45, 0x80, 0x7E, 0x90, 0x82, 0x11,
+ 0xE0, 0x24, 0xF8, 0xF0, 0xE0, 0x24, 0x04, 0xFF,
+ 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3,
+ 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x43,
+ 0xE0, 0x5F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E,
+ 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8,
+ 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC,
+ 0xFF, 0x90, 0x00, 0x43, 0xE0, 0x4F, 0xFD, 0x7F,
+ 0x43, 0x12, 0x32, 0x1E, 0x90, 0x82, 0x12, 0xE0,
+ 0x60, 0x1D, 0x90, 0x82, 0x11, 0xE0, 0x24, 0x04,
+ 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02,
+ 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x42,
+ 0xE0, 0x4F, 0xFD, 0x7F, 0x42, 0x80, 0x1C, 0x90,
+ 0x82, 0x11, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01,
+ 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8,
+ 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x5F,
+ 0xFD, 0x7F, 0x42, 0x12, 0x32, 0x1E, 0xD0, 0xD0,
+ 0x92, 0xAF, 0x22, 0x90, 0x81, 0x24, 0xE0, 0x54,
+ 0xFB, 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90,
+ 0x81, 0x2B, 0xF0, 0x22, 0xEF, 0x24, 0xFE, 0x60,
+ 0x0C, 0x04, 0x70, 0x28, 0x90, 0x81, 0x2D, 0x74,
+ 0x01, 0xF0, 0xA3, 0xF0, 0x22, 0xED, 0x70, 0x0A,
+ 0x90, 0x81, 0x3B, 0xE0, 0x90, 0x81, 0x2D, 0xF0,
+ 0x80, 0x05, 0x90, 0x81, 0x2D, 0xED, 0xF0, 0x90,
+ 0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x90, 0x81, 0x25,
+ 0xE0, 0x44, 0x08, 0xF0, 0x22, 0x12, 0x4E, 0xAB,
+ 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8,
+ 0x74, 0x01, 0xF0, 0x80, 0x67, 0x90, 0x81, 0x2B,
+ 0xE0, 0xFF, 0x54, 0x03, 0x60, 0x08, 0x90, 0x01,
+ 0xB8, 0x74, 0x02, 0xF0, 0x80, 0x56, 0x90, 0x81,
+ 0x29, 0xE0, 0xFE, 0xE4, 0xC3, 0x9E, 0x50, 0x08,
+ 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x44,
+ 0xEF, 0x30, 0xE2, 0x08, 0x90, 0x01, 0xB8, 0x74,
+ 0x08, 0xF0, 0x80, 0x38, 0x90, 0x81, 0x2B, 0xE0,
+ 0x30, 0xE4, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x10,
+ 0xF0, 0x80, 0x29, 0x90, 0x81, 0x25, 0xE0, 0x13,
+ 0x13, 0x54, 0x3F, 0x20, 0xE0, 0x08, 0x90, 0x01,
+ 0xB8, 0x74, 0x20, 0xF0, 0x80, 0x16, 0x90, 0x81,
+ 0x3E, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74,
+ 0x80, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4,
+ 0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74,
+ 0x04, 0xF0, 0x7F, 0x00, 0x22, 0xEF, 0x60, 0x42,
+ 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, 0x3A,
+ 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFE, 0xF0, 0x90,
+ 0x05, 0x22, 0x74, 0x0F, 0xF0, 0x90, 0x06, 0x04,
+ 0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0xFF, 0x12, 0x4F,
+ 0x0D, 0xBF, 0x01, 0x12, 0x90, 0x81, 0x24, 0xE0,
+ 0x44, 0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x06,
+ 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x01,
+ 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74,
+ 0x08, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F,
+ 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0,
+ 0x90, 0x81, 0x2A, 0x74, 0x02, 0xF0, 0x90, 0x81,
+ 0x23, 0xF0, 0x22, 0x12, 0x54, 0x65, 0x90, 0x81,
+ 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0,
+ 0x22, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, 0x13,
+ 0x54, 0x3F, 0x30, 0xE0, 0x11, 0xEF, 0x54, 0xFB,
+ 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0,
+ 0x54, 0x07, 0x70, 0x42, 0x80, 0x3D, 0x90, 0x81,
+ 0x30, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x2B, 0xE0,
+ 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x30, 0xE0, 0xFF,
+ 0xB4, 0x01, 0x02, 0x80, 0x04, 0xEF, 0xB4, 0x02,
+ 0x06, 0x90, 0x05, 0x58, 0xE0, 0x04, 0xF0, 0x90,
+ 0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0,
+ 0xD3, 0x9F, 0x40, 0x0F, 0x90, 0x80, 0xDE, 0xE0,
+ 0xB4, 0x01, 0x0B, 0x90, 0x81, 0x25, 0xE0, 0x54,
+ 0xFB, 0xF0, 0x22, 0x12, 0x47, 0x2A, 0x22, 0x22,
+ 0x90, 0x05, 0x2B, 0xE0, 0x7F, 0x00, 0x30, 0xE7,
+ 0x02, 0x7F, 0x01, 0x22, 0x90, 0x05, 0x22, 0x74,
+ 0xFF, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40,
+ 0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22,
+ 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x12,
+ 0x49, 0xDD, 0x90, 0x81, 0x22, 0x74, 0x02, 0xF0,
+ 0x22, 0x12, 0x49, 0xE3, 0x90, 0x81, 0x22, 0x74,
+ 0x02, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F,
+ 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0,
+ 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0xAE,
+ 0x07, 0x12, 0x51, 0x73, 0xBF, 0x01, 0x12, 0x90,
+ 0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, 0x0A, 0xAF,
+ 0x06, 0x7D, 0x01, 0x12, 0x47, 0x3D, 0x7F, 0x01,
+ 0x22, 0x7F, 0x00, 0x22, 0x90, 0x01, 0x57, 0xE0,
+ 0x60, 0x48, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74,
+ 0x02, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13,
+ 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0C, 0xEF, 0x54,
+ 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD,
+ 0xF0, 0x22, 0x90, 0x81, 0x30, 0xE0, 0x04, 0xF0,
+ 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xEF, 0xF0, 0x90,
+ 0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0,
+ 0xD3, 0x9F, 0x40, 0x0E, 0x90, 0x80, 0xDE, 0xE0,
+ 0xB4, 0x01, 0x07, 0x90, 0x81, 0x25, 0xE0, 0x54,
+ 0xFB, 0xF0, 0x22, 0x90, 0x80, 0x3F, 0xE0, 0xFF,
+ 0x7D, 0x01, 0x12, 0x6D, 0x69, 0x8E, 0x54, 0x8F,
+ 0x55, 0xAD, 0x55, 0xAC, 0x54, 0xAF, 0x53, 0x12,
+ 0x4F, 0x82, 0xAF, 0x55, 0xAE, 0x54, 0x90, 0x04,
+ 0x80, 0xE0, 0x54, 0x0F, 0xFD, 0xAC, 0x07, 0x74,
+ 0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5,
+ 0x83, 0xE0, 0x44, 0x01, 0xF0, 0x74, 0x11, 0x2C,
+ 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0,
+ 0x54, 0xFB, 0xF0, 0xAC, 0x07, 0x74, 0x16, 0x2C,
+ 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0,
+ 0x44, 0xFA, 0xF0, 0x74, 0x15, 0x2C, 0xF5, 0x82,
+ 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x1F,
+ 0xF0, 0xAC, 0x07, 0x74, 0x06, 0x2C, 0xF5, 0x82,
+ 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x0F,
+ 0xF0, 0x90, 0x04, 0x53, 0xE4, 0xF0, 0x90, 0x04,
+ 0x52, 0xF0, 0x90, 0x04, 0x51, 0x74, 0xFF, 0xF0,
+ 0x90, 0x04, 0x50, 0x74, 0xFD, 0xF0, 0x74, 0x14,
+ 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83,
+ 0xE0, 0x54, 0xC0, 0x4D, 0xFD, 0x74, 0x14, 0x2F,
+ 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xED,
+ 0xF0, 0x22, 0xAB, 0x07, 0xAA, 0x06, 0xED, 0x2B,
+ 0xFB, 0xE4, 0x3A, 0xFA, 0xC3, 0x90, 0x80, 0xDB,
+ 0xE0, 0x9B, 0x90, 0x80, 0xDA, 0xE0, 0x9A, 0x50,
+ 0x13, 0xA3, 0xE0, 0x24, 0x01, 0xFF, 0x90, 0x80,
+ 0xDA, 0xE0, 0x34, 0x00, 0xFE, 0xC3, 0xEB, 0x9F,
+ 0xFB, 0xEA, 0x9E, 0xFA, 0xEA, 0x90, 0xFD, 0x11,
+ 0xF0, 0xAF, 0x03, 0x74, 0x00, 0x2F, 0xF5, 0x82,
+ 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x22,
+ 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90,
+ 0x81, 0x42, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF,
+ 0xC3, 0x13, 0x30, 0xE0, 0x0A, 0x90, 0x00, 0x01,
+ 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x43, 0xF0, 0x22,
+ 0x90, 0x81, 0x45, 0xE0, 0x30, 0xE0, 0x2D, 0x90,
+ 0x81, 0x48, 0xE0, 0x04, 0xF0, 0xE0, 0xFF, 0x90,
+ 0x81, 0x46, 0xE0, 0xB5, 0x07, 0x1E, 0x90, 0x06,
+ 0x92, 0xE0, 0x54, 0x1C, 0x70, 0x0B, 0x12, 0x4F,
+ 0x0B, 0x90, 0x81, 0x49, 0xE0, 0x04, 0xF0, 0x80,
+ 0x06, 0x90, 0x06, 0x92, 0x74, 0x1C, 0xF0, 0xE4,
+ 0x90, 0x81, 0x48, 0xF0, 0x22, 0x00, 0xBB, 0x8E,
+};
diff --git a/drivers/staging/rtl8188eu/hal/Hal8188EPwrSeq.c b/drivers/staging/rtl8188eu/hal/Hal8188EPwrSeq.c
new file mode 100644
index 00000000000..fc23bf15934
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/Hal8188EPwrSeq.c
@@ -0,0 +1,86 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#include "Hal8188EPwrSeq.h"
+#include <rtl8188e_hal.h>
+
+/*
+ drivers should parse below arrays and do the corresponding actions
+*/
+/* 3 Power on Array */
+struct wl_pwr_cfg rtl8188E_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_CARDEMU_TO_ACT
+ RTL8188E_TRANS_END
+};
+
+/* 3Radio off Array */
+struct wl_pwr_cfg rtl8188E_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_END
+};
+
+/* 3Card Disable Array */
+struct wl_pwr_cfg rtl8188E_card_disable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_CARDDIS
+ RTL8188E_TRANS_END
+};
+
+/* 3 Card Enable Array */
+struct wl_pwr_cfg rtl8188E_card_enable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_CARDDIS_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_ACT
+ RTL8188E_TRANS_END
+};
+
+/* 3Suspend Array */
+struct wl_pwr_cfg rtl8188E_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_SUS
+ RTL8188E_TRANS_END
+};
+
+/* 3 Resume Array */
+struct wl_pwr_cfg rtl8188E_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_SUS_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_ACT
+ RTL8188E_TRANS_END
+};
+
+/* 3HWPDN Array */
+struct wl_pwr_cfg rtl8188E_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_PDN
+ RTL8188E_TRANS_END
+};
+
+/* 3 Enter LPS */
+struct wl_pwr_cfg rtl8188E_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS + RTL8188E_TRANS_END_STEPS] = {
+ /* FW behavior */
+ RTL8188E_TRANS_ACT_TO_LPS
+ RTL8188E_TRANS_END
+};
+
+/* 3 Leave LPS */
+struct wl_pwr_cfg rtl8188E_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS + RTL8188E_TRANS_END_STEPS] = {
+ /* FW behavior */
+ RTL8188E_TRANS_LPS_TO_ACT
+ RTL8188E_TRANS_END
+};
diff --git a/drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c b/drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c
new file mode 100644
index 00000000000..aaa261771ab
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c
@@ -0,0 +1,760 @@
+/*++
+Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+
+Module Name:
+ RateAdaptive.c
+
+Abstract:
+ Implement Rate Adaptive functions for common operations.
+
+Major Change History:
+ When Who What
+ ---------- --------------- -------------------------------
+ 2011-08-12 Page Create.
+
+--*/
+#include "odm_precomp.h"
+
+/* Rate adaptive parameters */
+
+static u8 RETRY_PENALTY[PERENTRY][RETRYSIZE+1] = {
+ {5, 4, 3, 2, 0, 3}, /* 92 , idx = 0 */
+ {6, 5, 4, 3, 0, 4}, /* 86 , idx = 1 */
+ {6, 5, 4, 2, 0, 4}, /* 81 , idx = 2 */
+ {8, 7, 6, 4, 0, 6}, /* 75 , idx = 3 */
+ {10, 9, 8, 6, 0, 8}, /* 71 , idx = 4 */
+ {10, 9, 8, 4, 0, 8}, /* 66 , idx = 5 */
+ {10, 9, 8, 2, 0, 8}, /* 62 , idx = 6 */
+ {10, 9, 8, 0, 0, 8}, /* 59 , idx = 7 */
+ {18, 17, 16, 8, 0, 16}, /* 53 , idx = 8 */
+ {26, 25, 24, 16, 0, 24}, /* 50 , idx = 9 */
+ {34, 33, 32, 24, 0, 32}, /* 47 , idx = 0x0a */
+ {34, 31, 28, 20, 0, 32}, /* 43 , idx = 0x0b */
+ {34, 31, 27, 18, 0, 32}, /* 40 , idx = 0x0c */
+ {34, 31, 26, 16, 0, 32}, /* 37 , idx = 0x0d */
+ {34, 30, 22, 16, 0, 32}, /* 32 , idx = 0x0e */
+ {34, 30, 24, 16, 0, 32}, /* 26 , idx = 0x0f */
+ {49, 46, 40, 16, 0, 48}, /* 20 , idx = 0x10 */
+ {49, 45, 32, 0, 0, 48}, /* 17 , idx = 0x11 */
+ {49, 45, 22, 18, 0, 48}, /* 15 , idx = 0x12 */
+ {49, 40, 24, 16, 0, 48}, /* 12 , idx = 0x13 */
+ {49, 32, 18, 12, 0, 48}, /* 9 , idx = 0x14 */
+ {49, 22, 18, 14, 0, 48}, /* 6 , idx = 0x15 */
+ {49, 16, 16, 0, 0, 48}
+ }; /* 3, idx = 0x16 */
+
+static u8 PT_PENALTY[RETRYSIZE+1] = {34, 31, 30, 24, 0, 32};
+
+/* wilson modify */
+static u8 RETRY_PENALTY_IDX[2][RATESIZE] = {
+ {4, 4, 4, 5, 4, 4, 5, 7, 7, 7, 8, 0x0a, /* SS>TH */
+ 4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d,
+ 5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f}, /* 0329 R01 */
+ {0x0a, 0x0a, 0x0b, 0x0c, 0x0a,
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x14, /* SS<TH */
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x13, 0x15,
+ 9, 9, 9, 9, 0x0c, 0x0e, 0x11, 0x13}
+ };
+
+static u8 RETRY_PENALTY_UP_IDX[RATESIZE] = {
+ 0x0c, 0x0d, 0x0d, 0x0f, 0x0d, 0x0e,
+ 0x0f, 0x0f, 0x10, 0x12, 0x13, 0x14, /* SS>TH */
+ 0x0f, 0x10, 0x10, 0x12, 0x12, 0x13, 0x14, 0x15,
+ 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15};
+
+static u8 RSSI_THRESHOLD[RATESIZE] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x24, 0x26, 0x2a,
+ 0x18, 0x1a, 0x1d, 0x1f, 0x21, 0x27, 0x29, 0x2a,
+ 0, 0, 0, 0x1f, 0x23, 0x28, 0x2a, 0x2c};
+
+static u16 N_THRESHOLD_HIGH[RATESIZE] = {
+ 4, 4, 8, 16,
+ 24, 36, 48, 72, 96, 144, 192, 216,
+ 60, 80, 100, 160, 240, 400, 560, 640,
+ 300, 320, 480, 720, 1000, 1200, 1600, 2000};
+static u16 N_THRESHOLD_LOW[RATESIZE] = {
+ 2, 2, 4, 8,
+ 12, 18, 24, 36, 48, 72, 96, 108,
+ 30, 40, 50, 80, 120, 200, 280, 320,
+ 150, 160, 240, 360, 500, 600, 800, 1000};
+
+static u8 DROPING_NECESSARY[RATESIZE] = {
+ 1, 1, 1, 1,
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 5, 6, 7, 8, 9, 10, 11, 12};
+
+static u8 PendingForRateUpFail[5] = {2, 10, 24, 40, 60};
+static u16 DynamicTxRPTTiming[6] = {
+ 0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12 , 0x927c}; /* 200ms-1200ms */
+
+/* End Rate adaptive parameters */
+
+static void odm_SetTxRPTTiming_8188E(
+ struct odm_dm_struct *dm_odm,
+ struct odm_ra_info *pRaInfo,
+ u8 extend
+ )
+{
+ u8 idx = 0;
+
+ for (idx = 0; idx < 5; idx++)
+ if (DynamicTxRPTTiming[idx] == pRaInfo->RptTime)
+ break;
+
+ if (extend == 0) { /* back to default timing */
+ idx = 0; /* 200ms */
+ } else if (extend == 1) {/* increase the timing */
+ idx += 1;
+ if (idx > 5)
+ idx = 5;
+ } else if (extend == 2) {/* decrease the timing */
+ if (idx != 0)
+ idx -= 1;
+ }
+ pRaInfo->RptTime = DynamicTxRPTTiming[idx];
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("pRaInfo->RptTime = 0x%x\n", pRaInfo->RptTime));
+}
+
+static int odm_RateDown_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_info *pRaInfo)
+{
+ u8 RateID, LowestRate, HighestRate;
+ u8 i;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDown_8188E()\n"));
+ if (NULL == pRaInfo) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateDown_8188E(): pRaInfo is NULL\n"));
+ return -1;
+ }
+ RateID = pRaInfo->PreRate;
+ LowestRate = pRaInfo->LowestRate;
+ HighestRate = pRaInfo->HighestRate;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+ (" RateID =%d LowestRate =%d HighestRate =%d RateSGI =%d\n",
+ RateID, LowestRate, HighestRate, pRaInfo->RateSGI));
+ if (RateID > HighestRate) {
+ RateID = HighestRate;
+ } else if (pRaInfo->RateSGI) {
+ pRaInfo->RateSGI = 0;
+ } else if (RateID > LowestRate) {
+ if (RateID > 0) {
+ for (i = RateID-1; i > LowestRate; i--) {
+ if (pRaInfo->RAUseRate & BIT(i)) {
+ RateID = i;
+ goto RateDownFinish;
+ }
+ }
+ }
+ } else if (RateID <= LowestRate) {
+ RateID = LowestRate;
+ }
+RateDownFinish:
+ if (pRaInfo->RAWaitingCounter == 1) {
+ pRaInfo->RAWaitingCounter += 1;
+ pRaInfo->RAPendingCounter += 1;
+ } else if (pRaInfo->RAWaitingCounter == 0) {
+ ;
+ } else {
+ pRaInfo->RAWaitingCounter = 0;
+ pRaInfo->RAPendingCounter = 0;
+ }
+
+ if (pRaInfo->RAPendingCounter >= 4)
+ pRaInfo->RAPendingCounter = 4;
+
+ pRaInfo->DecisionRate = RateID;
+ odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 2);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down, RPT Timing default\n"));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d", pRaInfo->RAWaitingCounter, pRaInfo->RAPendingCounter));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down to RateID %d RateSGI %d\n", RateID, pRaInfo->RateSGI));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<===== odm_RateDown_8188E()\n"));
+ return 0;
+}
+
+static int odm_RateUp_8188E(
+ struct odm_dm_struct *dm_odm,
+ struct odm_ra_info *pRaInfo
+ )
+{
+ u8 RateID, HighestRate;
+ u8 i;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateUp_8188E()\n"));
+ if (NULL == pRaInfo) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E(): pRaInfo is NULL\n"));
+ return -1;
+ }
+ RateID = pRaInfo->PreRate;
+ HighestRate = pRaInfo->HighestRate;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+ (" RateID =%d HighestRate =%d\n",
+ RateID, HighestRate));
+ if (pRaInfo->RAWaitingCounter == 1) {
+ pRaInfo->RAWaitingCounter = 0;
+ pRaInfo->RAPendingCounter = 0;
+ } else if (pRaInfo->RAWaitingCounter > 1) {
+ pRaInfo->PreRssiStaRA = pRaInfo->RssiStaRA;
+ goto RateUpfinish;
+ }
+ odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 0);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E():Decrease RPT Timing\n"));
+
+ if (RateID < HighestRate) {
+ for (i = RateID+1; i <= HighestRate; i++) {
+ if (pRaInfo->RAUseRate & BIT(i)) {
+ RateID = i;
+ goto RateUpfinish;
+ }
+ }
+ } else if (RateID == HighestRate) {
+ if (pRaInfo->SGIEnable && (pRaInfo->RateSGI != 1))
+ pRaInfo->RateSGI = 1;
+ else if ((pRaInfo->SGIEnable) != 1)
+ pRaInfo->RateSGI = 0;
+ } else {
+ RateID = HighestRate;
+ }
+RateUpfinish:
+ if (pRaInfo->RAWaitingCounter == (4+PendingForRateUpFail[pRaInfo->RAPendingCounter]))
+ pRaInfo->RAWaitingCounter = 0;
+ else
+ pRaInfo->RAWaitingCounter++;
+
+ pRaInfo->DecisionRate = RateID;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate up to RateID %d\n", RateID));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d", pRaInfo->RAWaitingCounter, pRaInfo->RAPendingCounter));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<===== odm_RateUp_8188E()\n"));
+ return 0;
+}
+
+static void odm_ResetRaCounter_8188E(struct odm_ra_info *pRaInfo)
+{
+ u8 RateID;
+
+ RateID = pRaInfo->DecisionRate;
+ pRaInfo->NscUp = (N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1;
+ pRaInfo->NscDown = (N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1;
+}
+
+static void odm_RateDecision_8188E(struct odm_dm_struct *dm_odm,
+ struct odm_ra_info *pRaInfo
+ )
+{
+ u8 RateID = 0, RtyPtID = 0, PenaltyID1 = 0, PenaltyID2 = 0;
+ /* u32 pool_retry; */
+ static u8 DynamicTxRPTTimingCounter;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDecision_8188E()\n"));
+
+ if (pRaInfo->Active && (pRaInfo->TOTAL > 0)) { /* STA used and data packet exits */
+ if ((pRaInfo->RssiStaRA < (pRaInfo->PreRssiStaRA - 3)) ||
+ (pRaInfo->RssiStaRA > (pRaInfo->PreRssiStaRA + 3))) {
+ pRaInfo->RAWaitingCounter = 0;
+ pRaInfo->RAPendingCounter = 0;
+ }
+ /* Start RA decision */
+ if (pRaInfo->PreRate > pRaInfo->HighestRate)
+ RateID = pRaInfo->HighestRate;
+ else
+ RateID = pRaInfo->PreRate;
+ if (pRaInfo->RssiStaRA > RSSI_THRESHOLD[RateID])
+ RtyPtID = 0;
+ else
+ RtyPtID = 1;
+ PenaltyID1 = RETRY_PENALTY_IDX[RtyPtID][RateID]; /* TODO by page */
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+ (" NscDown init is %d\n", pRaInfo->NscDown));
+ pRaInfo->NscDown += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID1][0];
+ pRaInfo->NscDown += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID1][1];
+ pRaInfo->NscDown += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID1][2];
+ pRaInfo->NscDown += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID1][3];
+ pRaInfo->NscDown += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID1][4];
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+ (" NscDown is %d, total*penalty[5] is %d\n",
+ pRaInfo->NscDown, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5])));
+ if (pRaInfo->NscDown > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]))
+ pRaInfo->NscDown -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5];
+ else
+ pRaInfo->NscDown = 0;
+
+ /* rate up */
+ PenaltyID2 = RETRY_PENALTY_UP_IDX[RateID];
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+ (" NscUp init is %d\n", pRaInfo->NscUp));
+ pRaInfo->NscUp += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID2][0];
+ pRaInfo->NscUp += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID2][1];
+ pRaInfo->NscUp += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID2][2];
+ pRaInfo->NscUp += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID2][3];
+ pRaInfo->NscUp += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID2][4];
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+ ("NscUp is %d, total*up[5] is %d\n",
+ pRaInfo->NscUp, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5])));
+ if (pRaInfo->NscUp > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]))
+ pRaInfo->NscUp -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5];
+ else
+ pRaInfo->NscUp = 0;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE|ODM_COMP_INIT, ODM_DBG_LOUD,
+ (" RssiStaRa = %d RtyPtID =%d PenaltyID1 = 0x%x PenaltyID2 = 0x%x RateID =%d NscDown =%d NscUp =%d SGI =%d\n",
+ pRaInfo->RssiStaRA, RtyPtID, PenaltyID1, PenaltyID2, RateID, pRaInfo->NscDown, pRaInfo->NscUp, pRaInfo->RateSGI));
+ if ((pRaInfo->NscDown < N_THRESHOLD_LOW[RateID]) ||
+ (pRaInfo->DROP > DROPING_NECESSARY[RateID]))
+ odm_RateDown_8188E(dm_odm, pRaInfo);
+ else if (pRaInfo->NscUp > N_THRESHOLD_HIGH[RateID])
+ odm_RateUp_8188E(dm_odm, pRaInfo);
+
+ if (pRaInfo->DecisionRate > pRaInfo->HighestRate)
+ pRaInfo->DecisionRate = pRaInfo->HighestRate;
+
+ if ((pRaInfo->DecisionRate) == (pRaInfo->PreRate))
+ DynamicTxRPTTimingCounter += 1;
+ else
+ DynamicTxRPTTimingCounter = 0;
+
+ if (DynamicTxRPTTimingCounter >= 4) {
+ odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 1);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE,
+ ODM_DBG_LOUD, ("<===== Rate don't change 4 times, Extend RPT Timing\n"));
+ DynamicTxRPTTimingCounter = 0;
+ }
+
+ pRaInfo->PreRate = pRaInfo->DecisionRate; /* YJ, add, 120120 */
+
+ odm_ResetRaCounter_8188E(pRaInfo);
+ }
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<===== odm_RateDecision_8188E()\n"));
+}
+
+static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_info *pRaInfo)
+{ /* Wilson 2011/10/26 */
+ u32 MaskFromReg;
+ s8 i;
+
+ switch (pRaInfo->RateID) {
+ case RATR_INX_WIRELESS_NGB:
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff015;
+ break;
+ case RATR_INX_WIRELESS_NG:
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff010;
+ break;
+ case RATR_INX_WIRELESS_NB:
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff005;
+ break;
+ case RATR_INX_WIRELESS_N:
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff000;
+ break;
+ case RATR_INX_WIRELESS_GB:
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x00000ff5;
+ break;
+ case RATR_INX_WIRELESS_G:
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x00000ff0;
+ break;
+ case RATR_INX_WIRELESS_B:
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0000000d;
+ break;
+ case 12:
+ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR0);
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
+ break;
+ case 13:
+ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR1);
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
+ break;
+ case 14:
+ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR2);
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
+ break;
+ case 15:
+ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR3);
+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
+ break;
+ default:
+ pRaInfo->RAUseRate = (pRaInfo->RateMask);
+ break;
+ }
+ /* Highest rate */
+ if (pRaInfo->RAUseRate) {
+ for (i = RATESIZE; i >= 0; i--) {
+ if ((pRaInfo->RAUseRate)&BIT(i)) {
+ pRaInfo->HighestRate = i;
+ break;
+ }
+ }
+ } else {
+ pRaInfo->HighestRate = 0;
+ }
+ /* Lowest rate */
+ if (pRaInfo->RAUseRate) {
+ for (i = 0; i < RATESIZE; i++) {
+ if ((pRaInfo->RAUseRate) & BIT(i)) {
+ pRaInfo->LowestRate = i;
+ break;
+ }
+ }
+ } else {
+ pRaInfo->LowestRate = 0;
+ }
+ if (pRaInfo->HighestRate > 0x13)
+ pRaInfo->PTModeSS = 3;
+ else if (pRaInfo->HighestRate > 0x0b)
+ pRaInfo->PTModeSS = 2;
+ else if (pRaInfo->HighestRate > 0x0b)
+ pRaInfo->PTModeSS = 1;
+ else
+ pRaInfo->PTModeSS = 0;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+ ("ODM_ARFBRefresh_8188E(): PTModeSS =%d\n", pRaInfo->PTModeSS));
+
+ if (pRaInfo->DecisionRate > pRaInfo->HighestRate)
+ pRaInfo->DecisionRate = pRaInfo->HighestRate;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+ ("ODM_ARFBRefresh_8188E(): RateID =%d RateMask =%8.8x RAUseRate =%8.8x HighestRate =%d, DecisionRate =%d\n",
+ pRaInfo->RateID, pRaInfo->RateMask, pRaInfo->RAUseRate, pRaInfo->HighestRate, pRaInfo->DecisionRate));
+ return 0;
+}
+
+static void odm_PTTryState_8188E(struct odm_ra_info *pRaInfo)
+{
+ pRaInfo->PTTryState = 0;
+ switch (pRaInfo->PTModeSS) {
+ case 3:
+ if (pRaInfo->DecisionRate >= 0x19)
+ pRaInfo->PTTryState = 1;
+ break;
+ case 2:
+ if (pRaInfo->DecisionRate >= 0x11)
+ pRaInfo->PTTryState = 1;
+ break;
+ case 1:
+ if (pRaInfo->DecisionRate >= 0x0a)
+ pRaInfo->PTTryState = 1;
+ break;
+ case 0:
+ if (pRaInfo->DecisionRate >= 0x03)
+ pRaInfo->PTTryState = 1;
+ break;
+ default:
+ pRaInfo->PTTryState = 0;
+ break;
+ }
+
+ if (pRaInfo->RssiStaRA < 48) {
+ pRaInfo->PTStage = 0;
+ } else if (pRaInfo->PTTryState == 1) {
+ if ((pRaInfo->PTStopCount >= 10) ||
+ (pRaInfo->PTPreRssi > pRaInfo->RssiStaRA + 5) ||
+ (pRaInfo->PTPreRssi < pRaInfo->RssiStaRA - 5) ||
+ (pRaInfo->DecisionRate != pRaInfo->PTPreRate)) {
+ if (pRaInfo->PTStage == 0)
+ pRaInfo->PTStage = 1;
+ else if (pRaInfo->PTStage == 1)
+ pRaInfo->PTStage = 3;
+ else
+ pRaInfo->PTStage = 5;
+
+ pRaInfo->PTPreRssi = pRaInfo->RssiStaRA;
+ pRaInfo->PTStopCount = 0;
+ } else {
+ pRaInfo->RAstage = 0;
+ pRaInfo->PTStopCount++;
+ }
+ } else {
+ pRaInfo->PTStage = 0;
+ pRaInfo->RAstage = 0;
+ }
+ pRaInfo->PTPreRate = pRaInfo->DecisionRate;
+}
+
+static void odm_PTDecision_8188E(struct odm_ra_info *pRaInfo)
+{
+ u8 j;
+ u8 temp_stage;
+ u32 numsc;
+ u32 num_total;
+ u8 stage_id;
+
+ numsc = 0;
+ num_total = pRaInfo->TOTAL * PT_PENALTY[5];
+ for (j = 0; j <= 4; j++) {
+ numsc += pRaInfo->RTY[j] * PT_PENALTY[j];
+ if (numsc > num_total)
+ break;
+ }
+
+ j = j >> 1;
+ temp_stage = (pRaInfo->PTStage + 1) >> 1;
+ if (temp_stage > j)
+ stage_id = temp_stage-j;
+ else
+ stage_id = 0;
+
+ pRaInfo->PTSmoothFactor = (pRaInfo->PTSmoothFactor>>1) + (pRaInfo->PTSmoothFactor>>2) + stage_id*16+2;
+ if (pRaInfo->PTSmoothFactor > 192)
+ pRaInfo->PTSmoothFactor = 192;
+ stage_id = pRaInfo->PTSmoothFactor >> 6;
+ temp_stage = stage_id*2;
+ if (temp_stage != 0)
+ temp_stage -= 1;
+ if (pRaInfo->DROP > 3)
+ temp_stage = 0;
+ pRaInfo->PTStage = temp_stage;
+}
+
+static void
+odm_RATxRPTTimerSetting(
+ struct odm_dm_struct *dm_odm,
+ u16 minRptTime
+)
+{
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, (" =====>odm_RATxRPTTimerSetting()\n"));
+
+ if (dm_odm->CurrminRptTime != minRptTime) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+ (" CurrminRptTime = 0x%04x minRptTime = 0x%04x\n", dm_odm->CurrminRptTime, minRptTime));
+ rtw_rpt_timer_cfg_cmd(dm_odm->Adapter, minRptTime);
+ dm_odm->CurrminRptTime = minRptTime;
+ }
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, (" <===== odm_RATxRPTTimerSetting()\n"));
+}
+
+void
+ODM_RASupport_Init(
+ struct odm_dm_struct *dm_odm
+ )
+{
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>ODM_RASupport_Init()\n"));
+
+ /* 2012/02/14 MH Be noticed, the init must be after IC type is recognized!!!!! */
+ if (dm_odm->SupportICType == ODM_RTL8188E)
+ dm_odm->RaSupport88E = true;
+}
+
+int ODM_RAInfo_Init(struct odm_dm_struct *dm_odm, u8 macid)
+{
+ struct odm_ra_info *pRaInfo = &dm_odm->RAInfo[macid];
+ u8 WirelessMode = 0xFF; /* invalid value */
+ u8 max_rate_idx = 0x13; /* MCS7 */
+ if (dm_odm->pWirelessMode != NULL)
+ WirelessMode = *(dm_odm->pWirelessMode);
+
+ if (WirelessMode != 0xFF) {
+ if (WirelessMode & ODM_WM_N24G)
+ max_rate_idx = 0x13;
+ else if (WirelessMode & ODM_WM_G)
+ max_rate_idx = 0x0b;
+ else if (WirelessMode & ODM_WM_B)
+ max_rate_idx = 0x03;
+ }
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+ ("ODM_RAInfo_Init(): WirelessMode:0x%08x , max_raid_idx:0x%02x\n",
+ WirelessMode, max_rate_idx));
+
+ pRaInfo->DecisionRate = max_rate_idx;
+ pRaInfo->PreRate = max_rate_idx;
+ pRaInfo->HighestRate = max_rate_idx;
+ pRaInfo->LowestRate = 0;
+ pRaInfo->RateID = 0;
+ pRaInfo->RateMask = 0xffffffff;
+ pRaInfo->RssiStaRA = 0;
+ pRaInfo->PreRssiStaRA = 0;
+ pRaInfo->SGIEnable = 0;
+ pRaInfo->RAUseRate = 0xffffffff;
+ pRaInfo->NscDown = (N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2;
+ pRaInfo->NscUp = (N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2;
+ pRaInfo->RateSGI = 0;
+ pRaInfo->Active = 1; /* Active is not used at present. by page, 110819 */
+ pRaInfo->RptTime = 0x927c;
+ pRaInfo->DROP = 0;
+ pRaInfo->RTY[0] = 0;
+ pRaInfo->RTY[1] = 0;
+ pRaInfo->RTY[2] = 0;
+ pRaInfo->RTY[3] = 0;
+ pRaInfo->RTY[4] = 0;
+ pRaInfo->TOTAL = 0;
+ pRaInfo->RAWaitingCounter = 0;
+ pRaInfo->RAPendingCounter = 0;
+ pRaInfo->PTActive = 1; /* Active when this STA is use */
+ pRaInfo->PTTryState = 0;
+ pRaInfo->PTStage = 5; /* Need to fill into HW_PWR_STATUS */
+ pRaInfo->PTSmoothFactor = 192;
+ pRaInfo->PTStopCount = 0;
+ pRaInfo->PTPreRate = 0;
+ pRaInfo->PTPreRssi = 0;
+ pRaInfo->PTModeSS = 0;
+ pRaInfo->RAstage = 0;
+ return 0;
+}
+
+int ODM_RAInfo_Init_all(struct odm_dm_struct *dm_odm)
+{
+ u8 macid = 0;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>\n"));
+ dm_odm->CurrminRptTime = 0;
+
+ for (macid = 0; macid < ODM_ASSOCIATE_ENTRY_NUM; macid++)
+ ODM_RAInfo_Init(dm_odm, macid);
+
+ return 0;
+}
+
+u8 ODM_RA_GetShortGI_8188E(struct odm_dm_struct *dm_odm, u8 macid)
+{
+ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
+ return 0;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+ ("macid =%d SGI =%d\n", macid, dm_odm->RAInfo[macid].RateSGI));
+ return dm_odm->RAInfo[macid].RateSGI;
+}
+
+u8 ODM_RA_GetDecisionRate_8188E(struct odm_dm_struct *dm_odm, u8 macid)
+{
+ u8 DecisionRate = 0;
+
+ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
+ return 0;
+ DecisionRate = (dm_odm->RAInfo[macid].DecisionRate);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+ (" macid =%d DecisionRate = 0x%x\n", macid, DecisionRate));
+ return DecisionRate;
+}
+
+u8 ODM_RA_GetHwPwrStatus_8188E(struct odm_dm_struct *dm_odm, u8 macid)
+{
+ u8 PTStage = 5;
+
+ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
+ return 0;
+ PTStage = (dm_odm->RAInfo[macid].PTStage);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+ ("macid =%d PTStage = 0x%x\n", macid, PTStage));
+ return PTStage;
+}
+
+void ODM_RA_UpdateRateInfo_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 RateID, u32 RateMask, u8 SGIEnable)
+{
+ struct odm_ra_info *pRaInfo = NULL;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+ ("macid =%d RateID = 0x%x RateMask = 0x%x SGIEnable =%d\n",
+ macid, RateID, RateMask, SGIEnable));
+ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
+ return;
+
+ pRaInfo = &(dm_odm->RAInfo[macid]);
+ pRaInfo->RateID = RateID;
+ pRaInfo->RateMask = RateMask;
+ pRaInfo->SGIEnable = SGIEnable;
+ odm_ARFBRefresh_8188E(dm_odm, pRaInfo);
+}
+
+void ODM_RA_SetRSSI_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 Rssi)
+{
+ struct odm_ra_info *pRaInfo = NULL;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+ (" macid =%d Rssi =%d\n", macid, Rssi));
+ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
+ return;
+
+ pRaInfo = &(dm_odm->RAInfo[macid]);
+ pRaInfo->RssiStaRA = Rssi;
+}
+
+void ODM_RA_Set_TxRPT_Time(struct odm_dm_struct *dm_odm, u16 minRptTime)
+{
+ ODM_Write2Byte(dm_odm, REG_TX_RPT_TIME, minRptTime);
+}
+
+void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, u8 *TxRPT_Buf, u16 TxRPT_Len, u32 macid_entry0, u32 macid_entry1)
+{
+ struct odm_ra_info *pRAInfo = NULL;
+ u8 MacId = 0;
+ u8 *pBuffer = NULL;
+ u32 valid = 0, ItemNum = 0;
+ u16 minRptTime = 0x927c;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+ ("=====>ODM_RA_TxRPT2Handle_8188E(): valid0 =%d valid1 =%d BufferLength =%d\n",
+ macid_entry0, macid_entry1, TxRPT_Len));
+
+ ItemNum = TxRPT_Len >> 3;
+ pBuffer = TxRPT_Buf;
+
+ do {
+ if (MacId >= ASSOCIATE_ENTRY_NUM)
+ valid = 0;
+ else if (MacId >= 32)
+ valid = (1 << (MacId - 32)) & macid_entry1;
+ else
+ valid = (1 << MacId) & macid_entry0;
+
+ pRAInfo = &(dm_odm->RAInfo[MacId]);
+ if (valid) {
+ pRAInfo->RTY[0] = (u16)GET_TX_REPORT_TYPE1_RERTY_0(pBuffer);
+ pRAInfo->RTY[1] = (u16)GET_TX_REPORT_TYPE1_RERTY_1(pBuffer);
+ pRAInfo->RTY[2] = (u16)GET_TX_REPORT_TYPE1_RERTY_2(pBuffer);
+ pRAInfo->RTY[3] = (u16)GET_TX_REPORT_TYPE1_RERTY_3(pBuffer);
+ pRAInfo->RTY[4] = (u16)GET_TX_REPORT_TYPE1_RERTY_4(pBuffer);
+ pRAInfo->DROP = (u16)GET_TX_REPORT_TYPE1_DROP_0(pBuffer);
+ pRAInfo->TOTAL = pRAInfo->RTY[0] + pRAInfo->RTY[1] +
+ pRAInfo->RTY[2] + pRAInfo->RTY[3] +
+ pRAInfo->RTY[4] + pRAInfo->DROP;
+ if (pRAInfo->TOTAL != 0) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+ ("macid =%d Total =%d R0 =%d R1 =%d R2 =%d R3 =%d R4 =%d D0 =%d valid0 =%x valid1 =%x\n",
+ MacId, pRAInfo->TOTAL,
+ pRAInfo->RTY[0], pRAInfo->RTY[1],
+ pRAInfo->RTY[2], pRAInfo->RTY[3],
+ pRAInfo->RTY[4], pRAInfo->DROP,
+ macid_entry0 , macid_entry1));
+ if (pRAInfo->PTActive) {
+ if (pRAInfo->RAstage < 5)
+ odm_RateDecision_8188E(dm_odm, pRAInfo);
+ else if (pRAInfo->RAstage == 5) /* Power training try state */
+ odm_PTTryState_8188E(pRAInfo);
+ else /* RAstage == 6 */
+ odm_PTDecision_8188E(pRAInfo);
+
+ /* Stage_RA counter */
+ if (pRAInfo->RAstage <= 5)
+ pRAInfo->RAstage++;
+ else
+ pRAInfo->RAstage = 0;
+ } else {
+ odm_RateDecision_8188E(dm_odm, pRAInfo);
+ }
+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+ ("macid =%d R0 =%d R1 =%d R2 =%d R3 =%d R4 =%d drop =%d valid0 =%x RateID =%d SGI =%d\n",
+ MacId,
+ pRAInfo->RTY[0],
+ pRAInfo->RTY[1],
+ pRAInfo->RTY[2],
+ pRAInfo->RTY[3],
+ pRAInfo->RTY[4],
+ pRAInfo->DROP,
+ macid_entry0,
+ pRAInfo->DecisionRate,
+ pRAInfo->RateSGI));
+ } else {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, (" TOTAL = 0!!!!\n"));
+ }
+ }
+
+ if (minRptTime > pRAInfo->RptTime)
+ minRptTime = pRAInfo->RptTime;
+
+ pBuffer += TX_RPT2_ITEM_SIZE;
+ MacId++;
+ } while (MacId < ItemNum);
+
+ odm_RATxRPTTimerSetting(dm_odm, minRptTime);
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("<===== ODM_RA_TxRPT2Handle_8188E()\n"));
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalHWImg8188E_BB.c b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_BB.c
new file mode 100644
index 00000000000..787e8f1f97f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_BB.c
@@ -0,0 +1,721 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+*
+*
+******************************************************************************/
+
+#include "odm_precomp.h"
+
+#include <rtw_iol.h>
+
+#define read_next_pair(array, v1, v2, i) \
+ do { \
+ i += 2; \
+ v1 = array[i]; \
+ v2 = array[i+1]; \
+ } while (0)
+
+static bool CheckCondition(const u32 condition, const u32 hex)
+{
+ u32 _board = (hex & 0x000000FF);
+ u32 _interface = (hex & 0x0000FF00) >> 8;
+ u32 _platform = (hex & 0x00FF0000) >> 16;
+ u32 cond = condition;
+
+ if (condition == 0xCDCDCDCD)
+ return true;
+
+ cond = condition & 0x000000FF;
+ if ((_board == cond) && cond != 0x00)
+ return false;
+
+ cond = condition & 0x0000FF00;
+ cond = cond >> 8;
+ if ((_interface & cond) == 0 && cond != 0x07)
+ return false;
+
+ cond = condition & 0x00FF0000;
+ cond = cond >> 16;
+ if ((_platform & cond) == 0 && cond != 0x0F)
+ return false;
+ return true;
+}
+
+
+/******************************************************************************
+* AGC_TAB_1T.TXT
+******************************************************************************/
+
+static u32 array_agc_tab_1t_8188e[] = {
+ 0xC78, 0xFB000001,
+ 0xC78, 0xFB010001,
+ 0xC78, 0xFB020001,
+ 0xC78, 0xFB030001,
+ 0xC78, 0xFB040001,
+ 0xC78, 0xFB050001,
+ 0xC78, 0xFA060001,
+ 0xC78, 0xF9070001,
+ 0xC78, 0xF8080001,
+ 0xC78, 0xF7090001,
+ 0xC78, 0xF60A0001,
+ 0xC78, 0xF50B0001,
+ 0xC78, 0xF40C0001,
+ 0xC78, 0xF30D0001,
+ 0xC78, 0xF20E0001,
+ 0xC78, 0xF10F0001,
+ 0xC78, 0xF0100001,
+ 0xC78, 0xEF110001,
+ 0xC78, 0xEE120001,
+ 0xC78, 0xED130001,
+ 0xC78, 0xEC140001,
+ 0xC78, 0xEB150001,
+ 0xC78, 0xEA160001,
+ 0xC78, 0xE9170001,
+ 0xC78, 0xE8180001,
+ 0xC78, 0xE7190001,
+ 0xC78, 0xE61A0001,
+ 0xC78, 0xE51B0001,
+ 0xC78, 0xE41C0001,
+ 0xC78, 0xE31D0001,
+ 0xC78, 0xE21E0001,
+ 0xC78, 0xE11F0001,
+ 0xC78, 0x8A200001,
+ 0xC78, 0x89210001,
+ 0xC78, 0x88220001,
+ 0xC78, 0x87230001,
+ 0xC78, 0x86240001,
+ 0xC78, 0x85250001,
+ 0xC78, 0x84260001,
+ 0xC78, 0x83270001,
+ 0xC78, 0x82280001,
+ 0xC78, 0x6B290001,
+ 0xC78, 0x6A2A0001,
+ 0xC78, 0x692B0001,
+ 0xC78, 0x682C0001,
+ 0xC78, 0x672D0001,
+ 0xC78, 0x662E0001,
+ 0xC78, 0x652F0001,
+ 0xC78, 0x64300001,
+ 0xC78, 0x63310001,
+ 0xC78, 0x62320001,
+ 0xC78, 0x61330001,
+ 0xC78, 0x46340001,
+ 0xC78, 0x45350001,
+ 0xC78, 0x44360001,
+ 0xC78, 0x43370001,
+ 0xC78, 0x42380001,
+ 0xC78, 0x41390001,
+ 0xC78, 0x403A0001,
+ 0xC78, 0x403B0001,
+ 0xC78, 0x403C0001,
+ 0xC78, 0x403D0001,
+ 0xC78, 0x403E0001,
+ 0xC78, 0x403F0001,
+ 0xC78, 0xFB400001,
+ 0xC78, 0xFB410001,
+ 0xC78, 0xFB420001,
+ 0xC78, 0xFB430001,
+ 0xC78, 0xFB440001,
+ 0xC78, 0xFB450001,
+ 0xC78, 0xFB460001,
+ 0xC78, 0xFB470001,
+ 0xC78, 0xFB480001,
+ 0xC78, 0xFA490001,
+ 0xC78, 0xF94A0001,
+ 0xC78, 0xF84B0001,
+ 0xC78, 0xF74C0001,
+ 0xC78, 0xF64D0001,
+ 0xC78, 0xF54E0001,
+ 0xC78, 0xF44F0001,
+ 0xC78, 0xF3500001,
+ 0xC78, 0xF2510001,
+ 0xC78, 0xF1520001,
+ 0xC78, 0xF0530001,
+ 0xC78, 0xEF540001,
+ 0xC78, 0xEE550001,
+ 0xC78, 0xED560001,
+ 0xC78, 0xEC570001,
+ 0xC78, 0xEB580001,
+ 0xC78, 0xEA590001,
+ 0xC78, 0xE95A0001,
+ 0xC78, 0xE85B0001,
+ 0xC78, 0xE75C0001,
+ 0xC78, 0xE65D0001,
+ 0xC78, 0xE55E0001,
+ 0xC78, 0xE45F0001,
+ 0xC78, 0xE3600001,
+ 0xC78, 0xE2610001,
+ 0xC78, 0xC3620001,
+ 0xC78, 0xC2630001,
+ 0xC78, 0xC1640001,
+ 0xC78, 0x8B650001,
+ 0xC78, 0x8A660001,
+ 0xC78, 0x89670001,
+ 0xC78, 0x88680001,
+ 0xC78, 0x87690001,
+ 0xC78, 0x866A0001,
+ 0xC78, 0x856B0001,
+ 0xC78, 0x846C0001,
+ 0xC78, 0x676D0001,
+ 0xC78, 0x666E0001,
+ 0xC78, 0x656F0001,
+ 0xC78, 0x64700001,
+ 0xC78, 0x63710001,
+ 0xC78, 0x62720001,
+ 0xC78, 0x61730001,
+ 0xC78, 0x60740001,
+ 0xC78, 0x46750001,
+ 0xC78, 0x45760001,
+ 0xC78, 0x44770001,
+ 0xC78, 0x43780001,
+ 0xC78, 0x42790001,
+ 0xC78, 0x417A0001,
+ 0xC78, 0x407B0001,
+ 0xC78, 0x407C0001,
+ 0xC78, 0x407D0001,
+ 0xC78, 0x407E0001,
+ 0xC78, 0x407F0001,
+};
+
+enum HAL_STATUS ODM_ReadAndConfig_AGC_TAB_1T_8188E(struct odm_dm_struct *dm_odm)
+{
+ u32 hex = 0;
+ u32 i = 0;
+ u8 platform = dm_odm->SupportPlatform;
+ u8 interfaceValue = dm_odm->SupportInterface;
+ u8 board = dm_odm->BoardType;
+ u32 arraylen = sizeof(array_agc_tab_1t_8188e)/sizeof(u32);
+ u32 *array = array_agc_tab_1t_8188e;
+ bool biol = false;
+ struct adapter *adapter = dm_odm->Adapter;
+ struct xmit_frame *pxmit_frame = NULL;
+ u8 bndy_cnt = 1;
+ enum HAL_STATUS rst = HAL_STATUS_SUCCESS;
+
+ hex += board;
+ hex += interfaceValue << 8;
+ hex += platform << 16;
+ hex += 0xFF000000;
+ biol = rtw_IOL_applied(adapter);
+
+ if (biol) {
+ pxmit_frame = rtw_IOL_accquire_xmit_frame(adapter);
+ if (pxmit_frame == NULL) {
+ pr_info("rtw_IOL_accquire_xmit_frame failed\n");
+ return HAL_STATUS_FAILURE;
+ }
+ }
+
+ for (i = 0; i < arraylen; i += 2) {
+ u32 v1 = array[i];
+ u32 v2 = array[i+1];
+
+ /* This (offset, data) pair meets the condition. */
+ if (v1 < 0xCDCDCDCD) {
+ if (biol) {
+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+ bndy_cnt++;
+ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord);
+ } else {
+ odm_ConfigBB_AGC_8188E(dm_odm, v1, bMaskDWord, v2);
+ }
+ continue;
+ } else {
+ /* This line is the start line of branch. */
+ if (!CheckCondition(array[i], hex)) {
+ /* Discard the following (offset, data) pairs. */
+ read_next_pair(array, v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2)
+ read_next_pair(array, v1, v2, i);
+ i -= 2; /* prevent from for-loop += 2 */
+ } else { /* Configure matched pairs and skip to end of if-else. */
+ read_next_pair(array, v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2) {
+ if (biol) {
+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+ bndy_cnt++;
+ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord);
+ } else {
+ odm_ConfigBB_AGC_8188E(dm_odm, v1, bMaskDWord, v2);
+ }
+ read_next_pair(array, v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < arraylen - 2)
+ read_next_pair(array, v1, v2, i);
+ }
+ }
+ }
+ if (biol) {
+ if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) {
+ printk("~~~ %s IOL_exec_cmds Failed !!!\n", __func__);
+ rst = HAL_STATUS_FAILURE;
+ }
+ }
+ return rst;
+}
+
+/******************************************************************************
+* PHY_REG_1T.TXT
+******************************************************************************/
+
+static u32 array_phy_reg_1t_8188e[] = {
+ 0x800, 0x80040000,
+ 0x804, 0x00000003,
+ 0x808, 0x0000FC00,
+ 0x80C, 0x0000000A,
+ 0x810, 0x10001331,
+ 0x814, 0x020C3D10,
+ 0x818, 0x02200385,
+ 0x81C, 0x00000000,
+ 0x820, 0x01000100,
+ 0x824, 0x00390204,
+ 0x828, 0x00000000,
+ 0x82C, 0x00000000,
+ 0x830, 0x00000000,
+ 0x834, 0x00000000,
+ 0x838, 0x00000000,
+ 0x83C, 0x00000000,
+ 0x840, 0x00010000,
+ 0x844, 0x00000000,
+ 0x848, 0x00000000,
+ 0x84C, 0x00000000,
+ 0x850, 0x00000000,
+ 0x854, 0x00000000,
+ 0x858, 0x569A11A9,
+ 0x85C, 0x01000014,
+ 0x860, 0x66F60110,
+ 0x864, 0x061F0649,
+ 0x868, 0x00000000,
+ 0x86C, 0x27272700,
+ 0x870, 0x07000760,
+ 0x874, 0x25004000,
+ 0x878, 0x00000808,
+ 0x87C, 0x00000000,
+ 0x880, 0xB0000C1C,
+ 0x884, 0x00000001,
+ 0x888, 0x00000000,
+ 0x88C, 0xCCC000C0,
+ 0x890, 0x00000800,
+ 0x894, 0xFFFFFFFE,
+ 0x898, 0x40302010,
+ 0x89C, 0x00706050,
+ 0x900, 0x00000000,
+ 0x904, 0x00000023,
+ 0x908, 0x00000000,
+ 0x90C, 0x81121111,
+ 0x910, 0x00000002,
+ 0x914, 0x00000201,
+ 0xA00, 0x00D047C8,
+ 0xA04, 0x80FF000C,
+ 0xA08, 0x8C838300,
+ 0xA0C, 0x2E7F120F,
+ 0xA10, 0x9500BB78,
+ 0xA14, 0x1114D028,
+ 0xA18, 0x00881117,
+ 0xA1C, 0x89140F00,
+ 0xA20, 0x1A1B0000,
+ 0xA24, 0x090E1317,
+ 0xA28, 0x00000204,
+ 0xA2C, 0x00D30000,
+ 0xA70, 0x101FBF00,
+ 0xA74, 0x00000007,
+ 0xA78, 0x00000900,
+ 0xA7C, 0x225B0606,
+ 0xA80, 0x218075B1,
+ 0xB2C, 0x80000000,
+ 0xC00, 0x48071D40,
+ 0xC04, 0x03A05611,
+ 0xC08, 0x000000E4,
+ 0xC0C, 0x6C6C6C6C,
+ 0xC10, 0x08800000,
+ 0xC14, 0x40000100,
+ 0xC18, 0x08800000,
+ 0xC1C, 0x40000100,
+ 0xC20, 0x00000000,
+ 0xC24, 0x00000000,
+ 0xC28, 0x00000000,
+ 0xC2C, 0x00000000,
+ 0xC30, 0x69E9AC47,
+ 0xC34, 0x469652AF,
+ 0xC38, 0x49795994,
+ 0xC3C, 0x0A97971C,
+ 0xC40, 0x1F7C403F,
+ 0xC44, 0x000100B7,
+ 0xC48, 0xEC020107,
+ 0xC4C, 0x007F037F,
+ 0xC50, 0x69553420,
+ 0xC54, 0x43BC0094,
+ 0xC58, 0x00013169,
+ 0xC5C, 0x00250492,
+ 0xC60, 0x00000000,
+ 0xC64, 0x7112848B,
+ 0xC68, 0x47C00BFF,
+ 0xC6C, 0x00000036,
+ 0xC70, 0x2C7F000D,
+ 0xC74, 0x020610DB,
+ 0xC78, 0x0000001F,
+ 0xC7C, 0x00B91612,
+ 0xC80, 0x390000E4,
+ 0xC84, 0x20F60000,
+ 0xC88, 0x40000100,
+ 0xC8C, 0x20200000,
+ 0xC90, 0x00091521,
+ 0xC94, 0x00000000,
+ 0xC98, 0x00121820,
+ 0xC9C, 0x00007F7F,
+ 0xCA0, 0x00000000,
+ 0xCA4, 0x000300A0,
+ 0xCA8, 0x00000000,
+ 0xCAC, 0x00000000,
+ 0xCB0, 0x00000000,
+ 0xCB4, 0x00000000,
+ 0xCB8, 0x00000000,
+ 0xCBC, 0x28000000,
+ 0xCC0, 0x00000000,
+ 0xCC4, 0x00000000,
+ 0xCC8, 0x00000000,
+ 0xCCC, 0x00000000,
+ 0xCD0, 0x00000000,
+ 0xCD4, 0x00000000,
+ 0xCD8, 0x64B22427,
+ 0xCDC, 0x00766932,
+ 0xCE0, 0x00222222,
+ 0xCE4, 0x00000000,
+ 0xCE8, 0x37644302,
+ 0xCEC, 0x2F97D40C,
+ 0xD00, 0x00000740,
+ 0xD04, 0x00020401,
+ 0xD08, 0x0000907F,
+ 0xD0C, 0x20010201,
+ 0xD10, 0xA0633333,
+ 0xD14, 0x3333BC43,
+ 0xD18, 0x7A8F5B6F,
+ 0xD2C, 0xCC979975,
+ 0xD30, 0x00000000,
+ 0xD34, 0x80608000,
+ 0xD38, 0x00000000,
+ 0xD3C, 0x00127353,
+ 0xD40, 0x00000000,
+ 0xD44, 0x00000000,
+ 0xD48, 0x00000000,
+ 0xD4C, 0x00000000,
+ 0xD50, 0x6437140A,
+ 0xD54, 0x00000000,
+ 0xD58, 0x00000282,
+ 0xD5C, 0x30032064,
+ 0xD60, 0x4653DE68,
+ 0xD64, 0x04518A3C,
+ 0xD68, 0x00002101,
+ 0xD6C, 0x2A201C16,
+ 0xD70, 0x1812362E,
+ 0xD74, 0x322C2220,
+ 0xD78, 0x000E3C24,
+ 0xE00, 0x2D2D2D2D,
+ 0xE04, 0x2D2D2D2D,
+ 0xE08, 0x0390272D,
+ 0xE10, 0x2D2D2D2D,
+ 0xE14, 0x2D2D2D2D,
+ 0xE18, 0x2D2D2D2D,
+ 0xE1C, 0x2D2D2D2D,
+ 0xE28, 0x00000000,
+ 0xE30, 0x1000DC1F,
+ 0xE34, 0x10008C1F,
+ 0xE38, 0x02140102,
+ 0xE3C, 0x681604C2,
+ 0xE40, 0x01007C00,
+ 0xE44, 0x01004800,
+ 0xE48, 0xFB000000,
+ 0xE4C, 0x000028D1,
+ 0xE50, 0x1000DC1F,
+ 0xE54, 0x10008C1F,
+ 0xE58, 0x02140102,
+ 0xE5C, 0x28160D05,
+ 0xE60, 0x00000008,
+ 0xE68, 0x001B25A4,
+ 0xE6C, 0x00C00014,
+ 0xE70, 0x00C00014,
+ 0xE74, 0x01000014,
+ 0xE78, 0x01000014,
+ 0xE7C, 0x01000014,
+ 0xE80, 0x01000014,
+ 0xE84, 0x00C00014,
+ 0xE88, 0x01000014,
+ 0xE8C, 0x00C00014,
+ 0xED0, 0x00C00014,
+ 0xED4, 0x00C00014,
+ 0xED8, 0x00C00014,
+ 0xEDC, 0x00000014,
+ 0xEE0, 0x00000014,
+ 0xEEC, 0x01C00014,
+ 0xF14, 0x00000003,
+ 0xF4C, 0x00000000,
+ 0xF00, 0x00000300,
+};
+
+enum HAL_STATUS ODM_ReadAndConfig_PHY_REG_1T_8188E(struct odm_dm_struct *dm_odm)
+{
+ u32 hex = 0;
+ u32 i = 0;
+ u8 platform = dm_odm->SupportPlatform;
+ u8 interfaceValue = dm_odm->SupportInterface;
+ u8 board = dm_odm->BoardType;
+ u32 arraylen = sizeof(array_phy_reg_1t_8188e)/sizeof(u32);
+ u32 *array = array_phy_reg_1t_8188e;
+ bool biol = false;
+ struct adapter *adapter = dm_odm->Adapter;
+ struct xmit_frame *pxmit_frame = NULL;
+ u8 bndy_cnt = 1;
+ enum HAL_STATUS rst = HAL_STATUS_SUCCESS;
+ hex += board;
+ hex += interfaceValue << 8;
+ hex += platform << 16;
+ hex += 0xFF000000;
+ biol = rtw_IOL_applied(adapter);
+
+ if (biol) {
+ pxmit_frame = rtw_IOL_accquire_xmit_frame(adapter);
+ if (pxmit_frame == NULL) {
+ pr_info("rtw_IOL_accquire_xmit_frame failed\n");
+ return HAL_STATUS_FAILURE;
+ }
+ }
+
+ for (i = 0; i < arraylen; i += 2) {
+ u32 v1 = array[i];
+ u32 v2 = array[i+1];
+
+ /* This (offset, data) pair meets the condition. */
+ if (v1 < 0xCDCDCDCD) {
+ if (biol) {
+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+ bndy_cnt++;
+ if (v1 == 0xfe) {
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50);
+ } else if (v1 == 0xfd) {
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5);
+ } else if (v1 == 0xfc) {
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1);
+ } else if (v1 == 0xfb) {
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50);
+ } else if (v1 == 0xfa) {
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5);
+ } else if (v1 == 0xf9) {
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1);
+ } else {
+ if (v1 == 0xa24)
+ dm_odm->RFCalibrateInfo.RegA24 = v2;
+ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord);
+ }
+ } else {
+ odm_ConfigBB_PHY_8188E(dm_odm, v1, bMaskDWord, v2);
+ }
+ continue;
+ } else { /* This line is the start line of branch. */
+ if (!CheckCondition(array[i], hex)) {
+ /* Discard the following (offset, data) pairs. */
+ read_next_pair(array, v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2)
+ read_next_pair(array, v1, v2, i);
+ i -= 2; /* prevent from for-loop += 2 */
+ } else { /* Configure matched pairs and skip to end of if-else. */
+ read_next_pair(array, v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2) {
+ if (biol) {
+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+ bndy_cnt++;
+ if (v1 == 0xfe) {
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50);
+ } else if (v1 == 0xfd) {
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5);
+ } else if (v1 == 0xfc) {
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1);
+ } else if (v1 == 0xfb) {
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50);
+ } else if (v1 == 0xfa) {
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5);
+ } else if (v1 == 0xf9) {
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1);
+ } else{
+ if (v1 == 0xa24)
+ dm_odm->RFCalibrateInfo.RegA24 = v2;
+
+ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord);
+ }
+ } else {
+ odm_ConfigBB_PHY_8188E(dm_odm, v1, bMaskDWord, v2);
+ }
+ read_next_pair(array, v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < arraylen - 2)
+ read_next_pair(array, v1, v2, i);
+ }
+ }
+ }
+ if (biol) {
+ if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) {
+ rst = HAL_STATUS_FAILURE;
+ pr_info("~~~ IOL Config %s Failed !!!\n", __func__);
+ }
+ }
+ return rst;
+}
+
+/******************************************************************************
+* PHY_REG_PG.TXT
+******************************************************************************/
+
+static u32 array_phy_reg_pg_8188e[] = {
+ 0xE00, 0xFFFFFFFF, 0x06070809,
+ 0xE04, 0xFFFFFFFF, 0x02020405,
+ 0xE08, 0x0000FF00, 0x00000006,
+ 0x86C, 0xFFFFFF00, 0x00020400,
+ 0xE10, 0xFFFFFFFF, 0x08090A0B,
+ 0xE14, 0xFFFFFFFF, 0x01030607,
+ 0xE18, 0xFFFFFFFF, 0x08090A0B,
+ 0xE1C, 0xFFFFFFFF, 0x01030607,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x02020202,
+ 0xE04, 0xFFFFFFFF, 0x00020202,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x04040404,
+ 0xE14, 0xFFFFFFFF, 0x00020404,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x02020202,
+ 0xE04, 0xFFFFFFFF, 0x00020202,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x04040404,
+ 0xE14, 0xFFFFFFFF, 0x00020404,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x02020202,
+ 0xE04, 0xFFFFFFFF, 0x00020202,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x04040404,
+ 0xE14, 0xFFFFFFFF, 0x00020404,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+
+};
+
+void ODM_ReadAndConfig_PHY_REG_PG_8188E(struct odm_dm_struct *dm_odm)
+{
+ u32 hex;
+ u32 i = 0;
+ u8 platform = dm_odm->SupportPlatform;
+ u8 interfaceValue = dm_odm->SupportInterface;
+ u8 board = dm_odm->BoardType;
+ u32 arraylen = sizeof(array_phy_reg_pg_8188e) / sizeof(u32);
+ u32 *array = array_phy_reg_pg_8188e;
+
+ hex = board + (interfaceValue << 8);
+ hex += (platform << 16) + 0xFF000000;
+
+ for (i = 0; i < arraylen; i += 3) {
+ u32 v1 = array[i];
+ u32 v2 = array[i+1];
+ u32 v3 = array[i+2];
+
+ /* this line is a line of pure_body */
+ if (v1 < 0xCDCDCDCD) {
+ odm_ConfigBB_PHY_REG_PG_8188E(dm_odm, v1, v2, v3);
+ continue;
+ } else { /* this line is the start of branch */
+ if (!CheckCondition(array[i], hex)) {
+ /* don't need the hw_body */
+ i += 2; /* skip the pair of expression */
+ v1 = array[i];
+ v2 = array[i+1];
+ v3 = array[i+2];
+ while (v2 != 0xDEAD) {
+ i += 3;
+ v1 = array[i];
+ v2 = array[i+1];
+ v3 = array[i+1];
+ }
+ }
+ }
+ }
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalHWImg8188E_MAC.c b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_MAC.c
new file mode 100644
index 00000000000..b49b5ab48b1
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_MAC.c
@@ -0,0 +1,231 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+*
+*
+******************************************************************************/
+
+#include "odm_precomp.h"
+#include <rtw_iol.h>
+
+static bool Checkcondition(const u32 condition, const u32 hex)
+{
+ u32 _board = (hex & 0x000000FF);
+ u32 _interface = (hex & 0x0000FF00) >> 8;
+ u32 _platform = (hex & 0x00FF0000) >> 16;
+ u32 cond = condition;
+
+ if (condition == 0xCDCDCDCD)
+ return true;
+
+ cond = condition & 0x000000FF;
+ if ((_board == cond) && cond != 0x00)
+ return false;
+
+ cond = condition & 0x0000FF00;
+ cond = cond >> 8;
+ if ((_interface & cond) == 0 && cond != 0x07)
+ return false;
+
+ cond = condition & 0x00FF0000;
+ cond = cond >> 16;
+ if ((_platform & cond) == 0 && cond != 0x0F)
+ return false;
+ return true;
+}
+
+
+/******************************************************************************
+* MAC_REG.TXT
+******************************************************************************/
+
+static u32 array_MAC_REG_8188E[] = {
+ 0x026, 0x00000041,
+ 0x027, 0x00000035,
+ 0x428, 0x0000000A,
+ 0x429, 0x00000010,
+ 0x430, 0x00000000,
+ 0x431, 0x00000001,
+ 0x432, 0x00000002,
+ 0x433, 0x00000004,
+ 0x434, 0x00000005,
+ 0x435, 0x00000006,
+ 0x436, 0x00000007,
+ 0x437, 0x00000008,
+ 0x438, 0x00000000,
+ 0x439, 0x00000000,
+ 0x43A, 0x00000001,
+ 0x43B, 0x00000002,
+ 0x43C, 0x00000004,
+ 0x43D, 0x00000005,
+ 0x43E, 0x00000006,
+ 0x43F, 0x00000007,
+ 0x440, 0x0000005D,
+ 0x441, 0x00000001,
+ 0x442, 0x00000000,
+ 0x444, 0x00000015,
+ 0x445, 0x000000F0,
+ 0x446, 0x0000000F,
+ 0x447, 0x00000000,
+ 0x458, 0x00000041,
+ 0x459, 0x000000A8,
+ 0x45A, 0x00000072,
+ 0x45B, 0x000000B9,
+ 0x460, 0x00000066,
+ 0x461, 0x00000066,
+ 0x480, 0x00000008,
+ 0x4C8, 0x000000FF,
+ 0x4C9, 0x00000008,
+ 0x4CC, 0x000000FF,
+ 0x4CD, 0x000000FF,
+ 0x4CE, 0x00000001,
+ 0x4D3, 0x00000001,
+ 0x500, 0x00000026,
+ 0x501, 0x000000A2,
+ 0x502, 0x0000002F,
+ 0x503, 0x00000000,
+ 0x504, 0x00000028,
+ 0x505, 0x000000A3,
+ 0x506, 0x0000005E,
+ 0x507, 0x00000000,
+ 0x508, 0x0000002B,
+ 0x509, 0x000000A4,
+ 0x50A, 0x0000005E,
+ 0x50B, 0x00000000,
+ 0x50C, 0x0000004F,
+ 0x50D, 0x000000A4,
+ 0x50E, 0x00000000,
+ 0x50F, 0x00000000,
+ 0x512, 0x0000001C,
+ 0x514, 0x0000000A,
+ 0x516, 0x0000000A,
+ 0x525, 0x0000004F,
+ 0x550, 0x00000010,
+ 0x551, 0x00000010,
+ 0x559, 0x00000002,
+ 0x55D, 0x000000FF,
+ 0x605, 0x00000030,
+ 0x608, 0x0000000E,
+ 0x609, 0x0000002A,
+ 0x620, 0x000000FF,
+ 0x621, 0x000000FF,
+ 0x622, 0x000000FF,
+ 0x623, 0x000000FF,
+ 0x624, 0x000000FF,
+ 0x625, 0x000000FF,
+ 0x626, 0x000000FF,
+ 0x627, 0x000000FF,
+ 0x652, 0x00000020,
+ 0x63C, 0x0000000A,
+ 0x63D, 0x0000000A,
+ 0x63E, 0x0000000E,
+ 0x63F, 0x0000000E,
+ 0x640, 0x00000040,
+ 0x66E, 0x00000005,
+ 0x700, 0x00000021,
+ 0x701, 0x00000043,
+ 0x702, 0x00000065,
+ 0x703, 0x00000087,
+ 0x708, 0x00000021,
+ 0x709, 0x00000043,
+ 0x70A, 0x00000065,
+ 0x70B, 0x00000087,
+};
+
+enum HAL_STATUS ODM_ReadAndConfig_MAC_REG_8188E(struct odm_dm_struct *dm_odm)
+{
+ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = array[i]; v2 = array[i+1]; } while (0)
+
+ u32 hex = 0;
+ u32 i;
+ u8 platform = dm_odm->SupportPlatform;
+ u8 interface_val = dm_odm->SupportInterface;
+ u8 board = dm_odm->BoardType;
+ u32 array_len = sizeof(array_MAC_REG_8188E)/sizeof(u32);
+ u32 *array = array_MAC_REG_8188E;
+ bool biol = false;
+
+ struct adapter *adapt = dm_odm->Adapter;
+ struct xmit_frame *pxmit_frame = NULL;
+ u8 bndy_cnt = 1;
+ enum HAL_STATUS rst = HAL_STATUS_SUCCESS;
+ hex += board;
+ hex += interface_val << 8;
+ hex += platform << 16;
+ hex += 0xFF000000;
+
+ biol = rtw_IOL_applied(adapt);
+
+ if (biol) {
+ pxmit_frame = rtw_IOL_accquire_xmit_frame(adapt);
+ if (pxmit_frame == NULL) {
+ pr_info("rtw_IOL_accquire_xmit_frame failed\n");
+ return HAL_STATUS_FAILURE;
+ }
+ }
+
+ for (i = 0; i < array_len; i += 2) {
+ u32 v1 = array[i];
+ u32 v2 = array[i+1];
+
+ /* This (offset, data) pair meets the condition. */
+ if (v1 < 0xCDCDCDCD) {
+ if (biol) {
+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+ bndy_cnt++;
+ rtw_IOL_append_WB_cmd(pxmit_frame, (u16)v1, (u8)v2, 0xFF);
+ } else {
+ odm_ConfigMAC_8188E(dm_odm, v1, (u8)v2);
+ }
+ continue;
+ } else { /* This line is the start line of branch. */
+ if (!Checkcondition(array[i], hex)) {
+ /* Discard the following (offset, data) pairs. */
+ READ_NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < array_len - 2) {
+ READ_NEXT_PAIR(v1, v2, i);
+ }
+ i -= 2; /* prevent from for-loop += 2 */
+ } else { /* Configure matched pairs and skip to end of if-else. */
+ READ_NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < array_len - 2) {
+ if (biol) {
+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+ bndy_cnt++;
+ rtw_IOL_append_WB_cmd(pxmit_frame, (u16)v1, (u8)v2, 0xFF);
+ } else {
+ odm_ConfigMAC_8188E(dm_odm, v1, (u8)v2);
+ }
+
+ READ_NEXT_PAIR(v1, v2, i);
+ }
+ while (v2 != 0xDEAD && i < array_len - 2)
+ READ_NEXT_PAIR(v1, v2, i);
+ }
+ }
+ }
+ if (biol) {
+ if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) {
+ pr_info("~~~ MAC IOL_exec_cmds Failed !!!\n");
+ rst = HAL_STATUS_FAILURE;
+ }
+ }
+ return rst;
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalHWImg8188E_RF.c b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_RF.c
new file mode 100644
index 00000000000..480c810c446
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_RF.c
@@ -0,0 +1,269 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+*
+*
+******************************************************************************/
+
+#include "odm_precomp.h"
+
+#include <rtw_iol.h>
+
+static bool CheckCondition(const u32 Condition, const u32 Hex)
+{
+ u32 _board = (Hex & 0x000000FF);
+ u32 _interface = (Hex & 0x0000FF00) >> 8;
+ u32 _platform = (Hex & 0x00FF0000) >> 16;
+ u32 cond = Condition;
+
+ if (Condition == 0xCDCDCDCD)
+ return true;
+
+ cond = Condition & 0x000000FF;
+ if ((_board == cond) && cond != 0x00)
+ return false;
+
+ cond = Condition & 0x0000FF00;
+ cond = cond >> 8;
+ if ((_interface & cond) == 0 && cond != 0x07)
+ return false;
+
+ cond = Condition & 0x00FF0000;
+ cond = cond >> 16;
+ if ((_platform & cond) == 0 && cond != 0x0F)
+ return false;
+ return true;
+}
+
+
+/******************************************************************************
+* RadioA_1T.TXT
+******************************************************************************/
+
+static u32 Array_RadioA_1T_8188E[] = {
+ 0x000, 0x00030000,
+ 0x008, 0x00084000,
+ 0x018, 0x00000407,
+ 0x019, 0x00000012,
+ 0x01E, 0x00080009,
+ 0x01F, 0x00000880,
+ 0x02F, 0x0001A060,
+ 0x03F, 0x00000000,
+ 0x042, 0x000060C0,
+ 0x057, 0x000D0000,
+ 0x058, 0x000BE180,
+ 0x067, 0x00001552,
+ 0x083, 0x00000000,
+ 0x0B0, 0x000FF8FC,
+ 0x0B1, 0x00054400,
+ 0x0B2, 0x000CCC19,
+ 0x0B4, 0x00043003,
+ 0x0B6, 0x0004953E,
+ 0x0B7, 0x0001C718,
+ 0x0B8, 0x000060FF,
+ 0x0B9, 0x00080001,
+ 0x0BA, 0x00040000,
+ 0x0BB, 0x00000400,
+ 0x0BF, 0x000C0000,
+ 0x0C2, 0x00002400,
+ 0x0C3, 0x00000009,
+ 0x0C4, 0x00040C91,
+ 0x0C5, 0x00099999,
+ 0x0C6, 0x000000A3,
+ 0x0C7, 0x00088820,
+ 0x0C8, 0x00076C06,
+ 0x0C9, 0x00000000,
+ 0x0CA, 0x00080000,
+ 0x0DF, 0x00000180,
+ 0x0EF, 0x000001A0,
+ 0x051, 0x0006B27D,
+ 0xFF0F041F, 0xABCD,
+ 0x052, 0x0007E4DD,
+ 0xCDCDCDCD, 0xCDCD,
+ 0x052, 0x0007E49D,
+ 0xFF0F041F, 0xDEAD,
+ 0x053, 0x00000073,
+ 0x056, 0x00051FF3,
+ 0x035, 0x00000086,
+ 0x035, 0x00000186,
+ 0x035, 0x00000286,
+ 0x036, 0x00001C25,
+ 0x036, 0x00009C25,
+ 0x036, 0x00011C25,
+ 0x036, 0x00019C25,
+ 0x0B6, 0x00048538,
+ 0x018, 0x00000C07,
+ 0x05A, 0x0004BD00,
+ 0x019, 0x000739D0,
+ 0x034, 0x0000ADF3,
+ 0x034, 0x00009DF0,
+ 0x034, 0x00008DED,
+ 0x034, 0x00007DEA,
+ 0x034, 0x00006DE7,
+ 0x034, 0x000054EE,
+ 0x034, 0x000044EB,
+ 0x034, 0x000034E8,
+ 0x034, 0x0000246B,
+ 0x034, 0x00001468,
+ 0x034, 0x0000006D,
+ 0x000, 0x00030159,
+ 0x084, 0x00068200,
+ 0x086, 0x000000CE,
+ 0x087, 0x00048A00,
+ 0x08E, 0x00065540,
+ 0x08F, 0x00088000,
+ 0x0EF, 0x000020A0,
+ 0x03B, 0x000F02B0,
+ 0x03B, 0x000EF7B0,
+ 0x03B, 0x000D4FB0,
+ 0x03B, 0x000CF060,
+ 0x03B, 0x000B0090,
+ 0x03B, 0x000A0080,
+ 0x03B, 0x00090080,
+ 0x03B, 0x0008F780,
+ 0x03B, 0x000722B0,
+ 0x03B, 0x0006F7B0,
+ 0x03B, 0x00054FB0,
+ 0x03B, 0x0004F060,
+ 0x03B, 0x00030090,
+ 0x03B, 0x00020080,
+ 0x03B, 0x00010080,
+ 0x03B, 0x0000F780,
+ 0x0EF, 0x000000A0,
+ 0x000, 0x00010159,
+ 0x018, 0x0000F407,
+ 0xFFE, 0x00000000,
+ 0xFFE, 0x00000000,
+ 0x01F, 0x00080003,
+ 0xFFE, 0x00000000,
+ 0xFFE, 0x00000000,
+ 0x01E, 0x00000001,
+ 0x01F, 0x00080000,
+ 0x000, 0x00033E60,
+};
+
+enum HAL_STATUS ODM_ReadAndConfig_RadioA_1T_8188E(struct odm_dm_struct *pDM_Odm)
+{
+ #define READ_NEXT_PAIR(v1, v2, i) do \
+ { i += 2; v1 = Array[i]; \
+ v2 = Array[i+1]; } while (0)
+
+ u32 hex = 0;
+ u32 i = 0;
+ u8 platform = pDM_Odm->SupportPlatform;
+ u8 interfaceValue = pDM_Odm->SupportInterface;
+ u8 board = pDM_Odm->BoardType;
+ u32 ArrayLen = sizeof(Array_RadioA_1T_8188E)/sizeof(u32);
+ u32 *Array = Array_RadioA_1T_8188E;
+ bool biol = false;
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ struct xmit_frame *pxmit_frame = NULL;
+ u8 bndy_cnt = 1;
+ enum HAL_STATUS rst = HAL_STATUS_SUCCESS;
+
+ hex += board;
+ hex += interfaceValue << 8;
+ hex += platform << 16;
+ hex += 0xFF000000;
+ biol = rtw_IOL_applied(Adapter);
+
+ if (biol) {
+ pxmit_frame = rtw_IOL_accquire_xmit_frame(Adapter);
+ if (pxmit_frame == NULL) {
+ pr_info("rtw_IOL_accquire_xmit_frame failed\n");
+ return HAL_STATUS_FAILURE;
+ }
+ }
+
+ for (i = 0; i < ArrayLen; i += 2) {
+ u32 v1 = Array[i];
+ u32 v2 = Array[i+1];
+
+ /* This (offset, data) pair meets the condition. */
+ if (v1 < 0xCDCDCDCD) {
+ if (biol) {
+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+ bndy_cnt++;
+
+ if (v1 == 0xffe)
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50);
+ else if (v1 == 0xfd)
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5);
+ else if (v1 == 0xfc)
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1);
+ else if (v1 == 0xfb)
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50);
+ else if (v1 == 0xfa)
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5);
+ else if (v1 == 0xf9)
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1);
+ else
+ rtw_IOL_append_WRF_cmd(pxmit_frame, ODM_RF_PATH_A, (u16)v1, v2, bRFRegOffsetMask);
+ } else {
+ odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2);
+ }
+ continue;
+ } else { /* This line is the start line of branch. */
+ if (!CheckCondition(Array[i], hex)) {
+ /* Discard the following (offset, data) pairs. */
+ READ_NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < ArrayLen - 2)
+ READ_NEXT_PAIR(v1, v2, i);
+ i -= 2; /* prevent from for-loop += 2 */
+ } else { /* Configure matched pairs and skip to end of if-else. */
+ READ_NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < ArrayLen - 2) {
+ if (biol) {
+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+ bndy_cnt++;
+
+ if (v1 == 0xffe)
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50);
+ else if (v1 == 0xfd)
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5);
+ else if (v1 == 0xfc)
+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1);
+ else if (v1 == 0xfb)
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50);
+ else if (v1 == 0xfa)
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5);
+ else if (v1 == 0xf9)
+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1);
+ else
+ rtw_IOL_append_WRF_cmd(pxmit_frame, ODM_RF_PATH_A, (u16)v1, v2, bRFRegOffsetMask);
+ } else {
+ odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2);
+ }
+ READ_NEXT_PAIR(v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < ArrayLen - 2)
+ READ_NEXT_PAIR(v1, v2, i);
+ }
+ }
+ }
+ if (biol) {
+ if (!rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) {
+ rst = HAL_STATUS_FAILURE;
+ pr_info("~~~ IOL Config %s Failed !!!\n", __func__);
+ }
+ }
+ return rst;
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalPhyRf.c b/drivers/staging/rtl8188eu/hal/HalPhyRf.c
new file mode 100644
index 00000000000..980f7da8ab3
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalPhyRf.c
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+ #include "odm_precomp.h"
+
+/* 3============================================================ */
+/* 3 IQ Calibration */
+/* 3============================================================ */
+
+void ODM_ResetIQKResult(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+u8 ODM_GetRightChnlPlaceforIQK(u8 chnl)
+{
+ u8 channel_all[ODM_TARGET_CHNL_NUM_2G_5G] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64,
+ 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122,
+ 124, 126, 128, 130, 132, 134, 136, 138, 140, 149, 151, 153,
+ 155, 157, 159, 161, 163, 165
+ };
+ u8 place = chnl;
+
+ if (chnl > 14) {
+ for (place = 14; place < sizeof(channel_all); place++) {
+ if (channel_all[place] == chnl)
+ return place-13;
+ }
+ }
+ return 0;
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c b/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c
new file mode 100644
index 00000000000..e4f20da91b4
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c
@@ -0,0 +1,1928 @@
+
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#include "odm_precomp.h"
+
+/*---------------------------Define Local Constant---------------------------*/
+/* 2010/04/25 MH Define the max tx power tracking tx agc power. */
+#define ODM_TXPWRTRACK_MAX_IDX_88E 6
+
+/*---------------------------Define Local Constant---------------------------*/
+
+/* 3============================================================ */
+/* 3 Tx Power Tracking */
+/* 3============================================================ */
+/*-----------------------------------------------------------------------------
+ * Function: ODM_TxPwrTrackAdjust88E()
+ *
+ * Overview: 88E we can not write 0xc80/c94/c4c/ 0xa2x. Instead of write TX agc.
+ * No matter OFDM & CCK use the same method.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 04/23/2012 MHC Create Version 0.
+ * 04/23/2012 MHC Adjust TX agc directly not throughput BB digital.
+ *
+ *---------------------------------------------------------------------------*/
+void ODM_TxPwrTrackAdjust88E(struct odm_dm_struct *dm_odm, u8 Type,/* 0 = OFDM, 1 = CCK */
+ u8 *pDirection, /* 1 = +(increase) 2 = -(decrease) */
+ u32 *pOutWriteVal /* Tx tracking CCK/OFDM BB swing index adjust */
+ )
+{
+ u8 pwr_value = 0;
+ /* Tx power tracking BB swing table. */
+ /* The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB */
+ if (Type == 0) { /* For OFDM afjust */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
+ ("BbSwingIdxOfdm = %d BbSwingFlagOfdm=%d\n",
+ dm_odm->BbSwingIdxOfdm, dm_odm->BbSwingFlagOfdm));
+
+ if (dm_odm->BbSwingIdxOfdm <= dm_odm->BbSwingIdxOfdmBase) {
+ *pDirection = 1;
+ pwr_value = (dm_odm->BbSwingIdxOfdmBase - dm_odm->BbSwingIdxOfdm);
+ } else {
+ *pDirection = 2;
+ pwr_value = (dm_odm->BbSwingIdxOfdm - dm_odm->BbSwingIdxOfdmBase);
+ }
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
+ ("BbSwingIdxOfdm = %d BbSwingFlagOfdm=%d\n",
+ dm_odm->BbSwingIdxOfdm, dm_odm->BbSwingFlagOfdm));
+ } else if (Type == 1) { /* For CCK adjust. */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
+ ("dm_odm->BbSwingIdxCck = %d dm_odm->BbSwingIdxCckBase = %d\n",
+ dm_odm->BbSwingIdxCck, dm_odm->BbSwingIdxCckBase));
+
+ if (dm_odm->BbSwingIdxCck <= dm_odm->BbSwingIdxCckBase) {
+ *pDirection = 1;
+ pwr_value = (dm_odm->BbSwingIdxCckBase - dm_odm->BbSwingIdxCck);
+ } else {
+ *pDirection = 2;
+ pwr_value = (dm_odm->BbSwingIdxCck - dm_odm->BbSwingIdxCckBase);
+ }
+ }
+
+ /* */
+ /* 2012/04/25 MH According to Ed/Luke.Lees estimate for EVM the max tx power tracking */
+ /* need to be less than 6 power index for 88E. */
+ /* */
+ if (pwr_value >= ODM_TXPWRTRACK_MAX_IDX_88E && *pDirection == 1)
+ pwr_value = ODM_TXPWRTRACK_MAX_IDX_88E;
+
+ *pOutWriteVal = pwr_value | (pwr_value<<8) | (pwr_value<<16) | (pwr_value<<24);
+} /* ODM_TxPwrTrackAdjust88E */
+
+/*-----------------------------------------------------------------------------
+ * Function: odm_TxPwrTrackSetPwr88E()
+ *
+ * Overview: 88E change all channel tx power accordign to flag.
+ * OFDM & CCK are all different.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 04/23/2012 MHC Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+static void odm_TxPwrTrackSetPwr88E(struct odm_dm_struct *dm_odm)
+{
+ if (dm_odm->BbSwingFlagOfdm || dm_odm->BbSwingFlagCck) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("odm_TxPwrTrackSetPwr88E CH=%d\n", *(dm_odm->pChannel)));
+ PHY_SetTxPowerLevel8188E(dm_odm->Adapter, *(dm_odm->pChannel));
+ dm_odm->BbSwingFlagOfdm = false;
+ dm_odm->BbSwingFlagCck = false;
+ }
+} /* odm_TxPwrTrackSetPwr88E */
+
+/* 091212 chiyokolin */
+void
+odm_TXPowerTrackingCallback_ThermalMeter_8188E(
+ struct adapter *Adapter
+ )
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, offset;
+ u8 ThermalValue_AVG_count = 0;
+ u32 ThermalValue_AVG = 0;
+ s32 ele_A = 0, ele_D, TempCCk, X, value32;
+ s32 Y, ele_C = 0;
+ s8 OFDM_index[2], CCK_index = 0;
+ s8 OFDM_index_old[2] = {0, 0}, CCK_index_old = 0;
+ u32 i = 0, j = 0;
+ bool is2t = false;
+
+ u8 OFDM_min_index = 6, rf; /* OFDM BB Swing should be less than +3.0dB, which is required by Arthur */
+ u8 Indexforchannel = 0/*GetRightChnlPlaceforIQK(pHalData->CurrentChannel)*/;
+ s8 OFDM_index_mapping[2][index_mapping_NUM_88E] = {
+ {0, 0, 2, 3, 4, 4, /* 2.4G, decrease power */
+ 5, 6, 7, 7, 8, 9,
+ 10, 10, 11}, /* For lower temperature, 20120220 updated on 20120220. */
+ {0, 0, -1, -2, -3, -4, /* 2.4G, increase power */
+ -4, -4, -4, -5, -7, -8,
+ -9, -9, -10},
+ };
+ u8 Thermal_mapping[2][index_mapping_NUM_88E] = {
+ {0, 2, 4, 6, 8, 10, /* 2.4G, decrease power */
+ 12, 14, 16, 18, 20, 22,
+ 24, 26, 27},
+ {0, 2, 4, 6, 8, 10, /* 2.4G,, increase power */
+ 12, 14, 16, 18, 20, 22,
+ 25, 25, 25},
+ };
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ /* 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */
+ odm_TxPwrTrackSetPwr88E(dm_odm);
+
+ dm_odm->RFCalibrateInfo.TXPowerTrackingCallbackCnt++; /* cosa add for debug */
+ dm_odm->RFCalibrateInfo.bTXPowerTrackingInit = true;
+
+ /* <Kordan> RFCalibrateInfo.RegA24 will be initialized when ODM HW configuring, but MP configures with para files. */
+ dm_odm->RFCalibrateInfo.RegA24 = 0x090e1317;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("===>dm_TXPowerTrackingCallback_ThermalMeter_8188E txpowercontrol %d\n",
+ dm_odm->RFCalibrateInfo.TxPowerTrackControl));
+
+ ThermalValue = (u8)ODM_GetRFReg(dm_odm, RF_PATH_A, RF_T_METER_88E, 0xfc00); /* 0x42: RF Reg[15:10] 88E */
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x\n",
+ ThermalValue, dm_odm->RFCalibrateInfo.ThermalValue, pHalData->EEPROMThermalMeter));
+
+ if (is2t)
+ rf = 2;
+ else
+ rf = 1;
+
+ if (ThermalValue) {
+ /* Query OFDM path A default setting */
+ ele_D = ODM_GetBBReg(dm_odm, rOFDM0_XATxIQImbalance, bMaskDWord)&bMaskOFDM_D;
+ for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { /* find the index */
+ if (ele_D == (OFDMSwingTable[i]&bMaskOFDM_D)) {
+ OFDM_index_old[0] = (u8)i;
+ dm_odm->BbSwingIdxOfdmBase = (u8)i;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("Initial pathA ele_D reg0x%x = 0x%x, OFDM_index=0x%x\n",
+ rOFDM0_XATxIQImbalance, ele_D, OFDM_index_old[0]));
+ break;
+ }
+ }
+
+ /* Query OFDM path B default setting */
+ if (is2t) {
+ ele_D = ODM_GetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord)&bMaskOFDM_D;
+ for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { /* find the index */
+ if (ele_D == (OFDMSwingTable[i]&bMaskOFDM_D)) {
+ OFDM_index_old[1] = (u8)i;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("Initial pathB ele_D reg0x%x = 0x%x, OFDM_index=0x%x\n",
+ rOFDM0_XBTxIQImbalance, ele_D, OFDM_index_old[1]));
+ break;
+ }
+ }
+ }
+
+ /* Query CCK default setting From 0xa24 */
+ TempCCk = dm_odm->RFCalibrateInfo.RegA24;
+
+ for (i = 0; i < CCK_TABLE_SIZE; i++) {
+ if (dm_odm->RFCalibrateInfo.bCCKinCH14) {
+ if (ODM_CompareMemory(dm_odm, (void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4) == 0) {
+ CCK_index_old = (u8)i;
+ dm_odm->BbSwingIdxCckBase = (u8)i;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("Initial reg0x%x = 0x%x, CCK_index=0x%x, ch 14 %d\n",
+ rCCK0_TxFilter2, TempCCk, CCK_index_old, dm_odm->RFCalibrateInfo.bCCKinCH14));
+ break;
+ }
+ } else {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("RegA24: 0x%X, CCKSwingTable_Ch1_Ch13[%d][2]: CCKSwingTable_Ch1_Ch13[i][2]: 0x%X\n",
+ TempCCk, i, CCKSwingTable_Ch1_Ch13[i][2]));
+ if (ODM_CompareMemory(dm_odm, (void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4) == 0) {
+ CCK_index_old = (u8)i;
+ dm_odm->BbSwingIdxCckBase = (u8)i;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("Initial reg0x%x = 0x%x, CCK_index=0x%x, ch14 %d\n",
+ rCCK0_TxFilter2, TempCCk, CCK_index_old, dm_odm->RFCalibrateInfo.bCCKinCH14));
+ break;
+ }
+ }
+ }
+
+ if (!dm_odm->RFCalibrateInfo.ThermalValue) {
+ dm_odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter;
+ dm_odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue;
+ dm_odm->RFCalibrateInfo.ThermalValue_IQK = ThermalValue;
+
+ for (i = 0; i < rf; i++)
+ dm_odm->RFCalibrateInfo.OFDM_index[i] = OFDM_index_old[i];
+ dm_odm->RFCalibrateInfo.CCK_index = CCK_index_old;
+ }
+
+ if (dm_odm->RFCalibrateInfo.bReloadtxpowerindex)
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("reload ofdm index for band switch\n"));
+
+ /* calculate average thermal meter */
+ dm_odm->RFCalibrateInfo.ThermalValue_AVG[dm_odm->RFCalibrateInfo.ThermalValue_AVG_index] = ThermalValue;
+ dm_odm->RFCalibrateInfo.ThermalValue_AVG_index++;
+ if (dm_odm->RFCalibrateInfo.ThermalValue_AVG_index == AVG_THERMAL_NUM_88E)
+ dm_odm->RFCalibrateInfo.ThermalValue_AVG_index = 0;
+
+ for (i = 0; i < AVG_THERMAL_NUM_88E; i++) {
+ if (dm_odm->RFCalibrateInfo.ThermalValue_AVG[i]) {
+ ThermalValue_AVG += dm_odm->RFCalibrateInfo.ThermalValue_AVG[i];
+ ThermalValue_AVG_count++;
+ }
+ }
+
+ if (ThermalValue_AVG_count) {
+ ThermalValue = (u8)(ThermalValue_AVG / ThermalValue_AVG_count);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("AVG Thermal Meter = 0x%x\n", ThermalValue));
+ }
+
+ if (dm_odm->RFCalibrateInfo.bReloadtxpowerindex) {
+ delta = ThermalValue > pHalData->EEPROMThermalMeter ?
+ (ThermalValue - pHalData->EEPROMThermalMeter) :
+ (pHalData->EEPROMThermalMeter - ThermalValue);
+ dm_odm->RFCalibrateInfo.bReloadtxpowerindex = false;
+ dm_odm->RFCalibrateInfo.bDoneTxpower = false;
+ } else if (dm_odm->RFCalibrateInfo.bDoneTxpower) {
+ delta = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue) ?
+ (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue) :
+ (dm_odm->RFCalibrateInfo.ThermalValue - ThermalValue);
+ } else {
+ delta = ThermalValue > pHalData->EEPROMThermalMeter ?
+ (ThermalValue - pHalData->EEPROMThermalMeter) :
+ (pHalData->EEPROMThermalMeter - ThermalValue);
+ }
+ delta_LCK = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue_LCK) ?
+ (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue_LCK) :
+ (dm_odm->RFCalibrateInfo.ThermalValue_LCK - ThermalValue);
+ delta_IQK = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue_IQK) ?
+ (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue_IQK) :
+ (dm_odm->RFCalibrateInfo.ThermalValue_IQK - ThermalValue);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x delta 0x%x delta_LCK 0x%x delta_IQK 0x%x\n",
+ ThermalValue, dm_odm->RFCalibrateInfo.ThermalValue,
+ pHalData->EEPROMThermalMeter, delta, delta_LCK, delta_IQK));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("pre thermal meter LCK 0x%x pre thermal meter IQK 0x%x delta_LCK_bound 0x%x delta_IQK_bound 0x%x\n",
+ dm_odm->RFCalibrateInfo.ThermalValue_LCK,
+ dm_odm->RFCalibrateInfo.ThermalValue_IQK,
+ dm_odm->RFCalibrateInfo.Delta_LCK,
+ dm_odm->RFCalibrateInfo.Delta_IQK));
+
+ if ((delta_LCK >= 8)) { /* Delta temperature is equal to or larger than 20 centigrade. */
+ dm_odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue;
+ PHY_LCCalibrate_8188E(Adapter);
+ }
+
+ if (delta > 0 && dm_odm->RFCalibrateInfo.TxPowerTrackControl) {
+ delta = ThermalValue > pHalData->EEPROMThermalMeter ?
+ (ThermalValue - pHalData->EEPROMThermalMeter) :
+ (pHalData->EEPROMThermalMeter - ThermalValue);
+ /* calculate new OFDM / CCK offset */
+ if (ThermalValue > pHalData->EEPROMThermalMeter)
+ j = 1;
+ else
+ j = 0;
+ for (offset = 0; offset < index_mapping_NUM_88E; offset++) {
+ if (delta < Thermal_mapping[j][offset]) {
+ if (offset != 0)
+ offset--;
+ break;
+ }
+ }
+ if (offset >= index_mapping_NUM_88E)
+ offset = index_mapping_NUM_88E-1;
+ for (i = 0; i < rf; i++)
+ OFDM_index[i] = dm_odm->RFCalibrateInfo.OFDM_index[i] + OFDM_index_mapping[j][offset];
+ CCK_index = dm_odm->RFCalibrateInfo.CCK_index + OFDM_index_mapping[j][offset];
+
+ if (is2t) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("temp OFDM_A_index=0x%x, OFDM_B_index=0x%x, CCK_index=0x%x\n",
+ dm_odm->RFCalibrateInfo.OFDM_index[0],
+ dm_odm->RFCalibrateInfo.OFDM_index[1],
+ dm_odm->RFCalibrateInfo.CCK_index));
+ } else {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("temp OFDM_A_index=0x%x, CCK_index=0x%x\n",
+ dm_odm->RFCalibrateInfo.OFDM_index[0],
+ dm_odm->RFCalibrateInfo.CCK_index));
+ }
+
+ for (i = 0; i < rf; i++) {
+ if (OFDM_index[i] > OFDM_TABLE_SIZE_92D-1)
+ OFDM_index[i] = OFDM_TABLE_SIZE_92D-1;
+ else if (OFDM_index[i] < OFDM_min_index)
+ OFDM_index[i] = OFDM_min_index;
+ }
+
+ if (CCK_index > CCK_TABLE_SIZE-1)
+ CCK_index = CCK_TABLE_SIZE-1;
+ else if (CCK_index < 0)
+ CCK_index = 0;
+
+ if (is2t) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("new OFDM_A_index=0x%x, OFDM_B_index=0x%x, CCK_index=0x%x\n",
+ OFDM_index[0], OFDM_index[1], CCK_index));
+ } else {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("new OFDM_A_index=0x%x, CCK_index=0x%x\n",
+ OFDM_index[0], CCK_index));
+ }
+
+ /* 2 temporarily remove bNOPG */
+ /* Config by SwingTable */
+ if (dm_odm->RFCalibrateInfo.TxPowerTrackControl) {
+ dm_odm->RFCalibrateInfo.bDoneTxpower = true;
+
+ /* Adujst OFDM Ant_A according to IQK result */
+ ele_D = (OFDMSwingTable[(u8)OFDM_index[0]] & 0xFFC00000)>>22;
+ X = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][0];
+ Y = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][1];
+
+ /* Revse TX power table. */
+ dm_odm->BbSwingIdxOfdm = (u8)OFDM_index[0];
+ dm_odm->BbSwingIdxCck = (u8)CCK_index;
+
+ if (dm_odm->BbSwingIdxOfdmCurrent != dm_odm->BbSwingIdxOfdm) {
+ dm_odm->BbSwingIdxOfdmCurrent = dm_odm->BbSwingIdxOfdm;
+ dm_odm->BbSwingFlagOfdm = true;
+ }
+
+ if (dm_odm->BbSwingIdxCckCurrent != dm_odm->BbSwingIdxCck) {
+ dm_odm->BbSwingIdxCckCurrent = dm_odm->BbSwingIdxCck;
+ dm_odm->BbSwingFlagCck = true;
+ }
+
+ if (X != 0) {
+ if ((X & 0x00000200) != 0)
+ X = X | 0xFFFFFC00;
+ ele_A = ((X * ele_D)>>8)&0x000003FF;
+
+ /* new element C = element D x Y */
+ if ((Y & 0x00000200) != 0)
+ Y = Y | 0xFFFFFC00;
+ ele_C = ((Y * ele_D)>>8)&0x000003FF;
+
+ /* 2012/04/23 MH According to Luke's suggestion, we can not write BB digital */
+ /* to increase TX power. Otherwise, EVM will be bad. */
+ }
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("TxPwrTracking for path A: X=0x%x, Y=0x%x ele_A=0x%x ele_C=0x%x ele_D=0x%x 0xe94=0x%x 0xe9c=0x%x\n",
+ (u32)X, (u32)Y, (u32)ele_A, (u32)ele_C, (u32)ele_D, (u32)X, (u32)Y));
+
+ if (is2t) {
+ ele_D = (OFDMSwingTable[(u8)OFDM_index[1]] & 0xFFC00000)>>22;
+
+ /* new element A = element D x X */
+ X = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][4];
+ Y = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][5];
+
+ if ((X != 0) && (*(dm_odm->pBandType) == ODM_BAND_2_4G)) {
+ if ((X & 0x00000200) != 0) /* consider minus */
+ X = X | 0xFFFFFC00;
+ ele_A = ((X * ele_D)>>8)&0x000003FF;
+
+ /* new element C = element D x Y */
+ if ((Y & 0x00000200) != 0)
+ Y = Y | 0xFFFFFC00;
+ ele_C = ((Y * ele_D)>>8)&0x00003FF;
+
+ /* wtite new elements A, C, D to regC88 and regC9C, element B is always 0 */
+ value32 = (ele_D<<22) | ((ele_C&0x3F)<<16) | ele_A;
+ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord, value32);
+
+ value32 = (ele_C&0x000003C0)>>6;
+ ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, bMaskH4Bits, value32);
+
+ value32 = ((X * ele_D)>>7)&0x01;
+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT28, value32);
+ } else {
+ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord, OFDMSwingTable[(u8)OFDM_index[1]]);
+ ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, bMaskH4Bits, 0x00);
+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT28, 0x00);
+ }
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("TxPwrTracking path B: X=0x%x, Y=0x%x ele_A=0x%x ele_C=0x%x ele_D=0x%x 0xeb4=0x%x 0xebc=0x%x\n",
+ (u32)X, (u32)Y, (u32)ele_A,
+ (u32)ele_C, (u32)ele_D, (u32)X, (u32)Y));
+ }
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("TxPwrTracking 0xc80 = 0x%x, 0xc94 = 0x%x RF 0x24 = 0x%x\n",
+ ODM_GetBBReg(dm_odm, 0xc80, bMaskDWord), ODM_GetBBReg(dm_odm,
+ 0xc94, bMaskDWord), ODM_GetRFReg(dm_odm, RF_PATH_A, 0x24, bRFRegOffsetMask)));
+ }
+ }
+
+ if (delta_IQK >= 8) { /* Delta temperature is equal to or larger than 20 centigrade. */
+ ODM_ResetIQKResult(dm_odm);
+
+ dm_odm->RFCalibrateInfo.ThermalValue_IQK = ThermalValue;
+ PHY_IQCalibrate_8188E(Adapter, false);
+ }
+ /* update thermal meter value */
+ if (dm_odm->RFCalibrateInfo.TxPowerTrackControl)
+ dm_odm->RFCalibrateInfo.ThermalValue = ThermalValue;
+ }
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("<===dm_TXPowerTrackingCallback_ThermalMeter_8188E\n"));
+ dm_odm->RFCalibrateInfo.TXPowercount = 0;
+}
+
+/* 1 7. IQK */
+#define MAX_TOLERANCE 5
+#define IQK_DELAY_TIME 1 /* ms */
+
+static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */
+phy_PathA_IQK_8188E(struct adapter *adapt, bool configPathB)
+{
+ u32 regeac, regE94, regE9C, regEA4;
+ u8 result = 0x00;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK!\n"));
+
+ /* 1 Tx IQK */
+ /* path-A IQK setting */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A IQK setting!\n"));
+ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c);
+ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c);
+ ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x8214032a);
+ ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000);
+
+ /* LO calibration setting */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n"));
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x00462911);
+
+ /* One shot, path A LOK & IQK */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n"));
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
+
+ /* delay x ms */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E));
+ /* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */
+ ODM_delay_ms(IQK_DELAY_TIME_88E);
+
+ /* Check failed */
+ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regeac));
+ regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94));
+ regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe9c = 0x%x\n", regE9C));
+ regEA4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x\n", regEA4));
+
+ if (!(regeac & BIT28) &&
+ (((regE94 & 0x03FF0000)>>16) != 0x142) &&
+ (((regE9C & 0x03FF0000)>>16) != 0x42))
+ result |= 0x01;
+ return result;
+}
+
+static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */
+phy_PathA_RxIQK(struct adapter *adapt, bool configPathB)
+{
+ u32 regeac, regE94, regE9C, regEA4, u4tmp;
+ u8 result = 0x00;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK!\n"));
+
+ /* 1 Get TXIMR setting */
+ /* modify RXIQK mode table */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table!\n"));
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf117B);
+
+ /* PA,PAD off */
+ ODM_SetRFReg(dm_odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x980);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, 0x56, bRFRegOffsetMask, 0x51000);
+
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+
+ /* IQK setting */
+ ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, 0x01007c00);
+ ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x81004800);
+
+ /* path-A IQK setting */
+ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c);
+ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c);
+ ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c1f);
+ ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000);
+
+ /* LO calibration setting */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n"));
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911);
+
+ /* One shot, path A LOK & IQK */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n"));
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
+
+ /* delay x ms */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("Delay %d ms for One shot, path A LOK & IQK.\n",
+ IQK_DELAY_TIME_88E));
+ ODM_delay_ms(IQK_DELAY_TIME_88E);
+
+ /* Check failed */
+ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("0xeac = 0x%x\n", regeac));
+ regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("0xe94 = 0x%x\n", regE94));
+ regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("0xe9c = 0x%x\n", regE9C));
+
+ if (!(regeac & BIT28) &&
+ (((regE94 & 0x03FF0000)>>16) != 0x142) &&
+ (((regE9C & 0x03FF0000)>>16) != 0x42))
+ result |= 0x01;
+ else /* if Tx not OK, ignore Rx */
+ return result;
+
+ u4tmp = 0x80007C00 | (regE94&0x3FF0000) | ((regE9C&0x3FF0000) >> 16);
+ ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, u4tmp);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe40 = 0x%x u4tmp = 0x%x\n", ODM_GetBBReg(dm_odm, rTx_IQK, bMaskDWord), u4tmp));
+
+ /* 1 RX IQK */
+ /* modify RXIQK mode table */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table 2!\n"));
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7ffa);
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+
+ /* IQK setting */
+ ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x01004800);
+
+ /* path-A IQK setting */
+ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x38008c1c);
+ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x18008c1c);
+ ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c05);
+ ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160c1f);
+
+ /* LO calibration setting */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n"));
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911);
+
+ /* One shot, path A LOK & IQK */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n"));
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
+
+ /* delay x ms */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E));
+ /* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */
+ ODM_delay_ms(IQK_DELAY_TIME_88E);
+
+ /* Check failed */
+ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regeac));
+ regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94));
+ regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe9c = 0x%x\n", regE9C));
+ regEA4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x\n", regEA4));
+
+ /* reload RF 0xdf */
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x180);
+
+ if (!(regeac & BIT27) && /* if Tx is OK, check whether Rx is OK */
+ (((regEA4 & 0x03FF0000)>>16) != 0x132) &&
+ (((regeac & 0x03FF0000)>>16) != 0x36))
+ result |= 0x02;
+ else
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK fail!!\n"));
+
+ return result;
+}
+
+static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */
+phy_PathB_IQK_8188E(struct adapter *adapt)
+{
+ u32 regeac, regeb4, regebc, regec4, regecc;
+ u8 result = 0x00;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK!\n"));
+
+ /* One shot, path B LOK & IQK */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n"));
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Cont, bMaskDWord, 0x00000002);
+ ODM_SetBBReg(dm_odm, rIQK_AGC_Cont, bMaskDWord, 0x00000000);
+
+ /* delay x ms */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("Delay %d ms for One shot, path B LOK & IQK.\n",
+ IQK_DELAY_TIME_88E));
+ ODM_delay_ms(IQK_DELAY_TIME_88E);
+
+ /* Check failed */
+ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("0xeac = 0x%x\n", regeac));
+ regeb4 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("0xeb4 = 0x%x\n", regeb4));
+ regebc = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("0xebc = 0x%x\n", regebc));
+ regec4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_B_2, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("0xec4 = 0x%x\n", regec4));
+ regecc = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_B_2, bMaskDWord);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("0xecc = 0x%x\n", regecc));
+
+ if (!(regeac & BIT31) &&
+ (((regeb4 & 0x03FF0000)>>16) != 0x142) &&
+ (((regebc & 0x03FF0000)>>16) != 0x42))
+ result |= 0x01;
+ else
+ return result;
+
+ if (!(regeac & BIT30) &&
+ (((regec4 & 0x03FF0000)>>16) != 0x132) &&
+ (((regecc & 0x03FF0000)>>16) != 0x36))
+ result |= 0x02;
+ else
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK fail!!\n"));
+ return result;
+}
+
+static void patha_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8], u8 final_candidate, bool txonly)
+{
+ u32 Oldval_0, X, TX0_A, reg;
+ s32 Y, TX0_C;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("Path A IQ Calibration %s !\n",
+ (iqkok) ? "Success" : "Failed"));
+
+ if (final_candidate == 0xFF) {
+ return;
+ } else if (iqkok) {
+ Oldval_0 = (ODM_GetBBReg(dm_odm, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF;
+
+ X = result[final_candidate][0];
+ if ((X & 0x00000200) != 0)
+ X = X | 0xFFFFFC00;
+ TX0_A = (X * Oldval_0) >> 8;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("X = 0x%x, TX0_A = 0x%x, Oldval_0 0x%x\n",
+ X, TX0_A, Oldval_0));
+ ODM_SetBBReg(dm_odm, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A);
+
+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(31), ((X * Oldval_0>>7) & 0x1));
+
+ Y = result[final_candidate][1];
+ if ((Y & 0x00000200) != 0)
+ Y = Y | 0xFFFFFC00;
+
+ TX0_C = (Y * Oldval_0) >> 8;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX = 0x%x\n", Y, TX0_C));
+ ODM_SetBBReg(dm_odm, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6));
+ ODM_SetBBReg(dm_odm, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C&0x3F));
+
+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(29), ((Y * Oldval_0>>7) & 0x1));
+
+ if (txonly) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("patha_fill_iqk only Tx OK\n"));
+ return;
+ }
+
+ reg = result[final_candidate][2];
+ ODM_SetBBReg(dm_odm, rOFDM0_XARxIQImbalance, 0x3FF, reg);
+
+ reg = result[final_candidate][3] & 0x3F;
+ ODM_SetBBReg(dm_odm, rOFDM0_XARxIQImbalance, 0xFC00, reg);
+
+ reg = (result[final_candidate][3] >> 6) & 0xF;
+ ODM_SetBBReg(dm_odm, rOFDM0_RxIQExtAnta, 0xF0000000, reg);
+ }
+}
+
+static void pathb_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8], u8 final_candidate, bool txonly)
+{
+ u32 Oldval_1, X, TX1_A, reg;
+ s32 Y, TX1_C;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("Path B IQ Calibration %s !\n",
+ (iqkok) ? "Success" : "Failed"));
+
+ if (final_candidate == 0xFF) {
+ return;
+ } else if (iqkok) {
+ Oldval_1 = (ODM_GetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF;
+
+ X = result[final_candidate][4];
+ if ((X & 0x00000200) != 0)
+ X = X | 0xFFFFFC00;
+ TX1_A = (X * Oldval_1) >> 8;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX1_A = 0x%x\n", X, TX1_A));
+ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A);
+
+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(27), ((X * Oldval_1>>7) & 0x1));
+
+ Y = result[final_candidate][5];
+ if ((Y & 0x00000200) != 0)
+ Y = Y | 0xFFFFFC00;
+
+ TX1_C = (Y * Oldval_1) >> 8;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX1_C = 0x%x\n", Y, TX1_C));
+ ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6));
+ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C&0x3F));
+
+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(25), ((Y * Oldval_1>>7) & 0x1));
+
+ if (txonly)
+ return;
+
+ reg = result[final_candidate][6];
+ ODM_SetBBReg(dm_odm, rOFDM0_XBRxIQImbalance, 0x3FF, reg);
+
+ reg = result[final_candidate][7] & 0x3F;
+ ODM_SetBBReg(dm_odm, rOFDM0_XBRxIQImbalance, 0xFC00, reg);
+
+ reg = (result[final_candidate][7] >> 6) & 0xF;
+ ODM_SetBBReg(dm_odm, rOFDM0_AGCRSSITable, 0x0000F000, reg);
+ }
+}
+
+/* */
+/* 2011/07/26 MH Add an API for testing IQK fail case. */
+/* */
+/* MP Already declare in odm.c */
+static bool ODM_CheckPowerStatus(struct adapter *Adapter)
+{
+ return true;
+}
+
+void _PHY_SaveADDARegisters(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup, u32 RegisterNum)
+{
+ u32 i;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ if (ODM_CheckPowerStatus(adapt) == false)
+ return;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save ADDA parameters.\n"));
+ for (i = 0; i < RegisterNum; i++) {
+ ADDABackup[i] = ODM_GetBBReg(dm_odm, ADDAReg[i], bMaskDWord);
+ }
+}
+
+static void _PHY_SaveMACRegisters(
+ struct adapter *adapt,
+ u32 *MACReg,
+ u32 *MACBackup
+ )
+{
+ u32 i;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save MAC parameters.\n"));
+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) {
+ MACBackup[i] = ODM_Read1Byte(dm_odm, MACReg[i]);
+ }
+ MACBackup[i] = ODM_Read4Byte(dm_odm, MACReg[i]);
+}
+
+static void reload_adda_reg(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup, u32 RegiesterNum)
+{
+ u32 i;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload ADDA power saving parameters !\n"));
+ for (i = 0; i < RegiesterNum; i++)
+ ODM_SetBBReg(dm_odm, ADDAReg[i], bMaskDWord, ADDABackup[i]);
+}
+
+static void
+_PHY_ReloadMACRegisters(
+ struct adapter *adapt,
+ u32 *MACReg,
+ u32 *MACBackup
+ )
+{
+ u32 i;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload MAC parameters !\n"));
+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) {
+ ODM_Write1Byte(dm_odm, MACReg[i], (u8)MACBackup[i]);
+ }
+ ODM_Write4Byte(dm_odm, MACReg[i], MACBackup[i]);
+}
+
+void
+_PHY_PathADDAOn(
+ struct adapter *adapt,
+ u32 *ADDAReg,
+ bool isPathAOn,
+ bool is2t
+ )
+{
+ u32 pathOn;
+ u32 i;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ADDA ON.\n"));
+
+ pathOn = isPathAOn ? 0x04db25a4 : 0x0b1b25a4;
+ if (false == is2t) {
+ pathOn = 0x0bdb25a0;
+ ODM_SetBBReg(dm_odm, ADDAReg[0], bMaskDWord, 0x0b1b25a0);
+ } else {
+ ODM_SetBBReg(dm_odm, ADDAReg[0], bMaskDWord, pathOn);
+ }
+
+ for (i = 1; i < IQK_ADDA_REG_NUM; i++)
+ ODM_SetBBReg(dm_odm, ADDAReg[i], bMaskDWord, pathOn);
+}
+
+void
+_PHY_MACSettingCalibration(
+ struct adapter *adapt,
+ u32 *MACReg,
+ u32 *MACBackup
+ )
+{
+ u32 i = 0;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("MAC settings for Calibration.\n"));
+
+ ODM_Write1Byte(dm_odm, MACReg[i], 0x3F);
+
+ for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) {
+ ODM_Write1Byte(dm_odm, MACReg[i], (u8)(MACBackup[i]&(~BIT3)));
+ }
+ ODM_Write1Byte(dm_odm, MACReg[i], (u8)(MACBackup[i]&(~BIT5)));
+}
+
+void
+_PHY_PathAStandBy(
+ struct adapter *adapt
+ )
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A standby mode!\n"));
+
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x0);
+ ODM_SetBBReg(dm_odm, 0x840, bMaskDWord, 0x00010000);
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+}
+
+static void _PHY_PIModeSwitch(
+ struct adapter *adapt,
+ bool PIMode
+ )
+{
+ u32 mode;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("BB Switch to %s mode!\n", (PIMode ? "PI" : "SI")));
+
+ mode = PIMode ? 0x01000100 : 0x01000000;
+ ODM_SetBBReg(dm_odm, rFPGA0_XA_HSSIParameter1, bMaskDWord, mode);
+ ODM_SetBBReg(dm_odm, rFPGA0_XB_HSSIParameter1, bMaskDWord, mode);
+}
+
+static bool phy_SimularityCompare_8188E(
+ struct adapter *adapt,
+ s32 resulta[][8],
+ u8 c1,
+ u8 c2
+ )
+{
+ u32 i, j, diff, sim_bitmap, bound = 0;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ u8 final_candidate[2] = {0xFF, 0xFF}; /* for path A and path B */
+ bool result = true;
+ bool is2t;
+ s32 tmp1 = 0, tmp2 = 0;
+
+ if ((dm_odm->RFType == ODM_2T2R) || (dm_odm->RFType == ODM_2T3R) || (dm_odm->RFType == ODM_2T4R))
+ is2t = true;
+ else
+ is2t = false;
+
+ if (is2t)
+ bound = 8;
+ else
+ bound = 4;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("===> IQK:phy_SimularityCompare_8188E c1 %d c2 %d!!!\n", c1, c2));
+
+ sim_bitmap = 0;
+
+ for (i = 0; i < bound; i++) {
+ if ((i == 1) || (i == 3) || (i == 5) || (i == 7)) {
+ if ((resulta[c1][i] & 0x00000200) != 0)
+ tmp1 = resulta[c1][i] | 0xFFFFFC00;
+ else
+ tmp1 = resulta[c1][i];
+
+ if ((resulta[c2][i] & 0x00000200) != 0)
+ tmp2 = resulta[c2][i] | 0xFFFFFC00;
+ else
+ tmp2 = resulta[c2][i];
+ } else {
+ tmp1 = resulta[c1][i];
+ tmp2 = resulta[c2][i];
+ }
+
+ diff = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1);
+
+ if (diff > MAX_TOLERANCE) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("IQK:phy_SimularityCompare_8188E differnece overflow index %d compare1 0x%x compare2 0x%x!!!\n",
+ i, resulta[c1][i], resulta[c2][i]));
+
+ if ((i == 2 || i == 6) && !sim_bitmap) {
+ if (resulta[c1][i] + resulta[c1][i+1] == 0)
+ final_candidate[(i/4)] = c2;
+ else if (resulta[c2][i] + resulta[c2][i+1] == 0)
+ final_candidate[(i/4)] = c1;
+ else
+ sim_bitmap = sim_bitmap | (1<<i);
+ } else {
+ sim_bitmap = sim_bitmap | (1<<i);
+ }
+ }
+ }
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:phy_SimularityCompare_8188E sim_bitmap %d !!!\n", sim_bitmap));
+
+ if (sim_bitmap == 0) {
+ for (i = 0; i < (bound/4); i++) {
+ if (final_candidate[i] != 0xFF) {
+ for (j = i*4; j < (i+1)*4-2; j++)
+ resulta[3][j] = resulta[final_candidate[i]][j];
+ result = false;
+ }
+ }
+ return result;
+ } else {
+ if (!(sim_bitmap & 0x03)) { /* path A TX OK */
+ for (i = 0; i < 2; i++)
+ resulta[3][i] = resulta[c1][i];
+ }
+ if (!(sim_bitmap & 0x0c)) { /* path A RX OK */
+ for (i = 2; i < 4; i++)
+ resulta[3][i] = resulta[c1][i];
+ }
+
+ if (!(sim_bitmap & 0x30)) { /* path B TX OK */
+ for (i = 4; i < 6; i++)
+ resulta[3][i] = resulta[c1][i];
+ }
+
+ if (!(sim_bitmap & 0xc0)) { /* path B RX OK */
+ for (i = 6; i < 8; i++)
+ resulta[3][i] = resulta[c1][i];
+ }
+ return false;
+ }
+}
+
+static void phy_IQCalibrate_8188E(struct adapter *adapt, s32 result[][8], u8 t, bool is2t)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ u32 i;
+ u8 PathAOK, PathBOK;
+ u32 ADDA_REG[IQK_ADDA_REG_NUM] = {
+ rFPGA0_XCD_SwitchControl, rBlue_Tooth,
+ rRx_Wait_CCA, rTx_CCK_RFON,
+ rTx_CCK_BBON, rTx_OFDM_RFON,
+ rTx_OFDM_BBON, rTx_To_Rx,
+ rTx_To_Tx, rRx_CCK,
+ rRx_OFDM, rRx_Wait_RIFS,
+ rRx_TO_Rx, rStandby,
+ rSleep, rPMPD_ANAEN };
+ u32 IQK_MAC_REG[IQK_MAC_REG_NUM] = {
+ REG_TXPAUSE, REG_BCN_CTRL,
+ REG_BCN_CTRL_1, REG_GPIO_MUXCFG};
+
+ /* since 92C & 92D have the different define in IQK_BB_REG */
+ u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = {
+ rOFDM0_TRxPathEnable, rOFDM0_TRMuxPar,
+ rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB,
+ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE,
+ rFPGA0_XB_RFInterfaceOE, rFPGA0_RFMOD
+ };
+
+ u32 retryCount = 9;
+ if (*(dm_odm->mp_mode) == 1)
+ retryCount = 9;
+ else
+ retryCount = 2;
+ /* Note: IQ calibration must be performed after loading */
+ /* PHY_REG.txt , and radio_a, radio_b.txt */
+
+ if (t == 0) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2t ? "2T2R" : "1T1R"), t));
+
+ /* Save ADDA parameters, turn Path A ADDA on */
+ _PHY_SaveADDARegisters(adapt, ADDA_REG, dm_odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM);
+ _PHY_SaveMACRegisters(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup);
+ _PHY_SaveADDARegisters(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM);
+ }
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2t ? "2T2R" : "1T1R"), t));
+
+ _PHY_PathADDAOn(adapt, ADDA_REG, true, is2t);
+ if (t == 0)
+ dm_odm->RFCalibrateInfo.bRfPiEnable = (u8)ODM_GetBBReg(dm_odm, rFPGA0_XA_HSSIParameter1, BIT(8));
+
+ if (!dm_odm->RFCalibrateInfo.bRfPiEnable) {
+ /* Switch BB to PI mode to do IQ Calibration. */
+ _PHY_PIModeSwitch(adapt, true);
+ }
+
+ /* BB setting */
+ ODM_SetBBReg(dm_odm, rFPGA0_RFMOD, BIT24, 0x00);
+ ODM_SetBBReg(dm_odm, rOFDM0_TRxPathEnable, bMaskDWord, 0x03a05600);
+ ODM_SetBBReg(dm_odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800e4);
+ ODM_SetBBReg(dm_odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22204000);
+
+ ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFInterfaceSW, BIT10, 0x01);
+ ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFInterfaceSW, BIT26, 0x01);
+ ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT10, 0x00);
+ ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT10, 0x00);
+
+ if (is2t) {
+ ODM_SetBBReg(dm_odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00010000);
+ ODM_SetBBReg(dm_odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00010000);
+ }
+
+ /* MAC settings */
+ _PHY_MACSettingCalibration(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup);
+
+ /* Page B init */
+ /* AP or IQK */
+ ODM_SetBBReg(dm_odm, rConfig_AntA, bMaskDWord, 0x0f600000);
+
+ if (is2t)
+ ODM_SetBBReg(dm_odm, rConfig_AntB, bMaskDWord, 0x0f600000);
+
+ /* IQ calibration setting */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK setting!\n"));
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+ ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, 0x01007c00);
+ ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x81004800);
+
+ for (i = 0; i < retryCount; i++) {
+ PathAOK = phy_PathA_IQK_8188E(adapt, is2t);
+ if (PathAOK == 0x01) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Tx IQK Success!!\n"));
+ result[t][0] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16;
+ result[t][1] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16;
+ break;
+ }
+ }
+
+ for (i = 0; i < retryCount; i++) {
+ PathAOK = phy_PathA_RxIQK(adapt, is2t);
+ if (PathAOK == 0x03) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Success!!\n"));
+ result[t][2] = (ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16;
+ result[t][3] = (ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16;
+ break;
+ } else {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Fail!!\n"));
+ }
+ }
+
+ if (0x00 == PathAOK) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK failed!!\n"));
+ }
+
+ if (is2t) {
+ _PHY_PathAStandBy(adapt);
+
+ /* Turn Path B ADDA on */
+ _PHY_PathADDAOn(adapt, ADDA_REG, false, is2t);
+
+ for (i = 0; i < retryCount; i++) {
+ PathBOK = phy_PathB_IQK_8188E(adapt);
+ if (PathBOK == 0x03) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK Success!!\n"));
+ result[t][4] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+ result[t][5] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+ result[t][6] = (ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_B_2, bMaskDWord)&0x3FF0000)>>16;
+ result[t][7] = (ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_B_2, bMaskDWord)&0x3FF0000)>>16;
+ break;
+ } else if (i == (retryCount - 1) && PathBOK == 0x01) { /* Tx IQK OK */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Only Tx IQK Success!!\n"));
+ result[t][4] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+ result[t][5] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+ }
+ }
+
+ if (0x00 == PathBOK) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK failed!!\n"));
+ }
+ }
+
+ /* Back to BB mode, load original value */
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Back to BB mode, load original value!\n"));
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0);
+
+ if (t != 0) {
+ if (!dm_odm->RFCalibrateInfo.bRfPiEnable) {
+ /* Switch back BB to SI mode after finish IQ Calibration. */
+ _PHY_PIModeSwitch(adapt, false);
+ }
+
+ /* Reload ADDA power saving parameters */
+ reload_adda_reg(adapt, ADDA_REG, dm_odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM);
+
+ /* Reload MAC parameters */
+ _PHY_ReloadMACRegisters(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup);
+
+ reload_adda_reg(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM);
+
+ /* Restore RX initial gain */
+ ODM_SetBBReg(dm_odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00032ed3);
+ if (is2t)
+ ODM_SetBBReg(dm_odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00032ed3);
+
+ /* load 0xe30 IQC default value */
+ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00);
+ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00);
+ }
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_IQCalibrate_8188E() <==\n"));
+}
+
+static void phy_LCCalibrate_8188E(struct adapter *adapt, bool is2t)
+{
+ u8 tmpreg;
+ u32 RF_Amode = 0, RF_Bmode = 0, LC_Cal;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ /* Check continuous TX and Packet TX */
+ tmpreg = ODM_Read1Byte(dm_odm, 0xd03);
+
+ if ((tmpreg&0x70) != 0) /* Deal with contisuous TX case */
+ ODM_Write1Byte(dm_odm, 0xd03, tmpreg&0x8F); /* disable all continuous TX */
+ else /* Deal with Packet TX case */
+ ODM_Write1Byte(dm_odm, REG_TXPAUSE, 0xFF); /* block all queues */
+
+ if ((tmpreg&0x70) != 0) {
+ /* 1. Read original RF mode */
+ /* Path-A */
+ RF_Amode = PHY_QueryRFReg(adapt, RF_PATH_A, RF_AC, bMask12Bits);
+
+ /* Path-B */
+ if (is2t)
+ RF_Bmode = PHY_QueryRFReg(adapt, RF_PATH_B, RF_AC, bMask12Bits);
+
+ /* 2. Set RF mode = standby mode */
+ /* Path-A */
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode&0x8FFFF)|0x10000);
+
+ /* Path-B */
+ if (is2t)
+ ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode&0x8FFFF)|0x10000);
+ }
+
+ /* 3. Read RF reg18 */
+ LC_Cal = PHY_QueryRFReg(adapt, RF_PATH_A, RF_CHNLBW, bMask12Bits);
+
+ /* 4. Set LC calibration begin bit15 */
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal|0x08000);
+
+ ODM_sleep_ms(100);
+
+ /* Restore original situation */
+ if ((tmpreg&0x70) != 0) {
+ /* Deal with continuous TX case */
+ /* Path-A */
+ ODM_Write1Byte(dm_odm, 0xd03, tmpreg);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMask12Bits, RF_Amode);
+
+ /* Path-B */
+ if (is2t)
+ ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode);
+ } else {
+ /* Deal with Packet TX case */
+ ODM_Write1Byte(dm_odm, REG_TXPAUSE, 0x00);
+ }
+}
+
+/* Analog Pre-distortion calibration */
+#define APK_BB_REG_NUM 8
+#define APK_CURVE_REG_NUM 4
+#define PATH_NUM 2
+
+static void phy_APCalibrate_8188E(struct adapter *adapt, s8 delta, bool is2t)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ u32 regD[PATH_NUM];
+ u32 tmpreg, index, offset, apkbound;
+ u8 path, i, pathbound = PATH_NUM;
+ u32 BB_backup[APK_BB_REG_NUM];
+ u32 BB_REG[APK_BB_REG_NUM] = {
+ rFPGA1_TxBlock, rOFDM0_TRxPathEnable,
+ rFPGA0_RFMOD, rOFDM0_TRMuxPar,
+ rFPGA0_XCD_RFInterfaceSW, rFPGA0_XAB_RFInterfaceSW,
+ rFPGA0_XA_RFInterfaceOE, rFPGA0_XB_RFInterfaceOE };
+ u32 BB_AP_MODE[APK_BB_REG_NUM] = {
+ 0x00000020, 0x00a05430, 0x02040000,
+ 0x000800e4, 0x00204000 };
+ u32 BB_normal_AP_MODE[APK_BB_REG_NUM] = {
+ 0x00000020, 0x00a05430, 0x02040000,
+ 0x000800e4, 0x22204000 };
+
+ u32 AFE_backup[IQK_ADDA_REG_NUM];
+ u32 AFE_REG[IQK_ADDA_REG_NUM] = {
+ rFPGA0_XCD_SwitchControl, rBlue_Tooth,
+ rRx_Wait_CCA, rTx_CCK_RFON,
+ rTx_CCK_BBON, rTx_OFDM_RFON,
+ rTx_OFDM_BBON, rTx_To_Rx,
+ rTx_To_Tx, rRx_CCK,
+ rRx_OFDM, rRx_Wait_RIFS,
+ rRx_TO_Rx, rStandby,
+ rSleep, rPMPD_ANAEN };
+
+ u32 MAC_backup[IQK_MAC_REG_NUM];
+ u32 MAC_REG[IQK_MAC_REG_NUM] = {
+ REG_TXPAUSE, REG_BCN_CTRL,
+ REG_BCN_CTRL_1, REG_GPIO_MUXCFG};
+
+ u32 APK_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = {
+ {0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c},
+ {0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e}
+ };
+
+ u32 APK_normal_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = {
+ {0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c}, /* path settings equal to path b settings */
+ {0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c}
+ };
+
+ u32 APK_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = {
+ {0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d},
+ {0x5201a, 0x52019, 0x52016, 0x52033, 0x52050}
+ };
+
+ u32 APK_normal_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = {
+ {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}, /* path settings equal to path b settings */
+ {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}
+ };
+
+ u32 AFE_on_off[PATH_NUM] = {
+ 0x04db25a4, 0x0b1b25a4}; /* path A on path B off / path A off path B on */
+
+ u32 APK_offset[PATH_NUM] = {
+ rConfig_AntA, rConfig_AntB};
+
+ u32 APK_normal_offset[PATH_NUM] = {
+ rConfig_Pmpd_AntA, rConfig_Pmpd_AntB};
+
+ u32 APK_value[PATH_NUM] = {
+ 0x92fc0000, 0x12fc0000};
+
+ u32 APK_normal_value[PATH_NUM] = {
+ 0x92680000, 0x12680000};
+
+ s8 APK_delta_mapping[APK_BB_REG_NUM][13] = {
+ {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+ {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+ {-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+ {-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+ {-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0}
+ };
+
+ u32 APK_normal_setting_value_1[13] = {
+ 0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28,
+ 0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3,
+ 0x12680000, 0x00880000, 0x00880000
+ };
+
+ u32 APK_normal_setting_value_2[16] = {
+ 0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3,
+ 0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025,
+ 0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008,
+ 0x00050006
+ };
+
+ u32 APK_result[PATH_NUM][APK_BB_REG_NUM]; /* val_1_1a, val_1_2a, val_2a, val_3a, val_4a */
+ s32 BB_offset, delta_V, delta_offset;
+
+ if (*(dm_odm->mp_mode) == 1) {
+ struct mpt_context *pMptCtx = &(adapt->mppriv.MptCtx);
+ pMptCtx->APK_bound[0] = 45;
+ pMptCtx->APK_bound[1] = 52;
+ }
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("==>phy_APCalibrate_8188E() delta %d\n", delta));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("AP Calibration for %s\n", (is2t ? "2T2R" : "1T1R")));
+ if (!is2t)
+ pathbound = 1;
+
+ /* 2 FOR NORMAL CHIP SETTINGS */
+
+/* Temporarily do not allow normal driver to do the following settings
+ * because these offset and value will cause RF internal PA to be
+ * unpredictably disabled by HW, such that RF Tx signal will disappear
+ * after disable/enable card many times on 88CU. RF SD and DD have not
+ * find the root cause, so we remove these actions temporarily.
+ */
+ if (*(dm_odm->mp_mode) != 1)
+ return;
+ /* settings adjust for normal chip */
+ for (index = 0; index < PATH_NUM; index++) {
+ APK_offset[index] = APK_normal_offset[index];
+ APK_value[index] = APK_normal_value[index];
+ AFE_on_off[index] = 0x6fdb25a4;
+ }
+
+ for (index = 0; index < APK_BB_REG_NUM; index++) {
+ for (path = 0; path < pathbound; path++) {
+ APK_RF_init_value[path][index] = APK_normal_RF_init_value[path][index];
+ APK_RF_value_0[path][index] = APK_normal_RF_value_0[path][index];
+ }
+ BB_AP_MODE[index] = BB_normal_AP_MODE[index];
+ }
+
+ apkbound = 6;
+
+ /* save BB default value */
+ for (index = 0; index < APK_BB_REG_NUM; index++) {
+ if (index == 0) /* skip */
+ continue;
+ BB_backup[index] = ODM_GetBBReg(dm_odm, BB_REG[index], bMaskDWord);
+ }
+
+ /* save MAC default value */
+ _PHY_SaveMACRegisters(adapt, MAC_REG, MAC_backup);
+
+ /* save AFE default value */
+ _PHY_SaveADDARegisters(adapt, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM);
+
+ for (path = 0; path < pathbound; path++) {
+ if (path == RF_PATH_A) {
+ /* path A APK */
+ /* load APK setting */
+ /* path-A */
+ offset = rPdp_AntA;
+ for (index = 0; index < 11; index++) {
+ ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+ offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+ offset += 0x04;
+ }
+
+ ODM_SetBBReg(dm_odm, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000);
+
+ offset = rConfig_AntA;
+ for (; index < 13; index++) {
+ ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+ offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+ offset += 0x04;
+ }
+
+ /* page-B1 */
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x40000000);
+
+ /* path A */
+ offset = rPdp_AntA;
+ for (index = 0; index < 16; index++) {
+ ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_2[index]);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+ offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+
+ offset += 0x04;
+ }
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+ } else if (path == RF_PATH_B) {
+ /* path B APK */
+ /* load APK setting */
+ /* path-B */
+ offset = rPdp_AntB;
+ for (index = 0; index < 10; index++) {
+ ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+ offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+
+ offset += 0x04;
+ }
+ ODM_SetBBReg(dm_odm, rConfig_Pmpd_AntA, bMaskDWord, 0x12680000);
+ PHY_SetBBReg(adapt, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000);
+
+ offset = rConfig_AntA;
+ index = 11;
+ for (; index < 13; index++) { /* offset 0xb68, 0xb6c */
+ ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+ offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+ offset += 0x04;
+ }
+
+ /* page-B1 */
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x40000000);
+
+ /* path B */
+ offset = 0xb60;
+ for (index = 0; index < 16; index++) {
+ ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_2[index]);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+ offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+
+ offset += 0x04;
+ }
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0);
+ }
+
+ /* save RF default value */
+ regD[path] = PHY_QueryRFReg(adapt, path, RF_TXBIAS_A, bMaskDWord);
+
+ /* Path A AFE all on, path B AFE All off or vise versa */
+ for (index = 0; index < IQK_ADDA_REG_NUM; index++)
+ ODM_SetBBReg(dm_odm, AFE_REG[index], bMaskDWord, AFE_on_off[path]);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("phy_APCalibrate_8188E() offset 0xe70 %x\n",
+ ODM_GetBBReg(dm_odm, rRx_Wait_CCA, bMaskDWord)));
+
+ /* BB to AP mode */
+ if (path == 0) {
+ for (index = 0; index < APK_BB_REG_NUM; index++) {
+ if (index == 0) /* skip */
+ continue;
+ else if (index < 5)
+ ODM_SetBBReg(dm_odm, BB_REG[index], bMaskDWord, BB_AP_MODE[index]);
+ else if (BB_REG[index] == 0x870)
+ ODM_SetBBReg(dm_odm, BB_REG[index], bMaskDWord, BB_backup[index]|BIT10|BIT26);
+ else
+ ODM_SetBBReg(dm_odm, BB_REG[index], BIT10, 0x0);
+ }
+
+ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00);
+ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00);
+ } else {
+ /* path B */
+ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_B, bMaskDWord, 0x01008c00);
+ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_B, bMaskDWord, 0x01008c00);
+ }
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("phy_APCalibrate_8188E() offset 0x800 %x\n",
+ ODM_GetBBReg(dm_odm, 0x800, bMaskDWord)));
+
+ /* MAC settings */
+ _PHY_MACSettingCalibration(adapt, MAC_REG, MAC_backup);
+
+ if (path == RF_PATH_A) {
+ /* Path B to standby mode */
+ ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMaskDWord, 0x10000);
+ } else {
+ /* Path A to standby mode */
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMaskDWord, 0x10000);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE2, bMaskDWord, 0x20103);
+ }
+
+ delta_offset = ((delta+14)/2);
+ if (delta_offset < 0)
+ delta_offset = 0;
+ else if (delta_offset > 12)
+ delta_offset = 12;
+
+ /* AP calibration */
+ for (index = 0; index < APK_BB_REG_NUM; index++) {
+ if (index != 1) /* only DO PA11+PAD01001, AP RF setting */
+ continue;
+
+ tmpreg = APK_RF_init_value[path][index];
+ if (!dm_odm->RFCalibrateInfo.bAPKThermalMeterIgnore) {
+ BB_offset = (tmpreg & 0xF0000) >> 16;
+
+ if (!(tmpreg & BIT15)) /* sign bit 0 */
+ BB_offset = -BB_offset;
+
+ delta_V = APK_delta_mapping[index][delta_offset];
+
+ BB_offset += delta_V;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("phy_APCalibrate_8188E() APK index %d tmpreg 0x%x delta_V %d delta_offset %d\n",
+ index, tmpreg, delta_V, delta_offset));
+
+ if (BB_offset < 0) {
+ tmpreg = tmpreg & (~BIT15);
+ BB_offset = -BB_offset;
+ } else {
+ tmpreg = tmpreg | BIT15;
+ }
+ tmpreg = (tmpreg & 0xFFF0FFFF) | (BB_offset << 16);
+ }
+
+ ODM_SetRFReg(dm_odm, path, RF_IPA_A, bMaskDWord, 0x8992e);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xc %x\n", PHY_QueryRFReg(adapt, path, RF_IPA_A, bMaskDWord)));
+ ODM_SetRFReg(dm_odm, path, RF_AC, bMaskDWord, APK_RF_value_0[path][index]);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x0 %x\n", PHY_QueryRFReg(adapt, path, RF_AC, bMaskDWord)));
+ ODM_SetRFReg(dm_odm, path, RF_TXBIAS_A, bMaskDWord, tmpreg);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xd %x\n", PHY_QueryRFReg(adapt, path, RF_TXBIAS_A, bMaskDWord)));
+ /* PA11+PAD01111, one shot */
+ i = 0;
+ do {
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80000000);
+ ODM_SetBBReg(dm_odm, APK_offset[path], bMaskDWord, APK_value[0]);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", APK_offset[path], ODM_GetBBReg(dm_odm, APK_offset[path], bMaskDWord)));
+ ODM_delay_ms(3);
+ ODM_SetBBReg(dm_odm, APK_offset[path], bMaskDWord, APK_value[1]);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", APK_offset[path], ODM_GetBBReg(dm_odm, APK_offset[path], bMaskDWord)));
+
+ ODM_delay_ms(20);
+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+
+ if (path == RF_PATH_A)
+ tmpreg = ODM_GetBBReg(dm_odm, rAPK, 0x03E00000);
+ else
+ tmpreg = ODM_GetBBReg(dm_odm, rAPK, 0xF8000000);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xbd8[25:21] %x\n", tmpreg));
+
+ i++;
+ } while (tmpreg > apkbound && i < 4);
+
+ APK_result[path][index] = tmpreg;
+ }
+ }
+
+ /* reload MAC default value */
+ _PHY_ReloadMACRegisters(adapt, MAC_REG, MAC_backup);
+
+ /* reload BB default value */
+ for (index = 0; index < APK_BB_REG_NUM; index++) {
+ if (index == 0) /* skip */
+ continue;
+ ODM_SetBBReg(dm_odm, BB_REG[index], bMaskDWord, BB_backup[index]);
+ }
+
+ /* reload AFE default value */
+ reload_adda_reg(adapt, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM);
+
+ /* reload RF path default value */
+ for (path = 0; path < pathbound; path++) {
+ ODM_SetRFReg(dm_odm, path, 0xd, bMaskDWord, regD[path]);
+ if (path == RF_PATH_B) {
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f);
+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE2, bMaskDWord, 0x20101);
+ }
+
+ /* note no index == 0 */
+ if (APK_result[path][1] > 6)
+ APK_result[path][1] = 6;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("apk path %d result %d 0x%x \t", path, 1, APK_result[path][1]));
+ }
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("\n"));
+
+ for (path = 0; path < pathbound; path++) {
+ ODM_SetRFReg(dm_odm, path, 0x3, bMaskDWord,
+ ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (APK_result[path][1] << 5) | APK_result[path][1]));
+ if (path == RF_PATH_A)
+ ODM_SetRFReg(dm_odm, path, 0x4, bMaskDWord,
+ ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x00 << 5) | 0x05));
+ else
+ ODM_SetRFReg(dm_odm, path, 0x4, bMaskDWord,
+ ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x02 << 5) | 0x05));
+ ODM_SetRFReg(dm_odm, path, RF_BS_PA_APSET_G9_G11, bMaskDWord,
+ ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) | 0x08));
+ }
+
+ dm_odm->RFCalibrateInfo.bAPKdone = true;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("<==phy_APCalibrate_8188E()\n"));
+}
+
+#define DP_BB_REG_NUM 7
+#define DP_RF_REG_NUM 1
+#define DP_RETRY_LIMIT 10
+#define DP_PATH_NUM 2
+#define DP_DPK_NUM 3
+#define DP_DPK_VALUE_NUM 2
+
+void PHY_IQCalibrate_8188E(struct adapter *adapt, bool recovery)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ struct mpt_context *pMptCtx = &(adapt->mppriv.MptCtx);
+ s32 result[4][8]; /* last is final result */
+ u8 i, final_candidate, Indexforchannel;
+ bool pathaok, pathbok;
+ s32 RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC;
+ bool is12simular, is13simular, is23simular;
+ bool singletone = false, carrier_sup = false;
+ u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = {
+ rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance,
+ rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable,
+ rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance,
+ rOFDM0_XCTxAFE, rOFDM0_XDTxAFE,
+ rOFDM0_RxIQExtAnta};
+ bool is2t;
+
+ is2t = (dm_odm->RFType == ODM_2T2R) ? true : false;
+ if (ODM_CheckPowerStatus(adapt) == false)
+ return;
+
+ if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION))
+ return;
+
+ if (*(dm_odm->mp_mode) == 1) {
+ singletone = pMptCtx->bSingleTone;
+ carrier_sup = pMptCtx->bCarrierSuppression;
+ }
+
+ /* 20120213<Kordan> Turn on when continuous Tx to pass lab testing. (required by Edlu) */
+ if (singletone || carrier_sup)
+ return;
+
+ if (recovery) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("PHY_IQCalibrate_8188E: Return due to recovery!\n"));
+ reload_adda_reg(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup_recover, 9);
+ return;
+ }
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Start!!!\n"));
+
+ for (i = 0; i < 8; i++) {
+ result[0][i] = 0;
+ result[1][i] = 0;
+ result[2][i] = 0;
+ if ((i == 0) || (i == 2) || (i == 4) || (i == 6))
+ result[3][i] = 0x100;
+ else
+ result[3][i] = 0;
+ }
+ final_candidate = 0xff;
+ pathaok = false;
+ pathbok = false;
+ is12simular = false;
+ is23simular = false;
+ is13simular = false;
+
+ for (i = 0; i < 3; i++) {
+ phy_IQCalibrate_8188E(adapt, result, i, is2t);
+
+ if (i == 1) {
+ is12simular = phy_SimularityCompare_8188E(adapt, result, 0, 1);
+ if (is12simular) {
+ final_candidate = 0;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is12simular final_candidate is %x\n", final_candidate));
+ break;
+ }
+ }
+
+ if (i == 2) {
+ is13simular = phy_SimularityCompare_8188E(adapt, result, 0, 2);
+ if (is13simular) {
+ final_candidate = 0;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is13simular final_candidate is %x\n", final_candidate));
+
+ break;
+ }
+ is23simular = phy_SimularityCompare_8188E(adapt, result, 1, 2);
+ if (is23simular) {
+ final_candidate = 1;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is23simular final_candidate is %x\n", final_candidate));
+ } else {
+ final_candidate = 3;
+ }
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ RegE94 = result[i][0];
+ RegE9C = result[i][1];
+ RegEA4 = result[i][2];
+ RegEAC = result[i][3];
+ RegEB4 = result[i][4];
+ RegEBC = result[i][5];
+ RegEC4 = result[i][6];
+ RegECC = result[i][7];
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n",
+ RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC));
+ }
+
+ if (final_candidate != 0xff) {
+ RegE94 = result[final_candidate][0];
+ RegE9C = result[final_candidate][1];
+ RegEA4 = result[final_candidate][2];
+ RegEAC = result[final_candidate][3];
+ RegEB4 = result[final_candidate][4];
+ RegEBC = result[final_candidate][5];
+ dm_odm->RFCalibrateInfo.RegE94 = RegE94;
+ dm_odm->RFCalibrateInfo.RegE9C = RegE9C;
+ dm_odm->RFCalibrateInfo.RegEB4 = RegEB4;
+ dm_odm->RFCalibrateInfo.RegEBC = RegEBC;
+ RegEC4 = result[final_candidate][6];
+ RegECC = result[final_candidate][7];
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("IQK: final_candidate is %x\n", final_candidate));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n",
+ RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC));
+ pathaok = true;
+ pathbok = true;
+ } else {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: FAIL use default value\n"));
+ dm_odm->RFCalibrateInfo.RegE94 = 0x100;
+ dm_odm->RFCalibrateInfo.RegEB4 = 0x100; /* X default value */
+ dm_odm->RFCalibrateInfo.RegE9C = 0x0;
+ dm_odm->RFCalibrateInfo.RegEBC = 0x0; /* Y default value */
+ }
+ if (RegE94 != 0)
+ patha_fill_iqk(adapt, pathaok, result, final_candidate, (RegEA4 == 0));
+ if (is2t) {
+ if (RegEB4 != 0)
+ pathb_fill_iqk(adapt, pathbok, result, final_candidate, (RegEC4 == 0));
+ }
+
+ Indexforchannel = ODM_GetRightChnlPlaceforIQK(pHalData->CurrentChannel);
+
+/* To Fix BSOD when final_candidate is 0xff */
+/* by sherry 20120321 */
+ if (final_candidate < 4) {
+ for (i = 0; i < IQK_Matrix_REG_NUM; i++)
+ dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][i] = result[final_candidate][i];
+ dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].bIQKDone = true;
+ }
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("\nIQK OK Indexforchannel %d.\n", Indexforchannel));
+
+ _PHY_SaveADDARegisters(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup_recover, 9);
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK finished\n"));
+}
+
+void PHY_LCCalibrate_8188E(struct adapter *adapt)
+{
+ bool singletone = false, carrier_sup = false;
+ u32 timeout = 2000, timecount = 0;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+ struct mpt_context *pMptCtx = &(adapt->mppriv.MptCtx);
+
+ if (*(dm_odm->mp_mode) == 1) {
+ singletone = pMptCtx->bSingleTone;
+ carrier_sup = pMptCtx->bCarrierSuppression;
+ }
+ if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION))
+ return;
+ /* 20120213<Kordan> Turn on when continuous Tx to pass lab testing. (required by Edlu) */
+ if (singletone || carrier_sup)
+ return;
+
+ while (*(dm_odm->pbScanInProcess) && timecount < timeout) {
+ ODM_delay_ms(50);
+ timecount += 50;
+ }
+
+ dm_odm->RFCalibrateInfo.bLCKInProgress = true;
+
+ if (dm_odm->RFType == ODM_2T2R) {
+ phy_LCCalibrate_8188E(adapt, true);
+ } else {
+ /* For 88C 1T1R */
+ phy_LCCalibrate_8188E(adapt, false);
+ }
+
+ dm_odm->RFCalibrateInfo.bLCKInProgress = false;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+ ("LCK:Finish!!!interface %d\n", dm_odm->InterfaceIndex));
+}
+
+void PHY_APCalibrate_8188E(struct adapter *adapt, s8 delta)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ return;
+ if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION))
+ return;
+
+#if FOR_BRAZIL_PRETEST != 1
+ if (dm_odm->RFCalibrateInfo.bAPKdone)
+#endif
+ return;
+
+ if (dm_odm->RFType == ODM_2T2R) {
+ phy_APCalibrate_8188E(adapt, delta, true);
+ } else {
+ /* For 88C 1T1R */
+ phy_APCalibrate_8188E(adapt, delta, false);
+ }
+}
+
+static void phy_setrfpathswitch_8188e(struct adapter *adapt, bool main, bool is2t)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ if (!adapt->hw_init_completed) {
+ u8 u1btmp;
+ u1btmp = ODM_Read1Byte(dm_odm, REG_LEDCFG2) | BIT7;
+ ODM_Write1Byte(dm_odm, REG_LEDCFG2, u1btmp);
+ ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFParameter, BIT13, 0x01);
+ }
+
+ if (is2t) { /* 92C */
+ if (main)
+ ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x1); /* 92C_Path_A */
+ else
+ ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x2); /* BT */
+ } else { /* 88C */
+ if (main)
+ ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9, 0x2); /* Main */
+ else
+ ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9, 0x1); /* Aux */
+ }
+}
+
+void PHY_SetRFPathSwitch_8188E(struct adapter *adapt, bool main)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+ if (dm_odm->RFType == ODM_2T2R) {
+ phy_setrfpathswitch_8188e(adapt, main, true);
+ } else {
+ /* For 88C 1T1R */
+ phy_setrfpathswitch_8188e(adapt, main, false);
+ }
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c b/drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c
new file mode 100644
index 00000000000..e913a22a642
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c
@@ -0,0 +1,132 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+/*++
+Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+
+Module Name:
+ HalPwrSeqCmd.c
+
+Abstract:
+ Implement HW Power sequence configuration CMD handling routine for Realtek devices.
+
+Major Change History:
+ When Who What
+ ---------- --------------- -------------------------------
+ 2011-10-26 Lucas Modify to be compatible with SD4-CE driver.
+ 2011-07-07 Roger Create.
+
+--*/
+
+#include <HalPwrSeqCmd.h>
+
+/* Description: */
+/* This routine deals with the Power Configuration CMDs parsing
+ * for RTL8723/RTL8188E Series IC.
+ * Assumption:
+ * We should follow specific format which was released from HW SD.
+ */
+u8 HalPwrSeqCmdParsing(struct adapter *padapter, u8 cut_vers, u8 fab_vers,
+ u8 ifacetype, struct wl_pwr_cfg pwrseqcmd[])
+{
+ struct wl_pwr_cfg pwrcfgcmd = {0};
+ u8 poll_bit = false;
+ u32 aryidx = 0;
+ u8 value = 0;
+ u32 offset = 0;
+ u32 poll_count = 0; /* polling autoload done. */
+ u32 max_poll_count = 5000;
+
+ do {
+ pwrcfgcmd = pwrseqcmd[aryidx];
+
+ RT_TRACE(_module_hal_init_c_ , _drv_info_,
+ ("HalPwrSeqCmdParsing: offset(%#x) cut_msk(%#x) fab_msk(%#x) interface_msk(%#x) base(%#x) cmd(%#x) msk(%#x) value(%#x)\n",
+ GET_PWR_CFG_OFFSET(pwrcfgcmd),
+ GET_PWR_CFG_CUT_MASK(pwrcfgcmd),
+ GET_PWR_CFG_FAB_MASK(pwrcfgcmd),
+ GET_PWR_CFG_INTF_MASK(pwrcfgcmd),
+ GET_PWR_CFG_BASE(pwrcfgcmd),
+ GET_PWR_CFG_CMD(pwrcfgcmd),
+ GET_PWR_CFG_MASK(pwrcfgcmd),
+ GET_PWR_CFG_VALUE(pwrcfgcmd)));
+
+ /* 2 Only Handle the command whose FAB, CUT, and Interface are matched */
+ if ((GET_PWR_CFG_FAB_MASK(pwrcfgcmd) & fab_vers) &&
+ (GET_PWR_CFG_CUT_MASK(pwrcfgcmd) & cut_vers) &&
+ (GET_PWR_CFG_INTF_MASK(pwrcfgcmd) & ifacetype)) {
+ switch (GET_PWR_CFG_CMD(pwrcfgcmd)) {
+ case PWR_CMD_READ:
+ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_READ\n"));
+ break;
+ case PWR_CMD_WRITE:
+ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_WRITE\n"));
+ offset = GET_PWR_CFG_OFFSET(pwrcfgcmd);
+
+ /* Read the value from system register */
+ value = rtw_read8(padapter, offset);
+
+ value &= ~(GET_PWR_CFG_MASK(pwrcfgcmd));
+ value |= (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd));
+
+ /* Write the value back to sytem register */
+ rtw_write8(padapter, offset, value);
+ break;
+ case PWR_CMD_POLLING:
+ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_POLLING\n"));
+
+ poll_bit = false;
+ offset = GET_PWR_CFG_OFFSET(pwrcfgcmd);
+ do {
+ value = rtw_read8(padapter, offset);
+
+ value &= GET_PWR_CFG_MASK(pwrcfgcmd);
+ if (value == (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd)))
+ poll_bit = true;
+ else
+ rtw_udelay_os(10);
+
+ if (poll_count++ > max_poll_count) {
+ DBG_88E("Fail to polling Offset[%#x]\n", offset);
+ return false;
+ }
+ } while (!poll_bit);
+ break;
+ case PWR_CMD_DELAY:
+ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_DELAY\n"));
+ if (GET_PWR_CFG_VALUE(pwrcfgcmd) == PWRSEQ_DELAY_US)
+ rtw_udelay_os(GET_PWR_CFG_OFFSET(pwrcfgcmd));
+ else
+ rtw_udelay_os(GET_PWR_CFG_OFFSET(pwrcfgcmd)*1000);
+ break;
+ case PWR_CMD_END:
+ /* When this command is parsed, end the process */
+ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_END\n"));
+ return true;
+ break;
+ default:
+ RT_TRACE(_module_hal_init_c_ , _drv_err_, ("HalPwrSeqCmdParsing: Unknown CMD!!\n"));
+ break;
+ }
+ }
+
+ aryidx++;/* Add Array Index */
+ } while (1);
+ return true;
+}
diff --git a/drivers/staging/rtl8188eu/hal/hal_com.c b/drivers/staging/rtl8188eu/hal/hal_com.c
new file mode 100644
index 00000000000..829b900ee93
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/hal_com.c
@@ -0,0 +1,381 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <hal_intf.h>
+#include <hal_com.h>
+#include <rtl8188e_hal.h>
+
+#define _HAL_INIT_C_
+
+void dump_chip_info(struct HAL_VERSION chip_vers)
+{
+ uint cnt = 0;
+ char buf[128];
+
+ if (IS_81XXC(chip_vers)) {
+ cnt += sprintf((buf+cnt), "Chip Version Info: %s_",
+ IS_92C_SERIAL(chip_vers) ?
+ "CHIP_8192C" : "CHIP_8188C");
+ } else if (IS_92D(chip_vers)) {
+ cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8192D_");
+ } else if (IS_8723_SERIES(chip_vers)) {
+ cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8723A_");
+ } else if (IS_8188E(chip_vers)) {
+ cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8188E_");
+ }
+
+ cnt += sprintf((buf+cnt), "%s_", IS_NORMAL_CHIP(chip_vers) ?
+ "Normal_Chip" : "Test_Chip");
+ cnt += sprintf((buf+cnt), "%s_", IS_CHIP_VENDOR_TSMC(chip_vers) ?
+ "TSMC" : "UMC");
+ if (IS_A_CUT(chip_vers))
+ cnt += sprintf((buf+cnt), "A_CUT_");
+ else if (IS_B_CUT(chip_vers))
+ cnt += sprintf((buf+cnt), "B_CUT_");
+ else if (IS_C_CUT(chip_vers))
+ cnt += sprintf((buf+cnt), "C_CUT_");
+ else if (IS_D_CUT(chip_vers))
+ cnt += sprintf((buf+cnt), "D_CUT_");
+ else if (IS_E_CUT(chip_vers))
+ cnt += sprintf((buf+cnt), "E_CUT_");
+ else
+ cnt += sprintf((buf+cnt), "UNKNOWN_CUT(%d)_",
+ chip_vers.CUTVersion);
+
+ if (IS_1T1R(chip_vers))
+ cnt += sprintf((buf+cnt), "1T1R_");
+ else if (IS_1T2R(chip_vers))
+ cnt += sprintf((buf+cnt), "1T2R_");
+ else if (IS_2T2R(chip_vers))
+ cnt += sprintf((buf+cnt), "2T2R_");
+ else
+ cnt += sprintf((buf+cnt), "UNKNOWN_RFTYPE(%d)_",
+ chip_vers.RFType);
+
+ cnt += sprintf((buf+cnt), "RomVer(%d)\n", chip_vers.ROMVer);
+
+ pr_info("%s", buf);
+}
+
+#define CHAN_PLAN_HW 0x80
+
+u8 /* return the final channel plan decision */
+hal_com_get_channel_plan(struct adapter *padapter, u8 hw_channel_plan,
+ u8 sw_channel_plan, u8 def_channel_plan,
+ bool load_fail)
+{
+ u8 sw_cfg;
+ u8 chnlplan;
+
+ sw_cfg = true;
+ if (!load_fail) {
+ if (!rtw_is_channel_plan_valid(sw_channel_plan))
+ sw_cfg = false;
+ if (hw_channel_plan & CHAN_PLAN_HW)
+ sw_cfg = false;
+ }
+
+ if (sw_cfg)
+ chnlplan = sw_channel_plan;
+ else
+ chnlplan = hw_channel_plan & (~CHAN_PLAN_HW);
+
+ if (!rtw_is_channel_plan_valid(chnlplan))
+ chnlplan = def_channel_plan;
+
+ return chnlplan;
+}
+
+u8 MRateToHwRate(u8 rate)
+{
+ u8 ret = DESC_RATE1M;
+
+ switch (rate) {
+ /* CCK and OFDM non-HT rates */
+ case IEEE80211_CCK_RATE_1MB:
+ ret = DESC_RATE1M;
+ break;
+ case IEEE80211_CCK_RATE_2MB:
+ ret = DESC_RATE2M;
+ break;
+ case IEEE80211_CCK_RATE_5MB:
+ ret = DESC_RATE5_5M;
+ break;
+ case IEEE80211_CCK_RATE_11MB:
+ ret = DESC_RATE11M;
+ break;
+ case IEEE80211_OFDM_RATE_6MB:
+ ret = DESC_RATE6M;
+ break;
+ case IEEE80211_OFDM_RATE_9MB:
+ ret = DESC_RATE9M;
+ break;
+ case IEEE80211_OFDM_RATE_12MB:
+ ret = DESC_RATE12M;
+ break;
+ case IEEE80211_OFDM_RATE_18MB:
+ ret = DESC_RATE18M;
+ break;
+ case IEEE80211_OFDM_RATE_24MB:
+ ret = DESC_RATE24M;
+ break;
+ case IEEE80211_OFDM_RATE_36MB:
+ ret = DESC_RATE36M;
+ break;
+ case IEEE80211_OFDM_RATE_48MB:
+ ret = DESC_RATE48M;
+ break;
+ case IEEE80211_OFDM_RATE_54MB:
+ ret = DESC_RATE54M;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+void HalSetBrateCfg(struct adapter *adapt, u8 *brates, u16 *rate_cfg)
+{
+ u8 i, is_brate, brate;
+
+ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+ is_brate = brates[i] & IEEE80211_BASIC_RATE_MASK;
+ brate = brates[i] & 0x7f;
+
+ if (is_brate) {
+ switch (brate) {
+ case IEEE80211_CCK_RATE_1MB:
+ *rate_cfg |= RATE_1M;
+ break;
+ case IEEE80211_CCK_RATE_2MB:
+ *rate_cfg |= RATE_2M;
+ break;
+ case IEEE80211_CCK_RATE_5MB:
+ *rate_cfg |= RATE_5_5M;
+ break;
+ case IEEE80211_CCK_RATE_11MB:
+ *rate_cfg |= RATE_11M;
+ break;
+ case IEEE80211_OFDM_RATE_6MB:
+ *rate_cfg |= RATE_6M;
+ break;
+ case IEEE80211_OFDM_RATE_9MB:
+ *rate_cfg |= RATE_9M;
+ break;
+ case IEEE80211_OFDM_RATE_12MB:
+ *rate_cfg |= RATE_12M;
+ break;
+ case IEEE80211_OFDM_RATE_18MB:
+ *rate_cfg |= RATE_18M;
+ break;
+ case IEEE80211_OFDM_RATE_24MB:
+ *rate_cfg |= RATE_24M;
+ break;
+ case IEEE80211_OFDM_RATE_36MB:
+ *rate_cfg |= RATE_36M;
+ break;
+ case IEEE80211_OFDM_RATE_48MB:
+ *rate_cfg |= RATE_48M;
+ break;
+ case IEEE80211_OFDM_RATE_54MB:
+ *rate_cfg |= RATE_54M;
+ break;
+ }
+ }
+ }
+}
+
+static void one_out_pipe(struct adapter *adapter)
+{
+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter);
+
+ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
+ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */
+ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];/* BE */
+ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */
+
+ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
+ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
+ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
+ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
+}
+
+static void two_out_pipe(struct adapter *adapter, bool wifi_cfg)
+{
+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter);
+
+ if (wifi_cfg) { /* WMM */
+ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */
+ /* 0, 1, 0, 1, 0, 0, 0, 0, 0}; */
+ /* 0:H, 1:L */
+
+ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1];/* VO */
+ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */
+ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */
+ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */
+
+ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
+ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
+ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
+ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
+
+ } else {/* typical setting */
+ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */
+ /* 1, 1, 0, 0, 0, 0, 0, 0, 0}; */
+ /* 0:H, 1:L */
+
+ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
+ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */
+ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */
+ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */
+
+ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
+ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
+ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
+ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
+ }
+}
+
+static void three_out_pipe(struct adapter *adapter, bool wifi_cfg)
+{
+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter);
+
+ if (wifi_cfg) {/* for WMM */
+ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */
+ /* 1, 2, 1, 0, 0, 0, 0, 0, 0}; */
+ /* 0:H, 1:N, 2:L */
+
+ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
+ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */
+ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */
+ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */
+
+ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
+ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
+ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
+ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
+
+ } else {/* typical setting */
+ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */
+ /* 2, 2, 1, 0, 0, 0, 0, 0, 0}; */
+ /* 0:H, 1:N, 2:L */
+
+ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
+ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */
+ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */
+ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];/* BK */
+
+ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
+ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
+ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
+ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
+ }
+}
+
+bool Hal_MappingOutPipe(struct adapter *adapter, u8 numoutpipe)
+{
+ struct registry_priv *pregistrypriv = &adapter->registrypriv;
+ bool wifi_cfg = (pregistrypriv->wifi_spec) ? true : false;
+ bool result = true;
+
+ switch (numoutpipe) {
+ case 2:
+ two_out_pipe(adapter, wifi_cfg);
+ break;
+ case 3:
+ three_out_pipe(adapter, wifi_cfg);
+ break;
+ case 1:
+ one_out_pipe(adapter);
+ break;
+ default:
+ result = false;
+ break;
+ }
+ return result;
+}
+
+void hal_init_macaddr(struct adapter *adapter)
+{
+ rtw_hal_set_hwreg(adapter, HW_VAR_MAC_ADDR,
+ adapter->eeprompriv.mac_addr);
+}
+
+/*
+* C2H event format:
+* Field TRIGGER CONTENT CMD_SEQ CMD_LEN CMD_ID
+* BITS [127:120] [119:16] [15:8] [7:4] [3:0]
+*/
+
+void c2h_evt_clear(struct adapter *adapter)
+{
+ rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
+}
+
+s32 c2h_evt_read(struct adapter *adapter, u8 *buf)
+{
+ s32 ret = _FAIL;
+ struct c2h_evt_hdr *c2h_evt;
+ int i;
+ u8 trigger;
+
+ if (buf == NULL)
+ goto exit;
+
+ trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR);
+
+ if (trigger == C2H_EVT_HOST_CLOSE)
+ goto exit; /* Not ready */
+ else if (trigger != C2H_EVT_FW_CLOSE)
+ goto clear_evt; /* Not a valid value */
+
+ c2h_evt = (struct c2h_evt_hdr *)buf;
+
+ _rtw_memset(c2h_evt, 0, 16);
+
+ *buf = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL);
+ *(buf+1) = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1);
+
+ RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read(): ",
+ &c2h_evt , sizeof(c2h_evt));
+
+ /* Read the content */
+ for (i = 0; i < c2h_evt->plen; i++)
+ c2h_evt->payload[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL +
+ sizeof(*c2h_evt) + i);
+
+ RT_PRINT_DATA(_module_hal_init_c_, _drv_info_,
+ "c2h_evt_read(): Command Content:\n",
+ c2h_evt->payload, c2h_evt->plen);
+
+ ret = _SUCCESS;
+
+clear_evt:
+ /*
+ * Clear event to notify FW we have read the command.
+ * If this field isn't clear, the FW won't update the next
+ * command message.
+ */
+ c2h_evt_clear(adapter);
+exit:
+ return ret;
+}
diff --git a/drivers/staging/rtl8188eu/hal/hal_intf.c b/drivers/staging/rtl8188eu/hal/hal_intf.c
new file mode 100644
index 00000000000..598140464f0
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/hal_intf.c
@@ -0,0 +1,464 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#define _HAL_INTF_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <hal_intf.h>
+#include <usb_hal.h>
+
+void rtw_hal_chip_configure(struct adapter *adapt)
+{
+ if (adapt->HalFunc.intf_chip_configure)
+ adapt->HalFunc.intf_chip_configure(adapt);
+}
+
+void rtw_hal_read_chip_info(struct adapter *adapt)
+{
+ if (adapt->HalFunc.read_adapter_info)
+ adapt->HalFunc.read_adapter_info(adapt);
+}
+
+void rtw_hal_read_chip_version(struct adapter *adapt)
+{
+ if (adapt->HalFunc.read_chip_version)
+ adapt->HalFunc.read_chip_version(adapt);
+}
+
+void rtw_hal_def_value_init(struct adapter *adapt)
+{
+ if (adapt->HalFunc.init_default_value)
+ adapt->HalFunc.init_default_value(adapt);
+}
+
+void rtw_hal_free_data(struct adapter *adapt)
+{
+ if (adapt->HalFunc.free_hal_data)
+ adapt->HalFunc.free_hal_data(adapt);
+}
+
+void rtw_hal_dm_init(struct adapter *adapt)
+{
+ if (adapt->HalFunc.dm_init)
+ adapt->HalFunc.dm_init(adapt);
+}
+
+void rtw_hal_dm_deinit(struct adapter *adapt)
+{
+ /* cancel dm timer */
+ if (adapt->HalFunc.dm_deinit)
+ adapt->HalFunc.dm_deinit(adapt);
+}
+
+void rtw_hal_sw_led_init(struct adapter *adapt)
+{
+ if (adapt->HalFunc.InitSwLeds)
+ adapt->HalFunc.InitSwLeds(adapt);
+}
+
+void rtw_hal_sw_led_deinit(struct adapter *adapt)
+{
+ if (adapt->HalFunc.DeInitSwLeds)
+ adapt->HalFunc.DeInitSwLeds(adapt);
+}
+
+u32 rtw_hal_power_on(struct adapter *adapt)
+{
+ if (adapt->HalFunc.hal_power_on)
+ return adapt->HalFunc.hal_power_on(adapt);
+ return _FAIL;
+}
+
+uint rtw_hal_init(struct adapter *adapt)
+{
+ uint status = _SUCCESS;
+
+ adapt->hw_init_completed = false;
+
+ status = adapt->HalFunc.hal_init(adapt);
+
+ if (status == _SUCCESS) {
+ adapt->hw_init_completed = true;
+
+ if (adapt->registrypriv.notch_filter == 1)
+ rtw_hal_notch_filter(adapt, 1);
+
+ rtw_hal_reset_security_engine(adapt);
+ } else {
+ adapt->hw_init_completed = false;
+ DBG_88E("rtw_hal_init: hal__init fail\n");
+ }
+
+ RT_TRACE(_module_hal_init_c_, _drv_err_,
+ ("-rtl871x_hal_init:status=0x%x\n", status));
+
+ return status;
+}
+
+uint rtw_hal_deinit(struct adapter *adapt)
+{
+ uint status = _SUCCESS;
+
+_func_enter_;
+
+ status = adapt->HalFunc.hal_deinit(adapt);
+
+ if (status == _SUCCESS)
+ adapt->hw_init_completed = false;
+ else
+ DBG_88E("\n rtw_hal_deinit: hal_init fail\n");
+
+_func_exit_;
+
+ return status;
+}
+
+void rtw_hal_set_hwreg(struct adapter *adapt, u8 variable, u8 *val)
+{
+ if (adapt->HalFunc.SetHwRegHandler)
+ adapt->HalFunc.SetHwRegHandler(adapt, variable, val);
+}
+
+void rtw_hal_get_hwreg(struct adapter *adapt, u8 variable, u8 *val)
+{
+ if (adapt->HalFunc.GetHwRegHandler)
+ adapt->HalFunc.GetHwRegHandler(adapt, variable, val);
+}
+
+u8 rtw_hal_set_def_var(struct adapter *adapt, enum hal_def_variable var,
+ void *val)
+{
+ if (adapt->HalFunc.SetHalDefVarHandler)
+ return adapt->HalFunc.SetHalDefVarHandler(adapt, var, val);
+ return _FAIL;
+}
+
+u8 rtw_hal_get_def_var(struct adapter *adapt,
+ enum hal_def_variable var, void *val)
+{
+ if (adapt->HalFunc.GetHalDefVarHandler)
+ return adapt->HalFunc.GetHalDefVarHandler(adapt, var, val);
+ return _FAIL;
+}
+
+void rtw_hal_set_odm_var(struct adapter *adapt,
+ enum hal_odm_variable var, void *val1,
+ bool set)
+{
+ if (adapt->HalFunc.SetHalODMVarHandler)
+ adapt->HalFunc.SetHalODMVarHandler(adapt, var,
+ val1, set);
+}
+
+void rtw_hal_get_odm_var(struct adapter *adapt,
+ enum hal_odm_variable var, void *val1,
+ bool set)
+{
+ if (adapt->HalFunc.GetHalODMVarHandler)
+ adapt->HalFunc.GetHalODMVarHandler(adapt, var,
+ val1, set);
+}
+
+void rtw_hal_enable_interrupt(struct adapter *adapt)
+{
+ if (adapt->HalFunc.enable_interrupt)
+ adapt->HalFunc.enable_interrupt(adapt);
+ else
+ DBG_88E("%s: HalFunc.enable_interrupt is NULL!\n", __func__);
+}
+
+void rtw_hal_disable_interrupt(struct adapter *adapt)
+{
+ if (adapt->HalFunc.disable_interrupt)
+ adapt->HalFunc.disable_interrupt(adapt);
+ else
+ DBG_88E("%s: HalFunc.disable_interrupt is NULL!\n", __func__);
+}
+
+u32 rtw_hal_inirp_init(struct adapter *adapt)
+{
+ u32 rst = _FAIL;
+
+ if (adapt->HalFunc.inirp_init)
+ rst = adapt->HalFunc.inirp_init(adapt);
+ else
+ DBG_88E(" %s HalFunc.inirp_init is NULL!!!\n", __func__);
+ return rst;
+}
+
+u32 rtw_hal_inirp_deinit(struct adapter *adapt)
+{
+ if (adapt->HalFunc.inirp_deinit)
+ return adapt->HalFunc.inirp_deinit(adapt);
+
+ return _FAIL;
+}
+
+u8 rtw_hal_intf_ps_func(struct adapter *adapt,
+ enum hal_intf_ps_func efunc_id, u8 *val)
+{
+ if (adapt->HalFunc.interface_ps_func)
+ return adapt->HalFunc.interface_ps_func(adapt, efunc_id,
+ val);
+ return _FAIL;
+}
+
+s32 rtw_hal_xmit(struct adapter *adapt, struct xmit_frame *pxmitframe)
+{
+ if (adapt->HalFunc.hal_xmit)
+ return adapt->HalFunc.hal_xmit(adapt, pxmitframe);
+
+ return false;
+}
+
+s32 rtw_hal_mgnt_xmit(struct adapter *adapt, struct xmit_frame *pmgntframe)
+{
+ s32 ret = _FAIL;
+ if (adapt->HalFunc.mgnt_xmit)
+ ret = adapt->HalFunc.mgnt_xmit(adapt, pmgntframe);
+ return ret;
+}
+
+s32 rtw_hal_init_xmit_priv(struct adapter *adapt)
+{
+ if (adapt->HalFunc.init_xmit_priv != NULL)
+ return adapt->HalFunc.init_xmit_priv(adapt);
+ return _FAIL;
+}
+
+void rtw_hal_free_xmit_priv(struct adapter *adapt)
+{
+ if (adapt->HalFunc.free_xmit_priv != NULL)
+ adapt->HalFunc.free_xmit_priv(adapt);
+}
+
+s32 rtw_hal_init_recv_priv(struct adapter *adapt)
+{
+ if (adapt->HalFunc.init_recv_priv)
+ return adapt->HalFunc.init_recv_priv(adapt);
+
+ return _FAIL;
+}
+
+void rtw_hal_free_recv_priv(struct adapter *adapt)
+{
+ if (adapt->HalFunc.free_recv_priv)
+ adapt->HalFunc.free_recv_priv(adapt);
+}
+
+void rtw_hal_update_ra_mask(struct adapter *adapt, u32 mac_id, u8 rssi_level)
+{
+ struct mlme_priv *pmlmepriv = &(adapt->mlmepriv);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
+#ifdef CONFIG_88EU_AP_MODE
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &adapt->stapriv;
+ if ((mac_id-1) > 0)
+ psta = pstapriv->sta_aid[(mac_id-1) - 1];
+ if (psta)
+ add_RATid(adapt, psta, 0);/* todo: based on rssi_level*/
+#endif
+ } else {
+ if (adapt->HalFunc.UpdateRAMaskHandler)
+ adapt->HalFunc.UpdateRAMaskHandler(adapt, mac_id,
+ rssi_level);
+ }
+}
+
+void rtw_hal_add_ra_tid(struct adapter *adapt, u32 bitmap, u8 arg,
+ u8 rssi_level)
+{
+ if (adapt->HalFunc.Add_RateATid)
+ adapt->HalFunc.Add_RateATid(adapt, bitmap, arg,
+ rssi_level);
+}
+
+/* Start specifical interface thread */
+void rtw_hal_start_thread(struct adapter *adapt)
+{
+ if (adapt->HalFunc.run_thread)
+ adapt->HalFunc.run_thread(adapt);
+}
+
+/* Start specifical interface thread */
+void rtw_hal_stop_thread(struct adapter *adapt)
+{
+ if (adapt->HalFunc.cancel_thread)
+ adapt->HalFunc.cancel_thread(adapt);
+}
+
+u32 rtw_hal_read_bbreg(struct adapter *adapt, u32 regaddr, u32 bitmask)
+{
+ u32 data = 0;
+
+ if (adapt->HalFunc.read_bbreg)
+ data = adapt->HalFunc.read_bbreg(adapt, regaddr, bitmask);
+ return data;
+}
+
+void rtw_hal_write_bbreg(struct adapter *adapt, u32 regaddr, u32 bitmask,
+ u32 data)
+{
+ if (adapt->HalFunc.write_bbreg)
+ adapt->HalFunc.write_bbreg(adapt, regaddr, bitmask, data);
+}
+
+u32 rtw_hal_read_rfreg(struct adapter *adapt, enum rf_radio_path rfpath,
+ u32 regaddr, u32 bitmask)
+{
+ u32 data = 0;
+
+ if (adapt->HalFunc.read_rfreg)
+ data = adapt->HalFunc.read_rfreg(adapt, rfpath, regaddr,
+ bitmask);
+ return data;
+}
+
+void rtw_hal_write_rfreg(struct adapter *adapt, enum rf_radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ if (adapt->HalFunc.write_rfreg)
+ adapt->HalFunc.write_rfreg(adapt, rfpath, regaddr,
+ bitmask, data);
+}
+
+s32 rtw_hal_interrupt_handler(struct adapter *adapt)
+{
+ if (adapt->HalFunc.interrupt_handler)
+ return adapt->HalFunc.interrupt_handler(adapt);
+ return _FAIL;
+}
+
+void rtw_hal_set_bwmode(struct adapter *adapt,
+ enum ht_channel_width bandwidth, u8 offset)
+{
+ if (adapt->HalFunc.set_bwmode_handler)
+ adapt->HalFunc.set_bwmode_handler(adapt, bandwidth,
+ offset);
+}
+
+void rtw_hal_set_chan(struct adapter *adapt, u8 channel)
+{
+ if (adapt->HalFunc.set_channel_handler)
+ adapt->HalFunc.set_channel_handler(adapt, channel);
+}
+
+void rtw_hal_dm_watchdog(struct adapter *adapt)
+{
+ if (adapt->HalFunc.hal_dm_watchdog)
+ adapt->HalFunc.hal_dm_watchdog(adapt);
+}
+
+void rtw_hal_bcn_related_reg_setting(struct adapter *adapt)
+{
+ if (adapt->HalFunc.SetBeaconRelatedRegistersHandler)
+ adapt->HalFunc.SetBeaconRelatedRegistersHandler(adapt);
+}
+
+u8 rtw_hal_antdiv_before_linked(struct adapter *adapt)
+{
+ if (adapt->HalFunc.AntDivBeforeLinkHandler)
+ return adapt->HalFunc.AntDivBeforeLinkHandler(adapt);
+ return false;
+}
+
+void rtw_hal_antdiv_rssi_compared(struct adapter *adapt,
+ struct wlan_bssid_ex *dst,
+ struct wlan_bssid_ex *src)
+{
+ if (adapt->HalFunc.AntDivCompareHandler)
+ adapt->HalFunc.AntDivCompareHandler(adapt, dst, src);
+}
+
+void rtw_hal_sreset_init(struct adapter *adapt)
+{
+ if (adapt->HalFunc.sreset_init_value)
+ adapt->HalFunc.sreset_init_value(adapt);
+}
+
+void rtw_hal_sreset_reset(struct adapter *adapt)
+{
+ if (adapt->HalFunc.silentreset)
+ adapt->HalFunc.silentreset(adapt);
+}
+
+void rtw_hal_sreset_reset_value(struct adapter *adapt)
+{
+ if (adapt->HalFunc.sreset_reset_value)
+ adapt->HalFunc.sreset_reset_value(adapt);
+}
+
+void rtw_hal_sreset_xmit_status_check(struct adapter *adapt)
+{
+ if (adapt->HalFunc.sreset_xmit_status_check)
+ adapt->HalFunc.sreset_xmit_status_check(adapt);
+}
+
+void rtw_hal_sreset_linked_status_check(struct adapter *adapt)
+{
+ if (adapt->HalFunc.sreset_linked_status_check)
+ adapt->HalFunc.sreset_linked_status_check(adapt);
+}
+
+u8 rtw_hal_sreset_get_wifi_status(struct adapter *adapt)
+{
+ u8 status = 0;
+
+ if (adapt->HalFunc.sreset_get_wifi_status)
+ status = adapt->HalFunc.sreset_get_wifi_status(adapt);
+ return status;
+}
+
+int rtw_hal_iol_cmd(struct adapter *adapter, struct xmit_frame *xmit_frame,
+ u32 max_wating_ms, u32 bndy_cnt)
+{
+ if (adapter->HalFunc.IOL_exec_cmds_sync)
+ return adapter->HalFunc.IOL_exec_cmds_sync(adapter, xmit_frame,
+ max_wating_ms,
+ bndy_cnt);
+ return _FAIL;
+}
+
+void rtw_hal_notch_filter(struct adapter *adapter, bool enable)
+{
+ if (adapter->HalFunc.hal_notch_filter)
+ adapter->HalFunc.hal_notch_filter(adapter, enable);
+}
+
+void rtw_hal_reset_security_engine(struct adapter *adapter)
+{
+ if (adapter->HalFunc.hal_reset_security_engine)
+ adapter->HalFunc.hal_reset_security_engine(adapter);
+}
+
+s32 rtw_hal_c2h_handler(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt)
+{
+ s32 ret = _FAIL;
+
+ if (adapter->HalFunc.c2h_handler)
+ ret = adapter->HalFunc.c2h_handler(adapter, c2h_evt);
+ return ret;
+}
+
+c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter)
+{
+ return adapter->HalFunc.c2h_id_filter_ccx;
+}
diff --git a/drivers/staging/rtl8188eu/hal/odm.c b/drivers/staging/rtl8188eu/hal/odm.c
new file mode 100644
index 00000000000..285475f9613
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm.c
@@ -0,0 +1,2171 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+/* include files */
+
+#include "odm_precomp.h"
+
+static const u16 dB_Invert_Table[8][12] = {
+ {1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4},
+ {4, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16},
+ {18, 20, 22, 25, 28, 32, 35, 40, 45, 50, 56, 63},
+ {71, 79, 89, 100, 112, 126, 141, 158, 178, 200, 224, 251},
+ {282, 316, 355, 398, 447, 501, 562, 631, 708, 794, 891, 1000},
+ {1122, 1259, 1413, 1585, 1778, 1995, 2239, 2512, 2818, 3162, 3548, 3981},
+ {4467, 5012, 5623, 6310, 7079, 7943, 8913, 10000, 11220, 12589, 14125, 15849},
+ {17783, 19953, 22387, 25119, 28184, 31623, 35481, 39811, 44668, 50119, 56234, 65535}
+};
+
+/* avoid to warn in FreeBSD ==> To DO modify */
+static u32 EDCAParam[HT_IOT_PEER_MAX][3] = {
+ /* UL DL */
+ {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 0:unknown AP */
+ {0xa44f, 0x5ea44f, 0x5e431c}, /* 1:realtek AP */
+ {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 2:unknown AP => realtek_92SE */
+ {0x5ea32b, 0x5ea42b, 0x5e4322}, /* 3:broadcom AP */
+ {0x5ea422, 0x00a44f, 0x00a44f}, /* 4:ralink AP */
+ {0x5ea322, 0x00a630, 0x00a44f}, /* 5:atheros AP */
+ {0x5e4322, 0x5e4322, 0x5e4322},/* 6:cisco AP */
+ {0x5ea44f, 0x00a44f, 0x5ea42b}, /* 8:marvell AP */
+ {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 10:unknown AP=> 92U AP */
+ {0x5ea42b, 0xa630, 0x5e431c}, /* 11:airgocap AP */
+};
+
+/* Global var */
+u32 OFDMSwingTable[OFDM_TABLE_SIZE_92D] = {
+ 0x7f8001fe, /* 0, +6.0dB */
+ 0x788001e2, /* 1, +5.5dB */
+ 0x71c001c7, /* 2, +5.0dB */
+ 0x6b8001ae, /* 3, +4.5dB */
+ 0x65400195, /* 4, +4.0dB */
+ 0x5fc0017f, /* 5, +3.5dB */
+ 0x5a400169, /* 6, +3.0dB */
+ 0x55400155, /* 7, +2.5dB */
+ 0x50800142, /* 8, +2.0dB */
+ 0x4c000130, /* 9, +1.5dB */
+ 0x47c0011f, /* 10, +1.0dB */
+ 0x43c0010f, /* 11, +0.5dB */
+ 0x40000100, /* 12, +0dB */
+ 0x3c8000f2, /* 13, -0.5dB */
+ 0x390000e4, /* 14, -1.0dB */
+ 0x35c000d7, /* 15, -1.5dB */
+ 0x32c000cb, /* 16, -2.0dB */
+ 0x300000c0, /* 17, -2.5dB */
+ 0x2d4000b5, /* 18, -3.0dB */
+ 0x2ac000ab, /* 19, -3.5dB */
+ 0x288000a2, /* 20, -4.0dB */
+ 0x26000098, /* 21, -4.5dB */
+ 0x24000090, /* 22, -5.0dB */
+ 0x22000088, /* 23, -5.5dB */
+ 0x20000080, /* 24, -6.0dB */
+ 0x1e400079, /* 25, -6.5dB */
+ 0x1c800072, /* 26, -7.0dB */
+ 0x1b00006c, /* 27. -7.5dB */
+ 0x19800066, /* 28, -8.0dB */
+ 0x18000060, /* 29, -8.5dB */
+ 0x16c0005b, /* 30, -9.0dB */
+ 0x15800056, /* 31, -9.5dB */
+ 0x14400051, /* 32, -10.0dB */
+ 0x1300004c, /* 33, -10.5dB */
+ 0x12000048, /* 34, -11.0dB */
+ 0x11000044, /* 35, -11.5dB */
+ 0x10000040, /* 36, -12.0dB */
+ 0x0f00003c,/* 37, -12.5dB */
+ 0x0e400039,/* 38, -13.0dB */
+ 0x0d800036,/* 39, -13.5dB */
+ 0x0cc00033,/* 40, -14.0dB */
+ 0x0c000030,/* 41, -14.5dB */
+ 0x0b40002d,/* 42, -15.0dB */
+};
+
+u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8] = {
+ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */
+ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */
+ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */
+ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */
+ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */
+ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */
+ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */
+ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */
+ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */
+ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */
+ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */
+ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */
+ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB */
+ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */
+ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */
+ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */
+ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */
+ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */
+ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */
+ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */
+ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB */
+ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB */
+ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB */
+ {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB */
+ {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB */
+ {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB */
+ {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB */
+ {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB */
+ {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB */
+ {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB */
+ {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB */
+ {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB */
+ {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} /* 32, -16.0dB */
+};
+
+u8 CCKSwingTable_Ch14[CCK_TABLE_SIZE][8] = {
+ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */
+ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */
+ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */
+ {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */
+ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */
+ {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */
+ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */
+ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */
+ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */
+ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */
+ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */
+ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */
+ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB */
+ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */
+ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */
+ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */
+ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */
+ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */
+ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */
+ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */
+ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB */
+ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB */
+ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB */
+ {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB */
+ {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB */
+ {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB */
+ {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB */
+ {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB */
+ {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB */
+ {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB */
+ {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB */
+ {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB */
+ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */
+};
+
+
+#define RxDefaultAnt1 0x65a9
+#define RxDefaultAnt2 0x569a
+
+/* 3 Export Interface */
+
+/* 2011/09/21 MH Add to describe different team necessary resource allocate?? */
+void ODM_DMInit(struct odm_dm_struct *pDM_Odm)
+{
+ /* 2012.05.03 Luke: For all IC series */
+ odm_CommonInfoSelfInit(pDM_Odm);
+ odm_CmnInfoInit_Debug(pDM_Odm);
+ odm_DIGInit(pDM_Odm);
+ odm_RateAdaptiveMaskInit(pDM_Odm);
+
+ if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) {
+ ;
+ } else if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) {
+ odm_PrimaryCCA_Init(pDM_Odm); /* Gary */
+ odm_DynamicBBPowerSavingInit(pDM_Odm);
+ odm_DynamicTxPowerInit(pDM_Odm);
+ odm_TXPowerTrackingInit(pDM_Odm);
+ ODM_EdcaTurboInit(pDM_Odm);
+ ODM_RAInfo_Init_all(pDM_Odm);
+ if ((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ||
+ (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) ||
+ (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV))
+ odm_InitHybridAntDiv(pDM_Odm);
+ else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV)
+ odm_SwAntDivInit(pDM_Odm);
+ }
+}
+
+/* 2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. */
+/* You can not add any dummy function here, be care, you can only use DM structure */
+/* to perform any new ODM_DM. */
+void ODM_DMWatchdog(struct odm_dm_struct *pDM_Odm)
+{
+ /* 2012.05.03 Luke: For all IC series */
+ odm_GlobalAdapterCheck();
+ odm_CmnInfoHook_Debug(pDM_Odm);
+ odm_CmnInfoUpdate_Debug(pDM_Odm);
+ odm_CommonInfoSelfUpdate(pDM_Odm);
+ odm_FalseAlarmCounterStatistics(pDM_Odm);
+ odm_RSSIMonitorCheck(pDM_Odm);
+
+ /* For CE Platform(SPRD or Tablet) */
+ /* 8723A or 8189ES platform */
+ /* NeilChen--2012--08--24-- */
+ /* Fix Leave LPS issue */
+ if ((pDM_Odm->Adapter->pwrctrlpriv.pwr_mode != PS_MODE_ACTIVE) &&/* in LPS mode */
+ ((pDM_Odm->SupportICType & (ODM_RTL8723A)) ||
+ (pDM_Odm->SupportICType & (ODM_RTL8188E) &&
+ ((pDM_Odm->SupportInterface == ODM_ITRF_SDIO))))) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG is in LPS mode\n"));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n"));
+ odm_DIGbyRSSI_LPS(pDM_Odm);
+ } else {
+ odm_DIG(pDM_Odm);
+ }
+ odm_CCKPacketDetectionThresh(pDM_Odm);
+
+ if (*(pDM_Odm->pbPowerSaving))
+ return;
+
+ odm_RefreshRateAdaptiveMask(pDM_Odm);
+
+ odm_DynamicBBPowerSaving(pDM_Odm);
+ odm_DynamicPrimaryCCA(pDM_Odm);
+ if ((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ||
+ (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) ||
+ (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV))
+ odm_HwAntDiv(pDM_Odm);
+ else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV)
+ odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_PEAK);
+
+ if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) {
+ ;
+ } else if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) {
+ ODM_TXPowerTrackingCheck(pDM_Odm);
+ odm_EdcaTurboCheck(pDM_Odm);
+ odm_DynamicTxPower(pDM_Odm);
+ }
+ odm_dtc(pDM_Odm);
+}
+
+/* Init /.. Fixed HW value. Only init time. */
+void ODM_CmnInfoInit(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, u32 Value)
+{
+ /* This section is used for init value */
+ switch (CmnInfo) {
+ /* Fixed ODM value. */
+ case ODM_CMNINFO_ABILITY:
+ pDM_Odm->SupportAbility = (u32)Value;
+ break;
+ case ODM_CMNINFO_PLATFORM:
+ pDM_Odm->SupportPlatform = (u8)Value;
+ break;
+ case ODM_CMNINFO_INTERFACE:
+ pDM_Odm->SupportInterface = (u8)Value;
+ break;
+ case ODM_CMNINFO_MP_TEST_CHIP:
+ pDM_Odm->bIsMPChip = (u8)Value;
+ break;
+ case ODM_CMNINFO_IC_TYPE:
+ pDM_Odm->SupportICType = Value;
+ break;
+ case ODM_CMNINFO_CUT_VER:
+ pDM_Odm->CutVersion = (u8)Value;
+ break;
+ case ODM_CMNINFO_FAB_VER:
+ pDM_Odm->FabVersion = (u8)Value;
+ break;
+ case ODM_CMNINFO_RF_TYPE:
+ pDM_Odm->RFType = (u8)Value;
+ break;
+ case ODM_CMNINFO_RF_ANTENNA_TYPE:
+ pDM_Odm->AntDivType = (u8)Value;
+ break;
+ case ODM_CMNINFO_BOARD_TYPE:
+ pDM_Odm->BoardType = (u8)Value;
+ break;
+ case ODM_CMNINFO_EXT_LNA:
+ pDM_Odm->ExtLNA = (u8)Value;
+ break;
+ case ODM_CMNINFO_EXT_PA:
+ pDM_Odm->ExtPA = (u8)Value;
+ break;
+ case ODM_CMNINFO_EXT_TRSW:
+ pDM_Odm->ExtTRSW = (u8)Value;
+ break;
+ case ODM_CMNINFO_PATCH_ID:
+ pDM_Odm->PatchID = (u8)Value;
+ break;
+ case ODM_CMNINFO_BINHCT_TEST:
+ pDM_Odm->bInHctTest = (bool)Value;
+ break;
+ case ODM_CMNINFO_BWIFI_TEST:
+ pDM_Odm->bWIFITest = (bool)Value;
+ break;
+ case ODM_CMNINFO_SMART_CONCURRENT:
+ pDM_Odm->bDualMacSmartConcurrent = (bool)Value;
+ break;
+ /* To remove the compiler warning, must add an empty default statement to handle the other values. */
+ default:
+ /* do nothing */
+ break;
+ }
+
+ /* Tx power tracking BB swing table. */
+ /* The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB */
+ pDM_Odm->BbSwingIdxOfdm = 12; /* Set defalut value as index 12. */
+ pDM_Odm->BbSwingIdxOfdmCurrent = 12;
+ pDM_Odm->BbSwingFlagOfdm = false;
+}
+
+void ODM_CmnInfoHook(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, void *pValue)
+{
+ /* */
+ /* Hook call by reference pointer. */
+ /* */
+ switch (CmnInfo) {
+ /* Dynamic call by reference pointer. */
+ case ODM_CMNINFO_MAC_PHY_MODE:
+ pDM_Odm->pMacPhyMode = (u8 *)pValue;
+ break;
+ case ODM_CMNINFO_TX_UNI:
+ pDM_Odm->pNumTxBytesUnicast = (u64 *)pValue;
+ break;
+ case ODM_CMNINFO_RX_UNI:
+ pDM_Odm->pNumRxBytesUnicast = (u64 *)pValue;
+ break;
+ case ODM_CMNINFO_WM_MODE:
+ pDM_Odm->pWirelessMode = (u8 *)pValue;
+ break;
+ case ODM_CMNINFO_BAND:
+ pDM_Odm->pBandType = (u8 *)pValue;
+ break;
+ case ODM_CMNINFO_SEC_CHNL_OFFSET:
+ pDM_Odm->pSecChOffset = (u8 *)pValue;
+ break;
+ case ODM_CMNINFO_SEC_MODE:
+ pDM_Odm->pSecurity = (u8 *)pValue;
+ break;
+ case ODM_CMNINFO_BW:
+ pDM_Odm->pBandWidth = (u8 *)pValue;
+ break;
+ case ODM_CMNINFO_CHNL:
+ pDM_Odm->pChannel = (u8 *)pValue;
+ break;
+ case ODM_CMNINFO_DMSP_GET_VALUE:
+ pDM_Odm->pbGetValueFromOtherMac = (bool *)pValue;
+ break;
+ case ODM_CMNINFO_BUDDY_ADAPTOR:
+ pDM_Odm->pBuddyAdapter = (struct adapter **)pValue;
+ break;
+ case ODM_CMNINFO_DMSP_IS_MASTER:
+ pDM_Odm->pbMasterOfDMSP = (bool *)pValue;
+ break;
+ case ODM_CMNINFO_SCAN:
+ pDM_Odm->pbScanInProcess = (bool *)pValue;
+ break;
+ case ODM_CMNINFO_POWER_SAVING:
+ pDM_Odm->pbPowerSaving = (bool *)pValue;
+ break;
+ case ODM_CMNINFO_ONE_PATH_CCA:
+ pDM_Odm->pOnePathCCA = (u8 *)pValue;
+ break;
+ case ODM_CMNINFO_DRV_STOP:
+ pDM_Odm->pbDriverStopped = (bool *)pValue;
+ break;
+ case ODM_CMNINFO_PNP_IN:
+ pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = (bool *)pValue;
+ break;
+ case ODM_CMNINFO_INIT_ON:
+ pDM_Odm->pinit_adpt_in_progress = (bool *)pValue;
+ break;
+ case ODM_CMNINFO_ANT_TEST:
+ pDM_Odm->pAntennaTest = (u8 *)pValue;
+ break;
+ case ODM_CMNINFO_NET_CLOSED:
+ pDM_Odm->pbNet_closed = (bool *)pValue;
+ break;
+ case ODM_CMNINFO_MP_MODE:
+ pDM_Odm->mp_mode = (u8 *)pValue;
+ break;
+ /* To remove the compiler warning, must add an empty default statement to handle the other values. */
+ default:
+ /* do nothing */
+ break;
+ }
+}
+
+void ODM_CmnInfoPtrArrayHook(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, u16 Index, void *pValue)
+{
+ /* Hook call by reference pointer. */
+ switch (CmnInfo) {
+ /* Dynamic call by reference pointer. */
+ case ODM_CMNINFO_STA_STATUS:
+ pDM_Odm->pODM_StaInfo[Index] = (struct sta_info *)pValue;
+ break;
+ /* To remove the compiler warning, must add an empty default statement to handle the other values. */
+ default:
+ /* do nothing */
+ break;
+ }
+}
+
+/* Update Band/CHannel/.. The values are dynamic but non-per-packet. */
+void ODM_CmnInfoUpdate(struct odm_dm_struct *pDM_Odm, u32 CmnInfo, u64 Value)
+{
+ /* */
+ /* This init variable may be changed in run time. */
+ /* */
+ switch (CmnInfo) {
+ case ODM_CMNINFO_ABILITY:
+ pDM_Odm->SupportAbility = (u32)Value;
+ break;
+ case ODM_CMNINFO_RF_TYPE:
+ pDM_Odm->RFType = (u8)Value;
+ break;
+ case ODM_CMNINFO_WIFI_DIRECT:
+ pDM_Odm->bWIFI_Direct = (bool)Value;
+ break;
+ case ODM_CMNINFO_WIFI_DISPLAY:
+ pDM_Odm->bWIFI_Display = (bool)Value;
+ break;
+ case ODM_CMNINFO_LINK:
+ pDM_Odm->bLinked = (bool)Value;
+ break;
+ case ODM_CMNINFO_RSSI_MIN:
+ pDM_Odm->RSSI_Min = (u8)Value;
+ break;
+ case ODM_CMNINFO_DBG_COMP:
+ pDM_Odm->DebugComponents = Value;
+ break;
+ case ODM_CMNINFO_DBG_LEVEL:
+ pDM_Odm->DebugLevel = (u32)Value;
+ break;
+ case ODM_CMNINFO_RA_THRESHOLD_HIGH:
+ pDM_Odm->RateAdaptive.HighRSSIThresh = (u8)Value;
+ break;
+ case ODM_CMNINFO_RA_THRESHOLD_LOW:
+ pDM_Odm->RateAdaptive.LowRSSIThresh = (u8)Value;
+ break;
+ }
+}
+
+void odm_CommonInfoSelfInit(struct odm_dm_struct *pDM_Odm)
+{
+ pDM_Odm->bCckHighPower = (bool) ODM_GetBBReg(pDM_Odm, 0x824, BIT9);
+ pDM_Odm->RFPathRxEnable = (u8) ODM_GetBBReg(pDM_Odm, 0xc04, 0x0F);
+ if (pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8192D))
+ pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV;
+ if (pDM_Odm->SupportICType & (ODM_RTL8723A))
+ pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV;
+
+ ODM_InitDebugSetting(pDM_Odm);
+}
+
+void odm_CommonInfoSelfUpdate(struct odm_dm_struct *pDM_Odm)
+{
+ u8 EntryCnt = 0;
+ u8 i;
+ struct sta_info *pEntry;
+
+ if (*(pDM_Odm->pBandWidth) == ODM_BW40M) {
+ if (*(pDM_Odm->pSecChOffset) == 1)
+ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) - 2;
+ else if (*(pDM_Odm->pSecChOffset) == 2)
+ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) + 2;
+ } else {
+ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel);
+ }
+
+ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+ pEntry = pDM_Odm->pODM_StaInfo[i];
+ if (IS_STA_VALID(pEntry))
+ EntryCnt++;
+ }
+ if (EntryCnt == 1)
+ pDM_Odm->bOneEntryOnly = true;
+ else
+ pDM_Odm->bOneEntryOnly = false;
+}
+
+void odm_CmnInfoInit_Debug(struct odm_dm_struct *pDM_Odm)
+{
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug==>\n"));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportPlatform=%d\n", pDM_Odm->SupportPlatform));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility=0x%x\n", pDM_Odm->SupportAbility));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface=%d\n", pDM_Odm->SupportInterface));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType=0x%x\n", pDM_Odm->SupportICType));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion=%d\n", pDM_Odm->CutVersion));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion=%d\n", pDM_Odm->FabVersion));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType=%d\n", pDM_Odm->RFType));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType=%d\n", pDM_Odm->BoardType));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA=%d\n", pDM_Odm->ExtLNA));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA=%d\n", pDM_Odm->ExtPA));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW=%d\n", pDM_Odm->ExtTRSW));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID=%d\n", pDM_Odm->PatchID));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest=%d\n", pDM_Odm->bInHctTest));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest=%d\n", pDM_Odm->bWIFITest));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent=%d\n", pDM_Odm->bDualMacSmartConcurrent));
+}
+
+void odm_CmnInfoHook_Debug(struct odm_dm_struct *pDM_Odm)
+{
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoHook_Debug==>\n"));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumTxBytesUnicast=%llu\n", *(pDM_Odm->pNumTxBytesUnicast)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumRxBytesUnicast=%llu\n", *(pDM_Odm->pNumRxBytesUnicast)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pWirelessMode=0x%x\n", *(pDM_Odm->pWirelessMode)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecChOffset=%d\n", *(pDM_Odm->pSecChOffset)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecurity=%d\n", *(pDM_Odm->pSecurity)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBandWidth=%d\n", *(pDM_Odm->pBandWidth)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pChannel=%d\n", *(pDM_Odm->pChannel)));
+
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbScanInProcess=%d\n", *(pDM_Odm->pbScanInProcess)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbPowerSaving=%d\n", *(pDM_Odm->pbPowerSaving)));
+
+ if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL))
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pOnePathCCA=%d\n", *(pDM_Odm->pOnePathCCA)));
+}
+
+void odm_CmnInfoUpdate_Debug(struct odm_dm_struct *pDM_Odm)
+{
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoUpdate_Debug==>\n"));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Direct=%d\n", pDM_Odm->bWIFI_Direct));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Display=%d\n", pDM_Odm->bWIFI_Display));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked=%d\n", pDM_Odm->bLinked));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RSSI_Min=%d\n", pDM_Odm->RSSI_Min));
+}
+
+static int getIGIForDiff(int value_IGI)
+{
+ #define ONERCCA_LOW_TH 0x30
+ #define ONERCCA_LOW_DIFF 8
+
+ if (value_IGI < ONERCCA_LOW_TH) {
+ if ((ONERCCA_LOW_TH - value_IGI) < ONERCCA_LOW_DIFF)
+ return ONERCCA_LOW_TH;
+ else
+ return value_IGI + ONERCCA_LOW_DIFF;
+ } else {
+ return value_IGI;
+ }
+}
+
+void ODM_Write_DIG(struct odm_dm_struct *pDM_Odm, u8 CurrentIGI)
+{
+ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable;
+
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+ ("ODM_REG(IGI_A,pDM_Odm)=0x%x, ODM_BIT(IGI,pDM_Odm)=0x%x\n",
+ ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm)));
+
+ if (pDM_DigTable->CurIGValue != CurrentIGI) {
+ if (pDM_Odm->SupportPlatform & (ODM_CE|ODM_MP)) {
+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+ if (pDM_Odm->SupportICType != ODM_RTL8188E)
+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+ } else if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) {
+ switch (*(pDM_Odm->pOnePathCCA)) {
+ case ODM_CCA_2R:
+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+ if (pDM_Odm->SupportICType != ODM_RTL8188E)
+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+ break;
+ case ODM_CCA_1R_A:
+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+ if (pDM_Odm->SupportICType != ODM_RTL8188E)
+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), getIGIForDiff(CurrentIGI));
+ break;
+ case ODM_CCA_1R_B:
+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), getIGIForDiff(CurrentIGI));
+ if (pDM_Odm->SupportICType != ODM_RTL8188E)
+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+ break;
+ }
+ }
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("CurrentIGI(0x%02x).\n", CurrentIGI));
+ /* pDM_DigTable->PreIGValue = pDM_DigTable->CurIGValue; */
+ pDM_DigTable->CurIGValue = CurrentIGI;
+ }
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("ODM_Write_DIG():CurrentIGI=0x%x\n", CurrentIGI));
+
+/* Add by Neil Chen to enable edcca to MP Platform */
+}
+
+/* Need LPS mode for CE platform --2012--08--24--- */
+/* 8723AS/8189ES */
+void odm_DIGbyRSSI_LPS(struct odm_dm_struct *pDM_Odm)
+{
+ struct adapter *pAdapter = pDM_Odm->Adapter;
+ struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt;
+
+ u8 RSSI_Lower = DM_DIG_MIN_NIC; /* 0x1E or 0x1C */
+ u8 bFwCurrentInPSMode = false;
+ u8 CurrentIGI = pDM_Odm->RSSI_Min;
+
+ if (!(pDM_Odm->SupportICType & (ODM_RTL8723A | ODM_RTL8188E)))
+ return;
+
+ CurrentIGI = CurrentIGI + RSSI_OFFSET_DIG;
+ bFwCurrentInPSMode = pAdapter->pwrctrlpriv.bFwCurrentInPSMode;
+
+ /* Using FW PS mode to make IGI */
+ if (bFwCurrentInPSMode) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Neil---odm_DIG is in LPS mode\n"));
+ /* Adjust by FA in LPS MODE */
+ if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_LPS)
+ CurrentIGI = CurrentIGI+2;
+ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_LPS)
+ CurrentIGI = CurrentIGI+1;
+ else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_LPS)
+ CurrentIGI = CurrentIGI-1;
+ } else {
+ CurrentIGI = RSSI_Lower;
+ }
+
+ /* Lower bound checking */
+
+ /* RSSI Lower bound check */
+ if ((pDM_Odm->RSSI_Min-10) > DM_DIG_MIN_NIC)
+ RSSI_Lower = (pDM_Odm->RSSI_Min-10);
+ else
+ RSSI_Lower = DM_DIG_MIN_NIC;
+
+ /* Upper and Lower Bound checking */
+ if (CurrentIGI > DM_DIG_MAX_NIC)
+ CurrentIGI = DM_DIG_MAX_NIC;
+ else if (CurrentIGI < RSSI_Lower)
+ CurrentIGI = RSSI_Lower;
+
+ ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */
+}
+
+void odm_DIGInit(struct odm_dm_struct *pDM_Odm)
+{
+ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable;
+
+ pDM_DigTable->CurIGValue = (u8) ODM_GetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm));
+ pDM_DigTable->RssiLowThresh = DM_DIG_THRESH_LOW;
+ pDM_DigTable->RssiHighThresh = DM_DIG_THRESH_HIGH;
+ pDM_DigTable->FALowThresh = DM_false_ALARM_THRESH_LOW;
+ pDM_DigTable->FAHighThresh = DM_false_ALARM_THRESH_HIGH;
+ if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) {
+ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
+ } else {
+ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
+ }
+ pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT;
+ pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX;
+ pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN;
+ pDM_DigTable->PreCCK_CCAThres = 0xFF;
+ pDM_DigTable->CurCCK_CCAThres = 0x83;
+ pDM_DigTable->ForbiddenIGI = DM_DIG_MIN_NIC;
+ pDM_DigTable->LargeFAHit = 0;
+ pDM_DigTable->Recover_cnt = 0;
+ pDM_DigTable->DIG_Dynamic_MIN_0 = DM_DIG_MIN_NIC;
+ pDM_DigTable->DIG_Dynamic_MIN_1 = DM_DIG_MIN_NIC;
+ pDM_DigTable->bMediaConnect_0 = false;
+ pDM_DigTable->bMediaConnect_1 = false;
+
+ /* To Initialize pDM_Odm->bDMInitialGainEnable == false to avoid DIG error */
+ pDM_Odm->bDMInitialGainEnable = true;
+}
+
+void odm_DIG(struct odm_dm_struct *pDM_Odm)
+{
+ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable;
+ struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt;
+ u8 DIG_Dynamic_MIN;
+ u8 DIG_MaxOfMin;
+ bool FirstConnect, FirstDisConnect;
+ u8 dm_dig_max, dm_dig_min;
+ u8 CurrentIGI = pDM_DigTable->CurIGValue;
+
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG()==>\n"));
+ if ((!(pDM_Odm->SupportAbility&ODM_BB_DIG)) || (!(pDM_Odm->SupportAbility&ODM_BB_FA_CNT))) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+ ("odm_DIG() Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n"));
+ return;
+ }
+
+ if (*(pDM_Odm->pbScanInProcess)) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In Scan Progress\n"));
+ return;
+ }
+
+ /* add by Neil Chen to avoid PSD is processing */
+ if (pDM_Odm->bDMInitialGainEnable == false) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: PSD is Processing\n"));
+ return;
+ }
+
+ if (pDM_Odm->SupportICType == ODM_RTL8192D) {
+ if (*(pDM_Odm->pMacPhyMode) == ODM_DMSP) {
+ if (*(pDM_Odm->pbMasterOfDMSP)) {
+ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0;
+ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0);
+ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0);
+ } else {
+ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1;
+ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_1);
+ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1);
+ }
+ } else {
+ if (*(pDM_Odm->pBandType) == ODM_BAND_5G) {
+ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0;
+ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0);
+ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0);
+ } else {
+ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1;
+ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_1);
+ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1);
+ }
+ }
+ } else {
+ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0;
+ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0);
+ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0);
+ }
+
+ /* 1 Boundary Decision */
+ if ((pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8723A)) &&
+ ((pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) || pDM_Odm->ExtLNA)) {
+ if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) {
+ dm_dig_max = DM_DIG_MAX_AP_HP;
+ dm_dig_min = DM_DIG_MIN_AP_HP;
+ } else {
+ dm_dig_max = DM_DIG_MAX_NIC_HP;
+ dm_dig_min = DM_DIG_MIN_NIC_HP;
+ }
+ DIG_MaxOfMin = DM_DIG_MAX_AP_HP;
+ } else {
+ if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) {
+ dm_dig_max = DM_DIG_MAX_AP;
+ dm_dig_min = DM_DIG_MIN_AP;
+ DIG_MaxOfMin = dm_dig_max;
+ } else {
+ dm_dig_max = DM_DIG_MAX_NIC;
+ dm_dig_min = DM_DIG_MIN_NIC;
+ DIG_MaxOfMin = DM_DIG_MAX_AP;
+ }
+ }
+ if (pDM_Odm->bLinked) {
+ /* 2 8723A Series, offset need to be 10 */
+ if (pDM_Odm->SupportICType == (ODM_RTL8723A)) {
+ /* 2 Upper Bound */
+ if ((pDM_Odm->RSSI_Min + 10) > DM_DIG_MAX_NIC)
+ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+ else if ((pDM_Odm->RSSI_Min + 10) < DM_DIG_MIN_NIC)
+ pDM_DigTable->rx_gain_range_max = DM_DIG_MIN_NIC;
+ else
+ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10;
+ /* 2 If BT is Concurrent, need to set Lower Bound */
+ DIG_Dynamic_MIN = DM_DIG_MIN_NIC;
+ } else {
+ /* 2 Modify DIG upper bound */
+ if ((pDM_Odm->RSSI_Min + 20) > dm_dig_max)
+ pDM_DigTable->rx_gain_range_max = dm_dig_max;
+ else if ((pDM_Odm->RSSI_Min + 20) < dm_dig_min)
+ pDM_DigTable->rx_gain_range_max = dm_dig_min;
+ else
+ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 20;
+ /* 2 Modify DIG lower bound */
+ if (pDM_Odm->bOneEntryOnly) {
+ if (pDM_Odm->RSSI_Min < dm_dig_min)
+ DIG_Dynamic_MIN = dm_dig_min;
+ else if (pDM_Odm->RSSI_Min > DIG_MaxOfMin)
+ DIG_Dynamic_MIN = DIG_MaxOfMin;
+ else
+ DIG_Dynamic_MIN = pDM_Odm->RSSI_Min;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+ ("odm_DIG() : bOneEntryOnly=true, DIG_Dynamic_MIN=0x%x\n",
+ DIG_Dynamic_MIN));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+ ("odm_DIG() : pDM_Odm->RSSI_Min=%d\n",
+ pDM_Odm->RSSI_Min));
+ } else if ((pDM_Odm->SupportICType == ODM_RTL8188E) &&
+ (pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) {
+ /* 1 Lower Bound for 88E AntDiv */
+ if (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) {
+ DIG_Dynamic_MIN = (u8) pDM_DigTable->AntDiv_RSSI_max;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+ ("odm_DIG(): pDM_DigTable->AntDiv_RSSI_max=%d\n",
+ pDM_DigTable->AntDiv_RSSI_max));
+ }
+ } else {
+ DIG_Dynamic_MIN = dm_dig_min;
+ }
+ }
+ } else {
+ pDM_DigTable->rx_gain_range_max = dm_dig_max;
+ DIG_Dynamic_MIN = dm_dig_min;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : No Link\n"));
+ }
+
+ /* 1 Modify DIG lower bound, deal with abnormally large false alarm */
+ if (pFalseAlmCnt->Cnt_all > 10000) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("dm_DIG(): Abnornally false alarm case.\n"));
+
+ if (pDM_DigTable->LargeFAHit != 3)
+ pDM_DigTable->LargeFAHit++;
+ if (pDM_DigTable->ForbiddenIGI < CurrentIGI) {
+ pDM_DigTable->ForbiddenIGI = CurrentIGI;
+ pDM_DigTable->LargeFAHit = 1;
+ }
+
+ if (pDM_DigTable->LargeFAHit >= 3) {
+ if ((pDM_DigTable->ForbiddenIGI+1) > pDM_DigTable->rx_gain_range_max)
+ pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max;
+ else
+ pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1);
+ pDM_DigTable->Recover_cnt = 3600; /* 3600=2hr */
+ }
+
+ } else {
+ /* Recovery mechanism for IGI lower bound */
+ if (pDM_DigTable->Recover_cnt != 0) {
+ pDM_DigTable->Recover_cnt--;
+ } else {
+ if (pDM_DigTable->LargeFAHit < 3) {
+ if ((pDM_DigTable->ForbiddenIGI-1) < DIG_Dynamic_MIN) { /* DM_DIG_MIN) */
+ pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
+ pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: At Lower Bound\n"));
+ } else {
+ pDM_DigTable->ForbiddenIGI--;
+ pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1);
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: Approach Lower Bound\n"));
+ }
+ } else {
+ pDM_DigTable->LargeFAHit = 0;
+ }
+ }
+ }
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+ ("odm_DIG(): pDM_DigTable->LargeFAHit=%d\n",
+ pDM_DigTable->LargeFAHit));
+
+ /* 1 Adjust initial gain by false alarm */
+ if (pDM_Odm->bLinked) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG AfterLink\n"));
+ if (FirstConnect) {
+ CurrentIGI = pDM_Odm->RSSI_Min;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("DIG: First Connect\n"));
+ } else {
+ if (pDM_Odm->SupportICType == ODM_RTL8192D) {
+ if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_92D)
+ CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */
+ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_92D)
+ CurrentIGI = CurrentIGI + 1; /* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */
+ else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_92D)
+ CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */
+ } else {
+ if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2)
+ CurrentIGI = CurrentIGI + 4;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */
+ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1)
+ CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */
+ else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0)
+ CurrentIGI = CurrentIGI - 2;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */
+ }
+ }
+ } else {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG BeforeLink\n"));
+ if (FirstDisConnect) {
+ CurrentIGI = pDM_DigTable->rx_gain_range_min;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): First DisConnect\n"));
+ } else {
+ /* 2012.03.30 LukeLee: enable DIG before link but with very high thresholds */
+ if (pFalseAlmCnt->Cnt_all > 10000)
+ CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */
+ else if (pFalseAlmCnt->Cnt_all > 8000)
+ CurrentIGI = CurrentIGI + 1;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */
+ else if (pFalseAlmCnt->Cnt_all < 500)
+ CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): England DIG\n"));
+ }
+ }
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG End Adjust IGI\n"));
+ /* 1 Check initial gain by upper/lower bound */
+ if (CurrentIGI > pDM_DigTable->rx_gain_range_max)
+ CurrentIGI = pDM_DigTable->rx_gain_range_max;
+ if (CurrentIGI < pDM_DigTable->rx_gain_range_min)
+ CurrentIGI = pDM_DigTable->rx_gain_range_min;
+
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+ ("odm_DIG(): rx_gain_range_max=0x%x, rx_gain_range_min=0x%x\n",
+ pDM_DigTable->rx_gain_range_max, pDM_DigTable->rx_gain_range_min));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): TotalFA=%d\n", pFalseAlmCnt->Cnt_all));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue=0x%x\n", CurrentIGI));
+
+ /* 2 High power RSSI threshold */
+
+ ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */
+ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked;
+ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN;
+}
+
+/* 3============================================================ */
+/* 3 FASLE ALARM CHECK */
+/* 3============================================================ */
+
+void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm)
+{
+ u32 ret_value;
+ struct false_alarm_stats *FalseAlmCnt = &(pDM_Odm->FalseAlmCnt);
+
+ if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT))
+ return;
+
+ if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) {
+ /* hold ofdm counter */
+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 1); /* hold page C counter */
+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 1); /* hold page D counter */
+
+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE1_11N, bMaskDWord);
+ FalseAlmCnt->Cnt_Fast_Fsync = (ret_value&0xffff);
+ FalseAlmCnt->Cnt_SB_Search_fail = ((ret_value&0xffff0000)>>16);
+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE2_11N, bMaskDWord);
+ FalseAlmCnt->Cnt_OFDM_CCA = (ret_value&0xffff);
+ FalseAlmCnt->Cnt_Parity_Fail = ((ret_value&0xffff0000)>>16);
+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE3_11N, bMaskDWord);
+ FalseAlmCnt->Cnt_Rate_Illegal = (ret_value&0xffff);
+ FalseAlmCnt->Cnt_Crc8_fail = ((ret_value&0xffff0000)>>16);
+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE4_11N, bMaskDWord);
+ FalseAlmCnt->Cnt_Mcs_fail = (ret_value&0xffff);
+
+ FalseAlmCnt->Cnt_Ofdm_fail = FalseAlmCnt->Cnt_Parity_Fail + FalseAlmCnt->Cnt_Rate_Illegal +
+ FalseAlmCnt->Cnt_Crc8_fail + FalseAlmCnt->Cnt_Mcs_fail +
+ FalseAlmCnt->Cnt_Fast_Fsync + FalseAlmCnt->Cnt_SB_Search_fail;
+
+ if (pDM_Odm->SupportICType == ODM_RTL8188E) {
+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_SC_CNT_11N, bMaskDWord);
+ FalseAlmCnt->Cnt_BW_LSC = (ret_value&0xffff);
+ FalseAlmCnt->Cnt_BW_USC = ((ret_value&0xffff0000)>>16);
+ }
+
+ /* hold cck counter */
+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT12, 1);
+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT14, 1);
+
+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_LSB_11N, bMaskByte0);
+ FalseAlmCnt->Cnt_Cck_fail = ret_value;
+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_MSB_11N, bMaskByte3);
+ FalseAlmCnt->Cnt_Cck_fail += (ret_value & 0xff)<<8;
+
+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_CCA_CNT_11N, bMaskDWord);
+ FalseAlmCnt->Cnt_CCK_CCA = ((ret_value&0xFF)<<8) | ((ret_value&0xFF00)>>8);
+
+ FalseAlmCnt->Cnt_all = (FalseAlmCnt->Cnt_Fast_Fsync +
+ FalseAlmCnt->Cnt_SB_Search_fail +
+ FalseAlmCnt->Cnt_Parity_Fail +
+ FalseAlmCnt->Cnt_Rate_Illegal +
+ FalseAlmCnt->Cnt_Crc8_fail +
+ FalseAlmCnt->Cnt_Mcs_fail +
+ FalseAlmCnt->Cnt_Cck_fail);
+
+ FalseAlmCnt->Cnt_CCA_all = FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA;
+
+ if (pDM_Odm->SupportICType >= ODM_RTL8723A) {
+ /* reset false alarm counter registers */
+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 1);
+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 0);
+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 1);
+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 0);
+ /* update ofdm counter */
+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 0); /* update page C counter */
+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 0); /* update page D counter */
+
+ /* reset CCK CCA counter */
+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 0);
+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 2);
+ /* reset CCK FA counter */
+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 0);
+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 2);
+ }
+
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Enter odm_FalseAlarmCounterStatistics\n"));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD,
+ ("Cnt_Fast_Fsync=%d, Cnt_SB_Search_fail=%d\n",
+ FalseAlmCnt->Cnt_Fast_Fsync, FalseAlmCnt->Cnt_SB_Search_fail));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD,
+ ("Cnt_Parity_Fail=%d, Cnt_Rate_Illegal=%d\n",
+ FalseAlmCnt->Cnt_Parity_Fail, FalseAlmCnt->Cnt_Rate_Illegal));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD,
+ ("Cnt_Crc8_fail=%d, Cnt_Mcs_fail=%d\n",
+ FalseAlmCnt->Cnt_Crc8_fail, FalseAlmCnt->Cnt_Mcs_fail));
+ } else { /* FOR ODM_IC_11AC_SERIES */
+ /* read OFDM FA counter */
+ FalseAlmCnt->Cnt_Ofdm_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_11AC, bMaskLWord);
+ FalseAlmCnt->Cnt_Cck_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_11AC, bMaskLWord);
+ FalseAlmCnt->Cnt_all = FalseAlmCnt->Cnt_Ofdm_fail + FalseAlmCnt->Cnt_Cck_fail;
+
+ /* reset OFDM FA coutner */
+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 1);
+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 0);
+ /* reset CCK FA counter */
+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 0);
+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 1);
+ }
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Cck_fail=%d\n", FalseAlmCnt->Cnt_Cck_fail));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Ofdm_fail=%d\n", FalseAlmCnt->Cnt_Ofdm_fail));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Total False Alarm=%d\n", FalseAlmCnt->Cnt_all));
+}
+
+/* 3============================================================ */
+/* 3 CCK Packet Detect Threshold */
+/* 3============================================================ */
+
+void odm_CCKPacketDetectionThresh(struct odm_dm_struct *pDM_Odm)
+{
+ u8 CurCCK_CCAThres;
+ struct false_alarm_stats *FalseAlmCnt = &(pDM_Odm->FalseAlmCnt);
+
+ if (!(pDM_Odm->SupportAbility & (ODM_BB_CCK_PD|ODM_BB_FA_CNT)))
+ return;
+ if (pDM_Odm->ExtLNA)
+ return;
+ if (pDM_Odm->bLinked) {
+ if (pDM_Odm->RSSI_Min > 25) {
+ CurCCK_CCAThres = 0xcd;
+ } else if ((pDM_Odm->RSSI_Min <= 25) && (pDM_Odm->RSSI_Min > 10)) {
+ CurCCK_CCAThres = 0x83;
+ } else {
+ if (FalseAlmCnt->Cnt_Cck_fail > 1000)
+ CurCCK_CCAThres = 0x83;
+ else
+ CurCCK_CCAThres = 0x40;
+ }
+ } else {
+ if (FalseAlmCnt->Cnt_Cck_fail > 1000)
+ CurCCK_CCAThres = 0x83;
+ else
+ CurCCK_CCAThres = 0x40;
+ }
+ ODM_Write_CCK_CCA_Thres(pDM_Odm, CurCCK_CCAThres);
+}
+
+void ODM_Write_CCK_CCA_Thres(struct odm_dm_struct *pDM_Odm, u8 CurCCK_CCAThres)
+{
+ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable;
+
+ if (pDM_DigTable->CurCCK_CCAThres != CurCCK_CCAThres) /* modify by Guo.Mingzhi 2012-01-03 */
+ ODM_Write1Byte(pDM_Odm, ODM_REG(CCK_CCA, pDM_Odm), CurCCK_CCAThres);
+ pDM_DigTable->PreCCK_CCAThres = pDM_DigTable->CurCCK_CCAThres;
+ pDM_DigTable->CurCCK_CCAThres = CurCCK_CCAThres;
+}
+
+/* 3============================================================ */
+/* 3 BB Power Save */
+/* 3============================================================ */
+void odm_DynamicBBPowerSavingInit(struct odm_dm_struct *pDM_Odm)
+{
+ struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable;
+
+ pDM_PSTable->PreCCAState = CCA_MAX;
+ pDM_PSTable->CurCCAState = CCA_MAX;
+ pDM_PSTable->PreRFState = RF_MAX;
+ pDM_PSTable->CurRFState = RF_MAX;
+ pDM_PSTable->Rssi_val_min = 0;
+ pDM_PSTable->initialize = 0;
+}
+
+void odm_DynamicBBPowerSaving(struct odm_dm_struct *pDM_Odm)
+{
+ if ((pDM_Odm->SupportICType != ODM_RTL8192C) && (pDM_Odm->SupportICType != ODM_RTL8723A))
+ return;
+ if (!(pDM_Odm->SupportAbility & ODM_BB_PWR_SAVE))
+ return;
+ if (!(pDM_Odm->SupportPlatform & (ODM_MP|ODM_CE)))
+ return;
+
+ /* 1 2.Power Saving for 92C */
+ if ((pDM_Odm->SupportICType == ODM_RTL8192C) && (pDM_Odm->RFType == ODM_2T2R)) {
+ odm_1R_CCA(pDM_Odm);
+ } else {
+ /* 20100628 Joseph: Turn off BB power save for 88CE because it makesthroughput unstable. */
+ /* 20100831 Joseph: Turn ON BB power save again after modifying AGC delay from 900ns ot 600ns. */
+ /* 1 3.Power Saving for 88C */
+ ODM_RF_Saving(pDM_Odm, false);
+ }
+}
+
+void odm_1R_CCA(struct odm_dm_struct *pDM_Odm)
+{
+ struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable;
+
+ if (pDM_Odm->RSSI_Min != 0xFF) {
+ if (pDM_PSTable->PreCCAState == CCA_2R) {
+ if (pDM_Odm->RSSI_Min >= 35)
+ pDM_PSTable->CurCCAState = CCA_1R;
+ else
+ pDM_PSTable->CurCCAState = CCA_2R;
+ } else {
+ if (pDM_Odm->RSSI_Min <= 30)
+ pDM_PSTable->CurCCAState = CCA_2R;
+ else
+ pDM_PSTable->CurCCAState = CCA_1R;
+ }
+ } else {
+ pDM_PSTable->CurCCAState = CCA_MAX;
+ }
+
+ if (pDM_PSTable->PreCCAState != pDM_PSTable->CurCCAState) {
+ if (pDM_PSTable->CurCCAState == CCA_1R) {
+ if (pDM_Odm->RFType == ODM_2T2R)
+ ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x13);
+ else
+ ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x23);
+ } else {
+ ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x33);
+ }
+ pDM_PSTable->PreCCAState = pDM_PSTable->CurCCAState;
+ }
+}
+
+void ODM_RF_Saving(struct odm_dm_struct *pDM_Odm, u8 bForceInNormal)
+{
+ struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable;
+ u8 Rssi_Up_bound = 30;
+ u8 Rssi_Low_bound = 25;
+
+ if (pDM_Odm->PatchID == 40) { /* RT_CID_819x_FUNAI_TV */
+ Rssi_Up_bound = 50;
+ Rssi_Low_bound = 45;
+ }
+ if (pDM_PSTable->initialize == 0) {
+ pDM_PSTable->Reg874 = (ODM_GetBBReg(pDM_Odm, 0x874, bMaskDWord)&0x1CC000)>>14;
+ pDM_PSTable->RegC70 = (ODM_GetBBReg(pDM_Odm, 0xc70, bMaskDWord)&BIT3)>>3;
+ pDM_PSTable->Reg85C = (ODM_GetBBReg(pDM_Odm, 0x85c, bMaskDWord)&0xFF000000)>>24;
+ pDM_PSTable->RegA74 = (ODM_GetBBReg(pDM_Odm, 0xa74, bMaskDWord)&0xF000)>>12;
+ pDM_PSTable->initialize = 1;
+ }
+
+ if (!bForceInNormal) {
+ if (pDM_Odm->RSSI_Min != 0xFF) {
+ if (pDM_PSTable->PreRFState == RF_Normal) {
+ if (pDM_Odm->RSSI_Min >= Rssi_Up_bound)
+ pDM_PSTable->CurRFState = RF_Save;
+ else
+ pDM_PSTable->CurRFState = RF_Normal;
+ } else {
+ if (pDM_Odm->RSSI_Min <= Rssi_Low_bound)
+ pDM_PSTable->CurRFState = RF_Normal;
+ else
+ pDM_PSTable->CurRFState = RF_Save;
+ }
+ } else {
+ pDM_PSTable->CurRFState = RF_MAX;
+ }
+ } else {
+ pDM_PSTable->CurRFState = RF_Normal;
+ }
+
+ if (pDM_PSTable->PreRFState != pDM_PSTable->CurRFState) {
+ if (pDM_PSTable->CurRFState == RF_Save) {
+ /* <tynli_note> 8723 RSSI report will be wrong. Set 0x874[5]=1 when enter BB power saving mode. */
+ /* Suggested by SD3 Yu-Nan. 2011.01.20. */
+ if (pDM_Odm->SupportICType == ODM_RTL8723A)
+ ODM_SetBBReg(pDM_Odm, 0x874 , BIT5, 0x1); /* Reg874[5]=1b'1 */
+ ODM_SetBBReg(pDM_Odm, 0x874 , 0x1C0000, 0x2); /* Reg874[20:18]=3'b010 */
+ ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, 0); /* RegC70[3]=1'b0 */
+ ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, 0x63); /* Reg85C[31:24]=0x63 */
+ ODM_SetBBReg(pDM_Odm, 0x874, 0xC000, 0x2); /* Reg874[15:14]=2'b10 */
+ ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, 0x3); /* RegA75[7:4]=0x3 */
+ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); /* Reg818[28]=1'b0 */
+ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x1); /* Reg818[28]=1'b1 */
+ } else {
+ ODM_SetBBReg(pDM_Odm, 0x874 , 0x1CC000, pDM_PSTable->Reg874);
+ ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, pDM_PSTable->RegC70);
+ ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, pDM_PSTable->Reg85C);
+ ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, pDM_PSTable->RegA74);
+ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0);
+
+ if (pDM_Odm->SupportICType == ODM_RTL8723A)
+ ODM_SetBBReg(pDM_Odm, 0x874, BIT5, 0x0); /* Reg874[5]=1b'0 */
+ }
+ pDM_PSTable->PreRFState = pDM_PSTable->CurRFState;
+ }
+}
+
+/* 3============================================================ */
+/* 3 RATR MASK */
+/* 3============================================================ */
+/* 3============================================================ */
+/* 3 Rate Adaptive */
+/* 3============================================================ */
+
+void odm_RateAdaptiveMaskInit(struct odm_dm_struct *pDM_Odm)
+{
+ struct odm_rate_adapt *pOdmRA = &pDM_Odm->RateAdaptive;
+
+ pOdmRA->Type = DM_Type_ByDriver;
+ if (pOdmRA->Type == DM_Type_ByDriver)
+ pDM_Odm->bUseRAMask = true;
+ else
+ pDM_Odm->bUseRAMask = false;
+
+ pOdmRA->RATRState = DM_RATR_STA_INIT;
+ pOdmRA->HighRSSIThresh = 50;
+ pOdmRA->LowRSSIThresh = 20;
+}
+
+u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid, u32 ra_mask, u8 rssi_level)
+{
+ struct sta_info *pEntry;
+ u32 rate_bitmap = 0x0fffffff;
+ u8 WirelessMode;
+
+ pEntry = pDM_Odm->pODM_StaInfo[macid];
+ if (!IS_STA_VALID(pEntry))
+ return ra_mask;
+
+ WirelessMode = pEntry->wireless_mode;
+
+ switch (WirelessMode) {
+ case ODM_WM_B:
+ if (ra_mask & 0x0000000c) /* 11M or 5.5M enable */
+ rate_bitmap = 0x0000000d;
+ else
+ rate_bitmap = 0x0000000f;
+ break;
+ case (ODM_WM_A|ODM_WM_G):
+ if (rssi_level == DM_RATR_STA_HIGH)
+ rate_bitmap = 0x00000f00;
+ else
+ rate_bitmap = 0x00000ff0;
+ break;
+ case (ODM_WM_B|ODM_WM_G):
+ if (rssi_level == DM_RATR_STA_HIGH)
+ rate_bitmap = 0x00000f00;
+ else if (rssi_level == DM_RATR_STA_MIDDLE)
+ rate_bitmap = 0x00000ff0;
+ else
+ rate_bitmap = 0x00000ff5;
+ break;
+ case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G):
+ case (ODM_WM_A|ODM_WM_B|ODM_WM_G|ODM_WM_N24G):
+ if (pDM_Odm->RFType == ODM_1T2R || pDM_Odm->RFType == ODM_1T1R) {
+ if (rssi_level == DM_RATR_STA_HIGH) {
+ rate_bitmap = 0x000f0000;
+ } else if (rssi_level == DM_RATR_STA_MIDDLE) {
+ rate_bitmap = 0x000ff000;
+ } else {
+ if (*(pDM_Odm->pBandWidth) == ODM_BW40M)
+ rate_bitmap = 0x000ff015;
+ else
+ rate_bitmap = 0x000ff005;
+ }
+ } else {
+ if (rssi_level == DM_RATR_STA_HIGH) {
+ rate_bitmap = 0x0f8f0000;
+ } else if (rssi_level == DM_RATR_STA_MIDDLE) {
+ rate_bitmap = 0x0f8ff000;
+ } else {
+ if (*(pDM_Odm->pBandWidth) == ODM_BW40M)
+ rate_bitmap = 0x0f8ff015;
+ else
+ rate_bitmap = 0x0f8ff005;
+ }
+ }
+ break;
+ default:
+ /* case WIRELESS_11_24N: */
+ /* case WIRELESS_11_5N: */
+ if (pDM_Odm->RFType == RF_1T2R)
+ rate_bitmap = 0x000fffff;
+ else
+ rate_bitmap = 0x0fffffff;
+ break;
+ }
+
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD,
+ (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n",
+ rssi_level, WirelessMode, rate_bitmap));
+
+ return rate_bitmap;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: odm_RefreshRateAdaptiveMask()
+ *
+ * Overview: Update rate table mask according to rssi
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 05/27/2009 hpfan Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void odm_RefreshRateAdaptiveMask(struct odm_dm_struct *pDM_Odm)
+{
+ if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK))
+ return;
+ /* */
+ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */
+ /* HW dynamic mechanism. */
+ /* */
+ switch (pDM_Odm->SupportPlatform) {
+ case ODM_MP:
+ odm_RefreshRateAdaptiveMaskMP(pDM_Odm);
+ break;
+ case ODM_CE:
+ odm_RefreshRateAdaptiveMaskCE(pDM_Odm);
+ break;
+ case ODM_AP:
+ case ODM_ADSL:
+ odm_RefreshRateAdaptiveMaskAPADSL(pDM_Odm);
+ break;
+ }
+}
+
+void odm_RefreshRateAdaptiveMaskMP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+void odm_RefreshRateAdaptiveMaskCE(struct odm_dm_struct *pDM_Odm)
+{
+ u8 i;
+ struct adapter *pAdapter = pDM_Odm->Adapter;
+
+ if (pAdapter->bDriverStopped) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n"));
+ return;
+ }
+
+ if (!pDM_Odm->bUseRAMask) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n"));
+ return;
+ }
+
+ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+ struct sta_info *pstat = pDM_Odm->pODM_StaInfo[i];
+ if (IS_STA_VALID(pstat)) {
+ if (ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false , &pstat->rssi_level)) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD,
+ ("RSSI:%d, RSSI_LEVEL:%d\n",
+ pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level));
+ rtw_hal_update_ra_mask(pAdapter, i, pstat->rssi_level);
+ }
+ }
+ }
+}
+
+void odm_RefreshRateAdaptiveMaskAPADSL(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+/* Return Value: bool */
+/* - true: RATRState is changed. */
+bool ODM_RAStateCheck(struct odm_dm_struct *pDM_Odm, s32 RSSI, bool bForceUpdate, u8 *pRATRState)
+{
+ struct odm_rate_adapt *pRA = &pDM_Odm->RateAdaptive;
+ const u8 GoUpGap = 5;
+ u8 HighRSSIThreshForRA = pRA->HighRSSIThresh;
+ u8 LowRSSIThreshForRA = pRA->LowRSSIThresh;
+ u8 RATRState;
+
+ /* Threshold Adjustment: */
+ /* when RSSI state trends to go up one or two levels, make sure RSSI is high enough. */
+ /* Here GoUpGap is added to solve the boundary's level alternation issue. */
+ switch (*pRATRState) {
+ case DM_RATR_STA_INIT:
+ case DM_RATR_STA_HIGH:
+ break;
+ case DM_RATR_STA_MIDDLE:
+ HighRSSIThreshForRA += GoUpGap;
+ break;
+ case DM_RATR_STA_LOW:
+ HighRSSIThreshForRA += GoUpGap;
+ LowRSSIThreshForRA += GoUpGap;
+ break;
+ default:
+ ODM_RT_ASSERT(pDM_Odm, false, ("wrong rssi level setting %d !", *pRATRState));
+ break;
+ }
+
+ /* Decide RATRState by RSSI. */
+ if (RSSI > HighRSSIThreshForRA)
+ RATRState = DM_RATR_STA_HIGH;
+ else if (RSSI > LowRSSIThreshForRA)
+ RATRState = DM_RATR_STA_MIDDLE;
+ else
+ RATRState = DM_RATR_STA_LOW;
+
+ if (*pRATRState != RATRState || bForceUpdate) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI Level %d -> %d\n", *pRATRState, RATRState));
+ *pRATRState = RATRState;
+ return true;
+ }
+ return false;
+}
+
+/* 3============================================================ */
+/* 3 Dynamic Tx Power */
+/* 3============================================================ */
+
+void odm_DynamicTxPowerInit(struct odm_dm_struct *pDM_Odm)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ struct dm_priv *pdmpriv = &pHalData->dmpriv;
+ pdmpriv->bDynamicTxPowerEnable = false;
+ pdmpriv->LastDTPLvl = TxHighPwrLevel_Normal;
+ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal;
+}
+
+void odm_DynamicTxPower(struct odm_dm_struct *pDM_Odm)
+{
+ /* For AP/ADSL use struct rtl8192cd_priv * */
+ /* For CE/NIC use struct adapter * */
+
+ if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR))
+ return;
+
+ /* 2012/01/12 MH According to Luke's suggestion, only high power will support the feature. */
+ if (!pDM_Odm->ExtPA)
+ return;
+
+ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */
+ /* HW dynamic mechanism. */
+ switch (pDM_Odm->SupportPlatform) {
+ case ODM_MP:
+ case ODM_CE:
+ odm_DynamicTxPowerNIC(pDM_Odm);
+ break;
+ case ODM_AP:
+ odm_DynamicTxPowerAP(pDM_Odm);
+ break;
+ case ODM_ADSL:
+ break;
+ }
+}
+
+void odm_DynamicTxPowerNIC(struct odm_dm_struct *pDM_Odm)
+{
+ if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR))
+ return;
+
+ if (pDM_Odm->SupportICType == ODM_RTL8188E) {
+ /* ??? */
+ /* This part need to be redefined. */
+ }
+}
+
+void odm_DynamicTxPowerAP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+/* 3============================================================ */
+/* 3 RSSI Monitor */
+/* 3============================================================ */
+
+void odm_RSSIMonitorCheck(struct odm_dm_struct *pDM_Odm)
+{
+ if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR))
+ return;
+
+ /* */
+ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */
+ /* HW dynamic mechanism. */
+ /* */
+ switch (pDM_Odm->SupportPlatform) {
+ case ODM_MP:
+ odm_RSSIMonitorCheckMP(pDM_Odm);
+ break;
+ case ODM_CE:
+ odm_RSSIMonitorCheckCE(pDM_Odm);
+ break;
+ case ODM_AP:
+ odm_RSSIMonitorCheckAP(pDM_Odm);
+ break;
+ case ODM_ADSL:
+ /* odm_DIGAP(pDM_Odm); */
+ break;
+ }
+
+} /* odm_RSSIMonitorCheck */
+
+void odm_RSSIMonitorCheckMP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+static void FindMinimumRSSI(struct adapter *pAdapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+ struct dm_priv *pdmpriv = &pHalData->dmpriv;
+ struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv;
+
+ /* 1 1.Determine the minimum RSSI */
+ if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) &&
+ (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0))
+ pdmpriv->MinUndecoratedPWDBForDM = 0;
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) /* Default port */
+ pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
+ else /* associated entry pwdb */
+ pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
+}
+
+void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ struct dm_priv *pdmpriv = &pHalData->dmpriv;
+ int i;
+ int tmpEntryMaxPWDB = 0, tmpEntryMinPWDB = 0xff;
+ u8 sta_cnt = 0;
+ u32 PWDB_rssi[NUM_STA] = {0};/* 0~15]:MACID, [16~31]:PWDB_rssi */
+ struct sta_info *psta;
+ u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ if (!check_fwstate(&Adapter->mlmepriv, _FW_LINKED))
+ return;
+
+ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+ psta = pDM_Odm->pODM_StaInfo[i];
+ if (IS_STA_VALID(psta) &&
+ (psta->state & WIFI_ASOC_STATE) &&
+ !_rtw_memcmp(psta->hwaddr, bcast_addr, ETH_ALEN) &&
+ !_rtw_memcmp(psta->hwaddr, myid(&Adapter->eeprompriv), ETH_ALEN)) {
+ if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB)
+ tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB;
+
+ if (psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB)
+ tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB;
+ if (psta->rssi_stat.UndecoratedSmoothedPWDB != (-1))
+ PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16));
+ }
+ }
+
+ for (i = 0; i < sta_cnt; i++) {
+ if (PWDB_rssi[i] != (0)) {
+ if (pHalData->fw_ractrl) {
+ /* Report every sta's RSSI to FW */
+ } else {
+ ODM_RA_SetRSSI_8188E(
+ &(pHalData->odmpriv), (PWDB_rssi[i]&0xFF), (u8)((PWDB_rssi[i]>>16) & 0xFF));
+ }
+ }
+ }
+
+ if (tmpEntryMaxPWDB != 0) /* If associated entry is found */
+ pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB;
+ else
+ pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0;
+
+ if (tmpEntryMinPWDB != 0xff) /* If associated entry is found */
+ pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB;
+ else
+ pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0;
+
+ FindMinimumRSSI(Adapter);
+ ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM);
+}
+
+void odm_RSSIMonitorCheckAP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+void ODM_InitAllTimers(struct odm_dm_struct *pDM_Odm)
+{
+ ODM_InitializeTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer,
+ (void *)odm_SwAntDivChkAntSwitchCallback, NULL, "SwAntennaSwitchTimer");
+}
+
+void ODM_CancelAllTimers(struct odm_dm_struct *pDM_Odm)
+{
+ ODM_CancelTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer);
+}
+
+void ODM_ReleaseAllTimers(struct odm_dm_struct *pDM_Odm)
+{
+ ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer);
+
+ ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->FastAntTrainingTimer);
+}
+
+/* 3============================================================ */
+/* 3 Tx Power Tracking */
+/* 3============================================================ */
+
+void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm)
+{
+ odm_TXPowerTrackingThermalMeterInit(pDM_Odm);
+}
+
+void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm)
+{
+ pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true;
+ pDM_Odm->RFCalibrateInfo.TXPowercount = 0;
+ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = false;
+ if (*(pDM_Odm->mp_mode) != 1)
+ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true;
+ MSG_88E("pDM_Odm TxPowerTrackControl = %d\n", pDM_Odm->RFCalibrateInfo.TxPowerTrackControl);
+
+ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true;
+}
+
+void ODM_TXPowerTrackingCheck(struct odm_dm_struct *pDM_Odm)
+{
+ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */
+ /* HW dynamic mechanism. */
+ switch (pDM_Odm->SupportPlatform) {
+ case ODM_MP:
+ odm_TXPowerTrackingCheckMP(pDM_Odm);
+ break;
+ case ODM_CE:
+ odm_TXPowerTrackingCheckCE(pDM_Odm);
+ break;
+ case ODM_AP:
+ odm_TXPowerTrackingCheckAP(pDM_Odm);
+ break;
+ case ODM_ADSL:
+ break;
+ }
+}
+
+void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+
+ if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK))
+ return;
+
+ if (!pDM_Odm->RFCalibrateInfo.TM_Trigger) { /* at least delay 1 sec */
+ PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER_88E, BIT17 | BIT16, 0x03);
+
+ pDM_Odm->RFCalibrateInfo.TM_Trigger = 1;
+ return;
+ } else {
+ odm_TXPowerTrackingCallback_ThermalMeter_8188E(Adapter);
+ pDM_Odm->RFCalibrateInfo.TM_Trigger = 0;
+ }
+}
+
+void odm_TXPowerTrackingCheckMP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+void odm_TXPowerTrackingCheckAP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+/* antenna mapping info */
+/* 1: right-side antenna */
+/* 2/0: left-side antenna */
+/* PDM_SWAT_Table->CCK_Ant1_Cnt /OFDM_Ant1_Cnt: for right-side antenna: Ant:1 RxDefaultAnt1 */
+/* PDM_SWAT_Table->CCK_Ant2_Cnt /OFDM_Ant2_Cnt: for left-side antenna: Ant:0 RxDefaultAnt2 */
+/* We select left antenna as default antenna in initial process, modify it as needed */
+/* */
+
+/* 3============================================================ */
+/* 3 SW Antenna Diversity */
+/* 3============================================================ */
+void odm_SwAntDivInit(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+void ODM_SwAntDivChkPerPktRssi(struct odm_dm_struct *pDM_Odm, u8 StationID, struct odm_phy_status_info *pPhyInfo)
+{
+}
+
+void odm_SwAntDivChkAntSwitch(struct odm_dm_struct *pDM_Odm, u8 Step)
+{
+}
+
+void ODM_SwAntDivRestAfterLink(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+void odm_SwAntDivChkAntSwitchCallback(void *FunctionContext)
+{
+}
+
+/* 3============================================================ */
+/* 3 SW Antenna Diversity */
+/* 3============================================================ */
+
+void odm_InitHybridAntDiv(struct odm_dm_struct *pDM_Odm)
+{
+ if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Return: Not Support HW AntDiv\n"));
+ return;
+ }
+
+ if (pDM_Odm->SupportICType & (ODM_RTL8192C | ODM_RTL8192D))
+ ;
+ else if (pDM_Odm->SupportICType == ODM_RTL8188E)
+ ODM_AntennaDiversityInit_88E(pDM_Odm);
+}
+
+void ODM_AntselStatistics_88C(struct odm_dm_struct *pDM_Odm, u8 MacId, u32 PWDBAll, bool isCCKrate)
+{
+ struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+
+ if (pDM_SWAT_Table->antsel == 1) {
+ if (isCCKrate) {
+ pDM_SWAT_Table->CCK_Ant1_Cnt[MacId]++;
+ } else {
+ pDM_SWAT_Table->OFDM_Ant1_Cnt[MacId]++;
+ pDM_SWAT_Table->RSSI_Ant1_Sum[MacId] += PWDBAll;
+ }
+ } else {
+ if (isCCKrate) {
+ pDM_SWAT_Table->CCK_Ant2_Cnt[MacId]++;
+ } else {
+ pDM_SWAT_Table->OFDM_Ant2_Cnt[MacId]++;
+ pDM_SWAT_Table->RSSI_Ant2_Sum[MacId] += PWDBAll;
+ }
+ }
+}
+
+void odm_HwAntDiv(struct odm_dm_struct *pDM_Odm)
+{
+ if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Return: Not Support HW AntDiv\n"));
+ return;
+ }
+
+ if (pDM_Odm->SupportICType == ODM_RTL8188E)
+ ODM_AntennaDiversity_88E(pDM_Odm);
+}
+
+/* EDCA Turbo */
+void ODM_EdcaTurboInit(struct odm_dm_struct *pDM_Odm)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false;
+ pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false;
+ Adapter->recvpriv.bIsAnyNonBEPkts = false;
+
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VO PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VO_PARAM)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VI PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VI_PARAM)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BE PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BE_PARAM)));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BK PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BK_PARAM)));
+} /* ODM_InitEdcaTurbo */
+
+void odm_EdcaTurboCheck(struct odm_dm_struct *pDM_Odm)
+{
+ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */
+ /* HW dynamic mechanism. */
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("odm_EdcaTurboCheck========================>\n"));
+
+ if (!(pDM_Odm->SupportAbility & ODM_MAC_EDCA_TURBO))
+ return;
+
+ switch (pDM_Odm->SupportPlatform) {
+ case ODM_MP:
+ break;
+ case ODM_CE:
+ odm_EdcaTurboCheckCE(pDM_Odm);
+ break;
+ case ODM_AP:
+ case ODM_ADSL:
+ break;
+ }
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("<========================odm_EdcaTurboCheck\n"));
+} /* odm_CheckEdcaTurbo */
+
+void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ u32 trafficIndex;
+ u32 edca_param;
+ u64 cur_tx_bytes = 0;
+ u64 cur_rx_bytes = 0;
+ u8 bbtchange = false;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv);
+ struct recv_priv *precvpriv = &(Adapter->recvpriv);
+ struct registry_priv *pregpriv = &Adapter->registrypriv;
+ struct mlme_ext_priv *pmlmeext = &(Adapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if ((pregpriv->wifi_spec == 1))/* (pmlmeinfo->HT_enable == 0)) */
+ goto dm_CheckEdcaTurbo_EXIT;
+
+ if (pmlmeinfo->assoc_AP_vendor >= HT_IOT_PEER_MAX)
+ goto dm_CheckEdcaTurbo_EXIT;
+
+ /* Check if the status needs to be changed. */
+ if ((bbtchange) || (!precvpriv->bIsAnyNonBEPkts)) {
+ cur_tx_bytes = pxmitpriv->tx_bytes - pxmitpriv->last_tx_bytes;
+ cur_rx_bytes = precvpriv->rx_bytes - precvpriv->last_rx_bytes;
+
+ /* traffic, TX or RX */
+ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK) ||
+ (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS)) {
+ if (cur_tx_bytes > (cur_rx_bytes << 2)) {
+ /* Uplink TP is present. */
+ trafficIndex = UP_LINK;
+ } else {
+ /* Balance TP is present. */
+ trafficIndex = DOWN_LINK;
+ }
+ } else {
+ if (cur_rx_bytes > (cur_tx_bytes << 2)) {
+ /* Downlink TP is present. */
+ trafficIndex = DOWN_LINK;
+ } else {
+ /* Balance TP is present. */
+ trafficIndex = UP_LINK;
+ }
+ }
+
+ if ((pDM_Odm->DM_EDCA_Table.prv_traffic_idx != trafficIndex) || (!pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA)) {
+ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_CISCO) && (pmlmeext->cur_wireless_mode & WIRELESS_11_24N))
+ edca_param = EDCAParam[pmlmeinfo->assoc_AP_vendor][trafficIndex];
+ else
+ edca_param = EDCAParam[HT_IOT_PEER_UNKNOWN][trafficIndex];
+
+ rtw_write32(Adapter, REG_EDCA_BE_PARAM, edca_param);
+
+ pDM_Odm->DM_EDCA_Table.prv_traffic_idx = trafficIndex;
+ }
+
+ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = true;
+ } else {
+ /* Turn Off EDCA turbo here. */
+ /* Restore original EDCA according to the declaration of AP. */
+ if (pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) {
+ rtw_write32(Adapter, REG_EDCA_BE_PARAM, pHalData->AcParam_BE);
+ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false;
+ }
+ }
+
+dm_CheckEdcaTurbo_EXIT:
+ /* Set variables for next time. */
+ precvpriv->bIsAnyNonBEPkts = false;
+ pxmitpriv->last_tx_bytes = pxmitpriv->tx_bytes;
+ precvpriv->last_rx_bytes = precvpriv->rx_bytes;
+}
+
+/* need to ODM CE Platform */
+/* move to here for ANT detection mechanism using */
+
+u32 GetPSDData(struct odm_dm_struct *pDM_Odm, unsigned int point, u8 initial_gain_psd)
+{
+ u32 psd_report;
+
+ /* Set DCO frequency index, offset=(40MHz/SamplePts)*point */
+ ODM_SetBBReg(pDM_Odm, 0x808, 0x3FF, point);
+
+ /* Start PSD calculation, Reg808[22]=0->1 */
+ ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 1);
+ /* Need to wait for HW PSD report */
+ ODM_StallExecution(30);
+ ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 0);
+ /* Read PSD report, Reg8B4[15:0] */
+ psd_report = ODM_GetBBReg(pDM_Odm, 0x8B4, bMaskDWord) & 0x0000FFFF;
+
+ psd_report = (u32) (ConvertTo_dB(psd_report))+(u32)(initial_gain_psd-0x1c);
+
+ return psd_report;
+}
+
+u32 ConvertTo_dB(u32 Value)
+{
+ u8 i;
+ u8 j;
+ u32 dB;
+
+ Value = Value & 0xFFFF;
+ for (i = 0; i < 8; i++) {
+ if (Value <= dB_Invert_Table[i][11])
+ break;
+ }
+
+ if (i >= 8)
+ return 96; /* maximum 96 dB */
+
+ for (j = 0; j < 12; j++) {
+ if (Value <= dB_Invert_Table[i][j])
+ break;
+ }
+
+ dB = i*12 + j + 1;
+
+ return dB;
+}
+
+/* 2011/09/22 MH Add for 92D global spin lock utilization. */
+void odm_GlobalAdapterCheck(void)
+{
+} /* odm_GlobalAdapterCheck */
+
+/* Description: */
+/* Set Single/Dual Antenna default setting for products that do not do detection in advance. */
+/* Added by Joseph, 2012.03.22 */
+void ODM_SingleDualAntennaDefaultSetting(struct odm_dm_struct *pDM_Odm)
+{
+ struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+
+ pDM_SWAT_Table->ANTA_ON = true;
+ pDM_SWAT_Table->ANTB_ON = true;
+}
+
+
+/* 2 8723A ANT DETECT */
+
+static void odm_PHY_SaveAFERegisters(struct odm_dm_struct *pDM_Odm, u32 *AFEReg, u32 *AFEBackup, u32 RegisterNum)
+{
+ u32 i;
+
+ /* RTPRINT(FINIT, INIT_IQK, ("Save ADDA parameters.\n")); */
+ for (i = 0; i < RegisterNum; i++)
+ AFEBackup[i] = ODM_GetBBReg(pDM_Odm, AFEReg[i], bMaskDWord);
+}
+
+static void odm_PHY_ReloadAFERegisters(struct odm_dm_struct *pDM_Odm, u32 *AFEReg, u32 *AFEBackup, u32 RegiesterNum)
+{
+ u32 i;
+
+ for (i = 0; i < RegiesterNum; i++)
+ ODM_SetBBReg(pDM_Odm, AFEReg[i], bMaskDWord, AFEBackup[i]);
+}
+
+/* 2 8723A ANT DETECT */
+/* Description: */
+/* Implement IQK single tone for RF DPK loopback and BB PSD scanning. */
+/* This function is cooperated with BB team Neil. */
+bool ODM_SingleDualAntennaDetection(struct odm_dm_struct *pDM_Odm, u8 mode)
+{
+ struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+ u32 CurrentChannel, RfLoopReg;
+ u8 n;
+ u32 Reg88c, Regc08, Reg874, Regc50;
+ u8 initial_gain = 0x5a;
+ u32 PSD_report_tmp;
+ u32 AntA_report = 0x0, AntB_report = 0x0, AntO_report = 0x0;
+ bool bResult = true;
+ u32 AFE_Backup[16];
+ u32 AFE_REG_8723A[16] = {
+ rRx_Wait_CCA, rTx_CCK_RFON,
+ rTx_CCK_BBON, rTx_OFDM_RFON,
+ rTx_OFDM_BBON, rTx_To_Rx,
+ rTx_To_Tx, rRx_CCK,
+ rRx_OFDM, rRx_Wait_RIFS,
+ rRx_TO_Rx, rStandby,
+ rSleep, rPMPD_ANAEN,
+ rFPGA0_XCD_SwitchControl, rBlue_Tooth};
+
+ if (!(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8192C)))
+ return bResult;
+
+ if (!(pDM_Odm->SupportAbility&ODM_BB_ANT_DIV))
+ return bResult;
+
+ if (pDM_Odm->SupportICType == ODM_RTL8192C) {
+ /* Which path in ADC/DAC is turnned on for PSD: both I/Q */
+ ODM_SetBBReg(pDM_Odm, 0x808, BIT10|BIT11, 0x3);
+ /* Ageraged number: 8 */
+ ODM_SetBBReg(pDM_Odm, 0x808, BIT12|BIT13, 0x1);
+ /* pts = 128; */
+ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x0);
+ }
+
+ /* 1 Backup Current RF/BB Settings */
+
+ CurrentChannel = ODM_GetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask);
+ RfLoopReg = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask);
+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, Antenna_A); /* change to Antenna A */
+ /* Step 1: USE IQK to transmitter single tone */
+
+ ODM_StallExecution(10);
+
+ /* Store A Path Register 88c, c08, 874, c50 */
+ Reg88c = ODM_GetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord);
+ Regc08 = ODM_GetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord);
+ Reg874 = ODM_GetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord);
+ Regc50 = ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord);
+
+ /* Store AFE Registers */
+ odm_PHY_SaveAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16);
+
+ /* Set PSD 128 pts */
+ ODM_SetBBReg(pDM_Odm, rFPGA0_PSDFunction, BIT14|BIT15, 0x0); /* 128 pts */
+
+ /* To SET CH1 to do */
+ ODM_SetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask, 0x01); /* Channel 1 */
+
+ /* AFE all on step */
+ ODM_SetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rTx_CCK_RFON, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rTx_CCK_BBON, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rTx_OFDM_RFON, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rTx_OFDM_BBON, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rTx_To_Rx, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rTx_To_Tx, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rRx_CCK, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rRx_OFDM, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rRx_Wait_RIFS, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rRx_TO_Rx, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rStandby, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rSleep, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rPMPD_ANAEN, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_SwitchControl, bMaskDWord, 0x6FDB25A4);
+ ODM_SetBBReg(pDM_Odm, rBlue_Tooth, bMaskDWord, 0x6FDB25A4);
+
+ /* 3 wire Disable */
+ ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, 0xCCF000C0);
+
+ /* BB IQK Setting */
+ ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800E4);
+ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22208000);
+
+ /* IQK setting tone@ 4.34Mhz */
+ ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008C1C);
+ ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00);
+
+
+ /* Page B init */
+ ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x00080000);
+ ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x0f600000);
+ ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x01004800);
+ ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f);
+ ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82150008);
+ ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28150008);
+ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x001028d0);
+
+ /* RF loop Setting */
+ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x0, 0xFFFFF, 0x50008);
+
+ /* IQK Single tone start */
+ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
+ ODM_StallExecution(1000);
+ PSD_report_tmp = 0x0;
+
+ for (n = 0; n < 2; n++) {
+ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain);
+ if (PSD_report_tmp > AntA_report)
+ AntA_report = PSD_report_tmp;
+ }
+
+ PSD_report_tmp = 0x0;
+
+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B); /* change to Antenna B */
+ ODM_StallExecution(10);
+
+
+ for (n = 0; n < 2; n++) {
+ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain);
+ if (PSD_report_tmp > AntB_report)
+ AntB_report = PSD_report_tmp;
+ }
+
+ /* change to open case */
+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, 0); /* change to Ant A and B all open case */
+ ODM_StallExecution(10);
+
+ for (n = 0; n < 2; n++) {
+ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain);
+ if (PSD_report_tmp > AntO_report)
+ AntO_report = PSD_report_tmp;
+ }
+
+ /* Close IQK Single Tone function */
+ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+ PSD_report_tmp = 0x0;
+
+ /* 1 Return to antanna A */
+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A);
+ ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, Reg88c);
+ ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, Regc08);
+ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, Reg874);
+ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, 0x7F, 0x40);
+ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord, Regc50);
+ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, CurrentChannel);
+ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask, RfLoopReg);
+
+ /* Reload AFE Registers */
+ odm_PHY_ReloadAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16);
+
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_A[%d]= %d\n", 2416, AntA_report));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_B[%d]= %d\n", 2416, AntB_report));
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_O[%d]= %d\n", 2416, AntO_report));
+
+
+ if (pDM_Odm->SupportICType == ODM_RTL8723A) {
+ /* 2 Test Ant B based on Ant A is ON */
+ if (mode == ANTTESTB) {
+ if (AntA_report >= 100) {
+ if (AntB_report > (AntA_report+1)) {
+ pDM_SWAT_Table->ANTB_ON = false;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n"));
+ } else {
+ pDM_SWAT_Table->ANTB_ON = true;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Dual Antenna is A and B\n"));
+ }
+ } else {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n"));
+ pDM_SWAT_Table->ANTB_ON = false; /* Set Antenna B off as default */
+ bResult = false;
+ }
+ } else if (mode == ANTTESTALL) {
+ /* 2 Test Ant A and B based on DPDT Open */
+ if ((AntO_report >= 100)&(AntO_report < 118)) {
+ if (AntA_report > (AntO_report+1)) {
+ pDM_SWAT_Table->ANTA_ON = false;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant A is OFF"));
+ } else {
+ pDM_SWAT_Table->ANTA_ON = true;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant A is ON"));
+ }
+
+ if (AntB_report > (AntO_report+2)) {
+ pDM_SWAT_Table->ANTB_ON = false;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant B is OFF"));
+ } else {
+ pDM_SWAT_Table->ANTB_ON = true;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant B is ON"));
+ }
+ }
+ }
+ } else if (pDM_Odm->SupportICType == ODM_RTL8192C) {
+ if (AntA_report >= 100) {
+ if (AntB_report > (AntA_report+2)) {
+ pDM_SWAT_Table->ANTA_ON = false;
+ pDM_SWAT_Table->ANTB_ON = true;
+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B);
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna B\n"));
+ } else if (AntA_report > (AntB_report+2)) {
+ pDM_SWAT_Table->ANTA_ON = true;
+ pDM_SWAT_Table->ANTB_ON = false;
+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A);
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n"));
+ } else {
+ pDM_SWAT_Table->ANTA_ON = true;
+ pDM_SWAT_Table->ANTB_ON = true;
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+ ("ODM_SingleDualAntennaDetection(): Dual Antenna\n"));
+ }
+ } else {
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n"));
+ pDM_SWAT_Table->ANTA_ON = true; /* Set Antenna A on as default */
+ pDM_SWAT_Table->ANTB_ON = false; /* Set Antenna B off as default */
+ bResult = false;
+ }
+ }
+ return bResult;
+}
+
+/* Justin: According to the current RRSI to adjust Response Frame TX power, 2012/11/05 */
+void odm_dtc(struct odm_dm_struct *pDM_Odm)
+{
+}
diff --git a/drivers/staging/rtl8188eu/hal/odm_HWConfig.c b/drivers/staging/rtl8188eu/hal/odm_HWConfig.c
new file mode 100644
index 00000000000..19c509a2beb
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm_HWConfig.c
@@ -0,0 +1,596 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+/* include files */
+
+#include "odm_precomp.h"
+
+#define READ_AND_CONFIG READ_AND_CONFIG_MP
+
+#define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig##txt##ic(dm_odm))
+#define READ_AND_CONFIG_TC(ic, txt) (ODM_ReadAndConfig_TC##txt##ic(dm_odm))
+
+static u8 odm_QueryRxPwrPercentage(s8 AntPower)
+{
+ if ((AntPower <= -100) || (AntPower >= 20))
+ return 0;
+ else if (AntPower >= 0)
+ return 100;
+ else
+ return 100+AntPower;
+}
+
+/* 2012/01/12 MH MOve some signal strength smooth method to MP HAL layer. */
+/* IF other SW team do not support the feature, remove this section.?? */
+static s32 odm_sig_patch_lenove(struct odm_dm_struct *dm_odm, s32 CurrSig)
+{
+ return 0;
+}
+
+static s32 odm_sig_patch_netcore(struct odm_dm_struct *dm_odm, s32 CurrSig)
+{
+ return 0;
+}
+
+static s32 odm_SignalScaleMapping_92CSeries(struct odm_dm_struct *dm_odm, s32 CurrSig)
+{
+ s32 RetSig = 0;
+
+ if ((dm_odm->SupportInterface == ODM_ITRF_USB) ||
+ (dm_odm->SupportInterface == ODM_ITRF_SDIO)) {
+ if (CurrSig >= 51 && CurrSig <= 100)
+ RetSig = 100;
+ else if (CurrSig >= 41 && CurrSig <= 50)
+ RetSig = 80 + ((CurrSig - 40)*2);
+ else if (CurrSig >= 31 && CurrSig <= 40)
+ RetSig = 66 + (CurrSig - 30);
+ else if (CurrSig >= 21 && CurrSig <= 30)
+ RetSig = 54 + (CurrSig - 20);
+ else if (CurrSig >= 10 && CurrSig <= 20)
+ RetSig = 42 + (((CurrSig - 10) * 2) / 3);
+ else if (CurrSig >= 5 && CurrSig <= 9)
+ RetSig = 22 + (((CurrSig - 5) * 3) / 2);
+ else if (CurrSig >= 1 && CurrSig <= 4)
+ RetSig = 6 + (((CurrSig - 1) * 3) / 2);
+ else
+ RetSig = CurrSig;
+ }
+ return RetSig;
+}
+
+static s32 odm_SignalScaleMapping(struct odm_dm_struct *dm_odm, s32 CurrSig)
+{
+ if ((dm_odm->SupportPlatform == ODM_MP) &&
+ (dm_odm->SupportInterface != ODM_ITRF_PCIE) && /* USB & SDIO */
+ (dm_odm->PatchID == 10))
+ return odm_sig_patch_netcore(dm_odm, CurrSig);
+ else if ((dm_odm->SupportPlatform == ODM_MP) &&
+ (dm_odm->SupportInterface == ODM_ITRF_PCIE) &&
+ (dm_odm->PatchID == 19))
+ return odm_sig_patch_lenove(dm_odm, CurrSig);
+ else
+ return odm_SignalScaleMapping_92CSeries(dm_odm, CurrSig);
+}
+
+/* pMgntInfo->CustomerID == RT_CID_819x_Lenovo */
+static u8 odm_SQ_process_patch_RT_CID_819x_Lenovo(struct odm_dm_struct *dm_odm,
+ u8 isCCKrate, u8 PWDB_ALL, u8 path, u8 RSSI)
+{
+ return 0;
+}
+
+static u8 odm_EVMdbToPercentage(s8 Value)
+{
+ /* -33dB~0dB to 0%~99% */
+ s8 ret_val;
+
+ ret_val = Value;
+
+ if (ret_val >= 0)
+ ret_val = 0;
+ if (ret_val <= -33)
+ ret_val = -33;
+
+ ret_val = 0 - ret_val;
+ ret_val *= 3;
+
+ if (ret_val == 99)
+ ret_val = 100;
+ return ret_val;
+}
+
+static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
+ struct odm_phy_status_info *pPhyInfo,
+ u8 *pPhyStatus,
+ struct odm_per_pkt_info *pPktinfo)
+{
+ struct sw_ant_switch *pDM_SWAT_Table = &dm_odm->DM_SWAT_Table;
+ u8 i, Max_spatial_stream;
+ s8 rx_pwr[4], rx_pwr_all = 0;
+ u8 EVM, PWDB_ALL = 0, PWDB_ALL_BT;
+ u8 RSSI, total_rssi = 0;
+ u8 isCCKrate = 0;
+ u8 rf_rx_num = 0;
+ u8 cck_highpwr = 0;
+ u8 LNA_idx, VGA_idx;
+
+ struct phy_status_rpt *pPhyStaRpt = (struct phy_status_rpt *)pPhyStatus;
+
+ isCCKrate = ((pPktinfo->Rate >= DESC92C_RATE1M) && (pPktinfo->Rate <= DESC92C_RATE11M)) ? true : false;
+
+ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = -1;
+ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1;
+
+ if (isCCKrate) {
+ u8 report;
+ u8 cck_agc_rpt;
+
+ dm_odm->PhyDbgInfo.NumQryPhyStatusCCK++;
+ /* (1)Hardware does not provide RSSI for CCK */
+ /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */
+
+ cck_highpwr = dm_odm->bCckHighPower;
+
+ cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ;
+
+ /* 2011.11.28 LukeLee: 88E use different LNA & VGA gain table */
+ /* The RSSI formula should be modified according to the gain table */
+ /* In 88E, cck_highpwr is always set to 1 */
+ if (dm_odm->SupportICType & (ODM_RTL8188E|ODM_RTL8812)) {
+ LNA_idx = ((cck_agc_rpt & 0xE0) >> 5);
+ VGA_idx = (cck_agc_rpt & 0x1F);
+ switch (LNA_idx) {
+ case 7:
+ if (VGA_idx <= 27)
+ rx_pwr_all = -100 + 2*(27-VGA_idx); /* VGA_idx = 27~2 */
+ else
+ rx_pwr_all = -100;
+ break;
+ case 6:
+ rx_pwr_all = -48 + 2*(2-VGA_idx); /* VGA_idx = 2~0 */
+ break;
+ case 5:
+ rx_pwr_all = -42 + 2*(7-VGA_idx); /* VGA_idx = 7~5 */
+ break;
+ case 4:
+ rx_pwr_all = -36 + 2*(7-VGA_idx); /* VGA_idx = 7~4 */
+ break;
+ case 3:
+ rx_pwr_all = -24 + 2*(7-VGA_idx); /* VGA_idx = 7~0 */
+ break;
+ case 2:
+ if (cck_highpwr)
+ rx_pwr_all = -12 + 2*(5-VGA_idx); /* VGA_idx = 5~0 */
+ else
+ rx_pwr_all = -6 + 2*(5-VGA_idx);
+ break;
+ case 1:
+ rx_pwr_all = 8-2*VGA_idx;
+ break;
+ case 0:
+ rx_pwr_all = 14-2*VGA_idx;
+ break;
+ default:
+ break;
+ }
+ rx_pwr_all += 6;
+ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
+ if (!cck_highpwr) {
+ if (PWDB_ALL >= 80)
+ PWDB_ALL = ((PWDB_ALL-80)<<1)+((PWDB_ALL-80)>>1)+80;
+ else if ((PWDB_ALL <= 78) && (PWDB_ALL >= 20))
+ PWDB_ALL += 3;
+ if (PWDB_ALL > 100)
+ PWDB_ALL = 100;
+ }
+ } else {
+ if (!cck_highpwr) {
+ report = (cck_agc_rpt & 0xc0)>>6;
+ switch (report) {
+ /* 03312009 modified by cosa */
+ /* Modify the RF RNA gain value to -40, -20, -2, 14 by Jenyu's suggestion */
+ /* Note: different RF with the different RNA gain. */
+ case 0x3:
+ rx_pwr_all = -46 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x2:
+ rx_pwr_all = -26 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x1:
+ rx_pwr_all = -12 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x0:
+ rx_pwr_all = 16 - (cck_agc_rpt & 0x3e);
+ break;
+ }
+ } else {
+ report = (cck_agc_rpt & 0x60)>>5;
+ switch (report) {
+ case 0x3:
+ rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1) ;
+ break;
+ case 0x2:
+ rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f)<<1);
+ break;
+ case 0x1:
+ rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1);
+ break;
+ case 0x0:
+ rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1);
+ break;
+ }
+ }
+
+ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
+
+ /* Modification for ext-LNA board */
+ if (dm_odm->BoardType == ODM_BOARD_HIGHPWR) {
+ if ((cck_agc_rpt>>7) == 0) {
+ PWDB_ALL = (PWDB_ALL > 94) ? 100 : (PWDB_ALL+6);
+ } else {
+ if (PWDB_ALL > 38)
+ PWDB_ALL -= 16;
+ else
+ PWDB_ALL = (PWDB_ALL <= 16) ? (PWDB_ALL>>2) : (PWDB_ALL-12);
+ }
+
+ /* CCK modification */
+ if (PWDB_ALL > 25 && PWDB_ALL <= 60)
+ PWDB_ALL += 6;
+ } else {/* Modification for int-LNA board */
+ if (PWDB_ALL > 99)
+ PWDB_ALL -= 8;
+ else if (PWDB_ALL > 50 && PWDB_ALL <= 68)
+ PWDB_ALL += 4;
+ }
+ }
+
+ pPhyInfo->RxPWDBAll = PWDB_ALL;
+ pPhyInfo->BTRxRSSIPercentage = PWDB_ALL;
+ pPhyInfo->RecvSignalPower = rx_pwr_all;
+ /* (3) Get Signal Quality (EVM) */
+ if (pPktinfo->bPacketMatchBSSID) {
+ u8 SQ, SQ_rpt;
+
+ if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) {
+ SQ = odm_SQ_process_patch_RT_CID_819x_Lenovo(dm_odm, isCCKrate, PWDB_ALL, 0, 0);
+ } else if (pPhyInfo->RxPWDBAll > 40 && !dm_odm->bInHctTest) {
+ SQ = 100;
+ } else {
+ SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all;
+
+ if (SQ_rpt > 64)
+ SQ = 0;
+ else if (SQ_rpt < 20)
+ SQ = 100;
+ else
+ SQ = ((64-SQ_rpt) * 100) / 44;
+ }
+ pPhyInfo->SignalQuality = SQ;
+ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = SQ;
+ pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1;
+ }
+ } else { /* is OFDM rate */
+ dm_odm->PhyDbgInfo.NumQryPhyStatusOFDM++;
+
+ /* (1)Get RSSI for HT rate */
+
+ for (i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX; i++) {
+ /* 2008/01/30 MH we will judge RF RX path now. */
+ if (dm_odm->RFPathRxEnable & BIT(i))
+ rf_rx_num++;
+
+ rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain & 0x3F)*2) - 110;
+
+ pPhyInfo->RxPwr[i] = rx_pwr[i];
+
+ /* Translate DBM to percentage. */
+ RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]);
+ total_rssi += RSSI;
+
+ /* Modification for ext-LNA board */
+ if (dm_odm->BoardType == ODM_BOARD_HIGHPWR) {
+ if ((pPhyStaRpt->path_agc[i].trsw) == 1)
+ RSSI = (RSSI > 94) ? 100 : (RSSI + 6);
+ else
+ RSSI = (RSSI <= 16) ? (RSSI >> 3) : (RSSI - 16);
+
+ if ((RSSI <= 34) && (RSSI >= 4))
+ RSSI -= 4;
+ }
+
+ pPhyInfo->RxMIMOSignalStrength[i] = (u8)RSSI;
+
+ /* Get Rx snr value in DB */
+ pPhyInfo->RxSNR[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2);
+ dm_odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2);
+
+ /* Record Signal Strength for next packet */
+ if (pPktinfo->bPacketMatchBSSID) {
+ if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) {
+ if (i == ODM_RF_PATH_A)
+ pPhyInfo->SignalQuality = odm_SQ_process_patch_RT_CID_819x_Lenovo(dm_odm, isCCKrate, PWDB_ALL, i, RSSI);
+ }
+ }
+ }
+ /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */
+ rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1) & 0x7f) - 110;
+
+ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
+ PWDB_ALL_BT = PWDB_ALL;
+
+ pPhyInfo->RxPWDBAll = PWDB_ALL;
+ pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT;
+ pPhyInfo->RxPower = rx_pwr_all;
+ pPhyInfo->RecvSignalPower = rx_pwr_all;
+
+ if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) {
+ /* do nothing */
+ } else {
+ /* (3)EVM of HT rate */
+ if (pPktinfo->Rate >= DESC92C_RATEMCS8 && pPktinfo->Rate <= DESC92C_RATEMCS15)
+ Max_spatial_stream = 2; /* both spatial stream make sense */
+ else
+ Max_spatial_stream = 1; /* only spatial stream 1 makes sense */
+
+ for (i = 0; i < Max_spatial_stream; i++) {
+ /* Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment */
+ /* fill most significant bit to "zero" when doing shifting operation which may change a negative */
+ /* value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. */
+ EVM = odm_EVMdbToPercentage((pPhyStaRpt->stream_rxevm[i])); /* dbm */
+
+ if (pPktinfo->bPacketMatchBSSID) {
+ if (i == ODM_RF_PATH_A) /* Fill value in RFD, Get the first spatial stream only */
+ pPhyInfo->SignalQuality = (u8)(EVM & 0xff);
+ pPhyInfo->RxMIMOSignalQuality[i] = (u8)(EVM & 0xff);
+ }
+ }
+ }
+ }
+ /* UI BSS List signal strength(in percentage), make it good looking, from 0~100. */
+ /* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */
+ if (isCCKrate) {
+ pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(dm_odm, PWDB_ALL));/* PWDB_ALL; */
+ } else {
+ if (rf_rx_num != 0)
+ pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(dm_odm, total_rssi /= rf_rx_num));
+ }
+
+ /* For 92C/92D HW (Hybrid) Antenna Diversity */
+ pDM_SWAT_Table->antsel = pPhyStaRpt->ant_sel;
+ /* For 88E HW Antenna Diversity */
+ dm_odm->DM_FatTable.antsel_rx_keep_0 = pPhyStaRpt->ant_sel;
+ dm_odm->DM_FatTable.antsel_rx_keep_1 = pPhyStaRpt->ant_sel_b;
+ dm_odm->DM_FatTable.antsel_rx_keep_2 = pPhyStaRpt->antsel_rx_keep_2;
+}
+
+void odm_Init_RSSIForDM(struct odm_dm_struct *dm_odm)
+{
+}
+
+static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
+ struct odm_phy_status_info *pPhyInfo,
+ struct odm_per_pkt_info *pPktinfo)
+{
+ s32 UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK;
+ s32 UndecoratedSmoothedOFDM, RSSI_Ave;
+ u8 isCCKrate = 0;
+ u8 RSSI_max, RSSI_min, i;
+ u32 OFDM_pkt = 0;
+ u32 Weighting = 0;
+ struct sta_info *pEntry;
+
+ if (pPktinfo->StationID == 0xFF)
+ return;
+ pEntry = dm_odm->pODM_StaInfo[pPktinfo->StationID];
+ if (!IS_STA_VALID(pEntry))
+ return;
+ if ((!pPktinfo->bPacketMatchBSSID))
+ return;
+
+ isCCKrate = ((pPktinfo->Rate >= DESC92C_RATE1M) && (pPktinfo->Rate <= DESC92C_RATE11M)) ? true : false;
+
+ /* Smart Antenna Debug Message------------------ */
+ if (dm_odm->SupportICType == ODM_RTL8188E) {
+ u8 antsel_tr_mux;
+ struct fast_ant_train *pDM_FatTable = &dm_odm->DM_FatTable;
+
+ if (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV) {
+ if (pDM_FatTable->FAT_State == FAT_TRAINING_STATE) {
+ if (pPktinfo->bPacketToSelf) {
+ antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) |
+ (pDM_FatTable->antsel_rx_keep_1<<1) |
+ pDM_FatTable->antsel_rx_keep_0;
+ pDM_FatTable->antSumRSSI[antsel_tr_mux] += pPhyInfo->RxPWDBAll;
+ pDM_FatTable->antRSSIcnt[antsel_tr_mux]++;
+ }
+ }
+ } else if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV)) {
+ if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) {
+ antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) |
+ (pDM_FatTable->antsel_rx_keep_1<<1) | pDM_FatTable->antsel_rx_keep_0;
+ ODM_AntselStatistics_88E(dm_odm, antsel_tr_mux, pPktinfo->StationID, pPhyInfo->RxPWDBAll);
+ }
+ }
+ }
+ /* Smart Antenna Debug Message------------------ */
+
+ UndecoratedSmoothedCCK = pEntry->rssi_stat.UndecoratedSmoothedCCK;
+ UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM;
+ UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB;
+
+ if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) {
+ if (!isCCKrate) { /* ofdm rate */
+ if (pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B] == 0) {
+ RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
+ } else {
+ if (pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A] > pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]) {
+ RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
+ RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B];
+ } else {
+ RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B];
+ RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
+ }
+ if ((RSSI_max - RSSI_min) < 3)
+ RSSI_Ave = RSSI_max;
+ else if ((RSSI_max - RSSI_min) < 6)
+ RSSI_Ave = RSSI_max - 1;
+ else if ((RSSI_max - RSSI_min) < 10)
+ RSSI_Ave = RSSI_max - 2;
+ else
+ RSSI_Ave = RSSI_max - 3;
+ }
+
+ /* 1 Process OFDM RSSI */
+ if (UndecoratedSmoothedOFDM <= 0) { /* initialize */
+ UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll;
+ } else {
+ if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) {
+ UndecoratedSmoothedOFDM =
+ (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) +
+ (RSSI_Ave)) / (Rx_Smooth_Factor);
+ UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1;
+ } else {
+ UndecoratedSmoothedOFDM =
+ (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) +
+ (RSSI_Ave)) / (Rx_Smooth_Factor);
+ }
+ }
+
+ pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0;
+
+ } else {
+ RSSI_Ave = pPhyInfo->RxPWDBAll;
+
+ /* 1 Process CCK RSSI */
+ if (UndecoratedSmoothedCCK <= 0) { /* initialize */
+ UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll;
+ } else {
+ if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) {
+ UndecoratedSmoothedCCK =
+ ((UndecoratedSmoothedCCK * (Rx_Smooth_Factor-1)) +
+ pPhyInfo->RxPWDBAll) / Rx_Smooth_Factor;
+ UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1;
+ } else {
+ UndecoratedSmoothedCCK =
+ ((UndecoratedSmoothedCCK * (Rx_Smooth_Factor-1)) +
+ pPhyInfo->RxPWDBAll) / Rx_Smooth_Factor;
+ }
+ }
+ pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1;
+ }
+ /* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */
+ if (pEntry->rssi_stat.ValidBit >= 64)
+ pEntry->rssi_stat.ValidBit = 64;
+ else
+ pEntry->rssi_stat.ValidBit++;
+
+ for (i = 0; i < pEntry->rssi_stat.ValidBit; i++)
+ OFDM_pkt += (u8)(pEntry->rssi_stat.PacketMap>>i)&BIT0;
+
+ if (pEntry->rssi_stat.ValidBit == 64) {
+ Weighting = ((OFDM_pkt<<4) > 64) ? 64 : (OFDM_pkt<<4);
+ UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6;
+ } else {
+ if (pEntry->rssi_stat.ValidBit != 0)
+ UndecoratedSmoothedPWDB = (OFDM_pkt * UndecoratedSmoothedOFDM +
+ (pEntry->rssi_stat.ValidBit-OFDM_pkt) *
+ UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit;
+ else
+ UndecoratedSmoothedPWDB = 0;
+ }
+ pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK;
+ pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM;
+ pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB;
+ }
+}
+
+/* Endianness before calling this API */
+static void ODM_PhyStatusQuery_92CSeries(struct odm_dm_struct *dm_odm,
+ struct odm_phy_status_info *pPhyInfo,
+ u8 *pPhyStatus,
+ struct odm_per_pkt_info *pPktinfo)
+{
+ odm_RxPhyStatus92CSeries_Parsing(dm_odm, pPhyInfo, pPhyStatus,
+ pPktinfo);
+ if (dm_odm->RSSI_test) {
+ /* Select the packets to do RSSI checking for antenna switching. */
+ if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon)
+ ODM_SwAntDivChkPerPktRssi(dm_odm, pPktinfo->StationID, pPhyInfo);
+ } else {
+ odm_Process_RSSIForDM(dm_odm, pPhyInfo, pPktinfo);
+ }
+}
+
+void ODM_PhyStatusQuery(struct odm_dm_struct *dm_odm,
+ struct odm_phy_status_info *pPhyInfo,
+ u8 *pPhyStatus, struct odm_per_pkt_info *pPktinfo)
+{
+ ODM_PhyStatusQuery_92CSeries(dm_odm, pPhyInfo, pPhyStatus, pPktinfo);
+}
+
+/* For future use. */
+void ODM_MacStatusQuery(struct odm_dm_struct *dm_odm, u8 *mac_stat,
+ u8 macid, bool pkt_match_bssid,
+ bool pkttoself, bool pkt_beacon)
+{
+ /* 2011/10/19 Driver team will handle in the future. */
+}
+
+enum HAL_STATUS ODM_ConfigRFWithHeaderFile(struct odm_dm_struct *dm_odm,
+ enum ODM_RF_RADIO_PATH content,
+ enum ODM_RF_RADIO_PATH rfpath)
+{
+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===>ODM_ConfigRFWithHeaderFile\n"));
+ if (dm_odm->SupportICType == ODM_RTL8188E) {
+ if (rfpath == ODM_RF_PATH_A)
+ READ_AND_CONFIG(8188E, _RadioA_1T_);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> ODM_ConfigRFWithHeaderFile() Radio_A:Rtl8188ERadioA_1TArray\n"));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> ODM_ConfigRFWithHeaderFile() Radio_B:Rtl8188ERadioB_1TArray\n"));
+ }
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("ODM_ConfigRFWithHeaderFile: Radio No %x\n", rfpath));
+ return HAL_STATUS_SUCCESS;
+}
+
+enum HAL_STATUS ODM_ConfigBBWithHeaderFile(struct odm_dm_struct *dm_odm,
+ enum odm_bb_config_type config_tp)
+{
+ if (dm_odm->SupportICType == ODM_RTL8188E) {
+ if (config_tp == CONFIG_BB_PHY_REG) {
+ READ_AND_CONFIG(8188E, _PHY_REG_1T_);
+ } else if (config_tp == CONFIG_BB_AGC_TAB) {
+ READ_AND_CONFIG(8188E, _AGC_TAB_1T_);
+ } else if (config_tp == CONFIG_BB_PHY_REG_PG) {
+ READ_AND_CONFIG(8188E, _PHY_REG_PG_);
+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+ (" ===> phy_ConfigBBWithHeaderFile() agc:Rtl8188EPHY_REG_PGArray\n"));
+ }
+ }
+ return HAL_STATUS_SUCCESS;
+}
+
+enum HAL_STATUS ODM_ConfigMACWithHeaderFile(struct odm_dm_struct *dm_odm)
+{
+ u8 result = HAL_STATUS_SUCCESS;
+ if (dm_odm->SupportICType == ODM_RTL8188E)
+ result = READ_AND_CONFIG(8188E, _MAC_REG_);
+ return result;
+}
diff --git a/drivers/staging/rtl8188eu/hal/odm_RTL8188E.c b/drivers/staging/rtl8188eu/hal/odm_RTL8188E.c
new file mode 100644
index 00000000000..58410f3e531
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm_RTL8188E.c
@@ -0,0 +1,399 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#include "odm_precomp.h"
+
+void ODM_DIG_LowerBound_88E(struct odm_dm_struct *dm_odm)
+{
+ struct rtw_dig *pDM_DigTable = &dm_odm->DM_DigTable;
+
+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) {
+ pDM_DigTable->rx_gain_range_min = (u8) pDM_DigTable->AntDiv_RSSI_max;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+ ("ODM_DIG_LowerBound_88E(): pDM_DigTable->AntDiv_RSSI_max=%d\n", pDM_DigTable->AntDiv_RSSI_max));
+ }
+ /* If only one Entry connected */
+}
+
+static void odm_RX_HWAntDivInit(struct odm_dm_struct *dm_odm)
+{
+ u32 value32;
+
+ if (*(dm_odm->mp_mode) == 1) {
+ dm_odm->AntDivType = CGCS_RX_SW_ANTDIV;
+ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 0); /* disable HW AntDiv */
+ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT31, 1); /* 1:CG, 0:CS */
+ return;
+ }
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_RX_HWAntDivInit()\n"));
+
+ /* MAC Setting */
+ value32 = ODM_GetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord);
+ ODM_SetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32|(BIT23|BIT25)); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */
+ /* Pin Settings */
+ ODM_SetBBReg(dm_odm, ODM_REG_PIN_CTRL_11N, BIT9|BIT8, 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0 antsel antselb by HW */
+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT10, 0); /* Reg864[10]=1'b0 antsel2 by HW */
+ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT22, 1); /* Regb2c[22]=1'b0 disable CS/CG switch */
+ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT31, 1); /* Regb2c[31]=1'b1 output at CG only */
+ /* OFDM Settings */
+ ODM_SetBBReg(dm_odm, ODM_REG_ANTDIV_PARA1_11N, bMaskDWord, 0x000000a0);
+ /* CCK Settings */
+ ODM_SetBBReg(dm_odm, ODM_REG_BB_PWR_SAV4_11N, BIT7, 1); /* Fix CCK PHY status report issue */
+ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA2_11N, BIT4, 1); /* CCK complete HW AntDiv within 64 samples */
+ ODM_UpdateRxIdleAnt_88E(dm_odm, MAIN_ANT);
+ ODM_SetBBReg(dm_odm, ODM_REG_ANT_MAPPING1_11N, 0xFFFF, 0x0201); /* antenna mapping table */
+}
+
+static void odm_TRX_HWAntDivInit(struct odm_dm_struct *dm_odm)
+{
+ u32 value32;
+
+ if (*(dm_odm->mp_mode) == 1) {
+ dm_odm->AntDivType = CGCS_RX_SW_ANTDIV;
+ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 0); /* disable HW AntDiv */
+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT5|BIT4|BIT3, 0); /* Default RX (0/1) */
+ return;
+ }
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_TRX_HWAntDivInit()\n"));
+
+ /* MAC Setting */
+ value32 = ODM_GetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord);
+ ODM_SetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32|(BIT23|BIT25)); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */
+ /* Pin Settings */
+ ODM_SetBBReg(dm_odm, ODM_REG_PIN_CTRL_11N, BIT9|BIT8, 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0 antsel antselb by HW */
+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT10, 0); /* Reg864[10]=1'b0 antsel2 by HW */
+ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT22, 0); /* Regb2c[22]=1'b0 disable CS/CG switch */
+ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT31, 1); /* Regb2c[31]=1'b1 output at CG only */
+ /* OFDM Settings */
+ ODM_SetBBReg(dm_odm, ODM_REG_ANTDIV_PARA1_11N, bMaskDWord, 0x000000a0);
+ /* CCK Settings */
+ ODM_SetBBReg(dm_odm, ODM_REG_BB_PWR_SAV4_11N, BIT7, 1); /* Fix CCK PHY status report issue */
+ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA2_11N, BIT4, 1); /* CCK complete HW AntDiv within 64 samples */
+ /* Tx Settings */
+ ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT21, 0); /* Reg80c[21]=1'b0 from TX Reg */
+ ODM_UpdateRxIdleAnt_88E(dm_odm, MAIN_ANT);
+
+ /* antenna mapping table */
+ if (!dm_odm->bIsMPChip) { /* testchip */
+ ODM_SetBBReg(dm_odm, ODM_REG_RX_DEFUALT_A_11N, BIT10|BIT9|BIT8, 1); /* Reg858[10:8]=3'b001 */
+ ODM_SetBBReg(dm_odm, ODM_REG_RX_DEFUALT_A_11N, BIT13|BIT12|BIT11, 2); /* Reg858[13:11]=3'b010 */
+ } else { /* MPchip */
+ ODM_SetBBReg(dm_odm, ODM_REG_ANT_MAPPING1_11N, bMaskDWord, 0x0201); /* Reg914=3'b010, Reg915=3'b001 */
+ }
+}
+
+static void odm_FastAntTrainingInit(struct odm_dm_struct *dm_odm)
+{
+ u32 value32, i;
+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+ u32 AntCombination = 2;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_FastAntTrainingInit()\n"));
+
+ if (*(dm_odm->mp_mode) == 1) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("dm_odm->AntDivType: %d\n", dm_odm->AntDivType));
+ return;
+ }
+
+ for (i = 0; i < 6; i++) {
+ dm_fat_tbl->Bssid[i] = 0;
+ dm_fat_tbl->antSumRSSI[i] = 0;
+ dm_fat_tbl->antRSSIcnt[i] = 0;
+ dm_fat_tbl->antAveRSSI[i] = 0;
+ }
+ dm_fat_tbl->TrainIdx = 0;
+ dm_fat_tbl->FAT_State = FAT_NORMAL_STATE;
+
+ /* MAC Setting */
+ value32 = ODM_GetMACReg(dm_odm, 0x4c, bMaskDWord);
+ ODM_SetMACReg(dm_odm, 0x4c, bMaskDWord, value32|(BIT23|BIT25)); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */
+ value32 = ODM_GetMACReg(dm_odm, 0x7B4, bMaskDWord);
+ ODM_SetMACReg(dm_odm, 0x7b4, bMaskDWord, value32|(BIT16|BIT17)); /* Reg7B4[16]=1 enable antenna training, Reg7B4[17]=1 enable A2 match */
+
+ /* Match MAC ADDR */
+ ODM_SetMACReg(dm_odm, 0x7b4, 0xFFFF, 0);
+ ODM_SetMACReg(dm_odm, 0x7b0, bMaskDWord, 0);
+
+ ODM_SetBBReg(dm_odm, 0x870, BIT9|BIT8, 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0 antsel antselb by HW */
+ ODM_SetBBReg(dm_odm, 0x864, BIT10, 0); /* Reg864[10]=1'b0 antsel2 by HW */
+ ODM_SetBBReg(dm_odm, 0xb2c, BIT22, 0); /* Regb2c[22]=1'b0 disable CS/CG switch */
+ ODM_SetBBReg(dm_odm, 0xb2c, BIT31, 1); /* Regb2c[31]=1'b1 output at CG only */
+ ODM_SetBBReg(dm_odm, 0xca4, bMaskDWord, 0x000000a0);
+
+ /* antenna mapping table */
+ if (AntCombination == 2) {
+ if (!dm_odm->bIsMPChip) { /* testchip */
+ ODM_SetBBReg(dm_odm, 0x858, BIT10|BIT9|BIT8, 1); /* Reg858[10:8]=3'b001 */
+ ODM_SetBBReg(dm_odm, 0x858, BIT13|BIT12|BIT11, 2); /* Reg858[13:11]=3'b010 */
+ } else { /* MPchip */
+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte0, 1);
+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte1, 2);
+ }
+ } else if (AntCombination == 7) {
+ if (!dm_odm->bIsMPChip) { /* testchip */
+ ODM_SetBBReg(dm_odm, 0x858, BIT10|BIT9|BIT8, 0); /* Reg858[10:8]=3'b000 */
+ ODM_SetBBReg(dm_odm, 0x858, BIT13|BIT12|BIT11, 1); /* Reg858[13:11]=3'b001 */
+ ODM_SetBBReg(dm_odm, 0x878, BIT16, 0);
+ ODM_SetBBReg(dm_odm, 0x858, BIT15|BIT14, 2); /* Reg878[0],Reg858[14:15])=3'b010 */
+ ODM_SetBBReg(dm_odm, 0x878, BIT19|BIT18|BIT17, 3);/* Reg878[3:1]=3b'011 */
+ ODM_SetBBReg(dm_odm, 0x878, BIT22|BIT21|BIT20, 4);/* Reg878[6:4]=3b'100 */
+ ODM_SetBBReg(dm_odm, 0x878, BIT25|BIT24|BIT23, 5);/* Reg878[9:7]=3b'101 */
+ ODM_SetBBReg(dm_odm, 0x878, BIT28|BIT27|BIT26, 6);/* Reg878[12:10]=3b'110 */
+ ODM_SetBBReg(dm_odm, 0x878, BIT31|BIT30|BIT29, 7);/* Reg878[15:13]=3b'111 */
+ } else { /* MPchip */
+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte0, 0);
+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte1, 1);
+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte2, 2);
+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte3, 3);
+ ODM_SetBBReg(dm_odm, 0x918, bMaskByte0, 4);
+ ODM_SetBBReg(dm_odm, 0x918, bMaskByte1, 5);
+ ODM_SetBBReg(dm_odm, 0x918, bMaskByte2, 6);
+ ODM_SetBBReg(dm_odm, 0x918, bMaskByte3, 7);
+ }
+ }
+
+ /* Default Ant Setting when no fast training */
+ ODM_SetBBReg(dm_odm, 0x80c, BIT21, 1); /* Reg80c[21]=1'b1 from TX Info */
+ ODM_SetBBReg(dm_odm, 0x864, BIT5|BIT4|BIT3, 0); /* Default RX */
+ ODM_SetBBReg(dm_odm, 0x864, BIT8|BIT7|BIT6, 1); /* Optional RX */
+
+ /* Enter Traing state */
+ ODM_SetBBReg(dm_odm, 0x864, BIT2|BIT1|BIT0, (AntCombination-1)); /* Reg864[2:0]=3'd6 ant combination=reg864[2:0]+1 */
+ ODM_SetBBReg(dm_odm, 0xc50, BIT7, 1); /* RegC50[7]=1'b1 enable HW AntDiv */
+}
+
+void ODM_AntennaDiversityInit_88E(struct odm_dm_struct *dm_odm)
+{
+ if (dm_odm->SupportICType != ODM_RTL8188E)
+ return;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_odm->AntDivType=%d\n", dm_odm->AntDivType));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_odm->bIsMPChip=%s\n", (dm_odm->bIsMPChip ? "true" : "false")));
+
+ if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV)
+ odm_RX_HWAntDivInit(dm_odm);
+ else if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV)
+ odm_TRX_HWAntDivInit(dm_odm);
+ else if (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV)
+ odm_FastAntTrainingInit(dm_odm);
+}
+
+void ODM_UpdateRxIdleAnt_88E(struct odm_dm_struct *dm_odm, u8 Ant)
+{
+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+ u32 DefaultAnt, OptionalAnt;
+
+ if (dm_fat_tbl->RxIdleAnt != Ant) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Update Rx Idle Ant\n"));
+ if (Ant == MAIN_ANT) {
+ DefaultAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
+ OptionalAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
+ } else {
+ DefaultAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
+ OptionalAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
+ }
+
+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) {
+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT5|BIT4|BIT3, DefaultAnt); /* Default RX */
+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT8|BIT7|BIT6, OptionalAnt); /* Optional RX */
+ ODM_SetBBReg(dm_odm, ODM_REG_ANTSEL_CTRL_11N, BIT14|BIT13|BIT12, DefaultAnt); /* Default TX */
+ ODM_SetMACReg(dm_odm, ODM_REG_RESP_TX_11N, BIT6|BIT7, DefaultAnt); /* Resp Tx */
+ } else if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV) {
+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT5|BIT4|BIT3, DefaultAnt); /* Default RX */
+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT8|BIT7|BIT6, OptionalAnt); /* Optional RX */
+ }
+ }
+ dm_fat_tbl->RxIdleAnt = Ant;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("RxIdleAnt=%s\n", (Ant == MAIN_ANT) ? "MAIN_ANT" : "AUX_ANT"));
+ pr_info("RxIdleAnt=%s\n", (Ant == MAIN_ANT) ? "MAIN_ANT" : "AUX_ANT");
+}
+
+static void odm_UpdateTxAnt_88E(struct odm_dm_struct *dm_odm, u8 Ant, u32 MacId)
+{
+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+ u8 TargetAnt;
+
+ if (Ant == MAIN_ANT)
+ TargetAnt = MAIN_ANT_CG_TRX;
+ else
+ TargetAnt = AUX_ANT_CG_TRX;
+ dm_fat_tbl->antsel_a[MacId] = TargetAnt&BIT0;
+ dm_fat_tbl->antsel_b[MacId] = (TargetAnt&BIT1)>>1;
+ dm_fat_tbl->antsel_c[MacId] = (TargetAnt&BIT2)>>2;
+
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+ ("Tx from TxInfo, TargetAnt=%s\n",
+ (Ant == MAIN_ANT) ? "MAIN_ANT" : "AUX_ANT"));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+ ("antsel_tr_mux=3'b%d%d%d\n",
+ dm_fat_tbl->antsel_c[MacId], dm_fat_tbl->antsel_b[MacId], dm_fat_tbl->antsel_a[MacId]));
+}
+
+void ODM_SetTxAntByTxInfo_88E(struct odm_dm_struct *dm_odm, u8 *pDesc, u8 macId)
+{
+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+
+ if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV)) {
+ SET_TX_DESC_ANTSEL_A_88E(pDesc, dm_fat_tbl->antsel_a[macId]);
+ SET_TX_DESC_ANTSEL_B_88E(pDesc, dm_fat_tbl->antsel_b[macId]);
+ SET_TX_DESC_ANTSEL_C_88E(pDesc, dm_fat_tbl->antsel_c[macId]);
+ }
+}
+
+void ODM_AntselStatistics_88E(struct odm_dm_struct *dm_odm, u8 antsel_tr_mux, u32 MacId, u8 RxPWDBAll)
+{
+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) {
+ if (antsel_tr_mux == MAIN_ANT_CG_TRX) {
+ dm_fat_tbl->MainAnt_Sum[MacId] += RxPWDBAll;
+ dm_fat_tbl->MainAnt_Cnt[MacId]++;
+ } else {
+ dm_fat_tbl->AuxAnt_Sum[MacId] += RxPWDBAll;
+ dm_fat_tbl->AuxAnt_Cnt[MacId]++;
+ }
+ } else if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV) {
+ if (antsel_tr_mux == MAIN_ANT_CGCS_RX) {
+ dm_fat_tbl->MainAnt_Sum[MacId] += RxPWDBAll;
+ dm_fat_tbl->MainAnt_Cnt[MacId]++;
+ } else {
+ dm_fat_tbl->AuxAnt_Sum[MacId] += RxPWDBAll;
+ dm_fat_tbl->AuxAnt_Cnt[MacId]++;
+ }
+ }
+}
+
+static void odm_HWAntDiv(struct odm_dm_struct *dm_odm)
+{
+ u32 i, MinRSSI = 0xFF, AntDivMaxRSSI = 0, MaxRSSI = 0, LocalMinRSSI, LocalMaxRSSI;
+ u32 Main_RSSI, Aux_RSSI;
+ u8 RxIdleAnt = 0, TargetAnt = 7;
+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+ struct rtw_dig *pDM_DigTable = &dm_odm->DM_DigTable;
+ struct sta_info *pEntry;
+
+ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+ pEntry = dm_odm->pODM_StaInfo[i];
+ if (IS_STA_VALID(pEntry)) {
+ /* 2 Caculate RSSI per Antenna */
+ Main_RSSI = (dm_fat_tbl->MainAnt_Cnt[i] != 0) ? (dm_fat_tbl->MainAnt_Sum[i]/dm_fat_tbl->MainAnt_Cnt[i]) : 0;
+ Aux_RSSI = (dm_fat_tbl->AuxAnt_Cnt[i] != 0) ? (dm_fat_tbl->AuxAnt_Sum[i]/dm_fat_tbl->AuxAnt_Cnt[i]) : 0;
+ TargetAnt = (Main_RSSI >= Aux_RSSI) ? MAIN_ANT : AUX_ANT;
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+ ("MacID=%d, MainAnt_Sum=%d, MainAnt_Cnt=%d\n",
+ i, dm_fat_tbl->MainAnt_Sum[i],
+ dm_fat_tbl->MainAnt_Cnt[i]));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+ ("MacID=%d, AuxAnt_Sum=%d, AuxAnt_Cnt=%d\n",
+ i, dm_fat_tbl->AuxAnt_Sum[i], dm_fat_tbl->AuxAnt_Cnt[i]));
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+ ("MacID=%d, Main_RSSI= %d, Aux_RSSI= %d\n",
+ i, Main_RSSI, Aux_RSSI));
+ /* 2 Select MaxRSSI for DIG */
+ LocalMaxRSSI = (Main_RSSI > Aux_RSSI) ? Main_RSSI : Aux_RSSI;
+ if ((LocalMaxRSSI > AntDivMaxRSSI) && (LocalMaxRSSI < 40))
+ AntDivMaxRSSI = LocalMaxRSSI;
+ if (LocalMaxRSSI > MaxRSSI)
+ MaxRSSI = LocalMaxRSSI;
+
+ /* 2 Select RX Idle Antenna */
+ if ((dm_fat_tbl->RxIdleAnt == MAIN_ANT) && (Main_RSSI == 0))
+ Main_RSSI = Aux_RSSI;
+ else if ((dm_fat_tbl->RxIdleAnt == AUX_ANT) && (Aux_RSSI == 0))
+ Aux_RSSI = Main_RSSI;
+
+ LocalMinRSSI = (Main_RSSI > Aux_RSSI) ? Aux_RSSI : Main_RSSI;
+ if (LocalMinRSSI < MinRSSI) {
+ MinRSSI = LocalMinRSSI;
+ RxIdleAnt = TargetAnt;
+ }
+ /* 2 Select TRX Antenna */
+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV)
+ odm_UpdateTxAnt_88E(dm_odm, TargetAnt, i);
+ }
+ dm_fat_tbl->MainAnt_Sum[i] = 0;
+ dm_fat_tbl->AuxAnt_Sum[i] = 0;
+ dm_fat_tbl->MainAnt_Cnt[i] = 0;
+ dm_fat_tbl->AuxAnt_Cnt[i] = 0;
+ }
+
+ /* 2 Set RX Idle Antenna */
+ ODM_UpdateRxIdleAnt_88E(dm_odm, RxIdleAnt);
+
+ pDM_DigTable->AntDiv_RSSI_max = AntDivMaxRSSI;
+ pDM_DigTable->RSSI_max = MaxRSSI;
+}
+
+void ODM_AntennaDiversity_88E(struct odm_dm_struct *dm_odm)
+{
+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+ if ((dm_odm->SupportICType != ODM_RTL8188E) || (!(dm_odm->SupportAbility & ODM_BB_ANT_DIV)))
+ return;
+ if (!dm_odm->bLinked) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_AntennaDiversity_88E(): No Link.\n"));
+ if (dm_fat_tbl->bBecomeLinked) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Turn off HW AntDiv\n"));
+ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 0); /* RegC50[7]=1'b1 enable HW AntDiv */
+ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA1_11N, BIT15, 0); /* Enable CCK AntDiv */
+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV)
+ ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT21, 0); /* Reg80c[21]=1'b0 from TX Reg */
+ dm_fat_tbl->bBecomeLinked = dm_odm->bLinked;
+ }
+ return;
+ } else {
+ if (!dm_fat_tbl->bBecomeLinked) {
+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Turn on HW AntDiv\n"));
+ /* Because HW AntDiv is disabled before Link, we enable HW AntDiv after link */
+ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 1); /* RegC50[7]=1'b1 enable HW AntDiv */
+ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA1_11N, BIT15, 1); /* Enable CCK AntDiv */
+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV)
+ ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT21, 1); /* Reg80c[21]=1'b1 from TX Info */
+ dm_fat_tbl->bBecomeLinked = dm_odm->bLinked;
+ }
+ }
+ if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV))
+ odm_HWAntDiv(dm_odm);
+}
+
+/* 3============================================================ */
+/* 3 Dynamic Primary CCA */
+/* 3============================================================ */
+
+void odm_PrimaryCCA_Init(struct odm_dm_struct *dm_odm)
+{
+ struct dyn_primary_cca *PrimaryCCA = &(dm_odm->DM_PriCCA);
+
+ PrimaryCCA->DupRTS_flag = 0;
+ PrimaryCCA->intf_flag = 0;
+ PrimaryCCA->intf_type = 0;
+ PrimaryCCA->Monitor_flag = 0;
+ PrimaryCCA->PriCCA_flag = 0;
+}
+
+bool ODM_DynamicPrimaryCCA_DupRTS(struct odm_dm_struct *dm_odm)
+{
+ struct dyn_primary_cca *PrimaryCCA = &(dm_odm->DM_PriCCA);
+
+ return PrimaryCCA->DupRTS_flag;
+}
+
+void odm_DynamicPrimaryCCA(struct odm_dm_struct *dm_odm)
+{
+ return;
+}
diff --git a/drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c b/drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c
new file mode 100644
index 00000000000..18c0533fbd0
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#include "odm_precomp.h"
+
+void odm_ConfigRFReg_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr,
+ u32 Data, enum ODM_RF_RADIO_PATH RF_PATH,
+ u32 RegAddr)
+{
+ if (Addr == 0xffe) {
+ ODM_sleep_ms(50);
+ } else if (Addr == 0xfd) {
+ ODM_delay_ms(5);
+ } else if (Addr == 0xfc) {
+ ODM_delay_ms(1);
+ } else if (Addr == 0xfb) {
+ ODM_delay_us(50);
+ } else if (Addr == 0xfa) {
+ ODM_delay_us(5);
+ } else if (Addr == 0xf9) {
+ ODM_delay_us(1);
+ } else {
+ ODM_SetRFReg(pDM_Odm, RF_PATH, RegAddr, bRFRegOffsetMask, Data);
+ /* Add 1us delay between BB/RF register setting. */
+ ODM_delay_us(1);
+ }
+}
+
+void odm_ConfigRF_RadioA_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data)
+{
+ u32 content = 0x1000; /* RF_Content: radioa_txt */
+ u32 maskforPhySet = (u32)(content&0xE000);
+
+ odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, ODM_RF_PATH_A, Addr|maskforPhySet);
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioA] %08X %08X\n", Addr, Data));
+}
+
+void odm_ConfigRF_RadioB_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data)
+{
+ u32 content = 0x1001; /* RF_Content: radiob_txt */
+ u32 maskforPhySet = (u32)(content&0xE000);
+
+ odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, ODM_RF_PATH_B, Addr|maskforPhySet);
+
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioB] %08X %08X\n", Addr, Data));
+}
+
+void odm_ConfigMAC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u8 Data)
+{
+ ODM_Write1Byte(pDM_Odm, Addr, Data);
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigMACWithHeaderFile: [MAC_REG] %08X %08X\n", Addr, Data));
+}
+
+void odm_ConfigBB_AGC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data)
+{
+ ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data);
+ /* Add 1us delay between BB/RF register setting. */
+ ODM_delay_us(1);
+
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE,
+ ("===> ODM_ConfigBBWithHeaderFile: [AGC_TAB] %08X %08X\n",
+ Addr, Data));
+}
+
+void odm_ConfigBB_PHY_REG_PG_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr,
+ u32 Bitmask, u32 Data)
+{
+ if (Addr == 0xfe) {
+ ODM_sleep_ms(50);
+ } else if (Addr == 0xfd) {
+ ODM_delay_ms(5);
+ } else if (Addr == 0xfc) {
+ ODM_delay_ms(1);
+ } else if (Addr == 0xfb) {
+ ODM_delay_us(50);
+ } else if (Addr == 0xfa) {
+ ODM_delay_us(5);
+ } else if (Addr == 0xf9) {
+ ODM_delay_us(1);
+ } else{
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+ ("===> @@@@@@@ ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X %08X\n",
+ Addr, Bitmask, Data));
+ storePwrIndexDiffRateOffset(pDM_Odm->Adapter, Addr, Bitmask, Data);
+ }
+}
+
+void odm_ConfigBB_PHY_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data)
+{
+ if (Addr == 0xfe) {
+ ODM_sleep_ms(50);
+ } else if (Addr == 0xfd) {
+ ODM_delay_ms(5);
+ } else if (Addr == 0xfc) {
+ ODM_delay_ms(1);
+ } else if (Addr == 0xfb) {
+ ODM_delay_us(50);
+ } else if (Addr == 0xfa) {
+ ODM_delay_us(5);
+ } else if (Addr == 0xf9) {
+ ODM_delay_us(1);
+ } else {
+ if (Addr == 0xa24)
+ pDM_Odm->RFCalibrateInfo.RegA24 = Data;
+ ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data);
+
+ /* Add 1us delay between BB/RF register setting. */
+ ODM_delay_us(1);
+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE,
+ ("===> ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X\n",
+ Addr, Data));
+ }
+}
diff --git a/drivers/staging/rtl8188eu/hal/odm_debug.c b/drivers/staging/rtl8188eu/hal/odm_debug.c
new file mode 100644
index 00000000000..84caadd6c8e
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm_debug.c
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+/* include files */
+
+#include "odm_precomp.h"
+
+void ODM_InitDebugSetting(struct odm_dm_struct *pDM_Odm)
+{
+ pDM_Odm->DebugLevel = ODM_DBG_TRACE;
+
+ pDM_Odm->DebugComponents = 0;
+}
+
+u32 GlobalDebugLevel;
diff --git a/drivers/staging/rtl8188eu/hal/odm_interface.c b/drivers/staging/rtl8188eu/hal/odm_interface.c
new file mode 100644
index 00000000000..59ad5bf4d94
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm_interface.c
@@ -0,0 +1,203 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#include "odm_precomp.h"
+/* ODM IO Relative API. */
+
+u8 ODM_Read1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ return rtw_read8(Adapter, RegAddr);
+}
+
+u16 ODM_Read2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ return rtw_read16(Adapter, RegAddr);
+}
+
+u32 ODM_Read4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ return rtw_read32(Adapter, RegAddr);
+}
+
+void ODM_Write1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u8 Data)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ rtw_write8(Adapter, RegAddr, Data);
+}
+
+void ODM_Write2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u16 Data)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ rtw_write16(Adapter, RegAddr, Data);
+}
+
+void ODM_Write4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 Data)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ rtw_write32(Adapter, RegAddr, Data);
+}
+
+void ODM_SetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ PHY_SetBBReg(Adapter, RegAddr, BitMask, Data);
+}
+
+u32 ODM_GetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ return PHY_QueryBBReg(Adapter, RegAddr, BitMask);
+}
+
+void ODM_SetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ PHY_SetBBReg(Adapter, RegAddr, BitMask, Data);
+}
+
+u32 ODM_GetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ return PHY_QueryBBReg(Adapter, RegAddr, BitMask);
+}
+
+void ODM_SetRFReg(struct odm_dm_struct *pDM_Odm, enum ODM_RF_RADIO_PATH eRFPath, u32 RegAddr, u32 BitMask, u32 Data)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ PHY_SetRFReg(Adapter, (enum rf_radio_path)eRFPath, RegAddr, BitMask, Data);
+}
+
+u32 ODM_GetRFReg(struct odm_dm_struct *pDM_Odm, enum ODM_RF_RADIO_PATH eRFPath, u32 RegAddr, u32 BitMask)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ return PHY_QueryRFReg(Adapter, (enum rf_radio_path)eRFPath, RegAddr, BitMask);
+}
+
+/* ODM Memory relative API. */
+void ODM_AllocateMemory(struct odm_dm_struct *pDM_Odm, void **pPtr, u32 length)
+{
+ *pPtr = rtw_zvmalloc(length);
+}
+
+/* length could be ignored, used to detect memory leakage. */
+void ODM_FreeMemory(struct odm_dm_struct *pDM_Odm, void *pPtr, u32 length)
+{
+ rtw_vmfree(pPtr, length);
+}
+
+s32 ODM_CompareMemory(struct odm_dm_struct *pDM_Odm, void *pBuf1, void *pBuf2, u32 length)
+{
+ return _rtw_memcmp(pBuf1, pBuf2, length);
+}
+
+/* ODM MISC relative API. */
+void ODM_AcquireSpinLock(struct odm_dm_struct *pDM_Odm, enum RT_SPINLOCK_TYPE type)
+{
+}
+
+void ODM_ReleaseSpinLock(struct odm_dm_struct *pDM_Odm, enum RT_SPINLOCK_TYPE type)
+{
+}
+
+/* Work item relative API. FOr MP driver only~! */
+void ODM_InitializeWorkItem(struct odm_dm_struct *pDM_Odm, void *pRtWorkItem,
+ RT_WORKITEM_CALL_BACK RtWorkItemCallback,
+ void *pContext, const char *szID)
+{
+}
+
+void ODM_StartWorkItem(void *pRtWorkItem)
+{
+}
+
+void ODM_StopWorkItem(void *pRtWorkItem)
+{
+}
+
+void ODM_FreeWorkItem(void *pRtWorkItem)
+{
+}
+
+void ODM_ScheduleWorkItem(void *pRtWorkItem)
+{
+}
+
+void ODM_IsWorkItemScheduled(void *pRtWorkItem)
+{
+}
+
+/* ODM Timer relative API. */
+void ODM_StallExecution(u32 usDelay)
+{
+ rtw_udelay_os(usDelay);
+}
+
+void ODM_delay_ms(u32 ms)
+{
+ rtw_mdelay_os(ms);
+}
+
+void ODM_delay_us(u32 us)
+{
+ rtw_udelay_os(us);
+}
+
+void ODM_sleep_ms(u32 ms)
+{
+ rtw_msleep_os(ms);
+}
+
+void ODM_sleep_us(u32 us)
+{
+ rtw_usleep_os(us);
+}
+
+void ODM_SetTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer, u32 msDelay)
+{
+ _set_timer(pTimer, msDelay); /* ms */
+}
+
+void ODM_InitializeTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer,
+ void *CallBackFunc, void *pContext,
+ const char *szID)
+{
+ struct adapter *Adapter = pDM_Odm->Adapter;
+ _init_timer(pTimer, Adapter->pnetdev, CallBackFunc, pDM_Odm);
+}
+
+void ODM_CancelTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer)
+{
+ _cancel_timer_ex(pTimer);
+}
+
+void ODM_ReleaseTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer)
+{
+}
+
+/* ODM FW relative API. */
+u32 ODM_FillH2CCmd(u8 *pH2CBuffer, u32 H2CBufferLen, u32 CmdNum,
+ u32 *pElementID, u32 *pCmdLen,
+ u8 **pCmbBuffer, u8 *CmdStartSeq)
+{
+ return true;
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
new file mode 100644
index 00000000000..8c858775451
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
@@ -0,0 +1,779 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_CMD_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <cmd_osdep.h>
+#include <mlme_osdep.h>
+#include <rtw_ioctl_set.h>
+
+#include <rtl8188e_hal.h>
+
+#define RTL88E_MAX_H2C_BOX_NUMS 4
+#define RTL88E_MAX_CMD_LEN 7
+#define RTL88E_MESSAGE_BOX_SIZE 4
+#define RTL88E_EX_MESSAGE_BOX_SIZE 4
+
+static u8 _is_fw_read_cmd_down(struct adapter *adapt, u8 msgbox_num)
+{
+ u8 read_down = false;
+ int retry_cnts = 100;
+
+ u8 valid;
+
+ do {
+ valid = rtw_read8(adapt, REG_HMETFR) & BIT(msgbox_num);
+ if (0 == valid)
+ read_down = true;
+ } while ((!read_down) && (retry_cnts--));
+
+ return read_down;
+}
+
+/*****************************************
+* H2C Msg format :
+* 0x1DF - 0x1D0
+*| 31 - 8 | 7-5 4 - 0 |
+*| h2c_msg |Class_ID CMD_ID |
+*
+* Extend 0x1FF - 0x1F0
+*|31 - 0 |
+*|ext_msg|
+******************************************/
+static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer)
+{
+ u8 bcmd_down = false;
+ s32 retry_cnts = 100;
+ u8 h2c_box_num;
+ u32 msgbox_addr;
+ u32 msgbox_ex_addr;
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ u8 cmd_idx, ext_cmd_len;
+ u32 h2c_cmd = 0;
+ u32 h2c_cmd_ex = 0;
+ s32 ret = _FAIL;
+
+_func_enter_;
+
+ if (!adapt->bFWReady) {
+ DBG_88E("FillH2CCmd_88E(): return H2C cmd because fw is not ready\n");
+ return ret;
+ }
+
+ if (!pCmdBuffer)
+ goto exit;
+ if (CmdLen > RTL88E_MAX_CMD_LEN)
+ goto exit;
+ if (adapt->bSurpriseRemoved)
+ goto exit;
+
+ /* pay attention to if race condition happened in H2C cmd setting. */
+ do {
+ h2c_box_num = haldata->LastHMEBoxNum;
+
+ if (!_is_fw_read_cmd_down(adapt, h2c_box_num)) {
+ DBG_88E(" fw read cmd failed...\n");
+ goto exit;
+ }
+
+ *(u8 *)(&h2c_cmd) = ElementID;
+
+ if (CmdLen <= 3) {
+ memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen);
+ } else {
+ memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, 3);
+ ext_cmd_len = CmdLen-3;
+ memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer+3, ext_cmd_len);
+
+ /* Write Ext command */
+ msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * RTL88E_EX_MESSAGE_BOX_SIZE);
+ for (cmd_idx = 0; cmd_idx < ext_cmd_len; cmd_idx++) {
+ rtw_write8(adapt, msgbox_ex_addr+cmd_idx, *((u8 *)(&h2c_cmd_ex)+cmd_idx));
+ }
+ }
+ /* Write command */
+ msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * RTL88E_MESSAGE_BOX_SIZE);
+ for (cmd_idx = 0; cmd_idx < RTL88E_MESSAGE_BOX_SIZE; cmd_idx++) {
+ rtw_write8(adapt, msgbox_addr+cmd_idx, *((u8 *)(&h2c_cmd)+cmd_idx));
+ }
+ bcmd_down = true;
+
+ haldata->LastHMEBoxNum = (h2c_box_num+1) % RTL88E_MAX_H2C_BOX_NUMS;
+
+ } while ((!bcmd_down) && (retry_cnts--));
+
+ ret = _SUCCESS;
+
+exit:
+
+_func_exit_;
+
+ return ret;
+}
+
+u8 rtl8188e_set_rssi_cmd(struct adapter *adapt, u8 *param)
+{
+ u8 res = _SUCCESS;
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+_func_enter_;
+
+ if (haldata->fw_ractrl) {
+ ;
+ } else {
+ DBG_88E("==>%s fw dont support RA\n", __func__);
+ res = _FAIL;
+ }
+
+_func_exit_;
+
+ return res;
+}
+
+u8 rtl8188e_set_raid_cmd(struct adapter *adapt, u32 mask)
+{
+ u8 buf[3];
+ u8 res = _SUCCESS;
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+
+_func_enter_;
+ if (haldata->fw_ractrl) {
+ __le32 lmask;
+
+ _rtw_memset(buf, 0, 3);
+ lmask = cpu_to_le32(mask);
+ memcpy(buf, &lmask, 3);
+
+ FillH2CCmd_88E(adapt, H2C_DM_MACID_CFG, 3, buf);
+ } else {
+ DBG_88E("==>%s fw dont support RA\n", __func__);
+ res = _FAIL;
+ }
+
+_func_exit_;
+
+ return res;
+}
+
+/* bitmap[0:27] = tx_rate_bitmap */
+/* bitmap[28:31]= Rate Adaptive id */
+/* arg[0:4] = macid */
+/* arg[5] = Short GI */
+void rtl8188e_Add_RateATid(struct adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_level)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(pAdapter);
+
+ u8 macid, init_rate, raid, shortGIrate = false;
+
+ macid = arg&0x1f;
+
+ raid = (bitmap>>28) & 0x0f;
+ bitmap &= 0x0fffffff;
+
+ if (rssi_level != DM_RATR_STA_INIT)
+ bitmap = ODM_Get_Rate_Bitmap(&haldata->odmpriv, macid, bitmap, rssi_level);
+
+ bitmap |= ((raid<<28)&0xf0000000);
+
+ init_rate = get_highest_rate_idx(bitmap&0x0fffffff)&0x3f;
+
+ shortGIrate = (arg&BIT(5)) ? true : false;
+
+ if (shortGIrate)
+ init_rate |= BIT(6);
+
+ raid = (bitmap>>28) & 0x0f;
+
+ bitmap &= 0x0fffffff;
+
+ DBG_88E("%s=> mac_id:%d, raid:%d, ra_bitmap=0x%x, shortGIrate=0x%02x\n",
+ __func__, macid, raid, bitmap, shortGIrate);
+
+ ODM_RA_UpdateRateInfo_8188E(&(haldata->odmpriv), macid, raid, bitmap, shortGIrate);
+}
+
+void rtl8188e_set_FwPwrMode_cmd(struct adapter *adapt, u8 Mode)
+{
+ struct setpwrmode_parm H2CSetPwrMode;
+ struct pwrctrl_priv *pwrpriv = &adapt->pwrctrlpriv;
+ u8 RLBM = 0; /* 0:Min, 1:Max, 2:User define */
+_func_enter_;
+
+ DBG_88E("%s: Mode=%d SmartPS=%d UAPSD=%d\n", __func__,
+ Mode, pwrpriv->smart_ps, adapt->registrypriv.uapsd_enable);
+
+ switch (Mode) {
+ case PS_MODE_ACTIVE:
+ H2CSetPwrMode.Mode = 0;
+ break;
+ case PS_MODE_MIN:
+ H2CSetPwrMode.Mode = 1;
+ break;
+ case PS_MODE_MAX:
+ RLBM = 1;
+ H2CSetPwrMode.Mode = 1;
+ break;
+ case PS_MODE_DTIM:
+ RLBM = 2;
+ H2CSetPwrMode.Mode = 1;
+ break;
+ case PS_MODE_UAPSD_WMM:
+ H2CSetPwrMode.Mode = 2;
+ break;
+ default:
+ H2CSetPwrMode.Mode = 0;
+ break;
+ }
+
+ H2CSetPwrMode.SmartPS_RLBM = (((pwrpriv->smart_ps<<4)&0xf0) | (RLBM & 0x0f));
+
+ H2CSetPwrMode.AwakeInterval = 1;
+
+ H2CSetPwrMode.bAllQueueUAPSD = adapt->registrypriv.uapsd_enable;
+
+ if (Mode > 0)
+ H2CSetPwrMode.PwrState = 0x00;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
+ else
+ H2CSetPwrMode.PwrState = 0x0C;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */
+
+ FillH2CCmd_88E(adapt, H2C_PS_PWR_MODE, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode);
+
+_func_exit_;
+}
+
+void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt)
+{
+ u8 opmode, macid;
+ u16 mst_rpt = le16_to_cpu(mstatus_rpt);
+ opmode = (u8) mst_rpt;
+ macid = (u8)(mst_rpt >> 8);
+
+ DBG_88E("### %s: MStatus=%x MACID=%d\n", __func__, opmode, macid);
+ FillH2CCmd_88E(adapt, H2C_COM_MEDIA_STATUS_RPT, sizeof(mst_rpt), (u8 *)&mst_rpt);
+}
+
+static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength)
+{
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ u16 *fctrl;
+ u32 rate_len, pktlen;
+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
+ SetFrameSubType(pframe, WIFI_BEACON);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ /* timestamp will be inserted by hardware */
+ pframe += 8;
+ pktlen += 8;
+
+ /* beacon interval: 2 bytes */
+ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
+
+ pframe += 2;
+ pktlen += 2;
+
+ /* capability info: 2 bytes */
+ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2);
+
+ pframe += 2;
+ pktlen += 2;
+
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+ pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fixed_ie);
+ memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fixed_ie), pktlen);
+
+ goto _ConstructBeacon;
+ }
+
+ /* below for ad-hoc mode */
+
+ /* SSID */
+ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen);
+
+ /* supported rates... */
+ rate_len = rtw_get_rateset_len(cur_network->SupportedRates);
+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen);
+
+ /* DS parameter set */
+ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen);
+
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+ u32 ATIMWindow;
+ /* IBSS Parameter Set... */
+ ATIMWindow = 0;
+ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen);
+ }
+
+ /* todo: ERP IE */
+
+ /* EXTERNDED SUPPORTED RATE */
+ if (rate_len > 8)
+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen);
+
+ /* todo:HT for adhoc */
+
+_ConstructBeacon:
+
+ if ((pktlen + TXDESC_SIZE) > 512) {
+ DBG_88E("beacon frame too large\n");
+ return;
+ }
+
+ *pLength = pktlen;
+}
+
+static void ConstructPSPoll(struct adapter *adapt, u8 *pframe, u32 *pLength)
+{
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u16 *fctrl;
+
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ /* Frame control. */
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+ SetPwrMgt(fctrl);
+ SetFrameSubType(pframe, WIFI_PSPOLL);
+
+ /* AID. */
+ SetDuration(pframe, (pmlmeinfo->aid | 0xc000));
+
+ /* BSSID. */
+ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+ /* TA. */
+ memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
+
+ *pLength = 16;
+}
+
+static void ConstructNullFunctionData(struct adapter *adapt, u8 *pframe,
+ u32 *pLength,
+ u8 *StaAddr,
+ u8 bQoS,
+ u8 AC,
+ u8 bEosp,
+ u8 bForcePowerSave)
+{
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ u16 *fctrl;
+ u32 pktlen;
+ struct mlme_priv *pmlmepriv = &adapt->mlmepriv;
+ struct wlan_network *cur_network = &pmlmepriv->cur_network;
+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &pwlanhdr->frame_ctl;
+ *(fctrl) = 0;
+ if (bForcePowerSave)
+ SetPwrMgt(fctrl);
+
+ switch (cur_network->network.InfrastructureMode) {
+ case Ndis802_11Infrastructure:
+ SetToDs(fctrl);
+ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
+ break;
+ case Ndis802_11APMode:
+ SetFrDs(fctrl);
+ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, myid(&(adapt->eeprompriv)), ETH_ALEN);
+ break;
+ case Ndis802_11IBSS:
+ default:
+ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ break;
+ }
+
+ SetSeqNum(pwlanhdr, 0);
+
+ if (bQoS) {
+ struct rtw_ieee80211_hdr_3addr_qos *pwlanqoshdr;
+
+ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
+
+ pwlanqoshdr = (struct rtw_ieee80211_hdr_3addr_qos *)pframe;
+ SetPriority(&pwlanqoshdr->qc, AC);
+ SetEOSP(&pwlanqoshdr->qc, bEosp);
+
+ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos);
+ } else {
+ SetFrameSubType(pframe, WIFI_DATA_NULL);
+
+ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+ }
+
+ *pLength = pktlen;
+}
+
+static void ConstructProbeRsp(struct adapter *adapt, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID)
+{
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ u16 *fctrl;
+ u8 *mac, *bssid;
+ u32 pktlen;
+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ mac = myid(&(adapt->eeprompriv));
+ bssid = cur_network->MacAddress;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, bssid, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, 0);
+ SetFrameSubType(fctrl, WIFI_PROBERSP);
+
+ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+ pframe += pktlen;
+
+ if (cur_network->IELength > MAX_IE_SZ)
+ return;
+
+ memcpy(pframe, cur_network->IEs, cur_network->IELength);
+ pframe += cur_network->IELength;
+ pktlen += cur_network->IELength;
+
+ *pLength = pktlen;
+}
+
+/* To check if reserved page content is destroyed by beacon beacuse beacon is too large. */
+/* 2010.06.23. Added by tynli. */
+void CheckFwRsvdPageContent(struct adapter *Adapter)
+{
+}
+
+/* */
+/* Description: Fill the reserved packets that FW will use to RSVD page. */
+/* Now we just send 4 types packet to rsvd page. */
+/* (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */
+/* Input: */
+/* bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */
+/* so we need to set the packet length to total lengh. */
+/* true: At the second time, we should send the first packet (default:beacon) */
+/* to Hw again and set the lengh in descriptor to the real beacon lengh. */
+/* 2009.10.15 by tynli. */
+static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
+{
+ struct hal_data_8188e *haldata;
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ struct xmit_priv *pxmitpriv;
+ struct mlme_ext_priv *pmlmeext;
+ struct mlme_ext_info *pmlmeinfo;
+ u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength;
+ u32 NullDataLength, QosNullLength;
+ u8 *ReservedPagePacket;
+ u8 PageNum, PageNeed, TxDescLen;
+ u16 BufIndex;
+ u32 TotalPacketLen;
+ struct rsvdpage_loc RsvdPageLoc;
+
+ DBG_88E("%s\n", __func__);
+ ReservedPagePacket = (u8 *)rtw_zmalloc(1000);
+ if (ReservedPagePacket == NULL) {
+ DBG_88E("%s: alloc ReservedPagePacket fail!\n", __func__);
+ return;
+ }
+
+ haldata = GET_HAL_DATA(adapt);
+ pxmitpriv = &adapt->xmitpriv;
+ pmlmeext = &adapt->mlmeextpriv;
+ pmlmeinfo = &pmlmeext->mlmext_info;
+
+ TxDescLen = TXDESC_SIZE;
+ PageNum = 0;
+
+ /* 3 (1) beacon * 2 pages */
+ BufIndex = TXDESC_OFFSET;
+ ConstructBeacon(adapt, &ReservedPagePacket[BufIndex], &BeaconLength);
+
+ /* When we count the first page size, we need to reserve description size for the RSVD */
+ /* packet, it will be filled in front of the packet in TXPKTBUF. */
+ PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength);
+ /* To reserved 2 pages for beacon buffer. 2010.06.24. */
+ if (PageNeed == 1)
+ PageNeed += 1;
+ PageNum += PageNeed;
+ haldata->FwRsvdPageStartOffset = PageNum;
+
+ BufIndex += PageNeed*128;
+
+ /* 3 (2) ps-poll *1 page */
+ RsvdPageLoc.LocPsPoll = PageNum;
+ ConstructPSPoll(adapt, &ReservedPagePacket[BufIndex], &PSPollLength);
+ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false);
+
+ PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength);
+ PageNum += PageNeed;
+
+ BufIndex += PageNeed*128;
+
+ /* 3 (3) null data * 1 page */
+ RsvdPageLoc.LocNullData = PageNum;
+ ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], &NullDataLength, get_my_bssid(&pmlmeinfo->network), false, 0, 0, false);
+ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
+
+ PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
+ PageNum += PageNeed;
+
+ BufIndex += PageNeed*128;
+
+ /* 3 (4) probe response * 1page */
+ RsvdPageLoc.LocProbeRsp = PageNum;
+ ConstructProbeRsp(adapt, &ReservedPagePacket[BufIndex], &ProbeRspLength, get_my_bssid(&pmlmeinfo->network), false);
+ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false);
+
+ PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength);
+ PageNum += PageNeed;
+
+ BufIndex += PageNeed*128;
+
+ /* 3 (5) Qos null data */
+ RsvdPageLoc.LocQosNull = PageNum;
+ ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex],
+ &QosNullLength, get_my_bssid(&pmlmeinfo->network), true, 0, 0, false);
+ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false);
+
+ PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength);
+ PageNum += PageNeed;
+
+ TotalPacketLen = BufIndex + QosNullLength;
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ goto exit;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(adapt, pattrib);
+ pattrib->qsel = 0x10;
+ pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
+ pattrib->pktlen = pattrib->last_txcmdsz;
+ memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
+
+ rtw_hal_mgnt_xmit(adapt, pmgntframe);
+
+ DBG_88E("%s: Set RSVD page location to Fw\n", __func__);
+ FillH2CCmd_88E(adapt, H2C_COM_RSVD_PAGE, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
+
+exit:
+ kfree(ReservedPagePacket);
+}
+
+void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ bool bSendBeacon = false;
+ bool bcn_valid = false;
+ u8 DLBcnCount = 0;
+ u32 poll = 0;
+
+_func_enter_;
+
+ DBG_88E("%s mstatus(%x)\n", __func__, mstatus);
+
+ if (mstatus == 1) {
+ /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
+ /* Suggested by filen. Added by tynli. */
+ rtw_write16(adapt, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
+ /* Do not set TSF again here or vWiFi beacon DMA INT will not work. */
+
+ /* Set REG_CR bit 8. DMA beacon by SW. */
+ haldata->RegCR_1 |= BIT0;
+ rtw_write8(adapt, REG_CR+1, haldata->RegCR_1);
+
+ /* Disable Hw protection for a time which revserd for Hw sending beacon. */
+ /* Fix download reserved page packet fail that access collision with the protection time. */
+ /* 2010.05.11. Added by tynli. */
+ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)&(~BIT(3)));
+ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)|BIT(4));
+
+ if (haldata->RegFwHwTxQCtrl&BIT6) {
+ DBG_88E("HalDownloadRSVDPage(): There is an Adapter is sending beacon.\n");
+ bSendBeacon = true;
+ }
+
+ /* Set FWHW_TXQ_CTRL 0x422[6]=0 to tell Hw the packet is not a real beacon frame. */
+ rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl&(~BIT6)));
+ haldata->RegFwHwTxQCtrl &= (~BIT6);
+
+ /* Clear beacon valid check bit. */
+ rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL);
+ DLBcnCount = 0;
+ poll = 0;
+ do {
+ /* download rsvd page. */
+ SetFwRsvdPagePkt(adapt, false);
+ DLBcnCount++;
+ do {
+ rtw_yield_os();
+ /* rtw_mdelay_os(10); */
+ /* check rsvd page download OK. */
+ rtw_hal_get_hwreg(adapt, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid));
+ poll++;
+ } while (!bcn_valid && (poll%10) != 0 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
+ } while (!bcn_valid && DLBcnCount <= 100 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
+
+ if (adapt->bSurpriseRemoved || adapt->bDriverStopped)
+ ;
+ else if (!bcn_valid)
+ DBG_88E("%s: 1 Download RSVD page failed! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll);
+ else
+ DBG_88E("%s: 1 Download RSVD success! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll);
+ /* */
+ /* We just can send the reserved page twice during the time that Tx thread is stopped (e.g. pnpsetpower) */
+ /* becuase we need to free the Tx BCN Desc which is used by the first reserved page packet. */
+ /* At run time, we cannot get the Tx Desc until it is released in TxHandleInterrupt() so we will return */
+ /* the beacon TCB in the following code. 2011.11.23. by tynli. */
+ /* */
+
+ /* Enable Bcn */
+ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)|BIT(3));
+ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)&(~BIT(4)));
+
+ /* To make sure that if there exists an adapter which would like to send beacon. */
+ /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */
+ /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
+ /* the beacon cannot be sent by HW. */
+ /* 2010.06.23. Added by tynli. */
+ if (bSendBeacon) {
+ rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl|BIT6));
+ haldata->RegFwHwTxQCtrl |= BIT6;
+ }
+
+ /* Update RSVD page location H2C to Fw. */
+ if (bcn_valid) {
+ rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL);
+ DBG_88E("Set RSVD page location to Fw.\n");
+ }
+
+ /* Do not enable HW DMA BCN or it will cause Pcie interface hang by timing issue. 2011.11.24. by tynli. */
+ /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
+ haldata->RegCR_1 &= (~BIT0);
+ rtw_write8(adapt, REG_CR+1, haldata->RegCR_1);
+ }
+_func_exit_;
+}
+
+void rtl8188e_set_p2p_ps_offload_cmd(struct adapter *adapt, u8 p2p_ps_state)
+{
+#ifdef CONFIG_88EU_P2P
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ struct wifidirect_info *pwdinfo = &(adapt->wdinfo);
+ struct P2P_PS_Offload_t *p2p_ps_offload = &haldata->p2p_ps_offload;
+ u8 i;
+
+_func_enter_;
+
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ DBG_88E("P2P_PS_DISABLE\n");
+ _rtw_memset(p2p_ps_offload, 0, 1);
+ break;
+ case P2P_PS_ENABLE:
+ DBG_88E("P2P_PS_ENABLE\n");
+ /* update CTWindow value. */
+ if (pwdinfo->ctwindow > 0) {
+ p2p_ps_offload->CTWindow_En = 1;
+ rtw_write8(adapt, REG_P2P_CTWIN, pwdinfo->ctwindow);
+ }
+
+ /* hw only support 2 set of NoA */
+ for (i = 0; i < pwdinfo->noa_num; i++) {
+ /* To control the register setting for which NOA */
+ rtw_write8(adapt, REG_NOA_DESC_SEL, (i << 4));
+ if (i == 0)
+ p2p_ps_offload->NoA0_En = 1;
+ else
+ p2p_ps_offload->NoA1_En = 1;
+
+ /* config P2P NoA Descriptor Register */
+ rtw_write32(adapt, REG_NOA_DESC_DURATION, pwdinfo->noa_duration[i]);
+ rtw_write32(adapt, REG_NOA_DESC_INTERVAL, pwdinfo->noa_interval[i]);
+ rtw_write32(adapt, REG_NOA_DESC_START, pwdinfo->noa_start_time[i]);
+ rtw_write8(adapt, REG_NOA_DESC_COUNT, pwdinfo->noa_count[i]);
+ }
+
+ if ((pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0)) {
+ /* rst p2p circuit */
+ rtw_write8(adapt, REG_DUAL_TSF_RST, BIT(4));
+
+ p2p_ps_offload->Offload_En = 1;
+
+ if (pwdinfo->role == P2P_ROLE_GO) {
+ p2p_ps_offload->role = 1;
+ p2p_ps_offload->AllStaSleep = 0;
+ } else {
+ p2p_ps_offload->role = 0;
+ }
+
+ p2p_ps_offload->discovery = 0;
+ }
+ break;
+ case P2P_PS_SCAN:
+ DBG_88E("P2P_PS_SCAN\n");
+ p2p_ps_offload->discovery = 1;
+ break;
+ case P2P_PS_SCAN_DONE:
+ DBG_88E("P2P_PS_SCAN_DONE\n");
+ p2p_ps_offload->discovery = 0;
+ pwdinfo->p2p_ps_state = P2P_PS_ENABLE;
+ break;
+ default:
+ break;
+ }
+
+ FillH2CCmd_88E(adapt, H2C_PS_P2P_OFFLOAD, 1, (u8 *)p2p_ps_offload);
+#endif
+
+_func_exit_;
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
new file mode 100644
index 00000000000..9c2e7a20c09
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
@@ -0,0 +1,268 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+/* */
+/* Description: */
+/* */
+/* This file is for 92CE/92CU dynamic mechanism only */
+/* */
+/* */
+/* */
+#define _RTL8188E_DM_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <rtl8188e_hal.h>
+
+static void dm_CheckStatistics(struct adapter *Adapter)
+{
+}
+
+/* Initialize GPIO setting registers */
+static void dm_InitGPIOSetting(struct adapter *Adapter)
+{
+ u8 tmp1byte;
+
+ tmp1byte = rtw_read8(Adapter, REG_GPIO_MUXCFG);
+ tmp1byte &= (GPIOSEL_GPIO | ~GPIOSEL_ENBT);
+
+ rtw_write8(Adapter, REG_GPIO_MUXCFG, tmp1byte);
+}
+
+/* */
+/* functions */
+/* */
+static void Init_ODM_ComInfo_88E(struct adapter *Adapter)
+{
+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+ struct dm_priv *pdmpriv = &hal_data->dmpriv;
+ struct odm_dm_struct *dm_odm = &(hal_data->odmpriv);
+ u8 cut_ver, fab_ver;
+
+ /* Init Value */
+ _rtw_memset(dm_odm, 0, sizeof(dm_odm));
+
+ dm_odm->Adapter = Adapter;
+
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_PLATFORM, ODM_CE);
+
+ if (Adapter->interface_type == RTW_GSPI)
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_INTERFACE, ODM_ITRF_SDIO);
+ else
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_INTERFACE, Adapter->interface_type);/* RTL871X_HCI_TYPE */
+
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_IC_TYPE, ODM_RTL8188E);
+
+ fab_ver = ODM_TSMC;
+ cut_ver = ODM_CUT_A;
+
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_FAB_VER, fab_ver);
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_CUT_VER, cut_ver);
+
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_MP_TEST_CHIP, IS_NORMAL_CHIP(hal_data->VersionID));
+
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_PATCH_ID, hal_data->CustomerID);
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_BWIFI_TEST, Adapter->registrypriv.wifi_spec);
+
+
+ if (hal_data->rf_type == RF_1T1R)
+ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_1T1R);
+ else if (hal_data->rf_type == RF_2T2R)
+ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R);
+ else if (hal_data->rf_type == RF_1T2R)
+ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_1T2R);
+
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_RF_ANTENNA_TYPE, hal_data->TRxAntDivType);
+
+ pdmpriv->InitODMFlag = ODM_RF_CALIBRATION |
+ ODM_RF_TX_PWR_TRACK;
+
+ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag);
+}
+
+static void Update_ODM_ComInfo_88E(struct adapter *Adapter)
+{
+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
+ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv;
+ struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv;
+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+ struct odm_dm_struct *dm_odm = &(hal_data->odmpriv);
+ struct dm_priv *pdmpriv = &hal_data->dmpriv;
+ int i;
+
+ pdmpriv->InitODMFlag = ODM_BB_DIG |
+ ODM_BB_RA_MASK |
+ ODM_BB_DYNAMIC_TXPWR |
+ ODM_BB_FA_CNT |
+ ODM_BB_RSSI_MONITOR |
+ ODM_BB_CCK_PD |
+ ODM_BB_PWR_SAVE |
+ ODM_MAC_EDCA_TURBO |
+ ODM_RF_CALIBRATION |
+ ODM_RF_TX_PWR_TRACK;
+ if (hal_data->AntDivCfg)
+ pdmpriv->InitODMFlag |= ODM_BB_ANT_DIV;
+
+ if (Adapter->registrypriv.mp_mode == 1) {
+ pdmpriv->InitODMFlag = ODM_RF_CALIBRATION |
+ ODM_RF_TX_PWR_TRACK;
+ }
+
+ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag);
+
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_TX_UNI, &(Adapter->xmitpriv.tx_bytes));
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_RX_UNI, &(Adapter->recvpriv.rx_bytes));
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_WM_MODE, &(pmlmeext->cur_wireless_mode));
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SEC_CHNL_OFFSET, &(hal_data->nCur40MhzPrimeSC));
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SEC_MODE, &(Adapter->securitypriv.dot11PrivacyAlgrthm));
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_BW, &(hal_data->CurrentChannelBW));
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_CHNL, &(hal_data->CurrentChannel));
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_NET_CLOSED, &(Adapter->net_closed));
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_MP_MODE, &(Adapter->registrypriv.mp_mode));
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SCAN, &(pmlmepriv->bScanInProcess));
+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_POWER_SAVING, &(pwrctrlpriv->bpower_saving));
+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_RF_ANTENNA_TYPE, hal_data->TRxAntDivType);
+
+ for (i = 0; i < NUM_STA; i++)
+ ODM_CmnInfoPtrArrayHook(dm_odm, ODM_CMNINFO_STA_STATUS, i, NULL);
+}
+
+void rtl8188e_InitHalDm(struct adapter *Adapter)
+{
+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+ struct dm_priv *pdmpriv = &hal_data->dmpriv;
+ struct odm_dm_struct *dm_odm = &(hal_data->odmpriv);
+
+ dm_InitGPIOSetting(Adapter);
+ pdmpriv->DM_Type = DM_Type_ByDriver;
+ pdmpriv->DMFlag = DYNAMIC_FUNC_DISABLE;
+ Update_ODM_ComInfo_88E(Adapter);
+ ODM_DMInit(dm_odm);
+ Adapter->fix_rate = 0xFF;
+}
+
+void rtl8188e_HalDmWatchDog(struct adapter *Adapter)
+{
+ bool fw_cur_in_ps = false;
+ bool fw_ps_awake = true;
+ u8 hw_init_completed = false;
+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+
+ _func_enter_;
+ hw_init_completed = Adapter->hw_init_completed;
+
+ if (!hw_init_completed)
+ goto skip_dm;
+
+ fw_cur_in_ps = Adapter->pwrctrlpriv.bFwCurrentInPSMode;
+ rtw_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&fw_ps_awake));
+
+ /* Fw is under p2p powersaving mode, driver should stop dynamic mechanism. */
+ /* modifed by thomas. 2011.06.11. */
+ if (Adapter->wdinfo.p2p_ps_mode)
+ fw_ps_awake = false;
+
+ if (hw_init_completed && ((!fw_cur_in_ps) && fw_ps_awake)) {
+ /* Calculate Tx/Rx statistics. */
+ dm_CheckStatistics(Adapter);
+
+ _func_exit_;
+ }
+
+ /* ODM */
+ if (hw_init_completed) {
+ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv;
+ u8 bLinked = false;
+
+ if ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE))) {
+ if (Adapter->stapriv.asoc_sta_count > 2)
+ bLinked = true;
+ } else {/* Station mode */
+ if (check_fwstate(pmlmepriv, _FW_LINKED))
+ bLinked = true;
+ }
+
+ ODM_CmnInfoUpdate(&hal_data->odmpriv, ODM_CMNINFO_LINK, bLinked);
+ ODM_DMWatchdog(&hal_data->odmpriv);
+ }
+skip_dm:
+ /* Check GPIO to determine current RF on/off and Pbc status. */
+ /* Check Hardware Radio ON/OFF or not */
+ return;
+}
+
+void rtl8188e_init_dm_priv(struct adapter *Adapter)
+{
+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+ struct dm_priv *pdmpriv = &hal_data->dmpriv;
+ struct odm_dm_struct *podmpriv = &hal_data->odmpriv;
+
+ _rtw_memset(pdmpriv, 0, sizeof(struct dm_priv));
+ Init_ODM_ComInfo_88E(Adapter);
+ ODM_InitDebugSetting(podmpriv);
+}
+
+void rtl8188e_deinit_dm_priv(struct adapter *Adapter)
+{
+}
+
+/* Add new function to reset the state of antenna diversity before link. */
+/* Compare RSSI for deciding antenna */
+void AntDivCompare8188E(struct adapter *Adapter, struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src)
+{
+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+
+ if (0 != hal_data->AntDivCfg) {
+ /* select optimum_antenna for before linked =>For antenna diversity */
+ if (dst->Rssi >= src->Rssi) {/* keep org parameter */
+ src->Rssi = dst->Rssi;
+ src->PhyInfo.Optimum_antenna = dst->PhyInfo.Optimum_antenna;
+ }
+ }
+}
+
+/* Add new function to reset the state of antenna diversity before link. */
+u8 AntDivBeforeLink8188E(struct adapter *Adapter)
+{
+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+ struct odm_dm_struct *dm_odm = &hal_data->odmpriv;
+ struct sw_ant_switch *dm_swat_tbl = &dm_odm->DM_SWAT_Table;
+ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
+
+ /* Condition that does not need to use antenna diversity. */
+ if (hal_data->AntDivCfg == 0)
+ return false;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED))
+ return false;
+
+ if (dm_swat_tbl->SWAS_NoLink_State == 0) {
+ /* switch channel */
+ dm_swat_tbl->SWAS_NoLink_State = 1;
+ dm_swat_tbl->CurAntenna = (dm_swat_tbl->CurAntenna == Antenna_A) ? Antenna_B : Antenna_A;
+
+ rtw_antenna_select_cmd(Adapter, dm_swat_tbl->CurAntenna, false);
+ return true;
+ } else {
+ dm_swat_tbl->SWAS_NoLink_State = 0;
+ return false;
+ }
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
new file mode 100644
index 00000000000..292ba62d722
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
@@ -0,0 +1,2378 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _HAL_INIT_C_
+
+#include <drv_types.h>
+#include <rtw_efuse.h>
+
+#include <rtl8188e_hal.h>
+
+#include <rtw_iol.h>
+
+#include <usb_ops.h>
+
+static void iol_mode_enable(struct adapter *padapter, u8 enable)
+{
+ u8 reg_0xf0 = 0;
+
+ if (enable) {
+ /* Enable initial offload */
+ reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG);
+ rtw_write8(padapter, REG_SYS_CFG, reg_0xf0|SW_OFFLOAD_EN);
+
+ if (!padapter->bFWReady) {
+ DBG_88E("bFWReady == false call reset 8051...\n");
+ _8051Reset88E(padapter);
+ }
+
+ } else {
+ /* disable initial offload */
+ reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG);
+ rtw_write8(padapter, REG_SYS_CFG, reg_0xf0 & ~SW_OFFLOAD_EN);
+ }
+}
+
+static s32 iol_execute(struct adapter *padapter, u8 control)
+{
+ s32 status = _FAIL;
+ u8 reg_0x88 = 0;
+ u32 start = 0, passing_time = 0;
+
+ control = control&0x0f;
+ reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0);
+ rtw_write8(padapter, REG_HMEBOX_E0, reg_0x88|control);
+
+ start = rtw_get_current_time();
+ while ((reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0)) & control &&
+ (passing_time = rtw_get_passing_time_ms(start)) < 1000) {
+ ;
+ }
+
+ reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0);
+ status = (reg_0x88 & control) ? _FAIL : _SUCCESS;
+ if (reg_0x88 & control<<4)
+ status = _FAIL;
+ return status;
+}
+
+static s32 iol_InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
+{
+ s32 rst = _SUCCESS;
+ iol_mode_enable(padapter, 1);
+ rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
+ rst = iol_execute(padapter, CMD_INIT_LLT);
+ iol_mode_enable(padapter, 0);
+ return rst;
+}
+
+static void
+efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
+{
+ u8 *efuseTbl = NULL;
+ u8 rtemp8;
+ u16 eFuse_Addr = 0;
+ u8 offset, wren;
+ u16 i, j;
+ u16 **eFuseWord = NULL;
+ u16 efuse_utilized = 0;
+ u8 u1temp = 0;
+
+ efuseTbl = (u8 *)rtw_zmalloc(EFUSE_MAP_LEN_88E);
+ if (efuseTbl == NULL) {
+ DBG_88E("%s: alloc efuseTbl fail!\n", __func__);
+ goto exit;
+ }
+
+ eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
+ if (eFuseWord == NULL) {
+ DBG_88E("%s: alloc eFuseWord fail!\n", __func__);
+ goto exit;
+ }
+
+ /* 0. Refresh efuse init map as all oxFF. */
+ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++)
+ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
+ eFuseWord[i][j] = 0xFFFF;
+
+ /* */
+ /* 1. Read the first byte to check if efuse is empty!!! */
+ /* */
+ /* */
+ rtemp8 = *(phymap+eFuse_Addr);
+ if (rtemp8 != 0xFF) {
+ efuse_utilized++;
+ eFuse_Addr++;
+ } else {
+ DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, rtemp8);
+ goto exit;
+ }
+
+ /* */
+ /* 2. Read real efuse content. Filter PG header and every section data. */
+ /* */
+ while ((rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
+ /* Check PG header for section num. */
+ if ((rtemp8 & 0x1F) == 0x0F) { /* extended header */
+ u1temp = ((rtemp8 & 0xE0) >> 5);
+ rtemp8 = *(phymap+eFuse_Addr);
+ if ((rtemp8 & 0x0F) == 0x0F) {
+ eFuse_Addr++;
+ rtemp8 = *(phymap+eFuse_Addr);
+
+ if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E))
+ eFuse_Addr++;
+ continue;
+ } else {
+ offset = ((rtemp8 & 0xF0) >> 1) | u1temp;
+ wren = (rtemp8 & 0x0F);
+ eFuse_Addr++;
+ }
+ } else {
+ offset = ((rtemp8 >> 4) & 0x0f);
+ wren = (rtemp8 & 0x0f);
+ }
+
+ if (offset < EFUSE_MAX_SECTION_88E) {
+ /* Get word enable value from PG header */
+ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+ /* Check word enable condition in the section */
+ if (!(wren & 0x01)) {
+ rtemp8 = *(phymap+eFuse_Addr);
+ eFuse_Addr++;
+ efuse_utilized++;
+ eFuseWord[offset][i] = (rtemp8 & 0xff);
+ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
+ break;
+ rtemp8 = *(phymap+eFuse_Addr);
+ eFuse_Addr++;
+ efuse_utilized++;
+ eFuseWord[offset][i] |= (((u16)rtemp8 << 8) & 0xff00);
+
+ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
+ break;
+ }
+ wren >>= 1;
+ }
+ }
+ /* Read next PG header */
+ rtemp8 = *(phymap+eFuse_Addr);
+
+ if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
+ efuse_utilized++;
+ eFuse_Addr++;
+ }
+ }
+
+ /* */
+ /* 3. Collect 16 sections and 4 word unit into Efuse map. */
+ /* */
+ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) {
+ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
+ efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff);
+ efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff);
+ }
+ }
+
+ /* */
+ /* 4. Copy from Efuse map to output pointer memory!!! */
+ /* */
+ for (i = 0; i < _size_byte; i++)
+ pbuf[i] = efuseTbl[_offset+i];
+
+ /* */
+ /* 5. Calculate Efuse utilization. */
+ /* */
+
+exit:
+ kfree(efuseTbl);
+
+ if (eFuseWord)
+ rtw_mfree2d((void *)eFuseWord, EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
+}
+
+static void efuse_read_phymap_from_txpktbuf(
+ struct adapter *adapter,
+ int bcnhead, /* beacon head, where FW store len(2-byte) and efuse physical map. */
+ u8 *content, /* buffer to store efuse physical map */
+ u16 *size /* for efuse content: the max byte to read. will update to byte read */
+ )
+{
+ u16 dbg_addr = 0;
+ u32 start = 0, passing_time = 0;
+ u8 reg_0x143 = 0;
+ u32 lo32 = 0, hi32 = 0;
+ u16 len = 0, count = 0;
+ int i = 0;
+ u16 limit = *size;
+
+ u8 *pos = content;
+
+ if (bcnhead < 0) /* if not valid */
+ bcnhead = rtw_read8(adapter, REG_TDECTRL+1);
+
+ DBG_88E("%s bcnhead:%d\n", __func__, bcnhead);
+
+ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
+
+ dbg_addr = bcnhead*128/8; /* 8-bytes addressing */
+
+ while (1) {
+ rtw_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr+i);
+
+ rtw_write8(adapter, REG_TXPKTBUF_DBG, 0);
+ start = rtw_get_current_time();
+ while (!(reg_0x143 = rtw_read8(adapter, REG_TXPKTBUF_DBG)) &&
+ (passing_time = rtw_get_passing_time_ms(start)) < 1000) {
+ DBG_88E("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __func__, reg_0x143, rtw_read8(adapter, 0x106));
+ rtw_usleep_os(100);
+ }
+
+ lo32 = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L);
+ hi32 = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H);
+
+ if (i == 0) {
+ u8 lenc[2];
+ u16 lenbak, aaabak;
+ u16 aaa;
+ lenc[0] = rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L);
+ lenc[1] = rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L+1);
+
+ aaabak = le16_to_cpup((__le16 *)lenc);
+ lenbak = le16_to_cpu(*((__le16 *)lenc));
+ aaa = le16_to_cpup((__le16 *)&lo32);
+ len = le16_to_cpu(*((__le16 *)&lo32));
+
+ limit = (len-2 < limit) ? len-2 : limit;
+
+ DBG_88E("%s len:%u, lenbak:%u, aaa:%u, aaabak:%u\n", __func__, len, lenbak, aaa, aaabak);
+
+ memcpy(pos, ((u8 *)&lo32)+2, (limit >= count+2) ? 2 : limit-count);
+ count += (limit >= count+2) ? 2 : limit-count;
+ pos = content+count;
+
+ } else {
+ memcpy(pos, ((u8 *)&lo32), (limit >= count+4) ? 4 : limit-count);
+ count += (limit >= count+4) ? 4 : limit-count;
+ pos = content+count;
+ }
+
+ if (limit > count && len-2 > count) {
+ memcpy(pos, (u8 *)&hi32, (limit >= count+4) ? 4 : limit-count);
+ count += (limit >= count+4) ? 4 : limit-count;
+ pos = content+count;
+ }
+
+ if (limit <= count || len-2 <= count)
+ break;
+ i++;
+ }
+ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS);
+ DBG_88E("%s read count:%u\n", __func__, count);
+ *size = count;
+}
+
+static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset, u16 size_byte, u8 *logical_map)
+{
+ s32 status = _FAIL;
+ u8 physical_map[512];
+ u16 size = 512;
+
+ rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
+ _rtw_memset(physical_map, 0xFF, 512);
+ rtw_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
+ status = iol_execute(padapter, CMD_READ_EFUSE_MAP);
+ if (status == _SUCCESS)
+ efuse_read_phymap_from_txpktbuf(padapter, txpktbuf_bndy, physical_map, &size);
+ efuse_phymap_to_logical(physical_map, offset, size_byte, logical_map);
+ return status;
+}
+
+s32 rtl8188e_iol_efuse_patch(struct adapter *padapter)
+{
+ s32 result = _SUCCESS;
+
+ DBG_88E("==> %s\n", __func__);
+ if (rtw_IOL_applied(padapter)) {
+ iol_mode_enable(padapter, 1);
+ result = iol_execute(padapter, CMD_READ_EFUSE_MAP);
+ if (result == _SUCCESS)
+ result = iol_execute(padapter, CMD_EFUSE_PATCH);
+
+ iol_mode_enable(padapter, 0);
+ }
+ return result;
+}
+
+static s32 iol_ioconfig(struct adapter *padapter, u8 iocfg_bndy)
+{
+ s32 rst = _SUCCESS;
+
+ rtw_write8(padapter, REG_TDECTRL+1, iocfg_bndy);
+ rst = iol_execute(padapter, CMD_IOCONFIG);
+ return rst;
+}
+
+static int rtl8188e_IOL_exec_cmds_sync(struct adapter *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt)
+{
+ struct pkt_attrib *pattrib = &xmit_frame->attrib;
+ u8 i;
+ int ret = _FAIL;
+
+ if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS)
+ goto exit;
+ if (rtw_usb_bulk_size_boundary(adapter, TXDESC_SIZE+pattrib->last_txcmdsz)) {
+ if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS)
+ goto exit;
+ }
+
+ dump_mgntframe_and_wait(adapter, xmit_frame, max_wating_ms);
+
+ iol_mode_enable(adapter, 1);
+ for (i = 0; i < bndy_cnt; i++) {
+ u8 page_no = 0;
+ page_no = i*2;
+ ret = iol_ioconfig(adapter, page_no);
+ if (ret != _SUCCESS)
+ break;
+ }
+ iol_mode_enable(adapter, 0);
+exit:
+ /* restore BCN_HEAD */
+ rtw_write8(adapter, REG_TDECTRL+1, 0);
+ return ret;
+}
+
+void rtw_IOL_cmd_tx_pkt_buf_dump(struct adapter *Adapter, int data_len)
+{
+ u32 fifo_data, reg_140;
+ u32 addr, rstatus, loop = 0;
+ u16 data_cnts = (data_len/8)+1;
+ u8 *pbuf = rtw_zvmalloc(data_len+10);
+ DBG_88E("###### %s ######\n", __func__);
+
+ rtw_write8(Adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
+ if (pbuf) {
+ for (addr = 0; addr < data_cnts; addr++) {
+ rtw_write32(Adapter, 0x140, addr);
+ rtw_usleep_os(2);
+ loop = 0;
+ do {
+ rstatus = (reg_140 = rtw_read32(Adapter, REG_PKTBUF_DBG_CTRL)&BIT24);
+ if (rstatus) {
+ fifo_data = rtw_read32(Adapter, REG_PKTBUF_DBG_DATA_L);
+ memcpy(pbuf+(addr*8), &fifo_data, 4);
+
+ fifo_data = rtw_read32(Adapter, REG_PKTBUF_DBG_DATA_H);
+ memcpy(pbuf+(addr*8+4), &fifo_data, 4);
+ }
+ rtw_usleep_os(2);
+ } while (!rstatus && (loop++ < 10));
+ }
+ rtw_IOL_cmd_buf_dump(Adapter, data_len, pbuf);
+ rtw_vmfree(pbuf, data_len+10);
+ }
+ DBG_88E("###### %s ######\n", __func__);
+}
+
+static void _FWDownloadEnable(struct adapter *padapter, bool enable)
+{
+ u8 tmp;
+
+ if (enable) {
+ /* MCU firmware download enable. */
+ tmp = rtw_read8(padapter, REG_MCUFWDL);
+ rtw_write8(padapter, REG_MCUFWDL, tmp | 0x01);
+
+ /* 8051 reset */
+ tmp = rtw_read8(padapter, REG_MCUFWDL+2);
+ rtw_write8(padapter, REG_MCUFWDL+2, tmp&0xf7);
+ } else {
+ /* MCU firmware download disable. */
+ tmp = rtw_read8(padapter, REG_MCUFWDL);
+ rtw_write8(padapter, REG_MCUFWDL, tmp&0xfe);
+
+ /* Reserved for fw extension. */
+ rtw_write8(padapter, REG_MCUFWDL+1, 0x00);
+ }
+}
+
+#define MAX_REG_BOLCK_SIZE 196
+
+static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize)
+{
+ int ret = _SUCCESS;
+ u32 blockSize_p1 = 4; /* (Default) Phase #1 : PCI muse use 4-byte write to download FW */
+ u32 blockSize_p2 = 8; /* Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */
+ u32 blockSize_p3 = 1; /* Phase #3 : Use 1-byte, the remnant of FW image. */
+ u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0;
+ u32 remainSize_p1 = 0, remainSize_p2 = 0;
+ u8 *bufferPtr = (u8 *)buffer;
+ u32 i = 0, offset = 0;
+
+ blockSize_p1 = MAX_REG_BOLCK_SIZE;
+
+ /* 3 Phase #1 */
+ blockCount_p1 = buffSize / blockSize_p1;
+ remainSize_p1 = buffSize % blockSize_p1;
+
+ if (blockCount_p1) {
+ RT_TRACE(_module_hal_init_c_, _drv_notice_,
+ ("_BlockWrite: [P1] buffSize(%d) blockSize_p1(%d) blockCount_p1(%d) remainSize_p1(%d)\n",
+ buffSize, blockSize_p1, blockCount_p1, remainSize_p1));
+ }
+
+ for (i = 0; i < blockCount_p1; i++) {
+ ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + i * blockSize_p1), blockSize_p1, (bufferPtr + i * blockSize_p1));
+ if (ret == _FAIL)
+ goto exit;
+ }
+
+ /* 3 Phase #2 */
+ if (remainSize_p1) {
+ offset = blockCount_p1 * blockSize_p1;
+
+ blockCount_p2 = remainSize_p1/blockSize_p2;
+ remainSize_p2 = remainSize_p1%blockSize_p2;
+
+ if (blockCount_p2) {
+ RT_TRACE(_module_hal_init_c_, _drv_notice_,
+ ("_BlockWrite: [P2] buffSize_p2(%d) blockSize_p2(%d) blockCount_p2(%d) remainSize_p2(%d)\n",
+ (buffSize-offset), blockSize_p2 , blockCount_p2, remainSize_p2));
+ }
+
+ for (i = 0; i < blockCount_p2; i++) {
+ ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + offset + i*blockSize_p2), blockSize_p2, (bufferPtr + offset + i*blockSize_p2));
+
+ if (ret == _FAIL)
+ goto exit;
+ }
+ }
+
+ /* 3 Phase #3 */
+ if (remainSize_p2) {
+ offset = (blockCount_p1 * blockSize_p1) + (blockCount_p2 * blockSize_p2);
+
+ blockCount_p3 = remainSize_p2 / blockSize_p3;
+
+ RT_TRACE(_module_hal_init_c_, _drv_notice_,
+ ("_BlockWrite: [P3] buffSize_p3(%d) blockSize_p3(%d) blockCount_p3(%d)\n",
+ (buffSize-offset), blockSize_p3, blockCount_p3));
+
+ for (i = 0; i < blockCount_p3; i++) {
+ ret = rtw_write8(padapter, (FW_8188E_START_ADDRESS + offset + i), *(bufferPtr + offset + i));
+
+ if (ret == _FAIL)
+ goto exit;
+ }
+ }
+
+exit:
+ return ret;
+}
+
+static int _PageWrite(struct adapter *padapter, u32 page, void *buffer, u32 size)
+{
+ u8 value8;
+ u8 u8Page = (u8)(page & 0x07);
+
+ value8 = (rtw_read8(padapter, REG_MCUFWDL+2) & 0xF8) | u8Page;
+ rtw_write8(padapter, REG_MCUFWDL+2, value8);
+
+ return _BlockWrite(padapter, buffer, size);
+}
+
+static int _WriteFW(struct adapter *padapter, void *buffer, u32 size)
+{
+ /* Since we need dynamic decide method of dwonload fw, so we call this function to get chip version. */
+ /* We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */
+ int ret = _SUCCESS;
+ u32 pageNums, remainSize;
+ u32 page, offset;
+ u8 *bufferPtr = (u8 *)buffer;
+
+ pageNums = size / MAX_PAGE_SIZE;
+ remainSize = size % MAX_PAGE_SIZE;
+
+ for (page = 0; page < pageNums; page++) {
+ offset = page * MAX_PAGE_SIZE;
+ ret = _PageWrite(padapter, page, bufferPtr+offset, MAX_PAGE_SIZE);
+
+ if (ret == _FAIL)
+ goto exit;
+ }
+ if (remainSize) {
+ offset = pageNums * MAX_PAGE_SIZE;
+ page = pageNums;
+ ret = _PageWrite(padapter, page, bufferPtr+offset, remainSize);
+
+ if (ret == _FAIL)
+ goto exit;
+ }
+ RT_TRACE(_module_hal_init_c_, _drv_info_, ("_WriteFW Done- for Normal chip.\n"));
+exit:
+ return ret;
+}
+
+void _8051Reset88E(struct adapter *padapter)
+{
+ u8 u1bTmp;
+
+ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1);
+ rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp&(~BIT2));
+ rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp|(BIT2));
+ DBG_88E("=====> _8051Reset88E(): 8051 reset success .\n");
+}
+
+static s32 _FWFreeToGo(struct adapter *padapter)
+{
+ u32 counter = 0;
+ u32 value32;
+
+ /* polling CheckSum report */
+ do {
+ value32 = rtw_read32(padapter, REG_MCUFWDL);
+ if (value32 & FWDL_ChkSum_rpt)
+ break;
+ } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
+
+ if (counter >= POLLING_READY_TIMEOUT_COUNT) {
+ DBG_88E("%s: chksum report fail! REG_MCUFWDL:0x%08x\n", __func__, value32);
+ return _FAIL;
+ }
+ DBG_88E("%s: Checksum report OK! REG_MCUFWDL:0x%08x\n", __func__, value32);
+
+ value32 = rtw_read32(padapter, REG_MCUFWDL);
+ value32 |= MCUFWDL_RDY;
+ value32 &= ~WINTINI_RDY;
+ rtw_write32(padapter, REG_MCUFWDL, value32);
+
+ _8051Reset88E(padapter);
+
+ /* polling for FW ready */
+ counter = 0;
+ do {
+ value32 = rtw_read32(padapter, REG_MCUFWDL);
+ if (value32 & WINTINI_RDY) {
+ DBG_88E("%s: Polling FW ready success!! REG_MCUFWDL:0x%08x\n", __func__, value32);
+ return _SUCCESS;
+ }
+ rtw_udelay_os(5);
+ } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
+
+ DBG_88E("%s: Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", __func__, value32);
+ return _FAIL;
+}
+
+#define IS_FW_81xxC(padapter) (((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0)
+
+s32 rtl8188e_FirmwareDownload(struct adapter *padapter)
+{
+ s32 rtStatus = _SUCCESS;
+ u8 writeFW_retry = 0;
+ u32 fwdl_start_time;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+
+ u8 *FwImage;
+ u32 FwImageLen;
+ struct rt_firmware *pFirmware = NULL;
+ struct rt_firmware_hdr *pFwHdr = NULL;
+ u8 *pFirmwareBuf;
+ u32 FirmwareLen;
+
+ RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__));
+ pFirmware = (struct rt_firmware *)rtw_zmalloc(sizeof(struct rt_firmware));
+ if (!pFirmware) {
+ rtStatus = _FAIL;
+ goto Exit;
+ }
+
+ FwImage = (u8 *)Rtl8188E_FwImageArray;
+ FwImageLen = Rtl8188E_FWImgArrayLength;
+
+ pFirmware->eFWSource = FW_SOURCE_HEADER_FILE;
+
+ switch (pFirmware->eFWSource) {
+ case FW_SOURCE_IMG_FILE:
+ break;
+ case FW_SOURCE_HEADER_FILE:
+ if (FwImageLen > FW_8188E_SIZE) {
+ rtStatus = _FAIL;
+ RT_TRACE(_module_hal_init_c_, _drv_err_, ("Firmware size exceed 0x%X. Check it.\n", FW_8188E_SIZE));
+ goto Exit;
+ }
+
+ pFirmware->szFwBuffer = FwImage;
+ pFirmware->ulFwLength = FwImageLen;
+ break;
+ }
+ pFirmwareBuf = pFirmware->szFwBuffer;
+ FirmwareLen = pFirmware->ulFwLength;
+ DBG_88E_LEVEL(_drv_info_, "+%s: !bUsedWoWLANFw, FmrmwareLen:%d+\n", __func__, FirmwareLen);
+
+ /* To Check Fw header. Added by tynli. 2009.12.04. */
+ pFwHdr = (struct rt_firmware_hdr *)pFirmware->szFwBuffer;
+
+ pHalData->FirmwareVersion = le16_to_cpu(pFwHdr->Version);
+ pHalData->FirmwareSubVersion = pFwHdr->Subversion;
+ pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->Signature);
+
+ DBG_88E("%s: fw_ver =%d fw_subver =%d sig = 0x%x\n",
+ __func__, pHalData->FirmwareVersion, pHalData->FirmwareSubVersion, pHalData->FirmwareSignature);
+
+ if (IS_FW_HEADER_EXIST(pFwHdr)) {
+ /* Shift 32 bytes for FW header */
+ pFirmwareBuf = pFirmwareBuf + 32;
+ FirmwareLen = FirmwareLen - 32;
+ }
+
+ /* Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, */
+ /* or it will cause download Fw fail. 2010.02.01. by tynli. */
+ if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) { /* 8051 RAM code */
+ rtw_write8(padapter, REG_MCUFWDL, 0x00);
+ _8051Reset88E(padapter);
+ }
+
+ _FWDownloadEnable(padapter, true);
+ fwdl_start_time = rtw_get_current_time();
+ while (1) {
+ /* reset the FWDL chksum */
+ rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL) | FWDL_ChkSum_rpt);
+
+ rtStatus = _WriteFW(padapter, pFirmwareBuf, FirmwareLen);
+
+ if (rtStatus == _SUCCESS ||
+ (rtw_get_passing_time_ms(fwdl_start_time) > 500 && writeFW_retry++ >= 3))
+ break;
+
+ DBG_88E("%s writeFW_retry:%u, time after fwdl_start_time:%ums\n",
+ __func__, writeFW_retry, rtw_get_passing_time_ms(fwdl_start_time)
+ );
+ }
+ _FWDownloadEnable(padapter, false);
+ if (_SUCCESS != rtStatus) {
+ DBG_88E("DL Firmware failed!\n");
+ goto Exit;
+ }
+
+ rtStatus = _FWFreeToGo(padapter);
+ if (_SUCCESS != rtStatus) {
+ DBG_88E("DL Firmware failed!\n");
+ goto Exit;
+ }
+ RT_TRACE(_module_hal_init_c_, _drv_info_, ("Firmware is ready to run!\n"));
+
+Exit:
+
+ kfree(pFirmware);
+ return rtStatus;
+}
+
+void rtl8188e_InitializeFirmwareVars(struct adapter *padapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+
+ /* Init Fw LPS related. */
+ padapter->pwrctrlpriv.bFwCurrentInPSMode = false;
+
+ /* Init H2C counter. by tynli. 2009.12.09. */
+ pHalData->LastHMEBoxNum = 0;
+}
+
+static void rtl8188e_free_hal_data(struct adapter *padapter)
+{
+_func_enter_;
+ kfree(padapter->HalData);
+ padapter->HalData = NULL;
+_func_exit_;
+}
+
+/* */
+/* Efuse related code */
+/* */
+enum{
+ VOLTAGE_V25 = 0x03,
+ LDOE25_SHIFT = 28 ,
+ };
+
+static bool
+hal_EfusePgPacketWrite2ByteHeader(
+ struct adapter *pAdapter,
+ u8 efuseType,
+ u16 *pAddr,
+ struct pgpkt *pTargetPkt,
+ bool bPseudoTest);
+static bool
+hal_EfusePgPacketWrite1ByteHeader(
+ struct adapter *pAdapter,
+ u8 efuseType,
+ u16 *pAddr,
+ struct pgpkt *pTargetPkt,
+ bool bPseudoTest);
+static bool
+hal_EfusePgPacketWriteData(
+ struct adapter *pAdapter,
+ u8 efuseType,
+ u16 *pAddr,
+ struct pgpkt *pTargetPkt,
+ bool bPseudoTest);
+
+static void
+hal_EfusePowerSwitch_RTL8188E(
+ struct adapter *pAdapter,
+ u8 bWrite,
+ u8 PwrState)
+{
+ u8 tempval;
+ u16 tmpV16;
+
+ if (PwrState) {
+ rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON);
+
+ /* 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid */
+ tmpV16 = rtw_read16(pAdapter, REG_SYS_ISO_CTRL);
+ if (!(tmpV16 & PWC_EV12V)) {
+ tmpV16 |= PWC_EV12V;
+ rtw_write16(pAdapter, REG_SYS_ISO_CTRL, tmpV16);
+ }
+ /* Reset: 0x0000h[28], default valid */
+ tmpV16 = rtw_read16(pAdapter, REG_SYS_FUNC_EN);
+ if (!(tmpV16 & FEN_ELDR)) {
+ tmpV16 |= FEN_ELDR;
+ rtw_write16(pAdapter, REG_SYS_FUNC_EN, tmpV16);
+ }
+
+ /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */
+ tmpV16 = rtw_read16(pAdapter, REG_SYS_CLKR);
+ if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) {
+ tmpV16 |= (LOADER_CLK_EN | ANA8M);
+ rtw_write16(pAdapter, REG_SYS_CLKR, tmpV16);
+ }
+
+ if (bWrite) {
+ /* Enable LDO 2.5V before read/write action */
+ tempval = rtw_read8(pAdapter, EFUSE_TEST+3);
+ tempval &= 0x0F;
+ tempval |= (VOLTAGE_V25 << 4);
+ rtw_write8(pAdapter, EFUSE_TEST+3, (tempval | 0x80));
+ }
+ } else {
+ rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF);
+
+ if (bWrite) {
+ /* Disable LDO 2.5V after read/write action */
+ tempval = rtw_read8(pAdapter, EFUSE_TEST+3);
+ rtw_write8(pAdapter, EFUSE_TEST+3, (tempval & 0x7F));
+ }
+ }
+}
+
+static void
+rtl8188e_EfusePowerSwitch(
+ struct adapter *pAdapter,
+ u8 bWrite,
+ u8 PwrState)
+{
+ hal_EfusePowerSwitch_RTL8188E(pAdapter, bWrite, PwrState);
+}
+
+
+static void Hal_EfuseReadEFuse88E(struct adapter *Adapter,
+ u16 _offset,
+ u16 _size_byte,
+ u8 *pbuf,
+ bool bPseudoTest
+ )
+{
+ u8 *efuseTbl = NULL;
+ u8 rtemp8[1];
+ u16 eFuse_Addr = 0;
+ u8 offset, wren;
+ u16 i, j;
+ u16 **eFuseWord = NULL;
+ u16 efuse_utilized = 0;
+ u8 u1temp = 0;
+
+ /* */
+ /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */
+ /* */
+ if ((_offset + _size_byte) > EFUSE_MAP_LEN_88E) {/* total E-Fuse table is 512bytes */
+ DBG_88E("Hal_EfuseReadEFuse88E(): Invalid offset(%#x) with read bytes(%#x)!!\n", _offset, _size_byte);
+ goto exit;
+ }
+
+ efuseTbl = (u8 *)rtw_zmalloc(EFUSE_MAP_LEN_88E);
+ if (efuseTbl == NULL) {
+ DBG_88E("%s: alloc efuseTbl fail!\n", __func__);
+ goto exit;
+ }
+
+ eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
+ if (eFuseWord == NULL) {
+ DBG_88E("%s: alloc eFuseWord fail!\n", __func__);
+ goto exit;
+ }
+
+ /* 0. Refresh efuse init map as all oxFF. */
+ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++)
+ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
+ eFuseWord[i][j] = 0xFFFF;
+
+ /* */
+ /* 1. Read the first byte to check if efuse is empty!!! */
+ /* */
+ /* */
+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+ if (*rtemp8 != 0xFF) {
+ efuse_utilized++;
+ eFuse_Addr++;
+ } else {
+ DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, *rtemp8);
+ goto exit;
+ }
+
+ /* */
+ /* 2. Read real efuse content. Filter PG header and every section data. */
+ /* */
+ while ((*rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
+ /* Check PG header for section num. */
+ if ((*rtemp8 & 0x1F) == 0x0F) { /* extended header */
+ u1temp = ((*rtemp8 & 0xE0) >> 5);
+
+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+
+ if ((*rtemp8 & 0x0F) == 0x0F) {
+ eFuse_Addr++;
+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+
+ if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E))
+ eFuse_Addr++;
+ continue;
+ } else {
+ offset = ((*rtemp8 & 0xF0) >> 1) | u1temp;
+ wren = (*rtemp8 & 0x0F);
+ eFuse_Addr++;
+ }
+ } else {
+ offset = ((*rtemp8 >> 4) & 0x0f);
+ wren = (*rtemp8 & 0x0f);
+ }
+
+ if (offset < EFUSE_MAX_SECTION_88E) {
+ /* Get word enable value from PG header */
+
+ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+ /* Check word enable condition in the section */
+ if (!(wren & 0x01)) {
+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+ eFuse_Addr++;
+ efuse_utilized++;
+ eFuseWord[offset][i] = (*rtemp8 & 0xff);
+ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
+ break;
+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+ eFuse_Addr++;
+ efuse_utilized++;
+ eFuseWord[offset][i] |= (((u16)*rtemp8 << 8) & 0xff00);
+ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
+ break;
+ }
+ wren >>= 1;
+ }
+ }
+
+ /* Read next PG header */
+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+
+ if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
+ efuse_utilized++;
+ eFuse_Addr++;
+ }
+ }
+
+ /* 3. Collect 16 sections and 4 word unit into Efuse map. */
+ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) {
+ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
+ efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff);
+ efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff);
+ }
+ }
+
+ /* 4. Copy from Efuse map to output pointer memory!!! */
+ for (i = 0; i < _size_byte; i++)
+ pbuf[i] = efuseTbl[_offset+i];
+
+ /* 5. Calculate Efuse utilization. */
+ rtw_hal_set_hwreg(Adapter, HW_VAR_EFUSE_BYTES, (u8 *)&eFuse_Addr);
+
+exit:
+ kfree(efuseTbl);
+
+ if (eFuseWord)
+ rtw_mfree2d((void *)eFuseWord, EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
+}
+
+static void ReadEFuseByIC(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest)
+{
+ if (!bPseudoTest) {
+ int ret = _FAIL;
+ if (rtw_IOL_applied(Adapter)) {
+ rtw_hal_power_on(Adapter);
+
+ iol_mode_enable(Adapter, 1);
+ ret = iol_read_efuse(Adapter, 0, _offset, _size_byte, pbuf);
+ iol_mode_enable(Adapter, 0);
+
+ if (_SUCCESS == ret)
+ goto exit;
+ }
+ }
+ Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest);
+
+exit:
+ return;
+}
+
+static void ReadEFuse_Pseudo(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest)
+{
+ Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest);
+}
+
+static void rtl8188e_ReadEFuse(struct adapter *Adapter, u8 efuseType,
+ u16 _offset, u16 _size_byte, u8 *pbuf,
+ bool bPseudoTest)
+{
+ if (bPseudoTest)
+ ReadEFuse_Pseudo (Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest);
+ else
+ ReadEFuseByIC(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest);
+}
+
+/* Do not support BT */
+static void Hal_EFUSEGetEfuseDefinition88E(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut)
+{
+ switch (type) {
+ case TYPE_EFUSE_MAX_SECTION:
+ {
+ u8 *pMax_section;
+ pMax_section = (u8 *)pOut;
+ *pMax_section = EFUSE_MAX_SECTION_88E;
+ }
+ break;
+ case TYPE_EFUSE_REAL_CONTENT_LEN:
+ {
+ u16 *pu2Tmp;
+ pu2Tmp = (u16 *)pOut;
+ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
+ }
+ break;
+ case TYPE_EFUSE_CONTENT_LEN_BANK:
+ {
+ u16 *pu2Tmp;
+ pu2Tmp = (u16 *)pOut;
+ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
+ }
+ break;
+ case TYPE_AVAILABLE_EFUSE_BYTES_BANK:
+ {
+ u16 *pu2Tmp;
+ pu2Tmp = (u16 *)pOut;
+ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
+ }
+ break;
+ case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL:
+ {
+ u16 *pu2Tmp;
+ pu2Tmp = (u16 *)pOut;
+ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
+ }
+ break;
+ case TYPE_EFUSE_MAP_LEN:
+ {
+ u16 *pu2Tmp;
+ pu2Tmp = (u16 *)pOut;
+ *pu2Tmp = (u16)EFUSE_MAP_LEN_88E;
+ }
+ break;
+ case TYPE_EFUSE_PROTECT_BYTES_BANK:
+ {
+ u8 *pu1Tmp;
+ pu1Tmp = (u8 *)pOut;
+ *pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E);
+ }
+ break;
+ default:
+ {
+ u8 *pu1Tmp;
+ pu1Tmp = (u8 *)pOut;
+ *pu1Tmp = 0;
+ }
+ break;
+ }
+}
+
+static void Hal_EFUSEGetEfuseDefinition_Pseudo88E(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut)
+{
+ switch (type) {
+ case TYPE_EFUSE_MAX_SECTION:
+ {
+ u8 *pMax_section;
+ pMax_section = (u8 *)pOut;
+ *pMax_section = EFUSE_MAX_SECTION_88E;
+ }
+ break;
+ case TYPE_EFUSE_REAL_CONTENT_LEN:
+ {
+ u16 *pu2Tmp;
+ pu2Tmp = (u16 *)pOut;
+ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
+ }
+ break;
+ case TYPE_EFUSE_CONTENT_LEN_BANK:
+ {
+ u16 *pu2Tmp;
+ pu2Tmp = (u16 *)pOut;
+ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
+ }
+ break;
+ case TYPE_AVAILABLE_EFUSE_BYTES_BANK:
+ {
+ u16 *pu2Tmp;
+ pu2Tmp = (u16 *)pOut;
+ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
+ }
+ break;
+ case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL:
+ {
+ u16 *pu2Tmp;
+ pu2Tmp = (u16 *)pOut;
+ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
+ }
+ break;
+ case TYPE_EFUSE_MAP_LEN:
+ {
+ u16 *pu2Tmp;
+ pu2Tmp = (u16 *)pOut;
+ *pu2Tmp = (u16)EFUSE_MAP_LEN_88E;
+ }
+ break;
+ case TYPE_EFUSE_PROTECT_BYTES_BANK:
+ {
+ u8 *pu1Tmp;
+ pu1Tmp = (u8 *)pOut;
+ *pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E);
+ }
+ break;
+ default:
+ {
+ u8 *pu1Tmp;
+ pu1Tmp = (u8 *)pOut;
+ *pu1Tmp = 0;
+ }
+ break;
+ }
+}
+
+static void rtl8188e_EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest)
+{
+ if (bPseudoTest)
+ Hal_EFUSEGetEfuseDefinition_Pseudo88E(pAdapter, efuseType, type, pOut);
+ else
+ Hal_EFUSEGetEfuseDefinition88E(pAdapter, efuseType, type, pOut);
+}
+
+static u8 Hal_EfuseWordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest)
+{
+ u16 tmpaddr = 0;
+ u16 start_addr = efuse_addr;
+ u8 badworden = 0x0F;
+ u8 tmpdata[8];
+
+ _rtw_memset((void *)tmpdata, 0xff, PGPKT_DATA_SIZE);
+
+ if (!(word_en&BIT0)) {
+ tmpaddr = start_addr;
+ efuse_OneByteWrite(pAdapter, start_addr++, data[0], bPseudoTest);
+ efuse_OneByteWrite(pAdapter, start_addr++, data[1], bPseudoTest);
+
+ efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[0], bPseudoTest);
+ efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[1], bPseudoTest);
+ if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1]))
+ badworden &= (~BIT0);
+ }
+ if (!(word_en&BIT1)) {
+ tmpaddr = start_addr;
+ efuse_OneByteWrite(pAdapter, start_addr++, data[2], bPseudoTest);
+ efuse_OneByteWrite(pAdapter, start_addr++, data[3], bPseudoTest);
+
+ efuse_OneByteRead(pAdapter, tmpaddr , &tmpdata[2], bPseudoTest);
+ efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[3], bPseudoTest);
+ if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3]))
+ badworden &= (~BIT1);
+ }
+ if (!(word_en&BIT2)) {
+ tmpaddr = start_addr;
+ efuse_OneByteWrite(pAdapter, start_addr++, data[4], bPseudoTest);
+ efuse_OneByteWrite(pAdapter, start_addr++, data[5], bPseudoTest);
+
+ efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[4], bPseudoTest);
+ efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[5], bPseudoTest);
+ if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5]))
+ badworden &= (~BIT2);
+ }
+ if (!(word_en&BIT3)) {
+ tmpaddr = start_addr;
+ efuse_OneByteWrite(pAdapter, start_addr++, data[6], bPseudoTest);
+ efuse_OneByteWrite(pAdapter, start_addr++, data[7], bPseudoTest);
+
+ efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[6], bPseudoTest);
+ efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[7], bPseudoTest);
+ if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7]))
+ badworden &= (~BIT3);
+ }
+ return badworden;
+}
+
+static u8 Hal_EfuseWordEnableDataWrite_Pseudo(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest)
+{
+ u8 ret;
+
+ ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest);
+ return ret;
+}
+
+static u8 rtl8188e_Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest)
+{
+ u8 ret = 0;
+
+ if (bPseudoTest)
+ ret = Hal_EfuseWordEnableDataWrite_Pseudo (pAdapter, efuse_addr, word_en, data, bPseudoTest);
+ else
+ ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest);
+ return ret;
+}
+
+static u16 hal_EfuseGetCurrentSize_8188e(struct adapter *pAdapter, bool bPseudoTest)
+{
+ int bContinual = true;
+ u16 efuse_addr = 0;
+ u8 hoffset = 0, hworden = 0;
+ u8 efuse_data, word_cnts = 0;
+
+ if (bPseudoTest)
+ efuse_addr = (u16)(fakeEfuseUsedBytes);
+ else
+ rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr);
+
+ while (bContinual &&
+ efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest) &&
+ AVAILABLE_EFUSE_ADDR(efuse_addr)) {
+ if (efuse_data != 0xFF) {
+ if ((efuse_data&0x1F) == 0x0F) { /* extended header */
+ hoffset = efuse_data;
+ efuse_addr++;
+ efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest);
+ if ((efuse_data & 0x0F) == 0x0F) {
+ efuse_addr++;
+ continue;
+ } else {
+ hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
+ hworden = efuse_data & 0x0F;
+ }
+ } else {
+ hoffset = (efuse_data>>4) & 0x0F;
+ hworden = efuse_data & 0x0F;
+ }
+ word_cnts = Efuse_CalculateWordCnts(hworden);
+ /* read next header */
+ efuse_addr = efuse_addr + (word_cnts*2)+1;
+ } else {
+ bContinual = false;
+ }
+ }
+
+ if (bPseudoTest)
+ fakeEfuseUsedBytes = efuse_addr;
+ else
+ rtw_hal_set_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr);
+
+ return efuse_addr;
+}
+
+static u16 Hal_EfuseGetCurrentSize_Pseudo(struct adapter *pAdapter, bool bPseudoTest)
+{
+ u16 ret = 0;
+
+ ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest);
+ return ret;
+}
+
+static u16 rtl8188e_EfuseGetCurrentSize(struct adapter *pAdapter, u8 efuseType, bool bPseudoTest)
+{
+ u16 ret = 0;
+
+ if (bPseudoTest)
+ ret = Hal_EfuseGetCurrentSize_Pseudo(pAdapter, bPseudoTest);
+ else
+ ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest);
+ return ret;
+}
+
+static int hal_EfusePgPacketRead_8188e(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
+{
+ u8 ReadState = PG_STATE_HEADER;
+ int bContinual = true;
+ int bDataEmpty = true;
+ u8 efuse_data, word_cnts = 0;
+ u16 efuse_addr = 0;
+ u8 hoffset = 0, hworden = 0;
+ u8 tmpidx = 0;
+ u8 tmpdata[8];
+ u8 max_section = 0;
+ u8 tmp_header = 0;
+
+ EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, (void *)&max_section, bPseudoTest);
+
+ if (data == NULL)
+ return false;
+ if (offset > max_section)
+ return false;
+
+ _rtw_memset((void *)data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE);
+ _rtw_memset((void *)tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE);
+
+ /* <Roger_TODO> Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */
+ /* Skip dummy parts to prevent unexpected data read from Efuse. */
+ /* By pass right now. 2009.02.19. */
+ while (bContinual && AVAILABLE_EFUSE_ADDR(efuse_addr)) {
+ /* Header Read ------------- */
+ if (ReadState & PG_STATE_HEADER) {
+ if (efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) {
+ if (EXT_HEADER(efuse_data)) {
+ tmp_header = efuse_data;
+ efuse_addr++;
+ efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest);
+ if (!ALL_WORDS_DISABLED(efuse_data)) {
+ hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
+ hworden = efuse_data & 0x0F;
+ } else {
+ DBG_88E("Error, All words disabled\n");
+ efuse_addr++;
+ continue;
+ }
+ } else {
+ hoffset = (efuse_data>>4) & 0x0F;
+ hworden = efuse_data & 0x0F;
+ }
+ word_cnts = Efuse_CalculateWordCnts(hworden);
+ bDataEmpty = true;
+
+ if (hoffset == offset) {
+ for (tmpidx = 0; tmpidx < word_cnts*2; tmpidx++) {
+ if (efuse_OneByteRead(pAdapter, efuse_addr+1+tmpidx, &efuse_data, bPseudoTest)) {
+ tmpdata[tmpidx] = efuse_data;
+ if (efuse_data != 0xff)
+ bDataEmpty = false;
+ }
+ }
+ if (bDataEmpty == false) {
+ ReadState = PG_STATE_DATA;
+ } else {/* read next header */
+ efuse_addr = efuse_addr + (word_cnts*2)+1;
+ ReadState = PG_STATE_HEADER;
+ }
+ } else {/* read next header */
+ efuse_addr = efuse_addr + (word_cnts*2)+1;
+ ReadState = PG_STATE_HEADER;
+ }
+ } else {
+ bContinual = false;
+ }
+ } else if (ReadState & PG_STATE_DATA) {
+ /* Data section Read ------------- */
+ efuse_WordEnableDataRead(hworden, tmpdata, data);
+ efuse_addr = efuse_addr + (word_cnts*2)+1;
+ ReadState = PG_STATE_HEADER;
+ }
+
+ }
+
+ if ((data[0] == 0xff) && (data[1] == 0xff) && (data[2] == 0xff) && (data[3] == 0xff) &&
+ (data[4] == 0xff) && (data[5] == 0xff) && (data[6] == 0xff) && (data[7] == 0xff))
+ return false;
+ else
+ return true;
+}
+
+static int Hal_EfusePgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
+{
+ int ret;
+
+ ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest);
+ return ret;
+}
+
+static int Hal_EfusePgPacketRead_Pseudo(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
+{
+ int ret;
+
+ ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest);
+ return ret;
+}
+
+static int rtl8188e_Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
+{
+ int ret;
+
+ if (bPseudoTest)
+ ret = Hal_EfusePgPacketRead_Pseudo (pAdapter, offset, data, bPseudoTest);
+ else
+ ret = Hal_EfusePgPacketRead(pAdapter, offset, data, bPseudoTest);
+ return ret;
+}
+
+static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, struct pgpkt *pFixPkt, u16 *pAddr, bool bPseudoTest)
+{
+ u8 originaldata[8], badworden = 0;
+ u16 efuse_addr = *pAddr;
+ u32 PgWriteSuccess = 0;
+
+ _rtw_memset((void *)originaldata, 0xff, 8);
+
+ if (Efuse_PgPacketRead(pAdapter, pFixPkt->offset, originaldata, bPseudoTest)) {
+ /* check if data exist */
+ badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pFixPkt->word_en, originaldata, bPseudoTest);
+
+ if (badworden != 0xf) { /* write fail */
+ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pFixPkt->offset, badworden, originaldata, bPseudoTest);
+
+ if (!PgWriteSuccess)
+ return false;
+ else
+ efuse_addr = Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest);
+ } else {
+ efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1;
+ }
+ } else {
+ efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1;
+ }
+ *pAddr = efuse_addr;
+ return true;
+}
+
+static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
+{
+ bool bRet = false;
+ u16 efuse_addr = *pAddr, efuse_max_available_len = 0;
+ u8 pg_header = 0, tmp_header = 0, pg_header_temp = 0;
+ u8 repeatcnt = 0;
+
+ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len, bPseudoTest);
+
+ while (efuse_addr < efuse_max_available_len) {
+ pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F;
+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+
+ while (tmp_header == 0xFF) {
+ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
+ return false;
+
+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+ }
+
+ /* to write ext_header */
+ if (tmp_header == pg_header) {
+ efuse_addr++;
+ pg_header_temp = pg_header;
+ pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en;
+
+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+
+ while (tmp_header == 0xFF) {
+ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
+ return false;
+
+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+ }
+
+ if ((tmp_header & 0x0F) == 0x0F) { /* word_en PG fail */
+ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+ return false;
+ } else {
+ efuse_addr++;
+ continue;
+ }
+ } else if (pg_header != tmp_header) { /* offset PG fail */
+ struct pgpkt fixPkt;
+ fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1);
+ fixPkt.word_en = tmp_header & 0x0F;
+ fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
+ if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest))
+ return false;
+ } else {
+ bRet = true;
+ break;
+ }
+ } else if ((tmp_header & 0x1F) == 0x0F) { /* wrong extended header */
+ efuse_addr += 2;
+ continue;
+ }
+ }
+
+ *pAddr = efuse_addr;
+ return bRet;
+}
+
+static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
+{
+ bool bRet = false;
+ u8 pg_header = 0, tmp_header = 0;
+ u16 efuse_addr = *pAddr;
+ u8 repeatcnt = 0;
+
+ pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en;
+
+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+
+ while (tmp_header == 0xFF) {
+ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
+ return false;
+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+ }
+
+ if (pg_header == tmp_header) {
+ bRet = true;
+ } else {
+ struct pgpkt fixPkt;
+ fixPkt.offset = (tmp_header>>4) & 0x0F;
+ fixPkt.word_en = tmp_header & 0x0F;
+ fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
+ if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest))
+ return false;
+ }
+
+ *pAddr = efuse_addr;
+ return bRet;
+}
+
+static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
+{
+ bool bRet = false;
+ u16 efuse_addr = *pAddr;
+ u8 badworden = 0;
+ u32 PgWriteSuccess = 0;
+
+ badworden = 0x0f;
+ badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest);
+ if (badworden == 0x0F) {
+ /* write ok */
+ return true;
+ } else {
+ /* reorganize other pg packet */
+ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest);
+ if (!PgWriteSuccess)
+ return false;
+ else
+ return true;
+ }
+ return bRet;
+}
+
+static bool
+hal_EfusePgPacketWriteHeader(
+ struct adapter *pAdapter,
+ u8 efuseType,
+ u16 *pAddr,
+ struct pgpkt *pTargetPkt,
+ bool bPseudoTest)
+{
+ bool bRet = false;
+
+ if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE)
+ bRet = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest);
+ else
+ bRet = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest);
+
+ return bRet;
+}
+
+static bool wordEnMatched(struct pgpkt *pTargetPkt, struct pgpkt *pCurPkt,
+ u8 *pWden)
+{
+ u8 match_word_en = 0x0F; /* default all words are disabled */
+
+ /* check if the same words are enabled both target and current PG packet */
+ if (((pTargetPkt->word_en & BIT0) == 0) &&
+ ((pCurPkt->word_en & BIT0) == 0))
+ match_word_en &= ~BIT0; /* enable word 0 */
+ if (((pTargetPkt->word_en & BIT1) == 0) &&
+ ((pCurPkt->word_en & BIT1) == 0))
+ match_word_en &= ~BIT1; /* enable word 1 */
+ if (((pTargetPkt->word_en & BIT2) == 0) &&
+ ((pCurPkt->word_en & BIT2) == 0))
+ match_word_en &= ~BIT2; /* enable word 2 */
+ if (((pTargetPkt->word_en & BIT3) == 0) &&
+ ((pCurPkt->word_en & BIT3) == 0))
+ match_word_en &= ~BIT3; /* enable word 3 */
+
+ *pWden = match_word_en;
+
+ if (match_word_en != 0xf)
+ return true;
+ else
+ return false;
+}
+
+static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts, u16 startAddr, bool bPseudoTest)
+{
+ bool bRet = false;
+ u8 i, efuse_data;
+
+ for (i = 0; i < (word_cnts*2); i++) {
+ if (efuse_OneByteRead(pAdapter, (startAddr+i), &efuse_data, bPseudoTest) && (efuse_data != 0xFF))
+ bRet = true;
+ }
+ return bRet;
+}
+
+static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
+{
+ bool bRet = false;
+ u8 i, efuse_data = 0, cur_header = 0;
+ u8 matched_wden = 0, badworden = 0;
+ u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0;
+ struct pgpkt curPkt;
+
+ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len, bPseudoTest);
+ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&efuse_max, bPseudoTest);
+
+ if (efuseType == EFUSE_WIFI) {
+ if (bPseudoTest) {
+ startAddr = (u16)(fakeEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN);
+ } else {
+ rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr);
+ startAddr %= EFUSE_REAL_CONTENT_LEN;
+ }
+ } else {
+ if (bPseudoTest)
+ startAddr = (u16)(fakeBTEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN);
+ else
+ startAddr = (u16)(BTEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN);
+ }
+
+ while (1) {
+ if (startAddr >= efuse_max_available_len) {
+ bRet = false;
+ break;
+ }
+
+ if (efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) {
+ if (EXT_HEADER(efuse_data)) {
+ cur_header = efuse_data;
+ startAddr++;
+ efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest);
+ if (ALL_WORDS_DISABLED(efuse_data)) {
+ bRet = false;
+ break;
+ } else {
+ curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
+ curPkt.word_en = efuse_data & 0x0F;
+ }
+ } else {
+ cur_header = efuse_data;
+ curPkt.offset = (cur_header>>4) & 0x0F;
+ curPkt.word_en = cur_header & 0x0F;
+ }
+
+ curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en);
+ /* if same header is found but no data followed */
+ /* write some part of data followed by the header. */
+ if ((curPkt.offset == pTargetPkt->offset) &&
+ (!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr+1, bPseudoTest)) &&
+ wordEnMatched(pTargetPkt, &curPkt, &matched_wden)) {
+ /* Here to write partial data */
+ badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr+1, matched_wden, pTargetPkt->data, bPseudoTest);
+ if (badworden != 0x0F) {
+ u32 PgWriteSuccess = 0;
+ /* if write fail on some words, write these bad words again */
+
+ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest);
+
+ if (!PgWriteSuccess) {
+ bRet = false; /* write fail, return */
+ break;
+ }
+ }
+ /* partial write ok, update the target packet for later use */
+ for (i = 0; i < 4; i++) {
+ if ((matched_wden & (0x1<<i)) == 0) /* this word has been written */
+ pTargetPkt->word_en |= (0x1<<i); /* disable the word */
+ }
+ pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
+ }
+ /* read from next header */
+ startAddr = startAddr + (curPkt.word_cnts*2) + 1;
+ } else {
+ /* not used header, 0xff */
+ *pAddr = startAddr;
+ bRet = true;
+ break;
+ }
+ }
+ return bRet;
+}
+
+static bool
+hal_EfusePgCheckAvailableAddr(
+ struct adapter *pAdapter,
+ u8 efuseType,
+ bool bPseudoTest
+ )
+{
+ u16 efuse_max_available_len = 0;
+
+ /* Change to check TYPE_EFUSE_MAP_LEN , beacuse 8188E raw 256, logic map over 256. */
+ EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&efuse_max_available_len, false);
+
+ if (Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest) >= efuse_max_available_len)
+ return false;
+ return true;
+}
+
+static void hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData, struct pgpkt *pTargetPkt)
+{
+ _rtw_memset((void *)pTargetPkt->data, 0xFF, sizeof(u8)*8);
+ pTargetPkt->offset = offset;
+ pTargetPkt->word_en = word_en;
+ efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data);
+ pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
+}
+
+static bool hal_EfusePgPacketWrite_8188e(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *pData, bool bPseudoTest)
+{
+ struct pgpkt targetPkt;
+ u16 startAddr = 0;
+ u8 efuseType = EFUSE_WIFI;
+
+ if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType, bPseudoTest))
+ return false;
+
+ hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt);
+
+ if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
+ return false;
+
+ if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
+ return false;
+
+ if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
+ return false;
+
+ return true;
+}
+
+static int Hal_EfusePgPacketWrite_Pseudo(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest)
+{
+ int ret;
+
+ ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest);
+ return ret;
+}
+
+static int Hal_EfusePgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest)
+{
+ int ret = 0;
+ ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest);
+
+ return ret;
+}
+
+static int rtl8188e_Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest)
+{
+ int ret;
+
+ if (bPseudoTest)
+ ret = Hal_EfusePgPacketWrite_Pseudo (pAdapter, offset, word_en, data, bPseudoTest);
+ else
+ ret = Hal_EfusePgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest);
+ return ret;
+}
+
+static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter)
+{
+ u32 value32;
+ struct HAL_VERSION ChipVersion;
+ struct hal_data_8188e *pHalData;
+
+ pHalData = GET_HAL_DATA(padapter);
+
+ value32 = rtw_read32(padapter, REG_SYS_CFG);
+ ChipVersion.ICType = CHIP_8188E;
+ ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP);
+
+ ChipVersion.RFType = RF_TYPE_1T1R;
+ ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC);
+ ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; /* IC version (CUT) */
+
+ /* For regulator mode. by tynli. 2011.01.14 */
+ pHalData->RegulatorMode = ((value32 & TRP_BT_EN) ? RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR);
+
+ ChipVersion.ROMVer = 0; /* ROM code version. */
+ pHalData->MultiFunc = RT_MULTI_FUNC_NONE;
+
+ dump_chip_info(ChipVersion);
+
+ pHalData->VersionID = ChipVersion;
+
+ if (IS_1T2R(ChipVersion)) {
+ pHalData->rf_type = RF_1T2R;
+ pHalData->NumTotalRFPath = 2;
+ } else if (IS_2T2R(ChipVersion)) {
+ pHalData->rf_type = RF_2T2R;
+ pHalData->NumTotalRFPath = 2;
+ } else{
+ pHalData->rf_type = RF_1T1R;
+ pHalData->NumTotalRFPath = 1;
+ }
+
+ MSG_88E("RF_Type is %x!!\n", pHalData->rf_type);
+
+ return ChipVersion;
+}
+
+static void rtl8188e_read_chip_version(struct adapter *padapter)
+{
+ ReadChipVersion8188E(padapter);
+}
+
+static void rtl8188e_GetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet)
+{
+}
+
+static void rtl8188e_SetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ struct odm_dm_struct *podmpriv = &pHalData->odmpriv;
+ switch (eVariable) {
+ case HAL_ODM_STA_INFO:
+ {
+ struct sta_info *psta = (struct sta_info *)pValue1;
+ if (bSet) {
+ DBG_88E("### Set STA_(%d) info\n", psta->mac_id);
+ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta);
+ ODM_RAInfo_Init(podmpriv, psta->mac_id);
+ } else {
+ DBG_88E("### Clean STA_(%d) info\n", psta->mac_id);
+ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, NULL);
+ }
+ }
+ break;
+ case HAL_ODM_P2P_STATE:
+ ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet);
+ break;
+ case HAL_ODM_WIFI_DISPLAY_STATE:
+ ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet);
+ break;
+ default:
+ break;
+ }
+}
+
+void rtl8188e_clone_haldata(struct adapter *dst_adapter, struct adapter *src_adapter)
+{
+ memcpy(dst_adapter->HalData, src_adapter->HalData, dst_adapter->hal_data_sz);
+}
+
+void rtl8188e_start_thread(struct adapter *padapter)
+{
+}
+
+void rtl8188e_stop_thread(struct adapter *padapter)
+{
+}
+
+static void hal_notch_filter_8188e(struct adapter *adapter, bool enable)
+{
+ if (enable) {
+ DBG_88E("Enable notch filter\n");
+ rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) | BIT1);
+ } else {
+ DBG_88E("Disable notch filter\n");
+ rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) & ~BIT1);
+ }
+}
+void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc)
+{
+ pHalFunc->free_hal_data = &rtl8188e_free_hal_data;
+
+ pHalFunc->dm_init = &rtl8188e_init_dm_priv;
+ pHalFunc->dm_deinit = &rtl8188e_deinit_dm_priv;
+
+ pHalFunc->read_chip_version = &rtl8188e_read_chip_version;
+
+ pHalFunc->set_bwmode_handler = &PHY_SetBWMode8188E;
+ pHalFunc->set_channel_handler = &PHY_SwChnl8188E;
+
+ pHalFunc->hal_dm_watchdog = &rtl8188e_HalDmWatchDog;
+
+ pHalFunc->Add_RateATid = &rtl8188e_Add_RateATid;
+ pHalFunc->run_thread = &rtl8188e_start_thread;
+ pHalFunc->cancel_thread = &rtl8188e_stop_thread;
+
+ pHalFunc->AntDivBeforeLinkHandler = &AntDivBeforeLink8188E;
+ pHalFunc->AntDivCompareHandler = &AntDivCompare8188E;
+ pHalFunc->read_bbreg = &rtl8188e_PHY_QueryBBReg;
+ pHalFunc->write_bbreg = &rtl8188e_PHY_SetBBReg;
+ pHalFunc->read_rfreg = &rtl8188e_PHY_QueryRFReg;
+ pHalFunc->write_rfreg = &rtl8188e_PHY_SetRFReg;
+
+ /* Efuse related function */
+ pHalFunc->EfusePowerSwitch = &rtl8188e_EfusePowerSwitch;
+ pHalFunc->ReadEFuse = &rtl8188e_ReadEFuse;
+ pHalFunc->EFUSEGetEfuseDefinition = &rtl8188e_EFUSE_GetEfuseDefinition;
+ pHalFunc->EfuseGetCurrentSize = &rtl8188e_EfuseGetCurrentSize;
+ pHalFunc->Efuse_PgPacketRead = &rtl8188e_Efuse_PgPacketRead;
+ pHalFunc->Efuse_PgPacketWrite = &rtl8188e_Efuse_PgPacketWrite;
+ pHalFunc->Efuse_WordEnableDataWrite = &rtl8188e_Efuse_WordEnableDataWrite;
+
+ pHalFunc->sreset_init_value = &sreset_init_value;
+ pHalFunc->sreset_reset_value = &sreset_reset_value;
+ pHalFunc->silentreset = &rtl8188e_silentreset_for_specific_platform;
+ pHalFunc->sreset_xmit_status_check = &rtl8188e_sreset_xmit_status_check;
+ pHalFunc->sreset_linked_status_check = &rtl8188e_sreset_linked_status_check;
+ pHalFunc->sreset_get_wifi_status = &sreset_get_wifi_status;
+
+ pHalFunc->GetHalODMVarHandler = &rtl8188e_GetHalODMVar;
+ pHalFunc->SetHalODMVarHandler = &rtl8188e_SetHalODMVar;
+
+ pHalFunc->IOL_exec_cmds_sync = &rtl8188e_IOL_exec_cmds_sync;
+
+ pHalFunc->hal_notch_filter = &hal_notch_filter_8188e;
+}
+
+u8 GetEEPROMSize8188E(struct adapter *padapter)
+{
+ u8 size = 0;
+ u32 cr;
+
+ cr = rtw_read16(padapter, REG_9346CR);
+ /* 6: EEPROM used is 93C46, 4: boot from E-Fuse. */
+ size = (cr & BOOT_FROM_EEPROM) ? 6 : 4;
+
+ MSG_88E("EEPROM type is %s\n", size == 4 ? "E-FUSE" : "93C46");
+
+ return size;
+}
+
+/* */
+/* */
+/* LLT R/W/Init function */
+/* */
+/* */
+static s32 _LLTWrite(struct adapter *padapter, u32 address, u32 data)
+{
+ s32 status = _SUCCESS;
+ s32 count = 0;
+ u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS);
+ u16 LLTReg = REG_LLT_INIT;
+
+ rtw_write32(padapter, LLTReg, value);
+
+ /* polling */
+ do {
+ value = rtw_read32(padapter, LLTReg);
+ if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value))
+ break;
+
+ if (count > POLLING_LLT_THRESHOLD) {
+ RT_TRACE(_module_hal_init_c_, _drv_err_, ("Failed to polling write LLT done at address %d!\n", address));
+ status = _FAIL;
+ break;
+ }
+ } while (count++);
+
+ return status;
+}
+
+s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
+{
+ s32 status = _FAIL;
+ u32 i;
+ u32 Last_Entry_Of_TxPktBuf = LAST_ENTRY_OF_TX_PKT_BUFFER;/* 176, 22k */
+
+ if (rtw_IOL_applied(padapter)) {
+ status = iol_InitLLTTable(padapter, txpktbuf_bndy);
+ } else {
+ for (i = 0; i < (txpktbuf_bndy - 1); i++) {
+ status = _LLTWrite(padapter, i, i + 1);
+ if (_SUCCESS != status)
+ return status;
+ }
+
+ /* end of list */
+ status = _LLTWrite(padapter, (txpktbuf_bndy - 1), 0xFF);
+ if (_SUCCESS != status)
+ return status;
+
+ /* Make the other pages as ring buffer */
+ /* This ring buffer is used as beacon buffer if we config this MAC as two MAC transfer. */
+ /* Otherwise used as local loopback buffer. */
+ for (i = txpktbuf_bndy; i < Last_Entry_Of_TxPktBuf; i++) {
+ status = _LLTWrite(padapter, i, (i + 1));
+ if (_SUCCESS != status)
+ return status;
+ }
+
+ /* Let last entry point to the start entry of ring buffer */
+ status = _LLTWrite(padapter, Last_Entry_Of_TxPktBuf, txpktbuf_bndy);
+ if (_SUCCESS != status) {
+ return status;
+ }
+ }
+
+ return status;
+}
+
+void
+Hal_InitPGData88E(struct adapter *padapter)
+{
+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+
+ if (!pEEPROM->bautoload_fail_flag) { /* autoload OK. */
+ if (!is_boot_from_eeprom(padapter)) {
+ /* Read EFUSE real map to shadow. */
+ EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false);
+ }
+ } else {/* autoload fail */
+ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("AutoLoad Fail reported from CR9346!!\n"));
+ /* update to default value 0xFF */
+ if (!is_boot_from_eeprom(padapter))
+ EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false);
+ }
+}
+
+void
+Hal_EfuseParseIDCode88E(
+ struct adapter *padapter,
+ u8 *hwinfo
+ )
+{
+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+ u16 EEPROMId;
+
+ /* Checl 0x8129 again for making sure autoload status!! */
+ EEPROMId = le16_to_cpu(*((__le16 *)hwinfo));
+ if (EEPROMId != RTL_EEPROM_ID) {
+ DBG_88E("EEPROM ID(%#x) is invalid!!\n", EEPROMId);
+ pEEPROM->bautoload_fail_flag = true;
+ } else {
+ pEEPROM->bautoload_fail_flag = false;
+ }
+
+ DBG_88E("EEPROM ID = 0x%04x\n", EEPROMId);
+}
+
+static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G, u8 *PROMContent, bool AutoLoadFail)
+{
+ u32 rfPath, eeAddr = EEPROM_TX_PWR_INX_88E, group, TxCount = 0;
+
+ _rtw_memset(pwrInfo24G, 0, sizeof(struct txpowerinfo24g));
+
+ if (AutoLoadFail) {
+ for (rfPath = 0; rfPath < MAX_RF_PATH; rfPath++) {
+ /* 2.4G default value */
+ for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
+ pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX;
+ pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX;
+ }
+ for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+ if (TxCount == 0) {
+ pwrInfo24G->BW20_Diff[rfPath][0] = EEPROM_DEFAULT_24G_HT20_DIFF;
+ pwrInfo24G->OFDM_Diff[rfPath][0] = EEPROM_DEFAULT_24G_OFDM_DIFF;
+ } else {
+ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+ pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+ pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+ }
+ }
+ }
+ return;
+ }
+
+ for (rfPath = 0; rfPath < MAX_RF_PATH; rfPath++) {
+ /* 2.4G default value */
+ for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
+ pwrInfo24G->IndexCCK_Base[rfPath][group] = PROMContent[eeAddr++];
+ if (pwrInfo24G->IndexCCK_Base[rfPath][group] == 0xFF)
+ pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX;
+ }
+ for (group = 0; group < MAX_CHNL_GROUP_24G-1; group++) {
+ pwrInfo24G->IndexBW40_Base[rfPath][group] = PROMContent[eeAddr++];
+ if (pwrInfo24G->IndexBW40_Base[rfPath][group] == 0xFF)
+ pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX;
+ }
+ for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+ if (TxCount == 0) {
+ pwrInfo24G->BW40_Diff[rfPath][TxCount] = 0;
+ if (PROMContent[eeAddr] == 0xFF) {
+ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_HT20_DIFF;
+ } else {
+ pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4;
+ if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
+ pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0;
+ }
+
+ if (PROMContent[eeAddr] == 0xFF) {
+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_OFDM_DIFF;
+ } else {
+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f);
+ if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0;
+ }
+ pwrInfo24G->CCK_Diff[rfPath][TxCount] = 0;
+ eeAddr++;
+ } else {
+ if (PROMContent[eeAddr] == 0xFF) {
+ pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+ } else {
+ pwrInfo24G->BW40_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4;
+ if (pwrInfo24G->BW40_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
+ pwrInfo24G->BW40_Diff[rfPath][TxCount] |= 0xF0;
+ }
+
+ if (PROMContent[eeAddr] == 0xFF) {
+ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+ } else {
+ pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f);
+ if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
+ pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0;
+ }
+ eeAddr++;
+
+ if (PROMContent[eeAddr] == 0xFF) {
+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+ } else {
+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4;
+ if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0;
+ }
+
+ if (PROMContent[eeAddr] == 0xFF) {
+ pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+ } else {
+ pwrInfo24G->CCK_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f);
+ if (pwrInfo24G->CCK_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */
+ pwrInfo24G->CCK_Diff[rfPath][TxCount] |= 0xF0;
+ }
+ eeAddr++;
+ }
+ }
+ }
+}
+
+static u8 Hal_GetChnlGroup88E(u8 chnl, u8 *pGroup)
+{
+ u8 bIn24G = true;
+
+ if (chnl <= 14) {
+ bIn24G = true;
+
+ if (chnl < 3) /* Chanel 1-2 */
+ *pGroup = 0;
+ else if (chnl < 6) /* Channel 3-5 */
+ *pGroup = 1;
+ else if (chnl < 9) /* Channel 6-8 */
+ *pGroup = 2;
+ else if (chnl < 12) /* Channel 9-11 */
+ *pGroup = 3;
+ else if (chnl < 14) /* Channel 12-13 */
+ *pGroup = 4;
+ else if (chnl == 14) /* Channel 14 */
+ *pGroup = 5;
+ } else {
+ bIn24G = false;
+
+ if (chnl <= 40)
+ *pGroup = 0;
+ else if (chnl <= 48)
+ *pGroup = 1;
+ else if (chnl <= 56)
+ *pGroup = 2;
+ else if (chnl <= 64)
+ *pGroup = 3;
+ else if (chnl <= 104)
+ *pGroup = 4;
+ else if (chnl <= 112)
+ *pGroup = 5;
+ else if (chnl <= 120)
+ *pGroup = 5;
+ else if (chnl <= 128)
+ *pGroup = 6;
+ else if (chnl <= 136)
+ *pGroup = 7;
+ else if (chnl <= 144)
+ *pGroup = 8;
+ else if (chnl <= 153)
+ *pGroup = 9;
+ else if (chnl <= 161)
+ *pGroup = 10;
+ else if (chnl <= 177)
+ *pGroup = 11;
+ }
+ return bIn24G;
+}
+
+void Hal_ReadPowerSavingMode88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
+{
+ if (AutoLoadFail) {
+ padapter->pwrctrlpriv.bHWPowerdown = false;
+ padapter->pwrctrlpriv.bSupportRemoteWakeup = false;
+ } else {
+ /* hw power down mode selection , 0:rf-off / 1:power down */
+
+ if (padapter->registrypriv.hwpdn_mode == 2)
+ padapter->pwrctrlpriv.bHWPowerdown = (hwinfo[EEPROM_RF_FEATURE_OPTION_88E] & BIT4);
+ else
+ padapter->pwrctrlpriv.bHWPowerdown = padapter->registrypriv.hwpdn_mode;
+
+ /* decide hw if support remote wakeup function */
+ /* if hw supported, 8051 (SIE) will generate WeakUP signal(D+/D- toggle) when autoresume */
+ padapter->pwrctrlpriv.bSupportRemoteWakeup = (hwinfo[EEPROM_USB_OPTIONAL_FUNCTION0] & BIT1) ? true : false;
+
+ DBG_88E("%s...bHWPwrPindetect(%x)-bHWPowerdown(%x) , bSupportRemoteWakeup(%x)\n", __func__,
+ padapter->pwrctrlpriv.bHWPwrPindetect, padapter->pwrctrlpriv.bHWPowerdown , padapter->pwrctrlpriv.bSupportRemoteWakeup);
+
+ DBG_88E("### PS params => power_mgnt(%x), usbss_enable(%x) ###\n", padapter->registrypriv.power_mgnt, padapter->registrypriv.usbss_enable);
+ }
+}
+
+void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool AutoLoadFail)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+ struct txpowerinfo24g pwrInfo24G;
+ u8 rfPath, ch, group;
+ u8 bIn24G, TxCount;
+
+ Hal_ReadPowerValueFromPROM_8188E(&pwrInfo24G, PROMContent, AutoLoadFail);
+
+ if (!AutoLoadFail)
+ pHalData->bTXPowerDataReadFromEEPORM = true;
+
+ for (rfPath = 0; rfPath < pHalData->NumTotalRFPath; rfPath++) {
+ for (ch = 0; ch <= CHANNEL_MAX_NUMBER; ch++) {
+ bIn24G = Hal_GetChnlGroup88E(ch, &group);
+ if (bIn24G) {
+ pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][group];
+ if (ch == 14)
+ pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][4];
+ else
+ pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][group];
+ }
+ if (bIn24G) {
+ DBG_88E("======= Path %d, Channel %d =======\n", rfPath, ch);
+ DBG_88E("Index24G_CCK_Base[%d][%d] = 0x%x\n", rfPath, ch , pHalData->Index24G_CCK_Base[rfPath][ch]);
+ DBG_88E("Index24G_BW40_Base[%d][%d] = 0x%x\n", rfPath, ch , pHalData->Index24G_BW40_Base[rfPath][ch]);
+ }
+ }
+ for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+ pHalData->CCK_24G_Diff[rfPath][TxCount] = pwrInfo24G.CCK_Diff[rfPath][TxCount];
+ pHalData->OFDM_24G_Diff[rfPath][TxCount] = pwrInfo24G.OFDM_Diff[rfPath][TxCount];
+ pHalData->BW20_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW20_Diff[rfPath][TxCount];
+ pHalData->BW40_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW40_Diff[rfPath][TxCount];
+ DBG_88E("======= TxCount %d =======\n", TxCount);
+ DBG_88E("CCK_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->CCK_24G_Diff[rfPath][TxCount]);
+ DBG_88E("OFDM_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->OFDM_24G_Diff[rfPath][TxCount]);
+ DBG_88E("BW20_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->BW20_24G_Diff[rfPath][TxCount]);
+ DBG_88E("BW40_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->BW40_24G_Diff[rfPath][TxCount]);
+ }
+ }
+
+ /* 2010/10/19 MH Add Regulator recognize for CU. */
+ if (!AutoLoadFail) {
+ pHalData->EEPROMRegulatory = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x7); /* bit0~2 */
+ if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
+ pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION&0x7); /* bit0~2 */
+ } else {
+ pHalData->EEPROMRegulatory = 0;
+ }
+ DBG_88E("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory);
+}
+
+void Hal_EfuseParseXtal_8188E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+
+ if (!AutoLoadFail) {
+ pHalData->CrystalCap = hwinfo[EEPROM_XTAL_88E];
+ if (pHalData->CrystalCap == 0xFF)
+ pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E;
+ } else {
+ pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E;
+ }
+ DBG_88E("CrystalCap: 0x%2x\n", pHalData->CrystalCap);
+}
+
+void Hal_EfuseParseBoardType88E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+
+ if (!AutoLoadFail)
+ pHalData->BoardType = ((hwinfo[EEPROM_RF_BOARD_OPTION_88E]&0xE0)>>5);
+ else
+ pHalData->BoardType = 0;
+ DBG_88E("Board Type: 0x%2x\n", pHalData->BoardType);
+}
+
+void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+
+ if (!AutoLoadFail) {
+ pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_88E];
+ if (pHalData->EEPROMVersion == 0xFF)
+ pHalData->EEPROMVersion = EEPROM_Default_Version;
+ } else {
+ pHalData->EEPROMVersion = 1;
+ }
+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+ ("Hal_EfuseParseEEPROMVer(), EEVer = %d\n",
+ pHalData->EEPROMVersion));
+}
+
+void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
+{
+ padapter->mlmepriv.ChannelPlan =
+ hal_com_get_channel_plan(padapter,
+ hwinfo ? hwinfo[EEPROM_ChannelPlan_88E] : 0xFF,
+ padapter->registrypriv.channel_plan,
+ RT_CHANNEL_DOMAIN_WORLD_WIDE_13, AutoLoadFail);
+
+ DBG_88E("mlmepriv.ChannelPlan = 0x%02x\n", padapter->mlmepriv.ChannelPlan);
+}
+
+void Hal_EfuseParseCustomerID88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+
+ if (!AutoLoadFail) {
+ pHalData->EEPROMCustomerID = hwinfo[EEPROM_CUSTOMERID_88E];
+ } else {
+ pHalData->EEPROMCustomerID = 0;
+ pHalData->EEPROMSubCustomerID = 0;
+ }
+ DBG_88E("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID);
+}
+
+void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter, u8 *PROMContent, bool AutoLoadFail)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+ struct registry_priv *registry_par = &pAdapter->registrypriv;
+
+ if (!AutoLoadFail) {
+ /* Antenna Diversity setting. */
+ if (registry_par->antdiv_cfg == 2) { /* 2:By EFUSE */
+ pHalData->AntDivCfg = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x18)>>3;
+ if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
+ pHalData->AntDivCfg = (EEPROM_DEFAULT_BOARD_OPTION&0x18)>>3;;
+ } else {
+ pHalData->AntDivCfg = registry_par->antdiv_cfg; /* 0:OFF , 1:ON, 2:By EFUSE */
+ }
+
+ if (registry_par->antdiv_type == 0) {
+ /* If TRxAntDivType is AUTO in advanced setting, use EFUSE value instead. */
+ pHalData->TRxAntDivType = PROMContent[EEPROM_RF_ANTENNA_OPT_88E];
+ if (pHalData->TRxAntDivType == 0xFF)
+ pHalData->TRxAntDivType = CG_TRX_HW_ANTDIV; /* For 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */
+ } else {
+ pHalData->TRxAntDivType = registry_par->antdiv_type;
+ }
+
+ if (pHalData->TRxAntDivType == CG_TRX_HW_ANTDIV || pHalData->TRxAntDivType == CGCS_RX_HW_ANTDIV)
+ pHalData->AntDivCfg = 1; /* 0xC1[3] is ignored. */
+ } else {
+ pHalData->AntDivCfg = 0;
+ pHalData->TRxAntDivType = pHalData->TRxAntDivType; /* The value in the driver setting of device manager. */
+ }
+ DBG_88E("EEPROM : AntDivCfg = %x, TRxAntDivType = %x\n", pHalData->AntDivCfg, pHalData->TRxAntDivType);
+}
+
+void Hal_ReadThermalMeter_88E(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+
+ /* ThermalMeter from EEPROM */
+ if (!AutoloadFail)
+ pHalData->EEPROMThermalMeter = PROMContent[EEPROM_THERMAL_METER_88E];
+ else
+ pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E;
+
+ if (pHalData->EEPROMThermalMeter == 0xff || AutoloadFail) {
+ pHalData->bAPKThermalMeterIgnore = true;
+ pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E;
+ }
+ DBG_88E("ThermalMeter = 0x%x\n", pHalData->EEPROMThermalMeter);
+}
+
+void Hal_InitChannelPlan(struct adapter *padapter)
+{
+}
+
+bool HalDetectPwrDownMode88E(struct adapter *Adapter)
+{
+ u8 tmpvalue = 0;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv;
+
+ EFUSE_ShadowRead(Adapter, 1, EEPROM_RF_FEATURE_OPTION_88E, (u32 *)&tmpvalue);
+
+ /* 2010/08/25 MH INF priority > PDN Efuse value. */
+ if (tmpvalue & BIT(4) && pwrctrlpriv->reg_pdnmode)
+ pHalData->pwrdown = true;
+ else
+ pHalData->pwrdown = false;
+
+ DBG_88E("HalDetectPwrDownMode(): PDN =%d\n", pHalData->pwrdown);
+
+ return pHalData->pwrdown;
+} /* HalDetectPwrDownMode */
+
+/* This function is used only for 92C to set REG_BCN_CTRL(0x550) register. */
+/* We just reserve the value of the register in variable pHalData->RegBcnCtrlVal and then operate */
+/* the value of the register via atomic operation. */
+/* This prevents from race condition when setting this register. */
+/* The value of pHalData->RegBcnCtrlVal is initialized in HwConfigureRTL8192CE() function. */
+
+void SetBcnCtrlReg(struct adapter *padapter, u8 SetBits, u8 ClearBits)
+{
+ struct hal_data_8188e *pHalData;
+
+ pHalData = GET_HAL_DATA(padapter);
+
+ pHalData->RegBcnCtrlVal |= SetBits;
+ pHalData->RegBcnCtrlVal &= ~ClearBits;
+
+ rtw_write8(padapter, REG_BCN_CTRL, (u8)pHalData->RegBcnCtrlVal);
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_mp.c b/drivers/staging/rtl8188eu/hal/rtl8188e_mp.c
new file mode 100644
index 00000000000..e97ba02fa04
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_mp.c
@@ -0,0 +1,860 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_MP_C_
+
+#include <drv_types.h>
+#include <rtw_mp.h>
+#include <rtl8188e_hal.h>
+#include <rtl8188e_dm.h>
+
+s32 Hal_SetPowerTracking(struct adapter *padapter, u8 enable)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+ struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
+
+ if (!netif_running(padapter->pnetdev)) {
+ RT_TRACE(_module_mp_, _drv_warning_,
+ ("SetPowerTracking! Fail: interface not opened!\n"));
+ return _FAIL;
+ }
+
+ if (!check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE)) {
+ RT_TRACE(_module_mp_, _drv_warning_,
+ ("SetPowerTracking! Fail: not in MP mode!\n"));
+ return _FAIL;
+ }
+
+ if (enable)
+ pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true;
+ else
+ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = false;
+
+ return _SUCCESS;
+}
+
+void Hal_GetPowerTracking(struct adapter *padapter, u8 *enable)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+ struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
+
+ *enable = pDM_Odm->RFCalibrateInfo.TxPowerTrackControl;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: mpt_SwitchRfSetting
+ *
+ * Overview: Change RF Setting when we siwthc channel/rate/BW for MP.
+ *
+ * Input: struct adapter * pAdapter
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 01/08/2009 MHC Suggestion from SD3 Willis for 92S series.
+ * 01/09/2009 MHC Add CCK modification for 40MHZ. Suggestion from SD3.
+ *
+ *---------------------------------------------------------------------------*/
+void Hal_mpt_SwitchRfSetting(struct adapter *pAdapter)
+{
+ struct mp_priv *pmp = &pAdapter->mppriv;
+
+ /* <20120525, Kordan> Dynamic mechanism for APK, asked by Dennis. */
+ pmp->MptCtx.backup0x52_RF_A = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0);
+ pmp->MptCtx.backup0x52_RF_B = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0);
+ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0, 0xD);
+ PHY_SetRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0, 0xD);
+
+ return;
+}
+/*---------------------------hal\rtl8192c\MPT_Phy.c---------------------------*/
+
+/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/
+void Hal_MPT_CCKTxPowerAdjust(struct adapter *Adapter, bool bInCH14)
+{
+ u32 TempVal = 0, TempVal2 = 0, TempVal3 = 0;
+ u32 CurrCCKSwingVal = 0, CCKSwingIndex = 12;
+ u8 i;
+
+ /* get current cck swing value and check 0xa22 & 0xa23 later to match the table. */
+ CurrCCKSwingVal = read_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord);
+
+ if (!bInCH14) {
+ /* Readback the current bb cck swing value and compare with the table to */
+ /* get the current swing index */
+ for (i = 0; i < CCK_TABLE_SIZE; i++) {
+ if (((CurrCCKSwingVal&0xff) == (u32)CCKSwingTable_Ch1_Ch13[i][0]) &&
+ (((CurrCCKSwingVal&0xff00)>>8) == (u32)CCKSwingTable_Ch1_Ch13[i][1])) {
+ CCKSwingIndex = i;
+ break;
+ }
+ }
+
+ /* Write 0xa22 0xa23 */
+ TempVal = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][0] +
+ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][1]<<8);
+
+
+ /* Write 0xa24 ~ 0xa27 */
+ TempVal2 = 0;
+ TempVal2 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][2] +
+ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][3]<<8) +
+ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][4]<<16)+
+ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][5]<<24);
+
+ /* Write 0xa28 0xa29 */
+ TempVal3 = 0;
+ TempVal3 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][6] +
+ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][7]<<8);
+ } else {
+ for (i = 0; i < CCK_TABLE_SIZE; i++) {
+ if (((CurrCCKSwingVal&0xff) == (u32)CCKSwingTable_Ch14[i][0]) &&
+ (((CurrCCKSwingVal&0xff00)>>8) == (u32)CCKSwingTable_Ch14[i][1])) {
+ CCKSwingIndex = i;
+ break;
+ }
+ }
+
+ /* Write 0xa22 0xa23 */
+ TempVal = CCKSwingTable_Ch14[CCKSwingIndex][0] +
+ (CCKSwingTable_Ch14[CCKSwingIndex][1]<<8);
+
+ /* Write 0xa24 ~ 0xa27 */
+ TempVal2 = 0;
+ TempVal2 = CCKSwingTable_Ch14[CCKSwingIndex][2] +
+ (CCKSwingTable_Ch14[CCKSwingIndex][3]<<8) +
+ (CCKSwingTable_Ch14[CCKSwingIndex][4]<<16)+
+ (CCKSwingTable_Ch14[CCKSwingIndex][5]<<24);
+
+ /* Write 0xa28 0xa29 */
+ TempVal3 = 0;
+ TempVal3 = CCKSwingTable_Ch14[CCKSwingIndex][6] +
+ (CCKSwingTable_Ch14[CCKSwingIndex][7]<<8);
+ }
+
+ write_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord, TempVal);
+ write_bbreg(Adapter, rCCK0_TxFilter2, bMaskDWord, TempVal2);
+ write_bbreg(Adapter, rCCK0_DebugPort, bMaskLWord, TempVal3);
+}
+
+void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *pAdapter, bool beven)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+ struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx;
+ struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
+ s32 TempCCk;
+ u8 CCK_index, CCK_index_old = 0;
+ u8 Action = 0; /* 0: no action, 1: even->odd, 2:odd->even */
+ s32 i = 0;
+
+
+ if (!IS_92C_SERIAL(pHalData->VersionID))
+ return;
+ if (beven && !pMptCtx->bMptIndexEven) {
+ /* odd->even */
+ Action = 2;
+ pMptCtx->bMptIndexEven = true;
+ } else if (!beven && pMptCtx->bMptIndexEven) {
+ /* even->odd */
+ Action = 1;
+ pMptCtx->bMptIndexEven = false;
+ }
+
+ if (Action != 0) {
+ /* Query CCK default setting From 0xa24 */
+ TempCCk = read_bbreg(pAdapter, rCCK0_TxFilter2, bMaskDWord) & bMaskCCK;
+ for (i = 0; i < CCK_TABLE_SIZE; i++) {
+ if (pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
+ if (_rtw_memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4)) {
+ CCK_index_old = (u8)i;
+ break;
+ }
+ } else {
+ if (_rtw_memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4)) {
+ CCK_index_old = (u8)i;
+ break;
+ }
+ }
+ }
+
+ if (Action == 1)
+ CCK_index = CCK_index_old - 1;
+ else
+ CCK_index = CCK_index_old + 1;
+
+ /* Adjust CCK according to gain index */
+ if (!pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
+ rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch1_Ch13[CCK_index][0]);
+ rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch1_Ch13[CCK_index][1]);
+ rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch1_Ch13[CCK_index][2]);
+ rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch1_Ch13[CCK_index][3]);
+ rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch1_Ch13[CCK_index][4]);
+ rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch1_Ch13[CCK_index][5]);
+ rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch1_Ch13[CCK_index][6]);
+ rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch1_Ch13[CCK_index][7]);
+ } else {
+ rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch14[CCK_index][0]);
+ rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch14[CCK_index][1]);
+ rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch14[CCK_index][2]);
+ rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch14[CCK_index][3]);
+ rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch14[CCK_index][4]);
+ rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch14[CCK_index][5]);
+ rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch14[CCK_index][6]);
+ rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch14[CCK_index][7]);
+ }
+ }
+}
+/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/
+
+/*
+ * SetChannel
+ * Description
+ * Use H2C command to change channel,
+ * not only modify rf register, but also other setting need to be done.
+ */
+void Hal_SetChannel(struct adapter *pAdapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+ struct mp_priv *pmp = &pAdapter->mppriv;
+ struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
+ u8 eRFPath;
+ u8 channel = pmp->channel;
+
+ /* set RF channel register */
+ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++)
+ _write_rfreg(pAdapter, eRFPath, ODM_CHANNEL, 0x3FF, channel);
+ Hal_mpt_SwitchRfSetting(pAdapter);
+
+ SelectChannel(pAdapter, channel);
+
+ if (pHalData->CurrentChannel == 14 && !pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
+ pDM_Odm->RFCalibrateInfo.bCCKinCH14 = true;
+ Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14);
+ } else if (pHalData->CurrentChannel != 14 && pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
+ pDM_Odm->RFCalibrateInfo.bCCKinCH14 = false;
+ Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14);
+ }
+}
+
+/*
+ * Notice
+ * Switch bandwitdth may change center frequency(channel)
+ */
+void Hal_SetBandwidth(struct adapter *pAdapter)
+{
+ struct mp_priv *pmp = &pAdapter->mppriv;
+
+
+ SetBWMode(pAdapter, pmp->bandwidth, pmp->prime_channel_offset);
+ Hal_mpt_SwitchRfSetting(pAdapter);
+}
+
+void Hal_SetCCKTxPower(struct adapter *pAdapter, u8 *TxPower)
+{
+ u32 tmpval = 0;
+
+
+ /* rf-A cck tx power */
+ write_bbreg(pAdapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, TxPower[RF_PATH_A]);
+ tmpval = (TxPower[RF_PATH_A]<<16) | (TxPower[RF_PATH_A]<<8) | TxPower[RF_PATH_A];
+ write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+ /* rf-B cck tx power */
+ write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, TxPower[RF_PATH_B]);
+ tmpval = (TxPower[RF_PATH_B]<<16) | (TxPower[RF_PATH_B]<<8) | TxPower[RF_PATH_B];
+ write_bbreg(pAdapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
+
+ RT_TRACE(_module_mp_, _drv_notice_,
+ ("-SetCCKTxPower: A[0x%02x] B[0x%02x]\n",
+ TxPower[RF_PATH_A], TxPower[RF_PATH_B]));
+}
+
+void Hal_SetOFDMTxPower(struct adapter *pAdapter, u8 *TxPower)
+{
+ u32 TxAGC = 0;
+ u8 tmpval = 0;
+
+ /* HT Tx-rf(A) */
+ tmpval = TxPower[RF_PATH_A];
+ TxAGC = (tmpval<<24) | (tmpval<<16) | (tmpval<<8) | tmpval;
+
+ write_bbreg(pAdapter, rTxAGC_A_Rate18_06, bMaskDWord, TxAGC);
+ write_bbreg(pAdapter, rTxAGC_A_Rate54_24, bMaskDWord, TxAGC);
+ write_bbreg(pAdapter, rTxAGC_A_Mcs03_Mcs00, bMaskDWord, TxAGC);
+ write_bbreg(pAdapter, rTxAGC_A_Mcs07_Mcs04, bMaskDWord, TxAGC);
+ write_bbreg(pAdapter, rTxAGC_A_Mcs11_Mcs08, bMaskDWord, TxAGC);
+ write_bbreg(pAdapter, rTxAGC_A_Mcs15_Mcs12, bMaskDWord, TxAGC);
+
+ /* HT Tx-rf(B) */
+ tmpval = TxPower[RF_PATH_B];
+ TxAGC = (tmpval<<24) | (tmpval<<16) | (tmpval<<8) | tmpval;
+
+ write_bbreg(pAdapter, rTxAGC_B_Rate18_06, bMaskDWord, TxAGC);
+ write_bbreg(pAdapter, rTxAGC_B_Rate54_24, bMaskDWord, TxAGC);
+ write_bbreg(pAdapter, rTxAGC_B_Mcs03_Mcs00, bMaskDWord, TxAGC);
+ write_bbreg(pAdapter, rTxAGC_B_Mcs07_Mcs04, bMaskDWord, TxAGC);
+ write_bbreg(pAdapter, rTxAGC_B_Mcs11_Mcs08, bMaskDWord, TxAGC);
+ write_bbreg(pAdapter, rTxAGC_B_Mcs15_Mcs12, bMaskDWord, TxAGC);
+}
+
+void Hal_SetAntennaPathPower(struct adapter *pAdapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+ u8 TxPowerLevel[MAX_RF_PATH_NUMS];
+ u8 rfPath;
+
+ TxPowerLevel[RF_PATH_A] = pAdapter->mppriv.txpoweridx;
+ TxPowerLevel[RF_PATH_B] = pAdapter->mppriv.txpoweridx_b;
+
+ switch (pAdapter->mppriv.antenna_tx) {
+ case ANTENNA_A:
+ default:
+ rfPath = RF_PATH_A;
+ break;
+ case ANTENNA_B:
+ rfPath = RF_PATH_B;
+ break;
+ case ANTENNA_C:
+ rfPath = RF_PATH_C;
+ break;
+ }
+
+ switch (pHalData->rf_chip) {
+ case RF_8225:
+ case RF_8256:
+ case RF_6052:
+ Hal_SetCCKTxPower(pAdapter, TxPowerLevel);
+ if (pAdapter->mppriv.rateidx < MPT_RATE_6M) /* CCK rate */
+ Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath]%2 == 0);
+ Hal_SetOFDMTxPower(pAdapter, TxPowerLevel);
+ break;
+ default:
+ break;
+ }
+}
+
+void Hal_SetTxPower(struct adapter *pAdapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+ u8 TxPower = pAdapter->mppriv.txpoweridx;
+ u8 TxPowerLevel[MAX_RF_PATH_NUMS];
+ u8 rf, rfPath;
+
+ for (rf = 0; rf < MAX_RF_PATH_NUMS; rf++)
+ TxPowerLevel[rf] = TxPower;
+
+ switch (pAdapter->mppriv.antenna_tx) {
+ case ANTENNA_A:
+ default:
+ rfPath = RF_PATH_A;
+ break;
+ case ANTENNA_B:
+ rfPath = RF_PATH_B;
+ break;
+ case ANTENNA_C:
+ rfPath = RF_PATH_C;
+ break;
+ }
+
+ switch (pHalData->rf_chip) {
+ /* 2008/09/12 MH Test only !! We enable the TX power tracking for MP!!!!! */
+ /* We should call normal driver API later!! */
+ case RF_8225:
+ case RF_8256:
+ case RF_6052:
+ Hal_SetCCKTxPower(pAdapter, TxPowerLevel);
+ if (pAdapter->mppriv.rateidx < MPT_RATE_6M) /* CCK rate */
+ Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath]%2 == 0);
+ Hal_SetOFDMTxPower(pAdapter, TxPowerLevel);
+ break;
+ default:
+ break;
+ }
+}
+
+void Hal_SetDataRate(struct adapter *pAdapter)
+{
+ Hal_mpt_SwitchRfSetting(pAdapter);
+}
+
+void Hal_SetAntenna(struct adapter *pAdapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+
+ struct ant_sel_ofdm *p_ofdm_tx; /* OFDM Tx register */
+ struct ant_sel_cck *p_cck_txrx;
+ u8 r_rx_antenna_ofdm = 0, r_ant_select_cck_val = 0;
+ u8 chgTx = 0, chgRx = 0;
+ u32 r_ant_select_ofdm_val = 0, r_ofdm_tx_en_val = 0;
+
+
+ p_ofdm_tx = (struct ant_sel_ofdm *)&r_ant_select_ofdm_val;
+ p_cck_txrx = (struct ant_sel_cck *)&r_ant_select_cck_val;
+
+ p_ofdm_tx->r_ant_ht1 = 0x1;
+ p_ofdm_tx->r_ant_ht2 = 0x2; /* Second TX RF path is A */
+ p_ofdm_tx->r_ant_non_ht = 0x3; /* 0x1+0x2=0x3 */
+
+ switch (pAdapter->mppriv.antenna_tx) {
+ case ANTENNA_A:
+ p_ofdm_tx->r_tx_antenna = 0x1;
+ r_ofdm_tx_en_val = 0x1;
+ p_ofdm_tx->r_ant_l = 0x1;
+ p_ofdm_tx->r_ant_ht_s1 = 0x1;
+ p_ofdm_tx->r_ant_non_ht_s1 = 0x1;
+ p_cck_txrx->r_ccktx_enable = 0x8;
+ chgTx = 1;
+
+ /* From SD3 Willis suggestion !!! Set RF A=TX and B as standby */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 1);
+ r_ofdm_tx_en_val = 0x3;
+
+ /* Power save */
+
+ /* We need to close RFB by SW control */
+ if (pHalData->rf_type == RF_2T2R) {
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0);
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 1);
+ PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0);
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1);
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 0);
+ }
+ break;
+ case ANTENNA_B:
+ p_ofdm_tx->r_tx_antenna = 0x2;
+ r_ofdm_tx_en_val = 0x2;
+ p_ofdm_tx->r_ant_l = 0x2;
+ p_ofdm_tx->r_ant_ht_s1 = 0x2;
+ p_ofdm_tx->r_ant_non_ht_s1 = 0x2;
+ p_cck_txrx->r_ccktx_enable = 0x4;
+ chgTx = 1;
+ /* From SD3 Willis suggestion !!! Set RF A as standby */
+ PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 1);
+ PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2);
+
+ /* Power save */
+ /* cosa r_ant_select_ofdm_val = 0x22222222; */
+
+ /* 2008/10/31 MH From SD3 Willi's suggestion. We must read RF 1T table. */
+ /* 2009/01/08 MH From Sd3 Willis. We need to close RFA by SW control */
+ if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_1T2R) {
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 1);
+ PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT10, 0);
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0);
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 0);
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1);
+ }
+ break;
+ case ANTENNA_AB: /* For 8192S */
+ p_ofdm_tx->r_tx_antenna = 0x3;
+ r_ofdm_tx_en_val = 0x3;
+ p_ofdm_tx->r_ant_l = 0x3;
+ p_ofdm_tx->r_ant_ht_s1 = 0x3;
+ p_ofdm_tx->r_ant_non_ht_s1 = 0x3;
+ p_cck_txrx->r_ccktx_enable = 0xC;
+ chgTx = 1;
+
+ /* From SD3 Willis suggestion !!! Set RF B as standby */
+ PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2);
+ PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2);
+
+ /* Disable Power save */
+ /* cosa r_ant_select_ofdm_val = 0x3321333; */
+ /* 2009/01/08 MH From Sd3 Willis. We need to enable RFA/B by SW control */
+ if (pHalData->rf_type == RF_2T2R) {
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0);
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0);
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1);
+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* r_rx_antenna_ofdm, bit0=A, bit1=B, bit2=C, bit3=D */
+ /* r_cckrx_enable : CCK default, 0=A, 1=B, 2=C, 3=D */
+ /* r_cckrx_enable_2 : CCK option, 0=A, 1=B, 2=C, 3=D */
+ switch (pAdapter->mppriv.antenna_rx) {
+ case ANTENNA_A:
+ r_rx_antenna_ofdm = 0x1; /* A */
+ p_cck_txrx->r_cckrx_enable = 0x0; /* default: A */
+ p_cck_txrx->r_cckrx_enable_2 = 0x0; /* option: A */
+ chgRx = 1;
+ break;
+ case ANTENNA_B:
+ r_rx_antenna_ofdm = 0x2; /* B */
+ p_cck_txrx->r_cckrx_enable = 0x1; /* default: B */
+ p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option: B */
+ chgRx = 1;
+ break;
+ case ANTENNA_AB:
+ r_rx_antenna_ofdm = 0x3; /* AB */
+ p_cck_txrx->r_cckrx_enable = 0x0; /* default:A */
+ p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option:B */
+ chgRx = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (chgTx && chgRx) {
+ switch (pHalData->rf_chip) {
+ case RF_8225:
+ case RF_8256:
+ case RF_6052:
+ /* r_ant_sel_cck_val = r_ant_select_cck_val; */
+ PHY_SetBBReg(pAdapter, rFPGA1_TxInfo, 0x7fffffff, r_ant_select_ofdm_val); /* OFDM Tx */
+ PHY_SetBBReg(pAdapter, rFPGA0_TxInfo, 0x0000000f, r_ofdm_tx_en_val); /* OFDM Tx */
+ PHY_SetBBReg(pAdapter, rOFDM0_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); /* OFDM Rx */
+ PHY_SetBBReg(pAdapter, rOFDM1_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); /* OFDM Rx */
+ PHY_SetBBReg(pAdapter, rCCK0_AFESetting, bMaskByte3, r_ant_select_cck_val); /* CCK TxRx */
+
+ break;
+ default:
+ break;
+ }
+ }
+
+ RT_TRACE(_module_mp_, _drv_notice_, ("-SwitchAntenna: finished\n"));
+}
+
+s32 Hal_SetThermalMeter(struct adapter *pAdapter, u8 target_ther)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+
+
+ if (!netif_running(pAdapter->pnetdev)) {
+ RT_TRACE(_module_mp_, _drv_warning_, ("SetThermalMeter! Fail: interface not opened!\n"));
+ return _FAIL;
+ }
+
+ if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == false) {
+ RT_TRACE(_module_mp_, _drv_warning_, ("SetThermalMeter: Fail! not in MP mode!\n"));
+ return _FAIL;
+ }
+
+ target_ther &= 0xff;
+ if (target_ther < 0x07)
+ target_ther = 0x07;
+ else if (target_ther > 0x1d)
+ target_ther = 0x1d;
+
+ pHalData->EEPROMThermalMeter = target_ther;
+
+ return _SUCCESS;
+}
+
+void Hal_TriggerRFThermalMeter(struct adapter *pAdapter)
+{
+ _write_rfreg(pAdapter, RF_PATH_A , RF_T_METER_88E , BIT17 | BIT16 , 0x03);
+}
+
+u8 Hal_ReadRFThermalMeter(struct adapter *pAdapter)
+{
+ u32 ThermalValue = 0;
+
+ ThermalValue = _read_rfreg(pAdapter, RF_PATH_A, RF_T_METER_88E, 0xfc00);
+ return (u8)ThermalValue;
+}
+
+void Hal_GetThermalMeter(struct adapter *pAdapter, u8 *value)
+{
+ Hal_TriggerRFThermalMeter(pAdapter);
+ rtw_msleep_os(1000);
+ *value = Hal_ReadRFThermalMeter(pAdapter);
+}
+
+void Hal_SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart)
+{
+ pAdapter->mppriv.MptCtx.bSingleCarrier = bStart;
+ if (bStart) {
+ /* Start Single Carrier. */
+ RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleCarrierTx: test start\n"));
+ /* 1. if OFDM block on? */
+ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn))
+ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);/* set OFDM block on */
+
+ /* 2. set CCK test mode off, set to CCK normal mode */
+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable);
+ /* 3. turn on scramble setting */
+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable);
+ /* 4. Turn On Single Carrier Tx and turn off the other test modes. */
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bEnable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+ /* for dynamic set Power index. */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
+ } else {
+ /* Stop Single Carrier. */
+ RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleCarrierTx: test stop\n"));
+
+ /* Turn off all test modes. */
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+ rtw_msleep_os(10);
+
+ /* BB Reset */
+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
+
+ /* Stop for dynamic set Power index. */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
+ }
+}
+
+
+void Hal_SetSingleToneTx(struct adapter *pAdapter, u8 bStart)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+ bool is92C = IS_92C_SERIAL(pHalData->VersionID);
+
+ u8 rfPath;
+ u32 reg58 = 0x0;
+ switch (pAdapter->mppriv.antenna_tx) {
+ case ANTENNA_A:
+ default:
+ rfPath = RF_PATH_A;
+ break;
+ case ANTENNA_B:
+ rfPath = RF_PATH_B;
+ break;
+ case ANTENNA_C:
+ rfPath = RF_PATH_C;
+ break;
+ }
+
+ pAdapter->mppriv.MptCtx.bSingleTone = bStart;
+ if (bStart) {
+ /* Start Single Tone. */
+ RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleToneTx: test start\n"));
+ /* <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) */
+ if (IS_HARDWARE_TYPE_8188E(pAdapter)) {
+ reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask);
+ reg58 &= 0xFFFFFFF0;
+ reg58 += 2;
+ PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58);
+ }
+ PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x0);
+ PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x0);
+
+ if (is92C) {
+ _write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT19, 0x01);
+ rtw_usleep_os(100);
+ if (rfPath == RF_PATH_A)
+ write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x10000); /* PAD all on. */
+ else if (rfPath == RF_PATH_B)
+ write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x10000); /* PAD all on. */
+ write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); /* PAD all on. */
+ rtw_usleep_os(100);
+ } else {
+ write_rfreg(pAdapter, rfPath, 0x21, 0xd4000);
+ rtw_usleep_os(100);
+ write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); /* PAD all on. */
+ rtw_usleep_os(100);
+ }
+
+ /* for dynamic set Power index. */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
+
+ } else {
+ /* Stop Single Tone. */
+ RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleToneTx: test stop\n"));
+
+ /* <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) */
+ /* <20120326, Kordan> Only in single tone mode. (asked by Edlu) */
+ if (IS_HARDWARE_TYPE_8188E(pAdapter)) {
+ reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask);
+ reg58 &= 0xFFFFFFF0;
+ PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58);
+ }
+ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x1);
+ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x1);
+ if (is92C) {
+ _write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT19, 0x00);
+ rtw_usleep_os(100);
+ write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x32d75); /* PAD all on. */
+ write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x32d75); /* PAD all on. */
+ rtw_usleep_os(100);
+ } else {
+ write_rfreg(pAdapter, rfPath, 0x21, 0x54000);
+ rtw_usleep_os(100);
+ write_rfreg(pAdapter, rfPath, 0x00, 0x30000); /* PAD all on. */
+ rtw_usleep_os(100);
+ }
+
+ /* Stop for dynamic set Power index. */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
+ }
+}
+
+
+
+void Hal_SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart)
+{
+ pAdapter->mppriv.MptCtx.bCarrierSuppression = bStart;
+ if (bStart) {
+ /* Start Carrier Suppression. */
+ RT_TRACE(_module_mp_, _drv_alert_, ("SetCarrierSuppressionTx: test start\n"));
+ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) {
+ /* 1. if CCK block on? */
+ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn))
+ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/* set CCK block on */
+
+ /* Turn Off All Test Mode */
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+
+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); /* transmit mode */
+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x0); /* turn off scramble setting */
+
+ /* Set CCK Tx Test Rate */
+ write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, 0x0); /* Set FTxRate to 1Mbps */
+ }
+
+ /* for dynamic set Power index. */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
+ } else {
+ /* Stop Carrier Suppression. */
+ RT_TRACE(_module_mp_, _drv_alert_, ("SetCarrierSuppressionTx: test stop\n"));
+ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) {
+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); /* normal mode */
+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x1); /* turn on scramble setting */
+
+ /* BB Reset */
+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
+ }
+
+ /* Stop for dynamic set Power index. */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
+ }
+}
+
+void Hal_SetCCKContinuousTx(struct adapter *pAdapter, u8 bStart)
+{
+ u32 cckrate;
+
+ if (bStart) {
+ RT_TRACE(_module_mp_, _drv_alert_,
+ ("SetCCKContinuousTx: test start\n"));
+
+ /* 1. if CCK block on? */
+ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn))
+ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/* set CCK block on */
+
+ /* Turn Off All Test Mode */
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+ /* Set CCK Tx Test Rate */
+ cckrate = pAdapter->mppriv.rateidx;
+ write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, cckrate);
+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); /* transmit mode */
+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); /* turn on scramble setting */
+
+ /* for dynamic set Power index. */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
+ } else {
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("SetCCKContinuousTx: test stop\n"));
+
+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); /* normal mode */
+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); /* turn on scramble setting */
+
+ /* BB Reset */
+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
+
+ /* Stop for dynamic set Power index. */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
+ }
+
+ pAdapter->mppriv.MptCtx.bCckContTx = bStart;
+ pAdapter->mppriv.MptCtx.bOfdmContTx = false;
+} /* mpt_StartCckContTx */
+
+void Hal_SetOFDMContinuousTx(struct adapter *pAdapter, u8 bStart)
+{
+ if (bStart) {
+ RT_TRACE(_module_mp_, _drv_info_, ("SetOFDMContinuousTx: test start\n"));
+ /* 1. if OFDM block on? */
+ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn))
+ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);/* set OFDM block on */
+
+ /* 2. set CCK test mode off, set to CCK normal mode */
+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable);
+
+ /* 3. turn on scramble setting */
+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable);
+ /* 4. Turn On Continue Tx and turn off the other test modes. */
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bEnable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+
+ /* for dynamic set Power index. */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
+
+ } else {
+ RT_TRACE(_module_mp_, _drv_info_, ("SetOFDMContinuousTx: test stop\n"));
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+ /* Delay 10 ms */
+ rtw_msleep_os(10);
+ /* BB Reset */
+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
+
+ /* Stop for dynamic set Power index. */
+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
+ }
+
+ pAdapter->mppriv.MptCtx.bCckContTx = false;
+ pAdapter->mppriv.MptCtx.bOfdmContTx = bStart;
+} /* mpt_StartOfdmContTx */
+
+void Hal_SetContinuousTx(struct adapter *pAdapter, u8 bStart)
+{
+ RT_TRACE(_module_mp_, _drv_info_,
+ ("SetContinuousTx: rate:%d\n", pAdapter->mppriv.rateidx));
+
+ pAdapter->mppriv.MptCtx.bStartContTx = bStart;
+ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M)
+ Hal_SetCCKContinuousTx(pAdapter, bStart);
+ else if ((pAdapter->mppriv.rateidx >= MPT_RATE_6M) &&
+ (pAdapter->mppriv.rateidx <= MPT_RATE_MCS15))
+ Hal_SetOFDMContinuousTx(pAdapter, bStart);
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c b/drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c
new file mode 100644
index 00000000000..ff468a68e32
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c
@@ -0,0 +1,1144 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_PHYCFG_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_iol.h>
+#include <rtl8188e_hal.h>
+
+/*---------------------------Define Local Constant---------------------------*/
+/* Channel switch:The size of command tables for switch channel*/
+#define MAX_PRECMD_CNT 16
+#define MAX_RFDEPENDCMD_CNT 16
+#define MAX_POSTCMD_CNT 16
+
+#define MAX_DOZE_WAITING_TIMES_9x 64
+
+/*---------------------------Define Local Constant---------------------------*/
+
+
+/*------------------------Define global variable-----------------------------*/
+
+/*------------------------Define local variable------------------------------*/
+
+
+/*--------------------Define export function prototype-----------------------*/
+/* Please refer to header file */
+/*--------------------Define export function prototype-----------------------*/
+
+/*----------------------------Function Body----------------------------------*/
+/* */
+/* 1. BB register R/W API */
+/* */
+
+/**
+* Function: phy_CalculateBitShift
+*
+* OverView: Get shifted position of the BitMask
+*
+* Input:
+* u32 BitMask,
+*
+* Output: none
+* Return: u32 Return the shift bit bit position of the mask
+*/
+static u32 phy_CalculateBitShift(u32 BitMask)
+{
+ u32 i;
+
+ for (i = 0; i <= 31; i++) {
+ if (((BitMask>>i) & 0x1) == 1)
+ break;
+ }
+ return i;
+}
+
+/**
+* Function: PHY_QueryBBReg
+*
+* OverView: Read "sepcific bits" from BB register
+*
+* Input:
+* struct adapter *Adapter,
+* u32 RegAddr, The target address to be readback
+* u32 BitMask The target bit position in the target address
+* to be readback
+* Output: None
+* Return: u32 Data The readback register value
+* Note: This function is equal to "GetRegSetting" in PHY programming guide
+*/
+u32
+rtl8188e_PHY_QueryBBReg(
+ struct adapter *Adapter,
+ u32 RegAddr,
+ u32 BitMask
+ )
+{
+ u32 ReturnValue = 0, OriginalValue, BitShift;
+
+ OriginalValue = rtw_read32(Adapter, RegAddr);
+ BitShift = phy_CalculateBitShift(BitMask);
+ ReturnValue = (OriginalValue & BitMask) >> BitShift;
+ return ReturnValue;
+}
+
+
+/**
+* Function: PHY_SetBBReg
+*
+* OverView: Write "Specific bits" to BB register (page 8~)
+*
+* Input:
+* struct adapter *Adapter,
+* u32 RegAddr, The target address to be modified
+* u32 BitMask The target bit position in the target address
+* to be modified
+* u32 Data The new register value in the target bit position
+* of the target address
+*
+* Output: None
+* Return: None
+* Note: This function is equal to "PutRegSetting" in PHY programming guide
+*/
+
+void rtl8188e_PHY_SetBBReg(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data)
+{
+ u32 OriginalValue, BitShift;
+
+ if (BitMask != bMaskDWord) { /* if not "double word" write */
+ OriginalValue = rtw_read32(Adapter, RegAddr);
+ BitShift = phy_CalculateBitShift(BitMask);
+ Data = ((OriginalValue & (~BitMask)) | (Data << BitShift));
+ }
+
+ rtw_write32(Adapter, RegAddr, Data);
+}
+
+
+/* */
+/* 2. RF register R/W API */
+/* */
+/**
+* Function: phy_RFSerialRead
+*
+* OverView: Read regster from RF chips
+*
+* Input:
+* struct adapter *Adapter,
+* enum rf_radio_path eRFPath, Radio path of A/B/C/D
+* u32 Offset, The target address to be read
+*
+* Output: None
+* Return: u32 reback value
+* Note: Threre are three types of serial operations:
+* 1. Software serial write
+* 2. Hardware LSSI-Low Speed Serial Interface
+* 3. Hardware HSSI-High speed
+* serial write. Driver need to implement (1) and (2).
+* This function is equal to the combination of RF_ReadReg() and RFLSSIRead()
+*/
+static u32
+phy_RFSerialRead(
+ struct adapter *Adapter,
+ enum rf_radio_path eRFPath,
+ u32 Offset
+ )
+{
+ u32 retValue = 0;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ struct bb_reg_def *pPhyReg = &pHalData->PHYRegDef[eRFPath];
+ u32 NewOffset;
+ u32 tmplong, tmplong2;
+ u8 RfPiEnable = 0;
+ /* */
+ /* Make sure RF register offset is correct */
+ /* */
+ Offset &= 0xff;
+
+ /* */
+ /* Switch page for 8256 RF IC */
+ /* */
+ NewOffset = Offset;
+
+ /* For 92S LSSI Read RFLSSIRead */
+ /* For RF A/B write 0x824/82c(does not work in the future) */
+ /* We must use 0x824 for RF A and B to execute read trigger */
+ tmplong = PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord);
+ if (eRFPath == RF_PATH_A)
+ tmplong2 = tmplong;
+ else
+ tmplong2 = PHY_QueryBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord);
+
+ tmplong2 = (tmplong2 & (~bLSSIReadAddress)) | (NewOffset<<23) | bLSSIReadEdge; /* T65 RF */
+
+ PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord, tmplong&(~bLSSIReadEdge));
+ rtw_udelay_os(10);/* PlatformStallExecution(10); */
+
+ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord, tmplong2);
+ rtw_udelay_os(100);/* PlatformStallExecution(100); */
+
+ rtw_udelay_os(10);/* PlatformStallExecution(10); */
+
+ if (eRFPath == RF_PATH_A)
+ RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter1, BIT8);
+ else if (eRFPath == RF_PATH_B)
+ RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XB_HSSIParameter1, BIT8);
+
+ if (RfPiEnable) { /* Read from BBreg8b8, 12 bits for 8190, 20bits for T65 RF */
+ retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBackPi, bLSSIReadBackData);
+ } else { /* Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF */
+ retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBack, bLSSIReadBackData);
+ }
+ return retValue;
+}
+
+/**
+* Function: phy_RFSerialWrite
+*
+* OverView: Write data to RF register (page 8~)
+*
+* Input:
+* struct adapter *Adapter,
+* enum rf_radio_path eRFPath, Radio path of A/B/C/D
+* u32 Offset, The target address to be read
+* u32 Data The new register Data in the target bit position
+* of the target to be read
+*
+* Output: None
+* Return: None
+* Note: Threre are three types of serial operations:
+* 1. Software serial write
+* 2. Hardware LSSI-Low Speed Serial Interface
+* 3. Hardware HSSI-High speed
+* serial write. Driver need to implement (1) and (2).
+* This function is equal to the combination of RF_ReadReg() and RFLSSIRead()
+ *
+ * Note: For RF8256 only
+ * The total count of RTL8256(Zebra4) register is around 36 bit it only employs
+ * 4-bit RF address. RTL8256 uses "register mode control bit" (Reg00[12], Reg00[10])
+ * to access register address bigger than 0xf. See "Appendix-4 in PHY Configuration
+ * programming guide" for more details.
+ * Thus, we define a sub-finction for RTL8526 register address conversion
+ * ===========================================================
+ * Register Mode RegCTL[1] RegCTL[0] Note
+ * (Reg00[12]) (Reg00[10])
+ * ===========================================================
+ * Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf)
+ * ------------------------------------------------------------------
+ * Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf)
+ * ------------------------------------------------------------------
+ * Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf)
+ * ------------------------------------------------------------------
+ *
+ * 2008/09/02 MH Add 92S RF definition
+ *
+ *
+ *
+*/
+static void
+phy_RFSerialWrite(
+ struct adapter *Adapter,
+ enum rf_radio_path eRFPath,
+ u32 Offset,
+ u32 Data
+ )
+{
+ u32 DataAndAddr = 0;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ struct bb_reg_def *pPhyReg = &pHalData->PHYRegDef[eRFPath];
+ u32 NewOffset;
+
+
+ /* 2009/06/17 MH We can not execute IO for power save or other accident mode. */
+
+ Offset &= 0xff;
+
+ /* */
+ /* Switch page for 8256 RF IC */
+ /* */
+ NewOffset = Offset;
+
+ /* */
+ /* Put write addr in [5:0] and write data in [31:16] */
+ /* */
+ DataAndAddr = ((NewOffset<<20) | (Data&0x000fffff)) & 0x0fffffff; /* T65 RF */
+
+ /* */
+ /* Write Operation */
+ /* */
+ PHY_SetBBReg(Adapter, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr);
+}
+
+/**
+* Function: PHY_QueryRFReg
+*
+* OverView: Query "Specific bits" to RF register (page 8~)
+*
+* Input:
+* struct adapter *Adapter,
+* enum rf_radio_path eRFPath, Radio path of A/B/C/D
+* u32 RegAddr, The target address to be read
+* u32 BitMask The target bit position in the target address
+* to be read
+*
+* Output: None
+* Return: u32 Readback value
+* Note: This function is equal to "GetRFRegSetting" in PHY programming guide
+*/
+u32 rtl8188e_PHY_QueryRFReg(struct adapter *Adapter, enum rf_radio_path eRFPath,
+ u32 RegAddr, u32 BitMask)
+{
+ u32 Original_Value, Readback_Value, BitShift;
+
+ Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr);
+
+ BitShift = phy_CalculateBitShift(BitMask);
+ Readback_Value = (Original_Value & BitMask) >> BitShift;
+ return Readback_Value;
+}
+
+/**
+* Function: PHY_SetRFReg
+*
+* OverView: Write "Specific bits" to RF register (page 8~)
+*
+* Input:
+* struct adapter *Adapter,
+* enum rf_radio_path eRFPath, Radio path of A/B/C/D
+* u32 RegAddr, The target address to be modified
+* u32 BitMask The target bit position in the target address
+* to be modified
+* u32 Data The new register Data in the target bit position
+* of the target address
+*
+* Output: None
+* Return: None
+* Note: This function is equal to "PutRFRegSetting" in PHY programming guide
+*/
+void
+rtl8188e_PHY_SetRFReg(
+ struct adapter *Adapter,
+ enum rf_radio_path eRFPath,
+ u32 RegAddr,
+ u32 BitMask,
+ u32 Data
+ )
+{
+ u32 Original_Value, BitShift;
+
+ /* RF data is 12 bits only */
+ if (BitMask != bRFRegOffsetMask) {
+ Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr);
+ BitShift = phy_CalculateBitShift(BitMask);
+ Data = ((Original_Value & (~BitMask)) | (Data << BitShift));
+ }
+
+ phy_RFSerialWrite(Adapter, eRFPath, RegAddr, Data);
+}
+
+/* */
+/* 3. Initial MAC/BB/RF config by reading MAC/BB/RF txt. */
+/* */
+
+/*-----------------------------------------------------------------------------
+ * Function: PHY_MACConfig8192C
+ *
+ * Overview: Condig MAC by header file or parameter file.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 08/12/2008 MHC Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+s32 PHY_MACConfig8188E(struct adapter *Adapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ int rtStatus = _SUCCESS;
+
+ /* */
+ /* Config MAC */
+ /* */
+ if (HAL_STATUS_FAILURE == ODM_ConfigMACWithHeaderFile(&pHalData->odmpriv))
+ rtStatus = _FAIL;
+
+ /* 2010.07.13 AMPDU aggregation number B */
+ rtw_write16(Adapter, REG_MAX_AGGR_NUM, MAX_AGGR_NUM);
+
+ return rtStatus;
+}
+
+/**
+* Function: phy_InitBBRFRegisterDefinition
+*
+* OverView: Initialize Register definition offset for Radio Path A/B/C/D
+*
+* Input:
+* struct adapter *Adapter,
+*
+* Output: None
+* Return: None
+* Note: The initialization value is constant and it should never be changes
+*/
+static void
+phy_InitBBRFRegisterDefinition(
+ struct adapter *Adapter
+)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+
+ /* RF Interface Sowrtware Control */
+ pHalData->PHYRegDef[RF_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 LSBs if read 32-bit from 0x870 */
+ pHalData->PHYRegDef[RF_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */
+ pHalData->PHYRegDef[RF_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;/* 16 LSBs if read 32-bit from 0x874 */
+ pHalData->PHYRegDef[RF_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;/* 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) */
+
+ /* RF Interface Readback Value */
+ pHalData->PHYRegDef[RF_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; /* 16 LSBs if read 32-bit from 0x8E0 */
+ pHalData->PHYRegDef[RF_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;/* 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) */
+ pHalData->PHYRegDef[RF_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;/* 16 LSBs if read 32-bit from 0x8E4 */
+ pHalData->PHYRegDef[RF_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;/* 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) */
+
+ /* RF Interface Output (and Enable) */
+ pHalData->PHYRegDef[RF_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; /* 16 LSBs if read 32-bit from 0x860 */
+ pHalData->PHYRegDef[RF_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; /* 16 LSBs if read 32-bit from 0x864 */
+
+ /* RF Interface (Output and) Enable */
+ pHalData->PHYRegDef[RF_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; /* 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) */
+ pHalData->PHYRegDef[RF_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; /* 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) */
+
+ /* Addr of LSSI. Wirte RF register by driver */
+ pHalData->PHYRegDef[RF_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; /* LSSI Parameter */
+ pHalData->PHYRegDef[RF_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
+
+ /* RF parameter */
+ pHalData->PHYRegDef[RF_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; /* BB Band Select */
+ pHalData->PHYRegDef[RF_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter;
+ pHalData->PHYRegDef[RF_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter;
+ pHalData->PHYRegDef[RF_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter;
+
+ /* Tx AGC Gain Stage (same for all path. Should we remove this?) */
+ pHalData->PHYRegDef[RF_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
+ pHalData->PHYRegDef[RF_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
+ pHalData->PHYRegDef[RF_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
+ pHalData->PHYRegDef[RF_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
+
+ /* Tranceiver A~D HSSI Parameter-1 */
+ pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; /* wire control parameter1 */
+ pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; /* wire control parameter1 */
+
+ /* Tranceiver A~D HSSI Parameter-2 */
+ pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; /* wire control parameter2 */
+ pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; /* wire control parameter2 */
+
+ /* RF switch Control */
+ pHalData->PHYRegDef[RF_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; /* TR/Ant switch control */
+ pHalData->PHYRegDef[RF_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl;
+ pHalData->PHYRegDef[RF_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl;
+ pHalData->PHYRegDef[RF_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl;
+
+ /* AGC control 1 */
+ pHalData->PHYRegDef[RF_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1;
+ pHalData->PHYRegDef[RF_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1;
+ pHalData->PHYRegDef[RF_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1;
+ pHalData->PHYRegDef[RF_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1;
+
+ /* AGC control 2 */
+ pHalData->PHYRegDef[RF_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2;
+ pHalData->PHYRegDef[RF_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2;
+ pHalData->PHYRegDef[RF_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2;
+ pHalData->PHYRegDef[RF_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2;
+
+ /* RX AFE control 1 */
+ pHalData->PHYRegDef[RF_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance;
+ pHalData->PHYRegDef[RF_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance;
+ pHalData->PHYRegDef[RF_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance;
+ pHalData->PHYRegDef[RF_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance;
+
+ /* RX AFE control 1 */
+ pHalData->PHYRegDef[RF_PATH_A].rfRxAFE = rOFDM0_XARxAFE;
+ pHalData->PHYRegDef[RF_PATH_B].rfRxAFE = rOFDM0_XBRxAFE;
+ pHalData->PHYRegDef[RF_PATH_C].rfRxAFE = rOFDM0_XCRxAFE;
+ pHalData->PHYRegDef[RF_PATH_D].rfRxAFE = rOFDM0_XDRxAFE;
+
+ /* Tx AFE control 1 */
+ pHalData->PHYRegDef[RF_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance;
+ pHalData->PHYRegDef[RF_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance;
+ pHalData->PHYRegDef[RF_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance;
+ pHalData->PHYRegDef[RF_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance;
+
+ /* Tx AFE control 2 */
+ pHalData->PHYRegDef[RF_PATH_A].rfTxAFE = rOFDM0_XATxAFE;
+ pHalData->PHYRegDef[RF_PATH_B].rfTxAFE = rOFDM0_XBTxAFE;
+ pHalData->PHYRegDef[RF_PATH_C].rfTxAFE = rOFDM0_XCTxAFE;
+ pHalData->PHYRegDef[RF_PATH_D].rfTxAFE = rOFDM0_XDTxAFE;
+
+ /* Tranceiver LSSI Readback SI mode */
+ pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack;
+ pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack;
+ pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack;
+ pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack;
+
+ /* Tranceiver LSSI Readback PI mode */
+ pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback;
+ pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback;
+}
+
+void storePwrIndexDiffRateOffset(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+
+ if (RegAddr == rTxAGC_A_Rate18_06)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0] = Data;
+ if (RegAddr == rTxAGC_A_Rate54_24)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][1] = Data;
+ if (RegAddr == rTxAGC_A_CCK1_Mcs32)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][6] = Data;
+ if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0xffffff00)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][7] = Data;
+ if (RegAddr == rTxAGC_A_Mcs03_Mcs00)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][2] = Data;
+ if (RegAddr == rTxAGC_A_Mcs07_Mcs04)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][3] = Data;
+ if (RegAddr == rTxAGC_A_Mcs11_Mcs08)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][4] = Data;
+ if (RegAddr == rTxAGC_A_Mcs15_Mcs12) {
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][5] = Data;
+ if (pHalData->rf_type == RF_1T1R)
+ pHalData->pwrGroupCnt++;
+ }
+ if (RegAddr == rTxAGC_B_Rate18_06)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][8] = Data;
+ if (RegAddr == rTxAGC_B_Rate54_24)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][9] = Data;
+ if (RegAddr == rTxAGC_B_CCK1_55_Mcs32)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][14] = Data;
+ if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0x000000ff)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][15] = Data;
+ if (RegAddr == rTxAGC_B_Mcs03_Mcs00)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][10] = Data;
+ if (RegAddr == rTxAGC_B_Mcs07_Mcs04)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][11] = Data;
+ if (RegAddr == rTxAGC_B_Mcs11_Mcs08)
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][12] = Data;
+ if (RegAddr == rTxAGC_B_Mcs15_Mcs12) {
+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][13] = Data;
+ if (pHalData->rf_type != RF_1T1R)
+ pHalData->pwrGroupCnt++;
+ }
+}
+
+static int phy_BB8188E_Config_ParaFile(struct adapter *Adapter)
+{
+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter);
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ int rtStatus = _SUCCESS;
+
+ /* */
+ /* 1. Read PHY_REG.TXT BB INIT!! */
+ /* We will seperate as 88C / 92C according to chip version */
+ /* */
+ if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG))
+ rtStatus = _FAIL;
+ if (rtStatus != _SUCCESS)
+ goto phy_BB8190_Config_ParaFile_Fail;
+
+ /* 2. If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt */
+ if (!pEEPROM->bautoload_fail_flag) {
+ pHalData->pwrGroupCnt = 0;
+
+ if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG_PG))
+ rtStatus = _FAIL;
+ }
+
+ if (rtStatus != _SUCCESS)
+ goto phy_BB8190_Config_ParaFile_Fail;
+
+ /* 3. BB AGC table Initialization */
+ if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_AGC_TAB))
+ rtStatus = _FAIL;
+
+ if (rtStatus != _SUCCESS)
+ goto phy_BB8190_Config_ParaFile_Fail;
+
+phy_BB8190_Config_ParaFile_Fail:
+
+ return rtStatus;
+}
+
+int
+PHY_BBConfig8188E(
+ struct adapter *Adapter
+ )
+{
+ int rtStatus = _SUCCESS;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u32 RegVal;
+ u8 CrystalCap;
+
+ phy_InitBBRFRegisterDefinition(Adapter);
+
+
+ /* Enable BB and RF */
+ RegVal = rtw_read16(Adapter, REG_SYS_FUNC_EN);
+ rtw_write16(Adapter, REG_SYS_FUNC_EN, (u16)(RegVal|BIT13|BIT0|BIT1));
+
+ /* 20090923 Joseph: Advised by Steven and Jenyu. Power sequence before init RF. */
+
+ rtw_write8(Adapter, REG_RF_CTRL, RF_EN|RF_RSTB|RF_SDMRSTB);
+
+ rtw_write8(Adapter, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | FEN_BB_GLB_RSTn | FEN_BBRSTB);
+
+ /* Config BB and AGC */
+ rtStatus = phy_BB8188E_Config_ParaFile(Adapter);
+
+ /* write 0x24[16:11] = 0x24[22:17] = CrystalCap */
+ CrystalCap = pHalData->CrystalCap & 0x3F;
+ PHY_SetBBReg(Adapter, REG_AFE_XTAL_CTRL, 0x7ff800, (CrystalCap | (CrystalCap << 6)));
+
+ return rtStatus;
+}
+
+int PHY_RFConfig8188E(struct adapter *Adapter)
+{
+ int rtStatus = _SUCCESS;
+
+ /* RF config */
+ rtStatus = PHY_RF6052_Config8188E(Adapter);
+ return rtStatus;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Function: PHY_ConfigRFWithParaFile()
+ *
+ * Overview: This function read RF parameters from general file format, and do RF 3-wire
+ *
+ * Input: struct adapter *Adapter
+ * ps8 pFileName
+ * enum rf_radio_path eRFPath
+ *
+ * Output: NONE
+ *
+ * Return: RT_STATUS_SUCCESS: configuration file exist
+ *
+ * Note: Delay may be required for RF configuration
+ *---------------------------------------------------------------------------*/
+int rtl8188e_PHY_ConfigRFWithParaFile(struct adapter *Adapter, u8 *pFileName, enum rf_radio_path eRFPath)
+{
+ return _SUCCESS;
+}
+
+void
+rtl8192c_PHY_GetHWRegOriginalValue(
+ struct adapter *Adapter
+ )
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+
+ /* read rx initial gain */
+ pHalData->DefaultInitialGain[0] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XAAGCCore1, bMaskByte0);
+ pHalData->DefaultInitialGain[1] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XBAGCCore1, bMaskByte0);
+ pHalData->DefaultInitialGain[2] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XCAGCCore1, bMaskByte0);
+ pHalData->DefaultInitialGain[3] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XDAGCCore1, bMaskByte0);
+
+ /* read framesync */
+ pHalData->framesync = (u8)PHY_QueryBBReg(Adapter, rOFDM0_RxDetector3, bMaskByte0);
+ pHalData->framesyncC34 = PHY_QueryBBReg(Adapter, rOFDM0_RxDetector2, bMaskDWord);
+}
+
+/* */
+/* Description: */
+/* Map dBm into Tx power index according to */
+/* current HW model, for example, RF and PA, and */
+/* current wireless mode. */
+/* By Bruce, 2008-01-29. */
+/* */
+static u8 phy_DbmToTxPwrIdx(struct adapter *Adapter, enum wireless_mode WirelessMode, int PowerInDbm)
+{
+ u8 TxPwrIdx = 0;
+ int Offset = 0;
+
+
+ /* */
+ /* Tested by MP, we found that CCK Index 0 equals to 8dbm, OFDM legacy equals to */
+ /* 3dbm, and OFDM HT equals to 0dbm repectively. */
+ /* Note: */
+ /* The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */
+ /* By Bruce, 2008-01-29. */
+ /* */
+ switch (WirelessMode) {
+ case WIRELESS_MODE_B:
+ Offset = -7;
+ break;
+
+ case WIRELESS_MODE_G:
+ case WIRELESS_MODE_N_24G:
+ default:
+ Offset = -8;
+ break;
+ }
+
+ if ((PowerInDbm - Offset) > 0)
+ TxPwrIdx = (u8)((PowerInDbm - Offset) * 2);
+ else
+ TxPwrIdx = 0;
+
+ /* Tx Power Index is too large. */
+ if (TxPwrIdx > MAX_TXPWR_IDX_NMODE_92S)
+ TxPwrIdx = MAX_TXPWR_IDX_NMODE_92S;
+
+ return TxPwrIdx;
+}
+
+/* */
+/* Description: */
+/* Map Tx power index into dBm according to */
+/* current HW model, for example, RF and PA, and */
+/* current wireless mode. */
+/* By Bruce, 2008-01-29. */
+/* */
+static int phy_TxPwrIdxToDbm(struct adapter *Adapter, enum wireless_mode WirelessMode, u8 TxPwrIdx)
+{
+ int Offset = 0;
+ int PwrOutDbm = 0;
+
+ /* */
+ /* Tested by MP, we found that CCK Index 0 equals to -7dbm, OFDM legacy equals to -8dbm. */
+ /* Note: */
+ /* The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */
+ /* By Bruce, 2008-01-29. */
+ /* */
+ switch (WirelessMode) {
+ case WIRELESS_MODE_B:
+ Offset = -7;
+ break;
+ case WIRELESS_MODE_G:
+ case WIRELESS_MODE_N_24G:
+ default:
+ Offset = -8;
+ break;
+ }
+
+ PwrOutDbm = TxPwrIdx / 2 + Offset; /* Discard the decimal part. */
+
+ return PwrOutDbm;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Function: GetTxPowerLevel8190()
+ *
+ * Overview: This function is export to "common" moudule
+ *
+ * Input: struct adapter *Adapter
+ * psByte Power Level
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ *---------------------------------------------------------------------------*/
+void PHY_GetTxPowerLevel8188E(struct adapter *Adapter, u32 *powerlevel)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u8 TxPwrLevel = 0;
+ int TxPwrDbm;
+
+ /* */
+ /* Because the Tx power indexes are different, we report the maximum of them to */
+ /* meet the CCX TPC request. By Bruce, 2008-01-31. */
+ /* */
+
+ /* CCK */
+ TxPwrLevel = pHalData->CurrentCckTxPwrIdx;
+ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_B, TxPwrLevel);
+
+ /* Legacy OFDM */
+ TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx + pHalData->LegacyHTTxPowerDiff;
+
+ /* Compare with Legacy OFDM Tx power. */
+ if (phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel) > TxPwrDbm)
+ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel);
+
+ /* HT OFDM */
+ TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx;
+
+ /* Compare with HT OFDM Tx power. */
+ if (phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel) > TxPwrDbm)
+ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel);
+
+ *powerlevel = TxPwrDbm;
+}
+
+static void getTxPowerIndex88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel,
+ u8 *ofdmPowerLevel, u8 *BW20PowerLevel,
+ u8 *BW40PowerLevel)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u8 index = (channel - 1);
+ u8 TxCount = 0, path_nums;
+
+ if ((RF_1T2R == pHalData->rf_type) || (RF_1T1R == pHalData->rf_type))
+ path_nums = 1;
+ else
+ path_nums = 2;
+
+ for (TxCount = 0; TxCount < path_nums; TxCount++) {
+ if (TxCount == RF_PATH_A) {
+ /* 1. CCK */
+ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index];
+ /* 2. OFDM */
+ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+ pHalData->OFDM_24G_Diff[TxCount][RF_PATH_A];
+ /* 1. BW20 */
+ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[TxCount][RF_PATH_A];
+ /* 2. BW40 */
+ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index];
+ } else if (TxCount == RF_PATH_B) {
+ /* 1. CCK */
+ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index];
+ /* 2. OFDM */
+ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[TxCount][index];
+ /* 1. BW20 */
+ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[TxCount][RF_PATH_A]+
+ pHalData->BW20_24G_Diff[TxCount][index];
+ /* 2. BW40 */
+ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index];
+ } else if (TxCount == RF_PATH_C) {
+ /* 1. CCK */
+ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index];
+ /* 2. OFDM */
+ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_B][index]+
+ pHalData->BW20_24G_Diff[TxCount][index];
+ /* 1. BW20 */
+ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_B][index]+
+ pHalData->BW20_24G_Diff[TxCount][index];
+ /* 2. BW40 */
+ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index];
+ } else if (TxCount == RF_PATH_D) {
+ /* 1. CCK */
+ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index];
+ /* 2. OFDM */
+ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_B][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_C][index]+
+ pHalData->BW20_24G_Diff[TxCount][index];
+
+ /* 1. BW20 */
+ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_A][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_B][index]+
+ pHalData->BW20_24G_Diff[RF_PATH_C][index]+
+ pHalData->BW20_24G_Diff[TxCount][index];
+
+ /* 2. BW40 */
+ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index];
+ }
+ }
+}
+
+static void phy_PowerIndexCheck88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel,
+ u8 *ofdmPowerLevel, u8 *BW20PowerLevel, u8 *BW40PowerLevel)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+
+ pHalData->CurrentCckTxPwrIdx = cckPowerLevel[0];
+ pHalData->CurrentOfdm24GTxPwrIdx = ofdmPowerLevel[0];
+ pHalData->CurrentBW2024GTxPwrIdx = BW20PowerLevel[0];
+ pHalData->CurrentBW4024GTxPwrIdx = BW40PowerLevel[0];
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: SetTxPowerLevel8190()
+ *
+ * Overview: This function is export to "HalCommon" moudule
+ * We must consider RF path later!!!!!!!
+ *
+ * Input: struct adapter *Adapter
+ * u8 channel
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ * 2008/11/04 MHC We remove EEPROM_93C56.
+ * We need to move CCX relative code to independet file.
+ * 2009/01/21 MHC Support new EEPROM format from SD3 requirement.
+ *
+ *---------------------------------------------------------------------------*/
+void
+PHY_SetTxPowerLevel8188E(
+ struct adapter *Adapter,
+ u8 channel
+ )
+{
+ u8 cckPowerLevel[MAX_TX_COUNT] = {0};
+ u8 ofdmPowerLevel[MAX_TX_COUNT] = {0};/* [0]:RF-A, [1]:RF-B */
+ u8 BW20PowerLevel[MAX_TX_COUNT] = {0};
+ u8 BW40PowerLevel[MAX_TX_COUNT] = {0};
+
+ getTxPowerIndex88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0]);
+
+ phy_PowerIndexCheck88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0]);
+
+ rtl8188e_PHY_RF6052SetCckTxPower(Adapter, &cckPowerLevel[0]);
+ rtl8188e_PHY_RF6052SetOFDMTxPower(Adapter, &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0], channel);
+}
+
+/* */
+/* Description: */
+/* Update transmit power level of all channel supported. */
+/* */
+/* TODO: */
+/* A mode. */
+/* By Bruce, 2008-02-04. */
+/* */
+bool
+PHY_UpdateTxPowerDbm8188E(
+ struct adapter *Adapter,
+ int powerInDbm
+ )
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u8 idx;
+ u8 rf_path;
+
+ /* TODO: A mode Tx power. */
+ u8 CckTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_B, powerInDbm);
+ u8 OfdmTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_N_24G, powerInDbm);
+
+ if (OfdmTxPwrIdx - pHalData->LegacyHTTxPowerDiff > 0)
+ OfdmTxPwrIdx -= pHalData->LegacyHTTxPowerDiff;
+ else
+ OfdmTxPwrIdx = 0;
+
+ for (idx = 0; idx < 14; idx++) {
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ pHalData->TxPwrLevelCck[rf_path][idx] = CckTxPwrIdx;
+ pHalData->TxPwrLevelHT40_1S[rf_path][idx] =
+ pHalData->TxPwrLevelHT40_2S[rf_path][idx] = OfdmTxPwrIdx;
+ }
+ }
+ return true;
+}
+
+void
+PHY_ScanOperationBackup8188E(
+ struct adapter *Adapter,
+ u8 Operation
+ )
+{
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: PHY_SetBWModeCallback8192C()
+ *
+ * Overview: Timer callback function for SetSetBWMode
+ *
+ * Input: PRT_TIMER pTimer
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Note: (1) We do not take j mode into consideration now
+ * (2) Will two workitem of "switch channel" and "switch channel bandwidth" run
+ * concurrently?
+ *---------------------------------------------------------------------------*/
+static void
+_PHY_SetBWMode92C(
+ struct adapter *Adapter
+)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u8 regBwOpMode;
+ u8 regRRSR_RSC;
+
+ if (pHalData->rf_chip == RF_PSEUDO_11N)
+ return;
+
+ /* There is no 40MHz mode in RF_8225. */
+ if (pHalData->rf_chip == RF_8225)
+ return;
+
+ if (Adapter->bDriverStopped)
+ return;
+
+ /* 3 */
+ /* 3<1>Set MAC register */
+ /* 3 */
+
+ regBwOpMode = rtw_read8(Adapter, REG_BWOPMODE);
+ regRRSR_RSC = rtw_read8(Adapter, REG_RRSR+2);
+
+ switch (pHalData->CurrentChannelBW) {
+ case HT_CHANNEL_WIDTH_20:
+ regBwOpMode |= BW_OPMODE_20MHZ;
+ /* 2007/02/07 Mark by Emily becasue we have not verify whether this register works */
+ rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode);
+ break;
+ case HT_CHANNEL_WIDTH_40:
+ regBwOpMode &= ~BW_OPMODE_20MHZ;
+ /* 2007/02/07 Mark by Emily becasue we have not verify whether this register works */
+ rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode);
+ regRRSR_RSC = (regRRSR_RSC&0x90) | (pHalData->nCur40MhzPrimeSC<<5);
+ rtw_write8(Adapter, REG_RRSR+2, regRRSR_RSC);
+ break;
+ default:
+ break;
+ }
+
+ /* 3 */
+ /* 3 <2>Set PHY related register */
+ /* 3 */
+ switch (pHalData->CurrentChannelBW) {
+ /* 20 MHz channel*/
+ case HT_CHANNEL_WIDTH_20:
+ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x0);
+ PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x0);
+ break;
+ /* 40 MHz channel*/
+ case HT_CHANNEL_WIDTH_40:
+ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x1);
+ PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x1);
+ /* Set Control channel to upper or lower. These settings are required only for 40MHz */
+ PHY_SetBBReg(Adapter, rCCK0_System, bCCKSideBand, (pHalData->nCur40MhzPrimeSC>>1));
+ PHY_SetBBReg(Adapter, rOFDM1_LSTF, 0xC00, pHalData->nCur40MhzPrimeSC);
+ PHY_SetBBReg(Adapter, 0x818, (BIT26 | BIT27),
+ (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+ break;
+ default:
+ break;
+ }
+ /* Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 */
+
+ /* 3<3>Set RF related register */
+ switch (pHalData->rf_chip) {
+ case RF_8225:
+ break;
+ case RF_8256:
+ /* Please implement this function in Hal8190PciPhy8256.c */
+ break;
+ case RF_8258:
+ /* Please implement this function in Hal8190PciPhy8258.c */
+ break;
+ case RF_PSEUDO_11N:
+ break;
+ case RF_6052:
+ rtl8188e_PHY_RF6052SetBandwidth(Adapter, pHalData->CurrentChannelBW);
+ break;
+ default:
+ break;
+ }
+}
+
+ /*-----------------------------------------------------------------------------
+ * Function: SetBWMode8190Pci()
+ *
+ * Overview: This function is export to "HalCommon" moudule
+ *
+ * Input: struct adapter *Adapter
+ * enum ht_channel_width Bandwidth 20M or 40M
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Note: We do not take j mode into consideration now
+ *---------------------------------------------------------------------------*/
+void PHY_SetBWMode8188E(struct adapter *Adapter, enum ht_channel_width Bandwidth, /* 20M or 40M */
+ unsigned char Offset) /* Upper, Lower, or Don't care */
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ enum ht_channel_width tmpBW = pHalData->CurrentChannelBW;
+
+ pHalData->CurrentChannelBW = Bandwidth;
+
+ pHalData->nCur40MhzPrimeSC = Offset;
+
+ if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved))
+ _PHY_SetBWMode92C(Adapter);
+ else
+ pHalData->CurrentChannelBW = tmpBW;
+}
+
+static void _PHY_SwChnl8192C(struct adapter *Adapter, u8 channel)
+{
+ u8 eRFPath;
+ u32 param1, param2;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+
+ if (Adapter->bNotifyChannelChange)
+ DBG_88E("[%s] ch = %d\n", __func__, channel);
+
+ /* s1. pre common command - CmdID_SetTxPowerLevel */
+ PHY_SetTxPowerLevel8188E(Adapter, channel);
+
+ /* s2. RF dependent command - CmdID_RF_WriteReg, param1=RF_CHNLBW, param2=channel */
+ param1 = RF_CHNLBW;
+ param2 = channel;
+ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
+ pHalData->RfRegChnlVal[eRFPath] = ((pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | param2);
+ PHY_SetRFReg(Adapter, (enum rf_radio_path)eRFPath, param1, bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]);
+ }
+}
+
+void PHY_SwChnl8188E(struct adapter *Adapter, u8 channel)
+{
+ /* Call after initialization */
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u8 tmpchannel = pHalData->CurrentChannel;
+ bool bResult = true;
+
+ if (pHalData->rf_chip == RF_PSEUDO_11N)
+ return; /* return immediately if it is peudo-phy */
+
+ if (channel == 0)
+ channel = 1;
+
+ pHalData->CurrentChannel = channel;
+
+ if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) {
+ _PHY_SwChnl8192C(Adapter, channel);
+
+ if (bResult)
+ ;
+ else
+ pHalData->CurrentChannel = tmpchannel;
+
+ } else {
+ pHalData->CurrentChannel = tmpchannel;
+ }
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c b/drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c
new file mode 100644
index 00000000000..bfdf9b3ce77
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c
@@ -0,0 +1,572 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ *
+ * Module: rtl8192c_rf6052.c ( Source C File)
+ *
+ * Note: Provide RF 6052 series relative API.
+ *
+ * Function:
+ *
+ * Export:
+ *
+ * Abbrev:
+ *
+ * History:
+ * Data Who Remark
+ *
+ * 09/25/2008 MHC Create initial version.
+ * 11/05/2008 MHC Add API for tw power setting.
+ *
+ *
+******************************************************************************/
+
+#define _RTL8188E_RF6052_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <rtl8188e_hal.h>
+
+/*---------------------------Define Local Constant---------------------------*/
+/* Define local structure for debug!!!!! */
+struct rf_shadow {
+ /* Shadow register value */
+ u32 Value;
+ /* Compare or not flag */
+ u8 Compare;
+ /* Record If it had ever modified unpredicted */
+ u8 ErrorOrNot;
+ /* Recorver Flag */
+ u8 Recorver;
+ /* */
+ u8 Driver_Write;
+};
+
+/*---------------------------Define Local Constant---------------------------*/
+
+
+/*------------------------Define global variable-----------------------------*/
+
+/*------------------------Define local variable------------------------------*/
+
+/*-----------------------------------------------------------------------------
+ * Function: RF_ChangeTxPath
+ *
+ * Overview: For RL6052, we must change some RF settign for 1T or 2T.
+ *
+ * Input: u16 DataRate 0x80-8f, 0x90-9f
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 09/25/2008 MHC Create Version 0.
+ * Firmwaer support the utility later.
+ *
+ *---------------------------------------------------------------------------*/
+void rtl8188e_RF_ChangeTxPath(struct adapter *Adapter, u16 DataRate)
+{
+/* We do not support gain table change inACUT now !!!! Delete later !!! */
+} /* RF_ChangeTxPath */
+
+
+/*-----------------------------------------------------------------------------
+ * Function: PHY_RF6052SetBandwidth()
+ *
+ * Overview: This function is called by SetBWModeCallback8190Pci() only
+ *
+ * Input: struct adapter *Adapter
+ * WIRELESS_BANDWIDTH_E Bandwidth 20M or 40M
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Note: For RF type 0222D
+ *---------------------------------------------------------------------------*/
+void rtl8188e_PHY_RF6052SetBandwidth(struct adapter *Adapter,
+ enum ht_channel_width Bandwidth)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+
+ switch (Bandwidth) {
+ case HT_CHANNEL_WIDTH_20:
+ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10) | BIT(11));
+ PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]);
+ break;
+ case HT_CHANNEL_WIDTH_40:
+ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10));
+ PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]);
+ break;
+ default:
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: PHY_RF6052SetCckTxPower
+ *
+ * Overview:
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/05/2008 MHC Simulate 8192series..
+ *
+ *---------------------------------------------------------------------------*/
+
+void
+rtl8188e_PHY_RF6052SetCckTxPower(
+ struct adapter *Adapter,
+ u8 *pPowerlevel)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ struct dm_priv *pdmpriv = &pHalData->dmpriv;
+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
+ u32 TxAGC[2] = {0, 0}, tmpval = 0, pwrtrac_value;
+ bool TurboScanOff = false;
+ u8 idx1, idx2;
+ u8 *ptr;
+ u8 direction;
+ /* FOR CE ,must disable turbo scan */
+ TurboScanOff = true;
+
+
+ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+ TxAGC[RF_PATH_A] = 0x3f3f3f3f;
+ TxAGC[RF_PATH_B] = 0x3f3f3f3f;
+
+ TurboScanOff = true;/* disable turbo scan */
+
+ if (TurboScanOff) {
+ for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
+ TxAGC[idx1] =
+ pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) |
+ (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24);
+ /* 2010/10/18 MH For external PA module. We need to limit power index to be less than 0x20. */
+ if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA)
+ TxAGC[idx1] = 0x20;
+ }
+ }
+ } else {
+ /* Driver dynamic Tx power shall not affect Tx power.
+ * It shall be determined by power training mechanism.
+i * Currently, we cannot fully disable driver dynamic
+ * tx power mechanism because it is referenced by BT
+ * coexist mechanism.
+ * In the future, two mechanism shall be separated from
+ * each other and maintained independantly. */
+ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
+ TxAGC[RF_PATH_A] = 0x10101010;
+ TxAGC[RF_PATH_B] = 0x10101010;
+ } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) {
+ TxAGC[RF_PATH_A] = 0x00000000;
+ TxAGC[RF_PATH_B] = 0x00000000;
+ } else {
+ for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
+ TxAGC[idx1] =
+ pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) |
+ (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24);
+ }
+ if (pHalData->EEPROMRegulatory == 0) {
+ tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) +
+ (pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8);
+ TxAGC[RF_PATH_A] += tmpval;
+
+ tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) +
+ (pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24);
+ TxAGC[RF_PATH_B] += tmpval;
+ }
+ }
+ }
+ for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
+ ptr = (u8 *)(&(TxAGC[idx1]));
+ for (idx2 = 0; idx2 < 4; idx2++) {
+ if (*ptr > RF6052_MAX_TX_PWR)
+ *ptr = RF6052_MAX_TX_PWR;
+ ptr++;
+ }
+ }
+ ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 1, &direction, &pwrtrac_value);
+
+ if (direction == 1) {
+ /* Increase TX pwoer */
+ TxAGC[0] += pwrtrac_value;
+ TxAGC[1] += pwrtrac_value;
+ } else if (direction == 2) {
+ /* Decrease TX pwoer */
+ TxAGC[0] -= pwrtrac_value;
+ TxAGC[1] -= pwrtrac_value;
+ }
+
+ /* rf-A cck tx power */
+ tmpval = TxAGC[RF_PATH_A]&0xff;
+ PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
+ tmpval = TxAGC[RF_PATH_A]>>8;
+ PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+ /* rf-B cck tx power */
+ tmpval = TxAGC[RF_PATH_B]>>24;
+ PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
+ tmpval = TxAGC[RF_PATH_B]&0x00ffffff;
+ PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
+} /* PHY_RF6052SetCckTxPower */
+
+/* */
+/* powerbase0 for OFDM rates */
+/* powerbase1 for HT MCS rates */
+/* */
+static void getpowerbase88e(struct adapter *Adapter, u8 *pPowerLevelOFDM,
+ u8 *pPowerLevelBW20, u8 *pPowerLevelBW40, u8 Channel, u32 *OfdmBase, u32 *MCSBase)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u32 powerBase0, powerBase1;
+ u8 i, powerlevel[2];
+
+ for (i = 0; i < 2; i++) {
+ powerBase0 = pPowerLevelOFDM[i];
+
+ powerBase0 = (powerBase0<<24) | (powerBase0<<16) | (powerBase0<<8) | powerBase0;
+ *(OfdmBase+i) = powerBase0;
+ }
+ for (i = 0; i < pHalData->NumTotalRFPath; i++) {
+ /* Check HT20 to HT40 diff */
+ if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
+ powerlevel[i] = pPowerLevelBW20[i];
+ else
+ powerlevel[i] = pPowerLevelBW40[i];
+ powerBase1 = powerlevel[i];
+ powerBase1 = (powerBase1<<24) | (powerBase1<<16) | (powerBase1<<8) | powerBase1;
+ *(MCSBase+i) = powerBase1;
+ }
+}
+static void get_rx_power_val_by_reg(struct adapter *Adapter, u8 Channel,
+ u8 index, u32 *powerBase0, u32 *powerBase1,
+ u32 *pOutWriteVal)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ struct dm_priv *pdmpriv = &pHalData->dmpriv;
+ u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit;
+ s8 pwr_diff = 0;
+ u32 writeVal, customer_limit, rf;
+ u8 Regulatory = pHalData->EEPROMRegulatory;
+
+ /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
+
+ for (rf = 0; rf < 2; rf++) {
+ switch (Regulatory) {
+ case 0: /* Realtek better performance */
+ /* increase power diff defined by Realtek for large power */
+ chnlGroup = 0;
+ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
+ ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+ break;
+ case 1: /* Realtek regulatory */
+ /* increase power diff defined by Realtek for regulatory */
+ if (pHalData->pwrGroupCnt == 1)
+ chnlGroup = 0;
+ if (pHalData->pwrGroupCnt >= pHalData->PGMaxGroup) {
+ if (Channel < 3) /* Chanel 1-2 */
+ chnlGroup = 0;
+ else if (Channel < 6) /* Channel 3-5 */
+ chnlGroup = 1;
+ else if (Channel < 9) /* Channel 6-8 */
+ chnlGroup = 2;
+ else if (Channel < 12) /* Channel 9-11 */
+ chnlGroup = 3;
+ else if (Channel < 14) /* Channel 12-13 */
+ chnlGroup = 4;
+ else if (Channel == 14) /* Channel 14 */
+ chnlGroup = 5;
+ }
+ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
+ ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+ break;
+ case 2: /* Better regulatory */
+ /* don't increase any power diff */
+ writeVal = ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+ break;
+ case 3: /* Customer defined power diff. */
+ /* increase power diff defined by customer. */
+ chnlGroup = 0;
+
+ if (index < 2)
+ pwr_diff = pHalData->TxPwrLegacyHtDiff[rf][Channel-1];
+ else if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
+ pwr_diff = pHalData->TxPwrHt20Diff[rf][Channel-1];
+
+ if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
+ customer_pwr_limit = pHalData->PwrGroupHT40[rf][Channel-1];
+ else
+ customer_pwr_limit = pHalData->PwrGroupHT20[rf][Channel-1];
+
+ if (pwr_diff >= customer_pwr_limit)
+ pwr_diff = 0;
+ else
+ pwr_diff = customer_pwr_limit - pwr_diff;
+
+ for (i = 0; i < 4; i++) {
+ pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)]&(0x7f<<(i*8)))>>(i*8));
+
+ if (pwr_diff_limit[i] > pwr_diff)
+ pwr_diff_limit[i] = pwr_diff;
+ }
+ customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) |
+ (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]);
+ writeVal = customer_limit + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+ break;
+ default:
+ chnlGroup = 0;
+ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
+ ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+ break;
+ }
+/* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
+/* Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
+/* In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. */
+ /* 92d do not need this */
+ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
+ writeVal = 0x14141414;
+ else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
+ writeVal = 0x00000000;
+
+ /* 20100628 Joseph: High power mode for BT-Coexist mechanism. */
+ /* This mechanism is only applied when Driver-Highpower-Mechanism is OFF. */
+ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1)
+ writeVal = writeVal - 0x06060606;
+ else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2)
+ writeVal = writeVal;
+ *(pOutWriteVal+rf) = writeVal;
+ }
+}
+static void writeOFDMPowerReg88E(struct adapter *Adapter, u8 index, u32 *pValue)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u16 regoffset_a[6] = {
+ rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
+ rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
+ rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12};
+ u16 regoffset_b[6] = {
+ rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
+ rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
+ rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12};
+ u8 i, rf, pwr_val[4];
+ u32 writeVal;
+ u16 regoffset;
+
+ for (rf = 0; rf < 2; rf++) {
+ writeVal = pValue[rf];
+ for (i = 0; i < 4; i++) {
+ pwr_val[i] = (u8)((writeVal & (0x7f<<(i*8)))>>(i*8));
+ if (pwr_val[i] > RF6052_MAX_TX_PWR)
+ pwr_val[i] = RF6052_MAX_TX_PWR;
+ }
+ writeVal = (pwr_val[3]<<24) | (pwr_val[2]<<16) | (pwr_val[1]<<8) | pwr_val[0];
+
+ if (rf == 0)
+ regoffset = regoffset_a[index];
+ else
+ regoffset = regoffset_b[index];
+
+ PHY_SetBBReg(Adapter, regoffset, bMaskDWord, writeVal);
+
+ /* 201005115 Joseph: Set Tx Power diff for Tx power training mechanism. */
+ if (((pHalData->rf_type == RF_2T2R) &&
+ (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs15_Mcs12)) ||
+ ((pHalData->rf_type != RF_2T2R) &&
+ (regoffset == rTxAGC_A_Mcs07_Mcs04 || regoffset == rTxAGC_B_Mcs07_Mcs04))) {
+ writeVal = pwr_val[3];
+ if (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_A_Mcs07_Mcs04)
+ regoffset = 0xc90;
+ if (regoffset == rTxAGC_B_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs07_Mcs04)
+ regoffset = 0xc98;
+ for (i = 0; i < 3; i++) {
+ if (i != 2)
+ writeVal = (writeVal > 8) ? (writeVal-8) : 0;
+ else
+ writeVal = (writeVal > 6) ? (writeVal-6) : 0;
+ rtw_write8(Adapter, (u32)(regoffset+i), (u8)writeVal);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: PHY_RF6052SetOFDMTxPower
+ *
+ * Overview: For legacy and HY OFDM, we must read EEPROM TX power index for
+ * different channel and read original value in TX power register area from
+ * 0xe00. We increase offset and original value to be correct tx pwr.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/05/2008 MHC Simulate 8192 series method.
+ * 01/06/2009 MHC 1. Prevent Path B tx power overflow or underflow dure to
+ * A/B pwr difference or legacy/HT pwr diff.
+ * 2. We concern with path B legacy/HT OFDM difference.
+ * 01/22/2009 MHC Support new EPRO format from SD3.
+ *
+ *---------------------------------------------------------------------------*/
+
+void
+rtl8188e_PHY_RF6052SetOFDMTxPower(
+ struct adapter *Adapter,
+ u8 *pPowerLevelOFDM,
+ u8 *pPowerLevelBW20,
+ u8 *pPowerLevelBW40,
+ u8 Channel)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u32 writeVal[2], powerBase0[2], powerBase1[2], pwrtrac_value;
+ u8 direction;
+ u8 index = 0;
+
+ getpowerbase88e(Adapter, pPowerLevelOFDM, pPowerLevelBW20, pPowerLevelBW40, Channel, &powerBase0[0], &powerBase1[0]);
+
+ /* 2012/04/23 MH According to power tracking value, we need to revise OFDM tx power. */
+ /* This is ued to fix unstable power tracking mode. */
+ ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 0, &direction, &pwrtrac_value);
+
+ for (index = 0; index < 6; index++) {
+ get_rx_power_val_by_reg(Adapter, Channel, index,
+ &powerBase0[0], &powerBase1[0],
+ &writeVal[0]);
+
+ if (direction == 1) {
+ writeVal[0] += pwrtrac_value;
+ writeVal[1] += pwrtrac_value;
+ } else if (direction == 2) {
+ writeVal[0] -= pwrtrac_value;
+ writeVal[1] -= pwrtrac_value;
+ }
+ writeOFDMPowerReg88E(Adapter, index, &writeVal[0]);
+ }
+}
+
+static int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
+{
+ struct bb_reg_def *pPhyReg;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ u32 u4RegValue = 0;
+ u8 eRFPath;
+ int rtStatus = _SUCCESS;
+
+ /* 3----------------------------------------------------------------- */
+ /* 3 <2> Initialize RF */
+ /* 3----------------------------------------------------------------- */
+ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
+ pPhyReg = &pHalData->PHYRegDef[eRFPath];
+
+ /*----Store original RFENV control type----*/
+ switch (eRFPath) {
+ case RF_PATH_A:
+ case RF_PATH_C:
+ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV);
+ break;
+ case RF_PATH_B:
+ case RF_PATH_D:
+ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16);
+ break;
+ }
+ /*----Set RF_ENV enable----*/
+ PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1);
+ rtw_udelay_os(1);/* PlatformStallExecution(1); */
+
+ /*----Set RF_ENV output high----*/
+ PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
+ rtw_udelay_os(1);/* PlatformStallExecution(1); */
+
+ /* Set bit number of Address and Data for RF register */
+ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); /* Set 1 to 4 bits for 8255 */
+ rtw_udelay_os(1);/* PlatformStallExecution(1); */
+
+ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); /* Set 0 to 12 bits for 8255 */
+ rtw_udelay_os(1);/* PlatformStallExecution(1); */
+
+ /*----Initialize RF fom connfiguration file----*/
+ switch (eRFPath) {
+ case RF_PATH_A:
+ if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, (enum ODM_RF_RADIO_PATH)eRFPath, (enum ODM_RF_RADIO_PATH)eRFPath))
+ rtStatus = _FAIL;
+ break;
+ case RF_PATH_B:
+ if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, (enum ODM_RF_RADIO_PATH)eRFPath, (enum ODM_RF_RADIO_PATH)eRFPath))
+ rtStatus = _FAIL;
+ break;
+ case RF_PATH_C:
+ break;
+ case RF_PATH_D:
+ break;
+ }
+ /*----Restore RFENV control type----*/;
+ switch (eRFPath) {
+ case RF_PATH_A:
+ case RF_PATH_C:
+ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue);
+ break;
+ case RF_PATH_B:
+ case RF_PATH_D:
+ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue);
+ break;
+ }
+ if (rtStatus != _SUCCESS)
+ goto phy_RF6052_Config_ParaFile_Fail;
+ }
+ return rtStatus;
+
+phy_RF6052_Config_ParaFile_Fail:
+ return rtStatus;
+}
+
+int PHY_RF6052_Config8188E(struct adapter *Adapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+ int rtStatus = _SUCCESS;
+
+ /* */
+ /* Initialize general global value */
+ /* */
+ /* TODO: Extend RF_PATH_C and RF_PATH_D in the future */
+ if (pHalData->rf_type == RF_1T1R)
+ pHalData->NumTotalRFPath = 1;
+ else
+ pHalData->NumTotalRFPath = 2;
+
+ /* */
+ /* Config BB and RF */
+ /* */
+ rtStatus = phy_RF6052_Config_ParaFile(Adapter);
+ return rtStatus;
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c b/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
new file mode 100644
index 00000000000..05e2475cfd6
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
@@ -0,0 +1,202 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_REDESC_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtl8188e_hal.h>
+
+static void process_rssi(struct adapter *padapter, union recv_frame *prframe)
+{
+ struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
+ struct signal_stat *signal_stat = &padapter->recvpriv.signal_strength_data;
+
+ if (signal_stat->update_req) {
+ signal_stat->total_num = 0;
+ signal_stat->total_val = 0;
+ signal_stat->update_req = 0;
+ }
+
+ signal_stat->total_num++;
+ signal_stat->total_val += pattrib->phy_info.SignalStrength;
+ signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num;
+} /* Process_UI_RSSI_8192C */
+
+static void process_link_qual(struct adapter *padapter, union recv_frame *prframe)
+{
+ struct rx_pkt_attrib *pattrib;
+ struct signal_stat *signal_stat;
+
+ if (prframe == NULL || padapter == NULL)
+ return;
+
+ pattrib = &prframe->u.hdr.attrib;
+ signal_stat = &padapter->recvpriv.signal_qual_data;
+
+ if (signal_stat->update_req) {
+ signal_stat->total_num = 0;
+ signal_stat->total_val = 0;
+ signal_stat->update_req = 0;
+ }
+
+ signal_stat->total_num++;
+ signal_stat->total_val += pattrib->phy_info.SignalQuality;
+ signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num;
+}
+
+void rtl8188e_process_phy_info(struct adapter *padapter, void *prframe)
+{
+ union recv_frame *precvframe = (union recv_frame *)prframe;
+
+ /* Check RSSI */
+ process_rssi(padapter, precvframe);
+ /* Check EVM */
+ process_link_qual(padapter, precvframe);
+}
+
+void update_recvframe_attrib_88e(union recv_frame *precvframe, struct recv_stat *prxstat)
+{
+ struct rx_pkt_attrib *pattrib;
+ struct recv_stat report;
+
+ report.rxdw0 = prxstat->rxdw0;
+ report.rxdw1 = prxstat->rxdw1;
+ report.rxdw2 = prxstat->rxdw2;
+ report.rxdw3 = prxstat->rxdw3;
+ report.rxdw4 = prxstat->rxdw4;
+ report.rxdw5 = prxstat->rxdw5;
+
+ pattrib = &precvframe->u.hdr.attrib;
+ _rtw_memset(pattrib, 0, sizeof(struct rx_pkt_attrib));
+
+ pattrib->crc_err = (u8)((le32_to_cpu(report.rxdw0) >> 14) & 0x1);;/* u8)prxreport->crc32; */
+
+ /* update rx report to recv_frame attribute */
+ pattrib->pkt_rpt_type = (u8)((le32_to_cpu(report.rxdw3) >> 14) & 0x3);/* prxreport->rpt_sel; */
+
+ if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */
+ pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x00003fff);/* u16)prxreport->pktlen; */
+ pattrib->drvinfo_sz = (u8)((le32_to_cpu(report.rxdw0) >> 16) & 0xf) * 8;/* u8)(prxreport->drvinfosize << 3); */
+
+ pattrib->physt = (u8)((le32_to_cpu(report.rxdw0) >> 26) & 0x1);/* u8)prxreport->physt; */
+
+ pattrib->bdecrypted = (le32_to_cpu(report.rxdw0) & BIT(27)) ? 0 : 1;/* u8)(prxreport->swdec ? 0 : 1); */
+ pattrib->encrypt = (u8)((le32_to_cpu(report.rxdw0) >> 20) & 0x7);/* u8)prxreport->security; */
+
+ pattrib->qos = (u8)((le32_to_cpu(report.rxdw0) >> 23) & 0x1);/* u8)prxreport->qos; */
+ pattrib->priority = (u8)((le32_to_cpu(report.rxdw1) >> 8) & 0xf);/* u8)prxreport->tid; */
+
+ pattrib->amsdu = (u8)((le32_to_cpu(report.rxdw1) >> 13) & 0x1);/* u8)prxreport->amsdu; */
+
+ pattrib->seq_num = (u16)(le32_to_cpu(report.rxdw2) & 0x00000fff);/* u16)prxreport->seq; */
+ pattrib->frag_num = (u8)((le32_to_cpu(report.rxdw2) >> 12) & 0xf);/* u8)prxreport->frag; */
+ pattrib->mfrag = (u8)((le32_to_cpu(report.rxdw1) >> 27) & 0x1);/* u8)prxreport->mf; */
+ pattrib->mdata = (u8)((le32_to_cpu(report.rxdw1) >> 26) & 0x1);/* u8)prxreport->md; */
+
+ pattrib->mcs_rate = (u8)(le32_to_cpu(report.rxdw3) & 0x3f);/* u8)prxreport->rxmcs; */
+ pattrib->rxht = (u8)((le32_to_cpu(report.rxdw3) >> 6) & 0x1);/* u8)prxreport->rxht; */
+
+ pattrib->icv_err = (u8)((le32_to_cpu(report.rxdw0) >> 15) & 0x1);/* u8)prxreport->icverr; */
+ pattrib->shift_sz = (u8)((le32_to_cpu(report.rxdw0) >> 24) & 0x3);
+ } else if (pattrib->pkt_rpt_type == TX_REPORT1) { /* CCX */
+ pattrib->pkt_len = TX_RPT1_PKT_LEN;
+ pattrib->drvinfo_sz = 0;
+ } else if (pattrib->pkt_rpt_type == TX_REPORT2) { /* TX RPT */
+ pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x3FF);/* Rx length[9:0] */
+ pattrib->drvinfo_sz = 0;
+
+ /* */
+ /* Get TX report MAC ID valid. */
+ /* */
+ pattrib->MacIDValidEntry[0] = le32_to_cpu(report.rxdw4);
+ pattrib->MacIDValidEntry[1] = le32_to_cpu(report.rxdw5);
+
+ } else if (pattrib->pkt_rpt_type == HIS_REPORT) { /* USB HISR RPT */
+ pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x00003fff);/* u16)prxreport->pktlen; */
+ }
+}
+
+/*
+ * Notice:
+ * Before calling this function,
+ * precvframe->u.hdr.rx_data should be ready!
+ */
+void update_recvframe_phyinfo_88e(union recv_frame *precvframe, struct phy_stat *pphy_status)
+{
+ struct adapter *padapter = precvframe->u.hdr.adapter;
+ struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+ struct odm_phy_status_info *pPHYInfo = (struct odm_phy_status_info *)(&pattrib->phy_info);
+ u8 *wlanhdr;
+ struct odm_per_pkt_info pkt_info;
+ u8 *sa = NULL;
+ struct sta_priv *pstapriv;
+ struct sta_info *psta;
+
+ pkt_info.bPacketMatchBSSID = false;
+ pkt_info.bPacketToSelf = false;
+ pkt_info.bPacketBeacon = false;
+
+ wlanhdr = get_recvframe_data(precvframe);
+
+ pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) &&
+ !pattrib->icv_err && !pattrib->crc_err &&
+ _rtw_memcmp(get_hdr_bssid(wlanhdr),
+ get_bssid(&padapter->mlmepriv), ETH_ALEN));
+
+ pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID &&
+ (_rtw_memcmp(get_da(wlanhdr),
+ myid(&padapter->eeprompriv), ETH_ALEN));
+
+ pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID &&
+ (GetFrameSubType(wlanhdr) == WIFI_BEACON);
+
+ if (pkt_info.bPacketBeacon) {
+ if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE))
+ sa = padapter->mlmepriv.cur_network.network.MacAddress;
+ /* to do Ad-hoc */
+ } else {
+ sa = get_sa(wlanhdr);
+ }
+
+ pstapriv = &padapter->stapriv;
+ pkt_info.StationID = 0xFF;
+ psta = rtw_get_stainfo(pstapriv, sa);
+ if (psta)
+ pkt_info.StationID = psta->mac_id;
+ pkt_info.Rate = pattrib->mcs_rate;
+
+ ODM_PhyStatusQuery(&pHalData->odmpriv, pPHYInfo, (u8 *)pphy_status, &(pkt_info));
+
+ precvframe->u.hdr.psta = NULL;
+ if (pkt_info.bPacketMatchBSSID &&
+ (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE))) {
+ if (psta) {
+ precvframe->u.hdr.psta = psta;
+ rtl8188e_process_phy_info(padapter, precvframe);
+ }
+ } else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) {
+ if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) {
+ if (psta)
+ precvframe->u.hdr.psta = psta;
+ }
+ rtl8188e_process_phy_info(padapter, precvframe);
+ }
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_sreset.c b/drivers/staging/rtl8188eu/hal/rtl8188e_sreset.c
new file mode 100644
index 00000000000..96d698e1f33
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_sreset.c
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_SRESET_C_
+
+#include <rtl8188e_sreset.h>
+#include <rtl8188e_hal.h>
+
+void rtl8188e_silentreset_for_specific_platform(struct adapter *padapter)
+{
+}
+
+void rtl8188e_sreset_xmit_status_check(struct adapter *padapter)
+{
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+ struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+ unsigned long current_time;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ unsigned int diff_time;
+ u32 txdma_status;
+
+ txdma_status = rtw_read32(padapter, REG_TXDMA_STATUS);
+ if (txdma_status != 0x00) {
+ DBG_88E("%s REG_TXDMA_STATUS:0x%08x\n", __func__, txdma_status);
+ rtw_write32(padapter, REG_TXDMA_STATUS, txdma_status);
+ rtl8188e_silentreset_for_specific_platform(padapter);
+ }
+ /* total xmit irp = 4 */
+ current_time = rtw_get_current_time();
+ if (0 == pxmitpriv->free_xmitbuf_cnt) {
+ diff_time = jiffies_to_msecs(current_time - psrtpriv->last_tx_time);
+
+ if (diff_time > 2000) {
+ if (psrtpriv->last_tx_complete_time == 0) {
+ psrtpriv->last_tx_complete_time = current_time;
+ } else {
+ diff_time = jiffies_to_msecs(current_time - psrtpriv->last_tx_complete_time);
+ if (diff_time > 4000) {
+ DBG_88E("%s tx hang\n", __func__);
+ rtl8188e_silentreset_for_specific_platform(padapter);
+ }
+ }
+ }
+ }
+}
+
+void rtl8188e_sreset_linked_status_check(struct adapter *padapter)
+{
+ u32 rx_dma_status = 0;
+ u8 fw_status = 0;
+ rx_dma_status = rtw_read32(padapter, REG_RXDMA_STATUS);
+ if (rx_dma_status != 0x00) {
+ DBG_88E("%s REG_RXDMA_STATUS:0x%08x\n", __func__, rx_dma_status);
+ rtw_write32(padapter, REG_RXDMA_STATUS, rx_dma_status);
+ }
+ fw_status = rtw_read8(padapter, REG_FMETHR);
+ if (fw_status != 0x00) {
+ if (fw_status == 1)
+ DBG_88E("%s REG_FW_STATUS (0x%02x), Read_Efuse_Fail !!\n", __func__, fw_status);
+ else if (fw_status == 2)
+ DBG_88E("%s REG_FW_STATUS (0x%02x), Condition_No_Match !!\n", __func__, fw_status);
+ }
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c
new file mode 100644
index 00000000000..7ecbcf731ea
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c
@@ -0,0 +1,91 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_XMIT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtl8188e_hal.h>
+
+void dump_txrpt_ccx_88e(void *buf)
+{
+ struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf;
+
+ DBG_88E("%s:\n"
+ "tag1:%u, pkt_num:%u, txdma_underflow:%u, int_bt:%u, int_tri:%u, int_ccx:%u\n"
+ "mac_id:%u, pkt_ok:%u, bmc:%u\n"
+ "retry_cnt:%u, lifetime_over:%u, retry_over:%u\n"
+ "ccx_qtime:%u\n"
+ "final_data_rate:0x%02x\n"
+ "qsel:%u, sw:0x%03x\n",
+ __func__, txrpt_ccx->tag1, txrpt_ccx->pkt_num,
+ txrpt_ccx->txdma_underflow, txrpt_ccx->int_bt,
+ txrpt_ccx->int_tri, txrpt_ccx->int_ccx,
+ txrpt_ccx->mac_id, txrpt_ccx->pkt_ok, txrpt_ccx->bmc,
+ txrpt_ccx->retry_cnt, txrpt_ccx->lifetime_over,
+ txrpt_ccx->retry_over, txrpt_ccx_qtime_88e(txrpt_ccx),
+ txrpt_ccx->final_data_rate, txrpt_ccx->qsel,
+ txrpt_ccx_sw_88e(txrpt_ccx)
+ );
+}
+
+void handle_txrpt_ccx_88e(struct adapter *adapter, u8 *buf)
+{
+ struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf;
+
+ if (txrpt_ccx->int_ccx) {
+ if (txrpt_ccx->pkt_ok)
+ rtw_ack_tx_done(&adapter->xmitpriv,
+ RTW_SCTX_DONE_SUCCESS);
+ else
+ rtw_ack_tx_done(&adapter->xmitpriv,
+ RTW_SCTX_DONE_CCX_PKT_FAIL);
+ }
+}
+
+void _dbg_dump_tx_info(struct adapter *padapter, int frame_tag,
+ struct tx_desc *ptxdesc)
+{
+ u8 dmp_txpkt;
+ bool dump_txdesc = false;
+ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(dmp_txpkt));
+
+ if (dmp_txpkt == 1) {/* dump txdesc for data frame */
+ DBG_88E("dump tx_desc for data frame\n");
+ if ((frame_tag & 0x0f) == DATA_FRAMETAG)
+ dump_txdesc = true;
+ } else if (dmp_txpkt == 2) {/* dump txdesc for mgnt frame */
+ DBG_88E("dump tx_desc for mgnt frame\n");
+ if ((frame_tag & 0x0f) == MGNT_FRAMETAG)
+ dump_txdesc = true;
+ }
+
+ if (dump_txdesc) {
+ DBG_88E("=====================================\n");
+ DBG_88E("txdw0(0x%08x)\n", ptxdesc->txdw0);
+ DBG_88E("txdw1(0x%08x)\n", ptxdesc->txdw1);
+ DBG_88E("txdw2(0x%08x)\n", ptxdesc->txdw2);
+ DBG_88E("txdw3(0x%08x)\n", ptxdesc->txdw3);
+ DBG_88E("txdw4(0x%08x)\n", ptxdesc->txdw4);
+ DBG_88E("txdw5(0x%08x)\n", ptxdesc->txdw5);
+ DBG_88E("txdw6(0x%08x)\n", ptxdesc->txdw6);
+ DBG_88E("txdw7(0x%08x)\n", ptxdesc->txdw7);
+ DBG_88E("=====================================\n");
+ }
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c
new file mode 100644
index 00000000000..08dfd94163e
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtl8188e_hal.h>
+#include <rtl8188e_led.h>
+
+/* LED object. */
+
+/* LED_819xUsb routines. */
+/* Description: */
+/* Turn on LED according to LedPin specified. */
+void SwLedOn(struct adapter *padapter, struct LED_871x *pLed)
+{
+ u8 LedCfg;
+
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+ return;
+ LedCfg = rtw_read8(padapter, REG_LEDCFG2);
+ switch (pLed->LedPin) {
+ case LED_PIN_LED0:
+ rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0xf0)|BIT5|BIT6); /* SW control led0 on. */
+ break;
+ case LED_PIN_LED1:
+ rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0x0f)|BIT5); /* SW control led1 on. */
+ break;
+ default:
+ break;
+ }
+ pLed->bLedOn = true;
+}
+
+/* Description: */
+/* Turn off LED according to LedPin specified. */
+void SwLedOff(struct adapter *padapter, struct LED_871x *pLed)
+{
+ u8 LedCfg;
+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+ goto exit;
+
+ LedCfg = rtw_read8(padapter, REG_LEDCFG2);/* 0x4E */
+
+ switch (pLed->LedPin) {
+ case LED_PIN_LED0:
+ if (pHalData->bLedOpenDrain) {
+ /* Open-drain arrangement for controlling the LED) */
+ LedCfg &= 0x90; /* Set to software control. */
+ rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3));
+ LedCfg = rtw_read8(padapter, REG_MAC_PINMUX_CFG);
+ LedCfg &= 0xFE;
+ rtw_write8(padapter, REG_MAC_PINMUX_CFG, LedCfg);
+ } else {
+ rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3|BIT5|BIT6));
+ }
+ break;
+ case LED_PIN_LED1:
+ LedCfg &= 0x0f; /* Set to software control. */
+ rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3));
+ break;
+ default:
+ break;
+ }
+exit:
+ pLed->bLedOn = false;
+}
+
+/* Interface to manipulate LED objects. */
+/* Default LED behavior. */
+
+/* Description: */
+/* Initialize all LED_871x objects. */
+void rtl8188eu_InitSwLeds(struct adapter *padapter)
+{
+ struct led_priv *pledpriv = &(padapter->ledpriv);
+
+ pledpriv->LedControlHandler = LedControl8188eu;
+
+ InitLed871x(padapter, &(pledpriv->SwLed0), LED_PIN_LED0);
+
+ InitLed871x(padapter, &(pledpriv->SwLed1), LED_PIN_LED1);
+}
+
+/* Description: */
+/* DeInitialize all LED_819xUsb objects. */
+void rtl8188eu_DeInitSwLeds(struct adapter *padapter)
+{
+ struct led_priv *ledpriv = &(padapter->ledpriv);
+
+ DeInitLed871x(&(ledpriv->SwLed0));
+ DeInitLed871x(&(ledpriv->SwLed1));
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c
new file mode 100644
index 00000000000..0f47b891859
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c
@@ -0,0 +1,138 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188EU_RECV_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <mlme_osdep.h>
+#include <ip.h>
+#include <if_ether.h>
+#include <ethernet.h>
+
+#include <usb_ops.h>
+#include <wifi.h>
+
+#include <rtl8188e_hal.h>
+
+void rtl8188eu_init_recvbuf(struct adapter *padapter, struct recv_buf *precvbuf)
+{
+ precvbuf->transfer_len = 0;
+
+ precvbuf->len = 0;
+
+ precvbuf->ref_cnt = 0;
+
+ if (precvbuf->pbuf) {
+ precvbuf->pdata = precvbuf->pbuf;
+ precvbuf->phead = precvbuf->pbuf;
+ precvbuf->ptail = precvbuf->pbuf;
+ precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ;
+ }
+}
+
+int rtl8188eu_init_recv_priv(struct adapter *padapter)
+{
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+ int i, res = _SUCCESS;
+ struct recv_buf *precvbuf;
+
+ tasklet_init(&precvpriv->recv_tasklet,
+ (void(*)(unsigned long))rtl8188eu_recv_tasklet,
+ (unsigned long)padapter);
+
+ /* init recv_buf */
+ _rtw_init_queue(&precvpriv->free_recv_buf_queue);
+
+ precvpriv->pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4);
+ if (precvpriv->pallocated_recv_buf == NULL) {
+ res = _FAIL;
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("alloc recv_buf fail!\n"));
+ goto exit;
+ }
+ _rtw_memset(precvpriv->pallocated_recv_buf, 0, NR_RECVBUFF * sizeof(struct recv_buf) + 4);
+
+ precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_recv_buf), 4);
+
+
+ precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+
+ for (i = 0; i < NR_RECVBUFF; i++) {
+ _rtw_init_listhead(&precvbuf->list);
+ _rtw_spinlock_init(&precvbuf->recvbuf_lock);
+ precvbuf->alloc_sz = MAX_RECVBUF_SZ;
+ res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);
+ if (res == _FAIL)
+ break;
+ precvbuf->ref_cnt = 0;
+ precvbuf->adapter = padapter;
+ precvbuf++;
+ }
+ precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;
+ skb_queue_head_init(&precvpriv->rx_skb_queue);
+ {
+ int i;
+ size_t tmpaddr = 0;
+ size_t alignment = 0;
+ struct sk_buff *pskb = NULL;
+
+ skb_queue_head_init(&precvpriv->free_recv_skb_queue);
+
+ for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) {
+ pskb = __netdev_alloc_skb(padapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ, GFP_KERNEL);
+ if (pskb) {
+ pskb->dev = padapter->pnetdev;
+ tmpaddr = (size_t)pskb->data;
+ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
+ skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
+
+ skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
+ }
+ pskb = NULL;
+ }
+ }
+exit:
+ return res;
+}
+
+void rtl8188eu_free_recv_priv(struct adapter *padapter)
+{
+ int i;
+ struct recv_buf *precvbuf;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+ precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+
+ for (i = 0; i < NR_RECVBUFF; i++) {
+ rtw_os_recvbuf_resource_free(padapter, precvbuf);
+ precvbuf++;
+ }
+
+ kfree(precvpriv->pallocated_recv_buf);
+
+ if (skb_queue_len(&precvpriv->rx_skb_queue))
+ DBG_88E(KERN_WARNING "rx_skb_queue not empty\n");
+ skb_queue_purge(&precvpriv->rx_skb_queue);
+
+
+ if (skb_queue_len(&precvpriv->free_recv_skb_queue))
+ DBG_88E(KERN_WARNING "free_recv_skb_queue not empty, %d\n", skb_queue_len(&precvpriv->free_recv_skb_queue));
+
+ skb_queue_purge(&precvpriv->free_recv_skb_queue);
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
new file mode 100644
index 00000000000..bd8a9ae5d07
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
@@ -0,0 +1,706 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_XMIT_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <osdep_intf.h>
+#include <usb_ops.h>
+#include <rtl8188e_hal.h>
+
+s32 rtl8188eu_init_xmit_priv(struct adapter *adapt)
+{
+ struct xmit_priv *pxmitpriv = &adapt->xmitpriv;
+
+ tasklet_init(&pxmitpriv->xmit_tasklet,
+ (void(*)(unsigned long))rtl8188eu_xmit_tasklet,
+ (unsigned long)adapt);
+ return _SUCCESS;
+}
+
+void rtl8188eu_free_xmit_priv(struct adapter *adapt)
+{
+}
+
+static u8 urb_zero_packet_chk(struct adapter *adapt, int sz)
+{
+ u8 set_tx_desc_offset;
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ set_tx_desc_offset = (((sz + TXDESC_SIZE) % haldata->UsbBulkOutSize) == 0) ? 1 : 0;
+
+ return set_tx_desc_offset;
+}
+
+static void rtl8188eu_cal_txdesc_chksum(struct tx_desc *ptxdesc)
+{
+ u16 *usptr = (u16 *)ptxdesc;
+ u32 count = 16; /* (32 bytes / 2 bytes per XOR) => 16 times */
+ u32 index;
+ u16 checksum = 0;
+
+ /* Clear first */
+ ptxdesc->txdw7 &= cpu_to_le32(0xffff0000);
+
+ for (index = 0; index < count; index++)
+ checksum = checksum ^ le16_to_cpu(*(__le16 *)(usptr + index));
+ ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff & checksum);
+}
+
+/* Description: In normal chip, we should send some packet to Hw which will be used by Fw */
+/* in FW LPS mode. The function is to fill the Tx descriptor of this packets, then */
+/* Fw can tell Hw to send these packet derectly. */
+void rtl8188e_fill_fake_txdesc(struct adapter *adapt, u8 *desc, u32 BufferLen, u8 ispspoll, u8 is_btqosnull)
+{
+ struct tx_desc *ptxdesc;
+
+ /* Clear all status */
+ ptxdesc = (struct tx_desc *)desc;
+ _rtw_memset(desc, 0, TXDESC_SIZE);
+
+ /* offset 0 */
+ ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); /* own, bFirstSeg, bLastSeg; */
+
+ ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000); /* 32 bytes for TX Desc */
+
+ ptxdesc->txdw0 |= cpu_to_le32(BufferLen&0x0000ffff); /* Buffer size + command header */
+
+ /* offset 4 */
+ ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT<<QSEL_SHT)&0x00001f00); /* Fixed queue of Mgnt queue */
+
+ /* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error vlaue by Hw. */
+ if (ispspoll) {
+ ptxdesc->txdw1 |= cpu_to_le32(NAVUSEHDR);
+ } else {
+ ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); /* Hw set sequence number */
+ ptxdesc->txdw3 |= cpu_to_le32((8 << 28)); /* set bit3 to 1. Suugested by TimChen. 2009.12.29. */
+ }
+
+ if (is_btqosnull)
+ ptxdesc->txdw2 |= cpu_to_le32(BIT(23)); /* BT NULL */
+
+ /* offset 16 */
+ ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
+
+ /* USB interface drop packet if the checksum of descriptor isn't correct. */
+ /* Using this checksum can let hardware recovery from packet bulk out error (e.g. Cancel URC, Bulk out error.). */
+ rtl8188eu_cal_txdesc_chksum(ptxdesc);
+}
+
+static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc)
+{
+ if ((pattrib->encrypt > 0) && !pattrib->bswenc) {
+ switch (pattrib->encrypt) {
+ /* SEC_TYPE : 0:NO_ENC,1:WEP40/TKIP,2:WAPI,3:AES */
+ case _WEP40_:
+ case _WEP104_:
+ ptxdesc->txdw1 |= cpu_to_le32((0x01<<SEC_TYPE_SHT)&0x00c00000);
+ ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT);
+ break;
+ case _TKIP_:
+ case _TKIP_WTMIC_:
+ ptxdesc->txdw1 |= cpu_to_le32((0x01<<SEC_TYPE_SHT)&0x00c00000);
+ ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT);
+ break;
+ case _AES_:
+ ptxdesc->txdw1 |= cpu_to_le32((0x03<<SEC_TYPE_SHT)&0x00c00000);
+ ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT);
+ break;
+ case _NO_PRIVACY_:
+ default:
+ break;
+ }
+ }
+}
+
+static void fill_txdesc_vcs(struct pkt_attrib *pattrib, __le32 *pdw)
+{
+ switch (pattrib->vcs_mode) {
+ case RTS_CTS:
+ *pdw |= cpu_to_le32(RTS_EN);
+ break;
+ case CTS_TO_SELF:
+ *pdw |= cpu_to_le32(CTS_2_SELF);
+ break;
+ case NONE_VCS:
+ default:
+ break;
+ }
+ if (pattrib->vcs_mode) {
+ *pdw |= cpu_to_le32(HW_RTS_EN);
+ /* Set RTS BW */
+ if (pattrib->ht_en) {
+ *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(27)) : 0;
+
+ if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+ *pdw |= cpu_to_le32((0x01 << 28) & 0x30000000);
+ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+ *pdw |= cpu_to_le32((0x02 << 28) & 0x30000000);
+ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
+ *pdw |= 0;
+ else
+ *pdw |= cpu_to_le32((0x03 << 28) & 0x30000000);
+ }
+ }
+}
+
+static void fill_txdesc_phy(struct pkt_attrib *pattrib, __le32 *pdw)
+{
+ if (pattrib->ht_en) {
+ *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0;
+
+ if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+ *pdw |= cpu_to_le32((0x01 << DATA_SC_SHT) & 0x003f0000);
+ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+ *pdw |= cpu_to_le32((0x02 << DATA_SC_SHT) & 0x003f0000);
+ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
+ *pdw |= 0;
+ else
+ *pdw |= cpu_to_le32((0x03 << DATA_SC_SHT) & 0x003f0000);
+ }
+}
+
+static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bagg_pkt)
+{
+ int pull = 0;
+ uint qsel;
+ u8 data_rate, pwr_status, offset;
+ struct adapter *adapt = pxmitframe->padapter;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ struct tx_desc *ptxdesc = (struct tx_desc *)pmem;
+ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ int bmcst = IS_MCAST(pattrib->ra);
+
+ if (adapt->registrypriv.mp_mode == 0) {
+ if ((!bagg_pkt) && (urb_zero_packet_chk(adapt, sz) == 0)) {
+ ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ);
+ pull = 1;
+ }
+ }
+
+ _rtw_memset(ptxdesc, 0, sizeof(struct tx_desc));
+
+ /* 4 offset 0 */
+ ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
+ ptxdesc->txdw0 |= cpu_to_le32(sz & 0x0000ffff);/* update TXPKTSIZE */
+
+ offset = TXDESC_SIZE + OFFSET_SZ;
+
+ ptxdesc->txdw0 |= cpu_to_le32(((offset) << OFFSET_SHT) & 0x00ff0000);/* 32 bytes for TX Desc */
+
+ if (bmcst)
+ ptxdesc->txdw0 |= cpu_to_le32(BMC);
+
+ if (adapt->registrypriv.mp_mode == 0) {
+ if (!bagg_pkt) {
+ if ((pull) && (pxmitframe->pkt_offset > 0))
+ pxmitframe->pkt_offset = pxmitframe->pkt_offset - 1;
+ }
+ }
+
+ /* pkt_offset, unit:8 bytes padding */
+ if (pxmitframe->pkt_offset > 0)
+ ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000);
+
+ /* driver uses rate */
+ ptxdesc->txdw4 |= cpu_to_le32(USERATE);/* rate control always by driver */
+
+ if ((pxmitframe->frame_tag & 0x0f) == DATA_FRAMETAG) {
+ /* offset 4 */
+ ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x3F);
+
+ qsel = (uint)(pattrib->qsel & 0x0000001f);
+ ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
+
+ ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000F0000);
+
+ fill_txdesc_sectype(pattrib, ptxdesc);
+
+ if (pattrib->ampdu_en) {
+ ptxdesc->txdw2 |= cpu_to_le32(AGG_EN);/* AGG EN */
+ ptxdesc->txdw6 = cpu_to_le32(0x6666f800);
+ } else {
+ ptxdesc->txdw2 |= cpu_to_le32(AGG_BK);/* AGG BK */
+ }
+
+ /* offset 8 */
+
+ /* offset 12 */
+ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 0x0FFF0000);
+
+ /* offset 16 , offset 20 */
+ if (pattrib->qos_en)
+ ptxdesc->txdw4 |= cpu_to_le32(QOS);/* QoS */
+
+ /* offset 20 */
+ if (pxmitframe->agg_num > 1)
+ ptxdesc->txdw5 |= cpu_to_le32((pxmitframe->agg_num << USB_TXAGG_NUM_SHT) & 0xFF000000);
+
+ if ((pattrib->ether_type != 0x888e) &&
+ (pattrib->ether_type != 0x0806) &&
+ (pattrib->ether_type != 0x88b4) &&
+ (pattrib->dhcp_pkt != 1)) {
+ /* Non EAP & ARP & DHCP type data packet */
+
+ fill_txdesc_vcs(pattrib, &ptxdesc->txdw4);
+ fill_txdesc_phy(pattrib, &ptxdesc->txdw4);
+
+ ptxdesc->txdw4 |= cpu_to_le32(0x00000008);/* RTS Rate=24M */
+ ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);/* DATA/RTS Rate FB LMT */
+
+ if (pattrib->ht_en) {
+ if (ODM_RA_GetShortGI_8188E(&haldata->odmpriv, pattrib->mac_id))
+ ptxdesc->txdw5 |= cpu_to_le32(SGI);/* SGI */
+ }
+ data_rate = ODM_RA_GetDecisionRate_8188E(&haldata->odmpriv, pattrib->mac_id);
+ ptxdesc->txdw5 |= cpu_to_le32(data_rate & 0x3F);
+ pwr_status = ODM_RA_GetHwPwrStatus_8188E(&haldata->odmpriv, pattrib->mac_id);
+ ptxdesc->txdw4 |= cpu_to_le32((pwr_status & 0x7) << PWR_STATUS_SHT);
+ } else {
+ /* EAP data packet and ARP packet and DHCP. */
+ /* Use the 1M data rate to send the EAP/ARP packet. */
+ /* This will maybe make the handshake smooth. */
+ ptxdesc->txdw2 |= cpu_to_le32(AGG_BK);/* AGG BK */
+ if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT)
+ ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/* DATA_SHORT */
+ ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate));
+ }
+ } else if ((pxmitframe->frame_tag&0x0f) == MGNT_FRAMETAG) {
+ /* offset 4 */
+ ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x3f);
+
+ qsel = (uint)(pattrib->qsel&0x0000001f);
+ ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
+
+ ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000f0000);
+
+ /* offset 8 */
+ /* CCX-TXRPT ack for xmit mgmt frames. */
+ if (pxmitframe->ack_report)
+ ptxdesc->txdw2 |= cpu_to_le32(BIT(19));
+
+ /* offset 12 */
+ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<SEQ_SHT)&0x0FFF0000);
+
+ /* offset 20 */
+ ptxdesc->txdw5 |= cpu_to_le32(RTY_LMT_EN);/* retry limit enable */
+ if (pattrib->retry_ctrl)
+ ptxdesc->txdw5 |= cpu_to_le32(0x00180000);/* retry limit = 6 */
+ else
+ ptxdesc->txdw5 |= cpu_to_le32(0x00300000);/* retry limit = 12 */
+
+ ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate));
+ } else if ((pxmitframe->frame_tag&0x0f) == TXAGG_FRAMETAG) {
+ DBG_88E("pxmitframe->frame_tag == TXAGG_FRAMETAG\n");
+ } else if (((pxmitframe->frame_tag&0x0f) == MP_FRAMETAG) &&
+ (adapt->registrypriv.mp_mode == 1)) {
+ fill_txdesc_for_mp(adapt, ptxdesc);
+ } else {
+ DBG_88E("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag);
+
+ /* offset 4 */
+ ptxdesc->txdw1 |= cpu_to_le32((4) & 0x3f);/* CAM_ID(MAC_ID) */
+
+ ptxdesc->txdw1 |= cpu_to_le32((6 << RATE_ID_SHT) & 0x000f0000);/* raid */
+
+ /* offset 8 */
+
+ /* offset 12 */
+ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<SEQ_SHT)&0x0fff0000);
+
+ /* offset 20 */
+ ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate));
+ }
+
+ /* 2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. */
+ /* (1) The sequence number of each non-Qos frame / broadcast / multicast / */
+ /* mgnt frame should be controled by Hw because Fw will also send null data */
+ /* which we cannot control when Fw LPS enable. */
+ /* --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */
+ /* (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */
+ /* (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */
+ /* 2010.06.23. Added by tynli. */
+ if (!pattrib->qos_en) {
+ ptxdesc->txdw3 |= cpu_to_le32(EN_HWSEQ); /* Hw set sequence number */
+ ptxdesc->txdw4 |= cpu_to_le32(HW_SSN); /* Hw set sequence number */
+ }
+
+ ODM_SetTxAntByTxInfo_88E(&haldata->odmpriv, pmem, pattrib->mac_id);
+
+ rtl8188eu_cal_txdesc_chksum(ptxdesc);
+ _dbg_dump_tx_info(adapt, pxmitframe->frame_tag, ptxdesc);
+ return pull;
+}
+
+/* for non-agg data frame or management frame */
+static s32 rtw_dump_xframe(struct adapter *adapt, struct xmit_frame *pxmitframe)
+{
+ s32 ret = _SUCCESS;
+ s32 inner_ret = _SUCCESS;
+ int t, sz, w_sz, pull = 0;
+ u8 *mem_addr;
+ u32 ff_hwaddr;
+ struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+ struct xmit_priv *pxmitpriv = &adapt->xmitpriv;
+ struct security_priv *psecuritypriv = &adapt->securitypriv;
+ if ((pxmitframe->frame_tag == DATA_FRAMETAG) &&
+ (pxmitframe->attrib.ether_type != 0x0806) &&
+ (pxmitframe->attrib.ether_type != 0x888e) &&
+ (pxmitframe->attrib.ether_type != 0x88b4) &&
+ (pxmitframe->attrib.dhcp_pkt != 1))
+ rtw_issue_addbareq_cmd(adapt, pxmitframe);
+ mem_addr = pxmitframe->buf_addr;
+
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_dump_xframe()\n"));
+
+ for (t = 0; t < pattrib->nr_frags; t++) {
+ if (inner_ret != _SUCCESS && ret == _SUCCESS)
+ ret = _FAIL;
+
+ if (t != (pattrib->nr_frags - 1)) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("pattrib->nr_frags=%d\n", pattrib->nr_frags));
+
+ sz = pxmitpriv->frag_len;
+ sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 : pattrib->icv_len);
+ } else {
+ /* no frag */
+ sz = pattrib->last_txcmdsz;
+ }
+
+ pull = update_txdesc(pxmitframe, mem_addr, sz, false);
+
+ if (pull) {
+ mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */
+ pxmitframe->buf_addr = mem_addr;
+ w_sz = sz + TXDESC_SIZE;
+ } else {
+ w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ;
+ }
+ ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
+
+ inner_ret = rtw_write_port(adapt, ff_hwaddr, w_sz, (unsigned char *)pxmitbuf);
+
+ rtw_count_tx_stats(adapt, pxmitframe, sz);
+
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_write_port, w_sz=%d\n", w_sz));
+
+ mem_addr += w_sz;
+
+ mem_addr = (u8 *)RND4(((size_t)(mem_addr)));
+ }
+
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+ if (ret != _SUCCESS)
+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN);
+
+ return ret;
+}
+
+static u32 xmitframe_need_length(struct xmit_frame *pxmitframe)
+{
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+
+ u32 len = 0;
+
+ /* no consider fragement */
+ len = pattrib->hdrlen + pattrib->iv_len +
+ SNAP_SIZE + sizeof(u16) +
+ pattrib->pktlen +
+ ((pattrib->bswenc) ? pattrib->icv_len : 0);
+
+ if (pattrib->encrypt == _TKIP_)
+ len += 8;
+
+ return len;
+}
+
+s32 rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ struct xmit_frame *pxmitframe = NULL;
+ struct xmit_frame *pfirstframe = NULL;
+
+ /* aggregate variable */
+ struct hw_xmit *phwxmit;
+ struct sta_info *psta = NULL;
+ struct tx_servq *ptxservq = NULL;
+
+ unsigned long irql;
+ struct list_head *xmitframe_plist = NULL, *xmitframe_phead = NULL;
+
+ u32 pbuf; /* next pkt address */
+ u32 pbuf_tail; /* last pkt tail */
+ u32 len; /* packet length, except TXDESC_SIZE and PKT_OFFSET */
+
+ u32 bulksize = haldata->UsbBulkOutSize;
+ u8 desc_cnt;
+ u32 bulkptr;
+
+ /* dump frame variable */
+ u32 ff_hwaddr;
+
+ RT_TRACE(_module_rtl8192c_xmit_c_, _drv_info_, ("+xmitframe_complete\n"));
+
+ /* check xmitbuffer is ok */
+ if (pxmitbuf == NULL) {
+ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+ if (pxmitbuf == NULL)
+ return false;
+ }
+
+ /* 3 1. pick up first frame */
+ do {
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+ pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+ if (pxmitframe == NULL) {
+ /* no more xmit frame, release xmit buffer */
+ rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+ return false;
+ }
+
+ pxmitframe->pxmitbuf = pxmitbuf;
+ pxmitframe->buf_addr = pxmitbuf->pbuf;
+ pxmitbuf->priv_data = pxmitframe;
+
+ pxmitframe->agg_num = 1; /* alloc xmitframe should assign to 1. */
+ pxmitframe->pkt_offset = 1; /* first frame of aggregation, reserve offset */
+
+ rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe);
+
+ /* always return ndis_packet after rtw_xmitframe_coalesce */
+ rtw_os_xmit_complete(adapt, pxmitframe);
+
+ break;
+ } while (1);
+
+ /* 3 2. aggregate same priority and same DA(AP or STA) frames */
+ pfirstframe = pxmitframe;
+ len = xmitframe_need_length(pfirstframe) + TXDESC_SIZE + (pfirstframe->pkt_offset*PACKET_OFFSET_SZ);
+ pbuf_tail = len;
+ pbuf = _RND8(pbuf_tail);
+
+ /* check pkt amount in one bulk */
+ desc_cnt = 0;
+ bulkptr = bulksize;
+ if (pbuf < bulkptr) {
+ desc_cnt++;
+ } else {
+ desc_cnt = 0;
+ bulkptr = ((pbuf / bulksize) + 1) * bulksize; /* round to next bulksize */
+ }
+
+ /* dequeue same priority packet from station tx queue */
+ psta = pfirstframe->attrib.psta;
+ switch (pfirstframe->attrib.priority) {
+ case 1:
+ case 2:
+ ptxservq = &(psta->sta_xmitpriv.bk_q);
+ phwxmit = pxmitpriv->hwxmits + 3;
+ break;
+ case 4:
+ case 5:
+ ptxservq = &(psta->sta_xmitpriv.vi_q);
+ phwxmit = pxmitpriv->hwxmits + 1;
+ break;
+ case 6:
+ case 7:
+ ptxservq = &(psta->sta_xmitpriv.vo_q);
+ phwxmit = pxmitpriv->hwxmits;
+ break;
+ case 0:
+ case 3:
+ default:
+ ptxservq = &(psta->sta_xmitpriv.be_q);
+ phwxmit = pxmitpriv->hwxmits + 2;
+ break;
+ }
+ _enter_critical_bh(&pxmitpriv->lock, &irql);
+
+ xmitframe_phead = get_list_head(&ptxservq->sta_pending);
+ xmitframe_plist = get_next(xmitframe_phead);
+
+ while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+ pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+ xmitframe_plist = get_next(xmitframe_plist);
+
+ pxmitframe->agg_num = 0; /* not first frame of aggregation */
+ pxmitframe->pkt_offset = 0; /* not first frame of aggregation, no need to reserve offset */
+
+ len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE + (pxmitframe->pkt_offset*PACKET_OFFSET_SZ);
+
+ if (_RND8(pbuf + len) > MAX_XMITBUF_SZ) {
+ pxmitframe->agg_num = 1;
+ pxmitframe->pkt_offset = 1;
+ break;
+ }
+ rtw_list_delete(&pxmitframe->list);
+ ptxservq->qcnt--;
+ phwxmit->accnt--;
+
+ pxmitframe->buf_addr = pxmitbuf->pbuf + pbuf;
+
+ rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe);
+ /* always return ndis_packet after rtw_xmitframe_coalesce */
+ rtw_os_xmit_complete(adapt, pxmitframe);
+
+ /* (len - TXDESC_SIZE) == pxmitframe->attrib.last_txcmdsz */
+ update_txdesc(pxmitframe, pxmitframe->buf_addr, pxmitframe->attrib.last_txcmdsz, true);
+
+ /* don't need xmitframe any more */
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+ /* handle pointer and stop condition */
+ pbuf_tail = pbuf + len;
+ pbuf = _RND8(pbuf_tail);
+
+ pfirstframe->agg_num++;
+ if (MAX_TX_AGG_PACKET_NUMBER == pfirstframe->agg_num)
+ break;
+
+ if (pbuf < bulkptr) {
+ desc_cnt++;
+ if (desc_cnt == haldata->UsbTxAggDescNum)
+ break;
+ } else {
+ desc_cnt = 0;
+ bulkptr = ((pbuf / bulksize) + 1) * bulksize;
+ }
+ } /* end while (aggregate same priority and same DA(AP or STA) frames) */
+
+ if (_rtw_queue_empty(&ptxservq->sta_pending) == true)
+ rtw_list_delete(&ptxservq->tx_pending);
+
+ _exit_critical_bh(&pxmitpriv->lock, &irql);
+ if ((pfirstframe->attrib.ether_type != 0x0806) &&
+ (pfirstframe->attrib.ether_type != 0x888e) &&
+ (pfirstframe->attrib.ether_type != 0x88b4) &&
+ (pfirstframe->attrib.dhcp_pkt != 1))
+ rtw_issue_addbareq_cmd(adapt, pfirstframe);
+ /* 3 3. update first frame txdesc */
+ if ((pbuf_tail % bulksize) == 0) {
+ /* remove pkt_offset */
+ pbuf_tail -= PACKET_OFFSET_SZ;
+ pfirstframe->buf_addr += PACKET_OFFSET_SZ;
+ pfirstframe->pkt_offset--;
+ }
+
+ update_txdesc(pfirstframe, pfirstframe->buf_addr, pfirstframe->attrib.last_txcmdsz, true);
+
+ /* 3 4. write xmit buffer to USB FIFO */
+ ff_hwaddr = rtw_get_ff_hwaddr(pfirstframe);
+ rtw_write_port(adapt, ff_hwaddr, pbuf_tail, (u8 *)pxmitbuf);
+
+ /* 3 5. update statisitc */
+ pbuf_tail -= (pfirstframe->agg_num * TXDESC_SIZE);
+ pbuf_tail -= (pfirstframe->pkt_offset * PACKET_OFFSET_SZ);
+
+ rtw_count_tx_stats(adapt, pfirstframe, pbuf_tail);
+
+ rtw_free_xmitframe(pxmitpriv, pfirstframe);
+
+ return true;
+}
+
+static s32 xmitframe_direct(struct adapter *adapt, struct xmit_frame *pxmitframe)
+{
+ s32 res = _SUCCESS;
+
+ res = rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe);
+ if (res == _SUCCESS)
+ rtw_dump_xframe(adapt, pxmitframe);
+ else
+ DBG_88E("==> %s xmitframe_coalsece failed\n", __func__);
+ return res;
+}
+
+/*
+ * Return
+ * true dump packet directly
+ * false enqueue packet
+ */
+static s32 pre_xmitframe(struct adapter *adapt, struct xmit_frame *pxmitframe)
+{
+ unsigned long irql;
+ s32 res;
+ struct xmit_buf *pxmitbuf = NULL;
+ struct xmit_priv *pxmitpriv = &adapt->xmitpriv;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+ struct mlme_priv *pmlmepriv = &adapt->mlmepriv;
+
+ _enter_critical_bh(&pxmitpriv->lock, &irql);
+
+ if (rtw_txframes_sta_ac_pending(adapt, pattrib) > 0)
+ goto enqueue;
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true)
+ goto enqueue;
+
+ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+ if (pxmitbuf == NULL)
+ goto enqueue;
+
+ _exit_critical_bh(&pxmitpriv->lock, &irql);
+
+ pxmitframe->pxmitbuf = pxmitbuf;
+ pxmitframe->buf_addr = pxmitbuf->pbuf;
+ pxmitbuf->priv_data = pxmitframe;
+
+ if (xmitframe_direct(adapt, pxmitframe) != _SUCCESS) {
+ rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
+ }
+
+ return true;
+
+enqueue:
+ res = rtw_xmitframe_enqueue(adapt, pxmitframe);
+ _exit_critical_bh(&pxmitpriv->lock, &irql);
+
+ if (res != _SUCCESS) {
+ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("pre_xmitframe: enqueue xmitframe fail\n"));
+ rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+ /* Trick, make the statistics correct */
+ pxmitpriv->tx_pkts--;
+ pxmitpriv->tx_drop++;
+ return true;
+ }
+
+ return false;
+}
+
+s32 rtl8188eu_mgnt_xmit(struct adapter *adapt, struct xmit_frame *pmgntframe)
+{
+ return rtw_dump_xframe(adapt, pmgntframe);
+}
+
+/*
+ * Return
+ * true dump packet directly ok
+ * false temporary can't transmit packets to hardware
+ */
+s32 rtl8188eu_hal_xmit(struct adapter *adapt, struct xmit_frame *pxmitframe)
+{
+ return pre_xmitframe(adapt, pxmitframe);
+}
diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c
new file mode 100644
index 00000000000..5e656ce4540
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c
@@ -0,0 +1,2346 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _HCI_HAL_INIT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_efuse.h>
+
+#include <rtl8188e_hal.h>
+#include <rtl8188e_led.h>
+#include <rtw_iol.h>
+#include <usb_ops.h>
+#include <usb_hal.h>
+#include <usb_osintf.h>
+
+#define HAL_MAC_ENABLE 1
+#define HAL_BB_ENABLE 1
+#define HAL_RF_ENABLE 1
+
+static void _ConfigNormalChipOutEP_8188E(struct adapter *adapt, u8 NumOutPipe)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+
+ switch (NumOutPipe) {
+ case 3:
+ haldata->OutEpQueueSel = TX_SELE_HQ | TX_SELE_LQ | TX_SELE_NQ;
+ haldata->OutEpNumber = 3;
+ break;
+ case 2:
+ haldata->OutEpQueueSel = TX_SELE_HQ | TX_SELE_NQ;
+ haldata->OutEpNumber = 2;
+ break;
+ case 1:
+ haldata->OutEpQueueSel = TX_SELE_HQ;
+ haldata->OutEpNumber = 1;
+ break;
+ default:
+ break;
+ }
+ DBG_88E("%s OutEpQueueSel(0x%02x), OutEpNumber(%d)\n", __func__, haldata->OutEpQueueSel, haldata->OutEpNumber);
+}
+
+static bool HalUsbSetQueuePipeMapping8188EUsb(struct adapter *adapt, u8 NumInPipe, u8 NumOutPipe)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ bool result = false;
+
+ _ConfigNormalChipOutEP_8188E(adapt, NumOutPipe);
+
+ /* Normal chip with one IN and one OUT doesn't have interrupt IN EP. */
+ if (1 == haldata->OutEpNumber) {
+ if (1 != NumInPipe)
+ return result;
+ }
+
+ /* All config other than above support one Bulk IN and one Interrupt IN. */
+
+ result = Hal_MappingOutPipe(adapt, NumOutPipe);
+
+ return result;
+}
+
+static void rtl8188eu_interface_configure(struct adapter *adapt)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapt);
+
+ if (pdvobjpriv->ishighspeed)
+ haldata->UsbBulkOutSize = USB_HIGH_SPEED_BULK_SIZE;/* 512 bytes */
+ else
+ haldata->UsbBulkOutSize = USB_FULL_SPEED_BULK_SIZE;/* 64 bytes */
+
+ haldata->interfaceIndex = pdvobjpriv->InterfaceNumber;
+
+ haldata->UsbTxAggMode = 1;
+ haldata->UsbTxAggDescNum = 0x6; /* only 4 bits */
+
+ haldata->UsbRxAggMode = USB_RX_AGG_DMA;/* USB_RX_AGG_DMA; */
+ haldata->UsbRxAggBlockCount = 8; /* unit : 512b */
+ haldata->UsbRxAggBlockTimeout = 0x6;
+ haldata->UsbRxAggPageCount = 48; /* uint :128 b 0x0A; 10 = MAX_RX_DMA_BUFFER_SIZE/2/haldata->UsbBulkOutSize */
+ haldata->UsbRxAggPageTimeout = 0x4; /* 6, absolute time = 34ms/(2^6) */
+
+ HalUsbSetQueuePipeMapping8188EUsb(adapt,
+ pdvobjpriv->RtNumInPipes, pdvobjpriv->RtNumOutPipes);
+}
+
+static u32 rtl8188eu_InitPowerOn(struct adapter *adapt)
+{
+ u16 value16;
+ /* HW Power on sequence */
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ if (haldata->bMacPwrCtrlOn)
+ return _SUCCESS;
+
+ if (!HalPwrSeqCmdParsing(adapt, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_PWR_ON_FLOW)) {
+ DBG_88E(KERN_ERR "%s: run power on flow fail\n", __func__);
+ return _FAIL;
+ }
+
+ /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */
+ /* Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. */
+ rtw_write16(adapt, REG_CR, 0x00); /* suggseted by zhouzhou, by page, 20111230 */
+
+ /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */
+ value16 = rtw_read16(adapt, REG_CR);
+ value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN
+ | PROTOCOL_EN | SCHEDULE_EN | ENSEC | CALTMR_EN);
+ /* for SDIO - Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. */
+
+ rtw_write16(adapt, REG_CR, value16);
+ haldata->bMacPwrCtrlOn = true;
+
+ return _SUCCESS;
+}
+
+/* Shall USB interface init this? */
+static void _InitInterrupt(struct adapter *Adapter)
+{
+ u32 imr, imr_ex;
+ u8 usb_opt;
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+
+ /* HISR write one to clear */
+ rtw_write32(Adapter, REG_HISR_88E, 0xFFFFFFFF);
+ /* HIMR - */
+ imr = IMR_PSTIMEOUT_88E | IMR_TBDER_88E | IMR_CPWM_88E | IMR_CPWM2_88E;
+ rtw_write32(Adapter, REG_HIMR_88E, imr);
+ haldata->IntrMask[0] = imr;
+
+ imr_ex = IMR_TXERR_88E | IMR_RXERR_88E | IMR_TXFOVW_88E | IMR_RXFOVW_88E;
+ rtw_write32(Adapter, REG_HIMRE_88E, imr_ex);
+ haldata->IntrMask[1] = imr_ex;
+
+ /* REG_USB_SPECIAL_OPTION - BIT(4) */
+ /* 0; Use interrupt endpoint to upload interrupt pkt */
+ /* 1; Use bulk endpoint to upload interrupt pkt, */
+ usb_opt = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION);
+
+ if (!adapter_to_dvobj(Adapter)->ishighspeed)
+ usb_opt = usb_opt & (~INT_BULK_SEL);
+ else
+ usb_opt = usb_opt | (INT_BULK_SEL);
+
+ rtw_write8(Adapter, REG_USB_SPECIAL_OPTION, usb_opt);
+}
+
+static void _InitQueueReservedPage(struct adapter *Adapter)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+ struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+ u32 numHQ = 0;
+ u32 numLQ = 0;
+ u32 numNQ = 0;
+ u32 numPubQ;
+ u32 value32;
+ u8 value8;
+ bool bWiFiConfig = pregistrypriv->wifi_spec;
+
+ if (bWiFiConfig) {
+ if (haldata->OutEpQueueSel & TX_SELE_HQ)
+ numHQ = 0x29;
+
+ if (haldata->OutEpQueueSel & TX_SELE_LQ)
+ numLQ = 0x1C;
+
+ /* NOTE: This step shall be proceed before writting REG_RQPN. */
+ if (haldata->OutEpQueueSel & TX_SELE_NQ)
+ numNQ = 0x1C;
+ value8 = (u8)_NPQ(numNQ);
+ rtw_write8(Adapter, REG_RQPN_NPQ, value8);
+
+ numPubQ = 0xA8 - numHQ - numLQ - numNQ;
+
+ /* TX DMA */
+ value32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN;
+ rtw_write32(Adapter, REG_RQPN, value32);
+ } else {
+ rtw_write16(Adapter, REG_RQPN_NPQ, 0x0000);/* Just follow MP Team,??? Georgia 03/28 */
+ rtw_write16(Adapter, REG_RQPN_NPQ, 0x0d);
+ rtw_write32(Adapter, REG_RQPN, 0x808E000d);/* reserve 7 page for LPS */
+ }
+}
+
+static void _InitTxBufferBoundary(struct adapter *Adapter, u8 txpktbuf_bndy)
+{
+ rtw_write8(Adapter, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy);
+ rtw_write8(Adapter, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
+ rtw_write8(Adapter, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy);
+ rtw_write8(Adapter, REG_TRXFF_BNDY, txpktbuf_bndy);
+ rtw_write8(Adapter, REG_TDECTRL+1, txpktbuf_bndy);
+}
+
+static void _InitPageBoundary(struct adapter *Adapter)
+{
+ /* RX Page Boundary */
+ /* */
+ u16 rxff_bndy = MAX_RX_DMA_BUFFER_SIZE_88E-1;
+
+ rtw_write16(Adapter, (REG_TRXFF_BNDY + 2), rxff_bndy);
+}
+
+static void _InitNormalChipRegPriority(struct adapter *Adapter, u16 beQ,
+ u16 bkQ, u16 viQ, u16 voQ, u16 mgtQ,
+ u16 hiQ)
+{
+ u16 value16 = (rtw_read16(Adapter, REG_TRXDMA_CTRL) & 0x7);
+
+ value16 |= _TXDMA_BEQ_MAP(beQ) | _TXDMA_BKQ_MAP(bkQ) |
+ _TXDMA_VIQ_MAP(viQ) | _TXDMA_VOQ_MAP(voQ) |
+ _TXDMA_MGQ_MAP(mgtQ) | _TXDMA_HIQ_MAP(hiQ);
+
+ rtw_write16(Adapter, REG_TRXDMA_CTRL, value16);
+}
+
+static void _InitNormalChipOneOutEpPriority(struct adapter *Adapter)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+
+ u16 value = 0;
+ switch (haldata->OutEpQueueSel) {
+ case TX_SELE_HQ:
+ value = QUEUE_HIGH;
+ break;
+ case TX_SELE_LQ:
+ value = QUEUE_LOW;
+ break;
+ case TX_SELE_NQ:
+ value = QUEUE_NORMAL;
+ break;
+ default:
+ break;
+ }
+ _InitNormalChipRegPriority(Adapter, value, value, value, value,
+ value, value);
+}
+
+static void _InitNormalChipTwoOutEpPriority(struct adapter *Adapter)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+ struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+ u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ;
+ u16 valueHi = 0;
+ u16 valueLow = 0;
+
+ switch (haldata->OutEpQueueSel) {
+ case (TX_SELE_HQ | TX_SELE_LQ):
+ valueHi = QUEUE_HIGH;
+ valueLow = QUEUE_LOW;
+ break;
+ case (TX_SELE_NQ | TX_SELE_LQ):
+ valueHi = QUEUE_NORMAL;
+ valueLow = QUEUE_LOW;
+ break;
+ case (TX_SELE_HQ | TX_SELE_NQ):
+ valueHi = QUEUE_HIGH;
+ valueLow = QUEUE_NORMAL;
+ break;
+ default:
+ break;
+ }
+
+ if (!pregistrypriv->wifi_spec) {
+ beQ = valueLow;
+ bkQ = valueLow;
+ viQ = valueHi;
+ voQ = valueHi;
+ mgtQ = valueHi;
+ hiQ = valueHi;
+ } else {/* for WMM ,CONFIG_OUT_EP_WIFI_MODE */
+ beQ = valueLow;
+ bkQ = valueHi;
+ viQ = valueHi;
+ voQ = valueLow;
+ mgtQ = valueHi;
+ hiQ = valueHi;
+ }
+ _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ);
+}
+
+static void _InitNormalChipThreeOutEpPriority(struct adapter *Adapter)
+{
+ struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+ u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ;
+
+ if (!pregistrypriv->wifi_spec) {/* typical setting */
+ beQ = QUEUE_LOW;
+ bkQ = QUEUE_LOW;
+ viQ = QUEUE_NORMAL;
+ voQ = QUEUE_HIGH;
+ mgtQ = QUEUE_HIGH;
+ hiQ = QUEUE_HIGH;
+ } else {/* for WMM */
+ beQ = QUEUE_LOW;
+ bkQ = QUEUE_NORMAL;
+ viQ = QUEUE_NORMAL;
+ voQ = QUEUE_HIGH;
+ mgtQ = QUEUE_HIGH;
+ hiQ = QUEUE_HIGH;
+ }
+ _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ);
+}
+
+static void _InitQueuePriority(struct adapter *Adapter)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+
+ switch (haldata->OutEpNumber) {
+ case 1:
+ _InitNormalChipOneOutEpPriority(Adapter);
+ break;
+ case 2:
+ _InitNormalChipTwoOutEpPriority(Adapter);
+ break;
+ case 3:
+ _InitNormalChipThreeOutEpPriority(Adapter);
+ break;
+ default:
+ break;
+ }
+}
+
+static void _InitNetworkType(struct adapter *Adapter)
+{
+ u32 value32;
+
+ value32 = rtw_read32(Adapter, REG_CR);
+ /* TODO: use the other function to set network type */
+ value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AP);
+
+ rtw_write32(Adapter, REG_CR, value32);
+}
+
+static void _InitTransferPageSize(struct adapter *Adapter)
+{
+ /* Tx page size is always 128. */
+
+ u8 value8;
+ value8 = _PSRX(PBP_128) | _PSTX(PBP_128);
+ rtw_write8(Adapter, REG_PBP, value8);
+}
+
+static void _InitDriverInfoSize(struct adapter *Adapter, u8 drvInfoSize)
+{
+ rtw_write8(Adapter, REG_RX_DRVINFO_SZ, drvInfoSize);
+}
+
+static void _InitWMACSetting(struct adapter *Adapter)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+
+ haldata->ReceiveConfig = RCR_AAP | RCR_APM | RCR_AM | RCR_AB |
+ RCR_CBSSID_DATA | RCR_CBSSID_BCN |
+ RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL |
+ RCR_APP_MIC | RCR_APP_PHYSTS;
+
+ /* some REG_RCR will be modified later by phy_ConfigMACWithHeaderFile() */
+ rtw_write32(Adapter, REG_RCR, haldata->ReceiveConfig);
+
+ /* Accept all multicast address */
+ rtw_write32(Adapter, REG_MAR, 0xFFFFFFFF);
+ rtw_write32(Adapter, REG_MAR + 4, 0xFFFFFFFF);
+}
+
+static void _InitAdaptiveCtrl(struct adapter *Adapter)
+{
+ u16 value16;
+ u32 value32;
+
+ /* Response Rate Set */
+ value32 = rtw_read32(Adapter, REG_RRSR);
+ value32 &= ~RATE_BITMAP_ALL;
+ value32 |= RATE_RRSR_CCK_ONLY_1M;
+ rtw_write32(Adapter, REG_RRSR, value32);
+
+ /* CF-END Threshold */
+
+ /* SIFS (used in NAV) */
+ value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10);
+ rtw_write16(Adapter, REG_SPEC_SIFS, value16);
+
+ /* Retry Limit */
+ value16 = _LRL(0x30) | _SRL(0x30);
+ rtw_write16(Adapter, REG_RL, value16);
+}
+
+static void _InitEDCA(struct adapter *Adapter)
+{
+ /* Set Spec SIFS (used in NAV) */
+ rtw_write16(Adapter, REG_SPEC_SIFS, 0x100a);
+ rtw_write16(Adapter, REG_MAC_SPEC_SIFS, 0x100a);
+
+ /* Set SIFS for CCK */
+ rtw_write16(Adapter, REG_SIFS_CTX, 0x100a);
+
+ /* Set SIFS for OFDM */
+ rtw_write16(Adapter, REG_SIFS_TRX, 0x100a);
+
+ /* TXOP */
+ rtw_write32(Adapter, REG_EDCA_BE_PARAM, 0x005EA42B);
+ rtw_write32(Adapter, REG_EDCA_BK_PARAM, 0x0000A44F);
+ rtw_write32(Adapter, REG_EDCA_VI_PARAM, 0x005EA324);
+ rtw_write32(Adapter, REG_EDCA_VO_PARAM, 0x002FA226);
+}
+
+static void _InitBeaconMaxError(struct adapter *Adapter, bool InfraMode)
+{
+}
+
+static void _InitHWLed(struct adapter *Adapter)
+{
+ struct led_priv *pledpriv = &(Adapter->ledpriv);
+
+ if (pledpriv->LedStrategy != HW_LED)
+ return;
+
+/* HW led control */
+/* to do .... */
+/* must consider cases of antenna diversity/ commbo card/solo card/mini card */
+}
+
+static void _InitRDGSetting(struct adapter *Adapter)
+{
+ rtw_write8(Adapter, REG_RD_CTRL, 0xFF);
+ rtw_write16(Adapter, REG_RD_NAV_NXT, 0x200);
+ rtw_write8(Adapter, REG_RD_RESP_PKT_TH, 0x05);
+}
+
+static void _InitRxSetting(struct adapter *Adapter)
+{
+ rtw_write32(Adapter, REG_MACID, 0x87654321);
+ rtw_write32(Adapter, 0x0700, 0x87654321);
+}
+
+static void _InitRetryFunction(struct adapter *Adapter)
+{
+ u8 value8;
+
+ value8 = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL);
+ value8 |= EN_AMPDU_RTY_NEW;
+ rtw_write8(Adapter, REG_FWHW_TXQ_CTRL, value8);
+
+ /* Set ACK timeout */
+ rtw_write8(Adapter, REG_ACKTO, 0x40);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: usb_AggSettingTxUpdate()
+ *
+ * Overview: Seperate TX/RX parameters update independent for TP detection and
+ * dynamic TX/RX aggreagtion parameters update.
+ *
+ * Input: struct adapter *
+ *
+ * Output/Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 12/10/2010 MHC Seperate to smaller function.
+ *
+ *---------------------------------------------------------------------------*/
+static void usb_AggSettingTxUpdate(struct adapter *Adapter)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+ u32 value32;
+
+ if (Adapter->registrypriv.wifi_spec)
+ haldata->UsbTxAggMode = false;
+
+ if (haldata->UsbTxAggMode) {
+ value32 = rtw_read32(Adapter, REG_TDECTRL);
+ value32 = value32 & ~(BLK_DESC_NUM_MASK << BLK_DESC_NUM_SHIFT);
+ value32 |= ((haldata->UsbTxAggDescNum & BLK_DESC_NUM_MASK) << BLK_DESC_NUM_SHIFT);
+
+ rtw_write32(Adapter, REG_TDECTRL, value32);
+ }
+} /* usb_AggSettingTxUpdate */
+
+/*-----------------------------------------------------------------------------
+ * Function: usb_AggSettingRxUpdate()
+ *
+ * Overview: Seperate TX/RX parameters update independent for TP detection and
+ * dynamic TX/RX aggreagtion parameters update.
+ *
+ * Input: struct adapter *
+ *
+ * Output/Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 12/10/2010 MHC Seperate to smaller function.
+ *
+ *---------------------------------------------------------------------------*/
+static void
+usb_AggSettingRxUpdate(
+ struct adapter *Adapter
+ )
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+ u8 valueDMA;
+ u8 valueUSB;
+
+ valueDMA = rtw_read8(Adapter, REG_TRXDMA_CTRL);
+ valueUSB = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION);
+
+ switch (haldata->UsbRxAggMode) {
+ case USB_RX_AGG_DMA:
+ valueDMA |= RXDMA_AGG_EN;
+ valueUSB &= ~USB_AGG_EN;
+ break;
+ case USB_RX_AGG_USB:
+ valueDMA &= ~RXDMA_AGG_EN;
+ valueUSB |= USB_AGG_EN;
+ break;
+ case USB_RX_AGG_MIX:
+ valueDMA |= RXDMA_AGG_EN;
+ valueUSB |= USB_AGG_EN;
+ break;
+ case USB_RX_AGG_DISABLE:
+ default:
+ valueDMA &= ~RXDMA_AGG_EN;
+ valueUSB &= ~USB_AGG_EN;
+ break;
+ }
+
+ rtw_write8(Adapter, REG_TRXDMA_CTRL, valueDMA);
+ rtw_write8(Adapter, REG_USB_SPECIAL_OPTION, valueUSB);
+
+ switch (haldata->UsbRxAggMode) {
+ case USB_RX_AGG_DMA:
+ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, haldata->UsbRxAggPageCount);
+ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH+1, haldata->UsbRxAggPageTimeout);
+ break;
+ case USB_RX_AGG_USB:
+ rtw_write8(Adapter, REG_USB_AGG_TH, haldata->UsbRxAggBlockCount);
+ rtw_write8(Adapter, REG_USB_AGG_TO, haldata->UsbRxAggBlockTimeout);
+ break;
+ case USB_RX_AGG_MIX:
+ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, haldata->UsbRxAggPageCount);
+ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH+1, (haldata->UsbRxAggPageTimeout & 0x1F));/* 0x280[12:8] */
+ rtw_write8(Adapter, REG_USB_AGG_TH, haldata->UsbRxAggBlockCount);
+ rtw_write8(Adapter, REG_USB_AGG_TO, haldata->UsbRxAggBlockTimeout);
+ break;
+ case USB_RX_AGG_DISABLE:
+ default:
+ /* TODO: */
+ break;
+ }
+
+ switch (PBP_128) {
+ case PBP_128:
+ haldata->HwRxPageSize = 128;
+ break;
+ case PBP_64:
+ haldata->HwRxPageSize = 64;
+ break;
+ case PBP_256:
+ haldata->HwRxPageSize = 256;
+ break;
+ case PBP_512:
+ haldata->HwRxPageSize = 512;
+ break;
+ case PBP_1024:
+ haldata->HwRxPageSize = 1024;
+ break;
+ default:
+ break;
+ }
+} /* usb_AggSettingRxUpdate */
+
+static void InitUsbAggregationSetting(struct adapter *Adapter)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+
+ /* Tx aggregation setting */
+ usb_AggSettingTxUpdate(Adapter);
+
+ /* Rx aggregation setting */
+ usb_AggSettingRxUpdate(Adapter);
+
+ /* 201/12/10 MH Add for USB agg mode dynamic switch. */
+ haldata->UsbRxHighSpeedMode = false;
+}
+
+static void _InitOperationMode(struct adapter *Adapter)
+{
+}
+
+static void _InitBeaconParameters(struct adapter *Adapter)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+
+ rtw_write16(Adapter, REG_BCN_CTRL, 0x1010);
+
+ /* TODO: Remove these magic number */
+ rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0x6404);/* ms */
+ rtw_write8(Adapter, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);/* 5ms */
+ rtw_write8(Adapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); /* 2ms */
+
+ /* Suggested by designer timchen. Change beacon AIFS to the largest number */
+ /* beacause test chip does not contension before sending beacon. by tynli. 2009.11.03 */
+ rtw_write16(Adapter, REG_BCNTCFG, 0x660F);
+
+ haldata->RegBcnCtrlVal = rtw_read8(Adapter, REG_BCN_CTRL);
+ haldata->RegTxPause = rtw_read8(Adapter, REG_TXPAUSE);
+ haldata->RegFwHwTxQCtrl = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL+2);
+ haldata->RegReg542 = rtw_read8(Adapter, REG_TBTT_PROHIBIT+2);
+ haldata->RegCR_1 = rtw_read8(Adapter, REG_CR+1);
+}
+
+static void _BeaconFunctionEnable(struct adapter *Adapter,
+ bool Enable, bool Linked)
+{
+ rtw_write8(Adapter, REG_BCN_CTRL, (BIT4 | BIT3 | BIT1));
+
+ rtw_write8(Adapter, REG_RD_CTRL+1, 0x6F);
+}
+
+/* Set CCK and OFDM Block "ON" */
+static void _BBTurnOnBlock(struct adapter *Adapter)
+{
+ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bCCKEn, 0x1);
+ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bOFDMEn, 0x1);
+}
+
+enum {
+ Antenna_Lfet = 1,
+ Antenna_Right = 2,
+};
+
+static void _InitAntenna_Selection(struct adapter *Adapter)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+
+ if (haldata->AntDivCfg == 0)
+ return;
+ DBG_88E("==> %s ....\n", __func__);
+
+ rtw_write32(Adapter, REG_LEDCFG0, rtw_read32(Adapter, REG_LEDCFG0)|BIT23);
+ PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, BIT13, 0x01);
+
+ if (PHY_QueryBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300) == Antenna_A)
+ haldata->CurAntenna = Antenna_A;
+ else
+ haldata->CurAntenna = Antenna_B;
+ DBG_88E("%s,Cur_ant:(%x)%s\n", __func__, haldata->CurAntenna, (haldata->CurAntenna == Antenna_A) ? "Antenna_A" : "Antenna_B");
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: HwSuspendModeEnable92Cu()
+ *
+ * Overview: HW suspend mode switch.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 08/23/2010 MHC HW suspend mode switch test..
+ *---------------------------------------------------------------------------*/
+enum rt_rf_power_state RfOnOffDetect(struct adapter *adapt)
+{
+ u8 val8;
+ enum rt_rf_power_state rfpowerstate = rf_off;
+
+ if (adapt->pwrctrlpriv.bHWPowerdown) {
+ val8 = rtw_read8(adapt, REG_HSISR);
+ DBG_88E("pwrdown, 0x5c(BIT7)=%02x\n", val8);
+ rfpowerstate = (val8 & BIT7) ? rf_off : rf_on;
+ } else { /* rf on/off */
+ rtw_write8(adapt, REG_MAC_PINMUX_CFG, rtw_read8(adapt, REG_MAC_PINMUX_CFG)&~(BIT3));
+ val8 = rtw_read8(adapt, REG_GPIO_IO_SEL);
+ DBG_88E("GPIO_IN=%02x\n", val8);
+ rfpowerstate = (val8 & BIT3) ? rf_on : rf_off;
+ }
+ return rfpowerstate;
+} /* HalDetectPwrDownMode */
+
+static u32 rtl8188eu_hal_init(struct adapter *Adapter)
+{
+ u8 value8 = 0;
+ u16 value16;
+ u8 txpktbuf_bndy;
+ u32 status = _SUCCESS;
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+ struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv;
+ struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+ u32 init_start_time = rtw_get_current_time();
+
+ #define HAL_INIT_PROFILE_TAG(stage) do {} while (0)
+
+_func_enter_;
+
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BEGIN);
+
+ if (Adapter->pwrctrlpriv.bkeepfwalive) {
+ _ps_open_RF(Adapter);
+
+ if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) {
+ PHY_IQCalibrate_8188E(Adapter, true);
+ } else {
+ PHY_IQCalibrate_8188E(Adapter, false);
+ haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = true;
+ }
+
+ ODM_TXPowerTrackingCheck(&haldata->odmpriv);
+ PHY_LCCalibrate_8188E(Adapter);
+
+ goto exit;
+ }
+
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PW_ON);
+ status = rtl8188eu_InitPowerOn(Adapter);
+ if (status == _FAIL) {
+ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init power on!\n"));
+ goto exit;
+ }
+
+ /* Save target channel */
+ haldata->CurrentChannel = 6;/* default set to 6 */
+
+ if (pwrctrlpriv->reg_rfoff) {
+ pwrctrlpriv->rf_pwrstate = rf_off;
+ }
+
+ /* 2010/08/09 MH We need to check if we need to turnon or off RF after detecting */
+ /* HW GPIO pin. Before PHY_RFConfig8192C. */
+ /* 2010/08/26 MH If Efuse does not support sective suspend then disable the function. */
+
+ if (!pregistrypriv->wifi_spec) {
+ txpktbuf_bndy = TX_PAGE_BOUNDARY_88E;
+ } else {
+ /* for WMM */
+ txpktbuf_bndy = WMM_NORMAL_TX_PAGE_BOUNDARY_88E;
+ }
+
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC01);
+ _InitQueueReservedPage(Adapter);
+ _InitQueuePriority(Adapter);
+ _InitPageBoundary(Adapter);
+ _InitTransferPageSize(Adapter);
+
+ _InitTxBufferBoundary(Adapter, 0);
+
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_DOWNLOAD_FW);
+ if (Adapter->registrypriv.mp_mode == 1) {
+ _InitRxSetting(Adapter);
+ Adapter->bFWReady = false;
+ haldata->fw_ractrl = false;
+ } else {
+ status = rtl8188e_FirmwareDownload(Adapter);
+
+ if (status != _SUCCESS) {
+ DBG_88E("%s: Download Firmware failed!!\n", __func__);
+ Adapter->bFWReady = false;
+ haldata->fw_ractrl = false;
+ return status;
+ } else {
+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializeadapt8192CSdio(): Download Firmware Success!!\n"));
+ Adapter->bFWReady = true;
+ haldata->fw_ractrl = false;
+ }
+ }
+ rtl8188e_InitializeFirmwareVars(Adapter);
+
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MAC);
+#if (HAL_MAC_ENABLE == 1)
+ status = PHY_MACConfig8188E(Adapter);
+ if (status == _FAIL) {
+ DBG_88E(" ### Failed to init MAC ......\n ");
+ goto exit;
+ }
+#endif
+
+ /* */
+ /* d. Initialize BB related configurations. */
+ /* */
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BB);
+#if (HAL_BB_ENABLE == 1)
+ status = PHY_BBConfig8188E(Adapter);
+ if (status == _FAIL) {
+ DBG_88E(" ### Failed to init BB ......\n ");
+ goto exit;
+ }
+#endif
+
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_RF);
+#if (HAL_RF_ENABLE == 1)
+ status = PHY_RFConfig8188E(Adapter);
+ if (status == _FAIL) {
+ DBG_88E(" ### Failed to init RF ......\n ");
+ goto exit;
+ }
+#endif
+
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_EFUSE_PATCH);
+ status = rtl8188e_iol_efuse_patch(Adapter);
+ if (status == _FAIL) {
+ DBG_88E("%s rtl8188e_iol_efuse_patch failed\n", __func__);
+ goto exit;
+ }
+
+ _InitTxBufferBoundary(Adapter, txpktbuf_bndy);
+
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_LLTT);
+ status = InitLLTTable(Adapter, txpktbuf_bndy);
+ if (status == _FAIL) {
+ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init LLT table\n"));
+ goto exit;
+ }
+
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC02);
+ /* Get Rx PHY status in order to report RSSI and others. */
+ _InitDriverInfoSize(Adapter, DRVINFO_SZ);
+
+ _InitInterrupt(Adapter);
+ hal_init_macaddr(Adapter);/* set mac_address */
+ _InitNetworkType(Adapter);/* set msr */
+ _InitWMACSetting(Adapter);
+ _InitAdaptiveCtrl(Adapter);
+ _InitEDCA(Adapter);
+ _InitRetryFunction(Adapter);
+ InitUsbAggregationSetting(Adapter);
+ _InitOperationMode(Adapter);/* todo */
+ _InitBeaconParameters(Adapter);
+ _InitBeaconMaxError(Adapter, true);
+
+ /* */
+ /* Init CR MACTXEN, MACRXEN after setting RxFF boundary REG_TRXFF_BNDY to patch */
+ /* Hw bug which Hw initials RxFF boundry size to a value which is larger than the real Rx buffer size in 88E. */
+ /* */
+ /* Enable MACTXEN/MACRXEN block */
+ value16 = rtw_read16(Adapter, REG_CR);
+ value16 |= (MACTXEN | MACRXEN);
+ rtw_write8(Adapter, REG_CR, value16);
+
+ if (haldata->bRDGEnable)
+ _InitRDGSetting(Adapter);
+
+ /* Enable TX Report */
+ /* Enable Tx Report Timer */
+ value8 = rtw_read8(Adapter, REG_TX_RPT_CTRL);
+ rtw_write8(Adapter, REG_TX_RPT_CTRL, (value8|BIT1|BIT0));
+ /* Set MAX RPT MACID */
+ rtw_write8(Adapter, REG_TX_RPT_CTRL+1, 2);/* FOR sta mode ,0: bc/mc ,1:AP */
+ /* Tx RPT Timer. Unit: 32us */
+ rtw_write16(Adapter, REG_TX_RPT_TIME, 0xCdf0);
+
+ rtw_write8(Adapter, REG_EARLY_MODE_CONTROL, 0);
+
+ rtw_write16(Adapter, REG_PKT_VO_VI_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */
+ rtw_write16(Adapter, REG_PKT_BE_BK_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */
+
+ _InitHWLed(Adapter);
+
+ /* Keep RfRegChnlVal for later use. */
+ haldata->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, (enum rf_radio_path)0, RF_CHNLBW, bRFRegOffsetMask);
+ haldata->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, (enum rf_radio_path)1, RF_CHNLBW, bRFRegOffsetMask);
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_TURN_ON_BLOCK);
+ _BBTurnOnBlock(Adapter);
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY);
+ invalidate_cam_all(Adapter);
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11);
+ /* 2010/12/17 MH We need to set TX power according to EFUSE content at first. */
+ PHY_SetTxPowerLevel8188E(Adapter, haldata->CurrentChannel);
+
+/* Move by Neo for USB SS to below setp */
+/* _RfPowerSave(Adapter); */
+
+ _InitAntenna_Selection(Adapter);
+
+ /* */
+ /* Disable BAR, suggested by Scott */
+ /* 2010.04.09 add by hpfan */
+ /* */
+ rtw_write32(Adapter, REG_BAR_MODE_CTRL, 0x0201ffff);
+
+ /* HW SEQ CTRL */
+ /* set 0x0 to 0xFF by tynli. Default enable HW SEQ NUM. */
+ rtw_write8(Adapter, REG_HWSEQ_CTRL, 0xFF);
+
+ if (pregistrypriv->wifi_spec)
+ rtw_write16(Adapter, REG_FAST_EDCA_CTRL, 0);
+
+ /* Nav limit , suggest by scott */
+ rtw_write8(Adapter, 0x652, 0x0);
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM);
+ rtl8188e_InitHalDm(Adapter);
+
+ if (Adapter->registrypriv.mp_mode == 1) {
+ Adapter->mppriv.channel = haldata->CurrentChannel;
+ MPT_InitializeAdapter(Adapter, Adapter->mppriv.channel);
+ } else {
+ /* 2010/08/11 MH Merge from 8192SE for Minicard init. We need to confirm current radio status */
+ /* and then decide to enable RF or not.!!!??? For Selective suspend mode. We may not */
+ /* call initstruct adapter. May cause some problem?? */
+ /* Fix the bug that Hw/Sw radio off before S3/S4, the RF off action will not be executed */
+ /* in MgntActSet_RF_State() after wake up, because the value of haldata->eRFPowerState */
+ /* is the same as eRfOff, we should change it to eRfOn after we config RF parameters. */
+ /* Added by tynli. 2010.03.30. */
+ pwrctrlpriv->rf_pwrstate = rf_on;
+
+ /* enable Tx report. */
+ rtw_write8(Adapter, REG_FWHW_TXQ_CTRL+1, 0x0F);
+
+ /* Suggested by SD1 pisa. Added by tynli. 2011.10.21. */
+ rtw_write8(Adapter, REG_EARLY_MODE_CONTROL+3, 0x01);/* Pretx_en, for WEP/TKIP SEC */
+
+ /* tynli_test_tx_report. */
+ rtw_write16(Adapter, REG_TX_RPT_TIME, 0x3DF0);
+
+ /* enable tx DMA to drop the redundate data of packet */
+ rtw_write16(Adapter, REG_TXDMA_OFFSET_CHK, (rtw_read16(Adapter, REG_TXDMA_OFFSET_CHK) | DROP_DATA_EN));
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK);
+ /* 2010/08/26 MH Merge from 8192CE. */
+ if (pwrctrlpriv->rf_pwrstate == rf_on) {
+ if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) {
+ PHY_IQCalibrate_8188E(Adapter, true);
+ } else {
+ PHY_IQCalibrate_8188E(Adapter, false);
+ haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = true;
+ }
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_PW_TRACK);
+
+ ODM_TXPowerTrackingCheck(&haldata->odmpriv);
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK);
+ PHY_LCCalibrate_8188E(Adapter);
+ }
+ }
+
+/* HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PABIAS); */
+/* _InitPABias(Adapter); */
+ rtw_write8(Adapter, REG_USB_HRPWM, 0);
+
+ /* ack for xmit mgmt frames. */
+ rtw_write32(Adapter, REG_FWHW_TXQ_CTRL, rtw_read32(Adapter, REG_FWHW_TXQ_CTRL)|BIT(12));
+
+exit:
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END);
+
+ DBG_88E("%s in %dms\n", __func__, rtw_get_passing_time_ms(init_start_time));
+
+_func_exit_;
+
+ return status;
+}
+
+void _ps_open_RF(struct adapter *adapt)
+{
+ /* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */
+ /* phy_SsPwrSwitch92CU(adapt, rf_on, 1); */
+}
+
+static void _ps_close_RF(struct adapter *adapt)
+{
+ /* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */
+ /* phy_SsPwrSwitch92CU(adapt, rf_off, 1); */
+}
+
+static void CardDisableRTL8188EU(struct adapter *Adapter)
+{
+ u8 val8;
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+
+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("CardDisableRTL8188EU\n"));
+
+ /* Stop Tx Report Timer. 0x4EC[Bit1]=b'0 */
+ val8 = rtw_read8(Adapter, REG_TX_RPT_CTRL);
+ rtw_write8(Adapter, REG_TX_RPT_CTRL, val8&(~BIT1));
+
+ /* stop rx */
+ rtw_write8(Adapter, REG_CR, 0x0);
+
+ /* Run LPS WL RFOFF flow */
+ HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_LPS_ENTER_FLOW);
+
+ /* 2. 0x1F[7:0] = 0 turn off RF */
+
+ val8 = rtw_read8(Adapter, REG_MCUFWDL);
+ if ((val8 & RAM_DL_SEL) && Adapter->bFWReady) { /* 8051 RAM code */
+ /* Reset MCU 0x2[10]=0. */
+ val8 = rtw_read8(Adapter, REG_SYS_FUNC_EN+1);
+ val8 &= ~BIT(2); /* 0x2[10], FEN_CPUEN */
+ rtw_write8(Adapter, REG_SYS_FUNC_EN+1, val8);
+ }
+
+ /* reset MCU ready status */
+ rtw_write8(Adapter, REG_MCUFWDL, 0);
+
+ /* YJ,add,111212 */
+ /* Disable 32k */
+ val8 = rtw_read8(Adapter, REG_32K_CTRL);
+ rtw_write8(Adapter, REG_32K_CTRL, val8&(~BIT0));
+
+ /* Card disable power action flow */
+ HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_DISABLE_FLOW);
+
+ /* Reset MCU IO Wrapper */
+ val8 = rtw_read8(Adapter, REG_RSV_CTRL+1);
+ rtw_write8(Adapter, REG_RSV_CTRL+1, (val8&(~BIT3)));
+ val8 = rtw_read8(Adapter, REG_RSV_CTRL+1);
+ rtw_write8(Adapter, REG_RSV_CTRL+1, val8|BIT3);
+
+ /* YJ,test add, 111207. For Power Consumption. */
+ val8 = rtw_read8(Adapter, GPIO_IN);
+ rtw_write8(Adapter, GPIO_OUT, val8);
+ rtw_write8(Adapter, GPIO_IO_SEL, 0xFF);/* Reg0x46 */
+
+ val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL);
+ rtw_write8(Adapter, REG_GPIO_IO_SEL, (val8<<4));
+ val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL+1);
+ rtw_write8(Adapter, REG_GPIO_IO_SEL+1, val8|0x0F);/* Reg0x43 */
+ rtw_write32(Adapter, REG_BB_PAD_CTRL, 0x00080808);/* set LNA ,TRSW,EX_PA Pin to output mode */
+ haldata->bMacPwrCtrlOn = false;
+ Adapter->bFWReady = false;
+}
+static void rtl8192cu_hw_power_down(struct adapter *adapt)
+{
+ /* 2010/-8/09 MH For power down module, we need to enable register block contrl reg at 0x1c. */
+ /* Then enable power down control bit of register 0x04 BIT4 and BIT15 as 1. */
+
+ /* Enable register area 0x0-0xc. */
+ rtw_write8(adapt, REG_RSV_CTRL, 0x0);
+ rtw_write16(adapt, REG_APS_FSMCO, 0x8812);
+}
+
+static u32 rtl8188eu_hal_deinit(struct adapter *Adapter)
+{
+
+ DBG_88E("==> %s\n", __func__);
+
+ rtw_write32(Adapter, REG_HIMR_88E, IMR_DISABLED_88E);
+ rtw_write32(Adapter, REG_HIMRE_88E, IMR_DISABLED_88E);
+
+ DBG_88E("bkeepfwalive(%x)\n", Adapter->pwrctrlpriv.bkeepfwalive);
+ if (Adapter->pwrctrlpriv.bkeepfwalive) {
+ _ps_close_RF(Adapter);
+ if ((Adapter->pwrctrlpriv.bHWPwrPindetect) && (Adapter->pwrctrlpriv.bHWPowerdown))
+ rtl8192cu_hw_power_down(Adapter);
+ } else {
+ if (Adapter->hw_init_completed) {
+ CardDisableRTL8188EU(Adapter);
+
+ if ((Adapter->pwrctrlpriv.bHWPwrPindetect) && (Adapter->pwrctrlpriv.bHWPowerdown))
+ rtl8192cu_hw_power_down(Adapter);
+ }
+ }
+ return _SUCCESS;
+ }
+
+static unsigned int rtl8188eu_inirp_init(struct adapter *Adapter)
+{
+ u8 i;
+ struct recv_buf *precvbuf;
+ uint status;
+ struct intf_hdl *pintfhdl = &Adapter->iopriv.intf;
+ struct recv_priv *precvpriv = &(Adapter->recvpriv);
+ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+
+_func_enter_;
+
+ _read_port = pintfhdl->io_ops._read_port;
+
+ status = _SUCCESS;
+
+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+ ("===> usb_inirp_init\n"));
+
+ precvpriv->ff_hwaddr = RECV_BULK_IN_ADDR;
+
+ /* issue Rx irp to receive data */
+ precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+ for (i = 0; i < NR_RECVBUFF; i++) {
+ if (_read_port(pintfhdl, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf) == false) {
+ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("usb_rx_init: usb_read_port error\n"));
+ status = _FAIL;
+ goto exit;
+ }
+
+ precvbuf++;
+ precvpriv->free_recv_buf_queue_cnt--;
+ }
+
+exit:
+
+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("<=== usb_inirp_init\n"));
+
+_func_exit_;
+
+ return status;
+}
+
+static unsigned int rtl8188eu_inirp_deinit(struct adapter *Adapter)
+{
+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("\n ===> usb_rx_deinit\n"));
+
+ rtw_read_port_cancel(Adapter);
+
+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("\n <=== usb_rx_deinit\n"));
+
+ return _SUCCESS;
+}
+
+/* */
+/* */
+/* EEPROM/EFUSE Content Parsing */
+/* */
+/* */
+static void _ReadLEDSetting(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail)
+{
+ struct led_priv *pledpriv = &(Adapter->ledpriv);
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+
+ pledpriv->bRegUseLed = true;
+ pledpriv->LedStrategy = SW_LED_MODE1;
+ haldata->bLedOpenDrain = true;/* Support Open-drain arrangement for controlling the LED. */
+}
+
+static void Hal_EfuseParsePIDVID_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+
+ if (!AutoLoadFail) {
+ /* VID, PID */
+ haldata->EEPROMVID = EF2BYTE(*(__le16 *)&hwinfo[EEPROM_VID_88EU]);
+ haldata->EEPROMPID = EF2BYTE(*(__le16 *)&hwinfo[EEPROM_PID_88EU]);
+
+ /* Customer ID, 0x00 and 0xff are reserved for Realtek. */
+ haldata->EEPROMCustomerID = *(u8 *)&hwinfo[EEPROM_CUSTOMERID_88E];
+ haldata->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID;
+ } else {
+ haldata->EEPROMVID = EEPROM_Default_VID;
+ haldata->EEPROMPID = EEPROM_Default_PID;
+
+ /* Customer ID, 0x00 and 0xff are reserved for Realtek. */
+ haldata->EEPROMCustomerID = EEPROM_Default_CustomerID;
+ haldata->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID;
+ }
+
+ DBG_88E("VID = 0x%04X, PID = 0x%04X\n", haldata->EEPROMVID, haldata->EEPROMPID);
+ DBG_88E("Customer ID: 0x%02X, SubCustomer ID: 0x%02X\n", haldata->EEPROMCustomerID, haldata->EEPROMSubCustomerID);
+}
+
+static void Hal_EfuseParseMACAddr_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail)
+{
+ u16 i;
+ u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x88, 0x02};
+ struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(adapt);
+
+ if (AutoLoadFail) {
+ for (i = 0; i < 6; i++)
+ eeprom->mac_addr[i] = sMacAddr[i];
+ } else {
+ /* Read Permanent MAC address */
+ memcpy(eeprom->mac_addr, &hwinfo[EEPROM_MAC_ADDR_88EU], ETH_ALEN);
+ }
+ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_,
+ ("Hal_EfuseParseMACAddr_8188EU: Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ eeprom->mac_addr[0], eeprom->mac_addr[1],
+ eeprom->mac_addr[2], eeprom->mac_addr[3],
+ eeprom->mac_addr[4], eeprom->mac_addr[5]));
+}
+
+static void Hal_CustomizeByCustomerID_8188EU(struct adapter *adapt)
+{
+}
+
+static void
+readAdapterInfo_8188EU(
+ struct adapter *adapt
+ )
+{
+ struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(adapt);
+
+ /* parse the eeprom/efuse content */
+ Hal_EfuseParseIDCode88E(adapt, eeprom->efuse_eeprom_data);
+ Hal_EfuseParsePIDVID_8188EU(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+ Hal_EfuseParseMACAddr_8188EU(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+
+ Hal_ReadPowerSavingMode88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+ Hal_ReadTxPowerInfo88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+ Hal_EfuseParseEEPROMVer88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+ rtl8188e_EfuseParseChnlPlan(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+ Hal_EfuseParseXtal_8188E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+ Hal_EfuseParseCustomerID88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+ Hal_ReadAntennaDiversity88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+ Hal_EfuseParseBoardType88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+ Hal_ReadThermalMeter_88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+
+ /* */
+ /* The following part initialize some vars by PG info. */
+ /* */
+ Hal_InitChannelPlan(adapt);
+ Hal_CustomizeByCustomerID_8188EU(adapt);
+
+ _ReadLEDSetting(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+}
+
+static void _ReadPROMContent(
+ struct adapter *Adapter
+ )
+{
+ struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(Adapter);
+ u8 eeValue;
+
+ /* check system boot selection */
+ eeValue = rtw_read8(Adapter, REG_9346CR);
+ eeprom->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM) ? true : false;
+ eeprom->bautoload_fail_flag = (eeValue & EEPROM_EN) ? false : true;
+
+ DBG_88E("Boot from %s, Autoload %s !\n", (eeprom->EepromOrEfuse ? "EEPROM" : "EFUSE"),
+ (eeprom->bautoload_fail_flag ? "Fail" : "OK"));
+
+ Hal_InitPGData88E(Adapter);
+ readAdapterInfo_8188EU(Adapter);
+}
+
+static void _ReadRFType(struct adapter *Adapter)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+
+ haldata->rf_chip = RF_6052;
+}
+
+static int _ReadAdapterInfo8188EU(struct adapter *Adapter)
+{
+ u32 start = rtw_get_current_time();
+
+ MSG_88E("====> %s\n", __func__);
+
+ _ReadRFType(Adapter);/* rf_chip -> _InitRFType() */
+ _ReadPROMContent(Adapter);
+
+ MSG_88E("<==== %s in %d ms\n", __func__, rtw_get_passing_time_ms(start));
+
+ return _SUCCESS;
+}
+
+static void ReadAdapterInfo8188EU(struct adapter *Adapter)
+{
+ /* Read EEPROM size before call any EEPROM function */
+ Adapter->EepromAddressSize = GetEEPROMSize8188E(Adapter);
+
+ _ReadAdapterInfo8188EU(Adapter);
+}
+
+#define GPIO_DEBUG_PORT_NUM 0
+static void rtl8192cu_trigger_gpio_0(struct adapter *adapt)
+{
+}
+
+static void ResumeTxBeacon(struct adapter *adapt)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+
+ /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */
+ /* which should be read from register to a global variable. */
+
+ rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl) | BIT6);
+ haldata->RegFwHwTxQCtrl |= BIT6;
+ rtw_write8(adapt, REG_TBTT_PROHIBIT+1, 0xff);
+ haldata->RegReg542 |= BIT0;
+ rtw_write8(adapt, REG_TBTT_PROHIBIT+2, haldata->RegReg542);
+}
+
+static void StopTxBeacon(struct adapter *adapt)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+
+ /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */
+ /* which should be read from register to a global variable. */
+
+ rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl) & (~BIT6));
+ haldata->RegFwHwTxQCtrl &= (~BIT6);
+ rtw_write8(adapt, REG_TBTT_PROHIBIT+1, 0x64);
+ haldata->RegReg542 &= ~(BIT0);
+ rtw_write8(adapt, REG_TBTT_PROHIBIT+2, haldata->RegReg542);
+
+ /* todo: CheckFwRsvdPageContent(Adapter); 2010.06.23. Added by tynli. */
+}
+
+static void hw_var_set_opmode(struct adapter *Adapter, u8 variable, u8 *val)
+{
+ u8 val8;
+ u8 mode = *((u8 *)val);
+
+ /* disable Port0 TSF update */
+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4));
+
+ /* set net_type */
+ val8 = rtw_read8(Adapter, MSR)&0x0c;
+ val8 |= mode;
+ rtw_write8(Adapter, MSR, val8);
+
+ DBG_88E("%s()-%d mode = %d\n", __func__, __LINE__, mode);
+
+ if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) {
+ StopTxBeacon(Adapter);
+
+ rtw_write8(Adapter, REG_BCN_CTRL, 0x19);/* disable atim wnd */
+ } else if ((mode == _HW_STATE_ADHOC_)) {
+ ResumeTxBeacon(Adapter);
+ rtw_write8(Adapter, REG_BCN_CTRL, 0x1a);
+ } else if (mode == _HW_STATE_AP_) {
+ ResumeTxBeacon(Adapter);
+
+ rtw_write8(Adapter, REG_BCN_CTRL, 0x12);
+
+ /* Set RCR */
+ rtw_write32(Adapter, REG_RCR, 0x7000208e);/* CBSSID_DATA must set to 0,reject ICV_ERR packet */
+ /* enable to rx data frame */
+ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
+ /* enable to rx ps-poll */
+ rtw_write16(Adapter, REG_RXFLTMAP1, 0x0400);
+
+ /* Beacon Control related register for first time */
+ rtw_write8(Adapter, REG_BCNDMATIM, 0x02); /* 2ms */
+
+ rtw_write8(Adapter, REG_ATIMWND, 0x0a); /* 10ms */
+ rtw_write16(Adapter, REG_BCNTCFG, 0x00);
+ rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0xff04);
+ rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);/* +32767 (~32ms) */
+
+ /* reset TSF */
+ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0));
+
+ /* BIT3 - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 */
+ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM) | BIT(3) | BIT(4));
+
+ /* enable BCN0 Function for if1 */
+ /* don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) */
+ rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP|EN_BCN_FUNCTION | BIT(1)));
+
+ /* dis BCN1 ATIM WND if if2 is station */
+ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1) | BIT(0));
+ }
+}
+
+static void hw_var_set_macaddr(struct adapter *Adapter, u8 variable, u8 *val)
+{
+ u8 idx = 0;
+ u32 reg_macid;
+
+ reg_macid = REG_MACID;
+
+ for (idx = 0; idx < 6; idx++)
+ rtw_write8(Adapter, (reg_macid+idx), val[idx]);
+}
+
+static void hw_var_set_bssid(struct adapter *Adapter, u8 variable, u8 *val)
+{
+ u8 idx = 0;
+ u32 reg_bssid;
+
+ reg_bssid = REG_BSSID;
+
+ for (idx = 0; idx < 6; idx++)
+ rtw_write8(Adapter, (reg_bssid+idx), val[idx]);
+}
+
+static void hw_var_set_bcn_func(struct adapter *Adapter, u8 variable, u8 *val)
+{
+ u32 bcn_ctrl_reg;
+
+ bcn_ctrl_reg = REG_BCN_CTRL;
+
+ if (*((u8 *)val))
+ rtw_write8(Adapter, bcn_ctrl_reg, (EN_BCN_FUNCTION | EN_TXBCN_RPT));
+ else
+ rtw_write8(Adapter, bcn_ctrl_reg, rtw_read8(Adapter, bcn_ctrl_reg)&(~(EN_BCN_FUNCTION | EN_TXBCN_RPT)));
+}
+
+static void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+ struct dm_priv *pdmpriv = &haldata->dmpriv;
+ struct odm_dm_struct *podmpriv = &haldata->odmpriv;
+_func_enter_;
+
+ switch (variable) {
+ case HW_VAR_MEDIA_STATUS:
+ {
+ u8 val8;
+
+ val8 = rtw_read8(Adapter, MSR)&0x0c;
+ val8 |= *((u8 *)val);
+ rtw_write8(Adapter, MSR, val8);
+ }
+ break;
+ case HW_VAR_MEDIA_STATUS1:
+ {
+ u8 val8;
+
+ val8 = rtw_read8(Adapter, MSR) & 0x03;
+ val8 |= *((u8 *)val) << 2;
+ rtw_write8(Adapter, MSR, val8);
+ }
+ break;
+ case HW_VAR_SET_OPMODE:
+ hw_var_set_opmode(Adapter, variable, val);
+ break;
+ case HW_VAR_MAC_ADDR:
+ hw_var_set_macaddr(Adapter, variable, val);
+ break;
+ case HW_VAR_BSSID:
+ hw_var_set_bssid(Adapter, variable, val);
+ break;
+ case HW_VAR_BASIC_RATE:
+ {
+ u16 BrateCfg = 0;
+ u8 RateIndex = 0;
+
+ /* 2007.01.16, by Emily */
+ /* Select RRSR (in Legacy-OFDM and CCK) */
+ /* For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. */
+ /* We do not use other rates. */
+ HalSetBrateCfg(Adapter, val, &BrateCfg);
+ DBG_88E("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", BrateCfg);
+
+ /* 2011.03.30 add by Luke Lee */
+ /* CCK 2M ACK should be disabled for some BCM and Atheros AP IOT */
+ /* because CCK 2M has poor TXEVM */
+ /* CCK 5.5M & 11M ACK should be enabled for better performance */
+
+ BrateCfg = (BrateCfg | 0xd) & 0x15d;
+ haldata->BasicRateSet = BrateCfg;
+
+ BrateCfg |= 0x01; /* default enable 1M ACK rate */
+ /* Set RRSR rate table. */
+ rtw_write8(Adapter, REG_RRSR, BrateCfg & 0xff);
+ rtw_write8(Adapter, REG_RRSR+1, (BrateCfg >> 8) & 0xff);
+ rtw_write8(Adapter, REG_RRSR+2, rtw_read8(Adapter, REG_RRSR+2)&0xf0);
+
+ /* Set RTS initial rate */
+ while (BrateCfg > 0x1) {
+ BrateCfg = (BrateCfg >> 1);
+ RateIndex++;
+ }
+ /* Ziv - Check */
+ rtw_write8(Adapter, REG_INIRTS_RATE_SEL, RateIndex);
+ }
+ break;
+ case HW_VAR_TXPAUSE:
+ rtw_write8(Adapter, REG_TXPAUSE, *((u8 *)val));
+ break;
+ case HW_VAR_BCN_FUNC:
+ hw_var_set_bcn_func(Adapter, variable, val);
+ break;
+ case HW_VAR_CORRECT_TSF:
+ {
+ u64 tsf;
+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ tsf = pmlmeext->TSFValue - rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024)) - 1024; /* us */
+
+ if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
+ StopTxBeacon(Adapter);
+
+ /* disable related TSF function */
+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(3)));
+
+ rtw_write32(Adapter, REG_TSFTR, tsf);
+ rtw_write32(Adapter, REG_TSFTR+4, tsf>>32);
+
+ /* enable related TSF function */
+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(3));
+
+ if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
+ ResumeTxBeacon(Adapter);
+ }
+ break;
+ case HW_VAR_CHECK_BSSID:
+ if (*((u8 *)val)) {
+ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN);
+ } else {
+ u32 val32;
+
+ val32 = rtw_read32(Adapter, REG_RCR);
+
+ val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+
+ rtw_write32(Adapter, REG_RCR, val32);
+ }
+ break;
+ case HW_VAR_MLME_DISCONNECT:
+ /* Set RCR to not to receive data frame when NO LINK state */
+ /* reject all data frames */
+ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00);
+
+ /* reset TSF */
+ rtw_write8(Adapter, REG_DUAL_TSF_RST, (BIT(0)|BIT(1)));
+
+ /* disable update TSF */
+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4));
+ break;
+ case HW_VAR_MLME_SITESURVEY:
+ if (*((u8 *)val)) { /* under sitesurvey */
+ /* config RCR to receive different BSSID & not to receive data frame */
+ u32 v = rtw_read32(Adapter, REG_RCR);
+ v &= ~(RCR_CBSSID_BCN);
+ rtw_write32(Adapter, REG_RCR, v);
+ /* reject all data frame */
+ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00);
+
+ /* disable update TSF */
+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4));
+ } else { /* sitesurvey done */
+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ if ((is_client_associated_to_ap(Adapter)) ||
+ ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) {
+ /* enable to rx data frame */
+ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
+
+ /* enable update TSF */
+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4)));
+ } else if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
+ /* enable update TSF */
+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4)));
+ }
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN);
+ } else {
+ if (Adapter->in_cta_test) {
+ u32 v = rtw_read32(Adapter, REG_RCR);
+ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/* RCR_ADF */
+ rtw_write32(Adapter, REG_RCR, v);
+ } else {
+ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN);
+ }
+ }
+ }
+ break;
+ case HW_VAR_MLME_JOIN:
+ {
+ u8 RetryLimit = 0x30;
+ u8 type = *((u8 *)val);
+ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv;
+
+ if (type == 0) { /* prepare to join */
+ /* enable to rx data frame.Accept all data frame */
+ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
+
+ if (Adapter->in_cta_test) {
+ u32 v = rtw_read32(Adapter, REG_RCR);
+ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/* RCR_ADF */
+ rtw_write32(Adapter, REG_RCR, v);
+ } else {
+ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN);
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+ RetryLimit = (haldata->CustomerID == RT_CID_CCX) ? 7 : 48;
+ else /* Ad-hoc Mode */
+ RetryLimit = 0x7;
+ } else if (type == 1) {
+ /* joinbss_event call back when join res < 0 */
+ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00);
+ } else if (type == 2) {
+ /* sta add event call back */
+ /* enable update TSF */
+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4)));
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE))
+ RetryLimit = 0x7;
+ }
+ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT);
+ }
+ break;
+ case HW_VAR_BEACON_INTERVAL:
+ rtw_write16(Adapter, REG_BCN_INTERVAL, *((u16 *)val));
+ break;
+ case HW_VAR_SLOT_TIME:
+ {
+ u8 u1bAIFS, aSifsTime;
+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ rtw_write8(Adapter, REG_SLOT, val[0]);
+
+ if (pmlmeinfo->WMM_enable == 0) {
+ if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
+ aSifsTime = 10;
+ else
+ aSifsTime = 16;
+
+ u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime);
+
+ /* <Roger_EXP> Temporary removed, 2008.06.20. */
+ rtw_write8(Adapter, REG_EDCA_VO_PARAM, u1bAIFS);
+ rtw_write8(Adapter, REG_EDCA_VI_PARAM, u1bAIFS);
+ rtw_write8(Adapter, REG_EDCA_BE_PARAM, u1bAIFS);
+ rtw_write8(Adapter, REG_EDCA_BK_PARAM, u1bAIFS);
+ }
+ }
+ break;
+ case HW_VAR_RESP_SIFS:
+ /* RESP_SIFS for CCK */
+ rtw_write8(Adapter, REG_R2T_SIFS, val[0]); /* SIFS_T2T_CCK (0x08) */
+ rtw_write8(Adapter, REG_R2T_SIFS+1, val[1]); /* SIFS_R2T_CCK(0x08) */
+ /* RESP_SIFS for OFDM */
+ rtw_write8(Adapter, REG_T2T_SIFS, val[2]); /* SIFS_T2T_OFDM (0x0a) */
+ rtw_write8(Adapter, REG_T2T_SIFS+1, val[3]); /* SIFS_R2T_OFDM(0x0a) */
+ break;
+ case HW_VAR_ACK_PREAMBLE:
+ {
+ u8 regTmp;
+ u8 bShortPreamble = *((bool *)val);
+ /* Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) */
+ regTmp = (haldata->nCur40MhzPrimeSC)<<5;
+ if (bShortPreamble)
+ regTmp |= 0x80;
+
+ rtw_write8(Adapter, REG_RRSR+2, regTmp);
+ }
+ break;
+ case HW_VAR_SEC_CFG:
+ rtw_write8(Adapter, REG_SECCFG, *((u8 *)val));
+ break;
+ case HW_VAR_DM_FLAG:
+ podmpriv->SupportAbility = *((u8 *)val);
+ break;
+ case HW_VAR_DM_FUNC_OP:
+ if (val[0])
+ podmpriv->BK_SupportAbility = podmpriv->SupportAbility;
+ else
+ podmpriv->SupportAbility = podmpriv->BK_SupportAbility;
+ break;
+ case HW_VAR_DM_FUNC_SET:
+ if (*((u32 *)val) == DYNAMIC_ALL_FUNC_ENABLE) {
+ pdmpriv->DMFlag = pdmpriv->InitDMFlag;
+ podmpriv->SupportAbility = pdmpriv->InitODMFlag;
+ } else {
+ podmpriv->SupportAbility |= *((u32 *)val);
+ }
+ break;
+ case HW_VAR_DM_FUNC_CLR:
+ podmpriv->SupportAbility &= *((u32 *)val);
+ break;
+ case HW_VAR_CAM_EMPTY_ENTRY:
+ {
+ u8 ucIndex = *((u8 *)val);
+ u8 i;
+ u32 ulCommand = 0;
+ u32 ulContent = 0;
+ u32 ulEncAlgo = CAM_AES;
+
+ for (i = 0; i < CAM_CONTENT_COUNT; i++) {
+ /* filled id in CAM config 2 byte */
+ if (i == 0)
+ ulContent |= (ucIndex & 0x03) | ((u16)(ulEncAlgo)<<2);
+ else
+ ulContent = 0;
+ /* polling bit, and No Write enable, and address */
+ ulCommand = CAM_CONTENT_COUNT*ucIndex+i;
+ ulCommand = ulCommand | CAM_POLLINIG|CAM_WRITE;
+ /* write content 0 is equall to mark invalid */
+ rtw_write32(Adapter, WCAMI, ulContent); /* delay_ms(40); */
+ rtw_write32(Adapter, RWCAM, ulCommand); /* delay_ms(40); */
+ }
+ }
+ break;
+ case HW_VAR_CAM_INVALID_ALL:
+ rtw_write32(Adapter, RWCAM, BIT(31)|BIT(30));
+ break;
+ case HW_VAR_CAM_WRITE:
+ {
+ u32 cmd;
+ u32 *cam_val = (u32 *)val;
+ rtw_write32(Adapter, WCAMI, cam_val[0]);
+
+ cmd = CAM_POLLINIG | CAM_WRITE | cam_val[1];
+ rtw_write32(Adapter, RWCAM, cmd);
+ }
+ break;
+ case HW_VAR_AC_PARAM_VO:
+ rtw_write32(Adapter, REG_EDCA_VO_PARAM, ((u32 *)(val))[0]);
+ break;
+ case HW_VAR_AC_PARAM_VI:
+ rtw_write32(Adapter, REG_EDCA_VI_PARAM, ((u32 *)(val))[0]);
+ break;
+ case HW_VAR_AC_PARAM_BE:
+ haldata->AcParam_BE = ((u32 *)(val))[0];
+ rtw_write32(Adapter, REG_EDCA_BE_PARAM, ((u32 *)(val))[0]);
+ break;
+ case HW_VAR_AC_PARAM_BK:
+ rtw_write32(Adapter, REG_EDCA_BK_PARAM, ((u32 *)(val))[0]);
+ break;
+ case HW_VAR_ACM_CTRL:
+ {
+ u8 acm_ctrl = *((u8 *)val);
+ u8 AcmCtrl = rtw_read8(Adapter, REG_ACMHWCTRL);
+
+ if (acm_ctrl > 1)
+ AcmCtrl = AcmCtrl | 0x1;
+
+ if (acm_ctrl & BIT(3))
+ AcmCtrl |= AcmHw_VoqEn;
+ else
+ AcmCtrl &= (~AcmHw_VoqEn);
+
+ if (acm_ctrl & BIT(2))
+ AcmCtrl |= AcmHw_ViqEn;
+ else
+ AcmCtrl &= (~AcmHw_ViqEn);
+
+ if (acm_ctrl & BIT(1))
+ AcmCtrl |= AcmHw_BeqEn;
+ else
+ AcmCtrl &= (~AcmHw_BeqEn);
+
+ DBG_88E("[HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl);
+ rtw_write8(Adapter, REG_ACMHWCTRL, AcmCtrl);
+ }
+ break;
+ case HW_VAR_AMPDU_MIN_SPACE:
+ {
+ u8 MinSpacingToSet;
+ u8 SecMinSpace;
+
+ MinSpacingToSet = *((u8 *)val);
+ if (MinSpacingToSet <= 7) {
+ switch (Adapter->securitypriv.dot11PrivacyAlgrthm) {
+ case _NO_PRIVACY_:
+ case _AES_:
+ SecMinSpace = 0;
+ break;
+ case _WEP40_:
+ case _WEP104_:
+ case _TKIP_:
+ case _TKIP_WTMIC_:
+ SecMinSpace = 6;
+ break;
+ default:
+ SecMinSpace = 7;
+ break;
+ }
+ if (MinSpacingToSet < SecMinSpace)
+ MinSpacingToSet = SecMinSpace;
+ rtw_write8(Adapter, REG_AMPDU_MIN_SPACE, (rtw_read8(Adapter, REG_AMPDU_MIN_SPACE) & 0xf8) | MinSpacingToSet);
+ }
+ }
+ break;
+ case HW_VAR_AMPDU_FACTOR:
+ {
+ u8 RegToSet_Normal[4] = {0x41, 0xa8, 0x72, 0xb9};
+ u8 FactorToSet;
+ u8 *pRegToSet;
+ u8 index = 0;
+
+ pRegToSet = RegToSet_Normal; /* 0xb972a841; */
+ FactorToSet = *((u8 *)val);
+ if (FactorToSet <= 3) {
+ FactorToSet = (1<<(FactorToSet + 2));
+ if (FactorToSet > 0xf)
+ FactorToSet = 0xf;
+
+ for (index = 0; index < 4; index++) {
+ if ((pRegToSet[index] & 0xf0) > (FactorToSet<<4))
+ pRegToSet[index] = (pRegToSet[index] & 0x0f) | (FactorToSet<<4);
+
+ if ((pRegToSet[index] & 0x0f) > FactorToSet)
+ pRegToSet[index] = (pRegToSet[index] & 0xf0) | (FactorToSet);
+
+ rtw_write8(Adapter, (REG_AGGLEN_LMT+index), pRegToSet[index]);
+ }
+ }
+ }
+ break;
+ case HW_VAR_RXDMA_AGG_PG_TH:
+ {
+ u8 threshold = *((u8 *)val);
+ if (threshold == 0)
+ threshold = haldata->UsbRxAggPageCount;
+ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, threshold);
+ }
+ break;
+ case HW_VAR_SET_RPWM:
+ break;
+ case HW_VAR_H2C_FW_PWRMODE:
+ {
+ u8 psmode = (*(u8 *)val);
+
+ /* Forece leave RF low power mode for 1T1R to prevent conficting setting in Fw power */
+ /* saving sequence. 2010.06.07. Added by tynli. Suggested by SD3 yschang. */
+ if ((psmode != PS_MODE_ACTIVE) && (!IS_92C_SERIAL(haldata->VersionID)))
+ ODM_RF_Saving(podmpriv, true);
+ rtl8188e_set_FwPwrMode_cmd(Adapter, psmode);
+ }
+ break;
+ case HW_VAR_H2C_FW_JOINBSSRPT:
+ {
+ u8 mstatus = (*(u8 *)val);
+ rtl8188e_set_FwJoinBssReport_cmd(Adapter, mstatus);
+ }
+ break;
+#ifdef CONFIG_88EU_P2P
+ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+ {
+ u8 p2p_ps_state = (*(u8 *)val);
+ rtl8188e_set_p2p_ps_offload_cmd(Adapter, p2p_ps_state);
+ }
+ break;
+#endif
+ case HW_VAR_INITIAL_GAIN:
+ {
+ struct rtw_dig *pDigTable = &podmpriv->DM_DigTable;
+ u32 rx_gain = ((u32 *)(val))[0];
+
+ if (rx_gain == 0xff) {/* restore rx gain */
+ ODM_Write_DIG(podmpriv, pDigTable->BackupIGValue);
+ } else {
+ pDigTable->BackupIGValue = pDigTable->CurIGValue;
+ ODM_Write_DIG(podmpriv, rx_gain);
+ }
+ }
+ break;
+ case HW_VAR_TRIGGER_GPIO_0:
+ rtl8192cu_trigger_gpio_0(Adapter);
+ break;
+ case HW_VAR_RPT_TIMER_SETTING:
+ {
+ u16 min_rpt_time = (*(u16 *)val);
+ ODM_RA_Set_TxRPT_Time(podmpriv, min_rpt_time);
+ }
+ break;
+ case HW_VAR_ANTENNA_DIVERSITY_SELECT:
+ {
+ u8 Optimum_antenna = (*(u8 *)val);
+ u8 Ant;
+ /* switch antenna to Optimum_antenna */
+ if (haldata->CurAntenna != Optimum_antenna) {
+ Ant = (Optimum_antenna == 2) ? MAIN_ANT : AUX_ANT;
+ ODM_UpdateRxIdleAnt_88E(&haldata->odmpriv, Ant);
+
+ haldata->CurAntenna = Optimum_antenna;
+ }
+ }
+ break;
+ case HW_VAR_EFUSE_BYTES: /* To set EFUE total used bytes, added by Roger, 2008.12.22. */
+ haldata->EfuseUsedBytes = *((u16 *)val);
+ break;
+ case HW_VAR_FIFO_CLEARN_UP:
+ {
+ struct pwrctrl_priv *pwrpriv = &Adapter->pwrctrlpriv;
+ u8 trycnt = 100;
+
+ /* pause tx */
+ rtw_write8(Adapter, REG_TXPAUSE, 0xff);
+
+ /* keep sn */
+ Adapter->xmitpriv.nqos_ssn = rtw_read16(Adapter, REG_NQOS_SEQ);
+
+ if (!pwrpriv->bkeepfwalive) {
+ /* RX DMA stop */
+ rtw_write32(Adapter, REG_RXPKT_NUM, (rtw_read32(Adapter, REG_RXPKT_NUM)|RW_RELEASE_EN));
+ do {
+ if (!(rtw_read32(Adapter, REG_RXPKT_NUM)&RXDMA_IDLE))
+ break;
+ } while (trycnt--);
+ if (trycnt == 0)
+ DBG_88E("Stop RX DMA failed......\n");
+
+ /* RQPN Load 0 */
+ rtw_write16(Adapter, REG_RQPN_NPQ, 0x0);
+ rtw_write32(Adapter, REG_RQPN, 0x80000000);
+ rtw_mdelay_os(10);
+ }
+ }
+ break;
+ case HW_VAR_CHECK_TXBUF:
+ break;
+ case HW_VAR_APFM_ON_MAC:
+ haldata->bMacPwrCtrlOn = *val;
+ DBG_88E("%s: bMacPwrCtrlOn=%d\n", __func__, haldata->bMacPwrCtrlOn);
+ break;
+ case HW_VAR_TX_RPT_MAX_MACID:
+ {
+ u8 maxMacid = *val;
+ DBG_88E("### MacID(%d),Set Max Tx RPT MID(%d)\n", maxMacid, maxMacid+1);
+ rtw_write8(Adapter, REG_TX_RPT_CTRL+1, maxMacid+1);
+ }
+ break;
+ case HW_VAR_H2C_MEDIA_STATUS_RPT:
+ rtl8188e_set_FwMediaStatus_cmd(Adapter , (*(__le16 *)val));
+ break;
+ case HW_VAR_BCN_VALID:
+ /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2, write 1 to clear, Clear by sw */
+ rtw_write8(Adapter, REG_TDECTRL+2, rtw_read8(Adapter, REG_TDECTRL+2) | BIT0);
+ break;
+ default:
+ break;
+ }
+_func_exit_;
+}
+
+static void GetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+ struct odm_dm_struct *podmpriv = &haldata->odmpriv;
+_func_enter_;
+
+ switch (variable) {
+ case HW_VAR_BASIC_RATE:
+ *((u16 *)(val)) = haldata->BasicRateSet;
+ case HW_VAR_TXPAUSE:
+ val[0] = rtw_read8(Adapter, REG_TXPAUSE);
+ break;
+ case HW_VAR_BCN_VALID:
+ /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 */
+ val[0] = (BIT0 & rtw_read8(Adapter, REG_TDECTRL+2)) ? true : false;
+ break;
+ case HW_VAR_DM_FLAG:
+ val[0] = podmpriv->SupportAbility;
+ break;
+ case HW_VAR_RF_TYPE:
+ val[0] = haldata->rf_type;
+ break;
+ case HW_VAR_FWLPS_RF_ON:
+ {
+ /* When we halt NIC, we should check if FW LPS is leave. */
+ if (Adapter->pwrctrlpriv.rf_pwrstate == rf_off) {
+ /* If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, */
+ /* because Fw is unload. */
+ val[0] = true;
+ } else {
+ u32 valRCR;
+ valRCR = rtw_read32(Adapter, REG_RCR);
+ valRCR &= 0x00070000;
+ if (valRCR)
+ val[0] = false;
+ else
+ val[0] = true;
+ }
+ }
+ break;
+ case HW_VAR_CURRENT_ANTENNA:
+ val[0] = haldata->CurAntenna;
+ break;
+ case HW_VAR_EFUSE_BYTES: /* To get EFUE total used bytes, added by Roger, 2008.12.22. */
+ *((u16 *)(val)) = haldata->EfuseUsedBytes;
+ break;
+ case HW_VAR_APFM_ON_MAC:
+ *val = haldata->bMacPwrCtrlOn;
+ break;
+ case HW_VAR_CHK_HI_QUEUE_EMPTY:
+ *val = ((rtw_read32(Adapter, REG_HGQ_INFORMATION)&0x0000ff00) == 0) ? true : false;
+ break;
+ default:
+ break;
+ }
+
+_func_exit_;
+}
+
+/* */
+/* Description: */
+/* Query setting of specified variable. */
+/* */
+static u8
+GetHalDefVar8188EUsb(
+ struct adapter *Adapter,
+ enum hal_def_variable eVariable,
+ void *pValue
+ )
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+ u8 bResult = _SUCCESS;
+
+ switch (eVariable) {
+ case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB:
+ {
+ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv;
+ struct sta_priv *pstapriv = &Adapter->stapriv;
+ struct sta_info *psta;
+ psta = rtw_get_stainfo(pstapriv, pmlmepriv->cur_network.network.MacAddress);
+ if (psta)
+ *((int *)pValue) = psta->rssi_stat.UndecoratedSmoothedPWDB;
+ }
+ break;
+ case HAL_DEF_IS_SUPPORT_ANT_DIV:
+ *((u8 *)pValue) = (haldata->AntDivCfg == 0) ? false : true;
+ break;
+ case HAL_DEF_CURRENT_ANTENNA:
+ *((u8 *)pValue) = haldata->CurAntenna;
+ break;
+ case HAL_DEF_DRVINFO_SZ:
+ *((u32 *)pValue) = DRVINFO_SZ;
+ break;
+ case HAL_DEF_MAX_RECVBUF_SZ:
+ *((u32 *)pValue) = MAX_RECVBUF_SZ;
+ break;
+ case HAL_DEF_RX_PACKET_OFFSET:
+ *((u32 *)pValue) = RXDESC_SIZE + DRVINFO_SZ;
+ break;
+ case HAL_DEF_DBG_DM_FUNC:
+ *((u32 *)pValue) = haldata->odmpriv.SupportAbility;
+ break;
+ case HAL_DEF_RA_DECISION_RATE:
+ {
+ u8 MacID = *((u8 *)pValue);
+ *((u8 *)pValue) = ODM_RA_GetDecisionRate_8188E(&(haldata->odmpriv), MacID);
+ }
+ break;
+ case HAL_DEF_RA_SGI:
+ {
+ u8 MacID = *((u8 *)pValue);
+ *((u8 *)pValue) = ODM_RA_GetShortGI_8188E(&(haldata->odmpriv), MacID);
+ }
+ break;
+ case HAL_DEF_PT_PWR_STATUS:
+ {
+ u8 MacID = *((u8 *)pValue);
+ *((u8 *)pValue) = ODM_RA_GetHwPwrStatus_8188E(&(haldata->odmpriv), MacID);
+ }
+ break;
+ case HW_VAR_MAX_RX_AMPDU_FACTOR:
+ *((u32 *)pValue) = MAX_AMPDU_FACTOR_64K;
+ break;
+ case HW_DEF_RA_INFO_DUMP:
+ {
+ u8 entry_id = *((u8 *)pValue);
+ if (check_fwstate(&Adapter->mlmepriv, _FW_LINKED)) {
+ DBG_88E("============ RA status check ===================\n");
+ DBG_88E("Mac_id:%d , RateID = %d, RAUseRate = 0x%08x, RateSGI = %d, DecisionRate = 0x%02x ,PTStage = %d\n",
+ entry_id,
+ haldata->odmpriv.RAInfo[entry_id].RateID,
+ haldata->odmpriv.RAInfo[entry_id].RAUseRate,
+ haldata->odmpriv.RAInfo[entry_id].RateSGI,
+ haldata->odmpriv.RAInfo[entry_id].DecisionRate,
+ haldata->odmpriv.RAInfo[entry_id].PTStage);
+ }
+ }
+ break;
+ case HW_DEF_ODM_DBG_FLAG:
+ {
+ struct odm_dm_struct *dm_ocm = &(haldata->odmpriv);
+ pr_info("dm_ocm->DebugComponents = 0x%llx\n", dm_ocm->DebugComponents);
+ }
+ break;
+ case HAL_DEF_DBG_DUMP_RXPKT:
+ *((u8 *)pValue) = haldata->bDumpRxPkt;
+ break;
+ case HAL_DEF_DBG_DUMP_TXPKT:
+ *((u8 *)pValue) = haldata->bDumpTxPkt;
+ break;
+ default:
+ bResult = _FAIL;
+ break;
+ }
+
+ return bResult;
+}
+
+/* */
+/* Description: */
+/* Change default setting of specified variable. */
+/* */
+static u8 SetHalDefVar8188EUsb(struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter);
+ u8 bResult = _SUCCESS;
+
+ switch (eVariable) {
+ case HAL_DEF_DBG_DM_FUNC:
+ {
+ u8 dm_func = *((u8 *)pValue);
+ struct odm_dm_struct *podmpriv = &haldata->odmpriv;
+
+ if (dm_func == 0) { /* disable all dynamic func */
+ podmpriv->SupportAbility = DYNAMIC_FUNC_DISABLE;
+ DBG_88E("==> Disable all dynamic function...\n");
+ } else if (dm_func == 1) {/* disable DIG */
+ podmpriv->SupportAbility &= (~DYNAMIC_BB_DIG);
+ DBG_88E("==> Disable DIG...\n");
+ } else if (dm_func == 2) {/* disable High power */
+ podmpriv->SupportAbility &= (~DYNAMIC_BB_DYNAMIC_TXPWR);
+ } else if (dm_func == 3) {/* disable tx power tracking */
+ podmpriv->SupportAbility &= (~DYNAMIC_RF_CALIBRATION);
+ DBG_88E("==> Disable tx power tracking...\n");
+ } else if (dm_func == 5) {/* disable antenna diversity */
+ podmpriv->SupportAbility &= (~DYNAMIC_BB_ANT_DIV);
+ } else if (dm_func == 6) {/* turn on all dynamic func */
+ if (!(podmpriv->SupportAbility & DYNAMIC_BB_DIG)) {
+ struct rtw_dig *pDigTable = &podmpriv->DM_DigTable;
+ pDigTable->CurIGValue = rtw_read8(Adapter, 0xc50);
+ }
+ podmpriv->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE;
+ DBG_88E("==> Turn on all dynamic function...\n");
+ }
+ }
+ break;
+ case HAL_DEF_DBG_DUMP_RXPKT:
+ haldata->bDumpRxPkt = *((u8 *)pValue);
+ break;
+ case HAL_DEF_DBG_DUMP_TXPKT:
+ haldata->bDumpTxPkt = *((u8 *)pValue);
+ break;
+ case HW_DEF_FA_CNT_DUMP:
+ {
+ u8 bRSSIDump = *((u8 *)pValue);
+ struct odm_dm_struct *dm_ocm = &(haldata->odmpriv);
+ if (bRSSIDump)
+ dm_ocm->DebugComponents = ODM_COMP_DIG|ODM_COMP_FA_CNT ;
+ else
+ dm_ocm->DebugComponents = 0;
+ }
+ break;
+ case HW_DEF_ODM_DBG_FLAG:
+ {
+ u64 DebugComponents = *((u64 *)pValue);
+ struct odm_dm_struct *dm_ocm = &(haldata->odmpriv);
+ dm_ocm->DebugComponents = DebugComponents;
+ }
+ break;
+ default:
+ bResult = _FAIL;
+ break;
+ }
+
+ return bResult;
+}
+
+static void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level)
+{
+ u8 init_rate = 0;
+ u8 networkType, raid;
+ u32 mask, rate_bitmap;
+ u8 shortGIrate = false;
+ int supportRateNum = 0;
+ struct sta_info *psta;
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+
+ if (mac_id >= NUM_STA) /* CAM_SIZE */
+ return;
+ psta = pmlmeinfo->FW_sta_info[mac_id].psta;
+ if (psta == NULL)
+ return;
+ switch (mac_id) {
+ case 0:/* for infra mode */
+ supportRateNum = rtw_get_rateset_len(cur_network->SupportedRates);
+ networkType = judge_network_type(adapt, cur_network->SupportedRates, supportRateNum) & 0xf;
+ raid = networktype_to_raid(networkType);
+ mask = update_supported_rate(cur_network->SupportedRates, supportRateNum);
+ mask |= (pmlmeinfo->HT_enable) ? update_MSC_rate(&(pmlmeinfo->HT_caps)) : 0;
+ if (support_short_GI(adapt, &(pmlmeinfo->HT_caps)))
+ shortGIrate = true;
+ break;
+ case 1:/* for broadcast/multicast */
+ supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates);
+ if (pmlmeext->cur_wireless_mode & WIRELESS_11B)
+ networkType = WIRELESS_11B;
+ else
+ networkType = WIRELESS_11G;
+ raid = networktype_to_raid(networkType);
+ mask = update_basic_rate(cur_network->SupportedRates, supportRateNum);
+ break;
+ default: /* for each sta in IBSS */
+ supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates);
+ networkType = judge_network_type(adapt, pmlmeinfo->FW_sta_info[mac_id].SupportedRates, supportRateNum) & 0xf;
+ raid = networktype_to_raid(networkType);
+ mask = update_supported_rate(cur_network->SupportedRates, supportRateNum);
+
+ /* todo: support HT in IBSS */
+ break;
+ }
+
+ rate_bitmap = 0x0fffffff;
+ rate_bitmap = ODM_Get_Rate_Bitmap(&haldata->odmpriv, mac_id, mask, rssi_level);
+ DBG_88E("%s => mac_id:%d, networkType:0x%02x, mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n",
+ __func__, mac_id, networkType, mask, rssi_level, rate_bitmap);
+
+ mask &= rate_bitmap;
+
+ init_rate = get_highest_rate_idx(mask)&0x3f;
+
+ if (haldata->fw_ractrl) {
+ u8 arg;
+
+ arg = mac_id & 0x1f;/* MACID */
+ arg |= BIT(7);
+ if (shortGIrate)
+ arg |= BIT(5);
+ mask |= ((raid << 28) & 0xf0000000);
+ DBG_88E("update raid entry, mask=0x%x, arg=0x%x\n", mask, arg);
+ psta->ra_mask = mask;
+ mask |= ((raid << 28) & 0xf0000000);
+
+ /* to do ,for 8188E-SMIC */
+ rtl8188e_set_raid_cmd(adapt, mask);
+ } else {
+ ODM_RA_UpdateRateInfo_8188E(&(haldata->odmpriv),
+ mac_id,
+ raid,
+ mask,
+ shortGIrate
+ );
+ }
+ /* set ra_id */
+ psta->raid = raid;
+ psta->init_rate = init_rate;
+}
+
+static void SetBeaconRelatedRegisters8188EUsb(struct adapter *adapt)
+{
+ u32 value32;
+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u32 bcn_ctrl_reg = REG_BCN_CTRL;
+ /* reset TSF, enable update TSF, correcting TSF On Beacon */
+
+ /* BCN interval */
+ rtw_write16(adapt, REG_BCN_INTERVAL, pmlmeinfo->bcn_interval);
+ rtw_write8(adapt, REG_ATIMWND, 0x02);/* 2ms */
+
+ _InitBeaconParameters(adapt);
+
+ rtw_write8(adapt, REG_SLOT, 0x09);
+
+ value32 = rtw_read32(adapt, REG_TCR);
+ value32 &= ~TSFRST;
+ rtw_write32(adapt, REG_TCR, value32);
+
+ value32 |= TSFRST;
+ rtw_write32(adapt, REG_TCR, value32);
+
+ /* NOTE: Fix test chip's bug (about contention windows's randomness) */
+ rtw_write8(adapt, REG_RXTSF_OFFSET_CCK, 0x50);
+ rtw_write8(adapt, REG_RXTSF_OFFSET_OFDM, 0x50);
+
+ _BeaconFunctionEnable(adapt, true, true);
+
+ ResumeTxBeacon(adapt);
+
+ rtw_write8(adapt, bcn_ctrl_reg, rtw_read8(adapt, bcn_ctrl_reg)|BIT(1));
+}
+
+static void rtl8188eu_init_default_value(struct adapter *adapt)
+{
+ struct hal_data_8188e *haldata;
+ struct pwrctrl_priv *pwrctrlpriv;
+ u8 i;
+
+ haldata = GET_HAL_DATA(adapt);
+ pwrctrlpriv = &adapt->pwrctrlpriv;
+
+ /* init default value */
+ haldata->fw_ractrl = false;
+ if (!pwrctrlpriv->bkeepfwalive)
+ haldata->LastHMEBoxNum = 0;
+
+ /* init dm default value */
+ haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = false;
+ haldata->odmpriv.RFCalibrateInfo.TM_Trigger = 0;/* for IQK */
+ haldata->pwrGroupCnt = 0;
+ haldata->PGMaxGroup = 13;
+ haldata->odmpriv.RFCalibrateInfo.ThermalValue_HP_index = 0;
+ for (i = 0; i < HP_THERMAL_NUM; i++)
+ haldata->odmpriv.RFCalibrateInfo.ThermalValue_HP[i] = 0;
+}
+
+static u8 rtl8188eu_ps_func(struct adapter *Adapter, enum hal_intf_ps_func efunc_id, u8 *val)
+{
+ u8 bResult = true;
+ return bResult;
+}
+
+void rtl8188eu_set_hal_ops(struct adapter *adapt)
+{
+ struct hal_ops *halfunc = &adapt->HalFunc;
+
+_func_enter_;
+
+ adapt->HalData = rtw_zmalloc(sizeof(struct hal_data_8188e));
+ if (adapt->HalData == NULL)
+ DBG_88E("cant not alloc memory for HAL DATA\n");
+ adapt->hal_data_sz = sizeof(struct hal_data_8188e);
+
+ halfunc->hal_power_on = rtl8188eu_InitPowerOn;
+ halfunc->hal_init = &rtl8188eu_hal_init;
+ halfunc->hal_deinit = &rtl8188eu_hal_deinit;
+
+ halfunc->inirp_init = &rtl8188eu_inirp_init;
+ halfunc->inirp_deinit = &rtl8188eu_inirp_deinit;
+
+ halfunc->init_xmit_priv = &rtl8188eu_init_xmit_priv;
+ halfunc->free_xmit_priv = &rtl8188eu_free_xmit_priv;
+
+ halfunc->init_recv_priv = &rtl8188eu_init_recv_priv;
+ halfunc->free_recv_priv = &rtl8188eu_free_recv_priv;
+ halfunc->InitSwLeds = &rtl8188eu_InitSwLeds;
+ halfunc->DeInitSwLeds = &rtl8188eu_DeInitSwLeds;
+
+ halfunc->init_default_value = &rtl8188eu_init_default_value;
+ halfunc->intf_chip_configure = &rtl8188eu_interface_configure;
+ halfunc->read_adapter_info = &ReadAdapterInfo8188EU;
+
+ halfunc->SetHwRegHandler = &SetHwReg8188EU;
+ halfunc->GetHwRegHandler = &GetHwReg8188EU;
+ halfunc->GetHalDefVarHandler = &GetHalDefVar8188EUsb;
+ halfunc->SetHalDefVarHandler = &SetHalDefVar8188EUsb;
+
+ halfunc->UpdateRAMaskHandler = &UpdateHalRAMask8188EUsb;
+ halfunc->SetBeaconRelatedRegistersHandler = &SetBeaconRelatedRegisters8188EUsb;
+
+ halfunc->hal_xmit = &rtl8188eu_hal_xmit;
+ halfunc->mgnt_xmit = &rtl8188eu_mgnt_xmit;
+
+ halfunc->interface_ps_func = &rtl8188eu_ps_func;
+
+ rtl8188e_set_hal_ops(halfunc);
+_func_exit_;
+}
diff --git a/drivers/staging/rtl8188eu/hal/usb_ops_linux.c b/drivers/staging/rtl8188eu/hal/usb_ops_linux.c
new file mode 100644
index 00000000000..bc564169b2f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/usb_ops_linux.c
@@ -0,0 +1,726 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _HCI_OPS_OS_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <osdep_intf.h>
+#include <usb_ops.h>
+#include <recv_osdep.h>
+#include <rtl8188e_hal.h>
+
+static int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u8 request, u16 value, u16 index, void *pdata, u16 len, u8 requesttype)
+{
+ struct adapter *adapt = pintfhdl->padapter;
+ struct dvobj_priv *dvobjpriv = adapter_to_dvobj(adapt);
+ struct usb_device *udev = dvobjpriv->pusbdev;
+ unsigned int pipe;
+ int status = 0;
+ u8 reqtype;
+ u8 *pIo_buf;
+ int vendorreq_times = 0;
+
+ if ((adapt->bSurpriseRemoved) || (adapt->pwrctrlpriv.pnp_bstop_trx)) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usbctrl_vendorreq:(adapt->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n"));
+ status = -EPERM;
+ goto exit;
+ }
+
+ if (len > MAX_VENDOR_REQ_CMD_SIZE) {
+ DBG_88E("[%s] Buffer len error ,vendor request failed\n", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+
+ _enter_critical_mutex(&dvobjpriv->usb_vendor_req_mutex, NULL);
+
+ /* Acquire IO memory for vendorreq */
+ pIo_buf = dvobjpriv->usb_vendor_req_buf;
+
+ if (pIo_buf == NULL) {
+ DBG_88E("[%s] pIo_buf == NULL\n", __func__);
+ status = -ENOMEM;
+ goto release_mutex;
+ }
+
+ while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) {
+ _rtw_memset(pIo_buf, 0, len);
+
+ if (requesttype == 0x01) {
+ pipe = usb_rcvctrlpipe(udev, 0);/* read_in */
+ reqtype = REALTEK_USB_VENQT_READ;
+ } else {
+ pipe = usb_sndctrlpipe(udev, 0);/* write_out */
+ reqtype = REALTEK_USB_VENQT_WRITE;
+ memcpy(pIo_buf, pdata, len);
+ }
+
+ status = rtw_usb_control_msg(udev, pipe, request, reqtype, value, index, pIo_buf, len, RTW_USB_CONTROL_MSG_TIMEOUT);
+
+ if (status == len) { /* Success this control transfer. */
+ rtw_reset_continual_urb_error(dvobjpriv);
+ if (requesttype == 0x01)
+ memcpy(pdata, pIo_buf, len);
+ } else { /* error cases */
+ DBG_88E("reg 0x%x, usb %s %u fail, status:%d value=0x%x, vendorreq_times:%d\n",
+ value, (requesttype == 0x01) ? "read" : "write",
+ len, status, *(u32 *)pdata, vendorreq_times);
+
+ if (status < 0) {
+ if (status == (-ESHUTDOWN) || status == -ENODEV) {
+ adapt->bSurpriseRemoved = true;
+ } else {
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ haldata->srestpriv.Wifi_Error_Status = USB_VEN_REQ_CMD_FAIL;
+ }
+ } else { /* status != len && status >= 0 */
+ if (status > 0) {
+ if (requesttype == 0x01) {
+ /* For Control read transfer, we have to copy the read data from pIo_buf to pdata. */
+ memcpy(pdata, pIo_buf, len);
+ }
+ }
+ }
+
+ if (rtw_inc_and_chk_continual_urb_error(dvobjpriv)) {
+ adapt->bSurpriseRemoved = true;
+ break;
+ }
+
+ }
+
+ /* firmware download is checksumed, don't retry */
+ if ((value >= FW_8188E_START_ADDRESS && value <= FW_8188E_END_ADDRESS) || status == len)
+ break;
+ }
+release_mutex:
+ _exit_critical_mutex(&dvobjpriv->usb_vendor_req_mutex, NULL);
+exit:
+ return status;
+}
+
+static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
+{
+ u8 request;
+ u8 requesttype;
+ u16 wvalue;
+ u16 index;
+ u16 len;
+ u8 data = 0;
+
+ _func_enter_;
+
+ request = 0x05;
+ requesttype = 0x01;/* read_in */
+ index = 0;/* n/a */
+
+ wvalue = (u16)(addr&0x0000ffff);
+ len = 1;
+
+ usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+ _func_exit_;
+
+ return data;
+
+}
+
+static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr)
+{
+ u8 request;
+ u8 requesttype;
+ u16 wvalue;
+ u16 index;
+ u16 len;
+ __le32 data;
+
+_func_enter_;
+ request = 0x05;
+ requesttype = 0x01;/* read_in */
+ index = 0;/* n/a */
+ wvalue = (u16)(addr&0x0000ffff);
+ len = 2;
+ usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+_func_exit_;
+
+ return (u16)(le32_to_cpu(data)&0xffff);
+}
+
+static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr)
+{
+ u8 request;
+ u8 requesttype;
+ u16 wvalue;
+ u16 index;
+ u16 len;
+ __le32 data;
+
+_func_enter_;
+
+ request = 0x05;
+ requesttype = 0x01;/* read_in */
+ index = 0;/* n/a */
+
+ wvalue = (u16)(addr&0x0000ffff);
+ len = 4;
+
+ usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+_func_exit_;
+
+ return le32_to_cpu(data);
+}
+
+static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
+{
+ u8 request;
+ u8 requesttype;
+ u16 wvalue;
+ u16 index;
+ u16 len;
+ u8 data;
+ int ret;
+
+ _func_enter_;
+ request = 0x05;
+ requesttype = 0x00;/* write_out */
+ index = 0;/* n/a */
+ wvalue = (u16)(addr&0x0000ffff);
+ len = 1;
+ data = val;
+ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+ _func_exit_;
+ return ret;
+}
+
+static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
+{
+ u8 request;
+ u8 requesttype;
+ u16 wvalue;
+ u16 index;
+ u16 len;
+ __le32 data;
+ int ret;
+
+ _func_enter_;
+
+ request = 0x05;
+ requesttype = 0x00;/* write_out */
+ index = 0;/* n/a */
+
+ wvalue = (u16)(addr&0x0000ffff);
+ len = 2;
+
+ data = cpu_to_le32(val & 0x0000ffff);
+
+ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+ _func_exit_;
+
+ return ret;
+}
+
+static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
+{
+ u8 request;
+ u8 requesttype;
+ u16 wvalue;
+ u16 index;
+ u16 len;
+ __le32 data;
+ int ret;
+
+ _func_enter_;
+
+ request = 0x05;
+ requesttype = 0x00;/* write_out */
+ index = 0;/* n/a */
+
+ wvalue = (u16)(addr&0x0000ffff);
+ len = 4;
+ data = cpu_to_le32(val);
+
+ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+ _func_exit_;
+
+ return ret;
+}
+
+static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata)
+{
+ u8 request;
+ u8 requesttype;
+ u16 wvalue;
+ u16 index;
+ u16 len;
+ u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0};
+ int ret;
+
+ _func_enter_;
+
+ request = 0x05;
+ requesttype = 0x00;/* write_out */
+ index = 0;/* n/a */
+
+ wvalue = (u16)(addr&0x0000ffff);
+ len = length;
+ memcpy(buf, pdata, len);
+
+ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, buf, len, requesttype);
+
+ _func_exit_;
+
+ return ret;
+}
+
+static void interrupt_handler_8188eu(struct adapter *adapt, u16 pkt_len, u8 *pbuf)
+{
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+
+ if (pkt_len != INTERRUPT_MSG_FORMAT_LEN) {
+ DBG_88E("%s Invalid interrupt content length (%d)!\n", __func__, pkt_len);
+ return;
+ }
+
+ /* HISR */
+ memcpy(&(haldata->IntArray[0]), &(pbuf[USB_INTR_CONTENT_HISR_OFFSET]), 4);
+ memcpy(&(haldata->IntArray[1]), &(pbuf[USB_INTR_CONTENT_HISRE_OFFSET]), 4);
+
+ /* C2H Event */
+ if (pbuf[0] != 0)
+ memcpy(&(haldata->C2hArray[0]), &(pbuf[USB_INTR_CONTENT_C2H_OFFSET]), 16);
+}
+
+static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
+{
+ u8 *pbuf;
+ u8 shift_sz = 0;
+ u16 pkt_cnt;
+ u32 pkt_offset, skb_len, alloc_sz;
+ s32 transfer_len;
+ struct recv_stat *prxstat;
+ struct phy_stat *pphy_status = NULL;
+ struct sk_buff *pkt_copy = NULL;
+ union recv_frame *precvframe = NULL;
+ struct rx_pkt_attrib *pattrib = NULL;
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ struct recv_priv *precvpriv = &adapt->recvpriv;
+ struct __queue *pfree_recv_queue = &precvpriv->free_recv_queue;
+
+ transfer_len = (s32)pskb->len;
+ pbuf = pskb->data;
+
+ prxstat = (struct recv_stat *)pbuf;
+ pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff;
+
+ do {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+ ("recvbuf2recvframe: rxdesc=offsset 0:0x%08x, 4:0x%08x, 8:0x%08x, C:0x%08x\n",
+ prxstat->rxdw0, prxstat->rxdw1, prxstat->rxdw2, prxstat->rxdw4));
+
+ prxstat = (struct recv_stat *)pbuf;
+
+ precvframe = rtw_alloc_recvframe(pfree_recv_queue);
+ if (precvframe == NULL) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvbuf2recvframe: precvframe==NULL\n"));
+ DBG_88E("%s()-%d: rtw_alloc_recvframe() failed! RX Drop!\n", __func__, __LINE__);
+ goto _exit_recvbuf2recvframe;
+ }
+
+ _rtw_init_listhead(&precvframe->u.hdr.list);
+ precvframe->u.hdr.precvbuf = NULL; /* can't access the precvbuf for new arch. */
+ precvframe->u.hdr.len = 0;
+
+ update_recvframe_attrib_88e(precvframe, prxstat);
+
+ pattrib = &precvframe->u.hdr.attrib;
+
+ if ((pattrib->crc_err) || (pattrib->icv_err)) {
+ DBG_88E("%s: RX Warning! crc_err=%d icv_err=%d, skip!\n", __func__, pattrib->crc_err, pattrib->icv_err);
+
+ rtw_free_recvframe(precvframe, pfree_recv_queue);
+ goto _exit_recvbuf2recvframe;
+ }
+
+ if ((pattrib->physt) && (pattrib->pkt_rpt_type == NORMAL_RX))
+ pphy_status = (struct phy_stat *)(pbuf + RXDESC_OFFSET);
+
+ pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->shift_sz + pattrib->pkt_len;
+
+ if ((pattrib->pkt_len <= 0) || (pkt_offset > transfer_len)) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recvbuf2recvframe: pkt_len<=0\n"));
+ DBG_88E("%s()-%d: RX Warning!,pkt_len<=0 or pkt_offset> transfoer_len\n", __func__, __LINE__);
+ rtw_free_recvframe(precvframe, pfree_recv_queue);
+ goto _exit_recvbuf2recvframe;
+ }
+
+ /* Modified by Albert 20101213 */
+ /* For 8 bytes IP header alignment. */
+ if (pattrib->qos) /* Qos data, wireless lan header length is 26 */
+ shift_sz = 6;
+ else
+ shift_sz = 0;
+
+ skb_len = pattrib->pkt_len;
+
+ /* for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. */
+ /* modify alloc_sz for recvive crc error packet by thomas 2011-06-02 */
+ if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
+ if (skb_len <= 1650)
+ alloc_sz = 1664;
+ else
+ alloc_sz = skb_len + 14;
+ } else {
+ alloc_sz = skb_len;
+ /* 6 is for IP header 8 bytes alignment in QoS packet case. */
+ /* 8 is for skb->data 4 bytes alignment. */
+ alloc_sz += 14;
+ }
+
+ pkt_copy = netdev_alloc_skb(adapt->pnetdev, alloc_sz);
+ if (pkt_copy) {
+ pkt_copy->dev = adapt->pnetdev;
+ precvframe->u.hdr.pkt = pkt_copy;
+ precvframe->u.hdr.rx_head = pkt_copy->data;
+ precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz;
+ skb_reserve(pkt_copy, 8 - ((size_t)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */
+ skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */
+ memcpy(pkt_copy->data, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len);
+ precvframe->u.hdr.rx_tail = pkt_copy->data;
+ precvframe->u.hdr.rx_data = pkt_copy->data;
+ } else {
+ if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
+ DBG_88E("recvbuf2recvframe: alloc_skb fail , drop frag frame\n");
+ rtw_free_recvframe(precvframe, pfree_recv_queue);
+ goto _exit_recvbuf2recvframe;
+ }
+ precvframe->u.hdr.pkt = skb_clone(pskb, GFP_ATOMIC);
+ if (precvframe->u.hdr.pkt) {
+ precvframe->u.hdr.rx_tail = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE;
+ precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_tail;
+ precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail;
+ precvframe->u.hdr.rx_end = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE + alloc_sz;
+ } else {
+ DBG_88E("recvbuf2recvframe: skb_clone fail\n");
+ rtw_free_recvframe(precvframe, pfree_recv_queue);
+ goto _exit_recvbuf2recvframe;
+ }
+ }
+
+ recvframe_put(precvframe, skb_len);
+
+ switch (haldata->UsbRxAggMode) {
+ case USB_RX_AGG_DMA:
+ case USB_RX_AGG_MIX:
+ pkt_offset = (u16)_RND128(pkt_offset);
+ break;
+ case USB_RX_AGG_USB:
+ pkt_offset = (u16)_RND4(pkt_offset);
+ break;
+ case USB_RX_AGG_DISABLE:
+ default:
+ break;
+ }
+ if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */
+ if (pattrib->physt)
+ update_recvframe_phyinfo_88e(precvframe, (struct phy_stat *)pphy_status);
+ if (rtw_recv_entry(precvframe) != _SUCCESS) {
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+ ("recvbuf2recvframe: rtw_recv_entry(precvframe) != _SUCCESS\n"));
+ }
+ } else {
+ /* enqueue recvframe to txrtp queue */
+ if (pattrib->pkt_rpt_type == TX_REPORT1) {
+ /* CCX-TXRPT ack for xmit mgmt frames. */
+ handle_txrpt_ccx_88e(adapt, precvframe->u.hdr.rx_data);
+ } else if (pattrib->pkt_rpt_type == TX_REPORT2) {
+ ODM_RA_TxRPT2Handle_8188E(
+ &haldata->odmpriv,
+ precvframe->u.hdr.rx_data,
+ pattrib->pkt_len,
+ pattrib->MacIDValidEntry[0],
+ pattrib->MacIDValidEntry[1]
+ );
+ } else if (pattrib->pkt_rpt_type == HIS_REPORT) {
+ interrupt_handler_8188eu(adapt, pattrib->pkt_len, precvframe->u.hdr.rx_data);
+ }
+ rtw_free_recvframe(precvframe, pfree_recv_queue);
+ }
+ pkt_cnt--;
+ transfer_len -= pkt_offset;
+ pbuf += pkt_offset;
+ precvframe = NULL;
+ pkt_copy = NULL;
+
+ if (transfer_len > 0 && pkt_cnt == 0)
+ pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff;
+
+ } while ((transfer_len > 0) && (pkt_cnt > 0));
+
+_exit_recvbuf2recvframe:
+
+ return _SUCCESS;
+}
+
+void rtl8188eu_recv_tasklet(void *priv)
+{
+ struct sk_buff *pskb;
+ struct adapter *adapt = (struct adapter *)priv;
+ struct recv_priv *precvpriv = &adapt->recvpriv;
+
+ while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) {
+ if ((adapt->bDriverStopped) || (adapt->bSurpriseRemoved)) {
+ DBG_88E("recv_tasklet => bDriverStopped or bSurpriseRemoved\n");
+ dev_kfree_skb_any(pskb);
+ break;
+ }
+ recvbuf2recvframe(adapt, pskb);
+ skb_reset_tail_pointer(pskb);
+ pskb->len = 0;
+ skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
+ }
+}
+
+static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
+{
+ struct recv_buf *precvbuf = (struct recv_buf *)purb->context;
+ struct adapter *adapt = (struct adapter *)precvbuf->adapter;
+ struct recv_priv *precvpriv = &adapt->recvpriv;
+
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete!!!\n"));
+
+ precvpriv->rx_pending_cnt--;
+
+ if (adapt->bSurpriseRemoved || adapt->bDriverStopped || adapt->bReadPortCancel) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+ ("usb_read_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)\n",
+ adapt->bDriverStopped, adapt->bSurpriseRemoved));
+
+ precvbuf->reuse = true;
+ DBG_88E("%s() RX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bReadPortCancel(%d)\n",
+ __func__, adapt->bDriverStopped,
+ adapt->bSurpriseRemoved, adapt->bReadPortCancel);
+ goto exit;
+ }
+
+ if (purb->status == 0) { /* SUCCESS */
+ if ((purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+ ("usb_read_port_complete: (purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)\n"));
+ precvbuf->reuse = true;
+ rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+ DBG_88E("%s()-%d: RX Warning!\n", __func__, __LINE__);
+ } else {
+ rtw_reset_continual_urb_error(adapter_to_dvobj(adapt));
+
+ precvbuf->transfer_len = purb->actual_length;
+ skb_put(precvbuf->pskb, purb->actual_length);
+ skb_queue_tail(&precvpriv->rx_skb_queue, precvbuf->pskb);
+
+ if (skb_queue_len(&precvpriv->rx_skb_queue) <= 1)
+ tasklet_schedule(&precvpriv->recv_tasklet);
+
+ precvbuf->pskb = NULL;
+ precvbuf->reuse = false;
+ rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+ }
+ } else {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete : purb->status(%d) != 0\n", purb->status));
+
+ DBG_88E("###=> usb_read_port_complete => urb status(%d)\n", purb->status);
+
+ if (rtw_inc_and_chk_continual_urb_error(adapter_to_dvobj(adapt)))
+ adapt->bSurpriseRemoved = true;
+
+ switch (purb->status) {
+ case -EINVAL:
+ case -EPIPE:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete:bSurpriseRemoved=true\n"));
+ case -ENOENT:
+ adapt->bDriverStopped = true;
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete:bDriverStopped=true\n"));
+ break;
+ case -EPROTO:
+ case -EOVERFLOW:
+ {
+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+ haldata->srestpriv.Wifi_Error_Status = USB_READ_PORT_FAIL;
+ }
+ precvbuf->reuse = true;
+ rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+ break;
+ case -EINPROGRESS:
+ DBG_88E("ERROR: URB IS IN PROGRESS!/n");
+ break;
+ default:
+ break;
+ }
+ }
+
+exit:
+_func_exit_;
+}
+
+static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
+{
+ struct urb *purb = NULL;
+ struct recv_buf *precvbuf = (struct recv_buf *)rmem;
+ struct adapter *adapter = pintfhdl->padapter;
+ struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
+ struct recv_priv *precvpriv = &adapter->recvpriv;
+ struct usb_device *pusbd = pdvobj->pusbdev;
+ int err;
+ unsigned int pipe;
+ size_t tmpaddr = 0;
+ size_t alignment = 0;
+ u32 ret = _SUCCESS;
+
+_func_enter_;
+
+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved ||
+ adapter->pwrctrlpriv.pnp_bstop_trx) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+ ("usb_read_port:(adapt->bDriverStopped ||adapt->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n"));
+ return _FAIL;
+ }
+
+ if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) {
+ precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue);
+ if (NULL != precvbuf->pskb)
+ precvbuf->reuse = true;
+ }
+
+ if (precvbuf != NULL) {
+ rtl8188eu_init_recvbuf(adapter, precvbuf);
+
+ /* re-assign for linux based on skb */
+ if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) {
+ precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
+ if (precvbuf->pskb == NULL) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("init_recvbuf(): alloc_skb fail!\n"));
+ DBG_88E("#### usb_read_port() alloc_skb fail!#####\n");
+ return _FAIL;
+ }
+
+ tmpaddr = (size_t)precvbuf->pskb->data;
+ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
+ skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
+
+ precvbuf->phead = precvbuf->pskb->head;
+ precvbuf->pdata = precvbuf->pskb->data;
+ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb);
+ precvbuf->pend = skb_end_pointer(precvbuf->pskb);
+ precvbuf->pbuf = precvbuf->pskb->data;
+ } else { /* reuse skb */
+ precvbuf->phead = precvbuf->pskb->head;
+ precvbuf->pdata = precvbuf->pskb->data;
+ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb);
+ precvbuf->pend = skb_end_pointer(precvbuf->pskb);
+ precvbuf->pbuf = precvbuf->pskb->data;
+
+ precvbuf->reuse = false;
+ }
+
+ precvpriv->rx_pending_cnt++;
+
+ purb = precvbuf->purb;
+
+ /* translate DMA FIFO addr to pipehandle */
+ pipe = ffaddr2pipehdl(pdvobj, addr);
+
+ usb_fill_bulk_urb(purb, pusbd, pipe,
+ precvbuf->pbuf,
+ MAX_RECVBUF_SZ,
+ usb_read_port_complete,
+ precvbuf);/* context is precvbuf */
+
+ err = usb_submit_urb(purb, GFP_ATOMIC);
+ if ((err) && (err != (-EPERM))) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+ ("cannot submit rx in-token(err=0x%.8x), URB_STATUS =0x%.8x",
+ err, purb->status));
+ DBG_88E("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n",
+ err, purb->status);
+ ret = _FAIL;
+ }
+ } else {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+ ("usb_read_port:precvbuf ==NULL\n"));
+ ret = _FAIL;
+ }
+
+_func_exit_;
+ return ret;
+}
+
+void rtl8188eu_xmit_tasklet(void *priv)
+{
+ int ret = false;
+ struct adapter *adapt = (struct adapter *)priv;
+ struct xmit_priv *pxmitpriv = &adapt->xmitpriv;
+
+ if (check_fwstate(&adapt->mlmepriv, _FW_UNDER_SURVEY))
+ return;
+
+ while (1) {
+ if ((adapt->bDriverStopped) ||
+ (adapt->bSurpriseRemoved) ||
+ (adapt->bWritePortCancel)) {
+ DBG_88E("xmit_tasklet => bDriverStopped or bSurpriseRemoved or bWritePortCancel\n");
+ break;
+ }
+
+ ret = rtl8188eu_xmitframe_complete(adapt, pxmitpriv, NULL);
+
+ if (!ret)
+ break;
+ }
+}
+
+void rtl8188eu_set_intf_ops(struct _io_ops *pops)
+{
+ _func_enter_;
+ _rtw_memset((u8 *)pops, 0, sizeof(struct _io_ops));
+ pops->_read8 = &usb_read8;
+ pops->_read16 = &usb_read16;
+ pops->_read32 = &usb_read32;
+ pops->_read_mem = &usb_read_mem;
+ pops->_read_port = &usb_read_port;
+ pops->_write8 = &usb_write8;
+ pops->_write16 = &usb_write16;
+ pops->_write32 = &usb_write32;
+ pops->_writeN = &usb_writeN;
+ pops->_write_mem = &usb_write_mem;
+ pops->_write_port = &usb_write_port;
+ pops->_read_port_cancel = &usb_read_port_cancel;
+ pops->_write_port_cancel = &usb_write_port_cancel;
+ _func_exit_;
+}
+
+void rtl8188eu_set_hw_type(struct adapter *adapt)
+{
+ adapt->chip_type = RTL8188E;
+ adapt->HardwareType = HARDWARE_TYPE_RTL8188EU;
+ DBG_88E("CHIP TYPE: RTL8188E\n");
+}
diff --git a/drivers/staging/rtl8188eu/include/Hal8188EFWImg_CE.h b/drivers/staging/rtl8188eu/include/Hal8188EFWImg_CE.h
new file mode 100644
index 00000000000..949c33b9ed6
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188EFWImg_CE.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+*
+*
+******************************************************************************/
+#ifndef __INC_HAL8188E_FW_IMG_H
+#define __INC_HAL8188E_FW_IMG_H
+
+/* V10(1641) */
+#define Rtl8188EFWImgArrayLength 13904
+
+extern const u8 Rtl8188EFwImgArray[Rtl8188EFWImgArrayLength];
+
+#endif /* __INC_HAL8188E_FW_IMG_H */
diff --git a/drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h b/drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h
new file mode 100644
index 00000000000..c4769e20a5c
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h
@@ -0,0 +1,276 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __INC_HAL8188EPHYCFG_H__
+#define __INC_HAL8188EPHYCFG_H__
+
+
+/*--------------------------Define Parameters-------------------------------*/
+#define LOOP_LIMIT 5
+#define MAX_STALL_TIME 50 /* us */
+#define AntennaDiversityValue 0x80
+#define MAX_TXPWR_IDX_NMODE_92S 63
+#define Reset_Cnt_Limit 3
+
+#define IQK_MAC_REG_NUM 4
+#define IQK_ADDA_REG_NUM 16
+#define IQK_BB_REG_NUM 9
+#define HP_THERMAL_NUM 8
+
+#define MAX_AGGR_NUM 0x07
+
+
+/*--------------------------Define Parameters-------------------------------*/
+
+
+/*------------------------------Define structure----------------------------*/
+enum sw_chnl_cmd_id {
+ CmdID_End,
+ CmdID_SetTxPowerLevel,
+ CmdID_BBRegWrite10,
+ CmdID_WritePortUlong,
+ CmdID_WritePortUshort,
+ CmdID_WritePortUchar,
+ CmdID_RF_WriteReg,
+};
+
+/* 1. Switch channel related */
+struct sw_chnl_cmd {
+ enum sw_chnl_cmd_id CmdID;
+ u32 Para1;
+ u32 Para2;
+ u32 msDelay;
+};
+
+enum hw90_block {
+ HW90_BLOCK_MAC = 0,
+ HW90_BLOCK_PHY0 = 1,
+ HW90_BLOCK_PHY1 = 2,
+ HW90_BLOCK_RF = 3,
+ HW90_BLOCK_MAXIMUM = 4, /* Never use this */
+};
+
+enum rf_radio_path {
+ RF_PATH_A = 0, /* Radio Path A */
+ RF_PATH_B = 1, /* Radio Path B */
+ RF_PATH_C = 2, /* Radio Path C */
+ RF_PATH_D = 3, /* Radio Path D */
+};
+
+#define MAX_PG_GROUP 13
+
+#define RF_PATH_MAX 2
+#define MAX_RF_PATH RF_PATH_MAX
+#define MAX_TX_COUNT 4 /* path numbers */
+
+#define CHANNEL_MAX_NUMBER 14 /* 14 is the max chnl number */
+#define MAX_CHNL_GROUP_24G 6 /* ch1~2, ch3~5, ch6~8,
+ *ch9~11, ch12~13, CH 14
+ * total three groups */
+#define CHANNEL_GROUP_MAX_88E 6
+
+enum wireless_mode {
+ WIRELESS_MODE_UNKNOWN = 0x00,
+ WIRELESS_MODE_A = BIT2,
+ WIRELESS_MODE_B = BIT0,
+ WIRELESS_MODE_G = BIT1,
+ WIRELESS_MODE_AUTO = BIT5,
+ WIRELESS_MODE_N_24G = BIT3,
+ WIRELESS_MODE_N_5G = BIT4,
+ WIRELESS_MODE_AC = BIT6
+};
+
+enum phy_rate_tx_offset_area {
+ RA_OFFSET_LEGACY_OFDM1,
+ RA_OFFSET_LEGACY_OFDM2,
+ RA_OFFSET_HT_OFDM1,
+ RA_OFFSET_HT_OFDM2,
+ RA_OFFSET_HT_OFDM3,
+ RA_OFFSET_HT_OFDM4,
+ RA_OFFSET_HT_CCK,
+};
+
+/* BB/RF related */
+enum RF_TYPE_8190P {
+ RF_TYPE_MIN, /* 0 */
+ RF_8225 = 1, /* 1 11b/g RF for verification only */
+ RF_8256 = 2, /* 2 11b/g/n */
+ RF_8258 = 3, /* 3 11a/b/g/n RF */
+ RF_6052 = 4, /* 4 11b/g/n RF */
+ /* TODO: We should remove this psudo PHY RF after we get new RF. */
+ RF_PSEUDO_11N = 5, /* 5, It is a temporality RF. */
+};
+
+struct bb_reg_def {
+ u32 rfintfs; /* set software control: */
+ /* 0x870~0x877[8 bytes] */
+ u32 rfintfi; /* readback data: */
+ /* 0x8e0~0x8e7[8 bytes] */
+ u32 rfintfo; /* output data: */
+ /* 0x860~0x86f [16 bytes] */
+ u32 rfintfe; /* output enable: */
+ /* 0x860~0x86f [16 bytes] */
+ u32 rf3wireOffset; /* LSSI data: */
+ /* 0x840~0x84f [16 bytes] */
+ u32 rfLSSI_Select; /* BB Band Select: */
+ /* 0x878~0x87f [8 bytes] */
+ u32 rfTxGainStage; /* Tx gain stage: */
+ /* 0x80c~0x80f [4 bytes] */
+ u32 rfHSSIPara1; /* wire parameter control1 : */
+ /* 0x820~0x823,0x828~0x82b,
+ * 0x830~0x833, 0x838~0x83b [16 bytes] */
+ u32 rfHSSIPara2; /* wire parameter control2 : */
+ /* 0x824~0x827,0x82c~0x82f, 0x834~0x837,
+ * 0x83c~0x83f [16 bytes] */
+ u32 rfSwitchControl; /* Tx Rx antenna control : */
+ /* 0x858~0x85f [16 bytes] */
+ u32 rfAGCControl1; /* AGC parameter control1 : */
+ /* 0xc50~0xc53,0xc58~0xc5b, 0xc60~0xc63,
+ * 0xc68~0xc6b [16 bytes] */
+ u32 rfAGCControl2; /* AGC parameter control2 : */
+ /* 0xc54~0xc57,0xc5c~0xc5f, 0xc64~0xc67,
+ * 0xc6c~0xc6f [16 bytes] */
+ u32 rfRxIQImbalance; /* OFDM Rx IQ imbalance matrix : */
+ /* 0xc14~0xc17,0xc1c~0xc1f, 0xc24~0xc27,
+ * 0xc2c~0xc2f [16 bytes] */
+ u32 rfRxAFE; /* Rx IQ DC ofset and Rx digital filter,
+ * Rx DC notch filter : */
+ /* 0xc10~0xc13,0xc18~0xc1b, 0xc20~0xc23,
+ * 0xc28~0xc2b [16 bytes] */
+ u32 rfTxIQImbalance; /* OFDM Tx IQ imbalance matrix */
+ /* 0xc80~0xc83,0xc88~0xc8b, 0xc90~0xc93,
+ * 0xc98~0xc9b [16 bytes] */
+ u32 rfTxAFE; /* Tx IQ DC Offset and Tx DFIR type */
+ /* 0xc84~0xc87,0xc8c~0xc8f, 0xc94~0xc97,
+ * 0xc9c~0xc9f [16 bytes] */
+ u32 rfLSSIReadBack; /* LSSI RF readback data SI mode */
+ /* 0x8a0~0x8af [16 bytes] */
+ u32 rfLSSIReadBackPi; /* LSSI RF readback data PI mode 0x8b8-8bc for
+ * Path A and B */
+};
+
+struct ant_sel_ofdm {
+ u32 r_tx_antenna:4;
+ u32 r_ant_l:4;
+ u32 r_ant_non_ht:4;
+ u32 r_ant_ht1:4;
+ u32 r_ant_ht2:4;
+ u32 r_ant_ht_s1:4;
+ u32 r_ant_non_ht_s1:4;
+ u32 OFDM_TXSC:2;
+ u32 reserved:2;
+};
+
+struct ant_sel_cck {
+ u8 r_cckrx_enable_2:2;
+ u8 r_cckrx_enable:2;
+ u8 r_ccktx_enable:4;
+};
+
+/*------------------------------Define structure----------------------------*/
+
+
+/*------------------------Export global variable----------------------------*/
+/*------------------------Export global variable----------------------------*/
+
+
+/*------------------------Export Marco Definition---------------------------*/
+/*------------------------Export Marco Definition---------------------------*/
+
+
+/*--------------------------Exported Function prototype---------------------*/
+/* */
+/* BB and RF register read/write */
+/* */
+u32 rtl8188e_PHY_QueryBBReg(struct adapter *adapter, u32 regaddr, u32 mask);
+void rtl8188e_PHY_SetBBReg(struct adapter *Adapter, u32 RegAddr,
+ u32 mask, u32 data);
+u32 rtl8188e_PHY_QueryRFReg(struct adapter *adapter, enum rf_radio_path rfpath,
+ u32 regaddr, u32 mask);
+void rtl8188e_PHY_SetRFReg(struct adapter *adapter, enum rf_radio_path rfpath,
+ u32 regaddr, u32 mask, u32 data);
+
+/* Initialization related function */
+/* MAC/BB/RF HAL config */
+int PHY_MACConfig8188E(struct adapter *adapter);
+int PHY_BBConfig8188E(struct adapter *adapter);
+int PHY_RFConfig8188E(struct adapter *adapter);
+
+/* RF config */
+int rtl8188e_PHY_ConfigRFWithParaFile(struct adapter *adapter, u8 *filename,
+ enum rf_radio_path rfpath);
+int rtl8188e_PHY_ConfigRFWithHeaderFile(struct adapter *adapter,
+ enum rf_radio_path rfpath);
+
+/* Read initi reg value for tx power setting. */
+void rtl8192c_PHY_GetHWRegOriginalValue(struct adapter *adapter);
+
+/* BB TX Power R/W */
+void PHY_GetTxPowerLevel8188E(struct adapter *adapter, u32 *powerlevel);
+void PHY_SetTxPowerLevel8188E(struct adapter *adapter, u8 channel);
+bool PHY_UpdateTxPowerDbm8188E(struct adapter *adapter, int power);
+
+void PHY_ScanOperationBackup8188E(struct adapter *Adapter, u8 Operation);
+
+/* Switch bandwidth for 8192S */
+void PHY_SetBWMode8188E(struct adapter *adapter,
+ enum ht_channel_width chnlwidth, unsigned char offset);
+
+/* channel switch related funciton */
+void PHY_SwChnl8188E(struct adapter *adapter, u8 channel);
+/* Call after initialization */
+void ChkFwCmdIoDone(struct adapter *adapter);
+
+/* BB/MAC/RF other monitor API */
+void PHY_SetRFPathSwitch_8188E(struct adapter *adapter, bool main);
+
+void PHY_SwitchEphyParameter(struct adapter *adapter);
+
+void PHY_EnableHostClkReq(struct adapter *adapter);
+
+bool SetAntennaConfig92C(struct adapter *adapter, u8 defaultant);
+
+void storePwrIndexDiffRateOffset(struct adapter *adapter, u32 regaddr,
+ u32 mask, u32 data);
+/*--------------------------Exported Function prototype---------------------*/
+
+#define PHY_QueryBBReg(adapt, regaddr, mask) \
+ rtl8188e_PHY_QueryBBReg((adapt), (regaddr), (mask))
+#define PHY_SetBBReg(adapt, regaddr, bitmask, data) \
+ rtl8188e_PHY_SetBBReg((adapt), (regaddr), (bitmask), (data))
+#define PHY_QueryRFReg(adapt, rfpath, regaddr, bitmask) \
+ rtl8188e_PHY_QueryRFReg((adapt), (rfpath), (regaddr), (bitmask))
+#define PHY_SetRFReg(adapt, rfpath, regaddr, bitmask, data) \
+ rtl8188e_PHY_SetRFReg((adapt), (rfpath), (regaddr), (bitmask), (data))
+
+#define PHY_SetMacReg PHY_SetBBReg
+
+#define SIC_HW_SUPPORT 0
+
+#define SIC_MAX_POLL_CNT 5
+
+#define SIC_CMD_READY 0
+#define SIC_CMD_WRITE 1
+#define SIC_CMD_READ 2
+
+#define SIC_CMD_REG 0x1EB /* 1byte */
+#define SIC_ADDR_REG 0x1E8 /* 1b9~1ba, 2 bytes */
+#define SIC_DATA_REG 0x1EC /* 1bc~1bf */
+
+#endif /* __INC_HAL8192CPHYCFG_H */
diff --git a/drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h b/drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h
new file mode 100644
index 00000000000..0e06d29b2d2
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h
@@ -0,0 +1,1094 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __INC_HAL8188EPHYREG_H__
+#define __INC_HAL8188EPHYREG_H__
+/*--------------------------Define Parameters-------------------------------*/
+/* */
+/* BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF */
+/* 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */
+/* 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 */
+/* 3. RF register 0x00-2E */
+/* 4. Bit Mask for BB/RF register */
+/* 5. Other defintion for BB/RF R/W */
+/* */
+
+
+/* */
+/* 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */
+/* 1. Page1(0x100) */
+/* */
+#define rPMAC_Reset 0x100
+#define rPMAC_TxStart 0x104
+#define rPMAC_TxLegacySIG 0x108
+#define rPMAC_TxHTSIG1 0x10c
+#define rPMAC_TxHTSIG2 0x110
+#define rPMAC_PHYDebug 0x114
+#define rPMAC_TxPacketNum 0x118
+#define rPMAC_TxIdle 0x11c
+#define rPMAC_TxMACHeader0 0x120
+#define rPMAC_TxMACHeader1 0x124
+#define rPMAC_TxMACHeader2 0x128
+#define rPMAC_TxMACHeader3 0x12c
+#define rPMAC_TxMACHeader4 0x130
+#define rPMAC_TxMACHeader5 0x134
+#define rPMAC_TxDataType 0x138
+#define rPMAC_TxRandomSeed 0x13c
+#define rPMAC_CCKPLCPPreamble 0x140
+#define rPMAC_CCKPLCPHeader 0x144
+#define rPMAC_CCKCRC16 0x148
+#define rPMAC_OFDMRxCRC32OK 0x170
+#define rPMAC_OFDMRxCRC32Er 0x174
+#define rPMAC_OFDMRxParityEr 0x178
+#define rPMAC_OFDMRxCRC8Er 0x17c
+#define rPMAC_CCKCRxRC16Er 0x180
+#define rPMAC_CCKCRxRC32Er 0x184
+#define rPMAC_CCKCRxRC32OK 0x188
+#define rPMAC_TxStatus 0x18c
+
+/* 2. Page2(0x200) */
+/* The following two definition are only used for USB interface. */
+#define RF_BB_CMD_ADDR 0x02c0 /* RF/BB r/w cmd address. */
+#define RF_BB_CMD_DATA 0x02c4 /* RF/BB r/w cmd data. */
+
+/* 3. Page8(0x800) */
+#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC RF BW Setting */
+
+#define rFPGA0_TxInfo 0x804 /* Status report?? */
+#define rFPGA0_PSDFunction 0x808
+
+#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */
+
+#define rFPGA0_RFTiming1 0x810 /* Useless now */
+#define rFPGA0_RFTiming2 0x814
+
+#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */
+#define rFPGA0_XA_HSSIParameter2 0x824
+#define rFPGA0_XB_HSSIParameter1 0x828
+#define rFPGA0_XB_HSSIParameter2 0x82c
+
+#define rFPGA0_XA_LSSIParameter 0x840
+#define rFPGA0_XB_LSSIParameter 0x844
+
+#define rFPGA0_RFWakeUpParameter 0x850 /* Useless now */
+#define rFPGA0_RFSleepUpParameter 0x854
+
+#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */
+#define rFPGA0_XCD_SwitchControl 0x85c
+
+#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */
+#define rFPGA0_XB_RFInterfaceOE 0x864
+
+#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Iface Software Control */
+#define rFPGA0_XCD_RFInterfaceSW 0x874
+
+#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */
+#define rFPGA0_XCD_RFParameter 0x87c
+
+/* Crystal cap setting RF-R/W protection for parameter4?? */
+#define rFPGA0_AnalogParameter1 0x880
+#define rFPGA0_AnalogParameter2 0x884
+#define rFPGA0_AnalogParameter3 0x888
+/* enable ad/da clock1 for dual-phy */
+#define rFPGA0_AdDaClockEn 0x888
+#define rFPGA0_AnalogParameter4 0x88c
+
+#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Tranceiver LSSI Readback */
+#define rFPGA0_XB_LSSIReadBack 0x8a4
+#define rFPGA0_XC_LSSIReadBack 0x8a8
+#define rFPGA0_XD_LSSIReadBack 0x8ac
+
+#define rFPGA0_PSDReport 0x8b4 /* Useless now */
+/* Transceiver A HSPI Readback */
+#define TransceiverA_HSPI_Readback 0x8b8
+/* Transceiver B HSPI Readback */
+#define TransceiverB_HSPI_Readback 0x8bc
+/* Useless now RF Interface Readback Value */
+#define rFPGA0_XAB_RFInterfaceRB 0x8e0
+#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Useless now */
+
+/* 4. Page9(0x900) */
+/* RF mode & OFDM TxSC RF BW Setting?? */
+#define rFPGA1_RFMOD 0x900
+
+#define rFPGA1_TxBlock 0x904 /* Useless now */
+#define rFPGA1_DebugSelect 0x908 /* Useless now */
+#define rFPGA1_TxInfo 0x90c /* Useless now Status report */
+
+/* 5. PageA(0xA00) */
+/* Set Control channel to upper or lower - required only for 40MHz */
+#define rCCK0_System 0xa00
+
+/* Disable init gain now Select RX path by RSSI */
+#define rCCK0_AFESetting 0xa04
+/* Disable init gain now Init gain */
+#define rCCK0_CCA 0xa08
+
+/* AGC default value, saturation level Antenna Diversity, RX AGC, LNA Threshold,
+ * RX LNA Threshold useless now. Not the same as 90 series */
+#define rCCK0_RxAGC1 0xa0c
+#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */
+
+#define rCCK0_RxHP 0xa14
+
+/* Timing recovery & Channel estimation threshold */
+#define rCCK0_DSPParameter1 0xa18
+#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */
+
+#define rCCK0_TxFilter1 0xa20
+#define rCCK0_TxFilter2 0xa24
+#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */
+#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now */
+#define rCCK0_TRSSIReport 0xa50
+#define rCCK0_RxReport 0xa54 /* 0xa57 */
+#define rCCK0_FACounterLower 0xa5c /* 0xa5b */
+#define rCCK0_FACounterUpper 0xa58 /* 0xa5c */
+
+/* */
+/* PageB(0xB00) */
+/* */
+#define rPdp_AntA 0xb00
+#define rPdp_AntA_4 0xb04
+#define rConfig_Pmpd_AntA 0xb28
+#define rConfig_AntA 0xb68
+#define rConfig_AntB 0xb6c
+#define rPdp_AntB 0xb70
+#define rPdp_AntB_4 0xb74
+#define rConfig_Pmpd_AntB 0xb98
+#define rAPK 0xbd8
+
+/* */
+/* 6. PageC(0xC00) */
+/* */
+#define rOFDM0_LSTF 0xc00
+
+#define rOFDM0_TRxPathEnable 0xc04
+#define rOFDM0_TRMuxPar 0xc08
+#define rOFDM0_TRSWIsolation 0xc0c
+
+/* RxIQ DC offset, Rx digital filter, DC notch filter */
+#define rOFDM0_XARxAFE 0xc10
+#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */
+#define rOFDM0_XBRxAFE 0xc18
+#define rOFDM0_XBRxIQImbalance 0xc1c
+#define rOFDM0_XCRxAFE 0xc20
+#define rOFDM0_XCRxIQImbalance 0xc24
+#define rOFDM0_XDRxAFE 0xc28
+#define rOFDM0_XDRxIQImbalance 0xc2c
+
+#define rOFDM0_RxDetector1 0xc30 /*PD,BW & SBD DM tune init gain*/
+#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */
+#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */
+#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & Short-GI */
+
+#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */
+#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */
+#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */
+#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */
+
+#define rOFDM0_XAAGCCore1 0xc50 /* DIG */
+#define rOFDM0_XAAGCCore2 0xc54
+#define rOFDM0_XBAGCCore1 0xc58
+#define rOFDM0_XBAGCCore2 0xc5c
+#define rOFDM0_XCAGCCore1 0xc60
+#define rOFDM0_XCAGCCore2 0xc64
+#define rOFDM0_XDAGCCore1 0xc68
+#define rOFDM0_XDAGCCore2 0xc6c
+
+#define rOFDM0_AGCParameter1 0xc70
+#define rOFDM0_AGCParameter2 0xc74
+#define rOFDM0_AGCRSSITable 0xc78
+#define rOFDM0_HTSTFAGC 0xc7c
+
+#define rOFDM0_XATxIQImbalance 0xc80 /* TX PWR TRACK and DIG */
+#define rOFDM0_XATxAFE 0xc84
+#define rOFDM0_XBTxIQImbalance 0xc88
+#define rOFDM0_XBTxAFE 0xc8c
+#define rOFDM0_XCTxIQImbalance 0xc90
+#define rOFDM0_XCTxAFE 0xc94
+#define rOFDM0_XDTxIQImbalance 0xc98
+#define rOFDM0_XDTxAFE 0xc9c
+
+#define rOFDM0_RxIQExtAnta 0xca0
+#define rOFDM0_TxCoeff1 0xca4
+#define rOFDM0_TxCoeff2 0xca8
+#define rOFDM0_TxCoeff3 0xcac
+#define rOFDM0_TxCoeff4 0xcb0
+#define rOFDM0_TxCoeff5 0xcb4
+#define rOFDM0_TxCoeff6 0xcb8
+#define rOFDM0_RxHPParameter 0xce0
+#define rOFDM0_TxPseudoNoiseWgt 0xce4
+#define rOFDM0_FrameSync 0xcf0
+#define rOFDM0_DFSReport 0xcf4
+
+
+/* */
+/* 7. PageD(0xD00) */
+/* */
+#define rOFDM1_LSTF 0xd00
+#define rOFDM1_TRxPathEnable 0xd04
+
+#define rOFDM1_CFO 0xd08 /* No setting now */
+#define rOFDM1_CSI1 0xd10
+#define rOFDM1_SBD 0xd14
+#define rOFDM1_CSI2 0xd18
+#define rOFDM1_CFOTracking 0xd2c
+#define rOFDM1_TRxMesaure1 0xd34
+#define rOFDM1_IntfDet 0xd3c
+#define rOFDM1_PseudoNoiseStateAB 0xd50
+#define rOFDM1_PseudoNoiseStateCD 0xd54
+#define rOFDM1_RxPseudoNoiseWgt 0xd58
+
+#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */
+#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */
+#define rOFDM_PHYCounter3 0xda8 /* MCS not support */
+
+#define rOFDM_ShortCFOAB 0xdac /* No setting now */
+#define rOFDM_ShortCFOCD 0xdb0
+#define rOFDM_LongCFOAB 0xdb4
+#define rOFDM_LongCFOCD 0xdb8
+#define rOFDM_TailCFOAB 0xdbc
+#define rOFDM_TailCFOCD 0xdc0
+#define rOFDM_PWMeasure1 0xdc4
+#define rOFDM_PWMeasure2 0xdc8
+#define rOFDM_BWReport 0xdcc
+#define rOFDM_AGCReport 0xdd0
+#define rOFDM_RxSNR 0xdd4
+#define rOFDM_RxEVMCSI 0xdd8
+#define rOFDM_SIGReport 0xddc
+
+
+/* */
+/* 8. PageE(0xE00) */
+/* */
+#define rTxAGC_A_Rate18_06 0xe00
+#define rTxAGC_A_Rate54_24 0xe04
+#define rTxAGC_A_CCK1_Mcs32 0xe08
+#define rTxAGC_A_Mcs03_Mcs00 0xe10
+#define rTxAGC_A_Mcs07_Mcs04 0xe14
+#define rTxAGC_A_Mcs11_Mcs08 0xe18
+#define rTxAGC_A_Mcs15_Mcs12 0xe1c
+
+#define rTxAGC_B_Rate18_06 0x830
+#define rTxAGC_B_Rate54_24 0x834
+#define rTxAGC_B_CCK1_55_Mcs32 0x838
+#define rTxAGC_B_Mcs03_Mcs00 0x83c
+#define rTxAGC_B_Mcs07_Mcs04 0x848
+#define rTxAGC_B_Mcs11_Mcs08 0x84c
+#define rTxAGC_B_Mcs15_Mcs12 0x868
+#define rTxAGC_B_CCK11_A_CCK2_11 0x86c
+
+#define rFPGA0_IQK 0xe28
+#define rTx_IQK_Tone_A 0xe30
+#define rRx_IQK_Tone_A 0xe34
+#define rTx_IQK_PI_A 0xe38
+#define rRx_IQK_PI_A 0xe3c
+
+#define rTx_IQK 0xe40
+#define rRx_IQK 0xe44
+#define rIQK_AGC_Pts 0xe48
+#define rIQK_AGC_Rsp 0xe4c
+#define rTx_IQK_Tone_B 0xe50
+#define rRx_IQK_Tone_B 0xe54
+#define rTx_IQK_PI_B 0xe58
+#define rRx_IQK_PI_B 0xe5c
+#define rIQK_AGC_Cont 0xe60
+
+#define rBlue_Tooth 0xe6c
+#define rRx_Wait_CCA 0xe70
+#define rTx_CCK_RFON 0xe74
+#define rTx_CCK_BBON 0xe78
+#define rTx_OFDM_RFON 0xe7c
+#define rTx_OFDM_BBON 0xe80
+#define rTx_To_Rx 0xe84
+#define rTx_To_Tx 0xe88
+#define rRx_CCK 0xe8c
+
+#define rTx_Power_Before_IQK_A 0xe94
+#define rTx_Power_After_IQK_A 0xe9c
+
+#define rRx_Power_Before_IQK_A 0xea0
+#define rRx_Power_Before_IQK_A_2 0xea4
+#define rRx_Power_After_IQK_A 0xea8
+#define rRx_Power_After_IQK_A_2 0xeac
+
+#define rTx_Power_Before_IQK_B 0xeb4
+#define rTx_Power_After_IQK_B 0xebc
+
+#define rRx_Power_Before_IQK_B 0xec0
+#define rRx_Power_Before_IQK_B_2 0xec4
+#define rRx_Power_After_IQK_B 0xec8
+#define rRx_Power_After_IQK_B_2 0xecc
+
+#define rRx_OFDM 0xed0
+#define rRx_Wait_RIFS 0xed4
+#define rRx_TO_Rx 0xed8
+#define rStandby 0xedc
+#define rSleep 0xee0
+#define rPMPD_ANAEN 0xeec
+
+/* */
+/* 7. RF Register 0x00-0x2E (RF 8256) */
+/* RF-0222D 0x00-3F */
+/* */
+/* Zebra1 */
+#define rZebra1_HSSIEnable 0x0 /* Useless now */
+#define rZebra1_TRxEnable1 0x1
+#define rZebra1_TRxEnable2 0x2
+#define rZebra1_AGC 0x4
+#define rZebra1_ChargePump 0x5
+#define rZebra1_Channel 0x7 /* RF channel switch */
+
+/* endif */
+#define rZebra1_TxGain 0x8 /* Useless now */
+#define rZebra1_TxLPF 0x9
+#define rZebra1_RxLPF 0xb
+#define rZebra1_RxHPFCorner 0xc
+
+/* Zebra4 */
+#define rGlobalCtrl 0 /* Useless now */
+#define rRTL8256_TxLPF 19
+#define rRTL8256_RxLPF 11
+
+/* RTL8258 */
+#define rRTL8258_TxLPF 0x11 /* Useless now */
+#define rRTL8258_RxLPF 0x13
+#define rRTL8258_RSSILPF 0xa
+
+/* */
+/* RL6052 Register definition */
+/* */
+#define RF_AC 0x00 /* */
+
+#define RF_IQADJ_G1 0x01 /* */
+#define RF_IQADJ_G2 0x02 /* */
+
+#define RF_POW_TRSW 0x05 /* */
+
+#define RF_GAIN_RX 0x06 /* */
+#define RF_GAIN_TX 0x07 /* */
+
+#define RF_TXM_IDAC 0x08 /* */
+#define RF_IPA_G 0x09 /* */
+#define RF_TXBIAS_G 0x0A
+#define RF_TXPA_AG 0x0B
+#define RF_IPA_A 0x0C /* */
+#define RF_TXBIAS_A 0x0D
+#define RF_BS_PA_APSET_G9_G11 0x0E
+#define RF_BS_IQGEN 0x0F /* */
+
+#define RF_MODE1 0x10 /* */
+#define RF_MODE2 0x11 /* */
+
+#define RF_RX_AGC_HP 0x12 /* */
+#define RF_TX_AGC 0x13 /* */
+#define RF_BIAS 0x14 /* */
+#define RF_IPA 0x15 /* */
+#define RF_TXBIAS 0x16
+#define RF_POW_ABILITY 0x17 /* */
+#define RF_CHNLBW 0x18 /* RF channel and BW switch */
+#define RF_TOP 0x19 /* */
+
+#define RF_RX_G1 0x1A /* */
+#define RF_RX_G2 0x1B /* */
+
+#define RF_RX_BB2 0x1C /* */
+#define RF_RX_BB1 0x1D /* */
+
+#define RF_RCK1 0x1E /* */
+#define RF_RCK2 0x1F /* */
+
+#define RF_TX_G1 0x20 /* */
+#define RF_TX_G2 0x21 /* */
+#define RF_TX_G3 0x22 /* */
+
+#define RF_TX_BB1 0x23 /* */
+
+#define RF_T_METER_92D 0x42 /* */
+#define RF_T_METER_88E 0x42 /* */
+#define RF_T_METER 0x24 /* */
+
+#define RF_SYN_G1 0x25 /* RF TX Power control */
+#define RF_SYN_G2 0x26 /* RF TX Power control */
+#define RF_SYN_G3 0x27 /* RF TX Power control */
+#define RF_SYN_G4 0x28 /* RF TX Power control */
+#define RF_SYN_G5 0x29 /* RF TX Power control */
+#define RF_SYN_G6 0x2A /* RF TX Power control */
+#define RF_SYN_G7 0x2B /* RF TX Power control */
+#define RF_SYN_G8 0x2C /* RF TX Power control */
+
+#define RF_RCK_OS 0x30 /* RF TX PA control */
+#define RF_TXPA_G1 0x31 /* RF TX PA control */
+#define RF_TXPA_G2 0x32 /* RF TX PA control */
+#define RF_TXPA_G3 0x33 /* RF TX PA control */
+#define RF_TX_BIAS_A 0x35
+#define RF_TX_BIAS_D 0x36
+#define RF_LOBF_9 0x38
+#define RF_RXRF_A3 0x3C /* */
+#define RF_TRSW 0x3F
+
+#define RF_TXRF_A2 0x41
+#define RF_TXPA_G4 0x46
+#define RF_TXPA_A4 0x4B
+#define RF_0x52 0x52
+#define RF_WE_LUT 0xEF
+
+
+/* */
+/* Bit Mask */
+/* */
+/* 1. Page1(0x100) */
+#define bBBResetB 0x100 /* Useless now? */
+#define bGlobalResetB 0x200
+#define bOFDMTxStart 0x4
+#define bCCKTxStart 0x8
+#define bCRC32Debug 0x100
+#define bPMACLoopback 0x10
+#define bTxLSIG 0xffffff
+#define bOFDMTxRate 0xf
+#define bOFDMTxReserved 0x10
+#define bOFDMTxLength 0x1ffe0
+#define bOFDMTxParity 0x20000
+#define bTxHTSIG1 0xffffff
+#define bTxHTMCSRate 0x7f
+#define bTxHTBW 0x80
+#define bTxHTLength 0xffff00
+#define bTxHTSIG2 0xffffff
+#define bTxHTSmoothing 0x1
+#define bTxHTSounding 0x2
+#define bTxHTReserved 0x4
+#define bTxHTAggreation 0x8
+#define bTxHTSTBC 0x30
+#define bTxHTAdvanceCoding 0x40
+#define bTxHTShortGI 0x80
+#define bTxHTNumberHT_LTF 0x300
+#define bTxHTCRC8 0x3fc00
+#define bCounterReset 0x10000
+#define bNumOfOFDMTx 0xffff
+#define bNumOfCCKTx 0xffff0000
+#define bTxIdleInterval 0xffff
+#define bOFDMService 0xffff0000
+#define bTxMACHeader 0xffffffff
+#define bTxDataInit 0xff
+#define bTxHTMode 0x100
+#define bTxDataType 0x30000
+#define bTxRandomSeed 0xffffffff
+#define bCCKTxPreamble 0x1
+#define bCCKTxSFD 0xffff0000
+#define bCCKTxSIG 0xff
+#define bCCKTxService 0xff00
+#define bCCKLengthExt 0x8000
+#define bCCKTxLength 0xffff0000
+#define bCCKTxCRC16 0xffff
+#define bCCKTxStatus 0x1
+#define bOFDMTxStatus 0x2
+
+#define IS_BB_REG_OFFSET_92S(_Offset) \
+ ((_Offset >= 0x800) && (_Offset <= 0xfff))
+
+/* 2. Page8(0x800) */
+#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */
+#define bJapanMode 0x2
+#define bCCKTxSC 0x30
+#define bCCKEn 0x1000000
+#define bOFDMEn 0x2000000
+
+#define bOFDMRxADCPhase 0x10000 /* Useless now */
+#define bOFDMTxDACPhase 0x40000
+#define bXATxAGC 0x3f
+
+#define bAntennaSelect 0x0300
+
+#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */
+#define bXCTxAGC 0xf000
+#define bXDTxAGC 0xf0000
+
+#define bPAStart 0xf0000000 /* Useless now */
+#define bTRStart 0x00f00000
+#define bRFStart 0x0000f000
+#define bBBStart 0x000000f0
+#define bBBCCKStart 0x0000000f
+#define bPAEnd 0xf /* Reg0x814 */
+#define bTREnd 0x0f000000
+#define bRFEnd 0x000f0000
+#define bCCAMask 0x000000f0 /* T2R */
+#define bR2RCCAMask 0x00000f00
+#define bHSSI_R2TDelay 0xf8000000
+#define bHSSI_T2RDelay 0xf80000
+#define bContTxHSSI 0x400 /* change gain at continue Tx */
+#define bIGFromCCK 0x200
+#define bAGCAddress 0x3f
+#define bRxHPTx 0x7000
+#define bRxHPT2R 0x38000
+#define bRxHPCCKIni 0xc0000
+#define bAGCTxCode 0xc00000
+#define bAGCRxCode 0x300000
+
+/* Reg 0x820~84f rFPGA0_XA_HSSIParameter1 */
+#define b3WireDataLength 0x800
+#define b3WireAddressLength 0x400
+
+#define b3WireRFPowerDown 0x1 /* Useless now */
+#define b5GPAPEPolarity 0x40000000
+#define b2GPAPEPolarity 0x80000000
+#define bRFSW_TxDefaultAnt 0x3
+#define bRFSW_TxOptionAnt 0x30
+#define bRFSW_RxDefaultAnt 0x300
+#define bRFSW_RxOptionAnt 0x3000
+#define bRFSI_3WireData 0x1
+#define bRFSI_3WireClock 0x2
+#define bRFSI_3WireLoad 0x4
+#define bRFSI_3WireRW 0x8
+#define bRFSI_3Wire 0xf
+
+#define bRFSI_RFENV 0x10 /* Reg 0x870 rFPGA0_XAB_RFInterfaceSW */
+
+#define bRFSI_TRSW 0x20 /* Useless now */
+#define bRFSI_TRSWB 0x40
+#define bRFSI_ANTSW 0x100
+#define bRFSI_ANTSWB 0x200
+#define bRFSI_PAPE 0x400
+#define bRFSI_PAPE5G 0x800
+#define bBandSelect 0x1
+#define bHTSIG2_GI 0x80
+#define bHTSIG2_Smoothing 0x01
+#define bHTSIG2_Sounding 0x02
+#define bHTSIG2_Aggreaton 0x08
+#define bHTSIG2_STBC 0x30
+#define bHTSIG2_AdvCoding 0x40
+#define bHTSIG2_NumOfHTLTF 0x300
+#define bHTSIG2_CRC8 0x3fc
+#define bHTSIG1_MCS 0x7f
+#define bHTSIG1_BandWidth 0x80
+#define bHTSIG1_HTLength 0xffff
+#define bLSIG_Rate 0xf
+#define bLSIG_Reserved 0x10
+#define bLSIG_Length 0x1fffe
+#define bLSIG_Parity 0x20
+#define bCCKRxPhase 0x4
+
+#define bLSSIReadAddress 0x7f800000 /* T65 RF */
+
+#define bLSSIReadEdge 0x80000000 /* LSSI "Read" edge signal */
+
+#define bLSSIReadBackData 0xfffff /* T65 RF */
+
+#define bLSSIReadOKFlag 0x1000 /* Useless now */
+#define bCCKSampleRate 0x8 /* 0: 44MHz, 1:88MHz */
+#define bRegulator0Standby 0x1
+#define bRegulatorPLLStandby 0x2
+#define bRegulator1Standby 0x4
+#define bPLLPowerUp 0x8
+#define bDPLLPowerUp 0x10
+#define bDA10PowerUp 0x20
+#define bAD7PowerUp 0x200
+#define bDA6PowerUp 0x2000
+#define bXtalPowerUp 0x4000
+#define b40MDClkPowerUP 0x8000
+#define bDA6DebugMode 0x20000
+#define bDA6Swing 0x380000
+
+/* Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */
+#define bADClkPhase 0x4000000
+
+#define b80MClkDelay 0x18000000 /* Useless */
+#define bAFEWatchDogEnable 0x20000000
+
+/* Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap */
+#define bXtalCap01 0xc0000000
+#define bXtalCap23 0x3
+#define bXtalCap92x 0x0f000000
+#define bXtalCap 0x0f000000
+
+#define bIntDifClkEnable 0x400 /* Useless */
+#define bExtSigClkEnable 0x800
+#define bBandgapMbiasPowerUp 0x10000
+#define bAD11SHGain 0xc0000
+#define bAD11InputRange 0x700000
+#define bAD11OPCurrent 0x3800000
+#define bIPathLoopback 0x4000000
+#define bQPathLoopback 0x8000000
+#define bAFELoopback 0x10000000
+#define bDA10Swing 0x7e0
+#define bDA10Reverse 0x800
+#define bDAClkSource 0x1000
+#define bAD7InputRange 0x6000
+#define bAD7Gain 0x38000
+#define bAD7OutputCMMode 0x40000
+#define bAD7InputCMMode 0x380000
+#define bAD7Current 0xc00000
+#define bRegulatorAdjust 0x7000000
+#define bAD11PowerUpAtTx 0x1
+#define bDA10PSAtTx 0x10
+#define bAD11PowerUpAtRx 0x100
+#define bDA10PSAtRx 0x1000
+#define bCCKRxAGCFormat 0x200
+#define bPSDFFTSamplepPoint 0xc000
+#define bPSDAverageNum 0x3000
+#define bIQPathControl 0xc00
+#define bPSDFreq 0x3ff
+#define bPSDAntennaPath 0x30
+#define bPSDIQSwitch 0x40
+#define bPSDRxTrigger 0x400000
+#define bPSDTxTrigger 0x80000000
+#define bPSDSineToneScale 0x7f000000
+#define bPSDReport 0xffff
+
+/* 3. Page9(0x900) */
+#define bOFDMTxSC 0x30000000 /* Useless */
+#define bCCKTxOn 0x1
+#define bOFDMTxOn 0x2
+#define bDebugPage 0xfff /* reset debug page and HWord, LWord */
+#define bDebugItem 0xff /* reset debug page and LWord */
+#define bAntL 0x10
+#define bAntNonHT 0x100
+#define bAntHT1 0x1000
+#define bAntHT2 0x10000
+#define bAntHT1S1 0x100000
+#define bAntNonHTS1 0x1000000
+
+/* 4. PageA(0xA00) */
+#define bCCKBBMode 0x3 /* Useless */
+#define bCCKTxPowerSaving 0x80
+#define bCCKRxPowerSaving 0x40
+
+#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 */
+
+#define bCCKScramble 0x8 /* Useless */
+#define bCCKAntDiversity 0x8000
+#define bCCKCarrierRecovery 0x4000
+#define bCCKTxRate 0x3000
+#define bCCKDCCancel 0x0800
+#define bCCKISICancel 0x0400
+#define bCCKMatchFilter 0x0200
+#define bCCKEqualizer 0x0100
+#define bCCKPreambleDetect 0x800000
+#define bCCKFastFalseCCA 0x400000
+#define bCCKChEstStart 0x300000
+#define bCCKCCACount 0x080000
+#define bCCKcs_lim 0x070000
+#define bCCKBistMode 0x80000000
+#define bCCKCCAMask 0x40000000
+#define bCCKTxDACPhase 0x4
+#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */
+#define bCCKr_cp_mode0 0x0100
+#define bCCKTxDCOffset 0xf0
+#define bCCKRxDCOffset 0xf
+#define bCCKCCAMode 0xc000
+#define bCCKFalseCS_lim 0x3f00
+#define bCCKCS_ratio 0xc00000
+#define bCCKCorgBit_sel 0x300000
+#define bCCKPD_lim 0x0f0000
+#define bCCKNewCCA 0x80000000
+#define bCCKRxHPofIG 0x8000
+#define bCCKRxIG 0x7f00
+#define bCCKLNAPolarity 0x800000
+#define bCCKRx1stGain 0x7f0000
+#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */
+#define bCCKRxAGCSatLevel 0x1f000000
+#define bCCKRxAGCSatCount 0xe0
+#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */
+#define bCCKFixedRxAGC 0x8000
+#define bCCKAntennaPolarity 0x2000
+#define bCCKTxFilterType 0x0c00
+#define bCCKRxAGCReportType 0x0300
+#define bCCKRxDAGCEn 0x80000000
+#define bCCKRxDAGCPeriod 0x20000000
+#define bCCKRxDAGCSatLevel 0x1f000000
+#define bCCKTimingRecovery 0x800000
+#define bCCKTxC0 0x3f0000
+#define bCCKTxC1 0x3f000000
+#define bCCKTxC2 0x3f
+#define bCCKTxC3 0x3f00
+#define bCCKTxC4 0x3f0000
+#define bCCKTxC5 0x3f000000
+#define bCCKTxC6 0x3f
+#define bCCKTxC7 0x3f00
+#define bCCKDebugPort 0xff0000
+#define bCCKDACDebug 0x0f000000
+#define bCCKFalseAlarmEnable 0x8000
+#define bCCKFalseAlarmRead 0x4000
+#define bCCKTRSSI 0x7f
+#define bCCKRxAGCReport 0xfe
+#define bCCKRxReport_AntSel 0x80000000
+#define bCCKRxReport_MFOff 0x40000000
+#define bCCKRxRxReport_SQLoss 0x20000000
+#define bCCKRxReport_Pktloss 0x10000000
+#define bCCKRxReport_Lockedbit 0x08000000
+#define bCCKRxReport_RateError 0x04000000
+#define bCCKRxReport_RxRate 0x03000000
+#define bCCKRxFACounterLower 0xff
+#define bCCKRxFACounterUpper 0xff000000
+#define bCCKRxHPAGCStart 0xe000
+#define bCCKRxHPAGCFinal 0x1c00
+#define bCCKRxFalseAlarmEnable 0x8000
+#define bCCKFACounterFreeze 0x4000
+#define bCCKTxPathSel 0x10000000
+#define bCCKDefaultRxPath 0xc000000
+#define bCCKOptionRxPath 0x3000000
+
+/* 5. PageC(0xC00) */
+#define bNumOfSTF 0x3 /* Useless */
+#define bShift_L 0xc0
+#define bGI_TH 0xc
+#define bRxPathA 0x1
+#define bRxPathB 0x2
+#define bRxPathC 0x4
+#define bRxPathD 0x8
+#define bTxPathA 0x1
+#define bTxPathB 0x2
+#define bTxPathC 0x4
+#define bTxPathD 0x8
+#define bTRSSIFreq 0x200
+#define bADCBackoff 0x3000
+#define bDFIRBackoff 0xc000
+#define bTRSSILatchPhase 0x10000
+#define bRxIDCOffset 0xff
+#define bRxQDCOffset 0xff00
+#define bRxDFIRMode 0x1800000
+#define bRxDCNFType 0xe000000
+#define bRXIQImb_A 0x3ff
+#define bRXIQImb_B 0xfc00
+#define bRXIQImb_C 0x3f0000
+#define bRXIQImb_D 0xffc00000
+#define bDC_dc_Notch 0x60000
+#define bRxNBINotch 0x1f000000
+#define bPD_TH 0xf
+#define bPD_TH_Opt2 0xc000
+#define bPWED_TH 0x700
+#define bIfMF_Win_L 0x800
+#define bPD_Option 0x1000
+#define bMF_Win_L 0xe000
+#define bBW_Search_L 0x30000
+#define bwin_enh_L 0xc0000
+#define bBW_TH 0x700000
+#define bED_TH2 0x3800000
+#define bBW_option 0x4000000
+#define bRatio_TH 0x18000000
+#define bWindow_L 0xe0000000
+#define bSBD_Option 0x1
+#define bFrame_TH 0x1c
+#define bFS_Option 0x60
+#define bDC_Slope_check 0x80
+#define bFGuard_Counter_DC_L 0xe00
+#define bFrame_Weight_Short 0x7000
+#define bSub_Tune 0xe00000
+#define bFrame_DC_Length 0xe000000
+#define bSBD_start_offset 0x30000000
+#define bFrame_TH_2 0x7
+#define bFrame_GI2_TH 0x38
+#define bGI2_Sync_en 0x40
+#define bSarch_Short_Early 0x300
+#define bSarch_Short_Late 0xc00
+#define bSarch_GI2_Late 0x70000
+#define bCFOAntSum 0x1
+#define bCFOAcc 0x2
+#define bCFOStartOffset 0xc
+#define bCFOLookBack 0x70
+#define bCFOSumWeight 0x80
+#define bDAGCEnable 0x10000
+#define bTXIQImb_A 0x3ff
+#define bTXIQImb_B 0xfc00
+#define bTXIQImb_C 0x3f0000
+#define bTXIQImb_D 0xffc00000
+#define bTxIDCOffset 0xff
+#define bTxQDCOffset 0xff00
+#define bTxDFIRMode 0x10000
+#define bTxPesudoNoiseOn 0x4000000
+#define bTxPesudoNoise_A 0xff
+#define bTxPesudoNoise_B 0xff00
+#define bTxPesudoNoise_C 0xff0000
+#define bTxPesudoNoise_D 0xff000000
+#define bCCADropOption 0x20000
+#define bCCADropThres 0xfff00000
+#define bEDCCA_H 0xf
+#define bEDCCA_L 0xf0
+#define bLambda_ED 0x300
+#define bRxInitialGain 0x7f
+#define bRxAntDivEn 0x80
+#define bRxAGCAddressForLNA 0x7f00
+#define bRxHighPowerFlow 0x8000
+#define bRxAGCFreezeThres 0xc0000
+#define bRxFreezeStep_AGC1 0x300000
+#define bRxFreezeStep_AGC2 0xc00000
+#define bRxFreezeStep_AGC3 0x3000000
+#define bRxFreezeStep_AGC0 0xc000000
+#define bRxRssi_Cmp_En 0x10000000
+#define bRxQuickAGCEn 0x20000000
+#define bRxAGCFreezeThresMode 0x40000000
+#define bRxOverFlowCheckType 0x80000000
+#define bRxAGCShift 0x7f
+#define bTRSW_Tri_Only 0x80
+#define bPowerThres 0x300
+#define bRxAGCEn 0x1
+#define bRxAGCTogetherEn 0x2
+#define bRxAGCMin 0x4
+#define bRxHP_Ini 0x7
+#define bRxHP_TRLNA 0x70
+#define bRxHP_RSSI 0x700
+#define bRxHP_BBP1 0x7000
+#define bRxHP_BBP2 0x70000
+#define bRxHP_BBP3 0x700000
+#define bRSSI_H 0x7f0000 /* threshold for high power */
+#define bRSSI_Gen 0x7f000000 /* threshold for ant diversity */
+#define bRxSettle_TRSW 0x7
+#define bRxSettle_LNA 0x38
+#define bRxSettle_RSSI 0x1c0
+#define bRxSettle_BBP 0xe00
+#define bRxSettle_RxHP 0x7000
+#define bRxSettle_AntSW_RSSI 0x38000
+#define bRxSettle_AntSW 0xc0000
+#define bRxProcessTime_DAGC 0x300000
+#define bRxSettle_HSSI 0x400000
+#define bRxProcessTime_BBPPW 0x800000
+#define bRxAntennaPowerShift 0x3000000
+#define bRSSITableSelect 0xc000000
+#define bRxHP_Final 0x7000000
+#define bRxHTSettle_BBP 0x7
+#define bRxHTSettle_HSSI 0x8
+#define bRxHTSettle_RxHP 0x70
+#define bRxHTSettle_BBPPW 0x80
+#define bRxHTSettle_Idle 0x300
+#define bRxHTSettle_Reserved 0x1c00
+#define bRxHTRxHPEn 0x8000
+#define bRxHTAGCFreezeThres 0x30000
+#define bRxHTAGCTogetherEn 0x40000
+#define bRxHTAGCMin 0x80000
+#define bRxHTAGCEn 0x100000
+#define bRxHTDAGCEn 0x200000
+#define bRxHTRxHP_BBP 0x1c00000
+#define bRxHTRxHP_Final 0xe0000000
+#define bRxPWRatioTH 0x3
+#define bRxPWRatioEn 0x4
+#define bRxMFHold 0x3800
+#define bRxPD_Delay_TH1 0x38
+#define bRxPD_Delay_TH2 0x1c0
+#define bRxPD_DC_COUNT_MAX 0x600
+#define bRxPD_Delay_TH 0x8000
+#define bRxProcess_Delay 0xf0000
+#define bRxSearchrange_GI2_Early 0x700000
+#define bRxFrame_Guard_Counter_L 0x3800000
+#define bRxSGI_Guard_L 0xc000000
+#define bRxSGI_Search_L 0x30000000
+#define bRxSGI_TH 0xc0000000
+#define bDFSCnt0 0xff
+#define bDFSCnt1 0xff00
+#define bDFSFlag 0xf0000
+#define bMFWeightSum 0x300000
+#define bMinIdxTH 0x7f000000
+#define bDAFormat 0x40000
+#define bTxChEmuEnable 0x01000000
+#define bTRSWIsolation_A 0x7f
+#define bTRSWIsolation_B 0x7f00
+#define bTRSWIsolation_C 0x7f0000
+#define bTRSWIsolation_D 0x7f000000
+#define bExtLNAGain 0x7c00
+
+/* 6. PageE(0xE00) */
+#define bSTBCEn 0x4 /* Useless */
+#define bAntennaMapping 0x10
+#define bNss 0x20
+#define bCFOAntSumD 0x200
+#define bPHYCounterReset 0x8000000
+#define bCFOReportGet 0x4000000
+#define bOFDMContinueTx 0x10000000
+#define bOFDMSingleCarrier 0x20000000
+#define bOFDMSingleTone 0x40000000
+#define bHTDetect 0x100
+#define bCFOEn 0x10000
+#define bCFOValue 0xfff00000
+#define bSigTone_Re 0x3f
+#define bSigTone_Im 0x7f00
+#define bCounter_CCA 0xffff
+#define bCounter_ParityFail 0xffff0000
+#define bCounter_RateIllegal 0xffff
+#define bCounter_CRC8Fail 0xffff0000
+#define bCounter_MCSNoSupport 0xffff
+#define bCounter_FastSync 0xffff
+#define bShortCFO 0xfff
+#define bShortCFOTLength 12 /* total */
+#define bShortCFOFLength 11 /* fraction */
+#define bLongCFO 0x7ff
+#define bLongCFOTLength 11
+#define bLongCFOFLength 11
+#define bTailCFO 0x1fff
+#define bTailCFOTLength 13
+#define bTailCFOFLength 12
+#define bmax_en_pwdB 0xffff
+#define bCC_power_dB 0xffff0000
+#define bnoise_pwdB 0xffff
+#define bPowerMeasTLength 10
+#define bPowerMeasFLength 3
+#define bRx_HT_BW 0x1
+#define bRxSC 0x6
+#define bRx_HT 0x8
+#define bNB_intf_det_on 0x1
+#define bIntf_win_len_cfg 0x30
+#define bNB_Intf_TH_cfg 0x1c0
+#define bRFGain 0x3f
+#define bTableSel 0x40
+#define bTRSW 0x80
+#define bRxSNR_A 0xff
+#define bRxSNR_B 0xff00
+#define bRxSNR_C 0xff0000
+#define bRxSNR_D 0xff000000
+#define bSNREVMTLength 8
+#define bSNREVMFLength 1
+#define bCSI1st 0xff
+#define bCSI2nd 0xff00
+#define bRxEVM1st 0xff0000
+#define bRxEVM2nd 0xff000000
+#define bSIGEVM 0xff
+#define bPWDB 0xff00
+#define bSGIEN 0x10000
+
+#define bSFactorQAM1 0xf /* Useless */
+#define bSFactorQAM2 0xf0
+#define bSFactorQAM3 0xf00
+#define bSFactorQAM4 0xf000
+#define bSFactorQAM5 0xf0000
+#define bSFactorQAM6 0xf0000
+#define bSFactorQAM7 0xf00000
+#define bSFactorQAM8 0xf000000
+#define bSFactorQAM9 0xf0000000
+#define bCSIScheme 0x100000
+
+#define bNoiseLvlTopSet 0x3 /* Useless */
+#define bChSmooth 0x4
+#define bChSmoothCfg1 0x38
+#define bChSmoothCfg2 0x1c0
+#define bChSmoothCfg3 0xe00
+#define bChSmoothCfg4 0x7000
+#define bMRCMode 0x800000
+#define bTHEVMCfg 0x7000000
+
+#define bLoopFitType 0x1 /* Useless */
+#define bUpdCFO 0x40
+#define bUpdCFOOffData 0x80
+#define bAdvUpdCFO 0x100
+#define bAdvTimeCtrl 0x800
+#define bUpdClko 0x1000
+#define bFC 0x6000
+#define bTrackingMode 0x8000
+#define bPhCmpEnable 0x10000
+#define bUpdClkoLTF 0x20000
+#define bComChCFO 0x40000
+#define bCSIEstiMode 0x80000
+#define bAdvUpdEqz 0x100000
+#define bUChCfg 0x7000000
+#define bUpdEqz 0x8000000
+
+/* Rx Pseduo noise */
+#define bRxPesudoNoiseOn 0x20000000 /* Useless */
+#define bRxPesudoNoise_A 0xff
+#define bRxPesudoNoise_B 0xff00
+#define bRxPesudoNoise_C 0xff0000
+#define bRxPesudoNoise_D 0xff000000
+#define bPesudoNoiseState_A 0xffff
+#define bPesudoNoiseState_B 0xffff0000
+#define bPesudoNoiseState_C 0xffff
+#define bPesudoNoiseState_D 0xffff0000
+
+/* 7. RF Register */
+/* Zebra1 */
+#define bZebra1_HSSIEnable 0x8 /* Useless */
+#define bZebra1_TRxControl 0xc00
+#define bZebra1_TRxGainSetting 0x07f
+#define bZebra1_RxCorner 0xc00
+#define bZebra1_TxChargePump 0x38
+#define bZebra1_RxChargePump 0x7
+#define bZebra1_ChannelNum 0xf80
+#define bZebra1_TxLPFBW 0x400
+#define bZebra1_RxLPFBW 0x600
+
+/* Zebra4 */
+#define bRTL8256RegModeCtrl1 0x100 /* Useless */
+#define bRTL8256RegModeCtrl0 0x40
+#define bRTL8256_TxLPFBW 0x18
+#define bRTL8256_RxLPFBW 0x600
+
+/* RTL8258 */
+#define bRTL8258_TxLPFBW 0xc /* Useless */
+#define bRTL8258_RxLPFBW 0xc00
+#define bRTL8258_RSSILPFBW 0xc0
+
+
+/* */
+/* Other Definition */
+/* */
+
+/* byte endable for sb_write */
+#define bByte0 0x1 /* Useless */
+#define bByte1 0x2
+#define bByte2 0x4
+#define bByte3 0x8
+#define bWord0 0x3
+#define bWord1 0xc
+#define bDWord 0xf
+
+/* for PutRegsetting & GetRegSetting BitMask */
+#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */
+#define bMaskByte1 0xff00
+#define bMaskByte2 0xff0000
+#define bMaskByte3 0xff000000
+#define bMaskHWord 0xffff0000
+#define bMaskLWord 0x0000ffff
+#define bMaskDWord 0xffffffff
+#define bMask12Bits 0xfff
+#define bMaskH4Bits 0xf0000000
+#define bMaskOFDM_D 0xffc00000
+#define bMaskCCK 0x3f3f3f3f
+
+/* for PutRFRegsetting & GetRFRegSetting BitMask */
+#define bRFRegOffsetMask 0xfffff
+
+#define bEnable 0x1 /* Useless */
+#define bDisable 0x0
+
+#define LeftAntenna 0x0 /* Useless */
+#define RightAntenna 0x1
+
+#define tCheckTxStatus 500 /* 500ms Useless */
+#define tUpdateRxCounter 100 /* 100ms */
+
+#define rateCCK 0 /* Useless */
+#define rateOFDM 1
+#define rateHT 2
+
+/* define Register-End */
+#define bPMAC_End 0x1ff /* Useless */
+#define bFPGAPHY0_End 0x8ff
+#define bFPGAPHY1_End 0x9ff
+#define bCCKPHY0_End 0xaff
+#define bOFDMPHY0_End 0xcff
+#define bOFDMPHY1_End 0xdff
+
+#define bPMACControl 0x0 /* Useless */
+#define bWMACControl 0x1
+#define bWNICControl 0x2
+
+#define PathA 0x0 /* Useless */
+#define PathB 0x1
+#define PathC 0x2
+#define PathD 0x3
+
+/*--------------------------Define Parameters-------------------------------*/
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/Hal8188EPwrSeq.h b/drivers/staging/rtl8188eu/include/Hal8188EPwrSeq.h
new file mode 100644
index 00000000000..20d0b3e3ad7
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188EPwrSeq.h
@@ -0,0 +1,176 @@
+
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __HAL8188EPWRSEQ_H__
+#define __HAL8188EPWRSEQ_H__
+
+#include "HalPwrSeqCmd.h"
+
+/*
+ Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.vsd
+ There are 6 HW Power States:
+ 0: POFF--Power Off
+ 1: PDN--Power Down
+ 2: CARDEMU--Card Emulation
+ 3: ACT--Active Mode
+ 4: LPS--Low Power State
+ 5: SUS--Suspend
+
+ The transision from different states are defined below
+ TRANS_CARDEMU_TO_ACT
+ TRANS_ACT_TO_CARDEMU
+ TRANS_CARDEMU_TO_SUS
+ TRANS_SUS_TO_CARDEMU
+ TRANS_CARDEMU_TO_PDN
+ TRANS_ACT_TO_LPS
+ TRANS_LPS_TO_ACT
+
+ TRANS_END
+
+ PWR SEQ Version: rtl8188E_PwrSeq_V09.h
+*/
+#define RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS 10
+#define RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS 10
+#define RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS 10
+#define RTL8188E_TRANS_SUS_TO_CARDEMU_STEPS 10
+#define RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS 10
+#define RTL8188E_TRANS_PDN_TO_CARDEMU_STEPS 10
+#define RTL8188E_TRANS_ACT_TO_LPS_STEPS 15
+#define RTL8188E_TRANS_LPS_TO_ACT_STEPS 15
+#define RTL8188E_TRANS_END_STEPS 1
+
+
+#define RTL8188E_TRANS_CARDEMU_TO_ACT \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \
+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1 power ready*/ \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0|BIT1, 0}, /* 0x02[1:0] = 0 reset BB*/ \
+ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7}, /*0x24[23] = 2b'01 schmit trigger */ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0}, /* 0x04[15] = 0 disable HWPDN (control by DRV)*/\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4|BIT3, 0}, /*0x04[12:11] = 2b'00 disable WL suspend*/ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0}, /*0x04[8] = 1 polling until return 0*/ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0}, /*wait till 0x04[8] = 0*/ \
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*LDO normal mode*/ \
+ {0x0074, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*SDIO Driving*/ \
+
+#define RTL8188E_TRANS_ACT_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \
+ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/ \
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*LDO Sleep mode*/ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \
+
+#define RTL8188E_TRANS_CARDEMU_TO_SUS \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01enable WL suspend*/ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3|BIT4}, /*0x04[12:11] = 2b'11enable WL suspend for PCIe*/ \
+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, BIT7}, /* 0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */ \
+ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*Clear SIC_EN register 0x40[12] = 1'b0 */ \
+ {0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*Set USB suspend enable local register 0xfe10[4]=1 */ \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/
+
+#define RTL8188E_TRANS_SUS_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/
+
+#define RTL8188E_TRANS_CARDEMU_TO_CARDDIS \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \
+ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7}, /*0x24[23] = 2b'01 schmit trigger */ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \
+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /* 0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */ \
+ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*Clear SIC_EN register 0x40[12] = 1'b0 */ \
+ {0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*Set USB suspend enable local register 0xfe10[4]=1 */ \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/ \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/
+
+#define RTL8188E_TRANS_CARDDIS_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/ \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/
+
+#define RTL8188E_TRANS_CARDEMU_TO_PDN \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \
+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/* 0x04[16] = 0*/\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/
+
+#define RTL8188E_TRANS_PDN_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here */ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/
+
+/* This is used by driver for LPSRadioOff Procedure, not for FW LPS Step */
+#define RTL8188E_TRANS_ACT_TO_LPS \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here */ \
+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/ \
+ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \
+ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \
+ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \
+ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled,and clock are gated*/ \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \
+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F},/*Reset MAC TRX*/ \
+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/ \
+ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/ \
+
+
+#define RTL8188E_TRANS_LPS_TO_ACT \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here */ \
+ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\
+ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\
+ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\
+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*. 0x08[4] = 0 switch TSF to 40M*/\
+ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]=0 TSF in 40M*/\
+ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6|BIT7, 0}, /*. 0x29[7:6] = 2b'00 enable BB clock*/\
+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*. 0x101[1] = 1*/\
+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0}, /*. 0x02[1:0] = 2b'11 enable BB macro*/\
+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/
+
+#define RTL8188E_TRANS_END \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \
+ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,0, PWR_CMD_END, 0, 0}, /* */
+
+
+extern struct wl_pwr_cfg rtl8188E_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_card_disable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_card_enable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS+RTL8188E_TRANS_END_STEPS];
+
+#endif /* __HAL8188EPWRSEQ_H__ */
diff --git a/drivers/staging/rtl8188eu/include/Hal8188ERateAdaptive.h b/drivers/staging/rtl8188eu/include/Hal8188ERateAdaptive.h
new file mode 100644
index 00000000000..21996a1173e
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188ERateAdaptive.h
@@ -0,0 +1,75 @@
+#ifndef __INC_RA_H
+#define __INC_RA_H
+/*++
+Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+
+Module Name:
+ RateAdaptive.h
+
+Abstract:
+ Prototype of RA and related data structure.
+
+Major Change History:
+ When Who What
+ ---------- --------------- -------------------------------
+ 2011-08-12 Page Create.
+--*/
+
+/* Rate adaptive define */
+#define PERENTRY 23
+#define RETRYSIZE 5
+#define RATESIZE 28
+#define TX_RPT2_ITEM_SIZE 8
+
+/* */
+/* TX report 2 format in Rx desc */
+/* */
+#define GET_TX_RPT2_DESC_PKT_LEN_88E(__pRxStatusDesc) \
+ LE_BITS_TO_4BYTE(__pRxStatusDesc, 0, 9)
+#define GET_TX_RPT2_DESC_MACID_VALID_1_88E(__pRxStatusDesc) \
+ LE_BITS_TO_4BYTE(__pRxStatusDesc+16, 0, 32)
+#define GET_TX_RPT2_DESC_MACID_VALID_2_88E(__pRxStatusDesc) \
+ LE_BITS_TO_4BYTE(__pRxStatusDesc+20, 0, 32)
+
+#define GET_TX_REPORT_TYPE1_RERTY_0(__pAddr) \
+ LE_BITS_TO_4BYTE(__pAddr, 0, 16)
+#define GET_TX_REPORT_TYPE1_RERTY_1(__pAddr) \
+ LE_BITS_TO_1BYTE(__pAddr+2, 0, 8)
+#define GET_TX_REPORT_TYPE1_RERTY_2(__pAddr) \
+ LE_BITS_TO_1BYTE(__pAddr+3, 0, 8)
+#define GET_TX_REPORT_TYPE1_RERTY_3(__pAddr) \
+ LE_BITS_TO_1BYTE(__pAddr+4, 0, 8)
+#define GET_TX_REPORT_TYPE1_RERTY_4(__pAddr) \
+ LE_BITS_TO_1BYTE(__pAddr+4+1, 0, 8)
+#define GET_TX_REPORT_TYPE1_DROP_0(__pAddr) \
+ LE_BITS_TO_1BYTE(__pAddr+4+2, 0, 8)
+#define GET_TX_REPORT_TYPE1_DROP_1(__pAddr) \
+ LE_BITS_TO_1BYTE(__pAddr+4+3, 0, 8)
+
+/* End rate adaptive define */
+
+void ODM_RASupport_Init(struct odm_dm_struct *dm_odm);
+
+int ODM_RAInfo_Init_all(struct odm_dm_struct *dm_odm);
+
+int ODM_RAInfo_Init(struct odm_dm_struct *dm_odm, u8 MacID);
+
+u8 ODM_RA_GetShortGI_8188E(struct odm_dm_struct *dm_odm, u8 MacID);
+
+u8 ODM_RA_GetDecisionRate_8188E(struct odm_dm_struct *dm_odm, u8 MacID);
+
+u8 ODM_RA_GetHwPwrStatus_8188E(struct odm_dm_struct *dm_odm, u8 MacID);
+void ODM_RA_UpdateRateInfo_8188E(struct odm_dm_struct *dm_odm, u8 MacID,
+ u8 RateID, u32 RateMask,
+ u8 SGIEnable);
+
+void ODM_RA_SetRSSI_8188E(struct odm_dm_struct *dm_odm, u8 macid,
+ u8 rssi);
+
+void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm,
+ u8 *txrpt_buf, u16 txrpt_len,
+ u32 validentry0, u32 validentry1);
+
+void ODM_RA_Set_TxRPT_Time(struct odm_dm_struct *dm_odm, u16 minRptTime);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/Hal8188EReg.h b/drivers/staging/rtl8188eu/include/Hal8188EReg.h
new file mode 100644
index 00000000000..d880b0cc803
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188EReg.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+/* */
+/* File Name: Hal8188EReg.h */
+/* */
+/* Description: */
+/* */
+/* This file is for RTL8188E register definition. */
+/* */
+/* */
+/* */
+#ifndef __HAL_8188E_REG_H__
+#define __HAL_8188E_REG_H__
+
+/* */
+/* Register Definition */
+/* */
+#define TRX_ANTDIV_PATH 0x860
+#define RX_ANTDIV_PATH 0xb2c
+#define ODM_R_A_AGC_CORE1_8188E 0xc50
+
+
+/* */
+/* Bitmap Definition */
+/* */
+#define BIT_FA_RESET_8188E BIT0
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/HalHWImg8188E_BB.h b/drivers/staging/rtl8188eu/include/HalHWImg8188E_BB.h
new file mode 100644
index 00000000000..e57452104bf
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalHWImg8188E_BB.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+*
+*
+******************************************************************************/
+
+#ifndef __INC_BB_8188E_HW_IMG_H
+#define __INC_BB_8188E_HW_IMG_H
+
+/* static bool CheckCondition(const u32 Condition, const u32 Hex); */
+
+/******************************************************************************
+* AGC_TAB_1T.TXT
+******************************************************************************/
+
+enum HAL_STATUS ODM_ReadAndConfig_AGC_TAB_1T_8188E(struct odm_dm_struct *odm);
+
+/******************************************************************************
+* PHY_REG_1T.TXT
+******************************************************************************/
+
+enum HAL_STATUS ODM_ReadAndConfig_PHY_REG_1T_8188E(struct odm_dm_struct *odm);
+
+/******************************************************************************
+* PHY_REG_PG.TXT
+******************************************************************************/
+
+void ODM_ReadAndConfig_PHY_REG_PG_8188E(struct odm_dm_struct *dm_odm);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/HalHWImg8188E_FW.h b/drivers/staging/rtl8188eu/include/HalHWImg8188E_FW.h
new file mode 100644
index 00000000000..1bf9bc70a69
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalHWImg8188E_FW.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+*
+*
+******************************************************************************/
+
+#ifndef __INC_FW_8188E_HW_IMG_H
+#define __INC_FW_8188E_HW_IMG_H
+
+
+/******************************************************************************
+* FW_AP.TXT
+******************************************************************************/
+/******************************************************************************
+* FW_WoWLAN.TXT
+******************************************************************************/
+#define ArrayLength_8188E_FW_WoWLAN 15764
+extern const u8 Array_8188E_FW_WoWLAN[ArrayLength_8188E_FW_WoWLAN];
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/HalHWImg8188E_MAC.h b/drivers/staging/rtl8188eu/include/HalHWImg8188E_MAC.h
new file mode 100644
index 00000000000..acf78b94fdd
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalHWImg8188E_MAC.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+*
+*
+******************************************************************************/
+
+#ifndef __INC_MAC_8188E_HW_IMG_H
+#define __INC_MAC_8188E_HW_IMG_H
+
+/******************************************************************************
+* MAC_REG.TXT
+******************************************************************************/
+
+enum HAL_STATUS ODM_ReadAndConfig_MAC_REG_8188E(struct odm_dm_struct *pDM_Odm);
+
+#endif /* end of HWIMG_SUPPORT */
diff --git a/drivers/staging/rtl8188eu/include/HalHWImg8188E_RF.h b/drivers/staging/rtl8188eu/include/HalHWImg8188E_RF.h
new file mode 100644
index 00000000000..8ecb40d26c7
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalHWImg8188E_RF.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+*
+*
+******************************************************************************/
+
+#ifndef __INC_RF_8188E_HW_IMG_H
+#define __INC_RF_8188E_HW_IMG_H
+
+/******************************************************************************
+ * RadioA_1T.TXT
+ ******************************************************************************/
+
+enum HAL_STATUS ODM_ReadAndConfig_RadioA_1T_8188E(struct odm_dm_struct *odm);
+
+#endif /* end of HWIMG_SUPPORT */
diff --git a/drivers/staging/rtl8188eu/include/HalPhyRf.h b/drivers/staging/rtl8188eu/include/HalPhyRf.h
new file mode 100644
index 00000000000..1ec497100da
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalPhyRf.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+ #ifndef __HAL_PHY_RF_H__
+ #define __HAL_PHY_RF_H__
+
+#define ODM_TARGET_CHNL_NUM_2G_5G 59
+
+void ODM_ResetIQKResult(struct odm_dm_struct *pDM_Odm);
+
+u8 ODM_GetRightChnlPlaceforIQK(u8 chnl);
+
+#endif /* #ifndef __HAL_PHY_RF_H__ */
diff --git a/drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h b/drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h
new file mode 100644
index 00000000000..fa583f24832
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __HAL_PHY_RF_8188E_H__
+#define __HAL_PHY_RF_8188E_H__
+
+/*--------------------------Define Parameters-------------------------------*/
+#define IQK_DELAY_TIME_88E 10 /* ms */
+#define index_mapping_NUM_88E 15
+#define AVG_THERMAL_NUM_88E 4
+
+
+void ODM_TxPwrTrackAdjust88E(struct odm_dm_struct *pDM_Odm,
+ u8 Type, /* 0 = OFDM, 1 = CCK */
+ u8 *pDirection,/* 1 = +(incr) 2 = -(decr) */
+ u32 *pOutWriteVal); /* Tx tracking CCK/OFDM BB
+ * swing index adjust */
+
+
+void odm_TXPowerTrackingCallback_ThermalMeter_8188E(struct adapter *Adapter);
+
+
+/* 1 7. IQK */
+
+void PHY_IQCalibrate_8188E(struct adapter *Adapter, bool ReCovery);
+
+/* LC calibrate */
+void PHY_LCCalibrate_8188E(struct adapter *pAdapter);
+
+/* AP calibrate */
+void PHY_APCalibrate_8188E(struct adapter *pAdapter, s8 delta);
+
+void PHY_DigitalPredistortion_8188E(struct adapter *pAdapter);
+
+void _PHY_SaveADDARegisters(struct adapter *pAdapter, u32 *ADDAReg,
+ u32 *ADDABackup, u32 RegisterNum);
+
+void _PHY_PathADDAOn(struct adapter *pAdapter, u32 *ADDAReg,
+ bool isPathAOn, bool is2T);
+
+void _PHY_MACSettingCalibration(struct adapter *pAdapter, u32 *MACReg,
+ u32 *MACBackup);
+
+void _PHY_PathAStandBy(struct adapter *pAdapter);
+
+#endif /* #ifndef __HAL_PHY_RF_8188E_H__ */
diff --git a/drivers/staging/rtl8188eu/include/HalPwrSeqCmd.h b/drivers/staging/rtl8188eu/include/HalPwrSeqCmd.h
new file mode 100644
index 00000000000..d945784ed5d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalPwrSeqCmd.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __HALPWRSEQCMD_H__
+#define __HALPWRSEQCMD_H__
+
+#include <drv_types.h>
+
+/*---------------------------------------------*/
+/* 3 The value of cmd: 4 bits */
+/*---------------------------------------------*/
+#define PWR_CMD_READ 0x00
+ /* offset: the read register offset */
+ /* msk: the mask of the read value */
+ /* value: N/A, left by 0 */
+ /* note: dirver shall implement this function by read & msk */
+
+#define PWR_CMD_WRITE 0x01
+ /* offset: the read register offset */
+ /* msk: the mask of the write bits */
+ /* value: write value */
+ /* note: driver shall implement this cmd by read & msk after write */
+
+#define PWR_CMD_POLLING 0x02
+ /* offset: the read register offset */
+ /* msk: the mask of the polled value */
+ /* value: the value to be polled, masked by the msd field. */
+ /* note: driver shall implement this cmd by */
+ /* do{ */
+ /* if ( (Read(offset) & msk) == (value & msk) ) */
+ /* break; */
+ /* } while (not timeout); */
+
+#define PWR_CMD_DELAY 0x03
+ /* offset: the value to delay */
+ /* msk: N/A */
+ /* value: the unit of delay, 0: us, 1: ms */
+
+#define PWR_CMD_END 0x04
+ /* offset: N/A */
+ /* msk: N/A */
+ /* value: N/A */
+
+/*---------------------------------------------*/
+/* 3 The value of base: 4 bits */
+/*---------------------------------------------*/
+ /* define the base address of each block */
+#define PWR_BASEADDR_MAC 0x00
+#define PWR_BASEADDR_USB 0x01
+#define PWR_BASEADDR_PCIE 0x02
+#define PWR_BASEADDR_SDIO 0x03
+
+/*---------------------------------------------*/
+/* 3 The value of interface_msk: 4 bits */
+/*---------------------------------------------*/
+#define PWR_INTF_SDIO_MSK BIT(0)
+#define PWR_INTF_USB_MSK BIT(1)
+#define PWR_INTF_PCI_MSK BIT(2)
+#define PWR_INTF_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+/*---------------------------------------------*/
+/* 3 The value of fab_msk: 4 bits */
+/*---------------------------------------------*/
+#define PWR_FAB_TSMC_MSK BIT(0)
+#define PWR_FAB_UMC_MSK BIT(1)
+#define PWR_FAB_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+/*---------------------------------------------*/
+/* 3 The value of cut_msk: 8 bits */
+/*---------------------------------------------*/
+#define PWR_CUT_TESTCHIP_MSK BIT(0)
+#define PWR_CUT_A_MSK BIT(1)
+#define PWR_CUT_B_MSK BIT(2)
+#define PWR_CUT_C_MSK BIT(3)
+#define PWR_CUT_D_MSK BIT(4)
+#define PWR_CUT_E_MSK BIT(5)
+#define PWR_CUT_F_MSK BIT(6)
+#define PWR_CUT_G_MSK BIT(7)
+#define PWR_CUT_ALL_MSK 0xFF
+
+
+enum pwrseq_cmd_delat_unit {
+ PWRSEQ_DELAY_US,
+ PWRSEQ_DELAY_MS,
+};
+
+struct wl_pwr_cfg {
+ u16 offset;
+ u8 cut_msk;
+ u8 fab_msk:4;
+ u8 interface_msk:4;
+ u8 base:4;
+ u8 cmd:4;
+ u8 msk;
+ u8 value;
+};
+
+#define GET_PWR_CFG_OFFSET(__PWR_CMD) __PWR_CMD.offset
+#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) __PWR_CMD.cut_msk
+#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) __PWR_CMD.fab_msk
+#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) __PWR_CMD.interface_msk
+#define GET_PWR_CFG_BASE(__PWR_CMD) __PWR_CMD.base
+#define GET_PWR_CFG_CMD(__PWR_CMD) __PWR_CMD.cmd
+#define GET_PWR_CFG_MASK(__PWR_CMD) __PWR_CMD.msk
+#define GET_PWR_CFG_VALUE(__PWR_CMD) __PWR_CMD.value
+
+
+/* Prototype of protected function. */
+u8 HalPwrSeqCmdParsing(struct adapter *padapter, u8 CutVersion, u8 FabVersion,
+ u8 InterfaceType, struct wl_pwr_cfg PwrCfgCmd[]);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/HalVerDef.h b/drivers/staging/rtl8188eu/include/HalVerDef.h
new file mode 100644
index 00000000000..97047cf0678
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalVerDef.h
@@ -0,0 +1,167 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __HAL_VERSION_DEF_H__
+#define __HAL_VERSION_DEF_H__
+
+enum HAL_IC_TYPE {
+ CHIP_8192S = 0,
+ CHIP_8188C = 1,
+ CHIP_8192C = 2,
+ CHIP_8192D = 3,
+ CHIP_8723A = 4,
+ CHIP_8188E = 5,
+ CHIP_8881A = 6,
+ CHIP_8812A = 7,
+ CHIP_8821A = 8,
+ CHIP_8723B = 9,
+ CHIP_8192E = 10,
+};
+
+enum HAL_CHIP_TYPE {
+ TEST_CHIP = 0,
+ NORMAL_CHIP = 1,
+ FPGA = 2,
+};
+
+enum HAL_CUT_VERSION {
+ A_CUT_VERSION = 0,
+ B_CUT_VERSION = 1,
+ C_CUT_VERSION = 2,
+ D_CUT_VERSION = 3,
+ E_CUT_VERSION = 4,
+ F_CUT_VERSION = 5,
+ G_CUT_VERSION = 6,
+};
+
+enum HAL_VENDOR {
+ CHIP_VENDOR_TSMC = 0,
+ CHIP_VENDOR_UMC = 1,
+};
+
+enum HAL_RF_TYPE {
+ RF_TYPE_1T1R = 0,
+ RF_TYPE_1T2R = 1,
+ RF_TYPE_2T2R = 2,
+ RF_TYPE_2T3R = 3,
+ RF_TYPE_2T4R = 4,
+ RF_TYPE_3T3R = 5,
+ RF_TYPE_3T4R = 6,
+ RF_TYPE_4T4R = 7,
+};
+
+struct HAL_VERSION {
+ enum HAL_IC_TYPE ICType;
+ enum HAL_CHIP_TYPE ChipType;
+ enum HAL_CUT_VERSION CUTVersion;
+ enum HAL_VENDOR VendorType;
+ enum HAL_RF_TYPE RFType;
+ u8 ROMVer;
+};
+
+/* Get element */
+#define GET_CVID_IC_TYPE(version) (((version).ICType))
+#define GET_CVID_CHIP_TYPE(version) (((version).ChipType))
+#define GET_CVID_RF_TYPE(version) (((version).RFType))
+#define GET_CVID_MANUFACTUER(version) (((version).VendorType))
+#define GET_CVID_CUT_VERSION(version) (((version).CUTVersion))
+#define GET_CVID_ROM_VERSION(version) (((version).ROMVer) & ROM_VERSION_MASK)
+
+/* Common Macro. -- */
+/* HAL_VERSION VersionID */
+
+/* HAL_IC_TYPE_E */
+#define IS_81XXC(version) \
+ (((GET_CVID_IC_TYPE(version) == CHIP_8192C) || \
+ (GET_CVID_IC_TYPE(version) == CHIP_8188C)) ? true : false)
+#define IS_8723_SERIES(version) \
+ ((GET_CVID_IC_TYPE(version) == CHIP_8723A) ? true : false)
+#define IS_92D(version) \
+ ((GET_CVID_IC_TYPE(version) == CHIP_8192D) ? true : false)
+#define IS_8188E(version) \
+ ((GET_CVID_IC_TYPE(version) == CHIP_8188E) ? true : false)
+
+/* HAL_CHIP_TYPE_E */
+#define IS_TEST_CHIP(version) \
+ ((GET_CVID_CHIP_TYPE(version) == TEST_CHIP) ? true : false)
+#define IS_NORMAL_CHIP(version) \
+ ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? true : false)
+
+/* HAL_CUT_VERSION_E */
+#define IS_A_CUT(version) \
+ ((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? true : false)
+#define IS_B_CUT(version) \
+ ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? true : false)
+#define IS_C_CUT(version) \
+ ((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? true : false)
+#define IS_D_CUT(version) \
+ ((GET_CVID_CUT_VERSION(version) == D_CUT_VERSION) ? true : false)
+#define IS_E_CUT(version) \
+ ((GET_CVID_CUT_VERSION(version) == E_CUT_VERSION) ? true : false)
+
+
+/* HAL_VENDOR_E */
+#define IS_CHIP_VENDOR_TSMC(version) \
+ ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC) ? true : false)
+#define IS_CHIP_VENDOR_UMC(version) \
+ ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC) ? true : false)
+
+/* HAL_RF_TYPE_E */
+#define IS_1T1R(version) \
+ ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R) ? true : false)
+#define IS_1T2R(version) \
+ ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? true : false)
+#define IS_2T2R(version) \
+ ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? true : false)
+
+/* Chip version Macro. -- */
+#define IS_81XXC_TEST_CHIP(version) \
+ ((IS_81XXC(version) && (!IS_NORMAL_CHIP(version))) ? true : false)
+
+#define IS_92C_SERIAL(version) \
+ ((IS_81XXC(version) && IS_2T2R(version)) ? true : false)
+#define IS_81xxC_VENDOR_UMC_A_CUT(version) \
+ (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? \
+ (IS_A_CUT(version) ? true : false) : false) : false)
+#define IS_81xxC_VENDOR_UMC_B_CUT(version) \
+ (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? \
+ (IS_B_CUT(version) ? true : false) : false) : false)
+#define IS_81xxC_VENDOR_UMC_C_CUT(version) \
+ (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? \
+ (IS_C_CUT(version) ? true : false) : false) : false)
+
+#define IS_NORMAL_CHIP92D(version) \
+ ((IS_92D(version)) ? \
+ ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? true : false) : false)
+
+#define IS_92D_SINGLEPHY(version) \
+ ((IS_92D(version)) ? (IS_2T2R(version) ? true : false) : false)
+#define IS_92D_C_CUT(version) \
+ ((IS_92D(version)) ? (IS_C_CUT(version) ? true : false) : false)
+#define IS_92D_D_CUT(version) \
+ ((IS_92D(version)) ? (IS_D_CUT(version) ? true : false) : false)
+#define IS_92D_E_CUT(version) \
+ ((IS_92D(version)) ? (IS_E_CUT(version) ? true : false) : false)
+
+#define IS_8723A_A_CUT(version) \
+ ((IS_8723_SERIES(version)) ? (IS_A_CUT(version) ? true : false) : false)
+#define IS_8723A_B_CUT(version) \
+ ((IS_8723_SERIES(version)) ? (IS_B_CUT(version) ? true : false) : false)
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/basic_types.h b/drivers/staging/rtl8188eu/include/basic_types.h
new file mode 100644
index 00000000000..8a7ca992674
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/basic_types.h
@@ -0,0 +1,184 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __BASIC_TYPES_H__
+#define __BASIC_TYPES_H__
+
+#define SUCCESS 0
+#define FAIL (-1)
+
+#include <linux/types.h>
+#define NDIS_OID uint
+
+typedef void (*proc_t)(void *);
+
+#define FIELD_OFFSET(s, field) ((ssize_t)&((s *)(0))->field)
+
+#define MEM_ALIGNMENT_OFFSET (sizeof(size_t))
+#define MEM_ALIGNMENT_PADDING (sizeof(size_t) - 1)
+
+/* port from fw */
+/* TODO: Macros Below are Sync from SD7-Driver. It is necessary
+ * to check correctness */
+
+/*
+ * Call endian free function when
+ * 1. Read/write packet content.
+ * 2. Before write integer to IO.
+ * 3. After read integer from IO.
+*/
+
+/* Convert little data endian to host ordering */
+#define EF1BYTE(_val) \
+ ((u8)(_val))
+#define EF2BYTE(_val) \
+ (le16_to_cpu(_val))
+#define EF4BYTE(_val) \
+ (le32_to_cpu(_val))
+
+/* Read data from memory */
+#define READEF1BYTE(_ptr) \
+ EF1BYTE(*((u8 *)(_ptr)))
+/* Read le16 data from memory and convert to host ordering */
+#define READEF2BYTE(_ptr) \
+ EF2BYTE(*(_ptr))
+#define READEF4BYTE(_ptr) \
+ EF4BYTE(*(_ptr))
+
+/* Write data to memory */
+#define WRITEEF1BYTE(_ptr, _val) \
+ do { \
+ (*((u8 *)(_ptr))) = EF1BYTE(_val) \
+ } while (0)
+/* Write le data to memory in host ordering */
+#define WRITEEF2BYTE(_ptr, _val) \
+ do { \
+ (*((u16 *)(_ptr))) = EF2BYTE(_val) \
+ } while (0)
+
+#define WRITEEF4BYTE(_ptr, _val) \
+ do { \
+ (*((u32 *)(_ptr))) = EF2BYTE(_val) \
+ } while (0)
+
+/* Create a bit mask
+ * Examples:
+ * BIT_LEN_MASK_32(0) => 0x00000000
+ * BIT_LEN_MASK_32(1) => 0x00000001
+ * BIT_LEN_MASK_32(2) => 0x00000003
+ * BIT_LEN_MASK_32(32) => 0xFFFFFFFF
+ */
+#define BIT_LEN_MASK_32(__bitlen) \
+ (0xFFFFFFFF >> (32 - (__bitlen)))
+#define BIT_LEN_MASK_16(__bitlen) \
+ (0xFFFF >> (16 - (__bitlen)))
+#define BIT_LEN_MASK_8(__bitlen) \
+ (0xFF >> (8 - (__bitlen)))
+
+/* Create an offset bit mask
+ * Examples:
+ * BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003
+ * BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000
+ */
+#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) \
+ (BIT_LEN_MASK_32(__bitlen) << (__bitoffset))
+#define BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) \
+ (BIT_LEN_MASK_16(__bitlen) << (__bitoffset))
+#define BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) \
+ (BIT_LEN_MASK_8(__bitlen) << (__bitoffset))
+
+/*Description:
+ * Return 4-byte value in host byte ordering from
+ * 4-byte pointer in little-endian system.
+ */
+#define LE_P4BYTE_TO_HOST_4BYTE(__pstart) \
+ (EF4BYTE(*((__le32 *)(__pstart))))
+#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \
+ (EF2BYTE(*((__le16 *)(__pstart))))
+#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \
+ (EF1BYTE(*((u8 *)(__pstart))))
+
+/*Description:
+Translate subfield (continuous bits in little-endian) of 4-byte
+value to host byte ordering.*/
+#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \
+ BIT_LEN_MASK_32(__bitlen) \
+ )
+#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \
+ BIT_LEN_MASK_16(__bitlen) \
+ )
+#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \
+ BIT_LEN_MASK_8(__bitlen) \
+ )
+
+/* Description:
+ * Mask subfield (continuous bits in little-endian) of 4-byte value
+ * and return the result in 4-byte value in host byte ordering.
+ */
+#define LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ LE_P4BYTE_TO_HOST_4BYTE(__pstart) & \
+ (~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)) \
+ )
+#define LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ LE_P2BYTE_TO_HOST_2BYTE(__pstart) & \
+ (~BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen)) \
+ )
+#define LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ LE_P1BYTE_TO_HOST_1BYTE(__pstart) & \
+ (~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen)) \
+ )
+
+/* Description:
+ * Set subfield of little-endian 4-byte value to specified value.
+ */
+#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \
+ *((u32 *)(__pstart)) = \
+ ( \
+ LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \
+ ((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \
+ )
+
+#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \
+ *((u16 *)(__pstart)) = \
+ ( \
+ LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \
+ ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \
+ );
+
+#define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \
+ *((u8 *)(__pstart)) = EF1BYTE \
+ ( \
+ LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) | \
+ ((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \
+ )
+
+/* Get the N-bytes aligment offset from the current length */
+#define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \
+ (__value) : (((__value + __aligment - 1) / __aligment) * __aligment))
+
+#endif /* __BASIC_TYPES_H__ */
diff --git a/drivers/staging/rtl8188eu/include/cmd_osdep.h b/drivers/staging/rtl8188eu/include/cmd_osdep.h
new file mode 100644
index 00000000000..5a8465e147b
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/cmd_osdep.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __CMD_OSDEP_H_
+#define __CMD_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+extern int _rtw_init_cmd_priv(struct cmd_priv *pcmdpriv);
+extern int _rtw_init_evt_priv(struct evt_priv *pevtpriv);
+extern void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv);
+extern int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj);
+extern struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/drv_types.h b/drivers/staging/rtl8188eu/include/drv_types.h
new file mode 100644
index 00000000000..ad073c8af27
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/drv_types.h
@@ -0,0 +1,334 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+/*-----------------------------------------------------------------------------
+
+ For type defines and data structure defines
+
+------------------------------------------------------------------------------*/
+
+
+#ifndef __DRV_TYPES_H__
+#define __DRV_TYPES_H__
+
+#define DRV_NAME "r8188eu"
+
+#include <osdep_service.h>
+#include <wlan_bssdef.h>
+#include <drv_types_linux.h>
+#include <rtw_ht.h>
+#include <rtw_cmd.h>
+#include <rtw_xmit.h>
+#include <rtw_recv.h>
+#include <hal_intf.h>
+#include <hal_com.h>
+#include <rtw_qos.h>
+#include <rtw_security.h>
+#include <rtw_pwrctrl.h>
+#include <rtw_io.h>
+#include <rtw_eeprom.h>
+#include <sta_info.h>
+#include <rtw_mlme.h>
+#include <rtw_debug.h>
+#include <rtw_rf.h>
+#include <rtw_event.h>
+#include <rtw_led.h>
+#include <rtw_mlme_ext.h>
+#include <rtw_p2p.h>
+#include <rtw_ap.h>
+#include <rtw_mp.h>
+#include <rtw_br_ext.h>
+
+enum _NIC_VERSION {
+ RTL8711_NIC,
+ RTL8712_NIC,
+ RTL8713_NIC,
+ RTL8716_NIC
+};
+
+#define SPEC_DEV_ID_NONE BIT(0)
+#define SPEC_DEV_ID_DISABLE_HT BIT(1)
+#define SPEC_DEV_ID_ENABLE_PS BIT(2)
+#define SPEC_DEV_ID_RF_CONFIG_1T1R BIT(3)
+#define SPEC_DEV_ID_RF_CONFIG_2T2R BIT(4)
+#define SPEC_DEV_ID_ASSIGN_IFNAME BIT(5)
+
+struct specific_device_id {
+ u32 flags;
+ u16 idVendor;
+ u16 idProduct;
+};
+
+struct registry_priv {
+ u8 chip_version;
+ u8 rfintfs;
+ u8 lbkmode;
+ u8 hci;
+ struct ndis_802_11_ssid ssid;
+ u8 network_mode; /* infra, ad-hoc, auto */
+ u8 channel;/* ad-hoc support requirement */
+ u8 wireless_mode;/* A, B, G, auto */
+ u8 scan_mode;/* active, passive */
+ u8 radio_enable;
+ u8 preamble;/* long, short, auto */
+ u8 vrtl_carrier_sense;/* Enable, Disable, Auto */
+ u8 vcs_type;/* RTS/CTS, CTS-to-self */
+ u16 rts_thresh;
+ u16 frag_thresh;
+ u8 adhoc_tx_pwr;
+ u8 soft_ap;
+ u8 power_mgnt;
+ u8 ips_mode;
+ u8 smart_ps;
+ u8 long_retry_lmt;
+ u8 short_retry_lmt;
+ u16 busy_thresh;
+ u8 ack_policy;
+ u8 mp_mode;
+ u8 software_encrypt;
+ u8 software_decrypt;
+ u8 acm_method;
+ /* UAPSD */
+ u8 wmm_enable;
+ u8 uapsd_enable;
+ u8 uapsd_max_sp;
+ u8 uapsd_acbk_en;
+ u8 uapsd_acbe_en;
+ u8 uapsd_acvi_en;
+ u8 uapsd_acvo_en;
+
+ struct wlan_bssid_ex dev_network;
+
+ u8 ht_enable;
+ u8 cbw40_enable;
+ u8 ampdu_enable;/* for tx */
+ u8 rx_stbc;
+ u8 ampdu_amsdu;/* A-MPDU Supports A-MSDU is permitted */
+ u8 lowrate_two_xmit;
+
+ u8 rf_config;
+ u8 low_power;
+
+ u8 wifi_spec;/* !turbo_mode */
+
+ u8 channel_plan;
+ bool bAcceptAddbaReq;
+
+ u8 antdiv_cfg;
+ u8 antdiv_type;
+
+ u8 usbss_enable;/* 0:disable,1:enable */
+ u8 hwpdn_mode;/* 0:disable,1:enable,2:decide by EFUSE config */
+ u8 hwpwrp_detect;/* 0:disable,1:enable */
+
+ u8 hw_wps_pbc;/* 0:disable,1:enable */
+
+ u8 max_roaming_times; /* the max number driver will try */
+
+ u8 fw_iol; /* enable iol without other concern */
+
+ u8 enable80211d;
+
+ u8 ifname[16];
+ u8 if2name[16];
+
+ u8 notch_filter;
+};
+
+/* For registry parameters */
+#define RGTRY_OFT(field) ((u32)FIELD_OFFSET(struct registry_priv, field))
+#define RGTRY_SZ(field) sizeof(((struct registry_priv *)0)->field)
+#define BSSID_OFT(field) ((u32)FIELD_OFFSET(struct wlan_bssid_ex, field))
+#define BSSID_SZ(field) sizeof(((struct wlan_bssid_ex *)0)->field)
+
+#define MAX_CONTINUAL_URB_ERR 4
+
+struct dvobj_priv {
+ struct adapter *if1;
+ struct adapter *if2;
+
+ /* For 92D, DMDP have 2 interface. */
+ u8 InterfaceNumber;
+ u8 NumInterfaces;
+
+ /* In /Out Pipe information */
+ int RtInPipe[2];
+ int RtOutPipe[3];
+ u8 Queue2Pipe[HW_QUEUE_ENTRY];/* for out pipe mapping */
+
+ u8 irq_alloc;
+
+/*-------- below is for USB INTERFACE --------*/
+
+ u8 nr_endpoint;
+ u8 ishighspeed;
+ u8 RtNumInPipes;
+ u8 RtNumOutPipes;
+ int ep_num[5]; /* endpoint number */
+ int RegUsbSS;
+ struct semaphore usb_suspend_sema;
+ struct mutex usb_vendor_req_mutex;
+
+ u8 *usb_alloc_vendor_req_buf;
+ u8 *usb_vendor_req_buf;
+
+ struct usb_interface *pusbintf;
+ struct usb_device *pusbdev;
+
+ ATOMIC_T continual_urb_error;
+};
+
+static inline struct device *dvobj_to_dev(struct dvobj_priv *dvobj)
+{
+ /* todo: get interface type from dvobj and the return
+ * the dev accordingly */
+ return &dvobj->pusbintf->dev;
+};
+
+enum _IFACE_TYPE {
+ IFACE_PORT0, /* mapping to port0 for C/D series chips */
+ IFACE_PORT1, /* mapping to port1 for C/D series chip */
+ MAX_IFACE_PORT,
+};
+
+enum _ADAPTER_TYPE {
+ PRIMARY_ADAPTER,
+ SECONDARY_ADAPTER,
+ MAX_ADAPTER,
+};
+
+enum driver_state {
+ DRIVER_NORMAL = 0,
+ DRIVER_DISAPPEAR = 1,
+ DRIVER_REPLACE_DONGLE = 2,
+};
+
+struct adapter {
+ int DriverState;/* for disable driver using module, use dongle toi
+ * replace module. */
+ int pid[3];/* process id from UI, 0:wps, 1:hostapd, 2:dhcpcd */
+ int bDongle;/* build-in module or external dongle */
+ u16 chip_type;
+ u16 HardwareType;
+ u16 interface_type;/* USB,SDIO,SPI,PCI */
+
+ struct dvobj_priv *dvobj;
+ struct mlme_priv mlmepriv;
+ struct mlme_ext_priv mlmeextpriv;
+ struct cmd_priv cmdpriv;
+ struct evt_priv evtpriv;
+ struct io_priv iopriv;
+ struct xmit_priv xmitpriv;
+ struct recv_priv recvpriv;
+ struct sta_priv stapriv;
+ struct security_priv securitypriv;
+ struct registry_priv registrypriv;
+ struct pwrctrl_priv pwrctrlpriv;
+ struct eeprom_priv eeprompriv;
+ struct led_priv ledpriv;
+ struct mp_priv mppriv;
+
+#ifdef CONFIG_88EU_AP_MODE
+ struct hostapd_priv *phostapdpriv;
+#endif
+
+ struct wifidirect_info wdinfo;
+
+ void *HalData;
+ u32 hal_data_sz;
+ struct hal_ops HalFunc;
+
+ s32 bDriverStopped;
+ s32 bSurpriseRemoved;
+ s32 bCardDisableWOHSM;
+
+ u32 IsrContent;
+ u32 ImrContent;
+
+ u8 EepromAddressSize;
+ u8 hw_init_completed;
+ u8 bDriverIsGoingToUnload;
+ u8 init_adpt_in_progress;
+ u8 bHaltInProgress;
+
+ void *cmdThread;
+ void *evtThread;
+ void *xmitThread;
+ void *recvThread;
+ void (*intf_start)(struct adapter *adapter);
+ void (*intf_stop)(struct adapter *adapter);
+ struct net_device *pnetdev;
+
+ /* used by rtw_rereg_nd_name related function */
+ struct rereg_nd_name_data {
+ struct net_device *old_pnetdev;
+ char old_ifname[IFNAMSIZ];
+ u8 old_ips_mode;
+ u8 old_bRegUseLed;
+ } rereg_nd_name_priv;
+
+ int bup;
+ struct net_device_stats stats;
+ struct iw_statistics iwstats;
+ struct proc_dir_entry *dir_dev;/* for proc directory */
+
+ int net_closed;
+ u8 bFWReady;
+ u8 bBTFWReady;
+ u8 bReadPortCancel;
+ u8 bWritePortCancel;
+ u8 bRxRSSIDisplay;
+ /* The driver will show up the desired channel number
+ * when this flag is 1. */
+ u8 bNotifyChannelChange;
+#ifdef CONFIG_88EU_P2P
+ /* The driver will show the current P2P status when the
+ * upper application reads it. */
+ u8 bShowGetP2PState;
+#endif
+ struct adapter *pbuddy_adapter;
+
+ struct mutex *hw_init_mutex;
+
+ spinlock_t br_ext_lock;
+ struct nat25_network_db_entry *nethash[NAT25_HASH_SIZE];
+ int pppoe_connection_in_progress;
+ unsigned char pppoe_addr[MACADDRLEN];
+ unsigned char scdb_mac[MACADDRLEN];
+ unsigned char scdb_ip[4];
+ struct nat25_network_db_entry *scdb_entry;
+ unsigned char br_mac[MACADDRLEN];
+ unsigned char br_ip[4];
+ struct br_ext_info ethBrExtInfo;
+
+ u8 fix_rate;
+
+ unsigned char in_cta_test;
+};
+
+#define adapter_to_dvobj(adapter) (adapter->dvobj)
+
+int rtw_handle_dualmac(struct adapter *adapter, bool init);
+
+static inline u8 *myid(struct eeprom_priv *peepriv)
+{
+ return peepriv->mac_addr;
+}
+
+#endif /* __DRV_TYPES_H__ */
diff --git a/drivers/staging/rtl8188eu/include/drv_types_linux.h b/drivers/staging/rtl8188eu/include/drv_types_linux.h
new file mode 100644
index 00000000000..812b7440d4b
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/drv_types_linux.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __DRV_TYPES_LINUX_H__
+#define __DRV_TYPES_LINUX_H__
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/ethernet.h b/drivers/staging/rtl8188eu/include/ethernet.h
new file mode 100644
index 00000000000..a59f9120cd7
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/ethernet.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+/*! \file */
+#ifndef __INC_ETHERNET_H
+#define __INC_ETHERNET_H
+
+#define ETHERNET_ADDRESS_LENGTH 6 /* Ethernet Address Length */
+#define ETHERNET_HEADER_SIZE 14 /* Ethernet Header Length */
+#define LLC_HEADER_SIZE 6 /* LLC Header Length */
+#define TYPE_LENGTH_FIELD_SIZE 2 /* Type/Length Size */
+#define MINIMUM_ETHERNET_PACKET_SIZE 60 /* Min Ethernet Packet Size */
+#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 /* Max Ethernet Packet Size */
+
+/* Is Multicast Address? */
+#define RT_ETH_IS_MULTICAST(_addr) ((((u8 *)(_addr))[0]&0x01) != 0)
+#define RT_ETH_IS_BROADCAST(_addr) ( \
+ ((u8 *)(_addr))[0] == 0xff && \
+ ((u8 *)(_addr))[1] == 0xff && \
+ ((u8 *)(_addr))[2] == 0xff && \
+ ((u8 *)(_addr))[3] == 0xff && \
+ ((u8 *)(_addr))[4] == 0xff && \
+ ((u8 *)(_addr))[5] == 0xff) /* Is Broadcast Address? */
+
+
+#endif /* #ifndef __INC_ETHERNET_H */
diff --git a/drivers/staging/rtl8188eu/include/h2clbk.h b/drivers/staging/rtl8188eu/include/h2clbk.h
new file mode 100644
index 00000000000..e595030ac8a
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/h2clbk.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+
+#define _H2CLBK_H_
+
+
+#include <rtl8711_spec.h>
+#include <TypeDef.h>
+
+
+void _lbk_cmd(struct adapter *adapter);
+
+void _lbk_rsp(struct adapter *adapter);
+
+void _lbk_evt(IN struct adapter *adapter);
+
+void h2c_event_callback(unsigned char *dev, unsigned char *pbuf);
diff --git a/drivers/staging/rtl8188eu/include/hal_com.h b/drivers/staging/rtl8188eu/include/hal_com.h
new file mode 100644
index 00000000000..81c27090dd5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/hal_com.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __HAL_COMMON_H__
+#define __HAL_COMMON_H__
+
+/* */
+/* Rate Definition */
+/* */
+/* CCK */
+#define RATR_1M 0x00000001
+#define RATR_2M 0x00000002
+#define RATR_55M 0x00000004
+#define RATR_11M 0x00000008
+/* OFDM */
+#define RATR_6M 0x00000010
+#define RATR_9M 0x00000020
+#define RATR_12M 0x00000040
+#define RATR_18M 0x00000080
+#define RATR_24M 0x00000100
+#define RATR_36M 0x00000200
+#define RATR_48M 0x00000400
+#define RATR_54M 0x00000800
+/* MCS 1 Spatial Stream */
+#define RATR_MCS0 0x00001000
+#define RATR_MCS1 0x00002000
+#define RATR_MCS2 0x00004000
+#define RATR_MCS3 0x00008000
+#define RATR_MCS4 0x00010000
+#define RATR_MCS5 0x00020000
+#define RATR_MCS6 0x00040000
+#define RATR_MCS7 0x00080000
+/* MCS 2 Spatial Stream */
+#define RATR_MCS8 0x00100000
+#define RATR_MCS9 0x00200000
+#define RATR_MCS10 0x00400000
+#define RATR_MCS11 0x00800000
+#define RATR_MCS12 0x01000000
+#define RATR_MCS13 0x02000000
+#define RATR_MCS14 0x04000000
+#define RATR_MCS15 0x08000000
+
+/* CCK */
+#define RATE_1M BIT(0)
+#define RATE_2M BIT(1)
+#define RATE_5_5M BIT(2)
+#define RATE_11M BIT(3)
+/* OFDM */
+#define RATE_6M BIT(4)
+#define RATE_9M BIT(5)
+#define RATE_12M BIT(6)
+#define RATE_18M BIT(7)
+#define RATE_24M BIT(8)
+#define RATE_36M BIT(9)
+#define RATE_48M BIT(10)
+#define RATE_54M BIT(11)
+/* MCS 1 Spatial Stream */
+#define RATE_MCS0 BIT(12)
+#define RATE_MCS1 BIT(13)
+#define RATE_MCS2 BIT(14)
+#define RATE_MCS3 BIT(15)
+#define RATE_MCS4 BIT(16)
+#define RATE_MCS5 BIT(17)
+#define RATE_MCS6 BIT(18)
+#define RATE_MCS7 BIT(19)
+/* MCS 2 Spatial Stream */
+#define RATE_MCS8 BIT(20)
+#define RATE_MCS9 BIT(21)
+#define RATE_MCS10 BIT(22)
+#define RATE_MCS11 BIT(23)
+#define RATE_MCS12 BIT(24)
+#define RATE_MCS13 BIT(25)
+#define RATE_MCS14 BIT(26)
+#define RATE_MCS15 BIT(27)
+
+/* ALL CCK Rate */
+#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M | \
+ RATR_24M | RATR_36M | RATR_48M | RATR_54M)
+#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \
+ RATR_MCS3 | RATR_MCS4 | RATR_MCS5|RATR_MCS6 | \
+ RATR_MCS7)
+#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \
+ RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \
+ RATR_MCS14 | RATR_MCS15)
+
+/*------------------------------ Tx Desc definition Macro --------------------*/
+/* pragma mark -- Tx Desc related definition. -- */
+/* Rate */
+/* CCK Rates, TxHT = 0 */
+#define DESC_RATE1M 0x00
+#define DESC_RATE2M 0x01
+#define DESC_RATE5_5M 0x02
+#define DESC_RATE11M 0x03
+
+/* OFDM Rates, TxHT = 0 */
+#define DESC_RATE6M 0x04
+#define DESC_RATE9M 0x05
+#define DESC_RATE12M 0x06
+#define DESC_RATE18M 0x07
+#define DESC_RATE24M 0x08
+#define DESC_RATE36M 0x09
+#define DESC_RATE48M 0x0a
+#define DESC_RATE54M 0x0b
+
+/* MCS Rates, TxHT = 1 */
+#define DESC_RATEMCS0 0x0c
+#define DESC_RATEMCS1 0x0d
+#define DESC_RATEMCS2 0x0e
+#define DESC_RATEMCS3 0x0f
+#define DESC_RATEMCS4 0x10
+#define DESC_RATEMCS5 0x11
+#define DESC_RATEMCS6 0x12
+#define DESC_RATEMCS7 0x13
+#define DESC_RATEMCS8 0x14
+#define DESC_RATEMCS9 0x15
+#define DESC_RATEMCS10 0x16
+#define DESC_RATEMCS11 0x17
+#define DESC_RATEMCS12 0x18
+#define DESC_RATEMCS13 0x19
+#define DESC_RATEMCS14 0x1a
+#define DESC_RATEMCS15 0x1b
+#define DESC_RATEMCS15_SG 0x1c
+#define DESC_RATEMCS32 0x20
+
+/* 1 Byte long (in unit of TU) */
+#define REG_P2P_CTWIN 0x0572
+#define REG_NOA_DESC_SEL 0x05CF
+#define REG_NOA_DESC_DURATION 0x05E0
+#define REG_NOA_DESC_INTERVAL 0x05E4
+#define REG_NOA_DESC_START 0x05E8
+#define REG_NOA_DESC_COUNT 0x05EC
+
+#include "HalVerDef.h"
+void dump_chip_info(struct HAL_VERSION ChipVersion);
+
+
+/* return the final channel plan decision */
+u8 hal_com_get_channel_plan(struct adapter *padapter,
+ u8 hw_channel_plan,
+ u8 sw_channel_plan,
+ u8 def_channel_plan,
+ bool AutoLoadFail
+);
+
+u8 MRateToHwRate(u8 rate);
+
+void HalSetBrateCfg(struct adapter *Adapter, u8 *mBratesOS, u16 *pBrateCfg);
+
+bool Hal_MappingOutPipe(struct adapter *pAdapter, u8 NumOutPipe);
+
+void hal_init_macaddr(struct adapter *adapter);
+
+void c2h_evt_clear(struct adapter *adapter);
+s32 c2h_evt_read(struct adapter *adapter, u8 *buf);
+
+#endif /* __HAL_COMMON_H__ */
diff --git a/drivers/staging/rtl8188eu/include/hal_intf.h b/drivers/staging/rtl8188eu/include/hal_intf.h
new file mode 100644
index 00000000000..439c3c941ba
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/hal_intf.h
@@ -0,0 +1,426 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __HAL_INTF_H__
+#define __HAL_INTF_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <Hal8188EPhyCfg.h>
+
+enum RTL871X_HCI_TYPE {
+ RTW_PCIE = BIT0,
+ RTW_USB = BIT1,
+ RTW_SDIO = BIT2,
+ RTW_GSPI = BIT3,
+};
+
+enum _CHIP_TYPE {
+ NULL_CHIP_TYPE,
+ RTL8712_8188S_8191S_8192S,
+ RTL8188C_8192C,
+ RTL8192D,
+ RTL8723A,
+ RTL8188E,
+ MAX_CHIP_TYPE
+};
+
+enum hw_variables {
+ HW_VAR_MEDIA_STATUS,
+ HW_VAR_MEDIA_STATUS1,
+ HW_VAR_SET_OPMODE,
+ HW_VAR_MAC_ADDR,
+ HW_VAR_BSSID,
+ HW_VAR_INIT_RTS_RATE,
+ HW_VAR_BASIC_RATE,
+ HW_VAR_TXPAUSE,
+ HW_VAR_BCN_FUNC,
+ HW_VAR_CORRECT_TSF,
+ HW_VAR_CHECK_BSSID,
+ HW_VAR_MLME_DISCONNECT,
+ HW_VAR_MLME_SITESURVEY,
+ HW_VAR_MLME_JOIN,
+ HW_VAR_BEACON_INTERVAL,
+ HW_VAR_SLOT_TIME,
+ HW_VAR_RESP_SIFS,
+ HW_VAR_ACK_PREAMBLE,
+ HW_VAR_SEC_CFG,
+ HW_VAR_BCN_VALID,
+ HW_VAR_RF_TYPE,
+ HW_VAR_DM_FLAG,
+ HW_VAR_DM_FUNC_OP,
+ HW_VAR_DM_FUNC_SET,
+ HW_VAR_DM_FUNC_CLR,
+ HW_VAR_CAM_EMPTY_ENTRY,
+ HW_VAR_CAM_INVALID_ALL,
+ HW_VAR_CAM_WRITE,
+ HW_VAR_CAM_READ,
+ HW_VAR_AC_PARAM_VO,
+ HW_VAR_AC_PARAM_VI,
+ HW_VAR_AC_PARAM_BE,
+ HW_VAR_AC_PARAM_BK,
+ HW_VAR_ACM_CTRL,
+ HW_VAR_AMPDU_MIN_SPACE,
+ HW_VAR_AMPDU_FACTOR,
+ HW_VAR_RXDMA_AGG_PG_TH,
+ HW_VAR_SET_RPWM,
+ HW_VAR_H2C_FW_PWRMODE,
+ HW_VAR_H2C_FW_JOINBSSRPT,
+ HW_VAR_FWLPS_RF_ON,
+ HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+ HW_VAR_TDLS_WRCR,
+ HW_VAR_TDLS_INIT_CH_SEN,
+ HW_VAR_TDLS_RS_RCR,
+ HW_VAR_TDLS_DONE_CH_SEN,
+ HW_VAR_INITIAL_GAIN,
+ HW_VAR_TRIGGER_GPIO_0,
+ HW_VAR_BT_SET_COEXIST,
+ HW_VAR_BT_ISSUE_DELBA,
+ HW_VAR_CURRENT_ANTENNA,
+ HW_VAR_ANTENNA_DIVERSITY_LINK,
+ HW_VAR_ANTENNA_DIVERSITY_SELECT,
+ HW_VAR_SWITCH_EPHY_WoWLAN,
+ HW_VAR_EFUSE_USAGE,
+ HW_VAR_EFUSE_BYTES,
+ HW_VAR_EFUSE_BT_USAGE,
+ HW_VAR_EFUSE_BT_BYTES,
+ HW_VAR_FIFO_CLEARN_UP,
+ HW_VAR_CHECK_TXBUF,
+ HW_VAR_APFM_ON_MAC, /* Auto FSM to Turn On, include clock, isolation,
+ * power control for MAC only */
+ /* The valid upper nav range for the HW updating, if the true value is
+ * larger than the upper range, the HW won't update it. */
+ /* Unit in microsecond. 0 means disable this function. */
+ HW_VAR_NAV_UPPER,
+ HW_VAR_RPT_TIMER_SETTING,
+ HW_VAR_TX_RPT_MAX_MACID,
+ HW_VAR_H2C_MEDIA_STATUS_RPT,
+ HW_VAR_CHK_HI_QUEUE_EMPTY,
+};
+
+enum hal_def_variable {
+ HAL_DEF_UNDERCORATEDSMOOTHEDPWDB,
+ HAL_DEF_IS_SUPPORT_ANT_DIV,
+ HAL_DEF_CURRENT_ANTENNA,
+ HAL_DEF_DRVINFO_SZ,
+ HAL_DEF_MAX_RECVBUF_SZ,
+ HAL_DEF_RX_PACKET_OFFSET,
+ HAL_DEF_DBG_DUMP_RXPKT,/* for dbg */
+ HAL_DEF_DBG_DM_FUNC,/* for dbg */
+ HAL_DEF_RA_DECISION_RATE,
+ HAL_DEF_RA_SGI,
+ HAL_DEF_PT_PWR_STATUS,
+ HW_VAR_MAX_RX_AMPDU_FACTOR,
+ HW_DEF_RA_INFO_DUMP,
+ HAL_DEF_DBG_DUMP_TXPKT,
+ HW_DEF_FA_CNT_DUMP,
+ HW_DEF_ODM_DBG_FLAG,
+};
+
+enum hal_odm_variable {
+ HAL_ODM_STA_INFO,
+ HAL_ODM_P2P_STATE,
+ HAL_ODM_WIFI_DISPLAY_STATE,
+};
+
+enum hal_intf_ps_func {
+ HAL_USB_SELECT_SUSPEND,
+ HAL_MAX_ID,
+};
+
+typedef s32 (*c2h_id_filter)(u8 id);
+
+struct hal_ops {
+ u32 (*hal_power_on)(struct adapter *padapter);
+ u32 (*hal_init)(struct adapter *padapter);
+ u32 (*hal_deinit)(struct adapter *padapter);
+
+ void (*free_hal_data)(struct adapter *padapter);
+
+ u32 (*inirp_init)(struct adapter *padapter);
+ u32 (*inirp_deinit)(struct adapter *padapter);
+
+ s32 (*init_xmit_priv)(struct adapter *padapter);
+ void (*free_xmit_priv)(struct adapter *padapter);
+
+ s32 (*init_recv_priv)(struct adapter *padapter);
+ void (*free_recv_priv)(struct adapter *padapter);
+
+ void (*InitSwLeds)(struct adapter *padapter);
+ void (*DeInitSwLeds)(struct adapter *padapter);
+
+ void (*dm_init)(struct adapter *padapter);
+ void (*dm_deinit)(struct adapter *padapter);
+ void (*read_chip_version)(struct adapter *padapter);
+
+ void (*init_default_value)(struct adapter *padapter);
+
+ void (*intf_chip_configure)(struct adapter *padapter);
+
+ void (*read_adapter_info)(struct adapter *padapter);
+
+ void (*enable_interrupt)(struct adapter *padapter);
+ void (*disable_interrupt)(struct adapter *padapter);
+ s32 (*interrupt_handler)(struct adapter *padapter);
+
+ void (*set_bwmode_handler)(struct adapter *padapter,
+ enum ht_channel_width Bandwidth,
+ u8 Offset);
+ void (*set_channel_handler)(struct adapter *padapter, u8 channel);
+
+ void (*hal_dm_watchdog)(struct adapter *padapter);
+
+ void (*SetHwRegHandler)(struct adapter *padapter, u8 variable,
+ u8 *val);
+ void (*GetHwRegHandler)(struct adapter *padapter, u8 variable,
+ u8 *val);
+
+ u8 (*GetHalDefVarHandler)(struct adapter *padapter,
+ enum hal_def_variable eVariable,
+ void *pValue);
+ u8 (*SetHalDefVarHandler)(struct adapter *padapter,
+ enum hal_def_variable eVariable,
+ void *pValue);
+
+ void (*GetHalODMVarHandler)(struct adapter *padapter,
+ enum hal_odm_variable eVariable,
+ void *pValue1, bool bSet);
+ void (*SetHalODMVarHandler)(struct adapter *padapter,
+ enum hal_odm_variable eVariable,
+ void *pValue1, bool bSet);
+
+ void (*UpdateRAMaskHandler)(struct adapter *padapter,
+ u32 mac_id, u8 rssi_level);
+ void (*SetBeaconRelatedRegistersHandler)(struct adapter *padapter);
+
+ void (*Add_RateATid)(struct adapter *adapter, u32 bitmap, u8 arg,
+ u8 rssi_level);
+ void (*run_thread)(struct adapter *adapter);
+ void (*cancel_thread)(struct adapter *adapter);
+
+ u8 (*AntDivBeforeLinkHandler)(struct adapter *adapter);
+ void (*AntDivCompareHandler)(struct adapter *adapter,
+ struct wlan_bssid_ex *dst,
+ struct wlan_bssid_ex *src);
+ u8 (*interface_ps_func)(struct adapter *padapter,
+ enum hal_intf_ps_func efunc_id, u8 *val);
+
+ s32 (*hal_xmit)(struct adapter *padapter,
+ struct xmit_frame *pxmitframe);
+ s32 (*mgnt_xmit)(struct adapter *padapter,
+ struct xmit_frame *pmgntframe);
+
+ u32 (*read_bbreg)(struct adapter *padapter, u32 RegAddr,
+ u32 BitMask);
+ void (*write_bbreg)(struct adapter *padapter, u32 RegAddr,
+ u32 BitMask, u32 Data);
+ u32 (*read_rfreg)(struct adapter *padapter,
+ enum rf_radio_path eRFPath, u32 RegAddr,
+ u32 BitMask);
+ void (*write_rfreg)(struct adapter *padapter,
+ enum rf_radio_path eRFPath, u32 RegAddr,
+ u32 BitMask, u32 Data);
+
+ void (*EfusePowerSwitch)(struct adapter *padapter, u8 bWrite,
+ u8 PwrState);
+ void (*ReadEFuse)(struct adapter *padapter, u8 efuseType, u16 _offset,
+ u16 _size_byte, u8 *pbuf, bool bPseudoTest);
+ void (*EFUSEGetEfuseDefinition)(struct adapter *padapter, u8 efuseType,
+ u8 type, void *pOut, bool bPseudoTest);
+ u16 (*EfuseGetCurrentSize)(struct adapter *padapter, u8 efuseType,
+ bool bPseudoTest);
+ int (*Efuse_PgPacketRead)(struct adapter *adapter, u8 offset,
+ u8 *data, bool bPseudoTest);
+ int (*Efuse_PgPacketWrite)(struct adapter *padapter, u8 offset,
+ u8 word_en, u8 *data, bool bPseudoTest);
+ u8 (*Efuse_WordEnableDataWrite)(struct adapter *padapter,
+ u16 efuse_addr, u8 word_en,
+ u8 *data, bool bPseudoTest);
+ bool (*Efuse_PgPacketWrite_BT)(struct adapter *padapter, u8 offset,
+ u8 word_en, u8 *data, bool test);
+
+ void (*sreset_init_value)(struct adapter *padapter);
+ void (*sreset_reset_value)(struct adapter *padapter);
+ void (*silentreset)(struct adapter *padapter);
+ void (*sreset_xmit_status_check)(struct adapter *padapter);
+ void (*sreset_linked_status_check) (struct adapter *padapter);
+ u8 (*sreset_get_wifi_status)(struct adapter *padapter);
+
+ int (*IOL_exec_cmds_sync)(struct adapter *padapter,
+ struct xmit_frame *frame, u32 max_wait,
+ u32 bndy_cnt);
+
+ void (*hal_notch_filter)(struct adapter *adapter, bool enable);
+ void (*hal_reset_security_engine)(struct adapter *adapter);
+ s32 (*c2h_handler)(struct adapter *padapter,
+ struct c2h_evt_hdr *c2h_evt);
+ c2h_id_filter c2h_id_filter_ccx;
+};
+
+enum rt_eeprom_type {
+ EEPROM_93C46,
+ EEPROM_93C56,
+ EEPROM_BOOT_EFUSE,
+};
+
+#define RF_CHANGE_BY_INIT 0
+#define RF_CHANGE_BY_IPS BIT28
+#define RF_CHANGE_BY_PS BIT29
+#define RF_CHANGE_BY_HW BIT30
+#define RF_CHANGE_BY_SW BIT31
+
+enum hardware_type {
+ HARDWARE_TYPE_RTL8180,
+ HARDWARE_TYPE_RTL8185,
+ HARDWARE_TYPE_RTL8187,
+ HARDWARE_TYPE_RTL8188,
+ HARDWARE_TYPE_RTL8190P,
+ HARDWARE_TYPE_RTL8192E,
+ HARDWARE_TYPE_RTL819xU,
+ HARDWARE_TYPE_RTL8192SE,
+ HARDWARE_TYPE_RTL8192SU,
+ HARDWARE_TYPE_RTL8192CE,
+ HARDWARE_TYPE_RTL8192CU,
+ HARDWARE_TYPE_RTL8192DE,
+ HARDWARE_TYPE_RTL8192DU,
+ HARDWARE_TYPE_RTL8723AE,
+ HARDWARE_TYPE_RTL8723AU,
+ HARDWARE_TYPE_RTL8723AS,
+ HARDWARE_TYPE_RTL8188EE,
+ HARDWARE_TYPE_RTL8188EU,
+ HARDWARE_TYPE_RTL8188ES,
+ HARDWARE_TYPE_MAX,
+};
+
+/* RTL8188E Series */
+#define IS_HARDWARE_TYPE_8188EE(_Adapter) \
+(((struct adapter *)_Adapter)->HardwareType == HARDWARE_TYPE_RTL8188EE)
+#define IS_HARDWARE_TYPE_8188EU(_Adapter) \
+(((struct adapter *)_Adapter)->HardwareType == HARDWARE_TYPE_RTL8188EU)
+#define IS_HARDWARE_TYPE_8188ES(_Adapter) \
+(((struct adapter *)_Adapter)->HardwareType == HARDWARE_TYPE_RTL8188ES)
+#define IS_HARDWARE_TYPE_8188E(_Adapter) \
+(IS_HARDWARE_TYPE_8188EE(_Adapter) || IS_HARDWARE_TYPE_8188EU(_Adapter) || \
+ IS_HARDWARE_TYPE_8188ES(_Adapter))
+
+#define GET_EEPROM_EFUSE_PRIV(adapter) (&adapter->eeprompriv)
+
+#define is_boot_from_eeprom(adapter) (adapter->eeprompriv.EepromOrEfuse)
+
+void rtw_hal_def_value_init(struct adapter *padapter);
+
+void rtw_hal_free_data(struct adapter *padapter);
+
+void rtw_hal_dm_init(struct adapter *padapter);
+void rtw_hal_dm_deinit(struct adapter *padapter);
+void rtw_hal_sw_led_init(struct adapter *padapter);
+void rtw_hal_sw_led_deinit(struct adapter *padapter);
+
+u32 rtw_hal_power_on(struct adapter *padapter);
+uint rtw_hal_init(struct adapter *padapter);
+uint rtw_hal_deinit(struct adapter *padapter);
+void rtw_hal_stop(struct adapter *padapter);
+void rtw_hal_set_hwreg(struct adapter *padapter, u8 variable, u8 *val);
+void rtw_hal_get_hwreg(struct adapter *padapter, u8 variable, u8 *val);
+
+void rtw_hal_chip_configure(struct adapter *padapter);
+void rtw_hal_read_chip_info(struct adapter *padapter);
+void rtw_hal_read_chip_version(struct adapter *padapter);
+
+u8 rtw_hal_set_def_var(struct adapter *padapter,
+ enum hal_def_variable eVariable, void *pValue);
+u8 rtw_hal_get_def_var(struct adapter *padapter,
+ enum hal_def_variable eVariable, void *pValue);
+
+void rtw_hal_set_odm_var(struct adapter *padapter,
+ enum hal_odm_variable eVariable, void *pValue1,
+ bool bSet);
+void rtw_hal_get_odm_var(struct adapter *padapter,
+ enum hal_odm_variable eVariable,
+ void *pValue1, bool bSet);
+
+void rtw_hal_enable_interrupt(struct adapter *padapter);
+void rtw_hal_disable_interrupt(struct adapter *padapter);
+
+u32 rtw_hal_inirp_init(struct adapter *padapter);
+u32 rtw_hal_inirp_deinit(struct adapter *padapter);
+
+u8 rtw_hal_intf_ps_func(struct adapter *padapter,
+ enum hal_intf_ps_func efunc_id, u8 *val);
+
+s32 rtw_hal_xmit(struct adapter *padapter, struct xmit_frame *pxmitframe);
+s32 rtw_hal_mgnt_xmit(struct adapter *padapter,
+ struct xmit_frame *pmgntframe);
+
+s32 rtw_hal_init_xmit_priv(struct adapter *padapter);
+void rtw_hal_free_xmit_priv(struct adapter *padapter);
+
+s32 rtw_hal_init_recv_priv(struct adapter *padapter);
+void rtw_hal_free_recv_priv(struct adapter *padapter);
+
+void rtw_hal_update_ra_mask(struct adapter *padapter, u32 mac_id, u8 level);
+void rtw_hal_add_ra_tid(struct adapter *adapt, u32 bitmap, u8 arg, u8 level);
+void rtw_hal_clone_data(struct adapter *dst_adapt,
+ struct adapter *src_adapt);
+void rtw_hal_start_thread(struct adapter *padapter);
+void rtw_hal_stop_thread(struct adapter *padapter);
+
+void rtw_hal_bcn_related_reg_setting(struct adapter *padapter);
+
+u32 rtw_hal_read_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask);
+void rtw_hal_write_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask,
+ u32 Data);
+u32 rtw_hal_read_rfreg(struct adapter *padapter, enum rf_radio_path eRFPath,
+ u32 RegAddr, u32 BitMask);
+void rtw_hal_write_rfreg(struct adapter *padapter,
+ enum rf_radio_path eRFPath, u32 RegAddr,
+ u32 BitMask, u32 Data);
+
+s32 rtw_hal_interrupt_handler(struct adapter *padapter);
+
+void rtw_hal_set_bwmode(struct adapter *padapter,
+ enum ht_channel_width Bandwidth, u8 Offset);
+void rtw_hal_set_chan(struct adapter *padapter, u8 channel);
+void rtw_hal_dm_watchdog(struct adapter *padapter);
+
+u8 rtw_hal_antdiv_before_linked(struct adapter *padapter);
+void rtw_hal_antdiv_rssi_compared(struct adapter *padapter,
+ struct wlan_bssid_ex *dst,
+ struct wlan_bssid_ex *src);
+
+void rtw_hal_sreset_init(struct adapter *padapter);
+void rtw_hal_sreset_reset(struct adapter *padapter);
+void rtw_hal_sreset_reset_value(struct adapter *padapter);
+void rtw_hal_sreset_xmit_status_check(struct adapter *padapter);
+void rtw_hal_sreset_linked_status_check(struct adapter *padapter);
+u8 rtw_hal_sreset_get_wifi_status(struct adapter *padapter);
+
+int rtw_hal_iol_cmd(struct adapter *adapter, struct xmit_frame *xmit_frame,
+ u32 max_wating_ms, u32 bndy_cnt);
+
+void rtw_hal_notch_filter(struct adapter *adapter, bool enable);
+void rtw_hal_reset_security_engine(struct adapter *adapter);
+
+s32 rtw_hal_c2h_handler(struct adapter *adapter,
+ struct c2h_evt_hdr *c2h_evt);
+c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter);
+void indicate_wx_scan_complete_event(struct adapter *padapter);
+u8 rtw_do_join(struct adapter *padapter);
+
+#endif /* __HAL_INTF_H__ */
diff --git a/drivers/staging/rtl8188eu/include/ieee80211.h b/drivers/staging/rtl8188eu/include/ieee80211.h
new file mode 100644
index 00000000000..cd37ea4df4c
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/ieee80211.h
@@ -0,0 +1,1274 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __IEEE80211_H
+#define __IEEE80211_H
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include "wifi.h"
+#include <linux/wireless.h>
+
+#define MGMT_QUEUE_NUM 5
+
+#define ETH_ALEN 6
+#define ETH_TYPE_LEN 2
+#define PAYLOAD_TYPE_LEN 1
+
+#ifdef CONFIG_88EU_AP_MODE
+
+#define RTL_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 28)
+
+/* RTL871X_IOCTL_HOSTAPD ioctl() cmd: */
+enum {
+ RTL871X_HOSTAPD_FLUSH = 1,
+ RTL871X_HOSTAPD_ADD_STA = 2,
+ RTL871X_HOSTAPD_REMOVE_STA = 3,
+ RTL871X_HOSTAPD_GET_INFO_STA = 4,
+ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
+ RTL871X_HOSTAPD_GET_WPAIE_STA = 5,
+ RTL871X_SET_ENCRYPTION = 6,
+ RTL871X_GET_ENCRYPTION = 7,
+ RTL871X_HOSTAPD_SET_FLAGS_STA = 8,
+ RTL871X_HOSTAPD_GET_RID = 9,
+ RTL871X_HOSTAPD_SET_RID = 10,
+ RTL871X_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
+ RTL871X_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+ RTL871X_HOSTAPD_MLME = 13,
+ RTL871X_HOSTAPD_SCAN_REQ = 14,
+ RTL871X_HOSTAPD_STA_CLEAR_STATS = 15,
+ RTL871X_HOSTAPD_SET_BEACON = 16,
+ RTL871X_HOSTAPD_SET_WPS_BEACON = 17,
+ RTL871X_HOSTAPD_SET_WPS_PROBE_RESP = 18,
+ RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP = 19,
+ RTL871X_HOSTAPD_SET_HIDDEN_SSID = 20,
+ RTL871X_HOSTAPD_SET_MACADDR_ACL = 21,
+ RTL871X_HOSTAPD_ACL_ADD_STA = 22,
+ RTL871X_HOSTAPD_ACL_REMOVE_STA = 23,
+};
+
+/* STA flags */
+#define WLAN_STA_AUTH BIT(0)
+#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_PS BIT(2)
+#define WLAN_STA_TIM BIT(3)
+#define WLAN_STA_PERM BIT(4)
+#define WLAN_STA_AUTHORIZED BIT(5)
+#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
+#define WLAN_STA_SHORT_PREAMBLE BIT(7)
+#define WLAN_STA_PREAUTH BIT(8)
+#define WLAN_STA_WME BIT(9)
+#define WLAN_STA_MFP BIT(10)
+#define WLAN_STA_HT BIT(11)
+#define WLAN_STA_WPS BIT(12)
+#define WLAN_STA_MAYBE_WPS BIT(13)
+#define WLAN_STA_NONERP BIT(31)
+
+#endif
+
+#define IEEE_CMD_SET_WPA_PARAM 1
+#define IEEE_CMD_SET_WPA_IE 2
+#define IEEE_CMD_SET_ENCRYPTION 3
+#define IEEE_CMD_MLME 4
+
+#define IEEE_PARAM_WPA_ENABLED 1
+#define IEEE_PARAM_TKIP_COUNTERMEASURES 2
+#define IEEE_PARAM_DROP_UNENCRYPTED 3
+#define IEEE_PARAM_PRIVACY_INVOKED 4
+#define IEEE_PARAM_AUTH_ALGS 5
+#define IEEE_PARAM_IEEE_802_1X 6
+#define IEEE_PARAM_WPAX_SELECT 7
+
+#define AUTH_ALG_OPEN_SYSTEM 0x1
+#define AUTH_ALG_SHARED_KEY 0x2
+#define AUTH_ALG_LEAP 0x00000004
+
+#define IEEE_MLME_STA_DEAUTH 1
+#define IEEE_MLME_STA_DISASSOC 2
+
+#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2
+#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3
+#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5
+#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7
+
+
+#define IEEE_CRYPT_ALG_NAME_LEN 16
+
+#define WPA_CIPHER_NONE BIT(0)
+#define WPA_CIPHER_WEP40 BIT(1)
+#define WPA_CIPHER_WEP104 BIT(2)
+#define WPA_CIPHER_TKIP BIT(3)
+#define WPA_CIPHER_CCMP BIT(4)
+
+
+
+#define WPA_SELECTOR_LEN 4
+extern u8 RTW_WPA_OUI_TYPE[];
+extern u16 RTW_WPA_VERSION;
+extern u8 WPA_AUTH_KEY_MGMT_NONE[];
+extern u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[];
+extern u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[];
+extern u8 WPA_CIPHER_SUITE_NONE[];
+extern u8 WPA_CIPHER_SUITE_WEP40[];
+extern u8 WPA_CIPHER_SUITE_TKIP[];
+extern u8 WPA_CIPHER_SUITE_WRAP[];
+extern u8 WPA_CIPHER_SUITE_CCMP[];
+extern u8 WPA_CIPHER_SUITE_WEP104[];
+
+
+#define RSN_HEADER_LEN 4
+#define RSN_SELECTOR_LEN 4
+
+extern u16 RSN_VERSION_BSD;
+extern u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[];
+extern u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[];
+extern u8 RSN_CIPHER_SUITE_NONE[];
+extern u8 RSN_CIPHER_SUITE_WEP40[];
+extern u8 RSN_CIPHER_SUITE_TKIP[];
+extern u8 RSN_CIPHER_SUITE_WRAP[];
+extern u8 RSN_CIPHER_SUITE_CCMP[];
+extern u8 RSN_CIPHER_SUITE_WEP104[];
+
+enum ratr_table_mode {
+ RATR_INX_WIRELESS_NGB = 0, /* BGN 40 Mhz 2SS 1SS */
+ RATR_INX_WIRELESS_NG = 1, /* GN or N */
+ RATR_INX_WIRELESS_NB = 2, /* BGN 20 Mhz 2SS 1SS or BN */
+ RATR_INX_WIRELESS_N = 3,
+ RATR_INX_WIRELESS_GB = 4,
+ RATR_INX_WIRELESS_G = 5,
+ RATR_INX_WIRELESS_B = 6,
+ RATR_INX_WIRELESS_MC = 7,
+ RATR_INX_WIRELESS_AC_N = 8,
+};
+
+enum NETWORK_TYPE {
+ WIRELESS_INVALID = 0,
+ /* Sub-Element */
+ WIRELESS_11B = BIT(0), /* tx:cck only, rx:cck only, hw: cck */
+ WIRELESS_11G = BIT(1), /* tx:ofdm only, rx:ofdm & cck, hw:cck & ofdm*/
+ WIRELESS_11A = BIT(2), /* tx:ofdm only, rx: ofdm only, hw:ofdm only */
+ WIRELESS_11_24N = BIT(3), /* tx:MCS only, rx:MCS & cck, hw:MCS & cck */
+ WIRELESS_11_5N = BIT(4), /* tx:MCS only, rx:MCS & ofdm, hw:ofdm only */
+ WIRELESS_AC = BIT(6),
+
+ /* Combination */
+ /* tx: cck & ofdm, rx: cck & ofdm & MCS, hw: cck & ofdm */
+ WIRELESS_11BG = (WIRELESS_11B | WIRELESS_11G),
+ /* tx: ofdm & MCS, rx: ofdm & cck & MCS, hw: cck & ofdm */
+ WIRELESS_11G_24N = (WIRELESS_11G | WIRELESS_11_24N),
+ /* tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */
+ WIRELESS_11A_5N = (WIRELESS_11A | WIRELESS_11_5N),
+ /* tx: ofdm & cck & MCS, rx: ofdm & cck & MCS, hw: ofdm & cck */
+ WIRELESS_11BG_24N = (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N),
+ /* tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */
+ WIRELESS_11AGN = (WIRELESS_11A | WIRELESS_11G | WIRELESS_11_24N |
+ WIRELESS_11_5N),
+ WIRELESS_11ABGN = (WIRELESS_11A | WIRELESS_11B | WIRELESS_11G |
+ WIRELESS_11_24N | WIRELESS_11_5N),
+};
+
+#define SUPPORTED_24G_NETTYPE_MSK \
+ (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N)
+#define SUPPORTED_5G_NETTYPE_MSK \
+ (WIRELESS_11A | WIRELESS_11_5N)
+
+#define IsSupported24G(NetType) \
+ ((NetType) & SUPPORTED_24G_NETTYPE_MSK ? true : false)
+#define IsSupported5G(NetType) \
+ ((NetType) & SUPPORTED_5G_NETTYPE_MSK ? true : false)
+
+#define IsEnableHWCCK(NetType) \
+ IsSupported24G(NetType)
+#define IsEnableHWOFDM(NetType) \
+ ((NetType) & (WIRELESS_11G | WIRELESS_11_24N | \
+ SUPPORTED_5G_NETTYPE_MSK) ? true : false)
+
+#define IsSupportedRxCCK(NetType) IsEnableHWCCK(NetType)
+#define IsSupportedRxOFDM(NetType) IsEnableHWOFDM(NetType)
+#define IsSupportedRxMCS(NetType) IsEnableHWOFDM(NetType)
+
+#define IsSupportedTxCCK(NetType) \
+ ((NetType) & (WIRELESS_11B) ? true : false)
+#define IsSupportedTxOFDM(NetType) \
+ ((NetType) & (WIRELESS_11G|WIRELESS_11A) ? true : false)
+#define IsSupportedTxMCS(NetType) \
+ ((NetType) & (WIRELESS_11_24N|WIRELESS_11_5N) ? true : false)
+
+
+struct ieee_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u8 name;
+ u32 value;
+ } wpa_param;
+ struct {
+ u32 len;
+ u8 reserved[32];
+ u8 data[0];
+ } wpa_ie;
+ struct {
+ int command;
+ int reason_code;
+ } mlme;
+ struct {
+ u8 alg[IEEE_CRYPT_ALG_NAME_LEN];
+ u8 set_tx;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+#ifdef CONFIG_88EU_AP_MODE
+ struct {
+ u16 aid;
+ u16 capability;
+ int flags;
+ u8 tx_supp_rates[16];
+ struct rtw_ieee80211_ht_cap ht_cap;
+ } add_sta;
+ struct {
+ u8 reserved[2];/* for set max_num_sta */
+ u8 buf[0];
+ } bcn_ie;
+#endif
+
+ } u;
+};
+
+#ifdef CONFIG_88EU_AP_MODE
+struct ieee_param_ex {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ u8 data[0];
+};
+
+struct sta_data {
+ u16 aid;
+ u16 capability;
+ int flags;
+ u32 sta_set;
+ u8 tx_supp_rates[16];
+ u32 tx_supp_rates_len;
+ struct rtw_ieee80211_ht_cap ht_cap;
+ u64 rx_pkts;
+ u64 rx_bytes;
+ u64 rx_drops;
+ u64 tx_pkts;
+ u64 tx_bytes;
+ u64 tx_drops;
+};
+#endif
+
+#define IEEE80211_DATA_LEN 2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+ 6.2.1.1.2.
+
+ The figure in section 7.1.2 suggests a body size of up to 2312
+ bytes is allowed, which is a bit confusing, I suspect this
+ represents the 2304 bytes of real data, plus a possible 8 bytes of
+ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+
+#define IEEE80211_HLEN 30
+#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+
+/* this is stolen from ipw2200 driver */
+#define IEEE_IBSS_MAC_HASH_SIZE 31
+
+struct ieee_ibss_seq {
+ u8 mac[ETH_ALEN];
+ u16 seq_num;
+ u16 frag_num;
+ unsigned long packet_time;
+ struct list_head list;
+};
+
+struct rtw_ieee80211_hdr {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u8 addr4[ETH_ALEN];
+} __packed;
+
+struct rtw_ieee80211_hdr_3addr {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+} __packed;
+
+struct rtw_ieee80211_hdr_qos {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u8 addr4[ETH_ALEN];
+ u16 qc;
+} __packed;
+
+struct rtw_ieee80211_hdr_3addr_qos {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u16 qc;
+} __packed;
+
+struct eapol {
+ u8 snap[6];
+ u16 ethertype;
+ u8 version;
+ u8 type;
+ u16 length;
+} __packed;
+
+enum eap_type {
+ EAP_PACKET = 0,
+ EAPOL_START,
+ EAPOL_LOGOFF,
+ EAPOL_KEY,
+ EAPOL_ENCAP_ASF_ALERT
+};
+
+#define IEEE80211_3ADDR_LEN 24
+#define IEEE80211_4ADDR_LEN 30
+#define IEEE80211_FCS_LEN 4
+
+#define MIN_FRAG_THRESHOLD 256U
+#define MAX_FRAG_THRESHOLD 2346U
+
+/* Frame control field constants */
+#define RTW_IEEE80211_FCTL_VERS 0x0003
+#define RTW_IEEE80211_FCTL_FTYPE 0x000c
+#define RTW_IEEE80211_FCTL_STYPE 0x00f0
+#define RTW_IEEE80211_FCTL_TODS 0x0100
+#define RTW_IEEE80211_FCTL_FROMDS 0x0200
+#define RTW_IEEE80211_FCTL_MOREFRAGS 0x0400
+#define RTW_IEEE80211_FCTL_RETRY 0x0800
+#define RTW_IEEE80211_FCTL_PM 0x1000
+#define RTW_IEEE80211_FCTL_MOREDATA 0x2000
+#define RTW_IEEE80211_FCTL_PROTECTED 0x4000
+#define RTW_IEEE80211_FCTL_ORDER 0x8000
+#define RTW_IEEE80211_FCTL_CTL_EXT 0x0f00
+
+#define RTW_IEEE80211_FTYPE_MGMT 0x0000
+#define RTW_IEEE80211_FTYPE_CTL 0x0004
+#define RTW_IEEE80211_FTYPE_DATA 0x0008
+#define RTW_IEEE80211_FTYPE_EXT 0x000c
+
+/* management */
+#define RTW_IEEE80211_STYPE_ASSOC_REQ 0x0000
+#define RTW_IEEE80211_STYPE_ASSOC_RESP 0x0010
+#define RTW_IEEE80211_STYPE_REASSOC_REQ 0x0020
+#define RTW_IEEE80211_STYPE_REASSOC_RESP 0x0030
+#define RTW_IEEE80211_STYPE_PROBE_REQ 0x0040
+#define RTW_IEEE80211_STYPE_PROBE_RESP 0x0050
+#define RTW_IEEE80211_STYPE_BEACON 0x0080
+#define RTW_IEEE80211_STYPE_ATIM 0x0090
+#define RTW_IEEE80211_STYPE_DISASSOC 0x00A0
+#define RTW_IEEE80211_STYPE_AUTH 0x00B0
+#define RTW_IEEE80211_STYPE_DEAUTH 0x00C0
+#define RTW_IEEE80211_STYPE_ACTION 0x00D0
+
+/* control */
+#define RTW_IEEE80211_STYPE_CTL_EXT 0x0060
+#define RTW_IEEE80211_STYPE_BACK_REQ 0x0080
+#define RTW_IEEE80211_STYPE_BACK 0x0090
+#define RTW_IEEE80211_STYPE_PSPOLL 0x00A0
+#define RTW_IEEE80211_STYPE_RTS 0x00B0
+#define RTW_IEEE80211_STYPE_CTS 0x00C0
+#define RTW_IEEE80211_STYPE_ACK 0x00D0
+#define RTW_IEEE80211_STYPE_CFEND 0x00E0
+#define RTW_IEEE80211_STYPE_CFENDACK 0x00F0
+
+/* data */
+#define RTW_IEEE80211_STYPE_DATA 0x0000
+#define RTW_IEEE80211_STYPE_DATA_CFACK 0x0010
+#define RTW_IEEE80211_STYPE_DATA_CFPOLL 0x0020
+#define RTW_IEEE80211_STYPE_DATA_CFACKPOLL 0x0030
+#define RTW_IEEE80211_STYPE_NULLFUNC 0x0040
+#define RTW_IEEE80211_STYPE_CFACK 0x0050
+#define RTW_IEEE80211_STYPE_CFPOLL 0x0060
+#define RTW_IEEE80211_STYPE_CFACKPOLL 0x0070
+#define RTW_IEEE80211_STYPE_QOS_DATA 0x0080
+#define RTW_IEEE80211_STYPE_QOS_DATA_CFACK 0x0090
+#define RTW_IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0
+#define RTW_IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0
+#define RTW_IEEE80211_STYPE_QOS_NULLFUNC 0x00C0
+#define RTW_IEEE80211_STYPE_QOS_CFACK 0x00D0
+#define RTW_IEEE80211_STYPE_QOS_CFPOLL 0x00E0
+#define RTW_IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0
+
+/* sequence control field */
+#define RTW_IEEE80211_SCTL_FRAG 0x000F
+#define RTW_IEEE80211_SCTL_SEQ 0xFFF0
+
+
+#define RTW_ERP_INFO_NON_ERP_PRESENT BIT(0)
+#define RTW_ERP_INFO_USE_PROTECTION BIT(1)
+#define RTW_ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
+
+/* QoS, QOS */
+#define NORMAL_ACK 0
+#define NO_ACK 1
+#define NON_EXPLICIT_ACK 2
+#define BLOCK_ACK 3
+
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+
+#define ETH_P_ECONET 0x0018
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
+#endif
+
+/* IEEE 802.11 defines */
+
+#define P80211_OUI_LEN 3
+
+struct ieee80211_snap_hdr {
+ u8 dsap; /* always 0xAA */
+ u8 ssap; /* always 0xAA */
+ u8 ctrl; /* always 0x03 */
+ u8 oui[P80211_OUI_LEN]; /* organizational universal id */
+} __packed;
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define WLAN_FC_GET_TYPE(fc) ((fc) & RTW_IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & RTW_IEEE80211_FCTL_STYPE)
+
+#define WLAN_QC_GET_TID(qc) ((qc) & 0x0f)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTW_IEEE80211_SCTL_FRAG)
+#define WLAN_GET_SEQ_SEQ(seq) ((seq) & RTW_IEEE80211_SCTL_SEQ)
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_BSS (1<<0)
+#define WLAN_CAPABILITY_IBSS (1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
+#define WLAN_CAPABILITY_PRIVACY (1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
+#define WLAN_CAPABILITY_PBCC (1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
+#define WLAN_CAPABILITY_SHORT_SLOT (1<<10)
+
+/* Status codes */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+
+/* Reason codes */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+#define WLAN_REASON_JOIN_WRONG_CHANNEL 65534
+#define WLAN_REASON_EXPIRATION_CHK 65535
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_CHALLENGE 16
+/* EIDs defined by IEEE 802.11h - START */
+#define WLAN_EID_PWR_CONSTRAINT 32
+#define WLAN_EID_PWR_CAPABILITY 33
+#define WLAN_EID_TPC_REQUEST 34
+#define WLAN_EID_TPC_REPORT 35
+#define WLAN_EID_SUPPORTED_CHANNELS 36
+#define WLAN_EID_CHANNEL_SWITCH 37
+#define WLAN_EID_MEASURE_REQUEST 38
+#define WLAN_EID_MEASURE_REPORT 39
+#define WLAN_EID_QUITE 40
+#define WLAN_EID_IBSS_DFS 41
+/* EIDs defined by IEEE 802.11h - END */
+#define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_HT_CAP 45
+#define WLAN_EID_RSN 48
+#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_MOBILITY_DOMAIN 54
+#define WLAN_EID_FAST_BSS_TRANSITION 55
+#define WLAN_EID_TIMEOUT_INTERVAL 56
+#define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_HT_OPERATION 61
+#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_20_40_BSS_COEXISTENCE 72
+#define WLAN_EID_20_40_BSS_INTOLERANT 73
+#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
+#define WLAN_EID_MMIE 76
+#define WLAN_EID_VENDOR_SPECIFIC 221
+#define WLAN_EID_GENERIC (WLAN_EID_VENDOR_SPECIFIC)
+
+#define IEEE80211_MGMT_HDR_LEN 24
+#define IEEE80211_DATA_HDR3_LEN 24
+#define IEEE80211_DATA_HDR4_LEN 30
+
+
+#define IEEE80211_STATMASK_SIGNAL (1<<0)
+#define IEEE80211_STATMASK_RSSI (1<<1)
+#define IEEE80211_STATMASK_NOISE (1<<2)
+#define IEEE80211_STATMASK_RATE (1<<3)
+#define IEEE80211_STATMASK_WEMASK 0x7
+
+
+#define IEEE80211_CCK_MODULATION (1<<0)
+#define IEEE80211_OFDM_MODULATION (1<<1)
+
+#define IEEE80211_24GHZ_BAND (1<<0)
+#define IEEE80211_52GHZ_BAND (1<<1)
+
+#define IEEE80211_CCK_RATE_LEN 4
+#define IEEE80211_NUM_OFDM_RATESLEN 8
+
+
+#define IEEE80211_CCK_RATE_1MB 0x02
+#define IEEE80211_CCK_RATE_2MB 0x04
+#define IEEE80211_CCK_RATE_5MB 0x0B
+#define IEEE80211_CCK_RATE_11MB 0x16
+#define IEEE80211_OFDM_RATE_LEN 8
+#define IEEE80211_OFDM_RATE_6MB 0x0C
+#define IEEE80211_OFDM_RATE_9MB 0x12
+#define IEEE80211_OFDM_RATE_12MB 0x18
+#define IEEE80211_OFDM_RATE_18MB 0x24
+#define IEEE80211_OFDM_RATE_24MB 0x30
+#define IEEE80211_OFDM_RATE_36MB 0x48
+#define IEEE80211_OFDM_RATE_48MB 0x60
+#define IEEE80211_OFDM_RATE_54MB 0x6C
+#define IEEE80211_BASIC_RATE_MASK 0x80
+
+#define IEEE80211_CCK_RATE_1MB_MASK (1<<0)
+#define IEEE80211_CCK_RATE_2MB_MASK (1<<1)
+#define IEEE80211_CCK_RATE_5MB_MASK (1<<2)
+#define IEEE80211_CCK_RATE_11MB_MASK (1<<3)
+#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4)
+#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5)
+#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6)
+#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7)
+#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8)
+#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9)
+#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10)
+#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11)
+
+#define IEEE80211_CCK_RATES_MASK 0x0000000F
+#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \
+ IEEE80211_CCK_RATE_2MB_MASK)
+#define IEEE80211_CCK_DEFAULT_RATES_MASK \
+ (IEEE80211_CCK_BASIC_RATES_MASK | \
+ IEEE80211_CCK_RATE_5MB_MASK | \
+ IEEE80211_CCK_RATE_11MB_MASK)
+
+#define IEEE80211_OFDM_RATES_MASK 0x00000FF0
+#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \
+ IEEE80211_OFDM_RATE_12MB_MASK | \
+ IEEE80211_OFDM_RATE_24MB_MASK)
+#define IEEE80211_OFDM_DEFAULT_RATES_MASK \
+ (IEEE80211_OFDM_BASIC_RATES_MASK | \
+ IEEE80211_OFDM_RATE_9MB_MASK | \
+ IEEE80211_OFDM_RATE_18MB_MASK | \
+ IEEE80211_OFDM_RATE_36MB_MASK | \
+ IEEE80211_OFDM_RATE_48MB_MASK | \
+ IEEE80211_OFDM_RATE_54MB_MASK)
+#define IEEE80211_DEFAULT_RATES_MASK \
+ (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
+ IEEE80211_CCK_DEFAULT_RATES_MASK)
+
+#define IEEE80211_NUM_OFDM_RATES 8
+#define IEEE80211_NUM_CCK_RATES 4
+#define IEEE80211_OFDM_SHIFT_MASK_A 4
+
+/* NOTE: This data is for statistical purposes; not all hardware provides this
+ * information for frames received. Not setting these will not cause
+ * any adverse affects. */
+struct ieee80211_rx_stats {
+ /* u32 mac_time[2]; */
+ s8 rssi;
+ u8 signal;
+ u8 noise;
+ u8 received_channel;
+ u16 rate; /* in 100 kbps */
+ /* u8 control; */
+ u8 mask;
+ u8 freq;
+ u16 len;
+};
+
+/* IEEE 802.11 requires that STA supports concurrent reception of at least
+ * three fragmented frames. This define can be increased to support more
+ * concurrent frames, but it should be noted that each entry can consume about
+ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
+#define IEEE80211_FRAG_CACHE_LEN 4
+
+struct ieee80211_frag_entry {
+ u32 first_frag_time;
+ uint seq;
+ uint last_frag;
+ uint qos; /* jackson */
+ uint tid; /* jackson */
+ struct sk_buff *skb;
+ u8 src_addr[ETH_ALEN];
+ u8 dst_addr[ETH_ALEN];
+};
+
+struct ieee80211_stats {
+ uint tx_unicast_frames;
+ uint tx_multicast_frames;
+ uint tx_fragments;
+ uint tx_unicast_octets;
+ uint tx_multicast_octets;
+ uint tx_deferred_transmissions;
+ uint tx_single_retry_frames;
+ uint tx_multiple_retry_frames;
+ uint tx_retry_limit_exceeded;
+ uint tx_discards;
+ uint rx_unicast_frames;
+ uint rx_multicast_frames;
+ uint rx_fragments;
+ uint rx_unicast_octets;
+ uint rx_multicast_octets;
+ uint rx_fcs_errors;
+ uint rx_discards_no_buffer;
+ uint tx_discards_wrong_sa;
+ uint rx_discards_undecryptable;
+ uint rx_message_in_msg_fragments;
+ uint rx_message_in_bad_msg_fragments;
+};
+
+struct ieee80211_softmac_stats {
+ uint rx_ass_ok;
+ uint rx_ass_err;
+ uint rx_probe_rq;
+ uint tx_probe_rs;
+ uint tx_beacons;
+ uint rx_auth_rq;
+ uint rx_auth_rs_ok;
+ uint rx_auth_rs_err;
+ uint tx_auth_rq;
+ uint no_auth_rs;
+ uint no_ass_rs;
+ uint tx_ass_rq;
+ uint rx_ass_rq;
+ uint tx_probe_rq;
+ uint reassoc;
+ uint swtxstop;
+ uint swtxawake;
+};
+
+#define SEC_KEY_1 (1<<0)
+#define SEC_KEY_2 (1<<1)
+#define SEC_KEY_3 (1<<2)
+#define SEC_KEY_4 (1<<3)
+#define SEC_ACTIVE_KEY (1<<4)
+#define SEC_AUTH_MODE (1<<5)
+#define SEC_UNICAST_GROUP (1<<6)
+#define SEC_LEVEL (1<<7)
+#define SEC_ENABLED (1<<8)
+
+#define SEC_LEVEL_0 0 /* None */
+#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
+#define SEC_LEVEL_2 2 /* Level 1 + TKIP */
+#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
+#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
+
+#define WEP_KEYS 4
+#define WEP_KEY_LEN 13
+
+struct ieee80211_security {
+ u16 active_key:2,
+ enabled:1,
+ auth_mode:2,
+ auth_algo:4,
+ unicast_uses_group:1;
+ u8 key_sizes[WEP_KEYS];
+ u8 keys[WEP_KEYS][WEP_KEY_LEN];
+ u8 level;
+ u16 flags;
+} __packed;
+
+/*
+
+ 802.11 data frame from AP
+
+ ,-------------------------------------------------------------------.
+Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
+ |------|------|---------|---------|---------|------|---------|------|
+Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs |
+ | | tion | (BSSID) | | | ence | data | |
+ `-------------------------------------------------------------------'
+
+Total: 28-2340 bytes
+
+*/
+
+struct ieee80211_header_data {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[6];
+ u8 addr2[6];
+ u8 addr3[6];
+ u16 seq_ctrl;
+};
+
+#define BEACON_PROBE_SSID_ID_POSITION 12
+
+/* Management Frame Information Element Types */
+#define MFIE_TYPE_SSID 0
+#define MFIE_TYPE_RATES 1
+#define MFIE_TYPE_FH_SET 2
+#define MFIE_TYPE_DS_SET 3
+#define MFIE_TYPE_CF_SET 4
+#define MFIE_TYPE_TIM 5
+#define MFIE_TYPE_IBSS_SET 6
+#define MFIE_TYPE_CHALLENGE 16
+#define MFIE_TYPE_ERP 42
+#define MFIE_TYPE_RSN 48
+#define MFIE_TYPE_RATES_EX 50
+#define MFIE_TYPE_GENERIC 221
+
+struct ieee80211_info_element_hdr {
+ u8 id;
+ u8 len;
+} __packed;
+
+struct ieee80211_info_element {
+ u8 id;
+ u8 len;
+ u8 data[0];
+} __packed;
+
+/*
+ * These are the data types that can make up management packets
+ *
+ u16 auth_algorithm;
+ u16 auth_sequence;
+ u16 beacon_interval;
+ u16 capability;
+ u8 current_ap[ETH_ALEN];
+ u16 listen_interval;
+ struct {
+ u16 association_id:14, reserved:2;
+ } __packed;
+ u32 time_stamp[2];
+ u16 reason;
+ u16 status;
+*/
+
+#define IEEE80211_DEFAULT_TX_ESSID "Penguin"
+#define IEEE80211_DEFAULT_BASIC_RATE 10
+
+struct ieee80211_authentication {
+ struct ieee80211_header_data header;
+ u16 algorithm;
+ u16 transaction;
+ u16 status;
+ /* struct ieee80211_info_element_hdr info_element; */
+} __packed;
+
+struct ieee80211_probe_response {
+ struct ieee80211_header_data header;
+ u32 time_stamp[2];
+ u16 beacon_interval;
+ u16 capability;
+ struct ieee80211_info_element info_element;
+} __packed;
+
+struct ieee80211_probe_request {
+ struct ieee80211_header_data header;
+} __packed;
+
+struct ieee80211_assoc_request_frame {
+ struct rtw_ieee80211_hdr_3addr header;
+ u16 capability;
+ u16 listen_interval;
+ struct ieee80211_info_element_hdr info_element;
+} __packed;
+
+struct ieee80211_assoc_response_frame {
+ struct rtw_ieee80211_hdr_3addr header;
+ u16 capability;
+ u16 status;
+ u16 aid;
+} __packed;
+
+struct ieee80211_txb {
+ u8 nr_frags;
+ u8 encrypted;
+ u16 reserved;
+ u16 frag_size;
+ u16 payload_size;
+ struct sk_buff *fragments[0];
+};
+
+
+/* SWEEP TABLE ENTRIES NUMBER*/
+#define MAX_SWEEP_TAB_ENTRIES 42
+#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7
+/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
+ * only use 8, and then use extended rates for the remaining supported
+ * rates. Other APs, however, stick all of their supported rates on the
+ * main rates information element... */
+#define MAX_RATES_LENGTH ((u8)12)
+#define MAX_RATES_EX_LENGTH ((u8)16)
+#define MAX_NETWORK_COUNT 128
+#define MAX_CHANNEL_NUMBER 161
+#define IEEE80211_SOFTMAC_SCAN_TIME 400
+/* HZ / 2) */
+#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2)
+
+#define CRC_LENGTH 4U
+
+#define MAX_WPA_IE_LEN (256)
+#define MAX_WPS_IE_LEN (512)
+#define MAX_P2P_IE_LEN (256)
+#define MAX_WFD_IE_LEN (128)
+
+#define NETWORK_EMPTY_ESSID (1<<0)
+#define NETWORK_HAS_OFDM (1<<1)
+#define NETWORK_HAS_CCK (1<<2)
+
+#define IEEE80211_DTIM_MBCAST 4
+#define IEEE80211_DTIM_UCAST 2
+#define IEEE80211_DTIM_VALID 1
+#define IEEE80211_DTIM_INVALID 0
+
+#define IEEE80211_PS_DISABLED 0
+#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST
+#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST
+#define IW_ESSID_MAX_SIZE 32
+/*
+join_res:
+-1: authentication fail
+-2: association fail
+> 0: TID
+*/
+
+enum ieee80211_state {
+ /* the card is not linked at all */
+ IEEE80211_NOLINK = 0,
+
+ /* IEEE80211_ASSOCIATING* are for BSS client mode
+ * the driver shall not perform RX filtering unless
+ * the state is LINKED.
+ * The driver shall just check for the state LINKED and
+ * defaults to NOLINK for ALL the other states (including
+ * LINKED_SCANNING)
+ */
+
+ /* the association procedure will start (wq scheduling)*/
+ IEEE80211_ASSOCIATING,
+ IEEE80211_ASSOCIATING_RETRY,
+
+ /* the association procedure is sending AUTH request*/
+ IEEE80211_ASSOCIATING_AUTHENTICATING,
+
+ /* the association procedure has successfully authentcated
+ * and is sending association request
+ */
+ IEEE80211_ASSOCIATING_AUTHENTICATED,
+
+ /* the link is ok. the card associated to a BSS or linked
+ * to a ibss cell or acting as an AP and creating the bss
+ */
+ IEEE80211_LINKED,
+
+ /* same as LINKED, but the driver shall apply RX filter
+ * rules as we are in NO_LINK mode. As the card is still
+ * logically linked, but it is doing a syncro site survey
+ * then it will be back to LINKED state.
+ */
+ IEEE80211_LINKED_SCANNING,
+
+};
+
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+#define DEFAULT_FTS 2346
+
+static inline int is_multicast_mac_addr(const u8 *addr)
+{
+ return ((addr[0] != 0xff) && (0x01 & addr[0]));
+}
+
+static inline int is_broadcast_mac_addr(const u8 *addr)
+{
+ return (addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) &&
+ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff);
+}
+
+#define CFG_IEEE80211_RESERVE_FCS (1<<0)
+#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
+
+struct tx_pending {
+ int frag;
+ struct ieee80211_txb *txb;
+};
+
+#define MAXTID 16
+
+#define IEEE_A (1<<0)
+#define IEEE_B (1<<1)
+#define IEEE_G (1<<2)
+#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
+
+/* Baron move to ieee80211.c */
+int ieee80211_is_empty_essid(const char *essid, int essid_len);
+int ieee80211_get_hdrlen(u16 fc);
+
+/* Action category code */
+enum rtw_ieee80211_category {
+ RTW_WLAN_CATEGORY_SPECTRUM_MGMT = 0,
+ RTW_WLAN_CATEGORY_QOS = 1,
+ RTW_WLAN_CATEGORY_DLS = 2,
+ RTW_WLAN_CATEGORY_BACK = 3,
+ RTW_WLAN_CATEGORY_PUBLIC = 4, /* IEEE 802.11 public action frames */
+ RTW_WLAN_CATEGORY_RADIO_MEASUREMENT = 5,
+ RTW_WLAN_CATEGORY_FT = 6,
+ RTW_WLAN_CATEGORY_HT = 7,
+ RTW_WLAN_CATEGORY_SA_QUERY = 8,
+ RTW_WLAN_CATEGORY_TDLS = 12,
+ RTW_WLAN_CATEGORY_WMM = 17,
+ RTW_WLAN_CATEGORY_P2P = 0x7f,/* P2P action frames */
+};
+
+/* SPECTRUM_MGMT action code */
+enum rtw_ieee80211_spectrum_mgmt_actioncode {
+ RTW_WLAN_ACTION_SPCT_MSR_REQ = 0,
+ RTW_WLAN_ACTION_SPCT_MSR_RPRT = 1,
+ RTW_WLAN_ACTION_SPCT_TPC_REQ = 2,
+ RTW_WLAN_ACTION_SPCT_TPC_RPRT = 3,
+ RTW_WLAN_ACTION_SPCT_CHL_SWITCH = 4,
+ RTW_WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5,
+};
+
+enum _PUBLIC_ACTION {
+ ACT_PUBLIC_BSSCOEXIST = 0, /* 20/40 BSS Coexistence */
+ ACT_PUBLIC_DSE_ENABLE = 1,
+ ACT_PUBLIC_DSE_DEENABLE = 2,
+ ACT_PUBLIC_DSE_REG_LOCATION = 3,
+ ACT_PUBLIC_EXT_CHL_SWITCH = 4,
+ ACT_PUBLIC_DSE_MSR_REQ = 5,
+ ACT_PUBLIC_DSE_MSR_RPRT = 6,
+ ACT_PUBLIC_MP = 7, /* Measurement Pilot */
+ ACT_PUBLIC_DSE_PWR_CONSTRAINT = 8,
+ ACT_PUBLIC_VENDOR = 9, /* for WIFI_DIRECT */
+ ACT_PUBLIC_GAS_INITIAL_REQ = 10,
+ ACT_PUBLIC_GAS_INITIAL_RSP = 11,
+ ACT_PUBLIC_GAS_COMEBACK_REQ = 12,
+ ACT_PUBLIC_GAS_COMEBACK_RSP = 13,
+ ACT_PUBLIC_TDLS_DISCOVERY_RSP = 14,
+ ACT_PUBLIC_LOCATION_TRACK = 15,
+ ACT_PUBLIC_MAX
+};
+
+/* BACK action code */
+enum rtw_ieee80211_back_actioncode {
+ RTW_WLAN_ACTION_ADDBA_REQ = 0,
+ RTW_WLAN_ACTION_ADDBA_RESP = 1,
+ RTW_WLAN_ACTION_DELBA = 2,
+};
+
+/* HT features action code */
+enum rtw_ieee80211_ht_actioncode {
+ RTW_WLAN_ACTION_NOTIFY_CH_WIDTH = 0,
+ RTW_WLAN_ACTION_SM_PS = 1,
+ RTW_WLAN_ACTION_PSPM = 2,
+ RTW_WLAN_ACTION_PCO_PHASE = 3,
+ RTW_WLAN_ACTION_MIMO_CSI_MX = 4,
+ RTW_WLAN_ACTION_MIMO_NONCP_BF = 5,
+ RTW_WLAN_ACTION_MIMP_CP_BF = 6,
+ RTW_WLAN_ACTION_ASEL_INDICATES_FB = 7,
+ RTW_WLAN_ACTION_HI_INFO_EXCHG = 8,
+};
+
+/* BACK (block-ack) parties */
+enum rtw_ieee80211_back_parties {
+ RTW_WLAN_BACK_RECIPIENT = 0,
+ RTW_WLAN_BACK_INITIATOR = 1,
+ RTW_WLAN_BACK_TIMER = 2,
+};
+
+#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
+ * 00:50:F2 */
+#define WME_OUI_TYPE 2
+#define WME_OUI_SUBTYPE_INFORMATION_ELEMENT 0
+#define WME_OUI_SUBTYPE_PARAMETER_ELEMENT 1
+#define WME_OUI_SUBTYPE_TSPEC_ELEMENT 2
+#define WME_VERSION 1
+
+#define WME_ACTION_CODE_SETUP_REQUEST 0
+#define WME_ACTION_CODE_SETUP_RESPONSE 1
+#define WME_ACTION_CODE_TEARDOWN 2
+
+#define WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED 0
+#define WME_SETUP_RESPONSE_STATUS_INVALID_PARAMETERS 1
+#define WME_SETUP_RESPONSE_STATUS_REFUSED 3
+
+#define WME_TSPEC_DIRECTION_UPLINK 0
+#define WME_TSPEC_DIRECTION_DOWNLINK 1
+#define WME_TSPEC_DIRECTION_BI_DIRECTIONAL 3
+
+
+#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+
+#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
+
+/**
+ * enum rtw_ieee80211_channel_flags - channel flags
+ *
+ * Channel flags set by the regulatory control code.
+ *
+ * @RTW_IEEE80211_CHAN_DISABLED: This channel is disabled.
+ * @RTW_IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
+ * on this channel.
+ * @RTW_IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
+ * @RTW_IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
+ * @RTW_IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel
+ * is not permitted.
+ * @RTW_IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel
+ * is not permitted.
+ */
+enum rtw_ieee80211_channel_flags {
+ RTW_IEEE80211_CHAN_DISABLED = 1<<0,
+ RTW_IEEE80211_CHAN_PASSIVE_SCAN = 1<<1,
+ RTW_IEEE80211_CHAN_NO_IBSS = 1<<2,
+ RTW_IEEE80211_CHAN_RADAR = 1<<3,
+ RTW_IEEE80211_CHAN_NO_HT40PLUS = 1<<4,
+ RTW_IEEE80211_CHAN_NO_HT40MINUS = 1<<5,
+};
+
+#define RTW_IEEE80211_CHAN_NO_HT40 \
+ (RTW_IEEE80211_CHAN_NO_HT40PLUS | RTW_IEEE80211_CHAN_NO_HT40MINUS)
+
+/* Represent channel details, subset of ieee80211_channel */
+struct rtw_ieee80211_channel {
+ u16 hw_value;
+ u32 flags;
+};
+
+#define CHAN_FMT \
+ "hw_value:%u, " \
+ "flags:0x%08x" \
+
+#define CHAN_ARG(channel) \
+ (channel)->hw_value \
+ , (channel)->flags \
+
+/* Parsed Information Elements */
+struct rtw_ieee802_11_elems {
+ u8 *ssid;
+ u8 ssid_len;
+ u8 *supp_rates;
+ u8 supp_rates_len;
+ u8 *fh_params;
+ u8 fh_params_len;
+ u8 *ds_params;
+ u8 ds_params_len;
+ u8 *cf_params;
+ u8 cf_params_len;
+ u8 *tim;
+ u8 tim_len;
+ u8 *ibss_params;
+ u8 ibss_params_len;
+ u8 *challenge;
+ u8 challenge_len;
+ u8 *erp_info;
+ u8 erp_info_len;
+ u8 *ext_supp_rates;
+ u8 ext_supp_rates_len;
+ u8 *wpa_ie;
+ u8 wpa_ie_len;
+ u8 *rsn_ie;
+ u8 rsn_ie_len;
+ u8 *wme;
+ u8 wme_len;
+ u8 *wme_tspec;
+ u8 wme_tspec_len;
+ u8 *wps_ie;
+ u8 wps_ie_len;
+ u8 *power_cap;
+ u8 power_cap_len;
+ u8 *supp_channels;
+ u8 supp_channels_len;
+ u8 *mdie;
+ u8 mdie_len;
+ u8 *ftie;
+ u8 ftie_len;
+ u8 *timeout_int;
+ u8 timeout_int_len;
+ u8 *ht_capabilities;
+ u8 ht_capabilities_len;
+ u8 *ht_operation;
+ u8 ht_operation_len;
+ u8 *vendor_ht_cap;
+ u8 vendor_ht_cap_len;
+};
+
+enum parse_res {
+ ParseOK = 0,
+ ParseUnknown = 1,
+ ParseFailed = -1
+};
+
+enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len,
+ struct rtw_ieee802_11_elems *elems,
+ int show_errors);
+
+u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len,
+ unsigned char *source, unsigned int *frlen);
+u8 *rtw_set_ie(u8 *pbuf, int index, uint len, u8 *source, uint *frlen);
+
+enum secondary_ch_offset {
+ SCN = 0, /* no secondary channel */
+ SCA = 1, /* secondary channel above */
+ SCB = 3, /* secondary channel below */
+};
+u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset);
+u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset);
+u8 *rtw_set_ie_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode,
+ u8 new_ch, u8 ch_switch_cnt);
+u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len,
+ u8 secondary_ch_offset);
+u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl,
+ u8 flags, u16 reason, u16 precedence);
+
+u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit);
+u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui,
+ u8 oui_len, u8 *ie, uint *ielen);
+int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset,
+ u8 eid, u8 *oui, u8 oui_len);
+
+void rtw_set_supported_rate(u8 *SupportedRates, uint mode);
+
+unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit);
+unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit);
+int rtw_get_wpa_cipher_suite(u8 *s);
+int rtw_get_wpa2_cipher_suite(u8 *s);
+int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len);
+int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
+ int *pairwise_cipher, int *is_8021x);
+int rtw_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
+ int *pairwise_cipher, int *is_8021x);
+
+int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len,
+ u8 *wpa_ie, u16 *wpa_len);
+
+u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen);
+u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen);
+u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id,
+ u8 *buf_attr, u32 *len_attr);
+u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id,
+ u8 *buf_content, uint *len_content);
+
+/**
+ * for_each_ie - iterate over continuous IEs
+ * @ie:
+ * @buf:
+ * @buf_len:
+ */
+#define for_each_ie(ie, buf, buf_len) \
+ for (ie = (void *)buf; (((u8 *)ie) - ((u8 *)buf) + 1) < buf_len; \
+ ie = (void *)(((u8 *)ie) + *(((u8 *)ie)+1) + 2))
+
+void dump_ies(u8 *buf, u32 buf_len);
+void dump_wps_ie(u8 *ie, u32 ie_len);
+
+#ifdef CONFIG_88EU_P2P
+void dump_p2p_ie(u8 *ie, u32 ie_len);
+u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen);
+u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id,
+ u8 *buf_attr, u32 *len_attr);
+u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id,
+ u8 *buf_content, uint *len_content);
+u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len,
+ u8 *pdata_attr);
+void rtw_wlan_bssid_ex_remove_p2p_attr(struct wlan_bssid_ex *bss_ex,
+ u8 attr_id);
+#endif
+
+uint rtw_get_rateset_len(u8 *rateset);
+
+struct registry_priv;
+int rtw_generate_ie(struct registry_priv *pregistrypriv);
+
+
+int rtw_get_bit_value_from_ieee_value(u8 val);
+
+uint rtw_is_cckrates_included(u8 *rate);
+
+uint rtw_is_cckratesonly_included(u8 *rate);
+
+int rtw_check_network_type(unsigned char *rate, int ratelen, int channel);
+
+void rtw_get_bcn_info(struct wlan_network *pnetwork);
+
+void rtw_macaddr_cfg(u8 *mac_addr);
+
+u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40,
+ unsigned char *MCS_rate);
+
+int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category,
+ u8 *action);
+const char *action_public_str(u8 action);
+
+#endif /* IEEE80211_H */
diff --git a/drivers/staging/rtl8188eu/include/ieee80211_ext.h b/drivers/staging/rtl8188eu/include/ieee80211_ext.h
new file mode 100644
index 00000000000..1052d1817a9
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/ieee80211_ext.h
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __IEEE80211_EXT_H
+#define __IEEE80211_EXT_H
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define WMM_OUI_TYPE 2
+#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
+#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
+#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
+#define WMM_VERSION 1
+
+#define WPA_PROTO_WPA BIT(0)
+#define WPA_PROTO_RSN BIT(1)
+
+#define WPA_KEY_MGMT_IEEE8021X BIT(0)
+#define WPA_KEY_MGMT_PSK BIT(1)
+#define WPA_KEY_MGMT_NONE BIT(2)
+#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
+#define WPA_KEY_MGMT_WPA_NONE BIT(4)
+
+
+#define WPA_CAPABILITY_PREAUTH BIT(0)
+#define WPA_CAPABILITY_MGMT_FRAME_PROTECTION BIT(6)
+#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
+
+
+#define PMKID_LEN 16
+
+
+struct wpa_ie_hdr {
+ u8 elem_id;
+ u8 len;
+ u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
+ u8 version[2]; /* little endian */
+} __packed;
+
+struct rsn_ie_hdr {
+ u8 elem_id; /* WLAN_EID_RSN */
+ u8 len;
+ u8 version[2]; /* little endian */
+} __packed;
+
+struct wme_ac_parameter {
+#if defined(__LITTLE_ENDIAN)
+ /* byte 1 */
+ u8 aifsn:4,
+ acm:1,
+ aci:2,
+ reserved:1;
+
+ /* byte 2 */
+ u8 eCWmin:4,
+ eCWmax:4;
+#elif defined(__BIG_ENDIAN)
+ /* byte 1 */
+ u8 reserved:1,
+ aci:2,
+ acm:1,
+ aifsn:4;
+
+ /* byte 2 */
+ u8 eCWmax:4,
+ eCWmin:4;
+#else
+#error "Please fix <endian.h>"
+#endif
+
+ /* bytes 3 & 4 */
+ u16 txopLimit;
+} __packed;
+
+struct wme_parameter_element {
+ /* required fields for WME version 1 */
+ u8 oui[3];
+ u8 oui_type;
+ u8 oui_subtype;
+ u8 version;
+ u8 acInfo;
+ u8 reserved;
+ struct wme_ac_parameter ac[4];
+
+} __packed;
+
+#define WPA_PUT_LE16(a, val) \
+ do { \
+ (a)[1] = ((u16) (val)) >> 8; \
+ (a)[0] = ((u16) (val)) & 0xff; \
+ } while (0)
+
+#define WPA_PUT_BE32(a, val) \
+ do { \
+ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \
+ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \
+ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \
+ (a)[3] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#define WPA_PUT_LE32(a, val) \
+ do { \
+ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \
+ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \
+ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
+ (a)[0] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *)(a), (val))
+
+/* Action category code */
+enum ieee80211_category {
+ WLAN_CATEGORY_SPECTRUM_MGMT = 0,
+ WLAN_CATEGORY_QOS = 1,
+ WLAN_CATEGORY_DLS = 2,
+ WLAN_CATEGORY_BACK = 3,
+ WLAN_CATEGORY_HT = 7,
+ WLAN_CATEGORY_WMM = 17,
+};
+
+/* SPECTRUM_MGMT action code */
+enum ieee80211_spectrum_mgmt_actioncode {
+ WLAN_ACTION_SPCT_MSR_REQ = 0,
+ WLAN_ACTION_SPCT_MSR_RPRT = 1,
+ WLAN_ACTION_SPCT_TPC_REQ = 2,
+ WLAN_ACTION_SPCT_TPC_RPRT = 3,
+ WLAN_ACTION_SPCT_CHL_SWITCH = 4,
+ WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5,
+};
+
+/* BACK action code */
+enum ieee80211_back_actioncode {
+ WLAN_ACTION_ADDBA_REQ = 0,
+ WLAN_ACTION_ADDBA_RESP = 1,
+ WLAN_ACTION_DELBA = 2,
+};
+
+/* HT features action code */
+enum ieee80211_ht_actioncode {
+ WLAN_ACTION_NOTIFY_CH_WIDTH = 0,
+ WLAN_ACTION_SM_PS = 1,
+ WLAN_ACTION_PSPM = 2,
+ WLAN_ACTION_PCO_PHASE = 3,
+ WLAN_ACTION_MIMO_CSI_MX = 4,
+ WLAN_ACTION_MIMO_NONCP_BF = 5,
+ WLAN_ACTION_MIMP_CP_BF = 6,
+ WLAN_ACTION_ASEL_INDICATES_FB = 7,
+ WLAN_ACTION_HI_INFO_EXCHG = 8,
+};
+
+/* BACK (block-ack) parties */
+enum ieee80211_back_parties {
+ WLAN_BACK_RECIPIENT = 0,
+ WLAN_BACK_INITIATOR = 1,
+ WLAN_BACK_TIMER = 2,
+};
+
+struct ieee80211_mgmt {
+ u16 frame_control;
+ u16 duration;
+ u8 da[6];
+ u8 sa[6];
+ u8 bssid[6];
+ u16 seq_ctrl;
+ union {
+ struct {
+ u16 auth_alg;
+ u16 auth_transaction;
+ u16 status_code;
+ /* possibly followed by Challenge text */
+ u8 variable[0];
+ } __packed auth;
+ struct {
+ u16 reason_code;
+ } __packed deauth;
+ struct {
+ u16 capab_info;
+ u16 listen_interval;
+ /* followed by SSID and Supported rates */
+ u8 variable[0];
+ } __packed assoc_req;
+ struct {
+ u16 capab_info;
+ u16 status_code;
+ u16 aid;
+ /* followed by Supported rates */
+ u8 variable[0];
+ } __packed assoc_resp, reassoc_resp;
+ struct {
+ u16 capab_info;
+ u16 listen_interval;
+ u8 current_ap[6];
+ /* followed by SSID and Supported rates */
+ u8 variable[0];
+ } __packed reassoc_req;
+ struct {
+ u16 reason_code;
+ } __packed disassoc;
+ struct {
+ __le64 timestamp;
+ u16 beacon_int;
+ u16 capab_info;
+ /* followed by some of SSID, Supported rates,
+ * FH Params, DS Params, CF Params, IBSS Params, TIM */
+ u8 variable[0];
+ } __packed beacon;
+ struct {
+ /* only variable items: SSID, Supported rates */
+ u8 variable[0];
+ } __packed probe_req;
+ struct {
+ __le64 timestamp;
+ u16 beacon_int;
+ u16 capab_info;
+ /* followed by some of SSID, Supported rates,
+ * FH Params, DS Params, CF Params, IBSS Params */
+ u8 variable[0];
+ } __packed probe_resp;
+ struct {
+ u8 category;
+ union {
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ u8 status_code;
+ u8 variable[0];
+ } __packed wme_action;
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ u16 capab;
+ u16 timeout;
+ u16 start_seq_num;
+ } __packed addba_req;
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ u16 status;
+ u16 capab;
+ u16 timeout;
+ } __packed addba_resp;
+ struct {
+ u8 action_code;
+ u16 params;
+ u16 reason_code;
+ } __packed delba;
+ structi {
+ u8 action_code;
+ /* capab_info for open and confirm,
+ * reason for close
+ */
+ u16 aux;
+ /* Followed in plink_confirm by status
+ * code, AID and supported rates,
+ * and directly by supported rates in
+ * plink_open and plink_close
+ */
+ u8 variable[0];
+ } __packed plink_action;
+ struct{
+ u8 action_code;
+ u8 variable[0];
+ } __packed mesh_action;
+ } __packed u;
+ } __packed action;
+ } __packed u;
+} __packed;
+
+/* mgmt header + 1 byte category code */
+#define IEEE80211_MIN_ACTION_SIZE \
+ FIELD_OFFSET(struct ieee80211_mgmt, u.action.u)
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/if_ether.h b/drivers/staging/rtl8188eu/include/if_ether.h
new file mode 100644
index 00000000000..db157712a20
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/if_ether.h
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef _LINUX_IF_ETHER_H
+#define _LINUX_IF_ETHER_H
+
+/*
+ * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
+ * and FCS/CRC (frame check sequence).
+ */
+
+#define ETH_ALEN 6 /* Octets in one ethernet addr */
+#define ETH_HLEN 14 /* Total octets in header. */
+#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN 1500 /* Max. octets in payload */
+#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
+
+/*
+ * These are the defined Ethernet Protocol ID's.
+ */
+
+#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
+#define ETH_P_PUP 0x0200 /* Xerox PUP packet */
+#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */
+#define ETH_P_IP 0x0800 /* Internet Protocol packet */
+#define ETH_P_X25 0x0805 /* CCITT X.25 */
+#define ETH_P_ARP 0x0806 /* Address Resolution packet */
+#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet */
+#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */
+#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP */
+#define ETH_P_DEC 0x6000 /* DEC Assigned proto */
+#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */
+#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */
+#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */
+#define ETH_P_LAT 0x6004 /* DEC LAT */
+#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */
+#define ETH_P_CUST 0x6006 /* DEC Customer use */
+#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */
+#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
+#define ETH_P_ATALK 0x809B /* Appletalk DDP */
+#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
+#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
+#define ETH_P_IPX 0x8137 /* IPX over DIX */
+#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
+#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */
+#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */
+#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */
+#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport
+ * over Ethernet
+ */
+
+/*
+ * Non DIX types. Won't clash for 1500 types.
+ */
+
+#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
+#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
+#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
+#define ETH_P_802_2 0x0004 /* 802.2 frames */
+#define ETH_P_SNAP 0x0005 /* Internal only */
+#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */
+#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
+#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
+#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
+#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
+#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
+#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
+#define ETH_P_CONTROL 0x0016 /* Card specific control frames */
+#define ETH_P_IRDA 0x0017 /* Linux-IrDA */
+#define ETH_P_ECONET 0x0018 /* Acorn Econet */
+
+/*
+ * This is an Ethernet frame header.
+ */
+
+struct ethhdr {
+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
+ unsigned char h_source[ETH_ALEN]; /* source ether addr */
+ unsigned short h_proto; /* packet type ID field */
+};
+
+struct _vlan {
+ unsigned short h_vlan_TCI; /* Encap prio and VLAN ID */
+ unsigned short h_vlan_encapsulated_proto;
+};
+
+#define get_vlan_id(pvlan) \
+ ((ntohs((unsigned short)pvlan->h_vlan_TCI)) & 0xfff)
+#define get_vlan_priority(pvlan) \
+ ((ntohs((unsigned short)pvlan->h_vlan_TCI))>>13)
+#define get_vlan_encap_proto(pvlan) \
+ (ntohs((unsigned short)pvlan->h_vlan_encapsulated_proto))
+
+#endif /* _LINUX_IF_ETHER_H */
diff --git a/drivers/staging/rtl8188eu/include/ioctl_cfg80211.h b/drivers/staging/rtl8188eu/include/ioctl_cfg80211.h
new file mode 100644
index 00000000000..037e9a5e5af
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/ioctl_cfg80211.h
@@ -0,0 +1,107 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __IOCTL_CFG80211_H__
+#define __IOCTL_CFG80211_H__
+
+struct rtw_wdev_invit_info {
+ u8 token;
+ u8 flags;
+ u8 status;
+ u8 req_op_ch;
+ u8 rsp_op_ch;
+};
+
+#define rtw_wdev_invit_info_init(invit_info) \
+ do { \
+ (invit_info)->token = 0; \
+ (invit_info)->flags = 0x00; \
+ (invit_info)->status = 0xff; \
+ (invit_info)->req_op_ch = 0; \
+ (invit_info)->rsp_op_ch = 0; \
+ } while (0)
+
+struct rtw_wdev_priv {
+ struct wireless_dev *rtw_wdev;
+
+ struct adapter *padapter;
+
+ struct cfg80211_scan_request *scan_request;
+ spinlock_t scan_req_lock;
+
+ struct net_device *pmon_ndev;/* for monitor interface */
+ char ifname_mon[IFNAMSIZ + 1]; /* name of monitor interface */
+
+ u8 p2p_enabled;
+
+ u8 provdisc_req_issued;
+
+ struct rtw_wdev_invit_info invit_info;
+
+ u8 bandroid_scan;
+ bool block;
+ bool power_mgmt;
+};
+
+#define wdev_to_priv(w) ((struct rtw_wdev_priv *)(wdev_priv(w)))
+
+#define wiphy_to_wdev(x) \
+((struct wireless_dev *)(((struct rtw_wdev_priv *)wiphy_priv(x))->rtw_wdev))
+
+int rtw_wdev_alloc(struct adapter *padapter, struct device *dev);
+void rtw_wdev_free(struct wireless_dev *wdev);
+void rtw_wdev_unregister(struct wireless_dev *wdev);
+
+void rtw_cfg80211_init_wiphy(struct adapter *padapter);
+
+void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter);
+
+void rtw_cfg80211_indicate_connect(struct adapter *padapter);
+void rtw_cfg80211_indicate_disconnect(struct adapter *padapter);
+void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv,
+ bool aborted);
+
+#ifdef CONFIG_88EU_AP_MODE
+void rtw_cfg80211_indicate_sta_assoc(struct adapter *padapter,
+ u8 *pmgmt_frame, uint frame_len);
+void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter,
+ unsigned char *da,
+ unsigned short reason);
+#endif /* CONFIG_88EU_AP_MODE */
+
+void rtw_cfg80211_issue_p2p_provision_request(struct adapter *padapter,
+ const u8 *buf, size_t len);
+void rtw_cfg80211_rx_p2p_action_public(struct adapter *padapter,
+ u8 *pmgmt_frame, uint frame_len);
+void rtw_cfg80211_rx_action_p2p(struct adapter *padapter, u8 *pmgmt_frame,
+ uint frame_len);
+void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame,
+ uint frame_len, const char *msg);
+
+int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net,
+ char *buf, int len, int type);
+
+bool rtw_cfg80211_pwr_mgmt(struct adapter *adapter);
+
+#define rtw_cfg80211_rx_mgmt(dev, freq, sig_dbm, buf, len, gfp) \
+ cfg80211_rx_mgmt(dev, freq, sig_dbm, buf, len, gfp)
+#define rtw_cfg80211_send_rx_assoc(dev, bss, buf, len) \
+ cfg80211_send_rx_assoc(dev, bss, buf, len)
+
+#endif /* __IOCTL_CFG80211_H__ */
diff --git a/drivers/staging/rtl8188eu/include/ip.h b/drivers/staging/rtl8188eu/include/ip.h
new file mode 100644
index 00000000000..9fdac6d42d1
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/ip.h
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _LINUX_IP_H
+#define _LINUX_IP_H
+
+/* SOL_IP socket options */
+
+#define IPTOS_TOS_MASK 0x1E
+#define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK)
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#define IPTOS_MINCOST 0x02
+
+#define IPTOS_PREC_MASK 0xE0
+#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK)
+#define IPTOS_PREC_NETCONTROL 0xe0
+#define IPTOS_PREC_INTERNETCONTROL 0xc0
+#define IPTOS_PREC_CRITIC_ECP 0xa0
+#define IPTOS_PREC_FLASHOVERRIDE 0x80
+#define IPTOS_PREC_FLASH 0x60
+#define IPTOS_PREC_IMMEDIATE 0x40
+#define IPTOS_PREC_PRIORITY 0x20
+#define IPTOS_PREC_ROUTINE 0x00
+
+
+/* IP options */
+#define IPOPT_COPY 0x80
+#define IPOPT_CLASS_MASK 0x60
+#define IPOPT_NUMBER_MASK 0x1f
+
+#define IPOPT_COPIED(o) ((o)&IPOPT_COPY)
+#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK)
+#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK)
+
+#define IPOPT_CONTROL 0x00
+#define IPOPT_RESERVED1 0x20
+#define IPOPT_MEASUREMENT 0x40
+#define IPOPT_RESERVED2 0x60
+
+#define IPOPT_END (0 | IPOPT_CONTROL)
+#define IPOPT_NOOP (1 | IPOPT_CONTROL)
+#define IPOPT_SEC (2 | IPOPT_CONTROL | IPOPT_COPY)
+#define IPOPT_LSRR (3 | IPOPT_CONTROL | IPOPT_COPY)
+#define IPOPT_TIMESTAMP (4 | IPOPT_MEASUREMENT)
+#define IPOPT_RR (7 | IPOPT_CONTROL)
+#define IPOPT_SID (8 | IPOPT_CONTROL | IPOPT_COPY)
+#define IPOPT_SSRR (9 | IPOPT_CONTROL | IPOPT_COPY)
+#define IPOPT_RA (20 | IPOPT_CONTROL | IPOPT_COPY)
+
+#define IPVERSION 4
+#define MAXTTL 255
+#define IPDEFTTL 64
+#define IPOPT_OPTVAL 0
+#define IPOPT_OLEN 1
+#define IPOPT_OFFSET 2
+#define IPOPT_MINOFF 4
+#define MAX_IPOPTLEN 40
+#define IPOPT_NOP IPOPT_NOOP
+#define IPOPT_EOL IPOPT_END
+#define IPOPT_TS IPOPT_TIMESTAMP
+
+#define IPOPT_TS_TSONLY 0 /* timestamps only */
+#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
+#define IPOPT_TS_PRESPEC 3 /* specified modules only */
+
+struct ip_options {
+ __u32 faddr; /* Saved first hop address */
+ unsigned char optlen;
+ unsigned char srr;
+ unsigned char rr;
+ unsigned char ts;
+ unsigned char is_setbyuser:1, /* Set by setsockopt? */
+ is_data:1, /* Options in __data, rather than skb*/
+ is_strictroute:1,/* Strict source route */
+ srr_is_hit:1, /* Packet destn addr was ours */
+ is_changed:1, /* IP checksum more not valid */
+ rr_needaddr:1, /* Need to record addr of out dev*/
+ ts_needtime:1, /* Need to record timestamp */
+ ts_needaddr:1; /* Need to record addr of out dev */
+ unsigned char router_alert;
+ unsigned char __pad1;
+ unsigned char __pad2;
+ unsigned char __data[0];
+};
+
+#define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
+
+struct iphdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 ihl:4,
+ version:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 version:4,
+ ihl:4;
+#endif
+ __u8 tos;
+ __u16 tot_len;
+ __u16 id;
+ __u16 frag_off;
+ __u8 ttl;
+ __u8 protocol;
+ __u16 check;
+ __u32 saddr;
+ __u32 daddr;
+ /*The options start here. */
+};
+
+#endif /* _LINUX_IP_H */
diff --git a/drivers/staging/rtl8188eu/include/mlme_osdep.h b/drivers/staging/rtl8188eu/include/mlme_osdep.h
new file mode 100644
index 00000000000..ae1722c6703
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/mlme_osdep.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __MLME_OSDEP_H_
+#define __MLME_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+void rtw_init_mlme_timer(struct adapter *padapter);
+void rtw_os_indicate_disconnect(struct adapter *adapter);
+void rtw_os_indicate_connect(struct adapter *adapter);
+void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted);
+void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie);
+
+void rtw_reset_securitypriv(struct adapter *adapter);
+void indicate_wx_scan_complete_event(struct adapter *padapter);
+
+#endif /* _MLME_OSDEP_H_ */
diff --git a/drivers/staging/rtl8188eu/include/mp_custom_oid.h b/drivers/staging/rtl8188eu/include/mp_custom_oid.h
new file mode 100644
index 00000000000..6fa52cf99c4
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/mp_custom_oid.h
@@ -0,0 +1,352 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __CUSTOM_OID_H
+#define __CUSTOM_OID_H
+
+/* by Owen */
+/* 0xFF818000 - 0xFF81802F RTL8180 Mass Production Kit */
+/* 0xFF818500 - 0xFF81850F RTL8185 Setup Utility */
+/* 0xFF818580 - 0xFF81858F RTL8185 Phy Status Utility */
+
+/* */
+
+/* by Owen for Production Kit */
+/* For Production Kit with Agilent Equipments */
+/* in order to make our custom oids hopefully somewhat unique */
+/* we will use 0xFF (indicating implementation specific OID) */
+/* 81(first byte of non zero Realtek unique identifier) */
+/* 80 (second byte of non zero Realtek unique identifier) */
+/* XX (the custom OID number - providing 255 possible custom oids) */
+
+#define OID_RT_PRO_RESET_DUT 0xFF818000
+#define OID_RT_PRO_SET_DATA_RATE 0xFF818001
+#define OID_RT_PRO_START_TEST 0xFF818002
+#define OID_RT_PRO_STOP_TEST 0xFF818003
+#define OID_RT_PRO_SET_PREAMBLE 0xFF818004
+#define OID_RT_PRO_SET_SCRAMBLER 0xFF818005
+#define OID_RT_PRO_SET_FILTER_BB 0xFF818006
+#define OID_RT_PRO_SET_MANUAL_DIVERSITY_BB 0xFF818007
+#define OID_RT_PRO_SET_CHANNEL_DIRECT_CALL 0xFF818008
+#define OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL 0xFF818009
+#define OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL 0xFF81800A
+
+#define OID_RT_PRO_SET_TX_ANTENNA_BB 0xFF81800D
+#define OID_RT_PRO_SET_ANTENNA_BB 0xFF81800E
+#define OID_RT_PRO_SET_CR_SCRAMBLER 0xFF81800F
+#define OID_RT_PRO_SET_CR_NEW_FILTER 0xFF818010
+#define OID_RT_PRO_SET_TX_POWER_CONTROL 0xFF818011
+#define OID_RT_PRO_SET_CR_TX_CONFIG 0xFF818012
+#define OID_RT_PRO_GET_TX_POWER_CONTROL 0xFF818013
+#define OID_RT_PRO_GET_CR_SIGNAL_QUALITY 0xFF818014
+#define OID_RT_PRO_SET_CR_SETPOINT 0xFF818015
+#define OID_RT_PRO_SET_INTEGRATOR 0xFF818016
+#define OID_RT_PRO_SET_SIGNAL_QUALITY 0xFF818017
+#define OID_RT_PRO_GET_INTEGRATOR 0xFF818018
+#define OID_RT_PRO_GET_SIGNAL_QUALITY 0xFF818019
+#define OID_RT_PRO_QUERY_EEPROM_TYPE 0xFF81801A
+#define OID_RT_PRO_WRITE_MAC_ADDRESS 0xFF81801B
+#define OID_RT_PRO_READ_MAC_ADDRESS 0xFF81801C
+#define OID_RT_PRO_WRITE_CIS_DATA 0xFF81801D
+#define OID_RT_PRO_READ_CIS_DATA 0xFF81801E
+#define OID_RT_PRO_WRITE_POWER_CONTROL 0xFF81801F
+#define OID_RT_PRO_READ_POWER_CONTROL 0xFF818020
+#define OID_RT_PRO_WRITE_EEPROM 0xFF818021
+#define OID_RT_PRO_READ_EEPROM 0xFF818022
+#define OID_RT_PRO_RESET_TX_PACKET_SENT 0xFF818023
+#define OID_RT_PRO_QUERY_TX_PACKET_SENT 0xFF818024
+#define OID_RT_PRO_RESET_RX_PACKET_RECEIVED 0xFF818025
+#define OID_RT_PRO_QUERY_RX_PACKET_RECEIVED 0xFF818026
+#define OID_RT_PRO_QUERY_RX_PACKET_CRC32_ERROR 0xFF818027
+#define OID_RT_PRO_QUERY_CURRENT_ADDRESS 0xFF818028
+#define OID_RT_PRO_QUERY_PERMANENT_ADDRESS 0xFF818029
+#define OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS 0xFF81802A
+#define OID_RT_PRO_RECEIVE_PACKET 0xFF81802C
+/* added by Owen on 04/08/03 for Cameo's request */
+#define OID_RT_PRO_WRITE_EEPROM_BYTE 0xFF81802D
+#define OID_RT_PRO_READ_EEPROM_BYTE 0xFF81802E
+#define OID_RT_PRO_SET_MODULATION 0xFF81802F
+/* */
+
+/* Sean */
+#define OID_RT_DRIVER_OPTION 0xFF818080
+#define OID_RT_RF_OFF 0xFF818081
+#define OID_RT_AUTH_STATUS 0xFF818082
+
+/* */
+#define OID_RT_PRO_SET_CONTINUOUS_TX 0xFF81800B
+#define OID_RT_PRO_SET_SINGLE_CARRIER_TX 0xFF81800C
+#define OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX 0xFF81802B
+#define OID_RT_PRO_SET_SINGLE_TONE_TX 0xFF818043
+/* */
+
+
+/* by Owen for RTL8185 Phy Status Report Utility */
+#define OID_RT_UTILITY_false_ALARM_COUNTERS 0xFF818580
+#define OID_RT_UTILITY_SELECT_DEBUG_MODE 0xFF818581
+#define OID_RT_UTILITY_SELECT_SUBCARRIER_NUMBER 0xFF818582
+#define OID_RT_UTILITY_GET_RSSI_STATUS 0xFF818583
+#define OID_RT_UTILITY_GET_FRAME_DETECTION_STATUS 0xFF818584
+#define OID_RT_UTILITY_GET_AGC_AND_FREQUENCY_OFFSET_ESTIMATION_STATUS \
+ 0xFF818585
+#define OID_RT_UTILITY_GET_CHANNEL_ESTIMATION_STATUS 0xFF818586
+/* */
+
+/* by Owen on 03/09/19-03/09/22 for RTL8185 */
+#define OID_RT_WIRELESS_MODE 0xFF818500
+#define OID_RT_SUPPORTED_RATES 0xFF818501
+#define OID_RT_DESIRED_RATES 0xFF818502
+#define OID_RT_WIRELESS_MODE_STARTING_ADHOC 0xFF818503
+/* */
+
+#define OID_RT_GET_CONNECT_STATE 0xFF030001
+#define OID_RT_RESCAN 0xFF030002
+#define OID_RT_SET_KEY_LENGTH 0xFF030003
+#define OID_RT_SET_DEFAULT_KEY_ID 0xFF030004
+
+#define OID_RT_SET_CHANNEL 0xFF010182
+#define OID_RT_SET_SNIFFER_MODE 0xFF010183
+#define OID_RT_GET_SIGNAL_QUALITY 0xFF010184
+#define OID_RT_GET_SMALL_PACKET_CRC 0xFF010185
+#define OID_RT_GET_MIDDLE_PACKET_CRC 0xFF010186
+#define OID_RT_GET_LARGE_PACKET_CRC 0xFF010187
+#define OID_RT_GET_TX_RETRY 0xFF010188
+#define OID_RT_GET_RX_RETRY 0xFF010189
+#define OID_RT_PRO_SET_FW_DIG_STATE 0xFF01018A/* S */
+#define OID_RT_PRO_SET_FW_RA_STATE 0xFF01018B/* S */
+
+#define OID_RT_GET_RX_TOTAL_PACKET 0xFF010190
+#define OID_RT_GET_TX_BEACON_OK 0xFF010191
+#define OID_RT_GET_TX_BEACON_ERR 0xFF010192
+#define OID_RT_GET_RX_ICV_ERR 0xFF010193
+#define OID_RT_SET_ENCRYPTION_ALGORITHM 0xFF010194
+#define OID_RT_SET_NO_AUTO_RESCAN 0xFF010195
+#define OID_RT_GET_PREAMBLE_MODE 0xFF010196
+#define OID_RT_GET_DRIVER_UP_DELTA_TIME 0xFF010197
+#define OID_RT_GET_AP_IP 0xFF010198
+#define OID_RT_GET_CHANNELPLAN 0xFF010199
+#define OID_RT_SET_PREAMBLE_MODE 0xFF01019A
+#define OID_RT_SET_BCN_INTVL 0xFF01019B
+#define OID_RT_GET_RF_VENDER 0xFF01019C
+#define OID_RT_DEDICATE_PROBE 0xFF01019D
+#define OID_RT_PRO_RX_FILTER_PATTERN 0xFF01019E
+
+#define OID_RT_GET_DCST_CURRENT_THRESHOLD 0xFF01019F
+
+#define OID_RT_GET_CCA_ERR 0xFF0101A0
+#define OID_RT_GET_CCA_UPGRADE_THRESHOLD 0xFF0101A1
+#define OID_RT_GET_CCA_FALLBACK_THRESHOLD 0xFF0101A2
+
+#define OID_RT_GET_CCA_UPGRADE_EVALUATE_TIMES 0xFF0101A3
+#define OID_RT_GET_CCA_FALLBACK_EVALUATE_TIMES 0xFF0101A4
+
+/* by Owen on 03/31/03 for Cameo's request */
+#define OID_RT_SET_RATE_ADAPTIVE 0xFF0101A5
+/* */
+#define OID_RT_GET_DCST_EVALUATE_PERIOD 0xFF0101A5
+#define OID_RT_GET_DCST_TIME_UNIT_INDEX 0xFF0101A6
+#define OID_RT_GET_TOTAL_TX_BYTES 0xFF0101A7
+#define OID_RT_GET_TOTAL_RX_BYTES 0xFF0101A8
+#define OID_RT_CURRENT_TX_POWER_LEVEL 0xFF0101A9
+#define OID_RT_GET_ENC_KEY_MISMATCH_COUNT 0xFF0101AA
+#define OID_RT_GET_ENC_KEY_MATCH_COUNT 0xFF0101AB
+#define OID_RT_GET_CHANNEL 0xFF0101AC
+
+#define OID_RT_SET_CHANNELPLAN 0xFF0101AD
+#define OID_RT_GET_HARDWARE_RADIO_OFF 0xFF0101AE
+#define OID_RT_CHANNELPLAN_BY_COUNTRY 0xFF0101AF
+#define OID_RT_SCAN_AVAILABLE_BSSID 0xFF0101B0
+#define OID_RT_GET_HARDWARE_VERSION 0xFF0101B1
+#define OID_RT_GET_IS_ROAMING 0xFF0101B2
+#define OID_RT_GET_IS_PRIVACY 0xFF0101B3
+#define OID_RT_GET_KEY_MISMATCH 0xFF0101B4
+#define OID_RT_SET_RSSI_ROAM_TRAFFIC_TH 0xFF0101B5
+#define OID_RT_SET_RSSI_ROAM_SIGNAL_TH 0xFF0101B6
+#define OID_RT_RESET_LOG 0xFF0101B7
+#define OID_RT_GET_LOG 0xFF0101B8
+#define OID_RT_SET_INDICATE_HIDDEN_AP 0xFF0101B9
+#define OID_RT_GET_HEADER_FAIL 0xFF0101BA
+#define OID_RT_SUPPORTED_WIRELESS_MODE 0xFF0101BB
+#define OID_RT_GET_CHANNEL_LIST 0xFF0101BC
+#define OID_RT_GET_SCAN_IN_PROGRESS 0xFF0101BD
+#define OID_RT_GET_TX_INFO 0xFF0101BE
+#define OID_RT_RF_READ_WRITE_OFFSET 0xFF0101BF
+#define OID_RT_RF_READ_WRITE 0xFF0101C0
+
+/* For Netgear request. 2005.01.13, by rcnjko. */
+#define OID_RT_FORCED_DATA_RATE 0xFF0101C1
+#define OID_RT_WIRELESS_MODE_FOR_SCAN_LIST 0xFF0101C2
+/* For Netgear request. 2005.02.17, by rcnjko. */
+#define OID_RT_GET_BSS_WIRELESS_MODE 0xFF0101C3
+/* For AZ project. 2005.06.27, by rcnjko. */
+#define OID_RT_SCAN_WITH_MAGIC_PACKET 0xFF0101C4
+
+/* Vincent 8185MP */
+#define OID_RT_PRO_RX_FILTER 0xFF0111C0
+
+#define OID_CE_USB_WRITE_REGISTRY 0xFF0111C1
+#define OID_CE_USB_READ_REGISTRY 0xFF0111C2
+
+#define OID_RT_PRO_SET_INITIAL_GA 0xFF0111C3
+#define OID_RT_PRO_SET_BB_RF_STANDBY_MODE 0xFF0111C4
+#define OID_RT_PRO_SET_BB_RF_SHUTDOWN_MODE 0xFF0111C5
+#define OID_RT_PRO_SET_TX_CHARGE_PUMP 0xFF0111C6
+#define OID_RT_PRO_SET_RX_CHARGE_PUMP 0xFF0111C7
+#define OID_RT_PRO_RF_WRITE_REGISTRY 0xFF0111C8
+#define OID_RT_PRO_RF_READ_REGISTRY 0xFF0111C9
+#define OID_RT_PRO_QUERY_RF_TYPE 0xFF0111CA
+
+/* AP OID */
+#define OID_RT_AP_GET_ASSOCIATED_STATION_LIST 0xFF010300
+#define OID_RT_AP_GET_CURRENT_TIME_STAMP 0xFF010301
+#define OID_RT_AP_SWITCH_INTO_AP_MODE 0xFF010302
+#define OID_RT_AP_SET_DTIM_PERIOD 0xFF010303
+/* Determine if driver supports AP mode. */
+#define OID_RT_AP_SUPPORTED 0xFF010304
+/* Set WPA-PSK passphrase into authenticator. */
+#define OID_RT_AP_SET_PASSPHRASE 0xFF010305
+
+/* 8187MP. 2004.09.06, by rcnjko. */
+#define OID_RT_PRO8187_WI_POLL 0xFF818780
+#define OID_RT_PRO_WRITE_BB_REG 0xFF818781
+#define OID_RT_PRO_READ_BB_REG 0xFF818782
+#define OID_RT_PRO_WRITE_RF_REG 0xFF818783
+#define OID_RT_PRO_READ_RF_REG 0xFF818784
+
+/* Meeting House. added by Annie, 2005-07-20. */
+#define OID_RT_MH_VENDER_ID 0xFFEDC100
+
+/* 8711 MP OID added 20051230. */
+#define OID_RT_PRO8711_JOIN_BSS 0xFF871100/* S */
+
+#define OID_RT_PRO_READ_REGISTER 0xFF871101 /* Q */
+#define OID_RT_PRO_WRITE_REGISTER 0xFF871102 /* S */
+
+#define OID_RT_PRO_BURST_READ_REGISTER 0xFF871103 /* Q */
+#define OID_RT_PRO_BURST_WRITE_REGISTER 0xFF871104 /* S */
+
+#define OID_RT_PRO_WRITE_TXCMD 0xFF871105 /* S */
+
+#define OID_RT_PRO_READ16_EEPROM 0xFF871106 /* Q */
+#define OID_RT_PRO_WRITE16_EEPROM 0xFF871107 /* S */
+
+#define OID_RT_PRO_H2C_SET_COMMAND 0xFF871108 /* S */
+#define OID_RT_PRO_H2C_QUERY_RESULT 0xFF871109 /* Q */
+
+#define OID_RT_PRO8711_WI_POLL 0xFF87110A /* Q */
+#define OID_RT_PRO8711_PKT_LOSS 0xFF87110B /* Q */
+#define OID_RT_RD_ATTRIB_MEM 0xFF87110C/* Q */
+#define OID_RT_WR_ATTRIB_MEM 0xFF87110D/* S */
+
+
+/* Method 2 for H2C/C2H */
+#define OID_RT_PRO_H2C_CMD_MODE 0xFF871110 /* S */
+#define OID_RT_PRO_H2C_CMD_RSP_MODE 0xFF871111 /* Q */
+#define OID_RT_PRO_H2C_CMD_EVENT_MODE 0xFF871112 /* S */
+#define OID_RT_PRO_WAIT_C2H_EVENT 0xFF871113 /* Q */
+#define OID_RT_PRO_RW_ACCESS_PROTOCOL_TEST 0xFF871114/* Q */
+
+#define OID_RT_PRO_SCSI_ACCESS_TEST 0xFF871115 /* Q, S */
+
+#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_OUT 0xFF871116 /* S */
+#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_IN 0xFF871117 /* Q,S */
+#define OID_RT_RRO_RX_PKT_VIA_IOCTRL 0xFF871118 /* Q */
+#define OID_RT_RRO_RX_PKTARRAY_VIA_IOCTRL 0xFF871119 /* Q */
+
+#define OID_RT_RPO_SET_PWRMGT_TEST 0xFF87111A /* S */
+#define OID_RT_PRO_QRY_PWRMGT_TEST 0XFF87111B /* Q */
+#define OID_RT_RPO_ASYNC_RWIO_TEST 0xFF87111C /* S */
+#define OID_RT_RPO_ASYNC_RWIO_POLL 0xFF87111D /* Q */
+#define OID_RT_PRO_SET_RF_INTFS 0xFF87111E /* S */
+#define OID_RT_POLL_RX_STATUS 0xFF87111F /* Q */
+
+#define OID_RT_PRO_CFG_DEBUG_MESSAGE 0xFF871120 /* Q,S */
+#define OID_RT_PRO_SET_DATA_RATE_EX 0xFF871121/* S */
+#define OID_RT_PRO_SET_BASIC_RATE 0xFF871122/* S */
+#define OID_RT_PRO_READ_TSSI 0xFF871123/* S */
+#define OID_RT_PRO_SET_POWER_TRACKING 0xFF871124/* S */
+
+
+#define OID_RT_PRO_QRY_PWRSTATE 0xFF871150 /* Q */
+#define OID_RT_PRO_SET_PWRSTATE 0xFF871151 /* S */
+
+/* Method 2 , using workitem */
+#define OID_RT_SET_READ_REG 0xFF871181 /* S */
+#define OID_RT_SET_WRITE_REG 0xFF871182 /* S */
+#define OID_RT_SET_BURST_READ_REG 0xFF871183 /* S */
+#define OID_RT_SET_BURST_WRITE_REG 0xFF871184 /* S */
+#define OID_RT_SET_WRITE_TXCMD 0xFF871185 /* S */
+#define OID_RT_SET_READ16_EEPROM 0xFF871186 /* S */
+#define OID_RT_SET_WRITE16_EEPROM 0xFF871187 /* S */
+#define OID_RT_QRY_POLL_WKITEM 0xFF871188 /* Q */
+
+/* For SDIO INTERFACE only */
+#define OID_RT_PRO_SYNCPAGERW_SRAM 0xFF8711A0 /* Q, S */
+#define OID_RT_PRO_871X_DRV_EXT 0xFF8711A1
+
+/* For USB INTERFACE only */
+#define OID_RT_PRO_USB_VENDOR_REQ 0xFF8711B0 /* Q, S */
+#define OID_RT_PRO_SCSI_AUTO_TEST 0xFF8711B1 /* S */
+#define OID_RT_PRO_USB_MAC_AC_FIFO_WRITE 0xFF8711B2 /* S */
+#define OID_RT_PRO_USB_MAC_RX_FIFO_READ 0xFF8711B3 /* Q */
+#define OID_RT_PRO_USB_MAC_RX_FIFO_POLLING 0xFF8711B4 /* Q */
+
+#define OID_RT_PRO_H2C_SET_RATE_TABLE 0xFF8711FB /* S */
+#define OID_RT_PRO_H2C_GET_RATE_TABLE 0xFF8711FC /* S */
+#define OID_RT_PRO_H2C_C2H_LBK_TEST 0xFF8711FE
+
+#define OID_RT_PRO_ENCRYPTION_CTRL 0xFF871200 /* Q, S */
+#define OID_RT_PRO_ADD_STA_INFO 0xFF871201 /* S */
+#define OID_RT_PRO_DELE_STA_INFO 0xFF871202 /* S */
+#define OID_RT_PRO_QUERY_DR_VARIABLE 0xFF871203 /* Q */
+
+#define OID_RT_PRO_RX_PACKET_TYPE 0xFF871204 /* Q, S */
+
+#define OID_RT_PRO_READ_EFUSE 0xFF871205 /* Q */
+#define OID_RT_PRO_WRITE_EFUSE 0xFF871206 /* S */
+#define OID_RT_PRO_RW_EFUSE_PGPKT 0xFF871207 /* Q, S */
+#define OID_RT_GET_EFUSE_CURRENT_SIZE 0xFF871208 /* Q */
+
+#define OID_RT_SET_BANDWIDTH 0xFF871209 /* S */
+#define OID_RT_SET_CRYSTAL_CAP 0xFF87120A /* S */
+
+#define OID_RT_SET_RX_PACKET_TYPE 0xFF87120B /* S */
+
+#define OID_RT_GET_EFUSE_MAX_SIZE 0xFF87120C /* Q */
+
+#define OID_RT_PRO_SET_TX_AGC_OFFSET 0xFF87120D /* S */
+
+#define OID_RT_PRO_SET_PKT_TEST_MODE 0xFF87120E /* S */
+
+#define OID_RT_PRO_FOR_EVM_TEST_SETTING 0xFF87120F /* S */
+
+#define OID_RT_PRO_GET_THERMAL_METER 0xFF871210 /* Q */
+
+#define OID_RT_RESET_PHY_RX_PACKET_COUNT 0xFF871211 /* S */
+#define OID_RT_GET_PHY_RX_PACKET_RECEIVED 0xFF871212 /* Q */
+#define OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR 0xFF871213 /* Q */
+
+#define OID_RT_SET_POWER_DOWN 0xFF871214 /* S */
+
+#define OID_RT_GET_POWER_MODE 0xFF871215 /* Q */
+
+#define OID_RT_PRO_EFUSE 0xFF871216 /* Q, S */
+#define OID_RT_PRO_EFUSE_MAP 0xFF871217 /* Q, S */
+
+#endif /* ifndef __CUSTOM_OID_H */
diff --git a/drivers/staging/rtl8188eu/include/nic_spec.h b/drivers/staging/rtl8188eu/include/nic_spec.h
new file mode 100644
index 00000000000..d42244788ca
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/nic_spec.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+
+#ifndef __NIC_SPEC_H__
+#define __NIC_SPEC_H__
+
+#define RTL8711_MCTRL_ (0x20000)
+#define RTL8711_UART_ (0x30000)
+#define RTL8711_TIMER_ (0x40000)
+#define RTL8711_FINT_ (0x50000)
+#define RTL8711_HINT_ (0x50000)
+#define RTL8711_GPIO_ (0x60000)
+#define RTL8711_WLANCTRL_ (0x200000)
+#define RTL8711_WLANFF_ (0xe00000)
+#define RTL8711_HCICTRL_ (0x600000)
+#define RTL8711_SYSCFG_ (0x620000)
+#define RTL8711_SYSCTRL_ (0x620000)
+#define RTL8711_MCCTRL_ (0x020000)
+
+
+#include <rtl8711_regdef.h>
+
+#include <rtl8711_bitdef.h>
+
+
+#endif /* __RTL8711_SPEC_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm.h b/drivers/staging/rtl8188eu/include/odm.h
new file mode 100644
index 00000000000..2bfe7284192
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm.h
@@ -0,0 +1,1198 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+
+#ifndef __HALDMOUTSRC_H__
+#define __HALDMOUTSRC_H__
+
+/* Definition */
+/* Define all team support ability. */
+
+/* Define for all teams. Please Define the constant in your precomp header. */
+
+/* define DM_ODM_SUPPORT_AP 0 */
+/* define DM_ODM_SUPPORT_ADSL 0 */
+/* define DM_ODM_SUPPORT_CE 0 */
+/* define DM_ODM_SUPPORT_MP 1 */
+
+/* Define ODM SW team support flag. */
+
+/* Antenna Switch Relative Definition. */
+
+/* Add new function SwAntDivCheck8192C(). */
+/* This is the main function of Antenna diversity function before link. */
+/* Mainly, it just retains last scan result and scan again. */
+/* After that, it compares the scan result to see which one gets better
+ * RSSI. It selects antenna with better receiving power and returns better
+ * scan result. */
+
+#define TP_MODE 0
+#define RSSI_MODE 1
+#define TRAFFIC_LOW 0
+#define TRAFFIC_HIGH 1
+
+/* 3 Tx Power Tracking */
+/* 3============================================================ */
+#define DPK_DELTA_MAPPING_NUM 13
+#define index_mapping_HP_NUM 15
+
+
+/* */
+/* 3 PSD Handler */
+/* 3============================================================ */
+
+#define AFH_PSD 1 /* 0:normal PSD scan, 1: only do 20 pts PSD */
+#define MODE_40M 0 /* 0:20M, 1:40M */
+#define PSD_TH2 3
+#define PSD_CHM 20 /* Minimum channel number for BT AFH */
+#define SIR_STEP_SIZE 3
+#define Smooth_Size_1 5
+#define Smooth_TH_1 3
+#define Smooth_Size_2 10
+#define Smooth_TH_2 4
+#define Smooth_Size_3 20
+#define Smooth_TH_3 4
+#define Smooth_Step_Size 5
+#define Adaptive_SIR 1
+#define PSD_RESCAN 4
+#define PSD_SCAN_INTERVAL 700 /* ms */
+
+/* 8723A High Power IGI Setting */
+#define DM_DIG_HIGH_PWR_IGI_LOWER_BOUND 0x22
+#define DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND 0x28
+#define DM_DIG_HIGH_PWR_THRESHOLD 0x3a
+
+/* LPS define */
+#define DM_DIG_FA_TH0_LPS 4 /* 4 in lps */
+#define DM_DIG_FA_TH1_LPS 15 /* 15 lps */
+#define DM_DIG_FA_TH2_LPS 30 /* 30 lps */
+#define RSSI_OFFSET_DIG 0x05;
+
+/* ANT Test */
+#define ANTTESTALL 0x00 /* Ant A or B will be Testing */
+#define ANTTESTA 0x01 /* Ant A will be Testing */
+#define ANTTESTB 0x02 /* Ant B will be testing */
+
+/* structure and define */
+
+/* Add for AP/ADSLpseudo DM structuer requirement. */
+/* We need to remove to other position??? */
+struct rtl8192cd_priv {
+ u8 temp;
+};
+
+struct rtw_dig {
+ u8 Dig_Enable_Flag;
+ u8 Dig_Ext_Port_Stage;
+
+ int RssiLowThresh;
+ int RssiHighThresh;
+
+ u32 FALowThresh;
+ u32 FAHighThresh;
+
+ u8 CurSTAConnectState;
+ u8 PreSTAConnectState;
+ u8 CurMultiSTAConnectState;
+
+ u8 PreIGValue;
+ u8 CurIGValue;
+ u8 BackupIGValue;
+
+ s8 BackoffVal;
+ s8 BackoffVal_range_max;
+ s8 BackoffVal_range_min;
+ u8 rx_gain_range_max;
+ u8 rx_gain_range_min;
+ u8 Rssi_val_min;
+
+ u8 PreCCK_CCAThres;
+ u8 CurCCK_CCAThres;
+ u8 PreCCKPDState;
+ u8 CurCCKPDState;
+
+ u8 LargeFAHit;
+ u8 ForbiddenIGI;
+ u32 Recover_cnt;
+
+ u8 DIG_Dynamic_MIN_0;
+ u8 DIG_Dynamic_MIN_1;
+ bool bMediaConnect_0;
+ bool bMediaConnect_1;
+
+ u32 AntDiv_RSSI_max;
+ u32 RSSI_max;
+};
+
+struct rtl_ps {
+ u8 PreCCAState;
+ u8 CurCCAState;
+
+ u8 PreRFState;
+ u8 CurRFState;
+
+ int Rssi_val_min;
+
+ u8 initialize;
+ u32 Reg874,RegC70,Reg85C,RegA74;
+
+};
+
+struct false_alarm_stats {
+ u32 Cnt_Parity_Fail;
+ u32 Cnt_Rate_Illegal;
+ u32 Cnt_Crc8_fail;
+ u32 Cnt_Mcs_fail;
+ u32 Cnt_Ofdm_fail;
+ u32 Cnt_Cck_fail;
+ u32 Cnt_all;
+ u32 Cnt_Fast_Fsync;
+ u32 Cnt_SB_Search_fail;
+ u32 Cnt_OFDM_CCA;
+ u32 Cnt_CCK_CCA;
+ u32 Cnt_CCA_all;
+ u32 Cnt_BW_USC; /* Gary */
+ u32 Cnt_BW_LSC; /* Gary */
+};
+
+struct dyn_primary_cca {
+ u8 PriCCA_flag;
+ u8 intf_flag;
+ u8 intf_type;
+ u8 DupRTS_flag;
+ u8 Monitor_flag;
+};
+
+struct rx_hpc {
+ u8 RXHP_flag;
+ u8 PSD_func_trigger;
+ u8 PSD_bitmap_RXHP[80];
+ u8 Pre_IGI;
+ u8 Cur_IGI;
+ u8 Pre_pw_th;
+ u8 Cur_pw_th;
+ bool First_time_enter;
+ bool RXHP_enable;
+ u8 TP_Mode;
+ struct timer_list PSDTimer;
+};
+
+#define ASSOCIATE_ENTRY_NUM 32 /* Max size of AsocEntry[]. */
+#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM
+
+/* This indicates two different steps. */
+/* In SWAW_STEP_PEAK, driver needs to switch antenna and listen to
+ * the signal on the air. */
+/* In SWAW_STEP_DETERMINE, driver just compares the signal captured in
+ * SWAW_STEP_PEAK with original RSSI to determine if it is necessary to
+ * switch antenna. */
+
+#define SWAW_STEP_PEAK 0
+#define SWAW_STEP_DETERMINE 1
+
+#define TP_MODE 0
+#define RSSI_MODE 1
+#define TRAFFIC_LOW 0
+#define TRAFFIC_HIGH 1
+
+struct sw_ant_switch {
+ u8 try_flag;
+ s32 PreRSSI;
+ u8 CurAntenna;
+ u8 PreAntenna;
+ u8 RSSI_Trying;
+ u8 TestMode;
+ u8 bTriggerAntennaSwitch;
+ u8 SelectAntennaMap;
+ u8 RSSI_target;
+
+ /* Before link Antenna Switch check */
+ u8 SWAS_NoLink_State;
+ u32 SWAS_NoLink_BK_Reg860;
+ bool ANTA_ON; /* To indicate Ant A is or not */
+ bool ANTB_ON; /* To indicate Ant B is on or not */
+
+ s32 RSSI_sum_A;
+ s32 RSSI_sum_B;
+ s32 RSSI_cnt_A;
+ s32 RSSI_cnt_B;
+ u64 lastTxOkCnt;
+ u64 lastRxOkCnt;
+ u64 TXByteCnt_A;
+ u64 TXByteCnt_B;
+ u64 RXByteCnt_A;
+ u64 RXByteCnt_B;
+ u8 TrafficLoad;
+ struct timer_list SwAntennaSwitchTimer;
+ /* Hybrid Antenna Diversity */
+ u32 CCK_Ant1_Cnt[ASSOCIATE_ENTRY_NUM];
+ u32 CCK_Ant2_Cnt[ASSOCIATE_ENTRY_NUM];
+ u32 OFDM_Ant1_Cnt[ASSOCIATE_ENTRY_NUM];
+ u32 OFDM_Ant2_Cnt[ASSOCIATE_ENTRY_NUM];
+ u32 RSSI_Ant1_Sum[ASSOCIATE_ENTRY_NUM];
+ u32 RSSI_Ant2_Sum[ASSOCIATE_ENTRY_NUM];
+ u8 TxAnt[ASSOCIATE_ENTRY_NUM];
+ u8 TargetSTA;
+ u8 antsel;
+ u8 RxIdleAnt;
+};
+
+struct edca_turbo {
+ bool bCurrentTurboEDCA;
+ bool bIsCurRDLState;
+ u32 prv_traffic_idx; /* edca turbo */
+};
+
+struct odm_rate_adapt {
+ u8 Type; /* DM_Type_ByFW/DM_Type_ByDriver */
+ u8 HighRSSIThresh; /* if RSSI > HighRSSIThresh => RATRState is DM_RATR_STA_HIGH */
+ u8 LowRSSIThresh; /* if RSSI <= LowRSSIThresh => RATRState is DM_RATR_STA_LOW */
+ u8 RATRState; /* Current RSSI level, DM_RATR_STA_HIGH/DM_RATR_STA_MIDDLE/DM_RATR_STA_LOW */
+ u32 LastRATR; /* RATR Register Content */
+};
+
+#define IQK_MAC_REG_NUM 4
+#define IQK_ADDA_REG_NUM 16
+#define IQK_BB_REG_NUM_MAX 10
+#define IQK_BB_REG_NUM 9
+#define HP_THERMAL_NUM 8
+
+#define AVG_THERMAL_NUM 8
+#define IQK_Matrix_REG_NUM 8
+#define IQK_Matrix_Settings_NUM 1+24+21
+
+#define DM_Type_ByFWi 0
+#define DM_Type_ByDriver 1
+
+/* Declare for common info */
+
+#define MAX_PATH_NUM_92CS 2
+
+struct odm_phy_status_info {
+ u8 RxPWDBAll;
+ u8 SignalQuality; /* in 0-100 index. */
+ u8 RxMIMOSignalQuality[MAX_PATH_NUM_92CS]; /* EVM */
+ u8 RxMIMOSignalStrength[MAX_PATH_NUM_92CS];/* in 0~100 index */
+ s8 RxPower; /* in dBm Translate from PWdB */
+ s8 RecvSignalPower;/* Real power in dBm for this packet, no
+ * beautification and aggregation. Keep this raw
+ * info to be used for the other procedures. */
+ u8 BTRxRSSIPercentage;
+ u8 SignalStrength; /* in 0-100 index. */
+ u8 RxPwr[MAX_PATH_NUM_92CS];/* per-path's pwdb */
+ u8 RxSNR[MAX_PATH_NUM_92CS];/* per-path's SNR */
+};
+
+struct odm_phy_dbg_info {
+ /* ODM Write,debug info */
+ s8 RxSNRdB[MAX_PATH_NUM_92CS];
+ u64 NumQryPhyStatus;
+ u64 NumQryPhyStatusCCK;
+ u64 NumQryPhyStatusOFDM;
+ /* Others */
+ s32 RxEVM[MAX_PATH_NUM_92CS];
+};
+
+struct odm_per_pkt_info {
+ s8 Rate;
+ u8 StationID;
+ bool bPacketMatchBSSID;
+ bool bPacketToSelf;
+ bool bPacketBeacon;
+};
+
+struct odm_mac_status_info {
+ u8 test;
+};
+
+enum odm_ability {
+ /* BB Team */
+ ODM_DIG = 0x00000001,
+ ODM_HIGH_POWER = 0x00000002,
+ ODM_CCK_CCA_TH = 0x00000004,
+ ODM_FA_STATISTICS = 0x00000008,
+ ODM_RAMASK = 0x00000010,
+ ODM_RSSI_MONITOR = 0x00000020,
+ ODM_SW_ANTDIV = 0x00000040,
+ ODM_HW_ANTDIV = 0x00000080,
+ ODM_BB_PWRSV = 0x00000100,
+ ODM_2TPATHDIV = 0x00000200,
+ ODM_1TPATHDIV = 0x00000400,
+ ODM_PSD2AFH = 0x00000800
+};
+
+/* 2011/20/20 MH For MP driver RT_WLAN_STA = struct sta_info */
+/* Please declare below ODM relative info in your STA info structure. */
+
+struct odm_sta_info {
+ /* Driver Write */
+ bool bUsed; /* record the sta status link or not? */
+ u8 IOTPeer; /* Enum value. HT_IOT_PEER_E */
+
+ /* ODM Write */
+ /* 1 PHY_STATUS_INFO */
+ u8 RSSI_Path[4]; /* */
+ u8 RSSI_Ave;
+ u8 RXEVM[4];
+ u8 RXSNR[4];
+};
+
+/* 2011/10/20 MH Define Common info enum for all team. */
+
+enum odm_common_info_def {
+ /* Fixed value: */
+
+ /* HOOK BEFORE REG INIT----------- */
+ ODM_CMNINFO_PLATFORM = 0,
+ ODM_CMNINFO_ABILITY, /* ODM_ABILITY_E */
+ ODM_CMNINFO_INTERFACE, /* ODM_INTERFACE_E */
+ ODM_CMNINFO_MP_TEST_CHIP,
+ ODM_CMNINFO_IC_TYPE, /* ODM_IC_TYPE_E */
+ ODM_CMNINFO_CUT_VER, /* ODM_CUT_VERSION_E */
+ ODM_CMNINFO_FAB_VER, /* ODM_FAB_E */
+ ODM_CMNINFO_RF_TYPE, /* ODM_RF_PATH_E or ODM_RF_TYPE_E? */
+ ODM_CMNINFO_BOARD_TYPE, /* ODM_BOARD_TYPE_E */
+ ODM_CMNINFO_EXT_LNA, /* true */
+ ODM_CMNINFO_EXT_PA,
+ ODM_CMNINFO_EXT_TRSW,
+ ODM_CMNINFO_PATCH_ID, /* CUSTOMER ID */
+ ODM_CMNINFO_BINHCT_TEST,
+ ODM_CMNINFO_BWIFI_TEST,
+ ODM_CMNINFO_SMART_CONCURRENT,
+ /* HOOK BEFORE REG INIT----------- */
+
+ /* Dynamic value: */
+/* POINTER REFERENCE----------- */
+ ODM_CMNINFO_MAC_PHY_MODE, /* ODM_MAC_PHY_MODE_E */
+ ODM_CMNINFO_TX_UNI,
+ ODM_CMNINFO_RX_UNI,
+ ODM_CMNINFO_WM_MODE, /* ODM_WIRELESS_MODE_E */
+ ODM_CMNINFO_BAND, /* ODM_BAND_TYPE_E */
+ ODM_CMNINFO_SEC_CHNL_OFFSET, /* ODM_SEC_CHNL_OFFSET_E */
+ ODM_CMNINFO_SEC_MODE, /* ODM_SECURITY_E */
+ ODM_CMNINFO_BW, /* ODM_BW_E */
+ ODM_CMNINFO_CHNL,
+
+ ODM_CMNINFO_DMSP_GET_VALUE,
+ ODM_CMNINFO_BUDDY_ADAPTOR,
+ ODM_CMNINFO_DMSP_IS_MASTER,
+ ODM_CMNINFO_SCAN,
+ ODM_CMNINFO_POWER_SAVING,
+ ODM_CMNINFO_ONE_PATH_CCA, /* ODM_CCA_PATH_E */
+ ODM_CMNINFO_DRV_STOP,
+ ODM_CMNINFO_PNP_IN,
+ ODM_CMNINFO_INIT_ON,
+ ODM_CMNINFO_ANT_TEST,
+ ODM_CMNINFO_NET_CLOSED,
+ ODM_CMNINFO_MP_MODE,
+/* POINTER REFERENCE----------- */
+
+/* CALL BY VALUE------------- */
+ ODM_CMNINFO_WIFI_DIRECT,
+ ODM_CMNINFO_WIFI_DISPLAY,
+ ODM_CMNINFO_LINK,
+ ODM_CMNINFO_RSSI_MIN,
+ ODM_CMNINFO_DBG_COMP, /* u64 */
+ ODM_CMNINFO_DBG_LEVEL, /* u32 */
+ ODM_CMNINFO_RA_THRESHOLD_HIGH, /* u8 */
+ ODM_CMNINFO_RA_THRESHOLD_LOW, /* u8 */
+ ODM_CMNINFO_RF_ANTENNA_TYPE, /* u8 */
+ ODM_CMNINFO_BT_DISABLED,
+ ODM_CMNINFO_BT_OPERATION,
+ ODM_CMNINFO_BT_DIG,
+ ODM_CMNINFO_BT_BUSY, /* Check Bt is using or not */
+ ODM_CMNINFO_BT_DISABLE_EDCA,
+/* CALL BY VALUE-------------*/
+
+ /* Dynamic ptr array hook itms. */
+ ODM_CMNINFO_STA_STATUS,
+ ODM_CMNINFO_PHY_STATUS,
+ ODM_CMNINFO_MAC_STATUS,
+ ODM_CMNINFO_MAX,
+};
+
+/* 2011/10/20 MH Define ODM support ability. ODM_CMNINFO_ABILITY */
+
+enum odm_ability_def {
+ /* BB ODM section BIT 0-15 */
+ ODM_BB_DIG = BIT0,
+ ODM_BB_RA_MASK = BIT1,
+ ODM_BB_DYNAMIC_TXPWR = BIT2,
+ ODM_BB_FA_CNT = BIT3,
+ ODM_BB_RSSI_MONITOR = BIT4,
+ ODM_BB_CCK_PD = BIT5,
+ ODM_BB_ANT_DIV = BIT6,
+ ODM_BB_PWR_SAVE = BIT7,
+ ODM_BB_PWR_TRA = BIT8,
+ ODM_BB_RATE_ADAPTIVE = BIT9,
+ ODM_BB_PATH_DIV = BIT10,
+ ODM_BB_PSD = BIT11,
+ ODM_BB_RXHP = BIT12,
+
+ /* MAC DM section BIT 16-23 */
+ ODM_MAC_EDCA_TURBO = BIT16,
+ ODM_MAC_EARLY_MODE = BIT17,
+
+ /* RF ODM section BIT 24-31 */
+ ODM_RF_TX_PWR_TRACK = BIT24,
+ ODM_RF_RX_GAIN_TRACK = BIT25,
+ ODM_RF_CALIBRATION = BIT26,
+};
+
+/* ODM_CMNINFO_INTERFACE */
+enum odm_interface_def {
+ ODM_ITRF_PCIE = 0x1,
+ ODM_ITRF_USB = 0x2,
+ ODM_ITRF_SDIO = 0x4,
+ ODM_ITRF_ALL = 0x7,
+};
+
+/* ODM_CMNINFO_IC_TYPE */
+enum odm_ic_type {
+ ODM_RTL8192S = BIT0,
+ ODM_RTL8192C = BIT1,
+ ODM_RTL8192D = BIT2,
+ ODM_RTL8723A = BIT3,
+ ODM_RTL8188E = BIT4,
+ ODM_RTL8812 = BIT5,
+ ODM_RTL8821 = BIT6,
+};
+
+#define ODM_IC_11N_SERIES \
+ (ODM_RTL8192S | ODM_RTL8192C | ODM_RTL8192D | \
+ ODM_RTL8723A | ODM_RTL8188E)
+#define ODM_IC_11AC_SERIES (ODM_RTL8812)
+
+/* ODM_CMNINFO_CUT_VER */
+enum odm_cut_version {
+ ODM_CUT_A = 1,
+ ODM_CUT_B = 2,
+ ODM_CUT_C = 3,
+ ODM_CUT_D = 4,
+ ODM_CUT_E = 5,
+ ODM_CUT_F = 6,
+ ODM_CUT_TEST = 7,
+};
+
+/* ODM_CMNINFO_FAB_VER */
+enum odm_fab_Version {
+ ODM_TSMC = 0,
+ ODM_UMC = 1,
+};
+
+/* ODM_CMNINFO_RF_TYPE */
+/* For example 1T2R (A+AB = BIT0|BIT4|BIT5) */
+enum odm_rf_path {
+ ODM_RF_TX_A = BIT0,
+ ODM_RF_TX_B = BIT1,
+ ODM_RF_TX_C = BIT2,
+ ODM_RF_TX_D = BIT3,
+ ODM_RF_RX_A = BIT4,
+ ODM_RF_RX_B = BIT5,
+ ODM_RF_RX_C = BIT6,
+ ODM_RF_RX_D = BIT7,
+};
+
+enum odm_rf_type {
+ ODM_1T1R = 0,
+ ODM_1T2R = 1,
+ ODM_2T2R = 2,
+ ODM_2T3R = 3,
+ ODM_2T4R = 4,
+ ODM_3T3R = 5,
+ ODM_3T4R = 6,
+ ODM_4T4R = 7,
+};
+
+/* ODM Dynamic common info value definition */
+
+enum odm_mac_phy_mode {
+ ODM_SMSP = 0,
+ ODM_DMSP = 1,
+ ODM_DMDP = 2,
+};
+
+enum odm_bt_coexist {
+ ODM_BT_BUSY = 1,
+ ODM_BT_ON = 2,
+ ODM_BT_OFF = 3,
+ ODM_BT_NONE = 4,
+};
+
+/* ODM_CMNINFO_OP_MODE */
+enum odm_operation_mode {
+ ODM_NO_LINK = BIT0,
+ ODM_LINK = BIT1,
+ ODM_SCAN = BIT2,
+ ODM_POWERSAVE = BIT3,
+ ODM_AP_MODE = BIT4,
+ ODM_CLIENT_MODE = BIT5,
+ ODM_AD_HOC = BIT6,
+ ODM_WIFI_DIRECT = BIT7,
+ ODM_WIFI_DISPLAY = BIT8,
+};
+
+/* ODM_CMNINFO_WM_MODE */
+enum odm_wireless_mode {
+ ODM_WM_UNKNOW = 0x0,
+ ODM_WM_B = BIT0,
+ ODM_WM_G = BIT1,
+ ODM_WM_A = BIT2,
+ ODM_WM_N24G = BIT3,
+ ODM_WM_N5G = BIT4,
+ ODM_WM_AUTO = BIT5,
+ ODM_WM_AC = BIT6,
+};
+
+/* ODM_CMNINFO_BAND */
+enum odm_band_type {
+ ODM_BAND_2_4G = BIT0,
+ ODM_BAND_5G = BIT1,
+};
+
+/* ODM_CMNINFO_SEC_CHNL_OFFSET */
+enum odm_sec_chnl_offset {
+ ODM_DONT_CARE = 0,
+ ODM_BELOW = 1,
+ ODM_ABOVE = 2
+};
+
+/* ODM_CMNINFO_SEC_MODE */
+enum odm_security {
+ ODM_SEC_OPEN = 0,
+ ODM_SEC_WEP40 = 1,
+ ODM_SEC_TKIP = 2,
+ ODM_SEC_RESERVE = 3,
+ ODM_SEC_AESCCMP = 4,
+ ODM_SEC_WEP104 = 5,
+ ODM_WEP_WPA_MIXED = 6, /* WEP + WPA */
+ ODM_SEC_SMS4 = 7,
+};
+
+/* ODM_CMNINFO_BW */
+enum odm_bw {
+ ODM_BW20M = 0,
+ ODM_BW40M = 1,
+ ODM_BW80M = 2,
+ ODM_BW160M = 3,
+ ODM_BW10M = 4,
+};
+
+/* ODM_CMNINFO_BOARD_TYPE */
+enum odm_board_type {
+ ODM_BOARD_NORMAL = 0,
+ ODM_BOARD_HIGHPWR = 1,
+ ODM_BOARD_MINICARD = 2,
+ ODM_BOARD_SLIM = 3,
+ ODM_BOARD_COMBO = 4,
+};
+
+/* ODM_CMNINFO_ONE_PATH_CCA */
+enum odm_cca_path {
+ ODM_CCA_2R = 0,
+ ODM_CCA_1R_A = 1,
+ ODM_CCA_1R_B = 2,
+};
+
+struct odm_ra_info {
+ u8 RateID;
+ u32 RateMask;
+ u32 RAUseRate;
+ u8 RateSGI;
+ u8 RssiStaRA;
+ u8 PreRssiStaRA;
+ u8 SGIEnable;
+ u8 DecisionRate;
+ u8 PreRate;
+ u8 HighestRate;
+ u8 LowestRate;
+ u32 NscUp;
+ u32 NscDown;
+ u16 RTY[5];
+ u32 TOTAL;
+ u16 DROP;
+ u8 Active;
+ u16 RptTime;
+ u8 RAWaitingCounter;
+ u8 RAPendingCounter;
+ u8 PTActive; /* on or off */
+ u8 PTTryState; /* 0 trying state, 1 for decision state */
+ u8 PTStage; /* 0~6 */
+ u8 PTStopCount; /* Stop PT counter */
+ u8 PTPreRate; /* if rate change do PT */
+ u8 PTPreRssi; /* if RSSI change 5% do PT */
+ u8 PTModeSS; /* decide whitch rate should do PT */
+ u8 RAstage; /* StageRA, decide how many times RA will be done
+ * between PT */
+ u8 PTSmoothFactor;
+};
+
+struct ijk_matrix_regs_set {
+ bool bIQKDone;
+ s32 Value[1][IQK_Matrix_REG_NUM];
+};
+
+struct odm_rf_cal {
+ /* for tx power tracking */
+ u32 RegA24; /* for TempCCK */
+ s32 RegE94;
+ s32 RegE9C;
+ s32 RegEB4;
+ s32 RegEBC;
+
+ u8 TXPowercount;
+ bool bTXPowerTrackingInit;
+ bool bTXPowerTracking;
+ u8 TxPowerTrackControl; /* for mp mode, turn off txpwrtracking
+ * as default */
+ u8 TM_Trigger;
+ u8 InternalPA5G[2]; /* pathA / pathB */
+
+ u8 ThermalMeter[2]; /* ThermalMeter, index 0 for RFIC0,
+ * and 1 for RFIC1 */
+ u8 ThermalValue;
+ u8 ThermalValue_LCK;
+ u8 ThermalValue_IQK;
+ u8 ThermalValue_DPK;
+ u8 ThermalValue_AVG[AVG_THERMAL_NUM];
+ u8 ThermalValue_AVG_index;
+ u8 ThermalValue_RxGain;
+ u8 ThermalValue_Crystal;
+ u8 ThermalValue_DPKstore;
+ u8 ThermalValue_DPKtrack;
+ bool TxPowerTrackingInProgress;
+ bool bDPKenable;
+
+ bool bReloadtxpowerindex;
+ u8 bRfPiEnable;
+ u32 TXPowerTrackingCallbackCnt; /* cosa add for debug */
+
+ u8 bCCKinCH14;
+ u8 CCK_index;
+ u8 OFDM_index[2];
+ bool bDoneTxpower;
+
+ u8 ThermalValue_HP[HP_THERMAL_NUM];
+ u8 ThermalValue_HP_index;
+ struct ijk_matrix_regs_set IQKMatrixRegSetting[IQK_Matrix_Settings_NUM];
+
+ u8 Delta_IQK;
+ u8 Delta_LCK;
+
+ /* for IQK */
+ u32 RegC04;
+ u32 Reg874;
+ u32 RegC08;
+ u32 RegB68;
+ u32 RegB6C;
+ u32 Reg870;
+ u32 Reg860;
+ u32 Reg864;
+
+ bool bIQKInitialized;
+ bool bLCKInProgress;
+ bool bAntennaDetected;
+ u32 ADDA_backup[IQK_ADDA_REG_NUM];
+ u32 IQK_MAC_backup[IQK_MAC_REG_NUM];
+ u32 IQK_BB_backup_recover[9];
+ u32 IQK_BB_backup[IQK_BB_REG_NUM];
+
+ /* for APK */
+ u32 APKoutput[2][2]; /* path A/B; output1_1a/output1_2a */
+ u8 bAPKdone;
+ u8 bAPKThermalMeterIgnore;
+ u8 bDPdone;
+ u8 bDPPathAOK;
+ u8 bDPPathBOK;
+};
+
+/* ODM Dynamic common info value definition */
+
+struct fast_ant_train {
+ u8 Bssid[6];
+ u8 antsel_rx_keep_0;
+ u8 antsel_rx_keep_1;
+ u8 antsel_rx_keep_2;
+ u32 antSumRSSI[7];
+ u32 antRSSIcnt[7];
+ u32 antAveRSSI[7];
+ u8 FAT_State;
+ u32 TrainIdx;
+ u8 antsel_a[ODM_ASSOCIATE_ENTRY_NUM];
+ u8 antsel_b[ODM_ASSOCIATE_ENTRY_NUM];
+ u8 antsel_c[ODM_ASSOCIATE_ENTRY_NUM];
+ u32 MainAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM];
+ u32 AuxAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM];
+ u32 MainAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM];
+ u32 AuxAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM];
+ u8 RxIdleAnt;
+ bool bBecomeLinked;
+};
+
+enum fat_state {
+ FAT_NORMAL_STATE = 0,
+ FAT_TRAINING_STATE = 1,
+};
+
+enum ant_div_type {
+ NO_ANTDIV = 0xFF,
+ CG_TRX_HW_ANTDIV = 0x01,
+ CGCS_RX_HW_ANTDIV = 0x02,
+ FIXED_HW_ANTDIV = 0x03,
+ CG_TRX_SMART_ANTDIV = 0x04,
+ CGCS_RX_SW_ANTDIV = 0x05,
+};
+
+/* Copy from SD4 defined structure. We use to support PHY DM integration. */
+struct odm_dm_struct {
+ /* Add for different team use temporarily */
+ struct adapter *Adapter; /* For CE/NIC team */
+ struct rtl8192cd_priv *priv; /* For AP/ADSL team */
+ /* WHen you use above pointers, they must be initialized. */
+ bool odm_ready;
+
+ struct rtl8192cd_priv *fake_priv;
+ u64 DebugComponents;
+ u32 DebugLevel;
+
+/* ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */
+ bool bCckHighPower;
+ u8 RFPathRxEnable; /* ODM_CMNINFO_RFPATH_ENABLE */
+ u8 ControlChannel;
+/* ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */
+
+/* 1 COMMON INFORMATION */
+ /* Init Value */
+/* HOOK BEFORE REG INIT----------- */
+ /* ODM Platform info AP/ADSL/CE/MP = 1/2/3/4 */
+ u8 SupportPlatform;
+ /* ODM Support Ability DIG/RATR/TX_PWR_TRACK/ ¡K¡K = 1/2/3/¡K */
+ u32 SupportAbility;
+ /* ODM PCIE/USB/SDIO/GSPI = 0/1/2/3 */
+ u8 SupportInterface;
+ /* ODM composite or independent. Bit oriented/ 92C+92D+ .... or any
+ * other type = 1/2/3/... */
+ u32 SupportICType;
+ /* Cut Version TestChip/A-cut/B-cut... = 0/1/2/3/... */
+ u8 CutVersion;
+ /* Fab Version TSMC/UMC = 0/1 */
+ u8 FabVersion;
+ /* RF Type 4T4R/3T3R/2T2R/1T2R/1T1R/... */
+ u8 RFType;
+ /* Board Type Normal/HighPower/MiniCard/SLIM/Combo/. = 0/1/2/3/4/. */
+ u8 BoardType;
+ /* with external LNA NO/Yes = 0/1 */
+ u8 ExtLNA;
+ /* with external PA NO/Yes = 0/1 */
+ u8 ExtPA;
+ /* with external TRSW NO/Yes = 0/1 */
+ u8 ExtTRSW;
+ u8 PatchID; /* Customer ID */
+ bool bInHctTest;
+ bool bWIFITest;
+
+ bool bDualMacSmartConcurrent;
+ u32 BK_SupportAbility;
+ u8 AntDivType;
+/* HOOK BEFORE REG INIT----------- */
+
+ /* Dynamic Value */
+/* POINTER REFERENCE----------- */
+
+ u8 u8_temp;
+ bool bool_temp;
+ struct adapter *adapter_temp;
+
+ /* MAC PHY Mode SMSP/DMSP/DMDP = 0/1/2 */
+ u8 *pMacPhyMode;
+ /* TX Unicast byte count */
+ u64 *pNumTxBytesUnicast;
+ /* RX Unicast byte count */
+ u64 *pNumRxBytesUnicast;
+ /* Wireless mode B/G/A/N = BIT0/BIT1/BIT2/BIT3 */
+ u8 *pWirelessMode; /* ODM_WIRELESS_MODE_E */
+ /* Frequence band 2.4G/5G = 0/1 */
+ u8 *pBandType;
+ /* Secondary channel offset don't_care/below/above = 0/1/2 */
+ u8 *pSecChOffset;
+ /* Security mode Open/WEP/AES/TKIP = 0/1/2/3 */
+ u8 *pSecurity;
+ /* BW info 20M/40M/80M = 0/1/2 */
+ u8 *pBandWidth;
+ /* Central channel location Ch1/Ch2/.... */
+ u8 *pChannel; /* central channel number */
+ /* Common info for 92D DMSP */
+
+ bool *pbGetValueFromOtherMac;
+ struct adapter **pBuddyAdapter;
+ bool *pbMasterOfDMSP; /* MAC0: master, MAC1: slave */
+ /* Common info for Status */
+ bool *pbScanInProcess;
+ bool *pbPowerSaving;
+ /* CCA Path 2-path/path-A/path-B = 0/1/2; using ODM_CCA_PATH_E. */
+ u8 *pOnePathCCA;
+ /* pMgntInfo->AntennaTest */
+ u8 *pAntennaTest;
+ bool *pbNet_closed;
+/* POINTER REFERENCE----------- */
+ /* */
+/* CALL BY VALUE------------- */
+ bool bWIFI_Direct;
+ bool bWIFI_Display;
+ bool bLinked;
+ u8 RSSI_Min;
+ u8 InterfaceIndex; /* Add for 92D dual MAC: 0--Mac0 1--Mac1 */
+ bool bIsMPChip;
+ bool bOneEntryOnly;
+ /* Common info for BTDM */
+ bool bBtDisabled; /* BT is disabled */
+ bool bBtHsOperation; /* BT HS mode is under progress */
+ u8 btHsDigVal; /* use BT rssi to decide the DIG value */
+ bool bBtDisableEdcaTurbo;/* Under some condition, don't enable the
+ * EDCA Turbo */
+ bool bBtBusy; /* BT is busy. */
+/* CALL BY VALUE------------- */
+
+ /* 2 Define STA info. */
+ /* _ODM_STA_INFO */
+ /* For MP, we need to reduce one array pointer for default port.?? */
+ struct sta_info *pODM_StaInfo[ODM_ASSOCIATE_ENTRY_NUM];
+
+ u16 CurrminRptTime;
+ struct odm_ra_info RAInfo[ODM_ASSOCIATE_ENTRY_NUM]; /* Use MacID as
+ * array index. STA MacID=0,
+ * VWiFi Client MacID={1, ODM_ASSOCIATE_ENTRY_NUM-1} */
+ /* */
+ /* 2012/02/14 MH Add to share 88E ra with other SW team. */
+ /* We need to colelct all support abilit to a proper area. */
+ /* */
+ bool RaSupport88E;
+
+ /* Define ........... */
+
+ /* Latest packet phy info (ODM write) */
+ struct odm_phy_dbg_info PhyDbgInfo;
+
+ /* Latest packet phy info (ODM write) */
+ struct odm_mac_status_info *pMacInfo;
+
+ /* Different Team independt structure?? */
+
+ /* ODM Structure */
+ struct fast_ant_train DM_FatTable;
+ struct rtw_dig DM_DigTable;
+ struct rtl_ps DM_PSTable;
+ struct dyn_primary_cca DM_PriCCA;
+ struct rx_hpc DM_RXHP_Table;
+ struct false_alarm_stats FalseAlmCnt;
+ struct false_alarm_stats FlaseAlmCntBuddyAdapter;
+ struct sw_ant_switch DM_SWAT_Table;
+ bool RSSI_test;
+
+ struct edca_turbo DM_EDCA_Table;
+ u32 WMMEDCA_BE;
+ /* Copy from SD4 structure */
+ /* */
+ /* ================================================== */
+ /* */
+
+ bool *pbDriverStopped;
+ bool *pbDriverIsGoingToPnpSetPowerSleep;
+ bool *pinit_adpt_in_progress;
+
+ /* PSD */
+ bool bUserAssignLevel;
+ struct timer_list PSDTimer;
+ u8 RSSI_BT; /* come from BT */
+ bool bPSDinProcess;
+ bool bDMInitialGainEnable;
+
+ /* for rate adaptive, in fact, 88c/92c fw will handle this */
+ u8 bUseRAMask;
+
+ struct odm_rate_adapt RateAdaptive;
+
+ struct odm_rf_cal RFCalibrateInfo;
+
+ /* TX power tracking */
+ u8 BbSwingIdxOfdm;
+ u8 BbSwingIdxOfdmCurrent;
+ u8 BbSwingIdxOfdmBase;
+ bool BbSwingFlagOfdm;
+ u8 BbSwingIdxCck;
+ u8 BbSwingIdxCckCurrent;
+ u8 BbSwingIdxCckBase;
+ bool BbSwingFlagCck;
+ u8 *mp_mode;
+ /* ODM system resource. */
+
+ /* ODM relative time. */
+ struct timer_list PathDivSwitchTimer;
+ /* 2011.09.27 add for Path Diversity */
+ struct timer_list CCKPathDiversityTimer;
+ struct timer_list FastAntTrainingTimer;
+}; /* DM_Dynamic_Mechanism_Structure */
+
+#define ODM_RF_PATH_MAX 2
+
+enum ODM_RF_RADIO_PATH {
+ ODM_RF_PATH_A = 0, /* Radio Path A */
+ ODM_RF_PATH_B = 1, /* Radio Path B */
+ ODM_RF_PATH_C = 2, /* Radio Path C */
+ ODM_RF_PATH_D = 3, /* Radio Path D */
+};
+
+enum ODM_RF_CONTENT {
+ odm_radioa_txt = 0x1000,
+ odm_radiob_txt = 0x1001,
+ odm_radioc_txt = 0x1002,
+ odm_radiod_txt = 0x1003
+};
+
+enum odm_bb_config_type {
+ CONFIG_BB_PHY_REG,
+ CONFIG_BB_AGC_TAB,
+ CONFIG_BB_AGC_TAB_2G,
+ CONFIG_BB_AGC_TAB_5G,
+ CONFIG_BB_PHY_REG_PG,
+};
+
+/* Status code */
+enum rt_status {
+ RT_STATUS_SUCCESS,
+ RT_STATUS_FAILURE,
+ RT_STATUS_PENDING,
+ RT_STATUS_RESOURCE,
+ RT_STATUS_INVALID_CONTEXT,
+ RT_STATUS_INVALID_PARAMETER,
+ RT_STATUS_NOT_SUPPORT,
+ RT_STATUS_OS_API_FAILED,
+};
+
+/* 3=========================================================== */
+/* 3 DIG */
+/* 3=========================================================== */
+
+enum dm_dig_op {
+ RT_TYPE_THRESH_HIGH = 0,
+ RT_TYPE_THRESH_LOW = 1,
+ RT_TYPE_BACKOFF = 2,
+ RT_TYPE_RX_GAIN_MIN = 3,
+ RT_TYPE_RX_GAIN_MAX = 4,
+ RT_TYPE_ENABLE = 5,
+ RT_TYPE_DISABLE = 6,
+ DIG_OP_TYPE_MAX
+};
+
+#define DM_DIG_THRESH_HIGH 40
+#define DM_DIG_THRESH_LOW 35
+
+#define DM_SCAN_RSSI_TH 0x14 /* scan return issue for LC */
+
+
+#define DM_false_ALARM_THRESH_LOW 400
+#define DM_false_ALARM_THRESH_HIGH 1000
+
+#define DM_DIG_MAX_NIC 0x3e
+#define DM_DIG_MIN_NIC 0x1e /* 0x22/0x1c */
+
+#define DM_DIG_MAX_AP 0x32
+#define DM_DIG_MIN_AP 0x20
+
+#define DM_DIG_MAX_NIC_HP 0x46
+#define DM_DIG_MIN_NIC_HP 0x2e
+
+#define DM_DIG_MAX_AP_HP 0x42
+#define DM_DIG_MIN_AP_HP 0x30
+
+/* vivi 92c&92d has different definition, 20110504 */
+/* this is for 92c */
+#define DM_DIG_FA_TH0 0x200/* 0x20 */
+#define DM_DIG_FA_TH1 0x300/* 0x100 */
+#define DM_DIG_FA_TH2 0x400/* 0x200 */
+/* this is for 92d */
+#define DM_DIG_FA_TH0_92D 0x100
+#define DM_DIG_FA_TH1_92D 0x400
+#define DM_DIG_FA_TH2_92D 0x600
+
+#define DM_DIG_BACKOFF_MAX 12
+#define DM_DIG_BACKOFF_MIN -4
+#define DM_DIG_BACKOFF_DEFAULT 10
+
+/* 3=========================================================== */
+/* 3 AGC RX High Power Mode */
+/* 3=========================================================== */
+#define LNA_Low_Gain_1 0x64
+#define LNA_Low_Gain_2 0x5A
+#define LNA_Low_Gain_3 0x58
+
+#define FA_RXHP_TH1 5000
+#define FA_RXHP_TH2 1500
+#define FA_RXHP_TH3 800
+#define FA_RXHP_TH4 600
+#define FA_RXHP_TH5 500
+
+/* 3=========================================================== */
+/* 3 EDCA */
+/* 3=========================================================== */
+
+/* 3=========================================================== */
+/* 3 Dynamic Tx Power */
+/* 3=========================================================== */
+/* Dynamic Tx Power Control Threshold */
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67
+#define TX_POWER_NEAR_FIELD_THRESH_AP 0x3F
+
+#define TxHighPwrLevel_Normal 0
+#define TxHighPwrLevel_Level1 1
+#define TxHighPwrLevel_Level2 2
+#define TxHighPwrLevel_BT1 3
+#define TxHighPwrLevel_BT2 4
+#define TxHighPwrLevel_15 5
+#define TxHighPwrLevel_35 6
+#define TxHighPwrLevel_50 7
+#define TxHighPwrLevel_70 8
+#define TxHighPwrLevel_100 9
+
+/* 3=========================================================== */
+/* 3 Rate Adaptive */
+/* 3=========================================================== */
+#define DM_RATR_STA_INIT 0
+#define DM_RATR_STA_HIGH 1
+#define DM_RATR_STA_MIDDLE 2
+#define DM_RATR_STA_LOW 3
+
+/* 3=========================================================== */
+/* 3 BB Power Save */
+/* 3=========================================================== */
+
+
+enum dm_1r_cca {
+ CCA_1R = 0,
+ CCA_2R = 1,
+ CCA_MAX = 2,
+};
+
+enum dm_rf {
+ RF_Save = 0,
+ RF_Normal = 1,
+ RF_MAX = 2,
+};
+
+/* 3=========================================================== */
+/* 3 Antenna Diversity */
+/* 3=========================================================== */
+enum dm_swas {
+ Antenna_A = 1,
+ Antenna_B = 2,
+ Antenna_MAX = 3,
+};
+
+/* Maximal number of antenna detection mechanism needs to perform. */
+#define MAX_ANTENNA_DETECTION_CNT 10
+
+/* Extern Global Variables. */
+#define OFDM_TABLE_SIZE_92C 37
+#define OFDM_TABLE_SIZE_92D 43
+#define CCK_TABLE_SIZE 33
+
+extern u32 OFDMSwingTable[OFDM_TABLE_SIZE_92D];
+extern u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8];
+extern u8 CCKSwingTable_Ch14 [CCK_TABLE_SIZE][8];
+
+/* check Sta pointer valid or not */
+#define IS_STA_VALID(pSta) (pSta)
+/* 20100514 Joseph: Add definition for antenna switching test after link. */
+/* This indicates two different the steps. */
+/* In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the
+ * signal on the air. */
+/* In SWAW_STEP_DETERMINE, driver just compares the signal captured in
+ * SWAW_STEP_PEAK */
+/* with original RSSI to determine if it is necessary to switch antenna. */
+#define SWAW_STEP_PEAK 0
+#define SWAW_STEP_DETERMINE 1
+
+void ODM_Write_DIG(struct odm_dm_struct *pDM_Odm, u8 CurrentIGI);
+void ODM_Write_CCK_CCA_Thres(struct odm_dm_struct *pDM_Odm, u8 CurCCK_CCAThres);
+
+void ODM_SetAntenna(struct odm_dm_struct *pDM_Odm, u8 Antenna);
+
+
+#define dm_RF_Saving ODM_RF_Saving
+void ODM_RF_Saving(struct odm_dm_struct *pDM_Odm, u8 bForceInNormal);
+
+#define SwAntDivRestAfterLink ODM_SwAntDivRestAfterLink
+void ODM_SwAntDivRestAfterLink(struct odm_dm_struct *pDM_Odm);
+
+#define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck
+void ODM_TXPowerTrackingCheck(struct odm_dm_struct *pDM_Odm);
+
+bool ODM_RAStateCheck(struct odm_dm_struct *pDM_Odm, s32 RSSI,
+ bool bForceUpdate, u8 *pRATRState);
+
+#define dm_SWAW_RSSI_Check ODM_SwAntDivChkPerPktRssi
+void ODM_SwAntDivChkPerPktRssi(struct odm_dm_struct *pDM_Odm, u8 StationID,
+ struct odm_phy_status_info *pPhyInfo);
+
+u32 ConvertTo_dB(u32 Value);
+
+u32 GetPSDData(struct odm_dm_struct *pDM_Odm, unsigned int point,
+ u8 initial_gain_psd);
+
+void odm_DIGbyRSSI_LPS(struct odm_dm_struct *pDM_Odm);
+
+u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid,
+ u32 ra_mask, u8 rssi_level);
+
+void ODM_DMInit(struct odm_dm_struct *pDM_Odm);
+
+void ODM_DMWatchdog(struct odm_dm_struct *pDM_Odm);
+
+void ODM_CmnInfoInit(struct odm_dm_struct *pDM_Odm,
+ enum odm_common_info_def CmnInfo, u32 Value);
+
+void ODM_CmnInfoHook(struct odm_dm_struct *pDM_Odm,
+ enum odm_common_info_def CmnInfo, void *pValue);
+
+void ODM_CmnInfoPtrArrayHook(struct odm_dm_struct *pDM_Odm,
+ enum odm_common_info_def CmnInfo,
+ u16 Index, void *pValue);
+
+void ODM_CmnInfoUpdate(struct odm_dm_struct *pDM_Odm, u32 CmnInfo, u64 Value);
+
+void ODM_InitAllTimers(struct odm_dm_struct *pDM_Odm);
+
+void ODM_CancelAllTimers(struct odm_dm_struct *pDM_Odm);
+
+void ODM_ReleaseAllTimers(struct odm_dm_struct *pDM_Odm);
+
+void ODM_ResetIQKResult(struct odm_dm_struct *pDM_Odm);
+
+void ODM_AntselStatistics_88C(struct odm_dm_struct *pDM_Odm, u8 MacId,
+ u32 PWDBAll, bool isCCKrate);
+
+void ODM_SingleDualAntennaDefaultSetting(struct odm_dm_struct *pDM_Odm);
+
+bool ODM_SingleDualAntennaDetection(struct odm_dm_struct *pDM_Odm, u8 mode);
+
+void odm_dtc(struct odm_dm_struct *pDM_Odm);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_HWConfig.h b/drivers/staging/rtl8188eu/include/odm_HWConfig.h
new file mode 100644
index 00000000000..63779f5b2a3
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_HWConfig.h
@@ -0,0 +1,132 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __HALHWOUTSRC_H__
+#define __HALHWOUTSRC_H__
+
+/* Definition */
+/* CCK Rates, TxHT = 0 */
+#define DESC92C_RATE1M 0x00
+#define DESC92C_RATE2M 0x01
+#define DESC92C_RATE5_5M 0x02
+#define DESC92C_RATE11M 0x03
+
+/* OFDM Rates, TxHT = 0 */
+#define DESC92C_RATE6M 0x04
+#define DESC92C_RATE9M 0x05
+#define DESC92C_RATE12M 0x06
+#define DESC92C_RATE18M 0x07
+#define DESC92C_RATE24M 0x08
+#define DESC92C_RATE36M 0x09
+#define DESC92C_RATE48M 0x0a
+#define DESC92C_RATE54M 0x0b
+
+/* MCS Rates, TxHT = 1 */
+#define DESC92C_RATEMCS0 0x0c
+#define DESC92C_RATEMCS1 0x0d
+#define DESC92C_RATEMCS2 0x0e
+#define DESC92C_RATEMCS3 0x0f
+#define DESC92C_RATEMCS4 0x10
+#define DESC92C_RATEMCS5 0x11
+#define DESC92C_RATEMCS6 0x12
+#define DESC92C_RATEMCS7 0x13
+#define DESC92C_RATEMCS8 0x14
+#define DESC92C_RATEMCS9 0x15
+#define DESC92C_RATEMCS10 0x16
+#define DESC92C_RATEMCS11 0x17
+#define DESC92C_RATEMCS12 0x18
+#define DESC92C_RATEMCS13 0x19
+#define DESC92C_RATEMCS14 0x1a
+#define DESC92C_RATEMCS15 0x1b
+#define DESC92C_RATEMCS15_SG 0x1c
+#define DESC92C_RATEMCS32 0x20
+
+/* structure and define */
+
+struct phy_rx_agc_info {
+ #ifdef __LITTLE_ENDIAN
+ u8 gain:7, trsw:1;
+ #else
+ u8 trsw:1, gain:7;
+ #endif
+};
+
+struct phy_status_rpt {
+ struct phy_rx_agc_info path_agc[2];
+ u8 ch_corr[2];
+ u8 cck_sig_qual_ofdm_pwdb_all;
+ u8 cck_agc_rpt_ofdm_cfosho_a;
+ u8 cck_rpt_b_ofdm_cfosho_b;
+ u8 rsvd_1;/* ch_corr_msb; */
+ u8 noise_power_db_msb;
+ u8 path_cfotail[2];
+ u8 pcts_mask[2];
+ s8 stream_rxevm[2];
+ u8 path_rxsnr[2];
+ u8 noise_power_db_lsb;
+ u8 rsvd_2[3];
+ u8 stream_csi[2];
+ u8 stream_target_csi[2];
+ s8 sig_evm;
+ u8 rsvd_3;
+
+#ifdef __LITTLE_ENDIAN
+ u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */
+ u8 sgi_en:1;
+ u8 rxsc:2;
+ u8 idle_long:1;
+ u8 r_ant_train_en:1;
+ u8 ant_sel_b:1;
+ u8 ant_sel:1;
+#else /* _BIG_ENDIAN_ */
+ u8 ant_sel:1;
+ u8 ant_sel_b:1;
+ u8 r_ant_train_en:1;
+ u8 idle_long:1;
+ u8 rxsc:2;
+ u8 sgi_en:1;
+ u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */
+#endif
+};
+
+void odm_Init_RSSIForDM(struct odm_dm_struct *pDM_Odm);
+
+void ODM_PhyStatusQuery(struct odm_dm_struct *pDM_Odm,
+ struct odm_phy_status_info *pPhyInfo,
+ u8 *pPhyStatus,
+ struct odm_per_pkt_info *pPktinfo);
+
+void ODM_MacStatusQuery(struct odm_dm_struct *pDM_Odm,
+ u8 *pMacStatus,
+ u8 MacID,
+ bool bPacketMatchBSSID,
+ bool bPacketToSelf,
+ bool bPacketBeacon);
+
+enum HAL_STATUS ODM_ConfigRFWithHeaderFile(struct odm_dm_struct *pDM_Odm,
+ enum ODM_RF_RADIO_PATH Content,
+ enum ODM_RF_RADIO_PATH eRFPath);
+
+enum HAL_STATUS ODM_ConfigBBWithHeaderFile(struct odm_dm_struct *pDM_Odm,
+ enum odm_bb_config_type ConfigType);
+
+enum HAL_STATUS ODM_ConfigMACWithHeaderFile(struct odm_dm_struct *pDM_Odm);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_RTL8188E.h b/drivers/staging/rtl8188eu/include/odm_RTL8188E.h
new file mode 100644
index 00000000000..f96ad5af4bd
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_RTL8188E.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __ODM_RTL8188E_H__
+#define __ODM_RTL8188E_H__
+
+#define MAIN_ANT 0
+#define AUX_ANT 1
+#define MAIN_ANT_CG_TRX 1
+#define AUX_ANT_CG_TRX 0
+#define MAIN_ANT_CGCS_RX 0
+#define AUX_ANT_CGCS_RX 1
+
+void ODM_DIG_LowerBound_88E(struct odm_dm_struct *pDM_Odm);
+
+void ODM_AntennaDiversityInit_88E(struct odm_dm_struct *pDM_Odm);
+
+void ODM_AntennaDiversity_88E(struct odm_dm_struct *pDM_Odm);
+
+void ODM_SetTxAntByTxInfo_88E(struct odm_dm_struct *pDM_Odm, u8 *pDesc,
+ u8 macId);
+
+void ODM_UpdateRxIdleAnt_88E(struct odm_dm_struct *pDM_Odm, u8 Ant);
+
+void ODM_AntselStatistics_88E(struct odm_dm_struct *pDM_Odm, u8 antsel_tr_mux,
+ u32 MacId, u8 RxPWDBAll);
+
+void odm_FastAntTraining(struct odm_dm_struct *pDM_Odm);
+
+void odm_FastAntTrainingCallback(struct odm_dm_struct *pDM_Odm);
+
+void odm_FastAntTrainingWorkItemCallback(struct odm_dm_struct *pDM_Odm);
+
+void odm_PrimaryCCA_Init(struct odm_dm_struct *pDM_Odm);
+
+bool ODM_DynamicPrimaryCCA_DupRTS(struct odm_dm_struct *pDM_Odm);
+
+void odm_DynamicPrimaryCCA(struct odm_dm_struct *pDM_Odm);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_RegConfig8188E.h b/drivers/staging/rtl8188eu/include/odm_RegConfig8188E.h
new file mode 100644
index 00000000000..727e6b26fb0
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_RegConfig8188E.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __INC_ODM_REGCONFIG_H_8188E
+#define __INC_ODM_REGCONFIG_H_8188E
+
+void odm_ConfigRFReg_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data,
+ enum ODM_RF_RADIO_PATH RF_PATH, u32 RegAddr);
+
+void odm_ConfigRF_RadioA_8188E(struct odm_dm_struct *pDM_Odm,
+ u32 Addr, u32 Data);
+
+void odm_ConfigRF_RadioB_8188E(struct odm_dm_struct *pDM_Odm,
+ u32 Addr, u32 Data);
+
+void odm_ConfigMAC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u8 Data);
+
+void odm_ConfigBB_AGC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr,
+ u32 Bitmask, u32 Data);
+
+void odm_ConfigBB_PHY_REG_PG_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr,
+ u32 Bitmask, u32 Data);
+
+void odm_ConfigBB_PHY_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr,
+ u32 Bitmask, u32 Data);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_RegDefine11AC.h b/drivers/staging/rtl8188eu/include/odm_RegDefine11AC.h
new file mode 100644
index 00000000000..f08775c0dd8
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_RegDefine11AC.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __ODM_REGDEFINE11AC_H__
+#define __ODM_REGDEFINE11AC_H__
+
+/* 2 RF REG LIST */
+
+
+
+/* 2 BB REG LIST */
+/* PAGE 8 */
+/* PAGE 9 */
+#define ODM_REG_OFDM_FA_RST_11AC 0x9A4
+/* PAGE A */
+#define ODM_REG_CCK_CCA_11AC 0xA0A
+#define ODM_REG_CCK_FA_RST_11AC 0xA2C
+#define ODM_REG_CCK_FA_11AC 0xA5C
+/* PAGE C */
+#define ODM_REG_IGI_A_11AC 0xC50
+/* PAGE E */
+#define ODM_REG_IGI_B_11AC 0xE50
+/* PAGE F */
+#define ODM_REG_OFDM_FA_11AC 0xF48
+
+
+/* 2 MAC REG LIST */
+
+
+
+
+/* DIG Related */
+#define ODM_BIT_IGI_11AC 0xFFFFFFFF
+
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_RegDefine11N.h b/drivers/staging/rtl8188eu/include/odm_RegDefine11N.h
new file mode 100644
index 00000000000..5a61f902bc1
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_RegDefine11N.h
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __ODM_REGDEFINE11N_H__
+#define __ODM_REGDEFINE11N_H__
+
+
+/* 2 RF REG LIST */
+#define ODM_REG_RF_MODE_11N 0x00
+#define ODM_REG_RF_0B_11N 0x0B
+#define ODM_REG_CHNBW_11N 0x18
+#define ODM_REG_T_METER_11N 0x24
+#define ODM_REG_RF_25_11N 0x25
+#define ODM_REG_RF_26_11N 0x26
+#define ODM_REG_RF_27_11N 0x27
+#define ODM_REG_RF_2B_11N 0x2B
+#define ODM_REG_RF_2C_11N 0x2C
+#define ODM_REG_RXRF_A3_11N 0x3C
+#define ODM_REG_T_METER_92D_11N 0x42
+#define ODM_REG_T_METER_88E_11N 0x42
+
+
+
+/* 2 BB REG LIST */
+/* PAGE 8 */
+#define ODM_REG_BB_CTRL_11N 0x800
+#define ODM_REG_RF_PIN_11N 0x804
+#define ODM_REG_PSD_CTRL_11N 0x808
+#define ODM_REG_TX_ANT_CTRL_11N 0x80C
+#define ODM_REG_BB_PWR_SAV5_11N 0x818
+#define ODM_REG_CCK_RPT_FORMAT_11N 0x824
+#define ODM_REG_RX_DEFUALT_A_11N 0x858
+#define ODM_REG_RX_DEFUALT_B_11N 0x85A
+#define ODM_REG_BB_PWR_SAV3_11N 0x85C
+#define ODM_REG_ANTSEL_CTRL_11N 0x860
+#define ODM_REG_RX_ANT_CTRL_11N 0x864
+#define ODM_REG_PIN_CTRL_11N 0x870
+#define ODM_REG_BB_PWR_SAV1_11N 0x874
+#define ODM_REG_ANTSEL_PATH_11N 0x878
+#define ODM_REG_BB_3WIRE_11N 0x88C
+#define ODM_REG_SC_CNT_11N 0x8C4
+#define ODM_REG_PSD_DATA_11N 0x8B4
+/* PAGE 9 */
+#define ODM_REG_ANT_MAPPING1_11N 0x914
+#define ODM_REG_ANT_MAPPING2_11N 0x918
+/* PAGE A */
+#define ODM_REG_CCK_ANTDIV_PARA1_11N 0xA00
+#define ODM_REG_CCK_CCA_11N 0xA0A
+#define ODM_REG_CCK_ANTDIV_PARA2_11N 0xA0C
+#define ODM_REG_CCK_ANTDIV_PARA3_11N 0xA10
+#define ODM_REG_CCK_ANTDIV_PARA4_11N 0xA14
+#define ODM_REG_CCK_FILTER_PARA1_11N 0xA22
+#define ODM_REG_CCK_FILTER_PARA2_11N 0xA23
+#define ODM_REG_CCK_FILTER_PARA3_11N 0xA24
+#define ODM_REG_CCK_FILTER_PARA4_11N 0xA25
+#define ODM_REG_CCK_FILTER_PARA5_11N 0xA26
+#define ODM_REG_CCK_FILTER_PARA6_11N 0xA27
+#define ODM_REG_CCK_FILTER_PARA7_11N 0xA28
+#define ODM_REG_CCK_FILTER_PARA8_11N 0xA29
+#define ODM_REG_CCK_FA_RST_11N 0xA2C
+#define ODM_REG_CCK_FA_MSB_11N 0xA58
+#define ODM_REG_CCK_FA_LSB_11N 0xA5C
+#define ODM_REG_CCK_CCA_CNT_11N 0xA60
+#define ODM_REG_BB_PWR_SAV4_11N 0xA74
+/* PAGE B */
+#define ODM_REG_LNA_SWITCH_11N 0xB2C
+#define ODM_REG_PATH_SWITCH_11N 0xB30
+#define ODM_REG_RSSI_CTRL_11N 0xB38
+#define ODM_REG_CONFIG_ANTA_11N 0xB68
+#define ODM_REG_RSSI_BT_11N 0xB9C
+/* PAGE C */
+#define ODM_REG_OFDM_FA_HOLDC_11N 0xC00
+#define ODM_REG_RX_PATH_11N 0xC04
+#define ODM_REG_TRMUX_11N 0xC08
+#define ODM_REG_OFDM_FA_RSTC_11N 0xC0C
+#define ODM_REG_RXIQI_MATRIX_11N 0xC14
+#define ODM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C
+#define ODM_REG_IGI_A_11N 0xC50
+#define ODM_REG_ANTDIV_PARA2_11N 0xC54
+#define ODM_REG_IGI_B_11N 0xC58
+#define ODM_REG_ANTDIV_PARA3_11N 0xC5C
+#define ODM_REG_BB_PWR_SAV2_11N 0xC70
+#define ODM_REG_RX_OFF_11N 0xC7C
+#define ODM_REG_TXIQK_MATRIXA_11N 0xC80
+#define ODM_REG_TXIQK_MATRIXB_11N 0xC88
+#define ODM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94
+#define ODM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C
+#define ODM_REG_RXIQK_MATRIX_LSB_11N 0xCA0
+#define ODM_REG_ANTDIV_PARA1_11N 0xCA4
+#define ODM_REG_OFDM_FA_TYPE1_11N 0xCF0
+/* PAGE D */
+#define ODM_REG_OFDM_FA_RSTD_11N 0xD00
+#define ODM_REG_OFDM_FA_TYPE2_11N 0xDA0
+#define ODM_REG_OFDM_FA_TYPE3_11N 0xDA4
+#define ODM_REG_OFDM_FA_TYPE4_11N 0xDA8
+/* PAGE E */
+#define ODM_REG_TXAGC_A_6_18_11N 0xE00
+#define ODM_REG_TXAGC_A_24_54_11N 0xE04
+#define ODM_REG_TXAGC_A_1_MCS32_11N 0xE08
+#define ODM_REG_TXAGC_A_MCS0_3_11N 0xE10
+#define ODM_REG_TXAGC_A_MCS4_7_11N 0xE14
+#define ODM_REG_TXAGC_A_MCS8_11_11N 0xE18
+#define ODM_REG_TXAGC_A_MCS12_15_11N 0xE1C
+#define ODM_REG_FPGA0_IQK_11N 0xE28
+#define ODM_REG_TXIQK_TONE_A_11N 0xE30
+#define ODM_REG_RXIQK_TONE_A_11N 0xE34
+#define ODM_REG_TXIQK_PI_A_11N 0xE38
+#define ODM_REG_RXIQK_PI_A_11N 0xE3C
+#define ODM_REG_TXIQK_11N 0xE40
+#define ODM_REG_RXIQK_11N 0xE44
+#define ODM_REG_IQK_AGC_PTS_11N 0xE48
+#define ODM_REG_IQK_AGC_RSP_11N 0xE4C
+#define ODM_REG_BLUETOOTH_11N 0xE6C
+#define ODM_REG_RX_WAIT_CCA_11N 0xE70
+#define ODM_REG_TX_CCK_RFON_11N 0xE74
+#define ODM_REG_TX_CCK_BBON_11N 0xE78
+#define ODM_REG_OFDM_RFON_11N 0xE7C
+#define ODM_REG_OFDM_BBON_11N 0xE80
+#define ODM_REG_TX2RX_11N 0xE84
+#define ODM_REG_TX2TX_11N 0xE88
+#define ODM_REG_RX_CCK_11N 0xE8C
+#define ODM_REG_RX_OFDM_11N 0xED0
+#define ODM_REG_RX_WAIT_RIFS_11N 0xED4
+#define ODM_REG_RX2RX_11N 0xED8
+#define ODM_REG_STANDBY_11N 0xEDC
+#define ODM_REG_SLEEP_11N 0xEE0
+#define ODM_REG_PMPD_ANAEN_11N 0xEEC
+
+
+
+
+
+
+
+/* 2 MAC REG LIST */
+#define ODM_REG_BB_RST_11N 0x02
+#define ODM_REG_ANTSEL_PIN_11N 0x4C
+#define ODM_REG_EARLY_MODE_11N 0x4D0
+#define ODM_REG_RSSI_MONITOR_11N 0x4FE
+#define ODM_REG_EDCA_VO_11N 0x500
+#define ODM_REG_EDCA_VI_11N 0x504
+#define ODM_REG_EDCA_BE_11N 0x508
+#define ODM_REG_EDCA_BK_11N 0x50C
+#define ODM_REG_TXPAUSE_11N 0x522
+#define ODM_REG_RESP_TX_11N 0x6D8
+#define ODM_REG_ANT_TRAIN_PARA1_11N 0x7b0
+#define ODM_REG_ANT_TRAIN_PARA2_11N 0x7b4
+
+
+/* DIG Related */
+#define ODM_BIT_IGI_11N 0x0000007F
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_debug.h b/drivers/staging/rtl8188eu/include/odm_debug.h
new file mode 100644
index 00000000000..a9ba6df26b9
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_debug.h
@@ -0,0 +1,145 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+
+#ifndef __ODM_DBG_H__
+#define __ODM_DBG_H__
+
+
+/* */
+/* Define the debug levels */
+/* */
+/* 1. DBG_TRACE and DBG_LOUD are used for normal cases. */
+/* They can help SW engineer to develope or trace states changed */
+/* and also help HW enginner to trace every operation to and from HW, */
+/* e.g IO, Tx, Rx. */
+/* */
+/* 2. DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, */
+/* which help us to debug SW or HW. */
+
+/* Never used in a call to ODM_RT_TRACE()! */
+#define ODM_DBG_OFF 1
+
+/* Fatal bug. */
+/* For example, Tx/Rx/IO locked up, OS hangs, memory access violation, */
+/* resource allocation failed, unexpected HW behavior, HW BUG and so on. */
+#define ODM_DBG_SERIOUS 2
+
+/* Abnormal, rare, or unexpeted cases. */
+/* For example, IRP/Packet/OID canceled, device suprisely unremoved and so on. */
+#define ODM_DBG_WARNING 3
+
+/* Normal case with useful information about current SW or HW state. */
+/* For example, Tx/Rx descriptor to fill, Tx/Rx descr. completed status, */
+/* SW protocol state change, dynamic mechanism state change and so on. */
+/* */
+#define ODM_DBG_LOUD 4
+
+/* Normal case with detail execution flow or information. */
+#define ODM_DBG_TRACE 5
+
+/* Define the tracing components */
+/* BB Functions */
+#define ODM_COMP_DIG BIT0
+#define ODM_COMP_RA_MASK BIT1
+#define ODM_COMP_DYNAMIC_TXPWR BIT2
+#define ODM_COMP_FA_CNT BIT3
+#define ODM_COMP_RSSI_MONITOR BIT4
+#define ODM_COMP_CCK_PD BIT5
+#define ODM_COMP_ANT_DIV BIT6
+#define ODM_COMP_PWR_SAVE BIT7
+#define ODM_COMP_PWR_TRA BIT8
+#define ODM_COMP_RATE_ADAPTIVE BIT9
+#define ODM_COMP_PATH_DIV BIT10
+#define ODM_COMP_PSD BIT11
+#define ODM_COMP_DYNAMIC_PRICCA BIT12
+#define ODM_COMP_RXHP BIT13
+/* MAC Functions */
+#define ODM_COMP_EDCA_TURBO BIT16
+#define ODM_COMP_EARLY_MODE BIT17
+/* RF Functions */
+#define ODM_COMP_TX_PWR_TRACK BIT24
+#define ODM_COMP_RX_GAIN_TRACK BIT25
+#define ODM_COMP_CALIBRATION BIT26
+/* Common Functions */
+#define ODM_COMP_COMMON BIT30
+#define ODM_COMP_INIT BIT31
+
+/*------------------------Export Marco Definition---------------------------*/
+#define DbgPrint pr_info
+#define RT_PRINTK(fmt, args...) \
+ DbgPrint( "%s(): " fmt, __func__, ## args);
+
+#ifndef ASSERT
+ #define ASSERT(expr)
+#endif
+
+#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt) \
+ if (((comp) & pDM_Odm->DebugComponents) && \
+ (level <= pDM_Odm->DebugLevel)) { \
+ if (pDM_Odm->SupportICType == ODM_RTL8192C) \
+ DbgPrint("[ODM-92C] "); \
+ else if (pDM_Odm->SupportICType == ODM_RTL8192D) \
+ DbgPrint("[ODM-92D] "); \
+ else if (pDM_Odm->SupportICType == ODM_RTL8723A) \
+ DbgPrint("[ODM-8723A] "); \
+ else if (pDM_Odm->SupportICType == ODM_RTL8188E) \
+ DbgPrint("[ODM-8188E] "); \
+ else if (pDM_Odm->SupportICType == ODM_RTL8812) \
+ DbgPrint("[ODM-8812] "); \
+ else if (pDM_Odm->SupportICType == ODM_RTL8821) \
+ DbgPrint("[ODM-8821] "); \
+ RT_PRINTK fmt; \
+ }
+
+#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt) \
+ if (((comp) & pDM_Odm->DebugComponents) && \
+ (level <= pDM_Odm->DebugLevel)) { \
+ RT_PRINTK fmt; \
+ }
+
+#define ODM_RT_ASSERT(pDM_Odm, expr, fmt) \
+ if (!(expr)) { \
+ DbgPrint( "Assertion failed! %s at ......\n", #expr); \
+ DbgPrint( " ......%s,%s,line=%d\n", __FILE__, \
+ __func__, __LINE__); \
+ RT_PRINTK fmt; \
+ ASSERT(false); \
+ }
+#define ODM_dbg_enter() { DbgPrint("==> %s\n", __func__); }
+#define ODM_dbg_exit() { DbgPrint("<== %s\n", __func__); }
+#define ODM_dbg_trace(str) { DbgPrint("%s:%s\n", __func__, str); }
+
+#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr) \
+ if (((comp) & pDM_Odm->DebugComponents) && \
+ (level <= pDM_Odm->DebugLevel)) { \
+ int __i; \
+ u8 *__ptr = (u8 *)ptr; \
+ DbgPrint("[ODM] "); \
+ DbgPrint(title_str); \
+ DbgPrint(" "); \
+ for (__i = 0; __i < 6; __i++) \
+ DbgPrint("%02X%s", __ptr[__i], (__i==5)?"":"-");\
+ DbgPrint("\n"); \
+ }
+
+void ODM_InitDebugSetting(struct odm_dm_struct *pDM_Odm);
+
+#endif /* __ODM_DBG_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm_interface.h b/drivers/staging/rtl8188eu/include/odm_interface.h
new file mode 100644
index 00000000000..e5c8704ac01
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_interface.h
@@ -0,0 +1,164 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __ODM_INTERFACE_H__
+#define __ODM_INTERFACE_H__
+
+/* */
+/* =========== Constant/Structure/Enum/... Define */
+/* */
+
+/* */
+/* =========== Macro Define */
+/* */
+
+#define _reg_all(_name) ODM_##_name
+#define _reg_ic(_name, _ic) ODM_##_name##_ic
+#define _bit_all(_name) BIT_##_name
+#define _bit_ic(_name, _ic) BIT_##_name##_ic
+
+/* _cat: implemented by Token-Pasting Operator. */
+
+/*===================================
+
+#define ODM_REG_DIG_11N 0xC50
+#define ODM_REG_DIG_11AC 0xDDD
+
+ODM_REG(DIG,_pDM_Odm)
+=====================================*/
+
+#define _reg_11N(_name) ODM_REG_##_name##_11N
+#define _reg_11AC(_name) ODM_REG_##_name##_11AC
+#define _bit_11N(_name) ODM_BIT_##_name##_11N
+#define _bit_11AC(_name) ODM_BIT_##_name##_11AC
+
+#define _cat(_name, _ic_type, _func) \
+ ( \
+ ((_ic_type) & ODM_IC_11N_SERIES) ? _func##_11N(_name) : \
+ _func##_11AC(_name) \
+ )
+
+/* _name: name of register or bit. */
+/* Example: "ODM_REG(R_A_AGC_CORE1, pDM_Odm)" */
+/* gets "ODM_R_A_AGC_CORE1" or "ODM_R_A_AGC_CORE1_8192C",
+ * depends on SupportICType. */
+#define ODM_REG(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _reg)
+#define ODM_BIT(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _bit)
+
+enum odm_h2c_cmd {
+ ODM_H2C_RSSI_REPORT = 0,
+ ODM_H2C_PSD_RESULT= 1,
+ ODM_H2C_PathDiv = 2,
+ ODM_MAX_H2CCMD
+};
+
+/* 2012/02/17 MH For non-MP compile pass only. Linux does not support workitem. */
+/* Suggest HW team to use thread instead of workitem. Windows also support the feature. */
+typedef void (*RT_WORKITEM_CALL_BACK)(void *pContext);
+
+/* =========== Extern Variable ??? It should be forbidden. */
+
+/* =========== EXtern Function Prototype */
+
+u8 ODM_Read1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr);
+
+u16 ODM_Read2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr);
+
+u32 ODM_Read4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr);
+
+void ODM_Write1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u8 Data);
+
+void ODM_Write2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u16 Data);
+
+void ODM_Write4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 Data);
+
+void ODM_SetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr,
+ u32 BitMask, u32 Data);
+
+u32 ODM_GetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask);
+
+void ODM_SetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr,
+ u32 BitMask, u32 Data);
+
+u32 ODM_GetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask);
+
+void ODM_SetRFReg(struct odm_dm_struct *pDM_Odm, enum ODM_RF_RADIO_PATH eRFPath,
+ u32 RegAddr, u32 BitMask, u32 Data);
+
+u32 ODM_GetRFReg(struct odm_dm_struct *pDM_Odm, enum ODM_RF_RADIO_PATH eRFPath,
+ u32 RegAddr, u32 BitMask);
+
+/* Memory Relative Function. */
+void ODM_AllocateMemory(struct odm_dm_struct *pDM_Odm, void **pPtr, u32 length);
+void ODM_FreeMemory(struct odm_dm_struct *pDM_Odm, void *pPtr, u32 length);
+
+s32 ODM_CompareMemory(struct odm_dm_struct *pDM_Odm, void *pBuf1, void *pBuf2,
+ u32 length);
+
+/* ODM MISC-spin lock relative API. */
+void ODM_AcquireSpinLock(struct odm_dm_struct *pDM_Odm,
+ enum RT_SPINLOCK_TYPE type);
+
+void ODM_ReleaseSpinLock(struct odm_dm_struct *pDM_Odm,
+ enum RT_SPINLOCK_TYPE type);
+
+/* ODM MISC-workitem relative API. */
+void ODM_InitializeWorkItem(struct odm_dm_struct *pDM_Odm, void *pRtWorkItem,
+ RT_WORKITEM_CALL_BACK RtWorkItemCallback,
+ void *pContext, const char *szID);
+
+void ODM_StartWorkItem(void *pRtWorkItem);
+
+void ODM_StopWorkItem(void *pRtWorkItem);
+
+void ODM_FreeWorkItem(void *pRtWorkItem);
+
+void ODM_ScheduleWorkItem(void *pRtWorkItem);
+
+void ODM_IsWorkItemScheduled(void *pRtWorkItem);
+
+/* ODM Timer relative API. */
+void ODM_StallExecution(u32 usDelay);
+
+void ODM_delay_ms(u32 ms);
+
+void ODM_delay_us(u32 us);
+
+void ODM_sleep_ms(u32 ms);
+
+void ODM_sleep_us(u32 us);
+
+void ODM_SetTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer,
+ u32 msDelay);
+
+void ODM_InitializeTimer(struct odm_dm_struct *pDM_Odm,
+ struct timer_list *pTimer, void *CallBackFunc,
+ void *pContext, const char *szID);
+
+void ODM_CancelTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer);
+
+void ODM_ReleaseTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer);
+
+/* ODM FW relative API. */
+u32 ODM_FillH2CCmd(u8 *pH2CBuffer, u32 H2CBufferLen, u32 CmdNum,
+ u32 *pElementID, u32 *pCmdLen, u8 **pCmbBuffer,
+ u8 *CmdStartSeq);
+
+#endif /* __ODM_INTERFACE_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm_precomp.h b/drivers/staging/rtl8188eu/include/odm_precomp.h
new file mode 100644
index 00000000000..520cbbaac35
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_precomp.h
@@ -0,0 +1,104 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __ODM_PRECOMP_H__
+#define __ODM_PRECOMP_H__
+
+#include "odm_types.h"
+
+#define TEST_FALG___ 1
+
+/* 2 Config Flags and Structs - defined by each ODM Type */
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <hal_intf.h>
+
+/* 2 Hardware Parameter Files */
+
+#include "Hal8188EFWImg_CE.h"
+
+
+/* 2 OutSrc Header Files */
+
+#include "odm.h"
+#include "odm_HWConfig.h"
+#include "odm_debug.h"
+#include "odm_RegDefine11AC.h"
+#include "odm_RegDefine11N.h"
+
+#include "HalPhyRf.h"
+#include "HalPhyRf_8188e.h"/* for IQK,LCK,Power-tracking */
+#include "Hal8188ERateAdaptive.h"/* for RA,Power training */
+#include "rtl8188e_hal.h"
+
+#include "odm_interface.h"
+#include "odm_reg.h"
+
+#include "HalHWImg8188E_MAC.h"
+#include "HalHWImg8188E_RF.h"
+#include "HalHWImg8188E_BB.h"
+#include "Hal8188EReg.h"
+
+#include "odm_RegConfig8188E.h"
+#include "odm_RTL8188E.h"
+
+void odm_CmnInfoHook_Debug(struct odm_dm_struct *pDM_Odm);
+void odm_CmnInfoInit_Debug(struct odm_dm_struct *pDM_Odm);
+void odm_DIGInit(struct odm_dm_struct *pDM_Odm);
+void odm_RateAdaptiveMaskInit(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicBBPowerSavingInit(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicTxPowerInit(struct odm_dm_struct *pDM_Odm);
+void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm);
+void ODM_EdcaTurboInit(struct odm_dm_struct *pDM_Odm);
+void odm_SwAntDivInit_NIC(struct odm_dm_struct *pDM_Odm);
+void odm_GlobalAdapterCheck(void);
+void odm_CmnInfoUpdate_Debug(struct odm_dm_struct *pDM_Odm);
+void odm_CommonInfoSelfUpdate(struct odm_dm_struct *pDM_Odm);
+void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm);
+void odm_DIG(struct odm_dm_struct *pDM_Odm);
+void odm_CCKPacketDetectionThresh(struct odm_dm_struct *pDM_Odm);
+void odm_RefreshRateAdaptiveMaskMP(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicBBPowerSaving(struct odm_dm_struct *pDM_Odm);
+void odm_SwAntDivChkAntSwitch(struct odm_dm_struct *pDM_Odm, u8 Step);
+void odm_EdcaTurboCheck(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicTxPower(struct odm_dm_struct *pDM_Odm);
+void odm_CommonInfoSelfInit(struct odm_dm_struct *pDM_Odm);
+void odm_SwAntDivInit(struct odm_dm_struct *pDM_Odm);
+void odm_RSSIMonitorCheck(struct odm_dm_struct *pDM_Odm);
+void odm_RefreshRateAdaptiveMask(struct odm_dm_struct *pDM_Odm);
+void odm_1R_CCA(struct odm_dm_struct *pDM_Odm);
+void odm_RefreshRateAdaptiveMaskCE(struct odm_dm_struct *pDM_Odm);
+void odm_RefreshRateAdaptiveMaskAPADSL(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicTxPowerNIC(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicTxPowerAP(struct odm_dm_struct *pDM_Odm);
+void odm_RSSIMonitorCheckMP(struct odm_dm_struct *pDM_Odm);
+void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm);
+void odm_RSSIMonitorCheckAP(struct odm_dm_struct *pDM_Odm);
+void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm);
+void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm);
+void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm);
+void odm_TXPowerTrackingCheckMP(struct odm_dm_struct *pDM_Odm);
+void odm_TXPowerTrackingCheckAP(struct odm_dm_struct *pDM_Odm);
+void odm_SwAntDivChkAntSwitchCallback(void *FunctionContext);
+void odm_InitHybridAntDiv(struct odm_dm_struct *pDM_Odm);
+void odm_HwAntDiv(struct odm_dm_struct *pDM_Odm);
+
+#endif /* __ODM_PRECOMP_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm_reg.h b/drivers/staging/rtl8188eu/include/odm_reg.h
new file mode 100644
index 00000000000..89bc46bc71b
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_reg.h
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+/* */
+/* File Name: odm_reg.h */
+/* */
+/* Description: */
+/* */
+/* This file is for general register definition. */
+/* */
+/* */
+/* */
+#ifndef __HAL_ODM_REG_H__
+#define __HAL_ODM_REG_H__
+
+/* */
+/* Register Definition */
+/* */
+
+/* MAC REG */
+#define ODM_BB_RESET 0x002
+#define ODM_DUMMY 0x4fe
+#define ODM_EDCA_VO_PARAM 0x500
+#define ODM_EDCA_VI_PARAM 0x504
+#define ODM_EDCA_BE_PARAM 0x508
+#define ODM_EDCA_BK_PARAM 0x50C
+#define ODM_TXPAUSE 0x522
+
+/* BB REG */
+#define ODM_FPGA_PHY0_PAGE8 0x800
+#define ODM_PSD_SETTING 0x808
+#define ODM_AFE_SETTING 0x818
+#define ODM_TXAGC_B_6_18 0x830
+#define ODM_TXAGC_B_24_54 0x834
+#define ODM_TXAGC_B_MCS32_5 0x838
+#define ODM_TXAGC_B_MCS0_MCS3 0x83c
+#define ODM_TXAGC_B_MCS4_MCS7 0x848
+#define ODM_TXAGC_B_MCS8_MCS11 0x84c
+#define ODM_ANALOG_REGISTER 0x85c
+#define ODM_RF_INTERFACE_OUTPUT 0x860
+#define ODM_TXAGC_B_MCS12_MCS15 0x868
+#define ODM_TXAGC_B_11_A_2_11 0x86c
+#define ODM_AD_DA_LSB_MASK 0x874
+#define ODM_ENABLE_3_WIRE 0x88c
+#define ODM_PSD_REPORT 0x8b4
+#define ODM_R_ANT_SELECT 0x90c
+#define ODM_CCK_ANT_SELECT 0xa07
+#define ODM_CCK_PD_THRESH 0xa0a
+#define ODM_CCK_RF_REG1 0xa11
+#define ODM_CCK_MATCH_FILTER 0xa20
+#define ODM_CCK_RAKE_MAC 0xa2e
+#define ODM_CCK_CNT_RESET 0xa2d
+#define ODM_CCK_TX_DIVERSITY 0xa2f
+#define ODM_CCK_FA_CNT_MSB 0xa5b
+#define ODM_CCK_FA_CNT_LSB 0xa5c
+#define ODM_CCK_NEW_FUNCTION 0xa75
+#define ODM_OFDM_PHY0_PAGE_C 0xc00
+#define ODM_OFDM_RX_ANT 0xc04
+#define ODM_R_A_RXIQI 0xc14
+#define ODM_R_A_AGC_CORE1 0xc50
+#define ODM_R_A_AGC_CORE2 0xc54
+#define ODM_R_B_AGC_CORE1 0xc58
+#define ODM_R_AGC_PAR 0xc70
+#define ODM_R_HTSTF_AGC_PAR 0xc7c
+#define ODM_TX_PWR_TRAINING_A 0xc90
+#define ODM_TX_PWR_TRAINING_B 0xc98
+#define ODM_OFDM_FA_CNT1 0xcf0
+#define ODM_OFDM_PHY0_PAGE_D 0xd00
+#define ODM_OFDM_FA_CNT2 0xda0
+#define ODM_OFDM_FA_CNT3 0xda4
+#define ODM_OFDM_FA_CNT4 0xda8
+#define ODM_TXAGC_A_6_18 0xe00
+#define ODM_TXAGC_A_24_54 0xe04
+#define ODM_TXAGC_A_1_MCS32 0xe08
+#define ODM_TXAGC_A_MCS0_MCS3 0xe10
+#define ODM_TXAGC_A_MCS4_MCS7 0xe14
+#define ODM_TXAGC_A_MCS8_MCS11 0xe18
+#define ODM_TXAGC_A_MCS12_MCS15 0xe1c
+
+/* RF REG */
+#define ODM_GAIN_SETTING 0x00
+#define ODM_CHANNEL 0x18
+
+/* Ant Detect Reg */
+#define ODM_DPDT 0x300
+
+/* PSD Init */
+#define ODM_PSDREG 0x808
+
+/* 92D Path Div */
+#define PATHDIV_REG 0xB30
+#define PATHDIV_TRI 0xBA0
+
+
+/* */
+/* Bitmap Definition */
+/* */
+
+#define BIT_FA_RESET BIT0
+
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_types.h b/drivers/staging/rtl8188eu/include/odm_types.h
new file mode 100644
index 00000000000..78ee2bac0d8
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_types.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __ODM_TYPES_H__
+#define __ODM_TYPES_H__
+
+/* */
+/* Define Different SW team support */
+/* */
+#define ODM_AP 0x01 /* BIT0 */
+#define ODM_ADSL 0x02 /* BIT1 */
+#define ODM_CE 0x04 /* BIT2 */
+#define ODM_MP 0x08 /* BIT3 */
+
+#define RT_PCI_INTERFACE 1
+#define RT_USB_INTERFACE 2
+#define RT_SDIO_INTERFACE 3
+
+enum HAL_STATUS {
+ HAL_STATUS_SUCCESS,
+ HAL_STATUS_FAILURE,
+};
+
+enum RT_SPINLOCK_TYPE {
+ RT_TEMP = 1,
+};
+
+#include <basic_types.h>
+
+#define DEV_BUS_TYPE RT_USB_INTERFACE
+
+#define SET_TX_DESC_ANTSEL_A_88E(__pTxDesc, __Value) \
+ SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 24, 1, __Value)
+#define SET_TX_DESC_ANTSEL_B_88E(__pTxDesc, __Value) \
+ SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 25, 1, __Value)
+#define SET_TX_DESC_ANTSEL_C_88E(__pTxDesc, __Value) \
+ SET_BITS_TO_LE_4BYTE(__pTxDesc+28, 29, 1, __Value)
+
+/* define useless flag to avoid compile warning */
+#define USE_WORKITEM 0
+#define FOR_BRAZIL_PRETEST 0
+#define BT_30_SUPPORT 0
+#define FPGA_TWO_MAC_VERIFICATION 0
+
+
+#endif /* __ODM_TYPES_H__ */
diff --git a/drivers/staging/rtl8188eu/include/osdep_intf.h b/drivers/staging/rtl8188eu/include/osdep_intf.h
new file mode 100644
index 00000000000..c4599c583b5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/osdep_intf.h
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __OSDEP_INTF_H_
+#define __OSDEP_INTF_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+struct intf_priv {
+ u8 *intf_dev;
+ u32 max_iosz; /* USB2.0: 128, USB1.1: 64, SDIO:64 */
+ u32 max_xmitsz; /* USB2.0: unlimited, SDIO:512 */
+ u32 max_recvsz; /* USB2.0: unlimited, SDIO:512 */
+
+ u8 *io_rwmem;
+ u8 *allocated_io_rwmem;
+ u32 io_wsz; /* unit: 4bytes */
+ u32 io_rsz;/* unit: 4bytes */
+ u8 intf_status;
+
+ void (*_bus_io)(u8 *priv);
+
+/*
+Under Sync. IRP (SDIO/USB)
+A protection mechanism is necessary for the io_rwmem(read/write protocol)
+
+Under Async. IRP (SDIO/USB)
+The protection mechanism is through the pending queue.
+*/
+ struct mutex ioctl_mutex;
+ /* when in USB, IO is through interrupt in/out endpoints */
+ struct usb_device *udev;
+ struct urb *piorw_urb;
+ u8 io_irp_cnt;
+ u8 bio_irp_pending;
+ struct semaphore io_retevt;
+ struct timer_list io_timer;
+ u8 bio_irp_timeout;
+ u8 bio_timer_cancel;
+};
+
+u8 rtw_init_drv_sw(struct adapter *padapter);
+u8 rtw_free_drv_sw(struct adapter *padapter);
+u8 rtw_reset_drv_sw(struct adapter *padapter);
+
+u32 rtw_start_drv_threads(struct adapter *padapter);
+void rtw_stop_drv_threads (struct adapter *padapter);
+void rtw_cancel_all_timer(struct adapter *padapter);
+
+int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+
+int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname);
+struct net_device *rtw_init_netdev(struct adapter *padapter);
+u16 rtw_recv_select_queue(struct sk_buff *skb);
+void rtw_proc_init_one(struct net_device *dev);
+void rtw_proc_remove_one(struct net_device *dev);
+
+void rtw_ips_dev_unload(struct adapter *padapter);
+
+int rtw_ips_pwr_up(struct adapter *padapter);
+void rtw_ips_pwr_down(struct adapter *padapter);
+int rtw_hw_suspend(struct adapter *padapter);
+int rtw_hw_resume(struct adapter *padapter);
+
+#endif /* _OSDEP_INTF_H_ */
diff --git a/drivers/staging/rtl8188eu/include/osdep_service.h b/drivers/staging/rtl8188eu/include/osdep_service.h
new file mode 100644
index 00000000000..44f24fa31a3
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/osdep_service.h
@@ -0,0 +1,547 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __OSDEP_SERVICE_H_
+#define __OSDEP_SERVICE_H_
+
+#include <basic_types.h>
+
+#define _FAIL 0
+#define _SUCCESS 1
+#define RTW_RX_HANDLED 2
+
+#include <linux/spinlock.h>
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/circ_buf.h>
+#include <linux/uaccess.h>
+#include <asm/byteorder.h>
+#include <linux/atomic.h>
+#include <linux/io.h>
+#include <linux/semaphore.h>
+#include <linux/sem.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
+#include <linux/interrupt.h> /* for struct tasklet_struct */
+#include <linux/ip.h>
+#include <linux/kthread.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+
+struct __queue {
+ struct list_head queue;
+ spinlock_t lock;
+};
+
+#define thread_exit() complete_and_exit(NULL, 0)
+
+static inline struct list_head *get_next(struct list_head *list)
+{
+ return list->next;
+}
+
+static inline struct list_head *get_list_head(struct __queue *queue)
+{
+ return (&(queue->queue));
+}
+
+
+#define LIST_CONTAINOR(ptr, type, member) \
+ ((type *)((char *)(ptr)-(size_t)(&((type *)0)->member)))
+
+
+static inline void _enter_critical(spinlock_t *plock, unsigned long *pirqL)
+{
+ spin_lock_irqsave(plock, *pirqL);
+}
+
+static inline void _exit_critical(spinlock_t *plock, unsigned long *pirqL)
+{
+ spin_unlock_irqrestore(plock, *pirqL);
+}
+
+static inline void _enter_critical_ex(spinlock_t *plock, unsigned long *pirqL)
+{
+ spin_lock_irqsave(plock, *pirqL);
+}
+
+static inline void _exit_critical_ex(spinlock_t *plock, unsigned long *pirqL)
+{
+ spin_unlock_irqrestore(plock, *pirqL);
+}
+
+static inline void _enter_critical_bh(spinlock_t *plock, unsigned long *pirqL)
+{
+ spin_lock_bh(plock);
+}
+
+static inline void _exit_critical_bh(spinlock_t *plock, unsigned long *pirqL)
+{
+ spin_unlock_bh(plock);
+}
+
+static inline int _enter_critical_mutex(struct mutex *pmutex, unsigned long *pirqL)
+{
+ int ret;
+
+ ret = mutex_lock_interruptible(pmutex);
+ return ret;
+}
+
+
+static inline void _exit_critical_mutex(struct mutex *pmutex, unsigned long *pirqL)
+{
+ mutex_unlock(pmutex);
+}
+
+static inline void rtw_list_delete(struct list_head *plist)
+{
+ list_del_init(plist);
+}
+
+static inline void _init_timer(struct timer_list *ptimer,struct net_device *nic_hdl,void *pfunc,void* cntx)
+{
+ ptimer->function = pfunc;
+ ptimer->data = (unsigned long)cntx;
+ init_timer(ptimer);
+}
+
+static inline void _set_timer(struct timer_list *ptimer,u32 delay_time)
+{
+ mod_timer(ptimer , (jiffies+(delay_time*HZ/1000)));
+}
+
+static inline void _cancel_timer(struct timer_list *ptimer,u8 *bcancelled)
+{
+ del_timer_sync(ptimer);
+ *bcancelled= true;/* true ==1; false==0 */
+}
+
+#define RTW_TIMER_HDL_ARGS void *FunctionContext
+#define RTW_TIMER_HDL_NAME(name) rtw_##name##_timer_hdl
+#define RTW_DECLARE_TIMER_HDL(name) void RTW_TIMER_HDL_NAME(name)(RTW_TIMER_HDL_ARGS)
+
+static inline void _init_workitem(struct work_struct *pwork, void *pfunc, void * cntx)
+{
+ INIT_WORK(pwork, pfunc);
+}
+
+static inline void _set_workitem(struct work_struct *pwork)
+{
+ schedule_work(pwork);
+}
+
+static inline void _cancel_workitem_sync(struct work_struct *pwork)
+{
+ cancel_work_sync(pwork);
+}
+/* */
+/* Global Mutex: can only be used at PASSIVE level. */
+/* */
+
+#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter) \
+{ \
+ while (atomic_inc_return((atomic_t *)&(_MutexCounter)) != 1)\
+ { \
+ atomic_dec((atomic_t *)&(_MutexCounter)); \
+ msleep(10); \
+ } \
+}
+
+#define RELEASE_GLOBAL_MUTEX(_MutexCounter) \
+{ \
+ atomic_dec((atomic_t *)&(_MutexCounter)); \
+}
+
+static inline int rtw_netif_queue_stopped(struct net_device *pnetdev)
+{
+ return netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 0)) &&
+ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 1)) &&
+ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 2)) &&
+ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 3));
+}
+
+static inline void rtw_netif_wake_queue(struct net_device *pnetdev)
+{
+ netif_tx_wake_all_queues(pnetdev);
+}
+
+static inline void rtw_netif_start_queue(struct net_device *pnetdev)
+{
+ netif_tx_start_all_queues(pnetdev);
+}
+
+static inline void rtw_netif_stop_queue(struct net_device *pnetdev)
+{
+ netif_tx_stop_all_queues(pnetdev);
+}
+
+#ifndef BIT
+ #define BIT(x) ( 1 << (x))
+#endif
+
+#define BIT0 0x00000001
+#define BIT1 0x00000002
+#define BIT2 0x00000004
+#define BIT3 0x00000008
+#define BIT4 0x00000010
+#define BIT5 0x00000020
+#define BIT6 0x00000040
+#define BIT7 0x00000080
+#define BIT8 0x00000100
+#define BIT9 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+#define BIT32 0x0100000000
+#define BIT33 0x0200000000
+#define BIT34 0x0400000000
+#define BIT35 0x0800000000
+#define BIT36 0x1000000000
+
+extern int RTW_STATUS_CODE(int error_code);
+
+/* flags used for rtw_update_mem_stat() */
+enum {
+ MEM_STAT_VIR_ALLOC_SUCCESS,
+ MEM_STAT_VIR_ALLOC_FAIL,
+ MEM_STAT_VIR_FREE,
+ MEM_STAT_PHY_ALLOC_SUCCESS,
+ MEM_STAT_PHY_ALLOC_FAIL,
+ MEM_STAT_PHY_FREE,
+ MEM_STAT_TX, /* used to distinguish TX/RX, asigned from caller */
+ MEM_STAT_TX_ALLOC_SUCCESS,
+ MEM_STAT_TX_ALLOC_FAIL,
+ MEM_STAT_TX_FREE,
+ MEM_STAT_RX, /* used to distinguish TX/RX, asigned from caller */
+ MEM_STAT_RX_ALLOC_SUCCESS,
+ MEM_STAT_RX_ALLOC_FAIL,
+ MEM_STAT_RX_FREE
+};
+
+extern unsigned char MCS_rate_2R[16];
+extern unsigned char MCS_rate_1R[16];
+extern unsigned char RTW_WPA_OUI[];
+extern unsigned char WPA_TKIP_CIPHER[4];
+extern unsigned char RSN_TKIP_CIPHER[4];
+
+#define rtw_update_mem_stat(flag, sz) do {} while (0)
+u8 *_rtw_vmalloc(u32 sz);
+u8 *_rtw_zvmalloc(u32 sz);
+void _rtw_vmfree(u8 *pbuf, u32 sz);
+u8 *_rtw_zmalloc(u32 sz);
+u8 *_rtw_malloc(u32 sz);
+void _rtw_mfree(u8 *pbuf, u32 sz);
+#define rtw_vmalloc(sz) _rtw_vmalloc((sz))
+#define rtw_zvmalloc(sz) _rtw_zvmalloc((sz))
+#define rtw_vmfree(pbuf, sz) _rtw_vmfree((pbuf), (sz))
+#define rtw_malloc(sz) _rtw_malloc((sz))
+#define rtw_zmalloc(sz) _rtw_zmalloc((sz))
+#define rtw_mfree(pbuf, sz) _rtw_mfree((pbuf), (sz))
+
+void *rtw_malloc2d(int h, int w, int size);
+void rtw_mfree2d(void *pbuf, int h, int w, int size);
+
+void _rtw_memcpy(void *dec, void *sour, u32 sz);
+int _rtw_memcmp(void *dst, void *src, u32 sz);
+void _rtw_memset(void *pbuf, int c, u32 sz);
+
+void _rtw_init_listhead(struct list_head *list);
+u32 rtw_is_list_empty(struct list_head *phead);
+void rtw_list_insert_head(struct list_head *plist, struct list_head *phead);
+void rtw_list_insert_tail(struct list_head *plist, struct list_head *phead);
+void rtw_list_delete(struct list_head *plist);
+
+void _rtw_init_sema(struct semaphore *sema, int init_val);
+void _rtw_free_sema(struct semaphore *sema);
+void _rtw_up_sema(struct semaphore *sema);
+u32 _rtw_down_sema(struct semaphore *sema);
+void _rtw_mutex_init(struct mutex *pmutex);
+void _rtw_mutex_free(struct mutex *pmutex);
+void _rtw_spinlock_init(spinlock_t *plock);
+void _rtw_spinlock_free(spinlock_t *plock);
+
+void _rtw_init_queue(struct __queue *pqueue);
+u32 _rtw_queue_empty(struct __queue *pqueue);
+u32 rtw_end_of_queue_search(struct list_head *queue, struct list_head *pelement);
+
+u32 rtw_get_current_time(void);
+u32 rtw_systime_to_ms(u32 systime);
+u32 rtw_ms_to_systime(u32 ms);
+s32 rtw_get_passing_time_ms(u32 start);
+s32 rtw_get_time_interval_ms(u32 start, u32 end);
+
+void rtw_sleep_schedulable(int ms);
+
+void rtw_msleep_os(int ms);
+void rtw_usleep_os(int us);
+
+u32 rtw_atoi(u8 *s);
+
+void rtw_mdelay_os(int ms);
+void rtw_udelay_os(int us);
+
+void rtw_yield_os(void);
+
+static inline unsigned char _cancel_timer_ex(struct timer_list *ptimer)
+{
+ return del_timer_sync(ptimer);
+}
+
+static __inline void thread_enter(char *name)
+{
+#ifdef daemonize
+ daemonize("%s", name);
+#endif
+ allow_signal(SIGTERM);
+}
+
+static inline void flush_signals_thread(void)
+{
+ if (signal_pending (current))
+ flush_signals(current);
+}
+
+static inline int res_to_status(int res)
+{
+ return res;
+}
+
+#define _RND(sz, r) ((((sz)+((r)-1))/(r))*(r))
+#define RND4(x) (((x >> 2) + (((x & 3) == 0) ? 0: 1)) << 2)
+
+static inline u32 _RND4(u32 sz)
+{
+ u32 val;
+
+ val = ((sz >> 2) + ((sz & 3) ? 1: 0)) << 2;
+ return val;
+}
+
+static inline u32 _RND8(u32 sz)
+{
+ u32 val;
+
+ val = ((sz >> 3) + ((sz & 7) ? 1: 0)) << 3;
+ return val;
+}
+
+static inline u32 _RND128(u32 sz)
+{
+ u32 val;
+
+ val = ((sz >> 7) + ((sz & 127) ? 1: 0)) << 7;
+ return val;
+}
+
+static inline u32 _RND256(u32 sz)
+{
+ u32 val;
+
+ val = ((sz >> 8) + ((sz & 255) ? 1: 0)) << 8;
+ return val;
+}
+
+static inline u32 _RND512(u32 sz)
+{
+ u32 val;
+
+ val = ((sz >> 9) + ((sz & 511) ? 1: 0)) << 9;
+ return val;
+}
+
+static inline u32 bitshift(u32 bitmask)
+{
+ u32 i;
+
+ for (i = 0; i <= 31; i++)
+ if (((bitmask>>i) & 0x1) == 1) break;
+ return i;
+}
+
+/* limitation of path length */
+#define PATH_LENGTH_MAX PATH_MAX
+
+void rtw_suspend_lock_init(void);
+void rtw_suspend_lock_uninit(void);
+void rtw_lock_suspend(void);
+void rtw_unlock_suspend(void);
+
+/* Atomic integer operations */
+#define ATOMIC_T atomic_t
+
+void ATOMIC_SET(ATOMIC_T *v, int i);
+int ATOMIC_READ(ATOMIC_T *v);
+void ATOMIC_ADD(ATOMIC_T *v, int i);
+void ATOMIC_SUB(ATOMIC_T *v, int i);
+void ATOMIC_INC(ATOMIC_T *v);
+void ATOMIC_DEC(ATOMIC_T *v);
+int ATOMIC_ADD_RETURN(ATOMIC_T *v, int i);
+int ATOMIC_SUB_RETURN(ATOMIC_T *v, int i);
+int ATOMIC_INC_RETURN(ATOMIC_T *v);
+int ATOMIC_DEC_RETURN(ATOMIC_T *v);
+
+/* File operation APIs, just for linux now */
+int rtw_is_file_readable(char *path);
+int rtw_retrive_from_file(char *path, u8 __user *buf, u32 sz);
+int rtw_store_to_file(char *path, u8 __user *buf, u32 sz);
+
+struct rtw_netdev_priv_indicator {
+ void *priv;
+ u32 sizeof_priv;
+};
+struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv,
+ void *old_priv);
+struct net_device *rtw_alloc_etherdev(int sizeof_priv);
+
+#define rtw_netdev_priv(netdev) \
+ (((struct rtw_netdev_priv_indicator *)netdev_priv(netdev))->priv)
+void rtw_free_netdev(struct net_device *netdev);
+
+#define NDEV_FMT "%s"
+#define NDEV_ARG(ndev) ndev->name
+#define ADPT_FMT "%s"
+#define ADPT_ARG(adapter) adapter->pnetdev->name
+#define FUNC_NDEV_FMT "%s(%s)"
+#define FUNC_NDEV_ARG(ndev) __func__, ndev->name
+#define FUNC_ADPT_FMT "%s(%s)"
+#define FUNC_ADPT_ARG(adapter) __func__, adapter->pnetdev->name
+
+#define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)),(sig), 1)
+
+u64 rtw_modular64(u64 x, u64 y);
+u64 rtw_division64(u64 x, u64 y);
+
+/* Macros for handling unaligned memory accesses */
+
+#define RTW_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
+#define RTW_PUT_BE16(a, val) \
+ do { \
+ (a)[0] = ((u16) (val)) >> 8; \
+ (a)[1] = ((u16) (val)) & 0xff; \
+ } while (0)
+
+#define RTW_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
+#define RTW_PUT_LE16(a, val) \
+ do { \
+ (a)[1] = ((u16) (val)) >> 8; \
+ (a)[0] = ((u16) (val)) & 0xff; \
+ } while (0)
+
+#define RTW_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
+ ((u32) (a)[2]))
+#define RTW_PUT_BE24(a, val) \
+ do { \
+ (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \
+ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
+ (a)[2] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#define RTW_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
+ (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
+#define RTW_PUT_BE32(a, val) \
+ do { \
+ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \
+ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \
+ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \
+ (a)[3] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#define RTW_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
+ (((u32) (a)[1]) << 8) | ((u32) (a)[0]))
+#define RTW_PUT_LE32(a, val) \
+ do { \
+ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \
+ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \
+ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
+ (a)[0] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#define RTW_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \
+ (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \
+ (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \
+ (((u64) (a)[6]) << 8) | ((u64) (a)[7]))
+#define RTW_PUT_BE64(a, val) \
+ do { \
+ (a)[0] = (u8) (((u64) (val)) >> 56); \
+ (a)[1] = (u8) (((u64) (val)) >> 48); \
+ (a)[2] = (u8) (((u64) (val)) >> 40); \
+ (a)[3] = (u8) (((u64) (val)) >> 32); \
+ (a)[4] = (u8) (((u64) (val)) >> 24); \
+ (a)[5] = (u8) (((u64) (val)) >> 16); \
+ (a)[6] = (u8) (((u64) (val)) >> 8); \
+ (a)[7] = (u8) (((u64) (val)) & 0xff); \
+ } while (0)
+
+#define RTW_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \
+ (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \
+ (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \
+ (((u64) (a)[1]) << 8) | ((u64) (a)[0]))
+
+void rtw_buf_free(u8 **buf, u32 *buf_len);
+void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len);
+
+struct rtw_cbuf {
+ u32 write;
+ u32 read;
+ u32 size;
+ void *bufs[0];
+};
+
+bool rtw_cbuf_full(struct rtw_cbuf *cbuf);
+bool rtw_cbuf_empty(struct rtw_cbuf *cbuf);
+bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf);
+void *rtw_cbuf_pop(struct rtw_cbuf *cbuf);
+struct rtw_cbuf *rtw_cbuf_alloc(u32 size);
+int wifirate2_ratetbl_inx(unsigned char rate);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/recv_osdep.h b/drivers/staging/rtl8188eu/include/recv_osdep.h
new file mode 100644
index 00000000000..69123807807
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/recv_osdep.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RECV_OSDEP_H_
+#define __RECV_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter);
+void _rtw_free_recv_priv(struct recv_priv *precvpriv);
+
+
+s32 rtw_recv_entry(union recv_frame *precv_frame);
+int rtw_recv_indicatepkt(struct adapter *adapter, union recv_frame *recv_frame);
+void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *retpkt);
+
+void rtw_hostapd_mlme_rx(struct adapter *padapter, union recv_frame *recv_fr);
+void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup);
+
+int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter);
+void rtw_free_recv_priv(struct recv_priv *precvpriv);
+
+int rtw_os_recv_resource_init(struct recv_priv *recvpr, struct adapter *adapt);
+int rtw_os_recv_resource_alloc(struct adapter *adapt, union recv_frame *recvfr);
+void rtw_os_recv_resource_free(struct recv_priv *precvpriv);
+
+int rtw_os_recvbuf_resource_alloc(struct adapter *adapt, struct recv_buf *buf);
+int rtw_os_recvbuf_resource_free(struct adapter *adapt, struct recv_buf *buf);
+
+void rtw_os_read_port(struct adapter *padapter, struct recv_buf *precvbuf);
+
+void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl);
+int nat25_handle_frame(struct adapter *priv, struct sk_buff *skb);
+int _netdev_open(struct net_device *pnetdev);
+int netdev_open(struct net_device *pnetdev);
+int netdev_close(struct net_device *pnetdev);
+
+#endif /* */
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h b/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h
new file mode 100644
index 00000000000..b32bc28503d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h
@@ -0,0 +1,122 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_CMD_H__
+#define __RTL8188E_CMD_H__
+
+enum RTL8188E_H2C_CMD_ID {
+ /* Class Common */
+ H2C_COM_RSVD_PAGE = 0x00,
+ H2C_COM_MEDIA_STATUS_RPT = 0x01,
+ H2C_COM_SCAN = 0x02,
+ H2C_COM_KEEP_ALIVE = 0x03,
+ H2C_COM_DISCNT_DECISION = 0x04,
+ H2C_COM_INIT_OFFLOAD = 0x06,
+ H2C_COM_REMOTE_WAKE_CTL = 0x07,
+ H2C_COM_AP_OFFLOAD = 0x08,
+ H2C_COM_BCN_RSVD_PAGE = 0x09,
+ H2C_COM_PROB_RSP_RSVD_PAGE = 0x0A,
+
+ /* Class PS */
+ H2C_PS_PWR_MODE = 0x20,
+ H2C_PS_TUNE_PARA = 0x21,
+ H2C_PS_TUNE_PARA_2 = 0x22,
+ H2C_PS_LPS_PARA = 0x23,
+ H2C_PS_P2P_OFFLOAD = 0x24,
+
+ /* Class DM */
+ H2C_DM_MACID_CFG = 0x40,
+ H2C_DM_TXBF = 0x41,
+
+ /* Class BT */
+ H2C_BT_COEX_MASK = 0x60,
+ H2C_BT_COEX_GPIO_MODE = 0x61,
+ H2C_BT_DAC_SWING_VAL = 0x62,
+ H2C_BT_PSD_RST = 0x63,
+
+ /* Class */
+ H2C_RESET_TSF = 0xc0,
+};
+
+struct cmd_msg_parm {
+ u8 eid; /* element id */
+ u8 sz; /* sz */
+ u8 buf[6];
+};
+
+enum {
+ PWRS
+};
+
+struct setpwrmode_parm {
+ u8 Mode;/* 0:Active,1:LPS,2:WMMPS */
+ u8 SmartPS_RLBM;/* LPS= 0:PS_Poll,1:PS_Poll,2:NullData,WMM= 0:PS_Poll,1:NullData */
+ u8 AwakeInterval; /* unit: beacon interval */
+ u8 bAllQueueUAPSD;
+ u8 PwrState;/* AllON(0x0c),RFON(0x04),RFOFF(0x00) */
+};
+
+struct H2C_SS_RFOFF_PARAM {
+ u8 ROFOn; /* 1: on, 0:off */
+ u16 gpio_period; /* unit: 1024 us */
+} __packed;
+
+struct joinbssrpt_parm {
+ u8 OpMode; /* RT_MEDIA_STATUS */
+};
+
+struct rsvdpage_loc {
+ u8 LocProbeRsp;
+ u8 LocPsPoll;
+ u8 LocNullData;
+ u8 LocQosNull;
+ u8 LocBTQosNull;
+};
+
+struct P2P_PS_Offload_t {
+ u8 Offload_En:1;
+ u8 role:1; /* 1: Owner, 0: Client */
+ u8 CTWindow_En:1;
+ u8 NoA0_En:1;
+ u8 NoA1_En:1;
+ u8 AllStaSleep:1; /* Only valid in Owner */
+ u8 discovery:1;
+ u8 rsvd:1;
+};
+
+struct P2P_PS_CTWPeriod_t {
+ u8 CTWPeriod; /* TU */
+};
+
+/* host message to firmware cmd */
+void rtl8188e_set_FwPwrMode_cmd(struct adapter *padapter, u8 Mode);
+void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *padapter, u8 mstatus);
+u8 rtl8188e_set_rssi_cmd(struct adapter *padapter, u8 *param);
+u8 rtl8188e_set_raid_cmd(struct adapter *padapter, u32 mask);
+void rtl8188e_Add_RateATid(struct adapter *padapter, u32 bitmap, u8 arg,
+ u8 rssi_level);
+
+#ifdef CONFIG_88EU_P2P
+void rtl8188e_set_p2p_ps_offload_cmd(struct adapter *adapt, u8 p2p_ps_state);
+#endif /* CONFIG_88EU_P2P */
+
+void CheckFwRsvdPageContent(struct adapter *adapt);
+void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt);
+
+#endif/* __RTL8188E_CMD_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_dm.h b/drivers/staging/rtl8188eu/include/rtl8188e_dm.h
new file mode 100644
index 00000000000..97a3175250e
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_dm.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_DM_H__
+#define __RTL8188E_DM_H__
+enum{
+ UP_LINK,
+ DOWN_LINK,
+};
+/* duplicate code,will move to ODM ######### */
+#define IQK_MAC_REG_NUM 4
+#define IQK_ADDA_REG_NUM 16
+#define IQK_BB_REG_NUM 9
+#define HP_THERMAL_NUM 8
+/* duplicate code,will move to ODM ######### */
+struct dm_priv {
+ u8 DM_Type;
+ u8 DMFlag;
+ u8 InitDMFlag;
+ u32 InitODMFlag;
+
+ /* Upper and Lower Signal threshold for Rate Adaptive*/
+ int UndecoratedSmoothedPWDB;
+ int UndecoratedSmoothedCCK;
+ int EntryMinUndecoratedSmoothedPWDB;
+ int EntryMaxUndecoratedSmoothedPWDB;
+ int MinUndecoratedPWDBForDM;
+ int LastMinUndecoratedPWDBForDM;
+
+ /* for High Power */
+ u8 bDynamicTxPowerEnable;
+ u8 LastDTPLvl;
+ u8 DynamicTxHighPowerLvl;/* Tx Power Control for Near/Far Range */
+ u8 PowerIndex_backup[6];
+};
+
+void rtl8188e_init_dm_priv(struct adapter *adapt);
+void rtl8188e_deinit_dm_priv(struct adapter *adapt);
+void rtl8188e_InitHalDm(struct adapter *adapt);
+void rtl8188e_HalDmWatchDog(struct adapter *adapt);
+
+void AntDivCompare8188E(struct adapter *adapt, struct wlan_bssid_ex *dst,
+ struct wlan_bssid_ex *src);
+u8 AntDivBeforeLink8188E(struct adapter *adapt);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
new file mode 100644
index 00000000000..52b280165a9
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
@@ -0,0 +1,487 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_HAL_H__
+#define __RTL8188E_HAL_H__
+
+
+/* include HAL Related header after HAL Related compiling flags */
+#include "rtl8188e_spec.h"
+#include "Hal8188EPhyReg.h"
+#include "Hal8188EPhyCfg.h"
+#include "rtl8188e_rf.h"
+#include "rtl8188e_dm.h"
+#include "rtl8188e_recv.h"
+#include "rtl8188e_xmit.h"
+#include "rtl8188e_cmd.h"
+#include "Hal8188EPwrSeq.h"
+#include "rtl8188e_sreset.h"
+#include "rtw_efuse.h"
+
+#include "odm_precomp.h"
+
+/* Fw Array */
+#define Rtl8188E_FwImageArray Rtl8188EFwImgArray
+#define Rtl8188E_FWImgArrayLength Rtl8188EFWImgArrayLength
+
+#define RTL8188E_FW_UMC_IMG "rtl8188E\\rtl8188efw.bin"
+#define RTL8188E_PHY_REG "rtl8188E\\PHY_REG_1T.txt"
+#define RTL8188E_PHY_RADIO_A "rtl8188E\\radio_a_1T.txt"
+#define RTL8188E_PHY_RADIO_B "rtl8188E\\radio_b_1T.txt"
+#define RTL8188E_AGC_TAB "rtl8188E\\AGC_TAB_1T.txt"
+#define RTL8188E_PHY_MACREG "rtl8188E\\MAC_REG.txt"
+#define RTL8188E_PHY_REG_PG "rtl8188E\\PHY_REG_PG.txt"
+#define RTL8188E_PHY_REG_MP "rtl8188E\\PHY_REG_MP.txt"
+
+/* RTL8188E Power Configuration CMDs for USB/SDIO interfaces */
+#define Rtl8188E_NIC_PWR_ON_FLOW rtl8188E_power_on_flow
+#define Rtl8188E_NIC_RF_OFF_FLOW rtl8188E_radio_off_flow
+#define Rtl8188E_NIC_DISABLE_FLOW rtl8188E_card_disable_flow
+#define Rtl8188E_NIC_ENABLE_FLOW rtl8188E_card_enable_flow
+#define Rtl8188E_NIC_SUSPEND_FLOW rtl8188E_suspend_flow
+#define Rtl8188E_NIC_RESUME_FLOW rtl8188E_resume_flow
+#define Rtl8188E_NIC_PDN_FLOW rtl8188E_hwpdn_flow
+#define Rtl8188E_NIC_LPS_ENTER_FLOW rtl8188E_enter_lps_flow
+#define Rtl8188E_NIC_LPS_LEAVE_FLOW rtl8188E_leave_lps_flow
+
+#define DRVINFO_SZ 4 /* unit is 8bytes */
+#define PageNum_128(_Len) (u32)(((_Len)>>7) + ((_Len) & 0x7F ? 1 : 0))
+
+/* download firmware related data structure */
+#define FW_8188E_SIZE 0x4000 /* 16384,16k */
+#define FW_8188E_START_ADDRESS 0x1000
+#define FW_8188E_END_ADDRESS 0x1FFF /* 0x5FFF */
+
+#define MAX_PAGE_SIZE 4096 /* @ page : 4k bytes */
+
+#define IS_FW_HEADER_EXIST(_pFwHdr) \
+ ((le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x92C0 || \
+ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88C0 || \
+ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x2300 || \
+ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88E0)
+
+enum firmware_source {
+ FW_SOURCE_IMG_FILE = 0,
+ FW_SOURCE_HEADER_FILE = 1, /* from header file */
+};
+
+struct rt_firmware {
+ enum firmware_source eFWSource;
+ u8 *szFwBuffer;
+ u32 ulFwLength;
+};
+
+/* This structure must be careful with byte-ordering */
+
+struct rt_firmware_hdr {
+ /* 8-byte alinment required */
+ /* LONG WORD 0 ---- */
+ __le16 Signature; /* 92C0: test chip; 92C,
+ * 88C0: test chip; 88C1: MP A-cut;
+ * 92C1: MP A-cut */
+ u8 Category; /* AP/NIC and USB/PCI */
+ u8 Function; /* Reserved for different FW function
+ * indcation, for further use when
+ * driver needs to download different
+ * FW for different conditions */
+ __le16 Version; /* FW Version */
+ u8 Subversion; /* FW Subversion, default 0x00 */
+ u16 Rsvd1;
+
+ /* LONG WORD 1 ---- */
+ u8 Month; /* Release time Month field */
+ u8 Date; /* Release time Date field */
+ u8 Hour; /* Release time Hour field */
+ u8 Minute; /* Release time Minute field */
+ __le16 RamCodeSize; /* The size of RAM code */
+ u8 Foundry;
+ u8 Rsvd2;
+
+ /* LONG WORD 2 ---- */
+ __le32 SvnIdx; /* The SVN entry index */
+ u32 Rsvd3;
+
+ /* LONG WORD 3 ---- */
+ u32 Rsvd4;
+ u32 Rsvd5;
+};
+
+#define DRIVER_EARLY_INT_TIME 0x05
+#define BCN_DMA_ATIME_INT_TIME 0x02
+
+enum usb_rx_agg_mode {
+ USB_RX_AGG_DISABLE,
+ USB_RX_AGG_DMA,
+ USB_RX_AGG_USB,
+ USB_RX_AGG_MIX
+};
+
+#define MAX_RX_DMA_BUFFER_SIZE_88E \
+ 0x2400 /* 9k for 88E nornal chip , MaxRxBuff=10k-max(TxReportSize(64*8),
+ * WOLPattern(16*24)) */
+
+#define MAX_TX_REPORT_BUFFER_SIZE 0x0400 /* 1k */
+
+
+/* BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */
+#define MAX_TX_QUEUE 9
+
+#define TX_SELE_HQ BIT(0) /* High Queue */
+#define TX_SELE_LQ BIT(1) /* Low Queue */
+#define TX_SELE_NQ BIT(2) /* Normal Queue */
+
+/* Note: We will divide number of page equally for each queue other
+ * than public queue! */
+/* 22k = 22528 bytes = 176 pages (@page = 128 bytes) */
+/* must reserved about 7 pages for LPS => 176-7 = 169 (0xA9) */
+/* 2*BCN / 1*ps-poll / 1*null-data /1*prob_rsp /1*QOS null-data /1*BT QOS
+ * null-data */
+
+#define TX_TOTAL_PAGE_NUMBER_88E 0xA9/* 169 (21632=> 21k) */
+
+#define TX_PAGE_BOUNDARY_88E (TX_TOTAL_PAGE_NUMBER_88E + 1)
+
+/* Note: For Normal Chip Setting ,modify later */
+#define WMM_NORMAL_TX_TOTAL_PAGE_NUMBER \
+ TX_TOTAL_PAGE_NUMBER_88E /* 0xA9 , 0xb0=>176=>22k */
+#define WMM_NORMAL_TX_PAGE_BOUNDARY_88E \
+ (WMM_NORMAL_TX_TOTAL_PAGE_NUMBER + 1) /* 0xA9 */
+
+/* Chip specific */
+#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3)
+#define CHIP_BONDING_92C_1T2R 0x1
+#define CHIP_BONDING_88C_USB_MCARD 0x2
+#define CHIP_BONDING_88C_USB_HP 0x1
+#include "HalVerDef.h"
+#include "hal_com.h"
+
+/* Channel Plan */
+enum ChannelPlan {
+ CHPL_FCC = 0,
+ CHPL_IC = 1,
+ CHPL_ETSI = 2,
+ CHPL_SPA = 3,
+ CHPL_FRANCE = 4,
+ CHPL_MKK = 5,
+ CHPL_MKK1 = 6,
+ CHPL_ISRAEL = 7,
+ CHPL_TELEC = 8,
+ CHPL_GLOBAL = 9,
+ CHPL_WORLD = 10,
+};
+
+struct txpowerinfo24g {
+ u8 IndexCCK_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
+ u8 IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G-1];
+ /* If only one tx, only BW20 and OFDM are used. */
+ s8 CCK_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+ s8 OFDM_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+ s8 BW20_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+ s8 BW40_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+};
+
+#define EFUSE_REAL_CONTENT_LEN 512
+#define EFUSE_MAX_SECTION 16
+#define EFUSE_IC_ID_OFFSET 506 /* For some inferior IC purpose*/
+#define AVAILABLE_EFUSE_ADDR(addr) (addr < EFUSE_REAL_CONTENT_LEN)
+/* To prevent out of boundary programming case, */
+/* leave 1byte and program full section */
+/* 9bytes + 1byt + 5bytes and pre 1byte. */
+/* For worst case: */
+/* | 1byte|----8bytes----|1byte|--5bytes--| */
+/* | | Reserved(14bytes) | */
+
+/* PG data exclude header, dummy 6 bytes frome CP test and reserved 1byte. */
+#define EFUSE_OOB_PROTECT_BYTES 15
+
+#define HWSET_MAX_SIZE_88E 512
+
+#define EFUSE_REAL_CONTENT_LEN_88E 256
+#define EFUSE_MAP_LEN_88E 512
+#define EFUSE_MAP_LEN EFUSE_MAP_LEN_88E
+#define EFUSE_MAX_SECTION_88E 64
+#define EFUSE_MAX_WORD_UNIT_88E 4
+#define EFUSE_IC_ID_OFFSET_88E 506
+#define AVAILABLE_EFUSE_ADDR_88E(addr) \
+ (addr < EFUSE_REAL_CONTENT_LEN_88E)
+/* To prevent out of boundary programming case, leave 1byte and program
+ * full section */
+/* 9bytes + 1byt + 5bytes and pre 1byte. */
+/* For worst case: */
+/* | 2byte|----8bytes----|1byte|--7bytes--| 92D */
+/* PG data exclude header, dummy 7 bytes frome CP test and reserved 1byte. */
+#define EFUSE_OOB_PROTECT_BYTES_88E 18
+#define EFUSE_PROTECT_BYTES_BANK_88E 16
+
+/* EFUSE for BT definition */
+#define EFUSE_BT_REAL_CONTENT_LEN 1536 /* 512*3 */
+#define EFUSE_BT_MAP_LEN 1024 /* 1k bytes */
+#define EFUSE_BT_MAX_SECTION 128 /* 1024/8 */
+
+#define EFUSE_PROTECT_BYTES_BANK 16
+
+/* For RTL8723 WiFi/BT/GPS multi-function configuration. */
+enum rt_multi_func {
+ RT_MULTI_FUNC_NONE = 0x00,
+ RT_MULTI_FUNC_WIFI = 0x01,
+ RT_MULTI_FUNC_BT = 0x02,
+ RT_MULTI_FUNC_GPS = 0x04,
+};
+
+/* For RTL8723 regulator mode. */
+enum rt_regulator_mode {
+ RT_SWITCHING_REGULATOR = 0,
+ RT_LDO_REGULATOR = 1,
+};
+
+struct hal_data_8188e {
+ struct HAL_VERSION VersionID;
+ enum rt_multi_func MultiFunc; /* For multi-function consideration. */
+ enum rt_regulator_mode RegulatorMode; /* switching regulator or LDO */
+ u16 CustomerID;
+
+ u16 FirmwareVersion;
+ u16 FirmwareVersionRev;
+ u16 FirmwareSubVersion;
+ u16 FirmwareSignature;
+ u8 PGMaxGroup;
+ /* current WIFI_PHY values */
+ u32 ReceiveConfig;
+ enum wireless_mode CurrentWirelessMode;
+ enum ht_channel_width CurrentChannelBW;
+ u8 CurrentChannel;
+ u8 nCur40MhzPrimeSC;/* Control channel sub-carrier */
+
+ u16 BasicRateSet;
+
+ /* rf_ctrl */
+ u8 rf_chip;
+ u8 rf_type;
+ u8 NumTotalRFPath;
+
+ u8 BoardType;
+
+ /* EEPROM setting. */
+ u16 EEPROMVID;
+ u16 EEPROMPID;
+ u16 EEPROMSVID;
+ u16 EEPROMSDID;
+ u8 EEPROMCustomerID;
+ u8 EEPROMSubCustomerID;
+ u8 EEPROMVersion;
+ u8 EEPROMRegulatory;
+
+ u8 bTXPowerDataReadFromEEPORM;
+ u8 EEPROMThermalMeter;
+ u8 bAPKThermalMeterIgnore;
+
+ bool EepromOrEfuse;
+ /* 92C:256bytes, 88E:512bytes, we use union set (512bytes) */
+ u8 EfuseMap[2][HWSET_MAX_SIZE_512];
+ u8 EfuseUsedPercentage;
+ struct efuse_hal EfuseHal;
+
+ u8 Index24G_CCK_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+ u8 Index24G_BW40_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+ /* If only one tx, only BW20 and OFDM are used. */
+ s8 CCK_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+ s8 OFDM_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+ s8 BW20_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+ s8 BW40_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+
+ u8 TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+ /* For HT 40MHZ pwr */
+ u8 TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+ /* For HT 40MHZ pwr */
+ u8 TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+ /* HT 20<->40 Pwr diff */
+ u8 TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+ /* For HT<->legacy pwr diff */
+ u8 TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+ /* For power group */
+ u8 PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+ u8 PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+
+ u8 LegacyHTTxPowerDiff;/* Legacy to HT rate power diff */
+ /* The current Tx Power Level */
+ u8 CurrentCckTxPwrIdx;
+ u8 CurrentOfdm24GTxPwrIdx;
+ u8 CurrentBW2024GTxPwrIdx;
+ u8 CurrentBW4024GTxPwrIdx;
+
+
+ /* Read/write are allow for following hardware information variables */
+ u8 framesync;
+ u32 framesyncC34;
+ u8 framesyncMonitor;
+ u8 DefaultInitialGain[4];
+ u8 pwrGroupCnt;
+ u32 MCSTxPowerLevelOriginalOffset[MAX_PG_GROUP][16];
+ u32 CCKTxPowerLevelOriginalOffset;
+
+ u8 CrystalCap;
+ u32 AntennaTxPath; /* Antenna path Tx */
+ u32 AntennaRxPath; /* Antenna path Rx */
+ u8 BluetoothCoexist;
+ u8 ExternalPA;
+
+ u8 bLedOpenDrain; /* Open-drain support for controlling the LED.*/
+
+ u8 b1x1RecvCombine; /* for 1T1R receive combining */
+
+ u32 AcParam_BE; /* Original parameter for BE, use for EDCA turbo. */
+
+ struct bb_reg_def PHYRegDef[4]; /* Radio A/B/C/D */
+
+ u32 RfRegChnlVal[2];
+
+ /* RDG enable */
+ bool bRDGEnable;
+
+ /* for host message to fw */
+ u8 LastHMEBoxNum;
+
+ u8 fw_ractrl;
+ u8 RegTxPause;
+ /* Beacon function related global variable. */
+ u32 RegBcnCtrlVal;
+ u8 RegFwHwTxQCtrl;
+ u8 RegReg542;
+ u8 RegCR_1;
+
+ struct dm_priv dmpriv;
+ struct odm_dm_struct odmpriv;
+ struct sreset_priv srestpriv;
+
+ u8 CurAntenna;
+ u8 AntDivCfg;
+ u8 TRxAntDivType;
+
+
+ u8 bDumpRxPkt;/* for debug */
+ u8 bDumpTxPkt;/* for debug */
+ u8 FwRsvdPageStartOffset; /* Reserve page start offset except
+ * beacon in TxQ. */
+
+ /* 2010/08/09 MH Add CU power down mode. */
+ bool pwrdown;
+
+ /* Add for dual MAC 0--Mac0 1--Mac1 */
+ u32 interfaceIndex;
+
+ u8 OutEpQueueSel;
+ u8 OutEpNumber;
+
+ /* Add for USB aggreation mode dynamic shceme. */
+ bool UsbRxHighSpeedMode;
+
+ /* 2010/11/22 MH Add for slim combo debug mode selective. */
+ /* This is used for fix the drawback of CU TSMC-A/UMC-A cut.
+ * HW auto suspend ability. Close BT clock. */
+ bool SlimComboDbg;
+
+ u16 EfuseUsedBytes;
+
+#ifdef CONFIG_88EU_P2P
+ struct P2P_PS_Offload_t p2p_ps_offload;
+#endif
+
+ /* Auto FSM to Turn On, include clock, isolation, power control
+ * for MAC only */
+ u8 bMacPwrCtrlOn;
+
+ u32 UsbBulkOutSize;
+
+ /* Interrupt relatd register information. */
+ u32 IntArray[3];/* HISR0,HISR1,HSISR */
+ u32 IntrMask[3];
+ u8 C2hArray[16];
+ u8 UsbTxAggMode;
+ u8 UsbTxAggDescNum;
+ u16 HwRxPageSize; /* Hardware setting */
+ u32 MaxUsbRxAggBlock;
+
+ enum usb_rx_agg_mode UsbRxAggMode;
+ u8 UsbRxAggBlockCount; /* USB Block count. Block size is
+ * 512-byte in high speed and 64-byte
+ * in full speed */
+ u8 UsbRxAggBlockTimeout;
+ u8 UsbRxAggPageCount; /* 8192C DMA page count */
+ u8 UsbRxAggPageTimeout;
+};
+
+#define GET_HAL_DATA(__pAdapter) \
+ ((struct hal_data_8188e *)((__pAdapter)->HalData))
+#define GET_RF_TYPE(priv) (GET_HAL_DATA(priv)->rf_type)
+
+#define INCLUDE_MULTI_FUNC_BT(_Adapter) \
+ (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_BT)
+#define INCLUDE_MULTI_FUNC_GPS(_Adapter) \
+ (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_GPS)
+
+/* rtl8188e_hal_init.c */
+s32 rtl8188e_FirmwareDownload(struct adapter *padapter);
+void _8051Reset88E(struct adapter *padapter);
+void rtl8188e_InitializeFirmwareVars(struct adapter *padapter);
+
+
+s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy);
+
+/* EFuse */
+u8 GetEEPROMSize8188E(struct adapter *padapter);
+void Hal_InitPGData88E(struct adapter *padapter);
+void Hal_EfuseParseIDCode88E(struct adapter *padapter, u8 *hwinfo);
+void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *hwinfo,
+ bool AutoLoadFail);
+
+void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo,
+ bool AutoLoadFail);
+void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo,
+ bool AutoLoadFail);
+void Hal_EfuseParseCustomerID88E(struct adapter *padapter, u8 *hwinfo,
+ bool AutoLoadFail);
+void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter,u8 *PROMContent,
+ bool AutoLoadFail);
+void Hal_ReadThermalMeter_88E(struct adapter * dapter, u8 *PROMContent,
+ bool AutoloadFail);
+void Hal_EfuseParseXtal_8188E(struct adapter *pAdapter, u8 *hwinfo,
+ bool AutoLoadFail);
+void Hal_EfuseParseBoardType88E(struct adapter *pAdapter, u8 *hwinfo,
+ bool AutoLoadFail);
+void Hal_ReadPowerSavingMode88E(struct adapter *pAdapter, u8 *hwinfo,
+ bool AutoLoadFail);
+
+bool HalDetectPwrDownMode88E(struct adapter *Adapter);
+
+void Hal_InitChannelPlan(struct adapter *padapter);
+void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc);
+
+/* register */
+void SetBcnCtrlReg(struct adapter *padapter, u8 SetBits, u8 ClearBits);
+
+void rtl8188e_clone_haldata(struct adapter *dst, struct adapter *src);
+void rtl8188e_start_thread(struct adapter *padapter);
+void rtl8188e_stop_thread(struct adapter *padapter);
+
+void rtw_IOL_cmd_tx_pkt_buf_dump(struct adapter *Adapter, int len);
+s32 rtl8188e_iol_efuse_patch(struct adapter *padapter);
+void rtw_cancel_all_timer(struct adapter *padapter);
+void _ps_open_RF(struct adapter *adapt);
+
+#endif /* __RTL8188E_HAL_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_led.h b/drivers/staging/rtl8188eu/include/rtl8188e_led.h
new file mode 100644
index 00000000000..c0147e73cd8
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_led.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_LED_H__
+#define __RTL8188E_LED_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+/* */
+/* Interface to manipulate LED objects. */
+/* */
+void rtl8188eu_InitSwLeds(struct adapter *padapter);
+void rtl8188eu_DeInitSwLeds(struct adapter *padapter);
+void SwLedOn(struct adapter *padapter, struct LED_871x *pLed);
+void SwLedOff(struct adapter *padapter, struct LED_871x *pLed);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_recv.h b/drivers/staging/rtl8188eu/include/rtl8188e_recv.h
new file mode 100644
index 00000000000..02ccb404f53
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_recv.h
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_RECV_H__
+#define __RTL8188E_RECV_H__
+
+#define TX_RPT1_PKT_LEN 8
+
+#define RECV_BLK_SZ 512
+#define RECV_BLK_CNT 16
+#define RECV_BLK_TH RECV_BLK_CNT
+#define RECV_BULK_IN_ADDR 0x80
+#define RECV_INT_IN_ADDR 0x81
+
+#define NR_PREALLOC_RECV_SKB (8)
+
+#define NR_RECVBUFF (4)
+
+#define MAX_RECVBUF_SZ (15360) /* 15k < 16k */
+
+struct phy_stat {
+ unsigned int phydw0;
+ unsigned int phydw1;
+ unsigned int phydw2;
+ unsigned int phydw3;
+ unsigned int phydw4;
+ unsigned int phydw5;
+ unsigned int phydw6;
+ unsigned int phydw7;
+};
+
+/* Rx smooth factor */
+#define Rx_Smooth_Factor (20)
+
+enum rx_packet_type {
+ NORMAL_RX,/* Normal rx packet */
+ TX_REPORT1,/* CCX */
+ TX_REPORT2,/* TX RPT */
+ HIS_REPORT,/* USB HISR RPT */
+};
+
+#define INTERRUPT_MSG_FORMAT_LEN 60
+void rtl8188eu_init_recvbuf(struct adapter *padapter, struct recv_buf *buf);
+s32 rtl8188eu_init_recv_priv(struct adapter *padapter);
+void rtl8188eu_free_recv_priv(struct adapter * padapter);
+void rtl8188eu_recv_hdl(struct adapter * padapter, struct recv_buf *precvbuf);
+void rtl8188eu_recv_tasklet(void *priv);
+void rtl8188e_query_rx_phy_status(union recv_frame *fr, struct phy_stat *phy);
+void rtl8188e_process_phy_info(struct adapter * padapter, void *prframe);
+void update_recvframe_phyinfo_88e(union recv_frame *fra, struct phy_stat *phy);
+void update_recvframe_attrib_88e(union recv_frame *fra, struct recv_stat *stat);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_rf.h b/drivers/staging/rtl8188eu/include/rtl8188e_rf.h
new file mode 100644
index 00000000000..10fc356e020
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_rf.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_RF_H__
+#define __RTL8188E_RF_H__
+
+#define RF6052_MAX_TX_PWR 0x3F
+#define RF6052_MAX_REG 0x3F
+#define RF6052_MAX_PATH 2
+
+
+int PHY_RF6052_Config8188E(struct adapter *Adapter);
+void rtl8188e_RF_ChangeTxPath(struct adapter *Adapter, u16 DataRate);
+void rtl8188e_PHY_RF6052SetBandwidth(struct adapter *Adapter,
+ enum ht_channel_width Bandwidth);
+void rtl8188e_PHY_RF6052SetCckTxPower(struct adapter *Adapter, u8 *level);
+void rtl8188e_PHY_RF6052SetOFDMTxPower(struct adapter *Adapter, u8 *ofdm,
+ u8 *pwrbw20, u8 *pwrbw40, u8 channel);
+
+#endif/* __RTL8188E_RF_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_spec.h b/drivers/staging/rtl8188eu/include/rtl8188e_spec.h
new file mode 100644
index 00000000000..c12c56b9734
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_spec.h
@@ -0,0 +1,1439 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *******************************************************************************/
+#ifndef __RTL8188E_SPEC_H__
+#define __RTL8188E_SPEC_H__
+
+#ifndef BIT
+#define BIT(x) (1 << (x))
+#endif
+
+#define BIT0 0x00000001
+#define BIT1 0x00000002
+#define BIT2 0x00000004
+#define BIT3 0x00000008
+#define BIT4 0x00000010
+#define BIT5 0x00000020
+#define BIT6 0x00000040
+#define BIT7 0x00000080
+#define BIT8 0x00000100
+#define BIT9 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+
+/* 8192C Regsiter offset definition */
+
+#define HAL_PS_TIMER_INT_DELAY 50 /* 50 microseconds */
+#define HAL_92C_NAV_UPPER_UNIT 128 /* micro-second */
+
+#define MAC_ADDR_LEN 6
+/* 8188E PKT_BUFF_ACCESS_CTRL value */
+#define TXPKT_BUF_SELECT 0x69
+#define RXPKT_BUF_SELECT 0xA5
+#define DISABLE_TRXPKT_BUF_ACCESS 0x0
+
+
+/* 0x0000h ~ 0x00FFh System Configuration */
+#define REG_SYS_ISO_CTRL 0x0000
+#define REG_SYS_FUNC_EN 0x0002
+#define REG_APS_FSMCO 0x0004
+#define REG_SYS_CLKR 0x0008
+#define REG_9346CR 0x000A
+#define REG_EE_VPD 0x000C
+#define REG_AFE_MISC 0x0010
+#define REG_SPS0_CTRL 0x0011
+#define REG_SPS_OCP_CFG 0x0018
+#define REG_RSV_CTRL 0x001C
+#define REG_RF_CTRL 0x001F
+#define REG_LDOA15_CTRL 0x0020
+#define REG_LDOV12D_CTRL 0x0021
+#define REG_LDOHCI12_CTRL 0x0022
+#define REG_LPLDO_CTRL 0x0023
+#define REG_AFE_XTAL_CTRL 0x0024
+#define REG_AFE_PLL_CTRL 0x0028
+#define REG_APE_PLL_CTRL_EXT 0x002c
+#define REG_EFUSE_CTRL 0x0030
+#define REG_EFUSE_TEST 0x0034
+#define REG_GPIO_MUXCFG 0x0040
+#define REG_GPIO_IO_SEL 0x0042
+#define REG_MAC_PINMUX_CFG 0x0043
+#define REG_GPIO_PIN_CTRL 0x0044
+#define REG_GPIO_INTM 0x0048
+#define REG_LEDCFG0 0x004C
+#define REG_LEDCFG1 0x004D
+#define REG_LEDCFG2 0x004E
+#define REG_LEDCFG3 0x004F
+#define REG_FSIMR 0x0050
+#define REG_FSISR 0x0054
+#define REG_HSIMR 0x0058
+#define REG_HSISR 0x005c
+#define REG_GPIO_PIN_CTRL_2 0x0060 /* RTL8723 WIFI/BT/GPS
+ * Multi-Function GPIO Pin Control. */
+#define REG_GPIO_IO_SEL_2 0x0062 /* RTL8723 WIFI/BT/GPS
+ * Multi-Function GPIO Select. */
+#define REG_BB_PAD_CTRL 0x0064
+#define REG_MULTI_FUNC_CTRL 0x0068 /* RTL8723 WIFI/BT/GPS
+ * Multi-Function control source. */
+#define REG_GPIO_OUTPUT 0x006c
+#define REG_AFE_XTAL_CTRL_EXT 0x0078 /* RTL8188E */
+#define REG_XCK_OUT_CTRL 0x007c /* RTL8188E */
+#define REG_MCUFWDL 0x0080
+#define REG_WOL_EVENT 0x0081 /* RTL8188E */
+#define REG_MCUTSTCFG 0x0084
+#define REG_HMEBOX_E0 0x0088
+#define REG_HMEBOX_E1 0x008A
+#define REG_HMEBOX_E2 0x008C
+#define REG_HMEBOX_E3 0x008E
+#define REG_HMEBOX_EXT_0 0x01F0
+#define REG_HMEBOX_EXT_1 0x01F4
+#define REG_HMEBOX_EXT_2 0x01F8
+#define REG_HMEBOX_EXT_3 0x01FC
+#define REG_HIMR_88E 0x00B0
+#define REG_HISR_88E 0x00B4
+#define REG_HIMRE_88E 0x00B8
+#define REG_HISRE_88E 0x00BC
+#define REG_EFUSE_ACCESS 0x00CF /* Efuse access protection
+ * for RTL8723 */
+#define REG_BIST_SCAN 0x00D0
+#define REG_BIST_RPT 0x00D4
+#define REG_BIST_ROM_RPT 0x00D8
+#define REG_USB_SIE_INTF 0x00E0
+#define REG_PCIE_MIO_INTF 0x00E4
+#define REG_PCIE_MIO_INTD 0x00E8
+#define REG_HPON_FSM 0x00EC
+#define REG_SYS_CFG 0x00F0
+#define REG_GPIO_OUTSTS 0x00F4 /* For RTL8723 only. */
+#define REG_TYPE_ID 0x00FC
+
+#define REG_MAC_PHY_CTRL_NORMAL 0x00f8
+
+/* 0x0100h ~ 0x01FFh MACTOP General Configuration */
+#define REG_CR 0x0100
+#define REG_PBP 0x0104
+#define REG_PKT_BUFF_ACCESS_CTRL 0x0106
+#define REG_TRXDMA_CTRL 0x010C
+#define REG_TRXFF_BNDY 0x0114
+#define REG_TRXFF_STATUS 0x0118
+#define REG_RXFF_PTR 0x011C
+/* define REG_HIMR 0x0120 */
+/* define REG_HISR 0x0124 */
+#define REG_HIMRE 0x0128
+#define REG_HISRE 0x012C
+#define REG_CPWM 0x012F
+#define REG_FWIMR 0x0130
+#define REG_FTIMR 0x0138
+#define REG_FWISR 0x0134
+#define REG_PKTBUF_DBG_CTRL 0x0140
+#define REG_PKTBUF_DBG_ADDR (REG_PKTBUF_DBG_CTRL)
+#define REG_RXPKTBUF_DBG (REG_PKTBUF_DBG_CTRL+2)
+#define REG_TXPKTBUF_DBG (REG_PKTBUF_DBG_CTRL+3)
+#define REG_RXPKTBUF_CTRL (REG_PKTBUF_DBG_CTRL+2)
+#define REG_PKTBUF_DBG_DATA_L 0x0144
+#define REG_PKTBUF_DBG_DATA_H 0x0148
+
+#define REG_TC0_CTRL 0x0150
+#define REG_TC1_CTRL 0x0154
+#define REG_TC2_CTRL 0x0158
+#define REG_TC3_CTRL 0x015C
+#define REG_TC4_CTRL 0x0160
+#define REG_TCUNIT_BASE 0x0164
+#define REG_MBIST_START 0x0174
+#define REG_MBIST_DONE 0x0178
+#define REG_MBIST_FAIL 0x017C
+#define REG_32K_CTRL 0x0194 /* RTL8188E */
+#define REG_C2HEVT_MSG_NORMAL 0x01A0
+#define REG_C2HEVT_CLEAR 0x01AF
+#define REG_MCUTST_1 0x01c0
+#define REG_FMETHR 0x01C8
+#define REG_HMETFR 0x01CC
+#define REG_HMEBOX_0 0x01D0
+#define REG_HMEBOX_1 0x01D4
+#define REG_HMEBOX_2 0x01D8
+#define REG_HMEBOX_3 0x01DC
+
+#define REG_LLT_INIT 0x01E0
+
+/* 0x0200h ~ 0x027Fh TXDMA Configuration */
+#define REG_RQPN 0x0200
+#define REG_FIFOPAGE 0x0204
+#define REG_TDECTRL 0x0208
+#define REG_TXDMA_OFFSET_CHK 0x020C
+#define REG_TXDMA_STATUS 0x0210
+#define REG_RQPN_NPQ 0x0214
+
+/* 0x0280h ~ 0x02FFh RXDMA Configuration */
+#define REG_RXDMA_AGG_PG_TH 0x0280
+#define REG_RXPKT_NUM 0x0284
+#define REG_RXDMA_STATUS 0x0288
+
+/* 0x0300h ~ 0x03FFh PCIe */
+#define REG_PCIE_CTRL_REG 0x0300
+#define REG_INT_MIG 0x0304 /* Interrupt Migration */
+#define REG_BCNQ_DESA 0x0308 /* TX Beacon Descr Address */
+#define REG_HQ_DESA 0x0310 /* TX High Queue Descr Addr */
+#define REG_MGQ_DESA 0x0318 /* TX Manage Queue Descr Addr*/
+#define REG_VOQ_DESA 0x0320 /* TX VO Queue Descr Addr */
+#define REG_VIQ_DESA 0x0328 /* TX VI Queue Descr Addr */
+#define REG_BEQ_DESA 0x0330 /* TX BE Queue Descr Addr */
+#define REG_BKQ_DESA 0x0338 /* TX BK Queue Descr Addr */
+#define REG_RX_DESA 0x0340 /* RX Queue Descr Addr */
+#define REG_MDIO 0x0354 /* MDIO for Access PCIE PHY */
+#define REG_DBG_SEL 0x0360 /* Debug Selection Register */
+#define REG_PCIE_HRPWM 0x0361 /* PCIe RPWM */
+#define REG_PCIE_HCPWM 0x0363 /* PCIe CPWM */
+#define REG_WATCH_DOG 0x0368
+
+/* RTL8723 series ------------------------------ */
+#define REG_PCIE_HISR 0x03A0
+
+/* spec version 11 */
+/* 0x0400h ~ 0x047Fh Protocol Configuration */
+#define REG_VOQ_INFORMATION 0x0400
+#define REG_VIQ_INFORMATION 0x0404
+#define REG_BEQ_INFORMATION 0x0408
+#define REG_BKQ_INFORMATION 0x040C
+#define REG_MGQ_INFORMATION 0x0410
+#define REG_HGQ_INFORMATION 0x0414
+#define REG_BCNQ_INFORMATION 0x0418
+#define REG_TXPKT_EMPTY 0x041A
+
+#define REG_CPU_MGQ_INFORMATION 0x041C
+#define REG_FWHW_TXQ_CTRL 0x0420
+#define REG_HWSEQ_CTRL 0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY 0x0424
+#define REG_TXPKTBUF_MGQ_BDNY 0x0425
+#define REG_LIFETIME_EN 0x0426
+#define REG_MULTI_BCNQ_OFFSET 0x0427
+#define REG_SPEC_SIFS 0x0428
+#define REG_RL 0x042A
+#define REG_DARFRC 0x0430
+#define REG_RARFRC 0x0438
+#define REG_RRSR 0x0440
+#define REG_ARFR0 0x0444
+#define REG_ARFR1 0x0448
+#define REG_ARFR2 0x044C
+#define REG_ARFR3 0x0450
+#define REG_AGGLEN_LMT 0x0458
+#define REG_AMPDU_MIN_SPACE 0x045C
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D
+#define REG_FAST_EDCA_CTRL 0x0460
+#define REG_RD_RESP_PKT_TH 0x0463
+#define REG_INIRTS_RATE_SEL 0x0480
+/* define REG_INIDATA_RATE_SEL 0x0484 */
+#define REG_POWER_STATUS 0x04A4
+#define REG_POWER_STAGE1 0x04B4
+#define REG_POWER_STAGE2 0x04B8
+#define REG_PKT_VO_VI_LIFE_TIME 0x04C0
+#define REG_PKT_BE_BK_LIFE_TIME 0x04C2
+#define REG_STBC_SETTING 0x04C4
+#define REG_PROT_MODE_CTRL 0x04C8
+#define REG_MAX_AGGR_NUM 0x04CA
+#define REG_RTS_MAX_AGGR_NUM 0x04CB
+#define REG_BAR_MODE_CTRL 0x04CC
+#define REG_RA_TRY_RATE_AGG_LMT 0x04CF
+#define REG_EARLY_MODE_CONTROL 0x4D0
+#define REG_NQOS_SEQ 0x04DC
+#define REG_QOS_SEQ 0x04DE
+#define REG_NEED_CPU_HANDLE 0x04E0
+#define REG_PKT_LOSE_RPT 0x04E1
+#define REG_PTCL_ERR_STATUS 0x04E2
+#define REG_TX_RPT_CTRL 0x04EC
+#define REG_TX_RPT_TIME 0x04F0 /* 2 byte */
+#define REG_DUMMY 0x04FC
+
+/* 0x0500h ~ 0x05FFh EDCA Configuration */
+#define REG_EDCA_VO_PARAM 0x0500
+#define REG_EDCA_VI_PARAM 0x0504
+#define REG_EDCA_BE_PARAM 0x0508
+#define REG_EDCA_BK_PARAM 0x050C
+#define REG_BCNTCFG 0x0510
+#define REG_PIFS 0x0512
+#define REG_RDG_PIFS 0x0513
+#define REG_SIFS_CTX 0x0514
+#define REG_SIFS_TRX 0x0516
+#define REG_TSFTR_SYN_OFFSET 0x0518
+#define REG_AGGR_BREAK_TIME 0x051A
+#define REG_SLOT 0x051B
+#define REG_TX_PTCL_CTRL 0x0520
+#define REG_TXPAUSE 0x0522
+#define REG_DIS_TXREQ_CLR 0x0523
+#define REG_RD_CTRL 0x0524
+/* Format for offset 540h-542h: */
+/* [3:0]: TBTT prohibit setup in unit of 32us. The time for HW getting
+ * beacon content before TBTT. */
+/* [7:4]: Reserved. */
+/* [19:8]: TBTT prohibit hold in unit of 32us. The time for HW holding
+ * to send the beacon packet. */
+/* [23:20]: Reserved */
+/* Description: */
+/* | */
+/* |<--Setup--|--Hold------------>| */
+/* --------------|---------------------- */
+/* | */
+/* TBTT */
+/* Note: We cannot update beacon content to HW or send any AC packets during
+ * the time between Setup and Hold. */
+#define REG_TBTT_PROHIBIT 0x0540
+#define REG_RD_NAV_NXT 0x0544
+#define REG_NAV_PROT_LEN 0x0546
+#define REG_BCN_CTRL 0x0550
+#define REG_BCN_CTRL_1 0x0551
+#define REG_MBID_NUM 0x0552
+#define REG_DUAL_TSF_RST 0x0553
+#define REG_BCN_INTERVAL 0x0554
+#define REG_DRVERLYINT 0x0558
+#define REG_BCNDMATIM 0x0559
+#define REG_ATIMWND 0x055A
+#define REG_BCN_MAX_ERR 0x055D
+#define REG_RXTSF_OFFSET_CCK 0x055E
+#define REG_RXTSF_OFFSET_OFDM 0x055F
+#define REG_TSFTR 0x0560
+#define REG_TSFTR1 0x0568
+#define REG_ATIMWND_1 0x0570
+#define REG_PSTIMER 0x0580
+#define REG_TIMER0 0x0584
+#define REG_TIMER1 0x0588
+#define REG_ACMHWCTRL 0x05C0
+
+/* define REG_FW_TSF_SYNC_CNT 0x04A0 */
+#define REG_FW_RESET_TSF_CNT_1 0x05FC
+#define REG_FW_RESET_TSF_CNT_0 0x05FD
+#define REG_FW_BCN_DIS_CNT 0x05FE
+
+/* 0x0600h ~ 0x07FFh WMAC Configuration */
+#define REG_APSD_CTRL 0x0600
+#define REG_BWOPMODE 0x0603
+#define REG_TCR 0x0604
+#define REG_RCR 0x0608
+#define REG_RX_PKT_LIMIT 0x060C
+#define REG_RX_DLK_TIME 0x060D
+#define REG_RX_DRVINFO_SZ 0x060F
+
+#define REG_MACID 0x0610
+#define REG_BSSID 0x0618
+#define REG_MAR 0x0620
+#define REG_MBIDCAMCFG 0x0628
+
+#define REG_USTIME_EDCA 0x0638
+#define REG_MAC_SPEC_SIFS 0x063A
+
+/* 20100719 Joseph: Hardware register definition change. (HW datasheet v54) */
+/* [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */
+#define REG_R2T_SIFS 0x063C
+/* [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */
+#define REG_T2T_SIFS 0x063E
+#define REG_ACKTO 0x0640
+#define REG_CTS2TO 0x0641
+#define REG_EIFS 0x0642
+
+/* RXERR_RPT */
+#define RXERR_TYPE_OFDM_PPDU 0
+#define RXERR_TYPE_OFDM_false_ALARM 1
+#define RXERR_TYPE_OFDM_MPDU_OK 2
+#define RXERR_TYPE_OFDM_MPDU_FAIL 3
+#define RXERR_TYPE_CCK_PPDU 4
+#define RXERR_TYPE_CCK_false_ALARM 5
+#define RXERR_TYPE_CCK_MPDU_OK 6
+#define RXERR_TYPE_CCK_MPDU_FAIL 7
+#define RXERR_TYPE_HT_PPDU 8
+#define RXERR_TYPE_HT_false_ALARM 9
+#define RXERR_TYPE_HT_MPDU_TOTAL 10
+#define RXERR_TYPE_HT_MPDU_OK 11
+#define RXERR_TYPE_HT_MPDU_FAIL 12
+#define RXERR_TYPE_RX_FULL_DROP 15
+
+#define RXERR_COUNTER_MASK 0xFFFFF
+#define RXERR_RPT_RST BIT(27)
+#define _RXERR_RPT_SEL(type) ((type) << 28)
+
+/* Note: */
+/* The NAV upper value is very important to WiFi 11n 5.2.3 NAV test.
+ * The default value is always too small, but the WiFi TestPlan test
+ * by 25,000 microseconds of NAV through sending CTS in the air.
+ * We must update this value greater than 25,000 microseconds to pass
+ * the item. The offset of NAV_UPPER in 8192C Spec is incorrect, and
+ * the offset should be 0x0652. */
+#define REG_NAV_UPPER 0x0652 /* unit of 128 */
+
+/* WMA, BA, CCX */
+/* define REG_NAV_CTRL 0x0650 */
+#define REG_BACAMCMD 0x0654
+#define REG_BACAMCONTENT 0x0658
+#define REG_LBDLY 0x0660
+#define REG_FWDLY 0x0661
+#define REG_RXERR_RPT 0x0664
+#define REG_WMAC_TRXPTCL_CTL 0x0668
+
+/* Security */
+#define REG_CAMCMD 0x0670
+#define REG_CAMWRITE 0x0674
+#define REG_CAMREAD 0x0678
+#define REG_CAMDBG 0x067C
+#define REG_SECCFG 0x0680
+
+/* Power */
+#define REG_WOW_CTRL 0x0690
+#define REG_PS_RX_INFO 0x0692
+#define REG_UAPSD_TID 0x0693
+#define REG_WKFMCAM_CMD 0x0698
+#define REG_WKFMCAM_NUM_88E 0x698
+#define REG_RXFLTMAP0 0x06A0
+#define REG_RXFLTMAP1 0x06A2
+#define REG_RXFLTMAP2 0x06A4
+#define REG_BCN_PSR_RPT 0x06A8
+#define REG_BT_COEX_TABLE 0x06C0
+
+/* Hardware Port 2 */
+#define REG_MACID1 0x0700
+#define REG_BSSID1 0x0708
+
+/* 0xFE00h ~ 0xFE55h USB Configuration */
+#define REG_USB_INFO 0xFE17
+#define REG_USB_SPECIAL_OPTION 0xFE55
+#define REG_USB_DMA_AGG_TO 0xFE5B
+#define REG_USB_AGG_TO 0xFE5C
+#define REG_USB_AGG_TH 0xFE5D
+
+/* For normal chip */
+#define REG_NORMAL_SIE_VID 0xFE60 /* 0xFE60~0xFE61 */
+#define REG_NORMAL_SIE_PID 0xFE62 /* 0xFE62~0xFE63 */
+#define REG_NORMAL_SIE_OPTIONAL 0xFE64
+#define REG_NORMAL_SIE_EP 0xFE65 /* 0xFE65~0xFE67 */
+#define REG_NORMAL_SIE_PHY 0xFE68 /* 0xFE68~0xFE6B */
+#define REG_NORMAL_SIE_OPTIONAL2 0xFE6C
+#define REG_NORMAL_SIE_GPS_EP 0xFE6D /* 0xFE6D, for RTL8723 only. */
+#define REG_NORMAL_SIE_MAC_ADDR 0xFE70 /* 0xFE70~0xFE75 */
+#define REG_NORMAL_SIE_STRING 0xFE80 /* 0xFE80~0xFEDF */
+
+/* TODO: use these definition when using REG_xxx naming rule. */
+/* NOTE: DO NOT Remove these definition. Use later. */
+
+#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */
+#define EFUSE_TEST REG_EFUSE_TEST /* E-Fuse Test. */
+#define MSR (REG_CR + 2) /* Media Status reg */
+#define ISR REG_HISR_88E
+/* Timing Sync Function Timer Register. */
+#define TSFR REG_TSFTR
+
+#define PBP REG_PBP
+
+/* Redifine MACID register, to compatible prior ICs. */
+/* MAC ID Register, Offset 0x0050-0x0053 */
+#define IDR0 REG_MACID
+/* MAC ID Register, Offset 0x0054-0x0055 */
+#define IDR4 (REG_MACID + 4)
+
+/* 9. Security Control Registers (Offset: ) */
+/* IN 8190 Data Sheet is called CAMcmd */
+#define RWCAM REG_CAMCMD
+/* Software write CAM input content */
+#define WCAMI REG_CAMWRITE
+/* Software read/write CAM config */
+#define RCAMO REG_CAMREAD
+#define CAMDBG REG_CAMDBG
+/* Security Configuration Register */
+#define SECR REG_SECCFG
+
+/* Unused register */
+#define UnusedRegister 0x1BF
+#define DCAM UnusedRegister
+#define PSR UnusedRegister
+#define BBAddr UnusedRegister
+#define PhyDataR UnusedRegister
+
+/* Min Spacing related settings. */
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+/* EEPROM enable when set 1 */
+#define CmdEEPROM_En BIT5
+/* System EEPROM select, 0: boot from E-FUSE, 1: The EEPROM used is 9346 */
+#define CmdEERPOMSEL BIT4
+#define Cmd9346CR_9356SEL BIT4
+
+/* 8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) */
+#define GPIOSEL_GPIO 0
+#define GPIOSEL_ENBT BIT5
+
+/* 8192C GPIO PIN Control Register (offset 0x44, 4 byte) */
+/* GPIO pins input value */
+#define GPIO_IN REG_GPIO_PIN_CTRL
+/* GPIO pins output value */
+#define GPIO_OUT (REG_GPIO_PIN_CTRL+1)
+/* GPIO pins output enable when a bit is set to "1"; otherwise,
+ * input is configured. */
+#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2)
+#define GPIO_MOD (REG_GPIO_PIN_CTRL+3)
+
+/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */
+#define HSIMR_GPIO12_0_INT_EN BIT0
+#define HSIMR_SPS_OCP_INT_EN BIT5
+#define HSIMR_RON_INT_EN BIT6
+#define HSIMR_PDN_INT_EN BIT7
+#define HSIMR_GPIO9_INT_EN BIT25
+
+/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
+#define HSISR_GPIO12_0_INT BIT0
+#define HSISR_SPS_OCP_INT BIT5
+#define HSISR_RON_INT_EN BIT6
+#define HSISR_PDNINT BIT7
+#define HSISR_GPIO9_INT BIT25
+
+/* 8192C (MSR) Media Status Register (Offset 0x4C, 8 bits) */
+/*
+Network Type
+00: No link
+01: Link in ad hoc network
+10: Link in infrastructure network
+11: AP mode
+Default: 00b.
+*/
+#define MSR_NOLINK 0x00
+#define MSR_ADHOC 0x01
+#define MSR_INFRA 0x02
+#define MSR_AP 0x03
+
+/* 88EU (MSR) Media Status Register (Offset 0x4C, 8 bits) */
+#define USB_INTR_CONTENT_C2H_OFFSET 0
+#define USB_INTR_CONTENT_CPWM1_OFFSET 16
+#define USB_INTR_CONTENT_CPWM2_OFFSET 20
+#define USB_INTR_CONTENT_HISR_OFFSET 48
+#define USB_INTR_CONTENT_HISRE_OFFSET 52
+
+/* 88E Driver Initialization Offload REG_FDHM0(Offset 0x88, 8 bits) */
+/* IOL config for REG_FDHM0(Reg0x88) */
+#define CMD_INIT_LLT BIT0
+#define CMD_READ_EFUSE_MAP BIT1
+#define CMD_EFUSE_PATCH BIT2
+#define CMD_IOCONFIG BIT3
+#define CMD_INIT_LLT_ERR BIT4
+#define CMD_READ_EFUSE_MAP_ERR BIT5
+#define CMD_EFUSE_PATCH_ERR BIT6
+#define CMD_IOCONFIG_ERR BIT7
+
+/* 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) */
+/* 8192C Response Rate Set Register (offset 0x181, 24bits) */
+#define RRSR_1M BIT0
+#define RRSR_2M BIT1
+#define RRSR_5_5M BIT2
+#define RRSR_11M BIT3
+#define RRSR_6M BIT4
+#define RRSR_9M BIT5
+#define RRSR_12M BIT6
+#define RRSR_18M BIT7
+#define RRSR_24M BIT8
+#define RRSR_36M BIT9
+#define RRSR_48M BIT10
+#define RRSR_54M BIT11
+#define RRSR_MCS0 BIT12
+#define RRSR_MCS1 BIT13
+#define RRSR_MCS2 BIT14
+#define RRSR_MCS3 BIT15
+#define RRSR_MCS4 BIT16
+#define RRSR_MCS5 BIT17
+#define RRSR_MCS6 BIT18
+#define RRSR_MCS7 BIT19
+
+/* 8192C Response Rate Set Register (offset 0x1BF, 8bits) */
+/* WOL bit information */
+#define HAL92C_WOL_PTK_UPDATE_EVENT BIT0
+#define HAL92C_WOL_GTK_UPDATE_EVENT BIT1
+
+/* 8192C BW_OPMODE bits (Offset 0x203, 8bit) */
+#define BW_OPMODE_20MHZ BIT2
+#define BW_OPMODE_5G BIT1
+
+/* 8192C CAM Config Setting (offset 0x250, 1 byte) */
+#define CAM_VALID BIT15
+#define CAM_NOTVALID 0x0000
+#define CAM_USEDK BIT5
+
+#define CAM_CONTENT_COUNT 8
+
+#define CAM_NONE 0x0
+#define CAM_WEP40 0x01
+#define CAM_TKIP 0x02
+#define CAM_AES 0x04
+#define CAM_WEP104 0x05
+#define CAM_SMS4 0x6
+
+#define TOTAL_CAM_ENTRY 32
+#define HALF_CAM_ENTRY 16
+
+#define CAM_CONFIG_USEDK true
+#define CAM_CONFIG_NO_USEDK false
+
+#define CAM_WRITE BIT16
+#define CAM_READ 0x00000000
+#define CAM_POLLINIG BIT31
+
+#define SCR_UseDK 0x01
+#define SCR_TxSecEnable 0x02
+#define SCR_RxSecEnable 0x04
+
+/* 10. Power Save Control Registers (Offset: 0x0260 - 0x02DF) */
+#define WOW_PMEN BIT0 /* Power management Enable. */
+#define WOW_WOMEN BIT1 /* WoW function on or off. */
+#define WOW_MAGIC BIT2 /* Magic packet */
+#define WOW_UWF BIT3 /* Unicast Wakeup frame. */
+
+/* 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) */
+/* 8188 IMR/ISR bits */
+#define IMR_DISABLED_88E 0x0
+/* IMR DW0(0x0060-0063) Bit 0-31 */
+#define IMR_TXCCK_88E BIT30 /* TXRPT interrupt when CCX bit of the packet is set */
+#define IMR_PSTIMEOUT_88E BIT29 /* Power Save Time Out Interrupt */
+#define IMR_GTINT4_88E BIT28 /* When GTIMER4 expires, this bit is set to 1 */
+#define IMR_GTINT3_88E BIT27 /* When GTIMER3 expires, this bit is set to 1 */
+#define IMR_TBDER_88E BIT26 /* Transmit Beacon0 Error */
+#define IMR_TBDOK_88E BIT25 /* Transmit Beacon0 OK */
+#define IMR_TSF_BIT32_TOGGLE_88E BIT24 /* TSF Timer BIT32 toggle indication interrupt */
+#define IMR_BCNDMAINT0_88E BIT20 /* Beacon DMA Interrupt 0 */
+#define IMR_BCNDERR0_88E BIT16 /* Beacon Queue DMA Error 0 */
+#define IMR_HSISR_IND_ON_INT_88E BIT15 /* HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1) */
+#define IMR_BCNDMAINT_E_88E BIT14 /* Beacon DMA Interrupt Extension for Win7 */
+#define IMR_ATIMEND_88E BIT12 /* CTWidnow End or ATIM Window End */
+#define IMR_HISR1_IND_INT_88E BIT11 /* HISR1 Indicator (HISR1 & HIMR1 is true, this bit is set to 1) */
+#define IMR_C2HCMD_88E BIT10 /* CPU to Host Command INT Status, Write 1 clear */
+#define IMR_CPWM2_88E BIT9 /* CPU power Mode exchange INT Status, Write 1 clear */
+#define IMR_CPWM_88E BIT8 /* CPU power Mode exchange INT Status, Write 1 clear */
+#define IMR_HIGHDOK_88E BIT7 /* High Queue DMA OK */
+#define IMR_MGNTDOK_88E BIT6 /* Management Queue DMA OK */
+#define IMR_BKDOK_88E BIT5 /* AC_BK DMA OK */
+#define IMR_BEDOK_88E BIT4 /* AC_BE DMA OK */
+#define IMR_VIDOK_88E BIT3 /* AC_VI DMA OK */
+#define IMR_VODOK_88E BIT2 /* AC_VO DMA OK */
+#define IMR_RDU_88E BIT1 /* Rx Descriptor Unavailable */
+#define IMR_ROK_88E BIT0 /* Receive DMA OK */
+
+/* IMR DW1(0x00B4-00B7) Bit 0-31 */
+#define IMR_BCNDMAINT7_88E BIT27 /* Beacon DMA Interrupt 7 */
+#define IMR_BCNDMAINT6_88E BIT26 /* Beacon DMA Interrupt 6 */
+#define IMR_BCNDMAINT5_88E BIT25 /* Beacon DMA Interrupt 5 */
+#define IMR_BCNDMAINT4_88E BIT24 /* Beacon DMA Interrupt 4 */
+#define IMR_BCNDMAINT3_88E BIT23 /* Beacon DMA Interrupt 3 */
+#define IMR_BCNDMAINT2_88E BIT22 /* Beacon DMA Interrupt 2 */
+#define IMR_BCNDMAINT1_88E BIT21 /* Beacon DMA Interrupt 1 */
+#define IMR_BCNDERR7_88E BIT20 /* Beacon DMA Error Int 7 */
+#define IMR_BCNDERR6_88E BIT19 /* Beacon DMA Error Int 6 */
+#define IMR_BCNDERR5_88E BIT18 /* Beacon DMA Error Int 5 */
+#define IMR_BCNDERR4_88E BIT17 /* Beacon DMA Error Int 4 */
+#define IMR_BCNDERR3_88E BIT16 /* Beacon DMA Error Int 3 */
+#define IMR_BCNDERR2_88E BIT15 /* Beacon DMA Error Int 2 */
+#define IMR_BCNDERR1_88E BIT14 /* Beacon DMA Error Int 1 */
+#define IMR_ATIMEND_E_88E BIT13 /* ATIM Window End Ext for Win7 */
+#define IMR_TXERR_88E BIT11 /* Tx Err Flag Int Status, write 1 clear. */
+#define IMR_RXERR_88E BIT10 /* Rx Err Flag INT Status, Write 1 clear */
+#define IMR_TXFOVW_88E BIT9 /* Transmit FIFO Overflow */
+#define IMR_RXFOVW_88E BIT8 /* Receive FIFO Overflow */
+
+#define HAL_NIC_UNPLUG_ISR 0xFFFFFFFF /* The value when the NIC is unplugged for PCI. */
+
+/* 8192C EFUSE */
+#define HWSET_MAX_SIZE 256
+#define HWSET_MAX_SIZE_88E 512
+
+/*===================================================================
+=====================================================================
+Here the register defines are for 92C. When the define is as same with 92C,
+we will use the 92C's define for the consistency
+So the following defines for 92C is not entire!!!!!!
+=====================================================================
+=====================================================================*/
+/*
+Based on Datasheet V33---090401
+Register Summary
+Current IOREG MAP
+0x0000h ~ 0x00FFh System Configuration (256 Bytes)
+0x0100h ~ 0x01FFh MACTOP General Configuration (256 Bytes)
+0x0200h ~ 0x027Fh TXDMA Configuration (128 Bytes)
+0x0280h ~ 0x02FFh RXDMA Configuration (128 Bytes)
+0x0300h ~ 0x03FFh PCIE EMAC Reserved Region (256 Bytes)
+0x0400h ~ 0x04FFh Protocol Configuration (256 Bytes)
+0x0500h ~ 0x05FFh EDCA Configuration (256 Bytes)
+0x0600h ~ 0x07FFh WMAC Configuration (512 Bytes)
+0x2000h ~ 0x3FFFh 8051 FW Download Region (8196 Bytes)
+*/
+/* 8192C (TXPAUSE) transmission pause (Offset 0x522, 8 bits) */
+/* Note: */
+/* The bits of stopping AC(VO/VI/BE/BK) queue in datasheet
+ * RTL8192S/RTL8192C are wrong, */
+/* the correct arragement is VO - Bit0, VI - Bit1, BE - Bit2,
+ * and BK - Bit3. */
+/* 8723 and 88E may be not correct either in the earlier version. */
+#define StopBecon BIT6
+#define StopHigh BIT5
+#define StopMgt BIT4
+#define StopBK BIT3
+#define StopBE BIT2
+#define StopVI BIT1
+#define StopVO BIT0
+
+/* 8192C (RCR) Receive Configuration Register(Offset 0x608, 32 bits) */
+#define RCR_APPFCS BIT31 /* WMAC append FCS after payload */
+#define RCR_APP_MIC BIT30
+#define RCR_APP_PHYSTS BIT28
+#define RCR_APP_ICV BIT29
+#define RCR_APP_PHYST_RXFF BIT28
+#define RCR_APP_BA_SSN BIT27 /* Accept BA SSN */
+#define RCR_ENMBID BIT24 /* Enable Multiple BssId. */
+#define RCR_LSIGEN BIT23
+#define RCR_MFBEN BIT22
+#define RCR_HTC_LOC_CTRL BIT14 /* MFC<--HTC=1 MFC-->HTC=0 */
+#define RCR_AMF BIT13 /* Accept management type frame */
+#define RCR_ACF BIT12 /* Accept control type frame */
+#define RCR_ADF BIT11 /* Accept data type frame */
+#define RCR_AICV BIT9 /* Accept ICV error packet */
+#define RCR_ACRC32 BIT8 /* Accept CRC32 error packet */
+#define RCR_CBSSID_BCN BIT7 /* Accept BSSID match packet
+ * (Rx beacon, probe rsp) */
+#define RCR_CBSSID_DATA BIT6 /* Accept BSSID match (Data)*/
+#define RCR_CBSSID RCR_CBSSID_DATA /* Accept BSSID match */
+#define RCR_APWRMGT BIT5 /* Accept power management pkt*/
+#define RCR_ADD3 BIT4 /* Accept address 3 match pkt */
+#define RCR_AB BIT3 /* Accept broadcast packet */
+#define RCR_AM BIT2 /* Accept multicast packet */
+#define RCR_APM BIT1 /* Accept physical match pkt */
+#define RCR_AAP BIT0 /* Accept all unicast packet */
+#define RCR_MXDMA_OFFSET 8
+#define RCR_FIFO_OFFSET 13
+
+/* 0xFE00h ~ 0xFE55h USB Configuration */
+#define REG_USB_INFO 0xFE17
+#define REG_USB_SPECIAL_OPTION 0xFE55
+#define REG_USB_DMA_AGG_TO 0xFE5B
+#define REG_USB_AGG_TO 0xFE5C
+#define REG_USB_AGG_TH 0xFE5D
+
+#define REG_USB_HRPWM 0xFE58
+#define REG_USB_HCPWM 0xFE57
+/* 8192C Regsiter Bit and Content definition */
+/* 0x0000h ~ 0x00FFh System Configuration */
+
+/* 2 SYS_ISO_CTRL */
+#define ISO_MD2PP BIT(0)
+#define ISO_UA2USB BIT(1)
+#define ISO_UD2CORE BIT(2)
+#define ISO_PA2PCIE BIT(3)
+#define ISO_PD2CORE BIT(4)
+#define ISO_IP2MAC BIT(5)
+#define ISO_DIOP BIT(6)
+#define ISO_DIOE BIT(7)
+#define ISO_EB2CORE BIT(8)
+#define ISO_DIOR BIT(9)
+#define PWC_EV12V BIT(15)
+
+/* 2 SYS_FUNC_EN */
+#define FEN_BBRSTB BIT(0)
+#define FEN_BB_GLB_RSTn BIT(1)
+#define FEN_USBA BIT(2)
+#define FEN_UPLL BIT(3)
+#define FEN_USBD BIT(4)
+#define FEN_DIO_PCIE BIT(5)
+#define FEN_PCIEA BIT(6)
+#define FEN_PPLL BIT(7)
+#define FEN_PCIED BIT(8)
+#define FEN_DIOE BIT(9)
+#define FEN_CPUEN BIT(10)
+#define FEN_DCORE BIT(11)
+#define FEN_ELDR BIT(12)
+#define FEN_DIO_RF BIT(13)
+#define FEN_HWPDN BIT(14)
+#define FEN_MREGEN BIT(15)
+
+/* 2 APS_FSMCO */
+#define PFM_LDALL BIT(0)
+#define PFM_ALDN BIT(1)
+#define PFM_LDKP BIT(2)
+#define PFM_WOWL BIT(3)
+#define EnPDN BIT(4)
+#define PDN_PL BIT(5)
+#define APFM_ONMAC BIT(8)
+#define APFM_OFF BIT(9)
+#define APFM_RSM BIT(10)
+#define AFSM_HSUS BIT(11)
+#define AFSM_PCIE BIT(12)
+#define APDM_MAC BIT(13)
+#define APDM_HOST BIT(14)
+#define APDM_HPDN BIT(15)
+#define RDY_MACON BIT(16)
+#define SUS_HOST BIT(17)
+#define ROP_ALD BIT(20)
+#define ROP_PWR BIT(21)
+#define ROP_SPS BIT(22)
+#define SOP_MRST BIT(25)
+#define SOP_FUSE BIT(26)
+#define SOP_ABG BIT(27)
+#define SOP_AMB BIT(28)
+#define SOP_RCK BIT(29)
+#define SOP_A8M BIT(30)
+#define XOP_BTCK BIT(31)
+
+/* 2 SYS_CLKR */
+#define ANAD16V_EN BIT(0)
+#define ANA8M BIT(1)
+#define MACSLP BIT(4)
+#define LOADER_CLK_EN BIT(5)
+
+/* 2 9346CR */
+
+#define BOOT_FROM_EEPROM BIT(4)
+#define EEPROM_EN BIT(5)
+
+/* 2 SPS0_CTRL */
+
+/* 2 SPS_OCP_CFG */
+
+/* 2 RF_CTRL */
+#define RF_EN BIT(0)
+#define RF_RSTB BIT(1)
+#define RF_SDMRSTB BIT(2)
+
+/* 2 LDOV12D_CTRL */
+#define LDV12_EN BIT(0)
+#define LDV12_SDBY BIT(1)
+#define LPLDO_HSM BIT(2)
+#define LPLDO_LSM_DIS BIT(3)
+#define _LDV12_VADJ(x) (((x) & 0xF) << 4)
+
+/* 2EFUSE_CTRL */
+#define ALD_EN BIT(18)
+#define EF_PD BIT(19)
+#define EF_FLAG BIT(31)
+
+/* 2 EFUSE_TEST (For RTL8723 partially) */
+#define EF_TRPT BIT(7)
+/* 00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */
+#define EF_CELL_SEL (BIT(8)|BIT(9))
+#define LDOE25_EN BIT(31)
+#define EFUSE_SEL(x) (((x) & 0x3) << 8)
+#define EFUSE_SEL_MASK 0x300
+#define EFUSE_WIFI_SEL_0 0x0
+#define EFUSE_BT_SEL_0 0x1
+#define EFUSE_BT_SEL_1 0x2
+#define EFUSE_BT_SEL_2 0x3
+
+#define EFUSE_ACCESS_ON 0x69 /* For RTL8723 only. */
+#define EFUSE_ACCESS_OFF 0x00 /* For RTL8723 only. */
+
+/* 2 8051FWDL */
+/* 2 MCUFWDL */
+#define MCUFWDL_EN BIT(0)
+#define MCUFWDL_RDY BIT(1)
+#define FWDL_ChkSum_rpt BIT(2)
+#define MACINI_RDY BIT(3)
+#define BBINI_RDY BIT(4)
+#define RFINI_RDY BIT(5)
+#define WINTINI_RDY BIT(6)
+#define RAM_DL_SEL BIT(7) /* 1:RAM, 0:ROM */
+#define ROM_DLEN BIT(19)
+#define CPRST BIT(23)
+
+/* 2 REG_SYS_CFG */
+#define XCLK_VLD BIT(0)
+#define ACLK_VLD BIT(1)
+#define UCLK_VLD BIT(2)
+#define PCLK_VLD BIT(3)
+#define PCIRSTB BIT(4)
+#define V15_VLD BIT(5)
+#define SW_OFFLOAD_EN BIT(7)
+#define SIC_IDLE BIT(8)
+#define BD_MAC2 BIT(9)
+#define BD_MAC1 BIT(10)
+#define IC_MACPHY_MODE BIT(11)
+#define CHIP_VER (BIT(12)|BIT(13)|BIT(14)|BIT(15))
+#define BT_FUNC BIT(16)
+#define VENDOR_ID BIT(19)
+#define PAD_HWPD_IDN BIT(22)
+#define TRP_VAUX_EN BIT(23) /* RTL ID */
+#define TRP_BT_EN BIT(24)
+#define BD_PKG_SEL BIT(25)
+#define BD_HCI_SEL BIT(26)
+#define TYPE_ID BIT(27)
+
+#define CHIP_VER_RTL_MASK 0xF000 /* Bit 12 ~ 15 */
+#define CHIP_VER_RTL_SHIFT 12
+
+/* 2REG_GPIO_OUTSTS (For RTL8723 only) */
+#define EFS_HCI_SEL (BIT(0)|BIT(1))
+#define PAD_HCI_SEL (BIT(2)|BIT(3))
+#define HCI_SEL (BIT(4)|BIT(5))
+#define PKG_SEL_HCI BIT(6)
+#define FEN_GPS BIT(7)
+#define FEN_BT BIT(8)
+#define FEN_WL BIT(9)
+#define FEN_PCI BIT(10)
+#define FEN_USB BIT(11)
+#define BTRF_HWPDN_N BIT(12)
+#define WLRF_HWPDN_N BIT(13)
+#define PDN_BT_N BIT(14)
+#define PDN_GPS_N BIT(15)
+#define BT_CTL_HWPDN BIT(16)
+#define GPS_CTL_HWPDN BIT(17)
+#define PPHY_SUSB BIT(20)
+#define UPHY_SUSB BIT(21)
+#define PCI_SUSEN BIT(22)
+#define USB_SUSEN BIT(23)
+#define RF_RL_ID (BIT(31)|BIT(30)|BIT(29)|BIT(28))
+
+/* 2SYS_CFG */
+#define RTL_ID BIT(23) /* TestChip ID, 1:Test(RLE); 0:MP(RL) */
+
+/* 0x0100h ~ 0x01FFh MACTOP General Configuration */
+
+/* 2 Function Enable Registers */
+/* 2 CR */
+
+#define HCI_TXDMA_EN BIT(0)
+#define HCI_RXDMA_EN BIT(1)
+#define TXDMA_EN BIT(2)
+#define RXDMA_EN BIT(3)
+#define PROTOCOL_EN BIT(4)
+#define SCHEDULE_EN BIT(5)
+#define MACTXEN BIT(6)
+#define MACRXEN BIT(7)
+#define ENSWBCN BIT(8)
+#define ENSEC BIT(9)
+#define CALTMR_EN BIT(10) /* 32k CAL TMR enable */
+
+/* Network type */
+#define _NETTYPE(x) (((x) & 0x3) << 16)
+#define MASK_NETTYPE 0x30000
+#define NT_NO_LINK 0x0
+#define NT_LINK_AD_HOC 0x1
+#define NT_LINK_AP 0x2
+#define NT_AS_AP 0x3
+
+/* 2 PBP - Page Size Register */
+#define GET_RX_PAGE_SIZE(value) ((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4)
+#define _PSRX_MASK 0xF
+#define _PSTX_MASK 0xF0
+#define _PSRX(x) (x)
+#define _PSTX(x) ((x) << 4)
+
+#define PBP_64 0x0
+#define PBP_128 0x1
+#define PBP_256 0x2
+#define PBP_512 0x3
+#define PBP_1024 0x4
+
+/* 2 TX/RXDMA */
+#define RXDMA_ARBBW_EN BIT(0)
+#define RXSHFT_EN BIT(1)
+#define RXDMA_AGG_EN BIT(2)
+#define QS_VO_QUEUE BIT(8)
+#define QS_VI_QUEUE BIT(9)
+#define QS_BE_QUEUE BIT(10)
+#define QS_BK_QUEUE BIT(11)
+#define QS_MANAGER_QUEUE BIT(12)
+#define QS_HIGH_QUEUE BIT(13)
+
+#define HQSEL_VOQ BIT(0)
+#define HQSEL_VIQ BIT(1)
+#define HQSEL_BEQ BIT(2)
+#define HQSEL_BKQ BIT(3)
+#define HQSEL_MGTQ BIT(4)
+#define HQSEL_HIQ BIT(5)
+
+/* For normal driver, 0x10C */
+#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14)
+#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12)
+#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10)
+#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8 )
+#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6 )
+#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4 )
+
+#define QUEUE_LOW 1
+#define QUEUE_NORMAL 2
+#define QUEUE_HIGH 3
+
+/* 2 TRXFF_BNDY */
+
+/* 2 LLT_INIT */
+#define _LLT_NO_ACTIVE 0x0
+#define _LLT_WRITE_ACCESS 0x1
+#define _LLT_READ_ACCESS 0x2
+
+#define _LLT_INIT_DATA(x) ((x) & 0xFF)
+#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8)
+#define _LLT_OP(x) (((x) & 0x3) << 30)
+#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3)
+
+/* 0x0200h ~ 0x027Fh TXDMA Configuration */
+/* 2RQPN */
+#define _HPQ(x) ((x) & 0xFF)
+#define _LPQ(x) (((x) & 0xFF) << 8)
+#define _PUBQ(x) (((x) & 0xFF) << 16)
+/* NOTE: in RQPN_NPQ register */
+#define _NPQ(x) ((x) & 0xFF)
+
+#define HPQ_PUBLIC_DIS BIT(24)
+#define LPQ_PUBLIC_DIS BIT(25)
+#define LD_RQPN BIT(31)
+
+/* 2TDECTRL */
+#define BCN_VALID BIT(16)
+#define BCN_HEAD(x) (((x) & 0xFF) << 8)
+#define BCN_HEAD_MASK 0xFF00
+
+/* 2 TDECTL */
+#define BLK_DESC_NUM_SHIFT 4
+#define BLK_DESC_NUM_MASK 0xF
+
+/* 2 TXDMA_OFFSET_CHK */
+#define DROP_DATA_EN BIT(9)
+
+/* 0x0280h ~ 0x028Bh RX DMA Configuration */
+
+/* REG_RXDMA_CONTROL, 0x0286h */
+
+/* 2 REG_RXPKT_NUM, 0x0284 */
+#define RXPKT_RELEASE_POLL BIT(16)
+#define RXDMA_IDLE BIT(17)
+#define RW_RELEASE_EN BIT(18)
+
+/* 0x0400h ~ 0x047Fh Protocol Configuration */
+/* 2 FWHW_TXQ_CTRL */
+#define EN_AMPDU_RTY_NEW BIT(7)
+
+/* 2 SPEC SIFS */
+#define _SPEC_SIFS_CCK(x) ((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8)
+
+/* 2 RL */
+#define RETRY_LIMIT_SHORT_SHIFT 8
+#define RETRY_LIMIT_LONG_SHIFT 0
+
+/* 0x0500h ~ 0x05FFh EDCA Configuration */
+
+/* 2 EDCA setting */
+#define AC_PARAM_TXOP_LIMIT_OFFSET 16
+#define AC_PARAM_ECW_MAX_OFFSET 12
+#define AC_PARAM_ECW_MIN_OFFSET 8
+#define AC_PARAM_AIFS_OFFSET 0
+
+#define _LRL(x) ((x) & 0x3F)
+#define _SRL(x) (((x) & 0x3F) << 8)
+
+/* 2 BCN_CTRL */
+#define EN_MBSSID BIT(1)
+#define EN_TXBCN_RPT BIT(2)
+#define EN_BCN_FUNCTION BIT(3)
+#define DIS_TSF_UPDATE BIT(3)
+
+/* The same function but different bit field. */
+#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4)
+#define DIS_TSF_UDT0_TEST_CHIP BIT(5)
+#define STOP_BCNQ BIT(6)
+
+/* 2 ACMHWCTRL */
+#define AcmHw_HwEn BIT(0)
+#define AcmHw_BeqEn BIT(1)
+#define AcmHw_ViqEn BIT(2)
+#define AcmHw_VoqEn BIT(3)
+#define AcmHw_BeqStatus BIT(4)
+#define AcmHw_ViqStatus BIT(5)
+#define AcmHw_VoqStatus BIT(6)
+
+/* 0x0600h ~ 0x07FFh WMAC Configuration */
+/* 2APSD_CTRL */
+#define APSDOFF BIT(6)
+#define APSDOFF_STATUS BIT(7)
+
+#define RATE_BITMAP_ALL 0xFFFFF
+
+/* Only use CCK 1M rate for ACK */
+#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1
+
+/* 2 TCR */
+#define TSFRST BIT(0)
+#define DIS_GCLK BIT(1)
+#define PAD_SEL BIT(2)
+#define PWR_ST BIT(6)
+#define PWRBIT_OW_EN BIT(7)
+#define ACRC BIT(8)
+#define CFENDFORM BIT(9)
+#define ICV BIT(10)
+
+/* 2 RCR */
+#define AAP BIT(0)
+#define APM BIT(1)
+#define AM BIT(2)
+#define AB BIT(3)
+#define ADD3 BIT(4)
+#define APWRMGT BIT(5)
+#define CBSSID BIT(6)
+#define CBSSID_DATA BIT(6)
+#define CBSSID_BCN BIT(7)
+#define ACRC32 BIT(8)
+#define AICV BIT(9)
+#define ADF BIT(11)
+#define ACF BIT(12)
+#define AMF BIT(13)
+#define HTC_LOC_CTRL BIT(14)
+#define UC_DATA_EN BIT(16)
+#define BM_DATA_EN BIT(17)
+#define MFBEN BIT(22)
+#define LSIGEN BIT(23)
+#define EnMBID BIT(24)
+#define APP_BASSN BIT(27)
+#define APP_PHYSTS BIT(28)
+#define APP_ICV BIT(29)
+#define APP_MIC BIT(30)
+#define APP_FCS BIT(31)
+
+/* 2 SECCFG */
+#define SCR_TxUseDK BIT(0) /* Force Tx Use Default Key */
+#define SCR_RxUseDK BIT(1) /* Force Rx Use Default Key */
+#define SCR_TxEncEnable BIT(2) /* Enable Tx Encryption */
+#define SCR_RxDecEnable BIT(3) /* Enable Rx Decryption */
+#define SCR_SKByA2 BIT(4) /* Search kEY BY A2 */
+#define SCR_NoSKMC BIT(5) /* No Key Search Multicast */
+#define SCR_TXBCUSEDK BIT(6) /* Force Tx Bcast pkt Use Default Key */
+#define SCR_RXBCUSEDK BIT(7) /* Force Rx Bcast pkt Use Default Key */
+
+/* RTL8188E SDIO Configuration */
+
+/* I/O bus domain address mapping */
+#define SDIO_LOCAL_BASE 0x10250000
+#define WLAN_IOREG_BASE 0x10260000
+#define FIRMWARE_FIFO_BASE 0x10270000
+#define TX_HIQ_BASE 0x10310000
+#define TX_MIQ_BASE 0x10320000
+#define TX_LOQ_BASE 0x10330000
+#define RX_RX0FF_BASE 0x10340000
+
+/* SDIO host local register space mapping. */
+#define SDIO_LOCAL_MSK 0x0FFF
+#define WLAN_IOREG_MSK 0x7FFF
+#define WLAN_FIFO_MSK 0x1FFF /* Aggregation Length[12:0] */
+#define WLAN_RX0FF_MSK 0x0003
+
+/* Without ref to the SDIO Device ID */
+#define SDIO_WITHOUT_REF_DEVICE_ID 0
+#define SDIO_LOCAL_DEVICE_ID 0 /* 0b[16], 000b[15:13] */
+#define WLAN_TX_HIQ_DEVICE_ID 4 /* 0b[16], 100b[15:13] */
+#define WLAN_TX_MIQ_DEVICE_ID 5 /* 0b[16], 101b[15:13] */
+#define WLAN_TX_LOQ_DEVICE_ID 6 /* 0b[16], 110b[15:13] */
+#define WLAN_RX0FF_DEVICE_ID 7 /* 0b[16], 111b[15:13] */
+#define WLAN_IOREG_DEVICE_ID 8 /* 1b[16] */
+
+/* SDIO Tx Free Page Index */
+#define HI_QUEUE_IDX 0
+#define MID_QUEUE_IDX 1
+#define LOW_QUEUE_IDX 2
+#define PUBLIC_QUEUE_IDX 3
+
+#define SDIO_MAX_TX_QUEUE 3 /* HIQ, MIQ and LOQ */
+#define SDIO_MAX_RX_QUEUE 1
+
+/* SDIO Tx Control */
+#define SDIO_REG_TX_CTRL 0x0000
+/* SDIO Host Interrupt Mask */
+#define SDIO_REG_HIMR 0x0014
+/* SDIO Host Interrupt Service Routine */
+#define SDIO_REG_HISR 0x0018
+/* HCI Current Power Mode */
+#define SDIO_REG_HCPWM 0x0019
+/* RXDMA Request Length */
+#define SDIO_REG_RX0_REQ_LEN 0x001C
+/* Free Tx Buffer Page */
+#define SDIO_REG_FREE_TXPG 0x0020
+/* HCI Current Power Mode 1 */
+#define SDIO_REG_HCPWM1 0x0024
+/* HCI Current Power Mode 2 */
+#define SDIO_REG_HCPWM2 0x0026
+/* HTSF Informaion */
+#define SDIO_REG_HTSFR_INFO 0x0030
+/* HCI Request Power Mode 1 */
+#define SDIO_REG_HRPWM1 0x0080
+/* HCI Request Power Mode 2 */
+#define SDIO_REG_HRPWM2 0x0082
+/* HCI Power Save Clock */
+#define SDIO_REG_HPS_CLKR 0x0084
+/* SDIO HCI Suspend Control */
+#define SDIO_REG_HSUS_CTRL 0x0086
+/* SDIO Host Extension Interrupt Mask Always */
+#define SDIO_REG_HIMR_ON 0x0090
+/* SDIO Host Extension Interrupt Status Always */
+#define SDIO_REG_HISR_ON 0x0091
+
+#define SDIO_HIMR_DISABLED 0
+
+/* RTL8188E SDIO Host Interrupt Mask Register */
+#define SDIO_HIMR_RX_REQUEST_MSK BIT0
+#define SDIO_HIMR_AVAL_MSK BIT1
+#define SDIO_HIMR_TXERR_MSK BIT2
+#define SDIO_HIMR_RXERR_MSK BIT3
+#define SDIO_HIMR_TXFOVW_MSK BIT4
+#define SDIO_HIMR_RXFOVW_MSK BIT5
+#define SDIO_HIMR_TXBCNOK_MSK BIT6
+#define SDIO_HIMR_TXBCNERR_MSK BIT7
+#define SDIO_HIMR_BCNERLY_INT_MSK BIT16
+#define SDIO_HIMR_C2HCMD_MSK BIT17
+#define SDIO_HIMR_CPWM1_MSK BIT18
+#define SDIO_HIMR_CPWM2_MSK BIT19
+#define SDIO_HIMR_HSISR_IND_MSK BIT20
+#define SDIO_HIMR_GTINT3_IND_MSK BIT21
+#define SDIO_HIMR_GTINT4_IND_MSK BIT22
+#define SDIO_HIMR_PSTIMEOUT_MSK BIT23
+#define SDIO_HIMR_OCPINT_MSK BIT24
+#define SDIO_HIMR_ATIMEND_MSK BIT25
+#define SDIO_HIMR_ATIMEND_E_MSK BIT26
+#define SDIO_HIMR_CTWEND_MSK BIT27
+
+/* RTL8188E SDIO Specific */
+#define SDIO_HIMR_MCU_ERR_MSK BIT28
+#define SDIO_HIMR_TSF_BIT32_TOGGLE_MSK BIT29
+
+/* SDIO Host Interrupt Service Routine */
+#define SDIO_HISR_RX_REQUEST BIT0
+#define SDIO_HISR_AVAL BIT1
+#define SDIO_HISR_TXERR BIT2
+#define SDIO_HISR_RXERR BIT3
+#define SDIO_HISR_TXFOVW BIT4
+#define SDIO_HISR_RXFOVW BIT5
+#define SDIO_HISR_TXBCNOK BIT6
+#define SDIO_HISR_TXBCNERR BIT7
+#define SDIO_HISR_BCNERLY_INT BIT16
+#define SDIO_HISR_C2HCMD BIT17
+#define SDIO_HISR_CPWM1 BIT18
+#define SDIO_HISR_CPWM2 BIT19
+#define SDIO_HISR_HSISR_IND BIT20
+#define SDIO_HISR_GTINT3_IND BIT21
+#define SDIO_HISR_GTINT4_IND BIT22
+#define SDIO_HISR_PSTIME BIT23
+#define SDIO_HISR_OCPINT BIT24
+#define SDIO_HISR_ATIMEND BIT25
+#define SDIO_HISR_ATIMEND_E BIT26
+#define SDIO_HISR_CTWEND BIT27
+
+/* RTL8188E SDIO Specific */
+#define SDIO_HISR_MCU_ERR BIT28
+#define SDIO_HISR_TSF_BIT32_TOGGLE BIT29
+
+#define MASK_SDIO_HISR_CLEAR \
+ (SDIO_HISR_TXERR | SDIO_HISR_RXERR | SDIO_HISR_TXFOVW |\
+ SDIO_HISR_RXFOVW | SDIO_HISR_TXBCNOK | SDIO_HISR_TXBCNERR |\
+ SDIO_HISR_C2HCMD | SDIO_HISR_CPWM1 | SDIO_HISR_CPWM2 |\
+ SDIO_HISR_HSISR_IND | SDIO_HISR_GTINT3_IND | SDIO_HISR_GTINT4_IND |\
+ SDIO_HISR_PSTIMEOUT | SDIO_HISR_OCPINT)
+
+/* SDIO HCI Suspend Control Register */
+#define HCI_RESUME_PWR_RDY BIT1
+#define HCI_SUS_CTRL BIT0
+
+/* SDIO Tx FIFO related */
+/* The number of Tx FIFO free page */
+#define SDIO_TX_FREE_PG_QUEUE 4
+#define SDIO_TX_FIFO_PAGE_SZ 128
+
+/* 0xFE00h ~ 0xFE55h USB Configuration */
+
+/* 2 USB Information (0xFE17) */
+#define USB_IS_HIGH_SPEED 0
+#define USB_IS_FULL_SPEED 1
+#define USB_SPEED_MASK BIT(5)
+
+#define USB_NORMAL_SIE_EP_MASK 0xF
+#define USB_NORMAL_SIE_EP_SHIFT 4
+
+/* 2 Special Option */
+#define USB_AGG_EN BIT(3)
+
+/* 0; Use interrupt endpoint to upload interrupt pkt */
+/* 1; Use bulk endpoint to upload interrupt pkt, */
+#define INT_BULK_SEL BIT(4)
+
+/* 2REG_C2HEVT_CLEAR */
+/* Set by driver and notify FW that the driver has read
+ * the C2H command message */
+#define C2H_EVT_HOST_CLOSE 0x00
+/* Set by FW indicating that FW had set the C2H command
+ * message and it's not yet read by driver. */
+#define C2H_EVT_FW_CLOSE 0xFF
+
+/* 2REG_MULTI_FUNC_CTRL(For RTL8723 Only) */
+/* Enable GPIO[9] as WiFi HW PDn source */
+#define WL_HWPDN_EN BIT0
+/* WiFi HW PDn polarity control */
+#define WL_HWPDN_SL BIT1
+/* WiFi function enable */
+#define WL_FUNC_EN BIT2
+/* Enable GPIO[9] as WiFi RF HW PDn source */
+#define WL_HWROF_EN BIT3
+/* Enable GPIO[11] as BT HW PDn source */
+#define BT_HWPDN_EN BIT16
+/* BT HW PDn polarity control */
+#define BT_HWPDN_SL BIT17
+/* BT function enable */
+#define BT_FUNC_EN BIT18
+/* Enable GPIO[11] as BT/GPS RF HW PDn source */
+#define BT_HWROF_EN BIT19
+/* Enable GPIO[10] as GPS HW PDn source */
+#define GPS_HWPDN_EN BIT20
+/* GPS HW PDn polarity control */
+#define GPS_HWPDN_SL BIT21
+/* GPS function enable */
+#define GPS_FUNC_EN BIT22
+
+/* 3 REG_LIFECTRL_CTRL */
+#define HAL92C_EN_PKT_LIFE_TIME_BK BIT3
+#define HAL92C_EN_PKT_LIFE_TIME_BE BIT2
+#define HAL92C_EN_PKT_LIFE_TIME_VI BIT1
+#define HAL92C_EN_PKT_LIFE_TIME_VO BIT0
+
+#define HAL92C_MSDU_LIFE_TIME_UNIT 128 /* in us */
+
+/* General definitions */
+#define LAST_ENTRY_OF_TX_PKT_BUFFER 176 /* 22k 22528 bytes */
+
+#define POLLING_LLT_THRESHOLD 20
+#define POLLING_READY_TIMEOUT_COUNT 1000
+/* GPIO BIT */
+#define HAL_8192C_HW_GPIO_WPS_BIT BIT2
+
+/* 8192C EEPROM/EFUSE share register definition. */
+
+/* EEPROM/Efuse PG Offset for 88EE/88EU/88ES */
+#define EEPROM_TX_PWR_INX_88E 0x10
+
+#define EEPROM_ChannelPlan_88E 0xB8
+#define EEPROM_XTAL_88E 0xB9
+#define EEPROM_THERMAL_METER_88E 0xBA
+#define EEPROM_IQK_LCK_88E 0xBB
+
+#define EEPROM_RF_BOARD_OPTION_88E 0xC1
+#define EEPROM_RF_FEATURE_OPTION_88E 0xC2
+#define EEPROM_RF_BT_SETTING_88E 0xC3
+#define EEPROM_VERSION_88E 0xC4
+#define EEPROM_CUSTOMERID_88E 0xC5
+#define EEPROM_RF_ANTENNA_OPT_88E 0xC9
+
+/* RTL88EE */
+#define EEPROM_MAC_ADDR_88EE 0xD0
+#define EEPROM_VID_88EE 0xD6
+#define EEPROM_DID_88EE 0xD8
+#define EEPROM_SVID_88EE 0xDA
+#define EEPROM_SMID_88EE 0xDC
+
+/* RTL88EU */
+#define EEPROM_MAC_ADDR_88EU 0xD7
+#define EEPROM_VID_88EU 0xD0
+#define EEPROM_PID_88EU 0xD2
+#define EEPROM_USB_OPTIONAL_FUNCTION0 0xD4
+
+/* RTL88ES */
+#define EEPROM_MAC_ADDR_88ES 0x11A
+
+/* EEPROM/Efuse Value Type */
+#define EETYPE_TX_PWR 0x0
+
+/* Default Value for EEPROM or EFUSE!!! */
+#define EEPROM_Default_TSSI 0x0
+#define EEPROM_Default_TxPowerDiff 0x0
+#define EEPROM_Default_CrystalCap 0x5
+/* Default: 2X2, RTL8192CE(QFPN68) */
+#define EEPROM_Default_BoardType 0x02
+#define EEPROM_Default_TxPower 0x1010
+#define EEPROM_Default_HT2T_TxPwr 0x10
+
+#define EEPROM_Default_LegacyHTTxPowerDiff 0x3
+#define EEPROM_Default_ThermalMeter 0x12
+
+#define EEPROM_Default_AntTxPowerDiff 0x0
+#define EEPROM_Default_TxPwDiff_CrystalCap 0x5
+#define EEPROM_Default_TxPowerLevel 0x2A
+
+#define EEPROM_Default_HT40_2SDiff 0x0
+/* HT20<->40 default Tx Power Index Difference */
+#define EEPROM_Default_HT20_Diff 2
+#define EEPROM_Default_LegacyHTTxPowerDiff 0x3
+#define EEPROM_Default_HT40_PwrMaxOffset 0
+#define EEPROM_Default_HT20_PwrMaxOffset 0
+
+#define EEPROM_Default_CrystalCap_88E 0x20
+#define EEPROM_Default_ThermalMeter_88E 0x18
+
+/* New EFUSE deafult value */
+#define EEPROM_DEFAULT_24G_INDEX 0x2D
+#define EEPROM_DEFAULT_24G_HT20_DIFF 0X02
+#define EEPROM_DEFAULT_24G_OFDM_DIFF 0X04
+
+#define EEPROM_DEFAULT_5G_INDEX 0X2A
+#define EEPROM_DEFAULT_5G_HT20_DIFF 0X00
+#define EEPROM_DEFAULT_5G_OFDM_DIFF 0X04
+
+#define EEPROM_DEFAULT_DIFF 0XFE
+#define EEPROM_DEFAULT_CHANNEL_PLAN 0x7F
+#define EEPROM_DEFAULT_BOARD_OPTION 0x00
+#define EEPROM_DEFAULT_FEATURE_OPTION 0x00
+#define EEPROM_DEFAULT_BT_OPTION 0x10
+
+/* For debug */
+#define EEPROM_Default_PID 0x1234
+#define EEPROM_Default_VID 0x5678
+#define EEPROM_Default_CustomerID 0xAB
+#define EEPROM_Default_CustomerID_8188E 0x00
+#define EEPROM_Default_SubCustomerID 0xCD
+#define EEPROM_Default_Version 0
+
+#define EEPROM_CHANNEL_PLAN_FCC 0x0
+#define EEPROM_CHANNEL_PLAN_IC 0x1
+#define EEPROM_CHANNEL_PLAN_ETSI 0x2
+#define EEPROM_CHANNEL_PLAN_SPA 0x3
+#define EEPROM_CHANNEL_PLAN_FRANCE 0x4
+#define EEPROM_CHANNEL_PLAN_MKK 0x5
+#define EEPROM_CHANNEL_PLAN_MKK1 0x6
+#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7
+#define EEPROM_CHANNEL_PLAN_TELEC 0x8
+#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMA 0x9
+#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA
+#define EEPROM_CHANNEL_PLAN_NCC 0xB
+#define EEPROM_USB_OPTIONAL1 0xE
+#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80
+
+#define EEPROM_CID_DEFAULT 0x0
+#define EEPROM_CID_TOSHIBA 0x4
+#define EEPROM_CID_CCX 0x10 /* CCX test. */
+#define EEPROM_CID_QMI 0x0D
+#define EEPROM_CID_WHQL 0xFE
+#define RTL_EEPROM_ID 0x8129
+
+#endif /* __RTL8188E_SPEC_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_sreset.h b/drivers/staging/rtl8188eu/include/rtl8188e_sreset.h
new file mode 100644
index 00000000000..a29e6951979
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_sreset.h
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTL8188E_SRESET_H_
+#define _RTL8188E_SRESET_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_sreset.h>
+
+void rtl8188e_silentreset_for_specific_platform(struct adapter *padapter);
+void rtl8188e_sreset_xmit_status_check(struct adapter *padapter);
+void rtl8188e_sreset_linked_status_check(struct adapter *padapter);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_xmit.h b/drivers/staging/rtl8188eu/include/rtl8188e_xmit.h
new file mode 100644
index 00000000000..cf7267a5365
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_xmit.h
@@ -0,0 +1,178 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_XMIT_H__
+#define __RTL8188E_XMIT_H__
+
+#define MAX_TX_AGG_PACKET_NUMBER 0xFF
+/* */
+/* Queue Select Value in TxDesc */
+/* */
+#define QSLT_BK 0x2/* 0x01 */
+#define QSLT_BE 0x0
+#define QSLT_VI 0x5/* 0x4 */
+#define QSLT_VO 0x7/* 0x6 */
+#define QSLT_BEACON 0x10
+#define QSLT_HIGH 0x11
+#define QSLT_MGNT 0x12
+#define QSLT_CMD 0x13
+
+/* For 88e early mode */
+#define SET_EARLYMODE_PKTNUM(__pAddr, __Value) \
+ SET_BITS_TO_LE_4BYTE(__pAddr, 0, 3, __Value)
+#define SET_EARLYMODE_LEN0(__pAddr, __Value) \
+ SET_BITS_TO_LE_4BYTE(__pAddr, 4, 12, __Value)
+#define SET_EARLYMODE_LEN1(__pAddr, __Value) \
+ SET_BITS_TO_LE_4BYTE(__pAddr, 16, 12, __Value)
+#define SET_EARLYMODE_LEN2_1(__pAddr, __Value) \
+ SET_BITS_TO_LE_4BYTE(__pAddr, 28, 4, __Value)
+#define SET_EARLYMODE_LEN2_2(__pAddr, __Value) \
+ SET_BITS_TO_LE_4BYTE(__pAddr+4, 0, 8, __Value)
+#define SET_EARLYMODE_LEN3(__pAddr, __Value) \
+ SET_BITS_TO_LE_4BYTE(__pAddr+4, 8, 12, __Value)
+#define SET_EARLYMODE_LEN4(__pAddr, __Value) \
+ SET_BITS_TO_LE_4BYTE(__pAddr+4, 20, 12, __Value)
+
+/* */
+/* defined for TX DESC Operation */
+/* */
+
+#define MAX_TID (15)
+
+/* OFFSET 0 */
+#define OFFSET_SZ 0
+#define OFFSET_SHT 16
+#define BMC BIT(24)
+#define LSG BIT(26)
+#define FSG BIT(27)
+#define OWN BIT(31)
+
+
+/* OFFSET 4 */
+#define PKT_OFFSET_SZ 0
+#define QSEL_SHT 8
+#define RATE_ID_SHT 16
+#define NAVUSEHDR BIT(20)
+#define SEC_TYPE_SHT 22
+#define PKT_OFFSET_SHT 26
+
+/* OFFSET 8 */
+#define AGG_EN BIT(12)
+#define AGG_BK BIT(16)
+#define AMPDU_DENSITY_SHT 20
+#define ANTSEL_A BIT(24)
+#define ANTSEL_B BIT(25)
+#define TX_ANT_CCK_SHT 26
+#define TX_ANTL_SHT 28
+#define TX_ANT_HT_SHT 30
+
+/* OFFSET 12 */
+#define SEQ_SHT 16
+#define EN_HWSEQ BIT(31)
+
+/* OFFSET 16 */
+#define QOS BIT(6)
+#define HW_SSN BIT(7)
+#define USERATE BIT(8)
+#define DISDATAFB BIT(10)
+#define CTS_2_SELF BIT(11)
+#define RTS_EN BIT(12)
+#define HW_RTS_EN BIT(13)
+#define DATA_SHORT BIT(24)
+#define PWR_STATUS_SHT 15
+#define DATA_SC_SHT 20
+#define DATA_BW BIT(25)
+
+/* OFFSET 20 */
+#define RTY_LMT_EN BIT(17)
+
+enum TXDESC_SC {
+ SC_DONT_CARE = 0x00,
+ SC_UPPER = 0x01,
+ SC_LOWER = 0x02,
+ SC_DUPLICATE = 0x03
+};
+/* OFFSET 20 */
+#define SGI BIT(6)
+#define USB_TXAGG_NUM_SHT 24
+
+#define txdesc_set_ccx_sw_88e(txdesc, value) \
+ do { \
+ ((struct txdesc_88e *)(txdesc))->sw1 = (((value)>>8) & 0x0f); \
+ ((struct txdesc_88e *)(txdesc))->sw0 = ((value) & 0xff); \
+ } while (0)
+
+struct txrpt_ccx_88e {
+ /* offset 0 */
+ u8 tag1:1;
+ u8 pkt_num:3;
+ u8 txdma_underflow:1;
+ u8 int_bt:1;
+ u8 int_tri:1;
+ u8 int_ccx:1;
+
+ /* offset 1 */
+ u8 mac_id:6;
+ u8 pkt_ok:1;
+ u8 bmc:1;
+
+ /* offset 2 */
+ u8 retry_cnt:6;
+ u8 lifetime_over:1;
+ u8 retry_over:1;
+
+ /* offset 3 */
+ u8 ccx_qtime0;
+ u8 ccx_qtime1;
+
+ /* offset 5 */
+ u8 final_data_rate;
+
+ /* offset 6 */
+ u8 sw1:4;
+ u8 qsel:4;
+
+ /* offset 7 */
+ u8 sw0;
+};
+
+#define txrpt_ccx_sw_88e(txrpt_ccx) ((txrpt_ccx)->sw0 + ((txrpt_ccx)->sw1<<8))
+#define txrpt_ccx_qtime_88e(txrpt_ccx) \
+ ((txrpt_ccx)->ccx_qtime0+((txrpt_ccx)->ccx_qtime1<<8))
+
+void rtl8188e_fill_fake_txdesc(struct adapter *padapter, u8 *pDesc,
+ u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull);
+s32 rtl8188eu_init_xmit_priv(struct adapter *padapter);
+void rtl8188eu_free_xmit_priv(struct adapter *padapter);
+s32 rtl8188eu_hal_xmit(struct adapter *padapter, struct xmit_frame *frame);
+s32 rtl8188eu_mgnt_xmit(struct adapter *padapter, struct xmit_frame *frame);
+s32 rtl8188eu_xmit_buf_handler(struct adapter *padapter);
+#define hal_xmit_handler rtl8188eu_xmit_buf_handler
+void rtl8188eu_xmit_tasklet(void *priv);
+s32 rtl8188eu_xmitframe_complete(struct adapter *padapter,
+ struct xmit_priv *pxmitpriv,
+ struct xmit_buf *pxmitbuf);
+
+void dump_txrpt_ccx_88e(void *buf);
+void handle_txrpt_ccx_88e(struct adapter *adapter, u8 *buf);
+
+void _dbg_dump_tx_info(struct adapter *padapter, int frame_tag,
+ struct tx_desc *ptxdesc);
+
+#endif /* __RTL8188E_XMIT_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_android.h b/drivers/staging/rtl8188eu/include/rtw_android.h
new file mode 100644
index 00000000000..e85bf1ff01f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_android.h
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __RTW_ANDROID_H__
+#define __RTW_ANDROID_H__
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+enum ANDROID_WIFI_CMD {
+ ANDROID_WIFI_CMD_START,
+ ANDROID_WIFI_CMD_STOP,
+ ANDROID_WIFI_CMD_SCAN_ACTIVE,
+ ANDROID_WIFI_CMD_SCAN_PASSIVE,
+ ANDROID_WIFI_CMD_RSSI,
+ ANDROID_WIFI_CMD_LINKSPEED,
+ ANDROID_WIFI_CMD_RXFILTER_START,
+ ANDROID_WIFI_CMD_RXFILTER_STOP,
+ ANDROID_WIFI_CMD_RXFILTER_ADD,
+ ANDROID_WIFI_CMD_RXFILTER_REMOVE,
+ ANDROID_WIFI_CMD_BTCOEXSCAN_START,
+ ANDROID_WIFI_CMD_BTCOEXSCAN_STOP,
+ ANDROID_WIFI_CMD_BTCOEXMODE,
+ ANDROID_WIFI_CMD_SETSUSPENDOPT,
+ ANDROID_WIFI_CMD_P2P_DEV_ADDR,
+ ANDROID_WIFI_CMD_SETFWPATH,
+ ANDROID_WIFI_CMD_SETBAND,
+ ANDROID_WIFI_CMD_GETBAND,
+ ANDROID_WIFI_CMD_COUNTRY,
+ ANDROID_WIFI_CMD_P2P_SET_NOA,
+ ANDROID_WIFI_CMD_P2P_GET_NOA,
+ ANDROID_WIFI_CMD_P2P_SET_PS,
+ ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE,
+ ANDROID_WIFI_CMD_MACADDR,
+ ANDROID_WIFI_CMD_BLOCK,
+ ANDROID_WIFI_CMD_WFD_ENABLE,
+ ANDROID_WIFI_CMD_WFD_DISABLE,
+ ANDROID_WIFI_CMD_WFD_SET_TCPPORT,
+ ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT,
+ ANDROID_WIFI_CMD_WFD_SET_DEVTYPE,
+ ANDROID_WIFI_CMD_MAX
+};
+
+int rtw_android_cmdstr_to_num(char *cmdstr);
+int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
+
+#endif /* __RTW_ANDROID_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_ap.h b/drivers/staging/rtl8188eu/include/rtw_ap.h
new file mode 100644
index 00000000000..92334015979
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_ap.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_AP_H_
+#define __RTW_AP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#ifdef CONFIG_88EU_AP_MODE
+
+/* external function */
+void rtw_indicate_sta_assoc_event(struct adapter *padapter,
+ struct sta_info *psta);
+void rtw_indicate_sta_disassoc_event(struct adapter *padapter,
+ struct sta_info *psta);
+void init_mlme_ap_info(struct adapter *padapter);
+void free_mlme_ap_info(struct adapter *padapter);
+void rtw_add_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork,
+ u8 index, u8 *data, u8 len);
+void rtw_remove_bcn_ie(struct adapter *padapter,
+ struct wlan_bssid_ex *pnetwork, u8 index);
+void update_beacon(struct adapter *padapter, u8 ie_id,
+ u8 *oui, u8 tx);
+void add_RATid(struct adapter *padapter, struct sta_info *psta,
+ u8 rssi_level);
+void expire_timeout_chk(struct adapter *padapter);
+void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta);
+int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len);
+void rtw_set_macaddr_acl(struct adapter *padapter, int mode);
+int rtw_acl_add_sta(struct adapter *padapter, u8 *addr);
+int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr);
+
+#ifdef CONFIG_88EU_AP_MODE
+void associated_clients_update(struct adapter *padapter, u8 updated);
+void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta);
+u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta);
+void sta_info_update(struct adapter *padapter, struct sta_info *psta);
+void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta);
+u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta,
+ bool active, u16 reason);
+int rtw_sta_flush(struct adapter *padapter);
+int rtw_ap_inform_ch_switch(struct adapter *padapter, u8 new_ch, u8 ch_offset);
+void start_ap_mode(struct adapter *padapter);
+void stop_ap_mode(struct adapter *padapter);
+#endif
+#endif /* end of CONFIG_88EU_AP_MODE */
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_br_ext.h b/drivers/staging/rtl8188eu/include/rtw_br_ext.h
new file mode 100644
index 00000000000..f21e7a4515d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_br_ext.h
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_BR_EXT_H_
+#define _RTW_BR_EXT_H_
+
+#define MACADDRLEN 6
+#define _DEBUG_ERR DBG_88E
+#define _DEBUG_INFO DBG_88E
+#define DEBUG_WARN DBG_88E
+#define DEBUG_INFO DBG_88E
+#define DEBUG_ERR DBG_88E
+#define GET_MY_HWADDR(padapter) ((padapter)->eeprompriv.mac_addr)
+
+#define NAT25_HASH_BITS 4
+#define NAT25_HASH_SIZE (1 << NAT25_HASH_BITS)
+#define NAT25_AGEING_TIME 300
+
+#define MAX_NETWORK_ADDR_LEN 17
+
+struct nat25_network_db_entry {
+ struct nat25_network_db_entry *next_hash;
+ struct nat25_network_db_entry **pprev_hash;
+ atomic_t use_count;
+ unsigned char macAddr[6];
+ unsigned long ageing_timer;
+ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+};
+
+enum NAT25_METHOD {
+ NAT25_MIN,
+ NAT25_CHECK,
+ NAT25_INSERT,
+ NAT25_LOOKUP,
+ NAT25_PARSE,
+ NAT25_MAX
+};
+
+struct br_ext_info {
+ unsigned int nat25_disable;
+ unsigned int macclone_enable;
+ unsigned int dhcp_bcst_disable;
+ int addPPPoETag; /* 1: Add PPPoE relay-SID, 0: disable */
+ unsigned char nat25_dmzMac[MACADDRLEN];
+ unsigned int nat25sc_disable;
+};
+
+void nat25_db_cleanup(struct adapter *priv);
+
+#endif /* _RTW_BR_EXT_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_cmd.h b/drivers/staging/rtl8188eu/include/rtw_cmd.h
new file mode 100644
index 00000000000..819285b9a78
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_cmd.h
@@ -0,0 +1,991 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_CMD_H_
+#define __RTW_CMD_H_
+
+#include <wlan_bssdef.h>
+#include <rtw_rf.h>
+#include <rtw_led.h>
+
+#define C2H_MEM_SZ (16*1024)
+
+#include <osdep_service.h>
+#include <ieee80211.h> /* <ieee80211/ieee80211.h> */
+
+#define FREE_CMDOBJ_SZ 128
+
+#define MAX_CMDSZ 1024
+#define MAX_RSPSZ 512
+#define MAX_EVTSZ 1024
+
+#define CMDBUFF_ALIGN_SZ 512
+
+struct cmd_obj {
+ struct adapter *padapter;
+ u16 cmdcode;
+ u8 res;
+ u8 *parmbuf;
+ u32 cmdsz;
+ u8 *rsp;
+ u32 rspsz;
+ struct list_head list;
+};
+
+struct cmd_priv {
+ struct semaphore cmd_queue_sema;
+ struct semaphore terminate_cmdthread_sema;
+ struct __queue cmd_queue;
+ u8 cmd_seq;
+ u8 *cmd_buf; /* shall be non-paged, and 4 bytes aligned */
+ u8 *cmd_allocated_buf;
+ u8 *rsp_buf; /* shall be non-paged, and 4 bytes aligned */
+ u8 *rsp_allocated_buf;
+ u32 cmd_issued_cnt;
+ u32 cmd_done_cnt;
+ u32 rsp_cnt;
+ u8 cmdthd_running;
+ struct adapter *padapter;
+};
+
+struct evt_priv {
+ struct work_struct c2h_wk;
+ bool c2h_wk_alive;
+ struct rtw_cbuf *c2h_queue;
+ #define C2H_QUEUE_MAX_LEN 10
+ ATOMIC_T event_seq;
+ u8 *evt_buf; /* shall be non-paged, and 4 bytes aligned */
+ u8 *evt_allocated_buf;
+ u32 evt_done_cnt;
+};
+
+#define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \
+do {\
+ _rtw_init_listhead(&pcmd->list);\
+ pcmd->cmdcode = code;\
+ pcmd->parmbuf = (u8 *)(pparm);\
+ pcmd->cmdsz = sizeof(*pparm);\
+ pcmd->rsp = NULL;\
+ pcmd->rspsz = 0;\
+} while (0)
+
+struct c2h_evt_hdr {
+ u8 id:4;
+ u8 plen:4;
+ u8 seq;
+ u8 payload[0];
+};
+
+#define c2h_evt_exist(c2h_evt) ((c2h_evt)->id || (c2h_evt)->plen)
+
+u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
+struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv);
+void rtw_free_cmd_obj(struct cmd_obj *pcmd);
+
+int rtw_cmd_thread(void *context);
+
+u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv);
+void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv);
+
+u32 rtw_init_evt_priv(struct evt_priv *pevtpriv);
+void rtw_free_evt_priv(struct evt_priv *pevtpriv);
+void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv);
+void rtw_evt_notify_isr(struct evt_priv *pevtpriv);
+#ifdef CONFIG_88EU_P2P
+u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType);
+#endif /* CONFIG_88EU_P2P */
+
+enum rtw_drvextra_cmd_id {
+ NONE_WK_CID,
+ DYNAMIC_CHK_WK_CID,
+ DM_CTRL_WK_CID,
+ PBC_POLLING_WK_CID,
+ POWER_SAVING_CTRL_WK_CID,/* IPS,AUTOSuspend */
+ LPS_CTRL_WK_CID,
+ ANT_SELECT_WK_CID,
+ P2P_PS_WK_CID,
+ P2P_PROTO_WK_CID,
+ CHECK_HIQ_WK_CID,/* for softap mode, check hi queue if empty */
+ INTEl_WIDI_WK_CID,
+ C2H_WK_CID,
+ RTP_TIMER_CFG_WK_CID,
+ MAX_WK_CID
+};
+
+enum LPS_CTRL_TYPE {
+ LPS_CTRL_SCAN = 0,
+ LPS_CTRL_JOINBSS = 1,
+ LPS_CTRL_CONNECT = 2,
+ LPS_CTRL_DISCONNECT = 3,
+ LPS_CTRL_SPECIAL_PACKET = 4,
+ LPS_CTRL_LEAVE = 5,
+};
+
+enum RFINTFS {
+ SWSI,
+ HWSI,
+ HWPI,
+};
+
+/*
+Caller Mode: Infra, Ad-HoC(C)
+
+Notes: To enter USB suspend mode
+
+Command Mode
+
+*/
+struct usb_suspend_parm {
+ u32 action;/* 1: sleep, 0:resume */
+};
+
+/*
+Caller Mode: Infra, Ad-HoC
+
+Notes: To join a known BSS.
+
+Command-Event Mode
+
+*/
+
+/*
+Caller Mode: Infra, Ad-Hoc
+
+Notes: To join the specified bss
+
+Command Event Mode
+
+*/
+struct joinbss_parm {
+ struct wlan_bssid_ex network;
+};
+
+/*
+Caller Mode: Infra, Ad-HoC(C)
+
+Notes: To disconnect the current associated BSS
+
+Command Mode
+
+*/
+struct disconnect_parm {
+ u32 deauth_timeout_ms;
+};
+
+/*
+Caller Mode: AP, Ad-HoC(M)
+
+Notes: To create a BSS
+
+Command Mode
+*/
+struct createbss_parm {
+ struct wlan_bssid_ex network;
+};
+
+struct setopmode_parm {
+ u8 mode;
+ u8 rsvd[3];
+};
+
+/*
+Caller Mode: AP, Ad-HoC, Infra
+
+Notes: To ask RTL8711 performing site-survey
+
+Command-Event Mode
+
+*/
+
+#define RTW_SSID_SCAN_AMOUNT 9 /* for WEXT_CSCAN_AMOUNT 9 */
+#define RTW_CHANNEL_SCAN_AMOUNT (14+37)
+struct sitesurvey_parm {
+ int scan_mode; /* active: 1, passive: 0 */
+ u8 ssid_num;
+ u8 ch_num;
+ struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT];
+ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To set the auth type of RTL8711. open/shared/802.1x
+
+Command Mode
+
+*/
+struct setauth_parm {
+ u8 mode; /* 0: legacy open, 1: legacy shared 2: 802.1x */
+ u8 _1x; /* 0: PSK, 1: TLS */
+ u8 rsvd[2];
+};
+
+/*
+Caller Mode: Infra
+
+a. algorithm: wep40, wep104, tkip & aes
+b. keytype: grp key/unicast key
+c. key contents
+
+when shared key ==> keyid is the camid
+when 802.1x ==> keyid [0:1] ==> grp key
+when 802.1x ==> keyid > 2 ==> unicast key
+
+*/
+struct setkey_parm {
+ u8 algorithm; /* could be none, wep40, TKIP, CCMP, wep104 */
+ u8 keyid;
+ u8 grpkey; /* 1: this is the grpkey for 802.1x.
+ * 0: this is the unicast key for 802.1x */
+ u8 set_tx; /* 1: main tx key for wep. 0: other key. */
+ u8 key[16]; /* this could be 40 or 104 */
+};
+
+/*
+When in AP or Ad-Hoc mode, this is used to
+allocate an sw/hw entry for a newly associated sta.
+
+Command
+
+when shared key ==> algorithm/keyid
+
+*/
+struct set_stakey_parm {
+ u8 addr[ETH_ALEN];
+ u8 algorithm;
+ u8 id;/* currently for erasing cam entry if
+ * algorithm == _NO_PRIVACY_ */
+ u8 key[16];
+};
+
+struct set_stakey_rsp {
+ u8 addr[ETH_ALEN];
+ u8 keyid;
+ u8 rsvd;
+};
+
+/*
+Caller Ad-Hoc/AP
+
+Command -Rsp(AID == CAMID) mode
+
+This is to force fw to add an sta_data entry per driver's request.
+
+FW will write an cam entry associated with it.
+
+*/
+struct set_assocsta_parm {
+ u8 addr[ETH_ALEN];
+};
+
+struct set_assocsta_rsp {
+ u8 cam_id;
+ u8 rsvd[3];
+};
+
+/*
+ Caller Ad-Hoc/AP
+
+ Command mode
+
+ This is to force fw to del an sta_data entry per driver's request
+
+ FW will invalidate the cam entry associated with it.
+
+*/
+struct del_assocsta_parm {
+ u8 addr[ETH_ALEN];
+};
+
+/*
+Caller Mode: AP/Ad-HoC(M)
+
+Notes: To notify fw that given staid has changed its power state
+
+Command Mode
+
+*/
+struct setstapwrstate_parm {
+ u8 staid;
+ u8 status;
+ u8 hwaddr[6];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To setup the basic rate of RTL8711
+
+Command Mode
+
+*/
+struct setbasicrate_parm {
+ u8 basicrates[NumRates];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To read the current basic rate
+
+Command-Rsp Mode
+
+*/
+struct getbasicrate_parm {
+ u32 rsvd;
+};
+
+struct getbasicrate_rsp {
+ u8 basicrates[NumRates];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To setup the data rate of RTL8711
+
+Command Mode
+
+*/
+struct setdatarate_parm {
+ u8 mac_id;
+ u8 datarates[NumRates];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To read the current data rate
+
+Command-Rsp Mode
+
+*/
+struct getdatarate_parm {
+ u32 rsvd;
+
+};
+struct getdatarate_rsp {
+ u8 datarates[NumRates];
+};
+
+/*
+Caller Mode: Any
+AP: AP can use the info for the contents of beacon frame
+Infra: STA can use the info when sitesurveying
+Ad-HoC(M): Like AP
+Ad-HoC(C): Like STA
+
+Notes: To set the phy capability of the NIC
+
+Command Mode
+
+*/
+
+struct setphyinfo_parm {
+ struct regulatory_class class_sets[NUM_REGULATORYS];
+ u8 status;
+};
+
+struct getphyinfo_parm {
+ u32 rsvd;
+};
+
+struct getphyinfo_rsp {
+ struct regulatory_class class_sets[NUM_REGULATORYS];
+ u8 status;
+};
+
+/*
+Caller Mode: Any
+
+Notes: To set the channel/modem/band
+This command will be used when channel/modem/band is changed.
+
+Command Mode
+
+*/
+struct setphy_parm {
+ u8 rfchannel;
+ u8 modem;
+};
+
+/*
+Caller Mode: Any
+
+Notes: To get the current setting of channel/modem/band
+
+Command-Rsp Mode
+
+*/
+struct getphy_parm {
+ u32 rsvd;
+
+};
+struct getphy_rsp {
+ u8 rfchannel;
+ u8 modem;
+};
+
+struct readBB_parm {
+ u8 offset;
+};
+struct readBB_rsp {
+ u8 value;
+};
+
+struct readTSSI_parm {
+ u8 offset;
+};
+struct readTSSI_rsp {
+ u8 value;
+};
+
+struct writeBB_parm {
+ u8 offset;
+ u8 value;
+};
+
+struct readRF_parm {
+ u8 offset;
+};
+struct readRF_rsp {
+ u32 value;
+};
+
+struct writeRF_parm {
+ u32 offset;
+ u32 value;
+};
+
+struct getrfintfs_parm {
+ u8 rfintfs;
+};
+
+struct Tx_Beacon_param
+{
+ struct wlan_bssid_ex network;
+};
+
+/*
+ Notes: This command is used for H2C/C2H loopback testing
+
+ mac[0] == 0
+ ==> CMD mode, return H2C_SUCCESS.
+ The following condition must be ture under CMD mode
+ mac[1] == mac[4], mac[2] == mac[3], mac[0]=mac[5]= 0;
+ s0 == 0x1234, s1 == 0xabcd, w0 == 0x78563412, w1 == 0x5aa5def7;
+ s2 == (b1 << 8 | b0);
+
+ mac[0] == 1
+ ==> CMD_RSP mode, return H2C_SUCCESS_RSP
+
+ The rsp layout shall be:
+ rsp: parm:
+ mac[0] = mac[5];
+ mac[1] = mac[4];
+ mac[2] = mac[3];
+ mac[3] = mac[2];
+ mac[4] = mac[1];
+ mac[5] = mac[0];
+ s0 = s1;
+ s1 = swap16(s0);
+ w0 = swap32(w1);
+ b0 = b1
+ s2 = s0 + s1
+ b1 = b0
+ w1 = w0
+
+ mac[0] == 2
+ ==> CMD_EVENT mode, return H2C_SUCCESS
+ The event layout shall be:
+ event: parm:
+ mac[0] = mac[5];
+ mac[1] = mac[4];
+ mac[2] = event's seq no, starting from 1 to parm's marc[3]
+ mac[3] = mac[2];
+ mac[4] = mac[1];
+ mac[5] = mac[0];
+ s0 = swap16(s0) - event.mac[2];
+ s1 = s1 + event.mac[2];
+ w0 = swap32(w0);
+ b0 = b1
+ s2 = s0 + event.mac[2]
+ b1 = b0
+ w1 = swap32(w1) - event.mac[2];
+
+ parm->mac[3] is the total event counts that host requested.
+ event will be the same with the cmd's param.
+*/
+
+/* CMD param Format for driver extra cmd handler */
+struct drvextra_cmd_parm {
+ int ec_id; /* extra cmd id */
+ int type_size; /* Can use this field as the type id or command size */
+ unsigned char *pbuf;
+};
+
+/*------------------- Below are used for RF/BB tunning ---------------------*/
+
+struct setantenna_parm {
+ u8 tx_antset;
+ u8 rx_antset;
+ u8 tx_antenna;
+ u8 rx_antenna;
+};
+
+struct enrateadaptive_parm {
+ u32 en;
+};
+
+struct settxagctbl_parm {
+ u32 txagc[MAX_RATES_LENGTH];
+};
+
+struct gettxagctbl_parm {
+ u32 rsvd;
+};
+struct gettxagctbl_rsp {
+ u32 txagc[MAX_RATES_LENGTH];
+};
+
+struct setagcctrl_parm {
+ u32 agcctrl; /* 0: pure hw, 1: fw */
+};
+
+struct setssup_parm {
+ u32 ss_ForceUp[MAX_RATES_LENGTH];
+};
+
+struct getssup_parm {
+ u32 rsvd;
+};
+
+struct getssup_rsp {
+ u8 ss_ForceUp[MAX_RATES_LENGTH];
+};
+
+struct setssdlevel_parm {
+ u8 ss_DLevel[MAX_RATES_LENGTH];
+};
+
+struct getssdlevel_parm {
+ u32 rsvd;
+};
+
+struct getssdlevel_rsp {
+ u8 ss_DLevel[MAX_RATES_LENGTH];
+};
+
+struct setssulevel_parm {
+ u8 ss_ULevel[MAX_RATES_LENGTH];
+};
+
+struct getssulevel_parm {
+ u32 rsvd;
+};
+
+struct getssulevel_rsp {
+ u8 ss_ULevel[MAX_RATES_LENGTH];
+};
+
+struct setcountjudge_parm {
+ u8 count_judge[MAX_RATES_LENGTH];
+};
+
+struct getcountjudge_parm {
+ u32 rsvd;
+};
+
+struct getcountjudge_rsp {
+ u8 count_judge[MAX_RATES_LENGTH];
+};
+
+struct setratable_parm {
+ u8 ss_ForceUp[NumRates];
+ u8 ss_ULevel[NumRates];
+ u8 ss_DLevel[NumRates];
+ u8 count_judge[NumRates];
+};
+
+struct getratable_parm {
+ uint rsvd;
+};
+
+struct getratable_rsp {
+ u8 ss_ForceUp[NumRates];
+ u8 ss_ULevel[NumRates];
+ u8 ss_DLevel[NumRates];
+ u8 count_judge[NumRates];
+};
+
+/* to get TX,RX retry count */
+
+struct gettxretrycnt_parm {
+ unsigned int rsvd;
+};
+
+struct gettxretrycnt_rsp {
+ unsigned long tx_retrycnt;
+};
+
+struct getrxretrycnt_parm {
+ unsigned int rsvd;
+};
+
+struct getrxretrycnt_rsp {
+ unsigned long rx_retrycnt;
+};
+
+/* to get BCNOK,BCNERR count */
+struct getbcnokcnt_parm {
+ unsigned int rsvd;
+};
+
+struct getbcnokcnt_rsp {
+ unsigned long bcnokcnt;
+};
+
+struct getbcnerrcnt_parm {
+ unsigned int rsvd;
+};
+
+struct getbcnerrcnt_rsp {
+ unsigned long bcnerrcnt;
+};
+
+/* to get current TX power level */
+struct getcurtxpwrlevel_parm {
+ unsigned int rsvd;
+};
+struct getcurtxpwrlevel_rspi {
+ unsigned short tx_power;
+};
+
+struct setprobereqextraie_parm {
+ unsigned char e_id;
+ unsigned char ie_len;
+ unsigned char ie[0];
+};
+
+struct setassocreqextraie_parm {
+ unsigned char e_id;
+ unsigned char ie_len;
+ unsigned char ie[0];
+};
+
+struct setproberspextraie_parm {
+ unsigned char e_id;
+ unsigned char ie_len;
+ unsigned char ie[0];
+};
+
+struct setassocrspextraie_parm {
+ unsigned char e_id;
+ unsigned char ie_len;
+ unsigned char ie[0];
+};
+
+struct addBaReq_parm {
+ unsigned int tid;
+ u8 addr[ETH_ALEN];
+};
+
+/*H2C Handler index: 46 */
+struct set_ch_parm {
+ u8 ch;
+ u8 bw;
+ u8 ch_offset;
+};
+
+/*H2C Handler index: 59 */
+struct SetChannelPlan_param
+{
+ u8 channel_plan;
+};
+
+/*H2C Handler index: 60 */
+struct LedBlink_param
+{
+ struct LED_871x *pLed;
+};
+
+/*H2C Handler index: 61 */
+struct SetChannelSwitch_param
+{
+ u8 new_ch_no;
+};
+
+/*H2C Handler index: 62 */
+struct TDLSoption_param
+{
+ u8 addr[ETH_ALEN];
+ u8 option;
+};
+
+#define GEN_CMD_CODE(cmd) cmd ## _CMD_
+
+/*
+
+Result:
+0x00: success
+0x01: sucess, and check Response.
+0x02: cmd ignored due to duplicated sequcne number
+0x03: cmd dropped due to invalid cmd code
+0x04: reserved.
+
+*/
+
+#define H2C_RSP_OFFSET 512
+
+#define H2C_SUCCESS 0x00
+#define H2C_SUCCESS_RSP 0x01
+#define H2C_DUPLICATED 0x02
+#define H2C_DROPPED 0x03
+#define H2C_PARAMETERS_ERROR 0x04
+#define H2C_REJECTED 0x05
+#define H2C_CMD_OVERFLOW 0x06
+#define H2C_RESERVED 0x07
+
+u8 rtw_setassocsta_cmd(struct adapter *padapter, u8 *mac_addr);
+u8 rtw_setstandby_cmd(struct adapter *padapter, uint action);
+u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid,
+ int ssid_num, struct rtw_ieee80211_channel *ch,
+ int ch_num);
+u8 rtw_createbss_cmd(struct adapter *padapter);
+u8 rtw_createbss_cmd_ex(struct adapter *padapter, unsigned char *pbss,
+ unsigned int sz);
+u8 rtw_setphy_cmd(struct adapter *padapter, u8 modem, u8 ch);
+u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key);
+u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue);
+u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network* pnetwork);
+u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue);
+u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infra networktype);
+u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset);
+u8 rtw_setbasicrate_cmd(struct adapter *padapter, u8 *rateset);
+u8 rtw_setbbreg_cmd(struct adapter * padapter, u8 offset, u8 val);
+u8 rtw_setrfreg_cmd(struct adapter * padapter, u8 offset, u32 val);
+u8 rtw_getbbreg_cmd(struct adapter * padapter, u8 offset, u8 * pval);
+u8 rtw_getrfreg_cmd(struct adapter * padapter, u8 offset, u8 * pval);
+u8 rtw_setrfintfs_cmd(struct adapter *padapter, u8 mode);
+u8 rtw_setrttbl_cmd(struct adapter *padapter, struct setratable_parm *prate_table);
+u8 rtw_getrttbl_cmd(struct adapter *padapter, struct getratable_rsp *pval);
+
+u8 rtw_gettssi_cmd(struct adapter *padapter, u8 offset,u8 *pval);
+u8 rtw_setfwdig_cmd(struct adapter*padapter, u8 type);
+u8 rtw_setfwra_cmd(struct adapter*padapter, u8 type);
+
+u8 rtw_addbareq_cmd(struct adapter*padapter, u8 tid, u8 *addr);
+
+u8 rtw_dynamic_chk_wk_cmd(struct adapter *adapter);
+
+u8 rtw_lps_ctrl_wk_cmd(struct adapter*padapter, u8 lps_ctrl_type, u8 enqueue);
+u8 rtw_rpt_timer_cfg_cmd(struct adapter*padapter, u16 minRptTime);
+
+ u8 rtw_antenna_select_cmd(struct adapter*padapter, u8 antenna,u8 enqueue);
+u8 rtw_ps_cmd(struct adapter*padapter);
+
+#ifdef CONFIG_88EU_AP_MODE
+u8 rtw_chk_hi_queue_cmd(struct adapter*padapter);
+#endif
+
+u8 rtw_set_ch_cmd(struct adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue);
+u8 rtw_set_chplan_cmd(struct adapter*padapter, u8 chplan, u8 enqueue);
+u8 rtw_led_blink_cmd(struct adapter*padapter, struct LED_871x * pLed);
+u8 rtw_set_csa_cmd(struct adapter*padapter, u8 new_ch_no);
+u8 rtw_tdls_cmd(struct adapter *padapter, u8 *addr, u8 option);
+
+u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt);
+
+u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf);
+
+void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd);
+void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd);
+void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd);
+void rtw_createbss_cmd_callback(struct adapter *adapt, struct cmd_obj *pcmd);
+void rtw_getbbrfreg_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd);
+void rtw_readtssi_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd);
+
+void rtw_setstaKey_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd);
+void rtw_setassocsta_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cm);
+void rtw_getrttbl_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd);
+
+struct _cmd_callback {
+ u32 cmd_code;
+ void (*callback)(struct adapter *padapter, struct cmd_obj *cmd);
+};
+
+enum rtw_h2c_cmd {
+ GEN_CMD_CODE(_Read_MACREG), /*0*/
+ GEN_CMD_CODE(_Write_MACREG),
+ GEN_CMD_CODE(_Read_BBREG),
+ GEN_CMD_CODE(_Write_BBREG),
+ GEN_CMD_CODE(_Read_RFREG),
+ GEN_CMD_CODE(_Write_RFREG), /*5*/
+ GEN_CMD_CODE(_Read_EEPROM),
+ GEN_CMD_CODE(_Write_EEPROM),
+ GEN_CMD_CODE(_Read_EFUSE),
+ GEN_CMD_CODE(_Write_EFUSE),
+
+ GEN_CMD_CODE(_Read_CAM), /*10*/
+ GEN_CMD_CODE(_Write_CAM),
+ GEN_CMD_CODE(_setBCNITV),
+ GEN_CMD_CODE(_setMBIDCFG),
+ GEN_CMD_CODE(_JoinBss), /*14*/
+ GEN_CMD_CODE(_DisConnect), /*15*/
+ GEN_CMD_CODE(_CreateBss),
+ GEN_CMD_CODE(_SetOpMode),
+ GEN_CMD_CODE(_SiteSurvey), /*18*/
+ GEN_CMD_CODE(_SetAuth),
+
+ GEN_CMD_CODE(_SetKey), /*20*/
+ GEN_CMD_CODE(_SetStaKey),
+ GEN_CMD_CODE(_SetAssocSta),
+ GEN_CMD_CODE(_DelAssocSta),
+ GEN_CMD_CODE(_SetStaPwrState),
+ GEN_CMD_CODE(_SetBasicRate), /*25*/
+ GEN_CMD_CODE(_GetBasicRate),
+ GEN_CMD_CODE(_SetDataRate),
+ GEN_CMD_CODE(_GetDataRate),
+ GEN_CMD_CODE(_SetPhyInfo),
+
+ GEN_CMD_CODE(_GetPhyInfo), /*30*/
+ GEN_CMD_CODE(_SetPhy),
+ GEN_CMD_CODE(_GetPhy),
+ GEN_CMD_CODE(_readRssi),
+ GEN_CMD_CODE(_readGain),
+ GEN_CMD_CODE(_SetAtim), /*35*/
+ GEN_CMD_CODE(_SetPwrMode),
+ GEN_CMD_CODE(_JoinbssRpt),
+ GEN_CMD_CODE(_SetRaTable),
+ GEN_CMD_CODE(_GetRaTable),
+
+ GEN_CMD_CODE(_GetCCXReport), /*40*/
+ GEN_CMD_CODE(_GetDTMReport),
+ GEN_CMD_CODE(_GetTXRateStatistics),
+ GEN_CMD_CODE(_SetUsbSuspend),
+ GEN_CMD_CODE(_SetH2cLbk),
+ GEN_CMD_CODE(_AddBAReq), /*45*/
+ GEN_CMD_CODE(_SetChannel), /*46*/
+ GEN_CMD_CODE(_SetTxPower),
+ GEN_CMD_CODE(_SwitchAntenna),
+ GEN_CMD_CODE(_SetCrystalCap),
+ GEN_CMD_CODE(_SetSingleCarrierTx), /*50*/
+
+ GEN_CMD_CODE(_SetSingleToneTx),/*51*/
+ GEN_CMD_CODE(_SetCarrierSuppressionTx),
+ GEN_CMD_CODE(_SetContinuousTx),
+ GEN_CMD_CODE(_SwitchBandwidth), /*54*/
+ GEN_CMD_CODE(_TX_Beacon), /*55*/
+
+ GEN_CMD_CODE(_Set_MLME_EVT), /*56*/
+ GEN_CMD_CODE(_Set_Drv_Extra), /*57*/
+ GEN_CMD_CODE(_Set_H2C_MSG), /*58*/
+
+ GEN_CMD_CODE(_SetChannelPlan), /*59*/
+ GEN_CMD_CODE(_LedBlink), /*60*/
+
+ GEN_CMD_CODE(_SetChannelSwitch), /*61*/
+ GEN_CMD_CODE(_TDLS), /*62*/
+
+ MAX_H2CCMD
+};
+
+#define _GetBBReg_CMD_ _Read_BBREG_CMD_
+#define _SetBBReg_CMD_ _Write_BBREG_CMD_
+#define _GetRFReg_CMD_ _Read_RFREG_CMD_
+#define _SetRFReg_CMD_ _Write_RFREG_CMD_
+
+#ifdef _RTW_CMD_C_
+static struct _cmd_callback rtw_cmd_callback[] =
+{
+ {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/
+ {GEN_CMD_CODE(_Write_MACREG), NULL},
+ {GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback},
+ {GEN_CMD_CODE(_Write_BBREG), NULL},
+ {GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback},
+ {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/
+ {GEN_CMD_CODE(_Read_EEPROM), NULL},
+ {GEN_CMD_CODE(_Write_EEPROM), NULL},
+ {GEN_CMD_CODE(_Read_EFUSE), NULL},
+ {GEN_CMD_CODE(_Write_EFUSE), NULL},
+
+ {GEN_CMD_CODE(_Read_CAM), NULL}, /*10*/
+ {GEN_CMD_CODE(_Write_CAM), NULL},
+ {GEN_CMD_CODE(_setBCNITV), NULL},
+ {GEN_CMD_CODE(_setMBIDCFG), NULL},
+ {GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd_callback}, /*14*/
+ {GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd_callback}, /*15*/
+ {GEN_CMD_CODE(_CreateBss), &rtw_createbss_cmd_callback},
+ {GEN_CMD_CODE(_SetOpMode), NULL},
+ {GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback}, /*18*/
+ {GEN_CMD_CODE(_SetAuth), NULL},
+
+ {GEN_CMD_CODE(_SetKey), NULL}, /*20*/
+ {GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback},
+ {GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback},
+ {GEN_CMD_CODE(_DelAssocSta), NULL},
+ {GEN_CMD_CODE(_SetStaPwrState), NULL},
+ {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/
+ {GEN_CMD_CODE(_GetBasicRate), NULL},
+ {GEN_CMD_CODE(_SetDataRate), NULL},
+ {GEN_CMD_CODE(_GetDataRate), NULL},
+ {GEN_CMD_CODE(_SetPhyInfo), NULL},
+
+ {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/
+ {GEN_CMD_CODE(_SetPhy), NULL},
+ {GEN_CMD_CODE(_GetPhy), NULL},
+ {GEN_CMD_CODE(_readRssi), NULL},
+ {GEN_CMD_CODE(_readGain), NULL},
+ {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/
+ {GEN_CMD_CODE(_SetPwrMode), NULL},
+ {GEN_CMD_CODE(_JoinbssRpt), NULL},
+ {GEN_CMD_CODE(_SetRaTable), NULL},
+ {GEN_CMD_CODE(_GetRaTable), NULL},
+
+ {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/
+ {GEN_CMD_CODE(_GetDTMReport), NULL},
+ {GEN_CMD_CODE(_GetTXRateStatistics), NULL},
+ {GEN_CMD_CODE(_SetUsbSuspend), NULL},
+ {GEN_CMD_CODE(_SetH2cLbk), NULL},
+ {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/
+ {GEN_CMD_CODE(_SetChannel), NULL}, /*46*/
+ {GEN_CMD_CODE(_SetTxPower), NULL},
+ {GEN_CMD_CODE(_SwitchAntenna), NULL},
+ {GEN_CMD_CODE(_SetCrystalCap), NULL},
+ {GEN_CMD_CODE(_SetSingleCarrierTx), NULL}, /*50*/
+
+ {GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/
+ {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL},
+ {GEN_CMD_CODE(_SetContinuousTx), NULL},
+ {GEN_CMD_CODE(_SwitchBandwidth), NULL}, /*54*/
+ {GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/
+
+ {GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/
+ {GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/
+ {GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/
+ {GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/
+ {GEN_CMD_CODE(_LedBlink), NULL},/*60*/
+
+ {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*61*/
+ {GEN_CMD_CODE(_TDLS), NULL},/*62*/
+};
+#endif
+
+#endif /* _CMD_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_debug.h b/drivers/staging/rtl8188eu/include/rtw_debug.h
new file mode 100644
index 00000000000..c6b193a2e79
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_debug.h
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_DEBUG_H__
+#define __RTW_DEBUG_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+#define _drv_always_ 1
+#define _drv_emerg_ 2
+#define _drv_alert_ 3
+#define _drv_crit_ 4
+#define _drv_err_ 5
+#define _drv_warning_ 6
+#define _drv_notice_ 7
+#define _drv_info_ 8
+#define _drv_debug_ 9
+
+
+#define _module_rtl871x_xmit_c_ BIT(0)
+#define _module_xmit_osdep_c_ BIT(1)
+#define _module_rtl871x_recv_c_ BIT(2)
+#define _module_recv_osdep_c_ BIT(3)
+#define _module_rtl871x_mlme_c_ BIT(4)
+#define _module_mlme_osdep_c_ BIT(5)
+#define _module_rtl871x_sta_mgt_c_ BIT(6)
+#define _module_rtl871x_cmd_c_ BIT(7)
+#define _module_cmd_osdep_c_ BIT(8)
+#define _module_rtl871x_io_c_ BIT(9)
+#define _module_io_osdep_c_ BIT(10)
+#define _module_os_intfs_c_ BIT(11)
+#define _module_rtl871x_security_c_ BIT(12)
+#define _module_rtl871x_eeprom_c_ BIT(13)
+#define _module_hal_init_c_ BIT(14)
+#define _module_hci_hal_init_c_ BIT(15)
+#define _module_rtl871x_ioctl_c_ BIT(16)
+#define _module_rtl871x_ioctl_set_c_ BIT(17)
+#define _module_rtl871x_ioctl_query_c_ BIT(18)
+#define _module_rtl871x_pwrctrl_c_ BIT(19)
+#define _module_hci_intfs_c_ BIT(20)
+#define _module_hci_ops_c_ BIT(21)
+#define _module_osdep_service_c_ BIT(22)
+#define _module_mp_ BIT(23)
+#define _module_hci_ops_os_c_ BIT(24)
+#define _module_rtl871x_ioctl_os_c BIT(25)
+#define _module_rtl8712_cmd_c_ BIT(26)
+#define _module_rtl8192c_xmit_c_ BIT(27)
+#define _module_hal_xmit_c_ BIT(28)
+#define _module_efuse_ BIT(29)
+#define _module_rtl8712_recv_c_ BIT(30)
+#define _module_rtl8712_led_c_ BIT(31)
+
+#define DRIVER_PREFIX "R8188EU: "
+
+extern u32 GlobalDebugLevel;
+
+#define DBG_88E_LEVEL(_level, fmt, arg...) \
+ do { \
+ if (_level <= GlobalDebugLevel) \
+ pr_info(DRIVER_PREFIX"ERROR " fmt, ##arg); \
+ } while (0)
+
+#define DBG_88E(...) \
+ do { \
+ if (_drv_err_ <= GlobalDebugLevel) \
+ pr_info(DRIVER_PREFIX __VA_ARGS__); \
+ } while (0)
+
+#define MSG_88E(...) \
+ do { \
+ if (_drv_err_ <= GlobalDebugLevel) \
+ pr_info(DRIVER_PREFIX __VA_ARGS__); \
+ } while (0)
+
+#define RT_TRACE(_comp, _level, fmt) \
+ do { \
+ if (_level <= GlobalDebugLevel) { \
+ pr_info("%s [0x%08x,%d]", DRIVER_PREFIX, \
+ (unsigned int)_comp, _level); \
+ pr_info fmt; \
+ } \
+ } while (0)
+
+#define _func_enter_ \
+ do { \
+ if (GlobalDebugLevel >= _drv_debug_) \
+ pr_info("%s : %s enters at %d\n", \
+ DRIVER_PREFIX, __func__, __LINE__); \
+ } while (0)
+
+#define _func_exit_ \
+ do { \
+ if (GlobalDebugLevel >= _drv_debug_) \
+ pr_info("%s : %s exits at %d\n", \
+ DRIVER_PREFIX, __func__, __LINE__); \
+ } while (0)
+
+#define RT_PRINT_DATA(_comp, _level, _titlestring, _hexdata, _hexdatalen)\
+ do { \
+ if (_level <= GlobalDebugLevel) { \
+ int __i; \
+ u8 *ptr = (u8 *)_hexdata; \
+ pr_info("%s", DRIVER_PREFIX); \
+ pr_info(_titlestring); \
+ for (__i = 0; __i < (int)_hexdatalen; __i++ ) { \
+ pr_info("%02X%s", ptr[__i], \
+ (((__i + 1) % 4) == 0) ? \
+ " " : " "); \
+ if (((__i + 1) % 16) == 0) \
+ printk("\n"); \
+ } \
+ printk("\n"); \
+ } \
+ } while (0)
+
+int proc_get_drv_version(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_write_reg(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_set_write_reg(struct file *file, const char __user *buffer,
+ unsigned long count, void *data);
+int proc_get_read_reg(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_set_read_reg(struct file *file, const char __user *buffer,
+ unsigned long count, void *data);
+
+int proc_get_fwstate(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+int proc_get_sec_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+int proc_get_mlmext_state(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_qos_option(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+int proc_get_ht_option(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+int proc_get_rf_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+int proc_get_ap_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_adapter_state(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_trx_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_mac_reg_dump1(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_mac_reg_dump2(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_mac_reg_dump3(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_bb_reg_dump1(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_bb_reg_dump2(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_bb_reg_dump3(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_rf_reg_dump1(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_rf_reg_dump2(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_rf_reg_dump3(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_rf_reg_dump4(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+#ifdef CONFIG_88EU_AP_MODE
+
+int proc_get_all_sta_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+#endif
+
+int proc_get_best_channel(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_rx_signal(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_set_rx_signal(struct file *file, const char __user *buffer,
+ unsigned long count, void *data);
+
+int proc_get_ht_enable(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_set_ht_enable(struct file *file, const char __user *buffer,
+ unsigned long count, void *data);
+
+int proc_get_cbw40_enable(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_set_cbw40_enable(struct file *file, const char __user *buffer,
+ unsigned long count, void *data);
+
+int proc_get_ampdu_enable(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_set_ampdu_enable(struct file *file, const char __user *buffer,
+ unsigned long count, void *data);
+
+int proc_get_rx_stbc(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_set_rx_stbc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data);
+
+int proc_get_two_path_rssi(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_get_rssi_disp(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_set_rssi_disp(struct file *file, const char __user *buffer,
+ unsigned long count, void *data);
+
+#ifdef CONFIG_BT_COEXIST
+int proc_get_btcoex_dbg(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data);
+
+int proc_set_btcoex_dbg(struct file *file, const char *buffer,
+ signed long count, void *data);
+
+#endif /* CONFIG_BT_COEXIST */
+
+#endif /* __RTW_DEBUG_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_eeprom.h b/drivers/staging/rtl8188eu/include/rtw_eeprom.h
new file mode 100644
index 00000000000..b2672c3febd
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_eeprom.h
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_EEPROM_H__
+#define __RTW_EEPROM_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define RTL8712_EEPROM_ID 0x8712
+
+#define HWSET_MAX_SIZE_512 512
+#define EEPROM_MAX_SIZE HWSET_MAX_SIZE_512
+
+#define CLOCK_RATE 50 /* 100us */
+
+/* EEPROM opcodes */
+#define EEPROM_READ_OPCODE 06
+#define EEPROM_WRITE_OPCODE 05
+#define EEPROM_ERASE_OPCODE 07
+#define EEPROM_EWEN_OPCODE 19 /* Erase/write enable */
+#define EEPROM_EWDS_OPCODE 16 /* Erase/write disable */
+
+/* Country codes */
+#define USA 0x555320
+#define EUROPE 0x1 /* temp, should be provided later */
+#define JAPAN 0x2 /* temp, should be provided later */
+
+#define EEPROM_CID_DEFAULT 0x0
+#define EEPROM_CID_ALPHA 0x1
+#define EEPROM_CID_Senao 0x3
+#define EEPROM_CID_NetCore 0x5
+#define EEPROM_CID_CAMEO 0X8
+#define EEPROM_CID_SITECOM 0x9
+#define EEPROM_CID_COREGA 0xB
+#define EEPROM_CID_EDIMAX_BELK 0xC
+#define EEPROM_CID_SERCOMM_BELK 0xE
+#define EEPROM_CID_CAMEO1 0xF
+#define EEPROM_CID_WNC_COREGA 0x12
+#define EEPROM_CID_CLEVO 0x13
+#define EEPROM_CID_WHQL 0xFE
+
+/* Customer ID, note that: */
+/* This variable is initiailzed through EEPROM or registry, */
+/* however, its definition may be different with that in EEPROM for */
+/* EEPROM size consideration. So, we have to perform proper translation
+ * between them. */
+/* Besides, CustomerID of registry has precedence of that of EEPROM. */
+/* defined below. 060703, by rcnjko. */
+enum RT_CUSTOMER_ID {
+ RT_CID_DEFAULT = 0,
+ RT_CID_8187_ALPHA0 = 1,
+ RT_CID_8187_SERCOMM_PS = 2,
+ RT_CID_8187_HW_LED = 3,
+ RT_CID_8187_NETGEAR = 4,
+ RT_CID_WHQL = 5,
+ RT_CID_819x_CAMEO = 6,
+ RT_CID_819x_RUNTOP = 7,
+ RT_CID_819x_Senao = 8,
+ RT_CID_TOSHIBA = 9, /* Merge by Jacken, 2008/01/31. */
+ RT_CID_819x_Netcore = 10,
+ RT_CID_Nettronix = 11,
+ RT_CID_DLINK = 12,
+ RT_CID_PRONET = 13,
+ RT_CID_COREGA = 14,
+ RT_CID_CHINA_MOBILE = 15,
+ RT_CID_819x_ALPHA = 16,
+ RT_CID_819x_Sitecom = 17,
+ RT_CID_CCX = 18, /* It's set under CCX logo test and isn't demanded
+ * for CCX functions, but for test behavior like retry
+ * limit and tx report. By Bruce, 2009-02-17. */
+ RT_CID_819x_Lenovo = 19,
+ RT_CID_819x_QMI = 20,
+ RT_CID_819x_Edimax_Belkin = 21,
+ RT_CID_819x_Sercomm_Belkin = 22,
+ RT_CID_819x_CAMEO1 = 23,
+ RT_CID_819x_MSI = 24,
+ RT_CID_819x_Acer = 25,
+ RT_CID_819x_AzWave_ASUS = 26,
+ RT_CID_819x_AzWave = 27, /* For AzWave in PCIe,i
+ * The ID is AzWave use and not only Asus */
+ RT_CID_819x_HP = 28,
+ RT_CID_819x_WNC_COREGA = 29,
+ RT_CID_819x_Arcadyan_Belkin = 30,
+ RT_CID_819x_SAMSUNG = 31,
+ RT_CID_819x_CLEVO = 32,
+ RT_CID_819x_DELL = 33,
+ RT_CID_819x_PRONETS = 34,
+ RT_CID_819x_Edimax_ASUS = 35,
+ RT_CID_819x_CAMEO_NETGEAR = 36,
+ RT_CID_PLANEX = 37,
+ RT_CID_CC_C = 38,
+ RT_CID_819x_Xavi = 39,
+ RT_CID_819x_FUNAI_TV = 40,
+ RT_CID_819x_ALPHA_WD=41,
+};
+
+struct eeprom_priv {
+ u8 bautoload_fail_flag;
+ u8 bloadfile_fail_flag;
+ u8 bloadmac_fail_flag;
+ u8 mac_addr[6]; /* PermanentAddress */
+ u16 channel_plan;
+ u8 EepromOrEfuse;
+ u8 efuse_eeprom_data[HWSET_MAX_SIZE_512];
+};
+
+void eeprom_write16(struct adapter *padapter, u16 reg, u16 data);
+u16 eeprom_read16(struct adapter *padapter, u16 reg);
+void read_eeprom_content(struct adapter *padapter);
+void eeprom_read_sz(struct adapter *adapt, u16 reg, u8 *data, u32 sz);
+void read_eeprom_content_by_attrib(struct adapter *padapter);
+
+#endif /* __RTL871X_EEPROM_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_efuse.h b/drivers/staging/rtl8188eu/include/rtw_efuse.h
new file mode 100644
index 00000000000..cee6b5e8b07
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_efuse.h
@@ -0,0 +1,150 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_EFUSE_H__
+#define __RTW_EFUSE_H__
+
+#include <osdep_service.h>
+
+#define EFUSE_ERROE_HANDLE 1
+
+#define PG_STATE_HEADER 0x01
+#define PG_STATE_WORD_0 0x02
+#define PG_STATE_WORD_1 0x04
+#define PG_STATE_WORD_2 0x08
+#define PG_STATE_WORD_3 0x10
+#define PG_STATE_DATA 0x20
+
+#define PG_SWBYTE_H 0x01
+#define PG_SWBYTE_L 0x02
+
+#define PGPKT_DATA_SIZE 8
+
+#define EFUSE_WIFI 0
+#define EFUSE_BT 1
+
+enum _EFUSE_DEF_TYPE {
+ TYPE_EFUSE_MAX_SECTION = 0,
+ TYPE_EFUSE_REAL_CONTENT_LEN = 1,
+ TYPE_AVAILABLE_EFUSE_BYTES_BANK = 2,
+ TYPE_AVAILABLE_EFUSE_BYTES_TOTAL = 3,
+ TYPE_EFUSE_MAP_LEN = 4,
+ TYPE_EFUSE_PROTECT_BYTES_BANK = 5,
+ TYPE_EFUSE_CONTENT_LEN_BANK = 6,
+};
+
+/* E-Fuse */
+#define EFUSE_MAP_SIZE 512
+#define EFUSE_MAX_SIZE 256
+/* end of E-Fuse */
+
+#define EFUSE_MAX_MAP_LEN 512
+#define EFUSE_MAX_HW_SIZE 512
+#define EFUSE_MAX_SECTION_BASE 16
+
+#define EXT_HEADER(header) ((header & 0x1F) == 0x0F)
+#define ALL_WORDS_DISABLED(wde) ((wde & 0x0F) == 0x0F)
+#define GET_HDR_OFFSET_2_0(header) ((header & 0xE0) >> 5)
+
+#define EFUSE_REPEAT_THRESHOLD_ 3
+
+/* The following is for BT Efuse definition */
+#define EFUSE_BT_MAX_MAP_LEN 1024
+#define EFUSE_MAX_BANK 4
+#define EFUSE_MAX_BT_BANK (EFUSE_MAX_BANK-1)
+/*--------------------------Define Parameters-------------------------------*/
+#define EFUSE_MAX_WORD_UNIT 4
+
+/*------------------------------Define structure----------------------------*/
+struct pgpkt {
+ u8 offset;
+ u8 word_en;
+ u8 data[8];
+ u8 word_cnts;
+};
+
+/*------------------------------Define structure----------------------------*/
+struct efuse_hal {
+ u8 fakeEfuseBank;
+ u32 fakeEfuseUsedBytes;
+ u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE];
+ u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN];
+ u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN];
+
+ u16 BTEfuseUsedBytes;
+ u8 BTEfuseUsedPercentage;
+ u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+ u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN];
+ u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN];
+
+ u16 fakeBTEfuseUsedBytes;
+ u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+ u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN];
+ u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN];
+};
+
+/*------------------------Export global variable----------------------------*/
+extern u8 fakeEfuseBank;
+extern u32 fakeEfuseUsedBytes;
+extern u8 fakeEfuseContent[];
+extern u8 fakeEfuseInitMap[];
+extern u8 fakeEfuseModifiedMap[];
+
+extern u32 BTEfuseUsedBytes;
+extern u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+extern u8 BTEfuseInitMap[];
+extern u8 BTEfuseModifiedMap[];
+
+extern u32 fakeBTEfuseUsedBytes;
+extern u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+extern u8 fakeBTEfuseInitMap[];
+extern u8 fakeBTEfuseModifiedMap[];
+/*------------------------Export global variable----------------------------*/
+
+u8 efuse_GetCurrentSize(struct adapter *adapter, u16 *size);
+u16 efuse_GetMaxSize(struct adapter *adapter);
+u8 rtw_efuse_access(struct adapter *adapter, u8 read, u16 start_addr,
+ u16 cnts, u8 *data);
+u8 rtw_efuse_map_read(struct adapter *adapter, u16 addr, u16 cnts, u8 *data);
+u8 rtw_efuse_map_write(struct adapter *adapter, u16 addr, u16 cnts, u8 *data);
+u8 rtw_BT_efuse_map_read(struct adapter *adapter, u16 addr,
+ u16 cnts, u8 *data);
+u8 rtw_BT_efuse_map_write(struct adapter *adapter, u16 addr,
+ u16 cnts, u8 *data);
+u16 Efuse_GetCurrentSize(struct adapter *adapter, u8 efusetype, bool test);
+u8 Efuse_CalculateWordCnts(u8 word_en);
+void ReadEFuseByte(struct adapter *adapter, u16 _offset, u8 *pbuf, bool test);
+void EFUSE_GetEfuseDefinition(struct adapter *adapt, u8 type, u8 type1,
+ void *out, bool bPseudoTest);
+u8 efuse_OneByteRead(struct adapter *adapter, u16 addr, u8 *data, bool test);
+u8 efuse_OneByteWrite(struct adapter *adapter, u16 addr, u8 data, bool test);
+
+void Efuse_PowerSwitch(struct adapter *adapt,u8 bWrite,u8 PwrState);
+int Efuse_PgPacketRead(struct adapter *adapt, u8 offset, u8 *data, bool test);
+int Efuse_PgPacketWrite(struct adapter *adapter, u8 offset, u8 word, u8 *data,
+ bool test);
+void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata);
+u8 Efuse_WordEnableDataWrite(struct adapter *adapter, u16 efuse_addr,
+ u8 word_en, u8 *data, bool test);
+
+u8 EFUSE_Read1Byte(struct adapter *adapter, u16 address);
+void EFUSE_ShadowMapUpdate(struct adapter *adapter, u8 efusetype, bool test);
+void EFUSE_ShadowRead(struct adapter *adapt, u8 type, u16 offset, u32 *val);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_event.h b/drivers/staging/rtl8188eu/include/rtw_event.h
new file mode 100644
index 00000000000..52151dc4495
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_event.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_EVENT_H_
+#define _RTW_EVENT_H_
+
+#include <osdep_service.h>
+
+#include <wlan_bssdef.h>
+#include <linux/semaphore.h>
+#include <linux/sem.h>
+
+/*
+Used to report a bss has been scanned
+*/
+struct survey_event {
+ struct wlan_bssid_ex bss;
+};
+
+/*
+Used to report that the requested site survey has been done.
+
+bss_cnt indicates the number of bss that has been reported.
+
+
+*/
+struct surveydone_event {
+ unsigned int bss_cnt;
+
+};
+
+/*
+Used to report the link result of joinning the given bss
+
+
+join_res:
+-1: authentication fail
+-2: association fail
+> 0: TID
+
+*/
+struct joinbss_event {
+ struct wlan_network network;
+};
+
+/*
+Used to report a given STA has joinned the created BSS.
+It is used in AP/Ad-HoC(M) mode.
+*/
+
+struct stassoc_event {
+ unsigned char macaddr[6];
+ unsigned char rsvd[2];
+ int cam_id;
+};
+
+struct stadel_event {
+ unsigned char macaddr[6];
+ unsigned char rsvd[2]; /* for reason */
+ int mac_id;
+};
+
+struct addba_event {
+ unsigned int tid;
+};
+
+#define GEN_EVT_CODE(event) event ## _EVT_
+
+struct fwevent {
+ u32 parmsize;
+ void (*event_callback)(struct adapter *dev, u8 *pbuf);
+};
+
+#define C2HEVENT_SZ 32
+
+struct event_node {
+ unsigned char *node;
+ unsigned char evt_code;
+ unsigned short evt_sz;
+ int *caller_ff_tail;
+ int caller_ff_sz;
+};
+
+struct c2hevent_queue {
+ int head;
+ int tail;
+ struct event_node nodes[C2HEVENT_SZ];
+ unsigned char seq;
+};
+
+#define NETWORK_QUEUE_SZ 4
+
+struct network_queue {
+ int head;
+ int tail;
+ struct wlan_bssid_ex networks[NETWORK_QUEUE_SZ];
+};
+
+#endif /* _WLANEVENT_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_ht.h b/drivers/staging/rtl8188eu/include/rtw_ht.h
new file mode 100644
index 00000000000..beb210b3708
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_ht.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_HT_H_
+#define _RTW_HT_H_
+
+#include <osdep_service.h>
+#include "wifi.h"
+
+struct ht_priv {
+ u32 ht_option;
+ u32 ampdu_enable;/* for enable Tx A-MPDU */
+ u32 tx_amsdu_enable;/* for enable Tx A-MSDU */
+ u32 tx_amdsu_maxlen; /* 1: 8k, 0:4k ; default:8k, for tx */
+ u32 rx_ampdu_maxlen; /* for rx reordering ctrl win_sz,
+ * updated when join_callback. */
+ u8 bwmode;/* */
+ u8 ch_offset;/* PRIME_CHNL_OFFSET */
+ u8 sgi;/* short GI */
+
+ /* for processing Tx A-MPDU */
+ u8 agg_enable_bitmap;
+ u8 candidate_tid_bitmap;
+
+ struct rtw_ieee80211_ht_cap ht_cap;
+};
+
+#endif /* _RTL871X_HT_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_io.h b/drivers/staging/rtl8188eu/include/rtw_io.h
new file mode 100644
index 00000000000..eb6f0e550ac
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_io.h
@@ -0,0 +1,387 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#ifndef _RTW_IO_H_
+#define _RTW_IO_H_
+
+#include <osdep_service.h>
+#include <osdep_intf.h>
+
+#include <asm/byteorder.h>
+#include <linux/semaphore.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+
+#define rtw_usb_buffer_alloc(dev, size, dma) \
+ usb_alloc_coherent((dev), (size), (in_interrupt() ? \
+ GFP_ATOMIC : GFP_KERNEL), (dma))
+#define rtw_usb_buffer_free(dev, size, addr, dma) \
+ usb_free_coherent((dev), (size), (addr), (dma))
+
+#define NUM_IOREQ 8
+
+#define MAX_PROT_SZ (64-16)
+
+#define _IOREADY 0
+#define _IO_WAIT_COMPLETE 1
+#define _IO_WAIT_RSP 2
+
+/* IO COMMAND TYPE */
+#define _IOSZ_MASK_ (0x7F)
+#define _IO_WRITE_ BIT(7)
+#define _IO_FIXED_ BIT(8)
+#define _IO_BURST_ BIT(9)
+#define _IO_BYTE_ BIT(10)
+#define _IO_HW_ BIT(11)
+#define _IO_WORD_ BIT(12)
+#define _IO_SYNC_ BIT(13)
+#define _IO_CMDMASK_ (0x1F80)
+
+/*
+ For prompt mode accessing, caller shall free io_req
+ Otherwise, io_handler will free io_req
+*/
+
+/* IO STATUS TYPE */
+#define _IO_ERR_ BIT(2)
+#define _IO_SUCCESS_ BIT(1)
+#define _IO_DONE_ BIT(0)
+
+#define IO_RD32 (_IO_SYNC_ | _IO_WORD_)
+#define IO_RD16 (_IO_SYNC_ | _IO_HW_)
+#define IO_RD8 (_IO_SYNC_ | _IO_BYTE_)
+
+#define IO_RD32_ASYNC (_IO_WORD_)
+#define IO_RD16_ASYNC (_IO_HW_)
+#define IO_RD8_ASYNC (_IO_BYTE_)
+
+#define IO_WR32 (_IO_WRITE_ | _IO_SYNC_ | _IO_WORD_)
+#define IO_WR16 (_IO_WRITE_ | _IO_SYNC_ | _IO_HW_)
+#define IO_WR8 (_IO_WRITE_ | _IO_SYNC_ | _IO_BYTE_)
+
+#define IO_WR32_ASYNC (_IO_WRITE_ | _IO_WORD_)
+#define IO_WR16_ASYNC (_IO_WRITE_ | _IO_HW_)
+#define IO_WR8_ASYNC (_IO_WRITE_ | _IO_BYTE_)
+
+/*
+ Only Sync. burst accessing is provided.
+*/
+
+#define IO_WR_BURST(x) \
+ (_IO_WRITE_ | _IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_))
+#define IO_RD_BURST(x) \
+ (_IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_))
+
+/* below is for the intf_option bit defition... */
+
+#define _INTF_ASYNC_ BIT(0) /* support async io */
+
+struct intf_priv;
+struct intf_hdl;
+struct io_queue;
+
+struct _io_ops {
+ u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr);
+ u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr);
+ u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr);
+ int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
+ int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
+ int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
+ int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length,
+ u8 *pdata);
+ int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
+ int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
+ int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
+ void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+ u8 *pmem);
+ void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+ u8 *pmem);
+ void (*_sync_irp_protocol_rw)(struct io_queue *pio_q);
+ u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr);
+ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+ u8 *pmem);
+ u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+ u8 *pmem);
+ u32 (*_write_scsi)(struct intf_hdl *pintfhdl,u32 cnt, u8 *pmem);
+ void (*_read_port_cancel)(struct intf_hdl *pintfhdl);
+ void (*_write_port_cancel)(struct intf_hdl *pintfhdl);
+};
+
+struct io_req {
+ struct list_head list;
+ u32 addr;
+ u32 val;
+ u32 command;
+ u32 status;
+ u8 *pbuf;
+ struct semaphore sema;
+
+ void (*_async_io_callback)(struct adapter *padater,
+ struct io_req *pio_req, u8 *cnxt);
+ u8 *cnxt;
+};
+
+struct intf_hdl {
+ struct adapter *padapter;
+ struct dvobj_priv *pintf_dev;
+ struct _io_ops io_ops;
+};
+
+struct reg_protocol_rd {
+#ifdef __LITTLE_ENDIAN
+ /* DW1 */
+ u32 NumOfTrans:4;
+ u32 Reserved1:4;
+ u32 Reserved2:24;
+ /* DW2 */
+ u32 ByteCount:7;
+ u32 WriteEnable:1; /* 0:read, 1:write */
+ u32 FixOrContinuous:1; /* 0:continuous, 1: Fix */
+ u32 BurstMode:1;
+ u32 Byte1Access:1;
+ u32 Byte2Access:1;
+ u32 Byte4Access:1;
+ u32 Reserved3:3;
+ u32 Reserved4:16;
+ /* DW3 */
+ u32 BusAddress;
+ /* DW4 */
+ /* u32 Value; */
+#else
+/* DW1 */
+ u32 Reserved1:4;
+ u32 NumOfTrans:4;
+ u32 Reserved2:24;
+ /* DW2 */
+ u32 WriteEnable:1;
+ u32 ByteCount:7;
+ u32 Reserved3:3;
+ u32 Byte4Access:1;
+
+ u32 Byte2Access:1;
+ u32 Byte1Access:1;
+ u32 BurstMode:1;
+ u32 FixOrContinuous:1;
+ u32 Reserved4:16;
+ /* DW3 */
+ u32 BusAddress;
+
+ /* DW4 */
+#endif
+};
+
+struct reg_protocol_wt {
+#ifdef __LITTLE_ENDIAN
+ /* DW1 */
+ u32 NumOfTrans:4;
+ u32 Reserved1:4;
+ u32 Reserved2:24;
+ /* DW2 */
+ u32 ByteCount:7;
+ u32 WriteEnable:1; /* 0:read, 1:write */
+ u32 FixOrContinuous:1; /* 0:continuous, 1: Fix */
+ u32 BurstMode:1;
+ u32 Byte1Access:1;
+ u32 Byte2Access:1;
+ u32 Byte4Access:1;
+ u32 Reserved3:3;
+ u32 Reserved4:16;
+ /* DW3 */
+ u32 BusAddress;
+ /* DW4 */
+ u32 Value;
+#else
+ /* DW1 */
+ u32 Reserved1 :4;
+ u32 NumOfTrans:4;
+ u32 Reserved2:24;
+ /* DW2 */
+ u32 WriteEnable:1;
+ u32 ByteCount:7;
+ u32 Reserved3:3;
+ u32 Byte4Access:1;
+ u32 Byte2Access:1;
+ u32 Byte1Access:1;
+ u32 BurstMode:1;
+ u32 FixOrContinuous:1;
+ u32 Reserved4:16;
+ /* DW3 */
+ u32 BusAddress;
+ /* DW4 */
+ u32 Value;
+#endif
+};
+
+/*
+Below is the data structure used by _io_handler
+*/
+
+struct io_queue {
+ spinlock_t lock;
+ struct list_head free_ioreqs;
+ struct list_head pending; /* The io_req list that will be served
+ * in the single protocol read/write.*/
+ struct list_head processing;
+ u8 *free_ioreqs_buf; /* 4-byte aligned */
+ u8 *pallocated_free_ioreqs_buf;
+ struct intf_hdl intf;
+};
+
+struct io_priv {
+ struct adapter *padapter;
+ struct intf_hdl intf;
+};
+
+uint ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue);
+void sync_ioreq_enqueue(struct io_req *preq,struct io_queue *ioqueue);
+uint sync_ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue);
+uint free_ioreq(struct io_req *preq, struct io_queue *pio_queue);
+struct io_req *alloc_ioreq(struct io_queue *pio_q);
+
+uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl);
+void unregister_intf_hdl(struct intf_hdl *pintfhdl);
+
+void _rtw_attrib_read(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void _rtw_attrib_write(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+
+u8 _rtw_read8(struct adapter *adapter, u32 addr);
+u16 _rtw_read16(struct adapter *adapter, u32 addr);
+u32 _rtw_read32(struct adapter *adapter, u32 addr);
+void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void _rtw_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void _rtw_read_port_cancel(struct adapter *adapter);
+
+int _rtw_write8(struct adapter *adapter, u32 addr, u8 val);
+int _rtw_write16(struct adapter *adapter, u32 addr, u16 val);
+int _rtw_write32(struct adapter *adapter, u32 addr, u32 val);
+int _rtw_writeN(struct adapter *adapter, u32 addr, u32 length, u8 *pdata);
+
+int _rtw_write8_async(struct adapter *adapter, u32 addr, u8 val);
+int _rtw_write16_async(struct adapter *adapter, u32 addr, u16 val);
+int _rtw_write32_async(struct adapter *adapter, u32 addr, u32 val);
+
+void _rtw_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+u32 _rtw_write_port_and_wait(struct adapter *adapter, u32 addr, u32 cnt,
+ u8 *pmem, int timeout_ms);
+void _rtw_write_port_cancel(struct adapter *adapter);
+
+#define rtw_read8(adapter, addr) _rtw_read8((adapter), (addr))
+#define rtw_read16(adapter, addr) _rtw_read16((adapter), (addr))
+#define rtw_read32(adapter, addr) _rtw_read32((adapter), (addr))
+#define rtw_read_mem(adapter, addr, cnt, mem) \
+ _rtw_read_mem((adapter), (addr), (cnt), (mem))
+#define rtw_read_port(adapter, addr, cnt, mem) \
+ _rtw_read_port((adapter), (addr), (cnt), (mem))
+#define rtw_read_port_cancel(adapter) _rtw_read_port_cancel((adapter))
+
+#define rtw_write8(adapter, addr, val) \
+ _rtw_write8((adapter), (addr), (val))
+#define rtw_write16(adapter, addr, val) \
+ _rtw_write16((adapter), (addr), (val))
+#define rtw_write32(adapter, addr, val) \
+ _rtw_write32((adapter), (addr), (val))
+#define rtw_writeN(adapter, addr, length, data) \
+ _rtw_writeN((adapter), (addr), (length), (data))
+#define rtw_write8_async(adapter, addr, val) \
+ _rtw_write8_async((adapter), (addr), (val))
+#define rtw_write16_async(adapter, addr, val) \
+ _rtw_write16_async((adapter), (addr), (val))
+#define rtw_write32_async(adapter, addr, val) \
+ _rtw_write32_async((adapter), (addr), (val))
+#define rtw_write_mem(adapter, addr, cnt, mem) \
+ _rtw_write_mem((adapter), (addr), (cnt), (mem))
+#define rtw_write_port(adapter, addr, cnt, mem) \
+ _rtw_write_port((adapter), (addr), (cnt), (mem))
+#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms) \
+ _rtw_write_port_and_wait((adapter), (addr), (cnt), (mem), (timeout_ms))
+#define rtw_write_port_cancel(adapter) _rtw_write_port_cancel((adapter))
+
+void rtw_write_scsi(struct adapter *adapter, u32 cnt, u8 *pmem);
+
+/* ioreq */
+void ioreq_read8(struct adapter *adapter, u32 addr, u8 *pval);
+void ioreq_read16(struct adapter *adapter, u32 addr, u16 *pval);
+void ioreq_read32(struct adapter *adapter, u32 addr, u32 *pval);
+void ioreq_write8(struct adapter *adapter, u32 addr, u8 val);
+void ioreq_write16(struct adapter *adapter, u32 addr, u16 val);
+void ioreq_write32(struct adapter *adapter, u32 addr, u32 val);
+
+uint async_read8(struct adapter *adapter, u32 addr, u8 *pbuff,
+ void (*_async_io_callback)(struct adapter *padater,
+ struct io_req *pio_req,
+ u8 *cnxt), u8 *cnxt);
+uint async_read16(struct adapter *adapter, u32 addr, u8 *pbuff,
+ void (*_async_io_callback)(struct adapter *padater,
+ struct io_req *pio_req,
+ u8 *cnxt), u8 *cnxt);
+uint async_read32(struct adapter *adapter, u32 addr, u8 *pbuff,
+ void (*_async_io_callback)(struct adapter *padater,
+ struct io_req *pio_req,
+ u8 *cnxt), u8 *cnxt);
+
+void async_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void async_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+
+void async_write8(struct adapter *adapter, u32 addr, u8 val,
+ void (*_async_io_callback)(struct adapter *padater,
+ struct io_req *pio_req,
+ u8 *cnxt), u8 *cnxt);
+void async_write16(struct adapter *adapter, u32 addr, u16 val,
+ void (*_async_io_callback)(struct adapter *padater,
+ struct io_req *pio_req,
+ u8 *cnxt), u8 *cnxt);
+void async_write32(struct adapter *adapter, u32 addr, u32 val,
+ void (*_async_io_callback)(struct adapter *padater,
+ struct io_req *pio_req,
+ u8 *cnxt), u8 *cnxt);
+
+void async_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void async_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+
+int rtw_init_io_priv(struct adapter *padapter,
+ void (*set_intf_ops)(struct _io_ops *pops));
+
+uint alloc_io_queue(struct adapter *adapter);
+void free_io_queue(struct adapter *adapter);
+void async_bus_io(struct io_queue *pio_q);
+void bus_sync_io(struct io_queue *pio_q);
+u32 _ioreq2rwmem(struct io_queue *pio_q);
+void dev_power_down(struct adapter * Adapter, u8 bpwrup);
+
+#define PlatformEFIOWrite1Byte(_a,_b,_c) \
+ rtw_write8(_a,_b,_c)
+#define PlatformEFIOWrite2Byte(_a,_b,_c) \
+ rtw_write16(_a,_b,_c)
+#define PlatformEFIOWrite4Byte(_a,_b,_c) \
+ rtw_write32(_a,_b,_c)
+
+#define PlatformEFIORead1Byte(_a,_b) \
+ rtw_read8(_a,_b)
+#define PlatformEFIORead2Byte(_a,_b) \
+ rtw_read16(_a,_b)
+#define PlatformEFIORead4Byte(_a,_b) \
+ rtw_read32(_a,_b)
+
+#endif /* _RTL8711_IO_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_ioctl.h b/drivers/staging/rtl8188eu/include/rtw_ioctl.h
new file mode 100644
index 00000000000..8772d1d178c
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_ioctl.h
@@ -0,0 +1,124 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_IOCTL_H_
+#define _RTW_IOCTL_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+#ifndef OID_802_11_CAPABILITY
+ #define OID_802_11_CAPABILITY 0x0d010122
+#endif
+
+#ifndef OID_802_11_PMKID
+ #define OID_802_11_PMKID 0x0d010123
+#endif
+
+
+/* For DDK-defined OIDs */
+#define OID_NDIS_SEG1 0x00010100
+#define OID_NDIS_SEG2 0x00010200
+#define OID_NDIS_SEG3 0x00020100
+#define OID_NDIS_SEG4 0x01010100
+#define OID_NDIS_SEG5 0x01020100
+#define OID_NDIS_SEG6 0x01020200
+#define OID_NDIS_SEG7 0xFD010100
+#define OID_NDIS_SEG8 0x0D010100
+#define OID_NDIS_SEG9 0x0D010200
+#define OID_NDIS_SEG10 0x0D020200
+
+#define SZ_OID_NDIS_SEG1 23
+#define SZ_OID_NDIS_SEG2 3
+#define SZ_OID_NDIS_SEG3 6
+#define SZ_OID_NDIS_SEG4 6
+#define SZ_OID_NDIS_SEG5 4
+#define SZ_OID_NDIS_SEG6 8
+#define SZ_OID_NDIS_SEG7 7
+#define SZ_OID_NDIS_SEG8 36
+#define SZ_OID_NDIS_SEG9 24
+#define SZ_OID_NDIS_SEG10 19
+
+/* For Realtek-defined OIDs */
+#define OID_MP_SEG1 0xFF871100
+#define OID_MP_SEG2 0xFF818000
+
+#define OID_MP_SEG3 0xFF818700
+#define OID_MP_SEG4 0xFF011100
+
+#define DEBUG_OID(dbg, str) \
+ if ((!dbg)) { \
+ RT_TRACE(_module_rtl871x_ioctl_c_, _drv_info_, \
+ ("%s(%d): %s", __func__, __line__, str)); \
+ }
+
+enum oid_type {
+ QUERY_OID,
+ SET_OID
+};
+
+struct oid_funs_node {
+ unsigned int oid_start; /* the starting number for OID */
+ unsigned int oid_end; /* the ending number for OID */
+ struct oid_obj_priv *node_array;
+ unsigned int array_sz; /* the size of node_array */
+ int query_counter; /* count the number of query hits for this segment */
+ int set_counter; /* count the number of set hits for this segment */
+};
+
+struct oid_par_priv {
+ void *adapter_context;
+ NDIS_OID oid;
+ void *information_buf;
+ u32 information_buf_len;
+ u32 *bytes_rw;
+ u32 *bytes_needed;
+ enum oid_type type_of_oid;
+ u32 dbg;
+};
+
+struct oid_obj_priv {
+ unsigned char dbg; /* 0: without OID debug message
+ * 1: with OID debug message */
+ int (*oidfuns)(struct oid_par_priv *poid_par_priv);
+};
+
+#if defined(_RTW_MP_IOCTL_C_)
+static int oid_null_function(struct oid_par_priv *poid_par_priv) {
+ _func_enter_;
+ _func_exit_;
+ return NDIS_STATUS_SUCCESS;
+}
+#endif
+
+extern struct iw_handler_def rtw_handlers_def;
+
+int drv_query_info(struct net_device *miniportadaptercontext, NDIS_OID oid,
+ void *informationbuffer, u32 informationbufferlength,
+ u32 *byteswritten, u32 *bytesneeded);
+
+int drv_set_info(struct net_device *MiniportAdapterContext,
+ NDIS_OID oid, void *informationbuffer,
+ u32 informationbufferlength, u32 *bytesread,
+ u32 *bytesneeded);
+
+extern int ui_pid[3];
+
+#endif /* #ifndef __INC_CEINFO_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_ioctl_rtl.h b/drivers/staging/rtl8188eu/include/rtw_ioctl_rtl.h
new file mode 100644
index 00000000000..8fa3858cb77
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_ioctl_rtl.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_IOCTL_RTL_H_
+#define _RTW_IOCTL_RTL_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+/* oid_rtl_seg_01_01 ************** */
+int oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv);/* 84 */
+int oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv);
+
+int oid_rt_pro_set_fw_dig_state_hdl(struct oid_par_priv *poid_par_priv);/* 8a */
+int oid_rt_pro_set_fw_ra_state_hdl(struct oid_par_priv *poid_par_priv); /* 8b */
+
+int oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv);/* 93 */
+int oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_set_channelplan_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_set_preamble_mode_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_dedicate_probe_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_current_tx_power_level_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_supported_wireless_mode_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv *poid_par_priv);
+
+/* oid_rtl_seg_01_03 section start ************** */
+int oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv *priv);
+int oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv);
+
+/* oid_rtl_seg_01_11 */
+int oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv);
+
+/* oid_rtl_seg_03_00 section start ************** */
+int oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_ioctl_set.h b/drivers/staging/rtl8188eu/include/rtw_ioctl_set.h
new file mode 100644
index 00000000000..49efb23747d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_ioctl_set.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_IOCTL_SET_H_
+#define __RTW_IOCTL_SET_H_
+
+#include <drv_types.h>
+
+
+typedef u8 NDIS_802_11_PMKID_VALUE[16];
+
+u8 rtw_set_802_11_add_key(struct adapter *adapt, struct ndis_802_11_key *key);
+u8 rtw_set_802_11_authentication_mode(struct adapter *adapt,
+ enum ndis_802_11_auth_mode authmode);
+u8 rtw_set_802_11_bssid(struct adapter*adapter, u8 *bssid);
+u8 rtw_set_802_11_add_wep(struct adapter *adapter, struct ndis_802_11_wep *wep);
+u8 rtw_set_802_11_disassociate(struct adapter *adapter);
+u8 rtw_set_802_11_bssid_list_scan(struct adapter*adapter,
+ struct ndis_802_11_ssid *pssid,
+ int ssid_max_num);
+u8 rtw_set_802_11_infrastructure_mode(struct adapter *adapter,
+ enum ndis_802_11_network_infra type);
+u8 rtw_set_802_11_remove_wep(struct adapter *adapter, u32 keyindex);
+u8 rtw_set_802_11_ssid(struct adapter *adapt, struct ndis_802_11_ssid *ssid);
+u8 rtw_set_802_11_remove_key(struct adapter *adapt,
+ struct ndis_802_11_remove_key *key);
+u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid);
+u16 rtw_get_cur_max_rate(struct adapter *adapter);
+int rtw_set_scan_mode(struct adapter *adapter, enum rt_scan_type scan_mode);
+int rtw_set_channel_plan(struct adapter *adapter, u8 channel_plan);
+int rtw_set_country(struct adapter *adapter, const char *country_code);
+int rtw_change_ifname(struct adapter *padapter, const char *ifname);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_iol.h b/drivers/staging/rtl8188eu/include/rtw_iol.h
new file mode 100644
index 00000000000..6949922baa6
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_iol.h
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_IOL_H_
+#define __RTW_IOL_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define IOREG_CMD_END_LEN 4
+
+struct ioreg_cfg {
+ u8 length;
+ u8 cmd_id;
+ __le16 address;
+ __le32 data;
+ __le32 mask;
+};
+
+enum ioreg_cmd {
+ IOREG_CMD_LLT = 0x01,
+ IOREG_CMD_REFUSE = 0x02,
+ IOREG_CMD_EFUSE_PATH = 0x03,
+ IOREG_CMD_WB_REG = 0x04,
+ IOREG_CMD_WW_REG = 0x05,
+ IOREG_CMD_WD_REG = 0x06,
+ IOREG_CMD_W_RF = 0x07,
+ IOREG_CMD_DELAY_US = 0x10,
+ IOREG_CMD_DELAY_MS = 0x11,
+ IOREG_CMD_END = 0xFF,
+};
+
+struct xmit_frame *rtw_IOL_accquire_xmit_frame(struct adapter *adapter);
+int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds,
+ u32 cmd_len);
+int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary);
+int rtw_IOL_exec_cmds_sync(struct adapter *adapter,
+ struct xmit_frame *xmit_frame, u32 max_wating_ms,
+ u32 bndy_cnt);
+bool rtw_IOL_applied(struct adapter *adapter);
+int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us);
+int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms);
+int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame);
+
+void read_efuse_from_txpktbuf(struct adapter *adapter, int bcnhead,
+ u8 *content, u16 *size);
+
+int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr,
+ u8 value, u8 mask);
+int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr,
+ u16 value, u16 mask);
+int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr,
+ u32 value, u32 mask);
+int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path,
+ u16 addr, u32 value, u32 mask);
+#define rtw_IOL_append_WB_cmd(xmit_frame, addr, value, mask) \
+ _rtw_IOL_append_WB_cmd((xmit_frame), (addr), (value) ,(mask))
+#define rtw_IOL_append_WW_cmd(xmit_frame, addr, value, mask) \
+ _rtw_IOL_append_WW_cmd((xmit_frame), (addr), (value),(mask))
+#define rtw_IOL_append_WD_cmd(xmit_frame, addr, value, mask) \
+ _rtw_IOL_append_WD_cmd((xmit_frame), (addr), (value), (mask))
+#define rtw_IOL_append_WRF_cmd(xmit_frame, rf_path, addr, value, mask) \
+ _rtw_IOL_append_WRF_cmd((xmit_frame),(rf_path), (addr), (value), (mask))
+
+u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame);
+void rtw_IOL_cmd_buf_dump(struct adapter *Adapter,int buf_len,u8 *pbuf);
+
+#endif /* __RTW_IOL_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_led.h b/drivers/staging/rtl8188eu/include/rtw_led.h
new file mode 100644
index 00000000000..2e618043d35
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_led.h
@@ -0,0 +1,197 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_LED_H_
+#define __RTW_LED_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000)
+
+#define LED_BLINK_NORMAL_INTERVAL 100
+#define LED_BLINK_SLOWLY_INTERVAL 200
+#define LED_BLINK_LONG_INTERVAL 400
+
+#define LED_BLINK_NO_LINK_INTERVAL_ALPHA 1000
+#define LED_BLINK_LINK_INTERVAL_ALPHA 500 /* 500 */
+#define LED_BLINK_SCAN_INTERVAL_ALPHA 180 /* 150 */
+#define LED_BLINK_FASTER_INTERVAL_ALPHA 50
+#define LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA 5000
+
+#define LED_BLINK_NORMAL_INTERVAL_NETTRONIX 100
+#define LED_BLINK_SLOWLY_INTERVAL_NETTRONIX 2000
+
+#define LED_BLINK_SLOWLY_INTERVAL_PORNET 1000
+#define LED_BLINK_NORMAL_INTERVAL_PORNET 100
+
+#define LED_BLINK_FAST_INTERVAL_BITLAND 30
+
+/* 060403, rcnjko: Customized for AzWave. */
+#define LED_CM2_BLINK_ON_INTERVAL 250
+#define LED_CM2_BLINK_OFF_INTERVAL 4750
+
+#define LED_CM8_BLINK_INTERVAL 500 /* for QMI */
+#define LED_CM8_BLINK_OFF_INTERVAL 3750 /* for QMI */
+
+/* 080124, lanhsin: Customized for RunTop */
+#define LED_RunTop_BLINK_INTERVAL 300
+
+/* 060421, rcnjko: Customized for Sercomm Printer Server case. */
+#define LED_CM3_BLINK_INTERVAL 1500
+
+enum LED_CTL_MODE {
+ LED_CTL_POWER_ON = 1,
+ LED_CTL_LINK = 2,
+ LED_CTL_NO_LINK = 3,
+ LED_CTL_TX = 4,
+ LED_CTL_RX = 5,
+ LED_CTL_SITE_SURVEY = 6,
+ LED_CTL_POWER_OFF = 7,
+ LED_CTL_START_TO_LINK = 8,
+ LED_CTL_START_WPS = 9,
+ LED_CTL_STOP_WPS = 10,
+ LED_CTL_START_WPS_BOTTON = 11, /* added for runtop */
+ LED_CTL_STOP_WPS_FAIL = 12, /* added for ALPHA */
+ LED_CTL_STOP_WPS_FAIL_OVERLAP = 13, /* added for BELKIN */
+ LED_CTL_CONNECTION_NO_TRANSFER = 14,
+};
+
+enum LED_STATE_871x {
+ LED_UNKNOWN = 0,
+ RTW_LED_ON = 1,
+ RTW_LED_OFF = 2,
+ LED_BLINK_NORMAL = 3,
+ LED_BLINK_SLOWLY = 4,
+ LED_BLINK_POWER_ON = 5,
+ LED_BLINK_SCAN = 6, /* LED is blinking during scanning period,
+ * the # of times to blink is depend on time
+ * for scanning. */
+ LED_BLINK_NO_LINK = 7, /* LED is blinking during no link state. */
+ LED_BLINK_StartToBlink = 8,/* Customzied for Sercomm Printer
+ * Server case */
+ LED_BLINK_TXRX = 9,
+ LED_BLINK_WPS = 10, /* LED is blinkg during WPS communication */
+ LED_BLINK_WPS_STOP = 11, /* for ALPHA */
+ LED_BLINK_WPS_STOP_OVERLAP = 12, /* for BELKIN */
+ LED_BLINK_RUNTOP = 13, /* Customized for RunTop */
+ LED_BLINK_CAMEO = 14,
+ LED_BLINK_XAVI = 15,
+ LED_BLINK_ALWAYS_ON = 16,
+};
+
+enum LED_PIN_871x {
+ LED_PIN_NULL = 0,
+ LED_PIN_LED0 = 1,
+ LED_PIN_LED1 = 2,
+ LED_PIN_LED2 = 3,
+ LED_PIN_GPIO0 = 4,
+};
+
+struct LED_871x {
+ struct adapter *padapter;
+
+ enum LED_PIN_871x LedPin; /* Identify how to implement this
+ * SW led. */
+ enum LED_STATE_871x CurrLedState; /* Current LED state. */
+ enum LED_STATE_871x BlinkingLedState; /* Next state for blinking,
+ * either RTW_LED_ON or RTW_LED_OFF are. */
+
+ u8 bLedOn; /* true if LED is ON, false if LED is OFF. */
+
+ u8 bLedBlinkInProgress; /* true if it is blinking, false o.w.. */
+
+ u8 bLedWPSBlinkInProgress;
+
+ u32 BlinkTimes; /* Number of times to toggle led state for blinking. */
+
+ struct timer_list BlinkTimer; /* Timer object for led blinking. */
+
+ u8 bSWLedCtrl;
+
+ /* ALPHA, added by chiyoko, 20090106 */
+ u8 bLedNoLinkBlinkInProgress;
+ u8 bLedLinkBlinkInProgress;
+ u8 bLedStartToLinkBlinkInProgress;
+ u8 bLedScanBlinkInProgress;
+ struct work_struct BlinkWorkItem; /* Workitem used by BlinkTimer to
+ * manipulate H/W to blink LED. */
+};
+
+#define IS_LED_WPS_BLINKING(_LED_871x) \
+ (((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS || \
+ ((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS_STOP || \
+ ((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress)
+
+#define IS_LED_BLINKING(_LED_871x) \
+ (((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress || \
+ ((struct LED_871x *)_LED_871x)->bLedScanBlinkInProgress)
+
+/* LED customization. */
+
+enum LED_STRATEGY_871x {
+ SW_LED_MODE0 = 0, /* SW control 1 LED via GPIO0. It is default option.*/
+ SW_LED_MODE1= 1, /* 2 LEDs, through LED0 and LED1. For ALPHA. */
+ SW_LED_MODE2 = 2, /* SW control 1 LED via GPIO0, customized for AzWave
+ * 8187 minicard. */
+ SW_LED_MODE3 = 3, /* SW control 1 LED via GPIO0, customized for Sercomm
+ * Printer Server case. */
+ SW_LED_MODE4 = 4, /* for Edimax / Belkin */
+ SW_LED_MODE5 = 5, /* for Sercomm / Belkin */
+ SW_LED_MODE6 = 6, /* for 88CU minicard, porting from ce SW_LED_MODE7 */
+ HW_LED = 50, /* HW control 2 LEDs, LED0 and LED1 (there are 4
+ * different control modes, see MAC.CONFIG1 for details.)*/
+ LED_ST_NONE = 99,
+};
+
+void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction);
+
+struct led_priv{
+ /* add for led controll */
+ struct LED_871x SwLed0;
+ struct LED_871x SwLed1;
+ enum LED_STRATEGY_871x LedStrategy;
+ u8 bRegUseLed;
+ void (*LedControlHandler)(struct adapter *padapter,
+ enum LED_CTL_MODE LedAction);
+ /* add for led controll */
+};
+
+#define rtw_led_control(adapt, action) \
+ do { \
+ if ((adapt)->ledpriv.LedControlHandler) \
+ (adapt)->ledpriv.LedControlHandler((adapt), (action)); \
+ } while (0)
+
+void BlinkTimerCallback(void *data);
+void BlinkWorkItemCallback(struct work_struct *work);
+
+void ResetLedStatus(struct LED_871x * pLed);
+
+void InitLed871x(struct adapter *padapter, struct LED_871x *pLed,
+ enum LED_PIN_871x LedPin);
+
+void DeInitLed871x(struct LED_871x *pLed);
+
+/* hal... */
+void BlinkHandler(struct LED_871x * pLed);
+void SwLedOn(struct adapter *padapter, struct LED_871x *pLed);
+void SwLedOff(struct adapter *padapter, struct LED_871x *pLed);
+
+#endif /* __RTW_LED_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme.h b/drivers/staging/rtl8188eu/include/rtw_mlme.h
new file mode 100644
index 00000000000..22538e61695
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme.h
@@ -0,0 +1,655 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_MLME_H_
+#define __RTW_MLME_H_
+
+#include <osdep_service.h>
+#include <mlme_osdep.h>
+#include <drv_types.h>
+#include <wlan_bssdef.h>
+
+#define MAX_BSS_CNT 128
+#define MAX_JOIN_TIMEOUT 6500
+
+/* Increase the scanning timeout because of increasing the SURVEY_TO value. */
+
+#define SCANNING_TIMEOUT 8000
+
+#define SCAN_INTERVAL (30) /* unit:2sec, 30*2=60sec */
+
+#define SCANQUEUE_LIFETIME 20 /* unit:sec */
+
+#define WIFI_NULL_STATE 0x00000000
+
+#define WIFI_ASOC_STATE 0x00000001 /* Under Linked state */
+#define WIFI_REASOC_STATE 0x00000002
+#define WIFI_SLEEP_STATE 0x00000004
+#define WIFI_STATION_STATE 0x00000008
+
+#define WIFI_AP_STATE 0x00000010
+#define WIFI_ADHOC_STATE 0x00000020
+#define WIFI_ADHOC_MASTER_STATE 0x00000040
+#define WIFI_UNDER_LINKING 0x00000080
+
+#define WIFI_UNDER_WPS 0x00000100
+#define WIFI_STA_ALIVE_CHK_STATE 0x00000400
+#define WIFI_SITE_MONITOR 0x00000800 /* to indicate the station is under site surveying */
+
+#define WIFI_MP_STATE 0x00010000
+#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in continous tx background */
+#define WIFI_MP_CTX_ST 0x00040000 /* in continous tx with single-tone */
+#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in continous tx background due to out of skb */
+#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continous tx */
+#define WIFI_MP_CTX_CCK_CS 0x00200000 /* in continous tx with carrier suppression */
+#define WIFI_MP_LPBK_STATE 0x00400000
+
+#define _FW_UNDER_LINKING WIFI_UNDER_LINKING
+#define _FW_LINKED WIFI_ASOC_STATE
+#define _FW_UNDER_SURVEY WIFI_SITE_MONITOR
+
+enum dot11AuthAlgrthmNum {
+ dot11AuthAlgrthm_Open = 0,
+ dot11AuthAlgrthm_Shared,
+ dot11AuthAlgrthm_8021X,
+ dot11AuthAlgrthm_Auto,
+ dot11AuthAlgrthm_WAPI,
+ dot11AuthAlgrthm_MaxNum
+};
+
+/* Scan type including active and passive scan. */
+enum rt_scan_type {
+ SCAN_PASSIVE,
+ SCAN_ACTIVE,
+ SCAN_MIX,
+};
+
+enum SCAN_RESULT_TYPE {
+ SCAN_RESULT_P2P_ONLY = 0, /* Will return all the P2P devices. */
+ SCAN_RESULT_ALL = 1, /* Will return all the scanned device,
+ * include AP. */
+ SCAN_RESULT_WFD_TYPE = 2 /* Will just return the correct WFD
+ * device. */
+ /* If this device is Miracast sink
+ * device, it will just return all the
+ * Miracast source devices. */
+};
+
+/*
+there are several "locks" in mlme_priv,
+since mlme_priv is a shared resource between many threads,
+like ISR/Call-Back functions, the OID handlers, and even timer functions.
+
+Each _queue has its own locks, already.
+Other items are protected by mlme_priv.lock.
+
+To avoid possible dead lock, any thread trying to modifiying mlme_priv
+SHALL not lock up more than one lock at a time!
+*/
+
+#define traffic_threshold 10
+#define traffic_scan_period 500
+
+struct sitesurvey_ctrl {
+ u64 last_tx_pkts;
+ uint last_rx_pkts;
+ int traffic_busy;
+ struct timer_list sitesurvey_ctrl_timer;
+};
+
+struct rt_link_detect {
+ u32 NumTxOkInPeriod;
+ u32 NumRxOkInPeriod;
+ u32 NumRxUnicastOkInPeriod;
+ bool bBusyTraffic;
+ bool bTxBusyTraffic;
+ bool bRxBusyTraffic;
+ bool bHigherBusyTraffic; /* For interrupt migration purpose. */
+ bool bHigherBusyRxTraffic; /* We may disable Tx interrupt according
+ * to Rx traffic. */
+ bool bHigherBusyTxTraffic; /* We may disable Tx interrupt according
+ * to Tx traffic. */
+};
+
+struct profile_info {
+ u8 ssidlen;
+ u8 ssid[ WLAN_SSID_MAXLEN ];
+ u8 peermac[ ETH_ALEN ];
+};
+
+struct tx_invite_req_info {
+ u8 token;
+ u8 benable;
+ u8 go_ssid[ WLAN_SSID_MAXLEN ];
+ u8 ssidlen;
+ u8 go_bssid[ ETH_ALEN ];
+ u8 peer_macaddr[ ETH_ALEN ];
+ u8 operating_ch; /* This information will be set by using the
+ * p2p_set op_ch=x */
+ u8 peer_ch; /* The listen channel for peer P2P device */
+};
+
+struct tx_invite_resp_info {
+ u8 token; /* Used to record the dialog token of p2p invitation
+ * request frame. */
+};
+
+struct tx_provdisc_req_info {
+ u16 wps_config_method_request; /* Used when sending the
+ * provisioning request frame*/
+ u16 peer_channel_num[2]; /* The channel number which the
+ * receiver stands. */
+ struct ndis_802_11_ssid ssid;
+ u8 peerDevAddr[ETH_ALEN]; /* Peer device address */
+ u8 peerIFAddr[ETH_ALEN]; /* Peer interface address */
+ u8 benable; /* This provision discovery
+ * request frame is trigger
+ * to send or not */
+};
+
+/* When peer device issue prov_disc_req first, we should store the following
+ * information */
+/* The UI must know this information to know which config method the
+ * remote p2p device needs. */
+struct rx_provdisc_req_info {
+ u8 peerDevAddr[ETH_ALEN]; /* Peer device address */
+ u8 strconfig_method_desc_of_prov_disc_req[4]; /* description
+ * for the config method located in the provisioning
+ * discovery request frame. */
+};
+
+struct tx_nego_req_info {
+ u16 peer_channel_num[2]; /* The channel number. */
+ u8 peerDevAddr[ETH_ALEN]; /* Peer device address */
+ u8 benable; /* This negotiation request frame is
+ * trigger to send or not */
+};
+
+struct group_id_info {
+ u8 go_device_addr[ ETH_ALEN ]; /* The GO's device address of
+ * this P2P group */
+ u8 ssid[ WLAN_SSID_MAXLEN ]; /* The SSID of this P2P group */
+};
+
+struct scan_limit_info {
+ u8 scan_op_ch_only; /* When this flag is set, the driver
+ * should only scan the op. channel */
+ u8 operation_ch[2]; /* Store the op. chan of invitation */
+};
+
+struct wifidirect_info {
+ struct adapter *padapter;
+ struct timer_list find_phase_timer;
+ struct timer_list restore_p2p_state_timer;
+
+ /* Used to do the scanning. After confirming the peer is availalble,
+ * the driver transmits the P2P frame to peer. */
+ struct timer_list pre_tx_scan_timer;
+ struct timer_list reset_ch_sitesurvey;
+ struct timer_list reset_ch_sitesurvey2; /* Just for resetting the scan
+ * limit function by using p2p nego */
+ struct tx_provdisc_req_info tx_prov_disc_info;
+ struct rx_provdisc_req_info rx_prov_disc_info;
+ struct tx_invite_req_info invitereq_info;
+ /* Store the profile information of persistent group */
+ struct profile_info profileinfo[P2P_MAX_PERSISTENT_GROUP_NUM];
+ struct tx_invite_resp_info inviteresp_info;
+ struct tx_nego_req_info nego_req_info;
+ /* Store the group id info when doing the group negot handshake. */
+ struct group_id_info groupid_info;
+ /* Used for get the limit scan channel from the Invitation procedure */
+ struct scan_limit_info rx_invitereq_info;
+ /* Used for get the limit scan chan from the P2P negotiation handshake*/
+ struct scan_limit_info p2p_info;
+ enum P2P_ROLE role;
+ enum P2P_STATE pre_p2p_state;
+ enum P2P_STATE p2p_state;
+ /* The device address should be the mac address of this device. */
+ u8 device_addr[ETH_ALEN];
+ u8 interface_addr[ETH_ALEN];
+ u8 social_chan[4];
+ u8 listen_channel;
+ u8 operating_channel;
+ u8 listen_dwell; /* This value should be between 1 and 3 */
+ u8 support_rate[8];
+ u8 p2p_wildcard_ssid[P2P_WILDCARD_SSID_LEN];
+ u8 intent; /* should only include the intent value. */
+ u8 p2p_peer_interface_addr[ETH_ALEN];
+ u8 p2p_peer_device_addr[ETH_ALEN];
+ u8 peer_intent; /* Included the intent value and tie breaker value. */
+ /* Device name for displaying on searching device screen */
+ u8 device_name[WPS_MAX_DEVICE_NAME_LEN];
+ u8 device_name_len;
+ u8 profileindex; /* Used to point to the index of profileinfo array */
+ u8 peer_operating_ch;
+ u8 find_phase_state_exchange_cnt;
+ /* The device password ID for group negotation */
+ u16 device_password_id_for_nego;
+ u8 negotiation_dialog_token;
+ /* SSID information for group negotitation */
+ u8 nego_ssid[WLAN_SSID_MAXLEN];
+ u8 nego_ssidlen;
+ u8 p2p_group_ssid[WLAN_SSID_MAXLEN];
+ u8 p2p_group_ssid_len;
+ /* Flag to know if the persistent function should be supported or not.*/
+ u8 persistent_supported;
+ /* In the Sigma test, the Sigma will provide this enable from the
+ * sta_set_p2p CAPI. */
+ /* 0: disable */
+ /* 1: enable */
+ u8 session_available; /* Flag to set the WFD session available to
+ * enable or disable "by Sigma" */
+ /* In the Sigma test, the Sigma will disable the session available
+ * by using the sta_preset CAPI. */
+ /* 0: disable */
+ /* 1: enable */
+ u8 wfd_tdls_enable; /* Flag to enable or disable the TDLS by WFD Sigma*/
+ /* 0: disable */
+ /* 1: enable */
+ u8 wfd_tdls_weaksec; /* Flag to enable or disable the weak security
+ * function for TDLS by WFD Sigma */
+ /* 0: disable */
+ /* In this case, the driver can't issue the tdsl
+ * setup request frame. */
+ /* 1: enable */
+ /* In this case, the driver can issue the tdls
+ * setup request frame */
+ /* even the current security is weak security. */
+
+ /* This field will store the WPS value (PIN value or PBC) that UI had
+ * got from the user. */
+ enum P2P_WPSINFO ui_got_wps_info;
+ u16 supported_wps_cm; /* This field describes the WPS config method
+ * which this driver supported. */
+ /* The value should be the combination of config
+ * method defined in page104 of WPS v2.0 spec.*/
+ /* This field will contain the length of body of P2P Channel List
+ * attribute of group negotiation response frame. */
+ uint channel_list_attr_len;
+ /* This field will contain the body of P2P Channel List attribute of
+ * group negotitation response frame. */
+ /* We will use the channel_cnt and channel_list fields when constructing
+ * the group negotiation confirm frame. */
+ u8 channel_list_attr[100];
+ enum P2P_PS_MODE p2p_ps_mode; /* indicate p2p ps mode */
+ enum P2P_PS_STATE p2p_ps_state; /* indicate p2p ps state */
+ u8 noa_index; /* Identifies and instance of Notice of Absence timing. */
+ u8 ctwindow; /* Client traffic window. A period of time in TU after TBTT. */
+ u8 opp_ps; /* opportunistic power save. */
+ u8 noa_num; /* number of NoA descriptor in P2P IE. */
+ u8 noa_count[P2P_MAX_NOA_NUM]; /* Count for owner, Type of client. */
+ /* Max duration for owner, preferred or min acceptable duration for
+ * client. */
+ u32 noa_duration[P2P_MAX_NOA_NUM];
+ /* Length of interval for owner, preferred or max acceptable interval
+ * of client. */
+ u32 noa_interval[P2P_MAX_NOA_NUM];
+ /* schedule expressed in terms of the lower 4 bytes of the TSF timer. */
+ u32 noa_start_time[P2P_MAX_NOA_NUM];
+};
+
+struct tdls_ss_record { /* signal strength record */
+ u8 macaddr[ETH_ALEN];
+ u8 RxPWDBAll;
+ u8 is_tdls_sta; /* true: direct link sta, false: else */
+};
+
+struct tdls_info {
+ u8 ap_prohibited;
+ uint setup_state;
+ u8 sta_cnt;
+ u8 sta_maximum; /* 1:tdls sta is equal (NUM_STA-1), reach max direct link number; 0: else; */
+ struct tdls_ss_record ss_record;
+ u8 macid_index; /* macid entry that is ready to write */
+ u8 clear_cam; /* cam entry that is trying to clear, using it in direct link teardown */
+ u8 ch_sensing;
+ u8 cur_channel;
+ u8 candidate_ch;
+ u8 collect_pkt_num[MAX_CHANNEL_NUM];
+ spinlock_t cmd_lock;
+ spinlock_t hdl_lock;
+ u8 watchdog_count;
+ u8 dev_discovered; /* WFD_TDLS: for sigma test */
+ u8 enable;
+};
+
+struct mlme_priv {
+ spinlock_t lock;
+ int fw_state; /* shall we protect this variable? maybe not necessarily... */
+ u8 bScanInProcess;
+ u8 to_join; /* flag */
+ u8 to_roaming; /* roaming trying times */
+
+ u8 *nic_hdl;
+
+ u8 not_indic_disco;
+ struct list_head *pscanned;
+ struct __queue free_bss_pool;
+ struct __queue scanned_queue;
+ u8 *free_bss_buf;
+ u32 num_of_scanned;
+
+ struct ndis_802_11_ssid assoc_ssid;
+ u8 assoc_bssid[6];
+
+ struct wlan_network cur_network;
+
+ u32 scan_interval;
+
+ struct timer_list assoc_timer;
+
+ uint assoc_by_bssid;
+ uint assoc_by_rssi;
+
+ struct timer_list scan_to_timer; /* driver itself handles scan_timeout status. */
+ u32 scan_start_time; /* used to evaluate the time spent in scanning */
+
+ struct qos_priv qospriv;
+
+ /* Number of non-HT AP/stations */
+ int num_sta_no_ht;
+
+ /* Number of HT AP/stations 20 MHz */
+ /* int num_sta_ht_20mhz; */
+
+ int num_FortyMHzIntolerant;
+ struct ht_priv htpriv;
+ struct rt_link_detect LinkDetectInfo;
+ struct timer_list dynamic_chk_timer; /* dynamic/periodic check timer */
+
+ u8 key_mask; /* use for ips to set wep key after ips_leave */
+ u8 acm_mask; /* for wmm acm mask */
+ u8 ChannelPlan;
+ enum rt_scan_type scan_mode; /* active: 1, passive: 0 */
+
+ /* u8 probereq_wpsie[MAX_WPS_IE_LEN];added in probe req */
+ /* int probereq_wpsie_len; */
+ u8 *wps_probe_req_ie;
+ u32 wps_probe_req_ie_len;
+
+ u8 *assoc_req;
+ u32 assoc_req_len;
+ u8 *assoc_rsp;
+ u32 assoc_rsp_len;
+
+#if defined (CONFIG_88EU_AP_MODE)
+ /* Number of associated Non-ERP stations (i.e., stations using 802.11b
+ * in 802.11g BSS) */
+ int num_sta_non_erp;
+
+ /* Number of associated stations that do not support Short Slot Time */
+ int num_sta_no_short_slot_time;
+
+ /* Number of associated stations that do not support Short Preamble */
+ int num_sta_no_short_preamble;
+
+ int olbc; /* Overlapping Legacy BSS Condition */
+
+ /* Number of HT assoc sta that do not support greenfield */
+ int num_sta_ht_no_gf;
+
+ /* Number of associated non-HT stations */
+ /* int num_sta_no_ht; */
+
+ /* Number of HT associated stations 20 MHz */
+ int num_sta_ht_20mhz;
+
+ /* Overlapping BSS information */
+ int olbc_ht;
+
+ u16 ht_op_mode;
+
+ u8 *wps_beacon_ie;
+ /* u8 *wps_probe_req_ie; */
+ u8 *wps_probe_resp_ie;
+ u8 *wps_assoc_resp_ie;
+
+ u32 wps_beacon_ie_len;
+ u32 wps_probe_resp_ie_len;
+ u32 wps_assoc_resp_ie_len;
+
+ u8 *p2p_beacon_ie;
+ u8 *p2p_probe_req_ie;
+ u8 *p2p_probe_resp_ie;
+ u8 *p2p_go_probe_resp_ie; /* for GO */
+ u8 *p2p_assoc_req_ie;
+
+ u32 p2p_beacon_ie_len;
+ u32 p2p_probe_req_ie_len;
+ u32 p2p_probe_resp_ie_len;
+ u32 p2p_go_probe_resp_ie_len; /* for GO */
+ u32 p2p_assoc_req_ie_len;
+ spinlock_t bcn_update_lock;
+ u8 update_bcn;
+#endif /* if defined (CONFIG_88EU_AP_MODE) */
+};
+
+#ifdef CONFIG_88EU_AP_MODE
+
+struct hostapd_priv {
+ struct adapter *padapter;
+};
+
+int hostapd_mode_init(struct adapter *padapter);
+void hostapd_mode_unload(struct adapter *padapter);
+#endif
+
+extern unsigned char WPA_TKIP_CIPHER[4];
+extern unsigned char RSN_TKIP_CIPHER[4];
+extern unsigned char REALTEK_96B_IE[];
+extern unsigned char MCS_rate_2R[16];
+extern unsigned char MCS_rate_1R[16];
+
+void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf);
+void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_atimdone_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_cpwm_event_callback(struct adapter *adapter, u8 *pbuf);
+void indicate_wx_scan_complete_event(struct adapter *padapter);
+void rtw_indicate_wx_assoc_event(struct adapter *padapter);
+void rtw_indicate_wx_disassoc_event(struct adapter *padapter);
+int event_thread(void *context);
+void rtw_join_timeout_handler(void *FunctionContext);
+void _rtw_scan_timeout_handler(void *FunctionContext);
+void rtw_free_network_queue(struct adapter *adapter, u8 isfreeall);
+int rtw_init_mlme_priv(struct adapter *adapter);
+void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv);
+int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv);
+int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv,
+ int keyid, u8 set_tx);
+int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv);
+
+static inline u8 *get_bssid(struct mlme_priv *pmlmepriv)
+{ /* if sta_mode:pmlmepriv->cur_network.network.MacAddress=> bssid */
+ /* if adhoc_mode:pmlmepriv->cur_network.network.MacAddress=> ibss mac address */
+ return pmlmepriv->cur_network.network.MacAddress;
+}
+
+static inline int check_fwstate(struct mlme_priv *pmlmepriv, int state)
+{
+ if (pmlmepriv->fw_state & state)
+ return true;
+
+ return false;
+}
+
+static inline int get_fwstate(struct mlme_priv *pmlmepriv)
+{
+ return pmlmepriv->fw_state;
+}
+
+/*
+ * No Limit on the calling context,
+ * therefore set it to be the critical section...
+ *
+ * ### NOTE:#### (!!!!)
+ * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
+ */
+static inline void set_fwstate(struct mlme_priv *pmlmepriv, int state)
+{
+ pmlmepriv->fw_state |= state;
+ /* FOR HW integration */
+ if (_FW_UNDER_SURVEY==state)
+ pmlmepriv->bScanInProcess = true;
+}
+
+static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, int state)
+{
+ pmlmepriv->fw_state &= ~state;
+ /* FOR HW integration */
+ if (_FW_UNDER_SURVEY==state)
+ pmlmepriv->bScanInProcess = false;
+}
+
+/*
+ * No Limit on the calling context,
+ * therefore set it to be the critical section...
+ */
+static inline void clr_fwstate(struct mlme_priv *pmlmepriv, int state)
+{
+ unsigned long irql;
+
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+ if (check_fwstate(pmlmepriv, state) == true)
+ pmlmepriv->fw_state ^= state;
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+
+static inline void clr_fwstate_ex(struct mlme_priv *pmlmepriv, int state)
+{
+ unsigned long irql;
+
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+ _clr_fwstate_(pmlmepriv, state);
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+
+static inline void up_scanned_network(struct mlme_priv *pmlmepriv)
+{
+ unsigned long irql;
+
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+ pmlmepriv->num_of_scanned++;
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+
+static inline void down_scanned_network(struct mlme_priv *pmlmepriv)
+{
+ unsigned long irql;
+
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+ pmlmepriv->num_of_scanned--;
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+
+static inline void set_scanned_network_val(struct mlme_priv *pmlmepriv, int val)
+{
+ unsigned long irql;
+
+ _enter_critical_bh(&pmlmepriv->lock, &irql);
+ pmlmepriv->num_of_scanned = val;
+ _exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+
+u16 rtw_get_capability(struct wlan_bssid_ex *bss);
+void rtw_update_scanned_network(struct adapter *adapter,
+ struct wlan_bssid_ex *target);
+void rtw_disconnect_hdl_under_linked(struct adapter *adapter,
+ struct sta_info *psta, u8 free_assoc);
+void rtw_generate_random_ibss(u8 *pibss);
+struct wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr);
+struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue);
+
+void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue);
+void rtw_indicate_disconnect(struct adapter *adapter);
+void rtw_indicate_connect(struct adapter *adapter);
+void rtw_indicate_scan_done( struct adapter *padapter, bool aborted);
+void rtw_scan_abort(struct adapter *adapter);
+
+int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie,
+ uint in_len);
+int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie,
+ uint in_len, uint initial_out_len);
+void rtw_init_registrypriv_dev_network(struct adapter *adapter);
+
+void rtw_update_registrypriv_dev_network(struct adapter *adapter);
+
+void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter);
+
+void _rtw_join_timeout_handler(struct adapter *adapter);
+void rtw_scan_timeout_handler(struct adapter *adapter);
+
+ void rtw_dynamic_check_timer_handlder(struct adapter *adapter);
+#define rtw_is_scan_deny(adapter) false
+#define rtw_clear_scan_deny(adapter) do {} while (0)
+#define rtw_set_scan_deny_timer_hdl(adapter) do {} while (0)
+#define rtw_set_scan_deny(adapter, ms) do {} while (0)
+
+
+int _rtw_init_mlme_priv(struct adapter *padapter);
+
+void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv);
+
+void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv);
+
+int _rtw_enqueue_network(struct __queue *queue, struct wlan_network *pnetwork);
+
+struct wlan_network *_rtw_dequeue_network(struct __queue *queue);
+
+ struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv);
+
+
+void _rtw_free_network(struct mlme_priv *pmlmepriv,
+ struct wlan_network *pnetwork, u8 isfreeall);
+void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
+ struct wlan_network *pnetwork);
+
+
+struct wlan_network* _rtw_find_network(struct __queue *scanned_queue, u8 *addr);
+
+void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall);
+
+int rtw_if_up(struct adapter *padapter);
+
+
+u8 *rtw_get_capability_from_ie(u8 *ie);
+u8 *rtw_get_timestampe_from_ie(u8 *ie);
+u8 *rtw_get_beacon_interval_from_ie(u8 *ie);
+
+
+void rtw_joinbss_reset(struct adapter *padapter);
+
+unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie,
+ u8 *out_ie, uint in_len, uint *pout_len);
+void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len);
+void rtw_issue_addbareq_cmd(struct adapter *padapter,
+ struct xmit_frame *pxmitframe);
+
+int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork);
+int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst);
+
+void rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network);
+void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network);
+
+void rtw_stassoc_hw_rpt(struct adapter *adapter,struct sta_info *psta);
+
+#endif /* __RTL871X_MLME_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
new file mode 100644
index 00000000000..a96b018e5e6
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
@@ -0,0 +1,877 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_MLME_EXT_H_
+#define __RTW_MLME_EXT_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wlan_bssdef.h>
+
+
+/* Commented by Albert 20101105 */
+/* Increase the SURVEY_TO value from 100 to 150 ( 100ms to 150ms ) */
+/* The Realtek 8188CE SoftAP will spend around 100ms to send the probe response after receiving the probe request. */
+/* So, this driver tried to extend the dwell time for each scanning channel. */
+/* This will increase the chance to receive the probe response from SoftAP. */
+
+#define SURVEY_TO (100)
+#define REAUTH_TO (300) /* 50) */
+#define REASSOC_TO (300) /* 50) */
+/* define DISCONNECT_TO (3000) */
+#define ADDBA_TO (2000)
+
+#define LINKED_TO (1) /* unit:2 sec, 1x2=2 sec */
+
+#define REAUTH_LIMIT (4)
+#define REASSOC_LIMIT (4)
+#define READDBA_LIMIT (2)
+
+#define ROAMING_LIMIT 8
+
+#define DYNAMIC_FUNC_DISABLE (0x0)
+
+/* ====== ODM_ABILITY_E ======== */
+/* BB ODM section BIT 0-15 */
+#define DYNAMIC_BB_DIG BIT(0)
+#define DYNAMIC_BB_RA_MASK BIT(1)
+#define DYNAMIC_BB_DYNAMIC_TXPWR BIT(2)
+#define DYNAMIC_BB_BB_FA_CNT BIT(3)
+
+#define DYNAMIC_BB_RSSI_MONITOR BIT(4)
+#define DYNAMIC_BB_CCK_PD BIT(5)
+#define DYNAMIC_BB_ANT_DIV BIT(6)
+#define DYNAMIC_BB_PWR_SAVE BIT(7)
+#define DYNAMIC_BB_PWR_TRA BIT(8)
+#define DYNAMIC_BB_RATE_ADAPTIVE BIT(9)
+#define DYNAMIC_BB_PATH_DIV BIT(10)
+#define DYNAMIC_BB_PSD BIT(11)
+
+/* MAC DM section BIT 16-23 */
+#define DYNAMIC_MAC_EDCA_TURBO BIT(16)
+#define DYNAMIC_MAC_EARLY_MODE BIT(17)
+
+/* RF ODM section BIT 24-31 */
+#define DYNAMIC_RF_TX_PWR_TRACK BIT(24)
+#define DYNAMIC_RF_RX_GAIN_TRACK BIT(25)
+#define DYNAMIC_RF_CALIBRATION BIT(26)
+
+#define DYNAMIC_ALL_FUNC_ENABLE 0xFFFFFFF
+
+#define _HW_STATE_NOLINK_ 0x00
+#define _HW_STATE_ADHOC_ 0x01
+#define _HW_STATE_STATION_ 0x02
+#define _HW_STATE_AP_ 0x03
+
+
+#define _1M_RATE_ 0
+#define _2M_RATE_ 1
+#define _5M_RATE_ 2
+#define _11M_RATE_ 3
+#define _6M_RATE_ 4
+#define _9M_RATE_ 5
+#define _12M_RATE_ 6
+#define _18M_RATE_ 7
+#define _24M_RATE_ 8
+#define _36M_RATE_ 9
+#define _48M_RATE_ 10
+#define _54M_RATE_ 11
+
+
+extern unsigned char RTW_WPA_OUI[];
+extern unsigned char WMM_OUI[];
+extern unsigned char WPS_OUI[];
+extern unsigned char WFD_OUI[];
+extern unsigned char P2P_OUI[];
+
+extern unsigned char WMM_INFO_OUI[];
+extern unsigned char WMM_PARA_OUI[];
+
+/* Channel Plan Type. */
+/* Note: */
+/* We just add new channel plan when the new channel plan is different
+ * from any of the following channel plan. */
+/* If you just wnat to customize the acitions(scan period or join actions)
+ * about one of the channel plan, */
+/* customize them in struct rt_channel_info in the RT_CHANNEL_LIST. */
+enum RT_CHANNEL_DOMAIN {
+ /* old channel plan mapping ===== */
+ RT_CHANNEL_DOMAIN_FCC = 0x00,
+ RT_CHANNEL_DOMAIN_IC = 0x01,
+ RT_CHANNEL_DOMAIN_ETSI = 0x02,
+ RT_CHANNEL_DOMAIN_SPAIN = 0x03,
+ RT_CHANNEL_DOMAIN_FRANCE = 0x04,
+ RT_CHANNEL_DOMAIN_MKK = 0x05,
+ RT_CHANNEL_DOMAIN_MKK1 = 0x06,
+ RT_CHANNEL_DOMAIN_ISRAEL = 0x07,
+ RT_CHANNEL_DOMAIN_TELEC = 0x08,
+ RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN = 0x09,
+ RT_CHANNEL_DOMAIN_WORLD_WIDE_13 = 0x0A,
+ RT_CHANNEL_DOMAIN_TAIWAN = 0x0B,
+ RT_CHANNEL_DOMAIN_CHINA = 0x0C,
+ RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO = 0x0D,
+ RT_CHANNEL_DOMAIN_KOREA = 0x0E,
+ RT_CHANNEL_DOMAIN_TURKEY = 0x0F,
+ RT_CHANNEL_DOMAIN_JAPAN = 0x10,
+ RT_CHANNEL_DOMAIN_FCC_NO_DFS = 0x11,
+ RT_CHANNEL_DOMAIN_JAPAN_NO_DFS = 0x12,
+ RT_CHANNEL_DOMAIN_WORLD_WIDE_5G = 0x13,
+ RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS = 0x14,
+
+ /* new channel plan mapping, (2GDOMAIN_5GDOMAIN) ===== */
+ RT_CHANNEL_DOMAIN_WORLD_NULL = 0x20,
+ RT_CHANNEL_DOMAIN_ETSI1_NULL = 0x21,
+ RT_CHANNEL_DOMAIN_FCC1_NULL = 0x22,
+ RT_CHANNEL_DOMAIN_MKK1_NULL = 0x23,
+ RT_CHANNEL_DOMAIN_ETSI2_NULL = 0x24,
+ RT_CHANNEL_DOMAIN_FCC1_FCC1 = 0x25,
+ RT_CHANNEL_DOMAIN_WORLD_ETSI1 = 0x26,
+ RT_CHANNEL_DOMAIN_MKK1_MKK1 = 0x27,
+ RT_CHANNEL_DOMAIN_WORLD_KCC1 = 0x28,
+ RT_CHANNEL_DOMAIN_WORLD_FCC2 = 0x29,
+ RT_CHANNEL_DOMAIN_WORLD_FCC3 = 0x30,
+ RT_CHANNEL_DOMAIN_WORLD_FCC4 = 0x31,
+ RT_CHANNEL_DOMAIN_WORLD_FCC5 = 0x32,
+ RT_CHANNEL_DOMAIN_WORLD_FCC6 = 0x33,
+ RT_CHANNEL_DOMAIN_FCC1_FCC7 = 0x34,
+ RT_CHANNEL_DOMAIN_WORLD_ETSI2 = 0x35,
+ RT_CHANNEL_DOMAIN_WORLD_ETSI3 = 0x36,
+ RT_CHANNEL_DOMAIN_MKK1_MKK2 = 0x37,
+ RT_CHANNEL_DOMAIN_MKK1_MKK3 = 0x38,
+ RT_CHANNEL_DOMAIN_FCC1_NCC1 = 0x39,
+ RT_CHANNEL_DOMAIN_FCC1_NCC2 = 0x40,
+ RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G = 0x41,
+ /* Add new channel plan above this line=============== */
+ RT_CHANNEL_DOMAIN_MAX,
+ RT_CHANNEL_DOMAIN_REALTEK_DEFINE = 0x7F,
+};
+
+enum RT_CHANNEL_DOMAIN_2G {
+ RT_CHANNEL_DOMAIN_2G_WORLD = 0x00, /* Worldwide 13 */
+ RT_CHANNEL_DOMAIN_2G_ETSI1 = 0x01, /* Europe */
+ RT_CHANNEL_DOMAIN_2G_FCC1 = 0x02, /* US */
+ RT_CHANNEL_DOMAIN_2G_MKK1 = 0x03, /* Japan */
+ RT_CHANNEL_DOMAIN_2G_ETSI2 = 0x04, /* France */
+ RT_CHANNEL_DOMAIN_2G_NULL = 0x05,
+ /* Add new channel plan above this line=============== */
+ RT_CHANNEL_DOMAIN_2G_MAX,
+};
+
+#define rtw_is_channel_plan_valid(chplan) \
+ (chplan < RT_CHANNEL_DOMAIN_MAX || \
+ chplan == RT_CHANNEL_DOMAIN_REALTEK_DEFINE)
+
+struct rt_channel_plan {
+ unsigned char Channel[MAX_CHANNEL_NUM];
+ unsigned char Len;
+};
+
+struct rt_channel_plan_2g {
+ unsigned char Channel[MAX_CHANNEL_NUM_2G];
+ unsigned char Len;
+};
+
+struct rt_channel_plan_map {
+ unsigned char Index2G;
+};
+
+enum Associated_AP {
+ atherosAP = 0,
+ broadcomAP = 1,
+ ciscoAP = 2,
+ marvellAP = 3,
+ ralinkAP = 4,
+ realtekAP = 5,
+ airgocapAP = 6,
+ unknownAP = 7,
+ maxAP,
+};
+
+enum HT_IOT_PEER {
+ HT_IOT_PEER_UNKNOWN = 0,
+ HT_IOT_PEER_REALTEK = 1,
+ HT_IOT_PEER_REALTEK_92SE = 2,
+ HT_IOT_PEER_BROADCOM = 3,
+ HT_IOT_PEER_RALINK = 4,
+ HT_IOT_PEER_ATHEROS = 5,
+ HT_IOT_PEER_CISCO = 6,
+ HT_IOT_PEER_MERU = 7,
+ HT_IOT_PEER_MARVELL = 8,
+ HT_IOT_PEER_REALTEK_SOFTAP = 9,/* peer is RealTek SOFT_AP */
+ HT_IOT_PEER_SELF_SOFTAP = 10, /* Self is SoftAP */
+ HT_IOT_PEER_AIRGO = 11,
+ HT_IOT_PEER_INTEL = 12,
+ HT_IOT_PEER_RTK_APCLIENT = 13,
+ HT_IOT_PEER_REALTEK_81XX = 14,
+ HT_IOT_PEER_REALTEK_WOW = 15,
+ HT_IOT_PEER_TENDA = 16,
+ HT_IOT_PEER_MAX = 17
+};
+
+enum SCAN_STATE {
+ SCAN_DISABLE = 0,
+ SCAN_START = 1,
+ SCAN_TXNULL = 2,
+ SCAN_PROCESS = 3,
+ SCAN_COMPLETE = 4,
+ SCAN_STATE_MAX,
+};
+
+struct mlme_handler {
+ unsigned int num;
+ char *str;
+ unsigned int (*func)(struct adapter *adapt, union recv_frame *frame);
+};
+
+struct action_handler {
+ unsigned int num;
+ char* str;
+ unsigned int (*func)(struct adapter *adapt, union recv_frame *frame);
+};
+
+struct ss_res {
+ int state;
+ int bss_cnt;
+ int channel_idx;
+ int scan_mode;
+ u8 ssid_num;
+ u8 ch_num;
+ struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT];
+ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT];
+};
+
+/* define AP_MODE 0x0C */
+/* define STATION_MODE 0x08 */
+/* define AD_HOC_MODE 0x04 */
+/* define NO_LINK_MODE 0x00 */
+
+#define WIFI_FW_NULL_STATE _HW_STATE_NOLINK_
+#define WIFI_FW_STATION_STATE _HW_STATE_STATION_
+#define WIFI_FW_AP_STATE _HW_STATE_AP_
+#define WIFI_FW_ADHOC_STATE _HW_STATE_ADHOC_
+
+#define WIFI_FW_AUTH_NULL 0x00000100
+#define WIFI_FW_AUTH_STATE 0x00000200
+#define WIFI_FW_AUTH_SUCCESS 0x00000400
+
+#define WIFI_FW_ASSOC_STATE 0x00002000
+#define WIFI_FW_ASSOC_SUCCESS 0x00004000
+
+#define WIFI_FW_LINKING_STATE (WIFI_FW_AUTH_NULL | \
+ WIFI_FW_AUTH_STATE | \
+ WIFI_FW_AUTH_SUCCESS | \
+ WIFI_FW_ASSOC_STATE)
+
+struct FW_Sta_Info {
+ struct sta_info *psta;
+ u32 status;
+ u32 rx_pkt;
+ u32 retry;
+ unsigned char SupportedRates[NDIS_802_11_LENGTH_RATES_EX];
+};
+
+/*
+ * Usage:
+ * When one iface acted as AP mode and the other iface is STA mode and scanning,
+ * it should switch back to AP's operating channel periodically.
+ * Parameters info:
+ * When the driver scanned RTW_SCAN_NUM_OF_CH channels, it would switch back to
+ * AP's operating channel for
+ * RTW_STAY_AP_CH_MILLISECOND * SURVEY_TO milliseconds.
+ * Example:
+ * For chip supports 2.4G + 5GHz and AP mode is operating in channel 1,
+ * RTW_SCAN_NUM_OF_CH is 8, RTW_STAY_AP_CH_MS is 3 and SURVEY_TO is 100.
+ * When it's STA mode gets set_scan command,
+ * it would
+ * 1. Doing the scan on channel 1.2.3.4.5.6.7.8
+ * 2. Back to channel 1 for 300 milliseconds
+ * 3. Go through doing site survey on channel 9.10.11.36.40.44.48.52
+ * 4. Back to channel 1 for 300 milliseconds
+ * 5. ... and so on, till survey done.
+ */
+
+struct mlme_ext_info {
+ u32 state;
+ u32 reauth_count;
+ u32 reassoc_count;
+ u32 link_count;
+ u32 auth_seq;
+ u32 auth_algo; /* 802.11 auth, could be open, shared, auto */
+ u32 authModeToggle;
+ u32 enc_algo;/* encrypt algorithm; */
+ u32 key_index; /* this is only valid for legacy wep,
+ * 0~3 for key id. */
+ u32 iv;
+ u8 chg_txt[128];
+ u16 aid;
+ u16 bcn_interval;
+ u16 capability;
+ u8 assoc_AP_vendor;
+ u8 slotTime;
+ u8 preamble_mode;
+ u8 WMM_enable;
+ u8 ERP_enable;
+ u8 ERP_IE;
+ u8 HT_enable;
+ u8 HT_caps_enable;
+ u8 HT_info_enable;
+ u8 HT_protection;
+ u8 turboMode_cts2self;
+ u8 turboMode_rtsen;
+ u8 SM_PS;
+ u8 agg_enable_bitmap;
+ u8 ADDBA_retry_count;
+ u8 candidate_tid_bitmap;
+ u8 dialogToken;
+ /* Accept ADDBA Request */
+ bool bAcceptAddbaReq;
+ u8 bwmode_updated;
+ u8 hidden_ssid_mode;
+
+ struct ADDBA_request ADDBA_req;
+ struct WMM_para_element WMM_param;
+ struct HT_caps_element HT_caps;
+ struct HT_info_element HT_info;
+ struct wlan_bssid_ex network;/* join network or bss_network,
+ * if in ap mode, it is the same
+ * as cur_network.network */
+ struct FW_Sta_Info FW_sta_info[NUM_STA];
+};
+
+/* The channel information about this channel including joining,
+ * scanning, and power constraints. */
+struct rt_channel_info {
+ u8 ChannelNum; /* The channel number. */
+ enum rt_scan_type ScanType; /* Scan type such as passive
+ * or active scan. */
+ u32 rx_count;
+};
+
+int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch);
+
+/* P2P_MAX_REG_CLASSES - Maximum number of regulatory classes */
+#define P2P_MAX_REG_CLASSES 10
+
+/* P2P_MAX_REG_CLASS_CHANNELS - Maximum number of chan per regulatory class */
+#define P2P_MAX_REG_CLASS_CHANNELS 20
+
+/* struct p2p_channels - List of supported channels */
+struct p2p_channels {
+ /* struct p2p_reg_class - Supported regulatory class */
+ struct p2p_reg_class {
+ /* reg_class - Regulatory class (IEEE 802.11-2007, Annex J) */
+ u8 reg_class;
+
+ /* channel - Supported channels */
+ u8 channel[P2P_MAX_REG_CLASS_CHANNELS];
+
+ /* channels - Number of channel entries in use */
+ size_t channels;
+ } reg_class[P2P_MAX_REG_CLASSES];
+
+ /* reg_classes - Number of reg_class entries in use */
+ size_t reg_classes;
+};
+
+struct p2p_oper_class_map {
+ enum hw_mode {IEEE80211G} mode;
+ u8 op_class;
+ u8 min_chan;
+ u8 max_chan;
+ u8 inc;
+ enum {BW20, BW40PLUS, BW40MINUS} bw;
+};
+
+struct mlme_ext_priv {
+ struct adapter *padapter;
+ u8 mlmeext_init;
+ ATOMIC_T event_seq;
+ u16 mgnt_seq;
+
+ unsigned char cur_channel;
+ unsigned char cur_bwmode;
+ unsigned char cur_ch_offset;/* PRIME_CHNL_OFFSET */
+ unsigned char cur_wireless_mode; /* NETWORK_TYPE */
+
+ unsigned char oper_channel; /* saved chan info when call
+ * set_channel_bw */
+ unsigned char oper_bwmode;
+ unsigned char oper_ch_offset;/* PRIME_CHNL_OFFSET */
+
+ unsigned char max_chan_nums;
+ struct rt_channel_info channel_set[MAX_CHANNEL_NUM];
+ struct p2p_channels channel_list;
+ unsigned char basicrate[NumRates];
+ unsigned char datarate[NumRates];
+
+ struct ss_res sitesurvey_res;
+ struct mlme_ext_info mlmext_info;/* for sta/adhoc mode, including
+ * current scan/connecting/connected
+ * related info. For ap mode,
+ * network includes ap's cap_info*/
+ struct timer_list survey_timer;
+ struct timer_list link_timer;
+ u16 chan_scan_time;
+
+ u8 scan_abort;
+ u8 tx_rate; /* TXRATE when USERATE is set. */
+
+ u32 retry; /* retry for issue probereq */
+
+ u64 TSFValue;
+
+#ifdef CONFIG_88EU_AP_MODE
+ unsigned char bstart_bss;
+#endif
+ u8 update_channel_plan_by_ap_done;
+ /* recv_decache check for Action_public frame */
+ u8 action_public_dialog_token;
+ u16 action_public_rxseq;
+ u8 active_keep_alive_check;
+};
+
+int init_mlme_ext_priv(struct adapter *adapter);
+int init_hw_mlme_ext(struct adapter *padapter);
+void free_mlme_ext_priv (struct mlme_ext_priv *pmlmeext);
+extern void init_mlme_ext_timer(struct adapter *padapter);
+extern void init_addba_retry_timer(struct adapter *adapt, struct sta_info *sta);
+extern struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv);
+
+unsigned char networktype_to_raid(unsigned char network_type);
+u8 judge_network_type(struct adapter *padapter, unsigned char *rate, int len);
+void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *len);
+void UpdateBrateTbl(struct adapter *padapter, u8 *mBratesOS);
+void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen);
+
+void Save_DM_Func_Flag(struct adapter *padapter);
+void Restore_DM_Func_Flag(struct adapter *padapter);
+void Switch_DM_Func(struct adapter *padapter, u32 mode, u8 enable);
+
+void Set_MSR(struct adapter *padapter, u8 type);
+
+u8 rtw_get_oper_ch(struct adapter *adapter);
+void rtw_set_oper_ch(struct adapter *adapter, u8 ch);
+u8 rtw_get_oper_bw(struct adapter *adapter);
+void rtw_set_oper_bw(struct adapter *adapter, u8 bw);
+u8 rtw_get_oper_choffset(struct adapter *adapter);
+void rtw_set_oper_choffset(struct adapter *adapter, u8 offset);
+
+void set_channel_bwmode(struct adapter *padapter, unsigned char channel,
+ unsigned char channel_offset, unsigned short bwmode);
+void SelectChannel(struct adapter *padapter, unsigned char channel);
+void SetBWMode(struct adapter *padapter, unsigned short bwmode,
+ unsigned char channel_offset);
+
+unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval);
+
+void write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key);
+void clear_cam_entry(struct adapter *padapter, u8 entry);
+
+void invalidate_cam_all(struct adapter *padapter);
+void CAM_empty_entry(struct adapter * Adapter, u8 ucIndex);
+
+int allocate_fw_sta_entry(struct adapter *padapter);
+void flush_all_cam_entry(struct adapter *padapter);
+
+void site_survey(struct adapter *padapter);
+u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame,
+ struct wlan_bssid_ex *bssid);
+void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
+ struct adapter *adapter, bool update_ie);
+
+int get_bsstype(unsigned short capability);
+u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork);
+u16 get_beacon_interval(struct wlan_bssid_ex *bss);
+
+int is_client_associated_to_ap(struct adapter *padapter);
+int is_client_associated_to_ibss(struct adapter *padapter);
+int is_IBSS_empty(struct adapter *padapter);
+
+unsigned char check_assoc_AP(u8 *pframe, uint len);
+
+int WMM_param_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE);
+void WMMOnAssocRsp(struct adapter *padapter);
+
+void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE);
+void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE);
+void HTOnAssocRsp(struct adapter *padapter);
+
+void ERP_IE_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE);
+void VCS_update(struct adapter *padapter, struct sta_info *psta);
+
+void update_beacon_info(struct adapter *padapter, u8 *pframe, uint len,
+ struct sta_info *psta);
+int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len);
+void update_IOT_info(struct adapter *padapter);
+void update_capinfo(struct adapter *adapter, u16 updatecap);
+void update_wireless_mode(struct adapter *padapter);
+void update_tx_basic_rate(struct adapter *padapter, u8 modulation);
+void update_bmc_sta_support_rate(struct adapter *padapter, u32 mac_id);
+int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie,
+ uint var_ie_len, int cam_idx);
+
+/* for sta/adhoc mode */
+void update_sta_info(struct adapter *padapter, struct sta_info *psta);
+unsigned int update_basic_rate(unsigned char *ptn, unsigned int ptn_sz);
+unsigned int update_supported_rate(unsigned char *ptn, unsigned int ptn_sz);
+unsigned int update_MSC_rate(struct HT_caps_element *pHT_caps);
+void Update_RA_Entry(struct adapter *padapter, u32 mac_id);
+void set_sta_rate(struct adapter *padapter, struct sta_info *psta);
+
+unsigned int receive_disconnect(struct adapter *padapter,
+ unsigned char *macaddr, unsigned short reason);
+
+unsigned char get_highest_rate_idx(u32 mask);
+int support_short_GI(struct adapter *padapter, struct HT_caps_element *caps);
+unsigned int is_ap_in_tkip(struct adapter *padapter);
+unsigned int is_ap_in_wep(struct adapter *padapter);
+unsigned int should_forbid_n_rate(struct adapter *padapter);
+
+void report_join_res(struct adapter *padapter, int res);
+void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame);
+void report_surveydone_event(struct adapter *padapter);
+void report_del_sta_event(struct adapter *padapter,
+ unsigned char *addr, unsigned short reason);
+void report_add_sta_event(struct adapter *padapter, unsigned char* addr,
+ int cam_idx);
+
+void beacon_timing_control(struct adapter *padapter);
+extern u8 set_tx_beacon_cmd(struct adapter*padapter);
+unsigned int setup_beacon_frame(struct adapter *padapter,
+ unsigned char *beacon_frame);
+void update_mgnt_tx_rate(struct adapter *padapter, u8 rate);
+void update_mgntframe_attrib(struct adapter *padapter,
+ struct pkt_attrib *pattrib);
+void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe);
+s32 dump_mgntframe_and_wait(struct adapter *padapter,
+ struct xmit_frame *pmgntframe, int timeout_ms);
+s32 dump_mgntframe_and_wait_ack(struct adapter *padapter,
+ struct xmit_frame *pmgntframe);
+
+#ifdef CONFIG_88EU_P2P
+void issue_probersp_p2p(struct adapter *padapter, unsigned char *da);
+void issue_p2p_provision_request(struct adapter *padapter, u8 *pssid,
+ u8 ussidlen, u8 *pdev_raddr);
+void issue_p2p_GO_request(struct adapter *padapter, u8 *raddr);
+void issue_probereq_p2p(struct adapter *padapter, u8 *da);
+int issue_probereq_p2p_ex(struct adapter *adapter, u8 *da, int try_cnt,
+ int wait_ms);
+void issue_p2p_invitation_response(struct adapter *padapter, u8 *raddr,
+ u8 dialogToken, u8 success);
+void issue_p2p_invitation_request(struct adapter *padapter, u8* raddr);
+#endif /* CONFIG_88EU_P2P */
+void issue_beacon(struct adapter *padapter, int timeout_ms);
+void issue_probersp(struct adapter *padapter, unsigned char *da,
+ u8 is_valid_p2p_probereq);
+void issue_assocreq(struct adapter *padapter);
+void issue_asocrsp(struct adapter *padapter, unsigned short status,
+ struct sta_info *pstat, int pkt_type);
+void issue_auth(struct adapter *padapter, struct sta_info *psta,
+ unsigned short status);
+void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid,
+ u8 *da);
+s32 issue_probereq_ex(struct adapter *adapter, struct ndis_802_11_ssid *pssid,
+ u8* da, int try_cnt, int wait_ms);
+int issue_nulldata(struct adapter *padapter, unsigned char *da,
+ unsigned int power_mode, int try_cnt, int wait_ms);
+int issue_qos_nulldata(struct adapter *padapter, unsigned char *da,
+ u16 tid, int try_cnt, int wait_ms);
+int issue_deauth(struct adapter *padapter, unsigned char *da,
+ unsigned short reason);
+int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason,
+ int try_cnt, int wait_ms);
+void issue_action_spct_ch_switch(struct adapter *padapter, u8 *ra, u8 new_ch,
+ u8 ch_offset);
+void issue_action_BA(struct adapter *padapter, unsigned char *raddr,
+ unsigned char action, unsigned short status);
+unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr);
+unsigned int send_beacon(struct adapter *padapter);
+
+void start_clnt_assoc(struct adapter *padapter);
+void start_clnt_auth(struct adapter *padapter);
+void start_clnt_join(struct adapter *padapter);
+void start_create_ibss(struct adapter *padapter);
+
+unsigned int OnAssocReq(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAssocRsp(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnProbeReq(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnProbeRsp(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int DoReserved(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnBeacon(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAtim(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnDisassoc(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAuth(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAuthClient(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnDeAuth(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAction(struct adapter *padapter,
+ union recv_frame *precv_frame);
+
+unsigned int on_action_spct(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAction_qos(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAction_dls(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAction_back(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int on_action_public(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAction_ht(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAction_wmm(struct adapter *padapter,
+ union recv_frame *precv_frame);
+unsigned int OnAction_p2p(struct adapter *padapter,
+ union recv_frame *precv_frame);
+
+void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res);
+void mlmeext_sta_del_event_callback(struct adapter *padapter);
+void mlmeext_sta_add_event_callback(struct adapter *padapter,
+ struct sta_info *psta);
+
+void linked_status_chk(struct adapter *padapter);
+
+void survey_timer_hdl (struct adapter *padapter);
+void link_timer_hdl (struct adapter *padapter);
+void addba_timer_hdl(struct sta_info *psta);
+
+#define set_survey_timer(mlmeext, ms) \
+ do { \
+ _set_timer(&(mlmeext)->survey_timer, (ms)); \
+ } while (0)
+
+#define set_link_timer(mlmeext, ms) \
+ do { \
+ _set_timer(&(mlmeext)->link_timer, (ms)); \
+ } while (0)
+
+int cckrates_included(unsigned char *rate, int ratelen);
+int cckratesonly_included(unsigned char *rate, int ratelen);
+
+void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr);
+
+void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len);
+void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext);
+
+struct cmd_hdl {
+ uint parmsize;
+ u8 (*h2cfuns)(struct adapter *padapter, u8 *pbuf);
+};
+
+u8 read_macreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 write_macreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 read_bbreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 write_bbreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 read_rfreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 write_rfreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 NULL_hdl(struct adapter *padapter, u8 *pbuf);
+u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf);
+u8 disconnect_hdl(struct adapter *padapter, u8 *pbuf);
+u8 createbss_hdl(struct adapter *padapter, u8 *pbuf);
+u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf);
+u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf);
+u8 setauth_hdl(struct adapter *padapter, u8 *pbuf);
+u8 setkey_hdl(struct adapter *padapter, u8 *pbuf);
+u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf);
+u8 set_assocsta_hdl(struct adapter *padapter, u8 *pbuf);
+u8 del_assocsta_hdl(struct adapter *padapter, u8 *pbuf);
+u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf);
+
+u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf);
+u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf);
+u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf);
+u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf);
+u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf);
+u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf);
+/* Handling DFS channel switch announcement ie. */
+u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf);
+u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf);
+
+#define GEN_DRV_CMD_HANDLER(size, cmd) {size, &cmd ## _hdl},
+#define GEN_MLME_EXT_HANDLER(size, cmd) {size, cmd},
+
+#ifdef _RTW_CMD_C_
+
+static struct cmd_hdl wlancmds[] = {
+ GEN_DRV_CMD_HANDLER(0, NULL) /*0*/
+ GEN_DRV_CMD_HANDLER(0, NULL)
+ GEN_DRV_CMD_HANDLER(0, NULL)
+ GEN_DRV_CMD_HANDLER(0, NULL)
+ GEN_DRV_CMD_HANDLER(0, NULL)
+ GEN_DRV_CMD_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL) /*10*/
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(sizeof (struct joinbss_parm), join_cmd_hdl) /*14*/
+ GEN_MLME_EXT_HANDLER(sizeof (struct disconnect_parm), disconnect_hdl)
+ GEN_MLME_EXT_HANDLER(sizeof (struct createbss_parm), createbss_hdl)
+ GEN_MLME_EXT_HANDLER(sizeof (struct setopmode_parm), setopmode_hdl)
+ GEN_MLME_EXT_HANDLER(sizeof (struct sitesurvey_parm),
+ sitesurvey_cmd_hdl) /*18*/
+ GEN_MLME_EXT_HANDLER(sizeof (struct setauth_parm), setauth_hdl)
+ GEN_MLME_EXT_HANDLER(sizeof (struct setkey_parm), setkey_hdl) /*20*/
+ GEN_MLME_EXT_HANDLER(sizeof (struct set_stakey_parm), set_stakey_hdl)
+ GEN_MLME_EXT_HANDLER(sizeof (struct set_assocsta_parm), NULL)
+ GEN_MLME_EXT_HANDLER(sizeof (struct del_assocsta_parm), NULL)
+ GEN_MLME_EXT_HANDLER(sizeof (struct setstapwrstate_parm), NULL)
+ GEN_MLME_EXT_HANDLER(sizeof (struct setbasicrate_parm), NULL)
+ GEN_MLME_EXT_HANDLER(sizeof (struct getbasicrate_parm), NULL)
+ GEN_MLME_EXT_HANDLER(sizeof (struct setdatarate_parm), NULL)
+ GEN_MLME_EXT_HANDLER(sizeof (struct getdatarate_parm), NULL)
+ GEN_MLME_EXT_HANDLER(sizeof (struct setphyinfo_parm), NULL)
+ GEN_MLME_EXT_HANDLER(sizeof (struct getphyinfo_parm), NULL) /*30*/
+ GEN_MLME_EXT_HANDLER(sizeof (struct setphy_parm), NULL)
+ GEN_MLME_EXT_HANDLER(sizeof (struct getphy_parm), NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL) /*40*/
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl)
+ GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), set_ch_hdl) /* 46 */
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL) /*50*/
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(0, NULL)
+ GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param),
+ tx_beacon_hdl) /*55*/
+
+ GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl) /*56*/
+ GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl) /*57*/
+
+ GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl) /*58*/
+ GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param),
+ set_chplan_hdl) /*59*/
+ GEN_MLME_EXT_HANDLER(sizeof(struct LedBlink_param),
+ led_blink_hdl) /*60*/
+
+ GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param),
+ set_csa_hdl) /*61*/
+ GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param),
+ tdls_hdl) /*62*/
+};
+
+#endif
+
+struct C2HEvent_Header {
+#ifdef __LITTLE_ENDIAN
+ unsigned int len:16;
+ unsigned int ID:8;
+ unsigned int seq:8;
+#elif defined(__BIG_ENDIAN)
+ unsigned int seq:8;
+ unsigned int ID:8;
+ unsigned int len:16;
+#endif
+ unsigned int rsvd;
+};
+
+void rtw_dummy_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_fwdbg_event_callback(struct adapter *adapter, u8 *pbuf);
+
+enum rtw_c2h_event {
+ GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/
+ GEN_EVT_CODE(_Read_BBREG),
+ GEN_EVT_CODE(_Read_RFREG),
+ GEN_EVT_CODE(_Read_EEPROM),
+ GEN_EVT_CODE(_Read_EFUSE),
+ GEN_EVT_CODE(_Read_CAM), /*5*/
+ GEN_EVT_CODE(_Get_BasicRate),
+ GEN_EVT_CODE(_Get_DataRate),
+ GEN_EVT_CODE(_Survey), /*8*/
+ GEN_EVT_CODE(_SurveyDone), /*9*/
+
+ GEN_EVT_CODE(_JoinBss) , /*10*/
+ GEN_EVT_CODE(_AddSTA),
+ GEN_EVT_CODE(_DelSTA),
+ GEN_EVT_CODE(_AtimDone),
+ GEN_EVT_CODE(_TX_Report),
+ GEN_EVT_CODE(_CCX_Report), /*15*/
+ GEN_EVT_CODE(_DTM_Report),
+ GEN_EVT_CODE(_TX_Rate_Statistics),
+ GEN_EVT_CODE(_C2HLBK),
+ GEN_EVT_CODE(_FWDBG),
+ GEN_EVT_CODE(_C2HFEEDBACK), /*20*/
+ GEN_EVT_CODE(_ADDBA),
+ GEN_EVT_CODE(_C2HBCN),
+ GEN_EVT_CODE(_ReportPwrState), /* filen: only for PCIE, USB */
+ GEN_EVT_CODE(_CloseRF), /* filen: only for PCIE,
+ * work around ASPM */
+ MAX_C2HEVT
+};
+
+
+#ifdef _RTW_MLME_EXT_C_
+
+static struct fwevent wlanevents[] = {
+ {0, rtw_dummy_event_callback}, /*0*/
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, &rtw_survey_event_callback}, /*8*/
+ {sizeof (struct surveydone_event), &rtw_surveydone_event_callback},/*9*/
+ {0, &rtw_joinbss_event_callback}, /*10*/
+ {sizeof(struct stassoc_event), &rtw_stassoc_event_callback},
+ {sizeof(struct stadel_event), &rtw_stadel_event_callback},
+ {0, &rtw_atimdone_event_callback},
+ {0, rtw_dummy_event_callback},
+ {0, NULL}, /*15*/
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, rtw_fwdbg_event_callback},
+ {0, NULL}, /*20*/
+ {0, NULL},
+ {0, NULL},
+ {0, &rtw_cpwm_event_callback},
+};
+
+#endif/* _RTL_MLME_EXT_C_ */
+
+#endif /* __RTW_MLME_EXT_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mp.h b/drivers/staging/rtl8188eu/include/rtw_mp.h
new file mode 100644
index 00000000000..59bdbb5f396
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_mp.h
@@ -0,0 +1,495 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_MP_H_
+#define _RTW_MP_H_
+
+/* 00 - Success */
+/* 11 - Error */
+#define STATUS_SUCCESS (0x00000000L)
+#define STATUS_PENDING (0x00000103L)
+
+#define STATUS_UNSUCCESSFUL (0xC0000001L)
+#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AL)
+#define STATUS_NOT_SUPPORTED (0xC00000BBL)
+
+#define NDIS_STATUS_SUCCESS ((int)STATUS_SUCCESS)
+#define NDIS_STATUS_PENDING ((int)STATUS_PENDING)
+#define NDIS_STATUS_NOT_RECOGNIZED ((int)0x00010001L)
+#define NDIS_STATUS_NOT_COPIED ((int)0x00010002L)
+#define NDIS_STATUS_NOT_ACCEPTED ((int)0x00010003L)
+#define NDIS_STATUS_CALL_ACTIVE ((int)0x00010007L)
+
+#define NDIS_STATUS_FAILURE ((int)STATUS_UNSUCCESSFUL)
+#define NDIS_STATUS_RESOURCES ((int)STATUS_INSUFFICIENT_RESOURCES)
+#define NDIS_STATUS_CLOSING ((int)0xC0010002L)
+#define NDIS_STATUS_BAD_VERSION ((int)0xC0010004L)
+#define NDIS_STATUS_BAD_CHARACTERISTICS ((int)0xC0010005L)
+#define NDIS_STATUS_ADAPTER_NOT_FOUND ((int)0xC0010006L)
+#define NDIS_STATUS_OPEN_FAILED ((int)0xC0010007L)
+#define NDIS_STATUS_DEVICE_FAILED ((int)0xC0010008L)
+#define NDIS_STATUS_MULTICAST_FULL ((int)0xC0010009L)
+#define NDIS_STATUS_MULTICAST_EXISTS ((int)0xC001000AL)
+#define NDIS_STATUS_MULTICAST_NOT_FOUND ((int)0xC001000BL)
+#define NDIS_STATUS_REQUEST_ABORTED ((int)0xC001000CL)
+#define NDIS_STATUS_RESET_IN_PROGRESS ((int)0xC001000DL)
+#define NDIS_STATUS_CLOSING_INDICATING ((int)0xC001000EL)
+#define NDIS_STATUS_NOT_SUPPORTED ((int)STATUS_NOT_SUPPORTED)
+#define NDIS_STATUS_INVALID_PACKET ((int)0xC001000FL)
+#define NDIS_STATUS_OPEN_LIST_FULL ((int)0xC0010010L)
+#define NDIS_STATUS_ADAPTER_NOT_READY ((int)0xC0010011L)
+#define NDIS_STATUS_ADAPTER_NOT_OPEN ((int)0xC0010012L)
+#define NDIS_STATUS_NOT_INDICATING ((int)0xC0010013L)
+#define NDIS_STATUS_INVALID_LENGTH ((int)0xC0010014L)
+#define NDIS_STATUS_INVALID_DATA ((int)0xC0010015L)
+#define NDIS_STATUS_BUFFER_TOO_SHORT ((int)0xC0010016L)
+#define NDIS_STATUS_INVALID_OID ((int)0xC0010017L)
+#define NDIS_STATUS_ADAPTER_REMOVED ((int)0xC0010018L)
+#define NDIS_STATUS_UNSUPPORTED_MEDIA ((int)0xC0010019L)
+#define NDIS_STATUS_GROUP_ADDRESS_IN_USE ((int)0xC001001AL)
+#define NDIS_STATUS_FILE_NOT_FOUND ((int)0xC001001BL)
+#define NDIS_STATUS_ERROR_READING_FILE ((int)0xC001001CL)
+#define NDIS_STATUS_ALREADY_MAPPED ((int)0xC001001DL)
+#define NDIS_STATUS_RESOURCE_CONFLICT ((int)0xC001001EL)
+#define NDIS_STATUS_NO_CABLE ((int)0xC001001FL)
+
+#define NDIS_STATUS_INVALID_SAP ((int)0xC0010020L)
+#define NDIS_STATUS_SAP_IN_USE ((int)0xC0010021L)
+#define NDIS_STATUS_INVALID_ADDRESS ((int)0xC0010022L)
+#define NDIS_STATUS_VC_NOT_ACTIVATED ((int)0xC0010023L)
+#define NDIS_STATUS_DEST_OUT_OF_ORDER ((int)0xC0010024L) /*cause 27*/
+#define NDIS_STATUS_VC_NOT_AVAILABLE ((int)0xC0010025L) /*cause 35,45 */
+#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE ((int)0xC0010026L) /*cause 37*/
+#define NDIS_STATUS_INCOMPATABLE_QOS ((int)0xC0010027L) /*cause 49*/
+#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED ((int)0xC0010028L) /*cause 93*/
+#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION ((int)0xC0010029L) /*cause 3 */
+
+enum antenna_path {
+ ANTENNA_NONE = 0x00,
+ ANTENNA_D,
+ ANTENNA_C,
+ ANTENNA_CD,
+ ANTENNA_B,
+ ANTENNA_BD,
+ ANTENNA_BC,
+ ANTENNA_BCD,
+ ANTENNA_A,
+ ANTENNA_AD,
+ ANTENNA_AC,
+ ANTENNA_ACD,
+ ANTENNA_AB,
+ ANTENNA_ABD,
+ ANTENNA_ABC,
+ ANTENNA_ABCD
+};
+
+
+#define MAX_MP_XMITBUF_SZ 2048
+#define NR_MP_XMITFRAME 8
+
+struct mp_xmit_frame {
+ struct list_head list;
+ struct pkt_attrib attrib;
+ struct sk_buff *pkt;
+ int frame_tag;
+ struct adapter *padapter;
+ struct urb *pxmit_urb[8];
+ /* insert urb, irp, and irpcnt info below... */
+ u8 *mem_addr;
+ u32 sz[8];
+ u8 bpending[8];
+ int ac_tag[8];
+ int last[8];
+ uint irpcnt;
+ uint fragcnt;
+ uint mem[(MAX_MP_XMITBUF_SZ >> 2)];
+};
+
+struct mp_wiparam {
+ u32 bcompleted;
+ u32 act_type;
+ u32 io_offset;
+ u32 io_value;
+};
+
+typedef void(*wi_act_func)(void *padapter);
+
+struct mp_tx {
+ u8 stop;
+ u32 count, sended;
+ u8 payload;
+ struct pkt_attrib attrib;
+ struct tx_desc desc;
+ u8 *pallocated_buf;
+ u8 *buf;
+ u32 buf_size, write_size;
+ void *PktTxThread;
+};
+
+#include <Hal8188EPhyCfg.h>
+
+#define MP_MAX_LINES 1000
+#define MP_MAX_LINES_BYTES 256
+
+typedef void (*MPT_WORK_ITEM_HANDLER)(void *Adapter);
+
+struct mpt_context {
+ /* Indicate if we have started Mass Production Test. */
+ bool bMassProdTest;
+
+ /* Indicate if the driver is unloading or unloaded. */
+ bool bMptDrvUnload;
+
+ struct semaphore MPh2c_Sema;
+ struct timer_list MPh2c_timeout_timer;
+/* Event used to sync H2c for BT control */
+
+ bool MptH2cRspEvent;
+ bool MptBtC2hEvent;
+ bool bMPh2c_timeout;
+
+ /* 8190 PCI does not support NDIS_WORK_ITEM. */
+ /* Work Item for Mass Production Test. */
+ /* Event used to sync the case unloading driver and MptWorkItem
+ * is still in progress. */
+ /* Indicate a MptWorkItem is scheduled and not yet finished. */
+ bool bMptWorkItemInProgress;
+ /* An instance which implements function and context of MptWorkItem. */
+ MPT_WORK_ITEM_HANDLER CurrMptAct;
+
+ /* 1=Start, 0=Stop from UI. */
+ u32 MptTestStart;
+ /* _TEST_MODE, defined in MPT_Req2.h */
+ u32 MptTestItem;
+ /* Variable needed in each implementation of CurrMptAct. */
+ u32 MptActType; /* Type of action performed in CurrMptAct. */
+ /* The Offset of IO operation is depend of MptActType. */
+ u32 MptIoOffset;
+ /* The Value of IO operation is depend of MptActType. */
+ u32 MptIoValue;
+ /* The RfPath of IO operation is depend of MptActType. */
+ u32 MptRfPath;
+
+ enum wireless_mode MptWirelessModeToSw; /* Wireless mode to switch. */
+ u8 MptChannelToSw; /* Channel to switch. */
+ u8 MptInitGainToSet; /* Initial gain to set. */
+ u32 MptBandWidth; /* bandwidth to switch. */
+ u32 MptRateIndex; /* rate index. */
+ /* Register value kept for Single Carrier Tx test. */
+ u8 btMpCckTxPower;
+ /* Register value kept for Single Carrier Tx test. */
+ u8 btMpOfdmTxPower;
+ /* For MP Tx Power index */
+ u8 TxPwrLevel[2]; /* rf-A, rf-B */
+
+ /* Content of RCR Regsiter for Mass Production Test. */
+ u32 MptRCR;
+ /* true if we only receive packets with specific pattern. */
+ bool bMptFilterPattern;
+ /* Rx OK count, statistics used in Mass Production Test. */
+ u32 MptRxOkCnt;
+ /* Rx CRC32 error count, statistics used in Mass Production Test. */
+ u32 MptRxCrcErrCnt;
+
+ bool bCckContTx; /* true if we are in CCK Continuous Tx test. */
+ bool bOfdmContTx; /* true if we are in OFDM Continuous Tx test. */
+ bool bStartContTx; /* true if we have start Continuous Tx test. */
+ /* true if we are in Single Carrier Tx test. */
+ bool bSingleCarrier;
+ /* true if we are in Carrier Suppression Tx Test. */
+ bool bCarrierSuppression;
+ /* true if we are in Single Tone Tx test. */
+ bool bSingleTone;
+
+ /* ACK counter asked by K.Y.. */
+ bool bMptEnableAckCounter;
+ u32 MptAckCounter;
+
+ u8 APK_bound[2]; /* for APK path A/path B */
+ bool bMptIndexEven;
+
+ u8 backup0xc50;
+ u8 backup0xc58;
+ u8 backup0xc30;
+ u8 backup0x52_RF_A;
+ u8 backup0x52_RF_B;
+
+ u8 h2cReqNum;
+ u8 c2hBuf[20];
+
+ u8 btInBuf[100];
+ u32 mptOutLen;
+ u8 mptOutBuf[100];
+};
+
+enum {
+ WRITE_REG = 1,
+ READ_REG,
+ WRITE_RF,
+ READ_RF,
+ MP_START,
+ MP_STOP,
+ MP_RATE,
+ MP_CHANNEL,
+ MP_BANDWIDTH,
+ MP_TXPOWER,
+ MP_ANT_TX,
+ MP_ANT_RX,
+ MP_CTX,
+ MP_QUERY,
+ MP_ARX,
+ MP_PSD,
+ MP_PWRTRK,
+ MP_THER,
+ MP_IOCTL,
+ EFUSE_GET,
+ EFUSE_SET,
+ MP_RESET_STATS,
+ MP_DUMP,
+ MP_PHYPARA,
+ MP_SetRFPathSwh,
+ MP_QueryDrvStats,
+ MP_SetBT,
+ CTA_TEST,
+ MP_NULL,
+};
+
+struct mp_priv {
+ struct adapter *papdater;
+
+ /* Testing Flag */
+ /* 0 for normal type packet, 1 for loopback packet (16bytes TXCMD) */
+ u32 mode;
+
+ u32 prev_fw_state;
+
+ /* OID cmd handler */
+ struct mp_wiparam workparam;
+
+ /* Tx Section */
+ u8 TID;
+ u32 tx_pktcount;
+ struct mp_tx tx;
+
+ /* Rx Section */
+ u32 rx_pktcount;
+ u32 rx_crcerrpktcount;
+ u32 rx_pktloss;
+
+ struct recv_stat rxstat;
+
+ /* RF/BB relative */
+ u8 channel;
+ u8 bandwidth;
+ u8 prime_channel_offset;
+ u8 txpoweridx;
+ u8 txpoweridx_b;
+ u8 rateidx;
+ u32 preamble;
+ u32 CrystalCap;
+
+ u16 antenna_tx;
+ u16 antenna_rx;
+
+ u8 check_mp_pkt;
+
+ u8 bSetTxPower;
+
+ struct wlan_network mp_network;
+ unsigned char network_macaddr[ETH_ALEN];
+
+ u8 *pallocated_mp_xmitframe_buf;
+ u8 *pmp_xmtframe_buf;
+ struct __queue free_mp_xmitqueue;
+ u32 free_mp_xmitframe_cnt;
+
+ struct mpt_context MptCtx;
+};
+
+struct iocmd_struct {
+ u8 cmdclass;
+ u16 value;
+ u8 index;
+};
+
+struct rf_reg_param {
+ u32 path;
+ u32 offset;
+ u32 value;
+};
+
+struct bb_reg_param {
+ u32 offset;
+ u32 value;
+};
+/* */
+
+#define LOWER true
+#define RAISE false
+
+/* Hardware Registers */
+#define BB_REG_BASE_ADDR 0x800
+
+/* MP variables */
+enum mp_mode_{
+ MP_OFF,
+ MP_ON,
+ MP_ERR,
+ MP_CONTINUOUS_TX,
+ MP_SINGLE_CARRIER_TX,
+ MP_CARRIER_SUPPRISSION_TX,
+ MP_SINGLE_TONE_TX,
+ MP_PACKET_TX,
+ MP_PACKET_RX
+};
+
+#define MAX_RF_PATH_NUMS RF_PATH_MAX
+
+extern u8 mpdatarate[NumRates];
+
+/* MP set force data rate base on the definition. */
+enum mpt_rate_index {
+ /* CCK rate. */
+ MPT_RATE_1M, /* 0 */
+ MPT_RATE_2M,
+ MPT_RATE_55M,
+ MPT_RATE_11M, /* 3 */
+
+ /* OFDM rate. */
+ MPT_RATE_6M, /* 4 */
+ MPT_RATE_9M,
+ MPT_RATE_12M,
+ MPT_RATE_18M,
+ MPT_RATE_24M,
+ MPT_RATE_36M,
+ MPT_RATE_48M,
+ MPT_RATE_54M, /* 11 */
+
+ /* HT rate. */
+ MPT_RATE_MCS0, /* 12 */
+ MPT_RATE_MCS1,
+ MPT_RATE_MCS2,
+ MPT_RATE_MCS3,
+ MPT_RATE_MCS4,
+ MPT_RATE_MCS5,
+ MPT_RATE_MCS6,
+ MPT_RATE_MCS7, /* 19 */
+ MPT_RATE_MCS8,
+ MPT_RATE_MCS9,
+ MPT_RATE_MCS10,
+ MPT_RATE_MCS11,
+ MPT_RATE_MCS12,
+ MPT_RATE_MCS13,
+ MPT_RATE_MCS14,
+ MPT_RATE_MCS15, /* 27 */
+ MPT_RATE_LAST
+};
+
+#define MAX_TX_PWR_INDEX_N_MODE 64 /* 0x3F */
+
+enum power_mode {
+ POWER_LOW = 0,
+ POWER_NORMAL
+};
+
+#define RX_PKT_BROADCAST 1
+#define RX_PKT_DEST_ADDR 2
+#define RX_PKT_PHY_MATCH 3
+
+enum encry_ctrl_state {
+ HW_CONTROL, /* hw encryption& decryption */
+ SW_CONTROL, /* sw encryption& decryption */
+ HW_ENCRY_SW_DECRY, /* hw encryption & sw decryption */
+ SW_ENCRY_HW_DECRY /* sw encryption & hw decryption */
+};
+
+s32 init_mp_priv(struct adapter *padapter);
+void free_mp_priv(struct mp_priv *pmp_priv);
+s32 MPT_InitializeAdapter(struct adapter *padapter, u8 Channel);
+void MPT_DeInitAdapter(struct adapter *padapter);
+s32 mp_start_test(struct adapter *padapter);
+void mp_stop_test(struct adapter *padapter);
+
+u32 _read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask);
+void _write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val);
+
+u32 read_macreg(struct adapter *padapter, u32 addr, u32 sz);
+void write_macreg(struct adapter *padapter, u32 addr, u32 val, u32 sz);
+u32 read_bbreg(struct adapter *padapter, u32 addr, u32 bitmask);
+void write_bbreg(struct adapter *padapter, u32 addr, u32 bitmask, u32 val);
+u32 read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr);
+void write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 val);
+
+void SetChannel(struct adapter *pAdapter);
+void SetBandwidth(struct adapter *pAdapter);
+void SetTxPower(struct adapter *pAdapter);
+void SetAntennaPathPower(struct adapter *pAdapter);
+void SetDataRate(struct adapter *pAdapter);
+
+void SetAntenna(struct adapter *pAdapter);
+
+s32 SetThermalMeter(struct adapter *pAdapter, u8 target_ther);
+void GetThermalMeter(struct adapter *pAdapter, u8 *value);
+
+void SetContinuousTx(struct adapter *pAdapter, u8 bStart);
+void SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart);
+void SetSingleToneTx(struct adapter *pAdapter, u8 bStart);
+void SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart);
+void PhySetTxPowerLevel(struct adapter *pAdapter);
+
+void fill_txdesc_for_mp(struct adapter *padapter, struct tx_desc *ptxdesc);
+void SetPacketTx(struct adapter *padapter);
+void SetPacketRx(struct adapter *pAdapter, u8 bStartRx);
+
+void ResetPhyRxPktCount(struct adapter *pAdapter);
+u32 GetPhyRxPktReceived(struct adapter *pAdapter);
+u32 GetPhyRxPktCRC32Error(struct adapter *pAdapter);
+
+s32 SetPowerTracking(struct adapter *padapter, u8 enable);
+void GetPowerTracking(struct adapter *padapter, u8 *enable);
+u32 mp_query_psd(struct adapter *pAdapter, u8 *data);
+void Hal_SetAntenna(struct adapter *pAdapter);
+void Hal_SetBandwidth(struct adapter *pAdapter);
+void Hal_SetTxPower(struct adapter *pAdapter);
+void Hal_SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart);
+void Hal_SetSingleToneTx(struct adapter *pAdapter, u8 bStart);
+void Hal_SetSingleCarrierTx (struct adapter *pAdapter, u8 bStart);
+void Hal_SetContinuousTx (struct adapter *pAdapter, u8 bStart);
+void Hal_SetBandwidth(struct adapter *pAdapter);
+void Hal_SetDataRate(struct adapter *pAdapter);
+void Hal_SetChannel(struct adapter *pAdapter);
+void Hal_SetAntennaPathPower(struct adapter *pAdapter);
+s32 Hal_SetThermalMeter(struct adapter *pAdapter, u8 target_ther);
+s32 Hal_SetPowerTracking(struct adapter *padapter, u8 enable);
+void Hal_GetPowerTracking(struct adapter *padapter, u8 * enable);
+void Hal_GetThermalMeter(struct adapter *pAdapter, u8 *value);
+void Hal_mpt_SwitchRfSetting(struct adapter *pAdapter);
+void Hal_MPT_CCKTxPowerAdjust(struct adapter * Adapter, bool bInCH14);
+void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *pAdapter, bool beven);
+void Hal_SetCCKTxPower(struct adapter *pAdapter, u8 * TxPower);
+void Hal_SetOFDMTxPower(struct adapter *pAdapter, u8 * TxPower);
+void Hal_TriggerRFThermalMeter(struct adapter *pAdapter);
+u8 Hal_ReadRFThermalMeter(struct adapter *pAdapter);
+void Hal_SetCCKContinuousTx(struct adapter *pAdapter, u8 bStart);
+void Hal_SetOFDMContinuousTx(struct adapter *pAdapter, u8 bStart);
+void Hal_ProSetCrystalCap (struct adapter *pAdapter , u32 CrystalCapVal);
+void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv);
+void MP_PHY_SetRFPathSwitch(struct adapter *pAdapter ,bool bMain);
+
+#endif /* _RTW_MP_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mp_ioctl.h b/drivers/staging/rtl8188eu/include/rtw_mp_ioctl.h
new file mode 100644
index 00000000000..494e90e5a75
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_mp_ioctl.h
@@ -0,0 +1,340 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_MP_IOCTL_H_
+#define _RTW_MP_IOCTL_H_
+
+#include <drv_types.h>
+#include <mp_custom_oid.h>
+#include <rtw_ioctl.h>
+#include <rtw_ioctl_rtl.h>
+#include <rtw_efuse.h>
+#include <rtw_mp.h>
+
+/* */
+struct cfg_dbg_msg_struct {
+ u32 DebugLevel;
+ u32 DebugComponent_H32;
+ u32 DebugComponent_L32;
+};
+
+struct mp_rw_reg {
+ u32 offset;
+ u32 width;
+ u32 value;
+};
+
+struct efuse_access_struct {
+ u16 start_addr;
+ u16 cnts;
+ u8 data[0];
+};
+
+struct burst_rw_reg {
+ u32 offset;
+ u32 len;
+ u8 Data[256];
+};
+
+struct usb_vendor_req {
+ u8 bRequest;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+ u8 u8Dir;/* 0:OUT, 1:IN */
+ u8 u8InData;
+};
+
+struct dr_variable_struct {
+ u8 offset;
+ u32 variable;
+};
+
+#define _irqlevel_changed_(a, b)
+
+/* rtl8188eu_oid_rtl_seg_81_80_00 */
+int rtl8188eu_oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv);
+
+/* rtl8188eu_oid_rtl_seg_81_80_20 */
+int rtl8188eu_oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *par_priv);
+int rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *par_priv);
+int rtl8188eu_oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *par_priv);
+int rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv);
+
+/* rtl8188eu_oid_rtl_seg_81_87 */
+int rtl8188eu_oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv);
+
+/* rtl8188eu_oid_rtl_seg_81_85 */
+int rtl8188eu_oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv);
+
+/* rtl8188eu_oid_rtl_seg_87_11_00 */
+int rtl8188eu_oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_burst_read_register_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_burst_write_register_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_write16_eeprom_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_wr_attrib_mem_hdl (struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv);
+/* rtl8188eu_oid_rtl_seg_87_11_20 */
+int rtl8188eu_oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read_tssi_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_priv);
+/* rtl8188eu_oid_rtl_seg_87_11_50 */
+int rtl8188eu_oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv);
+/* rtl8188eu_oid_rtl_seg_87_11_F0 */
+int rtl8188eu_oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv *poid_par_priv);
+
+/* rtl8188eu_oid_rtl_seg_87_12_00 */
+int rtl8188eu_oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *par_priv);
+int rtl8188eu_oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv);
+
+#ifdef _RTW_MP_IOCTL_C_
+
+static const struct oid_obj_priv rtl8188eu_oid_rtl_seg_81_80_00[] = {
+ {1, &oid_null_function}, /* 0x00 OID_RT_PRO_RESET_DUT */
+ {1, &rtl8188eu_oid_rt_pro_set_data_rate_hdl}, /* 0x01 */
+ {1, &rtl8188eu_oid_rt_pro_start_test_hdl}, /* 0x02 */
+ {1, &rtl8188eu_oid_rt_pro_stop_test_hdl}, /* 0x03 */
+ {1, &oid_null_function}, /* 0x04 OID_RT_PRO_SET_PREAMBLE */
+ {1, &oid_null_function}, /* 0x05 OID_RT_PRO_SET_SCRAMBLER */
+ {1, &oid_null_function}, /* 0x06 OID_RT_PRO_SET_FILTER_BB */
+ {1, &oid_null_function},/* 0x07 OID_RT_PRO_SET_MANUAL_DIVERSITY_BB */
+ {1, &rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl}, /* 0x08 */
+ {1, &oid_null_function},/* 0x09 OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL */
+ {1, &oid_null_function},/* 0x0A OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL */
+ {1, &rtl8188eu_oid_rt_pro_set_continuous_tx_hdl}, /* 0x0B OID_RT_PRO_SET_TX_CONTINUOUS_DIRECT_CALL */
+ {1, &rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl},/* 0x0C OID_RT_PRO_SET_SINGLE_CARRIER_TX_CONTINUOUS */
+ {1, &oid_null_function}, /* 0x0D OID_RT_PRO_SET_TX_ANTENNA_BB */
+ {1, &rtl8188eu_oid_rt_pro_set_antenna_bb_hdl}, /* 0x0E */
+ {1, &oid_null_function}, /* 0x0F OID_RT_PRO_SET_CR_SCRAMBLER */
+ {1, &oid_null_function}, /* 0x10 OID_RT_PRO_SET_CR_NEW_FILTER */
+ {1, &rtl8188eu_oid_rt_pro_set_tx_power_control_hdl},/* 0x11 OID_RT_PRO_SET_TX_POWER_CONTROL */
+ {1, &oid_null_function}, /* 0x12 OID_RT_PRO_SET_CR_TX_CONFIG */
+ {1, &oid_null_function}, /* 0x13 OID_RT_PRO_GET_TX_POWER_CONTROL */
+ {1, &oid_null_function}, /* 0x14 OID_RT_PRO_GET_CR_SIGNAL_QUALITY */
+ {1, &oid_null_function}, /* 0x15 OID_RT_PRO_SET_CR_SETPOINT */
+ {1, &oid_null_function}, /* 0x16 OID_RT_PRO_SET_INTEGRATOR */
+ {1, &oid_null_function}, /* 0x17 OID_RT_PRO_SET_SIGNAL_QUALITY */
+ {1, &oid_null_function}, /* 0x18 OID_RT_PRO_GET_INTEGRATOR */
+ {1, &oid_null_function}, /* 0x19 OID_RT_PRO_GET_SIGNAL_QUALITY */
+ {1, &oid_null_function}, /* 0x1A OID_RT_PRO_QUERY_EEPROM_TYPE */
+ {1, &oid_null_function}, /* 0x1B OID_RT_PRO_WRITE_MAC_ADDRESS */
+ {1, &oid_null_function}, /* 0x1C OID_RT_PRO_READ_MAC_ADDRESS */
+ {1, &oid_null_function}, /* 0x1D OID_RT_PRO_WRITE_CIS_DATA */
+ {1, &oid_null_function}, /* 0x1E OID_RT_PRO_READ_CIS_DATA */
+ {1, &oid_null_function} /* 0x1F OID_RT_PRO_WRITE_POWER_CONTROL */
+};
+
+static const struct oid_obj_priv rtl8188eu_oid_rtl_seg_81_80_20[] = {
+ {1, &oid_null_function}, /* 0x20 OID_RT_PRO_READ_POWER_CONTROL */
+ {1, &oid_null_function}, /* 0x21 OID_RT_PRO_WRITE_EEPROM */
+ {1, &oid_null_function}, /* 0x22 OID_RT_PRO_READ_EEPROM */
+ {1, &rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl}, /* 0x23 */
+ {1, &rtl8188eu_oid_rt_pro_query_tx_packet_sent_hdl}, /* 0x24 */
+ {1, &rtl8188eu_oid_rt_pro_reset_rx_packet_received_hdl}, /* 0x25 */
+ {1, &rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl}, /* 0x26 */
+ {1, &rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl}, /* 0x27 */
+ {1, &oid_null_function}, /* 0x28 OID_RT_PRO_QUERY_CURRENT_ADDRESS */
+ {1, &oid_null_function}, /* 0x29 OID_RT_PRO_QUERY_PERMANENT_ADDRESS */
+ {1, &oid_null_function}, /* 0x2A OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS */
+ {1, &rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl},/* 0x2B OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX */
+ {1, &oid_null_function}, /* 0x2C OID_RT_PRO_RECEIVE_PACKET */
+ {1, &oid_null_function}, /* 0x2D OID_RT_PRO_WRITE_EEPROM_BYTE */
+ {1, &oid_null_function}, /* 0x2E OID_RT_PRO_READ_EEPROM_BYTE */
+ {1, &rtl8188eu_oid_rt_pro_set_modulation_hdl} /* 0x2F */
+};
+
+static const struct oid_obj_priv rtl8188eu_oid_rtl_seg_81_80_40[] = {
+ {1, &oid_null_function}, /* 0x40 */
+ {1, &oid_null_function}, /* 0x41 */
+ {1, &oid_null_function}, /* 0x42 */
+ {1, &rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl}, /* 0x43 */
+ {1, &oid_null_function}, /* 0x44 */
+ {1, &oid_null_function} /* 0x45 */
+};
+
+static const struct oid_obj_priv rtl8188eu_oid_rtl_seg_81_80_80[] = {
+ {1, &oid_null_function}, /* 0x80 OID_RT_DRIVER_OPTION */
+ {1, &oid_null_function}, /* 0x81 OID_RT_RF_OFF */
+ {1, &oid_null_function} /* 0x82 OID_RT_AUTH_STATUS */
+};
+
+static const struct oid_obj_priv rtl8188eu_oid_rtl_seg_81_85[] = {
+ {1, &rtl8188eu_oid_rt_wireless_mode_hdl} /* 0x00 OID_RT_WIRELESS_MODE */
+};
+
+#endif /* _RTL871X_MP_IOCTL_C_ */
+
+struct rwreg_param {
+ u32 offset;
+ u32 width;
+ u32 value;
+};
+
+struct bbreg_param {
+ u32 offset;
+ u32 phymask;
+ u32 value;
+};
+
+struct txpower_param {
+ u32 pwr_index;
+};
+
+struct datarate_param {
+ u32 rate_index;
+};
+
+struct rfintfs_parm {
+ u32 rfintfs;
+};
+
+struct mp_xmit_parm {
+ u8 enable;
+ u32 count;
+ u16 length;
+ u8 payload_type;
+ u8 da[ETH_ALEN];
+};
+
+struct mp_xmit_packet {
+ u32 len;
+ u32 mem[MAX_MP_XMITBUF_SZ >> 2];
+};
+
+struct psmode_param {
+ u32 ps_mode;
+ u32 smart_ps;
+};
+
+/* for OID_RT_PRO_READ16_EEPROM & OID_RT_PRO_WRITE16_EEPROM */
+struct eeprom_rw_param {
+ u32 offset;
+ u16 value;
+};
+
+struct mp_ioctl_handler {
+ u32 paramsize;
+ s32 (*handler)(struct oid_par_priv* poid_par_priv);
+ u32 oid;
+};
+
+struct mp_ioctl_param{
+ u32 subcode;
+ u32 len;
+ u8 data[0];
+};
+
+#define GEN_MP_IOCTL_SUBCODE(code) _MP_IOCTL_ ## code ## _CMD_
+
+enum RTL871X_MP_IOCTL_SUBCODE {
+ GEN_MP_IOCTL_SUBCODE(MP_START), /*0*/
+ GEN_MP_IOCTL_SUBCODE(MP_STOP),
+ GEN_MP_IOCTL_SUBCODE(READ_REG),
+ GEN_MP_IOCTL_SUBCODE(WRITE_REG),
+ GEN_MP_IOCTL_SUBCODE(READ_BB_REG),
+ GEN_MP_IOCTL_SUBCODE(WRITE_BB_REG), /*5*/
+ GEN_MP_IOCTL_SUBCODE(READ_RF_REG),
+ GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG),
+ GEN_MP_IOCTL_SUBCODE(SET_CHANNEL),
+ GEN_MP_IOCTL_SUBCODE(SET_TXPOWER),
+ GEN_MP_IOCTL_SUBCODE(SET_DATARATE), /*10*/
+ GEN_MP_IOCTL_SUBCODE(SET_BANDWIDTH),
+ GEN_MP_IOCTL_SUBCODE(SET_ANTENNA),
+ GEN_MP_IOCTL_SUBCODE(CNTU_TX),
+ GEN_MP_IOCTL_SUBCODE(SC_TX),
+ GEN_MP_IOCTL_SUBCODE(CS_TX), /*15*/
+ GEN_MP_IOCTL_SUBCODE(ST_TX),
+ GEN_MP_IOCTL_SUBCODE(IOCTL_XMIT_PACKET),
+ GEN_MP_IOCTL_SUBCODE(SET_RX_PKT_TYPE),
+ GEN_MP_IOCTL_SUBCODE(RESET_PHY_RX_PKT_CNT),
+ GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_RECV), /*20*/
+ GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_ERROR),
+ GEN_MP_IOCTL_SUBCODE(READ16_EEPROM),
+ GEN_MP_IOCTL_SUBCODE(WRITE16_EEPROM),
+ GEN_MP_IOCTL_SUBCODE(EFUSE),
+ GEN_MP_IOCTL_SUBCODE(EFUSE_MAP), /*25*/
+ GEN_MP_IOCTL_SUBCODE(GET_EFUSE_MAX_SIZE),
+ GEN_MP_IOCTL_SUBCODE(GET_EFUSE_CURRENT_SIZE),
+ GEN_MP_IOCTL_SUBCODE(GET_THERMAL_METER),
+ GEN_MP_IOCTL_SUBCODE(SET_PTM),
+ GEN_MP_IOCTL_SUBCODE(SET_POWER_DOWN), /*30*/
+ GEN_MP_IOCTL_SUBCODE(TRIGGER_GPIO),
+ GEN_MP_IOCTL_SUBCODE(SET_DM_BT), /*35*/
+ GEN_MP_IOCTL_SUBCODE(DEL_BA), /*36*/
+ GEN_MP_IOCTL_SUBCODE(GET_WIFI_STATUS), /*37*/
+ MAX_MP_IOCTL_SUBCODE,
+};
+
+s32 rtl8188eu_mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv);
+
+#define GEN_HANDLER(sz, hdl, oid) {sz, hdl, oid},
+
+#define EXT_MP_IOCTL_HANDLER(sz, subcode, oid) \
+ {sz, rtl8188eu_mp_ioctl_##subcode##_hdl, oid},
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h b/drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h
new file mode 100644
index 00000000000..3ad22076de3
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h
@@ -0,0 +1,1084 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+/*****************************************************************************
+ *
+ * Module: __RTW_MP_PHY_REGDEF_H_
+ *
+ *
+ * Note: 1. Define PMAC/BB register map
+ * 2. Define RF register map
+ * 3. PMAC/BB register bit mask.
+ * 4. RF reg bit mask.
+ * 5. Other BB/RF relative definition.
+ *
+ *
+ * Export: Constants, macro, functions(API), global variables(None).
+ *
+ * Abbrev:
+ *
+ * History:
+ * Data Who Remark
+ * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h.
+ * 2. Reorganize code architecture.
+ * 09/25/2008 MH 1. Add RL6052 register definition
+ *
+ *****************************************************************************/
+#ifndef __RTW_MP_PHY_REGDEF_H_
+#define __RTW_MP_PHY_REGDEF_H_
+
+
+/*--------------------------Define Parameters-------------------------------*/
+
+/* */
+/* 8192S Regsiter offset definition */
+/* */
+
+/* */
+/* BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF */
+/* 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */
+/* 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 */
+/* 3. RF register 0x00-2E */
+/* 4. Bit Mask for BB/RF register */
+/* 5. Other defintion for BB/RF R/W */
+/* */
+
+
+/* */
+/* 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */
+/* 1. Page1(0x100) */
+/* */
+#define rPMAC_Reset 0x100
+#define rPMAC_TxStart 0x104
+#define rPMAC_TxLegacySIG 0x108
+#define rPMAC_TxHTSIG1 0x10c
+#define rPMAC_TxHTSIG2 0x110
+#define rPMAC_PHYDebug 0x114
+#define rPMAC_TxPacketNum 0x118
+#define rPMAC_TxIdle 0x11c
+#define rPMAC_TxMACHeader0 0x120
+#define rPMAC_TxMACHeader1 0x124
+#define rPMAC_TxMACHeader2 0x128
+#define rPMAC_TxMACHeader3 0x12c
+#define rPMAC_TxMACHeader4 0x130
+#define rPMAC_TxMACHeader5 0x134
+#define rPMAC_TxDataType 0x138
+#define rPMAC_TxRandomSeed 0x13c
+#define rPMAC_CCKPLCPPreamble 0x140
+#define rPMAC_CCKPLCPHeader 0x144
+#define rPMAC_CCKCRC16 0x148
+#define rPMAC_OFDMRxCRC32OK 0x170
+#define rPMAC_OFDMRxCRC32Er 0x174
+#define rPMAC_OFDMRxParityEr 0x178
+#define rPMAC_OFDMRxCRC8Er 0x17c
+#define rPMAC_CCKCRxRC16Er 0x180
+#define rPMAC_CCKCRxRC32Er 0x184
+#define rPMAC_CCKCRxRC32OK 0x188
+#define rPMAC_TxStatus 0x18c
+
+/* */
+/* 2. Page2(0x200) */
+/* */
+/* The following two definition are only used for USB interface. */
+/* define RF_BB_CMD_ADDR 0x02c0 RF/BB read/write command address. */
+/* define RF_BB_CMD_DATA 0x02c4 RF/BB read/write command data. */
+
+/* */
+/* 3. Page8(0x800) */
+/* */
+#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC RF BW Setting?? */
+
+#define rFPGA0_TxInfo 0x804 /* Status report?? */
+#define rFPGA0_PSDFunction 0x808
+
+#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */
+
+#define rFPGA0_RFTiming1 0x810 /* Useless now */
+#define rFPGA0_RFTiming2 0x814
+/* define rFPGA0_XC_RFTiming 0x818 */
+/* define rFPGA0_XD_RFTiming 0x81c */
+
+#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */
+#define rFPGA0_XA_HSSIParameter2 0x824
+#define rFPGA0_XB_HSSIParameter1 0x828
+#define rFPGA0_XB_HSSIParameter2 0x82c
+#define rFPGA0_XC_HSSIParameter1 0x830
+#define rFPGA0_XC_HSSIParameter2 0x834
+#define rFPGA0_XD_HSSIParameter1 0x838
+#define rFPGA0_XD_HSSIParameter2 0x83c
+#define rFPGA0_XA_LSSIParameter 0x840
+#define rFPGA0_XB_LSSIParameter 0x844
+#define rFPGA0_XC_LSSIParameter 0x848
+#define rFPGA0_XD_LSSIParameter 0x84c
+
+#define rFPGA0_RFWakeUpParameter 0x850 /* Useless now */
+#define rFPGA0_RFSleepUpParameter 0x854
+
+#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */
+#define rFPGA0_XCD_SwitchControl 0x85c
+
+#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */
+#define rFPGA0_XB_RFInterfaceOE 0x864
+#define rFPGA0_XC_RFInterfaceOE 0x868
+#define rFPGA0_XD_RFInterfaceOE 0x86c
+
+#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Interface Software Control */
+#define rFPGA0_XCD_RFInterfaceSW 0x874
+
+#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */
+#define rFPGA0_XCD_RFParameter 0x87c
+
+#define rFPGA0_AnalogParameter1 0x880 /* Crystal cap setting RF-R/W protection for parameter4?? */
+#define rFPGA0_AnalogParameter2 0x884
+#define rFPGA0_AnalogParameter3 0x888 /* Useless now */
+#define rFPGA0_AnalogParameter4 0x88c
+
+#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Tranceiver LSSI Readback */
+#define rFPGA0_XB_LSSIReadBack 0x8a4
+#define rFPGA0_XC_LSSIReadBack 0x8a8
+#define rFPGA0_XD_LSSIReadBack 0x8ac
+
+#define rFPGA0_PSDReport 0x8b4 /* Useless now */
+#define rFPGA0_XAB_RFInterfaceRB 0x8e0 /* Useless now RF Interface Readback Value */
+#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Useless now */
+
+/* */
+/* 4. Page9(0x900) */
+/* */
+#define rFPGA1_RFMOD 0x900 /* RF mode & OFDM TxSC RF BW Setting?? */
+
+#define rFPGA1_TxBlock 0x904 /* Useless now */
+#define rFPGA1_DebugSelect 0x908 /* Useless now */
+#define rFPGA1_TxInfo 0x90c /* Useless now Status report?? */
+
+/* */
+/* 5. PageA(0xA00) */
+/* */
+/* Set Control channel to upper or lower. These settings are required only for 40MHz */
+#define rCCK0_System 0xa00
+
+#define rCCK0_AFESetting 0xa04 /* Disable init gain now Select RX path by RSSI */
+#define rCCK0_CCA 0xa08 /* Disable init gain now Init gain */
+
+#define rCCK0_RxAGC1 0xa0c /* AGC default value, saturation level Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series */
+#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */
+
+#define rCCK0_RxHP 0xa14
+
+#define rCCK0_DSPParameter1 0xa18 /* Timing recovery & Channel estimation threshold */
+#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */
+
+#define rCCK0_TxFilter1 0xa20
+#define rCCK0_TxFilter2 0xa24
+#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */
+#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now 0xa30-a4f channel report */
+#define rCCK0_TRSSIReport 0xa50
+#define rCCK0_RxReport 0xa54 /* 0xa57 */
+#define rCCK0_FACounterLower 0xa5c /* 0xa5b */
+#define rCCK0_FACounterUpper 0xa58 /* 0xa5c */
+
+/* */
+/* 6. PageC(0xC00) */
+/* */
+#define rOFDM0_LSTF 0xc00
+
+#define rOFDM0_TRxPathEnable 0xc04
+#define rOFDM0_TRMuxPar 0xc08
+#define rOFDM0_TRSWIsolation 0xc0c
+
+#define rOFDM0_XARxAFE 0xc10 /* RxIQ DC offset, Rx digital filter, DC notch filter */
+#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */
+#define rOFDM0_XBRxAFE 0xc18
+#define rOFDM0_XBRxIQImbalance 0xc1c
+#define rOFDM0_XCRxAFE 0xc20
+#define rOFDM0_XCRxIQImbalance 0xc24
+#define rOFDM0_XDRxAFE 0xc28
+#define rOFDM0_XDRxIQImbalance 0xc2c
+
+#define rOFDM0_RxDetector1 0xc30 /* PD,BW & SBD DM tune init gain */
+#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */
+#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */
+#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & Short-GI */
+
+#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */
+#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */
+#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */
+#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */
+
+#define rOFDM0_XAAGCCore1 0xc50 /* DIG */
+#define rOFDM0_XAAGCCore2 0xc54
+#define rOFDM0_XBAGCCore1 0xc58
+#define rOFDM0_XBAGCCore2 0xc5c
+#define rOFDM0_XCAGCCore1 0xc60
+#define rOFDM0_XCAGCCore2 0xc64
+#define rOFDM0_XDAGCCore1 0xc68
+#define rOFDM0_XDAGCCore2 0xc6c
+
+#define rOFDM0_AGCParameter1 0xc70
+#define rOFDM0_AGCParameter2 0xc74
+#define rOFDM0_AGCRSSITable 0xc78
+#define rOFDM0_HTSTFAGC 0xc7c
+
+#define rOFDM0_XATxIQImbalance 0xc80 /* TX PWR TRACK and DIG */
+#define rOFDM0_XATxAFE 0xc84
+#define rOFDM0_XBTxIQImbalance 0xc88
+#define rOFDM0_XBTxAFE 0xc8c
+#define rOFDM0_XCTxIQImbalance 0xc90
+#define rOFDM0_XCTxAFE 0xc94
+#define rOFDM0_XDTxIQImbalance 0xc98
+#define rOFDM0_XDTxAFE 0xc9c
+#define rOFDM0_RxIQExtAnta 0xca0
+
+#define rOFDM0_RxHPParameter 0xce0
+#define rOFDM0_TxPseudoNoiseWgt 0xce4
+#define rOFDM0_FrameSync 0xcf0
+#define rOFDM0_DFSReport 0xcf4
+#define rOFDM0_TxCoeff1 0xca4
+#define rOFDM0_TxCoeff2 0xca8
+#define rOFDM0_TxCoeff3 0xcac
+#define rOFDM0_TxCoeff4 0xcb0
+#define rOFDM0_TxCoeff5 0xcb4
+#define rOFDM0_TxCoeff6 0xcb8
+
+/* 7. PageD(0xD00) */
+#define rOFDM1_LSTF 0xd00
+#define rOFDM1_TRxPathEnable 0xd04
+
+#define rOFDM1_CFO 0xd08 /* No setting now */
+#define rOFDM1_CSI1 0xd10
+#define rOFDM1_SBD 0xd14
+#define rOFDM1_CSI2 0xd18
+#define rOFDM1_CFOTracking 0xd2c
+#define rOFDM1_TRxMesaure1 0xd34
+#define rOFDM1_IntfDet 0xd3c
+#define rOFDM1_PseudoNoiseStateAB 0xd50
+#define rOFDM1_PseudoNoiseStateCD 0xd54
+#define rOFDM1_RxPseudoNoiseWgt 0xd58
+
+#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */
+#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */
+#define rOFDM_PHYCounter3 0xda8 /* MCS not support */
+
+#define rOFDM_ShortCFOAB 0xdac /* No setting now */
+#define rOFDM_ShortCFOCD 0xdb0
+#define rOFDM_LongCFOAB 0xdb4
+#define rOFDM_LongCFOCD 0xdb8
+#define rOFDM_TailCFOAB 0xdbc
+#define rOFDM_TailCFOCD 0xdc0
+#define rOFDM_PWMeasure1 0xdc4
+#define rOFDM_PWMeasure2 0xdc8
+#define rOFDM_BWReport 0xdcc
+#define rOFDM_AGCReport 0xdd0
+#define rOFDM_RxSNR 0xdd4
+#define rOFDM_RxEVMCSI 0xdd8
+#define rOFDM_SIGReport 0xddc
+
+
+/* */
+/* 8. PageE(0xE00) */
+/* */
+#define rTxAGC_Rate18_06 0xe00
+#define rTxAGC_Rate54_24 0xe04
+#define rTxAGC_CCK_Mcs32 0xe08
+#define rTxAGC_Mcs03_Mcs00 0xe10
+#define rTxAGC_Mcs07_Mcs04 0xe14
+#define rTxAGC_Mcs11_Mcs08 0xe18
+#define rTxAGC_Mcs15_Mcs12 0xe1c
+
+/* Analog- control in RX_WAIT_CCA : REG: EE0 [Analog- Power & Control Register] */
+#define rRx_Wait_CCCA 0xe70
+#define rAnapar_Ctrl_BB 0xee0
+
+/* */
+/* 7. RF Register 0x00-0x2E (RF 8256) */
+/* RF-0222D 0x00-3F */
+/* */
+/* Zebra1 */
+#define RTL92SE_FPGA_VERIFY 0
+#define rZebra1_HSSIEnable 0x0 /* Useless now */
+#define rZebra1_TRxEnable1 0x1
+#define rZebra1_TRxEnable2 0x2
+#define rZebra1_AGC 0x4
+#define rZebra1_ChargePump 0x5
+/* if (RTL92SE_FPGA_VERIFY == 1) */
+#define rZebra1_Channel 0x7 /* RF channel switch */
+/* else */
+
+/* endif */
+#define rZebra1_TxGain 0x8 /* Useless now */
+#define rZebra1_TxLPF 0x9
+#define rZebra1_RxLPF 0xb
+#define rZebra1_RxHPFCorner 0xc
+
+/* Zebra4 */
+#define rGlobalCtrl 0 /* Useless now */
+#define rRTL8256_TxLPF 19
+#define rRTL8256_RxLPF 11
+
+/* RTL8258 */
+#define rRTL8258_TxLPF 0x11 /* Useless now */
+#define rRTL8258_RxLPF 0x13
+#define rRTL8258_RSSILPF 0xa
+
+/* */
+/* RL6052 Register definition */
+#define RF_AC 0x00 /* */
+
+#define RF_IQADJ_G1 0x01 /* */
+#define RF_IQADJ_G2 0x02 /* */
+#define RF_POW_TRSW 0x05 /* */
+
+#define RF_GAIN_RX 0x06 /* */
+#define RF_GAIN_TX 0x07 /* */
+
+#define RF_TXM_IDAC 0x08 /* */
+#define RF_BS_IQGEN 0x0F /* */
+
+#define RF_MODE1 0x10 /* */
+#define RF_MODE2 0x11 /* */
+
+#define RF_RX_AGC_HP 0x12 /* */
+#define RF_TX_AGC 0x13 /* */
+#define RF_BIAS 0x14 /* */
+#define RF_IPA 0x15 /* */
+#define RF_TXBIAS 0x16 /* */
+#define RF_POW_ABILITY 0x17 /* */
+#define RF_MODE_AG 0x18 /* */
+#define rRfChannel 0x18 /* RF channel and BW switch */
+#define RF_CHNLBW 0x18 /* RF channel and BW switch */
+#define RF_TOP 0x19 /* */
+
+#define RF_RX_G1 0x1A /* */
+#define RF_RX_G2 0x1B /* */
+
+#define RF_RX_BB2 0x1C /* */
+#define RF_RX_BB1 0x1D /* */
+
+#define RF_RCK1 0x1E /* */
+#define RF_RCK2 0x1F /* */
+
+#define RF_TX_G1 0x20 /* */
+#define RF_TX_G2 0x21 /* */
+#define RF_TX_G3 0x22 /* */
+
+#define RF_TX_BB1 0x23 /* */
+
+#define RF_T_METER 0x24 /* */
+
+#define RF_SYN_G1 0x25 /* RF TX Power control */
+#define RF_SYN_G2 0x26 /* RF TX Power control */
+#define RF_SYN_G3 0x27 /* RF TX Power control */
+#define RF_SYN_G4 0x28 /* RF TX Power control */
+#define RF_SYN_G5 0x29 /* RF TX Power control */
+#define RF_SYN_G6 0x2A /* RF TX Power control */
+#define RF_SYN_G7 0x2B /* RF TX Power control */
+#define RF_SYN_G8 0x2C /* RF TX Power control */
+
+#define RF_RCK_OS 0x30 /* RF TX PA control */
+#define RF_TXPA_G1 0x31 /* RF TX PA control */
+#define RF_TXPA_G2 0x32 /* RF TX PA control */
+#define RF_TXPA_G3 0x33 /* RF TX PA control */
+
+/* */
+/* Bit Mask */
+/* */
+/* 1. Page1(0x100) */
+#define bBBResetB 0x100 /* Useless now? */
+#define bGlobalResetB 0x200
+#define bOFDMTxStart 0x4
+#define bCCKTxStart 0x8
+#define bCRC32Debug 0x100
+#define bPMACLoopback 0x10
+#define bTxLSIG 0xffffff
+#define bOFDMTxRate 0xf
+#define bOFDMTxReserved 0x10
+#define bOFDMTxLength 0x1ffe0
+#define bOFDMTxParity 0x20000
+#define bTxHTSIG1 0xffffff
+#define bTxHTMCSRate 0x7f
+#define bTxHTBW 0x80
+#define bTxHTLength 0xffff00
+#define bTxHTSIG2 0xffffff
+#define bTxHTSmoothing 0x1
+#define bTxHTSounding 0x2
+#define bTxHTReserved 0x4
+#define bTxHTAggreation 0x8
+#define bTxHTSTBC 0x30
+#define bTxHTAdvanceCoding 0x40
+#define bTxHTShortGI 0x80
+#define bTxHTNumberHT_LTF 0x300
+#define bTxHTCRC8 0x3fc00
+#define bCounterReset 0x10000
+#define bNumOfOFDMTx 0xffff
+#define bNumOfCCKTx 0xffff0000
+#define bTxIdleInterval 0xffff
+#define bOFDMService 0xffff0000
+#define bTxMACHeader 0xffffffff
+#define bTxDataInit 0xff
+#define bTxHTMode 0x100
+#define bTxDataType 0x30000
+#define bTxRandomSeed 0xffffffff
+#define bCCKTxPreamble 0x1
+#define bCCKTxSFD 0xffff0000
+#define bCCKTxSIG 0xff
+#define bCCKTxService 0xff00
+#define bCCKLengthExt 0x8000
+#define bCCKTxLength 0xffff0000
+#define bCCKTxCRC16 0xffff
+#define bCCKTxStatus 0x1
+#define bOFDMTxStatus 0x2
+
+#define IS_BB_REG_OFFSET_92S(_Offset) ((_Offset >= 0x800) && (_Offset <= 0xfff))
+
+/* 2. Page8(0x800) */
+#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */
+#define bJapanMode 0x2
+#define bCCKTxSC 0x30
+#define bCCKEn 0x1000000
+#define bOFDMEn 0x2000000
+
+#define bOFDMRxADCPhase 0x10000 /* Useless now */
+#define bOFDMTxDACPhase 0x40000
+#define bXATxAGC 0x3f
+
+#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */
+#define bXCTxAGC 0xf000
+#define bXDTxAGC 0xf0000
+
+#define bPAStart 0xf0000000 /* Useless now */
+#define bTRStart 0x00f00000
+#define bRFStart 0x0000f000
+#define bBBStart 0x000000f0
+#define bBBCCKStart 0x0000000f
+#define bPAEnd 0xf /* Reg0x814 */
+#define bTREnd 0x0f000000
+#define bRFEnd 0x000f0000
+#define bCCAMask 0x000000f0 /* T2R */
+#define bR2RCCAMask 0x00000f00
+#define bHSSI_R2TDelay 0xf8000000
+#define bHSSI_T2RDelay 0xf80000
+#define bContTxHSSI 0x400 /* chane gain at continue Tx */
+#define bIGFromCCK 0x200
+#define bAGCAddress 0x3f
+#define bRxHPTx 0x7000
+#define bRxHPT2R 0x38000
+#define bRxHPCCKIni 0xc0000
+#define bAGCTxCode 0xc00000
+#define bAGCRxCode 0x300000
+
+#define b3WireDataLength 0x800 /* Reg 0x820~84f rFPGA0_XA_HSSIParameter1 */
+#define b3WireAddressLength 0x400
+
+#define b3WireRFPowerDown 0x1 /* Useless now */
+/* define bHWSISelect 0x8 */
+#define b5GPAPEPolarity 0x40000000
+#define b2GPAPEPolarity 0x80000000
+#define bRFSW_TxDefaultAnt 0x3
+#define bRFSW_TxOptionAnt 0x30
+#define bRFSW_RxDefaultAnt 0x300
+#define bRFSW_RxOptionAnt 0x3000
+#define bRFSI_3WireData 0x1
+#define bRFSI_3WireClock 0x2
+#define bRFSI_3WireLoad 0x4
+#define bRFSI_3WireRW 0x8
+#define bRFSI_3Wire 0xf
+
+#define bRFSI_RFENV 0x10 /* Reg 0x870 rFPGA0_XAB_RFInterfaceSW */
+
+#define bRFSI_TRSW 0x20 /* Useless now */
+#define bRFSI_TRSWB 0x40
+#define bRFSI_ANTSW 0x100
+#define bRFSI_ANTSWB 0x200
+#define bRFSI_PAPE 0x400
+#define bRFSI_PAPE5G 0x800
+#define bBandSelect 0x1
+#define bHTSIG2_GI 0x80
+#define bHTSIG2_Smoothing 0x01
+#define bHTSIG2_Sounding 0x02
+#define bHTSIG2_Aggreaton 0x08
+#define bHTSIG2_STBC 0x30
+#define bHTSIG2_AdvCoding 0x40
+#define bHTSIG2_NumOfHTLTF 0x300
+#define bHTSIG2_CRC8 0x3fc
+#define bHTSIG1_MCS 0x7f
+#define bHTSIG1_BandWidth 0x80
+#define bHTSIG1_HTLength 0xffff
+#define bLSIG_Rate 0xf
+#define bLSIG_Reserved 0x10
+#define bLSIG_Length 0x1fffe
+#define bLSIG_Parity 0x20
+#define bCCKRxPhase 0x4
+#if (RTL92SE_FPGA_VERIFY == 1)
+#define bLSSIReadAddress 0x3f000000 /* LSSI "Read" Address
+ Reg 0x824 rFPGA0_XA_HSSIParameter2 */
+#else
+#define bLSSIReadAddress 0x7f800000 /* T65 RF */
+#endif
+#define bLSSIReadEdge 0x80000000 /* LSSI "Read" edge signal */
+#if (RTL92SE_FPGA_VERIFY == 1)
+#define bLSSIReadBackData 0xfff /* Reg 0x8a0
+ rFPGA0_XA_LSSIReadBack */
+#else
+#define bLSSIReadBackData 0xfffff /* T65 RF */
+#endif
+#define bLSSIReadOKFlag 0x1000 /* Useless now */
+#define bCCKSampleRate 0x8 /* 0: 44MHz, 1:88MHz */
+#define bRegulator0Standby 0x1
+#define bRegulatorPLLStandby 0x2
+#define bRegulator1Standby 0x4
+#define bPLLPowerUp 0x8
+#define bDPLLPowerUp 0x10
+#define bDA10PowerUp 0x20
+#define bAD7PowerUp 0x200
+#define bDA6PowerUp 0x2000
+#define bXtalPowerUp 0x4000
+#define b40MDClkPowerUP 0x8000
+#define bDA6DebugMode 0x20000
+#define bDA6Swing 0x380000
+
+#define bADClkPhase 0x4000000 /* Reg 0x880
+ rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */
+
+#define b80MClkDelay 0x18000000 /* Useless */
+#define bAFEWatchDogEnable 0x20000000
+
+#define bXtalCap01 0xc0000000 /* Reg 0x884
+ rFPGA0_AnalogParameter2 Crystal cap */
+#define bXtalCap23 0x3
+#define bXtalCap92x 0x0f000000
+#define bXtalCap 0x0f000000
+
+#define bIntDifClkEnable 0x400 /* Useless */
+#define bExtSigClkEnable 0x800
+#define bBandgapMbiasPowerUp 0x10000
+#define bAD11SHGain 0xc0000
+#define bAD11InputRange 0x700000
+#define bAD11OPCurrent 0x3800000
+#define bIPathLoopback 0x4000000
+#define bQPathLoopback 0x8000000
+#define bAFELoopback 0x10000000
+#define bDA10Swing 0x7e0
+#define bDA10Reverse 0x800
+#define bDAClkSource 0x1000
+#define bAD7InputRange 0x6000
+#define bAD7Gain 0x38000
+#define bAD7OutputCMMode 0x40000
+#define bAD7InputCMMode 0x380000
+#define bAD7Current 0xc00000
+#define bRegulatorAdjust 0x7000000
+#define bAD11PowerUpAtTx 0x1
+#define bDA10PSAtTx 0x10
+#define bAD11PowerUpAtRx 0x100
+#define bDA10PSAtRx 0x1000
+#define bCCKRxAGCFormat 0x200
+#define bPSDFFTSamplepPoint 0xc000
+#define bPSDAverageNum 0x3000
+#define bIQPathControl 0xc00
+#define bPSDFreq 0x3ff
+#define bPSDAntennaPath 0x30
+#define bPSDIQSwitch 0x40
+#define bPSDRxTrigger 0x400000
+#define bPSDTxTrigger 0x80000000
+#define bPSDSineToneScale 0x7f000000
+#define bPSDReport 0xffff
+
+/* 3. Page9(0x900) */
+#define bOFDMTxSC 0x30000000 /* Useless */
+#define bCCKTxOn 0x1
+#define bOFDMTxOn 0x2
+#define bDebugPage 0xfff /* reset debug page and HWord,
+ * LWord */
+#define bDebugItem 0xff /* reset debug page and LWord */
+#define bAntL 0x10
+#define bAntNonHT 0x100
+#define bAntHT1 0x1000
+#define bAntHT2 0x10000
+#define bAntHT1S1 0x100000
+#define bAntNonHTS1 0x1000000
+
+/* 4. PageA(0xA00) */
+#define bCCKBBMode 0x3 /* Useless */
+#define bCCKTxPowerSaving 0x80
+#define bCCKRxPowerSaving 0x40
+
+#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0 20/40 sw */
+
+#define bCCKScramble 0x8 /* Useless */
+#define bCCKAntDiversity 0x8000
+#define bCCKCarrierRecovery 0x4000
+#define bCCKTxRate 0x3000
+#define bCCKDCCancel 0x0800
+#define bCCKISICancel 0x0400
+#define bCCKMatchFilter 0x0200
+#define bCCKEqualizer 0x0100
+#define bCCKPreambleDetect 0x800000
+#define bCCKFastFalseCCA 0x400000
+#define bCCKChEstStart 0x300000
+#define bCCKCCACount 0x080000
+#define bCCKcs_lim 0x070000
+#define bCCKBistMode 0x80000000
+#define bCCKCCAMask 0x40000000
+#define bCCKTxDACPhase 0x4
+#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */
+#define bCCKr_cp_mode0 0x0100
+#define bCCKTxDCOffset 0xf0
+#define bCCKRxDCOffset 0xf
+#define bCCKCCAMode 0xc000
+#define bCCKFalseCS_lim 0x3f00
+#define bCCKCS_ratio 0xc00000
+#define bCCKCorgBit_sel 0x300000
+#define bCCKPD_lim 0x0f0000
+#define bCCKNewCCA 0x80000000
+#define bCCKRxHPofIG 0x8000
+#define bCCKRxIG 0x7f00
+#define bCCKLNAPolarity 0x800000
+#define bCCKRx1stGain 0x7f0000
+#define bCCKRFExtend 0x20000000 /* CCK Rx init gain polar */
+#define bCCKRxAGCSatLevel 0x1f000000
+#define bCCKRxAGCSatCount 0xe0
+#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */
+#define bCCKFixedRxAGC 0x8000
+#define bCCKAntennaPolarity 0x2000
+#define bCCKTxFilterType 0x0c00
+#define bCCKRxAGCReportType 0x0300
+#define bCCKRxDAGCEn 0x80000000
+#define bCCKRxDAGCPeriod 0x20000000
+#define bCCKRxDAGCSatLevel 0x1f000000
+#define bCCKTimingRecovery 0x800000
+#define bCCKTxC0 0x3f0000
+#define bCCKTxC1 0x3f000000
+#define bCCKTxC2 0x3f
+#define bCCKTxC3 0x3f00
+#define bCCKTxC4 0x3f0000
+#define bCCKTxC5 0x3f000000
+#define bCCKTxC6 0x3f
+#define bCCKTxC7 0x3f00
+#define bCCKDebugPort 0xff0000
+#define bCCKDACDebug 0x0f000000
+#define bCCKFalseAlarmEnable 0x8000
+#define bCCKFalseAlarmRead 0x4000
+#define bCCKTRSSI 0x7f
+#define bCCKRxAGCReport 0xfe
+#define bCCKRxReport_AntSel 0x80000000
+#define bCCKRxReport_MFOff 0x40000000
+#define bCCKRxRxReport_SQLoss 0x20000000
+#define bCCKRxReport_Pktloss 0x10000000
+#define bCCKRxReport_Lockedbit 0x08000000
+#define bCCKRxReport_RateError 0x04000000
+#define bCCKRxReport_RxRate 0x03000000
+#define bCCKRxFACounterLower 0xff
+#define bCCKRxFACounterUpper 0xff000000
+#define bCCKRxHPAGCStart 0xe000
+#define bCCKRxHPAGCFinal 0x1c00
+#define bCCKRxFalseAlarmEnable 0x8000
+#define bCCKFACounterFreeze 0x4000
+#define bCCKTxPathSel 0x10000000
+#define bCCKDefaultRxPath 0xc000000
+#define bCCKOptionRxPath 0x3000000
+
+/* 5. PageC(0xC00) */
+#define bNumOfSTF 0x3 /* Useless */
+#define bShift_L 0xc0
+#define bGI_TH 0xc
+#define bRxPathA 0x1
+#define bRxPathB 0x2
+#define bRxPathC 0x4
+#define bRxPathD 0x8
+#define bTxPathA 0x1
+#define bTxPathB 0x2
+#define bTxPathC 0x4
+#define bTxPathD 0x8
+#define bTRSSIFreq 0x200
+#define bADCBackoff 0x3000
+#define bDFIRBackoff 0xc000
+#define bTRSSILatchPhase 0x10000
+#define bRxIDCOffset 0xff
+#define bRxQDCOffset 0xff00
+#define bRxDFIRMode 0x1800000
+#define bRxDCNFType 0xe000000
+#define bRXIQImb_A 0x3ff
+#define bRXIQImb_B 0xfc00
+#define bRXIQImb_C 0x3f0000
+#define bRXIQImb_D 0xffc00000
+#define bDC_dc_Notch 0x60000
+#define bRxNBINotch 0x1f000000
+#define bPD_TH 0xf
+#define bPD_TH_Opt2 0xc000
+#define bPWED_TH 0x700
+#define bIfMF_Win_L 0x800
+#define bPD_Option 0x1000
+#define bMF_Win_L 0xe000
+#define bBW_Search_L 0x30000
+#define bwin_enh_L 0xc0000
+#define bBW_TH 0x700000
+#define bED_TH2 0x3800000
+#define bBW_option 0x4000000
+#define bRatio_TH 0x18000000
+#define bWindow_L 0xe0000000
+#define bSBD_Option 0x1
+#define bFrame_TH 0x1c
+#define bFS_Option 0x60
+#define bDC_Slope_check 0x80
+#define bFGuard_Counter_DC_L 0xe00
+#define bFrame_Weight_Short 0x7000
+#define bSub_Tune 0xe00000
+#define bFrame_DC_Length 0xe000000
+#define bSBD_start_offset 0x30000000
+#define bFrame_TH_2 0x7
+#define bFrame_GI2_TH 0x38
+#define bGI2_Sync_en 0x40
+#define bSarch_Short_Early 0x300
+#define bSarch_Short_Late 0xc00
+#define bSarch_GI2_Late 0x70000
+#define bCFOAntSum 0x1
+#define bCFOAcc 0x2
+#define bCFOStartOffset 0xc
+#define bCFOLookBack 0x70
+#define bCFOSumWeight 0x80
+#define bDAGCEnable 0x10000
+#define bTXIQImb_A 0x3ff
+#define bTXIQImb_B 0xfc00
+#define bTXIQImb_C 0x3f0000
+#define bTXIQImb_D 0xffc00000
+#define bTxIDCOffset 0xff
+#define bTxQDCOffset 0xff00
+#define bTxDFIRMode 0x10000
+#define bTxPesudoNoiseOn 0x4000000
+#define bTxPesudoNoise_A 0xff
+#define bTxPesudoNoise_B 0xff00
+#define bTxPesudoNoise_C 0xff0000
+#define bTxPesudoNoise_D 0xff000000
+#define bCCADropOption 0x20000
+#define bCCADropThres 0xfff00000
+#define bEDCCA_H 0xf
+#define bEDCCA_L 0xf0
+#define bLambda_ED 0x300
+#define bRxInitialGain 0x7f
+#define bRxAntDivEn 0x80
+#define bRxAGCAddressForLNA 0x7f00
+#define bRxHighPowerFlow 0x8000
+#define bRxAGCFreezeThres 0xc0000
+#define bRxFreezeStep_AGC1 0x300000
+#define bRxFreezeStep_AGC2 0xc00000
+#define bRxFreezeStep_AGC3 0x3000000
+#define bRxFreezeStep_AGC0 0xc000000
+#define bRxRssi_Cmp_En 0x10000000
+#define bRxQuickAGCEn 0x20000000
+#define bRxAGCFreezeThresMode 0x40000000
+#define bRxOverFlowCheckType 0x80000000
+#define bRxAGCShift 0x7f
+#define bTRSW_Tri_Only 0x80
+#define bPowerThres 0x300
+#define bRxAGCEn 0x1
+#define bRxAGCTogetherEn 0x2
+#define bRxAGCMin 0x4
+#define bRxHP_Ini 0x7
+#define bRxHP_TRLNA 0x70
+#define bRxHP_RSSI 0x700
+#define bRxHP_BBP1 0x7000
+#define bRxHP_BBP2 0x70000
+#define bRxHP_BBP3 0x700000
+#define bRSSI_H 0x7f0000 /* thresh for hi power */
+#define bRSSI_Gen 0x7f000000 /* thresh for ant div */
+#define bRxSettle_TRSW 0x7
+#define bRxSettle_LNA 0x38
+#define bRxSettle_RSSI 0x1c0
+#define bRxSettle_BBP 0xe00
+#define bRxSettle_RxHP 0x7000
+#define bRxSettle_AntSW_RSSI 0x38000
+#define bRxSettle_AntSW 0xc0000
+#define bRxProcessTime_DAGC 0x300000
+#define bRxSettle_HSSI 0x400000
+#define bRxProcessTime_BBPPW 0x800000
+#define bRxAntennaPowerShift 0x3000000
+#define bRSSITableSelect 0xc000000
+#define bRxHP_Final 0x7000000
+#define bRxHTSettle_BBP 0x7
+#define bRxHTSettle_HSSI 0x8
+#define bRxHTSettle_RxHP 0x70
+#define bRxHTSettle_BBPPW 0x80
+#define bRxHTSettle_Idle 0x300
+#define bRxHTSettle_Reserved 0x1c00
+#define bRxHTRxHPEn 0x8000
+#define bRxHTAGCFreezeThres 0x30000
+#define bRxHTAGCTogetherEn 0x40000
+#define bRxHTAGCMin 0x80000
+#define bRxHTAGCEn 0x100000
+#define bRxHTDAGCEn 0x200000
+#define bRxHTRxHP_BBP 0x1c00000
+#define bRxHTRxHP_Final 0xe0000000
+#define bRxPWRatioTH 0x3
+#define bRxPWRatioEn 0x4
+#define bRxMFHold 0x3800
+#define bRxPD_Delay_TH1 0x38
+#define bRxPD_Delay_TH2 0x1c0
+#define bRxPD_DC_COUNT_MAX 0x600
+/* define bRxMF_Hold 0x3800 */
+#define bRxPD_Delay_TH 0x8000
+#define bRxProcess_Delay 0xf0000
+#define bRxSearchrange_GI2_Early 0x700000
+#define bRxFrame_Guard_Counter_L 0x3800000
+#define bRxSGI_Guard_L 0xc000000
+#define bRxSGI_Search_L 0x30000000
+#define bRxSGI_TH 0xc0000000
+#define bDFSCnt0 0xff
+#define bDFSCnt1 0xff00
+#define bDFSFlag 0xf0000
+#define bMFWeightSum 0x300000
+#define bMinIdxTH 0x7f000000
+#define bDAFormat 0x40000
+#define bTxChEmuEnable 0x01000000
+#define bTRSWIsolation_A 0x7f
+#define bTRSWIsolation_B 0x7f00
+#define bTRSWIsolation_C 0x7f0000
+#define bTRSWIsolation_D 0x7f000000
+#define bExtLNAGain 0x7c00
+
+/* 6. PageE(0xE00) */
+#define bSTBCEn 0x4 /* Useless */
+#define bAntennaMapping 0x10
+#define bNss 0x20
+#define bCFOAntSumD 0x200
+#define bPHYCounterReset 0x8000000
+#define bCFOReportGet 0x4000000
+#define bOFDMContinueTx 0x10000000
+#define bOFDMSingleCarrier 0x20000000
+#define bOFDMSingleTone 0x40000000
+/* define bRxPath1 0x01 */
+/* define bRxPath2 0x02 */
+/* define bRxPath3 0x04 */
+/* define bRxPath4 0x08 */
+/* define bTxPath1 0x10 */
+/* define bTxPath2 0x20 */
+#define bHTDetect 0x100
+#define bCFOEn 0x10000
+#define bCFOValue 0xfff00000
+#define bSigTone_Re 0x3f
+#define bSigTone_Im 0x7f00
+#define bCounter_CCA 0xffff
+#define bCounter_ParityFail 0xffff0000
+#define bCounter_RateIllegal 0xffff
+#define bCounter_CRC8Fail 0xffff0000
+#define bCounter_MCSNoSupport 0xffff
+#define bCounter_FastSync 0xffff
+#define bShortCFO 0xfff
+#define bShortCFOTLength 12 /* total */
+#define bShortCFOFLength 11 /* fraction */
+#define bLongCFO 0x7ff
+#define bLongCFOTLength 11
+#define bLongCFOFLength 11
+#define bTailCFO 0x1fff
+#define bTailCFOTLength 13
+#define bTailCFOFLength 12
+#define bmax_en_pwdB 0xffff
+#define bCC_power_dB 0xffff0000
+#define bnoise_pwdB 0xffff
+#define bPowerMeasTLength 10
+#define bPowerMeasFLength 3
+#define bRx_HT_BW 0x1
+#define bRxSC 0x6
+#define bRx_HT 0x8
+#define bNB_intf_det_on 0x1
+#define bIntf_win_len_cfg 0x30
+#define bNB_Intf_TH_cfg 0x1c0
+#define bRFGain 0x3f
+#define bTableSel 0x40
+#define bTRSW 0x80
+#define bRxSNR_A 0xff
+#define bRxSNR_B 0xff00
+#define bRxSNR_C 0xff0000
+#define bRxSNR_D 0xff000000
+#define bSNREVMTLength 8
+#define bSNREVMFLength 1
+#define bCSI1st 0xff
+#define bCSI2nd 0xff00
+#define bRxEVM1st 0xff0000
+#define bRxEVM2nd 0xff000000
+#define bSIGEVM 0xff
+#define bPWDB 0xff00
+#define bSGIEN 0x10000
+
+#define bSFactorQAM1 0xf /* Useless */
+#define bSFactorQAM2 0xf0
+#define bSFactorQAM3 0xf00
+#define bSFactorQAM4 0xf000
+#define bSFactorQAM5 0xf0000
+#define bSFactorQAM6 0xf0000
+#define bSFactorQAM7 0xf00000
+#define bSFactorQAM8 0xf000000
+#define bSFactorQAM9 0xf0000000
+#define bCSIScheme 0x100000
+
+#define bNoiseLvlTopSet 0x3 /* Useless */
+#define bChSmooth 0x4
+#define bChSmoothCfg1 0x38
+#define bChSmoothCfg2 0x1c0
+#define bChSmoothCfg3 0xe00
+#define bChSmoothCfg4 0x7000
+#define bMRCMode 0x800000
+#define bTHEVMCfg 0x7000000
+
+#define bLoopFitType 0x1 /* Useless */
+#define bUpdCFO 0x40
+#define bUpdCFOOffData 0x80
+#define bAdvUpdCFO 0x100
+#define bAdvTimeCtrl 0x800
+#define bUpdClko 0x1000
+#define bFC 0x6000
+#define bTrackingMode 0x8000
+#define bPhCmpEnable 0x10000
+#define bUpdClkoLTF 0x20000
+#define bComChCFO 0x40000
+#define bCSIEstiMode 0x80000
+#define bAdvUpdEqz 0x100000
+#define bUChCfg 0x7000000
+#define bUpdEqz 0x8000000
+
+#define bTxAGCRate18_06 0x7f7f7f7f /* Useless */
+#define bTxAGCRate54_24 0x7f7f7f7f
+#define bTxAGCRateMCS32 0x7f
+#define bTxAGCRateCCK 0x7f00
+#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f
+#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f
+#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f
+#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f
+
+/* Rx Pseduo noise */
+#define bRxPesudoNoiseOn 0x20000000 /* Useless */
+#define bRxPesudoNoise_A 0xff
+#define bRxPesudoNoise_B 0xff00
+#define bRxPesudoNoise_C 0xff0000
+#define bRxPesudoNoise_D 0xff000000
+#define bPesudoNoiseState_A 0xffff
+#define bPesudoNoiseState_B 0xffff0000
+#define bPesudoNoiseState_C 0xffff
+#define bPesudoNoiseState_D 0xffff0000
+
+/* 7. RF Register */
+/* Zebra1 */
+#define bZebra1_HSSIEnable 0x8 /* Useless */
+#define bZebra1_TRxControl 0xc00
+#define bZebra1_TRxGainSetting 0x07f
+#define bZebra1_RxCorner 0xc00
+#define bZebra1_TxChargePump 0x38
+#define bZebra1_RxChargePump 0x7
+#define bZebra1_ChannelNum 0xf80
+#define bZebra1_TxLPFBW 0x400
+#define bZebra1_RxLPFBW 0x600
+
+/* Zebra4 */
+#define bRTL8256RegModeCtrl1 0x100 /* Useless */
+#define bRTL8256RegModeCtrl0 0x40
+#define bRTL8256_TxLPFBW 0x18
+#define bRTL8256_RxLPFBW 0x600
+
+/* RTL8258 */
+#define bRTL8258_TxLPFBW 0xc /* Useless */
+#define bRTL8258_RxLPFBW 0xc00
+#define bRTL8258_RSSILPFBW 0xc0
+
+
+/* */
+/* Other Definition */
+/* */
+
+/* byte endable for sb_write */
+#define bByte0 0x1 /* Useless */
+#define bByte1 0x2
+#define bByte2 0x4
+#define bByte3 0x8
+#define bWord0 0x3
+#define bWord1 0xc
+#define bDWord 0xf
+
+/* for PutRegsetting & GetRegSetting BitMask */
+#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */
+#define bMaskByte1 0xff00
+#define bMaskByte2 0xff0000
+#define bMaskByte3 0xff000000
+#define bMaskHWord 0xffff0000
+#define bMaskLWord 0x0000ffff
+#define bMaskDWord 0xffffffff
+#define bMaskH4Bits 0xf0000000
+#define bMaskOFDM_D 0xffc00000
+#define bMaskCCK 0x3f3f3f3f
+#define bMask12Bits 0xfff
+
+/* for PutRFRegsetting & GetRFRegSetting BitMask */
+#if (RTL92SE_FPGA_VERIFY == 1)
+#define bRFRegOffsetMask 0xfff
+#else
+#define bRFRegOffsetMask 0xfffff
+#endif
+#define bEnable 0x1 /* Useless */
+#define bDisabl 0x0
+
+#define LeftAntenna 0x0 /* Useless */
+#define RightAntenna 0x1
+
+#define tCheckTxStatus 500 /* 500ms Useless */
+#define tUpdateRxCounter 100 /* 100ms */
+
+#define rateCCK 0 /* Useless */
+#define rateOFDM 1
+#define rateHT 2
+
+/* define Register-End */
+#define bPMAC_End 0x1ff /* Useless */
+#define bFPGAPHY0_End 0x8ff
+#define bFPGAPHY1_End 0x9ff
+#define bCCKPHY0_End 0xaff
+#define bOFDMPHY0_End 0xcff
+#define bOFDMPHY1_End 0xdff
+
+/* define max debug item in each debug page */
+/* define bMaxItem_FPGA_PHY0 0x9 */
+/* define bMaxItem_FPGA_PHY1 0x3 */
+/* define bMaxItem_PHY_11B 0x16 */
+/* define bMaxItem_OFDM_PHY0 0x29 */
+/* define bMaxItem_OFDM_PHY1 0x0 */
+
+#define bPMACControl 0x0 /* Useless */
+#define bWMACControl 0x1
+#define bWNICControl 0x2
+
+#define RCR_AAP BIT(0) /* accept all physical address */
+#define RCR_APM BIT(1) /* accept physical match */
+#define RCR_AM BIT(2) /* accept multicast */
+#define RCR_AB BIT(3) /* accept broadcast */
+#define RCR_ACRC32 BIT(5) /* accept error packet */
+#define RCR_9356SEL BIT(6)
+#define RCR_AICV BIT(12) /* Accept ICV error packet */
+#define RCR_RXFTH0 (BIT(13)|BIT(14)|BIT(15)) /* Rx FIFO threshold */
+#define RCR_ADF BIT(18) /* Accept Data(frame type) frame */
+#define RCR_ACF BIT(19) /* Accept control frame */
+#define RCR_AMF BIT(20) /* Accept management frame */
+#define RCR_ADD3 BIT(21)
+#define RCR_APWRMGT BIT(22) /* Accept power management packet */
+#define RCR_CBSSID BIT(23) /* Accept BSSID match packet */
+#define RCR_ENMARP BIT(28) /* enable mac auto reset phy */
+#define RCR_EnCS1 BIT(29) /* enable carrier sense method 1 */
+#define RCR_EnCS2 BIT(30) /* enable carrier sense method 2 */
+#define RCR_OnlyErlPkt BIT(31) /* Rx Early mode is performed for
+ * packet size greater than 1536 */
+
+/*--------------------------Define Parameters-------------------------------*/
+
+
+#endif /* __INC_HAL8192SPHYREG_H */
diff --git a/drivers/staging/rtl8188eu/include/rtw_p2p.h b/drivers/staging/rtl8188eu/include/rtw_p2p.h
new file mode 100644
index 00000000000..a3e3adc92b9
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_p2p.h
@@ -0,0 +1,135 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_P2P_H_
+#define __RTW_P2P_H_
+
+#include <drv_types.h>
+
+u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo,
+ u8 *pbuf, u8 *pssid, u8 ussidlen,
+ u8 *pdev_raddr);
+u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo,
+ u8 *pbuf, u8 status_code);
+u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo,
+ u8 *pframe, uint len);
+u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo,
+ u8 *pframe, uint len, struct sta_info *psta);
+u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo,
+ u8 *pframe, uint len);
+u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo,
+ u8 *pframe, uint len);
+u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo,
+ u8 *pframe, uint len);
+u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe);
+u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo,
+ u8 *pframe, uint len);
+u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo,
+ u8 *pframe, uint len);
+u8 process_p2p_group_negotation_confirm(struct wifidirect_info *pwdinfo,
+ u8 *pframe, uint len);
+u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe,
+ uint len);
+void p2p_protocol_wk_hdl(struct adapter *padapter, int intcmdtype);
+void process_p2p_ps_ie(struct adapter *padapter, u8 *ies, u32 ielength);
+void p2p_ps_wk_hdl(struct adapter *padapter, u8 p2p_ps_state);
+u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue);
+void reset_global_wifidirect_info(struct adapter *padapter);
+int rtw_init_wifi_display_info(struct adapter *padapter);
+void rtw_init_wifidirect_timers(struct adapter *padapter);
+void rtw_init_wifidirect_addrs(struct adapter *padapter, u8 *dev_addr,
+ u8 *iface_addr);
+void init_wifidirect_info(struct adapter *padapter, enum P2P_ROLE role);
+int rtw_p2p_enable(struct adapter *padapter, enum P2P_ROLE role);
+
+static inline void _rtw_p2p_set_state(struct wifidirect_info *wdinfo,
+ enum P2P_STATE state)
+{
+ if (wdinfo->p2p_state != state)
+ wdinfo->p2p_state = state;
+}
+
+static inline void _rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo,
+ enum P2P_STATE state)
+{
+ if (wdinfo->pre_p2p_state != state)
+ wdinfo->pre_p2p_state = state;
+}
+
+static inline void _rtw_p2p_set_role(struct wifidirect_info *wdinfo,
+ enum P2P_ROLE role)
+{
+ if (wdinfo->role != role)
+ wdinfo->role = role;
+}
+
+static inline int _rtw_p2p_state(struct wifidirect_info *wdinfo)
+{
+ return wdinfo->p2p_state;
+}
+
+static inline int _rtw_p2p_pre_state(struct wifidirect_info *wdinfo)
+{
+ return wdinfo->pre_p2p_state;
+}
+
+static inline int _rtw_p2p_role(struct wifidirect_info *wdinfo)
+{
+ return wdinfo->role;
+}
+
+static inline bool _rtw_p2p_chk_state(struct wifidirect_info *wdinfo,
+ enum P2P_STATE state)
+{
+ return wdinfo->p2p_state == state;
+}
+
+static inline bool _rtw_p2p_chk_role(struct wifidirect_info *wdinfo,
+ enum P2P_ROLE role)
+{
+ return wdinfo->role == role;
+}
+
+#define rtw_p2p_set_state(wdinfo, state) _rtw_p2p_set_state(wdinfo, state)
+#define rtw_p2p_set_pre_state(wdinfo, state) \
+ _rtw_p2p_set_pre_state(wdinfo, state)
+#define rtw_p2p_set_role(wdinfo, role) _rtw_p2p_set_role(wdinfo, role)
+
+#define rtw_p2p_state(wdinfo) _rtw_p2p_state(wdinfo)
+#define rtw_p2p_pre_state(wdinfo) _rtw_p2p_pre_state(wdinfo)
+#define rtw_p2p_role(wdinfo) _rtw_p2p_role(wdinfo)
+#define rtw_p2p_chk_state(wdinfo, state) _rtw_p2p_chk_state(wdinfo, state)
+#define rtw_p2p_chk_role(wdinfo, role) _rtw_p2p_chk_role(wdinfo, role)
+
+#define rtw_p2p_findphase_ex_set(wdinfo, value) \
+ ((wdinfo)->find_phase_state_exchange_cnt = (value))
+
+/* is this find phase exchange for social channel scan? */
+#define rtw_p2p_findphase_ex_is_social(wdinfo) \
+((wdinfo)->find_phase_state_exchange_cnt >= P2P_FINDPHASE_EX_SOCIAL_FIRST)
+
+/* should we need find phase exchange anymore? */
+#define rtw_p2p_findphase_ex_is_needed(wdinfo) \
+ ((wdinfo)->find_phase_state_exchange_cnt < P2P_FINDPHASE_EX_MAX && \
+ (wdinfo)->find_phase_state_exchange_cnt != P2P_FINDPHASE_EX_NONE)
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h b/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h
new file mode 100644
index 00000000000..d4b8acb8025
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h
@@ -0,0 +1,283 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_PWRCTRL_H_
+#define __RTW_PWRCTRL_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define FW_PWR0 0
+#define FW_PWR1 1
+#define FW_PWR2 2
+#define FW_PWR3 3
+#define HW_PWR0 7
+#define HW_PWR1 6
+#define HW_PWR2 2
+#define HW_PWR3 0
+#define HW_PWR4 8
+
+#define FW_PWRMSK 0x7
+
+#define XMIT_ALIVE BIT(0)
+#define RECV_ALIVE BIT(1)
+#define CMD_ALIVE BIT(2)
+#define EVT_ALIVE BIT(3)
+
+enum power_mgnt {
+ PS_MODE_ACTIVE = 0,
+ PS_MODE_MIN,
+ PS_MODE_MAX,
+ PS_MODE_DTIM,
+ PS_MODE_VOIP,
+ PS_MODE_UAPSD_WMM,
+ PS_MODE_UAPSD,
+ PS_MODE_IBSS,
+ PS_MODE_WWLAN,
+ PM_Radio_Off,
+ PM_Card_Disable,
+ PS_MODE_NUM
+};
+
+/*
+ BIT[2:0] = HW state
+ BIT[3] = Protocol PS state, 0: register active state,
+ 1: register sleep state
+ BIT[4] = sub-state
+*/
+
+#define PS_DPS BIT(0)
+#define PS_LCLK (PS_DPS)
+#define PS_RF_OFF BIT(1)
+#define PS_ALL_ON BIT(2)
+#define PS_ST_ACTIVE BIT(3)
+
+#define PS_ISR_ENABLE BIT(4)
+#define PS_IMR_ENABLE BIT(5)
+#define PS_ACK BIT(6)
+#define PS_TOGGLE BIT(7)
+
+#define PS_STATE_MASK (0x0F)
+#define PS_STATE_HW_MASK (0x07)
+#define PS_SEQ_MASK (0xc0)
+
+#define PS_STATE(x) (PS_STATE_MASK & (x))
+#define PS_STATE_HW(x) (PS_STATE_HW_MASK & (x))
+#define PS_SEQ(x) (PS_SEQ_MASK & (x))
+
+#define PS_STATE_S0 (PS_DPS)
+#define PS_STATE_S1 (PS_LCLK)
+#define PS_STATE_S2 (PS_RF_OFF)
+#define PS_STATE_S3 (PS_ALL_ON)
+#define PS_STATE_S4 ((PS_ST_ACTIVE) | (PS_ALL_ON))
+
+#define PS_IS_RF_ON(x) ((x) & (PS_ALL_ON))
+#define PS_IS_ACTIVE(x) ((x) & (PS_ST_ACTIVE))
+#define CLR_PS_STATE(x) ((x) = ((x) & (0xF0)))
+
+struct reportpwrstate_parm {
+ unsigned char mode;
+ unsigned char state; /* the CPWM value */
+ unsigned short rsvd;
+};
+
+static inline void _init_pwrlock(struct semaphore *plock)
+{
+ _rtw_init_sema(plock, 1);
+}
+
+static inline void _free_pwrlock(struct semaphore *plock)
+{
+ _rtw_free_sema(plock);
+}
+
+static inline void _enter_pwrlock(struct semaphore *plock)
+{
+ _rtw_down_sema(plock);
+}
+
+static inline void _exit_pwrlock(struct semaphore *plock)
+{
+ _rtw_up_sema(plock);
+}
+
+#define LPS_DELAY_TIME 1*HZ /* 1 sec */
+
+#define EXE_PWR_NONE 0x01
+#define EXE_PWR_IPS 0x02
+#define EXE_PWR_LPS 0x04
+
+/* RF state. */
+enum rt_rf_power_state {
+ rf_on, /* RF is on after RFSleep or RFOff */
+ rf_sleep, /* 802.11 Power Save mode */
+ rf_off, /* HW/SW Radio OFF or Inactive Power Save */
+ /* Add the new RF state above this line===== */
+ rf_max
+};
+
+/* RF Off Level for IPS or HW/SW radio off */
+#define RT_RF_OFF_LEVL_ASPM BIT(0) /* PCI ASPM */
+#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /* PCI clock request */
+#define RT_RF_OFF_LEVL_PCI_D3 BIT(2) /* PCI D3 mode */
+#define RT_RF_OFF_LEVL_HALT_NIC BIT(3) /* NIC halt, re-init hw param*/
+#define RT_RF_OFF_LEVL_FREE_FW BIT(4) /* FW free, re-download the FW*/
+#define RT_RF_OFF_LEVL_FW_32K BIT(5) /* FW in 32k */
+#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6) /* Always enable ASPM and Clock
+ * Req in initialization. */
+#define RT_RF_LPS_DISALBE_2R BIT(30) /* When LPS is on, disable 2R
+ * if no packet is RX or TX. */
+#define RT_RF_LPS_LEVEL_ASPM BIT(31) /* LPS with ASPM */
+
+#define RT_IN_PS_LEVEL(ppsc, _PS_FLAG) \
+ ((ppsc->cur_ps_level & _PS_FLAG) ? true : false)
+#define RT_CLEAR_PS_LEVEL(ppsc, _PS_FLAG) \
+ (ppsc->cur_ps_level &= (~(_PS_FLAG)))
+#define RT_SET_PS_LEVEL(ppsc, _PS_FLAG) \
+ (ppsc->cur_ps_level |= _PS_FLAG)
+
+enum _PS_BBRegBackup_ {
+ PSBBREG_RF0 = 0,
+ PSBBREG_RF1,
+ PSBBREG_RF2,
+ PSBBREG_AFE0,
+ PSBBREG_TOTALCNT
+};
+
+enum { /* for ips_mode */
+ IPS_NONE = 0,
+ IPS_NORMAL,
+ IPS_LEVEL_2,
+};
+
+struct pwrctrl_priv {
+ struct semaphore lock;
+ volatile u8 rpwm; /* requested power state for fw */
+ volatile u8 cpwm; /* fw current power state. updated when
+ * 1. read from HCPWM 2. driver lowers power level */
+ volatile u8 tog; /* toggling */
+ volatile u8 cpwm_tog; /* toggling */
+
+ u8 pwr_mode;
+ u8 smart_ps;
+ u8 bcn_ant_mode;
+
+ u32 alives;
+ struct work_struct cpwm_event;
+ u8 bpower_saving;
+
+ u8 b_hw_radio_off;
+ u8 reg_rfoff;
+ u8 reg_pdnmode; /* powerdown mode */
+ u32 rfoff_reason;
+
+ /* RF OFF Level */
+ u32 cur_ps_level;
+ u32 reg_rfps_level;
+ uint ips_enter_cnts;
+ uint ips_leave_cnts;
+
+ u8 ips_mode;
+ u8 ips_mode_req; /* used to accept the mode setting request,
+ * will update to ipsmode later */
+ uint bips_processing;
+ u32 ips_deny_time; /* will deny IPS when system time less than this */
+ u8 ps_processing; /* temp used to mark whether in rtw_ps_processor */
+
+ u8 bLeisurePs;
+ u8 LpsIdleCount;
+ u8 power_mgnt;
+ u8 bFwCurrentInPSMode;
+ u32 DelayLPSLastTimeStamp;
+ u8 btcoex_rfon;
+ s32 pnp_current_pwr_state;
+ u8 pnp_bstop_trx;
+
+ u8 bInternalAutoSuspend;
+ u8 bInSuspend;
+#ifdef CONFIG_BT_COEXIST
+ u8 bAutoResume;
+ u8 autopm_cnt;
+#endif
+ u8 bSupportRemoteWakeup;
+ struct timer_list pwr_state_check_timer;
+ int pwr_state_check_interval;
+ u8 pwr_state_check_cnts;
+
+ int ps_flag;
+
+ enum rt_rf_power_state rf_pwrstate;/* cur power state */
+ enum rt_rf_power_state change_rfpwrstate;
+
+ u8 wepkeymask;
+ u8 bHWPowerdown;/* if support hw power down */
+ u8 bHWPwrPindetect;
+ u8 bkeepfwalive;
+ u8 brfoffbyhw;
+ unsigned long PS_BBRegBackup[PSBBREG_TOTALCNT];
+};
+
+#define rtw_get_ips_mode_req(pwrctrlpriv) \
+ (pwrctrlpriv)->ips_mode_req
+
+#define rtw_ips_mode_req(pwrctrlpriv, ips_mode) \
+ ((pwrctrlpriv)->ips_mode_req = (ips_mode))
+
+#define RTW_PWR_STATE_CHK_INTERVAL 2000
+
+#define _rtw_set_pwr_state_check_timer(pwrctrlpriv, ms) \
+ do { \
+ _set_timer(&(pwrctrlpriv)->pwr_state_check_timer, (ms)); \
+ } while (0)
+
+#define rtw_set_pwr_state_check_timer(pwrctrl) \
+ _rtw_set_pwr_state_check_timer((pwrctrl), \
+ (pwrctrl)->pwr_state_check_interval)
+
+void rtw_init_pwrctrl_priv(struct adapter *adapter);
+void rtw_free_pwrctrl_priv(struct adapter *adapter);
+
+void rtw_set_ps_mode(struct adapter *adapter, u8 ps_mode, u8 smart_ps,
+ u8 bcn_ant_mode);
+void rtw_set_rpwm(struct adapter *adapter, u8 val8);
+void LeaveAllPowerSaveMode(struct adapter *adapter);
+void ips_enter(struct adapter *padapter);
+int ips_leave(struct adapter *padapter);
+
+void rtw_ps_processor(struct adapter *padapter);
+
+enum rt_rf_power_state RfOnOffDetect(struct adapter *iadapter);
+
+s32 LPS_RF_ON_check(struct adapter *adapter, u32 delay_ms);
+void LPS_Enter(struct adapter *adapter);
+void LPS_Leave(struct adapter *adapter);
+
+u8 rtw_interface_ps_func(struct adapter *adapter,
+ enum hal_intf_ps_func efunc_id, u8 *val);
+void rtw_set_ips_deny(struct adapter *adapter, u32 ms);
+int _rtw_pwr_wakeup(struct adapter *adapter, u32 ips_defer_ms,
+ const char *caller);
+#define rtw_pwr_wakeup(adapter) \
+ _rtw_pwr_wakeup(adapter, RTW_PWR_STATE_CHK_INTERVAL, __func__)
+#define rtw_pwr_wakeup_ex(adapter, ips_deffer_ms) \
+ _rtw_pwr_wakeup(adapter, ips_deffer_ms, __func__)
+int rtw_pm_set_ips(struct adapter *adapter, u8 mode);
+int rtw_pm_set_lps(struct adapter *adapter, u8 mode);
+
+#endif /* __RTL871X_PWRCTRL_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_qos.h b/drivers/staging/rtl8188eu/include/rtw_qos.h
new file mode 100644
index 00000000000..bbee1ddc00b
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_qos.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_QOS_H_
+#define _RTW_QOS_H_
+
+#include <osdep_service.h>
+
+struct qos_priv {
+ unsigned int qos_option; /* bit mask option: u-apsd,
+ * s-apsd, ts, block ack... */
+};
+
+#endif /* _RTL871X_QOS_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_recv.h b/drivers/staging/rtl8188eu/include/rtw_recv.h
new file mode 100644
index 00000000000..bae8885c57f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_recv.h
@@ -0,0 +1,485 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_RECV_H_
+#define _RTW_RECV_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+#define NR_RECVFRAME 256
+
+#define RXFRAME_ALIGN 8
+#define RXFRAME_ALIGN_SZ (1<<RXFRAME_ALIGN)
+
+#define MAX_RXFRAME_CNT 512
+#define MAX_RX_NUMBLKS (32)
+#define RECVFRAME_HDR_ALIGN 128
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define MAX_SUBFRAME_COUNT 64
+
+/* for Rx reordering buffer control */
+struct recv_reorder_ctrl {
+ struct adapter *padapter;
+ u8 enable;
+ u16 indicate_seq;/* wstart_b, init_value=0xffff */
+ u16 wend_b;
+ u8 wsize_b;
+ struct __queue pending_recvframe_queue;
+ struct timer_list reordering_ctrl_timer;
+};
+
+struct stainfo_rxcache {
+ u16 tid_rxseq[16];
+/*
+ unsigned short tid0_rxseq;
+ unsigned short tid1_rxseq;
+ unsigned short tid2_rxseq;
+ unsigned short tid3_rxseq;
+ unsigned short tid4_rxseq;
+ unsigned short tid5_rxseq;
+ unsigned short tid6_rxseq;
+ unsigned short tid7_rxseq;
+ unsigned short tid8_rxseq;
+ unsigned short tid9_rxseq;
+ unsigned short tid10_rxseq;
+ unsigned short tid11_rxseq;
+ unsigned short tid12_rxseq;
+ unsigned short tid13_rxseq;
+ unsigned short tid14_rxseq;
+ unsigned short tid15_rxseq;
+*/
+};
+
+struct smooth_rssi_data {
+ u32 elements[100]; /* array to store values */
+ u32 index; /* index to current array to store */
+ u32 total_num; /* num of valid elements */
+ u32 total_val; /* sum of valid elements */
+};
+
+struct signal_stat {
+ u8 update_req; /* used to indicate */
+ u8 avg_val; /* avg of valid elements */
+ u32 total_num; /* num of valid elements */
+ u32 total_val; /* sum of valid elements */
+};
+#define MAX_PATH_NUM_92CS 2
+struct phy_info {
+ u8 RxPWDBAll;
+ u8 SignalQuality; /* in 0-100 index. */
+ u8 RxMIMOSignalQuality[MAX_PATH_NUM_92CS]; /* EVM */
+ u8 RxMIMOSignalStrength[MAX_PATH_NUM_92CS];/* in 0~100 index */
+ s8 RxPower; /* in dBm Translate from PWdB */
+/* Real power in dBm for this packet, no beautification and aggregation.
+ * Keep this raw info to be used for the other procedures. */
+ s8 recvpower;
+ u8 BTRxRSSIPercentage;
+ u8 SignalStrength; /* in 0-100 index. */
+ u8 RxPwr[MAX_PATH_NUM_92CS];/* per-path's pwdb */
+ u8 RxSNR[MAX_PATH_NUM_92CS];/* per-path's SNR */
+};
+
+struct rx_pkt_attrib {
+ u16 pkt_len;
+ u8 physt;
+ u8 drvinfo_sz;
+ u8 shift_sz;
+ u8 hdrlen; /* the WLAN Header Len */
+ u8 to_fr_ds;
+ u8 amsdu;
+ u8 qos;
+ u8 priority;
+ u8 pw_save;
+ u8 mdata;
+ u16 seq_num;
+ u8 frag_num;
+ u8 mfrag;
+ u8 order;
+ u8 privacy; /* in frame_ctrl field */
+ u8 bdecrypted;
+ u8 encrypt; /* when 0 indicate no encrypt. when non-zero,
+ * indicate the encrypt algorith */
+ u8 iv_len;
+ u8 icv_len;
+ u8 crc_err;
+ u8 icv_err;
+
+ u16 eth_type;
+
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u8 ta[ETH_ALEN];
+ u8 ra[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+
+ u8 ack_policy;
+
+ u8 key_index;
+
+ u8 mcs_rate;
+ u8 rxht;
+ u8 sgi;
+ u8 pkt_rpt_type;
+ u32 MacIDValidEntry[2]; /* 64 bits present 64 entry. */
+
+ struct phy_info phy_info;
+};
+
+
+/* These definition is used for Rx packet reordering. */
+#define SN_LESS(a, b) (((a - b) & 0x800) != 0)
+#define SN_EQUAL(a, b) (a == b)
+#define REORDER_WAIT_TIME (50) /* (ms) */
+
+#define RECVBUFF_ALIGN_SZ 8
+
+#define RXDESC_SIZE 24
+#define RXDESC_OFFSET RXDESC_SIZE
+
+struct recv_stat {
+ __le32 rxdw0;
+ __le32 rxdw1;
+ __le32 rxdw2;
+ __le32 rxdw3;
+ __le32 rxdw4;
+ __le32 rxdw5;
+};
+
+#define EOR BIT(30)
+
+/*
+accesser of recv_priv: rtw_recv_entry(dispatch / passive level);
+recv_thread(passive) ; returnpkt(dispatch)
+; halt(passive) ;
+
+using enter_critical section to protect
+*/
+struct recv_priv {
+ spinlock_t lock;
+ struct __queue free_recv_queue;
+ struct __queue recv_pending_queue;
+ struct __queue uc_swdec_pending_queue;
+ u8 *pallocated_frame_buf;
+ u8 *precv_frame_buf;
+ uint free_recvframe_cnt;
+ struct adapter *adapter;
+ u32 bIsAnyNonBEPkts;
+ u64 rx_bytes;
+ u64 rx_pkts;
+ u64 rx_drop;
+ u64 last_rx_bytes;
+
+ uint rx_icv_err;
+ uint rx_largepacket_crcerr;
+ uint rx_smallpacket_crcerr;
+ uint rx_middlepacket_crcerr;
+ struct semaphore allrxreturnevt;
+ uint ff_hwaddr;
+ u8 rx_pending_cnt;
+
+ struct tasklet_struct irq_prepare_beacon_tasklet;
+ struct tasklet_struct recv_tasklet;
+ struct sk_buff_head free_recv_skb_queue;
+ struct sk_buff_head rx_skb_queue;
+ u8 *pallocated_recv_buf;
+ u8 *precv_buf; /* 4 alignment */
+ struct __queue free_recv_buf_queue;
+ u32 free_recv_buf_queue_cnt;
+ /* For display the phy informatiom */
+ u8 is_signal_dbg; /* for debug */
+ u8 signal_strength_dbg; /* for debug */
+ s8 rssi;
+ s8 rxpwdb;
+ u8 signal_strength;
+ u8 signal_qual;
+ u8 noise;
+ int RxSNRdB[2];
+ s8 RxRssi[2];
+ int FalseAlmCnt_all;
+
+ struct timer_list signal_stat_timer;
+ u32 signal_stat_sampling_interval;
+ struct signal_stat signal_qual_data;
+ struct signal_stat signal_strength_data;
+};
+
+#define rtw_set_signal_stat_timer(recvpriv) \
+ _set_timer(&(recvpriv)->signal_stat_timer, \
+ (recvpriv)->signal_stat_sampling_interval)
+
+struct sta_recv_priv {
+ spinlock_t lock;
+ int option;
+ struct __queue defrag_q; /* keeping the fragment frame until defrag */
+ struct stainfo_rxcache rxcache;
+};
+
+struct recv_buf {
+ struct list_head list;
+ spinlock_t recvbuf_lock;
+ u32 ref_cnt;
+ struct adapter *adapter;
+ u8 *pbuf;
+ u8 *pallocated_buf;
+ u32 len;
+ u8 *phead;
+ u8 *pdata;
+ u8 *ptail;
+ u8 *pend;
+ struct urb *purb;
+ dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */
+ u32 alloc_sz;
+ u8 irp_pending;
+ int transfer_len;
+ struct sk_buff *pskb;
+ u8 reuse;
+};
+
+/*
+ head ----->
+
+ data ----->
+
+ payload
+
+ tail ----->
+
+
+ end ----->
+
+ len = (unsigned int )(tail - data);
+
+*/
+struct recv_frame_hdr {
+ struct list_head list;
+ struct sk_buff *pkt;
+ struct sk_buff *pkt_newalloc;
+ struct adapter *adapter;
+ u8 fragcnt;
+ int frame_tag;
+ struct rx_pkt_attrib attrib;
+ uint len;
+ u8 *rx_head;
+ u8 *rx_data;
+ u8 *rx_tail;
+ u8 *rx_end;
+ void *precvbuf;
+ struct sta_info *psta;
+ /* for A-MPDU Rx reordering buffer control */
+ struct recv_reorder_ctrl *preorder_ctrl;
+};
+
+union recv_frame {
+ union {
+ struct list_head list;
+ struct recv_frame_hdr hdr;
+ uint mem[RECVFRAME_HDR_ALIGN>>2];
+ } u;
+};
+
+union recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue);
+union recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue);
+void rtw_init_recvframe(union recv_frame *precvframe,
+ struct recv_priv *precvpriv);
+int rtw_free_recvframe(union recv_frame *precvframe,
+ struct __queue *pfree_recv_queue);
+#define rtw_dequeue_recvframe(queue) rtw_alloc_recvframe(queue)
+int _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue);
+int rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue);
+void rtw_free_recvframe_queue(struct __queue *pframequeue,
+ struct __queue *pfree_recv_queue);
+u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter);
+int rtw_enqueue_recvbuf_to_head(struct recv_buf *buf, struct __queue *queue);
+int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue);
+struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue);
+
+void rtw_reordering_ctrl_timeout_handler(void *pcontext);
+
+static inline u8 *get_rxmem(union recv_frame *precvframe)
+{
+ /* always return rx_head... */
+ if (precvframe == NULL)
+ return NULL;
+ return precvframe->u.hdr.rx_head;
+}
+
+static inline u8 *get_rx_status(union recv_frame *precvframe)
+{
+ return get_rxmem(precvframe);
+}
+
+static inline u8 *get_recvframe_data(union recv_frame *precvframe)
+{
+ /* always return rx_data */
+ if (precvframe == NULL)
+ return NULL;
+
+ return precvframe->u.hdr.rx_data;
+}
+
+static inline u8 *recvframe_push(union recv_frame *precvframe, int sz)
+{
+ /* append data before rx_data */
+
+ /* add data to the start of recv_frame
+ *
+ * This function extends the used data area of the recv_frame at the buffer
+ * start. rx_data must be still larger than rx_head, after pushing.
+ */
+ if (precvframe == NULL)
+ return NULL;
+ precvframe->u.hdr.rx_data -= sz ;
+ if (precvframe->u.hdr.rx_data < precvframe->u.hdr.rx_head) {
+ precvframe->u.hdr.rx_data += sz;
+ return NULL;
+ }
+ precvframe->u.hdr.len += sz;
+ return precvframe->u.hdr.rx_data;
+}
+
+static inline u8 *recvframe_pull(union recv_frame *precvframe, int sz)
+{
+ /* rx_data += sz; move rx_data sz bytes hereafter */
+
+ /* used for extract sz bytes from rx_data, update rx_data and return
+ * the updated rx_data to the caller */
+
+ if (precvframe == NULL)
+ return NULL;
+ precvframe->u.hdr.rx_data += sz;
+ if (precvframe->u.hdr.rx_data > precvframe->u.hdr.rx_tail) {
+ precvframe->u.hdr.rx_data -= sz;
+ return NULL;
+ }
+ precvframe->u.hdr.len -= sz;
+ return precvframe->u.hdr.rx_data;
+}
+
+static inline u8 *recvframe_put(union recv_frame *precvframe, int sz)
+{
+ /* used for append sz bytes from ptr to rx_tail, update rx_tail
+ * and return the updated rx_tail to the caller */
+ /* after putting, rx_tail must be still larger than rx_end. */
+
+ if (precvframe == NULL)
+ return NULL;
+
+ precvframe->u.hdr.rx_tail += sz;
+
+ if (precvframe->u.hdr.rx_tail > precvframe->u.hdr.rx_end) {
+ precvframe->u.hdr.rx_tail -= sz;
+ return NULL;
+ }
+ precvframe->u.hdr.len += sz;
+ return precvframe->u.hdr.rx_tail;
+}
+
+static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, int sz)
+{
+ /* rmv data from rx_tail (by yitsen) */
+
+ /* used for extract sz bytes from rx_end, update rx_end and return
+ * the updated rx_end to the caller */
+ /* after pulling, rx_end must be still larger than rx_data. */
+
+ if (precvframe == NULL)
+ return NULL;
+ precvframe->u.hdr.rx_tail -= sz;
+ if (precvframe->u.hdr.rx_tail < precvframe->u.hdr.rx_data) {
+ precvframe->u.hdr.rx_tail += sz;
+ return NULL;
+ }
+ precvframe->u.hdr.len -= sz;
+ return precvframe->u.hdr.rx_tail;
+}
+
+static inline unsigned char *get_rxbuf_desc(union recv_frame *precvframe)
+{
+ unsigned char *buf_desc;
+
+ if (precvframe == NULL)
+ return NULL;
+ return buf_desc;
+}
+
+static inline union recv_frame *rxmem_to_recvframe(u8 *rxmem)
+{
+ /* due to the design of 2048 bytes alignment of recv_frame,
+ * we can reference the union recv_frame */
+ /* from any given member of recv_frame. */
+ /* rxmem indicates the any member/address in recv_frame */
+
+ return (union recv_frame *)(((size_t)rxmem >> RXFRAME_ALIGN) << RXFRAME_ALIGN);
+}
+
+static inline union recv_frame *pkt_to_recvframe(struct sk_buff *pkt)
+{
+ u8 *buf_star;
+ union recv_frame *precv_frame;
+ precv_frame = rxmem_to_recvframe((unsigned char *)buf_star);
+
+ return precv_frame;
+}
+
+static inline u8 *pkt_to_recvmem(struct sk_buff *pkt)
+{
+ /* return the rx_head */
+
+ union recv_frame *precv_frame = pkt_to_recvframe(pkt);
+
+ return precv_frame->u.hdr.rx_head;
+}
+
+static inline u8 *pkt_to_recvdata(struct sk_buff *pkt)
+{
+ /* return the rx_data */
+
+ union recv_frame *precv_frame = pkt_to_recvframe(pkt);
+
+ return precv_frame->u.hdr.rx_data;
+}
+
+static inline int get_recvframe_len(union recv_frame *precvframe)
+{
+ return precvframe->u.hdr.len;
+}
+
+static inline s32 translate_percentage_to_dbm(u32 sig_stren_index)
+{
+ s32 power; /* in dBm. */
+
+ /* Translate to dBm (x=0.5y-95). */
+ power = (s32)((sig_stren_index + 1) >> 1);
+ power -= 95;
+
+ return power;
+}
+
+
+struct sta_info;
+
+void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv);
+
+void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_rf.h b/drivers/staging/rtl8188eu/include/rtw_rf.h
new file mode 100644
index 00000000000..089ecee6c1f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_rf.h
@@ -0,0 +1,146 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_RF_H_
+#define __RTW_RF_H_
+
+#include <rtw_cmd.h>
+
+#define OFDM_PHY 1
+#define MIXED_PHY 2
+#define CCK_PHY 3
+
+#define NumRates (13)
+
+/* slot time for 11g */
+#define SHORT_SLOT_TIME 9
+#define NON_SHORT_SLOT_TIME 20
+
+#define RTL8711_RF_MAX_SENS 6
+#define RTL8711_RF_DEF_SENS 4
+
+/* We now define the following channels as the max channels in each
+ * channel plan. */
+/* 2G, total 14 chnls */
+/* {1,2,3,4,5,6,7,8,9,10,11,12,13,14} */
+#define MAX_CHANNEL_NUM_2G 14
+#define MAX_CHANNEL_NUM 14 /* 2.4 GHz only */
+
+#define NUM_REGULATORYS 1
+
+/* Country codes */
+#define USA 0x555320
+#define EUROPE 0x1 /* temp, should be provided later */
+#define JAPAN 0x2 /* temp, should be provided later */
+
+struct regulatory_class {
+ u32 starting_freq; /* MHz, */
+ u8 channel_set[MAX_CHANNEL_NUM];
+ u8 channel_cck_power[MAX_CHANNEL_NUM]; /* dbm */
+ u8 channel_ofdm_power[MAX_CHANNEL_NUM]; /* dbm */
+ u8 txpower_limit; /* dbm */
+ u8 channel_spacing; /* MHz */
+ u8 modem;
+};
+
+enum capability {
+ cESS = 0x0001,
+ cIBSS = 0x0002,
+ cPollable = 0x0004,
+ cPollReq = 0x0008,
+ cPrivacy = 0x0010,
+ cShortPreamble = 0x0020,
+ cPBCC = 0x0040,
+ cChannelAgility = 0x0080,
+ cSpectrumMgnt = 0x0100,
+ cQos = 0x0200, /* For HCCA, use with CF-Pollable
+ * and CF-PollReq */
+ cShortSlotTime = 0x0400,
+ cAPSD = 0x0800,
+ cRM = 0x1000, /* RRM (Radio Request Measurement) */
+ cDSSS_OFDM = 0x2000,
+ cDelayedBA = 0x4000,
+ cImmediateBA = 0x8000,
+};
+
+enum _REG_PREAMBLE_MODE {
+ PREAMBLE_LONG = 1,
+ PREAMBLE_AUTO = 2,
+ PREAMBLE_SHORT = 3,
+};
+
+enum _RTL8712_RF_MIMO_CONFIG_ {
+ RTL8712_RFCONFIG_1T = 0x10,
+ RTL8712_RFCONFIG_2T = 0x20,
+ RTL8712_RFCONFIG_1R = 0x01,
+ RTL8712_RFCONFIG_2R = 0x02,
+ RTL8712_RFCONFIG_1T1R = 0x11,
+ RTL8712_RFCONFIG_1T2R = 0x12,
+ RTL8712_RFCONFIG_TURBO = 0x92,
+ RTL8712_RFCONFIG_2T2R = 0x22
+};
+
+enum rf90_radio_path {
+ RF90_PATH_A = 0, /* Radio Path A */
+ RF90_PATH_B = 1, /* Radio Path B */
+ RF90_PATH_C = 2, /* Radio Path C */
+ RF90_PATH_D = 3 /* Radio Path D */
+};
+
+/* Bandwidth Offset */
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0
+#define HAL_PRIME_CHNL_OFFSET_LOWER 1
+#define HAL_PRIME_CHNL_OFFSET_UPPER 2
+
+/* Represent Channel Width in HT Capabilities */
+/* */
+enum ht_channel_width {
+ HT_CHANNEL_WIDTH_20 = 0,
+ HT_CHANNEL_WIDTH_40 = 1,
+ HT_CHANNEL_WIDTH_80 = 2,
+ HT_CHANNEL_WIDTH_160 = 3,
+ HT_CHANNEL_WIDTH_10 = 4,
+};
+
+/* */
+/* Represent Extention Channel Offset in HT Capabilities */
+/* This is available only in 40Mhz mode. */
+/* */
+enum ht_extchnl_offset {
+ HT_EXTCHNL_OFFSET_NO_EXT = 0,
+ HT_EXTCHNL_OFFSET_UPPER = 1,
+ HT_EXTCHNL_OFFSET_NO_DEF = 2,
+ HT_EXTCHNL_OFFSET_LOWER = 3,
+};
+
+/* 2007/11/15 MH Define different RF type. */
+enum rt_rf_type_def {
+ RF_1T2R = 0,
+ RF_2T4R = 1,
+ RF_2T2R = 2,
+ RF_1T1R = 3,
+ RF_2T2R_GREEN = 4,
+ RF_819X_MAX_TYPE = 5,
+};
+
+u32 rtw_ch2freq(u32 ch);
+u32 rtw_freq2ch(u32 freq);
+
+
+#endif /* _RTL8711_RF_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_security.h b/drivers/staging/rtl8188eu/include/rtw_security.h
new file mode 100644
index 00000000000..23c7814a50e
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_security.h
@@ -0,0 +1,383 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_SECURITY_H_
+#define __RTW_SECURITY_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define _NO_PRIVACY_ 0x0
+#define _WEP40_ 0x1
+#define _TKIP_ 0x2
+#define _TKIP_WTMIC_ 0x3
+#define _AES_ 0x4
+#define _WEP104_ 0x5
+#define _WEP_WPA_MIXED_ 0x07 /* WEP + WPA */
+#define _SMS4_ 0x06
+
+#define is_wep_enc(alg) (((alg) == _WEP40_) || ((alg) == _WEP104_))
+
+#define _WPA_IE_ID_ 0xdd
+#define _WPA2_IE_ID_ 0x30
+
+#define SHA256_MAC_LEN 32
+#define AES_BLOCK_SIZE 16
+#define AES_PRIV_SIZE (4 * 44)
+
+enum {
+ ENCRYP_PROTOCOL_OPENSYS, /* open system */
+ ENCRYP_PROTOCOL_WEP, /* WEP */
+ ENCRYP_PROTOCOL_WPA, /* WPA */
+ ENCRYP_PROTOCOL_WPA2, /* WPA2 */
+ ENCRYP_PROTOCOL_WAPI, /* WAPI: Not support in this version */
+ ENCRYP_PROTOCOL_MAX
+};
+
+
+#ifndef Ndis802_11AuthModeWPA2
+#define Ndis802_11AuthModeWPA2 (Ndis802_11AuthModeWPANone + 1)
+#endif
+
+#ifndef Ndis802_11AuthModeWPA2PSK
+#define Ndis802_11AuthModeWPA2PSK (Ndis802_11AuthModeWPANone + 2)
+#endif
+
+union pn48 {
+ u64 val;
+
+#ifdef __LITTLE_ENDIAN
+ struct {
+ u8 TSC0;
+ u8 TSC1;
+ u8 TSC2;
+ u8 TSC3;
+ u8 TSC4;
+ u8 TSC5;
+ u8 TSC6;
+ u8 TSC7;
+ } _byte_;
+
+#elif defined(__BIG_ENDIAN)
+
+ struct {
+ u8 TSC7;
+ u8 TSC6;
+ u8 TSC5;
+ u8 TSC4;
+ u8 TSC3;
+ u8 TSC2;
+ u8 TSC1;
+ u8 TSC0;
+ } _byte_;
+#endif
+};
+
+union Keytype {
+ u8 skey[16];
+ u32 lkey[4];
+};
+
+struct rt_pmkid_list {
+ u8 bUsed;
+ u8 Bssid[6];
+ u8 PMKID[16];
+ u8 SsidBuf[33];
+ u8 *ssid_octet;
+ u16 ssid_length;
+};
+
+struct security_priv {
+ u32 dot11AuthAlgrthm; /* 802.11 auth, could be open,
+ * shared, 8021x and authswitch */
+ u32 dot11PrivacyAlgrthm; /* This specify the privacy for
+ * shared auth. algorithm. */
+ /* WEP */
+ u32 dot11PrivacyKeyIndex; /* this is only valid for legendary
+ * wep, 0~3 for key id.(tx key index) */
+ union Keytype dot11DefKey[4]; /* this is only valid for def. key */
+ u32 dot11DefKeylen[4];
+ u32 dot118021XGrpPrivacy; /* This specify the privacy algthm.
+ * used for Grp key */
+ u32 dot118021XGrpKeyid; /* key id used for Grp Key
+ * ( tx key index) */
+ union Keytype dot118021XGrpKey[4]; /* 802.1x Group Key,
+ * for inx0 and inx1 */
+ union Keytype dot118021XGrptxmickey[4];
+ union Keytype dot118021XGrprxmickey[4];
+ union pn48 dot11Grptxpn; /* PN48 used for Grp Key xmit.*/
+ union pn48 dot11Grprxpn; /* PN48 used for Grp Key recv.*/
+#ifdef CONFIG_88EU_AP_MODE
+ /* extend security capabilities for AP_MODE */
+ unsigned int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */
+ unsigned int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */
+ unsigned int wpa_group_cipher;
+ unsigned int wpa2_group_cipher;
+ unsigned int wpa_pairwise_cipher;
+ unsigned int wpa2_pairwise_cipher;
+#endif
+ u8 wps_ie[MAX_WPS_IE_LEN];/* added in assoc req */
+ int wps_ie_len;
+ u8 binstallGrpkey;
+ u8 busetkipkey;
+ u8 bcheck_grpkey;
+ u8 bgrpkey_handshake;
+ s32 sw_encrypt;/* from registry_priv */
+ s32 sw_decrypt;/* from registry_priv */
+ s32 hw_decrypted;/* if the rx packets is hw_decrypted==false,i
+ * it means the hw has not been ready. */
+
+ /* keeps the auth_type & enc_status from upper layer
+ * ioctl(wpa_supplicant or wzc) */
+ u32 ndisauthtype; /* NDIS_802_11_AUTHENTICATION_MODE */
+ u32 ndisencryptstatus; /* NDIS_802_11_ENCRYPTION_STATUS */
+ struct wlan_bssid_ex sec_bss; /* for joinbss (h2c buffer) usage */
+ struct ndis_802_11_wep ndiswep;
+ u8 assoc_info[600];
+ u8 szofcapability[256]; /* for wpa2 usage */
+ u8 oidassociation[512]; /* for wpa/wpa2 usage */
+ u8 authenticator_ie[256]; /* store ap security information element */
+ u8 supplicant_ie[256]; /* store sta security information element */
+
+ /* for tkip countermeasure */
+ u32 last_mic_err_time;
+ u8 btkip_countermeasure;
+ u8 btkip_wait_report;
+ u32 btkip_countermeasure_time;
+
+ /* */
+ /* For WPA2 Pre-Authentication. */
+ /* */
+ struct rt_pmkid_list PMKIDList[NUM_PMKID_CACHE];
+ u8 PMKIDIndex;
+ u8 bWepDefaultKeyIdxSet;
+};
+
+struct sha256_state {
+ u64 length;
+ u32 state[8], curlen;
+ u8 buf[64];
+};
+
+#define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst) \
+do { \
+ switch (psecuritypriv->dot11AuthAlgrthm) { \
+ case dot11AuthAlgrthm_Open: \
+ case dot11AuthAlgrthm_Shared: \
+ case dot11AuthAlgrthm_Auto: \
+ encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm; \
+ break; \
+ case dot11AuthAlgrthm_8021X: \
+ if (bmcst) \
+ encry_algo = (u8)psecuritypriv->dot118021XGrpPrivacy;\
+ else \
+ encry_algo = (u8)psta->dot118021XPrivacy; \
+ break; \
+ case dot11AuthAlgrthm_WAPI: \
+ encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm; \
+ break; \
+ } \
+} while (0)
+
+#define SET_ICE_IV_LEN(iv_len, icv_len, encrypt) \
+do { \
+ switch (encrypt) { \
+ case _WEP40_: \
+ case _WEP104_: \
+ iv_len = 4; \
+ icv_len = 4; \
+ break; \
+ case _TKIP_: \
+ iv_len = 8; \
+ icv_len = 4; \
+ break; \
+ case _AES_: \
+ iv_len = 8; \
+ icv_len = 8; \
+ break; \
+ case _SMS4_: \
+ iv_len = 18; \
+ icv_len = 16; \
+ break; \
+ default: \
+ iv_len = 0; \
+ icv_len = 0; \
+ break; \
+ } \
+} while (0)
+
+
+#define GET_TKIP_PN(iv, dot11txpn) \
+do { \
+ dot11txpn._byte_.TSC0 = iv[2]; \
+ dot11txpn._byte_.TSC1 = iv[0]; \
+ dot11txpn._byte_.TSC2 = iv[4]; \
+ dot11txpn._byte_.TSC3 = iv[5]; \
+ dot11txpn._byte_.TSC4 = iv[6]; \
+ dot11txpn._byte_.TSC5 = iv[7]; \
+} while (0)
+
+
+#define ROL32(A, n) (((A) << (n)) | (((A)>>(32-(n))) & ((1UL << (n)) - 1)))
+#define ROR32(A, n) ROL32((A), 32-(n))
+
+struct mic_data {
+ u32 K0, K1; /* Key */
+ u32 L, R; /* Current state */
+ u32 M; /* Message accumulator (single word) */
+ u32 nBytesInM; /* # bytes in M */
+};
+
+extern const u32 Te0[256];
+extern const u32 Te1[256];
+extern const u32 Te2[256];
+extern const u32 Te3[256];
+extern const u32 Te4[256];
+extern const u32 Td0[256];
+extern const u32 Td1[256];
+extern const u32 Td2[256];
+extern const u32 Td3[256];
+extern const u32 Td4[256];
+extern const u32 rcon[10];
+extern const u8 Td4s[256];
+extern const u8 rcons[10];
+
+#define RCON(i) (rcons[(i)] << 24)
+
+static inline u32 rotr(u32 val, int bits)
+{
+ return (val >> bits) | (val << (32 - bits));
+}
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
+#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
+#define TE3(i) rotr(Te0[(i) & 0xff], 24)
+#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
+#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
+#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
+#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
+#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
+#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
+#define TD3(i) rotr(Td0[(i) & 0xff], 24)
+#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
+#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
+#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
+#define TD44(i) (Td4s[(i) & 0xff])
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
+#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
+#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
+
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
+ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
+
+#define PUTU32(ct, st) { \
+(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
+(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
+
+#define WPA_GET_BE32(a) ((((u32)(a)[0]) << 24) | (((u32)(a)[1]) << 16) | \
+ (((u32)(a)[2]) << 8) | ((u32)(a)[3]))
+
+#define WPA_PUT_LE16(a, val) \
+ do { \
+ (a)[1] = ((u16)(val)) >> 8; \
+ (a)[0] = ((u16)(val)) & 0xff; \
+ } while (0)
+
+#define WPA_PUT_BE32(a, val) \
+ do { \
+ (a)[0] = (u8)((((u32)(val)) >> 24) & 0xff); \
+ (a)[1] = (u8)((((u32)(val)) >> 16) & 0xff); \
+ (a)[2] = (u8)((((u32)(val)) >> 8) & 0xff); \
+ (a)[3] = (u8)(((u32)(val)) & 0xff); \
+ } while (0)
+
+#define WPA_PUT_BE64(a, val) \
+ do { \
+ (a)[0] = (u8)(((u64)(val)) >> 56); \
+ (a)[1] = (u8)(((u64)(val)) >> 48); \
+ (a)[2] = (u8)(((u64)(val)) >> 40); \
+ (a)[3] = (u8)(((u64)(val)) >> 32); \
+ (a)[4] = (u8)(((u64)(val)) >> 24); \
+ (a)[5] = (u8)(((u64)(val)) >> 16); \
+ (a)[6] = (u8)(((u64)(val)) >> 8); \
+ (a)[7] = (u8)(((u64)(val)) & 0xff); \
+ } while (0)
+
+/* ===== start - public domain SHA256 implementation ===== */
+
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+/* the K array */
+static const unsigned long K[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Various logical functions */
+#define RORc(x, y) \
+ (((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y)&31)) | \
+ ((unsigned long)(x) << (unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define Ch(x, y ,z) (z ^ (x & (y ^ z)))
+#define Maj(x, y, z) (((x | y) & z) | (x & y))
+#define S(x, n) RORc((x), (n))
+#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key);
+void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b);
+void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nBytes);
+void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst);
+void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len,
+ u8 *Miccode, u8 priority);
+u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe);
+u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe);
+void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe);
+u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe);
+u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe);
+void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe);
+void rtw_use_tkipkey_handler(void *FunctionContext);
+
+#endif /* __RTL871X_SECURITY_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_sreset.h b/drivers/staging/rtl8188eu/include/rtw_sreset.h
new file mode 100644
index 00000000000..2a1244f7579
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_sreset.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_SRESET_C_
+#define _RTW_SRESET_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+struct sreset_priv {
+ struct mutex silentreset_mutex;
+ u8 silent_reset_inprogress;
+ u8 Wifi_Error_Status;
+ unsigned long last_tx_time;
+ unsigned long last_tx_complete_time;
+};
+
+#include <rtl8188e_hal.h>
+
+#define WIFI_STATUS_SUCCESS 0
+#define USB_VEN_REQ_CMD_FAIL BIT0
+#define USB_READ_PORT_FAIL BIT1
+#define USB_WRITE_PORT_FAIL BIT2
+#define WIFI_MAC_TXDMA_ERROR BIT3
+#define WIFI_TX_HANG BIT4
+#define WIFI_RX_HANG BIT5
+#define WIFI_IF_NOT_EXIST BIT6
+
+void sreset_init_value(struct adapter *padapter);
+void sreset_reset_value(struct adapter *padapter);
+u8 sreset_get_wifi_status(struct adapter *padapter);
+void sreset_set_wifi_error_status(struct adapter *padapter, u32 status);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_version.h b/drivers/staging/rtl8188eu/include/rtw_version.h
new file mode 100644
index 00000000000..6d2d52cbb3d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_version.h
@@ -0,0 +1 @@
+#define DRIVERVERSION "v4.1.4_6773.20130222"
diff --git a/drivers/staging/rtl8188eu/include/rtw_xmit.h b/drivers/staging/rtl8188eu/include/rtw_xmit.h
new file mode 100644
index 00000000000..1ac1dd31db6
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_xmit.h
@@ -0,0 +1,384 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_XMIT_H_
+#define _RTW_XMIT_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define MAX_XMITBUF_SZ (20480) /* 20k */
+#define NR_XMITBUFF (4)
+
+#define XMITBUF_ALIGN_SZ 4
+
+/* xmit extension buff defination */
+#define MAX_XMIT_EXTBUF_SZ (1536)
+#define NR_XMIT_EXTBUFF (32)
+
+#define MAX_NUMBLKS (1)
+
+#define XMIT_VO_QUEUE (0)
+#define XMIT_VI_QUEUE (1)
+#define XMIT_BE_QUEUE (2)
+#define XMIT_BK_QUEUE (3)
+
+#define VO_QUEUE_INX 0
+#define VI_QUEUE_INX 1
+#define BE_QUEUE_INX 2
+#define BK_QUEUE_INX 3
+#define BCN_QUEUE_INX 4
+#define MGT_QUEUE_INX 5
+#define HIGH_QUEUE_INX 6
+#define TXCMD_QUEUE_INX 7
+
+#define HW_QUEUE_ENTRY 8
+
+#define WEP_IV(pattrib_iv, dot11txpn, keyidx)\
+do {\
+ pattrib_iv[0] = dot11txpn._byte_.TSC0;\
+ pattrib_iv[1] = dot11txpn._byte_.TSC1;\
+ pattrib_iv[2] = dot11txpn._byte_.TSC2;\
+ pattrib_iv[3] = ((keyidx & 0x3)<<6);\
+ dot11txpn.val = (dot11txpn.val == 0xffffff) ? 0 : (dot11txpn.val+1);\
+} while (0)
+
+
+#define TKIP_IV(pattrib_iv, dot11txpn, keyidx)\
+do {\
+ pattrib_iv[0] = dot11txpn._byte_.TSC1;\
+ pattrib_iv[1] = (dot11txpn._byte_.TSC1 | 0x20) & 0x7f;\
+ pattrib_iv[2] = dot11txpn._byte_.TSC0;\
+ pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);\
+ pattrib_iv[4] = dot11txpn._byte_.TSC2;\
+ pattrib_iv[5] = dot11txpn._byte_.TSC3;\
+ pattrib_iv[6] = dot11txpn._byte_.TSC4;\
+ pattrib_iv[7] = dot11txpn._byte_.TSC5;\
+ dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 : (dot11txpn.val+1);\
+} while (0)
+
+#define AES_IV(pattrib_iv, dot11txpn, keyidx)\
+do { \
+ pattrib_iv[0] = dot11txpn._byte_.TSC0; \
+ pattrib_iv[1] = dot11txpn._byte_.TSC1; \
+ pattrib_iv[2] = 0; \
+ pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6); \
+ pattrib_iv[4] = dot11txpn._byte_.TSC2; \
+ pattrib_iv[5] = dot11txpn._byte_.TSC3; \
+ pattrib_iv[6] = dot11txpn._byte_.TSC4; \
+ pattrib_iv[7] = dot11txpn._byte_.TSC5; \
+ dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 : (dot11txpn.val+1);\
+} while (0)
+
+#define HWXMIT_ENTRY 4
+
+#define TXDESC_SIZE 32
+
+#define PACKET_OFFSET_SZ (8)
+#define TXDESC_OFFSET (TXDESC_SIZE + PACKET_OFFSET_SZ)
+
+struct tx_desc {
+ /* DWORD 0 */
+ __le32 txdw0;
+ __le32 txdw1;
+ __le32 txdw2;
+ __le32 txdw3;
+ __le32 txdw4;
+ __le32 txdw5;
+ __le32 txdw6;
+ __le32 txdw7;
+};
+
+union txdesc {
+ struct tx_desc txdesc;
+ unsigned int value[TXDESC_SIZE>>2];
+};
+
+struct hw_xmit {
+ struct __queue *sta_queue;
+ int accnt;
+};
+
+/* reduce size */
+struct pkt_attrib {
+ u8 type;
+ u8 subtype;
+ u8 bswenc;
+ u8 dhcp_pkt;
+ u16 ether_type;
+ u16 seqnum;
+ u16 pkt_hdrlen; /* the original 802.3 pkt header len */
+ u16 hdrlen; /* the WLAN Header Len */
+ u32 pktlen; /* the original 802.3 pkt raw_data len (not include
+ * ether_hdr data) */
+ u32 last_txcmdsz;
+ u8 nr_frags;
+ u8 encrypt; /* when 0 indicate no encrypt. when non-zero,
+ * indicate the encrypt algorith */
+ u8 iv_len;
+ u8 icv_len;
+ u8 iv[18];
+ u8 icv[16];
+ u8 priority;
+ u8 ack_policy;
+ u8 mac_id;
+ u8 vcs_mode; /* virtual carrier sense method */
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u8 ta[ETH_ALEN];
+ u8 ra[ETH_ALEN];
+ u8 key_idx;
+ u8 qos_en;
+ u8 ht_en;
+ u8 raid;/* rate adpative id */
+ u8 bwmode;
+ u8 ch_offset;/* PRIME_CHNL_OFFSET */
+ u8 sgi;/* short GI */
+ u8 ampdu_en;/* tx ampdu enable */
+ u8 mdata;/* more data bit */
+ u8 pctrl;/* per packet txdesc control enable */
+ u8 triggered;/* for ap mode handling Power Saving sta */
+ u8 qsel;
+ u8 eosp;
+ u8 rate;
+ u8 intel_proxim;
+ u8 retry_ctrl;
+ struct sta_info *psta;
+};
+
+#define WLANHDR_OFFSET 64
+
+#define NULL_FRAMETAG (0x0)
+#define DATA_FRAMETAG 0x01
+#define L2_FRAMETAG 0x02
+#define MGNT_FRAMETAG 0x03
+#define AMSDU_FRAMETAG 0x04
+
+#define EII_FRAMETAG 0x05
+#define IEEE8023_FRAMETAG 0x06
+
+#define MP_FRAMETAG 0x07
+
+#define TXAGG_FRAMETAG 0x08
+
+struct submit_ctx {
+ u32 submit_time; /* */
+ u32 timeout_ms; /* <0: not synchronous, 0: wait forever, >0: up to ms waiting */
+ int status; /* status for operation */
+ struct completion done;
+};
+
+enum {
+ RTW_SCTX_SUBMITTED = -1,
+ RTW_SCTX_DONE_SUCCESS = 0,
+ RTW_SCTX_DONE_UNKNOWN,
+ RTW_SCTX_DONE_TIMEOUT,
+ RTW_SCTX_DONE_BUF_ALLOC,
+ RTW_SCTX_DONE_BUF_FREE,
+ RTW_SCTX_DONE_WRITE_PORT_ERR,
+ RTW_SCTX_DONE_TX_DESC_NA,
+ RTW_SCTX_DONE_TX_DENY,
+ RTW_SCTX_DONE_CCX_PKT_FAIL,
+ RTW_SCTX_DONE_DRV_STOP,
+ RTW_SCTX_DONE_DEV_REMOVE,
+};
+
+void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms);
+int rtw_sctx_wait(struct submit_ctx *sctx);
+void rtw_sctx_done_err(struct submit_ctx **sctx, int status);
+void rtw_sctx_done(struct submit_ctx **sctx);
+
+struct xmit_buf {
+ struct list_head list;
+ struct adapter *padapter;
+ u8 *pallocated_buf;
+ u8 *pbuf;
+ void *priv_data;
+ u16 ext_tag; /* 0: Normal xmitbuf, 1: extension xmitbuf. */
+ u16 flags;
+ u32 alloc_sz;
+ u32 len;
+ struct submit_ctx *sctx;
+ u32 ff_hwaddr;
+ struct urb *pxmit_urb[8];
+ dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */
+ u8 bpending[8];
+ int last[8];
+};
+
+struct xmit_frame {
+ struct list_head list;
+ struct pkt_attrib attrib;
+ struct sk_buff *pkt;
+ int frame_tag;
+ struct adapter *padapter;
+ u8 *buf_addr;
+ struct xmit_buf *pxmitbuf;
+
+ u8 agg_num;
+ s8 pkt_offset;
+ u8 ack_report;
+};
+
+struct tx_servq {
+ struct list_head tx_pending;
+ struct __queue sta_pending;
+ int qcnt;
+};
+
+struct sta_xmit_priv {
+ spinlock_t lock;
+ int option;
+ int apsd_setting; /* When bit mask is on, the associated edca
+ * queue supports APSD. */
+ struct tx_servq be_q; /* priority == 0,3 */
+ struct tx_servq bk_q; /* priority == 1,2 */
+ struct tx_servq vi_q; /* priority == 4,5 */
+ struct tx_servq vo_q; /* priority == 6,7 */
+ struct list_head legacy_dz;
+ struct list_head apsd;
+ u16 txseq_tid[16];
+};
+
+struct hw_txqueue {
+ volatile int head;
+ volatile int tail;
+ volatile int free_sz; /* in units of 64 bytes */
+ volatile int free_cmdsz;
+ volatile int txsz[8];
+ uint ff_hwaddr;
+ uint cmd_hwaddr;
+ int ac_tag;
+};
+
+struct agg_pkt_info {
+ u16 offset;
+ u16 pkt_len;
+};
+
+struct xmit_priv {
+ spinlock_t lock;
+ struct semaphore xmit_sema;
+ struct semaphore terminate_xmitthread_sema;
+ struct __queue be_pending;
+ struct __queue bk_pending;
+ struct __queue vi_pending;
+ struct __queue vo_pending;
+ struct __queue bm_pending;
+ u8 *pallocated_frame_buf;
+ u8 *pxmit_frame_buf;
+ uint free_xmitframe_cnt;
+ struct __queue free_xmit_queue;
+ uint frag_len;
+ struct adapter *adapter;
+ u8 vcs_setting;
+ u8 vcs;
+ u8 vcs_type;
+ u64 tx_bytes;
+ u64 tx_pkts;
+ u64 tx_drop;
+ u64 last_tx_bytes;
+ u64 last_tx_pkts;
+ struct hw_xmit *hwxmits;
+ u8 hwxmit_entry;
+ u8 wmm_para_seq[4];/* sequence for wmm ac parameter strength
+ * from large to small. it's value is 0->vo,
+ * 1->vi, 2->be, 3->bk. */
+ struct semaphore tx_retevt;/* all tx return event; */
+ u8 txirp_cnt;/* */
+ struct tasklet_struct xmit_tasklet;
+ /* per AC pending irp */
+ int beq_cnt;
+ int bkq_cnt;
+ int viq_cnt;
+ int voq_cnt;
+ struct __queue free_xmitbuf_queue;
+ struct __queue pending_xmitbuf_queue;
+ u8 *pallocated_xmitbuf;
+ u8 *pxmitbuf;
+ uint free_xmitbuf_cnt;
+ struct __queue free_xmit_extbuf_queue;
+ u8 *pallocated_xmit_extbuf;
+ u8 *pxmit_extbuf;
+ uint free_xmit_extbuf_cnt;
+ u16 nqos_ssn;
+ int ack_tx;
+ struct mutex ack_tx_mutex;
+ struct submit_ctx ack_tx_ops;
+};
+
+struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv);
+s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv,
+ struct xmit_buf *pxmitbuf);
+struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv);
+s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv,
+ struct xmit_buf *pxmitbuf);
+void rtw_count_tx_stats(struct adapter *padapter,
+ struct xmit_frame *pxmitframe, int sz);
+void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len);
+s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr,
+ struct pkt_attrib *pattrib);
+s32 rtw_put_snap(u8 *data, u16 h_proto);
+
+struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv);
+s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv,
+ struct xmit_frame *pxmitframe);
+void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv,
+ struct __queue *pframequeue);
+struct tx_servq *rtw_get_sta_pending(struct adapter *padapter,
+ struct sta_info *psta, int up, u8 *ac);
+s32 rtw_xmitframe_enqueue(struct adapter *padapter,
+ struct xmit_frame *pxmitframe);
+struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv,
+ struct hw_xmit *phwxmit_i, int entry);
+
+s32 rtw_xmit_classifier(struct adapter *padapter,
+ struct xmit_frame *pxmitframe);
+u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib);
+#define rtw_wlan_pkt_size(f) rtw_calculate_wlan_pkt_size_by_attribue(&f->attrib)
+s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt,
+ struct xmit_frame *pxmitframe);
+s32 _rtw_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag);
+void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv);
+s32 rtw_txframes_pending(struct adapter *padapter);
+s32 rtw_txframes_sta_ac_pending(struct adapter *padapter,
+ struct pkt_attrib *pattrib);
+void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry);
+s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter);
+void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv);
+void rtw_alloc_hwxmits(struct adapter *padapter);
+void rtw_free_hwxmits(struct adapter *padapter);
+s32 rtw_xmit(struct adapter *padapter, struct sk_buff **pkt);
+
+#if defined(CONFIG_88EU_AP_MODE)
+int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe);
+void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta);
+void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta);
+void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta);
+#endif
+
+u8 qos_acm(u8 acm_mask, u8 priority);
+u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe);
+int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms);
+void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status);
+
+/* include after declaring struct xmit_buf, in order to avoid warning */
+#include <xmit_osdep.h>
+
+#endif /* _RTL871X_XMIT_H_ */
diff --git a/drivers/staging/rtl8188eu/include/sta_info.h b/drivers/staging/rtl8188eu/include/sta_info.h
new file mode 100644
index 00000000000..3ed2a39741a
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/sta_info.h
@@ -0,0 +1,384 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __STA_INFO_H_
+#define __STA_INFO_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+
+#define IBSS_START_MAC_ID 2
+#define NUM_STA 32
+#define NUM_ACL 16
+
+/* if mode ==0, then the sta is allowed once the addr is hit. */
+/* if mode ==1, then the sta is rejected once the addr is non-hit. */
+struct rtw_wlan_acl_node {
+ struct list_head list;
+ u8 addr[ETH_ALEN];
+ u8 valid;
+};
+
+/* mode=0, disable */
+/* mode=1, accept unless in deny list */
+/* mode=2, deny unless in accept list */
+struct wlan_acl_pool {
+ int mode;
+ int num;
+ struct rtw_wlan_acl_node aclnode[NUM_ACL];
+ struct __queue acl_node_q;
+};
+
+struct rssi_sta {
+ s32 UndecoratedSmoothedPWDB;
+ s32 UndecoratedSmoothedCCK;
+ s32 UndecoratedSmoothedOFDM;
+ u64 PacketMap;
+ u8 ValidBit;
+};
+
+struct stainfo_stats {
+ u64 rx_mgnt_pkts;
+ u64 rx_beacon_pkts;
+ u64 rx_probereq_pkts;
+ u64 rx_probersp_pkts;
+ u64 rx_probersp_bm_pkts;
+ u64 rx_probersp_uo_pkts;
+ u64 rx_ctrl_pkts;
+ u64 rx_data_pkts;
+
+ u64 last_rx_mgnt_pkts;
+ u64 last_rx_beacon_pkts;
+ u64 last_rx_probereq_pkts;
+ u64 last_rx_probersp_pkts;
+ u64 last_rx_probersp_bm_pkts;
+ u64 last_rx_probersp_uo_pkts;
+ u64 last_rx_ctrl_pkts;
+ u64 last_rx_data_pkts;
+ u64 rx_bytes;
+ u64 rx_drops;
+ u64 tx_pkts;
+ u64 tx_bytes;
+ u64 tx_drops;
+};
+
+struct sta_info {
+ spinlock_t lock;
+ struct list_head list; /* free_sta_queue */
+ struct list_head hash_list; /* sta_hash */
+
+ struct sta_xmit_priv sta_xmitpriv;
+ struct sta_recv_priv sta_recvpriv;
+
+ struct __queue sleep_q;
+ unsigned int sleepq_len;
+
+ uint state;
+ uint aid;
+ uint mac_id;
+ uint qos_option;
+ u8 hwaddr[ETH_ALEN];
+
+ uint ieee8021x_blocked; /* 0: allowed, 1:blocked */
+ uint dot118021XPrivacy; /* aes, tkip... */
+ union Keytype dot11tkiptxmickey;
+ union Keytype dot11tkiprxmickey;
+ union Keytype dot118021x_UncstKey;
+ union pn48 dot11txpn; /* PN48 used for Unicast xmit. */
+ union pn48 dot11rxpn; /* PN48 used for Unicast recv. */
+ u8 bssrateset[16];
+ u32 bssratelen;
+ s32 rssi;
+ s32 signal_quality;
+
+ u8 cts2self;
+ u8 rtsen;
+
+ u8 raid;
+ u8 init_rate;
+ u32 ra_mask;
+ u8 wireless_mode; /* NETWORK_TYPE */
+ struct stainfo_stats sta_stats;
+
+ /* for A-MPDU TX, ADDBA timeout check */
+ struct timer_list addba_retry_timer;
+
+ /* for A-MPDU Rx reordering buffer control */
+ struct recv_reorder_ctrl recvreorder_ctrl[16];
+
+ /* for A-MPDU Tx */
+ /* unsigned char ampdu_txen_bitmap; */
+ u16 BA_starting_seqctrl[16];
+
+ struct ht_priv htpriv;
+
+ /* Notes: */
+ /* STA_Mode: */
+ /* curr_network(mlme_priv/security_priv/qos/ht) +
+ * sta_info: (STA & AP) CAP/INFO */
+ /* scan_q: AP CAP/INFO */
+
+ /* AP_Mode: */
+ /* curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO */
+ /* sta_info: (AP & STA) CAP/INFO */
+
+ struct list_head asoc_list;
+#ifdef CONFIG_88EU_AP_MODE
+ struct list_head auth_list;
+
+ unsigned int expire_to;
+ unsigned int auth_seq;
+ unsigned int authalg;
+ unsigned char chg_txt[128];
+
+ u16 capability;
+ int flags;
+
+ int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */
+ int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */
+ int wpa_group_cipher;
+ int wpa2_group_cipher;
+ int wpa_pairwise_cipher;
+ int wpa2_pairwise_cipher;
+
+ u8 bpairwise_key_installed;
+
+ u8 wpa_ie[32];
+
+ u8 nonerp_set;
+ u8 no_short_slot_time_set;
+ u8 no_short_preamble_set;
+ u8 no_ht_gf_set;
+ u8 no_ht_set;
+ u8 ht_20mhz_set;
+
+ unsigned int tx_ra_bitmap;
+ u8 qos_info;
+
+ u8 max_sp_len;
+ u8 uapsd_bk;/* BIT(0): Delivery enabled, BIT(1): Trigger enabled */
+ u8 uapsd_be;
+ u8 uapsd_vi;
+ u8 uapsd_vo;
+
+ u8 has_legacy_ac;
+ unsigned int sleepq_ac_len;
+#endif /* CONFIG_88EU_AP_MODE */
+
+#ifdef CONFIG_88EU_P2P
+ /* p2p priv data */
+ u8 is_p2p_device;
+ u8 p2p_status_code;
+
+ /* p2p client info */
+ u8 dev_addr[ETH_ALEN];
+ u8 dev_cap;
+ u16 config_methods;
+ u8 primary_dev_type[8];
+ u8 num_of_secdev_type;
+ u8 secdev_types_list[32];/* 32/8 == 4; */
+ u16 dev_name_len;
+ u8 dev_name[32];
+#endif /* CONFIG_88EU_P2P */
+ u8 under_exist_checking;
+ u8 keep_alive_trycnt;
+
+ /* for DM */
+ struct rssi_sta rssi_stat;
+
+ /* ================ODM Relative Info======================= */
+ /* Please be careful, don't declare too much structure here.
+ * It will cost memory * STA support num. */
+ /* 2011/10/20 MH Add for ODM STA info. */
+ /* Driver Write */
+ u8 bValid; /* record the sta status link or not? */
+ u8 IOTPeer; /* Enum value. HT_IOT_PEER_E */
+ u8 rssi_level; /* for Refresh RA mask */
+ /* ODM Write */
+ /* 1 PHY_STATUS_INFO */
+ u8 RSSI_Path[4]; /* */
+ u8 RSSI_Ave;
+ u8 RXEVM[4];
+ u8 RXSNR[4];
+
+ /* ================ODM Relative Info======================= */
+ /* */
+
+ /* To store the sequence number of received management frame */
+ u16 RxMgmtFrameSeqNum;
+};
+
+#define sta_rx_pkts(sta) \
+ (sta->sta_stats.rx_mgnt_pkts \
+ + sta->sta_stats.rx_ctrl_pkts \
+ + sta->sta_stats.rx_data_pkts)
+
+#define sta_last_rx_pkts(sta) \
+ (sta->sta_stats.last_rx_mgnt_pkts \
+ + sta->sta_stats.last_rx_ctrl_pkts \
+ + sta->sta_stats.last_rx_data_pkts)
+
+#define sta_rx_data_pkts(sta) \
+ (sta->sta_stats.rx_data_pkts)
+
+#define sta_last_rx_data_pkts(sta) \
+ (sta->sta_stats.last_rx_data_pkts)
+
+#define sta_rx_mgnt_pkts(sta) \
+ (sta->sta_stats.rx_mgnt_pkts)
+
+#define sta_last_rx_mgnt_pkts(sta) \
+ (sta->sta_stats.last_rx_mgnt_pkts)
+
+#define sta_rx_beacon_pkts(sta) \
+ (sta->sta_stats.rx_beacon_pkts)
+
+#define sta_last_rx_beacon_pkts(sta) \
+ (sta->sta_stats.last_rx_beacon_pkts)
+
+#define sta_rx_probereq_pkts(sta) \
+ (sta->sta_stats.rx_probereq_pkts)
+
+#define sta_last_rx_probereq_pkts(sta) \
+ (sta->sta_stats.last_rx_probereq_pkts)
+
+#define sta_rx_probersp_pkts(sta) \
+ (sta->sta_stats.rx_probersp_pkts)
+
+#define sta_last_rx_probersp_pkts(sta) \
+ (sta->sta_stats.last_rx_probersp_pkts)
+
+#define sta_rx_probersp_bm_pkts(sta) \
+ (sta->sta_stats.rx_probersp_bm_pkts)
+
+#define sta_last_rx_probersp_bm_pkts(sta) \
+ (sta->sta_stats.last_rx_probersp_bm_pkts)
+
+#define sta_rx_probersp_uo_pkts(sta) \
+ (sta->sta_stats.rx_probersp_uo_pkts)
+
+#define sta_last_rx_probersp_uo_pkts(sta) \
+ (sta->sta_stats.last_rx_probersp_uo_pkts)
+
+#define sta_update_last_rx_pkts(sta) \
+do { \
+ sta->sta_stats.last_rx_mgnt_pkts = sta->sta_stats.rx_mgnt_pkts; \
+ sta->sta_stats.last_rx_beacon_pkts = sta->sta_stats.rx_beacon_pkts; \
+ sta->sta_stats.last_rx_probereq_pkts = sta->sta_stats.rx_probereq_pkts; \
+ sta->sta_stats.last_rx_probersp_pkts = sta->sta_stats.rx_probersp_pkts; \
+ sta->sta_stats.last_rx_probersp_bm_pkts = sta->sta_stats.rx_probersp_bm_pkts; \
+ sta->sta_stats.last_rx_probersp_uo_pkts = sta->sta_stats.rx_probersp_uo_pkts; \
+ sta->sta_stats.last_rx_ctrl_pkts = sta->sta_stats.rx_ctrl_pkts; \
+ sta->sta_stats.last_rx_data_pkts = sta->sta_stats.rx_data_pkts; \
+} while (0)
+
+#define STA_RX_PKTS_ARG(sta) \
+ sta->sta_stats.rx_mgnt_pkts \
+ , sta->sta_stats.rx_ctrl_pkts \
+ , sta->sta_stats.rx_data_pkts
+
+#define STA_LAST_RX_PKTS_ARG(sta) \
+ sta->sta_stats.last_rx_mgnt_pkts \
+ , sta->sta_stats.last_rx_ctrl_pkts \
+ , sta->sta_stats.last_rx_data_pkts
+
+#define STA_RX_PKTS_DIFF_ARG(sta) \
+ sta->sta_stats.rx_mgnt_pkts - sta->sta_stats.last_rx_mgnt_pkts \
+ , sta->sta_stats.rx_ctrl_pkts - sta->sta_stats.last_rx_ctrl_pkts \
+ , sta->sta_stats.rx_data_pkts - sta->sta_stats.last_rx_data_pkts
+
+#define STA_PKTS_FMT "(m:%llu, c:%llu, d:%llu)"
+
+struct sta_priv {
+ u8 *pallocated_stainfo_buf;
+ u8 *pstainfo_buf;
+ struct __queue free_sta_queue;
+
+ spinlock_t sta_hash_lock;
+ struct list_head sta_hash[NUM_STA];
+ int asoc_sta_count;
+ struct __queue sleep_q;
+ struct __queue wakeup_q;
+
+ struct adapter *padapter;
+
+ spinlock_t asoc_list_lock;
+ struct list_head asoc_list;
+
+#ifdef CONFIG_88EU_AP_MODE
+ struct list_head auth_list;
+ spinlock_t auth_list_lock;
+ u8 asoc_list_cnt;
+ u8 auth_list_cnt;
+
+ unsigned int auth_to; /* sec, time to expire in authenticating. */
+ unsigned int assoc_to; /* sec, time to expire before associating. */
+ unsigned int expire_to; /* sec , time to expire after associated. */
+
+ /* pointers to STA info; based on allocated AID or NULL if AID free
+ * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
+ * and so on
+ */
+ struct sta_info *sta_aid[NUM_STA];
+
+ u16 sta_dz_bitmap;/* only support 15 stations, staion aid bitmap
+ * for sleeping sta. */
+ u16 tim_bitmap; /* only support 15 stations, aid=0~15 mapping
+ * bit0~bit15 */
+
+ u16 max_num_sta;
+
+ struct wlan_acl_pool acl_list;
+#endif
+
+};
+
+static inline u32 wifi_mac_hash(u8 *mac)
+{
+ u32 x;
+
+ x = mac[0];
+ x = (x << 2) ^ mac[1];
+ x = (x << 2) ^ mac[2];
+ x = (x << 2) ^ mac[3];
+ x = (x << 2) ^ mac[4];
+ x = (x << 2) ^ mac[5];
+
+ x ^= x >> 8;
+ x = x & (NUM_STA - 1);
+ return x;
+}
+
+extern u32 _rtw_init_sta_priv(struct sta_priv *pstapriv);
+extern u32 _rtw_free_sta_priv(struct sta_priv *pstapriv);
+
+#define stainfo_offset_valid(offset) (offset < NUM_STA && offset >= 0)
+int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta);
+struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int off);
+
+extern struct sta_info *rtw_alloc_stainfo(struct sta_priv *stapriv, u8 *hwaddr);
+extern u32 rtw_free_stainfo(struct adapter *adapt, struct sta_info *psta);
+extern void rtw_free_all_stainfo(struct adapter *adapt);
+extern struct sta_info *rtw_get_stainfo(struct sta_priv *stapriv, u8 *hwaddr);
+extern u32 rtw_init_bcmc_stainfo(struct adapter *adapt);
+extern struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter);
+extern u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr);
+
+#endif /* _STA_INFO_H_ */
diff --git a/drivers/staging/rtl8188eu/include/usb_hal.h b/drivers/staging/rtl8188eu/include/usb_hal.h
new file mode 100644
index 00000000000..8a65995d5e4
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/usb_hal.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __USB_HAL_H__
+#define __USB_HAL_H__
+
+void rtl8188eu_set_hal_ops(struct adapter *padapter);
+#define hal_set_hal_ops rtl8188eu_set_hal_ops
+
+#endif /* __USB_HAL_H__ */
diff --git a/drivers/staging/rtl8188eu/include/usb_ops.h b/drivers/staging/rtl8188eu/include/usb_ops.h
new file mode 100644
index 00000000000..df342376553
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/usb_ops.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __USB_OPS_H_
+#define __USB_OPS_H_
+
+#include <linux/version.h>
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <osdep_intf.h>
+
+#define REALTEK_USB_VENQT_READ 0xC0
+#define REALTEK_USB_VENQT_WRITE 0x40
+#define REALTEK_USB_VENQT_CMD_REQ 0x05
+#define REALTEK_USB_VENQT_CMD_IDX 0x00
+
+enum{
+ VENDOR_WRITE = 0x00,
+ VENDOR_READ = 0x01,
+};
+#define ALIGNMENT_UNIT 16
+#define MAX_VENDOR_REQ_CMD_SIZE 254 /* 8188cu SIE Support */
+#define MAX_USB_IO_CTL_SIZE (MAX_VENDOR_REQ_CMD_SIZE + ALIGNMENT_UNIT)
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+#define rtw_usb_control_msg(dev, pipe, request, requesttype, \
+ value, index, data, size, timeout_ms) \
+ usb_control_msg((dev), (pipe), (request), (requesttype), (value),\
+ (index), (data), (size), (timeout_ms))
+#define rtw_usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout_ms) \
+ usb_bulk_msg((usb_dev), (pipe), (data), (len), \
+ (actual_length), (timeout_ms))
+#else
+#define rtw_usb_control_msg(dev, pipe, request, requesttype, \
+ value, index, data, size, timeout_ms) \
+ usb_control_msg((dev), (pipe), (request), (requesttype), \
+ (value), (index), (data), (size), \
+ ((timeout_ms) == 0) || \
+ ((timeout_ms)*HZ/1000 > 0) ? \
+ ((timeout_ms)*HZ/1000) : 1)
+#define rtw_usb_bulk_msg(usb_dev, pipe, data, len, \
+ actual_length, timeout_ms) \
+ usb_bulk_msg((usb_dev), (pipe), (data), (len), (actual_length), \
+ ((timeout_ms) == 0) || ((timeout_ms)*HZ/1000 > 0) ?\
+ ((timeout_ms)*HZ/1000) : 1)
+#endif
+#include <usb_ops_linux.h>
+
+void rtl8188eu_set_hw_type(struct adapter *padapter);
+#define hal_set_hw_type rtl8188eu_set_hw_type
+void rtl8188eu_set_intf_ops(struct _io_ops *pops);
+#define usb_set_intf_ops rtl8188eu_set_intf_ops
+
+/*
+ * Increase and check if the continual_urb_error of this @param dvobjprivei
+ * is larger than MAX_CONTINUAL_URB_ERR
+ * @return true:
+ * @return false:
+ */
+static inline int rtw_inc_and_chk_continual_urb_error(struct dvobj_priv *dvobj)
+{
+ int ret = false;
+ int value;
+ value = ATOMIC_INC_RETURN(&dvobj->continual_urb_error);
+ if (value > MAX_CONTINUAL_URB_ERR) {
+ DBG_88E("[dvobj:%p][ERROR] continual_urb_error:%d > %d\n",
+ dvobj, value, MAX_CONTINUAL_URB_ERR);
+ ret = true;
+ }
+ return ret;
+}
+
+/*
+* Set the continual_urb_error of this @param dvobjprive to 0
+*/
+static inline void rtw_reset_continual_urb_error(struct dvobj_priv *dvobj)
+{
+ ATOMIC_SET(&dvobj->continual_urb_error, 0);
+}
+
+#define USB_HIGH_SPEED_BULK_SIZE 512
+#define USB_FULL_SPEED_BULK_SIZE 64
+
+static inline u8 rtw_usb_bulk_size_boundary(struct adapter *padapter,
+ int buf_len)
+{
+ u8 rst = true;
+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+
+ if (pdvobjpriv->ishighspeed)
+ rst = (0 == (buf_len) % USB_HIGH_SPEED_BULK_SIZE) ?
+ true : false;
+ else
+ rst = (0 == (buf_len) % USB_FULL_SPEED_BULK_SIZE) ?
+ true : false;
+ return rst;
+}
+
+#endif /* __USB_OPS_H_ */
diff --git a/drivers/staging/rtl8188eu/include/usb_ops_linux.h b/drivers/staging/rtl8188eu/include/usb_ops_linux.h
new file mode 100644
index 00000000000..e5b758a81a5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/usb_ops_linux.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __USB_OPS_LINUX_H__
+#define __USB_OPS_LINUX_H__
+
+#define VENDOR_CMD_MAX_DATA_LEN 254
+
+#define RTW_USB_CONTROL_MSG_TIMEOUT_TEST 10/* ms */
+#define RTW_USB_CONTROL_MSG_TIMEOUT 500/* ms */
+
+#define MAX_USBCTRL_VENDORREQ_TIMES 10
+
+#define RTW_USB_BULKOUT_TIME 5000/* ms */
+
+#define _usbctrl_vendorreq_async_callback(urb, regs) \
+ _usbctrl_vendorreq_async_callback(urb)
+#define usb_bulkout_zero_complete(purb, regs) \
+ usb_bulkout_zero_complete(purb)
+#define usb_write_mem_complete(purb, regs) \
+ usb_write_mem_complete(purb)
+#define usb_write_port_complete(purb, regs) \
+ usb_write_port_complete(purb)
+#define usb_read_port_complete(purb, regs) \
+ usb_read_port_complete(purb)
+#define usb_read_interrupt_complete(purb, regs) \
+ usb_read_interrupt_complete(purb)
+
+unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr);
+
+void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem);
+void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem);
+
+void usb_read_port_cancel(struct intf_hdl *pintfhdl);
+
+u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem);
+void usb_write_port_cancel(struct intf_hdl *pintfhdl);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/usb_osintf.h b/drivers/staging/rtl8188eu/include/usb_osintf.h
new file mode 100644
index 00000000000..9de99ca9799
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/usb_osintf.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __USB_OSINTF_H
+#define __USB_OSINTF_H
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <usb_vendor_req.h>
+
+extern char *rtw_initmac;
+extern int rtw_mc2u_disable;
+
+#define USBD_HALTED(Status) ((u32)(Status) >> 30 == 3)
+
+u8 usbvendorrequest(struct dvobj_priv *pdvobjpriv, enum bt_usb_request brequest,
+ enum rt_usb_wvalue wvalue, u8 windex, void *data,
+ u8 datalen, u8 isdirectionin);
+int pm_netdev_open(struct net_device *pnetdev, u8 bnormal);
+void netdev_br_init(struct net_device *netdev);
+void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb);
+void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr,
+ unsigned char *ipAddr);
+void nat25_db_expire(struct adapter *priv);
+int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method);
+
+int rtw_resume_process(struct adapter *padapter);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/usb_vendor_req.h b/drivers/staging/rtl8188eu/include/usb_vendor_req.h
new file mode 100644
index 00000000000..7f26c8f2c78
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/usb_vendor_req.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _USB_VENDOR_REQUEST_H_
+#define _USB_VENDOR_REQUEST_H_
+
+/* 4 Set/Get Register related wIndex/Data */
+#define RT_USB_RESET_MASK_OFF 0
+#define RT_USB_RESET_MASK_ON 1
+#define RT_USB_SLEEP_MASK_OFF 0
+#define RT_USB_SLEEP_MASK_ON 1
+#define RT_USB_LDO_ON 1
+#define RT_USB_LDO_OFF 0
+
+/* 4 Set/Get SYSCLK related wValue or Data */
+#define RT_USB_SYSCLK_32KHZ 0
+#define RT_USB_SYSCLK_40MHZ 1
+#define RT_USB_SYSCLK_60MHZ 2
+
+
+enum bt_usb_request {
+ RT_USB_SET_REGISTER = 1,
+ RT_USB_SET_SYSCLK = 2,
+ RT_USB_GET_SYSCLK = 3,
+ RT_USB_GET_REGISTER = 4
+};
+
+enum rt_usb_wvalue {
+ RT_USB_RESET_MASK = 1,
+ RT_USB_SLEEP_MASK = 2,
+ RT_USB_USB_HRCPWM = 3,
+ RT_USB_LDO = 4,
+ RT_USB_BOOT_TYPE = 5
+};
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/wifi.h b/drivers/staging/rtl8188eu/include/wifi.h
new file mode 100644
index 00000000000..a615659f947
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/wifi.h
@@ -0,0 +1,1127 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef _WIFI_H_
+#define _WIFI_H_
+
+
+#ifdef BIT
+/* error "BIT define occurred earlier elsewhere!\n" */
+#undef BIT
+#endif
+#define BIT(x) (1 << (x))
+
+
+#define WLAN_ETHHDR_LEN 14
+#define WLAN_ETHADDR_LEN 6
+#define WLAN_IEEE_OUI_LEN 3
+#define WLAN_ADDR_LEN 6
+#define WLAN_CRC_LEN 4
+#define WLAN_BSSID_LEN 6
+#define WLAN_BSS_TS_LEN 8
+#define WLAN_HDR_A3_LEN 24
+#define WLAN_HDR_A4_LEN 30
+#define WLAN_HDR_A3_QOS_LEN 26
+#define WLAN_HDR_A4_QOS_LEN 32
+#define WLAN_SSID_MAXLEN 32
+#define WLAN_DATA_MAXLEN 2312
+
+#define WLAN_A3_PN_OFFSET 24
+#define WLAN_A4_PN_OFFSET 30
+
+#define WLAN_MIN_ETHFRM_LEN 60
+#define WLAN_MAX_ETHFRM_LEN 1514
+#define WLAN_ETHHDR_LEN 14
+
+#define P80211CAPTURE_VERSION 0x80211001
+
+/* This value is tested by WiFi 11n Test Plan 5.2.3. */
+/* This test verifies the WLAN NIC can update the NAV through sending
+ * the CTS with large duration. */
+#define WiFiNavUpperUs 30000 /* 30 ms */
+
+enum WIFI_FRAME_TYPE {
+ WIFI_MGT_TYPE = (0),
+ WIFI_CTRL_TYPE = (BIT(2)),
+ WIFI_DATA_TYPE = (BIT(3)),
+ WIFI_QOS_DATA_TYPE = (BIT(7)|BIT(3)), /* QoS Data */
+};
+
+enum WIFI_FRAME_SUBTYPE {
+ /* below is for mgt frame */
+ WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE),
+ WIFI_ASSOCRSP = (BIT(4) | WIFI_MGT_TYPE),
+ WIFI_REASSOCREQ = (BIT(5) | WIFI_MGT_TYPE),
+ WIFI_REASSOCRSP = (BIT(5) | BIT(4) | WIFI_MGT_TYPE),
+ WIFI_PROBEREQ = (BIT(6) | WIFI_MGT_TYPE),
+ WIFI_PROBERSP = (BIT(6) | BIT(4) | WIFI_MGT_TYPE),
+ WIFI_BEACON = (BIT(7) | WIFI_MGT_TYPE),
+ WIFI_ATIM = (BIT(7) | BIT(4) | WIFI_MGT_TYPE),
+ WIFI_DISASSOC = (BIT(7) | BIT(5) | WIFI_MGT_TYPE),
+ WIFI_AUTH = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE),
+ WIFI_DEAUTH = (BIT(7) | BIT(6) | WIFI_MGT_TYPE),
+ WIFI_ACTION = (BIT(7) | BIT(6) | BIT(4) | WIFI_MGT_TYPE),
+
+ /* below is for control frame */
+ WIFI_PSPOLL = (BIT(7) | BIT(5) | WIFI_CTRL_TYPE),
+ WIFI_RTS = (BIT(7) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE),
+ WIFI_CTS = (BIT(7) | BIT(6) | WIFI_CTRL_TYPE),
+ WIFI_ACK = (BIT(7) | BIT(6) | BIT(4) | WIFI_CTRL_TYPE),
+ WIFI_CFEND = (BIT(7) | BIT(6) | BIT(5) | WIFI_CTRL_TYPE),
+ WIFI_CFEND_CFACK = (BIT(7) | BIT(6) | BIT(5) | BIT(4) |
+ WIFI_CTRL_TYPE),
+
+ /* below is for data frame */
+ WIFI_DATA = (0 | WIFI_DATA_TYPE),
+ WIFI_DATA_CFACK = (BIT(4) | WIFI_DATA_TYPE),
+ WIFI_DATA_CFPOLL = (BIT(5) | WIFI_DATA_TYPE),
+ WIFI_DATA_CFACKPOLL = (BIT(5) | BIT(4) | WIFI_DATA_TYPE),
+ WIFI_DATA_NULL = (BIT(6) | WIFI_DATA_TYPE),
+ WIFI_CF_ACK = (BIT(6) | BIT(4) | WIFI_DATA_TYPE),
+ WIFI_CF_POLL = (BIT(6) | BIT(5) | WIFI_DATA_TYPE),
+ WIFI_CF_ACKPOLL = (BIT(6) | BIT(5) | BIT(4) | WIFI_DATA_TYPE),
+ WIFI_QOS_DATA_NULL = (BIT(6) | WIFI_QOS_DATA_TYPE),
+};
+
+enum WIFI_REASON_CODE {
+ _RSON_RESERVED_ = 0,
+ _RSON_UNSPECIFIED_ = 1,
+ _RSON_AUTH_NO_LONGER_VALID_ = 2,
+ _RSON_DEAUTH_STA_LEAVING_ = 3,
+ _RSON_INACTIVITY_ = 4,
+ _RSON_UNABLE_HANDLE_ = 5,
+ _RSON_CLS2_ = 6,
+ _RSON_CLS3_ = 7,
+ _RSON_DISAOC_STA_LEAVING_ = 8,
+ _RSON_ASOC_NOT_AUTH_ = 9,
+
+ /* WPA reason */
+ _RSON_INVALID_IE_ = 13,
+ _RSON_MIC_FAILURE_ = 14,
+ _RSON_4WAY_HNDSHK_TIMEOUT_ = 15,
+ _RSON_GROUP_KEY_UPDATE_TIMEOUT_ = 16,
+ _RSON_DIFF_IE_ = 17,
+ _RSON_MLTCST_CIPHER_NOT_VALID_ = 18,
+ _RSON_UNICST_CIPHER_NOT_VALID_ = 19,
+ _RSON_AKMP_NOT_VALID_ = 20,
+ _RSON_UNSUPPORT_RSNE_VER_ = 21,
+ _RSON_INVALID_RSNE_CAP_ = 22,
+ _RSON_IEEE_802DOT1X_AUTH_FAIL_ = 23,
+
+ /* belowing are Realtek definition */
+ _RSON_PMK_NOT_AVAILABLE_ = 24,
+ _RSON_TDLS_TEAR_TOOFAR_ = 25,
+ _RSON_TDLS_TEAR_UN_RSN_ = 26,
+};
+
+/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22)
+
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 */
+/* IEEE 802.11h */
+#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
+#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
+
+/* IEEE 802.11i
+#define WLAN_REASON_INVALID_IE 13
+#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
+#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
+#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
+#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
+#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
+#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
+#define WLAN_REASON_AKMP_NOT_VALID 20
+#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
+#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
+#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
+#define WLAN_REASON_CIPHER_SUITE_REJECTED 24 */
+
+enum WIFI_STATUS_CODE {
+ _STATS_SUCCESSFUL_ = 0,
+ _STATS_FAILURE_ = 1,
+ _STATS_CAP_FAIL_ = 10,
+ _STATS_NO_ASOC_ = 11,
+ _STATS_OTHER_ = 12,
+ _STATS_NO_SUPP_ALG_ = 13,
+ _STATS_OUT_OF_AUTH_SEQ_ = 14,
+ _STATS_CHALLENGE_FAIL_ = 15,
+ _STATS_AUTH_TIMEOUT_ = 16,
+ _STATS_UNABLE_HANDLE_STA_ = 17,
+ _STATS_RATE_FAIL_ = 18,
+};
+
+/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23)
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18 */
+
+/* entended */
+/* IEEE 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+/* IEEE 802.11h */
+#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
+#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
+#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
+/* IEEE 802.11g */
+#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
+#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
+#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
+/* IEEE 802.11w */
+#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
+#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
+/* IEEE 802.11i */
+#define WLAN_STATUS_INVALID_IE 40
+#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
+#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
+#define WLAN_STATUS_AKMP_NOT_VALID 43
+#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
+#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
+#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
+#define WLAN_STATUS_TS_NOT_CREATED 47
+#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
+#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
+#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
+#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
+/* IEEE 802.11r */
+#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
+#define WLAN_STATUS_INVALID_PMKID 53
+#define WLAN_STATUS_INVALID_MDIE 54
+#define WLAN_STATUS_INVALID_FTIE 55
+
+enum WIFI_REG_DOMAIN {
+ DOMAIN_FCC = 1,
+ DOMAIN_IC = 2,
+ DOMAIN_ETSI = 3,
+ DOMAIN_SPA = 4,
+ DOMAIN_FRANCE = 5,
+ DOMAIN_MKK = 6,
+ DOMAIN_ISRAEL = 7,
+ DOMAIN_MKK1 = 8,
+ DOMAIN_MKK2 = 9,
+ DOMAIN_MKK3 = 10,
+ DOMAIN_MAX
+};
+
+#define _TO_DS_ BIT(8)
+#define _FROM_DS_ BIT(9)
+#define _MORE_FRAG_ BIT(10)
+#define _RETRY_ BIT(11)
+#define _PWRMGT_ BIT(12)
+#define _MORE_DATA_ BIT(13)
+#define _PRIVACY_ BIT(14)
+#define _ORDER_ BIT(15)
+
+#define SetToDs(pbuf) \
+ *(__le16 *)(pbuf) |= cpu_to_le16(_TO_DS_)
+
+#define GetToDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_TO_DS_)) != 0)
+
+#define ClearToDs(pbuf) \
+ *(__le16 *)(pbuf) &= (~cpu_to_le16(_TO_DS_))
+
+#define SetFrDs(pbuf) \
+ *(__le16 *)(pbuf) |= cpu_to_le16(_FROM_DS_)
+
+#define GetFrDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_FROM_DS_)) != 0)
+
+#define ClearFrDs(pbuf) \
+ *(__le16 *)(pbuf) &= (~cpu_to_le16(_FROM_DS_))
+
+#define get_tofr_ds(pframe) ((GetToDs(pframe) << 1) | GetFrDs(pframe))
+
+
+#define SetMFrag(pbuf) \
+ *(__le16 *)(pbuf) |= cpu_to_le16(_MORE_FRAG_)
+
+#define GetMFrag(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_FRAG_)) != 0)
+
+#define ClearMFrag(pbuf) \
+ *(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_FRAG_))
+
+#define SetRetry(pbuf) \
+ *(__le16 *)(pbuf) |= cpu_to_le16(_RETRY_)
+
+#define GetRetry(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_RETRY_)) != 0)
+
+#define ClearRetry(pbuf) \
+ *(__le16 *)(pbuf) &= (~cpu_to_le16(_RETRY_))
+
+#define SetPwrMgt(pbuf) \
+ *(__le16 *)(pbuf) |= cpu_to_le16(_PWRMGT_)
+
+#define GetPwrMgt(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_PWRMGT_)) != 0)
+
+#define ClearPwrMgt(pbuf) \
+ *(__le16 *)(pbuf) &= (~cpu_to_le16(_PWRMGT_))
+
+#define SetMData(pbuf) \
+ *(__le16 *)(pbuf) |= cpu_to_le16(_MORE_DATA_)
+
+#define GetMData(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_DATA_)) != 0)
+
+#define ClearMData(pbuf) \
+ *(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_DATA_))
+
+#define SetPrivacy(pbuf) \
+ *(__le16 *)(pbuf) |= cpu_to_le16(_PRIVACY_)
+
+#define GetPrivacy(pbuf) \
+ (((*(__le16 *)(pbuf)) & cpu_to_le16(_PRIVACY_)) != 0)
+
+#define ClearPrivacy(pbuf) \
+ *(__le16 *)(pbuf) &= (~cpu_to_le16(_PRIVACY_))
+
+
+#define GetOrder(pbuf) \
+ (((*(__le16 *)(pbuf)) & cpu_to_le16(_ORDER_)) != 0)
+
+#define GetFrameType(pbuf) \
+ (le16_to_cpu(*(__le16 *)(pbuf)) & (BIT(3) | BIT(2)))
+
+#define SetFrameType(pbuf, type) \
+ do { \
+ *(unsigned short *)(pbuf) &= __constant_cpu_to_le16(~(BIT(3) | BIT(2))); \
+ *(unsigned short *)(pbuf) |= __constant_cpu_to_le16(type); \
+ } while (0)
+
+#define GetFrameSubType(pbuf) (le16_to_cpu(*(__le16 *)(pbuf)) & (BIT(7) |\
+ BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2)))
+
+#define SetFrameSubType(pbuf, type) \
+ do { \
+ *(__le16 *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) | \
+ BIT(5) | BIT(4) | BIT(3) | BIT(2))); \
+ *(__le16 *)(pbuf) |= cpu_to_le16(type); \
+ } while (0)
+
+#define GetSequence(pbuf) \
+ (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 22)) >> 4)
+
+#define GetFragNum(pbuf) \
+ (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 22)) & 0x0f)
+
+#define GetTupleCache(pbuf) \
+ (cpu_to_le16(*(unsigned short *)((size_t)(pbuf) + 22)))
+
+#define SetFragNum(pbuf, num) \
+ do { \
+ *(unsigned short *)((size_t)(pbuf) + 22) = \
+ ((*(unsigned short *)((size_t)(pbuf) + 22)) & \
+ le16_to_cpu(~(0x000f))) | \
+ cpu_to_le16(0x0f & (num)); \
+ } while (0)
+
+#define SetSeqNum(pbuf, num) \
+ do { \
+ *(__le16 *)((size_t)(pbuf) + 22) = \
+ ((*(__le16 *)((size_t)(pbuf) + 22)) & cpu_to_le16((unsigned short)0x000f)) | \
+ cpu_to_le16((unsigned short)(0xfff0 & (num << 4))); \
+ } while (0)
+
+#define SetDuration(pbuf, dur) \
+ *(__le16 *)((size_t)(pbuf) + 2) = cpu_to_le16(0xffff & (dur))
+
+
+#define SetPriority(pbuf, tid) \
+ *(__le16 *)(pbuf) |= cpu_to_le16(tid & 0xf)
+
+#define GetPriority(pbuf) ((le16_to_cpu(*(__le16 *)(pbuf))) & 0xf)
+
+#define SetEOSP(pbuf, eosp) \
+ *(__le16 *)(pbuf) |= cpu_to_le16((eosp & 1) << 4)
+
+#define SetAckpolicy(pbuf, ack) \
+ *(__le16 *)(pbuf) |= cpu_to_le16((ack & 3) << 5)
+
+#define GetAckpolicy(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 5) & 0x3)
+
+#define GetAMsdu(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 7) & 0x1)
+
+#define SetAMsdu(pbuf, amsdu) \
+ *(__le16 *)(pbuf) |= cpu_to_le16((amsdu & 1) << 7)
+
+#define GetAid(pbuf) (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 2)) & 0x3fff)
+
+#define GetTid(pbuf) (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + \
+ (((GetToDs(pbuf)<<1) | GetFrDs(pbuf)) == 3 ? \
+ 30 : 24))) & 0x000f)
+
+#define GetAddr1Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 4))
+
+#define GetAddr2Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 10))
+
+#define GetAddr3Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 16))
+
+#define GetAddr4Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 24))
+
+#define MacAddr_isBcst(addr) \
+ ( \
+ ((addr[0] == 0xff) && (addr[1] == 0xff) && \
+ (addr[2] == 0xff) && (addr[3] == 0xff) && \
+ (addr[4] == 0xff) && (addr[5] == 0xff)) ? true : false \
+)
+
+static inline int IS_MCAST(unsigned char *da)
+{
+ if ((*da) & 0x01)
+ return true;
+ else
+ return false;
+}
+
+static inline unsigned char *get_da(unsigned char *pframe)
+{
+ unsigned char *da;
+ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
+
+ switch (to_fr_ds) {
+ case 0x00: /* ToDs=0, FromDs=0 */
+ da = GetAddr1Ptr(pframe);
+ break;
+ case 0x01: /* ToDs=0, FromDs=1 */
+ da = GetAddr1Ptr(pframe);
+ break;
+ case 0x02: /* ToDs=1, FromDs=0 */
+ da = GetAddr3Ptr(pframe);
+ break;
+ default: /* ToDs=1, FromDs=1 */
+ da = GetAddr3Ptr(pframe);
+ break;
+ }
+ return da;
+}
+
+static inline unsigned char *get_sa(unsigned char *pframe)
+{
+ unsigned char *sa;
+ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
+
+ switch (to_fr_ds) {
+ case 0x00: /* ToDs=0, FromDs=0 */
+ sa = GetAddr2Ptr(pframe);
+ break;
+ case 0x01: /* ToDs=0, FromDs=1 */
+ sa = GetAddr3Ptr(pframe);
+ break;
+ case 0x02: /* ToDs=1, FromDs=0 */
+ sa = GetAddr2Ptr(pframe);
+ break;
+ default: /* ToDs=1, FromDs=1 */
+ sa = GetAddr4Ptr(pframe);
+ break;
+ }
+ return sa;
+}
+
+static inline unsigned char *get_hdr_bssid(unsigned char *pframe)
+{
+ unsigned char *sa;
+ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
+
+ switch (to_fr_ds) {
+ case 0x00: /* ToDs=0, FromDs=0 */
+ sa = GetAddr3Ptr(pframe);
+ break;
+ case 0x01: /* ToDs=0, FromDs=1 */
+ sa = GetAddr2Ptr(pframe);
+ break;
+ case 0x02: /* ToDs=1, FromDs=0 */
+ sa = GetAddr1Ptr(pframe);
+ break;
+ case 0x03: /* ToDs=1, FromDs=1 */
+ sa = GetAddr1Ptr(pframe);
+ break;
+ default:
+ sa = NULL; /* */
+ break;
+ }
+ return sa;
+}
+
+static inline int IsFrameTypeCtrl(unsigned char *pframe)
+{
+ if (WIFI_CTRL_TYPE == GetFrameType(pframe))
+ return true;
+ else
+ return false;
+}
+/*-----------------------------------------------------------------------------
+ Below is for the security related definition
+------------------------------------------------------------------------------*/
+#define _RESERVED_FRAME_TYPE_ 0
+#define _SKB_FRAME_TYPE_ 2
+#define _PRE_ALLOCMEM_ 1
+#define _PRE_ALLOCHDR_ 3
+#define _PRE_ALLOCLLCHDR_ 4
+#define _PRE_ALLOCICVHDR_ 5
+#define _PRE_ALLOCMICHDR_ 6
+
+#define _SIFSTIME_ \
+ ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11A) ? 16 : 10)
+#define _ACKCTSLNG_ 14 /* 14 bytes long, including crclng */
+#define _CRCLNG_ 4
+
+#define _ASOCREQ_IE_OFFSET_ 4 /* excluding wlan_hdr */
+#define _ASOCRSP_IE_OFFSET_ 6
+#define _REASOCREQ_IE_OFFSET_ 10
+#define _REASOCRSP_IE_OFFSET_ 6
+#define _PROBEREQ_IE_OFFSET_ 0
+#define _PROBERSP_IE_OFFSET_ 12
+#define _AUTH_IE_OFFSET_ 6
+#define _DEAUTH_IE_OFFSET_ 0
+#define _BEACON_IE_OFFSET_ 12
+#define _PUBLIC_ACTION_IE_OFFSET_ 8
+
+#define _FIXED_IE_LENGTH_ _BEACON_IE_OFFSET_
+
+#define _SSID_IE_ 0
+#define _SUPPORTEDRATES_IE_ 1
+#define _DSSET_IE_ 3
+#define _TIM_IE_ 5
+#define _IBSS_PARA_IE_ 6
+#define _COUNTRY_IE_ 7
+#define _CHLGETXT_IE_ 16
+#define _SUPPORTED_CH_IE_ 36
+#define _CH_SWTICH_ANNOUNCE_ 37 /* Secondary Channel Offset */
+#define _RSN_IE_2_ 48
+#define _SSN_IE_1_ 221
+#define _ERPINFO_IE_ 42
+#define _EXT_SUPPORTEDRATES_IE_ 50
+
+#define _HT_CAPABILITY_IE_ 45
+#define _FTIE_ 55
+#define _TIMEOUT_ITVL_IE_ 56
+#define _SRC_IE_ 59
+#define _HT_EXTRA_INFO_IE_ 61
+#define _HT_ADD_INFO_IE_ 61 /* _HT_EXTRA_INFO_IE_ */
+#define _WAPI_IE_ 68
+
+
+#define EID_BSSCoexistence 72 /* 20/40 BSS Coexistence */
+#define EID_BSSIntolerantChlReport 73
+#define _RIC_Descriptor_IE_ 75
+
+#define _LINK_ID_IE_ 101
+#define _CH_SWITCH_TIMING_ 104
+#define _PTI_BUFFER_STATUS_ 106
+#define _EXT_CAP_IE_ 127
+#define _VENDOR_SPECIFIC_IE_ 221
+
+#define _RESERVED47_ 47
+
+/* ---------------------------------------------------------------------------
+ Below is the fixed elements...
+-----------------------------------------------------------------------------*/
+#define _AUTH_ALGM_NUM_ 2
+#define _AUTH_SEQ_NUM_ 2
+#define _BEACON_ITERVAL_ 2
+#define _CAPABILITY_ 2
+#define _CURRENT_APADDR_ 6
+#define _LISTEN_INTERVAL_ 2
+#define _RSON_CODE_ 2
+#define _ASOC_ID_ 2
+#define _STATUS_CODE_ 2
+#define _TIMESTAMP_ 8
+
+#define AUTH_ODD_TO 0
+#define AUTH_EVEN_TO 1
+
+#define WLAN_ETHCONV_ENCAP 1
+#define WLAN_ETHCONV_RFC1042 2
+#define WLAN_ETHCONV_8021h 3
+
+#define cap_ESS BIT(0)
+#define cap_IBSS BIT(1)
+#define cap_CFPollable BIT(2)
+#define cap_CFRequest BIT(3)
+#define cap_Privacy BIT(4)
+#define cap_ShortPremble BIT(5)
+#define cap_PBCC BIT(6)
+#define cap_ChAgility BIT(7)
+#define cap_SpecMgmt BIT(8)
+#define cap_QoSi BIT(9)
+#define cap_ShortSlot BIT(10)
+
+/*-----------------------------------------------------------------------------
+ Below is the definition for 802.11i / 802.1x
+------------------------------------------------------------------------------*/
+#define _IEEE8021X_MGT_ 1 /* WPA */
+#define _IEEE8021X_PSK_ 2 /* WPA with pre-shared key */
+
+/*
+#define _NO_PRIVACY_ 0
+#define _WEP_40_PRIVACY_ 1
+#define _TKIP_PRIVACY_ 2
+#define _WRAP_PRIVACY_ 3
+#define _CCMP_PRIVACY_ 4
+#define _WEP_104_PRIVACY_ 5
+#define _WEP_WPA_MIXED_PRIVACY_ 6 WEP + WPA
+*/
+
+/*-----------------------------------------------------------------------------
+ Below is the definition for WMM
+------------------------------------------------------------------------------*/
+#define _WMM_IE_Length_ 7 /* for WMM STA */
+#define _WMM_Para_Element_Length_ 24
+
+
+/*-----------------------------------------------------------------------------
+ Below is the definition for 802.11n
+------------------------------------------------------------------------------*/
+
+#define SetOrderBit(pbuf) \
+ do { \
+ *(unsigned short *)(pbuf) |= cpu_to_le16(_ORDER_); \
+ } while (0)
+
+#define GetOrderBit(pbuf) \
+ (((*(unsigned short *)(pbuf)) & le16_to_cpu(_ORDER_)) != 0)
+
+
+/**
+ * struct rtw_ieee80211_bar - HT Block Ack Request
+ *
+ * This structure refers to "HT BlockAckReq" as
+ * described in 802.11n draft section 7.2.1.7.1
+ */
+struct rtw_ieee80211_bar {
+ unsigned short frame_control;
+ unsigned short duration;
+ unsigned char ra[6];
+ unsigned char ta[6];
+ unsigned short control;
+ unsigned short start_seq_num;
+} __packed;
+
+/* 802.11 BAR control masks */
+#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000
+#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004
+
+ /**
+ * struct rtw_ieee80211_ht_cap - HT capabilities
+ *
+ * This structure refers to "HT capabilities element" as
+ * described in 802.11n draft section 7.3.2.52
+ */
+
+struct rtw_ieee80211_ht_cap {
+ unsigned short cap_info;
+ unsigned char ampdu_params_info;
+ unsigned char supp_mcs_set[16];
+ unsigned short extended_ht_cap_info;
+ unsigned int tx_BF_cap_info;
+ unsigned char antenna_selection_info;
+} __packed;
+
+/**
+ * struct rtw_ieee80211_ht_cap - HT additional information
+ *
+ * This structure refers to "HT information element" as
+ * described in 802.11n draft section 7.3.2.53
+ */
+struct ieee80211_ht_addt_info {
+ unsigned char control_chan;
+ unsigned char ht_param;
+ unsigned short operation_mode;
+ unsigned short stbc_param;
+ unsigned char basic_set[16];
+} __packed;
+
+struct HT_caps_element {
+ union {
+ struct {
+ __le16 HT_caps_info;
+ unsigned char AMPDU_para;
+ unsigned char MCS_rate[16];
+ unsigned short HT_ext_caps;
+ unsigned int Beamforming_caps;
+ unsigned char ASEL_caps;
+ } HT_cap_element;
+ unsigned char HT_cap[26];
+ } u;
+} __packed;
+
+struct HT_info_element {
+ unsigned char primary_channel;
+ unsigned char infos[5];
+ unsigned char MCS_rate[16];
+} __packed;
+
+struct AC_param {
+ unsigned char ACI_AIFSN;
+ unsigned char CW;
+ __le16 TXOP_limit;
+} __packed;
+
+struct WMM_para_element {
+ unsigned char QoS_info;
+ unsigned char reserved;
+ struct AC_param ac_param[4];
+} __packed;
+
+struct ADDBA_request {
+ unsigned char dialog_token;
+ unsigned short BA_para_set;
+ unsigned short BA_timeout_value;
+ unsigned short BA_starting_seqctrl;
+} __packed;
+
+enum ht_cap_ampdu_factor {
+ MAX_AMPDU_FACTOR_8K = 0,
+ MAX_AMPDU_FACTOR_16K = 1,
+ MAX_AMPDU_FACTOR_32K = 2,
+ MAX_AMPDU_FACTOR_64K = 3,
+};
+
+/* 802.11n HT capabilities masks */
+#define IEEE80211_HT_CAP_SUP_WIDTH 0x0002
+#define IEEE80211_HT_CAP_SM_PS 0x000C
+#define IEEE80211_HT_CAP_GRN_FLD 0x0010
+#define IEEE80211_HT_CAP_SGI_20 0x0020
+#define IEEE80211_HT_CAP_SGI_40 0x0040
+#define IEEE80211_HT_CAP_TX_STBC 0x0080
+#define IEEE80211_HT_CAP_RX_STBC 0x0300
+#define IEEE80211_HT_CAP_DELAY_BA 0x0400
+#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800
+#define IEEE80211_HT_CAP_DSSSCCK40 0x1000
+/* 802.11n HT capability AMPDU settings */
+#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03
+#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C
+/* 802.11n HT capability MSC set */
+#define IEEE80211_SUPP_MCS_SET_UEQM 4
+#define IEEE80211_HT_CAP_MAX_STREAMS 4
+#define IEEE80211_SUPP_MCS_SET_LEN 10
+/* maximum streams the spec allows */
+#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01
+#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02
+#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C
+#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10
+/* 802.11n HT IE masks */
+#define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03
+#define IEEE80211_HT_IE_CHA_SEC_NONE 0x00
+#define IEEE80211_HT_IE_CHA_SEC_ABOVE 0x01
+#define IEEE80211_HT_IE_CHA_SEC_BELOW 0x03
+#define IEEE80211_HT_IE_CHA_WIDTH 0x04
+#define IEEE80211_HT_IE_HT_PROTECTION 0x0003
+#define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004
+#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010
+
+/* block-ack parameters */
+#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
+#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
+#define RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0
+#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
+#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
+
+/*
+ * A-PMDU buffer sizes
+ * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
+ */
+#define IEEE80211_MIN_AMPDU_BUF 0x8
+#define IEEE80211_MAX_AMPDU_BUF 0x40
+
+
+/* Spatial Multiplexing Power Save Modes */
+#define WLAN_HT_CAP_SM_PS_STATIC 0
+#define WLAN_HT_CAP_SM_PS_DYNAMIC 1
+#define WLAN_HT_CAP_SM_PS_INVALID 2
+#define WLAN_HT_CAP_SM_PS_DISABLED 3
+
+
+#define OP_MODE_PURE 0
+#define OP_MODE_MAY_BE_LEGACY_STAS 1
+#define OP_MODE_20MHZ_HT_STA_ASSOCED 2
+#define OP_MODE_MIXED 3
+
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2))
+#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3))
+#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4))
+#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5))
+
+#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \
+ ((u16) (0x0001 | 0x0002))
+#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0
+#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2))
+#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3))
+#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4))
+
+#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6))
+#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7))
+#define HT_INFO_STBC_PARAM_SECONDARY_BC ((u16) BIT(8))
+#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9))
+#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10))
+#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11))
+
+/* ===============WPS Section=============== */
+/* For WPSv1.0 */
+#define WPSOUI 0x0050f204
+/* WPS attribute ID */
+#define WPS_ATTR_VER1 0x104A
+#define WPS_ATTR_SIMPLE_CONF_STATE 0x1044
+#define WPS_ATTR_RESP_TYPE 0x103B
+#define WPS_ATTR_UUID_E 0x1047
+#define WPS_ATTR_MANUFACTURER 0x1021
+#define WPS_ATTR_MODEL_NAME 0x1023
+#define WPS_ATTR_MODEL_NUMBER 0x1024
+#define WPS_ATTR_SERIAL_NUMBER 0x1042
+#define WPS_ATTR_PRIMARY_DEV_TYPE 0x1054
+#define WPS_ATTR_SEC_DEV_TYPE_LIST 0x1055
+#define WPS_ATTR_DEVICE_NAME 0x1011
+#define WPS_ATTR_CONF_METHOD 0x1008
+#define WPS_ATTR_RF_BANDS 0x103C
+#define WPS_ATTR_DEVICE_PWID 0x1012
+#define WPS_ATTR_REQUEST_TYPE 0x103A
+#define WPS_ATTR_ASSOCIATION_STATE 0x1002
+#define WPS_ATTR_CONFIG_ERROR 0x1009
+#define WPS_ATTR_VENDOR_EXT 0x1049
+#define WPS_ATTR_SELECTED_REGISTRAR 0x1041
+
+/* Value of WPS attribute "WPS_ATTR_DEVICE_NAME */
+#define WPS_MAX_DEVICE_NAME_LEN 32
+
+/* Value of WPS Request Type Attribute */
+#define WPS_REQ_TYPE_ENROLLEE_INFO_ONLY 0x00
+#define WPS_REQ_TYPE_ENROLLEE_OPEN_8021X 0x01
+#define WPS_REQ_TYPE_REGISTRAR 0x02
+#define WPS_REQ_TYPE_WLAN_MANAGER_REGISTRAR 0x03
+
+/* Value of WPS Response Type Attribute */
+#define WPS_RESPONSE_TYPE_INFO_ONLY 0x00
+#define WPS_RESPONSE_TYPE_8021X 0x01
+#define WPS_RESPONSE_TYPE_REGISTRAR 0x02
+#define WPS_RESPONSE_TYPE_AP 0x03
+
+/* Value of WPS WiFi Simple Configuration State Attribute */
+#define WPS_WSC_STATE_NOT_CONFIG 0x01
+#define WPS_WSC_STATE_CONFIG 0x02
+
+/* Value of WPS Version Attribute */
+#define WPS_VERSION_1 0x10
+
+/* Value of WPS Configuration Method Attribute */
+#define WPS_CONFIG_METHOD_FLASH 0x0001
+#define WPS_CONFIG_METHOD_ETHERNET 0x0002
+#define WPS_CONFIG_METHOD_LABEL 0x0004
+#define WPS_CONFIG_METHOD_DISPLAY 0x0008
+#define WPS_CONFIG_METHOD_E_NFC 0x0010
+#define WPS_CONFIG_METHOD_I_NFC 0x0020
+#define WPS_CONFIG_METHOD_NFC 0x0040
+#define WPS_CONFIG_METHOD_PBC 0x0080
+#define WPS_CONFIG_METHOD_KEYPAD 0x0100
+#define WPS_CONFIG_METHOD_VPBC 0x0280
+#define WPS_CONFIG_METHOD_PPBC 0x0480
+#define WPS_CONFIG_METHOD_VDISPLAY 0x2008
+#define WPS_CONFIG_METHOD_PDISPLAY 0x4008
+
+/* Value of Category ID of WPS Primary Device Type Attribute */
+#define WPS_PDT_CID_DISPLAYS 0x0007
+#define WPS_PDT_CID_MULIT_MEDIA 0x0008
+#define WPS_PDT_CID_RTK_WIDI WPS_PDT_CID_MULIT_MEDIA
+
+/* Value of Sub Category ID of WPS Primary Device Type Attribute */
+#define WPS_PDT_SCID_MEDIA_SERVER 0x0005
+#define WPS_PDT_SCID_RTK_DMP WPS_PDT_SCID_MEDIA_SERVER
+
+/* Value of Device Password ID */
+#define WPS_DPID_P 0x0000
+#define WPS_DPID_USER_SPEC 0x0001
+#define WPS_DPID_MACHINE_SPEC 0x0002
+#define WPS_DPID_REKEY 0x0003
+#define WPS_DPID_PBC 0x0004
+#define WPS_DPID_REGISTRAR_SPEC 0x0005
+
+/* Value of WPS RF Bands Attribute */
+#define WPS_RF_BANDS_2_4_GHZ 0x01
+#define WPS_RF_BANDS_5_GHZ 0x02
+
+/* Value of WPS Association State Attribute */
+#define WPS_ASSOC_STATE_NOT_ASSOCIATED 0x00
+#define WPS_ASSOC_STATE_CONNECTION_SUCCESS 0x01
+#define WPS_ASSOC_STATE_CONFIGURATION_FAILURE 0x02
+#define WPS_ASSOC_STATE_ASSOCIATION_FAILURE 0x03
+#define WPS_ASSOC_STATE_IP_FAILURE 0x04
+
+/* =====================P2P Section===================== */
+/* For P2P */
+#define P2POUI 0x506F9A09
+
+/* P2P Attribute ID */
+#define P2P_ATTR_STATUS 0x00
+#define P2P_ATTR_MINOR_REASON_CODE 0x01
+#define P2P_ATTR_CAPABILITY 0x02
+#define P2P_ATTR_DEVICE_ID 0x03
+#define P2P_ATTR_GO_INTENT 0x04
+#define P2P_ATTR_CONF_TIMEOUT 0x05
+#define P2P_ATTR_LISTEN_CH 0x06
+#define P2P_ATTR_GROUP_BSSID 0x07
+#define P2P_ATTR_EX_LISTEN_TIMING 0x08
+#define P2P_ATTR_INTENTED_IF_ADDR 0x09
+#define P2P_ATTR_MANAGEABILITY 0x0A
+#define P2P_ATTR_CH_LIST 0x0B
+#define P2P_ATTR_NOA 0x0C
+#define P2P_ATTR_DEVICE_INFO 0x0D
+#define P2P_ATTR_GROUP_INFO 0x0E
+#define P2P_ATTR_GROUP_ID 0x0F
+#define P2P_ATTR_INTERFACE 0x10
+#define P2P_ATTR_OPERATING_CH 0x11
+#define P2P_ATTR_INVITATION_FLAGS 0x12
+
+/* Value of Status Attribute */
+#define P2P_STATUS_SUCCESS 0x00
+#define P2P_STATUS_FAIL_INFO_UNAVAILABLE 0x01
+#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 0x02
+#define P2P_STATUS_FAIL_LIMIT_REACHED 0x03
+#define P2P_STATUS_FAIL_INVALID_PARAM 0x04
+#define P2P_STATUS_FAIL_REQUEST_UNABLE 0x05
+#define P2P_STATUS_FAIL_PREVOUS_PROTO_ERR 0x06
+#define P2P_STATUS_FAIL_NO_COMMON_CH 0x07
+#define P2P_STATUS_FAIL_UNKNOWN_P2PGROUP 0x08
+#define P2P_STATUS_FAIL_BOTH_GOINTENT_15 0x09
+#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVSION 0x0A
+#define P2P_STATUS_FAIL_USER_REJECT 0x0B
+
+/* Value of Inviation Flags Attribute */
+#define P2P_INVITATION_FLAGS_PERSISTENT BIT(0)
+
+#define DMP_P2P_DEVCAP_SUPPORT (P2P_DEVCAP_SERVICE_DISCOVERY | \
+ P2P_DEVCAP_CLIENT_DISCOVERABILITY | \
+ P2P_DEVCAP_CONCURRENT_OPERATION | \
+ P2P_DEVCAP_INVITATION_PROC)
+
+#define DMP_P2P_GRPCAP_SUPPORT (P2P_GRPCAP_INTRABSS)
+
+/* Value of Device Capability Bitmap */
+#define P2P_DEVCAP_SERVICE_DISCOVERY BIT(0)
+#define P2P_DEVCAP_CLIENT_DISCOVERABILITY BIT(1)
+#define P2P_DEVCAP_CONCURRENT_OPERATION BIT(2)
+#define P2P_DEVCAP_INFRA_MANAGED BIT(3)
+#define P2P_DEVCAP_DEVICE_LIMIT BIT(4)
+#define P2P_DEVCAP_INVITATION_PROC BIT(5)
+
+/* Value of Group Capability Bitmap */
+#define P2P_GRPCAP_GO BIT(0)
+#define P2P_GRPCAP_PERSISTENT_GROUP BIT(1)
+#define P2P_GRPCAP_GROUP_LIMIT BIT(2)
+#define P2P_GRPCAP_INTRABSS BIT(3)
+#define P2P_GRPCAP_CROSS_CONN BIT(4)
+#define P2P_GRPCAP_PERSISTENT_RECONN BIT(5)
+#define P2P_GRPCAP_GROUP_FORMATION BIT(6)
+
+/* P2P Public Action Frame (Management Frame) */
+#define P2P_PUB_ACTION_ACTION 0x09
+
+/* P2P Public Action Frame Type */
+#define P2P_GO_NEGO_REQ 0
+#define P2P_GO_NEGO_RESP 1
+#define P2P_GO_NEGO_CONF 2
+#define P2P_INVIT_REQ 3
+#define P2P_INVIT_RESP 4
+#define P2P_DEVDISC_REQ 5
+#define P2P_DEVDISC_RESP 6
+#define P2P_PROVISION_DISC_REQ 7
+#define P2P_PROVISION_DISC_RESP 8
+
+/* P2P Action Frame Type */
+#define P2P_NOTICE_OF_ABSENCE 0
+#define P2P_PRESENCE_REQUEST 1
+#define P2P_PRESENCE_RESPONSE 2
+#define P2P_GO_DISC_REQUEST 3
+
+
+#define P2P_MAX_PERSISTENT_GROUP_NUM 10
+
+#define P2P_PROVISIONING_SCAN_CNT 3
+
+#define P2P_WILDCARD_SSID_LEN 7
+
+/* default value, used when: (1)p2p disabed or (2)p2p enabled
+ * but only do 1 scan phase */
+#define P2P_FINDPHASE_EX_NONE 0
+/* used when p2p enabled and want to do 1 scan phase and
+ * P2P_FINDPHASE_EX_MAX-1 find phase */
+#define P2P_FINDPHASE_EX_FULL 1
+#define P2P_FINDPHASE_EX_SOCIAL_FIRST (P2P_FINDPHASE_EX_FULL+1)
+#define P2P_FINDPHASE_EX_MAX 4
+#define P2P_FINDPHASE_EX_SOCIAL_LAST P2P_FINDPHASE_EX_MAX
+
+/* 5 seconds timeout for sending the provision discovery request */
+#define P2P_PROVISION_TIMEOUT 5000
+/* 3 seconds timeout for sending the prov disc request concurrent mode */
+#define P2P_CONCURRENT_PROVISION_TIME 3000
+/* 5 seconds timeout for receiving the group negotation response */
+#define P2P_GO_NEGO_TIMEOUT 5000
+/* 3 seconds timeout for sending the negotiation request under concurrent mode */
+#define P2P_CONCURRENT_GO_NEGO_TIME 3000
+/* 100ms */
+#define P2P_TX_PRESCAN_TIMEOUT 100
+/* 5 seconds timeout for sending the invitation request */
+#define P2P_INVITE_TIMEOUT 5000
+/* 3 seconds timeout for sending the invitation request under concurrent mode */
+#define P2P_CONCURRENT_INVITE_TIME 3000
+/* 25 seconds timeout to reset the scan channel (based on channel plan) */
+#define P2P_RESET_SCAN_CH 25000
+#define P2P_MAX_INTENT 15
+
+#define P2P_MAX_NOA_NUM 2
+
+/* WPS Configuration Method */
+#define WPS_CM_NONE 0x0000
+#define WPS_CM_LABEL 0x0004
+#define WPS_CM_DISPLYA 0x0008
+#define WPS_CM_EXTERNAL_NFC_TOKEN 0x0010
+#define WPS_CM_INTEGRATED_NFC_TOKEN 0x0020
+#define WPS_CM_NFC_INTERFACE 0x0040
+#define WPS_CM_PUSH_BUTTON 0x0080
+#define WPS_CM_KEYPAD 0x0100
+#define WPS_CM_SW_PUHS_BUTTON 0x0280
+#define WPS_CM_HW_PUHS_BUTTON 0x0480
+#define WPS_CM_SW_DISPLAY_P 0x2008
+#define WPS_CM_LCD_DISPLAY_P 0x4008
+
+enum P2P_ROLE {
+ P2P_ROLE_DISABLE = 0,
+ P2P_ROLE_DEVICE = 1,
+ P2P_ROLE_CLIENT = 2,
+ P2P_ROLE_GO = 3
+};
+
+enum P2P_STATE {
+ P2P_STATE_NONE = 0, /* P2P disable */
+ /* P2P had enabled and do nothing */
+ P2P_STATE_IDLE = 1,
+ P2P_STATE_LISTEN = 2, /* In pure listen state */
+ P2P_STATE_SCAN = 3, /* In scan phase */
+ /* In the listen state of find phase */
+ P2P_STATE_FIND_PHASE_LISTEN = 4,
+ /* In the search state of find phase */
+ P2P_STATE_FIND_PHASE_SEARCH = 5,
+ /* In P2P provisioning discovery */
+ P2P_STATE_TX_PROVISION_DIS_REQ = 6,
+ P2P_STATE_RX_PROVISION_DIS_RSP = 7,
+ P2P_STATE_RX_PROVISION_DIS_REQ = 8,
+ /* Doing the group owner negoitation handshake */
+ P2P_STATE_GONEGO_ING = 9,
+ /* finish the group negoitation handshake with success */
+ P2P_STATE_GONEGO_OK = 10,
+ /* finish the group negoitation handshake with failure */
+ P2P_STATE_GONEGO_FAIL = 11,
+ /* receiving the P2P Inviation request and match with the profile. */
+ P2P_STATE_RECV_INVITE_REQ_MATCH = 12,
+ /* Doing the P2P WPS */
+ P2P_STATE_PROVISIONING_ING = 13,
+ /* Finish the P2P WPS */
+ P2P_STATE_PROVISIONING_DONE = 14,
+ /* Transmit the P2P Invitation request */
+ P2P_STATE_TX_INVITE_REQ = 15,
+ /* Receiving the P2P Invitation response */
+ P2P_STATE_RX_INVITE_RESP_OK = 16,
+ /* receiving the P2P Inviation request and dismatch with the profile. */
+ P2P_STATE_RECV_INVITE_REQ_DISMATCH = 17,
+ /* receiving the P2P Inviation request and this wifi is GO. */
+ P2P_STATE_RECV_INVITE_REQ_GO = 18,
+ /* receiving the P2P Inviation request to join an existing P2P Group. */
+ P2P_STATE_RECV_INVITE_REQ_JOIN = 19,
+ /* recveing the P2P Inviation response with failure */
+ P2P_STATE_RX_INVITE_RESP_FAIL = 20,
+ /* receiving p2p negoitation response with information is not available */
+ P2P_STATE_RX_INFOR_NOREADY = 21,
+ /* sending p2p negoitation response with information is not available */
+ P2P_STATE_TX_INFOR_NOREADY = 22,
+};
+
+enum P2P_WPSINFO {
+ P2P_NO_WPSINFO = 0,
+ P2P_GOT_WPSINFO_PEER_DISPLAY_PIN = 1,
+ P2P_GOT_WPSINFO_SELF_DISPLAY_PIN = 2,
+ P2P_GOT_WPSINFO_PBC = 3,
+};
+
+#define P2P_PRIVATE_IOCTL_SET_LEN 64
+
+enum P2P_PROTO_WK_ID {
+ P2P_FIND_PHASE_WK = 0,
+ P2P_RESTORE_STATE_WK = 1,
+ P2P_PRE_TX_PROVDISC_PROCESS_WK = 2,
+ P2P_PRE_TX_NEGOREQ_PROCESS_WK = 3,
+ P2P_PRE_TX_INVITEREQ_PROCESS_WK = 4,
+ P2P_AP_P2P_CH_SWITCH_PROCESS_WK =5,
+ P2P_RO_CH_WK = 6,
+};
+
+enum P2P_PS_STATE {
+ P2P_PS_DISABLE = 0,
+ P2P_PS_ENABLE = 1,
+ P2P_PS_SCAN = 2,
+ P2P_PS_SCAN_DONE = 3,
+ P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */
+};
+
+enum P2P_PS_MODE {
+ P2P_PS_NONE = 0,
+ P2P_PS_CTWINDOW = 1,
+ P2P_PS_NOA = 2,
+ P2P_PS_MIX = 3, /* CTWindow and NoA */
+};
+
+/* =====================WFD Section===================== */
+/* For Wi-Fi Display */
+#define WFD_ATTR_DEVICE_INFO 0x00
+#define WFD_ATTR_ASSOC_BSSID 0x01
+#define WFD_ATTR_COUPLED_SINK_INFO 0x06
+#define WFD_ATTR_LOCAL_IP_ADDR 0x08
+#define WFD_ATTR_SESSION_INFO 0x09
+#define WFD_ATTR_ALTER_MAC 0x0a
+
+/* For WFD Device Information Attribute */
+#define WFD_DEVINFO_SOURCE 0x0000
+#define WFD_DEVINFO_PSINK 0x0001
+#define WFD_DEVINFO_SSINK 0x0002
+#define WFD_DEVINFO_DUAL 0x0003
+
+#define WFD_DEVINFO_SESSION_AVAIL 0x0010
+#define WFD_DEVINFO_WSD 0x0040
+#define WFD_DEVINFO_PC_TDLS 0x0080
+#define WFD_DEVINFO_HDCP_SUPPORT 0x0100
+
+#define IP_MCAST_MAC(mac) \
+ ((mac[0] == 0x01) && (mac[1] == 0x00) && (mac[2] == 0x5e))
+#define ICMPV6_MCAST_MAC(mac) \
+ ((mac[0] == 0x33) && (mac[1] == 0x33) && (mac[2] != 0xff))
+
+#endif /* _WIFI_H_ */
diff --git a/drivers/staging/rtl8188eu/include/wlan_bssdef.h b/drivers/staging/rtl8188eu/include/wlan_bssdef.h
new file mode 100644
index 00000000000..e70075d586d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/wlan_bssdef.h
@@ -0,0 +1,347 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __WLAN_BSSDEF_H__
+#define __WLAN_BSSDEF_H__
+
+
+#define MAX_IE_SZ 768
+
+#define NDIS_802_11_LENGTH_SSID 32
+#define NDIS_802_11_LENGTH_RATES 8
+#define NDIS_802_11_LENGTH_RATES_EX 16
+
+#define NDIS_802_11_RSSI long /* in dBm */
+
+struct ndis_802_11_ssid {
+ u32 SsidLength;
+ u8 Ssid[32];
+};
+
+enum NDIS_802_11_NETWORK_TYPE {
+ Ndis802_11FH,
+ Ndis802_11DS,
+ Ndis802_11OFDM5,
+ Ndis802_11OFDM24,
+ Ndis802_11NetworkTypeMax /* dummy upper bound */
+};
+
+struct ndis_802_11_config_fh {
+ u32 Length; /* Length of structure */
+ u32 HopPattern; /* As defined by 802.11, MSB set */
+ u32 HopSet; /* to one if non-802.11 */
+ u32 DwellTime; /* units are Kusec */
+};
+
+/*
+ * FW will only save the channel number in DSConfig.
+ * ODI Handler will convert the channel number to freq. number.
+ */
+struct ndis_802_11_config {
+ u32 Length; /* Length of structure */
+ u32 BeaconPeriod; /* units are Kusec */
+ u32 ATIMWindow; /* units are Kusec */
+ u32 DSConfig; /* Frequency, units are kHz */
+ struct ndis_802_11_config_fh FHConfig;
+};
+
+enum ndis_802_11_network_infra {
+ Ndis802_11IBSS,
+ Ndis802_11Infrastructure,
+ Ndis802_11AutoUnknown,
+ Ndis802_11InfrastructureMax, /* dummy upper bound */
+ Ndis802_11APMode
+};
+
+struct ndis_802_11_fixed_ie {
+ u8 Timestamp[8];
+ u16 BeaconInterval;
+ u16 Capabilities;
+};
+
+
+
+struct ndis_802_11_var_ie {
+ u8 ElementID;
+ u8 Length;
+ u8 data[1];
+};
+
+/*
+ * Length is the 4 bytes multiples of the sume of
+ * [ETH_ALEN] + 2 + sizeof (struct ndis_802_11_ssid) + sizeof (u32)
+ * + sizeof (NDIS_802_11_RSSI) + sizeof (enum NDIS_802_11_NETWORK_TYPE)
+ * + sizeof (struct ndis_802_11_config)
+ * + NDIS_802_11_LENGTH_RATES_EX + IELength
+ *
+ * Except the IELength, all other fields are fixed length.
+ * Therefore, we can define a macro to represent the partial sum. */
+
+enum ndis_802_11_auth_mode {
+ Ndis802_11AuthModeOpen,
+ Ndis802_11AuthModeShared,
+ Ndis802_11AuthModeAutoSwitch,
+ Ndis802_11AuthModeWPA,
+ Ndis802_11AuthModeWPAPSK,
+ Ndis802_11AuthModeWPANone,
+ Ndis802_11AuthModeWAPI,
+ Ndis802_11AuthModeMax /* Not a real mode, upper bound */
+};
+
+enum ndis_802_11_wep_status {
+ Ndis802_11WEPEnabled,
+ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
+ Ndis802_11WEPDisabled,
+ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
+ Ndis802_11WEPKeyAbsent,
+ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
+ Ndis802_11WEPNotSupported,
+ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
+ Ndis802_11Encryption2Enabled,
+ Ndis802_11Encryption2KeyAbsent,
+ Ndis802_11Encryption3Enabled,
+ Ndis802_11Encryption3KeyAbsent,
+ Ndis802_11_EncryptionWAPI
+};
+
+#define NDIS_802_11_AI_REQFI_CAPABILITIES 1
+#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2
+#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4
+
+#define NDIS_802_11_AI_RESFI_CAPABILITIES 1
+#define NDIS_802_11_AI_RESFI_STATUSCODE 2
+#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4
+
+struct ndis_802_11_ai_reqfi {
+ u16 Capabilities;
+ u16 ListenInterval;
+ unsigned char CurrentAPAddress[ETH_ALEN];
+};
+
+struct ndis_802_11_ai_resfi {
+ u16 Capabilities;
+ u16 StatusCode;
+ u16 AssociationId;
+};
+
+struct ndis_802_11_assoc_info {
+ u32 Length;
+ u16 AvailableRequestFixedIEs;
+ struct ndis_802_11_ai_reqfi RequestFixedIEs;
+ u32 RequestIELength;
+ u32 OffsetRequestIEs;
+ u16 AvailableResponseFixedIEs;
+ struct ndis_802_11_ai_resfi ResponseFixedIEs;
+ u32 ResponseIELength;
+ u32 OffsetResponseIEs;
+};
+
+enum ndis_802_11_reload_def {
+ Ndis802_11ReloadWEPKeys
+};
+
+/* Key mapping keys require a BSSID */
+struct ndis_802_11_key {
+ u32 Length; /* Length of this structure */
+ u32 KeyIndex;
+ u32 KeyLength; /* length of key in bytes */
+ unsigned char BSSID[ETH_ALEN];
+ unsigned long long KeyRSC;
+ u8 KeyMaterial[32]; /* var len depending on above field */
+};
+
+struct ndis_802_11_remove_key {
+ u32 Length; /* Length */
+ u32 KeyIndex;
+ unsigned char BSSID[ETH_ALEN];
+};
+
+struct ndis_802_11_wep {
+ u32 Length; /* Length of this structure */
+ u32 KeyIndex; /* 0 is the per-client key,
+ * 1-N are the global keys */
+ u32 KeyLength; /* length of key in bytes */
+ u8 KeyMaterial[16];/* variable len depending on above field */
+};
+
+struct ndis_802_11_auth_req {
+ u32 Length; /* Length of structure */
+ unsigned char Bssid[ETH_ALEN];
+ u32 Flags;
+};
+
+enum ndis_802_11_status_type {
+ Ndis802_11StatusType_Authentication,
+ Ndis802_11StatusType_MediaStreamMode,
+ Ndis802_11StatusType_PMKID_CandidateList,
+ Ndis802_11StatusTypeMax /* not a real type, defined as
+ * an upper bound */
+};
+
+struct ndis_802_11_status_ind {
+ enum ndis_802_11_status_type StatusType;
+};
+
+/* mask for authentication/integrity fields */
+#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f
+#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01
+#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02
+#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
+#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
+
+/* MIC check time, 60 seconds. */
+#define MIC_CHECK_TIME 60000000
+
+struct ndis_802_11_auth_evt {
+ struct ndis_802_11_status_ind Status;
+ struct ndis_802_11_auth_req Request[1];
+};
+
+struct ndis_802_11_test {
+ u32 Length;
+ u32 Type;
+ union {
+ struct ndis_802_11_auth_evt AuthenticationEvent;
+ NDIS_802_11_RSSI RssiTrigger;
+ } tt;
+};
+
+
+#ifndef Ndis802_11APMode
+#define Ndis802_11APMode (Ndis802_11InfrastructureMax+1)
+#endif
+
+struct wlan_phy_info {
+ u8 SignalStrength;/* in percentage) */
+ u8 SignalQuality;/* in percentage) */
+ u8 Optimum_antenna; /* for Antenna diversity */
+ u8 Reserved_0;
+};
+
+struct wlan_bcn_info {
+ /* these infor get from rtw_get_encrypt_info when
+ * * translate scan to UI */
+ u8 encryp_protocol;/* ENCRYP_PROTOCOL_E: OPEN/WEP/WPA/WPA2/WAPI */
+ int group_cipher; /* WPA/WPA2 group cipher */
+ int pairwise_cipher;/* WPA/WPA2/WEP pairwise cipher */
+ int is_8021x;
+
+ /* bwmode 20/40 and ch_offset UP/LOW */
+ unsigned short ht_cap_info;
+ unsigned char ht_info_infos_0;
+};
+
+/* temporally add #pragma pack for structure alignment issue of
+* struct wlan_bssid_ex and get_struct wlan_bssid_ex_sz()
+*/
+struct wlan_bssid_ex {
+ u32 Length;
+ unsigned char MacAddress[ETH_ALEN];
+ u8 Reserved[2];/* 0]: IS beacon frame */
+ struct ndis_802_11_ssid Ssid;
+ u32 Privacy;
+ NDIS_802_11_RSSI Rssi;/* in dBM,raw data ,get from PHY) */
+ enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
+ struct ndis_802_11_config Configuration;
+ enum ndis_802_11_network_infra InfrastructureMode;
+ unsigned char SupportedRates[NDIS_802_11_LENGTH_RATES_EX];
+ struct wlan_phy_info PhyInfo;
+ u32 IELength;
+ u8 IEs[MAX_IE_SZ]; /* timestamp, beacon interval, and
+ * capability information) */
+} __packed;
+
+static inline uint get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss)
+{
+ return sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + bss->IELength;
+}
+
+struct wlan_network {
+ struct list_head list;
+ int network_type; /* refer to ieee80211.h for WIRELESS_11A/B/G */
+ int fixed; /* set fixed when not to be removed
+ * in site-surveying */
+ unsigned long last_scanned; /* timestamp for the network */
+ int aid; /* will only be valid when a BSS is joinned. */
+ int join_res;
+ struct wlan_bssid_ex network; /* must be the last item */
+ struct wlan_bcn_info BcnInfo;
+};
+
+enum VRTL_CARRIER_SENSE {
+ DISABLE_VCS,
+ ENABLE_VCS,
+ AUTO_VCS
+};
+
+enum VCS_TYPE {
+ NONE_VCS,
+ RTS_CTS,
+ CTS_TO_SELF
+};
+
+#define PWR_CAM 0
+#define PWR_MINPS 1
+#define PWR_MAXPS 2
+#define PWR_UAPSD 3
+#define PWR_VOIP 4
+
+enum UAPSD_MAX_SP {
+ NO_LIMIT,
+ TWO_MSDU,
+ FOUR_MSDU,
+ SIX_MSDU
+};
+
+#define NUM_PRE_AUTH_KEY 16
+#define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY
+
+/*
+* WPA2
+*/
+
+struct pmkid_candidate {
+ unsigned char BSSID[ETH_ALEN];
+ u32 Flags;
+};
+
+struct ndis_802_11_pmkid_list {
+ u32 Version; /* Version of the structure */
+ u32 NumCandidates; /* No. of pmkid candidates */
+ struct pmkid_candidate CandidateList[1];
+};
+
+struct ndis_802_11_auth_encrypt {
+ enum ndis_802_11_auth_mode AuthModeSupported;
+ enum ndis_802_11_wep_status EncryptStatusSupported;
+};
+
+struct ndis_802_11_cap {
+ u32 Length;
+ u32 Version;
+ u32 NoOfPMKIDs;
+ u32 NoOfAuthEncryptPairsSupported;
+ struct ndis_802_11_auth_encrypt AuthenticationEncryptionSupported[1];
+};
+
+u8 key_2char2num(u8 hch, u8 lch);
+u8 key_char2num(u8 ch);
+u8 str_2char2num(u8 hch, u8 lch);
+
+#endif /* ifndef WLAN_BSSDEF_H_ */
diff --git a/drivers/staging/rtl8188eu/include/xmit_osdep.h b/drivers/staging/rtl8188eu/include/xmit_osdep.h
new file mode 100644
index 00000000000..2ff622ba24f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/xmit_osdep.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#ifndef __XMIT_OSDEP_H_
+#define __XMIT_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+struct pkt_file {
+ struct sk_buff *pkt;
+ size_t pkt_len; /* the remainder length of the open_file */
+ unsigned char *cur_buffer;
+ u8 *buf_start;
+ u8 *cur_addr;
+ size_t buf_len;
+};
+
+extern int rtw_ht_enable;
+extern int rtw_cbw40_enable;
+extern int rtw_ampdu_enable;/* for enable tx_ampdu */
+
+#define NR_XMITFRAME 256
+
+struct xmit_priv;
+struct pkt_attrib;
+struct sta_xmit_priv;
+struct xmit_frame;
+struct xmit_buf;
+
+int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev);
+
+void rtw_os_xmit_schedule(struct adapter *padapter);
+
+int rtw_os_xmit_resource_alloc(struct adapter *padapter,
+ struct xmit_buf *pxmitbuf, u32 alloc_sz);
+void rtw_os_xmit_resource_free(struct adapter *padapter,
+ struct xmit_buf *pxmitbuf, u32 free_sz);
+
+void rtw_set_tx_chksum_offload(struct sk_buff *pkt, struct pkt_attrib *pattrib);
+
+uint rtw_remainder_len(struct pkt_file *pfile);
+void _rtw_open_pktfile(struct sk_buff *pkt, struct pkt_file *pfile);
+uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen);
+int rtw_endofpktfile(struct pkt_file *pfile);
+
+void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt);
+void rtw_os_xmit_complete(struct adapter *padapter,
+ struct xmit_frame *pxframe);
+
+#endif /* __XMIT_OSDEP_H_ */
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
new file mode 100644
index 00000000000..cd4100fb364
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -0,0 +1,8222 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _IOCTL_LINUX_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wlan_bssdef.h>
+#include <rtw_debug.h>
+#include <wifi.h>
+#include <rtw_mlme.h>
+#include <rtw_mlme_ext.h>
+#include <rtw_ioctl.h>
+#include <rtw_ioctl_set.h>
+#include <rtw_mp_ioctl.h>
+#include <usb_ops.h>
+#include <rtw_version.h>
+#include <rtl8188e_hal.h>
+
+#include <rtw_mp.h>
+#include <rtw_iol.h>
+
+#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 30)
+
+#define SCAN_ITEM_SIZE 768
+#define MAX_CUSTOM_LEN 64
+#define RATE_COUNT 4
+
+/* combo scan */
+#define WEXT_CSCAN_AMOUNT 9
+#define WEXT_CSCAN_BUF_LEN 360
+#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00"
+#define WEXT_CSCAN_HEADER_SIZE 12
+#define WEXT_CSCAN_SSID_SECTION 'S'
+#define WEXT_CSCAN_CHANNEL_SECTION 'C'
+#define WEXT_CSCAN_NPROBE_SECTION 'N'
+#define WEXT_CSCAN_ACTV_DWELL_SECTION 'A'
+#define WEXT_CSCAN_PASV_DWELL_SECTION 'P'
+#define WEXT_CSCAN_HOME_DWELL_SECTION 'H'
+#define WEXT_CSCAN_TYPE_SECTION 'T'
+
+static struct mp_ioctl_handler mp_ioctl_hdl[] = {
+/*0*/ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_start_test_hdl, OID_RT_PRO_START_TEST)
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_stop_test_hdl, OID_RT_PRO_STOP_TEST)
+
+ GEN_HANDLER(sizeof(struct rwreg_param), rtl8188eu_oid_rt_pro_read_register_hdl, OID_RT_PRO_READ_REGISTER)
+ GEN_HANDLER(sizeof(struct rwreg_param), rtl8188eu_oid_rt_pro_write_register_hdl, OID_RT_PRO_WRITE_REGISTER)
+ GEN_HANDLER(sizeof(struct bb_reg_param), rtl8188eu_oid_rt_pro_read_bb_reg_hdl, OID_RT_PRO_READ_BB_REG)
+/*5*/ GEN_HANDLER(sizeof(struct bb_reg_param), rtl8188eu_oid_rt_pro_write_bb_reg_hdl, OID_RT_PRO_WRITE_BB_REG)
+ GEN_HANDLER(sizeof(struct rf_reg_param), rtl8188eu_oid_rt_pro_read_rf_reg_hdl, OID_RT_PRO_RF_READ_REGISTRY)
+ GEN_HANDLER(sizeof(struct rf_reg_param), rtl8188eu_oid_rt_pro_write_rf_reg_hdl, OID_RT_PRO_RF_WRITE_REGISTRY)
+
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl, OID_RT_PRO_SET_CHANNEL_DIRECT_CALL)
+ GEN_HANDLER(sizeof(struct txpower_param), rtl8188eu_oid_rt_pro_set_tx_power_control_hdl, OID_RT_PRO_SET_TX_POWER_CONTROL)
+/*10*/ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_data_rate_hdl, OID_RT_PRO_SET_DATA_RATE)
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_set_bandwidth_hdl, OID_RT_SET_BANDWIDTH)
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_antenna_bb_hdl, OID_RT_PRO_SET_ANTENNA_BB)
+
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_continuous_tx_hdl, OID_RT_PRO_SET_CONTINUOUS_TX)
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl, OID_RT_PRO_SET_SINGLE_CARRIER_TX)
+/*15*/ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl, OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX)
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl, OID_RT_PRO_SET_SINGLE_TONE_TX)
+
+ EXT_MP_IOCTL_HANDLER(0, xmit_packet, 0)
+
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_set_rx_packet_type_hdl, OID_RT_SET_RX_PACKET_TYPE)
+ GEN_HANDLER(0, rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl, OID_RT_RESET_PHY_RX_PACKET_COUNT)
+/*20*/ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl, OID_RT_GET_PHY_RX_PACKET_RECEIVED)
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl, OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR)
+
+ GEN_HANDLER(sizeof(struct eeprom_rw_param), NULL, 0)
+ GEN_HANDLER(sizeof(struct eeprom_rw_param), NULL, 0)
+ GEN_HANDLER(sizeof(struct efuse_access_struct), rtl8188eu_oid_rt_pro_efuse_hdl, OID_RT_PRO_EFUSE)
+/*25*/ GEN_HANDLER(0, rtl8188eu_oid_rt_pro_efuse_map_hdl, OID_RT_PRO_EFUSE_MAP)
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_efuse_max_size_hdl, OID_RT_GET_EFUSE_MAX_SIZE)
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_efuse_current_size_hdl, OID_RT_GET_EFUSE_CURRENT_SIZE)
+
+ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_thermal_meter_hdl, OID_RT_PRO_GET_THERMAL_METER)
+ GEN_HANDLER(sizeof(u8), rtl8188eu_oid_rt_pro_set_power_tracking_hdl, OID_RT_PRO_SET_POWER_TRACKING)
+/*30*/ GEN_HANDLER(sizeof(u8), rtl8188eu_oid_rt_set_power_down_hdl, OID_RT_SET_POWER_DOWN)
+/*31*/ GEN_HANDLER(0, rtl8188eu_oid_rt_pro_trigger_gpio_hdl, 0)
+};
+
+static u32 rtw_rates[] = {1000000, 2000000, 5500000, 11000000,
+ 6000000, 9000000, 12000000, 18000000, 24000000, 36000000,
+ 48000000, 54000000};
+
+static const char * const iw_operation_mode[] = {
+ "Auto", "Ad-Hoc", "Managed", "Master", "Repeater",
+ "Secondary", "Monitor"
+};
+
+static int hex2num_i(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+/**
+ * hwaddr_aton - Convert ASCII string to MAC address
+ * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+static int hwaddr_aton_i(const char *txt, u8 *addr)
+{
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ int a, b;
+
+ a = hex2num_i(*txt++);
+ if (a < 0)
+ return -1;
+ b = hex2num_i(*txt++);
+ if (b < 0)
+ return -1;
+ *addr++ = (a << 4) | b;
+ if (i < 5 && *txt++ != ':')
+ return -1;
+ }
+
+ return 0;
+}
+
+void indicate_wx_scan_complete_event(struct adapter *padapter)
+{
+ union iwreq_data wrqu;
+
+ _rtw_memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(padapter->pnetdev, SIOCGIWSCAN, &wrqu, NULL);
+}
+
+void rtw_indicate_wx_assoc_event(struct adapter *padapter)
+{
+ union iwreq_data wrqu;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ _rtw_memset(&wrqu, 0, sizeof(union iwreq_data));
+
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+ memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN);
+
+ DBG_88E_LEVEL(_drv_always_, "assoc success\n");
+ wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
+}
+
+void rtw_indicate_wx_disassoc_event(struct adapter *padapter)
+{
+ union iwreq_data wrqu;
+
+ _rtw_memset(&wrqu, 0, sizeof(union iwreq_data));
+
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ _rtw_memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+
+ DBG_88E_LEVEL(_drv_always_, "indicate disassoc\n");
+ wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
+}
+
+static char *translate_scan(struct adapter *padapter,
+ struct iw_request_info *info,
+ struct wlan_network *pnetwork,
+ char *start, char *stop)
+{
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct iw_event iwe;
+ u16 cap;
+ __le16 le_tmp;
+ u32 ht_ielen = 0;
+ char custom[MAX_CUSTOM_LEN];
+ char *p;
+ u16 max_rate = 0, rate, ht_cap = false;
+ u32 i = 0;
+ u8 bw_40MHz = 0, short_GI = 0;
+ u16 mcs_rate = 0;
+ u8 ss, sq;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ u32 blnGotP2PIE = false;
+
+ /* User is doing the P2P device discovery */
+ /* The prefix of SSID should be "DIRECT-" and the IE should contains the P2P IE. */
+ /* If not, the driver should ignore this AP and go to the next AP. */
+
+ /* Verifying the SSID */
+ if (!memcmp(pnetwork->network.Ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN)) {
+ u32 p2pielen = 0;
+
+ if (pnetwork->network.Reserved[0] == 2) {/* Probe Request */
+ /* Verifying the P2P IE */
+ if (rtw_get_p2p_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &p2pielen))
+ blnGotP2PIE = true;
+ } else {/* Beacon or Probe Respones */
+ /* Verifying the P2P IE */
+ if (rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen))
+ blnGotP2PIE = true;
+ }
+ }
+
+ if (!blnGotP2PIE)
+ return start;
+ }
+#endif /* CONFIG_88EU_P2P */
+
+ /* AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+
+ memcpy(iwe.u.ap_addr.sa_data, pnetwork->network.MacAddress, ETH_ALEN);
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
+
+ /* Add the ESSID */
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.flags = 1;
+ iwe.u.data.length = min_t(u16, pnetwork->network.Ssid.SsidLength, 32);
+ start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid);
+
+ /* parsing HT_CAP_IE */
+ p = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength-12);
+
+ if (p && ht_ielen > 0) {
+ struct rtw_ieee80211_ht_cap *pht_capie;
+ ht_cap = true;
+ pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2);
+ memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
+ bw_40MHz = (pht_capie->cap_info&IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0;
+ short_GI = (pht_capie->cap_info&(IEEE80211_HT_CAP_SGI_20|IEEE80211_HT_CAP_SGI_40)) ? 1 : 0;
+ }
+
+ /* Add the protocol name */
+ iwe.cmd = SIOCGIWNAME;
+ if ((rtw_is_cckratesonly_included((u8 *)&pnetwork->network.SupportedRates))) {
+ if (ht_cap)
+ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn");
+ else
+ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b");
+ } else if ((rtw_is_cckrates_included((u8 *)&pnetwork->network.SupportedRates))) {
+ if (ht_cap)
+ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn");
+ else
+ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg");
+ } else {
+ if (pnetwork->network.Configuration.DSConfig > 14) {
+ if (ht_cap)
+ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11an");
+ else
+ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11a");
+ } else {
+ if (ht_cap)
+ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn");
+ else
+ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g");
+ }
+ }
+
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
+
+ /* Add mode */
+ iwe.cmd = SIOCGIWMODE;
+ memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);
+
+ cap = le16_to_cpu(le_tmp);
+
+ if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_BSS)) {
+ if (cap & WLAN_CAPABILITY_BSS)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
+ }
+
+ if (pnetwork->network.Configuration.DSConfig < 1)
+ pnetwork->network.Configuration.DSConfig = 1;
+
+ /* Add frequency/channel */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = rtw_ch2freq(pnetwork->network.Configuration.DSConfig) * 100000;
+ iwe.u.freq.e = 1;
+ iwe.u.freq.i = pnetwork->network.Configuration.DSConfig;
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
+
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (cap & WLAN_CAPABILITY_PRIVACY)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid);
+
+ /*Add basic and extended rates */
+ max_rate = 0;
+ p = custom;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
+ while (pnetwork->network.SupportedRates[i] != 0) {
+ rate = pnetwork->network.SupportedRates[i]&0x7F;
+ if (rate > max_rate)
+ max_rate = rate;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+ "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
+ i++;
+ }
+
+ if (ht_cap) {
+ if (mcs_rate&0x8000)/* MCS15 */
+ max_rate = (bw_40MHz) ? ((short_GI) ? 300 : 270) : ((short_GI) ? 144 : 130);
+ else if (mcs_rate&0x0080)/* MCS7 */
+ ;
+ else/* default MCS7 */
+ max_rate = (bw_40MHz) ? ((short_GI) ? 150 : 135) : ((short_GI) ? 72 : 65);
+
+ max_rate = max_rate*2;/* Mbps/2; */
+ }
+
+ iwe.cmd = SIOCGIWRATE;
+ iwe.u.bitrate.fixed = 0;
+ iwe.u.bitrate.disabled = 0;
+ iwe.u.bitrate.value = max_rate * 500000;
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN);
+
+ /* parsing WPA/WPA2 IE */
+ {
+ u8 buf[MAX_WPA_IE_LEN];
+ u8 wpa_ie[255], rsn_ie[255];
+ u16 wpa_len = 0, rsn_len = 0;
+ u8 *p;
+
+ rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, rsn_ie, &rsn_len, wpa_ie, &wpa_len);
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: ssid =%s\n", pnetwork->network.Ssid.Ssid));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
+
+ if (wpa_len > 0) {
+ p = buf;
+ _rtw_memset(buf, 0, MAX_WPA_IE_LEN);
+ p += sprintf(p, "wpa_ie =");
+ for (i = 0; i < wpa_len; i++)
+ p += sprintf(p, "%02x", wpa_ie[i]);
+
+ _rtw_memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ iwe.u.data.length = strlen(buf);
+ start = iwe_stream_add_point(info, start, stop, &iwe, buf);
+
+ _rtw_memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = wpa_len;
+ start = iwe_stream_add_point(info, start, stop, &iwe, wpa_ie);
+ }
+ if (rsn_len > 0) {
+ p = buf;
+ _rtw_memset(buf, 0, MAX_WPA_IE_LEN);
+ p += sprintf(p, "rsn_ie =");
+ for (i = 0; i < rsn_len; i++)
+ p += sprintf(p, "%02x", rsn_ie[i]);
+ _rtw_memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ iwe.u.data.length = strlen(buf);
+ start = iwe_stream_add_point(info, start, stop, &iwe, buf);
+
+ _rtw_memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = rsn_len;
+ start = iwe_stream_add_point(info, start, stop, &iwe, rsn_ie);
+ }
+ }
+
+ {/* parsing WPS IE */
+ uint cnt = 0, total_ielen;
+ u8 *wpsie_ptr = NULL;
+ uint wps_ielen = 0;
+
+ u8 *ie_ptr = pnetwork->network.IEs + _FIXED_IE_LENGTH_;
+ total_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_;
+
+ while (cnt < total_ielen) {
+ if (rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen > 2)) {
+ wpsie_ptr = &ie_ptr[cnt];
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = (u16)wps_ielen;
+ start = iwe_stream_add_point(info, start, stop, &iwe, wpsie_ptr);
+ }
+ cnt += ie_ptr[cnt+1]+2; /* goto next */
+ }
+ }
+
+ /* Add quality statistics */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true &&
+ is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network)) {
+ ss = padapter->recvpriv.signal_strength;
+ sq = padapter->recvpriv.signal_qual;
+ } else {
+ ss = pnetwork->network.PhyInfo.SignalStrength;
+ sq = pnetwork->network.PhyInfo.SignalQuality;
+ }
+
+ iwe.u.qual.level = (u8)ss;
+ iwe.u.qual.qual = (u8)sq; /* signal quality */
+ iwe.u.qual.noise = 0; /* noise level */
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
+ return start;
+}
+
+static int wpa_set_auth_algs(struct net_device *dev, u32 value)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int ret = 0;
+
+ if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) {
+ DBG_88E("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY and AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n", value);
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+ } else if (value & AUTH_ALG_SHARED_KEY) {
+ DBG_88E("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY [value:0x%x]\n", value);
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
+ } else if (value & AUTH_ALG_OPEN_SYSTEM) {
+ DBG_88E("wpa_set_auth_algs, AUTH_ALG_OPEN_SYSTEM\n");
+ if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) {
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+ }
+ } else if (value & AUTH_ALG_LEAP) {
+ DBG_88E("wpa_set_auth_algs, AUTH_ALG_LEAP\n");
+ } else {
+ DBG_88E("wpa_set_auth_algs, error!\n");
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
+{
+ int ret = 0;
+ u32 wep_key_idx, wep_key_len, wep_total_len;
+ struct ndis_802_11_wep *pwep = NULL;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_88EU_P2P */
+
+_func_enter_;
+
+ param->u.crypt.err = 0;
+ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+ if (param_len < (u32) ((u8 *)param->u.crypt.key - (u8 *)param) + param->u.crypt.key_len) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ if (param->u.crypt.idx >= WEP_KEYS) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ } else {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("wpa_set_encryption, crypt.alg = WEP\n"));
+ DBG_88E("wpa_set_encryption, crypt.alg = WEP\n");
+
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
+
+ wep_key_idx = param->u.crypt.idx;
+ wep_key_len = param->u.crypt.key_len;
+
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(1)wep_key_idx =%d\n", wep_key_idx));
+ DBG_88E("(1)wep_key_idx =%d\n", wep_key_idx);
+
+ if (wep_key_idx > WEP_KEYS)
+ return -EINVAL;
+
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(2)wep_key_idx =%d\n", wep_key_idx));
+
+ if (wep_key_len > 0) {
+ wep_key_len = wep_key_len <= 5 ? 5 : 13;
+ wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
+ pwep = (struct ndis_802_11_wep *)rtw_malloc(wep_total_len);
+ if (pwep == NULL) {
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, (" wpa_set_encryption: pwep allocate fail !!!\n"));
+ goto exit;
+ }
+ _rtw_memset(pwep, 0, wep_total_len);
+ pwep->KeyLength = wep_key_len;
+ pwep->Length = wep_total_len;
+ if (wep_key_len == 13) {
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_;
+ }
+ } else {
+ ret = -EINVAL;
+ goto exit;
+ }
+ pwep->KeyIndex = wep_key_idx;
+ pwep->KeyIndex |= 0x80000000;
+ memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength);
+ if (param->u.crypt.set_tx) {
+ DBG_88E("wep, set_tx = 1\n");
+ if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL)
+ ret = -EOPNOTSUPP;
+ } else {
+ DBG_88E("wep, set_tx = 0\n");
+ if (wep_key_idx >= WEP_KEYS) {
+ ret = -EOPNOTSUPP;
+ goto exit;
+ }
+ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
+ psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
+ rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0);
+ }
+ goto exit;
+ }
+
+ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /* 802_1x */
+ struct sta_info *psta, *pbcmc_sta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE)) { /* sta mode */
+ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
+ if (psta == NULL) {
+ ;
+ } else {
+ if (strcmp(param->u.crypt.alg, "none") != 0)
+ psta->ieee8021x_blocked = false;
+
+ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
+ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled))
+ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+
+ if (param->u.crypt.set_tx == 1) { /* pairwise key */
+ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */
+ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
+ padapter->securitypriv.busetkipkey = false;
+ }
+
+ DBG_88E(" ~~~~set sta key:unicastkey\n");
+
+ rtw_setstakey_cmd(padapter, (unsigned char *)psta, true);
+ } else { /* group key */
+ memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+ memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+ padapter->securitypriv.binstallGrpkey = true;
+ DBG_88E(" ~~~~set sta key:groupkey\n");
+
+ padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx;
+
+ rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1);
+#ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_DONE);
+#endif /* CONFIG_88EU_P2P */
+ }
+ }
+ pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+ if (pbcmc_sta == NULL) {
+ ;
+ } else {
+ /* Jeff: don't disable ieee8021x_blocked while clearing key */
+ if (strcmp(param->u.crypt.alg, "none") != 0)
+ pbcmc_sta->ieee8021x_blocked = false;
+
+ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
+ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled))
+ pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+ }
+ }
+ }
+
+exit:
+
+ kfree(pwep);
+
+_func_exit_;
+
+ return ret;
+}
+
+static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ielen)
+{
+ u8 *buf = NULL;
+ int group_cipher = 0, pairwise_cipher = 0;
+ int ret = 0;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_88EU_P2P */
+
+ if ((ielen > MAX_WPA_IE_LEN) || (pie == NULL)) {
+ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+ if (pie == NULL)
+ return ret;
+ else
+ return -EINVAL;
+ }
+
+ if (ielen) {
+ buf = rtw_zmalloc(ielen);
+ if (buf == NULL) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ memcpy(buf, pie, ielen);
+
+ /* dump */
+ {
+ int i;
+ DBG_88E("\n wpa_ie(length:%d):\n", ielen);
+ for (i = 0; i < ielen; i += 8)
+ DBG_88E("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
+ }
+
+ if (ielen < RSN_HEADER_LEN) {
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("Ie len too short %d\n", ielen));
+ ret = -1;
+ goto exit;
+ }
+
+ if (rtw_parse_wpa_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK;
+ memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);
+ }
+
+ if (rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK;
+ memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);
+ }
+
+ switch (group_cipher) {
+ case WPA_CIPHER_NONE:
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ break;
+ case WPA_CIPHER_WEP40:
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ case WPA_CIPHER_TKIP:
+ padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+ break;
+ case WPA_CIPHER_CCMP:
+ padapter->securitypriv.dot118021XGrpPrivacy = _AES_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+ break;
+ case WPA_CIPHER_WEP104:
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ }
+
+ switch (pairwise_cipher) {
+ case WPA_CIPHER_NONE:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ break;
+ case WPA_CIPHER_WEP40:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ case WPA_CIPHER_TKIP:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+ break;
+ case WPA_CIPHER_CCMP:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _AES_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+ break;
+ case WPA_CIPHER_WEP104:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ }
+
+ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+ {/* set wps_ie */
+ u16 cnt = 0;
+ u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+ while (cnt < ielen) {
+ eid = buf[cnt];
+ if ((eid == _VENDOR_SPECIFIC_IE_) && (!memcmp(&buf[cnt+2], wps_oui, 4))) {
+ DBG_88E("SET WPS_IE\n");
+
+ padapter->securitypriv.wps_ie_len = ((buf[cnt+1]+2) < (MAX_WPA_IE_LEN<<2)) ? (buf[cnt+1]+2) : (MAX_WPA_IE_LEN<<2);
+
+ memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len);
+
+ set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS);
+#ifdef CONFIG_88EU_P2P
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK))
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_ING);
+#endif /* CONFIG_88EU_P2P */
+ cnt += buf[cnt+1]+2;
+ break;
+ } else {
+ cnt += buf[cnt+1]+2; /* goto next */
+ }
+ }
+ }
+ }
+
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+ ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->securitypriv.ndisencryptstatus =%d padapter->securitypriv.ndisauthtype =%d\n",
+ pairwise_cipher, padapter->securitypriv.ndisencryptstatus, padapter->securitypriv.ndisauthtype));
+exit:
+ kfree(buf);
+ return ret;
+}
+
+typedef unsigned char NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];
+
+static int rtw_wx_get_name(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ u32 ht_ielen = 0;
+ char *p;
+ u8 ht_cap = false;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
+ NDIS_802_11_RATES_EX *prates = NULL;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("cmd_code =%x\n", info->cmd));
+
+ _func_enter_;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) {
+ /* parsing HT_CAP_IE */
+ p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12);
+ if (p && ht_ielen > 0)
+ ht_cap = true;
+
+ prates = &pcur_bss->SupportedRates;
+
+ if (rtw_is_cckratesonly_included((u8 *)prates) == true) {
+ if (ht_cap)
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bn");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
+ } else if ((rtw_is_cckrates_included((u8 *)prates)) == true) {
+ if (ht_cap)
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bgn");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bg");
+ } else {
+ if (pcur_bss->Configuration.DSConfig > 14) {
+ if (ht_cap)
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11an");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11a");
+ } else {
+ if (ht_cap)
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11gn");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g");
+ }
+ }
+ } else {
+ snprintf(wrqu->name, IFNAMSIZ, "unassociated");
+ }
+
+ _func_exit_;
+
+ return 0;
+}
+
+static int rtw_wx_set_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _func_enter_;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_wx_set_freq\n"));
+
+ _func_exit_;
+
+ return 0;
+}
+
+static int rtw_wx_get_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ /* wrqu->freq.m = ieee80211_wlan_frequencies[pcur_bss->Configuration.DSConfig-1] * 100000; */
+ wrqu->freq.m = rtw_ch2freq(pcur_bss->Configuration.DSConfig) * 100000;
+ wrqu->freq.e = 1;
+ wrqu->freq.i = pcur_bss->Configuration.DSConfig;
+ } else {
+ wrqu->freq.m = rtw_ch2freq(padapter->mlmeextpriv.cur_channel) * 100000;
+ wrqu->freq.e = 1;
+ wrqu->freq.i = padapter->mlmeextpriv.cur_channel;
+ }
+
+ return 0;
+}
+
+static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ enum ndis_802_11_network_infra networkType;
+ int ret = 0;
+
+ _func_enter_;
+
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -EPERM;
+ goto exit;
+ }
+
+ if (!padapter->hw_init_completed) {
+ ret = -EPERM;
+ goto exit;
+ }
+
+ switch (wrqu->mode) {
+ case IW_MODE_AUTO:
+ networkType = Ndis802_11AutoUnknown;
+ DBG_88E("set_mode = IW_MODE_AUTO\n");
+ break;
+ case IW_MODE_ADHOC:
+ networkType = Ndis802_11IBSS;
+ DBG_88E("set_mode = IW_MODE_ADHOC\n");
+ break;
+ case IW_MODE_MASTER:
+ networkType = Ndis802_11APMode;
+ DBG_88E("set_mode = IW_MODE_MASTER\n");
+ break;
+ case IW_MODE_INFRA:
+ networkType = Ndis802_11Infrastructure;
+ DBG_88E("set_mode = IW_MODE_INFRA\n");
+ break;
+ default:
+ ret = -EINVAL;
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("\n Mode: %s is not supported\n", iw_operation_mode[wrqu->mode]));
+ goto exit;
+ }
+ if (rtw_set_802_11_infrastructure_mode(padapter, networkType) == false) {
+ ret = -EPERM;
+ goto exit;
+ }
+ rtw_setopmode_cmd(padapter, networkType);
+exit:
+ _func_exit_;
+ return ret;
+}
+
+static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_get_mode\n"));
+
+ _func_enter_;
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+ wrqu->mode = IW_MODE_INFRA;
+ else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)))
+ wrqu->mode = IW_MODE_ADHOC;
+ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+ wrqu->mode = IW_MODE_MASTER;
+ else
+ wrqu->mode = IW_MODE_AUTO;
+
+ _func_exit_;
+
+ return 0;
+}
+
+static int rtw_wx_set_pmkid(struct net_device *dev,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ u8 j, blInserted = false;
+ int ret = false;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct iw_pmksa *pPMK = (struct iw_pmksa *)extra;
+ u8 strZeroMacAddress[ETH_ALEN] = {0x00};
+ u8 strIssueBssid[ETH_ALEN] = {0x00};
+
+ memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN);
+ if (pPMK->cmd == IW_PMKSA_ADD) {
+ DBG_88E("[rtw_wx_set_pmkid] IW_PMKSA_ADD!\n");
+ if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN) == true)
+ return ret;
+ else
+ ret = true;
+ blInserted = false;
+
+ /* overwrite PMKID */
+ for (j = 0; j < NUM_PMKID_CACHE; j++) {
+ if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) {
+ /* BSSID is matched, the same AP => rewrite with new PMKID. */
+ DBG_88E("[rtw_wx_set_pmkid] BSSID exists in the PMKList.\n");
+ memcpy(psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, IW_PMKID_LEN);
+ psecuritypriv->PMKIDList[j].bUsed = true;
+ psecuritypriv->PMKIDIndex = j+1;
+ blInserted = true;
+ break;
+ }
+ }
+
+ if (!blInserted) {
+ /* Find a new entry */
+ DBG_88E("[rtw_wx_set_pmkid] Use the new entry index = %d for this PMKID.\n",
+ psecuritypriv->PMKIDIndex);
+
+ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN);
+ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN);
+
+ psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = true;
+ psecuritypriv->PMKIDIndex++;
+ if (psecuritypriv->PMKIDIndex == 16)
+ psecuritypriv->PMKIDIndex = 0;
+ }
+ } else if (pPMK->cmd == IW_PMKSA_REMOVE) {
+ DBG_88E("[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n");
+ ret = true;
+ for (j = 0; j < NUM_PMKID_CACHE; j++) {
+ if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) {
+ /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */
+ _rtw_memset(psecuritypriv->PMKIDList[j].Bssid, 0x00, ETH_ALEN);
+ psecuritypriv->PMKIDList[j].bUsed = false;
+ break;
+ }
+ }
+ } else if (pPMK->cmd == IW_PMKSA_FLUSH) {
+ DBG_88E("[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n");
+ _rtw_memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+ psecuritypriv->PMKIDIndex = 0;
+ ret = true;
+ }
+ return ret;
+}
+
+static int rtw_wx_get_sens(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ wrqu->sens.value = 0;
+ wrqu->sens.fixed = 0; /* no auto select */
+ wrqu->sens.disabled = 1;
+ return 0;
+}
+
+static int rtw_wx_get_range(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct iw_range *range = (struct iw_range *)extra;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ u16 val;
+ int i;
+
+ _func_enter_;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_range. cmd_code =%x\n", info->cmd));
+
+ wrqu->data.length = sizeof(*range);
+ _rtw_memset(range, 0, sizeof(*range));
+
+ /* Let's try to keep this struct in the same order as in
+ * linux/include/wireless.h
+ */
+
+ /* TODO: See what values we can set, and remove the ones we can't
+ * set, or fill them with some default data.
+ */
+
+ /* ~5 Mb/s real (802.11b) */
+ range->throughput = 5 * 1000 * 1000;
+
+ /* signal level threshold range */
+
+ /* percent values between 0 and 100. */
+ range->max_qual.qual = 100;
+ range->max_qual.level = 100;
+ range->max_qual.noise = 100;
+ range->max_qual.updated = 7; /* Updated all three */
+
+ range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
+ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+ range->avg_qual.level = 20 + -98;
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = 7; /* Updated all three */
+
+ range->num_bitrates = RATE_COUNT;
+
+ for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++)
+ range->bitrate[i] = rtw_rates[i];
+
+ range->min_frag = MIN_FRAG_THRESHOLD;
+ range->max_frag = MAX_FRAG_THRESHOLD;
+
+ range->pm_capa = 0;
+
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 16;
+
+ for (i = 0, val = 0; i < MAX_CHANNEL_NUM; i++) {
+ /* Include only legal frequencies for some countries */
+ if (pmlmeext->channel_set[i].ChannelNum != 0) {
+ range->freq[val].i = pmlmeext->channel_set[i].ChannelNum;
+ range->freq[val].m = rtw_ch2freq(pmlmeext->channel_set[i].ChannelNum) * 100000;
+ range->freq[val].e = 1;
+ val++;
+ }
+
+ if (val == IW_MAX_FREQUENCIES)
+ break;
+ }
+
+ range->num_channels = val;
+ range->num_frequency = val;
+
+/* The following code will proivde the security capability to network manager. */
+/* If the driver doesn't provide this capability to network manager, */
+/* the WPA/WPA2 routers can't be choosen in the network manager. */
+
+/*
+#define IW_SCAN_CAPA_NONE 0x00
+#define IW_SCAN_CAPA_ESSID 0x01
+#define IW_SCAN_CAPA_BSSID 0x02
+#define IW_SCAN_CAPA_CHANNEL 0x04
+#define IW_SCAN_CAPA_MODE 0x08
+#define IW_SCAN_CAPA_RATE 0x10
+#define IW_SCAN_CAPA_TYPE 0x20
+#define IW_SCAN_CAPA_TIME 0x40
+*/
+
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
+ range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE |
+ IW_SCAN_CAPA_BSSID | IW_SCAN_CAPA_CHANNEL |
+ IW_SCAN_CAPA_MODE | IW_SCAN_CAPA_RATE;
+ _func_exit_;
+
+ return 0;
+}
+
+/* set bssid flow */
+/* s1. rtw_set_802_11_infrastructure_mode() */
+/* s2. rtw_set_802_11_authentication_mode() */
+/* s3. set_802_11_encryption_mode() */
+/* s4. rtw_set_802_11_bssid() */
+static int rtw_wx_set_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *awrq,
+ char *extra)
+{
+ unsigned long irqL;
+ uint ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct sockaddr *temp = (struct sockaddr *)awrq;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct list_head *phead;
+ u8 *dst_bssid, *src_bssid;
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ enum ndis_802_11_auth_mode authmode;
+
+ _func_enter_;
+
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -1;
+ goto exit;
+ }
+
+ if (!padapter->bup) {
+ ret = -1;
+ goto exit;
+ }
+
+ if (temp->sa_family != ARPHRD_ETHER) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ authmode = padapter->securitypriv.ndisauthtype;
+ _enter_critical_bh(&queue->lock, &irqL);
+ phead = get_list_head(queue);
+ pmlmepriv->pscanned = get_next(phead);
+
+ while (1) {
+ if ((rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) == true)
+ break;
+
+ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+
+ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+
+ dst_bssid = pnetwork->network.MacAddress;
+
+ src_bssid = temp->sa_data;
+
+ if ((!memcmp(dst_bssid, src_bssid, ETH_ALEN))) {
+ if (!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) {
+ ret = -1;
+ _exit_critical_bh(&queue->lock, &irqL);
+ goto exit;
+ }
+
+ break;
+ }
+ }
+ _exit_critical_bh(&queue->lock, &irqL);
+
+ rtw_set_802_11_authentication_mode(padapter, authmode);
+ /* set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */
+ if (rtw_set_802_11_bssid(padapter, temp->sa_data) == false) {
+ ret = -1;
+ goto exit;
+ }
+
+exit:
+
+ _func_exit_;
+
+ return ret;
+}
+
+static int rtw_wx_get_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
+
+ wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+
+ _rtw_memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_wap\n"));
+
+ _func_enter_;
+
+ if (((check_fwstate(pmlmepriv, _FW_LINKED)) == true) ||
+ ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) ||
+ ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == true))
+ memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN);
+ else
+ _rtw_memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+
+ _func_exit_;
+
+ return 0;
+}
+
+static int rtw_wx_set_mlme(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ u16 reason;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
+
+ if (mlme == NULL)
+ return -1;
+
+ DBG_88E("%s\n", __func__);
+
+ reason = mlme->reason_code;
+
+ DBG_88E("%s, cmd =%d, reason =%d\n", __func__, mlme->cmd, reason);
+
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+ if (!rtw_set_802_11_disassociate(padapter))
+ ret = -1;
+ break;
+ case IW_MLME_DISASSOC:
+ if (!rtw_set_802_11_disassociate(padapter))
+ ret = -1;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ u8 _status = false;
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT];
+ unsigned long irqL;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_set_scan\n"));
+
+_func_enter_;
+ if (padapter->registrypriv.mp_mode == 1) {
+ if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
+ ret = -1;
+ goto exit;
+ }
+ }
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -1;
+ goto exit;
+ }
+
+ if (padapter->bDriverStopped) {
+ DBG_88E("bDriverStopped =%d\n", padapter->bDriverStopped);
+ ret = -1;
+ goto exit;
+ }
+
+ if (!padapter->bup) {
+ ret = -1;
+ goto exit;
+ }
+
+ if (!padapter->hw_init_completed) {
+ ret = -1;
+ goto exit;
+ }
+
+ /* When Busy Traffic, driver do not site survey. So driver return success. */
+ /* wpa_supplicant will not issue SIOCSIWSCAN cmd again after scan timeout. */
+ /* modify by thomas 2011-02-22. */
+ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) {
+ indicate_wx_scan_complete_event(padapter);
+ goto exit;
+ }
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) {
+ indicate_wx_scan_complete_event(padapter);
+ goto exit;
+ }
+
+/* For the DMP WiFi Display project, the driver won't to scan because */
+/* the pmlmepriv->scan_interval is always equal to 3. */
+/* So, the wpa_supplicant won't find out the WPS SoftAP. */
+
+#ifdef CONFIG_88EU_P2P
+ if (pwdinfo->p2p_state != P2P_STATE_NONE) {
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_FULL);
+ rtw_free_network_queue(padapter, true);
+ }
+#endif /* CONFIG_88EU_P2P */
+
+ _rtw_memset(ssid, 0, sizeof(struct ndis_802_11_ssid)*RTW_SSID_SCAN_AMOUNT);
+
+ if (wrqu->data.length == sizeof(struct iw_scan_req)) {
+ struct iw_scan_req *req = (struct iw_scan_req *)extra;
+
+ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+ int len = min((int)req->essid_len, IW_ESSID_MAX_SIZE);
+
+ memcpy(ssid[0].Ssid, req->essid, len);
+ ssid[0].SsidLength = len;
+
+ DBG_88E("IW_SCAN_THIS_ESSID, ssid =%s, len =%d\n", req->essid, req->essid_len);
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+ _status = rtw_sitesurvey_cmd(padapter, ssid, 1, NULL, 0);
+
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+ } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
+ DBG_88E("rtw_wx_set_scan, req->scan_type == IW_SCAN_TYPE_PASSIVE\n");
+ }
+ } else {
+ if (wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE &&
+ !memcmp(extra, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)) {
+ int len = wrqu->data.length - WEXT_CSCAN_HEADER_SIZE;
+ char *pos = extra+WEXT_CSCAN_HEADER_SIZE;
+ char section;
+ char sec_len;
+ int ssid_index = 0;
+
+ while (len >= 1) {
+ section = *(pos++);
+ len -= 1;
+
+ switch (section) {
+ case WEXT_CSCAN_SSID_SECTION:
+ if (len < 1) {
+ len = 0;
+ break;
+ }
+ sec_len = *(pos++); len -= 1;
+ if (sec_len > 0 && sec_len <= len) {
+ ssid[ssid_index].SsidLength = sec_len;
+ memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength);
+ ssid_index++;
+ }
+ pos += sec_len;
+ len -= sec_len;
+ break;
+ case WEXT_CSCAN_TYPE_SECTION:
+ case WEXT_CSCAN_CHANNEL_SECTION:
+ pos += 1;
+ len -= 1;
+ break;
+ case WEXT_CSCAN_PASV_DWELL_SECTION:
+ case WEXT_CSCAN_HOME_DWELL_SECTION:
+ case WEXT_CSCAN_ACTV_DWELL_SECTION:
+ pos += 2;
+ len -= 2;
+ break;
+ default:
+ len = 0; /* stop parsing */
+ }
+ }
+
+ /* it has still some scan paramater to parse, we only do this now... */
+ _status = rtw_set_802_11_bssid_list_scan(padapter, ssid, RTW_SSID_SCAN_AMOUNT);
+ } else {
+ _status = rtw_set_802_11_bssid_list_scan(padapter, NULL, 0);
+ }
+ }
+
+ if (!_status)
+ ret = -1;
+
+exit:
+
+_func_exit_;
+ return ret;
+}
+
+static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ char *ev = extra;
+ char *stop = ev + wrqu->data.length;
+ u32 ret = 0;
+ u32 cnt = 0;
+ u32 wait_for_surveydone;
+ int wait_status;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_88EU_P2P */
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan\n"));
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, (" Start of Query SIOCGIWSCAN .\n"));
+
+ _func_enter_;
+
+ if (padapter->pwrctrlpriv.brfoffbyhw && padapter->bDriverStopped) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+#ifdef CONFIG_88EU_P2P
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ /* P2P is enabled */
+ wait_for_surveydone = 200;
+ } else {
+ /* P2P is disabled */
+ wait_for_surveydone = 100;
+ }
+#else
+ {
+ wait_for_surveydone = 100;
+ }
+#endif /* CONFIG_88EU_P2P */
+
+ wait_status = _FW_UNDER_SURVEY | _FW_UNDER_LINKING;
+
+ while (check_fwstate(pmlmepriv, wait_status)) {
+ rtw_msleep_os(30);
+ cnt++;
+ if (cnt > wait_for_surveydone)
+ break;
+ }
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist))
+ break;
+
+ if ((stop - ev) < SCAN_ITEM_SIZE) {
+ ret = -E2BIG;
+ break;
+ }
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ /* report network only if the current channel set contains the channel to which this network belongs */
+ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0)
+ ev = translate_scan(padapter, a, pnetwork, ev, stop);
+
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ wrqu->data.length = ev-extra;
+ wrqu->data.flags = 0;
+
+exit:
+ _func_exit_;
+ return ret;
+}
+
+/* set ssid flow */
+/* s1. rtw_set_802_11_infrastructure_mode() */
+/* s2. set_802_11_authenticaion_mode() */
+/* s3. set_802_11_encryption_mode() */
+/* s4. rtw_set_802_11_ssid() */
+static int rtw_wx_set_essid(struct net_device *dev,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ unsigned long irqL;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct __queue *queue = &pmlmepriv->scanned_queue;
+ struct list_head *phead;
+ struct wlan_network *pnetwork = NULL;
+ enum ndis_802_11_auth_mode authmode;
+ struct ndis_802_11_ssid ndis_ssid;
+ u8 *dst_ssid, *src_ssid;
+
+ uint ret = 0, len;
+
+ _func_enter_;
+
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+ ("+rtw_wx_set_essid: fw_state = 0x%08x\n", get_fwstate(pmlmepriv)));
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -1;
+ goto exit;
+ }
+
+ if (!padapter->bup) {
+ ret = -1;
+ goto exit;
+ }
+
+ if (wrqu->essid.length > IW_ESSID_MAX_SIZE) {
+ ret = -E2BIG;
+ goto exit;
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ ret = -1;
+ goto exit;
+ }
+
+ authmode = padapter->securitypriv.ndisauthtype;
+ DBG_88E("=>%s\n", __func__);
+ if (wrqu->essid.flags && wrqu->essid.length) {
+ len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length : IW_ESSID_MAX_SIZE;
+
+ if (wrqu->essid.length != 33)
+ DBG_88E("ssid =%s, len =%d\n", extra, wrqu->essid.length);
+
+ _rtw_memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid));
+ ndis_ssid.SsidLength = len;
+ memcpy(ndis_ssid.Ssid, extra, len);
+ src_ssid = ndis_ssid.Ssid;
+
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: ssid =[%s]\n", src_ssid));
+ _enter_critical_bh(&queue->lock, &irqL);
+ phead = get_list_head(queue);
+ pmlmepriv->pscanned = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, pmlmepriv->pscanned) == true) {
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_warning_,
+ ("rtw_wx_set_essid: scan_q is empty, set ssid to check if scanning again!\n"));
+
+ break;
+ }
+
+ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+
+ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+
+ dst_ssid = pnetwork->network.Ssid.Ssid;
+
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+ ("rtw_wx_set_essid: dst_ssid =%s\n",
+ pnetwork->network.Ssid.Ssid));
+
+ if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength)) &&
+ (pnetwork->network.Ssid.SsidLength == ndis_ssid.SsidLength)) {
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+ ("rtw_wx_set_essid: find match, set infra mode\n"));
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) {
+ if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode)
+ continue;
+ }
+
+ if (!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) {
+ ret = -1;
+ _exit_critical_bh(&queue->lock, &irqL);
+ goto exit;
+ }
+
+ break;
+ }
+ }
+ _exit_critical_bh(&queue->lock, &irqL);
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+ ("set ssid: set_802_11_auth. mode =%d\n", authmode));
+ rtw_set_802_11_authentication_mode(padapter, authmode);
+ if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == false) {
+ ret = -1;
+ goto exit;
+ }
+ }
+
+exit:
+
+ DBG_88E("<=%s, ret %d\n", __func__, ret);
+
+ _func_exit_;
+
+ return ret;
+}
+
+static int rtw_wx_get_essid(struct net_device *dev,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ u32 len, ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_essid\n"));
+
+ _func_enter_;
+
+ if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) {
+ len = pcur_bss->Ssid.SsidLength;
+
+ wrqu->essid.length = len;
+
+ memcpy(extra, pcur_bss->Ssid.Ssid, len);
+
+ wrqu->essid.flags = 1;
+ } else {
+ ret = -1;
+ goto exit;
+ }
+
+exit:
+
+ _func_exit_;
+
+ return ret;
+}
+
+static int rtw_wx_set_rate(struct net_device *dev,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ int i, ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ u8 datarates[NumRates];
+ u32 target_rate = wrqu->bitrate.value;
+ u32 fixed = wrqu->bitrate.fixed;
+ u32 ratevalue = 0;
+ u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_set_rate\n"));
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("target_rate = %d, fixed = %d\n", target_rate, fixed));
+
+ if (target_rate == -1) {
+ ratevalue = 11;
+ goto set_rate;
+ }
+ target_rate = target_rate/100000;
+
+ switch (target_rate) {
+ case 10:
+ ratevalue = 0;
+ break;
+ case 20:
+ ratevalue = 1;
+ break;
+ case 55:
+ ratevalue = 2;
+ break;
+ case 60:
+ ratevalue = 3;
+ break;
+ case 90:
+ ratevalue = 4;
+ break;
+ case 110:
+ ratevalue = 5;
+ break;
+ case 120:
+ ratevalue = 6;
+ break;
+ case 180:
+ ratevalue = 7;
+ break;
+ case 240:
+ ratevalue = 8;
+ break;
+ case 360:
+ ratevalue = 9;
+ break;
+ case 480:
+ ratevalue = 10;
+ break;
+ case 540:
+ ratevalue = 11;
+ break;
+ default:
+ ratevalue = 11;
+ break;
+ }
+
+set_rate:
+
+ for (i = 0; i < NumRates; i++) {
+ if (ratevalue == mpdatarate[i]) {
+ datarates[i] = mpdatarate[i];
+ if (fixed == 0)
+ break;
+ } else {
+ datarates[i] = 0xff;
+ }
+
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("datarate_inx =%d\n", datarates[i]));
+ }
+
+ if (rtw_setdatarate_cmd(padapter, datarates) != _SUCCESS) {
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("rtw_wx_set_rate Fail!!!\n"));
+ ret = -1;
+ }
+
+_func_exit_;
+
+ return ret;
+}
+
+static int rtw_wx_get_rate(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ u16 max_rate = 0;
+
+ max_rate = rtw_get_cur_max_rate((struct adapter *)rtw_netdev_priv(dev));
+
+ if (max_rate == 0)
+ return -EPERM;
+
+ wrqu->bitrate.fixed = 0; /* no auto select */
+ wrqu->bitrate.value = max_rate * 100000;
+
+ return 0;
+}
+
+static int rtw_wx_set_rts(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ _func_enter_;
+
+ if (wrqu->rts.disabled) {
+ padapter->registrypriv.rts_thresh = 2347;
+ } else {
+ if (wrqu->rts.value < 0 ||
+ wrqu->rts.value > 2347)
+ return -EINVAL;
+
+ padapter->registrypriv.rts_thresh = wrqu->rts.value;
+ }
+
+ DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh);
+
+ _func_exit_;
+
+ return 0;
+}
+
+static int rtw_wx_get_rts(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ _func_enter_;
+
+ DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh);
+
+ wrqu->rts.value = padapter->registrypriv.rts_thresh;
+ wrqu->rts.fixed = 0; /* no auto select */
+ /* wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); */
+
+ _func_exit_;
+
+ return 0;
+}
+
+static int rtw_wx_set_frag(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ _func_enter_;
+
+ if (wrqu->frag.disabled) {
+ padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD;
+ } else {
+ if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
+ wrqu->frag.value > MAX_FRAG_THRESHOLD)
+ return -EINVAL;
+
+ padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1;
+ }
+
+ DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len);
+
+ _func_exit_;
+
+ return 0;
+}
+
+static int rtw_wx_get_frag(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ _func_enter_;
+
+ DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len);
+
+ wrqu->frag.value = padapter->xmitpriv.frag_len;
+ wrqu->frag.fixed = 0; /* no auto select */
+
+ _func_exit_;
+
+ return 0;
+}
+
+static int rtw_wx_get_retry(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ wrqu->retry.value = 7;
+ wrqu->retry.fixed = 0; /* no auto select */
+ wrqu->retry.disabled = 1;
+
+ return 0;
+}
+
+static int rtw_wx_set_enc(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *keybuf)
+{
+ u32 key, ret = 0;
+ u32 keyindex_provided;
+ struct ndis_802_11_wep wep;
+ enum ndis_802_11_auth_mode authmode;
+
+ struct iw_point *erq = &(wrqu->encoding);
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ DBG_88E("+rtw_wx_set_enc, flags = 0x%x\n", erq->flags);
+
+ _rtw_memset(&wep, 0, sizeof(struct ndis_802_11_wep));
+
+ key = erq->flags & IW_ENCODE_INDEX;
+
+ _func_enter_;
+
+ if (erq->flags & IW_ENCODE_DISABLED) {
+ DBG_88E("EncryptionDisabled\n");
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ authmode = Ndis802_11AuthModeOpen;
+ padapter->securitypriv.ndisauthtype = authmode;
+
+ goto exit;
+ }
+
+ if (key) {
+ if (key > WEP_KEYS)
+ return -EINVAL;
+ key--;
+ keyindex_provided = 1;
+ } else {
+ keyindex_provided = 0;
+ key = padapter->securitypriv.dot11PrivacyKeyIndex;
+ DBG_88E("rtw_wx_set_enc, key =%d\n", key);
+ }
+
+ /* set authentication mode */
+ if (erq->flags & IW_ENCODE_OPEN) {
+ DBG_88E("rtw_wx_set_enc():IW_ENCODE_OPEN\n");
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ authmode = Ndis802_11AuthModeOpen;
+ padapter->securitypriv.ndisauthtype = authmode;
+ } else if (erq->flags & IW_ENCODE_RESTRICTED) {
+ DBG_88E("rtw_wx_set_enc():IW_ENCODE_RESTRICTED\n");
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
+ authmode = Ndis802_11AuthModeShared;
+ padapter->securitypriv.ndisauthtype = authmode;
+ } else {
+ DBG_88E("rtw_wx_set_enc():erq->flags = 0x%x\n", erq->flags);
+
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ authmode = Ndis802_11AuthModeOpen;
+ padapter->securitypriv.ndisauthtype = authmode;
+ }
+
+ wep.KeyIndex = key;
+ if (erq->length > 0) {
+ wep.KeyLength = erq->length <= 5 ? 5 : 13;
+
+ wep.Length = wep.KeyLength + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
+ } else {
+ wep.KeyLength = 0;
+
+ if (keyindex_provided == 1) {
+ /* set key_id only, no given KeyMaterial(erq->length == 0). */
+ padapter->securitypriv.dot11PrivacyKeyIndex = key;
+
+ DBG_88E("(keyindex_provided == 1), keyid =%d, key_len =%d\n", key, padapter->securitypriv.dot11DefKeylen[key]);
+
+ switch (padapter->securitypriv.dot11DefKeylen[key]) {
+ case 5:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+ break;
+ case 13:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+ break;
+ default:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ break;
+ }
+
+ goto exit;
+ }
+ }
+
+ wep.KeyIndex |= 0x80000000;
+
+ memcpy(wep.KeyMaterial, keybuf, wep.KeyLength);
+
+ if (rtw_set_802_11_add_wep(padapter, &wep) == false) {
+ if (rf_on == pwrpriv->rf_pwrstate)
+ ret = -EOPNOTSUPP;
+ goto exit;
+ }
+
+exit:
+
+ _func_exit_;
+
+ return ret;
+}
+
+static int rtw_wx_get_enc(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *keybuf)
+{
+ uint key, ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct iw_point *erq = &(wrqu->encoding);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ _func_enter_;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) != true) {
+ if (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ return 0;
+ }
+ }
+
+ key = erq->flags & IW_ENCODE_INDEX;
+
+ if (key) {
+ if (key > WEP_KEYS)
+ return -EINVAL;
+ key--;
+ } else {
+ key = padapter->securitypriv.dot11PrivacyKeyIndex;
+ }
+
+ erq->flags = key + 1;
+
+ switch (padapter->securitypriv.ndisencryptstatus) {
+ case Ndis802_11EncryptionNotSupported:
+ case Ndis802_11EncryptionDisabled:
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ break;
+ case Ndis802_11Encryption1Enabled:
+ erq->length = padapter->securitypriv.dot11DefKeylen[key];
+ if (erq->length) {
+ memcpy(keybuf, padapter->securitypriv.dot11DefKey[key].skey, padapter->securitypriv.dot11DefKeylen[key]);
+
+ erq->flags |= IW_ENCODE_ENABLED;
+
+ if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen)
+ erq->flags |= IW_ENCODE_OPEN;
+ else if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeShared)
+ erq->flags |= IW_ENCODE_RESTRICTED;
+ } else {
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ }
+ break;
+ case Ndis802_11Encryption2Enabled:
+ case Ndis802_11Encryption3Enabled:
+ erq->length = 16;
+ erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN | IW_ENCODE_NOKEY);
+ break;
+ default:
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ break;
+ }
+ _func_exit_;
+
+ return ret;
+}
+
+static int rtw_wx_get_power(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ wrqu->power.value = 0;
+ wrqu->power.fixed = 0; /* no auto select */
+ wrqu->power.disabled = 1;
+
+ return 0;
+}
+
+static int rtw_wx_set_gen_ie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ ret = rtw_set_wpa_ie(padapter, extra, wrqu->data.length);
+ return ret;
+}
+
+static int rtw_wx_set_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct iw_param *param = (struct iw_param *)&(wrqu->param);
+ int ret = 0;
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ break;
+ case IW_AUTH_CIPHER_PAIRWISE:
+
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+
+ break;
+ case IW_AUTH_KEY_MGMT:
+ /*
+ * ??? does not use these parameters
+ */
+ break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ if (param->value) {
+ /* wpa_supplicant is enabling the tkip countermeasure. */
+ padapter->securitypriv.btkip_countermeasure = true;
+ } else {
+ /* wpa_supplicant is disabling the tkip countermeasure. */
+ padapter->securitypriv.btkip_countermeasure = false;
+ }
+ break;
+ case IW_AUTH_DROP_UNENCRYPTED:
+ /* HACK:
+ *
+ * wpa_supplicant calls set_wpa_enabled when the driver
+ * is loaded and unloaded, regardless of if WPA is being
+ * used. No other calls are made which can be used to
+ * determine if encryption will be used or not prior to
+ * association being expected. If encryption is not being
+ * used, drop_unencrypted is set to false, else true -- we
+ * can use this to determine if the CAP_PRIVACY_ON bit should
+ * be set.
+ */
+
+ if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled)
+ break;/* it means init value, or using wep, ndisencryptstatus = Ndis802_11Encryption1Enabled, */
+ /* then it needn't reset it; */
+
+ if (param->value) {
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+ }
+
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ /*
+ * It's the starting point of a link layer connection using wpa_supplicant
+ */
+ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+ LeaveAllPowerSaveMode(padapter);
+ rtw_disassoc_cmd(padapter, 500, false);
+ DBG_88E("%s...call rtw_indicate_disconnect\n ", __func__);
+ rtw_indicate_disconnect(padapter);
+ rtw_free_assoc_resources(padapter, 1);
+ }
+ ret = wpa_set_auth_algs(dev, (u32)param->value);
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ break;
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ break;
+ case IW_AUTH_PRIVACY_INVOKED:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+static int rtw_wx_set_enc_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ char *alg_name;
+ u32 param_len;
+ struct ieee_param *param = NULL;
+ struct iw_point *pencoding = &wrqu->encoding;
+ struct iw_encode_ext *pext = (struct iw_encode_ext *)extra;
+ int ret = 0;
+
+ param_len = sizeof(struct ieee_param) + pext->key_len;
+ param = (struct ieee_param *)rtw_malloc(param_len);
+ if (param == NULL)
+ return -1;
+
+ _rtw_memset(param, 0, param_len);
+
+ param->cmd = IEEE_CMD_SET_ENCRYPTION;
+ _rtw_memset(param->sta_addr, 0xff, ETH_ALEN);
+
+ switch (pext->alg) {
+ case IW_ENCODE_ALG_NONE:
+ /* todo: remove key */
+ /* remove = 1; */
+ alg_name = "none";
+ break;
+ case IW_ENCODE_ALG_WEP:
+ alg_name = "WEP";
+ break;
+ case IW_ENCODE_ALG_TKIP:
+ alg_name = "TKIP";
+ break;
+ case IW_ENCODE_ALG_CCMP:
+ alg_name = "CCMP";
+ break;
+ default:
+ return -1;
+ }
+
+ strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
+
+ if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ param->u.crypt.set_tx = 1;
+
+ /* cliW: WEP does not have group key
+ * just not checking GROUP key setting
+ */
+ if ((pext->alg != IW_ENCODE_ALG_WEP) &&
+ (pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY))
+ param->u.crypt.set_tx = 0;
+
+ param->u.crypt.idx = (pencoding->flags&0x00FF) - 1;
+
+ if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+ memcpy(param->u.crypt.seq, pext->rx_seq, 8);
+
+ if (pext->key_len) {
+ param->u.crypt.key_len = pext->key_len;
+ memcpy(param->u.crypt.key, pext + 1, pext->key_len);
+ }
+
+ ret = wpa_set_encryption(dev, param, param_len);
+
+ kfree(param);
+ return ret;
+}
+
+static int rtw_wx_get_nick(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ if (extra) {
+ wrqu->data.length = 14;
+ wrqu->data.flags = 1;
+ memcpy(extra, "<WIFI@REALTEK>", 14);
+ }
+
+ /* dump debug info here */
+ return 0;
+}
+
+static int rtw_wx_read32(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter;
+ struct iw_point *p;
+ u16 len;
+ u32 addr;
+ u32 data32;
+ u32 bytes;
+ u8 *ptmp;
+
+ padapter = (struct adapter *)rtw_netdev_priv(dev);
+ p = &wrqu->data;
+ len = p->length;
+ ptmp = (u8 *)rtw_malloc(len);
+ if (NULL == ptmp)
+ return -ENOMEM;
+
+ if (copy_from_user(ptmp, p->pointer, len)) {
+ kfree(ptmp);
+ return -EFAULT;
+ }
+
+ bytes = 0;
+ addr = 0;
+ sscanf(ptmp, "%d,%x", &bytes, &addr);
+
+ switch (bytes) {
+ case 1:
+ data32 = rtw_read8(padapter, addr);
+ sprintf(extra, "0x%02X", data32);
+ break;
+ case 2:
+ data32 = rtw_read16(padapter, addr);
+ sprintf(extra, "0x%04X", data32);
+ break;
+ case 4:
+ data32 = rtw_read32(padapter, addr);
+ sprintf(extra, "0x%08X", data32);
+ break;
+ default:
+ DBG_88E(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__);
+ return -EINVAL;
+ }
+ DBG_88E(KERN_INFO "%s: addr = 0x%08X data =%s\n", __func__, addr, extra);
+
+ kfree(ptmp);
+ return 0;
+}
+
+static int rtw_wx_write32(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ u32 addr;
+ u32 data32;
+ u32 bytes;
+
+ bytes = 0;
+ addr = 0;
+ data32 = 0;
+ sscanf(extra, "%d,%x,%x", &bytes, &addr, &data32);
+
+ switch (bytes) {
+ case 1:
+ rtw_write8(padapter, addr, (u8)data32);
+ DBG_88E(KERN_INFO "%s: addr = 0x%08X data = 0x%02X\n", __func__, addr, (u8)data32);
+ break;
+ case 2:
+ rtw_write16(padapter, addr, (u16)data32);
+ DBG_88E(KERN_INFO "%s: addr = 0x%08X data = 0x%04X\n", __func__, addr, (u16)data32);
+ break;
+ case 4:
+ rtw_write32(padapter, addr, data32);
+ DBG_88E(KERN_INFO "%s: addr = 0x%08X data = 0x%08X\n", __func__, addr, data32);
+ break;
+ default:
+ DBG_88E(KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rtw_wx_read_rf(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ u32 path, addr, data32;
+
+ path = *(u32 *)extra;
+ addr = *((u32 *)extra + 1);
+ data32 = rtw_hal_read_rfreg(padapter, path, addr, 0xFFFFF);
+ /*
+ * IMPORTANT!!
+ * Only when wireless private ioctl is at odd order,
+ * "extra" would be copied to user space.
+ */
+ sprintf(extra, "0x%05x", data32);
+
+ return 0;
+}
+
+static int rtw_wx_write_rf(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ u32 path, addr, data32;
+
+ path = *(u32 *)extra;
+ addr = *((u32 *)extra + 1);
+ data32 = *((u32 *)extra + 2);
+ rtw_hal_write_rfreg(padapter, path, addr, 0xFFFFF, data32);
+
+ return 0;
+}
+
+static int rtw_wx_priv_null(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b)
+{
+ return -1;
+}
+
+static int dummy(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b)
+{
+ return -1;
+}
+
+static int rtw_wx_set_channel_plan(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ u8 channel_plan_req = (u8) (*((int *)wrqu));
+
+ if (_SUCCESS == rtw_set_chplan_cmd(padapter, channel_plan_req, 1))
+ DBG_88E("%s set channel_plan = 0x%02X\n", __func__, pmlmepriv->ChannelPlan);
+ else
+ return -EPERM;
+
+ return 0;
+}
+
+static int rtw_wx_set_mtk_wps_probe_ie(struct net_device *dev,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b)
+{
+ return 0;
+}
+
+static int rtw_wx_get_sensitivity(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *buf)
+{
+ return 0;
+}
+
+static int rtw_wx_set_mtk_wps_ie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ return 0;
+}
+
+/*
+ * For all data larger than 16 octets, we need to use a
+ * pointer to memory allocated in user space.
+ */
+static int rtw_drvext_hdl(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ return 0;
+}
+
+static void rtw_dbg_mode_hdl(struct adapter *padapter, u32 id, u8 *pdata, u32 len)
+{
+ struct mp_rw_reg *RegRWStruct;
+ struct rf_reg_param *prfreg;
+ u8 path;
+ u8 offset;
+ u32 value;
+
+ DBG_88E("%s\n", __func__);
+
+ switch (id) {
+ case GEN_MP_IOCTL_SUBCODE(MP_START):
+ DBG_88E("871x_driver is only for normal mode, can't enter mp mode\n");
+ break;
+ case GEN_MP_IOCTL_SUBCODE(READ_REG):
+ RegRWStruct = (struct mp_rw_reg *)pdata;
+ switch (RegRWStruct->width) {
+ case 1:
+ RegRWStruct->value = rtw_read8(padapter, RegRWStruct->offset);
+ break;
+ case 2:
+ RegRWStruct->value = rtw_read16(padapter, RegRWStruct->offset);
+ break;
+ case 4:
+ RegRWStruct->value = rtw_read32(padapter, RegRWStruct->offset);
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case GEN_MP_IOCTL_SUBCODE(WRITE_REG):
+ RegRWStruct = (struct mp_rw_reg *)pdata;
+ switch (RegRWStruct->width) {
+ case 1:
+ rtw_write8(padapter, RegRWStruct->offset, (u8)RegRWStruct->value);
+ break;
+ case 2:
+ rtw_write16(padapter, RegRWStruct->offset, (u16)RegRWStruct->value);
+ break;
+ case 4:
+ rtw_write32(padapter, RegRWStruct->offset, (u32)RegRWStruct->value);
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case GEN_MP_IOCTL_SUBCODE(READ_RF_REG):
+
+ prfreg = (struct rf_reg_param *)pdata;
+
+ path = (u8)prfreg->path;
+ offset = (u8)prfreg->offset;
+
+ value = rtw_hal_read_rfreg(padapter, path, offset, 0xffffffff);
+
+ prfreg->value = value;
+
+ break;
+ case GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG):
+
+ prfreg = (struct rf_reg_param *)pdata;
+
+ path = (u8)prfreg->path;
+ offset = (u8)prfreg->offset;
+ value = prfreg->value;
+
+ rtw_hal_write_rfreg(padapter, path, offset, 0xffffffff, value);
+
+ break;
+ case GEN_MP_IOCTL_SUBCODE(TRIGGER_GPIO):
+ DBG_88E("==> trigger gpio 0\n");
+ rtw_hal_set_hwreg(padapter, HW_VAR_TRIGGER_GPIO_0, NULL);
+ break;
+ case GEN_MP_IOCTL_SUBCODE(GET_WIFI_STATUS):
+ *pdata = rtw_hal_sreset_get_wifi_status(padapter);
+ break;
+ default:
+ break;
+ }
+}
+
+static int rtw_mp_ioctl_hdl(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ u32 BytesRead, BytesWritten, BytesNeeded;
+ struct oid_par_priv oid_par;
+ struct mp_ioctl_handler *phandler;
+ struct mp_ioctl_param *poidparam;
+ uint status = 0;
+ u16 len;
+ u8 *pparmbuf = NULL, bset;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct iw_point *p = &wrqu->data;
+
+ if ((!p->length) || (!p->pointer)) {
+ ret = -EINVAL;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+ pparmbuf = NULL;
+ bset = (u8)(p->flags & 0xFFFF);
+ len = p->length;
+ pparmbuf = (u8 *)rtw_malloc(len);
+ if (pparmbuf == NULL) {
+ ret = -ENOMEM;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+ if (copy_from_user(pparmbuf, p->pointer, len)) {
+ ret = -EFAULT;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+ poidparam = (struct mp_ioctl_param *)pparmbuf;
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+ ("rtw_mp_ioctl_hdl: subcode [%d], len[%d], buffer_len[%d]\r\n",
+ poidparam->subcode, poidparam->len, len));
+
+ if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) {
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("no matching drvext subcodes\r\n"));
+ ret = -EINVAL;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+ if (padapter->registrypriv.mp_mode == 1) {
+ phandler = mp_ioctl_hdl + poidparam->subcode;
+
+ if ((phandler->paramsize != 0) && (poidparam->len < phandler->paramsize)) {
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_,
+ ("no matching drvext param size %d vs %d\r\n",
+ poidparam->len, phandler->paramsize));
+ ret = -EINVAL;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+ if (phandler->handler) {
+ oid_par.adapter_context = padapter;
+ oid_par.oid = phandler->oid;
+ oid_par.information_buf = poidparam->data;
+ oid_par.information_buf_len = poidparam->len;
+ oid_par.dbg = 0;
+
+ BytesWritten = 0;
+ BytesNeeded = 0;
+
+ if (bset) {
+ oid_par.bytes_rw = &BytesRead;
+ oid_par.bytes_needed = &BytesNeeded;
+ oid_par.type_of_oid = SET_OID;
+ } else {
+ oid_par.bytes_rw = &BytesWritten;
+ oid_par.bytes_needed = &BytesNeeded;
+ oid_par.type_of_oid = QUERY_OID;
+ }
+
+ status = phandler->handler(&oid_par);
+ } else {
+ DBG_88E("rtw_mp_ioctl_hdl(): err!, subcode =%d, oid =%d, handler =%p\n",
+ poidparam->subcode, phandler->oid, phandler->handler);
+ ret = -EFAULT;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+ } else {
+ rtw_dbg_mode_hdl(padapter, poidparam->subcode, poidparam->data, poidparam->len);
+ }
+
+ if (bset == 0x00) {/* query info */
+ if (copy_to_user(p->pointer, pparmbuf, len))
+ ret = -EFAULT;
+ }
+
+ if (status) {
+ ret = -EFAULT;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+_rtw_mp_ioctl_hdl_exit:
+
+ kfree(pparmbuf);
+ return ret;
+}
+
+static int rtw_get_ap_info(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ u32 cnt = 0, wpa_ielen;
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ unsigned char *pbuf;
+ u8 bssid[ETH_ALEN];
+ char data[32];
+ struct wlan_network *pnetwork = NULL;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct iw_point *pdata = &wrqu->data;
+
+ DBG_88E("+rtw_get_aplist_info\n");
+
+ if ((padapter->bDriverStopped) || (pdata == NULL)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ while ((check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)))) {
+ rtw_msleep_os(30);
+ cnt++;
+ if (cnt > 100)
+ break;
+ }
+ pdata->flags = 0;
+ if (pdata->length >= 32) {
+ if (copy_from_user(data, pdata->pointer, 32)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ } else {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ if (hwaddr_aton_i(data, bssid)) {
+ DBG_88E("Invalid BSSID '%s'.\n", (u8 *)data);
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+ return -EINVAL;
+ }
+
+ if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN) == true) {
+ /* BSSID match, then check if supporting wpa/wpa2 */
+ DBG_88E("BSSID:%pM\n", (bssid));
+
+ pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
+ if (pbuf && (wpa_ielen > 0)) {
+ pdata->flags = 1;
+ break;
+ }
+
+ pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
+ if (pbuf && (wpa_ielen > 0)) {
+ pdata->flags = 2;
+ break;
+ }
+ }
+
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (pdata->length >= 34) {
+ if (copy_to_user(pdata->pointer+32, (u8 *)&pdata->flags, 1)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+exit:
+
+ return ret;
+}
+
+static int rtw_set_pid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ int *pdata = (int *)wrqu;
+ int selector;
+
+ if ((padapter->bDriverStopped) || (pdata == NULL)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ selector = *pdata;
+ if (selector < 3 && selector >= 0) {
+ padapter->pid[selector] = *(pdata+1);
+ ui_pid[selector] = *(pdata+1);
+ DBG_88E("%s set pid[%d] =%d\n", __func__, selector, padapter->pid[selector]);
+ } else {
+ DBG_88E("%s selector %d error\n", __func__, selector);
+ }
+exit:
+ return ret;
+}
+
+static int rtw_wps_start(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ u32 u32wps_start = 0;
+
+ ret = copy_from_user((void *)&u32wps_start, pdata->pointer, 4);
+ if (ret) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if ((padapter->bDriverStopped) || (pdata == NULL)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (u32wps_start == 0)
+ u32wps_start = *extra;
+
+ DBG_88E("[%s] wps_start = %d\n", __func__, u32wps_start);
+
+ if (u32wps_start == 1) /* WPS Start */
+ rtw_led_control(padapter, LED_CTL_START_WPS);
+ else if (u32wps_start == 2) /* WPS Stop because of wps success */
+ rtw_led_control(padapter, LED_CTL_STOP_WPS);
+ else if (u32wps_start == 3) /* WPS Stop because of wps fail */
+ rtw_led_control(padapter, LED_CTL_STOP_WPS_FAIL);
+
+exit:
+ return ret;
+}
+
+#ifdef CONFIG_88EU_P2P
+static int rtw_wext_p2p_enable(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ enum P2P_ROLE init_role = P2P_ROLE_DISABLE;
+
+ if (*extra == '0')
+ init_role = P2P_ROLE_DISABLE;
+ else if (*extra == '1')
+ init_role = P2P_ROLE_DEVICE;
+ else if (*extra == '2')
+ init_role = P2P_ROLE_CLIENT;
+ else if (*extra == '3')
+ init_role = P2P_ROLE_GO;
+
+ if (_FAIL == rtw_p2p_enable(padapter, init_role)) {
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ /* set channel/bandwidth */
+ if (init_role != P2P_ROLE_DISABLE) {
+ u8 channel, ch_offset;
+ u16 bwmode;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN)) {
+ /* Stay at the listen state and wait for discovery. */
+ channel = pwdinfo->listen_channel;
+ pwdinfo->operating_channel = pwdinfo->listen_channel;
+ ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ bwmode = HT_CHANNEL_WIDTH_20;
+ } else {
+ pwdinfo->operating_channel = pmlmeext->cur_channel;
+
+ channel = pwdinfo->operating_channel;
+ ch_offset = pmlmeext->cur_ch_offset;
+ bwmode = pmlmeext->cur_bwmode;
+ }
+
+ set_channel_bwmode(padapter, channel, ch_offset, bwmode);
+ }
+
+exit:
+ return ret;
+}
+
+static int rtw_p2p_set_go_nego_ssid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ DBG_88E("[%s] ssid = %s, len = %zu\n", __func__, extra, strlen(extra));
+ memcpy(pwdinfo->nego_ssid, extra, strlen(extra));
+ pwdinfo->nego_ssidlen = strlen(extra);
+
+ return ret;
+}
+
+static int rtw_p2p_set_intent(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 intent = pwdinfo->intent;
+
+ switch (wrqu->data.length) {
+ case 1:
+ intent = extra[0] - '0';
+ break;
+ case 2:
+ intent = str_2char2num(extra[0], extra[1]);
+ break;
+ }
+ if (intent <= 15)
+ pwdinfo->intent = intent;
+ else
+ ret = -1;
+ DBG_88E("[%s] intent = %d\n", __func__, intent);
+ return ret;
+}
+
+static int rtw_p2p_set_listen_ch(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 listen_ch = pwdinfo->listen_channel; /* Listen channel number */
+
+ switch (wrqu->data.length) {
+ case 1:
+ listen_ch = extra[0] - '0';
+ break;
+ case 2:
+ listen_ch = str_2char2num(extra[0], extra[1]);
+ break;
+ }
+
+ if ((listen_ch == 1) || (listen_ch == 6) || (listen_ch == 11)) {
+ pwdinfo->listen_channel = listen_ch;
+ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+ } else {
+ ret = -1;
+ }
+
+ DBG_88E("[%s] listen_ch = %d\n", __func__, pwdinfo->listen_channel);
+
+ return ret;
+}
+
+static int rtw_p2p_set_op_ch(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+/* Commented by Albert 20110524 */
+/* This function is used to set the operating channel if the driver will become the group owner */
+
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 op_ch = pwdinfo->operating_channel; /* Operating channel number */
+
+ switch (wrqu->data.length) {
+ case 1:
+ op_ch = extra[0] - '0';
+ break;
+ case 2:
+ op_ch = str_2char2num(extra[0], extra[1]);
+ break;
+ }
+
+ if (op_ch > 0)
+ pwdinfo->operating_channel = op_ch;
+ else
+ ret = -1;
+
+ DBG_88E("[%s] op_ch = %d\n", __func__, pwdinfo->operating_channel);
+
+ return ret;
+}
+
+static int rtw_p2p_profilefound(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ /* Comment by Albert 2010/10/13 */
+ /* Input data format: */
+ /* Ex: 0 */
+ /* Ex: 1XX:XX:XX:XX:XX:XXYYSSID */
+ /* 0 => Reflush the profile record list. */
+ /* 1 => Add the profile list */
+ /* XX:XX:XX:XX:XX:XX => peer's MAC Address (ex: 00:E0:4C:00:00:01) */
+ /* YY => SSID Length */
+ /* SSID => SSID for persistence group */
+
+ DBG_88E("[%s] In value = %s, len = %d\n", __func__, extra, wrqu->data.length - 1);
+
+ /* The upper application should pass the SSID to driver by using this rtw_p2p_profilefound function. */
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ if (extra[0] == '0') {
+ /* Remove all the profile information of wifidirect_info structure. */
+ _rtw_memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM);
+ pwdinfo->profileindex = 0;
+ } else {
+ if (pwdinfo->profileindex >= P2P_MAX_PERSISTENT_GROUP_NUM) {
+ ret = -1;
+ } else {
+ int jj, kk;
+
+ /* Add this profile information into pwdinfo->profileinfo */
+ /* Ex: 1XX:XX:XX:XX:XX:XXYYSSID */
+ for (jj = 0, kk = 1; jj < ETH_ALEN; jj++, kk += 3)
+ pwdinfo->profileinfo[pwdinfo->profileindex].peermac[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ pwdinfo->profileinfo[pwdinfo->profileindex].ssidlen = (extra[18] - '0') * 10 + (extra[19] - '0');
+ memcpy(pwdinfo->profileinfo[pwdinfo->profileindex].ssid, &extra[20], pwdinfo->profileinfo[pwdinfo->profileindex].ssidlen);
+ pwdinfo->profileindex++;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int rtw_p2p_setDN(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ DBG_88E("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+ _rtw_memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN);
+ memcpy(pwdinfo->device_name, extra, wrqu->data.length - 1);
+ pwdinfo->device_name_len = wrqu->data.length - 1;
+
+ return ret;
+}
+
+static int rtw_p2p_get_status(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ if (padapter->bShowGetP2PState)
+ DBG_88E("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2],
+ pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+
+ /* Commented by Albert 2010/10/12 */
+ /* Because of the output size limitation, I had removed the "Role" information. */
+ /* About the "Role" information, we will use the new private IOCTL to get the "Role" information. */
+ sprintf(extra, "\n\nStatus =%.2d\n", rtw_p2p_state(pwdinfo));
+ wrqu->data.length = strlen(extra);
+
+ return ret;
+}
+
+/* Commented by Albert 20110520 */
+/* This function will return the config method description */
+/* This config method description will show us which config method the remote P2P device is intented to use */
+/* by sending the provisioning discovery request frame. */
+
+static int rtw_p2p_get_req_cm(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ sprintf(extra, "\n\nCM =%s\n", pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req);
+ wrqu->data.length = strlen(extra);
+ return ret;
+}
+
+static int rtw_p2p_get_role(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ DBG_88E("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2],
+ pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+
+ sprintf(extra, "\n\nRole =%.2d\n", rtw_p2p_role(pwdinfo));
+ wrqu->data.length = strlen(extra);
+ return ret;
+}
+
+static int rtw_p2p_get_peer_ifaddr(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ DBG_88E("[%s] Role = %d, Status = %d, peer addr = %pM\n", __func__,
+ rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+ pwdinfo->p2p_peer_interface_addr);
+ sprintf(extra, "\nMAC %pM",
+ pwdinfo->p2p_peer_interface_addr);
+ wrqu->data.length = strlen(extra);
+ return ret;
+}
+
+static int rtw_p2p_get_peer_devaddr(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ DBG_88E("[%s] Role = %d, Status = %d, peer addr = %pM\n", __func__,
+ rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+ pwdinfo->rx_prov_disc_info.peerDevAddr);
+ sprintf(extra, "\n%pM",
+ pwdinfo->rx_prov_disc_info.peerDevAddr);
+ wrqu->data.length = strlen(extra);
+ return ret;
+}
+
+static int rtw_p2p_get_peer_devaddr_by_invitation(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ DBG_88E("[%s] Role = %d, Status = %d, peer addr = %pM\n",
+ __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+ pwdinfo->p2p_peer_device_addr);
+ sprintf(extra, "\nMAC %pM",
+ pwdinfo->p2p_peer_device_addr);
+ wrqu->data.length = strlen(extra);
+ return ret;
+}
+
+static int rtw_p2p_get_groupid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ sprintf(extra, "\n%.2X:%.2X:%.2X:%.2X:%.2X:%.2X %s",
+ pwdinfo->groupid_info.go_device_addr[0], pwdinfo->groupid_info.go_device_addr[1],
+ pwdinfo->groupid_info.go_device_addr[2], pwdinfo->groupid_info.go_device_addr[3],
+ pwdinfo->groupid_info.go_device_addr[4], pwdinfo->groupid_info.go_device_addr[5],
+ pwdinfo->groupid_info.ssid);
+ wrqu->data.length = strlen(extra);
+ return ret;
+}
+
+static int rtw_p2p_get_op_ch(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ DBG_88E("[%s] Op_ch = %02x\n", __func__, pwdinfo->operating_channel);
+
+ sprintf(extra, "\n\nOp_ch =%.2d\n", pwdinfo->operating_channel);
+ wrqu->data.length = strlen(extra);
+ return ret;
+}
+
+static int rtw_p2p_get_wps_configmethod(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ u8 peerMAC[ETH_ALEN] = {0x00};
+ int jj, kk;
+ u8 peerMACStr[17] = {0x00};
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 blnMatch = 0;
+ u16 attr_content = 0;
+ uint attr_contentlen = 0;
+ /* 6 is the string "wpsCM =", 17 is the MAC addr, we have to clear it at wrqu->data.pointer */
+ u8 attr_content_str[6 + 17] = {0x00};
+
+ /* Commented by Albert 20110727 */
+ /* The input data is the MAC address which the application wants to know its WPS config method. */
+ /* After knowing its WPS config method, the application can decide the config method for provisioning discovery. */
+ /* Format: iwpriv wlanx p2p_get_wpsCM 00:E0:4C:00:00:05 */
+
+ DBG_88E("[%s] data = %s\n", __func__, (char *)extra);
+ if (copy_from_user(peerMACStr, wrqu->data.pointer + 6, 17))
+ return -EFAULT;
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ u8 *wpsie;
+ uint wpsie_len = 0;
+ __be16 be_tmp;
+
+ /* The mac address is matched. */
+ wpsie = rtw_get_wps_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &wpsie_len);
+ if (wpsie) {
+ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_CONF_METHOD, (u8 *) &be_tmp, &attr_contentlen);
+ if (attr_contentlen) {
+ attr_content = be16_to_cpu(be_tmp);
+ sprintf(attr_content_str, "\n\nM =%.4d", attr_content);
+ blnMatch = 1;
+ }
+ }
+ break;
+ }
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (!blnMatch)
+ sprintf(attr_content_str, "\n\nM = 0000");
+
+ if (copy_to_user(wrqu->data.pointer, attr_content_str, 6 + 17))
+ return -EFAULT;
+ return ret;
+}
+
+static int rtw_p2p_get_go_device_address(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ u8 peerMAC[ETH_ALEN] = {0x00};
+ int jj, kk;
+ u8 peerMACStr[17] = {0x00};
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 blnMatch = 0;
+ u8 *p2pie;
+ uint p2pielen = 0, attr_contentlen = 0;
+ u8 attr_content[100] = {0x00};
+
+ u8 go_devadd_str[17 + 10] = {0x00};
+ /* +10 is for the str "go_devadd =", we have to clear it at wrqu->data.pointer */
+
+ /* Commented by Albert 20121209 */
+ /* The input data is the GO's interface address which the application wants to know its device address. */
+ /* Format: iwpriv wlanx p2p_get2 go_devadd = 00:E0:4C:00:00:05 */
+
+ DBG_88E("[%s] data = %s\n", __func__, (char *)extra);
+ if (copy_from_user(peerMACStr, wrqu->data.pointer + 10, 17))
+ return -EFAULT;
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ /* Commented by Albert 2011/05/18 */
+ /* Match the device address located in the P2P IE */
+ /* This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+ p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen);
+ if (p2pie) {
+ while (p2pie) {
+ /* The P2P Device ID attribute is included in the Beacon frame. */
+ /* The P2P Device Info attribute is included in the probe response frame. */
+
+ _rtw_memset(attr_content, 0x00, 100);
+ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device ID attribute of Beacon first */
+ blnMatch = 1;
+ break;
+ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device Info attribute of probe response */
+ blnMatch = 1;
+ break;
+ }
+
+ /* Get the next P2P IE */
+ p2pie = rtw_get_p2p_ie(p2pie+p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen);
+ }
+ }
+ }
+
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (!blnMatch)
+ sprintf(go_devadd_str, "\n\ndev_add = NULL");
+ else
+ sprintf(go_devadd_str, "\n\ndev_add =%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
+ attr_content[0], attr_content[1], attr_content[2], attr_content[3], attr_content[4], attr_content[5]);
+
+ if (copy_to_user(wrqu->data.pointer, go_devadd_str, 10 + 17))
+ return -EFAULT;
+ return ret;
+}
+
+static int rtw_p2p_get_device_type(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ u8 peerMAC[ETH_ALEN] = {0x00};
+ int jj, kk;
+ u8 peerMACStr[17] = {0x00};
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 blnMatch = 0;
+ u8 dev_type[8] = {0x00};
+ uint dev_type_len = 0;
+ u8 dev_type_str[17 + 9] = {0x00}; /* +9 is for the str "dev_type =", we have to clear it at wrqu->data.pointer */
+
+ /* Commented by Albert 20121209 */
+ /* The input data is the MAC address which the application wants to know its device type. */
+ /* Such user interface could know the device type. */
+ /* Format: iwpriv wlanx p2p_get2 dev_type = 00:E0:4C:00:00:05 */
+
+ DBG_88E("[%s] data = %s\n", __func__, (char *)extra);
+ if (copy_from_user(peerMACStr, wrqu->data.pointer + 9, 17))
+ return -EFAULT;
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ u8 *wpsie;
+ uint wpsie_len = 0;
+
+ /* The mac address is matched. */
+
+ wpsie = rtw_get_wps_ie(&pnetwork->network.IEs[12],
+ pnetwork->network.IELength - 12,
+ NULL, &wpsie_len);
+ if (wpsie) {
+ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_PRIMARY_DEV_TYPE, dev_type, &dev_type_len);
+ if (dev_type_len) {
+ u16 type = 0;
+ __be16 be_tmp;
+
+ memcpy(&be_tmp, dev_type, 2);
+ type = be16_to_cpu(be_tmp);
+ sprintf(dev_type_str, "\n\nN =%.2d", type);
+ blnMatch = 1;
+ }
+ }
+ break;
+ }
+
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (!blnMatch)
+ sprintf(dev_type_str, "\n\nN = 00");
+
+ if (copy_to_user(wrqu->data.pointer, dev_type_str, 9 + 17)) {
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+static int rtw_p2p_get_device_name(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ u8 peerMAC[ETH_ALEN] = {0x00};
+ int jj, kk;
+ u8 peerMACStr[17] = {0x00};
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 blnMatch = 0;
+ u8 dev_name[WPS_MAX_DEVICE_NAME_LEN] = {0x00};
+ uint dev_len = 0;
+ u8 dev_name_str[WPS_MAX_DEVICE_NAME_LEN + 5] = {0x00}; /* +5 is for the str "devN =", we have to clear it at wrqu->data.pointer */
+
+ /* Commented by Albert 20121225 */
+ /* The input data is the MAC address which the application wants to know its device name. */
+ /* Such user interface could show peer device's device name instead of ssid. */
+ /* Format: iwpriv wlanx p2p_get2 devN = 00:E0:4C:00:00:05 */
+
+ DBG_88E("[%s] data = %s\n", __func__, (char *)extra);
+ if (copy_from_user(peerMACStr, wrqu->data.pointer + 5, 17))
+ return -EFAULT;
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ u8 *wpsie;
+ uint wpsie_len = 0;
+
+ /* The mac address is matched. */
+ wpsie = rtw_get_wps_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &wpsie_len);
+ if (wpsie) {
+ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_DEVICE_NAME, dev_name, &dev_len);
+ if (dev_len) {
+ sprintf(dev_name_str, "\n\nN =%s", dev_name);
+ blnMatch = 1;
+ }
+ }
+ break;
+ }
+
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (!blnMatch)
+ sprintf(dev_name_str, "\n\nN = 0000");
+
+ if (copy_to_user(wrqu->data.pointer, dev_name_str, 5 + ((dev_len > 17) ? dev_len : 17)))
+ return -EFAULT;
+ return ret;
+}
+
+static int rtw_p2p_get_invitation_procedure(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ u8 peerMAC[ETH_ALEN] = {0x00};
+ int jj, kk;
+ u8 peerMACStr[17] = {0x00};
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 blnMatch = 0;
+ u8 *p2pie;
+ uint p2pielen = 0, attr_contentlen = 0;
+ u8 attr_content[2] = {0x00};
+
+ u8 inv_proc_str[17 + 8] = {0x00};
+ /* +8 is for the str "InvProc =", we have to clear it at wrqu->data.pointer */
+
+ /* Commented by Ouden 20121226 */
+ /* The application wants to know P2P initation procedure is support or not. */
+ /* Format: iwpriv wlanx p2p_get2 InvProc = 00:E0:4C:00:00:05 */
+
+ DBG_88E("[%s] data = %s\n", __func__, (char *)extra);
+ if (copy_from_user(peerMACStr, wrqu->data.pointer + 8, 17))
+ return -EFAULT;
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ /* Commented by Albert 20121226 */
+ /* Match the device address located in the P2P IE */
+ /* This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+ p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen);
+ if (p2pie) {
+ while (p2pie) {
+ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_CAPABILITY, attr_content, &attr_contentlen)) {
+ /* Handle the P2P capability attribute */
+ blnMatch = 1;
+ break;
+ }
+
+ /* Get the next P2P IE */
+ p2pie = rtw_get_p2p_ie(p2pie+p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen);
+ }
+ }
+ }
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (!blnMatch) {
+ sprintf(inv_proc_str, "\nIP =-1");
+ } else {
+ if (attr_content[0] & 0x20)
+ sprintf(inv_proc_str, "\nIP = 1");
+ else
+ sprintf(inv_proc_str, "\nIP = 0");
+ }
+ if (copy_to_user(wrqu->data.pointer, inv_proc_str, 8 + 17))
+ return -EFAULT;
+ return ret;
+}
+
+static int rtw_p2p_connect(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 peerMAC[ETH_ALEN] = {0x00};
+ int jj, kk;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ struct list_head *plist, *phead;
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ uint uintPeerChannel = 0;
+
+ /* Commented by Albert 20110304 */
+ /* The input data contains two informations. */
+ /* 1. First information is the MAC address which wants to formate with */
+ /* 2. Second information is the WPS PINCode or "pbc" string for push button method */
+ /* Format: 00:E0:4C:00:00:05 */
+ /* Format: 00:E0:4C:00:00:05 */
+
+ DBG_88E("[%s] data = %s\n", __func__, extra);
+
+ if (pwdinfo->p2p_state == P2P_STATE_NONE) {
+ DBG_88E("[%s] WiFi Direct is disable!\n", __func__);
+ return ret;
+ }
+
+ if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO)
+ return -1;
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ peerMAC[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (uintPeerChannel) {
+ _rtw_memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info));
+ _rtw_memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
+
+ pwdinfo->nego_req_info.peer_channel_num[0] = uintPeerChannel;
+ memcpy(pwdinfo->nego_req_info.peerDevAddr, pnetwork->network.MacAddress, ETH_ALEN);
+ pwdinfo->nego_req_info.benable = true;
+
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ if (rtw_p2p_state(pwdinfo) != P2P_STATE_GONEGO_OK) {
+ /* Restore to the listen state if the current p2p state is not nego OK */
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
+ }
+
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING);
+
+ DBG_88E("[%s] Start PreTx Procedure!\n", __func__);
+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_GO_NEGO_TIMEOUT);
+ } else {
+ DBG_88E("[%s] Not Found in Scanning Queue~\n", __func__);
+ ret = -1;
+ }
+ return ret;
+}
+
+static int rtw_p2p_invite_req(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ int jj, kk;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct list_head *plist, *phead;
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ uint uintPeerChannel = 0;
+ u8 attr_content[50] = {0x00};
+ u8 *p2pie;
+ uint p2pielen = 0, attr_contentlen = 0;
+ unsigned long irqL;
+ struct tx_invite_req_info *pinvite_req_info = &pwdinfo->invitereq_info;
+
+ /* The input data contains two informations. */
+ /* 1. First information is the P2P device address which you want to send to. */
+ /* 2. Second information is the group id which combines with GO's mac address, space and GO's ssid. */
+ /* Command line sample: iwpriv wlan0 p2p_set invite ="00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy" */
+ /* Format: 00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy */
+
+ DBG_88E("[%s] data = %s\n", __func__, extra);
+
+ if (wrqu->data.length <= 37) {
+ DBG_88E("[%s] Wrong format!\n", __func__);
+ return ret;
+ }
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ DBG_88E("[%s] WiFi Direct is disable!\n", __func__);
+ return ret;
+ } else {
+ /* Reset the content of struct tx_invite_req_info */
+ pinvite_req_info->benable = false;
+ _rtw_memset(pinvite_req_info->go_bssid, 0x00, ETH_ALEN);
+ _rtw_memset(pinvite_req_info->go_ssid, 0x00, WLAN_SSID_MAXLEN);
+ pinvite_req_info->ssidlen = 0x00;
+ pinvite_req_info->operating_ch = pwdinfo->operating_channel;
+ _rtw_memset(pinvite_req_info->peer_macaddr, 0x00, ETH_ALEN);
+ pinvite_req_info->token = 3;
+ }
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ pinvite_req_info->peer_macaddr[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ /* Commented by Albert 2011/05/18 */
+ /* Match the device address located in the P2P IE */
+ /* This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+ p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen);
+ if (p2pie) {
+ /* The P2P Device ID attribute is included in the Beacon frame. */
+ /* The P2P Device Info attribute is included in the probe response frame. */
+
+ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device ID attribute of Beacon first */
+ if (!memcmp(attr_content, pinvite_req_info->peer_macaddr, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device Info attribute of probe response */
+ if (!memcmp(attr_content, pinvite_req_info->peer_macaddr, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ }
+ }
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (uintPeerChannel) {
+ /* Store the GO's bssid */
+ for (jj = 0, kk = 18; jj < ETH_ALEN; jj++, kk += 3)
+ pinvite_req_info->go_bssid[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ /* Store the GO's ssid */
+ pinvite_req_info->ssidlen = wrqu->data.length - 36;
+ memcpy(pinvite_req_info->go_ssid, &extra[36], (u32) pinvite_req_info->ssidlen);
+ pinvite_req_info->benable = true;
+ pinvite_req_info->peer_ch = uintPeerChannel;
+
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INVITE_REQ);
+
+ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+
+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_INVITE_TIMEOUT);
+ } else {
+ DBG_88E("[%s] NOT Found in the Scanning Queue!\n", __func__);
+ }
+ return ret;
+}
+
+static int rtw_p2p_set_persistent(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ /* The input data is 0 or 1 */
+ /* 0: disable persistent group functionality */
+ /* 1: enable persistent group founctionality */
+
+ DBG_88E("[%s] data = %s\n", __func__, extra);
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ DBG_88E("[%s] WiFi Direct is disable!\n", __func__);
+ return ret;
+ } else {
+ if (extra[0] == '0') /* Disable the persistent group function. */
+ pwdinfo->persistent_supported = false;
+ else if (extra[0] == '1') /* Enable the persistent group function. */
+ pwdinfo->persistent_supported = true;
+ else
+ pwdinfo->persistent_supported = false;
+ }
+ pr_info("[%s] persistent_supported = %d\n", __func__, pwdinfo->persistent_supported);
+ return ret;
+}
+
+static int rtw_p2p_prov_disc(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 peerMAC[ETH_ALEN] = {0x00};
+ int jj, kk;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct list_head *plist, *phead;
+ struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ uint uintPeerChannel = 0;
+ u8 attr_content[100] = {0x00};
+ u8 *p2pie;
+ uint p2pielen = 0, attr_contentlen = 0;
+ unsigned long irqL;
+
+ /* The input data contains two informations. */
+ /* 1. First information is the MAC address which wants to issue the provisioning discovery request frame. */
+ /* 2. Second information is the WPS configuration method which wants to discovery */
+ /* Format: 00:E0:4C:00:00:05_display */
+ /* Format: 00:E0:4C:00:00:05_keypad */
+ /* Format: 00:E0:4C:00:00:05_pbc */
+ /* Format: 00:E0:4C:00:00:05_label */
+
+ DBG_88E("[%s] data = %s\n", __func__, extra);
+
+ if (pwdinfo->p2p_state == P2P_STATE_NONE) {
+ DBG_88E("[%s] WiFi Direct is disable!\n", __func__);
+ return ret;
+ } else {
+ /* Reset the content of struct tx_provdisc_req_info excluded the wps_config_method_request. */
+ _rtw_memset(pwdinfo->tx_prov_disc_info.peerDevAddr, 0x00, ETH_ALEN);
+ _rtw_memset(pwdinfo->tx_prov_disc_info.peerIFAddr, 0x00, ETH_ALEN);
+ _rtw_memset(&pwdinfo->tx_prov_disc_info.ssid, 0x00, sizeof(struct ndis_802_11_ssid));
+ pwdinfo->tx_prov_disc_info.peer_channel_num[0] = 0;
+ pwdinfo->tx_prov_disc_info.peer_channel_num[1] = 0;
+ pwdinfo->tx_prov_disc_info.benable = false;
+ }
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ peerMAC[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ if (!memcmp(&extra[18], "display", 7)) {
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_DISPLYA;
+ } else if (!memcmp(&extra[18], "keypad", 7)) {
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_KEYPAD;
+ } else if (!memcmp(&extra[18], "pbc", 3)) {
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_PUSH_BUTTON;
+ } else if (!memcmp(&extra[18], "label", 5)) {
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_LABEL;
+ } else {
+ DBG_88E("[%s] Unknown WPS config methodn", __func__);
+ return ret;
+ }
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) == true)
+ break;
+
+ if (uintPeerChannel != 0)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ /* Commented by Albert 2011/05/18 */
+ /* Match the device address located in the P2P IE */
+ /* This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+ p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen);
+ if (p2pie) {
+ while (p2pie) {
+ /* The P2P Device ID attribute is included in the Beacon frame. */
+ /* The P2P Device Info attribute is included in the probe response frame. */
+
+ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device ID attribute of Beacon first */
+ if (!memcmp(attr_content, peerMAC, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device Info attribute of probe response */
+ if (!memcmp(attr_content, peerMAC, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ }
+
+ /* Get the next P2P IE */
+ p2pie = rtw_get_p2p_ie(p2pie+p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen);
+ }
+ }
+
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (uintPeerChannel) {
+ DBG_88E("[%s] peer channel: %d!\n", __func__, uintPeerChannel);
+ memcpy(pwdinfo->tx_prov_disc_info.peerIFAddr, pnetwork->network.MacAddress, ETH_ALEN);
+ memcpy(pwdinfo->tx_prov_disc_info.peerDevAddr, peerMAC, ETH_ALEN);
+ pwdinfo->tx_prov_disc_info.peer_channel_num[0] = (u16) uintPeerChannel;
+ pwdinfo->tx_prov_disc_info.benable = true;
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ);
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+ memcpy(&pwdinfo->tx_prov_disc_info.ssid, &pnetwork->network.Ssid, sizeof(struct ndis_802_11_ssid));
+ } else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ memcpy(pwdinfo->tx_prov_disc_info.ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN);
+ pwdinfo->tx_prov_disc_info.ssid.SsidLength = P2P_WILDCARD_SSID_LEN;
+ }
+
+ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+
+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT);
+ } else {
+ DBG_88E("[%s] NOT Found in the Scanning Queue!\n", __func__);
+ }
+ return ret;
+}
+
+/* This function is used to inform the driver the user had specified the pin code value or pbc */
+/* to application. */
+
+static int rtw_p2p_got_wpsinfo(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ DBG_88E("[%s] data = %s\n", __func__, extra);
+ /* Added by Albert 20110328 */
+ /* if the input data is P2P_NO_WPSINFO -> reset the wpsinfo */
+ /* if the input data is P2P_GOT_WPSINFO_PEER_DISPLAY_PIN -> the utility just input the PIN code got from the peer P2P device. */
+ /* if the input data is P2P_GOT_WPSINFO_SELF_DISPLAY_PIN -> the utility just got the PIN code from itself. */
+ /* if the input data is P2P_GOT_WPSINFO_PBC -> the utility just determine to use the PBC */
+
+ if (*extra == '0')
+ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO;
+ else if (*extra == '1')
+ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_PEER_DISPLAY_PIN;
+ else if (*extra == '2')
+ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_SELF_DISPLAY_PIN;
+ else if (*extra == '3')
+ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_PBC;
+ else
+ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO;
+ return ret;
+}
+
+#endif /* CONFIG_88EU_P2P */
+
+static int rtw_p2p_set(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_88EU_P2P
+ DBG_88E("[%s] extra = %s\n", __func__, extra);
+ if (!memcmp(extra, "enable =", 7)) {
+ rtw_wext_p2p_enable(dev, info, wrqu, &extra[7]);
+ } else if (!memcmp(extra, "setDN =", 6)) {
+ wrqu->data.length -= 6;
+ rtw_p2p_setDN(dev, info, wrqu, &extra[6]);
+ } else if (!memcmp(extra, "profilefound =", 13)) {
+ wrqu->data.length -= 13;
+ rtw_p2p_profilefound(dev, info, wrqu, &extra[13]);
+ } else if (!memcmp(extra, "prov_disc =", 10)) {
+ wrqu->data.length -= 10;
+ rtw_p2p_prov_disc(dev, info, wrqu, &extra[10]);
+ } else if (!memcmp(extra, "nego =", 5)) {
+ wrqu->data.length -= 5;
+ rtw_p2p_connect(dev, info, wrqu, &extra[5]);
+ } else if (!memcmp(extra, "intent =", 7)) {
+ /* Commented by Albert 2011/03/23 */
+ /* The wrqu->data.length will include the null character */
+ /* So, we will decrease 7 + 1 */
+ wrqu->data.length -= 8;
+ rtw_p2p_set_intent(dev, info, wrqu, &extra[7]);
+ } else if (!memcmp(extra, "ssid =", 5)) {
+ wrqu->data.length -= 5;
+ rtw_p2p_set_go_nego_ssid(dev, info, wrqu, &extra[5]);
+ } else if (!memcmp(extra, "got_wpsinfo =", 12)) {
+ wrqu->data.length -= 12;
+ rtw_p2p_got_wpsinfo(dev, info, wrqu, &extra[12]);
+ } else if (!memcmp(extra, "listen_ch =", 10)) {
+ /* Commented by Albert 2011/05/24 */
+ /* The wrqu->data.length will include the null character */
+ /* So, we will decrease (10 + 1) */
+ wrqu->data.length -= 11;
+ rtw_p2p_set_listen_ch(dev, info, wrqu, &extra[10]);
+ } else if (!memcmp(extra, "op_ch =", 6)) {
+ /* Commented by Albert 2011/05/24 */
+ /* The wrqu->data.length will include the null character */
+ /* So, we will decrease (6 + 1) */
+ wrqu->data.length -= 7;
+ rtw_p2p_set_op_ch(dev, info, wrqu, &extra[6]);
+ } else if (!memcmp(extra, "invite =", 7)) {
+ wrqu->data.length -= 8;
+ rtw_p2p_invite_req(dev, info, wrqu, &extra[7]);
+ } else if (!memcmp(extra, "persistent =", 11)) {
+ wrqu->data.length -= 11;
+ rtw_p2p_set_persistent(dev, info, wrqu, &extra[11]);
+ }
+#endif /* CONFIG_88EU_P2P */
+
+ return ret;
+}
+
+static int rtw_p2p_get(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_88EU_P2P
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ if (padapter->bShowGetP2PState)
+ DBG_88E("[%s] extra = %s\n", __func__, (char *)wrqu->data.pointer);
+ if (!memcmp(wrqu->data.pointer, "status", 6)) {
+ rtw_p2p_get_status(dev, info, wrqu, extra);
+ } else if (!memcmp(wrqu->data.pointer, "role", 4)) {
+ rtw_p2p_get_role(dev, info, wrqu, extra);
+ } else if (!memcmp(wrqu->data.pointer, "peer_ifa", 8)) {
+ rtw_p2p_get_peer_ifaddr(dev, info, wrqu, extra);
+ } else if (!memcmp(wrqu->data.pointer, "req_cm", 6)) {
+ rtw_p2p_get_req_cm(dev, info, wrqu, extra);
+ } else if (!memcmp(wrqu->data.pointer, "peer_deva", 9)) {
+ /* Get the P2P device address when receiving the provision discovery request frame. */
+ rtw_p2p_get_peer_devaddr(dev, info, wrqu, extra);
+ } else if (!memcmp(wrqu->data.pointer, "group_id", 8)) {
+ rtw_p2p_get_groupid(dev, info, wrqu, extra);
+ } else if (!memcmp(wrqu->data.pointer, "peer_deva_inv", 9)) {
+ /* Get the P2P device address when receiving the P2P Invitation request frame. */
+ rtw_p2p_get_peer_devaddr_by_invitation(dev, info, wrqu, extra);
+ } else if (!memcmp(wrqu->data.pointer, "op_ch", 5)) {
+ rtw_p2p_get_op_ch(dev, info, wrqu, extra);
+ }
+#endif /* CONFIG_88EU_P2P */
+ return ret;
+}
+
+static int rtw_p2p_get2(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_88EU_P2P
+ DBG_88E("[%s] extra = %s\n", __func__, (char *)wrqu->data.pointer);
+ if (!memcmp(extra, "wpsCM =", 6)) {
+ wrqu->data.length -= 6;
+ rtw_p2p_get_wps_configmethod(dev, info, wrqu, &extra[6]);
+ } else if (!memcmp(extra, "devN =", 5)) {
+ wrqu->data.length -= 5;
+ rtw_p2p_get_device_name(dev, info, wrqu, &extra[5]);
+ } else if (!memcmp(extra, "dev_type =", 9)) {
+ wrqu->data.length -= 9;
+ rtw_p2p_get_device_type(dev, info, wrqu, &extra[9]);
+ } else if (!memcmp(extra, "go_devadd =", 10)) {
+ wrqu->data.length -= 10;
+ rtw_p2p_get_go_device_address(dev, info, wrqu, &extra[10]);
+ } else if (!memcmp(extra, "InvProc =", 8)) {
+ wrqu->data.length -= 8;
+ rtw_p2p_get_invitation_procedure(dev, info, wrqu, &extra[8]);
+ }
+
+#endif /* CONFIG_88EU_P2P */
+
+ return ret;
+}
+
+static int rtw_cta_test_start(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ DBG_88E("%s %s\n", __func__, extra);
+ if (!strcmp(extra, "1"))
+ padapter->in_cta_test = 1;
+ else
+ padapter->in_cta_test = 0;
+
+ if (padapter->in_cta_test) {
+ u32 v = rtw_read32(padapter, REG_RCR);
+ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/* RCR_ADF */
+ rtw_write32(padapter, REG_RCR, v);
+ DBG_88E("enable RCR_ADF\n");
+ } else {
+ u32 v = rtw_read32(padapter, REG_RCR);
+ v |= RCR_CBSSID_DATA | RCR_CBSSID_BCN;/* RCR_ADF */
+ rtw_write32(padapter, REG_RCR, v);
+ DBG_88E("disable RCR_ADF\n");
+ }
+ return ret;
+}
+
+static int rtw_rereg_nd_name(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ struct rereg_nd_name_data *rereg_priv = &padapter->rereg_nd_name_priv;
+ char new_ifname[IFNAMSIZ];
+
+ if (rereg_priv->old_ifname[0] == 0) {
+ char *reg_ifname;
+ reg_ifname = padapter->registrypriv.if2name;
+
+ strncpy(rereg_priv->old_ifname, reg_ifname, IFNAMSIZ);
+ rereg_priv->old_ifname[IFNAMSIZ-1] = 0;
+ }
+
+ if (wrqu->data.length > IFNAMSIZ)
+ return -EFAULT;
+
+ if (copy_from_user(new_ifname, wrqu->data.pointer, IFNAMSIZ))
+ return -EFAULT;
+
+ if (0 == strcmp(rereg_priv->old_ifname, new_ifname))
+ return ret;
+
+ DBG_88E("%s new_ifname:%s\n", __func__, new_ifname);
+ ret = rtw_change_ifname(padapter, new_ifname);
+ if (0 != ret)
+ goto exit;
+
+ if (!memcmp(rereg_priv->old_ifname, "disable%d", 9) == true) {
+ padapter->ledpriv.bRegUseLed = rereg_priv->old_bRegUseLed;
+ rtw_hal_sw_led_init(padapter);
+ rtw_ips_mode_req(&padapter->pwrctrlpriv, rereg_priv->old_ips_mode);
+ }
+
+ strncpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ);
+ rereg_priv->old_ifname[IFNAMSIZ-1] = 0;
+
+ if (!memcmp(new_ifname, "disable%d", 9) == true) {
+ DBG_88E("%s disable\n", __func__);
+ /* free network queue for Android's timming issue */
+ rtw_free_network_queue(padapter, true);
+
+ /* close led */
+ rtw_led_control(padapter, LED_CTL_POWER_OFF);
+ rereg_priv->old_bRegUseLed = padapter->ledpriv.bRegUseLed;
+ padapter->ledpriv.bRegUseLed = false;
+ rtw_hal_sw_led_deinit(padapter);
+
+ /* the interface is being "disabled", we can do deeper IPS */
+ rereg_priv->old_ips_mode = rtw_get_ips_mode_req(&padapter->pwrctrlpriv);
+ rtw_ips_mode_req(&padapter->pwrctrlpriv, IPS_NORMAL);
+ }
+exit:
+ return ret;
+}
+
+static void mac_reg_dump(struct adapter *padapter)
+{
+ int i, j = 1;
+ pr_info("\n ======= MAC REG =======\n");
+ for (i = 0x0; i < 0x300; i += 4) {
+ if (j%4 == 1)
+ pr_info("0x%02x", i);
+ pr_info(" 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ pr_info("\n");
+ }
+ for (i = 0x400; i < 0x800; i += 4) {
+ if (j%4 == 1)
+ pr_info("0x%02x", i);
+ pr_info(" 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ pr_info("\n");
+ }
+}
+
+static void bb_reg_dump(struct adapter *padapter)
+{
+ int i, j = 1;
+ pr_info("\n ======= BB REG =======\n");
+ for (i = 0x800; i < 0x1000; i += 4) {
+ if (j%4 == 1)
+ pr_info("0x%02x", i);
+
+ pr_info(" 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ pr_info("\n");
+ }
+}
+
+static void rf_reg_dump(struct adapter *padapter)
+{
+ int i, j = 1, path;
+ u32 value;
+ u8 rf_type, path_nums = 0;
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+ pr_info("\n ======= RF REG =======\n");
+ if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type))
+ path_nums = 1;
+ else
+ path_nums = 2;
+
+ for (path = 0; path < path_nums; path++) {
+ pr_info("\nRF_Path(%x)\n", path);
+ for (i = 0; i < 0x100; i++) {
+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+ if (j%4 == 1)
+ pr_info("0x%02x ", i);
+ pr_info(" 0x%08x ", value);
+ if ((j++)%4 == 0)
+ pr_info("\n");
+ }
+ }
+}
+
+static int rtw_dbg_port(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ unsigned long irqL;
+ int ret = 0;
+ u8 major_cmd, minor_cmd;
+ u16 arg;
+ s32 extra_arg;
+ u32 *pdata, val32;
+ struct sta_info *psta;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ pdata = (u32 *)&wrqu->data;
+
+ val32 = *pdata;
+ arg = (u16)(val32 & 0x0000ffff);
+ major_cmd = (u8)(val32 >> 24);
+ minor_cmd = (u8)((val32 >> 16) & 0x00ff);
+
+ extra_arg = *(pdata+1);
+
+ switch (major_cmd) {
+ case 0x70:/* read_reg */
+ switch (minor_cmd) {
+ case 1:
+ DBG_88E("rtw_read8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg));
+ break;
+ case 2:
+ DBG_88E("rtw_read16(0x%x) = 0x%04x\n", arg, rtw_read16(padapter, arg));
+ break;
+ case 4:
+ DBG_88E("rtw_read32(0x%x) = 0x%08x\n", arg, rtw_read32(padapter, arg));
+ break;
+ }
+ break;
+ case 0x71:/* write_reg */
+ switch (minor_cmd) {
+ case 1:
+ rtw_write8(padapter, arg, extra_arg);
+ DBG_88E("rtw_write8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg));
+ break;
+ case 2:
+ rtw_write16(padapter, arg, extra_arg);
+ DBG_88E("rtw_write16(0x%x) = 0x%04x\n", arg, rtw_read16(padapter, arg));
+ break;
+ case 4:
+ rtw_write32(padapter, arg, extra_arg);
+ DBG_88E("rtw_write32(0x%x) = 0x%08x\n", arg, rtw_read32(padapter, arg));
+ break;
+ }
+ break;
+ case 0x72:/* read_bb */
+ DBG_88E("read_bbreg(0x%x) = 0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff));
+ break;
+ case 0x73:/* write_bb */
+ rtw_hal_write_bbreg(padapter, arg, 0xffffffff, extra_arg);
+ DBG_88E("write_bbreg(0x%x) = 0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff));
+ break;
+ case 0x74:/* read_rf */
+ DBG_88E("read RF_reg path(0x%02x), offset(0x%x), value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff));
+ break;
+ case 0x75:/* write_rf */
+ rtw_hal_write_rfreg(padapter, minor_cmd, arg, 0xffffffff, extra_arg);
+ DBG_88E("write RF_reg path(0x%02x), offset(0x%x), value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff));
+ break;
+
+ case 0x76:
+ switch (minor_cmd) {
+ case 0x00: /* normal mode, */
+ padapter->recvpriv.is_signal_dbg = 0;
+ break;
+ case 0x01: /* dbg mode */
+ padapter->recvpriv.is_signal_dbg = 1;
+ extra_arg = extra_arg > 100 ? 100 : extra_arg;
+ extra_arg = extra_arg < 0 ? 0 : extra_arg;
+ padapter->recvpriv.signal_strength_dbg = extra_arg;
+ break;
+ }
+ break;
+ case 0x78: /* IOL test */
+ switch (minor_cmd) {
+ case 0x04: /* LLT table initialization test */
+ {
+ u8 page_boundary = 0xf9;
+ struct xmit_frame *xmit_frame;
+
+ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+ if (xmit_frame == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ rtw_IOL_append_LLT_cmd(xmit_frame, page_boundary);
+
+ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 500, 0))
+ ret = -EPERM;
+ }
+ break;
+ case 0x05: /* blink LED test */
+ {
+ u16 reg = 0x4c;
+ u32 blink_num = 50;
+ u32 blink_delay_ms = 200;
+ int i;
+ struct xmit_frame *xmit_frame;
+
+ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+ if (xmit_frame == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ for (i = 0; i < blink_num; i++) {
+ rtw_IOL_append_WB_cmd(xmit_frame, reg, 0x00, 0xff);
+ rtw_IOL_append_DELAY_MS_cmd(xmit_frame, blink_delay_ms);
+ rtw_IOL_append_WB_cmd(xmit_frame, reg, 0x08, 0xff);
+ rtw_IOL_append_DELAY_MS_cmd(xmit_frame, blink_delay_ms);
+ }
+ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, (blink_delay_ms*blink_num*2)+200, 0))
+ ret = -EPERM;
+ }
+ break;
+
+ case 0x06: /* continuous write byte test */
+ {
+ u16 reg = arg;
+ u16 start_value = 0;
+ u32 write_num = extra_arg;
+ int i;
+ u8 final;
+ struct xmit_frame *xmit_frame;
+
+ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+ if (xmit_frame == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ for (i = 0; i < write_num; i++)
+ rtw_IOL_append_WB_cmd(xmit_frame, reg, i+start_value, 0xFF);
+ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0))
+ ret = -EPERM;
+
+ final = rtw_read8(padapter, reg);
+ if (start_value+write_num-1 == final)
+ DBG_88E("continuous IOL_CMD_WB_REG to 0x%x %u times Success, start:%u, final:%u\n", reg, write_num, start_value, final);
+ else
+ DBG_88E("continuous IOL_CMD_WB_REG to 0x%x %u times Fail, start:%u, final:%u\n", reg, write_num, start_value, final);
+ }
+ break;
+
+ case 0x07: /* continuous write word test */
+ {
+ u16 reg = arg;
+ u16 start_value = 200;
+ u32 write_num = extra_arg;
+
+ int i;
+ u16 final;
+ struct xmit_frame *xmit_frame;
+
+ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+ if (xmit_frame == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ for (i = 0; i < write_num; i++)
+ rtw_IOL_append_WW_cmd(xmit_frame, reg, i+start_value, 0xFFFF);
+ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0))
+ ret = -EPERM;
+
+ final = rtw_read16(padapter, reg);
+ if (start_value+write_num-1 == final)
+ DBG_88E("continuous IOL_CMD_WW_REG to 0x%x %u times Success, start:%u, final:%u\n", reg, write_num, start_value, final);
+ else
+ DBG_88E("continuous IOL_CMD_WW_REG to 0x%x %u times Fail, start:%u, final:%u\n", reg, write_num, start_value, final);
+ }
+ break;
+ case 0x08: /* continuous write dword test */
+ {
+ u16 reg = arg;
+ u32 start_value = 0x110000c7;
+ u32 write_num = extra_arg;
+
+ int i;
+ u32 final;
+ struct xmit_frame *xmit_frame;
+
+ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+ if (xmit_frame == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ for (i = 0; i < write_num; i++)
+ rtw_IOL_append_WD_cmd(xmit_frame, reg, i+start_value, 0xFFFFFFFF);
+ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0))
+ ret = -EPERM;
+
+ final = rtw_read32(padapter, reg);
+ if (start_value+write_num-1 == final)
+ DBG_88E("continuous IOL_CMD_WD_REG to 0x%x %u times Success, start:%u, final:%u\n",
+ reg, write_num, start_value, final);
+ else
+ DBG_88E("continuous IOL_CMD_WD_REG to 0x%x %u times Fail, start:%u, final:%u\n",
+ reg, write_num, start_value, final);
+ }
+ break;
+ }
+ break;
+ case 0x79:
+ {
+ /*
+ * dbg 0x79000000 [value], set RESP_TXAGC to + value, value:0~15
+ * dbg 0x79010000 [value], set RESP_TXAGC to - value, value:0~15
+ */
+ u8 value = extra_arg & 0x0f;
+ u8 sign = minor_cmd;
+ u16 write_value = 0;
+
+ DBG_88E("%s set RESP_TXAGC to %s %u\n", __func__, sign ? "minus" : "plus", value);
+
+ if (sign)
+ value = value | 0x10;
+
+ write_value = value | (value << 5);
+ rtw_write16(padapter, 0x6d9, write_value);
+ }
+ break;
+ case 0x7a:
+ receive_disconnect(padapter, pmlmeinfo->network.MacAddress
+ , WLAN_REASON_EXPIRATION_CHK);
+ break;
+ case 0x7F:
+ switch (minor_cmd) {
+ case 0x0:
+ DBG_88E("fwstate = 0x%x\n", get_fwstate(pmlmepriv));
+ break;
+ case 0x01:
+ DBG_88E("auth_alg = 0x%x, enc_alg = 0x%x, auth_type = 0x%x, enc_type = 0x%x\n",
+ psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm,
+ psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus);
+ break;
+ case 0x02:
+ DBG_88E("pmlmeinfo->state = 0x%x\n", pmlmeinfo->state);
+ break;
+ case 0x03:
+ DBG_88E("qos_option =%d\n", pmlmepriv->qospriv.qos_option);
+ DBG_88E("ht_option =%d\n", pmlmepriv->htpriv.ht_option);
+ break;
+ case 0x04:
+ DBG_88E("cur_ch =%d\n", pmlmeext->cur_channel);
+ DBG_88E("cur_bw =%d\n", pmlmeext->cur_bwmode);
+ DBG_88E("cur_ch_off =%d\n", pmlmeext->cur_ch_offset);
+ break;
+ case 0x05:
+ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
+ if (psta) {
+ int i;
+ struct recv_reorder_ctrl *preorder_ctrl;
+
+ DBG_88E("SSID =%s\n", cur_network->network.Ssid.Ssid);
+ DBG_88E("sta's macaddr: %pM\n", psta->hwaddr);
+ DBG_88E("cur_channel =%d, cur_bwmode =%d, cur_ch_offset =%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
+ DBG_88E("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self);
+ DBG_88E("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+ DBG_88E("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+ DBG_88E("bwmode =%d, ch_offset =%d, sgi =%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi);
+ DBG_88E("ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+ DBG_88E("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+ for (i = 0; i < 16; i++) {
+ preorder_ctrl = &psta->recvreorder_ctrl[i];
+ if (preorder_ctrl->enable)
+ DBG_88E("tid =%d, indicate_seq =%d\n", i, preorder_ctrl->indicate_seq);
+ }
+ } else {
+ DBG_88E("can't get sta's macaddr, cur_network's macaddr:%pM\n", (cur_network->network.MacAddress));
+ }
+ break;
+ case 0x06:
+ {
+ u32 ODMFlag;
+ rtw_hal_get_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag));
+ DBG_88E("(B)DMFlag = 0x%x, arg = 0x%x\n", ODMFlag, arg);
+ ODMFlag = (u32)(0x0f&arg);
+ DBG_88E("(A)DMFlag = 0x%x\n", ODMFlag);
+ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag));
+ }
+ break;
+ case 0x07:
+ DBG_88E("bSurpriseRemoved =%d, bDriverStopped =%d\n",
+ padapter->bSurpriseRemoved, padapter->bDriverStopped);
+ break;
+ case 0x08:
+ {
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+ DBG_88E("free_xmitbuf_cnt =%d, free_xmitframe_cnt =%d, free_xmit_extbuf_cnt =%d\n",
+ pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmit_extbuf_cnt);
+ DBG_88E("rx_urb_pending_cn =%d\n", precvpriv->rx_pending_cnt);
+ }
+ break;
+ case 0x09:
+ {
+ int i, j;
+ struct list_head *plist, *phead;
+ struct recv_reorder_ctrl *preorder_ctrl;
+
+#ifdef CONFIG_88EU_AP_MODE
+ DBG_88E("sta_dz_bitmap = 0x%x, tim_bitmap = 0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap);
+#endif
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+ for (i = 0; i < NUM_STA; i++) {
+ phead = &(pstapriv->sta_hash[i]);
+ plist = get_next(phead);
+
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+ plist = get_next(plist);
+
+ if (extra_arg == psta->aid) {
+ DBG_88E("sta's macaddr:%pM\n", (psta->hwaddr));
+ DBG_88E("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self);
+ DBG_88E("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+ DBG_88E("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+ DBG_88E("bwmode =%d, ch_offset =%d, sgi =%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi);
+ DBG_88E("ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+ DBG_88E("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+
+#ifdef CONFIG_88EU_AP_MODE
+ DBG_88E("capability = 0x%x\n", psta->capability);
+ DBG_88E("flags = 0x%x\n", psta->flags);
+ DBG_88E("wpa_psk = 0x%x\n", psta->wpa_psk);
+ DBG_88E("wpa2_group_cipher = 0x%x\n", psta->wpa2_group_cipher);
+ DBG_88E("wpa2_pairwise_cipher = 0x%x\n", psta->wpa2_pairwise_cipher);
+ DBG_88E("qos_info = 0x%x\n", psta->qos_info);
+#endif
+ DBG_88E("dot118021XPrivacy = 0x%x\n", psta->dot118021XPrivacy);
+
+ for (j = 0; j < 16; j++) {
+ preorder_ctrl = &psta->recvreorder_ctrl[j];
+ if (preorder_ctrl->enable)
+ DBG_88E("tid =%d, indicate_seq =%d\n", j, preorder_ctrl->indicate_seq);
+ }
+ }
+ }
+ }
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+ }
+ break;
+ case 0x0c:/* dump rx/tx packet */
+ if (arg == 0) {
+ DBG_88E("dump rx packet (%d)\n", extra_arg);
+ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_RXPKT, &(extra_arg));
+ } else if (arg == 1) {
+ DBG_88E("dump tx packet (%d)\n", extra_arg);
+ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(extra_arg));
+ }
+ break;
+ case 0x0f:
+ if (extra_arg == 0) {
+ DBG_88E("###### silent reset test.......#####\n");
+ rtw_hal_sreset_reset(padapter);
+ }
+ break;
+ case 0x15:
+ {
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ DBG_88E("==>silent resete cnts:%d\n", pwrpriv->ips_enter_cnts);
+ }
+ break;
+ case 0x10:/* driver version display */
+ DBG_88E("rtw driver version =%s\n", DRIVERVERSION);
+ break;
+ case 0x11:
+ DBG_88E("turn %s Rx RSSI display function\n", (extra_arg == 1) ? "on" : "off");
+ padapter->bRxRSSIDisplay = extra_arg;
+ rtw_hal_set_def_var(padapter, HW_DEF_FA_CNT_DUMP, &extra_arg);
+ break;
+ case 0x12: /* set rx_stbc */
+ {
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ /* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, 0x3: enable both 2.4g and 5g */
+ /* default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */
+ if (pregpriv &&
+ (extra_arg == 0 ||
+ extra_arg == 1 ||
+ extra_arg == 2 ||
+ extra_arg == 3)) {
+ pregpriv->rx_stbc = extra_arg;
+ DBG_88E("set rx_stbc =%d\n", pregpriv->rx_stbc);
+ } else {
+ DBG_88E("get rx_stbc =%d\n", pregpriv->rx_stbc);
+ }
+ }
+ break;
+ case 0x13: /* set ampdu_enable */
+ {
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ /* 0: disable, 0x1:enable (but wifi_spec should be 0), 0x2: force enable (don't care wifi_spec) */
+ if (pregpriv && extra_arg >= 0 && extra_arg < 3) {
+ pregpriv->ampdu_enable = extra_arg;
+ DBG_88E("set ampdu_enable =%d\n", pregpriv->ampdu_enable);
+ } else {
+ DBG_88E("get ampdu_enable =%d\n", pregpriv->ampdu_enable);
+ }
+ }
+ break;
+ case 0x14: /* get wifi_spec */
+ {
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ DBG_88E("get wifi_spec =%d\n", pregpriv->wifi_spec);
+ }
+ break;
+ case 0x16:
+ if (arg == 0xff) {
+ pr_info("ODM_COMP_DIG\t\tBIT0\n");
+ pr_info("ODM_COMP_RA_MASK\t\tBIT1\n");
+ pr_info("ODM_COMP_DYNAMIC_TXPWR\tBIT2\n");
+ pr_info("ODM_COMP_FA_CNT\t\tBIT3\n");
+ pr_info("ODM_COMP_RSSI_MONITOR\tBIT4\n");
+ pr_info("ODM_COMP_CCK_PD\t\tBIT5\n");
+ pr_info("ODM_COMP_ANT_DIV\t\tBIT6\n");
+ pr_info("ODM_COMP_PWR_SAVE\t\tBIT7\n");
+ pr_info("ODM_COMP_PWR_TRAIN\tBIT8\n");
+ pr_info("ODM_COMP_RATE_ADAPTIVE\tBIT9\n");
+ pr_info("ODM_COMP_PATH_DIV\t\tBIT10\n");
+ pr_info("ODM_COMP_PSD \tBIT11\n");
+ pr_info("ODM_COMP_DYNAMIC_PRICCA\tBIT12\n");
+ pr_info("ODM_COMP_RXHP\t\tBIT13\n");
+ pr_info("ODM_COMP_EDCA_TURBO\tBIT16\n");
+ pr_info("ODM_COMP_EARLY_MODE\tBIT17\n");
+ pr_info("ODM_COMP_TX_PWR_TRACK\tBIT24\n");
+ pr_info("ODM_COMP_RX_GAIN_TRACK\tBIT25\n");
+ pr_info("ODM_COMP_CALIBRATION\tBIT26\n");
+ rtw_hal_get_def_var(padapter, HW_DEF_ODM_DBG_FLAG, &extra_arg);
+ } else {
+ rtw_hal_set_def_var(padapter, HW_DEF_ODM_DBG_FLAG, &extra_arg);
+ }
+ break;
+ case 0x23:
+ DBG_88E("turn %s the bNotifyChannelChange Variable\n", (extra_arg == 1) ? "on" : "off");
+ padapter->bNotifyChannelChange = extra_arg;
+ break;
+ case 0x24:
+#ifdef CONFIG_88EU_P2P
+ DBG_88E("turn %s the bShowGetP2PState Variable\n", (extra_arg == 1) ? "on" : "off");
+ padapter->bShowGetP2PState = extra_arg;
+#endif /* CONFIG_88EU_P2P */
+ break;
+ case 0xaa:
+ if (extra_arg > 0x13)
+ extra_arg = 0xFF;
+ DBG_88E("chang data rate to :0x%02x\n", extra_arg);
+ padapter->fix_rate = extra_arg;
+ break;
+ case 0xdd:/* registers dump, 0 for mac reg, 1 for bb reg, 2 for rf reg */
+ if (extra_arg == 0)
+ mac_reg_dump(padapter);
+ else if (extra_arg == 1)
+ bb_reg_dump(padapter);
+ else if (extra_arg == 2)
+ rf_reg_dump(padapter);
+ break;
+ case 0xee:/* turn on/off dynamic funcs */
+ {
+ u32 odm_flag;
+
+ if (0xf == extra_arg) {
+ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &odm_flag);
+ DBG_88E(" === DMFlag(0x%08x) ===\n", odm_flag);
+ DBG_88E("extra_arg = 0 - disable all dynamic func\n");
+ DBG_88E("extra_arg = 1 - disable DIG- BIT(0)\n");
+ DBG_88E("extra_arg = 2 - disable High power - BIT(1)\n");
+ DBG_88E("extra_arg = 3 - disable tx power tracking - BIT(2)\n");
+ DBG_88E("extra_arg = 4 - disable BT coexistence - BIT(3)\n");
+ DBG_88E("extra_arg = 5 - disable antenna diversity - BIT(4)\n");
+ DBG_88E("extra_arg = 6 - enable all dynamic func\n");
+ } else {
+ /* extra_arg = 0 - disable all dynamic func
+ extra_arg = 1 - disable DIG
+ extra_arg = 2 - disable tx power tracking
+ extra_arg = 3 - turn on all dynamic func
+ */
+ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &(extra_arg));
+ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &odm_flag);
+ DBG_88E(" === DMFlag(0x%08x) ===\n", odm_flag);
+ }
+ }
+ break;
+
+ case 0xfd:
+ rtw_write8(padapter, 0xc50, arg);
+ DBG_88E("wr(0xc50) = 0x%x\n", rtw_read8(padapter, 0xc50));
+ rtw_write8(padapter, 0xc58, arg);
+ DBG_88E("wr(0xc58) = 0x%x\n", rtw_read8(padapter, 0xc58));
+ break;
+ case 0xfe:
+ DBG_88E("rd(0xc50) = 0x%x\n", rtw_read8(padapter, 0xc50));
+ DBG_88E("rd(0xc58) = 0x%x\n", rtw_read8(padapter, 0xc58));
+ break;
+ case 0xff:
+ DBG_88E("dbg(0x210) = 0x%x\n", rtw_read32(padapter, 0x210));
+ DBG_88E("dbg(0x608) = 0x%x\n", rtw_read32(padapter, 0x608));
+ DBG_88E("dbg(0x280) = 0x%x\n", rtw_read32(padapter, 0x280));
+ DBG_88E("dbg(0x284) = 0x%x\n", rtw_read32(padapter, 0x284));
+ DBG_88E("dbg(0x288) = 0x%x\n", rtw_read32(padapter, 0x288));
+
+ DBG_88E("dbg(0x664) = 0x%x\n", rtw_read32(padapter, 0x664));
+
+ DBG_88E("\n");
+
+ DBG_88E("dbg(0x430) = 0x%x\n", rtw_read32(padapter, 0x430));
+ DBG_88E("dbg(0x438) = 0x%x\n", rtw_read32(padapter, 0x438));
+
+ DBG_88E("dbg(0x440) = 0x%x\n", rtw_read32(padapter, 0x440));
+
+ DBG_88E("dbg(0x458) = 0x%x\n", rtw_read32(padapter, 0x458));
+
+ DBG_88E("dbg(0x484) = 0x%x\n", rtw_read32(padapter, 0x484));
+ DBG_88E("dbg(0x488) = 0x%x\n", rtw_read32(padapter, 0x488));
+
+ DBG_88E("dbg(0x444) = 0x%x\n", rtw_read32(padapter, 0x444));
+ DBG_88E("dbg(0x448) = 0x%x\n", rtw_read32(padapter, 0x448));
+ DBG_88E("dbg(0x44c) = 0x%x\n", rtw_read32(padapter, 0x44c));
+ DBG_88E("dbg(0x450) = 0x%x\n", rtw_read32(padapter, 0x450));
+ break;
+ }
+ break;
+ default:
+ DBG_88E("error dbg cmd!\n");
+ break;
+ }
+ return ret;
+}
+
+static int wpa_set_param(struct net_device *dev, u8 name, u32 value)
+{
+ uint ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ switch (name) {
+ case IEEE_PARAM_WPA_ENABLED:
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; /* 802.1x */
+ switch ((value)&0xff) {
+ case 1: /* WPA */
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; /* WPA_PSK */
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+ break;
+ case 2: /* WPA2 */
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+ break;
+ }
+ RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+ ("wpa_set_param:padapter->securitypriv.ndisauthtype =%d\n", padapter->securitypriv.ndisauthtype));
+ break;
+ case IEEE_PARAM_TKIP_COUNTERMEASURES:
+ break;
+ case IEEE_PARAM_DROP_UNENCRYPTED: {
+ /* HACK:
+ *
+ * wpa_supplicant calls set_wpa_enabled when the driver
+ * is loaded and unloaded, regardless of if WPA is being
+ * used. No other calls are made which can be used to
+ * determine if encryption will be used or not prior to
+ * association being expected. If encryption is not being
+ * used, drop_unencrypted is set to false, else true -- we
+ * can use this to determine if the CAP_PRIVACY_ON bit should
+ * be set.
+ */
+
+ break;
+ }
+ case IEEE_PARAM_PRIVACY_INVOKED:
+ break;
+
+ case IEEE_PARAM_AUTH_ALGS:
+ ret = wpa_set_auth_algs(dev, value);
+ break;
+ case IEEE_PARAM_IEEE_802_1X:
+ break;
+ case IEEE_PARAM_WPAX_SELECT:
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+static int wpa_mlme(struct net_device *dev, u32 command, u32 reason)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ switch (command) {
+ case IEEE_MLME_STA_DEAUTH:
+ if (!rtw_set_802_11_disassociate(padapter))
+ ret = -1;
+ break;
+ case IEEE_MLME_STA_DISASSOC:
+ if (!rtw_set_802_11_disassociate(padapter))
+ ret = -1;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p)
+{
+ struct ieee_param *param;
+ uint ret = 0;
+
+ if (p->length < sizeof(struct ieee_param) || !p->pointer) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ param = (struct ieee_param *)rtw_malloc(p->length);
+ if (param == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(param, p->pointer, p->length)) {
+ kfree(param);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ switch (param->cmd) {
+ case IEEE_CMD_SET_WPA_PARAM:
+ ret = wpa_set_param(dev, param->u.wpa_param.name, param->u.wpa_param.value);
+ break;
+
+ case IEEE_CMD_SET_WPA_IE:
+ ret = rtw_set_wpa_ie((struct adapter *)rtw_netdev_priv(dev),
+ (char *)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len);
+ break;
+
+ case IEEE_CMD_SET_ENCRYPTION:
+ ret = wpa_set_encryption(dev, param, p->length);
+ break;
+
+ case IEEE_CMD_MLME:
+ ret = wpa_mlme(dev, param->u.mlme.command, param->u.mlme.reason_code);
+ break;
+
+ default:
+ DBG_88E("Unknown WPA supplicant request: %d\n", param->cmd);
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+ ret = -EFAULT;
+
+ kfree(param);
+
+out:
+
+ return ret;
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+static u8 set_pairwise_key(struct adapter *padapter, struct sta_info *psta)
+{
+ struct cmd_obj *ph2c;
+ struct set_stakey_parm *psetstakey_para;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (ph2c == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm));
+ if (psetstakey_para == NULL) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+
+ psetstakey_para->algorithm = (u8)psta->dot118021XPrivacy;
+
+ memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN);
+
+ memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16);
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+ return res;
+}
+
+static int set_group_key(struct adapter *padapter, u8 *key, u8 alg, int keyid)
+{
+ u8 keylen;
+ struct cmd_obj *pcmd;
+ struct setkey_parm *psetkeyparm;
+ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
+ int res = _SUCCESS;
+
+ DBG_88E("%s\n", __func__);
+
+ pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+ if (pcmd == NULL) {
+ res = _FAIL;
+ goto exit;
+ }
+ psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm));
+ if (psetkeyparm == NULL) {
+ kfree(pcmd);
+ res = _FAIL;
+ goto exit;
+ }
+
+ _rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm));
+
+ psetkeyparm->keyid = (u8)keyid;
+
+ psetkeyparm->algorithm = alg;
+
+ psetkeyparm->set_tx = 1;
+
+ switch (alg) {
+ case _WEP40_:
+ keylen = 5;
+ break;
+ case _WEP104_:
+ keylen = 13;
+ break;
+ case _TKIP_:
+ case _TKIP_WTMIC_:
+ case _AES_:
+ keylen = 16;
+ default:
+ keylen = 16;
+ }
+
+ memcpy(&(psetkeyparm->key[0]), key, keylen);
+
+ pcmd->cmdcode = _SetKey_CMD_;
+ pcmd->parmbuf = (u8 *)psetkeyparm;
+ pcmd->cmdsz = (sizeof(struct setkey_parm));
+ pcmd->rsp = NULL;
+ pcmd->rspsz = 0;
+
+ _rtw_init_listhead(&pcmd->list);
+
+ res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+ return res;
+}
+
+static int set_wep_key(struct adapter *padapter, u8 *key, u8 keylen, int keyid)
+{
+ u8 alg;
+
+ switch (keylen) {
+ case 5:
+ alg = _WEP40_;
+ break;
+ case 13:
+ alg = _WEP104_;
+ break;
+ default:
+ alg = _NO_PRIVACY_;
+ }
+
+ return set_group_key(padapter, key, alg, keyid);
+}
+
+static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
+{
+ int ret = 0;
+ u32 wep_key_idx, wep_key_len, wep_total_len;
+ struct ndis_802_11_wep *pwep = NULL;
+ struct sta_info *psta = NULL, *pbcmc_sta = NULL;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &(padapter->securitypriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ DBG_88E("%s\n", __func__);
+ param->u.crypt.err = 0;
+ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+ if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ if (param->u.crypt.idx >= WEP_KEYS) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ } else {
+ psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+ if (!psta) {
+ DBG_88E("rtw_set_encryption(), sta has already been removed or never been added\n");
+ goto exit;
+ }
+ }
+
+ if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) {
+ /* todo:clear default encryption keys */
+
+ DBG_88E("clear default encryption keys, keyid =%d\n", param->u.crypt.idx);
+ goto exit;
+ }
+ if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) {
+ DBG_88E("r871x_set_encryption, crypt.alg = WEP\n");
+ wep_key_idx = param->u.crypt.idx;
+ wep_key_len = param->u.crypt.key_len;
+ DBG_88E("r871x_set_encryption, wep_key_idx=%d, len=%d\n", wep_key_idx, wep_key_len);
+ if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (wep_key_len > 0) {
+ wep_key_len = wep_key_len <= 5 ? 5 : 13;
+ wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
+ pwep = (struct ndis_802_11_wep *)rtw_malloc(wep_total_len);
+ if (pwep == NULL) {
+ DBG_88E(" r871x_set_encryption: pwep allocate fail !!!\n");
+ goto exit;
+ }
+
+ _rtw_memset(pwep, 0, wep_total_len);
+
+ pwep->KeyLength = wep_key_len;
+ pwep->Length = wep_total_len;
+ }
+
+ pwep->KeyIndex = wep_key_idx;
+
+ memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength);
+
+ if (param->u.crypt.set_tx) {
+ DBG_88E("wep, set_tx = 1\n");
+
+ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+
+ if (pwep->KeyLength == 13) {
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+ }
+
+ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
+
+ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
+
+ psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
+
+ set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx);
+ } else {
+ DBG_88E("wep, set_tx = 0\n");
+
+ /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */
+ /* psecuritypriv->dot11PrivacyKeyIndex = keyid", but can rtw_set_key to cam */
+
+ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
+
+ psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
+
+ set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx);
+ }
+
+ goto exit;
+ }
+
+ if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /* group key */
+ if (param->u.crypt.set_tx == 1) {
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ DBG_88E("%s, set group_key, WEP\n", __func__);
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+ param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+ if (param->u.crypt.key_len == 13)
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ DBG_88E("%s, set group_key, TKIP\n", __func__);
+ psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+ param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ /* set mic key */
+ memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+
+ psecuritypriv->busetkipkey = true;
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ DBG_88E("%s, set group_key, CCMP\n", __func__);
+ psecuritypriv->dot118021XGrpPrivacy = _AES_;
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+ param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ } else {
+ DBG_88E("%s, set group_key, none\n", __func__);
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+ }
+ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+ psecuritypriv->binstallGrpkey = true;
+ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* */
+ set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
+ pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+ if (pbcmc_sta) {
+ pbcmc_sta->ieee8021x_blocked = false;
+ pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */
+ }
+ }
+ goto exit;
+ }
+
+ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) { /* psk/802_1x */
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ if (param->u.crypt.set_tx == 1) {
+ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ DBG_88E("%s, set pairwise key, WEP\n", __func__);
+
+ psta->dot118021XPrivacy = _WEP40_;
+ if (param->u.crypt.key_len == 13)
+ psta->dot118021XPrivacy = _WEP104_;
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ DBG_88E("%s, set pairwise key, TKIP\n", __func__);
+
+ psta->dot118021XPrivacy = _TKIP_;
+
+ /* set mic key */
+ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
+
+ psecuritypriv->busetkipkey = true;
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ DBG_88E("%s, set pairwise key, CCMP\n", __func__);
+
+ psta->dot118021XPrivacy = _AES_;
+ } else {
+ DBG_88E("%s, set pairwise key, none\n", __func__);
+
+ psta->dot118021XPrivacy = _NO_PRIVACY_;
+ }
+
+ set_pairwise_key(padapter, psta);
+
+ psta->ieee8021x_blocked = false;
+ } else { /* group key??? */
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+ param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+ if (param->u.crypt.key_len == 13)
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+ param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ /* set mic key */
+ memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+
+ psecuritypriv->busetkipkey = true;
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ psecuritypriv->dot118021XGrpPrivacy = _AES_;
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+ param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ } else {
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+ }
+
+ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+
+ psecuritypriv->binstallGrpkey = true;
+
+ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* */
+
+ set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
+
+ pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+ if (pbcmc_sta) {
+ pbcmc_sta->ieee8021x_blocked = false;
+ pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */
+ }
+ }
+ }
+ }
+
+exit:
+
+ kfree(pwep);
+
+ return ret;
+}
+
+static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ unsigned char *pbuf = param->u.bcn_ie.buf;
+
+ DBG_88E("%s, len =%d\n", __func__, len);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2);
+
+ if ((pstapriv->max_num_sta > NUM_STA) || (pstapriv->max_num_sta <= 0))
+ pstapriv->max_num_sta = NUM_STA;
+
+ if (rtw_check_beacon_data(padapter, pbuf, (len-12-2)) == _SUCCESS)/* 12 = param header, 2:no packed */
+ ret = 0;
+ else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static int rtw_hostapd_sta_flush(struct net_device *dev)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ DBG_88E("%s\n", __func__);
+
+ flush_all_cam_entry(padapter); /* clear CAM */
+
+ ret = rtw_sta_flush(padapter);
+
+ return ret;
+}
+
+static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
+{
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ DBG_88E("rtw_add_sta(aid =%d) =%pM\n", param->u.add_sta.aid, (param->sta_addr));
+
+ if (!check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)))
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+ return -EINVAL;
+
+ psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+ if (psta) {
+ int flags = param->u.add_sta.flags;
+
+ psta->aid = param->u.add_sta.aid;/* aid = 1~2007 */
+
+ memcpy(psta->bssrateset, param->u.add_sta.tx_supp_rates, 16);
+
+ /* check wmm cap. */
+ if (WLAN_STA_WME&flags)
+ psta->qos_option = 1;
+ else
+ psta->qos_option = 0;
+
+ if (pmlmepriv->qospriv.qos_option == 0)
+ psta->qos_option = 0;
+
+ /* chec 802.11n ht cap. */
+ if (WLAN_STA_HT&flags) {
+ psta->htpriv.ht_option = true;
+ psta->qos_option = 1;
+ memcpy((void *)&psta->htpriv.ht_cap, (void *)&param->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap));
+ } else {
+ psta->htpriv.ht_option = false;
+ }
+
+ if (pmlmepriv->htpriv.ht_option == false)
+ psta->htpriv.ht_option = false;
+
+ update_sta_info_apmode(padapter, psta);
+ } else {
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
+{
+ unsigned long irqL;
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ int updated = 0;
+
+ DBG_88E("rtw_del_sta =%pM\n", (param->sta_addr));
+
+ if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+ return -EINVAL;
+
+ psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+ if (psta) {
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ if (!rtw_is_list_empty(&psta->asoc_list)) {
+ rtw_list_delete(&psta->asoc_list);
+ pstapriv->asoc_list_cnt--;
+ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ associated_clients_update(padapter, updated);
+ psta = NULL;
+ } else {
+ DBG_88E("rtw_del_sta(), sta has already been removed or never been added\n");
+ }
+
+ return ret;
+}
+
+static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param;
+ struct sta_data *psta_data = (struct sta_data *)param_ex->data;
+
+ DBG_88E("rtw_ioctl_get_sta_info, sta_addr: %pM\n", (param_ex->sta_addr));
+
+ if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true)
+ return -EINVAL;
+
+ if (param_ex->sta_addr[0] == 0xff && param_ex->sta_addr[1] == 0xff &&
+ param_ex->sta_addr[2] == 0xff && param_ex->sta_addr[3] == 0xff &&
+ param_ex->sta_addr[4] == 0xff && param_ex->sta_addr[5] == 0xff)
+ return -EINVAL;
+
+ psta = rtw_get_stainfo(pstapriv, param_ex->sta_addr);
+ if (psta) {
+ psta_data->aid = (u16)psta->aid;
+ psta_data->capability = psta->capability;
+ psta_data->flags = psta->flags;
+
+/*
+ nonerp_set : BIT(0)
+ no_short_slot_time_set : BIT(1)
+ no_short_preamble_set : BIT(2)
+ no_ht_gf_set : BIT(3)
+ no_ht_set : BIT(4)
+ ht_20mhz_set : BIT(5)
+*/
+
+ psta_data->sta_set = ((psta->nonerp_set) |
+ (psta->no_short_slot_time_set << 1) |
+ (psta->no_short_preamble_set << 2) |
+ (psta->no_ht_gf_set << 3) |
+ (psta->no_ht_set << 4) |
+ (psta->ht_20mhz_set << 5));
+ psta_data->tx_supp_rates_len = psta->bssratelen;
+ memcpy(psta_data->tx_supp_rates, psta->bssrateset, psta->bssratelen);
+ memcpy(&psta_data->ht_cap, &psta->htpriv.ht_cap, sizeof(struct rtw_ieee80211_ht_cap));
+ psta_data->rx_pkts = psta->sta_stats.rx_data_pkts;
+ psta_data->rx_bytes = psta->sta_stats.rx_bytes;
+ psta_data->rx_drops = psta->sta_stats.rx_drops;
+ psta_data->tx_pkts = psta->sta_stats.tx_pkts;
+ psta_data->tx_bytes = psta->sta_stats.tx_bytes;
+ psta_data->tx_drops = psta->sta_stats.tx_drops;
+ } else {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param)
+{
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ DBG_88E("rtw_get_sta_wpaie, sta_addr: %pM\n", (param->sta_addr));
+
+ if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+ return -EINVAL;
+
+ psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+ if (psta) {
+ if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_GENERIC)) {
+ int wpa_ie_len;
+ int copy_len;
+
+ wpa_ie_len = psta->wpa_ie[1];
+ copy_len = ((wpa_ie_len+2) > sizeof(psta->wpa_ie)) ? (sizeof(psta->wpa_ie)) : (wpa_ie_len+2);
+ param->u.wpa_ie.len = copy_len;
+ memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len);
+ } else {
+ DBG_88E("sta's wpa_ie is NONE\n");
+ }
+ } else {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ unsigned char wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ int ie_len;
+
+ DBG_88E("%s, len =%d\n", __func__, len);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ ie_len = len-12-2;/* 12 = param header, 2:no packed */
+
+ if (pmlmepriv->wps_beacon_ie) {
+ kfree(pmlmepriv->wps_beacon_ie);
+ pmlmepriv->wps_beacon_ie = NULL;
+ }
+
+ if (ie_len > 0) {
+ pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len);
+ pmlmepriv->wps_beacon_ie_len = ie_len;
+ if (pmlmepriv->wps_beacon_ie == NULL) {
+ DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ memcpy(pmlmepriv->wps_beacon_ie, param->u.bcn_ie.buf, ie_len);
+
+ update_beacon(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, true);
+
+ pmlmeext->bstart_bss = true;
+ }
+
+ return ret;
+}
+
+static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ int ie_len;
+
+ DBG_88E("%s, len =%d\n", __func__, len);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ ie_len = len-12-2;/* 12 = param header, 2:no packed */
+
+ if (pmlmepriv->wps_probe_resp_ie) {
+ kfree(pmlmepriv->wps_probe_resp_ie);
+ pmlmepriv->wps_probe_resp_ie = NULL;
+ }
+
+ if (ie_len > 0) {
+ pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len);
+ pmlmepriv->wps_probe_resp_ie_len = ie_len;
+ if (pmlmepriv->wps_probe_resp_ie == NULL) {
+ DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len);
+ }
+
+ return ret;
+}
+
+static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ int ie_len;
+
+ DBG_88E("%s, len =%d\n", __func__, len);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ ie_len = len-12-2;/* 12 = param header, 2:no packed */
+
+ if (pmlmepriv->wps_assoc_resp_ie) {
+ kfree(pmlmepriv->wps_assoc_resp_ie);
+ pmlmepriv->wps_assoc_resp_ie = NULL;
+ }
+
+ if (ie_len > 0) {
+ pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len);
+ pmlmepriv->wps_assoc_resp_ie_len = ie_len;
+ if (pmlmepriv->wps_assoc_resp_ie == NULL) {
+ DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len);
+ }
+
+ return ret;
+}
+
+static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+ u8 value;
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ if (param->u.wpa_param.name != 0) /* dummy test... */
+ DBG_88E("%s name(%u) != 0\n", __func__, param->u.wpa_param.name);
+ value = param->u.wpa_param.value;
+
+ /* use the same definition of hostapd's ignore_broadcast_ssid */
+ if (value != 1 && value != 2)
+ value = 0;
+ DBG_88E("%s value(%u)\n", __func__, value);
+ pmlmeinfo->hidden_ssid_mode = value;
+ return ret;
+}
+
+static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+ return -EINVAL;
+ ret = rtw_acl_remove_sta(padapter, param->sta_addr);
+ return ret;
+}
+
+static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+ return -EINVAL;
+ ret = rtw_acl_add_sta(padapter, param->sta_addr);
+ return ret;
+}
+
+static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ rtw_set_macaddr_acl(padapter, param->u.mlme.command);
+
+ return ret;
+}
+
+static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p)
+{
+ struct ieee_param *param;
+ int ret = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ /*
+ * this function is expect to call in master mode, which allows no power saving
+ * so, we just check hw_init_completed
+ */
+
+ if (!padapter->hw_init_completed) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ if (!p->pointer) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ param = (struct ieee_param *)rtw_malloc(p->length);
+ if (param == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(param, p->pointer, p->length)) {
+ kfree(param);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ switch (param->cmd) {
+ case RTL871X_HOSTAPD_FLUSH:
+ ret = rtw_hostapd_sta_flush(dev);
+ break;
+ case RTL871X_HOSTAPD_ADD_STA:
+ ret = rtw_add_sta(dev, param);
+ break;
+ case RTL871X_HOSTAPD_REMOVE_STA:
+ ret = rtw_del_sta(dev, param);
+ break;
+ case RTL871X_HOSTAPD_SET_BEACON:
+ ret = rtw_set_beacon(dev, param, p->length);
+ break;
+ case RTL871X_SET_ENCRYPTION:
+ ret = rtw_set_encryption(dev, param, p->length);
+ break;
+ case RTL871X_HOSTAPD_GET_WPAIE_STA:
+ ret = rtw_get_sta_wpaie(dev, param);
+ break;
+ case RTL871X_HOSTAPD_SET_WPS_BEACON:
+ ret = rtw_set_wps_beacon(dev, param, p->length);
+ break;
+ case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP:
+ ret = rtw_set_wps_probe_resp(dev, param, p->length);
+ break;
+ case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP:
+ ret = rtw_set_wps_assoc_resp(dev, param, p->length);
+ break;
+ case RTL871X_HOSTAPD_SET_HIDDEN_SSID:
+ ret = rtw_set_hidden_ssid(dev, param, p->length);
+ break;
+ case RTL871X_HOSTAPD_GET_INFO_STA:
+ ret = rtw_ioctl_get_sta_data(dev, param, p->length);
+ break;
+ case RTL871X_HOSTAPD_SET_MACADDR_ACL:
+ ret = rtw_ioctl_set_macaddr_acl(dev, param, p->length);
+ break;
+ case RTL871X_HOSTAPD_ACL_ADD_STA:
+ ret = rtw_ioctl_acl_add_sta(dev, param, p->length);
+ break;
+ case RTL871X_HOSTAPD_ACL_REMOVE_STA:
+ ret = rtw_ioctl_acl_remove_sta(dev, param, p->length);
+ break;
+ default:
+ DBG_88E("Unknown hostapd request: %d\n", param->cmd);
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+ ret = -EFAULT;
+ kfree(param);
+out:
+ return ret;
+}
+#endif
+
+#include <rtw_android.h>
+static int rtw_wx_set_priv(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *awrq,
+ char *extra)
+{
+ int ret = 0;
+ int len = 0;
+ char *ext;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct iw_point *dwrq = (struct iw_point *)awrq;
+
+ if (dwrq->length == 0)
+ return -EFAULT;
+
+ len = dwrq->length;
+ ext = rtw_vmalloc(len);
+ if (!ext)
+ return -ENOMEM;
+
+ if (copy_from_user(ext, dwrq->pointer, len)) {
+ rtw_vmfree(ext, len);
+ return -EFAULT;
+ }
+
+ /* added for wps2.0 @20110524 */
+ if (dwrq->flags == 0x8766 && len > 8) {
+ u32 cp_sz;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u8 *probereq_wpsie = ext;
+ int probereq_wpsie_len = len;
+ u8 wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+ if ((_VENDOR_SPECIFIC_IE_ == probereq_wpsie[0]) &&
+ (!memcmp(&probereq_wpsie[2], wps_oui, 4))) {
+ cp_sz = probereq_wpsie_len > MAX_WPS_IE_LEN ? MAX_WPS_IE_LEN : probereq_wpsie_len;
+
+ pmlmepriv->wps_probe_req_ie_len = 0;
+ kfree(pmlmepriv->wps_probe_req_ie);
+ pmlmepriv->wps_probe_req_ie = NULL;
+
+ pmlmepriv->wps_probe_req_ie = rtw_malloc(cp_sz);
+ if (pmlmepriv->wps_probe_req_ie == NULL) {
+ pr_info("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ ret = -EINVAL;
+ goto FREE_EXT;
+ }
+ memcpy(pmlmepriv->wps_probe_req_ie, probereq_wpsie, cp_sz);
+ pmlmepriv->wps_probe_req_ie_len = cp_sz;
+ }
+ goto FREE_EXT;
+ }
+
+ if (len >= WEXT_CSCAN_HEADER_SIZE &&
+ !memcmp(ext, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)) {
+ ret = rtw_wx_set_scan(dev, info, awrq, ext);
+ goto FREE_EXT;
+ }
+
+FREE_EXT:
+
+ rtw_vmfree(ext, len);
+
+ return ret;
+}
+
+static int rtw_pm_set(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ unsigned mode = 0;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ DBG_88E("[%s] extra = %s\n", __func__, extra);
+
+ if (!memcmp(extra, "lps =", 4)) {
+ sscanf(extra+4, "%u", &mode);
+ ret = rtw_pm_set_lps(padapter, mode);
+ } else if (!memcmp(extra, "ips =", 4)) {
+ sscanf(extra+4, "%u", &mode);
+ ret = rtw_pm_set_ips(padapter, mode);
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int rtw_mp_efuse_get(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wdata, char *extra)
+{
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+ struct hal_data_8188e *haldata = GET_HAL_DATA(padapter);
+ struct efuse_hal *pEfuseHal;
+ struct iw_point *wrqu;
+
+ u8 *PROMContent = pEEPROM->efuse_eeprom_data;
+ u8 ips_mode = 0, lps_mode = 0;
+ struct pwrctrl_priv *pwrctrlpriv;
+ u8 *data = NULL;
+ u8 *rawdata = NULL;
+ char *pch, *ptmp, *token, *tmp[3] = {NULL, NULL, NULL};
+ u16 i = 0, j = 0, mapLen = 0, addr = 0, cnts = 0;
+ u16 max_available_size = 0, raw_cursize = 0, raw_maxsize = 0;
+ int err;
+ u8 org_fw_iol = padapter->registrypriv.fw_iol;/* 0:Disable, 1:enable, 2:by usb speed */
+
+ wrqu = (struct iw_point *)wdata;
+ pwrctrlpriv = &padapter->pwrctrlpriv;
+ pEfuseHal = &haldata->EfuseHal;
+
+ err = 0;
+ data = _rtw_zmalloc(EFUSE_BT_MAX_MAP_LEN);
+ if (data == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ rawdata = _rtw_zmalloc(EFUSE_BT_MAX_MAP_LEN);
+ if (rawdata == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ if (copy_from_user(extra, wrqu->pointer, wrqu->length)) {
+ err = -EFAULT;
+ goto exit;
+ }
+ lps_mode = pwrctrlpriv->power_mgnt;/* keep org value */
+ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
+
+ ips_mode = pwrctrlpriv->ips_mode;/* keep org value */
+ rtw_pm_set_ips(padapter, IPS_NONE);
+
+ pch = extra;
+ DBG_88E("%s: in =%s\n", __func__, extra);
+
+ i = 0;
+ /* mac 16 "00e04c871200" rmap, 00, 2 */
+ while ((token = strsep(&pch, ",")) != NULL) {
+ if (i > 2)
+ break;
+ tmp[i] = token;
+ i++;
+ }
+ padapter->registrypriv.fw_iol = 0;/* 0:Disable, 1:enable, 2:by usb speed */
+
+ if (strcmp(tmp[0], "status") == 0) {
+ sprintf(extra, "Load File efuse =%s, Load File MAC =%s", (pEEPROM->bloadfile_fail_flag ? "FAIL" : "OK"), (pEEPROM->bloadmac_fail_flag ? "FAIL" : "OK"));
+
+ goto exit;
+ } else if (strcmp(tmp[0], "filemap") == 0) {
+ mapLen = EFUSE_MAP_SIZE;
+
+ sprintf(extra, "\n");
+ for (i = 0; i < EFUSE_MAP_SIZE; i += 16) {
+ sprintf(extra, "%s0x%02x\t", extra, i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra, "%s%02X ", extra, PROMContent[i+j]);
+ sprintf(extra, "%s\t", extra);
+ for (; j < 16; j++)
+ sprintf(extra, "%s%02X ", extra, PROMContent[i+j]);
+ sprintf(extra, "%s\n", extra);
+ }
+ } else if (strcmp(tmp[0], "realmap") == 0) {
+ mapLen = EFUSE_MAP_SIZE;
+ if (rtw_efuse_map_read(padapter, 0, mapLen, pEfuseHal->fakeEfuseInitMap) == _FAIL) {
+ DBG_88E("%s: read realmap Fail!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ sprintf(extra, "\n");
+ for (i = 0; i < EFUSE_MAP_SIZE; i += 16) {
+ sprintf(extra, "%s0x%02x\t", extra, i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeEfuseInitMap[i+j]);
+ sprintf(extra, "%s\t", extra);
+ for (; j < 16; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeEfuseInitMap[i+j]);
+ sprintf(extra, "%s\n", extra);
+ }
+ } else if (strcmp(tmp[0], "rmap") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ DBG_88E("%s: rmap Fail!! Parameters error!\n", __func__);
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* rmap addr cnts */
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ DBG_88E("%s: addr =%x\n", __func__, addr);
+
+ cnts = simple_strtoul(tmp[2], &ptmp, 10);
+ if (cnts == 0) {
+ DBG_88E("%s: rmap Fail!! cnts error!\n", __func__);
+ err = -EINVAL;
+ goto exit;
+ }
+ DBG_88E("%s: cnts =%d\n", __func__, cnts);
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+ if ((addr + cnts) > max_available_size) {
+ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EINVAL;
+ goto exit;
+ }
+
+ if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) {
+ DBG_88E("%s: rtw_efuse_map_read error!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ *extra = 0;
+ for (i = 0; i < cnts; i++)
+ sprintf(extra, "%s0x%02X ", extra, data[i]);
+ } else if (strcmp(tmp[0], "realraw") == 0) {
+ addr = 0;
+ mapLen = EFUSE_MAX_SIZE;
+ if (rtw_efuse_access(padapter, false, addr, mapLen, rawdata) == _FAIL) {
+ DBG_88E("%s: rtw_efuse_access Fail!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ sprintf(extra, "\n");
+ for (i = 0; i < mapLen; i++) {
+ sprintf(extra, "%s%02X", extra, rawdata[i]);
+
+ if ((i & 0xF) == 0xF)
+ sprintf(extra, "%s\n", extra);
+ else if ((i & 0x7) == 0x7)
+ sprintf(extra, "%s\t", extra);
+ else
+ sprintf(extra, "%s ", extra);
+ }
+ } else if (strcmp(tmp[0], "mac") == 0) {
+ cnts = 6;
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+ if ((addr + cnts) > max_available_size) {
+ DBG_88E("%s: addr(0x%02x)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) {
+ DBG_88E("%s: rtw_efuse_map_read error!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ *extra = 0;
+ for (i = 0; i < cnts; i++) {
+ sprintf(extra, "%s%02X", extra, data[i]);
+ if (i != (cnts-1))
+ sprintf(extra, "%s:", extra);
+ }
+ } else if (strcmp(tmp[0], "vidpid") == 0) {
+ cnts = 4;
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+ if ((addr + cnts) > max_available_size) {
+ DBG_88E("%s: addr(0x%02x)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+ if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) {
+ DBG_88E("%s: rtw_efuse_access error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ *extra = 0;
+ for (i = 0; i < cnts; i++) {
+ sprintf(extra, "%s0x%02X", extra, data[i]);
+ if (i != (cnts-1))
+ sprintf(extra, "%s,", extra);
+ }
+ } else if (strcmp(tmp[0], "ableraw") == 0) {
+ efuse_GetCurrentSize(padapter, &raw_cursize);
+ raw_maxsize = efuse_GetMaxSize(padapter);
+ sprintf(extra, "[available raw size] = %d bytes", raw_maxsize-raw_cursize);
+ } else if (strcmp(tmp[0], "btfmap") == 0) {
+ mapLen = EFUSE_BT_MAX_MAP_LEN;
+ if (rtw_BT_efuse_map_read(padapter, 0, mapLen, pEfuseHal->BTEfuseInitMap) == _FAIL) {
+ DBG_88E("%s: rtw_BT_efuse_map_read Fail!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ sprintf(extra, "\n");
+ for (i = 0; i < 512; i += 16) {
+ /* set 512 because the iwpriv's extra size have limit 0x7FF */
+ sprintf(extra, "%s0x%03x\t", extra, i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]);
+ sprintf(extra, "%s\t", extra);
+ for (; j < 16; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]);
+ sprintf(extra, "%s\n", extra);
+ }
+ } else if (strcmp(tmp[0], "btbmap") == 0) {
+ mapLen = EFUSE_BT_MAX_MAP_LEN;
+ if (rtw_BT_efuse_map_read(padapter, 0, mapLen, pEfuseHal->BTEfuseInitMap) == _FAIL) {
+ DBG_88E("%s: rtw_BT_efuse_map_read Fail!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ sprintf(extra, "\n");
+ for (i = 512; i < 1024; i += 16) {
+ sprintf(extra, "%s0x%03x\t", extra, i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]);
+ sprintf(extra, "%s\t", extra);
+ for (; j < 16; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]);
+ sprintf(extra, "%s\n", extra);
+ }
+ } else if (strcmp(tmp[0], "btrmap") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* rmap addr cnts */
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+
+ cnts = simple_strtoul(tmp[2], &ptmp, 10);
+ if (cnts == 0) {
+ DBG_88E("%s: btrmap Fail!! cnts error!\n", __func__);
+ err = -EINVAL;
+ goto exit;
+ }
+ DBG_88E("%s: cnts =%d\n", __func__, cnts);
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+ if ((addr + cnts) > max_available_size) {
+ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_BT_efuse_map_read(padapter, addr, cnts, data) == _FAIL) {
+ DBG_88E("%s: rtw_BT_efuse_map_read error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ *extra = 0;
+ for (i = 0; i < cnts; i++)
+ sprintf(extra, "%s 0x%02X ", extra, data[i]);
+ } else if (strcmp(tmp[0], "btffake") == 0) {
+ sprintf(extra, "\n");
+ for (i = 0; i < 512; i += 16) {
+ sprintf(extra, "%s0x%03x\t", extra, i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]);
+ sprintf(extra, "%s\t", extra);
+ for (; j < 16; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]);
+ sprintf(extra, "%s\n", extra);
+ }
+ } else if (strcmp(tmp[0], "btbfake") == 0) {
+ sprintf(extra, "\n");
+ for (i = 512; i < 1024; i += 16) {
+ sprintf(extra, "%s0x%03x\t", extra, i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]);
+ sprintf(extra, "%s\t", extra);
+ for (; j < 16; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]);
+ sprintf(extra, "%s\n", extra);
+ }
+ } else if (strcmp(tmp[0], "wlrfkmap") == 0) {
+ sprintf(extra, "\n");
+ for (i = 0; i < EFUSE_MAP_SIZE; i += 16) {
+ sprintf(extra, "%s0x%02x\t", extra, i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeEfuseModifiedMap[i+j]);
+ sprintf(extra, "%s\t", extra);
+ for (; j < 16; j++)
+ sprintf(extra, "%s %02X", extra, pEfuseHal->fakeEfuseModifiedMap[i+j]);
+ sprintf(extra, "%s\n", extra);
+ }
+ } else {
+ sprintf(extra, "Command not found!");
+ }
+
+exit:
+ kfree(data);
+ kfree(rawdata);
+ if (!err)
+ wrqu->length = strlen(extra);
+
+ rtw_pm_set_ips(padapter, ips_mode);
+ rtw_pm_set_lps(padapter, lps_mode);
+ padapter->registrypriv.fw_iol = org_fw_iol;/* 0:Disable, 1:enable, 2:by usb speed */
+ return err;
+}
+
+static int rtw_mp_efuse_set(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wdata, char *extra)
+{
+ struct adapter *padapter;
+ struct pwrctrl_priv *pwrctrlpriv;
+ struct hal_data_8188e *haldata;
+ struct efuse_hal *pEfuseHal;
+
+ u8 ips_mode = 0, lps_mode = 0;
+ u32 i, jj, kk;
+ u8 *setdata = NULL;
+ u8 *ShadowMapBT = NULL;
+ u8 *ShadowMapWiFi = NULL;
+ u8 *setrawdata = NULL;
+ char *pch, *ptmp, *token, *tmp[3] = {NULL, NULL, NULL};
+ u16 addr = 0, cnts = 0, max_available_size = 0;
+ int err;
+
+ padapter = rtw_netdev_priv(dev);
+ pwrctrlpriv = &padapter->pwrctrlpriv;
+ haldata = GET_HAL_DATA(padapter);
+ pEfuseHal = &haldata->EfuseHal;
+ err = 0;
+ setdata = _rtw_zmalloc(1024);
+ if (setdata == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ ShadowMapBT = _rtw_malloc(EFUSE_BT_MAX_MAP_LEN);
+ if (ShadowMapBT == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ ShadowMapWiFi = _rtw_malloc(EFUSE_MAP_SIZE);
+ if (ShadowMapWiFi == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ setrawdata = _rtw_malloc(EFUSE_MAX_SIZE);
+ if (setrawdata == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ lps_mode = pwrctrlpriv->power_mgnt;/* keep org value */
+ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
+
+ ips_mode = pwrctrlpriv->ips_mode;/* keep org value */
+ rtw_pm_set_ips(padapter, IPS_NONE);
+
+ pch = extra;
+ DBG_88E("%s: in =%s\n", __func__, extra);
+
+ i = 0;
+ while ((token = strsep(&pch, ",")) != NULL) {
+ if (i > 2)
+ break;
+ tmp[i] = token;
+ i++;
+ }
+
+ /* tmp[0],[1],[2] */
+ /* wmap, addr, 00e04c871200 */
+ if (strcmp(tmp[0], "wmap") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts%2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+ DBG_88E("%s: cnts =%d\n", __func__, cnts);
+ DBG_88E("%s: map data =%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+ /* Change to check TYPE_EFUSE_MAP_LEN, beacuse 8188E raw 256, logic map over 256. */
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_size, false);
+ if ((addr+cnts) > max_available_size) {
+ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+ DBG_88E("%s: rtw_efuse_map_write error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ } else if (strcmp(tmp[0], "wraw") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts%2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+ DBG_88E("%s: cnts =%d\n", __func__, cnts);
+ DBG_88E("%s: raw data =%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setrawdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+
+ if (rtw_efuse_access(padapter, true, addr, cnts, setrawdata) == _FAIL) {
+ DBG_88E("%s: rtw_efuse_access error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ } else if (strcmp(tmp[0], "mac") == 0) {
+ if (tmp[1] == NULL) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* mac, 00e04c871200 */
+ addr = EEPROM_MAC_ADDR_88EU;
+ cnts = strlen(tmp[1]);
+ if (cnts%2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (cnts > 6) {
+ DBG_88E("%s: error data for mac addr =\"%s\"\n", __func__, tmp[1]);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+ DBG_88E("%s: cnts =%d\n", __func__, cnts);
+ DBG_88E("%s: MAC address =%s\n", __func__, tmp[1]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setdata[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]);
+ /* Change to check TYPE_EFUSE_MAP_LEN, beacuse 8188E raw 256, logic map over 256. */
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_size, false);
+ if ((addr+cnts) > max_available_size) {
+ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+ DBG_88E("%s: rtw_efuse_map_write error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ } else if (strcmp(tmp[0], "vidpid") == 0) {
+ if (tmp[1] == NULL) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* pidvid, da0b7881 */
+ addr = EEPROM_VID_88EE;
+ cnts = strlen(tmp[1]);
+ if (cnts%2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+ DBG_88E("%s: cnts =%d\n", __func__, cnts);
+ DBG_88E("%s: VID/PID =%s\n", __func__, tmp[1]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setdata[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]);
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+ if ((addr+cnts) > max_available_size) {
+ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+ DBG_88E("%s: rtw_efuse_map_write error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ } else if (strcmp(tmp[0], "btwmap") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts%2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+ DBG_88E("%s: cnts =%d\n", __func__, cnts);
+ DBG_88E("%s: BT data =%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+ if ((addr+cnts) > max_available_size) {
+ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_BT_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+ DBG_88E("%s: rtw_BT_efuse_map_write error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ } else if (strcmp(tmp[0], "btwfake") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts%2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+ DBG_88E("%s: cnts =%d\n", __func__, cnts);
+ DBG_88E("%s: BT tmp data =%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ pEfuseHal->fakeBTEfuseModifiedMap[addr+jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+ } else if (strcmp(tmp[0], "btdumpfake") == 0) {
+ if (rtw_BT_efuse_map_read(padapter, 0, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _SUCCESS) {
+ DBG_88E("%s: BT read all map success\n", __func__);
+ } else {
+ DBG_88E("%s: BT read all map Fail!\n", __func__);
+ err = -EFAULT;
+ }
+ } else if (strcmp(tmp[0], "wldumpfake") == 0) {
+ if (rtw_efuse_map_read(padapter, 0, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeEfuseModifiedMap) == _SUCCESS) {
+ DBG_88E("%s: BT read all map success\n", __func__);
+ } else {
+ DBG_88E("%s: BT read all map Fail\n", __func__);
+ err = -EFAULT;
+ }
+ } else if (strcmp(tmp[0], "btfk2map") == 0) {
+ memcpy(pEfuseHal->BTEfuseModifiedMap, pEfuseHal->fakeBTEfuseModifiedMap, EFUSE_BT_MAX_MAP_LEN);
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+ if (max_available_size < 1) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_BT_efuse_map_write(padapter, 0x00, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _FAIL) {
+ DBG_88E("%s: rtw_BT_efuse_map_write error!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ } else if (strcmp(tmp[0], "wlfk2map") == 0) {
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+ if (max_available_size < 1) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_efuse_map_write(padapter, 0x00, EFUSE_MAX_MAP_LEN, pEfuseHal->fakeEfuseModifiedMap) == _FAIL) {
+ DBG_88E("%s: rtw_efuse_map_write error!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ } else if (strcmp(tmp[0], "wlwfake") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts%2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+ DBG_88E("%s: cnts =%d\n", __func__, cnts);
+ DBG_88E("%s: map tmp data =%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ pEfuseHal->fakeEfuseModifiedMap[addr+jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+ }
+
+exit:
+ kfree(setdata);
+ kfree(ShadowMapBT);
+ kfree(ShadowMapWiFi);
+ kfree(setrawdata);
+
+ rtw_pm_set_ips(padapter, ips_mode);
+ rtw_pm_set_lps(padapter, lps_mode);
+
+ return err;
+}
+
+/*
+ * Input Format: %s,%d,%d
+ * %s is width, could be
+ * "b" for 1 byte
+ * "w" for WORD (2 bytes)
+ * "dw" for DWORD (4 bytes)
+ * 1st %d is address(offset)
+ * 2st %d is data to write
+ */
+static int rtw_mp_write_reg(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ char *pch, *pnext, *ptmp;
+ char *width_str;
+ char width;
+ u32 addr, data;
+ int ret;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ pch = extra;
+ pnext = strpbrk(pch, ",.-");
+ if (pnext == NULL)
+ return -EINVAL;
+ *pnext = 0;
+ width_str = pch;
+
+ pch = pnext + 1;
+ pnext = strpbrk(pch, ",.-");
+ if (pnext == NULL)
+ return -EINVAL;
+ *pnext = 0;
+ addr = simple_strtoul(pch, &ptmp, 16);
+ if (addr > 0x3FFF)
+ return -EINVAL;
+
+ pch = pnext + 1;
+ if ((pch - extra) >= wrqu->length)
+ return -EINVAL;
+ data = simple_strtoul(pch, &ptmp, 16);
+
+ ret = 0;
+ width = width_str[0];
+ switch (width) {
+ case 'b':
+ /* 1 byte */
+ if (data > 0xFF) {
+ ret = -EINVAL;
+ break;
+ }
+ rtw_write8(padapter, addr, data);
+ break;
+ case 'w':
+ /* 2 bytes */
+ if (data > 0xFFFF) {
+ ret = -EINVAL;
+ break;
+ }
+ rtw_write16(padapter, addr, data);
+ break;
+ case 'd':
+ /* 4 bytes */
+ rtw_write32(padapter, addr, data);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Input Format: %s,%d
+ * %s is width, could be
+ * "b" for 1 byte
+ * "w" for WORD (2 bytes)
+ * "dw" for DWORD (4 bytes)
+ * %d is address(offset)
+ *
+ * Return:
+ * %d for data readed
+ */
+static int rtw_mp_read_reg(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+ char *pch, *pnext, *ptmp;
+ char *width_str;
+ char width;
+ char data[20], tmp[20];
+ u32 addr;
+ u32 ret, i = 0, j = 0, strtout = 0;
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+ _rtw_memset(data, 0, 20);
+ _rtw_memset(tmp, 0, 20);
+ _rtw_memset(extra, 0, wrqu->length);
+
+ pch = input;
+ pnext = strpbrk(pch, ",.-");
+ if (pnext == NULL) {
+ kfree(input);
+ return -EINVAL;
+ }
+ *pnext = 0;
+ width_str = pch;
+
+ pch = pnext + 1;
+ if ((pch - input) >= wrqu->length) {
+ kfree(input);
+ return -EINVAL;
+ }
+ kfree(input);
+ addr = simple_strtoul(pch, &ptmp, 16);
+ if (addr > 0x3FFF)
+ return -EINVAL;
+
+ ret = 0;
+ width = width_str[0];
+ switch (width) {
+ case 'b':
+ /* 1 byte */
+ sprintf(extra, "%d\n", rtw_read8(padapter, addr));
+ wrqu->length = strlen(extra);
+ break;
+ case 'w':
+ /* 2 bytes */
+ sprintf(data, "%04x\n", rtw_read16(padapter, addr));
+ for (i = 0; i <= strlen(data); i++) {
+ if (i%2 == 0) {
+ tmp[j] = ' ';
+ j++;
+ }
+ if (data[i] != '\0')
+ tmp[j] = data[i];
+ j++;
+ }
+ pch = tmp;
+ DBG_88E("pch =%s", pch);
+
+ while (*pch != '\0') {
+ pnext = strpbrk(pch, " ");
+ if (!pnext)
+ break;
+
+ pnext++;
+ if (*pnext != '\0') {
+ strtout = simple_strtoul(pnext, &ptmp, 16);
+ sprintf(extra, "%s %d", extra, strtout);
+ } else {
+ break;
+ }
+ pch = pnext;
+ }
+ wrqu->length = 6;
+ break;
+ case 'd':
+ /* 4 bytes */
+ sprintf(data, "%08x", rtw_read32(padapter, addr));
+ /* add read data format blank */
+ for (i = 0; i <= strlen(data); i++) {
+ if (i%2 == 0) {
+ tmp[j] = ' ';
+ j++;
+ }
+ if (data[i] != '\0')
+ tmp[j] = data[i];
+
+ j++;
+ }
+ pch = tmp;
+ DBG_88E("pch =%s", pch);
+
+ while (*pch != '\0') {
+ pnext = strpbrk(pch, " ");
+ if (!pnext)
+ break;
+ pnext++;
+ if (*pnext != '\0') {
+ strtout = simple_strtoul(pnext, &ptmp, 16);
+ sprintf(extra, "%s %d", extra, strtout);
+ } else {
+ break;
+ }
+ pch = pnext;
+ }
+ wrqu->length = strlen(extra);
+ break;
+ default:
+ wrqu->length = 0;
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Input Format: %d,%x,%x
+ * %d is RF path, should be smaller than MAX_RF_PATH_NUMS
+ * 1st %x is address(offset)
+ * 2st %x is data to write
+ */
+ static int rtw_mp_write_rf(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 path, addr, data;
+ int ret;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ ret = sscanf(extra, "%d,%x,%x", &path, &addr, &data);
+ if (ret < 3)
+ return -EINVAL;
+
+ if (path >= MAX_RF_PATH_NUMS)
+ return -EINVAL;
+ if (addr > 0xFF)
+ return -EINVAL;
+ if (data > 0xFFFFF)
+ return -EINVAL;
+
+ _rtw_memset(extra, 0, wrqu->length);
+
+ write_rfreg(padapter, path, addr, data);
+
+ sprintf(extra, "write_rf completed\n");
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+/*
+ * Input Format: %d,%x
+ * %d is RF path, should be smaller than MAX_RF_PATH_NUMS
+ * %x is address(offset)
+ *
+ * Return:
+ * %d for data readed
+ */
+static int rtw_mp_read_rf(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+ char *pch, *pnext, *ptmp;
+ char data[20], tmp[20];
+ u32 path, addr;
+ u32 ret, i = 0, j = 0, strtou = 0;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+ ret = sscanf(input, "%d,%x", &path, &addr);
+ kfree(input);
+ if (ret < 2)
+ return -EINVAL;
+
+ if (path >= MAX_RF_PATH_NUMS)
+ return -EINVAL;
+ if (addr > 0xFF)
+ return -EINVAL;
+
+ _rtw_memset(extra, 0, wrqu->length);
+
+ sprintf(data, "%08x", read_rfreg(padapter, path, addr));
+ /* add read data format blank */
+ for (i = 0; i <= strlen(data); i++) {
+ if (i%2 == 0) {
+ tmp[j] = ' ';
+ j++;
+ }
+ tmp[j] = data[i];
+ j++;
+ }
+ pch = tmp;
+ DBG_88E("pch =%s", pch);
+
+ while (*pch != '\0') {
+ pnext = strpbrk(pch, " ");
+ pnext++;
+ if (*pnext != '\0') {
+ strtou = simple_strtoul(pnext, &ptmp, 16);
+ sprintf(extra, "%s %d", extra, strtou);
+ } else {
+ break;
+ }
+ pch = pnext;
+ }
+ wrqu->length = strlen(extra);
+ return 0;
+}
+
+static int rtw_mp_start(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (padapter->registrypriv.mp_mode == 0) {
+ padapter->registrypriv.mp_mode = 1;
+
+ rtw_pm_set_ips(padapter, IPS_NONE);
+ LeaveAllPowerSaveMode(padapter);
+
+ MPT_InitializeAdapter(padapter, 1);
+ }
+ if (padapter->registrypriv.mp_mode == 0)
+ return -EPERM;
+ if (padapter->mppriv.mode == MP_OFF) {
+ if (mp_start_test(padapter) == _FAIL)
+ return -EPERM;
+ padapter->mppriv.mode = MP_ON;
+ }
+ return 0;
+}
+
+static int rtw_mp_stop(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (padapter->registrypriv.mp_mode == 1) {
+ MPT_DeInitAdapter(padapter);
+ padapter->registrypriv.mp_mode = 0;
+ }
+
+ if (padapter->mppriv.mode != MP_OFF) {
+ mp_stop_test(padapter);
+ padapter->mppriv.mode = MP_OFF;
+ }
+
+ return 0;
+}
+
+extern int wifirate2_ratetbl_inx(unsigned char rate);
+
+static int rtw_mp_rate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 rate = MPT_RATE_1M;
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+ rate = rtw_atoi(input);
+ sprintf(extra, "Set data rate to %d", rate);
+ kfree(input);
+ if (rate <= 0x7f)
+ rate = wifirate2_ratetbl_inx((u8)rate);
+ else
+ rate = (rate-0x80+MPT_RATE_MCS0);
+
+ if (rate >= MPT_RATE_LAST)
+ return -EINVAL;
+
+ padapter->mppriv.rateidx = rate;
+ Hal_SetDataRate(padapter);
+
+ wrqu->length = strlen(extra) + 1;
+ return 0;
+}
+
+static int rtw_mp_channel(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+ u32 channel = 1;
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+ channel = rtw_atoi(input);
+ sprintf(extra, "Change channel %d to channel %d", padapter->mppriv.channel, channel);
+
+ padapter->mppriv.channel = channel;
+ Hal_SetChannel(padapter);
+
+ wrqu->length = strlen(extra) + 1;
+ kfree(input);
+ return 0;
+}
+
+static int rtw_mp_bandwidth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 bandwidth = 0, sg = 0;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ sscanf(extra, "40M =%d, shortGI =%d", &bandwidth, &sg);
+
+ if (bandwidth != HT_CHANNEL_WIDTH_40)
+ bandwidth = HT_CHANNEL_WIDTH_20;
+
+ padapter->mppriv.bandwidth = (u8)bandwidth;
+ padapter->mppriv.preamble = sg;
+
+ SetBandwidth(padapter);
+
+ return 0;
+}
+
+static int rtw_mp_txpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 idx_a = 0, idx_b = 0;
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+ sscanf(input, "patha =%d, pathb =%d", &idx_a, &idx_b);
+
+ sprintf(extra, "Set power level path_A:%d path_B:%d", idx_a, idx_b);
+ padapter->mppriv.txpoweridx = (u8)idx_a;
+ padapter->mppriv.txpoweridx_b = (u8)idx_b;
+ padapter->mppriv.bSetTxPower = 1;
+ Hal_SetAntennaPathPower(padapter);
+
+ wrqu->length = strlen(extra) + 1;
+ kfree(input);
+ return 0;
+}
+
+static int rtw_mp_ant_tx(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u8 i;
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+ u16 antenna = 0;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+
+ sprintf(extra, "switch Tx antenna to %s", input);
+
+ for (i = 0; i < strlen(input); i++) {
+ switch (input[i]) {
+ case 'a':
+ antenna |= ANTENNA_A;
+ break;
+ case 'b':
+ antenna |= ANTENNA_B;
+ break;
+ }
+ }
+ padapter->mppriv.antenna_tx = antenna;
+
+ Hal_SetAntenna(padapter);
+
+ wrqu->length = strlen(extra) + 1;
+ kfree(input);
+ return 0;
+}
+
+static int rtw_mp_ant_rx(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u8 i;
+ u16 antenna = 0;
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+ _rtw_memset(extra, 0, wrqu->length);
+
+ sprintf(extra, "switch Rx antenna to %s", input);
+
+ for (i = 0; i < strlen(input); i++) {
+ switch (input[i]) {
+ case 'a':
+ antenna |= ANTENNA_A;
+ break;
+ case 'b':
+ antenna |= ANTENNA_B;
+ break;
+ }
+ }
+
+ padapter->mppriv.antenna_rx = antenna;
+ Hal_SetAntenna(padapter);
+ wrqu->length = strlen(extra);
+ kfree(input);
+ return 0;
+}
+
+static int rtw_mp_ctx(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 pkTx = 1, countPkTx = 1, cotuTx = 1, CarrSprTx = 1, scTx = 1, sgleTx = 1, stop = 1;
+ u32 bStartTest = 1;
+ u32 count = 0;
+ struct mp_priv *pmp_priv;
+ struct pkt_attrib *pattrib;
+
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ pmp_priv = &padapter->mppriv;
+
+ if (copy_from_user(extra, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ DBG_88E("%s: in =%s\n", __func__, extra);
+
+ countPkTx = strncmp(extra, "count =", 5); /* strncmp true is 0 */
+ cotuTx = strncmp(extra, "background", 20);
+ CarrSprTx = strncmp(extra, "background, cs", 20);
+ scTx = strncmp(extra, "background, sc", 20);
+ sgleTx = strncmp(extra, "background, stone", 20);
+ pkTx = strncmp(extra, "background, pkt", 20);
+ stop = strncmp(extra, "stop", 4);
+ sscanf(extra, "count =%d, pkt", &count);
+
+ _rtw_memset(extra, '\0', sizeof(extra));
+
+ if (stop == 0) {
+ bStartTest = 0; /* To set Stop */
+ pmp_priv->tx.stop = 1;
+ sprintf(extra, "Stop continuous Tx");
+ } else {
+ bStartTest = 1;
+ if (pmp_priv->mode != MP_ON) {
+ if (pmp_priv->tx.stop != 1) {
+ DBG_88E("%s: MP_MODE != ON %d\n", __func__, pmp_priv->mode);
+ return -EFAULT;
+ }
+ }
+ }
+
+ if (pkTx == 0 || countPkTx == 0)
+ pmp_priv->mode = MP_PACKET_TX;
+ if (sgleTx == 0)
+ pmp_priv->mode = MP_SINGLE_TONE_TX;
+ if (cotuTx == 0)
+ pmp_priv->mode = MP_CONTINUOUS_TX;
+ if (CarrSprTx == 0)
+ pmp_priv->mode = MP_CARRIER_SUPPRISSION_TX;
+ if (scTx == 0)
+ pmp_priv->mode = MP_SINGLE_CARRIER_TX;
+
+ switch (pmp_priv->mode) {
+ case MP_PACKET_TX:
+ if (bStartTest == 0) {
+ pmp_priv->tx.stop = 1;
+ pmp_priv->mode = MP_ON;
+ sprintf(extra, "Stop continuous Tx");
+ } else if (pmp_priv->tx.stop == 1) {
+ sprintf(extra, "Start continuous DA = ffffffffffff len = 1500 count =%u,\n", count);
+ pmp_priv->tx.stop = 0;
+ pmp_priv->tx.count = count;
+ pmp_priv->tx.payload = 2;
+ pattrib = &pmp_priv->tx.attrib;
+ pattrib->pktlen = 1500;
+ _rtw_memset(pattrib->dst, 0xFF, ETH_ALEN);
+ SetPacketTx(padapter);
+ } else {
+ return -EFAULT;
+ }
+ wrqu->length = strlen(extra);
+ return 0;
+ case MP_SINGLE_TONE_TX:
+ if (bStartTest != 0)
+ sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes.");
+ Hal_SetSingleToneTx(padapter, (u8)bStartTest);
+ break;
+ case MP_CONTINUOUS_TX:
+ if (bStartTest != 0)
+ sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes.");
+ Hal_SetContinuousTx(padapter, (u8)bStartTest);
+ break;
+ case MP_CARRIER_SUPPRISSION_TX:
+ if (bStartTest != 0) {
+ if (pmp_priv->rateidx <= MPT_RATE_11M) {
+ sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes.");
+ Hal_SetCarrierSuppressionTx(padapter, (u8)bStartTest);
+ } else {
+ sprintf(extra, "Specify carrier suppression but not CCK rate");
+ }
+ }
+ break;
+ case MP_SINGLE_CARRIER_TX:
+ if (bStartTest != 0)
+ sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes.");
+ Hal_SetSingleCarrierTx(padapter, (u8)bStartTest);
+ break;
+ default:
+ sprintf(extra, "Error! Continuous-Tx is not on-going.");
+ return -EFAULT;
+ }
+
+ if (bStartTest == 1 && pmp_priv->mode != MP_ON) {
+ struct mp_priv *pmp_priv = &padapter->mppriv;
+ if (pmp_priv->tx.stop == 0) {
+ pmp_priv->tx.stop = 1;
+ rtw_msleep_os(5);
+ }
+ pmp_priv->tx.stop = 0;
+ pmp_priv->tx.count = 1;
+ SetPacketTx(padapter);
+ } else {
+ pmp_priv->mode = MP_ON;
+ }
+
+ wrqu->length = strlen(extra);
+ return 0;
+}
+
+static int rtw_mp_arx(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u8 bStartRx = 0, bStopRx = 0, bQueryPhy;
+ u32 cckok = 0, cckcrc = 0, ofdmok = 0, ofdmcrc = 0, htok = 0, htcrc = 0, OFDM_FA = 0, CCK_FA = 0;
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (!input)
+ return -ENOMEM;
+
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+ DBG_88E("%s: %s\n", __func__, input);
+
+ bStartRx = (strncmp(input, "start", 5) == 0) ? 1 : 0; /* strncmp true is 0 */
+ bStopRx = (strncmp(input, "stop", 5) == 0) ? 1 : 0; /* strncmp true is 0 */
+ bQueryPhy = (strncmp(input, "phy", 3) == 0) ? 1 : 0; /* strncmp true is 0 */
+
+ if (bStartRx) {
+ sprintf(extra, "start");
+ SetPacketRx(padapter, bStartRx);
+ } else if (bStopRx) {
+ SetPacketRx(padapter, 0);
+ sprintf(extra, "Received packet OK:%d CRC error:%d", padapter->mppriv.rx_pktcount, padapter->mppriv.rx_crcerrpktcount);
+ } else if (bQueryPhy) {
+ /*
+ OFDM FA
+ RegCF0[15:0]
+ RegCF2[31:16]
+ RegDA0[31:16]
+ RegDA4[15:0]
+ RegDA4[31:16]
+ RegDA8[15:0]
+ CCK FA
+ (RegA5B<<8) | RegA5C
+ */
+ cckok = read_bbreg(padapter, 0xf88, 0xffffffff);
+ cckcrc = read_bbreg(padapter, 0xf84, 0xffffffff);
+ ofdmok = read_bbreg(padapter, 0xf94, 0x0000FFFF);
+ ofdmcrc = read_bbreg(padapter, 0xf94, 0xFFFF0000);
+ htok = read_bbreg(padapter, 0xf90, 0x0000FFFF);
+ htcrc = read_bbreg(padapter, 0xf90, 0xFFFF0000);
+
+ OFDM_FA = read_bbreg(padapter, 0xcf0, 0x0000FFFF);
+ OFDM_FA = read_bbreg(padapter, 0xcf2, 0xFFFF0000);
+ OFDM_FA = read_bbreg(padapter, 0xda0, 0xFFFF0000);
+ OFDM_FA = read_bbreg(padapter, 0xda4, 0x0000FFFF);
+ OFDM_FA = read_bbreg(padapter, 0xda4, 0xFFFF0000);
+ OFDM_FA = read_bbreg(padapter, 0xda8, 0x0000FFFF);
+ CCK_FA = (rtw_read8(padapter, 0xa5b)<<8) | (rtw_read8(padapter, 0xa5c));
+
+ sprintf(extra, "Phy Received packet OK:%d CRC error:%d FA Counter: %d", cckok+ofdmok+htok, cckcrc+ofdmcrc+htcrc, OFDM_FA+CCK_FA);
+ }
+ wrqu->length = strlen(extra) + 1;
+ kfree(input);
+ return 0;
+}
+
+static int rtw_mp_trx_query(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 txok, txfail, rxok, rxfail;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ txok = padapter->mppriv.tx.sended;
+ txfail = 0;
+ rxok = padapter->mppriv.rx_pktcount;
+ rxfail = padapter->mppriv.rx_crcerrpktcount;
+
+ _rtw_memset(extra, '\0', 128);
+
+ sprintf(extra, "Tx OK:%d, Tx Fail:%d, Rx OK:%d, CRC error:%d ", txok, txfail, rxok, rxfail);
+
+ wrqu->length = strlen(extra)+1;
+
+ return 0;
+}
+
+static int rtw_mp_pwrtrk(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u8 enable;
+ u32 thermal;
+ s32 ret;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+ _rtw_memset(extra, 0, wrqu->length);
+
+ enable = 1;
+ if (wrqu->length > 1) {/* not empty string */
+ if (strncmp(input, "stop", 4) == 0) {
+ enable = 0;
+ sprintf(extra, "mp tx power tracking stop");
+ } else if (sscanf(input, "ther =%d", &thermal)) {
+ ret = Hal_SetThermalMeter(padapter, (u8)thermal);
+ if (ret == _FAIL)
+ return -EPERM;
+ sprintf(extra, "mp tx power tracking start, target value =%d ok ", thermal);
+ } else {
+ kfree(input);
+ return -EINVAL;
+ }
+ }
+
+ kfree(input);
+ ret = Hal_SetPowerTracking(padapter, enable);
+ if (ret == _FAIL)
+ return -EPERM;
+
+ wrqu->length = strlen(extra);
+ return 0;
+}
+
+static int rtw_mp_psd(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+
+ strcpy(extra, input);
+
+ wrqu->length = mp_query_psd(padapter, extra);
+ kfree(input);
+ return 0;
+}
+
+static int rtw_mp_thermal(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u8 val;
+ u16 bwrite = 1;
+ u16 addr = EEPROM_THERMAL_METER_88E;
+
+ u16 cnt = 1;
+ u16 max_available_size = 0;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (copy_from_user(extra, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ bwrite = strncmp(extra, "write", 6); /* strncmp true is 0 */
+
+ Hal_GetThermalMeter(padapter, &val);
+
+ if (bwrite == 0) {
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+ if (2 > max_available_size) {
+ DBG_88E("no available efuse!\n");
+ return -EFAULT;
+ }
+ if (rtw_efuse_map_write(padapter, addr, cnt, &val) == _FAIL) {
+ DBG_88E("rtw_efuse_map_write error\n");
+ return -EFAULT;
+ } else {
+ sprintf(extra, " efuse write ok :%d", val);
+ }
+ } else {
+ sprintf(extra, "%d", val);
+ }
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+static int rtw_mp_reset_stats(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ struct mp_priv *pmp_priv;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ pmp_priv = &padapter->mppriv;
+
+ pmp_priv->tx.sended = 0;
+ pmp_priv->tx_pktcount = 0;
+ pmp_priv->rx_pktcount = 0;
+ pmp_priv->rx_crcerrpktcount = 0;
+
+ /* reset phy counter */
+ write_bbreg(padapter, 0xf14, BIT16, 0x1);
+ rtw_msleep_os(10);
+ write_bbreg(padapter, 0xf14, BIT16, 0x0);
+
+ return 0;
+}
+
+static int rtw_mp_dump(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 value;
+ u8 rf_type, path_nums = 0;
+ u32 i, j = 1, path;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (strncmp(extra, "all", 4) == 0) {
+ DBG_88E("\n ======= MAC REG =======\n");
+ for (i = 0x0; i < 0x300; i += 4) {
+ if (j%4 == 1)
+ DBG_88E("0x%02x", i);
+ DBG_88E(" 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ DBG_88E("\n");
+ }
+ for (i = 0x400; i < 0x1000; i += 4) {
+ if (j%4 == 1)
+ DBG_88E("0x%02x", i);
+ DBG_88E(" 0x%08x ", rtw_read32(padapter, i));
+ if ((j++)%4 == 0)
+ DBG_88E("\n");
+ }
+
+ j = 1;
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+ DBG_88E("\n ======= RF REG =======\n");
+ if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type))
+ path_nums = 1;
+ else
+ path_nums = 2;
+
+ for (path = 0; path < path_nums; path++) {
+ for (i = 0; i < 0x34; i++) {
+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+ if (j%4 == 1)
+ DBG_88E("0x%02x ", i);
+ DBG_88E(" 0x%08x ", value);
+ if ((j++)%4 == 0)
+ DBG_88E("\n");
+ }
+ }
+ }
+ return 0;
+}
+
+static int rtw_mp_phypara(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ char *input = kmalloc(wrqu->length, GFP_KERNEL);
+ u32 valxcap;
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ kfree(input);
+ return -EFAULT;
+ }
+
+ DBG_88E("%s:iwpriv in =%s\n", __func__, input);
+
+ sscanf(input, "xcap =%d", &valxcap);
+
+ kfree(input);
+ return 0;
+}
+
+static int rtw_mp_SetRFPath(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ char *input = kmalloc(wrqu->data.length, GFP_KERNEL);
+ u8 bMain = 1, bTurnoff = 1;
+
+ if (!input)
+ return -ENOMEM;
+ if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+ DBG_88E("%s:iwpriv in =%s\n", __func__, input);
+
+ bMain = strncmp(input, "1", 2); /* strncmp true is 0 */
+ bTurnoff = strncmp(input, "0", 3); /* strncmp true is 0 */
+
+ if (bMain == 0) {
+ MP_PHY_SetRFPathSwitch(padapter, true);
+ DBG_88E("%s:PHY_SetRFPathSwitch = true\n", __func__);
+ } else if (bTurnoff == 0) {
+ MP_PHY_SetRFPathSwitch(padapter, false);
+ DBG_88E("%s:PHY_SetRFPathSwitch = false\n", __func__);
+ }
+ kfree(input);
+ return 0;
+}
+
+static int rtw_mp_QueryDrv(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ char *input = kmalloc(wrqu->data.length, GFP_KERNEL);
+ u8 qAutoLoad = 1;
+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+
+ if (!input)
+ return -ENOMEM;
+
+ if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+ DBG_88E("%s:iwpriv in =%s\n", __func__, input);
+
+ qAutoLoad = strncmp(input, "autoload", 8); /* strncmp true is 0 */
+
+ if (qAutoLoad == 0) {
+ DBG_88E("%s:qAutoLoad\n", __func__);
+
+ if (pEEPROM->bautoload_fail_flag)
+ sprintf(extra, "fail");
+ else
+ sprintf(extra, "ok");
+ }
+ wrqu->data.length = strlen(extra) + 1;
+ kfree(input);
+ return 0;
+}
+
+static int rtw_mp_set(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wdata, char *extra)
+{
+ struct iw_point *wrqu = (struct iw_point *)wdata;
+ u32 subcmd = wrqu->flags;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (padapter == NULL)
+ return -ENETDOWN;
+
+ if (extra == NULL) {
+ wrqu->length = 0;
+ return -EIO;
+ }
+
+ switch (subcmd) {
+ case MP_START:
+ DBG_88E("set case mp_start\n");
+ rtw_mp_start(dev, info, wrqu, extra);
+ break;
+ case MP_STOP:
+ DBG_88E("set case mp_stop\n");
+ rtw_mp_stop(dev, info, wrqu, extra);
+ break;
+ case MP_BANDWIDTH:
+ DBG_88E("set case mp_bandwidth\n");
+ rtw_mp_bandwidth(dev, info, wrqu, extra);
+ break;
+ case MP_RESET_STATS:
+ DBG_88E("set case MP_RESET_STATS\n");
+ rtw_mp_reset_stats(dev, info, wrqu, extra);
+ break;
+ case MP_SetRFPathSwh:
+ DBG_88E("set MP_SetRFPathSwitch\n");
+ rtw_mp_SetRFPath(dev, info, wdata, extra);
+ break;
+ case CTA_TEST:
+ DBG_88E("set CTA_TEST\n");
+ rtw_cta_test_start(dev, info, wdata, extra);
+ break;
+ }
+
+ return 0;
+}
+
+static int rtw_mp_get(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wdata, char *extra)
+{
+ struct iw_point *wrqu = (struct iw_point *)wdata;
+ u32 subcmd = wrqu->flags;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+
+ if (padapter == NULL)
+ return -ENETDOWN;
+ if (extra == NULL) {
+ wrqu->length = 0;
+ return -EIO;
+ }
+
+ switch (subcmd) {
+ case WRITE_REG:
+ rtw_mp_write_reg(dev, info, wrqu, extra);
+ break;
+ case WRITE_RF:
+ rtw_mp_write_rf(dev, info, wrqu, extra);
+ break;
+ case MP_PHYPARA:
+ DBG_88E("mp_get MP_PHYPARA\n");
+ rtw_mp_phypara(dev, info, wrqu, extra);
+ break;
+ case MP_CHANNEL:
+ DBG_88E("set case mp_channel\n");
+ rtw_mp_channel(dev, info, wrqu, extra);
+ break;
+ case READ_REG:
+ DBG_88E("mp_get READ_REG\n");
+ rtw_mp_read_reg(dev, info, wrqu, extra);
+ break;
+ case READ_RF:
+ DBG_88E("mp_get READ_RF\n");
+ rtw_mp_read_rf(dev, info, wrqu, extra);
+ break;
+ case MP_RATE:
+ DBG_88E("set case mp_rate\n");
+ rtw_mp_rate(dev, info, wrqu, extra);
+ break;
+ case MP_TXPOWER:
+ DBG_88E("set case MP_TXPOWER\n");
+ rtw_mp_txpower(dev, info, wrqu, extra);
+ break;
+ case MP_ANT_TX:
+ DBG_88E("set case MP_ANT_TX\n");
+ rtw_mp_ant_tx(dev, info, wrqu, extra);
+ break;
+ case MP_ANT_RX:
+ DBG_88E("set case MP_ANT_RX\n");
+ rtw_mp_ant_rx(dev, info, wrqu, extra);
+ break;
+ case MP_QUERY:
+ rtw_mp_trx_query(dev, info, wrqu, extra);
+ break;
+ case MP_CTX:
+ DBG_88E("set case MP_CTX\n");
+ rtw_mp_ctx(dev, info, wrqu, extra);
+ break;
+ case MP_ARX:
+ DBG_88E("set case MP_ARX\n");
+ rtw_mp_arx(dev, info, wrqu, extra);
+ break;
+ case EFUSE_GET:
+ DBG_88E("efuse get EFUSE_GET\n");
+ rtw_mp_efuse_get(dev, info, wdata, extra);
+ break;
+ case MP_DUMP:
+ DBG_88E("set case MP_DUMP\n");
+ rtw_mp_dump(dev, info, wrqu, extra);
+ break;
+ case MP_PSD:
+ DBG_88E("set case MP_PSD\n");
+ rtw_mp_psd(dev, info, wrqu, extra);
+ break;
+ case MP_THER:
+ DBG_88E("set case MP_THER\n");
+ rtw_mp_thermal(dev, info, wrqu, extra);
+ break;
+ case MP_QueryDrvStats:
+ DBG_88E("mp_get MP_QueryDrvStats\n");
+ rtw_mp_QueryDrv (dev, info, wdata, extra);
+ break;
+ case MP_PWRTRK:
+ DBG_88E("set case MP_PWRTRK\n");
+ rtw_mp_pwrtrk(dev, info, wrqu, extra);
+ break;
+ case EFUSE_SET:
+ DBG_88E("set case efuse set\n");
+ rtw_mp_efuse_set(dev, info, wdata, extra);
+ break;
+ }
+
+ rtw_msleep_os(10); /* delay 5ms for sending pkt before exit adb shell operation */
+ return 0;
+}
+
+static int rtw_tdls(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ return 0;
+}
+
+static int rtw_tdls_get(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ return 0;
+}
+
+static int rtw_test(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ u32 len;
+ u8 *pbuf, *pch;
+ char *ptmp;
+ u8 *delim = ",";
+
+ DBG_88E("+%s\n", __func__);
+ len = wrqu->data.length;
+
+ pbuf = (u8 *)rtw_zmalloc(len);
+ if (pbuf == NULL) {
+ DBG_88E("%s: no memory!\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(pbuf, wrqu->data.pointer, len)) {
+ kfree(pbuf);
+ DBG_88E("%s: copy from user fail!\n", __func__);
+ return -EFAULT;
+ }
+ DBG_88E("%s: string =\"%s\"\n", __func__, pbuf);
+
+ ptmp = (char *)pbuf;
+ pch = strsep(&ptmp, delim);
+ if ((pch == NULL) || (strlen(pch) == 0)) {
+ kfree(pbuf);
+ DBG_88E("%s: parameter error(level 1)!\n", __func__);
+ return -EFAULT;
+ }
+ kfree(pbuf);
+ return 0;
+}
+
+static iw_handler rtw_handlers[] = {
+ NULL, /* SIOCSIWCOMMIT */
+ rtw_wx_get_name, /* SIOCGIWNAME */
+ dummy, /* SIOCSIWNWID */
+ dummy, /* SIOCGIWNWID */
+ rtw_wx_set_freq, /* SIOCSIWFREQ */
+ rtw_wx_get_freq, /* SIOCGIWFREQ */
+ rtw_wx_set_mode, /* SIOCSIWMODE */
+ rtw_wx_get_mode, /* SIOCGIWMODE */
+ dummy, /* SIOCSIWSENS */
+ rtw_wx_get_sens, /* SIOCGIWSENS */
+ NULL, /* SIOCSIWRANGE */
+ rtw_wx_get_range, /* SIOCGIWRANGE */
+ rtw_wx_set_priv, /* SIOCSIWPRIV */
+ NULL, /* SIOCGIWPRIV */
+ NULL, /* SIOCSIWSTATS */
+ NULL, /* SIOCGIWSTATS */
+ dummy, /* SIOCSIWSPY */
+ dummy, /* SIOCGIWSPY */
+ NULL, /* SIOCGIWTHRSPY */
+ NULL, /* SIOCWIWTHRSPY */
+ rtw_wx_set_wap, /* SIOCSIWAP */
+ rtw_wx_get_wap, /* SIOCGIWAP */
+ rtw_wx_set_mlme, /* request MLME operation; uses struct iw_mlme */
+ dummy, /* SIOCGIWAPLIST -- depricated */
+ rtw_wx_set_scan, /* SIOCSIWSCAN */
+ rtw_wx_get_scan, /* SIOCGIWSCAN */
+ rtw_wx_set_essid, /* SIOCSIWESSID */
+ rtw_wx_get_essid, /* SIOCGIWESSID */
+ dummy, /* SIOCSIWNICKN */
+ rtw_wx_get_nick, /* SIOCGIWNICKN */
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+ rtw_wx_set_rate, /* SIOCSIWRATE */
+ rtw_wx_get_rate, /* SIOCGIWRATE */
+ rtw_wx_set_rts, /* SIOCSIWRTS */
+ rtw_wx_get_rts, /* SIOCGIWRTS */
+ rtw_wx_set_frag, /* SIOCSIWFRAG */
+ rtw_wx_get_frag, /* SIOCGIWFRAG */
+ dummy, /* SIOCSIWTXPOW */
+ dummy, /* SIOCGIWTXPOW */
+ dummy, /* SIOCSIWRETRY */
+ rtw_wx_get_retry, /* SIOCGIWRETRY */
+ rtw_wx_set_enc, /* SIOCSIWENCODE */
+ rtw_wx_get_enc, /* SIOCGIWENCODE */
+ dummy, /* SIOCSIWPOWER */
+ rtw_wx_get_power, /* SIOCGIWPOWER */
+ NULL, /*---hole---*/
+ NULL, /*---hole---*/
+ rtw_wx_set_gen_ie, /* SIOCSIWGENIE */
+ NULL, /* SIOCGWGENIE */
+ rtw_wx_set_auth, /* SIOCSIWAUTH */
+ NULL, /* SIOCGIWAUTH */
+ rtw_wx_set_enc_ext, /* SIOCSIWENCODEEXT */
+ NULL, /* SIOCGIWENCODEEXT */
+ rtw_wx_set_pmkid, /* SIOCSIWPMKSA */
+ NULL, /*---hole---*/
+};
+
+static const struct iw_priv_args rtw_private_args[] = {
+ {
+ SIOCIWFIRSTPRIV + 0x0,
+ IW_PRIV_TYPE_CHAR | 0x7FF, 0, "write"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x1,
+ IW_PRIV_TYPE_CHAR | 0x7FF,
+ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "read"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x4,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x5,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setpid"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x6,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x7,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "get_sensitivity"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x8,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_prob_req_ie"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x9,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_assoc_req_ie"
+ },
+
+ {
+ SIOCIWFIRSTPRIV + 0xA,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "channel_plan"
+ },
+
+ {
+ SIOCIWFIRSTPRIV + 0xB,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "dbg"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0xC,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "rfw"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0xD,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "rfr"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x10,
+ IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, 0, "p2p_set"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x11,
+ IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | P2P_PRIVATE_IOCTL_SET_LEN, "p2p_get"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x12,
+ IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, IW_PRIV_TYPE_CHAR | IFNAMSIZ, "p2p_get2"
+ },
+ {SIOCIWFIRSTPRIV + 0x13, IW_PRIV_TYPE_CHAR | 128, 0, "NULL"},
+ {
+ SIOCIWFIRSTPRIV + 0x14,
+ IW_PRIV_TYPE_CHAR | 64, 0, "tdls"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x15,
+ IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | P2P_PRIVATE_IOCTL_SET_LEN, "tdls_get"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x16,
+ IW_PRIV_TYPE_CHAR | 64, 0, "pm_set"
+ },
+
+ {SIOCIWFIRSTPRIV + 0x18, IW_PRIV_TYPE_CHAR | IFNAMSIZ, 0, "rereg_nd_name"},
+
+ {SIOCIWFIRSTPRIV + 0x1A, IW_PRIV_TYPE_CHAR | 1024, 0, "efuse_set"},
+ {SIOCIWFIRSTPRIV + 0x1B, IW_PRIV_TYPE_CHAR | 128, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get"},
+ {SIOCIWFIRSTPRIV + 0x1D, IW_PRIV_TYPE_CHAR | 40, IW_PRIV_TYPE_CHAR | 0x7FF, "test"
+ },
+
+ {SIOCIWFIRSTPRIV + 0x0E, IW_PRIV_TYPE_CHAR | 1024, 0, ""}, /* set */
+ {SIOCIWFIRSTPRIV + 0x0F, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ""},/* get */
+/* --- sub-ioctls definitions --- */
+
+ {MP_START, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_start"}, /* set */
+ {MP_PHYPARA, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_phypara"},/* get */
+ {MP_STOP, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_stop"}, /* set */
+ {MP_CHANNEL, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_channel"},/* get */
+ {MP_BANDWIDTH, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_bandwidth"}, /* set */
+ {MP_RATE, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate"},/* get */
+ {MP_RESET_STATS, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_reset_stats"},
+ {MP_QUERY, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_query"}, /* get */
+ {READ_REG, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_reg"},
+ {MP_RATE, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate"},
+ {READ_RF, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_rf"},
+ {MP_PSD, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_psd"},
+ {MP_DUMP, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_dump"},
+ {MP_TXPOWER, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_txpower"},
+ {MP_ANT_TX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_tx"},
+ {MP_ANT_RX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_rx"},
+ {WRITE_REG, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "write_reg"},
+ {WRITE_RF, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "write_rf"},
+ {MP_CTX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ctx"},
+ {MP_ARX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_arx"},
+ {MP_THER, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ther"},
+ {EFUSE_SET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_set"},
+ {EFUSE_GET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get"},
+ {MP_PWRTRK, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_pwrtrk"},
+ {MP_QueryDrvStats, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_drvquery"},
+ {MP_IOCTL, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_ioctl"}, /* mp_ioctl */
+ {MP_SetRFPathSwh, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_setrfpath"},
+ {CTA_TEST, IW_PRIV_TYPE_CHAR | 1024, 0, "cta_test"},
+};
+
+static iw_handler rtw_private_handler[] = {
+rtw_wx_write32, /* 0x00 */
+rtw_wx_read32, /* 0x01 */
+rtw_drvext_hdl, /* 0x02 */
+rtw_mp_ioctl_hdl, /* 0x03 */
+
+/* for MM DTV platform */
+ rtw_get_ap_info, /* 0x04 */
+
+ rtw_set_pid, /* 0x05 */
+ rtw_wps_start, /* 0x06 */
+
+ rtw_wx_get_sensitivity, /* 0x07 */
+ rtw_wx_set_mtk_wps_probe_ie, /* 0x08 */
+ rtw_wx_set_mtk_wps_ie, /* 0x09 */
+
+/* Set Channel depend on the country code */
+ rtw_wx_set_channel_plan, /* 0x0A */
+
+ rtw_dbg_port, /* 0x0B */
+ rtw_wx_write_rf, /* 0x0C */
+ rtw_wx_read_rf, /* 0x0D */
+
+ rtw_mp_set, /* 0x0E */
+ rtw_mp_get, /* 0x0F */
+ rtw_p2p_set, /* 0x10 */
+ rtw_p2p_get, /* 0x11 */
+ rtw_p2p_get2, /* 0x12 */
+
+ NULL, /* 0x13 */
+ rtw_tdls, /* 0x14 */
+ rtw_tdls_get, /* 0x15 */
+
+ rtw_pm_set, /* 0x16 */
+ rtw_wx_priv_null, /* 0x17 */
+ rtw_rereg_nd_name, /* 0x18 */
+ rtw_wx_priv_null, /* 0x19 */
+
+ rtw_mp_efuse_set, /* 0x1A */
+ rtw_mp_efuse_get, /* 0x1B */
+ NULL, /* 0x1C is reserved for hostapd */
+ rtw_test, /* 0x1D */
+};
+
+static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct iw_statistics *piwstats = &padapter->iwstats;
+ int tmp_level = 0;
+ int tmp_qual = 0;
+ int tmp_noise = 0;
+
+ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+ piwstats->qual.qual = 0;
+ piwstats->qual.level = 0;
+ piwstats->qual.noise = 0;
+ } else {
+ tmp_level = padapter->recvpriv.signal_strength;
+ tmp_qual = padapter->recvpriv.signal_qual;
+ tmp_noise = padapter->recvpriv.noise;
+
+ piwstats->qual.level = tmp_level;
+ piwstats->qual.qual = tmp_qual;
+ piwstats->qual.noise = tmp_noise;
+ }
+ piwstats->qual.updated = IW_QUAL_ALL_UPDATED;/* IW_QUAL_DBM; */
+ return &padapter->iwstats;
+}
+
+struct iw_handler_def rtw_handlers_def = {
+ .standard = rtw_handlers,
+ .num_standard = sizeof(rtw_handlers) / sizeof(iw_handler),
+ .private = rtw_private_handler,
+ .private_args = (struct iw_priv_args *)rtw_private_args,
+ .num_private = sizeof(rtw_private_handler) / sizeof(iw_handler),
+ .num_private_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args),
+ .get_wireless_stats = rtw_get_wireless_stats,
+};
+
+/* copy from net/wireless/wext.c start */
+/* ---------------------------------------------------------------- */
+/*
+ * Calculate size of private arguments
+ */
+static const char iw_priv_type_size[] = {
+ 0, /* IW_PRIV_TYPE_NONE */
+ 1, /* IW_PRIV_TYPE_BYTE */
+ 1, /* IW_PRIV_TYPE_CHAR */
+ 0, /* Not defined */
+ sizeof(__u32), /* IW_PRIV_TYPE_INT */
+ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
+ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
+ 0, /* Not defined */
+};
+
+static int get_priv_size(__u16 args)
+{
+ int num = args & IW_PRIV_SIZE_MASK;
+ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+ return num * iw_priv_type_size[type];
+}
+/* copy from net/wireless/wext.c end */
+
+static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_data)
+{
+ int err = 0;
+ u8 *input = NULL;
+ u32 input_len = 0;
+ const char delim[] = " ";
+ u8 *output = NULL;
+ u32 output_len = 0;
+ u32 count = 0;
+ u8 *buffer = NULL;
+ u32 buffer_len = 0;
+ char *ptr = NULL;
+ u8 cmdname[17] = {0}; /* IFNAMSIZ+1 */
+ u32 cmdlen;
+ s32 len;
+ u8 *extra = NULL;
+ u32 extra_size = 0;
+
+ s32 k;
+ const iw_handler *priv; /* Private ioctl */
+ const struct iw_priv_args *priv_args; /* Private ioctl description */
+ u32 num_priv_args; /* Number of descriptions */
+ iw_handler handler;
+ int temp;
+ int subcmd = 0; /* sub-ioctl index */
+ int offset = 0; /* Space for sub-ioctl index */
+
+ union iwreq_data wdata;
+
+ memcpy(&wdata, wrq_data, sizeof(wdata));
+
+ input_len = wdata.data.length;
+ input = rtw_zmalloc(input_len);
+ if (NULL == input)
+ return -ENOMEM;
+ if (copy_from_user(input, wdata.data.pointer, input_len)) {
+ err = -EFAULT;
+ goto exit;
+ }
+ ptr = input;
+ len = input_len;
+
+ sscanf(ptr, "%16s", cmdname);
+ cmdlen = strlen(cmdname);
+ DBG_88E("%s: cmd =%s\n", __func__, cmdname);
+
+ /* skip command string */
+ if (cmdlen > 0)
+ cmdlen += 1; /* skip one space */
+ ptr += cmdlen;
+ len -= cmdlen;
+ DBG_88E("%s: parameters =%s\n", __func__, ptr);
+
+ priv = rtw_private_handler;
+ priv_args = rtw_private_args;
+ num_priv_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args);
+
+ if (num_priv_args == 0) {
+ err = -EOPNOTSUPP;
+ goto exit;
+ }
+
+ /* Search the correct ioctl */
+ k = -1;
+ while ((++k < num_priv_args) && strcmp(priv_args[k].name, cmdname));
+
+ /* If not found... */
+ if (k == num_priv_args) {
+ err = -EOPNOTSUPP;
+ goto exit;
+ }
+
+ /* Watch out for sub-ioctls ! */
+ if (priv_args[k].cmd < SIOCDEVPRIVATE) {
+ int j = -1;
+
+ /* Find the matching *real* ioctl */
+ while ((++j < num_priv_args) && ((priv_args[j].name[0] != '\0') ||
+ (priv_args[j].set_args != priv_args[k].set_args) ||
+ (priv_args[j].get_args != priv_args[k].get_args)));
+
+ /* If not found... */
+ if (j == num_priv_args) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* Save sub-ioctl number */
+ subcmd = priv_args[k].cmd;
+ /* Reserve one int (simplify alignment issues) */
+ offset = sizeof(__u32);
+ /* Use real ioctl definition from now on */
+ k = j;
+ }
+
+ buffer = rtw_zmalloc(4096);
+ if (NULL == buffer) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ /* If we have to set some data */
+ if ((priv_args[k].set_args & IW_PRIV_TYPE_MASK) &&
+ (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) {
+ u8 *str;
+
+ switch (priv_args[k].set_args & IW_PRIV_TYPE_MASK) {
+ case IW_PRIV_TYPE_BYTE:
+ /* Fetch args */
+ count = 0;
+ do {
+ str = strsep(&ptr, delim);
+ if (NULL == str)
+ break;
+ sscanf(str, "%i", &temp);
+ buffer[count++] = (u8)temp;
+ } while (1);
+ buffer_len = count;
+ /* Number of args to fetch */
+ wdata.data.length = count;
+ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+ break;
+ case IW_PRIV_TYPE_INT:
+ /* Fetch args */
+ count = 0;
+ do {
+ str = strsep(&ptr, delim);
+ if (NULL == str)
+ break;
+ sscanf(str, "%i", &temp);
+ ((s32 *)buffer)[count++] = (s32)temp;
+ } while (1);
+ buffer_len = count * sizeof(s32);
+ /* Number of args to fetch */
+ wdata.data.length = count;
+ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+ break;
+ case IW_PRIV_TYPE_CHAR:
+ if (len > 0) {
+ /* Size of the string to fetch */
+ wdata.data.length = len;
+ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+
+ /* Fetch string */
+ memcpy(buffer, ptr, wdata.data.length);
+ } else {
+ wdata.data.length = 1;
+ buffer[0] = '\0';
+ }
+ buffer_len = wdata.data.length;
+ break;
+ default:
+ DBG_88E("%s: Not yet implemented...\n", __func__);
+ err = -1;
+ goto exit;
+ }
+
+ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
+ (wdata.data.length != (priv_args[k].set_args & IW_PRIV_SIZE_MASK))) {
+ DBG_88E("%s: The command %s needs exactly %d argument(s)...\n",
+ __func__, cmdname, priv_args[k].set_args & IW_PRIV_SIZE_MASK);
+ err = -EINVAL;
+ goto exit;
+ }
+ } else {
+ /* if args to set */
+ wdata.data.length = 0L;
+ }
+
+ /* Those two tests are important. They define how the driver
+ * will have to handle the data */
+ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
+ ((get_priv_size(priv_args[k].set_args) + offset) <= IFNAMSIZ)) {
+ /* First case : all SET args fit within wrq */
+ if (offset)
+ wdata.mode = subcmd;
+ memcpy(wdata.name + offset, buffer, IFNAMSIZ - offset);
+ } else {
+ if ((priv_args[k].set_args == 0) &&
+ (priv_args[k].get_args & IW_PRIV_SIZE_FIXED) &&
+ (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ)) {
+ /* Second case : no SET args, GET args fit within wrq */
+ if (offset)
+ wdata.mode = subcmd;
+ } else {
+ /* Third case : args won't fit in wrq, or variable number of args */
+ if (copy_to_user(wdata.data.pointer, buffer, buffer_len)) {
+ err = -EFAULT;
+ goto exit;
+ }
+ wdata.data.flags = subcmd;
+ }
+ }
+
+ kfree(input);
+ input = NULL;
+
+ extra_size = 0;
+ if (IW_IS_SET(priv_args[k].cmd)) {
+ /* Size of set arguments */
+ extra_size = get_priv_size(priv_args[k].set_args);
+
+ /* Does it fits in iwr ? */
+ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
+ ((extra_size + offset) <= IFNAMSIZ))
+ extra_size = 0;
+ } else {
+ /* Size of get arguments */
+ extra_size = get_priv_size(priv_args[k].get_args);
+
+ /* Does it fits in iwr ? */
+ if ((priv_args[k].get_args & IW_PRIV_SIZE_FIXED) &&
+ (extra_size <= IFNAMSIZ))
+ extra_size = 0;
+ }
+
+ if (extra_size == 0) {
+ extra = (u8 *)&wdata;
+ kfree(buffer);
+ buffer = NULL;
+ } else {
+ extra = buffer;
+ }
+
+ handler = priv[priv_args[k].cmd - SIOCIWFIRSTPRIV];
+ err = handler(dev, NULL, &wdata, extra);
+
+ /* If we have to get some data */
+ if ((priv_args[k].get_args & IW_PRIV_TYPE_MASK) &&
+ (priv_args[k].get_args & IW_PRIV_SIZE_MASK)) {
+ int j;
+ int n = 0; /* number of args */
+ u8 str[20] = {0};
+
+ /* Check where is the returned data */
+ if ((priv_args[k].get_args & IW_PRIV_SIZE_FIXED) &&
+ (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ))
+ n = priv_args[k].get_args & IW_PRIV_SIZE_MASK;
+ else
+ n = wdata.data.length;
+
+ output = rtw_zmalloc(4096);
+ if (NULL == output) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ switch (priv_args[k].get_args & IW_PRIV_TYPE_MASK) {
+ case IW_PRIV_TYPE_BYTE:
+ /* Display args */
+ for (j = 0; j < n; j++) {
+ sprintf(str, "%d ", extra[j]);
+ len = strlen(str);
+ output_len = strlen(output);
+ if ((output_len + len + 1) > 4096) {
+ err = -E2BIG;
+ goto exit;
+ }
+ memcpy(output+output_len, str, len);
+ }
+ break;
+ case IW_PRIV_TYPE_INT:
+ /* Display args */
+ for (j = 0; j < n; j++) {
+ sprintf(str, "%d ", ((__s32 *)extra)[j]);
+ len = strlen(str);
+ output_len = strlen(output);
+ if ((output_len + len + 1) > 4096) {
+ err = -E2BIG;
+ goto exit;
+ }
+ memcpy(output+output_len, str, len);
+ }
+ break;
+ case IW_PRIV_TYPE_CHAR:
+ /* Display args */
+ memcpy(output, extra, n);
+ break;
+ default:
+ DBG_88E("%s: Not yet implemented...\n", __func__);
+ err = -1;
+ goto exit;
+ }
+
+ output_len = strlen(output) + 1;
+ wrq_data->data.length = output_len;
+ if (copy_to_user(wrq_data->data.pointer, output, output_len)) {
+ err = -EFAULT;
+ goto exit;
+ }
+ } else {
+ /* if args to set */
+ wrq_data->data.length = 0;
+ }
+
+exit:
+ kfree(input);
+ kfree(buffer);
+ kfree(output);
+ return err;
+}
+
+#include <rtw_android.h>
+int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct iwreq *wrq = (struct iwreq *)rq;
+ int ret = 0;
+
+ switch (cmd) {
+ case RTL_IOCTL_WPA_SUPPLICANT:
+ ret = wpa_supplicant_ioctl(dev, &wrq->u.data);
+ break;
+#ifdef CONFIG_88EU_AP_MODE
+ case RTL_IOCTL_HOSTAPD:
+ ret = rtw_hostapd_ioctl(dev, &wrq->u.data);
+ break;
+#endif /* CONFIG_88EU_AP_MODE */
+ case SIOCDEVPRIVATE:
+ ret = rtw_ioctl_wext_private(dev, &wrq->u);
+ break;
+ case (SIOCDEVPRIVATE+1):
+ ret = rtw_android_priv_cmd(dev, rq, cmd);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
new file mode 100644
index 00000000000..57d1ff750d5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
@@ -0,0 +1,246 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+
+#define _MLME_OSDEP_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <mlme_osdep.h>
+
+void rtw_join_timeout_handler (void *FunctionContext)
+{
+ struct adapter *adapter = (struct adapter *)FunctionContext;
+
+ _rtw_join_timeout_handler(adapter);
+}
+
+
+void _rtw_scan_timeout_handler (void *FunctionContext)
+{
+ struct adapter *adapter = (struct adapter *)FunctionContext;
+
+ rtw_scan_timeout_handler(adapter);
+}
+
+static void _dynamic_check_timer_handlder(void *FunctionContext)
+{
+ struct adapter *adapter = (struct adapter *)FunctionContext;
+
+ if (adapter->registrypriv.mp_mode == 1)
+ return;
+ rtw_dynamic_check_timer_handlder(adapter);
+ _set_timer(&adapter->mlmepriv.dynamic_chk_timer, 2000);
+}
+
+void rtw_init_mlme_timer(struct adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ _init_timer(&(pmlmepriv->assoc_timer), padapter->pnetdev, rtw_join_timeout_handler, padapter);
+ _init_timer(&(pmlmepriv->scan_to_timer), padapter->pnetdev, _rtw_scan_timeout_handler, padapter);
+ _init_timer(&(pmlmepriv->dynamic_chk_timer), padapter->pnetdev, _dynamic_check_timer_handlder, padapter);
+}
+
+void rtw_os_indicate_connect(struct adapter *adapter)
+{
+_func_enter_;
+ rtw_indicate_wx_assoc_event(adapter);
+ netif_carrier_on(adapter->pnetdev);
+ if (adapter->pid[2] != 0)
+ rtw_signal_process(adapter->pid[2], SIGALRM);
+_func_exit_;
+}
+
+void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted)
+{
+ indicate_wx_scan_complete_event(padapter);
+}
+
+static struct rt_pmkid_list backup_pmkid[NUM_PMKID_CACHE];
+
+void rtw_reset_securitypriv(struct adapter *adapter)
+{
+ u8 backup_index = 0;
+ u8 backup_counter = 0x00;
+ u32 backup_time = 0;
+
+ if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+ /* 802.1x */
+ /* We have to backup the PMK information for WiFi PMK Caching test item. */
+ /* Backup the btkip_countermeasure information. */
+ /* When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */
+ _rtw_memset(&backup_pmkid[0], 0x00, sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+ memcpy(&backup_pmkid[0], &adapter->securitypriv.PMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+ backup_index = adapter->securitypriv.PMKIDIndex;
+ backup_counter = adapter->securitypriv.btkip_countermeasure;
+ backup_time = adapter->securitypriv.btkip_countermeasure_time;
+ _rtw_memset((unsigned char *)&adapter->securitypriv, 0, sizeof(struct security_priv));
+
+ /* Restore the PMK information to securitypriv structure for the following connection. */
+ memcpy(&adapter->securitypriv.PMKIDList[0],
+ &backup_pmkid[0],
+ sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+ adapter->securitypriv.PMKIDIndex = backup_index;
+ adapter->securitypriv.btkip_countermeasure = backup_counter;
+ adapter->securitypriv.btkip_countermeasure_time = backup_time;
+ adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+ adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+ } else {
+ /* reset values in securitypriv */
+ struct security_priv *psec_priv = &adapter->securitypriv;
+
+ psec_priv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ psec_priv->dot11PrivacyKeyIndex = 0;
+ psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+ psec_priv->dot118021XGrpKeyid = 1;
+ psec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
+ psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
+ }
+}
+
+void rtw_os_indicate_disconnect(struct adapter *adapter)
+{
+_func_enter_;
+ netif_carrier_off(adapter->pnetdev); /* Do it first for tx broadcast pkt after disconnection issue! */
+ rtw_indicate_wx_disassoc_event(adapter);
+ rtw_reset_securitypriv(adapter);
+_func_exit_;
+}
+
+void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
+{
+ uint len;
+ u8 *buff, *p, i;
+ union iwreq_data wrqu;
+
+_func_enter_;
+ RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
+ ("+rtw_report_sec_ie, authmode=%d\n", authmode));
+ buff = NULL;
+ if (authmode == _WPA_IE_ID_) {
+ RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
+ ("rtw_report_sec_ie, authmode=%d\n", authmode));
+ buff = rtw_malloc(IW_CUSTOM_MAX);
+ if (!buff)
+ goto exit;
+ _rtw_memset(buff, 0, IW_CUSTOM_MAX);
+ p = buff;
+ p += sprintf(p, "ASSOCINFO(ReqIEs =");
+ len = sec_ie[1]+2;
+ len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX;
+ for (i = 0; i < len; i++)
+ p += sprintf(p, "%02x", sec_ie[i]);
+ p += sprintf(p, ")");
+ _rtw_memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = p-buff;
+ wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ?
+ wrqu.data.length : IW_CUSTOM_MAX;
+ wireless_send_event(adapter->pnetdev, IWEVCUSTOM, &wrqu, buff);
+ kfree(buff);
+ }
+exit:
+_func_exit_;
+}
+
+static void _survey_timer_hdl(void *FunctionContext)
+{
+ struct adapter *padapter = (struct adapter *)FunctionContext;
+
+ survey_timer_hdl(padapter);
+}
+
+static void _link_timer_hdl(void *FunctionContext)
+{
+ struct adapter *padapter = (struct adapter *)FunctionContext;
+ link_timer_hdl(padapter);
+}
+
+static void _addba_timer_hdl(void *FunctionContext)
+{
+ struct sta_info *psta = (struct sta_info *)FunctionContext;
+ addba_timer_hdl(psta);
+}
+
+void init_addba_retry_timer(struct adapter *padapter, struct sta_info *psta)
+{
+ _init_timer(&psta->addba_retry_timer, padapter->pnetdev, _addba_timer_hdl, psta);
+}
+
+void init_mlme_ext_timer(struct adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ _init_timer(&pmlmeext->survey_timer, padapter->pnetdev, _survey_timer_hdl, padapter);
+ _init_timer(&pmlmeext->link_timer, padapter->pnetdev, _link_timer_hdl, padapter);
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+void rtw_indicate_sta_assoc_event(struct adapter *padapter, struct sta_info *psta)
+{
+ union iwreq_data wrqu;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ if (psta == NULL)
+ return;
+
+ if (psta->aid > NUM_STA)
+ return;
+
+ if (pstapriv->sta_aid[psta->aid - 1] != psta)
+ return;
+
+
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+
+ memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
+
+ DBG_88E("+rtw_indicate_sta_assoc_event\n");
+
+ wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL);
+}
+
+void rtw_indicate_sta_disassoc_event(struct adapter *padapter, struct sta_info *psta)
+{
+ union iwreq_data wrqu;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ if (psta == NULL)
+ return;
+
+ if (psta->aid > NUM_STA)
+ return;
+
+ if (pstapriv->sta_aid[psta->aid - 1] != psta)
+ return;
+
+
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+
+ memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
+
+ DBG_88E("+rtw_indicate_sta_disassoc_event\n");
+
+ wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL);
+}
+
+#endif
diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
new file mode 100644
index 00000000000..63bc913eba6
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
@@ -0,0 +1,1251 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _OS_INTFS_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <xmit_osdep.h>
+#include <recv_osdep.h>
+#include <hal_intf.h>
+#include <rtw_ioctl.h>
+#include <rtw_version.h>
+
+#include <usb_osintf.h>
+#include <usb_hal.h>
+#include <rtw_br_ext.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek Wireless Lan Driver");
+MODULE_AUTHOR("Realtek Semiconductor Corp.");
+MODULE_VERSION(DRIVERVERSION);
+
+#define CONFIG_BR_EXT_BRNAME "br0"
+#define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */
+
+/* module param defaults */
+static int rtw_chip_version = 0x00;
+static int rtw_rfintfs = HWPI;
+static int rtw_lbkmode;/* RTL8712_AIR_TRX; */
+static int rtw_network_mode = Ndis802_11IBSS;/* Ndis802_11Infrastructure; infra, ad-hoc, auto */
+static int rtw_channel = 1;/* ad-hoc support requirement */
+static int rtw_wireless_mode = WIRELESS_11BG_24N;
+static int rtw_vrtl_carrier_sense = AUTO_VCS;
+static int rtw_vcs_type = RTS_CTS;/* */
+static int rtw_rts_thresh = 2347;/* */
+static int rtw_frag_thresh = 2346;/* */
+static int rtw_preamble = PREAMBLE_LONG;/* long, short, auto */
+static int rtw_scan_mode = 1;/* active, passive */
+static int rtw_adhoc_tx_pwr = 1;
+static int rtw_soft_ap;
+static int rtw_power_mgnt = 1;
+static int rtw_ips_mode = IPS_NORMAL;
+
+static int rtw_smart_ps = 2;
+
+module_param(rtw_ips_mode, int, 0644);
+MODULE_PARM_DESC(rtw_ips_mode, "The default IPS mode");
+
+static int rtw_debug = 1;
+static int rtw_radio_enable = 1;
+static int rtw_long_retry_lmt = 7;
+static int rtw_short_retry_lmt = 7;
+static int rtw_busy_thresh = 40;
+static int rtw_ack_policy = NORMAL_ACK;
+
+static int rtw_mp_mode;
+
+static int rtw_software_encrypt;
+static int rtw_software_decrypt;
+
+static int rtw_acm_method;/* 0:By SW 1:By HW. */
+
+static int rtw_wmm_enable = 1;/* default is set to enable the wmm. */
+static int rtw_uapsd_enable;
+static int rtw_uapsd_max_sp = NO_LIMIT;
+static int rtw_uapsd_acbk_en;
+static int rtw_uapsd_acbe_en;
+static int rtw_uapsd_acvi_en;
+static int rtw_uapsd_acvo_en;
+
+int rtw_ht_enable = 1;
+int rtw_cbw40_enable = 3; /* 0 :diable, bit(0): enable 2.4g, bit(1): enable 5g */
+int rtw_ampdu_enable = 1;/* for enable tx_ampdu */
+static int rtw_rx_stbc = 1;/* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */
+static int rtw_ampdu_amsdu;/* 0: disabled, 1:enabled, 2:auto */
+
+static int rtw_lowrate_two_xmit = 1;/* Use 2 path Tx to transmit MCS0~7 and legacy mode */
+
+static int rtw_rf_config = RF_819X_MAX_TYPE; /* auto */
+static int rtw_low_power;
+static int rtw_wifi_spec;
+static int rtw_channel_plan = RT_CHANNEL_DOMAIN_MAX;
+static int rtw_AcceptAddbaReq = true;/* 0:Reject AP's Add BA req, 1:Accept AP's Add BA req. */
+
+static int rtw_antdiv_cfg = 2; /* 0:OFF , 1:ON, 2:decide by Efuse config */
+static int rtw_antdiv_type; /* 0:decide by efuse 1: for 88EE, 1Tx and 1RxCG are diversity.(2 Ant with SPDT), 2: for 88EE, 1Tx and 2Rx are diversity.(2 Ant, Tx and RxCG are both on aux port, RxCS is on main port), 3: for 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */
+
+static int rtw_enusbss;/* 0:disable, 1:enable */
+
+static int rtw_hwpdn_mode = 2;/* 0:disable, 1:enable, 2: by EFUSE config */
+
+static int rtw_hwpwrp_detect; /* HW power ping detect 0:disable , 1:enable */
+
+static int rtw_hw_wps_pbc = 1;
+
+int rtw_mc2u_disable;
+
+static int rtw_80211d;
+
+static char *ifname = "wlan%d";
+module_param(ifname, charp, 0644);
+MODULE_PARM_DESC(ifname, "The default name to allocate for first interface");
+
+static char *if2name = "wlan%d";
+module_param(if2name, charp, 0644);
+MODULE_PARM_DESC(if2name, "The default name to allocate for second interface");
+
+char *rtw_initmac; /* temp mac address if users want to use instead of the mac address in Efuse */
+
+module_param(rtw_initmac, charp, 0644);
+module_param(rtw_channel_plan, int, 0644);
+module_param(rtw_chip_version, int, 0644);
+module_param(rtw_rfintfs, int, 0644);
+module_param(rtw_lbkmode, int, 0644);
+module_param(rtw_network_mode, int, 0644);
+module_param(rtw_channel, int, 0644);
+module_param(rtw_mp_mode, int, 0644);
+module_param(rtw_wmm_enable, int, 0644);
+module_param(rtw_vrtl_carrier_sense, int, 0644);
+module_param(rtw_vcs_type, int, 0644);
+module_param(rtw_busy_thresh, int, 0644);
+module_param(rtw_ht_enable, int, 0644);
+module_param(rtw_cbw40_enable, int, 0644);
+module_param(rtw_ampdu_enable, int, 0644);
+module_param(rtw_rx_stbc, int, 0644);
+module_param(rtw_ampdu_amsdu, int, 0644);
+module_param(rtw_lowrate_two_xmit, int, 0644);
+module_param(rtw_rf_config, int, 0644);
+module_param(rtw_power_mgnt, int, 0644);
+module_param(rtw_smart_ps, int, 0644);
+module_param(rtw_low_power, int, 0644);
+module_param(rtw_wifi_spec, int, 0644);
+module_param(rtw_antdiv_cfg, int, 0644);
+module_param(rtw_antdiv_type, int, 0644);
+module_param(rtw_enusbss, int, 0644);
+module_param(rtw_hwpdn_mode, int, 0644);
+module_param(rtw_hwpwrp_detect, int, 0644);
+module_param(rtw_hw_wps_pbc, int, 0644);
+
+static uint rtw_max_roaming_times = 2;
+module_param(rtw_max_roaming_times, uint, 0644);
+MODULE_PARM_DESC(rtw_max_roaming_times, "The max roaming times to try");
+
+static int rtw_fw_iol = 1;/* 0:Disable, 1:enable, 2:by usb speed */
+module_param(rtw_fw_iol, int, 0644);
+MODULE_PARM_DESC(rtw_fw_iol, "FW IOL");
+
+module_param(rtw_mc2u_disable, int, 0644);
+
+module_param(rtw_80211d, int, 0644);
+MODULE_PARM_DESC(rtw_80211d, "Enable 802.11d mechanism");
+
+static uint rtw_notch_filter = RTW_NOTCH_FILTER;
+module_param(rtw_notch_filter, uint, 0644);
+MODULE_PARM_DESC(rtw_notch_filter, "0:Disable, 1:Enable, 2:Enable only for P2P");
+module_param_named(debug, rtw_debug, int, 0444);
+MODULE_PARM_DESC(debug, "Set debug level (1-9) (default 1)");
+
+/* dummy routines */
+void rtw_proc_remove_one(struct net_device *dev)
+{
+}
+
+void rtw_proc_init_one(struct net_device *dev)
+{
+}
+
+#if 0 /* TODO: Convert these to /sys */
+void rtw_proc_init_one(struct net_device *dev)
+{
+ struct proc_dir_entry *dir_dev = NULL;
+ struct proc_dir_entry *entry = NULL;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ u8 rf_type;
+
+ if (rtw_proc == NULL) {
+ memcpy(rtw_proc_name, DRV_NAME, sizeof(DRV_NAME));
+
+ rtw_proc = create_proc_entry(rtw_proc_name, S_IFDIR, init_net.proc_net);
+ if (rtw_proc == NULL) {
+ DBG_88E(KERN_ERR "Unable to create rtw_proc directory\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("ver_info", S_IFREG | S_IRUGO, rtw_proc, proc_get_drv_version, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ }
+
+ if (padapter->dir_dev == NULL) {
+ padapter->dir_dev = create_proc_entry(dev->name,
+ S_IFDIR | S_IRUGO | S_IXUGO,
+ rtw_proc);
+ dir_dev = padapter->dir_dev;
+ if (dir_dev == NULL) {
+ if (rtw_proc_cnt == 0) {
+ if (rtw_proc) {
+ remove_proc_entry(rtw_proc_name, init_net.proc_net);
+ rtw_proc = NULL;
+ }
+ }
+
+ pr_info("Unable to create dir_dev directory\n");
+ return;
+ }
+ } else {
+ return;
+ }
+
+ rtw_proc_cnt++;
+
+ entry = create_proc_read_entry("write_reg", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_write_reg, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ entry->write_proc = proc_set_write_reg;
+
+ entry = create_proc_read_entry("read_reg", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_read_reg, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ entry->write_proc = proc_set_read_reg;
+
+
+ entry = create_proc_read_entry("fwstate", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_fwstate, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("sec_info", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_sec_info, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("mlmext_state", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_mlmext_state, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("qos_option", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_qos_option, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("ht_option", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_ht_option, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("rf_info", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_rf_info, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("ap_info", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_ap_info, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("adapter_state", S_IFREG | S_IRUGO,
+ dir_dev, proc_getstruct adapter_state, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("trx_info", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_trx_info, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("mac_reg_dump1", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_mac_reg_dump1, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("mac_reg_dump2", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_mac_reg_dump2, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("mac_reg_dump3", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_mac_reg_dump3, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("bb_reg_dump1", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_bb_reg_dump1, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("bb_reg_dump2", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_bb_reg_dump2, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("bb_reg_dump3", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_bb_reg_dump3, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("rf_reg_dump1", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_rf_reg_dump1, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("rf_reg_dump2", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_rf_reg_dump2, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+ if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type)) {
+ entry = create_proc_read_entry("rf_reg_dump3", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_rf_reg_dump3, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("rf_reg_dump4", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_rf_reg_dump4, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ }
+
+#ifdef CONFIG_88EU_AP_MODE
+
+ entry = create_proc_read_entry("all_sta_info", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_all_sta_info, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+#endif
+
+ entry = create_proc_read_entry("best_channel", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_best_channel, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+
+ entry = create_proc_read_entry("rx_signal", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_rx_signal, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ entry->write_proc = proc_set_rx_signal;
+ entry = create_proc_read_entry("ht_enable", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_ht_enable, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ entry->write_proc = proc_set_ht_enable;
+
+ entry = create_proc_read_entry("cbw40_enable", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_cbw40_enable, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ entry->write_proc = proc_set_cbw40_enable;
+
+ entry = create_proc_read_entry("ampdu_enable", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_ampdu_enable, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ entry->write_proc = proc_set_ampdu_enable;
+
+ entry = create_proc_read_entry("rx_stbc", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_rx_stbc, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ entry->write_proc = proc_set_rx_stbc;
+
+ entry = create_proc_read_entry("path_rssi", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_two_path_rssi, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ entry = create_proc_read_entry("rssi_disp", S_IFREG | S_IRUGO,
+ dir_dev, proc_get_rssi_disp, dev);
+ if (!entry) {
+ pr_info("Unable to create_proc_read_entry!\n");
+ return;
+ }
+ entry->write_proc = proc_set_rssi_disp;
+}
+
+void rtw_proc_remove_one(struct net_device *dev)
+{
+ struct proc_dir_entry *dir_dev = NULL;
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ u8 rf_type;
+
+ dir_dev = padapter->dir_dev;
+ padapter->dir_dev = NULL;
+
+ if (dir_dev) {
+ remove_proc_entry("write_reg", dir_dev);
+ remove_proc_entry("read_reg", dir_dev);
+ remove_proc_entry("fwstate", dir_dev);
+ remove_proc_entry("sec_info", dir_dev);
+ remove_proc_entry("mlmext_state", dir_dev);
+ remove_proc_entry("qos_option", dir_dev);
+ remove_proc_entry("ht_option", dir_dev);
+ remove_proc_entry("rf_info", dir_dev);
+ remove_proc_entry("ap_info", dir_dev);
+ remove_proc_entry("adapter_state", dir_dev);
+ remove_proc_entry("trx_info", dir_dev);
+ remove_proc_entry("mac_reg_dump1", dir_dev);
+ remove_proc_entry("mac_reg_dump2", dir_dev);
+ remove_proc_entry("mac_reg_dump3", dir_dev);
+ remove_proc_entry("bb_reg_dump1", dir_dev);
+ remove_proc_entry("bb_reg_dump2", dir_dev);
+ remove_proc_entry("bb_reg_dump3", dir_dev);
+ remove_proc_entry("rf_reg_dump1", dir_dev);
+ remove_proc_entry("rf_reg_dump2", dir_dev);
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+ if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type)) {
+ remove_proc_entry("rf_reg_dump3", dir_dev);
+ remove_proc_entry("rf_reg_dump4", dir_dev);
+ }
+#ifdef CONFIG_88EU_AP_MODE
+ remove_proc_entry("all_sta_info", dir_dev);
+#endif
+
+ remove_proc_entry("best_channel", dir_dev);
+ remove_proc_entry("rx_signal", dir_dev);
+ remove_proc_entry("cbw40_enable", dir_dev);
+ remove_proc_entry("ht_enable", dir_dev);
+ remove_proc_entry("ampdu_enable", dir_dev);
+ remove_proc_entry("rx_stbc", dir_dev);
+ remove_proc_entry("path_rssi", dir_dev);
+ remove_proc_entry("rssi_disp", dir_dev);
+ remove_proc_entry(dev->name, rtw_proc);
+ dir_dev = NULL;
+ } else {
+ return;
+ }
+ rtw_proc_cnt--;
+
+ if (rtw_proc_cnt == 0) {
+ if (rtw_proc) {
+ remove_proc_entry("ver_info", rtw_proc);
+
+ remove_proc_entry(rtw_proc_name, init_net.proc_net);
+ rtw_proc = NULL;
+ }
+ }
+}
+#endif
+
+static uint loadparam(struct adapter *padapter, struct net_device *pnetdev)
+{
+ uint status = _SUCCESS;
+ struct registry_priv *registry_par = &padapter->registrypriv;
+
+_func_enter_;
+
+ GlobalDebugLevel = rtw_debug;
+ registry_par->chip_version = (u8)rtw_chip_version;
+ registry_par->rfintfs = (u8)rtw_rfintfs;
+ registry_par->lbkmode = (u8)rtw_lbkmode;
+ registry_par->network_mode = (u8)rtw_network_mode;
+
+ memcpy(registry_par->ssid.Ssid, "ANY", 3);
+ registry_par->ssid.SsidLength = 3;
+
+ registry_par->channel = (u8)rtw_channel;
+ registry_par->wireless_mode = (u8)rtw_wireless_mode;
+ registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense ;
+ registry_par->vcs_type = (u8)rtw_vcs_type;
+ registry_par->rts_thresh = (u16)rtw_rts_thresh;
+ registry_par->frag_thresh = (u16)rtw_frag_thresh;
+ registry_par->preamble = (u8)rtw_preamble;
+ registry_par->scan_mode = (u8)rtw_scan_mode;
+ registry_par->adhoc_tx_pwr = (u8)rtw_adhoc_tx_pwr;
+ registry_par->soft_ap = (u8)rtw_soft_ap;
+ registry_par->smart_ps = (u8)rtw_smart_ps;
+ registry_par->power_mgnt = (u8)rtw_power_mgnt;
+ registry_par->ips_mode = (u8)rtw_ips_mode;
+ registry_par->radio_enable = (u8)rtw_radio_enable;
+ registry_par->long_retry_lmt = (u8)rtw_long_retry_lmt;
+ registry_par->short_retry_lmt = (u8)rtw_short_retry_lmt;
+ registry_par->busy_thresh = (u16)rtw_busy_thresh;
+ registry_par->ack_policy = (u8)rtw_ack_policy;
+ registry_par->mp_mode = (u8)rtw_mp_mode;
+ registry_par->software_encrypt = (u8)rtw_software_encrypt;
+ registry_par->software_decrypt = (u8)rtw_software_decrypt;
+ registry_par->acm_method = (u8)rtw_acm_method;
+
+ /* UAPSD */
+ registry_par->wmm_enable = (u8)rtw_wmm_enable;
+ registry_par->uapsd_enable = (u8)rtw_uapsd_enable;
+ registry_par->uapsd_max_sp = (u8)rtw_uapsd_max_sp;
+ registry_par->uapsd_acbk_en = (u8)rtw_uapsd_acbk_en;
+ registry_par->uapsd_acbe_en = (u8)rtw_uapsd_acbe_en;
+ registry_par->uapsd_acvi_en = (u8)rtw_uapsd_acvi_en;
+ registry_par->uapsd_acvo_en = (u8)rtw_uapsd_acvo_en;
+
+ registry_par->ht_enable = (u8)rtw_ht_enable;
+ registry_par->cbw40_enable = (u8)rtw_cbw40_enable;
+ registry_par->ampdu_enable = (u8)rtw_ampdu_enable;
+ registry_par->rx_stbc = (u8)rtw_rx_stbc;
+ registry_par->ampdu_amsdu = (u8)rtw_ampdu_amsdu;
+ registry_par->lowrate_two_xmit = (u8)rtw_lowrate_two_xmit;
+ registry_par->rf_config = (u8)rtw_rf_config;
+ registry_par->low_power = (u8)rtw_low_power;
+ registry_par->wifi_spec = (u8)rtw_wifi_spec;
+ registry_par->channel_plan = (u8)rtw_channel_plan;
+ registry_par->bAcceptAddbaReq = (u8)rtw_AcceptAddbaReq;
+ registry_par->antdiv_cfg = (u8)rtw_antdiv_cfg;
+ registry_par->antdiv_type = (u8)rtw_antdiv_type;
+ registry_par->hwpdn_mode = (u8)rtw_hwpdn_mode;/* 0:disable, 1:enable, 2:by EFUSE config */
+ registry_par->hwpwrp_detect = (u8)rtw_hwpwrp_detect;/* 0:disable, 1:enable */
+ registry_par->hw_wps_pbc = (u8)rtw_hw_wps_pbc;
+
+ registry_par->max_roaming_times = (u8)rtw_max_roaming_times;
+
+ registry_par->fw_iol = rtw_fw_iol;
+
+ registry_par->enable80211d = (u8)rtw_80211d;
+ snprintf(registry_par->ifname, 16, "%s", ifname);
+ snprintf(registry_par->if2name, 16, "%s", if2name);
+ registry_par->notch_filter = (u8)rtw_notch_filter;
+_func_exit_;
+ return status;
+}
+
+static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+ struct sockaddr *addr = p;
+
+ if (!padapter->bup)
+ memcpy(padapter->eeprompriv.mac_addr, addr->sa_data, ETH_ALEN);
+
+ return 0;
+}
+
+static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct recv_priv *precvpriv = &(padapter->recvpriv);
+
+ padapter->stats.tx_packets = pxmitpriv->tx_pkts;/* pxmitpriv->tx_pkts++; */
+ padapter->stats.rx_packets = precvpriv->rx_pkts;/* precvpriv->rx_pkts++; */
+ padapter->stats.tx_dropped = pxmitpriv->tx_drop;
+ padapter->stats.rx_dropped = precvpriv->rx_drop;
+ padapter->stats.tx_bytes = pxmitpriv->tx_bytes;
+ padapter->stats.rx_bytes = precvpriv->rx_bytes;
+ return &padapter->stats;
+}
+
+/*
+ * AC to queue mapping
+ *
+ * AC_VO -> queue 0
+ * AC_VI -> queue 1
+ * AC_BE -> queue 2
+ * AC_BK -> queue 3
+ */
+static const u16 rtw_1d_to_queue[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
+
+/* Given a data frame determine the 802.1p/1d tag to use. */
+static unsigned int rtw_classify8021d(struct sk_buff *skb)
+{
+ unsigned int dscp;
+
+ /* skb->priority values from 256->263 are magic values to
+ * directly indicate a specific 802.1d priority. This is used
+ * to allow 802.1d priority to be passed directly in from VLAN
+ * tags, etc.
+ */
+ if (skb->priority >= 256 && skb->priority <= 263)
+ return skb->priority - 256;
+
+ switch (skb->protocol) {
+ case htons(ETH_P_IP):
+ dscp = ip_hdr(skb)->tos & 0xfc;
+ break;
+ default:
+ return 0;
+ }
+
+ return dscp >> 5;
+}
+
+static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+ struct adapter *padapter = rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ skb->priority = rtw_classify8021d(skb);
+
+ if (pmlmepriv->acm_mask != 0)
+ skb->priority = qos_acm(pmlmepriv->acm_mask, skb->priority);
+
+ return rtw_1d_to_queue[skb->priority];
+}
+
+u16 rtw_recv_select_queue(struct sk_buff *skb)
+{
+ struct iphdr *piphdr;
+ unsigned int dscp;
+ __be16 eth_type;
+ u32 priority;
+ u8 *pdata = skb->data;
+
+ memcpy(&eth_type, pdata+(ETH_ALEN<<1), 2);
+
+ switch (eth_type) {
+ case htons(ETH_P_IP):
+ piphdr = (struct iphdr *)(pdata+ETH_HLEN);
+ dscp = piphdr->tos & 0xfc;
+ priority = dscp >> 5;
+ break;
+ default:
+ priority = 0;
+ }
+
+ return rtw_1d_to_queue[priority];
+}
+
+static const struct net_device_ops rtw_netdev_ops = {
+ .ndo_open = netdev_open,
+ .ndo_stop = netdev_close,
+ .ndo_start_xmit = rtw_xmit_entry,
+ .ndo_select_queue = rtw_select_queue,
+ .ndo_set_mac_address = rtw_net_set_mac_address,
+ .ndo_get_stats = rtw_net_get_stats,
+ .ndo_do_ioctl = rtw_ioctl,
+};
+
+int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname)
+{
+ if (dev_alloc_name(pnetdev, ifname) < 0)
+ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("dev_alloc_name, fail!\n"));
+
+ netif_carrier_off(pnetdev);
+ return 0;
+}
+
+struct net_device *rtw_init_netdev(struct adapter *old_padapter)
+{
+ struct adapter *padapter;
+ struct net_device *pnetdev;
+
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+init_net_dev\n"));
+
+ if (old_padapter != NULL)
+ pnetdev = rtw_alloc_etherdev_with_old_priv(sizeof(struct adapter), (void *)old_padapter);
+ else
+ pnetdev = rtw_alloc_etherdev(sizeof(struct adapter));
+
+ if (!pnetdev)
+ return NULL;
+
+ padapter = rtw_netdev_priv(pnetdev);
+ padapter->pnetdev = pnetdev;
+ DBG_88E("register rtw_netdev_ops to netdev_ops\n");
+ pnetdev->netdev_ops = &rtw_netdev_ops;
+ pnetdev->watchdog_timeo = HZ*3; /* 3 second timeout */
+ pnetdev->wireless_handlers = (struct iw_handler_def *)&rtw_handlers_def;
+
+ /* step 2. */
+ loadparam(padapter, pnetdev);
+
+ return pnetdev;
+}
+
+u32 rtw_start_drv_threads(struct adapter *padapter)
+{
+ u32 _status = _SUCCESS;
+
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_start_drv_threads\n"));
+
+ padapter->cmdThread = kthread_run(rtw_cmd_thread, padapter, "RTW_CMD_THREAD");
+ if (IS_ERR(padapter->cmdThread))
+ _status = _FAIL;
+ else
+ _rtw_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema); /* wait for cmd_thread to run */
+
+ rtw_hal_start_thread(padapter);
+ return _status;
+}
+
+void rtw_stop_drv_threads(struct adapter *padapter)
+{
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_stop_drv_threads\n"));
+
+ /* Below is to termindate rtw_cmd_thread & event_thread... */
+ _rtw_up_sema(&padapter->cmdpriv.cmd_queue_sema);
+ if (padapter->cmdThread)
+ _rtw_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema);
+
+ rtw_hal_stop_thread(padapter);
+}
+
+static u8 rtw_init_default_value(struct adapter *padapter)
+{
+ u8 ret = _SUCCESS;
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+ /* xmit_priv */
+ pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense;
+ pxmitpriv->vcs = pregistrypriv->vcs_type;
+ pxmitpriv->vcs_type = pregistrypriv->vcs_type;
+ pxmitpriv->frag_len = pregistrypriv->frag_thresh;
+
+ /* mlme_priv */
+ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */
+ pmlmepriv->scan_mode = SCAN_ACTIVE;
+
+ /* ht_priv */
+ pmlmepriv->htpriv.ampdu_enable = false;/* set to disabled */
+
+ /* security_priv */
+ psecuritypriv->binstallGrpkey = _FAIL;
+ psecuritypriv->sw_encrypt = pregistrypriv->software_encrypt;
+ psecuritypriv->sw_decrypt = pregistrypriv->software_decrypt;
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ psecuritypriv->dot11PrivacyKeyIndex = 0;
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+ psecuritypriv->dot118021XGrpKeyid = 1;
+ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
+ psecuritypriv->ndisencryptstatus = Ndis802_11WEPDisabled;
+
+ /* registry_priv */
+ rtw_init_registrypriv_dev_network(padapter);
+ rtw_update_registrypriv_dev_network(padapter);
+
+ /* hal_priv */
+ rtw_hal_def_value_init(padapter);
+
+ /* misc. */
+ padapter->bReadPortCancel = false;
+ padapter->bWritePortCancel = false;
+ padapter->bRxRSSIDisplay = 0;
+ padapter->bNotifyChannelChange = 0;
+#ifdef CONFIG_88EU_P2P
+ padapter->bShowGetP2PState = 1;
+#endif
+ return ret;
+}
+
+u8 rtw_reset_drv_sw(struct adapter *padapter)
+{
+ u8 ret8 = _SUCCESS;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+ /* hal_priv */
+ rtw_hal_def_value_init(padapter);
+ padapter->bReadPortCancel = false;
+ padapter->bWritePortCancel = false;
+ padapter->bRxRSSIDisplay = 0;
+ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */
+
+ padapter->xmitpriv.tx_pkts = 0;
+ padapter->recvpriv.rx_pkts = 0;
+
+ pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING);
+
+ rtw_hal_sreset_reset_value(padapter);
+ pwrctrlpriv->pwr_state_check_cnts = 0;
+
+ /* mlmeextpriv */
+ padapter->mlmeextpriv.sitesurvey_res.state = SCAN_DISABLE;
+
+ rtw_set_signal_stat_timer(&padapter->recvpriv);
+
+ return ret8;
+}
+
+u8 rtw_init_drv_sw(struct adapter *padapter)
+{
+ u8 ret8 = _SUCCESS;
+
+_func_enter_;
+
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw\n"));
+
+ if ((rtw_init_cmd_priv(&padapter->cmdpriv)) == _FAIL) {
+ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init cmd_priv\n"));
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+ padapter->cmdpriv.padapter = padapter;
+
+ if ((rtw_init_evt_priv(&padapter->evtpriv)) == _FAIL) {
+ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init evt_priv\n"));
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+ if (rtw_init_mlme_priv(padapter) == _FAIL) {
+ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init mlme_priv\n"));
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+#ifdef CONFIG_88EU_P2P
+ rtw_init_wifidirect_timers(padapter);
+ init_wifidirect_info(padapter, P2P_ROLE_DISABLE);
+ reset_global_wifidirect_info(padapter);
+#endif /* CONFIG_88EU_P2P */
+
+ if (init_mlme_ext_priv(padapter) == _FAIL) {
+ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init mlme_ext_priv\n"));
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+ if (_rtw_init_xmit_priv(&padapter->xmitpriv, padapter) == _FAIL) {
+ DBG_88E("Can't _rtw_init_xmit_priv\n");
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+ if (_rtw_init_recv_priv(&padapter->recvpriv, padapter) == _FAIL) {
+ DBG_88E("Can't _rtw_init_recv_priv\n");
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+ if (_rtw_init_sta_priv(&padapter->stapriv) == _FAIL) {
+ DBG_88E("Can't _rtw_init_sta_priv\n");
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+ padapter->stapriv.padapter = padapter;
+
+ rtw_init_bcmc_stainfo(padapter);
+
+ rtw_init_pwrctrl_priv(padapter);
+
+ if (init_mp_priv(padapter) == _FAIL)
+ DBG_88E("%s: initialize MP private data Fail!\n", __func__);
+
+ ret8 = rtw_init_default_value(padapter);
+
+ rtw_hal_dm_init(padapter);
+ rtw_hal_sw_led_init(padapter);
+
+ rtw_hal_sreset_init(padapter);
+
+ _rtw_spinlock_init(&padapter->br_ext_lock);
+
+exit:
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_init_drv_sw\n"));
+
+ _func_exit_;
+
+ return ret8;
+}
+
+void rtw_cancel_all_timer(struct adapter *padapter)
+{
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_cancel_all_timer\n"));
+
+ _cancel_timer_ex(&padapter->mlmepriv.assoc_timer);
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel association timer complete!\n"));
+
+ _cancel_timer_ex(&padapter->mlmepriv.scan_to_timer);
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel scan_to_timer!\n"));
+
+ _cancel_timer_ex(&padapter->mlmepriv.dynamic_chk_timer);
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel dynamic_chk_timer!\n"));
+
+ /* cancel sw led timer */
+ rtw_hal_sw_led_deinit(padapter);
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel DeInitSwLeds!\n"));
+
+ _cancel_timer_ex(&padapter->pwrctrlpriv.pwr_state_check_timer);
+
+ _cancel_timer_ex(&padapter->recvpriv.signal_stat_timer);
+ /* cancel dm timer */
+ rtw_hal_dm_deinit(padapter);
+}
+
+u8 rtw_free_drv_sw(struct adapter *padapter)
+{
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("==>rtw_free_drv_sw"));
+
+ /* we can call rtw_p2p_enable here, but: */
+ /* 1. rtw_p2p_enable may have IO operation */
+ /* 2. rtw_p2p_enable is bundled with wext interface */
+ #ifdef CONFIG_88EU_P2P
+ {
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ _cancel_timer_ex(&pwdinfo->find_phase_timer);
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ _cancel_timer_ex(&pwdinfo->pre_tx_scan_timer);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE);
+ }
+ }
+ #endif
+
+
+ _rtw_spinlock_free(&padapter->br_ext_lock);
+
+ free_mlme_ext_priv(&padapter->mlmeextpriv);
+
+ rtw_free_cmd_priv(&padapter->cmdpriv);
+
+ rtw_free_evt_priv(&padapter->evtpriv);
+
+ rtw_free_mlme_priv(&padapter->mlmepriv);
+ _rtw_free_xmit_priv(&padapter->xmitpriv);
+
+ _rtw_free_sta_priv(&padapter->stapriv); /* will free bcmc_stainfo here */
+
+ _rtw_free_recv_priv(&padapter->recvpriv);
+
+ rtw_free_pwrctrl_priv(padapter);
+
+ rtw_hal_free_data(padapter);
+
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("<== rtw_free_drv_sw\n"));
+
+ /* free the old_pnetdev */
+ if (padapter->rereg_nd_name_priv.old_pnetdev) {
+ free_netdev(padapter->rereg_nd_name_priv.old_pnetdev);
+ padapter->rereg_nd_name_priv.old_pnetdev = NULL;
+ }
+
+ /* clear pbuddystruct adapter to avoid access wrong pointer. */
+ if (padapter->pbuddy_adapter != NULL)
+ padapter->pbuddy_adapter->pbuddy_adapter = NULL;
+
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_free_drv_sw\n"));
+
+ return _SUCCESS;
+}
+
+void netdev_br_init(struct net_device *netdev)
+{
+ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(netdev);
+
+ rcu_read_lock();
+
+ if (rcu_dereference(adapter->pnetdev->rx_handler_data)) {
+ struct net_device *br_netdev;
+ struct net *devnet = NULL;
+
+ devnet = dev_net(netdev);
+ br_netdev = dev_get_by_name(devnet, CONFIG_BR_EXT_BRNAME);
+ if (br_netdev) {
+ memcpy(adapter->br_mac, br_netdev->dev_addr, ETH_ALEN);
+ dev_put(br_netdev);
+ } else {
+ pr_info("%s()-%d: dev_get_by_name(%s) failed!",
+ __func__, __LINE__, CONFIG_BR_EXT_BRNAME);
+ }
+ }
+ adapter->ethBrExtInfo.addPPPoETag = 1;
+
+ rcu_read_unlock();
+}
+
+int _netdev_open(struct net_device *pnetdev)
+{
+ uint status;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+88eu_drv - dev_open\n"));
+ DBG_88E("+88eu_drv - drv_open, bup =%d\n", padapter->bup);
+
+ if (pwrctrlpriv->ps_flag) {
+ padapter->net_closed = false;
+ goto netdev_open_normal_process;
+ }
+
+ if (!padapter->bup) {
+ padapter->bDriverStopped = false;
+ padapter->bSurpriseRemoved = false;
+ padapter->bCardDisableWOHSM = false;
+
+ status = rtw_hal_init(padapter);
+ if (status == _FAIL) {
+ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("rtl88eu_hal_init(): Can't init h/w!\n"));
+ goto netdev_open_error;
+ }
+
+ pr_info("MAC Address = %pM\n", pnetdev->dev_addr);
+
+ status = rtw_start_drv_threads(padapter);
+ if (status == _FAIL) {
+ pr_info("Initialize driver software resource Failed!\n");
+ goto netdev_open_error;
+ }
+
+ if (init_hw_mlme_ext(padapter) == _FAIL) {
+ pr_info("can't init mlme_ext_priv\n");
+ goto netdev_open_error;
+ }
+ if (padapter->intf_start)
+ padapter->intf_start(padapter);
+ rtw_proc_init_one(pnetdev);
+
+ rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+ padapter->bup = true;
+ }
+ padapter->net_closed = false;
+
+ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000);
+
+ padapter->pwrctrlpriv.bips_processing = false;
+ rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+
+ if (!rtw_netif_queue_stopped(pnetdev))
+ rtw_netif_start_queue(pnetdev);
+ else
+ rtw_netif_wake_queue(pnetdev);
+
+ netdev_br_init(pnetdev);
+
+netdev_open_normal_process:
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-88eu_drv - dev_open\n"));
+ DBG_88E("-88eu_drv - drv_open, bup =%d\n", padapter->bup);
+ return 0;
+
+netdev_open_error:
+ padapter->bup = false;
+ netif_carrier_off(pnetdev);
+ rtw_netif_stop_queue(pnetdev);
+ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("-88eu_drv - dev_open, fail!\n"));
+ DBG_88E("-88eu_drv - drv_open fail, bup =%d\n", padapter->bup);
+ return -1;
+}
+
+int netdev_open(struct net_device *pnetdev)
+{
+ int ret;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+
+ _enter_critical_mutex(padapter->hw_init_mutex, NULL);
+ ret = _netdev_open(pnetdev);
+ _exit_critical_mutex(padapter->hw_init_mutex, NULL);
+ return ret;
+}
+
+static int ips_netdrv_open(struct adapter *padapter)
+{
+ int status = _SUCCESS;
+ padapter->net_closed = false;
+ DBG_88E("===> %s.........\n", __func__);
+
+ padapter->bDriverStopped = false;
+ padapter->bSurpriseRemoved = false;
+ padapter->bCardDisableWOHSM = false;
+
+ status = rtw_hal_init(padapter);
+ if (status == _FAIL) {
+ RT_TRACE(_module_os_intfs_c_, _drv_err_, ("ips_netdrv_open(): Can't init h/w!\n"));
+ goto netdev_open_error;
+ }
+
+ if (padapter->intf_start)
+ padapter->intf_start(padapter);
+
+ rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 5000);
+
+ return _SUCCESS;
+
+netdev_open_error:
+ DBG_88E("-ips_netdrv_open - drv_open failure, bup =%d\n", padapter->bup);
+
+ return _FAIL;
+}
+
+
+int rtw_ips_pwr_up(struct adapter *padapter)
+{
+ int result;
+ u32 start_time = rtw_get_current_time();
+ DBG_88E("===> rtw_ips_pwr_up..............\n");
+ rtw_reset_drv_sw(padapter);
+
+ result = ips_netdrv_open(padapter);
+
+ rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+ DBG_88E("<=== rtw_ips_pwr_up.............. in %dms\n", rtw_get_passing_time_ms(start_time));
+ return result;
+}
+
+void rtw_ips_pwr_down(struct adapter *padapter)
+{
+ u32 start_time = rtw_get_current_time();
+ DBG_88E("===> rtw_ips_pwr_down...................\n");
+
+ padapter->bCardDisableWOHSM = true;
+ padapter->net_closed = true;
+
+ rtw_led_control(padapter, LED_CTL_POWER_OFF);
+
+ rtw_ips_dev_unload(padapter);
+ padapter->bCardDisableWOHSM = false;
+ DBG_88E("<=== rtw_ips_pwr_down..................... in %dms\n", rtw_get_passing_time_ms(start_time));
+}
+
+void rtw_ips_dev_unload(struct adapter *padapter)
+{
+ DBG_88E("====> %s...\n", __func__);
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_FIFO_CLEARN_UP, NULL);
+
+ if (padapter->intf_stop)
+ padapter->intf_stop(padapter);
+
+ /* s5. */
+ if (!padapter->bSurpriseRemoved)
+ rtw_hal_deinit(padapter);
+}
+
+int pm_netdev_open(struct net_device *pnetdev, u8 bnormal)
+{
+ int status;
+
+ if (bnormal)
+ status = netdev_open(pnetdev);
+ else
+ status = (_SUCCESS == ips_netdrv_open((struct adapter *)rtw_netdev_priv(pnetdev))) ? (0) : (-1);
+ return status;
+}
+
+int netdev_close(struct net_device *pnetdev)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+88eu_drv - drv_close\n"));
+
+ if (padapter->pwrctrlpriv.bInternalAutoSuspend) {
+ if (padapter->pwrctrlpriv.rf_pwrstate == rf_off)
+ padapter->pwrctrlpriv.ps_flag = true;
+ }
+ padapter->net_closed = true;
+
+ if (padapter->pwrctrlpriv.rf_pwrstate == rf_on) {
+ DBG_88E("(2)88eu_drv - drv_close, bup =%d, hw_init_completed =%d\n",
+ padapter->bup, padapter->hw_init_completed);
+
+ /* s1. */
+ if (pnetdev) {
+ if (!rtw_netif_queue_stopped(pnetdev))
+ rtw_netif_stop_queue(pnetdev);
+ }
+
+ /* s2. */
+ LeaveAllPowerSaveMode(padapter);
+ rtw_disassoc_cmd(padapter, 500, false);
+ /* s2-2. indicate disconnect to os */
+ rtw_indicate_disconnect(padapter);
+ /* s2-3. */
+ rtw_free_assoc_resources(padapter, 1);
+ /* s2-4. */
+ rtw_free_network_queue(padapter, true);
+ /* Close LED */
+ rtw_led_control(padapter, LED_CTL_POWER_OFF);
+ }
+
+ nat25_db_cleanup(padapter);
+
+#ifdef CONFIG_88EU_P2P
+ rtw_p2p_enable(padapter, P2P_ROLE_DISABLE);
+#endif /* CONFIG_88EU_P2P */
+
+ RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-88eu_drv - drv_close\n"));
+ DBG_88E("-88eu_drv - drv_close, bup =%d\n", padapter->bup);
+ return 0;
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/osdep_service.c b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
new file mode 100644
index 00000000000..4e0bfb7e153
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
@@ -0,0 +1,815 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+
+#define _OSDEP_SERVICE_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <linux/vmalloc.h>
+#include <rtw_ioctl_set.h>
+
+/*
+* Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE
+* @return: one of RTW_STATUS_CODE
+*/
+inline int RTW_STATUS_CODE(int error_code)
+{
+ if (error_code >= 0)
+ return _SUCCESS;
+ return _FAIL;
+}
+
+u32 rtw_atoi(u8 *s)
+{
+ int num = 0, flag = 0;
+ int i;
+ for (i = 0; i <= strlen(s); i++) {
+ if (s[i] >= '0' && s[i] <= '9')
+ num = num * 10 + s[i] - '0';
+ else if (s[0] == '-' && i == 0)
+ flag = 1;
+ else
+ break;
+ }
+ if (flag == 1)
+ num = num * -1;
+ return num;
+}
+
+inline u8 *_rtw_vmalloc(u32 sz)
+{
+ u8 *pbuf;
+ pbuf = vmalloc(sz);
+ return pbuf;
+}
+
+inline u8 *_rtw_zvmalloc(u32 sz)
+{
+ u8 *pbuf;
+ pbuf = _rtw_vmalloc(sz);
+ if (pbuf != NULL)
+ memset(pbuf, 0, sz);
+ return pbuf;
+}
+
+inline void _rtw_vmfree(u8 *pbuf, u32 sz)
+{
+ vfree(pbuf);
+}
+
+u8 *_rtw_malloc(u32 sz)
+{
+ u8 *pbuf = NULL;
+
+ pbuf = kmalloc(sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+ return pbuf;
+}
+
+u8 *_rtw_zmalloc(u32 sz)
+{
+ u8 *pbuf = _rtw_malloc(sz);
+
+ if (pbuf != NULL)
+ memset(pbuf, 0, sz);
+ return pbuf;
+}
+
+void *rtw_malloc2d(int h, int w, int size)
+{
+ int j;
+
+ void **a = (void **)rtw_zmalloc(h*sizeof(void *) + h*w*size);
+ if (a == NULL) {
+ pr_info("%s: alloc memory fail!\n", __func__);
+ return NULL;
+ }
+
+ for (j = 0; j < h; j++)
+ a[j] = ((char *)(a+h)) + j*w*size;
+
+ return a;
+}
+
+void rtw_mfree2d(void *pbuf, int h, int w, int size)
+{
+ kfree(pbuf);
+}
+
+int _rtw_memcmp(void *dst, void *src, u32 sz)
+{
+/* under Linux/GNU/GLibc, the return value of memcmp for two same
+ * mem. chunk is 0 */
+ if (!(memcmp(dst, src, sz)))
+ return true;
+ else
+ return false;
+}
+
+void _rtw_memset(void *pbuf, int c, u32 sz)
+{
+ memset(pbuf, c, sz);
+}
+
+void _rtw_init_listhead(struct list_head *list)
+{
+ INIT_LIST_HEAD(list);
+}
+
+/*
+For the following list_xxx operations,
+caller must guarantee the atomic context.
+Otherwise, there will be racing condition.
+*/
+u32 rtw_is_list_empty(struct list_head *phead)
+{
+ if (list_empty(phead))
+ return true;
+ else
+ return false;
+}
+
+void rtw_list_insert_head(struct list_head *plist, struct list_head *phead)
+{
+ list_add(plist, phead);
+}
+
+void rtw_list_insert_tail(struct list_head *plist, struct list_head *phead)
+{
+ list_add_tail(plist, phead);
+}
+
+/*
+Caller must check if the list is empty before calling rtw_list_delete
+*/
+
+void _rtw_init_sema(struct semaphore *sema, int init_val)
+{
+ sema_init(sema, init_val);
+}
+
+void _rtw_free_sema(struct semaphore *sema)
+{
+}
+
+void _rtw_up_sema(struct semaphore *sema)
+{
+ up(sema);
+}
+
+u32 _rtw_down_sema(struct semaphore *sema)
+{
+ if (down_interruptible(sema))
+ return _FAIL;
+ else
+ return _SUCCESS;
+}
+
+void _rtw_mutex_init(struct mutex *pmutex)
+{
+ mutex_init(pmutex);
+}
+
+void _rtw_mutex_free(struct mutex *pmutex)
+{
+ mutex_destroy(pmutex);
+}
+
+void _rtw_spinlock_init(spinlock_t *plock)
+{
+ spin_lock_init(plock);
+}
+
+void _rtw_spinlock_free(spinlock_t *plock)
+{
+}
+
+void _rtw_init_queue(struct __queue *pqueue)
+{
+ _rtw_init_listhead(&(pqueue->queue));
+ _rtw_spinlock_init(&(pqueue->lock));
+}
+
+u32 _rtw_queue_empty(struct __queue *pqueue)
+{
+ return rtw_is_list_empty(&(pqueue->queue));
+}
+
+u32 rtw_end_of_queue_search(struct list_head *head, struct list_head *plist)
+{
+ if (head == plist)
+ return true;
+ else
+ return false;
+}
+
+u32 rtw_get_current_time(void)
+{
+ return jiffies;
+}
+
+inline u32 rtw_systime_to_ms(u32 systime)
+{
+ return systime * 1000 / HZ;
+}
+
+inline u32 rtw_ms_to_systime(u32 ms)
+{
+ return ms * HZ / 1000;
+}
+
+/* the input parameter start use the same unit as returned by
+ * rtw_get_current_time */
+inline s32 rtw_get_passing_time_ms(u32 start)
+{
+ return rtw_systime_to_ms(jiffies-start);
+}
+
+inline s32 rtw_get_time_interval_ms(u32 start, u32 end)
+{
+ return rtw_systime_to_ms(end-start);
+}
+
+void rtw_sleep_schedulable(int ms)
+{
+ u32 delta;
+
+ delta = (ms * HZ)/1000;/* ms) */
+ if (delta == 0)
+ delta = 1;/* 1 ms */
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (schedule_timeout(delta) != 0)
+ return;
+}
+
+void rtw_msleep_os(int ms)
+{
+ msleep((unsigned int)ms);
+}
+
+void rtw_usleep_os(int us)
+{
+ if (1 < (us/1000))
+ msleep(1);
+ else
+ msleep((us/1000) + 1);
+}
+
+void rtw_mdelay_os(int ms)
+{
+ mdelay((unsigned long)ms);
+}
+
+void rtw_udelay_os(int us)
+{
+ udelay((unsigned long)us);
+}
+
+void rtw_yield_os(void)
+{
+ yield();
+}
+
+#define RTW_SUSPEND_LOCK_NAME "rtw_wifi"
+
+inline void rtw_suspend_lock_init(void)
+{
+}
+
+inline void rtw_suspend_lock_uninit(void)
+{
+}
+
+inline void rtw_lock_suspend(void)
+{
+}
+
+inline void rtw_unlock_suspend(void)
+{
+}
+
+inline void ATOMIC_SET(ATOMIC_T *v, int i)
+{
+ atomic_set(v, i);
+}
+
+inline int ATOMIC_READ(ATOMIC_T *v)
+{
+ return atomic_read(v);
+}
+
+inline void ATOMIC_ADD(ATOMIC_T *v, int i)
+{
+ atomic_add(i, v);
+}
+
+inline void ATOMIC_SUB(ATOMIC_T *v, int i)
+{
+ atomic_sub(i, v);
+}
+
+inline void ATOMIC_INC(ATOMIC_T *v)
+{
+ atomic_inc(v);
+}
+
+inline void ATOMIC_DEC(ATOMIC_T *v)
+{
+ atomic_dec(v);
+}
+
+inline int ATOMIC_ADD_RETURN(ATOMIC_T *v, int i)
+{
+ return atomic_add_return(i, v);
+}
+
+inline int ATOMIC_SUB_RETURN(ATOMIC_T *v, int i)
+{
+ return atomic_sub_return(i, v);
+}
+
+inline int ATOMIC_INC_RETURN(ATOMIC_T *v)
+{
+ return atomic_inc_return(v);
+}
+
+inline int ATOMIC_DEC_RETURN(ATOMIC_T *v)
+{
+ return atomic_dec_return(v);
+}
+
+/* Open a file with the specific @param path, @param flag, @param mode
+ * @param fpp the pointer of struct file pointer to get struct file pointer while file opening is success
+ * @param path the path of the file to open
+ * @param flag file operation flags, please refer to linux document
+ * @param mode please refer to linux document
+ * @return Linux specific error code
+ */
+static int openfile(struct file **fpp, char *path, int flag, int mode)
+{
+ struct file *fp;
+
+ fp = filp_open(path, flag, mode);
+ if (IS_ERR(fp)) {
+ *fpp = NULL;
+ return PTR_ERR(fp);
+ } else {
+ *fpp = fp;
+ return 0;
+ }
+}
+
+/* Close the file with the specific @param fp
+ * @param fp the pointer of struct file to close
+ * @return always 0
+ */
+static int closefile(struct file *fp)
+{
+ filp_close(fp, NULL);
+ return 0;
+}
+
+static int readfile(struct file *fp, char __user *buf, int len)
+{
+ int rlen = 0, sum = 0;
+
+ if (!fp->f_op || !fp->f_op->read)
+ return -EPERM;
+
+ while (sum < len) {
+ rlen = fp->f_op->read(fp, buf+sum, len-sum, &fp->f_pos);
+ if (rlen > 0)
+ sum += rlen;
+ else if (0 != rlen)
+ return rlen;
+ else
+ break;
+ }
+ return sum;
+}
+
+static int writefile(struct file *fp, char __user *buf, int len)
+{
+ int wlen = 0, sum = 0;
+
+ if (!fp->f_op || !fp->f_op->write)
+ return -EPERM;
+
+ while (sum < len) {
+ wlen = fp->f_op->write(fp, buf+sum, len-sum, &fp->f_pos);
+ if (wlen > 0)
+ sum += wlen;
+ else if (0 != wlen)
+ return wlen;
+ else
+ break;
+ }
+ return sum;
+}
+
+/* Test if the specifi @param path is a file and readable
+ * @param path the path of the file to test
+ * @return Linux specific error code
+ */
+static int isfilereadable(char *path)
+{
+ struct file *fp;
+ int ret = 0;
+ mm_segment_t oldfs;
+ char __user buf;
+
+ fp = filp_open(path, O_RDONLY, 0);
+ if (IS_ERR(fp)) {
+ ret = PTR_ERR(fp);
+ } else {
+ oldfs = get_fs(); set_fs(get_ds());
+
+ if (1 != readfile(fp, &buf, 1))
+ ret = PTR_ERR(fp);
+
+ set_fs(oldfs);
+ filp_close(fp, NULL);
+ }
+ return ret;
+}
+
+/* Open the file with @param path and retrive the file content into
+ * memory starting from @param buf for @param sz at most
+ * @param path the path of the file to open and read
+ * @param buf the starting address of the buffer to store file content
+ * @param sz how many bytes to read at most
+ * @return the byte we've read, or Linux specific error code
+ */
+static int retrievefromfile(char *path, u8 __user *buf, u32 sz)
+{
+ int ret = -1;
+ mm_segment_t oldfs;
+ struct file *fp;
+
+ if (path && buf) {
+ ret = openfile(&fp, path, O_RDONLY, 0);
+ if (0 == ret) {
+ DBG_88E("%s openfile path:%s fp =%p\n", __func__,
+ path, fp);
+
+ oldfs = get_fs(); set_fs(get_ds());
+ ret = readfile(fp, buf, sz);
+ set_fs(oldfs);
+ closefile(fp);
+
+ DBG_88E("%s readfile, ret:%d\n", __func__, ret);
+
+ } else {
+ DBG_88E("%s openfile path:%s Fail, ret:%d\n", __func__,
+ path, ret);
+ }
+ } else {
+ DBG_88E("%s NULL pointer\n", __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/*
+* Open the file with @param path and wirte @param sz byte of data starting from @param buf into the file
+* @param path the path of the file to open and write
+* @param buf the starting address of the data to write into file
+* @param sz how many bytes to write at most
+* @return the byte we've written, or Linux specific error code
+*/
+static int storetofile(char *path, u8 __user *buf, u32 sz)
+{
+ int ret = 0;
+ mm_segment_t oldfs;
+ struct file *fp;
+
+ if (path && buf) {
+ ret = openfile(&fp, path, O_CREAT|O_WRONLY, 0666);
+ if (0 == ret) {
+ DBG_88E("%s openfile path:%s fp =%p\n", __func__, path, fp);
+
+ oldfs = get_fs(); set_fs(get_ds());
+ ret = writefile(fp, buf, sz);
+ set_fs(oldfs);
+ closefile(fp);
+
+ DBG_88E("%s writefile, ret:%d\n", __func__, ret);
+
+ } else {
+ DBG_88E("%s openfile path:%s Fail, ret:%d\n", __func__, path, ret);
+ }
+ } else {
+ DBG_88E("%s NULL pointer\n", __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/*
+* Test if the specifi @param path is a file and readable
+* @param path the path of the file to test
+* @return true or false
+*/
+int rtw_is_file_readable(char *path)
+{
+ if (isfilereadable(path) == 0)
+ return true;
+ else
+ return false;
+}
+
+/*
+* Open the file with @param path and retrive the file content into memory starting from @param buf for @param sz at most
+* @param path the path of the file to open and read
+* @param buf the starting address of the buffer to store file content
+* @param sz how many bytes to read at most
+* @return the byte we've read
+*/
+int rtw_retrive_from_file(char *path, u8 __user *buf, u32 sz)
+{
+ int ret = retrievefromfile(path, buf, sz);
+
+ return ret >= 0 ? ret : 0;
+}
+
+/*
+ * Open the file with @param path and wirte @param sz byte of data
+ * starting from @param buf into the file
+ * @param path the path of the file to open and write
+ * @param buf the starting address of the data to write into file
+ * @param sz how many bytes to write at most
+ * @return the byte we've written
+ */
+int rtw_store_to_file(char *path, u8 __user *buf, u32 sz)
+{
+ int ret = storetofile(path, buf, sz);
+ return ret >= 0 ? ret : 0;
+}
+
+struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv,
+ void *old_priv)
+{
+ struct net_device *pnetdev;
+ struct rtw_netdev_priv_indicator *pnpi;
+
+ pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4);
+ if (!pnetdev)
+ goto RETURN;
+
+ pnpi = netdev_priv(pnetdev);
+ pnpi->priv = old_priv;
+ pnpi->sizeof_priv = sizeof_priv;
+
+RETURN:
+ return pnetdev;
+}
+
+struct net_device *rtw_alloc_etherdev(int sizeof_priv)
+{
+ struct net_device *pnetdev;
+ struct rtw_netdev_priv_indicator *pnpi;
+
+ pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4);
+ if (!pnetdev)
+ goto RETURN;
+
+ pnpi = netdev_priv(pnetdev);
+
+ pnpi->priv = rtw_zvmalloc(sizeof_priv);
+ if (!pnpi->priv) {
+ free_netdev(pnetdev);
+ pnetdev = NULL;
+ goto RETURN;
+ }
+
+ pnpi->sizeof_priv = sizeof_priv;
+RETURN:
+ return pnetdev;
+}
+
+void rtw_free_netdev(struct net_device *netdev)
+{
+ struct rtw_netdev_priv_indicator *pnpi;
+
+ if (!netdev)
+ goto RETURN;
+
+ pnpi = netdev_priv(netdev);
+
+ if (!pnpi->priv)
+ goto RETURN;
+
+ rtw_vmfree(pnpi->priv, pnpi->sizeof_priv);
+ free_netdev(netdev);
+
+RETURN:
+ return;
+}
+
+int rtw_change_ifname(struct adapter *padapter, const char *ifname)
+{
+ struct net_device *pnetdev;
+ struct net_device *cur_pnetdev = padapter->pnetdev;
+ struct rereg_nd_name_data *rereg_priv;
+ int ret;
+
+ if (!padapter)
+ goto error;
+
+ rereg_priv = &padapter->rereg_nd_name_priv;
+
+ /* free the old_pnetdev */
+ if (rereg_priv->old_pnetdev) {
+ free_netdev(rereg_priv->old_pnetdev);
+ rereg_priv->old_pnetdev = NULL;
+ }
+
+ if (!rtnl_is_locked())
+ unregister_netdev(cur_pnetdev);
+ else
+ unregister_netdevice(cur_pnetdev);
+
+ rtw_proc_remove_one(cur_pnetdev);
+
+ rereg_priv->old_pnetdev = cur_pnetdev;
+
+ pnetdev = rtw_init_netdev(padapter);
+ if (!pnetdev) {
+ ret = -1;
+ goto error;
+ }
+
+ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(adapter_to_dvobj(padapter)));
+
+ rtw_init_netdev_name(pnetdev, ifname);
+
+ memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN);
+
+ if (!rtnl_is_locked())
+ ret = register_netdev(pnetdev);
+ else
+ ret = register_netdevice(pnetdev);
+ if (ret != 0) {
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+ ("register_netdev() failed\n"));
+ goto error;
+ }
+ rtw_proc_init_one(pnetdev);
+ return 0;
+error:
+ return -1;
+}
+
+u64 rtw_modular64(u64 x, u64 y)
+{
+ return do_div(x, y);
+}
+
+u64 rtw_division64(u64 x, u64 y)
+{
+ do_div(x, y);
+ return x;
+}
+
+void rtw_buf_free(u8 **buf, u32 *buf_len)
+{
+ *buf_len = 0;
+ kfree(*buf);
+ *buf = NULL;
+}
+
+void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len)
+{
+ u32 ori_len = 0, dup_len = 0;
+ u8 *ori = NULL;
+ u8 *dup = NULL;
+
+ if (!buf || !buf_len)
+ return;
+
+ if (!src || !src_len)
+ goto keep_ori;
+
+ /* duplicate src */
+ dup = rtw_malloc(src_len);
+ if (dup) {
+ dup_len = src_len;
+ memcpy(dup, src, dup_len);
+ }
+
+keep_ori:
+ ori = *buf;
+ ori_len = *buf_len;
+
+ /* replace buf with dup */
+ *buf_len = 0;
+ *buf = dup;
+ *buf_len = dup_len;
+
+ /* free ori */
+ kfree(ori);
+}
+
+
+/**
+ * rtw_cbuf_full - test if cbuf is full
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Returns: true if cbuf is full
+ */
+inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf)
+{
+ return (cbuf->write == cbuf->read-1) ? true : false;
+}
+
+/**
+ * rtw_cbuf_empty - test if cbuf is empty
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Returns: true if cbuf is empty
+ */
+inline bool rtw_cbuf_empty(struct rtw_cbuf *cbuf)
+{
+ return (cbuf->write == cbuf->read) ? true : false;
+}
+
+/**
+ * rtw_cbuf_push - push a pointer into cbuf
+ * @cbuf: pointer of struct rtw_cbuf
+ * @buf: pointer to push in
+ *
+ * Lock free operation, be careful of the use scheme
+ * Returns: true push success
+ */
+bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf)
+{
+ if (rtw_cbuf_full(cbuf))
+ return _FAIL;
+
+ if (0)
+ DBG_88E("%s on %u\n", __func__, cbuf->write);
+ cbuf->bufs[cbuf->write] = buf;
+ cbuf->write = (cbuf->write+1)%cbuf->size;
+
+ return _SUCCESS;
+}
+
+/**
+ * rtw_cbuf_pop - pop a pointer from cbuf
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Lock free operation, be careful of the use scheme
+ * Returns: pointer popped out
+ */
+void *rtw_cbuf_pop(struct rtw_cbuf *cbuf)
+{
+ void *buf;
+ if (rtw_cbuf_empty(cbuf))
+ return NULL;
+
+ if (0)
+ DBG_88E("%s on %u\n", __func__, cbuf->read);
+ buf = cbuf->bufs[cbuf->read];
+ cbuf->read = (cbuf->read+1)%cbuf->size;
+
+ return buf;
+}
+
+/**
+ * rtw_cbuf_alloc - allocte a rtw_cbuf with given size and do initialization
+ * @size: size of pointer
+ *
+ * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure
+ */
+struct rtw_cbuf *rtw_cbuf_alloc(u32 size)
+{
+ struct rtw_cbuf *cbuf;
+
+ cbuf = (struct rtw_cbuf *)rtw_malloc(sizeof(*cbuf) +
+ sizeof(void *)*size);
+
+ if (cbuf) {
+ cbuf->write = 0;
+ cbuf->read = 0;
+ cbuf->size = size;
+ }
+ return cbuf;
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c
new file mode 100644
index 00000000000..e2f4e7d7717
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c
@@ -0,0 +1,261 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RECV_OSDEP_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <wifi.h>
+#include <recv_osdep.h>
+
+#include <osdep_intf.h>
+#include <ethernet.h>
+#include <usb_ops.h>
+
+/* init os related resource in struct recv_priv */
+int rtw_os_recv_resource_init(struct recv_priv *precvpriv,
+ struct adapter *padapter)
+{
+ return _SUCCESS;
+}
+
+/* alloc os related resource in union recv_frame */
+int rtw_os_recv_resource_alloc(struct adapter *padapter,
+ union recv_frame *precvframe)
+{
+ precvframe->u.hdr.pkt_newalloc = NULL;
+ precvframe->u.hdr.pkt = NULL;
+ return _SUCCESS;
+}
+
+/* free os related resource in union recv_frame */
+void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
+{
+}
+
+/* alloc os related resource in struct recv_buf */
+int rtw_os_recvbuf_resource_alloc(struct adapter *padapter,
+ struct recv_buf *precvbuf)
+{
+ int res = _SUCCESS;
+
+ precvbuf->irp_pending = false;
+ precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
+ if (precvbuf->purb == NULL)
+ res = _FAIL;
+ precvbuf->pskb = NULL;
+ precvbuf->reuse = false;
+ precvbuf->pallocated_buf = NULL;
+ precvbuf->pbuf = NULL;
+ precvbuf->pdata = NULL;
+ precvbuf->phead = NULL;
+ precvbuf->ptail = NULL;
+ precvbuf->pend = NULL;
+ precvbuf->transfer_len = 0;
+ precvbuf->len = 0;
+ return res;
+}
+
+/* free os related resource in struct recv_buf */
+int rtw_os_recvbuf_resource_free(struct adapter *padapter,
+ struct recv_buf *precvbuf)
+{
+ if (precvbuf->purb)
+ usb_free_urb(precvbuf->purb);
+ return _SUCCESS;
+}
+
+void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup)
+{
+ union iwreq_data wrqu;
+ struct iw_michaelmicfailure ev;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ u32 cur_time = 0;
+
+ if (psecuritypriv->last_mic_err_time == 0) {
+ psecuritypriv->last_mic_err_time = rtw_get_current_time();
+ } else {
+ cur_time = rtw_get_current_time();
+
+ if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) {
+ psecuritypriv->btkip_countermeasure = true;
+ psecuritypriv->last_mic_err_time = 0;
+ psecuritypriv->btkip_countermeasure_time = cur_time;
+ } else {
+ psecuritypriv->last_mic_err_time = rtw_get_current_time();
+ }
+ }
+
+ _rtw_memset(&ev, 0x00, sizeof(ev));
+ if (bgroup)
+ ev.flags |= IW_MICFAILURE_GROUP;
+ else
+ ev.flags |= IW_MICFAILURE_PAIRWISE;
+
+ ev.src_addr.sa_family = ARPHRD_ETHER;
+ memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
+ _rtw_memset(&wrqu, 0x00, sizeof(wrqu));
+ wrqu.data.length = sizeof(ev);
+ wireless_send_event(padapter->pnetdev, IWEVMICHAELMICFAILURE,
+ &wrqu, (char *)&ev);
+}
+
+void rtw_hostapd_mlme_rx(struct adapter *padapter,
+ union recv_frame *precv_frame)
+{
+}
+
+int rtw_recv_indicatepkt(struct adapter *padapter,
+ union recv_frame *precv_frame)
+{
+ struct recv_priv *precvpriv;
+ struct __queue *pfree_recv_queue;
+ struct sk_buff *skb;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+ precvpriv = &(padapter->recvpriv);
+ pfree_recv_queue = &(precvpriv->free_recv_queue);
+
+ skb = precv_frame->u.hdr.pkt;
+ if (skb == NULL) {
+ RT_TRACE(_module_recv_osdep_c_, _drv_err_,
+ ("rtw_recv_indicatepkt():skb == NULL something wrong!!!!\n"));
+ goto _recv_indicatepkt_drop;
+ }
+
+ RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+ ("rtw_recv_indicatepkt():skb != NULL !!!\n"));
+ RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+ ("rtw_recv_indicatepkt():precv_frame->u.hdr.rx_head =%p precv_frame->hdr.rx_data =%p\n",
+ precv_frame->u.hdr.rx_head, precv_frame->u.hdr.rx_data));
+ RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+ ("precv_frame->hdr.rx_tail =%p precv_frame->u.hdr.rx_end =%p precv_frame->hdr.len =%d\n",
+ precv_frame->u.hdr.rx_tail, precv_frame->u.hdr.rx_end,
+ precv_frame->u.hdr.len));
+
+ skb->data = precv_frame->u.hdr.rx_data;
+
+ skb_set_tail_pointer(skb, precv_frame->u.hdr.len);
+
+ skb->len = precv_frame->u.hdr.len;
+
+ RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+ ("skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n",
+ skb->head, skb->data, skb_tail_pointer(skb),
+ skb_end_pointer(skb), skb->len));
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ struct sk_buff *pskb2 = NULL;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ int bmcast = IS_MCAST(pattrib->dst);
+
+ if (!_rtw_memcmp(pattrib->dst, myid(&padapter->eeprompriv),
+ ETH_ALEN)) {
+ if (bmcast) {
+ psta = rtw_get_bcmc_stainfo(padapter);
+ pskb2 = skb_clone(skb, GFP_ATOMIC);
+ } else {
+ psta = rtw_get_stainfo(pstapriv, pattrib->dst);
+ }
+
+ if (psta) {
+ struct net_device *pnetdev;
+
+ pnetdev = (struct net_device *)padapter->pnetdev;
+ skb->dev = pnetdev;
+ skb_set_queue_mapping(skb, rtw_recv_select_queue(skb));
+
+ rtw_xmit_entry(skb, pnetdev);
+
+ if (bmcast)
+ skb = pskb2;
+ else
+ goto _recv_indicatepkt_end;
+ }
+ }
+ }
+
+ rcu_read_lock();
+ rcu_dereference(padapter->pnetdev->rx_handler_data);
+ rcu_read_unlock();
+
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->dev = padapter->pnetdev;
+ skb->protocol = eth_type_trans(skb, padapter->pnetdev);
+
+ netif_rx(skb);
+
+_recv_indicatepkt_end:
+
+ /* pointers to NULL before rtw_free_recvframe() */
+ precv_frame->u.hdr.pkt = NULL;
+
+ rtw_free_recvframe(precv_frame, pfree_recv_queue);
+
+ RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+ ("\n rtw_recv_indicatepkt :after netif_rx!!!!\n"));
+
+_func_exit_;
+
+ return _SUCCESS;
+
+_recv_indicatepkt_drop:
+
+ /* enqueue back to free_recv_queue */
+ if (precv_frame)
+ rtw_free_recvframe(precv_frame, pfree_recv_queue);
+
+_func_exit_;
+ return _FAIL;
+}
+
+void rtw_os_read_port(struct adapter *padapter, struct recv_buf *precvbuf)
+{
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+ precvbuf->ref_cnt--;
+ /* free skb in recv_buf */
+ dev_kfree_skb_any(precvbuf->pskb);
+ precvbuf->pskb = NULL;
+ precvbuf->reuse = false;
+ if (!precvbuf->irp_pending)
+ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0,
+ (unsigned char *)precvbuf);
+}
+
+static void _rtw_reordering_ctrl_timeout_handler(void *func_context)
+{
+ struct recv_reorder_ctrl *preorder_ctrl;
+
+ preorder_ctrl = (struct recv_reorder_ctrl *)func_context;
+ rtw_reordering_ctrl_timeout_handler(preorder_ctrl);
+}
+
+void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl)
+{
+ struct adapter *padapter = preorder_ctrl->padapter;
+
+ _init_timer(&(preorder_ctrl->reordering_ctrl_timer), padapter->pnetdev, _rtw_reordering_ctrl_timeout_handler, preorder_ctrl);
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_android.c b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
new file mode 100644
index 00000000000..6cf71cc2ca2
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
@@ -0,0 +1,293 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include <rtw_android.h>
+#include <osdep_service.h>
+#include <rtw_debug.h>
+#include <ioctl_cfg80211.h>
+#include <rtw_ioctl_set.h>
+
+static const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
+ "START",
+ "STOP",
+ "SCAN-ACTIVE",
+ "SCAN-PASSIVE",
+ "RSSI",
+ "LINKSPEED",
+ "RXFILTER-START",
+ "RXFILTER-STOP",
+ "RXFILTER-ADD",
+ "RXFILTER-REMOVE",
+ "BTCOEXSCAN-START",
+ "BTCOEXSCAN-STOP",
+ "BTCOEXMODE",
+ "SETSUSPENDOPT",
+ "P2P_DEV_ADDR",
+ "SETFWPATH",
+ "SETBAND",
+ "GETBAND",
+ "COUNTRY",
+ "P2P_SET_NOA",
+ "P2P_GET_NOA",
+ "P2P_SET_PS",
+ "SET_AP_WPS_P2P_IE",
+ "MACADDR",
+ "BLOCK",
+ "WFD-ENABLE",
+ "WFD-DISABLE",
+ "WFD-SET-TCPPORT",
+ "WFD-SET-MAXTPUT",
+ "WFD-SET-DEVTYPE",
+};
+
+struct android_wifi_priv_cmd {
+ const char __user *buf;
+ int used_len;
+ int total_len;
+};
+
+/**
+ * Local (static) functions and variables
+ */
+
+/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
+ * time (only) in dhd_open, subsequential wifi on will be handled by
+ * wl_android_wifi_on
+ */
+static int g_wifi_on = true;
+
+int rtw_android_cmdstr_to_num(char *cmdstr)
+{
+ int cmd_num;
+ for (cmd_num = 0; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++)
+ if (0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num],
+ strlen(android_wifi_cmd_str[cmd_num])))
+ break;
+ return cmd_num;
+}
+
+static int rtw_android_get_rssi(struct net_device *net, char *command,
+ int total_len)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(net);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_network *pcur_network = &pmlmepriv->cur_network;
+ int bytes_written = 0;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ bytes_written += snprintf(&command[bytes_written], total_len,
+ "%s rssi %d",
+ pcur_network->network.Ssid.Ssid,
+ padapter->recvpriv.rssi);
+ }
+ return bytes_written;
+}
+
+static int rtw_android_get_link_speed(struct net_device *net, char *command,
+ int total_len)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(net);
+ int bytes_written;
+ u16 link_speed;
+
+ link_speed = rtw_get_cur_max_rate(padapter) / 10;
+ bytes_written = snprintf(command, total_len, "LinkSpeed %d",
+ link_speed);
+ return bytes_written;
+}
+
+static int rtw_android_get_macaddr(struct net_device *net, char *command,
+ int total_len)
+{
+ int bytes_written;
+
+ bytes_written = snprintf(command, total_len, "Macaddr = %pM",
+ net->dev_addr);
+ return bytes_written;
+}
+
+static int android_set_cntry(struct net_device *net, char *command,
+ int total_len)
+{
+ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(net);
+ char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1;
+ int ret;
+
+ ret = rtw_set_country(adapter, country_code);
+ return (ret == _SUCCESS) ? 0 : -1;
+}
+
+static int android_get_p2p_addr(struct net_device *net, char *command,
+ int total_len)
+{
+ /* We use the same address as our HW MAC address */
+ memcpy(command, net->dev_addr, ETH_ALEN);
+ return ETH_ALEN;
+}
+
+static int rtw_android_set_block(struct net_device *net, char *command,
+ int total_len)
+{
+ return 0;
+}
+
+int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
+{
+ int ret = 0;
+ char *command = NULL;
+ int cmd_num;
+ int bytes_written = 0;
+ struct android_wifi_priv_cmd priv_cmd;
+
+ rtw_lock_suspend();
+ if (!ifr->ifr_data) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ if (copy_from_user(&priv_cmd, ifr->ifr_data,
+ sizeof(struct android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ command = kmalloc(priv_cmd.total_len, GFP_KERNEL);
+ if (!command) {
+ DBG_88E("%s: failed to allocate memory\n", __func__);
+ ret = -ENOMEM;
+ goto exit;
+ }
+ if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)) {
+ DBG_88E("%s: failed to access memory\n", __func__);
+ ret = -EFAULT;
+ goto exit;
+ }
+ if (copy_from_user(command, (char __user *)priv_cmd.buf,
+ priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ DBG_88E("%s: Android private cmd \"%s\" on %s\n",
+ __func__, command, ifr->ifr_name);
+ cmd_num = rtw_android_cmdstr_to_num(command);
+ switch (cmd_num) {
+ case ANDROID_WIFI_CMD_START:
+ goto response;
+ case ANDROID_WIFI_CMD_SETFWPATH:
+ goto response;
+ }
+ if (!g_wifi_on) {
+ DBG_88E("%s: Ignore private cmd \"%s\" - iface %s is down\n",
+ __func__, command, ifr->ifr_name);
+ ret = 0;
+ goto exit;
+ }
+ switch (cmd_num) {
+ case ANDROID_WIFI_CMD_STOP:
+ break;
+ case ANDROID_WIFI_CMD_SCAN_ACTIVE:
+ break;
+ case ANDROID_WIFI_CMD_SCAN_PASSIVE:
+ break;
+ case ANDROID_WIFI_CMD_RSSI:
+ bytes_written = rtw_android_get_rssi(net, command,
+ priv_cmd.total_len);
+ break;
+ case ANDROID_WIFI_CMD_LINKSPEED:
+ bytes_written = rtw_android_get_link_speed(net, command,
+ priv_cmd.total_len);
+ break;
+ case ANDROID_WIFI_CMD_MACADDR:
+ bytes_written = rtw_android_get_macaddr(net, command,
+ priv_cmd.total_len);
+ break;
+ case ANDROID_WIFI_CMD_BLOCK:
+ bytes_written = rtw_android_set_block(net, command,
+ priv_cmd.total_len);
+ break;
+ case ANDROID_WIFI_CMD_RXFILTER_START:
+ break;
+ case ANDROID_WIFI_CMD_RXFILTER_STOP:
+ break;
+ case ANDROID_WIFI_CMD_RXFILTER_ADD:
+ break;
+ case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
+ break;
+ case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
+ /* TBD: BTCOEXSCAN-START */
+ break;
+ case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP:
+ /* TBD: BTCOEXSCAN-STOP */
+ break;
+ case ANDROID_WIFI_CMD_BTCOEXMODE:
+ break;
+ case ANDROID_WIFI_CMD_SETSUSPENDOPT:
+ break;
+ case ANDROID_WIFI_CMD_SETBAND:
+ break;
+ case ANDROID_WIFI_CMD_GETBAND:
+ break;
+ case ANDROID_WIFI_CMD_COUNTRY:
+ bytes_written = android_set_cntry(net, command,
+ priv_cmd.total_len);
+ break;
+ case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
+ bytes_written = android_get_p2p_addr(net, command,
+ priv_cmd.total_len);
+ break;
+ case ANDROID_WIFI_CMD_P2P_SET_NOA:
+ break;
+ case ANDROID_WIFI_CMD_P2P_GET_NOA:
+ break;
+ case ANDROID_WIFI_CMD_P2P_SET_PS:
+ break;
+ default:
+ DBG_88E("Unknown PRIVATE command %s - ignored\n", command);
+ snprintf(command, 3, "OK");
+ bytes_written = strlen("OK");
+ }
+
+response:
+ if (bytes_written >= 0) {
+ if ((bytes_written == 0) && (priv_cmd.total_len > 0))
+ command[0] = '\0';
+ if (bytes_written >= priv_cmd.total_len) {
+ DBG_88E("%s: bytes_written = %d\n", __func__,
+ bytes_written);
+ bytes_written = priv_cmd.total_len;
+ } else {
+ bytes_written++;
+ }
+ priv_cmd.used_len = bytes_written;
+ if (copy_to_user((char __user *)priv_cmd.buf, command,
+ bytes_written)) {
+ DBG_88E("%s: failed to copy data to user buffer\n",
+ __func__);
+ ret = -EFAULT;
+ }
+ } else {
+ ret = bytes_written;
+ }
+exit:
+ rtw_unlock_suspend();
+ kfree(command);
+ return ret;
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
new file mode 100644
index 00000000000..d3078d200e5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -0,0 +1,892 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _HCI_INTF_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+#include <hal_intf.h>
+#include <rtw_version.h>
+#include <linux/usb.h>
+#include <osdep_intf.h>
+
+#include <usb_vendor_req.h>
+#include <usb_ops.h>
+#include <usb_osintf.h>
+#include <usb_hal.h>
+#include <rtw_ioctl.h>
+
+int ui_pid[3] = {0, 0, 0};
+
+static int rtw_suspend(struct usb_interface *intf, pm_message_t message);
+static int rtw_resume(struct usb_interface *intf);
+
+
+static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid);
+static void rtw_dev_remove(struct usb_interface *pusb_intf);
+
+
+#define USB_VENDER_ID_REALTEK 0x0bda
+
+/* DID_USB_v916_20130116 */
+static struct usb_device_id rtw_usb_id_tbl[] = {
+ /*=== Realtek demoboard ===*/
+ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8179)}, /* 8188EUS */
+ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */
+ /*=== Customer ID ===*/
+ /****** 8188EUS ********/
+ {USB_DEVICE(0x8179, 0x07B8)}, /* Abocom - Abocom */
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, rtw_usb_id_tbl);
+
+static struct specific_device_id specific_device_id_tbl[] = {
+ {} /* empty table for now */
+};
+
+struct rtw_usb_drv {
+ struct usb_driver usbdrv;
+ int drv_registered;
+ struct mutex hw_init_mutex;
+};
+
+static struct rtw_usb_drv rtl8188e_usb_drv = {
+ .usbdrv.name = (char *)"r8188eu",
+ .usbdrv.probe = rtw_drv_init,
+ .usbdrv.disconnect = rtw_dev_remove,
+ .usbdrv.id_table = rtw_usb_id_tbl,
+ .usbdrv.suspend = rtw_suspend,
+ .usbdrv.resume = rtw_resume,
+ .usbdrv.reset_resume = rtw_resume,
+};
+
+static struct rtw_usb_drv *usb_drv = &rtl8188e_usb_drv;
+
+static inline int RT_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+{
+ return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN;
+}
+
+static inline int RT_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+{
+ return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT;
+}
+
+static inline int RT_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+{
+ return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT;
+}
+
+static inline int RT_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
+{
+ return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK;
+}
+
+static inline int RT_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
+{
+ return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_in(epd);
+}
+
+static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
+{
+ return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_out(epd);
+}
+
+static inline int usb_endpoint_is_int(const struct usb_endpoint_descriptor *epd)
+{
+ return RT_usb_endpoint_xfer_int(epd) && RT_usb_endpoint_dir_in(epd);
+}
+
+static inline int RT_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
+{
+ return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+}
+
+static u8 rtw_init_intf_priv(struct dvobj_priv *dvobj)
+{
+ u8 rst = _SUCCESS;
+
+ _rtw_mutex_init(&dvobj->usb_vendor_req_mutex);
+
+ dvobj->usb_alloc_vendor_req_buf = rtw_zmalloc(MAX_USB_IO_CTL_SIZE);
+ if (dvobj->usb_alloc_vendor_req_buf == NULL) {
+ DBG_88E("alloc usb_vendor_req_buf failed... /n");
+ rst = _FAIL;
+ goto exit;
+ }
+ dvobj->usb_vendor_req_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(dvobj->usb_alloc_vendor_req_buf), ALIGNMENT_UNIT);
+exit:
+ return rst;
+}
+
+static u8 rtw_deinit_intf_priv(struct dvobj_priv *dvobj)
+{
+ u8 rst = _SUCCESS;
+
+ kfree(dvobj->usb_alloc_vendor_req_buf);
+ _rtw_mutex_free(&dvobj->usb_vendor_req_mutex);
+ return rst;
+}
+
+static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf)
+{
+ int i;
+ int status = _FAIL;
+ struct dvobj_priv *pdvobjpriv;
+ struct usb_host_config *phost_conf;
+ struct usb_config_descriptor *pconf_desc;
+ struct usb_host_interface *phost_iface;
+ struct usb_interface_descriptor *piface_desc;
+ struct usb_host_endpoint *phost_endp;
+ struct usb_endpoint_descriptor *pendp_desc;
+ struct usb_device *pusbd;
+
+_func_enter_;
+
+ pdvobjpriv = (struct dvobj_priv *)rtw_zmalloc(sizeof(*pdvobjpriv));
+ if (pdvobjpriv == NULL)
+ goto exit;
+
+ pdvobjpriv->pusbintf = usb_intf;
+ pusbd = interface_to_usbdev(usb_intf);
+ pdvobjpriv->pusbdev = pusbd;
+ usb_set_intfdata(usb_intf, pdvobjpriv);
+
+ pdvobjpriv->RtNumInPipes = 0;
+ pdvobjpriv->RtNumOutPipes = 0;
+
+ phost_conf = pusbd->actconfig;
+ pconf_desc = &phost_conf->desc;
+
+ phost_iface = &usb_intf->altsetting[0];
+ piface_desc = &phost_iface->desc;
+
+ pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces;
+ pdvobjpriv->InterfaceNumber = piface_desc->bInterfaceNumber;
+ pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints;
+
+ for (i = 0; i < pdvobjpriv->nr_endpoint; i++) {
+ phost_endp = phost_iface->endpoint + i;
+ if (phost_endp) {
+ pendp_desc = &phost_endp->desc;
+
+ DBG_88E("\nusb_endpoint_descriptor(%d):\n", i);
+ DBG_88E("bLength=%x\n", pendp_desc->bLength);
+ DBG_88E("bDescriptorType=%x\n",
+ pendp_desc->bDescriptorType);
+ DBG_88E("bEndpointAddress=%x\n",
+ pendp_desc->bEndpointAddress);
+ DBG_88E("wMaxPacketSize=%d\n",
+ le16_to_cpu(pendp_desc->wMaxPacketSize));
+ DBG_88E("bInterval=%x\n", pendp_desc->bInterval);
+
+ if (RT_usb_endpoint_is_bulk_in(pendp_desc)) {
+ DBG_88E("RT_usb_endpoint_is_bulk_in = %x\n",
+ RT_usb_endpoint_num(pendp_desc));
+ pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = RT_usb_endpoint_num(pendp_desc);
+ pdvobjpriv->RtNumInPipes++;
+ } else if (usb_endpoint_is_int(pendp_desc)) {
+ DBG_88E("usb_endpoint_is_int = %x, Interval = %x\n",
+ RT_usb_endpoint_num(pendp_desc),
+ pendp_desc->bInterval);
+ pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = RT_usb_endpoint_num(pendp_desc);
+ pdvobjpriv->RtNumInPipes++;
+ } else if (RT_usb_endpoint_is_bulk_out(pendp_desc)) {
+ DBG_88E("RT_usb_endpoint_is_bulk_out = %x\n",
+ RT_usb_endpoint_num(pendp_desc));
+ pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] = RT_usb_endpoint_num(pendp_desc);
+ pdvobjpriv->RtNumOutPipes++;
+ }
+ pdvobjpriv->ep_num[i] = RT_usb_endpoint_num(pendp_desc);
+ }
+ }
+
+ DBG_88E("nr_endpoint=%d, in_num=%d, out_num=%d\n\n",
+ pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes,
+ pdvobjpriv->RtNumOutPipes);
+
+ if (pusbd->speed == USB_SPEED_HIGH) {
+ pdvobjpriv->ishighspeed = true;
+ DBG_88E("USB_SPEED_HIGH\n");
+ } else {
+ pdvobjpriv->ishighspeed = false;
+ DBG_88E("NON USB_SPEED_HIGH\n");
+ }
+
+ if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) {
+ RT_TRACE(_module_os_intfs_c_, _drv_err_,
+ ("\n Can't INIT rtw_init_intf_priv\n"));
+ goto free_dvobj;
+ }
+
+ /* 3 misc */
+ _rtw_init_sema(&(pdvobjpriv->usb_suspend_sema), 0);
+ rtw_reset_continual_urb_error(pdvobjpriv);
+
+ usb_get_dev(pusbd);
+
+ status = _SUCCESS;
+
+free_dvobj:
+ if (status != _SUCCESS && pdvobjpriv) {
+ usb_set_intfdata(usb_intf, NULL);
+ kfree(pdvobjpriv);
+ pdvobjpriv = NULL;
+ }
+exit:
+_func_exit_;
+ return pdvobjpriv;
+}
+
+static void usb_dvobj_deinit(struct usb_interface *usb_intf)
+{
+ struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf);
+
+_func_enter_;
+
+ usb_set_intfdata(usb_intf, NULL);
+ if (dvobj) {
+ /* Modify condition for 92DU DMDP 2010.11.18, by Thomas */
+ if ((dvobj->NumInterfaces != 2 &&
+ dvobj->NumInterfaces != 3) ||
+ (dvobj->InterfaceNumber == 1)) {
+ if (interface_to_usbdev(usb_intf)->state !=
+ USB_STATE_NOTATTACHED) {
+ /* If we didn't unplug usb dongle and
+ * remove/insert module, driver fails
+ * on sitesurvey for the first time when
+ * device is up . Reset usb port for sitesurvey
+ * fail issue. */
+ DBG_88E("usb attached..., try to reset usb device\n");
+ usb_reset_device(interface_to_usbdev(usb_intf));
+ }
+ }
+ rtw_deinit_intf_priv(dvobj);
+ kfree(dvobj);
+ }
+
+ usb_put_dev(interface_to_usbdev(usb_intf));
+
+_func_exit_;
+}
+
+static void chip_by_usb_id(struct adapter *padapter,
+ const struct usb_device_id *pdid)
+{
+ padapter->chip_type = NULL_CHIP_TYPE;
+ hal_set_hw_type(padapter);
+}
+
+static void usb_intf_start(struct adapter *padapter)
+{
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_start\n"));
+
+ rtw_hal_inirp_init(padapter);
+
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_start\n"));
+}
+
+static void usb_intf_stop(struct adapter *padapter)
+{
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_stop\n"));
+
+ /* disabel_hw_interrupt */
+ if (!padapter->bSurpriseRemoved) {
+ /* device still exists, so driver can do i/o operation */
+ /* TODO: */
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+ ("SurpriseRemoved == false\n"));
+ }
+
+ /* cancel in irp */
+ rtw_hal_inirp_deinit(padapter);
+
+ /* cancel out irp */
+ rtw_write_port_cancel(padapter);
+
+ /* todo:cancel other irps */
+
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_stop\n"));
+}
+
+static void rtw_dev_unload(struct adapter *padapter)
+{
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_dev_unload\n"));
+
+ if (padapter->bup) {
+ DBG_88E("===> rtw_dev_unload\n");
+ padapter->bDriverStopped = true;
+ if (padapter->xmitpriv.ack_tx)
+ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP);
+ /* s3. */
+ if (padapter->intf_stop)
+ padapter->intf_stop(padapter);
+ /* s4. */
+ if (!padapter->pwrctrlpriv.bInternalAutoSuspend)
+ rtw_stop_drv_threads(padapter);
+
+ /* s5. */
+ if (!padapter->bSurpriseRemoved) {
+ rtw_hal_deinit(padapter);
+ padapter->bSurpriseRemoved = true;
+ }
+
+ padapter->bup = false;
+ } else {
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+ ("r871x_dev_unload():padapter->bup == false\n"));
+ }
+
+ DBG_88E("<=== rtw_dev_unload\n");
+
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-rtw_dev_unload\n"));
+}
+
+static void process_spec_devid(const struct usb_device_id *pdid)
+{
+ u16 vid, pid;
+ u32 flags;
+ int i;
+ int num = sizeof(specific_device_id_tbl) /
+ sizeof(struct specific_device_id);
+
+ for (i = 0; i < num; i++) {
+ vid = specific_device_id_tbl[i].idVendor;
+ pid = specific_device_id_tbl[i].idProduct;
+ flags = specific_device_id_tbl[i].flags;
+
+ if ((pdid->idVendor == vid) && (pdid->idProduct == pid) &&
+ (flags&SPEC_DEV_ID_DISABLE_HT)) {
+ rtw_ht_enable = 0;
+ rtw_cbw40_enable = 0;
+ rtw_ampdu_enable = 0;
+ }
+ }
+}
+
+int rtw_hw_suspend(struct adapter *padapter)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct net_device *pnetdev = padapter->pnetdev;
+
+ _func_enter_;
+
+ if ((!padapter->bup) || (padapter->bDriverStopped) ||
+ (padapter->bSurpriseRemoved)) {
+ DBG_88E("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n",
+ padapter->bup, padapter->bDriverStopped,
+ padapter->bSurpriseRemoved);
+ goto error_exit;
+ }
+
+ if (padapter) { /* system suspend */
+ LeaveAllPowerSaveMode(padapter);
+
+ DBG_88E("==> rtw_hw_suspend\n");
+ _enter_pwrlock(&pwrpriv->lock);
+ pwrpriv->bips_processing = true;
+ /* s1. */
+ if (pnetdev) {
+ netif_carrier_off(pnetdev);
+ rtw_netif_stop_queue(pnetdev);
+ }
+
+ /* s2. */
+ rtw_disassoc_cmd(padapter, 500, false);
+
+ /* s2-2. indicate disconnect to os */
+ {
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ _clr_fwstate_(pmlmepriv, _FW_LINKED);
+
+ rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+ rtw_os_indicate_disconnect(padapter);
+
+ /* donnot enqueue cmd */
+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 0);
+ }
+ }
+ /* s2-3. */
+ rtw_free_assoc_resources(padapter, 1);
+
+ /* s2-4. */
+ rtw_free_network_queue(padapter, true);
+ rtw_ips_dev_unload(padapter);
+ pwrpriv->rf_pwrstate = rf_off;
+ pwrpriv->bips_processing = false;
+
+ _exit_pwrlock(&pwrpriv->lock);
+ } else {
+ goto error_exit;
+ }
+ _func_exit_;
+ return 0;
+
+error_exit:
+ DBG_88E("%s, failed\n", __func__);
+ return -1;
+}
+
+int rtw_hw_resume(struct adapter *padapter)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct net_device *pnetdev = padapter->pnetdev;
+
+ _func_enter_;
+
+ if (padapter) { /* system resume */
+ DBG_88E("==> rtw_hw_resume\n");
+ _enter_pwrlock(&pwrpriv->lock);
+ pwrpriv->bips_processing = true;
+ rtw_reset_drv_sw(padapter);
+
+ if (pm_netdev_open(pnetdev, false) != 0) {
+ _exit_pwrlock(&pwrpriv->lock);
+ goto error_exit;
+ }
+
+ netif_device_attach(pnetdev);
+ netif_carrier_on(pnetdev);
+
+ if (!netif_queue_stopped(pnetdev))
+ netif_start_queue(pnetdev);
+ else
+ netif_wake_queue(pnetdev);
+
+ pwrpriv->bkeepfwalive = false;
+ pwrpriv->brfoffbyhw = false;
+
+ pwrpriv->rf_pwrstate = rf_on;
+ pwrpriv->bips_processing = false;
+
+ _exit_pwrlock(&pwrpriv->lock);
+ } else {
+ goto error_exit;
+ }
+
+ _func_exit_;
+
+ return 0;
+error_exit:
+ DBG_88E("%s, Open net dev failed\n", __func__);
+ return -1;
+}
+
+static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message)
+{
+ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
+ struct adapter *padapter = dvobj->if1;
+ struct net_device *pnetdev = padapter->pnetdev;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+
+ int ret = 0;
+ u32 start_time = rtw_get_current_time();
+
+ _func_enter_;
+
+ DBG_88E("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
+
+ if ((!padapter->bup) || (padapter->bDriverStopped) ||
+ (padapter->bSurpriseRemoved)) {
+ DBG_88E("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n",
+ padapter->bup, padapter->bDriverStopped,
+ padapter->bSurpriseRemoved);
+ goto exit;
+ }
+
+ pwrpriv->bInSuspend = true;
+ rtw_cancel_all_timer(padapter);
+ LeaveAllPowerSaveMode(padapter);
+
+ _enter_pwrlock(&pwrpriv->lock);
+ /* s1. */
+ if (pnetdev) {
+ netif_carrier_off(pnetdev);
+ rtw_netif_stop_queue(pnetdev);
+ }
+
+ /* s2. */
+ rtw_disassoc_cmd(padapter, 0, false);
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) &&
+ check_fwstate(pmlmepriv, _FW_LINKED)) {
+ DBG_88E("%s:%d %s(%pM), length:%d assoc_ssid.length:%d\n",
+ __func__, __LINE__,
+ pmlmepriv->cur_network.network.Ssid.Ssid,
+ pmlmepriv->cur_network.network.MacAddress,
+ pmlmepriv->cur_network.network.Ssid.SsidLength,
+ pmlmepriv->assoc_ssid.SsidLength);
+
+ pmlmepriv->to_roaming = 1;
+ }
+ /* s2-2. indicate disconnect to os */
+ rtw_indicate_disconnect(padapter);
+ /* s2-3. */
+ rtw_free_assoc_resources(padapter, 1);
+ /* s2-4. */
+ rtw_free_network_queue(padapter, true);
+
+ rtw_dev_unload(padapter);
+ _exit_pwrlock(&pwrpriv->lock);
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
+ rtw_indicate_scan_done(padapter, 1);
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
+ rtw_indicate_disconnect(padapter);
+
+exit:
+ DBG_88E("<=== %s return %d.............. in %dms\n", __func__
+ , ret, rtw_get_passing_time_ms(start_time));
+
+ _func_exit_;
+ return ret;
+}
+
+static int rtw_resume(struct usb_interface *pusb_intf)
+{
+ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
+ struct adapter *padapter = dvobj->if1;
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ int ret = 0;
+
+ if (pwrpriv->bInternalAutoSuspend)
+ ret = rtw_resume_process(padapter);
+ else
+ ret = rtw_resume_process(padapter);
+ return ret;
+}
+
+int rtw_resume_process(struct adapter *padapter)
+{
+ struct net_device *pnetdev;
+ struct pwrctrl_priv *pwrpriv = NULL;
+ int ret = -1;
+ u32 start_time = rtw_get_current_time();
+ _func_enter_;
+
+ DBG_88E("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
+
+ if (padapter) {
+ pnetdev = padapter->pnetdev;
+ pwrpriv = &padapter->pwrctrlpriv;
+ } else {
+ goto exit;
+ }
+
+ _enter_pwrlock(&pwrpriv->lock);
+ rtw_reset_drv_sw(padapter);
+ if (pwrpriv)
+ pwrpriv->bkeepfwalive = false;
+
+ DBG_88E("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive);
+ if (pm_netdev_open(pnetdev, true) != 0)
+ goto exit;
+
+ netif_device_attach(pnetdev);
+ netif_carrier_on(pnetdev);
+
+ _exit_pwrlock(&pwrpriv->lock);
+
+ if (padapter->pid[1] != 0) {
+ DBG_88E("pid[1]:%d\n", padapter->pid[1]);
+ rtw_signal_process(padapter->pid[1], SIGUSR2);
+ }
+
+ rtw_roaming(padapter, NULL);
+
+ ret = 0;
+exit:
+ if (pwrpriv)
+ pwrpriv->bInSuspend = false;
+ DBG_88E("<=== %s return %d.............. in %dms\n", __func__,
+ ret, rtw_get_passing_time_ms(start_time));
+
+ _func_exit_;
+
+ return ret;
+}
+
+/*
+ * drv_init() - a device potentially for us
+ *
+ * notes: drv_init() is called when the bus driver has located
+ * a card for us to support.
+ * We accept the new device by returning 0.
+ */
+
+static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj,
+ struct usb_interface *pusb_intf, const struct usb_device_id *pdid)
+{
+ struct adapter *padapter = NULL;
+ struct net_device *pnetdev = NULL;
+ int status = _FAIL;
+
+ padapter = (struct adapter *)rtw_zvmalloc(sizeof(*padapter));
+ if (padapter == NULL)
+ goto exit;
+ padapter->dvobj = dvobj;
+ dvobj->if1 = padapter;
+
+ padapter->bDriverStopped = true;
+
+ padapter->hw_init_mutex = &usb_drv->hw_init_mutex;
+
+ /* step 1-1., decide the chip_type via vid/pid */
+ padapter->interface_type = RTW_USB;
+ chip_by_usb_id(padapter, pdid);
+
+ if (rtw_handle_dualmac(padapter, 1) != _SUCCESS)
+ goto free_adapter;
+
+ pnetdev = rtw_init_netdev(padapter);
+ if (pnetdev == NULL)
+ goto handle_dualmac;
+ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj));
+ padapter = rtw_netdev_priv(pnetdev);
+
+ /* step 2. hook HalFunc, allocate HalData */
+ hal_set_hal_ops(padapter);
+
+ padapter->intf_start = &usb_intf_start;
+ padapter->intf_stop = &usb_intf_stop;
+
+ /* step init_io_priv */
+ rtw_init_io_priv(padapter, usb_set_intf_ops);
+
+ /* step read_chip_version */
+ rtw_hal_read_chip_version(padapter);
+
+ /* step usb endpoint mapping */
+ rtw_hal_chip_configure(padapter);
+
+ /* step read efuse/eeprom data and get mac_addr */
+ rtw_hal_read_chip_info(padapter);
+
+ /* step 5. */
+ if (rtw_init_drv_sw(padapter) == _FAIL) {
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+ ("Initialize driver software resource Failed!\n"));
+ goto free_hal_data;
+ }
+
+#ifdef CONFIG_PM
+ if (padapter->pwrctrlpriv.bSupportRemoteWakeup) {
+ dvobj->pusbdev->do_remote_wakeup = 1;
+ pusb_intf->needs_remote_wakeup = 1;
+ device_init_wakeup(&pusb_intf->dev, 1);
+ DBG_88E("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n");
+ DBG_88E("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n",
+ device_may_wakeup(&pusb_intf->dev));
+ }
+#endif
+
+ /* 2012-07-11 Move here to prevent the 8723AS-VAU BT auto
+ * suspend influence */
+ if (usb_autopm_get_interface(pusb_intf) < 0)
+ DBG_88E("can't get autopm:\n");
+
+ /* alloc dev name after read efuse. */
+ rtw_init_netdev_name(pnetdev, padapter->registrypriv.ifname);
+ rtw_macaddr_cfg(padapter->eeprompriv.mac_addr);
+#ifdef CONFIG_88EU_P2P
+ rtw_init_wifidirect_addrs(padapter, padapter->eeprompriv.mac_addr,
+ padapter->eeprompriv.mac_addr);
+#endif
+ memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN);
+ DBG_88E("MAC Address from pnetdev->dev_addr = %pM\n",
+ pnetdev->dev_addr);
+
+ /* step 6. Tell the network stack we exist */
+ if (register_netdev(pnetdev) != 0) {
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("register_netdev() failed\n"));
+ goto free_hal_data;
+ }
+
+ DBG_88E("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n"
+ , padapter->bDriverStopped
+ , padapter->bSurpriseRemoved
+ , padapter->bup
+ , padapter->hw_init_completed
+ );
+
+ status = _SUCCESS;
+
+free_hal_data:
+ if (status != _SUCCESS && padapter->HalData)
+ kfree(padapter->HalData);
+handle_dualmac:
+ if (status != _SUCCESS)
+ rtw_handle_dualmac(padapter, 0);
+free_adapter:
+ if (status != _SUCCESS) {
+ if (pnetdev)
+ rtw_free_netdev(pnetdev);
+ else if (padapter)
+ rtw_vmfree((u8 *)padapter, sizeof(*padapter));
+ padapter = NULL;
+ }
+exit:
+ return padapter;
+}
+
+static void rtw_usb_if1_deinit(struct adapter *if1)
+{
+ struct net_device *pnetdev = if1->pnetdev;
+ struct mlme_priv *pmlmepriv = &if1->mlmepriv;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED))
+ rtw_disassoc_cmd(if1, 0, false);
+
+#ifdef CONFIG_88EU_AP_MODE
+ free_mlme_ap_info(if1);
+#endif
+
+ if (if1->DriverState != DRIVER_DISAPPEAR) {
+ if (pnetdev) {
+ /* will call netdev_close() */
+ unregister_netdev(pnetdev);
+ rtw_proc_remove_one(pnetdev);
+ }
+ }
+ rtw_cancel_all_timer(if1);
+
+ rtw_dev_unload(if1);
+ DBG_88E("+r871xu_dev_remove, hw_init_completed=%d\n",
+ if1->hw_init_completed);
+ rtw_handle_dualmac(if1, 0);
+ rtw_free_drv_sw(if1);
+ if (pnetdev)
+ rtw_free_netdev(pnetdev);
+}
+
+static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid)
+{
+ struct adapter *if1 = NULL;
+ int status;
+ struct dvobj_priv *dvobj;
+
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n"));
+
+ /* step 0. */
+ process_spec_devid(pdid);
+
+ /* Initialize dvobj_priv */
+ dvobj = usb_dvobj_init(pusb_intf);
+ if (dvobj == NULL) {
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+ ("initialize device object priv Failed!\n"));
+ goto exit;
+ }
+
+ if1 = rtw_usb_if1_init(dvobj, pusb_intf, pdid);
+ if (if1 == NULL) {
+ DBG_88E("rtw_init_primarystruct adapter Failed!\n");
+ goto free_dvobj;
+ }
+
+ if (ui_pid[1] != 0) {
+ DBG_88E("ui_pid[1]:%d\n", ui_pid[1]);
+ rtw_signal_process(ui_pid[1], SIGUSR2);
+ }
+
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-871x_drv - drv_init, success!\n"));
+
+ status = _SUCCESS;
+
+ if (status != _SUCCESS && if1)
+ rtw_usb_if1_deinit(if1);
+free_dvobj:
+ if (status != _SUCCESS)
+ usb_dvobj_deinit(pusb_intf);
+exit:
+ return status == _SUCCESS ? 0 : -ENODEV;
+}
+
+/*
+ * dev_remove() - our device is being removed
+*/
+/* rmmod module & unplug(SurpriseRemoved) will call r871xu_dev_remove() => how to recognize both */
+static void rtw_dev_remove(struct usb_interface *pusb_intf)
+{
+ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
+ struct adapter *padapter = dvobj->if1;
+
+_func_enter_;
+
+ DBG_88E("+rtw_dev_remove\n");
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n"));
+
+ if (usb_drv->drv_registered)
+ padapter->bSurpriseRemoved = true;
+
+ rtw_pm_set_ips(padapter, IPS_NONE);
+ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
+
+ LeaveAllPowerSaveMode(padapter);
+
+ rtw_usb_if1_deinit(padapter);
+
+ usb_dvobj_deinit(pusb_intf);
+
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-dev_remove()\n"));
+ DBG_88E("-r871xu_dev_remove, done\n");
+_func_exit_;
+
+ return;
+}
+
+static int __init rtw_drv_entry(void)
+{
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_entry\n"));
+
+ DBG_88E(DRV_NAME " driver version=%s\n", DRIVERVERSION);
+ DBG_88E("build time: %s %s\n", __DATE__, __TIME__);
+
+ rtw_suspend_lock_init();
+
+ _rtw_mutex_init(&usb_drv->hw_init_mutex);
+
+ usb_drv->drv_registered = true;
+ return usb_register(&usb_drv->usbdrv);
+}
+
+static void __exit rtw_drv_halt(void)
+{
+ RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_halt\n"));
+ DBG_88E("+rtw_drv_halt\n");
+
+ rtw_suspend_lock_uninit();
+
+ usb_drv->drv_registered = false;
+ usb_deregister(&usb_drv->usbdrv);
+
+ _rtw_mutex_free(&usb_drv->hw_init_mutex);
+ DBG_88E("-rtw_drv_halt\n");
+}
+
+module_init(rtw_drv_entry);
+module_exit(rtw_drv_halt);
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
new file mode 100644
index 00000000000..4c71e3b93b5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
@@ -0,0 +1,288 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ ******************************************************************************/
+#define _USB_OPS_LINUX_C_
+
+#include <drv_types.h>
+#include <usb_ops_linux.h>
+#include <rtw_sreset.h>
+
+unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr)
+{
+ unsigned int pipe = 0, ep_num = 0;
+ struct usb_device *pusbd = pdvobj->pusbdev;
+
+ if (addr == RECV_BULK_IN_ADDR) {
+ pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]);
+ } else if (addr == RECV_INT_IN_ADDR) {
+ pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]);
+ } else if (addr < HW_QUEUE_ENTRY) {
+ ep_num = pdvobj->Queue2Pipe[addr];
+ pipe = usb_sndbulkpipe(pusbd, ep_num);
+ }
+
+ return pipe;
+}
+
+struct zero_bulkout_context {
+ void *pbuf;
+ void *purb;
+ void *pirp;
+ void *padapter;
+};
+
+void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
+{
+}
+
+void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
+{
+}
+
+void usb_read_port_cancel(struct intf_hdl *pintfhdl)
+{
+ int i;
+ struct recv_buf *precvbuf;
+ struct adapter *padapter = pintfhdl->padapter;
+ precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
+
+ DBG_88E("%s\n", __func__);
+
+ padapter->bReadPortCancel = true;
+
+ for (i = 0; i < NR_RECVBUFF; i++) {
+ precvbuf->reuse = true;
+ if (precvbuf->purb)
+ usb_kill_urb(precvbuf->purb);
+ precvbuf++;
+ }
+}
+
+static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
+{
+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
+ struct adapter *padapter = pxmitbuf->padapter;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct hal_data_8188e *haldata;
+
+_func_enter_;
+
+ switch (pxmitbuf->flags) {
+ case VO_QUEUE_INX:
+ pxmitpriv->voq_cnt--;
+ break;
+ case VI_QUEUE_INX:
+ pxmitpriv->viq_cnt--;
+ break;
+ case BE_QUEUE_INX:
+ pxmitpriv->beq_cnt--;
+ break;
+ case BK_QUEUE_INX:
+ pxmitpriv->bkq_cnt--;
+ break;
+ case HIGH_QUEUE_INX:
+#ifdef CONFIG_88EU_AP_MODE
+ rtw_chk_hi_queue_cmd(padapter);
+#endif
+ break;
+ default:
+ break;
+ }
+
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
+ padapter->bWritePortCancel) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+ ("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
+ padapter->bDriverStopped, padapter->bSurpriseRemoved));
+ DBG_88E("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n",
+ __func__, padapter->bDriverStopped,
+ padapter->bSurpriseRemoved, padapter->bReadPortCancel,
+ pxmitbuf->ext_tag);
+
+ goto check_completion;
+ }
+
+ if (purb->status) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete : purb->status(%d) != 0\n", purb->status));
+ DBG_88E("###=> urb_write_port_complete status(%d)\n", purb->status);
+ if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) {
+ sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL);
+ } else if (purb->status == -EINPROGRESS) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete: EINPROGESS\n"));
+ goto check_completion;
+ } else if (purb->status == -ENOENT) {
+ DBG_88E("%s: -ENOENT\n", __func__);
+ goto check_completion;
+ } else if (purb->status == -ECONNRESET) {
+ DBG_88E("%s: -ECONNRESET\n", __func__);
+ goto check_completion;
+ } else if (purb->status == -ESHUTDOWN) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete: ESHUTDOWN\n"));
+ padapter->bDriverStopped = true;
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete:bDriverStopped = true\n"));
+ goto check_completion;
+ } else {
+ padapter->bSurpriseRemoved = true;
+ DBG_88E("bSurpriseRemoved = true\n");
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete:bSurpriseRemoved = true\n"));
+
+ goto check_completion;
+ }
+ }
+
+ haldata = GET_HAL_DATA(padapter);
+ haldata->srestpriv.last_tx_complete_time = rtw_get_current_time();
+
+check_completion:
+ rtw_sctx_done_err(&pxmitbuf->sctx,
+ purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR :
+ RTW_SCTX_DONE_SUCCESS);
+
+ rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+
+ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+
+_func_exit_;
+}
+
+u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
+{
+ unsigned long irqL;
+ unsigned int pipe;
+ int status;
+ u32 ret = _FAIL;
+ struct urb *purb = NULL;
+ struct adapter *padapter = (struct adapter *)pintfhdl->padapter;
+ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem;
+ struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
+ struct usb_device *pusbd = pdvobj->pusbdev;
+
+_func_enter_;
+
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("+usb_write_port\n"));
+
+ if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||
+ (padapter->pwrctrlpriv.pnp_bstop_trx)) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+ ("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n"));
+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
+ goto exit;
+ }
+
+ _enter_critical(&pxmitpriv->lock, &irqL);
+
+ switch (addr) {
+ case VO_QUEUE_INX:
+ pxmitpriv->voq_cnt++;
+ pxmitbuf->flags = VO_QUEUE_INX;
+ break;
+ case VI_QUEUE_INX:
+ pxmitpriv->viq_cnt++;
+ pxmitbuf->flags = VI_QUEUE_INX;
+ break;
+ case BE_QUEUE_INX:
+ pxmitpriv->beq_cnt++;
+ pxmitbuf->flags = BE_QUEUE_INX;
+ break;
+ case BK_QUEUE_INX:
+ pxmitpriv->bkq_cnt++;
+ pxmitbuf->flags = BK_QUEUE_INX;
+ break;
+ case HIGH_QUEUE_INX:
+ pxmitbuf->flags = HIGH_QUEUE_INX;
+ break;
+ default:
+ pxmitbuf->flags = MGT_QUEUE_INX;
+ break;
+ }
+
+ _exit_critical(&pxmitpriv->lock, &irqL);
+
+ purb = pxmitbuf->pxmit_urb[0];
+
+ /* translate DMA FIFO addr to pipehandle */
+ pipe = ffaddr2pipehdl(pdvobj, addr);
+
+ usb_fill_bulk_urb(purb, pusbd, pipe,
+ pxmitframe->buf_addr, /* pxmitbuf->pbuf */
+ cnt,
+ usb_write_port_complete,
+ pxmitbuf);/* context is pxmitbuf */
+
+ status = usb_submit_urb(purb, GFP_ATOMIC);
+ if (!status) {
+ struct hal_data_8188e *haldata = GET_HAL_DATA(padapter);
+
+ haldata->srestpriv.last_tx_time = rtw_get_current_time();
+ } else {
+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
+ DBG_88E("usb_write_port, status =%d\n", status);
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port(): usb_submit_urb, status =%x\n", status));
+
+ switch (status) {
+ case -ENODEV:
+ padapter->bDriverStopped = true;
+ break;
+ default:
+ break;
+ }
+ goto exit;
+ }
+
+ ret = _SUCCESS;
+
+/* We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */
+
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("-usb_write_port\n"));
+
+exit:
+ if (ret != _SUCCESS)
+ rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+_func_exit_;
+ return ret;
+}
+
+void usb_write_port_cancel(struct intf_hdl *pintfhdl)
+{
+ int i, j;
+ struct adapter *padapter = pintfhdl->padapter;
+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf;
+
+ DBG_88E("%s\n", __func__);
+
+ padapter->bWritePortCancel = true;
+
+ for (i = 0; i < NR_XMITBUFF; i++) {
+ for (j = 0; j < 8; j++) {
+ if (pxmitbuf->pxmit_urb[j])
+ usb_kill_urb(pxmitbuf->pxmit_urb[j]);
+ }
+ pxmitbuf++;
+ }
+
+ pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmit_extbuf;
+ for (i = 0; i < NR_XMIT_EXTBUFF; i++) {
+ for (j = 0; j < 8; j++) {
+ if (pxmitbuf->pxmit_urb[j])
+ usb_kill_urb(pxmitbuf->pxmit_urb[j]);
+ }
+ pxmitbuf++;
+ }
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
new file mode 100644
index 00000000000..2e586c063ab
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _XMIT_OSDEP_C_
+
+#include <linux/version.h>
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <if_ether.h>
+#include <ip.h>
+#include <wifi.h>
+#include <mlme_osdep.h>
+#include <xmit_osdep.h>
+#include <osdep_intf.h>
+#include <usb_osintf.h>
+
+uint rtw_remainder_len(struct pkt_file *pfile)
+{
+ return pfile->buf_len - ((size_t)(pfile->cur_addr) -
+ (size_t)(pfile->buf_start));
+}
+
+void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile)
+{
+_func_enter_;
+
+ pfile->pkt = pktptr;
+ pfile->cur_addr = pktptr->data;
+ pfile->buf_start = pktptr->data;
+ pfile->pkt_len = pktptr->len;
+ pfile->buf_len = pktptr->len;
+
+ pfile->cur_buffer = pfile->buf_start;
+
+_func_exit_;
+}
+
+uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen)
+{
+ uint len = 0;
+
+_func_enter_;
+
+ len = rtw_remainder_len(pfile);
+ len = (rlen > len) ? len : rlen;
+
+ if (rmem)
+ skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
+
+ pfile->cur_addr += len;
+ pfile->pkt_len -= len;
+
+_func_exit_;
+
+ return len;
+}
+
+int rtw_endofpktfile(struct pkt_file *pfile)
+{
+_func_enter_;
+
+ if (pfile->pkt_len == 0) {
+ _func_exit_;
+ return true;
+ }
+
+_func_exit_;
+
+ return false;
+}
+
+void rtw_set_tx_chksum_offload(struct sk_buff *pkt, struct pkt_attrib *pattrib)
+{
+}
+
+int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz)
+{
+ int i;
+
+ pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
+ if (pxmitbuf->pallocated_buf == NULL)
+ return _FAIL;
+
+ pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
+ pxmitbuf->dma_transfer_addr = 0;
+
+ for (i = 0; i < 8; i++) {
+ pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (pxmitbuf->pxmit_urb[i] == NULL) {
+ DBG_88E("pxmitbuf->pxmit_urb[i]==NULL");
+ return _FAIL;
+ }
+ }
+ return _SUCCESS;
+}
+
+void rtw_os_xmit_resource_free(struct adapter *padapter,
+ struct xmit_buf *pxmitbuf, u32 free_sz)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ usb_free_urb(pxmitbuf->pxmit_urb[i]);
+
+ kfree(pxmitbuf->pallocated_buf);
+}
+
+#define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5)
+
+void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ u16 queue;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+ queue = skb_get_queue_mapping(pkt);
+ if (padapter->registrypriv.wifi_spec) {
+ if (__netif_subqueue_stopped(padapter->pnetdev, queue) &&
+ (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
+ netif_wake_subqueue(padapter->pnetdev, queue);
+ } else {
+ if (__netif_subqueue_stopped(padapter->pnetdev, queue))
+ netif_wake_subqueue(padapter->pnetdev, queue);
+ }
+#else
+ if (netif_queue_stopped(padapter->pnetdev))
+ netif_wake_queue(padapter->pnetdev);
+#endif
+
+ dev_kfree_skb_any(pkt);
+}
+
+void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe)
+{
+ if (pxframe->pkt)
+ rtw_os_pkt_complete(padapter, pxframe->pkt);
+ pxframe->pkt = NULL;
+}
+
+void rtw_os_xmit_schedule(struct adapter *padapter)
+{
+ unsigned long irql;
+ struct xmit_priv *pxmitpriv;
+
+ if (!padapter)
+ return;
+
+ pxmitpriv = &padapter->xmitpriv;
+
+ _enter_critical_bh(&pxmitpriv->lock, &irql);
+
+ if (rtw_txframes_pending(padapter))
+ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+
+ _exit_critical_bh(&pxmitpriv->lock, &irql);
+}
+
+static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pkt)
+{
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ u16 queue;
+
+ queue = skb_get_queue_mapping(pkt);
+ if (padapter->registrypriv.wifi_spec) {
+ /* No free space for Tx, tx_worker is too slow */
+ if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD)
+ netif_stop_subqueue(padapter->pnetdev, queue);
+ } else {
+ if (pxmitpriv->free_xmitframe_cnt <= 4) {
+ if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
+ netif_stop_subqueue(padapter->pnetdev, queue);
+ }
+ }
+}
+
+static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
+{
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ unsigned long irql;
+ struct list_head *phead, *plist;
+ struct sk_buff *newskb;
+ struct sta_info *psta = NULL;
+ s32 res;
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irql);
+ phead = &pstapriv->asoc_list;
+ plist = get_next(phead);
+
+ /* free sta asoc_queue */
+ while (!rtw_end_of_queue_search(phead, plist)) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+ plist = get_next(plist);
+
+ /* avoid come from STA1 and send back STA1 */
+ if (!memcmp(psta->hwaddr, &skb->data[6], 6))
+ continue;
+
+ newskb = skb_copy(skb, GFP_ATOMIC);
+
+ if (newskb) {
+ memcpy(newskb->data, psta->hwaddr, 6);
+ res = rtw_xmit(padapter, &newskb);
+ if (res < 0) {
+ DBG_88E("%s()-%d: rtw_xmit() return error!\n", __func__, __LINE__);
+ pxmitpriv->tx_drop++;
+ dev_kfree_skb_any(newskb);
+ } else {
+ pxmitpriv->tx_pkts++;
+ }
+ } else {
+ DBG_88E("%s-%d: skb_copy() failed!\n", __func__, __LINE__);
+ pxmitpriv->tx_drop++;
+
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irql);
+ return false; /* Caller shall tx this multicast frame via normal way. */
+ }
+ }
+
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irql);
+ dev_kfree_skb_any(skb);
+ return true;
+}
+
+
+int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
+{
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ s32 res = 0;
+
+_func_enter_;
+
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
+
+ if (rtw_if_up(padapter) == false) {
+ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
+ goto drop_packet;
+ }
+
+ rtw_check_xmit_resource(padapter, pkt);
+
+ if (!rtw_mc2u_disable && check_fwstate(pmlmepriv, WIFI_AP_STATE) &&
+ (IP_MCAST_MAC(pkt->data) || ICMPV6_MCAST_MAC(pkt->data)) &&
+ (padapter->registrypriv.wifi_spec == 0)) {
+ if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) {
+ res = rtw_mlcst2unicst(padapter, pkt);
+ if (res)
+ goto exit;
+ }
+ }
+
+ res = rtw_xmit(padapter, &pkt);
+ if (res < 0)
+ goto drop_packet;
+
+ pxmitpriv->tx_pkts++;
+ RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts));
+ goto exit;
+
+drop_packet:
+ pxmitpriv->tx_drop++;
+ dev_kfree_skb_any(pkt);
+ RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
+
+exit:
+
+_func_exit_;
+
+ return 0;
+}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
index 50c7bb77398..74fbd70d583 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h
index b9b3b52f912..dbe0e1c8705 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
index baf3b6342e4..fa5603a562c 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
index fa607f98b17..7d075d3cbe6 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
index 2b6c61c5d3d..e0684435555 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
@@ -94,6 +94,7 @@ MODULE_DEVICE_TABLE(pci, rtl8192_pci_id_tbl);
static int rtl8192_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void rtl8192_pci_disconnect(struct pci_dev *pdev);
+static irqreturn_t rtl8192_interrupt(int irq, void *netdev);
static struct pci_driver rtl8192_pci_driver = {
.name = DRV_NAME, /* Driver name */
@@ -1324,7 +1325,7 @@ static short rtl8192_init(struct net_device *dev)
(unsigned long)dev);
rtl8192_irq_disable(dev);
- if (request_irq(dev->irq, (void *)rtl8192_interrupt_rsl, IRQF_SHARED,
+ if (request_irq(dev->irq, rtl8192_interrupt, IRQF_SHARED,
dev->name, dev)) {
printk(KERN_ERR "Error allocating IRQ %d", dev->irq);
return -1;
@@ -2704,7 +2705,7 @@ out:
}
-irqreturn_type rtl8192_interrupt(int irq, void *netdev, struct pt_regs *regs)
+irqreturn_t rtl8192_interrupt(int irq, void *netdev)
{
struct net_device *dev = (struct net_device *) netdev;
struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
index 87d4d349c89..b015bf61cf0 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
@@ -88,10 +88,6 @@
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID , \
.driver_data = (kernel_ulong_t)&(cfg)
-#define irqreturn_type irqreturn_t
-
-#define rtl8192_interrupt(x, y, z) rtl8192_interrupt_rsl(x, y)
-
#define RTL_MAX_SCAN_SIZE 128
#define RTL_RATE_MAX 30
@@ -1044,8 +1040,6 @@ void rtl8192_set_chan(struct net_device *dev, short ch);
void check_rfctrl_gpio_timer(unsigned long data);
void rtl8192_hw_wakeup_wq(void *data);
-irqreturn_type rtl8192_interrupt(int irq, void *netdev, struct pt_regs *regs);
-
short rtl8192_pci_initdescring(struct net_device *dev);
void rtl8192_cancel_deferred_work(struct r8192_priv *priv);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c
index c1ccff4a832..a6778e0853c 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h
index 9452e1683a7..adea2b4c7a4 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
index 0cfb3ecaade..529ea54d168 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
index 5abbee37cdc..2ad92eee50c 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
index 28c7da677a8..356aec43796 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c
index c9a7c563b68..a8c2ade4f43 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h
index df79d6c4ca0..962f2e5b8bf 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
index 3485ef1dfab..05ef49f24cd 100644
--- a/drivers/staging/rtl8192e/rtllib.h
+++ b/drivers/staging/rtl8192e/rtllib.h
@@ -14,7 +14,7 @@
* Copyright (c) 2004, Intel Corporation
*
* Modified for Realtek's wi-fi cards by Andrea Merello
- * <andreamrl@tiscali.it>
+ * <andrea.merello@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/staging/rtl8192e/rtllib_debug.h b/drivers/staging/rtl8192e/rtllib_debug.h
index 2bfc1155f50..c59f67b2636 100644
--- a/drivers/staging/rtl8192e/rtllib_debug.h
+++ b/drivers/staging/rtl8192e/rtllib_debug.h
@@ -2,7 +2,7 @@
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192e/rtllib_module.c b/drivers/staging/rtl8192e/rtllib_module.c
index 84ea721d5d8..51d46e04d3f 100644
--- a/drivers/staging/rtl8192e/rtllib_module.c
+++ b/drivers/staging/rtl8192e/rtllib_module.c
@@ -233,7 +233,8 @@ static const struct file_operations fops = {
.open = open_debug_level,
.read = seq_read,
.llseek = seq_lseek,
- .write = write_debug_level
+ .write = write_debug_level,
+ .release = single_release,
};
int __init rtllib_init(void)
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index e75364e3eb4..8aeaed5a987 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -14,7 +14,7 @@
******************************************************************************
Few modifications for Realtek's Wi-Fi drivers by
- Andrea Merello <andreamrl@tiscali.it>
+ Andrea Merello <andrea.merello@gmail.com>
A special thanks goes to Realtek for their support !
@@ -777,6 +777,8 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb,
/* Allocate new skb for releasing to upper layer */
sub_skb = dev_alloc_skb(RTLLIB_SKBBUFFER_SIZE);
+ if (!sub_skb)
+ return 0;
skb_reserve(sub_skb, 12);
data_ptr = (u8 *)skb_put(sub_skb, skb->len);
memcpy(data_ptr, skb->data, skb->len);
@@ -825,6 +827,8 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb,
/* Allocate new skb for releasing to upper layer */
sub_skb = dev_alloc_skb(nSubframe_Length + 12);
+ if (!sub_skb)
+ return 0;
skb_reserve(sub_skb, 12);
data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length);
memcpy(data_ptr, skb->data, nSubframe_Length);
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index aefffac556a..0cbf6f5593a 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -1,5 +1,5 @@
/* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
*
* Mostly extracted from the rtl8180-sa2400 driver for the
* in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
index 740cf85e9d5..e6af8cfab12 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
@@ -1,5 +1,5 @@
/* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
*
* Mostly extracted from the rtl8180-sa2400 driver for the
* in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c
index 759d7c7d78e..1cc6a9d5e8a 100644
--- a/drivers/staging/rtl8192e/rtllib_tx.c
+++ b/drivers/staging/rtl8192e/rtllib_tx.c
@@ -25,7 +25,7 @@
******************************************************************************
Few modifications for Realtek's Wi-Fi drivers by
- Andrea Merello <andreamrl@tiscali.it>
+ Andrea Merello <andrea.merello@gmail.com>
A special thanks goes to Realtek for their support !
diff --git a/drivers/staging/rtl8192u/authors b/drivers/staging/rtl8192u/authors
index b08bbae39e7..0fab11228b4 100644
--- a/drivers/staging/rtl8192u/authors
+++ b/drivers/staging/rtl8192u/authors
@@ -1 +1 @@
-Andrea Merello <andreamrl@tiscali.it>
+Andrea Merello <andrea.merello@gmail.com>
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
index c9f3bb363be..bc64f05a7e6 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
@@ -14,7 +14,7 @@
* Copyright (c) 2004, Intel Corporation
*
* Modified for Realtek's wi-fi cards by Andrea Merello
- * <andreamrl@tiscali.it>
+ * <andrea.merello@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
index e0870c05a5e..434c4312718 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
@@ -268,7 +268,8 @@ static const struct file_operations fops = {
.open = open_debug_level,
.read = seq_read,
.llseek = seq_lseek,
- .write = write_debug_level
+ .write = write_debug_level,
+ .release = single_release,
};
int __init ieee80211_debug_init(void)
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index a6b18409103..59900bfa1c1 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -14,7 +14,7 @@
******************************************************************************
Few modifications for Realtek's Wi-Fi drivers by
- Andrea Merello <andreamrl@tiscali.it>
+ Andrea Merello <andrea.merello@gmail.com>
A special thanks goes to Realtek for their support !
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index 8a0075db925..5fd696926ee 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -1,5 +1,5 @@
/* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
*
* Mostly extracted from the rtl8180-sa2400 driver for the
* in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
index 60746b8b1eb..7b7d929f153 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
@@ -1,5 +1,5 @@
/* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
*
* Mostly extracted from the rtl8180-sa2400 driver for the
* in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index 995504207fc..a7bcc64ff22 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -25,7 +25,7 @@
******************************************************************************
Few modifications for Realtek's Wi-Fi drivers by
- Andrea Merello <andreamrl@tiscali.it>
+ Andrea Merello <andrea.merello@gmail.com>
A special thanks goes to Realtek for their support !
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.c b/drivers/staging/rtl8192u/r8180_93cx6.c
index d2199986d13..c61729b727e 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.c
+++ b/drivers/staging/rtl8192u/r8180_93cx6.c
@@ -3,7 +3,7 @@
memory is addressed by 16 bits words.
This is part of rtl8180 OpenSource driver.
- Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.h b/drivers/staging/rtl8192u/r8180_93cx6.h
index 5cea51e1142..ee55dbffe32 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.h
+++ b/drivers/staging/rtl8192u/r8180_93cx6.h
@@ -1,6 +1,6 @@
/*
This is part of rtl8187 OpenSource driver
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the official realtek driver
diff --git a/drivers/staging/rtl8192u/r8180_pm.c b/drivers/staging/rtl8192u/r8180_pm.c
index 0c58d0ed502..999968d4172 100644
--- a/drivers/staging/rtl8192u/r8180_pm.c
+++ b/drivers/staging/rtl8192u/r8180_pm.c
@@ -5,7 +5,7 @@
does not do anything useful.
This is part of rtl8180 OpenSource driver.
- Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
*/
diff --git a/drivers/staging/rtl8192u/r8180_pm.h b/drivers/staging/rtl8192u/r8180_pm.h
index 52d6fba99de..4be63da0b78 100644
--- a/drivers/staging/rtl8192u/r8180_pm.h
+++ b/drivers/staging/rtl8192u/r8180_pm.h
@@ -5,7 +5,7 @@
does not do anything useful.
This is part of rtl8180 OpenSource driver.
- Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
*/
diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.h b/drivers/staging/rtl8192u/r8190_rtl8256.h
index b64dd662761..592e7807fa4 100644
--- a/drivers/staging/rtl8192u/r8190_rtl8256.h
+++ b/drivers/staging/rtl8192u/r8190_rtl8256.h
@@ -1,7 +1,7 @@
/*
This is part of the rtl8180-sa2400 driver
released under the GPL (See file COPYING for details).
- Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
This files contains programming code for the rtl8256
radio frontend.
diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h
index 338e7bc237c..b484ee128c1 100644
--- a/drivers/staging/rtl8192u/r8192U.h
+++ b/drivers/staging/rtl8192u/r8192U.h
@@ -1,6 +1,6 @@
/*
* This is part of rtl8187 OpenSource driver.
- * Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
+ * Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
* Released under the terms of GPL (General Public Licence)
*
* Parts of this driver are based on the GPL part of the
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index 14c14c24ac5..cd0946db025 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -3,7 +3,7 @@
* Linux device driver for RTL8192U
*
* Based on the r8187 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
diff --git a/drivers/staging/rtl8192u/r8192U_hw.h b/drivers/staging/rtl8192u/r8192U_hw.h
index 7e612aa56fa..dd07a735b53 100644
--- a/drivers/staging/rtl8192u/r8192U_hw.h
+++ b/drivers/staging/rtl8192u/r8192U_hw.h
@@ -1,6 +1,6 @@
/*
This is part of rtl8187 OpenSource driver.
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the
diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c
index 3e2576347d2..61f6620213e 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.c
+++ b/drivers/staging/rtl8192u/r8192U_wx.c
@@ -2,7 +2,7 @@
This file contains wireless extension handlers.
This is part of rtl8180 OpenSource driver.
- Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part
diff --git a/drivers/staging/rtl8192u/r8192U_wx.h b/drivers/staging/rtl8192u/r8192U_wx.h
index 9f6b1050542..ae7a617740a 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.h
+++ b/drivers/staging/rtl8192u/r8192U_wx.h
@@ -1,6 +1,6 @@
/*
This is part of rtl8180 OpenSource driver - v 0.3
- Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
+ Copyright (C) Andrea Merello 2004 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the official realtek driver
diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
index 6810766edfc..5bc361b16d4 100644
--- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c
+++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
@@ -1,81 +1,61 @@
/******************************************************************************
-
- (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
-
- Module: r819xusb_cmdpkt.c (RTL8190 TX/RX command packet handler Source C File)
-
- Note: The module is responsible for handling TX and RX command packet.
- 1. TX : Send set and query configuration command packet.
- 2. RX : Receive tx feedback, beacon state, query configuration
- command packet.
-
- Function:
-
- Export:
-
- Abbrev:
-
- History:
- Data Who Remark
-
- 05/06/2008 amy Create initial version porting from windows driver.
-
-******************************************************************************/
+ *
+ * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
+ *
+ * Module: r819xusb_cmdpkt.c
+ * (RTL8190 TX/RX command packet handler Source C File)
+ *
+ * Note: The module is responsible for handling TX and RX command packet.
+ * 1. TX : Send set and query configuration command packet.
+ * 2. RX : Receive tx feedback, beacon state, query configuration
+ * command packet.
+ *
+ * Function:
+ *
+ * Export:
+ *
+ * Abbrev:
+ *
+ * History:
+ *
+ * Date Who Remark
+ * 05/06/2008 amy Create initial version porting from
+ * windows driver.
+ *
+ ******************************************************************************/
#include "r8192U.h"
#include "r819xU_cmdpkt.h"
-/*---------------------------Define Local Constant---------------------------*/
-/* Debug constant*/
-#define CMPK_DEBOUNCE_CNT 1
-/* 2007/10/24 MH Add for printing a range of data. */
-#define CMPK_PRINT(Address)\
-{\
- unsigned char i;\
- u32 temp[10];\
- \
- memcpy(temp, Address, 40);\
- for (i = 0; i <40; i+=4)\
- printk("\r\n %08x", temp[i]);\
-}\
-/*---------------------------Define functions---------------------------------*/
-
-rt_status
-SendTxCommandPacket(
- struct net_device *dev,
- void *pData,
- u32 DataLen
- )
+
+rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
{
rt_status rtStatus = RT_STATUS_SUCCESS;
struct r8192_priv *priv = ieee80211_priv(dev);
struct sk_buff *skb;
cb_desc *tcb_desc;
unsigned char *ptr_buf;
- //bool bLastInitPacket = false;
- //PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
-
- //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
+ /* Get TCB and local buffer from common pool.
+ (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) */
skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
- memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
+ memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
tcb_desc->queue_index = TXCMD_QUEUE;
tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
tcb_desc->bLastIniPkt = 0;
skb_reserve(skb, USB_HWDESC_HEADER_LEN);
ptr_buf = skb_put(skb, DataLen);
- memcpy(ptr_buf,pData,DataLen);
- tcb_desc->txbuf_size= (u16)DataLen;
-
- if (!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
- (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
- (priv->ieee80211->queue_stop) ) {
- RT_TRACE(COMP_FIRMWARE,"===================NULL packet==================================> tx full!\n");
- skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
- } else {
- priv->ieee80211->softmac_hard_start_xmit(skb,dev);
- }
+ memcpy(ptr_buf, pData, DataLen);
+ tcb_desc->txbuf_size = (u16)DataLen;
+
+ if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
+ (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
+ (priv->ieee80211->queue_stop)) {
+ RT_TRACE(COMP_FIRMWARE, "=== NULL packet ======> tx full!\n");
+ skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
+ } else {
+ priv->ieee80211->softmac_hard_start_xmit(skb, dev);
+ }
- //PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
return rtStatus;
}
@@ -83,27 +63,25 @@ SendTxCommandPacket(
* Function: cmpk_message_handle_tx()
*
* Overview: Driver internal module can call the API to send message to
- * firmware side. For example, you can send a debug command packet.
- * Or you can send a request for FW to modify RLX4181 LBUS HW bank.
- * Otherwise, you can change MAC/PHT/RF register by firmware at
- * run time. We do not support message more than one segment now.
+ * firmware side. For example, you can send a debug command packet.
+ * Or you can send a request for FW to modify RLX4181 LBUS HW bank.
+ * Otherwise, you can change MAC/PHT/RF register by firmware at
+ * run time. We do not support message more than one segment now.
*
- * Input: NONE
+ * Input: NONE
*
- * Output: NONE
+ * Output: NONE
*
- * Return: NONE
+ * Return: NONE
*
* Revised History:
* When Who Remark
* 05/06/2008 amy porting from windows code.
*
*---------------------------------------------------------------------------*/
- extern rt_status cmpk_message_handle_tx(
- struct net_device *dev,
- u8 *codevirtualaddress,
- u32 packettype,
- u32 buffer_len)
+extern rt_status cmpk_message_handle_tx(struct net_device *dev,
+ u8 *codevirtualaddress,
+ u32 packettype, u32 buffer_len)
{
bool rt_status = true;
@@ -113,8 +91,6 @@ SendTxCommandPacket(
struct r8192_priv *priv = ieee80211_priv(dev);
u16 frag_threshold;
u16 frag_length, frag_offset = 0;
- //u16 total_size;
- //int i;
rt_firmware *pfirmware = priv->pFirmware;
struct sk_buff *skb;
@@ -123,11 +99,11 @@ SendTxCommandPacket(
u8 bLastIniPkt;
firmware_init_param(dev);
- //Fragmentation might be required
+ /* Fragmentation might be required */
frag_threshold = pfirmware->cmdpacket_frag_thresold;
do {
if ((buffer_len - frag_offset) > frag_threshold) {
- frag_length = frag_threshold ;
+ frag_length = frag_threshold;
bLastIniPkt = 0;
} else {
@@ -136,146 +112,127 @@ SendTxCommandPacket(
}
- /* Allocate skb buffer to contain firmware info and tx descriptor info
- * add 4 to avoid packet appending overflow.
- * */
- #ifdef RTL8192U
+ /* Allocate skb buffer to contain firmware info and tx
+ descriptor info add 4 to avoid packet appending overflow. */
+#ifdef RTL8192U
skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
- #else
+#else
skb = dev_alloc_skb(frag_length + 4);
- #endif
- memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
+#endif
+ memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
tcb_desc->queue_index = TXCMD_QUEUE;
tcb_desc->bCmdOrInit = packettype;
tcb_desc->bLastIniPkt = bLastIniPkt;
- #ifdef RTL8192U
+#ifdef RTL8192U
skb_reserve(skb, USB_HWDESC_HEADER_LEN);
- #endif
+#endif
seg_ptr = skb_put(skb, buffer_len);
/*
* Transform from little endian to big endian
* and pending zero
*/
- memcpy(seg_ptr,codevirtualaddress,buffer_len);
- tcb_desc->txbuf_size= (u16)buffer_len;
+ memcpy(seg_ptr, codevirtualaddress, buffer_len);
+ tcb_desc->txbuf_size = (u16)buffer_len;
- if (!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
- (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
- (priv->ieee80211->queue_stop) ) {
- RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n");
+ if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
+ (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
+ (priv->ieee80211->queue_stop)) {
+ RT_TRACE(COMP_FIRMWARE, "======> tx full!\n");
skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
} else {
- priv->ieee80211->softmac_hard_start_xmit(skb,dev);
+ priv->ieee80211->softmac_hard_start_xmit(skb, dev);
}
codevirtualaddress += frag_length;
frag_offset += frag_length;
- }while(frag_offset < buffer_len);
+ } while (frag_offset < buffer_len);
return rt_status;
#endif
-} /* CMPK_Message_Handle_Tx */
+}
/*-----------------------------------------------------------------------------
* Function: cmpk_counttxstatistic()
*
* Overview:
*
- * Input: PADAPTER pAdapter - .
- * CMPK_TXFB_T *psTx_FB - .
+ * Input: PADAPTER pAdapter
+ * CMPK_TXFB_T *psTx_FB
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
- * When Who Remark
- * 05/12/2008 amy Create Version 0 porting from windows code.
+ * When Who Remark
+ * 05/12/2008 amy Create Version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
-static void
-cmpk_count_txstatistic(
- struct net_device *dev,
- cmpk_txfb_t *pstx_fb)
+static void cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb)
{
struct r8192_priv *priv = ieee80211_priv(dev);
#ifdef ENABLE_PS
RT_RF_POWER_STATE rtState;
- pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
+ pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
+ (pu1Byte)(&rtState));
- // When RF is off, we should not count the packet for hw/sw synchronize
- // reason, ie. there may be a duration while sw switch is changed and hw
- // switch is being changed. 2006.12.04, by shien chang.
+ /* When RF is off, we should not count the packet for hw/sw synchronize
+ reason, ie. there may be a duration while sw switch is changed and
+ hw switch is being changed. */
if (rtState == eRfOff)
- {
return;
- }
#endif
#ifdef TODO
if (pAdapter->bInHctTest)
return;
#endif
- /* We can not know the packet length and transmit type: broadcast or uni
- or multicast. So the relative statistics must be collected in tx
- feedback info. */
- if (pstx_fb->tok)
- {
+ /* We can not know the packet length and transmit type:
+ broadcast or uni or multicast. So the relative statistics
+ must be collected in tx feedback info. */
+ if (pstx_fb->tok) {
priv->stats.txfeedbackok++;
priv->stats.txoktotal++;
priv->stats.txokbytestotal += pstx_fb->pkt_length;
priv->stats.txokinperiod++;
/* We can not make sure broadcast/multicast or unicast mode. */
- if (pstx_fb->pkt_type == PACKET_MULTICAST)
- {
+ if (pstx_fb->pkt_type == PACKET_MULTICAST) {
priv->stats.txmulticast++;
priv->stats.txbytesmulticast += pstx_fb->pkt_length;
- }
- else if (pstx_fb->pkt_type == PACKET_BROADCAST)
- {
+ } else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
priv->stats.txbroadcast++;
priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
- }
- else
- {
+ } else {
priv->stats.txunicast++;
priv->stats.txbytesunicast += pstx_fb->pkt_length;
}
- }
- else
- {
+ } else {
priv->stats.txfeedbackfail++;
priv->stats.txerrtotal++;
priv->stats.txerrbytestotal += pstx_fb->pkt_length;
/* We can not make sure broadcast/multicast or unicast mode. */
if (pstx_fb->pkt_type == PACKET_MULTICAST)
- {
priv->stats.txerrmulticast++;
- }
else if (pstx_fb->pkt_type == PACKET_BROADCAST)
- {
priv->stats.txerrbroadcast++;
- }
else
- {
priv->stats.txerrunicast++;
- }
}
priv->stats.txretrycount += pstx_fb->retry_cnt;
priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
-} /* cmpk_CountTxStatistic */
+}
@@ -283,80 +240,63 @@ cmpk_count_txstatistic(
* Function: cmpk_handle_tx_feedback()
*
* Overview: The function is responsible for extract the message inside TX
- * feedbck message from firmware. It will contain dedicated info in
- * ws-06-0063-rtl8190-command-packet-specification. Please
- * refer to chapter "TX Feedback Element". We have to read 20 bytes
- * in the command packet.
+ * feedbck message from firmware. It will contain dedicated info in
+ * ws-06-0063-rtl8190-command-packet-specification.
+ * Please refer to chapter "TX Feedback Element".
+ * We have to read 20 bytes in the command packet.
*
- * Input: struct net_device * dev
- * u8 * pmsg - Msg Ptr of the command packet.
+ * Input: struct net_device *dev
+ * u8 *pmsg - Msg Ptr of the command packet.
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
- * When Who Remark
- * 05/08/2008 amy Create Version 0 porting from windows code.
+ * When Who Remark
+ * 05/08/2008 amy Create Version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
-static void
-cmpk_handle_tx_feedback(
- struct net_device *dev,
- u8 *pmsg)
+static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- cmpk_txfb_t rx_tx_fb; /* */
+ cmpk_txfb_t rx_tx_fb;
priv->stats.txfeedback++;
- /* 0. Display received message. */
- //cmpk_Display_Message(CMPK_RX_TX_FB_SIZE, pMsg);
-
/* 1. Extract TX feedback info from RFD to temp structure buffer. */
/* It seems that FW use big endian(MIPS) and DRV use little endian in
windows OS. So we have to read the content byte by byte or transfer
endian type before copy the message copy. */
- /* 2007/07/05 MH Use pointer to transfer structure memory. */
- //memcpy((UINT8 *)&rx_tx_fb, pMsg, sizeof(CMPK_TXFB_T));
+ /* Use pointer to transfer structure memory. */
memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
/* 2. Use tx feedback info to count TX statistics. */
cmpk_count_txstatistic(dev, &rx_tx_fb);
- /* 2007/01/17 MH Comment previous method for TX statistic function. */
+ /* Comment previous method for TX statistic function. */
/* Collect info TX feedback packet to fill TCB. */
/* We can not know the packet length and transmit type: broadcast or uni
or multicast. */
- //CountTxStatistics( pAdapter, &tcb );
-} /* cmpk_Handle_Tx_Feedback */
+}
-void
-cmdpkt_beacontimerinterrupt_819xusb(
- struct net_device *dev
-)
+void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u16 tx_rate;
- {
- //
- // 070117, rcnjko: 87B have to S/W beacon for DTM encryption_cmn.
- //
- if (priv->ieee80211->current_network.mode == IEEE_A ||
+ /* 87B have to S/W beacon for DTM encryption_cmn. */
+ if (priv->ieee80211->current_network.mode == IEEE_A ||
priv->ieee80211->current_network.mode == IEEE_N_5G ||
- (priv->ieee80211->current_network.mode == IEEE_N_24G && (!priv->ieee80211->pHTInfo->bCurSuppCCK)))
- {
+ (priv->ieee80211->current_network.mode == IEEE_N_24G &&
+ (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
tx_rate = 60;
DMESG("send beacon frame tx rate is 6Mbpm\n");
- }
- else
- {
- tx_rate =10;
+ } else {
+ tx_rate = 10;
DMESG("send beacon frame tx rate is 1Mbpm\n");
}
- rtl819xusb_beacon_tx(dev,tx_rate); // HW Beacon
+ rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
- }
}
@@ -367,151 +307,129 @@ cmdpkt_beacontimerinterrupt_819xusb(
* Function: cmpk_handle_interrupt_status()
*
* Overview: The function is responsible for extract the message from
- * firmware. It will contain dedicated info in
- * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
- * Please refer to chapter "Interrupt Status Element".
+ * firmware. It will contain dedicated info in
+ * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
+ * Please refer to chapter "Interrupt Status Element".
*
- * Input: struct net_device *dev,
- * u8* pmsg - Message Pointer of the command packet.
+ * Input: struct net_device *dev
+ * u8 *pmsg - Message Pointer of the command packet.
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
- * When Who Remark
- * 05/12/2008 amy Add this for rtl8192 porting from windows code.
+ * When Who Remark
+ * 05/12/2008 amy Add this for rtl8192 porting from windows code.
*
*---------------------------------------------------------------------------*/
-static void
-cmpk_handle_interrupt_status(
- struct net_device *dev,
- u8 *pmsg)
+static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
{
cmpk_intr_sta_t rx_intr_status; /* */
struct r8192_priv *priv = ieee80211_priv(dev);
DMESG("---> cmpk_Handle_Interrupt_Status()\n");
- /* 0. Display received message. */
- //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
-
/* 1. Extract TX feedback info from RFD to temp structure buffer. */
/* It seems that FW use big endian(MIPS) and DRV use little endian in
windows OS. So we have to read the content byte by byte or transfer
endian type before copy the message copy. */
- //rx_bcn_state.Element_ID = pMsg[0];
- //rx_bcn_state.Length = pMsg[1];
rx_intr_status.length = pmsg[1];
- if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
- {
+ if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) {
DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
return;
}
- // Statistics of beacon for ad-hoc mode.
- if ( priv->ieee80211->iw_mode == IW_MODE_ADHOC)
- {
- //2 maybe need endian transform?
+ /* Statistics of beacon for ad-hoc mode. */
+ if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
+ /* 2 maybe need endian transform? */
rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
- //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
- DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
+ DMESG("interrupt status = 0x%x\n",
+ rx_intr_status.interrupt_status);
- if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
- {
+ if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
priv->ieee80211->bibsscoordinator = true;
priv->stats.txbeaconokint++;
- }
- else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
- {
+ } else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
priv->ieee80211->bibsscoordinator = false;
priv->stats.txbeaconerr++;
}
if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
- {
cmdpkt_beacontimerinterrupt_819xusb(dev);
- }
}
- // Other informations in interrupt status we need?
+ /* Other informations in interrupt status we need? */
DMESG("<---- cmpk_handle_interrupt_status()\n");
-} /* cmpk_handle_interrupt_status */
+}
/*-----------------------------------------------------------------------------
* Function: cmpk_handle_query_config_rx()
*
* Overview: The function is responsible for extract the message from
- * firmware. It will contain dedicated info in
- * ws-06-0063-rtl8190-command-packet-specification. Please
- * refer to chapter "Beacon State Element".
+ * firmware. It will contain dedicated info in
+ * ws-06-0063-rtl8190-command-packet-specification. Please
+ * refer to chapter "Beacon State Element".
*
- * Input: u8 * pmsg - Message Pointer of the command packet.
+ * Input: u8 *pmsg - Message Pointer of the command packet.
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
- * When Who Remark
- * 05/12/2008 amy Create Version 0 porting from windows code.
+ * When Who Remark
+ * 05/12/2008 amy Create Version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
-static void
-cmpk_handle_query_config_rx(
- struct net_device *dev,
- u8 *pmsg)
+static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
{
- cmpk_query_cfg_t rx_query_cfg; /* */
+ cmpk_query_cfg_t rx_query_cfg;
- /* 0. Display received message. */
- //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
/* 1. Extract TX feedback info from RFD to temp structure buffer. */
/* It seems that FW use big endian(MIPS) and DRV use little endian in
windows OS. So we have to read the content byte by byte or transfer
endian type before copy the message copy. */
- //rx_query_cfg.Element_ID = pMsg[0];
- //rx_query_cfg.Length = pMsg[1];
- rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
+ rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000) >> 31;
rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
- rx_query_cfg.cfg_offset = pmsg[7];
- rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
- (pmsg[10] << 8) | (pmsg[11] << 0);
- rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
- (pmsg[14] << 8) | (pmsg[15] << 0);
+ rx_query_cfg.cfg_offset = pmsg[7];
+ rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
+ (pmsg[10] << 8) | (pmsg[11] << 0);
+ rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
+ (pmsg[14] << 8) | (pmsg[15] << 0);
-} /* cmpk_Handle_Query_Config_Rx */
+}
/*-----------------------------------------------------------------------------
* Function: cmpk_count_tx_status()
*
* Overview: Count aggregated tx status from firmwar of one type rx command
- * packet element id = RX_TX_STATUS.
+ * packet element id = RX_TX_STATUS.
*
- * Input: NONE
+ * Input: NONE
*
- * Output: NONE
+ * Output: NONE
*
- * Return: NONE
+ * Return: NONE
*
* Revised History:
- * When Who Remark
- * 05/12/2008 amy Create Version 0 porting from windows code.
+ * When Who Remark
+ * 05/12/2008 amy Create Version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
-static void cmpk_count_tx_status( struct net_device *dev,
- cmpk_tx_status_t *pstx_status)
+static void cmpk_count_tx_status(struct net_device *dev,
+ cmpk_tx_status_t *pstx_status)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -519,15 +437,14 @@ static void cmpk_count_tx_status( struct net_device *dev,
RT_RF_POWER_STATE rtstate;
- pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
+ pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
+ (pu1Byte)(&rtState));
- // When RF is off, we should not count the packet for hw/sw synchronize
- // reason, ie. there may be a duration while sw switch is changed and hw
- // switch is being changed. 2006.12.04, by shien chang.
+ /* When RF is off, we should not count the packet for hw/sw synchronize
+ reason, ie. there may be a duration while sw switch is changed and
+ hw switch is being changed. */
if (rtState == eRfOff)
- {
return;
- }
#endif
priv->stats.txfeedbackok += pstx_status->txok;
@@ -536,15 +453,12 @@ static void cmpk_count_tx_status( struct net_device *dev,
priv->stats.txfeedbackfail += pstx_status->txfail;
priv->stats.txerrtotal += pstx_status->txfail;
- priv->stats.txretrycount += pstx_status->txretry;
+ priv->stats.txretrycount += pstx_status->txretry;
priv->stats.txfeedbackretry += pstx_status->txretry;
- //pAdapter->TxStats.NumTxOkBytesTotal += psTx_FB->pkt_length;
- //pAdapter->TxStats.NumTxErrBytesTotal += psTx_FB->pkt_length;
- //pAdapter->MgntInfo.LinkDetectInfo.NumTxOkInPeriod++;
- priv->stats.txmulticast += pstx_status->txmcok;
- priv->stats.txbroadcast += pstx_status->txbcok;
+ priv->stats.txmulticast += pstx_status->txmcok;
+ priv->stats.txbroadcast += pstx_status->txbcok;
priv->stats.txunicast += pstx_status->txucok;
priv->stats.txerrmulticast += pstx_status->txmcfail;
@@ -553,10 +467,10 @@ static void cmpk_count_tx_status( struct net_device *dev,
priv->stats.txbytesmulticast += pstx_status->txmclength;
priv->stats.txbytesbroadcast += pstx_status->txbclength;
- priv->stats.txbytesunicast += pstx_status->txuclength;
+ priv->stats.txbytesunicast += pstx_status->txuclength;
- priv->stats.last_packet_rate = pstx_status->rate;
-} /* cmpk_CountTxStatus */
+ priv->stats.last_packet_rate = pstx_status->rate;
+}
@@ -564,7 +478,7 @@ static void cmpk_count_tx_status( struct net_device *dev,
* Function: cmpk_handle_tx_status()
*
* Overview: Firmware add a new tx feedback status to reduce rx command
- * packet buffer operation load.
+ * packet buffer operation load.
*
* Input: NONE
*
@@ -573,22 +487,19 @@ static void cmpk_count_tx_status( struct net_device *dev,
* Return: NONE
*
* Revised History:
- * When Who Remark
- * 05/12/2008 amy Create Version 0 porting from windows code.
+ * When Who Remark
+ * 05/12/2008 amy Create Version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
-static void
-cmpk_handle_tx_status(
- struct net_device *dev,
- u8 *pmsg)
+static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
{
- cmpk_tx_status_t rx_tx_sts; /* */
+ cmpk_tx_status_t rx_tx_sts;
memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
/* 2. Use tx feedback info to count TX statistics. */
cmpk_count_tx_status(dev, &rx_tx_sts);
-} /* cmpk_Handle_Tx_Status */
+}
/*-----------------------------------------------------------------------------
@@ -603,82 +514,71 @@ cmpk_handle_tx_status(
* Return: NONE
*
* Revised History:
- * When Who Remark
- * 05/12/2008 amy Create Version 0 porting from windows code.
+ * When Who Remark
+ * 05/12/2008 amy Create Version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
-static void
-cmpk_handle_tx_rate_history(
- struct net_device *dev,
- u8 *pmsg)
+static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
{
cmpk_tx_rahis_t *ptxrate;
-// RT_RF_POWER_STATE rtState;
- u8 i, j;
- u16 length = sizeof(cmpk_tx_rahis_t);
- u32 *ptemp;
+ u8 i, j;
+ u16 length = sizeof(cmpk_tx_rahis_t);
+ u32 *ptemp;
struct r8192_priv *priv = ieee80211_priv(dev);
#ifdef ENABLE_PS
- pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
+ pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
+ (pu1Byte)(&rtState));
- // When RF is off, we should not count the packet for hw/sw synchronize
- // reason, ie. there may be a duration while sw switch is changed and hw
- // switch is being changed. 2006.12.04, by shien chang.
+ /* When RF is off, we should not count the packet for hw/sw synchronize
+ reason, ie. there may be a duration while sw switch is changed and
+ hw switch is being changed. */
if (rtState == eRfOff)
- {
return;
- }
#endif
ptemp = (u32 *)pmsg;
- //
- // Do endian transfer to word alignment(16 bits) for windows system.
- // You must do different endian transfer for linux and MAC OS
- //
- for (i = 0; i < (length/4); i++)
- {
+ /* Do endian transfer to word alignment(16 bits) for windows system.
+ You must do different endian transfer for linux and MAC OS */
+ for (i = 0; i < (length/4); i++) {
u16 temp1, temp2;
- temp1 = ptemp[i]&0x0000FFFF;
- temp2 = ptemp[i]>>16;
- ptemp[i] = (temp1<<16)|temp2;
+ temp1 = ptemp[i] & 0x0000FFFF;
+ temp2 = ptemp[i] >> 16;
+ ptemp[i] = (temp1 << 16) | temp2;
}
ptxrate = (cmpk_tx_rahis_t *)pmsg;
- if (ptxrate == NULL )
- {
+ if (ptxrate == NULL)
return;
- }
- for (i = 0; i < 16; i++)
- {
- // Collect CCK rate packet num
+ for (i = 0; i < 16; i++) {
+ /* Collect CCK rate packet num */
if (i < 4)
priv->stats.txrate.cck[i] += ptxrate->cck[i];
- // Collect OFDM rate packet num
- if (i< 8)
+ /* Collect OFDM rate packet num */
+ if (i < 8)
priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
for (j = 0; j < 4; j++)
priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
}
-} /* cmpk_Handle_Tx_Rate_History */
+}
/*-----------------------------------------------------------------------------
* Function: cmpk_message_handle_rx()
*
* Overview: In the function, we will capture different RX command packet
- * info. Every RX command packet element has different message
- * length and meaning in content. We only support three type of RX
- * command packet now. Please refer to document
- * ws-06-0063-rtl8190-command-packet-specification.
+ * info. Every RX command packet element has different message
+ * length and meaning in content. We only support three type of RX
+ * command packet now. Please refer to document
+ * ws-06-0063-rtl8190-command-packet-specification.
*
* Input: NONE
*
@@ -687,30 +587,22 @@ cmpk_handle_tx_rate_history(
* Return: NONE
*
* Revised History:
- * When Who Remark
- * 05/06/2008 amy Create Version 0 porting from windows code.
+ * When Who Remark
+ * 05/06/2008 amy Create Version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
-extern u32
-cmpk_message_handle_rx(
- struct net_device *dev,
- struct ieee80211_rx_stats *pstats)
+extern u32 cmpk_message_handle_rx(struct net_device *dev,
+ struct ieee80211_rx_stats *pstats)
{
-// u32 debug_level = DBG_LOUD;
int total_length;
u8 cmd_length, exe_cnt = 0;
u8 element_id;
u8 *pcmd_buff;
- /* 0. Check inpt arguments. If is is a command queue message or pointer is
- null. */
- if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
- {
- /* Print error message. */
- /*RT_TRACE(COMP_SEND, DebugLevel,
- ("\n\r[CMPK]-->Err queue id or pointer"));*/
+ /* 0. Check inpt arguments. If is is a command queue message or
+ pointer is null. */
+ if (pstats == NULL)
return 0; /* This is not a command packet. */
- }
/* 1. Read received command packet message length from RFD. */
total_length = pstats->Length;
@@ -720,67 +612,58 @@ cmpk_message_handle_rx(
/* 3. Read command packet element id and length. */
element_id = pcmd_buff[0];
- /*RT_TRACE(COMP_SEND, DebugLevel,
- ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
/* 4. Check every received command packet content according to different
- element type. Because FW may aggregate RX command packet to minimize
- transmit time between DRV and FW.*/
- // Add a counter to prevent the lock in the loop from being held too long
- while (total_length > 0 && exe_cnt++ < 100)
- {
- /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
+ element type. Because FW may aggregate RX command packet to
+ minimize transmit time between DRV and FW.*/
+ /* Add a counter to prevent the lock in the loop from being held too
+ long */
+ while (total_length > 0 && exe_cnt++ < 100) {
+ /* We support aggregation of different cmd in the same packet */
element_id = pcmd_buff[0];
- switch (element_id)
- {
- case RX_TX_FEEDBACK:
- cmpk_handle_tx_feedback (dev, pcmd_buff);
- cmd_length = CMPK_RX_TX_FB_SIZE;
- break;
-
- case RX_INTERRUPT_STATUS:
- cmpk_handle_interrupt_status(dev, pcmd_buff);
- cmd_length = sizeof(cmpk_intr_sta_t);
- break;
-
- case BOTH_QUERY_CONFIG:
- cmpk_handle_query_config_rx(dev, pcmd_buff);
- cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
- break;
-
- case RX_TX_STATUS:
- cmpk_handle_tx_status(dev, pcmd_buff);
- cmd_length = CMPK_RX_TX_STS_SIZE;
- break;
-
- case RX_TX_PER_PKT_FEEDBACK:
- // You must at lease add a switch case element here,
- // Otherwise, we will jump to default case.
- //DbgPrint("CCX Test\r\n");
- cmd_length = CMPK_RX_TX_FB_SIZE;
- break;
-
- case RX_TX_RATE_HISTORY:
- //DbgPrint(" rx tx rate history\r\n");
- cmpk_handle_tx_rate_history(dev, pcmd_buff);
- cmd_length = CMPK_TX_RAHIS_SIZE;
- break;
-
- default:
-
- RT_TRACE(COMP_ERR, "---->cmpk_message_handle_rx():unknow CMD Element\n");
- return 1; /* This is a command packet. */
+ switch (element_id) {
+ case RX_TX_FEEDBACK:
+ cmpk_handle_tx_feedback(dev, pcmd_buff);
+ cmd_length = CMPK_RX_TX_FB_SIZE;
+ break;
+
+ case RX_INTERRUPT_STATUS:
+ cmpk_handle_interrupt_status(dev, pcmd_buff);
+ cmd_length = sizeof(cmpk_intr_sta_t);
+ break;
+
+ case BOTH_QUERY_CONFIG:
+ cmpk_handle_query_config_rx(dev, pcmd_buff);
+ cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
+ break;
+
+ case RX_TX_STATUS:
+ cmpk_handle_tx_status(dev, pcmd_buff);
+ cmd_length = CMPK_RX_TX_STS_SIZE;
+ break;
+
+ case RX_TX_PER_PKT_FEEDBACK:
+ /* You must at lease add a switch case element here,
+ Otherwise, we will jump to default case. */
+ cmd_length = CMPK_RX_TX_FB_SIZE;
+ break;
+
+ case RX_TX_RATE_HISTORY:
+ cmpk_handle_tx_rate_history(dev, pcmd_buff);
+ cmd_length = CMPK_TX_RAHIS_SIZE;
+ break;
+
+ default:
+
+ RT_TRACE(COMP_ERR, "---->%s():unknown CMD Element\n",
+ __func__);
+ return 1; /* This is a command packet. */
}
- // 2007/01/22 MH Display received rx command packet info.
- //cmpk_Display_Message(cmd_length, pcmd_buff);
-
- // 2007/01/22 MH Add to display tx statistic.
- //cmpk_DisplayTxStatistic(pAdapter);
total_length -= cmd_length;
pcmd_buff += cmd_length;
- } /* while (total_length > 0) */
+ }
return 1; /* This is a command packet. */
-} /* CMPK_Message_Handle_Rx */
+}
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index f034567122d..d58aa7e3b15 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -1000,12 +1000,8 @@ static int r871x_wx_set_priv(struct net_device *dev,
sprintf(ext, "LINKSPEED %d", mbps);
} else if (0 == strcasecmp(ext, "MACADDR")) {
/*Return mac address of the station */
- /*Macaddr = xx.xx.xx.xx.xx.xx */
- sprintf(ext,
- "MACADDR = %02x.%02x.%02x.%02x.%02x.%02x",
- *(dev->dev_addr), *(dev->dev_addr+1),
- *(dev->dev_addr+2), *(dev->dev_addr+3),
- *(dev->dev_addr+4), *(dev->dev_addr+5));
+ /* Macaddr = xx:xx:xx:xx:xx:xx */
+ sprintf(ext, "MACADDR = %pM", dev->dev_addr);
} else if (0 == strcasecmp(ext, "SCAN-ACTIVE")) {
/*Set scan type to active */
/*OK if successful */
diff --git a/drivers/staging/silicom/bpctl_mod.c b/drivers/staging/silicom/bpctl_mod.c
index 48b9fb110ac..495272d0134 100644
--- a/drivers/staging/silicom/bpctl_mod.c
+++ b/drivers/staging/silicom/bpctl_mod.c
@@ -59,7 +59,7 @@ struct bypass_pfs_sd {
struct proc_dir_entry *bypass_entry;
};
-typedef struct _bpctl_dev {
+struct bpctl_dev {
char *name;
char *desc;
struct pci_dev *pdev; /* PCI device */
@@ -102,26 +102,26 @@ typedef struct _bpctl_dev {
char *bp_tx_data;
struct bypass_pfs_sd bypass_pfs_set;
-} bpctl_dev_t;
+};
-static bpctl_dev_t *bpctl_dev_arr;
+static struct bpctl_dev *bpctl_dev_arr;
static struct semaphore bpctl_sema;
static int device_num;
static int get_dev_idx(int ifindex);
-static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev);
-static int disc_status(bpctl_dev_t *pbpctl_dev);
-static int bypass_status(bpctl_dev_t *pbpctl_dev);
-static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left);
-static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev);
+static struct bpctl_dev *get_master_port_fn(struct bpctl_dev *pbpctl_dev);
+static int disc_status(struct bpctl_dev *pbpctl_dev);
+static int bypass_status(struct bpctl_dev *pbpctl_dev);
+static int wdt_timer(struct bpctl_dev *pbpctl_dev, int *time_left);
+static struct bpctl_dev *get_status_port_fn(struct bpctl_dev *pbpctl_dev);
static void if_scan_init(void);
-int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block);
-int bypass_proc_remove_dev_sd(bpctl_dev_t *pbp_device_block);
+int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block);
+int bypass_proc_remove_dev_sd(struct bpctl_dev *pbp_device_block);
int bp_proc_create(void);
-int is_bypass_fn(bpctl_dev_t *pbpctl_dev);
+int is_bypass_fn(struct bpctl_dev *pbpctl_dev);
int get_dev_idx_bsf(int bus, int slot, int func);
static unsigned long str_to_hex(char *p);
@@ -129,7 +129,7 @@ static int bp_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- static bpctl_dev_t *pbpctl_dev, *pbpctl_dev_m;
+ static struct bpctl_dev *pbpctl_dev, *pbpctl_dev_m;
int dev_num = 0, ret = 0, ret_d = 0, time_left = 0;
/* printk("BP_PROC_SUPPORT event =%d %s %d\n", event,dev->name, dev->ifindex ); */
/* return NOTIFY_DONE; */
@@ -284,17 +284,17 @@ static struct notifier_block bp_notifier_block = {
.notifier_call = bp_device_event,
};
-int is_bypass_fn(bpctl_dev_t *pbpctl_dev);
-int wdt_time_left(bpctl_dev_t *pbpctl_dev);
+int is_bypass_fn(struct bpctl_dev *pbpctl_dev);
+int wdt_time_left(struct bpctl_dev *pbpctl_dev);
-static void write_pulse(bpctl_dev_t *pbpctl_dev,
+static void write_pulse(struct bpctl_dev *pbpctl_dev,
unsigned int ctrl_ext,
unsigned char value, unsigned char len)
{
unsigned char ctrl_val = 0;
unsigned int i = len;
unsigned int ctrl = 0;
- bpctl_dev_t *pbpctl_dev_c = NULL;
+ struct bpctl_dev *pbpctl_dev_c = NULL;
if (pbpctl_dev->bp_i80)
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
@@ -590,13 +590,13 @@ static void write_pulse(bpctl_dev_t *pbpctl_dev,
}
}
-static int read_pulse(bpctl_dev_t *pbpctl_dev, unsigned int ctrl_ext,
+static int read_pulse(struct bpctl_dev *pbpctl_dev, unsigned int ctrl_ext,
unsigned char len)
{
unsigned char ctrl_val = 0;
unsigned int i = len;
unsigned int ctrl = 0;
- bpctl_dev_t *pbpctl_dev_c = NULL;
+ struct bpctl_dev *pbpctl_dev_c = NULL;
if (pbpctl_dev->bp_i80)
ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
@@ -765,11 +765,11 @@ static int read_pulse(bpctl_dev_t *pbpctl_dev, unsigned int ctrl_ext,
return ctrl_val;
}
-static void write_reg(bpctl_dev_t *pbpctl_dev, unsigned char value,
+static void write_reg(struct bpctl_dev *pbpctl_dev, unsigned char value,
unsigned char addr)
{
uint32_t ctrl_ext = 0, ctrl = 0;
- bpctl_dev_t *pbpctl_dev_c = NULL;
+ struct bpctl_dev *pbpctl_dev_c = NULL;
unsigned long flags;
if (pbpctl_dev->bp_10g9) {
pbpctl_dev_c = get_status_port_fn(pbpctl_dev);
@@ -934,15 +934,15 @@ static void write_reg(bpctl_dev_t *pbpctl_dev, unsigned char value,
}
-static void write_data(bpctl_dev_t *pbpctl_dev, unsigned char value)
+static void write_data(struct bpctl_dev *pbpctl_dev, unsigned char value)
{
write_reg(pbpctl_dev, value, CMND_REG_ADDR);
}
-static int read_reg(bpctl_dev_t *pbpctl_dev, unsigned char addr)
+static int read_reg(struct bpctl_dev *pbpctl_dev, unsigned char addr)
{
uint32_t ctrl_ext = 0, ctrl = 0, ctrl_value = 0;
- bpctl_dev_t *pbpctl_dev_c = NULL;
+ struct bpctl_dev *pbpctl_dev_c = NULL;
#ifdef BP_SYNC_FLAG
unsigned long flags;
@@ -1208,10 +1208,10 @@ static int read_reg(bpctl_dev_t *pbpctl_dev, unsigned char addr)
return ctrl_value;
}
-static int wdt_pulse(bpctl_dev_t *pbpctl_dev)
+static int wdt_pulse(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0, ctrl = 0;
- bpctl_dev_t *pbpctl_dev_c = NULL;
+ struct bpctl_dev *pbpctl_dev_c = NULL;
#ifdef BP_SYNC_FLAG
unsigned long flags;
@@ -1424,7 +1424,7 @@ static int wdt_pulse(bpctl_dev_t *pbpctl_dev)
return 0;
}
-static void data_pulse(bpctl_dev_t *pbpctl_dev, unsigned char value)
+static void data_pulse(struct bpctl_dev *pbpctl_dev, unsigned char value)
{
uint32_t ctrl_ext = 0;
@@ -1490,7 +1490,7 @@ static void data_pulse(bpctl_dev_t *pbpctl_dev, unsigned char value)
}
-static int send_wdt_pulse(bpctl_dev_t *pbpctl_dev)
+static int send_wdt_pulse(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
@@ -1524,7 +1524,7 @@ static int send_wdt_pulse(bpctl_dev_t *pbpctl_dev)
return 0;
}
-void send_bypass_clear_pulse(bpctl_dev_t *pbpctl_dev, unsigned int value)
+void send_bypass_clear_pulse(struct bpctl_dev *pbpctl_dev, unsigned int value)
{
uint32_t ctrl_ext = 0;
@@ -1550,7 +1550,7 @@ void send_bypass_clear_pulse(bpctl_dev_t *pbpctl_dev, unsigned int value)
/* #endif OLD_FW */
#ifdef BYPASS_DEBUG
-int pulse_set_fn(bpctl_dev_t *pbpctl_dev, unsigned int counter)
+int pulse_set_fn(struct bpctl_dev *pbpctl_dev, unsigned int counter)
{
uint32_t ctrl_ext = 0;
@@ -1578,7 +1578,7 @@ int pulse_set_fn(bpctl_dev_t *pbpctl_dev, unsigned int counter)
return 0;
}
-int zero_set_fn(bpctl_dev_t *pbpctl_dev)
+int zero_set_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0, ctrl_value = 0;
if (!pbpctl_dev)
@@ -1603,7 +1603,7 @@ int zero_set_fn(bpctl_dev_t *pbpctl_dev)
return ctrl_value;
}
-int pulse_get2_fn(bpctl_dev_t *pbpctl_dev)
+int pulse_get2_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0, ctrl_value = 0;
if (!pbpctl_dev)
@@ -1618,7 +1618,7 @@ int pulse_get2_fn(bpctl_dev_t *pbpctl_dev)
return ctrl_value;
}
-int pulse_get1_fn(bpctl_dev_t *pbpctl_dev)
+int pulse_get1_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0, ctrl_value = 0;
if (!pbpctl_dev)
@@ -1635,7 +1635,7 @@ int pulse_get1_fn(bpctl_dev_t *pbpctl_dev)
return ctrl_value;
}
-int gpio6_set_fn(bpctl_dev_t *pbpctl_dev)
+int gpio6_set_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
@@ -1646,7 +1646,7 @@ int gpio6_set_fn(bpctl_dev_t *pbpctl_dev)
return 0;
}
-int gpio7_set_fn(bpctl_dev_t *pbpctl_dev)
+int gpio7_set_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
@@ -1657,7 +1657,7 @@ int gpio7_set_fn(bpctl_dev_t *pbpctl_dev)
return 0;
}
-int gpio7_clear_fn(bpctl_dev_t *pbpctl_dev)
+int gpio7_clear_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
@@ -1668,7 +1668,7 @@ int gpio7_clear_fn(bpctl_dev_t *pbpctl_dev)
return 0;
}
-int gpio6_clear_fn(bpctl_dev_t *pbpctl_dev)
+int gpio6_clear_fn(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
@@ -1680,9 +1680,9 @@ int gpio6_clear_fn(bpctl_dev_t *pbpctl_dev)
}
#endif /*BYPASS_DEBUG */
-static bpctl_dev_t *lookup_port(bpctl_dev_t *dev)
+static struct bpctl_dev *lookup_port(struct bpctl_dev *dev)
{
- bpctl_dev_t *p;
+ struct bpctl_dev *p;
int n;
for (n = 0, p = bpctl_dev_arr; n < device_num && p->pdev; n++) {
if (p->bus == dev->bus
@@ -1693,7 +1693,7 @@ static bpctl_dev_t *lookup_port(bpctl_dev_t *dev)
return NULL;
}
-static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev)
+static struct bpctl_dev *get_status_port_fn(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev) {
if (pbpctl_dev->func == 0 || pbpctl_dev->func == 2)
@@ -1702,7 +1702,7 @@ static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev)
return NULL;
}
-static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev)
+static struct bpctl_dev *get_master_port_fn(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev) {
if (pbpctl_dev->func == 1 || pbpctl_dev->func == 3)
@@ -1715,7 +1715,7 @@ static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev)
/**************INTEL API***************/
/**************************************/
-static void write_data_port_int(bpctl_dev_t *pbpctl_dev,
+static void write_data_port_int(struct bpctl_dev *pbpctl_dev,
unsigned char ctrl_value)
{
uint32_t value;
@@ -1740,9 +1740,9 @@ static void write_data_port_int(bpctl_dev_t *pbpctl_dev,
}
-static int write_data_int(bpctl_dev_t *pbpctl_dev, unsigned char value)
+static int write_data_int(struct bpctl_dev *pbpctl_dev, unsigned char value)
{
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_b)
@@ -1755,7 +1755,7 @@ static int write_data_int(bpctl_dev_t *pbpctl_dev, unsigned char value)
return 0;
}
-static int wdt_pulse_int(bpctl_dev_t *pbpctl_dev)
+static int wdt_pulse_int(struct bpctl_dev *pbpctl_dev)
{
if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)
@@ -1779,7 +1779,7 @@ static int wdt_pulse_int(bpctl_dev_t *pbpctl_dev)
/*************************************/
/* CMND_ON 0x4 (100)*/
-int cmnd_on(bpctl_dev_t *pbpctl_dev)
+int cmnd_on(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -1796,7 +1796,7 @@ int cmnd_on(bpctl_dev_t *pbpctl_dev)
}
/* CMND_OFF 0x2 (10)*/
-int cmnd_off(bpctl_dev_t *pbpctl_dev)
+int cmnd_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -1809,12 +1809,12 @@ int cmnd_off(bpctl_dev_t *pbpctl_dev)
else
data_pulse(pbpctl_dev, CMND_OFF);
ret = 0;
- };
+ }
return ret;
}
/* BYPASS_ON (0xa)*/
-int bypass_on(bpctl_dev_t *pbpctl_dev)
+int bypass_on(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -1830,12 +1830,12 @@ int bypass_on(bpctl_dev_t *pbpctl_dev)
} else
data_pulse(pbpctl_dev, BYPASS_ON);
ret = 0;
- };
+ }
return ret;
}
/* BYPASS_OFF (0x8 111)*/
-int bypass_off(bpctl_dev_t *pbpctl_dev)
+int bypass_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -1858,7 +1858,7 @@ int bypass_off(bpctl_dev_t *pbpctl_dev)
}
/* TAP_OFF (0x9)*/
-int tap_off(bpctl_dev_t *pbpctl_dev)
+int tap_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if ((pbpctl_dev->bp_caps & TAP_CAP)
@@ -1866,12 +1866,12 @@ int tap_off(bpctl_dev_t *pbpctl_dev)
write_data(pbpctl_dev, TAP_OFF);
msec_delay_bp(LATCH_DELAY);
ret = 0;
- };
+ }
return ret;
}
/* TAP_ON (0xb)*/
-int tap_on(bpctl_dev_t *pbpctl_dev)
+int tap_on(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if ((pbpctl_dev->bp_caps & TAP_CAP)
@@ -1879,12 +1879,12 @@ int tap_on(bpctl_dev_t *pbpctl_dev)
write_data(pbpctl_dev, TAP_ON);
msec_delay_bp(LATCH_DELAY);
ret = 0;
- };
+ }
return ret;
}
/* DISC_OFF (0x9)*/
-int disc_off(bpctl_dev_t *pbpctl_dev)
+int disc_off(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) {
@@ -1896,7 +1896,7 @@ int disc_off(bpctl_dev_t *pbpctl_dev)
}
/* DISC_ON (0xb)*/
-int disc_on(bpctl_dev_t *pbpctl_dev)
+int disc_on(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) {
@@ -1908,10 +1908,10 @@ int disc_on(bpctl_dev_t *pbpctl_dev)
}
/* DISC_PORT_ON */
-int disc_port_on(bpctl_dev_t *pbpctl_dev)
+int disc_port_on(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
- bpctl_dev_t *pbpctl_dev_m;
+ struct bpctl_dev *pbpctl_dev_m;
if ((is_bypass_fn(pbpctl_dev)) == 1)
pbpctl_dev_m = pbpctl_dev;
@@ -1933,10 +1933,10 @@ int disc_port_on(bpctl_dev_t *pbpctl_dev)
}
/* DISC_PORT_OFF */
-int disc_port_off(bpctl_dev_t *pbpctl_dev)
+int disc_port_off(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
- bpctl_dev_t *pbpctl_dev_m;
+ struct bpctl_dev *pbpctl_dev_m;
if ((is_bypass_fn(pbpctl_dev)) == 1)
pbpctl_dev_m = pbpctl_dev;
@@ -1958,10 +1958,10 @@ int disc_port_off(bpctl_dev_t *pbpctl_dev)
}
/*TWO_PORT_LINK_HW_EN (0xe)*/
-int tpl_hw_on(bpctl_dev_t *pbpctl_dev)
+int tpl_hw_on(struct bpctl_dev *pbpctl_dev)
{
int ret = 0, ctrl = 0;
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_b)
@@ -1986,10 +1986,10 @@ int tpl_hw_on(bpctl_dev_t *pbpctl_dev)
}
/*TWO_PORT_LINK_HW_DIS (0xc)*/
-int tpl_hw_off(bpctl_dev_t *pbpctl_dev)
+int tpl_hw_off(struct bpctl_dev *pbpctl_dev)
{
int ret = 0, ctrl = 0;
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_b)
@@ -2012,7 +2012,7 @@ int tpl_hw_off(bpctl_dev_t *pbpctl_dev)
}
/* WDT_OFF (0x6 110)*/
-int wdt_off(bpctl_dev_t *pbpctl_dev)
+int wdt_off(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -2025,7 +2025,7 @@ int wdt_off(bpctl_dev_t *pbpctl_dev)
data_pulse(pbpctl_dev, WDT_OFF);
pbpctl_dev->wdt_status = WDT_STATUS_DIS;
ret = 0;
- };
+ }
return ret;
}
@@ -2035,7 +2035,7 @@ int wdt_off(bpctl_dev_t *pbpctl_dev)
static unsigned int
wdt_val_array[] = { 1000, 1500, 2000, 3000, 4000, 8000, 16000, 32000, 0 };
-int wdt_on(bpctl_dev_t *pbpctl_dev, unsigned int timeout)
+int wdt_on(struct bpctl_dev *pbpctl_dev, unsigned int timeout)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -2087,7 +2087,7 @@ int wdt_on(bpctl_dev_t *pbpctl_dev, unsigned int timeout)
return BP_NOT_CAP;
}
-void bp75_put_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev)
+void bp75_put_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
{
u32 swsm;
@@ -2098,7 +2098,7 @@ void bp75_put_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev)
BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm);
}
-s32 bp75_get_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev)
+s32 bp75_get_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
{
u32 swsm;
s32 ret_val = 0;
@@ -2146,7 +2146,7 @@ s32 bp75_get_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev)
return ret_val;
}
-static void bp75_release_phy(bpctl_dev_t *pbpctl_dev)
+static void bp75_release_phy(struct bpctl_dev *pbpctl_dev)
{
u16 mask = BPCTLI_SWFW_PHY0_SM;
u32 swfw_sync;
@@ -2166,7 +2166,7 @@ static void bp75_release_phy(bpctl_dev_t *pbpctl_dev)
bp75_put_hw_semaphore_generic(pbpctl_dev);
}
-static s32 bp75_acquire_phy(bpctl_dev_t *pbpctl_dev)
+static s32 bp75_acquire_phy(struct bpctl_dev *pbpctl_dev)
{
u16 mask = BPCTLI_SWFW_PHY0_SM;
u32 swfw_sync;
@@ -2212,7 +2212,7 @@ static s32 bp75_acquire_phy(bpctl_dev_t *pbpctl_dev)
return ret_val;
}
-s32 bp75_read_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data)
+s32 bp75_read_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset, u16 *data)
{
u32 i, mdic = 0;
s32 ret_val = 0;
@@ -2245,7 +2245,7 @@ s32 bp75_read_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data)
return ret_val;
}
-s32 bp75_write_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data)
+s32 bp75_write_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset, u16 data)
{
u32 i, mdic = 0;
s32 ret_val = 0;
@@ -2278,7 +2278,7 @@ s32 bp75_write_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data)
return ret_val;
}
-static s32 bp75_read_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data)
+static s32 bp75_read_phy_reg(struct bpctl_dev *pbpctl_dev, u32 offset, u16 *data)
{
s32 ret_val = 0;
@@ -2304,7 +2304,7 @@ static s32 bp75_read_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data)
return ret_val;
}
-static s32 bp75_write_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data)
+static s32 bp75_write_phy_reg(struct bpctl_dev *pbpctl_dev, u32 offset, u16 data)
{
s32 ret_val = 0;
@@ -2332,10 +2332,10 @@ static s32 bp75_write_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data)
}
/* SET_TX (non-Bypass command :)) */
-static int set_tx(bpctl_dev_t *pbpctl_dev, int tx_state)
+static int set_tx(struct bpctl_dev *pbpctl_dev, int tx_state)
{
int ret = 0, ctrl = 0;
- bpctl_dev_t *pbpctl_dev_m;
+ struct bpctl_dev *pbpctl_dev_m;
if ((is_bypass_fn(pbpctl_dev)) == 1)
pbpctl_dev_m = pbpctl_dev;
else
@@ -2532,7 +2532,7 @@ static int set_tx(bpctl_dev_t *pbpctl_dev, int tx_state)
}
/* SET_FORCE_LINK (non-Bypass command :)) */
-static int set_bp_force_link(bpctl_dev_t *pbpctl_dev, int tx_state)
+static int set_bp_force_link(struct bpctl_dev *pbpctl_dev, int tx_state)
{
int ret = 0, ctrl = 0;
@@ -2556,7 +2556,7 @@ static int set_bp_force_link(bpctl_dev_t *pbpctl_dev, int tx_state)
}
/*RESET_CONT 0x20 */
-int reset_cont(bpctl_dev_t *pbpctl_dev)
+int reset_cont(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -2568,12 +2568,12 @@ int reset_cont(bpctl_dev_t *pbpctl_dev)
else
data_pulse(pbpctl_dev, RESET_CONT);
ret = 0;
- };
+ }
return ret;
}
/*DIS_BYPASS_CAP 0x22 */
-int dis_bypass_cap(bpctl_dev_t *pbpctl_dev)
+int dis_bypass_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
@@ -2592,7 +2592,7 @@ int dis_bypass_cap(bpctl_dev_t *pbpctl_dev)
}
/*EN_BYPASS_CAP 0x24 */
-int en_bypass_cap(bpctl_dev_t *pbpctl_dev)
+int en_bypass_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
@@ -2608,7 +2608,7 @@ int en_bypass_cap(bpctl_dev_t *pbpctl_dev)
}
/* BYPASS_STATE_PWRON 0x26*/
-int bypass_state_pwron(bpctl_dev_t *pbpctl_dev)
+int bypass_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) {
write_data(pbpctl_dev, BYPASS_STATE_PWRON);
@@ -2622,7 +2622,7 @@ int bypass_state_pwron(bpctl_dev_t *pbpctl_dev)
}
/* NORMAL_STATE_PWRON 0x28*/
-int normal_state_pwron(bpctl_dev_t *pbpctl_dev)
+int normal_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if ((pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP)
|| (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP)) {
@@ -2637,7 +2637,7 @@ int normal_state_pwron(bpctl_dev_t *pbpctl_dev)
}
/* BYPASS_STATE_PWROFF 0x27*/
-int bypass_state_pwroff(bpctl_dev_t *pbpctl_dev)
+int bypass_state_pwroff(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP) {
write_data(pbpctl_dev, BYPASS_STATE_PWROFF);
@@ -2648,7 +2648,7 @@ int bypass_state_pwroff(bpctl_dev_t *pbpctl_dev)
}
/* NORMAL_STATE_PWROFF 0x29*/
-int normal_state_pwroff(bpctl_dev_t *pbpctl_dev)
+int normal_state_pwroff(struct bpctl_dev *pbpctl_dev)
{
if ((pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) {
write_data(pbpctl_dev, NORMAL_STATE_PWROFF);
@@ -2659,7 +2659,7 @@ int normal_state_pwroff(bpctl_dev_t *pbpctl_dev)
}
/*TAP_STATE_PWRON 0x2a*/
-int tap_state_pwron(bpctl_dev_t *pbpctl_dev)
+int tap_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
write_data(pbpctl_dev, TAP_STATE_PWRON);
@@ -2670,7 +2670,7 @@ int tap_state_pwron(bpctl_dev_t *pbpctl_dev)
}
/*DIS_TAP_CAP 0x2c*/
-int dis_tap_cap(bpctl_dev_t *pbpctl_dev)
+int dis_tap_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
write_data(pbpctl_dev, DIS_TAP_CAP);
@@ -2681,7 +2681,7 @@ int dis_tap_cap(bpctl_dev_t *pbpctl_dev)
}
/*EN_TAP_CAP 0x2e*/
-int en_tap_cap(bpctl_dev_t *pbpctl_dev)
+int en_tap_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
write_data(pbpctl_dev, EN_TAP_CAP);
@@ -2692,7 +2692,7 @@ int en_tap_cap(bpctl_dev_t *pbpctl_dev)
}
/*DISC_STATE_PWRON 0x2a*/
-int disc_state_pwron(bpctl_dev_t *pbpctl_dev)
+int disc_state_pwron(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8) {
@@ -2705,7 +2705,7 @@ int disc_state_pwron(bpctl_dev_t *pbpctl_dev)
}
/*DIS_DISC_CAP 0x2c*/
-int dis_disc_cap(bpctl_dev_t *pbpctl_dev)
+int dis_disc_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8) {
@@ -2718,10 +2718,10 @@ int dis_disc_cap(bpctl_dev_t *pbpctl_dev)
}
/*DISC_STATE_PWRON 0x2a*/
-int disc_port_state_pwron(bpctl_dev_t *pbpctl_dev)
+int disc_port_state_pwron(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
- bpctl_dev_t *pbpctl_dev_m;
+ struct bpctl_dev *pbpctl_dev_m;
return BP_NOT_CAP;
@@ -2744,10 +2744,10 @@ int disc_port_state_pwron(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int normal_port_state_pwron(bpctl_dev_t *pbpctl_dev)
+int normal_port_state_pwron(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
- bpctl_dev_t *pbpctl_dev_m;
+ struct bpctl_dev *pbpctl_dev_m;
return BP_NOT_CAP;
if ((is_bypass_fn(pbpctl_dev)) == 1)
@@ -2770,7 +2770,7 @@ int normal_port_state_pwron(bpctl_dev_t *pbpctl_dev)
}
/*EN_TAP_CAP 0x2e*/
-int en_disc_cap(bpctl_dev_t *pbpctl_dev)
+int en_disc_cap(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8) {
@@ -2782,7 +2782,7 @@ int en_disc_cap(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int std_nic_on(bpctl_dev_t *pbpctl_dev)
+int std_nic_on(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
@@ -2836,7 +2836,7 @@ int std_nic_on(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int std_nic_off(bpctl_dev_t *pbpctl_dev)
+int std_nic_off(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
@@ -2888,7 +2888,7 @@ int std_nic_off(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int wdt_time_left(bpctl_dev_t *pbpctl_dev)
+int wdt_time_left(struct bpctl_dev *pbpctl_dev)
{
/* unsigned long curr_time=((long long)(jiffies*1000))/HZ, delta_time=0,wdt_on_time=((long long)(pbpctl_dev->bypass_wdt_on_time*1000))/HZ; */
@@ -2920,7 +2920,7 @@ int wdt_time_left(bpctl_dev_t *pbpctl_dev)
return time_left;
}
-static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left)
+static int wdt_timer(struct bpctl_dev *pbpctl_dev, int *time_left)
{
int ret = 0;
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -2936,7 +2936,7 @@ static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left)
return ret;
}
-static int wdt_timer_reload(bpctl_dev_t *pbpctl_dev)
+static int wdt_timer_reload(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
@@ -2960,7 +2960,7 @@ static int wdt_timer_reload(bpctl_dev_t *pbpctl_dev)
static void wd_reset_timer(unsigned long param)
{
- bpctl_dev_t *pbpctl_dev = (bpctl_dev_t *) param;
+ struct bpctl_dev *pbpctl_dev = (struct bpctl_dev *) param;
#ifdef BP_SELF_TEST
struct sk_buff *skb_tmp;
#endif
@@ -2999,7 +2999,7 @@ static void wd_reset_timer(unsigned long param)
}
/*WAIT_AT_PWRUP 0x80 */
-int bp_wait_at_pwup_en(bpctl_dev_t *pbpctl_dev)
+int bp_wait_at_pwup_en(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3014,7 +3014,7 @@ int bp_wait_at_pwup_en(bpctl_dev_t *pbpctl_dev)
}
/*DIS_WAIT_AT_PWRUP 0x81 */
-int bp_wait_at_pwup_dis(bpctl_dev_t *pbpctl_dev)
+int bp_wait_at_pwup_dis(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3031,7 +3031,7 @@ int bp_wait_at_pwup_dis(bpctl_dev_t *pbpctl_dev)
/*EN_HW_RESET 0x82 */
-int bp_hw_reset_en(bpctl_dev_t *pbpctl_dev)
+int bp_hw_reset_en(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3047,7 +3047,7 @@ int bp_hw_reset_en(bpctl_dev_t *pbpctl_dev)
/*DIS_HW_RESET 0x83 */
-int bp_hw_reset_dis(bpctl_dev_t *pbpctl_dev)
+int bp_hw_reset_dis(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3062,7 +3062,7 @@ int bp_hw_reset_dis(bpctl_dev_t *pbpctl_dev)
}
-int wdt_exp_mode(bpctl_dev_t *pbpctl_dev, int mode)
+int wdt_exp_mode(struct bpctl_dev *pbpctl_dev, int mode)
{
uint32_t status_reg = 0, status_reg1 = 0;
@@ -3113,7 +3113,7 @@ int wdt_exp_mode(bpctl_dev_t *pbpctl_dev, int mode)
return BP_NOT_CAP;
}
-int bypass_fw_ver(bpctl_dev_t *pbpctl_dev)
+int bypass_fw_ver(struct bpctl_dev *pbpctl_dev)
{
if (is_bypass_fn(pbpctl_dev))
return read_reg(pbpctl_dev, VER_REG_ADDR);
@@ -3121,7 +3121,7 @@ int bypass_fw_ver(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_sign_check(bpctl_dev_t *pbpctl_dev)
+int bypass_sign_check(struct bpctl_dev *pbpctl_dev)
{
if (is_bypass_fn(pbpctl_dev))
@@ -3131,10 +3131,10 @@ int bypass_sign_check(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-static int tx_status(bpctl_dev_t *pbpctl_dev)
+static int tx_status(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl = 0;
- bpctl_dev_t *pbpctl_dev_m;
+ struct bpctl_dev *pbpctl_dev_m;
if ((is_bypass_fn(pbpctl_dev)) == 1)
pbpctl_dev_m = pbpctl_dev;
else
@@ -3218,7 +3218,7 @@ static int tx_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-static int bp_force_link_status(bpctl_dev_t *pbpctl_dev)
+static int bp_force_link_status(struct bpctl_dev *pbpctl_dev)
{
if (DBI_IF_SERIES(pbpctl_dev->subdevice)) {
@@ -3232,10 +3232,10 @@ static int bp_force_link_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_from_last_read(bpctl_dev_t *pbpctl_dev)
+int bypass_from_last_read(struct bpctl_dev *pbpctl_dev)
{
uint32_t ctrl_ext = 0;
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
@@ -3252,9 +3252,9 @@ int bypass_from_last_read(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_status_clear(bpctl_dev_t *pbpctl_dev)
+int bypass_status_clear(struct bpctl_dev *pbpctl_dev)
{
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
@@ -3266,7 +3266,7 @@ int bypass_status_clear(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_flag_status(bpctl_dev_t *pbpctl_dev)
+int bypass_flag_status(struct bpctl_dev *pbpctl_dev)
{
if ((pbpctl_dev->bp_caps & BP_CAP)) {
@@ -3279,7 +3279,7 @@ int bypass_flag_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_flag_status_clear(bpctl_dev_t *pbpctl_dev)
+int bypass_flag_status_clear(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_CAP) {
@@ -3294,7 +3294,7 @@ int bypass_flag_status_clear(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int bypass_change_status(bpctl_dev_t *pbpctl_dev)
+int bypass_change_status(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -3313,7 +3313,7 @@ int bypass_change_status(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int bypass_off_status(bpctl_dev_t *pbpctl_dev)
+int bypass_off_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_CAP) {
@@ -3325,12 +3325,12 @@ int bypass_off_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-static int bypass_status(bpctl_dev_t *pbpctl_dev)
+static int bypass_status(struct bpctl_dev *pbpctl_dev)
{
u32 ctrl_ext = 0;
if (pbpctl_dev->bp_caps & BP_CAP) {
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_b)
@@ -3408,7 +3408,7 @@ static int bypass_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int default_pwron_status(bpctl_dev_t *pbpctl_dev)
+int default_pwron_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3426,7 +3426,7 @@ int default_pwron_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-static int default_pwroff_status(bpctl_dev_t *pbpctl_dev)
+static int default_pwroff_status(struct bpctl_dev *pbpctl_dev)
{
/*if ((!pbpctl_dev->bp_caps&BP_DIS_CAP)&&
@@ -3440,7 +3440,7 @@ static int default_pwroff_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int dis_bypass_cap_status(bpctl_dev_t *pbpctl_dev)
+int dis_bypass_cap_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
@@ -3453,7 +3453,7 @@ int dis_bypass_cap_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int cmd_en_status(bpctl_dev_t *pbpctl_dev)
+int cmd_en_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3465,7 +3465,7 @@ int cmd_en_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int wdt_en_status(bpctl_dev_t *pbpctl_dev)
+int wdt_en_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -3477,7 +3477,7 @@ int wdt_en_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int wdt_programmed(bpctl_dev_t *pbpctl_dev, int *timeout)
+int wdt_programmed(struct bpctl_dev *pbpctl_dev, int *timeout)
{
int ret = 0;
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -3497,13 +3497,13 @@ int wdt_programmed(bpctl_dev_t *pbpctl_dev, int *timeout)
*timeout =
curr_wdt_status ==
0 ? 0 : pbpctl_dev->bypass_timer_interval;
- };
+ }
} else
ret = BP_NOT_CAP;
return ret;
}
-int bypass_support(bpctl_dev_t *pbpctl_dev)
+int bypass_support(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
@@ -3520,7 +3520,7 @@ int bypass_support(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int tap_support(bpctl_dev_t *pbpctl_dev)
+int tap_support(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
@@ -3536,7 +3536,7 @@ int tap_support(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int normal_support(bpctl_dev_t *pbpctl_dev)
+int normal_support(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
@@ -3548,11 +3548,11 @@ int normal_support(bpctl_dev_t *pbpctl_dev)
NORMAL_UNSUPPORT_MASK) ? 0 : 1);
} else
ret = 1;
- };
+ }
return ret;
}
-int get_bp_prod_caps(bpctl_dev_t *pbpctl_dev)
+int get_bp_prod_caps(struct bpctl_dev *pbpctl_dev)
{
if ((pbpctl_dev->bp_caps & SW_CTL_CAP) &&
(pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER))
@@ -3561,7 +3561,7 @@ int get_bp_prod_caps(bpctl_dev_t *pbpctl_dev)
}
-int tap_flag_status(bpctl_dev_t *pbpctl_dev)
+int tap_flag_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) {
@@ -3573,7 +3573,7 @@ int tap_flag_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int tap_flag_status_clear(bpctl_dev_t *pbpctl_dev)
+int tap_flag_status_clear(struct bpctl_dev *pbpctl_dev)
{
uint32_t status_reg = 0;
if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) {
@@ -3587,7 +3587,7 @@ int tap_flag_status_clear(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int tap_change_status(bpctl_dev_t *pbpctl_dev)
+int tap_change_status(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
@@ -3604,7 +3604,7 @@ int tap_change_status(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int tap_off_status(bpctl_dev_t *pbpctl_dev)
+int tap_off_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_CAP) {
if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
@@ -3614,12 +3614,12 @@ int tap_off_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int tap_status(bpctl_dev_t *pbpctl_dev)
+int tap_status(struct bpctl_dev *pbpctl_dev)
{
u32 ctrl_ext = 0;
if (pbpctl_dev->bp_caps & TAP_CAP) {
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_b)
@@ -3653,7 +3653,7 @@ int tap_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int default_pwron_tap_status(bpctl_dev_t *pbpctl_dev)
+int default_pwron_tap_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
@@ -3664,7 +3664,7 @@ int default_pwron_tap_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int dis_tap_cap_status(bpctl_dev_t *pbpctl_dev)
+int dis_tap_cap_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
@@ -3675,7 +3675,7 @@ int dis_tap_cap_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int disc_flag_status(bpctl_dev_t *pbpctl_dev)
+int disc_flag_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3687,7 +3687,7 @@ int disc_flag_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int disc_flag_status_clear(bpctl_dev_t *pbpctl_dev)
+int disc_flag_status_clear(struct bpctl_dev *pbpctl_dev)
{
uint32_t status_reg = 0;
if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3701,7 +3701,7 @@ int disc_flag_status_clear(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int disc_change_status(bpctl_dev_t *pbpctl_dev)
+int disc_change_status(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3712,9 +3712,9 @@ int disc_change_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int disc_off_status(bpctl_dev_t *pbpctl_dev)
+int disc_off_status(struct bpctl_dev *pbpctl_dev)
{
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
u32 ctrl_ext = 0;
if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3796,7 +3796,7 @@ int disc_off_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-static int disc_status(bpctl_dev_t *pbpctl_dev)
+static int disc_status(struct bpctl_dev *pbpctl_dev)
{
int ctrl = 0;
if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3808,7 +3808,7 @@ static int disc_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int default_pwron_disc_status(bpctl_dev_t *pbpctl_dev)
+int default_pwron_disc_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8)
@@ -3819,7 +3819,7 @@ int default_pwron_disc_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int dis_disc_cap_status(bpctl_dev_t *pbpctl_dev)
+int dis_disc_cap_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & DIS_DISC_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8)
@@ -3830,10 +3830,10 @@ int dis_disc_cap_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int disc_port_status(bpctl_dev_t *pbpctl_dev)
+int disc_port_status(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
- bpctl_dev_t *pbpctl_dev_m;
+ struct bpctl_dev *pbpctl_dev_m;
if ((is_bypass_fn(pbpctl_dev)) == 1)
pbpctl_dev_m = pbpctl_dev;
@@ -3854,10 +3854,10 @@ int disc_port_status(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int default_pwron_disc_port_status(bpctl_dev_t *pbpctl_dev)
+int default_pwron_disc_port_status(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
- bpctl_dev_t *pbpctl_dev_m;
+ struct bpctl_dev *pbpctl_dev_m;
if ((is_bypass_fn(pbpctl_dev)) == 1)
pbpctl_dev_m = pbpctl_dev;
@@ -3878,7 +3878,7 @@ int default_pwron_disc_port_status(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int wdt_exp_mode_status(bpctl_dev_t *pbpctl_dev)
+int wdt_exp_mode_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver <= PXG2BPI_VER)
@@ -3901,7 +3901,7 @@ int wdt_exp_mode_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int tpl2_flag_status(bpctl_dev_t *pbpctl_dev)
+int tpl2_flag_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) {
@@ -3912,9 +3912,9 @@ int tpl2_flag_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int tpl_hw_status(bpctl_dev_t *pbpctl_dev)
+int tpl_hw_status(struct bpctl_dev *pbpctl_dev)
{
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_b)
@@ -3927,7 +3927,7 @@ int tpl_hw_status(bpctl_dev_t *pbpctl_dev)
}
-int bp_wait_at_pwup_status(bpctl_dev_t *pbpctl_dev)
+int bp_wait_at_pwup_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
if (pbpctl_dev->bp_ext_ver >= 0x8)
@@ -3938,7 +3938,7 @@ int bp_wait_at_pwup_status(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int bp_hw_reset_status(bpctl_dev_t *pbpctl_dev)
+int bp_hw_reset_status(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3952,7 +3952,7 @@ int bp_hw_reset_status(bpctl_dev_t *pbpctl_dev)
}
-int std_nic_status(bpctl_dev_t *pbpctl_dev)
+int std_nic_status(struct bpctl_dev *pbpctl_dev)
{
int status_val = 0;
@@ -4000,10 +4000,10 @@ int std_nic_status(bpctl_dev_t *pbpctl_dev)
/******************************************************/
/**************SW_INIT*********************************/
/******************************************************/
-void bypass_caps_init(bpctl_dev_t *pbpctl_dev)
+void bypass_caps_init(struct bpctl_dev *pbpctl_dev)
{
u_int32_t ctrl_ext = 0;
- bpctl_dev_t *pbpctl_dev_m = NULL;
+ struct bpctl_dev *pbpctl_dev_m = NULL;
#ifdef BYPASS_DEBUG
int ret = 0;
@@ -4218,7 +4218,7 @@ void bypass_caps_init(bpctl_dev_t *pbpctl_dev)
}
}
-int bypass_off_init(bpctl_dev_t *pbpctl_dev)
+int bypass_off_init(struct bpctl_dev *pbpctl_dev)
{
int ret = cmnd_on(pbpctl_dev);
if (ret < 0)
@@ -4234,10 +4234,10 @@ int bypass_off_init(bpctl_dev_t *pbpctl_dev)
return 0;
}
-void remove_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
+void remove_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
{
#ifdef BP_SELF_TEST
- bpctl_dev_t *pbpctl_dev_sl = NULL;
+ struct bpctl_dev *pbpctl_dev_sl = NULL;
#endif
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -4263,7 +4263,7 @@ void remove_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
}
-int init_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
+int init_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
init_timer(&pbpctl_dev->bp_timer);
@@ -4277,7 +4277,7 @@ int init_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
#ifdef BP_SELF_TEST
int bp_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- bpctl_dev_t *pbpctl_dev = NULL, *pbpctl_dev_m = NULL;
+ struct bpctl_dev *pbpctl_dev = NULL, *pbpctl_dev_m = NULL;
int idx_dev = 0;
struct ethhdr *eth = (struct ethhdr *)skb->data;
@@ -4310,7 +4310,7 @@ int bp_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
#endif
-int set_bypass_wd_auto(bpctl_dev_t *pbpctl_dev, unsigned int param)
+int set_bypass_wd_auto(struct bpctl_dev *pbpctl_dev, unsigned int param)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
if (pbpctl_dev->reset_time != param) {
@@ -4329,7 +4329,7 @@ int set_bypass_wd_auto(bpctl_dev_t *pbpctl_dev, unsigned int param)
return BP_NOT_CAP;
}
-int get_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
+int get_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP)
return pbpctl_dev->reset_time;
@@ -4339,9 +4339,9 @@ int get_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
#ifdef BP_SELF_TEST
-int set_bp_self_test(bpctl_dev_t *pbpctl_dev, unsigned int param)
+int set_bp_self_test(struct bpctl_dev *pbpctl_dev, unsigned int param)
{
- bpctl_dev_t *pbpctl_dev_sl = NULL;
+ struct bpctl_dev *pbpctl_dev_sl = NULL;
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
pbpctl_dev->bp_self_test_flag = param == 0 ? 0 : 1;
@@ -4374,7 +4374,7 @@ int set_bp_self_test(bpctl_dev_t *pbpctl_dev, unsigned int param)
return BP_NOT_CAP;
}
-int get_bp_self_test(bpctl_dev_t *pbpctl_dev)
+int get_bp_self_test(struct bpctl_dev *pbpctl_dev)
{
if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -4392,7 +4392,7 @@ int get_bp_self_test(bpctl_dev_t *pbpctl_dev)
/************************* API ********************************/
/**************************************************************/
-int is_bypass_fn(bpctl_dev_t *pbpctl_dev)
+int is_bypass_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4400,7 +4400,7 @@ int is_bypass_fn(bpctl_dev_t *pbpctl_dev)
return (((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) ? 1 : 0);
}
-int set_bypass_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
+int set_bypass_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
{
int ret = 0;
@@ -4418,12 +4418,12 @@ int set_bypass_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
return ret;
}
-int get_bypass_fn(bpctl_dev_t *pbpctl_dev)
+int get_bypass_fn(struct bpctl_dev *pbpctl_dev)
{
return bypass_status(pbpctl_dev);
}
-int get_bypass_change_fn(bpctl_dev_t *pbpctl_dev)
+int get_bypass_change_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4431,7 +4431,7 @@ int get_bypass_change_fn(bpctl_dev_t *pbpctl_dev)
return bypass_change_status(pbpctl_dev);
}
-int set_dis_bypass_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
+int set_dis_bypass_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4450,7 +4450,7 @@ int set_dis_bypass_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
return ret;
}
-int get_dis_bypass_fn(bpctl_dev_t *pbpctl_dev)
+int get_dis_bypass_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4458,7 +4458,7 @@ int get_dis_bypass_fn(bpctl_dev_t *pbpctl_dev)
return dis_bypass_cap_status(pbpctl_dev);
}
-int set_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
+int set_bypass_pwoff_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4477,7 +4477,7 @@ int set_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
return ret;
}
-int get_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev)
+int get_bypass_pwoff_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4485,7 +4485,7 @@ int get_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev)
return default_pwroff_status(pbpctl_dev);
}
-int set_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
+int set_bypass_pwup_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4504,7 +4504,7 @@ int set_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
return ret;
}
-int get_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev)
+int get_bypass_pwup_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4512,7 +4512,7 @@ int get_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev)
return default_pwron_status(pbpctl_dev);
}
-int set_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int timeout)
+int set_bypass_wd_fn(struct bpctl_dev *pbpctl_dev, int timeout)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4534,7 +4534,7 @@ int set_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int timeout)
return ret;
}
-int get_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int *timeout)
+int get_bypass_wd_fn(struct bpctl_dev *pbpctl_dev, int *timeout)
{
if (!pbpctl_dev)
return -1;
@@ -4542,7 +4542,7 @@ int get_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int *timeout)
return wdt_programmed(pbpctl_dev, timeout);
}
-int get_wd_expire_time_fn(bpctl_dev_t *pbpctl_dev, int *time_left)
+int get_wd_expire_time_fn(struct bpctl_dev *pbpctl_dev, int *time_left)
{
if (!pbpctl_dev)
return -1;
@@ -4550,7 +4550,7 @@ int get_wd_expire_time_fn(bpctl_dev_t *pbpctl_dev, int *time_left)
return wdt_timer(pbpctl_dev, time_left);
}
-int reset_bypass_wd_timer_fn(bpctl_dev_t *pbpctl_dev)
+int reset_bypass_wd_timer_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4558,7 +4558,7 @@ int reset_bypass_wd_timer_fn(bpctl_dev_t *pbpctl_dev)
return wdt_timer_reload(pbpctl_dev);
}
-int get_wd_set_caps_fn(bpctl_dev_t *pbpctl_dev)
+int get_wd_set_caps_fn(struct bpctl_dev *pbpctl_dev)
{
int bp_status = 0;
@@ -4582,7 +4582,7 @@ int get_wd_set_caps_fn(bpctl_dev_t *pbpctl_dev)
return bp_status;
}
-int set_std_nic_fn(bpctl_dev_t *pbpctl_dev, int nic_mode)
+int set_std_nic_fn(struct bpctl_dev *pbpctl_dev, int nic_mode)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4602,7 +4602,7 @@ int set_std_nic_fn(bpctl_dev_t *pbpctl_dev, int nic_mode)
return ret;
}
-int get_std_nic_fn(bpctl_dev_t *pbpctl_dev)
+int get_std_nic_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4610,7 +4610,7 @@ int get_std_nic_fn(bpctl_dev_t *pbpctl_dev)
return std_nic_status(pbpctl_dev);
}
-int set_tap_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+int set_tap_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
{
if (!pbpctl_dev)
return -1;
@@ -4626,7 +4626,7 @@ int set_tap_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
return BP_NOT_CAP;
}
-int get_tap_fn(bpctl_dev_t *pbpctl_dev)
+int get_tap_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4634,7 +4634,7 @@ int get_tap_fn(bpctl_dev_t *pbpctl_dev)
return tap_status(pbpctl_dev);
}
-int set_tap_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+int set_tap_pwup_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4652,7 +4652,7 @@ int set_tap_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
return ret;
}
-int get_tap_pwup_fn(bpctl_dev_t *pbpctl_dev)
+int get_tap_pwup_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4664,7 +4664,7 @@ int get_tap_pwup_fn(bpctl_dev_t *pbpctl_dev)
return ((ret == 0) ? 1 : 0);
}
-int get_tap_change_fn(bpctl_dev_t *pbpctl_dev)
+int get_tap_change_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4672,7 +4672,7 @@ int get_tap_change_fn(bpctl_dev_t *pbpctl_dev)
return tap_change_status(pbpctl_dev);
}
-int set_dis_tap_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
+int set_dis_tap_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4689,7 +4689,7 @@ int set_dis_tap_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
return BP_NOT_CAP;
}
-int get_dis_tap_fn(bpctl_dev_t *pbpctl_dev)
+int get_dis_tap_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4697,7 +4697,7 @@ int get_dis_tap_fn(bpctl_dev_t *pbpctl_dev)
return dis_tap_cap_status(pbpctl_dev);
}
-int set_disc_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+int set_disc_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
{
if (!pbpctl_dev)
return -1;
@@ -4714,7 +4714,7 @@ int set_disc_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
return BP_NOT_CAP;
}
-int get_disc_fn(bpctl_dev_t *pbpctl_dev)
+int get_disc_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4725,7 +4725,7 @@ int get_disc_fn(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int set_disc_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+int set_disc_pwup_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4743,7 +4743,7 @@ int set_disc_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
return ret;
}
-int get_disc_pwup_fn(bpctl_dev_t *pbpctl_dev)
+int get_disc_pwup_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4753,7 +4753,7 @@ int get_disc_pwup_fn(bpctl_dev_t *pbpctl_dev)
return (ret == 0 ? 1 : (ret < 0 ? BP_NOT_CAP : 0));
}
-int get_disc_change_fn(bpctl_dev_t *pbpctl_dev)
+int get_disc_change_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4763,7 +4763,7 @@ int get_disc_change_fn(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int set_dis_disc_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
+int set_dis_disc_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4781,7 +4781,7 @@ int set_dis_disc_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
return BP_NOT_CAP;
}
-int get_dis_disc_fn(bpctl_dev_t *pbpctl_dev)
+int get_dis_disc_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4792,7 +4792,7 @@ int get_dis_disc_fn(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int set_disc_port_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+int set_disc_port_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
{
int ret = BP_NOT_CAP;
if (!pbpctl_dev)
@@ -4806,7 +4806,7 @@ int set_disc_port_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
return ret;
}
-int get_disc_port_fn(bpctl_dev_t *pbpctl_dev)
+int get_disc_port_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4814,7 +4814,7 @@ int get_disc_port_fn(bpctl_dev_t *pbpctl_dev)
return disc_port_status(pbpctl_dev);
}
-int set_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+int set_disc_port_pwup_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
{
int ret = BP_NOT_CAP;
if (!pbpctl_dev)
@@ -4828,7 +4828,7 @@ int set_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
return ret;
}
-int get_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev)
+int get_disc_port_pwup_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4840,7 +4840,7 @@ int get_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev)
return ((ret == 0) ? 1 : 0);
}
-int get_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev)
+int get_wd_exp_mode_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4848,7 +4848,7 @@ int get_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev)
return wdt_exp_mode_status(pbpctl_dev);
}
-int set_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev, int param)
+int set_wd_exp_mode_fn(struct bpctl_dev *pbpctl_dev, int param)
{
if (!pbpctl_dev)
return -1;
@@ -4856,7 +4856,7 @@ int set_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev, int param)
return wdt_exp_mode(pbpctl_dev, param);
}
-int reset_cont_fn(bpctl_dev_t *pbpctl_dev)
+int reset_cont_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -4868,10 +4868,10 @@ int reset_cont_fn(bpctl_dev_t *pbpctl_dev)
return reset_cont(pbpctl_dev);
}
-int set_tx_fn(bpctl_dev_t *pbpctl_dev, int tx_state)
+int set_tx_fn(struct bpctl_dev *pbpctl_dev, int tx_state)
{
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
if (!pbpctl_dev)
return -1;
@@ -4891,7 +4891,7 @@ int set_tx_fn(bpctl_dev_t *pbpctl_dev, int tx_state)
int set_bp_force_link_fn(int dev_num, int tx_state)
{
- static bpctl_dev_t *bpctl_dev_curr;
+ static struct bpctl_dev *bpctl_dev_curr;
if ((dev_num < 0) || (dev_num > device_num)
|| (bpctl_dev_arr[dev_num].pdev == NULL))
@@ -4901,7 +4901,7 @@ int set_bp_force_link_fn(int dev_num, int tx_state)
return set_bp_force_link(bpctl_dev_curr, tx_state);
}
-int set_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev, int param)
+int set_wd_autoreset_fn(struct bpctl_dev *pbpctl_dev, int param)
{
if (!pbpctl_dev)
return -1;
@@ -4909,7 +4909,7 @@ int set_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev, int param)
return set_bypass_wd_auto(pbpctl_dev, param);
}
-int get_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev)
+int get_wd_autoreset_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4918,7 +4918,7 @@ int get_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev)
}
#ifdef BP_SELF_TEST
-int set_bp_self_test_fn(bpctl_dev_t *pbpctl_dev, int param)
+int set_bp_self_test_fn(struct bpctl_dev *pbpctl_dev, int param)
{
if (!pbpctl_dev)
return -1;
@@ -4926,7 +4926,7 @@ int set_bp_self_test_fn(bpctl_dev_t *pbpctl_dev, int param)
return set_bp_self_test(pbpctl_dev, param);
}
-int get_bp_self_test_fn(bpctl_dev_t *pbpctl_dev)
+int get_bp_self_test_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4936,7 +4936,7 @@ int get_bp_self_test_fn(bpctl_dev_t *pbpctl_dev)
#endif
-int get_bypass_caps_fn(bpctl_dev_t *pbpctl_dev)
+int get_bypass_caps_fn(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4945,7 +4945,7 @@ int get_bypass_caps_fn(bpctl_dev_t *pbpctl_dev)
}
-int get_bypass_slave_fn(bpctl_dev_t *pbpctl_dev, bpctl_dev_t **pbpctl_dev_out)
+int get_bypass_slave_fn(struct bpctl_dev *pbpctl_dev, struct bpctl_dev **pbpctl_dev_out)
{
int idx_dev = 0;
if (!pbpctl_dev)
@@ -4977,7 +4977,7 @@ int get_bypass_slave_fn(bpctl_dev_t *pbpctl_dev, bpctl_dev_t **pbpctl_dev_out)
return 0;
}
-int is_bypass(bpctl_dev_t *pbpctl_dev)
+int is_bypass(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -4988,9 +4988,9 @@ int is_bypass(bpctl_dev_t *pbpctl_dev)
return 0;
}
-int get_tx_fn(bpctl_dev_t *pbpctl_dev)
+int get_tx_fn(struct bpctl_dev *pbpctl_dev)
{
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
if (!pbpctl_dev)
return -1;
@@ -5010,7 +5010,7 @@ int get_tx_fn(bpctl_dev_t *pbpctl_dev)
int get_bp_force_link_fn(int dev_num)
{
- static bpctl_dev_t *bpctl_dev_curr;
+ static struct bpctl_dev *bpctl_dev_curr;
if ((dev_num < 0) || (dev_num > device_num)
|| (bpctl_dev_arr[dev_num].pdev == NULL))
@@ -5020,7 +5020,7 @@ int get_bp_force_link_fn(int dev_num)
return bp_force_link_status(bpctl_dev_curr);
}
-static int get_bypass_link_status(bpctl_dev_t *pbpctl_dev)
+static int get_bypass_link_status(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -5036,9 +5036,9 @@ static int get_bypass_link_status(bpctl_dev_t *pbpctl_dev)
static void bp_tpl_timer_fn(unsigned long param)
{
- bpctl_dev_t *pbpctl_dev = (bpctl_dev_t *) param;
+ struct bpctl_dev *pbpctl_dev = (struct bpctl_dev *) param;
uint32_t link1, link2;
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
if (!pbpctl_dev_b)
@@ -5071,9 +5071,9 @@ static void bp_tpl_timer_fn(unsigned long param)
mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + BP_LINK_MON_DELAY * HZ);
}
-void remove_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
+void remove_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
{
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
if (!pbpctl_dev)
return;
pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
@@ -5089,7 +5089,7 @@ void remove_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
return;
}
-int init_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
+int init_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -5102,7 +5102,7 @@ int init_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int set_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev, unsigned int param)
+int set_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev, unsigned int param)
{
if (!pbpctl_dev)
return -1;
@@ -5111,7 +5111,7 @@ int set_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev, unsigned int param)
pbpctl_dev->bp_tpl_flag = param;
mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + 1);
return BP_OK;
- };
+ }
if ((!param) && (pbpctl_dev->bp_tpl_flag))
remove_bypass_tpl_auto(pbpctl_dev);
@@ -5120,7 +5120,7 @@ int set_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev, unsigned int param)
return BP_NOT_CAP;
}
-int get_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
+int get_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
{
if (!pbpctl_dev)
return -1;
@@ -5130,10 +5130,10 @@ int get_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
return BP_NOT_CAP;
}
-int set_tpl_fn(bpctl_dev_t *pbpctl_dev, int tpl_mode)
+int set_tpl_fn(struct bpctl_dev *pbpctl_dev, int tpl_mode)
{
- bpctl_dev_t *pbpctl_dev_b = NULL;
+ struct bpctl_dev *pbpctl_dev_b = NULL;
if (!pbpctl_dev)
return -1;
@@ -5160,7 +5160,7 @@ int set_tpl_fn(bpctl_dev_t *pbpctl_dev, int tpl_mode)
return BP_NOT_CAP;
}
-int get_tpl_fn(bpctl_dev_t *pbpctl_dev)
+int get_tpl_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = BP_NOT_CAP;
if (!pbpctl_dev)
@@ -5174,7 +5174,7 @@ int get_tpl_fn(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int set_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+int set_bp_wait_at_pwup_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
{
if (!pbpctl_dev)
return -1;
@@ -5194,7 +5194,7 @@ int set_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
return BP_NOT_CAP;
}
-int get_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev)
+int get_bp_wait_at_pwup_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -5207,7 +5207,7 @@ int get_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev)
return ret;
}
-int set_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+int set_bp_hw_reset_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
{
if (!pbpctl_dev)
return -1;
@@ -5227,7 +5227,7 @@ int set_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
return BP_NOT_CAP;
}
-int get_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev)
+int get_bp_hw_reset_fn(struct bpctl_dev *pbpctl_dev)
{
int ret = 0;
if (!pbpctl_dev)
@@ -5242,7 +5242,7 @@ int get_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev)
}
-int get_bypass_info_fn(bpctl_dev_t *pbpctl_dev, char *dev_name,
+int get_bypass_info_fn(struct bpctl_dev *pbpctl_dev, char *dev_name,
char *add_param)
{
if (!pbpctl_dev)
@@ -5313,7 +5313,7 @@ static int get_dev_idx(int ifindex)
return -1;
}
-static bpctl_dev_t *get_dev_idx_p(int ifindex)
+static struct bpctl_dev *get_dev_idx_p(int ifindex)
{
int idx_dev = 0;
@@ -5401,12 +5401,12 @@ static long device_ioctl(struct file *file, /* see include/linux/fs.h */
{
struct bpctl_cmd bpctl_cmd;
int dev_idx = 0;
- bpctl_dev_t *pbpctl_dev_out;
+ struct bpctl_dev *pbpctl_dev_out;
void __user *argp = (void __user *)ioctl_param;
int ret = 0;
unsigned long flags;
- static bpctl_dev_t *pbpctl_dev;
+ static struct bpctl_dev *pbpctl_dev;
/* lock_kernel(); */
if (down_interruptible(&bpctl_sema))
@@ -5971,7 +5971,7 @@ enum board_type {
PE210G2BPi40,
};
-typedef struct _bpmod_info_t {
+struct bpmod_info {
unsigned int vendor;
unsigned int device;
unsigned int subvendor;
@@ -5979,13 +5979,11 @@ typedef struct _bpmod_info_t {
unsigned int index;
char *bp_name;
-} bpmod_info_t;
+};
-typedef struct _dev_desc {
+struct {
char *name;
-} dev_desc_t;
-
-dev_desc_t dev_desc[] = {
+} dev_desc[] = {
{"Silicom Bypass PXG2BPFI-SD series adapter"},
{"Silicom Bypass PXG2BPFIL-SD series adapter"},
{"Silicom Bypass PXG2BPFILX-SD series adapter"},
@@ -6155,7 +6153,7 @@ dev_desc_t dev_desc[] = {
{0},
};
-static bpmod_info_t tx_ctl_pci_tbl[] = {
+static struct bpmod_info tx_ctl_pci_tbl[] = {
{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFI_SSID, PXG2BPFI,
"PXG2BPFI-SD"},
{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFIL_SSID, PXG2BPFIL,
@@ -6623,7 +6621,7 @@ static bpmod_info_t tx_ctl_pci_tbl[] = {
{0,}
};
-static void find_fw(bpctl_dev_t *dev)
+static void find_fw(struct bpctl_dev *dev)
{
unsigned long mmio_start, mmio_len;
struct pci_dev *pdev1 = dev->pdev;
@@ -6653,7 +6651,7 @@ static void find_fw(bpctl_dev_t *dev)
printk("firmware version: 0x%x\n", dev->bp_fw_ver);
}
-static int init_one(bpctl_dev_t *dev, bpmod_info_t *info, struct pci_dev *pdev1)
+static int init_one(struct bpctl_dev *dev, struct bpmod_info *info, struct pci_dev *pdev1)
{
unsigned long mmio_start, mmio_len;
@@ -6744,7 +6742,7 @@ static int __init bypass_init_module(void)
{
int ret_val, idx, idx_dev = 0;
struct pci_dev *pdev1 = NULL;
- bpctl_dev_t *dev;
+ struct bpctl_dev *dev;
printk(BP_MOD_DESCR " v" BP_MOD_VER "\n");
ret_val = register_chrdev(major_num, DEVICE_NAME, &Fops);
@@ -6769,14 +6767,14 @@ static int __init bypass_init_module(void)
return -1;
}
- bpctl_dev_arr = kmalloc((device_num) * sizeof(bpctl_dev_t), GFP_KERNEL);
+ bpctl_dev_arr = kmalloc((device_num) * sizeof(struct bpctl_dev), GFP_KERNEL);
if (!bpctl_dev_arr) {
printk("Allocation error\n");
unregister_chrdev(major_num, DEVICE_NAME);
return -1;
}
- memset(bpctl_dev_arr, 0, ((device_num) * sizeof(bpctl_dev_t)));
+ memset(bpctl_dev_arr, 0, ((device_num) * sizeof(struct bpctl_dev)));
pdev1 = NULL;
dev = bpctl_dev_arr;
@@ -6797,7 +6795,7 @@ static int __init bypass_init_module(void)
spin_lock_init(&bpvm_lock);
{
- bpctl_dev_t *pbpctl_dev_c = NULL;
+ struct bpctl_dev *pbpctl_dev_c = NULL;
for (idx_dev = 0, dev = bpctl_dev_arr;
idx_dev < device_num && dev->pdev;
idx_dev++, dev++) {
@@ -7169,7 +7167,7 @@ EXPORT_SYMBOL(get_bypass_caps_sd);
int get_bypass_slave_sd(int ifindex)
{
- bpctl_dev_t *pbpctl_dev_out;
+ struct bpctl_dev *pbpctl_dev_out;
int ret = get_bypass_slave_fn(get_dev_idx_p(ifindex), &pbpctl_dev_out);
if (ret == 1)
return pbpctl_dev_out->ifindex;
@@ -7229,7 +7227,7 @@ int bp_proc_create(void)
}
static int procfs_add(char *proc_name, const struct file_operations *fops,
- bpctl_dev_t *dev)
+ struct bpctl_dev *dev)
{
struct bypass_pfs_sd *pfs = &dev->bypass_pfs_set;
if (!proc_create_data(proc_name, 0644, pfs->bypass_entry, fops, dev))
@@ -7264,7 +7262,7 @@ static const struct file_operations name##_ops = { \
static int show_bypass_info(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
seq_printf(m, "Name\t\t\t%s\n", dev->name);
seq_printf(m, "Firmware version\t0x%x\n", dev->bp_fw_ver);
@@ -7274,8 +7272,8 @@ RO_FOPS(bypass_info)
static int show_bypass_slave(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
- bpctl_dev_t *slave = get_status_port_fn(dev);
+ struct bpctl_dev *dev = m->private;
+ struct bpctl_dev *slave = get_status_port_fn(dev);
if (!slave)
slave = dev;
if (!slave)
@@ -7288,7 +7286,7 @@ RO_FOPS(bypass_slave)
static int show_bypass_caps(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_bypass_caps_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "-1\n");
@@ -7300,7 +7298,7 @@ RO_FOPS(bypass_caps)
static int show_wd_set_caps(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_wd_set_caps_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "-1\n");
@@ -7346,7 +7344,7 @@ static ssize_t bypass_write(struct file *file, const char __user *buffer,
}
static int show_bypass(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_bypass_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7370,7 +7368,7 @@ static ssize_t tap_write(struct file *file, const char __user *buffer,
}
static int show_tap(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_tap_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7394,7 +7392,7 @@ static ssize_t disc_write(struct file *file, const char __user *buffer,
}
static int show_disc(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_disc_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7408,7 +7406,7 @@ RW_FOPS(disc)
static int show_bypass_change(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_bypass_change_fn(dev);
if (ret == 1)
seq_puts(m, "on\n");
@@ -7422,7 +7420,7 @@ RO_FOPS(bypass_change)
static int show_tap_change(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_tap_change_fn(dev);
if (ret == 1)
seq_puts(m, "on\n");
@@ -7436,7 +7434,7 @@ RO_FOPS(tap_change)
static int show_disc_change(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_disc_change_fn(dev);
if (ret == 1)
seq_puts(m, "on\n");
@@ -7451,7 +7449,7 @@ RO_FOPS(disc_change)
static ssize_t bypass_wd_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
- bpctl_dev_t *dev = PDE_DATA(file_inode(file));
+ struct bpctl_dev *dev = PDE_DATA(file_inode(file));
int timeout;
int ret = kstrtoint_from_user(buffer, count, 10, &timeout);
if (ret)
@@ -7461,7 +7459,7 @@ static ssize_t bypass_wd_write(struct file *file, const char __user *buffer,
}
static int show_bypass_wd(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = 0, timeout = 0;
ret = get_bypass_wd_fn(dev, &timeout);
@@ -7479,7 +7477,7 @@ RW_FOPS(bypass_wd)
static int show_wd_expire_time(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = 0, timeout = 0;
ret = get_wd_expire_time_fn(dev, &timeout);
if (ret == BP_NOT_CAP)
@@ -7497,7 +7495,7 @@ RO_FOPS(wd_expire_time)
static ssize_t tpl_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
- bpctl_dev_t *dev = PDE_DATA(file_inode(file));
+ struct bpctl_dev *dev = PDE_DATA(file_inode(file));
int tpl_param = user_on_off(buffer, count);
if (tpl_param < 0)
return -1;
@@ -7507,7 +7505,7 @@ static ssize_t tpl_write(struct file *file, const char __user *buffer,
}
static int show_tpl(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_tpl_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7523,7 +7521,7 @@ RW_FOPS(tpl)
static ssize_t wait_at_pwup_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
- bpctl_dev_t *dev = PDE_DATA(file_inode(file));
+ struct bpctl_dev *dev = PDE_DATA(file_inode(file));
int tpl_param = user_on_off(buffer, count);
if (tpl_param < 0)
return -1;
@@ -7533,7 +7531,7 @@ static ssize_t wait_at_pwup_write(struct file *file, const char __user *buffer,
}
static int show_wait_at_pwup(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_bp_wait_at_pwup_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7548,7 +7546,7 @@ RW_FOPS(wait_at_pwup)
static ssize_t hw_reset_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
- bpctl_dev_t *dev = PDE_DATA(file_inode(file));
+ struct bpctl_dev *dev = PDE_DATA(file_inode(file));
int tpl_param = user_on_off(buffer, count);
if (tpl_param < 0)
return -1;
@@ -7558,7 +7556,7 @@ static ssize_t hw_reset_write(struct file *file, const char __user *buffer,
}
static int show_hw_reset(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_bp_hw_reset_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7574,7 +7572,7 @@ RW_FOPS(hw_reset)
static int show_reset_bypass_wd(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = reset_bypass_wd_timer_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7598,7 +7596,7 @@ static ssize_t dis_bypass_write(struct file *file, const char __user *buffer,
}
static int show_dis_bypass(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_dis_bypass_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7622,7 +7620,7 @@ static ssize_t dis_tap_write(struct file *file, const char __user *buffer,
}
static int show_dis_tap(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_dis_tap_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7646,7 +7644,7 @@ static ssize_t dis_disc_write(struct file *file, const char __user *buffer,
}
static int show_dis_disc(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_dis_disc_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7670,7 +7668,7 @@ static ssize_t bypass_pwup_write(struct file *file, const char __user *buffer,
}
static int show_bypass_pwup(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_bypass_pwup_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7694,7 +7692,7 @@ static ssize_t bypass_pwoff_write(struct file *file, const char __user *buffer,
}
static int show_bypass_pwoff(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_bypass_pwoff_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7718,7 +7716,7 @@ static ssize_t tap_pwup_write(struct file *file, const char __user *buffer,
}
static int show_tap_pwup(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_tap_pwup_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7742,7 +7740,7 @@ static ssize_t disc_pwup_write(struct file *file, const char __user *buffer,
}
static int show_disc_pwup(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_disc_pwup_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7766,7 +7764,7 @@ static ssize_t std_nic_write(struct file *file, const char __user *buffer,
}
static int show_std_nic(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_std_nic_fn(dev);
if (ret == BP_NOT_CAP)
seq_puts(m, "fail\n");
@@ -7808,7 +7806,7 @@ static ssize_t wd_exp_mode_write(struct file *file, const char __user *buffer,
}
static int show_wd_exp_mode(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_wd_exp_mode_fn(dev);
if (ret == 1)
seq_puts(m, "tap\n");
@@ -7834,7 +7832,7 @@ static ssize_t wd_autoreset_write(struct file *file, const char __user *buffer,
}
static int show_wd_autoreset(struct seq_file *m, void *v)
{
- bpctl_dev_t *dev = m->private;
+ struct bpctl_dev *dev = m->private;
int ret = get_wd_autoreset_fn(dev);
if (ret >= 0)
seq_printf(m, "%d\n", ret);
@@ -7844,7 +7842,7 @@ static int show_wd_autoreset(struct seq_file *m, void *v)
}
RW_FOPS(wd_autoreset)
-int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block)
+int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block)
{
struct bypass_pfs_sd *current_pfs = &(pbp_device_block->bypass_pfs_set);
static struct proc_dir_entry *procfs_dir;
@@ -7914,7 +7912,7 @@ int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block)
return ret;
}
-int bypass_proc_remove_dev_sd(bpctl_dev_t *pbp_device_block)
+int bypass_proc_remove_dev_sd(struct bpctl_dev *pbp_device_block)
{
struct bypass_pfs_sd *current_pfs = &pbp_device_block->bypass_pfs_set;
diff --git a/drivers/staging/tidspbridge/include/dspbridge/cmm.h b/drivers/staging/tidspbridge/include/dspbridge/cmm.h
index c66bcf7ea90..2adf9ecdf07 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/cmm.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/cmm.h
@@ -293,7 +293,7 @@ extern int cmm_xlator_free_buf(struct cmm_xlatorobject *xlator,
* ======== cmm_xlator_info ========
* Purpose:
* Set/Get process specific "translator" address info.
- * This is used to perform fast virtaul address translation
+ * This is used to perform fast virtual address translation
* for shared memory buffers between the GPP and DSP.
* Parameters:
* xlator: handle to translator.
diff --git a/drivers/staging/tidspbridge/include/dspbridge/proc.h b/drivers/staging/tidspbridge/include/dspbridge/proc.h
index 774a3f6ff20..64c2457aae9 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/proc.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/proc.h
@@ -284,7 +284,7 @@ extern int proc_get_trace(void *hprocessor, u8 * pbuf, u32 max_size);
* user_envp: An Array of Environment settings(Unicode Strings)
* Returns:
* 0: Success.
- * -ENOENT: The DSP Execuetable was not found.
+ * -ENOENT: The DSP Executable was not found.
* -EFAULT: Invalid processor handle.
* -EPERM : Unable to Load the Processor
* Requires:
diff --git a/drivers/staging/tidspbridge/pmgr/dbll.c b/drivers/staging/tidspbridge/pmgr/dbll.c
index c191ae20356..41e88abe47a 100644
--- a/drivers/staging/tidspbridge/pmgr/dbll.c
+++ b/drivers/staging/tidspbridge/pmgr/dbll.c
@@ -1120,8 +1120,11 @@ static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
or DYN_EXTERNAL, then mem granularity information is present
within the section name - only process if there are at least three
tokens within the section name (just a minor optimization) */
- if (count >= 3)
- strict_strtol(sz_last_token, 10, (long *)&req);
+ if (count >= 3) {
+ status = kstrtos32(sz_last_token, 10, &req);
+ if (status)
+ goto func_cont;
+ }
if ((req == 0) || (req == 1)) {
if (strcmp(sz_sec_last_token, "DYN_DARAM") == 0) {
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index 83d629afdfe..d8957a55662 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -56,8 +56,8 @@ MODULE_DEVICE_TABLE(usb, stub_table);
* usbip_status shows the status of usbip-host as long as this driver is bound
* to the target device.
*/
-static ssize_t show_status(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t usbip_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct stub_device *sdev = dev_get_drvdata(dev);
int status;
@@ -73,7 +73,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%d\n", status);
}
-static DEVICE_ATTR(usbip_status, S_IRUGO, show_status, NULL);
+static DEVICE_ATTR_RO(usbip_status);
/*
* usbip_sockfd gets a socket descriptor of an established TCP connection that
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index 7b97df6f2a4..e3fc749c1e7 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -45,19 +45,20 @@ MODULE_PARM_DESC(usbip_debug_flag, "debug flags (defined in usbip_common.h)");
struct device_attribute dev_attr_usbip_debug;
EXPORT_SYMBOL_GPL(dev_attr_usbip_debug);
-static ssize_t show_flag(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t usbip_debug_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%lx\n", usbip_debug_flag);
}
-static ssize_t store_flag(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t usbip_debug_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
sscanf(buf, "%lx", &usbip_debug_flag);
return count;
}
-DEVICE_ATTR(usbip_debug, (S_IRUGO | S_IWUSR), show_flag, store_flag);
+DEVICE_ATTR_RW(usbip_debug);
static void usbip_dump_buffer(char *buff, int bufflen)
{
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
index 25e62e9f0a3..1091bb20de1 100644
--- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
+++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
@@ -230,7 +230,7 @@ static int refresh_class_device_list(void)
sysfs_close_list(cname_list);
- /* seach under /sys/block */
+ /* search under /sys/block */
ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME);
if (ret < 0)
return -1;
diff --git a/drivers/staging/usbip/userspace/src/usbip.c b/drivers/staging/usbip/userspace/src/usbip.c
index fff4b768e70..04a5f20bea6 100644
--- a/drivers/staging/usbip/userspace/src/usbip.c
+++ b/drivers/staging/usbip/userspace/src/usbip.c
@@ -26,6 +26,7 @@
#include <syslog.h>
#include "usbip_common.h"
+#include "usbip_network.h"
#include "usbip.h"
static int usbip_help(int argc, char *argv[]);
@@ -34,7 +35,7 @@ static int usbip_version(int argc, char *argv[]);
static const char usbip_version_string[] = PACKAGE_STRING;
static const char usbip_usage_string[] =
- "usbip [--debug] [--log] [version]\n"
+ "usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
" [help] <command> <args>\n";
static void usbip_usage(void)
@@ -138,9 +139,10 @@ static int run_command(const struct command *cmd, int argc, char *argv[])
int main(int argc, char *argv[])
{
static const struct option opts[] = {
- { "debug", no_argument, NULL, 'd' },
- { "log", no_argument, NULL, 'l' },
- { NULL, 0, NULL, 0 }
+ { "debug", no_argument, NULL, 'd' },
+ { "log", no_argument, NULL, 'l' },
+ { "tcp-port", required_argument, NULL, 't' },
+ { NULL, 0, NULL, 0 }
};
char *cmd;
@@ -150,7 +152,7 @@ int main(int argc, char *argv[])
usbip_use_stderr = 1;
opterr = 0;
for (;;) {
- opt = getopt_long(argc, argv, "+d", opts, NULL);
+ opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
if (opt == -1)
break;
@@ -163,6 +165,9 @@ int main(int argc, char *argv[])
usbip_use_syslog = 1;
openlog("", LOG_PID, LOG_USER);
break;
+ case 't':
+ usbip_setup_port_number(optarg);
+ break;
case '?':
printf("usbip: invalid option\n");
default:
diff --git a/drivers/staging/usbip/userspace/src/usbip_attach.c b/drivers/staging/usbip/userspace/src/usbip_attach.c
index 0ec16e54fb0..08584119652 100644
--- a/drivers/staging/usbip/userspace/src/usbip_attach.c
+++ b/drivers/staging/usbip/userspace/src/usbip_attach.c
@@ -144,7 +144,7 @@ static int query_import_device(int sockfd, char *busid)
return -1;
}
- /* recieve a reply */
+ /* receive a reply */
rc = usbip_net_recv_op_common(sockfd, &code);
if (rc < 0) {
err("recv op_common");
@@ -175,7 +175,7 @@ static int attach_device(char *host, char *busid)
int rc;
int rhport;
- sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING);
+ sockfd = usbip_net_tcp_connect(host, usbip_port_string);
if (sockfd < 0) {
err("tcp connect");
return -1;
@@ -189,7 +189,7 @@ static int attach_device(char *host, char *busid)
close(sockfd);
- rc = record_connection(host, USBIP_PORT_STRING, busid, rhport);
+ rc = record_connection(host, usbip_port_string, busid, rhport);
if (rc < 0) {
err("record connection");
return -1;
diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c
index ff56255f497..237e099337a 100644
--- a/drivers/staging/usbip/userspace/src/usbip_list.c
+++ b/drivers/staging/usbip/userspace/src/usbip_list.c
@@ -131,13 +131,13 @@ static int list_exported_devices(char *host)
int rc;
int sockfd;
- sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING);
+ sockfd = usbip_net_tcp_connect(host, usbip_port_string);
if (sockfd < 0) {
err("could not connect to %s:%s: %s", host,
- USBIP_PORT_STRING, gai_strerror(sockfd));
+ usbip_port_string, gai_strerror(sockfd));
return -1;
}
- dbg("connected to %s:%s", host, USBIP_PORT_STRING);
+ dbg("connected to %s:%s", host, usbip_port_string);
rc = get_exported_devices(host, sockfd);
if (rc < 0) {
diff --git a/drivers/staging/usbip/userspace/src/usbip_network.c b/drivers/staging/usbip/userspace/src/usbip_network.c
index b12448ec69a..c39a07f1d38 100644
--- a/drivers/staging/usbip/userspace/src/usbip_network.c
+++ b/drivers/staging/usbip/userspace/src/usbip_network.c
@@ -28,6 +28,36 @@
#include "usbip_common.h"
#include "usbip_network.h"
+int usbip_port = 3240;
+char *usbip_port_string = "3240";
+
+void usbip_setup_port_number(char *arg)
+{
+ dbg("parsing port arg '%s'", arg);
+ char *end;
+ unsigned long int port = strtoul(arg, &end, 10);
+
+ if (end == arg) {
+ err("port: could not parse '%s' as a decimal integer", arg);
+ return;
+ }
+
+ if (*end != '\0') {
+ err("port: garbage at end of '%s'", arg);
+ return;
+ }
+
+ if (port > UINT16_MAX) {
+ err("port: %s too high (max=%d)",
+ arg, UINT16_MAX);
+ return;
+ }
+
+ usbip_port = port;
+ usbip_port_string = arg;
+ info("using port %d (\"%s\")", usbip_port, usbip_port_string);
+}
+
void usbip_net_pack_uint32_t(int pack, uint32_t *num)
{
uint32_t i;
diff --git a/drivers/staging/usbip/userspace/src/usbip_network.h b/drivers/staging/usbip/userspace/src/usbip_network.h
index 1bbefc993fb..2d0e4277b62 100644
--- a/drivers/staging/usbip/userspace/src/usbip_network.h
+++ b/drivers/staging/usbip/userspace/src/usbip_network.h
@@ -14,8 +14,9 @@
#include <stdint.h>
-#define USBIP_PORT 3240
-#define USBIP_PORT_STRING "3240"
+extern int usbip_port;
+extern char *usbip_port_string;
+void usbip_setup_port_number(char *arg);
/* ---------------------------------------------------------------------- */
/* Common header for all the kinds of PDUs. */
diff --git a/drivers/staging/usbip/userspace/src/usbipd.c b/drivers/staging/usbip/userspace/src/usbipd.c
index 3e913b861dc..1c76cfd274d 100644
--- a/drivers/staging/usbip/userspace/src/usbipd.c
+++ b/drivers/staging/usbip/userspace/src/usbipd.c
@@ -50,21 +50,30 @@
#define MAIN_LOOP_TIMEOUT 10
+#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
+
static const char usbip_version_string[] = PACKAGE_STRING;
static const char usbipd_help_string[] =
- "usage: usbipd [options] \n"
- " -D, --daemon \n"
- " Run as a daemon process. \n"
- " \n"
- " -d, --debug \n"
- " Print debugging information. \n"
- " \n"
- " -h, --help \n"
- " Print this help. \n"
- " \n"
- " -v, --version \n"
- " Show version. \n";
+ "usage: usbipd [options]\n"
+ " -D, --daemon\n"
+ " Run as a daemon process.\n"
+ "\n"
+ " -d, --debug\n"
+ " Print debugging information.\n"
+ "\n"
+ " -PFILE, --pid FILE\n"
+ " Write process id to FILE.\n"
+ " If no FILE specified, use " DEFAULT_PID_FILE "\n"
+ "\n"
+ " -tPORT, --tcp-port PORT\n"
+ " Listen on TCP/IP port PORT.\n"
+ "\n"
+ " -h, --help\n"
+ " Print this help.\n"
+ "\n"
+ " -v, --version\n"
+ " Show version.\n";
static void usbipd_help(void)
{
@@ -286,13 +295,13 @@ static int do_accept(int listenfd)
memset(&ss, 0, sizeof(ss));
- connfd = accept(listenfd, (struct sockaddr *) &ss, &len);
+ connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
if (connfd < 0) {
err("failed to accept connection");
return -1;
}
- rc = getnameinfo((struct sockaddr *) &ss, len, host, sizeof(host),
+ rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
if (rc)
err("getnameinfo: %s", gai_strerror(rc));
@@ -328,56 +337,69 @@ int process_request(int listenfd)
return 0;
}
-static void log_addrinfo(struct addrinfo *ai)
+static void addrinfo_to_text(struct addrinfo *ai, char buf[],
+ const size_t buf_size)
{
char hbuf[NI_MAXHOST];
char sbuf[NI_MAXSERV];
int rc;
+ buf[0] = '\0';
+
rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
if (rc)
err("getnameinfo: %s", gai_strerror(rc));
- info("listening on %s:%s", hbuf, sbuf);
+ snprintf(buf, buf_size, "%s:%s", hbuf, sbuf);
}
static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[])
{
struct addrinfo *ai;
int ret, nsockfd = 0;
+ const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2;
+ char ai_buf[ai_buf_size];
for (ai = ai_head; ai && nsockfd < MAXSOCKFD; ai = ai->ai_next) {
- sockfdlist[nsockfd] = socket(ai->ai_family, ai->ai_socktype,
- ai->ai_protocol);
- if (sockfdlist[nsockfd] < 0)
+ int sock;
+ addrinfo_to_text(ai, ai_buf, ai_buf_size);
+ dbg("opening %s", ai_buf);
+ sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (sock < 0) {
+ err("socket: %s: %d (%s)",
+ ai_buf, errno, strerror(errno));
continue;
+ }
- usbip_net_set_reuseaddr(sockfdlist[nsockfd]);
- usbip_net_set_nodelay(sockfdlist[nsockfd]);
+ usbip_net_set_reuseaddr(sock);
+ usbip_net_set_nodelay(sock);
- if (sockfdlist[nsockfd] >= FD_SETSIZE) {
- close(sockfdlist[nsockfd]);
- sockfdlist[nsockfd] = -1;
+ if (sock >= FD_SETSIZE) {
+ err("FD_SETSIZE: %s: sock=%d, max=%d",
+ ai_buf, sock, FD_SETSIZE);
+ close(sock);
continue;
}
- ret = bind(sockfdlist[nsockfd], ai->ai_addr, ai->ai_addrlen);
+ ret = bind(sock, ai->ai_addr, ai->ai_addrlen);
if (ret < 0) {
- close(sockfdlist[nsockfd]);
- sockfdlist[nsockfd] = -1;
+ err("bind: %s: %d (%s)",
+ ai_buf, errno, strerror(errno));
+ close(sock);
continue;
}
- ret = listen(sockfdlist[nsockfd], SOMAXCONN);
+ ret = listen(sock, SOMAXCONN);
if (ret < 0) {
- close(sockfdlist[nsockfd]);
- sockfdlist[nsockfd] = -1;
+ err("listen: %s: %d (%s)",
+ ai_buf, errno, strerror(errno));
+ close(sock);
continue;
}
- log_addrinfo(ai);
- nsockfd++;
+ info("listening on %s", ai_buf);
+ sockfdlist[nsockfd++] = sock;
}
if (nsockfd == 0)
@@ -398,9 +420,9 @@ static struct addrinfo *do_getaddrinfo(char *host, int ai_family)
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
- rc = getaddrinfo(host, USBIP_PORT_STRING, &hints, &ai_head);
+ rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head);
if (rc) {
- err("failed to get a network address %s: %s", USBIP_PORT_STRING,
+ err("failed to get a network address %s: %s", usbip_port_string,
gai_strerror(rc));
return NULL;
}
@@ -426,6 +448,31 @@ static void set_signal(void)
sigaction(SIGCLD, &act, NULL);
}
+static const char *pid_file;
+
+static void write_pid_file()
+{
+ if (pid_file) {
+ dbg("creating pid file %s", pid_file);
+ FILE *fp = fopen(pid_file, "w");
+ if (!fp) {
+ err("pid_file: %s: %d (%s)",
+ pid_file, errno, strerror(errno));
+ return;
+ }
+ fprintf(fp, "%d\n", getpid());
+ fclose(fp);
+ }
+}
+
+static void remove_pid_file()
+{
+ if (pid_file) {
+ dbg("removing pid file %s", pid_file);
+ unlink(pid_file);
+ }
+}
+
static int do_standalone_mode(int daemonize)
{
struct addrinfo *ai_head;
@@ -452,6 +499,7 @@ static int do_standalone_mode(int daemonize)
usbip_use_syslog = 1;
}
set_signal();
+ write_pid_file();
ai_head = do_getaddrinfo(NULL, PF_UNSPEC);
if (!ai_head) {
@@ -496,8 +544,9 @@ static int do_standalone_mode(int daemonize)
process_request(sockfdlist[i]);
}
}
- } else
+ } else {
dbg("heartbeat timeout on ppoll()");
+ }
}
info("shutting down " PROGNAME);
@@ -511,11 +560,13 @@ static int do_standalone_mode(int daemonize)
int main(int argc, char *argv[])
{
static const struct option longopts[] = {
- { "daemon", no_argument, NULL, 'D' },
- { "debug", no_argument, NULL, 'd' },
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, 'v' },
- { NULL, 0, NULL, 0 }
+ { "daemon", no_argument, NULL, 'D' },
+ { "debug", no_argument, NULL, 'd' },
+ { "pid", optional_argument, NULL, 'P' },
+ { "tcp-port", required_argument, NULL, 't' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
};
enum {
@@ -526,6 +577,7 @@ int main(int argc, char *argv[])
int daemonize = 0;
int opt, rc = -1;
+ pid_file = NULL;
usbip_use_stderr = 1;
usbip_use_syslog = 0;
@@ -535,7 +587,7 @@ int main(int argc, char *argv[])
cmd = cmd_standalone_mode;
for (;;) {
- opt = getopt_long(argc, argv, "Ddhv", longopts, NULL);
+ opt = getopt_long(argc, argv, "DdP::t:hv", longopts, NULL);
if (opt == -1)
break;
@@ -550,6 +602,12 @@ int main(int argc, char *argv[])
case 'h':
cmd = cmd_help;
break;
+ case 'P':
+ pid_file = optarg ? optarg : DEFAULT_PID_FILE;
+ break;
+ case 't':
+ usbip_setup_port_number(optarg);
+ break;
case 'v':
cmd = cmd_version;
break;
@@ -563,6 +621,7 @@ int main(int argc, char *argv[])
switch (cmd) {
case cmd_standalone_mode:
rc = do_standalone_mode(daemonize);
+ remove_pid_file();
break;
case cmd_version:
printf(PROGNAME " (%s)\n", usbip_version_string);
diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c
index c66e9c05c76..9b51586d11d 100644
--- a/drivers/staging/usbip/vhci_sysfs.c
+++ b/drivers/staging/usbip/vhci_sysfs.c
@@ -27,7 +27,7 @@
/* TODO: refine locking ?*/
/* Sysfs entry to show port status */
-static ssize_t show_status(struct device *dev, struct device_attribute *attr,
+static ssize_t status_show(struct device *dev, struct device_attribute *attr,
char *out)
{
char *s = out;
@@ -74,7 +74,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr,
return out - s;
}
-static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+static DEVICE_ATTR_RO(status);
/* Sysfs entry to shutdown a virtual connection */
static int vhci_port_disconnect(__u32 rhport)
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index 08b250f01da..7f36a7103c3 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -3370,8 +3370,8 @@ viawget_resume(struct pci_dev *pcid)
PSMgmtObject pMgmt = pDevice->pMgmt;
int power_status; // to silence the compiler
- power_status = pci_set_power_state(pcid, 0);
- power_status = pci_enable_wake(pcid, 0, 0);
+ power_status = pci_set_power_state(pcid, PCI_D0);
+ power_status = pci_enable_wake(pcid, PCI_D0, 0);
pci_restore_state(pcid);
if (netif_running(pDevice->dev)) {
spin_lock_irq(&pDevice->lock);
diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c
index 33fa76759bf..1e8b8412e67 100644
--- a/drivers/staging/vt6656/baseband.c
+++ b/drivers/staging/vt6656/baseband.c
@@ -680,7 +680,6 @@ BBuGetFrameTime(
unsigned int uRate = 0;
if (uRateIdx > RATE_54M) {
- ASSERT(0);
return 0;
}
@@ -724,16 +723,16 @@ BBuGetFrameTime(
* cbFrameLength - Tx Frame Length
* wRate - Tx Rate
* Out:
- * pwPhyLen - pointer to Phy Length field
- * pbyPhySrv - pointer to Phy Service field
- * pbyPhySgn - pointer to Phy Signal field
+ * struct vnt_phy_field *phy
+ * - pointer to Phy Length field
+ * - pointer to Phy Service field
+ * - pointer to Phy Signal field
*
* Return Value: none
*
*/
void BBvCalculateParameter(struct vnt_private *pDevice, u32 cbFrameLength,
- u16 wRate, u8 byPacketType, u16 *pwPhyLen, u8 *pbyPhySrv,
- u8 *pbyPhySgn)
+ u16 wRate, u8 byPacketType, struct vnt_phy_field *phy)
{
u32 cbBitCount;
u32 cbUsCount = 0;
@@ -748,15 +747,15 @@ void BBvCalculateParameter(struct vnt_private *pDevice, u32 cbFrameLength,
switch (wRate) {
case RATE_1M :
cbUsCount = cbBitCount;
- *pbyPhySgn = 0x00;
+ phy->signal = 0x00;
break;
case RATE_2M :
cbUsCount = cbBitCount / 2;
if (byPreambleType == 1)
- *pbyPhySgn = 0x09;
+ phy->signal = 0x09;
else // long preamble
- *pbyPhySgn = 0x01;
+ phy->signal = 0x01;
break;
case RATE_5M :
@@ -767,9 +766,9 @@ void BBvCalculateParameter(struct vnt_private *pDevice, u32 cbFrameLength,
if (cbTmp != cbBitCount)
cbUsCount ++;
if (byPreambleType == 1)
- *pbyPhySgn = 0x0a;
+ phy->signal = 0x0a;
else // long preamble
- *pbyPhySgn = 0x02;
+ phy->signal = 0x02;
break;
case RATE_11M :
@@ -784,103 +783,102 @@ void BBvCalculateParameter(struct vnt_private *pDevice, u32 cbFrameLength,
bExtBit = true;
}
if (byPreambleType == 1)
- *pbyPhySgn = 0x0b;
+ phy->signal = 0x0b;
else // long preamble
- *pbyPhySgn = 0x03;
+ phy->signal = 0x03;
break;
case RATE_6M :
if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9B; //1001 1011
+ phy->signal = 0x9b;
}
else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8B; //1000 1011
+ phy->signal = 0x8b;
}
break;
case RATE_9M :
if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9F; //1001 1111
+ phy->signal = 0x9f;
}
else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8F; //1000 1111
+ phy->signal = 0x8f;
}
break;
case RATE_12M :
if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9A; //1001 1010
+ phy->signal = 0x9a;
}
else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8A; //1000 1010
+ phy->signal = 0x8a;
}
break;
case RATE_18M :
if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9E; //1001 1110
+ phy->signal = 0x9e;
}
else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8E; //1000 1110
+ phy->signal = 0x8e;
}
break;
case RATE_24M :
if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x99; //1001 1001
+ phy->signal = 0x99;
}
else {//11g, 2.4GHZ
- *pbyPhySgn = 0x89; //1000 1001
+ phy->signal = 0x89;
}
break;
case RATE_36M :
if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9D; //1001 1101
+ phy->signal = 0x9d;
}
else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8D; //1000 1101
+ phy->signal = 0x8d;
}
break;
case RATE_48M :
if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x98; //1001 1000
+ phy->signal = 0x98;
}
else {//11g, 2.4GHZ
- *pbyPhySgn = 0x88; //1000 1000
+ phy->signal = 0x88;
}
break;
case RATE_54M :
if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9C; //1001 1100
+ phy->signal = 0x9c;
}
else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8C; //1000 1100
+ phy->signal = 0x8c;
}
break;
default :
if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9C; //1001 1100
+ phy->signal = 0x9c;
}
else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8C; //1000 1100
+ phy->signal = 0x8c;
}
break;
}
- if (byPacketType == PK_TYPE_11B) {
- *pbyPhySrv = 0x00;
- if (bExtBit)
- *pbyPhySrv = *pbyPhySrv | 0x80;
- *pwPhyLen = (u16) cbUsCount;
- }
- else {
- *pbyPhySrv = 0x00;
- *pwPhyLen = (u16)cbFrameLength;
- }
+ if (byPacketType == PK_TYPE_11B) {
+ phy->service = 0x00;
+ if (bExtBit)
+ phy->service |= 0x80;
+ phy->len = cpu_to_le16((u16)cbUsCount);
+ } else {
+ phy->service = 0x00;
+ phy->len = cpu_to_le16((u16)cbFrameLength);
+ }
}
/*
diff --git a/drivers/staging/vt6656/baseband.h b/drivers/staging/vt6656/baseband.h
index 0a634adabf0..79faedf4a5e 100644
--- a/drivers/staging/vt6656/baseband.h
+++ b/drivers/staging/vt6656/baseband.h
@@ -81,6 +81,13 @@
#define TOP_RATE_2M 0x00200000
#define TOP_RATE_1M 0x00100000
+/* Length, Service, and Signal fields of Phy for Tx */
+struct vnt_phy_field {
+ u8 signal;
+ u8 service;
+ __le16 len;
+} __packed;
+
unsigned int
BBuGetFrameTime(
u8 byPreambleType,
@@ -90,8 +97,7 @@ BBuGetFrameTime(
);
void BBvCalculateParameter(struct vnt_private *, u32 cbFrameLength,
- u16 wRate, u8 byPacketType, u16 *pwPhyLen, u8 *pbyPhySrv,
- u8 *pbyPhySgn);
+ u16 wRate, u8 byPacketType, struct vnt_phy_field *);
/* timer for antenna diversity */
diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c
index 24291aee58b..dbf11ecb794 100644
--- a/drivers/staging/vt6656/card.c
+++ b/drivers/staging/vt6656/card.c
@@ -319,53 +319,27 @@ CARDvCalculateOFDMRParameter (
*/
void CARDvSetRSPINF(struct vnt_private *pDevice, u8 byBBType)
{
- u8 abyServ[4] = {0, 0, 0, 0}; /* For CCK */
- u8 abySignal[4] = {0, 0, 0, 0};
- u16 awLen[4] = {0, 0, 0, 0};
+ struct vnt_phy_field phy[4];
u8 abyTxRate[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; /* For OFDM */
u8 abyRsvTime[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
u8 abyData[34];
int i;
//RSPINF_b_1
- BBvCalculateParameter(pDevice,
- 14,
- swGetCCKControlRate(pDevice, RATE_1M),
- PK_TYPE_11B,
- &awLen[0],
- &abyServ[0],
- &abySignal[0]
- );
+ BBvCalculateParameter(pDevice, 14,
+ swGetCCKControlRate(pDevice, RATE_1M), PK_TYPE_11B, &phy[0]);
///RSPINF_b_2
- BBvCalculateParameter(pDevice,
- 14,
- swGetCCKControlRate(pDevice, RATE_2M),
- PK_TYPE_11B,
- &awLen[1],
- &abyServ[1],
- &abySignal[1]
- );
+ BBvCalculateParameter(pDevice, 14,
+ swGetCCKControlRate(pDevice, RATE_2M), PK_TYPE_11B, &phy[1]);
//RSPINF_b_5
- BBvCalculateParameter(pDevice,
- 14,
- swGetCCKControlRate(pDevice, RATE_5M),
- PK_TYPE_11B,
- &awLen[2],
- &abyServ[2],
- &abySignal[2]
- );
+ BBvCalculateParameter(pDevice, 14,
+ swGetCCKControlRate(pDevice, RATE_5M), PK_TYPE_11B, &phy[2]);
//RSPINF_b_11
- BBvCalculateParameter(pDevice,
- 14,
- swGetCCKControlRate(pDevice, RATE_11M),
- PK_TYPE_11B,
- &awLen[3],
- &abyServ[3],
- &abySignal[3]
- );
+ BBvCalculateParameter(pDevice, 14,
+ swGetCCKControlRate(pDevice, RATE_11M), PK_TYPE_11B, &phy[3]);
//RSPINF_a_6
CARDvCalculateOFDMRParameter (RATE_6M,
@@ -421,25 +395,21 @@ void CARDvSetRSPINF(struct vnt_private *pDevice, u8 byBBType)
&abyTxRate[8],
&abyRsvTime[8]);
- abyData[0] = (u8)(awLen[0]&0xFF);
- abyData[1] = (u8)(awLen[0]>>8);
- abyData[2] = abySignal[0];
- abyData[3] = abyServ[0];
-
- abyData[4] = (u8)(awLen[1]&0xFF);
- abyData[5] = (u8)(awLen[1]>>8);
- abyData[6] = abySignal[1];
- abyData[7] = abyServ[1];
-
- abyData[8] = (u8)(awLen[2]&0xFF);
- abyData[9] = (u8)(awLen[2]>>8);
- abyData[10] = abySignal[2];
- abyData[11] = abyServ[2];
-
- abyData[12] = (u8)(awLen[3]&0xFF);
- abyData[13] = (u8)(awLen[3]>>8);
- abyData[14] = abySignal[3];
- abyData[15] = abyServ[3];
+ put_unaligned(phy[0].len, (u16 *)&abyData[0]);
+ abyData[2] = phy[0].signal;
+ abyData[3] = phy[0].service;
+
+ put_unaligned(phy[1].len, (u16 *)&abyData[4]);
+ abyData[6] = phy[1].signal;
+ abyData[7] = phy[1].service;
+
+ put_unaligned(phy[2].len, (u16 *)&abyData[8]);
+ abyData[10] = phy[2].signal;
+ abyData[11] = phy[2].service;
+
+ put_unaligned(phy[3].len, (u16 *)&abyData[12]);
+ abyData[14] = phy[3].signal;
+ abyData[15] = phy[3].service;
for (i = 0; i < 9; i++) {
abyData[16+i*2] = abyTxRate[i];
diff --git a/drivers/staging/vt6656/desc.h b/drivers/staging/vt6656/desc.h
index 64cb046fe98..4675135aa25 100644
--- a/drivers/staging/vt6656/desc.h
+++ b/drivers/staging/vt6656/desc.h
@@ -144,160 +144,6 @@
#define TD_FLAGS_PS_RETRY 0x04 /* check if PS STA frame re-transmit */
/*
- * RsvTime buffer header
- */
-typedef struct tagSRrvTime_gRTS {
- u16 wRTSTxRrvTime_ba;
- u16 wRTSTxRrvTime_aa;
- u16 wRTSTxRrvTime_bb;
- u16 wReserved;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
-} __attribute__ ((__packed__))
-SRrvTime_gRTS, *PSRrvTime_gRTS;
-
-typedef const SRrvTime_gRTS *PCSRrvTime_gRTS;
-
-typedef struct tagSRrvTime_gCTS {
- u16 wCTSTxRrvTime_ba;
- u16 wReserved;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
-} __attribute__ ((__packed__))
-SRrvTime_gCTS, *PSRrvTime_gCTS;
-
-typedef const SRrvTime_gCTS *PCSRrvTime_gCTS;
-
-typedef struct tagSRrvTime_ab {
- u16 wRTSTxRrvTime;
- u16 wTxRrvTime;
-} __attribute__ ((__packed__))
-SRrvTime_ab, *PSRrvTime_ab;
-
-typedef const SRrvTime_ab *PCSRrvTime_ab;
-
-typedef struct tagSRrvTime_atim {
- u16 wCTSTxRrvTime_ba;
- u16 wTxRrvTime_a;
-} __attribute__ ((__packed__))
-SRrvTime_atim, *PSRrvTime_atim;
-
-typedef const SRrvTime_atim *PCSRrvTime_atim;
-
-/*
- * RTS buffer header
- */
-typedef struct tagSRTSData {
- u16 wFrameControl;
- u16 wDurationID;
- u8 abyRA[ETH_ALEN];
- u8 abyTA[ETH_ALEN];
-} __attribute__ ((__packed__))
-SRTSData, *PSRTSData;
-
-typedef const SRTSData *PCSRTSData;
-
-typedef struct tagSRTS_g {
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_ba;
- u16 wDuration_aa;
- u16 wDuration_bb;
- u16 wReserved;
- SRTSData Data;
-} __attribute__ ((__packed__))
-SRTS_g, *PSRTS_g;
-typedef const SRTS_g *PCSRTS_g;
-
-typedef struct tagSRTS_g_FB {
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_ba;
- u16 wDuration_aa;
- u16 wDuration_bb;
- u16 wReserved;
- u16 wRTSDuration_ba_f0;
- u16 wRTSDuration_aa_f0;
- u16 wRTSDuration_ba_f1;
- u16 wRTSDuration_aa_f1;
- SRTSData Data;
-} __attribute__ ((__packed__))
-SRTS_g_FB, *PSRTS_g_FB;
-
-typedef const SRTS_g_FB *PCSRTS_g_FB;
-
-typedef struct tagSRTS_ab {
- u8 bySignalField;
- u8 byServiceField;
- u16 wTransmitLength;
- u16 wDuration;
- u16 wReserved;
- SRTSData Data;
-} __attribute__ ((__packed__))
-SRTS_ab, *PSRTS_ab;
-
-typedef const SRTS_ab *PCSRTS_ab;
-
-typedef struct tagSRTS_a_FB {
- u8 bySignalField;
- u8 byServiceField;
- u16 wTransmitLength;
- u16 wDuration;
- u16 wReserved;
- u16 wRTSDuration_f0;
- u16 wRTSDuration_f1;
- SRTSData Data;
-} __attribute__ ((__packed__))
-SRTS_a_FB, *PSRTS_a_FB;
-
-typedef const SRTS_a_FB *PCSRTS_a_FB;
-
-/*
- * CTS buffer header
- */
-typedef struct tagSCTSData {
- u16 wFrameControl;
- u16 wDurationID;
- u8 abyRA[ETH_ALEN];
- u16 wReserved;
-} __attribute__ ((__packed__))
-SCTSData, *PSCTSData;
-
-typedef struct tagSCTS {
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u16 wDuration_ba;
- u16 wReserved;
- SCTSData Data;
-} __attribute__ ((__packed__))
-SCTS, *PSCTS;
-
-typedef const SCTS *PCSCTS;
-
-typedef struct tagSCTS_FB {
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u16 wDuration_ba;
- u16 wReserved;
- u16 wCTSDuration_ba_f0;
- u16 wCTSDuration_ba_f1;
- SCTSData Data;
-} __attribute__ ((__packed__))
-SCTS_FB, *PSCTS_FB;
-
-typedef const SCTS_FB *PCSCTS_FB;
-
-/*
* TX FIFO header
*/
typedef struct tagSTxBufHead {
@@ -317,76 +163,6 @@ typedef struct tagSTxShortBufHead {
STxShortBufHead, *PSTxShortBufHead;
typedef const STxShortBufHead *PCSTxShortBufHead;
-/*
- * TX data header
- */
-typedef struct tagSTxDataHead_g {
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
-} __attribute__ ((__packed__))
-STxDataHead_g, *PSTxDataHead_g;
-
-typedef const STxDataHead_g *PCSTxDataHead_g;
-
-typedef struct tagSTxDataHead_g_FB {
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wDuration_a_f0;
- u16 wDuration_a_f1;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
-} __attribute__ ((__packed__))
-STxDataHead_g_FB, *PSTxDataHead_g_FB;
-typedef const STxDataHead_g_FB *PCSTxDataHead_g_FB;
-
-typedef struct tagSTxDataHead_ab {
- u8 bySignalField;
- u8 byServiceField;
- u16 wTransmitLength;
- u16 wDuration;
- u16 wTimeStampOff;
-} __attribute__ ((__packed__))
-STxDataHead_ab, *PSTxDataHead_ab;
-typedef const STxDataHead_ab *PCSTxDataHead_ab;
-
-typedef struct tagSTxDataHead_a_FB {
- u8 bySignalField;
- u8 byServiceField;
- u16 wTransmitLength;
- u16 wDuration;
- u16 wTimeStampOff;
- u16 wDuration_f0;
- u16 wDuration_f1;
-} __attribute__ ((__packed__))
-STxDataHead_a_FB, *PSTxDataHead_a_FB;
-typedef const STxDataHead_a_FB *PCSTxDataHead_a_FB;
-
-/*
- * MICHDR data header
- */
-typedef struct tagSMICHDRHead {
- u32 adwHDR0[4];
- u32 adwHDR1[4];
- u32 adwHDR2[4];
-} __attribute__ ((__packed__))
-SMICHDRHead, *PSMICHDRHead;
-
-typedef const SMICHDRHead *PCSMICHDRHead;
-
typedef struct tagSBEACONCtl {
u32 BufReady:1;
u32 TSF:15;
diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h
index f07ba242811..8e396341c5e 100644
--- a/drivers/staging/vt6656/device.h
+++ b/drivers/staging/vt6656/device.h
@@ -166,8 +166,7 @@ typedef enum _CONTEXT_TYPE {
} CONTEXT_TYPE;
/* RCB (Receive Control Block) */
-typedef struct _RCB
-{
+struct vnt_rcb {
void *Next;
signed long Ref;
void *pDevice;
@@ -175,21 +174,20 @@ typedef struct _RCB
struct vnt_rx_mgmt sMngPacket;
struct sk_buff *skb;
int bBoolInUse;
-
-} RCB, *PRCB;
+};
/* used to track bulk out irps */
-typedef struct _USB_SEND_CONTEXT {
- void *pDevice;
- struct sk_buff *pPacket;
- struct urb *pUrb;
- unsigned int uBufLen;
- CONTEXT_TYPE Type;
- struct ethhdr sEthHeader;
- void *Next;
- bool bBoolInUse;
- unsigned char Data[MAX_TOTAL_SIZE_WITH_ALL_HEADERS];
-} USB_SEND_CONTEXT, *PUSB_SEND_CONTEXT;
+struct vnt_usb_send_context {
+ void *pDevice;
+ struct sk_buff *pPacket;
+ struct urb *pUrb;
+ unsigned int uBufLen;
+ CONTEXT_TYPE Type;
+ struct ethhdr sEthHeader;
+ void *Next;
+ bool bBoolInUse;
+ unsigned char Data[MAX_TOTAL_SIZE_WITH_ALL_HEADERS];
+};
/* structure got from configuration file as user-desired default settings */
typedef struct _DEFAULT_CONFIG {
@@ -416,21 +414,21 @@ struct vnt_private {
u32 int_interval;
/* Variables to track resources for the BULK In Pipe */
- PRCB pRCBMem;
- PRCB apRCB[CB_MAX_RX_DESC];
+ struct vnt_rcb *pRCBMem;
+ struct vnt_rcb *apRCB[CB_MAX_RX_DESC];
u32 cbRD;
- PRCB FirstRecvFreeList;
- PRCB LastRecvFreeList;
+ struct vnt_rcb *FirstRecvFreeList;
+ struct vnt_rcb *LastRecvFreeList;
u32 NumRecvFreeList;
- PRCB FirstRecvMngList;
- PRCB LastRecvMngList;
+ struct vnt_rcb *FirstRecvMngList;
+ struct vnt_rcb *LastRecvMngList;
u32 NumRecvMngList;
int bIsRxWorkItemQueued;
int bIsRxMngWorkItemQueued;
unsigned long ulRcvRefCount; /* packets that have not returned back */
/* Variables to track resources for the BULK Out Pipe */
- PUSB_SEND_CONTEXT apTD[CB_MAX_TX_DESC];
+ struct vnt_usb_send_context *apTD[CB_MAX_TX_DESC];
u32 cbTD;
/* Variables to track resources for the Interrupt In Pipe */
@@ -591,18 +589,11 @@ struct vnt_private {
u8 abyBSSID[ETH_ALEN];
u8 abyDesireBSSID[ETH_ALEN];
- u16 wCTSDuration; /* update while speed change */
- u16 wACKDuration;
- u16 wRTSTransmitLen;
- u8 byRTSServiceField;
- u8 byRTSSignalField;
-
u32 dwMaxReceiveLifetime; /* dot11MaxReceiveLifetime */
int bCCK;
int bEncryptionEnable;
int bLongHeader;
- int bSoftwareGenCrcErr;
int bShortSlotTime;
int bProtectMode;
int bNonERPPresent;
@@ -781,7 +772,7 @@ struct vnt_private {
#define DequeueRCB(Head, Tail) \
{ \
- PRCB RCB = Head; \
+ struct vnt_rcb *RCB = Head; \
if (!RCB->Next) { \
Tail = NULL; \
} \
diff --git a/drivers/staging/vt6656/device_cfg.h b/drivers/staging/vt6656/device_cfg.h
index ea66b975fa5..a97f7bb13db 100644
--- a/drivers/staging/vt6656/device_cfg.h
+++ b/drivers/staging/vt6656/device_cfg.h
@@ -82,18 +82,4 @@ typedef enum _chip_type {
VT3184 = 1
} CHIP_TYPE, *PCHIP_TYPE;
-#ifdef VIAWET_DEBUG
-#define ASSERT(x) { \
- if (!(x)) { \
- printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x, \
- __FUNCTION__, __LINE__);\
- *(int *) 0 = 0; \
- } \
-}
-#define DBG_PORT80(value) outb(value, 0x80)
-#else
-#define ASSERT(x)
-#define DBG_PORT80(value)
-#endif
-
#endif
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index 7ec166a2ac8..ea7d443b11d 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -246,7 +246,7 @@ s_vGetDASA (
*pcbHeaderSize = cbHeaderSize;
}
-int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
+int RXbBulkInProcessData(struct vnt_private *pDevice, struct vnt_rcb *pRCB,
unsigned long BytesToIndicate)
{
struct net_device_stats *pStats = &pDevice->stats;
@@ -271,7 +271,7 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
/* signed long ldBm = 0; */
int bIsWEP = false; int bExtIV = false;
u32 dwWbkStatus;
- PRCB pRCBIndicate = pRCB;
+ struct vnt_rcb *pRCBIndicate = pRCB;
u8 *pbyDAddress;
u16 *pwPLCP_Length;
u8 abyVaildRate[MAX_RATE]
@@ -314,7 +314,6 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
(BytesToIndicate < (*pwPLCP_Length)) ) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Wrong PLCP Length %x\n", (int) *pwPLCP_Length);
- ASSERT(0);
return false;
}
for ( ii=RATE_1M;ii<MAX_RATE;ii++) {
@@ -1337,7 +1336,7 @@ static int s_bAPModeRxData(struct vnt_private *pDevice, struct sk_buff *skb,
void RXvWorkItem(struct vnt_private *pDevice)
{
int ntStatus;
- PRCB pRCB = NULL;
+ struct vnt_rcb *pRCB = NULL;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Rx Polling Thread\n");
spin_lock_irq(&pDevice->lock);
@@ -1347,7 +1346,6 @@ void RXvWorkItem(struct vnt_private *pDevice)
(pDevice->NumRecvFreeList != 0) ) {
pRCB = pDevice->FirstRecvFreeList;
pDevice->NumRecvFreeList--;
- ASSERT(pRCB);// cannot be NULL
DequeueRCB(pDevice->FirstRecvFreeList, pDevice->LastRecvFreeList);
ntStatus = PIPEnsBulkInUsbRead(pDevice, pRCB);
}
@@ -1356,15 +1354,12 @@ void RXvWorkItem(struct vnt_private *pDevice)
}
-void RXvFreeRCB(PRCB pRCB, int bReAllocSkb)
+void RXvFreeRCB(struct vnt_rcb *pRCB, int bReAllocSkb)
{
struct vnt_private *pDevice = pRCB->pDevice;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->RXvFreeRCB\n");
- ASSERT(!pRCB->Ref); // should be 0
- ASSERT(pRCB->pDevice); // shouldn't be NULL
-
if (bReAllocSkb == false) {
kfree_skb(pRCB->skb);
bReAllocSkb = true;
@@ -1396,7 +1391,7 @@ void RXvFreeRCB(PRCB pRCB, int bReAllocSkb)
void RXvMngWorkItem(struct vnt_private *pDevice)
{
- PRCB pRCB = NULL;
+ struct vnt_rcb *pRCB = NULL;
struct vnt_rx_mgmt *pRxPacket;
int bReAllocSkb = false;
@@ -1411,7 +1406,6 @@ void RXvMngWorkItem(struct vnt_private *pDevice)
if(!pRCB){
break;
}
- ASSERT(pRCB);// cannot be NULL
pRxPacket = &(pRCB->sMngPacket);
vMgrRxManagePacket(pDevice, &pDevice->vnt_mgmt, pRxPacket);
pRCB->Ref--;
diff --git a/drivers/staging/vt6656/dpc.h b/drivers/staging/vt6656/dpc.h
index 876468f2c3d..95388dc03ee 100644
--- a/drivers/staging/vt6656/dpc.h
+++ b/drivers/staging/vt6656/dpc.h
@@ -36,9 +36,9 @@ void RXvWorkItem(void *Context);
void RXvMngWorkItem(void *Context);
-void RXvFreeRCB(PRCB pRCB, int bReAllocSkb);
+void RXvFreeRCB(struct vnt_rcb *pRCB, int bReAllocSkb);
-int RXbBulkInProcessData(struct vnt_private *, PRCB pRCB,
+int RXbBulkInProcessData(struct vnt_private *, struct vnt_rcb *pRCB,
unsigned long BytesToIndicate);
#endif /* __RXTX_H__ */
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 3a3fdc58b6d..536971786ae 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -267,7 +267,6 @@ device_set_options(struct vnt_private *pDevice) {
pDevice->bUpdateBBVGA = true;
pDevice->byFOETuning = 0;
pDevice->byAutoPwrTunning = 0;
- pDevice->wCTSDuration = 0;
pDevice->byPreambleType = 0;
pDevice->bExistSWNetAddr = false;
/* pDevice->bDiversityRegCtlON = true; */
@@ -734,7 +733,7 @@ err_nomem:
static void device_free_tx_bufs(struct vnt_private *pDevice)
{
- PUSB_SEND_CONTEXT pTxContext;
+ struct vnt_usb_send_context *pTxContext;
int ii;
for (ii = 0; ii < pDevice->cbTD; ii++) {
@@ -752,8 +751,8 @@ static void device_free_tx_bufs(struct vnt_private *pDevice)
static void device_free_rx_bufs(struct vnt_private *pDevice)
{
- PRCB pRCB;
- int ii;
+ struct vnt_rcb *pRCB;
+ int ii;
for (ii = 0; ii < pDevice->cbRD; ii++) {
@@ -789,14 +788,13 @@ static void device_free_int_bufs(struct vnt_private *pDevice)
static bool device_alloc_bufs(struct vnt_private *pDevice)
{
-
- PUSB_SEND_CONTEXT pTxContext;
- PRCB pRCB;
- int ii;
+ struct vnt_usb_send_context *pTxContext;
+ struct vnt_rcb *pRCB;
+ int ii;
for (ii = 0; ii < pDevice->cbTD; ii++) {
- pTxContext = kmalloc(sizeof(USB_SEND_CONTEXT), GFP_KERNEL);
+ pTxContext = kmalloc(sizeof(struct vnt_usb_send_context), GFP_KERNEL);
if (pTxContext == NULL) {
DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : allocate tx usb context failed\n", pDevice->dev->name);
goto free_tx;
@@ -813,7 +811,8 @@ static bool device_alloc_bufs(struct vnt_private *pDevice)
}
/* allocate RCB mem */
- pDevice->pRCBMem = kzalloc((sizeof(RCB) * pDevice->cbRD), GFP_KERNEL);
+ pDevice->pRCBMem = kzalloc((sizeof(struct vnt_rcb) * pDevice->cbRD),
+ GFP_KERNEL);
if (pDevice->pRCBMem == NULL) {
DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : alloc rx usb context failed\n", pDevice->dev->name);
goto free_tx;
@@ -824,7 +823,8 @@ static bool device_alloc_bufs(struct vnt_private *pDevice)
pDevice->FirstRecvMngList = NULL;
pDevice->LastRecvMngList = NULL;
pDevice->NumRecvFreeList = 0;
- pRCB = (PRCB) pDevice->pRCBMem;
+
+ pRCB = (struct vnt_rcb *)pDevice->pRCBMem;
for (ii = 0; ii < pDevice->cbRD; ii++) {
@@ -925,7 +925,6 @@ int device_alloc_frag_buf(struct vnt_private *pDevice,
pDeF->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
if (pDeF->skb == NULL)
return false;
- ASSERT(pDeF->skb);
pDeF->skb->dev = pDevice->dev;
return true;
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index 9bf2f8d562c..fb743a8811b 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -52,7 +52,6 @@
#include "card.h"
#include "bssdb.h"
#include "mac.h"
-#include "baseband.h"
#include "michael.h"
#include "tkip.h"
#include "tcrc.h"
@@ -101,13 +100,12 @@ static void *s_vGetFreeContext(struct vnt_private *pDevice);
static void s_vGenerateTxParameter(struct vnt_private *pDevice,
u8 byPktType, u16 wCurrentRate, void *pTxBufHead, void *pvRrvTime,
- void *pvRTS, void *pvCTS, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx,
- struct ethhdr *psEthHeader);
+ void *rts_cts, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx,
+ struct ethhdr *psEthHeader, bool need_rts);
static u32 s_uFillDataHead(struct vnt_private *pDevice,
u8 byPktType, u16 wCurrentRate, void *pTxDataHead, u32 cbFrameLength,
- u32 uDMAIdx, int bNeedAck, u32 uFragIdx, u32 cbLastFragmentSize,
- u32 uMACfragNum, u8 byFBOption);
+ u32 uDMAIdx, int bNeedAck, u8 byFBOption);
static void s_vGenerateMACHeader(struct vnt_private *pDevice,
u8 *pbyBufferAddr, u16 wDuration, struct ethhdr *psEthHeader,
@@ -115,7 +113,7 @@ static void s_vGenerateMACHeader(struct vnt_private *pDevice,
static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf,
u8 *pbyIVHead, PSKeyItem pTransmitKey, u8 *pbyHdrBuf, u16 wPayloadLen,
- u8 *pMICHDR);
+ struct vnt_mic_hdr *mic_hdr);
static void s_vSWencryption(struct vnt_private *pDevice,
PSKeyItem pTransmitKey, u8 *pbyPayloadHead, u16 wPayloadSize);
@@ -123,30 +121,28 @@ static void s_vSWencryption(struct vnt_private *pDevice,
static unsigned int s_uGetTxRsvTime(struct vnt_private *pDevice, u8 byPktType,
u32 cbFrameLength, u16 wRate, int bNeedAck);
-static u32 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice, u8 byRTSRsvType,
+static u16 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice, u8 byRTSRsvType,
u8 byPktType, u32 cbFrameLength, u16 wCurrentRate);
static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
- u8 byPktType, void *pvCTS, u32 cbFrameLength, int bNeedAck,
- int bDisCRC, u16 wCurrentRate, u8 byFBOption);
+ u8 byPktType, union vnt_tx_data_head *head, u32 cbFrameLength,
+ int bNeedAck, u16 wCurrentRate, u8 byFBOption);
static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
- void *pvRTS, u32 cbFrameLength, int bNeedAck, int bDisCRC,
+ union vnt_tx_data_head *head, u32 cbFrameLength, int bNeedAck,
struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption);
-static u32 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
- u32 cbFrameLength, u8 byPktType, u16 wRate, int bNeedAck,
- u32 uFragIdx, u32 cbLastFragmentSize, u32 uMACfragNum,
- u8 byFBOption);
+static u16 s_uGetDataDuration(struct vnt_private *pDevice,
+ u8 byPktType, int bNeedAck);
-static unsigned int s_uGetRTSCTSDuration(struct vnt_private *pDevice,
+static u16 s_uGetRTSCTSDuration(struct vnt_private *pDevice,
u8 byDurType, u32 cbFrameLength, u8 byPktType, u16 wRate,
int bNeedAck, u8 byFBOption);
static void *s_vGetFreeContext(struct vnt_private *pDevice)
{
- PUSB_SEND_CONTEXT pContext = NULL;
- PUSB_SEND_CONTEXT pReturnContext = NULL;
+ struct vnt_usb_send_context *pContext = NULL;
+ struct vnt_usb_send_context *pReturnContext = NULL;
int ii;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GetFreeContext()\n");
@@ -155,6 +151,7 @@ static void *s_vGetFreeContext(struct vnt_private *pDevice)
pContext = pDevice->apTD[ii];
if (pContext->bBoolInUse == false) {
pContext->bBoolInUse = true;
+ memset(pContext->Data, 0, MAX_TOTAL_SIZE_WITH_ALL_HEADERS);
pReturnContext = pContext;
break;
}
@@ -186,109 +183,117 @@ static void s_vSaveTxPktInfo(struct vnt_private *pDevice, u8 byPktNum,
static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf,
u8 *pbyIVHead, PSKeyItem pTransmitKey, u8 *pbyHdrBuf,
- u16 wPayloadLen, u8 *pMICHDR)
+ u16 wPayloadLen, struct vnt_mic_hdr *mic_hdr)
{
u32 *pdwIV = (u32 *)pbyIVHead;
u32 *pdwExtIV = (u32 *)((u8 *)pbyIVHead + 4);
- u16 wValue;
struct ieee80211_hdr *pMACHeader = (struct ieee80211_hdr *)pbyHdrBuf;
u32 dwRevIVCounter;
- //Fill TXKEY
- if (pTransmitKey == NULL)
- return;
+ /* Fill TXKEY */
+ if (pTransmitKey == NULL)
+ return;
- dwRevIVCounter = cpu_to_le32(pDevice->dwIVCounter);
- *pdwIV = pDevice->dwIVCounter;
- pDevice->byKeyIndex = pTransmitKey->dwKeyIndex & 0xf;
+ dwRevIVCounter = cpu_to_le32(pDevice->dwIVCounter);
+ *pdwIV = pDevice->dwIVCounter;
+ pDevice->byKeyIndex = pTransmitKey->dwKeyIndex & 0xf;
- if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
- if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN ){
- memcpy(pDevice->abyPRNG, (u8 *)&(dwRevIVCounter), 3);
- memcpy(pDevice->abyPRNG+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
- } else {
- memcpy(pbyBuf, (u8 *)&(dwRevIVCounter), 3);
- memcpy(pbyBuf+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
- if(pTransmitKey->uKeyLength == WLAN_WEP40_KEYLEN) {
- memcpy(pbyBuf+8, (u8 *)&(dwRevIVCounter), 3);
- memcpy(pbyBuf+11, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
- }
- memcpy(pDevice->abyPRNG, pbyBuf, 16);
- }
- // Append IV after Mac Header
- *pdwIV &= WEP_IV_MASK;//00000000 11111111 11111111 11111111
- *pdwIV |= (u32)pDevice->byKeyIndex << 30;
- *pdwIV = cpu_to_le32(*pdwIV);
- pDevice->dwIVCounter++;
- if (pDevice->dwIVCounter > WEP_IV_MASK) {
- pDevice->dwIVCounter = 0;
- }
- } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
- pTransmitKey->wTSC15_0++;
- if (pTransmitKey->wTSC15_0 == 0) {
- pTransmitKey->dwTSC47_16++;
- }
- TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr,
- pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG);
- memcpy(pbyBuf, pDevice->abyPRNG, 16);
- // Make IV
- memcpy(pdwIV, pDevice->abyPRNG, 3);
-
- *(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
- // Append IV&ExtIV after Mac Header
- *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFillTxKey()---- pdwExtIV: %x\n",
- *pdwExtIV);
-
- } else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) {
- pTransmitKey->wTSC15_0++;
- if (pTransmitKey->wTSC15_0 == 0) {
- pTransmitKey->dwTSC47_16++;
- }
- memcpy(pbyBuf, pTransmitKey->abyKey, 16);
-
- // Make IV
- *pdwIV = 0;
- *(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
- *pdwIV |= cpu_to_le16((u16)(pTransmitKey->wTSC15_0));
- //Append IV&ExtIV after Mac Header
- *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
-
- //Fill MICHDR0
- *pMICHDR = 0x59;
- *((u8 *)(pMICHDR+1)) = 0; // TxPriority
- memcpy(pMICHDR+2, &(pMACHeader->addr2[0]), 6);
- *((u8 *)(pMICHDR+8)) = HIBYTE(HIWORD(pTransmitKey->dwTSC47_16));
- *((u8 *)(pMICHDR+9)) = LOBYTE(HIWORD(pTransmitKey->dwTSC47_16));
- *((u8 *)(pMICHDR+10)) = HIBYTE(LOWORD(pTransmitKey->dwTSC47_16));
- *((u8 *)(pMICHDR+11)) = LOBYTE(LOWORD(pTransmitKey->dwTSC47_16));
- *((u8 *)(pMICHDR+12)) = HIBYTE(pTransmitKey->wTSC15_0);
- *((u8 *)(pMICHDR+13)) = LOBYTE(pTransmitKey->wTSC15_0);
- *((u8 *)(pMICHDR+14)) = HIBYTE(wPayloadLen);
- *((u8 *)(pMICHDR+15)) = LOBYTE(wPayloadLen);
-
- //Fill MICHDR1
- *((u8 *)(pMICHDR+16)) = 0; // HLEN[15:8]
- if (pDevice->bLongHeader) {
- *((u8 *)(pMICHDR+17)) = 28; // HLEN[7:0]
- } else {
- *((u8 *)(pMICHDR+17)) = 22; // HLEN[7:0]
- }
- wValue = cpu_to_le16(pMACHeader->frame_control & 0xC78F);
- memcpy(pMICHDR+18, (u8 *)&wValue, 2); // MSKFRACTL
- memcpy(pMICHDR+20, &(pMACHeader->addr1[0]), 6);
- memcpy(pMICHDR+26, &(pMACHeader->addr2[0]), 6);
-
- //Fill MICHDR2
- memcpy(pMICHDR+32, &(pMACHeader->addr3[0]), 6);
- wValue = pMACHeader->seq_ctrl;
- wValue &= 0x000F;
- wValue = cpu_to_le16(wValue);
- memcpy(pMICHDR+38, (u8 *)&wValue, 2); // MSKSEQCTL
- if (pDevice->bLongHeader) {
- memcpy(pMICHDR+40, &(pMACHeader->addr4[0]), 6);
- }
- }
+ switch (pTransmitKey->byCipherSuite) {
+ case KEY_CTL_WEP:
+ if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN) {
+ memcpy(pDevice->abyPRNG, (u8 *)&dwRevIVCounter, 3);
+ memcpy(pDevice->abyPRNG + 3, pTransmitKey->abyKey,
+ pTransmitKey->uKeyLength);
+ } else {
+ memcpy(pbyBuf, (u8 *)&dwRevIVCounter, 3);
+ memcpy(pbyBuf + 3, pTransmitKey->abyKey,
+ pTransmitKey->uKeyLength);
+ if (pTransmitKey->uKeyLength == WLAN_WEP40_KEYLEN) {
+ memcpy(pbyBuf+8, (u8 *)&dwRevIVCounter, 3);
+ memcpy(pbyBuf+11, pTransmitKey->abyKey,
+ pTransmitKey->uKeyLength);
+ }
+
+ memcpy(pDevice->abyPRNG, pbyBuf, 16);
+ }
+ /* Append IV after Mac Header */
+ *pdwIV &= WEP_IV_MASK;
+ *pdwIV |= (u32)pDevice->byKeyIndex << 30;
+ *pdwIV = cpu_to_le32(*pdwIV);
+
+ pDevice->dwIVCounter++;
+ if (pDevice->dwIVCounter > WEP_IV_MASK)
+ pDevice->dwIVCounter = 0;
+
+ break;
+ case KEY_CTL_TKIP:
+ pTransmitKey->wTSC15_0++;
+ if (pTransmitKey->wTSC15_0 == 0)
+ pTransmitKey->dwTSC47_16++;
+
+ TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr,
+ pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16,
+ pDevice->abyPRNG);
+ memcpy(pbyBuf, pDevice->abyPRNG, 16);
+
+ /* Make IV */
+ memcpy(pdwIV, pDevice->abyPRNG, 3);
+
+ *(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) &
+ 0xc0) | 0x20);
+ /* Append IV&ExtIV after Mac Header */
+ *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "vFillTxKey()---- pdwExtIV: %x\n", *pdwExtIV);
+
+ break;
+ case KEY_CTL_CCMP:
+ pTransmitKey->wTSC15_0++;
+ if (pTransmitKey->wTSC15_0 == 0)
+ pTransmitKey->dwTSC47_16++;
+
+ memcpy(pbyBuf, pTransmitKey->abyKey, 16);
+
+ /* Make IV */
+ *pdwIV = 0;
+ *(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) &
+ 0xc0) | 0x20);
+
+ *pdwIV |= cpu_to_le16((u16)(pTransmitKey->wTSC15_0));
+
+ /* Append IV&ExtIV after Mac Header */
+ *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
+
+ if (!mic_hdr)
+ return;
+
+ /* MICHDR0 */
+ mic_hdr->id = 0x59;
+ mic_hdr->payload_len = cpu_to_be16(wPayloadLen);
+ memcpy(mic_hdr->mic_addr2, pMACHeader->addr2, ETH_ALEN);
+
+ mic_hdr->tsc_47_16 = cpu_to_be32(pTransmitKey->dwTSC47_16);
+ mic_hdr->tsc_15_0 = cpu_to_be16(pTransmitKey->wTSC15_0);
+
+ /* MICHDR1 */
+ if (pDevice->bLongHeader)
+ mic_hdr->hlen = cpu_to_be16(28);
+ else
+ mic_hdr->hlen = cpu_to_be16(22);
+
+ memcpy(mic_hdr->addr1, pMACHeader->addr1, ETH_ALEN);
+ memcpy(mic_hdr->addr2, pMACHeader->addr2, ETH_ALEN);
+
+ /* MICHDR2 */
+ memcpy(mic_hdr->addr3, pMACHeader->addr3, ETH_ALEN);
+ mic_hdr->frame_control = cpu_to_le16(pMACHeader->frame_control
+ & 0xc78f);
+ mic_hdr->seq_ctrl = cpu_to_le16(pMACHeader->seq_ctrl & 0xf);
+
+ if (pDevice->bLongHeader)
+ memcpy(mic_hdr->addr4, pMACHeader->addr4, ETH_ALEN);
+ }
}
static void s_vSWencryption(struct vnt_private *pDevice,
@@ -326,6 +331,12 @@ static void s_vSWencryption(struct vnt_private *pDevice,
}
}
+static u16 vnt_time_stamp_off(struct vnt_private *priv, u16 rate)
+{
+ return cpu_to_le16(wTimeStampOff[priv->byPreambleType % 2]
+ [rate % MAX_RATE]);
+}
+
/*byPktType : PK_TYPE_11A 0
PK_TYPE_11B 1
PK_TYPE_11GB 2
@@ -351,8 +362,15 @@ static u32 s_uGetTxRsvTime(struct vnt_private *pDevice, u8 byPktType,
}
}
+static u16 vnt_rxtx_rsvtime_le16(struct vnt_private *priv, u8 pkt_type,
+ u32 frame_length, u16 rate, int need_ack)
+{
+ return cpu_to_le16((u16)s_uGetTxRsvTime(priv, pkt_type,
+ frame_length, rate, need_ack));
+}
+
//byFreqType: 0=>5GHZ 1=>2.4GHZ
-static u32 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice,
+static u16 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice,
u8 byRTSRsvType, u8 byPktType, u32 cbFrameLength, u16 wCurrentRate)
{
u32 uRrvTime, uRTSTime, uCTSTime, uAckTime, uDataTime;
@@ -382,168 +400,30 @@ static u32 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice,
//RTSRrvTime
uRrvTime = uRTSTime + uCTSTime + uAckTime + uDataTime + 3*pDevice->uSIFS;
- return uRrvTime;
+ return cpu_to_le16((u16)uRrvTime);
}
//byFreqType 0: 5GHz, 1:2.4Ghz
-static u32 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
- u32 cbFrameLength, u8 byPktType, u16 wRate, int bNeedAck,
- u32 uFragIdx, u32 cbLastFragmentSize, u32 uMACfragNum,
- u8 byFBOption)
+static u16 s_uGetDataDuration(struct vnt_private *pDevice,
+ u8 byPktType, int bNeedAck)
{
- int bLastFrag = 0;
- u32 uAckTime = 0, uNextPktTime = 0;
-
- if (uFragIdx == (uMACfragNum-1)) {
- bLastFrag = 1;
- }
-
- switch (byDurType) {
-
- case DATADUR_B: //DATADUR_B
- if (((uMACfragNum == 1)) || (bLastFrag == 1)) {//Non Frag or Last Frag
- if (bNeedAck) {
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- return (pDevice->uSIFS + uAckTime);
- } else {
- return 0;
- }
- }
- else {//First Frag or Mid Frag
- if (uFragIdx == (uMACfragNum-2)) {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
- }
- if (bNeedAck) {
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- return (pDevice->uSIFS + uAckTime + uNextPktTime);
- } else {
- return (pDevice->uSIFS + uNextPktTime);
- }
- }
- break;
-
- case DATADUR_A: //DATADUR_A
- if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime);
- } else {
- return 0;
- }
- }
- else {//First Frag or Mid Frag
- if(uFragIdx == (uMACfragNum-2)){
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
- }
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime + uNextPktTime);
- } else {
- return (pDevice->uSIFS + uNextPktTime);
- }
- }
- break;
-
- case DATADUR_A_F0: //DATADUR_A_F0
- if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime);
- } else {
- return 0;
- }
- }
- else { //First Frag or Mid Frag
- if (byFBOption == AUTO_FB_0) {
- if (wRate < RATE_18M)
- wRate = RATE_18M;
- else if (wRate > RATE_54M)
- wRate = RATE_54M;
-
- if(uFragIdx == (uMACfragNum-2)){
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
- }
- } else { // (byFBOption == AUTO_FB_1)
- if (wRate < RATE_18M)
- wRate = RATE_18M;
- else if (wRate > RATE_54M)
- wRate = RATE_54M;
-
- if(uFragIdx == (uMACfragNum-2)){
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
- }
- }
-
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime + uNextPktTime);
- } else {
- return (pDevice->uSIFS + uNextPktTime);
- }
- }
- break;
-
- case DATADUR_A_F1: //DATADUR_A_F1
- if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime);
- } else {
- return 0;
- }
- }
- else { //First Frag or Mid Frag
- if (byFBOption == AUTO_FB_0) {
- if (wRate < RATE_18M)
- wRate = RATE_18M;
- else if (wRate > RATE_54M)
- wRate = RATE_54M;
-
- if(uFragIdx == (uMACfragNum-2)){
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
- }
-
- } else { // (byFBOption == AUTO_FB_1)
- if (wRate < RATE_18M)
- wRate = RATE_18M;
- else if (wRate > RATE_54M)
- wRate = RATE_54M;
-
- if(uFragIdx == (uMACfragNum-2)){
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
- }
- }
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime + uNextPktTime);
- } else {
- return (pDevice->uSIFS + uNextPktTime);
- }
- }
- break;
-
- default:
- break;
- }
+ u32 uAckTime = 0;
+
+ if (bNeedAck) {
+ if (byPktType == PK_TYPE_11B)
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType,
+ byPktType, 14, pDevice->byTopCCKBasicRate);
+ else
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType,
+ byPktType, 14, pDevice->byTopOFDMBasicRate);
+ return cpu_to_le16((u16)(pDevice->uSIFS + uAckTime));
+ }
- ASSERT(false);
return 0;
}
//byFreqType: 0=>5GHZ 1=>2.4GHZ
-static u32 s_uGetRTSCTSDuration(struct vnt_private *pDevice, u8 byDurType,
+static u16 s_uGetRTSCTSDuration(struct vnt_private *pDevice, u8 byDurType,
u32 cbFrameLength, u8 byPktType, u16 wRate, int bNeedAck,
u8 byFBOption)
{
@@ -626,14 +506,12 @@ static u32 s_uGetRTSCTSDuration(struct vnt_private *pDevice, u8 byDurType,
break;
}
- return uDurTime;
-
+ return cpu_to_le16((u16)uDurTime);
}
static u32 s_uFillDataHead(struct vnt_private *pDevice,
u8 byPktType, u16 wCurrentRate, void *pTxDataHead, u32 cbFrameLength,
- u32 uDMAIdx, int bNeedAck, u32 uFragIdx, u32 cbLastFragmentSize,
- u32 uMACfragNum, u8 byFBOption)
+ u32 uDMAIdx, int bNeedAck, u8 byFBOption)
{
if (pTxDataHead == NULL) {
@@ -641,409 +519,301 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
}
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- if ((uDMAIdx == TYPE_ATIMDMA) || (uDMAIdx == TYPE_BEACONDMA)) {
- PSTxDataHead_ab pBuf = (PSTxDataHead_ab) pTxDataHead;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
- );
- //Get Duration and TimeStampOff
- pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx,
- cbLastFragmentSize, uMACfragNum,
- byFBOption); //1: 2.4GHz
- if(uDMAIdx!=TYPE_ATIMDMA) {
- pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
- }
- return (pBuf->wDuration);
- }
- else { // DATA & MANAGE Frame
if (byFBOption == AUTO_FB_NONE) {
- PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead;
+ struct vnt_tx_datahead_g *pBuf =
+ (struct vnt_tx_datahead_g *)pTxDataHead;
//Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (u16 *)&(pBuf->wTransmitLength_a), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
- );
- BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (u16 *)&(pBuf->wTransmitLength_b), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
- );
+ BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
+ byPktType, &pBuf->a);
+ BBvCalculateParameter(pDevice, cbFrameLength,
+ pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
//Get Duration and TimeStamp
- pBuf->wDuration_a = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength,
- byPktType, wCurrentRate, bNeedAck, uFragIdx,
- cbLastFragmentSize, uMACfragNum,
- byFBOption); //1: 2.4GHz
- pBuf->wDuration_b = (u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength,
- PK_TYPE_11B, pDevice->byTopCCKBasicRate,
- bNeedAck, uFragIdx, cbLastFragmentSize,
- uMACfragNum, byFBOption); //1: 2.4GHz
-
- pBuf->wTimeStampOff_a = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
- pBuf->wTimeStampOff_b = wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE];
+ pBuf->wDuration_a = s_uGetDataDuration(pDevice,
+ byPktType, bNeedAck);
+ pBuf->wDuration_b = s_uGetDataDuration(pDevice,
+ PK_TYPE_11B, bNeedAck);
+
+ pBuf->wTimeStampOff_a = vnt_time_stamp_off(pDevice,
+ wCurrentRate);
+ pBuf->wTimeStampOff_b = vnt_time_stamp_off(pDevice,
+ pDevice->byTopCCKBasicRate);
return (pBuf->wDuration_a);
} else {
// Auto Fallback
- PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead;
+ struct vnt_tx_datahead_g_fb *pBuf =
+ (struct vnt_tx_datahead_g_fb *)pTxDataHead;
//Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (u16 *)&(pBuf->wTransmitLength_a), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
- );
- BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (u16 *)&(pBuf->wTransmitLength_b), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
- );
+ BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
+ byPktType, &pBuf->a);
+ BBvCalculateParameter(pDevice, cbFrameLength,
+ pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
//Get Duration and TimeStamp
- pBuf->wDuration_a = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
- pBuf->wDuration_b = (u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, PK_TYPE_11B,
- pDevice->byTopCCKBasicRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
- pBuf->wDuration_a_f0 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
- pBuf->wDuration_a_f1 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
- pBuf->wTimeStampOff_a = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
- pBuf->wTimeStampOff_b = wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE];
+ pBuf->wDuration_a = s_uGetDataDuration(pDevice,
+ byPktType, bNeedAck);
+ pBuf->wDuration_b = s_uGetDataDuration(pDevice,
+ PK_TYPE_11B, bNeedAck);
+ pBuf->wDuration_a_f0 = s_uGetDataDuration(pDevice,
+ byPktType, bNeedAck);
+ pBuf->wDuration_a_f1 = s_uGetDataDuration(pDevice,
+ byPktType, bNeedAck);
+ pBuf->wTimeStampOff_a = vnt_time_stamp_off(pDevice,
+ wCurrentRate);
+ pBuf->wTimeStampOff_b = vnt_time_stamp_off(pDevice,
+ pDevice->byTopCCKBasicRate);
return (pBuf->wDuration_a);
} //if (byFBOption == AUTO_FB_NONE)
- }
}
else if (byPktType == PK_TYPE_11A) {
- if ((byFBOption != AUTO_FB_NONE) && (uDMAIdx != TYPE_ATIMDMA) && (uDMAIdx != TYPE_BEACONDMA)) {
- // Auto Fallback
- PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead;
+ if (byFBOption != AUTO_FB_NONE) {
+ struct vnt_tx_datahead_a_fb *pBuf =
+ (struct vnt_tx_datahead_a_fb *)pTxDataHead;
//Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
- );
+ BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
+ byPktType, &pBuf->a);
//Get Duration and TimeStampOff
- pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //0: 5GHz
- pBuf->wDuration_f0 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //0: 5GHz
- pBuf->wDuration_f1 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //0: 5GHz
- if(uDMAIdx!=TYPE_ATIMDMA) {
- pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
- }
+ pBuf->wDuration = s_uGetDataDuration(pDevice,
+ byPktType, bNeedAck);
+ pBuf->wDuration_f0 = s_uGetDataDuration(pDevice,
+ byPktType, bNeedAck);
+ pBuf->wDuration_f1 = s_uGetDataDuration(pDevice,
+ byPktType, bNeedAck);
+ pBuf->wTimeStampOff = vnt_time_stamp_off(pDevice,
+ wCurrentRate);
return (pBuf->wDuration);
} else {
- PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
+ struct vnt_tx_datahead_ab *pBuf =
+ (struct vnt_tx_datahead_ab *)pTxDataHead;
//Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
- );
+ BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
+ byPktType, &pBuf->ab);
//Get Duration and TimeStampOff
- pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx,
- cbLastFragmentSize, uMACfragNum,
- byFBOption);
-
- if(uDMAIdx!=TYPE_ATIMDMA) {
- pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
- }
+ pBuf->wDuration = s_uGetDataDuration(pDevice,
+ byPktType, bNeedAck);
+ pBuf->wTimeStampOff = vnt_time_stamp_off(pDevice,
+ wCurrentRate);
return (pBuf->wDuration);
}
}
else if (byPktType == PK_TYPE_11B) {
- PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
+ struct vnt_tx_datahead_ab *pBuf =
+ (struct vnt_tx_datahead_ab *)pTxDataHead;
//Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
- );
+ BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
+ byPktType, &pBuf->ab);
//Get Duration and TimeStampOff
- pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx,
- cbLastFragmentSize, uMACfragNum,
- byFBOption);
- if (uDMAIdx != TYPE_ATIMDMA) {
- pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
- }
+ pBuf->wDuration = s_uGetDataDuration(pDevice,
+ byPktType, bNeedAck);
+ pBuf->wTimeStampOff = vnt_time_stamp_off(pDevice,
+ wCurrentRate);
return (pBuf->wDuration);
}
return 0;
}
-static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
- void *pvRTS, u32 cbFrameLength, int bNeedAck, int bDisCRC,
- struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption)
+static int vnt_fill_ieee80211_rts(struct vnt_private *priv,
+ struct ieee80211_rts *rts, struct ethhdr *eth_hdr,
+ u16 duration)
{
- u32 uRTSFrameLen = 20;
- u16 wLen = 0;
+ rts->duration = duration;
+ rts->frame_control = TYPE_CTL_RTS;
- if (pvRTS == NULL)
- return;
+ if (priv->eOPMode == OP_MODE_ADHOC || priv->eOPMode == OP_MODE_AP)
+ memcpy(rts->ra, eth_hdr->h_dest, ETH_ALEN);
+ else
+ memcpy(rts->ra, priv->abyBSSID, ETH_ALEN);
- if (bDisCRC) {
- // When CRCDIS bit is on, H/W forgot to generate FCS for RTS frame,
- // in this case we need to decrease its length by 4.
- uRTSFrameLen -= 4;
- }
+ if (priv->eOPMode == OP_MODE_AP)
+ memcpy(rts->ta, priv->abyBSSID, ETH_ALEN);
+ else
+ memcpy(rts->ta, eth_hdr->h_source, ETH_ALEN);
- // Note: So far RTSHead doesn't appear in ATIM & Beacom DMA, so we don't need to take them into account.
- // Otherwise, we need to modified codes for them.
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- if (byFBOption == AUTO_FB_NONE) {
- PSRTS_g pBuf = (PSRTS_g)pvRTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
- );
- pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
- );
- pBuf->wTransmitLength_a = cpu_to_le16(wLen);
- //Get Duration
- pBuf->wDuration_bb = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
- pBuf->wDuration_aa = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3: 2.4G OFDMData
- pBuf->wDuration_ba = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
-
- pBuf->Data.wDurationID = pBuf->wDuration_aa;
- //Get RTS Frame body
- pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
+ return 0;
+}
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- memcpy(&(pBuf->Data.abyRA[0]),
- &(psEthHeader->h_dest[0]),
- ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyRA[0]),
- &(pDevice->abyBSSID[0]),
- ETH_ALEN);
- }
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pBuf->Data.abyTA[0]),
- &(pDevice->abyBSSID[0]),
- ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyTA[0]),
- &(psEthHeader->h_source[0]),
- ETH_ALEN);
- }
- }
- else {
- PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
- );
- pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
- );
- pBuf->wTransmitLength_a = cpu_to_le16(wLen);
- //Get Duration
- pBuf->wDuration_bb = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
- pBuf->wDuration_aa = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3:2.4G OFDMData
- pBuf->wDuration_ba = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDMData
- pBuf->wRTSDuration_ba_f0 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //4:wRTSDuration_ba_f0, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_aa_f0 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:wRTSDuration_aa_f0, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_ba_f1 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //6:wRTSDuration_ba_f1, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_aa_f1 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:wRTSDuration_aa_f1, 1:2.4G, 1:CCKData
- pBuf->Data.wDurationID = pBuf->wDuration_aa;
- //Get RTS Frame body
- pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
+static int vnt_rxtx_rts_g_head(struct vnt_private *priv,
+ struct vnt_rts_g *buf, struct ethhdr *eth_hdr,
+ u8 pkt_type, u32 frame_len, int need_ack,
+ u16 current_rate, u8 fb_option)
+{
+ u16 rts_frame_len = 20;
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- memcpy(&(pBuf->Data.abyRA[0]),
- &(psEthHeader->h_dest[0]),
- ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyRA[0]),
- &(pDevice->abyBSSID[0]),
- ETH_ALEN);
- }
+ BBvCalculateParameter(priv, rts_frame_len, priv->byTopCCKBasicRate,
+ PK_TYPE_11B, &buf->b);
+ BBvCalculateParameter(priv, rts_frame_len,
+ priv->byTopOFDMBasicRate, pkt_type, &buf->a);
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pBuf->Data.abyTA[0]),
- &(pDevice->abyBSSID[0]),
- ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyTA[0]),
- &(psEthHeader->h_source[0]),
- ETH_ALEN);
- }
+ buf->wDuration_bb = s_uGetRTSCTSDuration(priv, RTSDUR_BB, frame_len,
+ PK_TYPE_11B, priv->byTopCCKBasicRate, need_ack, fb_option);
+ buf->wDuration_aa = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+ pkt_type, current_rate, need_ack, fb_option);
+ buf->wDuration_ba = s_uGetRTSCTSDuration(priv, RTSDUR_BA, frame_len,
+ pkt_type, current_rate, need_ack, fb_option);
- } // if (byFBOption == AUTO_FB_NONE)
- }
- else if (byPktType == PK_TYPE_11A) {
- if (byFBOption == AUTO_FB_NONE) {
- PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
- );
- pBuf->wTransmitLength = cpu_to_le16(wLen);
- //Get Duration
- pBuf->wDuration = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
- pBuf->Data.wDurationID = pBuf->wDuration;
- //Get RTS Frame body
- pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
+ vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration_aa);
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- memcpy(&(pBuf->Data.abyRA[0]),
- &(psEthHeader->h_dest[0]),
- ETH_ALEN);
- } else {
- memcpy(&(pBuf->Data.abyRA[0]),
- &(pDevice->abyBSSID[0]),
- ETH_ALEN);
- }
+ return 0;
+}
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pBuf->Data.abyTA[0]),
- &(pDevice->abyBSSID[0]),
- ETH_ALEN);
- } else {
- memcpy(&(pBuf->Data.abyTA[0]),
- &(psEthHeader->h_source[0]),
- ETH_ALEN);
- }
+static int vnt_rxtx_rts_g_fb_head(struct vnt_private *priv,
+ struct vnt_rts_g_fb *buf, struct ethhdr *eth_hdr,
+ u8 pkt_type, u32 frame_len, int need_ack,
+ u16 current_rate, u8 fb_option)
+{
+ u16 rts_frame_len = 20;
- }
- else {
- PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
- );
- pBuf->wTransmitLength = cpu_to_le16(wLen);
- //Get Duration
- pBuf->wDuration = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
- pBuf->wRTSDuration_f0 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:RTSDuration_aa_f0, 0:5G, 0: 5G OFDMData
- pBuf->wRTSDuration_f1 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:RTSDuration_aa_f1, 0:5G, 0:
- pBuf->Data.wDurationID = pBuf->wDuration;
- //Get RTS Frame body
- pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
+ BBvCalculateParameter(priv, rts_frame_len, priv->byTopCCKBasicRate,
+ PK_TYPE_11B, &buf->b);
+ BBvCalculateParameter(priv, rts_frame_len,
+ priv->byTopOFDMBasicRate, pkt_type, &buf->a);
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- memcpy(&(pBuf->Data.abyRA[0]),
- &(psEthHeader->h_dest[0]),
- ETH_ALEN);
- } else {
- memcpy(&(pBuf->Data.abyRA[0]),
- &(pDevice->abyBSSID[0]),
- ETH_ALEN);
- }
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pBuf->Data.abyTA[0]),
- &(pDevice->abyBSSID[0]),
- ETH_ALEN);
- } else {
- memcpy(&(pBuf->Data.abyTA[0]),
- &(psEthHeader->h_source[0]),
- ETH_ALEN);
- }
- }
- }
- else if (byPktType == PK_TYPE_11B) {
- PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
- );
- pBuf->wTransmitLength = cpu_to_le16(wLen);
- //Get Duration
- pBuf->wDuration = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
- pBuf->Data.wDurationID = pBuf->wDuration;
- //Get RTS Frame body
- pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- memcpy(&(pBuf->Data.abyRA[0]),
- &(psEthHeader->h_dest[0]),
- ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyRA[0]),
- &(pDevice->abyBSSID[0]),
- ETH_ALEN);
- }
+ buf->wDuration_bb = s_uGetRTSCTSDuration(priv, RTSDUR_BB, frame_len,
+ PK_TYPE_11B, priv->byTopCCKBasicRate, need_ack, fb_option);
+ buf->wDuration_aa = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+ pkt_type, current_rate, need_ack, fb_option);
+ buf->wDuration_ba = s_uGetRTSCTSDuration(priv, RTSDUR_BA, frame_len,
+ pkt_type, current_rate, need_ack, fb_option);
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pBuf->Data.abyTA[0]),
- &(pDevice->abyBSSID[0]),
- ETH_ALEN);
- } else {
- memcpy(&(pBuf->Data.abyTA[0]),
- &(psEthHeader->h_source[0]),
- ETH_ALEN);
- }
- }
+
+ buf->wRTSDuration_ba_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_BA_F0,
+ frame_len, pkt_type, current_rate, need_ack, fb_option);
+ buf->wRTSDuration_aa_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F0,
+ frame_len, pkt_type, current_rate, need_ack, fb_option);
+ buf->wRTSDuration_ba_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_BA_F1,
+ frame_len, pkt_type, current_rate, need_ack, fb_option);
+ buf->wRTSDuration_aa_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F1,
+ frame_len, pkt_type, current_rate, need_ack, fb_option);
+
+ vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration_aa);
+
+ return 0;
}
-static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
- u8 byPktType, void *pvCTS, u32 cbFrameLength, int bNeedAck,
- int bDisCRC, u16 wCurrentRate, u8 byFBOption)
+static int vnt_rxtx_rts_ab_head(struct vnt_private *priv,
+ struct vnt_rts_ab *buf, struct ethhdr *eth_hdr,
+ u8 pkt_type, u32 frame_len, int need_ack,
+ u16 current_rate, u8 fb_option)
{
- u32 uCTSFrameLen = 14;
- u16 wLen = 0;
+ u16 rts_frame_len = 20;
- if (pvCTS == NULL) {
- return;
- }
+ BBvCalculateParameter(priv, rts_frame_len,
+ priv->byTopOFDMBasicRate, pkt_type, &buf->ab);
- if (bDisCRC) {
- // When CRCDIS bit is on, H/W forgot to generate FCS for CTS frame,
- // in this case we need to decrease its length by 4.
- uCTSFrameLen -= 4;
- }
+ buf->wDuration = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+ pkt_type, current_rate, need_ack, fb_option);
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA) {
- // Auto Fall back
- PSCTS_FB pBuf = (PSCTS_FB)pvCTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
- );
- pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- pBuf->wDuration_ba = (u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
- pBuf->wDuration_ba += pDevice->wCTSDuration;
- pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
- //Get CTSDuration_ba_f0
- pBuf->wCTSDuration_ba_f0 = (u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //8:CTSDuration_ba_f0, 1:2.4G, 2,3:2.4G OFDM Data
- pBuf->wCTSDuration_ba_f0 += pDevice->wCTSDuration;
- pBuf->wCTSDuration_ba_f0 = cpu_to_le16(pBuf->wCTSDuration_ba_f0);
- //Get CTSDuration_ba_f1
- pBuf->wCTSDuration_ba_f1 = (u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //9:CTSDuration_ba_f1, 1:2.4G, 2,3:2.4G OFDM Data
- pBuf->wCTSDuration_ba_f1 += pDevice->wCTSDuration;
- pBuf->wCTSDuration_ba_f1 = cpu_to_le16(pBuf->wCTSDuration_ba_f1);
- //Get CTS Frame body
- pBuf->Data.wDurationID = pBuf->wDuration_ba;
- pBuf->Data.wFrameControl = TYPE_CTL_CTS;//0x00C4
- pBuf->Data.wReserved = 0x0000;
- memcpy(&(pBuf->Data.abyRA[0]),
- &(pDevice->abyCurrentNetAddr[0]),
- ETH_ALEN);
- } else { //if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA)
- PSCTS pBuf = (PSCTS)pvCTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
- );
- pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- //Get CTSDuration_ba
- pBuf->wDuration_ba = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
- pBuf->wDuration_ba += pDevice->wCTSDuration;
- pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
-
- //Get CTS Frame body
- pBuf->Data.wDurationID = pBuf->wDuration_ba;
- pBuf->Data.wFrameControl = TYPE_CTL_CTS;//0x00C4
- pBuf->Data.wReserved = 0x0000;
- memcpy(&(pBuf->Data.abyRA[0]),
- &(pDevice->abyCurrentNetAddr[0]),
- ETH_ALEN);
+ vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration);
+
+ return 0;
+}
+
+static int vnt_rxtx_rts_a_fb_head(struct vnt_private *priv,
+ struct vnt_rts_a_fb *buf, struct ethhdr *eth_hdr,
+ u8 pkt_type, u32 frame_len, int need_ack,
+ u16 current_rate, u8 fb_option)
+{
+ u16 rts_frame_len = 20;
+
+ BBvCalculateParameter(priv, rts_frame_len,
+ priv->byTopOFDMBasicRate, pkt_type, &buf->a);
+
+ buf->wDuration = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+ pkt_type, current_rate, need_ack, fb_option);
+
+ buf->wRTSDuration_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F0,
+ frame_len, pkt_type, current_rate, need_ack, fb_option);
+
+ buf->wRTSDuration_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F1,
+ frame_len, pkt_type, current_rate, need_ack, fb_option);
+
+ vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration);
+
+ return 0;
+}
+
+static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
+ union vnt_tx_data_head *head, u32 cbFrameLength, int bNeedAck,
+ struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption)
+{
+
+ if (!head)
+ return;
+
+ /* Note: So far RTSHead doesn't appear in ATIM
+ * & Beacom DMA, so we don't need to take them
+ * into account.
+ * Otherwise, we need to modified codes for them.
+ */
+ switch (byPktType) {
+ case PK_TYPE_11GB:
+ case PK_TYPE_11GA:
+ if (byFBOption == AUTO_FB_NONE)
+ vnt_rxtx_rts_g_head(pDevice, &head->rts_g,
+ psEthHeader, byPktType, cbFrameLength,
+ bNeedAck, wCurrentRate, byFBOption);
+ else
+ vnt_rxtx_rts_g_fb_head(pDevice, &head->rts_g_fb,
+ psEthHeader, byPktType, cbFrameLength,
+ bNeedAck, wCurrentRate, byFBOption);
+ break;
+ case PK_TYPE_11A:
+ if (byFBOption) {
+ vnt_rxtx_rts_a_fb_head(pDevice, &head->rts_a_fb,
+ psEthHeader, byPktType, cbFrameLength,
+ bNeedAck, wCurrentRate, byFBOption);
+ break;
+ }
+ case PK_TYPE_11B:
+ vnt_rxtx_rts_ab_head(pDevice, &head->rts_ab,
+ psEthHeader, byPktType, cbFrameLength,
+ bNeedAck, wCurrentRate, byFBOption);
+ }
+}
+
+static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
+ u8 byPktType, union vnt_tx_data_head *head, u32 cbFrameLength,
+ int bNeedAck, u16 wCurrentRate, u8 byFBOption)
+{
+ u32 uCTSFrameLen = 14;
+
+ if (!head)
+ return;
+
+ if (byFBOption != AUTO_FB_NONE) {
+ /* Auto Fall back */
+ struct vnt_cts_fb *pBuf = &head->cts_g_fb;
+ /* Get SignalField,ServiceField,Length */
+ BBvCalculateParameter(pDevice, uCTSFrameLen,
+ pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
+ pBuf->wDuration_ba = s_uGetRTSCTSDuration(pDevice, CTSDUR_BA,
+ cbFrameLength, byPktType,
+ wCurrentRate, bNeedAck, byFBOption);
+ /* Get CTSDuration_ba_f0 */
+ pBuf->wCTSDuration_ba_f0 = s_uGetRTSCTSDuration(pDevice,
+ CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate,
+ bNeedAck, byFBOption);
+ /* Get CTSDuration_ba_f1 */
+ pBuf->wCTSDuration_ba_f1 = s_uGetRTSCTSDuration(pDevice,
+ CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate,
+ bNeedAck, byFBOption);
+ /* Get CTS Frame body */
+ pBuf->data.duration = pBuf->wDuration_ba;
+ pBuf->data.frame_control = TYPE_CTL_CTS;
+ memcpy(pBuf->data.ra, pDevice->abyCurrentNetAddr, ETH_ALEN);
+ } else {
+ struct vnt_cts *pBuf = &head->cts_g;
+ /* Get SignalField,ServiceField,Length */
+ BBvCalculateParameter(pDevice, uCTSFrameLen,
+ pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
+ /* Get CTSDuration_ba */
+ pBuf->wDuration_ba = s_uGetRTSCTSDuration(pDevice,
+ CTSDUR_BA, cbFrameLength, byPktType,
+ wCurrentRate, bNeedAck, byFBOption);
+ /*Get CTS Frame body*/
+ pBuf->data.duration = pBuf->wDuration_ba;
+ pBuf->data.frame_control = TYPE_CTL_CTS;
+ memcpy(pBuf->data.ra, pDevice->abyCurrentNetAddr, ETH_ALEN);
}
- }
}
/*+
@@ -1071,12 +841,12 @@ static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
static void s_vGenerateTxParameter(struct vnt_private *pDevice,
u8 byPktType, u16 wCurrentRate, void *pTxBufHead, void *pvRrvTime,
- void *pvRTS, void *pvCTS, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx,
- struct ethhdr *psEthHeader)
+ void *rts_cts, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx,
+ struct ethhdr *psEthHeader, bool need_rts)
{
+ union vnt_tx_data_head *head = rts_cts;
u32 cbMACHdLen = WLAN_HDR_ADDR3_LEN; /* 24 */
u16 wFifoCtl;
- int bDisCRC = false;
u8 byFBOption = AUTO_FB_NONE;
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter...\n");
@@ -1084,10 +854,6 @@ static void s_vGenerateTxParameter(struct vnt_private *pDevice,
pFifoHead->wReserved = wCurrentRate;
wFifoCtl = pFifoHead->wFIFOCtl;
- if (wFifoCtl & FIFOCTL_CRCDIS) {
- bDisCRC = true;
- }
-
if (wFifoCtl & FIFOCTL_AUTO_FB_0) {
byFBOption = AUTO_FB_0;
}
@@ -1095,75 +861,87 @@ static void s_vGenerateTxParameter(struct vnt_private *pDevice,
byFBOption = AUTO_FB_1;
}
+ if (!pvRrvTime)
+ return;
+
if (pDevice->bLongHeader)
cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6;
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
-
- if (pvRTS != NULL) { //RTS_need
+ if (need_rts) {
//Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_gRTS pBuf = (PSRrvTime_gRTS)pvRrvTime;
- pBuf->wRTSTxRrvTime_aa = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 1:2.4GHz
- pBuf->wRTSTxRrvTime_ba = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 1, byPktType, cbFrameSize, wCurrentRate));//1:RTSTxRrvTime_ba, 1:2.4GHz
- pBuf->wRTSTxRrvTime_bb = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
- pBuf->wTxRrvTime_a = cpu_to_le16((u16) s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
- pBuf->wTxRrvTime_b = cpu_to_le16((u16) s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
- }
- //Fill RTS
- s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
+ struct vnt_rrv_time_rts *pBuf =
+ (struct vnt_rrv_time_rts *)pvRrvTime;
+ pBuf->wRTSTxRrvTime_aa = s_uGetRTSCTSRsvTime(pDevice, 2,
+ byPktType, cbFrameSize, wCurrentRate);
+ pBuf->wRTSTxRrvTime_ba = s_uGetRTSCTSRsvTime(pDevice, 1,
+ byPktType, cbFrameSize, wCurrentRate);
+ pBuf->wRTSTxRrvTime_bb = s_uGetRTSCTSRsvTime(pDevice, 0,
+ byPktType, cbFrameSize, wCurrentRate);
+ pBuf->wTxRrvTime_a = vnt_rxtx_rsvtime_le16(pDevice,
+ byPktType, cbFrameSize, wCurrentRate, bNeedACK);
+ pBuf->wTxRrvTime_b = vnt_rxtx_rsvtime_le16(pDevice,
+ PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate,
+ bNeedACK);
+ /* Fill RTS */
+ s_vFillRTSHead(pDevice, byPktType, head, cbFrameSize,
+ bNeedACK, psEthHeader, wCurrentRate, byFBOption);
}
else {//RTS_needless, PCF mode
-
//Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_gCTS pBuf = (PSRrvTime_gCTS)pvRrvTime;
- pBuf->wTxRrvTime_a = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
- pBuf->wTxRrvTime_b = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
- pBuf->wCTSTxRrvTime_ba = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 3, byPktType, cbFrameSize, wCurrentRate));//3:CTSTxRrvTime_Ba, 1:2.4GHz
- }
- //Fill CTS
- s_vFillCTSHead(pDevice, uDMAIdx, byPktType, pvCTS, cbFrameSize, bNeedACK, bDisCRC, wCurrentRate, byFBOption);
+ struct vnt_rrv_time_cts *pBuf =
+ (struct vnt_rrv_time_cts *)pvRrvTime;
+ pBuf->wTxRrvTime_a = vnt_rxtx_rsvtime_le16(pDevice, byPktType,
+ cbFrameSize, wCurrentRate, bNeedACK);
+ pBuf->wTxRrvTime_b = vnt_rxtx_rsvtime_le16(pDevice,
+ PK_TYPE_11B, cbFrameSize,
+ pDevice->byTopCCKBasicRate, bNeedACK);
+ pBuf->wCTSTxRrvTime_ba = s_uGetRTSCTSRsvTime(pDevice, 3,
+ byPktType, cbFrameSize, wCurrentRate);
+ /* Fill CTS */
+ s_vFillCTSHead(pDevice, uDMAIdx, byPktType, head,
+ cbFrameSize, bNeedACK, wCurrentRate, byFBOption);
}
}
else if (byPktType == PK_TYPE_11A) {
-
- if (pvRTS != NULL) {//RTS_need, non PCF mode
+ if (need_rts) {
//Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wRTSTxRrvTime = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 0:5GHz
- pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//0:OFDM
- }
- //Fill RTS
- s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
- }
- else if (pvRTS == NULL) {//RTS_needless, non PCF mode
+ struct vnt_rrv_time_ab *pBuf =
+ (struct vnt_rrv_time_ab *)pvRrvTime;
+ pBuf->wRTSTxRrvTime = s_uGetRTSCTSRsvTime(pDevice, 2,
+ byPktType, cbFrameSize, wCurrentRate);
+ pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, byPktType,
+ cbFrameSize, wCurrentRate, bNeedACK);
+ /* Fill RTS */
+ s_vFillRTSHead(pDevice, byPktType, head, cbFrameSize,
+ bNeedACK, psEthHeader, wCurrentRate, byFBOption);
+ } else {
//Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK)); //0:OFDM
- }
+ struct vnt_rrv_time_ab *pBuf =
+ (struct vnt_rrv_time_ab *)pvRrvTime;
+ pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11A,
+ cbFrameSize, wCurrentRate, bNeedACK);
}
}
else if (byPktType == PK_TYPE_11B) {
-
- if ((pvRTS != NULL)) {//RTS_need, non PCF mode
+ if (need_rts) {
//Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wRTSTxRrvTime = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
- pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK));//1:CCK
- }
- //Fill RTS
- s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
+ struct vnt_rrv_time_ab *pBuf =
+ (struct vnt_rrv_time_ab *)pvRrvTime;
+ pBuf->wRTSTxRrvTime = s_uGetRTSCTSRsvTime(pDevice, 0,
+ byPktType, cbFrameSize, wCurrentRate);
+ pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11B,
+ cbFrameSize, wCurrentRate, bNeedACK);
+ /* Fill RTS */
+ s_vFillRTSHead(pDevice, byPktType, head, cbFrameSize,
+ bNeedACK, psEthHeader, wCurrentRate, byFBOption);
}
else { //RTS_needless, non PCF mode
//Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK)); //1:CCK
- }
+ struct vnt_rrv_time_ab *pBuf =
+ (struct vnt_rrv_time_ab *)pvRrvTime;
+ pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11B,
+ cbFrameSize, wCurrentRate, bNeedACK);
}
}
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter END.\n");
@@ -1175,17 +953,18 @@ static void s_vGenerateTxParameter(struct vnt_private *pDevice,
*/
static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
- u8 *usbPacketBuf, int bNeedEncryption, u32 uSkbPacketLen, u32 uDMAIdx,
- struct ethhdr *psEthHeader, u8 *pPacket, PSKeyItem pTransmitKey,
- u32 uNodeIndex, u16 wCurrentRate, u32 *pcbHeaderLen, u32 *pcbTotalLen)
+ struct vnt_tx_buffer *pTxBufHead, int bNeedEncryption,
+ u32 uSkbPacketLen, u32 uDMAIdx, struct ethhdr *psEthHeader,
+ u8 *pPacket, PSKeyItem pTransmitKey, u32 uNodeIndex, u16 wCurrentRate,
+ u32 *pcbHeaderLen, u32 *pcbTotalLen)
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
u32 cbFrameSize, cbFrameBodySize;
- PTX_BUFFER pTxBufHead;
u32 cb802_1_H_len;
u32 cbIVlen = 0, cbICVlen = 0, cbMIClen = 0, cbMACHdLen = 0;
u32 cbFCSlen = 4, cbMICHDR = 0;
- int bNeedACK, bRTS;
+ int bNeedACK;
+ bool bRTS = false;
u8 *pbyType, *pbyMacHdr, *pbyIVHead, *pbyPayloadHead, *pbyTxBufferAddr;
u8 abySNAP_RFC1042[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
u8 abySNAP_Bridgetunnel[ETH_ALEN]
@@ -1193,26 +972,22 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
u32 uDuration;
u32 cbHeaderLength = 0, uPadding = 0;
void *pvRrvTime;
- PSMICHDRHead pMICHDR;
- void *pvRTS;
- void *pvCTS;
+ struct vnt_mic_hdr *pMICHDR;
+ void *rts_cts = NULL;
void *pvTxDataHd;
u8 byFBOption = AUTO_FB_NONE, byFragType;
u16 wTxBufSize;
- u32 dwMICKey0, dwMICKey1, dwMIC_Priority, dwCRC;
+ u32 dwMICKey0, dwMICKey1, dwMIC_Priority;
u32 *pdwMIC_L, *pdwMIC_R;
int bSoftWEP = false;
- pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL;
+ pvRrvTime = pMICHDR = pvTxDataHd = NULL;
if (bNeedEncryption && pTransmitKey->pvKeyTable) {
if (((PSKeyTable)pTransmitKey->pvKeyTable)->bSoftWEP == true)
bSoftWEP = true; /* WEP 256 */
}
- pTxBufHead = (PTX_BUFFER) usbPacketBuf;
- memset(pTxBufHead, 0, sizeof(TX_BUFFER));
-
// Get pkt type
if (ntohs(psEthHeader->h_proto) > ETH_DATA_LEN) {
if (pDevice->dwDiagRefCount == 0) {
@@ -1257,10 +1032,6 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
if (pDevice->bLongHeader)
pTxBufHead->wFIFOCtl |= FIFOCTL_LHEAD;
- if (pDevice->bSoftwareGenCrcErr) {
- pTxBufHead->wFIFOCtl |= FIFOCTL_CRCDIS; // set tx descriptors to NO hardware CRC
- }
-
//Set FRAGCTL_MACHDCNT
if (pDevice->bLongHeader) {
cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6;
@@ -1313,7 +1084,7 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) {
cbIVlen = 8;//RSN Header
cbICVlen = 8;//MIC
- cbMICHDR = sizeof(SMICHDRHead);
+ cbMICHDR = sizeof(struct vnt_mic_hdr);
}
if (bSoftWEP == false) {
//MAC Header should be padding 0 to DW alignment.
@@ -1336,76 +1107,116 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
if (byFBOption == AUTO_FB_NONE) {
if (bRTS == true) {//RTS_need
- pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS));
- pvRTS = (PSRTS_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR);
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g));
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g) + sizeof(STxDataHead_g);
+ pvRrvTime = (struct vnt_rrv_time_rts *)
+ (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_rts));
+ rts_cts = (struct vnt_rts_g *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_rts) + cbMICHDR);
+ pvTxDataHd = (struct vnt_tx_datahead_g *) (pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_rts) +
+ cbMICHDR + sizeof(struct vnt_rts_g));
+ cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_rts) +
+ cbMICHDR + sizeof(struct vnt_rts_g) +
+ sizeof(struct vnt_tx_datahead_g);
}
else { //RTS_needless
- pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
- pvRTS = NULL;
- pvCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
- pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS));
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS) + sizeof(STxDataHead_g);
+ pvRrvTime = (struct vnt_rrv_time_cts *)
+ (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_cts));
+ rts_cts = (struct vnt_cts *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_cts) + cbMICHDR);
+ pvTxDataHd = (struct vnt_tx_datahead_g *)(pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
+ cbMICHDR + sizeof(struct vnt_cts));
+ cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
+ cbMICHDR + sizeof(struct vnt_cts) +
+ sizeof(struct vnt_tx_datahead_g);
}
} else {
// Auto Fall Back
if (bRTS == true) {//RTS_need
- pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS));
- pvRTS = (PSRTS_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR);
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g_FB));
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g_FB) + sizeof(STxDataHead_g_FB);
+ pvRrvTime = (struct vnt_rrv_time_rts *)(pbyTxBufferAddr +
+ wTxBufSize);
+ pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_rts));
+ rts_cts = (struct vnt_rts_g_fb *)(pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_rts) + cbMICHDR);
+ pvTxDataHd = (struct vnt_tx_datahead_g_fb *) (pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_rts) +
+ cbMICHDR + sizeof(struct vnt_rts_g_fb));
+ cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_rts) +
+ cbMICHDR + sizeof(struct vnt_rts_g_fb) +
+ sizeof(struct vnt_tx_datahead_g_fb);
}
else if (bRTS == false) { //RTS_needless
- pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
- pvRTS = NULL;
- pvCTS = (PSCTS_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
- pvTxDataHd = (PSTxDataHead_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS_FB));
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS_FB) + sizeof(STxDataHead_g_FB);
+ pvRrvTime = (struct vnt_rrv_time_cts *)
+ (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_cts));
+ rts_cts = (struct vnt_cts_fb *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_cts) + cbMICHDR);
+ pvTxDataHd = (struct vnt_tx_datahead_g_fb *) (pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
+ cbMICHDR + sizeof(struct vnt_cts_fb));
+ cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
+ cbMICHDR + sizeof(struct vnt_cts_fb) +
+ sizeof(struct vnt_tx_datahead_g_fb);
}
} // Auto Fall Back
}
else {//802.11a/b packet
if (byFBOption == AUTO_FB_NONE) {
if (bRTS == true) {//RTS_need
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- pvRTS = (PSRTS_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(SRTS_ab));
- cbHeaderLength = wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_ab) + sizeof(STxDataHead_ab);
+ pvRrvTime = (struct vnt_rrv_time_ab *) (pbyTxBufferAddr +
+ wTxBufSize);
+ pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_ab));
+ rts_cts = (struct vnt_rts_ab *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
+ pvTxDataHd = (struct vnt_tx_datahead_ab *)(pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR +
+ sizeof(struct vnt_rts_ab));
+ cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) +
+ cbMICHDR + sizeof(struct vnt_rts_ab) +
+ sizeof(struct vnt_tx_datahead_ab);
}
else if (bRTS == false) { //RTS_needless, no MICHDR
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- pvRTS = NULL;
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_ab);
+ pvRrvTime = (struct vnt_rrv_time_ab *)(pbyTxBufferAddr +
+ wTxBufSize);
+ pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_ab));
+ pvTxDataHd = (struct vnt_tx_datahead_ab *)(pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
+ cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) +
+ cbMICHDR + sizeof(struct vnt_tx_datahead_ab);
}
} else {
// Auto Fall Back
if (bRTS == true) {//RTS_need
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- pvRTS = (PSRTS_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(SRTS_a_FB));
- cbHeaderLength = wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_a_FB) + sizeof(STxDataHead_a_FB);
+ pvRrvTime = (struct vnt_rrv_time_ab *)(pbyTxBufferAddr +
+ wTxBufSize);
+ pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_ab));
+ rts_cts = (struct vnt_rts_a_fb *)(pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
+ pvTxDataHd = (struct vnt_tx_datahead_a_fb *)(pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR +
+ sizeof(struct vnt_rts_a_fb));
+ cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) +
+ cbMICHDR + sizeof(struct vnt_rts_a_fb) +
+ sizeof(struct vnt_tx_datahead_a_fb);
}
else if (bRTS == false) { //RTS_needless
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- pvRTS = NULL;
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_a_FB);
+ pvRrvTime = (struct vnt_rrv_time_ab *)(pbyTxBufferAddr +
+ wTxBufSize);
+ pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_ab));
+ pvTxDataHd = (struct vnt_tx_datahead_a_fb *)(pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
+ cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) +
+ cbMICHDR + sizeof(struct vnt_tx_datahead_a_fb);
}
} // Auto Fall Back
}
@@ -1424,11 +1235,11 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
//Fill FIFO,RrvTime,RTS,and CTS
s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate,
- (void *)pbyTxBufferAddr, pvRrvTime, pvRTS, pvCTS,
- cbFrameSize, bNeedACK, uDMAIdx, psEthHeader);
+ (void *)pbyTxBufferAddr, pvRrvTime, rts_cts,
+ cbFrameSize, bNeedACK, uDMAIdx, psEthHeader, bRTS);
//Fill DataHead
uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, uDMAIdx, bNeedACK,
- 0, 0, 1/*uMACfragNum*/, byFBOption);
+ byFBOption);
// Generate TX MAC Header
s_vGenerateMACHeader(pDevice, pbyMacHdr, (u16)uDuration, psEthHeader, bNeedEncryption,
byFragType, uDMAIdx, 0);
@@ -1436,7 +1247,7 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
if (bNeedEncryption == true) {
//Fill TXKEY
s_vFillTxKey(pDevice, (u8 *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (u16)cbFrameBodySize, (u8 *)pMICHDR);
+ pbyMacHdr, (u16)cbFrameBodySize, pMICHDR);
if (pDevice->bEnableHostWEP) {
pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -1475,8 +1286,6 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
memcpy((pbyPayloadHead + cb802_1_H_len), ((u8 *)psEthHeader) + ETH_HLEN, uSkbPacketLen - ETH_HLEN);
}
- ASSERT(uLength == cbNdisBodySize);
-
if ((bNeedEncryption == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
///////////////////////////////////////////////////////////////////
@@ -1537,22 +1346,7 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
cbFrameSize -= cbICVlen;
}
- if (pDevice->bSoftwareGenCrcErr == true) {
- unsigned int cbLen;
- u32 * pdwCRC;
-
- dwCRC = 0xFFFFFFFFL;
- cbLen = cbFrameSize - cbFCSlen;
- // calculate CRC, and wrtie CRC value to end of TD
- dwCRC = CRCdwGetCrc32Ex(pbyMacHdr, cbLen, dwCRC);
- pdwCRC = (u32 *)(pbyMacHdr + cbLen);
- // finally, we must invert dwCRC to get the correct answer
- *pdwCRC = ~dwCRC;
- // Force Error
- *pdwCRC -= 1;
- } else {
cbFrameSize -= cbFCSlen;
- }
*pcbHeaderLen = cbHeaderLength;
*pcbTotalLen = cbHeaderLength + cbFrameSize ;
@@ -1589,13 +1383,7 @@ static void s_vGenerateMACHeader(struct vnt_private *pDevice,
{
struct ieee80211_hdr *pMACHeader = (struct ieee80211_hdr *)pbyBufferAddr;
- memset(pMACHeader, 0, (sizeof(struct ieee80211_hdr)));
-
- if (uDMAIdx == TYPE_ATIMDMA) {
- pMACHeader->frame_control = TYPE_802_11_ATIM;
- } else {
- pMACHeader->frame_control = TYPE_802_11_DATA;
- }
+ pMACHeader->frame_control = TYPE_802_11_DATA;
if (pDevice->eOPMode == OP_MODE_AP) {
memcpy(&(pMACHeader->addr1[0]),
@@ -1678,14 +1466,14 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
struct vnt_tx_mgmt *pPacket)
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
- PTX_BUFFER pTX_Buffer;
+ struct vnt_tx_buffer *pTX_Buffer;
PSTxBufHead pTxBufHead;
- PUSB_SEND_CONTEXT pContext;
+ struct vnt_usb_send_context *pContext;
struct ieee80211_hdr *pMACHeader;
- PSCTS pCTS;
struct ethhdr sEthHeader;
u8 byPktType, *pbyTxBufferAddr;
- void *pvRTS, *pvTxDataHd, *pvRrvTime, *pMICHDR;
+ void *rts_cts = NULL;
+ void *pvTxDataHd, *pvRrvTime, *pMICHDR;
u32 uDuration, cbReqCount, cbHeaderSize, cbFrameBodySize, cbFrameSize;
int bNeedACK, bIsPSPOLL = false;
u32 cbIVlen = 0, cbICVlen = 0, cbMIClen = 0, cbFCSlen = 4;
@@ -1694,19 +1482,18 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
u32 cbMacHdLen;
u16 wCurrentRate = RATE_1M;
- pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
+ pContext = (struct vnt_usb_send_context *)s_vGetFreeContext(pDevice);
if (NULL == pContext) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ManagementSend TX...NO CONTEXT!\n");
return CMD_STATUS_RESOURCES;
}
- pTX_Buffer = (PTX_BUFFER) (&pContext->Data[0]);
+ pTX_Buffer = (struct vnt_tx_buffer *)&pContext->Data[0];
pbyTxBufferAddr = (u8 *)&(pTX_Buffer->adwTxKey[0]);
cbFrameBodySize = pPacket->cbPayloadLen;
pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
wTxBufSize = sizeof(STxBufHead);
- memset(pTxBufHead, 0, wTxBufSize);
if (pDevice->byBBType == BB_TYPE_11A) {
wCurrentRate = RATE_6M;
@@ -1819,25 +1606,24 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
//Set RrvTime/RTS/CTS Buffer
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
- pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
+ pvRrvTime = (struct vnt_rrv_time_cts *) (pbyTxBufferAddr + wTxBufSize);
pMICHDR = NULL;
- pvRTS = NULL;
- pCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
- pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + sizeof(SCTS));
- cbHeaderSize = wTxBufSize + sizeof(SRrvTime_gCTS) + sizeof(SCTS) + sizeof(STxDataHead_g);
+ rts_cts = (struct vnt_cts *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_cts));
+ pvTxDataHd = (struct vnt_tx_datahead_g *)(pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_cts) + sizeof(struct vnt_cts));
+ cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
+ sizeof(struct vnt_cts) + sizeof(struct vnt_tx_datahead_g);
}
else { // 802.11a/b packet
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
+ pvRrvTime = (struct vnt_rrv_time_ab *) (pbyTxBufferAddr + wTxBufSize);
pMICHDR = NULL;
- pvRTS = NULL;
- pCTS = NULL;
- pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- cbHeaderSize = wTxBufSize + sizeof(SRrvTime_ab) + sizeof(STxDataHead_ab);
+ pvTxDataHd = (struct vnt_tx_datahead_ab *) (pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_ab));
+ cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_ab) +
+ sizeof(struct vnt_tx_datahead_ab);
}
- memset((void *)(pbyTxBufferAddr + wTxBufSize), 0,
- (cbHeaderSize - wTxBufSize));
-
memcpy(&(sEthHeader.h_dest[0]),
&(pPacket->p80211Header->sA3.abyAddr1[0]),
ETH_ALEN);
@@ -1849,13 +1635,14 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
//=========================
pTxBufHead->wFragCtl |= (u16)FRAGCTL_NONFRAG;
- //Fill FIFO,RrvTime,RTS,and CTS
- s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, pbyTxBufferAddr, pvRrvTime, pvRTS, pCTS,
- cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader);
+ /* Fill FIFO,RrvTime,RTS,and CTS */
+ s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate,
+ pbyTxBufferAddr, pvRrvTime, rts_cts,
+ cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, false);
//Fill DataHead
uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK,
- 0, 0, 1, AUTO_FB_NONE);
+ AUTO_FB_NONE);
pMACHeader = (struct ieee80211_hdr *) (pbyTxBufferAddr + cbHeaderSize);
@@ -1918,12 +1705,15 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
// This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is
// in the same place of other packet's Duration-field).
// And it will cause Cisco-AP to issue Disassociation-packet
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- ((PSTxDataHead_g)pvTxDataHd)->wDuration_a = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
- ((PSTxDataHead_g)pvTxDataHd)->wDuration_b = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
- } else {
- ((PSTxDataHead_ab)pvTxDataHd)->wDuration = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
- }
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
+ ((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_a =
+ cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
+ ((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_b =
+ cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
+ } else {
+ ((struct vnt_tx_datahead_ab *)pvTxDataHd)->wDuration =
+ cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
+ }
}
pTX_Buffer->wTxByteCount = cpu_to_le16((u16)(cbReqCount));
@@ -1948,60 +1738,60 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
struct vnt_tx_mgmt *pPacket)
{
+ struct vnt_beacon_buffer *pTX_Buffer;
u32 cbFrameSize = pPacket->cbMPDULen + WLAN_FCS_LEN;
u32 cbHeaderSize = 0;
u16 wTxBufSize = sizeof(STxShortBufHead);
PSTxShortBufHead pTxBufHead;
struct ieee80211_hdr *pMACHeader;
- PSTxDataHead_ab pTxDataHead;
+ struct vnt_tx_datahead_ab *pTxDataHead;
u16 wCurrentRate;
u32 cbFrameBodySize;
u32 cbReqCount;
- PBEACON_BUFFER pTX_Buffer;
u8 *pbyTxBufferAddr;
- PUSB_SEND_CONTEXT pContext;
+ struct vnt_usb_send_context *pContext;
CMD_STATUS status;
- pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
+ pContext = (struct vnt_usb_send_context *)s_vGetFreeContext(pDevice);
if (NULL == pContext) {
status = CMD_STATUS_RESOURCES;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ManagementSend TX...NO CONTEXT!\n");
return status ;
}
- pTX_Buffer = (PBEACON_BUFFER) (&pContext->Data[0]);
+
+ pTX_Buffer = (struct vnt_beacon_buffer *)&pContext->Data[0];
pbyTxBufferAddr = (u8 *)&(pTX_Buffer->wFIFOCtl);
cbFrameBodySize = pPacket->cbPayloadLen;
pTxBufHead = (PSTxShortBufHead) pbyTxBufferAddr;
wTxBufSize = sizeof(STxShortBufHead);
- memset(pTxBufHead, 0, wTxBufSize);
if (pDevice->byBBType == BB_TYPE_11A) {
wCurrentRate = RATE_6M;
- pTxDataHead = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize);
+ pTxDataHead = (struct vnt_tx_datahead_ab *)
+ (pbyTxBufferAddr + wTxBufSize);
//Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11A,
- (u16 *)&(pTxDataHead->wTransmitLength), (u8 *)&(pTxDataHead->byServiceField), (u8 *)&(pTxDataHead->bySignalField)
- );
+ BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11A,
+ &pTxDataHead->ab);
//Get Duration and TimeStampOff
- pTxDataHead->wDuration = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameSize, PK_TYPE_11A,
- wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
- pTxDataHead->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
- cbHeaderSize = wTxBufSize + sizeof(STxDataHead_ab);
+ pTxDataHead->wDuration = s_uGetDataDuration(pDevice,
+ PK_TYPE_11A, false);
+ pTxDataHead->wTimeStampOff = vnt_time_stamp_off(pDevice, wCurrentRate);
+ cbHeaderSize = wTxBufSize + sizeof(struct vnt_tx_datahead_ab);
} else {
wCurrentRate = RATE_1M;
pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
- pTxDataHead = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize);
+ pTxDataHead = (struct vnt_tx_datahead_ab *)
+ (pbyTxBufferAddr + wTxBufSize);
//Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11B,
- (u16 *)&(pTxDataHead->wTransmitLength), (u8 *)&(pTxDataHead->byServiceField), (u8 *)&(pTxDataHead->bySignalField)
- );
+ BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11B,
+ &pTxDataHead->ab);
//Get Duration and TimeStampOff
- pTxDataHead->wDuration = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameSize, PK_TYPE_11B,
- wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
- pTxDataHead->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
- cbHeaderSize = wTxBufSize + sizeof(STxDataHead_ab);
+ pTxDataHead->wDuration = s_uGetDataDuration(pDevice,
+ PK_TYPE_11B, false);
+ pTxDataHead->wTimeStampOff = vnt_time_stamp_off(pDevice, wCurrentRate);
+ cbHeaderSize = wTxBufSize + sizeof(struct vnt_tx_datahead_ab);
}
//Generate Beacon Header
@@ -2032,9 +1822,11 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
+ struct vnt_tx_buffer *pTX_Buffer;
u8 byPktType;
u8 *pbyTxBufferAddr;
- void *pvRTS, *pvCTS, *pvTxDataHd;
+ void *rts_cts = NULL;
+ void *pvTxDataHd;
u32 uDuration, cbReqCount;
struct ieee80211_hdr *pMACHeader;
u32 cbHeaderSize, cbFrameBodySize;
@@ -2059,10 +1851,9 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
PSKeyItem pTransmitKey = NULL;
u8 *pbyIVHead, *pbyPayloadHead, *pbyMacHdr;
u32 cbExtSuppRate = 0;
- PTX_BUFFER pTX_Buffer;
- PUSB_SEND_CONTEXT pContext;
+ struct vnt_usb_send_context *pContext;
- pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL;
+ pvRrvTime = pMICHDR = pvTxDataHd = NULL;
if(skb->len <= WLAN_HDR_ADDR3_LEN) {
cbFrameBodySize = 0;
@@ -2072,7 +1863,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
}
p80211Header = (PUWLAN_80211HDR)skb->data;
- pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
+ pContext = (struct vnt_usb_send_context *)s_vGetFreeContext(pDevice);
if (NULL == pContext) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"DMA0 TX...NO CONTEXT!\n");
@@ -2080,11 +1871,10 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
return ;
}
- pTX_Buffer = (PTX_BUFFER)(&pContext->Data[0]);
+ pTX_Buffer = (struct vnt_tx_buffer *)&pContext->Data[0];
pbyTxBufferAddr = (u8 *)(&pTX_Buffer->adwTxKey[0]);
pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
wTxBufSize = sizeof(STxBufHead);
- memset(pTxBufHead, 0, wTxBufSize);
if (pDevice->byBBType == BB_TYPE_11A) {
wCurrentRate = RATE_6M;
@@ -2204,7 +1994,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
cbIVlen = 8;//RSN Header
cbICVlen = 8;//MIC
- cbMICHDR = sizeof(SMICHDRHead);
+ cbMICHDR = sizeof(struct vnt_mic_hdr);
pTxBufHead->wFragCtl |= FRAGCTL_AES;
pDevice->bAES = true;
}
@@ -2222,26 +2012,28 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
//the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter()
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
-
- pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
- pvRTS = NULL;
- pvCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
- pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS));
- cbHeaderSize = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS) + sizeof(STxDataHead_g);
+ pvRrvTime = (struct vnt_rrv_time_cts *) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_cts));
+ rts_cts = (struct vnt_cts *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_cts) + cbMICHDR);
+ pvTxDataHd = (struct vnt_tx_datahead_g *) (pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_cts) + cbMICHDR +
+ sizeof(struct vnt_cts));
+ cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_cts) + cbMICHDR +
+ sizeof(struct vnt_cts) + sizeof(struct vnt_tx_datahead_g);
}
else {//802.11a/b packet
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- pvRTS = NULL;
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
- cbHeaderSize = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_ab);
+ pvRrvTime = (struct vnt_rrv_time_ab *) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+ sizeof(struct vnt_rrv_time_ab));
+ pvTxDataHd = (struct vnt_tx_datahead_ab *)(pbyTxBufferAddr +
+ wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
+ cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR +
+ sizeof(struct vnt_tx_datahead_ab);
}
- memset((void *)(pbyTxBufferAddr + wTxBufSize), 0,
- (cbHeaderSize - wTxBufSize));
memcpy(&(sEthHeader.h_dest[0]),
&(p80211Header->sA3.abyAddr1[0]),
ETH_ALEN);
@@ -2253,13 +2045,14 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
//=========================
pTxBufHead->wFragCtl |= (u16)FRAGCTL_NONFRAG;
- //Fill FIFO,RrvTime,RTS,and CTS
- s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, pbyTxBufferAddr, pvRrvTime, pvRTS, pvCTS,
- cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader);
+ /* Fill FIFO,RrvTime,RTS,and CTS */
+ s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate,
+ pbyTxBufferAddr, pvRrvTime, rts_cts,
+ cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, false);
//Fill DataHead
uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK,
- 0, 0, 1, AUTO_FB_NONE);
+ AUTO_FB_NONE);
pMACHeader = (struct ieee80211_hdr *) (pbyTxBufferAddr + cbHeaderSize);
@@ -2345,7 +2138,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
}
s_vFillTxKey(pDevice, (u8 *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (u16)cbFrameBodySize, (u8 *)pMICHDR);
+ pbyMacHdr, (u16)cbFrameBodySize, pMICHDR);
if (pDevice->bEnableHostWEP) {
pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -2368,12 +2161,15 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
// This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is
// in the same place of other packet's Duration-field).
// And it will cause Cisco-AP to issue Disassociation-packet
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- ((PSTxDataHead_g)pvTxDataHd)->wDuration_a = cpu_to_le16(p80211Header->sA2.wDurationID);
- ((PSTxDataHead_g)pvTxDataHd)->wDuration_b = cpu_to_le16(p80211Header->sA2.wDurationID);
- } else {
- ((PSTxDataHead_ab)pvTxDataHd)->wDuration = cpu_to_le16(p80211Header->sA2.wDurationID);
- }
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
+ ((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_a =
+ cpu_to_le16(p80211Header->sA2.wDurationID);
+ ((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_b =
+ cpu_to_le16(p80211Header->sA2.wDurationID);
+ } else {
+ ((struct vnt_tx_datahead_ab *)pvTxDataHd)->wDuration =
+ cpu_to_le16(p80211Header->sA2.wDurationID);
+ }
}
pTX_Buffer->wTxByteCount = cpu_to_le16((u16)(cbReqCount));
@@ -2415,6 +2211,7 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
{
struct net_device_stats *pStats = &pDevice->stats;
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
+ struct vnt_tx_buffer *pTX_Buffer;
u32 BytesToWrite = 0, uHeaderLen = 0;
u32 uNodeIndex = 0;
u8 byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
@@ -2428,9 +2225,8 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
int bNeedDeAuth = false;
u8 *pbyBSSID;
int bNodeExist = false;
- PUSB_SEND_CONTEXT pContext;
+ struct vnt_usb_send_context *pContext;
bool fConvertedPacket;
- PTX_BUFFER pTX_Buffer;
u32 status;
u16 wKeepRate = pDevice->wCurrentRate;
int bTxeapol_key = false;
@@ -2500,7 +2296,7 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
}
- pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
+ pContext = (struct vnt_usb_send_context *)s_vGetFreeContext(pDevice);
if (pContext == NULL) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG" pContext == NULL\n");
@@ -2738,8 +2534,10 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
}
+ pTX_Buffer = (struct vnt_tx_buffer *)&pContext->Data[0];
+
fConvertedPacket = s_bPacketToWirelessUsb(pDevice, byPktType,
- (u8 *)(&pContext->Data[0]), bNeedEncryption,
+ pTX_Buffer, bNeedEncryption,
skb->len, uDMAIdx, &pDevice->sTxEthHeader,
(u8 *)skb->data, pTransmitKey, uNodeIndex,
pDevice->wCurrentRate,
@@ -2761,7 +2559,6 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
}
- pTX_Buffer = (PTX_BUFFER)&(pContext->Data[0]);
pTX_Buffer->byPKTNO = (u8) (((pDevice->wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
pTX_Buffer->wTxByteCount = (u16)BytesToWrite;
@@ -2808,20 +2605,20 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen,
u32 uNodeIndex)
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
+ struct vnt_tx_buffer *pTX_Buffer;
u32 BytesToWrite = 0, uHeaderLen = 0;
u8 byPktType = PK_TYPE_11B;
int bNeedEncryption = false;
SKeyItem STempKey;
PSKeyItem pTransmitKey = NULL;
u8 *pbyBSSID;
- PUSB_SEND_CONTEXT pContext;
+ struct vnt_usb_send_context *pContext;
u8 byPktTyp;
int fConvertedPacket;
- PTX_BUFFER pTX_Buffer;
u32 status;
u16 wKeepRate = pDevice->wCurrentRate;
- pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
+ pContext = (struct vnt_usb_send_context *)s_vGetFreeContext(pDevice);
if (NULL == pContext) {
return false;
@@ -2898,8 +2695,10 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen,
// Convert the packet to an usb frame and copy into our buffer
// and send the irp.
+ pTX_Buffer = (struct vnt_tx_buffer *)&pContext->Data[0];
+
fConvertedPacket = s_bPacketToWirelessUsb(pDevice, byPktType,
- (u8 *)(&pContext->Data[0]), bNeedEncryption,
+ pTX_Buffer, bNeedEncryption,
uDataLen, TYPE_AC0DMA, &pDevice->sTxEthHeader,
pbySkbData, pTransmitKey, uNodeIndex,
pDevice->wCurrentRate,
@@ -2911,7 +2710,6 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen,
return false;
}
- pTX_Buffer = (PTX_BUFFER)&(pContext->Data[0]);
pTX_Buffer->byPKTNO = (u8) (((pDevice->wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
pTX_Buffer->wTxByteCount = (u16)BytesToWrite;
diff --git a/drivers/staging/vt6656/rxtx.h b/drivers/staging/vt6656/rxtx.h
index dd7e85dde1a..4bbee1c2fca 100644
--- a/drivers/staging/vt6656/rxtx.h
+++ b/drivers/staging/vt6656/rxtx.h
@@ -31,602 +31,173 @@
#include "device.h"
#include "wcmd.h"
-
-//
-// RTS buffer header
-//
-typedef struct tagSRTSDataF {
- u16 wFrameControl;
- u16 wDurationID;
- u8 abyRA[ETH_ALEN];
- u8 abyTA[ETH_ALEN];
-} SRTSDataF, *PSRTSDataF;
-
-//
-// CTS buffer header
-//
-typedef struct tagSCTSDataF {
- u16 wFrameControl;
- u16 wDurationID;
- u8 abyRA[ETH_ALEN];
- u16 wReserved;
-} SCTSDataF, *PSCTSDataF;
-
-//
-// MICHDR data header
-//
-typedef struct tagSMICHDR {
- u32 adwHDR0[4];
- u32 adwHDR1[4];
- u32 adwHDR2[4];
-} SMICHDR, *PSMICHDR;
-
-typedef struct tagSTX_NAF_G_RTS
-{
- //RsvTime
- u16 wRTSTxRrvTime_ba;
- u16 wRTSTxRrvTime_aa;
- u16 wRTSTxRrvTime_bb;
- u16 wReserved2;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
-
- //RTS
- u8 byRTSSignalField_b;
- u8 byRTSServiceField_b;
- u16 wRTSTransmitLength_b;
- u8 byRTSSignalField_a;
- u8 byRTSServiceField_a;
- u16 wRTSTransmitLength_a;
- u16 wRTSDuration_ba;
- u16 wRTSDuration_aa;
- u16 wRTSDuration_bb;
- u16 wReserved3;
- SRTSDataF sRTS;
-
- //Data
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
-
-} TX_NAF_G_RTS, *PTX_NAF_G_RTS;
-
-typedef struct tagSTX_NAF_G_RTS_MIC
-{
- //RsvTime
- u16 wRTSTxRrvTime_ba;
- u16 wRTSTxRrvTime_aa;
- u16 wRTSTxRrvTime_bb;
- u16 wReserved2;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
-
- SMICHDR sMICHDR;
-
- //RTS
- u8 byRTSSignalField_b;
- u8 byRTSServiceField_b;
- u16 wRTSTransmitLength_b;
- u8 byRTSSignalField_a;
- u8 byRTSServiceField_a;
- u16 wRTSTransmitLength_a;
- u16 wRTSDuration_ba;
- u16 wRTSDuration_aa;
- u16 wRTSDuration_bb;
- u16 wReserved3;
- SRTSDataF sRTS;
-
- //Data
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
-
-} TX_NAF_G_RTS_MIC, *PTX_NAF_G_RTS_MIC;
-
-typedef struct tagSTX_NAF_G_CTS
-{
- //RsvTime
- u16 wCTSTxRrvTime_ba;
- u16 wReserved2;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
-
- //CTS
- u8 byCTSSignalField_b;
- u8 byCTSServiceField_b;
- u16 wCTSTransmitLength_b;
- u16 wCTSDuration_ba;
- u16 wReserved3;
- SCTSDataF sCTS;
-
- //Data
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
-
-} TX_NAF_G_CTS, *PTX_NAF_G_CTS;
-
-typedef struct tagSTX_NAF_G_CTS_MIC
-{
- //RsvTime
- u16 wCTSTxRrvTime_ba;
- u16 wReserved2;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
-
- SMICHDR sMICHDR;
-
- //CTS
- u8 byCTSSignalField_b;
- u8 byCTSServiceField_b;
- u16 wCTSTransmitLength_b;
- u16 wCTSDuration_ba;
- u16 wReserved3;
- SCTSDataF sCTS;
-
- //Data
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
-
-} TX_NAF_G_CTS_MIC, *PTX_NAF_G_CTS_MIC;
-
-typedef struct tagSTX_NAF_G_BEACON
-{
- u16 wFIFOCtl;
- u16 wTimeStamp;
-
- //CTS
- u8 byCTSSignalField_b;
- u8 byCTSServiceField_b;
- u16 wCTSTransmitLength_b;
- u16 wCTSDuration_ba;
- u16 wReserved1;
- SCTSDataF sCTS;
-
- //Data
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_a;
- u16 wTimeStampOff_a;
-
-} TX_NAF_G_BEACON, *PTX_NAF_G_BEACON;
-
-typedef struct tagSTX_NAF_AB_RTS
-{
- //RsvTime
- u16 wRTSTxRrvTime_ab;
- u16 wTxRrvTime_ab;
-
- //RTS
- u8 byRTSSignalField_ab;
- u8 byRTSServiceField_ab;
- u16 wRTSTransmitLength_ab;
- u16 wRTSDuration_ab;
- u16 wReserved2;
- SRTSDataF sRTS;
-
- //Data
- u8 bySignalField_ab;
- u8 byServiceField_ab;
- u16 wTransmitLength_ab;
- u16 wDuration_ab;
- u16 wTimeStampOff_ab;
-
-} TX_NAF_AB_RTS, *PTX_NAF_AB_RTS;
-
-typedef struct tagSTX_NAF_AB_RTS_MIC
-{
- //RsvTime
- u16 wRTSTxRrvTime_ab;
- u16 wTxRrvTime_ab;
-
- SMICHDR sMICHDR;
-
- //RTS
- u8 byRTSSignalField_ab;
- u8 byRTSServiceField_ab;
- u16 wRTSTransmitLength_ab;
- u16 wRTSDuration_ab;
- u16 wReserved2;
- SRTSDataF sRTS;
-
- //Data
- u8 bySignalField_ab;
- u8 byServiceField_ab;
- u16 wTransmitLength_ab;
- u16 wDuration_ab;
- u16 wTimeStampOff_ab;
-
-} TX_NAF_AB_RTS_MIC, *PTX_NAF_AB_RTS_MIC;
-
-typedef struct tagSTX_NAF_AB_CTS
-{
- //RsvTime
- u16 wReserved2;
- u16 wTxRrvTime_ab;
-
- //Data
- u8 bySignalField_ab;
- u8 byServiceField_ab;
- u16 wTransmitLength_ab;
- u16 wDuration_ab;
- u16 wTimeStampOff_ab;
-
-} TX_NAF_AB_CTS, *PTX_NAF_AB_CTS;
-
-typedef struct tagSTX_NAF_AB_CTS_MIC
-{
- //RsvTime
- u16 wReserved2;
- u16 wTxRrvTime_ab;
-
- SMICHDR sMICHDR;
-
- //Data
- u8 bySignalField_ab;
- u8 byServiceField_ab;
- u16 wTransmitLength_ab;
- u16 wDuration_ab;
- u16 wTimeStampOff_ab;
-
-} TX_NAF_AB_CTS_MIC, *PTX_NAF_AB_CTS_MIC;
-
-typedef struct tagSTX_NAF_AB_BEACON
-{
- u16 wFIFOCtl;
- u16 wTimeStamp;
-
- //Data
- u8 bySignalField_ab;
- u8 byServiceField_ab;
- u16 wTransmitLength_ab;
- u16 wDuration_ab;
- u16 wTimeStampOff_ab;
-
-} TX_NAF_AB_BEACON, *PTX_NAF_AB_BEACON;
-
-typedef struct tagSTX_AF_G_RTS
-{
- //RsvTime
- u16 wRTSTxRrvTime_ba;
- u16 wRTSTxRrvTime_aa;
- u16 wRTSTxRrvTime_bb;
- u16 wReserved2;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
-
- //RTS
- u8 byRTSSignalField_b;
- u8 byRTSServiceField_b;
- u16 wRTSTransmitLength_b;
- u8 byRTSSignalField_a;
- u8 byRTSServiceField_a;
- u16 wRTSTransmitLength_a;
- u16 wRTSDuration_ba;
- u16 wRTSDuration_aa;
- u16 wRTSDuration_bb;
- u16 wReserved3;
- u16 wRTSDuration_ba_f0;
- u16 wRTSDuration_aa_f0;
- u16 wRTSDuration_ba_f1;
- u16 wRTSDuration_aa_f1;
- SRTSDataF sRTS;
-
- //Data
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wDuration_a_f0;
- u16 wDuration_a_f1;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
-
-} TX_AF_G_RTS, *PTX_AF_G_RTS;
-
-typedef struct tagSTX_AF_G_RTS_MIC
-{
- //RsvTime
- u16 wRTSTxRrvTime_ba;
- u16 wRTSTxRrvTime_aa;
- u16 wRTSTxRrvTime_bb;
- u16 wReserved2;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
-
- SMICHDR sMICHDR;
-
- //RTS
- u8 byRTSSignalField_b;
- u8 byRTSServiceField_b;
- u16 wRTSTransmitLength_b;
- u8 byRTSSignalField_a;
- u8 byRTSServiceField_a;
- u16 wRTSTransmitLength_a;
- u16 wRTSDuration_ba;
- u16 wRTSDuration_aa;
- u16 wRTSDuration_bb;
- u16 wReserved3;
- u16 wRTSDuration_ba_f0;
- u16 wRTSDuration_aa_f0;
- u16 wRTSDuration_ba_f1;
- u16 wRTSDuration_aa_f1;
- SRTSDataF sRTS;
-
- //Data
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wDuration_a_f0;
- u16 wDuration_a_f1;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
-
-} TX_AF_G_RTS_MIC, *PTX_AF_G_RTS_MIC;
-
-typedef struct tagSTX_AF_G_CTS
-{
- //RsvTime
- u16 wCTSTxRrvTime_ba;
- u16 wReserved2;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
-
- //CTS
- u8 byCTSSignalField_b;
- u8 byCTSServiceField_b;
- u16 wCTSTransmitLength_b;
- u16 wCTSDuration_ba;
- u16 wReserved3;
- u16 wCTSDuration_ba_f0;
- u16 wCTSDuration_ba_f1;
- SCTSDataF sCTS;
-
- //Data
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wDuration_a_f0;
- u16 wDuration_a_f1;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
-
-} TX_AF_G_CTS, *PTX_AF_G_CTS;
-
-typedef struct tagSTX_AF_G_CTS_MIC
-{
- //RsvTime
- u16 wCTSTxRrvTime_ba;
- u16 wReserved2;
- u16 wTxRrvTime_b;
- u16 wTxRrvTime_a;
-
- SMICHDR sMICHDR;
-
- //CTS
- u8 byCTSSignalField_b;
- u8 byCTSServiceField_b;
- u16 wCTSTransmitLength_b;
- u16 wCTSDuration_ba;
- u16 wReserved3;
- u16 wCTSDuration_ba_f0;
- u16 wCTSDuration_ba_f1;
- SCTSDataF sCTS;
-
- //Data
- u8 bySignalField_b;
- u8 byServiceField_b;
- u16 wTransmitLength_b;
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_b;
- u16 wDuration_a;
- u16 wDuration_a_f0;
- u16 wDuration_a_f1;
- u16 wTimeStampOff_b;
- u16 wTimeStampOff_a;
-
-} TX_AF_G_CTS_MIC, *PTX_AF_G_CTS_MIC;
-
-typedef struct tagSTX_AF_A_RTS
-{
- //RsvTime
- u16 wRTSTxRrvTime_a;
- u16 wTxRrvTime_a;
-
- //RTS
- u8 byRTSSignalField_a;
- u8 byRTSServiceField_a;
- u16 wRTSTransmitLength_a;
- u16 wRTSDuration_a;
- u16 wReserved2;
- u16 wRTSDuration_a_f0;
- u16 wRTSDuration_a_f1;
- SRTSDataF sRTS;
-
- //Data
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_a;
- u16 wTimeStampOff_a;
- u16 wDuration_a_f0;
- u16 wDuration_a_f1;
-
-} TX_AF_A_RTS, *PTX_AF_A_RTS;
-
-typedef struct tagSTX_AF_A_RTS_MIC
-{
- //RsvTime
- u16 wRTSTxRrvTime_a;
- u16 wTxRrvTime_a;
-
- SMICHDR sMICHDR;
-
- //RTS
- u8 byRTSSignalField_a;
- u8 byRTSServiceField_a;
- u16 wRTSTransmitLength_a;
- u16 wRTSDuration_a;
- u16 wReserved2;
- u16 wRTSDuration_a_f0;
- u16 wRTSDuration_a_f1;
- SRTSDataF sRTS;
-
- //Data
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_a;
- u16 wTimeStampOff_a;
- u16 wDuration_a_f0;
- u16 wDuration_a_f1;
-
-} TX_AF_A_RTS_MIC, *PTX_AF_A_RTS_MIC;
-
-typedef struct tagSTX_AF_A_CTS
-{
- //RsvTime
- u16 wReserved2;
- u16 wTxRrvTime_a;
-
- //Data
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_a;
- u16 wTimeStampOff_a;
- u16 wDuration_a_f0;
- u16 wDuration_a_f1;
-
-} TX_AF_A_CTS, *PTX_AF_A_CTS;
-
-typedef struct tagSTX_AF_A_CTS_MIC
-{
- //RsvTime
- u16 wReserved2;
- u16 wTxRrvTime_a;
-
- SMICHDR sMICHDR;
-
- //Data
- u8 bySignalField_a;
- u8 byServiceField_a;
- u16 wTransmitLength_a;
- u16 wDuration_a;
- u16 wTimeStampOff_a;
- u16 wDuration_a_f0;
- u16 wDuration_a_f1;
-
-} TX_AF_A_CTS_MIC, *PTX_AF_A_CTS_MIC;
-
-//
-// union with all of the TX Buffer Type
-//
-typedef union tagUTX_BUFFER_CONTAINER
-{
- TX_NAF_G_RTS RTS_G;
- TX_NAF_G_RTS_MIC RTS_G_MIC;
- TX_NAF_G_CTS CTS_G;
- TX_NAF_G_CTS_MIC CTS_G_MIC;
- //TX_NAF_G_BEACON Beacon_G;
- TX_NAF_AB_RTS RTS_AB;
- TX_NAF_AB_RTS_MIC RTS_AB_MIC;
- TX_NAF_AB_CTS CTS_AB;
- TX_NAF_AB_CTS_MIC CTS_AB_MIC;
- //TX_NAF_AB_BEACON Beacon_AB;
- TX_AF_G_RTS RTS_G_AutoFB;
- TX_AF_G_RTS_MIC RTS_G_AutoFB_MIC;
- TX_AF_G_CTS CTS_G_AutoFB;
- TX_AF_G_CTS_MIC CTS_G_AutoFB_MIC;
- TX_AF_A_RTS RTS_A_AutoFB;
- TX_AF_A_RTS_MIC RTS_A_AutoFB_MIC;
- TX_AF_A_CTS CTS_A_AutoFB;
- TX_AF_A_CTS_MIC CTS_A_AutoFB_MIC;
-
-} TX_BUFFER_CONTAINER, *PTX_BUFFER_CONTAINER;
-
-//
-// Remote NDIS message format
-//
-typedef struct tagSTX_BUFFER
-{
- u8 byType;
- u8 byPKTNO;
- u16 wTxByteCount;
-
+#include "baseband.h"
+
+/* MIC HDR data header */
+struct vnt_mic_hdr {
+ u8 id;
+ u8 tx_priority;
+ u8 mic_addr2[6];
+ __be32 tsc_47_16;
+ __be16 tsc_15_0;
+ __be16 payload_len;
+ __be16 hlen;
+ __le16 frame_control;
+ u8 addr1[6];
+ u8 addr2[6];
+ u8 addr3[6];
+ __le16 seq_ctrl;
+ u8 addr4[6];
+ u16 packing; /* packing to 48 bytes */
+} __packed;
+
+/* RsvTime buffer header */
+struct vnt_rrv_time_rts {
+ u16 wRTSTxRrvTime_ba;
+ u16 wRTSTxRrvTime_aa;
+ u16 wRTSTxRrvTime_bb;
+ u16 wReserved;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
+} __packed;
+
+struct vnt_rrv_time_cts {
+ u16 wCTSTxRrvTime_ba;
+ u16 wReserved;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
+} __packed;
+
+struct vnt_rrv_time_ab {
+ u16 wRTSTxRrvTime;
+ u16 wTxRrvTime;
+} __packed;
+
+/* TX data header */
+struct vnt_tx_datahead_g {
+ struct vnt_phy_field b;
+ struct vnt_phy_field a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
+} __packed;
+
+struct vnt_tx_datahead_g_fb {
+ struct vnt_phy_field b;
+ struct vnt_phy_field a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wDuration_a_f0;
+ u16 wDuration_a_f1;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
+} __packed;
+
+struct vnt_tx_datahead_ab {
+ struct vnt_phy_field ab;
+ u16 wDuration;
+ u16 wTimeStampOff;
+} __packed;
+
+struct vnt_tx_datahead_a_fb {
+ struct vnt_phy_field a;
+ u16 wDuration;
+ u16 wTimeStampOff;
+ u16 wDuration_f0;
+ u16 wDuration_f1;
+} __packed;
+
+/* RTS buffer header */
+struct vnt_rts_g {
+ struct vnt_phy_field b;
+ struct vnt_phy_field a;
+ u16 wDuration_ba;
+ u16 wDuration_aa;
+ u16 wDuration_bb;
+ u16 wReserved;
+ struct ieee80211_rts data;
+} __packed;
+
+struct vnt_rts_g_fb {
+ struct vnt_phy_field b;
+ struct vnt_phy_field a;
+ u16 wDuration_ba;
+ u16 wDuration_aa;
+ u16 wDuration_bb;
+ u16 wReserved;
+ u16 wRTSDuration_ba_f0;
+ u16 wRTSDuration_aa_f0;
+ u16 wRTSDuration_ba_f1;
+ u16 wRTSDuration_aa_f1;
+ struct ieee80211_rts data;
+} __packed;
+
+struct vnt_rts_ab {
+ struct vnt_phy_field ab;
+ u16 wDuration;
+ u16 wReserved;
+ struct ieee80211_rts data;
+} __packed;
+
+struct vnt_rts_a_fb {
+ struct vnt_phy_field a;
+ u16 wDuration;
+ u16 wReserved;
+ u16 wRTSDuration_f0;
+ u16 wRTSDuration_f1;
+ struct ieee80211_rts data;
+} __packed;
+
+/* CTS buffer header */
+struct vnt_cts {
+ struct vnt_phy_field b;
+ u16 wDuration_ba;
+ u16 wReserved;
+ struct ieee80211_cts data;
+ u16 reserved2;
+} __packed;
+
+struct vnt_cts_fb {
+ struct vnt_phy_field b;
+ u16 wDuration_ba;
+ u16 wReserved;
+ u16 wCTSDuration_ba_f0;
+ u16 wCTSDuration_ba_f1;
+ struct ieee80211_cts data;
+ u16 reserved2;
+} __packed;
+
+union vnt_tx_data_head {
+ /* rts g */
+ struct vnt_rts_g rts_g;
+ struct vnt_rts_g_fb rts_g_fb;
+ /* rts a/b */
+ struct vnt_rts_ab rts_ab;
+ struct vnt_rts_a_fb rts_a_fb;
+ /* cts g */
+ struct vnt_cts cts_g;
+ struct vnt_cts_fb cts_g_fb;
+};
+
+struct vnt_tx_buffer {
+ u8 byType;
+ u8 byPKTNO;
+ u16 wTxByteCount;
u32 adwTxKey[4];
- u16 wFIFOCtl;
- u16 wTimeStamp;
- u16 wFragCtl;
- u16 wReserved;
-
- // Actual message
- TX_BUFFER_CONTAINER BufferHeader;
-
-} TX_BUFFER, *PTX_BUFFER;
-
-//
-// Remote NDIS message format
-//
-typedef struct tagSBEACON_BUFFER
-{
- u8 byType;
- u8 byPKTNO;
- u16 wTxByteCount;
-
- u16 wFIFOCtl;
- u16 wTimeStamp;
-
- // Actual message
- TX_BUFFER_CONTAINER BufferHeader;
-
-} BEACON_BUFFER, *PBEACON_BUFFER;
+ u16 wFIFOCtl;
+ u16 wTimeStamp;
+ u16 wFragCtl;
+ u16 wReserved;
+} __packed;
+
+struct vnt_beacon_buffer {
+ u8 byType;
+ u8 byPKTNO;
+ u16 wTxByteCount;
+ u16 wFIFOCtl;
+ u16 wTimeStamp;
+} __packed;
void vDMA0_tx_80211(struct vnt_private *, struct sk_buff *skb);
int nsDMA_tx_packet(struct vnt_private *, u32 uDMAIdx, struct sk_buff *skb);
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index 098be609107..3a03f1d5b68 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -421,7 +421,7 @@ static void s_nsInterruptUsbIoCompleteRead(struct urb *urb)
*
*/
-int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, PRCB pRCB)
+int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, struct vnt_rcb *pRCB)
{
int ntStatus = 0;
struct urb *pUrb;
@@ -479,7 +479,7 @@ int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, PRCB pRCB)
static void s_nsBulkInUsbIoCompleteRead(struct urb *urb)
{
- PRCB pRCB = (PRCB)urb->context;
+ struct vnt_rcb *pRCB = (struct vnt_rcb *)urb->context;
struct vnt_private *pDevice = pRCB->pDevice;
unsigned long bytesRead;
int bIndicateReceive = false;
@@ -546,7 +546,8 @@ static void s_nsBulkInUsbIoCompleteRead(struct urb *urb)
*
*/
-int PIPEnsSendBulkOut(struct vnt_private *pDevice, PUSB_SEND_CONTEXT pContext)
+int PIPEnsSendBulkOut(struct vnt_private *pDevice,
+ struct vnt_usb_send_context *pContext)
{
int status;
struct urb *pUrb;
@@ -628,14 +629,13 @@ static void s_nsBulkOutIoCompleteWrite(struct urb *urb)
int status;
CONTEXT_TYPE ContextType;
unsigned long ulBufLen;
- PUSB_SEND_CONTEXT pContext;
+ struct vnt_usb_send_context *pContext;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkOutIoCompleteWrite\n");
//
// The context given to IoSetCompletionRoutine is an USB_CONTEXT struct
//
- pContext = (PUSB_SEND_CONTEXT) urb->context;
- ASSERT( NULL != pContext );
+ pContext = (struct vnt_usb_send_context *)urb->context;
pDevice = pContext->pDevice;
ContextType = pContext->Type;
diff --git a/drivers/staging/vt6656/usbpipe.h b/drivers/staging/vt6656/usbpipe.h
index bb7a61111a6..f53770329e7 100644
--- a/drivers/staging/vt6656/usbpipe.h
+++ b/drivers/staging/vt6656/usbpipe.h
@@ -40,7 +40,8 @@ int PIPEnsControlIn(struct vnt_private *, u8 byRequest, u16 wValue,
u16 wIndex, u16 wLength, u8 *pbyBuffer);
int PIPEnsInterruptRead(struct vnt_private *);
-int PIPEnsBulkInUsbRead(struct vnt_private *, PRCB pRCB);
-int PIPEnsSendBulkOut(struct vnt_private *, PUSB_SEND_CONTEXT pContext);
+int PIPEnsBulkInUsbRead(struct vnt_private *, struct vnt_rcb *pRCB);
+int PIPEnsSendBulkOut(struct vnt_private *,
+ struct vnt_usb_send_context *pContext);
#endif /* __USBPIPE_H__ */
diff --git a/drivers/staging/vt6656/wmgr.c b/drivers/staging/vt6656/wmgr.c
index 6d1ff5eeafa..b6cbd138a2b 100644
--- a/drivers/staging/vt6656/wmgr.c
+++ b/drivers/staging/vt6656/wmgr.c
@@ -751,7 +751,6 @@ static void s_vMgrRxAssocResponse(struct vnt_private *pDevice,
|| (sFrame.pwStatus == NULL)
|| (sFrame.pwAid == NULL)
|| (sFrame.pSuppRates == NULL)) {
- DBG_PORT80(0xCC);
return;
}
@@ -3750,7 +3749,6 @@ static void s_vMgrRxProbeResponse(struct vnt_private *pDevice,
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe resp:Fail addr:[%p]\n",
pRxPacket->p80211Header);
- DBG_PORT80(0xCC);
return;
}
diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c
index faa93f0ee10..fcc3d2165ba 100644
--- a/drivers/staging/winbond/mds.c
+++ b/drivers/staging/winbond/mds.c
@@ -15,7 +15,8 @@ Mds_initial(struct wbsoft_priv *adapter)
return hal_get_tx_buffer(&adapter->sHwData, &pMds->pTxBuffer);
}
-static void Mds_DurationSet(struct wbsoft_priv *adapter, struct wb35_descriptor *pDes, u8 *buffer)
+static void Mds_DurationSet(struct wbsoft_priv *adapter,
+ struct wb35_descriptor *pDes, u8 *buffer)
{
struct T00_descriptor *pT00;
struct T01_descriptor *pT01;
@@ -43,10 +44,11 @@ static void Mds_DurationSet(struct wbsoft_priv *adapter, struct wb35_descriptor
* Set RTS/CTS mechanism
******************************************/
if (!boGroupAddr) {
- /* NOTE : If the protection mode is enabled and the MSDU will be fragmented,
- * the tx rates of MPDUs will all be DSSS rates. So it will not use
- * CTS-to-self in this case. CTS-To-self will only be used when without
- * fragmentation. -- 20050112 */
+ /* NOTE : If the protection mode is enabled and the MSDU will
+ * be fragmented, the tx rates of MPDUs will all be DSSS
+ * rates. So it will not use CTS-to-self in this case.
+ * CTS-To-self will only be used when without
+ * fragmentation. -- 20050112 */
BodyLen = (u16)pT00->T00_frame_length; /* include 802.11 header */
BodyLen += 4; /* CRC */
@@ -90,8 +92,8 @@ static void Mds_DurationSet(struct wbsoft_priv *adapter, struct wb35_descriptor
* CTS Rate : 24 Mega bps
* CTS frame length = 14 bytes */
Duration += (DEFAULT_SIFSTIME +
- PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION +
- ((112 + 22 + 95)/96)*Tsym);
+ PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION +
+ ((112 + 22 + 95)/96)*Tsym);
} else {
/* CTS + 1 SIFS + CTS duration
* CTS Rate : ?? Mega bps
@@ -101,7 +103,8 @@ static void Mds_DurationSet(struct wbsoft_priv *adapter, struct wb35_descriptor
else
Duration += SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME;
- Duration += (((112 + Rate-1) / Rate) + DEFAULT_SIFSTIME);
+ Duration += (((112 + Rate-1) / Rate) +
+ DEFAULT_SIFSTIME);
}
}
@@ -127,9 +130,10 @@ static void Mds_DurationSet(struct wbsoft_priv *adapter, struct wb35_descriptor
* Rate : ??Mega bps
* ACK frame length = 14 bytes, tx rate = 24M */
Duration = PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION * 3;
- Duration += (((NextBodyLen*8 + 22 + Rate*4 - 1)/(Rate*4)) * Tsym +
- (((2*14)*8 + 22 + 95)/96)*Tsym +
- DEFAULT_SIFSTIME*3);
+ Duration += (((NextBodyLen*8 + 22 + Rate*4 - 1)
+ /(Rate*4)) * Tsym +
+ (((2*14)*8 + 22 + 95)/96)*Tsym +
+ DEFAULT_SIFSTIME*3);
} else {
/* DSSS
* data transmit time + 2 ACK + 3 SIFS
@@ -141,8 +145,9 @@ static void Mds_DurationSet(struct wbsoft_priv *adapter, struct wb35_descriptor
else
Duration = SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME*3;
- Duration += (((NextBodyLen + (2*14))*8 + Rate-1) / Rate +
- DEFAULT_SIFSTIME*3);
+ Duration += (((NextBodyLen + (2*14))*8
+ + Rate-1) / Rate +
+ DEFAULT_SIFSTIME*3);
}
((u16 *)buffer)[5] = cpu_to_le16(Duration); /* 4 USHOR for skip 8B USB, 2USHORT=FC + Duration */
@@ -168,7 +173,8 @@ static void Mds_DurationSet(struct wbsoft_priv *adapter, struct wb35_descriptor
* ACK frame length = 14 bytes */
Duration = PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION;
/* The Tx rate of ACK use 24M */
- Duration += (((112 + 22 + 95)/96)*Tsym + DEFAULT_SIFSTIME);
+ Duration += (((112 + 22 + 95)/96)*Tsym +
+ DEFAULT_SIFSTIME);
} else {
/* DSSS
* 1 ACK + 1 SIFS
@@ -191,7 +197,8 @@ static void Mds_DurationSet(struct wbsoft_priv *adapter, struct wb35_descriptor
}
/* The function return the 4n size of usb pk */
-static u16 Mds_BodyCopy(struct wbsoft_priv *adapter, struct wb35_descriptor *pDes, u8 *TargetBuffer)
+static u16 Mds_BodyCopy(struct wbsoft_priv *adapter,
+ struct wb35_descriptor *pDes, u8 *TargetBuffer)
{
struct T00_descriptor *pT00;
struct wb35_mds *pMds = &adapter->Mds;
@@ -246,7 +253,7 @@ static u16 Mds_BodyCopy(struct wbsoft_priv *adapter, struct wb35_descriptor *pDe
buf_index++;
buf_index %= MAX_DESCRIPTOR_BUFFER_INDEX;
} else {
- u8 *pctmp = pDes->buffer_address[buf_index];
+ u8 *pctmp = pDes->buffer_address[buf_index];
pctmp += CopySize;
pDes->buffer_address[buf_index] = pctmp;
pDes->buffer_size[buf_index] -= CopySize;
@@ -290,7 +297,8 @@ static u16 Mds_BodyCopy(struct wbsoft_priv *adapter, struct wb35_descriptor *pDe
return Size;
}
-static void Mds_HeaderCopy(struct wbsoft_priv *adapter, struct wb35_descriptor *pDes, u8 *TargetBuffer)
+static void Mds_HeaderCopy(struct wbsoft_priv *adapter,
+ struct wb35_descriptor *pDes, u8 *TargetBuffer)
{
struct wb35_mds *pMds = &adapter->Mds;
u8 *src_buffer = pDes->buffer_address[0]; /* 931130.5.g */
@@ -391,11 +399,12 @@ static void Mds_HeaderCopy(struct wbsoft_priv *adapter, struct wb35_descriptor *
pDes->PreambleMode = WLAN_PREAMBLE_TYPE_LONG;
else
pDes->PreambleMode = CURRENT_PREAMBLE_MODE;
- pT01->T01_plcp_header_length = pDes->PreambleMode; /* Set preamble */
+ pT01->T01_plcp_header_length = pDes->PreambleMode; /* Set preamble */
}
-static void MLME_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *desc)
+static void MLME_GetNextPacket(struct wbsoft_priv *adapter,
+ struct wb35_descriptor *desc)
{
desc->InternalUsed = desc->buffer_start_index + desc->buffer_number;
desc->InternalUsed %= MAX_DESCRIPTOR_BUFFER_INDEX;
@@ -423,7 +432,8 @@ static void MLMEfreeMMPDUBuffer(struct wbsoft_priv *adapter, s8 *pData)
}
}
-static void MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID, unsigned char SendOK)
+static void MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID,
+ unsigned char SendOK)
{
/* Reclaim the data buffer */
adapter->sMlmeFrame.len = 0;
@@ -440,9 +450,9 @@ Mds_Tx(struct wbsoft_priv *adapter)
struct wb35_mds *pMds = &adapter->Mds;
struct wb35_descriptor TxDes;
struct wb35_descriptor *pTxDes = &TxDes;
- u8 *XmitBufAddress;
- u16 XmitBufSize, PacketSize, stmp, CurrentSize, FragmentThreshold;
- u8 FillIndex, TxDesIndex, FragmentCount, FillCount;
+ u8 *XmitBufAddress;
+ u16 XmitBufSize, PacketSize, stmp, CurrentSize, FragmentThreshold;
+ u8 FillIndex, TxDesIndex, FragmentCount, FillCount;
unsigned char BufferFilled = false;
diff --git a/drivers/staging/winbond/mds_f.h b/drivers/staging/winbond/mds_f.h
index ce8be079e95..159b2eb366e 100644
--- a/drivers/staging/winbond/mds_f.h
+++ b/drivers/staging/winbond/mds_f.h
@@ -7,13 +7,16 @@
unsigned char Mds_initial(struct wbsoft_priv *adapter);
void Mds_Tx(struct wbsoft_priv *adapter);
void Mds_SendComplete(struct wbsoft_priv *adapter, struct T02_descriptor *pt02);
-void Mds_MpduProcess(struct wbsoft_priv *adapter, struct wb35_descriptor *prxdes);
-extern void DataDmp(u8 *pdata, u32 len, u32 offset);
+void Mds_MpduProcess(struct wbsoft_priv *adapter,
+ struct wb35_descriptor *prxdes);
/* For data frame sending */
u16 MDS_GetPacketSize(struct wbsoft_priv *adapter);
-void MDS_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *pdes);
-void MDS_GetNextPacketComplete(struct wbsoft_priv *adapter, struct wb35_descriptor *pdes);
-void MDS_SendResult(struct wbsoft_priv *adapter, u8 packetid, unsigned char sendok);
+void MDS_GetNextPacket(struct wbsoft_priv *adapter,
+ struct wb35_descriptor *pdes);
+void MDS_GetNextPacketComplete(struct wbsoft_priv *adapter,
+ struct wb35_descriptor *pdes);
+void MDS_SendResult(struct wbsoft_priv *adapter, u8 packetid,
+ unsigned char sendok);
#endif
diff --git a/drivers/staging/winbond/phy_calibration.h b/drivers/staging/winbond/phy_calibration.h
index 84f6e840a47..78fc6805860 100644
--- a/drivers/staging/winbond/phy_calibration.h
+++ b/drivers/staging/winbond/phy_calibration.h
@@ -79,6 +79,7 @@
#define SHIFT_IQCAL_TONE_Q(x) ((x) >> 13)
void phy_set_rf_data(struct hw_data *pHwData, u32 index, u32 value);
+void phy_calibration_winbond(struct hw_data *phw_data, u32 frequency);
#define phy_init_rf(_A) /* RFSynthesizer_initial(_A) */
#endif
diff --git a/drivers/staging/winbond/wb35reg.c b/drivers/staging/winbond/wb35reg.c
index 9be1b3b004b..a5e255bb0f8 100644
--- a/drivers/staging/winbond/wb35reg.c
+++ b/drivers/staging/winbond/wb35reg.c
@@ -1,10 +1,9 @@
#include "wb35reg_f.h"
+#include "phy_calibration.h"
#include <linux/usb.h>
#include <linux/slab.h>
-extern void phy_calibration_winbond(struct hw_data *phw_data, u32 frequency);
-
/*
* true : read command process successfully
* false : register not support
@@ -14,7 +13,8 @@ extern void phy_calibration_winbond(struct hw_data *phw_data, u32 frequency);
* Flag : AUTO_INCREMENT - RegisterNo will auto increment 4
* NO_INCREMENT - Function will write data into the same register
*/
-unsigned char Wb35Reg_BurstWrite(struct hw_data *pHwData, u16 RegisterNo, u32 *pRegisterData, u8 NumberOfData, u8 Flag)
+unsigned char Wb35Reg_BurstWrite(struct hw_data *pHwData, u16 RegisterNo,
+ u32 *pRegisterData, u8 NumberOfData, u8 Flag)
{
struct wb35_reg *reg = &pHwData->reg;
struct urb *urb = NULL;
@@ -44,7 +44,7 @@ unsigned char Wb35Reg_BurstWrite(struct hw_data *pHwData, u16 RegisterNo, u32 *p
reg_queue->pBuffer = (u32 *)((u8 *)reg_queue + sizeof(struct wb35_reg_queue));
memcpy(reg_queue->pBuffer, pRegisterData, DataSize);
/* the function for reversing register data from little endian to big endian */
- for (i = 0; i < NumberOfData ; i++)
+ for (i = 0; i < NumberOfData; i++)
reg_queue->pBuffer[i] = cpu_to_le32(reg_queue->pBuffer[i]);
dr = (struct usb_ctrlrequest *)((u8 *)reg_queue + sizeof(struct wb35_reg_queue) + DataSize);
@@ -72,7 +72,7 @@ unsigned char Wb35Reg_BurstWrite(struct hw_data *pHwData, u16 RegisterNo, u32 *p
return true;
}
-void Wb35Reg_Update(struct hw_data *pHwData, u16 RegisterNo, u32 RegisterValue)
+void Wb35Reg_Update(struct hw_data *pHwData, u16 RegisterNo, u32 RegisterValue)
{
struct wb35_reg *reg = &pHwData->reg;
switch (RegisterNo) {
@@ -118,7 +118,8 @@ void Wb35Reg_Update(struct hw_data *pHwData, u16 RegisterNo, u32 RegisterValue
* true : read command process successfully
* false : register not support
*/
-unsigned char Wb35Reg_WriteSync(struct hw_data *pHwData, u16 RegisterNo, u32 RegisterValue)
+unsigned char Wb35Reg_WriteSync(struct hw_data *pHwData, u16 RegisterNo,
+ u32 RegisterValue)
{
struct wb35_reg *reg = &pHwData->reg;
int ret = -1;
@@ -139,9 +140,10 @@ unsigned char Wb35Reg_WriteSync(struct hw_data *pHwData, u16 RegisterNo, u32 Reg
/* Sync IoCallDriver */
reg->EP0vm_state = VM_RUNNING;
ret = usb_control_msg(pHwData->udev,
- usb_sndctrlpipe(pHwData->udev, 0),
- 0x03, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
- 0x0, RegisterNo, &RegisterValue, 4, HZ * 100);
+ usb_sndctrlpipe(pHwData->udev, 0),
+ 0x03,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x0, RegisterNo, &RegisterValue, 4, HZ * 100);
reg->EP0vm_state = VM_STOP;
reg->SyncIoPause = 0;
@@ -159,7 +161,8 @@ unsigned char Wb35Reg_WriteSync(struct hw_data *pHwData, u16 RegisterNo, u32 Reg
* true : read command process successfully
* false : register not support
*/
-unsigned char Wb35Reg_Write(struct hw_data *pHwData, u16 RegisterNo, u32 RegisterValue)
+unsigned char Wb35Reg_Write(struct hw_data *pHwData, u16 RegisterNo,
+ u32 RegisterValue)
{
struct wb35_reg *reg = &pHwData->reg;
struct usb_ctrlrequest *dr;
@@ -286,7 +289,8 @@ unsigned char Wb35Reg_WriteWithCallbackValue(struct hw_data *pHwData,
* pRegisterValue : It must be a resident buffer due to
* asynchronous read register.
*/
-unsigned char Wb35Reg_ReadSync(struct hw_data *pHwData, u16 RegisterNo, u32 *pRegisterValue)
+unsigned char Wb35Reg_ReadSync(struct hw_data *pHwData, u16 RegisterNo,
+ u32 *pRegisterValue)
{
struct wb35_reg *reg = &pHwData->reg;
u32 *pltmp = pRegisterValue;
@@ -305,9 +309,10 @@ unsigned char Wb35Reg_ReadSync(struct hw_data *pHwData, u16 RegisterNo, u32 *pRe
reg->EP0vm_state = VM_RUNNING;
ret = usb_control_msg(pHwData->udev,
- usb_rcvctrlpipe(pHwData->udev, 0),
- 0x01, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x0, RegisterNo, pltmp, 4, HZ * 100);
+ usb_rcvctrlpipe(pHwData->udev, 0),
+ 0x01,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x0, RegisterNo, pltmp, 4, HZ * 100);
*pRegisterValue = cpu_to_le32(*pltmp);
@@ -332,7 +337,8 @@ unsigned char Wb35Reg_ReadSync(struct hw_data *pHwData, u16 RegisterNo, u32 *pRe
* pRegisterValue : It must be a resident buffer due to
* asynchronous read register.
*/
-unsigned char Wb35Reg_Read(struct hw_data *pHwData, u16 RegisterNo, u32 *pRegisterValue)
+unsigned char Wb35Reg_Read(struct hw_data *pHwData, u16 RegisterNo,
+ u32 *pRegisterValue)
{
struct wb35_reg *reg = &pHwData->reg;
struct usb_ctrlrequest *dr;
diff --git a/drivers/staging/wlags49_h2/Makefile b/drivers/staging/wlags49_h2/Makefile
index 31e1d89a384..6eeb5d1845e 100644
--- a/drivers/staging/wlags49_h2/Makefile
+++ b/drivers/staging/wlags49_h2/Makefile
@@ -51,5 +51,3 @@ $(WLNAME)-y += wl_profile.o \
mmd.o \
hcf.o \
dhf.o
-
-$(WLNAME)-$(CONFIG_SYSFS) += wl_sysfs.o
diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c
index b55dc43a1d1..a458705a379 100644
--- a/drivers/staging/wlags49_h2/wl_cs.c
+++ b/drivers/staging/wlags49_h2/wl_cs.c
@@ -99,7 +99,6 @@
#include <wl_main.h>
#include <wl_netdev.h>
#include <wl_cs.h>
-#include <wl_sysfs.h>
/*******************************************************************************
@@ -178,7 +177,6 @@ static void wl_adapter_detach(struct pcmcia_device *link)
wl_adapter_release(link);
if (dev) {
- unregister_wlags_sysfs(dev);
unregister_netdev(dev);
wl_device_dealloc(dev);
}
@@ -265,8 +263,6 @@ int wl_adapter_insert(struct pcmcia_device *link)
goto failed;
}
- register_wlags_sysfs(dev);
-
printk(KERN_INFO "%s: Wireless, io_addr %#03lx, irq %d, mac_address"
" %pM\n", dev->name, dev->base_addr, dev->irq, dev->dev_addr);
diff --git a/drivers/staging/wlags49_h2/wl_internal.h b/drivers/staging/wlags49_h2/wl_internal.h
index b2307816414..78129e93920 100644
--- a/drivers/staging/wlags49_h2/wl_internal.h
+++ b/drivers/staging/wlags49_h2/wl_internal.h
@@ -883,7 +883,6 @@ struct wl_private
int is_registered;
int is_handling_int;
int firmware_present;
- bool sysfsCreated;
CFG_DRV_INFO_STRCT driverInfo;
CFG_IDENTITY_STRCT driverIdentity;
CFG_FW_IDENTITY_STRCT StationIdentity;
diff --git a/drivers/staging/wlags49_h2/wl_sysfs.c b/drivers/staging/wlags49_h2/wl_sysfs.c
deleted file mode 100644
index 1508f04b3c6..00000000000
--- a/drivers/staging/wlags49_h2/wl_sysfs.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * ex: sw=4
- */
-
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <net/sock.h>
-#include <linux/rtnetlink.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <linux/sysfs.h>
-
-#include <debug.h>
-#include <hcf.h>
-#include <hcfdef.h>
-
-#include <wl_if.h>
-#include <wl_internal.h>
-#include <wl_util.h>
-#include <wl_main.h>
-#include <wl_wext.h>
-#include <wl_priv.h>
-
-static inline int dev_isalive(const struct net_device *dev)
-{
- return dev->reg_state == NETREG_REGISTERED;
-}
-
-/*
- * empirically even if tallies are defined as 32 bits entities, only
- * high 16 bits are relevant; low half is always zero. It means tallies
- * are pretty much useless for traffic counting but at least give overview
- * about where error come from
- */
-static ssize_t show_tallies(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct net_device *dev = to_net_dev(d);
- struct wl_private *lp = wl_priv(dev);
- unsigned long flags;
- CFG_HERMES_TALLIES_STRCT tallies;
- ssize_t ret = -EINVAL;
-
- rcu_read_lock();
- if (dev_isalive(dev)) {
- wl_lock(lp, &flags);
-
- ret = wl_get_tallies(lp, &tallies);
- if (ret == 0) {
- wl_unlock(lp, &flags);
- ret = snprintf(buf, PAGE_SIZE,
- "TxUnicastFrames: %u\n"
- "TxMulticastFrames: %u\n"
- "TxFragments: %u\n"
- "TxUnicastOctets: %u\n"
- "TxMulticastOctets: %u\n"
- "TxDeferredTransmissions: %u\n"
- "TxSingleRetryFrames: %u\n"
- "TxMultipleRetryFrames: %u\n"
- "TxRetryLimitExceeded: %u\n"
- "TxDiscards: %u\n"
- "RxUnicastFrames: %u\n"
- "RxMulticastFrames: %u\n"
- "RxFragments: %u\n"
- "RxUnicastOctets: %u\n"
- "RxMulticastOctets: %u\n"
- "RxFCSErrors: %u\n"
- "RxDiscardsNoBuffer: %u\n"
- "TxDiscardsWrongSA: %u\n"
- "RxWEPUndecryptable: %u\n"
- "RxMsgInMsgFragments: %u\n"
- "RxMsgInBadMsgFragments: %u\n"
- "RxDiscardsWEPICVError: %u\n"
- "RxDiscardsWEPExcluded: %u\n"
- ,
- (unsigned int)tallies.TxUnicastFrames,
- (unsigned int)tallies.TxMulticastFrames,
- (unsigned int)tallies.TxFragments,
- (unsigned int)tallies.TxUnicastOctets,
- (unsigned int)tallies.TxMulticastOctets,
- (unsigned int)tallies.TxDeferredTransmissions,
- (unsigned int)tallies.TxSingleRetryFrames,
- (unsigned int)tallies.TxMultipleRetryFrames,
- (unsigned int)tallies.TxRetryLimitExceeded,
- (unsigned int)tallies.TxDiscards,
- (unsigned int)tallies.RxUnicastFrames,
- (unsigned int)tallies.RxMulticastFrames,
- (unsigned int)tallies.RxFragments,
- (unsigned int)tallies.RxUnicastOctets,
- (unsigned int)tallies.RxMulticastOctets,
- (unsigned int)tallies.RxFCSErrors,
- (unsigned int)tallies.RxDiscardsNoBuffer,
- (unsigned int)tallies.TxDiscardsWrongSA,
- (unsigned int)tallies.RxWEPUndecryptable,
- (unsigned int)tallies.RxMsgInMsgFragments,
- (unsigned int)tallies.RxMsgInBadMsgFragments,
- (unsigned int)tallies.RxDiscardsWEPICVError,
- (unsigned int)tallies.RxDiscardsWEPExcluded);
- } else {
- wl_unlock( lp, &flags );
- }
- }
-
- rcu_read_unlock();
- return ret;
-}
-
-static DEVICE_ATTR(tallies, S_IRUGO, show_tallies, NULL);
-
-static struct attribute *wlags_attrs[] = {
- &dev_attr_tallies.attr,
- NULL
-};
-
-static struct attribute_group wlags_group = {
- .name = "wlags",
- .attrs = wlags_attrs,
-};
-
-void register_wlags_sysfs(struct net_device *net)
-{
- struct device *dev = &(net->dev);
- struct wl_private *lp = wl_priv(net);
- int err;
- err = sysfs_create_group(&dev->kobj, &wlags_group);
- if (!err)
- lp->sysfsCreated = true;
-}
-
-void unregister_wlags_sysfs(struct net_device *net)
-{
- struct device *dev = &(net->dev);
- struct wl_private *lp = wl_priv(net);
-
- if (lp->sysfsCreated)
- sysfs_remove_group(&dev->kobj, &wlags_group);
-}
diff --git a/drivers/staging/wlags49_h2/wl_sysfs.h b/drivers/staging/wlags49_h2/wl_sysfs.h
deleted file mode 100644
index fa658c38001..00000000000
--- a/drivers/staging/wlags49_h2/wl_sysfs.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifdef CONFIG_SYSFS
-extern void register_wlags_sysfs(struct net_device *);
-extern void unregister_wlags_sysfs(struct net_device *);
-#else
-static inline void register_wlags_sysfs(struct net_device *net) { }
-static inline void unregister_wlags_sysfs(struct net_device *net) { }
-#endif
diff --git a/drivers/staging/wlags49_h25/Makefile b/drivers/staging/wlags49_h25/Makefile
index 6e0159d0a34..513ba01c2d5 100644
--- a/drivers/staging/wlags49_h25/Makefile
+++ b/drivers/staging/wlags49_h25/Makefile
@@ -50,6 +50,3 @@ $(WLNAME)-y += wl_profile.o \
mmd.o \
hcf.o \
dhf.o
-
-$(WLNAME)-$(CONFIG_SYSFS) += wl_sysfs.o
-
diff --git a/drivers/staging/wlags49_h25/wl_sysfs.c b/drivers/staging/wlags49_h25/wl_sysfs.c
deleted file mode 100644
index 6458ee63350..00000000000
--- a/drivers/staging/wlags49_h25/wl_sysfs.c
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Use common source from wlags49_h2 */
-#include "../wlags49_h2/wl_sysfs.c"
diff --git a/drivers/staging/wlags49_h25/wl_sysfs.h b/drivers/staging/wlags49_h25/wl_sysfs.h
deleted file mode 100644
index eb819a5ef8b..00000000000
--- a/drivers/staging/wlags49_h25/wl_sysfs.h
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Use common source from wlags49_h2 */
-#include "../wlags49_h2/wl_sysfs.h"
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 801ac4053a7..3b3e17d3f6f 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -60,7 +60,7 @@ static inline void dumpVGAReg(void)
static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr,
struct xgi_hw_device_info *HwDeviceExtension,
- unsigned char modeno, unsigned char rateindex)
+ unsigned char modeno)
{
unsigned short ModeNo = modeno;
unsigned short ModeIdIndex = 0, ClockIndex = 0;
@@ -68,7 +68,7 @@ static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr,
int Clock;
InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
- XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr);
+ XGI_SearchModeID(ModeNo, &ModeIdIndex);
RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
ModeIdIndex, XGI_Pr);
@@ -82,7 +82,7 @@ static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr,
static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
struct xgi_hw_device_info *HwDeviceExtension,
- unsigned char modeno, unsigned char rateindex,
+ unsigned char modeno,
u32 *left_margin, u32 *right_margin, u32 *upper_margin,
u32 *lower_margin, u32 *hsync_len, u32 *vsync_len, u32 *sync,
u32 *vmode)
@@ -96,7 +96,7 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
unsigned char sr_data, cr_data, cr_data2;
int B, C, D, F, temp, j;
InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
- if (!XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr))
+ if (!XGI_SearchModeID(ModeNo, &ModeIdIndex))
return 0;
RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
ModeIdIndex, XGI_Pr);
@@ -1980,12 +1980,10 @@ static int xgifb_probe(struct pci_dev *pdev,
fb_info->var.pixclock = (u32) (1000000000 /
XGIfb_mode_rate_to_dclock(&xgifb_info->dev_info,
hw_info,
- XGIbios_mode[xgifb_info->mode_idx].mode_no,
- xgifb_info->rate_idx));
+ XGIbios_mode[xgifb_info->mode_idx].mode_no));
if (XGIfb_mode_rate_to_ddata(&xgifb_info->dev_info, hw_info,
XGIbios_mode[xgifb_info->mode_idx].mode_no,
- xgifb_info->rate_idx,
&fb_info->var.left_margin,
&fb_info->var.right_margin,
&fb_info->var.upper_margin,
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index 5f1c41ed778..21541720e05 100644
--- a/drivers/staging/xgifb/vb_init.c
+++ b/drivers/staging/xgifb/vb_init.c
@@ -102,10 +102,8 @@ static void XGINew_DDR1x_MRS_340(unsigned long P3c4,
xgifb_reg_set(P3c4, 0x1B, 0x00);
}
-static void XGINew_SetMemoryClock(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+static void XGINew_SetMemoryClock(struct vb_device_info *pVBInfo)
{
-
xgifb_reg_set(pVBInfo->P3c4,
0x28,
pVBInfo->MCLKData[pVBInfo->ram_type].SR28);
@@ -133,7 +131,7 @@ static void XGINew_DDRII_Bootup_XG27(
{
unsigned long P3d4 = P3c4 + 0x10;
pVBInfo->ram_type = XGINew_GetXG20DRAMType(HwDeviceExtension, pVBInfo);
- XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
+ XGINew_SetMemoryClock(pVBInfo);
/* Set Double Frequency */
xgifb_reg_set(P3d4, 0x97, pVBInfo->XGINew_CR97); /* CR97 */
@@ -206,7 +204,7 @@ static void XGINew_DDR2_MRS_XG20(struct xgi_hw_device_info *HwDeviceExtension,
unsigned long P3d4 = P3c4 + 0x10;
pVBInfo->ram_type = XGINew_GetXG20DRAMType(HwDeviceExtension, pVBInfo);
- XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
+ XGINew_SetMemoryClock(pVBInfo);
xgifb_reg_set(P3d4, 0x97, 0x11); /* CR97 */
@@ -280,7 +278,7 @@ static void XGINew_DDR1x_DefaultRegister(
unsigned long P3d4 = Port, P3c4 = Port - 0x10;
if (HwDeviceExtension->jChipType >= XG20) {
- XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
+ XGINew_SetMemoryClock(pVBInfo);
xgifb_reg_set(P3d4,
0x82,
pVBInfo->CR40[11][pVBInfo->ram_type]); /* CR82 */
@@ -296,7 +294,7 @@ static void XGINew_DDR1x_DefaultRegister(
XGINew_DDR1x_MRS_XG20(P3c4, pVBInfo);
} else {
- XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
+ XGINew_SetMemoryClock(pVBInfo);
switch (HwDeviceExtension->jChipType) {
case XG42:
@@ -876,8 +874,7 @@ done:
return rom_copy;
}
-static bool xgifb_read_vbios(struct pci_dev *pdev,
- struct vb_device_info *pVBInfo)
+static bool xgifb_read_vbios(struct pci_dev *pdev)
{
struct xgifb_video_info *xgifb_info = pci_get_drvdata(pdev);
u8 *vbios;
@@ -948,8 +945,7 @@ error:
return false;
}
-static void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+static void XGINew_ChkSenseStatus(struct vb_device_info *pVBInfo)
{
unsigned short tempbx = 0, temp, tempcx, CR3CData;
@@ -991,8 +987,7 @@ static void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension,
xgifb_reg_set(pVBInfo->P3d4, 0x3e, ((tempbx & 0xFF00) >> 8));
}
-static void XGINew_SetModeScratch(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+static void XGINew_SetModeScratch(struct vb_device_info *pVBInfo)
{
unsigned short temp, tempcl = 0, tempch = 0, CR31Data, CR38Data;
@@ -1102,7 +1097,7 @@ static void XGINew_GetXG21Sense(struct pci_dev *pdev,
struct xgifb_video_info *xgifb_info = pci_get_drvdata(pdev);
unsigned char Temp;
- if (xgifb_read_vbios(pdev, pVBInfo)) { /* For XG21 LVDS */
+ if (xgifb_read_vbios(pdev)) { /* For XG21 LVDS */
xgifb_reg_or(pVBInfo->P3d4, 0x32, LCDSense);
/* LVDS on chip */
xgifb_reg_and_or(pVBInfo->P3d4, 0x38, ~0xE0, 0xC0);
@@ -1126,8 +1121,7 @@ static void XGINew_GetXG21Sense(struct pci_dev *pdev,
}
}
-static void XGINew_GetXG27Sense(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+static void XGINew_GetXG27Sense(struct vb_device_info *pVBInfo)
{
unsigned char Temp, bCR4A;
@@ -1222,7 +1216,7 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
XGINew_GetXG21Sense(pdev, pVBInfo);
if (HwDeviceExtension->jChipType == XG27)
- XGINew_GetXG27Sense(HwDeviceExtension, pVBInfo);
+ XGINew_GetXG27Sense(pVBInfo);
/* Reset Extended register */
@@ -1294,7 +1288,7 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
if (HwDeviceExtension->jChipType < XG20) {
/* Set VB */
- XGI_UnLockCRT2(HwDeviceExtension, pVBInfo);
+ XGI_UnLockCRT2(pVBInfo);
/* disable VideoCapture */
xgifb_reg_and_or(pVBInfo->Part0Port, 0x3F, 0xEF, 0x00);
xgifb_reg_set(pVBInfo->Part1Port, 0x00, 0x00);
@@ -1334,7 +1328,7 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
xgifb_reg_set(pVBInfo->Part4Port,
0x10, XGI330_CRT2Data_4_10);
xgifb_reg_set(pVBInfo->Part4Port, 0x0F, 0x3F);
- XGI_LockCRT2(HwDeviceExtension, pVBInfo);
+ XGI_LockCRT2(pVBInfo);
}
} /* != XG20 */
@@ -1370,8 +1364,8 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
xgifb_reg_set(pVBInfo->P3c4, 0x22, 0xfa);
xgifb_reg_set(pVBInfo->P3c4, 0x21, 0xa3);
- XGINew_ChkSenseStatus(HwDeviceExtension, pVBInfo);
- XGINew_SetModeScratch(HwDeviceExtension, pVBInfo);
+ XGINew_ChkSenseStatus(pVBInfo);
+ XGINew_SetModeScratch(pVBInfo);
xgifb_reg_set(pVBInfo->P3d4, 0x8c, 0x87);
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
index fcefe5b36cd..46dea3f1088 100644
--- a/drivers/staging/xgifb/vb_setmode.c
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -63,9 +63,7 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
}
-static void XGI_SetSeqRegs(unsigned short ModeNo,
- unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_SetSeqRegs(struct vb_device_info *pVBInfo)
{
unsigned char SRdata, i;
@@ -79,8 +77,7 @@ static void XGI_SetSeqRegs(unsigned short ModeNo,
}
}
-static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+static void XGI_SetCRTCRegs(struct vb_device_info *pVBInfo)
{
unsigned char CRTCdata;
unsigned short i;
@@ -96,8 +93,7 @@ static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension,
}
}
-static void XGI_SetATTRegs(unsigned short ModeNo,
- unsigned short ModeIdIndex,
+static void XGI_SetATTRegs(unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
unsigned char ARdata;
@@ -171,8 +167,7 @@ static unsigned char XGI_SetDefaultVCLK(struct vb_device_info *pVBInfo)
return 0;
}
-static unsigned char XGI_AjustCRT2Rate(unsigned short ModeNo,
- unsigned short ModeIdIndex,
+static unsigned char XGI_AjustCRT2Rate(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex, unsigned short *i,
struct vb_device_info *pVBInfo)
{
@@ -322,7 +317,6 @@ static void XGI_SetCRT1Timing_H(struct vb_device_info *pVBInfo,
}
static void XGI_SetCRT1Timing_V(unsigned short ModeIdIndex,
- unsigned short ModeNo,
struct vb_device_info *pVBInfo)
{
unsigned char data;
@@ -365,7 +359,7 @@ static void XGI_SetCRT1Timing_V(unsigned short ModeIdIndex,
xgifb_reg_set(pVBInfo->P3d4, 0x09, data);
}
-static void XGI_SetCRT1CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_SetCRT1CRTC(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo,
struct xgi_hw_device_info *HwDeviceExtension)
@@ -391,7 +385,7 @@ static void XGI_SetCRT1CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
XGI_SetCRT1Timing_H(pVBInfo, HwDeviceExtension);
- XGI_SetCRT1Timing_V(ModeIdIndex, ModeNo, pVBInfo);
+ XGI_SetCRT1Timing_V(ModeIdIndex, pVBInfo);
if (pVBInfo->ModeType > 0x03)
xgifb_reg_set(pVBInfo->P3d4, 0x14, 0x4F);
@@ -403,8 +397,7 @@ static void XGI_SetCRT1CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
/* Output : Fill CRT Hsync/Vsync to SR2E/SR2F/SR30/SR33/SR34/SR3F */
/* Description : Set LCD timing */
/* --------------------------------------------------------------------- */
-static void XGI_SetXG21CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
- unsigned short RefreshRateTableIndex,
+static void XGI_SetXG21CRTC(unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
unsigned char index, Tempax, Tempbx, Tempcx, Tempdx;
@@ -500,9 +493,7 @@ static void XGI_SetXG21CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
}
-static void XGI_SetXG27CRTC(unsigned short ModeNo,
- unsigned short ModeIdIndex,
- unsigned short RefreshRateTableIndex,
+static void XGI_SetXG27CRTC(unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
unsigned short index, Tempax, Tempbx, Tempcx;
@@ -605,8 +596,7 @@ static void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo)
static void xgifb_set_lcd(int chip_id,
struct vb_device_info *pVBInfo,
- unsigned short RefreshRateTableIndex,
- unsigned short ModeNo)
+ unsigned short RefreshRateTableIndex)
{
unsigned short temp;
@@ -687,8 +677,7 @@ static void XGI_UpdateXG21CRTC(unsigned short ModeNo,
}
}
-static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension,
- unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_SetCRT1DE(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
@@ -834,10 +823,8 @@ static void XGI_SetCRT1Offset(unsigned short ModeNo,
xgifb_reg_set(pVBInfo->P3c4, 0x10, ah);
}
-static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
- unsigned short ModeIdIndex,
+static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
struct vb_device_info *pVBInfo)
{
unsigned short VCLKIndex, modeflag;
@@ -886,8 +873,7 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
return VCLKIndex;
}
-static void XGI_SetCRT1VCLK(unsigned short ModeNo,
- unsigned short ModeIdIndex,
+static void XGI_SetCRT1VCLK(unsigned short ModeIdIndex,
struct xgi_hw_device_info *HwDeviceExtension,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
@@ -899,9 +885,8 @@ static void XGI_SetCRT1VCLK(unsigned short ModeNo,
(pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV |
VB_SIS302LV | VB_XGI301C)) &&
(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)) {
- vclkindex = XGI_GetVCLK2Ptr(ModeNo, ModeIdIndex,
- RefreshRateTableIndex, HwDeviceExtension,
- pVBInfo);
+ vclkindex = XGI_GetVCLK2Ptr(ModeIdIndex, RefreshRateTableIndex,
+ pVBInfo);
data = xgifb_reg_get(pVBInfo->P3c4, 0x31) & 0xCF;
xgifb_reg_set(pVBInfo->P3c4, 0x31, data);
data = XGI_VBVCLKData[vclkindex].Part4_A;
@@ -948,9 +933,8 @@ static void XGI_SetXG21FPBits(struct vb_device_info *pVBInfo)
}
-static void XGI_SetCRT1FIFO(unsigned short ModeNo,
- struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+static void XGI_SetCRT1FIFO(struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
unsigned short data;
@@ -971,7 +955,7 @@ static void XGI_SetCRT1FIFO(unsigned short ModeNo,
}
static void XGI_SetVCLKState(struct xgi_hw_device_info *HwDeviceExtension,
- unsigned short ModeNo, unsigned short RefreshRateTableIndex,
+ unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
unsigned short data, data2 = 0;
@@ -1010,7 +994,7 @@ static void XGI_SetVCLKState(struct xgi_hw_device_info *HwDeviceExtension,
}
static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension,
- unsigned short ModeNo, unsigned short ModeIdIndex,
+ unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
@@ -1063,8 +1047,7 @@ static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension,
data = data ^ 0xA0;
xgifb_reg_and_or(pVBInfo->P3c4, 0x21, 0x1F, data);
- XGI_SetVCLKState(HwDeviceExtension, ModeNo, RefreshRateTableIndex,
- pVBInfo);
+ XGI_SetVCLKState(HwDeviceExtension, RefreshRateTableIndex, pVBInfo);
data = xgifb_reg_get(pVBInfo->P3d4, 0x31);
@@ -1122,8 +1105,7 @@ static void XGI_WriteDAC(unsigned short dl,
outb((unsigned short) bl, pVBInfo->P3c9);
}
-static void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_LoadDAC(struct vb_device_info *pVBInfo)
{
unsigned short data, data2, i, k, m, n, o, si, di, bx, dl, al, ah, dh;
const unsigned short *table = XGINew_VGA_DAC;
@@ -1188,8 +1170,7 @@ static void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex,
}
}
-static void XGI_GetLVDSResInfo(unsigned short ModeNo,
- unsigned short ModeIdIndex,
+static void XGI_GetLVDSResInfo(unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
unsigned short resindex, xres, yres, modeflag;
@@ -1219,9 +1200,7 @@ static void XGI_GetLVDSResInfo(unsigned short ModeNo,
}
static void const *XGI_GetLcdPtr(struct XGI330_LCDDataTablStruct const *table,
- unsigned short ModeNo,
unsigned short ModeIdIndex,
- unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
unsigned short i, tempdx, tempbx, modeflag;
@@ -1259,8 +1238,7 @@ static void const *XGI_GetLcdPtr(struct XGI330_LCDDataTablStruct const *table,
return table[i].DATAPTR;
}
-static struct SiS_TVData const *XGI_GetTVPtr(unsigned short ModeNo,
- unsigned short ModeIdIndex,
+static struct SiS_TVData const *XGI_GetTVPtr(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
@@ -1289,17 +1267,15 @@ static struct SiS_TVData const *XGI_GetTVPtr(unsigned short ModeNo,
return &XGI_TVDataTable[i].DATAPTR[tempal];
}
-static void XGI_GetLVDSData(unsigned short ModeNo, unsigned short ModeIdIndex,
- unsigned short RefreshRateTableIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_GetLVDSData(unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
struct SiS_LVDSData const *LCDPtr;
if (!(pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)))
return;
- LCDPtr = XGI_GetLcdPtr(XGI_EPLLCDDataPtr, ModeNo, ModeIdIndex,
- RefreshRateTableIndex, pVBInfo);
+ LCDPtr = XGI_GetLcdPtr(XGI_EPLLCDDataPtr, ModeIdIndex, pVBInfo);
pVBInfo->VGAHT = LCDPtr->VGAHT;
pVBInfo->VGAVT = LCDPtr->VGAVT;
pVBInfo->HT = LCDPtr->LCDHT;
@@ -1325,18 +1301,17 @@ static void XGI_GetLVDSData(unsigned short ModeNo, unsigned short ModeIdIndex,
}
}
-static void XGI_ModCRT1Regs(unsigned short ModeNo, unsigned short ModeIdIndex,
- unsigned short RefreshRateTableIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+static void XGI_ModCRT1Regs(unsigned short ModeIdIndex,
+ struct xgi_hw_device_info *HwDeviceExtension,
+ struct vb_device_info *pVBInfo)
{
unsigned short i;
struct XGI_LVDSCRT1HDataStruct const *LCDPtr = NULL;
struct XGI_LVDSCRT1VDataStruct const *LCDPtr1 = NULL;
if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
- LCDPtr = XGI_GetLcdPtr(xgifb_epllcd_crt1_h, ModeNo, ModeIdIndex,
- RefreshRateTableIndex, pVBInfo);
+ LCDPtr = XGI_GetLcdPtr(xgifb_epllcd_crt1_h, ModeIdIndex,
+ pVBInfo);
for (i = 0; i < 8; i++)
pVBInfo->TimingH.data[i] = LCDPtr[0].Reg[i];
@@ -1345,14 +1320,13 @@ static void XGI_ModCRT1Regs(unsigned short ModeNo, unsigned short ModeIdIndex,
XGI_SetCRT1Timing_H(pVBInfo, HwDeviceExtension);
if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
- LCDPtr1 = XGI_GetLcdPtr(xgifb_epllcd_crt1_v, ModeNo,
- ModeIdIndex, RefreshRateTableIndex,
+ LCDPtr1 = XGI_GetLcdPtr(xgifb_epllcd_crt1_v, ModeIdIndex,
pVBInfo);
for (i = 0; i < 7; i++)
pVBInfo->TimingV.data[i] = LCDPtr1[0].Reg[i];
}
- XGI_SetCRT1Timing_V(ModeIdIndex, ModeNo, pVBInfo);
+ XGI_SetCRT1Timing_V(ModeIdIndex, pVBInfo);
}
static unsigned short XGI_GetLCDCapPtr(struct vb_device_info *pVBInfo)
@@ -1425,17 +1399,15 @@ static void XGI_GetLCDSync(unsigned short *HSyncWidth,
*VSyncWidth = pVBInfo->LCDCapList[Index].LCD_VSyncWidth;
}
-static void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
- unsigned short RefreshRateTableIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_SetLVDSRegs(unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
unsigned short tempbx, tempax, tempcx, tempdx, push1, push2, modeflag;
unsigned long temp, temp1, temp2, temp3, push3;
struct XGI330_LCDDataDesStruct2 const *LCDPtr1 = NULL;
modeflag = XGI330_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- LCDPtr1 = XGI_GetLcdPtr(XGI_EPLLCDDesDataPtr, ModeNo, ModeIdIndex,
- RefreshRateTableIndex, pVBInfo);
+ LCDPtr1 = XGI_GetLcdPtr(XGI_EPLLCDDesDataPtr, ModeIdIndex, pVBInfo);
XGI_GetLCDSync(&tempax, &tempbx, pVBInfo);
push1 = tempbx;
@@ -1686,8 +1658,7 @@ static void XGI_GetLCDVCLKPtr(unsigned char *di_0, unsigned char *di_1,
}
static unsigned char XGI_GetVCLKPtr(unsigned short RefreshRateTableIndex,
- unsigned short ModeNo, unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
+ unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
{
unsigned short index, modeflag;
@@ -1769,15 +1740,14 @@ static void XGI_GetVCLKLen(unsigned char tempal, unsigned char *di_0,
}
}
-static void XGI_SetCRT2ECLK(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_SetCRT2ECLK(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
unsigned char di_0, di_1, tempal;
int i;
- tempal = XGI_GetVCLKPtr(RefreshRateTableIndex, ModeNo, ModeIdIndex,
- pVBInfo);
+ tempal = XGI_GetVCLKPtr(RefreshRateTableIndex, ModeIdIndex, pVBInfo);
XGI_GetVCLKLen(tempal, &di_0, &di_1, pVBInfo);
XGI_GetLCDVCLKPtr(&di_0, &di_1, pVBInfo);
@@ -1795,8 +1765,7 @@ static void XGI_SetCRT2ECLK(unsigned short ModeNo, unsigned short ModeIdIndex,
}
}
-static void XGI_UpdateModeInfo(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+static void XGI_UpdateModeInfo(struct vb_device_info *pVBInfo)
{
unsigned short tempcl, tempch, temp, tempbl, tempax;
@@ -1922,8 +1891,7 @@ finish:
pVBInfo->VBType = tempbx;
}
-static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
+static void XGI_GetVBInfo(unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
unsigned short tempax, push, tempbx, temp, modeflag;
@@ -2048,7 +2016,7 @@ static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
pVBInfo->VBInfo = tempbx;
}
-static void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_GetTVInfo(unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
unsigned short tempbx = 0, resinfo = 0, modeflag, index1;
@@ -2115,8 +2083,8 @@ static void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
pVBInfo->TVInfo = tempbx;
}
-static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
- unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
+static unsigned char XGI_GetLCDInfo(unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
unsigned short temp, tempax, tempbx, resinfo = 0, LCDIdIndex;
@@ -2196,7 +2164,7 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
}
unsigned char XGI_SearchModeID(unsigned short ModeNo,
- unsigned short *ModeIdIndex, struct vb_device_info *pVBInfo)
+ unsigned short *ModeIdIndex)
{
for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
if (XGI330_EModeIDTable[*ModeIdIndex].Ext_ModeID == ModeNo)
@@ -2435,8 +2403,7 @@ static void XGI_SaveCRT2Info(unsigned short ModeNo,
xgifb_reg_and_or(pVBInfo->P3d4, 0x31, temp2, temp1);
}
-static void XGI_GetCRT2ResInfo(unsigned short ModeNo,
- unsigned short ModeIdIndex,
+static void XGI_GetCRT2ResInfo(unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
unsigned short xres, yres, modeflag, resindex;
@@ -2508,8 +2475,7 @@ static unsigned char XGI_IsLCDDualLink(struct vb_device_info *pVBInfo)
return 0;
}
-static void XGI_GetRAMDAC2DATA(unsigned short ModeNo,
- unsigned short ModeIdIndex,
+static void XGI_GetRAMDAC2DATA(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
@@ -2551,7 +2517,7 @@ static void XGI_GetRAMDAC2DATA(unsigned short ModeNo,
pVBInfo->VT = tempbx;
}
-static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_GetCRT2Data(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
@@ -2566,14 +2532,13 @@ static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex,
pVBInfo->RVBHRS = 50;
if (pVBInfo->VBInfo & SetCRT2ToRAMDAC) {
- XGI_GetRAMDAC2DATA(ModeNo, ModeIdIndex, RefreshRateTableIndex,
- pVBInfo);
+ XGI_GetRAMDAC2DATA(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
return;
}
if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
- LCDPtr = XGI_GetLcdPtr(XGI_LCDDataTable, ModeNo, ModeIdIndex,
- RefreshRateTableIndex, pVBInfo);
+ LCDPtr = XGI_GetLcdPtr(XGI_LCDDataTable, ModeIdIndex,
+ pVBInfo);
pVBInfo->RVBHCMAX = LCDPtr->RVBHCMAX;
pVBInfo->RVBHCFACT = LCDPtr->RVBHCFACT;
@@ -2654,7 +2619,7 @@ static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex,
if (pVBInfo->VBInfo & (SetCRT2ToTV)) {
struct SiS_TVData const *TVPtr;
- TVPtr = XGI_GetTVPtr(ModeNo, ModeIdIndex, RefreshRateTableIndex,
+ TVPtr = XGI_GetTVPtr(ModeIdIndex, RefreshRateTableIndex,
pVBInfo);
pVBInfo->RVBHCMAX = TVPtr->RVBHCMAX;
@@ -2722,14 +2687,13 @@ static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex,
}
}
-static void XGI_SetCRT2VCLK(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_SetCRT2VCLK(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
unsigned char di_0, di_1, tempal;
- tempal = XGI_GetVCLKPtr(RefreshRateTableIndex, ModeNo, ModeIdIndex,
- pVBInfo);
+ tempal = XGI_GetVCLKPtr(RefreshRateTableIndex, ModeIdIndex, pVBInfo);
XGI_GetVCLKLen(tempal, &di_0, &di_1, pVBInfo);
XGI_GetLCDVCLKPtr(&di_0, &di_1, pVBInfo);
@@ -2751,8 +2715,7 @@ static void XGI_SetCRT2VCLK(unsigned short ModeNo, unsigned short ModeIdIndex,
xgifb_reg_or(pVBInfo->Part4Port, 0x12, 0x08);
}
-static unsigned short XGI_GetColorDepth(unsigned short ModeNo,
- unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
+static unsigned short XGI_GetColorDepth(unsigned short ModeIdIndex)
{
unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
short index;
@@ -2769,9 +2732,7 @@ static unsigned short XGI_GetColorDepth(unsigned short ModeNo,
static unsigned short XGI_GetOffset(unsigned short ModeNo,
unsigned short ModeIdIndex,
- unsigned short RefreshRateTableIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+ unsigned short RefreshRateTableIndex)
{
unsigned short temp, colordepth, modeinfo, index, infoflag,
ColorDepth[] = { 0x01, 0x02, 0x04 };
@@ -2786,7 +2747,7 @@ static unsigned short XGI_GetOffset(unsigned short ModeNo,
if (infoflag & InterlaceMode)
temp = temp << 1;
- colordepth = XGI_GetColorDepth(ModeNo, ModeIdIndex, pVBInfo);
+ colordepth = XGI_GetColorDepth(ModeIdIndex);
if ((ModeNo >= 0x7C) && (ModeNo <= 0x7E)) {
temp = ModeNo - 0x7C;
@@ -2801,7 +2762,6 @@ static unsigned short XGI_GetOffset(unsigned short ModeNo,
static void XGI_SetCRT2Offset(unsigned short ModeNo,
unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
struct vb_device_info *pVBInfo)
{
unsigned short offset;
@@ -2810,8 +2770,7 @@ static void XGI_SetCRT2Offset(unsigned short ModeNo,
if (pVBInfo->VBInfo & SetInSlaveMode)
return;
- offset = XGI_GetOffset(ModeNo, ModeIdIndex, RefreshRateTableIndex,
- HwDeviceExtension, pVBInfo);
+ offset = XGI_GetOffset(ModeNo, ModeIdIndex, RefreshRateTableIndex);
temp = (unsigned char) (offset & 0xFF);
xgifb_reg_set(pVBInfo->Part1Port, 0x07, temp);
temp = (unsigned char) ((offset & 0xFF00) >> 8);
@@ -2829,14 +2788,12 @@ static void XGI_SetCRT2FIFO(struct vb_device_info *pVBInfo)
}
static void XGI_PreSetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
u8 tempcx;
- XGI_SetCRT2Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex,
- HwDeviceExtension, pVBInfo);
+ XGI_SetCRT2Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
XGI_SetCRT2FIFO(pVBInfo);
for (tempcx = 4; tempcx < 7; tempcx++)
@@ -2846,8 +2803,7 @@ static void XGI_PreSetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
xgifb_reg_set(pVBInfo->Part1Port, 0x02, 0x44); /* temp 0206 */
}
-static void XGI_SetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
+static void XGI_SetGroup1(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
@@ -3002,8 +2958,6 @@ static unsigned short XGI_GetVGAHT2(struct vb_device_info *pVBInfo)
}
static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
- unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
unsigned short push1, push2, tempax, tempbx = 0, tempcx, temp, resinfo,
@@ -3294,8 +3248,6 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
}
static void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex,
- unsigned short RefreshRateTableIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
struct vb_device_info *pVBInfo)
{
unsigned short i, j, tempax, tempbx, tempcx, temp, push1, push2,
@@ -3724,9 +3676,7 @@ static void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex,
}
}
-static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
- unsigned short RefreshRateTableIndex,
+static void XGI_SetLCDRegs(unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
unsigned short pushbx, tempax, tempbx, tempcx, temp, tempah,
@@ -3772,11 +3722,10 @@ static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
/* Customized LCDB Does not add */
if ((pVBInfo->VBType & VB_SIS301LV) || (pVBInfo->VBType & VB_SIS302LV))
- LCDBDesPtr = XGI_GetLcdPtr(xgifb_lcddldes, ModeNo, ModeIdIndex,
- RefreshRateTableIndex, pVBInfo);
+ LCDBDesPtr = XGI_GetLcdPtr(xgifb_lcddldes, ModeIdIndex,
+ pVBInfo);
else
- LCDBDesPtr = XGI_GetLcdPtr(XGI_LCDDesDataTable, ModeNo,
- ModeIdIndex, RefreshRateTableIndex,
+ LCDBDesPtr = XGI_GetLcdPtr(XGI_LCDDesDataTable, ModeIdIndex,
pVBInfo);
tempah = pVBInfo->LCDResInfo;
@@ -4003,8 +3952,8 @@ static void XGI_SetTap4Regs(struct vb_device_info *pVBInfo)
xgifb_reg_and_or(pVBInfo->Part2Port, 0x4E, ~0x14, 0x10);
}
-static void XGI_SetGroup3(unsigned short ModeNo, unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_SetGroup3(unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
unsigned short i;
unsigned char const *tempdi;
@@ -4059,9 +4008,8 @@ static void XGI_SetGroup3(unsigned short ModeNo, unsigned short ModeIdIndex,
}
}
-static void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_SetGroup4(unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
- struct xgi_hw_device_info *HwDeviceExtension,
struct vb_device_info *pVBInfo)
{
unsigned short tempax, tempcx, tempbx, modeflag, temp, temp2;
@@ -4224,7 +4172,7 @@ static void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex,
}
/* end 301b */
- XGI_SetCRT2VCLK(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+ XGI_SetCRT2VCLK(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
}
static void XGINew_EnableCRT2(struct vb_device_info *pVBInfo)
@@ -4232,8 +4180,7 @@ static void XGINew_EnableCRT2(struct vb_device_info *pVBInfo)
xgifb_reg_and_or(pVBInfo->P3c4, 0x1E, 0xFF, 0x20);
}
-static void XGI_SetGroup5(unsigned short ModeNo, unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_SetGroup5(struct vb_device_info *pVBInfo)
{
if (pVBInfo->ModeType == ModeVGA) {
if (!(pVBInfo->VBInfo & (SetInSlaveMode | LoadDACFlag
@@ -4243,16 +4190,13 @@ static void XGI_SetGroup5(unsigned short ModeNo, unsigned short ModeIdIndex,
}
}
-static void XGI_DisableGatingCRT(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+static void XGI_DisableGatingCRT(struct vb_device_info *pVBInfo)
{
-
xgifb_reg_and_or(pVBInfo->P3d4, 0x63, 0xBF, 0x00);
}
static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info,
- unsigned short ModeNo, unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
+ unsigned short ModeNo, unsigned short ModeIdIndex)
{
unsigned short xres, yres, colordepth, modeflag, resindex;
@@ -4281,7 +4225,7 @@ static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info,
if (xres != xgifb_info->lvds_data.LVDSHDE ||
yres != xgifb_info->lvds_data.LVDSVDE) {
- colordepth = XGI_GetColorDepth(ModeNo, ModeIdIndex, pVBInfo);
+ colordepth = XGI_GetColorDepth(ModeIdIndex);
if (colordepth > 2)
return 0;
}
@@ -4290,7 +4234,6 @@ static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info,
static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info,
int chip_id,
- unsigned short ModeNo,
unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
@@ -4831,9 +4774,7 @@ static void XGI_SetLCDCap(struct vb_device_info *pVBInfo)
/* Output : */
/* Description : Set TV Customized Param. */
/* --------------------------------------------------------------------- */
-static void XGI_SetAntiFlicker(unsigned short ModeNo,
- unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_SetAntiFlicker(struct vb_device_info *pVBInfo)
{
unsigned short tempbx;
@@ -4850,9 +4791,7 @@ static void XGI_SetAntiFlicker(unsigned short ModeNo,
xgifb_reg_and_or(pVBInfo->Part2Port, 0x0A, 0x8F, tempah);
}
-static void XGI_SetEdgeEnhance(unsigned short ModeNo,
- unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_SetEdgeEnhance(struct vb_device_info *pVBInfo)
{
unsigned short tempbx;
@@ -4887,8 +4826,8 @@ static void XGI_SetPhaseIncr(struct vb_device_info *pVBInfo)
& 0xFF000000) >> 24));
}
-static void XGI_SetYFilter(unsigned short ModeNo, unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_SetYFilter(unsigned short ModeIdIndex,
+ struct vb_device_info *pVBInfo)
{
unsigned short tempbx, index;
unsigned char const *filterPtr;
@@ -4957,8 +4896,7 @@ static void XGI_SetYFilter(unsigned short ModeNo, unsigned short ModeIdIndex,
/* Output : */
/* Description : Customized Param. for 301 */
/* --------------------------------------------------------------------- */
-static void XGI_OEM310Setting(unsigned short ModeNo,
- unsigned short ModeIdIndex,
+static void XGI_OEM310Setting(unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
XGI_SetDelayComp(pVBInfo);
@@ -4968,11 +4906,11 @@ static void XGI_OEM310Setting(unsigned short ModeNo,
if (pVBInfo->VBInfo & SetCRT2ToTV) {
XGI_SetPhaseIncr(pVBInfo);
- XGI_SetYFilter(ModeNo, ModeIdIndex, pVBInfo);
- XGI_SetAntiFlicker(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetYFilter(ModeIdIndex, pVBInfo);
+ XGI_SetAntiFlicker(pVBInfo);
if (pVBInfo->VBType & VB_SIS301)
- XGI_SetEdgeEnhance(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetEdgeEnhance(pVBInfo);
}
}
@@ -4982,9 +4920,7 @@ static void XGI_OEM310Setting(unsigned short ModeNo,
/* Output : */
/* Description : Origin code for crt2group */
/* --------------------------------------------------------------------- */
-static void XGI_SetCRT2ModeRegs(unsigned short ModeNo,
- struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+static void XGI_SetCRT2ModeRegs(struct vb_device_info *pVBInfo)
{
unsigned short tempbl;
short tempcl;
@@ -5146,20 +5082,14 @@ reg_and_or:
}
-void XGI_UnLockCRT2(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+void XGI_UnLockCRT2(struct vb_device_info *pVBInfo)
{
-
xgifb_reg_and_or(pVBInfo->Part1Port, 0x2f, 0xFF, 0x01);
-
}
-void XGI_LockCRT2(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *pVBInfo)
+void XGI_LockCRT2(struct vb_device_info *pVBInfo)
{
-
xgifb_reg_and_or(pVBInfo->Part1Port, 0x2F, 0xFE, 0x00);
-
}
unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE,
@@ -5231,8 +5161,8 @@ unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE,
}
i--;
if ((pVBInfo->SetFlag & ProgrammingCRT2)) {
- temp = XGI_AjustCRT2Rate(ModeNo, ModeIdIndex,
- RefreshRateTableIndex, &i, pVBInfo);
+ temp = XGI_AjustCRT2Rate(ModeIdIndex, RefreshRateTableIndex,
+ &i, pVBInfo);
}
return RefreshRateTableIndex + i;
}
@@ -5246,12 +5176,11 @@ static void XGI_SetLCDAGroup(unsigned short ModeNo, unsigned short ModeIdIndex,
pVBInfo->SetFlag |= ProgrammingCRT2;
RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
ModeIdIndex, pVBInfo);
- XGI_GetLVDSResInfo(ModeNo, ModeIdIndex, pVBInfo);
- XGI_GetLVDSData(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
- XGI_ModCRT1Regs(ModeNo, ModeIdIndex, RefreshRateTableIndex,
- HwDeviceExtension, pVBInfo);
- XGI_SetLVDSRegs(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
- XGI_SetCRT2ECLK(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+ XGI_GetLVDSResInfo(ModeIdIndex, pVBInfo);
+ XGI_GetLVDSData(ModeIdIndex, pVBInfo);
+ XGI_ModCRT1Regs(ModeIdIndex, HwDeviceExtension, pVBInfo);
+ XGI_SetLVDSRegs(ModeIdIndex, pVBInfo);
+ XGI_SetCRT2ECLK(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
}
static unsigned char XGI_SetCRT2Group301(unsigned short ModeNo,
@@ -5261,29 +5190,23 @@ static unsigned char XGI_SetCRT2Group301(unsigned short ModeNo,
unsigned short ModeIdIndex, RefreshRateTableIndex;
pVBInfo->SetFlag |= ProgrammingCRT2;
- XGI_SearchModeID(ModeNo, &ModeIdIndex, pVBInfo);
+ XGI_SearchModeID(ModeNo, &ModeIdIndex);
pVBInfo->SelectCRT2Rate = 4;
RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
ModeIdIndex, pVBInfo);
XGI_SaveCRT2Info(ModeNo, pVBInfo);
- XGI_GetCRT2ResInfo(ModeNo, ModeIdIndex, pVBInfo);
- XGI_GetCRT2Data(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
- XGI_PreSetGroup1(ModeNo, ModeIdIndex, HwDeviceExtension,
- RefreshRateTableIndex, pVBInfo);
- XGI_SetGroup1(ModeNo, ModeIdIndex, HwDeviceExtension,
- RefreshRateTableIndex, pVBInfo);
- XGI_SetLockRegs(ModeNo, ModeIdIndex, HwDeviceExtension,
- RefreshRateTableIndex, pVBInfo);
- XGI_SetGroup2(ModeNo, ModeIdIndex, RefreshRateTableIndex,
- HwDeviceExtension, pVBInfo);
- XGI_SetLCDRegs(ModeNo, ModeIdIndex, HwDeviceExtension,
- RefreshRateTableIndex, pVBInfo);
+ XGI_GetCRT2ResInfo(ModeIdIndex, pVBInfo);
+ XGI_GetCRT2Data(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+ XGI_PreSetGroup1(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+ XGI_SetGroup1(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+ XGI_SetLockRegs(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetGroup2(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetLCDRegs(ModeIdIndex, pVBInfo);
XGI_SetTap4Regs(pVBInfo);
- XGI_SetGroup3(ModeNo, ModeIdIndex, pVBInfo);
- XGI_SetGroup4(ModeNo, ModeIdIndex, RefreshRateTableIndex,
- HwDeviceExtension, pVBInfo);
- XGI_SetCRT2VCLK(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
- XGI_SetGroup5(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetGroup3(ModeIdIndex, pVBInfo);
+ XGI_SetGroup4(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+ XGI_SetCRT2VCLK(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+ XGI_SetGroup5(pVBInfo);
XGI_AutoThreshold(pVBInfo);
return 1;
}
@@ -5442,7 +5365,7 @@ static void XGI_EnableBridge(struct xgifb_video_info *xgifb_info,
/* EnablePart4_1F */
xgifb_reg_or(pVBInfo->Part4Port, 0x1F, tempah);
- XGI_DisableGatingCRT(HwDeviceExtension, pVBInfo);
+ XGI_DisableGatingCRT(pVBInfo);
XGI_DisplayOn(xgifb_info, HwDeviceExtension, pVBInfo);
} /* 301 */
else { /* LVDS */
@@ -5467,10 +5390,10 @@ static void XGI_SetCRT1Group(struct xgifb_video_info *xgifb_info,
{
unsigned short RefreshRateTableIndex, temp;
- XGI_SetSeqRegs(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetSeqRegs(pVBInfo);
outb(XGI330_StandTable.MISC, pVBInfo->P3c2);
- XGI_SetCRTCRegs(HwDeviceExtension, pVBInfo);
- XGI_SetATTRegs(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetCRTCRegs(pVBInfo);
+ XGI_SetATTRegs(ModeIdIndex, pVBInfo);
XGI_SetGRCRegs(pVBInfo);
XGI_ClearExt1Regs(pVBInfo);
@@ -5495,13 +5418,12 @@ static void XGI_SetCRT1Group(struct xgifb_video_info *xgifb_info,
ModeIdIndex, pVBInfo);
if (RefreshRateTableIndex != 0xFFFF) {
XGI_SetSync(RefreshRateTableIndex, pVBInfo);
- XGI_SetCRT1CRTC(ModeNo, ModeIdIndex, RefreshRateTableIndex,
+ XGI_SetCRT1CRTC(ModeIdIndex, RefreshRateTableIndex,
pVBInfo, HwDeviceExtension);
- XGI_SetCRT1DE(HwDeviceExtension, ModeNo, ModeIdIndex,
- RefreshRateTableIndex, pVBInfo);
+ XGI_SetCRT1DE(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
XGI_SetCRT1Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex,
HwDeviceExtension, pVBInfo);
- XGI_SetCRT1VCLK(ModeNo, ModeIdIndex, HwDeviceExtension,
+ XGI_SetCRT1VCLK(ModeIdIndex, HwDeviceExtension,
RefreshRateTableIndex, pVBInfo);
}
@@ -5510,30 +5432,28 @@ static void XGI_SetCRT1Group(struct xgifb_video_info *xgifb_info,
if (temp & 0xA0) {
if (HwDeviceExtension->jChipType == XG27)
- XGI_SetXG27CRTC(ModeNo, ModeIdIndex,
- RefreshRateTableIndex, pVBInfo);
+ XGI_SetXG27CRTC(RefreshRateTableIndex, pVBInfo);
else
- XGI_SetXG21CRTC(ModeNo, ModeIdIndex,
- RefreshRateTableIndex, pVBInfo);
+ XGI_SetXG21CRTC(RefreshRateTableIndex, pVBInfo);
XGI_UpdateXG21CRTC(ModeNo, pVBInfo,
RefreshRateTableIndex);
xgifb_set_lcd(HwDeviceExtension->jChipType,
- pVBInfo, RefreshRateTableIndex, ModeNo);
+ pVBInfo, RefreshRateTableIndex);
if (pVBInfo->IF_DEF_LVDS == 1)
xgifb_set_lvds(xgifb_info,
HwDeviceExtension->jChipType,
- ModeNo, ModeIdIndex, pVBInfo);
+ ModeIdIndex, pVBInfo);
}
}
pVBInfo->SetFlag &= (~ProgrammingCRT2);
- XGI_SetCRT1FIFO(ModeNo, HwDeviceExtension, pVBInfo);
- XGI_SetCRT1ModeRegs(HwDeviceExtension, ModeNo, ModeIdIndex,
- RefreshRateTableIndex, pVBInfo);
- XGI_LoadDAC(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetCRT1FIFO(HwDeviceExtension, pVBInfo);
+ XGI_SetCRT1ModeRegs(HwDeviceExtension, ModeIdIndex,
+ RefreshRateTableIndex, pVBInfo);
+ XGI_LoadDAC(pVBInfo);
}
unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
@@ -5568,14 +5488,14 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
xgifb_reg_set(pVBInfo->P3c4, 0x05, 0x86);
if (HwDeviceExtension->jChipType < XG20)
- XGI_UnLockCRT2(HwDeviceExtension, pVBInfo);
+ XGI_UnLockCRT2(pVBInfo);
- XGI_SearchModeID(ModeNo, &ModeIdIndex, pVBInfo);
+ XGI_SearchModeID(ModeNo, &ModeIdIndex);
if (HwDeviceExtension->jChipType < XG20) {
- XGI_GetVBInfo(ModeNo, ModeIdIndex, HwDeviceExtension, pVBInfo);
- XGI_GetTVInfo(ModeNo, ModeIdIndex, pVBInfo);
- XGI_GetLCDInfo(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_GetVBInfo(ModeIdIndex, pVBInfo);
+ XGI_GetTVInfo(ModeIdIndex, pVBInfo);
+ XGI_GetLCDInfo(ModeIdIndex, pVBInfo);
XGI_DisableBridge(xgifb_info, HwDeviceExtension, pVBInfo);
if (pVBInfo->VBInfo & (SetSimuScanMode | XGI_SetCRT2ToLCDA) ||
@@ -5602,15 +5522,14 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
}
}
- XGI_SetCRT2ModeRegs(ModeNo, HwDeviceExtension, pVBInfo);
- XGI_OEM310Setting(ModeNo, ModeIdIndex, pVBInfo); /*0212*/
+ XGI_SetCRT2ModeRegs(pVBInfo);
+ XGI_OEM310Setting(ModeIdIndex, pVBInfo); /*0212*/
XGI_EnableBridge(xgifb_info, HwDeviceExtension, pVBInfo);
} /* !XG20 */
else {
if (pVBInfo->IF_DEF_LVDS == 1)
if (!XGI_XG21CheckLVDSMode(xgifb_info, ModeNo,
- ModeIdIndex,
- pVBInfo))
+ ModeIdIndex))
return 0;
pVBInfo->ModeType = XGI330_EModeIDTable[ModeIdIndex].
@@ -5627,10 +5546,10 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
XGI_DisplayOn(xgifb_info, HwDeviceExtension, pVBInfo);
}
- XGI_UpdateModeInfo(HwDeviceExtension, pVBInfo);
+ XGI_UpdateModeInfo(pVBInfo);
if (HwDeviceExtension->jChipType < XG20)
- XGI_LockCRT2(HwDeviceExtension, pVBInfo);
+ XGI_LockCRT2(pVBInfo);
return 1;
}
diff --git a/drivers/staging/xgifb/vb_setmode.h b/drivers/staging/xgifb/vb_setmode.h
index 2c0a31c8dfd..5301bec6440 100644
--- a/drivers/staging/xgifb/vb_setmode.h
+++ b/drivers/staging/xgifb/vb_setmode.h
@@ -2,10 +2,8 @@
#define _VBSETMODE_
extern void InitTo330Pointer(unsigned char, struct vb_device_info *);
-extern void XGI_UnLockCRT2(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *);
-extern void XGI_LockCRT2(struct xgi_hw_device_info *HwDeviceExtension,
- struct vb_device_info *);
+extern void XGI_UnLockCRT2(struct vb_device_info *);
+extern void XGI_LockCRT2(struct vb_device_info *);
extern void XGI_DisplayOff(struct xgifb_video_info *,
struct xgi_hw_device_info *,
struct vb_device_info *);
@@ -13,11 +11,10 @@ extern void XGI_GetVBType(struct vb_device_info *);
extern void XGI_SenseCRT1(struct vb_device_info *);
extern unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
struct xgi_hw_device_info *HwDeviceExtension,
- unsigned short ModeNo) ;
+ unsigned short ModeNo);
extern unsigned char XGI_SearchModeID(unsigned short ModeNo,
- unsigned short *ModeIdIndex,
- struct vb_device_info *);
+ unsigned short *ModeIdIndex);
extern unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE,
unsigned short ModeNo,
unsigned short ModeIdIndex,
diff --git a/drivers/staging/xillybus/Kconfig b/drivers/staging/xillybus/Kconfig
new file mode 100644
index 00000000000..8a4181f846a
--- /dev/null
+++ b/drivers/staging/xillybus/Kconfig
@@ -0,0 +1,32 @@
+#
+# Xillybus devices
+#
+
+config XILLYBUS
+ tristate "Xillybus generic FPGA interface"
+ depends on PCI || (OF_ADDRESS && OF_IRQ) && m
+ help
+ Xillybus is a generic interface for peripherals designed on
+ programmable logic (FPGA). The driver probes the hardware for
+ its capabilities, and creates device files accordingly.
+
+ If unsure, say N.
+
+if XILLYBUS
+
+config XILLYBUS_PCIE
+ tristate "Xillybus over PCIe"
+ depends on XILLYBUS && PCI
+ help
+ Set to M if you want Xillybus to use PCI Express for communicating
+ with the FPGA.
+
+config XILLYBUS_OF
+ tristate "Xillybus over Device Tree"
+ depends on XILLYBUS && OF_ADDRESS && OF_IRQ
+ help
+ Set to M if you want Xillybus to find its resources from the
+ Open Firmware Flattened Device Tree. If the target is an embedded
+ system, say M.
+
+endif # if XILLYBUS
diff --git a/drivers/staging/xillybus/Makefile b/drivers/staging/xillybus/Makefile
new file mode 100644
index 00000000000..b68b7ebfd38
--- /dev/null
+++ b/drivers/staging/xillybus/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for Xillybus driver
+#
+
+obj-$(CONFIG_XILLYBUS) += xillybus_core.o
+obj-$(CONFIG_XILLYBUS_PCIE) += xillybus_pcie.o
+obj-$(CONFIG_XILLYBUS_OF) += xillybus_of.o
diff --git a/drivers/staging/xillybus/README b/drivers/staging/xillybus/README
new file mode 100644
index 00000000000..d2d848ae316
--- /dev/null
+++ b/drivers/staging/xillybus/README
@@ -0,0 +1,403 @@
+
+ ==========================================
+ Xillybus driver for generic FPGA interface
+ ==========================================
+
+Author: Eli Billauer, Xillybus Ltd. (http://xillybus.com)
+Email: eli.billauer@gmail.com or as advertised on Xillybus' site.
+
+Contents:
+
+ - Introduction
+ -- Background
+ -- Xillybus Overview
+
+ - Usage
+ -- User interface
+ -- Synchronization
+ -- Seekable pipes
+
+- Internals
+ -- Source code organization
+ -- Pipe attributes
+ -- Host never reads from the FPGA
+ -- Channels, pipes, and the message channel
+ -- Data streaming
+ -- Data granularity
+ -- Probing
+ -- Buffer allocation
+ -- Memory management
+ -- The "nonempty" message (supporting poll)
+
+
+INTRODUCTION
+============
+
+Background
+----------
+
+An FPGA (Field Programmable Gate Array) is a piece of logic hardware, which
+can be programmed to become virtually anything that is usually found as a
+dedicated chipset: For instance, a display adapter, network interface card,
+or even a processor with its peripherals. FPGAs are the LEGO of hardware:
+Based upon certain building blocks, you make your own toys the way you like
+them. It's usually pointless to reimplement something that is already
+available on the market as a chipset, so FPGAs are mostly used when some
+special functionality is needed, and the production volume is relatively low
+(hence not justifying the development of an ASIC).
+
+The challenge with FPGAs is that everything is implemented at a very low
+level, even lower than assembly language. In order to allow FPGA designers to
+focus on their specific project, and not reinvent the wheel over and over
+again, pre-designed building blocks, IP cores, are often used. These are the
+FPGA parallels of library functions. IP cores may implement certain
+mathematical functions, a functional unit (e.g. a USB interface), an entire
+processor (e.g. ARM) or anything that might come handy. Think of them as a
+building block, with electrical wires dangling on the sides for connection to
+other blocks.
+
+One of the daunting tasks in FPGA design is communicating with a fullblown
+operating system (actually, with the processor running it): Implementing the
+low-level bus protocol and the somewhat higher-level interface with the host
+(registers, interrupts, DMA etc.) is a project in itself. When the FPGA's
+function is a well-known one (e.g. a video adapter card, or a NIC), it can
+make sense to design the FPGA's interface logic specifically for the project.
+A special driver is then written to present the FPGA as a well-known interface
+to the kernel and/or user space. In that case, there is no reason to treat the
+FPGA differently than any device on the bus.
+
+It's however common that the desired data communication doesn't fit any well-
+known peripheral function. Also, the effort of designing an elegant
+abstraction for the data exchange is often considered too big. In those cases,
+a quicker and possibly less elegant solution is sought: The driver is
+effectively written as a user space program, leaving the kernel space part
+with just elementary data transport. This still requires designing some
+interface logic for the FPGA, and write a simple ad-hoc driver for the kernel.
+
+Xillybus Overview
+-----------------
+
+Xillybus is an IP core and a Linux driver. Together, they form a kit for
+elementary data transport between an FPGA and the host, providing pipe-like
+data streams with a straightforward user interface. It's intended as a low-
+effort solution for mixed FPGA-host projects, for which it makes sense to
+have the project-specific part of the driver running in a user-space program.
+
+Since the communication requirements may vary significantly from one FPGA
+project to another (the number of data pipes needed in each direction and
+their attributes), there isn't one specific chunk of logic being the Xillybus
+IP core. Rather, the IP core is configured and built based upon a
+specification given by its end user.
+
+Xillybus presents independent data streams, which resemble pipes or TCP/IP
+communication to the user. At the host side, a character device file is used
+just like any pipe file. On the FPGA side, hardware FIFOs are used to stream
+the data. This is contrary to a common method of communicating through fixed-
+sized buffers (even though such buffers are used by Xillybus under the hood).
+There may be more than a hundred of these streams on a single IP core, but
+also no more than one, depending on the configuration.
+
+In order to ease the deployment of the Xillybus IP core, it contains a simple
+data structure which completely defines the core's configuration. The Linux
+driver fetches this data structure during its initialization process, and sets
+up the DMA buffers and character devices accordingly. As a result, a single
+driver is used to work out of the box with any Xillybus IP core.
+
+The data structure just mentioned should not be confused with PCI's
+configuration space or the Flattened Device Tree.
+
+USAGE
+=====
+
+User interface
+--------------
+
+On the host, all interface with Xillybus is done through /dev/xillybus_*
+device files, which are generated automatically as the drivers loads. The
+names of these files depend on the IP core that is loaded in the FPGA (see
+Probing below). To communicate with the FPGA, open the device file that
+corresponds to the hardware FIFO you want to send data or receive data from,
+and use plain write() or read() calls, just like with a regular pipe. In
+particular, it makes perfect sense to go:
+
+$ cat mydata > /dev/xillybus_thisfifo
+
+$ cat /dev/xillybus_thatfifo > hisdata
+
+possibly pressing CTRL-C as some stage, even though the xillybus_* pipes have
+the capability to send an EOF (but may not use it).
+
+The driver and hardware are designed to behave sensibly as pipes, including:
+
+* Supporting non-blocking I/O (by setting O_NONBLOCK on open() ).
+
+* Supporting poll() and select().
+
+* Being bandwidth efficient under load (using DMA) but also handle small
+ pieces of data sent across (like TCP/IP) by autoflushing.
+
+A device file can be read only, write only or bidirectional. Bidirectional
+device files are treated like two independent pipes (except for sharing a
+"channel" structure in the implementation code).
+
+Synchronization
+---------------
+
+Xillybus pipes are configured (on the IP core) to be either synchronous or
+asynchronous. For a synchronous pipe, write() returns successfully only after
+some data has been submitted and acknowledged by the FPGA. This slows down
+bulk data transfers, and is nearly impossible for use with streams that
+require data at a constant rate: There is no data transmitted to the FPGA
+between write() calls, in particular when the process loses the CPU.
+
+When a pipe is configured asynchronous, write() returns if there was enough
+room in the buffers to store any of the data in the buffers.
+
+For FPGA to host pipes, asynchronous pipes allow data transfer from the FPGA
+as soon as the respective device file is opened, regardless of if the data
+has been requested by a read() call. On synchronous pipes, only the amount
+of data requested by a read() call is transmitted.
+
+In summary, for synchronous pipes, data between the host and FPGA is
+transmitted only to satisfy the read() or write() call currently handled
+by the driver, and those calls wait for the transmission to complete before
+returning.
+
+Note that the synchronization attribute has nothing to do with the possibility
+that read() or write() completes less bytes than requested. There is a
+separate configuration flag ("allowpartial") that determines whether such a
+partial completion is allowed.
+
+Seekable pipes
+--------------
+
+A synchronous pipe can be configured to have the stream's position exposed
+to the user logic at the FPGA. Such a pipe is also seekable on the host API.
+With this feature, a memory or register interface can be attached on the
+FPGA side to the seekable stream. Reading or writing to a certain address in
+the attached memory is done by seeking to the desired address, and calling
+read() or write() as required.
+
+
+INTERNALS
+=========
+
+Source code organization
+------------------------
+
+The Xillybus driver consists of a core module, xillybus_core.c, and modules
+that depend on the specific bus interface (xillybus_of.c and xillybus_pcie.c).
+
+The bus specific modules are those probed when a suitable device is found by
+the kernel. Since the DMA mapping and synchronization functions, which are bus
+dependent by their nature, are used by the core module, a
+xilly_endpoint_hardware structure is passed to the core module on
+initialization. This structure is populated with pointers to wrapper functions
+which execute the DMA-related operations on the bus.
+
+Pipe attributes
+---------------
+
+Each pipe has a number of attributes which are set when the FPGA component
+(IP core) is built. They are fetched from the IDT (the data structure which
+defines the core's configuration, see Probing below) by xilly_setupchannels()
+in xillybus_core.c as follows:
+
+* is_writebuf: The pipe's direction. A non-zero value means it's an FPGA to
+ host pipe (the FPGA "writes").
+
+* channelnum: The pipe's identification number in communication between the
+ host and FPGA.
+
+* format: The underlying data width. See Data Granularity below.
+
+* allowpartial: A non-zero value means that a read() or write() (whichever
+ applies) may return with less than the requested number of bytes. The common
+ choice is a non-zero value, to match standard UNIX behavior.
+
+* synchronous: A non-zero value means that the pipe is synchronous. See
+ Syncronization above.
+
+* bufsize: Each DMA buffer's size. Always a power of two.
+
+* bufnum: The number of buffers allocated for this pipe. Always a power of two.
+
+* exclusive_open: A non-zero value forces exclusive opening of the associated
+ device file. If the device file is bidirectional, and already opened only in
+ one direction, the opposite direction may be opened once.
+
+* seekable: A non-zero value indicates that the pipe is seekable. See
+ Seekable pipes above.
+
+* supports_nonempty: A non-zero value (which is typical) indicates that the
+ hardware will send the messages that are necessary to support select() and
+ poll() for this pipe.
+
+Host never reads from the FPGA
+------------------------------
+
+Even though PCI Express is hotpluggable in general, a typical motherboard
+doesn't expect a card to go away all of the sudden. But since the PCIe card
+is based upon reprogrammable logic, a sudden disappearance from the bus is
+quite likely as a result of an accidental reprogramming of the FPGA while the
+host is up. In practice, nothing happens immediately in such a situation. But
+if the host attempts to read from an address that is mapped to the PCI Express
+device, that leads to an immediate freeze of the system on some motherboards,
+even though the PCIe standard requires a graceful recovery.
+
+In order to avoid these freezes, the Xillybus driver refrains completely from
+reading from the device's register space. All communication from the FPGA to
+the host is done through DMA. In particular, the Interrupt Service Routine
+doesn't follow the common practice of checking a status register when it's
+invoked. Rather, the FPGA prepares a small buffer which contains short
+messages, which inform the host what the interrupt was about.
+
+This mechanism is used on non-PCIe buses as well for the sake of uniformity.
+
+
+Channels, pipes, and the message channel
+----------------------------------------
+
+Each of the (possibly bidirectional) pipes presented to the user is allocated
+a data channel between the FPGA and the host. The distinction between channels
+and pipes is necessary only because of channel 0, which is used for interrupt-
+related messages from the FPGA, and has no pipe attached to it.
+
+Data streaming
+--------------
+
+Even though a non-segmented data stream is presented to the user at both
+sides, the implementation relies on a set of DMA buffers which is allocated
+for each channel. For the sake of illustration, let's take the FPGA to host
+direction: As data streams into the respective channel's interface in the
+FPGA, the Xillybus IP core writes it to one of the DMA buffers. When the
+buffer is full, the FPGA informs the host about that (appending a
+XILLYMSG_OPCODE_RELEASEBUF message channel 0 and sending an interrupt if
+necessary). The host responds by making the data available for reading through
+the character device. When all data has been read, the host writes on the
+the FPGA's buffer control register, allowing the buffer's overwriting. Flow
+control mechanisms exist on both sides to prevent underflows and overflows.
+
+This is not good enough for creating a TCP/IP-like stream: If the data flow
+stops momentarily before a DMA buffer is filled, the intuitive expectation is
+that the partial data in buffer will arrive anyhow, despite the buffer not
+being completed. This is implemented by adding a field in the
+XILLYMSG_OPCODE_RELEASEBUF message, through which the FPGA informs not just
+which buffer is submitted, but how much data it contains.
+
+But the FPGA will submit a partially filled buffer only if directed to do so
+by the host. This situation occurs when the read() method has been blocking
+for XILLY_RX_TIMEOUT jiffies (currently 10 ms), after which the host commands
+the FPGA to submit a DMA buffer as soon as it can. This timeout mechanism
+balances between bus bandwidth efficiency (preventing a lot of partially
+filled buffers being sent) and a latency held fairly low for tails of data.
+
+A similar setting is used in the host to FPGA direction. The handling of
+partial DMA buffers is somewhat different, though. The user can tell the
+driver to submit all data it has in the buffers to the FPGA, by issuing a
+write() with the byte count set to zero. This is similar to a flush request,
+but it doesn't block. There is also an autoflushing mechanism, which triggers
+an equivalent flush roughly XILLY_RX_TIMEOUT jiffies after the last write().
+This allows the user to be oblivious about the underlying buffering mechanism
+and yet enjoy a stream-like interface.
+
+Note that the issue of partial buffer flushing is irrelevant for pipes having
+the "synchronous" attribute nonzero, since synchronous pipes don't allow data
+to lay around in the DMA buffers between read() and write() anyhow.
+
+Data granularity
+----------------
+
+The data arrives or is sent at the FPGA as 8, 16 or 32 bit wide words, as
+configured by the "format" attribute. Whenever possible, the driver attempts
+to hide this when the pipe is accessed differently from its natural alignment.
+For example, reading single bytes from a pipe with 32 bit granularity works
+with no issues. Writing single bytes to pipes with 16 or 32 bit granularity
+will also work, but the driver can't send partially completed words to the
+FPGA, so the transmission of up to one word may be held until it's fully
+occupied with user data.
+
+This somewhat complicates the handling of host to FPGA streams, because
+when a buffer is flushed, it may contain up to 3 bytes don't form a word in
+the FPGA, and hence can't be sent. To prevent loss of data, these leftover
+bytes need to be moved to the next buffer. The parts in xillybus_core.c
+that mention "leftovers" in some way are related to this complication.
+
+Probing
+-------
+
+As mentioned earlier, the number of pipes that are created when the driver
+loads and their attributes depend on the Xillybus IP core in the FPGA. During
+the driver's initialization, a blob containing configuration info, the
+Interface Description Table (IDT), is sent from the FPGA to the host. The
+bootstrap process is done in three phases:
+
+1. Acquire the length of the IDT, so a buffer can be allocated for it. This
+ is done by sending a quiesce command to the device, since the acknowledge
+ for this command contains the IDT's buffer length.
+
+2. Acquire the IDT itself.
+
+3. Create the interfaces according to the IDT.
+
+Buffer allocation
+-----------------
+
+In order to simplify the logic that prevents illegal boundary crossings of
+PCIe packets, the following rule applies: If a buffer is smaller than 4kB,
+it must not cross a 4kB boundary. Otherwise, it must be 4kB aligned. The
+xilly_setupchannels() functions allocates these buffers by requesting whole
+pages from the kernel, and diving them into DMA buffers as necessary. Since
+all buffers' sizes are powers of two, it's possible to pack any set of such
+buffers, with a maximal waste of one page of memory.
+
+All buffers are allocated when the driver is loaded. This is necessary,
+since large continuous physical memory segments are sometimes requested,
+which are more likely to be available when the system is freshly booted.
+
+The allocation of buffer memory takes place in the same order they appear in
+the IDT. The driver relies on a rule that the pipes are sorted with decreasing
+buffer size in the IDT. If a requested buffer is larger or equal to a page,
+the necessary number of pages is requested from the kernel, and these are
+used for this buffer. If the requested buffer is smaller than a page, one
+single page is requested from the kernel, and that page is partially used.
+Or, if there already is a partially used page at hand, the buffer is packed
+into that page. It can be shown that all pages requested from the kernel
+(except possibly for the last) are 100% utilized this way.
+
+Memory management
+-----------------
+
+The tricky part about the buffer allocation procedure described above is
+freeing and unmapping the buffers, in particular if something goes wrong in
+the middle, and the allocations need to be rolled back. The three-stage
+probing procedure makes this even more crucial, since temporary buffers are
+set up and mapped in the first of its two stages.
+
+To keep the code clean from complicated and bug-prone memory release routines,
+there are special routines for allocating memory. For example, instead of
+calling kzalloc, there's
+
+void *xilly_malloc(struct xilly_cleanup *mem, size_t size)
+
+which effectively allocates a zeroed buffer of size "size". Its first
+argument, "mem", is where this allocation is enlisted, so that it's released
+when xillybus_do_cleanup() is called with the same "mem" structure.
+
+Two other functions enlist allocations in this structure: xilly_pagealloc()
+for page allocations and xilly_map_single_*() for DMA mapping.
+
+The "nonempty" message (supporting poll)
+---------------------------------------
+
+In order to support the "poll" method (and hence select() ), there is a small
+catch regarding the FPGA to host direction: The FPGA may have filled a DMA
+buffer with some data, but not submitted that buffer. If the host waited for
+the buffer's submission by the FPGA, there would be a possibility that the
+FPGA side has sent data, but a select() call would still block, because the
+host has not received any notification about this. This is solved with
+XILLYMSG_OPCODE_NONEMPTY messages sent by the FPGA when a channel goes from
+completely empty to containing some data.
+
+These messages are used only to support poll() and select(). The IP core can
+be configured not to send them for a slight reduction of bandwidth.
diff --git a/drivers/staging/xillybus/TODO b/drivers/staging/xillybus/TODO
new file mode 100644
index 00000000000..95cfe2f62fc
--- /dev/null
+++ b/drivers/staging/xillybus/TODO
@@ -0,0 +1,5 @@
+TODO:
+- have the driver reviewed
+
+Please send any patches and/or comments to Eli Billauer,
+<eli.billauer@gmail.com>.
diff --git a/drivers/staging/xillybus/xillybus.h b/drivers/staging/xillybus/xillybus.h
new file mode 100644
index 00000000000..e5e91d61288
--- /dev/null
+++ b/drivers/staging/xillybus/xillybus.h
@@ -0,0 +1,182 @@
+/*
+ * linux/drivers/misc/xillybus.h
+ *
+ * Copyright 2011 Xillybus Ltd, http://xillybus.com
+ *
+ * Header file for the Xillybus FPGA/host framework.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#ifndef __XILLYBUS_H
+#define __XILLYBUS_H
+
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/cdev.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+struct xilly_endpoint_hardware;
+
+struct xilly_page {
+ struct list_head node;
+ unsigned long addr;
+ unsigned int order;
+};
+
+struct xilly_dma {
+ struct list_head node;
+ struct pci_dev *pdev;
+ struct device *dev;
+ dma_addr_t dma_addr;
+ size_t size;
+ int direction;
+};
+
+struct xilly_buffer {
+ void *addr;
+ dma_addr_t dma_addr;
+ int end_offset; /* Counting elements, not bytes */
+};
+
+struct xilly_cleanup {
+ struct list_head to_kfree;
+ struct list_head to_pagefree;
+ struct list_head to_unmap;
+};
+
+struct xilly_idt_handle {
+ unsigned char *chandesc;
+ unsigned char *idt;
+ int entries;
+};
+
+/*
+ * Read-write confusion: wr_* and rd_* notation sticks to FPGA view, so
+ * wr_* buffers are those consumed by read(), since the FPGA writes to them
+ * and vice versa.
+ */
+
+struct xilly_channel {
+ struct xilly_endpoint *endpoint;
+ int chan_num;
+ int log2_element_size;
+ int seekable;
+
+ struct xilly_buffer **wr_buffers; /* FPGA writes, driver reads! */
+ int num_wr_buffers;
+ unsigned int wr_buf_size; /* In bytes */
+ int wr_fpga_buf_idx;
+ int wr_host_buf_idx;
+ int wr_host_buf_pos;
+ int wr_empty;
+ int wr_ready; /* Significant only when wr_empty == 1 */
+ int wr_sleepy;
+ int wr_eof;
+ int wr_hangup;
+ spinlock_t wr_spinlock;
+ struct mutex wr_mutex;
+ wait_queue_head_t wr_wait;
+ wait_queue_head_t wr_ready_wait;
+ int wr_ref_count;
+ int wr_synchronous;
+ int wr_allow_partial;
+ int wr_exclusive_open;
+ int wr_supports_nonempty;
+
+ struct xilly_buffer **rd_buffers; /* FPGA reads, driver writes! */
+ int num_rd_buffers;
+ unsigned int rd_buf_size; /* In bytes */
+ int rd_fpga_buf_idx;
+ int rd_host_buf_pos;
+ int rd_host_buf_idx;
+ int rd_full;
+ spinlock_t rd_spinlock;
+ struct mutex rd_mutex;
+ wait_queue_head_t rd_wait;
+ int rd_ref_count;
+ int rd_allow_partial;
+ int rd_synchronous;
+ int rd_exclusive_open;
+ struct delayed_work rd_workitem;
+ unsigned char rd_leftovers[4];
+};
+
+struct xilly_endpoint {
+ /*
+ * One of pdev and dev is always NULL, and the other is a valid
+ * pointer, depending on the type of device
+ */
+ struct pci_dev *pdev;
+ struct device *dev;
+ struct resource res; /* OF devices only */
+ struct xilly_endpoint_hardware *ephw;
+
+ struct list_head ep_list;
+ int dma_using_dac; /* =1 if 64-bit DMA is used, =0 otherwise. */
+ __iomem u32 *registers;
+ int fatal_error;
+
+ struct mutex register_mutex;
+ wait_queue_head_t ep_wait;
+
+ /* List of memory allocations, to make release easy */
+ struct xilly_cleanup cleanup;
+
+ /* Channels and message handling */
+ struct cdev cdev;
+
+ int major;
+ int lowest_minor; /* Highest minor = lowest_minor + num_channels - 1 */
+
+ int num_channels; /* EXCLUDING message buffer */
+ struct xilly_channel **channels;
+ int msg_counter;
+ int failed_messages;
+ int idtlen;
+
+ u32 *msgbuf_addr;
+ dma_addr_t msgbuf_dma_addr;
+ unsigned int msg_buf_size;
+};
+
+struct xilly_endpoint_hardware {
+ struct module *owner;
+ void (*hw_sync_sgl_for_cpu)(struct xilly_endpoint *,
+ dma_addr_t,
+ size_t,
+ int);
+ void (*hw_sync_sgl_for_device)(struct xilly_endpoint *,
+ dma_addr_t,
+ size_t,
+ int);
+ dma_addr_t (*map_single)(struct xilly_cleanup *,
+ struct xilly_endpoint *,
+ void *,
+ size_t,
+ int);
+ void (*unmap_single)(struct xilly_dma *entry);
+};
+
+irqreturn_t xillybus_isr(int irq, void *data);
+
+void xillybus_do_cleanup(struct xilly_cleanup *mem,
+ struct xilly_endpoint *endpoint);
+
+struct xilly_endpoint *xillybus_init_endpoint(struct pci_dev *pdev,
+ struct device *dev,
+ struct xilly_endpoint_hardware
+ *ephw);
+
+int xillybus_endpoint_discovery(struct xilly_endpoint *endpoint);
+
+void xillybus_endpoint_remove(struct xilly_endpoint *endpoint);
+
+#endif /* __XILLYBUS_H */
diff --git a/drivers/staging/xillybus/xillybus_core.c b/drivers/staging/xillybus/xillybus_core.c
new file mode 100644
index 00000000000..efc56987a60
--- /dev/null
+++ b/drivers/staging/xillybus/xillybus_core.c
@@ -0,0 +1,2345 @@
+/*
+ * linux/drivers/misc/xillybus_core.c
+ *
+ * Copyright 2011 Xillybus Ltd, http://xillybus.com
+ *
+ * Driver for the Xillybus FPGA/host framework.
+ *
+ * This driver interfaces with a special IP core in an FPGA, setting up
+ * a pipe between a hardware FIFO in the programmable logic and a device
+ * file in the host. The number of such pipes and their attributes are
+ * set up on the logic. This driver detects these automatically and
+ * creates the device files accordingly.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/crc32.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include "xillybus.h"
+
+MODULE_DESCRIPTION("Xillybus core functions");
+MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
+MODULE_VERSION("1.07");
+MODULE_ALIAS("xillybus_core");
+MODULE_LICENSE("GPL v2");
+
+/* General timeout is 100 ms, rx timeout is 10 ms */
+#define XILLY_RX_TIMEOUT (10*HZ/1000)
+#define XILLY_TIMEOUT (100*HZ/1000)
+
+#define fpga_msg_ctrl_reg 0x0002
+#define fpga_dma_control_reg 0x0008
+#define fpga_dma_bufno_reg 0x0009
+#define fpga_dma_bufaddr_lowaddr_reg 0x000a
+#define fpga_dma_bufaddr_highaddr_reg 0x000b
+#define fpga_buf_ctrl_reg 0x000c
+#define fpga_buf_offset_reg 0x000d
+#define fpga_endian_reg 0x0010
+
+#define XILLYMSG_OPCODE_RELEASEBUF 1
+#define XILLYMSG_OPCODE_QUIESCEACK 2
+#define XILLYMSG_OPCODE_FIFOEOF 3
+#define XILLYMSG_OPCODE_FATAL_ERROR 4
+#define XILLYMSG_OPCODE_NONEMPTY 5
+
+static const char xillyname[] = "xillybus";
+
+static struct class *xillybus_class;
+
+/*
+ * ep_list_lock is the last lock to be taken; No other lock requests are
+ * allowed while holding it. It merely protects list_of_endpoints, and not
+ * the endpoints listed in it.
+ */
+
+static LIST_HEAD(list_of_endpoints);
+static struct mutex ep_list_lock;
+static struct workqueue_struct *xillybus_wq;
+
+/*
+ * Locking scheme: Mutexes protect invocations of character device methods.
+ * If both locks are taken, wr_mutex is taken first, rd_mutex second.
+ *
+ * wr_spinlock protects wr_*_buf_idx, wr_empty, wr_sleepy, wr_ready and the
+ * buffers' end_offset fields against changes made by IRQ handler (and in
+ * theory, other file request handlers, but the mutex handles that). Nothing
+ * else.
+ * They are held for short direct memory manipulations. Needless to say,
+ * no mutex locking is allowed when a spinlock is held.
+ *
+ * rd_spinlock does the same with rd_*_buf_idx, rd_empty and end_offset.
+ *
+ * register_mutex is endpoint-specific, and is held when non-atomic
+ * register operations are performed. wr_mutex and rd_mutex may be
+ * held when register_mutex is taken, but none of the spinlocks. Note that
+ * register_mutex doesn't protect against sporadic buf_ctrl_reg writes
+ * which are unrelated to buf_offset_reg, since they are harmless.
+ *
+ * Blocking on the wait queues is allowed with mutexes held, but not with
+ * spinlocks.
+ *
+ * Only interruptible blocking is allowed on mutexes and wait queues.
+ *
+ * All in all, the locking order goes (with skips allowed, of course):
+ * wr_mutex -> rd_mutex -> register_mutex -> wr_spinlock -> rd_spinlock
+ */
+
+static void malformed_message(u32 *buf)
+{
+ int opcode;
+ int msg_channel, msg_bufno, msg_data, msg_dir;
+
+ opcode = (buf[0] >> 24) & 0xff;
+ msg_dir = buf[0] & 1;
+ msg_channel = (buf[0] >> 1) & 0x7ff;
+ msg_bufno = (buf[0] >> 12) & 0x3ff;
+ msg_data = buf[1] & 0xfffffff;
+
+ pr_warn("xillybus: Malformed message (skipping): "
+ "opcode=%d, channel=%03x, dir=%d, bufno=%03x, data=%07x\n",
+ opcode, msg_channel, msg_dir, msg_bufno, msg_data);
+}
+
+/*
+ * xillybus_isr assumes the interrupt is allocated exclusively to it,
+ * which is the natural case MSI and several other hardware-oriented
+ * interrupts. Sharing is not allowed.
+ */
+
+irqreturn_t xillybus_isr(int irq, void *data)
+{
+ struct xilly_endpoint *ep = data;
+ u32 *buf;
+ unsigned int buf_size;
+ int i;
+ int opcode;
+ unsigned int msg_channel, msg_bufno, msg_data, msg_dir;
+ struct xilly_channel *channel;
+
+ /*
+ * The endpoint structure is altered during periods when it's
+ * guaranteed no interrupt will occur, but in theory, the cache
+ * lines may not be updated. So a memory barrier is issued.
+ */
+
+ smp_rmb();
+
+ buf = ep->msgbuf_addr;
+ buf_size = ep->msg_buf_size/sizeof(u32);
+
+
+ ep->ephw->hw_sync_sgl_for_cpu(ep,
+ ep->msgbuf_dma_addr,
+ ep->msg_buf_size,
+ DMA_FROM_DEVICE);
+
+ for (i = 0; i < buf_size; i += 2)
+ if (((buf[i+1] >> 28) & 0xf) != ep->msg_counter) {
+ malformed_message(&buf[i]);
+ pr_warn("xillybus: Sending a NACK on "
+ "counter %x (instead of %x) on entry %d\n",
+ ((buf[i+1] >> 28) & 0xf),
+ ep->msg_counter,
+ i/2);
+
+ if (++ep->failed_messages > 10)
+ pr_err("xillybus: Lost sync with "
+ "interrupt messages. Stopping.\n");
+ else {
+ ep->ephw->hw_sync_sgl_for_device(
+ ep,
+ ep->msgbuf_dma_addr,
+ ep->msg_buf_size,
+ DMA_FROM_DEVICE);
+
+ iowrite32(0x01, /* Message NACK */
+ &ep->registers[fpga_msg_ctrl_reg]);
+ }
+ return IRQ_HANDLED;
+ } else if (buf[i] & (1 << 22)) /* Last message */
+ break;
+
+ if (i >= buf_size) {
+ pr_err("xillybus: Bad interrupt message. Stopping.\n");
+ return IRQ_HANDLED;
+ }
+
+ buf_size = i;
+
+ for (i = 0; i <= buf_size; i += 2) { /* Scan through messages */
+ opcode = (buf[i] >> 24) & 0xff;
+
+ msg_dir = buf[i] & 1;
+ msg_channel = (buf[i] >> 1) & 0x7ff;
+ msg_bufno = (buf[i] >> 12) & 0x3ff;
+ msg_data = buf[i+1] & 0xfffffff;
+
+ switch (opcode) {
+ case XILLYMSG_OPCODE_RELEASEBUF:
+
+ if ((msg_channel > ep->num_channels) ||
+ (msg_channel == 0)) {
+ malformed_message(&buf[i]);
+ break;
+ }
+
+ channel = ep->channels[msg_channel];
+
+ if (msg_dir) { /* Write channel */
+ if (msg_bufno >= channel->num_wr_buffers) {
+ malformed_message(&buf[i]);
+ break;
+ }
+ spin_lock(&channel->wr_spinlock);
+ channel->wr_buffers[msg_bufno]->end_offset =
+ msg_data;
+ channel->wr_fpga_buf_idx = msg_bufno;
+ channel->wr_empty = 0;
+ channel->wr_sleepy = 0;
+ spin_unlock(&channel->wr_spinlock);
+
+ wake_up_interruptible(&channel->wr_wait);
+
+ } else {
+ /* Read channel */
+
+ if (msg_bufno >= channel->num_rd_buffers) {
+ malformed_message(&buf[i]);
+ break;
+ }
+
+ spin_lock(&channel->rd_spinlock);
+ channel->rd_fpga_buf_idx = msg_bufno;
+ channel->rd_full = 0;
+ spin_unlock(&channel->rd_spinlock);
+
+ wake_up_interruptible(&channel->rd_wait);
+ if (!channel->rd_synchronous)
+ queue_delayed_work(
+ xillybus_wq,
+ &channel->rd_workitem,
+ XILLY_RX_TIMEOUT);
+ }
+
+ break;
+ case XILLYMSG_OPCODE_NONEMPTY:
+ if ((msg_channel > ep->num_channels) ||
+ (msg_channel == 0) || (!msg_dir) ||
+ !ep->channels[msg_channel]->wr_supports_nonempty) {
+ malformed_message(&buf[i]);
+ break;
+ }
+
+ channel = ep->channels[msg_channel];
+
+ if (msg_bufno >= channel->num_wr_buffers) {
+ malformed_message(&buf[i]);
+ break;
+ }
+ spin_lock(&channel->wr_spinlock);
+ if (msg_bufno == channel->wr_host_buf_idx)
+ channel->wr_ready = 1;
+ spin_unlock(&channel->wr_spinlock);
+
+ wake_up_interruptible(&channel->wr_ready_wait);
+
+ break;
+ case XILLYMSG_OPCODE_QUIESCEACK:
+ ep->idtlen = msg_data;
+ wake_up_interruptible(&ep->ep_wait);
+
+ break;
+ case XILLYMSG_OPCODE_FIFOEOF:
+ channel = ep->channels[msg_channel];
+ spin_lock(&channel->wr_spinlock);
+ channel->wr_eof = msg_bufno;
+ channel->wr_sleepy = 0;
+
+ channel->wr_hangup = channel->wr_empty &&
+ (channel->wr_host_buf_idx == msg_bufno);
+
+ spin_unlock(&channel->wr_spinlock);
+
+ wake_up_interruptible(&channel->wr_wait);
+
+ break;
+ case XILLYMSG_OPCODE_FATAL_ERROR:
+ ep->fatal_error = 1;
+ wake_up_interruptible(&ep->ep_wait); /* For select() */
+ pr_err("xillybus: FPGA reported a fatal "
+ "error. This means that the low-level "
+ "communication with the device has failed. "
+ "This hardware problem is most likely "
+ "unrelated to xillybus (neither kernel "
+ "module nor FPGA core), but reports are "
+ "still welcome. All I/O is aborted.\n");
+ break;
+ default:
+ malformed_message(&buf[i]);
+ break;
+ }
+ }
+
+ ep->ephw->hw_sync_sgl_for_device(ep,
+ ep->msgbuf_dma_addr,
+ ep->msg_buf_size,
+ DMA_FROM_DEVICE);
+
+ ep->msg_counter = (ep->msg_counter + 1) & 0xf;
+ ep->failed_messages = 0;
+ iowrite32(0x03, &ep->registers[fpga_msg_ctrl_reg]); /* Message ACK */
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(xillybus_isr);
+
+/*
+ * A few trivial memory management functions.
+ * NOTE: These functions are used only on probe and remove, and therefore
+ * no locks are applied!
+ */
+
+void xillybus_do_cleanup(struct xilly_cleanup *mem,
+ struct xilly_endpoint *endpoint)
+{
+ struct list_head *this, *next;
+
+ list_for_each_safe(this, next, &mem->to_unmap) {
+ struct xilly_dma *entry =
+ list_entry(this, struct xilly_dma, node);
+
+ endpoint->ephw->unmap_single(entry);
+ kfree(entry);
+ }
+
+ INIT_LIST_HEAD(&mem->to_unmap);
+
+ list_for_each_safe(this, next, &mem->to_kfree)
+ kfree(this);
+
+ INIT_LIST_HEAD(&mem->to_kfree);
+
+ list_for_each_safe(this, next, &mem->to_pagefree) {
+ struct xilly_page *entry =
+ list_entry(this, struct xilly_page, node);
+
+ free_pages(entry->addr, entry->order);
+ kfree(entry);
+ }
+ INIT_LIST_HEAD(&mem->to_pagefree);
+}
+EXPORT_SYMBOL(xillybus_do_cleanup);
+
+static void *xilly_malloc(struct xilly_cleanup *mem, size_t size)
+{
+ void *ptr;
+
+ ptr = kzalloc(sizeof(struct list_head) + size, GFP_KERNEL);
+
+ if (!ptr)
+ return ptr;
+
+ list_add_tail((struct list_head *) ptr, &mem->to_kfree);
+
+ return ptr + sizeof(struct list_head);
+}
+
+static unsigned long xilly_pagealloc(struct xilly_cleanup *mem,
+ unsigned long order)
+{
+ unsigned long addr;
+ struct xilly_page *this;
+
+ this = kmalloc(sizeof(struct xilly_page), GFP_KERNEL);
+ if (!this)
+ return 0;
+
+ addr = __get_free_pages(GFP_KERNEL | __GFP_DMA32 | __GFP_ZERO, order);
+
+ if (!addr) {
+ kfree(this);
+ return 0;
+ }
+
+ this->addr = addr;
+ this->order = order;
+
+ list_add_tail(&this->node, &mem->to_pagefree);
+
+ return addr;
+}
+
+
+static void xillybus_autoflush(struct work_struct *work);
+
+static int xilly_setupchannels(struct xilly_endpoint *ep,
+ struct xilly_cleanup *mem,
+ unsigned char *chandesc,
+ int entries
+ )
+{
+ int i, entry, wr_nbuffer, rd_nbuffer;
+ struct xilly_channel *channel;
+ int channelnum, bufnum, bufsize, format, is_writebuf;
+ int bytebufsize;
+ int synchronous, allowpartial, exclusive_open, seekable;
+ int supports_nonempty;
+ void *wr_salami = NULL;
+ void *rd_salami = NULL;
+ int left_of_wr_salami = 0;
+ int left_of_rd_salami = 0;
+ dma_addr_t dma_addr;
+ int msg_buf_done = 0;
+
+ struct xilly_buffer *this_buffer = NULL; /* Init to silence warning */
+
+ channel = xilly_malloc(mem, ep->num_channels *
+ sizeof(struct xilly_channel));
+
+ if (!channel)
+ goto memfail;
+
+ ep->channels = xilly_malloc(mem, (ep->num_channels + 1) *
+ sizeof(struct xilly_channel *));
+
+ if (!ep->channels)
+ goto memfail;
+
+ ep->channels[0] = NULL; /* Channel 0 is message buf. */
+
+ /* Initialize all channels with defaults */
+
+ for (i = 1; i <= ep->num_channels; i++) {
+ channel->wr_buffers = NULL;
+ channel->rd_buffers = NULL;
+ channel->num_wr_buffers = 0;
+ channel->num_rd_buffers = 0;
+ channel->wr_fpga_buf_idx = -1;
+ channel->wr_host_buf_idx = 0;
+ channel->wr_host_buf_pos = 0;
+ channel->wr_empty = 1;
+ channel->wr_ready = 0;
+ channel->wr_sleepy = 1;
+ channel->rd_fpga_buf_idx = 0;
+ channel->rd_host_buf_idx = 0;
+ channel->rd_host_buf_pos = 0;
+ channel->rd_full = 0;
+ channel->wr_ref_count = 0;
+ channel->rd_ref_count = 0;
+
+ spin_lock_init(&channel->wr_spinlock);
+ spin_lock_init(&channel->rd_spinlock);
+ mutex_init(&channel->wr_mutex);
+ mutex_init(&channel->rd_mutex);
+ init_waitqueue_head(&channel->rd_wait);
+ init_waitqueue_head(&channel->wr_wait);
+ init_waitqueue_head(&channel->wr_ready_wait);
+
+ INIT_DELAYED_WORK(&channel->rd_workitem, xillybus_autoflush);
+
+ channel->endpoint = ep;
+ channel->chan_num = i;
+
+ channel->log2_element_size = 0;
+
+ ep->channels[i] = channel++;
+ }
+
+ /*
+ * The DMA buffer address update is atomic on the FPGA, so even if
+ * it was in the middle of sending messages to some buffer, changing
+ * the address is safe, since the data will go to either of the
+ * buffers. Not that this situation should occur at all anyhow.
+ */
+
+ wr_nbuffer = 1;
+ rd_nbuffer = 1; /* Buffer zero isn't used at all */
+
+ for (entry = 0; entry < entries; entry++, chandesc += 4) {
+ is_writebuf = chandesc[0] & 0x01;
+ channelnum = (chandesc[0] >> 1) | ((chandesc[1] & 0x0f) << 7);
+ format = (chandesc[1] >> 4) & 0x03;
+ allowpartial = (chandesc[1] >> 6) & 0x01;
+ synchronous = (chandesc[1] >> 7) & 0x01;
+ bufsize = 1 << (chandesc[2] & 0x1f);
+ bufnum = 1 << (chandesc[3] & 0x0f);
+ exclusive_open = (chandesc[2] >> 7) & 0x01;
+ seekable = (chandesc[2] >> 6) & 0x01;
+ supports_nonempty = (chandesc[2] >> 5) & 0x01;
+
+ if ((channelnum > ep->num_channels) ||
+ ((channelnum == 0) && !is_writebuf)) {
+ pr_err("xillybus: IDT requests channel out "
+ "of range. Aborting.\n");
+ return -ENODEV;
+ }
+
+ channel = ep->channels[channelnum]; /* NULL for msg channel */
+
+ bytebufsize = bufsize << 2; /* Overwritten just below */
+
+ if (!is_writebuf) {
+ channel->num_rd_buffers = bufnum;
+ channel->log2_element_size = ((format > 2) ?
+ 2 : format);
+ bytebufsize = channel->rd_buf_size = bufsize *
+ (1 << channel->log2_element_size);
+ channel->rd_allow_partial = allowpartial;
+ channel->rd_synchronous = synchronous;
+ channel->rd_exclusive_open = exclusive_open;
+ channel->seekable = seekable;
+
+ channel->rd_buffers = xilly_malloc(
+ mem,
+ bufnum * sizeof(struct xilly_buffer *));
+
+ if (!channel->rd_buffers)
+ goto memfail;
+
+ this_buffer = xilly_malloc(
+ mem,
+ bufnum * sizeof(struct xilly_buffer));
+
+ if (!this_buffer)
+ goto memfail;
+ }
+
+ else if (channelnum > 0) {
+ channel->num_wr_buffers = bufnum;
+ channel->log2_element_size = ((format > 2) ?
+ 2 : format);
+ bytebufsize = channel->wr_buf_size = bufsize *
+ (1 << channel->log2_element_size);
+
+ channel->seekable = seekable;
+ channel->wr_supports_nonempty = supports_nonempty;
+
+ channel->wr_allow_partial = allowpartial;
+ channel->wr_synchronous = synchronous;
+ channel->wr_exclusive_open = exclusive_open;
+
+ channel->wr_buffers = xilly_malloc(
+ mem,
+ bufnum * sizeof(struct xilly_buffer *));
+
+ if (!channel->wr_buffers)
+ goto memfail;
+
+ this_buffer = xilly_malloc(
+ mem,
+ bufnum * sizeof(struct xilly_buffer));
+
+ if (!this_buffer)
+ goto memfail;
+ }
+
+ /*
+ * Although daunting, we cut the chunks for read buffers
+ * from a different salami than the write buffers',
+ * possibly improving performance.
+ */
+
+ if (is_writebuf)
+ for (i = 0; i < bufnum; i++) {
+ /*
+ * Buffers are expected in descending
+ * byte-size order, so there is either
+ * enough for this buffer or none at all.
+ */
+ if ((left_of_wr_salami < bytebufsize) &&
+ (left_of_wr_salami > 0)) {
+ pr_err("xillybus: "
+ "Corrupt buffer allocation "
+ "in IDT. Aborting.\n");
+ return -ENODEV;
+ }
+
+ if (left_of_wr_salami == 0) {
+ int allocorder, allocsize;
+
+ allocsize = PAGE_SIZE;
+ allocorder = 0;
+ while (bytebufsize > allocsize) {
+ allocsize *= 2;
+ allocorder++;
+ }
+
+ wr_salami = (void *)
+ xilly_pagealloc(mem,
+ allocorder);
+ if (!wr_salami)
+ goto memfail;
+ left_of_wr_salami = allocsize;
+ }
+
+ dma_addr = ep->ephw->map_single(
+ mem,
+ ep,
+ wr_salami,
+ bytebufsize,
+ DMA_FROM_DEVICE);
+
+ if (!dma_addr)
+ goto dmafail;
+
+ iowrite32(
+ (u32) (dma_addr & 0xffffffff),
+ &ep->registers[
+ fpga_dma_bufaddr_lowaddr_reg]
+ );
+ iowrite32(
+ ((u32) ((((u64) dma_addr) >> 32)
+ & 0xffffffff)),
+ &ep->registers[
+ fpga_dma_bufaddr_highaddr_reg]
+ );
+ mmiowb();
+
+ if (channelnum > 0) {
+ this_buffer->addr = wr_salami;
+ this_buffer->dma_addr = dma_addr;
+ channel->wr_buffers[i] = this_buffer++;
+
+ iowrite32(
+ 0x80000000 | wr_nbuffer++,
+ &ep->registers[
+ fpga_dma_bufno_reg]);
+ } else {
+ ep->msgbuf_addr = wr_salami;
+ ep->msgbuf_dma_addr = dma_addr;
+ ep->msg_buf_size = bytebufsize;
+ msg_buf_done++;
+
+ iowrite32(
+ 0x80000000, &ep->registers[
+ fpga_dma_bufno_reg]);
+ }
+
+ left_of_wr_salami -= bytebufsize;
+ wr_salami += bytebufsize;
+ }
+ else /* Read buffers */
+ for (i = 0; i < bufnum; i++) {
+ /*
+ * Buffers are expected in descending
+ * byte-size order, so there is either
+ * enough for this buffer or none at all.
+ */
+ if ((left_of_rd_salami < bytebufsize) &&
+ (left_of_rd_salami > 0)) {
+ pr_err("xillybus: "
+ "Corrupt buffer allocation "
+ "in IDT. Aborting.\n");
+ return -ENODEV;
+ }
+
+ if (left_of_rd_salami == 0) {
+ int allocorder, allocsize;
+
+ allocsize = PAGE_SIZE;
+ allocorder = 0;
+ while (bytebufsize > allocsize) {
+ allocsize *= 2;
+ allocorder++;
+ }
+
+ rd_salami = (void *)
+ xilly_pagealloc(
+ mem,
+ allocorder);
+
+ if (!rd_salami)
+ goto memfail;
+ left_of_rd_salami = allocsize;
+ }
+
+ dma_addr = ep->ephw->map_single(
+ mem,
+ ep,
+ rd_salami,
+ bytebufsize,
+ DMA_TO_DEVICE);
+
+ if (!dma_addr)
+ goto dmafail;
+
+ iowrite32(
+ (u32) (dma_addr & 0xffffffff),
+ &ep->registers[
+ fpga_dma_bufaddr_lowaddr_reg]
+ );
+ iowrite32(
+ ((u32) ((((u64) dma_addr) >> 32)
+ & 0xffffffff)),
+ &ep->registers[
+ fpga_dma_bufaddr_highaddr_reg]
+ );
+ mmiowb();
+
+ this_buffer->addr = rd_salami;
+ this_buffer->dma_addr = dma_addr;
+ channel->rd_buffers[i] = this_buffer++;
+
+ iowrite32(rd_nbuffer++,
+ &ep->registers[fpga_dma_bufno_reg]);
+
+ left_of_rd_salami -= bytebufsize;
+ rd_salami += bytebufsize;
+ }
+ }
+
+ if (!msg_buf_done) {
+ pr_err("xillybus: Corrupt IDT: No message buffer. "
+ "Aborting.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+
+memfail:
+ pr_err("xillybus: Failed to allocate write buffer memory. "
+ "Aborting.\n");
+ return -ENOMEM;
+dmafail:
+ pr_err("xillybus: Failed to map DMA memory!. Aborting.\n");
+ return -ENOMEM;
+}
+
+static void xilly_scan_idt(struct xilly_endpoint *endpoint,
+ struct xilly_idt_handle *idt_handle)
+{
+ int count = 0;
+ unsigned char *idt = endpoint->channels[1]->wr_buffers[0]->addr;
+ unsigned char *end_of_idt = idt + endpoint->idtlen - 4;
+ unsigned char *scan;
+ int len;
+
+ scan = idt;
+ idt_handle->idt = idt;
+
+ scan++; /* Skip version number */
+
+ while ((scan <= end_of_idt) && *scan) {
+ while ((scan <= end_of_idt) && *scan++)
+ /* Do nothing, just scan thru string */;
+ count++;
+ }
+
+ scan++;
+
+ if (scan > end_of_idt) {
+ pr_err("xillybus: IDT device name list overflow. "
+ "Aborting.\n");
+ idt_handle->chandesc = NULL;
+ return;
+ } else
+ idt_handle->chandesc = scan;
+
+ len = endpoint->idtlen - (3 + ((int) (scan - idt)));
+
+ if (len & 0x03) {
+ idt_handle->chandesc = NULL;
+
+ pr_err("xillybus: Corrupt IDT device name list. "
+ "Aborting.\n");
+ }
+
+ idt_handle->entries = len >> 2;
+
+ endpoint->num_channels = count;
+}
+
+static int xilly_obtain_idt(struct xilly_endpoint *endpoint)
+{
+ int rc = 0;
+ struct xilly_channel *channel;
+ unsigned char *version;
+
+ channel = endpoint->channels[1]; /* This should be generated ad-hoc */
+
+ channel->wr_sleepy = 1;
+ wmb(); /* Setting wr_sleepy must come before the command */
+
+ iowrite32(1 |
+ (3 << 24), /* Opcode 3 for channel 0 = Send IDT */
+ &endpoint->registers[fpga_buf_ctrl_reg]);
+ mmiowb(); /* Just to appear safe */
+
+ wait_event_interruptible_timeout(channel->wr_wait,
+ (!channel->wr_sleepy),
+ XILLY_TIMEOUT);
+
+ if (channel->wr_sleepy) {
+ pr_err("xillybus: Failed to obtain IDT. Aborting.\n");
+
+ if (endpoint->fatal_error)
+ return -EIO;
+
+ rc = -ENODEV;
+ return rc;
+ }
+
+ endpoint->ephw->hw_sync_sgl_for_cpu(
+ channel->endpoint,
+ channel->wr_buffers[0]->dma_addr,
+ channel->wr_buf_size,
+ DMA_FROM_DEVICE);
+
+ if (channel->wr_buffers[0]->end_offset != endpoint->idtlen) {
+ pr_err("xillybus: IDT length mismatch (%d != %d). "
+ "Aborting.\n",
+ channel->wr_buffers[0]->end_offset, endpoint->idtlen);
+ rc = -ENODEV;
+ return rc;
+ }
+
+ if (crc32_le(~0, channel->wr_buffers[0]->addr,
+ endpoint->idtlen+1) != 0) {
+ pr_err("xillybus: IDT failed CRC check. Aborting.\n");
+ rc = -ENODEV;
+ return rc;
+ }
+
+ version = channel->wr_buffers[0]->addr;
+
+ /* Check version number. Accept anything below 0x82 for now. */
+ if (*version > 0x82) {
+ pr_err("xillybus: No support for IDT version 0x%02x. "
+ "Maybe the xillybus driver needs an upgarde. "
+ "Aborting.\n",
+ (int) *version);
+ rc = -ENODEV;
+ return rc;
+ }
+
+ return 0; /* Success */
+}
+
+static ssize_t xillybus_read(struct file *filp, char __user *userbuf,
+ size_t count, loff_t *f_pos)
+{
+ ssize_t rc;
+ unsigned long flags;
+ int bytes_done = 0;
+ int no_time_left = 0;
+ long deadline, left_to_sleep;
+ struct xilly_channel *channel = filp->private_data;
+
+ int empty, reached_eof, exhausted, ready;
+ /* Initializations are there only to silence warnings */
+
+ int howmany = 0, bufpos = 0, bufidx = 0, bufferdone = 0;
+ int waiting_bufidx;
+
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+
+ deadline = jiffies + 1 + XILLY_RX_TIMEOUT;
+
+ rc = mutex_lock_interruptible(&channel->wr_mutex);
+
+ if (rc)
+ return rc;
+
+ rc = 0; /* Just to be clear about it. Compiler optimizes this out */
+
+ while (1) { /* Note that we may drop mutex within this loop */
+ int bytes_to_do = count - bytes_done;
+ spin_lock_irqsave(&channel->wr_spinlock, flags);
+
+ empty = channel->wr_empty;
+ ready = !empty || channel->wr_ready;
+
+ if (!empty) {
+ bufidx = channel->wr_host_buf_idx;
+ bufpos = channel->wr_host_buf_pos;
+ howmany = ((channel->wr_buffers[bufidx]->end_offset
+ + 1) << channel->log2_element_size)
+ - bufpos;
+
+ /* Update wr_host_* to its post-operation state */
+ if (howmany > bytes_to_do) {
+ bufferdone = 0;
+
+ howmany = bytes_to_do;
+ channel->wr_host_buf_pos += howmany;
+ } else {
+ bufferdone = 1;
+
+ channel->wr_host_buf_pos = 0;
+
+ if (bufidx == channel->wr_fpga_buf_idx) {
+ channel->wr_empty = 1;
+ channel->wr_sleepy = 1;
+ channel->wr_ready = 0;
+ }
+
+ if (bufidx >= (channel->num_wr_buffers - 1))
+ channel->wr_host_buf_idx = 0;
+ else
+ channel->wr_host_buf_idx++;
+ }
+ }
+
+ /*
+ * Marking our situation after the possible changes above,
+ * for use after releasing the spinlock.
+ *
+ * empty = empty before change
+ * exhasted = empty after possible change
+ */
+
+ reached_eof = channel->wr_empty &&
+ (channel->wr_host_buf_idx == channel->wr_eof);
+ channel->wr_hangup = reached_eof;
+ exhausted = channel->wr_empty;
+ waiting_bufidx = channel->wr_host_buf_idx;
+
+ spin_unlock_irqrestore(&channel->wr_spinlock, flags);
+
+ if (!empty) { /* Go on, now without the spinlock */
+
+ if (bufpos == 0) /* Position zero means it's virgin */
+ channel->endpoint->ephw->hw_sync_sgl_for_cpu(
+ channel->endpoint,
+ channel->wr_buffers[bufidx]->dma_addr,
+ channel->wr_buf_size,
+ DMA_FROM_DEVICE);
+
+ if (copy_to_user(
+ userbuf,
+ channel->wr_buffers[bufidx]->addr
+ + bufpos, howmany))
+ rc = -EFAULT;
+
+ userbuf += howmany;
+ bytes_done += howmany;
+
+ if (bufferdone) {
+ channel->endpoint->ephw->
+ hw_sync_sgl_for_device
+ (
+ channel->endpoint,
+ channel->wr_buffers[bufidx]->
+ dma_addr,
+ channel->wr_buf_size,
+ DMA_FROM_DEVICE);
+
+ /*
+ * Tell FPGA the buffer is done with. It's an
+ * atomic operation to the FPGA, so what
+ * happens with other channels doesn't matter,
+ * and the certain channel is protected with
+ * the channel-specific mutex.
+ */
+
+ iowrite32(1 | (channel->chan_num << 1)
+ | (bufidx << 12),
+ &channel->endpoint->registers[
+ fpga_buf_ctrl_reg]);
+ mmiowb(); /* Just to appear safe */
+ }
+
+ if (rc) {
+ mutex_unlock(&channel->wr_mutex);
+ return rc;
+ }
+ }
+
+ /* This includes a zero-count return = EOF */
+ if ((bytes_done >= count) || reached_eof)
+ break;
+
+ if (!exhausted)
+ continue; /* More in RAM buffer(s)? Just go on. */
+
+ if ((bytes_done > 0) &&
+ (no_time_left ||
+ (channel->wr_synchronous && channel->wr_allow_partial)))
+ break;
+
+ /*
+ * Nonblocking read: The "ready" flag tells us that the FPGA
+ * has data to send. In non-blocking mode, if it isn't on,
+ * just return. But if there is, we jump directly to the point
+ * where we ask for the FPGA to send all it has, and wait
+ * until that data arrives. So in a sense, we *do* block in
+ * nonblocking mode, but only for a very short time.
+ */
+
+ if (!no_time_left && (filp->f_flags & O_NONBLOCK)) {
+ if (bytes_done > 0)
+ break;
+
+ if (ready)
+ goto desperate;
+
+ bytes_done = -EAGAIN;
+ break;
+ }
+
+ if (!no_time_left || (bytes_done > 0)) {
+ /*
+ * Note that in case of an element-misaligned read
+ * request, offsetlimit will include the last element,
+ * which will be partially read from.
+ */
+ int offsetlimit = ((count - bytes_done) - 1) >>
+ channel->log2_element_size;
+ int buf_elements = channel->wr_buf_size >>
+ channel->log2_element_size;
+
+ /*
+ * In synchronous mode, always send an offset limit.
+ * Just don't send a value too big.
+ */
+
+ if (channel->wr_synchronous) {
+ /* Don't request more than one buffer */
+ if (channel->wr_allow_partial &&
+ (offsetlimit >= buf_elements))
+ offsetlimit = buf_elements - 1;
+
+ /* Don't request more than all buffers */
+ if (!channel->wr_allow_partial &&
+ (offsetlimit >=
+ (buf_elements * channel->num_wr_buffers)))
+ offsetlimit = buf_elements *
+ channel->num_wr_buffers - 1;
+ }
+
+ /*
+ * In asynchronous mode, force early flush of a buffer
+ * only if that will allow returning a full count. The
+ * "offsetlimit < ( ... )" rather than "<=" excludes
+ * requesting a full buffer, which would obviously
+ * cause a buffer transmission anyhow
+ */
+
+ if (channel->wr_synchronous ||
+ (offsetlimit < (buf_elements - 1))) {
+
+ mutex_lock(&channel->endpoint->register_mutex);
+
+ iowrite32(offsetlimit,
+ &channel->endpoint->registers[
+ fpga_buf_offset_reg]);
+ mmiowb();
+
+ iowrite32(1 | (channel->chan_num << 1) |
+ (2 << 24) | /* 2 = offset limit */
+ (waiting_bufidx << 12),
+ &channel->endpoint->registers[
+ fpga_buf_ctrl_reg]);
+
+ mmiowb(); /* Just to appear safe */
+
+ mutex_unlock(&channel->endpoint->
+ register_mutex);
+ }
+
+ }
+
+ /*
+ * If partial completion is disallowed, there is no point in
+ * timeout sleeping. Neither if no_time_left is set and
+ * there's no data.
+ */
+
+ if (!channel->wr_allow_partial ||
+ (no_time_left && (bytes_done == 0))) {
+
+ /*
+ * This do-loop will run more than once if another
+ * thread reasserted wr_sleepy before we got the mutex
+ * back, so we try again.
+ */
+
+ do {
+ mutex_unlock(&channel->wr_mutex);
+
+ if (wait_event_interruptible(
+ channel->wr_wait,
+ (!channel->wr_sleepy)))
+ goto interrupted;
+
+ if (mutex_lock_interruptible(
+ &channel->wr_mutex))
+ goto interrupted;
+ } while (channel->wr_sleepy);
+
+ continue;
+
+interrupted: /* Mutex is not held if got here */
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+ if (bytes_done)
+ return bytes_done;
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN; /* Don't admit snoozing */
+ return -EINTR;
+ }
+
+ left_to_sleep = deadline - ((long) jiffies);
+
+ /*
+ * If our time is out, skip the waiting. We may miss wr_sleepy
+ * being deasserted but hey, almost missing the train is like
+ * missing it.
+ */
+
+ if (left_to_sleep > 0) {
+ left_to_sleep =
+ wait_event_interruptible_timeout(
+ channel->wr_wait,
+ (!channel->wr_sleepy),
+ left_to_sleep);
+
+ if (!channel->wr_sleepy)
+ continue;
+
+ if (left_to_sleep < 0) { /* Interrupt */
+ mutex_unlock(&channel->wr_mutex);
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+ if (bytes_done)
+ return bytes_done;
+ return -EINTR;
+ }
+ }
+
+desperate:
+ no_time_left = 1; /* We're out of sleeping time. Desperate! */
+
+ if (bytes_done == 0) {
+ /*
+ * Reaching here means that we allow partial return,
+ * that we've run out of time, and that we have
+ * nothing to return.
+ * So tell the FPGA to send anything it has or gets.
+ */
+
+ iowrite32(1 | (channel->chan_num << 1) |
+ (3 << 24) | /* Opcode 3, flush it all! */
+ (waiting_bufidx << 12),
+ &channel->endpoint->registers[
+ fpga_buf_ctrl_reg]);
+ mmiowb(); /* Just to appear safe */
+ }
+
+ /*
+ * Formally speaking, we should block for data at this point.
+ * But to keep the code cleaner, we'll just finish the loop,
+ * make the unlikely check for data, and then block at the
+ * usual place.
+ */
+ }
+
+ mutex_unlock(&channel->wr_mutex);
+
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+
+ return bytes_done;
+}
+
+/*
+ * The timeout argument takes values as follows:
+ * >0 : Flush with timeout
+ * ==0 : Flush, and wait idefinitely for the flush to complete
+ * <0 : Autoflush: Flush only if there's a single buffer occupied
+ */
+
+static int xillybus_myflush(struct xilly_channel *channel, long timeout)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ int end_offset_plus1;
+ int bufidx, bufidx_minus1;
+ int i;
+ int empty;
+ int new_rd_host_buf_pos;
+
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+ rc = mutex_lock_interruptible(&channel->rd_mutex);
+
+ if (rc)
+ return rc;
+
+ /*
+ * Don't flush a closed channel. This can happen when the work queued
+ * autoflush thread fires off after the file has closed. This is not
+ * an error, just something to dismiss.
+ */
+
+ if (!channel->rd_ref_count)
+ goto done;
+
+ bufidx = channel->rd_host_buf_idx;
+
+ bufidx_minus1 = (bufidx == 0) ? channel->num_rd_buffers - 1 : bufidx-1;
+
+ end_offset_plus1 = channel->rd_host_buf_pos >>
+ channel->log2_element_size;
+
+ new_rd_host_buf_pos = channel->rd_host_buf_pos -
+ (end_offset_plus1 << channel->log2_element_size);
+
+ /* Submit the current buffer if it's nonempty */
+ if (end_offset_plus1) {
+ unsigned char *tail = channel->rd_buffers[bufidx]->addr +
+ (end_offset_plus1 << channel->log2_element_size);
+
+ /* Copy unflushed data, so we can put it in next buffer */
+ for (i = 0; i < new_rd_host_buf_pos; i++)
+ channel->rd_leftovers[i] = *tail++;
+
+ spin_lock_irqsave(&channel->rd_spinlock, flags);
+
+ /* Autoflush only if a single buffer is occupied */
+
+ if ((timeout < 0) &&
+ (channel->rd_full ||
+ (bufidx_minus1 != channel->rd_fpga_buf_idx))) {
+ spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+ /*
+ * A new work item may be queued by the ISR exactly
+ * now, since the execution of a work item allows the
+ * queuing of a new one while it's running.
+ */
+ goto done;
+ }
+
+ /* The 4th element is never needed for data, so it's a flag */
+ channel->rd_leftovers[3] = (new_rd_host_buf_pos != 0);
+
+ /* Set up rd_full to reflect a certain moment's state */
+
+ if (bufidx == channel->rd_fpga_buf_idx)
+ channel->rd_full = 1;
+ spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+
+ if (bufidx >= (channel->num_rd_buffers - 1))
+ channel->rd_host_buf_idx = 0;
+ else
+ channel->rd_host_buf_idx++;
+
+ channel->endpoint->ephw->hw_sync_sgl_for_device(
+ channel->endpoint,
+ channel->rd_buffers[bufidx]->dma_addr,
+ channel->rd_buf_size,
+ DMA_TO_DEVICE);
+
+ mutex_lock(&channel->endpoint->register_mutex);
+
+ iowrite32(end_offset_plus1 - 1,
+ &channel->endpoint->registers[fpga_buf_offset_reg]);
+ mmiowb();
+
+ iowrite32((channel->chan_num << 1) | /* Channel ID */
+ (2 << 24) | /* Opcode 2, submit buffer */
+ (bufidx << 12),
+ &channel->endpoint->registers[fpga_buf_ctrl_reg]);
+ mmiowb(); /* Just to appear safe */
+
+ mutex_unlock(&channel->endpoint->register_mutex);
+ } else if (bufidx == 0)
+ bufidx = channel->num_rd_buffers - 1;
+ else
+ bufidx--;
+
+ channel->rd_host_buf_pos = new_rd_host_buf_pos;
+
+ if (timeout < 0)
+ goto done; /* Autoflush */
+
+
+ /*
+ * bufidx is now the last buffer written to (or equal to
+ * rd_fpga_buf_idx if buffer was never written to), and
+ * channel->rd_host_buf_idx the one after it.
+ *
+ * If bufidx == channel->rd_fpga_buf_idx we're either empty or full.
+ */
+
+ rc = 0;
+
+ while (1) { /* Loop waiting for draining of buffers */
+ spin_lock_irqsave(&channel->rd_spinlock, flags);
+
+ if (bufidx != channel->rd_fpga_buf_idx)
+ channel->rd_full = 1; /*
+ * Not really full,
+ * but needs waiting.
+ */
+
+ empty = !channel->rd_full;
+
+ spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+
+ if (empty)
+ break;
+
+ /*
+ * Indefinite sleep with mutex taken. With data waiting for
+ * flushing user should not be surprised if open() for write
+ * sleeps.
+ */
+ if (timeout == 0)
+ wait_event_interruptible(channel->rd_wait,
+ (!channel->rd_full));
+
+ else if (wait_event_interruptible_timeout(
+ channel->rd_wait,
+ (!channel->rd_full),
+ timeout) == 0) {
+ pr_warn("xillybus: "
+ "Timed out while flushing. "
+ "Output data may be lost.\n");
+
+ rc = -ETIMEDOUT;
+ break;
+ }
+
+ if (channel->rd_full) {
+ rc = -EINTR;
+ break;
+ }
+ }
+
+done:
+ mutex_unlock(&channel->rd_mutex);
+
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+
+ return rc;
+}
+
+static int xillybus_flush(struct file *filp, fl_owner_t id)
+{
+ if (!(filp->f_mode & FMODE_WRITE))
+ return 0;
+
+ return xillybus_myflush(filp->private_data, HZ); /* 1 second timeout */
+}
+
+static void xillybus_autoflush(struct work_struct *work)
+{
+ struct delayed_work *workitem = container_of(
+ work, struct delayed_work, work);
+ struct xilly_channel *channel = container_of(
+ workitem, struct xilly_channel, rd_workitem);
+ int rc;
+
+ rc = xillybus_myflush(channel, -1);
+
+ if (rc == -EINTR)
+ pr_warn("xillybus: Autoflush failed because "
+ "work queue thread got a signal.\n");
+ else if (rc)
+ pr_err("xillybus: Autoflush failed under "
+ "weird circumstances.\n");
+
+}
+
+static ssize_t xillybus_write(struct file *filp, const char __user *userbuf,
+ size_t count, loff_t *f_pos)
+{
+ ssize_t rc;
+ unsigned long flags;
+ int bytes_done = 0;
+ struct xilly_channel *channel = filp->private_data;
+
+ int full, exhausted;
+ /* Initializations are there only to silence warnings */
+
+ int howmany = 0, bufpos = 0, bufidx = 0, bufferdone = 0;
+ int end_offset_plus1 = 0;
+
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+
+ rc = mutex_lock_interruptible(&channel->rd_mutex);
+
+ if (rc)
+ return rc;
+
+ rc = 0; /* Just to be clear about it. Compiler optimizes this out */
+
+ while (1) {
+ int bytes_to_do = count - bytes_done;
+
+ spin_lock_irqsave(&channel->rd_spinlock, flags);
+
+ full = channel->rd_full;
+
+ if (!full) {
+ bufidx = channel->rd_host_buf_idx;
+ bufpos = channel->rd_host_buf_pos;
+ howmany = channel->rd_buf_size - bufpos;
+
+ /*
+ * Update rd_host_* to its state after this operation.
+ * count=0 means committing the buffer immediately,
+ * which is like flushing, but not necessarily block.
+ */
+
+ if ((howmany > bytes_to_do) &&
+ (count ||
+ ((bufpos >> channel->log2_element_size) == 0))) {
+ bufferdone = 0;
+
+ howmany = bytes_to_do;
+ channel->rd_host_buf_pos += howmany;
+ } else {
+ bufferdone = 1;
+
+ if (count) {
+ end_offset_plus1 =
+ channel->rd_buf_size >>
+ channel->log2_element_size;
+ channel->rd_host_buf_pos = 0;
+ } else {
+ unsigned char *tail;
+ int i;
+
+ end_offset_plus1 = bufpos >>
+ channel->log2_element_size;
+
+ channel->rd_host_buf_pos -=
+ end_offset_plus1 <<
+ channel->log2_element_size;
+
+ tail = channel->
+ rd_buffers[bufidx]->addr +
+ (end_offset_plus1 <<
+ channel->log2_element_size);
+
+ for (i = 0;
+ i < channel->rd_host_buf_pos;
+ i++)
+ channel->rd_leftovers[i] =
+ *tail++;
+ }
+
+ if (bufidx == channel->rd_fpga_buf_idx)
+ channel->rd_full = 1;
+
+ if (bufidx >= (channel->num_rd_buffers - 1))
+ channel->rd_host_buf_idx = 0;
+ else
+ channel->rd_host_buf_idx++;
+ }
+ }
+
+ /*
+ * Marking our situation after the possible changes above,
+ * for use after releasing the spinlock.
+ *
+ * full = full before change
+ * exhasted = full after possible change
+ */
+
+ exhausted = channel->rd_full;
+
+ spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+
+ if (!full) { /* Go on, now without the spinlock */
+ unsigned char *head =
+ channel->rd_buffers[bufidx]->addr;
+ int i;
+
+ if ((bufpos == 0) || /* Zero means it's virgin */
+ (channel->rd_leftovers[3] != 0)) {
+ channel->endpoint->ephw->hw_sync_sgl_for_cpu(
+ channel->endpoint,
+ channel->rd_buffers[bufidx]->dma_addr,
+ channel->rd_buf_size,
+ DMA_TO_DEVICE);
+
+ /* Virgin, but leftovers are due */
+ for (i = 0; i < bufpos; i++)
+ *head++ = channel->rd_leftovers[i];
+
+ channel->rd_leftovers[3] = 0; /* Clear flag */
+ }
+
+ if (copy_from_user(
+ channel->rd_buffers[bufidx]->addr + bufpos,
+ userbuf, howmany))
+ rc = -EFAULT;
+
+ userbuf += howmany;
+ bytes_done += howmany;
+
+ if (bufferdone) {
+ channel->endpoint->ephw->
+ hw_sync_sgl_for_device(
+ channel->endpoint,
+ channel->rd_buffers[bufidx]->
+ dma_addr,
+ channel->rd_buf_size,
+ DMA_TO_DEVICE);
+
+ mutex_lock(&channel->endpoint->register_mutex);
+
+ iowrite32(end_offset_plus1 - 1,
+ &channel->endpoint->registers[
+ fpga_buf_offset_reg]);
+ mmiowb();
+ iowrite32((channel->chan_num << 1) |
+ (2 << 24) | /* 2 = submit buffer */
+ (bufidx << 12),
+ &channel->endpoint->registers[
+ fpga_buf_ctrl_reg]);
+ mmiowb(); /* Just to appear safe */
+
+ mutex_unlock(&channel->endpoint->
+ register_mutex);
+
+ channel->rd_leftovers[3] =
+ (channel->rd_host_buf_pos != 0);
+ }
+
+ if (rc) {
+ mutex_unlock(&channel->rd_mutex);
+
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+
+ if (!channel->rd_synchronous)
+ queue_delayed_work(
+ xillybus_wq,
+ &channel->rd_workitem,
+ XILLY_RX_TIMEOUT);
+
+ return rc;
+ }
+ }
+
+ if (bytes_done >= count)
+ break;
+
+ if (!exhausted)
+ continue; /* If there's more space, just go on */
+
+ if ((bytes_done > 0) && channel->rd_allow_partial)
+ break;
+
+ /*
+ * Indefinite sleep with mutex taken. With data waiting for
+ * flushing, user should not be surprised if open() for write
+ * sleeps.
+ */
+
+ if (filp->f_flags & O_NONBLOCK) {
+ bytes_done = -EAGAIN;
+ break;
+ }
+
+ wait_event_interruptible(channel->rd_wait,
+ (!channel->rd_full));
+
+ if (channel->rd_full) {
+ mutex_unlock(&channel->rd_mutex);
+
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+
+ if (bytes_done)
+ return bytes_done;
+ return -EINTR;
+ }
+ }
+
+ mutex_unlock(&channel->rd_mutex);
+
+ if (!channel->rd_synchronous)
+ queue_delayed_work(xillybus_wq,
+ &channel->rd_workitem,
+ XILLY_RX_TIMEOUT);
+
+ if ((channel->rd_synchronous) && (bytes_done > 0)) {
+ rc = xillybus_myflush(filp->private_data, 0); /* No timeout */
+
+ if (rc && (rc != -EINTR))
+ return rc;
+ }
+
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+
+ return bytes_done;
+}
+
+static int xillybus_open(struct inode *inode, struct file *filp)
+{
+ int rc = 0;
+ unsigned long flags;
+ int minor = iminor(inode);
+ int major = imajor(inode);
+ struct xilly_endpoint *ep_iter, *endpoint = NULL;
+ struct xilly_channel *channel;
+
+ mutex_lock(&ep_list_lock);
+
+ list_for_each_entry(ep_iter, &list_of_endpoints, ep_list) {
+ if ((ep_iter->major == major) &&
+ (minor >= ep_iter->lowest_minor) &&
+ (minor < (ep_iter->lowest_minor +
+ ep_iter->num_channels))) {
+ endpoint = ep_iter;
+ break;
+ }
+ }
+ mutex_unlock(&ep_list_lock);
+
+ if (!endpoint) {
+ pr_err("xillybus: open() failed to find a device "
+ "for major=%d and minor=%d\n", major, minor);
+ return -ENODEV;
+ }
+
+ if (endpoint->fatal_error)
+ return -EIO;
+
+ channel = endpoint->channels[1 + minor - endpoint->lowest_minor];
+ filp->private_data = channel;
+
+
+ /*
+ * It gets complicated because:
+ * 1. We don't want to take a mutex we don't have to
+ * 2. We don't want to open one direction if the other will fail.
+ */
+
+ if ((filp->f_mode & FMODE_READ) && (!channel->num_wr_buffers))
+ return -ENODEV;
+
+ if ((filp->f_mode & FMODE_WRITE) && (!channel->num_rd_buffers))
+ return -ENODEV;
+
+ if ((filp->f_mode & FMODE_READ) && (filp->f_flags & O_NONBLOCK) &&
+ (channel->wr_synchronous || !channel->wr_allow_partial ||
+ !channel->wr_supports_nonempty)) {
+ pr_err("xillybus: open() failed: "
+ "O_NONBLOCK not allowed for read on this device\n");
+ return -ENODEV;
+ }
+
+ if ((filp->f_mode & FMODE_WRITE) && (filp->f_flags & O_NONBLOCK) &&
+ (channel->rd_synchronous || !channel->rd_allow_partial)) {
+ pr_err("xillybus: open() failed: "
+ "O_NONBLOCK not allowed for write on this device\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Note: open() may block on getting mutexes despite O_NONBLOCK.
+ * This shouldn't occur normally, since multiple open of the same
+ * file descriptor is almost always prohibited anyhow
+ * (*_exclusive_open is normally set in real-life systems).
+ */
+
+ if (filp->f_mode & FMODE_READ) {
+ rc = mutex_lock_interruptible(&channel->wr_mutex);
+ if (rc)
+ return rc;
+ }
+
+ if (filp->f_mode & FMODE_WRITE) {
+ rc = mutex_lock_interruptible(&channel->rd_mutex);
+ if (rc)
+ goto unlock_wr;
+ }
+
+ if ((filp->f_mode & FMODE_READ) &&
+ (channel->wr_ref_count != 0) &&
+ (channel->wr_exclusive_open)) {
+ rc = -EBUSY;
+ goto unlock;
+ }
+
+ if ((filp->f_mode & FMODE_WRITE) &&
+ (channel->rd_ref_count != 0) &&
+ (channel->rd_exclusive_open)) {
+ rc = -EBUSY;
+ goto unlock;
+ }
+
+
+ if (filp->f_mode & FMODE_READ) {
+ if (channel->wr_ref_count == 0) { /* First open of file */
+ /* Move the host to first buffer */
+ spin_lock_irqsave(&channel->wr_spinlock, flags);
+ channel->wr_host_buf_idx = 0;
+ channel->wr_host_buf_pos = 0;
+ channel->wr_fpga_buf_idx = -1;
+ channel->wr_empty = 1;
+ channel->wr_ready = 0;
+ channel->wr_sleepy = 1;
+ channel->wr_eof = -1;
+ channel->wr_hangup = 0;
+
+ spin_unlock_irqrestore(&channel->wr_spinlock, flags);
+
+ iowrite32(1 | (channel->chan_num << 1) |
+ (4 << 24) | /* Opcode 4, open channel */
+ ((channel->wr_synchronous & 1) << 23),
+ &channel->endpoint->registers[
+ fpga_buf_ctrl_reg]);
+ mmiowb(); /* Just to appear safe */
+ }
+
+ channel->wr_ref_count++;
+ }
+
+ if (filp->f_mode & FMODE_WRITE) {
+ if (channel->rd_ref_count == 0) { /* First open of file */
+ /* Move the host to first buffer */
+ spin_lock_irqsave(&channel->rd_spinlock, flags);
+ channel->rd_host_buf_idx = 0;
+ channel->rd_host_buf_pos = 0;
+ channel->rd_leftovers[3] = 0; /* No leftovers. */
+ channel->rd_fpga_buf_idx = channel->num_rd_buffers - 1;
+ channel->rd_full = 0;
+
+ spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+
+ iowrite32((channel->chan_num << 1) |
+ (4 << 24), /* Opcode 4, open channel */
+ &channel->endpoint->registers[
+ fpga_buf_ctrl_reg]);
+ mmiowb(); /* Just to appear safe */
+ }
+
+ channel->rd_ref_count++;
+ }
+
+unlock:
+ if (filp->f_mode & FMODE_WRITE)
+ mutex_unlock(&channel->rd_mutex);
+unlock_wr:
+ if (filp->f_mode & FMODE_READ)
+ mutex_unlock(&channel->wr_mutex);
+
+ if (!rc && (!channel->seekable))
+ return nonseekable_open(inode, filp);
+
+ return rc;
+}
+
+static int xillybus_release(struct inode *inode, struct file *filp)
+{
+ int rc;
+ unsigned long flags;
+ struct xilly_channel *channel = filp->private_data;
+
+ int buf_idx;
+ int eof;
+
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+
+ if (filp->f_mode & FMODE_WRITE) {
+ rc = mutex_lock_interruptible(&channel->rd_mutex);
+
+ if (rc) {
+ pr_warn("xillybus: Failed to close file. "
+ "Hardware left in messy state.\n");
+ return rc;
+ }
+
+ channel->rd_ref_count--;
+
+ if (channel->rd_ref_count == 0) {
+
+ /*
+ * We rely on the kernel calling flush()
+ * before we get here.
+ */
+
+ iowrite32((channel->chan_num << 1) | /* Channel ID */
+ (5 << 24), /* Opcode 5, close channel */
+ &channel->endpoint->registers[
+ fpga_buf_ctrl_reg]);
+ mmiowb(); /* Just to appear safe */
+ }
+ mutex_unlock(&channel->rd_mutex);
+ }
+
+ if (filp->f_mode & FMODE_READ) {
+ rc = mutex_lock_interruptible(&channel->wr_mutex);
+ if (rc) {
+ pr_warn("xillybus: Failed to close file. "
+ "Hardware left in messy state.\n");
+ return rc;
+ }
+
+ channel->wr_ref_count--;
+
+ if (channel->wr_ref_count == 0) {
+
+ iowrite32(1 | (channel->chan_num << 1) |
+ (5 << 24), /* Opcode 5, close channel */
+ &channel->endpoint->registers[
+ fpga_buf_ctrl_reg]);
+ mmiowb(); /* Just to appear safe */
+
+ /*
+ * This is crazily cautious: We make sure that not
+ * only that we got an EOF (be it because we closed
+ * the channel or because of a user's EOF), but verify
+ * that it's one beyond the last buffer arrived, so
+ * we have no leftover buffers pending before wrapping
+ * up (which can only happen in asynchronous channels,
+ * BTW)
+ */
+
+ while (1) {
+ spin_lock_irqsave(&channel->wr_spinlock,
+ flags);
+ buf_idx = channel->wr_fpga_buf_idx;
+ eof = channel->wr_eof;
+ channel->wr_sleepy = 1;
+ spin_unlock_irqrestore(&channel->wr_spinlock,
+ flags);
+
+ /*
+ * Check if eof points at the buffer after
+ * the last one the FPGA submitted. Note that
+ * no EOF is marked by negative eof.
+ */
+
+ buf_idx++;
+ if (buf_idx == channel->num_wr_buffers)
+ buf_idx = 0;
+
+ if (buf_idx == eof)
+ break;
+
+ /*
+ * Steal extra 100 ms if awaken by interrupt.
+ * This is a simple workaround for an
+ * interrupt pending when entering, which would
+ * otherwise result in declaring the hardware
+ * non-responsive.
+ */
+
+ if (wait_event_interruptible(
+ channel->wr_wait,
+ (!channel->wr_sleepy)))
+ msleep(100);
+
+ if (channel->wr_sleepy) {
+ mutex_unlock(&channel->wr_mutex);
+ pr_warn("xillybus: Hardware failed to "
+ "respond to close command, "
+ "therefore left in "
+ "messy state.\n");
+ return -EINTR;
+ }
+ }
+ }
+
+ mutex_unlock(&channel->wr_mutex);
+ }
+
+ return 0;
+}
+static loff_t xillybus_llseek(struct file *filp, loff_t offset, int whence)
+{
+ struct xilly_channel *channel = filp->private_data;
+ loff_t pos = filp->f_pos;
+ int rc = 0;
+
+ /*
+ * Take both mutexes not allowing interrupts, since it seems like
+ * common applications don't expect an -EINTR here. Besides, multiple
+ * access to a single file descriptor on seekable devices is a mess
+ * anyhow.
+ */
+
+ if (channel->endpoint->fatal_error)
+ return -EIO;
+
+ mutex_lock(&channel->wr_mutex);
+ mutex_lock(&channel->rd_mutex);
+
+ switch (whence) {
+ case 0:
+ pos = offset;
+ break;
+ case 1:
+ pos += offset;
+ break;
+ case 2:
+ pos = offset; /* Going to the end => to the beginning */
+ break;
+ default:
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* In any case, we must finish on an element boundary */
+ if (pos & ((1 << channel->log2_element_size) - 1)) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ mutex_lock(&channel->endpoint->register_mutex);
+
+ iowrite32(pos >> channel->log2_element_size,
+ &channel->endpoint->registers[fpga_buf_offset_reg]);
+ mmiowb();
+ iowrite32((channel->chan_num << 1) |
+ (6 << 24), /* Opcode 6, set address */
+ &channel->endpoint->registers[fpga_buf_ctrl_reg]);
+ mmiowb(); /* Just to appear safe */
+
+ mutex_unlock(&channel->endpoint->register_mutex);
+
+end:
+ mutex_unlock(&channel->rd_mutex);
+ mutex_unlock(&channel->wr_mutex);
+
+ if (rc) /* Return error after releasing mutexes */
+ return rc;
+
+ filp->f_pos = pos;
+
+ /*
+ * Since seekable devices are allowed only when the channel is
+ * synchronous, we assume that there is no data pending in either
+ * direction (which holds true as long as no concurrent access on the
+ * file descriptor takes place).
+ * The only thing we may need to throw away is leftovers from partial
+ * write() flush.
+ */
+
+ channel->rd_leftovers[3] = 0;
+
+ return pos;
+}
+
+static unsigned int xillybus_poll(struct file *filp, poll_table *wait)
+{
+ struct xilly_channel *channel = filp->private_data;
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &channel->endpoint->ep_wait, wait);
+
+ /*
+ * poll() won't play ball regarding read() channels which
+ * aren't asynchronous and support the nonempty message. Allowing
+ * that will create situations where data has been delivered at
+ * the FPGA, and users expecting select() to wake up, which it may
+ * not.
+ */
+
+ if (!channel->wr_synchronous && channel->wr_supports_nonempty) {
+ poll_wait(filp, &channel->wr_wait, wait);
+ poll_wait(filp, &channel->wr_ready_wait, wait);
+
+ spin_lock_irqsave(&channel->wr_spinlock, flags);
+ if (!channel->wr_empty || channel->wr_ready)
+ mask |= POLLIN | POLLRDNORM;
+
+ if (channel->wr_hangup)
+ /*
+ * Not POLLHUP, because its behavior is in the
+ * mist, and POLLIN does what we want: Wake up
+ * the read file descriptor so it sees EOF.
+ */
+ mask |= POLLIN | POLLRDNORM;
+ spin_unlock_irqrestore(&channel->wr_spinlock, flags);
+ }
+
+ /*
+ * If partial data write is disallowed on a write() channel,
+ * it's pointless to ever signal OK to write, because is could
+ * block despite some space being available.
+ */
+
+ if (channel->rd_allow_partial) {
+ poll_wait(filp, &channel->rd_wait, wait);
+
+ spin_lock_irqsave(&channel->rd_spinlock, flags);
+ if (!channel->rd_full)
+ mask |= POLLOUT | POLLWRNORM;
+ spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+ }
+
+ if (channel->endpoint->fatal_error)
+ mask |= POLLERR;
+
+ return mask;
+}
+
+static const struct file_operations xillybus_fops = {
+ .owner = THIS_MODULE,
+ .read = xillybus_read,
+ .write = xillybus_write,
+ .open = xillybus_open,
+ .flush = xillybus_flush,
+ .release = xillybus_release,
+ .llseek = xillybus_llseek,
+ .poll = xillybus_poll,
+};
+
+static int xillybus_init_chrdev(struct xilly_endpoint *endpoint,
+ const unsigned char *idt)
+{
+ int rc;
+ dev_t dev;
+ int devnum, i, minor, major;
+ char devname[48];
+ struct device *device;
+
+ rc = alloc_chrdev_region(&dev, 0, /* minor start */
+ endpoint->num_channels,
+ xillyname);
+
+ if (rc) {
+ pr_warn("xillybus: Failed to obtain major/minors");
+ goto error1;
+ }
+
+ endpoint->major = major = MAJOR(dev);
+ endpoint->lowest_minor = minor = MINOR(dev);
+
+ cdev_init(&endpoint->cdev, &xillybus_fops);
+ endpoint->cdev.owner = endpoint->ephw->owner;
+ rc = cdev_add(&endpoint->cdev, MKDEV(major, minor),
+ endpoint->num_channels);
+ if (rc) {
+ pr_warn("xillybus: Failed to add cdev. Aborting.\n");
+ goto error2;
+ }
+
+ idt++;
+
+ for (i = minor, devnum = 0;
+ devnum < endpoint->num_channels;
+ devnum++, i++) {
+ snprintf(devname, sizeof(devname)-1, "xillybus_%s", idt);
+
+ devname[sizeof(devname)-1] = 0; /* Should never matter */
+
+ while (*idt++)
+ /* Skip to next */;
+
+ device = device_create(xillybus_class,
+ NULL,
+ MKDEV(major, i),
+ NULL,
+ devname);
+
+ if (IS_ERR(device)) {
+ pr_warn("xillybus: Failed to create %s "
+ "device. Aborting.\n", devname);
+ goto error3;
+ }
+ }
+
+ pr_info("xillybus: Created %d device files.\n",
+ endpoint->num_channels);
+ return 0; /* succeed */
+
+error3:
+ devnum--; i--;
+ for (; devnum >= 0; devnum--, i--)
+ device_destroy(xillybus_class, MKDEV(major, i));
+
+ cdev_del(&endpoint->cdev);
+error2:
+ unregister_chrdev_region(MKDEV(major, minor), endpoint->num_channels);
+error1:
+
+ return rc;
+}
+
+static void xillybus_cleanup_chrdev(struct xilly_endpoint *endpoint)
+{
+ int minor;
+
+ for (minor = endpoint->lowest_minor;
+ minor < (endpoint->lowest_minor + endpoint->num_channels);
+ minor++)
+ device_destroy(xillybus_class, MKDEV(endpoint->major, minor));
+ cdev_del(&endpoint->cdev);
+ unregister_chrdev_region(MKDEV(endpoint->major,
+ endpoint->lowest_minor),
+ endpoint->num_channels);
+
+ pr_info("xillybus: Removed %d device files.\n",
+ endpoint->num_channels);
+}
+
+
+struct xilly_endpoint *xillybus_init_endpoint(struct pci_dev *pdev,
+ struct device *dev,
+ struct xilly_endpoint_hardware
+ *ephw)
+{
+ struct xilly_endpoint *endpoint;
+
+ endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL);
+ if (!endpoint) {
+ pr_err("xillybus: Failed to allocate memory. Aborting.\n");
+ return NULL;
+ }
+
+ endpoint->pdev = pdev;
+ endpoint->dev = dev;
+ endpoint->ephw = ephw;
+ INIT_LIST_HEAD(&endpoint->cleanup.to_kfree);
+ INIT_LIST_HEAD(&endpoint->cleanup.to_pagefree);
+ INIT_LIST_HEAD(&endpoint->cleanup.to_unmap);
+ endpoint->msg_counter = 0x0b;
+ endpoint->failed_messages = 0;
+ endpoint->fatal_error = 0;
+
+ init_waitqueue_head(&endpoint->ep_wait);
+ mutex_init(&endpoint->register_mutex);
+
+ return endpoint;
+}
+EXPORT_SYMBOL(xillybus_init_endpoint);
+
+static int xilly_quiesce(struct xilly_endpoint *endpoint)
+{
+ endpoint->idtlen = -1;
+ wmb(); /* Make sure idtlen is set before sending command */
+ iowrite32((u32) (endpoint->dma_using_dac & 0x0001),
+ &endpoint->registers[fpga_dma_control_reg]);
+ mmiowb();
+
+ wait_event_interruptible_timeout(endpoint->ep_wait,
+ (endpoint->idtlen >= 0),
+ XILLY_TIMEOUT);
+
+ if (endpoint->idtlen < 0) {
+ pr_err("xillybus: Failed to quiesce the device on "
+ "exit. Quitting while leaving a mess.\n");
+ return -ENODEV;
+ }
+ return 0; /* Success */
+}
+
+int xillybus_endpoint_discovery(struct xilly_endpoint *endpoint)
+{
+ int rc = 0;
+
+ struct xilly_cleanup tmpmem;
+ int idtbuffersize = (1 << PAGE_SHIFT);
+
+ /*
+ * The bogus IDT is used during bootstrap for allocating the initial
+ * message buffer, and then the message buffer and space for the IDT
+ * itself. The initial message buffer is of a single page's size, but
+ * it's soon replaced with a more modest one (and memory is freed).
+ */
+
+ unsigned char bogus_idt[8] = { 1, 224, (PAGE_SHIFT)-2, 0,
+ 3, 192, PAGE_SHIFT, 0 };
+ struct xilly_idt_handle idt_handle;
+
+ INIT_LIST_HEAD(&tmpmem.to_kfree);
+ INIT_LIST_HEAD(&tmpmem.to_pagefree);
+ INIT_LIST_HEAD(&tmpmem.to_unmap);
+
+ /*
+ * Writing the value 0x00000001 to Endianness register signals which
+ * endianness this processor is using, so the FPGA can swap words as
+ * necessary.
+ */
+
+ iowrite32(1, &endpoint->registers[fpga_endian_reg]);
+ mmiowb(); /* Writes below are affected by the one above. */
+
+ /* Bootstrap phase I: Allocate temporary message buffer */
+
+ endpoint->num_channels = 0;
+
+ rc = xilly_setupchannels(endpoint, &tmpmem, bogus_idt, 1);
+
+ if (rc)
+ goto failed_buffers;
+
+ /* Clear the message subsystem (and counter in particular) */
+ iowrite32(0x04, &endpoint->registers[fpga_msg_ctrl_reg]);
+ mmiowb();
+
+ endpoint->idtlen = -1;
+
+ smp_wmb();
+
+ /*
+ * Set DMA 32/64 bit mode, quiesce the device (?!) and get IDT
+ * buffer size.
+ */
+ iowrite32((u32) (endpoint->dma_using_dac & 0x0001),
+ &endpoint->registers[fpga_dma_control_reg]);
+ mmiowb();
+
+ wait_event_interruptible_timeout(endpoint->ep_wait,
+ (endpoint->idtlen >= 0),
+ XILLY_TIMEOUT);
+
+ if (endpoint->idtlen < 0) {
+ pr_err("xillybus: No response from FPGA. Aborting.\n");
+ rc = -ENODEV;
+ goto failed_quiesce;
+ }
+
+ /* Enable DMA */
+ iowrite32((u32) (0x0002 | (endpoint->dma_using_dac & 0x0001)),
+ &endpoint->registers[fpga_dma_control_reg]);
+ mmiowb();
+
+ /* Bootstrap phase II: Allocate buffer for IDT and obtain it */
+ while (endpoint->idtlen >= idtbuffersize) {
+ idtbuffersize *= 2;
+ bogus_idt[6]++;
+ }
+
+ endpoint->num_channels = 1;
+
+ rc = xilly_setupchannels(endpoint, &tmpmem, bogus_idt, 2);
+
+ if (rc)
+ goto failed_idt;
+
+ smp_wmb();
+
+ rc = xilly_obtain_idt(endpoint);
+
+ if (rc)
+ goto failed_idt;
+
+ xilly_scan_idt(endpoint, &idt_handle);
+
+ if (!idt_handle.chandesc) {
+ rc = -ENODEV;
+ goto failed_idt;
+ }
+ /* Bootstrap phase III: Allocate buffers according to IDT */
+
+ rc = xilly_setupchannels(endpoint,
+ &endpoint->cleanup,
+ idt_handle.chandesc,
+ idt_handle.entries);
+
+ if (rc)
+ goto failed_idt;
+
+ smp_wmb(); /* mutex_lock below should suffice, but won't hurt.*/
+
+ /*
+ * endpoint is now completely configured. We put it on the list
+ * available to open() before registering the char device(s)
+ */
+
+ mutex_lock(&ep_list_lock);
+ list_add_tail(&endpoint->ep_list, &list_of_endpoints);
+ mutex_unlock(&ep_list_lock);
+
+ rc = xillybus_init_chrdev(endpoint, idt_handle.idt);
+
+ if (rc)
+ goto failed_chrdevs;
+
+ xillybus_do_cleanup(&tmpmem, endpoint);
+
+ return 0;
+
+failed_chrdevs:
+ mutex_lock(&ep_list_lock);
+ list_del(&endpoint->ep_list);
+ mutex_unlock(&ep_list_lock);
+
+failed_idt:
+ /* Quiesce the device. Now it's serious to do it */
+ rc = xilly_quiesce(endpoint);
+
+ if (rc)
+ return rc; /* FPGA may still DMA, so no release */
+
+ flush_workqueue(xillybus_wq);
+failed_quiesce:
+failed_buffers:
+ xillybus_do_cleanup(&tmpmem, endpoint);
+
+ return rc;
+}
+EXPORT_SYMBOL(xillybus_endpoint_discovery);
+
+void xillybus_endpoint_remove(struct xilly_endpoint *endpoint)
+{
+ xillybus_cleanup_chrdev(endpoint);
+
+ mutex_lock(&ep_list_lock);
+ list_del(&endpoint->ep_list);
+ mutex_unlock(&ep_list_lock);
+
+ xilly_quiesce(endpoint);
+
+ /*
+ * Flushing is done upon endpoint release to prevent access to memory
+ * just about to be released. This makes the quiesce complete.
+ */
+ flush_workqueue(xillybus_wq);
+}
+EXPORT_SYMBOL(xillybus_endpoint_remove);
+
+static int __init xillybus_init(void)
+{
+ int rc = 0;
+
+ mutex_init(&ep_list_lock);
+
+ xillybus_class = class_create(THIS_MODULE, xillyname);
+ if (IS_ERR(xillybus_class)) {
+ rc = PTR_ERR(xillybus_class);
+ pr_warn("xillybus: Failed to register class xillybus\n");
+
+ return rc;
+ }
+
+ xillybus_wq = alloc_workqueue(xillyname, 0, 0);
+
+ return 0; /* Success */
+}
+
+static void __exit xillybus_exit(void)
+{
+ /* flush_workqueue() was called for each endpoint released */
+ destroy_workqueue(xillybus_wq);
+
+ class_destroy(xillybus_class);
+}
+
+module_init(xillybus_init);
+module_exit(xillybus_exit);
diff --git a/drivers/staging/xillybus/xillybus_of.c b/drivers/staging/xillybus/xillybus_of.c
new file mode 100644
index 00000000000..92c2931f434
--- /dev/null
+++ b/drivers/staging/xillybus/xillybus_of.c
@@ -0,0 +1,212 @@
+/*
+ * linux/drivers/misc/xillybus_of.c
+ *
+ * Copyright 2011 Xillybus Ltd, http://xillybus.com
+ *
+ * Driver for the Xillybus FPGA/host framework using Open Firmware.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include "xillybus.h"
+
+MODULE_DESCRIPTION("Xillybus driver for Open Firmware");
+MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
+MODULE_VERSION("1.06");
+MODULE_ALIAS("xillybus_of");
+MODULE_LICENSE("GPL v2");
+
+static const char xillyname[] = "xillybus_of";
+
+/* Match table for of_platform binding */
+static struct of_device_id xillybus_of_match[] = {
+ { .compatible = "xlnx,xillybus-1.00.a", },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, xillybus_of_match);
+
+static void xilly_dma_sync_single_for_cpu_of(struct xilly_endpoint *ep,
+ dma_addr_t dma_handle,
+ size_t size,
+ int direction)
+{
+ dma_sync_single_for_cpu(ep->dev, dma_handle, size, direction);
+}
+
+static void xilly_dma_sync_single_for_device_of(struct xilly_endpoint *ep,
+ dma_addr_t dma_handle,
+ size_t size,
+ int direction)
+{
+ dma_sync_single_for_device(ep->dev, dma_handle, size, direction);
+}
+
+static dma_addr_t xilly_map_single_of(struct xilly_cleanup *mem,
+ struct xilly_endpoint *ep,
+ void *ptr,
+ size_t size,
+ int direction
+ )
+{
+
+ dma_addr_t addr = 0;
+ struct xilly_dma *this;
+
+ this = kmalloc(sizeof(struct xilly_dma), GFP_KERNEL);
+ if (!this)
+ return 0;
+
+ addr = dma_map_single(ep->dev, ptr, size, direction);
+ this->direction = direction;
+
+ if (dma_mapping_error(ep->dev, addr)) {
+ kfree(this);
+ return 0;
+ }
+
+ this->dma_addr = addr;
+ this->dev = ep->dev;
+ this->size = size;
+
+ list_add_tail(&this->node, &mem->to_unmap);
+
+ return addr;
+}
+
+static void xilly_unmap_single_of(struct xilly_dma *entry)
+{
+ dma_unmap_single(entry->dev,
+ entry->dma_addr,
+ entry->size,
+ entry->direction);
+}
+
+static struct xilly_endpoint_hardware of_hw = {
+ .owner = THIS_MODULE,
+ .hw_sync_sgl_for_cpu = xilly_dma_sync_single_for_cpu_of,
+ .hw_sync_sgl_for_device = xilly_dma_sync_single_for_device_of,
+ .map_single = xilly_map_single_of,
+ .unmap_single = xilly_unmap_single_of
+};
+
+static int xilly_drv_probe(struct platform_device *op)
+{
+ struct device *dev = &op->dev;
+ struct xilly_endpoint *endpoint;
+ int rc = 0;
+ int irq;
+
+ endpoint = xillybus_init_endpoint(NULL, dev, &of_hw);
+
+ if (!endpoint)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, endpoint);
+
+ rc = of_address_to_resource(dev->of_node, 0, &endpoint->res);
+ if (rc) {
+ pr_warn("xillybus: Failed to obtain device tree "
+ "resource\n");
+ goto failed_request_regions;
+ }
+
+ if (!request_mem_region(endpoint->res.start,
+ resource_size(&endpoint->res), xillyname)) {
+ pr_err("xillybus: request_mem_region failed. Aborting.\n");
+ rc = -EBUSY;
+ goto failed_request_regions;
+ }
+
+ endpoint->registers = of_iomap(dev->of_node, 0);
+
+ if (!endpoint->registers) {
+ pr_err("xillybus: Failed to map I/O memory. Aborting.\n");
+ goto failed_iomap0;
+ }
+
+ irq = irq_of_parse_and_map(dev->of_node, 0);
+
+ rc = request_irq(irq, xillybus_isr, 0, xillyname, endpoint);
+
+ if (rc) {
+ pr_err("xillybus: Failed to register IRQ handler. "
+ "Aborting.\n");
+ rc = -ENODEV;
+ goto failed_register_irq;
+ }
+
+ rc = xillybus_endpoint_discovery(endpoint);
+
+ if (!rc)
+ return 0;
+
+ free_irq(irq, endpoint);
+
+failed_register_irq:
+ iounmap(endpoint->registers);
+failed_iomap0:
+ release_mem_region(endpoint->res.start,
+ resource_size(&endpoint->res));
+
+failed_request_regions:
+ xillybus_do_cleanup(&endpoint->cleanup, endpoint);
+
+ kfree(endpoint);
+ return rc;
+}
+
+static int xilly_drv_remove(struct platform_device *op)
+{
+ struct device *dev = &op->dev;
+ struct xilly_endpoint *endpoint = dev_get_drvdata(dev);
+ int irq = irq_of_parse_and_map(dev->of_node, 0);
+
+ xillybus_endpoint_remove(endpoint);
+
+ free_irq(irq, endpoint);
+
+ iounmap(endpoint->registers);
+ release_mem_region(endpoint->res.start,
+ resource_size(&endpoint->res));
+
+ xillybus_do_cleanup(&endpoint->cleanup, endpoint);
+
+ kfree(endpoint);
+
+ return 0;
+}
+
+static struct platform_driver xillybus_platform_driver = {
+ .probe = xilly_drv_probe,
+ .remove = xilly_drv_remove,
+ .driver = {
+ .name = xillyname,
+ .owner = THIS_MODULE,
+ .of_match_table = xillybus_of_match,
+ },
+};
+
+static int __init xillybus_of_init(void)
+{
+ return platform_driver_register(&xillybus_platform_driver);
+}
+
+static void __exit xillybus_of_exit(void)
+{
+ platform_driver_unregister(&xillybus_platform_driver);
+}
+
+module_init(xillybus_of_init);
+module_exit(xillybus_of_exit);
diff --git a/drivers/staging/xillybus/xillybus_pcie.c b/drivers/staging/xillybus/xillybus_pcie.c
new file mode 100644
index 00000000000..67013652358
--- /dev/null
+++ b/drivers/staging/xillybus/xillybus_pcie.c
@@ -0,0 +1,262 @@
+/*
+ * linux/drivers/misc/xillybus_pcie.c
+ *
+ * Copyright 2011 Xillybus Ltd, http://xillybus.com
+ *
+ * Driver for the Xillybus FPGA/host framework using PCI Express.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
+#include <linux/slab.h>
+#include "xillybus.h"
+
+MODULE_DESCRIPTION("Xillybus driver for PCIe");
+MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
+MODULE_VERSION("1.06");
+MODULE_ALIAS("xillybus_pcie");
+MODULE_LICENSE("GPL v2");
+
+#define PCI_DEVICE_ID_XILLYBUS 0xebeb
+
+#define PCI_VENDOR_ID_ALTERA 0x1172
+#define PCI_VENDOR_ID_ACTEL 0x11aa
+#define PCI_VENDOR_ID_LATTICE 0x1204
+
+static const char xillyname[] = "xillybus_pcie";
+
+static DEFINE_PCI_DEVICE_TABLE(xillyids) = {
+ {PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILLYBUS)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ALTERA, PCI_DEVICE_ID_XILLYBUS)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ACTEL, PCI_DEVICE_ID_XILLYBUS)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LATTICE, PCI_DEVICE_ID_XILLYBUS)},
+ { /* End: all zeroes */ }
+};
+
+static int xilly_pci_direction(int direction)
+{
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ return PCI_DMA_TODEVICE;
+ case DMA_FROM_DEVICE:
+ return PCI_DMA_FROMDEVICE;
+ default:
+ return PCI_DMA_BIDIRECTIONAL;
+ }
+}
+
+static void xilly_dma_sync_single_for_cpu_pci(struct xilly_endpoint *ep,
+ dma_addr_t dma_handle,
+ size_t size,
+ int direction)
+{
+ pci_dma_sync_single_for_cpu(ep->pdev,
+ dma_handle,
+ size,
+ xilly_pci_direction(direction));
+}
+
+static void xilly_dma_sync_single_for_device_pci(struct xilly_endpoint *ep,
+ dma_addr_t dma_handle,
+ size_t size,
+ int direction)
+{
+ pci_dma_sync_single_for_device(ep->pdev,
+ dma_handle,
+ size,
+ xilly_pci_direction(direction));
+}
+
+/*
+ * Map either through the PCI DMA mapper or the non_PCI one. Behind the
+ * scenes exactly the same functions are called with the same parameters,
+ * but that can change.
+ */
+
+static dma_addr_t xilly_map_single_pci(struct xilly_cleanup *mem,
+ struct xilly_endpoint *ep,
+ void *ptr,
+ size_t size,
+ int direction
+ )
+{
+
+ dma_addr_t addr = 0;
+ struct xilly_dma *this;
+ int pci_direction;
+
+ this = kmalloc(sizeof(struct xilly_dma), GFP_KERNEL);
+ if (!this)
+ return 0;
+
+ pci_direction = xilly_pci_direction(direction);
+ addr = pci_map_single(ep->pdev, ptr, size, pci_direction);
+ this->direction = pci_direction;
+
+ if (pci_dma_mapping_error(ep->pdev, addr)) {
+ kfree(this);
+ return 0;
+ }
+
+ this->dma_addr = addr;
+ this->pdev = ep->pdev;
+ this->size = size;
+
+ list_add_tail(&this->node, &mem->to_unmap);
+
+ return addr;
+}
+
+static void xilly_unmap_single_pci(struct xilly_dma *entry)
+{
+ pci_unmap_single(entry->pdev,
+ entry->dma_addr,
+ entry->size,
+ entry->direction);
+}
+
+static struct xilly_endpoint_hardware pci_hw = {
+ .owner = THIS_MODULE,
+ .hw_sync_sgl_for_cpu = xilly_dma_sync_single_for_cpu_pci,
+ .hw_sync_sgl_for_device = xilly_dma_sync_single_for_device_pci,
+ .map_single = xilly_map_single_pci,
+ .unmap_single = xilly_unmap_single_pci
+};
+
+static int xilly_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct xilly_endpoint *endpoint;
+ int rc = 0;
+
+ endpoint = xillybus_init_endpoint(pdev, NULL, &pci_hw);
+
+ if (!endpoint)
+ return -ENOMEM;
+
+ pci_set_drvdata(pdev, endpoint);
+
+ rc = pci_enable_device(pdev);
+
+ /* L0s has caused packet drops. No power saving, thank you. */
+
+ pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S);
+
+ if (rc) {
+ pr_err("xillybus: pci_enable_device() failed. "
+ "Aborting.\n");
+ goto no_enable;
+ }
+
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+ pr_err("xillybus: Incorrect BAR configuration. "
+ "Aborting.\n");
+ rc = -ENODEV;
+ goto bad_bar;
+ }
+
+ rc = pci_request_regions(pdev, xillyname);
+ if (rc) {
+ pr_err("xillybus: pci_request_regions() failed. "
+ "Aborting.\n");
+ goto failed_request_regions;
+ }
+
+ endpoint->registers = pci_iomap(pdev, 0, 128);
+
+ if (!endpoint->registers) {
+ pr_err("xillybus: Failed to map BAR 0. Aborting.\n");
+ goto failed_iomap0;
+ }
+
+ pci_set_master(pdev);
+
+ /* Set up a single MSI interrupt */
+ if (pci_enable_msi(pdev)) {
+ pr_err("xillybus: Failed to enable MSI interrupts. "
+ "Aborting.\n");
+ rc = -ENODEV;
+ goto failed_enable_msi;
+ }
+ rc = request_irq(pdev->irq, xillybus_isr, 0, xillyname, endpoint);
+
+ if (rc) {
+ pr_err("xillybus: Failed to register MSI handler. "
+ "Aborting.\n");
+ rc = -ENODEV;
+ goto failed_register_msi;
+ }
+
+ /*
+ * In theory, an attempt to set the DMA mask to 64 and dma_using_dac=1
+ * is the right thing. But some unclever PCIe drivers report it's OK
+ * when the hardware drops those 64-bit PCIe packets. So trust
+ * nobody and use 32 bits DMA addressing in any case.
+ */
+
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
+ endpoint->dma_using_dac = 0;
+ else {
+ pr_err("xillybus: Failed to set DMA mask. "
+ "Aborting.\n");
+ rc = -ENODEV;
+ goto failed_dmamask;
+ }
+
+ rc = xillybus_endpoint_discovery(endpoint);
+
+ if (!rc)
+ return 0;
+
+failed_dmamask:
+ free_irq(pdev->irq, endpoint);
+failed_register_msi:
+ pci_disable_msi(pdev);
+failed_enable_msi:
+ /* pci_clear_master(pdev); Nobody else seems to do this */
+ pci_iounmap(pdev, endpoint->registers);
+failed_iomap0:
+ pci_release_regions(pdev);
+failed_request_regions:
+bad_bar:
+ pci_disable_device(pdev);
+no_enable:
+ xillybus_do_cleanup(&endpoint->cleanup, endpoint);
+
+ kfree(endpoint);
+ return rc;
+}
+
+static void xilly_remove(struct pci_dev *pdev)
+{
+ struct xilly_endpoint *endpoint = pci_get_drvdata(pdev);
+
+ xillybus_endpoint_remove(endpoint);
+
+ free_irq(pdev->irq, endpoint);
+
+ pci_disable_msi(pdev);
+ pci_iounmap(pdev, endpoint->registers);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+
+ xillybus_do_cleanup(&endpoint->cleanup, endpoint);
+
+ kfree(endpoint);
+}
+
+MODULE_DEVICE_TABLE(pci, xillyids);
+
+static struct pci_driver xillybus_driver = {
+ .name = xillyname,
+ .id_table = xillyids,
+ .probe = xilly_probe,
+ .remove = xilly_remove,
+};
+
+module_pci_driver(xillybus_driver);
diff --git a/drivers/staging/zcache/Kconfig b/drivers/staging/zcache/Kconfig
deleted file mode 100644
index 2d7b2da3b9e..00000000000
--- a/drivers/staging/zcache/Kconfig
+++ /dev/null
@@ -1,59 +0,0 @@
-config ZCACHE
- tristate "Dynamic compression of swap pages and clean pagecache pages"
- depends on CRYPTO=y && SWAP=y && CLEANCACHE && FRONTSWAP
- select CRYPTO_LZO
- default n
- help
- Zcache doubles RAM efficiency while providing a significant
- performance boosts on many workloads. Zcache uses
- compression and an in-kernel implementation of transcendent
- memory to store clean page cache pages and swap in RAM,
- providing a noticeable reduction in disk I/O.
-
-config ZCACHE_DEBUG
- bool "Enable debug statistics"
- depends on DEBUG_FS && ZCACHE
- default n
- help
- This is used to provide an debugfs directory with counters of
- how zcache is doing. You probably want to set this to 'N'.
-
-config RAMSTER
- tristate "Cross-machine RAM capacity sharing, aka peer-to-peer tmem"
- depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE
- depends on NET
- # must ensure struct page is 8-byte aligned
- select HAVE_ALIGNED_STRUCT_PAGE if !64BIT
- default n
- help
- RAMster allows RAM on other machines in a cluster to be utilized
- dynamically and symmetrically instead of swapping to a local swap
- disk, thus improving performance on memory-constrained workloads
- while minimizing total RAM across the cluster. RAMster, like
- zcache2, compresses swap pages into local RAM, but then remotifies
- the compressed pages to another node in the RAMster cluster.
-
-config RAMSTER_DEBUG
- bool "Enable ramster debug statistics"
- depends on DEBUG_FS && RAMSTER
- default n
- help
- This is used to provide an debugfs directory with counters of
- how ramster is doing. You probably want to set this to 'N'.
-
-# Depends on not-yet-upstreamed mm patches to export end_swap_bio_write and
-# __add_to_swap_cache, and implement __swap_writepage (which is swap_writepage
-# without the frontswap call. When these are in-tree, the dependency on
-# BROKEN can be removed
-config ZCACHE_WRITEBACK
- bool "Allow compressed swap pages to be writtenback to swap disk"
- depends on ZCACHE=y && BROKEN
- default n
- help
- Zcache caches compressed swap pages (and other data) in RAM which
- often improves performance by avoiding I/O's due to swapping.
- In some workloads with very long-lived large processes, it can
- instead reduce performance. Writeback decompresses zcache-compressed
- pages (in LRU order) when under memory pressure and writes them to
- the backing swap disk to ameliorate this problem. Policy driving
- writeback is still under development.
diff --git a/drivers/staging/zcache/Makefile b/drivers/staging/zcache/Makefile
deleted file mode 100644
index 845a5c2721b..00000000000
--- a/drivers/staging/zcache/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-zcache-y := zcache-main.o tmem.o zbud.o
-zcache-$(CONFIG_ZCACHE_DEBUG) += debug.o
-zcache-$(CONFIG_RAMSTER_DEBUG) += ramster/debug.o
-zcache-$(CONFIG_RAMSTER) += ramster/ramster.o ramster/r2net.o
-zcache-$(CONFIG_RAMSTER) += ramster/nodemanager.o ramster/tcp.o
-zcache-$(CONFIG_RAMSTER) += ramster/heartbeat.o ramster/masklog.o
-
-obj-$(CONFIG_ZCACHE) += zcache.o
diff --git a/drivers/staging/zcache/TODO b/drivers/staging/zcache/TODO
deleted file mode 100644
index d0c18fa9574..00000000000
--- a/drivers/staging/zcache/TODO
+++ /dev/null
@@ -1,64 +0,0 @@
-
-** ZCACHE PLAN FOR PROMOTION FROM STAGING **
-
-Last updated: Feb 13, 2013
-
-PLAN STEPS
-
-1. merge zcache and ramster to eliminate horrible code duplication
-2. converge on a predictable, writeback-capable allocator
-3. use debugfs instead of sysfs (per akpm feedback in 2011)
-4. zcache side of cleancache/mm WasActive patch
-5. zcache side of frontswap exclusive gets
-6. zcache must be able to writeback to physical swap disk
- (per Andrea Arcangeli feedback in 2011)
-7. implement adequate policy for writeback
-8. frontswap/cleancache work to allow zcache to be loaded
- as a module
-9. get core mm developer to review
-10. incorporate feedback from review
-11. get review/acks from 1-2 additional mm developers
-12. incorporate any feedback from additional mm reviews
-13. propose location/file-naming in mm tree
-14. repeat 9-13 as necessary until akpm is happy and merges
-
-STATUS/OWNERSHIP
-
-1. DONE as part of "new" zcache; in staging/zcache for 3.9
-2. DONE as part of "new" zcache (cf zbud.[ch]); in staging/zcache for 3.9
- (this was the core of the zcache1 vs zcache2 flail)
-3. DONE as part of "new" zcache; in staging/zcache for 3.9
-4. DONE (w/caveats) as part of "new" zcache; per cleancache performance
- feedback see https://lkml.org/lkml/2011/8/17/351, in
- staging/zcache for 3.9; dependent on proposed mm patch, see
- https://lkml.org/lkml/2012/1/25/300
-5. DONE as part of "new" zcache; performance tuning only,
- in staging/zcache for 3.9; dependent on frontswap patch
- merged in 3.7 (33c2a174)
-6. DONE (w/caveats), prototyped as part of "new" zcache, had
- bad memory leak; reimplemented to use sjennings clever tricks
- and proposed mm patches with new version in staging/zcache
- for 3.9, see https://lkml.org/lkml/2013/2/6/437;
-7. PROTOTYPED as part of "new" zcache; in staging/zcache for 3.9;
- needs more review (plan to discuss at LSF/MM 2013)
-9. IN PROGRESS; owned by Konrad Wilk; Mel Gorman provided
- great feedback in August 2012 (unfortunately of "old"
- zcache)
-11. NOT DONE; owned by Konrad Wilk and Bob Liu
-12. TBD (depends on quantity of feedback)
-13. PROPOSED; one suggestion proposed by Dan; needs more ideas/feedback
-14. TBD (depends on feedback)
-
-WHO NEEDS TO AGREE
-
-Not sure. Seth Jennings is now pursuing a separate but semi-parallel
-track. Akpm clearly has to approve for any mm merge to happen. Minchan
-Kim has interest but may be happy if/when zram is merged into mm. Konrad
-Wilk may be maintainer if akpm decides compression is maintainable
-separately from the rest of mm. (More LSF/MM 2013 discussion.)
-
-ZCACHE FUTURE NEW FUNCTIONALITY
-
-A. Support zsmalloc as an alternative high-density allocator
- (See https://lkml.org/lkml/2013/1/23/511)
-B. Possibly support three zbuds per pageframe when space allows
diff --git a/drivers/staging/zcache/debug.c b/drivers/staging/zcache/debug.c
deleted file mode 100644
index daa26919b88..00000000000
--- a/drivers/staging/zcache/debug.c
+++ /dev/null
@@ -1,107 +0,0 @@
-#include <linux/atomic.h>
-#include "debug.h"
-
-#ifdef CONFIG_ZCACHE_DEBUG
-#include <linux/debugfs.h>
-
-ssize_t zcache_obj_count;
-ssize_t zcache_obj_count_max;
-ssize_t zcache_objnode_count;
-ssize_t zcache_objnode_count_max;
-u64 zcache_eph_zbytes;
-u64 zcache_eph_zbytes_max;
-u64 zcache_pers_zbytes_max;
-ssize_t zcache_eph_pageframes_max;
-ssize_t zcache_pers_pageframes_max;
-ssize_t zcache_pageframes_alloced;
-ssize_t zcache_pageframes_freed;
-ssize_t zcache_eph_zpages;
-ssize_t zcache_eph_zpages_max;
-ssize_t zcache_pers_zpages_max;
-ssize_t zcache_flush_total;
-ssize_t zcache_flush_found;
-ssize_t zcache_flobj_total;
-ssize_t zcache_flobj_found;
-ssize_t zcache_failed_eph_puts;
-ssize_t zcache_failed_pers_puts;
-ssize_t zcache_failed_getfreepages;
-ssize_t zcache_failed_alloc;
-ssize_t zcache_put_to_flush;
-ssize_t zcache_compress_poor;
-ssize_t zcache_mean_compress_poor;
-ssize_t zcache_eph_ate_tail;
-ssize_t zcache_eph_ate_tail_failed;
-ssize_t zcache_pers_ate_eph;
-ssize_t zcache_pers_ate_eph_failed;
-ssize_t zcache_evicted_eph_zpages;
-ssize_t zcache_evicted_eph_pageframes;
-ssize_t zcache_zero_filled_pages;
-ssize_t zcache_zero_filled_pages_max;
-
-#define ATTR(x) { .name = #x, .val = &zcache_##x, }
-static struct debug_entry {
- const char *name;
- ssize_t *val;
-} attrs[] = {
- ATTR(obj_count), ATTR(obj_count_max),
- ATTR(objnode_count), ATTR(objnode_count_max),
- ATTR(flush_total), ATTR(flush_found),
- ATTR(flobj_total), ATTR(flobj_found),
- ATTR(failed_eph_puts), ATTR(failed_pers_puts),
- ATTR(failed_getfreepages), ATTR(failed_alloc),
- ATTR(put_to_flush),
- ATTR(compress_poor), ATTR(mean_compress_poor),
- ATTR(eph_ate_tail), ATTR(eph_ate_tail_failed),
- ATTR(pers_ate_eph), ATTR(pers_ate_eph_failed),
- ATTR(evicted_eph_zpages), ATTR(evicted_eph_pageframes),
- ATTR(eph_pageframes), ATTR(eph_pageframes_max),
- ATTR(pers_pageframes), ATTR(pers_pageframes_max),
- ATTR(eph_zpages), ATTR(eph_zpages_max),
- ATTR(pers_zpages), ATTR(pers_zpages_max),
- ATTR(last_active_file_pageframes),
- ATTR(last_inactive_file_pageframes),
- ATTR(last_active_anon_pageframes),
- ATTR(last_inactive_anon_pageframes),
- ATTR(eph_nonactive_puts_ignored),
- ATTR(pers_nonactive_puts_ignored),
- ATTR(zero_filled_pages),
-#ifdef CONFIG_ZCACHE_WRITEBACK
- ATTR(outstanding_writeback_pages),
- ATTR(writtenback_pages),
-#endif
-};
-#undef ATTR
-int zcache_debugfs_init(void)
-{
- unsigned int i;
- struct dentry *root = debugfs_create_dir("zcache", NULL);
- if (root == NULL)
- return -ENXIO;
-
- for (i = 0; i < ARRAY_SIZE(attrs); i++)
- if (!debugfs_create_size_t(attrs[i].name, S_IRUGO, root, attrs[i].val))
- goto out;
-
- debugfs_create_u64("eph_zbytes", S_IRUGO, root, &zcache_eph_zbytes);
- debugfs_create_u64("eph_zbytes_max", S_IRUGO, root, &zcache_eph_zbytes_max);
- debugfs_create_u64("pers_zbytes", S_IRUGO, root, &zcache_pers_zbytes);
- debugfs_create_u64("pers_zbytes_max", S_IRUGO, root, &zcache_pers_zbytes_max);
-
- return 0;
-out:
- return -ENODEV;
-}
-
-/* developers can call this in case of ooms, e.g. to find memory leaks */
-void zcache_dump(void)
-{
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(attrs); i++)
- pr_debug("zcache: %s=%zu\n", attrs[i].name, *attrs[i].val);
-
- pr_debug("zcache: eph_zbytes=%llu\n", (unsigned long long)zcache_eph_zbytes);
- pr_debug("zcache: eph_zbytes_max=%llu\n", (unsigned long long)zcache_eph_zbytes_max);
- pr_debug("zcache: pers_zbytes=%llu\n", (unsigned long long)zcache_pers_zbytes);
- pr_debug("zcache: pers_zbytes_max=%llu\n", (unsigned long long)zcache_pers_zbytes_max);
-}
-#endif
diff --git a/drivers/staging/zcache/debug.h b/drivers/staging/zcache/debug.h
deleted file mode 100644
index 8088d28f2dc..00000000000
--- a/drivers/staging/zcache/debug.h
+++ /dev/null
@@ -1,305 +0,0 @@
-#include <linux/bug.h>
-
-#ifdef CONFIG_ZCACHE_DEBUG
-
-/* we try to keep these statistics SMP-consistent */
-extern ssize_t zcache_obj_count;
-static atomic_t zcache_obj_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_obj_count_max;
-static inline void inc_zcache_obj_count(void)
-{
- zcache_obj_count = atomic_inc_return(&zcache_obj_atomic);
- if (zcache_obj_count > zcache_obj_count_max)
- zcache_obj_count_max = zcache_obj_count;
-}
-static inline void dec_zcache_obj_count(void)
-{
- zcache_obj_count = atomic_dec_return(&zcache_obj_atomic);
- BUG_ON(zcache_obj_count < 0);
-};
-extern ssize_t zcache_objnode_count;
-static atomic_t zcache_objnode_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_objnode_count_max;
-static inline void inc_zcache_objnode_count(void)
-{
- zcache_objnode_count = atomic_inc_return(&zcache_objnode_atomic);
- if (zcache_objnode_count > zcache_objnode_count_max)
- zcache_objnode_count_max = zcache_objnode_count;
-};
-static inline void dec_zcache_objnode_count(void)
-{
- zcache_objnode_count = atomic_dec_return(&zcache_objnode_atomic);
- BUG_ON(zcache_objnode_count < 0);
-};
-extern u64 zcache_eph_zbytes;
-static atomic_long_t zcache_eph_zbytes_atomic = ATOMIC_INIT(0);
-extern u64 zcache_eph_zbytes_max;
-static inline void inc_zcache_eph_zbytes(unsigned clen)
-{
- zcache_eph_zbytes = atomic_long_add_return(clen, &zcache_eph_zbytes_atomic);
- if (zcache_eph_zbytes > zcache_eph_zbytes_max)
- zcache_eph_zbytes_max = zcache_eph_zbytes;
-};
-static inline void dec_zcache_eph_zbytes(unsigned zsize)
-{
- zcache_eph_zbytes = atomic_long_sub_return(zsize, &zcache_eph_zbytes_atomic);
-};
-extern u64 zcache_pers_zbytes;
-static atomic_long_t zcache_pers_zbytes_atomic = ATOMIC_INIT(0);
-extern u64 zcache_pers_zbytes_max;
-static inline void inc_zcache_pers_zbytes(unsigned clen)
-{
- zcache_pers_zbytes = atomic_long_add_return(clen, &zcache_pers_zbytes_atomic);
- if (zcache_pers_zbytes > zcache_pers_zbytes_max)
- zcache_pers_zbytes_max = zcache_pers_zbytes;
-}
-static inline void dec_zcache_pers_zbytes(unsigned zsize)
-{
- zcache_pers_zbytes = atomic_long_sub_return(zsize, &zcache_pers_zbytes_atomic);
-}
-extern ssize_t zcache_eph_pageframes;
-static atomic_t zcache_eph_pageframes_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_eph_pageframes_max;
-static inline void inc_zcache_eph_pageframes(void)
-{
- zcache_eph_pageframes = atomic_inc_return(&zcache_eph_pageframes_atomic);
- if (zcache_eph_pageframes > zcache_eph_pageframes_max)
- zcache_eph_pageframes_max = zcache_eph_pageframes;
-};
-static inline void dec_zcache_eph_pageframes(void)
-{
- zcache_eph_pageframes = atomic_dec_return(&zcache_eph_pageframes_atomic);
-};
-extern ssize_t zcache_pers_pageframes;
-static atomic_t zcache_pers_pageframes_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_pers_pageframes_max;
-static inline void inc_zcache_pers_pageframes(void)
-{
- zcache_pers_pageframes = atomic_inc_return(&zcache_pers_pageframes_atomic);
- if (zcache_pers_pageframes > zcache_pers_pageframes_max)
- zcache_pers_pageframes_max = zcache_pers_pageframes;
-}
-static inline void dec_zcache_pers_pageframes(void)
-{
- zcache_pers_pageframes = atomic_dec_return(&zcache_pers_pageframes_atomic);
-}
-extern ssize_t zcache_pageframes_alloced;
-static atomic_t zcache_pageframes_alloced_atomic = ATOMIC_INIT(0);
-static inline void inc_zcache_pageframes_alloced(void)
-{
- zcache_pageframes_alloced = atomic_inc_return(&zcache_pageframes_alloced_atomic);
-};
-extern ssize_t zcache_pageframes_freed;
-static atomic_t zcache_pageframes_freed_atomic = ATOMIC_INIT(0);
-static inline void inc_zcache_pageframes_freed(void)
-{
- zcache_pageframes_freed = atomic_inc_return(&zcache_pageframes_freed_atomic);
-}
-extern ssize_t zcache_eph_zpages;
-static atomic_t zcache_eph_zpages_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_eph_zpages_max;
-static inline void inc_zcache_eph_zpages(void)
-{
- zcache_eph_zpages = atomic_inc_return(&zcache_eph_zpages_atomic);
- if (zcache_eph_zpages > zcache_eph_zpages_max)
- zcache_eph_zpages_max = zcache_eph_zpages;
-}
-static inline void dec_zcache_eph_zpages(unsigned zpages)
-{
- zcache_eph_zpages = atomic_sub_return(zpages, &zcache_eph_zpages_atomic);
-}
-extern ssize_t zcache_pers_zpages;
-static atomic_t zcache_pers_zpages_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_pers_zpages_max;
-static inline void inc_zcache_pers_zpages(void)
-{
- zcache_pers_zpages = atomic_inc_return(&zcache_pers_zpages_atomic);
- if (zcache_pers_zpages > zcache_pers_zpages_max)
- zcache_pers_zpages_max = zcache_pers_zpages;
-}
-static inline void dec_zcache_pers_zpages(unsigned zpages)
-{
- zcache_pers_zpages = atomic_sub_return(zpages, &zcache_pers_zpages_atomic);
-}
-
-extern ssize_t zcache_zero_filled_pages;
-static atomic_t zcache_zero_filled_pages_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_zero_filled_pages_max;
-static inline void inc_zcache_zero_filled_pages(void)
-{
- zcache_zero_filled_pages = atomic_inc_return(
- &zcache_zero_filled_pages_atomic);
- if (zcache_zero_filled_pages > zcache_zero_filled_pages_max)
- zcache_zero_filled_pages_max = zcache_zero_filled_pages;
-}
-static inline void dec_zcache_zero_filled_pages(void)
-{
- zcache_zero_filled_pages = atomic_dec_return(
- &zcache_zero_filled_pages_atomic);
-}
-static inline unsigned long curr_pageframes_count(void)
-{
- return zcache_pageframes_alloced -
- atomic_read(&zcache_pageframes_freed_atomic) -
- atomic_read(&zcache_eph_pageframes_atomic) -
- atomic_read(&zcache_pers_pageframes_atomic);
-};
-/* but for the rest of these, counting races are ok */
-extern ssize_t zcache_flush_total;
-extern ssize_t zcache_flush_found;
-extern ssize_t zcache_flobj_total;
-extern ssize_t zcache_flobj_found;
-extern ssize_t zcache_failed_eph_puts;
-extern ssize_t zcache_failed_pers_puts;
-extern ssize_t zcache_failed_getfreepages;
-extern ssize_t zcache_failed_alloc;
-extern ssize_t zcache_put_to_flush;
-extern ssize_t zcache_compress_poor;
-extern ssize_t zcache_mean_compress_poor;
-extern ssize_t zcache_eph_ate_tail;
-extern ssize_t zcache_eph_ate_tail_failed;
-extern ssize_t zcache_pers_ate_eph;
-extern ssize_t zcache_pers_ate_eph_failed;
-extern ssize_t zcache_evicted_eph_zpages;
-extern ssize_t zcache_evicted_eph_pageframes;
-
-extern ssize_t zcache_last_active_file_pageframes;
-extern ssize_t zcache_last_inactive_file_pageframes;
-extern ssize_t zcache_last_active_anon_pageframes;
-extern ssize_t zcache_last_inactive_anon_pageframes;
-static ssize_t zcache_eph_nonactive_puts_ignored;
-static ssize_t zcache_pers_nonactive_puts_ignored;
-#ifdef CONFIG_ZCACHE_WRITEBACK
-extern ssize_t zcache_writtenback_pages;
-extern ssize_t zcache_outstanding_writeback_pages;
-#endif
-
-static inline void inc_zcache_flush_total(void)
-{
- zcache_flush_total++;
-};
-static inline void inc_zcache_flush_found(void)
-{
- zcache_flush_found++;
-};
-static inline void inc_zcache_flobj_total(void)
-{
- zcache_flobj_total++;
-};
-static inline void inc_zcache_flobj_found(void)
-{
- zcache_flobj_found++;
-};
-static inline void inc_zcache_failed_eph_puts(void)
-{
- zcache_failed_eph_puts++;
-};
-static inline void inc_zcache_failed_pers_puts(void)
-{
- zcache_failed_pers_puts++;
-};
-static inline void inc_zcache_failed_getfreepages(void)
-{
- zcache_failed_getfreepages++;
-};
-static inline void inc_zcache_failed_alloc(void)
-{
- zcache_failed_alloc++;
-};
-static inline void inc_zcache_put_to_flush(void)
-{
- zcache_put_to_flush++;
-};
-static inline void inc_zcache_compress_poor(void)
-{
- zcache_compress_poor++;
-};
-static inline void inc_zcache_mean_compress_poor(void)
-{
- zcache_mean_compress_poor++;
-};
-static inline void inc_zcache_eph_ate_tail(void)
-{
- zcache_eph_ate_tail++;
-};
-static inline void inc_zcache_eph_ate_tail_failed(void)
-{
- zcache_eph_ate_tail_failed++;
-};
-static inline void inc_zcache_pers_ate_eph(void)
-{
- zcache_pers_ate_eph++;
-};
-static inline void inc_zcache_pers_ate_eph_failed(void)
-{
- zcache_pers_ate_eph_failed++;
-};
-static inline void inc_zcache_evicted_eph_zpages(unsigned zpages)
-{
- zcache_evicted_eph_zpages += zpages;
-};
-static inline void inc_zcache_evicted_eph_pageframes(void)
-{
- zcache_evicted_eph_pageframes++;
-};
-
-static inline void inc_zcache_eph_nonactive_puts_ignored(void)
-{
- zcache_eph_nonactive_puts_ignored++;
-};
-static inline void inc_zcache_pers_nonactive_puts_ignored(void)
-{
- zcache_pers_nonactive_puts_ignored++;
-};
-
-int zcache_debugfs_init(void);
-#else
-static inline void inc_zcache_obj_count(void) { };
-static inline void dec_zcache_obj_count(void) { };
-static inline void inc_zcache_objnode_count(void) { };
-static inline void dec_zcache_objnode_count(void) { };
-static inline void inc_zcache_eph_zbytes(unsigned clen) { };
-static inline void dec_zcache_eph_zbytes(unsigned zsize) { };
-static inline void inc_zcache_pers_zbytes(unsigned clen) { };
-static inline void dec_zcache_pers_zbytes(unsigned zsize) { };
-static inline void inc_zcache_eph_pageframes(void) { };
-static inline void dec_zcache_eph_pageframes(void) { };
-static inline void inc_zcache_pers_pageframes(void) { };
-static inline void dec_zcache_pers_pageframes(void) { };
-static inline void inc_zcache_pageframes_alloced(void) { };
-static inline void inc_zcache_pageframes_freed(void) { };
-static inline void inc_zcache_eph_zpages(void) { };
-static inline void dec_zcache_eph_zpages(unsigned zpages) { };
-static inline void inc_zcache_pers_zpages(void) { };
-static inline void dec_zcache_pers_zpages(unsigned zpages) { };
-static inline void inc_zcache_zero_filled_pages(void) { };
-static inline void dec_zcache_zero_filled_pages(void) { };
-static inline unsigned long curr_pageframes_count(void)
-{
- return 0;
-};
-static inline int zcache_debugfs_init(void)
-{
- return 0;
-};
-static inline void inc_zcache_flush_total(void) { };
-static inline void inc_zcache_flush_found(void) { };
-static inline void inc_zcache_flobj_total(void) { };
-static inline void inc_zcache_flobj_found(void) { };
-static inline void inc_zcache_failed_eph_puts(void) { };
-static inline void inc_zcache_failed_pers_puts(void) { };
-static inline void inc_zcache_failed_getfreepages(void) { };
-static inline void inc_zcache_failed_alloc(void) { };
-static inline void inc_zcache_put_to_flush(void) { };
-static inline void inc_zcache_compress_poor(void) { };
-static inline void inc_zcache_mean_compress_poor(void) { };
-static inline void inc_zcache_eph_ate_tail(void) { };
-static inline void inc_zcache_eph_ate_tail_failed(void) { };
-static inline void inc_zcache_pers_ate_eph(void) { };
-static inline void inc_zcache_pers_ate_eph_failed(void) { };
-static inline void inc_zcache_evicted_eph_zpages(unsigned zpages) { };
-static inline void inc_zcache_evicted_eph_pageframes(void) { };
-
-static inline void inc_zcache_eph_nonactive_puts_ignored(void) { };
-static inline void inc_zcache_pers_nonactive_puts_ignored(void) { };
-#endif
diff --git a/drivers/staging/zcache/ramster.h b/drivers/staging/zcache/ramster.h
deleted file mode 100644
index a858666eae6..00000000000
--- a/drivers/staging/zcache/ramster.h
+++ /dev/null
@@ -1,59 +0,0 @@
-
-/*
- * zcache/ramster.h
- *
- * Placeholder to resolve ramster references when !CONFIG_RAMSTER
- * Real ramster.h lives in ramster subdirectory.
- *
- * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
- */
-
-#ifndef _ZCACHE_RAMSTER_H_
-#define _ZCACHE_RAMSTER_H_
-
-#ifdef CONFIG_RAMSTER
-#include "ramster/ramster.h"
-#else
-static inline void ramster_init(bool x, bool y, bool z, bool w)
-{
-}
-
-static inline void ramster_register_pamops(struct tmem_pamops *p)
-{
-}
-
-static inline int ramster_remotify_pageframe(bool b)
-{
- return 0;
-}
-
-static inline void *ramster_pampd_free(void *v, struct tmem_pool *p,
- struct tmem_oid *o, uint32_t u, bool b)
-{
- return NULL;
-}
-
-static inline int ramster_do_preload_flnode(struct tmem_pool *p)
-{
- return -1;
-}
-
-static inline bool pampd_is_remote(void *v)
-{
- return false;
-}
-
-static inline void ramster_count_foreign_pages(bool b, int i)
-{
-}
-
-static inline void ramster_cpu_up(int cpu)
-{
-}
-
-static inline void ramster_cpu_down(int cpu)
-{
-}
-#endif
-
-#endif /* _ZCACHE_RAMSTER_H */
diff --git a/drivers/staging/zcache/ramster/debug.c b/drivers/staging/zcache/ramster/debug.c
deleted file mode 100644
index 5b26ee977c2..00000000000
--- a/drivers/staging/zcache/ramster/debug.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <linux/atomic.h>
-#include "debug.h"
-
-ssize_t ramster_foreign_eph_pages;
-ssize_t ramster_foreign_pers_pages;
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-
-ssize_t ramster_eph_pages_remoted;
-ssize_t ramster_pers_pages_remoted;
-ssize_t ramster_eph_pages_remote_failed;
-ssize_t ramster_pers_pages_remote_failed;
-ssize_t ramster_remote_eph_pages_succ_get;
-ssize_t ramster_remote_pers_pages_succ_get;
-ssize_t ramster_remote_eph_pages_unsucc_get;
-ssize_t ramster_remote_pers_pages_unsucc_get;
-ssize_t ramster_pers_pages_remote_nomem;
-ssize_t ramster_remote_objects_flushed;
-ssize_t ramster_remote_object_flushes_failed;
-ssize_t ramster_remote_pages_flushed;
-ssize_t ramster_remote_page_flushes_failed;
-
-#define ATTR(x) { .name = #x, .val = &ramster_##x, }
-static struct debug_entry {
- const char *name;
- ssize_t *val;
-} attrs[] = {
- ATTR(eph_pages_remoted),
- ATTR(pers_pages_remoted),
- ATTR(eph_pages_remote_failed),
- ATTR(pers_pages_remote_failed),
- ATTR(remote_eph_pages_succ_get),
- ATTR(remote_pers_pages_succ_get),
- ATTR(remote_eph_pages_unsucc_get),
- ATTR(remote_pers_pages_unsucc_get),
- ATTR(pers_pages_remote_nomem),
- ATTR(remote_objects_flushed),
- ATTR(remote_pages_flushed),
- ATTR(remote_object_flushes_failed),
- ATTR(remote_page_flushes_failed),
- ATTR(foreign_eph_pages),
- ATTR(foreign_eph_pages_max),
- ATTR(foreign_pers_pages),
- ATTR(foreign_pers_pages_max),
-};
-#undef ATTR
-
-int ramster_debugfs_init(void)
-{
- int i;
- struct dentry *root = debugfs_create_dir("ramster", NULL);
- if (root == NULL)
- return -ENXIO;
-
- for (i = 0; i < ARRAY_SIZE(attrs); i++)
- if (!debugfs_create_size_t(attrs[i].name,
- S_IRUGO, root, attrs[i].val))
- goto out;
- return 0;
-out:
- return -ENODEV;
-}
-#else
-static inline int ramster_debugfs_init(void)
-{
- return 0;
-}
-#endif
diff --git a/drivers/staging/zcache/ramster/debug.h b/drivers/staging/zcache/ramster/debug.h
deleted file mode 100644
index 5ffab50807d..00000000000
--- a/drivers/staging/zcache/ramster/debug.h
+++ /dev/null
@@ -1,145 +0,0 @@
-#include <linux/bug.h>
-
-#ifdef CONFIG_RAMSTER_DEBUG
-
-extern long ramster_flnodes;
-static atomic_t ramster_flnodes_atomic = ATOMIC_INIT(0);
-static unsigned long ramster_flnodes_max;
-static inline void inc_ramster_flnodes(void)
-{
- ramster_flnodes = atomic_inc_return(&ramster_flnodes_atomic);
- if (ramster_flnodes > ramster_flnodes_max)
- ramster_flnodes_max = ramster_flnodes;
-}
-static inline void dec_ramster_flnodes(void)
-{
- ramster_flnodes = atomic_dec_return(&ramster_flnodes_atomic);
-}
-extern ssize_t ramster_foreign_eph_pages;
-static atomic_t ramster_foreign_eph_pages_atomic = ATOMIC_INIT(0);
-static ssize_t ramster_foreign_eph_pages_max;
-static inline void inc_ramster_foreign_eph_pages(void)
-{
- ramster_foreign_eph_pages = atomic_inc_return(
- &ramster_foreign_eph_pages_atomic);
- if (ramster_foreign_eph_pages > ramster_foreign_eph_pages_max)
- ramster_foreign_eph_pages_max = ramster_foreign_eph_pages;
-}
-static inline void dec_ramster_foreign_eph_pages(void)
-{
- ramster_foreign_eph_pages = atomic_dec_return(
- &ramster_foreign_eph_pages_atomic);
-}
-extern ssize_t ramster_foreign_pers_pages;
-static atomic_t ramster_foreign_pers_pages_atomic = ATOMIC_INIT(0);
-static ssize_t ramster_foreign_pers_pages_max;
-static inline void inc_ramster_foreign_pers_pages(void)
-{
- ramster_foreign_pers_pages = atomic_inc_return(
- &ramster_foreign_pers_pages_atomic);
- if (ramster_foreign_pers_pages > ramster_foreign_pers_pages_max)
- ramster_foreign_pers_pages_max = ramster_foreign_pers_pages;
-}
-static inline void dec_ramster_foreign_pers_pages(void)
-{
- ramster_foreign_pers_pages = atomic_dec_return(
- &ramster_foreign_pers_pages_atomic);
-}
-
-extern ssize_t ramster_eph_pages_remoted;
-extern ssize_t ramster_pers_pages_remoted;
-extern ssize_t ramster_eph_pages_remote_failed;
-extern ssize_t ramster_pers_pages_remote_failed;
-extern ssize_t ramster_remote_eph_pages_succ_get;
-extern ssize_t ramster_remote_pers_pages_succ_get;
-extern ssize_t ramster_remote_eph_pages_unsucc_get;
-extern ssize_t ramster_remote_pers_pages_unsucc_get;
-extern ssize_t ramster_pers_pages_remote_nomem;
-extern ssize_t ramster_remote_objects_flushed;
-extern ssize_t ramster_remote_object_flushes_failed;
-extern ssize_t ramster_remote_pages_flushed;
-extern ssize_t ramster_remote_page_flushes_failed;
-
-int ramster_debugfs_init(void);
-
-static inline void inc_ramster_eph_pages_remoted(void)
-{
- ramster_eph_pages_remoted++;
-};
-static inline void inc_ramster_pers_pages_remoted(void)
-{
- ramster_pers_pages_remoted++;
-};
-static inline void inc_ramster_eph_pages_remote_failed(void)
-{
- ramster_eph_pages_remote_failed++;
-};
-static inline void inc_ramster_pers_pages_remote_failed(void)
-{
- ramster_pers_pages_remote_failed++;
-};
-static inline void inc_ramster_remote_eph_pages_succ_get(void)
-{
- ramster_remote_eph_pages_succ_get++;
-};
-static inline void inc_ramster_remote_pers_pages_succ_get(void)
-{
- ramster_remote_pers_pages_succ_get++;
-};
-static inline void inc_ramster_remote_eph_pages_unsucc_get(void)
-{
- ramster_remote_eph_pages_unsucc_get++;
-};
-static inline void inc_ramster_remote_pers_pages_unsucc_get(void)
-{
- ramster_remote_pers_pages_unsucc_get++;
-};
-static inline void inc_ramster_pers_pages_remote_nomem(void)
-{
- ramster_pers_pages_remote_nomem++;
-};
-static inline void inc_ramster_remote_objects_flushed(void)
-{
- ramster_remote_objects_flushed++;
-};
-static inline void inc_ramster_remote_object_flushes_failed(void)
-{
- ramster_remote_object_flushes_failed++;
-};
-static inline void inc_ramster_remote_pages_flushed(void)
-{
- ramster_remote_pages_flushed++;
-};
-static inline void inc_ramster_remote_page_flushes_failed(void)
-{
- ramster_remote_page_flushes_failed++;
-};
-
-#else
-
-static inline void inc_ramster_flnodes(void) { };
-static inline void dec_ramster_flnodes(void) { };
-static inline void inc_ramster_foreign_eph_pages(void) { };
-static inline void dec_ramster_foreign_eph_pages(void) { };
-static inline void inc_ramster_foreign_pers_pages(void) { };
-static inline void dec_ramster_foreign_pers_pages(void) { };
-
-static inline void inc_ramster_eph_pages_remoted(void) { };
-static inline void inc_ramster_pers_pages_remoted(void) { };
-static inline void inc_ramster_eph_pages_remote_failed(void) { };
-static inline void inc_ramster_pers_pages_remote_failed(void) { };
-static inline void inc_ramster_remote_eph_pages_succ_get(void) { };
-static inline void inc_ramster_remote_pers_pages_succ_get(void) { };
-static inline void inc_ramster_remote_eph_pages_unsucc_get(void) { };
-static inline void inc_ramster_remote_pers_pages_unsucc_get(void) { };
-static inline void inc_ramster_pers_pages_remote_nomem(void) { };
-static inline void inc_ramster_remote_objects_flushed(void) { };
-static inline void inc_ramster_remote_object_flushes_failed(void) { };
-static inline void inc_ramster_remote_pages_flushed(void) { };
-static inline void inc_ramster_remote_page_flushes_failed(void) { };
-
-static inline int ramster_debugfs_init(void)
-{
- return 0;
-}
-#endif
diff --git a/drivers/staging/zcache/ramster/heartbeat.c b/drivers/staging/zcache/ramster/heartbeat.c
deleted file mode 100644
index 75d3fe80b05..00000000000
--- a/drivers/staging/zcache/ramster/heartbeat.c
+++ /dev/null
@@ -1,462 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * Copyright (C) 2004, 2005, 2012 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/configfs.h>
-
-#include "heartbeat.h"
-#include "tcp.h"
-#include "nodemanager.h"
-
-#include "masklog.h"
-
-/*
- * The first heartbeat pass had one global thread that would serialize all hb
- * callback calls. This global serializing sem should only be removed once
- * we've made sure that all callees can deal with being called concurrently
- * from multiple hb region threads.
- */
-static DECLARE_RWSEM(r2hb_callback_sem);
-
-/*
- * multiple hb threads are watching multiple regions. A node is live
- * whenever any of the threads sees activity from the node in its region.
- */
-static DEFINE_SPINLOCK(r2hb_live_lock);
-static unsigned long r2hb_live_node_bitmap[BITS_TO_LONGS(R2NM_MAX_NODES)];
-
-static struct r2hb_callback {
- struct list_head list;
-} r2hb_callbacks[R2HB_NUM_CB];
-
-enum r2hb_heartbeat_modes {
- R2HB_HEARTBEAT_LOCAL = 0,
- R2HB_HEARTBEAT_GLOBAL,
- R2HB_HEARTBEAT_NUM_MODES,
-};
-
-char *r2hb_heartbeat_mode_desc[R2HB_HEARTBEAT_NUM_MODES] = {
- "local", /* R2HB_HEARTBEAT_LOCAL */
- "global", /* R2HB_HEARTBEAT_GLOBAL */
-};
-
-unsigned int r2hb_dead_threshold = R2HB_DEFAULT_DEAD_THRESHOLD;
-unsigned int r2hb_heartbeat_mode = R2HB_HEARTBEAT_LOCAL;
-
-/* Only sets a new threshold if there are no active regions.
- *
- * No locking or otherwise interesting code is required for reading
- * r2hb_dead_threshold as it can't change once regions are active and
- * it's not interesting to anyone until then anyway. */
-static void r2hb_dead_threshold_set(unsigned int threshold)
-{
- if (threshold > R2HB_MIN_DEAD_THRESHOLD) {
- spin_lock(&r2hb_live_lock);
- r2hb_dead_threshold = threshold;
- spin_unlock(&r2hb_live_lock);
- }
-}
-
-static int r2hb_global_hearbeat_mode_set(unsigned int hb_mode)
-{
- int ret = -1;
-
- if (hb_mode < R2HB_HEARTBEAT_NUM_MODES) {
- spin_lock(&r2hb_live_lock);
- r2hb_heartbeat_mode = hb_mode;
- ret = 0;
- spin_unlock(&r2hb_live_lock);
- }
-
- return ret;
-}
-
-void r2hb_exit(void)
-{
-}
-
-int r2hb_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r2hb_callbacks); i++)
- INIT_LIST_HEAD(&r2hb_callbacks[i].list);
-
- memset(r2hb_live_node_bitmap, 0, sizeof(r2hb_live_node_bitmap));
-
- return 0;
-}
-
-/* if we're already in a callback then we're already serialized by the sem */
-static void r2hb_fill_node_map_from_callback(unsigned long *map,
- unsigned bytes)
-{
- BUG_ON(bytes < (BITS_TO_LONGS(R2NM_MAX_NODES) * sizeof(unsigned long)));
-
- memcpy(map, &r2hb_live_node_bitmap, bytes);
-}
-
-/*
- * get a map of all nodes that are heartbeating in any regions
- */
-void r2hb_fill_node_map(unsigned long *map, unsigned bytes)
-{
- /* callers want to serialize this map and callbacks so that they
- * can trust that they don't miss nodes coming to the party */
- down_read(&r2hb_callback_sem);
- spin_lock(&r2hb_live_lock);
- r2hb_fill_node_map_from_callback(map, bytes);
- spin_unlock(&r2hb_live_lock);
- up_read(&r2hb_callback_sem);
-}
-EXPORT_SYMBOL_GPL(r2hb_fill_node_map);
-
-/*
- * heartbeat configfs bits. The heartbeat set is a default set under
- * the cluster set in nodemanager.c.
- */
-
-/* heartbeat set */
-
-struct r2hb_hb_group {
- struct config_group hs_group;
- /* some stuff? */
-};
-
-static struct r2hb_hb_group *to_r2hb_hb_group(struct config_group *group)
-{
- return group ?
- container_of(group, struct r2hb_hb_group, hs_group)
- : NULL;
-}
-
-static struct config_item r2hb_config_item;
-
-static struct config_item *r2hb_hb_group_make_item(struct config_group *group,
- const char *name)
-{
- int ret;
-
- if (strlen(name) > R2HB_MAX_REGION_NAME_LEN) {
- ret = -ENAMETOOLONG;
- goto free;
- }
-
- config_item_put(&r2hb_config_item);
-
- return &r2hb_config_item;
-free:
- return ERR_PTR(ret);
-}
-
-static void r2hb_hb_group_drop_item(struct config_group *group,
- struct config_item *item)
-{
- if (r2hb_global_heartbeat_active()) {
- pr_notice("ramster: Heartbeat %s on region %s (%s)\n",
- "stopped/aborted", config_item_name(item),
- "no region");
- }
-
- config_item_put(item);
-}
-
-struct r2hb_hb_group_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct r2hb_hb_group *, char *);
- ssize_t (*store)(struct r2hb_hb_group *, const char *, size_t);
-};
-
-static ssize_t r2hb_hb_group_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct r2hb_hb_group *reg = to_r2hb_hb_group(to_config_group(item));
- struct r2hb_hb_group_attribute *r2hb_hb_group_attr =
- container_of(attr, struct r2hb_hb_group_attribute, attr);
- ssize_t ret = 0;
-
- if (r2hb_hb_group_attr->show)
- ret = r2hb_hb_group_attr->show(reg, page);
- return ret;
-}
-
-static ssize_t r2hb_hb_group_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
-{
- struct r2hb_hb_group *reg = to_r2hb_hb_group(to_config_group(item));
- struct r2hb_hb_group_attribute *r2hb_hb_group_attr =
- container_of(attr, struct r2hb_hb_group_attribute, attr);
- ssize_t ret = -EINVAL;
-
- if (r2hb_hb_group_attr->store)
- ret = r2hb_hb_group_attr->store(reg, page, count);
- return ret;
-}
-
-static ssize_t r2hb_hb_group_threshold_show(struct r2hb_hb_group *group,
- char *page)
-{
- return sprintf(page, "%u\n", r2hb_dead_threshold);
-}
-
-static ssize_t r2hb_hb_group_threshold_store(struct r2hb_hb_group *group,
- const char *page,
- size_t count)
-{
- unsigned long tmp;
- char *p = (char *)page;
- int err;
-
- err = kstrtoul(p, 10, &tmp);
- if (err)
- return err;
-
- /* this will validate ranges for us. */
- r2hb_dead_threshold_set((unsigned int) tmp);
-
- return count;
-}
-
-static
-ssize_t r2hb_hb_group_mode_show(struct r2hb_hb_group *group,
- char *page)
-{
- return sprintf(page, "%s\n",
- r2hb_heartbeat_mode_desc[r2hb_heartbeat_mode]);
-}
-
-static
-ssize_t r2hb_hb_group_mode_store(struct r2hb_hb_group *group,
- const char *page, size_t count)
-{
- unsigned int i;
- int ret;
- size_t len;
-
- len = (page[count - 1] == '\n') ? count - 1 : count;
- if (!len)
- return -EINVAL;
-
- for (i = 0; i < R2HB_HEARTBEAT_NUM_MODES; ++i) {
- if (strnicmp(page, r2hb_heartbeat_mode_desc[i], len))
- continue;
-
- ret = r2hb_global_hearbeat_mode_set(i);
- if (!ret)
- pr_notice("ramster: Heartbeat mode set to %s\n",
- r2hb_heartbeat_mode_desc[i]);
- return count;
- }
-
- return -EINVAL;
-
-}
-
-static struct r2hb_hb_group_attribute r2hb_hb_group_attr_threshold = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "dead_threshold",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = r2hb_hb_group_threshold_show,
- .store = r2hb_hb_group_threshold_store,
-};
-
-static struct r2hb_hb_group_attribute r2hb_hb_group_attr_mode = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "mode",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = r2hb_hb_group_mode_show,
- .store = r2hb_hb_group_mode_store,
-};
-
-static struct configfs_attribute *r2hb_hb_group_attrs[] = {
- &r2hb_hb_group_attr_threshold.attr,
- &r2hb_hb_group_attr_mode.attr,
- NULL,
-};
-
-static struct configfs_item_operations r2hb_hearbeat_group_item_ops = {
- .show_attribute = r2hb_hb_group_show,
- .store_attribute = r2hb_hb_group_store,
-};
-
-static struct configfs_group_operations r2hb_hb_group_group_ops = {
- .make_item = r2hb_hb_group_make_item,
- .drop_item = r2hb_hb_group_drop_item,
-};
-
-static struct config_item_type r2hb_hb_group_type = {
- .ct_group_ops = &r2hb_hb_group_group_ops,
- .ct_item_ops = &r2hb_hearbeat_group_item_ops,
- .ct_attrs = r2hb_hb_group_attrs,
- .ct_owner = THIS_MODULE,
-};
-
-/* this is just here to avoid touching group in heartbeat.h which the
- * entire damn world #includes */
-struct config_group *r2hb_alloc_hb_set(void)
-{
- struct r2hb_hb_group *hs = NULL;
- struct config_group *ret = NULL;
-
- hs = kzalloc(sizeof(struct r2hb_hb_group), GFP_KERNEL);
- if (hs == NULL)
- goto out;
-
- config_group_init_type_name(&hs->hs_group, "heartbeat",
- &r2hb_hb_group_type);
-
- ret = &hs->hs_group;
-out:
- if (ret == NULL)
- kfree(hs);
- return ret;
-}
-
-void r2hb_free_hb_set(struct config_group *group)
-{
- struct r2hb_hb_group *hs = to_r2hb_hb_group(group);
- kfree(hs);
-}
-
-/* hb callback registration and issuing */
-
-static struct r2hb_callback *hbcall_from_type(enum r2hb_callback_type type)
-{
- if (type == R2HB_NUM_CB)
- return ERR_PTR(-EINVAL);
-
- return &r2hb_callbacks[type];
-}
-
-void r2hb_setup_callback(struct r2hb_callback_func *hc,
- enum r2hb_callback_type type,
- r2hb_cb_func *func,
- void *data,
- int priority)
-{
- INIT_LIST_HEAD(&hc->hc_item);
- hc->hc_func = func;
- hc->hc_data = data;
- hc->hc_priority = priority;
- hc->hc_type = type;
- hc->hc_magic = R2HB_CB_MAGIC;
-}
-EXPORT_SYMBOL_GPL(r2hb_setup_callback);
-
-int r2hb_register_callback(const char *region_uuid,
- struct r2hb_callback_func *hc)
-{
- struct r2hb_callback_func *tmp;
- struct list_head *iter;
- struct r2hb_callback *hbcall;
- int ret;
-
- BUG_ON(hc->hc_magic != R2HB_CB_MAGIC);
- BUG_ON(!list_empty(&hc->hc_item));
-
- hbcall = hbcall_from_type(hc->hc_type);
- if (IS_ERR(hbcall)) {
- ret = PTR_ERR(hbcall);
- goto out;
- }
-
- down_write(&r2hb_callback_sem);
-
- list_for_each(iter, &hbcall->list) {
- tmp = list_entry(iter, struct r2hb_callback_func, hc_item);
- if (hc->hc_priority < tmp->hc_priority) {
- list_add_tail(&hc->hc_item, iter);
- break;
- }
- }
- if (list_empty(&hc->hc_item))
- list_add_tail(&hc->hc_item, &hbcall->list);
-
- up_write(&r2hb_callback_sem);
- ret = 0;
-out:
- mlog(ML_CLUSTER, "returning %d on behalf of %p for funcs %p\n",
- ret, __builtin_return_address(0), hc);
- return ret;
-}
-EXPORT_SYMBOL_GPL(r2hb_register_callback);
-
-void r2hb_unregister_callback(const char *region_uuid,
- struct r2hb_callback_func *hc)
-{
- BUG_ON(hc->hc_magic != R2HB_CB_MAGIC);
-
- mlog(ML_CLUSTER, "on behalf of %p for funcs %p\n",
- __builtin_return_address(0), hc);
-
- /* XXX Can this happen _with_ a region reference? */
- if (list_empty(&hc->hc_item))
- return;
-
- down_write(&r2hb_callback_sem);
-
- list_del_init(&hc->hc_item);
-
- up_write(&r2hb_callback_sem);
-}
-EXPORT_SYMBOL_GPL(r2hb_unregister_callback);
-
-int r2hb_check_node_heartbeating_from_callback(u8 node_num)
-{
- unsigned long testing_map[BITS_TO_LONGS(R2NM_MAX_NODES)];
-
- r2hb_fill_node_map_from_callback(testing_map, sizeof(testing_map));
- if (!test_bit(node_num, testing_map)) {
- mlog(ML_HEARTBEAT,
- "node (%u) does not have heartbeating enabled.\n",
- node_num);
- return 0;
- }
-
- return 1;
-}
-EXPORT_SYMBOL_GPL(r2hb_check_node_heartbeating_from_callback);
-
-void r2hb_stop_all_regions(void)
-{
-}
-EXPORT_SYMBOL_GPL(r2hb_stop_all_regions);
-
-/*
- * this is just a hack until we get the plumbing which flips file systems
- * read only and drops the hb ref instead of killing the node dead.
- */
-int r2hb_global_heartbeat_active(void)
-{
- return (r2hb_heartbeat_mode == R2HB_HEARTBEAT_GLOBAL);
-}
-EXPORT_SYMBOL(r2hb_global_heartbeat_active);
-
-/* added for RAMster */
-void r2hb_manual_set_node_heartbeating(int node_num)
-{
- if (node_num < R2NM_MAX_NODES)
- set_bit(node_num, r2hb_live_node_bitmap);
-}
-EXPORT_SYMBOL(r2hb_manual_set_node_heartbeating);
diff --git a/drivers/staging/zcache/ramster/heartbeat.h b/drivers/staging/zcache/ramster/heartbeat.h
deleted file mode 100644
index 6cbc775bd63..00000000000
--- a/drivers/staging/zcache/ramster/heartbeat.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * heartbeat.h
- *
- * Function prototypes
- *
- * Copyright (C) 2004 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- *
- */
-
-#ifndef R2CLUSTER_HEARTBEAT_H
-#define R2CLUSTER_HEARTBEAT_H
-
-#define R2HB_REGION_TIMEOUT_MS 2000
-
-#define R2HB_MAX_REGION_NAME_LEN 32
-
-/* number of changes to be seen as live */
-#define R2HB_LIVE_THRESHOLD 2
-/* number of equal samples to be seen as dead */
-extern unsigned int r2hb_dead_threshold;
-#define R2HB_DEFAULT_DEAD_THRESHOLD 31
-/* Otherwise MAX_WRITE_TIMEOUT will be zero... */
-#define R2HB_MIN_DEAD_THRESHOLD 2
-#define R2HB_MAX_WRITE_TIMEOUT_MS \
- (R2HB_REGION_TIMEOUT_MS * (r2hb_dead_threshold - 1))
-
-#define R2HB_CB_MAGIC 0x51d1e4ec
-
-/* callback stuff */
-enum r2hb_callback_type {
- R2HB_NODE_DOWN_CB = 0,
- R2HB_NODE_UP_CB,
- R2HB_NUM_CB
-};
-
-struct r2nm_node;
-typedef void (r2hb_cb_func)(struct r2nm_node *, int, void *);
-
-struct r2hb_callback_func {
- u32 hc_magic;
- struct list_head hc_item;
- r2hb_cb_func *hc_func;
- void *hc_data;
- int hc_priority;
- enum r2hb_callback_type hc_type;
-};
-
-struct config_group *r2hb_alloc_hb_set(void);
-void r2hb_free_hb_set(struct config_group *group);
-
-void r2hb_setup_callback(struct r2hb_callback_func *hc,
- enum r2hb_callback_type type,
- r2hb_cb_func *func,
- void *data,
- int priority);
-int r2hb_register_callback(const char *region_uuid,
- struct r2hb_callback_func *hc);
-void r2hb_unregister_callback(const char *region_uuid,
- struct r2hb_callback_func *hc);
-void r2hb_fill_node_map(unsigned long *map,
- unsigned bytes);
-void r2hb_exit(void);
-int r2hb_init(void);
-int r2hb_check_node_heartbeating_from_callback(u8 node_num);
-void r2hb_stop_all_regions(void);
-int r2hb_get_all_regions(char *region_uuids, u8 numregions);
-int r2hb_global_heartbeat_active(void);
-void r2hb_manual_set_node_heartbeating(int);
-
-#endif /* R2CLUSTER_HEARTBEAT_H */
diff --git a/drivers/staging/zcache/ramster/masklog.c b/drivers/staging/zcache/ramster/masklog.c
deleted file mode 100644
index 1261d8579aa..00000000000
--- a/drivers/staging/zcache/ramster/masklog.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * Copyright (C) 2004, 2005, 2012 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/string.h>
-#include <linux/uaccess.h>
-
-#include "masklog.h"
-
-struct mlog_bits r2_mlog_and_bits = MLOG_BITS_RHS(MLOG_INITIAL_AND_MASK);
-EXPORT_SYMBOL_GPL(r2_mlog_and_bits);
-struct mlog_bits r2_mlog_not_bits = MLOG_BITS_RHS(0);
-EXPORT_SYMBOL_GPL(r2_mlog_not_bits);
-
-static ssize_t mlog_mask_show(u64 mask, char *buf)
-{
- char *state;
-
- if (__mlog_test_u64(mask, r2_mlog_and_bits))
- state = "allow";
- else if (__mlog_test_u64(mask, r2_mlog_not_bits))
- state = "deny";
- else
- state = "off";
-
- return snprintf(buf, PAGE_SIZE, "%s\n", state);
-}
-
-static ssize_t mlog_mask_store(u64 mask, const char *buf, size_t count)
-{
- if (!strnicmp(buf, "allow", 5)) {
- __mlog_set_u64(mask, r2_mlog_and_bits);
- __mlog_clear_u64(mask, r2_mlog_not_bits);
- } else if (!strnicmp(buf, "deny", 4)) {
- __mlog_set_u64(mask, r2_mlog_not_bits);
- __mlog_clear_u64(mask, r2_mlog_and_bits);
- } else if (!strnicmp(buf, "off", 3)) {
- __mlog_clear_u64(mask, r2_mlog_not_bits);
- __mlog_clear_u64(mask, r2_mlog_and_bits);
- } else
- return -EINVAL;
-
- return count;
-}
-
-struct mlog_attribute {
- struct attribute attr;
- u64 mask;
-};
-
-#define to_mlog_attr(_attr) container_of(_attr, struct mlog_attribute, attr)
-
-#define define_mask(_name) { \
- .attr = { \
- .name = #_name, \
- .mode = S_IRUGO | S_IWUSR, \
- }, \
- .mask = ML_##_name, \
-}
-
-static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = {
- define_mask(TCP),
- define_mask(MSG),
- define_mask(SOCKET),
- define_mask(HEARTBEAT),
- define_mask(HB_BIO),
- define_mask(DLMFS),
- define_mask(DLM),
- define_mask(DLM_DOMAIN),
- define_mask(DLM_THREAD),
- define_mask(DLM_MASTER),
- define_mask(DLM_RECOVERY),
- define_mask(DLM_GLUE),
- define_mask(VOTE),
- define_mask(CONN),
- define_mask(QUORUM),
- define_mask(BASTS),
- define_mask(CLUSTER),
- define_mask(ERROR),
- define_mask(NOTICE),
- define_mask(KTHREAD),
-};
-
-static struct attribute *mlog_attr_ptrs[MLOG_MAX_BITS] = {NULL, };
-
-static ssize_t mlog_show(struct kobject *obj, struct attribute *attr,
- char *buf)
-{
- struct mlog_attribute *mlog_attr = to_mlog_attr(attr);
-
- return mlog_mask_show(mlog_attr->mask, buf);
-}
-
-static ssize_t mlog_store(struct kobject *obj, struct attribute *attr,
- const char *buf, size_t count)
-{
- struct mlog_attribute *mlog_attr = to_mlog_attr(attr);
-
- return mlog_mask_store(mlog_attr->mask, buf, count);
-}
-
-static const struct sysfs_ops mlog_attr_ops = {
- .show = mlog_show,
- .store = mlog_store,
-};
-
-static struct kobj_type mlog_ktype = {
- .default_attrs = mlog_attr_ptrs,
- .sysfs_ops = &mlog_attr_ops,
-};
-
-static struct kset mlog_kset = {
- .kobj = {.ktype = &mlog_ktype},
-};
-
-int r2_mlog_sys_init(struct kset *r2cb_kset)
-{
- int i = 0;
-
- while (mlog_attrs[i].attr.mode) {
- mlog_attr_ptrs[i] = &mlog_attrs[i].attr;
- i++;
- }
- mlog_attr_ptrs[i] = NULL;
-
- kobject_set_name(&mlog_kset.kobj, "logmask");
- mlog_kset.kobj.kset = r2cb_kset;
- return kset_register(&mlog_kset);
-}
-
-void r2_mlog_sys_shutdown(void)
-{
- kset_unregister(&mlog_kset);
-}
diff --git a/drivers/staging/zcache/ramster/masklog.h b/drivers/staging/zcache/ramster/masklog.h
deleted file mode 100644
index 918ae110b69..00000000000
--- a/drivers/staging/zcache/ramster/masklog.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * Copyright (C) 2005, 2012 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#ifndef R2CLUSTER_MASKLOG_H
-#define R2CLUSTER_MASKLOG_H
-
-/*
- * For now this is a trivial wrapper around printk() that gives the critical
- * ability to enable sets of debugging output at run-time. In the future this
- * will almost certainly be redirected to relayfs so that it can pay a
- * substantially lower heisenberg tax.
- *
- * Callers associate the message with a bitmask and a global bitmask is
- * maintained with help from /proc. If any of the bits match the message is
- * output.
- *
- * We must have efficient bit tests on i386 and it seems gcc still emits crazy
- * code for the 64bit compare. It emits very good code for the dual unsigned
- * long tests, though, completely avoiding tests that can never pass if the
- * caller gives a constant bitmask that fills one of the longs with all 0s. So
- * the desire is to have almost all of the calls decided on by comparing just
- * one of the longs. This leads to having infrequently given bits that are
- * frequently matched in the high bits.
- *
- * _ERROR and _NOTICE are used for messages that always go to the console and
- * have appropriate KERN_ prefixes. We wrap these in our function instead of
- * just calling printk() so that this can eventually make its way through
- * relayfs along with the debugging messages. Everything else gets KERN_DEBUG.
- * The inline tests and macro dance give GCC the opportunity to quite cleverly
- * only emit the appropriage printk() when the caller passes in a constant
- * mask, as is almost always the case.
- *
- * All this bitmask nonsense is managed from the files under
- * /sys/fs/r2cb/logmask/. Reading the files gives a straightforward
- * indication of which bits are allowed (allow) or denied (off/deny).
- * ENTRY deny
- * EXIT deny
- * TCP off
- * MSG off
- * SOCKET off
- * ERROR allow
- * NOTICE allow
- *
- * Writing changes the state of a given bit and requires a strictly formatted
- * single write() call:
- *
- * write(fd, "allow", 5);
- *
- * Echoing allow/deny/off string into the logmask files can flip the bits
- * on or off as expected; here is the bash script for example:
- *
- * log_mask="/sys/fs/r2cb/log_mask"
- * for node in ENTRY EXIT TCP MSG SOCKET ERROR NOTICE; do
- * echo allow >"$log_mask"/"$node"
- * done
- *
- * The debugfs.ramster tool can also flip the bits with the -l option:
- *
- * debugfs.ramster -l TCP allow
- */
-
-/* for task_struct */
-#include <linux/sched.h>
-
-/* bits that are frequently given and infrequently matched in the low word */
-/* NOTE: If you add a flag, you need to also update masklog.c! */
-#define ML_TCP 0x0000000000000001ULL /* net cluster/tcp.c */
-#define ML_MSG 0x0000000000000002ULL /* net network messages */
-#define ML_SOCKET 0x0000000000000004ULL /* net socket lifetime */
-#define ML_HEARTBEAT 0x0000000000000008ULL /* hb all heartbeat tracking */
-#define ML_HB_BIO 0x0000000000000010ULL /* hb io tracing */
-#define ML_DLMFS 0x0000000000000020ULL /* dlm user dlmfs */
-#define ML_DLM 0x0000000000000040ULL /* dlm general debugging */
-#define ML_DLM_DOMAIN 0x0000000000000080ULL /* dlm domain debugging */
-#define ML_DLM_THREAD 0x0000000000000100ULL /* dlm domain thread */
-#define ML_DLM_MASTER 0x0000000000000200ULL /* dlm master functions */
-#define ML_DLM_RECOVERY 0x0000000000000400ULL /* dlm master functions */
-#define ML_DLM_GLUE 0x0000000000000800ULL /* ramster dlm glue layer */
-#define ML_VOTE 0x0000000000001000ULL /* ramster node messaging */
-#define ML_CONN 0x0000000000002000ULL /* net connection management */
-#define ML_QUORUM 0x0000000000004000ULL /* net connection quorum */
-#define ML_BASTS 0x0000000000008000ULL /* dlmglue asts and basts */
-#define ML_CLUSTER 0x0000000000010000ULL /* cluster stack */
-
-/* bits that are infrequently given and frequently matched in the high word */
-#define ML_ERROR 0x1000000000000000ULL /* sent to KERN_ERR */
-#define ML_NOTICE 0x2000000000000000ULL /* setn to KERN_NOTICE */
-#define ML_KTHREAD 0x4000000000000000ULL /* kernel thread activity */
-
-#define MLOG_INITIAL_AND_MASK (ML_ERROR|ML_NOTICE)
-#ifndef MLOG_MASK_PREFIX
-#define MLOG_MASK_PREFIX 0
-#endif
-
-/*
- * When logging is disabled, force the bit test to 0 for anything other
- * than errors and notices, allowing gcc to remove the code completely.
- * When enabled, allow all masks.
- */
-#if defined(CONFIG_RAMSTER_DEBUG_MASKLOG)
-#define ML_ALLOWED_BITS (~0)
-#else
-#define ML_ALLOWED_BITS (ML_ERROR|ML_NOTICE)
-#endif
-
-#define MLOG_MAX_BITS 64
-
-struct mlog_bits {
- unsigned long words[MLOG_MAX_BITS / BITS_PER_LONG];
-};
-
-extern struct mlog_bits r2_mlog_and_bits, r2_mlog_not_bits;
-
-#if BITS_PER_LONG == 32
-
-#define __mlog_test_u64(mask, bits) \
- ((u32)(mask & 0xffffffff) & bits.words[0] || \
- ((u64)(mask) >> 32) & bits.words[1])
-#define __mlog_set_u64(mask, bits) do { \
- bits.words[0] |= (u32)(mask & 0xffffffff); \
- bits.words[1] |= (u64)(mask) >> 32; \
-} while (0)
-#define __mlog_clear_u64(mask, bits) do { \
- bits.words[0] &= ~((u32)(mask & 0xffffffff)); \
- bits.words[1] &= ~((u64)(mask) >> 32); \
-} while (0)
-#define MLOG_BITS_RHS(mask) { \
- { \
- [0] = (u32)(mask & 0xffffffff), \
- [1] = (u64)(mask) >> 32, \
- } \
-}
-
-#else /* 32bit long above, 64bit long below */
-
-#define __mlog_test_u64(mask, bits) ((mask) & bits.words[0])
-#define __mlog_set_u64(mask, bits) do { \
- bits.words[0] |= (mask); \
-} while (0)
-#define __mlog_clear_u64(mask, bits) do { \
- bits.words[0] &= ~(mask); \
-} while (0)
-#define MLOG_BITS_RHS(mask) { { (mask) } }
-
-#endif
-
-/*
- * smp_processor_id() "helpfully" screams when called outside preemptible
- * regions in current kernels. sles doesn't have the variants that don't
- * scream. just do this instead of trying to guess which we're building
- * against.. *sigh*.
- */
-#define __mlog_cpu_guess ({ \
- unsigned long _cpu = get_cpu(); \
- put_cpu(); \
- _cpu; \
-})
-
-/* In the following two macros, the whitespace after the ',' just
- * before ##args is intentional. Otherwise, gcc 2.95 will eat the
- * previous token if args expands to nothing.
- */
-#define __mlog_printk(level, fmt, args...) \
- printk(level "(%s,%u,%lu):%s:%d " fmt, current->comm, \
- task_pid_nr(current), __mlog_cpu_guess, \
- __PRETTY_FUNCTION__, __LINE__ , ##args)
-
-#define mlog(mask, fmt, args...) do { \
- u64 __m = MLOG_MASK_PREFIX | (mask); \
- if ((__m & ML_ALLOWED_BITS) && \
- __mlog_test_u64(__m, r2_mlog_and_bits) && \
- !__mlog_test_u64(__m, r2_mlog_not_bits)) { \
- if (__m & ML_ERROR) \
- __mlog_printk(KERN_ERR, "ERROR: "fmt , ##args); \
- else if (__m & ML_NOTICE) \
- __mlog_printk(KERN_NOTICE, fmt , ##args); \
- else \
- __mlog_printk(KERN_INFO, fmt , ##args); \
- } \
-} while (0)
-
-#define mlog_errno(st) do { \
- int _st = (st); \
- if (_st != -ERESTARTSYS && _st != -EINTR && \
- _st != AOP_TRUNCATED_PAGE && _st != -ENOSPC) \
- mlog(ML_ERROR, "status = %lld\n", (long long)_st); \
-} while (0)
-
-#define mlog_bug_on_msg(cond, fmt, args...) do { \
- if (cond) { \
- mlog(ML_ERROR, "bug expression: " #cond "\n"); \
- mlog(ML_ERROR, fmt, ##args); \
- BUG(); \
- } \
-} while (0)
-
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-int r2_mlog_sys_init(struct kset *r2cb_subsys);
-void r2_mlog_sys_shutdown(void);
-
-#endif /* R2CLUSTER_MASKLOG_H */
diff --git a/drivers/staging/zcache/ramster/nodemanager.c b/drivers/staging/zcache/ramster/nodemanager.c
deleted file mode 100644
index 2cfe93342c0..00000000000
--- a/drivers/staging/zcache/ramster/nodemanager.c
+++ /dev/null
@@ -1,996 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * Copyright (C) 2004, 2005, 2012 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/configfs.h>
-
-#include "tcp.h"
-#include "nodemanager.h"
-#include "heartbeat.h"
-#include "masklog.h"
-
-/* for now we operate under the assertion that there can be only one
- * cluster active at a time. Changing this will require trickling
- * cluster references throughout where nodes are looked up */
-struct r2nm_cluster *r2nm_single_cluster;
-
-char *r2nm_fence_method_desc[R2NM_FENCE_METHODS] = {
- "reset", /* R2NM_FENCE_RESET */
- "panic", /* R2NM_FENCE_PANIC */
-};
-
-struct r2nm_node *r2nm_get_node_by_num(u8 node_num)
-{
- struct r2nm_node *node = NULL;
-
- if (node_num >= R2NM_MAX_NODES || r2nm_single_cluster == NULL)
- goto out;
-
- read_lock(&r2nm_single_cluster->cl_nodes_lock);
- node = r2nm_single_cluster->cl_nodes[node_num];
- if (node)
- config_item_get(&node->nd_item);
- read_unlock(&r2nm_single_cluster->cl_nodes_lock);
-out:
- return node;
-}
-EXPORT_SYMBOL_GPL(r2nm_get_node_by_num);
-
-int r2nm_configured_node_map(unsigned long *map, unsigned bytes)
-{
- struct r2nm_cluster *cluster = r2nm_single_cluster;
-
- BUG_ON(bytes < (sizeof(cluster->cl_nodes_bitmap)));
-
- if (cluster == NULL)
- return -EINVAL;
-
- read_lock(&cluster->cl_nodes_lock);
- memcpy(map, cluster->cl_nodes_bitmap, sizeof(cluster->cl_nodes_bitmap));
- read_unlock(&cluster->cl_nodes_lock);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(r2nm_configured_node_map);
-
-static struct r2nm_node *r2nm_node_ip_tree_lookup(struct r2nm_cluster *cluster,
- __be32 ip_needle,
- struct rb_node ***ret_p,
- struct rb_node **ret_parent)
-{
- struct rb_node **p = &cluster->cl_node_ip_tree.rb_node;
- struct rb_node *parent = NULL;
- struct r2nm_node *node, *ret = NULL;
-
- while (*p) {
- int cmp;
-
- parent = *p;
- node = rb_entry(parent, struct r2nm_node, nd_ip_node);
-
- cmp = memcmp(&ip_needle, &node->nd_ipv4_address,
- sizeof(ip_needle));
- if (cmp < 0)
- p = &(*p)->rb_left;
- else if (cmp > 0)
- p = &(*p)->rb_right;
- else {
- ret = node;
- break;
- }
- }
-
- if (ret_p != NULL)
- *ret_p = p;
- if (ret_parent != NULL)
- *ret_parent = parent;
-
- return ret;
-}
-
-struct r2nm_node *r2nm_get_node_by_ip(__be32 addr)
-{
- struct r2nm_node *node = NULL;
- struct r2nm_cluster *cluster = r2nm_single_cluster;
-
- if (cluster == NULL)
- goto out;
-
- read_lock(&cluster->cl_nodes_lock);
- node = r2nm_node_ip_tree_lookup(cluster, addr, NULL, NULL);
- if (node)
- config_item_get(&node->nd_item);
- read_unlock(&cluster->cl_nodes_lock);
-
-out:
- return node;
-}
-EXPORT_SYMBOL_GPL(r2nm_get_node_by_ip);
-
-void r2nm_node_put(struct r2nm_node *node)
-{
- config_item_put(&node->nd_item);
-}
-EXPORT_SYMBOL_GPL(r2nm_node_put);
-
-void r2nm_node_get(struct r2nm_node *node)
-{
- config_item_get(&node->nd_item);
-}
-EXPORT_SYMBOL_GPL(r2nm_node_get);
-
-u8 r2nm_this_node(void)
-{
- u8 node_num = R2NM_MAX_NODES;
-
- if (r2nm_single_cluster && r2nm_single_cluster->cl_has_local)
- node_num = r2nm_single_cluster->cl_local_node;
-
- return node_num;
-}
-EXPORT_SYMBOL_GPL(r2nm_this_node);
-
-/* node configfs bits */
-
-static struct r2nm_cluster *to_r2nm_cluster(struct config_item *item)
-{
- return item ?
- container_of(to_config_group(item), struct r2nm_cluster,
- cl_group)
- : NULL;
-}
-
-static struct r2nm_node *to_r2nm_node(struct config_item *item)
-{
- return item ? container_of(item, struct r2nm_node, nd_item) : NULL;
-}
-
-static void r2nm_node_release(struct config_item *item)
-{
- struct r2nm_node *node = to_r2nm_node(item);
- kfree(node);
-}
-
-static ssize_t r2nm_node_num_read(struct r2nm_node *node, char *page)
-{
- return sprintf(page, "%d\n", node->nd_num);
-}
-
-static struct r2nm_cluster *to_r2nm_cluster_from_node(struct r2nm_node *node)
-{
- /* through the first node_set .parent
- * mycluster/nodes/mynode == r2nm_cluster->r2nm_node_group->r2nm_node */
- return to_r2nm_cluster(node->nd_item.ci_parent->ci_parent);
-}
-
-enum {
- R2NM_NODE_ATTR_NUM = 0,
- R2NM_NODE_ATTR_PORT,
- R2NM_NODE_ATTR_ADDRESS,
- R2NM_NODE_ATTR_LOCAL,
-};
-
-static ssize_t r2nm_node_num_write(struct r2nm_node *node, const char *page,
- size_t count)
-{
- struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
- unsigned long tmp;
- char *p = (char *)page;
- int err;
-
- err = kstrtoul(p, 10, &tmp);
- if (err)
- return err;
-
- if (tmp >= R2NM_MAX_NODES)
- return -ERANGE;
-
- /* once we're in the cl_nodes tree networking can look us up by
- * node number and try to use our address and port attributes
- * to connect to this node.. make sure that they've been set
- * before writing the node attribute? */
- if (!test_bit(R2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
- !test_bit(R2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
- return -EINVAL; /* XXX */
-
- write_lock(&cluster->cl_nodes_lock);
- if (cluster->cl_nodes[tmp])
- p = NULL;
- else {
- cluster->cl_nodes[tmp] = node;
- node->nd_num = tmp;
- set_bit(tmp, cluster->cl_nodes_bitmap);
- }
- write_unlock(&cluster->cl_nodes_lock);
- if (p == NULL)
- return -EEXIST;
-
- return count;
-}
-static ssize_t r2nm_node_ipv4_port_read(struct r2nm_node *node, char *page)
-{
- return sprintf(page, "%u\n", ntohs(node->nd_ipv4_port));
-}
-
-static ssize_t r2nm_node_ipv4_port_write(struct r2nm_node *node,
- const char *page, size_t count)
-{
- unsigned long tmp;
- char *p = (char *)page;
- int err;
-
- err = kstrtoul(p, 10, &tmp);
- if (err)
- return err;
-
- if (tmp == 0)
- return -EINVAL;
- if (tmp >= (u16)-1)
- return -ERANGE;
-
- node->nd_ipv4_port = htons(tmp);
-
- return count;
-}
-
-static ssize_t r2nm_node_ipv4_address_read(struct r2nm_node *node, char *page)
-{
- return sprintf(page, "%pI4\n", &node->nd_ipv4_address);
-}
-
-static ssize_t r2nm_node_ipv4_address_write(struct r2nm_node *node,
- const char *page,
- size_t count)
-{
- struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
- int ret, i;
- struct rb_node **p, *parent;
- unsigned int octets[4];
- __be32 ipv4_addr = 0;
-
- ret = sscanf(page, "%3u.%3u.%3u.%3u", &octets[3], &octets[2],
- &octets[1], &octets[0]);
- if (ret != 4)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(octets); i++) {
- if (octets[i] > 255)
- return -ERANGE;
- be32_add_cpu(&ipv4_addr, octets[i] << (i * 8));
- }
-
- ret = 0;
- write_lock(&cluster->cl_nodes_lock);
- if (r2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
- ret = -EEXIST;
- else {
- rb_link_node(&node->nd_ip_node, parent, p);
- rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
- }
- write_unlock(&cluster->cl_nodes_lock);
- if (ret)
- return ret;
-
- memcpy(&node->nd_ipv4_address, &ipv4_addr, sizeof(ipv4_addr));
-
- return count;
-}
-
-static ssize_t r2nm_node_local_read(struct r2nm_node *node, char *page)
-{
- return sprintf(page, "%d\n", node->nd_local);
-}
-
-static ssize_t r2nm_node_local_write(struct r2nm_node *node, const char *page,
- size_t count)
-{
- struct r2nm_cluster *cluster = to_r2nm_cluster_from_node(node);
- unsigned long tmp;
- char *p = (char *)page;
- ssize_t ret;
- int err;
-
- err = kstrtoul(p, 10, &tmp);
- if (err)
- return err;
-
- tmp = !!tmp; /* boolean of whether this node wants to be local */
-
- /* setting local turns on networking rx for now so we require having
- * set everything else first */
- if (!test_bit(R2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
- !test_bit(R2NM_NODE_ATTR_NUM, &node->nd_set_attributes) ||
- !test_bit(R2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
- return -EINVAL; /* XXX */
-
- /* the only failure case is trying to set a new local node
- * when a different one is already set */
- if (tmp && tmp == cluster->cl_has_local &&
- cluster->cl_local_node != node->nd_num)
- return -EBUSY;
-
- /* bring up the rx thread if we're setting the new local node. */
- if (tmp && !cluster->cl_has_local) {
- ret = r2net_start_listening(node);
- if (ret)
- return ret;
- }
-
- if (!tmp && cluster->cl_has_local &&
- cluster->cl_local_node == node->nd_num) {
- r2net_stop_listening(node);
- cluster->cl_local_node = R2NM_INVALID_NODE_NUM;
- }
-
- node->nd_local = tmp;
- if (node->nd_local) {
- cluster->cl_has_local = tmp;
- cluster->cl_local_node = node->nd_num;
- }
-
- return count;
-}
-
-struct r2nm_node_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct r2nm_node *, char *);
- ssize_t (*store)(struct r2nm_node *, const char *, size_t);
-};
-
-static struct r2nm_node_attribute r2nm_node_attr_num = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "num",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = r2nm_node_num_read,
- .store = r2nm_node_num_write,
-};
-
-static struct r2nm_node_attribute r2nm_node_attr_ipv4_port = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "ipv4_port",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = r2nm_node_ipv4_port_read,
- .store = r2nm_node_ipv4_port_write,
-};
-
-static struct r2nm_node_attribute r2nm_node_attr_ipv4_address = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "ipv4_address",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = r2nm_node_ipv4_address_read,
- .store = r2nm_node_ipv4_address_write,
-};
-
-static struct r2nm_node_attribute r2nm_node_attr_local = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "local",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = r2nm_node_local_read,
- .store = r2nm_node_local_write,
-};
-
-static struct configfs_attribute *r2nm_node_attrs[] = {
- [R2NM_NODE_ATTR_NUM] = &r2nm_node_attr_num.attr,
- [R2NM_NODE_ATTR_PORT] = &r2nm_node_attr_ipv4_port.attr,
- [R2NM_NODE_ATTR_ADDRESS] = &r2nm_node_attr_ipv4_address.attr,
- [R2NM_NODE_ATTR_LOCAL] = &r2nm_node_attr_local.attr,
- NULL,
-};
-
-static int r2nm_attr_index(struct configfs_attribute *attr)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(r2nm_node_attrs); i++) {
- if (attr == r2nm_node_attrs[i])
- return i;
- }
- BUG();
- return 0;
-}
-
-static ssize_t r2nm_node_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct r2nm_node *node = to_r2nm_node(item);
- struct r2nm_node_attribute *r2nm_node_attr =
- container_of(attr, struct r2nm_node_attribute, attr);
- ssize_t ret = 0;
-
- if (r2nm_node_attr->show)
- ret = r2nm_node_attr->show(node, page);
- return ret;
-}
-
-static ssize_t r2nm_node_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
-{
- struct r2nm_node *node = to_r2nm_node(item);
- struct r2nm_node_attribute *r2nm_node_attr =
- container_of(attr, struct r2nm_node_attribute, attr);
- ssize_t ret;
- int attr_index = r2nm_attr_index(attr);
-
- if (r2nm_node_attr->store == NULL) {
- ret = -EINVAL;
- goto out;
- }
-
- if (test_bit(attr_index, &node->nd_set_attributes))
- return -EBUSY;
-
- ret = r2nm_node_attr->store(node, page, count);
- if (ret < count)
- goto out;
-
- set_bit(attr_index, &node->nd_set_attributes);
-out:
- return ret;
-}
-
-static struct configfs_item_operations r2nm_node_item_ops = {
- .release = r2nm_node_release,
- .show_attribute = r2nm_node_show,
- .store_attribute = r2nm_node_store,
-};
-
-static struct config_item_type r2nm_node_type = {
- .ct_item_ops = &r2nm_node_item_ops,
- .ct_attrs = r2nm_node_attrs,
- .ct_owner = THIS_MODULE,
-};
-
-/* node set */
-
-struct r2nm_node_group {
- struct config_group ns_group;
- /* some stuff? */
-};
-
-#if 0
-static struct r2nm_node_group *to_r2nm_node_group(struct config_group *group)
-{
- return group ?
- container_of(group, struct r2nm_node_group, ns_group)
- : NULL;
-}
-#endif
-
-struct r2nm_cluster_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct r2nm_cluster *, char *);
- ssize_t (*store)(struct r2nm_cluster *, const char *, size_t);
-};
-
-static ssize_t r2nm_cluster_attr_write(const char *page, ssize_t count,
- unsigned int *val)
-{
- unsigned long tmp;
- char *p = (char *)page;
- int err;
-
- err = kstrtoul(p, 10, &tmp);
- if (err)
- return err;
-
- if (tmp == 0)
- return -EINVAL;
- if (tmp >= (u32)-1)
- return -ERANGE;
-
- *val = tmp;
-
- return count;
-}
-
-static ssize_t r2nm_cluster_attr_idle_timeout_ms_read(
- struct r2nm_cluster *cluster, char *page)
-{
- return sprintf(page, "%u\n", cluster->cl_idle_timeout_ms);
-}
-
-static ssize_t r2nm_cluster_attr_idle_timeout_ms_write(
- struct r2nm_cluster *cluster, const char *page, size_t count)
-{
- ssize_t ret;
- unsigned int val = 0;
-
- ret = r2nm_cluster_attr_write(page, count, &val);
-
- if (ret > 0) {
- if (cluster->cl_idle_timeout_ms != val
- && r2net_num_connected_peers()) {
- mlog(ML_NOTICE,
- "r2net: cannot change idle timeout after "
- "the first peer has agreed to it."
- " %d connected peers\n",
- r2net_num_connected_peers());
- ret = -EINVAL;
- } else if (val <= cluster->cl_keepalive_delay_ms) {
- mlog(ML_NOTICE,
- "r2net: idle timeout must be larger "
- "than keepalive delay\n");
- ret = -EINVAL;
- } else {
- cluster->cl_idle_timeout_ms = val;
- }
- }
-
- return ret;
-}
-
-static ssize_t r2nm_cluster_attr_keepalive_delay_ms_read(
- struct r2nm_cluster *cluster, char *page)
-{
- return sprintf(page, "%u\n", cluster->cl_keepalive_delay_ms);
-}
-
-static ssize_t r2nm_cluster_attr_keepalive_delay_ms_write(
- struct r2nm_cluster *cluster, const char *page, size_t count)
-{
- ssize_t ret;
- unsigned int val = 0;
-
- ret = r2nm_cluster_attr_write(page, count, &val);
-
- if (ret > 0) {
- if (cluster->cl_keepalive_delay_ms != val
- && r2net_num_connected_peers()) {
- mlog(ML_NOTICE,
- "r2net: cannot change keepalive delay after"
- " the first peer has agreed to it."
- " %d connected peers\n",
- r2net_num_connected_peers());
- ret = -EINVAL;
- } else if (val >= cluster->cl_idle_timeout_ms) {
- mlog(ML_NOTICE,
- "r2net: keepalive delay must be "
- "smaller than idle timeout\n");
- ret = -EINVAL;
- } else {
- cluster->cl_keepalive_delay_ms = val;
- }
- }
-
- return ret;
-}
-
-static ssize_t r2nm_cluster_attr_reconnect_delay_ms_read(
- struct r2nm_cluster *cluster, char *page)
-{
- return sprintf(page, "%u\n", cluster->cl_reconnect_delay_ms);
-}
-
-static ssize_t r2nm_cluster_attr_reconnect_delay_ms_write(
- struct r2nm_cluster *cluster, const char *page, size_t count)
-{
- return r2nm_cluster_attr_write(page, count,
- &cluster->cl_reconnect_delay_ms);
-}
-
-static ssize_t r2nm_cluster_attr_fence_method_read(
- struct r2nm_cluster *cluster, char *page)
-{
- ssize_t ret = 0;
-
- if (cluster)
- ret = sprintf(page, "%s\n",
- r2nm_fence_method_desc[cluster->cl_fence_method]);
- return ret;
-}
-
-static ssize_t r2nm_cluster_attr_fence_method_write(
- struct r2nm_cluster *cluster, const char *page, size_t count)
-{
- unsigned int i;
-
- if (page[count - 1] != '\n')
- goto bail;
-
- for (i = 0; i < R2NM_FENCE_METHODS; ++i) {
- if (count != strlen(r2nm_fence_method_desc[i]) + 1)
- continue;
- if (strncasecmp(page, r2nm_fence_method_desc[i], count - 1))
- continue;
- if (cluster->cl_fence_method != i) {
- pr_info("ramster: Changing fence method to %s\n",
- r2nm_fence_method_desc[i]);
- cluster->cl_fence_method = i;
- }
- return count;
- }
-
-bail:
- return -EINVAL;
-}
-
-static struct r2nm_cluster_attribute r2nm_cluster_attr_idle_timeout_ms = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "idle_timeout_ms",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = r2nm_cluster_attr_idle_timeout_ms_read,
- .store = r2nm_cluster_attr_idle_timeout_ms_write,
-};
-
-static struct r2nm_cluster_attribute r2nm_cluster_attr_keepalive_delay_ms = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "keepalive_delay_ms",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = r2nm_cluster_attr_keepalive_delay_ms_read,
- .store = r2nm_cluster_attr_keepalive_delay_ms_write,
-};
-
-static struct r2nm_cluster_attribute r2nm_cluster_attr_reconnect_delay_ms = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "reconnect_delay_ms",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = r2nm_cluster_attr_reconnect_delay_ms_read,
- .store = r2nm_cluster_attr_reconnect_delay_ms_write,
-};
-
-static struct r2nm_cluster_attribute r2nm_cluster_attr_fence_method = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "fence_method",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = r2nm_cluster_attr_fence_method_read,
- .store = r2nm_cluster_attr_fence_method_write,
-};
-
-static struct configfs_attribute *r2nm_cluster_attrs[] = {
- &r2nm_cluster_attr_idle_timeout_ms.attr,
- &r2nm_cluster_attr_keepalive_delay_ms.attr,
- &r2nm_cluster_attr_reconnect_delay_ms.attr,
- &r2nm_cluster_attr_fence_method.attr,
- NULL,
-};
-static ssize_t r2nm_cluster_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct r2nm_cluster *cluster = to_r2nm_cluster(item);
- struct r2nm_cluster_attribute *r2nm_cluster_attr =
- container_of(attr, struct r2nm_cluster_attribute, attr);
- ssize_t ret = 0;
-
- if (r2nm_cluster_attr->show)
- ret = r2nm_cluster_attr->show(cluster, page);
- return ret;
-}
-
-static ssize_t r2nm_cluster_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
-{
- struct r2nm_cluster *cluster = to_r2nm_cluster(item);
- struct r2nm_cluster_attribute *r2nm_cluster_attr =
- container_of(attr, struct r2nm_cluster_attribute, attr);
- ssize_t ret;
-
- if (r2nm_cluster_attr->store == NULL) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = r2nm_cluster_attr->store(cluster, page, count);
- if (ret < count)
- goto out;
-out:
- return ret;
-}
-
-static struct config_item *r2nm_node_group_make_item(struct config_group *group,
- const char *name)
-{
- struct r2nm_node *node = NULL;
-
- if (strlen(name) > R2NM_MAX_NAME_LEN)
- return ERR_PTR(-ENAMETOOLONG);
-
- node = kzalloc(sizeof(struct r2nm_node), GFP_KERNEL);
- if (node == NULL)
- return ERR_PTR(-ENOMEM);
-
- strcpy(node->nd_name, name); /* use item.ci_namebuf instead? */
- config_item_init_type_name(&node->nd_item, name, &r2nm_node_type);
- spin_lock_init(&node->nd_lock);
-
- mlog(ML_CLUSTER, "r2nm: Registering node %s\n", name);
-
- return &node->nd_item;
-}
-
-static void r2nm_node_group_drop_item(struct config_group *group,
- struct config_item *item)
-{
- struct r2nm_node *node = to_r2nm_node(item);
- struct r2nm_cluster *cluster =
- to_r2nm_cluster(group->cg_item.ci_parent);
-
- r2net_disconnect_node(node);
-
- if (cluster->cl_has_local &&
- (cluster->cl_local_node == node->nd_num)) {
- cluster->cl_has_local = 0;
- cluster->cl_local_node = R2NM_INVALID_NODE_NUM;
- r2net_stop_listening(node);
- }
-
- /* XXX call into net to stop this node from trading messages */
-
- write_lock(&cluster->cl_nodes_lock);
-
- /* XXX sloppy */
- if (node->nd_ipv4_address)
- rb_erase(&node->nd_ip_node, &cluster->cl_node_ip_tree);
-
- /* nd_num might be 0 if the node number hasn't been set.. */
- if (cluster->cl_nodes[node->nd_num] == node) {
- cluster->cl_nodes[node->nd_num] = NULL;
- clear_bit(node->nd_num, cluster->cl_nodes_bitmap);
- }
- write_unlock(&cluster->cl_nodes_lock);
-
- mlog(ML_CLUSTER, "r2nm: Unregistered node %s\n",
- config_item_name(&node->nd_item));
-
- config_item_put(item);
-}
-
-static struct configfs_group_operations r2nm_node_group_group_ops = {
- .make_item = r2nm_node_group_make_item,
- .drop_item = r2nm_node_group_drop_item,
-};
-
-static struct config_item_type r2nm_node_group_type = {
- .ct_group_ops = &r2nm_node_group_group_ops,
- .ct_owner = THIS_MODULE,
-};
-
-/* cluster */
-
-static void r2nm_cluster_release(struct config_item *item)
-{
- struct r2nm_cluster *cluster = to_r2nm_cluster(item);
-
- kfree(cluster->cl_group.default_groups);
- kfree(cluster);
-}
-
-static struct configfs_item_operations r2nm_cluster_item_ops = {
- .release = r2nm_cluster_release,
- .show_attribute = r2nm_cluster_show,
- .store_attribute = r2nm_cluster_store,
-};
-
-static struct config_item_type r2nm_cluster_type = {
- .ct_item_ops = &r2nm_cluster_item_ops,
- .ct_attrs = r2nm_cluster_attrs,
- .ct_owner = THIS_MODULE,
-};
-
-/* cluster set */
-
-struct r2nm_cluster_group {
- struct configfs_subsystem cs_subsys;
- /* some stuff? */
-};
-
-#if 0
-static struct r2nm_cluster_group *
-to_r2nm_cluster_group(struct config_group *group)
-{
- return group ?
- container_of(to_configfs_subsystem(group),
- struct r2nm_cluster_group, cs_subsys)
- : NULL;
-}
-#endif
-
-static struct config_group *
-r2nm_cluster_group_make_group(struct config_group *group,
- const char *name)
-{
- struct r2nm_cluster *cluster = NULL;
- struct r2nm_node_group *ns = NULL;
- struct config_group *r2hb_group = NULL, *ret = NULL;
- void *defs = NULL;
-
- /* this runs under the parent dir's i_mutex; there can be only
- * one caller in here at a time */
- if (r2nm_single_cluster)
- return ERR_PTR(-ENOSPC);
-
- cluster = kzalloc(sizeof(struct r2nm_cluster), GFP_KERNEL);
- ns = kzalloc(sizeof(struct r2nm_node_group), GFP_KERNEL);
- defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
- r2hb_group = r2hb_alloc_hb_set();
- if (cluster == NULL || ns == NULL || r2hb_group == NULL || defs == NULL)
- goto out;
-
- config_group_init_type_name(&cluster->cl_group, name,
- &r2nm_cluster_type);
- config_group_init_type_name(&ns->ns_group, "node",
- &r2nm_node_group_type);
-
- cluster->cl_group.default_groups = defs;
- cluster->cl_group.default_groups[0] = &ns->ns_group;
- cluster->cl_group.default_groups[1] = r2hb_group;
- cluster->cl_group.default_groups[2] = NULL;
- rwlock_init(&cluster->cl_nodes_lock);
- cluster->cl_node_ip_tree = RB_ROOT;
- cluster->cl_reconnect_delay_ms = R2NET_RECONNECT_DELAY_MS_DEFAULT;
- cluster->cl_idle_timeout_ms = R2NET_IDLE_TIMEOUT_MS_DEFAULT;
- cluster->cl_keepalive_delay_ms = R2NET_KEEPALIVE_DELAY_MS_DEFAULT;
- cluster->cl_fence_method = R2NM_FENCE_RESET;
-
- ret = &cluster->cl_group;
- r2nm_single_cluster = cluster;
-
-out:
- if (ret == NULL) {
- kfree(cluster);
- kfree(ns);
- r2hb_free_hb_set(r2hb_group);
- kfree(defs);
- ret = ERR_PTR(-ENOMEM);
- }
-
- return ret;
-}
-
-static void r2nm_cluster_group_drop_item(struct config_group *group,
- struct config_item *item)
-{
- struct r2nm_cluster *cluster = to_r2nm_cluster(item);
- int i;
- struct config_item *killme;
-
- BUG_ON(r2nm_single_cluster != cluster);
- r2nm_single_cluster = NULL;
-
- for (i = 0; cluster->cl_group.default_groups[i]; i++) {
- killme = &cluster->cl_group.default_groups[i]->cg_item;
- cluster->cl_group.default_groups[i] = NULL;
- config_item_put(killme);
- }
-
- config_item_put(item);
-}
-
-static struct configfs_group_operations r2nm_cluster_group_group_ops = {
- .make_group = r2nm_cluster_group_make_group,
- .drop_item = r2nm_cluster_group_drop_item,
-};
-
-static struct config_item_type r2nm_cluster_group_type = {
- .ct_group_ops = &r2nm_cluster_group_group_ops,
- .ct_owner = THIS_MODULE,
-};
-
-static struct r2nm_cluster_group r2nm_cluster_group = {
- .cs_subsys = {
- .su_group = {
- .cg_item = {
- .ci_namebuf = "cluster",
- .ci_type = &r2nm_cluster_group_type,
- },
- },
- },
-};
-
-int r2nm_depend_item(struct config_item *item)
-{
- return configfs_depend_item(&r2nm_cluster_group.cs_subsys, item);
-}
-
-void r2nm_undepend_item(struct config_item *item)
-{
- configfs_undepend_item(&r2nm_cluster_group.cs_subsys, item);
-}
-
-int r2nm_depend_this_node(void)
-{
- int ret = 0;
- struct r2nm_node *local_node;
-
- local_node = r2nm_get_node_by_num(r2nm_this_node());
- if (!local_node) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = r2nm_depend_item(&local_node->nd_item);
- r2nm_node_put(local_node);
-
-out:
- return ret;
-}
-
-void r2nm_undepend_this_node(void)
-{
- struct r2nm_node *local_node;
-
- local_node = r2nm_get_node_by_num(r2nm_this_node());
- BUG_ON(!local_node);
-
- r2nm_undepend_item(&local_node->nd_item);
- r2nm_node_put(local_node);
-}
-
-
-static void __exit exit_r2nm(void)
-{
- /* XXX sync with hb callbacks and shut down hb? */
- r2net_unregister_hb_callbacks();
- configfs_unregister_subsystem(&r2nm_cluster_group.cs_subsys);
-
- r2net_exit();
- r2hb_exit();
-}
-
-int r2nm_init(void)
-{
- int ret = -1;
-
- ret = r2hb_init();
- if (ret)
- goto out;
-
- ret = r2net_init();
- if (ret)
- goto out_r2hb;
-
- ret = r2net_register_hb_callbacks();
- if (ret)
- goto out_r2net;
-
- config_group_init(&r2nm_cluster_group.cs_subsys.su_group);
- mutex_init(&r2nm_cluster_group.cs_subsys.su_mutex);
- ret = configfs_register_subsystem(&r2nm_cluster_group.cs_subsys);
- if (ret) {
- pr_err("nodemanager: Registration returned %d\n", ret);
- goto out_callbacks;
- }
-
- if (!ret)
- goto out;
-
- configfs_unregister_subsystem(&r2nm_cluster_group.cs_subsys);
-out_callbacks:
- r2net_unregister_hb_callbacks();
-out_r2net:
- r2net_exit();
-out_r2hb:
- r2hb_exit();
-out:
- return ret;
-}
-EXPORT_SYMBOL_GPL(r2nm_init);
-
-MODULE_AUTHOR("Oracle");
-MODULE_LICENSE("GPL");
-
-#ifndef CONFIG_RAMSTER_MODULE
-late_initcall(r2nm_init);
-#endif
diff --git a/drivers/staging/zcache/ramster/nodemanager.h b/drivers/staging/zcache/ramster/nodemanager.h
deleted file mode 100644
index 41a04df5842..00000000000
--- a/drivers/staging/zcache/ramster/nodemanager.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * nodemanager.h
- *
- * Function prototypes
- *
- * Copyright (C) 2004 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- *
- */
-
-#ifndef R2CLUSTER_NODEMANAGER_H
-#define R2CLUSTER_NODEMANAGER_H
-
-#include "ramster_nodemanager.h"
-
-/* This totally doesn't belong here. */
-#include <linux/configfs.h>
-#include <linux/rbtree.h>
-
-enum r2nm_fence_method {
- R2NM_FENCE_RESET = 0,
- R2NM_FENCE_PANIC,
- R2NM_FENCE_METHODS, /* Number of fence methods */
-};
-
-struct r2nm_node {
- spinlock_t nd_lock;
- struct config_item nd_item;
- char nd_name[R2NM_MAX_NAME_LEN+1]; /* replace? */
- __u8 nd_num;
- /* only one address per node, as attributes, for now. */
- __be32 nd_ipv4_address;
- __be16 nd_ipv4_port;
- struct rb_node nd_ip_node;
- /* there can be only one local node for now */
- int nd_local;
-
- unsigned long nd_set_attributes;
-};
-
-struct r2nm_cluster {
- struct config_group cl_group;
- unsigned cl_has_local:1;
- u8 cl_local_node;
- rwlock_t cl_nodes_lock;
- struct r2nm_node *cl_nodes[R2NM_MAX_NODES];
- struct rb_root cl_node_ip_tree;
- unsigned int cl_idle_timeout_ms;
- unsigned int cl_keepalive_delay_ms;
- unsigned int cl_reconnect_delay_ms;
- enum r2nm_fence_method cl_fence_method;
-
- /* part of a hack for disk bitmap.. will go eventually. - zab */
- unsigned long cl_nodes_bitmap[BITS_TO_LONGS(R2NM_MAX_NODES)];
-};
-
-extern struct r2nm_cluster *r2nm_single_cluster;
-
-u8 r2nm_this_node(void);
-
-int r2nm_configured_node_map(unsigned long *map, unsigned bytes);
-struct r2nm_node *r2nm_get_node_by_num(u8 node_num);
-struct r2nm_node *r2nm_get_node_by_ip(__be32 addr);
-void r2nm_node_get(struct r2nm_node *node);
-void r2nm_node_put(struct r2nm_node *node);
-
-int r2nm_depend_item(struct config_item *item);
-void r2nm_undepend_item(struct config_item *item);
-int r2nm_depend_this_node(void);
-void r2nm_undepend_this_node(void);
-
-#endif /* R2CLUSTER_NODEMANAGER_H */
diff --git a/drivers/staging/zcache/ramster/r2net.c b/drivers/staging/zcache/ramster/r2net.c
deleted file mode 100644
index 34818dc6561..00000000000
--- a/drivers/staging/zcache/ramster/r2net.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * r2net.c
- *
- * Copyright (c) 2011-2012, Dan Magenheimer, Oracle Corp.
- *
- * Ramster_r2net provides an interface between zcache and r2net.
- *
- * FIXME: support more than two nodes
- */
-
-#include <linux/list.h>
-#include "tcp.h"
-#include "nodemanager.h"
-#include "../tmem.h"
-#include "../zcache.h"
-#include "ramster.h"
-
-#define RAMSTER_TESTING
-
-#define RMSTR_KEY 0x77347734
-
-enum {
- RMSTR_TMEM_PUT_EPH = 100,
- RMSTR_TMEM_PUT_PERS,
- RMSTR_TMEM_ASYNC_GET_REQUEST,
- RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST,
- RMSTR_TMEM_ASYNC_GET_REPLY,
- RMSTR_TMEM_FLUSH,
- RMSTR_TMEM_FLOBJ,
- RMSTR_TMEM_DESTROY_POOL,
-};
-
-#define RMSTR_R2NET_MAX_LEN \
- (R2NET_MAX_PAYLOAD_BYTES - sizeof(struct tmem_xhandle))
-
-#include "tcp_internal.h"
-
-static struct r2nm_node *r2net_target_node;
-static int r2net_target_nodenum;
-
-int r2net_remote_target_node_set(int node_num)
-{
- int ret = -1;
-
- r2net_target_node = r2nm_get_node_by_num(node_num);
- if (r2net_target_node != NULL) {
- r2net_target_nodenum = node_num;
- r2nm_node_put(r2net_target_node);
- ret = 0;
- }
- return ret;
-}
-
-/* FIXME following buffer should be per-cpu, protected by preempt_disable */
-static char ramster_async_get_buf[R2NET_MAX_PAYLOAD_BYTES];
-
-static int ramster_remote_async_get_request_handler(struct r2net_msg *msg,
- u32 len, void *data, void **ret_data)
-{
- char *pdata;
- struct tmem_xhandle xh;
- int found;
- size_t size = RMSTR_R2NET_MAX_LEN;
- u16 msgtype = be16_to_cpu(msg->msg_type);
- bool get_and_free = (msgtype == RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST);
- unsigned long flags;
-
- xh = *(struct tmem_xhandle *)msg->buf;
- if (xh.xh_data_size > RMSTR_R2NET_MAX_LEN)
- BUG();
- pdata = ramster_async_get_buf;
- *(struct tmem_xhandle *)pdata = xh;
- pdata += sizeof(struct tmem_xhandle);
- local_irq_save(flags);
- found = zcache_get_page(xh.client_id, xh.pool_id, &xh.oid, xh.index,
- pdata, &size, true, get_and_free ? 1 : -1);
- local_irq_restore(flags);
- if (found < 0) {
- /* a zero size indicates the get failed */
- size = 0;
- }
- if (size > RMSTR_R2NET_MAX_LEN)
- BUG();
- *ret_data = pdata - sizeof(struct tmem_xhandle);
- /* now make caller (r2net_process_message) handle specially */
- r2net_force_data_magic(msg, RMSTR_TMEM_ASYNC_GET_REPLY, RMSTR_KEY);
- return size + sizeof(struct tmem_xhandle);
-}
-
-static int ramster_remote_async_get_reply_handler(struct r2net_msg *msg,
- u32 len, void *data, void **ret_data)
-{
- char *in = (char *)msg->buf;
- int datalen = len - sizeof(struct r2net_msg);
- int ret = -1;
- struct tmem_xhandle *xh = (struct tmem_xhandle *)in;
-
- in += sizeof(struct tmem_xhandle);
- datalen -= sizeof(struct tmem_xhandle);
- BUG_ON(datalen < 0 || datalen > PAGE_SIZE);
- ret = ramster_localify(xh->pool_id, &xh->oid, xh->index,
- in, datalen, xh->extra);
-#ifdef RAMSTER_TESTING
- if (ret == -EEXIST)
- pr_err("TESTING ArrgREP, aborted overwrite on racy put\n");
-#endif
- return ret;
-}
-
-int ramster_remote_put_handler(struct r2net_msg *msg,
- u32 len, void *data, void **ret_data)
-{
- struct tmem_xhandle *xh;
- char *p = (char *)msg->buf;
- int datalen = len - sizeof(struct r2net_msg) -
- sizeof(struct tmem_xhandle);
- u16 msgtype = be16_to_cpu(msg->msg_type);
- bool ephemeral = (msgtype == RMSTR_TMEM_PUT_EPH);
- unsigned long flags;
- int ret;
-
- xh = (struct tmem_xhandle *)p;
- p += sizeof(struct tmem_xhandle);
- zcache_autocreate_pool(xh->client_id, xh->pool_id, ephemeral);
- local_irq_save(flags);
- ret = zcache_put_page(xh->client_id, xh->pool_id, &xh->oid, xh->index,
- p, datalen, true, ephemeral);
- local_irq_restore(flags);
- return ret;
-}
-
-int ramster_remote_flush_handler(struct r2net_msg *msg,
- u32 len, void *data, void **ret_data)
-{
- struct tmem_xhandle *xh;
- char *p = (char *)msg->buf;
-
- xh = (struct tmem_xhandle *)p;
- p += sizeof(struct tmem_xhandle);
- (void)zcache_flush_page(xh->client_id, xh->pool_id,
- &xh->oid, xh->index);
- return 0;
-}
-
-int ramster_remote_flobj_handler(struct r2net_msg *msg,
- u32 len, void *data, void **ret_data)
-{
- struct tmem_xhandle *xh;
- char *p = (char *)msg->buf;
-
- xh = (struct tmem_xhandle *)p;
- p += sizeof(struct tmem_xhandle);
- (void)zcache_flush_object(xh->client_id, xh->pool_id, &xh->oid);
- return 0;
-}
-
-int r2net_remote_async_get(struct tmem_xhandle *xh, bool free, int remotenode,
- size_t expect_size, uint8_t expect_cksum,
- void *extra)
-{
- int nodenum, ret = -1, status;
- struct r2nm_node *node = NULL;
- struct kvec vec[1];
- size_t veclen = 1;
- u32 msg_type;
- struct r2net_node *nn;
-
- node = r2nm_get_node_by_num(remotenode);
- if (node == NULL)
- goto out;
- xh->client_id = r2nm_this_node(); /* which node is getting */
- xh->xh_data_cksum = expect_cksum;
- xh->xh_data_size = expect_size;
- xh->extra = extra;
- vec[0].iov_len = sizeof(*xh);
- vec[0].iov_base = xh;
-
- node = r2net_target_node;
- if (!node)
- goto out;
-
- nodenum = r2net_target_nodenum;
-
- r2nm_node_get(node);
- nn = r2net_nn_from_num(nodenum);
- if (nn->nn_persistent_error || !nn->nn_sc_valid) {
- ret = -ENOTCONN;
- r2nm_node_put(node);
- goto out;
- }
-
- if (free)
- msg_type = RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST;
- else
- msg_type = RMSTR_TMEM_ASYNC_GET_REQUEST;
- ret = r2net_send_message_vec(msg_type, RMSTR_KEY,
- vec, veclen, remotenode, &status);
- r2nm_node_put(node);
- if (ret < 0) {
- if (ret == -ENOTCONN || ret == -EHOSTDOWN)
- goto out;
- if (ret == -EAGAIN)
- goto out;
- /* FIXME handle bad message possibilities here? */
- pr_err("UNTESTED ret<0 in ramster_remote_async_get: ret=%d\n",
- ret);
- }
- ret = status;
-out:
- return ret;
-}
-
-#ifdef RAMSTER_TESTING
-/* leave me here to see if it catches a weird crash */
-static void ramster_check_irq_counts(void)
-{
- static int last_hardirq_cnt, last_softirq_cnt, last_preempt_cnt;
- int cur_hardirq_cnt, cur_softirq_cnt, cur_preempt_cnt;
-
- cur_hardirq_cnt = hardirq_count() >> HARDIRQ_SHIFT;
- if (cur_hardirq_cnt > last_hardirq_cnt) {
- last_hardirq_cnt = cur_hardirq_cnt;
- if (!(last_hardirq_cnt&(last_hardirq_cnt-1)))
- pr_err("RAMSTER TESTING RRP hardirq_count=%d\n",
- last_hardirq_cnt);
- }
- cur_softirq_cnt = softirq_count() >> SOFTIRQ_SHIFT;
- if (cur_softirq_cnt > last_softirq_cnt) {
- last_softirq_cnt = cur_softirq_cnt;
- if (!(last_softirq_cnt&(last_softirq_cnt-1)))
- pr_err("RAMSTER TESTING RRP softirq_count=%d\n",
- last_softirq_cnt);
- }
- cur_preempt_cnt = preempt_count() & PREEMPT_MASK;
- if (cur_preempt_cnt > last_preempt_cnt) {
- last_preempt_cnt = cur_preempt_cnt;
- if (!(last_preempt_cnt&(last_preempt_cnt-1)))
- pr_err("RAMSTER TESTING RRP preempt_count=%d\n",
- last_preempt_cnt);
- }
-}
-#endif
-
-int r2net_remote_put(struct tmem_xhandle *xh, char *data, size_t size,
- bool ephemeral, int *remotenode)
-{
- int nodenum, ret = -1, status;
- struct r2nm_node *node = NULL;
- struct kvec vec[2];
- size_t veclen = 2;
- u32 msg_type;
- struct r2net_node *nn;
-
- BUG_ON(size > RMSTR_R2NET_MAX_LEN);
- xh->client_id = r2nm_this_node(); /* which node is putting */
- vec[0].iov_len = sizeof(*xh);
- vec[0].iov_base = xh;
- vec[1].iov_len = size;
- vec[1].iov_base = data;
-
- node = r2net_target_node;
- if (!node)
- goto out;
-
- nodenum = r2net_target_nodenum;
-
- r2nm_node_get(node);
-
- nn = r2net_nn_from_num(nodenum);
- if (nn->nn_persistent_error || !nn->nn_sc_valid) {
- ret = -ENOTCONN;
- r2nm_node_put(node);
- goto out;
- }
-
- if (ephemeral)
- msg_type = RMSTR_TMEM_PUT_EPH;
- else
- msg_type = RMSTR_TMEM_PUT_PERS;
-#ifdef RAMSTER_TESTING
- /* leave me here to see if it catches a weird crash */
- ramster_check_irq_counts();
-#endif
-
- ret = r2net_send_message_vec(msg_type, RMSTR_KEY, vec, veclen,
- nodenum, &status);
- if (ret < 0)
- ret = -1;
- else {
- ret = status;
- *remotenode = nodenum;
- }
-
- r2nm_node_put(node);
-out:
- return ret;
-}
-
-int r2net_remote_flush(struct tmem_xhandle *xh, int remotenode)
-{
- int ret = -1, status;
- struct r2nm_node *node = NULL;
- struct kvec vec[1];
- size_t veclen = 1;
-
- node = r2nm_get_node_by_num(remotenode);
- BUG_ON(node == NULL);
- xh->client_id = r2nm_this_node(); /* which node is flushing */
- vec[0].iov_len = sizeof(*xh);
- vec[0].iov_base = xh;
- BUG_ON(irqs_disabled());
- BUG_ON(in_softirq());
- ret = r2net_send_message_vec(RMSTR_TMEM_FLUSH, RMSTR_KEY,
- vec, veclen, remotenode, &status);
- r2nm_node_put(node);
- return ret;
-}
-
-int r2net_remote_flush_object(struct tmem_xhandle *xh, int remotenode)
-{
- int ret = -1, status;
- struct r2nm_node *node = NULL;
- struct kvec vec[1];
- size_t veclen = 1;
-
- node = r2nm_get_node_by_num(remotenode);
- BUG_ON(node == NULL);
- xh->client_id = r2nm_this_node(); /* which node is flobjing */
- vec[0].iov_len = sizeof(*xh);
- vec[0].iov_base = xh;
- ret = r2net_send_message_vec(RMSTR_TMEM_FLOBJ, RMSTR_KEY,
- vec, veclen, remotenode, &status);
- r2nm_node_put(node);
- return ret;
-}
-
-/*
- * Handler registration
- */
-
-static LIST_HEAD(r2net_unreg_list);
-
-static void r2net_unregister_handlers(void)
-{
- r2net_unregister_handler_list(&r2net_unreg_list);
-}
-
-int r2net_register_handlers(void)
-{
- int status;
-
- status = r2net_register_handler(RMSTR_TMEM_PUT_EPH, RMSTR_KEY,
- RMSTR_R2NET_MAX_LEN,
- ramster_remote_put_handler,
- NULL, NULL, &r2net_unreg_list);
- if (status)
- goto bail;
-
- status = r2net_register_handler(RMSTR_TMEM_PUT_PERS, RMSTR_KEY,
- RMSTR_R2NET_MAX_LEN,
- ramster_remote_put_handler,
- NULL, NULL, &r2net_unreg_list);
- if (status)
- goto bail;
-
- status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_REQUEST, RMSTR_KEY,
- RMSTR_R2NET_MAX_LEN,
- ramster_remote_async_get_request_handler,
- NULL, NULL,
- &r2net_unreg_list);
- if (status)
- goto bail;
-
- status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST,
- RMSTR_KEY, RMSTR_R2NET_MAX_LEN,
- ramster_remote_async_get_request_handler,
- NULL, NULL,
- &r2net_unreg_list);
- if (status)
- goto bail;
-
- status = r2net_register_handler(RMSTR_TMEM_ASYNC_GET_REPLY, RMSTR_KEY,
- RMSTR_R2NET_MAX_LEN,
- ramster_remote_async_get_reply_handler,
- NULL, NULL,
- &r2net_unreg_list);
- if (status)
- goto bail;
-
- status = r2net_register_handler(RMSTR_TMEM_FLUSH, RMSTR_KEY,
- RMSTR_R2NET_MAX_LEN,
- ramster_remote_flush_handler,
- NULL, NULL,
- &r2net_unreg_list);
- if (status)
- goto bail;
-
- status = r2net_register_handler(RMSTR_TMEM_FLOBJ, RMSTR_KEY,
- RMSTR_R2NET_MAX_LEN,
- ramster_remote_flobj_handler,
- NULL, NULL,
- &r2net_unreg_list);
- if (status)
- goto bail;
-
- pr_info("ramster: r2net handlers registered\n");
-
-bail:
- if (status) {
- r2net_unregister_handlers();
- pr_err("ramster: couldn't register r2net handlers\n");
- }
- return status;
-}
diff --git a/drivers/staging/zcache/ramster/ramster-howto.txt b/drivers/staging/zcache/ramster/ramster-howto.txt
deleted file mode 100644
index 7b1ee3bbfdd..00000000000
--- a/drivers/staging/zcache/ramster/ramster-howto.txt
+++ /dev/null
@@ -1,366 +0,0 @@
- RAMSTER HOW-TO
-
-Author: Dan Magenheimer
-Ramster maintainer: Konrad Wilk <konrad.wilk@oracle.com>
-
-This is a HOWTO document for ramster which, as of this writing, is in
-the kernel as a subdirectory of zcache in drivers/staging, called ramster.
-(Zcache can be built with or without ramster functionality.) If enabled
-and properly configured, ramster allows memory capacity load balancing
-across multiple machines in a cluster. Further, the ramster code serves
-as an example of asynchronous access for zcache (as well as cleancache and
-frontswap) that may prove useful for future transcendent memory
-implementations, such as KVM and NVRAM. While ramster works today on
-any network connection that supports kernel sockets, its features may
-become more interesting on future high-speed fabrics/interconnects.
-
-Ramster requires both kernel and userland support. The userland support,
-called ramster-tools, is known to work with EL6-based distros, but is a
-set of poorly-hacked slightly-modified cluster tools based on ocfs2, which
-includes an init file, a config file, and a userland binary that interfaces
-to the kernel. This state of userland support reflects the abysmal userland
-skills of this suitably-embarrassed author; any help/patches to turn
-ramster-tools into more distributable rpms/debs useful for a wider range
-of distros would be appreciated. The source RPM that can be used as a
-starting point is available at:
- http://oss.oracle.com/projects/tmem/files/RAMster/
-
-As a result of this author's ignorance, userland setup described in this
-HOWTO assumes an EL6 distro and is described in EL6 syntax. Apologies
-if this offends anyone!
-
-Kernel support has only been tested on x86_64. Systems with an active
-ocfs2 filesystem should work, but since ramster leverages a lot of
-code from ocfs2, there may be latent issues. A kernel configuration that
-includes CONFIG_OCFS2_FS should build OK, and should certainly run OK
-if no ocfs2 filesystem is mounted.
-
-This HOWTO demonstrates memory capacity load balancing for a two-node
-cluster, where one node called the "local" node becomes overcommitted
-and the other node called the "remote" node provides additional RAM
-capacity for use by the local node. Ramster is capable of more complex
-topologies; see the last section titled "ADVANCED RAMSTER TOPOLOGIES".
-
-If you find any terms in this HOWTO unfamiliar or don't understand the
-motivation for ramster, the following LWN reading is recommended:
--- Transcendent Memory in a Nutshell (lwn.net/Articles/454795)
--- The future calculus of memory management (lwn.net/Articles/475681)
-And since ramster is built on top of zcache, this article may be helpful:
--- In-kernel memory compression (lwn.net/Articles/545244)
-
-Now that you've memorized the contents of those articles, let's get started!
-
-A. PRELIMINARY
-
-1) Install two x86_64 Linux systems that are known to work when
- upgraded to a recent upstream Linux kernel version.
-
-On each system:
-
-2) Configure, build and install, then boot Linux, just to ensure it
- can be done with an unmodified upstream kernel. Confirm you booted
- the upstream kernel with "uname -a".
-
-3) If you plan to do any performance testing or unless you plan to
- test only swapping, the "WasActive" patch is also highly recommended.
- (Search lkml.org for WasActive, apply the patch, rebuild your kernel.)
- For a demo or simple testing, the patch can be ignored.
-
-4) Install ramster-tools as root. An x86_64 rpm for EL6-based systems
- can be found at:
- http://oss.oracle.com/projects/tmem/files/RAMster/
- (Sorry but for now, non-EL6 users must recreate ramster-tools on
- their own from source. See above.)
-
-5) Ensure that debugfs is mounted at each boot. Examples below assume it
- is mounted at /sys/kernel/debug.
-
-B. BUILDING RAMSTER INTO THE KERNEL
-
-Do the following on each system:
-
-1) Using the kernel configuration mechanism of your choice, change
- your config to include:
-
- CONFIG_CLEANCACHE=y
- CONFIG_FRONTSWAP=y
- CONFIG_STAGING=y
- CONFIG_CONFIGFS_FS=y # NOTE: MUST BE y, not m
- CONFIG_ZCACHE=y
- CONFIG_RAMSTER=y
-
- For a linux-3.10 or later kernel, you should also set:
-
- CONFIG_ZCACHE_DEBUG=y
- CONFIG_RAMSTER_DEBUG=y
-
- Before building the kernel please doublecheck your kernel config
- file to ensure all of the settings are correct.
-
-2) Build this kernel and change your boot file (e.g. /etc/grub.conf)
- so that the new kernel will boot.
-
-3) Add "zcache" and "ramster" as kernel boot parameters for the new kernel.
-
-4) Reboot each system approximately simultaneously.
-
-5) Check dmesg to ensure there are some messages from ramster, prefixed
- by "ramster:"
-
- # dmesg | grep ramster
-
- You should also see a lot of files in:
-
- # ls /sys/kernel/debug/zcache
- # ls /sys/kernel/debug/ramster
-
- These are mostly counters for various zcache and ramster activities.
- You should also see files in:
-
- # ls /sys/kernel/mm/ramster
-
- These are sysfs files that control ramster as we shall see.
-
- Ramster now will act as a single-system zcache on each system
- but doesn't yet know anything about the cluster so can't yet do
- anything remotely.
-
-C. CONFIGURING THE RAMSTER CLUSTER
-
-This part can be error prone unless you are familiar with clustering
-filesystems. We need to describe the cluster in a /etc/ramster.conf
-file and the init scripts that parse it are extremely picky about
-the syntax.
-
-1) Create a /etc/ramster.conf file and ensure it is identical on both
- systems. This file mimics the ocfs2 format and there is a good amount
- of documentation that can be searched for ocfs2.conf, but you can use:
-
- cluster:
- name = ramster
- node_count = 2
- node:
- name = system1
- cluster = ramster
- number = 0
- ip_address = my.ip.ad.r1
- ip_port = 7777
- node:
- name = system2
- cluster = ramster
- number = 1
- ip_address = my.ip.ad.r2
- ip_port = 7777
-
- You must ensure that the "name" field in the file exactly matches
- the output of "hostname" on each system; if "hostname" shows a
- fully-qualified hostname, ensure the name is fully qualified in
- /etc/ramster.conf. Obviously, substitute my.ip.ad.rx with proper
- ip addresses.
-
-2) Enable the ramster service and configure it. If you used the
- EL6 ramster-tools, this would be:
-
- # chkconfig --add ramster
- # service ramster configure
-
- Set "load on boot" to "y", cluster to start is "ramster" (or whatever
- name you chose in ramster.conf), heartbeat dead threshold as "500",
- network idle timeout as "1000000". Leave the others as default.
-
-3) Reboot both systems. After reboot, try (assuming EL6 ramster-tools):
-
- # service ramster status
-
- You should see "Checking RAMSTER cluster "ramster": Online". If you do
- not, something is wrong and ramster will not work. Note that you
- should also see that the driver for "configfs" is loaded and mounted,
- the driver for ocfs2_dlmfs is not loaded, and some numbers for network
- parameters. You will also see "Checking RAMSTER heartbeat: Not active".
- That's all OK.
-
-4) Now you need to start the cluster heartbeat; the cluster is not "up"
- until all nodes detect a heartbeat. In a real cluster, heartbeat detection
- is done via a cluster filesystem, but ramster doesn't require one. Some
- hack-y kernel code in ramster can start the heartbeat for you though if
- you tell it what nodes are "up". To enable the heartbeat, do:
-
- # echo 0 > /sys/kernel/mm/ramster/manual_node_up
- # echo 1 > /sys/kernel/mm/ramster/manual_node_up
-
- This must be done on BOTH nodes and, to avoid timeouts, must be done
- approximately concurrently on both nodes. On an EL6 system, it is
- convenient to put these lines in /etc/rc.local. To confirm that the
- cluster is now up, on both systems do:
-
- # dmesg | grep ramster
-
- You should see ramster "Accepted connection" messages in dmesg on both
- nodes after this. Note that if you check userland status again with
-
- # service ramster status
-
- you will still see "Checking RAMSTER heartbeat: Not active". That's
- still OK... the ramster kernel heartbeat hack doesn't communicate to
- userland.
-
-5) You now must tell each node the node to which it should "remotify" pages.
- On this two node cluster, we will assume the "local" node, node 0, has
- memory overcommitted and will use ramster to utilize RAM capacity on
- the "remote node", node 1. To configure this, on node 0, you do:
-
- # echo 1 > /sys/kernel/mm/ramster/remote_target_nodenum
-
- You should see "ramster: node 1 set as remotification target" in dmesg
- on node 0. Again, on EL6, /etc/rc.local is a good place to put this
- on node 0 so you don't forget to do it at each boot.
-
-6) One more step: By default, the ramster code does not "remotify" any
- pages; this is primarily for testing purposes, but sometimes it is
- useful. This may change in the future, but for now, on node 0, you do:
-
- # echo 1 > /sys/kernel/mm/ramster/pers_remotify_enable
- # echo 1 > /sys/kernel/mm/ramster/eph_remotify_enable
-
- The first enables remotifying swap (persistent, aka frontswap) pages,
- the second enables remotifying of page cache (ephemeral, cleancache)
- pages.
-
- On EL6, these lines can also be put in /etc/rc.local (AFTER the
- node_up lines), or at the beginning of a script that runs a workload.
-
-7) Note that most testing has been done with both/all machines booted
- roughly simultaneously to avoid cluster timeouts. Ideally, you should
- do this too unless you are trying to break ramster rather than just
- use it. ;-)
-
-D. TESTING RAMSTER
-
-1) Note that ramster has no value unless pages get "remotified". For
- swap/frontswap/persistent pages, this doesn't happen unless/until
- the workload would cause swapping to occur, at which point pages
- are put into frontswap/zcache, and the remotification thread starts
- working. To get to the point where the system swaps, you either
- need a workload for which the working set exceeds the RAM in the
- system; or you need to somehow reduce the amount of RAM one of
- the system sees. This latter is easy when testing in a VM, but
- harder on physical systems. In some cases, "mem=xxxM" on the
- kernel command line restricts memory, but for some values of xxx
- the kernel may fail to boot. One may also try creating a fixed
- RAMdisk, doing nothing with it, but ensuring that it eats up a fixed
- amount of RAM.
-
-2) To see if ramster is working, on the "remote node", node 1, try:
-
- # grep . /sys/kernel/debug/ramster/foreign_*
- # # note, that is space-dot-space between grep and the pathname
-
- to monitor the number (and max) ephemeral and persistent pages
- that ramster has sent. If these stay at zero, ramster is not working
- either because the workload on the local node (node 0) isn't creating
- enough memory pressure or because "remotifying" isn't working. On the
- local system, node 0, you can watch lots of useful information also.
- Try:
-
- grep . /sys/kernel/debug/zcache/*pageframes* \
- /sys/kernel/debug/zcache/*zbytes* \
- /sys/kernel/debug/zcache/*zpages* \
- /sys/kernel/debug/ramster/*remote*
-
- Of particular note are the remote_*_pages_succ_get counters. These
- show how many disk reads and/or disk writes have been avoided on the
- overcommitted local system by storing pages remotely using ramster.
-
- At the risk of information overload, you can also grep:
-
- /sys/kernel/debug/cleancache/* and /sys/kernel/debug/frontswap/*
-
- These show, for example, how many disk reads and/or disk writes have
- been avoided by using zcache to optimize RAM on the local system.
-
-
-AUTOMATIC SWAP REPATRIATION
-
-You may notice that while the systems are idle, the foreign persistent
-page count on the remote machine slowly decreases. This is because
-ramster implements "frontswap selfshrinking": When possible, swap
-pages that have been remotified are slowly repatriated to the local
-machine. This is so that local RAM can be used when possible and
-so that, in case of remote machine crash, the probability of loss
-of data is reduced.
-
-REBOOTING / POWEROFF
-
-If a system is shut down while some of its swap pages still reside
-on a remote system, the system may lock up during the shutdown
-sequence. This will occur if the network is shut down before the
-swap mechansim is shut down, which is the default ordering on many
-distros. To avoid this annoying problem, simply shut off the swap
-subsystem before starting the shutdown sequence, e.g.:
-
- # swapoff -a
- # reboot
-
-Ideally, this swapoff-before-ifdown ordering should be enforced permanently
-using shutdown scripts.
-
-KNOWN PROBLEMS
-
-1) You may periodically see messages such as:
-
- ramster_r2net, message length problem
-
- This is harmless but indicates that a node is sending messages
- containing compressed pages that exceed the maximum for zcache
- (PAGE_SIZE*15/16). The sender side needs to be fixed.
-
-2) If you see a "No longer connected to node..." message or a "No connection
- established with node X after N seconds", it is possible you may
- be in an unrecoverable state. If you are certain all of the
- appropriate cluster configuration steps described above have been
- performed, try rebooting the two servers concurrently to see if
- the cluster starts.
-
- Note that "Connection to node... shutdown, state 7" is an intermediate
- connection state. As long as you later see "Accepted connection", the
- intermediate states are harmless.
-
-3) There are known issues in counting certain values. As a result
- you may see periodic warnings from the kernel. Almost always you
- will see "ramster: bad accounting for XXX". There are also "WARN_ONCE"
- messages. If you see kernel warnings with a tombstone, please report
- them. They are harmless but reflect bugs that need to be eventually fixed.
-
-ADVANCED RAMSTER TOPOLOGIES
-
-The kernel code for ramster can support up to eight nodes in a cluster,
-but no testing has been done with more than three nodes.
-
-In the example described above, the "remote" node serves as a RAM
-overflow for the "local" node. This can be made symmetric by appropriate
-settings of the sysfs remote_target_nodenum file. For example, by setting:
-
- # echo 1 > /sys/kernel/mm/ramster/remote_target_nodenum
-
-on node 0, and
-
- # echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum
-
-on node 1, each node can serve as a RAM overflow for the other.
-
-For more than two nodes, a "RAM server" can be configured. For a
-three node system, set:
-
- # echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum
-
-on node 1, and
-
- # echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum
-
-on node 2. Then node 0 is a RAM server for node 1 and node 2.
-
-In this implementation of ramster, any remote node is potentially a single
-point of failure (SPOF). Though the probability of failure is reduced
-by automatic swap repatriation (see above), a proposed future enhancement
-to ramster improves high-availability for the cluster by sending a copy
-of each page of date to two other nodes. Patches welcome!
diff --git a/drivers/staging/zcache/ramster/ramster.c b/drivers/staging/zcache/ramster/ramster.c
deleted file mode 100644
index a937ce1fa27..00000000000
--- a/drivers/staging/zcache/ramster/ramster.c
+++ /dev/null
@@ -1,925 +0,0 @@
-/*
- * ramster.c
- *
- * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
- *
- * RAMster implements peer-to-peer transcendent memory, allowing a "cluster" of
- * kernels to dynamically pool their RAM so that a RAM-hungry workload on one
- * machine can temporarily and transparently utilize RAM on another machine
- * which is presumably idle or running a non-RAM-hungry workload.
- *
- * RAMster combines a clustering and messaging foundation based on the ocfs2
- * cluster layer with the in-kernel compression implementation of zcache, and
- * adds code to glue them together. When a page is "put" to RAMster, it is
- * compressed and stored locally. Periodically, a thread will "remotify" these
- * pages by sending them via messages to a remote machine. When the page is
- * later needed as indicated by a page fault, a "get" is issued. If the data
- * is local, it is uncompressed and the fault is resolved. If the data is
- * remote, a message is sent to fetch the data and the faulting thread sleeps;
- * when the data arrives, the thread awakens, the data is decompressed and
- * the fault is resolved.
-
- * As of V5, clusters up to eight nodes are supported; each node can remotify
- * pages to one specified node, so clusters can be configured as clients to
- * a "memory server". Some simple policy is in place that will need to be
- * refined over time. Larger clusters and fault-resistant protocols can also
- * be added over time.
- */
-
-#include <linux/module.h>
-#include <linux/cpu.h>
-#include <linux/highmem.h>
-#include <linux/list.h>
-#include <linux/lzo.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/atomic.h>
-#include <linux/frontswap.h>
-#include "../tmem.h"
-#include "../zcache.h"
-#include "../zbud.h"
-#include "ramster.h"
-#include "ramster_nodemanager.h"
-#include "tcp.h"
-#include "debug.h"
-
-#define RAMSTER_TESTING
-
-#ifndef CONFIG_SYSFS
-#error "ramster needs sysfs to define cluster nodes to use"
-#endif
-
-static bool use_cleancache __read_mostly;
-static bool use_frontswap __read_mostly;
-static bool use_frontswap_exclusive_gets __read_mostly;
-
-/* These must be sysfs not debugfs as they are checked/used by userland!! */
-static unsigned long ramster_interface_revision __read_mostly =
- R2NM_API_VERSION; /* interface revision must match userspace! */
-static unsigned long ramster_pers_remotify_enable __read_mostly;
-static unsigned long ramster_eph_remotify_enable __read_mostly;
-static atomic_t ramster_remote_pers_pages = ATOMIC_INIT(0);
-#define MANUAL_NODES 8
-static bool ramster_nodes_manual_up[MANUAL_NODES] __read_mostly;
-static int ramster_remote_target_nodenum __read_mostly = -1;
-
-/* Used by this code. */
-long ramster_flnodes;
-/* FIXME frontswap selfshrinking knobs in debugfs? */
-
-static LIST_HEAD(ramster_rem_op_list);
-static DEFINE_SPINLOCK(ramster_rem_op_list_lock);
-static DEFINE_PER_CPU(struct ramster_preload, ramster_preloads);
-
-static DEFINE_PER_CPU(unsigned char *, ramster_remoteputmem1);
-static DEFINE_PER_CPU(unsigned char *, ramster_remoteputmem2);
-
-static struct kmem_cache *ramster_flnode_cache __read_mostly;
-
-static struct flushlist_node *ramster_flnode_alloc(struct tmem_pool *pool)
-{
- struct flushlist_node *flnode = NULL;
- struct ramster_preload *kp;
-
- kp = &__get_cpu_var(ramster_preloads);
- flnode = kp->flnode;
- BUG_ON(flnode == NULL);
- kp->flnode = NULL;
- inc_ramster_flnodes();
- return flnode;
-}
-
-/* the "flush list" asynchronously collects pages to remotely flush */
-#define FLUSH_ENTIRE_OBJECT ((uint32_t)-1)
-static void ramster_flnode_free(struct flushlist_node *flnode,
- struct tmem_pool *pool)
-{
- dec_ramster_flnodes();
- BUG_ON(ramster_flnodes < 0);
- kmem_cache_free(ramster_flnode_cache, flnode);
-}
-
-int ramster_do_preload_flnode(struct tmem_pool *pool)
-{
- struct ramster_preload *kp;
- struct flushlist_node *flnode;
- int ret = -ENOMEM;
-
- BUG_ON(!irqs_disabled());
- if (unlikely(ramster_flnode_cache == NULL))
- BUG();
- kp = &__get_cpu_var(ramster_preloads);
- flnode = kmem_cache_alloc(ramster_flnode_cache, GFP_ATOMIC);
- if (unlikely(flnode == NULL) && kp->flnode == NULL)
- BUG(); /* FIXME handle more gracefully, but how??? */
- else if (kp->flnode == NULL)
- kp->flnode = flnode;
- else
- kmem_cache_free(ramster_flnode_cache, flnode);
- return ret;
-}
-EXPORT_SYMBOL_GPL(ramster_do_preload_flnode);
-
-/*
- * Called by the message handler after a (still compressed) page has been
- * fetched from the remote machine in response to an "is_remote" tmem_get
- * or persistent tmem_localify. For a tmem_get, "extra" is the address of
- * the page that is to be filled to successfully resolve the tmem_get; for
- * a (persistent) tmem_localify, "extra" is NULL (as the data is placed only
- * in the local zcache). "data" points to "size" bytes of (compressed) data
- * passed in the message. In the case of a persistent remote get, if
- * pre-allocation was successful (see ramster_repatriate_preload), the page
- * is placed into both local zcache and at "extra".
- */
-int ramster_localify(int pool_id, struct tmem_oid *oidp, uint32_t index,
- char *data, unsigned int size, void *extra)
-{
- int ret = -ENOENT;
- unsigned long flags;
- struct tmem_pool *pool;
- bool eph, delete = false;
- void *pampd, *saved_hb;
- struct tmem_obj *obj;
-
- pool = zcache_get_pool_by_id(LOCAL_CLIENT, pool_id);
- if (unlikely(pool == NULL))
- /* pool doesn't exist anymore */
- goto out;
- eph = is_ephemeral(pool);
- local_irq_save(flags); /* FIXME: maybe only disable softirqs? */
- pampd = tmem_localify_get_pampd(pool, oidp, index, &obj, &saved_hb);
- if (pampd == NULL) {
- /* hmmm... must have been a flush while waiting */
-#ifdef RAMSTER_TESTING
- pr_err("UNTESTED pampd==NULL in ramster_localify\n");
-#endif
- if (eph)
- inc_ramster_remote_eph_pages_unsucc_get();
- else
- inc_ramster_remote_pers_pages_unsucc_get();
- obj = NULL;
- goto finish;
- } else if (unlikely(!pampd_is_remote(pampd))) {
- /* hmmm... must have been a dup put while waiting */
-#ifdef RAMSTER_TESTING
- pr_err("UNTESTED dup while waiting in ramster_localify\n");
-#endif
- if (eph)
- inc_ramster_remote_eph_pages_unsucc_get();
- else
- inc_ramster_remote_pers_pages_unsucc_get();
- obj = NULL;
- pampd = NULL;
- ret = -EEXIST;
- goto finish;
- } else if (size == 0) {
- /* no remote data, delete the local is_remote pampd */
- pampd = NULL;
- if (eph)
- inc_ramster_remote_eph_pages_unsucc_get();
- else
- BUG();
- delete = true;
- goto finish;
- }
- if (pampd_is_intransit(pampd)) {
- /*
- * a pampd is marked intransit if it is remote and space has
- * been allocated for it locally (note, only happens for
- * persistent pages, in which case the remote copy is freed)
- */
- BUG_ON(eph);
- pampd = pampd_mask_intransit_and_remote(pampd);
- zbud_copy_to_zbud(pampd, data, size);
- } else {
- /*
- * setting pampd to NULL tells tmem_localify_finish to leave
- * pampd alone... meaning it is left pointing to the
- * remote copy
- */
- pampd = NULL;
- obj = NULL;
- }
- /*
- * but in all cases, we decompress direct-to-memory to complete
- * the remotify and return success
- */
- BUG_ON(extra == NULL);
- zcache_decompress_to_page(data, size, (struct page *)extra);
- if (eph)
- inc_ramster_remote_eph_pages_succ_get();
- else
- inc_ramster_remote_pers_pages_succ_get();
- ret = 0;
-finish:
- tmem_localify_finish(obj, index, pampd, saved_hb, delete);
- zcache_put_pool(pool);
- local_irq_restore(flags);
-out:
- return ret;
-}
-
-void ramster_pampd_new_obj(struct tmem_obj *obj)
-{
- obj->extra = NULL;
-}
-
-void ramster_pampd_free_obj(struct tmem_pool *pool, struct tmem_obj *obj,
- bool pool_destroy)
-{
- struct flushlist_node *flnode;
-
- BUG_ON(preemptible());
- if (obj->extra == NULL)
- return;
- if (pool_destroy && is_ephemeral(pool))
- /* FIXME don't bother with remote eph data for now */
- return;
- BUG_ON(!pampd_is_remote(obj->extra));
- flnode = ramster_flnode_alloc(pool);
- flnode->xh.client_id = pampd_remote_node(obj->extra);
- flnode->xh.pool_id = pool->pool_id;
- flnode->xh.oid = obj->oid;
- flnode->xh.index = FLUSH_ENTIRE_OBJECT;
- flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_OBJ;
- spin_lock(&ramster_rem_op_list_lock);
- list_add(&flnode->rem_op.list, &ramster_rem_op_list);
- spin_unlock(&ramster_rem_op_list_lock);
-}
-
-/*
- * Called on a remote persistent tmem_get to attempt to preallocate
- * local storage for the data contained in the remote persistent page.
- * If successfully preallocated, returns the pampd, marked as remote and
- * in_transit. Else returns NULL. Note that the appropriate tmem data
- * structure must be locked.
- */
-void *ramster_pampd_repatriate_preload(void *pampd, struct tmem_pool *pool,
- struct tmem_oid *oidp, uint32_t index,
- bool *intransit)
-{
- int clen = pampd_remote_size(pampd), c;
- void *ret_pampd = NULL;
- unsigned long flags;
- struct tmem_handle th;
-
- BUG_ON(!pampd_is_remote(pampd));
- BUG_ON(is_ephemeral(pool));
- if (use_frontswap_exclusive_gets)
- /* don't need local storage */
- goto out;
- if (pampd_is_intransit(pampd)) {
- /*
- * to avoid multiple allocations (and maybe a memory leak)
- * don't preallocate if already in the process of being
- * repatriated
- */
- *intransit = true;
- goto out;
- }
- *intransit = false;
- local_irq_save(flags);
- th.client_id = pampd_remote_node(pampd);
- th.pool_id = pool->pool_id;
- th.oid = *oidp;
- th.index = index;
- ret_pampd = zcache_pampd_create(NULL, clen, true, false, &th);
- if (ret_pampd != NULL) {
- /*
- * a pampd is marked intransit if it is remote and space has
- * been allocated for it locally (note, only happens for
- * persistent pages, in which case the remote copy is freed)
- */
- ret_pampd = pampd_mark_intransit(ret_pampd);
- c = atomic_dec_return(&ramster_remote_pers_pages);
- WARN_ON_ONCE(c < 0);
- } else {
- inc_ramster_pers_pages_remote_nomem();
- }
- local_irq_restore(flags);
-out:
- return ret_pampd;
-}
-
-/*
- * Called on a remote tmem_get to invoke a message to fetch the page.
- * Might sleep so no tmem locks can be held. "extra" is passed
- * all the way through the round-trip messaging to ramster_localify.
- */
-int ramster_pampd_repatriate(void *fake_pampd, void *real_pampd,
- struct tmem_pool *pool,
- struct tmem_oid *oid, uint32_t index,
- bool free, void *extra)
-{
- struct tmem_xhandle xh;
- int ret;
-
- if (pampd_is_intransit(real_pampd))
- /* have local space pre-reserved, so free remote copy */
- free = true;
- xh = tmem_xhandle_fill(LOCAL_CLIENT, pool, oid, index);
- /* unreliable request/response for now */
- ret = r2net_remote_async_get(&xh, free,
- pampd_remote_node(fake_pampd),
- pampd_remote_size(fake_pampd),
- pampd_remote_cksum(fake_pampd),
- extra);
- return ret;
-}
-
-bool ramster_pampd_is_remote(void *pampd)
-{
- return pampd_is_remote(pampd);
-}
-
-int ramster_pampd_replace_in_obj(void *new_pampd, struct tmem_obj *obj)
-{
- int ret = -1;
-
- if (new_pampd != NULL) {
- if (obj->extra == NULL)
- obj->extra = new_pampd;
- /* enforce that all remote pages in an object reside
- * in the same node! */
- else if (pampd_remote_node(new_pampd) !=
- pampd_remote_node((void *)(obj->extra)))
- BUG();
- ret = 0;
- }
- return ret;
-}
-
-void *ramster_pampd_free(void *pampd, struct tmem_pool *pool,
- struct tmem_oid *oid, uint32_t index, bool acct)
-{
- bool eph = is_ephemeral(pool);
- void *local_pampd = NULL;
- int c;
-
- BUG_ON(preemptible());
- BUG_ON(!pampd_is_remote(pampd));
- WARN_ON(acct == false);
- if (oid == NULL) {
- /*
- * a NULL oid means to ignore this pampd free
- * as the remote freeing will be handled elsewhere
- */
- } else if (eph) {
- /* FIXME remote flush optional but probably good idea */
- } else if (pampd_is_intransit(pampd)) {
- /* did a pers remote get_and_free, so just free local */
- local_pampd = pampd_mask_intransit_and_remote(pampd);
- } else {
- struct flushlist_node *flnode =
- ramster_flnode_alloc(pool);
-
- flnode->xh.client_id = pampd_remote_node(pampd);
- flnode->xh.pool_id = pool->pool_id;
- flnode->xh.oid = *oid;
- flnode->xh.index = index;
- flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_PAGE;
- spin_lock(&ramster_rem_op_list_lock);
- list_add(&flnode->rem_op.list, &ramster_rem_op_list);
- spin_unlock(&ramster_rem_op_list_lock);
- c = atomic_dec_return(&ramster_remote_pers_pages);
- WARN_ON_ONCE(c < 0);
- }
- return local_pampd;
-}
-EXPORT_SYMBOL_GPL(ramster_pampd_free);
-
-void ramster_count_foreign_pages(bool eph, int count)
-{
- BUG_ON(count != 1 && count != -1);
- if (eph) {
- if (count > 0) {
- inc_ramster_foreign_eph_pages();
- } else {
- dec_ramster_foreign_eph_pages();
-#ifdef CONFIG_RAMSTER_DEBUG
- WARN_ON_ONCE(ramster_foreign_eph_pages < 0);
-#endif
- }
- } else {
- if (count > 0) {
- inc_ramster_foreign_pers_pages();
- } else {
- dec_ramster_foreign_pers_pages();
-#ifdef CONFIG_RAMSTER_DEBUG
- WARN_ON_ONCE(ramster_foreign_pers_pages < 0);
-#endif
- }
- }
-}
-EXPORT_SYMBOL_GPL(ramster_count_foreign_pages);
-
-/*
- * For now, just push over a few pages every few seconds to
- * ensure that it basically works
- */
-static struct workqueue_struct *ramster_remotify_workqueue;
-static void ramster_remotify_process(struct work_struct *work);
-static DECLARE_DELAYED_WORK(ramster_remotify_worker,
- ramster_remotify_process);
-
-static void ramster_remotify_queue_delayed_work(unsigned long delay)
-{
- if (!queue_delayed_work(ramster_remotify_workqueue,
- &ramster_remotify_worker, delay))
- pr_err("ramster_remotify: bad workqueue\n");
-}
-
-static void ramster_remote_flush_page(struct flushlist_node *flnode)
-{
- struct tmem_xhandle *xh;
- int remotenode, ret;
-
- preempt_disable();
- xh = &flnode->xh;
- remotenode = flnode->xh.client_id;
- ret = r2net_remote_flush(xh, remotenode);
- if (ret >= 0)
- inc_ramster_remote_pages_flushed();
- else
- inc_ramster_remote_page_flushes_failed();
- preempt_enable_no_resched();
- ramster_flnode_free(flnode, NULL);
-}
-
-static void ramster_remote_flush_object(struct flushlist_node *flnode)
-{
- struct tmem_xhandle *xh;
- int remotenode, ret;
-
- preempt_disable();
- xh = &flnode->xh;
- remotenode = flnode->xh.client_id;
- ret = r2net_remote_flush_object(xh, remotenode);
- if (ret >= 0)
- inc_ramster_remote_objects_flushed();
- else
- inc_ramster_remote_object_flushes_failed();
- preempt_enable_no_resched();
- ramster_flnode_free(flnode, NULL);
-}
-
-int ramster_remotify_pageframe(bool eph)
-{
- struct tmem_xhandle xh;
- unsigned int size;
- int remotenode, ret, zbuds;
- struct tmem_pool *pool;
- unsigned long flags;
- unsigned char cksum;
- char *p;
- int i, j;
- unsigned char *tmpmem[2];
- struct tmem_handle th[2];
- unsigned int zsize[2];
-
- tmpmem[0] = __get_cpu_var(ramster_remoteputmem1);
- tmpmem[1] = __get_cpu_var(ramster_remoteputmem2);
- local_bh_disable();
- zbuds = zbud_make_zombie_lru(&th[0], &tmpmem[0], &zsize[0], eph);
- /* now OK to release lock set in caller */
- local_bh_enable();
- if (zbuds == 0)
- goto out;
- BUG_ON(zbuds > 2);
- for (i = 0; i < zbuds; i++) {
- xh.client_id = th[i].client_id;
- xh.pool_id = th[i].pool_id;
- xh.oid = th[i].oid;
- xh.index = th[i].index;
- size = zsize[i];
- BUG_ON(size == 0 || size > zbud_max_buddy_size());
- for (p = tmpmem[i], cksum = 0, j = 0; j < size; j++)
- cksum += *p++;
- ret = r2net_remote_put(&xh, tmpmem[i], size, eph, &remotenode);
- if (ret != 0) {
- /*
- * This is some form of a memory leak... if the remote put
- * fails, there will never be another attempt to remotify
- * this page. But since we've dropped the zv pointer,
- * the page may have been freed or the data replaced
- * so we can't just "put it back" in the remote op list.
- * Even if we could, not sure where to put it in the list
- * because there may be flushes that must be strictly
- * ordered vs the put. So leave this as a FIXME for now.
- * But count them so we know if it becomes a problem.
- */
- if (eph)
- inc_ramster_eph_pages_remote_failed();
- else
- inc_ramster_pers_pages_remote_failed();
- break;
- } else {
- if (!eph)
- atomic_inc(&ramster_remote_pers_pages);
- }
- if (eph)
- inc_ramster_eph_pages_remoted();
- else
- inc_ramster_pers_pages_remoted();
- /*
- * data was successfully remoted so change the local version to
- * point to the remote node where it landed
- */
- local_bh_disable();
- pool = zcache_get_pool_by_id(LOCAL_CLIENT, xh.pool_id);
- local_irq_save(flags);
- (void)tmem_replace(pool, &xh.oid, xh.index,
- pampd_make_remote(remotenode, size, cksum));
- local_irq_restore(flags);
- zcache_put_pool(pool);
- local_bh_enable();
- }
-out:
- return zbuds;
-}
-
-static void zcache_do_remotify_flushes(void)
-{
- struct ramster_remotify_hdr *rem_op;
- union remotify_list_node *u;
-
- while (1) {
- spin_lock(&ramster_rem_op_list_lock);
- if (list_empty(&ramster_rem_op_list)) {
- spin_unlock(&ramster_rem_op_list_lock);
- goto out;
- }
- rem_op = list_first_entry(&ramster_rem_op_list,
- struct ramster_remotify_hdr, list);
- list_del_init(&rem_op->list);
- spin_unlock(&ramster_rem_op_list_lock);
- u = (union remotify_list_node *)rem_op;
- switch (rem_op->op) {
- case RAMSTER_REMOTIFY_FLUSH_PAGE:
- ramster_remote_flush_page((struct flushlist_node *)u);
- break;
- case RAMSTER_REMOTIFY_FLUSH_OBJ:
- ramster_remote_flush_object((struct flushlist_node *)u);
- break;
- default:
- BUG();
- }
- }
-out:
- return;
-}
-
-static void ramster_remotify_process(struct work_struct *work)
-{
- static bool remotify_in_progress;
- int i;
-
- BUG_ON(irqs_disabled());
- if (remotify_in_progress)
- goto requeue;
- if (ramster_remote_target_nodenum == -1)
- goto requeue;
- remotify_in_progress = true;
- if (use_cleancache && ramster_eph_remotify_enable) {
- for (i = 0; i < 100; i++) {
- zcache_do_remotify_flushes();
- (void)ramster_remotify_pageframe(true);
- }
- }
- if (use_frontswap && ramster_pers_remotify_enable) {
- for (i = 0; i < 100; i++) {
- zcache_do_remotify_flushes();
- (void)ramster_remotify_pageframe(false);
- }
- }
- remotify_in_progress = false;
-requeue:
- ramster_remotify_queue_delayed_work(HZ);
-}
-
-void ramster_remotify_init(void)
-{
- unsigned long n = 60UL;
- ramster_remotify_workqueue =
- create_singlethread_workqueue("ramster_remotify");
- ramster_remotify_queue_delayed_work(n * HZ);
-}
-
-static ssize_t ramster_manual_node_up_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- int i;
- char *p = buf;
- for (i = 0; i < MANUAL_NODES; i++)
- if (ramster_nodes_manual_up[i])
- p += sprintf(p, "%d ", i);
- p += sprintf(p, "\n");
- return p - buf;
-}
-
-static ssize_t ramster_manual_node_up_store(struct kobject *kobj,
- struct kobj_attribute *attr, const char *buf, size_t count)
-{
- int err;
- unsigned long node_num;
-
- err = kstrtoul(buf, 10, &node_num);
- if (err) {
- pr_err("ramster: bad strtoul?\n");
- return -EINVAL;
- }
- if (node_num >= MANUAL_NODES) {
- pr_err("ramster: bad node_num=%lu?\n", node_num);
- return -EINVAL;
- }
- if (ramster_nodes_manual_up[node_num]) {
- pr_err("ramster: node %d already up, ignoring\n",
- (int)node_num);
- } else {
- ramster_nodes_manual_up[node_num] = true;
- r2net_hb_node_up_manual((int)node_num);
- }
- return count;
-}
-
-static struct kobj_attribute ramster_manual_node_up_attr = {
- .attr = { .name = "manual_node_up", .mode = 0644 },
- .show = ramster_manual_node_up_show,
- .store = ramster_manual_node_up_store,
-};
-
-static ssize_t ramster_remote_target_nodenum_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- if (ramster_remote_target_nodenum == -1UL)
- return sprintf(buf, "unset\n");
- else
- return sprintf(buf, "%d\n", ramster_remote_target_nodenum);
-}
-
-static ssize_t ramster_remote_target_nodenum_store(struct kobject *kobj,
- struct kobj_attribute *attr, const char *buf, size_t count)
-{
- int err;
- unsigned long node_num;
-
- err = kstrtoul(buf, 10, &node_num);
- if (err) {
- pr_err("ramster: bad strtoul?\n");
- return -EINVAL;
- } else if (node_num == -1UL) {
- pr_err("ramster: disabling all remotification, "
- "data may still reside on remote nodes however\n");
- return -EINVAL;
- } else if (node_num >= MANUAL_NODES) {
- pr_err("ramster: bad node_num=%lu?\n", node_num);
- return -EINVAL;
- } else if (!ramster_nodes_manual_up[node_num]) {
- pr_err("ramster: node %d not up, ignoring setting "
- "of remotification target\n", (int)node_num);
- } else if (r2net_remote_target_node_set((int)node_num) >= 0) {
- pr_info("ramster: node %d set as remotification target\n",
- (int)node_num);
- ramster_remote_target_nodenum = (int)node_num;
- } else {
- pr_err("ramster: bad num to node node_num=%d?\n",
- (int)node_num);
- return -EINVAL;
- }
- return count;
-}
-
-static struct kobj_attribute ramster_remote_target_nodenum_attr = {
- .attr = { .name = "remote_target_nodenum", .mode = 0644 },
- .show = ramster_remote_target_nodenum_show,
- .store = ramster_remote_target_nodenum_store,
-};
-
-#define RAMSTER_SYSFS_RO(_name) \
- static ssize_t ramster_##_name##_show(struct kobject *kobj, \
- struct kobj_attribute *attr, char *buf) \
- { \
- return sprintf(buf, "%lu\n", ramster_##_name); \
- } \
- static struct kobj_attribute ramster_##_name##_attr = { \
- .attr = { .name = __stringify(_name), .mode = 0444 }, \
- .show = ramster_##_name##_show, \
- }
-
-#define RAMSTER_SYSFS_RW(_name) \
- static ssize_t ramster_##_name##_show(struct kobject *kobj, \
- struct kobj_attribute *attr, char *buf) \
- { \
- return sprintf(buf, "%lu\n", ramster_##_name); \
- } \
- static ssize_t ramster_##_name##_store(struct kobject *kobj, \
- struct kobj_attribute *attr, const char *buf, size_t count) \
- { \
- int err; \
- unsigned long enable; \
- err = kstrtoul(buf, 10, &enable); \
- if (err) \
- return -EINVAL; \
- ramster_##_name = enable; \
- return count; \
- } \
- static struct kobj_attribute ramster_##_name##_attr = { \
- .attr = { .name = __stringify(_name), .mode = 0644 }, \
- .show = ramster_##_name##_show, \
- .store = ramster_##_name##_store, \
- }
-
-#define RAMSTER_SYSFS_RO_ATOMIC(_name) \
- static ssize_t ramster_##_name##_show(struct kobject *kobj, \
- struct kobj_attribute *attr, char *buf) \
- { \
- return sprintf(buf, "%d\n", atomic_read(&ramster_##_name)); \
- } \
- static struct kobj_attribute ramster_##_name##_attr = { \
- .attr = { .name = __stringify(_name), .mode = 0444 }, \
- .show = ramster_##_name##_show, \
- }
-
-RAMSTER_SYSFS_RO(interface_revision);
-RAMSTER_SYSFS_RO_ATOMIC(remote_pers_pages);
-RAMSTER_SYSFS_RW(pers_remotify_enable);
-RAMSTER_SYSFS_RW(eph_remotify_enable);
-
-static struct attribute *ramster_attrs[] = {
- &ramster_interface_revision_attr.attr,
- &ramster_remote_pers_pages_attr.attr,
- &ramster_manual_node_up_attr.attr,
- &ramster_remote_target_nodenum_attr.attr,
- &ramster_pers_remotify_enable_attr.attr,
- &ramster_eph_remotify_enable_attr.attr,
- NULL,
-};
-
-static struct attribute_group ramster_attr_group = {
- .attrs = ramster_attrs,
- .name = "ramster",
-};
-
-/*
- * frontswap selfshrinking
- */
-
-/* In HZ, controls frequency of worker invocation. */
-static unsigned int selfshrink_interval __read_mostly = 5;
-/* Enable/disable with sysfs. */
-static bool frontswap_selfshrinking __read_mostly;
-
-static void selfshrink_process(struct work_struct *work);
-static DECLARE_DELAYED_WORK(selfshrink_worker, selfshrink_process);
-
-#ifndef CONFIG_RAMSTER_MODULE
-/* Enable/disable with kernel boot option. */
-static bool use_frontswap_selfshrink = true;
-#endif
-
-/*
- * The default values for the following parameters were deemed reasonable
- * by experimentation, may be workload-dependent, and can all be
- * adjusted via sysfs.
- */
-
-/* Control rate for frontswap shrinking. Higher hysteresis is slower. */
-static unsigned int frontswap_hysteresis __read_mostly = 20;
-
-/*
- * Number of selfshrink worker invocations to wait before observing that
- * frontswap selfshrinking should commence. Note that selfshrinking does
- * not use a separate worker thread.
- */
-static unsigned int frontswap_inertia __read_mostly = 3;
-
-/* Countdown to next invocation of frontswap_shrink() */
-static unsigned long frontswap_inertia_counter;
-
-/*
- * Invoked by the selfshrink worker thread, uses current number of pages
- * in frontswap (frontswap_curr_pages()), previous status, and control
- * values (hysteresis and inertia) to determine if frontswap should be
- * shrunk and what the new frontswap size should be. Note that
- * frontswap_shrink is essentially a partial swapoff that immediately
- * transfers pages from the "swap device" (frontswap) back into kernel
- * RAM; despite the name, frontswap "shrinking" is very different from
- * the "shrinker" interface used by the kernel MM subsystem to reclaim
- * memory.
- */
-static void frontswap_selfshrink(void)
-{
- static unsigned long cur_frontswap_pages;
- static unsigned long last_frontswap_pages;
- static unsigned long tgt_frontswap_pages;
-
- last_frontswap_pages = cur_frontswap_pages;
- cur_frontswap_pages = frontswap_curr_pages();
- if (!cur_frontswap_pages ||
- (cur_frontswap_pages > last_frontswap_pages)) {
- frontswap_inertia_counter = frontswap_inertia;
- return;
- }
- if (frontswap_inertia_counter && --frontswap_inertia_counter)
- return;
- if (cur_frontswap_pages <= frontswap_hysteresis)
- tgt_frontswap_pages = 0;
- else
- tgt_frontswap_pages = cur_frontswap_pages -
- (cur_frontswap_pages / frontswap_hysteresis);
- frontswap_shrink(tgt_frontswap_pages);
-}
-
-#ifndef CONFIG_RAMSTER_MODULE
-static int __init ramster_nofrontswap_selfshrink_setup(char *s)
-{
- use_frontswap_selfshrink = false;
- return 1;
-}
-
-__setup("noselfshrink", ramster_nofrontswap_selfshrink_setup);
-#endif
-
-static void selfshrink_process(struct work_struct *work)
-{
- if (frontswap_selfshrinking && frontswap_enabled) {
- frontswap_selfshrink();
- schedule_delayed_work(&selfshrink_worker,
- selfshrink_interval * HZ);
- }
-}
-
-void ramster_cpu_up(int cpu)
-{
- unsigned char *p1 = kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT);
- unsigned char *p2 = kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT);
- BUG_ON(!p1 || !p2);
- per_cpu(ramster_remoteputmem1, cpu) = p1;
- per_cpu(ramster_remoteputmem2, cpu) = p2;
-}
-EXPORT_SYMBOL_GPL(ramster_cpu_up);
-
-void ramster_cpu_down(int cpu)
-{
- struct ramster_preload *kp;
-
- kfree(per_cpu(ramster_remoteputmem1, cpu));
- per_cpu(ramster_remoteputmem1, cpu) = NULL;
- kfree(per_cpu(ramster_remoteputmem2, cpu));
- per_cpu(ramster_remoteputmem2, cpu) = NULL;
- kp = &per_cpu(ramster_preloads, cpu);
- if (kp->flnode) {
- kmem_cache_free(ramster_flnode_cache, kp->flnode);
- kp->flnode = NULL;
- }
-}
-EXPORT_SYMBOL_GPL(ramster_cpu_down);
-
-void ramster_register_pamops(struct tmem_pamops *pamops)
-{
- pamops->free_obj = ramster_pampd_free_obj;
- pamops->new_obj = ramster_pampd_new_obj;
- pamops->replace_in_obj = ramster_pampd_replace_in_obj;
- pamops->is_remote = ramster_pampd_is_remote;
- pamops->repatriate = ramster_pampd_repatriate;
- pamops->repatriate_preload = ramster_pampd_repatriate_preload;
-}
-EXPORT_SYMBOL_GPL(ramster_register_pamops);
-
-void ramster_init(bool cleancache, bool frontswap,
- bool frontswap_exclusive_gets,
- bool frontswap_selfshrink)
-{
- int ret = 0;
-
- if (cleancache)
- use_cleancache = true;
- if (frontswap)
- use_frontswap = true;
- if (frontswap_exclusive_gets)
- use_frontswap_exclusive_gets = true;
- ramster_debugfs_init();
- ret = sysfs_create_group(mm_kobj, &ramster_attr_group);
- if (ret)
- pr_err("ramster: can't create sysfs for ramster\n");
- (void)r2net_register_handlers();
-#ifdef CONFIG_RAMSTER_MODULE
- ret = r2nm_init();
- if (ret)
- pr_err("ramster: can't init r2net\n");
- frontswap_selfshrinking = frontswap_selfshrink;
-#else
- frontswap_selfshrinking = use_frontswap_selfshrink;
-#endif
- INIT_LIST_HEAD(&ramster_rem_op_list);
- ramster_flnode_cache = kmem_cache_create("ramster_flnode",
- sizeof(struct flushlist_node), 0, 0, NULL);
- if (frontswap_selfshrinking) {
- pr_info("ramster: Initializing frontswap selfshrink driver.\n");
- schedule_delayed_work(&selfshrink_worker,
- selfshrink_interval * HZ);
- }
- ramster_remotify_init();
-}
-EXPORT_SYMBOL_GPL(ramster_init);
diff --git a/drivers/staging/zcache/ramster/ramster.h b/drivers/staging/zcache/ramster/ramster.h
deleted file mode 100644
index 6d41a7a772e..00000000000
--- a/drivers/staging/zcache/ramster/ramster.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * ramster.h
- *
- * Peer-to-peer transcendent memory
- *
- * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
- */
-
-#ifndef _RAMSTER_RAMSTER_H_
-#define _RAMSTER_RAMSTER_H_
-
-#include "../tmem.h"
-
-enum ramster_remotify_op {
- RAMSTER_REMOTIFY_FLUSH_PAGE,
- RAMSTER_REMOTIFY_FLUSH_OBJ,
-};
-
-struct ramster_remotify_hdr {
- enum ramster_remotify_op op;
- struct list_head list;
-};
-
-struct flushlist_node {
- struct ramster_remotify_hdr rem_op;
- struct tmem_xhandle xh;
-};
-
-struct ramster_preload {
- struct flushlist_node *flnode;
-};
-
-union remotify_list_node {
- struct ramster_remotify_hdr rem_op;
- struct {
- struct ramster_remotify_hdr rem_op;
- struct tmem_handle th;
- } zbud_hdr;
- struct flushlist_node flist;
-};
-
-/*
- * format of remote pampd:
- * bit 0 is reserved for zbud (in-page buddy selection)
- * bit 1 == intransit
- * bit 2 == is_remote... if this bit is set, then
- * bit 3-10 == remotenode
- * bit 11-23 == size
- * bit 24-31 == cksum
- */
-#define FAKE_PAMPD_INTRANSIT_BITS 1
-#define FAKE_PAMPD_ISREMOTE_BITS 1
-#define FAKE_PAMPD_REMOTENODE_BITS 8
-#define FAKE_PAMPD_REMOTESIZE_BITS 13
-#define FAKE_PAMPD_CHECKSUM_BITS 8
-
-#define FAKE_PAMPD_INTRANSIT_SHIFT 1
-#define FAKE_PAMPD_ISREMOTE_SHIFT (FAKE_PAMPD_INTRANSIT_SHIFT + \
- FAKE_PAMPD_INTRANSIT_BITS)
-#define FAKE_PAMPD_REMOTENODE_SHIFT (FAKE_PAMPD_ISREMOTE_SHIFT + \
- FAKE_PAMPD_ISREMOTE_BITS)
-#define FAKE_PAMPD_REMOTESIZE_SHIFT (FAKE_PAMPD_REMOTENODE_SHIFT + \
- FAKE_PAMPD_REMOTENODE_BITS)
-#define FAKE_PAMPD_CHECKSUM_SHIFT (FAKE_PAMPD_REMOTESIZE_SHIFT + \
- FAKE_PAMPD_REMOTESIZE_BITS)
-
-#define FAKE_PAMPD_MASK(x) ((1UL << (x)) - 1)
-
-static inline void *pampd_make_remote(int remotenode, size_t size,
- unsigned char cksum)
-{
- unsigned long fake_pampd = 0;
- fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT;
- fake_pampd |= ((unsigned long)remotenode &
- FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS)) <<
- FAKE_PAMPD_REMOTENODE_SHIFT;
- fake_pampd |= ((unsigned long)size &
- FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS)) <<
- FAKE_PAMPD_REMOTESIZE_SHIFT;
- fake_pampd |= ((unsigned long)cksum &
- FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS)) <<
- FAKE_PAMPD_CHECKSUM_SHIFT;
- return (void *)fake_pampd;
-}
-
-static inline unsigned int pampd_remote_node(void *pampd)
-{
- unsigned long fake_pampd = (unsigned long)pampd;
- return (fake_pampd >> FAKE_PAMPD_REMOTENODE_SHIFT) &
- FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS);
-}
-
-static inline unsigned int pampd_remote_size(void *pampd)
-{
- unsigned long fake_pampd = (unsigned long)pampd;
- return (fake_pampd >> FAKE_PAMPD_REMOTESIZE_SHIFT) &
- FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS);
-}
-
-static inline unsigned char pampd_remote_cksum(void *pampd)
-{
- unsigned long fake_pampd = (unsigned long)pampd;
- return (fake_pampd >> FAKE_PAMPD_CHECKSUM_SHIFT) &
- FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS);
-}
-
-static inline bool pampd_is_remote(void *pampd)
-{
- unsigned long fake_pampd = (unsigned long)pampd;
- return (fake_pampd >> FAKE_PAMPD_ISREMOTE_SHIFT) &
- FAKE_PAMPD_MASK(FAKE_PAMPD_ISREMOTE_BITS);
-}
-
-static inline bool pampd_is_intransit(void *pampd)
-{
- unsigned long fake_pampd = (unsigned long)pampd;
- return (fake_pampd >> FAKE_PAMPD_INTRANSIT_SHIFT) &
- FAKE_PAMPD_MASK(FAKE_PAMPD_INTRANSIT_BITS);
-}
-
-/* note that it is a BUG for intransit to be set without isremote also set */
-static inline void *pampd_mark_intransit(void *pampd)
-{
- unsigned long fake_pampd = (unsigned long)pampd;
-
- fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT;
- fake_pampd |= 1UL << FAKE_PAMPD_INTRANSIT_SHIFT;
- return (void *)fake_pampd;
-}
-
-static inline void *pampd_mask_intransit_and_remote(void *marked_pampd)
-{
- unsigned long pampd = (unsigned long)marked_pampd;
-
- pampd &= ~(1UL << FAKE_PAMPD_INTRANSIT_SHIFT);
- pampd &= ~(1UL << FAKE_PAMPD_ISREMOTE_SHIFT);
- return (void *)pampd;
-}
-
-extern int r2net_remote_async_get(struct tmem_xhandle *,
- bool, int, size_t, uint8_t, void *extra);
-extern int r2net_remote_put(struct tmem_xhandle *, char *, size_t,
- bool, int *);
-extern int r2net_remote_flush(struct tmem_xhandle *, int);
-extern int r2net_remote_flush_object(struct tmem_xhandle *, int);
-extern int r2net_register_handlers(void);
-extern int r2net_remote_target_node_set(int);
-
-extern int ramster_remotify_pageframe(bool);
-extern void ramster_init(bool, bool, bool, bool);
-extern void ramster_register_pamops(struct tmem_pamops *);
-extern int ramster_localify(int, struct tmem_oid *oidp, uint32_t, char *,
- unsigned int, void *);
-extern void *ramster_pampd_free(void *, struct tmem_pool *, struct tmem_oid *,
- uint32_t, bool);
-extern void ramster_count_foreign_pages(bool, int);
-extern int ramster_do_preload_flnode(struct tmem_pool *);
-extern void ramster_cpu_up(int);
-extern void ramster_cpu_down(int);
-
-#endif /* _RAMSTER_RAMSTER_H */
diff --git a/drivers/staging/zcache/ramster/ramster_nodemanager.h b/drivers/staging/zcache/ramster/ramster_nodemanager.h
deleted file mode 100644
index dbaae34ea61..00000000000
--- a/drivers/staging/zcache/ramster/ramster_nodemanager.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * ramster_nodemanager.h
- *
- * Header describing the interface between userspace and the kernel
- * for the ramster_nodemanager module.
- *
- * Copyright (C) 2002, 2004, 2012 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- *
- */
-
-#ifndef _RAMSTER_NODEMANAGER_H
-#define _RAMSTER_NODEMANAGER_H
-
-#define R2NM_API_VERSION 5
-
-#define R2NM_MAX_NODES 255
-#define R2NM_INVALID_NODE_NUM 255
-
-/* host name, group name, cluster name all 64 bytes */
-#define R2NM_MAX_NAME_LEN 64 /* __NEW_UTS_LEN */
-
-extern int r2nm_init(void);
-
-#endif /* _RAMSTER_NODEMANAGER_H */
diff --git a/drivers/staging/zcache/ramster/tcp.c b/drivers/staging/zcache/ramster/tcp.c
deleted file mode 100644
index f6e1e5209d8..00000000000
--- a/drivers/staging/zcache/ramster/tcp.c
+++ /dev/null
@@ -1,2248 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- *
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * Copyright (C) 2004 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- *
- * ----
- *
- * Callers for this were originally written against a very simple synchronus
- * API. This implementation reflects those simple callers. Some day I'm sure
- * we'll need to move to a more robust posting/callback mechanism.
- *
- * Transmit calls pass in kernel virtual addresses and block copying this into
- * the socket's tx buffers via a usual blocking sendmsg. They'll block waiting
- * for a failed socket to timeout. TX callers can also pass in a poniter to an
- * 'int' which gets filled with an errno off the wire in response to the
- * message they send.
- *
- * Handlers for unsolicited messages are registered. Each socket has a page
- * that incoming data is copied into. First the header, then the data.
- * Handlers are called from only one thread with a reference to this per-socket
- * page. This page is destroyed after the handler call, so it can't be
- * referenced beyond the call. Handlers may block but are discouraged from
- * doing so.
- *
- * Any framing errors (bad magic, large payload lengths) close a connection.
- *
- * Our sock_container holds the state we associate with a socket. It's current
- * framing state is held there as well as the refcounting we do around when it
- * is safe to tear down the socket. The socket is only finally torn down from
- * the container when the container loses all of its references -- so as long
- * as you hold a ref on the container you can trust that the socket is valid
- * for use with kernel socket APIs.
- *
- * Connections are initiated between a pair of nodes when the node with the
- * higher node number gets a heartbeat callback which indicates that the lower
- * numbered node has started heartbeating. The lower numbered node is passive
- * and only accepts the connection if the higher numbered node is heartbeating.
- */
-
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/slab.h>
-#include <linux/idr.h>
-#include <linux/kref.h>
-#include <linux/net.h>
-#include <linux/export.h>
-#include <linux/uaccess.h>
-#include <net/tcp.h>
-
-
-#include "heartbeat.h"
-#include "tcp.h"
-#include "nodemanager.h"
-#define MLOG_MASK_PREFIX ML_TCP
-#include "masklog.h"
-
-#include "tcp_internal.h"
-
-#define SC_NODEF_FMT "node %s (num %u) at %pI4:%u"
-
-/*
- * In the following two log macros, the whitespace after the ',' just
- * before ##args is intentional. Otherwise, gcc 2.95 will eat the
- * previous token if args expands to nothing.
- */
-#define msglog(hdr, fmt, args...) do { \
- typeof(hdr) __hdr = (hdr); \
- mlog(ML_MSG, "[mag %u len %u typ %u stat %d sys_stat %d " \
- "key %08x num %u] " fmt, \
- be16_to_cpu(__hdr->magic), be16_to_cpu(__hdr->data_len), \
- be16_to_cpu(__hdr->msg_type), be32_to_cpu(__hdr->status), \
- be32_to_cpu(__hdr->sys_status), be32_to_cpu(__hdr->key), \
- be32_to_cpu(__hdr->msg_num) , ##args); \
-} while (0)
-
-#define sclog(sc, fmt, args...) do { \
- typeof(sc) __sc = (sc); \
- mlog(ML_SOCKET, "[sc %p refs %d sock %p node %u page %p " \
- "pg_off %zu] " fmt, __sc, \
- atomic_read(&__sc->sc_kref.refcount), __sc->sc_sock, \
- __sc->sc_node->nd_num, __sc->sc_page, __sc->sc_page_off , \
- ##args); \
-} while (0)
-
-static DEFINE_RWLOCK(r2net_handler_lock);
-static struct rb_root r2net_handler_tree = RB_ROOT;
-
-static struct r2net_node r2net_nodes[R2NM_MAX_NODES];
-
-/* XXX someday we'll need better accounting */
-static struct socket *r2net_listen_sock;
-
-/*
- * listen work is only queued by the listening socket callbacks on the
- * r2net_wq. teardown detaches the callbacks before destroying the workqueue.
- * quorum work is queued as sock containers are shutdown.. stop_listening
- * tears down all the node's sock containers, preventing future shutdowns
- * and queued quorum work, before canceling delayed quorum work and
- * destroying the work queue.
- */
-static struct workqueue_struct *r2net_wq;
-static struct work_struct r2net_listen_work;
-
-static struct r2hb_callback_func r2net_hb_up, r2net_hb_down;
-#define R2NET_HB_PRI 0x1
-
-static struct r2net_handshake *r2net_hand;
-static struct r2net_msg *r2net_keep_req, *r2net_keep_resp;
-
-static int r2net_sys_err_translations[R2NET_ERR_MAX] = {
- [R2NET_ERR_NONE] = 0,
- [R2NET_ERR_NO_HNDLR] = -ENOPROTOOPT,
- [R2NET_ERR_OVERFLOW] = -EOVERFLOW,
- [R2NET_ERR_DIED] = -EHOSTDOWN,};
-
-/* can't quite avoid *all* internal declarations :/ */
-static void r2net_sc_connect_completed(struct work_struct *work);
-static void r2net_rx_until_empty(struct work_struct *work);
-static void r2net_shutdown_sc(struct work_struct *work);
-static void r2net_listen_data_ready(struct sock *sk, int bytes);
-static void r2net_sc_send_keep_req(struct work_struct *work);
-static void r2net_idle_timer(unsigned long data);
-static void r2net_sc_postpone_idle(struct r2net_sock_container *sc);
-static void r2net_sc_reset_idle_timer(struct r2net_sock_container *sc);
-
-#ifdef CONFIG_DEBUG_FS
-static void r2net_init_nst(struct r2net_send_tracking *nst, u32 msgtype,
- u32 msgkey, struct task_struct *task, u8 node)
-{
- INIT_LIST_HEAD(&nst->st_net_debug_item);
- nst->st_task = task;
- nst->st_msg_type = msgtype;
- nst->st_msg_key = msgkey;
- nst->st_node = node;
-}
-
-static inline void r2net_set_nst_sock_time(struct r2net_send_tracking *nst)
-{
- nst->st_sock_time = ktime_get();
-}
-
-static inline void r2net_set_nst_send_time(struct r2net_send_tracking *nst)
-{
- nst->st_send_time = ktime_get();
-}
-
-static inline void r2net_set_nst_status_time(struct r2net_send_tracking *nst)
-{
- nst->st_status_time = ktime_get();
-}
-
-static inline void r2net_set_nst_sock_container(struct r2net_send_tracking *nst,
- struct r2net_sock_container *sc)
-{
- nst->st_sc = sc;
-}
-
-static inline void r2net_set_nst_msg_id(struct r2net_send_tracking *nst,
- u32 msg_id)
-{
- nst->st_id = msg_id;
-}
-
-static inline void r2net_set_sock_timer(struct r2net_sock_container *sc)
-{
- sc->sc_tv_timer = ktime_get();
-}
-
-static inline void r2net_set_data_ready_time(struct r2net_sock_container *sc)
-{
- sc->sc_tv_data_ready = ktime_get();
-}
-
-static inline void r2net_set_advance_start_time(struct r2net_sock_container *sc)
-{
- sc->sc_tv_advance_start = ktime_get();
-}
-
-static inline void r2net_set_advance_stop_time(struct r2net_sock_container *sc)
-{
- sc->sc_tv_advance_stop = ktime_get();
-}
-
-static inline void r2net_set_func_start_time(struct r2net_sock_container *sc)
-{
- sc->sc_tv_func_start = ktime_get();
-}
-
-static inline void r2net_set_func_stop_time(struct r2net_sock_container *sc)
-{
- sc->sc_tv_func_stop = ktime_get();
-}
-
-#else /* CONFIG_DEBUG_FS */
-# define r2net_init_nst(a, b, c, d, e)
-# define r2net_set_nst_sock_time(a)
-# define r2net_set_nst_send_time(a)
-# define r2net_set_nst_status_time(a)
-# define r2net_set_nst_sock_container(a, b)
-# define r2net_set_nst_msg_id(a, b)
-# define r2net_set_sock_timer(a)
-# define r2net_set_data_ready_time(a)
-# define r2net_set_advance_start_time(a)
-# define r2net_set_advance_stop_time(a)
-# define r2net_set_func_start_time(a)
-# define r2net_set_func_stop_time(a)
-#endif /* CONFIG_DEBUG_FS */
-
-#ifdef CONFIG_RAMSTER_FS_STATS
-static ktime_t r2net_get_func_run_time(struct r2net_sock_container *sc)
-{
- return ktime_sub(sc->sc_tv_func_stop, sc->sc_tv_func_start);
-}
-
-static void r2net_update_send_stats(struct r2net_send_tracking *nst,
- struct r2net_sock_container *sc)
-{
- sc->sc_tv_status_total = ktime_add(sc->sc_tv_status_total,
- ktime_sub(ktime_get(),
- nst->st_status_time));
- sc->sc_tv_send_total = ktime_add(sc->sc_tv_send_total,
- ktime_sub(nst->st_status_time,
- nst->st_send_time));
- sc->sc_tv_acquiry_total = ktime_add(sc->sc_tv_acquiry_total,
- ktime_sub(nst->st_send_time,
- nst->st_sock_time));
- sc->sc_send_count++;
-}
-
-static void r2net_update_recv_stats(struct r2net_sock_container *sc)
-{
- sc->sc_tv_process_total = ktime_add(sc->sc_tv_process_total,
- r2net_get_func_run_time(sc));
- sc->sc_recv_count++;
-}
-
-#else
-
-# define r2net_update_send_stats(a, b)
-
-# define r2net_update_recv_stats(sc)
-
-#endif /* CONFIG_RAMSTER_FS_STATS */
-
-static inline int r2net_reconnect_delay(void)
-{
- return r2nm_single_cluster->cl_reconnect_delay_ms;
-}
-
-static inline int r2net_keepalive_delay(void)
-{
- return r2nm_single_cluster->cl_keepalive_delay_ms;
-}
-
-static inline int r2net_idle_timeout(void)
-{
- return r2nm_single_cluster->cl_idle_timeout_ms;
-}
-
-static inline int r2net_sys_err_to_errno(enum r2net_system_error err)
-{
- int trans;
- BUG_ON(err >= R2NET_ERR_MAX);
- trans = r2net_sys_err_translations[err];
-
- /* Just in case we mess up the translation table above */
- BUG_ON(err != R2NET_ERR_NONE && trans == 0);
- return trans;
-}
-
-struct r2net_node *r2net_nn_from_num(u8 node_num)
-{
- BUG_ON(node_num >= ARRAY_SIZE(r2net_nodes));
- return &r2net_nodes[node_num];
-}
-
-static u8 r2net_num_from_nn(struct r2net_node *nn)
-{
- BUG_ON(nn == NULL);
- return nn - r2net_nodes;
-}
-
-/* ------------------------------------------------------------ */
-
-static int r2net_prep_nsw(struct r2net_node *nn, struct r2net_status_wait *nsw)
-{
- int ret;
-
- spin_lock(&nn->nn_lock);
- ret = idr_alloc(&nn->nn_status_idr, nsw, 0, 0, GFP_ATOMIC);
- if (ret >= 0) {
- nsw->ns_id = ret;
- list_add_tail(&nsw->ns_node_item, &nn->nn_status_list);
- }
- spin_unlock(&nn->nn_lock);
-
- if (ret >= 0) {
- init_waitqueue_head(&nsw->ns_wq);
- nsw->ns_sys_status = R2NET_ERR_NONE;
- nsw->ns_status = 0;
- return 0;
- }
- return ret;
-}
-
-static void r2net_complete_nsw_locked(struct r2net_node *nn,
- struct r2net_status_wait *nsw,
- enum r2net_system_error sys_status,
- s32 status)
-{
- assert_spin_locked(&nn->nn_lock);
-
- if (!list_empty(&nsw->ns_node_item)) {
- list_del_init(&nsw->ns_node_item);
- nsw->ns_sys_status = sys_status;
- nsw->ns_status = status;
- idr_remove(&nn->nn_status_idr, nsw->ns_id);
- wake_up(&nsw->ns_wq);
- }
-}
-
-static void r2net_complete_nsw(struct r2net_node *nn,
- struct r2net_status_wait *nsw,
- u64 id, enum r2net_system_error sys_status,
- s32 status)
-{
- spin_lock(&nn->nn_lock);
- if (nsw == NULL) {
- if (id > INT_MAX)
- goto out;
-
- nsw = idr_find(&nn->nn_status_idr, id);
- if (nsw == NULL)
- goto out;
- }
-
- r2net_complete_nsw_locked(nn, nsw, sys_status, status);
-
-out:
- spin_unlock(&nn->nn_lock);
- return;
-}
-
-static void r2net_complete_nodes_nsw(struct r2net_node *nn)
-{
- struct r2net_status_wait *nsw, *tmp;
- unsigned int num_kills = 0;
-
- assert_spin_locked(&nn->nn_lock);
-
- list_for_each_entry_safe(nsw, tmp, &nn->nn_status_list, ns_node_item) {
- r2net_complete_nsw_locked(nn, nsw, R2NET_ERR_DIED, 0);
- num_kills++;
- }
-
- mlog(0, "completed %d messages for node %u\n", num_kills,
- r2net_num_from_nn(nn));
-}
-
-static int r2net_nsw_completed(struct r2net_node *nn,
- struct r2net_status_wait *nsw)
-{
- int completed;
- spin_lock(&nn->nn_lock);
- completed = list_empty(&nsw->ns_node_item);
- spin_unlock(&nn->nn_lock);
- return completed;
-}
-
-/* ------------------------------------------------------------ */
-
-static void sc_kref_release(struct kref *kref)
-{
- struct r2net_sock_container *sc = container_of(kref,
- struct r2net_sock_container, sc_kref);
- BUG_ON(timer_pending(&sc->sc_idle_timeout));
-
- sclog(sc, "releasing\n");
-
- if (sc->sc_sock) {
- sock_release(sc->sc_sock);
- sc->sc_sock = NULL;
- }
-
- r2nm_undepend_item(&sc->sc_node->nd_item);
- r2nm_node_put(sc->sc_node);
- sc->sc_node = NULL;
-
- r2net_debug_del_sc(sc);
- kfree(sc);
-}
-
-static void sc_put(struct r2net_sock_container *sc)
-{
- sclog(sc, "put\n");
- kref_put(&sc->sc_kref, sc_kref_release);
-}
-static void sc_get(struct r2net_sock_container *sc)
-{
- sclog(sc, "get\n");
- kref_get(&sc->sc_kref);
-}
-static struct r2net_sock_container *sc_alloc(struct r2nm_node *node)
-{
- struct r2net_sock_container *sc, *ret = NULL;
- struct page *page = NULL;
- int status = 0;
-
- page = alloc_page(GFP_NOFS);
- sc = kzalloc(sizeof(*sc), GFP_NOFS);
- if (sc == NULL || page == NULL)
- goto out;
-
- kref_init(&sc->sc_kref);
- r2nm_node_get(node);
- sc->sc_node = node;
-
- /* pin the node item of the remote node */
- status = r2nm_depend_item(&node->nd_item);
- if (status) {
- mlog_errno(status);
- r2nm_node_put(node);
- goto out;
- }
- INIT_WORK(&sc->sc_connect_work, r2net_sc_connect_completed);
- INIT_WORK(&sc->sc_rx_work, r2net_rx_until_empty);
- INIT_WORK(&sc->sc_shutdown_work, r2net_shutdown_sc);
- INIT_DELAYED_WORK(&sc->sc_keepalive_work, r2net_sc_send_keep_req);
-
- init_timer(&sc->sc_idle_timeout);
- sc->sc_idle_timeout.function = r2net_idle_timer;
- sc->sc_idle_timeout.data = (unsigned long)sc;
-
- sclog(sc, "alloced\n");
-
- ret = sc;
- sc->sc_page = page;
- r2net_debug_add_sc(sc);
- sc = NULL;
- page = NULL;
-
-out:
- if (page)
- __free_page(page);
- kfree(sc);
-
- return ret;
-}
-
-/* ------------------------------------------------------------ */
-
-static void r2net_sc_queue_work(struct r2net_sock_container *sc,
- struct work_struct *work)
-{
- sc_get(sc);
- if (!queue_work(r2net_wq, work))
- sc_put(sc);
-}
-static void r2net_sc_queue_delayed_work(struct r2net_sock_container *sc,
- struct delayed_work *work,
- int delay)
-{
- sc_get(sc);
- if (!queue_delayed_work(r2net_wq, work, delay))
- sc_put(sc);
-}
-static void r2net_sc_cancel_delayed_work(struct r2net_sock_container *sc,
- struct delayed_work *work)
-{
- if (cancel_delayed_work(work))
- sc_put(sc);
-}
-
-static atomic_t r2net_connected_peers = ATOMIC_INIT(0);
-
-int r2net_num_connected_peers(void)
-{
- return atomic_read(&r2net_connected_peers);
-}
-
-static void r2net_set_nn_state(struct r2net_node *nn,
- struct r2net_sock_container *sc,
- unsigned valid, int err)
-{
- int was_valid = nn->nn_sc_valid;
- int was_err = nn->nn_persistent_error;
- struct r2net_sock_container *old_sc = nn->nn_sc;
-
- assert_spin_locked(&nn->nn_lock);
-
- if (old_sc && !sc)
- atomic_dec(&r2net_connected_peers);
- else if (!old_sc && sc)
- atomic_inc(&r2net_connected_peers);
-
- /* the node num comparison and single connect/accept path should stop
- * an non-null sc from being overwritten with another */
- BUG_ON(sc && nn->nn_sc && nn->nn_sc != sc);
- mlog_bug_on_msg(err && valid, "err %d valid %u\n", err, valid);
- mlog_bug_on_msg(valid && !sc, "valid %u sc %p\n", valid, sc);
-
- if (was_valid && !valid && err == 0)
- err = -ENOTCONN;
-
- mlog(ML_CONN, "node %u sc: %p -> %p, valid %u -> %u, err %d -> %d\n",
- r2net_num_from_nn(nn), nn->nn_sc, sc, nn->nn_sc_valid, valid,
- nn->nn_persistent_error, err);
-
- nn->nn_sc = sc;
- nn->nn_sc_valid = valid ? 1 : 0;
- nn->nn_persistent_error = err;
-
- /* mirrors r2net_tx_can_proceed() */
- if (nn->nn_persistent_error || nn->nn_sc_valid)
- wake_up(&nn->nn_sc_wq);
-
- if (!was_err && nn->nn_persistent_error) {
- queue_delayed_work(r2net_wq, &nn->nn_still_up,
- msecs_to_jiffies(R2NET_QUORUM_DELAY_MS));
- }
-
- if (was_valid && !valid) {
- pr_notice("ramster: No longer connected to " SC_NODEF_FMT "\n",
- old_sc->sc_node->nd_name, old_sc->sc_node->nd_num,
- &old_sc->sc_node->nd_ipv4_address,
- ntohs(old_sc->sc_node->nd_ipv4_port));
- r2net_complete_nodes_nsw(nn);
- }
-
- if (!was_valid && valid) {
- cancel_delayed_work(&nn->nn_connect_expired);
- pr_notice("ramster: %s " SC_NODEF_FMT "\n",
- r2nm_this_node() > sc->sc_node->nd_num ?
- "Connected to" : "Accepted connection from",
- sc->sc_node->nd_name, sc->sc_node->nd_num,
- &sc->sc_node->nd_ipv4_address,
- ntohs(sc->sc_node->nd_ipv4_port));
- }
-
- /* trigger the connecting worker func as long as we're not valid,
- * it will back off if it shouldn't connect. This can be called
- * from node config teardown and so needs to be careful about
- * the work queue actually being up. */
- if (!valid && r2net_wq) {
- unsigned long delay;
- /* delay if we're within a RECONNECT_DELAY of the
- * last attempt */
- delay = (nn->nn_last_connect_attempt +
- msecs_to_jiffies(r2net_reconnect_delay()))
- - jiffies;
- if (delay > msecs_to_jiffies(r2net_reconnect_delay()))
- delay = 0;
- mlog(ML_CONN, "queueing conn attempt in %lu jiffies\n", delay);
- queue_delayed_work(r2net_wq, &nn->nn_connect_work, delay);
-
- /*
- * Delay the expired work after idle timeout.
- *
- * We might have lots of failed connection attempts that run
- * through here but we only cancel the connect_expired work when
- * a connection attempt succeeds. So only the first enqueue of
- * the connect_expired work will do anything. The rest will see
- * that it's already queued and do nothing.
- */
- delay += msecs_to_jiffies(r2net_idle_timeout());
- queue_delayed_work(r2net_wq, &nn->nn_connect_expired, delay);
- }
-
- /* keep track of the nn's sc ref for the caller */
- if ((old_sc == NULL) && sc)
- sc_get(sc);
- if (old_sc && (old_sc != sc)) {
- r2net_sc_queue_work(old_sc, &old_sc->sc_shutdown_work);
- sc_put(old_sc);
- }
-}
-
-/* see r2net_register_callbacks() */
-static void r2net_data_ready(struct sock *sk, int bytes)
-{
- void (*ready)(struct sock *sk, int bytes);
-
- read_lock(&sk->sk_callback_lock);
- if (sk->sk_user_data) {
- struct r2net_sock_container *sc = sk->sk_user_data;
- sclog(sc, "data_ready hit\n");
- r2net_set_data_ready_time(sc);
- r2net_sc_queue_work(sc, &sc->sc_rx_work);
- ready = sc->sc_data_ready;
- } else {
- ready = sk->sk_data_ready;
- }
- read_unlock(&sk->sk_callback_lock);
-
- ready(sk, bytes);
-}
-
-/* see r2net_register_callbacks() */
-static void r2net_state_change(struct sock *sk)
-{
- void (*state_change)(struct sock *sk);
- struct r2net_sock_container *sc;
-
- read_lock(&sk->sk_callback_lock);
- sc = sk->sk_user_data;
- if (sc == NULL) {
- state_change = sk->sk_state_change;
- goto out;
- }
-
- sclog(sc, "state_change to %d\n", sk->sk_state);
-
- state_change = sc->sc_state_change;
-
- switch (sk->sk_state) {
-
- /* ignore connecting sockets as they make progress */
- case TCP_SYN_SENT:
- case TCP_SYN_RECV:
- break;
- case TCP_ESTABLISHED:
- r2net_sc_queue_work(sc, &sc->sc_connect_work);
- break;
- default:
- pr_info("ramster: Connection to "
- SC_NODEF_FMT " shutdown, state %d\n",
- sc->sc_node->nd_name, sc->sc_node->nd_num,
- &sc->sc_node->nd_ipv4_address,
- ntohs(sc->sc_node->nd_ipv4_port), sk->sk_state);
- r2net_sc_queue_work(sc, &sc->sc_shutdown_work);
- break;
-
- }
-out:
- read_unlock(&sk->sk_callback_lock);
- state_change(sk);
-}
-
-/*
- * we register callbacks so we can queue work on events before calling
- * the original callbacks. our callbacks are careful to test user_data
- * to discover when they've reaced with r2net_unregister_callbacks().
- */
-static void r2net_register_callbacks(struct sock *sk,
- struct r2net_sock_container *sc)
-{
- write_lock_bh(&sk->sk_callback_lock);
-
- /* accepted sockets inherit the old listen socket data ready */
- if (sk->sk_data_ready == r2net_listen_data_ready) {
- sk->sk_data_ready = sk->sk_user_data;
- sk->sk_user_data = NULL;
- }
-
- BUG_ON(sk->sk_user_data != NULL);
- sk->sk_user_data = sc;
- sc_get(sc);
-
- sc->sc_data_ready = sk->sk_data_ready;
- sc->sc_state_change = sk->sk_state_change;
- sk->sk_data_ready = r2net_data_ready;
- sk->sk_state_change = r2net_state_change;
-
- mutex_init(&sc->sc_send_lock);
-
- write_unlock_bh(&sk->sk_callback_lock);
-}
-
-static int r2net_unregister_callbacks(struct sock *sk,
- struct r2net_sock_container *sc)
-{
- int ret = 0;
-
- write_lock_bh(&sk->sk_callback_lock);
- if (sk->sk_user_data == sc) {
- ret = 1;
- sk->sk_user_data = NULL;
- sk->sk_data_ready = sc->sc_data_ready;
- sk->sk_state_change = sc->sc_state_change;
- }
- write_unlock_bh(&sk->sk_callback_lock);
-
- return ret;
-}
-
-/*
- * this is a little helper that is called by callers who have seen a problem
- * with an sc and want to detach it from the nn if someone already hasn't beat
- * them to it. if an error is given then the shutdown will be persistent
- * and pending transmits will be canceled.
- */
-static void r2net_ensure_shutdown(struct r2net_node *nn,
- struct r2net_sock_container *sc,
- int err)
-{
- spin_lock(&nn->nn_lock);
- if (nn->nn_sc == sc)
- r2net_set_nn_state(nn, NULL, 0, err);
- spin_unlock(&nn->nn_lock);
-}
-
-/*
- * This work queue function performs the blocking parts of socket shutdown. A
- * few paths lead here. set_nn_state will trigger this callback if it sees an
- * sc detached from the nn. state_change will also trigger this callback
- * directly when it sees errors. In that case we need to call set_nn_state
- * ourselves as state_change couldn't get the nn_lock and call set_nn_state
- * itself.
- */
-static void r2net_shutdown_sc(struct work_struct *work)
-{
- struct r2net_sock_container *sc =
- container_of(work, struct r2net_sock_container,
- sc_shutdown_work);
- struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
-
- sclog(sc, "shutting down\n");
-
- /* drop the callbacks ref and call shutdown only once */
- if (r2net_unregister_callbacks(sc->sc_sock->sk, sc)) {
- /* we shouldn't flush as we're in the thread, the
- * races with pending sc work structs are harmless */
- del_timer_sync(&sc->sc_idle_timeout);
- r2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work);
- sc_put(sc);
- kernel_sock_shutdown(sc->sc_sock, SHUT_RDWR);
- }
-
- /* not fatal so failed connects before the other guy has our
- * heartbeat can be retried */
- r2net_ensure_shutdown(nn, sc, 0);
- sc_put(sc);
-}
-
-/* ------------------------------------------------------------ */
-
-static int r2net_handler_cmp(struct r2net_msg_handler *nmh, u32 msg_type,
- u32 key)
-{
- int ret = memcmp(&nmh->nh_key, &key, sizeof(key));
-
- if (ret == 0)
- ret = memcmp(&nmh->nh_msg_type, &msg_type, sizeof(msg_type));
-
- return ret;
-}
-
-static struct r2net_msg_handler *
-r2net_handler_tree_lookup(u32 msg_type, u32 key, struct rb_node ***ret_p,
- struct rb_node **ret_parent)
-{
- struct rb_node **p = &r2net_handler_tree.rb_node;
- struct rb_node *parent = NULL;
- struct r2net_msg_handler *nmh, *ret = NULL;
- int cmp;
-
- while (*p) {
- parent = *p;
- nmh = rb_entry(parent, struct r2net_msg_handler, nh_node);
- cmp = r2net_handler_cmp(nmh, msg_type, key);
-
- if (cmp < 0)
- p = &(*p)->rb_left;
- else if (cmp > 0)
- p = &(*p)->rb_right;
- else {
- ret = nmh;
- break;
- }
- }
-
- if (ret_p != NULL)
- *ret_p = p;
- if (ret_parent != NULL)
- *ret_parent = parent;
-
- return ret;
-}
-
-static void r2net_handler_kref_release(struct kref *kref)
-{
- struct r2net_msg_handler *nmh;
- nmh = container_of(kref, struct r2net_msg_handler, nh_kref);
-
- kfree(nmh);
-}
-
-static void r2net_handler_put(struct r2net_msg_handler *nmh)
-{
- kref_put(&nmh->nh_kref, r2net_handler_kref_release);
-}
-
-/* max_len is protection for the handler func. incoming messages won't
- * be given to the handler if their payload is longer than the max. */
-int r2net_register_handler(u32 msg_type, u32 key, u32 max_len,
- r2net_msg_handler_func *func, void *data,
- r2net_post_msg_handler_func *post_func,
- struct list_head *unreg_list)
-{
- struct r2net_msg_handler *nmh = NULL;
- struct rb_node **p, *parent;
- int ret = 0;
-
- if (max_len > R2NET_MAX_PAYLOAD_BYTES) {
- mlog(0, "max_len for message handler out of range: %u\n",
- max_len);
- ret = -EINVAL;
- goto out;
- }
-
- if (!msg_type) {
- mlog(0, "no message type provided: %u, %p\n", msg_type, func);
- ret = -EINVAL;
- goto out;
-
- }
- if (!func) {
- mlog(0, "no message handler provided: %u, %p\n",
- msg_type, func);
- ret = -EINVAL;
- goto out;
- }
-
- nmh = kzalloc(sizeof(struct r2net_msg_handler), GFP_NOFS);
- if (nmh == NULL) {
- ret = -ENOMEM;
- goto out;
- }
-
- nmh->nh_func = func;
- nmh->nh_func_data = data;
- nmh->nh_post_func = post_func;
- nmh->nh_msg_type = msg_type;
- nmh->nh_max_len = max_len;
- nmh->nh_key = key;
- /* the tree and list get this ref.. they're both removed in
- * unregister when this ref is dropped */
- kref_init(&nmh->nh_kref);
- INIT_LIST_HEAD(&nmh->nh_unregister_item);
-
- write_lock(&r2net_handler_lock);
- if (r2net_handler_tree_lookup(msg_type, key, &p, &parent))
- ret = -EEXIST;
- else {
- rb_link_node(&nmh->nh_node, parent, p);
- rb_insert_color(&nmh->nh_node, &r2net_handler_tree);
- list_add_tail(&nmh->nh_unregister_item, unreg_list);
-
- mlog(ML_TCP, "registered handler func %p type %u key %08x\n",
- func, msg_type, key);
- /* we've had some trouble with handlers seemingly vanishing. */
- mlog_bug_on_msg(r2net_handler_tree_lookup(msg_type, key, &p,
- &parent) == NULL,
- "couldn't find handler we *just* registered "
- "for type %u key %08x\n", msg_type, key);
- }
- write_unlock(&r2net_handler_lock);
- if (ret)
- goto out;
-
-out:
- if (ret)
- kfree(nmh);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(r2net_register_handler);
-
-void r2net_unregister_handler_list(struct list_head *list)
-{
- struct r2net_msg_handler *nmh, *n;
-
- write_lock(&r2net_handler_lock);
- list_for_each_entry_safe(nmh, n, list, nh_unregister_item) {
- mlog(ML_TCP, "unregistering handler func %p type %u key %08x\n",
- nmh->nh_func, nmh->nh_msg_type, nmh->nh_key);
- rb_erase(&nmh->nh_node, &r2net_handler_tree);
- list_del_init(&nmh->nh_unregister_item);
- kref_put(&nmh->nh_kref, r2net_handler_kref_release);
- }
- write_unlock(&r2net_handler_lock);
-}
-EXPORT_SYMBOL_GPL(r2net_unregister_handler_list);
-
-static struct r2net_msg_handler *r2net_handler_get(u32 msg_type, u32 key)
-{
- struct r2net_msg_handler *nmh;
-
- read_lock(&r2net_handler_lock);
- nmh = r2net_handler_tree_lookup(msg_type, key, NULL, NULL);
- if (nmh)
- kref_get(&nmh->nh_kref);
- read_unlock(&r2net_handler_lock);
-
- return nmh;
-}
-
-/* ------------------------------------------------------------ */
-
-static int r2net_recv_tcp_msg(struct socket *sock, void *data, size_t len)
-{
- int ret;
- mm_segment_t oldfs;
- struct kvec vec = {
- .iov_len = len,
- .iov_base = data,
- };
- struct msghdr msg = {
- .msg_iovlen = 1,
- .msg_iov = (struct iovec *)&vec,
- .msg_flags = MSG_DONTWAIT,
- };
-
- oldfs = get_fs();
- set_fs(get_ds());
- ret = sock_recvmsg(sock, &msg, len, msg.msg_flags);
- set_fs(oldfs);
-
- return ret;
-}
-
-static int r2net_send_tcp_msg(struct socket *sock, struct kvec *vec,
- size_t veclen, size_t total)
-{
- int ret;
- mm_segment_t oldfs;
- struct msghdr msg = {
- .msg_iov = (struct iovec *)vec,
- .msg_iovlen = veclen,
- };
-
- if (sock == NULL) {
- ret = -EINVAL;
- goto out;
- }
-
- oldfs = get_fs();
- set_fs(get_ds());
- ret = sock_sendmsg(sock, &msg, total);
- set_fs(oldfs);
- if (ret != total) {
- mlog(ML_ERROR, "sendmsg returned %d instead of %zu\n", ret,
- total);
- if (ret >= 0)
- ret = -EPIPE; /* should be smarter, I bet */
- goto out;
- }
-
- ret = 0;
-out:
- if (ret < 0)
- mlog(0, "returning error: %d\n", ret);
- return ret;
-}
-
-static void r2net_sendpage(struct r2net_sock_container *sc,
- void *kmalloced_virt,
- size_t size)
-{
- struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
- ssize_t ret;
-
- while (1) {
- mutex_lock(&sc->sc_send_lock);
- ret = sc->sc_sock->ops->sendpage(sc->sc_sock,
- virt_to_page(kmalloced_virt),
- (long)kmalloced_virt & ~PAGE_MASK,
- size, MSG_DONTWAIT);
- mutex_unlock(&sc->sc_send_lock);
- if (ret == size)
- break;
- if (ret == (ssize_t)-EAGAIN) {
- mlog(0, "sendpage of size %zu to " SC_NODEF_FMT
- " returned EAGAIN\n", size, sc->sc_node->nd_name,
- sc->sc_node->nd_num,
- &sc->sc_node->nd_ipv4_address,
- ntohs(sc->sc_node->nd_ipv4_port));
- cond_resched();
- continue;
- }
- mlog(ML_ERROR, "sendpage of size %zu to " SC_NODEF_FMT
- " failed with %zd\n", size, sc->sc_node->nd_name,
- sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
- ntohs(sc->sc_node->nd_ipv4_port), ret);
- r2net_ensure_shutdown(nn, sc, 0);
- break;
- }
-}
-
-static void r2net_init_msg(struct r2net_msg *msg, u16 data_len,
- u16 msg_type, u32 key)
-{
- memset(msg, 0, sizeof(struct r2net_msg));
- msg->magic = cpu_to_be16(R2NET_MSG_MAGIC);
- msg->data_len = cpu_to_be16(data_len);
- msg->msg_type = cpu_to_be16(msg_type);
- msg->sys_status = cpu_to_be32(R2NET_ERR_NONE);
- msg->status = 0;
- msg->key = cpu_to_be32(key);
-}
-
-static int r2net_tx_can_proceed(struct r2net_node *nn,
- struct r2net_sock_container **sc_ret,
- int *error)
-{
- int ret = 0;
-
- spin_lock(&nn->nn_lock);
- if (nn->nn_persistent_error) {
- ret = 1;
- *sc_ret = NULL;
- *error = nn->nn_persistent_error;
- } else if (nn->nn_sc_valid) {
- kref_get(&nn->nn_sc->sc_kref);
-
- ret = 1;
- *sc_ret = nn->nn_sc;
- *error = 0;
- }
- spin_unlock(&nn->nn_lock);
-
- return ret;
-}
-
-/* Get a map of all nodes to which this node is currently connected to */
-void r2net_fill_node_map(unsigned long *map, unsigned bytes)
-{
- struct r2net_sock_container *sc;
- int node, ret;
-
- BUG_ON(bytes < (BITS_TO_LONGS(R2NM_MAX_NODES) * sizeof(unsigned long)));
-
- memset(map, 0, bytes);
- for (node = 0; node < R2NM_MAX_NODES; ++node) {
- r2net_tx_can_proceed(r2net_nn_from_num(node), &sc, &ret);
- if (!ret) {
- set_bit(node, map);
- sc_put(sc);
- }
- }
-}
-EXPORT_SYMBOL_GPL(r2net_fill_node_map);
-
-int r2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
- size_t caller_veclen, u8 target_node, int *status)
-{
- int ret = 0;
- struct r2net_msg *msg = NULL;
- size_t veclen, caller_bytes = 0;
- struct kvec *vec = NULL;
- struct r2net_sock_container *sc = NULL;
- struct r2net_node *nn = r2net_nn_from_num(target_node);
- struct r2net_status_wait nsw = {
- .ns_node_item = LIST_HEAD_INIT(nsw.ns_node_item),
- };
- struct r2net_send_tracking nst;
-
- /* this may be a general bug fix */
- init_waitqueue_head(&nsw.ns_wq);
-
- r2net_init_nst(&nst, msg_type, key, current, target_node);
-
- if (r2net_wq == NULL) {
- mlog(0, "attempt to tx without r2netd running\n");
- ret = -ESRCH;
- goto out;
- }
-
- if (caller_veclen == 0) {
- mlog(0, "bad kvec array length\n");
- ret = -EINVAL;
- goto out;
- }
-
- caller_bytes = iov_length((struct iovec *)caller_vec, caller_veclen);
- if (caller_bytes > R2NET_MAX_PAYLOAD_BYTES) {
- mlog(0, "total payload len %zu too large\n", caller_bytes);
- ret = -EINVAL;
- goto out;
- }
-
- if (target_node == r2nm_this_node()) {
- ret = -ELOOP;
- goto out;
- }
-
- r2net_debug_add_nst(&nst);
-
- r2net_set_nst_sock_time(&nst);
-
- wait_event(nn->nn_sc_wq, r2net_tx_can_proceed(nn, &sc, &ret));
- if (ret)
- goto out;
-
- r2net_set_nst_sock_container(&nst, sc);
-
- veclen = caller_veclen + 1;
- vec = kmalloc(sizeof(struct kvec) * veclen, GFP_ATOMIC);
- if (vec == NULL) {
- mlog(0, "failed to %zu element kvec!\n", veclen);
- ret = -ENOMEM;
- goto out;
- }
-
- msg = kmalloc(sizeof(struct r2net_msg), GFP_ATOMIC);
- if (!msg) {
- mlog(0, "failed to allocate a r2net_msg!\n");
- ret = -ENOMEM;
- goto out;
- }
-
- r2net_init_msg(msg, caller_bytes, msg_type, key);
-
- vec[0].iov_len = sizeof(struct r2net_msg);
- vec[0].iov_base = msg;
- memcpy(&vec[1], caller_vec, caller_veclen * sizeof(struct kvec));
-
- ret = r2net_prep_nsw(nn, &nsw);
- if (ret)
- goto out;
-
- msg->msg_num = cpu_to_be32(nsw.ns_id);
- r2net_set_nst_msg_id(&nst, nsw.ns_id);
-
- r2net_set_nst_send_time(&nst);
-
- /* finally, convert the message header to network byte-order
- * and send */
- mutex_lock(&sc->sc_send_lock);
- ret = r2net_send_tcp_msg(sc->sc_sock, vec, veclen,
- sizeof(struct r2net_msg) + caller_bytes);
- mutex_unlock(&sc->sc_send_lock);
- msglog(msg, "sending returned %d\n", ret);
- if (ret < 0) {
- mlog(0, "error returned from r2net_send_tcp_msg=%d\n", ret);
- goto out;
- }
-
- /* wait on other node's handler */
- r2net_set_nst_status_time(&nst);
- wait_event(nsw.ns_wq, r2net_nsw_completed(nn, &nsw) ||
- nn->nn_persistent_error || !nn->nn_sc_valid);
-
- r2net_update_send_stats(&nst, sc);
-
- /* Note that we avoid overwriting the callers status return
- * variable if a system error was reported on the other
- * side. Callers beware. */
- ret = r2net_sys_err_to_errno(nsw.ns_sys_status);
- if (status && !ret)
- *status = nsw.ns_status;
-
- mlog(0, "woken, returning system status %d, user status %d\n",
- ret, nsw.ns_status);
-out:
- r2net_debug_del_nst(&nst); /* must be before dropping sc and node */
- if (sc)
- sc_put(sc);
- kfree(vec);
- kfree(msg);
- r2net_complete_nsw(nn, &nsw, 0, 0, 0);
- return ret;
-}
-EXPORT_SYMBOL_GPL(r2net_send_message_vec);
-
-int r2net_send_message(u32 msg_type, u32 key, void *data, u32 len,
- u8 target_node, int *status)
-{
- struct kvec vec = {
- .iov_base = data,
- .iov_len = len,
- };
- return r2net_send_message_vec(msg_type, key, &vec, 1,
- target_node, status);
-}
-EXPORT_SYMBOL_GPL(r2net_send_message);
-
-static int r2net_send_status_magic(struct socket *sock, struct r2net_msg *hdr,
- enum r2net_system_error syserr, int err)
-{
- struct kvec vec = {
- .iov_base = hdr,
- .iov_len = sizeof(struct r2net_msg),
- };
-
- BUG_ON(syserr >= R2NET_ERR_MAX);
-
- /* leave other fields intact from the incoming message, msg_num
- * in particular */
- hdr->sys_status = cpu_to_be32(syserr);
- hdr->status = cpu_to_be32(err);
- /* twiddle the magic */
- hdr->magic = cpu_to_be16(R2NET_MSG_STATUS_MAGIC);
- hdr->data_len = 0;
-
- msglog(hdr, "about to send status magic %d\n", err);
- /* hdr has been in host byteorder this whole time */
- return r2net_send_tcp_msg(sock, &vec, 1, sizeof(struct r2net_msg));
-}
-
-/*
- * "data magic" is a long version of "status magic" where the message
- * payload actually contains data to be passed in reply to certain messages
- */
-static int r2net_send_data_magic(struct r2net_sock_container *sc,
- struct r2net_msg *hdr,
- void *data, size_t data_len,
- enum r2net_system_error syserr, int err)
-{
- struct kvec vec[2];
- int ret;
-
- vec[0].iov_base = hdr;
- vec[0].iov_len = sizeof(struct r2net_msg);
- vec[1].iov_base = data;
- vec[1].iov_len = data_len;
-
- BUG_ON(syserr >= R2NET_ERR_MAX);
-
- /* leave other fields intact from the incoming message, msg_num
- * in particular */
- hdr->sys_status = cpu_to_be32(syserr);
- hdr->status = cpu_to_be32(err);
- hdr->magic = cpu_to_be16(R2NET_MSG_DATA_MAGIC); /* twiddle magic */
- hdr->data_len = cpu_to_be16(data_len);
-
- msglog(hdr, "about to send data magic %d\n", err);
- /* hdr has been in host byteorder this whole time */
- ret = r2net_send_tcp_msg(sc->sc_sock, vec, 2,
- sizeof(struct r2net_msg) + data_len);
- return ret;
-}
-
-/*
- * called by a message handler to convert an otherwise normal reply
- * message into a "data magic" message
- */
-void r2net_force_data_magic(struct r2net_msg *hdr, u16 msgtype, u32 msgkey)
-{
- hdr->magic = cpu_to_be16(R2NET_MSG_DATA_MAGIC);
- hdr->msg_type = cpu_to_be16(msgtype);
- hdr->key = cpu_to_be32(msgkey);
-}
-
-/* this returns -errno if the header was unknown or too large, etc.
- * after this is called the buffer us reused for the next message */
-static int r2net_process_message(struct r2net_sock_container *sc,
- struct r2net_msg *hdr)
-{
- struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
- int ret = 0, handler_status;
- enum r2net_system_error syserr;
- struct r2net_msg_handler *nmh = NULL;
- void *ret_data = NULL;
- int data_magic = 0;
-
- msglog(hdr, "processing message\n");
-
- r2net_sc_postpone_idle(sc);
-
- switch (be16_to_cpu(hdr->magic)) {
-
- case R2NET_MSG_STATUS_MAGIC:
- /* special type for returning message status */
- r2net_complete_nsw(nn, NULL, be32_to_cpu(hdr->msg_num),
- be32_to_cpu(hdr->sys_status),
- be32_to_cpu(hdr->status));
- goto out;
- case R2NET_MSG_KEEP_REQ_MAGIC:
- r2net_sendpage(sc, r2net_keep_resp, sizeof(*r2net_keep_resp));
- goto out;
- case R2NET_MSG_KEEP_RESP_MAGIC:
- goto out;
- case R2NET_MSG_MAGIC:
- break;
- case R2NET_MSG_DATA_MAGIC:
- /*
- * unlike a normal status magic, a data magic DOES
- * (MUST) have a handler, so the control flow is
- * a little funky here as a result
- */
- data_magic = 1;
- break;
- default:
- msglog(hdr, "bad magic\n");
- ret = -EINVAL;
- goto out;
- break;
- }
-
- /* find a handler for it */
- handler_status = 0;
- nmh = r2net_handler_get(be16_to_cpu(hdr->msg_type),
- be32_to_cpu(hdr->key));
- if (!nmh) {
- mlog(ML_TCP, "couldn't find handler for type %u key %08x\n",
- be16_to_cpu(hdr->msg_type), be32_to_cpu(hdr->key));
- syserr = R2NET_ERR_NO_HNDLR;
- goto out_respond;
- }
-
- syserr = R2NET_ERR_NONE;
-
- if (be16_to_cpu(hdr->data_len) > nmh->nh_max_len)
- syserr = R2NET_ERR_OVERFLOW;
-
- if (syserr != R2NET_ERR_NONE) {
- pr_err("ramster_r2net, message length problem\n");
- goto out_respond;
- }
-
- r2net_set_func_start_time(sc);
- sc->sc_msg_key = be32_to_cpu(hdr->key);
- sc->sc_msg_type = be16_to_cpu(hdr->msg_type);
- handler_status = (nmh->nh_func)(hdr, sizeof(struct r2net_msg) +
- be16_to_cpu(hdr->data_len),
- nmh->nh_func_data, &ret_data);
- if (data_magic) {
- /*
- * handler handled data sent in reply to request
- * so complete the transaction
- */
- r2net_complete_nsw(nn, NULL, be32_to_cpu(hdr->msg_num),
- be32_to_cpu(hdr->sys_status), handler_status);
- goto out;
- }
- /*
- * handler changed magic to DATA_MAGIC to reply to request for data,
- * implies ret_data points to data to return and handler_status
- * is the number of bytes of data
- */
- if (be16_to_cpu(hdr->magic) == R2NET_MSG_DATA_MAGIC) {
- ret = r2net_send_data_magic(sc, hdr,
- ret_data, handler_status,
- syserr, 0);
- hdr = NULL;
- mlog(0, "sending data reply %d, syserr %d returned %d\n",
- handler_status, syserr, ret);
- r2net_set_func_stop_time(sc);
-
- r2net_update_recv_stats(sc);
- goto out;
- }
- r2net_set_func_stop_time(sc);
-
- r2net_update_recv_stats(sc);
-
-out_respond:
- /* this destroys the hdr, so don't use it after this */
- mutex_lock(&sc->sc_send_lock);
- ret = r2net_send_status_magic(sc->sc_sock, hdr, syserr,
- handler_status);
- mutex_unlock(&sc->sc_send_lock);
- hdr = NULL;
- mlog(0, "sending handler status %d, syserr %d returned %d\n",
- handler_status, syserr, ret);
-
- if (nmh) {
- BUG_ON(ret_data != NULL && nmh->nh_post_func == NULL);
- if (nmh->nh_post_func)
- (nmh->nh_post_func)(handler_status, nmh->nh_func_data,
- ret_data);
- }
-
-out:
- if (nmh)
- r2net_handler_put(nmh);
- return ret;
-}
-
-static int r2net_check_handshake(struct r2net_sock_container *sc)
-{
- struct r2net_handshake *hand = page_address(sc->sc_page);
- struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
-
- if (hand->protocol_version != cpu_to_be64(R2NET_PROTOCOL_VERSION)) {
- pr_notice("ramster: " SC_NODEF_FMT " Advertised net "
- "protocol version %llu but %llu is required. "
- "Disconnecting.\n", sc->sc_node->nd_name,
- sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
- ntohs(sc->sc_node->nd_ipv4_port),
- (unsigned long long)be64_to_cpu(hand->protocol_version),
- R2NET_PROTOCOL_VERSION);
-
- /* don't bother reconnecting if its the wrong version. */
- r2net_ensure_shutdown(nn, sc, -ENOTCONN);
- return -1;
- }
-
- /*
- * Ensure timeouts are consistent with other nodes, otherwise
- * we can end up with one node thinking that the other must be down,
- * but isn't. This can ultimately cause corruption.
- */
- if (be32_to_cpu(hand->r2net_idle_timeout_ms) !=
- r2net_idle_timeout()) {
- pr_notice("ramster: " SC_NODEF_FMT " uses a network "
- "idle timeout of %u ms, but we use %u ms locally. "
- "Disconnecting.\n", sc->sc_node->nd_name,
- sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
- ntohs(sc->sc_node->nd_ipv4_port),
- be32_to_cpu(hand->r2net_idle_timeout_ms),
- r2net_idle_timeout());
- r2net_ensure_shutdown(nn, sc, -ENOTCONN);
- return -1;
- }
-
- if (be32_to_cpu(hand->r2net_keepalive_delay_ms) !=
- r2net_keepalive_delay()) {
- pr_notice("ramster: " SC_NODEF_FMT " uses a keepalive "
- "delay of %u ms, but we use %u ms locally. "
- "Disconnecting.\n", sc->sc_node->nd_name,
- sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
- ntohs(sc->sc_node->nd_ipv4_port),
- be32_to_cpu(hand->r2net_keepalive_delay_ms),
- r2net_keepalive_delay());
- r2net_ensure_shutdown(nn, sc, -ENOTCONN);
- return -1;
- }
-
- if (be32_to_cpu(hand->r2hb_heartbeat_timeout_ms) !=
- R2HB_MAX_WRITE_TIMEOUT_MS) {
- pr_notice("ramster: " SC_NODEF_FMT " uses a heartbeat "
- "timeout of %u ms, but we use %u ms locally. "
- "Disconnecting.\n", sc->sc_node->nd_name,
- sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
- ntohs(sc->sc_node->nd_ipv4_port),
- be32_to_cpu(hand->r2hb_heartbeat_timeout_ms),
- R2HB_MAX_WRITE_TIMEOUT_MS);
- r2net_ensure_shutdown(nn, sc, -ENOTCONN);
- return -1;
- }
-
- sc->sc_handshake_ok = 1;
-
- spin_lock(&nn->nn_lock);
- /* set valid and queue the idle timers only if it hasn't been
- * shut down already */
- if (nn->nn_sc == sc) {
- r2net_sc_reset_idle_timer(sc);
- atomic_set(&nn->nn_timeout, 0);
- r2net_set_nn_state(nn, sc, 1, 0);
- }
- spin_unlock(&nn->nn_lock);
-
- /* shift everything up as though it wasn't there */
- sc->sc_page_off -= sizeof(struct r2net_handshake);
- if (sc->sc_page_off)
- memmove(hand, hand + 1, sc->sc_page_off);
-
- return 0;
-}
-
-/* this demuxes the queued rx bytes into header or payload bits and calls
- * handlers as each full message is read off the socket. it returns -error,
- * == 0 eof, or > 0 for progress made.*/
-static int r2net_advance_rx(struct r2net_sock_container *sc)
-{
- struct r2net_msg *hdr;
- int ret = 0;
- void *data;
- size_t datalen;
-
- sclog(sc, "receiving\n");
- r2net_set_advance_start_time(sc);
-
- if (unlikely(sc->sc_handshake_ok == 0)) {
- if (sc->sc_page_off < sizeof(struct r2net_handshake)) {
- data = page_address(sc->sc_page) + sc->sc_page_off;
- datalen = sizeof(struct r2net_handshake) -
- sc->sc_page_off;
- ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
- if (ret > 0)
- sc->sc_page_off += ret;
- }
-
- if (sc->sc_page_off == sizeof(struct r2net_handshake)) {
- r2net_check_handshake(sc);
- if (unlikely(sc->sc_handshake_ok == 0))
- ret = -EPROTO;
- }
- goto out;
- }
-
- /* do we need more header? */
- if (sc->sc_page_off < sizeof(struct r2net_msg)) {
- data = page_address(sc->sc_page) + sc->sc_page_off;
- datalen = sizeof(struct r2net_msg) - sc->sc_page_off;
- ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
- if (ret > 0) {
- sc->sc_page_off += ret;
- /* only swab incoming here.. we can
- * only get here once as we cross from
- * being under to over */
- if (sc->sc_page_off == sizeof(struct r2net_msg)) {
- hdr = page_address(sc->sc_page);
- if (be16_to_cpu(hdr->data_len) >
- R2NET_MAX_PAYLOAD_BYTES)
- ret = -EOVERFLOW;
- WARN_ON_ONCE(ret == -EOVERFLOW);
- }
- }
- if (ret <= 0)
- goto out;
- }
-
- if (sc->sc_page_off < sizeof(struct r2net_msg)) {
- /* oof, still don't have a header */
- goto out;
- }
-
- /* this was swabbed above when we first read it */
- hdr = page_address(sc->sc_page);
-
- msglog(hdr, "at page_off %zu\n", sc->sc_page_off);
-
- /* do we need more payload? */
- if (sc->sc_page_off - sizeof(struct r2net_msg) <
- be16_to_cpu(hdr->data_len)) {
- /* need more payload */
- data = page_address(sc->sc_page) + sc->sc_page_off;
- datalen = (sizeof(struct r2net_msg) +
- be16_to_cpu(hdr->data_len)) -
- sc->sc_page_off;
- ret = r2net_recv_tcp_msg(sc->sc_sock, data, datalen);
- if (ret > 0)
- sc->sc_page_off += ret;
- if (ret <= 0)
- goto out;
- }
-
- if (sc->sc_page_off - sizeof(struct r2net_msg) ==
- be16_to_cpu(hdr->data_len)) {
- /* we can only get here once, the first time we read
- * the payload.. so set ret to progress if the handler
- * works out. after calling this the message is toast */
- ret = r2net_process_message(sc, hdr);
- if (ret == 0)
- ret = 1;
- sc->sc_page_off = 0;
- }
-
-out:
- sclog(sc, "ret = %d\n", ret);
- r2net_set_advance_stop_time(sc);
- return ret;
-}
-
-/* this work func is triggerd by data ready. it reads until it can read no
- * more. it interprets 0, eof, as fatal. if data_ready hits while we're doing
- * our work the work struct will be marked and we'll be called again. */
-static void r2net_rx_until_empty(struct work_struct *work)
-{
- struct r2net_sock_container *sc =
- container_of(work, struct r2net_sock_container, sc_rx_work);
- int ret;
-
- do {
- ret = r2net_advance_rx(sc);
- } while (ret > 0);
-
- if (ret <= 0 && ret != -EAGAIN) {
- struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
- sclog(sc, "saw error %d, closing\n", ret);
- /* not permanent so read failed handshake can retry */
- r2net_ensure_shutdown(nn, sc, 0);
- }
- sc_put(sc);
-}
-
-static int r2net_set_nodelay(struct socket *sock)
-{
- int ret, val = 1;
- mm_segment_t oldfs;
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
-
- /*
- * Dear unsuspecting programmer,
- *
- * Don't use sock_setsockopt() for SOL_TCP. It doesn't check its level
- * argument and assumes SOL_SOCKET so, say, your TCP_NODELAY will
- * silently turn into SO_DEBUG.
- *
- * Yours,
- * Keeper of hilariously fragile interfaces.
- */
- ret = sock->ops->setsockopt(sock, SOL_TCP, TCP_NODELAY,
- (char __user *)&val, sizeof(val));
-
- set_fs(oldfs);
- return ret;
-}
-
-static void r2net_initialize_handshake(void)
-{
- r2net_hand->r2hb_heartbeat_timeout_ms = cpu_to_be32(
- R2HB_MAX_WRITE_TIMEOUT_MS);
- r2net_hand->r2net_idle_timeout_ms = cpu_to_be32(r2net_idle_timeout());
- r2net_hand->r2net_keepalive_delay_ms = cpu_to_be32(
- r2net_keepalive_delay());
- r2net_hand->r2net_reconnect_delay_ms = cpu_to_be32(
- r2net_reconnect_delay());
-}
-
-/* ------------------------------------------------------------ */
-
-/* called when a connect completes and after a sock is accepted. the
- * rx path will see the response and mark the sc valid */
-static void r2net_sc_connect_completed(struct work_struct *work)
-{
- struct r2net_sock_container *sc =
- container_of(work, struct r2net_sock_container,
- sc_connect_work);
-
- mlog(ML_MSG, "sc sending handshake with ver %llu id %llx\n",
- (unsigned long long)R2NET_PROTOCOL_VERSION,
- (unsigned long long)be64_to_cpu(r2net_hand->connector_id));
-
- r2net_initialize_handshake();
- r2net_sendpage(sc, r2net_hand, sizeof(*r2net_hand));
- sc_put(sc);
-}
-
-/* this is called as a work_struct func. */
-static void r2net_sc_send_keep_req(struct work_struct *work)
-{
- struct r2net_sock_container *sc =
- container_of(work, struct r2net_sock_container,
- sc_keepalive_work.work);
-
- r2net_sendpage(sc, r2net_keep_req, sizeof(*r2net_keep_req));
- sc_put(sc);
-}
-
-/* socket shutdown does a del_timer_sync against this as it tears down.
- * we can't start this timer until we've got to the point in sc buildup
- * where shutdown is going to be involved */
-static void r2net_idle_timer(unsigned long data)
-{
- struct r2net_sock_container *sc = (struct r2net_sock_container *)data;
- struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
-#ifdef CONFIG_DEBUG_FS
- unsigned long msecs = ktime_to_ms(ktime_get()) -
- ktime_to_ms(sc->sc_tv_timer);
-#else
- unsigned long msecs = r2net_idle_timeout();
-#endif
-
- pr_notice("ramster: Connection to " SC_NODEF_FMT " has been "
- "idle for %lu.%lu secs, shutting it down.\n",
- sc->sc_node->nd_name, sc->sc_node->nd_num,
- &sc->sc_node->nd_ipv4_address, ntohs(sc->sc_node->nd_ipv4_port),
- msecs / 1000, msecs % 1000);
-
- /*
- * Initialize the nn_timeout so that the next connection attempt
- * will continue in r2net_start_connect.
- */
- atomic_set(&nn->nn_timeout, 1);
- r2net_sc_queue_work(sc, &sc->sc_shutdown_work);
-}
-
-static void r2net_sc_reset_idle_timer(struct r2net_sock_container *sc)
-{
- r2net_sc_cancel_delayed_work(sc, &sc->sc_keepalive_work);
- r2net_sc_queue_delayed_work(sc, &sc->sc_keepalive_work,
- msecs_to_jiffies(r2net_keepalive_delay()));
- r2net_set_sock_timer(sc);
- mod_timer(&sc->sc_idle_timeout,
- jiffies + msecs_to_jiffies(r2net_idle_timeout()));
-}
-
-static void r2net_sc_postpone_idle(struct r2net_sock_container *sc)
-{
- /* Only push out an existing timer */
- if (timer_pending(&sc->sc_idle_timeout))
- r2net_sc_reset_idle_timer(sc);
-}
-
-/* this work func is kicked whenever a path sets the nn state which doesn't
- * have valid set. This includes seeing hb come up, losing a connection,
- * having a connect attempt fail, etc. This centralizes the logic which decides
- * if a connect attempt should be made or if we should give up and all future
- * transmit attempts should fail */
-static void r2net_start_connect(struct work_struct *work)
-{
- struct r2net_node *nn =
- container_of(work, struct r2net_node, nn_connect_work.work);
- struct r2net_sock_container *sc = NULL;
- struct r2nm_node *node = NULL, *mynode = NULL;
- struct socket *sock = NULL;
- struct sockaddr_in myaddr = {0, }, remoteaddr = {0, };
- int ret = 0, stop;
- unsigned int timeout;
-
- /* if we're greater we initiate tx, otherwise we accept */
- if (r2nm_this_node() <= r2net_num_from_nn(nn))
- goto out;
-
- /* watch for racing with tearing a node down */
- node = r2nm_get_node_by_num(r2net_num_from_nn(nn));
- if (node == NULL) {
- ret = 0;
- goto out;
- }
-
- mynode = r2nm_get_node_by_num(r2nm_this_node());
- if (mynode == NULL) {
- ret = 0;
- goto out;
- }
-
- spin_lock(&nn->nn_lock);
- /*
- * see if we already have one pending or have given up.
- * For nn_timeout, it is set when we close the connection
- * because of the idle time out. So it means that we have
- * at least connected to that node successfully once,
- * now try to connect to it again.
- */
- timeout = atomic_read(&nn->nn_timeout);
- stop = (nn->nn_sc ||
- (nn->nn_persistent_error &&
- (nn->nn_persistent_error != -ENOTCONN || timeout == 0)));
- spin_unlock(&nn->nn_lock);
- if (stop)
- goto out;
-
- nn->nn_last_connect_attempt = jiffies;
-
- sc = sc_alloc(node);
- if (sc == NULL) {
- mlog(0, "couldn't allocate sc\n");
- ret = -ENOMEM;
- goto out;
- }
-
- ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
- if (ret < 0) {
- mlog(0, "can't create socket: %d\n", ret);
- goto out;
- }
- sc->sc_sock = sock; /* freed by sc_kref_release */
-
- sock->sk->sk_allocation = GFP_ATOMIC;
-
- myaddr.sin_family = AF_INET;
- myaddr.sin_addr.s_addr = mynode->nd_ipv4_address;
- myaddr.sin_port = htons(0); /* any port */
-
- ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr,
- sizeof(myaddr));
- if (ret) {
- mlog(ML_ERROR, "bind failed with %d at address %pI4\n",
- ret, &mynode->nd_ipv4_address);
- goto out;
- }
-
- ret = r2net_set_nodelay(sc->sc_sock);
- if (ret) {
- mlog(ML_ERROR, "setting TCP_NODELAY failed with %d\n", ret);
- goto out;
- }
-
- r2net_register_callbacks(sc->sc_sock->sk, sc);
-
- spin_lock(&nn->nn_lock);
- /* handshake completion will set nn->nn_sc_valid */
- r2net_set_nn_state(nn, sc, 0, 0);
- spin_unlock(&nn->nn_lock);
-
- remoteaddr.sin_family = AF_INET;
- remoteaddr.sin_addr.s_addr = node->nd_ipv4_address;
- remoteaddr.sin_port = node->nd_ipv4_port;
-
- ret = sc->sc_sock->ops->connect(sc->sc_sock,
- (struct sockaddr *)&remoteaddr,
- sizeof(remoteaddr),
- O_NONBLOCK);
- if (ret == -EINPROGRESS)
- ret = 0;
-
-out:
- if (ret) {
- pr_notice("ramster: Connect attempt to " SC_NODEF_FMT
- " failed with errno %d\n", sc->sc_node->nd_name,
- sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address,
- ntohs(sc->sc_node->nd_ipv4_port), ret);
- /* 0 err so that another will be queued and attempted
- * from set_nn_state */
- if (sc)
- r2net_ensure_shutdown(nn, sc, 0);
- }
- if (sc)
- sc_put(sc);
- if (node)
- r2nm_node_put(node);
- if (mynode)
- r2nm_node_put(mynode);
-
- return;
-}
-
-static void r2net_connect_expired(struct work_struct *work)
-{
- struct r2net_node *nn =
- container_of(work, struct r2net_node, nn_connect_expired.work);
-
- spin_lock(&nn->nn_lock);
- if (!nn->nn_sc_valid) {
- pr_notice("ramster: No connection established with "
- "node %u after %u.%u seconds, giving up.\n",
- r2net_num_from_nn(nn),
- r2net_idle_timeout() / 1000,
- r2net_idle_timeout() % 1000);
-
- r2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
- }
- spin_unlock(&nn->nn_lock);
-}
-
-static void r2net_still_up(struct work_struct *work)
-{
-}
-
-/* ------------------------------------------------------------ */
-
-void r2net_disconnect_node(struct r2nm_node *node)
-{
- struct r2net_node *nn = r2net_nn_from_num(node->nd_num);
-
- /* don't reconnect until it's heartbeating again */
- spin_lock(&nn->nn_lock);
- atomic_set(&nn->nn_timeout, 0);
- r2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
- spin_unlock(&nn->nn_lock);
-
- if (r2net_wq) {
- cancel_delayed_work(&nn->nn_connect_expired);
- cancel_delayed_work(&nn->nn_connect_work);
- cancel_delayed_work(&nn->nn_still_up);
- flush_workqueue(r2net_wq);
- }
-}
-
-static void r2net_hb_node_down_cb(struct r2nm_node *node, int node_num,
- void *data)
-{
- if (!node)
- return;
-
- if (node_num != r2nm_this_node())
- r2net_disconnect_node(node);
-
- BUG_ON(atomic_read(&r2net_connected_peers) < 0);
-}
-
-static void r2net_hb_node_up_cb(struct r2nm_node *node, int node_num,
- void *data)
-{
- struct r2net_node *nn = r2net_nn_from_num(node_num);
-
- BUG_ON(!node);
-
- /* ensure an immediate connect attempt */
- nn->nn_last_connect_attempt = jiffies -
- (msecs_to_jiffies(r2net_reconnect_delay()) + 1);
-
- if (node_num != r2nm_this_node()) {
- /* believe it or not, accept and node hearbeating testing
- * can succeed for this node before we got here.. so
- * only use set_nn_state to clear the persistent error
- * if that hasn't already happened */
- spin_lock(&nn->nn_lock);
- atomic_set(&nn->nn_timeout, 0);
- if (nn->nn_persistent_error)
- r2net_set_nn_state(nn, NULL, 0, 0);
- spin_unlock(&nn->nn_lock);
- }
-}
-
-void r2net_unregister_hb_callbacks(void)
-{
- r2hb_unregister_callback(NULL, &r2net_hb_up);
- r2hb_unregister_callback(NULL, &r2net_hb_down);
-}
-
-int r2net_register_hb_callbacks(void)
-{
- int ret;
-
- r2hb_setup_callback(&r2net_hb_down, R2HB_NODE_DOWN_CB,
- r2net_hb_node_down_cb, NULL, R2NET_HB_PRI);
- r2hb_setup_callback(&r2net_hb_up, R2HB_NODE_UP_CB,
- r2net_hb_node_up_cb, NULL, R2NET_HB_PRI);
-
- ret = r2hb_register_callback(NULL, &r2net_hb_up);
- if (ret == 0)
- ret = r2hb_register_callback(NULL, &r2net_hb_down);
-
- if (ret)
- r2net_unregister_hb_callbacks();
-
- return ret;
-}
-
-/* ------------------------------------------------------------ */
-
-static int r2net_accept_one(struct socket *sock)
-{
- int ret, slen;
- struct sockaddr_in sin;
- struct socket *new_sock = NULL;
- struct r2nm_node *node = NULL;
- struct r2nm_node *local_node = NULL;
- struct r2net_sock_container *sc = NULL;
- struct r2net_node *nn;
-
- BUG_ON(sock == NULL);
- ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type,
- sock->sk->sk_protocol, &new_sock);
- if (ret)
- goto out;
-
- new_sock->type = sock->type;
- new_sock->ops = sock->ops;
- ret = sock->ops->accept(sock, new_sock, O_NONBLOCK);
- if (ret < 0)
- goto out;
-
- new_sock->sk->sk_allocation = GFP_ATOMIC;
-
- ret = r2net_set_nodelay(new_sock);
- if (ret) {
- mlog(ML_ERROR, "setting TCP_NODELAY failed with %d\n", ret);
- goto out;
- }
-
- slen = sizeof(sin);
- ret = new_sock->ops->getname(new_sock, (struct sockaddr *) &sin,
- &slen, 1);
- if (ret < 0)
- goto out;
-
- node = r2nm_get_node_by_ip(sin.sin_addr.s_addr);
- if (node == NULL) {
- pr_notice("ramster: Attempt to connect from unknown "
- "node at %pI4:%d\n", &sin.sin_addr.s_addr,
- ntohs(sin.sin_port));
- ret = -EINVAL;
- goto out;
- }
-
- if (r2nm_this_node() >= node->nd_num) {
- local_node = r2nm_get_node_by_num(r2nm_this_node());
- pr_notice("ramster: Unexpected connect attempt seen "
- "at node '%s' (%u, %pI4:%d) from node '%s' (%u, "
- "%pI4:%d)\n", local_node->nd_name, local_node->nd_num,
- &(local_node->nd_ipv4_address),
- ntohs(local_node->nd_ipv4_port), node->nd_name,
- node->nd_num, &sin.sin_addr.s_addr, ntohs(sin.sin_port));
- ret = -EINVAL;
- goto out;
- }
-
- /* this happens all the time when the other node sees our heartbeat
- * and tries to connect before we see their heartbeat */
- if (!r2hb_check_node_heartbeating_from_callback(node->nd_num)) {
- mlog(ML_CONN, "attempt to connect from node '%s' at "
- "%pI4:%d but it isn't heartbeating\n",
- node->nd_name, &sin.sin_addr.s_addr,
- ntohs(sin.sin_port));
- ret = -EINVAL;
- goto out;
- }
-
- nn = r2net_nn_from_num(node->nd_num);
-
- spin_lock(&nn->nn_lock);
- if (nn->nn_sc)
- ret = -EBUSY;
- else
- ret = 0;
- spin_unlock(&nn->nn_lock);
- if (ret) {
- pr_notice("ramster: Attempt to connect from node '%s' "
- "at %pI4:%d but it already has an open connection\n",
- node->nd_name, &sin.sin_addr.s_addr,
- ntohs(sin.sin_port));
- goto out;
- }
-
- sc = sc_alloc(node);
- if (sc == NULL) {
- ret = -ENOMEM;
- goto out;
- }
-
- sc->sc_sock = new_sock;
- new_sock = NULL;
-
- spin_lock(&nn->nn_lock);
- atomic_set(&nn->nn_timeout, 0);
- r2net_set_nn_state(nn, sc, 0, 0);
- spin_unlock(&nn->nn_lock);
-
- r2net_register_callbacks(sc->sc_sock->sk, sc);
- r2net_sc_queue_work(sc, &sc->sc_rx_work);
-
- r2net_initialize_handshake();
- r2net_sendpage(sc, r2net_hand, sizeof(*r2net_hand));
-
-out:
- if (new_sock)
- sock_release(new_sock);
- if (node)
- r2nm_node_put(node);
- if (local_node)
- r2nm_node_put(local_node);
- if (sc)
- sc_put(sc);
- return ret;
-}
-
-static void r2net_accept_many(struct work_struct *work)
-{
- struct socket *sock = r2net_listen_sock;
- while (r2net_accept_one(sock) == 0)
- cond_resched();
-}
-
-static void r2net_listen_data_ready(struct sock *sk, int bytes)
-{
- void (*ready)(struct sock *sk, int bytes);
-
- read_lock(&sk->sk_callback_lock);
- ready = sk->sk_user_data;
- if (ready == NULL) { /* check for teardown race */
- ready = sk->sk_data_ready;
- goto out;
- }
-
- /* ->sk_data_ready is also called for a newly established child socket
- * before it has been accepted and the acceptor has set up their
- * data_ready.. we only want to queue listen work for our listening
- * socket */
- if (sk->sk_state == TCP_LISTEN) {
- mlog(ML_TCP, "bytes: %d\n", bytes);
- queue_work(r2net_wq, &r2net_listen_work);
- }
-
-out:
- read_unlock(&sk->sk_callback_lock);
- ready(sk, bytes);
-}
-
-static int r2net_open_listening_sock(__be32 addr, __be16 port)
-{
- struct socket *sock = NULL;
- int ret;
- struct sockaddr_in sin = {
- .sin_family = PF_INET,
- .sin_addr = { .s_addr = addr },
- .sin_port = port,
- };
-
- ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
- if (ret < 0) {
- pr_err("ramster: Error %d while creating socket\n", ret);
- goto out;
- }
-
- sock->sk->sk_allocation = GFP_ATOMIC;
-
- write_lock_bh(&sock->sk->sk_callback_lock);
- sock->sk->sk_user_data = sock->sk->sk_data_ready;
- sock->sk->sk_data_ready = r2net_listen_data_ready;
- write_unlock_bh(&sock->sk->sk_callback_lock);
-
- r2net_listen_sock = sock;
- INIT_WORK(&r2net_listen_work, r2net_accept_many);
-
- sock->sk->sk_reuse = /* SK_CAN_REUSE FIXME FOR 3.4 */ 1;
- ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
- if (ret < 0) {
- pr_err("ramster: Error %d while binding socket at %pI4:%u\n",
- ret, &addr, ntohs(port));
- goto out;
- }
-
- ret = sock->ops->listen(sock, 64);
- if (ret < 0)
- pr_err("ramster: Error %d while listening on %pI4:%u\n",
- ret, &addr, ntohs(port));
-
-out:
- if (ret) {
- r2net_listen_sock = NULL;
- if (sock)
- sock_release(sock);
- }
- return ret;
-}
-
-/*
- * called from node manager when we should bring up our network listening
- * socket. node manager handles all the serialization to only call this
- * once and to match it with r2net_stop_listening(). note,
- * r2nm_this_node() doesn't work yet as we're being called while it
- * is being set up.
- */
-int r2net_start_listening(struct r2nm_node *node)
-{
- int ret = 0;
-
- BUG_ON(r2net_wq != NULL);
- BUG_ON(r2net_listen_sock != NULL);
-
- mlog(ML_KTHREAD, "starting r2net thread...\n");
- r2net_wq = create_singlethread_workqueue("r2net");
- if (r2net_wq == NULL) {
- mlog(ML_ERROR, "unable to launch r2net thread\n");
- return -ENOMEM; /* ? */
- }
-
- ret = r2net_open_listening_sock(node->nd_ipv4_address,
- node->nd_ipv4_port);
- if (ret) {
- destroy_workqueue(r2net_wq);
- r2net_wq = NULL;
- }
-
- return ret;
-}
-
-/* again, r2nm_this_node() doesn't work here as we're involved in
- * tearing it down */
-void r2net_stop_listening(struct r2nm_node *node)
-{
- struct socket *sock = r2net_listen_sock;
- size_t i;
-
- BUG_ON(r2net_wq == NULL);
- BUG_ON(r2net_listen_sock == NULL);
-
- /* stop the listening socket from generating work */
- write_lock_bh(&sock->sk->sk_callback_lock);
- sock->sk->sk_data_ready = sock->sk->sk_user_data;
- sock->sk->sk_user_data = NULL;
- write_unlock_bh(&sock->sk->sk_callback_lock);
-
- for (i = 0; i < ARRAY_SIZE(r2net_nodes); i++) {
- struct r2nm_node *node = r2nm_get_node_by_num(i);
- if (node) {
- r2net_disconnect_node(node);
- r2nm_node_put(node);
- }
- }
-
- /* finish all work and tear down the work queue */
- mlog(ML_KTHREAD, "waiting for r2net thread to exit....\n");
- destroy_workqueue(r2net_wq);
- r2net_wq = NULL;
-
- sock_release(r2net_listen_sock);
- r2net_listen_sock = NULL;
-}
-
-void r2net_hb_node_up_manual(int node_num)
-{
- struct r2nm_node dummy;
- if (r2nm_single_cluster == NULL)
- pr_err("ramster: cluster not alive, node_up_manual ignored\n");
- else {
- r2hb_manual_set_node_heartbeating(node_num);
- r2net_hb_node_up_cb(&dummy, node_num, NULL);
- }
-}
-
-/* ------------------------------------------------------------ */
-
-int r2net_init(void)
-{
- unsigned long i;
-
- if (r2net_debugfs_init())
- return -ENOMEM;
-
- r2net_hand = kzalloc(sizeof(struct r2net_handshake), GFP_KERNEL);
- r2net_keep_req = kzalloc(sizeof(struct r2net_msg), GFP_KERNEL);
- r2net_keep_resp = kzalloc(sizeof(struct r2net_msg), GFP_KERNEL);
- if (!r2net_hand || !r2net_keep_req || !r2net_keep_resp) {
- kfree(r2net_hand);
- kfree(r2net_keep_req);
- kfree(r2net_keep_resp);
- return -ENOMEM;
- }
-
- r2net_hand->protocol_version = cpu_to_be64(R2NET_PROTOCOL_VERSION);
- r2net_hand->connector_id = cpu_to_be64(1);
-
- r2net_keep_req->magic = cpu_to_be16(R2NET_MSG_KEEP_REQ_MAGIC);
- r2net_keep_resp->magic = cpu_to_be16(R2NET_MSG_KEEP_RESP_MAGIC);
-
- for (i = 0; i < ARRAY_SIZE(r2net_nodes); i++) {
- struct r2net_node *nn = r2net_nn_from_num(i);
-
- atomic_set(&nn->nn_timeout, 0);
- spin_lock_init(&nn->nn_lock);
- INIT_DELAYED_WORK(&nn->nn_connect_work, r2net_start_connect);
- INIT_DELAYED_WORK(&nn->nn_connect_expired,
- r2net_connect_expired);
- INIT_DELAYED_WORK(&nn->nn_still_up, r2net_still_up);
- /* until we see hb from a node we'll return einval */
- nn->nn_persistent_error = -ENOTCONN;
- init_waitqueue_head(&nn->nn_sc_wq);
- idr_init(&nn->nn_status_idr);
- INIT_LIST_HEAD(&nn->nn_status_list);
- }
-
- return 0;
-}
-
-void r2net_exit(void)
-{
- kfree(r2net_hand);
- kfree(r2net_keep_req);
- kfree(r2net_keep_resp);
- r2net_debugfs_exit();
-}
diff --git a/drivers/staging/zcache/ramster/tcp.h b/drivers/staging/zcache/ramster/tcp.h
deleted file mode 100644
index 9d05833452b..00000000000
--- a/drivers/staging/zcache/ramster/tcp.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * tcp.h
- *
- * Function prototypes
- *
- * Copyright (C) 2004 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- *
- */
-
-#ifndef R2CLUSTER_TCP_H
-#define R2CLUSTER_TCP_H
-
-#include <linux/socket.h>
-#ifdef __KERNEL__
-#include <net/sock.h>
-#include <linux/tcp.h>
-#else
-#include <sys/socket.h>
-#endif
-#include <linux/inet.h>
-#include <linux/in.h>
-
-struct r2net_msg {
- __be16 magic;
- __be16 data_len;
- __be16 msg_type;
- __be16 pad1;
- __be32 sys_status;
- __be32 status;
- __be32 key;
- __be32 msg_num;
- __u8 buf[0];
-};
-
-typedef int (r2net_msg_handler_func)(struct r2net_msg *msg, u32 len, void *data,
- void **ret_data);
-typedef void (r2net_post_msg_handler_func)(int status, void *data,
- void *ret_data);
-
-#define R2NET_MAX_PAYLOAD_BYTES (4096 - sizeof(struct r2net_msg))
-
-/* same as hb delay, we're waiting for another node to recognize our hb */
-#define R2NET_RECONNECT_DELAY_MS_DEFAULT 2000
-
-#define R2NET_KEEPALIVE_DELAY_MS_DEFAULT 2000
-#define R2NET_IDLE_TIMEOUT_MS_DEFAULT 30000
-
-
-/* TODO: figure this out.... */
-static inline int r2net_link_down(int err, struct socket *sock)
-{
- if (sock) {
- if (sock->sk->sk_state != TCP_ESTABLISHED &&
- sock->sk->sk_state != TCP_CLOSE_WAIT)
- return 1;
- }
-
- if (err >= 0)
- return 0;
- switch (err) {
-
- /* ????????????????????????? */
- case -ERESTARTSYS:
- case -EBADF:
- /* When the server has died, an ICMP port unreachable
- * message prompts ECONNREFUSED. */
- case -ECONNREFUSED:
- case -ENOTCONN:
- case -ECONNRESET:
- case -EPIPE:
- return 1;
-
- }
- return 0;
-}
-
-enum {
- R2NET_DRIVER_UNINITED,
- R2NET_DRIVER_READY,
-};
-
-int r2net_send_message(u32 msg_type, u32 key, void *data, u32 len,
- u8 target_node, int *status);
-int r2net_send_message_vec(u32 msg_type, u32 key, struct kvec *vec,
- size_t veclen, u8 target_node, int *status);
-
-int r2net_register_handler(u32 msg_type, u32 key, u32 max_len,
- r2net_msg_handler_func *func, void *data,
- r2net_post_msg_handler_func *post_func,
- struct list_head *unreg_list);
-void r2net_unregister_handler_list(struct list_head *list);
-
-void r2net_fill_node_map(unsigned long *map, unsigned bytes);
-
-void r2net_force_data_magic(struct r2net_msg *, u16, u32);
-void r2net_hb_node_up_manual(int);
-struct r2net_node *r2net_nn_from_num(u8);
-
-struct r2nm_node;
-int r2net_register_hb_callbacks(void);
-void r2net_unregister_hb_callbacks(void);
-int r2net_start_listening(struct r2nm_node *node);
-void r2net_stop_listening(struct r2nm_node *node);
-void r2net_disconnect_node(struct r2nm_node *node);
-int r2net_num_connected_peers(void);
-
-int r2net_init(void);
-void r2net_exit(void);
-
-struct r2net_send_tracking;
-struct r2net_sock_container;
-
-#if 0
-int r2net_debugfs_init(void);
-void r2net_debugfs_exit(void);
-void r2net_debug_add_nst(struct r2net_send_tracking *nst);
-void r2net_debug_del_nst(struct r2net_send_tracking *nst);
-void r2net_debug_add_sc(struct r2net_sock_container *sc);
-void r2net_debug_del_sc(struct r2net_sock_container *sc);
-#else
-static inline int r2net_debugfs_init(void)
-{
- return 0;
-}
-static inline void r2net_debugfs_exit(void)
-{
-}
-static inline void r2net_debug_add_nst(struct r2net_send_tracking *nst)
-{
-}
-static inline void r2net_debug_del_nst(struct r2net_send_tracking *nst)
-{
-}
-static inline void r2net_debug_add_sc(struct r2net_sock_container *sc)
-{
-}
-static inline void r2net_debug_del_sc(struct r2net_sock_container *sc)
-{
-}
-#endif /* CONFIG_DEBUG_FS */
-
-#endif /* R2CLUSTER_TCP_H */
diff --git a/drivers/staging/zcache/ramster/tcp_internal.h b/drivers/staging/zcache/ramster/tcp_internal.h
deleted file mode 100644
index 4d8cc9f96fd..00000000000
--- a/drivers/staging/zcache/ramster/tcp_internal.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * Copyright (C) 2005 Oracle. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#ifndef R2CLUSTER_TCP_INTERNAL_H
-#define R2CLUSTER_TCP_INTERNAL_H
-
-#define R2NET_MSG_MAGIC ((u16)0xfa55)
-#define R2NET_MSG_STATUS_MAGIC ((u16)0xfa56)
-#define R2NET_MSG_KEEP_REQ_MAGIC ((u16)0xfa57)
-#define R2NET_MSG_KEEP_RESP_MAGIC ((u16)0xfa58)
-/*
- * "data magic" is a long version of "status magic" where the message
- * payload actually contains data to be passed in reply to certain messages
- */
-#define R2NET_MSG_DATA_MAGIC ((u16)0xfa59)
-
-/* we're delaying our quorum decision so that heartbeat will have timed
- * out truly dead nodes by the time we come around to making decisions
- * on their number */
-#define R2NET_QUORUM_DELAY_MS \
- ((r2hb_dead_threshold + 2) * R2HB_REGION_TIMEOUT_MS)
-
-/*
- * This version number represents quite a lot, unfortunately. It not
- * only represents the raw network message protocol on the wire but also
- * locking semantics of the file system using the protocol. It should
- * be somewhere else, I'm sure, but right now it isn't.
- *
- * With version 11, we separate out the filesystem locking portion. The
- * filesystem now has a major.minor version it negotiates. Version 11
- * introduces this negotiation to the r2dlm protocol, and as such the
- * version here in tcp_internal.h should not need to be bumped for
- * filesystem locking changes.
- *
- * New in version 11
- * - Negotiation of filesystem locking in the dlm join.
- *
- * New in version 10:
- * - Meta/data locks combined
- *
- * New in version 9:
- * - All votes removed
- *
- * New in version 8:
- * - Replace delete inode votes with a cluster lock
- *
- * New in version 7:
- * - DLM join domain includes the live nodemap
- *
- * New in version 6:
- * - DLM lockres remote refcount fixes.
- *
- * New in version 5:
- * - Network timeout checking protocol
- *
- * New in version 4:
- * - Remove i_generation from lock names for better stat performance.
- *
- * New in version 3:
- * - Replace dentry votes with a cluster lock
- *
- * New in version 2:
- * - full 64 bit i_size in the metadata lock lvbs
- * - introduction of "rw" lock and pushing meta/data locking down
- */
-#define R2NET_PROTOCOL_VERSION 11ULL
-struct r2net_handshake {
- __be64 protocol_version;
- __be64 connector_id;
- __be32 r2hb_heartbeat_timeout_ms;
- __be32 r2net_idle_timeout_ms;
- __be32 r2net_keepalive_delay_ms;
- __be32 r2net_reconnect_delay_ms;
-};
-
-struct r2net_node {
- /* this is never called from int/bh */
- spinlock_t nn_lock;
-
- /* set the moment an sc is allocated and a connect is started */
- struct r2net_sock_container *nn_sc;
- /* _valid is only set after the handshake passes and tx can happen */
- unsigned nn_sc_valid:1;
- /* if this is set tx just returns it */
- int nn_persistent_error;
- /* It is only set to 1 after the idle time out. */
- atomic_t nn_timeout;
-
- /* threads waiting for an sc to arrive wait on the wq for generation
- * to increase. it is increased when a connecting socket succeeds
- * or fails or when an accepted socket is attached. */
- wait_queue_head_t nn_sc_wq;
-
- struct idr nn_status_idr;
- struct list_head nn_status_list;
-
- /* connects are attempted from when heartbeat comes up until either hb
- * goes down, the node is unconfigured, no connect attempts succeed
- * before R2NET_CONN_IDLE_DELAY, or a connect succeeds. connect_work
- * is queued from set_nn_state both from hb up and from itself if a
- * connect attempt fails and so can be self-arming. shutdown is
- * careful to first mark the nn such that no connects will be attempted
- * before canceling delayed connect work and flushing the queue. */
- struct delayed_work nn_connect_work;
- unsigned long nn_last_connect_attempt;
-
- /* this is queued as nodes come up and is canceled when a connection is
- * established. this expiring gives up on the node and errors out
- * transmits */
- struct delayed_work nn_connect_expired;
-
- /* after we give up on a socket we wait a while before deciding
- * that it is still heartbeating and that we should do some
- * quorum work */
- struct delayed_work nn_still_up;
-};
-
-struct r2net_sock_container {
- struct kref sc_kref;
- /* the next two are valid for the life time of the sc */
- struct socket *sc_sock;
- struct r2nm_node *sc_node;
-
- /* all of these sc work structs hold refs on the sc while they are
- * queued. they should not be able to ref a freed sc. the teardown
- * race is with r2net_wq destruction in r2net_stop_listening() */
-
- /* rx and connect work are generated from socket callbacks. sc
- * shutdown removes the callbacks and then flushes the work queue */
- struct work_struct sc_rx_work;
- struct work_struct sc_connect_work;
- /* shutdown work is triggered in two ways. the simple way is
- * for a code path calls ensure_shutdown which gets a lock, removes
- * the sc from the nn, and queues the work. in this case the
- * work is single-shot. the work is also queued from a sock
- * callback, though, and in this case the work will find the sc
- * still on the nn and will call ensure_shutdown itself.. this
- * ends up triggering the shutdown work again, though nothing
- * will be done in that second iteration. so work queue teardown
- * has to be careful to remove the sc from the nn before waiting
- * on the work queue so that the shutdown work doesn't remove the
- * sc and rearm itself.
- */
- struct work_struct sc_shutdown_work;
-
- struct timer_list sc_idle_timeout;
- struct delayed_work sc_keepalive_work;
-
- unsigned sc_handshake_ok:1;
-
- struct page *sc_page;
- size_t sc_page_off;
-
- /* original handlers for the sockets */
- void (*sc_state_change)(struct sock *sk);
- void (*sc_data_ready)(struct sock *sk, int bytes);
-
- u32 sc_msg_key;
- u16 sc_msg_type;
-
-#ifdef CONFIG_DEBUG_FS
- struct list_head sc_net_debug_item;
- ktime_t sc_tv_timer;
- ktime_t sc_tv_data_ready;
- ktime_t sc_tv_advance_start;
- ktime_t sc_tv_advance_stop;
- ktime_t sc_tv_func_start;
- ktime_t sc_tv_func_stop;
-#endif
-#ifdef CONFIG_RAMSTER_FS_STATS
- ktime_t sc_tv_acquiry_total;
- ktime_t sc_tv_send_total;
- ktime_t sc_tv_status_total;
- u32 sc_send_count;
- u32 sc_recv_count;
- ktime_t sc_tv_process_total;
-#endif
- struct mutex sc_send_lock;
-};
-
-struct r2net_msg_handler {
- struct rb_node nh_node;
- u32 nh_max_len;
- u32 nh_msg_type;
- u32 nh_key;
- r2net_msg_handler_func *nh_func;
- r2net_msg_handler_func *nh_func_data;
- r2net_post_msg_handler_func
- *nh_post_func;
- struct kref nh_kref;
- struct list_head nh_unregister_item;
-};
-
-enum r2net_system_error {
- R2NET_ERR_NONE = 0,
- R2NET_ERR_NO_HNDLR,
- R2NET_ERR_OVERFLOW,
- R2NET_ERR_DIED,
- R2NET_ERR_MAX
-};
-
-struct r2net_status_wait {
- enum r2net_system_error ns_sys_status;
- s32 ns_status;
- int ns_id;
- wait_queue_head_t ns_wq;
- struct list_head ns_node_item;
-};
-
-#ifdef CONFIG_DEBUG_FS
-/* just for state dumps */
-struct r2net_send_tracking {
- struct list_head st_net_debug_item;
- struct task_struct *st_task;
- struct r2net_sock_container *st_sc;
- u32 st_id;
- u32 st_msg_type;
- u32 st_msg_key;
- u8 st_node;
- ktime_t st_sock_time;
- ktime_t st_send_time;
- ktime_t st_status_time;
-};
-#else
-struct r2net_send_tracking {
- u32 dummy;
-};
-#endif /* CONFIG_DEBUG_FS */
-
-#endif /* R2CLUSTER_TCP_INTERNAL_H */
diff --git a/drivers/staging/zcache/tmem.c b/drivers/staging/zcache/tmem.c
deleted file mode 100644
index d7e51e4152e..00000000000
--- a/drivers/staging/zcache/tmem.c
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * In-kernel transcendent memory (generic implementation)
- *
- * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
- *
- * The primary purpose of Transcedent Memory ("tmem") is to map object-oriented
- * "handles" (triples containing a pool id, and object id, and an index), to
- * pages in a page-accessible memory (PAM). Tmem references the PAM pages via
- * an abstract "pampd" (PAM page-descriptor), which can be operated on by a
- * set of functions (pamops). Each pampd contains some representation of
- * PAGE_SIZE bytes worth of data. For those familiar with key-value stores,
- * the tmem handle is a three-level hierarchical key, and the value is always
- * reconstituted (but not necessarily stored) as PAGE_SIZE bytes and is
- * referenced in the datastore by the pampd. The hierarchy is required
- * to ensure that certain invalidation functions can be performed efficiently
- * (i.e. flush all indexes associated with this object_id, or
- * flush all objects associated with this pool).
- *
- * Tmem must support potentially millions of pages and must be able to insert,
- * find, and delete these pages at a potential frequency of thousands per
- * second concurrently across many CPUs, (and, if used with KVM, across many
- * vcpus across many guests). Tmem is tracked with a hierarchy of data
- * structures, organized by the elements in the handle-tuple: pool_id,
- * object_id, and page index. One or more "clients" (e.g. guests) each
- * provide one or more tmem_pools. Each pool, contains a hash table of
- * rb_trees of tmem_objs. Each tmem_obj contains a radix-tree-like tree
- * of pointers, with intermediate nodes called tmem_objnodes. Each leaf
- * pointer in this tree points to a pampd, which is accessible only through
- * a small set of callbacks registered by the PAM implementation (see
- * tmem_register_pamops). Tmem only needs to memory allocation for objs
- * and objnodes and this is done via a set of callbacks that must be
- * registered by the tmem host implementation (e.g. see tmem_register_hostops).
- */
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/atomic.h>
-#include <linux/export.h>
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
-#include <linux/delay.h>
-#endif
-
-#include "tmem.h"
-
-/* data structure sentinels used for debugging... see tmem.h */
-#define POOL_SENTINEL 0x87658765
-#define OBJ_SENTINEL 0x12345678
-#define OBJNODE_SENTINEL 0xfedcba09
-
-/*
- * A tmem host implementation must use this function to register callbacks
- * for memory allocation.
- */
-static struct tmem_hostops tmem_hostops;
-
-static void tmem_objnode_tree_init(void);
-
-void tmem_register_hostops(struct tmem_hostops *m)
-{
- tmem_objnode_tree_init();
- tmem_hostops = *m;
-}
-
-/*
- * A tmem host implementation must use this function to register
- * callbacks for a page-accessible memory (PAM) implementation.
- */
-static struct tmem_pamops tmem_pamops;
-
-void tmem_register_pamops(struct tmem_pamops *m)
-{
- tmem_pamops = *m;
-}
-
-/*
- * Oid's are potentially very sparse and tmem_objs may have an indeterminately
- * short life, being added and deleted at a relatively high frequency.
- * So an rb_tree is an ideal data structure to manage tmem_objs. But because
- * of the potentially huge number of tmem_objs, each pool manages a hashtable
- * of rb_trees to reduce search, insert, delete, and rebalancing time.
- * Each hashbucket also has a lock to manage concurrent access and no
- * searches, inserts, or deletions can be performed unless the lock is held.
- * As a result, care must be taken to ensure tmem routines are not called
- * recursively; the vast majority of the time, a recursive call may work
- * but a deadlock will occur a small fraction of the time due to the
- * hashbucket lock.
- *
- * The following routines manage tmem_objs. In all of these routines,
- * the hashbucket lock is already held.
- */
-
-/* Search for object==oid in pool, returns object if found. */
-static struct tmem_obj *__tmem_obj_find(struct tmem_hashbucket *hb,
- struct tmem_oid *oidp,
- struct rb_node **parent,
- struct rb_node ***link)
-{
- struct rb_node *_parent = NULL, **rbnode;
- struct tmem_obj *obj = NULL;
-
- rbnode = &hb->obj_rb_root.rb_node;
- while (*rbnode) {
- BUG_ON(RB_EMPTY_NODE(*rbnode));
- _parent = *rbnode;
- obj = rb_entry(*rbnode, struct tmem_obj,
- rb_tree_node);
- switch (tmem_oid_compare(oidp, &obj->oid)) {
- case 0: /* equal */
- goto out;
- case -1:
- rbnode = &(*rbnode)->rb_left;
- break;
- case 1:
- rbnode = &(*rbnode)->rb_right;
- break;
- }
- }
-
- if (parent)
- *parent = _parent;
- if (link)
- *link = rbnode;
- obj = NULL;
-out:
- return obj;
-}
-
-static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb,
- struct tmem_oid *oidp)
-{
- return __tmem_obj_find(hb, oidp, NULL, NULL);
-}
-
-static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *, bool);
-
-/* Free an object that has no more pampds in it. */
-static void tmem_obj_free(struct tmem_obj *obj, struct tmem_hashbucket *hb)
-{
- struct tmem_pool *pool;
-
- BUG_ON(obj == NULL);
- ASSERT_SENTINEL(obj, OBJ);
- BUG_ON(obj->pampd_count > 0);
- pool = obj->pool;
- BUG_ON(pool == NULL);
- if (obj->objnode_tree_root != NULL) /* may be "stump" with no leaves */
- tmem_pampd_destroy_all_in_obj(obj, false);
- BUG_ON(obj->objnode_tree_root != NULL);
- BUG_ON((long)obj->objnode_count != 0);
- atomic_dec(&pool->obj_count);
- BUG_ON(atomic_read(&pool->obj_count) < 0);
- INVERT_SENTINEL(obj, OBJ);
- obj->pool = NULL;
- tmem_oid_set_invalid(&obj->oid);
- rb_erase(&obj->rb_tree_node, &hb->obj_rb_root);
-}
-
-/*
- * Initialize, and insert an tmem_object_root (called only if find failed).
- */
-static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb,
- struct tmem_pool *pool,
- struct tmem_oid *oidp)
-{
- struct rb_root *root = &hb->obj_rb_root;
- struct rb_node **new = NULL, *parent = NULL;
-
- BUG_ON(pool == NULL);
- atomic_inc(&pool->obj_count);
- obj->objnode_tree_height = 0;
- obj->objnode_tree_root = NULL;
- obj->pool = pool;
- obj->oid = *oidp;
- obj->objnode_count = 0;
- obj->pampd_count = 0;
-#ifdef CONFIG_RAMSTER
- if (tmem_pamops.new_obj != NULL)
- (*tmem_pamops.new_obj)(obj);
-#endif
- SET_SENTINEL(obj, OBJ);
-
- if (__tmem_obj_find(hb, oidp, &parent, &new))
- BUG();
-
- rb_link_node(&obj->rb_tree_node, parent, new);
- rb_insert_color(&obj->rb_tree_node, root);
-}
-
-/*
- * Tmem is managed as a set of tmem_pools with certain attributes, such as
- * "ephemeral" vs "persistent". These attributes apply to all tmem_objs
- * and all pampds that belong to a tmem_pool. A tmem_pool is created
- * or deleted relatively rarely (for example, when a filesystem is
- * mounted or unmounted).
- */
-
-/* flush all data from a pool and, optionally, free it */
-static void tmem_pool_flush(struct tmem_pool *pool, bool destroy)
-{
- struct rb_node *rbnode;
- struct tmem_obj *obj;
- struct tmem_hashbucket *hb = &pool->hashbucket[0];
- int i;
-
- BUG_ON(pool == NULL);
- for (i = 0; i < TMEM_HASH_BUCKETS; i++, hb++) {
- spin_lock(&hb->lock);
- rbnode = rb_first(&hb->obj_rb_root);
- while (rbnode != NULL) {
- obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node);
- rbnode = rb_next(rbnode);
- tmem_pampd_destroy_all_in_obj(obj, true);
- tmem_obj_free(obj, hb);
- (*tmem_hostops.obj_free)(obj, pool);
- }
- spin_unlock(&hb->lock);
- }
- if (destroy)
- list_del(&pool->pool_list);
-}
-
-/*
- * A tmem_obj contains a radix-tree-like tree in which the intermediate
- * nodes are called tmem_objnodes. (The kernel lib/radix-tree.c implementation
- * is very specialized and tuned for specific uses and is not particularly
- * suited for use from this code, though some code from the core algorithms has
- * been reused, thus the copyright notices below). Each tmem_objnode contains
- * a set of pointers which point to either a set of intermediate tmem_objnodes
- * or a set of of pampds.
- *
- * Portions Copyright (C) 2001 Momchil Velikov
- * Portions Copyright (C) 2001 Christoph Hellwig
- * Portions Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
- */
-
-struct tmem_objnode_tree_path {
- struct tmem_objnode *objnode;
- int offset;
-};
-
-/* objnode height_to_maxindex translation */
-static unsigned long tmem_objnode_tree_h2max[OBJNODE_TREE_MAX_PATH + 1];
-
-static void tmem_objnode_tree_init(void)
-{
- unsigned int ht, tmp;
-
- for (ht = 0; ht < ARRAY_SIZE(tmem_objnode_tree_h2max); ht++) {
- tmp = ht * OBJNODE_TREE_MAP_SHIFT;
- if (tmp >= OBJNODE_TREE_INDEX_BITS)
- tmem_objnode_tree_h2max[ht] = ~0UL;
- else
- tmem_objnode_tree_h2max[ht] =
- (~0UL >> (OBJNODE_TREE_INDEX_BITS - tmp - 1)) >> 1;
- }
-}
-
-static struct tmem_objnode *tmem_objnode_alloc(struct tmem_obj *obj)
-{
- struct tmem_objnode *objnode;
-
- ASSERT_SENTINEL(obj, OBJ);
- BUG_ON(obj->pool == NULL);
- ASSERT_SENTINEL(obj->pool, POOL);
- objnode = (*tmem_hostops.objnode_alloc)(obj->pool);
- if (unlikely(objnode == NULL))
- goto out;
- objnode->obj = obj;
- SET_SENTINEL(objnode, OBJNODE);
- memset(&objnode->slots, 0, sizeof(objnode->slots));
- objnode->slots_in_use = 0;
- obj->objnode_count++;
-out:
- return objnode;
-}
-
-static void tmem_objnode_free(struct tmem_objnode *objnode)
-{
- struct tmem_pool *pool;
- int i;
-
- BUG_ON(objnode == NULL);
- for (i = 0; i < OBJNODE_TREE_MAP_SIZE; i++)
- BUG_ON(objnode->slots[i] != NULL);
- ASSERT_SENTINEL(objnode, OBJNODE);
- INVERT_SENTINEL(objnode, OBJNODE);
- BUG_ON(objnode->obj == NULL);
- ASSERT_SENTINEL(objnode->obj, OBJ);
- pool = objnode->obj->pool;
- BUG_ON(pool == NULL);
- ASSERT_SENTINEL(pool, POOL);
- objnode->obj->objnode_count--;
- objnode->obj = NULL;
- (*tmem_hostops.objnode_free)(objnode, pool);
-}
-
-/*
- * Lookup index in object and return associated pampd (or NULL if not found).
- */
-static void **__tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index)
-{
- unsigned int height, shift;
- struct tmem_objnode **slot = NULL;
-
- BUG_ON(obj == NULL);
- ASSERT_SENTINEL(obj, OBJ);
- BUG_ON(obj->pool == NULL);
- ASSERT_SENTINEL(obj->pool, POOL);
-
- height = obj->objnode_tree_height;
- if (index > tmem_objnode_tree_h2max[obj->objnode_tree_height])
- goto out;
- if (height == 0 && obj->objnode_tree_root) {
- slot = &obj->objnode_tree_root;
- goto out;
- }
- shift = (height-1) * OBJNODE_TREE_MAP_SHIFT;
- slot = &obj->objnode_tree_root;
- while (height > 0) {
- if (*slot == NULL)
- goto out;
- slot = (struct tmem_objnode **)
- ((*slot)->slots +
- ((index >> shift) & OBJNODE_TREE_MAP_MASK));
- shift -= OBJNODE_TREE_MAP_SHIFT;
- height--;
- }
-out:
- return slot != NULL ? (void **)slot : NULL;
-}
-
-static void *tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index)
-{
- struct tmem_objnode **slot;
-
- slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index);
- return slot != NULL ? *slot : NULL;
-}
-
-#ifdef CONFIG_RAMSTER
-static void *tmem_pampd_replace_in_obj(struct tmem_obj *obj, uint32_t index,
- void *new_pampd, bool no_free)
-{
- struct tmem_objnode **slot;
- void *ret = NULL;
-
- slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index);
- if ((slot != NULL) && (*slot != NULL)) {
- void *old_pampd = *(void **)slot;
- *(void **)slot = new_pampd;
- if (!no_free)
- (*tmem_pamops.free)(old_pampd, obj->pool,
- NULL, 0, false);
- ret = new_pampd;
- }
- return ret;
-}
-#endif
-
-static int tmem_pampd_add_to_obj(struct tmem_obj *obj, uint32_t index,
- void *pampd)
-{
- int ret = 0;
- struct tmem_objnode *objnode = NULL, *newnode, *slot;
- unsigned int height, shift;
- int offset = 0;
-
- /* if necessary, extend the tree to be higher */
- if (index > tmem_objnode_tree_h2max[obj->objnode_tree_height]) {
- height = obj->objnode_tree_height + 1;
- if (index > tmem_objnode_tree_h2max[height])
- while (index > tmem_objnode_tree_h2max[height])
- height++;
- if (obj->objnode_tree_root == NULL) {
- obj->objnode_tree_height = height;
- goto insert;
- }
- do {
- newnode = tmem_objnode_alloc(obj);
- if (!newnode) {
- ret = -ENOMEM;
- goto out;
- }
- newnode->slots[0] = obj->objnode_tree_root;
- newnode->slots_in_use = 1;
- obj->objnode_tree_root = newnode;
- obj->objnode_tree_height++;
- } while (height > obj->objnode_tree_height);
- }
-insert:
- slot = obj->objnode_tree_root;
- height = obj->objnode_tree_height;
- shift = (height-1) * OBJNODE_TREE_MAP_SHIFT;
- while (height > 0) {
- if (slot == NULL) {
- /* add a child objnode. */
- slot = tmem_objnode_alloc(obj);
- if (!slot) {
- ret = -ENOMEM;
- goto out;
- }
- if (objnode) {
-
- objnode->slots[offset] = slot;
- objnode->slots_in_use++;
- } else
- obj->objnode_tree_root = slot;
- }
- /* go down a level */
- offset = (index >> shift) & OBJNODE_TREE_MAP_MASK;
- objnode = slot;
- slot = objnode->slots[offset];
- shift -= OBJNODE_TREE_MAP_SHIFT;
- height--;
- }
- BUG_ON(slot != NULL);
- if (objnode) {
- objnode->slots_in_use++;
- objnode->slots[offset] = pampd;
- } else
- obj->objnode_tree_root = pampd;
- obj->pampd_count++;
-out:
- return ret;
-}
-
-static void *tmem_pampd_delete_from_obj(struct tmem_obj *obj, uint32_t index)
-{
- struct tmem_objnode_tree_path path[OBJNODE_TREE_MAX_PATH + 1];
- struct tmem_objnode_tree_path *pathp = path;
- struct tmem_objnode *slot = NULL;
- unsigned int height, shift;
- int offset;
-
- BUG_ON(obj == NULL);
- ASSERT_SENTINEL(obj, OBJ);
- BUG_ON(obj->pool == NULL);
- ASSERT_SENTINEL(obj->pool, POOL);
- height = obj->objnode_tree_height;
- if (index > tmem_objnode_tree_h2max[height])
- goto out;
- slot = obj->objnode_tree_root;
- if (height == 0 && obj->objnode_tree_root) {
- obj->objnode_tree_root = NULL;
- goto out;
- }
- shift = (height - 1) * OBJNODE_TREE_MAP_SHIFT;
- pathp->objnode = NULL;
- do {
- if (slot == NULL)
- goto out;
- pathp++;
- offset = (index >> shift) & OBJNODE_TREE_MAP_MASK;
- pathp->offset = offset;
- pathp->objnode = slot;
- slot = slot->slots[offset];
- shift -= OBJNODE_TREE_MAP_SHIFT;
- height--;
- } while (height > 0);
- if (slot == NULL)
- goto out;
- while (pathp->objnode) {
- pathp->objnode->slots[pathp->offset] = NULL;
- pathp->objnode->slots_in_use--;
- if (pathp->objnode->slots_in_use) {
- if (pathp->objnode == obj->objnode_tree_root) {
- while (obj->objnode_tree_height > 0 &&
- obj->objnode_tree_root->slots_in_use == 1 &&
- obj->objnode_tree_root->slots[0]) {
- struct tmem_objnode *to_free =
- obj->objnode_tree_root;
-
- obj->objnode_tree_root =
- to_free->slots[0];
- obj->objnode_tree_height--;
- to_free->slots[0] = NULL;
- to_free->slots_in_use = 0;
- tmem_objnode_free(to_free);
- }
- }
- goto out;
- }
- tmem_objnode_free(pathp->objnode); /* 0 slots used, free it */
- pathp--;
- }
- obj->objnode_tree_height = 0;
- obj->objnode_tree_root = NULL;
-
-out:
- if (slot != NULL)
- obj->pampd_count--;
- BUG_ON(obj->pampd_count < 0);
- return slot;
-}
-
-/* Recursively walk the objnode_tree destroying pampds and objnodes. */
-static void tmem_objnode_node_destroy(struct tmem_obj *obj,
- struct tmem_objnode *objnode,
- unsigned int ht)
-{
- int i;
-
- if (ht == 0)
- return;
- for (i = 0; i < OBJNODE_TREE_MAP_SIZE; i++) {
- if (objnode->slots[i]) {
- if (ht == 1) {
- obj->pampd_count--;
- (*tmem_pamops.free)(objnode->slots[i],
- obj->pool, NULL, 0, true);
- objnode->slots[i] = NULL;
- continue;
- }
- tmem_objnode_node_destroy(obj, objnode->slots[i], ht-1);
- tmem_objnode_free(objnode->slots[i]);
- objnode->slots[i] = NULL;
- }
- }
-}
-
-static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj,
- bool pool_destroy)
-{
- if (obj->objnode_tree_root == NULL)
- return;
- if (obj->objnode_tree_height == 0) {
- obj->pampd_count--;
- (*tmem_pamops.free)(obj->objnode_tree_root,
- obj->pool, NULL, 0, true);
- } else {
- tmem_objnode_node_destroy(obj, obj->objnode_tree_root,
- obj->objnode_tree_height);
- tmem_objnode_free(obj->objnode_tree_root);
- obj->objnode_tree_height = 0;
- }
- obj->objnode_tree_root = NULL;
-#ifdef CONFIG_RAMSTER
- if (tmem_pamops.free_obj != NULL)
- (*tmem_pamops.free_obj)(obj->pool, obj, pool_destroy);
-#endif
-}
-
-/*
- * Tmem is operated on by a set of well-defined actions:
- * "put", "get", "flush", "flush_object", "new pool" and "destroy pool".
- * (The tmem ABI allows for subpages and exchanges but these operations
- * are not included in this implementation.)
- *
- * These "tmem core" operations are implemented in the following functions.
- */
-
-/*
- * "Put" a page, e.g. associate the passed pampd with the passed handle.
- * Tmem_put is complicated by a corner case: What if a page with matching
- * handle already exists in tmem? To guarantee coherency, one of two
- * actions is necessary: Either the data for the page must be overwritten,
- * or the page must be "flushed" so that the data is not accessible to a
- * subsequent "get". Since these "duplicate puts" are relatively rare,
- * this implementation always flushes for simplicity.
- */
-int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
- bool raw, void *pampd_to_use)
-{
- struct tmem_obj *obj = NULL, *objfound = NULL, *objnew = NULL;
- void *pampd = NULL, *pampd_del = NULL;
- int ret = -ENOMEM;
- struct tmem_hashbucket *hb;
-
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- obj = objfound = tmem_obj_find(hb, oidp);
- if (obj != NULL) {
- pampd = tmem_pampd_lookup_in_obj(objfound, index);
- if (pampd != NULL) {
- /* if found, is a dup put, flush the old one */
- pampd_del = tmem_pampd_delete_from_obj(obj, index);
- BUG_ON(pampd_del != pampd);
- (*tmem_pamops.free)(pampd, pool, oidp, index, true);
- if (obj->pampd_count == 0) {
- objnew = obj;
- objfound = NULL;
- }
- pampd = NULL;
- }
- } else {
- obj = objnew = (*tmem_hostops.obj_alloc)(pool);
- if (unlikely(obj == NULL)) {
- ret = -ENOMEM;
- goto out;
- }
- tmem_obj_init(obj, hb, pool, oidp);
- }
- BUG_ON(obj == NULL);
- BUG_ON(((objnew != obj) && (objfound != obj)) || (objnew == objfound));
- pampd = pampd_to_use;
- BUG_ON(pampd_to_use == NULL);
- ret = tmem_pampd_add_to_obj(obj, index, pampd);
- if (unlikely(ret == -ENOMEM))
- /* may have partially built objnode tree ("stump") */
- goto delete_and_free;
- (*tmem_pamops.create_finish)(pampd, is_ephemeral(pool));
- goto out;
-
-delete_and_free:
- (void)tmem_pampd_delete_from_obj(obj, index);
- if (pampd)
- (*tmem_pamops.free)(pampd, pool, NULL, 0, true);
- if (objnew) {
- tmem_obj_free(objnew, hb);
- (*tmem_hostops.obj_free)(objnew, pool);
- }
-out:
- spin_unlock(&hb->lock);
- return ret;
-}
-
-#ifdef CONFIG_RAMSTER
-/*
- * For ramster only: The following routines provide a two-step sequence
- * to allow the caller to replace a pampd in the tmem data structures with
- * another pampd. Here, we lookup the passed handle and, if found, return the
- * associated pampd and object, leaving the hashbucket locked and returning
- * a reference to it. The caller is expected to immediately call the
- * matching tmem_localify_finish routine which will handles the replacement
- * and unlocks the hashbucket.
- */
-void *tmem_localify_get_pampd(struct tmem_pool *pool, struct tmem_oid *oidp,
- uint32_t index, struct tmem_obj **ret_obj,
- void **saved_hb)
-{
- struct tmem_hashbucket *hb;
- struct tmem_obj *obj = NULL;
- void *pampd = NULL;
-
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- obj = tmem_obj_find(hb, oidp);
- if (likely(obj != NULL))
- pampd = tmem_pampd_lookup_in_obj(obj, index);
- *ret_obj = obj;
- *saved_hb = (void *)hb;
- /* note, hashbucket remains locked */
- return pampd;
-}
-EXPORT_SYMBOL_GPL(tmem_localify_get_pampd);
-
-void tmem_localify_finish(struct tmem_obj *obj, uint32_t index,
- void *pampd, void *saved_hb, bool delete)
-{
- struct tmem_hashbucket *hb = (struct tmem_hashbucket *)saved_hb;
-
- BUG_ON(!spin_is_locked(&hb->lock));
- if (pampd != NULL) {
- BUG_ON(obj == NULL);
- (void)tmem_pampd_replace_in_obj(obj, index, pampd, 1);
- (*tmem_pamops.create_finish)(pampd, is_ephemeral(obj->pool));
- } else if (delete) {
- BUG_ON(obj == NULL);
- (void)tmem_pampd_delete_from_obj(obj, index);
- }
- spin_unlock(&hb->lock);
-}
-EXPORT_SYMBOL_GPL(tmem_localify_finish);
-
-/*
- * For ramster only. Helper function to support asynchronous tmem_get.
- */
-static int tmem_repatriate(void **ppampd, struct tmem_hashbucket *hb,
- struct tmem_pool *pool, struct tmem_oid *oidp,
- uint32_t index, bool free, char *data)
-{
- void *old_pampd = *ppampd, *new_pampd = NULL;
- bool intransit = false;
- int ret = 0;
-
- if (!is_ephemeral(pool))
- new_pampd = (*tmem_pamops.repatriate_preload)(
- old_pampd, pool, oidp, index, &intransit);
- if (intransit)
- ret = -EAGAIN;
- else if (new_pampd != NULL)
- *ppampd = new_pampd;
- /* must release the hb->lock else repatriate can't sleep */
- spin_unlock(&hb->lock);
- if (!intransit)
- ret = (*tmem_pamops.repatriate)(old_pampd, new_pampd, pool,
- oidp, index, free, data);
- if (ret == -EAGAIN) {
- /* rare I think, but should cond_resched()??? */
- usleep_range(10, 1000);
- } else if (ret == -ENOTCONN || ret == -EHOSTDOWN) {
- ret = -1;
- } else if (ret != 0 && ret != -ENOENT) {
- ret = -1;
- }
- /* note hb->lock has now been unlocked */
- return ret;
-}
-
-/*
- * For ramster only. If a page in tmem matches the handle, replace the
- * page so that any subsequent "get" gets the new page. Returns 0 if
- * there was a page to replace, else returns -1.
- */
-int tmem_replace(struct tmem_pool *pool, struct tmem_oid *oidp,
- uint32_t index, void *new_pampd)
-{
- struct tmem_obj *obj;
- int ret = -1;
- struct tmem_hashbucket *hb;
-
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- obj = tmem_obj_find(hb, oidp);
- if (obj == NULL)
- goto out;
- new_pampd = tmem_pampd_replace_in_obj(obj, index, new_pampd, 0);
- /* if we bug here, pamops wasn't properly set up for ramster */
- BUG_ON(tmem_pamops.replace_in_obj == NULL);
- ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj);
-out:
- spin_unlock(&hb->lock);
- return ret;
-}
-EXPORT_SYMBOL_GPL(tmem_replace);
-#endif
-
-/*
- * "Get" a page, e.g. if a pampd can be found matching the passed handle,
- * use a pamops callback to recreated the page from the pampd with the
- * matching handle. By tmem definition, when a "get" is successful on
- * an ephemeral page, the page is "flushed", and when a "get" is successful
- * on a persistent page, the page is retained in tmem. Note that to preserve
- * coherency, "get" can never be skipped if tmem contains the data.
- * That is, if a get is done with a certain handle and fails, any
- * subsequent "get" must also fail (unless of course there is a
- * "put" done with the same handle).
- */
-int tmem_get(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index,
- char *data, size_t *sizep, bool raw, int get_and_free)
-{
- struct tmem_obj *obj;
- void *pampd = NULL;
- bool ephemeral = is_ephemeral(pool);
- int ret = -1;
- struct tmem_hashbucket *hb;
- bool free = (get_and_free == 1) || ((get_and_free == 0) && ephemeral);
- bool lock_held = false;
- void **ppampd;
-
- do {
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- lock_held = true;
- obj = tmem_obj_find(hb, oidp);
- if (obj == NULL)
- goto out;
- ppampd = __tmem_pampd_lookup_in_obj(obj, index);
- if (ppampd == NULL)
- goto out;
-#ifdef CONFIG_RAMSTER
- if ((tmem_pamops.is_remote != NULL) &&
- tmem_pamops.is_remote(*ppampd)) {
- ret = tmem_repatriate(ppampd, hb, pool, oidp,
- index, free, data);
- /* tmem_repatriate releases hb->lock */
- lock_held = false;
- *sizep = PAGE_SIZE;
- if (ret != -EAGAIN)
- goto out;
- }
-#endif
- } while (ret == -EAGAIN);
- if (free)
- pampd = tmem_pampd_delete_from_obj(obj, index);
- else
- pampd = tmem_pampd_lookup_in_obj(obj, index);
- if (pampd == NULL)
- goto out;
- if (free) {
- if (obj->pampd_count == 0) {
- tmem_obj_free(obj, hb);
- (*tmem_hostops.obj_free)(obj, pool);
- obj = NULL;
- }
- }
- if (free)
- ret = (*tmem_pamops.get_data_and_free)(
- data, sizep, raw, pampd, pool, oidp, index);
- else
- ret = (*tmem_pamops.get_data)(
- data, sizep, raw, pampd, pool, oidp, index);
- if (ret < 0)
- goto out;
- ret = 0;
-out:
- if (lock_held)
- spin_unlock(&hb->lock);
- return ret;
-}
-
-/*
- * If a page in tmem matches the handle, "flush" this page from tmem such
- * that any subsequent "get" does not succeed (unless, of course, there
- * was another "put" with the same handle).
- */
-int tmem_flush_page(struct tmem_pool *pool,
- struct tmem_oid *oidp, uint32_t index)
-{
- struct tmem_obj *obj;
- void *pampd;
- int ret = -1;
- struct tmem_hashbucket *hb;
-
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- obj = tmem_obj_find(hb, oidp);
- if (obj == NULL)
- goto out;
- pampd = tmem_pampd_delete_from_obj(obj, index);
- if (pampd == NULL)
- goto out;
- (*tmem_pamops.free)(pampd, pool, oidp, index, true);
- if (obj->pampd_count == 0) {
- tmem_obj_free(obj, hb);
- (*tmem_hostops.obj_free)(obj, pool);
- }
- ret = 0;
-
-out:
- spin_unlock(&hb->lock);
- return ret;
-}
-
-/*
- * "Flush" all pages in tmem matching this oid.
- */
-int tmem_flush_object(struct tmem_pool *pool, struct tmem_oid *oidp)
-{
- struct tmem_obj *obj;
- struct tmem_hashbucket *hb;
- int ret = -1;
-
- hb = &pool->hashbucket[tmem_oid_hash(oidp)];
- spin_lock(&hb->lock);
- obj = tmem_obj_find(hb, oidp);
- if (obj == NULL)
- goto out;
- tmem_pampd_destroy_all_in_obj(obj, false);
- tmem_obj_free(obj, hb);
- (*tmem_hostops.obj_free)(obj, pool);
- ret = 0;
-
-out:
- spin_unlock(&hb->lock);
- return ret;
-}
-
-/*
- * "Flush" all pages (and tmem_objs) from this tmem_pool and disable
- * all subsequent access to this tmem_pool.
- */
-int tmem_destroy_pool(struct tmem_pool *pool)
-{
- int ret = -1;
-
- if (pool == NULL)
- goto out;
- tmem_pool_flush(pool, 1);
- ret = 0;
-out:
- return ret;
-}
-
-static LIST_HEAD(tmem_global_pool_list);
-
-/*
- * Create a new tmem_pool with the provided flag and return
- * a pool id provided by the tmem host implementation.
- */
-void tmem_new_pool(struct tmem_pool *pool, uint32_t flags)
-{
- int persistent = flags & TMEM_POOL_PERSIST;
- int shared = flags & TMEM_POOL_SHARED;
- struct tmem_hashbucket *hb = &pool->hashbucket[0];
- int i;
-
- for (i = 0; i < TMEM_HASH_BUCKETS; i++, hb++) {
- hb->obj_rb_root = RB_ROOT;
- spin_lock_init(&hb->lock);
- }
- INIT_LIST_HEAD(&pool->pool_list);
- atomic_set(&pool->obj_count, 0);
- SET_SENTINEL(pool, POOL);
- list_add_tail(&pool->pool_list, &tmem_global_pool_list);
- pool->persistent = persistent;
- pool->shared = shared;
-}
diff --git a/drivers/staging/zcache/tmem.h b/drivers/staging/zcache/tmem.h
deleted file mode 100644
index d128ce290f1..00000000000
--- a/drivers/staging/zcache/tmem.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * tmem.h
- *
- * Transcendent memory
- *
- * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
- */
-
-#ifndef _TMEM_H_
-#define _TMEM_H_
-
-#include <linux/types.h>
-#include <linux/highmem.h>
-#include <linux/hash.h>
-#include <linux/atomic.h>
-
-/*
- * These are defined by the Xen<->Linux ABI so should remain consistent
- */
-#define TMEM_POOL_PERSIST 1
-#define TMEM_POOL_SHARED 2
-#define TMEM_POOL_PRECOMPRESSED 4
-#define TMEM_POOL_PAGESIZE_SHIFT 4
-#define TMEM_POOL_PAGESIZE_MASK 0xf
-#define TMEM_POOL_RESERVED_BITS 0x00ffff00
-
-/*
- * sentinels have proven very useful for debugging but can be removed
- * or disabled before final merge.
- */
-#undef SENTINELS
-#ifdef SENTINELS
-#define DECL_SENTINEL uint32_t sentinel;
-#define SET_SENTINEL(_x, _y) (_x->sentinel = _y##_SENTINEL)
-#define INVERT_SENTINEL(_x, _y) (_x->sentinel = ~_y##_SENTINEL)
-#define ASSERT_SENTINEL(_x, _y) WARN_ON(_x->sentinel != _y##_SENTINEL)
-#define ASSERT_INVERTED_SENTINEL(_x, _y) WARN_ON(_x->sentinel != ~_y##_SENTINEL)
-#else
-#define DECL_SENTINEL
-#define SET_SENTINEL(_x, _y) do { } while (0)
-#define INVERT_SENTINEL(_x, _y) do { } while (0)
-#define ASSERT_SENTINEL(_x, _y) do { } while (0)
-#define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0)
-#endif
-
-#define ASSERT_SPINLOCK(_l) lockdep_assert_held(_l)
-
-/*
- * A pool is the highest-level data structure managed by tmem and
- * usually corresponds to a large independent set of pages such as
- * a filesystem. Each pool has an id, and certain attributes and counters.
- * It also contains a set of hash buckets, each of which contains an rbtree
- * of objects and a lock to manage concurrency within the pool.
- */
-
-#define TMEM_HASH_BUCKET_BITS 8
-#define TMEM_HASH_BUCKETS (1<<TMEM_HASH_BUCKET_BITS)
-
-struct tmem_hashbucket {
- struct rb_root obj_rb_root;
- spinlock_t lock;
-};
-
-struct tmem_pool {
- void *client; /* "up" for some clients, avoids table lookup */
- struct list_head pool_list;
- uint32_t pool_id;
- bool persistent;
- bool shared;
- atomic_t obj_count;
- atomic_t refcount;
- struct tmem_hashbucket hashbucket[TMEM_HASH_BUCKETS];
- DECL_SENTINEL
-};
-
-#define is_persistent(_p) (_p->persistent)
-#define is_ephemeral(_p) (!(_p->persistent))
-
-/*
- * An object id ("oid") is large: 192-bits (to ensure, for example, files
- * in a modern filesystem can be uniquely identified).
- */
-
-struct tmem_oid {
- uint64_t oid[3];
-};
-
-static inline void tmem_oid_set_invalid(struct tmem_oid *oidp)
-{
- oidp->oid[0] = oidp->oid[1] = oidp->oid[2] = -1UL;
-}
-
-static inline bool tmem_oid_valid(struct tmem_oid *oidp)
-{
- return oidp->oid[0] != -1UL || oidp->oid[1] != -1UL ||
- oidp->oid[2] != -1UL;
-}
-
-static inline int tmem_oid_compare(struct tmem_oid *left,
- struct tmem_oid *right)
-{
- int ret;
-
- if (left->oid[2] == right->oid[2]) {
- if (left->oid[1] == right->oid[1]) {
- if (left->oid[0] == right->oid[0])
- ret = 0;
- else if (left->oid[0] < right->oid[0])
- ret = -1;
- else
- return 1;
- } else if (left->oid[1] < right->oid[1])
- ret = -1;
- else
- ret = 1;
- } else if (left->oid[2] < right->oid[2])
- ret = -1;
- else
- ret = 1;
- return ret;
-}
-
-static inline unsigned tmem_oid_hash(struct tmem_oid *oidp)
-{
- return hash_long(oidp->oid[0] ^ oidp->oid[1] ^ oidp->oid[2],
- TMEM_HASH_BUCKET_BITS);
-}
-
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
-struct tmem_xhandle {
- uint8_t client_id;
- uint8_t xh_data_cksum;
- uint16_t xh_data_size;
- uint16_t pool_id;
- struct tmem_oid oid;
- uint32_t index;
- void *extra;
-};
-
-static inline struct tmem_xhandle tmem_xhandle_fill(uint16_t client_id,
- struct tmem_pool *pool,
- struct tmem_oid *oidp,
- uint32_t index)
-{
- struct tmem_xhandle xh;
- xh.client_id = client_id;
- xh.xh_data_cksum = (uint8_t)-1;
- xh.xh_data_size = (uint16_t)-1;
- xh.pool_id = pool->pool_id;
- xh.oid = *oidp;
- xh.index = index;
- return xh;
-}
-#endif
-
-
-/*
- * A tmem_obj contains an identifier (oid), pointers to the parent
- * pool and the rb_tree to which it belongs, counters, and an ordered
- * set of pampds, structured in a radix-tree-like tree. The intermediate
- * nodes of the tree are called tmem_objnodes.
- */
-
-struct tmem_objnode;
-
-struct tmem_obj {
- struct tmem_oid oid;
- struct tmem_pool *pool;
- struct rb_node rb_tree_node;
- struct tmem_objnode *objnode_tree_root;
- unsigned int objnode_tree_height;
- unsigned long objnode_count;
- long pampd_count;
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
- /*
- * for current design of ramster, all pages belonging to
- * an object reside on the same remotenode and extra is
- * used to record the number of the remotenode so a
- * flush-object operation can specify it
- */
- void *extra; /* for private use by pampd implementation */
-#endif
- DECL_SENTINEL
-};
-
-#define OBJNODE_TREE_MAP_SHIFT 6
-#define OBJNODE_TREE_MAP_SIZE (1UL << OBJNODE_TREE_MAP_SHIFT)
-#define OBJNODE_TREE_MAP_MASK (OBJNODE_TREE_MAP_SIZE-1)
-#define OBJNODE_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long))
-#define OBJNODE_TREE_MAX_PATH \
- (OBJNODE_TREE_INDEX_BITS/OBJNODE_TREE_MAP_SHIFT + 2)
-
-struct tmem_objnode {
- struct tmem_obj *obj;
- DECL_SENTINEL
- void *slots[OBJNODE_TREE_MAP_SIZE];
- unsigned int slots_in_use;
-};
-
-struct tmem_handle {
- struct tmem_oid oid; /* 24 bytes */
- uint32_t index;
- uint16_t pool_id;
- uint16_t client_id;
-};
-
-
-/* pampd abstract datatype methods provided by the PAM implementation */
-struct tmem_pamops {
- void (*create_finish)(void *, bool);
- int (*get_data)(char *, size_t *, bool, void *, struct tmem_pool *,
- struct tmem_oid *, uint32_t);
- int (*get_data_and_free)(char *, size_t *, bool, void *,
- struct tmem_pool *, struct tmem_oid *,
- uint32_t);
- void (*free)(void *, struct tmem_pool *,
- struct tmem_oid *, uint32_t, bool);
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
- void (*new_obj)(struct tmem_obj *);
- void (*free_obj)(struct tmem_pool *, struct tmem_obj *, bool);
- void *(*repatriate_preload)(void *, struct tmem_pool *,
- struct tmem_oid *, uint32_t, bool *);
- int (*repatriate)(void *, void *, struct tmem_pool *,
- struct tmem_oid *, uint32_t, bool, void *);
- bool (*is_remote)(void *);
- int (*replace_in_obj)(void *, struct tmem_obj *);
-#endif
-};
-extern void tmem_register_pamops(struct tmem_pamops *m);
-
-/* memory allocation methods provided by the host implementation */
-struct tmem_hostops {
- struct tmem_obj *(*obj_alloc)(struct tmem_pool *);
- void (*obj_free)(struct tmem_obj *, struct tmem_pool *);
- struct tmem_objnode *(*objnode_alloc)(struct tmem_pool *);
- void (*objnode_free)(struct tmem_objnode *, struct tmem_pool *);
-};
-extern void tmem_register_hostops(struct tmem_hostops *m);
-
-/* core tmem accessor functions */
-extern int tmem_put(struct tmem_pool *, struct tmem_oid *, uint32_t index,
- bool, void *);
-extern int tmem_get(struct tmem_pool *, struct tmem_oid *, uint32_t index,
- char *, size_t *, bool, int);
-extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *,
- uint32_t index);
-extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *);
-extern int tmem_destroy_pool(struct tmem_pool *);
-extern void tmem_new_pool(struct tmem_pool *, uint32_t);
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
-extern int tmem_replace(struct tmem_pool *, struct tmem_oid *, uint32_t index,
- void *);
-extern void *tmem_localify_get_pampd(struct tmem_pool *, struct tmem_oid *,
- uint32_t index, struct tmem_obj **,
- void **);
-extern void tmem_localify_finish(struct tmem_obj *, uint32_t index,
- void *, void *, bool);
-#endif
-#endif /* _TMEM_H */
diff --git a/drivers/staging/zcache/zbud.c b/drivers/staging/zcache/zbud.c
deleted file mode 100644
index 6cda4ed9ed3..00000000000
--- a/drivers/staging/zcache/zbud.c
+++ /dev/null
@@ -1,1066 +0,0 @@
-/*
- * zbud.c - Compression buddies allocator
- *
- * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
- *
- * Compression buddies ("zbud") provides for efficiently packing two
- * (or, possibly in the future, more) compressed pages ("zpages") into
- * a single "raw" pageframe and for tracking both zpages and pageframes
- * so that whole pageframes can be easily reclaimed in LRU-like order.
- * It is designed to be used in conjunction with transcendent memory
- * ("tmem"); for example separate LRU lists are maintained for persistent
- * vs. ephemeral pages.
- *
- * A zbudpage is an overlay for a struct page and thus each zbudpage
- * refers to a physical pageframe of RAM. When the caller passes a
- * struct page from the kernel's page allocator, zbud "transforms" it
- * to a zbudpage which sets/uses a different set of fields than the
- * struct-page and thus must "untransform" it back by reinitializing
- * certain fields before the struct-page can be freed. The fields
- * of a zbudpage include a page lock for controlling access to the
- * corresponding pageframe, and there is a size field for each zpage.
- * Each zbudpage also lives on two linked lists: a "budlist" which is
- * used to support efficient buddying of zpages; and an "lru" which
- * is used for reclaiming pageframes in approximately least-recently-used
- * order.
- *
- * A zbudpageframe is a pageframe divided up into aligned 64-byte "chunks"
- * which contain the compressed data for zero, one, or two zbuds. Contained
- * with the compressed data is a tmem_handle which is a key to allow
- * the same data to be found via the tmem interface so the zpage can
- * be invalidated (for ephemeral pages) or repatriated to the swap cache
- * (for persistent pages). The contents of a zbudpageframe must never
- * be accessed without holding the page lock for the corresponding
- * zbudpage and, to accomodate highmem machines, the contents may
- * only be examined or changes when kmapped. Thus, when in use, a
- * kmapped zbudpageframe is referred to in the zbud code as "void *zbpg".
- *
- * Note that the term "zbud" refers to the combination of a zpage and
- * a tmem_handle that is stored as one of possibly two "buddied" zpages;
- * it also generically refers to this allocator... sorry for any confusion.
- *
- * A zbudref is a pointer to a struct zbudpage (which can be cast to a
- * struct page), with the LSB either cleared or set to indicate, respectively,
- * the first or second zpage in the zbudpageframe. Since a zbudref can be
- * cast to a pointer, it is used as the tmem "pampd" pointer and uniquely
- * references a stored tmem page and so is the only zbud data structure
- * externally visible to zbud.c/zbud.h.
- *
- * Since we wish to reclaim entire pageframes but zpages may be randomly
- * added and deleted to any given pageframe, we approximate LRU by
- * promoting a pageframe to MRU when a zpage is added to it, but
- * leaving it at the current place in the list when a zpage is deleted
- * from it. As a side effect, zpages that are difficult to buddy (e.g.
- * very large paages) will be reclaimed faster than average, which seems
- * reasonable.
- *
- * In the current implementation, no more than two zpages may be stored in
- * any pageframe and no zpage ever crosses a pageframe boundary. While
- * other zpage allocation mechanisms may allow greater density, this two
- * zpage-per-pageframe limit both ensures simple reclaim of pageframes
- * (including garbage collection of references to the contents of those
- * pageframes from tmem data structures) AND avoids the need for compaction.
- * With additional complexity, zbud could be modified to support storing
- * up to three zpages per pageframe or, to handle larger average zpages,
- * up to three zpages per pair of pageframes, but it is not clear if the
- * additional complexity would be worth it. So consider it an exercise
- * for future developers.
- *
- * Note also that zbud does no page allocation or freeing. This is so
- * that the caller has complete control over and, for accounting, visibility
- * into if/when pages are allocated and freed.
- *
- * Finally, note that zbud limits the size of zpages it can store; the
- * caller must check the zpage size with zbud_max_buddy_size before
- * storing it, else BUGs will result. User beware.
- */
-
-#include <linux/module.h>
-#include <linux/highmem.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/pagemap.h>
-#include <linux/atomic.h>
-#include <linux/bug.h>
-#include "tmem.h"
-#include "zcache.h"
-#include "zbud.h"
-
-/*
- * We need to ensure that a struct zbudpage is never larger than a
- * struct page. This is checked with a BUG_ON in zbud_init.
- *
- * The unevictable field indicates that a zbud is being added to the
- * zbudpage. Since this is a two-phase process (due to tmem locking),
- * this field locks the zbudpage against eviction when a zbud match
- * or creation is in process. Since this addition process may occur
- * in parallel for two zbuds in one zbudpage, the field is a counter
- * that must not exceed two.
- */
-struct zbudpage {
- union {
- struct page page;
- struct {
- unsigned long space_for_flags;
- struct {
- unsigned zbud0_size:PAGE_SHIFT;
- unsigned zbud1_size:PAGE_SHIFT;
- unsigned unevictable:2;
- };
- struct list_head budlist;
- struct list_head lru;
- };
- };
-};
-#if (PAGE_SHIFT * 2) + 2 > BITS_PER_LONG
-#error "zbud won't work for this arch, PAGE_SIZE is too large"
-#endif
-
-struct zbudref {
- union {
- struct zbudpage *zbudpage;
- unsigned long zbudref;
- };
-};
-
-#define CHUNK_SHIFT 6
-#define CHUNK_SIZE (1 << CHUNK_SHIFT)
-#define CHUNK_MASK (~(CHUNK_SIZE-1))
-#define NCHUNKS (PAGE_SIZE >> CHUNK_SHIFT)
-#define MAX_CHUNK (NCHUNKS-1)
-
-/*
- * The following functions deal with the difference between struct
- * page and struct zbudpage. Note the hack of using the pageflags
- * from struct page; this is to avoid duplicating all the complex
- * pageflag macros.
- */
-static inline void zbudpage_spin_lock(struct zbudpage *zbudpage)
-{
- struct page *page = (struct page *)zbudpage;
-
- while (unlikely(test_and_set_bit_lock(PG_locked, &page->flags))) {
- do {
- cpu_relax();
- } while (test_bit(PG_locked, &page->flags));
- }
-}
-
-static inline void zbudpage_spin_unlock(struct zbudpage *zbudpage)
-{
- struct page *page = (struct page *)zbudpage;
-
- clear_bit(PG_locked, &page->flags);
-}
-
-static inline int zbudpage_spin_trylock(struct zbudpage *zbudpage)
-{
- return trylock_page((struct page *)zbudpage);
-}
-
-static inline int zbudpage_is_locked(struct zbudpage *zbudpage)
-{
- return PageLocked((struct page *)zbudpage);
-}
-
-static inline void *kmap_zbudpage_atomic(struct zbudpage *zbudpage)
-{
- return kmap_atomic((struct page *)zbudpage);
-}
-
-/*
- * A dying zbudpage is an ephemeral page in the process of being evicted.
- * Any data contained in the zbudpage is invalid and we are just waiting for
- * the tmem pampds to be invalidated before freeing the page
- */
-static inline int zbudpage_is_dying(struct zbudpage *zbudpage)
-{
- struct page *page = (struct page *)zbudpage;
-
- return test_bit(PG_reclaim, &page->flags);
-}
-
-static inline void zbudpage_set_dying(struct zbudpage *zbudpage)
-{
- struct page *page = (struct page *)zbudpage;
-
- set_bit(PG_reclaim, &page->flags);
-}
-
-static inline void zbudpage_clear_dying(struct zbudpage *zbudpage)
-{
- struct page *page = (struct page *)zbudpage;
-
- clear_bit(PG_reclaim, &page->flags);
-}
-
-/*
- * A zombie zbudpage is a persistent page in the process of being evicted.
- * The data contained in the zbudpage is valid and we are just waiting for
- * the tmem pampds to be invalidated before freeing the page
- */
-static inline int zbudpage_is_zombie(struct zbudpage *zbudpage)
-{
- struct page *page = (struct page *)zbudpage;
-
- return test_bit(PG_dirty, &page->flags);
-}
-
-static inline void zbudpage_set_zombie(struct zbudpage *zbudpage)
-{
- struct page *page = (struct page *)zbudpage;
-
- set_bit(PG_dirty, &page->flags);
-}
-
-static inline void zbudpage_clear_zombie(struct zbudpage *zbudpage)
-{
- struct page *page = (struct page *)zbudpage;
-
- clear_bit(PG_dirty, &page->flags);
-}
-
-static inline void kunmap_zbudpage_atomic(void *zbpg)
-{
- kunmap_atomic(zbpg);
-}
-
-/*
- * zbud "translation" and helper functions
- */
-
-static inline struct zbudpage *zbudref_to_zbudpage(struct zbudref *zref)
-{
- unsigned long zbud = (unsigned long)zref;
- zbud &= ~1UL;
- return (struct zbudpage *)zbud;
-}
-
-static inline struct zbudref *zbudpage_to_zbudref(struct zbudpage *zbudpage,
- unsigned budnum)
-{
- unsigned long zbud = (unsigned long)zbudpage;
- BUG_ON(budnum > 1);
- zbud |= budnum;
- return (struct zbudref *)zbud;
-}
-
-static inline int zbudref_budnum(struct zbudref *zbudref)
-{
- unsigned long zbud = (unsigned long)zbudref;
- return zbud & 1UL;
-}
-
-static inline unsigned zbud_max_size(void)
-{
- return MAX_CHUNK << CHUNK_SHIFT;
-}
-
-static inline unsigned zbud_size_to_chunks(unsigned size)
-{
- BUG_ON(size == 0 || size > zbud_max_size());
- return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
-}
-
-/* can only be used between kmap_zbudpage_atomic/kunmap_zbudpage_atomic! */
-static inline char *zbud_data(void *zbpg,
- unsigned budnum, unsigned size)
-{
- char *p;
-
- BUG_ON(size == 0 || size > zbud_max_size());
- p = (char *)zbpg;
- if (budnum == 1)
- p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK);
- return p;
-}
-
-/*
- * These are all informative and exposed through debugfs... except for
- * the arrays... anyone know how to do that? To avoid confusion for
- * debugfs viewers, some of these should also be atomic_long_t, but
- * I don't know how to expose atomics via debugfs either...
- */
-static ssize_t zbud_eph_pageframes;
-static ssize_t zbud_pers_pageframes;
-static ssize_t zbud_eph_zpages;
-static ssize_t zbud_pers_zpages;
-static u64 zbud_eph_zbytes;
-static u64 zbud_pers_zbytes;
-static ssize_t zbud_eph_evicted_pageframes;
-static ssize_t zbud_pers_evicted_pageframes;
-static ssize_t zbud_eph_cumul_zpages;
-static ssize_t zbud_pers_cumul_zpages;
-static u64 zbud_eph_cumul_zbytes;
-static u64 zbud_pers_cumul_zbytes;
-static ssize_t zbud_eph_cumul_chunk_counts[NCHUNKS];
-static ssize_t zbud_pers_cumul_chunk_counts[NCHUNKS];
-static ssize_t zbud_eph_buddied_count;
-static ssize_t zbud_pers_buddied_count;
-static ssize_t zbud_eph_unbuddied_count;
-static ssize_t zbud_pers_unbuddied_count;
-static ssize_t zbud_eph_zombie_count;
-static ssize_t zbud_pers_zombie_count;
-static atomic_t zbud_eph_zombie_atomic;
-static atomic_t zbud_pers_zombie_atomic;
-
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#define zdfs debugfs_create_size_t
-#define zdfs64 debugfs_create_u64
-static int zbud_debugfs_init(void)
-{
- struct dentry *root = debugfs_create_dir("zbud", NULL);
- if (root == NULL)
- return -ENXIO;
-
- /*
- * would be nice to dump the sizes of the unbuddied
- * arrays, like was done with sysfs, but it doesn't
- * look like debugfs is flexible enough to do that
- */
- zdfs64("eph_zbytes", S_IRUGO, root, &zbud_eph_zbytes);
- zdfs64("eph_cumul_zbytes", S_IRUGO, root, &zbud_eph_cumul_zbytes);
- zdfs64("pers_zbytes", S_IRUGO, root, &zbud_pers_zbytes);
- zdfs64("pers_cumul_zbytes", S_IRUGO, root, &zbud_pers_cumul_zbytes);
- zdfs("eph_cumul_zpages", S_IRUGO, root, &zbud_eph_cumul_zpages);
- zdfs("eph_evicted_pageframes", S_IRUGO, root,
- &zbud_eph_evicted_pageframes);
- zdfs("eph_zpages", S_IRUGO, root, &zbud_eph_zpages);
- zdfs("eph_pageframes", S_IRUGO, root, &zbud_eph_pageframes);
- zdfs("eph_buddied_count", S_IRUGO, root, &zbud_eph_buddied_count);
- zdfs("eph_unbuddied_count", S_IRUGO, root, &zbud_eph_unbuddied_count);
- zdfs("pers_cumul_zpages", S_IRUGO, root, &zbud_pers_cumul_zpages);
- zdfs("pers_evicted_pageframes", S_IRUGO, root,
- &zbud_pers_evicted_pageframes);
- zdfs("pers_zpages", S_IRUGO, root, &zbud_pers_zpages);
- zdfs("pers_pageframes", S_IRUGO, root, &zbud_pers_pageframes);
- zdfs("pers_buddied_count", S_IRUGO, root, &zbud_pers_buddied_count);
- zdfs("pers_unbuddied_count", S_IRUGO, root, &zbud_pers_unbuddied_count);
- zdfs("pers_zombie_count", S_IRUGO, root, &zbud_pers_zombie_count);
- return 0;
-}
-#undef zdfs
-#undef zdfs64
-#else
-static inline int zbud_debugfs_init(void)
-{
- return 0;
-}
-#endif
-
-/* protects the buddied list and all unbuddied lists */
-static DEFINE_SPINLOCK(zbud_eph_lists_lock);
-static DEFINE_SPINLOCK(zbud_pers_lists_lock);
-
-struct zbud_unbuddied {
- struct list_head list;
- unsigned count;
-};
-
-/* list N contains pages with N chunks USED and NCHUNKS-N unused */
-/* element 0 is never used but optimizing that isn't worth it */
-static struct zbud_unbuddied zbud_eph_unbuddied[NCHUNKS];
-static struct zbud_unbuddied zbud_pers_unbuddied[NCHUNKS];
-static LIST_HEAD(zbud_eph_lru_list);
-static LIST_HEAD(zbud_pers_lru_list);
-static LIST_HEAD(zbud_eph_buddied_list);
-static LIST_HEAD(zbud_pers_buddied_list);
-static LIST_HEAD(zbud_eph_zombie_list);
-static LIST_HEAD(zbud_pers_zombie_list);
-
-/*
- * Given a struct page, transform it to a zbudpage so that it can be
- * used by zbud and initialize fields as necessary.
- */
-static inline struct zbudpage *zbud_init_zbudpage(struct page *page, bool eph)
-{
- struct zbudpage *zbudpage = (struct zbudpage *)page;
-
- BUG_ON(page == NULL);
- INIT_LIST_HEAD(&zbudpage->budlist);
- INIT_LIST_HEAD(&zbudpage->lru);
- zbudpage->zbud0_size = 0;
- zbudpage->zbud1_size = 0;
- zbudpage->unevictable = 0;
- if (eph)
- zbud_eph_pageframes++;
- else
- zbud_pers_pageframes++;
- return zbudpage;
-}
-
-/* "Transform" a zbudpage back to a struct page suitable to free. */
-static inline struct page *zbud_unuse_zbudpage(struct zbudpage *zbudpage,
- bool eph)
-{
- struct page *page = (struct page *)zbudpage;
-
- BUG_ON(!list_empty(&zbudpage->budlist));
- BUG_ON(!list_empty(&zbudpage->lru));
- BUG_ON(zbudpage->zbud0_size != 0);
- BUG_ON(zbudpage->zbud1_size != 0);
- BUG_ON(!PageLocked(page));
- BUG_ON(zbudpage->unevictable != 0);
- BUG_ON(zbudpage_is_dying(zbudpage));
- BUG_ON(zbudpage_is_zombie(zbudpage));
- if (eph)
- zbud_eph_pageframes--;
- else
- zbud_pers_pageframes--;
- zbudpage_spin_unlock(zbudpage);
- page_mapcount_reset(page);
- init_page_count(page);
- page->index = 0;
- return page;
-}
-
-/* Mark a zbud as unused and do accounting */
-static inline void zbud_unuse_zbud(struct zbudpage *zbudpage,
- int budnum, bool eph)
-{
- unsigned size;
-
- BUG_ON(!zbudpage_is_locked(zbudpage));
- if (budnum == 0) {
- size = zbudpage->zbud0_size;
- zbudpage->zbud0_size = 0;
- } else {
- size = zbudpage->zbud1_size;
- zbudpage->zbud1_size = 0;
- }
- if (eph) {
- zbud_eph_zbytes -= size;
- zbud_eph_zpages--;
- } else {
- zbud_pers_zbytes -= size;
- zbud_pers_zpages--;
- }
-}
-
-/*
- * Given a zbudpage/budnum/size, a tmem handle, and a kmapped pointer
- * to some data, set up the zbud appropriately including data copying
- * and accounting. Note that if cdata is NULL, the data copying is
- * skipped. (This is useful for lazy writes such as for RAMster.)
- */
-static void zbud_init_zbud(struct zbudpage *zbudpage, struct tmem_handle *th,
- bool eph, void *cdata,
- unsigned budnum, unsigned size)
-{
- char *to;
- void *zbpg;
- struct tmem_handle *to_th;
- unsigned nchunks = zbud_size_to_chunks(size);
-
- BUG_ON(!zbudpage_is_locked(zbudpage));
- zbpg = kmap_zbudpage_atomic(zbudpage);
- to = zbud_data(zbpg, budnum, size);
- to_th = (struct tmem_handle *)to;
- to_th->index = th->index;
- to_th->oid = th->oid;
- to_th->pool_id = th->pool_id;
- to_th->client_id = th->client_id;
- to += sizeof(struct tmem_handle);
- if (cdata != NULL)
- memcpy(to, cdata, size - sizeof(struct tmem_handle));
- kunmap_zbudpage_atomic(zbpg);
- if (budnum == 0)
- zbudpage->zbud0_size = size;
- else
- zbudpage->zbud1_size = size;
- if (eph) {
- zbud_eph_cumul_chunk_counts[nchunks]++;
- zbud_eph_zpages++;
- zbud_eph_cumul_zpages++;
- zbud_eph_zbytes += size;
- zbud_eph_cumul_zbytes += size;
- } else {
- zbud_pers_cumul_chunk_counts[nchunks]++;
- zbud_pers_zpages++;
- zbud_pers_cumul_zpages++;
- zbud_pers_zbytes += size;
- zbud_pers_cumul_zbytes += size;
- }
-}
-
-/*
- * Given a locked dying zbudpage, read out the tmem handles from the data,
- * unlock the page, then use the handles to tell tmem to flush out its
- * references
- */
-static void zbud_evict_tmem(struct zbudpage *zbudpage)
-{
- int i, j;
- uint32_t pool_id[2], client_id[2];
- uint32_t index[2];
- struct tmem_oid oid[2];
- struct tmem_pool *pool;
- void *zbpg;
- struct tmem_handle *th;
- unsigned size;
-
- /* read out the tmem handles from the data and set aside */
- zbpg = kmap_zbudpage_atomic(zbudpage);
- for (i = 0, j = 0; i < 2; i++) {
- size = (i == 0) ? zbudpage->zbud0_size : zbudpage->zbud1_size;
- if (size) {
- th = (struct tmem_handle *)zbud_data(zbpg, i, size);
- client_id[j] = th->client_id;
- pool_id[j] = th->pool_id;
- oid[j] = th->oid;
- index[j] = th->index;
- j++;
- zbud_unuse_zbud(zbudpage, i, true);
- }
- }
- kunmap_zbudpage_atomic(zbpg);
- zbudpage_spin_unlock(zbudpage);
- /* zbudpage is now an unlocked dying... tell tmem to flush pointers */
- for (i = 0; i < j; i++) {
- pool = zcache_get_pool_by_id(client_id[i], pool_id[i]);
- if (pool != NULL) {
- tmem_flush_page(pool, &oid[i], index[i]);
- zcache_put_pool(pool);
- }
- }
-}
-
-/*
- * Externally callable zbud handling routines.
- */
-
-/*
- * Return the maximum size compressed page that can be stored (secretly
- * setting aside space for the tmem handle.
- */
-unsigned int zbud_max_buddy_size(void)
-{
- return zbud_max_size() - sizeof(struct tmem_handle);
-}
-
-/*
- * Given a zbud reference, free the corresponding zbud from all lists,
- * mark it as unused, do accounting, and if the freeing of the zbud
- * frees up an entire pageframe, return it to the caller (else NULL).
- */
-struct page *zbud_free_and_delist(struct zbudref *zref, bool eph,
- unsigned int *zsize, unsigned int *zpages)
-{
- unsigned long budnum = zbudref_budnum(zref);
- struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
- struct page *page = NULL;
- unsigned chunks, bud_size, other_bud_size;
- spinlock_t *lists_lock =
- eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
- struct zbud_unbuddied *unbud =
- eph ? zbud_eph_unbuddied : zbud_pers_unbuddied;
-
-
- spin_lock(lists_lock);
- zbudpage_spin_lock(zbudpage);
- if (zbudpage_is_dying(zbudpage)) {
- /* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
- zbudpage_spin_unlock(zbudpage);
- spin_unlock(lists_lock);
- *zpages = 0;
- *zsize = 0;
- goto out;
- }
- if (budnum == 0) {
- bud_size = zbudpage->zbud0_size;
- other_bud_size = zbudpage->zbud1_size;
- } else {
- bud_size = zbudpage->zbud1_size;
- other_bud_size = zbudpage->zbud0_size;
- }
- *zsize = bud_size - sizeof(struct tmem_handle);
- *zpages = 1;
- zbud_unuse_zbud(zbudpage, budnum, eph);
- if (other_bud_size == 0) { /* was unbuddied: unlist and free */
- chunks = zbud_size_to_chunks(bud_size) ;
- if (zbudpage_is_zombie(zbudpage)) {
- if (eph)
- zbud_pers_zombie_count =
- atomic_dec_return(&zbud_eph_zombie_atomic);
- else
- zbud_pers_zombie_count =
- atomic_dec_return(&zbud_pers_zombie_atomic);
- zbudpage_clear_zombie(zbudpage);
- } else {
- BUG_ON(list_empty(&unbud[chunks].list));
- list_del_init(&zbudpage->budlist);
- unbud[chunks].count--;
- }
- list_del_init(&zbudpage->lru);
- spin_unlock(lists_lock);
- if (eph)
- zbud_eph_unbuddied_count--;
- else
- zbud_pers_unbuddied_count--;
- page = zbud_unuse_zbudpage(zbudpage, eph);
- } else { /* was buddied: move remaining buddy to unbuddied list */
- chunks = zbud_size_to_chunks(other_bud_size) ;
- if (!zbudpage_is_zombie(zbudpage)) {
- list_del_init(&zbudpage->budlist);
- list_add_tail(&zbudpage->budlist, &unbud[chunks].list);
- unbud[chunks].count++;
- }
- if (eph) {
- zbud_eph_buddied_count--;
- zbud_eph_unbuddied_count++;
- } else {
- zbud_pers_unbuddied_count++;
- zbud_pers_buddied_count--;
- }
- /* don't mess with lru, no need to move it */
- zbudpage_spin_unlock(zbudpage);
- spin_unlock(lists_lock);
- }
-out:
- return page;
-}
-
-/*
- * Given a tmem handle, and a kmapped pointer to compressed data of
- * the given size, try to find an unbuddied zbudpage in which to
- * create a zbud. If found, put it there, mark the zbudpage unevictable,
- * and return a zbudref to it. Else return NULL.
- */
-struct zbudref *zbud_match_prep(struct tmem_handle *th, bool eph,
- void *cdata, unsigned size)
-{
- struct zbudpage *zbudpage = NULL, *zbudpage2;
- unsigned long budnum = 0UL;
- unsigned nchunks;
- int i, found_good_buddy = 0;
- spinlock_t *lists_lock =
- eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
- struct zbud_unbuddied *unbud =
- eph ? zbud_eph_unbuddied : zbud_pers_unbuddied;
-
- size += sizeof(struct tmem_handle);
- nchunks = zbud_size_to_chunks(size);
- for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) {
- spin_lock(lists_lock);
- if (!list_empty(&unbud[i].list)) {
- list_for_each_entry_safe(zbudpage, zbudpage2,
- &unbud[i].list, budlist) {
- if (zbudpage_spin_trylock(zbudpage)) {
- found_good_buddy = i;
- goto found_unbuddied;
- }
- }
- }
- spin_unlock(lists_lock);
- }
- zbudpage = NULL;
- goto out;
-
-found_unbuddied:
- BUG_ON(!zbudpage_is_locked(zbudpage));
- BUG_ON(!((zbudpage->zbud0_size == 0) ^ (zbudpage->zbud1_size == 0)));
- if (zbudpage->zbud0_size == 0)
- budnum = 0UL;
- else if (zbudpage->zbud1_size == 0)
- budnum = 1UL;
- list_del_init(&zbudpage->budlist);
- if (eph) {
- list_add_tail(&zbudpage->budlist, &zbud_eph_buddied_list);
- unbud[found_good_buddy].count--;
- zbud_eph_unbuddied_count--;
- zbud_eph_buddied_count++;
- /* "promote" raw zbudpage to most-recently-used */
- list_del_init(&zbudpage->lru);
- list_add_tail(&zbudpage->lru, &zbud_eph_lru_list);
- } else {
- list_add_tail(&zbudpage->budlist, &zbud_pers_buddied_list);
- unbud[found_good_buddy].count--;
- zbud_pers_unbuddied_count--;
- zbud_pers_buddied_count++;
- /* "promote" raw zbudpage to most-recently-used */
- list_del_init(&zbudpage->lru);
- list_add_tail(&zbudpage->lru, &zbud_pers_lru_list);
- }
- zbud_init_zbud(zbudpage, th, eph, cdata, budnum, size);
- zbudpage->unevictable++;
- BUG_ON(zbudpage->unevictable == 3);
- zbudpage_spin_unlock(zbudpage);
- spin_unlock(lists_lock);
-out:
- return zbudpage_to_zbudref(zbudpage, budnum);
-
-}
-
-/*
- * Given a tmem handle, and a kmapped pointer to compressed data of
- * the given size, and a newly allocated struct page, create an unevictable
- * zbud in that new page and return a zbudref to it.
- */
-struct zbudref *zbud_create_prep(struct tmem_handle *th, bool eph,
- void *cdata, unsigned size,
- struct page *newpage)
-{
- struct zbudpage *zbudpage;
- unsigned long budnum = 0;
- unsigned nchunks;
- spinlock_t *lists_lock =
- eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
- struct zbud_unbuddied *unbud =
- eph ? zbud_eph_unbuddied : zbud_pers_unbuddied;
-
-#if 0
- /* this may be worth it later to support decompress-in-place? */
- static unsigned long counter;
- budnum = counter++ & 1; /* alternate using zbud0 and zbud1 */
-#endif
-
- if (size > zbud_max_buddy_size())
- return NULL;
- if (newpage == NULL)
- return NULL;
-
- size += sizeof(struct tmem_handle);
- nchunks = zbud_size_to_chunks(size) ;
- spin_lock(lists_lock);
- zbudpage = zbud_init_zbudpage(newpage, eph);
- zbudpage_spin_lock(zbudpage);
- list_add_tail(&zbudpage->budlist, &unbud[nchunks].list);
- if (eph) {
- list_add_tail(&zbudpage->lru, &zbud_eph_lru_list);
- zbud_eph_unbuddied_count++;
- } else {
- list_add_tail(&zbudpage->lru, &zbud_pers_lru_list);
- zbud_pers_unbuddied_count++;
- }
- unbud[nchunks].count++;
- zbud_init_zbud(zbudpage, th, eph, cdata, budnum, size);
- zbudpage->unevictable++;
- BUG_ON(zbudpage->unevictable == 3);
- zbudpage_spin_unlock(zbudpage);
- spin_unlock(lists_lock);
- return zbudpage_to_zbudref(zbudpage, budnum);
-}
-
-/*
- * Finish creation of a zbud by, assuming another zbud isn't being created
- * in parallel, marking it evictable.
- */
-void zbud_create_finish(struct zbudref *zref, bool eph)
-{
- struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
- spinlock_t *lists_lock =
- eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-
- spin_lock(lists_lock);
- zbudpage_spin_lock(zbudpage);
- BUG_ON(zbudpage_is_dying(zbudpage));
- zbudpage->unevictable--;
- BUG_ON((int)zbudpage->unevictable < 0);
- zbudpage_spin_unlock(zbudpage);
- spin_unlock(lists_lock);
-}
-
-/*
- * Given a zbudref and a struct page, decompress the data from
- * the zbud into the physical page represented by the struct page
- * by upcalling to zcache_decompress
- */
-int zbud_decompress(struct page *data_page, struct zbudref *zref, bool eph,
- void (*decompress)(char *, unsigned int, char *))
-{
- struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
- unsigned long budnum = zbudref_budnum(zref);
- void *zbpg;
- char *to_va, *from_va;
- unsigned size;
- int ret = -1;
- spinlock_t *lists_lock =
- eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-
- spin_lock(lists_lock);
- zbudpage_spin_lock(zbudpage);
- if (zbudpage_is_dying(zbudpage)) {
- /* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
- goto out;
- }
- zbpg = kmap_zbudpage_atomic(zbudpage);
- to_va = kmap_atomic(data_page);
- if (budnum == 0)
- size = zbudpage->zbud0_size;
- else
- size = zbudpage->zbud1_size;
- BUG_ON(size == 0 || size > zbud_max_size());
- from_va = zbud_data(zbpg, budnum, size);
- from_va += sizeof(struct tmem_handle);
- size -= sizeof(struct tmem_handle);
- decompress(from_va, size, to_va);
- kunmap_atomic(to_va);
- kunmap_zbudpage_atomic(zbpg);
- ret = 0;
-out:
- zbudpage_spin_unlock(zbudpage);
- spin_unlock(lists_lock);
- return ret;
-}
-
-/*
- * Given a zbudref and a kernel pointer, copy the data from
- * the zbud to the kernel pointer.
- */
-int zbud_copy_from_zbud(char *to_va, struct zbudref *zref,
- size_t *sizep, bool eph)
-{
- struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
- unsigned long budnum = zbudref_budnum(zref);
- void *zbpg;
- char *from_va;
- unsigned size;
- int ret = -1;
- spinlock_t *lists_lock =
- eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-
- spin_lock(lists_lock);
- zbudpage_spin_lock(zbudpage);
- if (zbudpage_is_dying(zbudpage)) {
- /* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
- goto out;
- }
- zbpg = kmap_zbudpage_atomic(zbudpage);
- if (budnum == 0)
- size = zbudpage->zbud0_size;
- else
- size = zbudpage->zbud1_size;
- BUG_ON(size == 0 || size > zbud_max_size());
- from_va = zbud_data(zbpg, budnum, size);
- from_va += sizeof(struct tmem_handle);
- size -= sizeof(struct tmem_handle);
- *sizep = size;
- memcpy(to_va, from_va, size);
-
- kunmap_zbudpage_atomic(zbpg);
- ret = 0;
-out:
- zbudpage_spin_unlock(zbudpage);
- spin_unlock(lists_lock);
- return ret;
-}
-
-/*
- * Given a zbudref and a kernel pointer, copy the data from
- * the kernel pointer to the zbud.
- */
-int zbud_copy_to_zbud(struct zbudref *zref, char *from_va, bool eph)
-{
- struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
- unsigned long budnum = zbudref_budnum(zref);
- void *zbpg;
- char *to_va;
- unsigned size;
- int ret = -1;
- spinlock_t *lists_lock =
- eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-
- spin_lock(lists_lock);
- zbudpage_spin_lock(zbudpage);
- if (zbudpage_is_dying(zbudpage)) {
- /* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
- goto out;
- }
- zbpg = kmap_zbudpage_atomic(zbudpage);
- if (budnum == 0)
- size = zbudpage->zbud0_size;
- else
- size = zbudpage->zbud1_size;
- BUG_ON(size == 0 || size > zbud_max_size());
- to_va = zbud_data(zbpg, budnum, size);
- to_va += sizeof(struct tmem_handle);
- size -= sizeof(struct tmem_handle);
- memcpy(to_va, from_va, size);
-
- kunmap_zbudpage_atomic(zbpg);
- ret = 0;
-out:
- zbudpage_spin_unlock(zbudpage);
- spin_unlock(lists_lock);
- return ret;
-}
-
-/*
- * Choose an ephemeral LRU zbudpage that is evictable (not locked), ensure
- * there are no references to it remaining, and return the now unused
- * (and re-init'ed) struct page and the total amount of compressed
- * data that was evicted.
- */
-struct page *zbud_evict_pageframe_lru(unsigned int *zsize, unsigned int *zpages)
-{
- struct zbudpage *zbudpage = NULL, *zbudpage2;
- struct zbud_unbuddied *unbud = zbud_eph_unbuddied;
- struct page *page = NULL;
- bool irqs_disabled = irqs_disabled();
-
- /*
- * Since this can be called indirectly from cleancache_put, which
- * has interrupts disabled, as well as frontswap_put, which does not,
- * we need to be able to handle both cases, even though it is ugly.
- */
- if (irqs_disabled)
- spin_lock(&zbud_eph_lists_lock);
- else
- spin_lock_bh(&zbud_eph_lists_lock);
- *zsize = 0;
- if (list_empty(&zbud_eph_lru_list))
- goto unlock_out;
- list_for_each_entry_safe(zbudpage, zbudpage2, &zbud_eph_lru_list, lru) {
- /* skip a locked zbudpage */
- if (unlikely(!zbudpage_spin_trylock(zbudpage)))
- continue;
- /* skip an unevictable zbudpage */
- if (unlikely(zbudpage->unevictable != 0)) {
- zbudpage_spin_unlock(zbudpage);
- continue;
- }
- /* got a locked evictable page */
- goto evict_page;
-
- }
-unlock_out:
- /* no unlocked evictable pages, give up */
- if (irqs_disabled)
- spin_unlock(&zbud_eph_lists_lock);
- else
- spin_unlock_bh(&zbud_eph_lists_lock);
- goto out;
-
-evict_page:
- list_del_init(&zbudpage->budlist);
- list_del_init(&zbudpage->lru);
- zbudpage_set_dying(zbudpage);
- /*
- * the zbudpage is now "dying" and attempts to read, write,
- * or delete data from it will be ignored
- */
- if (zbudpage->zbud0_size != 0 && zbudpage->zbud1_size != 0) {
- *zsize = zbudpage->zbud0_size + zbudpage->zbud1_size -
- (2 * sizeof(struct tmem_handle));
- *zpages = 2;
- } else if (zbudpage->zbud0_size != 0) {
- unbud[zbud_size_to_chunks(zbudpage->zbud0_size)].count--;
- *zsize = zbudpage->zbud0_size - sizeof(struct tmem_handle);
- *zpages = 1;
- } else if (zbudpage->zbud1_size != 0) {
- unbud[zbud_size_to_chunks(zbudpage->zbud1_size)].count--;
- *zsize = zbudpage->zbud1_size - sizeof(struct tmem_handle);
- *zpages = 1;
- } else {
- BUG();
- }
- spin_unlock(&zbud_eph_lists_lock);
- zbud_eph_evicted_pageframes++;
- if (*zpages == 1)
- zbud_eph_unbuddied_count--;
- else
- zbud_eph_buddied_count--;
- zbud_evict_tmem(zbudpage);
- zbudpage_spin_lock(zbudpage);
- zbudpage_clear_dying(zbudpage);
- page = zbud_unuse_zbudpage(zbudpage, true);
- if (!irqs_disabled)
- local_bh_enable();
-out:
- return page;
-}
-
-/*
- * Choose a persistent LRU zbudpage that is evictable (not locked), zombify it,
- * read the tmem_handle(s) out of it into the passed array, and return the
- * number of zbuds. Caller must perform necessary tmem functions and,
- * indirectly, zbud functions to fetch any valid data and cause the
- * now-zombified zbudpage to eventually be freed. We track the zombified
- * zbudpage count so it is possible to observe if there is a leak.
- FIXME: describe (ramster) case where data pointers are passed in for memcpy
- */
-unsigned int zbud_make_zombie_lru(struct tmem_handle *th, unsigned char **data,
- unsigned int *zsize, bool eph)
-{
- struct zbudpage *zbudpage = NULL, *zbudpag2;
- struct tmem_handle *thfrom;
- char *from_va;
- void *zbpg;
- unsigned size;
- int ret = 0, i;
- spinlock_t *lists_lock =
- eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
- struct list_head *lru_list =
- eph ? &zbud_eph_lru_list : &zbud_pers_lru_list;
-
- spin_lock_bh(lists_lock);
- if (list_empty(lru_list))
- goto out;
- list_for_each_entry_safe(zbudpage, zbudpag2, lru_list, lru) {
- /* skip a locked zbudpage */
- if (unlikely(!zbudpage_spin_trylock(zbudpage)))
- continue;
- /* skip an unevictable zbudpage */
- if (unlikely(zbudpage->unevictable != 0)) {
- zbudpage_spin_unlock(zbudpage);
- continue;
- }
- /* got a locked evictable page */
- goto zombify_page;
- }
- /* no unlocked evictable pages, give up */
- goto out;
-
-zombify_page:
- /* got an unlocked evictable page, zombify it */
- list_del_init(&zbudpage->budlist);
- zbudpage_set_zombie(zbudpage);
- /* FIXME what accounting do I need to do here? */
- list_del_init(&zbudpage->lru);
- if (eph) {
- list_add_tail(&zbudpage->lru, &zbud_eph_zombie_list);
- zbud_eph_zombie_count =
- atomic_inc_return(&zbud_eph_zombie_atomic);
- } else {
- list_add_tail(&zbudpage->lru, &zbud_pers_zombie_list);
- zbud_pers_zombie_count =
- atomic_inc_return(&zbud_pers_zombie_atomic);
- }
- /* FIXME what accounting do I need to do here? */
- zbpg = kmap_zbudpage_atomic(zbudpage);
- for (i = 0; i < 2; i++) {
- size = (i == 0) ? zbudpage->zbud0_size : zbudpage->zbud1_size;
- if (size) {
- from_va = zbud_data(zbpg, i, size);
- thfrom = (struct tmem_handle *)from_va;
- from_va += sizeof(struct tmem_handle);
- size -= sizeof(struct tmem_handle);
- if (th != NULL)
- th[ret] = *thfrom;
- if (data != NULL)
- memcpy(data[ret], from_va, size);
- if (zsize != NULL)
- *zsize++ = size;
- ret++;
- }
- }
- kunmap_zbudpage_atomic(zbpg);
- zbudpage_spin_unlock(zbudpage);
-out:
- spin_unlock_bh(lists_lock);
- return ret;
-}
-
-void zbud_init(void)
-{
- int i;
-
- zbud_debugfs_init();
- BUG_ON((sizeof(struct tmem_handle) * 2 > CHUNK_SIZE));
- BUG_ON(sizeof(struct zbudpage) > sizeof(struct page));
- for (i = 0; i < NCHUNKS; i++) {
- INIT_LIST_HEAD(&zbud_eph_unbuddied[i].list);
- INIT_LIST_HEAD(&zbud_pers_unbuddied[i].list);
- }
-}
diff --git a/drivers/staging/zcache/zbud.h b/drivers/staging/zcache/zbud.h
deleted file mode 100644
index 891e8a7d5aa..00000000000
--- a/drivers/staging/zcache/zbud.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * zbud.h
- *
- * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
- *
- */
-
-#ifndef _ZBUD_H_
-#define _ZBUD_H_
-
-#include "tmem.h"
-
-struct zbudref;
-
-extern unsigned int zbud_max_buddy_size(void);
-extern struct zbudref *zbud_match_prep(struct tmem_handle *th, bool eph,
- void *cdata, unsigned size);
-extern struct zbudref *zbud_create_prep(struct tmem_handle *th, bool eph,
- void *cdata, unsigned size,
- struct page *newpage);
-extern void zbud_create_finish(struct zbudref *, bool);
-extern int zbud_decompress(struct page *, struct zbudref *, bool,
- void (*func)(char *, unsigned int, char *));
-extern int zbud_copy_from_zbud(char *, struct zbudref *, size_t *, bool);
-extern int zbud_copy_to_zbud(struct zbudref *, char *, bool);
-extern struct page *zbud_free_and_delist(struct zbudref *, bool eph,
- unsigned int *, unsigned int *);
-extern struct page *zbud_evict_pageframe_lru(unsigned int *, unsigned int *);
-extern unsigned int zbud_make_zombie_lru(struct tmem_handle *, unsigned char **,
- unsigned int *, bool);
-extern void zbud_init(void);
-
-#endif /* _ZBUD_H_ */
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
deleted file mode 100644
index dcceed29d31..00000000000
--- a/drivers/staging/zcache/zcache-main.c
+++ /dev/null
@@ -1,1941 +0,0 @@
-/*
- * zcache.c
- *
- * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
- * Copyright (c) 2010,2011, Nitin Gupta
- *
- * Zcache provides an in-kernel "host implementation" for transcendent memory
- * ("tmem") and, thus indirectly, for cleancache and frontswap. Zcache uses
- * lzo1x compression to improve density and an embedded allocator called
- * "zbud" which "buddies" two compressed pages semi-optimally in each physical
- * pageframe. Zbud is integrally tied into tmem to allow pageframes to
- * be "reclaimed" efficiently.
- */
-
-#include <linux/module.h>
-#include <linux/cpu.h>
-#include <linux/highmem.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/atomic.h>
-#include <linux/math64.h>
-#include <linux/crypto.h>
-#include <linux/swap.h>
-#include <linux/swapops.h>
-#include <linux/pagemap.h>
-#include <linux/writeback.h>
-
-#include <linux/cleancache.h>
-#include <linux/frontswap.h>
-#include "tmem.h"
-#include "zcache.h"
-#include "zbud.h"
-#include "ramster.h"
-#include "debug.h"
-#ifdef CONFIG_RAMSTER
-static bool ramster_enabled __read_mostly;
-static int disable_frontswap_selfshrink;
-#else
-#define ramster_enabled false
-#define disable_frontswap_selfshrink 0
-#endif
-
-#ifndef __PG_WAS_ACTIVE
-static inline bool PageWasActive(struct page *page)
-{
- return true;
-}
-
-static inline void SetPageWasActive(struct page *page)
-{
-}
-#endif
-
-#ifdef FRONTSWAP_HAS_EXCLUSIVE_GETS
-static bool frontswap_has_exclusive_gets __read_mostly = true;
-#else
-static bool frontswap_has_exclusive_gets __read_mostly;
-static inline void frontswap_tmem_exclusive_gets(bool b)
-{
-}
-#endif
-
-/*
- * mark pampd to special value in order that later
- * retrieve will identify zero-filled pages
- */
-#define ZERO_FILLED 0x2
-
-/* enable (or fix code) when Seth's patches are accepted upstream */
-#define zcache_writeback_enabled 0
-
-static bool zcache_enabled __read_mostly;
-static bool disable_cleancache __read_mostly;
-static bool disable_frontswap __read_mostly;
-static bool disable_frontswap_ignore_nonactive __read_mostly;
-static bool disable_cleancache_ignore_nonactive __read_mostly;
-static char *namestr __read_mostly = "zcache";
-
-#define ZCACHE_GFP_MASK \
- (__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC)
-
-/* crypto API for zcache */
-#ifdef CONFIG_ZCACHE_MODULE
-static char *zcache_comp_name = "lzo";
-#else
-#define ZCACHE_COMP_NAME_SZ CRYPTO_MAX_ALG_NAME
-static char zcache_comp_name[ZCACHE_COMP_NAME_SZ] __read_mostly;
-#endif
-static struct crypto_comp * __percpu *zcache_comp_pcpu_tfms __read_mostly;
-
-enum comp_op {
- ZCACHE_COMPOP_COMPRESS,
- ZCACHE_COMPOP_DECOMPRESS
-};
-
-static inline int zcache_comp_op(enum comp_op op,
- const u8 *src, unsigned int slen,
- u8 *dst, unsigned int *dlen)
-{
- struct crypto_comp *tfm;
- int ret = -1;
-
- BUG_ON(!zcache_comp_pcpu_tfms);
- tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, get_cpu());
- BUG_ON(!tfm);
- switch (op) {
- case ZCACHE_COMPOP_COMPRESS:
- ret = crypto_comp_compress(tfm, src, slen, dst, dlen);
- break;
- case ZCACHE_COMPOP_DECOMPRESS:
- ret = crypto_comp_decompress(tfm, src, slen, dst, dlen);
- break;
- default:
- ret = -EINVAL;
- }
- put_cpu();
- return ret;
-}
-
-/*
- * policy parameters
- */
-
-/*
- * byte count defining poor compression; pages with greater zsize will be
- * rejected
- */
-static unsigned int zbud_max_zsize __read_mostly = (PAGE_SIZE / 8) * 7;
-/*
- * byte count defining poor *mean* compression; pages with greater zsize
- * will be rejected until sufficient better-compressed pages are accepted
- * driving the mean below this threshold
- */
-static unsigned int zbud_max_mean_zsize __read_mostly = (PAGE_SIZE / 8) * 5;
-
-/*
- * for now, used named slabs so can easily track usage; later can
- * either just use kmalloc, or perhaps add a slab-like allocator
- * to more carefully manage total memory utilization
- */
-static struct kmem_cache *zcache_objnode_cache;
-static struct kmem_cache *zcache_obj_cache;
-
-static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, };
-
-/* Used by debug.c */
-ssize_t zcache_pers_zpages;
-u64 zcache_pers_zbytes;
-ssize_t zcache_eph_pageframes;
-ssize_t zcache_pers_pageframes;
-
-/* Used by this code. */
-ssize_t zcache_last_active_file_pageframes;
-ssize_t zcache_last_inactive_file_pageframes;
-ssize_t zcache_last_active_anon_pageframes;
-ssize_t zcache_last_inactive_anon_pageframes;
-#ifdef CONFIG_ZCACHE_WRITEBACK
-ssize_t zcache_writtenback_pages;
-ssize_t zcache_outstanding_writeback_pages;
-#endif
-/*
- * zcache core code starts here
- */
-
-static struct zcache_client zcache_host;
-static struct zcache_client zcache_clients[MAX_CLIENTS];
-
-static inline bool is_local_client(struct zcache_client *cli)
-{
- return cli == &zcache_host;
-}
-
-static struct zcache_client *zcache_get_client_by_id(uint16_t cli_id)
-{
- struct zcache_client *cli = &zcache_host;
-
- if (cli_id != LOCAL_CLIENT) {
- if (cli_id >= MAX_CLIENTS)
- goto out;
- cli = &zcache_clients[cli_id];
- }
-out:
- return cli;
-}
-
-/*
- * Tmem operations assume the poolid implies the invoking client.
- * Zcache only has one client (the kernel itself): LOCAL_CLIENT.
- * RAMster has each client numbered by cluster node, and a KVM version
- * of zcache would have one client per guest and each client might
- * have a poolid==N.
- */
-struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid)
-{
- struct tmem_pool *pool = NULL;
- struct zcache_client *cli = NULL;
-
- cli = zcache_get_client_by_id(cli_id);
- if (cli == NULL)
- goto out;
- if (!is_local_client(cli))
- atomic_inc(&cli->refcount);
- if (poolid < MAX_POOLS_PER_CLIENT) {
- pool = cli->tmem_pools[poolid];
- if (pool != NULL)
- atomic_inc(&pool->refcount);
- }
-out:
- return pool;
-}
-
-void zcache_put_pool(struct tmem_pool *pool)
-{
- struct zcache_client *cli = NULL;
-
- if (pool == NULL)
- BUG();
- cli = pool->client;
- atomic_dec(&pool->refcount);
- if (!is_local_client(cli))
- atomic_dec(&cli->refcount);
-}
-
-int zcache_new_client(uint16_t cli_id)
-{
- struct zcache_client *cli;
- int ret = -1;
-
- cli = zcache_get_client_by_id(cli_id);
- if (cli == NULL)
- goto out;
- if (cli->allocated)
- goto out;
- cli->allocated = 1;
- ret = 0;
-out:
- return ret;
-}
-
-/*
- * zcache implementation for tmem host ops
- */
-
-static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool)
-{
- struct tmem_objnode *objnode = NULL;
- struct zcache_preload *kp;
- int i;
-
- kp = &__get_cpu_var(zcache_preloads);
- for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) {
- objnode = kp->objnodes[i];
- if (objnode != NULL) {
- kp->objnodes[i] = NULL;
- break;
- }
- }
- BUG_ON(objnode == NULL);
- inc_zcache_objnode_count();
- return objnode;
-}
-
-static void zcache_objnode_free(struct tmem_objnode *objnode,
- struct tmem_pool *pool)
-{
- dec_zcache_objnode_count();
- kmem_cache_free(zcache_objnode_cache, objnode);
-}
-
-static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool)
-{
- struct tmem_obj *obj = NULL;
- struct zcache_preload *kp;
-
- kp = &__get_cpu_var(zcache_preloads);
- obj = kp->obj;
- BUG_ON(obj == NULL);
- kp->obj = NULL;
- inc_zcache_obj_count();
- return obj;
-}
-
-static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool)
-{
- dec_zcache_obj_count();
- kmem_cache_free(zcache_obj_cache, obj);
-}
-
-/*
- * Compressing zero-filled pages will waste memory and introduce
- * serious fragmentation, skip it to avoid overhead.
- */
-static bool page_is_zero_filled(struct page *p)
-{
- unsigned int pos;
- char *page;
-
- page = kmap_atomic(p);
- for (pos = 0; pos < PAGE_SIZE / sizeof(*page); pos++) {
- if (page[pos]) {
- kunmap_atomic(page);
- return false;
- }
- }
- kunmap_atomic(page);
-
- return true;
-}
-
-static void handle_zero_filled_page(void *p)
-{
- void *user_mem;
- struct page *page = (struct page *)p;
-
- user_mem = kmap_atomic(page);
- memset(user_mem, 0, PAGE_SIZE);
- kunmap_atomic(user_mem);
-
- flush_dcache_page(page);
-}
-
-static struct tmem_hostops zcache_hostops = {
- .obj_alloc = zcache_obj_alloc,
- .obj_free = zcache_obj_free,
- .objnode_alloc = zcache_objnode_alloc,
- .objnode_free = zcache_objnode_free,
-};
-
-static struct page *zcache_alloc_page(void)
-{
- struct page *page = alloc_page(ZCACHE_GFP_MASK);
-
- if (page != NULL)
- inc_zcache_pageframes_alloced();
- return page;
-}
-
-static void zcache_free_page(struct page *page)
-{
- long curr_pageframes;
- static long max_pageframes, min_pageframes;
-
- if (page == NULL)
- BUG();
- __free_page(page);
- inc_zcache_pageframes_freed();
- curr_pageframes = curr_pageframes_count();
- if (curr_pageframes > max_pageframes)
- max_pageframes = curr_pageframes;
- if (curr_pageframes < min_pageframes)
- min_pageframes = curr_pageframes;
-#ifdef CONFIG_ZCACHE_DEBUG
- if (curr_pageframes > 2L || curr_pageframes < -2L) {
- /* pr_info here */
- }
-#endif
-}
-
-/*
- * zcache implementations for PAM page descriptor ops
- */
-
-/* forward reference */
-static void zcache_compress(struct page *from,
- void **out_va, unsigned *out_len);
-
-static struct page *zcache_evict_eph_pageframe(void);
-
-static void *zcache_pampd_eph_create(char *data, size_t size, bool raw,
- struct tmem_handle *th)
-{
- void *pampd = NULL, *cdata = data;
- unsigned clen = size;
- bool zero_filled = false;
- struct page *page = (struct page *)(data), *newpage;
-
- if (page_is_zero_filled(page)) {
- clen = 0;
- zero_filled = true;
- inc_zcache_zero_filled_pages();
- goto got_pampd;
- }
-
- if (!raw) {
- zcache_compress(page, &cdata, &clen);
- if (clen > zbud_max_buddy_size()) {
- inc_zcache_compress_poor();
- goto out;
- }
- } else {
- BUG_ON(clen > zbud_max_buddy_size());
- }
-
- /* look for space via an existing match first */
- pampd = (void *)zbud_match_prep(th, true, cdata, clen);
- if (pampd != NULL)
- goto got_pampd;
-
- /* no match, now we need to find (or free up) a full page */
- newpage = zcache_alloc_page();
- if (newpage != NULL)
- goto create_in_new_page;
-
- inc_zcache_failed_getfreepages();
- /* can't allocate a page, evict an ephemeral page via LRU */
- newpage = zcache_evict_eph_pageframe();
- if (newpage == NULL) {
- inc_zcache_eph_ate_tail_failed();
- goto out;
- }
- inc_zcache_eph_ate_tail();
-
-create_in_new_page:
- pampd = (void *)zbud_create_prep(th, true, cdata, clen, newpage);
- BUG_ON(pampd == NULL);
- inc_zcache_eph_pageframes();
-
-got_pampd:
- inc_zcache_eph_zbytes(clen);
- inc_zcache_eph_zpages();
- if (ramster_enabled && raw && !zero_filled)
- ramster_count_foreign_pages(true, 1);
- if (zero_filled)
- pampd = (void *)ZERO_FILLED;
-out:
- return pampd;
-}
-
-static void *zcache_pampd_pers_create(char *data, size_t size, bool raw,
- struct tmem_handle *th)
-{
- void *pampd = NULL, *cdata = data;
- unsigned clen = size;
- bool zero_filled = false;
- struct page *page = (struct page *)(data), *newpage;
- unsigned long zbud_mean_zsize;
- unsigned long curr_pers_zpages, total_zsize;
-
- if (data == NULL) {
- BUG_ON(!ramster_enabled);
- goto create_pampd;
- }
-
- if (page_is_zero_filled(page)) {
- clen = 0;
- zero_filled = true;
- inc_zcache_zero_filled_pages();
- goto got_pampd;
- }
-
- curr_pers_zpages = zcache_pers_zpages;
-/* FIXME CONFIG_RAMSTER... subtract atomic remote_pers_pages here? */
- if (!raw)
- zcache_compress(page, &cdata, &clen);
- /* reject if compression is too poor */
- if (clen > zbud_max_zsize) {
- inc_zcache_compress_poor();
- goto out;
- }
- /* reject if mean compression is too poor */
- if ((clen > zbud_max_mean_zsize) && (curr_pers_zpages > 0)) {
- total_zsize = zcache_pers_zbytes;
- if ((long)total_zsize < 0)
- total_zsize = 0;
- zbud_mean_zsize = div_u64(total_zsize,
- curr_pers_zpages);
- if (zbud_mean_zsize > zbud_max_mean_zsize) {
- inc_zcache_mean_compress_poor();
- goto out;
- }
- }
-
-create_pampd:
- /* look for space via an existing match first */
- pampd = (void *)zbud_match_prep(th, false, cdata, clen);
- if (pampd != NULL)
- goto got_pampd;
-
- /* no match, now we need to find (or free up) a full page */
- newpage = zcache_alloc_page();
- if (newpage != NULL)
- goto create_in_new_page;
- /*
- * FIXME do the following only if eph is oversized?
- * if (zcache_eph_pageframes >
- * (global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE) +
- * global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE)))
- */
- inc_zcache_failed_getfreepages();
- /* can't allocate a page, evict an ephemeral page via LRU */
- newpage = zcache_evict_eph_pageframe();
- if (newpage == NULL) {
- inc_zcache_pers_ate_eph_failed();
- goto out;
- }
- inc_zcache_pers_ate_eph();
-
-create_in_new_page:
- pampd = (void *)zbud_create_prep(th, false, cdata, clen, newpage);
- BUG_ON(pampd == NULL);
- inc_zcache_pers_pageframes();
-
-got_pampd:
- inc_zcache_pers_zpages();
- inc_zcache_pers_zbytes(clen);
- if (ramster_enabled && raw && !zero_filled)
- ramster_count_foreign_pages(false, 1);
- if (zero_filled)
- pampd = (void *)ZERO_FILLED;
-out:
- return pampd;
-}
-
-/*
- * This is called directly from zcache_put_page to pre-allocate space
- * to store a zpage.
- */
-void *zcache_pampd_create(char *data, unsigned int size, bool raw,
- int eph, struct tmem_handle *th)
-{
- void *pampd = NULL;
- struct zcache_preload *kp;
- struct tmem_objnode *objnode;
- struct tmem_obj *obj;
- int i;
-
- BUG_ON(!irqs_disabled());
- /* pre-allocate per-cpu metadata */
- BUG_ON(zcache_objnode_cache == NULL);
- BUG_ON(zcache_obj_cache == NULL);
- kp = &__get_cpu_var(zcache_preloads);
- for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) {
- objnode = kp->objnodes[i];
- if (objnode == NULL) {
- objnode = kmem_cache_alloc(zcache_objnode_cache,
- ZCACHE_GFP_MASK);
- if (unlikely(objnode == NULL)) {
- inc_zcache_failed_alloc();
- goto out;
- }
- kp->objnodes[i] = objnode;
- }
- }
- if (kp->obj == NULL) {
- obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK);
- kp->obj = obj;
- }
- if (unlikely(kp->obj == NULL)) {
- inc_zcache_failed_alloc();
- goto out;
- }
- /*
- * ok, have all the metadata pre-allocated, now do the data
- * but since how we allocate the data is dependent on ephemeral
- * or persistent, we split the call here to different sub-functions
- */
- if (eph)
- pampd = zcache_pampd_eph_create(data, size, raw, th);
- else
- pampd = zcache_pampd_pers_create(data, size, raw, th);
-out:
- return pampd;
-}
-
-/*
- * This is a pamops called via tmem_put and is necessary to "finish"
- * a pampd creation.
- */
-void zcache_pampd_create_finish(void *pampd, bool eph)
-{
- if (pampd != (void *)ZERO_FILLED)
- zbud_create_finish((struct zbudref *)pampd, eph);
-}
-
-/*
- * This is passed as a function parameter to zbud_decompress so that
- * zbud need not be familiar with the details of crypto. It assumes that
- * the bytes from_va and to_va through from_va+size-1 and to_va+size-1 are
- * kmapped. It must be successful, else there is a logic bug somewhere.
- */
-static void zcache_decompress(char *from_va, unsigned int size, char *to_va)
-{
- int ret;
- unsigned int outlen = PAGE_SIZE;
-
- ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, from_va, size,
- to_va, &outlen);
- BUG_ON(ret);
- BUG_ON(outlen != PAGE_SIZE);
-}
-
-/*
- * Decompress from the kernel va to a pageframe
- */
-void zcache_decompress_to_page(char *from_va, unsigned int size,
- struct page *to_page)
-{
- char *to_va = kmap_atomic(to_page);
- zcache_decompress(from_va, size, to_va);
- kunmap_atomic(to_va);
-}
-
-/*
- * fill the pageframe corresponding to the struct page with the data
- * from the passed pampd
- */
-static int zcache_pampd_get_data(char *data, size_t *sizep, bool raw,
- void *pampd, struct tmem_pool *pool,
- struct tmem_oid *oid, uint32_t index)
-{
- int ret;
- bool eph = !is_persistent(pool);
-
- BUG_ON(preemptible());
- BUG_ON(eph); /* fix later if shared pools get implemented */
- BUG_ON(pampd_is_remote(pampd));
-
- if (pampd == (void *)ZERO_FILLED) {
- handle_zero_filled_page(data);
- if (!raw)
- *sizep = PAGE_SIZE;
- return 0;
- }
-
- if (raw)
- ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd,
- sizep, eph);
- else {
- ret = zbud_decompress((struct page *)(data),
- (struct zbudref *)pampd, false,
- zcache_decompress);
- *sizep = PAGE_SIZE;
- }
- return ret;
-}
-
-/*
- * fill the pageframe corresponding to the struct page with the data
- * from the passed pampd
- */
-static int zcache_pampd_get_data_and_free(char *data, size_t *sizep, bool raw,
- void *pampd, struct tmem_pool *pool,
- struct tmem_oid *oid, uint32_t index)
-{
- int ret = 0;
- bool eph = !is_persistent(pool), zero_filled = false;
- struct page *page = NULL;
- unsigned int zsize, zpages;
-
- BUG_ON(preemptible());
- BUG_ON(pampd_is_remote(pampd));
-
- if (pampd == (void *)ZERO_FILLED) {
- handle_zero_filled_page(data);
- zero_filled = true;
- zsize = 0;
- zpages = 1;
- if (!raw)
- *sizep = PAGE_SIZE;
- dec_zcache_zero_filled_pages();
- goto zero_fill;
- }
-
- if (raw)
- ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd,
- sizep, eph);
- else {
- ret = zbud_decompress((struct page *)(data),
- (struct zbudref *)pampd, eph,
- zcache_decompress);
- *sizep = PAGE_SIZE;
- }
- page = zbud_free_and_delist((struct zbudref *)pampd, eph,
- &zsize, &zpages);
-zero_fill:
- if (eph) {
- if (page)
- dec_zcache_eph_pageframes();
- dec_zcache_eph_zpages(zpages);
- dec_zcache_eph_zbytes(zsize);
- } else {
- if (page)
- dec_zcache_pers_pageframes();
- dec_zcache_pers_zpages(zpages);
- dec_zcache_pers_zbytes(zsize);
- }
- if (!is_local_client(pool->client) && !zero_filled)
- ramster_count_foreign_pages(eph, -1);
- if (page && !zero_filled)
- zcache_free_page(page);
- return ret;
-}
-
-/*
- * free the pampd and remove it from any zcache lists
- * pampd must no longer be pointed to from any tmem data structures!
- */
-static void zcache_pampd_free(void *pampd, struct tmem_pool *pool,
- struct tmem_oid *oid, uint32_t index, bool acct)
-{
- struct page *page = NULL;
- unsigned int zsize, zpages;
- bool zero_filled = false;
-
- BUG_ON(preemptible());
-
- if (pampd == (void *)ZERO_FILLED) {
- zero_filled = true;
- zsize = 0;
- zpages = 1;
- dec_zcache_zero_filled_pages();
- }
-
- if (pampd_is_remote(pampd) && !zero_filled) {
- BUG_ON(!ramster_enabled);
- pampd = ramster_pampd_free(pampd, pool, oid, index, acct);
- if (pampd == NULL)
- return;
- }
- if (is_ephemeral(pool)) {
- if (!zero_filled)
- page = zbud_free_and_delist((struct zbudref *)pampd,
- true, &zsize, &zpages);
- if (page)
- dec_zcache_eph_pageframes();
- dec_zcache_eph_zpages(zpages);
- dec_zcache_eph_zbytes(zsize);
- /* FIXME CONFIG_RAMSTER... check acct parameter? */
- } else {
- if (!zero_filled)
- page = zbud_free_and_delist((struct zbudref *)pampd,
- false, &zsize, &zpages);
- if (page)
- dec_zcache_pers_pageframes();
- dec_zcache_pers_zpages(zpages);
- dec_zcache_pers_zbytes(zsize);
- }
- if (!is_local_client(pool->client) && !zero_filled)
- ramster_count_foreign_pages(is_ephemeral(pool), -1);
- if (page && !zero_filled)
- zcache_free_page(page);
-}
-
-static struct tmem_pamops zcache_pamops = {
- .create_finish = zcache_pampd_create_finish,
- .get_data = zcache_pampd_get_data,
- .get_data_and_free = zcache_pampd_get_data_and_free,
- .free = zcache_pampd_free,
-};
-
-/*
- * zcache compression/decompression and related per-cpu stuff
- */
-
-static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
-#define ZCACHE_DSTMEM_ORDER 1
-
-static void zcache_compress(struct page *from, void **out_va, unsigned *out_len)
-{
- int ret;
- unsigned char *dmem = __get_cpu_var(zcache_dstmem);
- char *from_va;
-
- BUG_ON(!irqs_disabled());
- /* no buffer or no compressor so can't compress */
- BUG_ON(dmem == NULL);
- *out_len = PAGE_SIZE << ZCACHE_DSTMEM_ORDER;
- from_va = kmap_atomic(from);
- mb();
- ret = zcache_comp_op(ZCACHE_COMPOP_COMPRESS, from_va, PAGE_SIZE, dmem,
- out_len);
- BUG_ON(ret);
- *out_va = dmem;
- kunmap_atomic(from_va);
-}
-
-static int zcache_comp_cpu_up(int cpu)
-{
- struct crypto_comp *tfm;
-
- tfm = crypto_alloc_comp(zcache_comp_name, 0, 0);
- if (IS_ERR(tfm))
- return NOTIFY_BAD;
- *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = tfm;
- return NOTIFY_OK;
-}
-
-static void zcache_comp_cpu_down(int cpu)
-{
- struct crypto_comp *tfm;
-
- tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu);
- crypto_free_comp(tfm);
- *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = NULL;
-}
-
-static int zcache_cpu_notifier(struct notifier_block *nb,
- unsigned long action, void *pcpu)
-{
- int ret, i, cpu = (long)pcpu;
- struct zcache_preload *kp;
-
- switch (action) {
- case CPU_UP_PREPARE:
- ret = zcache_comp_cpu_up(cpu);
- if (ret != NOTIFY_OK) {
- pr_err("%s: can't allocate compressor xform\n",
- namestr);
- return ret;
- }
- per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
- GFP_KERNEL | __GFP_REPEAT, ZCACHE_DSTMEM_ORDER);
- if (ramster_enabled)
- ramster_cpu_up(cpu);
- break;
- case CPU_DEAD:
- case CPU_UP_CANCELED:
- zcache_comp_cpu_down(cpu);
- free_pages((unsigned long)per_cpu(zcache_dstmem, cpu),
- ZCACHE_DSTMEM_ORDER);
- per_cpu(zcache_dstmem, cpu) = NULL;
- kp = &per_cpu(zcache_preloads, cpu);
- for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) {
- if (kp->objnodes[i])
- kmem_cache_free(zcache_objnode_cache,
- kp->objnodes[i]);
- }
- if (kp->obj) {
- kmem_cache_free(zcache_obj_cache, kp->obj);
- kp->obj = NULL;
- }
- if (ramster_enabled)
- ramster_cpu_down(cpu);
- break;
- default:
- break;
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block zcache_cpu_notifier_block = {
- .notifier_call = zcache_cpu_notifier
-};
-
-/*
- * The following code interacts with the zbud eviction and zbud
- * zombify code to access LRU pages
- */
-
-static struct page *zcache_evict_eph_pageframe(void)
-{
- struct page *page;
- unsigned int zsize = 0, zpages = 0;
-
- page = zbud_evict_pageframe_lru(&zsize, &zpages);
- if (page == NULL)
- goto out;
- dec_zcache_eph_zbytes(zsize);
- dec_zcache_eph_zpages(zpages);
- inc_zcache_evicted_eph_zpages(zpages);
- dec_zcache_eph_pageframes();
- inc_zcache_evicted_eph_pageframes();
-out:
- return page;
-}
-
-#ifdef CONFIG_ZCACHE_WRITEBACK
-
-static atomic_t zcache_outstanding_writeback_pages_atomic = ATOMIC_INIT(0);
-
-static inline void inc_zcache_outstanding_writeback_pages(void)
-{
- zcache_outstanding_writeback_pages =
- atomic_inc_return(&zcache_outstanding_writeback_pages_atomic);
-}
-static inline void dec_zcache_outstanding_writeback_pages(void)
-{
- zcache_outstanding_writeback_pages =
- atomic_dec_return(&zcache_outstanding_writeback_pages_atomic);
-};
-static void unswiz(struct tmem_oid oid, u32 index,
- unsigned *type, pgoff_t *offset);
-
-/*
- * Choose an LRU persistent pageframe and attempt to write it back to
- * the backing swap disk by calling frontswap_writeback on both zpages.
- *
- * This is work-in-progress.
- */
-
-static void zcache_end_swap_write(struct bio *bio, int err)
-{
- end_swap_bio_write(bio, err);
- dec_zcache_outstanding_writeback_pages();
- zcache_writtenback_pages++;
-}
-
-/*
- * zcache_get_swap_cache_page
- *
- * This is an adaption of read_swap_cache_async()
- *
- * If success, page is returned in retpage
- * Returns 0 if page was already in the swap cache, page is not locked
- * Returns 1 if the new page needs to be populated, page is locked
- */
-static int zcache_get_swap_cache_page(int type, pgoff_t offset,
- struct page *new_page)
-{
- struct page *found_page;
- swp_entry_t entry = swp_entry(type, offset);
- int err;
-
- BUG_ON(new_page == NULL);
- do {
- /*
- * First check the swap cache. Since this is normally
- * called after lookup_swap_cache() failed, re-calling
- * that would confuse statistics.
- */
- found_page = find_get_page(&swapper_space, entry.val);
- if (found_page)
- return 0;
-
- /*
- * call radix_tree_preload() while we can wait.
- */
- err = radix_tree_preload(GFP_KERNEL);
- if (err)
- break;
-
- /*
- * Swap entry may have been freed since our caller observed it.
- */
- err = swapcache_prepare(entry);
- if (err == -EEXIST) { /* seems racy */
- radix_tree_preload_end();
- continue;
- }
- if (err) { /* swp entry is obsolete ? */
- radix_tree_preload_end();
- break;
- }
-
- /* May fail (-ENOMEM) if radix-tree node allocation failed. */
- __set_page_locked(new_page);
- SetPageSwapBacked(new_page);
- err = __add_to_swap_cache(new_page, entry);
- if (likely(!err)) {
- radix_tree_preload_end();
- lru_cache_add_anon(new_page);
- return 1;
- }
- radix_tree_preload_end();
- ClearPageSwapBacked(new_page);
- __clear_page_locked(new_page);
- /*
- * add_to_swap_cache() doesn't return -EEXIST, so we can safely
- * clear SWAP_HAS_CACHE flag.
- */
- swapcache_free(entry, NULL);
- /* FIXME: is it possible to get here without err==-ENOMEM?
- * If not, we can dispense with the do loop, use goto retry */
- } while (err != -ENOMEM);
-
- return -ENOMEM;
-}
-
-/*
- * Given a frontswap zpage in zcache (identified by type/offset) and
- * an empty page, put the page into the swap cache, use frontswap
- * to get the page from zcache into the empty page, then give it
- * to the swap subsystem to send to disk (carefully avoiding the
- * possibility that frontswap might snatch it back).
- * Returns < 0 if error, 0 if successful, and 1 if successful but
- * the newpage passed in not needed and should be freed.
- */
-static int zcache_frontswap_writeback_zpage(int type, pgoff_t offset,
- struct page *newpage)
-{
- struct page *page = newpage;
- int ret;
- struct writeback_control wbc = {
- .sync_mode = WB_SYNC_NONE,
- };
-
- ret = zcache_get_swap_cache_page(type, offset, page);
- if (ret < 0)
- return ret;
- else if (ret == 0) {
- /* more uptodate page is already in swapcache */
- __frontswap_invalidate_page(type, offset);
- return 1;
- }
-
- BUG_ON(!frontswap_has_exclusive_gets); /* load must also invalidate */
- /* FIXME: how is it possible to get here when page is unlocked? */
- __frontswap_load(page);
- SetPageUptodate(page); /* above does SetPageDirty, is that enough? */
-
- /* start writeback */
- SetPageReclaim(page);
- /*
- * Return value is ignored here because it doesn't change anything
- * for us. Page is returned unlocked.
- */
- (void)__swap_writepage(page, &wbc, zcache_end_swap_write);
- page_cache_release(page);
- inc_zcache_outstanding_writeback_pages();
-
- return 0;
-}
-
-/*
- * The following is still a magic number... we want to allow forward progress
- * for writeback because it clears out needed RAM when under pressure, but
- * we don't want to allow writeback to absorb and queue too many GFP_KERNEL
- * pages if the swap device is very slow.
- */
-#define ZCACHE_MAX_OUTSTANDING_WRITEBACK_PAGES 6400
-
-/*
- * Try to allocate two free pages, first using a non-aggressive alloc,
- * then by evicting zcache ephemeral (clean pagecache) pages, and last
- * by aggressive GFP_KERNEL alloc. We allow zbud to choose a pageframe
- * consisting of 1-2 zbuds/zpages, then call the writeback_zpage helper
- * function above for each.
- */
-static int zcache_frontswap_writeback(void)
-{
- struct tmem_handle th[2];
- int ret = 0;
- int nzbuds, writeback_ret;
- unsigned type;
- struct page *znewpage1 = NULL, *znewpage2 = NULL;
- struct page *evictpage1 = NULL, *evictpage2 = NULL;
- struct page *newpage1 = NULL, *newpage2 = NULL;
- struct page *page1 = NULL, *page2 = NULL;
- pgoff_t offset;
-
- znewpage1 = alloc_page(ZCACHE_GFP_MASK);
- znewpage2 = alloc_page(ZCACHE_GFP_MASK);
- if (znewpage1 == NULL)
- evictpage1 = zcache_evict_eph_pageframe();
- if (znewpage2 == NULL)
- evictpage2 = zcache_evict_eph_pageframe();
-
- if ((evictpage1 == NULL || evictpage2 == NULL) &&
- atomic_read(&zcache_outstanding_writeback_pages_atomic) >
- ZCACHE_MAX_OUTSTANDING_WRITEBACK_PAGES) {
- goto free_and_out;
- }
- if (znewpage1 == NULL && evictpage1 == NULL)
- newpage1 = alloc_page(GFP_KERNEL);
- if (znewpage2 == NULL && evictpage2 == NULL)
- newpage2 = alloc_page(GFP_KERNEL);
- if (newpage1 == NULL || newpage2 == NULL)
- goto free_and_out;
-
- /* ok, we have two pageframes pre-allocated, get a pair of zbuds */
- nzbuds = zbud_make_zombie_lru(&th[0], NULL, NULL, false);
- if (nzbuds == 0) {
- ret = -ENOENT;
- goto free_and_out;
- }
-
- /* process the first zbud */
- unswiz(th[0].oid, th[0].index, &type, &offset);
- page1 = (znewpage1 != NULL) ? znewpage1 :
- ((newpage1 != NULL) ? newpage1 : evictpage1);
- writeback_ret = zcache_frontswap_writeback_zpage(type, offset, page1);
- if (writeback_ret < 0) {
- ret = -ENOMEM;
- goto free_and_out;
- }
- if (evictpage1 != NULL)
- zcache_pageframes_freed =
- atomic_inc_return(&zcache_pageframes_freed_atomic);
- if (writeback_ret == 0) {
- /* zcache_get_swap_cache_page will free, don't double free */
- znewpage1 = NULL;
- newpage1 = NULL;
- evictpage1 = NULL;
- }
- if (nzbuds < 2)
- goto free_and_out;
-
- /* if there is a second zbud, process it */
- unswiz(th[1].oid, th[1].index, &type, &offset);
- page2 = (znewpage2 != NULL) ? znewpage2 :
- ((newpage2 != NULL) ? newpage2 : evictpage2);
- writeback_ret = zcache_frontswap_writeback_zpage(type, offset, page2);
- if (writeback_ret < 0) {
- ret = -ENOMEM;
- goto free_and_out;
- }
- if (evictpage2 != NULL)
- zcache_pageframes_freed =
- atomic_inc_return(&zcache_pageframes_freed_atomic);
- if (writeback_ret == 0) {
- znewpage2 = NULL;
- newpage2 = NULL;
- evictpage2 = NULL;
- }
-
-free_and_out:
- if (znewpage1 != NULL)
- page_cache_release(znewpage1);
- if (znewpage2 != NULL)
- page_cache_release(znewpage2);
- if (newpage1 != NULL)
- page_cache_release(newpage1);
- if (newpage2 != NULL)
- page_cache_release(newpage2);
- if (evictpage1 != NULL)
- zcache_free_page(evictpage1);
- if (evictpage2 != NULL)
- zcache_free_page(evictpage2);
- return ret;
-}
-#endif /* CONFIG_ZCACHE_WRITEBACK */
-
-/*
- * When zcache is disabled ("frozen"), pools can be created and destroyed,
- * but all puts (and thus all other operations that require memory allocation)
- * must fail. If zcache is unfrozen, accepts puts, then frozen again,
- * data consistency requires all puts while frozen to be converted into
- * flushes.
- */
-static bool zcache_freeze;
-
-/*
- * This zcache shrinker interface reduces the number of ephemeral pageframes
- * used by zcache to approximately the same as the total number of LRU_FILE
- * pageframes in use, and now also reduces the number of persistent pageframes
- * used by zcache to approximately the same as the total number of LRU_ANON
- * pageframes in use. FIXME POLICY: Probably the writeback should only occur
- * if the eviction doesn't free enough pages.
- */
-static int shrink_zcache_memory(struct shrinker *shrink,
- struct shrink_control *sc)
-{
- static bool in_progress;
- int ret = -1;
- int nr = sc->nr_to_scan;
- int nr_evict = 0;
- int nr_writeback = 0;
- struct page *page;
- int file_pageframes_inuse, anon_pageframes_inuse;
-
- if (nr <= 0)
- goto skip_evict;
-
- /* don't allow more than one eviction thread at a time */
- if (in_progress)
- goto skip_evict;
-
- in_progress = true;
-
- /* we are going to ignore nr, and target a different value */
- zcache_last_active_file_pageframes =
- global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE);
- zcache_last_inactive_file_pageframes =
- global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE);
- file_pageframes_inuse = zcache_last_active_file_pageframes +
- zcache_last_inactive_file_pageframes;
- if (zcache_eph_pageframes > file_pageframes_inuse)
- nr_evict = zcache_eph_pageframes - file_pageframes_inuse;
- else
- nr_evict = 0;
- while (nr_evict-- > 0) {
- page = zcache_evict_eph_pageframe();
- if (page == NULL)
- break;
- zcache_free_page(page);
- }
-
- zcache_last_active_anon_pageframes =
- global_page_state(NR_LRU_BASE + LRU_ACTIVE_ANON);
- zcache_last_inactive_anon_pageframes =
- global_page_state(NR_LRU_BASE + LRU_INACTIVE_ANON);
- anon_pageframes_inuse = zcache_last_active_anon_pageframes +
- zcache_last_inactive_anon_pageframes;
- if (zcache_pers_pageframes > anon_pageframes_inuse)
- nr_writeback = zcache_pers_pageframes - anon_pageframes_inuse;
- else
- nr_writeback = 0;
- while (nr_writeback-- > 0) {
-#ifdef CONFIG_ZCACHE_WRITEBACK
- int writeback_ret;
- writeback_ret = zcache_frontswap_writeback();
- if (writeback_ret == -ENOMEM)
-#endif
- break;
- }
- in_progress = false;
-
-skip_evict:
- /* resample: has changed, but maybe not all the way yet */
- zcache_last_active_file_pageframes =
- global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE);
- zcache_last_inactive_file_pageframes =
- global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE);
- ret = zcache_eph_pageframes - zcache_last_active_file_pageframes +
- zcache_last_inactive_file_pageframes;
- if (ret < 0)
- ret = 0;
- return ret;
-}
-
-static struct shrinker zcache_shrinker = {
- .shrink = shrink_zcache_memory,
- .seeks = DEFAULT_SEEKS,
-};
-
-/*
- * zcache shims between cleancache/frontswap ops and tmem
- */
-
-/* FIXME rename these core routines to zcache_tmemput etc? */
-int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp,
- uint32_t index, void *page,
- unsigned int size, bool raw, int ephemeral)
-{
- struct tmem_pool *pool;
- struct tmem_handle th;
- int ret = -1;
- void *pampd = NULL;
-
- BUG_ON(!irqs_disabled());
- pool = zcache_get_pool_by_id(cli_id, pool_id);
- if (unlikely(pool == NULL))
- goto out;
- if (!zcache_freeze) {
- ret = 0;
- th.client_id = cli_id;
- th.pool_id = pool_id;
- th.oid = *oidp;
- th.index = index;
- pampd = zcache_pampd_create((char *)page, size, raw,
- ephemeral, &th);
- if (pampd == NULL) {
- ret = -ENOMEM;
- if (ephemeral)
- inc_zcache_failed_eph_puts();
- else
- inc_zcache_failed_pers_puts();
- } else {
- if (ramster_enabled)
- ramster_do_preload_flnode(pool);
- ret = tmem_put(pool, oidp, index, 0, pampd);
- if (ret < 0)
- BUG();
- }
- zcache_put_pool(pool);
- } else {
- inc_zcache_put_to_flush();
- if (ramster_enabled)
- ramster_do_preload_flnode(pool);
- if (atomic_read(&pool->obj_count) > 0)
- /* the put fails whether the flush succeeds or not */
- (void)tmem_flush_page(pool, oidp, index);
- zcache_put_pool(pool);
- }
-out:
- return ret;
-}
-
-int zcache_get_page(int cli_id, int pool_id, struct tmem_oid *oidp,
- uint32_t index, void *page,
- size_t *sizep, bool raw, int get_and_free)
-{
- struct tmem_pool *pool;
- int ret = -1;
- bool eph;
-
- if (!raw) {
- BUG_ON(irqs_disabled());
- BUG_ON(in_softirq());
- }
- pool = zcache_get_pool_by_id(cli_id, pool_id);
- eph = is_ephemeral(pool);
- if (likely(pool != NULL)) {
- if (atomic_read(&pool->obj_count) > 0)
- ret = tmem_get(pool, oidp, index, (char *)(page),
- sizep, raw, get_and_free);
- zcache_put_pool(pool);
- }
- WARN_ONCE((!is_ephemeral(pool) && (ret != 0)),
- "zcache_get fails on persistent pool, "
- "bad things are very likely to happen soon\n");
-#ifdef RAMSTER_TESTING
- if (ret != 0 && ret != -1 && !(ret == -EINVAL && is_ephemeral(pool)))
- pr_err("TESTING zcache_get tmem_get returns ret=%d\n", ret);
-#endif
- return ret;
-}
-
-int zcache_flush_page(int cli_id, int pool_id,
- struct tmem_oid *oidp, uint32_t index)
-{
- struct tmem_pool *pool;
- int ret = -1;
- unsigned long flags;
-
- local_irq_save(flags);
- inc_zcache_flush_total();
- pool = zcache_get_pool_by_id(cli_id, pool_id);
- if (ramster_enabled)
- ramster_do_preload_flnode(pool);
- if (likely(pool != NULL)) {
- if (atomic_read(&pool->obj_count) > 0)
- ret = tmem_flush_page(pool, oidp, index);
- zcache_put_pool(pool);
- }
- if (ret >= 0)
- inc_zcache_flush_found();
- local_irq_restore(flags);
- return ret;
-}
-
-int zcache_flush_object(int cli_id, int pool_id,
- struct tmem_oid *oidp)
-{
- struct tmem_pool *pool;
- int ret = -1;
- unsigned long flags;
-
- local_irq_save(flags);
- inc_zcache_flobj_total();
- pool = zcache_get_pool_by_id(cli_id, pool_id);
- if (ramster_enabled)
- ramster_do_preload_flnode(pool);
- if (likely(pool != NULL)) {
- if (atomic_read(&pool->obj_count) > 0)
- ret = tmem_flush_object(pool, oidp);
- zcache_put_pool(pool);
- }
- if (ret >= 0)
- inc_zcache_flobj_found();
- local_irq_restore(flags);
- return ret;
-}
-
-static int zcache_client_destroy_pool(int cli_id, int pool_id)
-{
- struct tmem_pool *pool = NULL;
- struct zcache_client *cli = NULL;
- int ret = -1;
-
- if (pool_id < 0)
- goto out;
- if (cli_id == LOCAL_CLIENT)
- cli = &zcache_host;
- else if ((unsigned int)cli_id < MAX_CLIENTS)
- cli = &zcache_clients[cli_id];
- if (cli == NULL)
- goto out;
- atomic_inc(&cli->refcount);
- pool = cli->tmem_pools[pool_id];
- if (pool == NULL)
- goto out;
- cli->tmem_pools[pool_id] = NULL;
- /* wait for pool activity on other cpus to quiesce */
- while (atomic_read(&pool->refcount) != 0)
- ;
- atomic_dec(&cli->refcount);
- local_bh_disable();
- ret = tmem_destroy_pool(pool);
- local_bh_enable();
- kfree(pool);
- if (cli_id == LOCAL_CLIENT)
- pr_info("%s: destroyed local pool id=%d\n", namestr, pool_id);
- else
- pr_info("%s: destroyed pool id=%d, client=%d\n",
- namestr, pool_id, cli_id);
-out:
- return ret;
-}
-
-int zcache_new_pool(uint16_t cli_id, uint32_t flags)
-{
- int poolid = -1;
- struct tmem_pool *pool;
- struct zcache_client *cli = NULL;
-
- if (cli_id == LOCAL_CLIENT)
- cli = &zcache_host;
- else if ((unsigned int)cli_id < MAX_CLIENTS)
- cli = &zcache_clients[cli_id];
- if (cli == NULL)
- goto out;
- atomic_inc(&cli->refcount);
- pool = kmalloc(sizeof(struct tmem_pool), GFP_ATOMIC);
- if (pool == NULL)
- goto out;
-
- for (poolid = 0; poolid < MAX_POOLS_PER_CLIENT; poolid++)
- if (cli->tmem_pools[poolid] == NULL)
- break;
- if (poolid >= MAX_POOLS_PER_CLIENT) {
- pr_info("%s: pool creation failed: max exceeded\n", namestr);
- kfree(pool);
- poolid = -1;
- goto out;
- }
- atomic_set(&pool->refcount, 0);
- pool->client = cli;
- pool->pool_id = poolid;
- tmem_new_pool(pool, flags);
- cli->tmem_pools[poolid] = pool;
- if (cli_id == LOCAL_CLIENT)
- pr_info("%s: created %s local tmem pool, id=%d\n", namestr,
- flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
- poolid);
- else
- pr_info("%s: created %s tmem pool, id=%d, client=%d\n", namestr,
- flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
- poolid, cli_id);
-out:
- if (cli != NULL)
- atomic_dec(&cli->refcount);
- return poolid;
-}
-
-static int zcache_local_new_pool(uint32_t flags)
-{
- return zcache_new_pool(LOCAL_CLIENT, flags);
-}
-
-int zcache_autocreate_pool(unsigned int cli_id, unsigned int pool_id, bool eph)
-{
- struct tmem_pool *pool;
- struct zcache_client *cli = NULL;
- uint32_t flags = eph ? 0 : TMEM_POOL_PERSIST;
- int ret = -1;
-
- BUG_ON(!ramster_enabled);
- if (cli_id == LOCAL_CLIENT)
- goto out;
- if (pool_id >= MAX_POOLS_PER_CLIENT)
- goto out;
- if (cli_id >= MAX_CLIENTS)
- goto out;
-
- cli = &zcache_clients[cli_id];
- if ((eph && disable_cleancache) || (!eph && disable_frontswap)) {
- pr_err("zcache_autocreate_pool: pool type disabled\n");
- goto out;
- }
- if (!cli->allocated) {
- if (zcache_new_client(cli_id)) {
- pr_err("zcache_autocreate_pool: can't create client\n");
- goto out;
- }
- cli = &zcache_clients[cli_id];
- }
- atomic_inc(&cli->refcount);
- pool = cli->tmem_pools[pool_id];
- if (pool != NULL) {
- if (pool->persistent && eph) {
- pr_err("zcache_autocreate_pool: type mismatch\n");
- goto out;
- }
- ret = 0;
- goto out;
- }
- pool = kmalloc(sizeof(struct tmem_pool), GFP_KERNEL);
- if (pool == NULL)
- goto out;
-
- atomic_set(&pool->refcount, 0);
- pool->client = cli;
- pool->pool_id = pool_id;
- tmem_new_pool(pool, flags);
- cli->tmem_pools[pool_id] = pool;
- pr_info("%s: AUTOcreated %s tmem poolid=%d, for remote client=%d\n",
- namestr, flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
- pool_id, cli_id);
- ret = 0;
-out:
- if (cli != NULL)
- atomic_dec(&cli->refcount);
- return ret;
-}
-
-/**********
- * Two kernel functionalities currently can be layered on top of tmem.
- * These are "cleancache" which is used as a second-chance cache for clean
- * page cache pages; and "frontswap" which is used for swap pages
- * to avoid writes to disk. A generic "shim" is provided here for each
- * to translate in-kernel semantics to zcache semantics.
- */
-
-static void zcache_cleancache_put_page(int pool_id,
- struct cleancache_filekey key,
- pgoff_t index, struct page *page)
-{
- u32 ind = (u32) index;
- struct tmem_oid oid = *(struct tmem_oid *)&key;
-
- if (!disable_cleancache_ignore_nonactive && !PageWasActive(page)) {
- inc_zcache_eph_nonactive_puts_ignored();
- return;
- }
- if (likely(ind == index))
- (void)zcache_put_page(LOCAL_CLIENT, pool_id, &oid, index,
- page, PAGE_SIZE, false, 1);
-}
-
-static int zcache_cleancache_get_page(int pool_id,
- struct cleancache_filekey key,
- pgoff_t index, struct page *page)
-{
- u32 ind = (u32) index;
- struct tmem_oid oid = *(struct tmem_oid *)&key;
- size_t size;
- int ret = -1;
-
- if (likely(ind == index)) {
- ret = zcache_get_page(LOCAL_CLIENT, pool_id, &oid, index,
- page, &size, false, 0);
- BUG_ON(ret >= 0 && size != PAGE_SIZE);
- if (ret == 0)
- SetPageWasActive(page);
- }
- return ret;
-}
-
-static void zcache_cleancache_flush_page(int pool_id,
- struct cleancache_filekey key,
- pgoff_t index)
-{
- u32 ind = (u32) index;
- struct tmem_oid oid = *(struct tmem_oid *)&key;
-
- if (likely(ind == index))
- (void)zcache_flush_page(LOCAL_CLIENT, pool_id, &oid, ind);
-}
-
-static void zcache_cleancache_flush_inode(int pool_id,
- struct cleancache_filekey key)
-{
- struct tmem_oid oid = *(struct tmem_oid *)&key;
-
- (void)zcache_flush_object(LOCAL_CLIENT, pool_id, &oid);
-}
-
-static void zcache_cleancache_flush_fs(int pool_id)
-{
- if (pool_id >= 0)
- (void)zcache_client_destroy_pool(LOCAL_CLIENT, pool_id);
-}
-
-static int zcache_cleancache_init_fs(size_t pagesize)
-{
- BUG_ON(sizeof(struct cleancache_filekey) !=
- sizeof(struct tmem_oid));
- BUG_ON(pagesize != PAGE_SIZE);
- return zcache_local_new_pool(0);
-}
-
-static int zcache_cleancache_init_shared_fs(char *uuid, size_t pagesize)
-{
- /* shared pools are unsupported and map to private */
- BUG_ON(sizeof(struct cleancache_filekey) !=
- sizeof(struct tmem_oid));
- BUG_ON(pagesize != PAGE_SIZE);
- return zcache_local_new_pool(0);
-}
-
-static struct cleancache_ops zcache_cleancache_ops = {
- .put_page = zcache_cleancache_put_page,
- .get_page = zcache_cleancache_get_page,
- .invalidate_page = zcache_cleancache_flush_page,
- .invalidate_inode = zcache_cleancache_flush_inode,
- .invalidate_fs = zcache_cleancache_flush_fs,
- .init_shared_fs = zcache_cleancache_init_shared_fs,
- .init_fs = zcache_cleancache_init_fs
-};
-
-struct cleancache_ops *zcache_cleancache_register_ops(void)
-{
- struct cleancache_ops *old_ops =
- cleancache_register_ops(&zcache_cleancache_ops);
-
- return old_ops;
-}
-
-/* a single tmem poolid is used for all frontswap "types" (swapfiles) */
-static int zcache_frontswap_poolid __read_mostly = -1;
-
-/*
- * Swizzling increases objects per swaptype, increasing tmem concurrency
- * for heavy swaploads. Later, larger nr_cpus -> larger SWIZ_BITS
- * Setting SWIZ_BITS to 27 basically reconstructs the swap entry from
- * frontswap_get_page(), but has side-effects. Hence using 8.
- */
-#define SWIZ_BITS 8
-#define SWIZ_MASK ((1 << SWIZ_BITS) - 1)
-#define _oswiz(_type, _ind) ((_type << SWIZ_BITS) | (_ind & SWIZ_MASK))
-#define iswiz(_ind) (_ind >> SWIZ_BITS)
-
-static inline struct tmem_oid oswiz(unsigned type, u32 ind)
-{
- struct tmem_oid oid = { .oid = { 0 } };
- oid.oid[0] = _oswiz(type, ind);
- return oid;
-}
-
-#ifdef CONFIG_ZCACHE_WRITEBACK
-static void unswiz(struct tmem_oid oid, u32 index,
- unsigned *type, pgoff_t *offset)
-{
- *type = (unsigned)(oid.oid[0] >> SWIZ_BITS);
- *offset = (pgoff_t)((index << SWIZ_BITS) |
- (oid.oid[0] & SWIZ_MASK));
-}
-#endif
-
-static int zcache_frontswap_put_page(unsigned type, pgoff_t offset,
- struct page *page)
-{
- u64 ind64 = (u64)offset;
- u32 ind = (u32)offset;
- struct tmem_oid oid = oswiz(type, ind);
- int ret = -1;
- unsigned long flags;
-
- BUG_ON(!PageLocked(page));
- if (!disable_frontswap_ignore_nonactive && !PageWasActive(page)) {
- inc_zcache_pers_nonactive_puts_ignored();
- ret = -ERANGE;
- goto out;
- }
- if (likely(ind64 == ind)) {
- local_irq_save(flags);
- ret = zcache_put_page(LOCAL_CLIENT, zcache_frontswap_poolid,
- &oid, iswiz(ind),
- page, PAGE_SIZE, false, 0);
- local_irq_restore(flags);
- }
-out:
- return ret;
-}
-
-/* returns 0 if the page was successfully gotten from frontswap, -1 if
- * was not present (should never happen!) */
-static int zcache_frontswap_get_page(unsigned type, pgoff_t offset,
- struct page *page)
-{
- u64 ind64 = (u64)offset;
- u32 ind = (u32)offset;
- struct tmem_oid oid = oswiz(type, ind);
- size_t size;
- int ret = -1, get_and_free;
-
- if (frontswap_has_exclusive_gets)
- get_and_free = 1;
- else
- get_and_free = -1;
- BUG_ON(!PageLocked(page));
- if (likely(ind64 == ind)) {
- ret = zcache_get_page(LOCAL_CLIENT, zcache_frontswap_poolid,
- &oid, iswiz(ind),
- page, &size, false, get_and_free);
- BUG_ON(ret >= 0 && size != PAGE_SIZE);
- }
- return ret;
-}
-
-/* flush a single page from frontswap */
-static void zcache_frontswap_flush_page(unsigned type, pgoff_t offset)
-{
- u64 ind64 = (u64)offset;
- u32 ind = (u32)offset;
- struct tmem_oid oid = oswiz(type, ind);
-
- if (likely(ind64 == ind))
- (void)zcache_flush_page(LOCAL_CLIENT, zcache_frontswap_poolid,
- &oid, iswiz(ind));
-}
-
-/* flush all pages from the passed swaptype */
-static void zcache_frontswap_flush_area(unsigned type)
-{
- struct tmem_oid oid;
- int ind;
-
- for (ind = SWIZ_MASK; ind >= 0; ind--) {
- oid = oswiz(type, ind);
- (void)zcache_flush_object(LOCAL_CLIENT,
- zcache_frontswap_poolid, &oid);
- }
-}
-
-static void zcache_frontswap_init(unsigned ignored)
-{
- /* a single tmem poolid is used for all frontswap "types" (swapfiles) */
- if (zcache_frontswap_poolid < 0)
- zcache_frontswap_poolid =
- zcache_local_new_pool(TMEM_POOL_PERSIST);
-}
-
-static struct frontswap_ops zcache_frontswap_ops = {
- .store = zcache_frontswap_put_page,
- .load = zcache_frontswap_get_page,
- .invalidate_page = zcache_frontswap_flush_page,
- .invalidate_area = zcache_frontswap_flush_area,
- .init = zcache_frontswap_init
-};
-
-struct frontswap_ops *zcache_frontswap_register_ops(void)
-{
- struct frontswap_ops *old_ops =
- frontswap_register_ops(&zcache_frontswap_ops);
-
- return old_ops;
-}
-
-/*
- * zcache initialization
- * NOTE FOR NOW zcache or ramster MUST BE PROVIDED AS A KERNEL BOOT PARAMETER
- * OR NOTHING HAPPENS!
- */
-
-#ifndef CONFIG_ZCACHE_MODULE
-static int __init enable_zcache(char *s)
-{
- zcache_enabled = true;
- return 1;
-}
-__setup("zcache", enable_zcache);
-
-static int __init enable_ramster(char *s)
-{
- zcache_enabled = true;
-#ifdef CONFIG_RAMSTER
- ramster_enabled = true;
-#endif
- return 1;
-}
-__setup("ramster", enable_ramster);
-
-/* allow independent dynamic disabling of cleancache and frontswap */
-
-static int __init no_cleancache(char *s)
-{
- disable_cleancache = true;
- return 1;
-}
-
-__setup("nocleancache", no_cleancache);
-
-static int __init no_frontswap(char *s)
-{
- disable_frontswap = true;
- return 1;
-}
-
-__setup("nofrontswap", no_frontswap);
-
-static int __init no_frontswap_exclusive_gets(char *s)
-{
- frontswap_has_exclusive_gets = false;
- return 1;
-}
-
-__setup("nofrontswapexclusivegets", no_frontswap_exclusive_gets);
-
-static int __init no_frontswap_ignore_nonactive(char *s)
-{
- disable_frontswap_ignore_nonactive = true;
- return 1;
-}
-
-__setup("nofrontswapignorenonactive", no_frontswap_ignore_nonactive);
-
-static int __init no_cleancache_ignore_nonactive(char *s)
-{
- disable_cleancache_ignore_nonactive = true;
- return 1;
-}
-
-__setup("nocleancacheignorenonactive", no_cleancache_ignore_nonactive);
-
-static int __init enable_zcache_compressor(char *s)
-{
- strlcpy(zcache_comp_name, s, sizeof(zcache_comp_name));
- zcache_enabled = true;
- return 1;
-}
-__setup("zcache=", enable_zcache_compressor);
-#endif
-
-
-static int zcache_comp_init(void)
-{
- int ret = 0;
-
- /* check crypto algorithm */
-#ifdef CONFIG_ZCACHE_MODULE
- ret = crypto_has_comp(zcache_comp_name, 0, 0);
- if (!ret) {
- ret = -1;
- goto out;
- }
-#else
- if (*zcache_comp_name != '\0') {
- ret = crypto_has_comp(zcache_comp_name, 0, 0);
- if (!ret)
- pr_info("zcache: %s not supported\n",
- zcache_comp_name);
- goto out;
- }
- if (!ret)
- strcpy(zcache_comp_name, "lzo");
- ret = crypto_has_comp(zcache_comp_name, 0, 0);
- if (!ret) {
- ret = 1;
- goto out;
- }
-#endif
- pr_info("zcache: using %s compressor\n", zcache_comp_name);
-
- /* alloc percpu transforms */
- ret = 0;
- zcache_comp_pcpu_tfms = alloc_percpu(struct crypto_comp *);
- if (!zcache_comp_pcpu_tfms)
- ret = 1;
-out:
- return ret;
-}
-
-static int zcache_init(void)
-{
- int ret = 0;
-
-#ifdef CONFIG_ZCACHE_MODULE
- zcache_enabled = 1;
-#endif
- if (ramster_enabled) {
- namestr = "ramster";
- ramster_register_pamops(&zcache_pamops);
- }
- zcache_debugfs_init();
- if (zcache_enabled) {
- unsigned int cpu;
-
- tmem_register_hostops(&zcache_hostops);
- tmem_register_pamops(&zcache_pamops);
- ret = register_cpu_notifier(&zcache_cpu_notifier_block);
- if (ret) {
- pr_err("%s: can't register cpu notifier\n", namestr);
- goto out;
- }
- ret = zcache_comp_init();
- if (ret) {
- pr_err("%s: compressor initialization failed\n",
- namestr);
- goto out;
- }
- for_each_online_cpu(cpu) {
- void *pcpu = (void *)(long)cpu;
- zcache_cpu_notifier(&zcache_cpu_notifier_block,
- CPU_UP_PREPARE, pcpu);
- }
- }
- zcache_objnode_cache = kmem_cache_create("zcache_objnode",
- sizeof(struct tmem_objnode), 0, 0, NULL);
- zcache_obj_cache = kmem_cache_create("zcache_obj",
- sizeof(struct tmem_obj), 0, 0, NULL);
- ret = zcache_new_client(LOCAL_CLIENT);
- if (ret) {
- pr_err("%s: can't create client\n", namestr);
- goto out;
- }
- zbud_init();
- if (zcache_enabled && !disable_cleancache) {
- struct cleancache_ops *old_ops;
-
- register_shrinker(&zcache_shrinker);
- old_ops = zcache_cleancache_register_ops();
- pr_info("%s: cleancache enabled using kernel transcendent "
- "memory and compression buddies\n", namestr);
-#ifdef CONFIG_ZCACHE_DEBUG
- pr_info("%s: cleancache: ignorenonactive = %d\n",
- namestr, !disable_cleancache_ignore_nonactive);
-#endif
- if (old_ops != NULL)
- pr_warn("%s: cleancache_ops overridden\n", namestr);
- }
- if (zcache_enabled && !disable_frontswap) {
- struct frontswap_ops *old_ops;
-
- old_ops = zcache_frontswap_register_ops();
- if (frontswap_has_exclusive_gets)
- frontswap_tmem_exclusive_gets(true);
- pr_info("%s: frontswap enabled using kernel transcendent "
- "memory and compression buddies\n", namestr);
-#ifdef CONFIG_ZCACHE_DEBUG
- pr_info("%s: frontswap: excl gets = %d active only = %d\n",
- namestr, frontswap_has_exclusive_gets,
- !disable_frontswap_ignore_nonactive);
-#endif
- if (IS_ERR(old_ops) || old_ops) {
- if (IS_ERR(old_ops))
- return PTR_RET(old_ops);
- pr_warn("%s: frontswap_ops overridden\n", namestr);
- }
- }
- if (ramster_enabled)
- ramster_init(!disable_cleancache, !disable_frontswap,
- frontswap_has_exclusive_gets,
- !disable_frontswap_selfshrink);
-out:
- return ret;
-}
-
-#ifdef CONFIG_ZCACHE_MODULE
-#ifdef CONFIG_RAMSTER
-module_param(ramster_enabled, bool, S_IRUGO);
-module_param(disable_frontswap_selfshrink, int, S_IRUGO);
-#endif
-module_param(disable_cleancache, bool, S_IRUGO);
-module_param(disable_frontswap, bool, S_IRUGO);
-#ifdef FRONTSWAP_HAS_EXCLUSIVE_GETS
-module_param(frontswap_has_exclusive_gets, bool, S_IRUGO);
-#endif
-module_param(disable_frontswap_ignore_nonactive, bool, S_IRUGO);
-module_param(zcache_comp_name, charp, S_IRUGO);
-module_init(zcache_init);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Dan Magenheimer <dan.magenheimer@oracle.com>");
-MODULE_DESCRIPTION("In-kernel compression of cleancache/frontswap pages");
-#else
-late_initcall(zcache_init);
-#endif
diff --git a/drivers/staging/zcache/zcache.h b/drivers/staging/zcache/zcache.h
deleted file mode 100644
index 849120095e7..00000000000
--- a/drivers/staging/zcache/zcache.h
+++ /dev/null
@@ -1,53 +0,0 @@
-
-/*
- * zcache.h
- *
- * Copyright (c) 2012, Dan Magenheimer, Oracle Corp.
- */
-
-#ifndef _ZCACHE_H_
-#define _ZCACHE_H_
-
-struct zcache_preload {
- struct tmem_obj *obj;
- struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH];
-};
-
-struct tmem_pool;
-
-#define MAX_POOLS_PER_CLIENT 16
-
-#define MAX_CLIENTS 16
-#define LOCAL_CLIENT ((uint16_t)-1)
-
-struct zcache_client {
- struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
- bool allocated;
- atomic_t refcount;
-};
-
-extern struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id,
- uint16_t poolid);
-extern void zcache_put_pool(struct tmem_pool *pool);
-
-extern int zcache_put_page(int, int, struct tmem_oid *,
- uint32_t, void *,
- unsigned int, bool, int);
-extern int zcache_get_page(int, int, struct tmem_oid *, uint32_t,
- void *, size_t *, bool, int);
-extern int zcache_flush_page(int, int, struct tmem_oid *, uint32_t);
-extern int zcache_flush_object(int, int, struct tmem_oid *);
-extern void zcache_decompress_to_page(char *, unsigned int, struct page *);
-
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
-extern void *zcache_pampd_create(char *, unsigned int, bool, int,
- struct tmem_handle *);
-int zcache_autocreate_pool(unsigned int cli_id, unsigned int pool_id, bool eph);
-#endif
-
-#define MAX_POOLS_PER_CLIENT 16
-
-#define MAX_CLIENTS 16
-#define LOCAL_CLIENT ((uint16_t)-1)
-
-#endif /* _ZCACHE_H_ */
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 82c7202fd5c..91d94b56443 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -169,7 +169,7 @@ static inline int is_partial_io(struct bio_vec *bvec)
static inline int valid_io_request(struct zram *zram, struct bio *bio)
{
u64 start, end, bound;
-
+
/* unaligned request */
if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
return 0;
@@ -418,14 +418,6 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
goto out;
}
- /*
- * System overwrites unused sectors. Free memory associated
- * with this sector now.
- */
- if (meta->table[index].handle ||
- zram_test_flag(meta, index, ZRAM_ZERO))
- zram_free_page(zram, index);
-
user_mem = kmap_atomic(page);
if (is_partial_io(bvec)) {
@@ -439,12 +431,23 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
if (page_zero_filled(uncmem)) {
kunmap_atomic(user_mem);
+ /* Free memory associated with this sector now. */
+ zram_free_page(zram, index);
+
zram->stats.pages_zero++;
zram_set_flag(meta, index, ZRAM_ZERO);
ret = 0;
goto out;
}
+ /*
+ * zram_slot_free_notify could miss free so that let's
+ * double check.
+ */
+ if (unlikely(meta->table[index].handle ||
+ zram_test_flag(meta, index, ZRAM_ZERO)))
+ zram_free_page(zram, index);
+
ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
meta->compress_workmem);
@@ -486,6 +489,12 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
zs_unmap_object(meta->mem_pool, handle);
+ /*
+ * Free memory associated with this sector
+ * before overwriting unused sectors.
+ */
+ zram_free_page(zram, index);
+
meta->table[index].handle = handle;
meta->table[index].size = clen;
@@ -504,6 +513,20 @@ out:
return ret;
}
+static void handle_pending_slot_free(struct zram *zram)
+{
+ struct zram_slot_free *free_rq;
+
+ spin_lock(&zram->slot_free_lock);
+ while (zram->slot_free_rq) {
+ free_rq = zram->slot_free_rq;
+ zram->slot_free_rq = free_rq->next;
+ zram_free_page(zram, free_rq->index);
+ kfree(free_rq);
+ }
+ spin_unlock(&zram->slot_free_lock);
+}
+
static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
int offset, struct bio *bio, int rw)
{
@@ -511,10 +534,12 @@ static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
if (rw == READ) {
down_read(&zram->lock);
+ handle_pending_slot_free(zram);
ret = zram_bvec_read(zram, bvec, index, offset, bio);
up_read(&zram->lock);
} else {
down_write(&zram->lock);
+ handle_pending_slot_free(zram);
ret = zram_bvec_write(zram, bvec, index, offset);
up_write(&zram->lock);
}
@@ -522,13 +547,18 @@ static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
return ret;
}
-static void zram_reset_device(struct zram *zram)
+static void zram_reset_device(struct zram *zram, bool reset_capacity)
{
size_t index;
struct zram_meta *meta;
- if (!zram->init_done)
+ flush_work(&zram->free_work);
+
+ down_write(&zram->init_lock);
+ if (!zram->init_done) {
+ up_write(&zram->init_lock);
return;
+ }
meta = zram->meta;
zram->init_done = 0;
@@ -548,7 +578,9 @@ static void zram_reset_device(struct zram *zram)
memset(&zram->stats, 0, sizeof(zram->stats));
zram->disksize = 0;
- set_capacity(zram->disk, 0);
+ if (reset_capacity)
+ set_capacity(zram->disk, 0);
+ up_write(&zram->init_lock);
}
static void zram_init_device(struct zram *zram, struct zram_meta *meta)
@@ -631,7 +663,7 @@ static ssize_t reset_store(struct device *dev,
if (bdev)
fsync_bdev(bdev);
- zram_reset_device(zram);
+ zram_reset_device(zram, true);
return len;
}
@@ -716,16 +748,40 @@ error:
bio_io_error(bio);
}
+static void zram_slot_free(struct work_struct *work)
+{
+ struct zram *zram;
+
+ zram = container_of(work, struct zram, free_work);
+ down_write(&zram->lock);
+ handle_pending_slot_free(zram);
+ up_write(&zram->lock);
+}
+
+static void add_slot_free(struct zram *zram, struct zram_slot_free *free_rq)
+{
+ spin_lock(&zram->slot_free_lock);
+ free_rq->next = zram->slot_free_rq;
+ zram->slot_free_rq = free_rq;
+ spin_unlock(&zram->slot_free_lock);
+}
+
static void zram_slot_free_notify(struct block_device *bdev,
unsigned long index)
{
struct zram *zram;
+ struct zram_slot_free *free_rq;
zram = bdev->bd_disk->private_data;
- down_write(&zram->lock);
- zram_free_page(zram, index);
- up_write(&zram->lock);
atomic64_inc(&zram->stats.notify_free);
+
+ free_rq = kmalloc(sizeof(struct zram_slot_free), GFP_ATOMIC);
+ if (!free_rq)
+ return;
+
+ free_rq->index = index;
+ add_slot_free(zram, free_rq);
+ schedule_work(&zram->free_work);
}
static const struct block_device_operations zram_devops = {
@@ -772,6 +828,10 @@ static int create_device(struct zram *zram, int device_id)
init_rwsem(&zram->lock);
init_rwsem(&zram->init_lock);
+ INIT_WORK(&zram->free_work, zram_slot_free);
+ spin_lock_init(&zram->slot_free_lock);
+ zram->slot_free_rq = NULL;
+
zram->queue = blk_alloc_queue(GFP_KERNEL);
if (!zram->queue) {
pr_err("Error allocating disk queue for device %d\n",
@@ -898,10 +958,12 @@ static void __exit zram_exit(void)
for (i = 0; i < num_devices; i++) {
zram = &zram_devices[i];
- get_disk(zram->disk);
destroy_device(zram);
- zram_reset_device(zram);
- put_disk(zram->disk);
+ /*
+ * Shouldn't access zram->disk after destroy_device
+ * because destroy_device already released zram->disk.
+ */
+ zram_reset_device(zram, false);
}
unregister_blkdev(zram_major, "zram");
@@ -919,3 +981,4 @@ MODULE_PARM_DESC(num_devices, "Number of zram devices");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
MODULE_DESCRIPTION("Compressed RAM Block Device");
+MODULE_ALIAS("devname:zram");
diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h
index 9e57bfb29b4..97a3acf6ab7 100644
--- a/drivers/staging/zram/zram_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -94,11 +94,20 @@ struct zram_meta {
struct zs_pool *mem_pool;
};
+struct zram_slot_free {
+ unsigned long index;
+ struct zram_slot_free *next;
+};
+
struct zram {
struct zram_meta *meta;
struct rw_semaphore lock; /* protect compression buffers, table,
* 32bit stat counters against concurrent
* notifications, reads and writes */
+
+ struct work_struct free_work; /* handle pending free request */
+ struct zram_slot_free *slot_free_rq; /* list head of free request */
+
struct request_queue *queue;
struct gendisk *disk;
int init_done;
@@ -109,6 +118,7 @@ struct zram {
* we can store in a disk.
*/
u64 disksize; /* bytes */
+ spinlock_t slot_free_lock;
struct zram_stats stats;
};
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 4bb275b2d98..1a67537dbc5 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -423,7 +423,7 @@ static struct page *get_next_page(struct page *page)
if (is_last_page(page))
next = NULL;
else if (is_first_page(page))
- next = (struct page *)page->private;
+ next = (struct page *)page_private(page);
else
next = list_entry(page->lru.next, struct page, lru);
@@ -581,7 +581,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
first_page->inuse = 0;
}
if (i == 1)
- first_page->private = (unsigned long)page;
+ set_page_private(first_page, (unsigned long)page);
if (i >= 1)
page->first_page = first_page;
if (i >= 2)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index f73da43cdf9..3a179302b90 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1086,7 +1086,6 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
if (cmd->reject_reason)
return 0;
- target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
return 1;
}
/*
@@ -1124,14 +1123,10 @@ after_immediate_data:
*/
cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd,
(unsigned char *)hdr, hdr->cmdsn);
- if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
+ 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 (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
int rc;
rc = iscsit_dump_data_payload(cmd->conn,
@@ -1527,6 +1522,10 @@ int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
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");
+ if (!cmd)
+ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+ (unsigned char *)hdr);
+
return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
(unsigned char *)hdr);
}
@@ -1536,6 +1535,10 @@ int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
" greater than MaxXmitDataSegmentLength: %u, protocol"
" error.\n", payload_length,
conn->conn_ops->MaxXmitDataSegmentLength);
+ if (!cmd)
+ return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+ (unsigned char *)hdr);
+
return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
(unsigned char *)hdr);
}
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 3402241be87..bc788c52b6c 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -1163,12 +1163,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
spin_unlock_bh(&np->np_thread_lock);
complete(&np->np_restart_comp);
- if (ret == -ENODEV) {
- iscsit_put_transport(conn->conn_transport);
- kfree(conn);
- conn = NULL;
+ iscsit_put_transport(conn->conn_transport);
+ kfree(conn);
+ conn = NULL;
+ if (ret == -ENODEV)
goto out;
- }
/* Get another socket */
return 1;
}
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 4cb667d720a..9fabbf7214c 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -97,9 +97,12 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
buf[7] = 0x2; /* CmdQue=1 */
- snprintf(&buf[8], 8, "LIO-ORG");
- snprintf(&buf[16], 16, "%s", dev->t10_wwn.model);
- snprintf(&buf[32], 4, "%s", dev->t10_wwn.revision);
+ memcpy(&buf[8], "LIO-ORG ", 8);
+ memset(&buf[16], 0x20, 16);
+ memcpy(&buf[16], dev->t10_wwn.model,
+ min_t(size_t, strlen(dev->t10_wwn.model), 16));
+ memcpy(&buf[32], dev->t10_wwn.revision,
+ min_t(size_t, strlen(dev->t10_wwn.revision), 4));
buf[4] = 31; /* Set additional length to 31 */
return 0;
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 7172d005d06..d8e49d79f8c 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -2134,6 +2134,7 @@ static void transport_write_pending_qf(struct se_cmd *cmd)
int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
{
+ unsigned long flags;
int ret = 0;
if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
@@ -2144,6 +2145,16 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
} else {
if (wait_for_tasks)
transport_wait_for_tasks(cmd);
+ /*
+ * Handle WRITE failure case where transport_generic_new_cmd()
+ * has already added se_cmd to state_list, but fabric has
+ * failed command before I/O submission.
+ */
+ if (cmd->state_active) {
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ target_remove_from_state_list(cmd);
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ }
if (cmd->se_lun)
transport_lun_remove_cmd(cmd);
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
index 5de56f671a9..f36950e4134 100644
--- a/drivers/thermal/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/x86_pkg_temp_thermal.c
@@ -54,6 +54,8 @@ MODULE_PARM_DESC(notify_delay_ms,
* is some wrong values returned by cpuid for number of thresholds.
*/
#define MAX_NUMBER_OF_TRIPS 2
+/* Limit number of package temp zones */
+#define MAX_PKG_TEMP_ZONE_IDS 256
struct phy_dev_entry {
struct list_head list;
@@ -394,12 +396,16 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
char buffer[30];
int thres_count;
u32 eax, ebx, ecx, edx;
+ u8 *temp;
cpuid(6, &eax, &ebx, &ecx, &edx);
thres_count = ebx & 0x07;
if (!thres_count)
return -ENODEV;
+ if (topology_physical_package_id(cpu) > MAX_PKG_TEMP_ZONE_IDS)
+ return -ENODEV;
+
thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS);
err = get_tj_max(cpu, &tj_max);
@@ -417,13 +423,14 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
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) {
+ temp = krealloc(pkg_work_scheduled,
+ (max_phy_id+1) * sizeof(u8), GFP_ATOMIC);
+ if (!temp) {
spin_unlock(&pkg_work_lock);
err = -ENOMEM;
goto err_ret_free;
}
+ pkg_work_scheduled = temp;
pkg_work_scheduled[topology_physical_package_id(cpu)] = 0;
spin_unlock(&pkg_work_lock);
@@ -511,7 +518,7 @@ static int get_core_online(unsigned int cpu)
/* Check if there is already an instance for this package */
if (!phdev) {
- if (!cpu_has(c, X86_FEATURE_DTHERM) &&
+ if (!cpu_has(c, X86_FEATURE_DTHERM) ||
!cpu_has(c, X86_FEATURE_PTS))
return -ENODEV;
if (pkg_temp_thermal_device_add(cpu))
@@ -562,7 +569,7 @@ static struct notifier_block pkg_temp_thermal_notifier __refdata = {
};
static const struct x86_cpu_id __initconst pkg_temp_thermal_ids[] = {
- { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM },
+ { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_PTS },
{}
};
MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids);
@@ -592,7 +599,6 @@ static int __init pkg_temp_thermal_init(void)
return 0;
err_ret:
- get_online_cpus();
for_each_online_cpu(i)
put_core_offline(i);
put_online_cpus();
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 083710e0236..2b86f8e0fb5 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1785,8 +1785,6 @@ static int __exit amiga_serial_remove(struct platform_device *pdev)
free_irq(IRQ_AMIGA_TBE, state);
free_irq(IRQ_AMIGA_RBF, state);
- platform_set_drvdata(pdev, NULL);
-
return error;
}
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index eb255e807c0..9eba119bcdd 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -361,7 +361,12 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
tty->driver_data = NULL;
tty_port_put(&hp->port);
printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
- }
+ } else
+ /* We are ready... raise DTR/RTS */
+ if (C_BAUD(tty))
+ if (hp->ops->dtr_rts)
+ hp->ops->dtr_rts(hp, 1);
+
/* Force wakeup of the polling thread */
hvc_kick();
@@ -393,6 +398,10 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
/* We are done with the tty pointer now. */
tty_port_tty_set(&hp->port, NULL);
+ if (C_HUPCL(tty))
+ if (hp->ops->dtr_rts)
+ hp->ops->dtr_rts(hp, 0);
+
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h
index 674d23cb919..91310198082 100644
--- a/drivers/tty/hvc/hvc_console.h
+++ b/drivers/tty/hvc/hvc_console.h
@@ -75,6 +75,9 @@ struct hv_ops {
/* tiocmget/set implementation */
int (*tiocmget)(struct hvc_struct *hp);
int (*tiocmset)(struct hvc_struct *hp, unsigned int set, unsigned int clear);
+
+ /* Callbacks to handle tty ports */
+ void (*dtr_rts)(struct hvc_struct *hp, int raise);
};
/* Register a vterm and a slot index for use as a console (console_init) */
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index 9d47f50c275..fd17a9b804b 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -656,21 +656,64 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
}
/**
+ * hvc_iucv_dtr_rts() - HVC notifier for handling DTR/RTS
+ * @hp: Pointer the HVC device (struct hvc_struct)
+ * @raise: Non-zero to raise or zero to lower DTR/RTS lines
+ *
+ * This routine notifies the HVC back-end to raise or lower DTR/RTS
+ * lines. Raising DTR/RTS is ignored. Lowering DTR/RTS indicates to
+ * drop the IUCV connection (similar to hang up the modem).
+ */
+static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise)
+{
+ struct hvc_iucv_private *priv;
+ struct iucv_path *path;
+
+ /* Raising the DTR/RTS is ignored as IUCV connections can be
+ * established at any times.
+ */
+ if (raise)
+ return;
+
+ priv = hvc_iucv_get_private(hp->vtermno);
+ if (!priv)
+ return;
+
+ /* Lowering the DTR/RTS lines disconnects an established IUCV
+ * connection.
+ */
+ flush_sndbuf_sync(priv);
+
+ spin_lock_bh(&priv->lock);
+ path = priv->path; /* save reference to IUCV path */
+ priv->path = NULL;
+ priv->iucv_state = IUCV_DISCONN;
+ spin_unlock_bh(&priv->lock);
+
+ /* Sever IUCV path outside of priv->lock due to lock ordering of:
+ * priv->lock <--> iucv_table_lock */
+ if (path) {
+ iucv_path_sever(path, NULL);
+ iucv_path_free(path);
+ }
+}
+
+/**
* hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time.
* @hp: Pointer to the HVC device (struct hvc_struct)
* @id: Additional data (originally passed to hvc_alloc):
* the index of an struct hvc_iucv_private instance.
*
* This routine notifies the HVC back-end that the last tty device fd has been
- * closed. The function calls hvc_iucv_cleanup() to clean up the struct
- * hvc_iucv_private instance.
+ * closed. The function cleans up tty resources. The clean-up of the IUCV
+ * connection is done in hvc_iucv_dtr_rts() and depends on the HUPCL termios
+ * control setting.
*
* Locking: struct hvc_iucv_private->lock
*/
static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
{
struct hvc_iucv_private *priv;
- struct iucv_path *path;
priv = hvc_iucv_get_private(id);
if (!priv)
@@ -679,17 +722,11 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
flush_sndbuf_sync(priv);
spin_lock_bh(&priv->lock);
- path = priv->path; /* save reference to IUCV path */
- priv->path = NULL;
- hvc_iucv_cleanup(priv);
+ destroy_tty_buffer_list(&priv->tty_outqueue);
+ destroy_tty_buffer_list(&priv->tty_inqueue);
+ priv->tty_state = TTY_CLOSED;
+ priv->sndbuf_len = 0;
spin_unlock_bh(&priv->lock);
-
- /* sever IUCV path outside of priv->lock due to lock ordering of:
- * priv->lock <--> iucv_table_lock */
- if (path) {
- iucv_path_sever(path, NULL);
- iucv_path_free(path);
- }
}
/**
@@ -931,6 +968,7 @@ static const struct hv_ops hvc_iucv_ops = {
.notifier_add = hvc_iucv_notifier_add,
.notifier_del = hvc_iucv_notifier_del,
.notifier_hangup = hvc_iucv_notifier_hangup,
+ .dtr_rts = hvc_iucv_dtr_rts,
};
/* Suspend / resume device operations */
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 682210d778b..e61c36cbb86 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -208,7 +208,7 @@ static int xen_hvm_console_init(void)
info = vtermno_to_xencons(HVC_COOKIE);
if (!info) {
- info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+ info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
} else if (info->intf != NULL) {
@@ -257,7 +257,7 @@ static int xen_pv_console_init(void)
info = vtermno_to_xencons(HVC_COOKIE);
if (!info) {
- info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+ info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
} else if (info->intf != NULL) {
@@ -284,7 +284,7 @@ static int xen_initial_domain_console_init(void)
info = vtermno_to_xencons(HVC_COOKIE);
if (!info) {
- info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+ info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
}
diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c
index 3396eb9d57a..ac2767100df 100644
--- a/drivers/tty/hvc/hvsi_lib.c
+++ b/drivers/tty/hvc/hvsi_lib.c
@@ -341,8 +341,8 @@ void hvsilib_establish(struct hvsi_priv *pv)
pr_devel("HVSI@%x: ... waiting handshake\n", pv->termno);
- /* Try for up to 200s */
- for (timeout = 0; timeout < 20; timeout++) {
+ /* Try for up to 400ms */
+ for (timeout = 0; timeout < 40; timeout++) {
if (pv->established)
goto established;
if (!hvsi_get_packet(pv))
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 642239015b4..c0f76da5530 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -807,7 +807,7 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
int h = dlci->adaption - 1;
total_size = 0;
- while(1) {
+ while (1) {
len = kfifo_len(dlci->fifo);
if (len == 0)
return total_size;
@@ -827,8 +827,8 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
switch (dlci->adaption) {
case 1: /* Unstructured */
break;
- case 2: /* Unstructed with modem bits. Always one byte as we never
- send inline break data */
+ case 2: /* Unstructed with modem bits.
+ Always one byte as we never send inline break data */
*dp++ = gsm_encode_modem(dlci);
break;
}
@@ -968,7 +968,7 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
unsigned long flags;
int sweep;
- if (dlci->constipated)
+ if (dlci->constipated)
return;
spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
@@ -981,7 +981,7 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
gsm_dlci_data_output(dlci->gsm, dlci);
}
if (sweep)
- gsm_dlci_data_sweep(dlci->gsm);
+ gsm_dlci_data_sweep(dlci->gsm);
spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
}
@@ -1138,7 +1138,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
{
struct tty_port *port;
- unsigned int addr = 0 ;
+ unsigned int addr = 0;
u8 bits;
int len = clen;
u8 *dp = data;
@@ -1740,10 +1740,11 @@ static void gsm_queue(struct gsm_mux *gsm)
if ((gsm->control & ~PF) == UI)
gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
- if (gsm->encoding == 0){
- /* WARNING: gsm->received_fcs is used for gsm->encoding = 0 only.
- In this case it contain the last piece of data
- required to generate final CRC */
+ if (gsm->encoding == 0) {
+ /* WARNING: gsm->received_fcs is used for
+ gsm->encoding = 0 only.
+ In this case it contain the last piece of data
+ required to generate final CRC */
gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
}
if (gsm->fcs != GOOD_FCS) {
@@ -2904,9 +2905,11 @@ static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
gsm = gsm_mux[mux];
if (gsm->dead)
return -EL2HLT;
- /* If DLCI 0 is not yet fully open return an error. This is ok from a locking
- perspective as we don't have to worry about this if DLCI0 is lost */
- if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN)
+ /* If DLCI 0 is not yet fully open return an error.
+ This is ok from a locking
+ perspective as we don't have to worry about this
+ if DLCI0 is lost */
+ if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN)
return -EL2NSYNC;
dlci = gsm->dlci[line];
if (dlci == NULL) {
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 4bf0fc0843d..c9a9ddd1d0b 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -50,6 +50,7 @@
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/ratelimit.h>
+#include <linux/vmalloc.h>
/* number of characters left in xmit buffer before select has we have room */
@@ -74,37 +75,81 @@
#define ECHO_OP_SET_CANON_COL 0x81
#define ECHO_OP_ERASE_TAB 0x82
+#define ECHO_COMMIT_WATERMARK 256
+#define ECHO_BLOCK 256
+#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
+
+
+#undef N_TTY_TRACE
+#ifdef N_TTY_TRACE
+# define n_tty_trace(f, args...) trace_printk(f, ##args)
+#else
+# define n_tty_trace(f, args...)
+#endif
+
struct n_tty_data {
- unsigned int column;
+ /* producer-published */
+ size_t read_head;
+ size_t canon_head;
+ size_t echo_head;
+ size_t echo_commit;
+ DECLARE_BITMAP(char_map, 256);
+
+ /* private to n_tty_receive_overrun (single-threaded) */
unsigned long overrun_time;
int num_overrun;
+ /* non-atomic */
+ bool no_room;
+
+ /* must hold exclusive termios_rwsem to reset these */
unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
- unsigned char echo_overrun:1;
- DECLARE_BITMAP(process_char_map, 256);
+ /* shared by producer and consumer */
+ char read_buf[N_TTY_BUF_SIZE];
DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
+ unsigned char echo_buf[N_TTY_BUF_SIZE];
- char *read_buf;
- int read_head;
- int read_tail;
- int read_cnt;
int minimum_to_wake;
- unsigned char *echo_buf;
- unsigned int echo_pos;
- unsigned int echo_cnt;
+ /* consumer-published */
+ size_t read_tail;
+ size_t line_start;
- int canon_data;
- unsigned long canon_head;
+ /* protected by output lock */
+ unsigned int column;
unsigned int canon_column;
+ size_t echo_tail;
struct mutex atomic_read_lock;
struct mutex output_lock;
- struct mutex echo_lock;
- raw_spinlock_t read_lock;
};
+static inline size_t read_cnt(struct n_tty_data *ldata)
+{
+ return ldata->read_head - ldata->read_tail;
+}
+
+static inline unsigned char read_buf(struct n_tty_data *ldata, size_t i)
+{
+ return ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)];
+}
+
+static inline unsigned char *read_buf_addr(struct n_tty_data *ldata, size_t i)
+{
+ return &ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)];
+}
+
+static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i)
+{
+ return ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
+}
+
+static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
+{
+ return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
+}
+
static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
unsigned char __user *ptr)
{
@@ -114,33 +159,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
return put_user(x, ptr);
}
-/**
- * n_tty_set_room - receive space
- * @tty: terminal
- *
- * Updates tty->receive_room to reflect the currently available space
- * in the input buffer, and re-schedules the flip buffer work if space
- * just became available.
- *
- * Locks: Concurrent update is protected with read_lock
- */
-
-static int set_room(struct tty_struct *tty)
+static int receive_room(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
int left;
- int old_left;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
if (I_PARMRK(tty)) {
/* Multiply read_cnt by 3, since each byte might take up to
* three times as many spaces when PARMRK is set (depending on
* its flags, e.g. parity error). */
- left = N_TTY_BUF_SIZE - ldata->read_cnt * 3 - 1;
+ left = N_TTY_BUF_SIZE - read_cnt(ldata) * 3 - 1;
} else
- left = N_TTY_BUF_SIZE - ldata->read_cnt - 1;
+ left = N_TTY_BUF_SIZE - read_cnt(ldata) - 1;
/*
* If we are doing input canonicalization, and there are no
@@ -149,19 +179,31 @@ static int set_room(struct tty_struct *tty)
* characters will be beeped.
*/
if (left <= 0)
- left = ldata->icanon && !ldata->canon_data;
- old_left = tty->receive_room;
- tty->receive_room = left;
+ left = ldata->icanon && ldata->canon_head == ldata->read_tail;
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
-
- return left && !old_left;
+ return left;
}
+/**
+ * n_tty_set_room - receive space
+ * @tty: terminal
+ *
+ * Re-schedules the flip buffer work if space just became available.
+ *
+ * Caller holds exclusive termios_rwsem
+ * or
+ * n_tty_read()/consumer path:
+ * holds non-exclusive termios_rwsem
+ */
+
static void n_tty_set_room(struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
+
/* Did this open up the receive buffer? We may need to flip */
- if (set_room(tty)) {
+ if (unlikely(ldata->no_room) && receive_room(tty)) {
+ ldata->no_room = 0;
+
WARN_RATELIMIT(tty->port->itty == NULL,
"scheduling with invalid itty\n");
/* see if ldisc has been killed - if so, this means that
@@ -170,17 +212,93 @@ static void n_tty_set_room(struct tty_struct *tty)
*/
WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
"scheduling buffer work for halted ldisc\n");
- schedule_work(&tty->port->buf.work);
+ queue_work(system_unbound_wq, &tty->port->buf.work);
}
}
-static void put_tty_queue_nolock(unsigned char c, struct n_tty_data *ldata)
+static ssize_t chars_in_buffer(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ ssize_t n = 0;
+
+ if (!ldata->icanon)
+ n = read_cnt(ldata);
+ else
+ n = ldata->canon_head - ldata->read_tail;
+ return n;
+}
+
+/**
+ * n_tty_write_wakeup - asynchronous I/O notifier
+ * @tty: tty device
+ *
+ * Required for the ptys, serial driver etc. since processes
+ * that attach themselves to the master and rely on ASYNC
+ * IO must be woken up
+ */
+
+static void n_tty_write_wakeup(struct tty_struct *tty)
{
- if (ldata->read_cnt < N_TTY_BUF_SIZE) {
- ldata->read_buf[ldata->read_head] = c;
- ldata->read_head = (ldata->read_head + 1) & (N_TTY_BUF_SIZE-1);
- ldata->read_cnt++;
+ if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
+ kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
+}
+
+static void n_tty_check_throttle(struct tty_struct *tty)
+{
+ if (tty->driver->type == TTY_DRIVER_TYPE_PTY)
+ return;
+ /*
+ * Check the remaining room for the input canonicalization
+ * mode. We don't want to throttle the driver if we're in
+ * canonical mode and don't have a newline yet!
+ */
+ while (1) {
+ int throttled;
+ tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
+ if (receive_room(tty) >= TTY_THRESHOLD_THROTTLE)
+ break;
+ throttled = tty_throttle_safe(tty);
+ if (!throttled)
+ break;
+ }
+ __tty_set_flow_change(tty, 0);
+}
+
+static void n_tty_check_unthrottle(struct tty_struct *tty)
+{
+ if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+ tty->link->ldisc->ops->write_wakeup == n_tty_write_wakeup) {
+ if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
+ return;
+ if (!tty->count)
+ return;
+ n_tty_set_room(tty);
+ n_tty_write_wakeup(tty->link);
+ wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
+ return;
+ }
+
+ /* If there is enough space in the read buffer now, let the
+ * low-level driver know. We use chars_in_buffer() to
+ * check the buffer, as it now knows about canonical mode.
+ * Otherwise, if the driver is throttled and the line is
+ * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
+ * we won't get any more characters.
+ */
+
+ while (1) {
+ int unthrottled;
+ tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
+ if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
+ break;
+ if (!tty->count)
+ break;
+ n_tty_set_room(tty);
+ unthrottled = tty_unthrottle_safe(tty);
+ if (!unthrottled)
+ break;
}
+ __tty_set_flow_change(tty, 0);
}
/**
@@ -188,21 +306,19 @@ static void put_tty_queue_nolock(unsigned char c, struct n_tty_data *ldata)
* @c: character
* @ldata: n_tty data
*
- * Add a character to the tty read_buf queue. This is done under the
- * read_lock to serialize character addition and also to protect us
- * against parallel reads or flushes
+ * Add a character to the tty read_buf queue.
+ *
+ * n_tty_receive_buf()/producer path:
+ * caller holds non-exclusive termios_rwsem
+ * modifies read_head
+ *
+ * read_head is only considered 'published' if canonical mode is
+ * not active.
*/
-static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
+static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
{
- unsigned long flags;
- /*
- * The problem of stomping on the buffers ends here.
- * Why didn't anyone see this one coming? --AJK
- */
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- put_tty_queue_nolock(c, ldata);
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
+ *read_buf_addr(ldata, ldata->read_head++) = c;
}
/**
@@ -212,22 +328,17 @@ static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
* Reset the read buffer counters and clear the flags.
* Called from n_tty_open() and n_tty_flush_buffer().
*
- * Locking: tty_read_lock for read fields.
+ * Locking: caller holds exclusive termios_rwsem
+ * (or locking is not required)
*/
static void reset_buffer_flags(struct n_tty_data *ldata)
{
- unsigned long flags;
+ ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
+ ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
+ ldata->line_start = 0;
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- ldata->read_head = ldata->read_tail = ldata->read_cnt = 0;
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
-
- mutex_lock(&ldata->echo_lock);
- ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0;
- mutex_unlock(&ldata->echo_lock);
-
- ldata->canon_head = ldata->canon_data = ldata->erasing = 0;
+ ldata->erasing = 0;
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
}
@@ -251,16 +362,21 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)
* buffer flushed (eg at hangup) or when the N_TTY line discipline
* internally has to clean the pending queue (for example some signals).
*
- * Locking: ctrl_lock, read_lock.
+ * Holds termios_rwsem to exclude producer/consumer while
+ * buffer indices are reset.
+ *
+ * Locking: ctrl_lock, exclusive termios_rwsem
*/
static void n_tty_flush_buffer(struct tty_struct *tty)
{
+ down_write(&tty->termios_rwsem);
reset_buffer_flags(tty->disc_data);
n_tty_set_room(tty);
if (tty->link)
n_tty_packet_mode_flush(tty);
+ up_write(&tty->termios_rwsem);
}
/**
@@ -270,24 +386,18 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
* Report the number of characters buffered to be delivered to user
* at this instant in time.
*
- * Locking: read_lock
+ * Locking: exclusive termios_rwsem
*/
static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
{
- struct n_tty_data *ldata = tty->disc_data;
- unsigned long flags;
- ssize_t n = 0;
+ ssize_t n;
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- if (!ldata->icanon) {
- n = ldata->read_cnt;
- } else if (ldata->canon_data) {
- n = (ldata->canon_head > ldata->read_tail) ?
- ldata->canon_head - ldata->read_tail :
- ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail);
- }
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
+ WARN_ONCE(1, "%s is deprecated and scheduled for removal.", __func__);
+
+ down_write(&tty->termios_rwsem);
+ n = chars_in_buffer(tty);
+ up_write(&tty->termios_rwsem);
return n;
}
@@ -532,33 +642,23 @@ break_out:
* are prioritized. Also, when control characters are echoed with a
* prefixed "^", the pair is treated atomically and thus not separated.
*
- * Locking: output_lock to protect column state and space left,
- * echo_lock to protect the echo buffer
+ * Locking: callers must hold output_lock
*/
-static void process_echoes(struct tty_struct *tty)
+static size_t __process_echoes(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
- int space, nr;
+ int space, old_space;
+ size_t tail;
unsigned char c;
- unsigned char *cp, *buf_end;
-
- if (!ldata->echo_cnt)
- return;
-
- mutex_lock(&ldata->output_lock);
- mutex_lock(&ldata->echo_lock);
- space = tty_write_room(tty);
+ old_space = space = tty_write_room(tty);
- buf_end = ldata->echo_buf + N_TTY_BUF_SIZE;
- cp = ldata->echo_buf + ldata->echo_pos;
- nr = ldata->echo_cnt;
- while (nr > 0) {
- c = *cp;
+ tail = ldata->echo_tail;
+ while (ldata->echo_commit != tail) {
+ c = echo_buf(ldata, tail);
if (c == ECHO_OP_START) {
unsigned char op;
- unsigned char *opp;
int no_space_left = 0;
/*
@@ -566,18 +666,13 @@ static void process_echoes(struct tty_struct *tty)
* operation, get the next byte, which is either the
* op code or a control character value.
*/
- opp = cp + 1;
- if (opp == buf_end)
- opp -= N_TTY_BUF_SIZE;
- op = *opp;
+ op = echo_buf(ldata, tail + 1);
switch (op) {
unsigned int num_chars, num_bs;
case ECHO_OP_ERASE_TAB:
- if (++opp == buf_end)
- opp -= N_TTY_BUF_SIZE;
- num_chars = *opp;
+ num_chars = echo_buf(ldata, tail + 2);
/*
* Determine how many columns to go back
@@ -603,21 +698,18 @@ static void process_echoes(struct tty_struct *tty)
if (ldata->column > 0)
ldata->column--;
}
- cp += 3;
- nr -= 3;
+ tail += 3;
break;
case ECHO_OP_SET_CANON_COL:
ldata->canon_column = ldata->column;
- cp += 2;
- nr -= 2;
+ tail += 2;
break;
case ECHO_OP_MOVE_BACK_COL:
if (ldata->column > 0)
ldata->column--;
- cp += 2;
- nr -= 2;
+ tail += 2;
break;
case ECHO_OP_START:
@@ -629,8 +721,7 @@ static void process_echoes(struct tty_struct *tty)
tty_put_char(tty, ECHO_OP_START);
ldata->column++;
space--;
- cp += 2;
- nr -= 2;
+ tail += 2;
break;
default:
@@ -651,8 +742,7 @@ static void process_echoes(struct tty_struct *tty)
tty_put_char(tty, op ^ 0100);
ldata->column += 2;
space -= 2;
- cp += 2;
- nr -= 2;
+ tail += 2;
}
if (no_space_left)
@@ -669,80 +759,92 @@ static void process_echoes(struct tty_struct *tty)
tty_put_char(tty, c);
space -= 1;
}
- cp += 1;
- nr -= 1;
+ tail += 1;
}
-
- /* When end of circular buffer reached, wrap around */
- if (cp >= buf_end)
- cp -= N_TTY_BUF_SIZE;
}
- if (nr == 0) {
- ldata->echo_pos = 0;
- ldata->echo_cnt = 0;
- ldata->echo_overrun = 0;
- } else {
- int num_processed = ldata->echo_cnt - nr;
- ldata->echo_pos += num_processed;
- ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
- ldata->echo_cnt = nr;
- if (num_processed > 0)
- ldata->echo_overrun = 0;
+ /* If the echo buffer is nearly full (so that the possibility exists
+ * of echo overrun before the next commit), then discard enough
+ * data at the tail to prevent a subsequent overrun */
+ while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
+ if (echo_buf(ldata, tail == ECHO_OP_START)) {
+ if (echo_buf(ldata, tail) == ECHO_OP_ERASE_TAB)
+ tail += 3;
+ else
+ tail += 2;
+ } else
+ tail++;
}
- mutex_unlock(&ldata->echo_lock);
+ ldata->echo_tail = tail;
+ return old_space - space;
+}
+
+static void commit_echoes(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ size_t nr, old, echoed;
+ size_t head;
+
+ head = ldata->echo_head;
+ old = ldata->echo_commit - ldata->echo_tail;
+
+ /* Process committed echoes if the accumulated # of bytes
+ * is over the threshold (and try again each time another
+ * block is accumulated) */
+ nr = head - ldata->echo_tail;
+ if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK))
+ return;
+
+ mutex_lock(&ldata->output_lock);
+ ldata->echo_commit = head;
+ echoed = __process_echoes(tty);
+ mutex_unlock(&ldata->output_lock);
+
+ if (echoed && tty->ops->flush_chars)
+ tty->ops->flush_chars(tty);
+}
+
+static void process_echoes(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ size_t echoed;
+
+ if (!L_ECHO(tty) || ldata->echo_commit == ldata->echo_tail)
+ return;
+
+ mutex_lock(&ldata->output_lock);
+ echoed = __process_echoes(tty);
mutex_unlock(&ldata->output_lock);
- if (tty->ops->flush_chars)
+ if (echoed && tty->ops->flush_chars)
tty->ops->flush_chars(tty);
}
+static void flush_echoes(struct tty_struct *tty)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ if (!L_ECHO(tty) || ldata->echo_commit == ldata->echo_head)
+ return;
+
+ mutex_lock(&ldata->output_lock);
+ ldata->echo_commit = ldata->echo_head;
+ __process_echoes(tty);
+ mutex_unlock(&ldata->output_lock);
+}
+
/**
* add_echo_byte - add a byte to the echo buffer
* @c: unicode byte to echo
* @ldata: n_tty data
*
* Add a character or operation byte to the echo buffer.
- *
- * Should be called under the echo lock to protect the echo buffer.
*/
-static void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
+static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
{
- int new_byte_pos;
-
- if (ldata->echo_cnt == N_TTY_BUF_SIZE) {
- /* Circular buffer is already at capacity */
- new_byte_pos = ldata->echo_pos;
-
- /*
- * Since the buffer start position needs to be advanced,
- * be sure to step by a whole operation byte group.
- */
- if (ldata->echo_buf[ldata->echo_pos] == ECHO_OP_START) {
- if (ldata->echo_buf[(ldata->echo_pos + 1) &
- (N_TTY_BUF_SIZE - 1)] ==
- ECHO_OP_ERASE_TAB) {
- ldata->echo_pos += 3;
- ldata->echo_cnt -= 2;
- } else {
- ldata->echo_pos += 2;
- ldata->echo_cnt -= 1;
- }
- } else {
- ldata->echo_pos++;
- }
- ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
-
- ldata->echo_overrun = 1;
- } else {
- new_byte_pos = ldata->echo_pos + ldata->echo_cnt;
- new_byte_pos &= N_TTY_BUF_SIZE - 1;
- ldata->echo_cnt++;
- }
-
- ldata->echo_buf[new_byte_pos] = c;
+ *echo_buf_addr(ldata, ldata->echo_head++) = c;
}
/**
@@ -750,16 +852,12 @@ static void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
* @ldata: n_tty data
*
* Add an operation to the echo buffer to move back one column.
- *
- * Locking: echo_lock to protect the echo buffer
*/
static void echo_move_back_col(struct n_tty_data *ldata)
{
- mutex_lock(&ldata->echo_lock);
add_echo_byte(ECHO_OP_START, ldata);
add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata);
- mutex_unlock(&ldata->echo_lock);
}
/**
@@ -768,16 +866,12 @@ static void echo_move_back_col(struct n_tty_data *ldata)
*
* Add an operation to the echo buffer to set the canon column
* to the current column.
- *
- * Locking: echo_lock to protect the echo buffer
*/
static void echo_set_canon_col(struct n_tty_data *ldata)
{
- mutex_lock(&ldata->echo_lock);
add_echo_byte(ECHO_OP_START, ldata);
add_echo_byte(ECHO_OP_SET_CANON_COL, ldata);
- mutex_unlock(&ldata->echo_lock);
}
/**
@@ -793,15 +887,11 @@ static void echo_set_canon_col(struct n_tty_data *ldata)
* of input. This information will be used later, along with
* canon column (if applicable), to go back the correct number
* of columns.
- *
- * Locking: echo_lock to protect the echo buffer
*/
static void echo_erase_tab(unsigned int num_chars, int after_tab,
struct n_tty_data *ldata)
{
- mutex_lock(&ldata->echo_lock);
-
add_echo_byte(ECHO_OP_START, ldata);
add_echo_byte(ECHO_OP_ERASE_TAB, ldata);
@@ -813,8 +903,6 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab,
num_chars |= 0x80;
add_echo_byte(num_chars, ldata);
-
- mutex_unlock(&ldata->echo_lock);
}
/**
@@ -826,20 +914,16 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab,
* L_ECHO(tty) is true. Called from the driver receive_buf path.
*
* This variant does not treat control characters specially.
- *
- * Locking: echo_lock to protect the echo buffer
*/
static void echo_char_raw(unsigned char c, struct n_tty_data *ldata)
{
- mutex_lock(&ldata->echo_lock);
if (c == ECHO_OP_START) {
add_echo_byte(ECHO_OP_START, ldata);
add_echo_byte(ECHO_OP_START, ldata);
} else {
add_echo_byte(c, ldata);
}
- mutex_unlock(&ldata->echo_lock);
}
/**
@@ -852,16 +936,12 @@ static void echo_char_raw(unsigned char c, struct n_tty_data *ldata)
*
* This variant tags control characters to be echoed as "^X"
* (where X is the letter representing the control char).
- *
- * Locking: echo_lock to protect the echo buffer
*/
static void echo_char(unsigned char c, struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
- mutex_lock(&ldata->echo_lock);
-
if (c == ECHO_OP_START) {
add_echo_byte(ECHO_OP_START, ldata);
add_echo_byte(ECHO_OP_START, ldata);
@@ -870,8 +950,6 @@ static void echo_char(unsigned char c, struct tty_struct *tty)
add_echo_byte(ECHO_OP_START, ldata);
add_echo_byte(c, ldata);
}
-
- mutex_unlock(&ldata->echo_lock);
}
/**
@@ -896,17 +974,22 @@ static inline void finish_erasing(struct n_tty_data *ldata)
* present in the stream from the driver layer. Handles the complexities
* of UTF-8 multibyte symbols.
*
- * Locking: read_lock for tty buffers
+ * n_tty_receive_buf()/producer path:
+ * caller holds non-exclusive termios_rwsem
+ * modifies read_head
+ *
+ * Modifying the read_head is not considered a publish in this context
+ * because canonical mode is active -- only canon_head publishes
*/
static void eraser(unsigned char c, struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
enum { ERASE, WERASE, KILL } kill_type;
- int head, seen_alnums, cnt;
- unsigned long flags;
+ size_t head;
+ size_t cnt;
+ int seen_alnums;
- /* FIXME: locking needed ? */
if (ldata->read_head == ldata->canon_head) {
/* process_output('\a', tty); */ /* what do you think? */
return;
@@ -917,19 +1000,11 @@ static void eraser(unsigned char c, struct tty_struct *tty)
kill_type = WERASE;
else {
if (!L_ECHO(tty)) {
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
- (N_TTY_BUF_SIZE - 1));
ldata->read_head = ldata->canon_head;
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
return;
}
if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
- (N_TTY_BUF_SIZE - 1));
ldata->read_head = ldata->canon_head;
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
finish_erasing(ldata);
echo_char(KILL_CHAR(tty), tty);
/* Add a newline if ECHOK is on and ECHOKE is off. */
@@ -941,14 +1016,13 @@ static void eraser(unsigned char c, struct tty_struct *tty)
}
seen_alnums = 0;
- /* FIXME: Locking ?? */
while (ldata->read_head != ldata->canon_head) {
head = ldata->read_head;
/* erase a single possibly multibyte character */
do {
- head = (head - 1) & (N_TTY_BUF_SIZE-1);
- c = ldata->read_buf[head];
+ head--;
+ c = read_buf(ldata, head);
} while (is_continuation(c, tty) && head != ldata->canon_head);
/* do not partially erase */
@@ -962,11 +1036,8 @@ static void eraser(unsigned char c, struct tty_struct *tty)
else if (seen_alnums)
break;
}
- cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1);
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
+ cnt = ldata->read_head - head;
ldata->read_head = head;
- ldata->read_cnt -= cnt;
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) {
if (!ldata->erasing) {
@@ -976,9 +1047,8 @@ static void eraser(unsigned char c, struct tty_struct *tty)
/* if cnt > 1, output a multi-byte character */
echo_char(c, tty);
while (--cnt > 0) {
- head = (head+1) & (N_TTY_BUF_SIZE-1);
- echo_char_raw(ldata->read_buf[head],
- ldata);
+ head++;
+ echo_char_raw(read_buf(ldata, head), ldata);
echo_move_back_col(ldata);
}
} else if (kill_type == ERASE && !L_ECHOE(tty)) {
@@ -986,7 +1056,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
} else if (c == '\t') {
unsigned int num_chars = 0;
int after_tab = 0;
- unsigned long tail = ldata->read_head;
+ size_t tail = ldata->read_head;
/*
* Count the columns used for characters
@@ -996,8 +1066,8 @@ static void eraser(unsigned char c, struct tty_struct *tty)
* number of columns.
*/
while (tail != ldata->canon_head) {
- tail = (tail-1) & (N_TTY_BUF_SIZE-1);
- c = ldata->read_buf[tail];
+ tail--;
+ c = read_buf(ldata, tail);
if (c == '\t') {
after_tab = 1;
break;
@@ -1040,7 +1110,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
* Locking: ctrl_lock
*/
-static inline void isig(int sig, struct tty_struct *tty)
+static void isig(int sig, struct tty_struct *tty)
{
struct pid *tty_pgrp = tty_get_pgrp(tty);
if (tty_pgrp) {
@@ -1056,10 +1126,14 @@ static inline void isig(int sig, struct tty_struct *tty)
* An RS232 break event has been hit in the incoming bitstream. This
* can cause a variety of events depending upon the termios settings.
*
- * Called from the receive_buf path so single threaded.
+ * n_tty_receive_buf()/producer path:
+ * caller holds non-exclusive termios_rwsem
+ * publishes read_head via put_tty_queue()
+ *
+ * Note: may get exclusive termios_rwsem if flushing input buffer
*/
-static inline void n_tty_receive_break(struct tty_struct *tty)
+static void n_tty_receive_break(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
@@ -1068,8 +1142,11 @@ static inline void n_tty_receive_break(struct tty_struct *tty)
if (I_BRKINT(tty)) {
isig(SIGINT, tty);
if (!L_NOFLSH(tty)) {
+ /* flushing needs exclusive termios_rwsem */
+ up_read(&tty->termios_rwsem);
n_tty_flush_buffer(tty);
tty_driver_flush_buffer(tty);
+ down_read(&tty->termios_rwsem);
}
return;
}
@@ -1094,7 +1171,7 @@ static inline void n_tty_receive_break(struct tty_struct *tty)
* private.
*/
-static inline void n_tty_receive_overrun(struct tty_struct *tty)
+static void n_tty_receive_overrun(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
char buf[64];
@@ -1116,10 +1193,13 @@ static inline void n_tty_receive_overrun(struct tty_struct *tty)
* @c: character
*
* Process a parity error and queue the right data to indicate
- * the error case if necessary. Locking as per n_tty_receive_buf.
+ * the error case if necessary.
+ *
+ * n_tty_receive_buf()/producer path:
+ * caller holds non-exclusive termios_rwsem
+ * publishes read_head via put_tty_queue()
*/
-static inline void n_tty_receive_parity_error(struct tty_struct *tty,
- unsigned char c)
+static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
@@ -1136,6 +1216,26 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty,
wake_up_interruptible(&tty->read_wait);
}
+static void
+n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
+{
+ if (!L_NOFLSH(tty)) {
+ /* flushing needs exclusive termios_rwsem */
+ up_read(&tty->termios_rwsem);
+ n_tty_flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
+ down_read(&tty->termios_rwsem);
+ }
+ if (I_IXON(tty))
+ start_tty(tty);
+ if (L_ECHO(tty)) {
+ echo_char(c, tty);
+ commit_echoes(tty);
+ }
+ isig(signal, tty);
+ return;
+}
+
/**
* n_tty_receive_char - perform processing
* @tty: terminal device
@@ -1144,117 +1244,54 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty,
* Process an individual character of input received from the driver.
* This is serialized with respect to itself by the rules for the
* driver above.
+ *
+ * n_tty_receive_buf()/producer path:
+ * caller holds non-exclusive termios_rwsem
+ * publishes canon_head if canonical mode is active
+ * otherwise, publishes read_head via put_tty_queue()
+ *
+ * Returns 1 if LNEXT was received, else returns 0
*/
-static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
+static int
+n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
- unsigned long flags;
int parmrk;
- if (ldata->raw) {
- put_tty_queue(c, ldata);
- return;
- }
-
- if (I_ISTRIP(tty))
- c &= 0x7f;
- if (I_IUCLC(tty) && L_IEXTEN(tty))
- c = tolower(c);
-
- if (L_EXTPROC(tty)) {
- put_tty_queue(c, ldata);
- return;
- }
-
- if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
- I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
- c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
- start_tty(tty);
- process_echoes(tty);
- }
-
- if (tty->closing) {
- if (I_IXON(tty)) {
- if (c == START_CHAR(tty)) {
- start_tty(tty);
- process_echoes(tty);
- } else if (c == STOP_CHAR(tty))
- stop_tty(tty);
- }
- return;
- }
-
- /*
- * If the previous character was LNEXT, or we know that this
- * character is not one of the characters that we'll have to
- * handle specially, do shortcut processing to speed things
- * up.
- */
- if (!test_bit(c, ldata->process_char_map) || ldata->lnext) {
- ldata->lnext = 0;
- parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
- if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
- /* beep if no space */
- if (L_ECHO(tty))
- process_output('\a', tty);
- return;
- }
- if (L_ECHO(tty)) {
- finish_erasing(ldata);
- /* Record the column of first canon char. */
- if (ldata->canon_head == ldata->read_head)
- echo_set_canon_col(ldata);
- echo_char(c, tty);
- process_echoes(tty);
- }
- if (parmrk)
- put_tty_queue(c, ldata);
- put_tty_queue(c, ldata);
- return;
- }
-
if (I_IXON(tty)) {
if (c == START_CHAR(tty)) {
start_tty(tty);
- process_echoes(tty);
- return;
+ commit_echoes(tty);
+ return 0;
}
if (c == STOP_CHAR(tty)) {
stop_tty(tty);
- return;
+ return 0;
}
}
if (L_ISIG(tty)) {
- int signal;
- signal = SIGINT;
- if (c == INTR_CHAR(tty))
- goto send_signal;
- signal = SIGQUIT;
- if (c == QUIT_CHAR(tty))
- goto send_signal;
- signal = SIGTSTP;
- if (c == SUSP_CHAR(tty)) {
-send_signal:
- if (!L_NOFLSH(tty)) {
- n_tty_flush_buffer(tty);
- tty_driver_flush_buffer(tty);
- }
- if (I_IXON(tty))
- start_tty(tty);
- if (L_ECHO(tty)) {
- echo_char(c, tty);
- process_echoes(tty);
- }
- isig(signal, tty);
- return;
+ if (c == INTR_CHAR(tty)) {
+ n_tty_receive_signal_char(tty, SIGINT, c);
+ return 0;
+ } else if (c == QUIT_CHAR(tty)) {
+ n_tty_receive_signal_char(tty, SIGQUIT, c);
+ return 0;
+ } else if (c == SUSP_CHAR(tty)) {
+ n_tty_receive_signal_char(tty, SIGTSTP, c);
+ return 0;
}
}
+ if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+ start_tty(tty);
+ process_echoes(tty);
+ }
+
if (c == '\r') {
if (I_IGNCR(tty))
- return;
+ return 0;
if (I_ICRNL(tty))
c = '\n';
} else if (c == '\n' && I_INLCR(tty))
@@ -1264,8 +1301,8 @@ send_signal:
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
eraser(c, tty);
- process_echoes(tty);
- return;
+ commit_echoes(tty);
+ return 0;
}
if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
ldata->lnext = 1;
@@ -1274,42 +1311,32 @@ send_signal:
if (L_ECHOCTL(tty)) {
echo_char_raw('^', ldata);
echo_char_raw('\b', ldata);
- process_echoes(tty);
+ commit_echoes(tty);
}
}
- return;
+ return 1;
}
- if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
- L_IEXTEN(tty)) {
- unsigned long tail = ldata->canon_head;
+ if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) {
+ size_t tail = ldata->canon_head;
finish_erasing(ldata);
echo_char(c, tty);
echo_char_raw('\n', ldata);
while (tail != ldata->read_head) {
- echo_char(ldata->read_buf[tail], tty);
- tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+ echo_char(read_buf(ldata, tail), tty);
+ tail++;
}
- process_echoes(tty);
- return;
+ commit_echoes(tty);
+ return 0;
}
if (c == '\n') {
- if (ldata->read_cnt >= N_TTY_BUF_SIZE) {
- if (L_ECHO(tty))
- process_output('\a', tty);
- return;
- }
if (L_ECHO(tty) || L_ECHONL(tty)) {
echo_char_raw('\n', ldata);
- process_echoes(tty);
+ commit_echoes(tty);
}
goto handle_newline;
}
if (c == EOF_CHAR(tty)) {
- if (ldata->read_cnt >= N_TTY_BUF_SIZE)
- return;
- if (ldata->canon_head != ldata->read_head)
- set_bit(TTY_PUSH, &tty->flags);
c = __DISABLED_CHAR;
goto handle_newline;
}
@@ -1317,11 +1344,6 @@ send_signal:
(c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
? 1 : 0;
- if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
- if (L_ECHO(tty))
- process_output('\a', tty);
- return;
- }
/*
* XXX are EOL_CHAR and EOL2_CHAR echoed?!?
*/
@@ -1330,7 +1352,7 @@ send_signal:
if (ldata->canon_head == ldata->read_head)
echo_set_canon_col(ldata);
echo_char(c, tty);
- process_echoes(tty);
+ commit_echoes(tty);
}
/*
* XXX does PARMRK doubling happen for
@@ -1340,26 +1362,17 @@ send_signal:
put_tty_queue(c, ldata);
handle_newline:
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- set_bit(ldata->read_head, ldata->read_flags);
- put_tty_queue_nolock(c, ldata);
+ set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags);
+ put_tty_queue(c, ldata);
ldata->canon_head = ldata->read_head;
- ldata->canon_data++;
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
- return;
+ return 0;
}
}
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
- if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
- /* beep if no space */
- if (L_ECHO(tty))
- process_output('\a', tty);
- return;
- }
if (L_ECHO(tty)) {
finish_erasing(ldata);
if (c == '\n')
@@ -1370,29 +1383,123 @@ handle_newline:
echo_set_canon_col(ldata);
echo_char(c, tty);
}
- process_echoes(tty);
+ commit_echoes(tty);
}
if (parmrk)
put_tty_queue(c, ldata);
put_tty_queue(c, ldata);
+ return 0;
}
+static inline void
+n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ int parmrk;
-/**
- * n_tty_write_wakeup - asynchronous I/O notifier
- * @tty: tty device
- *
- * Required for the ptys, serial driver etc. since processes
- * that attach themselves to the master and rely on ASYNC
- * IO must be woken up
- */
+ if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+ start_tty(tty);
+ process_echoes(tty);
+ }
+ if (L_ECHO(tty)) {
+ finish_erasing(ldata);
+ /* Record the column of first canon char. */
+ if (ldata->canon_head == ldata->read_head)
+ echo_set_canon_col(ldata);
+ echo_char(c, tty);
+ commit_echoes(tty);
+ }
+ parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
+ if (parmrk)
+ put_tty_queue(c, ldata);
+ put_tty_queue(c, ldata);
+}
-static void n_tty_write_wakeup(struct tty_struct *tty)
+static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{
- if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
- kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
+ n_tty_receive_char_inline(tty, c);
+}
+
+static inline void
+n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+ start_tty(tty);
+ process_echoes(tty);
+ }
+ if (L_ECHO(tty)) {
+ finish_erasing(ldata);
+ /* Record the column of first canon char. */
+ if (ldata->canon_head == ldata->read_head)
+ echo_set_canon_col(ldata);
+ echo_char(c, tty);
+ commit_echoes(tty);
+ }
+ put_tty_queue(c, ldata);
+}
+
+static inline void
+n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
+{
+ if (I_ISTRIP(tty))
+ c &= 0x7f;
+ if (I_IUCLC(tty) && L_IEXTEN(tty))
+ c = tolower(c);
+
+ if (I_IXON(tty)) {
+ if (c == STOP_CHAR(tty))
+ stop_tty(tty);
+ else if (c == START_CHAR(tty) ||
+ (tty->stopped && !tty->flow_stopped && I_IXANY(tty) &&
+ c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) &&
+ c != SUSP_CHAR(tty))) {
+ start_tty(tty);
+ process_echoes(tty);
+ }
+ }
+}
+
+static void
+n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
+{
+ char buf[64];
+
+ switch (flag) {
+ case TTY_BREAK:
+ n_tty_receive_break(tty);
+ break;
+ case TTY_PARITY:
+ case TTY_FRAME:
+ n_tty_receive_parity_error(tty, c);
+ break;
+ case TTY_OVERRUN:
+ n_tty_receive_overrun(tty);
+ break;
+ default:
+ printk(KERN_ERR "%s: unknown flag %d\n",
+ tty_name(tty, buf), flag);
+ break;
+ }
+}
+
+static void
+n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+
+ ldata->lnext = 0;
+ if (likely(flag == TTY_NORMAL)) {
+ if (I_ISTRIP(tty))
+ c &= 0x7f;
+ if (I_IUCLC(tty) && L_IEXTEN(tty))
+ c = tolower(c);
+ n_tty_receive_char(tty, c);
+ } else
+ n_tty_receive_char_flagged(tty, c, flag);
}
/**
@@ -1406,86 +1513,220 @@ static void n_tty_write_wakeup(struct tty_struct *tty)
* been received. This function must be called from soft contexts
* not from interrupt context. The driver is responsible for making
* calls one at a time and in order (or using flush_to_ldisc)
+ *
+ * n_tty_receive_buf()/producer path:
+ * claims non-exclusive termios_rwsem
+ * publishes read_head and canon_head
*/
-static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static void
+n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count)
{
struct n_tty_data *ldata = tty->disc_data;
- const unsigned char *p;
- char *f, flags = TTY_NORMAL;
- int i;
- char buf[64];
- unsigned long cpuflags;
-
- if (ldata->real_raw) {
- raw_spin_lock_irqsave(&ldata->read_lock, cpuflags);
- i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
- N_TTY_BUF_SIZE - ldata->read_head);
- i = min(count, i);
- memcpy(ldata->read_buf + ldata->read_head, cp, i);
- ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
- ldata->read_cnt += i;
- cp += i;
- count -= i;
-
- i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
- N_TTY_BUF_SIZE - ldata->read_head);
- i = min(count, i);
- memcpy(ldata->read_buf + ldata->read_head, cp, i);
- ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
- ldata->read_cnt += i;
- raw_spin_unlock_irqrestore(&ldata->read_lock, cpuflags);
- } else {
- for (i = count, p = cp, f = fp; i; i--, p++) {
- if (f)
- flags = *f++;
- switch (flags) {
- case TTY_NORMAL:
- n_tty_receive_char(tty, *p);
- break;
- case TTY_BREAK:
- n_tty_receive_break(tty);
- break;
- case TTY_PARITY:
- case TTY_FRAME:
- n_tty_receive_parity_error(tty, *p);
- break;
- case TTY_OVERRUN:
- n_tty_receive_overrun(tty);
- break;
- default:
- printk(KERN_ERR "%s: unknown flag %d\n",
- tty_name(tty, buf), flags);
- break;
+ size_t n, head;
+
+ head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
+ n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head);
+ n = min_t(size_t, count, n);
+ memcpy(read_buf_addr(ldata, head), cp, n);
+ ldata->read_head += n;
+ cp += n;
+ count -= n;
+
+ head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
+ n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head);
+ n = min_t(size_t, count, n);
+ memcpy(read_buf_addr(ldata, head), cp, n);
+ ldata->read_head += n;
+}
+
+static void
+n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ char flag = TTY_NORMAL;
+
+ while (count--) {
+ if (fp)
+ flag = *fp++;
+ if (likely(flag == TTY_NORMAL))
+ put_tty_queue(*cp++, ldata);
+ else
+ n_tty_receive_char_flagged(tty, *cp++, flag);
+ }
+}
+
+static void
+n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count)
+{
+ char flag = TTY_NORMAL;
+
+ while (count--) {
+ if (fp)
+ flag = *fp++;
+ if (likely(flag == TTY_NORMAL))
+ n_tty_receive_char_closing(tty, *cp++);
+ else
+ n_tty_receive_char_flagged(tty, *cp++, flag);
+ }
+}
+
+static void
+n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ char flag = TTY_NORMAL;
+
+ while (count--) {
+ if (fp)
+ flag = *fp++;
+ if (likely(flag == TTY_NORMAL)) {
+ unsigned char c = *cp++;
+
+ if (I_ISTRIP(tty))
+ c &= 0x7f;
+ if (I_IUCLC(tty) && L_IEXTEN(tty))
+ c = tolower(c);
+ if (L_EXTPROC(tty)) {
+ put_tty_queue(c, ldata);
+ continue;
}
+ if (!test_bit(c, ldata->char_map))
+ n_tty_receive_char_inline(tty, c);
+ else if (n_tty_receive_char_special(tty, c) && count) {
+ if (fp)
+ flag = *fp++;
+ n_tty_receive_char_lnext(tty, *cp++, flag);
+ count--;
+ }
+ } else
+ n_tty_receive_char_flagged(tty, *cp++, flag);
+ }
+}
+
+static void
+n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ char flag = TTY_NORMAL;
+
+ while (count--) {
+ if (fp)
+ flag = *fp++;
+ if (likely(flag == TTY_NORMAL)) {
+ unsigned char c = *cp++;
+
+ if (!test_bit(c, ldata->char_map))
+ n_tty_receive_char_fast(tty, c);
+ else if (n_tty_receive_char_special(tty, c) && count) {
+ if (fp)
+ flag = *fp++;
+ n_tty_receive_char_lnext(tty, *cp++, flag);
+ count--;
+ }
+ } else
+ n_tty_receive_char_flagged(tty, *cp++, flag);
+ }
+}
+
+static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
+
+ if (ldata->real_raw)
+ n_tty_receive_buf_real_raw(tty, cp, fp, count);
+ else if (ldata->raw || (L_EXTPROC(tty) && !preops))
+ n_tty_receive_buf_raw(tty, cp, fp, count);
+ else if (tty->closing && !L_EXTPROC(tty))
+ n_tty_receive_buf_closing(tty, cp, fp, count);
+ else {
+ if (ldata->lnext) {
+ char flag = TTY_NORMAL;
+
+ if (fp)
+ flag = *fp++;
+ n_tty_receive_char_lnext(tty, *cp++, flag);
+ count--;
}
+
+ if (!preops && !I_PARMRK(tty))
+ n_tty_receive_buf_fast(tty, cp, fp, count);
+ else
+ n_tty_receive_buf_standard(tty, cp, fp, count);
+
+ flush_echoes(tty);
if (tty->ops->flush_chars)
tty->ops->flush_chars(tty);
}
- set_room(tty);
-
- if ((!ldata->icanon && (ldata->read_cnt >= ldata->minimum_to_wake)) ||
+ if ((!ldata->icanon && (read_cnt(ldata) >= ldata->minimum_to_wake)) ||
L_EXTPROC(tty)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
}
+}
+
+static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count)
+{
+ int room, n;
+
+ down_read(&tty->termios_rwsem);
- /*
- * Check the remaining room for the input canonicalization
- * mode. We don't want to throttle the driver if we're in
- * canonical mode and don't have a newline yet!
- */
while (1) {
- tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
- if (tty->receive_room >= TTY_THRESHOLD_THROTTLE)
+ room = receive_room(tty);
+ n = min(count, room);
+ if (!n)
break;
- if (!tty_throttle_safe(tty))
+ __receive_buf(tty, cp, fp, n);
+ cp += n;
+ if (fp)
+ fp += n;
+ count -= n;
+ }
+
+ tty->receive_room = room;
+ n_tty_check_throttle(tty);
+ up_read(&tty->termios_rwsem);
+}
+
+static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ int room, n, rcvd = 0;
+
+ down_read(&tty->termios_rwsem);
+
+ while (1) {
+ room = receive_room(tty);
+ n = min(count, room);
+ if (!n) {
+ if (!room)
+ ldata->no_room = 1;
break;
+ }
+ __receive_buf(tty, cp, fp, n);
+ cp += n;
+ if (fp)
+ fp += n;
+ count -= n;
+ rcvd += n;
}
- __tty_set_flow_change(tty, 0);
+
+ tty->receive_room = room;
+ n_tty_check_throttle(tty);
+ up_read(&tty->termios_rwsem);
+
+ return rcvd;
}
int is_ignored(int sig)
@@ -1505,7 +1746,7 @@ int is_ignored(int sig)
* guaranteed that this function will not be re-entered or in progress
* when the ldisc is closed.
*
- * Locking: Caller holds tty->termios_mutex
+ * Locking: Caller holds tty->termios_rwsem
*/
static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
@@ -1517,12 +1758,13 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
if (canon_change) {
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
+ ldata->line_start = 0;
ldata->canon_head = ldata->read_tail;
- ldata->canon_data = 0;
ldata->erasing = 0;
+ ldata->lnext = 0;
}
- if (canon_change && !L_ICANON(tty) && ldata->read_cnt)
+ if (canon_change && !L_ICANON(tty) && read_cnt(ldata))
wake_up_interruptible(&tty->read_wait);
ldata->icanon = (L_ICANON(tty) != 0);
@@ -1531,41 +1773,38 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
I_PARMRK(tty)) {
- bitmap_zero(ldata->process_char_map, 256);
+ bitmap_zero(ldata->char_map, 256);
if (I_IGNCR(tty) || I_ICRNL(tty))
- set_bit('\r', ldata->process_char_map);
+ set_bit('\r', ldata->char_map);
if (I_INLCR(tty))
- set_bit('\n', ldata->process_char_map);
+ set_bit('\n', ldata->char_map);
if (L_ICANON(tty)) {
- set_bit(ERASE_CHAR(tty), ldata->process_char_map);
- set_bit(KILL_CHAR(tty), ldata->process_char_map);
- set_bit(EOF_CHAR(tty), ldata->process_char_map);
- set_bit('\n', ldata->process_char_map);
- set_bit(EOL_CHAR(tty), ldata->process_char_map);
+ set_bit(ERASE_CHAR(tty), ldata->char_map);
+ set_bit(KILL_CHAR(tty), ldata->char_map);
+ set_bit(EOF_CHAR(tty), ldata->char_map);
+ set_bit('\n', ldata->char_map);
+ set_bit(EOL_CHAR(tty), ldata->char_map);
if (L_IEXTEN(tty)) {
- set_bit(WERASE_CHAR(tty),
- ldata->process_char_map);
- set_bit(LNEXT_CHAR(tty),
- ldata->process_char_map);
- set_bit(EOL2_CHAR(tty),
- ldata->process_char_map);
+ set_bit(WERASE_CHAR(tty), ldata->char_map);
+ set_bit(LNEXT_CHAR(tty), ldata->char_map);
+ set_bit(EOL2_CHAR(tty), ldata->char_map);
if (L_ECHO(tty))
set_bit(REPRINT_CHAR(tty),
- ldata->process_char_map);
+ ldata->char_map);
}
}
if (I_IXON(tty)) {
- set_bit(START_CHAR(tty), ldata->process_char_map);
- set_bit(STOP_CHAR(tty), ldata->process_char_map);
+ set_bit(START_CHAR(tty), ldata->char_map);
+ set_bit(STOP_CHAR(tty), ldata->char_map);
}
if (L_ISIG(tty)) {
- set_bit(INTR_CHAR(tty), ldata->process_char_map);
- set_bit(QUIT_CHAR(tty), ldata->process_char_map);
- set_bit(SUSP_CHAR(tty), ldata->process_char_map);
+ set_bit(INTR_CHAR(tty), ldata->char_map);
+ set_bit(QUIT_CHAR(tty), ldata->char_map);
+ set_bit(SUSP_CHAR(tty), ldata->char_map);
}
- clear_bit(__DISABLED_CHAR, ldata->process_char_map);
+ clear_bit(__DISABLED_CHAR, ldata->char_map);
ldata->raw = 0;
ldata->real_raw = 0;
} else {
@@ -1608,9 +1847,7 @@ static void n_tty_close(struct tty_struct *tty)
if (tty->link)
n_tty_packet_mode_flush(tty);
- kfree(ldata->read_buf);
- kfree(ldata->echo_buf);
- kfree(ldata);
+ vfree(ldata);
tty->disc_data = NULL;
}
@@ -1628,26 +1865,23 @@ static int n_tty_open(struct tty_struct *tty)
{
struct n_tty_data *ldata;
- ldata = kzalloc(sizeof(*ldata), GFP_KERNEL);
+ /* Currently a malloc failure here can panic */
+ ldata = vmalloc(sizeof(*ldata));
if (!ldata)
goto err;
ldata->overrun_time = jiffies;
mutex_init(&ldata->atomic_read_lock);
mutex_init(&ldata->output_lock);
- mutex_init(&ldata->echo_lock);
- raw_spin_lock_init(&ldata->read_lock);
-
- /* These are ugly. Currently a malloc failure here can panic */
- ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
- ldata->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
- if (!ldata->read_buf || !ldata->echo_buf)
- goto err_free_bufs;
tty->disc_data = ldata;
reset_buffer_flags(tty->disc_data);
ldata->column = 0;
+ ldata->canon_column = 0;
ldata->minimum_to_wake = 1;
+ ldata->num_overrun = 0;
+ ldata->no_room = 0;
+ ldata->lnext = 0;
tty->closing = 0;
/* indicate buffer work may resume */
clear_bit(TTY_LDISC_HALTED, &tty->flags);
@@ -1655,10 +1889,6 @@ static int n_tty_open(struct tty_struct *tty)
tty_unthrottle(tty);
return 0;
-err_free_bufs:
- kfree(ldata->read_buf);
- kfree(ldata->echo_buf);
- kfree(ldata);
err:
return -ENOMEM;
}
@@ -1667,11 +1897,10 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
{
struct n_tty_data *ldata = tty->disc_data;
- tty_flush_to_ldisc(tty);
if (ldata->icanon && !L_EXTPROC(tty)) {
- if (ldata->canon_data)
+ if (ldata->canon_head != ldata->read_tail)
return 1;
- } else if (ldata->read_cnt >= (amt ? amt : 1))
+ } else if (read_cnt(ldata) >= (amt ? amt : 1))
return 1;
return 0;
@@ -1692,6 +1921,9 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
*
* Called under the ldata->atomic_read_lock sem
*
+ * n_tty_read()/consumer path:
+ * caller holds non-exclusive termios_rwsem
+ * read_tail published
*/
static int copy_from_read_buf(struct tty_struct *tty,
@@ -1702,34 +1934,114 @@ static int copy_from_read_buf(struct tty_struct *tty,
struct n_tty_data *ldata = tty->disc_data;
int retval;
size_t n;
- unsigned long flags;
bool is_eof;
+ size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
retval = 0;
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail);
+ n = min(read_cnt(ldata), N_TTY_BUF_SIZE - tail);
n = min(*nr, n);
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
if (n) {
- retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n);
+ retval = copy_to_user(*b, read_buf_addr(ldata, tail), n);
n -= retval;
- is_eof = n == 1 &&
- ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty);
- tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n,
+ is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty);
+ tty_audit_add_data(tty, read_buf_addr(ldata, tail), n,
ldata->icanon);
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1);
- ldata->read_cnt -= n;
+ ldata->read_tail += n;
/* Turn single EOF into zero-length read */
- if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt)
+ if (L_EXTPROC(tty) && ldata->icanon && is_eof && !read_cnt(ldata))
n = 0;
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
*b += n;
*nr -= n;
}
return retval;
}
+/**
+ * canon_copy_from_read_buf - copy read data in canonical mode
+ * @tty: terminal device
+ * @b: user data
+ * @nr: size of data
+ *
+ * Helper function for n_tty_read. It is only called when ICANON is on;
+ * it copies one line of input up to and including the line-delimiting
+ * character into the user-space buffer.
+ *
+ * Called under the atomic_read_lock mutex
+ *
+ * n_tty_read()/consumer path:
+ * caller holds non-exclusive termios_rwsem
+ * read_tail published
+ */
+
+static int canon_copy_from_read_buf(struct tty_struct *tty,
+ unsigned char __user **b,
+ size_t *nr)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ size_t n, size, more, c;
+ size_t eol;
+ size_t tail;
+ int ret, found = 0;
+ bool eof_push = 0;
+
+ /* N.B. avoid overrun if nr == 0 */
+ n = min(*nr, read_cnt(ldata));
+ if (!n)
+ return 0;
+
+ tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
+ size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
+
+ n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu\n",
+ __func__, *nr, tail, n, size);
+
+ eol = find_next_bit(ldata->read_flags, size, tail);
+ more = n - (size - tail);
+ if (eol == N_TTY_BUF_SIZE && more) {
+ /* scan wrapped without finding set bit */
+ eol = find_next_bit(ldata->read_flags, more, 0);
+ if (eol != more)
+ found = 1;
+ } else if (eol != size)
+ found = 1;
+
+ size = N_TTY_BUF_SIZE - tail;
+ n = (found + eol + size) & (N_TTY_BUF_SIZE - 1);
+ c = n;
+
+ if (found && read_buf(ldata, eol) == __DISABLED_CHAR) {
+ n--;
+ eof_push = !n && ldata->read_tail != ldata->line_start;
+ }
+
+ n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu size:%zu more:%zu\n",
+ __func__, eol, found, n, c, size, more);
+
+ if (n > size) {
+ ret = copy_to_user(*b, read_buf_addr(ldata, tail), size);
+ if (ret)
+ return -EFAULT;
+ ret = copy_to_user(*b + size, ldata->read_buf, n - size);
+ } else
+ ret = copy_to_user(*b, read_buf_addr(ldata, tail), n);
+
+ if (ret)
+ return -EFAULT;
+ *b += n;
+ *nr -= n;
+
+ if (found)
+ clear_bit(eol, ldata->read_flags);
+ smp_mb__after_clear_bit();
+ ldata->read_tail += c;
+
+ if (found) {
+ ldata->line_start = ldata->read_tail;
+ tty_audit_push(tty);
+ }
+ return eof_push ? -EAGAIN : 0;
+}
+
extern ssize_t redirected_tty_write(struct file *, const char __user *,
size_t, loff_t *);
@@ -1787,6 +2099,10 @@ static int job_control(struct tty_struct *tty, struct file *file)
* a hangup. Always called in user context, may sleep.
*
* This code must be sure never to sleep through a hangup.
+ *
+ * n_tty_read()/consumer path:
+ * claims non-exclusive termios_rwsem
+ * publishes read_tail
*/
static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
@@ -1798,16 +2114,27 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
int c;
int minimum, time;
ssize_t retval = 0;
- ssize_t size;
long timeout;
unsigned long flags;
int packet;
-do_it_again:
c = job_control(tty, file);
if (c < 0)
return c;
+ /*
+ * Internal serialization of reads.
+ */
+ if (file->f_flags & O_NONBLOCK) {
+ if (!mutex_trylock(&ldata->atomic_read_lock))
+ return -EAGAIN;
+ } else {
+ if (mutex_lock_interruptible(&ldata->atomic_read_lock))
+ return -ERESTARTSYS;
+ }
+
+ down_read(&tty->termios_rwsem);
+
minimum = time = 0;
timeout = MAX_SCHEDULE_TIMEOUT;
if (!ldata->icanon) {
@@ -1825,16 +2152,6 @@ do_it_again:
}
}
- /*
- * Internal serialization of reads.
- */
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&ldata->atomic_read_lock))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&ldata->atomic_read_lock))
- return -ERESTARTSYS;
- }
packet = tty->packet;
add_wait_queue(&tty->read_wait, &wait);
@@ -1883,7 +2200,11 @@ do_it_again:
break;
}
n_tty_set_room(tty);
+ up_read(&tty->termios_rwsem);
+
timeout = schedule_timeout(timeout);
+
+ down_read(&tty->termios_rwsem);
continue;
}
__set_current_state(TASK_RUNNING);
@@ -1899,45 +2220,11 @@ do_it_again:
}
if (ldata->icanon && !L_EXTPROC(tty)) {
- /* N.B. avoid overrun if nr == 0 */
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- while (nr && ldata->read_cnt) {
- int eol;
-
- eol = test_and_clear_bit(ldata->read_tail,
- ldata->read_flags);
- c = ldata->read_buf[ldata->read_tail];
- ldata->read_tail = ((ldata->read_tail+1) &
- (N_TTY_BUF_SIZE-1));
- ldata->read_cnt--;
- if (eol) {
- /* this test should be redundant:
- * we shouldn't be reading data if
- * canon_data is 0
- */
- if (--ldata->canon_data < 0)
- ldata->canon_data = 0;
- }
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
-
- if (!eol || (c != __DISABLED_CHAR)) {
- if (tty_put_user(tty, c, b++)) {
- retval = -EFAULT;
- b--;
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- break;
- }
- nr--;
- }
- if (eol) {
- tty_audit_push(tty);
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- break;
- }
- raw_spin_lock_irqsave(&ldata->read_lock, flags);
- }
- raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
- if (retval)
+ retval = canon_copy_from_read_buf(tty, &b, &nr);
+ if (retval == -EAGAIN) {
+ retval = 0;
+ continue;
+ } else if (retval)
break;
} else {
int uncopied;
@@ -1951,24 +2238,7 @@ do_it_again:
}
}
- /* If there is enough space in the read buffer now, let the
- * low-level driver know. We use n_tty_chars_in_buffer() to
- * check the buffer, as it now knows about canonical mode.
- * Otherwise, if the driver is throttled and the line is
- * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
- * we won't get any more characters.
- */
- while (1) {
- tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
- if (n_tty_chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
- break;
- if (!tty->count)
- break;
- n_tty_set_room(tty);
- if (!tty_unthrottle_safe(tty))
- break;
- }
- __tty_set_flow_change(tty, 0);
+ n_tty_check_unthrottle(tty);
if (b - buf >= minimum)
break;
@@ -1982,15 +2252,11 @@ do_it_again:
ldata->minimum_to_wake = minimum;
__set_current_state(TASK_RUNNING);
- size = b - buf;
- if (size) {
- retval = size;
- if (nr)
- clear_bit(TTY_PUSH, &tty->flags);
- } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
- goto do_it_again;
+ if (b - buf)
+ retval = b - buf;
n_tty_set_room(tty);
+ up_read(&tty->termios_rwsem);
return retval;
}
@@ -2031,6 +2297,8 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
return retval;
}
+ down_read(&tty->termios_rwsem);
+
/* Write out any echoed characters that are still pending */
process_echoes(tty);
@@ -2084,13 +2352,18 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
retval = -EAGAIN;
break;
}
+ up_read(&tty->termios_rwsem);
+
schedule();
+
+ down_read(&tty->termios_rwsem);
}
break_out:
__set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
if (b - buf != nr && tty->fasync)
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ up_read(&tty->termios_rwsem);
return (b - buf) ? b - buf : retval;
}
@@ -2139,19 +2412,19 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
static unsigned long inq_canon(struct n_tty_data *ldata)
{
- int nr, head, tail;
+ size_t nr, head, tail;
- if (!ldata->canon_data)
+ if (ldata->canon_head == ldata->read_tail)
return 0;
head = ldata->canon_head;
tail = ldata->read_tail;
- nr = (head - tail) & (N_TTY_BUF_SIZE-1);
+ nr = head - tail;
/* Skip EOF-chars.. */
while (head != tail) {
- if (test_bit(tail, ldata->read_flags) &&
- ldata->read_buf[tail] == __DISABLED_CHAR)
+ if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) &&
+ read_buf(ldata, tail) == __DISABLED_CHAR)
nr--;
- tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+ tail++;
}
return nr;
}
@@ -2166,10 +2439,12 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
case TIOCOUTQ:
return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
case TIOCINQ:
- /* FIXME: Locking */
- retval = ldata->read_cnt;
+ down_write(&tty->termios_rwsem);
if (L_ICANON(tty))
retval = inq_canon(ldata);
+ else
+ retval = read_cnt(ldata);
+ up_write(&tty->termios_rwsem);
return put_user(retval, (unsigned int __user *) arg);
default:
return n_tty_ioctl_helper(tty, file, cmd, arg);
@@ -2203,6 +2478,7 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
.receive_buf = n_tty_receive_buf,
.write_wakeup = n_tty_write_wakeup,
.fasync = n_tty_fasync,
+ .receive_buf2 = n_tty_receive_buf2,
};
/**
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index abfd9908978..25c9bc78372 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -89,17 +89,13 @@ static void pty_unthrottle(struct tty_struct *tty)
* pty_space - report space left for writing
* @to: tty we are writing into
*
- * The tty buffers allow 64K but we sneak a peak and clip at 8K this
- * allows a lot of overspill room for echo and other fun messes to
- * be handled properly
+ * Limit the buffer space used by ptys to 8k.
*/
static int pty_space(struct tty_struct *to)
{
- int n = 8192 - to->port->buf.memory_used;
- if (n < 0)
- return 0;
- return n;
+ int n = tty_buffer_space_avail(to->port);
+ return min(n, 8192);
}
/**
@@ -125,10 +121,8 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
/* Stuff the data into the input queue of the other end */
c = tty_insert_flip_string(to->port, buf, c);
/* And shovel */
- if (c) {
+ if (c)
tty_flip_buffer_push(to->port);
- tty_wakeup(tty);
- }
}
return c;
}
@@ -287,7 +281,7 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws)
struct tty_struct *pty = tty->link;
/* For a PTY we need to lock the tty side */
- mutex_lock(&tty->termios_mutex);
+ mutex_lock(&tty->winsize_mutex);
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
goto done;
@@ -314,7 +308,7 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws)
tty->winsize = *ws;
pty->winsize = *ws; /* Never used so will go away soon */
done:
- mutex_unlock(&tty->termios_mutex);
+ mutex_unlock(&tty->winsize_mutex);
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 86c00b1c558..570df9d2a5d 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -3062,7 +3062,7 @@ void serial8250_resume_port(int line)
*/
static int serial8250_probe(struct platform_device *dev)
{
- struct plat_serial8250_port *p = dev->dev.platform_data;
+ struct plat_serial8250_port *p = dev_get_platdata(&dev->dev);
struct uart_8250_port uart;
int ret, i, irqflag = 0;
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 76a8daadff4..daf710f5c3f 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -57,11 +57,25 @@
struct dw8250_data {
int last_lcr;
+ int last_mcr;
int line;
struct clk *clk;
u8 usr_reg;
};
+static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
+{
+ struct dw8250_data *d = p->private_data;
+
+ /* If reading MSR, report CTS asserted when auto-CTS/RTS enabled */
+ if (offset == UART_MSR && d->last_mcr & UART_MCR_AFE) {
+ value |= UART_MSR_CTS;
+ value &= ~UART_MSR_DCTS;
+ }
+
+ return value;
+}
+
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
@@ -69,15 +83,17 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
if (offset == UART_LCR)
d->last_lcr = value;
- offset <<= p->regshift;
- writeb(value, p->membase + offset);
+ if (offset == UART_MCR)
+ d->last_mcr = value;
+
+ writeb(value, p->membase + (offset << p->regshift));
}
static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
{
- offset <<= p->regshift;
+ unsigned int value = readb(p->membase + (offset << p->regshift));
- return readb(p->membase + offset);
+ return dw8250_modify_msr(p, offset, value);
}
/* Read Back (rb) version to ensure register access ording. */
@@ -94,15 +110,17 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
if (offset == UART_LCR)
d->last_lcr = value;
- offset <<= p->regshift;
- writel(value, p->membase + offset);
+ if (offset == UART_MCR)
+ d->last_mcr = value;
+
+ writel(value, p->membase + (offset << p->regshift));
}
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
{
- offset <<= p->regshift;
+ unsigned int value = readl(p->membase + (offset << p->regshift));
- return readl(p->membase + offset);
+ return dw8250_modify_msr(p, offset, value);
}
static int dw8250_handle_irq(struct uart_port *p)
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 721904f8efa..c100d6343d5 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -193,7 +193,8 @@ static int __init parse_options(struct early_serial8250_device *device,
if (options) {
options++;
device->baud = simple_strtoul(options, NULL, 0);
- length = min(strcspn(options, " "), sizeof(device->options));
+ length = min(strcspn(options, " ") + 1,
+ (size_t)(sizeof(device->options)));
strlcpy(device->options, options, length);
} else {
device->baud = probe_baud(port);
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
index 916cc19fbbd..5f3bba12c15 100644
--- a/drivers/tty/serial/8250/8250_em.c
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -95,25 +95,23 @@ static int serial8250_em_probe(struct platform_device *pdev)
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
struct serial8250_em_priv *priv;
struct uart_8250_port up;
- int ret = -EINVAL;
+ int ret;
if (!regs || !irq) {
dev_err(&pdev->dev, "missing registers or irq\n");
- goto err0;
+ return -EINVAL;
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "unable to allocate private data\n");
- ret = -ENOMEM;
- goto err0;
+ return -ENOMEM;
}
- priv->sclk = clk_get(&pdev->dev, "sclk");
+ priv->sclk = devm_clk_get(&pdev->dev, "sclk");
if (IS_ERR(priv->sclk)) {
dev_err(&pdev->dev, "unable to get clock\n");
- ret = PTR_ERR(priv->sclk);
- goto err1;
+ return PTR_ERR(priv->sclk);
}
memset(&up, 0, sizeof(up));
@@ -136,20 +134,13 @@ static int serial8250_em_probe(struct platform_device *pdev)
ret = serial8250_register_8250_port(&up);
if (ret < 0) {
dev_err(&pdev->dev, "unable to register 8250 port\n");
- goto err2;
+ clk_disable(priv->sclk);
+ return ret;
}
priv->line = ret;
platform_set_drvdata(pdev, priv);
return 0;
-
- err2:
- clk_disable(priv->sclk);
- clk_put(priv->sclk);
- err1:
- kfree(priv);
- err0:
- return ret;
}
static int serial8250_em_remove(struct platform_device *pdev)
@@ -158,8 +149,6 @@ static int serial8250_em_remove(struct platform_device *pdev)
serial8250_unregister_port(priv->line);
clk_disable(priv->sclk);
- clk_put(priv->sclk);
- kfree(priv);
return 0;
}
diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c
index bb91b4713eb..2e3ea1a70d7 100644
--- a/drivers/tty/serial/8250/8250_gsc.c
+++ b/drivers/tty/serial/8250/8250_gsc.c
@@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev)
int err;
#ifdef CONFIG_64BIT
- extern int iosapic_serial_irq(int cellnum);
if (!dev->irq && (dev->id.sversion == 0xad))
- dev->irq = iosapic_serial_irq(dev->mod_index-1);
+ dev->irq = iosapic_serial_irq(dev);
#endif
if (!dev->irq) {
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index c52948b368d..c810da7c7a8 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1565,6 +1565,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021
#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
+#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
#define PCI_VENDOR_ID_SUNIX 0x1fd4
#define PCI_DEVICE_ID_SUNIX_1999 0x1999
@@ -1587,8 +1588,8 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
* ADDI-DATA GmbH communication cards <info@addi-data.com>
*/
{
- .vendor = PCI_VENDOR_ID_ADDIDATA_OLD,
- .device = PCI_DEVICE_ID_ADDIDATA_APCI7800,
+ .vendor = PCI_VENDOR_ID_AMCC,
+ .device = PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = addidata_apci7800_setup,
@@ -4697,8 +4698,8 @@ static struct pci_device_id serial_pci_tbl[] = {
0,
pbn_b0_1_115200 },
- { PCI_VENDOR_ID_ADDIDATA_OLD,
- PCI_DEVICE_ID_ADDIDATA_APCI7800,
+ { PCI_VENDOR_ID_AMCC,
+ PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800,
PCI_ANY_ID,
PCI_ANY_ID,
0,
@@ -4797,6 +4798,12 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_VENDOR_ID_IBM, 0x0299,
0, 0, pbn_b0_bt_2_115200 },
+ /*
+ * other NetMos 9835 devices are most likely handled by the
+ * parport_serial driver, check drivers/parport/parport_serial.c
+ * before adding them here.
+ */
+
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
0xA000, 0x1000,
0, 0, pbn_b0_1_115200 },
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index a1ba94d6488..f3b306efaa5 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -116,6 +116,8 @@ config SERIAL_8250_PCI
This builds standard PCI serial support. You may be able to
disable this feature if you only need legacy serial support.
Saves about 9K.
+ Note that serial ports on NetMos 9835 Multi-I/O cards are handled
+ by the parport_serial driver, enabled with CONFIG_PARPORT_SERIAL.
config SERIAL_8250_HP300
tristate
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 5e3d68917ff..cc4c8682b47 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -277,7 +277,7 @@ config SERIAL_TEGRA
select SERIAL_CORE
help
Support for the on-chip UARTs on the NVIDIA Tegra series SOCs
- providing /dev/ttyHS0, 1, 2, 3 and 4 (note, some machines may not
+ providing /dev/ttyTHS0, 1, 2, 3 and 4 (note, some machines may not
provide all of these ports, depending on how the serial port
are enabled). This driver uses the APB DMA to achieve higher baudrate
and better performance.
@@ -291,13 +291,13 @@ config SERIAL_MAX3100
config SERIAL_MAX310X
bool "MAX310X support"
- depends on SPI
+ depends on SPI_MASTER
select SERIAL_CORE
- select REGMAP_SPI if SPI
+ select REGMAP_SPI if SPI_MASTER
default n
help
This selects support for an advanced UART from Maxim (Dallas).
- Supported ICs are MAX3107, MAX3108.
+ Supported ICs are MAX3107, MAX3108, MAX3109, MAX14830.
Each IC contains 128 words each of receive and transmit FIFO
that can be controlled through I2C or high-speed SPI.
@@ -1401,13 +1401,16 @@ config SERIAL_XILINX_PS_UART_CONSOLE
Enable a Xilinx PS UART port to be the system console.
config SERIAL_AR933X
- bool "AR933X serial port support"
- depends on SOC_AR933X
+ tristate "AR933X serial port support"
+ depends on HAVE_CLK && SOC_AR933X
select SERIAL_CORE
help
If you have an Atheros AR933X SOC based board and want to use the
built-in UART of the SoC, say Y to this option.
+ To compile this driver as a module, choose M here: the
+ module will be called ar933x_uart.
+
config SERIAL_AR933X_CONSOLE
bool "Console on AR933X serial port"
depends on SERIAL_AR933X=y
@@ -1424,8 +1427,8 @@ config SERIAL_AR933X_NR_UARTS
to support.
config SERIAL_EFM32_UART
- tristate "EFM32 UART/USART port."
- depends on ARCH_EFM32
+ tristate "EFM32 UART/USART port"
+ depends on ARM && (ARCH_EFM32 || COMPILE_TEST)
select SERIAL_CORE
help
This driver support the USART and UART ports on
@@ -1497,6 +1500,22 @@ config SERIAL_FSL_LPUART_CONSOLE
If you have enabled the lpuart serial port on the Freescale SoCs,
you can make it the console by answering Y to this option.
+config SERIAL_ST_ASC
+ tristate "ST ASC serial port support"
+ select SERIAL_CORE
+ help
+ This driver is for the on-chip Asychronous Serial Controller on
+ STMicroelectronics STi SoCs.
+ ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality.
+ It support all industry standard baud rates.
+
+ If unsure, say N.
+
+config SERIAL_ST_ASC_CONSOLE
+ bool "Support for console on ST ASC"
+ depends on SERIAL_ST_ASC=y
+ select SERIAL_CORE_CONSOLE
+
endmenu
endif # TTY
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index cf650f0cd6e..47b679c547e 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
+obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index c6bdb943726..18e038fbdcd 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -139,7 +139,9 @@ static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
uart_insert_char(port, 0, 0, ch, flag);
}
+ spin_unlock(&port->lock);
tty_flip_buffer_push(&port->state->port);
+ spin_lock(&port->lock);
}
static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
@@ -408,7 +410,8 @@ static struct uart_driver altera_jtaguart_driver = {
static int altera_jtaguart_probe(struct platform_device *pdev)
{
- struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
+ struct altera_jtaguart_platform_uart *platp =
+ dev_get_platdata(&pdev->dev);
struct uart_port *port;
struct resource *res_irq, *res_mem;
int i = pdev->id;
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 1d46966e2a6..6431472aeb1 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -231,7 +231,9 @@ static void altera_uart_rx_chars(struct altera_uart *pp)
flag);
}
+ spin_unlock(&port->lock);
tty_flip_buffer_push(&port->state->port);
+ spin_lock(&port->lock);
}
static void altera_uart_tx_chars(struct altera_uart *pp)
@@ -534,7 +536,7 @@ static int altera_uart_get_of_uartclk(struct platform_device *pdev,
static int altera_uart_probe(struct platform_device *pdev)
{
- struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
+ struct altera_uart_platform_uart *platp = dev_get_platdata(&pdev->dev);
struct uart_port *port;
struct resource *res_mem;
struct resource *res_irq;
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index c3684051952..8b90f0b6dfd 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -721,7 +721,7 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id)
uap->port.flags = UPF_BOOT_AUTOCONF;
uap->port.line = i;
uap->dev = dev;
- uap->data = dev->dev.platform_data;
+ uap->data = dev_get_platdata(&dev->dev);
amba_ports[i] = uap;
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 28b35ad9c6c..aaa22867e65 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -265,7 +265,7 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap)
{
/* DMA is the sole user of the platform data right now */
- struct amba_pl011_data *plat = uap->port.dev->platform_data;
+ struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
struct dma_slave_config tx_conf = {
.dst_addr = uap->port.mapbase + UART01x_DR,
.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
@@ -677,6 +677,8 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
* Locking: called with port lock held and IRQs disabled.
*/
static void pl011_dma_flush_buffer(struct uart_port *port)
+__releases(&uap->port.lock)
+__acquires(&uap->port.lock)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1198,6 +1200,8 @@ static void pl011_enable_ms(struct uart_port *port)
}
static void pl011_rx_chars(struct uart_amba_port *uap)
+__releases(&uap->port.lock)
+__acquires(&uap->port.lock)
{
pl011_fifo_to_tty(uap);
@@ -1497,10 +1501,10 @@ static int pl011_hwinit(struct uart_port *port)
uap->im = readw(uap->port.membase + UART011_IMSC);
writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
- if (uap->port.dev->platform_data) {
+ if (dev_get_platdata(uap->port.dev)) {
struct amba_pl011_data *plat;
- plat = uap->port.dev->platform_data;
+ plat = dev_get_platdata(uap->port.dev);
if (plat->init)
plat->init();
}
@@ -1645,10 +1649,10 @@ static void pl011_shutdown(struct uart_port *port)
/* Optionally let pins go into sleep states */
pinctrl_pm_select_sleep_state(port->dev);
- if (uap->port.dev->platform_data) {
+ if (dev_get_platdata(uap->port.dev)) {
struct amba_pl011_data *plat;
- plat = uap->port.dev->platform_data;
+ plat = dev_get_platdata(uap->port.dev);
if (plat->exit)
plat->exit();
}
@@ -2002,10 +2006,10 @@ static int __init pl011_console_setup(struct console *co, char *options)
if (ret)
return ret;
- if (uap->port.dev->platform_data) {
+ if (dev_get_platdata(uap->port.dev)) {
struct amba_pl011_data *plat;
- plat = uap->port.dev->platform_data;
+ plat = dev_get_platdata(uap->port.dev);
if (plat->init)
plat->init();
}
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c
index 6331464d910..de11ab8ffd9 100644
--- a/drivers/tty/serial/apbuart.c
+++ b/drivers/tty/serial/apbuart.c
@@ -125,7 +125,9 @@ static void apbuart_rx_chars(struct uart_port *port)
status = UART_GET_STATUS(port);
}
+ spin_unlock(&port->lock);
tty_flip_buffer_push(&port->state->port);
+ spin_lock(&port->lock);
}
static void apbuart_tx_chars(struct uart_port *port)
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index 27f20c57abe..acd03af7cd5 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -17,6 +17,8 @@
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
@@ -24,11 +26,11 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/clk.h>
#include <asm/div64.h>
#include <asm/mach-ath79/ar933x_uart.h>
-#include <asm/mach-ath79/ar933x_uart_platform.h>
#define DRIVER_NAME "ar933x-uart"
@@ -47,8 +49,14 @@ struct ar933x_uart_port {
unsigned int ier; /* shadow Interrupt Enable Register */
unsigned int min_baud;
unsigned int max_baud;
+ struct clk *clk;
};
+static inline bool ar933x_uart_console_enabled(void)
+{
+ return config_enabled(CONFIG_SERIAL_AR933X_CONSOLE);
+}
+
static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
int offset)
{
@@ -322,7 +330,9 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
tty_insert_flip_char(port, ch, TTY_NORMAL);
} while (max_count-- > 0);
+ spin_unlock(&up->port.lock);
tty_flip_buffer_push(port);
+ spin_lock(&up->port.lock);
}
static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
@@ -497,8 +507,6 @@ static struct uart_ops ar933x_uart_ops = {
.verify_port = ar933x_uart_verify_port,
};
-#ifdef CONFIG_SERIAL_AR933X_CONSOLE
-
static struct ar933x_uart_port *
ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS];
@@ -597,80 +605,88 @@ static struct console ar933x_uart_console = {
static void ar933x_uart_add_console_port(struct ar933x_uart_port *up)
{
+ if (!ar933x_uart_console_enabled())
+ return;
+
ar933x_console_ports[up->port.line] = up;
}
-#define AR933X_SERIAL_CONSOLE (&ar933x_uart_console)
-
-#else
-
-static inline void ar933x_uart_add_console_port(struct ar933x_uart_port *up) {}
-
-#define AR933X_SERIAL_CONSOLE NULL
-
-#endif /* CONFIG_SERIAL_AR933X_CONSOLE */
-
static struct uart_driver ar933x_uart_driver = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
.dev_name = "ttyATH",
.nr = CONFIG_SERIAL_AR933X_NR_UARTS,
- .cons = AR933X_SERIAL_CONSOLE,
+ .cons = NULL, /* filled in runtime */
};
static int ar933x_uart_probe(struct platform_device *pdev)
{
- struct ar933x_uart_platform_data *pdata;
struct ar933x_uart_port *up;
struct uart_port *port;
struct resource *mem_res;
struct resource *irq_res;
+ struct device_node *np;
unsigned int baud;
int id;
int ret;
- pdata = pdev->dev.platform_data;
- if (!pdata)
- return -EINVAL;
-
- id = pdev->id;
- if (id == -1)
- id = 0;
+ np = pdev->dev.of_node;
+ if (config_enabled(CONFIG_OF) && np) {
+ id = of_alias_get_id(np, "serial");
+ if (id < 0) {
+ dev_err(&pdev->dev, "unable to get alias id, err=%d\n",
+ id);
+ return id;
+ }
+ } else {
+ id = pdev->id;
+ if (id == -1)
+ id = 0;
+ }
if (id > CONFIG_SERIAL_AR933X_NR_UARTS)
return -EINVAL;
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- dev_err(&pdev->dev, "no MEM resource\n");
- return -EINVAL;
- }
-
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
dev_err(&pdev->dev, "no IRQ resource\n");
return -EINVAL;
}
- up = kzalloc(sizeof(struct ar933x_uart_port), GFP_KERNEL);
+ up = devm_kzalloc(&pdev->dev, sizeof(struct ar933x_uart_port),
+ GFP_KERNEL);
if (!up)
return -ENOMEM;
+ up->clk = devm_clk_get(&pdev->dev, "uart");
+ if (IS_ERR(up->clk)) {
+ dev_err(&pdev->dev, "unable to get UART clock\n");
+ return PTR_ERR(up->clk);
+ }
+
port = &up->port;
- port->mapbase = mem_res->start;
- port->membase = ioremap(mem_res->start, AR933X_UART_REGS_SIZE);
- if (!port->membase) {
- ret = -ENOMEM;
- goto err_free_up;
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ port->membase = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(port->membase))
+ return PTR_ERR(port->membase);
+
+ ret = clk_prepare_enable(up->clk);
+ if (ret)
+ return ret;
+
+ port->uartclk = clk_get_rate(up->clk);
+ if (!port->uartclk) {
+ ret = -EINVAL;
+ goto err_disable_clk;
}
+ port->mapbase = mem_res->start;
port->line = id;
port->irq = irq_res->start;
port->dev = &pdev->dev;
port->type = PORT_AR933X;
port->iotype = UPIO_MEM32;
- port->uartclk = pdata->uartclk;
port->regshift = 2;
port->fifosize = AR933X_UART_FIFO_SIZE;
@@ -686,15 +702,13 @@ static int ar933x_uart_probe(struct platform_device *pdev)
ret = uart_add_one_port(&ar933x_uart_driver, &up->port);
if (ret)
- goto err_unmap;
+ goto err_disable_clk;
platform_set_drvdata(pdev, up);
return 0;
-err_unmap:
- iounmap(up->port.membase);
-err_free_up:
- kfree(up);
+err_disable_clk:
+ clk_disable_unprepare(up->clk);
return ret;
}
@@ -703,23 +717,30 @@ static int ar933x_uart_remove(struct platform_device *pdev)
struct ar933x_uart_port *up;
up = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
if (up) {
uart_remove_one_port(&ar933x_uart_driver, &up->port);
- iounmap(up->port.membase);
- kfree(up);
+ clk_disable_unprepare(up->clk);
}
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id ar933x_uart_of_ids[] = {
+ { .compatible = "qca,ar9330-uart" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ar933x_uart_of_ids);
+#endif
+
static struct platform_driver ar933x_uart_platform_driver = {
.probe = ar933x_uart_probe,
.remove = ar933x_uart_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ar933x_uart_of_ids),
},
};
@@ -727,7 +748,9 @@ static int __init ar933x_uart_init(void)
{
int ret;
- ar933x_uart_driver.nr = CONFIG_SERIAL_AR933X_NR_UARTS;
+ if (ar933x_uart_console_enabled())
+ ar933x_uart_driver.cons = &ar933x_uart_console;
+
ret = uart_register_driver(&ar933x_uart_driver);
if (ret)
goto err_out;
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index cbf1d155b7b..569872f4c9b 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -209,9 +209,9 @@ static void arc_serial_start_tx(struct uart_port *port)
arc_serial_tx_chars(uart);
}
-static void arc_serial_rx_chars(struct arc_uart_port *uart)
+static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status)
{
- unsigned int status, ch, flg = 0;
+ unsigned int ch, flg = 0;
/*
* UART has 4 deep RX-FIFO. Driver's recongnition of this fact
@@ -222,11 +222,11 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart)
* before RX-EMPTY=0, implies some sort of buffering going on in the
* controller, which is indeed the Rx-FIFO.
*/
- while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)) {
-
- ch = UART_GET_DATA(uart);
- uart->port.icount.rx++;
-
+ do {
+ /*
+ * This could be an Rx Intr for err (no data),
+ * so check err and clear that Intr first
+ */
if (unlikely(status & (RXOERR | RXFERR))) {
if (status & RXOERR) {
uart->port.icount.overrun++;
@@ -242,14 +242,19 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart)
} else
flg = TTY_NORMAL;
- if (unlikely(uart_handle_sysrq_char(&uart->port, ch)))
- goto done;
+ if (status & RXEMPTY)
+ continue;
- uart_insert_char(&uart->port, status, RXOERR, ch, flg);
+ ch = UART_GET_DATA(uart);
+ uart->port.icount.rx++;
+
+ if (!(uart_handle_sysrq_char(&uart->port, ch)))
+ uart_insert_char(&uart->port, status, RXOERR, ch, flg);
-done:
+ spin_unlock(&uart->port.lock);
tty_flip_buffer_push(&uart->port.state->port);
- }
+ spin_lock(&uart->port.lock);
+ } while (!((status = UART_GET_STATUS(uart)) & RXEMPTY));
}
/*
@@ -292,11 +297,11 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id)
* notifications from the UART Controller.
* To demultiplex between the two, we check the relevant bits
*/
- if ((status & RXIENB) && !(status & RXEMPTY)) {
+ if (status & RXIENB) {
/* already in ISR, no need of xx_irqsave */
spin_lock(&uart->port.lock);
- arc_serial_rx_chars(uart);
+ arc_serial_rx_chars(uart, status);
spin_unlock(&uart->port.lock);
}
@@ -528,7 +533,7 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id)
unsigned long *plat_data;
struct arc_uart_port *uart = &arc_uart_ports[dev_id];
- plat_data = ((unsigned long *)(pdev->dev.platform_data));
+ plat_data = (unsigned long *)dev_get_platdata(&pdev->dev);
if (!plat_data)
return -ENODEV;
@@ -773,6 +778,6 @@ module_init(arc_serial_init);
module_exit(arc_serial_exit);
MODULE_LICENSE("GPL");
-MODULE_ALIAS("plat-arcfpga/uart");
+MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Vineet Gupta");
MODULE_DESCRIPTION("ARC(Synopsys) On-Chip(fpga) serial driver");
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 691265faebb..d067285a2d2 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -39,8 +39,8 @@
#include <linux/atmel_pdc.h>
#include <linux/atmel_serial.h>
#include <linux/uaccess.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/atmel.h>
+#include <linux/timer.h>
#include <asm/io.h>
#include <asm/ioctls.h>
@@ -98,6 +98,7 @@ static void atmel_stop_rx(struct uart_port *port);
#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR)
+#define UART_GET_IP_NAME(port) __raw_readl((port)->membase + ATMEL_US_NAME)
/* PDC registers */
#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
@@ -140,13 +141,25 @@ struct atmel_uart_port {
u32 backup_imr; /* IMR saved during suspend */
int break_active; /* break being received */
- short use_dma_rx; /* enable PDC receiver */
+ bool use_dma_rx; /* enable DMA receiver */
+ bool use_pdc_rx; /* enable PDC receiver */
short pdc_rx_idx; /* current PDC RX buffer */
struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */
- short use_dma_tx; /* enable PDC transmitter */
+ bool use_dma_tx; /* enable DMA transmitter */
+ bool use_pdc_tx; /* enable PDC transmitter */
struct atmel_dma_buffer pdc_tx; /* PDC transmitter */
+ spinlock_t lock_tx; /* port lock */
+ spinlock_t lock_rx; /* port lock */
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+ struct dma_async_tx_descriptor *desc_tx;
+ struct dma_async_tx_descriptor *desc_rx;
+ dma_cookie_t cookie_tx;
+ dma_cookie_t cookie_rx;
+ struct scatterlist sg_tx;
+ struct scatterlist sg_rx;
struct tasklet_struct tasklet;
unsigned int irq_status;
unsigned int irq_status_prev;
@@ -155,6 +168,14 @@ struct atmel_uart_port {
struct serial_rs485 rs485; /* rs485 settings */
unsigned int tx_done_mask;
+ bool is_usart; /* usart or uart */
+ struct timer_list uart_timer; /* uart timer */
+ int (*prepare_rx)(struct uart_port *port);
+ int (*prepare_tx)(struct uart_port *port);
+ void (*schedule_rx)(struct uart_port *port);
+ void (*schedule_tx)(struct uart_port *port);
+ void (*release_rx)(struct uart_port *port);
+ void (*release_tx)(struct uart_port *port);
};
static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
@@ -181,31 +202,45 @@ to_atmel_uart_port(struct uart_port *uart)
}
#ifdef CONFIG_SERIAL_ATMEL_PDC
-static bool atmel_use_dma_rx(struct uart_port *port)
+static bool atmel_use_pdc_rx(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- return atmel_port->use_dma_rx;
+ return atmel_port->use_pdc_rx;
}
-static bool atmel_use_dma_tx(struct uart_port *port)
+static bool atmel_use_pdc_tx(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- return atmel_port->use_dma_tx;
+ return atmel_port->use_pdc_tx;
}
#else
-static bool atmel_use_dma_rx(struct uart_port *port)
+static bool atmel_use_pdc_rx(struct uart_port *port)
{
return false;
}
-static bool atmel_use_dma_tx(struct uart_port *port)
+static bool atmel_use_pdc_tx(struct uart_port *port)
{
return false;
}
#endif
+static bool atmel_use_dma_tx(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ return atmel_port->use_dma_tx;
+}
+
+static bool atmel_use_dma_rx(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ return atmel_port->use_dma_rx;
+}
+
/* Enable or disable the rs485 support */
void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
{
@@ -233,7 +268,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
mode |= ATMEL_US_USMODE_RS485;
} else {
dev_dbg(port->dev, "Setting UART to RS232\n");
- if (atmel_use_dma_tx(port))
+ if (atmel_use_pdc_tx(port))
atmel_port->tx_done_mask = ATMEL_US_ENDTX |
ATMEL_US_TXBUFE;
else
@@ -345,7 +380,7 @@ static void atmel_stop_tx(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- if (atmel_use_dma_tx(port)) {
+ if (atmel_use_pdc_tx(port)) {
/* disable PDC transmit */
UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
}
@@ -364,7 +399,7 @@ static void atmel_start_tx(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- if (atmel_use_dma_tx(port)) {
+ if (atmel_use_pdc_tx(port)) {
if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
/* The transmitter is already running. Yes, we
really need this.*/
@@ -390,7 +425,7 @@ static void atmel_start_rx(struct uart_port *port)
UART_PUT_CR(port, ATMEL_US_RXEN);
- if (atmel_use_dma_rx(port)) {
+ if (atmel_use_pdc_rx(port)) {
/* enable PDC controller */
UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
port->read_status_mask);
@@ -407,7 +442,7 @@ static void atmel_stop_rx(struct uart_port *port)
{
UART_PUT_CR(port, ATMEL_US_RXDIS);
- if (atmel_use_dma_rx(port)) {
+ if (atmel_use_pdc_rx(port)) {
/* disable PDC receive */
UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
@@ -564,6 +599,372 @@ static void atmel_tx_chars(struct uart_port *port)
UART_PUT_IER(port, atmel_port->tx_done_mask);
}
+static void atmel_complete_tx_dma(void *arg)
+{
+ struct atmel_uart_port *atmel_port = arg;
+ struct uart_port *port = &atmel_port->uart;
+ struct circ_buf *xmit = &port->state->xmit;
+ struct dma_chan *chan = atmel_port->chan_tx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (chan)
+ dmaengine_terminate_all(chan);
+ xmit->tail += sg_dma_len(&atmel_port->sg_tx);
+ xmit->tail &= UART_XMIT_SIZE - 1;
+
+ port->icount.tx += sg_dma_len(&atmel_port->sg_tx);
+
+ spin_lock_irq(&atmel_port->lock_tx);
+ async_tx_ack(atmel_port->desc_tx);
+ atmel_port->cookie_tx = -EINVAL;
+ atmel_port->desc_tx = NULL;
+ spin_unlock_irq(&atmel_port->lock_tx);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ /* Do we really need this? */
+ if (!uart_circ_empty(xmit))
+ tasklet_schedule(&atmel_port->tasklet);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void atmel_release_tx_dma(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct dma_chan *chan = atmel_port->chan_tx;
+
+ if (chan) {
+ dmaengine_terminate_all(chan);
+ dma_release_channel(chan);
+ dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1,
+ DMA_MEM_TO_DEV);
+ }
+
+ atmel_port->desc_tx = NULL;
+ atmel_port->chan_tx = NULL;
+ atmel_port->cookie_tx = -EINVAL;
+}
+
+/*
+ * Called from tasklet with TXRDY interrupt is disabled.
+ */
+static void atmel_tx_dma(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct circ_buf *xmit = &port->state->xmit;
+ struct dma_chan *chan = atmel_port->chan_tx;
+ struct dma_async_tx_descriptor *desc;
+ struct scatterlist *sg = &atmel_port->sg_tx;
+
+ /* Make sure we have an idle channel */
+ if (atmel_port->desc_tx != NULL)
+ return;
+
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+ /*
+ * DMA is idle now.
+ * Port xmit buffer is already mapped,
+ * and it is one page... Just adjust
+ * offsets and lengths. Since it is a circular buffer,
+ * we have to transmit till the end, and then the rest.
+ * Take the port lock to get a
+ * consistent xmit buffer state.
+ */
+ sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+ sg_dma_address(sg) = (sg_dma_address(sg) &
+ ~(UART_XMIT_SIZE - 1))
+ + sg->offset;
+ sg_dma_len(sg) = CIRC_CNT_TO_END(xmit->head,
+ xmit->tail,
+ UART_XMIT_SIZE);
+ BUG_ON(!sg_dma_len(sg));
+
+ desc = dmaengine_prep_slave_sg(chan,
+ sg,
+ 1,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT |
+ DMA_CTRL_ACK);
+ if (!desc) {
+ dev_err(port->dev, "Failed to send via dma!\n");
+ return;
+ }
+
+ dma_sync_sg_for_device(port->dev, sg, 1, DMA_MEM_TO_DEV);
+
+ atmel_port->desc_tx = desc;
+ desc->callback = atmel_complete_tx_dma;
+ desc->callback_param = atmel_port;
+ atmel_port->cookie_tx = dmaengine_submit(desc);
+
+ } else {
+ if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+ /* DMA done, stop TX, start RX for RS485 */
+ atmel_start_rx(port);
+ }
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static int atmel_prepare_tx_dma(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ dma_cap_mask_t mask;
+ struct dma_slave_config config;
+ int ret, nent;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ atmel_port->chan_tx = dma_request_slave_channel(port->dev, "tx");
+ if (atmel_port->chan_tx == NULL)
+ goto chan_err;
+ dev_info(port->dev, "using %s for tx DMA transfers\n",
+ dma_chan_name(atmel_port->chan_tx));
+
+ spin_lock_init(&atmel_port->lock_tx);
+ sg_init_table(&atmel_port->sg_tx, 1);
+ /* UART circular tx buffer is an aligned page. */
+ BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+ sg_set_page(&atmel_port->sg_tx,
+ virt_to_page(port->state->xmit.buf),
+ UART_XMIT_SIZE,
+ (int)port->state->xmit.buf & ~PAGE_MASK);
+ nent = dma_map_sg(port->dev,
+ &atmel_port->sg_tx,
+ 1,
+ DMA_MEM_TO_DEV);
+
+ if (!nent) {
+ dev_dbg(port->dev, "need to release resource of dma\n");
+ goto chan_err;
+ } else {
+ dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+ sg_dma_len(&atmel_port->sg_tx),
+ port->state->xmit.buf,
+ sg_dma_address(&atmel_port->sg_tx));
+ }
+
+ /* Configure the slave DMA */
+ memset(&config, 0, sizeof(config));
+ config.direction = DMA_MEM_TO_DEV;
+ config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ config.dst_addr = port->mapbase + ATMEL_US_THR;
+
+ ret = dmaengine_device_control(atmel_port->chan_tx,
+ DMA_SLAVE_CONFIG,
+ (unsigned long)&config);
+ if (ret) {
+ dev_err(port->dev, "DMA tx slave configuration failed\n");
+ goto chan_err;
+ }
+
+ return 0;
+
+chan_err:
+ dev_err(port->dev, "TX channel not available, switch to pio\n");
+ atmel_port->use_dma_tx = 0;
+ if (atmel_port->chan_tx)
+ atmel_release_tx_dma(port);
+ return -EINVAL;
+}
+
+static void atmel_flip_buffer_rx_dma(struct uart_port *port,
+ char *buf, size_t count)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct tty_port *tport = &port->state->port;
+
+ dma_sync_sg_for_cpu(port->dev,
+ &atmel_port->sg_rx,
+ 1,
+ DMA_DEV_TO_MEM);
+
+ tty_insert_flip_string(tport, buf, count);
+
+ dma_sync_sg_for_device(port->dev,
+ &atmel_port->sg_rx,
+ 1,
+ DMA_DEV_TO_MEM);
+ /*
+ * Drop the lock here since it might end up calling
+ * uart_start(), which takes the lock.
+ */
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(tport);
+ spin_lock(&port->lock);
+}
+
+static void atmel_complete_rx_dma(void *arg)
+{
+ struct uart_port *port = arg;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ tasklet_schedule(&atmel_port->tasklet);
+}
+
+static void atmel_release_rx_dma(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct dma_chan *chan = atmel_port->chan_rx;
+
+ if (chan) {
+ dmaengine_terminate_all(chan);
+ dma_release_channel(chan);
+ dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1,
+ DMA_DEV_TO_MEM);
+ }
+
+ atmel_port->desc_rx = NULL;
+ atmel_port->chan_rx = NULL;
+ atmel_port->cookie_rx = -EINVAL;
+
+ if (!atmel_port->is_usart)
+ del_timer_sync(&atmel_port->uart_timer);
+}
+
+static void atmel_rx_from_dma(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct circ_buf *ring = &atmel_port->rx_ring;
+ struct dma_chan *chan = atmel_port->chan_rx;
+ struct dma_tx_state state;
+ enum dma_status dmastat;
+ size_t pending, count;
+
+
+ /* Reset the UART timeout early so that we don't miss one */
+ UART_PUT_CR(port, ATMEL_US_STTTO);
+ dmastat = dmaengine_tx_status(chan,
+ atmel_port->cookie_rx,
+ &state);
+ /* Restart a new tasklet if DMA status is error */
+ if (dmastat == DMA_ERROR) {
+ dev_dbg(port->dev, "Get residue error, restart tasklet\n");
+ UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+ tasklet_schedule(&atmel_port->tasklet);
+ return;
+ }
+ /* current transfer size should no larger than dma buffer */
+ pending = sg_dma_len(&atmel_port->sg_rx) - state.residue;
+ BUG_ON(pending > sg_dma_len(&atmel_port->sg_rx));
+
+ /*
+ * This will take the chars we have so far,
+ * ring->head will record the transfer size, only new bytes come
+ * will insert into the framework.
+ */
+ if (pending > ring->head) {
+ count = pending - ring->head;
+
+ atmel_flip_buffer_rx_dma(port, ring->buf + ring->head, count);
+
+ ring->head += count;
+ if (ring->head == sg_dma_len(&atmel_port->sg_rx))
+ ring->head = 0;
+
+ port->icount.rx += count;
+ }
+
+ UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+}
+
+static int atmel_prepare_rx_dma(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct dma_async_tx_descriptor *desc;
+ dma_cap_mask_t mask;
+ struct dma_slave_config config;
+ struct circ_buf *ring;
+ int ret, nent;
+
+ ring = &atmel_port->rx_ring;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_CYCLIC, mask);
+
+ atmel_port->chan_rx = dma_request_slave_channel(port->dev, "rx");
+ if (atmel_port->chan_rx == NULL)
+ goto chan_err;
+ dev_info(port->dev, "using %s for rx DMA transfers\n",
+ dma_chan_name(atmel_port->chan_rx));
+
+ spin_lock_init(&atmel_port->lock_rx);
+ sg_init_table(&atmel_port->sg_rx, 1);
+ /* UART circular rx buffer is an aligned page. */
+ BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+ sg_set_page(&atmel_port->sg_rx,
+ virt_to_page(ring->buf),
+ ATMEL_SERIAL_RINGSIZE,
+ (int)ring->buf & ~PAGE_MASK);
+ nent = dma_map_sg(port->dev,
+ &atmel_port->sg_rx,
+ 1,
+ DMA_DEV_TO_MEM);
+
+ if (!nent) {
+ dev_dbg(port->dev, "need to release resource of dma\n");
+ goto chan_err;
+ } else {
+ dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+ sg_dma_len(&atmel_port->sg_rx),
+ ring->buf,
+ sg_dma_address(&atmel_port->sg_rx));
+ }
+
+ /* Configure the slave DMA */
+ memset(&config, 0, sizeof(config));
+ config.direction = DMA_DEV_TO_MEM;
+ config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ config.src_addr = port->mapbase + ATMEL_US_RHR;
+
+ ret = dmaengine_device_control(atmel_port->chan_rx,
+ DMA_SLAVE_CONFIG,
+ (unsigned long)&config);
+ if (ret) {
+ dev_err(port->dev, "DMA rx slave configuration failed\n");
+ goto chan_err;
+ }
+ /*
+ * Prepare a cyclic dma transfer, assign 2 descriptors,
+ * each one is half ring buffer size
+ */
+ desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx,
+ sg_dma_address(&atmel_port->sg_rx),
+ sg_dma_len(&atmel_port->sg_rx),
+ sg_dma_len(&atmel_port->sg_rx)/2,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ desc->callback = atmel_complete_rx_dma;
+ desc->callback_param = port;
+ atmel_port->desc_rx = desc;
+ atmel_port->cookie_rx = dmaengine_submit(desc);
+
+ return 0;
+
+chan_err:
+ dev_err(port->dev, "RX channel not available, switch to pio\n");
+ atmel_port->use_dma_rx = 0;
+ if (atmel_port->chan_rx)
+ atmel_release_rx_dma(port);
+ return -EINVAL;
+}
+
+static void atmel_uart_timer_callback(unsigned long data)
+{
+ struct uart_port *port = (void *)data;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ tasklet_schedule(&atmel_port->tasklet);
+ mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port));
+}
+
/*
* receive interrupt handler.
*/
@@ -572,7 +973,7 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- if (atmel_use_dma_rx(port)) {
+ if (atmel_use_pdc_rx(port)) {
/*
* PDC receive. Just schedule the tasklet and let it
* figure out the details.
@@ -591,6 +992,13 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
atmel_pdc_rxerr(port, pending);
}
+ if (atmel_use_dma_rx(port)) {
+ if (pending & ATMEL_US_TIMEOUT) {
+ UART_PUT_IDR(port, ATMEL_US_TIMEOUT);
+ tasklet_schedule(&atmel_port->tasklet);
+ }
+ }
+
/* Interrupt receive */
if (pending & ATMEL_US_RXRDY)
atmel_rx_chars(port);
@@ -658,10 +1066,21 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
return pass_counter ? IRQ_HANDLED : IRQ_NONE;
}
+static void atmel_release_tx_pdc(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+
+ dma_unmap_single(port->dev,
+ pdc->dma_addr,
+ pdc->dma_size,
+ DMA_TO_DEVICE);
+}
+
/*
* Called from tasklet with ENDTX and TXBUFE interrupts disabled.
*/
-static void atmel_tx_dma(struct uart_port *port)
+static void atmel_tx_pdc(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
struct circ_buf *xmit = &port->state->xmit;
@@ -710,6 +1129,23 @@ static void atmel_tx_dma(struct uart_port *port)
uart_write_wakeup(port);
}
+static int atmel_prepare_tx_pdc(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+ struct circ_buf *xmit = &port->state->xmit;
+
+ pdc->buf = xmit->buf;
+ pdc->dma_addr = dma_map_single(port->dev,
+ pdc->buf,
+ UART_XMIT_SIZE,
+ DMA_TO_DEVICE);
+ pdc->dma_size = UART_XMIT_SIZE;
+ pdc->ofs = 0;
+
+ return 0;
+}
+
static void atmel_rx_from_ring(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -778,7 +1214,26 @@ static void atmel_rx_from_ring(struct uart_port *port)
spin_lock(&port->lock);
}
-static void atmel_rx_from_dma(struct uart_port *port)
+static void atmel_release_rx_pdc(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+ dma_unmap_single(port->dev,
+ pdc->dma_addr,
+ pdc->dma_size,
+ DMA_FROM_DEVICE);
+ kfree(pdc->buf);
+ }
+
+ if (!atmel_port->is_usart)
+ del_timer_sync(&atmel_port->uart_timer);
+}
+
+static void atmel_rx_from_pdc(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
struct tty_port *tport = &port->state->port;
@@ -855,6 +1310,45 @@ static void atmel_rx_from_dma(struct uart_port *port)
UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
}
+static int atmel_prepare_rx_pdc(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+ pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
+ if (pdc->buf == NULL) {
+ if (i != 0) {
+ dma_unmap_single(port->dev,
+ atmel_port->pdc_rx[0].dma_addr,
+ PDC_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ kfree(atmel_port->pdc_rx[0].buf);
+ }
+ atmel_port->use_pdc_rx = 0;
+ return -ENOMEM;
+ }
+ pdc->dma_addr = dma_map_single(port->dev,
+ pdc->buf,
+ PDC_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ pdc->dma_size = PDC_BUFFER_SIZE;
+ pdc->ofs = 0;
+ }
+
+ atmel_port->pdc_rx_idx = 0;
+
+ UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
+ UART_PUT_RCR(port, PDC_BUFFER_SIZE);
+
+ UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
+ UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+
+ return 0;
+}
+
/*
* tasklet handling tty stuff outside the interrupt handler.
*/
@@ -868,10 +1362,7 @@ static void atmel_tasklet_func(unsigned long data)
/* The interrupt handler does not take the lock */
spin_lock(&port->lock);
- if (atmel_use_dma_tx(port))
- atmel_tx_dma(port);
- else
- atmel_tx_chars(port);
+ atmel_port->schedule_tx(port);
status = atmel_port->irq_status;
status_change = status ^ atmel_port->irq_status_prev;
@@ -893,19 +1384,152 @@ static void atmel_tasklet_func(unsigned long data)
atmel_port->irq_status_prev = status;
}
- if (atmel_use_dma_rx(port))
- atmel_rx_from_dma(port);
- else
- atmel_rx_from_ring(port);
+ atmel_port->schedule_rx(port);
spin_unlock(&port->lock);
}
+static int atmel_init_property(struct atmel_uart_port *atmel_port,
+ struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
+
+ if (np) {
+ /* DMA/PDC usage specification */
+ if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
+ if (of_get_property(np, "dmas", NULL)) {
+ atmel_port->use_dma_rx = true;
+ atmel_port->use_pdc_rx = false;
+ } else {
+ atmel_port->use_dma_rx = false;
+ atmel_port->use_pdc_rx = true;
+ }
+ } else {
+ atmel_port->use_dma_rx = false;
+ atmel_port->use_pdc_rx = false;
+ }
+
+ if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
+ if (of_get_property(np, "dmas", NULL)) {
+ atmel_port->use_dma_tx = true;
+ atmel_port->use_pdc_tx = false;
+ } else {
+ atmel_port->use_dma_tx = false;
+ atmel_port->use_pdc_tx = true;
+ }
+ } else {
+ atmel_port->use_dma_tx = false;
+ atmel_port->use_pdc_tx = false;
+ }
+
+ } else {
+ atmel_port->use_pdc_rx = pdata->use_dma_rx;
+ atmel_port->use_pdc_tx = pdata->use_dma_tx;
+ atmel_port->use_dma_rx = false;
+ atmel_port->use_dma_tx = false;
+ }
+
+ return 0;
+}
+
+static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
+ struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
+
+ if (np) {
+ u32 rs485_delay[2];
+ /* rs485 properties */
+ if (of_property_read_u32_array(np, "rs485-rts-delay",
+ rs485_delay, 2) == 0) {
+ struct serial_rs485 *rs485conf = &atmel_port->rs485;
+
+ rs485conf->delay_rts_before_send = rs485_delay[0];
+ rs485conf->delay_rts_after_send = rs485_delay[1];
+ rs485conf->flags = 0;
+
+ if (of_get_property(np, "rs485-rx-during-tx", NULL))
+ rs485conf->flags |= SER_RS485_RX_DURING_TX;
+
+ if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
+ NULL))
+ rs485conf->flags |= SER_RS485_ENABLED;
+ }
+ } else {
+ atmel_port->rs485 = pdata->rs485;
+ }
+
+}
+
+static void atmel_set_ops(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ if (atmel_use_dma_rx(port)) {
+ atmel_port->prepare_rx = &atmel_prepare_rx_dma;
+ atmel_port->schedule_rx = &atmel_rx_from_dma;
+ atmel_port->release_rx = &atmel_release_rx_dma;
+ } else if (atmel_use_pdc_rx(port)) {
+ atmel_port->prepare_rx = &atmel_prepare_rx_pdc;
+ atmel_port->schedule_rx = &atmel_rx_from_pdc;
+ atmel_port->release_rx = &atmel_release_rx_pdc;
+ } else {
+ atmel_port->prepare_rx = NULL;
+ atmel_port->schedule_rx = &atmel_rx_from_ring;
+ atmel_port->release_rx = NULL;
+ }
+
+ if (atmel_use_dma_tx(port)) {
+ atmel_port->prepare_tx = &atmel_prepare_tx_dma;
+ atmel_port->schedule_tx = &atmel_tx_dma;
+ atmel_port->release_tx = &atmel_release_tx_dma;
+ } else if (atmel_use_pdc_tx(port)) {
+ atmel_port->prepare_tx = &atmel_prepare_tx_pdc;
+ atmel_port->schedule_tx = &atmel_tx_pdc;
+ atmel_port->release_tx = &atmel_release_tx_pdc;
+ } else {
+ atmel_port->prepare_tx = NULL;
+ atmel_port->schedule_tx = &atmel_tx_chars;
+ atmel_port->release_tx = NULL;
+ }
+}
+
+/*
+ * Get ip name usart or uart
+ */
+static int atmel_get_ip_name(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ int name = UART_GET_IP_NAME(port);
+ int usart, uart;
+ /* usart and uart ascii */
+ usart = 0x55534152;
+ uart = 0x44424755;
+
+ atmel_port->is_usart = false;
+
+ if (name == usart) {
+ dev_dbg(port->dev, "This is usart\n");
+ atmel_port->is_usart = true;
+ } else if (name == uart) {
+ dev_dbg(port->dev, "This is uart\n");
+ atmel_port->is_usart = false;
+ } else {
+ dev_err(port->dev, "Not supported ip name, set to uart\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/*
* Perform initialization and enable port for reception
*/
static int atmel_startup(struct uart_port *port)
{
+ struct platform_device *pdev = to_platform_device(port->dev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
struct tty_struct *tty = port->state->port.tty;
int retval;
@@ -930,53 +1554,19 @@ static int atmel_startup(struct uart_port *port)
/*
* Initialize DMA (if necessary)
*/
- if (atmel_use_dma_rx(port)) {
- int i;
-
- for (i = 0; i < 2; i++) {
- struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-
- pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
- if (pdc->buf == NULL) {
- if (i != 0) {
- dma_unmap_single(port->dev,
- atmel_port->pdc_rx[0].dma_addr,
- PDC_BUFFER_SIZE,
- DMA_FROM_DEVICE);
- kfree(atmel_port->pdc_rx[0].buf);
- }
- free_irq(port->irq, port);
- return -ENOMEM;
- }
- pdc->dma_addr = dma_map_single(port->dev,
- pdc->buf,
- PDC_BUFFER_SIZE,
- DMA_FROM_DEVICE);
- pdc->dma_size = PDC_BUFFER_SIZE;
- pdc->ofs = 0;
- }
+ atmel_init_property(atmel_port, pdev);
- atmel_port->pdc_rx_idx = 0;
-
- UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
- UART_PUT_RCR(port, PDC_BUFFER_SIZE);
-
- UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
- UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+ if (atmel_port->prepare_rx) {
+ retval = atmel_port->prepare_rx(port);
+ if (retval < 0)
+ atmel_set_ops(port);
}
- if (atmel_use_dma_tx(port)) {
- struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
- struct circ_buf *xmit = &port->state->xmit;
- pdc->buf = xmit->buf;
- pdc->dma_addr = dma_map_single(port->dev,
- pdc->buf,
- UART_XMIT_SIZE,
- DMA_TO_DEVICE);
- pdc->dma_size = UART_XMIT_SIZE;
- pdc->ofs = 0;
+ if (atmel_port->prepare_tx) {
+ retval = atmel_port->prepare_tx(port);
+ if (retval < 0)
+ atmel_set_ops(port);
}
-
/*
* If there is a specific "open" function (to register
* control line interrupts)
@@ -1000,14 +1590,38 @@ static int atmel_startup(struct uart_port *port)
/* enable xmit & rcvr */
UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
- if (atmel_use_dma_rx(port)) {
+ if (atmel_use_pdc_rx(port)) {
/* set UART timeout */
- UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
- UART_PUT_CR(port, ATMEL_US_STTTO);
-
- UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+ if (!atmel_port->is_usart) {
+ setup_timer(&atmel_port->uart_timer,
+ atmel_uart_timer_callback,
+ (unsigned long)port);
+ mod_timer(&atmel_port->uart_timer,
+ jiffies + uart_poll_timeout(port));
+ /* set USART timeout */
+ } else {
+ UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+ UART_PUT_CR(port, ATMEL_US_STTTO);
+
+ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+ }
/* enable PDC controller */
UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+ } else if (atmel_use_dma_rx(port)) {
+ /* set UART timeout */
+ if (!atmel_port->is_usart) {
+ setup_timer(&atmel_port->uart_timer,
+ atmel_uart_timer_callback,
+ (unsigned long)port);
+ mod_timer(&atmel_port->uart_timer,
+ jiffies + uart_poll_timeout(port));
+ /* set USART timeout */
+ } else {
+ UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+ UART_PUT_CR(port, ATMEL_US_STTTO);
+
+ UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+ }
} else {
/* enable receive only */
UART_PUT_IER(port, ATMEL_US_RXRDY);
@@ -1031,27 +1645,10 @@ static void atmel_shutdown(struct uart_port *port)
/*
* Shut-down the DMA.
*/
- if (atmel_use_dma_rx(port)) {
- int i;
-
- for (i = 0; i < 2; i++) {
- struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-
- dma_unmap_single(port->dev,
- pdc->dma_addr,
- pdc->dma_size,
- DMA_FROM_DEVICE);
- kfree(pdc->buf);
- }
- }
- if (atmel_use_dma_tx(port)) {
- struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-
- dma_unmap_single(port->dev,
- pdc->dma_addr,
- pdc->dma_size,
- DMA_TO_DEVICE);
- }
+ if (atmel_port->release_rx)
+ atmel_port->release_rx(port);
+ if (atmel_port->release_tx)
+ atmel_port->release_tx(port);
/*
* Disable all interrupts, port and break condition.
@@ -1080,7 +1677,7 @@ static void atmel_flush_buffer(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- if (atmel_use_dma_tx(port)) {
+ if (atmel_use_pdc_tx(port)) {
UART_PUT_TCR(port, 0);
atmel_port->pdc_tx.ofs = 0;
}
@@ -1193,7 +1790,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= ATMEL_US_RXBRK;
- if (atmel_use_dma_rx(port))
+ if (atmel_use_pdc_rx(port))
/* need to enable error interrupts */
UART_PUT_IER(port, port->read_status_mask);
@@ -1423,38 +2020,6 @@ static struct uart_ops atmel_pops = {
#endif
};
-static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
- struct device_node *np)
-{
- u32 rs485_delay[2];
-
- /* DMA/PDC usage specification */
- if (of_get_property(np, "atmel,use-dma-rx", NULL))
- atmel_port->use_dma_rx = 1;
- else
- atmel_port->use_dma_rx = 0;
- if (of_get_property(np, "atmel,use-dma-tx", NULL))
- atmel_port->use_dma_tx = 1;
- else
- atmel_port->use_dma_tx = 0;
-
- /* rs485 properties */
- if (of_property_read_u32_array(np, "rs485-rts-delay",
- rs485_delay, 2) == 0) {
- struct serial_rs485 *rs485conf = &atmel_port->rs485;
-
- rs485conf->delay_rts_before_send = rs485_delay[0];
- rs485conf->delay_rts_after_send = rs485_delay[1];
- rs485conf->flags = 0;
-
- if (of_get_property(np, "rs485-rx-during-tx", NULL))
- rs485conf->flags |= SER_RS485_RX_DURING_TX;
-
- if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
- rs485conf->flags |= SER_RS485_ENABLED;
- }
-}
-
/*
* Configure the port from the platform device resource info.
*/
@@ -1463,15 +2028,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
{
int ret;
struct uart_port *port = &atmel_port->uart;
- struct atmel_uart_data *pdata = pdev->dev.platform_data;
+ struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
- if (pdev->dev.of_node) {
- atmel_of_init_port(atmel_port, pdev->dev.of_node);
- } else {
- atmel_port->use_dma_rx = pdata->use_dma_rx;
- atmel_port->use_dma_tx = pdata->use_dma_tx;
- atmel_port->rs485 = pdata->rs485;
- }
+ if (!atmel_init_property(atmel_port, pdev))
+ atmel_set_ops(port);
+
+ atmel_init_rs485(atmel_port, pdev);
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
@@ -1516,7 +2078,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
if (atmel_port->rs485.flags & SER_RS485_ENABLED)
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
- else if (atmel_use_dma_tx(port)) {
+ else if (atmel_use_pdc_tx(port)) {
port->fifosize = PDC_BUFFER_SIZE;
atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
} else {
@@ -1664,7 +2226,7 @@ static int __init atmel_console_init(void)
int ret;
if (atmel_default_console_device) {
struct atmel_uart_data *pdata =
- atmel_default_console_device->dev.platform_data;
+ dev_get_platdata(&atmel_default_console_device->dev);
int id = pdata->num;
struct atmel_uart_port *port = &atmel_ports[id];
@@ -1772,10 +2334,9 @@ static int atmel_serial_probe(struct platform_device *pdev)
{
struct atmel_uart_port *port;
struct device_node *np = pdev->dev.of_node;
- struct atmel_uart_data *pdata = pdev->dev.platform_data;
+ struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
void *data;
int ret = -ENODEV;
- struct pinctrl *pinctrl;
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
@@ -1809,13 +2370,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
if (ret)
goto err;
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- ret = PTR_ERR(pinctrl);
- goto err;
- }
-
- if (!atmel_use_dma_rx(&port->uart)) {
+ if (!atmel_use_pdc_rx(&port->uart)) {
ret = -ENOMEM;
data = kmalloc(sizeof(struct atmel_uart_char)
* ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
@@ -1847,6 +2402,13 @@ static int atmel_serial_probe(struct platform_device *pdev)
UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
}
+ /*
+ * Get port name of usart or uart
+ */
+ ret = atmel_get_ip_name(&port->uart);
+ if (ret < 0)
+ goto err_add_port;
+
return 0;
err_add_port:
@@ -1868,7 +2430,6 @@ static int atmel_serial_remove(struct platform_device *pdev)
int ret = 0;
device_init_wakeup(&pdev->dev, 0);
- platform_set_drvdata(pdev, NULL);
ret = uart_remove_one_port(&atmel_uart, port);
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index 6fa2ae77fff..649d5129c4b 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -302,7 +302,9 @@ static void bcm_uart_do_rx(struct uart_port *port)
} while (--max_count);
+ spin_unlock(&port->lock);
tty_flip_buffer_push(tty_port);
+ spin_lock(&port->lock);
}
/*
@@ -852,7 +854,6 @@ static int bcm_uart_remove(struct platform_device *pdev)
port = platform_get_drvdata(pdev);
uart_remove_one_port(&bcm_uart_driver, port);
- platform_set_drvdata(pdev, NULL);
/* mark port as free */
ports[pdev->id].membase = 0;
return 0;
diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c
index 487c173b0f7..87636cc61a2 100644
--- a/drivers/tty/serial/bfin_sport_uart.c
+++ b/drivers/tty/serial/bfin_sport_uart.c
@@ -161,11 +161,12 @@ static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
if (!uart_handle_sysrq_char(&up->port, ch))
tty_insert_flip_char(port, ch, TTY_NORMAL);
}
- /* XXX this won't deadlock with lowlat? */
- tty_flip_buffer_push(port);
spin_unlock(&up->port.lock);
+ /* XXX this won't deadlock with lowlat? */
+ tty_flip_buffer_push(port);
+
return IRQ_HANDLED;
}
@@ -766,7 +767,8 @@ static int sport_uart_probe(struct platform_device *pdev)
}
ret = peripheral_request_list(
- (unsigned short *)pdev->dev.platform_data, DRV_NAME);
+ (unsigned short *)dev_get_platdata(&pdev->dev),
+ DRV_NAME);
if (ret) {
dev_err(&pdev->dev,
"Fail to request SPORT peripherals\n");
@@ -843,7 +845,7 @@ out_error_unmap:
iounmap(sport->port.membase);
out_error_free_peripherals:
peripheral_free_list(
- (unsigned short *)pdev->dev.platform_data);
+ (unsigned short *)dev_get_platdata(&pdev->dev));
out_error_free_mem:
kfree(sport);
bfin_sport_uart_ports[pdev->id] = NULL;
@@ -863,7 +865,7 @@ static int sport_uart_remove(struct platform_device *pdev)
uart_remove_one_port(&sport_uart_reg, &sport->port);
iounmap(sport->port.membase);
peripheral_free_list(
- (unsigned short *)pdev->dev.platform_data);
+ (unsigned short *)dev_get_platdata(&pdev->dev));
kfree(sport);
bfin_sport_uart_ports[pdev->id] = NULL;
}
@@ -883,7 +885,7 @@ static struct platform_driver sport_uart_driver = {
};
#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
-static __initdata struct early_platform_driver early_sport_uart_driver = {
+static struct early_platform_driver early_sport_uart_driver __initdata = {
.class_str = CLASS_BFIN_SPORT_CONSOLE,
.pdrv = &sport_uart_driver,
.requested_id = EARLY_PLATFORM_ID_UNSET,
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 26a3be7ced7..3c75e8e0402 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -41,10 +41,6 @@
# undef CONFIG_EARLY_PRINTK
#endif
-#ifdef CONFIG_SERIAL_BFIN_MODULE
-# undef CONFIG_EARLY_PRINTK
-#endif
-
/* UART name and device definitions */
#define BFIN_SERIAL_DEV_NAME "ttyBF"
#define BFIN_SERIAL_MAJOR 204
@@ -1180,7 +1176,7 @@ bfin_earlyprintk_console_write(struct console *co, const char *s, unsigned int c
* don't let the common infrastructure play with things. (see calls to setup
* & earlysetup in ./kernel/printk.c:register_console()
*/
-static struct __initdata console bfin_early_serial_console = {
+static struct console bfin_early_serial_console __initdata = {
.name = "early_BFuart",
.write = bfin_earlyprintk_console_write,
.device = uart_console_device,
@@ -1244,7 +1240,8 @@ static int bfin_serial_probe(struct platform_device *pdev)
*/
#endif
ret = peripheral_request_list(
- (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
+ (unsigned short *)dev_get_platdata(&pdev->dev),
+ DRIVER_NAME);
if (ret) {
dev_err(&pdev->dev,
"fail to request bfin serial peripherals\n");
@@ -1362,7 +1359,7 @@ out_error_unmap:
iounmap(uart->port.membase);
out_error_free_peripherals:
peripheral_free_list(
- (unsigned short *)pdev->dev.platform_data);
+ (unsigned short *)dev_get_platdata(&pdev->dev));
out_error_free_mem:
kfree(uart);
bfin_serial_ports[pdev->id] = NULL;
@@ -1381,7 +1378,7 @@ static int bfin_serial_remove(struct platform_device *pdev)
uart_remove_one_port(&bfin_serial_reg, &uart->port);
iounmap(uart->port.membase);
peripheral_free_list(
- (unsigned short *)pdev->dev.platform_data);
+ (unsigned short *)dev_get_platdata(&pdev->dev));
kfree(uart);
bfin_serial_ports[pdev->id] = NULL;
}
@@ -1401,7 +1398,7 @@ static struct platform_driver bfin_serial_driver = {
};
#if defined(CONFIG_SERIAL_BFIN_CONSOLE)
-static __initdata struct early_platform_driver early_bfin_serial_driver = {
+static struct early_platform_driver early_bfin_serial_driver __initdata = {
.class_str = CLASS_BFIN_CONSOLE,
.pdrv = &bfin_serial_driver,
.requested_id = EARLY_PLATFORM_ID_UNSET,
@@ -1436,7 +1433,7 @@ static int bfin_earlyprintk_probe(struct platform_device *pdev)
}
ret = peripheral_request_list(
- (unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
+ (unsigned short *)dev_get_platdata(&pdev->dev), DRIVER_NAME);
if (ret) {
dev_err(&pdev->dev,
"fail to request bfin serial peripherals\n");
@@ -1467,7 +1464,7 @@ static int bfin_earlyprintk_probe(struct platform_device *pdev)
out_error_free_peripherals:
peripheral_free_list(
- (unsigned short *)pdev->dev.platform_data);
+ (unsigned short *)dev_get_platdata(&pdev->dev));
return ret;
}
@@ -1480,7 +1477,7 @@ static struct platform_driver bfin_earlyprintk_driver = {
},
};
-static __initdata struct early_platform_driver early_bfin_earlyprintk_driver = {
+static struct early_platform_driver early_bfin_earlyprintk_driver __initdata = {
.class_str = CLASS_BFIN_EARLYPRINTK,
.pdrv = &bfin_earlyprintk_driver,
.requested_id = EARLY_PLATFORM_ID_UNSET,
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index bfb17968c8d..7e4e4088471 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -438,8 +438,7 @@ static int uart_clps711x_probe(struct platform_device *pdev)
s->uart_clk = devm_clk_get(&pdev->dev, "uart");
if (IS_ERR(s->uart_clk)) {
dev_err(&pdev->dev, "Can't get UART clocks\n");
- ret = PTR_ERR(s->uart_clk);
- goto err_out;
+ return PTR_ERR(s->uart_clk);
}
s->uart.owner = THIS_MODULE;
@@ -461,7 +460,7 @@ static int uart_clps711x_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "Registering UART driver failed\n");
devm_clk_put(&pdev->dev, s->uart_clk);
- goto err_out;
+ return ret;
}
for (i = 0; i < UART_CLPS711X_NR; i++) {
@@ -478,11 +477,6 @@ static int uart_clps711x_probe(struct platform_device *pdev)
}
return 0;
-
-err_out:
- platform_set_drvdata(pdev, NULL);
-
- return ret;
}
static int uart_clps711x_remove(struct platform_device *pdev)
@@ -495,7 +489,6 @@ static int uart_clps711x_remove(struct platform_device *pdev)
devm_clk_put(&pdev->dev, s->uart_clk);
uart_unregister_driver(&s->uart);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index f7672cae532..1a535f70dc4 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -1213,8 +1213,32 @@ static int cpm_uart_init_port(struct device_node *np,
goto out_pram;
}
- for (i = 0; i < NUM_GPIOS; i++)
- pinfo->gpios[i] = of_get_gpio(np, i);
+ for (i = 0; i < NUM_GPIOS; i++) {
+ int gpio;
+
+ pinfo->gpios[i] = -1;
+
+ gpio = of_get_gpio(np, i);
+
+ if (gpio_is_valid(gpio)) {
+ ret = gpio_request(gpio, "cpm_uart");
+ if (ret) {
+ pr_err("can't request gpio #%d: %d\n", i, ret);
+ continue;
+ }
+ if (i == GPIO_RTS || i == GPIO_DTR)
+ ret = gpio_direction_output(gpio, 0);
+ else
+ ret = gpio_direction_input(gpio);
+ if (ret) {
+ pr_err("can't set direction for gpio #%d: %d\n",
+ i, ret);
+ gpio_free(gpio);
+ continue;
+ }
+ pinfo->gpios[i] = gpio;
+ }
+ }
#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
udbg_putc = NULL;
diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c
index 7d199c8e1a7..0eb5b5673ed 100644
--- a/drivers/tty/serial/efm32-uart.c
+++ b/drivers/tty/serial/efm32-uart.c
@@ -268,10 +268,10 @@ static irqreturn_t efm32_uart_rxirq(int irq, void *data)
handled = IRQ_HANDLED;
}
- tty_flip_buffer_push(tport);
-
spin_unlock(&port->lock);
+ tty_flip_buffer_push(tport);
+
return handled;
}
@@ -698,6 +698,7 @@ static int efm32_uart_probe(struct platform_device *pdev)
{
struct efm32_uart_port *efm_port;
struct resource *res;
+ unsigned int line;
int ret;
efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL);
@@ -750,18 +751,21 @@ static int efm32_uart_probe(struct platform_device *pdev)
if (pdata)
efm_port->pdata = *pdata;
- }
+ } else if (ret < 0)
+ goto err_probe_dt;
+
+ line = efm_port->port.line;
- if (efm_port->port.line >= 0 &&
- efm_port->port.line < ARRAY_SIZE(efm32_uart_ports))
- efm32_uart_ports[efm_port->port.line] = efm_port;
+ if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports))
+ efm32_uart_ports[line] = efm_port;
ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port);
if (ret) {
dev_dbg(&pdev->dev, "failed to add port: %d\n", ret);
- if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
- efm32_uart_ports[pdev->id] = NULL;
+ if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports))
+ efm32_uart_ports[line] = NULL;
+err_probe_dt:
err_get_rxirq:
err_too_small:
err_get_base:
@@ -777,20 +781,19 @@ err_get_base:
static int efm32_uart_remove(struct platform_device *pdev)
{
struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
-
- platform_set_drvdata(pdev, NULL);
+ unsigned int line = efm_port->port.line;
uart_remove_one_port(&efm32_uart_reg, &efm_port->port);
- if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
- efm32_uart_ports[pdev->id] = NULL;
+ if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports))
+ efm32_uart_ports[line] = NULL;
kfree(efm_port);
return 0;
}
-static struct of_device_id efm32_uart_dt_ids[] = {
+static const struct of_device_id efm32_uart_dt_ids[] = {
{
.compatible = "efm32,uart",
}, {
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 263cfaabe9e..8978dc9a58b 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -342,8 +342,10 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state)
static void lpuart_setup_watermark(struct lpuart_port *sport)
{
unsigned char val, cr2;
+ unsigned char cr2_saved;
cr2 = readb(sport->port.membase + UARTCR2);
+ cr2_saved = cr2;
cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_TE |
UARTCR2_RIE | UARTCR2_RE);
writeb(cr2, sport->port.membase + UARTCR2);
@@ -366,6 +368,9 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
writeb(2, sport->port.membase + UARTTWFIFO);
writeb(1, sport->port.membase + UARTRWFIFO);
+
+ /* Restore cr2 */
+ writeb(cr2_saved, sport->port.membase + UARTCR2);
}
static int lpuart_startup(struct uart_port *port)
@@ -858,7 +863,7 @@ static int __init lpuart_serial_init(void)
if (ret)
uart_unregister_driver(&lpuart_reg);
- return 0;
+ return ret;
}
static void __exit lpuart_serial_exit(void)
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 18ed5aebb16..d98e4334897 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -105,7 +105,7 @@ static const struct pci_device_id icom_pci_table[] = {
{}
};
-struct lookup_proc_table start_proc[4] = {
+static struct lookup_proc_table start_proc[4] = {
{NULL, ICOM_CONTROL_START_A},
{NULL, ICOM_CONTROL_START_B},
{NULL, ICOM_CONTROL_START_C},
@@ -113,14 +113,14 @@ struct lookup_proc_table start_proc[4] = {
};
-struct lookup_proc_table stop_proc[4] = {
+static struct lookup_proc_table stop_proc[4] = {
{NULL, ICOM_CONTROL_STOP_A},
{NULL, ICOM_CONTROL_STOP_B},
{NULL, ICOM_CONTROL_STOP_C},
{NULL, ICOM_CONTROL_STOP_D}
};
-struct lookup_int_table int_mask_tbl[4] = {
+static struct lookup_int_table int_mask_tbl[4] = {
{NULL, ICOM_INT_MASK_PRC_A},
{NULL, ICOM_INT_MASK_PRC_B},
{NULL, ICOM_INT_MASK_PRC_C},
@@ -297,25 +297,25 @@ static void stop_processor(struct icom_port *icom_port)
spin_lock_irqsave(&icom_lock, flags);
port = icom_port->port;
+ if (port >= ARRAY_SIZE(stop_proc)) {
+ dev_err(&icom_port->adapter->pci_dev->dev,
+ "Invalid port assignment\n");
+ goto unlock;
+ }
+
if (port == 0 || port == 1)
stop_proc[port].global_control_reg = &icom_port->global_reg->control;
else
stop_proc[port].global_control_reg = &icom_port->global_reg->control_2;
+ temp = readl(stop_proc[port].global_control_reg);
+ temp = (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
+ writel(temp, stop_proc[port].global_control_reg);
- if (port < 4) {
- temp = readl(stop_proc[port].global_control_reg);
- temp =
- (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
- writel(temp, stop_proc[port].global_control_reg);
-
- /* write flush */
- readl(stop_proc[port].global_control_reg);
- } else {
- dev_err(&icom_port->adapter->pci_dev->dev,
- "Invalid port assignment\n");
- }
+ /* write flush */
+ readl(stop_proc[port].global_control_reg);
+unlock:
spin_unlock_irqrestore(&icom_lock, flags);
}
@@ -328,23 +328,25 @@ static void start_processor(struct icom_port *icom_port)
spin_lock_irqsave(&icom_lock, flags);
port = icom_port->port;
+ if (port >= ARRAY_SIZE(start_proc)) {
+ dev_err(&icom_port->adapter->pci_dev->dev,
+ "Invalid port assignment\n");
+ goto unlock;
+ }
+
if (port == 0 || port == 1)
start_proc[port].global_control_reg = &icom_port->global_reg->control;
else
start_proc[port].global_control_reg = &icom_port->global_reg->control_2;
- if (port < 4) {
- temp = readl(start_proc[port].global_control_reg);
- temp =
- (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
- writel(temp, start_proc[port].global_control_reg);
- /* write flush */
- readl(start_proc[port].global_control_reg);
- } else {
- dev_err(&icom_port->adapter->pci_dev->dev,
- "Invalid port assignment\n");
- }
+ temp = readl(start_proc[port].global_control_reg);
+ temp = (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
+ writel(temp, start_proc[port].global_control_reg);
+
+ /* write flush */
+ readl(start_proc[port].global_control_reg);
+unlock:
spin_unlock_irqrestore(&icom_lock, flags);
}
@@ -557,6 +559,12 @@ static int startup(struct icom_port *icom_port)
*/
spin_lock_irqsave(&icom_lock, flags);
port = icom_port->port;
+ if (port >= ARRAY_SIZE(int_mask_tbl)) {
+ dev_err(&icom_port->adapter->pci_dev->dev,
+ "Invalid port assignment\n");
+ goto unlock;
+ }
+
if (port == 0 || port == 1)
int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
else
@@ -566,17 +574,14 @@ static int startup(struct icom_port *icom_port)
writew(0x00FF, icom_port->int_reg);
else
writew(0x3F00, icom_port->int_reg);
- if (port < 4) {
- temp = readl(int_mask_tbl[port].global_int_mask);
- writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
- /* write flush */
- readl(int_mask_tbl[port].global_int_mask);
- } else {
- dev_err(&icom_port->adapter->pci_dev->dev,
- "Invalid port assignment\n");
- }
+ temp = readl(int_mask_tbl[port].global_int_mask);
+ writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
+ /* write flush */
+ readl(int_mask_tbl[port].global_int_mask);
+
+unlock:
spin_unlock_irqrestore(&icom_lock, flags);
return 0;
}
@@ -595,21 +600,23 @@ static void shutdown(struct icom_port *icom_port)
* disable all interrupts
*/
port = icom_port->port;
+ if (port >= ARRAY_SIZE(int_mask_tbl)) {
+ dev_err(&icom_port->adapter->pci_dev->dev,
+ "Invalid port assignment\n");
+ goto unlock;
+ }
if (port == 0 || port == 1)
int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
else
int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
- if (port < 4) {
- temp = readl(int_mask_tbl[port].global_int_mask);
- writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
+ temp = readl(int_mask_tbl[port].global_int_mask);
+ writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
- /* write flush */
- readl(int_mask_tbl[port].global_int_mask);
- } else {
- dev_err(&icom_port->adapter->pci_dev->dev,
- "Invalid port assignment\n");
- }
+ /* write flush */
+ readl(int_mask_tbl[port].global_int_mask);
+
+unlock:
spin_unlock_irqrestore(&icom_lock, flags);
/*
@@ -834,7 +841,10 @@ ignore_char:
status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
}
icom_port->next_rcv = rcv_buff;
+
+ spin_unlock(&icom_port->uart_port.lock);
tty_flip_buffer_push(port);
+ spin_lock(&icom_port->uart_port.lock);
}
static void process_interrupt(u16 port_int_reg,
@@ -1087,8 +1097,7 @@ static void icom_close(struct uart_port *port)
/* stop receiver */
cmdReg = readb(&ICOM_PORT->dram->CmdReg);
- writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE,
- &ICOM_PORT->dram->CmdReg);
+ writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
shutdown(ICOM_PORT);
@@ -1567,7 +1576,7 @@ static int icom_probe(struct pci_dev *dev,
icom_port->uart_port.type = PORT_ICOM;
icom_port->uart_port.iotype = UPIO_MEM;
icom_port->uart_port.membase =
- (char *) icom_adapter->base_addr_pci;
+ (unsigned char __iomem *)icom_adapter->base_addr_pci;
icom_port->uart_port.fifosize = 16;
icom_port->uart_port.ops = &icom_ops;
icom_port->uart_port.line =
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 8b1534c424a..af286e6713e 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -1008,7 +1008,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
return -ENODEV;
}
- pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data;
+ pl_data = (struct ifx_modem_platform_data *)dev_get_platdata(&spi->dev);
if (!pl_data) {
dev_err(&spi->dev, "missing platform data!");
return -ENODEV;
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 415cec62073..a0ebbc9ce5c 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -47,11 +47,12 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/io.h>
+#include <linux/dma-mapping.h>
#include <asm/irq.h>
#include <linux/platform_data/serial-imx.h>
+#include <linux/platform_data/dma-imx.h>
/* Register definitions */
#define URXD0 0x0 /* Receiver Register */
@@ -83,6 +84,7 @@
#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
+#define UCR1_ICD_REG(x) (((x) & 3) << 10) /* idle condition detect */
#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
#define UCR1_IREN (1<<7) /* Infrared interface enable */
@@ -91,6 +93,7 @@
#define UCR1_SNDBRK (1<<4) /* Send break */
#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
#define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */
+#define UCR1_ATDMAEN (1<<2) /* Aging DMA Timer Enable */
#define UCR1_DOZE (1<<1) /* Doze */
#define UCR1_UARTEN (1<<0) /* UART enabled */
#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */
@@ -126,6 +129,7 @@
#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */
#define UCR4_WKEN (1<<7) /* Wake interrupt enable */
#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */
+#define UCR4_IDDMAEN (1<<6) /* DMA IDLE Condition Detected */
#define UCR4_IRSC (1<<5) /* IR special case */
#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */
#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */
@@ -187,6 +191,7 @@
enum imx_uart_type {
IMX1_UART,
IMX21_UART,
+ IMX6Q_UART,
};
/* device type dependent stuff */
@@ -209,6 +214,19 @@ struct imx_port {
struct clk *clk_ipg;
struct clk *clk_per;
const struct imx_uart_data *devdata;
+
+ /* DMA fields */
+ unsigned int dma_is_inited:1;
+ unsigned int dma_is_enabled:1;
+ unsigned int dma_is_rxing:1;
+ unsigned int dma_is_txing:1;
+ struct dma_chan *dma_chan_rx, *dma_chan_tx;
+ struct scatterlist rx_sgl, tx_sgl[2];
+ void *rx_buf;
+ unsigned int rx_bytes, tx_bytes;
+ struct work_struct tsk_dma_rx, tsk_dma_tx;
+ unsigned int dma_tx_nents;
+ wait_queue_head_t dma_wait;
};
struct imx_port_ucrs {
@@ -232,6 +250,10 @@ static struct imx_uart_data imx_uart_devdata[] = {
.uts_reg = IMX21_UTS,
.devtype = IMX21_UART,
},
+ [IMX6Q_UART] = {
+ .uts_reg = IMX21_UTS,
+ .devtype = IMX6Q_UART,
+ },
};
static struct platform_device_id imx_uart_devtype[] = {
@@ -242,12 +264,16 @@ static struct platform_device_id imx_uart_devtype[] = {
.name = "imx21-uart",
.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART],
}, {
+ .name = "imx6q-uart",
+ .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART],
+ }, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
static struct of_device_id imx_uart_dt_ids[] = {
+ { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], },
{ .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },
{ .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },
{ /* sentinel */ }
@@ -269,6 +295,10 @@ static inline int is_imx21_uart(struct imx_port *sport)
return sport->devdata->devtype == IMX21_UART;
}
+static inline int is_imx6q_uart(struct imx_port *sport)
+{
+ return sport->devdata->devtype == IMX6Q_UART;
+}
/*
* Save and restore functions for UCR1, UCR2 and UCR3 registers
*/
@@ -387,6 +417,13 @@ static void imx_stop_tx(struct uart_port *port)
return;
}
+ /*
+ * We are maybe in the SMP context, so if the DMA TX thread is running
+ * on other cpu, we have to wait for it to finish.
+ */
+ if (sport->dma_is_enabled && sport->dma_is_txing)
+ return;
+
temp = readl(sport->port.membase + UCR1);
writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
}
@@ -399,6 +436,13 @@ static void imx_stop_rx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
+ /*
+ * We are maybe in the SMP context, so if the DMA TX thread is running
+ * on other cpu, we have to wait for it to finish.
+ */
+ if (sport->dma_is_enabled && sport->dma_is_rxing)
+ return;
+
temp = readl(sport->port.membase + UCR2);
writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
}
@@ -434,6 +478,95 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
imx_stop_tx(&sport->port);
}
+static void dma_tx_callback(void *data)
+{
+ struct imx_port *sport = data;
+ struct scatterlist *sgl = &sport->tx_sgl[0];
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long flags;
+
+ dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+
+ sport->dma_is_txing = 0;
+
+ /* update the stat */
+ spin_lock_irqsave(&sport->port.lock, flags);
+ xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx += sport->tx_bytes;
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ if (waitqueue_active(&sport->dma_wait)) {
+ wake_up(&sport->dma_wait);
+ dev_dbg(sport->port.dev, "exit in %s.\n", __func__);
+ return;
+ }
+
+ schedule_work(&sport->tsk_dma_tx);
+}
+
+static void dma_tx_work(struct work_struct *w)
+{
+ struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx);
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ struct scatterlist *sgl = sport->tx_sgl;
+ struct dma_async_tx_descriptor *desc;
+ struct dma_chan *chan = sport->dma_chan_tx;
+ struct device *dev = sport->port.dev;
+ enum dma_status status;
+ unsigned long flags;
+ int ret;
+
+ status = chan->device->device_tx_status(chan, (dma_cookie_t)0, NULL);
+ if (DMA_IN_PROGRESS == status)
+ return;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ sport->tx_bytes = uart_circ_chars_pending(xmit);
+ if (sport->tx_bytes == 0) {
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ return;
+ }
+
+ if (xmit->tail > xmit->head) {
+ sport->dma_tx_nents = 2;
+ sg_init_table(sgl, 2);
+ sg_set_buf(sgl, xmit->buf + xmit->tail,
+ UART_XMIT_SIZE - xmit->tail);
+ sg_set_buf(sgl + 1, xmit->buf, xmit->head);
+ } else {
+ sport->dma_tx_nents = 1;
+ sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
+ }
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+ if (ret == 0) {
+ dev_err(dev, "DMA mapping error for TX.\n");
+ return;
+ }
+ desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+ if (!desc) {
+ dev_err(dev, "We cannot prepare for the TX slave dma!\n");
+ return;
+ }
+ desc->callback = dma_tx_callback;
+ desc->callback_param = sport;
+
+ dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
+ uart_circ_chars_pending(xmit));
+ /* fire it */
+ sport->dma_is_txing = 1;
+ dmaengine_submit(desc);
+ dma_async_issue_pending(chan);
+ return;
+}
+
/*
* interrupts disabled on entry
*/
@@ -460,8 +593,10 @@ static void imx_start_tx(struct uart_port *port)
temp |= UCR4_OREN;
writel(temp, sport->port.membase + UCR4);
- temp = readl(sport->port.membase + UCR1);
- writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+ if (!sport->dma_is_enabled) {
+ temp = readl(sport->port.membase + UCR1);
+ writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+ }
if (USE_IRDA(sport)) {
temp = readl(sport->port.membase + UCR1);
@@ -473,6 +608,15 @@ static void imx_start_tx(struct uart_port *port)
writel(temp, sport->port.membase + UCR4);
}
+ if (sport->dma_is_enabled) {
+ /*
+ * We may in the interrupt context, so arise a work_struct to
+ * do the real job.
+ */
+ schedule_work(&sport->tsk_dma_tx);
+ return;
+ }
+
if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
imx_transmit_buffer(sport);
}
@@ -588,6 +732,28 @@ out:
return IRQ_HANDLED;
}
+/*
+ * If the RXFIFO is filled with some data, and then we
+ * arise a DMA operation to receive them.
+ */
+static void imx_dma_rxint(struct imx_port *sport)
+{
+ unsigned long temp;
+
+ temp = readl(sport->port.membase + USR2);
+ if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
+ sport->dma_is_rxing = 1;
+
+ /* disable the `Recerver Ready Interrrupt` */
+ temp = readl(sport->port.membase + UCR1);
+ temp &= ~(UCR1_RRDYEN);
+ writel(temp, sport->port.membase + UCR1);
+
+ /* tell the DMA to receive the data. */
+ schedule_work(&sport->tsk_dma_rx);
+ }
+}
+
static irqreturn_t imx_int(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
@@ -596,8 +762,12 @@ static irqreturn_t imx_int(int irq, void *dev_id)
sts = readl(sport->port.membase + USR1);
- if (sts & USR1_RRDY)
- imx_rxint(irq, dev_id);
+ if (sts & USR1_RRDY) {
+ if (sport->dma_is_enabled)
+ imx_dma_rxint(sport);
+ else
+ imx_rxint(irq, dev_id);
+ }
if (sts & USR1_TRDY &&
readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
@@ -654,7 +824,8 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
if (mctrl & TIOCM_RTS)
- temp |= UCR2_CTS;
+ if (!sport->dma_is_enabled)
+ temp |= UCR2_CTS;
writel(temp, sport->port.membase + UCR2);
}
@@ -693,6 +864,226 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
return 0;
}
+#define RX_BUF_SIZE (PAGE_SIZE)
+static int start_rx_dma(struct imx_port *sport);
+static void dma_rx_work(struct work_struct *w)
+{
+ struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_rx);
+ struct tty_port *port = &sport->port.state->port;
+
+ if (sport->rx_bytes) {
+ tty_insert_flip_string(port, sport->rx_buf, sport->rx_bytes);
+ tty_flip_buffer_push(port);
+ sport->rx_bytes = 0;
+ }
+
+ if (sport->dma_is_rxing)
+ start_rx_dma(sport);
+}
+
+static void imx_rx_dma_done(struct imx_port *sport)
+{
+ unsigned long temp;
+
+ /* Enable this interrupt when the RXFIFO is empty. */
+ temp = readl(sport->port.membase + UCR1);
+ temp |= UCR1_RRDYEN;
+ writel(temp, sport->port.membase + UCR1);
+
+ sport->dma_is_rxing = 0;
+
+ /* Is the shutdown waiting for us? */
+ if (waitqueue_active(&sport->dma_wait))
+ wake_up(&sport->dma_wait);
+}
+
+/*
+ * There are three kinds of RX DMA interrupts(such as in the MX6Q):
+ * [1] the RX DMA buffer is full.
+ * [2] the Aging timer expires(wait for 8 bytes long)
+ * [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
+ *
+ * The [2] is trigger when a character was been sitting in the FIFO
+ * meanwhile [3] can wait for 32 bytes long when the RX line is
+ * on IDLE state and RxFIFO is empty.
+ */
+static void dma_rx_callback(void *data)
+{
+ struct imx_port *sport = data;
+ struct dma_chan *chan = sport->dma_chan_rx;
+ struct scatterlist *sgl = &sport->rx_sgl;
+ struct dma_tx_state state;
+ enum dma_status status;
+ unsigned int count;
+
+ /* unmap it first */
+ dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE);
+
+ status = chan->device->device_tx_status(chan, (dma_cookie_t)0, &state);
+ count = RX_BUF_SIZE - state.residue;
+ dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
+
+ if (count) {
+ sport->rx_bytes = count;
+ schedule_work(&sport->tsk_dma_rx);
+ } else
+ imx_rx_dma_done(sport);
+}
+
+static int start_rx_dma(struct imx_port *sport)
+{
+ struct scatterlist *sgl = &sport->rx_sgl;
+ struct dma_chan *chan = sport->dma_chan_rx;
+ struct device *dev = sport->port.dev;
+ struct dma_async_tx_descriptor *desc;
+ int ret;
+
+ sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
+ ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
+ if (ret == 0) {
+ dev_err(dev, "DMA mapping error for RX.\n");
+ return -EINVAL;
+ }
+ desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ if (!desc) {
+ dev_err(dev, "We cannot prepare for the RX slave dma!\n");
+ return -EINVAL;
+ }
+ desc->callback = dma_rx_callback;
+ desc->callback_param = sport;
+
+ dev_dbg(dev, "RX: prepare for the DMA.\n");
+ dmaengine_submit(desc);
+ dma_async_issue_pending(chan);
+ return 0;
+}
+
+static void imx_uart_dma_exit(struct imx_port *sport)
+{
+ if (sport->dma_chan_rx) {
+ dma_release_channel(sport->dma_chan_rx);
+ sport->dma_chan_rx = NULL;
+
+ kfree(sport->rx_buf);
+ sport->rx_buf = NULL;
+ }
+
+ if (sport->dma_chan_tx) {
+ dma_release_channel(sport->dma_chan_tx);
+ sport->dma_chan_tx = NULL;
+ }
+
+ sport->dma_is_inited = 0;
+}
+
+static int imx_uart_dma_init(struct imx_port *sport)
+{
+ struct dma_slave_config slave_config = {};
+ struct device *dev = sport->port.dev;
+ int ret;
+
+ /* Prepare for RX : */
+ sport->dma_chan_rx = dma_request_slave_channel(dev, "rx");
+ if (!sport->dma_chan_rx) {
+ dev_dbg(dev, "cannot get the DMA channel.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ slave_config.direction = DMA_DEV_TO_MEM;
+ slave_config.src_addr = sport->port.mapbase + URXD0;
+ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config.src_maxburst = RXTL;
+ ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config);
+ if (ret) {
+ dev_err(dev, "error in RX dma configuration.\n");
+ goto err;
+ }
+
+ sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!sport->rx_buf) {
+ dev_err(dev, "cannot alloc DMA buffer.\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ sport->rx_bytes = 0;
+
+ /* Prepare for TX : */
+ sport->dma_chan_tx = dma_request_slave_channel(dev, "tx");
+ if (!sport->dma_chan_tx) {
+ dev_err(dev, "cannot get the TX DMA channel!\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ slave_config.direction = DMA_MEM_TO_DEV;
+ slave_config.dst_addr = sport->port.mapbase + URTX0;
+ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config.dst_maxburst = TXTL;
+ ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config);
+ if (ret) {
+ dev_err(dev, "error in TX dma configuration.");
+ goto err;
+ }
+
+ sport->dma_is_inited = 1;
+
+ return 0;
+err:
+ imx_uart_dma_exit(sport);
+ return ret;
+}
+
+static void imx_enable_dma(struct imx_port *sport)
+{
+ unsigned long temp;
+ struct tty_port *port = &sport->port.state->port;
+
+ port->low_latency = 1;
+ INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
+ INIT_WORK(&sport->tsk_dma_rx, dma_rx_work);
+ init_waitqueue_head(&sport->dma_wait);
+
+ /* set UCR1 */
+ temp = readl(sport->port.membase + UCR1);
+ temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN |
+ /* wait for 32 idle frames for IDDMA interrupt */
+ UCR1_ICD_REG(3);
+ writel(temp, sport->port.membase + UCR1);
+
+ /* set UCR4 */
+ temp = readl(sport->port.membase + UCR4);
+ temp |= UCR4_IDDMAEN;
+ writel(temp, sport->port.membase + UCR4);
+
+ sport->dma_is_enabled = 1;
+}
+
+static void imx_disable_dma(struct imx_port *sport)
+{
+ unsigned long temp;
+ struct tty_port *port = &sport->port.state->port;
+
+ /* clear UCR1 */
+ temp = readl(sport->port.membase + UCR1);
+ temp &= ~(UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN);
+ writel(temp, sport->port.membase + UCR1);
+
+ /* clear UCR2 */
+ temp = readl(sport->port.membase + UCR2);
+ temp &= ~(UCR2_CTSC | UCR2_CTS);
+ writel(temp, sport->port.membase + UCR2);
+
+ /* clear UCR4 */
+ temp = readl(sport->port.membase + UCR4);
+ temp &= ~UCR4_IDDMAEN;
+ writel(temp, sport->port.membase + UCR4);
+
+ sport->dma_is_enabled = 0;
+ port->low_latency = 0;
+}
+
/* half the RX buffer size */
#define CTSTL 16
@@ -702,15 +1093,13 @@ static int imx_startup(struct uart_port *port)
int retval;
unsigned long flags, temp;
- if (!uart_console(port)) {
- retval = clk_prepare_enable(sport->clk_per);
- if (retval)
- goto error_out1;
- retval = clk_prepare_enable(sport->clk_ipg);
- if (retval) {
- clk_disable_unprepare(sport->clk_per);
- goto error_out1;
- }
+ retval = clk_prepare_enable(sport->clk_per);
+ if (retval)
+ goto error_out1;
+ retval = clk_prepare_enable(sport->clk_ipg);
+ if (retval) {
+ clk_disable_unprepare(sport->clk_per);
+ goto error_out1;
}
imx_setup_ufcr(sport, 0);
@@ -803,7 +1192,7 @@ static int imx_startup(struct uart_port *port)
}
}
- if (is_imx21_uart(sport)) {
+ if (!is_imx1_uart(sport)) {
temp = readl(sport->port.membase + UCR3);
temp |= IMX21_UCR3_RXDMUXSEL;
writel(temp, sport->port.membase + UCR3);
@@ -833,7 +1222,7 @@ static int imx_startup(struct uart_port *port)
if (USE_IRDA(sport)) {
struct imxuart_platform_data *pdata;
- pdata = sport->port.dev->platform_data;
+ pdata = dev_get_platdata(sport->port.dev);
sport->irda_inv_rx = pdata->irda_inv_rx;
sport->irda_inv_tx = pdata->irda_inv_tx;
sport->trcv_delay = pdata->transceiver_delay;
@@ -859,6 +1248,15 @@ static void imx_shutdown(struct uart_port *port)
unsigned long temp;
unsigned long flags;
+ if (sport->dma_is_enabled) {
+ /* We have to wait for the DMA to finish. */
+ wait_event(sport->dma_wait,
+ !sport->dma_is_rxing && !sport->dma_is_txing);
+ imx_stop_rx(port);
+ imx_disable_dma(sport);
+ imx_uart_dma_exit(sport);
+ }
+
spin_lock_irqsave(&sport->port.lock, flags);
temp = readl(sport->port.membase + UCR2);
temp &= ~(UCR2_TXEN);
@@ -867,7 +1265,7 @@ static void imx_shutdown(struct uart_port *port)
if (USE_IRDA(sport)) {
struct imxuart_platform_data *pdata;
- pdata = sport->port.dev->platform_data;
+ pdata = dev_get_platdata(sport->port.dev);
if (pdata->irda_enable)
pdata->irda_enable(0);
}
@@ -901,10 +1299,8 @@ static void imx_shutdown(struct uart_port *port)
writel(temp, sport->port.membase + UCR1);
spin_unlock_irqrestore(&sport->port.lock, flags);
- if (!uart_console(&sport->port)) {
- clk_disable_unprepare(sport->clk_per);
- clk_disable_unprepare(sport->clk_ipg);
- }
+ clk_disable_unprepare(sport->clk_per);
+ clk_disable_unprepare(sport->clk_ipg);
}
static void
@@ -947,6 +1343,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
if (sport->have_rtscts) {
ucr2 &= ~UCR2_IRTS;
ucr2 |= UCR2_CTSC;
+
+ /* Can we enable the DMA support? */
+ if (is_imx6q_uart(sport) && !uart_console(port)
+ && !sport->dma_is_inited)
+ imx_uart_dma_init(sport);
} else {
termios->c_cflag &= ~CRTSCTS;
}
@@ -1020,6 +1421,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
*/
div = 1;
} else {
+ /* custom-baudrate handling */
+ div = sport->port.uartclk / (baud * 16);
+ if (baud == 38400 && quot != div)
+ baud = sport->port.uartclk / (quot * 16);
+
div = sport->port.uartclk / (baud * 16);
if (div > 7)
div = 7;
@@ -1048,7 +1454,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
writel(num, sport->port.membase + UBIR);
writel(denom, sport->port.membase + UBMR);
- if (is_imx21_uart(sport))
+ if (!is_imx1_uart(sport))
writel(sport->port.uartclk / div / 1000,
sport->port.membase + IMX21_ONEMS);
@@ -1060,6 +1466,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
imx_enable_ms(&sport->port);
+ if (sport->dma_is_inited && !sport->dma_is_enabled)
+ imx_enable_dma(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
@@ -1251,6 +1659,16 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
unsigned int ucr1;
unsigned long flags = 0;
int locked = 1;
+ int retval;
+
+ retval = clk_enable(sport->clk_per);
+ if (retval)
+ return;
+ retval = clk_enable(sport->clk_ipg);
+ if (retval) {
+ clk_disable(sport->clk_per);
+ return;
+ }
if (sport->port.sysrq)
locked = 0;
@@ -1286,6 +1704,9 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
if (locked)
spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ clk_disable(sport->clk_ipg);
+ clk_disable(sport->clk_per);
}
/*
@@ -1359,6 +1780,7 @@ imx_console_setup(struct console *co, char *options)
int bits = 8;
int parity = 'n';
int flow = 'n';
+ int retval;
/*
* Check whether an invalid uart number has been specified, and
@@ -1371,6 +1793,11 @@ imx_console_setup(struct console *co, char *options)
if (sport == NULL)
return -ENODEV;
+ /* For setting the registers, we only need to enable the ipg clock. */
+ retval = clk_prepare_enable(sport->clk_ipg);
+ if (retval)
+ goto error_console;
+
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
@@ -1378,7 +1805,20 @@ imx_console_setup(struct console *co, char *options)
imx_setup_ufcr(sport, 0);
- return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+ retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
+
+ clk_disable(sport->clk_ipg);
+ if (retval) {
+ clk_unprepare(sport->clk_ipg);
+ goto error_console;
+ }
+
+ retval = clk_prepare(sport->clk_per);
+ if (retval)
+ clk_disable_unprepare(sport->clk_ipg);
+
+error_console:
+ return retval;
}
static struct uart_driver imx_reg;
@@ -1472,6 +1912,9 @@ static int serial_imx_probe_dt(struct imx_port *sport,
sport->devdata = of_id->data;
+ if (of_device_is_stdout_path(np))
+ add_preferred_console(imx_reg.cons->name, sport->port.line, 0);
+
return 0;
}
#else
@@ -1485,7 +1928,7 @@ static inline int serial_imx_probe_dt(struct imx_port *sport,
static void serial_imx_probe_pdata(struct imx_port *sport,
struct platform_device *pdev)
{
- struct imxuart_platform_data *pdata = pdev->dev.platform_data;
+ struct imxuart_platform_data *pdata = dev_get_platdata(&pdev->dev);
sport->port.line = pdev->id;
sport->devdata = (struct imx_uart_data *) pdev->id_entry->driver_data;
@@ -1507,7 +1950,6 @@ static int serial_imx_probe(struct platform_device *pdev)
void __iomem *base;
int ret = 0;
struct resource *res;
- struct pinctrl *pinctrl;
sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
if (!sport)
@@ -1543,13 +1985,6 @@ static int serial_imx_probe(struct platform_device *pdev)
sport->timer.function = imx_timeout;
sport->timer.data = (unsigned long)sport;
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- ret = PTR_ERR(pinctrl);
- dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret);
- return ret;
- }
-
sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->clk_ipg)) {
ret = PTR_ERR(sport->clk_ipg);
@@ -1564,18 +1999,15 @@ static int serial_imx_probe(struct platform_device *pdev)
return ret;
}
- clk_prepare_enable(sport->clk_per);
- clk_prepare_enable(sport->clk_ipg);
-
sport->port.uartclk = clk_get_rate(sport->clk_per);
imx_ports[sport->port.line] = sport;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (pdata && pdata->init) {
ret = pdata->init(pdev);
if (ret)
- goto clkput;
+ return ret;
}
ret = uart_add_one_port(&imx_reg, &sport->port);
@@ -1583,18 +2015,10 @@ static int serial_imx_probe(struct platform_device *pdev)
goto deinit;
platform_set_drvdata(pdev, sport);
- if (!uart_console(&sport->port)) {
- clk_disable_unprepare(sport->clk_per);
- clk_disable_unprepare(sport->clk_ipg);
- }
-
return 0;
deinit:
if (pdata && pdata->exit)
pdata->exit(pdev);
-clkput:
- clk_disable_unprepare(sport->clk_per);
- clk_disable_unprepare(sport->clk_ipg);
return ret;
}
@@ -1603,9 +2027,7 @@ static int serial_imx_remove(struct platform_device *pdev)
struct imxuart_platform_data *pdata;
struct imx_port *sport = platform_get_drvdata(pdev);
- pdata = pdev->dev.platform_data;
-
- platform_set_drvdata(pdev, NULL);
+ pdata = dev_get_platdata(&pdev->dev);
uart_remove_one_port(&imx_reg, &sport->port);
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
index e2520abcb1c..1274499850f 100644
--- a/drivers/tty/serial/ioc4_serial.c
+++ b/drivers/tty/serial/ioc4_serial.c
@@ -297,7 +297,7 @@ struct ioc4_serial {
struct ioc4_uartregs uart_1;
struct ioc4_uartregs uart_2;
struct ioc4_uartregs uart_3;
-} ioc4_serial;
+};
/* UART clock speed */
#define IOC4_SER_XIN_CLK_66 66666667
@@ -2767,7 +2767,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
* called per card found from IOC4 master module.
* @idd: Master module data for this IOC4
*/
-int
+static int
ioc4_serial_attach_one(struct ioc4_driver_data *idd)
{
unsigned long tmp_addr1;
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 15733da757c..88d01e0bb0c 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -318,7 +318,7 @@ lqasc_startup(struct uart_port *port)
struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
int retval;
- if (ltq_port->clk)
+ if (!IS_ERR(ltq_port->clk))
clk_enable(ltq_port->clk);
port->uartclk = clk_get_rate(ltq_port->fpiclk);
@@ -386,7 +386,7 @@ lqasc_shutdown(struct uart_port *port)
port->membase + LTQ_ASC_RXFCON);
ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
port->membase + LTQ_ASC_TXFCON);
- if (ltq_port->clk)
+ if (!IS_ERR(ltq_port->clk))
clk_disable(ltq_port->clk);
}
@@ -636,6 +636,9 @@ lqasc_console_setup(struct console *co, char *options)
port = &ltq_port->port;
+ if (!IS_ERR(ltq_port->clk))
+ clk_enable(ltq_port->clk);
+
port->uartclk = clk_get_rate(ltq_port->fpiclk);
if (options)
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
index dffea6b2cd7..701644f0682 100644
--- a/drivers/tty/serial/lpc32xx_hs.c
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -279,7 +279,10 @@ static void __serial_lpc32xx_rx(struct uart_port *port)
tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
}
+
+ spin_unlock(&port->lock);
tty_flip_buffer_push(tport);
+ spin_lock(&port->lock);
}
static void __serial_lpc32xx_tx(struct uart_port *port)
@@ -351,10 +354,8 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
}
/* Data received? */
- if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) {
+ if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT))
__serial_lpc32xx_rx(port);
- tty_flip_buffer_push(tport);
- }
/* Transmit data request? */
if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) {
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index bb1afa0922e..9cd9b4eba9f 100644
--- a/drivers/tty/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
@@ -368,7 +368,10 @@ static void receive_chars(struct uart_sio_port *up, int *status)
ignore_char:
*status = serial_in(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
+
+ spin_unlock(&up->port.lock);
tty_flip_buffer_push(port);
+ spin_lock(&up->port.lock);
}
static void transmit_chars(struct uart_sio_port *up)
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index 35866d5872a..79f9a9eff54 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -779,7 +779,7 @@ static int max3100_probe(struct spi_device *spi)
max3100s[i]->irq = spi->irq;
spin_lock_init(&max3100s[i]->conf_lock);
spi_set_drvdata(spi, max3100s[i]);
- pdata = spi->dev.platform_data;
+ pdata = dev_get_platdata(&spi->dev);
max3100s[i]->crystal = pdata->crystal;
max3100s[i]->loopback = pdata->loopback;
max3100s[i]->poll_time = pdata->poll_time * HZ / 1000;
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 8941e641894..b2e707aa603 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1,7 +1,7 @@
/*
- * Maxim (Dallas) MAX3107/8 serial driver
+ * Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver
*
- * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ * Copyright (C) 2012-2013 Alexander Shiyan <shc_work@mail.ru>
*
* Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
* Based on max3110.c, by Feng Tang <feng.tang@intel.com>
@@ -13,11 +13,10 @@
* (at your option) any later version.
*/
-/* TODO: MAX3109 support (Dual) */
-/* TODO: MAX14830 support (Quad) */
-
#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/bitops.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/tty.h>
@@ -25,8 +24,10 @@
#include <linux/regmap.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
+
#include <linux/platform_data/max310x.h>
+#define MAX310X_NAME "max310x"
#define MAX310X_MAJOR 204
#define MAX310X_MINOR 209
@@ -37,7 +38,8 @@
#define MAX310X_IRQSTS_REG (0x02) /* IRQ status */
#define MAX310X_LSR_IRQEN_REG (0x03) /* LSR IRQ enable */
#define MAX310X_LSR_IRQSTS_REG (0x04) /* LSR IRQ status */
-#define MAX310X_SPCHR_IRQEN_REG (0x05) /* Special char IRQ enable */
+#define MAX310X_REG_05 (0x05)
+#define MAX310X_SPCHR_IRQEN_REG MAX310X_REG_05 /* Special char IRQ en */
#define MAX310X_SPCHR_IRQSTS_REG (0x06) /* Special char IRQ status */
#define MAX310X_STS_IRQEN_REG (0x07) /* Status IRQ enable */
#define MAX310X_STS_IRQSTS_REG (0x08) /* Status IRQ status */
@@ -63,8 +65,15 @@
#define MAX310X_BRGDIVLSB_REG (0x1c) /* Baud rate divisor LSB */
#define MAX310X_BRGDIVMSB_REG (0x1d) /* Baud rate divisor MSB */
#define MAX310X_CLKSRC_REG (0x1e) /* Clock source */
-/* Only present in MAX3107 */
-#define MAX3107_REVID_REG (0x1f) /* Revision identification */
+#define MAX310X_REG_1F (0x1f)
+
+#define MAX310X_REVID_REG MAX310X_REG_1F /* Revision ID */
+
+#define MAX310X_GLOBALIRQ_REG MAX310X_REG_1F /* Global IRQ (RO) */
+#define MAX310X_GLOBALCMD_REG MAX310X_REG_1F /* Global Command (WO) */
+
+/* Extended registers */
+#define MAX310X_REVID_EXTREG MAX310X_REG_05 /* Revision ID */
/* IRQ register bits */
#define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */
@@ -246,58 +255,210 @@
#define MAX310X_CLKSRC_EXTCLK_BIT (1 << 4) /* External clock enable */
#define MAX310X_CLKSRC_CLK2RTS_BIT (1 << 7) /* Baud clk to RTS pin */
+/* Global commands */
+#define MAX310X_EXTREG_ENBL (0xce)
+#define MAX310X_EXTREG_DSBL (0xcd)
+
/* Misc definitions */
#define MAX310X_FIFO_SIZE (128)
+#define MAX310x_REV_MASK (0xfc)
/* MAX3107 specific */
#define MAX3107_REV_ID (0xa0)
-#define MAX3107_REV_MASK (0xfe)
-
-/* IRQ status bits definitions */
-#define MAX310X_IRQ_TX (MAX310X_IRQ_TXFIFO_BIT | \
- MAX310X_IRQ_TXEMPTY_BIT)
-#define MAX310X_IRQ_RX (MAX310X_IRQ_RXFIFO_BIT | \
- MAX310X_IRQ_RXEMPTY_BIT)
-
-/* Supported chip types */
-enum {
- MAX310X_TYPE_MAX3107 = 3107,
- MAX310X_TYPE_MAX3108 = 3108,
+
+/* MAX3109 specific */
+#define MAX3109_REV_ID (0xc0)
+
+/* MAX14830 specific */
+#define MAX14830_BRGCFG_CLKDIS_BIT (1 << 6) /* Clock Disable */
+#define MAX14830_REV_ID (0xb0)
+
+struct max310x_devtype {
+ char name[9];
+ int nr;
+ int (*detect)(struct device *);
+ void (*power)(struct uart_port *, int);
};
-struct max310x_port {
- struct uart_driver uart;
+struct max310x_one {
struct uart_port port;
+ struct work_struct tx_work;
+};
- const char *name;
- int uartclk;
-
- unsigned int nr_gpio;
+struct max310x_port {
+ struct uart_driver uart;
+ struct max310x_devtype *devtype;
+ struct regmap *regmap;
+ struct regmap_config regcfg;
+ struct mutex mutex;
+ struct max310x_pdata *pdata;
+ int gpio_used;
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio;
#endif
+ struct max310x_one p[0];
+};
- struct regmap *regmap;
- struct regmap_config regcfg;
+static u8 max310x_port_read(struct uart_port *port, u8 reg)
+{
+ struct max310x_port *s = dev_get_drvdata(port->dev);
+ unsigned int val = 0;
- struct workqueue_struct *wq;
- struct work_struct tx_work;
+ regmap_read(s->regmap, port->iobase + reg, &val);
- struct mutex max310x_mutex;
+ return val;
+}
- struct max310x_pdata *pdata;
+static void max310x_port_write(struct uart_port *port, u8 reg, u8 val)
+{
+ struct max310x_port *s = dev_get_drvdata(port->dev);
+
+ regmap_write(s->regmap, port->iobase + reg, val);
+}
+
+static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val)
+{
+ struct max310x_port *s = dev_get_drvdata(port->dev);
+
+ regmap_update_bits(s->regmap, port->iobase + reg, mask, val);
+}
+
+static int max3107_detect(struct device *dev)
+{
+ struct max310x_port *s = dev_get_drvdata(dev);
+ unsigned int val = 0;
+ int ret;
+
+ ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val);
+ if (ret)
+ return ret;
+
+ if (((val & MAX310x_REV_MASK) != MAX3107_REV_ID)) {
+ dev_err(dev,
+ "%s ID 0x%02x does not match\n", s->devtype->name, val);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int max3108_detect(struct device *dev)
+{
+ struct max310x_port *s = dev_get_drvdata(dev);
+ unsigned int val = 0;
+ int ret;
+
+ /* MAX3108 have not REV ID register, we just check default value
+ * from clocksource register to make sure everything works.
+ */
+ ret = regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val);
+ if (ret)
+ return ret;
+
+ if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT)) {
+ dev_err(dev, "%s not present\n", s->devtype->name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int max3109_detect(struct device *dev)
+{
+ struct max310x_port *s = dev_get_drvdata(dev);
+ unsigned int val = 0;
+ int ret;
+
+ ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val);
+ if (ret)
+ return ret;
+
+ if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) {
+ dev_err(dev,
+ "%s ID 0x%02x does not match\n", s->devtype->name, val);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void max310x_power(struct uart_port *port, int on)
+{
+ max310x_port_update(port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_FORCESLEEP_BIT,
+ on ? 0 : MAX310X_MODE1_FORCESLEEP_BIT);
+ if (on)
+ msleep(50);
+}
+
+static int max14830_detect(struct device *dev)
+{
+ struct max310x_port *s = dev_get_drvdata(dev);
+ unsigned int val = 0;
+ int ret;
+
+ ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG,
+ MAX310X_EXTREG_ENBL);
+ if (ret)
+ return ret;
+
+ regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val);
+ regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL);
+ if (((val & MAX310x_REV_MASK) != MAX14830_REV_ID)) {
+ dev_err(dev,
+ "%s ID 0x%02x does not match\n", s->devtype->name, val);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void max14830_power(struct uart_port *port, int on)
+{
+ max310x_port_update(port, MAX310X_BRGCFG_REG,
+ MAX14830_BRGCFG_CLKDIS_BIT,
+ on ? 0 : MAX14830_BRGCFG_CLKDIS_BIT);
+ if (on)
+ msleep(50);
+}
+
+static const struct max310x_devtype max3107_devtype = {
+ .name = "MAX3107",
+ .nr = 1,
+ .detect = max3107_detect,
+ .power = max310x_power,
+};
+
+static const struct max310x_devtype max3108_devtype = {
+ .name = "MAX3108",
+ .nr = 1,
+ .detect = max3108_detect,
+ .power = max310x_power,
+};
+
+static const struct max310x_devtype max3109_devtype = {
+ .name = "MAX3109",
+ .nr = 2,
+ .detect = max3109_detect,
+ .power = max310x_power,
+};
+
+static const struct max310x_devtype max14830_devtype = {
+ .name = "MAX14830",
+ .nr = 4,
+ .detect = max14830_detect,
+ .power = max14830_power,
};
-static bool max3107_8_reg_writeable(struct device *dev, unsigned int reg)
+static bool max310x_reg_writeable(struct device *dev, unsigned int reg)
{
- switch (reg) {
+ switch (reg & 0x1f) {
case MAX310X_IRQSTS_REG:
case MAX310X_LSR_IRQSTS_REG:
case MAX310X_SPCHR_IRQSTS_REG:
case MAX310X_STS_IRQSTS_REG:
case MAX310X_TXFIFOLVL_REG:
case MAX310X_RXFIFOLVL_REG:
- case MAX3107_REVID_REG: /* Only available on MAX3107 */
return false;
default:
break;
@@ -308,7 +469,7 @@ static bool max3107_8_reg_writeable(struct device *dev, unsigned int reg)
static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
{
- switch (reg) {
+ switch (reg & 0x1f) {
case MAX310X_RHR_REG:
case MAX310X_IRQSTS_REG:
case MAX310X_LSR_IRQSTS_REG:
@@ -317,6 +478,9 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
case MAX310X_TXFIFOLVL_REG:
case MAX310X_RXFIFOLVL_REG:
case MAX310X_GPIODATA_REG:
+ case MAX310X_BRGDIVLSB_REG:
+ case MAX310X_REG_05:
+ case MAX310X_REG_1F:
return true;
default:
break;
@@ -327,7 +491,7 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
static bool max310x_reg_precious(struct device *dev, unsigned int reg)
{
- switch (reg) {
+ switch (reg & 0x1f) {
case MAX310X_RHR_REG:
case MAX310X_IRQSTS_REG:
case MAX310X_SPCHR_IRQSTS_REG:
@@ -340,42 +504,25 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
return false;
}
-static void max310x_set_baud(struct max310x_port *s, int baud)
+static void max310x_set_baud(struct uart_port *port, int baud)
{
- unsigned int mode = 0, div = s->uartclk / baud;
+ unsigned int mode = 0, div = port->uartclk / baud;
if (!(div / 16)) {
/* Mode x2 */
mode = MAX310X_BRGCFG_2XMODE_BIT;
- div = (s->uartclk * 2) / baud;
+ div = (port->uartclk * 2) / baud;
}
if (!(div / 16)) {
/* Mode x4 */
mode = MAX310X_BRGCFG_4XMODE_BIT;
- div = (s->uartclk * 4) / baud;
+ div = (port->uartclk * 4) / baud;
}
- regmap_write(s->regmap, MAX310X_BRGDIVMSB_REG,
- ((div / 16) >> 8) & 0xff);
- regmap_write(s->regmap, MAX310X_BRGDIVLSB_REG, (div / 16) & 0xff);
- regmap_write(s->regmap, MAX310X_BRGCFG_REG, (div % 16) | mode);
-}
-
-static void max310x_wait_pll(struct max310x_port *s)
-{
- int tryes = 1000;
-
- /* Wait for PLL only if crystal is used */
- if (!(s->pdata->driver_flags & MAX310X_EXT_CLK)) {
- unsigned int sts = 0;
-
- while (tryes--) {
- regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &sts);
- if (sts & MAX310X_STS_CLKREADY_BIT)
- break;
- }
- }
+ max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);
+ max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);
+ max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode);
}
static int max310x_update_best_err(unsigned long f, long *besterr)
@@ -449,49 +596,49 @@ static int max310x_set_ref_clk(struct max310x_port *s)
regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc);
- if (pllcfg)
- max310x_wait_pll(s);
-
- dev_dbg(s->port.dev, "Reference clock set to %lu Hz\n", bestfreq);
+ /* Wait for crystal */
+ if (pllcfg && !(s->pdata->driver_flags & MAX310X_EXT_CLK))
+ msleep(10);
return (int)bestfreq;
}
-static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen)
+static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
{
- unsigned int sts = 0, ch = 0, flag;
+ unsigned int sts, ch, flag;
- if (unlikely(rxlen >= MAX310X_FIFO_SIZE)) {
- dev_warn(s->port.dev, "Possible RX FIFO overrun %d\n", rxlen);
+ if (unlikely(rxlen >= port->fifosize)) {
+ dev_warn_ratelimited(port->dev,
+ "Port %i: Possible RX FIFO overrun\n",
+ port->line);
+ port->icount.buf_overrun++;
/* Ensure sanity of RX level */
- rxlen = MAX310X_FIFO_SIZE;
+ rxlen = port->fifosize;
}
- dev_dbg(s->port.dev, "RX Len = %u\n", rxlen);
-
while (rxlen--) {
- regmap_read(s->regmap, MAX310X_RHR_REG, &ch);
- regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &sts);
+ ch = max310x_port_read(port, MAX310X_RHR_REG);
+ sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT |
MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT;
- s->port.icount.rx++;
+ port->icount.rx++;
flag = TTY_NORMAL;
if (unlikely(sts)) {
if (sts & MAX310X_LSR_RXBRK_BIT) {
- s->port.icount.brk++;
- if (uart_handle_break(&s->port))
+ port->icount.brk++;
+ if (uart_handle_break(port))
continue;
} else if (sts & MAX310X_LSR_RXPAR_BIT)
- s->port.icount.parity++;
+ port->icount.parity++;
else if (sts & MAX310X_LSR_FRERR_BIT)
- s->port.icount.frame++;
+ port->icount.frame++;
else if (sts & MAX310X_LSR_RXOVR_BIT)
- s->port.icount.overrun++;
+ port->icount.overrun++;
- sts &= s->port.read_status_mask;
+ sts &= port->read_status_mask;
if (sts & MAX310X_LSR_RXBRK_BIT)
flag = TTY_BREAK;
else if (sts & MAX310X_LSR_RXPAR_BIT)
@@ -502,129 +649,129 @@ static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen)
flag = TTY_OVERRUN;
}
- if (uart_handle_sysrq_char(s->port, ch))
+ if (uart_handle_sysrq_char(port, ch))
continue;
- if (sts & s->port.ignore_status_mask)
+ if (sts & port->ignore_status_mask)
continue;
- uart_insert_char(&s->port, sts, MAX310X_LSR_RXOVR_BIT,
- ch, flag);
+ uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, ch, flag);
}
- tty_flip_buffer_push(&s->port.state->port);
+ tty_flip_buffer_push(&port->state->port);
}
-static void max310x_handle_tx(struct max310x_port *s)
+static void max310x_handle_tx(struct uart_port *port)
{
- struct circ_buf *xmit = &s->port.state->xmit;
- unsigned int txlen = 0, to_send;
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned int txlen, to_send;
- if (unlikely(s->port.x_char)) {
- regmap_write(s->regmap, MAX310X_THR_REG, s->port.x_char);
- s->port.icount.tx++;
- s->port.x_char = 0;
+ if (unlikely(port->x_char)) {
+ max310x_port_write(port, MAX310X_THR_REG, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return;
/* Get length of data pending in circular buffer */
to_send = uart_circ_chars_pending(xmit);
if (likely(to_send)) {
/* Limit to size of TX FIFO */
- regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &txlen);
- txlen = MAX310X_FIFO_SIZE - txlen;
+ txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
+ txlen = port->fifosize - txlen;
to_send = (to_send > txlen) ? txlen : to_send;
- dev_dbg(s->port.dev, "TX Len = %u\n", to_send);
-
/* Add data to send */
- s->port.icount.tx += to_send;
+ port->icount.tx += to_send;
while (to_send--) {
- regmap_write(s->regmap, MAX310X_THR_REG,
- xmit->buf[xmit->tail]);
+ max310x_port_write(port, MAX310X_THR_REG,
+ xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
};
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&s->port);
+ uart_write_wakeup(port);
}
-static irqreturn_t max310x_ist(int irq, void *dev_id)
+static void max310x_port_irq(struct max310x_port *s, int portno)
{
- struct max310x_port *s = (struct max310x_port *)dev_id;
- unsigned int ists = 0, lsr = 0, rxlen = 0;
+ struct uart_port *port = &s->p[portno].port;
- mutex_lock(&s->max310x_mutex);
+ do {
+ unsigned int ists, lsr, rxlen;
- for (;;) {
/* Read IRQ status & RX FIFO level */
- regmap_read(s->regmap, MAX310X_IRQSTS_REG, &ists);
- regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &lsr);
- regmap_read(s->regmap, MAX310X_RXFIFOLVL_REG, &rxlen);
- if (!ists && !(lsr & MAX310X_LSR_RXTO_BIT) && !rxlen)
+ ists = max310x_port_read(port, MAX310X_IRQSTS_REG);
+ rxlen = max310x_port_read(port, MAX310X_RXFIFOLVL_REG);
+ if (!ists && !rxlen)
break;
- dev_dbg(s->port.dev, "IRQ status: 0x%02x\n", ists);
-
- if (rxlen)
- max310x_handle_rx(s, rxlen);
- if (ists & MAX310X_IRQ_TX)
- max310x_handle_tx(s);
- if (ists & MAX310X_IRQ_CTS_BIT)
- uart_handle_cts_change(&s->port,
+ if (ists & MAX310X_IRQ_CTS_BIT) {
+ lsr = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
+ uart_handle_cts_change(port,
!!(lsr & MAX310X_LSR_CTS_BIT));
- }
+ }
+ if (rxlen)
+ max310x_handle_rx(port, rxlen);
+ if (ists & MAX310X_IRQ_TXEMPTY_BIT) {
+ mutex_lock(&s->mutex);
+ max310x_handle_tx(port);
+ mutex_unlock(&s->mutex);
+ }
+ } while (1);
+}
+
+static irqreturn_t max310x_ist(int irq, void *dev_id)
+{
+ struct max310x_port *s = (struct max310x_port *)dev_id;
- mutex_unlock(&s->max310x_mutex);
+ if (s->uart.nr > 1) {
+ do {
+ unsigned int val = ~0;
+
+ WARN_ON_ONCE(regmap_read(s->regmap,
+ MAX310X_GLOBALIRQ_REG, &val));
+ val = ((1 << s->uart.nr) - 1) & ~val;
+ if (!val)
+ break;
+ max310x_port_irq(s, fls(val) - 1);
+ } while (1);
+ } else
+ max310x_port_irq(s, 0);
return IRQ_HANDLED;
}
static void max310x_wq_proc(struct work_struct *ws)
{
- struct max310x_port *s = container_of(ws, struct max310x_port, tx_work);
+ struct max310x_one *one = container_of(ws, struct max310x_one, tx_work);
+ struct max310x_port *s = dev_get_drvdata(one->port.dev);
- mutex_lock(&s->max310x_mutex);
- max310x_handle_tx(s);
- mutex_unlock(&s->max310x_mutex);
+ mutex_lock(&s->mutex);
+ max310x_handle_tx(&one->port);
+ mutex_unlock(&s->mutex);
}
static void max310x_start_tx(struct uart_port *port)
{
- struct max310x_port *s = container_of(port, struct max310x_port, port);
-
- queue_work(s->wq, &s->tx_work);
-}
-
-static void max310x_stop_tx(struct uart_port *port)
-{
- /* Do nothing */
-}
+ struct max310x_one *one = container_of(port, struct max310x_one, port);
-static void max310x_stop_rx(struct uart_port *port)
-{
- /* Do nothing */
+ if (!work_pending(&one->tx_work))
+ schedule_work(&one->tx_work);
}
static unsigned int max310x_tx_empty(struct uart_port *port)
{
- unsigned int val = 0;
- struct max310x_port *s = container_of(port, struct max310x_port, port);
+ unsigned int lvl, sts;
- mutex_lock(&s->max310x_mutex);
- regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &val);
- mutex_unlock(&s->max310x_mutex);
+ lvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
+ sts = max310x_port_read(port, MAX310X_IRQSTS_REG);
- return val ? 0 : TIOCSER_TEMT;
-}
-
-static void max310x_enable_ms(struct uart_port *port)
-{
- /* Modem status not supported */
+ return ((sts & MAX310X_IRQ_TXEMPTY_BIT) && !lvl) ? TIOCSER_TEMT : 0;
}
static unsigned int max310x_get_mctrl(struct uart_port *port)
@@ -644,28 +791,20 @@ static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void max310x_break_ctl(struct uart_port *port, int break_state)
{
- struct max310x_port *s = container_of(port, struct max310x_port, port);
-
- mutex_lock(&s->max310x_mutex);
- regmap_update_bits(s->regmap, MAX310X_LCR_REG,
- MAX310X_LCR_TXBREAK_BIT,
- break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
- mutex_unlock(&s->max310x_mutex);
+ max310x_port_update(port, MAX310X_LCR_REG,
+ MAX310X_LCR_TXBREAK_BIT,
+ break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
}
static void max310x_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
- struct max310x_port *s = container_of(port, struct max310x_port, port);
unsigned int lcr, flow = 0;
int baud;
- mutex_lock(&s->max310x_mutex);
-
/* Mask termios capabilities we don't support */
termios->c_cflag &= ~CMSPAR;
- termios->c_iflag &= ~IXANY;
/* Word size */
switch (termios->c_cflag & CSIZE) {
@@ -696,7 +835,7 @@ static void max310x_set_termios(struct uart_port *port,
lcr |= MAX310X_LCR_STOPLEN_BIT; /* 2 stops */
/* Update LCR register */
- regmap_write(s->regmap, MAX310X_LCR_REG, lcr);
+ max310x_port_write(port, MAX310X_LCR_REG, lcr);
/* Set read status mask */
port->read_status_mask = MAX310X_LSR_RXOVR_BIT;
@@ -717,8 +856,8 @@ static void max310x_set_termios(struct uart_port *port,
MAX310X_LSR_RXBRK_BIT;
/* Configure flow control */
- regmap_write(s->regmap, MAX310X_XON1_REG, termios->c_cc[VSTART]);
- regmap_write(s->regmap, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]);
+ max310x_port_write(port, MAX310X_XON1_REG, termios->c_cc[VSTART]);
+ max310x_port_write(port, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]);
if (termios->c_cflag & CRTSCTS)
flow |= MAX310X_FLOWCTRL_AUTOCTS_BIT |
MAX310X_FLOWCTRL_AUTORTS_BIT;
@@ -728,7 +867,7 @@ static void max310x_set_termios(struct uart_port *port,
if (termios->c_iflag & IXOFF)
flow |= MAX310X_FLOWCTRL_SWFLOW1_BIT |
MAX310X_FLOWCTRL_SWFLOWEN_BIT;
- regmap_write(s->regmap, MAX310X_FLOWCTRL_REG, flow);
+ max310x_port_write(port, MAX310X_FLOWCTRL_REG, flow);
/* Get baud rate generator configuration */
baud = uart_get_baud_rate(port, termios, old,
@@ -736,36 +875,30 @@ static void max310x_set_termios(struct uart_port *port,
port->uartclk / 4);
/* Setup baudrate generator */
- max310x_set_baud(s, baud);
+ max310x_set_baud(port, baud);
/* Update timeout according to new baud rate */
uart_update_timeout(port, termios->c_cflag, baud);
-
- mutex_unlock(&s->max310x_mutex);
}
static int max310x_startup(struct uart_port *port)
{
unsigned int val, line = port->line;
- struct max310x_port *s = container_of(port, struct max310x_port, port);
-
- if (s->pdata->suspend)
- s->pdata->suspend(0);
+ struct max310x_port *s = dev_get_drvdata(port->dev);
- mutex_lock(&s->max310x_mutex);
+ s->devtype->power(port, 1);
/* Configure baud rate, 9600 as default */
- max310x_set_baud(s, 9600);
+ max310x_set_baud(port, 9600);
/* Configure LCR register, 8N1 mode by default */
- val = MAX310X_LCR_WORD_LEN_8;
- regmap_write(s->regmap, MAX310X_LCR_REG, val);
+ max310x_port_write(port, MAX310X_LCR_REG, MAX310X_LCR_WORD_LEN_8);
/* Configure MODE1 register */
- regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
- MAX310X_MODE1_TRNSCVCTRL_BIT,
- (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL)
- ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0);
+ max310x_port_update(port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT,
+ (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL)
+ ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0);
/* Configure MODE2 register */
val = MAX310X_MODE2_RXEMPTINV_BIT;
@@ -776,63 +909,40 @@ static int max310x_startup(struct uart_port *port)
/* Reset FIFOs */
val |= MAX310X_MODE2_FIFORST_BIT;
- regmap_write(s->regmap, MAX310X_MODE2_REG, val);
-
- /* Configure FIFO trigger level register */
- /* RX FIFO trigger for 16 words, TX FIFO trigger for 64 words */
- val = MAX310X_FIFOTRIGLVL_RX(16) | MAX310X_FIFOTRIGLVL_TX(64);
- regmap_write(s->regmap, MAX310X_FIFOTRIGLVL_REG, val);
+ max310x_port_write(port, MAX310X_MODE2_REG, val);
+ max310x_port_update(port, MAX310X_MODE2_REG,
+ MAX310X_MODE2_FIFORST_BIT, 0);
/* Configure flow control levels */
/* Flow control halt level 96, resume level 48 */
- val = MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96);
- regmap_write(s->regmap, MAX310X_FLOWLVL_REG, val);
-
- /* Clear timeout register */
- regmap_write(s->regmap, MAX310X_RXTO_REG, 0);
+ max310x_port_write(port, MAX310X_FLOWLVL_REG,
+ MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96));
- /* Configure LSR interrupt enable register */
- /* Enable RX timeout interrupt */
- val = MAX310X_LSR_RXTO_BIT;
- regmap_write(s->regmap, MAX310X_LSR_IRQEN_REG, val);
+ /* Clear IRQ status register */
+ max310x_port_read(port, MAX310X_IRQSTS_REG);
- /* Clear FIFO reset */
- regmap_update_bits(s->regmap, MAX310X_MODE2_REG,
- MAX310X_MODE2_FIFORST_BIT, 0);
-
- /* Clear IRQ status register by reading it */
- regmap_read(s->regmap, MAX310X_IRQSTS_REG, &val);
-
- /* Configure interrupt enable register */
- /* Enable CTS change interrupt */
- val = MAX310X_IRQ_CTS_BIT;
- /* Enable RX, TX interrupts */
- val |= MAX310X_IRQ_RX | MAX310X_IRQ_TX;
- regmap_write(s->regmap, MAX310X_IRQEN_REG, val);
-
- mutex_unlock(&s->max310x_mutex);
+ /* Enable RX, TX, CTS change interrupts */
+ val = MAX310X_IRQ_RXEMPTY_BIT | MAX310X_IRQ_TXEMPTY_BIT;
+ max310x_port_write(port, MAX310X_IRQEN_REG, val | MAX310X_IRQ_CTS_BIT);
return 0;
}
static void max310x_shutdown(struct uart_port *port)
{
- struct max310x_port *s = container_of(port, struct max310x_port, port);
+ struct max310x_port *s = dev_get_drvdata(port->dev);
/* Disable all interrupts */
- mutex_lock(&s->max310x_mutex);
- regmap_write(s->regmap, MAX310X_IRQEN_REG, 0);
- mutex_unlock(&s->max310x_mutex);
+ max310x_port_write(port, MAX310X_IRQEN_REG, 0);
- if (s->pdata->suspend)
- s->pdata->suspend(1);
+ s->devtype->power(port, 0);
}
static const char *max310x_type(struct uart_port *port)
{
- struct max310x_port *s = container_of(port, struct max310x_port, port);
+ struct max310x_port *s = dev_get_drvdata(port->dev);
- return (port->type == PORT_MAX310X) ? s->name : NULL;
+ return (port->type == PORT_MAX310X) ? s->devtype->name : NULL;
}
static int max310x_request_port(struct uart_port *port)
@@ -841,134 +951,99 @@ static int max310x_request_port(struct uart_port *port)
return 0;
}
-static void max310x_release_port(struct uart_port *port)
-{
- /* Do nothing */
-}
-
static void max310x_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_MAX310X;
}
-static int max310x_verify_port(struct uart_port *port, struct serial_struct *ser)
+static int max310x_verify_port(struct uart_port *port, struct serial_struct *s)
{
- if ((ser->type == PORT_UNKNOWN) || (ser->type == PORT_MAX310X))
- return 0;
- if (ser->irq == port->irq)
- return 0;
+ if ((s->type != PORT_UNKNOWN) && (s->type != PORT_MAX310X))
+ return -EINVAL;
+ if (s->irq != port->irq)
+ return -EINVAL;
- return -EINVAL;
+ return 0;
}
-static struct uart_ops max310x_ops = {
+static void max310x_null_void(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static const struct uart_ops max310x_ops = {
.tx_empty = max310x_tx_empty,
.set_mctrl = max310x_set_mctrl,
.get_mctrl = max310x_get_mctrl,
- .stop_tx = max310x_stop_tx,
+ .stop_tx = max310x_null_void,
.start_tx = max310x_start_tx,
- .stop_rx = max310x_stop_rx,
- .enable_ms = max310x_enable_ms,
+ .stop_rx = max310x_null_void,
+ .enable_ms = max310x_null_void,
.break_ctl = max310x_break_ctl,
.startup = max310x_startup,
.shutdown = max310x_shutdown,
.set_termios = max310x_set_termios,
.type = max310x_type,
.request_port = max310x_request_port,
- .release_port = max310x_release_port,
+ .release_port = max310x_null_void,
.config_port = max310x_config_port,
.verify_port = max310x_verify_port,
};
-#ifdef CONFIG_PM_SLEEP
-
-static int max310x_suspend(struct device *dev)
+static int __maybe_unused max310x_suspend(struct device *dev)
{
- int ret;
struct max310x_port *s = dev_get_drvdata(dev);
+ int i;
- dev_dbg(dev, "Suspend\n");
-
- ret = uart_suspend_port(&s->uart, &s->port);
-
- mutex_lock(&s->max310x_mutex);
-
- /* Enable sleep mode */
- regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
- MAX310X_MODE1_FORCESLEEP_BIT,
- MAX310X_MODE1_FORCESLEEP_BIT);
-
- mutex_unlock(&s->max310x_mutex);
-
- if (s->pdata->suspend)
- s->pdata->suspend(1);
+ for (i = 0; i < s->uart.nr; i++) {
+ uart_suspend_port(&s->uart, &s->p[i].port);
+ s->devtype->power(&s->p[i].port, 0);
+ }
- return ret;
+ return 0;
}
-static int max310x_resume(struct device *dev)
+static int __maybe_unused max310x_resume(struct device *dev)
{
struct max310x_port *s = dev_get_drvdata(dev);
+ int i;
- dev_dbg(dev, "Resume\n");
-
- if (s->pdata->suspend)
- s->pdata->suspend(0);
-
- mutex_lock(&s->max310x_mutex);
-
- /* Disable sleep mode */
- regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
- MAX310X_MODE1_FORCESLEEP_BIT,
- 0);
-
- max310x_wait_pll(s);
-
- mutex_unlock(&s->max310x_mutex);
+ for (i = 0; i < s->uart.nr; i++) {
+ s->devtype->power(&s->p[i].port, 1);
+ uart_resume_port(&s->uart, &s->p[i].port);
+ }
- return uart_resume_port(&s->uart, &s->port);
+ return 0;
}
-static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
-#define MAX310X_PM_OPS (&max310x_pm_ops)
-
-#else
-#define MAX310X_PM_OPS NULL
-#endif
-
#ifdef CONFIG_GPIOLIB
static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- unsigned int val = 0;
+ unsigned int val;
struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+ struct uart_port *port = &s->p[offset / 4].port;
- mutex_lock(&s->max310x_mutex);
- regmap_read(s->regmap, MAX310X_GPIODATA_REG, &val);
- mutex_unlock(&s->max310x_mutex);
+ val = max310x_port_read(port, MAX310X_GPIODATA_REG);
- return !!((val >> 4) & (1 << offset));
+ return !!((val >> 4) & (1 << (offset % 4)));
}
static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+ struct uart_port *port = &s->p[offset / 4].port;
- mutex_lock(&s->max310x_mutex);
- regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ?
- 1 << offset : 0);
- mutex_unlock(&s->max310x_mutex);
+ max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4),
+ value ? 1 << (offset % 4) : 0);
}
static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+ struct uart_port *port = &s->p[offset / 4].port;
- mutex_lock(&s->max310x_mutex);
-
- regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset, 0);
-
- mutex_unlock(&s->max310x_mutex);
+ max310x_port_update(port, MAX310X_GPIOCFG_REG, 1 << (offset % 4), 0);
return 0;
}
@@ -977,74 +1052,42 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+ struct uart_port *port = &s->p[offset / 4].port;
- mutex_lock(&s->max310x_mutex);
-
- regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset,
- 1 << offset);
- regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ?
- 1 << offset : 0);
-
- mutex_unlock(&s->max310x_mutex);
+ max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4),
+ value ? 1 << (offset % 4) : 0);
+ max310x_port_update(port, MAX310X_GPIOCFG_REG, 1 << (offset % 4),
+ 1 << (offset % 4));
return 0;
}
#endif
-/* Generic platform data */
-static struct max310x_pdata generic_plat_data = {
- .driver_flags = MAX310X_EXT_CLK,
- .uart_flags[0] = MAX310X_ECHO_SUPRESS,
- .frequency = 26000000,
-};
-
-static int max310x_probe(struct spi_device *spi)
+static int max310x_probe(struct device *dev, int is_spi,
+ struct max310x_devtype *devtype, int irq)
{
struct max310x_port *s;
- struct device *dev = &spi->dev;
- int chiptype = spi_get_device_id(spi)->driver_data;
- struct max310x_pdata *pdata = dev->platform_data;
- unsigned int val = 0;
- int ret;
+ struct max310x_pdata *pdata = dev_get_platdata(dev);
+ int i, ret, uartclk;
/* Check for IRQ */
- if (spi->irq <= 0) {
+ if (irq <= 0) {
dev_err(dev, "No IRQ specified\n");
return -ENOTSUPP;
}
+ if (!pdata) {
+ dev_err(dev, "No platform data supplied\n");
+ return -EINVAL;
+ }
+
/* Alloc port structure */
- s = devm_kzalloc(dev, sizeof(struct max310x_port), GFP_KERNEL);
+ s = devm_kzalloc(dev, sizeof(*s) +
+ sizeof(struct max310x_one) * devtype->nr, GFP_KERNEL);
if (!s) {
dev_err(dev, "Error allocating port structure\n");
return -ENOMEM;
}
- dev_set_drvdata(dev, s);
-
- if (!pdata) {
- dev_warn(dev, "No platform data supplied, using defaults\n");
- pdata = &generic_plat_data;
- }
- s->pdata = pdata;
-
- /* Individual chip settings */
- switch (chiptype) {
- case MAX310X_TYPE_MAX3107:
- s->name = "MAX3107";
- s->nr_gpio = 4;
- s->uart.nr = 1;
- s->regcfg.max_register = 0x1f;
- break;
- case MAX310X_TYPE_MAX3108:
- s->name = "MAX3108";
- s->nr_gpio = 4;
- s->uart.nr = 1;
- s->regcfg.max_register = 0x1e;
- break;
- default:
- dev_err(dev, "Unsupported chip type %i\n", chiptype);
- return -ENOTSUPP;
- }
/* Check input frequency */
if ((pdata->driver_flags & MAX310X_EXT_CLK) &&
@@ -1055,13 +1098,11 @@ static int max310x_probe(struct spi_device *spi)
((pdata->frequency < 1000000) || (pdata->frequency > 4000000)))
goto err_freq;
- mutex_init(&s->max310x_mutex);
+ s->pdata = pdata;
+ s->devtype = devtype;
+ dev_set_drvdata(dev, s);
- /* Setup SPI bus */
- spi->mode = SPI_MODE_0;
- spi->bits_per_word = 8;
- spi->max_speed_hz = 26000000;
- spi_setup(spi);
+ mutex_init(&s->mutex);
/* Setup regmap */
s->regcfg.reg_bits = 8;
@@ -1069,109 +1110,100 @@ static int max310x_probe(struct spi_device *spi)
s->regcfg.read_flag_mask = 0x00;
s->regcfg.write_flag_mask = 0x80;
s->regcfg.cache_type = REGCACHE_RBTREE;
- s->regcfg.writeable_reg = max3107_8_reg_writeable;
+ s->regcfg.writeable_reg = max310x_reg_writeable;
s->regcfg.volatile_reg = max310x_reg_volatile;
s->regcfg.precious_reg = max310x_reg_precious;
- s->regmap = devm_regmap_init_spi(spi, &s->regcfg);
+ s->regcfg.max_register = devtype->nr * 0x20 - 1;
+
+ if (IS_ENABLED(CONFIG_SPI_MASTER) && is_spi) {
+ struct spi_device *spi = to_spi_device(dev);
+
+ s->regmap = devm_regmap_init_spi(spi, &s->regcfg);
+ } else
+ return -ENOTSUPP;
+
if (IS_ERR(s->regmap)) {
- ret = PTR_ERR(s->regmap);
dev_err(dev, "Failed to initialize register map\n");
- goto err_out;
- }
-
- /* Reset chip & check SPI function */
- ret = regmap_write(s->regmap, MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT);
- if (ret) {
- dev_err(dev, "SPI transfer failed\n");
- goto err_out;
- }
- /* Clear chip reset */
- regmap_write(s->regmap, MAX310X_MODE2_REG, 0);
-
- switch (chiptype) {
- case MAX310X_TYPE_MAX3107:
- /* Check REV ID to ensure we are talking to what we expect */
- regmap_read(s->regmap, MAX3107_REVID_REG, &val);
- if (((val & MAX3107_REV_MASK) != MAX3107_REV_ID)) {
- dev_err(dev, "%s ID 0x%02x does not match\n",
- s->name, val);
- ret = -ENODEV;
- goto err_out;
- }
- break;
- case MAX310X_TYPE_MAX3108:
- /* MAX3108 have not REV ID register, we just check default value
- * from clocksource register to make sure everything works.
- */
- regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val);
- if (val != (MAX310X_CLKSRC_EXTCLK_BIT |
- MAX310X_CLKSRC_PLLBYP_BIT)) {
- dev_err(dev, "%s not present\n", s->name);
- ret = -ENODEV;
- goto err_out;
- }
- break;
+ return PTR_ERR(s->regmap);
}
/* Board specific configure */
- if (pdata->init)
- pdata->init();
- if (pdata->suspend)
- pdata->suspend(0);
-
- /* Calculate referecne clock */
- s->uartclk = max310x_set_ref_clk(s);
-
- /* Disable all interrupts */
- regmap_write(s->regmap, MAX310X_IRQEN_REG, 0);
-
- /* Setup MODE1 register */
- val = MAX310X_MODE1_IRQSEL_BIT; /* Enable IRQ pin */
- if (pdata->driver_flags & MAX310X_AUTOSLEEP)
- val = MAX310X_MODE1_AUTOSLEEP_BIT;
- regmap_write(s->regmap, MAX310X_MODE1_REG, val);
-
- /* Setup interrupt */
- ret = devm_request_threaded_irq(dev, spi->irq, NULL, max310x_ist,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- dev_name(dev), s);
- if (ret) {
- dev_err(dev, "Unable to reguest IRQ %i\n", spi->irq);
- goto err_out;
+ if (s->pdata->init)
+ s->pdata->init();
+
+ /* Check device to ensure we are talking to what we expect */
+ ret = devtype->detect(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < devtype->nr; i++) {
+ unsigned int offs = i << 5;
+
+ /* Reset port */
+ regmap_write(s->regmap, MAX310X_MODE2_REG + offs,
+ MAX310X_MODE2_RST_BIT);
+ /* Clear port reset */
+ regmap_write(s->regmap, MAX310X_MODE2_REG + offs, 0);
+
+ /* Wait for port startup */
+ do {
+ regmap_read(s->regmap,
+ MAX310X_BRGDIVLSB_REG + offs, &ret);
+ } while (ret != 0x01);
+
+ regmap_update_bits(s->regmap, MAX310X_MODE1_REG + offs,
+ MAX310X_MODE1_AUTOSLEEP_BIT,
+ MAX310X_MODE1_AUTOSLEEP_BIT);
}
+ uartclk = max310x_set_ref_clk(s);
+ dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
+
/* Register UART driver */
s->uart.owner = THIS_MODULE;
- s->uart.driver_name = dev_name(dev);
s->uart.dev_name = "ttyMAX";
s->uart.major = MAX310X_MAJOR;
s->uart.minor = MAX310X_MINOR;
+ s->uart.nr = devtype->nr;
ret = uart_register_driver(&s->uart);
if (ret) {
dev_err(dev, "Registering UART driver failed\n");
- goto err_out;
+ return ret;
}
- /* Initialize workqueue for start TX */
- s->wq = create_freezable_workqueue(dev_name(dev));
- INIT_WORK(&s->tx_work, max310x_wq_proc);
-
- /* Initialize UART port data */
- s->port.line = 0;
- s->port.dev = dev;
- s->port.irq = spi->irq;
- s->port.type = PORT_MAX310X;
- s->port.fifosize = MAX310X_FIFO_SIZE;
- s->port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
- s->port.iotype = UPIO_PORT;
- s->port.membase = (void __iomem *)0xffffffff; /* Bogus value */
- s->port.uartclk = s->uartclk;
- s->port.ops = &max310x_ops;
- uart_add_one_port(&s->uart, &s->port);
+ for (i = 0; i < devtype->nr; i++) {
+ /* Initialize port data */
+ s->p[i].port.line = i;
+ s->p[i].port.dev = dev;
+ s->p[i].port.irq = irq;
+ s->p[i].port.type = PORT_MAX310X;
+ s->p[i].port.fifosize = MAX310X_FIFO_SIZE;
+ s->p[i].port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE |
+ UPF_LOW_LATENCY;
+ s->p[i].port.iotype = UPIO_PORT;
+ s->p[i].port.iobase = i * 0x20;
+ s->p[i].port.membase = (void __iomem *)~0;
+ s->p[i].port.uartclk = uartclk;
+ s->p[i].port.ops = &max310x_ops;
+ /* Disable all interrupts */
+ max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0);
+ /* Clear IRQ status register */
+ max310x_port_read(&s->p[i].port, MAX310X_IRQSTS_REG);
+ /* Enable IRQ pin */
+ max310x_port_update(&s->p[i].port, MAX310X_MODE1_REG,
+ MAX310X_MODE1_IRQSEL_BIT,
+ MAX310X_MODE1_IRQSEL_BIT);
+ /* Initialize queue for start TX */
+ INIT_WORK(&s->p[i].tx_work, max310x_wq_proc);
+ /* Register port */
+ uart_add_one_port(&s->uart, &s->p[i].port);
+ /* Go to suspend mode */
+ devtype->power(&s->p[i].port, 0);
+ }
#ifdef CONFIG_GPIOLIB
/* Setup GPIO cotroller */
- if (pdata->gpio_base) {
+ if (s->pdata->gpio_base) {
s->gpio.owner = THIS_MODULE;
s->gpio.dev = dev;
s->gpio.label = dev_name(dev);
@@ -1179,86 +1211,107 @@ static int max310x_probe(struct spi_device *spi)
s->gpio.get = max310x_gpio_get;
s->gpio.direction_output= max310x_gpio_direction_output;
s->gpio.set = max310x_gpio_set;
- s->gpio.base = pdata->gpio_base;
- s->gpio.ngpio = s->nr_gpio;
+ s->gpio.base = s->pdata->gpio_base;
+ s->gpio.ngpio = devtype->nr * 4;
s->gpio.can_sleep = 1;
- if (gpiochip_add(&s->gpio)) {
- /* Indicate that we should not call gpiochip_remove */
- s->gpio.base = 0;
- }
+ if (!gpiochip_add(&s->gpio))
+ s->gpio_used = 1;
} else
dev_info(dev, "GPIO support not enabled\n");
#endif
- /* Go to suspend mode */
- if (pdata->suspend)
- pdata->suspend(1);
+ /* Setup interrupt */
+ ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(dev), s);
+ if (ret) {
+ dev_err(dev, "Unable to reguest IRQ %i\n", irq);
+#ifdef CONFIG_GPIOLIB
+ if (s->gpio_used)
+ WARN_ON(gpiochip_remove(&s->gpio));
+#endif
+ }
- return 0;
+ return ret;
err_freq:
dev_err(dev, "Frequency parameter incorrect\n");
- ret = -EINVAL;
-
-err_out:
- dev_set_drvdata(dev, NULL);
-
- return ret;
+ return -EINVAL;
}
-static int max310x_remove(struct spi_device *spi)
+static int max310x_remove(struct device *dev)
{
- struct device *dev = &spi->dev;
struct max310x_port *s = dev_get_drvdata(dev);
- int ret = 0;
-
- dev_dbg(dev, "Removing port\n");
-
- devm_free_irq(dev, s->port.irq, s);
-
- destroy_workqueue(s->wq);
+ int i, ret = 0;
- uart_remove_one_port(&s->uart, &s->port);
+ for (i = 0; i < s->uart.nr; i++) {
+ cancel_work_sync(&s->p[i].tx_work);
+ uart_remove_one_port(&s->uart, &s->p[i].port);
+ s->devtype->power(&s->p[i].port, 0);
+ }
uart_unregister_driver(&s->uart);
#ifdef CONFIG_GPIOLIB
- if (s->pdata->gpio_base) {
+ if (s->gpio_used)
ret = gpiochip_remove(&s->gpio);
- if (ret)
- dev_err(dev, "Failed to remove gpio chip: %d\n", ret);
- }
#endif
- dev_set_drvdata(dev, NULL);
-
- if (s->pdata->suspend)
- s->pdata->suspend(1);
if (s->pdata->exit)
s->pdata->exit();
return ret;
}
+#ifdef CONFIG_SPI_MASTER
+static int max310x_spi_probe(struct spi_device *spi)
+{
+ struct max310x_devtype *devtype =
+ (struct max310x_devtype *)spi_get_device_id(spi)->driver_data;
+ int ret;
+
+ /* Setup SPI bus */
+ spi->bits_per_word = 8;
+ spi->mode = spi->mode ? : SPI_MODE_0;
+ spi->max_speed_hz = spi->max_speed_hz ? : 26000000;
+ ret = spi_setup(spi);
+ if (ret) {
+ dev_err(&spi->dev, "SPI setup failed\n");
+ return ret;
+ }
+
+ return max310x_probe(&spi->dev, 1, devtype, spi->irq);
+}
+
+static int max310x_spi_remove(struct spi_device *spi)
+{
+ return max310x_remove(&spi->dev);
+}
+
+static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
+
static const struct spi_device_id max310x_id_table[] = {
- { "max3107", MAX310X_TYPE_MAX3107 },
- { "max3108", MAX310X_TYPE_MAX3108 },
+ { "max3107", (kernel_ulong_t)&max3107_devtype, },
+ { "max3108", (kernel_ulong_t)&max3108_devtype, },
+ { "max3109", (kernel_ulong_t)&max3109_devtype, },
+ { "max14830", (kernel_ulong_t)&max14830_devtype, },
{ }
};
MODULE_DEVICE_TABLE(spi, max310x_id_table);
-static struct spi_driver max310x_driver = {
+static struct spi_driver max310x_uart_driver = {
.driver = {
- .name = "max310x",
+ .name = MAX310X_NAME,
.owner = THIS_MODULE,
- .pm = MAX310X_PM_OPS,
+ .pm = &max310x_pm_ops,
},
- .probe = max310x_probe,
- .remove = max310x_remove,
+ .probe = max310x_spi_probe,
+ .remove = max310x_spi_remove,
.id_table = max310x_id_table,
};
-module_spi_driver(max310x_driver);
+module_spi_driver(max310x_uart_driver);
+#endif
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
MODULE_DESCRIPTION("MAX310X serial driver");
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 65be0c00c4b..0edfaf8cd26 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -24,6 +24,7 @@
#include <linux/serial_core.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/platform_device.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#include <asm/mcfuart.h>
@@ -324,7 +325,9 @@ static void mcf_rx_chars(struct mcf_uart *pp)
uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
}
+ spin_unlock(&port->lock);
tty_flip_buffer_push(&port->state->port);
+ spin_lock(&port->lock);
}
/****************************************************************************/
@@ -644,7 +647,7 @@ static struct uart_driver mcf_driver = {
static int mcf_probe(struct platform_device *pdev)
{
- struct mcf_platform_uart *platp = pdev->dev.platform_data;
+ struct mcf_platform_uart *platp = dev_get_platdata(&pdev->dev);
struct uart_port *port;
int i;
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
index 4a82267af83..d3db042f649 100644
--- a/drivers/tty/serial/mfd.c
+++ b/drivers/tty/serial/mfd.c
@@ -386,7 +386,7 @@ static void serial_hsu_stop_tx(struct uart_port *port)
/* This is always called in spinlock protected mode, so
* modify timeout timer is safe here */
-void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
+void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, unsigned long *flags)
{
struct hsu_dma_buffer *dbuf = &up->rxbuf;
struct hsu_dma_chan *chan = up->rxc;
@@ -438,7 +438,9 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
| (0x1 << 16)
| (0x1 << 24) /* timeout bit, see HSU Errata 1 */
);
+ spin_unlock_irqrestore(&up->port.lock, *flags);
tty_flip_buffer_push(tport);
+ spin_lock_irqsave(&up->port.lock, *flags);
chan_writel(chan, HSU_CH_CR, 0x3);
@@ -459,7 +461,8 @@ static void serial_hsu_stop_rx(struct uart_port *port)
}
}
-static inline void receive_chars(struct uart_hsu_port *up, int *status)
+static inline void receive_chars(struct uart_hsu_port *up, int *status,
+ unsigned long *flags)
{
unsigned int ch, flag;
unsigned int max_count = 256;
@@ -519,7 +522,10 @@ static inline void receive_chars(struct uart_hsu_port *up, int *status)
ignore_char:
*status = serial_in(up, UART_LSR);
} while ((*status & UART_LSR_DR) && max_count--);
+
+ spin_unlock_irqrestore(&up->port.lock, *flags);
tty_flip_buffer_push(&up->port.state->port);
+ spin_lock_irqsave(&up->port.lock, *flags);
}
static void transmit_chars(struct uart_hsu_port *up)
@@ -613,7 +619,7 @@ static irqreturn_t port_irq(int irq, void *dev_id)
lsr = serial_in(up, UART_LSR);
if (lsr & UART_LSR_DR)
- receive_chars(up, &lsr);
+ receive_chars(up, &lsr, &flags);
check_modem_status(up);
/* lsr will be renewed during the receive_chars */
@@ -643,7 +649,7 @@ static inline void dma_chan_irq(struct hsu_dma_chan *chan)
/* Rx channel */
if (chan->dirt == DMA_FROM_DEVICE)
- hsu_dma_rx(up, int_sts);
+ hsu_dma_rx(up, int_sts, &flags);
/* Tx channel */
if (chan->dirt == DMA_TO_DEVICE) {
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
index bc24f493167..8d702677acc 100644
--- a/drivers/tty/serial/mpsc.c
+++ b/drivers/tty/serial/mpsc.c
@@ -934,7 +934,7 @@ static int serial_polled;
******************************************************************************
*/
-static int mpsc_rx_intr(struct mpsc_port_info *pi)
+static int mpsc_rx_intr(struct mpsc_port_info *pi, unsigned long *flags)
{
struct mpsc_rx_desc *rxre;
struct tty_port *port = &pi->port.state->port;
@@ -969,8 +969,11 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi)
#endif
/* Following use of tty struct directly is deprecated */
if (tty_buffer_request_room(port, bytes_in) < bytes_in) {
- if (port->low_latency)
+ if (port->low_latency) {
+ spin_unlock_irqrestore(&pi->port.lock, *flags);
tty_flip_buffer_push(port);
+ spin_lock_irqsave(&pi->port.lock, *flags);
+ }
/*
* If this failed then we will throw away the bytes
* but must do so to clear interrupts.
@@ -1080,7 +1083,9 @@ next_frame:
if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
mpsc_start_rx(pi);
+ spin_unlock_irqrestore(&pi->port.lock, *flags);
tty_flip_buffer_push(port);
+ spin_lock_irqsave(&pi->port.lock, *flags);
return rc;
}
@@ -1222,7 +1227,7 @@ static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id)
spin_lock_irqsave(&pi->port.lock, iflags);
mpsc_sdma_intr_ack(pi);
- if (mpsc_rx_intr(pi))
+ if (mpsc_rx_intr(pi, &iflags))
rc = IRQ_HANDLED;
if (mpsc_tx_intr(pi))
rc = IRQ_HANDLED;
@@ -1884,7 +1889,7 @@ static int mpsc_shared_drv_probe(struct platform_device *dev)
if (dev->id == 0) {
if (!(rc = mpsc_shared_map_regs(dev))) {
pdata = (struct mpsc_shared_pdata *)
- dev->dev.platform_data;
+ dev_get_platdata(&dev->dev);
mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
@@ -2025,7 +2030,7 @@ static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
{
struct mpsc_pdata *pdata;
- pdata = (struct mpsc_pdata *)pd->dev.platform_data;
+ pdata = (struct mpsc_pdata *)dev_get_platdata(&pd->dev);
pi->port.uartclk = pdata->brg_clk_freq;
pi->port.iotype = UPIO_MEM;
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
index 9b6ef20420c..a67e7081f00 100644
--- a/drivers/tty/serial/mrst_max3110.c
+++ b/drivers/tty/serial/mrst_max3110.c
@@ -713,7 +713,7 @@ static void serial_m3110_enable_ms(struct uart_port *port)
{
}
-struct uart_ops serial_m3110_ops = {
+static struct uart_ops serial_m3110_ops = {
.tx_empty = serial_m3110_tx_empty,
.set_mctrl = serial_m3110_set_mctrl,
.get_mctrl = serial_m3110_get_mctrl,
@@ -844,7 +844,7 @@ static int serial_m3110_probe(struct spi_device *spi)
pmax = max;
/* Give membase a psudo value to pass serial_core's check */
- max->port.membase = (void *)0xff110000;
+ max->port.membase = (unsigned char __iomem *)0xff110000;
uart_add_one_port(&serial_m3110_reg, &max->port);
return 0;
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 2c6cfb3cf03..b5d779cd3c2 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -45,16 +45,19 @@ struct msm_port {
struct clk *clk;
struct clk *pclk;
unsigned int imr;
- unsigned int *gsbi_base;
+ void __iomem *gsbi_base;
int is_uartdm;
unsigned int old_snap_state;
};
-static inline void wait_for_xmitr(struct uart_port *port, int bits)
+static inline void wait_for_xmitr(struct uart_port *port)
{
- if (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY))
- while ((msm_read(port, UART_ISR) & bits) != bits)
- cpu_relax();
+ while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
+ if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
+ break;
+ udelay(1);
+ }
+ msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR);
}
static void msm_stop_tx(struct uart_port *port)
@@ -137,7 +140,10 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr)
count -= 4;
}
+ spin_unlock(&port->lock);
tty_flip_buffer_push(tport);
+ spin_lock(&port->lock);
+
if (misr & (UART_IMR_RXSTALE))
msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
msm_write(port, 0xFFFFFF, UARTDM_DMRX);
@@ -189,52 +195,69 @@ static void handle_rx(struct uart_port *port)
tty_insert_flip_char(tport, c, flag);
}
+ spin_unlock(&port->lock);
tty_flip_buffer_push(tport);
+ spin_lock(&port->lock);
}
-static void reset_dm_count(struct uart_port *port)
+static void reset_dm_count(struct uart_port *port, int count)
{
- wait_for_xmitr(port, UART_ISR_TX_READY);
- msm_write(port, 1, UARTDM_NCF_TX);
+ wait_for_xmitr(port);
+ msm_write(port, count, UARTDM_NCF_TX);
+ msm_read(port, UARTDM_NCF_TX);
}
static void handle_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
struct msm_port *msm_port = UART_TO_MSM(port);
- int sent_tx;
+ unsigned int tx_count, num_chars;
+ unsigned int tf_pointer = 0;
+
+ tx_count = uart_circ_chars_pending(xmit);
+ tx_count = min3(tx_count, (unsigned int)UART_XMIT_SIZE - xmit->tail,
+ port->fifosize);
if (port->x_char) {
if (msm_port->is_uartdm)
- reset_dm_count(port);
+ reset_dm_count(port, tx_count + 1);
msm_write(port, port->x_char,
msm_port->is_uartdm ? UARTDM_TF : UART_TF);
port->icount.tx++;
port->x_char = 0;
+ } else if (tx_count && msm_port->is_uartdm) {
+ reset_dm_count(port, tx_count);
}
- if (msm_port->is_uartdm)
- reset_dm_count(port);
+ while (tf_pointer < tx_count) {
+ int i;
+ char buf[4] = { 0 };
+ unsigned int *bf = (unsigned int *)&buf;
- while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
- if (uart_circ_empty(xmit)) {
- /* disable tx interrupts */
- msm_port->imr &= ~UART_IMR_TXLEV;
- msm_write(port, msm_port->imr, UART_IMR);
+ if (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
break;
- }
- msm_write(port, xmit->buf[xmit->tail],
- msm_port->is_uartdm ? UARTDM_TF : UART_TF);
if (msm_port->is_uartdm)
- reset_dm_count(port);
+ num_chars = min(tx_count - tf_pointer,
+ (unsigned int)sizeof(buf));
+ else
+ num_chars = 1;
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- sent_tx = 1;
+ for (i = 0; i < num_chars; i++) {
+ buf[i] = xmit->buf[xmit->tail + i];
+ port->icount.tx++;
+ }
+
+ msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
+ xmit->tail = (xmit->tail + num_chars) & (UART_XMIT_SIZE - 1);
+ tf_pointer += num_chars;
}
+ /* disable tx interrupts if nothing more to send */
+ if (uart_circ_empty(xmit))
+ msm_stop_tx(port);
+
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
@@ -295,7 +318,7 @@ static void msm_reset(struct uart_port *port)
msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
}
-void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
unsigned int mr;
mr = msm_read(port, UART_MR1);
@@ -318,70 +341,60 @@ static void msm_break_ctl(struct uart_port *port, int break_ctl)
msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
}
+struct msm_baud_map {
+ u16 divisor;
+ u8 code;
+ u8 rxstale;
+};
+
+static const struct msm_baud_map *
+msm_find_best_baud(struct uart_port *port, unsigned int baud)
+{
+ unsigned int i, divisor;
+ const struct msm_baud_map *entry;
+ static const struct msm_baud_map table[] = {
+ { 1536, 0x00, 1 },
+ { 768, 0x11, 1 },
+ { 384, 0x22, 1 },
+ { 192, 0x33, 1 },
+ { 96, 0x44, 1 },
+ { 48, 0x55, 1 },
+ { 32, 0x66, 1 },
+ { 24, 0x77, 1 },
+ { 16, 0x88, 1 },
+ { 12, 0x99, 6 },
+ { 8, 0xaa, 6 },
+ { 6, 0xbb, 6 },
+ { 4, 0xcc, 6 },
+ { 3, 0xdd, 8 },
+ { 2, 0xee, 16 },
+ { 1, 0xff, 31 },
+ };
+
+ divisor = uart_get_divisor(port, baud);
+
+ for (i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++)
+ if (entry->divisor <= divisor)
+ break;
+
+ return entry; /* Default to smallest divider */
+}
+
static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
{
- unsigned int baud_code, rxstale, watermark;
+ unsigned int rxstale, watermark;
struct msm_port *msm_port = UART_TO_MSM(port);
+ const struct msm_baud_map *entry;
- switch (baud) {
- case 300:
- baud_code = UART_CSR_300;
- rxstale = 1;
- break;
- case 600:
- baud_code = UART_CSR_600;
- rxstale = 1;
- break;
- case 1200:
- baud_code = UART_CSR_1200;
- rxstale = 1;
- break;
- case 2400:
- baud_code = UART_CSR_2400;
- rxstale = 1;
- break;
- case 4800:
- baud_code = UART_CSR_4800;
- rxstale = 1;
- break;
- case 9600:
- baud_code = UART_CSR_9600;
- rxstale = 2;
- break;
- case 14400:
- baud_code = UART_CSR_14400;
- rxstale = 3;
- break;
- case 19200:
- baud_code = UART_CSR_19200;
- rxstale = 4;
- break;
- case 28800:
- baud_code = UART_CSR_28800;
- rxstale = 6;
- break;
- case 38400:
- baud_code = UART_CSR_38400;
- rxstale = 8;
- break;
- case 57600:
- baud_code = UART_CSR_57600;
- rxstale = 16;
- break;
- case 115200:
- default:
- baud_code = UART_CSR_115200;
- baud = 115200;
- rxstale = 31;
- break;
- }
+ entry = msm_find_best_baud(port, baud);
if (msm_port->is_uartdm)
msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
- msm_write(port, baud_code, UART_CSR);
+ msm_write(port, entry->code, UART_CSR);
/* RX stale watermark */
+ rxstale = entry->rxstale;
watermark = UART_IPR_STALE_LSB & rxstale;
watermark |= UART_IPR_RXSTALE_LAST;
watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
@@ -409,8 +422,7 @@ static void msm_init_clock(struct uart_port *port)
struct msm_port *msm_port = UART_TO_MSM(port);
clk_prepare_enable(msm_port->clk);
- if (!IS_ERR(msm_port->pclk))
- clk_prepare_enable(msm_port->pclk);
+ clk_prepare_enable(msm_port->pclk);
msm_serial_set_mnd_regs(port);
}
@@ -589,12 +601,10 @@ static void msm_release_port(struct uart_port *port)
port->membase = NULL;
if (msm_port->gsbi_base) {
- iowrite32(GSBI_PROTOCOL_IDLE, msm_port->gsbi_base +
- GSBI_CONTROL);
-
- gsbi_resource = platform_get_resource(pdev,
- IORESOURCE_MEM, 1);
+ writel_relaxed(GSBI_PROTOCOL_IDLE,
+ msm_port->gsbi_base + GSBI_CONTROL);
+ gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (unlikely(!gsbi_resource))
return;
@@ -637,7 +647,7 @@ static int msm_request_port(struct uart_port *port)
if (!request_mem_region(gsbi_resource->start, size,
"msm_serial")) {
ret = -EBUSY;
- goto fail_release_port;
+ goto fail_release_port_membase;
}
msm_port->gsbi_base = ioremap(gsbi_resource->start, size);
@@ -651,6 +661,8 @@ static int msm_request_port(struct uart_port *port)
fail_release_gsbi:
release_mem_region(gsbi_resource->start, size);
+fail_release_port_membase:
+ iounmap(port->membase);
fail_release_port:
release_mem_region(port->mapbase, size);
return ret;
@@ -666,10 +678,9 @@ static void msm_config_port(struct uart_port *port, int flags)
if (ret)
return;
}
-
- if (msm_port->is_uartdm)
- iowrite32(GSBI_PROTOCOL_UART, msm_port->gsbi_base +
- GSBI_CONTROL);
+ if (msm_port->gsbi_base)
+ writel_relaxed(GSBI_PROTOCOL_UART,
+ msm_port->gsbi_base + GSBI_CONTROL);
}
static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
@@ -689,13 +700,11 @@ static void msm_power(struct uart_port *port, unsigned int state,
switch (state) {
case 0:
clk_prepare_enable(msm_port->clk);
- if (!IS_ERR(msm_port->pclk))
- clk_prepare_enable(msm_port->pclk);
+ clk_prepare_enable(msm_port->pclk);
break;
case 3:
clk_disable_unprepare(msm_port->clk);
- if (!IS_ERR(msm_port->pclk))
- clk_disable_unprepare(msm_port->pclk);
+ clk_disable_unprepare(msm_port->pclk);
break;
default:
printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
@@ -760,32 +769,63 @@ static inline struct uart_port *get_port_from_line(unsigned int line)
}
#ifdef CONFIG_SERIAL_MSM_CONSOLE
-
-static void msm_console_putchar(struct uart_port *port, int c)
-{
- struct msm_port *msm_port = UART_TO_MSM(port);
-
- if (msm_port->is_uartdm)
- reset_dm_count(port);
-
- while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
- ;
- msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
-}
-
static void msm_console_write(struct console *co, const char *s,
unsigned int count)
{
+ int i;
struct uart_port *port;
struct msm_port *msm_port;
+ int num_newlines = 0;
+ bool replaced = false;
BUG_ON(co->index < 0 || co->index >= UART_NR);
port = get_port_from_line(co->index);
msm_port = UART_TO_MSM(port);
+ /* Account for newlines that will get a carriage return added */
+ for (i = 0; i < count; i++)
+ if (s[i] == '\n')
+ num_newlines++;
+ count += num_newlines;
+
spin_lock(&port->lock);
- uart_console_write(port, s, count, msm_console_putchar);
+ if (msm_port->is_uartdm)
+ reset_dm_count(port, count);
+
+ i = 0;
+ while (i < count) {
+ int j;
+ unsigned int num_chars;
+ char buf[4] = { 0 };
+ unsigned int *bf = (unsigned int *)&buf;
+
+ if (msm_port->is_uartdm)
+ num_chars = min(count - i, (unsigned int)sizeof(buf));
+ else
+ num_chars = 1;
+
+ for (j = 0; j < num_chars; j++) {
+ char c = *s;
+
+ if (c == '\n' && !replaced) {
+ buf[j] = '\r';
+ j++;
+ replaced = true;
+ }
+ if (j < num_chars) {
+ buf[j] = c;
+ s++;
+ replaced = false;
+ }
+ }
+
+ while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
+ cpu_relax();
+
+ msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
+ i += num_chars;
+ }
spin_unlock(&port->lock);
}
@@ -859,6 +899,11 @@ static struct uart_driver msm_uart_driver = {
static atomic_t msm_uart_next_id = ATOMIC_INIT(0);
+static const struct of_device_id msm_uartdm_table[] = {
+ { .compatible = "qcom,msm-uartdm" },
+ { }
+};
+
static int __init msm_serial_probe(struct platform_device *pdev)
{
struct msm_port *msm_port;
@@ -878,23 +923,17 @@ static int __init msm_serial_probe(struct platform_device *pdev)
port->dev = &pdev->dev;
msm_port = UART_TO_MSM(port);
- if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
+ if (of_match_device(msm_uartdm_table, &pdev->dev))
msm_port->is_uartdm = 1;
else
msm_port->is_uartdm = 0;
- if (msm_port->is_uartdm) {
- msm_port->clk = devm_clk_get(&pdev->dev, "gsbi_uart_clk");
- msm_port->pclk = devm_clk_get(&pdev->dev, "gsbi_pclk");
- } else {
- msm_port->clk = devm_clk_get(&pdev->dev, "uart_clk");
- msm_port->pclk = ERR_PTR(-ENOENT);
- }
-
+ msm_port->clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(msm_port->clk))
return PTR_ERR(msm_port->clk);
if (msm_port->is_uartdm) {
+ msm_port->pclk = devm_clk_get(&pdev->dev, "iface");
if (IS_ERR(msm_port->pclk))
return PTR_ERR(msm_port->pclk);
@@ -931,6 +970,7 @@ static int msm_serial_remove(struct platform_device *pdev)
static struct of_device_id msm_match_table[] = {
{ .compatible = "qcom,msm-uart" },
+ { .compatible = "qcom,msm-uartdm" },
{}
};
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
index e4acef5de77..469fda50ac6 100644
--- a/drivers/tty/serial/msm_serial.h
+++ b/drivers/tty/serial/msm_serial.h
@@ -38,19 +38,7 @@
#define UART_MR2_PARITY_MODE_SPACE 0x3
#define UART_MR2_PARITY_MODE 0x3
-#define UART_CSR 0x0008
-#define UART_CSR_115200 0xFF
-#define UART_CSR_57600 0xEE
-#define UART_CSR_38400 0xDD
-#define UART_CSR_28800 0xCC
-#define UART_CSR_19200 0xBB
-#define UART_CSR_14400 0xAA
-#define UART_CSR_9600 0x99
-#define UART_CSR_4800 0x77
-#define UART_CSR_2400 0x55
-#define UART_CSR_1200 0x44
-#define UART_CSR_600 0x33
-#define UART_CSR_300 0x22
+#define UART_CSR 0x0008
#define UART_TF 0x000C
#define UARTDM_TF 0x0070
@@ -71,6 +59,7 @@
#define UART_CR_CMD_RESET_RFR (14 << 4)
#define UART_CR_CMD_PROTECTION_EN (16 << 4)
#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
+#define UART_CR_CMD_RESET_TX_READY (3 << 8)
#define UART_CR_TX_DISABLE (1 << 3)
#define UART_CR_TX_ENABLE (1 << 2)
#define UART_CR_RX_DISABLE (1 << 1)
@@ -151,6 +140,7 @@ static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
msm_write(port, 0xF1, UART_NREG);
msm_write(port, 0x0F, UART_DREG);
msm_write(port, 0x1A, UART_MNDREG);
+ port->uartclk = 1843200;
}
/*
@@ -162,6 +152,7 @@ static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
msm_write(port, 0xF6, UART_NREG);
msm_write(port, 0x0F, UART_DREG);
msm_write(port, 0x0A, UART_MNDREG);
+ port->uartclk = 1843200;
}
static inline
@@ -169,7 +160,7 @@ void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
{
if (port->uartclk == 19200000)
msm_serial_set_mnd_regs_tcxo(port);
- else
+ else if (port->uartclk == 4800000)
msm_serial_set_mnd_regs_tcxoby4(port);
}
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 4ca2f64861e..48e94961a9e 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1618,7 +1618,7 @@ static int msm_hs_probe(struct platform_device *pdev)
struct msm_hs_port *msm_uport;
struct resource *resource;
const struct msm_serial_hs_platform_data *pdata =
- pdev->dev.platform_data;
+ dev_get_platdata(&pdev->dev);
if (pdev->id < 0 || pdev->id >= UARTDM_NR) {
printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id);
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 4f5f161896a..10e9d70b5c4 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -32,7 +32,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/of_device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
@@ -134,10 +133,10 @@ enum mxs_auart_type {
struct mxs_auart_port {
struct uart_port port;
-#define MXS_AUART_DMA_CONFIG 0x1
#define MXS_AUART_DMA_ENABLED 0x2
#define MXS_AUART_DMA_TX_SYNC 2 /* bit 2 */
#define MXS_AUART_DMA_RX_READY 3 /* bit 3 */
+#define MXS_AUART_RTSCTS 4 /* bit 4 */
unsigned long flags;
unsigned int ctrl;
enum mxs_auart_type devtype;
@@ -640,7 +639,8 @@ static void mxs_auart_settermios(struct uart_port *u,
* we can only implement the DMA support for auart
* in mx28.
*/
- if (is_imx28_auart(s) && (s->flags & MXS_AUART_DMA_CONFIG)) {
+ if (is_imx28_auart(s)
+ && test_bit(MXS_AUART_RTSCTS, &s->flags)) {
if (!mxs_auart_dma_init(s))
/* enable DMA tranfer */
ctrl2 |= AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE
@@ -678,11 +678,18 @@ static void mxs_auart_settermios(struct uart_port *u,
static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
{
- u32 istatus, istat;
+ u32 istat;
struct mxs_auart_port *s = context;
u32 stat = readl(s->port.membase + AUART_STAT);
- istatus = istat = readl(s->port.membase + AUART_INTR);
+ istat = readl(s->port.membase + AUART_INTR);
+
+ /* ack irq */
+ writel(istat & (AUART_INTR_RTIS
+ | AUART_INTR_TXIS
+ | AUART_INTR_RXIS
+ | AUART_INTR_CTSMIS),
+ s->port.membase + AUART_INTR_CLR);
if (istat & AUART_INTR_CTSMIS) {
uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
@@ -702,12 +709,6 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
istat &= ~AUART_INTR_TXIS;
}
- writel(istatus & (AUART_INTR_RTIS
- | AUART_INTR_TXIS
- | AUART_INTR_RXIS
- | AUART_INTR_CTSMIS),
- s->port.membase + AUART_INTR_CLR);
-
return IRQ_HANDLED;
}
@@ -850,7 +851,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
struct mxs_auart_port *s;
struct uart_port *port;
unsigned int old_ctrl0, old_ctrl2;
- unsigned int to = 1000;
+ unsigned int to = 20000;
if (co->index >= MXS_AUART_PORTS || co->index < 0)
return;
@@ -871,18 +872,23 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
uart_console_write(port, str, count, mxs_auart_console_putchar);
- /*
- * Finally, wait for transmitter to become empty
- * and restore the TCR
- */
+ /* Finally, wait for transmitter to become empty ... */
while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) {
+ udelay(1);
if (!to--)
break;
- udelay(1);
}
- writel(old_ctrl0, port->membase + AUART_CTRL0);
- writel(old_ctrl2, port->membase + AUART_CTRL2);
+ /*
+ * ... and restore the TCR if we waited long enough for the transmitter
+ * to be idle. This might keep the transmitter enabled although it is
+ * unused, but that is better than to disable it while it is still
+ * transmitting.
+ */
+ if (!(readl(port->membase + AUART_STAT) & AUART_STAT_BUSY)) {
+ writel(old_ctrl0, port->membase + AUART_CTRL0);
+ writel(old_ctrl2, port->membase + AUART_CTRL2);
+ }
clk_disable(s->clk);
}
@@ -1002,7 +1008,8 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
}
s->port.line = ret;
- s->flags |= MXS_AUART_DMA_CONFIG;
+ if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
+ set_bit(MXS_AUART_RTSCTS, &s->flags);
return 0;
}
@@ -1015,7 +1022,6 @@ static int mxs_auart_probe(struct platform_device *pdev)
u32 version;
int ret = 0;
struct resource *r;
- struct pinctrl *pinctrl;
s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
if (!s) {
@@ -1029,12 +1035,6 @@ static int mxs_auart_probe(struct platform_device *pdev)
else if (ret < 0)
goto out_free;
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- ret = PTR_ERR(pinctrl);
- goto out_free;
- }
-
if (of_id) {
pdev->id_entry = of_id->data;
s->devtype = pdev->id_entry->driver_data;
diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c
index b9a40ed70be..0a4dd70d29e 100644
--- a/drivers/tty/serial/netx-serial.c
+++ b/drivers/tty/serial/netx-serial.c
@@ -196,7 +196,7 @@ static void netx_txint(struct uart_port *port)
uart_write_wakeup(port);
}
-static void netx_rxint(struct uart_port *port)
+static void netx_rxint(struct uart_port *port, unsigned long *flags)
{
unsigned char rx, flg, status;
@@ -236,7 +236,9 @@ static void netx_rxint(struct uart_port *port)
uart_insert_char(port, status, SR_OE, rx, flg);
}
+ spin_unlock_irqrestore(&port->lock, *flags);
tty_flip_buffer_push(&port->state->port);
+ spin_lock_irqsave(&port->lock, *flags);
}
static irqreturn_t netx_int(int irq, void *dev_id)
@@ -250,7 +252,7 @@ static irqreturn_t netx_int(int irq, void *dev_id)
status = readl(port->membase + UART_IIR) & IIR_MASK;
while (status) {
if (status & IIR_RIS)
- netx_rxint(port);
+ netx_rxint(port, &flags);
if (status & IIR_TIS)
netx_txint(port);
if (status & IIR_MIS) {
@@ -693,8 +695,6 @@ static int serial_netx_remove(struct platform_device *pdev)
{
struct netx_port *sport = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
-
if (sport)
uart_remove_one_port(&netx_reg, &sport->port);
diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c
index 549c70a2a63..693bc6c2561 100644
--- a/drivers/tty/serial/nwpserial.c
+++ b/drivers/tty/serial/nwpserial.c
@@ -149,7 +149,10 @@ static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
tty_insert_flip_char(port, ch, TTY_NORMAL);
} while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR);
+ spin_unlock(&up->port.lock);
tty_flip_buffer_push(port);
+ spin_lock(&up->port.lock);
+
ret = IRQ_HANDLED;
/* clear interrupt */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index b6d17287307..816d1a23f9d 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -40,9 +40,11 @@
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/gpio.h>
-#include <linux/pinctrl/consumer.h>
+#include <linux/of_gpio.h>
#include <linux/platform_data/serial-omap.h>
+#include <dt-bindings/gpio/gpio.h>
+
#define OMAP_MAX_HSUART_PORTS 6
#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
@@ -52,6 +54,11 @@
#define OMAP_UART_REV_52 0x0502
#define OMAP_UART_REV_63 0x0603
+#define OMAP_UART_TX_WAKEUP_EN BIT(7)
+
+/* Feature flags */
+#define OMAP_UART_WER_HAS_TX_WAKEUP BIT(0)
+
#define UART_ERRATA_i202_MDR1_ACCESS BIT(0)
#define UART_ERRATA_i291_DMA_FORCEIDLE BIT(1)
@@ -137,6 +144,7 @@ struct uart_omap_port {
unsigned char dlh;
unsigned char mdr1;
unsigned char scr;
+ unsigned char wer;
int use_dma;
/*
@@ -151,16 +159,19 @@ struct uart_omap_port {
int context_loss_cnt;
u32 errata;
u8 wakeups_enabled;
+ u32 features;
int DTR_gpio;
int DTR_inverted;
int DTR_active;
+ struct serial_rs485 rs485;
+ int rts_gpio;
+
struct pm_qos_request pm_qos_request;
u32 latency;
u32 calc_latency;
struct work_struct qos_work;
- struct pinctrl *pins;
bool is_suspending;
};
@@ -195,7 +206,7 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
{
- struct omap_uart_port_info *pdata = up->dev->platform_data;
+ struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
if (!pdata || !pdata->get_context_loss_count)
return -EINVAL;
@@ -205,7 +216,7 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
{
- struct omap_uart_port_info *pdata = up->dev->platform_data;
+ struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
if (!pdata || !pdata->enable_wakeup)
return;
@@ -272,13 +283,42 @@ static void serial_omap_enable_ms(struct uart_port *port)
static void serial_omap_stop_tx(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
+ struct circ_buf *xmit = &up->port.state->xmit;
+ int res;
pm_runtime_get_sync(up->dev);
+
+ /* handle rs485 */
+ if (up->rs485.flags & SER_RS485_ENABLED) {
+ /* do nothing if current tx not yet completed */
+ res = serial_in(up, UART_LSR) & UART_LSR_TEMT;
+ if (!res)
+ return;
+
+ /* if there's no more data to send, turn off rts */
+ if (uart_circ_empty(xmit)) {
+ /* if rts not already disabled */
+ res = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;
+ if (gpio_get_value(up->rts_gpio) != res) {
+ if (up->rs485.delay_rts_after_send > 0) {
+ mdelay(up->rs485.delay_rts_after_send);
+ }
+ gpio_set_value(up->rts_gpio, res);
+ }
+ }
+ }
+
if (up->ier & UART_IER_THRI) {
up->ier &= ~UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
}
+ if ((up->rs485.flags & SER_RS485_ENABLED) &&
+ !(up->rs485.flags & SER_RS485_RX_DURING_TX)) {
+ up->ier = UART_IER_RLSI | UART_IER_RDI;
+ serial_out(up, UART_IER, up->ier);
+ }
+
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
}
@@ -340,8 +380,26 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
static void serial_omap_start_tx(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
+ int res;
pm_runtime_get_sync(up->dev);
+
+ /* handle rs485 */
+ if (up->rs485.flags & SER_RS485_ENABLED) {
+ /* if rts not already enabled */
+ res = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0;
+ if (gpio_get_value(up->rts_gpio) != res) {
+ gpio_set_value(up->rts_gpio, res);
+ if (up->rs485.delay_rts_before_send > 0) {
+ mdelay(up->rs485.delay_rts_before_send);
+ }
+ }
+ }
+
+ if ((up->rs485.flags & SER_RS485_ENABLED) &&
+ !(up->rs485.flags & SER_RS485_RX_DURING_TX))
+ serial_omap_stop_rx(port);
+
serial_omap_enable_ier_thri(up);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
@@ -683,7 +741,11 @@ static int serial_omap_startup(struct uart_port *port)
serial_out(up, UART_IER, up->ier);
/* Enable module level wake up */
- serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP);
+ up->wer = OMAP_UART_WER_MOD_WKUP;
+ if (up->features & OMAP_UART_WER_HAS_TX_WAKEUP)
+ up->wer |= OMAP_UART_TX_WAKEUP_EN;
+
+ serial_out(up, UART_OMAP_WER, up->wer);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
@@ -1254,6 +1316,76 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up)
#endif
+/* Enable or disable the rs485 support */
+static void
+serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+{
+ struct uart_omap_port *up = to_uart_omap_port(port);
+ unsigned long flags;
+ unsigned int mode;
+ int val;
+
+ pm_runtime_get_sync(up->dev);
+ spin_lock_irqsave(&up->port.lock, flags);
+
+ /* Disable interrupts from this port */
+ mode = up->ier;
+ up->ier = 0;
+ serial_out(up, UART_IER, 0);
+
+ /* store new config */
+ up->rs485 = *rs485conf;
+
+ /*
+ * Just as a precaution, only allow rs485
+ * to be enabled if the gpio pin is valid
+ */
+ if (gpio_is_valid(up->rts_gpio)) {
+ /* enable / disable rts */
+ val = (up->rs485.flags & SER_RS485_ENABLED) ?
+ SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND;
+ val = (up->rs485.flags & val) ? 1 : 0;
+ gpio_set_value(up->rts_gpio, val);
+ } else
+ up->rs485.flags &= ~SER_RS485_ENABLED;
+
+ /* Enable interrupts */
+ up->ier = mode;
+ serial_out(up, UART_IER, up->ier);
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
+}
+
+static int
+serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+{
+ struct serial_rs485 rs485conf;
+
+ switch (cmd) {
+ case TIOCSRS485:
+ if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
+ sizeof(rs485conf)))
+ return -EFAULT;
+
+ serial_omap_config_rs485(port, &rs485conf);
+ break;
+
+ case TIOCGRS485:
+ if (copy_to_user((struct serial_rs485 *) arg,
+ &(to_uart_omap_port(port)->rs485),
+ sizeof(rs485conf)))
+ return -EFAULT;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+
static struct uart_ops serial_omap_pops = {
.tx_empty = serial_omap_tx_empty,
.set_mctrl = serial_omap_set_mctrl,
@@ -1275,6 +1407,7 @@ static struct uart_ops serial_omap_pops = {
.request_port = serial_omap_request_port,
.config_port = serial_omap_config_port,
.verify_port = serial_omap_verify_port,
+ .ioctl = serial_omap_ioctl,
#ifdef CONFIG_CONSOLE_POLL
.poll_put_char = serial_omap_poll_put_char,
.poll_get_char = serial_omap_poll_get_char,
@@ -1334,7 +1467,7 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
u32 mvr, scheme;
u16 revision, major, minor;
- mvr = serial_in(up, UART_OMAP_MVER);
+ mvr = readl(up->port.membase + (UART_OMAP_MVER << up->port.regshift));
/* Check revision register scheme */
scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT;
@@ -1373,9 +1506,11 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
case OMAP_UART_REV_52:
up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
UART_ERRATA_i291_DMA_FORCEIDLE);
+ up->features |= OMAP_UART_WER_HAS_TX_WAKEUP;
break;
case OMAP_UART_REV_63:
up->errata |= UART_ERRATA_i202_MDR1_ACCESS;
+ up->features |= OMAP_UART_WER_HAS_TX_WAKEUP;
break;
default:
break;
@@ -1395,15 +1530,64 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
return omap_up_info;
}
+static int serial_omap_probe_rs485(struct uart_omap_port *up,
+ struct device_node *np)
+{
+ struct serial_rs485 *rs485conf = &up->rs485;
+ u32 rs485_delay[2];
+ enum of_gpio_flags flags;
+ int ret;
+
+ rs485conf->flags = 0;
+ up->rts_gpio = -EINVAL;
+
+ if (!np)
+ return 0;
+
+ if (of_property_read_bool(np, "rs485-rts-active-high"))
+ rs485conf->flags |= SER_RS485_RTS_ON_SEND;
+ else
+ rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
+
+ /* check for tx enable gpio */
+ up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags);
+ if (gpio_is_valid(up->rts_gpio)) {
+ ret = gpio_request(up->rts_gpio, "omap-serial");
+ if (ret < 0)
+ return ret;
+ ret = gpio_direction_output(up->rts_gpio,
+ flags & SER_RS485_RTS_AFTER_SEND);
+ if (ret < 0)
+ return ret;
+ } else
+ up->rts_gpio = -EINVAL;
+
+ if (of_property_read_u32_array(np, "rs485-rts-delay",
+ rs485_delay, 2) == 0) {
+ rs485conf->delay_rts_before_send = rs485_delay[0];
+ rs485conf->delay_rts_after_send = rs485_delay[1];
+ }
+
+ if (of_property_read_bool(np, "rs485-rx-during-tx"))
+ rs485conf->flags |= SER_RS485_RX_DURING_TX;
+
+ if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time"))
+ rs485conf->flags |= SER_RS485_ENABLED;
+
+ return 0;
+}
+
static int serial_omap_probe(struct platform_device *pdev)
{
struct uart_omap_port *up;
struct resource *mem, *irq;
- struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
+ struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
int ret;
- if (pdev->dev.of_node)
+ if (pdev->dev.of_node) {
omap_up_info = of_get_uart_port_info(&pdev->dev);
+ pdev->dev.platform_data = omap_up_info;
+ }
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
@@ -1468,12 +1652,9 @@ static int serial_omap_probe(struct platform_device *pdev)
goto err_port_line;
}
- up->pins = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(up->pins)) {
- dev_warn(&pdev->dev, "did not get pins for uart%i error: %li\n",
- up->port.line, PTR_ERR(up->pins));
- up->pins = NULL;
- }
+ ret = serial_omap_probe_rs485(up, pdev->dev.of_node);
+ if (ret < 0)
+ goto err_rs485;
sprintf(up->name, "OMAP UART%d", up->port.line);
up->port.mapbase = mem->start;
@@ -1501,7 +1682,6 @@ static int serial_omap_probe(struct platform_device *pdev)
INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
platform_set_drvdata(pdev, up);
- pm_runtime_enable(&pdev->dev);
if (omap_up_info->autosuspend_timeout == 0)
omap_up_info->autosuspend_timeout = -1;
device_init_wakeup(up->dev, true);
@@ -1510,6 +1690,8 @@ static int serial_omap_probe(struct platform_device *pdev)
omap_up_info->autosuspend_timeout);
pm_runtime_irq_safe(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
pm_runtime_get_sync(&pdev->dev);
omap_serial_fill_features_erratas(up);
@@ -1529,6 +1711,7 @@ err_add_port:
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
err_ioremap:
+err_rs485:
err_port_line:
dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
pdev->id, __func__, ret);
@@ -1609,6 +1792,7 @@ static void serial_omap_restore_context(struct uart_omap_port *up)
serial_omap_mdr1_errataset(up, up->mdr1);
else
serial_out(up, UART_OMAP_MDR1, up->mdr1);
+ serial_out(up, UART_OMAP_WER, up->wer);
}
static int serial_omap_runtime_suspend(struct device *dev)
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 572d48189de..52379e56a31 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -232,7 +232,7 @@ struct eg20t_port {
unsigned int iobase;
struct pci_dev *pdev;
int fifo_size;
- int uartclk;
+ unsigned int uartclk;
int start_tx;
int start_rx;
int tx_empty;
@@ -373,35 +373,62 @@ static const struct file_operations port_regs_ops = {
};
#endif /* CONFIG_DEBUG_FS */
+static struct dmi_system_id pch_uart_dmi_table[] = {
+ {
+ .ident = "CM-iTC",
+ {
+ DMI_MATCH(DMI_BOARD_NAME, "CM-iTC"),
+ },
+ (void *)CMITC_UARTCLK,
+ },
+ {
+ .ident = "FRI2",
+ {
+ DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
+ },
+ (void *)FRI2_64_UARTCLK,
+ },
+ {
+ .ident = "Fish River Island II",
+ {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
+ },
+ (void *)FRI2_48_UARTCLK,
+ },
+ {
+ .ident = "COMe-mTT",
+ {
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
+ },
+ (void *)NTC1_UARTCLK,
+ },
+ {
+ .ident = "nanoETXexpress-TT",
+ {
+ DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
+ },
+ (void *)NTC1_UARTCLK,
+ },
+ {
+ .ident = "MinnowBoard",
+ {
+ DMI_MATCH(DMI_BOARD_NAME, "MinnowBoard"),
+ },
+ (void *)MINNOW_UARTCLK,
+ },
+};
+
/* Return UART clock, checking for board specific clocks. */
-static int pch_uart_get_uartclk(void)
+static unsigned int pch_uart_get_uartclk(void)
{
- const char *cmp;
+ const struct dmi_system_id *d;
if (user_uartclk)
return user_uartclk;
- cmp = dmi_get_system_info(DMI_BOARD_NAME);
- if (cmp && strstr(cmp, "CM-iTC"))
- return CMITC_UARTCLK;
-
- cmp = dmi_get_system_info(DMI_BIOS_VERSION);
- if (cmp && strnstr(cmp, "FRI2", 4))
- return FRI2_64_UARTCLK;
-
- cmp = dmi_get_system_info(DMI_PRODUCT_NAME);
- if (cmp && strstr(cmp, "Fish River Island II"))
- return FRI2_48_UARTCLK;
-
- /* Kontron COMe-mTT10 (nanoETXexpress-TT) */
- cmp = dmi_get_system_info(DMI_BOARD_NAME);
- if (cmp && (strstr(cmp, "COMe-mTT") ||
- strstr(cmp, "nanoETXexpress-TT")))
- return NTC1_UARTCLK;
-
- cmp = dmi_get_system_info(DMI_BOARD_NAME);
- if (cmp && strstr(cmp, "MinnowBoard"))
- return MINNOW_UARTCLK;
+ d = dmi_first_match(pch_uart_dmi_table);
+ if (d)
+ return (unsigned long)d->driver_data;
return DEFAULT_UARTCLK;
}
@@ -422,7 +449,7 @@ static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv,
iowrite8(ier, priv->membase + UART_IER);
}
-static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
+static int pch_uart_hal_set_line(struct eg20t_port *priv, unsigned int baud,
unsigned int parity, unsigned int bits,
unsigned int stb)
{
@@ -457,7 +484,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
lcr |= bits;
lcr |= stb;
- dev_dbg(priv->port.dev, "%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
+ dev_dbg(priv->port.dev, "%s:baud = %u, div = %04x, lcr = %02x (%lu)\n",
__func__, baud, div, lcr, jiffies);
iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
iowrite8(dll, priv->membase + PCH_UART_DLL);
@@ -1363,9 +1390,8 @@ static void pch_uart_shutdown(struct uart_port *port)
static void pch_uart_set_termios(struct uart_port *port,
struct ktermios *termios, struct ktermios *old)
{
- int baud;
int rtn;
- unsigned int parity, bits, stb;
+ unsigned int baud, parity, bits, stb;
struct eg20t_port *priv;
unsigned long flags;
@@ -1498,6 +1524,7 @@ static int pch_uart_verify_port(struct uart_port *port,
return 0;
}
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_PCH_UART_CONSOLE)
/*
* Wait for transmitter & holding register to empty
*/
@@ -1528,6 +1555,7 @@ static void wait_for_xmitr(struct eg20t_port *up, int bits)
}
}
}
+#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_PCH_UART_CONSOLE */
#ifdef CONFIG_CONSOLE_POLL
/*
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index b1785f58b6e..f87f1a0c8c6 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -1798,7 +1798,6 @@ static int __exit pmz_detach(struct platform_device *pdev)
uart_remove_one_port(&pmz_uart_reg, &uap->port);
- platform_set_drvdata(pdev, NULL);
uap->port.dev = NULL;
return 0;
diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c
index 7e277a5384a..de6c05c6368 100644
--- a/drivers/tty/serial/pnx8xxx_uart.c
+++ b/drivers/tty/serial/pnx8xxx_uart.c
@@ -237,7 +237,10 @@ static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
}
+
+ spin_unlock(&sport->port.lock);
tty_flip_buffer_push(&sport->port.state->port);
+ spin_lock(&sport->port.lock);
}
static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport)
@@ -801,8 +804,6 @@ static int pnx8xxx_serial_remove(struct platform_device *pdev)
{
struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
-
if (sport)
uart_remove_one_port(&pnx8xxx_reg, &sport->port);
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 05f504e0c27..f9f20f38376 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -332,31 +332,6 @@ static void serial_pxa_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&up->port.lock, flags);
}
-#if 0
-static void serial_pxa_dma_init(struct pxa_uart *up)
-{
- up->rxdma =
- pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up);
- if (up->rxdma < 0)
- goto out;
- up->txdma =
- pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up);
- if (up->txdma < 0)
- goto err_txdma;
- up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL);
- if (!up->dmadesc)
- goto err_alloc;
-
- /* ... */
-err_alloc:
- pxa_free_dma(up->txdma);
-err_rxdma:
- pxa_free_dma(up->rxdma);
-out:
- return;
-}
-#endif
-
static int serial_pxa_startup(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
@@ -790,7 +765,7 @@ static struct console serial_pxa_console = {
#define PXA_CONSOLE NULL
#endif
-struct uart_ops serial_pxa_pops = {
+static struct uart_ops serial_pxa_pops = {
.tx_empty = serial_pxa_tx_empty,
.set_mctrl = serial_pxa_set_mctrl,
.get_mctrl = serial_pxa_get_mctrl,
@@ -945,8 +920,6 @@ static int serial_pxa_remove(struct platform_device *dev)
{
struct uart_pxa_port *sport = platform_get_drvdata(dev);
- platform_set_drvdata(dev, NULL);
-
uart_remove_one_port(&serial_pxa_reg, &sport->port);
clk_unprepare(sport->clk);
@@ -970,7 +943,7 @@ static struct platform_driver serial_pxa_driver = {
},
};
-int __init serial_pxa_init(void)
+static int __init serial_pxa_init(void)
{
int ret;
@@ -985,7 +958,7 @@ int __init serial_pxa_init(void)
return ret;
}
-void __exit serial_pxa_exit(void)
+static void __exit serial_pxa_exit(void)
{
platform_driver_unregister(&serial_pxa_driver);
uart_unregister_driver(&serial_pxa_reg);
diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c
index a314a943f12..328d6deb6b0 100644
--- a/drivers/tty/serial/rp2.c
+++ b/drivers/tty/serial/rp2.c
@@ -427,7 +427,9 @@ static void rp2_rx_chars(struct rp2_uart_port *up)
up->port.icount.rx++;
}
+ spin_unlock(&up->port.lock);
tty_flip_buffer_push(port);
+ spin_lock(&up->port.lock);
}
static void rp2_tx_chars(struct rp2_uart_port *up)
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index af6b3e3ad24..ba25722a713 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -232,7 +232,10 @@ sa1100_rx_chars(struct sa1100_port *sport)
status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
UTSR0_TO_SM(UART_GET_UTSR0(sport));
}
+
+ spin_unlock(&sport->port.lock);
tty_flip_buffer_push(&sport->port.state->port);
+ spin_lock(&sport->port.lock);
}
static void sa1100_tx_chars(struct sa1100_port *sport)
@@ -864,8 +867,6 @@ static int sa1100_serial_remove(struct platform_device *pdev)
{
struct sa1100_port *sport = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
-
if (sport)
uart_remove_one_port(&sa1100_reg, &sport->port);
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 376079b9bd7..f3dfa19a1cb 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -249,6 +249,8 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
ufcon |= S3C2410_UFCON_RESETRX;
wr_regl(port, S3C2410_UFCON, ufcon);
rx_enabled(port) = 1;
+ spin_unlock_irqrestore(&port->lock,
+ flags);
goto out;
}
continue;
@@ -297,10 +299,11 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
ignore_char:
continue;
}
+
+ spin_unlock_irqrestore(&port->lock, flags);
tty_flip_buffer_push(&port->state->port);
out:
- spin_unlock_irqrestore(&port->lock, flags);
return IRQ_HANDLED;
}
@@ -1250,8 +1253,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
ourport->baudclk = ERR_PTR(-EINVAL);
ourport->info = ourport->drv_data->info;
- ourport->cfg = (pdev->dev.platform_data) ?
- (struct s3c2410_uartcfg *)pdev->dev.platform_data :
+ ourport->cfg = (dev_get_platdata(&pdev->dev)) ?
+ (struct s3c2410_uartcfg *)dev_get_platdata(&pdev->dev) :
ourport->drv_data->def_cfg;
ourport->port.fifosize = (ourport->info->fifosize) ?
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index 00a499ecd38..aaa617a6c49 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -68,7 +68,8 @@ struct s3c24xx_uart_port {
/* register access controls */
#define portaddr(port, reg) ((port)->membase + (reg))
-#define portaddrl(port, reg) ((unsigned long *)((port)->membase + (reg)))
+#define portaddrl(port, reg) \
+ ((unsigned long *)(unsigned long)((port)->membase + (reg)))
#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c
index 4b1434d53e9..887b4f77074 100644
--- a/drivers/tty/serial/sc26xx.c
+++ b/drivers/tty/serial/sc26xx.c
@@ -637,7 +637,7 @@ static int sc26xx_probe(struct platform_device *dev)
{
struct resource *res;
struct uart_sc26xx_port *up;
- unsigned int *sc26xx_data = dev->dev.platform_data;
+ unsigned int *sc26xx_data = dev_get_platdata(&dev->dev);
int err;
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index c7730415541..49e9bbfe6ca 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -15,6 +15,7 @@
#define SUPPORT_SYSRQ
#endif
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -94,16 +95,17 @@
#define MCTRL_IBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_IP0)
#define MCTRL_OBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_OP0)
-/* Supported chip types */
-enum {
- SCCNXP_TYPE_SC2681 = 2681,
- SCCNXP_TYPE_SC2691 = 2691,
- SCCNXP_TYPE_SC2692 = 2692,
- SCCNXP_TYPE_SC2891 = 2891,
- SCCNXP_TYPE_SC2892 = 2892,
- SCCNXP_TYPE_SC28202 = 28202,
- SCCNXP_TYPE_SC68681 = 68681,
- SCCNXP_TYPE_SC68692 = 68692,
+#define SCCNXP_HAVE_IO 0x00000001
+#define SCCNXP_HAVE_MR0 0x00000002
+
+struct sccnxp_chip {
+ const char *name;
+ unsigned int nr;
+ unsigned long freq_min;
+ unsigned long freq_std;
+ unsigned long freq_max;
+ unsigned int flags;
+ unsigned int fifosize;
};
struct sccnxp_port {
@@ -111,16 +113,10 @@ struct sccnxp_port {
struct uart_port port[SCCNXP_MAX_UARTS];
bool opened[SCCNXP_MAX_UARTS];
- const char *name;
int irq;
-
u8 imr;
- u8 addr_mask;
- int freq_std;
- int flags;
-#define SCCNXP_HAVE_IO 0x00000001
-#define SCCNXP_HAVE_MR0 0x00000002
+ struct sccnxp_chip *chip;
#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
struct console console;
@@ -136,29 +132,94 @@ struct sccnxp_port {
struct regulator *regulator;
};
-static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift)
-{
- return readb(base + (reg << shift));
-}
+static const struct sccnxp_chip sc2681 = {
+ .name = "SC2681",
+ .nr = 2,
+ .freq_min = 1000000,
+ .freq_std = 3686400,
+ .freq_max = 4000000,
+ .flags = SCCNXP_HAVE_IO,
+ .fifosize = 3,
+};
-static inline void sccnxp_raw_write(void __iomem *base, u8 reg, u8 shift, u8 v)
-{
- writeb(v, base + (reg << shift));
-}
+static const struct sccnxp_chip sc2691 = {
+ .name = "SC2691",
+ .nr = 1,
+ .freq_min = 1000000,
+ .freq_std = 3686400,
+ .freq_max = 4000000,
+ .flags = 0,
+ .fifosize = 3,
+};
+
+static const struct sccnxp_chip sc2692 = {
+ .name = "SC2692",
+ .nr = 2,
+ .freq_min = 1000000,
+ .freq_std = 3686400,
+ .freq_max = 4000000,
+ .flags = SCCNXP_HAVE_IO,
+ .fifosize = 3,
+};
+
+static const struct sccnxp_chip sc2891 = {
+ .name = "SC2891",
+ .nr = 1,
+ .freq_min = 100000,
+ .freq_std = 3686400,
+ .freq_max = 8000000,
+ .flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
+ .fifosize = 16,
+};
+
+static const struct sccnxp_chip sc2892 = {
+ .name = "SC2892",
+ .nr = 2,
+ .freq_min = 100000,
+ .freq_std = 3686400,
+ .freq_max = 8000000,
+ .flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
+ .fifosize = 16,
+};
+
+static const struct sccnxp_chip sc28202 = {
+ .name = "SC28202",
+ .nr = 2,
+ .freq_min = 1000000,
+ .freq_std = 14745600,
+ .freq_max = 50000000,
+ .flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
+ .fifosize = 256,
+};
+
+static const struct sccnxp_chip sc68681 = {
+ .name = "SC68681",
+ .nr = 2,
+ .freq_min = 1000000,
+ .freq_std = 3686400,
+ .freq_max = 4000000,
+ .flags = SCCNXP_HAVE_IO,
+ .fifosize = 3,
+};
+
+static const struct sccnxp_chip sc68692 = {
+ .name = "SC68692",
+ .nr = 2,
+ .freq_min = 1000000,
+ .freq_std = 3686400,
+ .freq_max = 4000000,
+ .flags = SCCNXP_HAVE_IO,
+ .fifosize = 3,
+};
static inline u8 sccnxp_read(struct uart_port *port, u8 reg)
{
- struct sccnxp_port *s = dev_get_drvdata(port->dev);
-
- return sccnxp_raw_read(port->membase, reg & s->addr_mask,
- port->regshift);
+ return readb(port->membase + (reg << port->regshift));
}
static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v)
{
- struct sccnxp_port *s = dev_get_drvdata(port->dev);
-
- sccnxp_raw_write(port->membase, reg & s->addr_mask, port->regshift, v);
+ writeb(v, port->membase + (reg << port->regshift));
}
static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg)
@@ -224,13 +285,14 @@ static int sccnxp_set_baud(struct uart_port *port, int baud)
{
struct sccnxp_port *s = dev_get_drvdata(port->dev);
int div_std, tmp_baud, bestbaud = baud, besterr = -1;
+ struct sccnxp_chip *chip = s->chip;
u8 i, acr = 0, csr = 0, mr0 = 0;
/* Find best baud from table */
for (i = 0; baud_std[i].baud && besterr; i++) {
- if (baud_std[i].mr0 && !(s->flags & SCCNXP_HAVE_MR0))
+ if (baud_std[i].mr0 && !(chip->flags & SCCNXP_HAVE_MR0))
continue;
- div_std = DIV_ROUND_CLOSEST(s->freq_std, baud_std[i].baud);
+ div_std = DIV_ROUND_CLOSEST(chip->freq_std, baud_std[i].baud);
tmp_baud = DIV_ROUND_CLOSEST(port->uartclk, div_std);
if (!sccnxp_update_best_err(baud, tmp_baud, &besterr)) {
acr = baud_std[i].acr;
@@ -240,7 +302,7 @@ static int sccnxp_set_baud(struct uart_port *port, int baud)
}
}
- if (s->flags & SCCNXP_HAVE_MR0) {
+ if (chip->flags & SCCNXP_HAVE_MR0) {
/* Enable FIFO, set half level for TX */
mr0 |= MR0_FIFO | MR0_TXLVL;
/* Update MR0 */
@@ -363,7 +425,7 @@ static void sccnxp_handle_tx(struct uart_port *port)
sccnxp_disable_irq(port, IMR_TXRDY);
/* Set direction to input */
- if (s->flags & SCCNXP_HAVE_IO)
+ if (s->chip->flags & SCCNXP_HAVE_IO)
sccnxp_set_bit(port, DIR_OP, 0);
}
return;
@@ -437,7 +499,7 @@ static void sccnxp_start_tx(struct uart_port *port)
spin_lock_irqsave(&s->lock, flags);
/* Set direction to output */
- if (s->flags & SCCNXP_HAVE_IO)
+ if (s->chip->flags & SCCNXP_HAVE_IO)
sccnxp_set_bit(port, DIR_OP, 1);
sccnxp_enable_irq(port, IMR_TXRDY);
@@ -483,7 +545,7 @@ static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl)
struct sccnxp_port *s = dev_get_drvdata(port->dev);
unsigned long flags;
- if (!(s->flags & SCCNXP_HAVE_IO))
+ if (!(s->chip->flags & SCCNXP_HAVE_IO))
return;
spin_lock_irqsave(&s->lock, flags);
@@ -501,7 +563,7 @@ static unsigned int sccnxp_get_mctrl(struct uart_port *port)
struct sccnxp_port *s = dev_get_drvdata(port->dev);
unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
- if (!(s->flags & SCCNXP_HAVE_IO))
+ if (!(s->chip->flags & SCCNXP_HAVE_IO))
return mctrl;
spin_lock_irqsave(&s->lock, flags);
@@ -617,7 +679,7 @@ static void sccnxp_set_termios(struct uart_port *port,
/* Setup baudrate */
baud = uart_get_baud_rate(port, termios, old, 50,
- (s->flags & SCCNXP_HAVE_MR0) ?
+ (s->chip->flags & SCCNXP_HAVE_MR0) ?
230400 : 38400);
baud = sccnxp_set_baud(port, baud);
@@ -641,7 +703,7 @@ static int sccnxp_startup(struct uart_port *port)
spin_lock_irqsave(&s->lock, flags);
- if (s->flags & SCCNXP_HAVE_IO) {
+ if (s->chip->flags & SCCNXP_HAVE_IO) {
/* Outputs are controlled manually */
sccnxp_write(port, SCCNXP_OPCR_REG, 0);
}
@@ -681,7 +743,7 @@ static void sccnxp_shutdown(struct uart_port *port)
sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE | CR_TX_DISABLE);
/* Leave direction to input */
- if (s->flags & SCCNXP_HAVE_IO)
+ if (s->chip->flags & SCCNXP_HAVE_IO)
sccnxp_set_bit(port, DIR_OP, 0);
spin_unlock_irqrestore(&s->lock, flags);
@@ -691,7 +753,7 @@ static const char *sccnxp_type(struct uart_port *port)
{
struct sccnxp_port *s = dev_get_drvdata(port->dev);
- return (port->type == PORT_SC26XX) ? s->name : NULL;
+ return (port->type == PORT_SC26XX) ? s->chip->name : NULL;
}
static void sccnxp_release_port(struct uart_port *port)
@@ -778,19 +840,31 @@ static int sccnxp_console_setup(struct console *co, char *options)
}
#endif
+static const struct platform_device_id sccnxp_id_table[] = {
+ { .name = "sc2681", .driver_data = (kernel_ulong_t)&sc2681, },
+ { .name = "sc2691", .driver_data = (kernel_ulong_t)&sc2691, },
+ { .name = "sc2692", .driver_data = (kernel_ulong_t)&sc2692, },
+ { .name = "sc2891", .driver_data = (kernel_ulong_t)&sc2891, },
+ { .name = "sc2892", .driver_data = (kernel_ulong_t)&sc2892, },
+ { .name = "sc28202", .driver_data = (kernel_ulong_t)&sc28202, },
+ { .name = "sc68681", .driver_data = (kernel_ulong_t)&sc68681, },
+ { .name = "sc68692", .driver_data = (kernel_ulong_t)&sc68692, },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, sccnxp_id_table);
+
static int sccnxp_probe(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- int chiptype = pdev->id_entry->driver_data;
struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev);
- int i, ret, fifosize, freq_min, freq_max;
+ int i, ret, uartclk;
struct sccnxp_port *s;
void __iomem *membase;
+ struct clk *clk;
- if (!res) {
- dev_err(&pdev->dev, "Missing memory resource data\n");
- return -EADDRNOTAVAIL;
- }
+ membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(membase))
+ return PTR_ERR(membase);
s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL);
if (!s) {
@@ -801,99 +875,38 @@ static int sccnxp_probe(struct platform_device *pdev)
spin_lock_init(&s->lock);
- /* Individual chip settings */
- switch (chiptype) {
- case SCCNXP_TYPE_SC2681:
- s->name = "SC2681";
- s->uart.nr = 2;
- s->freq_std = 3686400;
- s->addr_mask = 0x0f;
- s->flags = SCCNXP_HAVE_IO;
- fifosize = 3;
- freq_min = 1000000;
- freq_max = 4000000;
- break;
- case SCCNXP_TYPE_SC2691:
- s->name = "SC2691";
- s->uart.nr = 1;
- s->freq_std = 3686400;
- s->addr_mask = 0x07;
- s->flags = 0;
- fifosize = 3;
- freq_min = 1000000;
- freq_max = 4000000;
- break;
- case SCCNXP_TYPE_SC2692:
- s->name = "SC2692";
- s->uart.nr = 2;
- s->freq_std = 3686400;
- s->addr_mask = 0x0f;
- s->flags = SCCNXP_HAVE_IO;
- fifosize = 3;
- freq_min = 1000000;
- freq_max = 4000000;
- break;
- case SCCNXP_TYPE_SC2891:
- s->name = "SC2891";
- s->uart.nr = 1;
- s->freq_std = 3686400;
- s->addr_mask = 0x0f;
- s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
- fifosize = 16;
- freq_min = 100000;
- freq_max = 8000000;
- break;
- case SCCNXP_TYPE_SC2892:
- s->name = "SC2892";
- s->uart.nr = 2;
- s->freq_std = 3686400;
- s->addr_mask = 0x0f;
- s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
- fifosize = 16;
- freq_min = 100000;
- freq_max = 8000000;
- break;
- case SCCNXP_TYPE_SC28202:
- s->name = "SC28202";
- s->uart.nr = 2;
- s->freq_std = 14745600;
- s->addr_mask = 0x7f;
- s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
- fifosize = 256;
- freq_min = 1000000;
- freq_max = 50000000;
- break;
- case SCCNXP_TYPE_SC68681:
- s->name = "SC68681";
- s->uart.nr = 2;
- s->freq_std = 3686400;
- s->addr_mask = 0x0f;
- s->flags = SCCNXP_HAVE_IO;
- fifosize = 3;
- freq_min = 1000000;
- freq_max = 4000000;
- break;
- case SCCNXP_TYPE_SC68692:
- s->name = "SC68692";
- s->uart.nr = 2;
- s->freq_std = 3686400;
- s->addr_mask = 0x0f;
- s->flags = SCCNXP_HAVE_IO;
- fifosize = 3;
- freq_min = 1000000;
- freq_max = 4000000;
- break;
- default:
- dev_err(&pdev->dev, "Unsupported chip type %i\n", chiptype);
- ret = -ENOTSUPP;
+ s->chip = (struct sccnxp_chip *)pdev->id_entry->driver_data;
+
+ s->regulator = devm_regulator_get(&pdev->dev, "vcc");
+ if (!IS_ERR(s->regulator)) {
+ ret = regulator_enable(s->regulator);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to enable regulator: %i\n", ret);
+ return ret;
+ }
+ } else if (PTR_ERR(s->regulator) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_out;
+ }
+ dev_notice(&pdev->dev, "Using default clock frequency\n");
+ uartclk = s->chip->freq_std;
+ } else
+ uartclk = clk_get_rate(clk);
+
+ /* Check input frequency */
+ if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) {
+ dev_err(&pdev->dev, "Frequency out of bounds\n");
+ ret = -EINVAL;
goto err_out;
}
- if (!pdata) {
- dev_warn(&pdev->dev,
- "No platform data supplied, using defaults\n");
- s->pdata.frequency = s->freq_std;
- } else
+ if (pdata)
memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata));
if (s->pdata.poll_time_us) {
@@ -911,34 +924,11 @@ static int sccnxp_probe(struct platform_device *pdev)
}
}
- /* Check input frequency */
- if ((s->pdata.frequency < freq_min) ||
- (s->pdata.frequency > freq_max)) {
- dev_err(&pdev->dev, "Frequency out of bounds\n");
- ret = -EINVAL;
- goto err_out;
- }
-
- s->regulator = devm_regulator_get(&pdev->dev, "VCC");
- if (!IS_ERR(s->regulator)) {
- ret = regulator_enable(s->regulator);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to enable regulator: %i\n", ret);
- return ret;
- }
- }
-
- membase = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(membase)) {
- ret = PTR_ERR(membase);
- goto err_out;
- }
-
s->uart.owner = THIS_MODULE;
s->uart.dev_name = "ttySC";
s->uart.major = SCCNXP_MAJOR;
s->uart.minor = SCCNXP_MINOR;
+ s->uart.nr = s->chip->nr;
#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
s->uart.cons = &s->console;
s->uart.cons->device = uart_console_device;
@@ -960,17 +950,17 @@ static int sccnxp_probe(struct platform_device *pdev)
s->port[i].dev = &pdev->dev;
s->port[i].irq = s->irq;
s->port[i].type = PORT_SC26XX;
- s->port[i].fifosize = fifosize;
+ s->port[i].fifosize = s->chip->fifosize;
s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
s->port[i].iotype = UPIO_MEM;
s->port[i].mapbase = res->start;
s->port[i].membase = membase;
s->port[i].regshift = s->pdata.reg_shift;
- s->port[i].uartclk = s->pdata.frequency;
+ s->port[i].uartclk = uartclk;
s->port[i].ops = &sccnxp_ops;
uart_add_one_port(&s->uart, &s->port[i]);
/* Set direction to input */
- if (s->flags & SCCNXP_HAVE_IO)
+ if (s->chip->flags & SCCNXP_HAVE_IO)
sccnxp_set_bit(&s->port[i], DIR_OP, 0);
}
@@ -997,7 +987,8 @@ static int sccnxp_probe(struct platform_device *pdev)
}
err_out:
- platform_set_drvdata(pdev, NULL);
+ if (!IS_ERR(s->regulator))
+ return regulator_disable(s->regulator);
return ret;
}
@@ -1016,7 +1007,6 @@ static int sccnxp_remove(struct platform_device *pdev)
uart_remove_one_port(&s->uart, &s->port[i]);
uart_unregister_driver(&s->uart);
- platform_set_drvdata(pdev, NULL);
if (!IS_ERR(s->regulator))
return regulator_disable(s->regulator);
@@ -1024,19 +1014,6 @@ static int sccnxp_remove(struct platform_device *pdev)
return 0;
}
-static const struct platform_device_id sccnxp_id_table[] = {
- { "sc2681", SCCNXP_TYPE_SC2681 },
- { "sc2691", SCCNXP_TYPE_SC2691 },
- { "sc2692", SCCNXP_TYPE_SC2692 },
- { "sc2891", SCCNXP_TYPE_SC2891 },
- { "sc2892", SCCNXP_TYPE_SC2892 },
- { "sc28202", SCCNXP_TYPE_SC28202 },
- { "sc68681", SCCNXP_TYPE_SC68681 },
- { "sc68692", SCCNXP_TYPE_SC68692 },
- { },
-};
-MODULE_DEVICE_TABLE(platform, sccnxp_id_table);
-
static struct platform_driver sccnxp_uart_driver = {
.driver = {
.name = SCCNXP_NAME,
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index ee7c8123c37..d0d972f7e43 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -571,7 +571,9 @@ static void tegra_uart_rx_dma_complete(void *args)
tegra_uart_handle_rx_pio(tup, port);
if (tty) {
+ spin_unlock_irqrestore(&u->lock, flags);
tty_flip_buffer_push(port);
+ spin_lock_irqsave(&u->lock, flags);
tty_kref_put(tty);
}
tegra_uart_start_rx_dma(tup);
@@ -583,11 +585,13 @@ static void tegra_uart_rx_dma_complete(void *args)
spin_unlock_irqrestore(&u->lock, flags);
}
-static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup)
+static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
+ unsigned long *flags)
{
struct dma_tx_state state;
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
struct tty_port *port = &tup->uport.state->port;
+ struct uart_port *u = &tup->uport;
int count;
/* Deactivate flow control to stop sender */
@@ -604,7 +608,9 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup)
tegra_uart_handle_rx_pio(tup, port);
if (tty) {
+ spin_unlock_irqrestore(&u->lock, *flags);
tty_flip_buffer_push(port);
+ spin_lock_irqsave(&u->lock, *flags);
tty_kref_put(tty);
}
tegra_uart_start_rx_dma(tup);
@@ -671,7 +677,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
iir = tegra_uart_read(tup, UART_IIR);
if (iir & UART_IIR_NO_INT) {
if (is_rx_int) {
- tegra_uart_handle_rx_dma(tup);
+ tegra_uart_handle_rx_dma(tup, &flags);
if (tup->rx_in_progress) {
ier = tup->ier_shadow;
ier |= (UART_IER_RLSI | UART_IER_RTOIE |
@@ -1206,7 +1212,7 @@ static struct uart_driver tegra_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "tegra_hsuart",
.dev_name = "ttyTHS",
- .cons = 0,
+ .cons = NULL,
.nr = TEGRA_UART_MAXIMUM,
};
@@ -1237,13 +1243,13 @@ static int tegra_uart_parse_dt(struct platform_device *pdev,
return 0;
}
-struct tegra_uart_chip_data tegra20_uart_chip_data = {
+static struct tegra_uart_chip_data tegra20_uart_chip_data = {
.tx_fifo_full_status = false,
.allow_txfifo_reset_fifo_mode = true,
.support_clk_src_div = false,
};
-struct tegra_uart_chip_data tegra30_uart_chip_data = {
+static struct tegra_uart_chip_data tegra30_uart_chip_data = {
.tx_fifo_full_status = true,
.allow_txfifo_reset_fifo_mode = false,
.support_clk_src_div = true,
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 28cdd282913..0f02351c923 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2095,12 +2095,12 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
break;
}
- printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
+ printk(KERN_INFO "%s%s%s%d at %s (irq = %d, base_baud = %d) is a %s\n",
port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
drv->dev_name,
drv->tty_driver->name_base + port->line,
- address, port->irq, uart_type(port));
+ address, port->irq, port->uartclk / 16, uart_type(port));
}
static void
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index fe48a0c2b4c..440a962412d 100644
--- a/drivers/tty/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
@@ -1097,7 +1097,7 @@ static void serial_txx9_unregister_port(int line)
*/
static int serial_txx9_probe(struct platform_device *dev)
{
- struct uart_port *p = dev->dev.platform_data;
+ struct uart_port *p = dev_get_platdata(&dev->dev);
struct uart_port port;
int ret, i;
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 7477e0ea5cd..537750261aa 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2380,7 +2380,7 @@ static char early_serial_buf[32];
static int sci_probe_earlyprintk(struct platform_device *pdev)
{
- struct plat_sci_port *cfg = pdev->dev.platform_data;
+ struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev);
if (early_serial_console.data)
return -EEXIST;
@@ -2469,7 +2469,7 @@ static int sci_probe_single(struct platform_device *dev,
static int sci_probe(struct platform_device *dev)
{
- struct plat_sci_port *p = dev->dev.platform_data;
+ struct plat_sci_port *p = dev_get_platdata(&dev->dev);
struct sci_port *sp = &sci_ports[dev->id];
int ret;
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 1fd564b8194..61c1ad03db5 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -20,9 +20,13 @@
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/of_gpio.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+#include <linux/sirfsoc_dma.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
-#include <linux/pinctrl/consumer.h>
#include "sirfsoc_uart.h"
@@ -32,6 +36,9 @@ static unsigned int
sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count);
static struct uart_driver sirfsoc_uart_drv;
+static void sirfsoc_uart_tx_dma_complete_callback(void *param);
+static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port);
+static void sirfsoc_uart_rx_dma_complete_callback(void *param);
static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
{4000000, 2359296},
{3500000, 1310721},
@@ -89,6 +96,13 @@ static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = {
.line = 4,
},
},
+ [5] = {
+ .port = {
+ .iotype = UPIO_MEM,
+ .flags = UPF_BOOT_AUTOCONF,
+ .line = 5,
+ },
+ },
};
static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
@@ -99,21 +113,28 @@ static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port)
{
unsigned long reg;
- reg = rd_regl(port, SIRFUART_TX_FIFO_STATUS);
- if (reg & SIRFUART_FIFOEMPTY_MASK(port))
- return TIOCSER_TEMT;
- else
- return 0;
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
+ reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status);
+
+ return (reg & ufifo_st->ff_empty(port->line)) ? TIOCSER_TEMT : 0;
}
static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- if (!(sirfport->ms_enabled)) {
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
goto cts_asserted;
- } else if (sirfport->hw_flow_ctrl) {
- if (!(rd_regl(port, SIRFUART_AFC_CTRL) &
- SIRFUART_CTS_IN_STATUS))
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+ if (!(rd_regl(port, ureg->sirfsoc_afc_ctrl) &
+ SIRFUART_AFC_CTS_STATUS))
+ goto cts_asserted;
+ else
+ goto cts_deasserted;
+ } else {
+ if (!gpio_get_value(sirfport->cts_gpio))
goto cts_asserted;
else
goto cts_deasserted;
@@ -127,89 +148,276 @@ cts_asserted:
static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
unsigned int assert = mctrl & TIOCM_RTS;
unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
unsigned int current_val;
- if (sirfport->hw_flow_ctrl) {
- current_val = rd_regl(port, SIRFUART_AFC_CTRL) & ~0xFF;
+
+ if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
+ return;
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+ current_val = rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0xFF;
val |= current_val;
- wr_regl(port, SIRFUART_AFC_CTRL, val);
+ wr_regl(port, ureg->sirfsoc_afc_ctrl, val);
+ } else {
+ if (!val)
+ gpio_set_value(sirfport->rts_gpio, 1);
+ else
+ gpio_set_value(sirfport->rts_gpio, 0);
}
}
static void sirfsoc_uart_stop_tx(struct uart_port *port)
{
- unsigned int regv;
- regv = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_TX_INT_EN);
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+
+ if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
+ if (sirfport->tx_dma_state == TX_DMA_RUNNING) {
+ dmaengine_pause(sirfport->tx_dma_chan);
+ sirfport->tx_dma_state = TX_DMA_PAUSE;
+ } else {
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg) &
+ ~uint_en->sirfsoc_txfifo_empty_en);
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR,
+ uint_en->sirfsoc_txfifo_empty_en);
+ }
+ } else {
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg) &
+ ~uint_en->sirfsoc_txfifo_empty_en);
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR,
+ uint_en->sirfsoc_txfifo_empty_en);
+ }
}
-void sirfsoc_uart_start_tx(struct uart_port *port)
+static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
+{
+ struct uart_port *port = &sirfport->port;
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned long tran_size;
+ unsigned long tran_start;
+ unsigned long pio_tx_size;
+
+ tran_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ tran_start = (unsigned long)(xmit->buf + xmit->tail);
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port) ||
+ !tran_size)
+ return;
+ if (sirfport->tx_dma_state == TX_DMA_PAUSE) {
+ dmaengine_resume(sirfport->tx_dma_chan);
+ return;
+ }
+ if (sirfport->tx_dma_state == TX_DMA_RUNNING)
+ return;
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)&
+ ~(uint_en->sirfsoc_txfifo_empty_en));
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR,
+ uint_en->sirfsoc_txfifo_empty_en);
+ /*
+ * DMA requires buffer address and buffer length are both aligned with
+ * 4 bytes, so we use PIO for
+ * 1. if address is not aligned with 4bytes, use PIO for the first 1~3
+ * bytes, and move to DMA for the left part aligned with 4bytes
+ * 2. if buffer length is not aligned with 4bytes, use DMA for aligned
+ * part first, move to PIO for the left 1~3 bytes
+ */
+ if (tran_size < 4 || BYTES_TO_ALIGN(tran_start)) {
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
+ wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)|
+ SIRFUART_IO_MODE);
+ if (BYTES_TO_ALIGN(tran_start)) {
+ pio_tx_size = sirfsoc_uart_pio_tx_chars(sirfport,
+ BYTES_TO_ALIGN(tran_start));
+ tran_size -= pio_tx_size;
+ }
+ if (tran_size < 4)
+ sirfsoc_uart_pio_tx_chars(sirfport, tran_size);
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)|
+ uint_en->sirfsoc_txfifo_empty_en);
+ else
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ uint_en->sirfsoc_txfifo_empty_en);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
+ } else {
+ /* tx transfer mode switch into dma mode */
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
+ wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)&
+ ~SIRFUART_IO_MODE);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
+ tran_size &= ~(0x3);
+
+ sirfport->tx_dma_addr = dma_map_single(port->dev,
+ xmit->buf + xmit->tail,
+ tran_size, DMA_TO_DEVICE);
+ sirfport->tx_dma_desc = dmaengine_prep_slave_single(
+ sirfport->tx_dma_chan, sirfport->tx_dma_addr,
+ tran_size, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+ if (!sirfport->tx_dma_desc) {
+ dev_err(port->dev, "DMA prep slave single fail\n");
+ return;
+ }
+ sirfport->tx_dma_desc->callback =
+ sirfsoc_uart_tx_dma_complete_callback;
+ sirfport->tx_dma_desc->callback_param = (void *)sirfport;
+ sirfport->transfer_size = tran_size;
+
+ dmaengine_submit(sirfport->tx_dma_desc);
+ dma_async_issue_pending(sirfport->tx_dma_chan);
+ sirfport->tx_dma_state = TX_DMA_RUNNING;
+ }
+}
+
+static void sirfsoc_uart_start_tx(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- unsigned long regv;
- sirfsoc_uart_pio_tx_chars(sirfport, 1);
- wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_START);
- regv = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_TX_INT_EN);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+ if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
+ sirfsoc_uart_tx_with_dma(sirfport);
+ else {
+ sirfsoc_uart_pio_tx_chars(sirfport, 1);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)|
+ uint_en->sirfsoc_txfifo_empty_en);
+ else
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ uint_en->sirfsoc_txfifo_empty_en);
+ }
}
static void sirfsoc_uart_stop_rx(struct uart_port *port)
{
- unsigned long regv;
- wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
- regv = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_RX_IO_INT_EN);
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
+ if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg) &
+ ~(SIRFUART_RX_DMA_INT_EN(port, uint_en) |
+ uint_en->sirfsoc_rx_done_en));
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR,
+ SIRFUART_RX_DMA_INT_EN(port, uint_en)|
+ uint_en->sirfsoc_rx_done_en);
+ dmaengine_terminate_all(sirfport->rx_dma_chan);
+ } else {
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)&
+ ~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR,
+ SIRFUART_RX_IO_INT_EN(port, uint_en));
+ }
}
static void sirfsoc_uart_disable_ms(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- unsigned long reg;
- sirfport->ms_enabled = 0;
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+
if (!sirfport->hw_flow_ctrl)
return;
- reg = rd_regl(port, SIRFUART_AFC_CTRL);
- wr_regl(port, SIRFUART_AFC_CTRL, reg & ~0x3FF);
- reg = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, reg & ~SIRFUART_CTS_INT_EN);
+ sirfport->ms_enabled = false;
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+ wr_regl(port, ureg->sirfsoc_afc_ctrl,
+ rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF);
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)&
+ ~uint_en->sirfsoc_cts_en);
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR,
+ uint_en->sirfsoc_cts_en);
+ } else
+ disable_irq(gpio_to_irq(sirfport->cts_gpio));
+}
+
+static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)
+{
+ struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
+ struct uart_port *port = &sirfport->port;
+ if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)
+ uart_handle_cts_change(port,
+ !gpio_get_value(sirfport->cts_gpio));
+ return IRQ_HANDLED;
}
static void sirfsoc_uart_enable_ms(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- unsigned long reg;
- unsigned long flg;
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+
if (!sirfport->hw_flow_ctrl)
return;
- flg = SIRFUART_AFC_RX_EN | SIRFUART_AFC_TX_EN;
- reg = rd_regl(port, SIRFUART_AFC_CTRL);
- wr_regl(port, SIRFUART_AFC_CTRL, reg | flg);
- reg = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, reg | SIRFUART_CTS_INT_EN);
- uart_handle_cts_change(port,
- !(rd_regl(port, SIRFUART_AFC_CTRL) & SIRFUART_CTS_IN_STATUS));
- sirfport->ms_enabled = 1;
+ sirfport->ms_enabled = true;
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+ wr_regl(port, ureg->sirfsoc_afc_ctrl,
+ rd_regl(port, ureg->sirfsoc_afc_ctrl) |
+ SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN);
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)
+ | uint_en->sirfsoc_cts_en);
+ else
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ uint_en->sirfsoc_cts_en);
+ } else
+ enable_irq(gpio_to_irq(sirfport->cts_gpio));
}
static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state)
{
- unsigned long ulcon = rd_regl(port, SIRFUART_LINE_CTRL);
- if (break_state)
- ulcon |= SIRFUART_SET_BREAK;
- else
- ulcon &= ~SIRFUART_SET_BREAK;
- wr_regl(port, SIRFUART_LINE_CTRL, ulcon);
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+ unsigned long ulcon = rd_regl(port, ureg->sirfsoc_line_ctrl);
+ if (break_state)
+ ulcon |= SIRFUART_SET_BREAK;
+ else
+ ulcon &= ~SIRFUART_SET_BREAK;
+ wr_regl(port, ureg->sirfsoc_line_ctrl, ulcon);
+ }
}
static unsigned int
sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
unsigned int ch, rx_count = 0;
-
- while (!(rd_regl(port, SIRFUART_RX_FIFO_STATUS) &
- SIRFUART_FIFOEMPTY_MASK(port))) {
- ch = rd_regl(port, SIRFUART_RX_FIFO_DATA) | SIRFUART_DUMMY_READ;
+ struct tty_struct *tty;
+ tty = tty_port_tty_get(&port->state->port);
+ if (!tty)
+ return -ENODEV;
+ while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
+ ufifo_st->ff_empty(port->line))) {
+ ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) |
+ SIRFUART_DUMMY_READ;
if (unlikely(uart_handle_sysrq_char(port, ch)))
continue;
uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
@@ -218,8 +426,12 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
break;
}
+ sirfport->rx_io_count += rx_count;
port->icount.rx += rx_count;
+
+ spin_unlock(&port->lock);
tty_flip_buffer_push(&port->state->port);
+ spin_lock(&port->lock);
return rx_count;
}
@@ -228,13 +440,16 @@ static unsigned int
sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
{
struct uart_port *port = &sirfport->port;
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
struct circ_buf *xmit = &port->state->xmit;
unsigned int num_tx = 0;
while (!uart_circ_empty(xmit) &&
- !(rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
- SIRFUART_FIFOFULL_MASK(port)) &&
+ !(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
+ ufifo_st->ff_full(port->line)) &&
count--) {
- wr_regl(port, SIRFUART_TX_FIFO_DATA, xmit->buf[xmit->tail]);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_data,
+ xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
num_tx++;
@@ -244,6 +459,166 @@ sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
return num_tx;
}
+static void sirfsoc_uart_tx_dma_complete_callback(void *param)
+{
+ struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
+ struct uart_port *port = &sirfport->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned long flags;
+
+ xmit->tail = (xmit->tail + sirfport->transfer_size) &
+ (UART_XMIT_SIZE - 1);
+ port->icount.tx += sirfport->transfer_size;
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+ if (sirfport->tx_dma_addr)
+ dma_unmap_single(port->dev, sirfport->tx_dma_addr,
+ sirfport->transfer_size, DMA_TO_DEVICE);
+ spin_lock_irqsave(&sirfport->tx_lock, flags);
+ sirfport->tx_dma_state = TX_DMA_IDLE;
+ sirfsoc_uart_tx_with_dma(sirfport);
+ spin_unlock_irqrestore(&sirfport->tx_lock, flags);
+}
+
+static void sirfsoc_uart_insert_rx_buf_to_tty(
+ struct sirfsoc_uart_port *sirfport, int count)
+{
+ struct uart_port *port = &sirfport->port;
+ struct tty_port *tport = &port->state->port;
+ int inserted;
+
+ inserted = tty_insert_flip_string(tport,
+ sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
+ port->icount.rx += inserted;
+ tty_flip_buffer_push(tport);
+}
+
+static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+
+ sirfport->rx_dma_items[index].xmit.tail =
+ sirfport->rx_dma_items[index].xmit.head = 0;
+ sirfport->rx_dma_items[index].desc =
+ dmaengine_prep_slave_single(sirfport->rx_dma_chan,
+ sirfport->rx_dma_items[index].dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+ if (!sirfport->rx_dma_items[index].desc) {
+ dev_err(port->dev, "DMA slave single fail\n");
+ return;
+ }
+ sirfport->rx_dma_items[index].desc->callback =
+ sirfsoc_uart_rx_dma_complete_callback;
+ sirfport->rx_dma_items[index].desc->callback_param = sirfport;
+ sirfport->rx_dma_items[index].cookie =
+ dmaengine_submit(sirfport->rx_dma_items[index].desc);
+ dma_async_issue_pending(sirfport->rx_dma_chan);
+}
+
+static void sirfsoc_rx_tmo_process_tl(unsigned long param)
+{
+ struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
+ struct uart_port *port = &sirfport->port;
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+ struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
+ unsigned int count;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sirfport->rx_lock, flags);
+ while (sirfport->rx_completed != sirfport->rx_issued) {
+ sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
+ SIRFSOC_RX_DMA_BUF_SIZE);
+ sirfsoc_rx_submit_one_dma_desc(port, sirfport->rx_completed++);
+ sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
+ }
+ count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head,
+ sirfport->rx_dma_items[sirfport->rx_issued].xmit.tail,
+ SIRFSOC_RX_DMA_BUF_SIZE);
+ if (count > 0)
+ sirfsoc_uart_insert_rx_buf_to_tty(sirfport, count);
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
+ SIRFUART_IO_MODE);
+ sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
+ spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+ if (sirfport->rx_io_count == 4) {
+ spin_lock_irqsave(&sirfport->rx_lock, flags);
+ sirfport->rx_io_count = 0;
+ wr_regl(port, ureg->sirfsoc_int_st_reg,
+ uint_st->sirfsoc_rx_done);
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg) &
+ ~(uint_en->sirfsoc_rx_done_en));
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR,
+ uint_en->sirfsoc_rx_done_en);
+ spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+
+ sirfsoc_uart_start_next_rx_dma(port);
+ } else {
+ spin_lock_irqsave(&sirfport->rx_lock, flags);
+ wr_regl(port, ureg->sirfsoc_int_st_reg,
+ uint_st->sirfsoc_rx_done);
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg) |
+ (uint_en->sirfsoc_rx_done_en));
+ else
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ uint_en->sirfsoc_rx_done_en);
+ spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+ }
+}
+
+static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
+{
+ struct uart_port *port = &sirfport->port;
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+ struct dma_tx_state tx_state;
+ spin_lock(&sirfport->rx_lock);
+
+ dmaengine_tx_status(sirfport->rx_dma_chan,
+ sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
+ dmaengine_terminate_all(sirfport->rx_dma_chan);
+ sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
+ SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg) &
+ ~(uint_en->sirfsoc_rx_timeout_en));
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR,
+ uint_en->sirfsoc_rx_timeout_en);
+ spin_unlock(&sirfport->rx_lock);
+ tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
+}
+
+static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport)
+{
+ struct uart_port *port = &sirfport->port;
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+ struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
+
+ sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
+ if (sirfport->rx_io_count == 4) {
+ sirfport->rx_io_count = 0;
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg) &
+ ~(uint_en->sirfsoc_rx_done_en));
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR,
+ uint_en->sirfsoc_rx_done_en);
+ wr_regl(port, ureg->sirfsoc_int_st_reg,
+ uint_st->sirfsoc_rx_timeout);
+ sirfsoc_uart_start_next_rx_dma(port);
+ }
+}
+
static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
{
unsigned long intr_status;
@@ -251,79 +626,191 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
unsigned long flag = TTY_NORMAL;
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
struct uart_port *port = &sirfport->port;
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
+ struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
struct uart_state *state = port->state;
struct circ_buf *xmit = &port->state->xmit;
spin_lock(&port->lock);
- intr_status = rd_regl(port, SIRFUART_INT_STATUS);
- wr_regl(port, SIRFUART_INT_STATUS, intr_status);
- intr_status &= rd_regl(port, SIRFUART_INT_EN);
- if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT))) {
- if (intr_status & SIRFUART_RXD_BREAK) {
+ intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
+ wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
+ intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg);
+ if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(port, uint_st)))) {
+ if (intr_status & uint_st->sirfsoc_rxd_brk) {
+ port->icount.brk++;
if (uart_handle_break(port))
goto recv_char;
- uart_insert_char(port, intr_status,
- SIRFUART_RX_OFLOW, 0, TTY_BREAK);
- spin_unlock(&port->lock);
- return IRQ_HANDLED;
}
- if (intr_status & SIRFUART_RX_OFLOW)
+ if (intr_status & uint_st->sirfsoc_rx_oflow)
port->icount.overrun++;
- if (intr_status & SIRFUART_FRM_ERR) {
+ if (intr_status & uint_st->sirfsoc_frm_err) {
port->icount.frame++;
flag = TTY_FRAME;
}
- if (intr_status & SIRFUART_PARITY_ERR)
+ if (intr_status & uint_st->sirfsoc_parity_err)
flag = TTY_PARITY;
- wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
- wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
- wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
intr_status &= port->read_status_mask;
uart_insert_char(port, intr_status,
- SIRFUART_RX_OFLOW_INT, 0, flag);
+ uint_en->sirfsoc_rx_oflow_en, 0, flag);
+ tty_flip_buffer_push(&state->port);
}
recv_char:
- if (intr_status & SIRFUART_CTS_INT_EN) {
- cts_status = !(rd_regl(port, SIRFUART_AFC_CTRL) &
- SIRFUART_CTS_IN_STATUS);
- if (cts_status != 0) {
- uart_handle_cts_change(port, 1);
- } else {
- uart_handle_cts_change(port, 0);
- wake_up_interruptible(&state->port.delta_msr_wait);
- }
+ if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
+ (intr_status & SIRFUART_CTS_INT_ST(uint_st)) &&
+ !sirfport->tx_dma_state) {
+ cts_status = rd_regl(port, ureg->sirfsoc_afc_ctrl) &
+ SIRFUART_AFC_CTS_STATUS;
+ if (cts_status != 0)
+ cts_status = 0;
+ else
+ cts_status = 1;
+ uart_handle_cts_change(port, cts_status);
+ wake_up_interruptible(&state->port.delta_msr_wait);
}
- if (intr_status & SIRFUART_RX_IO_INT_EN)
- sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT);
- if (intr_status & SIRFUART_TX_INT_EN) {
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- spin_unlock(&port->lock);
- return IRQ_HANDLED;
- } else {
- sirfsoc_uart_pio_tx_chars(sirfport,
+ if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
+ if (intr_status & uint_st->sirfsoc_rx_timeout)
+ sirfsoc_uart_handle_rx_tmo(sirfport);
+ if (intr_status & uint_st->sirfsoc_rx_done)
+ sirfsoc_uart_handle_rx_done(sirfport);
+ } else {
+ if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))
+ sirfsoc_uart_pio_rx_chars(port,
+ SIRFSOC_UART_IO_RX_MAX_CNT);
+ }
+ if (intr_status & uint_st->sirfsoc_txfifo_empty) {
+ if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
+ sirfsoc_uart_tx_with_dma(sirfport);
+ else {
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ spin_unlock(&port->lock);
+ return IRQ_HANDLED;
+ } else {
+ sirfsoc_uart_pio_tx_chars(sirfport,
SIRFSOC_UART_IO_TX_REASONABLE_CNT);
- if ((uart_circ_empty(xmit)) &&
- (rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
- SIRFUART_FIFOEMPTY_MASK(port)))
- sirfsoc_uart_stop_tx(port);
+ if ((uart_circ_empty(xmit)) &&
+ (rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
+ ufifo_st->ff_empty(port->line)))
+ sirfsoc_uart_stop_tx(port);
+ }
}
}
spin_unlock(&port->lock);
return IRQ_HANDLED;
}
+static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
+{
+ struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
+ struct uart_port *port = &sirfport->port;
+ unsigned long flags;
+ spin_lock_irqsave(&sirfport->rx_lock, flags);
+ while (sirfport->rx_completed != sirfport->rx_issued) {
+ sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
+ SIRFSOC_RX_DMA_BUF_SIZE);
+ sirfsoc_rx_submit_one_dma_desc(port, sirfport->rx_completed++);
+ sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
+ }
+ spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+}
+
+static void sirfsoc_uart_rx_dma_complete_callback(void *param)
+{
+ struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
+ spin_lock(&sirfport->rx_lock);
+ sirfport->rx_issued++;
+ sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
+ spin_unlock(&sirfport->rx_lock);
+ tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
+}
+
+/* submit rx dma task into dmaengine */
+static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+ unsigned long flags;
+ int i;
+ spin_lock_irqsave(&sirfport->rx_lock, flags);
+ sirfport->rx_io_count = 0;
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
+ ~SIRFUART_IO_MODE);
+ spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+ for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
+ sirfsoc_rx_submit_one_dma_desc(port, i);
+ sirfport->rx_completed = sirfport->rx_issued = 0;
+ spin_lock_irqsave(&sirfport->rx_lock, flags);
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg) |
+ SIRFUART_RX_DMA_INT_EN(port, uint_en));
+ else
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ SIRFUART_RX_DMA_INT_EN(port, uint_en));
+ spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+}
+
static void sirfsoc_uart_start_rx(struct uart_port *port)
{
- unsigned long regv;
- regv = rd_regl(port, SIRFUART_INT_EN);
- wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_RX_IO_INT_EN);
- wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
- wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
- wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+
+ sirfport->rx_io_count = 0;
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
+ if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
+ sirfsoc_uart_start_next_rx_dma(port);
+ else {
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg) |
+ SIRFUART_RX_IO_INT_EN(port, uint_en));
+ else
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ SIRFUART_RX_IO_INT_EN(port, uint_en));
+ }
+}
+
+static unsigned int
+sirfsoc_usp_calc_sample_div(unsigned long set_rate,
+ unsigned long ioclk_rate, unsigned long *sample_reg)
+{
+ unsigned long min_delta = ~0UL;
+ unsigned short sample_div;
+ unsigned long ioclk_div = 0;
+ unsigned long temp_delta;
+
+ for (sample_div = SIRF_MIN_SAMPLE_DIV;
+ sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
+ temp_delta = ioclk_rate -
+ (ioclk_rate + (set_rate * sample_div) / 2)
+ / (set_rate * sample_div) * set_rate * sample_div;
+
+ temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
+ if (temp_delta < min_delta) {
+ ioclk_div = (2 * ioclk_rate /
+ (set_rate * sample_div) + 1) / 2 - 1;
+ if (ioclk_div > SIRF_IOCLK_DIV_MAX)
+ continue;
+ min_delta = temp_delta;
+ *sample_reg = sample_div;
+ if (!temp_delta)
+ break;
+ }
+ }
+ return ioclk_div;
}
static unsigned int
-sirfsoc_calc_sample_div(unsigned long baud_rate,
- unsigned long ioclk_rate, unsigned long *setted_baud)
+sirfsoc_uart_calc_sample_div(unsigned long baud_rate,
+ unsigned long ioclk_rate, unsigned long *set_baud)
{
unsigned long min_delta = ~0UL;
unsigned short sample_div;
@@ -346,7 +833,7 @@ sirfsoc_calc_sample_div(unsigned long baud_rate,
regv = regv & (~SIRF_SAMPLE_DIV_MASK);
regv = regv | (sample_div << SIRF_SAMPLE_DIV_SHIFT);
min_delta = temp_delta;
- *setted_baud = baud_tmp;
+ *set_baud = baud_tmp;
}
}
return regv;
@@ -357,63 +844,93 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
struct ktermios *old)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
unsigned long config_reg = 0;
unsigned long baud_rate;
- unsigned long setted_baud;
+ unsigned long set_baud;
unsigned long flags;
unsigned long ic;
unsigned int clk_div_reg = 0;
- unsigned long temp_reg_val;
+ unsigned long txfifo_op_reg, ioclk_rate;
unsigned long rx_time_out;
int threshold_div;
- int temp;
+ u32 data_bit_len, stop_bit_len, len_val;
+ unsigned long sample_div_reg = 0xf;
+ ioclk_rate = port->uartclk;
switch (termios->c_cflag & CSIZE) {
default:
case CS8:
+ data_bit_len = 8;
config_reg |= SIRFUART_DATA_BIT_LEN_8;
break;
case CS7:
+ data_bit_len = 7;
config_reg |= SIRFUART_DATA_BIT_LEN_7;
break;
case CS6:
+ data_bit_len = 6;
config_reg |= SIRFUART_DATA_BIT_LEN_6;
break;
case CS5:
+ data_bit_len = 5;
config_reg |= SIRFUART_DATA_BIT_LEN_5;
break;
}
- if (termios->c_cflag & CSTOPB)
+ if (termios->c_cflag & CSTOPB) {
config_reg |= SIRFUART_STOP_BIT_LEN_2;
- baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
+ stop_bit_len = 2;
+ } else
+ stop_bit_len = 1;
+
spin_lock_irqsave(&port->lock, flags);
- port->read_status_mask = SIRFUART_RX_OFLOW_INT;
+ port->read_status_mask = uint_en->sirfsoc_rx_oflow_en;
port->ignore_status_mask = 0;
- /* read flags */
- if (termios->c_iflag & INPCK)
- port->read_status_mask |=
- SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= uint_en->sirfsoc_frm_err_en |
+ uint_en->sirfsoc_parity_err_en;
+ } else {
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= uint_en->sirfsoc_frm_err_en;
+ }
if (termios->c_iflag & (BRKINT | PARMRK))
- port->read_status_mask |= SIRFUART_RXD_BREAK_INT;
- /* ignore flags */
- if (termios->c_iflag & IGNPAR)
+ port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en;
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |=
+ uint_en->sirfsoc_frm_err_en |
+ uint_en->sirfsoc_parity_err_en;
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & CMSPAR) {
+ if (termios->c_cflag & PARODD)
+ config_reg |= SIRFUART_STICK_BIT_MARK;
+ else
+ config_reg |= SIRFUART_STICK_BIT_SPACE;
+ } else if (termios->c_cflag & PARODD) {
+ config_reg |= SIRFUART_STICK_BIT_ODD;
+ } else {
+ config_reg |= SIRFUART_STICK_BIT_EVEN;
+ }
+ }
+ } else {
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |=
+ uint_en->sirfsoc_frm_err_en;
+ if (termios->c_cflag & PARENB)
+ dev_warn(port->dev,
+ "USP-UART not support parity err\n");
+ }
+ if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |=
- SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
+ uint_en->sirfsoc_rxd_brk_en;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |=
+ uint_en->sirfsoc_rx_oflow_en;
+ }
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= SIRFUART_DUMMY_READ;
- /* enable parity if PARENB is set*/
- if (termios->c_cflag & PARENB) {
- if (termios->c_cflag & CMSPAR) {
- if (termios->c_cflag & PARODD)
- config_reg |= SIRFUART_STICK_BIT_MARK;
- else
- config_reg |= SIRFUART_STICK_BIT_SPACE;
- } else if (termios->c_cflag & PARODD) {
- config_reg |= SIRFUART_STICK_BIT_ODD;
- } else {
- config_reg |= SIRFUART_STICK_BIT_EVEN;
- }
- }
/* Hardware Flow Control Settings */
if (UART_ENABLE_MS(port, termios->c_cflag)) {
if (!sirfport->ms_enabled)
@@ -422,75 +939,184 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
if (sirfport->ms_enabled)
sirfsoc_uart_disable_ms(port);
}
-
- if (port->uartclk == 150000000) {
- /* common rate: fast calculation */
+ baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
+ if (ioclk_rate == 150000000) {
for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
if (baud_rate == baudrate_to_regv[ic].baud_rate)
clk_div_reg = baudrate_to_regv[ic].reg_val;
}
-
- setted_baud = baud_rate;
- /* arbitary rate setting */
- if (unlikely(clk_div_reg == 0))
- clk_div_reg = sirfsoc_calc_sample_div(baud_rate, port->uartclk,
- &setted_baud);
- wr_regl(port, SIRFUART_DIVISOR, clk_div_reg);
-
+ set_baud = baud_rate;
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+ if (unlikely(clk_div_reg == 0))
+ clk_div_reg = sirfsoc_uart_calc_sample_div(baud_rate,
+ ioclk_rate, &set_baud);
+ wr_regl(port, ureg->sirfsoc_divisor, clk_div_reg);
+ } else {
+ clk_div_reg = sirfsoc_usp_calc_sample_div(baud_rate,
+ ioclk_rate, &sample_div_reg);
+ sample_div_reg--;
+ set_baud = ((ioclk_rate / (clk_div_reg+1) - 1) /
+ (sample_div_reg + 1));
+ /* setting usp mode 2 */
+ len_val = ((1 << SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET) |
+ (1 << SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET));
+ len_val |= ((clk_div_reg & SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK)
+ << SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET);
+ wr_regl(port, ureg->sirfsoc_mode2, len_val);
+ }
if (tty_termios_baud_rate(termios))
- tty_termios_encode_baud_rate(termios, setted_baud, setted_baud);
-
- /* set receive timeout */
- rx_time_out = SIRFSOC_UART_RX_TIMEOUT(baud_rate, 20000);
- rx_time_out = (rx_time_out > 0xFFFF) ? 0xFFFF : rx_time_out;
- config_reg |= SIRFUART_RECV_TIMEOUT(rx_time_out);
- temp_reg_val = rd_regl(port, SIRFUART_TX_FIFO_OP);
- wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
- wr_regl(port, SIRFUART_TX_FIFO_OP,
- temp_reg_val & ~SIRFUART_TX_FIFO_START);
- wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, SIRFUART_TX_MODE_IO);
- wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, SIRFUART_RX_MODE_IO);
- wr_regl(port, SIRFUART_LINE_CTRL, config_reg);
-
+ tty_termios_encode_baud_rate(termios, set_baud, set_baud);
+ /* set receive timeout && data bits len */
+ rx_time_out = SIRFSOC_UART_RX_TIMEOUT(set_baud, 20000);
+ rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE(rx_time_out);
+ txfifo_op_reg = rd_regl(port, ureg->sirfsoc_tx_fifo_op);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_STOP);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op,
+ (txfifo_op_reg & ~SIRFUART_FIFO_START));
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+ config_reg |= SIRFUART_RECV_TIMEOUT(port, rx_time_out);
+ wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg);
+ } else {
+ /*tx frame ctrl*/
+ len_val = (data_bit_len - 1) << SIRFSOC_USP_TX_DATA_LEN_OFFSET;
+ len_val |= (data_bit_len + 1 + stop_bit_len - 1) <<
+ SIRFSOC_USP_TX_FRAME_LEN_OFFSET;
+ len_val |= ((data_bit_len - 1) <<
+ SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET);
+ len_val |= (((clk_div_reg & 0xc00) >> 10) <<
+ SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET);
+ wr_regl(port, ureg->sirfsoc_tx_frame_ctrl, len_val);
+ /*rx frame ctrl*/
+ len_val = (data_bit_len - 1) << SIRFSOC_USP_RX_DATA_LEN_OFFSET;
+ len_val |= (data_bit_len + 1 + stop_bit_len - 1) <<
+ SIRFSOC_USP_RX_FRAME_LEN_OFFSET;
+ len_val |= (data_bit_len - 1) <<
+ SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET;
+ len_val |= (((clk_div_reg & 0xf000) >> 12) <<
+ SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET);
+ wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val);
+ /*async param*/
+ wr_regl(port, ureg->sirfsoc_async_param_reg,
+ (SIRFUART_RECV_TIMEOUT(port, rx_time_out)) |
+ (sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<
+ SIRFSOC_USP_ASYNC_DIV2_OFFSET);
+ }
+ if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
+ wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE);
+ else
+ wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE);
+ if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE);
+ else
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
/* Reset Rx/Tx FIFO Threshold level for proper baudrate */
- if (baud_rate < 1000000)
+ if (set_baud < 1000000)
threshold_div = 1;
else
threshold_div = 2;
- temp = port->line == 1 ? 16 : 64;
- wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp / threshold_div);
- wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp / threshold_div);
- temp_reg_val |= SIRFUART_TX_FIFO_START;
- wr_regl(port, SIRFUART_TX_FIFO_OP, temp_reg_val);
- uart_update_timeout(port, termios->c_cflag, baud_rate);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl,
+ SIRFUART_FIFO_THD(port) / threshold_div);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl,
+ SIRFUART_FIFO_THD(port) / threshold_div);
+ txfifo_op_reg |= SIRFUART_FIFO_START;
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op, txfifo_op_reg);
+ uart_update_timeout(port, termios->c_cflag, set_baud);
sirfsoc_uart_start_rx(port);
- wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_TX_EN | SIRFUART_RX_EN);
+ wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_TX_EN | SIRFUART_RX_EN);
spin_unlock_irqrestore(&port->lock, flags);
}
-static void startup_uart_controller(struct uart_port *port)
+static unsigned int sirfsoc_uart_init_tx_dma(struct uart_port *port)
{
- unsigned long temp_regv;
- int temp;
- temp_regv = rd_regl(port, SIRFUART_TX_DMA_IO_CTRL);
- wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, temp_regv | SIRFUART_TX_MODE_IO);
- temp_regv = rd_regl(port, SIRFUART_RX_DMA_IO_CTRL);
- wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, temp_regv | SIRFUART_RX_MODE_IO);
- wr_regl(port, SIRFUART_TX_DMA_IO_LEN, 0);
- wr_regl(port, SIRFUART_RX_DMA_IO_LEN, 0);
- wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_RX_EN | SIRFUART_TX_EN);
- wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_RESET);
- wr_regl(port, SIRFUART_TX_FIFO_OP, 0);
- wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
- wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
- temp = port->line == 1 ? 16 : 64;
- wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp);
- wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp);
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ dma_cap_mask_t dma_mask;
+ struct dma_slave_config tx_slv_cfg = {
+ .dst_maxburst = 2,
+ };
+
+ dma_cap_zero(dma_mask);
+ dma_cap_set(DMA_SLAVE, dma_mask);
+ sirfport->tx_dma_chan = dma_request_channel(dma_mask,
+ (dma_filter_fn)sirfsoc_dma_filter_id,
+ (void *)sirfport->tx_dma_no);
+ if (!sirfport->tx_dma_chan) {
+ dev_err(port->dev, "Uart Request Dma Channel Fail %d\n",
+ sirfport->tx_dma_no);
+ return -EPROBE_DEFER;
+ }
+ dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg);
+
+ return 0;
+}
+
+static unsigned int sirfsoc_uart_init_rx_dma(struct uart_port *port)
+{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ dma_cap_mask_t dma_mask;
+ int ret;
+ int i, j;
+ struct dma_slave_config slv_cfg = {
+ .src_maxburst = 2,
+ };
+
+ dma_cap_zero(dma_mask);
+ dma_cap_set(DMA_SLAVE, dma_mask);
+ sirfport->rx_dma_chan = dma_request_channel(dma_mask,
+ (dma_filter_fn)sirfsoc_dma_filter_id,
+ (void *)sirfport->rx_dma_no);
+ if (!sirfport->rx_dma_chan) {
+ dev_err(port->dev, "Uart Request Dma Channel Fail %d\n",
+ sirfport->rx_dma_no);
+ ret = -EPROBE_DEFER;
+ goto request_err;
+ }
+ for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) {
+ sirfport->rx_dma_items[i].xmit.buf =
+ dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL);
+ if (!sirfport->rx_dma_items[i].xmit.buf) {
+ dev_err(port->dev, "Uart alloc bufa failed\n");
+ ret = -ENOMEM;
+ goto alloc_coherent_err;
+ }
+ sirfport->rx_dma_items[i].xmit.head =
+ sirfport->rx_dma_items[i].xmit.tail = 0;
+ }
+ dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg);
+
+ return 0;
+alloc_coherent_err:
+ for (j = 0; j < i; j++)
+ dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ sirfport->rx_dma_items[j].xmit.buf,
+ sirfport->rx_dma_items[j].dma_addr);
+ dma_release_channel(sirfport->rx_dma_chan);
+request_err:
+ return ret;
+}
+
+static void sirfsoc_uart_uninit_tx_dma(struct sirfsoc_uart_port *sirfport)
+{
+ dmaengine_terminate_all(sirfport->tx_dma_chan);
+ dma_release_channel(sirfport->tx_dma_chan);
+}
+
+static void sirfsoc_uart_uninit_rx_dma(struct sirfsoc_uart_port *sirfport)
+{
+ int i;
+ struct uart_port *port = &sirfport->port;
+ dmaengine_terminate_all(sirfport->rx_dma_chan);
+ dma_release_channel(sirfport->rx_dma_chan);
+ for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
+ dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ sirfport->rx_dma_items[i].xmit.buf,
+ sirfport->rx_dma_items[i].dma_addr);
}
static int sirfsoc_uart_startup(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
unsigned int index = port->line;
int ret;
set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
@@ -504,8 +1130,64 @@ static int sirfsoc_uart_startup(struct uart_port *port)
index, port->irq);
goto irq_err;
}
- startup_uart_controller(port);
+
+ /* initial hardware settings */
+ wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) |
+ SIRFUART_IO_MODE);
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
+ SIRFUART_IO_MODE);
+ wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
+ wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
+ if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
+ wr_regl(port, ureg->sirfsoc_mode1,
+ SIRFSOC_USP_ENDIAN_CTRL_LSBF |
+ SIRFSOC_USP_EN);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
+ wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
+ wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port));
+
+ if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
+ ret = sirfsoc_uart_init_rx_dma(port);
+ if (ret)
+ goto init_rx_err;
+ wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk,
+ SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) |
+ SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) |
+ SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b));
+ }
+ if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
+ sirfsoc_uart_init_tx_dma(port);
+ sirfport->tx_dma_state = TX_DMA_IDLE;
+ wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk,
+ SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) |
+ SIRFUART_TX_FIFO_CHK_LC(port->line, 0xe) |
+ SIRFUART_TX_FIFO_CHK_HC(port->line, 0x4));
+ }
+ sirfport->ms_enabled = false;
+ if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
+ sirfport->hw_flow_ctrl) {
+ set_irq_flags(gpio_to_irq(sirfport->cts_gpio),
+ IRQF_VALID | IRQF_NOAUTOEN);
+ ret = request_irq(gpio_to_irq(sirfport->cts_gpio),
+ sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport);
+ if (ret != 0) {
+ dev_err(port->dev, "UART-USP:request gpio irq fail\n");
+ goto init_rx_err;
+ }
+ }
+
enable_irq(port->irq);
+
+ return 0;
+init_rx_err:
+ free_irq(port->irq, sirfport);
irq_err:
return ret;
}
@@ -513,11 +1195,25 @@ irq_err:
static void sirfsoc_uart_shutdown(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- wr_regl(port, SIRFUART_INT_EN, 0);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ if (!sirfport->is_marco)
+ wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
+ else
+ wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
+
free_irq(port->irq, sirfport);
- if (sirfport->ms_enabled) {
+ if (sirfport->ms_enabled)
sirfsoc_uart_disable_ms(port);
- sirfport->ms_enabled = 0;
+ if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
+ sirfport->hw_flow_ctrl) {
+ gpio_set_value(sirfport->rts_gpio, 1);
+ free_irq(gpio_to_irq(sirfport->cts_gpio), sirfport);
+ }
+ if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
+ sirfsoc_uart_uninit_rx_dma(sirfport);
+ if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
+ sirfsoc_uart_uninit_tx_dma(sirfport);
+ sirfport->tx_dma_state = TX_DMA_IDLE;
}
}
@@ -528,9 +1224,11 @@ static const char *sirfsoc_uart_type(struct uart_port *port)
static int sirfsoc_uart_request_port(struct uart_port *port)
{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_uart_param *uart_param = &sirfport->uart_reg->uart_param;
void *ret;
ret = request_mem_region(port->mapbase,
- SIRFUART_MAP_SIZE, SIRFUART_PORT_NAME);
+ SIRFUART_MAP_SIZE, uart_param->port_name);
return ret ? 0 : -EBUSY;
}
@@ -566,32 +1264,45 @@ static struct uart_ops sirfsoc_uart_ops = {
};
#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
-static int __init sirfsoc_uart_console_setup(struct console *co, char *options)
+static int __init
+sirfsoc_uart_console_setup(struct console *co, char *options)
{
unsigned int baud = 115200;
unsigned int bits = 8;
unsigned int parity = 'n';
unsigned int flow = 'n';
struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
-
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
return -EINVAL;
if (!port->mapbase)
return -ENODEV;
+ /* enable usp in mode1 register */
+ if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
+ wr_regl(port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
+ SIRFSOC_USP_ENDIAN_CTRL_LSBF);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
port->cons = co;
+
+ /* default console tx/rx transfer using io mode */
+ sirfport->rx_dma_no = UNVALID_DMA_CHAN;
+ sirfport->tx_dma_no = UNVALID_DMA_CHAN;
return uart_set_options(port, co, baud, parity, bits, flow);
}
static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
{
+ struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+ struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
while (rd_regl(port,
- SIRFUART_TX_FIFO_STATUS) & SIRFUART_FIFOFULL_MASK(port))
+ ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
cpu_relax();
- wr_regb(port, SIRFUART_TX_FIFO_DATA, ch);
+ wr_regb(port, ureg->sirfsoc_tx_fifo_data, ch);
}
static void sirfsoc_uart_console_write(struct console *co, const char *s,
@@ -633,27 +1344,99 @@ static struct uart_driver sirfsoc_uart_drv = {
#endif
};
-int sirfsoc_uart_probe(struct platform_device *pdev)
+static struct of_device_id sirfsoc_uart_ids[] = {
+ { .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
+ { .compatible = "sirf,marco-uart", .data = &sirfsoc_uart},
+ { .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
+ {}
+};
+MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
+
+static int sirfsoc_uart_probe(struct platform_device *pdev)
{
struct sirfsoc_uart_port *sirfport;
struct uart_port *port;
struct resource *res;
int ret;
+ const struct of_device_id *match;
+ match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) {
dev_err(&pdev->dev,
"Unable to find cell-index in uart node.\n");
ret = -EFAULT;
goto err;
}
-
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart"))
+ pdev->id += ((struct sirfsoc_uart_register *)
+ match->data)->uart_param.register_uart_nr;
sirfport = &sirfsoc_uart_ports[pdev->id];
port = &sirfport->port;
port->dev = &pdev->dev;
port->private_data = sirfport;
+ sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data;
+
+ sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,
+ "sirf,uart-has-rtscts");
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) {
+ sirfport->uart_reg->uart_type = SIRF_REAL_UART;
+ if (of_property_read_u32(pdev->dev.of_node,
+ "sirf,uart-dma-rx-channel",
+ &sirfport->rx_dma_no))
+ sirfport->rx_dma_no = UNVALID_DMA_CHAN;
+ if (of_property_read_u32(pdev->dev.of_node,
+ "sirf,uart-dma-tx-channel",
+ &sirfport->tx_dma_no))
+ sirfport->tx_dma_no = UNVALID_DMA_CHAN;
+ }
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) {
+ sirfport->uart_reg->uart_type = SIRF_USP_UART;
+ if (of_property_read_u32(pdev->dev.of_node,
+ "sirf,usp-dma-rx-channel",
+ &sirfport->rx_dma_no))
+ sirfport->rx_dma_no = UNVALID_DMA_CHAN;
+ if (of_property_read_u32(pdev->dev.of_node,
+ "sirf,usp-dma-tx-channel",
+ &sirfport->tx_dma_no))
+ sirfport->tx_dma_no = UNVALID_DMA_CHAN;
+ if (!sirfport->hw_flow_ctrl)
+ goto usp_no_flow_control;
+ if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL))
+ sirfport->cts_gpio = of_get_named_gpio(
+ pdev->dev.of_node, "cts-gpios", 0);
+ else
+ sirfport->cts_gpio = -1;
+ if (of_find_property(pdev->dev.of_node, "rts-gpios", NULL))
+ sirfport->rts_gpio = of_get_named_gpio(
+ pdev->dev.of_node, "rts-gpios", 0);
+ else
+ sirfport->rts_gpio = -1;
- if (of_find_property(pdev->dev.of_node, "hw_flow_ctrl", NULL))
- sirfport->hw_flow_ctrl = 1;
+ if ((!gpio_is_valid(sirfport->cts_gpio) ||
+ !gpio_is_valid(sirfport->rts_gpio))) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev,
+ "Usp flow control must have cts and rts gpio");
+ goto err;
+ }
+ ret = devm_gpio_request(&pdev->dev, sirfport->cts_gpio,
+ "usp-cts-gpio");
+ if (ret) {
+ dev_err(&pdev->dev, "Unable request cts gpio");
+ goto err;
+ }
+ gpio_direction_input(sirfport->cts_gpio);
+ ret = devm_gpio_request(&pdev->dev, sirfport->rts_gpio,
+ "usp-rts-gpio");
+ if (ret) {
+ dev_err(&pdev->dev, "Unable request rts gpio");
+ goto err;
+ }
+ gpio_direction_output(sirfport->rts_gpio, 1);
+ }
+usp_no_flow_control:
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-uart"))
+ sirfport->is_marco = true;
if (of_property_read_u32(pdev->dev.of_node,
"fifosize",
@@ -670,6 +1453,12 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
ret = -EFAULT;
goto err;
}
+ spin_lock_init(&sirfport->rx_lock);
+ spin_lock_init(&sirfport->tx_lock);
+ tasklet_init(&sirfport->rx_dma_complete_tasklet,
+ sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
+ tasklet_init(&sirfport->rx_tmo_process_tasklet,
+ sirfsoc_rx_tmo_process_tl, (unsigned long)sirfport);
port->mapbase = res->start;
port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!port->membase) {
@@ -685,18 +1474,10 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
}
port->irq = res->start;
- if (sirfport->hw_flow_ctrl) {
- sirfport->p = pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(sirfport->p)) {
- ret = PTR_ERR(sirfport->p);
- goto err;
- }
- }
-
sirfport->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(sirfport->clk)) {
ret = PTR_ERR(sirfport->clk);
- goto clk_err;
+ goto err;
}
clk_prepare_enable(sirfport->clk);
port->uartclk = clk_get_rate(sirfport->clk);
@@ -716,10 +1497,6 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
port_err:
clk_disable_unprepare(sirfport->clk);
clk_put(sirfport->clk);
-clk_err:
- platform_set_drvdata(pdev, NULL);
- if (sirfport->hw_flow_ctrl)
- pinctrl_put(sirfport->p);
err:
return ret;
}
@@ -728,9 +1505,6 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
{
struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
struct uart_port *port = &sirfport->port;
- platform_set_drvdata(pdev, NULL);
- if (sirfport->hw_flow_ctrl)
- pinctrl_put(sirfport->p);
clk_disable_unprepare(sirfport->clk);
clk_put(sirfport->clk);
uart_remove_one_port(&sirfsoc_uart_drv, port);
@@ -754,13 +1528,6 @@ static int sirfsoc_uart_resume(struct platform_device *pdev)
return 0;
}
-static struct of_device_id sirfsoc_uart_ids[] = {
- { .compatible = "sirf,prima2-uart", },
- { .compatible = "sirf,marco-uart", },
- {}
-};
-MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
-
static struct platform_driver sirfsoc_uart_driver = {
.probe = sirfsoc_uart_probe,
.remove = sirfsoc_uart_remove,
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
index 85328ba0c4e..fb8d0a00260 100644
--- a/drivers/tty/serial/sirfsoc_uart.h
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -6,31 +6,260 @@
* Licensed under GPLv2 or later.
*/
#include <linux/bitops.h>
+struct sirfsoc_uart_param {
+ const char *uart_name;
+ const char *port_name;
+ u32 uart_nr;
+ u32 register_uart_nr;
+};
+
+struct sirfsoc_register {
+ /* hardware uart specific */
+ u32 sirfsoc_line_ctrl;
+ u32 sirfsoc_divisor;
+ /* uart - usp common */
+ u32 sirfsoc_tx_rx_en;
+ u32 sirfsoc_int_en_reg;
+ u32 sirfsoc_int_st_reg;
+ u32 sirfsoc_tx_dma_io_ctrl;
+ u32 sirfsoc_tx_dma_io_len;
+ u32 sirfsoc_tx_fifo_ctrl;
+ u32 sirfsoc_tx_fifo_level_chk;
+ u32 sirfsoc_tx_fifo_op;
+ u32 sirfsoc_tx_fifo_status;
+ u32 sirfsoc_tx_fifo_data;
+ u32 sirfsoc_rx_dma_io_ctrl;
+ u32 sirfsoc_rx_dma_io_len;
+ u32 sirfsoc_rx_fifo_ctrl;
+ u32 sirfsoc_rx_fifo_level_chk;
+ u32 sirfsoc_rx_fifo_op;
+ u32 sirfsoc_rx_fifo_status;
+ u32 sirfsoc_rx_fifo_data;
+ u32 sirfsoc_afc_ctrl;
+ u32 sirfsoc_swh_dma_io;
+ /* hardware usp specific */
+ u32 sirfsoc_mode1;
+ u32 sirfsoc_mode2;
+ u32 sirfsoc_tx_frame_ctrl;
+ u32 sirfsoc_rx_frame_ctrl;
+ u32 sirfsoc_async_param_reg;
+};
+
+typedef u32 (*fifo_full_mask)(int line);
+typedef u32 (*fifo_empty_mask)(int line);
+
+struct sirfsoc_fifo_status {
+ fifo_full_mask ff_full;
+ fifo_empty_mask ff_empty;
+};
-/* UART Register Offset Define */
-#define SIRFUART_LINE_CTRL 0x0040
-#define SIRFUART_TX_RX_EN 0x004c
-#define SIRFUART_DIVISOR 0x0050
-#define SIRFUART_INT_EN 0x0054
-#define SIRFUART_INT_STATUS 0x0058
-#define SIRFUART_TX_DMA_IO_CTRL 0x0100
-#define SIRFUART_TX_DMA_IO_LEN 0x0104
-#define SIRFUART_TX_FIFO_CTRL 0x0108
-#define SIRFUART_TX_FIFO_LEVEL_CHK 0x010C
-#define SIRFUART_TX_FIFO_OP 0x0110
-#define SIRFUART_TX_FIFO_STATUS 0x0114
-#define SIRFUART_TX_FIFO_DATA 0x0118
-#define SIRFUART_RX_DMA_IO_CTRL 0x0120
-#define SIRFUART_RX_DMA_IO_LEN 0x0124
-#define SIRFUART_RX_FIFO_CTRL 0x0128
-#define SIRFUART_RX_FIFO_LEVEL_CHK 0x012C
-#define SIRFUART_RX_FIFO_OP 0x0130
-#define SIRFUART_RX_FIFO_STATUS 0x0134
-#define SIRFUART_RX_FIFO_DATA 0x0138
-#define SIRFUART_AFC_CTRL 0x0140
-#define SIRFUART_SWH_DMA_IO 0x0148
-
-/* UART Line Control Register */
+struct sirfsoc_int_en {
+ u32 sirfsoc_rx_done_en;
+ u32 sirfsoc_tx_done_en;
+ u32 sirfsoc_rx_oflow_en;
+ u32 sirfsoc_tx_allout_en;
+ u32 sirfsoc_rx_io_dma_en;
+ u32 sirfsoc_tx_io_dma_en;
+ u32 sirfsoc_rxfifo_full_en;
+ u32 sirfsoc_txfifo_empty_en;
+ u32 sirfsoc_rxfifo_thd_en;
+ u32 sirfsoc_txfifo_thd_en;
+ u32 sirfsoc_frm_err_en;
+ u32 sirfsoc_rxd_brk_en;
+ u32 sirfsoc_rx_timeout_en;
+ u32 sirfsoc_parity_err_en;
+ u32 sirfsoc_cts_en;
+ u32 sirfsoc_rts_en;
+};
+
+struct sirfsoc_int_status {
+ u32 sirfsoc_rx_done;
+ u32 sirfsoc_tx_done;
+ u32 sirfsoc_rx_oflow;
+ u32 sirfsoc_tx_allout;
+ u32 sirfsoc_rx_io_dma;
+ u32 sirfsoc_tx_io_dma;
+ u32 sirfsoc_rxfifo_full;
+ u32 sirfsoc_txfifo_empty;
+ u32 sirfsoc_rxfifo_thd;
+ u32 sirfsoc_txfifo_thd;
+ u32 sirfsoc_frm_err;
+ u32 sirfsoc_rxd_brk;
+ u32 sirfsoc_rx_timeout;
+ u32 sirfsoc_parity_err;
+ u32 sirfsoc_cts;
+ u32 sirfsoc_rts;
+};
+
+enum sirfsoc_uart_type {
+ SIRF_REAL_UART,
+ SIRF_USP_UART,
+};
+
+struct sirfsoc_uart_register {
+ struct sirfsoc_register uart_reg;
+ struct sirfsoc_int_en uart_int_en;
+ struct sirfsoc_int_status uart_int_st;
+ struct sirfsoc_fifo_status fifo_status;
+ struct sirfsoc_uart_param uart_param;
+ enum sirfsoc_uart_type uart_type;
+};
+
+u32 usp_ff_full(int line)
+{
+ return 0x80;
+}
+u32 usp_ff_empty(int line)
+{
+ return 0x100;
+}
+u32 uart_ff_full(int line)
+{
+ return (line == 1) ? (0x20) : (0x80);
+}
+u32 uart_ff_empty(int line)
+{
+ return (line == 1) ? (0x40) : (0x100);
+}
+struct sirfsoc_uart_register sirfsoc_usp = {
+ .uart_reg = {
+ .sirfsoc_mode1 = 0x0000,
+ .sirfsoc_mode2 = 0x0004,
+ .sirfsoc_tx_frame_ctrl = 0x0008,
+ .sirfsoc_rx_frame_ctrl = 0x000c,
+ .sirfsoc_tx_rx_en = 0x0010,
+ .sirfsoc_int_en_reg = 0x0014,
+ .sirfsoc_int_st_reg = 0x0018,
+ .sirfsoc_async_param_reg = 0x0024,
+ .sirfsoc_tx_dma_io_ctrl = 0x0100,
+ .sirfsoc_tx_dma_io_len = 0x0104,
+ .sirfsoc_tx_fifo_ctrl = 0x0108,
+ .sirfsoc_tx_fifo_level_chk = 0x010c,
+ .sirfsoc_tx_fifo_op = 0x0110,
+ .sirfsoc_tx_fifo_status = 0x0114,
+ .sirfsoc_tx_fifo_data = 0x0118,
+ .sirfsoc_rx_dma_io_ctrl = 0x0120,
+ .sirfsoc_rx_dma_io_len = 0x0124,
+ .sirfsoc_rx_fifo_ctrl = 0x0128,
+ .sirfsoc_rx_fifo_level_chk = 0x012c,
+ .sirfsoc_rx_fifo_op = 0x0130,
+ .sirfsoc_rx_fifo_status = 0x0134,
+ .sirfsoc_rx_fifo_data = 0x0138,
+ },
+ .uart_int_en = {
+ .sirfsoc_rx_done_en = BIT(0),
+ .sirfsoc_tx_done_en = BIT(1),
+ .sirfsoc_rx_oflow_en = BIT(2),
+ .sirfsoc_tx_allout_en = BIT(3),
+ .sirfsoc_rx_io_dma_en = BIT(4),
+ .sirfsoc_tx_io_dma_en = BIT(5),
+ .sirfsoc_rxfifo_full_en = BIT(6),
+ .sirfsoc_txfifo_empty_en = BIT(7),
+ .sirfsoc_rxfifo_thd_en = BIT(8),
+ .sirfsoc_txfifo_thd_en = BIT(9),
+ .sirfsoc_frm_err_en = BIT(10),
+ .sirfsoc_rx_timeout_en = BIT(11),
+ .sirfsoc_rxd_brk_en = BIT(15),
+ },
+ .uart_int_st = {
+ .sirfsoc_rx_done = BIT(0),
+ .sirfsoc_tx_done = BIT(1),
+ .sirfsoc_rx_oflow = BIT(2),
+ .sirfsoc_tx_allout = BIT(3),
+ .sirfsoc_rx_io_dma = BIT(4),
+ .sirfsoc_tx_io_dma = BIT(5),
+ .sirfsoc_rxfifo_full = BIT(6),
+ .sirfsoc_txfifo_empty = BIT(7),
+ .sirfsoc_rxfifo_thd = BIT(8),
+ .sirfsoc_txfifo_thd = BIT(9),
+ .sirfsoc_frm_err = BIT(10),
+ .sirfsoc_rx_timeout = BIT(11),
+ .sirfsoc_rxd_brk = BIT(15),
+ },
+ .fifo_status = {
+ .ff_full = usp_ff_full,
+ .ff_empty = usp_ff_empty,
+ },
+ .uart_param = {
+ .uart_name = "ttySiRF",
+ .port_name = "sirfsoc-uart",
+ .uart_nr = 2,
+ .register_uart_nr = 3,
+ },
+};
+
+struct sirfsoc_uart_register sirfsoc_uart = {
+ .uart_reg = {
+ .sirfsoc_line_ctrl = 0x0040,
+ .sirfsoc_tx_rx_en = 0x004c,
+ .sirfsoc_divisor = 0x0050,
+ .sirfsoc_int_en_reg = 0x0054,
+ .sirfsoc_int_st_reg = 0x0058,
+ .sirfsoc_tx_dma_io_ctrl = 0x0100,
+ .sirfsoc_tx_dma_io_len = 0x0104,
+ .sirfsoc_tx_fifo_ctrl = 0x0108,
+ .sirfsoc_tx_fifo_level_chk = 0x010c,
+ .sirfsoc_tx_fifo_op = 0x0110,
+ .sirfsoc_tx_fifo_status = 0x0114,
+ .sirfsoc_tx_fifo_data = 0x0118,
+ .sirfsoc_rx_dma_io_ctrl = 0x0120,
+ .sirfsoc_rx_dma_io_len = 0x0124,
+ .sirfsoc_rx_fifo_ctrl = 0x0128,
+ .sirfsoc_rx_fifo_level_chk = 0x012c,
+ .sirfsoc_rx_fifo_op = 0x0130,
+ .sirfsoc_rx_fifo_status = 0x0134,
+ .sirfsoc_rx_fifo_data = 0x0138,
+ .sirfsoc_afc_ctrl = 0x0140,
+ .sirfsoc_swh_dma_io = 0x0148,
+ },
+ .uart_int_en = {
+ .sirfsoc_rx_done_en = BIT(0),
+ .sirfsoc_tx_done_en = BIT(1),
+ .sirfsoc_rx_oflow_en = BIT(2),
+ .sirfsoc_tx_allout_en = BIT(3),
+ .sirfsoc_rx_io_dma_en = BIT(4),
+ .sirfsoc_tx_io_dma_en = BIT(5),
+ .sirfsoc_rxfifo_full_en = BIT(6),
+ .sirfsoc_txfifo_empty_en = BIT(7),
+ .sirfsoc_rxfifo_thd_en = BIT(8),
+ .sirfsoc_txfifo_thd_en = BIT(9),
+ .sirfsoc_frm_err_en = BIT(10),
+ .sirfsoc_rxd_brk_en = BIT(11),
+ .sirfsoc_rx_timeout_en = BIT(12),
+ .sirfsoc_parity_err_en = BIT(13),
+ .sirfsoc_cts_en = BIT(14),
+ .sirfsoc_rts_en = BIT(15),
+ },
+ .uart_int_st = {
+ .sirfsoc_rx_done = BIT(0),
+ .sirfsoc_tx_done = BIT(1),
+ .sirfsoc_rx_oflow = BIT(2),
+ .sirfsoc_tx_allout = BIT(3),
+ .sirfsoc_rx_io_dma = BIT(4),
+ .sirfsoc_tx_io_dma = BIT(5),
+ .sirfsoc_rxfifo_full = BIT(6),
+ .sirfsoc_txfifo_empty = BIT(7),
+ .sirfsoc_rxfifo_thd = BIT(8),
+ .sirfsoc_txfifo_thd = BIT(9),
+ .sirfsoc_frm_err = BIT(10),
+ .sirfsoc_rxd_brk = BIT(11),
+ .sirfsoc_rx_timeout = BIT(12),
+ .sirfsoc_parity_err = BIT(13),
+ .sirfsoc_cts = BIT(14),
+ .sirfsoc_rts = BIT(15),
+ },
+ .fifo_status = {
+ .ff_full = uart_ff_full,
+ .ff_empty = uart_ff_empty,
+ },
+ .uart_param = {
+ .uart_name = "ttySiRF",
+ .port_name = "sirfsoc_uart",
+ .uart_nr = 3,
+ .register_uart_nr = 0,
+ },
+};
+/* uart io ctrl */
#define SIRFUART_DATA_BIT_LEN_MASK 0x3
#define SIRFUART_DATA_BIT_LEN_5 BIT(0)
#define SIRFUART_DATA_BIT_LEN_6 1
@@ -50,96 +279,93 @@
#define SIRFUART_LOOP_BACK BIT(7)
#define SIRFUART_PARITY_MASK (7 << 3)
#define SIRFUART_DUMMY_READ BIT(16)
-
-#define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000)
-#define SIRFUART_RECV_TIMEOUT_MASK (0xFFFF << 16)
-#define SIRFUART_RECV_TIMEOUT(x) (((x) & 0xFFFF) << 16)
-
-/* UART Auto Flow Control */
-#define SIRFUART_AFC_RX_THD_MASK 0x000000FF
+#define SIRFUART_AFC_CTRL_RX_THD 0x70
#define SIRFUART_AFC_RX_EN BIT(8)
#define SIRFUART_AFC_TX_EN BIT(9)
-#define SIRFUART_CTS_CTRL BIT(10)
-#define SIRFUART_RTS_CTRL BIT(11)
-#define SIRFUART_CTS_IN_STATUS BIT(12)
-#define SIRFUART_RTS_OUT_STATUS BIT(13)
-
-/* UART Interrupt Enable Register */
-#define SIRFUART_RX_DONE_INT BIT(0)
-#define SIRFUART_TX_DONE_INT BIT(1)
-#define SIRFUART_RX_OFLOW_INT BIT(2)
-#define SIRFUART_TX_ALLOUT_INT BIT(3)
-#define SIRFUART_RX_IO_DMA_INT BIT(4)
-#define SIRFUART_TX_IO_DMA_INT BIT(5)
-#define SIRFUART_RXFIFO_FULL_INT BIT(6)
-#define SIRFUART_TXFIFO_EMPTY_INT BIT(7)
-#define SIRFUART_RXFIFO_THD_INT BIT(8)
-#define SIRFUART_TXFIFO_THD_INT BIT(9)
-#define SIRFUART_FRM_ERR_INT BIT(10)
-#define SIRFUART_RXD_BREAK_INT BIT(11)
-#define SIRFUART_RX_TIMEOUT_INT BIT(12)
-#define SIRFUART_PARITY_ERR_INT BIT(13)
-#define SIRFUART_CTS_INT_EN BIT(14)
-#define SIRFUART_RTS_INT_EN BIT(15)
-
-/* UART Interrupt Status Register */
-#define SIRFUART_RX_DONE BIT(0)
-#define SIRFUART_TX_DONE BIT(1)
-#define SIRFUART_RX_OFLOW BIT(2)
-#define SIRFUART_TX_ALL_EMPTY BIT(3)
-#define SIRFUART_DMA_IO_RX_DONE BIT(4)
-#define SIRFUART_DMA_IO_TX_DONE BIT(5)
-#define SIRFUART_RXFIFO_FULL BIT(6)
-#define SIRFUART_TXFIFO_EMPTY BIT(7)
-#define SIRFUART_RXFIFO_THD_REACH BIT(8)
-#define SIRFUART_TXFIFO_THD_REACH BIT(9)
-#define SIRFUART_FRM_ERR BIT(10)
-#define SIRFUART_RXD_BREAK BIT(11)
-#define SIRFUART_RX_TIMEOUT BIT(12)
-#define SIRFUART_PARITY_ERR BIT(13)
-#define SIRFUART_CTS_CHANGE BIT(14)
-#define SIRFUART_RTS_CHANGE BIT(15)
-#define SIRFUART_PLUG_IN BIT(16)
-
-#define SIRFUART_ERR_INT_STAT \
- (SIRFUART_RX_OFLOW | \
- SIRFUART_FRM_ERR | \
- SIRFUART_RXD_BREAK | \
- SIRFUART_PARITY_ERR)
-#define SIRFUART_ERR_INT_EN \
- (SIRFUART_RX_OFLOW_INT | \
- SIRFUART_FRM_ERR_INT | \
- SIRFUART_RXD_BREAK_INT | \
- SIRFUART_PARITY_ERR_INT)
-#define SIRFUART_TX_INT_EN SIRFUART_TXFIFO_EMPTY_INT
-#define SIRFUART_RX_IO_INT_EN \
- (SIRFUART_RX_TIMEOUT_INT | \
- SIRFUART_RXFIFO_THD_INT | \
- SIRFUART_RXFIFO_FULL_INT | \
- SIRFUART_ERR_INT_EN)
-
+#define SIRFUART_AFC_CTS_CTRL BIT(10)
+#define SIRFUART_AFC_RTS_CTRL BIT(11)
+#define SIRFUART_AFC_CTS_STATUS BIT(12)
+#define SIRFUART_AFC_RTS_STATUS BIT(13)
/* UART FIFO Register */
-#define SIRFUART_TX_FIFO_STOP 0x0
-#define SIRFUART_TX_FIFO_RESET 0x1
-#define SIRFUART_TX_FIFO_START 0x2
-#define SIRFUART_RX_FIFO_STOP 0x0
-#define SIRFUART_RX_FIFO_RESET 0x1
-#define SIRFUART_RX_FIFO_START 0x2
-#define SIRFUART_TX_MODE_DMA 0
-#define SIRFUART_TX_MODE_IO 1
-#define SIRFUART_RX_MODE_DMA 0
-#define SIRFUART_RX_MODE_IO 1
-
-#define SIRFUART_RX_EN 0x1
-#define SIRFUART_TX_EN 0x2
+#define SIRFUART_FIFO_STOP 0x0
+#define SIRFUART_FIFO_RESET BIT(0)
+#define SIRFUART_FIFO_START BIT(1)
+#define SIRFUART_RX_EN BIT(0)
+#define SIRFUART_TX_EN BIT(1)
+
+#define SIRFUART_IO_MODE BIT(0)
+#define SIRFUART_DMA_MODE 0x0
+
+/* Macro Specific*/
+#define SIRFUART_INT_EN_CLR 0x0060
+/* Baud Rate Calculation */
+#define SIRF_MIN_SAMPLE_DIV 0xf
+#define SIRF_MAX_SAMPLE_DIV 0x3f
+#define SIRF_IOCLK_DIV_MAX 0xffff
+#define SIRF_SAMPLE_DIV_SHIFT 16
+#define SIRF_IOCLK_DIV_MASK 0xffff
+#define SIRF_SAMPLE_DIV_MASK 0x3f0000
+#define SIRF_BAUD_RATE_SUPPORT_NR 18
+
+/* USP SPEC */
+#define SIRFSOC_USP_ENDIAN_CTRL_LSBF BIT(4)
+#define SIRFSOC_USP_EN BIT(5)
+#define SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET 0
+#define SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET 8
+#define SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK 0x3ff
+#define SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET 21
+#define SIRFSOC_USP_TX_DATA_LEN_OFFSET 0
+#define SIRFSOC_USP_TX_SYNC_LEN_OFFSET 8
+#define SIRFSOC_USP_TX_FRAME_LEN_OFFSET 16
+#define SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET 24
+#define SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET 30
+#define SIRFSOC_USP_RX_DATA_LEN_OFFSET 0
+#define SIRFSOC_USP_RX_FRAME_LEN_OFFSET 8
+#define SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET 16
+#define SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET 24
+#define SIRFSOC_USP_ASYNC_DIV2_MASK 0x3f
+#define SIRFSOC_USP_ASYNC_DIV2_OFFSET 16
+
+/* USP-UART Common */
+#define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000)
+#define SIRFUART_RECV_TIMEOUT_VALUE(x) \
+ (((x) > 0xFFFF) ? 0xFFFF : ((x) & 0xFFFF))
+#define SIRFUART_RECV_TIMEOUT(port, x) \
+ (((port)->line > 2) ? (x & 0xFFFF) : ((x) & 0xFFFF) << 16)
+
+#define SIRFUART_FIFO_THD(port) ((port->line) == 1 ? 16 : 64)
+#define SIRFUART_ERR_INT_STAT(port, unit_st) \
+ (uint_st->sirfsoc_rx_oflow | \
+ uint_st->sirfsoc_frm_err | \
+ uint_st->sirfsoc_rxd_brk | \
+ ((port->line > 2) ? 0 : uint_st->sirfsoc_parity_err))
+#define SIRFUART_RX_IO_INT_EN(port, uint_en) \
+ (uint_en->sirfsoc_rx_timeout_en |\
+ uint_en->sirfsoc_rxfifo_thd_en |\
+ uint_en->sirfsoc_rxfifo_full_en |\
+ uint_en->sirfsoc_frm_err_en |\
+ uint_en->sirfsoc_rx_oflow_en |\
+ uint_en->sirfsoc_rxd_brk_en |\
+ ((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en))
+#define SIRFUART_RX_IO_INT_ST(uint_st) \
+ (uint_st->sirfsoc_rx_timeout |\
+ uint_st->sirfsoc_rxfifo_thd |\
+ uint_st->sirfsoc_rxfifo_full)
+#define SIRFUART_CTS_INT_ST(uint_st) (uint_st->sirfsoc_cts)
+#define SIRFUART_RX_DMA_INT_EN(port, uint_en) \
+ (uint_en->sirfsoc_rx_timeout_en |\
+ uint_en->sirfsoc_frm_err_en |\
+ uint_en->sirfsoc_rx_oflow_en |\
+ uint_en->sirfsoc_rxd_brk_en |\
+ ((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en))
/* Generic Definitions */
#define SIRFSOC_UART_NAME "ttySiRF"
#define SIRFSOC_UART_MAJOR 0
#define SIRFSOC_UART_MINOR 0
#define SIRFUART_PORT_NAME "sirfsoc-uart"
#define SIRFUART_MAP_SIZE 0x200
-#define SIRFSOC_UART_NR 5
+#define SIRFSOC_UART_NR 6
#define SIRFSOC_PORT_TYPE 0xa5
/* Baud Rate Calculation */
@@ -151,19 +377,80 @@
#define SIRF_SAMPLE_DIV_MASK 0x3f0000
#define SIRF_BAUD_RATE_SUPPORT_NR 18
+/* Uart Common Use Macro*/
+#define SIRFSOC_RX_DMA_BUF_SIZE 256
+#define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3)
+#define LOOP_DMA_BUFA_FILL 1
+#define LOOP_DMA_BUFB_FILL 2
+#define TX_TRAN_PIO 1
+#define TX_TRAN_DMA 2
+/* Uart Fifo Level Chk */
+#define SIRFUART_TX_FIFO_SC_OFFSET 0
+#define SIRFUART_TX_FIFO_LC_OFFSET 10
+#define SIRFUART_TX_FIFO_HC_OFFSET 20
+#define SIRFUART_TX_FIFO_CHK_SC(line, value) ((((line) == 1) ? (value & 0x3) :\
+ (value & 0x1f)) << SIRFUART_TX_FIFO_SC_OFFSET)
+#define SIRFUART_TX_FIFO_CHK_LC(line, value) ((((line) == 1) ? (value & 0x3) :\
+ (value & 0x1f)) << SIRFUART_TX_FIFO_LC_OFFSET)
+#define SIRFUART_TX_FIFO_CHK_HC(line, value) ((((line) == 1) ? (value & 0x3) :\
+ (value & 0x1f)) << SIRFUART_TX_FIFO_HC_OFFSET)
+
+#define SIRFUART_RX_FIFO_CHK_SC SIRFUART_TX_FIFO_CHK_SC
+#define SIRFUART_RX_FIFO_CHK_LC SIRFUART_TX_FIFO_CHK_LC
+#define SIRFUART_RX_FIFO_CHK_HC SIRFUART_TX_FIFO_CHK_HC
+/* Indicate how many buffers used */
+#define SIRFSOC_RX_LOOP_BUF_CNT 2
+
+/* Indicate if DMA channel valid */
+#define IS_DMA_CHAN_VALID(x) ((x) != -1)
+#define UNVALID_DMA_CHAN -1
/* For Fast Baud Rate Calculation */
struct sirfsoc_baudrate_to_regv {
unsigned int baud_rate;
unsigned int reg_val;
};
+enum sirfsoc_tx_state {
+ TX_DMA_IDLE,
+ TX_DMA_RUNNING,
+ TX_DMA_PAUSE,
+};
+
+struct sirfsoc_loop_buffer {
+ struct circ_buf xmit;
+ dma_cookie_t cookie;
+ struct dma_async_tx_descriptor *desc;
+ dma_addr_t dma_addr;
+};
+
struct sirfsoc_uart_port {
- unsigned char hw_flow_ctrl;
- unsigned char ms_enabled;
+ bool hw_flow_ctrl;
+ bool ms_enabled;
struct uart_port port;
- struct pinctrl *p;
struct clk *clk;
+ /* for SiRFmarco, there are SET/CLR for UART_INT_EN */
+ bool is_marco;
+ struct sirfsoc_uart_register *uart_reg;
+ int rx_dma_no;
+ int tx_dma_no;
+ struct dma_chan *rx_dma_chan;
+ struct dma_chan *tx_dma_chan;
+ dma_addr_t tx_dma_addr;
+ struct dma_async_tx_descriptor *tx_dma_desc;
+ spinlock_t rx_lock;
+ spinlock_t tx_lock;
+ struct tasklet_struct rx_dma_complete_tasklet;
+ struct tasklet_struct rx_tmo_process_tasklet;
+ unsigned int rx_io_count;
+ unsigned long transfer_size;
+ enum sirfsoc_tx_state tx_dma_state;
+ unsigned int cts_gpio;
+ unsigned int rts_gpio;
+
+ struct sirfsoc_loop_buffer rx_dma_items[SIRFSOC_RX_LOOP_BUF_CNT];
+ int rx_completed;
+ int rx_issued;
};
/* Hardware Flow Control */
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
new file mode 100644
index 00000000000..21e6e84c0df
--- /dev/null
+++ b/drivers/tty/serial/st-asc.c
@@ -0,0 +1,932 @@
+/*
+ * st-asc.c: ST Asynchronous serial controller (ASC) driver
+ *
+ * Copyright (C) 2003-2013 STMicroelectronics (R&D) Limited
+ *
+ * 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.
+ *
+ */
+
+#if defined(CONFIG_SERIAL_ST_ASC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "st-asc"
+#define ASC_SERIAL_NAME "ttyAS"
+#define ASC_FIFO_SIZE 16
+#define ASC_MAX_PORTS 8
+
+struct asc_port {
+ struct uart_port port;
+ struct clk *clk;
+ unsigned int hw_flow_control:1;
+ unsigned int force_m1:1;
+};
+
+static struct asc_port asc_ports[ASC_MAX_PORTS];
+static struct uart_driver asc_uart_driver;
+
+/*---- UART Register definitions ------------------------------*/
+
+/* Register offsets */
+
+#define ASC_BAUDRATE 0x00
+#define ASC_TXBUF 0x04
+#define ASC_RXBUF 0x08
+#define ASC_CTL 0x0C
+#define ASC_INTEN 0x10
+#define ASC_STA 0x14
+#define ASC_GUARDTIME 0x18
+#define ASC_TIMEOUT 0x1C
+#define ASC_TXRESET 0x20
+#define ASC_RXRESET 0x24
+#define ASC_RETRIES 0x28
+
+/* ASC_RXBUF */
+#define ASC_RXBUF_PE 0x100
+#define ASC_RXBUF_FE 0x200
+/**
+ * Some of status comes from higher bits of the character and some come from
+ * the status register. Combining both of them in to single status using dummy
+ * bits.
+ */
+#define ASC_RXBUF_DUMMY_RX 0x10000
+#define ASC_RXBUF_DUMMY_BE 0x20000
+#define ASC_RXBUF_DUMMY_OE 0x40000
+
+/* ASC_CTL */
+
+#define ASC_CTL_MODE_MSK 0x0007
+#define ASC_CTL_MODE_8BIT 0x0001
+#define ASC_CTL_MODE_7BIT_PAR 0x0003
+#define ASC_CTL_MODE_9BIT 0x0004
+#define ASC_CTL_MODE_8BIT_WKUP 0x0005
+#define ASC_CTL_MODE_8BIT_PAR 0x0007
+#define ASC_CTL_STOP_MSK 0x0018
+#define ASC_CTL_STOP_HALFBIT 0x0000
+#define ASC_CTL_STOP_1BIT 0x0008
+#define ASC_CTL_STOP_1_HALFBIT 0x0010
+#define ASC_CTL_STOP_2BIT 0x0018
+#define ASC_CTL_PARITYODD 0x0020
+#define ASC_CTL_LOOPBACK 0x0040
+#define ASC_CTL_RUN 0x0080
+#define ASC_CTL_RXENABLE 0x0100
+#define ASC_CTL_SCENABLE 0x0200
+#define ASC_CTL_FIFOENABLE 0x0400
+#define ASC_CTL_CTSENABLE 0x0800
+#define ASC_CTL_BAUDMODE 0x1000
+
+/* ASC_GUARDTIME */
+
+#define ASC_GUARDTIME_MSK 0x00FF
+
+/* ASC_INTEN */
+
+#define ASC_INTEN_RBE 0x0001
+#define ASC_INTEN_TE 0x0002
+#define ASC_INTEN_THE 0x0004
+#define ASC_INTEN_PE 0x0008
+#define ASC_INTEN_FE 0x0010
+#define ASC_INTEN_OE 0x0020
+#define ASC_INTEN_TNE 0x0040
+#define ASC_INTEN_TOI 0x0080
+#define ASC_INTEN_RHF 0x0100
+
+/* ASC_RETRIES */
+
+#define ASC_RETRIES_MSK 0x00FF
+
+/* ASC_RXBUF */
+
+#define ASC_RXBUF_MSK 0x03FF
+
+/* ASC_STA */
+
+#define ASC_STA_RBF 0x0001
+#define ASC_STA_TE 0x0002
+#define ASC_STA_THE 0x0004
+#define ASC_STA_PE 0x0008
+#define ASC_STA_FE 0x0010
+#define ASC_STA_OE 0x0020
+#define ASC_STA_TNE 0x0040
+#define ASC_STA_TOI 0x0080
+#define ASC_STA_RHF 0x0100
+#define ASC_STA_TF 0x0200
+#define ASC_STA_NKD 0x0400
+
+/* ASC_TIMEOUT */
+
+#define ASC_TIMEOUT_MSK 0x00FF
+
+/* ASC_TXBUF */
+
+#define ASC_TXBUF_MSK 0x01FF
+
+/*---- Inline function definitions ---------------------------*/
+
+static inline struct asc_port *to_asc_port(struct uart_port *port)
+{
+ return container_of(port, struct asc_port, port);
+}
+
+static inline u32 asc_in(struct uart_port *port, u32 offset)
+{
+ return readl(port->membase + offset);
+}
+
+static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
+{
+ writel(value, port->membase + offset);
+}
+
+/*
+ * Some simple utility functions to enable and disable interrupts.
+ * Note that these need to be called with interrupts disabled.
+ */
+static inline void asc_disable_tx_interrupts(struct uart_port *port)
+{
+ u32 intenable = asc_in(port, ASC_INTEN) & ~ASC_INTEN_THE;
+ asc_out(port, ASC_INTEN, intenable);
+ (void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */
+}
+
+static inline void asc_enable_tx_interrupts(struct uart_port *port)
+{
+ u32 intenable = asc_in(port, ASC_INTEN) | ASC_INTEN_THE;
+ asc_out(port, ASC_INTEN, intenable);
+}
+
+static inline void asc_disable_rx_interrupts(struct uart_port *port)
+{
+ u32 intenable = asc_in(port, ASC_INTEN) & ~ASC_INTEN_RBE;
+ asc_out(port, ASC_INTEN, intenable);
+ (void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */
+}
+
+static inline void asc_enable_rx_interrupts(struct uart_port *port)
+{
+ u32 intenable = asc_in(port, ASC_INTEN) | ASC_INTEN_RBE;
+ asc_out(port, ASC_INTEN, intenable);
+}
+
+static inline u32 asc_txfifo_is_empty(struct uart_port *port)
+{
+ return asc_in(port, ASC_STA) & ASC_STA_TE;
+}
+
+static inline int asc_txfifo_is_full(struct uart_port *port)
+{
+ return asc_in(port, ASC_STA) & ASC_STA_TF;
+}
+
+static inline const char *asc_port_name(struct uart_port *port)
+{
+ return to_platform_device(port->dev)->name;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * This section contains code to support the use of the ASC as a
+ * generic serial port.
+ */
+
+static inline unsigned asc_hw_txroom(struct uart_port *port)
+{
+ u32 status = asc_in(port, ASC_STA);
+
+ if (status & ASC_STA_THE)
+ return port->fifosize / 2;
+ else if (!(status & ASC_STA_TF))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Start transmitting chars.
+ * This is called from both interrupt and task level.
+ * Either way interrupts are disabled.
+ */
+static void asc_transmit_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ int txroom;
+ unsigned char c;
+
+ txroom = asc_hw_txroom(port);
+
+ if ((txroom != 0) && port->x_char) {
+ c = port->x_char;
+ port->x_char = 0;
+ asc_out(port, ASC_TXBUF, c);
+ port->icount.tx++;
+ txroom = asc_hw_txroom(port);
+ }
+
+ if (uart_tx_stopped(port)) {
+ /*
+ * We should try and stop the hardware here, but I
+ * don't think the ASC has any way to do that.
+ */
+ asc_disable_tx_interrupts(port);
+ return;
+ }
+
+ if (uart_circ_empty(xmit)) {
+ asc_disable_tx_interrupts(port);
+ return;
+ }
+
+ if (txroom == 0)
+ return;
+
+ do {
+ c = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ asc_out(port, ASC_TXBUF, c);
+ port->icount.tx++;
+ txroom--;
+ } while ((txroom > 0) && (!uart_circ_empty(xmit)));
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ asc_disable_tx_interrupts(port);
+}
+
+static void asc_receive_chars(struct uart_port *port)
+{
+ struct tty_port *tport = &port->state->port;
+ unsigned long status;
+ unsigned long c = 0;
+ char flag;
+
+ if (port->irq_wake)
+ pm_wakeup_event(tport->tty->dev, 0);
+
+ while ((status = asc_in(port, ASC_STA)) & ASC_STA_RBF) {
+ c = asc_in(port, ASC_RXBUF) | ASC_RXBUF_DUMMY_RX;
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if ((c & (ASC_RXBUF_FE | ASC_RXBUF_PE)) ||
+ status & ASC_STA_OE) {
+
+ if (c & ASC_RXBUF_FE) {
+ if (c == ASC_RXBUF_FE) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ c |= ASC_RXBUF_DUMMY_BE;
+ } else {
+ port->icount.frame++;
+ }
+ } else if (c & ASC_RXBUF_PE) {
+ port->icount.parity++;
+ }
+ /*
+ * Reading any data from the RX FIFO clears the
+ * overflow error condition.
+ */
+ if (status & ASC_STA_OE) {
+ port->icount.overrun++;
+ c |= ASC_RXBUF_DUMMY_OE;
+ }
+
+ c &= port->read_status_mask;
+
+ if (c & ASC_RXBUF_DUMMY_BE)
+ flag = TTY_BREAK;
+ else if (c & ASC_RXBUF_PE)
+ flag = TTY_PARITY;
+ else if (c & ASC_RXBUF_FE)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, c))
+ continue;
+
+ uart_insert_char(port, c, ASC_RXBUF_DUMMY_OE, c & 0xff, flag);
+ }
+
+ /* Tell the rest of the system the news. New characters! */
+ tty_flip_buffer_push(tport);
+}
+
+static irqreturn_t asc_interrupt(int irq, void *ptr)
+{
+ struct uart_port *port = ptr;
+ u32 status;
+
+ spin_lock(&port->lock);
+
+ status = asc_in(port, ASC_STA);
+
+ if (status & ASC_STA_RBF) {
+ /* Receive FIFO not empty */
+ asc_receive_chars(port);
+ }
+
+ if ((status & ASC_STA_THE) &&
+ (asc_in(port, ASC_INTEN) & ASC_INTEN_THE)) {
+ /* Transmitter FIFO at least half empty */
+ asc_transmit_chars(port);
+ }
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * UART Functions
+ */
+
+static unsigned int asc_tx_empty(struct uart_port *port)
+{
+ return asc_txfifo_is_empty(port) ? TIOCSER_TEMT : 0;
+}
+
+static void asc_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /*
+ * This routine is used for seting signals of: DTR, DCD, CTS/RTS
+ * We use ASC's hardware for CTS/RTS, so don't need any for that.
+ * Some boards have DTR and DCD implemented using PIO pins,
+ * code to do this should be hooked in here.
+ */
+}
+
+static unsigned int asc_get_mctrl(struct uart_port *port)
+{
+ /*
+ * This routine is used for geting signals of: DTR, DCD, DSR, RI,
+ * and CTS/RTS
+ */
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* There are probably characters waiting to be transmitted. */
+static void asc_start_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+
+ if (!uart_circ_empty(xmit))
+ asc_enable_tx_interrupts(port);
+}
+
+/* Transmit stop */
+static void asc_stop_tx(struct uart_port *port)
+{
+ asc_disable_tx_interrupts(port);
+}
+
+/* Receive stop */
+static void asc_stop_rx(struct uart_port *port)
+{
+ asc_disable_rx_interrupts(port);
+}
+
+/* Force modem status interrupts on */
+static void asc_enable_ms(struct uart_port *port)
+{
+ /* Nothing here yet .. */
+}
+
+/* Handle breaks - ignored by us */
+static void asc_break_ctl(struct uart_port *port, int break_state)
+{
+ /* Nothing here yet .. */
+}
+
+/*
+ * Enable port for reception.
+ */
+static int asc_startup(struct uart_port *port)
+{
+ if (request_irq(port->irq, asc_interrupt, IRQF_NO_SUSPEND,
+ asc_port_name(port), port)) {
+ dev_err(port->dev, "cannot allocate irq.\n");
+ return -ENODEV;
+ }
+
+ asc_transmit_chars(port);
+ asc_enable_rx_interrupts(port);
+
+ return 0;
+}
+
+static void asc_shutdown(struct uart_port *port)
+{
+ asc_disable_tx_interrupts(port);
+ asc_disable_rx_interrupts(port);
+ free_irq(port->irq, port);
+}
+
+static void asc_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct asc_port *ascport = to_asc_port(port);
+ unsigned long flags = 0;
+ u32 ctl;
+
+ switch (state) {
+ case UART_PM_STATE_ON:
+ clk_prepare_enable(ascport->clk);
+ break;
+ case UART_PM_STATE_OFF:
+ /*
+ * Disable the ASC baud rate generator, which is as close as
+ * we can come to turning it off. Note this is not called with
+ * the port spinlock held.
+ */
+ spin_lock_irqsave(&port->lock, flags);
+ ctl = asc_in(port, ASC_CTL) & ~ASC_CTL_RUN;
+ asc_out(port, ASC_CTL, ctl);
+ spin_unlock_irqrestore(&port->lock, flags);
+ clk_disable_unprepare(ascport->clk);
+ break;
+ }
+}
+
+static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct asc_port *ascport = to_asc_port(port);
+ unsigned int baud;
+ u32 ctrl_val;
+ tcflag_t cflag;
+ unsigned long flags;
+
+ /* Update termios to reflect hardware capabilities */
+ termios->c_cflag &= ~(CMSPAR |
+ (ascport->hw_flow_control ? 0 : CRTSCTS));
+
+ port->uartclk = clk_get_rate(ascport->clk);
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ cflag = termios->c_cflag;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* read control register */
+ ctrl_val = asc_in(port, ASC_CTL);
+
+ /* stop serial port and reset value */
+ asc_out(port, ASC_CTL, (ctrl_val & ~ASC_CTL_RUN));
+ ctrl_val = ASC_CTL_RXENABLE | ASC_CTL_FIFOENABLE;
+
+ /* reset fifo rx & tx */
+ asc_out(port, ASC_TXRESET, 1);
+ asc_out(port, ASC_RXRESET, 1);
+
+ /* set character length */
+ if ((cflag & CSIZE) == CS7) {
+ ctrl_val |= ASC_CTL_MODE_7BIT_PAR;
+ } else {
+ ctrl_val |= (cflag & PARENB) ? ASC_CTL_MODE_8BIT_PAR :
+ ASC_CTL_MODE_8BIT;
+ }
+
+ /* set stop bit */
+ ctrl_val |= (cflag & CSTOPB) ? ASC_CTL_STOP_2BIT : ASC_CTL_STOP_1BIT;
+
+ /* odd parity */
+ if (cflag & PARODD)
+ ctrl_val |= ASC_CTL_PARITYODD;
+
+ /* hardware flow control */
+ if ((cflag & CRTSCTS))
+ ctrl_val |= ASC_CTL_CTSENABLE;
+
+ if ((baud < 19200) && !ascport->force_m1) {
+ asc_out(port, ASC_BAUDRATE, (port->uartclk / (16 * baud)));
+ } else {
+ /*
+ * MODE 1: recommended for high bit rates (above 19.2K)
+ *
+ * baudrate * 16 * 2^16
+ * ASCBaudRate = ------------------------
+ * inputclock
+ *
+ * However to keep the maths inside 32bits we divide top and
+ * bottom by 64. The +1 is to avoid a divide by zero if the
+ * input clock rate is something unexpected.
+ */
+ u32 counter = (baud * 16384) / ((port->uartclk / 64) + 1);
+ asc_out(port, ASC_BAUDRATE, counter);
+ ctrl_val |= ASC_CTL_BAUDMODE;
+ }
+
+ uart_update_timeout(port, cflag, baud);
+
+ ascport->port.read_status_mask = ASC_RXBUF_DUMMY_OE;
+ if (termios->c_iflag & INPCK)
+ ascport->port.read_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ ascport->port.read_status_mask |= ASC_RXBUF_DUMMY_BE;
+
+ /*
+ * Characters to ignore
+ */
+ ascport->port.ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ ascport->port.ignore_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE;
+ if (termios->c_iflag & IGNBRK) {
+ ascport->port.ignore_status_mask |= ASC_RXBUF_DUMMY_BE;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ ascport->port.ignore_status_mask |= ASC_RXBUF_DUMMY_OE;
+ }
+
+ /*
+ * Ignore all characters if CREAD is not set.
+ */
+ if (!(termios->c_cflag & CREAD))
+ ascport->port.ignore_status_mask |= ASC_RXBUF_DUMMY_RX;
+
+ /* Set the timeout */
+ asc_out(port, ASC_TIMEOUT, 20);
+
+ /* write final value and enable port */
+ asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN));
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *asc_type(struct uart_port *port)
+{
+ return (port->type == PORT_ASC) ? DRIVER_NAME : NULL;
+}
+
+static void asc_release_port(struct uart_port *port)
+{
+}
+
+static int asc_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+/*
+ * Called when the port is opened, and UPF_BOOT_AUTOCONF flag is set
+ * Set type field if successful
+ */
+static void asc_config_port(struct uart_port *port, int flags)
+{
+ if ((flags & UART_CONFIG_TYPE))
+ port->type = PORT_ASC;
+}
+
+static int
+asc_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ /* No user changeable parameters */
+ return -EINVAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context (i.e. kgdb).
+ */
+
+static int asc_get_poll_char(struct uart_port *port)
+{
+ if (!(asc_in(port, ASC_STA) & ASC_STA_RBF))
+ return NO_POLL_CHAR;
+
+ return asc_in(port, ASC_RXBUF);
+}
+
+static void asc_put_poll_char(struct uart_port *port, unsigned char c)
+{
+ while (asc_txfifo_is_full(port))
+ cpu_relax();
+ asc_out(port, ASC_TXBUF, c);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+/*---------------------------------------------------------------------*/
+
+static struct uart_ops asc_uart_ops = {
+ .tx_empty = asc_tx_empty,
+ .set_mctrl = asc_set_mctrl,
+ .get_mctrl = asc_get_mctrl,
+ .start_tx = asc_start_tx,
+ .stop_tx = asc_stop_tx,
+ .stop_rx = asc_stop_rx,
+ .enable_ms = asc_enable_ms,
+ .break_ctl = asc_break_ctl,
+ .startup = asc_startup,
+ .shutdown = asc_shutdown,
+ .set_termios = asc_set_termios,
+ .type = asc_type,
+ .release_port = asc_release_port,
+ .request_port = asc_request_port,
+ .config_port = asc_config_port,
+ .verify_port = asc_verify_port,
+ .pm = asc_pm,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = asc_get_poll_char,
+ .poll_put_char = asc_put_poll_char,
+#endif /* CONFIG_CONSOLE_POLL */
+};
+
+static int asc_init_port(struct asc_port *ascport,
+ struct platform_device *pdev)
+{
+ struct uart_port *port = &ascport->port;
+ struct resource *res;
+
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->ops = &asc_uart_ops;
+ port->fifosize = ASC_FIFO_SIZE;
+ port->dev = &pdev->dev;
+ port->irq = platform_get_irq(pdev, 0);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ port->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(port->membase))
+ return PTR_ERR(port->membase);
+ port->mapbase = res->start;
+
+ spin_lock_init(&port->lock);
+
+ ascport->clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (WARN_ON(IS_ERR(ascport->clk)))
+ return -EINVAL;
+ /* ensure that clk rate is correct by enabling the clk */
+ clk_prepare_enable(ascport->clk);
+ ascport->port.uartclk = clk_get_rate(ascport->clk);
+ WARN_ON(ascport->port.uartclk == 0);
+ clk_disable_unprepare(ascport->clk);
+
+ return 0;
+}
+
+static struct asc_port *asc_of_get_asc_port(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int id;
+
+ if (!np)
+ return NULL;
+
+ id = of_alias_get_id(np, ASC_SERIAL_NAME);
+
+ if (id < 0)
+ id = 0;
+
+ if (WARN_ON(id >= ASC_MAX_PORTS))
+ return NULL;
+
+ asc_ports[id].hw_flow_control = of_property_read_bool(np,
+ "st,hw-flow-control");
+ asc_ports[id].force_m1 = of_property_read_bool(np, "st,force_m1");
+ asc_ports[id].port.line = id;
+ return &asc_ports[id];
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id asc_match[] = {
+ { .compatible = "st,asc", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, asc_match);
+#endif
+
+static int asc_serial_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct asc_port *ascport;
+
+ ascport = asc_of_get_asc_port(pdev);
+ if (!ascport)
+ return -ENODEV;
+
+ ret = asc_init_port(ascport, pdev);
+ if (ret)
+ return ret;
+
+ ret = uart_add_one_port(&asc_uart_driver, &ascport->port);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, &ascport->port);
+
+ return 0;
+}
+
+static int asc_serial_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ return uart_remove_one_port(&asc_uart_driver, port);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int asc_serial_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ return uart_suspend_port(&asc_uart_driver, port);
+}
+
+static int asc_serial_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ return uart_resume_port(&asc_uart_driver, port);
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SERIAL_ST_ASC_CONSOLE
+static void asc_console_putchar(struct uart_port *port, int ch)
+{
+ unsigned int timeout = 1000000;
+
+ /* Wait for upto 1 second in case flow control is stopping us. */
+ while (--timeout && asc_txfifo_is_full(port))
+ udelay(1);
+
+ asc_out(port, ASC_TXBUF, ch);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+
+static void asc_console_write(struct console *co, const char *s, unsigned count)
+{
+ struct uart_port *port = &asc_ports[co->index].port;
+ unsigned long flags;
+ unsigned long timeout = 1000000;
+ int locked = 1;
+ u32 intenable;
+
+ local_irq_save(flags);
+ if (port->sysrq)
+ locked = 0; /* asc_interrupt has already claimed the lock */
+ else if (oops_in_progress)
+ locked = spin_trylock(&port->lock);
+ else
+ spin_lock(&port->lock);
+
+ /*
+ * Disable interrupts so we don't get the IRQ line bouncing
+ * up and down while interrupts are disabled.
+ */
+ intenable = asc_in(port, ASC_INTEN);
+ asc_out(port, ASC_INTEN, 0);
+ (void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */
+
+ uart_console_write(port, s, count, asc_console_putchar);
+
+ while (--timeout && !asc_txfifo_is_empty(port))
+ udelay(1);
+
+ asc_out(port, ASC_INTEN, intenable);
+
+ if (locked)
+ spin_unlock(&port->lock);
+ local_irq_restore(flags);
+}
+
+static int asc_console_setup(struct console *co, char *options)
+{
+ struct asc_port *ascport;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= ASC_MAX_PORTS)
+ return -ENODEV;
+
+ ascport = &asc_ports[co->index];
+
+ /*
+ * This driver does not support early console initialization
+ * (use ARM early printk support instead), so we only expect
+ * this to be called during the uart port registration when the
+ * driver gets probed and the port should be mapped at that point.
+ */
+ BUG_ON(ascport->port.mapbase == 0 || ascport->port.membase == NULL);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(&ascport->port, co, baud, parity, bits, flow);
+}
+
+static struct console asc_console = {
+ .name = ASC_SERIAL_NAME,
+ .device = uart_console_device,
+ .write = asc_console_write,
+ .setup = asc_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &asc_uart_driver,
+};
+
+#define ASC_SERIAL_CONSOLE (&asc_console)
+
+#else
+#define ASC_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_ST_ASC_CONSOLE */
+
+static struct uart_driver asc_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = DRIVER_NAME,
+ .dev_name = ASC_SERIAL_NAME,
+ .major = 0,
+ .minor = 0,
+ .nr = ASC_MAX_PORTS,
+ .cons = ASC_SERIAL_CONSOLE,
+};
+
+static const struct dev_pm_ops asc_serial_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(asc_serial_suspend, asc_serial_resume)
+};
+
+static struct platform_driver asc_serial_driver = {
+ .probe = asc_serial_probe,
+ .remove = asc_serial_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .pm = &asc_serial_pm_ops,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(asc_match),
+ },
+};
+
+static int __init asc_init(void)
+{
+ int ret;
+ static char banner[] __initdata =
+ KERN_INFO "STMicroelectronics ASC driver initialized\n";
+
+ printk(banner);
+
+ ret = uart_register_driver(&asc_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&asc_serial_driver);
+ if (ret)
+ uart_unregister_driver(&asc_uart_driver);
+
+ return ret;
+}
+
+static void __exit asc_exit(void)
+{
+ platform_driver_unregister(&asc_serial_driver);
+ uart_unregister_driver(&asc_uart_driver);
+}
+
+module_init(asc_init);
+module_exit(asc_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("STMicroelectronics (R&D) Limited");
+MODULE_DESCRIPTION("STMicroelectronics ASC serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c
index 6818410a2be..f87097acd8a 100644
--- a/drivers/tty/serial/timbuart.c
+++ b/drivers/tty/serial/timbuart.c
@@ -162,7 +162,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
dev_dbg(port->dev, "%s - leaving\n", __func__);
}
-void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
+static void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
{
if (isr & RXFLAGS) {
/* Some RX status is set */
@@ -184,7 +184,7 @@ void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
dev_dbg(port->dev, "%s - leaving\n", __func__);
}
-void timbuart_tasklet(unsigned long arg)
+static void timbuart_tasklet(unsigned long arg)
{
struct timbuart_port *uart = (struct timbuart_port *)arg;
u32 isr, ier = 0;
diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
index f655997f44a..a63c14bc9a2 100644
--- a/drivers/tty/serial/vr41xx_siu.c
+++ b/drivers/tty/serial/vr41xx_siu.c
@@ -705,7 +705,7 @@ static int siu_init_ports(struct platform_device *pdev)
{
struct uart_port *port;
struct resource *res;
- int *type = pdev->dev.platform_data;
+ int *type = dev_get_platdata(&pdev->dev);
int i;
if (!type)
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 48af43de346..93b697a0de6 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -170,7 +170,9 @@ static void handle_rx(struct uart_port *port)
tty_insert_flip_char(tport, c, flag);
}
+ spin_unlock(&port->lock);
tty_flip_buffer_push(tport);
+ spin_lock(&port->lock);
}
static void handle_tx(struct uart_port *port)
@@ -630,7 +632,6 @@ static int vt8500_serial_remove(struct platform_device *pdev)
{
struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
clk_disable_unprepare(vt8500_port->clk);
uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart);
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 8eaf1ab8add..e1ce141bad5 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -577,22 +577,22 @@ struct mgsl_struct {
#define SICR_RXC_ACTIVE BIT15
#define SICR_RXC_INACTIVE BIT14
-#define SICR_RXC (BIT15+BIT14)
+#define SICR_RXC (BIT15|BIT14)
#define SICR_TXC_ACTIVE BIT13
#define SICR_TXC_INACTIVE BIT12
-#define SICR_TXC (BIT13+BIT12)
+#define SICR_TXC (BIT13|BIT12)
#define SICR_RI_ACTIVE BIT11
#define SICR_RI_INACTIVE BIT10
-#define SICR_RI (BIT11+BIT10)
+#define SICR_RI (BIT11|BIT10)
#define SICR_DSR_ACTIVE BIT9
#define SICR_DSR_INACTIVE BIT8
-#define SICR_DSR (BIT9+BIT8)
+#define SICR_DSR (BIT9|BIT8)
#define SICR_DCD_ACTIVE BIT7
#define SICR_DCD_INACTIVE BIT6
-#define SICR_DCD (BIT7+BIT6)
+#define SICR_DCD (BIT7|BIT6)
#define SICR_CTS_ACTIVE BIT5
#define SICR_CTS_INACTIVE BIT4
-#define SICR_CTS (BIT5+BIT4)
+#define SICR_CTS (BIT5|BIT4)
#define SICR_RCC_UNDERFLOW BIT3
#define SICR_DPLL_NO_SYNC BIT2
#define SICR_BRG1_ZERO BIT1
@@ -1161,7 +1161,7 @@ static void mgsl_isr_receive_status( struct mgsl_struct *info )
{
u16 status = usc_InReg( info, RCSR );
- if ( debug_level >= DEBUG_LEVEL_ISR )
+ if ( debug_level >= DEBUG_LEVEL_ISR )
printk("%s(%d):mgsl_isr_receive_status status=%04X\n",
__FILE__,__LINE__,status);
@@ -1181,7 +1181,7 @@ static void mgsl_isr_receive_status( struct mgsl_struct *info )
(usc_InReg(info, RICR) & ~RXSTATUS_ABORT_RECEIVED));
}
- if (status & (RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)) {
+ if (status & (RXSTATUS_EXITED_HUNT | RXSTATUS_IDLE_RECEIVED)) {
if (status & RXSTATUS_EXITED_HUNT)
info->icount.exithunt++;
if (status & RXSTATUS_IDLE_RECEIVED)
@@ -1463,21 +1463,21 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info )
/* get the status of the received byte */
status = usc_InReg(info, RCSR);
- if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR +
- RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) )
+ if ( status & (RXSTATUS_FRAMING_ERROR | RXSTATUS_PARITY_ERROR |
+ RXSTATUS_OVERRUN | RXSTATUS_BREAK_RECEIVED) )
usc_UnlatchRxstatusBits(info,RXSTATUS_ALL);
icount->rx++;
flag = 0;
- if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR +
- RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) {
- printk("rxerr=%04X\n",status);
+ if ( status & (RXSTATUS_FRAMING_ERROR | RXSTATUS_PARITY_ERROR |
+ RXSTATUS_OVERRUN | RXSTATUS_BREAK_RECEIVED) ) {
+ printk("rxerr=%04X\n",status);
/* update error statistics */
if ( status & RXSTATUS_BREAK_RECEIVED ) {
- status &= ~(RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR);
+ status &= ~(RXSTATUS_FRAMING_ERROR | RXSTATUS_PARITY_ERROR);
icount->brk++;
- } else if (status & RXSTATUS_PARITY_ERROR)
+ } else if (status & RXSTATUS_PARITY_ERROR)
icount->parity++;
else if (status & RXSTATUS_FRAMING_ERROR)
icount->frame++;
@@ -1488,7 +1488,7 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info )
icount->overrun++;
}
- /* discard char if tty control flags say so */
+ /* discard char if tty control flags say so */
if (status & info->ignore_status_mask)
continue;
@@ -1545,8 +1545,8 @@ static void mgsl_isr_misc( struct mgsl_struct *info )
usc_EnableReceiver(info,DISABLE_UNCONDITIONAL);
usc_DmaCmd(info, DmaCmd_ResetRxChannel);
usc_UnlatchRxstatusBits(info, RXSTATUS_ALL);
- usc_ClearIrqPendingBits(info, RECEIVE_DATA + RECEIVE_STATUS);
- usc_DisableInterrupts(info, RECEIVE_DATA + RECEIVE_STATUS);
+ usc_ClearIrqPendingBits(info, RECEIVE_DATA | RECEIVE_STATUS);
+ usc_DisableInterrupts(info, RECEIVE_DATA | RECEIVE_STATUS);
/* schedule BH handler to restart receiver */
info->pending_bh |= BH_RECEIVE;
@@ -1595,7 +1595,7 @@ static void mgsl_isr_receive_dma( struct mgsl_struct *info )
u16 status;
/* clear interrupt pending and IUS bit for Rx DMA IRQ */
- usc_OutDmaReg( info, CDIR, BIT9+BIT1 );
+ usc_OutDmaReg( info, CDIR, BIT9 | BIT1 );
/* Read the receive DMA status to identify interrupt type. */
/* This also clears the status bits. */
@@ -1639,7 +1639,7 @@ static void mgsl_isr_transmit_dma( struct mgsl_struct *info )
u16 status;
/* clear interrupt pending and IUS bit for Tx DMA IRQ */
- usc_OutDmaReg(info, CDIR, BIT8+BIT0 );
+ usc_OutDmaReg(info, CDIR, BIT8 | BIT0 );
/* Read the transmit DMA status to identify interrupt type. */
/* This also clears the status bits. */
@@ -1832,8 +1832,8 @@ static void shutdown(struct mgsl_struct * info)
usc_DisableMasterIrqBit(info);
usc_stop_receiver(info);
usc_stop_transmitter(info);
- usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS +
- TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC );
+ usc_DisableInterrupts(info,RECEIVE_DATA | RECEIVE_STATUS |
+ TRANSMIT_DATA | TRANSMIT_STATUS | IO_PIN | MISC );
usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE);
/* Disable DMAEN (Port 7, Bit 14) */
@@ -1886,7 +1886,7 @@ static void mgsl_program_hw(struct mgsl_struct *info)
info->ri_chkcount = 0;
info->dsr_chkcount = 0;
- usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI);
+ usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI);
usc_EnableInterrupts(info, IO_PIN);
usc_get_serial_signals(info);
@@ -2773,7 +2773,7 @@ static int mgsl_wait_event(struct mgsl_struct * info, int __user * mask_ptr)
if (!waitqueue_active(&info->event_wait_q)) {
/* disable enable exit hunt mode/idle rcvd IRQs */
usc_OutReg(info, RICR, usc_InReg(info,RICR) &
- ~(RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED));
+ ~(RXSTATUS_EXITED_HUNT | RXSTATUS_IDLE_RECEIVED));
}
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
@@ -3092,7 +3092,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp)
printk("%s(%d):mgsl_close(%s) entry, count=%d\n",
__FILE__,__LINE__, info->device_name, info->port.count);
- if (tty_port_close_start(&info->port, tty, filp) == 0)
+ if (tty_port_close_start(&info->port, tty, filp) == 0)
goto cleanup;
mutex_lock(&info->port.mutex);
@@ -4297,7 +4297,7 @@ static struct mgsl_struct* mgsl_allocate_device(void)
spin_lock_init(&info->irq_spinlock);
spin_lock_init(&info->netlock);
memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
- info->idle_mode = HDLC_TXIDLE_FLAGS;
+ info->idle_mode = HDLC_TXIDLE_FLAGS;
info->num_tx_dma_buffers = 1;
info->num_tx_holding_buffers = 0;
}
@@ -4722,7 +4722,7 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG )
RegValue |= BIT15;
else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC )
- RegValue |= BIT15 + BIT14;
+ RegValue |= BIT15 | BIT14;
}
if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE )
@@ -4763,11 +4763,11 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
switch ( info->params.encoding ) {
case HDLC_ENCODING_NRZB: RegValue |= BIT13; break;
case HDLC_ENCODING_NRZI_MARK: RegValue |= BIT14; break;
- case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT14 + BIT13; break;
+ case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT14 | BIT13; break;
case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT15; break;
- case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT15 + BIT13; break;
- case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14; break;
- case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break;
+ case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT15 | BIT13; break;
+ case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT15 | BIT14; break;
+ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 | BIT14 | BIT13; break;
}
if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT )
@@ -4838,15 +4838,15 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
switch ( info->params.encoding ) {
case HDLC_ENCODING_NRZB: RegValue |= BIT13; break;
case HDLC_ENCODING_NRZI_MARK: RegValue |= BIT14; break;
- case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT14 + BIT13; break;
+ case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT14 | BIT13; break;
case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT15; break;
- case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT15 + BIT13; break;
- case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14; break;
- case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break;
+ case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT15 | BIT13; break;
+ case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT15 | BIT14; break;
+ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 | BIT14 | BIT13; break;
}
if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT )
- RegValue |= BIT9 + BIT8;
+ RegValue |= BIT9 | BIT8;
else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT )
RegValue |= ( BIT12 | BIT10 | BIT9 | BIT8);
@@ -4957,7 +4957,7 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
RegValue = 0x0000;
- if ( info->params.flags & (HDLC_FLAG_RXC_DPLL + HDLC_FLAG_TXC_DPLL) ) {
+ if ( info->params.flags & (HDLC_FLAG_RXC_DPLL | HDLC_FLAG_TXC_DPLL) ) {
u32 XtalSpeed;
u32 DpllDivisor;
u16 Tc;
@@ -5019,7 +5019,7 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
case HDLC_ENCODING_BIPHASE_MARK:
case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT9; break;
case HDLC_ENCODING_BIPHASE_LEVEL:
- case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT9 + BIT8; break;
+ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT9 | BIT8; break;
}
}
@@ -5056,8 +5056,8 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
/* enable Master Interrupt Enable bit (MIE) */
usc_EnableMasterIrqBit( info );
- usc_ClearIrqPendingBits( info, RECEIVE_STATUS + RECEIVE_DATA +
- TRANSMIT_STATUS + TRANSMIT_DATA + MISC);
+ usc_ClearIrqPendingBits( info, RECEIVE_STATUS | RECEIVE_DATA |
+ TRANSMIT_STATUS | TRANSMIT_DATA | MISC);
/* arm RCC underflow interrupt */
usc_OutReg(info, SICR, (u16)(usc_InReg(info,SICR) | BIT3));
@@ -5175,14 +5175,14 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info )
switch ( info->params.preamble_length ) {
case HDLC_PREAMBLE_LENGTH_16BITS: RegValue |= BIT10; break;
case HDLC_PREAMBLE_LENGTH_32BITS: RegValue |= BIT11; break;
- case HDLC_PREAMBLE_LENGTH_64BITS: RegValue |= BIT11 + BIT10; break;
+ case HDLC_PREAMBLE_LENGTH_64BITS: RegValue |= BIT11 | BIT10; break;
}
switch ( info->params.preamble ) {
- case HDLC_PREAMBLE_PATTERN_FLAGS: RegValue |= BIT8 + BIT12; break;
+ case HDLC_PREAMBLE_PATTERN_FLAGS: RegValue |= BIT8 | BIT12; break;
case HDLC_PREAMBLE_PATTERN_ONES: RegValue |= BIT8; break;
case HDLC_PREAMBLE_PATTERN_10: RegValue |= BIT9; break;
- case HDLC_PREAMBLE_PATTERN_01: RegValue |= BIT9 + BIT8; break;
+ case HDLC_PREAMBLE_PATTERN_01: RegValue |= BIT9 | BIT8; break;
}
usc_OutReg( info, CCR, RegValue );
@@ -5221,7 +5221,7 @@ static void usc_enable_loopback(struct mgsl_struct *info, int enable)
{
if (enable) {
/* blank external TXD output */
- usc_OutReg(info,IOCR,usc_InReg(info,IOCR) | (BIT7+BIT6));
+ usc_OutReg(info,IOCR,usc_InReg(info,IOCR) | (BIT7 | BIT6));
/* Clock mode Control Register (CMCR)
*
@@ -5260,7 +5260,7 @@ static void usc_enable_loopback(struct mgsl_struct *info, int enable)
outw( 0x0300, info->io_base + CCAR );
} else {
/* enable external TXD output */
- usc_OutReg(info,IOCR,usc_InReg(info,IOCR) & ~(BIT7+BIT6));
+ usc_OutReg(info,IOCR,usc_InReg(info,IOCR) & ~(BIT7 | BIT6));
/* clear Internal Data loopback mode */
info->loopback_bits = 0;
@@ -5447,13 +5447,13 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info )
usc_OutDmaReg( info, NRARU, (u16)(phys_addr >> 16) );
usc_UnlatchRxstatusBits( info, RXSTATUS_ALL );
- usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS );
+ usc_ClearIrqPendingBits( info, RECEIVE_DATA | RECEIVE_STATUS );
usc_EnableInterrupts( info, RECEIVE_STATUS );
/* 1. Arm End of Buffer (EOB) Receive DMA Interrupt (BIT2 of RDIAR) */
/* 2. Enable Receive DMA Interrupts (BIT1 of DICR) */
- usc_OutDmaReg( info, RDIAR, BIT3 + BIT2 );
+ usc_OutDmaReg( info, RDIAR, BIT3 | BIT2 );
usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT1) );
usc_DmaCmd( info, DmaCmd_InitRxChannel );
if ( info->params.flags & HDLC_FLAG_AUTO_DCD )
@@ -5488,8 +5488,8 @@ static void usc_stop_receiver( struct mgsl_struct *info )
usc_DmaCmd( info, DmaCmd_ResetRxChannel );
usc_UnlatchRxstatusBits( info, RXSTATUS_ALL );
- usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS );
- usc_DisableInterrupts( info, RECEIVE_DATA + RECEIVE_STATUS );
+ usc_ClearIrqPendingBits( info, RECEIVE_DATA | RECEIVE_STATUS );
+ usc_DisableInterrupts( info, RECEIVE_DATA | RECEIVE_STATUS );
usc_EnableReceiver(info,DISABLE_UNCONDITIONAL);
@@ -5536,13 +5536,13 @@ static void usc_start_receiver( struct mgsl_struct *info )
usc_OutDmaReg( info, NRARU, (u16)(phys_addr >> 16) );
usc_UnlatchRxstatusBits( info, RXSTATUS_ALL );
- usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS );
+ usc_ClearIrqPendingBits( info, RECEIVE_DATA | RECEIVE_STATUS );
usc_EnableInterrupts( info, RECEIVE_STATUS );
/* 1. Arm End of Buffer (EOB) Receive DMA Interrupt (BIT2 of RDIAR) */
/* 2. Enable Receive DMA Interrupts (BIT1 of DICR) */
- usc_OutDmaReg( info, RDIAR, BIT3 + BIT2 );
+ usc_OutDmaReg( info, RDIAR, BIT3 | BIT2 );
usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT1) );
usc_DmaCmd( info, DmaCmd_InitRxChannel );
if ( info->params.flags & HDLC_FLAG_AUTO_DCD )
@@ -5551,7 +5551,7 @@ static void usc_start_receiver( struct mgsl_struct *info )
usc_EnableReceiver(info,ENABLE_UNCONDITIONAL);
} else {
usc_UnlatchRxstatusBits(info, RXSTATUS_ALL);
- usc_ClearIrqPendingBits(info, RECEIVE_DATA + RECEIVE_STATUS);
+ usc_ClearIrqPendingBits(info, RECEIVE_DATA | RECEIVE_STATUS);
usc_EnableInterrupts(info, RECEIVE_DATA);
usc_RTCmd( info, RTCmd_PurgeRxFifo );
@@ -5925,7 +5925,7 @@ static void usc_set_async_mode( struct mgsl_struct *info )
RegValue = 0;
if ( info->params.data_bits != 8 )
- RegValue |= BIT4+BIT3+BIT2;
+ RegValue |= BIT4 | BIT3 | BIT2;
if ( info->params.parity != ASYNC_PARITY_NONE ) {
RegValue |= BIT5;
@@ -5982,7 +5982,7 @@ static void usc_set_async_mode( struct mgsl_struct *info )
RegValue = 0;
if ( info->params.data_bits != 8 )
- RegValue |= BIT4+BIT3+BIT2;
+ RegValue |= BIT4 | BIT3 | BIT2;
if ( info->params.parity != ASYNC_PARITY_NONE ) {
RegValue |= BIT5;
@@ -6129,7 +6129,7 @@ static void usc_loopback_frame( struct mgsl_struct *info )
/* WAIT FOR RECEIVE COMPLETE */
for (i=0 ; i<1000 ; i++)
- if (usc_InReg( info, RCSR ) & (BIT8 + BIT4 + BIT3 + BIT1))
+ if (usc_InReg( info, RCSR ) & (BIT8 | BIT4 | BIT3 | BIT1))
break;
/* clear Internal Data loopback mode */
@@ -6579,8 +6579,8 @@ static bool mgsl_get_rx_frame(struct mgsl_struct *info)
status = info->rx_buffer_list[EndIndex].status;
- if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN +
- RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) {
+ if ( status & (RXSTATUS_SHORT_FRAME | RXSTATUS_OVERRUN |
+ RXSTATUS_CRC_ERROR | RXSTATUS_ABORT) ) {
if ( status & RXSTATUS_SHORT_FRAME )
info->icount.rxshort++;
else if ( status & RXSTATUS_ABORT )
@@ -6762,8 +6762,8 @@ static bool mgsl_get_raw_rx_frame(struct mgsl_struct *info)
status = info->rx_buffer_list[CurrentIndex].status;
- if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN +
- RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) {
+ if ( status & (RXSTATUS_SHORT_FRAME | RXSTATUS_OVERRUN |
+ RXSTATUS_CRC_ERROR | RXSTATUS_ABORT) ) {
if ( status & RXSTATUS_SHORT_FRAME )
info->icount.rxshort++;
else if ( status & RXSTATUS_ABORT )
@@ -6899,7 +6899,7 @@ static void mgsl_load_tx_dma_buffer(struct mgsl_struct *info,
/* set CMR:13 to start transmit when
* next GoAhead (abort) is received
*/
- info->cmr_value |= BIT13;
+ info->cmr_value |= BIT13;
}
/* begin loading the frame in the next available tx dma
@@ -7278,7 +7278,7 @@ static bool mgsl_dma_test( struct mgsl_struct *info )
spin_unlock_irqrestore(&info->irq_spinlock,flags);
-
+
/******************************/
/* WAIT FOR TRANSMIT COMPLETE */
/******************************/
@@ -7292,7 +7292,7 @@ static bool mgsl_dma_test( struct mgsl_struct *info )
status = usc_InReg( info, TCSR );
spin_unlock_irqrestore(&info->irq_spinlock,flags);
- while ( !(status & (BIT6+BIT5+BIT4+BIT2+BIT1)) ) {
+ while ( !(status & (BIT6 | BIT5 | BIT4 | BIT2 | BIT1)) ) {
if (time_after(jiffies, EndTime)) {
rc = false;
break;
@@ -7307,7 +7307,7 @@ static bool mgsl_dma_test( struct mgsl_struct *info )
if ( rc ){
/* CHECK FOR TRANSMIT ERRORS */
- if ( status & (BIT5 + BIT1) )
+ if ( status & (BIT5 | BIT1) )
rc = false;
}
@@ -7333,7 +7333,7 @@ static bool mgsl_dma_test( struct mgsl_struct *info )
/* CHECK FOR RECEIVE ERRORS */
status = info->rx_buffer_list[0].status;
- if ( status & (BIT8 + BIT3 + BIT1) ) {
+ if ( status & (BIT8 | BIT3 | BIT1) ) {
/* receive error has occurred */
rc = false;
} else {
@@ -7605,7 +7605,7 @@ static void usc_loopmode_send_done( struct mgsl_struct * info )
{
info->loopmode_send_done_requested = false;
/* clear CMR:13 to 0 to start echoing RxData to TxData */
- info->cmr_value &= ~BIT13;
+ info->cmr_value &= ~BIT13;
usc_OutReg(info, CMR, info->cmr_value);
}
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index ff171384ea5..dc6e96996ea 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -3478,7 +3478,7 @@ static int alloc_buf_list(SLMP_INFO *info)
for ( i = 0; i < info->rx_buf_count; i++ ) {
/* calculate and store physical address of this buffer entry */
info->rx_buf_list_ex[i].phys_entry =
- info->buffer_list_phys + (i * sizeof(SCABUFSIZE));
+ info->buffer_list_phys + (i * SCABUFSIZE);
/* calculate and store physical address of */
/* next entry in cirular list of entries */
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 9121c1f7aee..c043136fbe5 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -18,31 +18,118 @@
#include <linux/module.h>
#include <linux/ratelimit.h>
+
+#define MIN_TTYB_SIZE 256
+#define TTYB_ALIGN_MASK 255
+
+/*
+ * Byte threshold to limit memory consumption for flip buffers.
+ * The actual memory limit is > 2x this amount.
+ */
+#define TTYB_MEM_LIMIT 65536
+
+/*
+ * We default to dicing tty buffer allocations to this many characters
+ * in order to avoid multiple page allocations. We know the size of
+ * tty_buffer itself but it must also be taken into account that the
+ * the buffer is 256 byte aligned. See tty_buffer_find for the allocation
+ * logic this must match
+ */
+
+#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
+
+
+/**
+ * tty_buffer_lock_exclusive - gain exclusive access to buffer
+ * tty_buffer_unlock_exclusive - release exclusive access
+ *
+ * @port - tty_port owning the flip buffer
+ *
+ * Guarantees safe use of the line discipline's receive_buf() method by
+ * excluding the buffer work and any pending flush from using the flip
+ * buffer. Data can continue to be added concurrently to the flip buffer
+ * from the driver side.
+ *
+ * On release, the buffer work is restarted if there is data in the
+ * flip buffer
+ */
+
+void tty_buffer_lock_exclusive(struct tty_port *port)
+{
+ struct tty_bufhead *buf = &port->buf;
+
+ atomic_inc(&buf->priority);
+ mutex_lock(&buf->lock);
+}
+
+void tty_buffer_unlock_exclusive(struct tty_port *port)
+{
+ struct tty_bufhead *buf = &port->buf;
+ int restart;
+
+ restart = buf->head->commit != buf->head->read;
+
+ atomic_dec(&buf->priority);
+ mutex_unlock(&buf->lock);
+ if (restart)
+ queue_work(system_unbound_wq, &buf->work);
+}
+
+/**
+ * tty_buffer_space_avail - return unused buffer space
+ * @port - tty_port owning the flip buffer
+ *
+ * Returns the # of bytes which can be written by the driver without
+ * reaching the buffer limit.
+ *
+ * Note: this does not guarantee that memory is available to write
+ * the returned # of bytes (use tty_prepare_flip_string_xxx() to
+ * pre-allocate if memory guarantee is required).
+ */
+
+int tty_buffer_space_avail(struct tty_port *port)
+{
+ int space = TTYB_MEM_LIMIT - atomic_read(&port->buf.memory_used);
+ return max(space, 0);
+}
+
+static void tty_buffer_reset(struct tty_buffer *p, size_t size)
+{
+ p->used = 0;
+ p->size = size;
+ p->next = NULL;
+ p->commit = 0;
+ p->read = 0;
+}
+
/**
* tty_buffer_free_all - free buffers used by a tty
* @tty: tty to free from
*
* Remove all the buffers pending on a tty whether queued with data
* or in the free ring. Must be called when the tty is no longer in use
- *
- * Locking: none
*/
void tty_buffer_free_all(struct tty_port *port)
{
struct tty_bufhead *buf = &port->buf;
- struct tty_buffer *thead;
+ struct tty_buffer *p, *next;
+ struct llist_node *llist;
- while ((thead = buf->head) != NULL) {
- buf->head = thead->next;
- kfree(thead);
- }
- while ((thead = buf->free) != NULL) {
- buf->free = thead->next;
- kfree(thead);
+ while ((p = buf->head) != NULL) {
+ buf->head = p->next;
+ if (p->size > 0)
+ kfree(p);
}
- buf->tail = NULL;
- buf->memory_used = 0;
+ llist = llist_del_all(&buf->free);
+ llist_for_each_entry_safe(p, next, llist, free)
+ kfree(p);
+
+ tty_buffer_reset(&buf->sentinel, 0);
+ buf->head = &buf->sentinel;
+ buf->tail = &buf->sentinel;
+
+ atomic_set(&buf->memory_used, 0);
}
/**
@@ -51,29 +138,39 @@ void tty_buffer_free_all(struct tty_port *port)
* @size: desired size (characters)
*
* Allocate a new tty buffer to hold the desired number of characters.
+ * We round our buffers off in 256 character chunks to get better
+ * allocation behaviour.
* Return NULL if out of memory or the allocation would exceed the
* per device queue
- *
- * Locking: Caller must hold tty->buf.lock
*/
static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
{
+ struct llist_node *free;
struct tty_buffer *p;
- if (port->buf.memory_used + size > 65536)
+ /* Round the buffer size out */
+ size = __ALIGN_MASK(size, TTYB_ALIGN_MASK);
+
+ if (size <= MIN_TTYB_SIZE) {
+ free = llist_del_first(&port->buf.free);
+ if (free) {
+ p = llist_entry(free, struct tty_buffer, free);
+ goto found;
+ }
+ }
+
+ /* Should possibly check if this fails for the largest buffer we
+ have queued and recycle that ? */
+ if (atomic_read(&port->buf.memory_used) > TTYB_MEM_LIMIT)
return NULL;
p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
if (p == NULL)
return NULL;
- p->used = 0;
- p->size = size;
- p->next = NULL;
- p->commit = 0;
- p->read = 0;
- p->char_buf_ptr = (char *)(p->data);
- p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
- port->buf.memory_used += size;
+
+found:
+ tty_buffer_reset(p, size);
+ atomic_add(size, &port->buf.memory_used);
return p;
}
@@ -84,8 +181,6 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
*
* Free a tty buffer, or add it to the free list according to our
* internal strategy
- *
- * Locking: Caller must hold tty->buf.lock
*/
static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
@@ -93,41 +188,12 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
struct tty_bufhead *buf = &port->buf;
/* Dumb strategy for now - should keep some stats */
- buf->memory_used -= b->size;
- WARN_ON(buf->memory_used < 0);
+ WARN_ON(atomic_sub_return(b->size, &buf->memory_used) < 0);
- if (b->size >= 512)
+ if (b->size > MIN_TTYB_SIZE)
kfree(b);
- else {
- b->next = buf->free;
- buf->free = b;
- }
-}
-
-/**
- * __tty_buffer_flush - flush full tty buffers
- * @tty: tty to flush
- *
- * flush all the buffers containing receive data. Caller must
- * hold the buffer lock and must have ensured no parallel flush to
- * ldisc is running.
- *
- * Locking: Caller must hold tty->buf.lock
- */
-
-static void __tty_buffer_flush(struct tty_port *port)
-{
- struct tty_bufhead *buf = &port->buf;
- struct tty_buffer *thead;
-
- if (unlikely(buf->head == NULL))
- return;
- while ((thead = buf->head->next) != NULL) {
- tty_buffer_free(port, buf->head);
- buf->head = thead;
- }
- WARN_ON(buf->head != buf->tail);
- buf->head->read = buf->head->commit;
+ else if (b->size > 0)
+ llist_add(&b->free, &buf->free);
}
/**
@@ -138,65 +204,28 @@ static void __tty_buffer_flush(struct tty_port *port)
* being processed by flush_to_ldisc then we defer the processing
* to that function
*
- * Locking: none
+ * Locking: takes buffer lock to ensure single-threaded flip buffer
+ * 'consumer'
*/
void tty_buffer_flush(struct tty_struct *tty)
{
struct tty_port *port = tty->port;
struct tty_bufhead *buf = &port->buf;
- unsigned long flags;
-
- spin_lock_irqsave(&buf->lock, flags);
-
- /* If the data is being pushed to the tty layer then we can't
- process it here. Instead set a flag and the flush_to_ldisc
- path will process the flush request before it exits */
- if (test_bit(TTYP_FLUSHING, &port->iflags)) {
- set_bit(TTYP_FLUSHPENDING, &port->iflags);
- spin_unlock_irqrestore(&buf->lock, flags);
- wait_event(tty->read_wait,
- test_bit(TTYP_FLUSHPENDING, &port->iflags) == 0);
- return;
- } else
- __tty_buffer_flush(port);
- spin_unlock_irqrestore(&buf->lock, flags);
-}
+ struct tty_buffer *next;
-/**
- * tty_buffer_find - find a free tty buffer
- * @tty: tty owning the buffer
- * @size: characters wanted
- *
- * Locate an existing suitable tty buffer or if we are lacking one then
- * allocate a new one. We round our buffers off in 256 character chunks
- * to get better allocation behaviour.
- *
- * Locking: Caller must hold tty->buf.lock
- */
+ atomic_inc(&buf->priority);
-static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size)
-{
- struct tty_buffer **tbh = &port->buf.free;
- while ((*tbh) != NULL) {
- struct tty_buffer *t = *tbh;
- if (t->size >= size) {
- *tbh = t->next;
- t->next = NULL;
- t->used = 0;
- t->commit = 0;
- t->read = 0;
- port->buf.memory_used += t->size;
- return t;
- }
- tbh = &((*tbh)->next);
+ mutex_lock(&buf->lock);
+ while ((next = buf->head->next) != NULL) {
+ tty_buffer_free(port, buf->head);
+ buf->head = next;
}
- /* Round the buffer size out */
- size = (size + 0xFF) & ~0xFF;
- return tty_buffer_alloc(port, size);
- /* Should possibly check if this fails for the largest buffer we
- have queued and recycle that ? */
+ buf->head->read = buf->head->commit;
+ atomic_dec(&buf->priority);
+ mutex_unlock(&buf->lock);
}
+
/**
* tty_buffer_request_room - grow tty buffer if needed
* @tty: tty structure
@@ -204,38 +233,26 @@ static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size)
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
- *
- * Locking: Takes port->buf.lock
*/
int tty_buffer_request_room(struct tty_port *port, size_t size)
{
struct tty_bufhead *buf = &port->buf;
struct tty_buffer *b, *n;
int left;
- unsigned long flags;
- spin_lock_irqsave(&buf->lock, flags);
- /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
- remove this conditional if its worth it. This would be invisible
- to the callers */
+
b = buf->tail;
- if (b != NULL)
- left = b->size - b->used;
- else
- left = 0;
+ left = b->size - b->used;
if (left < size) {
/* This is the slow path - looking for new buffers to use */
- if ((n = tty_buffer_find(port, size)) != NULL) {
- if (b != NULL) {
- b->next = n;
- b->commit = b->used;
- } else
- buf->head = n;
+ if ((n = tty_buffer_alloc(port, size)) != NULL) {
buf->tail = n;
+ b->commit = b->used;
+ smp_mb();
+ b->next = n;
} else
size = left;
}
- spin_unlock_irqrestore(&buf->lock, flags);
return size;
}
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
@@ -249,8 +266,6 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room);
*
* Queue a series of bytes to the tty buffering. All the characters
* passed are marked with the supplied flag. Returns the number added.
- *
- * Locking: Called functions may take port->buf.lock
*/
int tty_insert_flip_string_fixed_flag(struct tty_port *port,
@@ -261,12 +276,10 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port,
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int space = tty_buffer_request_room(port, goal);
struct tty_buffer *tb = port->buf.tail;
- /* If there is no space then tb may be NULL */
- if (unlikely(space == 0)) {
+ if (unlikely(space == 0))
break;
- }
- memcpy(tb->char_buf_ptr + tb->used, chars, space);
- memset(tb->flag_buf_ptr + tb->used, flag, space);
+ memcpy(char_buf_ptr(tb, tb->used), chars, space);
+ memset(flag_buf_ptr(tb, tb->used), flag, space);
tb->used += space;
copied += space;
chars += space;
@@ -287,8 +300,6 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
* Queue a series of bytes to the tty buffering. For each character
* the flags array indicates the status of the character. Returns the
* number added.
- *
- * Locking: Called functions may take port->buf.lock
*/
int tty_insert_flip_string_flags(struct tty_port *port,
@@ -299,12 +310,10 @@ int tty_insert_flip_string_flags(struct tty_port *port,
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int space = tty_buffer_request_room(port, goal);
struct tty_buffer *tb = port->buf.tail;
- /* If there is no space then tb may be NULL */
- if (unlikely(space == 0)) {
+ if (unlikely(space == 0))
break;
- }
- memcpy(tb->char_buf_ptr + tb->used, chars, space);
- memcpy(tb->flag_buf_ptr + tb->used, flags, space);
+ memcpy(char_buf_ptr(tb, tb->used), chars, space);
+ memcpy(flag_buf_ptr(tb, tb->used), flags, space);
tb->used += space;
copied += space;
chars += space;
@@ -325,20 +334,14 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags);
* processing by the line discipline.
* Note that this function can only be used when the low_latency flag
* is unset. Otherwise the workqueue won't be flushed.
- *
- * Locking: Takes port->buf.lock
*/
void tty_schedule_flip(struct tty_port *port)
{
struct tty_bufhead *buf = &port->buf;
- unsigned long flags;
WARN_ON(port->low_latency);
- spin_lock_irqsave(&buf->lock, flags);
- if (buf->tail != NULL)
- buf->tail->commit = buf->tail->used;
- spin_unlock_irqrestore(&buf->lock, flags);
+ buf->tail->commit = buf->tail->used;
schedule_work(&buf->work);
}
EXPORT_SYMBOL(tty_schedule_flip);
@@ -354,8 +357,6 @@ EXPORT_SYMBOL(tty_schedule_flip);
* accounted for as ready for normal characters. This is used for drivers
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
- *
- * Locking: May call functions taking port->buf.lock
*/
int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
@@ -364,8 +365,8 @@ int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
int space = tty_buffer_request_room(port, size);
if (likely(space)) {
struct tty_buffer *tb = port->buf.tail;
- *chars = tb->char_buf_ptr + tb->used;
- memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+ *chars = char_buf_ptr(tb, tb->used);
+ memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
tb->used += space;
}
return space;
@@ -384,8 +385,6 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
* accounted for as ready for characters. This is used for drivers
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
- *
- * Locking: May call functions taking port->buf.lock
*/
int tty_prepare_flip_string_flags(struct tty_port *port,
@@ -394,8 +393,8 @@ int tty_prepare_flip_string_flags(struct tty_port *port,
int space = tty_buffer_request_room(port, size);
if (likely(space)) {
struct tty_buffer *tb = port->buf.tail;
- *chars = tb->char_buf_ptr + tb->used;
- *flags = tb->flag_buf_ptr + tb->used;
+ *chars = char_buf_ptr(tb, tb->used);
+ *flags = flag_buf_ptr(tb, tb->used);
tb->used += space;
}
return space;
@@ -403,6 +402,23 @@ int tty_prepare_flip_string_flags(struct tty_port *port,
EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
+static int
+receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
+{
+ struct tty_ldisc *disc = tty->ldisc;
+ unsigned char *p = char_buf_ptr(head, head->read);
+ char *f = flag_buf_ptr(head, head->read);
+
+ if (disc->ops->receive_buf2)
+ count = disc->ops->receive_buf2(tty, p, f, count);
+ else {
+ count = min_t(int, count, tty->receive_room);
+ if (count)
+ disc->ops->receive_buf(tty, p, f, count);
+ }
+ head->read += count;
+ return count;
+}
/**
* flush_to_ldisc
@@ -411,9 +427,10 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
* This routine is called out of the software interrupt to flush data
* from the buffer chain to the line discipline.
*
- * Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- * while invoking the line discipline receive_buf method. The
- * receive_buf method is single threaded for each tty instance.
+ * The receive_buf method is single threaded for each tty instance.
+ *
+ * Locking: takes buffer lock to ensure single-threaded flip buffer
+ * 'consumer'
*/
static void flush_to_ldisc(struct work_struct *work)
@@ -421,7 +438,6 @@ static void flush_to_ldisc(struct work_struct *work)
struct tty_port *port = container_of(work, struct tty_port, buf.work);
struct tty_bufhead *buf = &port->buf;
struct tty_struct *tty;
- unsigned long flags;
struct tty_ldisc *disc;
tty = port->itty;
@@ -429,52 +445,34 @@ static void flush_to_ldisc(struct work_struct *work)
return;
disc = tty_ldisc_ref(tty);
- if (disc == NULL) /* !TTY_LDISC */
+ if (disc == NULL)
return;
- spin_lock_irqsave(&buf->lock, flags);
-
- if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) {
- struct tty_buffer *head;
- while ((head = buf->head) != NULL) {
- int count;
- char *char_buf;
- unsigned char *flag_buf;
-
- count = head->commit - head->read;
- if (!count) {
- if (head->next == NULL)
- break;
- buf->head = head->next;
- tty_buffer_free(port, head);
- continue;
- }
- if (!tty->receive_room)
- break;
- if (count > tty->receive_room)
- count = tty->receive_room;
- char_buf = head->char_buf_ptr + head->read;
- flag_buf = head->flag_buf_ptr + head->read;
- head->read += count;
- spin_unlock_irqrestore(&buf->lock, flags);
- disc->ops->receive_buf(tty, char_buf,
- flag_buf, count);
- spin_lock_irqsave(&buf->lock, flags);
- /* Ldisc or user is trying to flush the buffers.
- We may have a deferred request to flush the
- input buffer, if so pull the chain under the lock
- and empty the queue */
- if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
- __tty_buffer_flush(port);
- clear_bit(TTYP_FLUSHPENDING, &port->iflags);
- wake_up(&tty->read_wait);
+ mutex_lock(&buf->lock);
+
+ while (1) {
+ struct tty_buffer *head = buf->head;
+ int count;
+
+ /* Ldisc or user is trying to gain exclusive access */
+ if (atomic_read(&buf->priority))
+ break;
+
+ count = head->commit - head->read;
+ if (!count) {
+ if (head->next == NULL)
break;
- }
+ buf->head = head->next;
+ tty_buffer_free(port, head);
+ continue;
}
- clear_bit(TTYP_FLUSHING, &port->iflags);
+
+ count = receive_buf(tty, head, count);
+ if (!count)
+ break;
}
- spin_unlock_irqrestore(&buf->lock, flags);
+ mutex_unlock(&buf->lock);
tty_ldisc_deref(disc);
}
@@ -503,19 +501,13 @@ void tty_flush_to_ldisc(struct tty_struct *tty)
*
* In the event of the queue being busy for flipping the work will be
* held off and retried later.
- *
- * Locking: tty buffer lock. Driver locks in low latency mode.
*/
void tty_flip_buffer_push(struct tty_port *port)
{
struct tty_bufhead *buf = &port->buf;
- unsigned long flags;
- spin_lock_irqsave(&buf->lock, flags);
- if (buf->tail != NULL)
- buf->tail->commit = buf->tail->used;
- spin_unlock_irqrestore(&buf->lock, flags);
+ buf->tail->commit = buf->tail->used;
if (port->low_latency)
flush_to_ldisc(&buf->work);
@@ -530,19 +522,18 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
*
* Set up the initial state of the buffer management for a tty device.
* Must be called before the other tty buffer functions are used.
- *
- * Locking: none
*/
void tty_buffer_init(struct tty_port *port)
{
struct tty_bufhead *buf = &port->buf;
- spin_lock_init(&buf->lock);
- buf->head = NULL;
- buf->tail = NULL;
- buf->free = NULL;
- buf->memory_used = 0;
+ mutex_init(&buf->lock);
+ tty_buffer_reset(&buf->sentinel, 0);
+ buf->head = &buf->sentinel;
+ buf->tail = &buf->sentinel;
+ init_llist_head(&buf->free);
+ atomic_set(&buf->memory_used, 0);
+ atomic_set(&buf->priority, 0);
INIT_WORK(&buf->work, flush_to_ldisc);
}
-
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 366af832794..a9355ce1c6d 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -603,8 +603,8 @@ static int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
* BTM
* redirect lock for undoing redirection
* file list lock for manipulating list of ttys
- * tty_ldisc_lock from called functions
- * termios_mutex resetting termios data
+ * tty_ldiscs_lock from called functions
+ * termios_rwsem resetting termios data
* tasklist_lock to walk task list for hangup event
* ->siglock to protect ->signal/->sighand
*/
@@ -629,6 +629,11 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
tty_lock(tty);
+ if (test_bit(TTY_HUPPED, &tty->flags)) {
+ tty_unlock(tty);
+ return;
+ }
+
/* some functions below drop BTM, so we need this bit */
set_bit(TTY_HUPPING, &tty->flags);
@@ -664,7 +669,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
spin_lock_irq(&tty->ctrl_lock);
clear_bit(TTY_THROTTLED, &tty->flags);
- clear_bit(TTY_PUSH, &tty->flags);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
put_pid(tty->session);
put_pid(tty->pgrp);
@@ -1388,8 +1392,7 @@ static int tty_reopen(struct tty_struct *tty)
struct tty_driver *driver = tty->driver;
if (test_bit(TTY_CLOSING, &tty->flags) ||
- test_bit(TTY_HUPPING, &tty->flags) ||
- test_bit(TTY_LDISC_CHANGING, &tty->flags))
+ test_bit(TTY_HUPPING, &tty->flags))
return -EIO;
if (driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -1405,7 +1408,7 @@ static int tty_reopen(struct tty_struct *tty)
}
tty->count++;
- WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+ WARN_ON(!tty->ldisc);
return 0;
}
@@ -2202,7 +2205,7 @@ static int tty_fasync(int fd, struct file *filp, int on)
* FIXME: does not honour flow control ??
*
* Locking:
- * Called functions take tty_ldisc_lock
+ * Called functions take tty_ldiscs_lock
* current->signal->tty check is safe without locks
*
* FIXME: may race normal receive processing
@@ -2231,7 +2234,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
*
* Copies the kernel idea of the window size into the user buffer.
*
- * Locking: tty->termios_mutex is taken to ensure the winsize data
+ * Locking: tty->winsize_mutex is taken to ensure the winsize data
* is consistent.
*/
@@ -2239,9 +2242,9 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
{
int err;
- mutex_lock(&tty->termios_mutex);
+ mutex_lock(&tty->winsize_mutex);
err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
- mutex_unlock(&tty->termios_mutex);
+ mutex_unlock(&tty->winsize_mutex);
return err ? -EFAULT: 0;
}
@@ -2262,7 +2265,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
unsigned long flags;
/* Lock the tty */
- mutex_lock(&tty->termios_mutex);
+ mutex_lock(&tty->winsize_mutex);
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
goto done;
/* Get the PID values and reference them so we can
@@ -2277,7 +2280,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
tty->winsize = *ws;
done:
- mutex_unlock(&tty->termios_mutex);
+ mutex_unlock(&tty->winsize_mutex);
return 0;
}
EXPORT_SYMBOL(tty_do_resize);
@@ -3016,8 +3019,10 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->session = NULL;
tty->pgrp = NULL;
mutex_init(&tty->legacy_mutex);
- mutex_init(&tty->termios_mutex);
- mutex_init(&tty->ldisc_mutex);
+ mutex_init(&tty->throttle_mutex);
+ init_rwsem(&tty->termios_rwsem);
+ mutex_init(&tty->winsize_mutex);
+ init_ldsem(&tty->ldisc_sem);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup);
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 3500d411414..03ba081c577 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -94,20 +94,20 @@ EXPORT_SYMBOL(tty_driver_flush_buffer);
* @tty: terminal
*
* Indicate that a tty should stop transmitting data down the stack.
- * Takes the termios mutex to protect against parallel throttle/unthrottle
+ * Takes the termios rwsem to protect against parallel throttle/unthrottle
* and also to ensure the driver can consistently reference its own
* termios data at this point when implementing software flow control.
*/
void tty_throttle(struct tty_struct *tty)
{
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
/* check TTY_THROTTLED first so it indicates our state */
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->throttle)
tty->ops->throttle(tty);
tty->flow_change = 0;
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
}
EXPORT_SYMBOL(tty_throttle);
@@ -116,7 +116,7 @@ EXPORT_SYMBOL(tty_throttle);
* @tty: terminal
*
* Indicate that a tty may continue transmitting data down the stack.
- * Takes the termios mutex to protect against parallel throttle/unthrottle
+ * Takes the termios rwsem to protect against parallel throttle/unthrottle
* and also to ensure the driver can consistently reference its own
* termios data at this point when implementing software flow control.
*
@@ -126,12 +126,12 @@ EXPORT_SYMBOL(tty_throttle);
void tty_unthrottle(struct tty_struct *tty)
{
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->unthrottle)
tty->ops->unthrottle(tty);
tty->flow_change = 0;
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
}
EXPORT_SYMBOL(tty_unthrottle);
@@ -151,7 +151,7 @@ int tty_throttle_safe(struct tty_struct *tty)
{
int ret = 0;
- mutex_lock(&tty->termios_mutex);
+ mutex_lock(&tty->throttle_mutex);
if (!test_bit(TTY_THROTTLED, &tty->flags)) {
if (tty->flow_change != TTY_THROTTLE_SAFE)
ret = 1;
@@ -161,7 +161,7 @@ int tty_throttle_safe(struct tty_struct *tty)
tty->ops->throttle(tty);
}
}
- mutex_unlock(&tty->termios_mutex);
+ mutex_unlock(&tty->throttle_mutex);
return ret;
}
@@ -182,7 +182,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
{
int ret = 0;
- mutex_lock(&tty->termios_mutex);
+ mutex_lock(&tty->throttle_mutex);
if (test_bit(TTY_THROTTLED, &tty->flags)) {
if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
ret = 1;
@@ -192,7 +192,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
tty->ops->unthrottle(tty);
}
}
- mutex_unlock(&tty->termios_mutex);
+ mutex_unlock(&tty->throttle_mutex);
return ret;
}
@@ -468,7 +468,7 @@ EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
* @obad: output baud rate
*
* Update the current termios data for the tty with the new speed
- * settings. The caller must hold the termios_mutex for the tty in
+ * settings. The caller must hold the termios_rwsem for the tty in
* question.
*/
@@ -528,7 +528,7 @@ EXPORT_SYMBOL(tty_termios_hw_change);
* is a bit of layering violation here with n_tty in terms of the
* internal knowledge of this function.
*
- * Locking: termios_mutex
+ * Locking: termios_rwsem
*/
int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
@@ -544,7 +544,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
/* FIXME: we need to decide on some locking/ordering semantics
for the set_termios notification eventually */
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
old_termios = tty->termios;
tty->termios = *new_termios;
unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
@@ -586,7 +586,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
(ld->ops->set_termios)(tty, &old_termios);
tty_ldisc_deref(ld);
}
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
return 0;
}
EXPORT_SYMBOL_GPL(tty_set_termios);
@@ -601,7 +601,7 @@ EXPORT_SYMBOL_GPL(tty_set_termios);
* functions before using tty_set_termios to do the actual changes.
*
* Locking:
- * Called functions take ldisc and termios_mutex locks
+ * Called functions take ldisc and termios_rwsem locks
*/
static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
@@ -613,9 +613,9 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
if (retval)
return retval;
- mutex_lock(&tty->termios_mutex);
+ down_read(&tty->termios_rwsem);
tmp_termios = tty->termios;
- mutex_unlock(&tty->termios_mutex);
+ up_read(&tty->termios_rwsem);
if (opt & TERMIOS_TERMIO) {
if (user_termio_to_kernel_termios(&tmp_termios,
@@ -667,16 +667,16 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
{
- mutex_lock(&tty->termios_mutex);
+ down_read(&tty->termios_rwsem);
*kterm = tty->termios;
- mutex_unlock(&tty->termios_mutex);
+ up_read(&tty->termios_rwsem);
}
static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
{
- mutex_lock(&tty->termios_mutex);
+ down_read(&tty->termios_rwsem);
*kterm = tty->termios_locked;
- mutex_unlock(&tty->termios_mutex);
+ up_read(&tty->termios_rwsem);
}
static int get_termio(struct tty_struct *tty, struct termio __user *termio)
@@ -723,10 +723,10 @@ static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
return -ERESTARTSYS;
}
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
if (tty->ops->set_termiox)
tty->ops->set_termiox(tty, &tnew);
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
return 0;
}
@@ -761,13 +761,13 @@ static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
{
struct sgttyb tmp;
- mutex_lock(&tty->termios_mutex);
+ down_read(&tty->termios_rwsem);
tmp.sg_ispeed = tty->termios.c_ispeed;
tmp.sg_ospeed = tty->termios.c_ospeed;
tmp.sg_erase = tty->termios.c_cc[VERASE];
tmp.sg_kill = tty->termios.c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
- mutex_unlock(&tty->termios_mutex);
+ up_read(&tty->termios_rwsem);
return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -806,7 +806,7 @@ static void set_sgflags(struct ktermios *termios, int flags)
* Updates a terminal from the legacy BSD style terminal information
* structure.
*
- * Locking: termios_mutex
+ * Locking: termios_rwsem
*/
static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
@@ -822,7 +822,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
return -EFAULT;
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
termios = tty->termios;
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
@@ -832,7 +832,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
termios.c_ospeed);
#endif
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
tty_set_termios(tty, &termios);
return 0;
}
@@ -843,14 +843,14 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
{
struct tchars tmp;
- mutex_lock(&tty->termios_mutex);
+ down_read(&tty->termios_rwsem);
tmp.t_intrc = tty->termios.c_cc[VINTR];
tmp.t_quitc = tty->termios.c_cc[VQUIT];
tmp.t_startc = tty->termios.c_cc[VSTART];
tmp.t_stopc = tty->termios.c_cc[VSTOP];
tmp.t_eofc = tty->termios.c_cc[VEOF];
tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */
- mutex_unlock(&tty->termios_mutex);
+ up_read(&tty->termios_rwsem);
return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -860,14 +860,14 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
if (copy_from_user(&tmp, tchars, sizeof(tmp)))
return -EFAULT;
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
tty->termios.c_cc[VINTR] = tmp.t_intrc;
tty->termios.c_cc[VQUIT] = tmp.t_quitc;
tty->termios.c_cc[VSTART] = tmp.t_startc;
tty->termios.c_cc[VSTOP] = tmp.t_stopc;
tty->termios.c_cc[VEOF] = tmp.t_eofc;
tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
return 0;
}
#endif
@@ -877,7 +877,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
{
struct ltchars tmp;
- mutex_lock(&tty->termios_mutex);
+ down_read(&tty->termios_rwsem);
tmp.t_suspc = tty->termios.c_cc[VSUSP];
/* what is dsuspc anyway? */
tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
@@ -886,7 +886,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
tmp.t_flushc = tty->termios.c_cc[VEOL2];
tmp.t_werasc = tty->termios.c_cc[VWERASE];
tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
- mutex_unlock(&tty->termios_mutex);
+ up_read(&tty->termios_rwsem);
return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -897,7 +897,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
return -EFAULT;
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
tty->termios.c_cc[VSUSP] = tmp.t_suspc;
/* what is dsuspc anyway? */
tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
@@ -906,7 +906,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
tty->termios.c_cc[VEOL2] = tmp.t_flushc;
tty->termios.c_cc[VWERASE] = tmp.t_werasc;
tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
return 0;
}
#endif
@@ -946,7 +946,7 @@ static int send_prio_char(struct tty_struct *tty, char ch)
* @arg: enable/disable CLOCAL
*
* Perform a change to the CLOCAL state and call into the driver
- * layer to make it visible. All done with the termios mutex
+ * layer to make it visible. All done with the termios rwsem
*/
static int tty_change_softcar(struct tty_struct *tty, int arg)
@@ -955,7 +955,7 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
int bit = arg ? CLOCAL : 0;
struct ktermios old;
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
old = tty->termios;
tty->termios.c_cflag &= ~CLOCAL;
tty->termios.c_cflag |= bit;
@@ -963,7 +963,7 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
tty->ops->set_termios(tty, &old);
if ((tty->termios.c_cflag & CLOCAL) != bit)
ret = -EINVAL;
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
return ret;
}
@@ -1066,9 +1066,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
if (user_termios_to_kernel_termios(&kterm,
(struct termios __user *) arg))
return -EFAULT;
- mutex_lock(&real_tty->termios_mutex);
+ down_write(&real_tty->termios_rwsem);
real_tty->termios_locked = kterm;
- mutex_unlock(&real_tty->termios_mutex);
+ up_write(&real_tty->termios_rwsem);
return 0;
#else
case TIOCGLCKTRMIOS:
@@ -1083,9 +1083,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
if (user_termios_to_kernel_termios_1(&kterm,
(struct termios __user *) arg))
return -EFAULT;
- mutex_lock(&real_tty->termios_mutex);
+ down_write(&real_tty->termios_rwsem);
real_tty->termios_locked = kterm;
- mutex_unlock(&real_tty->termios_mutex);
+ up_write(&real_tty->termios_rwsem);
return ret;
#endif
#ifdef TCGETX
@@ -1093,9 +1093,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
struct termiox ktermx;
if (real_tty->termiox == NULL)
return -EINVAL;
- mutex_lock(&real_tty->termios_mutex);
+ down_read(&real_tty->termios_rwsem);
memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
- mutex_unlock(&real_tty->termios_mutex);
+ up_read(&real_tty->termios_rwsem);
if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
ret = -EFAULT;
return ret;
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 1afe192bef6..6458e11e8e9 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -31,14 +31,20 @@
#define tty_ldisc_debug(tty, f, args...)
#endif
+/* lockdep nested classes for tty->ldisc_sem */
+enum {
+ LDISC_SEM_NORMAL,
+ LDISC_SEM_OTHER,
+};
+
+
/*
* This guards the refcounted line discipline lists. The lock
* must be taken with irqs off because there are hangup path
* callers who will do ldisc lookups and cannot sleep.
*/
-static DEFINE_RAW_SPINLOCK(tty_ldisc_lock);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
+static DEFINE_RAW_SPINLOCK(tty_ldiscs_lock);
/* Line disc dispatch table */
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
@@ -52,7 +58,7 @@ static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
* from this point onwards.
*
* Locking:
- * takes tty_ldisc_lock to guard against ldisc races
+ * takes tty_ldiscs_lock to guard against ldisc races
*/
int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
@@ -63,11 +69,11 @@ int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
if (disc < N_TTY || disc >= NR_LDISCS)
return -EINVAL;
- raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+ raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
tty_ldiscs[disc] = new_ldisc;
new_ldisc->num = disc;
new_ldisc->refcount = 0;
- raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
return ret;
}
@@ -82,7 +88,7 @@ EXPORT_SYMBOL(tty_register_ldisc);
* currently in use.
*
* Locking:
- * takes tty_ldisc_lock to guard against ldisc races
+ * takes tty_ldiscs_lock to guard against ldisc races
*/
int tty_unregister_ldisc(int disc)
@@ -93,12 +99,12 @@ int tty_unregister_ldisc(int disc)
if (disc < N_TTY || disc >= NR_LDISCS)
return -EINVAL;
- raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+ raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
if (tty_ldiscs[disc]->refcount)
ret = -EBUSY;
else
tty_ldiscs[disc] = NULL;
- raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
return ret;
}
@@ -109,7 +115,7 @@ static struct tty_ldisc_ops *get_ldops(int disc)
unsigned long flags;
struct tty_ldisc_ops *ldops, *ret;
- raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+ raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
ret = ERR_PTR(-EINVAL);
ldops = tty_ldiscs[disc];
if (ldops) {
@@ -119,7 +125,7 @@ static struct tty_ldisc_ops *get_ldops(int disc)
ret = ldops;
}
}
- raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
return ret;
}
@@ -127,10 +133,10 @@ static void put_ldops(struct tty_ldisc_ops *ldops)
{
unsigned long flags;
- raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+ raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
ldops->refcount--;
module_put(ldops->owner);
- raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
}
/**
@@ -143,10 +149,10 @@ static void put_ldops(struct tty_ldisc_ops *ldops)
* available
*
* Locking:
- * takes tty_ldisc_lock to guard against ldisc races
+ * takes tty_ldiscs_lock to guard against ldisc races
*/
-static struct tty_ldisc *tty_ldisc_get(int disc)
+static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
{
struct tty_ldisc *ld;
struct tty_ldisc_ops *ldops;
@@ -173,8 +179,7 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
}
ld->ops = ldops;
- atomic_set(&ld->users, 1);
- init_waitqueue_head(&ld->wq_idle);
+ ld->tty = tty;
return ld;
}
@@ -186,20 +191,11 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
*/
static inline void tty_ldisc_put(struct tty_ldisc *ld)
{
- unsigned long flags;
-
if (WARN_ON_ONCE(!ld))
return;
- raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
-
- /* unreleased reader reference(s) will cause this WARN */
- WARN_ON(!atomic_dec_and_test(&ld->users));
-
- ld->ops->refcount--;
- module_put(ld->ops->owner);
+ put_ldops(ld->ops);
kfree(ld);
- raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
}
static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
@@ -251,34 +247,6 @@ const struct file_operations tty_ldiscs_proc_fops = {
};
/**
- * tty_ldisc_try - internal helper
- * @tty: the tty
- *
- * Make a single attempt to grab and bump the refcount on
- * the tty ldisc. Return 0 on failure or 1 on success. This is
- * used to implement both the waiting and non waiting versions
- * of tty_ldisc_ref
- *
- * Locking: takes tty_ldisc_lock
- */
-
-static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
-{
- unsigned long flags;
- struct tty_ldisc *ld;
-
- /* FIXME: this allows reference acquire after TTY_LDISC is cleared */
- raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
- ld = NULL;
- if (test_bit(TTY_LDISC, &tty->flags) && tty->ldisc) {
- ld = tty->ldisc;
- atomic_inc(&ld->users);
- }
- raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- return ld;
-}
-
-/**
* tty_ldisc_ref_wait - wait for the tty ldisc
* @tty: tty device
*
@@ -291,16 +259,15 @@ static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
* against a discipline change, such as an existing ldisc reference
* (which we check for)
*
- * Locking: call functions take tty_ldisc_lock
+ * Note: only callable from a file_operations routine (which
+ * guarantees tty->ldisc != NULL when the lock is acquired).
*/
struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
{
- struct tty_ldisc *ld;
-
- /* wait_event is a macro */
- wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
- return ld;
+ ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT);
+ WARN_ON(!tty->ldisc);
+ return tty->ldisc;
}
EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
@@ -311,13 +278,18 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
* Dereference the line discipline for the terminal and take a
* reference to it. If the line discipline is in flux then
* return NULL. Can be called from IRQ and timer functions.
- *
- * Locking: called functions take tty_ldisc_lock
*/
struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
{
- return tty_ldisc_try(tty);
+ struct tty_ldisc *ld = NULL;
+
+ if (ldsem_down_read_trylock(&tty->ldisc_sem)) {
+ ld = tty->ldisc;
+ if (!ld)
+ ldsem_up_read(&tty->ldisc_sem);
+ }
+ return ld;
}
EXPORT_SYMBOL_GPL(tty_ldisc_ref);
@@ -327,48 +299,91 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
*
* Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
* be called in IRQ context.
- *
- * Locking: takes tty_ldisc_lock
*/
void tty_ldisc_deref(struct tty_ldisc *ld)
{
- unsigned long flags;
+ ldsem_up_read(&ld->tty->ldisc_sem);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_deref);
- if (WARN_ON_ONCE(!ld))
- return;
- raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
- /*
- * WARNs if one-too-many reader references were released
- * - the last reference must be released with tty_ldisc_put
- */
- WARN_ON(atomic_dec_and_test(&ld->users));
- raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+static inline int __lockfunc
+tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
+{
+ return ldsem_down_write(&tty->ldisc_sem, timeout);
+}
- if (waitqueue_active(&ld->wq_idle))
- wake_up(&ld->wq_idle);
+static inline int __lockfunc
+tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
+{
+ return ldsem_down_write_nested(&tty->ldisc_sem,
+ LDISC_SEM_OTHER, timeout);
}
-EXPORT_SYMBOL_GPL(tty_ldisc_deref);
-/**
- * tty_ldisc_enable - allow ldisc use
- * @tty: terminal to activate ldisc on
- *
- * Set the TTY_LDISC flag when the line discipline can be called
- * again. Do necessary wakeups for existing sleepers. Clear the LDISC
- * changing flag to indicate any ldisc change is now over.
- *
- * Note: nobody should set the TTY_LDISC bit except via this function.
- * Clearing directly is allowed.
- */
+static inline void tty_ldisc_unlock(struct tty_struct *tty)
+{
+ return ldsem_up_write(&tty->ldisc_sem);
+}
-static void tty_ldisc_enable(struct tty_struct *tty)
+static int __lockfunc
+tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
+ unsigned long timeout)
+{
+ int ret;
+
+ if (tty < tty2) {
+ ret = tty_ldisc_lock(tty, timeout);
+ if (ret) {
+ ret = tty_ldisc_lock_nested(tty2, timeout);
+ if (!ret)
+ tty_ldisc_unlock(tty);
+ }
+ } else {
+ /* if this is possible, it has lots of implications */
+ WARN_ON_ONCE(tty == tty2);
+ if (tty2 && tty != tty2) {
+ ret = tty_ldisc_lock(tty2, timeout);
+ if (ret) {
+ ret = tty_ldisc_lock_nested(tty, timeout);
+ if (!ret)
+ tty_ldisc_unlock(tty2);
+ }
+ } else
+ ret = tty_ldisc_lock(tty, timeout);
+ }
+
+ if (!ret)
+ return -EBUSY;
+
+ set_bit(TTY_LDISC_HALTED, &tty->flags);
+ if (tty2)
+ set_bit(TTY_LDISC_HALTED, &tty2->flags);
+ return 0;
+}
+
+static void __lockfunc
+tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
+{
+ tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT);
+}
+
+static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2)
+{
+ tty_ldisc_unlock(tty);
+ if (tty2)
+ tty_ldisc_unlock(tty2);
+}
+
+static void __lockfunc tty_ldisc_enable_pair(struct tty_struct *tty,
+ struct tty_struct *tty2)
{
clear_bit(TTY_LDISC_HALTED, &tty->flags);
- set_bit(TTY_LDISC, &tty->flags);
- clear_bit(TTY_LDISC_CHANGING, &tty->flags);
- wake_up(&tty_ldisc_wait);
+ if (tty2)
+ clear_bit(TTY_LDISC_HALTED, &tty2->flags);
+
+ tty_ldisc_unlock_pair(tty, tty2);
}
/**
@@ -400,14 +415,14 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
* they are not on hot paths so a little discipline won't do
* any harm.
*
- * Locking: takes termios_mutex
+ * Locking: takes termios_rwsem
*/
static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
{
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
tty->termios.c_line = num;
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
}
/**
@@ -468,14 +483,14 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
int r;
/* There is an outstanding reference here so this is safe */
- old = tty_ldisc_get(old->ops->num);
+ old = tty_ldisc_get(tty, old->ops->num);
WARN_ON(IS_ERR(old));
tty->ldisc = old;
tty_set_termios_ldisc(tty, old->ops->num);
if (tty_ldisc_open(tty, old) < 0) {
tty_ldisc_put(old);
/* This driver is always present */
- new_ldisc = tty_ldisc_get(N_TTY);
+ new_ldisc = tty_ldisc_get(tty, N_TTY);
if (IS_ERR(new_ldisc))
panic("n_tty: get");
tty->ldisc = new_ldisc;
@@ -489,101 +504,6 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
}
/**
- * tty_ldisc_wait_idle - wait for the ldisc to become idle
- * @tty: tty to wait for
- * @timeout: for how long to wait at most
- *
- * Wait for the line discipline to become idle. The discipline must
- * have been halted for this to guarantee it remains idle.
- */
-static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
-{
- long ret;
- ret = wait_event_timeout(tty->ldisc->wq_idle,
- atomic_read(&tty->ldisc->users) == 1, timeout);
- return ret > 0 ? 0 : -EBUSY;
-}
-
-/**
- * tty_ldisc_halt - shut down the line discipline
- * @tty: tty device
- * @o_tty: paired pty device (can be NULL)
- * @timeout: # of jiffies to wait for ldisc refs to be released
- *
- * Shut down the line discipline and work queue for this tty device and
- * its paired pty (if exists). Clearing the TTY_LDISC flag ensures
- * no further references can be obtained, while waiting for existing
- * references to be released ensures no more data is fed to the ldisc.
- *
- * You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
- * in order to make sure any currently executing ldisc work is also
- * flushed.
- */
-
-static int tty_ldisc_halt(struct tty_struct *tty, struct tty_struct *o_tty,
- long timeout)
-{
- int retval;
-
- clear_bit(TTY_LDISC, &tty->flags);
- if (o_tty)
- clear_bit(TTY_LDISC, &o_tty->flags);
-
- retval = tty_ldisc_wait_idle(tty, timeout);
- if (!retval && o_tty)
- retval = tty_ldisc_wait_idle(o_tty, timeout);
- if (retval)
- return retval;
-
- set_bit(TTY_LDISC_HALTED, &tty->flags);
- if (o_tty)
- set_bit(TTY_LDISC_HALTED, &o_tty->flags);
-
- return 0;
-}
-
-/**
- * tty_ldisc_hangup_halt - halt the line discipline for hangup
- * @tty: tty being hung up
- *
- * Shut down the line discipline and work queue for the tty device
- * being hungup. Clear the TTY_LDISC flag to ensure no further
- * references can be obtained and wait for remaining references to be
- * released to ensure no more data is fed to this ldisc.
- * Caller must hold legacy and ->ldisc_mutex.
- *
- * NB: tty_set_ldisc() is prevented from changing the ldisc concurrently
- * with this function by checking the TTY_HUPPING flag.
- */
-static bool tty_ldisc_hangup_halt(struct tty_struct *tty)
-{
- char cur_n[TASK_COMM_LEN], tty_n[64];
- long timeout = 3 * HZ;
-
- clear_bit(TTY_LDISC, &tty->flags);
-
- if (tty->ldisc) { /* Not yet closed */
- tty_unlock(tty);
-
- while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
- timeout = MAX_SCHEDULE_TIMEOUT;
- printk_ratelimited(KERN_WARNING
- "%s: waiting (%s) for %s took too long, but we keep waiting...\n",
- __func__, get_task_comm(cur_n, current),
- tty_name(tty, tty_n));
- }
-
- set_bit(TTY_LDISC_HALTED, &tty->flags);
-
- /* must reacquire both locks and preserve lock order */
- mutex_unlock(&tty->ldisc_mutex);
- tty_lock(tty);
- mutex_lock(&tty->ldisc_mutex);
- }
- return !!tty->ldisc;
-}
-
-/**
* tty_set_ldisc - set line discipline
* @tty: the terminal to set
* @ldisc: the line discipline
@@ -592,110 +512,49 @@ static bool tty_ldisc_hangup_halt(struct tty_struct *tty)
* context. The ldisc change logic has to protect itself against any
* overlapping ldisc change (including on the other end of pty pairs),
* the close of one side of a tty/pty pair, and eventually hangup.
- *
- * Locking: takes tty_ldisc_lock, termios_mutex
*/
int tty_set_ldisc(struct tty_struct *tty, int ldisc)
{
int retval;
- struct tty_ldisc *o_ldisc, *new_ldisc;
- struct tty_struct *o_tty;
+ struct tty_ldisc *old_ldisc, *new_ldisc;
+ struct tty_struct *o_tty = tty->link;
- new_ldisc = tty_ldisc_get(ldisc);
+ new_ldisc = tty_ldisc_get(tty, ldisc);
if (IS_ERR(new_ldisc))
return PTR_ERR(new_ldisc);
- tty_lock(tty);
- /*
- * We need to look at the tty locking here for pty/tty pairs
- * when both sides try to change in parallel.
- */
-
- o_tty = tty->link; /* o_tty is the pty side or NULL */
-
+ retval = tty_ldisc_lock_pair_timeout(tty, o_tty, 5 * HZ);
+ if (retval) {
+ tty_ldisc_put(new_ldisc);
+ return retval;
+ }
/*
* Check the no-op case
*/
if (tty->ldisc->ops->num == ldisc) {
- tty_unlock(tty);
+ tty_ldisc_enable_pair(tty, o_tty);
tty_ldisc_put(new_ldisc);
return 0;
}
- mutex_lock(&tty->ldisc_mutex);
-
- /*
- * We could be midstream of another ldisc change which has
- * dropped the lock during processing. If so we need to wait.
- */
-
- while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
- mutex_unlock(&tty->ldisc_mutex);
- tty_unlock(tty);
- wait_event(tty_ldisc_wait,
- test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
- tty_lock(tty);
- mutex_lock(&tty->ldisc_mutex);
- }
-
- set_bit(TTY_LDISC_CHANGING, &tty->flags);
-
- /*
- * No more input please, we are switching. The new ldisc
- * will update this value in the ldisc open function
- */
-
- tty->receive_room = 0;
-
- o_ldisc = tty->ldisc;
-
- tty_unlock(tty);
- /*
- * Make sure we don't change while someone holds a
- * reference to the line discipline. The TTY_LDISC bit
- * prevents anyone taking a reference once it is clear.
- * We need the lock to avoid racing reference takers.
- *
- * We must clear the TTY_LDISC bit here to avoid a livelock
- * with a userspace app continually trying to use the tty in
- * parallel to the change and re-referencing the tty.
- */
-
- retval = tty_ldisc_halt(tty, o_tty, 5 * HZ);
-
- /*
- * Wait for hangup to complete, if pending.
- * We must drop the mutex here in case a hangup is also in process.
- */
-
- mutex_unlock(&tty->ldisc_mutex);
-
- flush_work(&tty->hangup_work);
-
+ old_ldisc = tty->ldisc;
tty_lock(tty);
- mutex_lock(&tty->ldisc_mutex);
-
- /* handle wait idle failure locked */
- if (retval) {
- tty_ldisc_put(new_ldisc);
- goto enable;
- }
- if (test_bit(TTY_HUPPING, &tty->flags)) {
+ if (test_bit(TTY_HUPPING, &tty->flags) ||
+ test_bit(TTY_HUPPED, &tty->flags)) {
/* We were raced by the hangup method. It will have stomped
the ldisc data and closed the ldisc down */
- clear_bit(TTY_LDISC_CHANGING, &tty->flags);
- mutex_unlock(&tty->ldisc_mutex);
+ tty_ldisc_enable_pair(tty, o_tty);
tty_ldisc_put(new_ldisc);
tty_unlock(tty);
return -EIO;
}
- /* Shutdown the current discipline. */
- tty_ldisc_close(tty, o_ldisc);
+ /* Shutdown the old discipline. */
+ tty_ldisc_close(tty, old_ldisc);
/* Now set up the new line discipline. */
tty->ldisc = new_ldisc;
@@ -705,26 +564,24 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
if (retval < 0) {
/* Back to the old one or N_TTY if we can't */
tty_ldisc_put(new_ldisc);
- tty_ldisc_restore(tty, o_ldisc);
+ tty_ldisc_restore(tty, old_ldisc);
}
- /* At this point we hold a reference to the new ldisc and a
- a reference to the old ldisc. If we ended up flipping back
- to the existing ldisc we have two references to it */
-
- if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
+ if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc)
tty->ops->set_ldisc(tty);
- tty_ldisc_put(o_ldisc);
+ /* At this point we hold a reference to the new ldisc and a
+ reference to the old ldisc, or we hold two references to
+ the old ldisc (if it was restored as part of error cleanup
+ above). In either case, releasing a single reference from
+ the old ldisc is correct. */
+
+ tty_ldisc_put(old_ldisc);
-enable:
/*
* Allow ldisc referencing to occur again
*/
-
- tty_ldisc_enable(tty);
- if (o_tty)
- tty_ldisc_enable(o_tty);
+ tty_ldisc_enable_pair(tty, o_tty);
/* Restart the work queue in case no characters kick it off. Safe if
already running */
@@ -732,7 +589,6 @@ enable:
if (o_tty)
schedule_work(&o_tty->port->buf.work);
- mutex_unlock(&tty->ldisc_mutex);
tty_unlock(tty);
return retval;
}
@@ -746,11 +602,11 @@ enable:
static void tty_reset_termios(struct tty_struct *tty)
{
- mutex_lock(&tty->termios_mutex);
+ down_write(&tty->termios_rwsem);
tty->termios = tty->driver->init_termios;
tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
- mutex_unlock(&tty->termios_mutex);
+ up_write(&tty->termios_rwsem);
}
@@ -765,7 +621,7 @@ static void tty_reset_termios(struct tty_struct *tty)
static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
{
- struct tty_ldisc *ld = tty_ldisc_get(ldisc);
+ struct tty_ldisc *ld = tty_ldisc_get(tty, ldisc);
if (IS_ERR(ld))
return -1;
@@ -804,14 +660,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
- /*
- * FIXME! What are the locking issues here? This may me overdoing
- * things... This question is especially important now that we've
- * removed the irqlock.
- */
ld = tty_ldisc_ref(tty);
if (ld != NULL) {
- /* We may have no line discipline at this point */
if (ld->ops->flush_buffer)
ld->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty);
@@ -822,21 +672,22 @@ void tty_ldisc_hangup(struct tty_struct *tty)
ld->ops->hangup(tty);
tty_ldisc_deref(ld);
}
- /*
- * FIXME: Once we trust the LDISC code better we can wait here for
- * ldisc completion and fix the driver call race
- */
+
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
+
+ tty_unlock(tty);
+
/*
* Shutdown the current line discipline, and reset it to
* N_TTY if need be.
*
* Avoid racing set_ldisc or tty_ldisc_release
*/
- mutex_lock(&tty->ldisc_mutex);
+ tty_ldisc_lock_pair(tty, tty->link);
+ tty_lock(tty);
- if (tty_ldisc_hangup_halt(tty)) {
+ if (tty->ldisc) {
/* At this point we have a halted ldisc; we want to close it and
reopen a new ldisc. We could defer the reopen to the next
@@ -855,9 +706,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
BUG_ON(tty_ldisc_reinit(tty, N_TTY));
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
}
- tty_ldisc_enable(tty);
}
- mutex_unlock(&tty->ldisc_mutex);
+ tty_ldisc_enable_pair(tty, tty->link);
if (reset)
tty_reset_termios(tty);
@@ -889,15 +739,12 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
tty_ldisc_close(tty, ld);
return retval;
}
- tty_ldisc_enable(o_tty);
}
- tty_ldisc_enable(tty);
return 0;
}
static void tty_ldisc_kill(struct tty_struct *tty)
{
- mutex_lock(&tty->ldisc_mutex);
/*
* Now kill off the ldisc
*/
@@ -908,7 +755,6 @@ static void tty_ldisc_kill(struct tty_struct *tty)
/* Ensure the next open requests the N_TTY ldisc */
tty_set_termios_ldisc(tty, N_TTY);
- mutex_unlock(&tty->ldisc_mutex);
}
/**
@@ -930,15 +776,16 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
- tty_ldisc_halt(tty, o_tty, MAX_SCHEDULE_TIMEOUT);
-
+ tty_ldisc_lock_pair(tty, o_tty);
tty_lock_pair(tty, o_tty);
- /* This will need doing differently if we need to lock */
+
tty_ldisc_kill(tty);
if (o_tty)
tty_ldisc_kill(o_tty);
tty_unlock_pair(tty, o_tty);
+ tty_ldisc_unlock_pair(tty, o_tty);
+
/* And the memory resources remaining (buffers, termios) will be
disposed of when the kref hits zero */
@@ -955,7 +802,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
void tty_ldisc_init(struct tty_struct *tty)
{
- struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
+ struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
if (IS_ERR(ld))
panic("n_tty: init_tty");
tty->ldisc = ld;
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 121aeb9393e..f597e88a705 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -256,10 +256,9 @@ void tty_port_tty_hangup(struct tty_port *port, bool check_clocal)
{
struct tty_struct *tty = tty_port_tty_get(port);
- if (tty && (!check_clocal || !C_CLOCAL(tty))) {
+ if (tty && (!check_clocal || !C_CLOCAL(tty)))
tty_hangup(tty);
- tty_kref_put(tty);
- }
+ tty_kref_put(tty);
}
EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index a9af1b9ae16..d0e3a449770 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -132,12 +132,6 @@ static int shift_state = 0;
static unsigned char ledstate = 0xff; /* undefined */
static unsigned char ledioctl;
-static struct ledptr {
- unsigned int *addr;
- unsigned int mask;
- unsigned char valid:1;
-} ledptrs[3];
-
/*
* Notifier list for console keyboard events
*/
@@ -994,24 +988,11 @@ void setledstate(struct kbd_struct *kbd, unsigned int led)
static inline unsigned char getleds(void)
{
struct kbd_struct *kbd = kbd_table + fg_console;
- unsigned char leds;
- int i;
if (kbd->ledmode == LED_SHOW_IOCTL)
return ledioctl;
- leds = kbd->ledflagstate;
-
- if (kbd->ledmode == LED_SHOW_MEM) {
- for (i = 0; i < 3; i++)
- if (ledptrs[i].valid) {
- if (*ledptrs[i].addr & ledptrs[i].mask)
- leds |= (1 << i);
- else
- leds &= ~(1 << i);
- }
- }
- return leds;
+ return kbd->ledflagstate;
}
static int kbd_update_leds_helper(struct input_handle *handle, void *data)
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 60b7b692605..ea27804d87a 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -24,6 +24,7 @@
#include <linux/selection.h>
#include <linux/tiocl.h>
#include <linux/console.h>
+#include <linux/tty_flip.h>
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
#define isspace(c) ((c) == ' ')
@@ -346,8 +347,8 @@ int paste_selection(struct tty_struct *tty)
console_unlock();
ld = tty_ldisc_ref_wait(tty);
+ tty_buffer_lock_exclusive(&vc->port);
- /* FIXME: this is completely unsafe */
add_wait_queue(&vc->paste_wait, &wait);
while (sel_buffer && sel_buffer_lth > pasted) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -356,13 +357,14 @@ int paste_selection(struct tty_struct *tty)
continue;
}
count = sel_buffer_lth - pasted;
- count = min(count, tty->receive_room);
- ld->ops->receive_buf(tty, sel_buffer + pasted, NULL, count);
+ count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL,
+ count);
pasted += count;
}
remove_wait_queue(&vc->paste_wait, &wait);
__set_current_state(TASK_RUNNING);
+ tty_buffer_unlock_exclusive(&vc->port);
tty_ldisc_deref(ld);
return 0;
}
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index c677829baa8..9a8e8c5a0c7 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -828,7 +828,7 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
* If the caller passes a tty structure then update the termios winsize
* information and perform any necessary signal handling.
*
- * Caller must hold the console semaphore. Takes the termios mutex and
+ * Caller must hold the console semaphore. Takes the termios rwsem and
* ctrl_lock of the tty IFF a tty is passed.
*/
@@ -972,7 +972,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
* the actual work.
*
* Takes the console sem and the called methods then take the tty
- * termios_mutex and the tty ctrl_lock in that order.
+ * termios_rwsem and the tty ctrl_lock in that order.
*/
static int vt_resize(struct tty_struct *tty, struct winsize *ws)
{
@@ -2809,8 +2809,10 @@ static void con_shutdown(struct tty_struct *tty)
console_unlock();
}
+static int default_color = 7; /* white */
static int default_italic_color = 2; // green (ASCII)
static int default_underline_color = 3; // cyan (ASCII)
+module_param_named(color, default_color, int, S_IRUGO | S_IWUSR);
module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
@@ -2832,7 +2834,7 @@ static void vc_init(struct vc_data *vc, unsigned int rows,
vc->vc_palette[k++] = default_grn[j] ;
vc->vc_palette[k++] = default_blu[j] ;
}
- vc->vc_def_color = 0x07; /* white */
+ vc->vc_def_color = default_color;
vc->vc_ulcolor = default_underline_color;
vc->vc_itcolor = default_italic_color;
vc->vc_halfcolor = 0x08; /* grey */
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 5295be0342c..5a90914d856 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -1,5 +1,6 @@
menuconfig UIO
tristate "Userspace I/O drivers"
+ depends on MMU
help
Enable this to allow the userspace driver core code to be
built. This code allows userspace programs easy access to
@@ -23,13 +24,6 @@ config UIO_CIF
To compile this driver as a module, choose M here: the module
will be called uio_cif.
-config UIO_PDRV
- tristate "Userspace I/O platform driver"
- help
- Generic platform driver for Userspace I/O devices.
-
- If you don't know what to do here, say N.
-
config UIO_PDRV_GENIRQ
tristate "Userspace I/O platform driver with generic IRQ handling"
help
@@ -128,4 +122,17 @@ config UIO_PRUSS
To compile this driver as a module, choose M here: the module
will be called uio_pruss.
+config UIO_MF624
+ tristate "Humusoft MF624 DAQ PCI card driver"
+ depends on PCI
+ help
+ Userspace I/O interface for the Humusoft MF624 PCI card.
+ A sample userspace application using this driver is available
+ (among other MF624 related information and software components)
+ for download in a git repository:
+
+ git clone git://rtime.felk.cvut.cz/mf6xx.git
+
+ If you compile this as a module, it will be called uio_mf624.
+
endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index b354c539507..d3218bde3ae 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -1,6 +1,5 @@
obj-$(CONFIG_UIO) += uio.o
obj-$(CONFIG_UIO_CIF) += uio_cif.o
-obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o
obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o
obj-$(CONFIG_UIO_DMEM_GENIRQ) += uio_dmem_genirq.o
obj-$(CONFIG_UIO_AEC) += uio_aec.o
@@ -8,3 +7,4 @@ obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o
obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
obj-$(CONFIG_UIO_NETX) += uio_netx.o
obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o
+obj-$(CONFIG_UIO_MF624) += uio_mf624.o
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 3b96f18593b..ba475632c5f 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -35,7 +35,6 @@ struct uio_device {
atomic_t event;
struct fasync_struct *async_queue;
wait_queue_head_t wait;
- int vma_count;
struct uio_info *info;
struct kobject *map_dir;
struct kobject *portio_dir;
@@ -224,38 +223,42 @@ static struct kobj_type portio_attr_type = {
.default_attrs = portio_attrs,
};
-static ssize_t show_name(struct device *dev,
+static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct uio_device *idev = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", idev->info->name);
}
+static DEVICE_ATTR_RO(name);
-static ssize_t show_version(struct device *dev,
+static ssize_t version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct uio_device *idev = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", idev->info->version);
}
+static DEVICE_ATTR_RO(version);
-static ssize_t show_event(struct device *dev,
+static ssize_t event_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct uio_device *idev = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event));
}
+static DEVICE_ATTR_RO(event);
-static struct device_attribute uio_class_attributes[] = {
- __ATTR(name, S_IRUGO, show_name, NULL),
- __ATTR(version, S_IRUGO, show_version, NULL),
- __ATTR(event, S_IRUGO, show_event, NULL),
- {}
+static struct attribute *uio_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_version.attr,
+ &dev_attr_event.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(uio);
/* UIO class infrastructure */
static struct class uio_class = {
.name = "uio",
- .dev_attrs = uio_class_attributes,
+ .dev_groups = uio_groups,
};
/*
@@ -593,18 +596,6 @@ static int uio_find_mem_index(struct vm_area_struct *vma)
return -1;
}
-static void uio_vma_open(struct vm_area_struct *vma)
-{
- struct uio_device *idev = vma->vm_private_data;
- idev->vma_count++;
-}
-
-static void uio_vma_close(struct vm_area_struct *vma)
-{
- struct uio_device *idev = vma->vm_private_data;
- idev->vma_count--;
-}
-
static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct uio_device *idev = vma->vm_private_data;
@@ -630,12 +621,23 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
return 0;
}
-static const struct vm_operations_struct uio_vm_ops = {
- .open = uio_vma_open,
- .close = uio_vma_close,
+static const struct vm_operations_struct uio_logical_vm_ops = {
.fault = uio_vma_fault,
};
+static int uio_mmap_logical(struct vm_area_struct *vma)
+{
+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_ops = &uio_logical_vm_ops;
+ return 0;
+}
+
+static const struct vm_operations_struct uio_physical_vm_ops = {
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+ .access = generic_access_phys,
+#endif
+};
+
static int uio_mmap_physical(struct vm_area_struct *vma)
{
struct uio_device *idev = vma->vm_private_data;
@@ -643,6 +645,8 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
if (mi < 0)
return -EINVAL;
+ vma->vm_ops = &uio_physical_vm_ops;
+
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return remap_pfn_range(vma,
@@ -652,14 +656,6 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
vma->vm_page_prot);
}
-static int uio_mmap_logical(struct vm_area_struct *vma)
-{
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
- vma->vm_ops = &uio_vm_ops;
- uio_vma_open(vma);
- return 0;
-}
-
static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
{
struct uio_listener *listener = filep->private_data;
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c
index 125d0e5a688..1270f3b2613 100644
--- a/drivers/uio/uio_dmem_genirq.c
+++ b/drivers/uio/uio_dmem_genirq.c
@@ -146,7 +146,7 @@ static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
static int uio_dmem_genirq_probe(struct platform_device *pdev)
{
- struct uio_dmem_genirq_pdata *pdata = pdev->dev.platform_data;
+ struct uio_dmem_genirq_pdata *pdata = dev_get_platdata(&pdev->dev);
struct uio_info *uioinfo = &pdata->uioinfo;
struct uio_dmem_genirq_platdata *priv;
struct uio_mem *uiomem;
diff --git a/drivers/uio/uio_mf624.c b/drivers/uio/uio_mf624.c
new file mode 100644
index 00000000000..a1768b2f449
--- /dev/null
+++ b/drivers/uio/uio_mf624.c
@@ -0,0 +1,247 @@
+/*
+ * UIO driver fo Humusoft MF624 DAQ card.
+ * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com>,
+ * Czech Technical University in Prague
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/uio_driver.h>
+
+#define PCI_VENDOR_ID_HUMUSOFT 0x186c
+#define PCI_DEVICE_ID_MF624 0x0624
+#define PCI_SUBVENDOR_ID_HUMUSOFT 0x186c
+#define PCI_SUBDEVICE_DEVICE 0x0624
+
+/* BAR0 Interrupt control/status register */
+#define INTCSR 0x4C
+#define INTCSR_ADINT_ENABLE (1 << 0)
+#define INTCSR_CTR4INT_ENABLE (1 << 3)
+#define INTCSR_PCIINT_ENABLE (1 << 6)
+#define INTCSR_ADINT_STATUS (1 << 2)
+#define INTCSR_CTR4INT_STATUS (1 << 5)
+
+enum mf624_interrupt_source {ADC, CTR4, ALL};
+
+void mf624_disable_interrupt(enum mf624_interrupt_source source,
+ struct uio_info *info)
+{
+ void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
+
+ switch (source) {
+ case ADC:
+ iowrite32(ioread32(INTCSR_reg)
+ & ~(INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE),
+ INTCSR_reg);
+ break;
+
+ case CTR4:
+ iowrite32(ioread32(INTCSR_reg)
+ & ~(INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE),
+ INTCSR_reg);
+ break;
+
+ case ALL:
+ default:
+ iowrite32(ioread32(INTCSR_reg)
+ & ~(INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
+ | INTCSR_PCIINT_ENABLE),
+ INTCSR_reg);
+ break;
+ }
+}
+
+void mf624_enable_interrupt(enum mf624_interrupt_source source,
+ struct uio_info *info)
+{
+ void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
+
+ switch (source) {
+ case ADC:
+ iowrite32(ioread32(INTCSR_reg)
+ | INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE,
+ INTCSR_reg);
+ break;
+
+ case CTR4:
+ iowrite32(ioread32(INTCSR_reg)
+ | INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE,
+ INTCSR_reg);
+ break;
+
+ case ALL:
+ default:
+ iowrite32(ioread32(INTCSR_reg)
+ | INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
+ | INTCSR_PCIINT_ENABLE,
+ INTCSR_reg);
+ break;
+ }
+}
+
+static irqreturn_t mf624_irq_handler(int irq, struct uio_info *info)
+{
+ void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
+
+ if ((ioread32(INTCSR_reg) & INTCSR_ADINT_ENABLE)
+ && (ioread32(INTCSR_reg) & INTCSR_ADINT_STATUS)) {
+ mf624_disable_interrupt(ADC, info);
+ return IRQ_HANDLED;
+ }
+
+ if ((ioread32(INTCSR_reg) & INTCSR_CTR4INT_ENABLE)
+ && (ioread32(INTCSR_reg) & INTCSR_CTR4INT_STATUS)) {
+ mf624_disable_interrupt(CTR4, info);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int mf624_irqcontrol(struct uio_info *info, s32 irq_on)
+{
+ if (irq_on == 0)
+ mf624_disable_interrupt(ALL, info);
+ else if (irq_on == 1)
+ mf624_enable_interrupt(ALL, info);
+
+ return 0;
+}
+
+static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct uio_info *info;
+
+ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ if (pci_enable_device(dev))
+ goto out_free;
+
+ if (pci_request_regions(dev, "mf624"))
+ goto out_disable;
+
+ info->name = "mf624";
+ info->version = "0.0.1";
+
+ /* Note: Datasheet says device uses BAR0, BAR1, BAR2 -- do not trust it */
+
+ /* BAR0 */
+ info->mem[0].name = "PCI chipset, interrupts, status "
+ "bits, special functions";
+ info->mem[0].addr = pci_resource_start(dev, 0);
+ if (!info->mem[0].addr)
+ goto out_release;
+ info->mem[0].size = pci_resource_len(dev, 0);
+ info->mem[0].memtype = UIO_MEM_PHYS;
+ info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
+ if (!info->mem[0].internal_addr)
+ goto out_release;
+
+ /* BAR2 */
+ info->mem[1].name = "ADC, DAC, DIO";
+ info->mem[1].addr = pci_resource_start(dev, 2);
+ if (!info->mem[1].addr)
+ goto out_unmap0;
+ info->mem[1].size = pci_resource_len(dev, 2);
+ info->mem[1].memtype = UIO_MEM_PHYS;
+ info->mem[1].internal_addr = pci_ioremap_bar(dev, 2);
+ if (!info->mem[1].internal_addr)
+ goto out_unmap0;
+
+ /* BAR4 */
+ info->mem[2].name = "Counter/timer chip";
+ info->mem[2].addr = pci_resource_start(dev, 4);
+ if (!info->mem[2].addr)
+ goto out_unmap1;
+ info->mem[2].size = pci_resource_len(dev, 4);
+ info->mem[2].memtype = UIO_MEM_PHYS;
+ info->mem[2].internal_addr = pci_ioremap_bar(dev, 4);
+ if (!info->mem[2].internal_addr)
+ goto out_unmap1;
+
+ info->irq = dev->irq;
+ info->irq_flags = IRQF_SHARED;
+ info->handler = mf624_irq_handler;
+
+ info->irqcontrol = mf624_irqcontrol;
+
+ if (uio_register_device(&dev->dev, info))
+ goto out_unmap2;
+
+ pci_set_drvdata(dev, info);
+
+ return 0;
+
+out_unmap2:
+ iounmap(info->mem[2].internal_addr);
+out_unmap1:
+ iounmap(info->mem[1].internal_addr);
+out_unmap0:
+ iounmap(info->mem[0].internal_addr);
+
+out_release:
+ pci_release_regions(dev);
+
+out_disable:
+ pci_disable_device(dev);
+
+out_free:
+ kfree(info);
+ return -ENODEV;
+}
+
+static void mf624_pci_remove(struct pci_dev *dev)
+{
+ struct uio_info *info = pci_get_drvdata(dev);
+
+ mf624_disable_interrupt(ALL, info);
+
+ uio_unregister_device(info);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ pci_set_drvdata(dev, NULL);
+
+ iounmap(info->mem[0].internal_addr);
+ iounmap(info->mem[1].internal_addr);
+ iounmap(info->mem[2].internal_addr);
+
+ kfree(info);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(mf624_pci_id) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF624) },
+ { 0, }
+};
+
+static struct pci_driver mf624_pci_driver = {
+ .name = "mf624",
+ .id_table = mf624_pci_id,
+ .probe = mf624_pci_probe,
+ .remove = mf624_pci_remove,
+};
+MODULE_DEVICE_TABLE(pci, mf624_pci_id);
+
+module_pci_driver(mf624_pci_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");
diff --git a/drivers/uio/uio_pdrv.c b/drivers/uio/uio_pdrv.c
deleted file mode 100644
index 39be9e06170..00000000000
--- a/drivers/uio/uio_pdrv.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * drivers/uio/uio_pdrv.c
- *
- * Copyright (C) 2008 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/platform_device.h>
-#include <linux/uio_driver.h>
-#include <linux/stringify.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#define DRIVER_NAME "uio_pdrv"
-
-struct uio_platdata {
- struct uio_info *uioinfo;
-};
-
-static int uio_pdrv_probe(struct platform_device *pdev)
-{
- struct uio_info *uioinfo = pdev->dev.platform_data;
- struct uio_platdata *pdata;
- struct uio_mem *uiomem;
- int ret = -ENODEV;
- int i;
-
- if (!uioinfo || !uioinfo->name || !uioinfo->version) {
- dev_dbg(&pdev->dev, "%s: err_uioinfo\n", __func__);
- goto err_uioinfo;
- }
-
- pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- ret = -ENOMEM;
- dev_dbg(&pdev->dev, "%s: err_alloc_pdata\n", __func__);
- goto err_alloc_pdata;
- }
-
- pdata->uioinfo = uioinfo;
-
- uiomem = &uioinfo->mem[0];
-
- for (i = 0; i < pdev->num_resources; ++i) {
- struct resource *r = &pdev->resource[i];
-
- if (r->flags != IORESOURCE_MEM)
- continue;
-
- if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
- dev_warn(&pdev->dev, "device has more than "
- __stringify(MAX_UIO_MAPS)
- " I/O memory resources.\n");
- break;
- }
-
- uiomem->memtype = UIO_MEM_PHYS;
- uiomem->addr = r->start;
- uiomem->size = resource_size(r);
- uiomem->name = r->name;
- ++uiomem;
- }
-
- while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) {
- uiomem->size = 0;
- ++uiomem;
- }
-
- pdata->uioinfo->priv = pdata;
-
- ret = uio_register_device(&pdev->dev, pdata->uioinfo);
-
- if (ret) {
- kfree(pdata);
-err_alloc_pdata:
-err_uioinfo:
- return ret;
- }
-
- platform_set_drvdata(pdev, pdata);
-
- return 0;
-}
-
-static int uio_pdrv_remove(struct platform_device *pdev)
-{
- struct uio_platdata *pdata = platform_get_drvdata(pdev);
-
- uio_unregister_device(pdata->uioinfo);
-
- kfree(pdata);
-
- return 0;
-}
-
-static struct platform_driver uio_pdrv = {
- .probe = uio_pdrv_probe,
- .remove = uio_pdrv_remove,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-module_platform_driver(uio_pdrv);
-
-MODULE_AUTHOR("Uwe Kleine-Koenig");
-MODULE_DESCRIPTION("Userspace I/O platform driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index 4eb8eaf71be..90ff17a0202 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -104,7 +104,7 @@ static int uio_pdrv_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
static int uio_pdrv_genirq_probe(struct platform_device *pdev)
{
- struct uio_info *uioinfo = pdev->dev.platform_data;
+ struct uio_info *uioinfo = dev_get_platdata(&pdev->dev);
struct uio_pdrv_genirq_platdata *priv;
struct uio_mem *uiomem;
int ret = -EINVAL;
diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c
index 21f7a72301e..f519da9034b 100644
--- a/drivers/uio/uio_pruss.c
+++ b/drivers/uio/uio_pruss.c
@@ -121,7 +121,7 @@ static int pruss_probe(struct platform_device *dev)
struct uio_pruss_dev *gdev;
struct resource *regs_prussio;
int ret = -ENODEV, cnt = 0, len;
- struct uio_pruss_pdata *pdata = dev->dev.platform_data;
+ struct uio_pruss_pdata *pdata = dev_get_platdata(&dev->dev);
gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL);
if (!gdev)
@@ -224,7 +224,6 @@ static int pruss_remove(struct platform_device *dev)
struct uio_pruss_dev *gdev = platform_get_drvdata(dev);
pruss_cleanup(dev, gdev);
- platform_set_drvdata(dev, NULL);
return 0;
}
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 73f62caa860..2642b8a11e0 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -6,9 +6,26 @@
config USB_ARCH_HAS_OHCI
bool
+config USB_OHCI_BIG_ENDIAN_DESC
+ bool
+
+config USB_OHCI_BIG_ENDIAN_MMIO
+ bool
+
+config USB_OHCI_LITTLE_ENDIAN
+ bool
+ default n if STB03xxx || PPC_MPC52xx
+ default y
+
config USB_ARCH_HAS_EHCI
bool
+config USB_EHCI_BIG_ENDIAN_MMIO
+ bool
+
+config USB_EHCI_BIG_ENDIAN_DESC
+ bool
+
config USB_ARCH_HAS_XHCI
bool
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 238c5d47cad..70d7c5b92c3 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_USB_ISP1760_HCD) += host/
obj-$(CONFIG_USB_IMX21_HCD) += host/
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
obj-$(CONFIG_USB_FUSBH200_HCD) += host/
+obj-$(CONFIG_USB_FOTG210_HCD) += host/
obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
@@ -45,7 +46,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/
-obj-$(CONFIG_USB_PHY) += phy/
+obj-$(CONFIG_USB_SUPPORT) += phy/
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/
diff --git a/drivers/usb/atm/Makefile b/drivers/usb/atm/Makefile
index a5d792ec3ad..ac278946b06 100644
--- a/drivers/usb/atm/Makefile
+++ b/drivers/usb/atm/Makefile
@@ -1,9 +1,6 @@
#
# Makefile for USB ATM/xDSL drivers
#
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-
obj-$(CONFIG_USB_CXACRU) += cxacru.o
obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o
obj-$(CONFIG_USB_UEAGLEATM) += ueagle-atm.o
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 807627b36cc..69461d65397 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -888,7 +888,7 @@ static int speedtch_bind(struct usbatm_data *usbatm,
usb_fill_int_urb(instance->int_urb, usb_dev,
usb_rcvintpipe(usb_dev, ENDPOINT_INT),
instance->int_data, sizeof(instance->int_data),
- speedtch_handle_int, instance, 50);
+ speedtch_handle_int, instance, 16);
else
usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__);
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 5e0d33a7da5..25a7bfcf666 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -311,8 +311,6 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char
int vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
u8 pti = ((source[3] & 0xe) >> 1);
- vdbg(&instance->usb_intf->dev, "%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
-
if ((vci != instance->cached_vci) || (vpi != instance->cached_vpi)) {
instance->cached_vpi = vpi;
instance->cached_vci = vci;
@@ -344,7 +342,6 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char
__func__, sarb->len, vcc);
/* discard cells already received */
skb_trim(sarb, 0);
- UDSL_ASSERT(instance, sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
}
memcpy(skb_tail_pointer(sarb), source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
@@ -437,8 +434,6 @@ static void usbatm_extract_cells(struct usbatm_data *instance,
unsigned char *cell_buf = instance->cell_buf;
unsigned int space_left = stride - buf_usage;
- UDSL_ASSERT(instance, buf_usage <= stride);
-
if (avail_data >= space_left) {
/* add new data and process cell */
memcpy(cell_buf + buf_usage, source, space_left);
@@ -479,10 +474,6 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance,
unsigned int bytes_written;
unsigned int stride = instance->tx_channel.stride;
- vdbg(&instance->usb_intf->dev, "%s: skb->len=%d, avail_space=%u",
- __func__, skb->len, avail_space);
- UDSL_ASSERT(instance, !(avail_space % stride));
-
for (bytes_written = 0; bytes_written < avail_space && ctrl->len;
bytes_written += stride, target += stride) {
unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD);
@@ -553,8 +544,6 @@ static void usbatm_rx_process(unsigned long data)
if (!urb->iso_frame_desc[i].status) {
unsigned int actual_length = urb->iso_frame_desc[i].actual_length;
- UDSL_ASSERT(instance, actual_length <= packet_size);
-
if (!merge_length)
merge_start = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
merge_length += actual_length;
@@ -645,7 +634,6 @@ static void usbatm_cancel_send(struct usbatm_data *instance,
{
struct sk_buff *skb, *n;
- atm_dbg(instance, "%s entered\n", __func__);
spin_lock_irq(&instance->sndqueue.lock);
skb_queue_walk_safe(&instance->sndqueue, skb, n) {
if (UDSL_SKB(skb)->atm.vcc == vcc) {
@@ -663,7 +651,6 @@ static void usbatm_cancel_send(struct usbatm_data *instance,
usbatm_pop(vcc, skb);
}
tasklet_enable(&instance->tx_channel.tasklet);
- atm_dbg(instance, "%s done\n", __func__);
}
static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
@@ -674,16 +661,13 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
/* racy disconnection check - fine */
if (!instance || instance->disconnected) {
-#ifdef DEBUG
+#ifdef VERBOSE_DEBUG
printk_ratelimited(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
#endif
err = -ENODEV;
goto fail;
}
- vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__,
- skb, skb->len);
-
if (vcc->qos.aal != ATM_AAL5) {
atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
err = -EINVAL;
@@ -723,8 +707,6 @@ static void usbatm_destroy_instance(struct kref *kref)
{
struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount);
- usb_dbg(instance, "%s\n", __func__);
-
tasklet_kill(&instance->rx_channel.tasklet);
tasklet_kill(&instance->tx_channel.tasklet);
usb_put_dev(instance->usb_dev);
@@ -733,15 +715,11 @@ static void usbatm_destroy_instance(struct kref *kref)
static void usbatm_get_instance(struct usbatm_data *instance)
{
- usb_dbg(instance, "%s\n", __func__);
-
kref_get(&instance->refcount);
}
static void usbatm_put_instance(struct usbatm_data *instance)
{
- usb_dbg(instance, "%s\n", __func__);
-
kref_put(&instance->refcount, usbatm_destroy_instance);
}
@@ -757,7 +735,6 @@ static void usbatm_atm_dev_close(struct atm_dev *atm_dev)
if (!instance)
return;
- usb_dbg(instance, "%s\n", __func__);
atm_dev->dev_data = NULL; /* catch bugs */
usbatm_put_instance(instance); /* taken in usbatm_atm_init */
}
@@ -813,8 +790,6 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
if (!instance)
return -ENODEV;
- atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);
-
/* only support AAL5 */
if ((vcc->qos.aal != ATM_AAL5)) {
atm_warn(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
@@ -891,11 +866,6 @@ static void usbatm_atm_close(struct atm_vcc *vcc)
if (!instance || !vcc_data)
return;
- atm_dbg(instance, "%s entered\n", __func__);
-
- atm_dbg(instance, "%s: deallocating vcc 0x%p with vpi %d vci %d\n",
- __func__, vcc_data, vcc_data->vpi, vcc_data->vci);
-
usbatm_cancel_send(instance, vcc);
mutex_lock(&instance->serialize); /* vs self, usbatm_atm_open, usbatm_usb_disconnect */
@@ -922,8 +892,6 @@ static void usbatm_atm_close(struct atm_vcc *vcc)
clear_bit(ATM_VF_ADDR, &vcc->flags);
mutex_unlock(&instance->serialize);
-
- atm_dbg(instance, "%s successful\n", __func__);
}
static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd,
@@ -1060,12 +1028,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
int i, length;
unsigned int maxpacket, num_packets;
- dev_dbg(dev, "%s: trying driver %s with vendor=%04x, product=%04x, ifnum %2d\n",
- __func__, driver->driver_name,
- le16_to_cpu(usb_dev->descriptor.idVendor),
- le16_to_cpu(usb_dev->descriptor.idProduct),
- intf->altsetting->desc.bInterfaceNumber);
-
/* instance init */
instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
if (!instance) {
@@ -1158,14 +1120,13 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
instance->rx_channel.buf_size = num_packets * maxpacket;
instance->rx_channel.packet_size = maxpacket;
-#ifdef DEBUG
for (i = 0; i < 2; i++) {
struct usbatm_channel *channel = i ?
&instance->tx_channel : &instance->rx_channel;
- dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n", __func__, channel->buf_size, i ? "tx" : "rx", channel);
+ dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n",
+ __func__, channel->buf_size, i ? "tx" : "rx", channel);
}
-#endif
/* initialize urbs */
@@ -1176,8 +1137,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
struct urb *urb;
unsigned int iso_packets = usb_pipeisoc(channel->endpoint) ? channel->buf_size / channel->packet_size : 0;
- UDSL_ASSERT(instance, !usb_pipeisoc(channel->endpoint) || usb_pipein(channel->endpoint));
-
urb = usb_alloc_urb(iso_packets, GFP_KERNEL);
if (!urb) {
dev_err(dev, "%s: no memory for urb %d!\n", __func__, i);
@@ -1266,8 +1225,6 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
struct usbatm_vcc_data *vcc_data;
int i;
- dev_dbg(dev, "%s entered\n", __func__);
-
if (!instance) {
dev_dbg(dev, "%s: NULL instance!\n", __func__);
return;
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h
index 5fc48940521..5651231a743 100644
--- a/drivers/usb/atm/usbatm.h
+++ b/drivers/usb/atm/usbatm.h
@@ -39,31 +39,14 @@
#define VERBOSE_DEBUG
*/
-#ifdef DEBUG
-#define UDSL_ASSERT(instance, x) BUG_ON(!(x))
-#else
-#define UDSL_ASSERT(instance, x) \
- do { \
- if (!(x)) \
- dev_warn(&(instance)->usb_intf->dev, \
- "failed assertion '%s' at line %d", \
- __stringify(x), __LINE__); \
- } while (0)
-#endif
-
#define usb_err(instance, format, arg...) \
dev_err(&(instance)->usb_intf->dev , format , ## arg)
#define usb_info(instance, format, arg...) \
dev_info(&(instance)->usb_intf->dev , format , ## arg)
#define usb_warn(instance, format, arg...) \
dev_warn(&(instance)->usb_intf->dev , format , ## arg)
-#ifdef DEBUG
-#define usb_dbg(instance, format, arg...) \
- dev_printk(KERN_DEBUG , &(instance)->usb_intf->dev , format , ## arg)
-#else
#define usb_dbg(instance, format, arg...) \
- do {} while (0)
-#endif
+ dev_dbg(&(instance)->usb_intf->dev , format , ## arg)
/* FIXME: move to dev_* once ATM is driver model aware */
#define atm_printk(level, instance, format, arg...) \
@@ -76,18 +59,12 @@
atm_printk(KERN_INFO, instance , format , ## arg)
#define atm_warn(instance, format, arg...) \
atm_printk(KERN_WARNING, instance , format , ## arg)
-#ifdef DEBUG
-#define atm_dbg(instance, format, arg...) \
- atm_printk(KERN_DEBUG, instance , format , ## arg)
-#define atm_rldbg(instance, format, arg...) \
+#define atm_dbg(instance, format, arg...) \
+ dynamic_pr_debug("ATM dev %d: " format , \
+ (instance)->atm_dev->number , ## arg)
+#define atm_rldbg(instance, format, arg...) \
if (printk_ratelimit()) \
- atm_printk(KERN_DEBUG, instance , format , ## arg)
-#else
-#define atm_dbg(instance, format, arg...) \
- do {} while (0)
-#define atm_rldbg(instance, format, arg...) \
- do {} while (0)
-#endif
+ atm_dbg(instance , format , ## arg)
/* flags, set by mini-driver in bind() */
diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c
index fe815ecd557..8db3380c332 100644
--- a/drivers/usb/c67x00/c67x00-drv.c
+++ b/drivers/usb/c67x00/c67x00-drv.c
@@ -131,7 +131,7 @@ static int c67x00_drv_probe(struct platform_device *pdev)
if (!res2)
return -ENODEV;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata)
return -ENODEV;
@@ -154,7 +154,7 @@ static int c67x00_drv_probe(struct platform_device *pdev)
spin_lock_init(&c67x00->hpi.lock);
c67x00->hpi.regstep = pdata->hpi_regstep;
- c67x00->pdata = pdev->dev.platform_data;
+ c67x00->pdata = dev_get_platdata(&pdev->dev);
c67x00->pdev = pdev;
c67x00_ll_init(c67x00);
diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig
index eb2aa2e5a84..4a851e15e58 100644
--- a/drivers/usb/chipidea/Kconfig
+++ b/drivers/usb/chipidea/Kconfig
@@ -1,6 +1,6 @@
config USB_CHIPIDEA
tristate "ChipIdea Highspeed Dual Role Controller"
- depends on USB || USB_GADGET
+ depends on (USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)
help
Say Y here if your system has a dual role high speed USB
controller based on ChipIdea silicon IP. Currently, only the
@@ -12,15 +12,14 @@ if USB_CHIPIDEA
config USB_CHIPIDEA_UDC
bool "ChipIdea device controller"
- depends on USB_GADGET=y || USB_CHIPIDEA=m
+ depends on USB_GADGET
help
Say Y here to enable device controller functionality of the
ChipIdea driver.
config USB_CHIPIDEA_HOST
bool "ChipIdea host controller"
- depends on USB=y
- depends on USB_EHCI_HCD=y || USB_CHIPIDEA=m
+ depends on USB_EHCI_HCD
select USB_EHCI_ROOT_HUB_TT
help
Say Y here to enable host controller functionality of the
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index 6cf5f68dedd..a99d980454a 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o
-ci_hdrc-y := core.o
+ci_hdrc-y := core.o otg.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index aefa0261220..464584c6cca 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -50,7 +50,7 @@
#define PORTSC_PTC (0x0FUL << 16)
/* PTS and PTW for non lpm version only */
#define PORTSC_PTS(d) \
- ((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
+ (u32)((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
#define PORTSC_PTW BIT(28)
#define PORTSC_STS BIT(29)
@@ -59,7 +59,7 @@
#define DEVLC_PSPD_HS (0x02UL << 25)
#define DEVLC_PTW BIT(27)
#define DEVLC_STS BIT(28)
-#define DEVLC_PTS(d) (((d) & 0x7) << 29)
+#define DEVLC_PTS(d) (u32)(((d) & 0x7) << 29)
/* Encoding for DEVLC_PTS and PORTSC_PTS */
#define PTS_UTMI 0
@@ -79,11 +79,21 @@
#define OTGSC_ASVIS BIT(18)
#define OTGSC_BSVIS BIT(19)
#define OTGSC_BSEIS BIT(20)
+#define OTGSC_1MSIS BIT(21)
+#define OTGSC_DPIS BIT(22)
#define OTGSC_IDIE BIT(24)
#define OTGSC_AVVIE BIT(25)
#define OTGSC_ASVIE BIT(26)
#define OTGSC_BSVIE BIT(27)
#define OTGSC_BSEIE BIT(28)
+#define OTGSC_1MSIE BIT(29)
+#define OTGSC_DPIE BIT(30)
+#define OTGSC_INT_EN_BITS (OTGSC_IDIE | OTGSC_AVVIE | OTGSC_ASVIE \
+ | OTGSC_BSVIE | OTGSC_BSEIE | OTGSC_1MSIE \
+ | OTGSC_DPIE)
+#define OTGSC_INT_STATUS_BITS (OTGSC_IDIS | OTGSC_AVVIS | OTGSC_ASVIS \
+ | OTGSC_BSVIS | OTGSC_BSEIS | OTGSC_1MSIS \
+ | OTGSC_DPIS)
/* USBMODE */
#define USBMODE_CM (0x03UL << 0)
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 33cb29f36e0..1c94fc5257f 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -132,6 +132,9 @@ struct hw_bank {
* @transceiver: pointer to USB PHY, if any
* @hcd: pointer to usb_hcd for ehci host driver
* @debugfs: root dentry for this controller in debugfs
+ * @id_event: indicates there is an id event, and handled at ci_otg_work
+ * @b_sess_valid_event: indicates there is a vbus event, and handled
+ * at ci_otg_work
*/
struct ci_hdrc {
struct device *dev;
@@ -168,6 +171,8 @@ struct ci_hdrc {
struct usb_phy *transceiver;
struct usb_hcd *hcd;
struct dentry *debugfs;
+ bool id_event;
+ bool b_sess_valid_event;
};
static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci)
@@ -303,4 +308,7 @@ int hw_port_test_set(struct ci_hdrc *ci, u8 mode);
u8 hw_port_test_get(struct ci_hdrc *ci);
+int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
+ u32 value, unsigned int timeout_ms);
+
#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 14362c00db3..74d998d9b45 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -19,70 +19,56 @@
#include <linux/dma-mapping.h>
#include <linux/usb/chipidea.h>
#include <linux/clk.h>
-#include <linux/regulator/consumer.h>
#include "ci.h"
#include "ci_hdrc_imx.h"
-#define pdev_to_phy(pdev) \
- ((struct usb_phy *)platform_get_drvdata(pdev))
-
struct ci_hdrc_imx_data {
struct usb_phy *phy;
struct platform_device *ci_pdev;
struct clk *clk;
- struct regulator *reg_vbus;
+ struct imx_usbmisc_data *usbmisc_data;
};
-static const struct usbmisc_ops *usbmisc_ops;
-
/* Common functions shared by usbmisc drivers */
-int usbmisc_set_ops(const struct usbmisc_ops *ops)
-{
- if (usbmisc_ops)
- return -EBUSY;
-
- usbmisc_ops = ops;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(usbmisc_set_ops);
-
-void usbmisc_unset_ops(const struct usbmisc_ops *ops)
-{
- usbmisc_ops = NULL;
-}
-EXPORT_SYMBOL_GPL(usbmisc_unset_ops);
-
-int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev)
+static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
{
struct device_node *np = dev->of_node;
struct of_phandle_args args;
+ struct imx_usbmisc_data *data;
int ret;
- usbdev->dev = dev;
+ /*
+ * In case the fsl,usbmisc property is not present this device doesn't
+ * need usbmisc. Return NULL (which is no error here)
+ */
+ if (!of_get_property(np, "fsl,usbmisc", NULL))
+ return NULL;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return ERR_PTR(-ENOMEM);
ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells",
0, &args);
if (ret) {
dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n",
ret);
- memset(usbdev, 0, sizeof(*usbdev));
- return ret;
+ return ERR_PTR(ret);
}
- usbdev->index = args.args[0];
+
+ data->index = args.args[0];
of_node_put(args.np);
if (of_find_property(np, "disable-over-current", NULL))
- usbdev->disable_oc = 1;
+ data->disable_oc = 1;
if (of_find_property(np, "external-vbus-divider", NULL))
- usbdev->evdo = 1;
+ data->evdo = 1;
- return 0;
+ return data;
}
-EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
/* End of common functions shared by usbmisc drivers*/
@@ -93,27 +79,19 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
.name = "ci_hdrc_imx",
.capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_REQUIRE_TRANSCEIVER |
- CI_HDRC_PULLUP_ON_VBUS |
CI_HDRC_DISABLE_STREAMING,
};
- struct resource *res;
int ret;
- if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL)
- && !usbmisc_ops)
- return -EPROBE_DEFER;
-
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&pdev->dev, "Failed to allocate ci_hdrc-imx data!\n");
return -ENOMEM;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Can't get device resources!\n");
- return -ENOENT;
- }
+ data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
+ if (IS_ERR(data->usbmisc_data))
+ return PTR_ERR(data->usbmisc_data);
data->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(data->clk)) {
@@ -141,20 +119,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
goto err_clk;
}
- /* we only support host now, so enable vbus here */
- data->reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
- if (!IS_ERR(data->reg_vbus)) {
- ret = regulator_enable(data->reg_vbus);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to enable vbus regulator, err=%d\n",
- ret);
- goto err_clk;
- }
- } else {
- data->reg_vbus = NULL;
- }
-
pdata.phy = data->phy;
if (!pdev->dev.dma_mask)
@@ -162,12 +126,12 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
if (!pdev->dev.coherent_dma_mask)
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- if (usbmisc_ops && usbmisc_ops->init) {
- ret = usbmisc_ops->init(&pdev->dev);
+ if (data->usbmisc_data) {
+ ret = imx_usbmisc_init(data->usbmisc_data);
if (ret) {
- dev_err(&pdev->dev,
- "usbmisc init failed, ret=%d\n", ret);
- goto err;
+ dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n",
+ ret);
+ goto err_clk;
}
}
@@ -179,14 +143,14 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"Can't register ci_hdrc platform device, err=%d\n",
ret);
- goto err;
+ goto err_clk;
}
- if (usbmisc_ops && usbmisc_ops->post) {
- ret = usbmisc_ops->post(&pdev->dev);
+ if (data->usbmisc_data) {
+ ret = imx_usbmisc_init_post(data->usbmisc_data);
if (ret) {
- dev_err(&pdev->dev,
- "usbmisc post failed, ret=%d\n", ret);
+ dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n",
+ ret);
goto disable_device;
}
}
@@ -200,9 +164,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
disable_device:
ci_hdrc_remove_device(data->ci_pdev);
-err:
- if (data->reg_vbus)
- regulator_disable(data->reg_vbus);
err_clk:
clk_disable_unprepare(data->clk);
return ret;
@@ -215,13 +176,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
ci_hdrc_remove_device(data->ci_pdev);
- if (data->reg_vbus)
- regulator_disable(data->reg_vbus);
-
- if (data->phy) {
+ if (data->phy)
usb_phy_shutdown(data->phy);
- module_put(data->phy->dev->driver->owner);
- }
clk_disable_unprepare(data->clk);
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h
index 550bfa45762..c7271590dd0 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.h
+++ b/drivers/usb/chipidea/ci_hdrc_imx.h
@@ -9,23 +9,12 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-/* Used to set SoC specific callbacks */
-struct usbmisc_ops {
- /* It's called once when probe a usb device */
- int (*init)(struct device *dev);
- /* It's called once after adding a usb device */
- int (*post)(struct device *dev);
-};
-
-struct usbmisc_usb_device {
- struct device *dev; /* usb controller device */
+struct imx_usbmisc_data {
int index;
unsigned int disable_oc:1; /* over current detect disabled */
unsigned int evdo:1; /* set external vbus divider option */
};
-int usbmisc_set_ops(const struct usbmisc_ops *ops);
-void usbmisc_unset_ops(const struct usbmisc_ops *ops);
-int
-usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev);
+int imx_usbmisc_init(struct imx_usbmisc_data *);
+int imx_usbmisc_init_post(struct imx_usbmisc_data *);
diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index fb657ef50a9..2d51d852b47 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -49,7 +49,6 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
.name = "ci_hdrc_msm",
.flags = CI_HDRC_REGS_SHARED |
CI_HDRC_REQUIRE_TRANSCEIVER |
- CI_HDRC_PULLUP_ON_VBUS |
CI_HDRC_DISABLE_STREAMING,
.notify_event = ci_hdrc_msm_notify_event,
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index a5df24c578f..94626409559 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -65,12 +65,14 @@
#include <linux/usb/chipidea.h>
#include <linux/usb/of.h>
#include <linux/phy.h>
+#include <linux/regulator/consumer.h>
#include "ci.h"
#include "udc.h"
#include "bits.h"
#include "host.h"
#include "debug.h"
+#include "otg.h"
/* Controller register map */
static uintptr_t ci_regs_nolpm[] = {
@@ -197,6 +199,12 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)
if (ci->hw_ep_max > ENDPT_MAX)
return -ENODEV;
+ /* Disable all interrupts bits */
+ hw_write(ci, OP_USBINTR, 0xffffffff, 0);
+
+ /* Clear all interrupts status bits*/
+ hw_write(ci, OP_USBSTS, 0xffffffff, 0xffffffff);
+
dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n",
ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op);
@@ -264,8 +272,6 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode)
while (hw_read(ci, OP_USBCMD, USBCMD_RST))
udelay(10); /* not RTOS friendly */
- hw_phymode_configure(ci);
-
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
CI_HDRC_CONTROLLER_RESET_EVENT);
@@ -289,37 +295,35 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode)
}
/**
- * ci_otg_role - pick role based on ID pin state
+ * hw_wait_reg: wait the register value
+ *
+ * Sometimes, it needs to wait register value before going on.
+ * Eg, when switch to device mode, the vbus value should be lower
+ * than OTGSC_BSV before connects to host.
+ *
* @ci: the controller
+ * @reg: register index
+ * @mask: mast bit
+ * @value: the bit value to wait
+ * @timeout_ms: timeout in millisecond
+ *
+ * This function returns an error code if timeout
*/
-static enum ci_role ci_otg_role(struct ci_hdrc *ci)
-{
- u32 sts = hw_read(ci, OP_OTGSC, ~0);
- enum ci_role role = sts & OTGSC_ID
- ? CI_ROLE_GADGET
- : CI_ROLE_HOST;
-
- return role;
-}
-
-/**
- * ci_role_work - perform role changing based on ID pin
- * @work: work struct
- */
-static void ci_role_work(struct work_struct *work)
+int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
+ u32 value, unsigned int timeout_ms)
{
- struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
- enum ci_role role = ci_otg_role(ci);
-
- if (role != ci->role) {
- dev_dbg(ci->dev, "switching from %s to %s\n",
- ci_role(ci)->name, ci->roles[role]->name);
-
- ci_role_stop(ci);
- ci_role_start(ci, role);
+ unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms);
+
+ while (hw_read(ci, reg, mask) != value) {
+ if (time_after(jiffies, elapse)) {
+ dev_err(ci->dev, "timeout waiting for %08x in %d\n",
+ mask, reg);
+ return -ETIMEDOUT;
+ }
+ msleep(20);
}
- enable_irq(ci->irq);
+ return 0;
}
static irqreturn_t ci_irq(int irq, void *data)
@@ -331,19 +335,55 @@ static irqreturn_t ci_irq(int irq, void *data)
if (ci->is_otg)
otgsc = hw_read(ci, OP_OTGSC, ~0);
- if (ci->role != CI_ROLE_END)
- ret = ci_role(ci)->irq(ci);
+ /*
+ * Handle id change interrupt, it indicates device/host function
+ * switch.
+ */
+ if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
+ ci->id_event = true;
+ ci_clear_otg_interrupt(ci, OTGSC_IDIS);
+ disable_irq_nosync(ci->irq);
+ queue_work(ci->wq, &ci->work);
+ return IRQ_HANDLED;
+ }
- if (ci->is_otg && (otgsc & OTGSC_IDIS)) {
- hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
+ /*
+ * Handle vbus change interrupt, it indicates device connection
+ * and disconnection events.
+ */
+ if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
+ ci->b_sess_valid_event = true;
+ ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
disable_irq_nosync(ci->irq);
queue_work(ci->wq, &ci->work);
- ret = IRQ_HANDLED;
+ return IRQ_HANDLED;
}
+ /* Handle device/host interrupt */
+ if (ci->role != CI_ROLE_END)
+ ret = ci_role(ci)->irq(ci);
+
return ret;
}
+static int ci_get_platdata(struct device *dev,
+ struct ci_hdrc_platform_data *platdata)
+{
+ /* Get the vbus regulator */
+ platdata->reg_vbus = devm_regulator_get(dev, "vbus");
+ if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) {
+ return -EPROBE_DEFER;
+ } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) {
+ platdata->reg_vbus = NULL; /* no vbus regualator is needed */
+ } else if (IS_ERR(platdata->reg_vbus)) {
+ dev_err(dev, "Getting regulator error: %ld\n",
+ PTR_ERR(platdata->reg_vbus));
+ return PTR_ERR(platdata->reg_vbus);
+ }
+
+ return 0;
+}
+
static DEFINE_IDA(ci_ida);
struct platform_device *ci_hdrc_add_device(struct device *dev,
@@ -353,6 +393,10 @@ struct platform_device *ci_hdrc_add_device(struct device *dev,
struct platform_device *pdev;
int id, ret;
+ ret = ci_get_platdata(dev, platdata);
+ if (ret)
+ return ERR_PTR(ret);
+
id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL);
if (id < 0)
return ERR_PTR(id);
@@ -398,6 +442,29 @@ void ci_hdrc_remove_device(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(ci_hdrc_remove_device);
+static inline void ci_role_destroy(struct ci_hdrc *ci)
+{
+ ci_hdrc_gadget_destroy(ci);
+ ci_hdrc_host_destroy(ci);
+ if (ci->is_otg)
+ ci_hdrc_otg_destroy(ci);
+}
+
+static void ci_get_otg_capable(struct ci_hdrc *ci)
+{
+ if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG)
+ ci->is_otg = false;
+ else
+ ci->is_otg = (hw_read(ci, CAP_DCCPARAMS,
+ DCCPARAMS_DC | DCCPARAMS_HC)
+ == (DCCPARAMS_DC | DCCPARAMS_HC));
+ if (ci->is_otg) {
+ dev_dbg(ci->dev, "It is OTG capable controller\n");
+ ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS);
+ ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS);
+ }
+}
+
static int ci_hdrc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -406,15 +473,13 @@ static int ci_hdrc_probe(struct platform_device *pdev)
void __iomem *base;
int ret;
enum usb_dr_mode dr_mode;
+ struct device_node *of_node = dev->of_node ?: dev->parent->of_node;
if (!dev->platform_data) {
dev_err(dev, "platform data missing\n");
return -ENODEV;
}
- if (!dev->of_node && dev->parent)
- dev->of_node = dev->parent->of_node;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
@@ -447,18 +512,15 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
- INIT_WORK(&ci->work, ci_role_work);
- ci->wq = create_singlethread_workqueue("ci_otg");
- if (!ci->wq) {
- dev_err(dev, "can't create workqueue\n");
- return -ENODEV;
- }
+ ci_get_otg_capable(ci);
if (!ci->platdata->phy_mode)
- ci->platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
+ ci->platdata->phy_mode = of_usb_get_phy_mode(of_node);
+
+ hw_phymode_configure(ci);
if (!ci->platdata->dr_mode)
- ci->platdata->dr_mode = of_usb_get_dr_mode(dev->of_node);
+ ci->platdata->dr_mode = of_usb_get_dr_mode(of_node);
if (ci->platdata->dr_mode == USB_DR_MODE_UNKNOWN)
ci->platdata->dr_mode = USB_DR_MODE_OTG;
@@ -479,15 +541,34 @@ static int ci_hdrc_probe(struct platform_device *pdev)
if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
dev_err(dev, "no supported roles\n");
- ret = -ENODEV;
- goto rm_wq;
+ return -ENODEV;
+ }
+
+ if (ci->is_otg) {
+ ret = ci_hdrc_otg_init(ci);
+ if (ret) {
+ dev_err(dev, "init otg fails, ret = %d\n", ret);
+ goto stop;
+ }
}
if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
- ci->is_otg = true;
- /* ID pin needs 1ms debouce time, we delay 2ms for safe */
- mdelay(2);
- ci->role = ci_otg_role(ci);
+ if (ci->is_otg) {
+ /*
+ * ID pin needs 1ms debouce time,
+ * we delay 2ms for safe.
+ */
+ mdelay(2);
+ ci->role = ci_otg_role(ci);
+ ci_enable_otg_interrupt(ci, OTGSC_IDIE);
+ } else {
+ /*
+ * If the controller is not OTG capable, but support
+ * role switch, the defalt role is gadget, and the
+ * user can switch it through debugfs.
+ */
+ ci->role = CI_ROLE_GADGET;
+ }
} else {
ci->role = ci->roles[CI_ROLE_HOST]
? CI_ROLE_HOST
@@ -497,8 +578,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
ret = ci_role_start(ci, ci->role);
if (ret) {
dev_err(dev, "can't start %s role\n", ci_role(ci)->name);
- ret = -ENODEV;
- goto rm_wq;
+ goto stop;
}
platform_set_drvdata(pdev, ci);
@@ -507,19 +587,13 @@ static int ci_hdrc_probe(struct platform_device *pdev)
if (ret)
goto stop;
- if (ci->is_otg)
- hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
-
ret = dbg_create_files(ci);
if (!ret)
return 0;
free_irq(ci->irq, ci);
stop:
- ci_role_stop(ci);
-rm_wq:
- flush_workqueue(ci->wq);
- destroy_workqueue(ci->wq);
+ ci_role_destroy(ci);
return ret;
}
@@ -529,10 +603,8 @@ static int ci_hdrc_remove(struct platform_device *pdev)
struct ci_hdrc *ci = platform_get_drvdata(pdev);
dbg_remove_files(ci);
- flush_workqueue(ci->wq);
- destroy_workqueue(ci->wq);
free_irq(ci->irq, ci);
- ci_role_stop(ci);
+ ci_role_destroy(ci);
return 0;
}
@@ -548,7 +620,6 @@ static struct platform_driver ci_hdrc_driver = {
module_platform_driver(ci_hdrc_driver);
MODULE_ALIAS("platform:ci_hdrc");
-MODULE_ALIAS("platform:ci13xxx");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>");
MODULE_DESCRIPTION("ChipIdea HDRC Driver");
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 40d0fda4f66..6f96795dd20 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -24,6 +24,7 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/chipidea.h>
+#include <linux/regulator/consumer.h>
#include "../host/ehci.h"
@@ -63,10 +64,21 @@ static int host_start(struct ci_hdrc *ci)
ehci = hcd_to_ehci(hcd);
ehci->caps = ci->hw_bank.cap;
ehci->has_hostpc = ci->hw_bank.lpm;
+ ehci->has_tdi_phy_lpm = ci->hw_bank.lpm;
+
+ if (ci->platdata->reg_vbus) {
+ ret = regulator_enable(ci->platdata->reg_vbus);
+ if (ret) {
+ dev_err(ci->dev,
+ "Failed to enable vbus regulator, ret=%d\n",
+ ret);
+ goto put_hcd;
+ }
+ }
ret = usb_add_hcd(hcd, 0, 0);
if (ret)
- usb_put_hcd(hcd);
+ goto disable_reg;
else
ci->hcd = hcd;
@@ -74,6 +86,14 @@ static int host_start(struct ci_hdrc *ci)
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
return ret;
+
+disable_reg:
+ regulator_disable(ci->platdata->reg_vbus);
+
+put_hcd:
+ usb_put_hcd(hcd);
+
+ return ret;
}
static void host_stop(struct ci_hdrc *ci)
@@ -82,6 +102,15 @@ static void host_stop(struct ci_hdrc *ci)
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
+ if (ci->platdata->reg_vbus)
+ regulator_disable(ci->platdata->reg_vbus);
+}
+
+
+void ci_hdrc_host_destroy(struct ci_hdrc *ci)
+{
+ if (ci->role == CI_ROLE_HOST)
+ host_stop(ci);
}
int ci_hdrc_host_init(struct ci_hdrc *ci)
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
index 058875c1533..5707bf379bf 100644
--- a/drivers/usb/chipidea/host.h
+++ b/drivers/usb/chipidea/host.h
@@ -4,6 +4,7 @@
#ifdef CONFIG_USB_CHIPIDEA_HOST
int ci_hdrc_host_init(struct ci_hdrc *ci);
+void ci_hdrc_host_destroy(struct ci_hdrc *ci);
#else
@@ -12,6 +13,11 @@ static inline int ci_hdrc_host_init(struct ci_hdrc *ci)
return -ENXIO;
}
+static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci)
+{
+
+}
+
#endif
#endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
new file mode 100644
index 00000000000..39bd7ec8bf7
--- /dev/null
+++ b/drivers/usb/chipidea/otg.c
@@ -0,0 +1,120 @@
+/*
+ * otg.c - ChipIdea USB IP core OTG driver
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Peter Chen
+ *
+ * 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 file mainly handles otgsc register, it may include OTG operation
+ * in the future.
+ */
+
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "bits.h"
+#include "otg.h"
+
+/**
+ * ci_otg_role - pick role based on ID pin state
+ * @ci: the controller
+ */
+enum ci_role ci_otg_role(struct ci_hdrc *ci)
+{
+ u32 sts = hw_read(ci, OP_OTGSC, ~0);
+ enum ci_role role = sts & OTGSC_ID
+ ? CI_ROLE_GADGET
+ : CI_ROLE_HOST;
+
+ return role;
+}
+
+void ci_handle_vbus_change(struct ci_hdrc *ci)
+{
+ u32 otgsc;
+
+ if (!ci->is_otg)
+ return;
+
+ otgsc = hw_read(ci, OP_OTGSC, ~0);
+
+ if (otgsc & OTGSC_BSV)
+ usb_gadget_vbus_connect(&ci->gadget);
+ else
+ usb_gadget_vbus_disconnect(&ci->gadget);
+}
+
+#define CI_VBUS_STABLE_TIMEOUT_MS 5000
+static void ci_handle_id_switch(struct ci_hdrc *ci)
+{
+ enum ci_role role = ci_otg_role(ci);
+
+ if (role != ci->role) {
+ dev_dbg(ci->dev, "switching from %s to %s\n",
+ ci_role(ci)->name, ci->roles[role]->name);
+
+ ci_role_stop(ci);
+ /* wait vbus lower than OTGSC_BSV */
+ hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
+ CI_VBUS_STABLE_TIMEOUT_MS);
+ ci_role_start(ci, role);
+ }
+}
+/**
+ * ci_otg_work - perform otg (vbus/id) event handle
+ * @work: work struct
+ */
+static void ci_otg_work(struct work_struct *work)
+{
+ struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
+
+ if (ci->id_event) {
+ ci->id_event = false;
+ ci_handle_id_switch(ci);
+ } else if (ci->b_sess_valid_event) {
+ ci->b_sess_valid_event = false;
+ ci_handle_vbus_change(ci);
+ } else
+ dev_err(ci->dev, "unexpected event occurs at %s\n", __func__);
+
+ enable_irq(ci->irq);
+}
+
+
+/**
+ * ci_hdrc_otg_init - initialize otg struct
+ * ci: the controller
+ */
+int ci_hdrc_otg_init(struct ci_hdrc *ci)
+{
+ INIT_WORK(&ci->work, ci_otg_work);
+ ci->wq = create_singlethread_workqueue("ci_otg");
+ if (!ci->wq) {
+ dev_err(ci->dev, "can't create workqueue\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * ci_hdrc_otg_destroy - destroy otg struct
+ * ci: the controller
+ */
+void ci_hdrc_otg_destroy(struct ci_hdrc *ci)
+{
+ if (ci->wq) {
+ flush_workqueue(ci->wq);
+ destroy_workqueue(ci->wq);
+ }
+ ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS);
+ ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS);
+}
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
new file mode 100644
index 00000000000..2d9f090733b
--- /dev/null
+++ b/drivers/usb/chipidea/otg.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Peter Chen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_USB_CHIPIDEA_OTG_H
+#define __DRIVERS_USB_CHIPIDEA_OTG_H
+
+static inline void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits)
+{
+ /* Only clear request bits */
+ hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits);
+}
+
+static inline void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits)
+{
+ hw_write(ci, OP_OTGSC, bits, bits);
+}
+
+static inline void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits)
+{
+ hw_write(ci, OP_OTGSC, bits, 0);
+}
+
+int ci_hdrc_otg_init(struct ci_hdrc *ci);
+void ci_hdrc_otg_destroy(struct ci_hdrc *ci);
+enum ci_role ci_otg_role(struct ci_hdrc *ci);
+void ci_handle_vbus_change(struct ci_hdrc *ci);
+
+#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index e475fcda1d6..6b4c2f2eb94 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -27,6 +27,7 @@
#include "udc.h"
#include "bits.h"
#include "debug.h"
+#include "otg.h"
/* control endpoint description */
static const struct usb_endpoint_descriptor
@@ -84,8 +85,10 @@ static int hw_device_state(struct ci_hdrc *ci, u32 dma)
/* interrupt, error, port change, reset, sleep/suspend */
hw_write(ci, OP_USBINTR, ~0,
USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+ hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
} else {
hw_write(ci, OP_USBINTR, ~0, 0);
+ hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
}
return 0;
}
@@ -1445,9 +1448,6 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
unsigned long flags;
int gadget_ready = 0;
- if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS))
- return -EOPNOTSUPP;
-
spin_lock_irqsave(&ci->lock, flags);
ci->vbus_active = is_active;
if (ci->driver)
@@ -1459,6 +1459,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
pm_runtime_get_sync(&_gadget->dev);
hw_device_reset(ci, USBMODE_CM_DC);
hw_device_state(ci, ci->ep0out->qh.dma);
+ dev_dbg(ci->dev, "Connected to host\n");
} else {
hw_device_state(ci, 0);
if (ci->platdata->notify_event)
@@ -1466,6 +1467,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
CI_HDRC_CONTROLLER_STOPPED_EVENT);
_gadget_stop_activity(&ci->gadget);
pm_runtime_put_sync(&_gadget->dev);
+ dev_dbg(ci->dev, "Disconnected from host\n");
}
}
@@ -1509,6 +1511,9 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
+ if (!ci->vbus_active)
+ return -EOPNOTSUPP;
+
if (is_on)
hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
else
@@ -1630,14 +1635,11 @@ static int ci_udc_start(struct usb_gadget *gadget,
ci->driver = driver;
pm_runtime_get_sync(&ci->gadget.dev);
- if (ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS) {
- if (ci->vbus_active) {
- if (ci->platdata->flags & CI_HDRC_REGS_SHARED)
- hw_device_reset(ci, USBMODE_CM_DC);
- } else {
- pm_runtime_put_sync(&ci->gadget.dev);
- goto done;
- }
+ if (ci->vbus_active) {
+ hw_device_reset(ci, USBMODE_CM_DC);
+ } else {
+ pm_runtime_put_sync(&ci->gadget.dev);
+ goto done;
}
retval = hw_device_state(ci, ci->ep0out->qh.dma);
@@ -1660,8 +1662,7 @@ static int ci_udc_stop(struct usb_gadget *gadget,
spin_lock_irqsave(&ci->lock, flags);
- if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS) ||
- ci->vbus_active) {
+ if (ci->vbus_active) {
hw_device_state(ci, 0);
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
@@ -1796,16 +1797,15 @@ static int udc_start(struct ci_hdrc *ci)
}
}
- if (!(ci->platdata->flags & CI_HDRC_REGS_SHARED)) {
- retval = hw_device_reset(ci, USBMODE_CM_DC);
- if (retval)
- goto put_transceiver;
- }
-
if (ci->transceiver) {
retval = otg_set_peripheral(ci->transceiver->otg,
&ci->gadget);
- if (retval)
+ /*
+ * If we implement all USB functions using chipidea drivers,
+ * it doesn't need to call above API, meanwhile, if we only
+ * use gadget function, calling above API is useless.
+ */
+ if (retval && retval != -ENOTSUPP)
goto put_transceiver;
}
@@ -1816,6 +1816,9 @@ static int udc_start(struct ci_hdrc *ci)
pm_runtime_no_callbacks(&ci->gadget.dev);
pm_runtime_enable(&ci->gadget.dev);
+ /* Update ci->vbus_active */
+ ci_handle_vbus_change(ci);
+
return retval;
remove_trans:
@@ -1839,13 +1842,13 @@ free_qh_pool:
}
/**
- * udc_remove: parent remove must call this to remove UDC
+ * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
*
* No interrupts active, the IRQ has been released
*/
-static void udc_stop(struct ci_hdrc *ci)
+void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
{
- if (ci == NULL)
+ if (!ci->roles[CI_ROLE_GADGET])
return;
usb_del_gadget_udc(&ci->gadget);
@@ -1860,15 +1863,32 @@ static void udc_stop(struct ci_hdrc *ci)
if (ci->global_phy)
usb_put_phy(ci->transceiver);
}
- /* my kobject is dynamic, I swear! */
- memset(&ci->gadget, 0, sizeof(ci->gadget));
+}
+
+static int udc_id_switch_for_device(struct ci_hdrc *ci)
+{
+ if (ci->is_otg) {
+ ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+ ci_enable_otg_interrupt(ci, OTGSC_BSVIE);
+ }
+
+ return 0;
+}
+
+static void udc_id_switch_for_host(struct ci_hdrc *ci)
+{
+ if (ci->is_otg) {
+ /* host doesn't care B_SESSION_VALID event */
+ ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+ ci_disable_otg_interrupt(ci, OTGSC_BSVIE);
+ }
}
/**
* ci_hdrc_gadget_init - initialize device related bits
* ci: the controller
*
- * This function enables the gadget role, if the device is "device capable".
+ * This function initializes the gadget, if the device is "device capable".
*/
int ci_hdrc_gadget_init(struct ci_hdrc *ci)
{
@@ -1881,11 +1901,11 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
if (!rdrv)
return -ENOMEM;
- rdrv->start = udc_start;
- rdrv->stop = udc_stop;
+ rdrv->start = udc_id_switch_for_device;
+ rdrv->stop = udc_id_switch_for_host;
rdrv->irq = udc_irq;
rdrv->name = "gadget";
ci->roles[CI_ROLE_GADGET] = rdrv;
- return 0;
+ return udc_start(ci);
}
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
index 455ac216922..e66df0020bd 100644
--- a/drivers/usb/chipidea/udc.h
+++ b/drivers/usb/chipidea/udc.h
@@ -84,6 +84,7 @@ struct ci_hw_req {
#ifdef CONFIG_USB_CHIPIDEA_UDC
int ci_hdrc_gadget_init(struct ci_hdrc *ci);
+void ci_hdrc_gadget_destroy(struct ci_hdrc *ci);
#else
@@ -92,6 +93,11 @@ static inline int ci_hdrc_gadget_init(struct ci_hdrc *ci)
return -ENXIO;
}
+static inline void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
+{
+
+}
+
#endif
#endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index ac5a4615520..8a1094b1182 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -18,8 +18,6 @@
#include "ci_hdrc_imx.h"
-#define USB_DEV_MAX 4
-
#define MX25_USB_PHY_CTRL_OFFSET 0x08
#define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23)
@@ -32,51 +30,34 @@
#define MX6_BM_OVER_CUR_DIS BIT(7)
+struct usbmisc_ops {
+ /* It's called once when probe a usb device */
+ int (*init)(struct imx_usbmisc_data *data);
+ /* It's called once after adding a usb device */
+ int (*post)(struct imx_usbmisc_data *data);
+};
+
struct imx_usbmisc {
void __iomem *base;
spinlock_t lock;
struct clk *clk;
- struct usbmisc_usb_device usbdev[USB_DEV_MAX];
const struct usbmisc_ops *ops;
};
static struct imx_usbmisc *usbmisc;
-static struct usbmisc_usb_device *get_usbdev(struct device *dev)
-{
- int i, ret;
-
- for (i = 0; i < USB_DEV_MAX; i++) {
- if (usbmisc->usbdev[i].dev == dev)
- return &usbmisc->usbdev[i];
- else if (!usbmisc->usbdev[i].dev)
- break;
- }
-
- if (i >= USB_DEV_MAX)
- return ERR_PTR(-EBUSY);
-
- ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
- if (ret)
- return ERR_PTR(ret);
-
- return &usbmisc->usbdev[i];
-}
-
-static int usbmisc_imx25_post(struct device *dev)
+static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
{
- struct usbmisc_usb_device *usbdev;
void __iomem *reg;
unsigned long flags;
u32 val;
- usbdev = get_usbdev(dev);
- if (IS_ERR(usbdev))
- return PTR_ERR(usbdev);
+ if (data->index > 2)
+ return -EINVAL;
reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
- if (usbdev->evdo) {
+ if (data->evdo) {
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(reg);
writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
@@ -87,20 +68,18 @@ static int usbmisc_imx25_post(struct device *dev)
return 0;
}
-static int usbmisc_imx53_init(struct device *dev)
+static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
{
- struct usbmisc_usb_device *usbdev;
void __iomem *reg = NULL;
unsigned long flags;
u32 val = 0;
- usbdev = get_usbdev(dev);
- if (IS_ERR(usbdev))
- return PTR_ERR(usbdev);
+ if (data->index > 3)
+ return -EINVAL;
- if (usbdev->disable_oc) {
+ if (data->disable_oc) {
spin_lock_irqsave(&usbmisc->lock, flags);
- switch (usbdev->index) {
+ switch (data->index) {
case 0:
reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
@@ -126,22 +105,19 @@ static int usbmisc_imx53_init(struct device *dev)
return 0;
}
-static int usbmisc_imx6q_init(struct device *dev)
+static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
{
-
- struct usbmisc_usb_device *usbdev;
unsigned long flags;
u32 reg;
- usbdev = get_usbdev(dev);
- if (IS_ERR(usbdev))
- return PTR_ERR(usbdev);
+ if (data->index > 3)
+ return -EINVAL;
- if (usbdev->disable_oc) {
+ if (data->disable_oc) {
spin_lock_irqsave(&usbmisc->lock, flags);
- reg = readl(usbmisc->base + usbdev->index * 4);
+ reg = readl(usbmisc->base + data->index * 4);
writel(reg | MX6_BM_OVER_CUR_DIS,
- usbmisc->base + usbdev->index * 4);
+ usbmisc->base + data->index * 4);
spin_unlock_irqrestore(&usbmisc->lock, flags);
}
@@ -160,6 +136,26 @@ static const struct usbmisc_ops imx6q_usbmisc_ops = {
.init = usbmisc_imx6q_init,
};
+int imx_usbmisc_init(struct imx_usbmisc_data *data)
+{
+ if (!usbmisc)
+ return -EPROBE_DEFER;
+ if (!usbmisc->ops->init)
+ return 0;
+ return usbmisc->ops->init(data);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_init);
+
+int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
+{
+ if (!usbmisc)
+ return -EPROBE_DEFER;
+ if (!usbmisc->ops->post)
+ return 0;
+ return usbmisc->ops->post(data);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
+
static const struct of_device_id usbmisc_imx_dt_ids[] = {
{
.compatible = "fsl,imx25-usbmisc",
@@ -216,19 +212,12 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
data->ops = (const struct usbmisc_ops *)tmp_dev->data;
usbmisc = data;
- ret = usbmisc_set_ops(data->ops);
- if (ret) {
- usbmisc = NULL;
- clk_disable_unprepare(data->clk);
- return ret;
- }
return 0;
}
static int usbmisc_imx_remove(struct platform_device *pdev)
{
- usbmisc_unset_ops(usbmisc->ops);
clk_disable_unprepare(usbmisc->clk);
usbmisc = NULL;
return 0;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 9f49bfe4c6f..3e7560f004f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1295,7 +1295,7 @@ skip_countries:
usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
/* works around buggy devices */
- epctrl->bInterval ? epctrl->bInterval : 0xff);
+ epctrl->bInterval ? epctrl->bInterval : 16);
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
acm->ctrlurb->transfer_dma = acm->ctrl_dma;
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 8a230f0ef77..d3318a0df8e 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -209,6 +209,7 @@ skip_error:
static void wdm_int_callback(struct urb *urb)
{
int rv = 0;
+ int responding;
int status = urb->status;
struct wdm_device *desc;
struct usb_cdc_notification *dr;
@@ -262,8 +263,8 @@ static void wdm_int_callback(struct urb *urb)
spin_lock(&desc->iuspin);
clear_bit(WDM_READ, &desc->flags);
- set_bit(WDM_RESPONDING, &desc->flags);
- if (!test_bit(WDM_DISCONNECTING, &desc->flags)
+ responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
+ if (!responding && !test_bit(WDM_DISCONNECTING, &desc->flags)
&& !test_bit(WDM_SUSPENDING, &desc->flags)) {
rv = usb_submit_urb(desc->response, GFP_ATOMIC);
dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d",
@@ -685,16 +686,20 @@ static void wdm_rxwork(struct work_struct *work)
{
struct wdm_device *desc = container_of(work, struct wdm_device, rxwork);
unsigned long flags;
- int rv;
+ int rv = 0;
+ int responding;
spin_lock_irqsave(&desc->iuspin, flags);
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
spin_unlock_irqrestore(&desc->iuspin, flags);
} else {
+ responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
spin_unlock_irqrestore(&desc->iuspin, flags);
- rv = usb_submit_urb(desc->response, GFP_KERNEL);
+ if (!responding)
+ rv = usb_submit_urb(desc->response, GFP_KERNEL);
if (rv < 0 && rv != -EPERM) {
spin_lock_irqsave(&desc->iuspin, flags);
+ clear_bit(WDM_RESPONDING, &desc->flags);
if (!test_bit(WDM_DISCONNECTING, &desc->flags))
schedule_work(&desc->rxwork);
spin_unlock_irqrestore(&desc->iuspin, flags);
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 609dbc2f715..09de131ee0c 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -19,6 +19,8 @@
* http://www.gnu.org/copyleft/gpl.html.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -119,7 +121,6 @@ static void usbtmc_delete(struct kref *kref)
struct usbtmc_device_data *data = to_usbtmc_data(kref);
usb_put_dev(data->usb_dev);
- kfree(data);
}
static int usbtmc_open(struct inode *inode, struct file *filp)
@@ -130,10 +131,8 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
intf = usb_find_interface(&usbtmc_driver, iminor(inode));
if (!intf) {
- printk(KERN_ERR KBUILD_MODNAME
- ": can not find device for minor %d", iminor(inode));
- retval = -ENODEV;
- goto exit;
+ pr_err("can not find device for minor %d", iminor(inode));
+ return -ENODEV;
}
data = usb_get_intfdata(intf);
@@ -142,7 +141,6 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
/* Store pointer in file structure's private data field */
filp->private_data = data;
-exit:
return retval;
}
@@ -394,12 +392,12 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
*/
buffer[0] = 2;
buffer[1] = data->bTag;
- buffer[2] = ~(data->bTag);
+ buffer[2] = ~data->bTag;
buffer[3] = 0; /* Reserved */
- buffer[4] = (transfer_size) & 255;
- buffer[5] = ((transfer_size) >> 8) & 255;
- buffer[6] = ((transfer_size) >> 16) & 255;
- buffer[7] = ((transfer_size) >> 24) & 255;
+ buffer[4] = transfer_size >> 0;
+ buffer[5] = transfer_size >> 8;
+ buffer[6] = transfer_size >> 16;
+ buffer[7] = transfer_size >> 24;
buffer[8] = data->TermCharEnabled * 2;
/* Use term character? */
buffer[9] = data->TermChar;
@@ -418,7 +416,7 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
/* Increment bTag -- and increment again if zero */
data->bTag++;
if (!data->bTag)
- (data->bTag)++;
+ data->bTag++;
if (retval < 0) {
dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval);
@@ -473,7 +471,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
done = 0;
while (remaining > 0) {
- if (!(data->rigol_quirk)) {
+ if (!data->rigol_quirk) {
dev_dbg(dev, "usb_bulk_msg_in: remaining(%zu), count(%zu)\n", remaining, count);
if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3)
@@ -510,7 +508,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
}
/* Parse header in first packet */
- if ((done == 0) || (!(data->rigol_quirk))) {
+ if ((done == 0) || !data->rigol_quirk) {
/* Sanity checks for the header */
if (actual < USBTMC_HEADER_SIZE) {
dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE);
@@ -554,14 +552,14 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
if (remaining > n_characters)
remaining = n_characters;
/* Remove padding if it exists */
- if (actual > remaining)
+ if (actual > remaining)
actual = remaining;
}
else {
if (this_part > n_characters)
this_part = n_characters;
/* Remove padding if it exists */
- if (actual > this_part)
+ if (actual > this_part)
actual = this_part;
}
@@ -570,7 +568,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
remaining -= actual;
/* Terminate if end-of-message bit received from device */
- if ((buffer[8] & 0x01) && (actual >= n_characters))
+ if ((buffer[8] & 0x01) && (actual >= n_characters))
remaining = 0;
dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done);
@@ -585,7 +583,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
done += actual;
}
else {
- if (actual > remaining)
+ if (actual > remaining)
actual = remaining;
remaining -= actual;
@@ -651,12 +649,12 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
/* Setup IO buffer for DEV_DEP_MSG_OUT message */
buffer[0] = 1;
buffer[1] = data->bTag;
- buffer[2] = ~(data->bTag);
+ buffer[2] = ~data->bTag;
buffer[3] = 0; /* Reserved */
- buffer[4] = this_part & 255;
- buffer[5] = (this_part >> 8) & 255;
- buffer[6] = (this_part >> 16) & 255;
- buffer[7] = (this_part >> 24) & 255;
+ buffer[4] = this_part >> 0;
+ buffer[5] = this_part >> 8;
+ buffer[6] = this_part >> 16;
+ buffer[7] = this_part >> 24;
/* buffer[8] is set above... */
buffer[9] = 0; /* Reserved */
buffer[10] = 0; /* Reserved */
@@ -901,7 +899,7 @@ err_out:
}
#define capability_attribute(name) \
-static ssize_t show_##name(struct device *dev, \
+static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
@@ -909,7 +907,7 @@ static ssize_t show_##name(struct device *dev, \
\
return sprintf(buf, "%d\n", data->capabilities.name); \
} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR_RO(name)
capability_attribute(interface_capabilities);
capability_attribute(device_capabilities);
@@ -928,7 +926,7 @@ static struct attribute_group capability_attr_grp = {
.attrs = capability_attrs,
};
-static ssize_t show_TermChar(struct device *dev,
+static ssize_t TermChar_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@@ -937,7 +935,7 @@ static ssize_t show_TermChar(struct device *dev,
return sprintf(buf, "%c\n", data->TermChar);
}
-static ssize_t store_TermChar(struct device *dev,
+static ssize_t TermChar_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -949,10 +947,10 @@ static ssize_t store_TermChar(struct device *dev,
data->TermChar = buf[0];
return count;
}
-static DEVICE_ATTR(TermChar, S_IRUGO, show_TermChar, store_TermChar);
+static DEVICE_ATTR_RW(TermChar);
#define data_attribute(name) \
-static ssize_t show_##name(struct device *dev, \
+static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
@@ -960,7 +958,7 @@ static ssize_t show_##name(struct device *dev, \
\
return sprintf(buf, "%d\n", data->name); \
} \
-static ssize_t store_##name(struct device *dev, \
+static ssize_t name##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
@@ -978,7 +976,7 @@ static ssize_t store_##name(struct device *dev, \
else \
return count; \
} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, store_##name)
+static DEVICE_ATTR_RW(name)
data_attribute(TermCharEnabled);
data_attribute(auto_abort);
@@ -1102,7 +1100,7 @@ static int usbtmc_probe(struct usb_interface *intf,
dev_dbg(&intf->dev, "%s called\n", __func__);
- data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL);
+ data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&intf->dev, "Unable to allocate kernel memory\n");
return -ENOMEM;
@@ -1119,11 +1117,11 @@ static int usbtmc_probe(struct usb_interface *intf,
/* Determine if it is a Rigol or not */
data->rigol_quirk = 0;
dev_dbg(&intf->dev, "Trying to find if device Vendor 0x%04X Product 0x%04X has the RIGOL quirk\n",
- data->usb_dev->descriptor.idVendor,
- data->usb_dev->descriptor.idProduct);
+ le16_to_cpu(data->usb_dev->descriptor.idVendor),
+ le16_to_cpu(data->usb_dev->descriptor.idProduct));
for(n = 0; usbtmc_id_quirk[n].idVendor > 0; n++) {
- if ((usbtmc_id_quirk[n].idVendor == data->usb_dev->descriptor.idVendor) &&
- (usbtmc_id_quirk[n].idProduct == data->usb_dev->descriptor.idProduct)) {
+ if ((usbtmc_id_quirk[n].idVendor == le16_to_cpu(data->usb_dev->descriptor.idVendor)) &&
+ (usbtmc_id_quirk[n].idProduct == le16_to_cpu(data->usb_dev->descriptor.idProduct))) {
dev_dbg(&intf->dev, "Setting this device as having the RIGOL quirk\n");
data->rigol_quirk = 1;
break;
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index b0585e623ba..23559746be9 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -43,10 +43,11 @@ static const size_t pool_max[HCD_BUFFER_POOLS] = {
*
* Call this as part of initializing a host controller that uses the dma
* memory allocators. It initializes some pools of dma-coherent memory that
- * will be shared by all drivers using that controller, or returns a negative
- * errno value on error.
+ * will be shared by all drivers using that controller.
*
* Call hcd_buffer_destroy() to clean up after using those pools.
+ *
+ * Return: 0 if successful. A negative errno value otherwise.
*/
int hcd_buffer_create(struct usb_hcd *hcd)
{
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 7199adccf44..a6b2cabe793 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -424,7 +424,8 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
if (config->desc.bDescriptorType != USB_DT_CONFIG ||
- config->desc.bLength < USB_DT_CONFIG_SIZE) {
+ config->desc.bLength < USB_DT_CONFIG_SIZE ||
+ config->desc.bLength > size) {
dev_err(ddev, "invalid descriptor for config index %d: "
"type = 0x%X, length = %d\n", cfgidx,
config->desc.bDescriptorType, config->desc.bLength);
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 05986507b58..737e3c19967 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -725,15 +725,15 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
/*
* check for the special corner case 'get_device_id' in the printer
- * class specification, where wIndex is (interface << 8 | altsetting)
- * instead of just interface
+ * class specification, which we always want to allow as it is used
+ * to query things like ink level, etc.
*/
if (requesttype == 0xa1 && request == 0) {
alt_setting = usb_find_alt_setting(ps->dev->actconfig,
index >> 8, index & 0xff);
if (alt_setting
&& alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
- index >>= 8;
+ return 0;
}
index &= 0xff;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 7609ac4aed1..f7841d44fed 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -94,32 +94,27 @@ ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf)
}
EXPORT_SYMBOL_GPL(usb_show_dynids);
-static ssize_t show_dynids(struct device_driver *driver, char *buf)
+static ssize_t new_id_show(struct device_driver *driver, char *buf)
{
struct usb_driver *usb_drv = to_usb_driver(driver);
return usb_show_dynids(&usb_drv->dynids, buf);
}
-static ssize_t store_new_id(struct device_driver *driver,
+static ssize_t new_id_store(struct device_driver *driver,
const char *buf, size_t count)
{
struct usb_driver *usb_drv = to_usb_driver(driver);
return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
}
-static DRIVER_ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id);
+static DRIVER_ATTR_RW(new_id);
-/**
- * store_remove_id - remove a USB device ID from this driver
- * @driver: target device driver
- * @buf: buffer for scanning device ID data
- * @count: input size
- *
- * Removes a dynamic usb device ID from this driver.
+/*
+ * Remove a USB device ID from this driver
*/
-static ssize_t
-store_remove_id(struct device_driver *driver, const char *buf, size_t count)
+static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
+ size_t count)
{
struct usb_dynid *dynid, *n;
struct usb_driver *usb_driver = to_usb_driver(driver);
@@ -144,7 +139,12 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count)
spin_unlock(&usb_driver->dynids.lock);
return count;
}
-static DRIVER_ATTR(remove_id, S_IRUGO | S_IWUSR, show_dynids, store_remove_id);
+
+static ssize_t remove_id_show(struct device_driver *driver, char *buf)
+{
+ return new_id_show(driver, buf);
+}
+static DRIVER_ATTR_RW(remove_id);
static int usb_create_newid_files(struct usb_driver *usb_drv)
{
@@ -457,6 +457,8 @@ static int usb_unbind_interface(struct device *dev)
* Callers must own the device lock, so driver probe() entries don't need
* extra locking, but other call contexts may need to explicitly claim that
* lock.
+ *
+ * Return: 0 on success.
*/
int usb_driver_claim_interface(struct usb_driver *driver,
struct usb_interface *iface, void *priv)
@@ -658,6 +660,8 @@ EXPORT_SYMBOL_GPL(usb_match_one_id);
* These device tables are exported with MODULE_DEVICE_TABLE, through
* modutils, to support the driver loading functionality of USB hotplugging.
*
+ * Return: The first matching usb_device_id, or %NULL.
+ *
* What Matches:
*
* The "match_flags" element in a usb_device_id controls which
@@ -823,7 +827,8 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
* Registers a USB device driver with the USB core. The list of
* unattached devices will be rescanned whenever a new driver is
* added, allowing the new driver to attach to any recognized devices.
- * Returns a negative error code on failure and 0 on success.
+ *
+ * Return: A negative error code on failure and 0 on success.
*/
int usb_register_device_driver(struct usb_device_driver *new_udriver,
struct module *owner)
@@ -879,7 +884,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
* Registers a USB interface driver with the USB core. The list of
* unattached interfaces will be rescanned whenever a new driver is
* added, allowing the new driver to attach to any recognized interfaces.
- * Returns a negative error code on failure and 0 on success.
+ *
+ * Return: A negative error code on failure and 0 on success.
*
* NOTE: if you want your driver to use the USB major number, you must call
* usb_register_dev() to enable that functionality. This function no longer
@@ -1213,6 +1219,8 @@ done:
* unpredictable times.
*
* This routine can run only in process context.
+ *
+ * Return: 0 if the suspend succeeded.
*/
static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
{
@@ -1294,6 +1302,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
* unpredictable times.
*
* This routine can run only in process context.
+ *
+ * Return: 0 on success.
*/
static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
{
@@ -1491,6 +1501,8 @@ void usb_autosuspend_device(struct usb_device *udev)
* The caller must hold @udev's device lock.
*
* This routine can run only in process context.
+ *
+ * Return: 0 on success. A negative error code otherwise.
*/
int usb_autoresume_device(struct usb_device *udev)
{
@@ -1600,6 +1612,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend);
* However if the autoresume fails then the counter is re-decremented.
*
* This routine can run only in process context.
+ *
+ * Return: 0 on success.
*/
int usb_autopm_get_interface(struct usb_interface *intf)
{
@@ -1633,6 +1647,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
* resumed.
*
* This routine can run in atomic context.
+ *
+ * Return: 0 on success. A negative error code otherwise.
*/
int usb_autopm_get_interface_async(struct usb_interface *intf)
{
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 68cc6532e74..39a24021fe4 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
-#include <linux/idr.h>
#include <linux/usb.h>
#include "usb.h"
@@ -33,31 +32,31 @@ struct ep_attribute {
container_of(_attr, struct ep_attribute, attr)
#define usb_ep_attr(field, format_string) \
-static ssize_t show_ep_##field(struct device *dev, \
+static ssize_t field##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct ep_device *ep = to_ep_device(dev); \
return sprintf(buf, format_string, ep->desc->field); \
} \
-static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL);
+static DEVICE_ATTR_RO(field)
-usb_ep_attr(bLength, "%02x\n")
-usb_ep_attr(bEndpointAddress, "%02x\n")
-usb_ep_attr(bmAttributes, "%02x\n")
-usb_ep_attr(bInterval, "%02x\n")
+usb_ep_attr(bLength, "%02x\n");
+usb_ep_attr(bEndpointAddress, "%02x\n");
+usb_ep_attr(bmAttributes, "%02x\n");
+usb_ep_attr(bInterval, "%02x\n");
-static ssize_t show_ep_wMaxPacketSize(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t wMaxPacketSize_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct ep_device *ep = to_ep_device(dev);
return sprintf(buf, "%04x\n",
usb_endpoint_maxp(ep->desc) & 0x07ff);
}
-static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
+static DEVICE_ATTR_RO(wMaxPacketSize);
-static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct ep_device *ep = to_ep_device(dev);
char *type = "unknown";
@@ -78,10 +77,10 @@ static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr,
}
return sprintf(buf, "%s\n", type);
}
-static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL);
+static DEVICE_ATTR_RO(type);
-static ssize_t show_ep_interval(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t interval_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct ep_device *ep = to_ep_device(dev);
char unit;
@@ -124,10 +123,10 @@ static ssize_t show_ep_interval(struct device *dev,
return sprintf(buf, "%d%cs\n", interval, unit);
}
-static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL);
+static DEVICE_ATTR_RO(interval);
-static ssize_t show_ep_direction(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t direction_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct ep_device *ep = to_ep_device(dev);
char *direction;
@@ -140,7 +139,7 @@ static ssize_t show_ep_direction(struct device *dev,
direction = "out";
return sprintf(buf, "%s\n", direction);
}
-static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL);
+static DEVICE_ATTR_RO(direction);
static struct attribute *ep_dev_attrs[] = {
&dev_attr_bLength.attr,
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 6a4c40766f0..7421888087a 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -153,7 +153,7 @@ void usb_major_cleanup(void)
* usb_deregister_dev() must be called when the driver is done with
* the minor numbers given out by this function.
*
- * Returns -EINVAL if something bad happens with trying to register a
+ * Return: -EINVAL if something bad happens with trying to register a
* device, and 0 on success.
*/
int usb_register_dev(struct usb_interface *intf,
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index caeb8d6d39f..b9d3c43e385 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -171,6 +171,8 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
* through the hotplug entry's driver_data.
*
* Store this function in the HCD's struct pci_driver as probe().
+ *
+ * Return: 0 if successful.
*/
int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 014dc996b4f..d6a8d23f047 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -378,9 +378,10 @@ MODULE_PARM_DESC(authorized_default,
* @buf: Buffer for USB string descriptor (header + UTF-16LE)
* @len: Length (in bytes; may be odd) of descriptor buffer.
*
- * The return value is the number of bytes filled in: 2 + 2*strlen(s) or
- * buflen, whichever is less.
+ * Return: The number of bytes filled in: 2 + 2*strlen(s) or @len,
+ * whichever is less.
*
+ * Note:
* USB String descriptors can contain at most 126 characters; input
* strings longer than that are truncated.
*/
@@ -416,7 +417,8 @@ ascii2desc(char const *s, u8 *buf, unsigned len)
*
* Produces either a manufacturer, product or serial number string for the
* virtual root hub device.
- * Returns the number of bytes filled in: the length of the descriptor or
+ *
+ * Return: The number of bytes filled in: the length of the descriptor or
* of the provided buffer, whichever is less.
*/
static unsigned
@@ -464,17 +466,13 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength;
u8 *ubuf = urb->transfer_buffer;
- /*
- * tbuf should be as big as the BOS descriptor and
- * the USB hub descriptor.
- */
- u8 tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
- __attribute__((aligned(4)));
- const u8 *bufp = tbuf;
unsigned len = 0;
int status;
u8 patch_wakeup = 0;
u8 patch_protocol = 0;
+ u16 tbuf_size;
+ u8 *tbuf = NULL;
+ const u8 *bufp;
might_sleep();
@@ -494,6 +492,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
if (wLength > urb->transfer_buffer_length)
goto error;
+ /*
+ * tbuf should be at least as big as the
+ * USB hub descriptor.
+ */
+ tbuf_size = max_t(u16, sizeof(struct usb_hub_descriptor), wLength);
+ tbuf = kzalloc(tbuf_size, GFP_KERNEL);
+ if (!tbuf)
+ return -ENOMEM;
+
+ bufp = tbuf;
+
+
urb->actual_length = 0;
switch (typeReq) {
@@ -691,18 +701,12 @@ error:
bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT;
}
+ kfree(tbuf);
+
/* any errors get returned through the urb completion */
spin_lock_irq(&hcd_root_hub_lock);
usb_hcd_unlink_urb_from_ep(hcd, urb);
-
- /* This peculiar use of spinlocks echoes what real HC drivers do.
- * Avoiding calls to local_irq_disable/enable makes the code
- * RT-friendly.
- */
- spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, status);
- spin_lock(&hcd_root_hub_lock);
-
spin_unlock_irq(&hcd_root_hub_lock);
return 0;
}
@@ -742,9 +746,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
memcpy(urb->transfer_buffer, buffer, length);
usb_hcd_unlink_urb_from_ep(hcd, urb);
- spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, 0);
- spin_lock(&hcd_root_hub_lock);
} else {
length = 0;
set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
@@ -834,10 +836,7 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
usb_hcd_unlink_urb_from_ep(hcd, urb);
-
- spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, status);
- spin_lock(&hcd_root_hub_lock);
}
}
done:
@@ -850,9 +849,8 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
/*
* Show & store the current value of authorized_default
*/
-static ssize_t usb_host_authorized_default_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t authorized_default_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_device *rh_usb_dev = to_usb_device(dev);
struct usb_bus *usb_bus = rh_usb_dev->bus;
@@ -864,9 +862,9 @@ static ssize_t usb_host_authorized_default_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
}
-static ssize_t usb_host_authorized_default_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
+static ssize_t authorized_default_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
{
ssize_t result;
unsigned val;
@@ -886,11 +884,7 @@ static ssize_t usb_host_authorized_default_store(struct device *dev,
result = -EINVAL;
return result;
}
-
-static DEVICE_ATTR(authorized_default, 0644,
- usb_host_authorized_default_show,
- usb_host_authorized_default_store);
-
+static DEVICE_ATTR_RW(authorized_default);
/* Group all the USB bus attributes */
static struct attribute *usb_bus_attrs[] = {
@@ -938,6 +932,8 @@ static void usb_bus_init (struct usb_bus *bus)
*
* Assigns a bus number, and links the controller into usbcore data
* structures so that it can be seen by scanning the bus list.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
*/
static int usb_register_bus(struct usb_bus *bus)
{
@@ -1002,6 +998,8 @@ static void usb_deregister_bus (struct usb_bus *bus)
* the device properly in the device tree and then calls usb_new_device()
* to register the usb device. It also assigns the root hub's USB address
* (always 1).
+ *
+ * Return: 0 if successful. A negative error code otherwise.
*/
static int register_root_hub(struct usb_hcd *hcd)
{
@@ -1108,7 +1106,9 @@ EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume);
* @isoc: true for isochronous transactions, false for interrupt ones
* @bytecount: how many bytes in the transaction.
*
- * Returns approximate bus time in nanoseconds for a periodic transaction.
+ * Return: Approximate bus time in nanoseconds for a periodic transaction.
+ *
+ * Note:
* See USB 2.0 spec section 5.11.3; only periodic transfers need to be
* scheduled in software, this function is only used for such scheduling.
*/
@@ -1166,7 +1166,7 @@ EXPORT_SYMBOL_GPL(usb_calc_bus_time);
* be disabled. The actions carried out here are required for URB
* submission, as well as for endpoint shutdown and for usb_kill_urb.
*
- * Returns 0 for no error, otherwise a negative error code (in which case
+ * Return: 0 for no error, otherwise a negative error code (in which case
* the enqueue() method must fail). If no error occurs but enqueue() fails
* anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
* the private spinlock and returning.
@@ -1221,7 +1221,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
* be disabled. The actions carried out here are required for making
* sure than an unlink is valid.
*
- * Returns 0 for no error, otherwise a negative error code (in which case
+ * Return: 0 for no error, otherwise a negative error code (in which case
* the dequeue() method must fail). The possible error codes are:
*
* -EIDRM: @urb was not submitted or has already completed.
@@ -1648,6 +1648,72 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
/*-------------------------------------------------------------------------*/
+static void __usb_hcd_giveback_urb(struct urb *urb)
+{
+ struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
+ int status = urb->unlinked;
+ unsigned long flags;
+
+ urb->hcpriv = NULL;
+ if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+ urb->actual_length < urb->transfer_buffer_length &&
+ !status))
+ status = -EREMOTEIO;
+
+ unmap_urb_for_dma(hcd, urb);
+ usbmon_urb_complete(&hcd->self, urb, status);
+ usb_unanchor_urb(urb);
+
+ /* pass ownership to the completion handler */
+ urb->status = status;
+
+ /*
+ * We disable local IRQs here avoid possible deadlock because
+ * drivers may call spin_lock() to hold lock which might be
+ * acquired in one hard interrupt handler.
+ *
+ * The local_irq_save()/local_irq_restore() around complete()
+ * will be removed if current USB drivers have been cleaned up
+ * and no one may trigger the above deadlock situation when
+ * running complete() in tasklet.
+ */
+ local_irq_save(flags);
+ urb->complete(urb);
+ local_irq_restore(flags);
+
+ atomic_dec(&urb->use_count);
+ if (unlikely(atomic_read(&urb->reject)))
+ wake_up(&usb_kill_urb_queue);
+ usb_put_urb(urb);
+}
+
+static void usb_giveback_urb_bh(unsigned long param)
+{
+ struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param;
+ struct list_head local_list;
+
+ spin_lock_irq(&bh->lock);
+ bh->running = true;
+ restart:
+ list_replace_init(&bh->head, &local_list);
+ spin_unlock_irq(&bh->lock);
+
+ while (!list_empty(&local_list)) {
+ struct urb *urb;
+
+ urb = list_entry(local_list.next, struct urb, urb_list);
+ list_del_init(&urb->urb_list);
+ __usb_hcd_giveback_urb(urb);
+ }
+
+ /* check if there are new URBs to giveback */
+ spin_lock_irq(&bh->lock);
+ if (!list_empty(&bh->head))
+ goto restart;
+ bh->running = false;
+ spin_unlock_irq(&bh->lock);
+}
+
/**
* usb_hcd_giveback_urb - return URB from HCD to device driver
* @hcd: host controller returning the URB
@@ -1667,25 +1733,37 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
*/
void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
{
- urb->hcpriv = NULL;
- if (unlikely(urb->unlinked))
- status = urb->unlinked;
- else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
- urb->actual_length < urb->transfer_buffer_length &&
- !status))
- status = -EREMOTEIO;
+ struct giveback_urb_bh *bh;
+ bool running, high_prio_bh;
- unmap_urb_for_dma(hcd, urb);
- usbmon_urb_complete(&hcd->self, urb, status);
- usb_unanchor_urb(urb);
+ /* pass status to tasklet via unlinked */
+ if (likely(!urb->unlinked))
+ urb->unlinked = status;
- /* pass ownership to the completion handler */
- urb->status = status;
- urb->complete (urb);
- atomic_dec (&urb->use_count);
- if (unlikely(atomic_read(&urb->reject)))
- wake_up (&usb_kill_urb_queue);
- usb_put_urb (urb);
+ if (!hcd_giveback_urb_in_bh(hcd) && !is_root_hub(urb->dev)) {
+ __usb_hcd_giveback_urb(urb);
+ return;
+ }
+
+ if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) {
+ bh = &hcd->high_prio_bh;
+ high_prio_bh = true;
+ } else {
+ bh = &hcd->low_prio_bh;
+ high_prio_bh = false;
+ }
+
+ spin_lock(&bh->lock);
+ list_add_tail(&urb->urb_list, &bh->head);
+ running = bh->running;
+ spin_unlock(&bh->lock);
+
+ if (running)
+ ;
+ else if (high_prio_bh)
+ tasklet_hi_schedule(&bh->bh);
+ else
+ tasklet_schedule(&bh->bh);
}
EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb);
@@ -1784,7 +1862,7 @@ rescan:
* pass in the current alternate interface setting in cur_alt,
* and pass in the new alternate interface setting in new_alt.
*
- * Returns an error if the requested bandwidth change exceeds the
+ * Return: An error if the requested bandwidth change exceeds the
* bus bandwidth or host controller internal resources.
*/
int usb_hcd_alloc_bandwidth(struct usb_device *udev,
@@ -1954,9 +2032,12 @@ void usb_hcd_reset_endpoint(struct usb_device *udev,
* @num_streams: number of streams to allocate.
* @mem_flags: flags hcd should use to allocate memory.
*
- * Sets up a group of bulk endpoints to have num_streams stream IDs available.
+ * Sets up a group of bulk endpoints to have @num_streams stream IDs available.
* Drivers may queue multiple transfers to different stream IDs, which may
* complete in a different order than they were queued.
+ *
+ * Return: On success, the number of allocated streams. On failure, a negative
+ * error code.
*/
int usb_alloc_streams(struct usb_interface *interface,
struct usb_host_endpoint **eps, unsigned int num_eps,
@@ -2201,6 +2282,8 @@ EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
* khubd identifying and possibly configuring the device.
* This is needed by OTG controller drivers, where it helps meet
* HNP protocol timing requirements for starting a port reset.
+ *
+ * Return: 0 if successful.
*/
int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
{
@@ -2235,6 +2318,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
*
* If the controller isn't HALTed, calls the driver's irq handler.
* Checks whether the controller is now dead.
+ *
+ * Return: %IRQ_HANDLED if the IRQ was handled. %IRQ_NONE otherwise.
*/
irqreturn_t usb_hcd_irq (int irq, void *__hcd)
{
@@ -2307,6 +2392,14 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
/*-------------------------------------------------------------------------*/
+static void init_giveback_urb_bh(struct giveback_urb_bh *bh)
+{
+
+ spin_lock_init(&bh->lock);
+ INIT_LIST_HEAD(&bh->head);
+ tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh);
+}
+
/**
* usb_create_shared_hcd - create and initialize an HCD structure
* @driver: HC driver that will use this hcd
@@ -2320,7 +2413,8 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
* HC driver's private data. Initialize the generic members of the
* hcd structure.
*
- * If memory is unavailable, returns NULL.
+ * Return: On success, a pointer to the created and initialized HCD structure.
+ * On failure (e.g. if memory is unavailable), %NULL.
*/
struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
struct device *dev, const char *bus_name,
@@ -2384,7 +2478,8 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
* HC driver's private data. Initialize the generic members of the
* hcd structure.
*
- * If memory is unavailable, returns NULL.
+ * Return: On success, a pointer to the created and initialized HCD
+ * structure. On failure (e.g. if memory is unavailable), %NULL.
*/
struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
struct device *dev, const char *bus_name)
@@ -2563,7 +2658,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
* should already have been reset (and boot firmware kicked off etc).
*/
if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
- dev_err(hcd->self.controller, "can't setup\n");
+ dev_err(hcd->self.controller, "can't setup: %d\n", retval);
goto err_hcd_driver_setup;
}
hcd->rh_pollable = 1;
@@ -2573,6 +2668,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
&& device_can_wakeup(&hcd->self.root_hub->dev))
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
+ /* initialize tasklets */
+ init_giveback_urb_bh(&hcd->high_prio_bh);
+ init_giveback_urb_bh(&hcd->low_prio_bh);
+
/* enable irqs just before we start the controller,
* if the BIOS provides legacy PCI irqs.
*/
@@ -2681,6 +2780,16 @@ void usb_remove_hcd(struct usb_hcd *hcd)
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
mutex_unlock(&usb_bus_list_lock);
+ /*
+ * tasklet_kill() isn't needed here because:
+ * - driver's disconnect() called from usb_disconnect() should
+ * make sure its URBs are completed during the disconnect()
+ * callback
+ *
+ * - it is too late to run complete() here since driver may have
+ * been removed already now
+ */
+
/* Prevent any more root-hub status calls from the timer.
* The HCD might still restart the timer (if a port status change
* interrupt occurs), but usb_hcd_poll_rh_status() won't invoke
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 4191db32f12..dde4c83516a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -451,7 +451,7 @@ static void led_work (struct work_struct *work)
if (hdev->state != USB_STATE_CONFIGURED || hub->quiescing)
return;
- for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
+ for (i = 0; i < hdev->maxchild; i++) {
unsigned selector, mode;
/* 30%-50% duty cycle */
@@ -500,7 +500,7 @@ static void led_work (struct work_struct *work)
}
if (!changed && blinkenlights) {
cursor++;
- cursor %= hub->descriptor->bNbrPorts;
+ cursor %= hdev->maxchild;
set_port_led(hub, cursor + 1, HUB_LED_GREEN);
hub->indicator[cursor] = INDICATOR_CYCLE;
changed++;
@@ -668,6 +668,15 @@ resubmit:
static inline int
hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
{
+ /* Need to clear both directions for control ep */
+ if (((devinfo >> 11) & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_CONTROL) {
+ int status = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
+ HUB_CLEAR_TT_BUFFER, USB_RT_PORT,
+ devinfo ^ 0x8000, tt, NULL, 0, 1000);
+ if (status)
+ return status;
+ }
return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo,
tt, NULL, 0, 1000);
@@ -725,6 +734,8 @@ static void hub_tt_work(struct work_struct *work)
*
* call this function to control port's power via setting or
* clearing the port's PORT_POWER feature.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
*/
int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
int port1, bool set)
@@ -753,6 +764,8 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
*
* It may not be possible for that hub to handle additional full (or low)
* speed transactions until that state is fully cleared out.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
*/
int usb_hub_clear_tt_buffer(struct urb *urb)
{
@@ -817,7 +830,7 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)
else
dev_dbg(hub->intfdev, "trying to enable port power on "
"non-switchable hub\n");
- for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
+ for (port1 = 1; port1 <= hub->hdev->maxchild; port1++)
if (hub->ports[port1 - 1]->power_is_on)
set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
else
@@ -955,6 +968,8 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
* see that the device has been disconnected. When the device is
* physically unplugged and something is plugged in, the events will
* be received and processed normally.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
*/
int usb_remove_device(struct usb_device *udev)
{
@@ -1455,11 +1470,10 @@ static int hub_configure(struct usb_hub *hub,
* and battery-powered root hubs (may provide just 8 mA).
*/
ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
- if (ret < 2) {
+ if (ret) {
message = "can't get hub status";
goto fail;
}
- le16_to_cpus(&hubstatus);
hcd = bus_to_hcd(hdev->bus);
if (hdev == hdev->bus->root_hub) {
if (hcd->power_budget > 0)
@@ -1548,10 +1562,15 @@ static int hub_configure(struct usb_hub *hub,
if (hub->has_indicators && blinkenlights)
hub->indicator [0] = INDICATOR_CYCLE;
- for (i = 0; i < hdev->maxchild; i++)
- if (usb_hub_create_port_device(hub, i + 1) < 0)
+ for (i = 0; i < hdev->maxchild; i++) {
+ ret = usb_hub_create_port_device(hub, i + 1);
+ if (ret < 0) {
dev_err(hub->intfdev,
"couldn't create port%d device.\n", i + 1);
+ hdev->maxchild = i;
+ goto fail_keep_maxchild;
+ }
+ }
usb_hub_adjust_deviceremovable(hdev, hub->descriptor);
@@ -1559,6 +1578,8 @@ static int hub_configure(struct usb_hub *hub,
return 0;
fail:
+ hdev->maxchild = 0;
+fail_keep_maxchild:
dev_err (hub_dev, "config failed, %s (err %d)\n",
message, ret);
/* hub_disconnect() frees urb and descriptor */
@@ -2107,6 +2128,8 @@ static inline void announce_device(struct usb_device *udev) { }
* @udev: newly addressed device (in ADDRESS state)
*
* Finish enumeration for On-The-Go devices
+ *
+ * Return: 0 if successful. A negative error code otherwise.
*/
static int usb_enumerate_device_otg(struct usb_device *udev)
{
@@ -2189,6 +2212,8 @@ fail:
* If the device is WUSB and not authorized, we don't attempt to read
* the string descriptors, as they will be errored out by the device
* until it has been authorized.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
*/
static int usb_enumerate_device(struct usb_device *udev)
{
@@ -2269,13 +2294,14 @@ static void set_usb_port_removable(struct usb_device *udev)
* udev has already been installed, but udev is not yet visible through
* sysfs or other filesystem code.
*
- * It will return if the device is configured properly or not. Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver or root-hub registrar should ever call this.
+ *
+ * Return: Whether the device is configured properly or not. Zero if the
+ * interface was registered with the driver core; else a negative errno
+ * value.
+ *
*/
int usb_new_device(struct usb_device *udev)
{
@@ -2383,6 +2409,8 @@ fail:
*
* We share a lock (that we have) with device_del(), so we need to
* defer its call.
+ *
+ * Return: 0.
*/
int usb_deauthorize_device(struct usb_device *usb_dev)
{
@@ -2829,25 +2857,65 @@ void usb_enable_ltm(struct usb_device *udev)
}
EXPORT_SYMBOL_GPL(usb_enable_ltm);
-#ifdef CONFIG_PM
/*
- * usb_disable_function_remotewakeup - disable usb3.0
- * device's function remote wakeup
+ * usb_enable_remote_wakeup - enable remote wakeup for a device
* @udev: target device
*
- * Assume there's only one function on the USB 3.0
- * device and disable remote wake for the first
- * interface. FIXME if the interface association
- * descriptor shows there's more than one function.
+ * For USB-2 devices: Set the device's remote wakeup feature.
+ *
+ * For USB-3 devices: Assume there's only one function on the device and
+ * enable remote wake for the first interface. FIXME if the interface
+ * association descriptor shows there's more than one function.
*/
-static int usb_disable_function_remotewakeup(struct usb_device *udev)
+static int usb_enable_remote_wakeup(struct usb_device *udev)
{
- return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ if (udev->speed < USB_SPEED_SUPER)
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ else
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE,
+ USB_INTRF_FUNC_SUSPEND,
+ USB_INTRF_FUNC_SUSPEND_RW |
+ USB_INTRF_FUNC_SUSPEND_LP,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * usb_disable_remote_wakeup - disable remote wakeup for a device
+ * @udev: target device
+ *
+ * For USB-2 devices: Clear the device's remote wakeup feature.
+ *
+ * For USB-3 devices: Assume there's only one function on the device and
+ * disable remote wake for the first interface. FIXME if the interface
+ * association descriptor shows there's more than one function.
+ */
+static int usb_disable_remote_wakeup(struct usb_device *udev)
+{
+ if (udev->speed < USB_SPEED_SUPER)
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ else
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_INTERFACE,
USB_INTRF_FUNC_SUSPEND, 0, NULL, 0,
USB_CTRL_SET_TIMEOUT);
}
+/* Count of wakeup-enabled devices at or below udev */
+static unsigned wakeup_enabled_descendants(struct usb_device *udev)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev);
+
+ return udev->do_remote_wakeup +
+ (hub ? hub->wakeup_enabled_descendants : 0);
+}
+
/*
* usb_port_suspend - suspend a usb device's upstream port
* @udev: device that's no longer in active use, not a root hub
@@ -2888,8 +2956,8 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
* Linux (2.6) currently has NO mechanisms to initiate that: no khubd
* timer, no SRP, no requests through sysfs.
*
- * If Runtime PM isn't enabled or used, non-SuperSpeed devices really get
- * suspended only when their bus goes into global suspend (i.e., the root
+ * If Runtime PM isn't enabled or used, non-SuperSpeed devices may not get
+ * suspended until their bus goes into global suspend (i.e., the root
* hub is suspended). Nevertheless, we change @udev->state to
* USB_STATE_SUSPENDED as this is the device's "logical" state. The actual
* upstream port setting is stored in @udev->port_is_suspended.
@@ -2900,7 +2968,6 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
{
struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
struct usb_port *port_dev = hub->ports[udev->portnum - 1];
- enum pm_qos_flags_status pm_qos_stat;
int port1 = udev->portnum;
int status;
bool really_suspend = true;
@@ -2912,33 +2979,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
* we don't explicitly enable it here.
*/
if (udev->do_remote_wakeup) {
- if (!hub_is_superspeed(hub->hdev)) {
- status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
- USB_DEVICE_REMOTE_WAKEUP, 0,
- NULL, 0,
- USB_CTRL_SET_TIMEOUT);
- } else {
- /* Assume there's only one function on the USB 3.0
- * device and enable remote wake for the first
- * interface. FIXME if the interface association
- * descriptor shows there's more than one function.
- */
- status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- USB_REQ_SET_FEATURE,
- USB_RECIP_INTERFACE,
- USB_INTRF_FUNC_SUSPEND,
- USB_INTRF_FUNC_SUSPEND_RW |
- USB_INTRF_FUNC_SUSPEND_LP,
- NULL, 0,
- USB_CTRL_SET_TIMEOUT);
- }
+ status = usb_enable_remote_wakeup(udev);
if (status) {
dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
status);
/* bail if autosuspend is requested */
if (PMSG_IS_AUTO(msg))
- return status;
+ goto err_wakeup;
}
}
@@ -2947,28 +2994,36 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
usb_set_usb2_hardware_lpm(udev, 0);
if (usb_disable_ltm(udev)) {
- dev_err(&udev->dev, "%s Failed to disable LTM before suspend\n.",
- __func__);
- return -ENOMEM;
+ dev_err(&udev->dev, "Failed to disable LTM before suspend\n.");
+ status = -ENOMEM;
+ if (PMSG_IS_AUTO(msg))
+ goto err_ltm;
}
if (usb_unlocked_disable_lpm(udev)) {
- dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.",
- __func__);
- return -ENOMEM;
+ dev_err(&udev->dev, "Failed to disable LPM before suspend\n.");
+ status = -ENOMEM;
+ if (PMSG_IS_AUTO(msg))
+ goto err_lpm3;
}
/* see 7.1.7.6 */
if (hub_is_superspeed(hub->hdev))
status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
- else if (PMSG_IS_AUTO(msg))
- status = set_port_feature(hub->hdev, port1,
- USB_PORT_FEAT_SUSPEND);
+
/*
* For system suspend, we do not need to enable the suspend feature
* on individual USB-2 ports. The devices will automatically go
* into suspend a few ms after the root hub stops sending packets.
* The USB 2.0 spec calls this "global suspend".
+ *
+ * However, many USB hubs have a bug: They don't relay wakeup requests
+ * from a downstream port if the port's suspend feature isn't on.
+ * Therefore we will turn on the suspend feature if udev or any of its
+ * descendants is enabled for remote wakeup.
*/
+ else if (PMSG_IS_AUTO(msg) || wakeup_enabled_descendants(udev) > 0)
+ status = set_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_SUSPEND);
else {
really_suspend = false;
status = 0;
@@ -2976,54 +3031,37 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
if (status) {
dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
port1, status);
- /* paranoia: "should not happen" */
- if (udev->do_remote_wakeup) {
- if (!hub_is_superspeed(hub->hdev)) {
- (void) usb_control_msg(udev,
- usb_sndctrlpipe(udev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_RECIP_DEVICE,
- USB_DEVICE_REMOTE_WAKEUP, 0,
- NULL, 0,
- USB_CTRL_SET_TIMEOUT);
- } else
- (void) usb_disable_function_remotewakeup(udev);
-
- }
+ /* Try to enable USB3 LPM and LTM again */
+ usb_unlocked_enable_lpm(udev);
+ err_lpm3:
+ usb_enable_ltm(udev);
+ err_ltm:
/* Try to enable USB2 hardware LPM again */
if (udev->usb2_hw_lpm_capable == 1)
usb_set_usb2_hardware_lpm(udev, 1);
- /* Try to enable USB3 LTM and LPM again */
- usb_enable_ltm(udev);
- usb_unlocked_enable_lpm(udev);
+ if (udev->do_remote_wakeup)
+ (void) usb_disable_remote_wakeup(udev);
+ err_wakeup:
/* System sleep transitions should never fail */
if (!PMSG_IS_AUTO(msg))
status = 0;
} else {
- /* device has up to 10 msec to fully suspend */
dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
(PMSG_IS_AUTO(msg) ? "auto-" : ""),
udev->do_remote_wakeup);
- usb_set_device_state(udev, USB_STATE_SUSPENDED);
if (really_suspend) {
udev->port_is_suspended = 1;
+
+ /* device has up to 10 msec to fully suspend */
msleep(10);
}
+ usb_set_device_state(udev, USB_STATE_SUSPENDED);
}
- /*
- * Check whether current status meets the requirement of
- * usb port power off mechanism
- */
- pm_qos_stat = dev_pm_qos_flags(&port_dev->dev,
- PM_QOS_FLAG_NO_POWER_OFF);
- if (!udev->do_remote_wakeup
- && pm_qos_stat != PM_QOS_FLAGS_ALL
- && udev->persist_enabled
- && !status) {
+ if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) {
pm_runtime_put_sync(&port_dev->dev);
port_dev->did_runtime_put = true;
}
@@ -3077,8 +3115,6 @@ static int finish_port_resume(struct usb_device *udev)
if (status == 0) {
devstatus = 0;
status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
- if (status >= 0)
- status = (status > 0 ? 0 : -ENODEV);
/* If a normal resume failed, try doing a reset-resume */
if (status && !udev->reset_resume && udev->persist_enabled) {
@@ -3098,24 +3134,15 @@ static int finish_port_resume(struct usb_device *udev)
* udev->reset_resume
*/
} else if (udev->actconfig && !udev->reset_resume) {
- if (!hub_is_superspeed(udev->parent)) {
- le16_to_cpus(&devstatus);
+ if (udev->speed < USB_SPEED_SUPER) {
if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
- status = usb_control_msg(udev,
- usb_sndctrlpipe(udev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_RECIP_DEVICE,
- USB_DEVICE_REMOTE_WAKEUP, 0,
- NULL, 0,
- USB_CTRL_SET_TIMEOUT);
+ status = usb_disable_remote_wakeup(udev);
} else {
status = usb_get_status(udev, USB_RECIP_INTERFACE, 0,
&devstatus);
- le16_to_cpus(&devstatus);
if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP
| USB_INTRF_STAT_FUNC_RW))
- status =
- usb_disable_function_remotewakeup(udev);
+ status = usb_disable_remote_wakeup(udev);
}
if (status)
@@ -3249,8 +3276,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return status;
}
-#endif /* CONFIG_PM */
-
#ifdef CONFIG_PM_RUNTIME
/* caller has locked udev */
@@ -3293,7 +3318,11 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
unsigned port1;
int status;
- /* Warn if children aren't already suspended */
+ /*
+ * Warn if children aren't already suspended.
+ * Also, add up the number of wakeup-enabled descendants.
+ */
+ hub->wakeup_enabled_descendants = 0;
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
struct usb_device *udev;
@@ -3303,6 +3332,9 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
if (PMSG_IS_AUTO(msg))
return -EBUSY;
}
+ if (udev)
+ hub->wakeup_enabled_descendants +=
+ wakeup_enabled_descendants(udev);
}
if (hdev->do_remote_wakeup && hub->quirk_check_port_auto_suspend) {
@@ -3811,7 +3843,8 @@ EXPORT_SYMBOL_GPL(usb_disable_ltm);
void usb_enable_ltm(struct usb_device *udev) { }
EXPORT_SYMBOL_GPL(usb_enable_ltm);
-#endif
+
+#endif /* CONFIG_PM */
/* USB 2.0 spec, 7.1.7.3 / fig 7-29:
@@ -4451,11 +4484,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
&devstat);
- if (status < 2) {
+ if (status) {
dev_dbg(&udev->dev, "get status %d ?\n", status);
goto loop_disable;
}
- le16_to_cpus(&devstat);
if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
dev_err(&udev->dev,
"can't connect bus-powered hub "
@@ -4616,9 +4648,7 @@ static void hub_events(void)
hub_dev = hub->intfdev;
intf = to_usb_interface(hub_dev);
dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
- hdev->state, hub->descriptor
- ? hub->descriptor->bNbrPorts
- : 0,
+ hdev->state, hdev->maxchild,
/* NOTE: expects max 15 ports... */
(u16) hub->change_bits[0],
(u16) hub->event_bits[0]);
@@ -4663,7 +4693,7 @@ static void hub_events(void)
}
/* deal with port status changes */
- for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
+ for (i = 1; i <= hdev->maxchild; i++) {
if (test_bit(i, hub->busy_bits))
continue;
connect_change = test_bit(i, hub->change_bits);
@@ -4766,7 +4796,8 @@ static void hub_events(void)
hub->ports[i - 1]->child;
dev_dbg(hub_dev, "warm reset port %d\n", i);
- if (!udev) {
+ if (!udev || !(portstatus &
+ USB_PORT_STAT_CONNECTION)) {
status = hub_port_reset(hub, i,
NULL, HUB_BH_RESET_TIME,
true);
@@ -4776,8 +4807,8 @@ static void hub_events(void)
usb_lock_device(udev);
status = usb_reset_device(udev);
usb_unlock_device(udev);
+ connect_change = 0;
}
- connect_change = 0;
}
if (connect_change)
@@ -4913,7 +4944,8 @@ void usb_hub_cleanup(void)
} /* usb_hub_cleanup() */
static int descriptors_changed(struct usb_device *udev,
- struct usb_device_descriptor *old_device_descriptor)
+ struct usb_device_descriptor *old_device_descriptor,
+ struct usb_host_bos *old_bos)
{
int changed = 0;
unsigned index;
@@ -4927,6 +4959,16 @@ static int descriptors_changed(struct usb_device *udev,
sizeof(*old_device_descriptor)) != 0)
return 1;
+ if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
+ return 1;
+ if (udev->bos) {
+ len = le16_to_cpu(udev->bos->desc->wTotalLength);
+ if (len != le16_to_cpu(old_bos->desc->wTotalLength))
+ return 1;
+ if (memcmp(udev->bos->desc, old_bos->desc, len))
+ return 1;
+ }
+
/* Since the idVendor, idProduct, and bcdDevice values in the
* device descriptor haven't changed, we will assume the
* Manufacturer and Product strings haven't changed either.
@@ -5002,10 +5044,11 @@ static int descriptors_changed(struct usb_device *udev,
* re-connected. All drivers will be unbound, and the device will be
* re-enumerated and probed all over again.
*
- * Returns 0 if the reset succeeded, -ENODEV if the device has been
+ * Return: 0 if the reset succeeded, -ENODEV if the device has been
* flagged for logical disconnection, or some other negative error code
* if the reset wasn't even attempted.
*
+ * Note:
* The caller must own the device lock. For example, it's safe to use
* this from a driver probe() routine after downloading new firmware.
* For calls that might not occur during probe(), drivers should lock
@@ -5022,6 +5065,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
struct usb_hub *parent_hub;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
struct usb_device_descriptor descriptor = udev->descriptor;
+ struct usb_host_bos *bos;
int i, ret = 0;
int port1 = udev->portnum;
@@ -5039,6 +5083,9 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
}
parent_hub = usb_hub_to_struct_hub(parent_hdev);
+ bos = udev->bos;
+ udev->bos = NULL;
+
/* Disable LPM and LTM while we reset the device and reinstall the alt
* settings. Device-initiated LPM settings, and system exit latency
* settings are cleared when the device is reset, so we have to set
@@ -5072,7 +5119,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
goto re_enumerate;
/* Device might have changed firmware (DFU or similar) */
- if (descriptors_changed(udev, &descriptor)) {
+ if (descriptors_changed(udev, &descriptor, bos)) {
dev_info(&udev->dev, "device firmware changed\n");
udev->descriptor = descriptor; /* for disconnect() calls */
goto re_enumerate;
@@ -5145,11 +5192,15 @@ done:
/* Now that the alt settings are re-installed, enable LTM and LPM. */
usb_unlocked_enable_lpm(udev);
usb_enable_ltm(udev);
+ usb_release_bos_descriptor(udev);
+ udev->bos = bos;
return 0;
re_enumerate:
/* LPM state doesn't matter when we're about to destroy the device. */
hub_port_logical_disconnect(parent_hub, port1);
+ usb_release_bos_descriptor(udev);
+ udev->bos = bos;
return -ENODEV;
}
@@ -5161,8 +5212,9 @@ re_enumerate:
* method), performs the port reset, and then lets the drivers know that
* the reset is over (using their post_reset method).
*
- * Return value is the same as for usb_reset_and_verify_device().
+ * Return: The same as for usb_reset_and_verify_device().
*
+ * Note:
* The caller must own the device lock. For example, it's safe to use
* this from a driver probe() routine after downloading new firmware.
* For calls that might not occur during probe(), drivers should lock
@@ -5300,7 +5352,7 @@ EXPORT_SYMBOL_GPL(usb_queue_reset_device);
* USB drivers call this function to get hub's child device
* pointer.
*
- * Return NULL if input param is invalid and
+ * Return: %NULL if input param is invalid and
* child's usb_device pointer if non-NULL.
*/
struct usb_device *usb_hub_find_child(struct usb_device *hdev,
@@ -5334,8 +5386,8 @@ void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
* @hdev: USB device belonging to the usb hub
* @port1: port num of the port
*
- * Return connect type of the port and if input params are
- * invalid, return USB_PORT_CONNECT_TYPE_UNKNOWN.
+ * Return: The connect type of the port if successful. Or
+ * USB_PORT_CONNECT_TYPE_UNKNOWN if input params are invalid.
*/
enum usb_port_connect_type
usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
@@ -5395,8 +5447,8 @@ void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
* @hdev: USB device belonging to the usb hub
* @port1: port num of the port
*
- * Return port's acpi handle if successful, NULL if params are
- * invaild.
+ * Return: Port's acpi handle if successful, %NULL if params are
+ * invalid.
*/
acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
int port1)
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 6508e02b3da..4e4790dea34 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -59,6 +59,9 @@ struct usb_hub {
struct usb_tt tt; /* Transaction Translator */
unsigned mA_per_port; /* current for each child */
+#ifdef CONFIG_PM
+ unsigned wakeup_enabled_descendants;
+#endif
unsigned limited_power:1;
unsigned quiescing:1;
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index e7ee1e45166..82927e1ed27 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -119,15 +119,15 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
* This function sends a simple control message to a specified endpoint and
* waits for the message to complete, or timeout.
*
- * If successful, it returns the number of bytes transferred, otherwise a
- * negative error number.
- *
* Don't use this function from within an interrupt context, like a bottom half
* handler. If you need an asynchronous message, or need to send a message
* from within interrupt context, use usb_submit_urb().
* If a thread in your driver uses this call, make sure your disconnect()
* method can wait for it to complete. Since you don't have a handle on the
* URB used, you can't cancel the request.
+ *
+ * Return: If successful, the number of bytes transferred. Otherwise, a negative
+ * error number.
*/
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
__u8 requesttype, __u16 value, __u16 index, void *data,
@@ -170,15 +170,16 @@ EXPORT_SYMBOL_GPL(usb_control_msg);
* This function sends a simple interrupt message to a specified endpoint and
* waits for the message to complete, or timeout.
*
- * If successful, it returns 0, otherwise a negative error number. The number
- * of actual bytes transferred will be stored in the actual_length paramater.
- *
* Don't use this function from within an interrupt context, like a bottom half
* handler. If you need an asynchronous message, or need to send a message
* from within interrupt context, use usb_submit_urb() If a thread in your
* driver uses this call, make sure your disconnect() method can wait for it to
* complete. Since you don't have a handle on the URB used, you can't cancel
* the request.
+ *
+ * Return:
+ * If successful, 0. Otherwise a negative error number. The number of actual
+ * bytes transferred will be stored in the @actual_length paramater.
*/
int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
@@ -203,9 +204,6 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg);
* This function sends a simple bulk message to a specified endpoint
* and waits for the message to complete, or timeout.
*
- * If successful, it returns 0, otherwise a negative error number. The number
- * of actual bytes transferred will be stored in the actual_length paramater.
- *
* Don't use this function from within an interrupt context, like a bottom half
* handler. If you need an asynchronous message, or need to send a message
* from within interrupt context, use usb_submit_urb() If a thread in your
@@ -217,6 +215,11 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg);
* users are forced to abuse this routine by using it to submit URBs for
* interrupt endpoints. We will take the liberty of creating an interrupt URB
* (with the default interval) if the target is an interrupt endpoint.
+ *
+ * Return:
+ * If successful, 0. Otherwise a negative error number. The number of actual
+ * bytes transferred will be stored in the @actual_length paramater.
+ *
*/
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
@@ -341,9 +344,9 @@ static void sg_complete(struct urb *urb)
* send every byte identified in the list.
* @mem_flags: SLAB_* flags affecting memory allocations in this call
*
- * Returns zero for success, else a negative errno value. This initializes a
- * scatter/gather request, allocating resources such as I/O mappings and urb
- * memory (except maybe memory used by USB controller drivers).
+ * This initializes a scatter/gather request, allocating resources such as
+ * I/O mappings and urb memory (except maybe memory used by USB controller
+ * drivers).
*
* The request must be issued using usb_sg_wait(), which waits for the I/O to
* complete (or to be canceled) and then cleans up all resources allocated by
@@ -351,6 +354,8 @@ static void sg_complete(struct urb *urb)
*
* The request may be canceled with usb_sg_cancel(), either before or after
* usb_sg_wait() is called.
+ *
+ * Return: Zero for success, else a negative errno value.
*/
int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
unsigned pipe, unsigned period, struct scatterlist *sg,
@@ -623,7 +628,7 @@ EXPORT_SYMBOL_GPL(usb_sg_cancel);
*
* This call is synchronous, and may not be used in an interrupt context.
*
- * Returns the number of bytes received on success, or else the status code
+ * Return: The number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
int usb_get_descriptor(struct usb_device *dev, unsigned char type,
@@ -671,7 +676,7 @@ EXPORT_SYMBOL_GPL(usb_get_descriptor);
*
* This call is synchronous, and may not be used in an interrupt context.
*
- * Returns the number of bytes received on success, or else the status code
+ * Return: The number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
static int usb_get_string(struct usb_device *dev, unsigned short langid,
@@ -805,7 +810,7 @@ static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
*
* This call is synchronous, and may not be used in an interrupt context.
*
- * Returns length of the string (>= 0) or usb_control_msg status (< 0).
+ * Return: length of the string (>= 0) or usb_control_msg status (< 0).
*/
int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
{
@@ -853,8 +858,8 @@ EXPORT_SYMBOL_GPL(usb_string);
* @udev: the device whose string descriptor is being read
* @index: the descriptor index
*
- * Returns a pointer to a kmalloc'ed buffer containing the descriptor string,
- * or NULL if the index is 0 or the string could not be read.
+ * Return: A pointer to a kmalloc'ed buffer containing the descriptor string,
+ * or %NULL if the index is 0 or the string could not be read.
*/
char *usb_cache_string(struct usb_device *udev, int index)
{
@@ -894,7 +899,7 @@ char *usb_cache_string(struct usb_device *udev, int index)
*
* This call is synchronous, and may not be used in an interrupt context.
*
- * Returns the number of bytes received on success, or else the status code
+ * Return: The number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
@@ -934,13 +939,13 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
*
* This call is synchronous, and may not be used in an interrupt context.
*
- * Returns the number of bytes received on success, or else the status code
- * returned by the underlying usb_control_msg() call.
+ * Returns 0 and the status value in *@data (in host byte order) on success,
+ * or else the status code from the underlying usb_control_msg() call.
*/
int usb_get_status(struct usb_device *dev, int type, int target, void *data)
{
int ret;
- u16 *status = kmalloc(sizeof(*status), GFP_KERNEL);
+ __le16 *status = kmalloc(sizeof(*status), GFP_KERNEL);
if (!status)
return -ENOMEM;
@@ -949,7 +954,12 @@ int usb_get_status(struct usb_device *dev, int type, int target, void *data)
USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status,
sizeof(*status), USB_CTRL_GET_TIMEOUT);
- *(u16 *)data = *status;
+ if (ret == 2) {
+ *(u16 *) data = le16_to_cpu(*status);
+ ret = 0;
+ } else if (ret >= 0) {
+ ret = -EIO;
+ }
kfree(status);
return ret;
}
@@ -975,7 +985,7 @@ EXPORT_SYMBOL_GPL(usb_get_status);
*
* This call is synchronous, and may not be used in an interrupt context.
*
- * Returns zero on success, or else the status code returned by the
+ * Return: Zero on success, or else the status code returned by the
* underlying usb_control_msg() call.
*/
int usb_clear_halt(struct usb_device *dev, int pipe)
@@ -1272,7 +1282,7 @@ void usb_enable_interface(struct usb_device *dev,
* endpoints in that interface; all such urbs must first be completed
* (perhaps forced by unlinking).
*
- * Returns zero on success, or else the status code returned by the
+ * Return: Zero on success, or else the status code returned by the
* underlying usb_control_msg() call.
*/
int usb_set_interface(struct usb_device *dev, int interface, int alternate)
@@ -1426,7 +1436,7 @@ EXPORT_SYMBOL_GPL(usb_set_interface);
*
* The caller must own the device lock.
*
- * Returns zero on success, else a negative error code.
+ * Return: Zero on success, else a negative error code.
*/
int usb_reset_configuration(struct usb_device *dev)
{
@@ -1968,7 +1978,7 @@ static void cancel_async_set_config(struct usb_device *udev)
* routine gets around the normal restrictions by using a work thread to
* submit the change-config request.
*
- * Returns 0 if the request was successfully queued, error code otherwise.
+ * Return: 0 if the request was successfully queued, error code otherwise.
* The caller has no way to know whether the queued request will eventually
* succeed.
*/
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index d6b0fadf53e..51542f85239 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -23,8 +23,8 @@
static const struct attribute_group *port_dev_group[];
-static ssize_t show_port_connect_type(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t connect_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_port *port_dev = to_usb_port(dev);
char *result;
@@ -46,8 +46,7 @@ static ssize_t show_port_connect_type(struct device *dev,
return sprintf(buf, "%s\n", result);
}
-static DEVICE_ATTR(connect_type, S_IRUGO, show_port_connect_type,
- NULL);
+static DEVICE_ATTR_RO(connect_type);
static struct attribute *port_dev_attrs[] = {
&dev_attr_connect_type.attr,
@@ -89,22 +88,19 @@ static int usb_port_runtime_resume(struct device *dev)
retval = usb_hub_set_port_power(hdev, hub, port1, true);
if (port_dev->child && !retval) {
/*
- * Wait for usb hub port to be reconnected in order to make
- * the resume procedure successful.
+ * Attempt to wait for usb hub port to be reconnected in order
+ * to make the resume procedure successful. The device may have
+ * disconnected while the port was powered off, so ignore the
+ * return status.
*/
retval = hub_port_debounce_be_connected(hub, port1);
- if (retval < 0) {
+ if (retval < 0)
dev_dbg(&port_dev->dev, "can't get reconnection after setting port power on, status %d\n",
retval);
- goto out;
- }
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
-
- /* Set return value to 0 if debounce successful */
retval = 0;
}
-out:
clear_bit(port1, hub->busy_bits);
usb_autopm_put_interface(intf);
return retval;
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index a6359889507..5b44cd47da5 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -78,6 +78,12 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x04d8, 0x000c), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
+ /* CarrolTouch 4000U */
+ { USB_DEVICE(0x04e7, 0x0009), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* CarrolTouch 4500U */
+ { USB_DEVICE(0x04e7, 0x0030), .driver_info = USB_QUIRK_RESET_RESUME },
+
/* Samsung Android phone modem - ID conflict with SPH-I500 */
{ USB_DEVICE(0x04e8, 0x6601), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d9284b998bd..6d2c8edb1ff 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -18,8 +18,8 @@
/* Active configuration fields */
#define usb_actconfig_show(field, format_string) \
-static ssize_t show_##field(struct device *dev, \
- struct device_attribute *attr, char *buf) \
+static ssize_t field##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
{ \
struct usb_device *udev; \
struct usb_host_config *actconfig; \
@@ -35,12 +35,12 @@ static ssize_t show_##field(struct device *dev, \
#define usb_actconfig_attr(field, format_string) \
usb_actconfig_show(field, format_string) \
- static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+ static DEVICE_ATTR_RO(field)
-usb_actconfig_attr(bNumInterfaces, "%2d\n")
-usb_actconfig_attr(bmAttributes, "%2x\n")
+usb_actconfig_attr(bNumInterfaces, "%2d\n");
+usb_actconfig_attr(bmAttributes, "%2x\n");
-static ssize_t show_bMaxPower(struct device *dev,
+static ssize_t bMaxPower_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
@@ -52,9 +52,9 @@ static ssize_t show_bMaxPower(struct device *dev,
return 0;
return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
}
-static DEVICE_ATTR(bMaxPower, S_IRUGO, show_bMaxPower, NULL);
+static DEVICE_ATTR_RO(bMaxPower);
-static ssize_t show_configuration_string(struct device *dev,
+static ssize_t configuration_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
@@ -66,14 +66,14 @@ static ssize_t show_configuration_string(struct device *dev,
return 0;
return sprintf(buf, "%s\n", actconfig->string);
}
-static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
+static DEVICE_ATTR_RO(configuration);
/* configuration value is always present, and r/w */
usb_actconfig_show(bConfigurationValue, "%u\n");
-static ssize_t
-set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t bConfigurationValue_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int config, value;
@@ -85,13 +85,12 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
usb_unlock_device(udev);
return (value < 0) ? value : count;
}
-
static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR,
- show_bConfigurationValue, set_bConfigurationValue);
+ bConfigurationValue_show, bConfigurationValue_store);
/* String fields */
#define usb_string_attr(name) \
-static ssize_t show_##name(struct device *dev, \
+static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_device *udev; \
@@ -103,14 +102,14 @@ static ssize_t show_##name(struct device *dev, \
usb_unlock_device(udev); \
return retval; \
} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+static DEVICE_ATTR_RO(name)
usb_string_attr(product);
usb_string_attr(manufacturer);
usb_string_attr(serial);
-static ssize_t
-show_speed(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev;
char *speed;
@@ -139,40 +138,40 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf)
}
return sprintf(buf, "%s\n", speed);
}
-static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
+static DEVICE_ATTR_RO(speed);
-static ssize_t
-show_busnum(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t busnum_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->bus->busnum);
}
-static DEVICE_ATTR(busnum, S_IRUGO, show_busnum, NULL);
+static DEVICE_ATTR_RO(busnum);
-static ssize_t
-show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t devnum_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->devnum);
}
-static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
+static DEVICE_ATTR_RO(devnum);
-static ssize_t
-show_devpath(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t devpath_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "%s\n", udev->devpath);
}
-static DEVICE_ATTR(devpath, S_IRUGO, show_devpath, NULL);
+static DEVICE_ATTR_RO(devpath);
-static ssize_t
-show_version(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev;
u16 bcdUSB;
@@ -181,30 +180,30 @@ show_version(struct device *dev, struct device_attribute *attr, char *buf)
bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB);
return sprintf(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff);
}
-static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+static DEVICE_ATTR_RO(version);
-static ssize_t
-show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t maxchild_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->maxchild);
}
-static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
+static DEVICE_ATTR_RO(maxchild);
-static ssize_t
-show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t quirks_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "0x%x\n", udev->quirks);
}
-static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
+static DEVICE_ATTR_RO(quirks);
-static ssize_t
-show_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t avoid_reset_quirk_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
@@ -212,9 +211,9 @@ show_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char *
return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET));
}
-static ssize_t
-set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t avoid_reset_quirk_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int val;
@@ -229,22 +228,20 @@ set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr,
usb_unlock_device(udev);
return count;
}
+static DEVICE_ATTR_RW(avoid_reset_quirk);
-static DEVICE_ATTR(avoid_reset_quirk, S_IRUGO | S_IWUSR,
- show_avoid_reset_quirk, set_avoid_reset_quirk);
-
-static ssize_t
-show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
}
-static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+static DEVICE_ATTR_RO(urbnum);
-static ssize_t
-show_removable(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev;
char *state;
@@ -264,30 +261,29 @@ show_removable(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s\n", state);
}
-static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL);
+static DEVICE_ATTR_RO(removable);
-static ssize_t
-show_ltm_capable(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t ltm_capable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
if (usb_device_supports_ltm(to_usb_device(dev)))
return sprintf(buf, "%s\n", "yes");
return sprintf(buf, "%s\n", "no");
}
-static DEVICE_ATTR(ltm_capable, S_IRUGO, show_ltm_capable, NULL);
+static DEVICE_ATTR_RO(ltm_capable);
#ifdef CONFIG_PM
-static ssize_t
-show_persist(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t persist_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->persist_enabled);
}
-static ssize_t
-set_persist(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int value;
@@ -304,8 +300,7 @@ set_persist(struct device *dev, struct device_attribute *attr,
usb_unlock_device(udev);
return count;
}
-
-static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_persist);
+static DEVICE_ATTR_RW(persist);
static int add_persist_attributes(struct device *dev)
{
@@ -340,17 +335,15 @@ static void remove_persist_attributes(struct device *dev)
#ifdef CONFIG_PM_RUNTIME
-static ssize_t
-show_connected_duration(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t connected_duration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_device *udev = to_usb_device(dev);
return sprintf(buf, "%u\n",
jiffies_to_msecs(jiffies - udev->connect_time));
}
-
-static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL);
+static DEVICE_ATTR_RO(connected_duration);
/*
* If the device is resumed, the last time the device was suspended has
@@ -359,9 +352,8 @@ static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL);
*
* If the device is suspended, the active_duration is up-to-date.
*/
-static ssize_t
-show_active_duration(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t active_duration_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_device *udev = to_usb_device(dev);
int duration;
@@ -372,18 +364,17 @@ show_active_duration(struct device *dev, struct device_attribute *attr,
duration = jiffies_to_msecs(udev->active_duration);
return sprintf(buf, "%u\n", duration);
}
+static DEVICE_ATTR_RO(active_duration);
-static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL);
-
-static ssize_t
-show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t autosuspend_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000);
}
-static ssize_t
-set_autosuspend(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t autosuspend_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
int value;
@@ -394,9 +385,7 @@ set_autosuspend(struct device *dev, struct device_attribute *attr,
pm_runtime_set_autosuspend_delay(dev, value * 1000);
return count;
}
-
-static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
- show_autosuspend, set_autosuspend);
+static DEVICE_ATTR_RW(autosuspend);
static const char on_string[] = "on";
static const char auto_string[] = "auto";
@@ -411,8 +400,8 @@ static void warn_level(void) {
}
}
-static ssize_t
-show_level(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t level_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev = to_usb_device(dev);
const char *p = auto_string;
@@ -423,9 +412,8 @@ show_level(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s\n", p);
}
-static ssize_t
-set_level(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t level_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int len = count;
@@ -453,12 +441,10 @@ set_level(struct device *dev, struct device_attribute *attr,
usb_unlock_device(udev);
return rc;
}
+static DEVICE_ATTR_RW(level);
-static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
-
-static ssize_t
-show_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t usb2_hardware_lpm_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_device *udev = to_usb_device(dev);
const char *p;
@@ -471,9 +457,9 @@ show_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%s\n", p);
}
-static ssize_t
-set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t usb2_hardware_lpm_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
bool value;
@@ -493,21 +479,19 @@ set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
return ret;
}
+static DEVICE_ATTR_RW(usb2_hardware_lpm);
-static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm,
- set_usb2_hardware_lpm);
-
-static ssize_t
-show_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t usb2_lpm_l1_timeout_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct usb_device *udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->l1_params.timeout);
}
-static ssize_t
-set_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t usb2_lpm_l1_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
u16 timeout;
@@ -519,21 +503,18 @@ set_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
return count;
}
+static DEVICE_ATTR_RW(usb2_lpm_l1_timeout);
-static DEVICE_ATTR(usb2_lpm_l1_timeout, S_IRUGO | S_IWUSR,
- show_usb2_lpm_l1_timeout, set_usb2_lpm_l1_timeout);
-
-static ssize_t
-show_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t usb2_lpm_besl_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_device *udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->l1_params.besl);
}
-static ssize_t
-set_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t usb2_lpm_besl_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
u8 besl;
@@ -545,9 +526,7 @@ set_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
return count;
}
-
-static DEVICE_ATTR(usb2_lpm_besl, S_IRUGO | S_IWUSR,
- show_usb2_lpm_besl, set_usb2_lpm_besl);
+static DEVICE_ATTR_RW(usb2_lpm_besl);
static struct attribute *usb2_hardware_lpm_attr[] = {
&dev_attr_usb2_hardware_lpm.attr,
@@ -604,7 +583,7 @@ static void remove_power_attributes(struct device *dev)
/* Descriptor fields */
#define usb_descriptor_attr_le16(field, format_string) \
static ssize_t \
-show_##field(struct device *dev, struct device_attribute *attr, \
+field##_show(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_device *udev; \
@@ -613,15 +592,15 @@ show_##field(struct device *dev, struct device_attribute *attr, \
return sprintf(buf, format_string, \
le16_to_cpu(udev->descriptor.field)); \
} \
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+static DEVICE_ATTR_RO(field)
-usb_descriptor_attr_le16(idVendor, "%04x\n")
-usb_descriptor_attr_le16(idProduct, "%04x\n")
-usb_descriptor_attr_le16(bcdDevice, "%04x\n")
+usb_descriptor_attr_le16(idVendor, "%04x\n");
+usb_descriptor_attr_le16(idProduct, "%04x\n");
+usb_descriptor_attr_le16(bcdDevice, "%04x\n");
#define usb_descriptor_attr(field, format_string) \
static ssize_t \
-show_##field(struct device *dev, struct device_attribute *attr, \
+field##_show(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_device *udev; \
@@ -629,34 +608,31 @@ show_##field(struct device *dev, struct device_attribute *attr, \
udev = to_usb_device(dev); \
return sprintf(buf, format_string, udev->descriptor.field); \
} \
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-
-usb_descriptor_attr(bDeviceClass, "%02x\n")
-usb_descriptor_attr(bDeviceSubClass, "%02x\n")
-usb_descriptor_attr(bDeviceProtocol, "%02x\n")
-usb_descriptor_attr(bNumConfigurations, "%d\n")
-usb_descriptor_attr(bMaxPacketSize0, "%d\n")
+static DEVICE_ATTR_RO(field)
+usb_descriptor_attr(bDeviceClass, "%02x\n");
+usb_descriptor_attr(bDeviceSubClass, "%02x\n");
+usb_descriptor_attr(bDeviceProtocol, "%02x\n");
+usb_descriptor_attr(bNumConfigurations, "%d\n");
+usb_descriptor_attr(bMaxPacketSize0, "%d\n");
/* show if the device is authorized (1) or not (0) */
-static ssize_t usb_dev_authorized_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t authorized_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_device *usb_dev = to_usb_device(dev);
return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
}
-
/*
* Authorize a device to be used in the system
*
* Writing a 0 deauthorizes the device, writing a 1 authorizes it.
*/
-static ssize_t usb_dev_authorized_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
+static ssize_t authorized_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
{
ssize_t result;
struct usb_device *usb_dev = to_usb_device(dev);
@@ -670,14 +646,12 @@ static ssize_t usb_dev_authorized_store(struct device *dev,
result = usb_authorize_device(usb_dev);
return result < 0? result : size;
}
-
-static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, 0644,
- usb_dev_authorized_show, usb_dev_authorized_store);
+static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, S_IRUGO | S_IWUSR,
+ authorized_show, authorized_store);
/* "Safely remove a device" */
-static ssize_t usb_remove_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int rc = 0;
@@ -694,7 +668,7 @@ static ssize_t usb_remove_store(struct device *dev,
usb_unlock_device(udev);
return rc;
}
-static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, usb_remove_store);
+static DEVICE_ATTR_IGNORE_LOCKDEP(remove, S_IWUSR, NULL, remove_store);
static struct attribute *dev_attrs[] = {
@@ -853,7 +827,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
/* Interface Accociation Descriptor fields */
#define usb_intf_assoc_attr(field, format_string) \
static ssize_t \
-show_iad_##field(struct device *dev, struct device_attribute *attr, \
+iad_##field##_show(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
@@ -861,18 +835,18 @@ show_iad_##field(struct device *dev, struct device_attribute *attr, \
return sprintf(buf, format_string, \
intf->intf_assoc->field); \
} \
-static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL);
+static DEVICE_ATTR_RO(iad_##field)
-usb_intf_assoc_attr(bFirstInterface, "%02x\n")
-usb_intf_assoc_attr(bInterfaceCount, "%02d\n")
-usb_intf_assoc_attr(bFunctionClass, "%02x\n")
-usb_intf_assoc_attr(bFunctionSubClass, "%02x\n")
-usb_intf_assoc_attr(bFunctionProtocol, "%02x\n")
+usb_intf_assoc_attr(bFirstInterface, "%02x\n");
+usb_intf_assoc_attr(bInterfaceCount, "%02d\n");
+usb_intf_assoc_attr(bFunctionClass, "%02x\n");
+usb_intf_assoc_attr(bFunctionSubClass, "%02x\n");
+usb_intf_assoc_attr(bFunctionProtocol, "%02x\n");
/* Interface fields */
#define usb_intf_attr(field, format_string) \
static ssize_t \
-show_##field(struct device *dev, struct device_attribute *attr, \
+field##_show(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
@@ -880,17 +854,17 @@ show_##field(struct device *dev, struct device_attribute *attr, \
return sprintf(buf, format_string, \
intf->cur_altsetting->desc.field); \
} \
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+static DEVICE_ATTR_RO(field)
-usb_intf_attr(bInterfaceNumber, "%02x\n")
-usb_intf_attr(bAlternateSetting, "%2d\n")
-usb_intf_attr(bNumEndpoints, "%02x\n")
-usb_intf_attr(bInterfaceClass, "%02x\n")
-usb_intf_attr(bInterfaceSubClass, "%02x\n")
-usb_intf_attr(bInterfaceProtocol, "%02x\n")
+usb_intf_attr(bInterfaceNumber, "%02x\n");
+usb_intf_attr(bAlternateSetting, "%2d\n");
+usb_intf_attr(bNumEndpoints, "%02x\n");
+usb_intf_attr(bInterfaceClass, "%02x\n");
+usb_intf_attr(bInterfaceSubClass, "%02x\n");
+usb_intf_attr(bInterfaceProtocol, "%02x\n");
-static ssize_t show_interface_string(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t interface_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_interface *intf;
char *string;
@@ -903,10 +877,10 @@ static ssize_t show_interface_string(struct device *dev,
return 0;
return sprintf(buf, "%s\n", string);
}
-static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
+static DEVICE_ATTR_RO(interface);
-static ssize_t show_modalias(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_interface *intf;
struct usb_device *udev;
@@ -929,10 +903,11 @@ static ssize_t show_modalias(struct device *dev,
alt->desc.bInterfaceProtocol,
alt->desc.bInterfaceNumber);
}
-static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+static DEVICE_ATTR_RO(modalias);
-static ssize_t show_supports_autosuspend(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t supports_autosuspend_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct usb_interface *intf;
struct usb_device *udev;
@@ -952,7 +927,7 @@ static ssize_t show_supports_autosuspend(struct device *dev,
return ret;
}
-static DEVICE_ATTR(supports_autosuspend, S_IRUGO, show_supports_autosuspend, NULL);
+static DEVICE_ATTR_RO(supports_autosuspend);
static struct attribute *intf_attrs[] = {
&dev_attr_bInterfaceNumber.attr,
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 16927fa88fb..c12bc790a6a 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -7,6 +7,7 @@
#include <linux/usb.h>
#include <linux/wait.h>
#include <linux/usb/hcd.h>
+#include <linux/scatterlist.h>
#define to_urb(d) container_of(d, struct urb, kref)
@@ -54,12 +55,12 @@ EXPORT_SYMBOL_GPL(usb_init_urb);
* Creates an urb for the USB driver to use, initializes a few internal
* structures, incrementes the usage counter, and returns a pointer to it.
*
- * If no memory is available, NULL is returned.
- *
* If the driver want to use this urb for interrupt, control, or bulk
* endpoints, pass '0' as the number of iso packets.
*
* The driver must call usb_free_urb() when it is finished with the urb.
+ *
+ * Return: A pointer to the new urb, or %NULL if no memory is available.
*/
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
@@ -102,7 +103,7 @@ EXPORT_SYMBOL_GPL(usb_free_urb);
* host controller driver. This allows proper reference counting to happen
* for urbs.
*
- * A pointer to the urb with the incremented reference counter is returned.
+ * Return: A pointer to the urb with the incremented reference counter.
*/
struct urb *usb_get_urb(struct urb *urb)
{
@@ -199,13 +200,12 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
* the particular kind of transfer, although they will not initialize
* any transfer flags.
*
- * Successful submissions return 0; otherwise this routine returns a
- * negative error number. If the submission is successful, the complete()
- * callback from the URB will be called exactly once, when the USB core and
- * Host Controller Driver (HCD) are finished with the URB. When the completion
- * function is called, control of the URB is returned to the device
- * driver which issued the request. The completion handler may then
- * immediately free or reuse that URB.
+ * If the submission is successful, the complete() callback from the URB
+ * will be called exactly once, when the USB core and Host Controller Driver
+ * (HCD) are finished with the URB. When the completion function is called,
+ * control of the URB is returned to the device driver which issued the
+ * request. The completion handler may then immediately free or reuse that
+ * URB.
*
* With few exceptions, USB device drivers should never access URB fields
* provided by usbcore or the HCD until its complete() is called.
@@ -240,6 +240,9 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
* that are standardized in the USB 2.0 specification. For bulk
* endpoints, a synchronous usb_bulk_msg() call is available.
*
+ * Return:
+ * 0 on successful submissions. A negative error number otherwise.
+ *
* Request Queuing:
*
* URBs may be submitted to endpoints before previous ones complete, to
@@ -413,6 +416,14 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->iso_frame_desc[n].status = -EXDEV;
urb->iso_frame_desc[n].actual_length = 0;
}
+ } else if (urb->num_sgs && !urb->dev->bus->no_sg_constraint &&
+ dev->speed != USB_SPEED_WIRELESS) {
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(urb->sg, sg, urb->num_sgs - 1, i)
+ if (sg->length % max)
+ return -EINVAL;
}
/* the I/O buffer must be mapped/unmapped, except when length=0 */
@@ -564,6 +575,9 @@ EXPORT_SYMBOL_GPL(usb_submit_urb);
* particular, when a driver calls this routine, it must insure that the
* completion handler cannot deallocate the URB.
*
+ * Return: -EINPROGRESS on success. See description for other values on
+ * failure.
+ *
* Unlinking and Endpoint Queues:
*
* [The behaviors and guarantees described below do not apply to virtual
@@ -838,6 +852,8 @@ EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);
*
* Call this is you want to be sure all an anchor's
* URBs have finished
+ *
+ * Return: Non-zero if the anchor became unused. Zero on timeout.
*/
int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
unsigned int timeout)
@@ -851,8 +867,11 @@ EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
* usb_get_from_anchor - get an anchor's oldest urb
* @anchor: the anchor whose urb you want
*
- * this will take the oldest urb from an anchor,
+ * This will take the oldest urb from an anchor,
* unanchor and return it
+ *
+ * Return: The oldest urb from @anchor, or %NULL if @anchor has no
+ * urbs associated with it.
*/
struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
{
@@ -901,7 +920,7 @@ EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs);
* usb_anchor_empty - is an anchor empty
* @anchor: the anchor you want to query
*
- * returns 1 if the anchor has no urbs associated with it
+ * Return: 1 if the anchor has no urbs associated with it.
*/
int usb_anchor_empty(struct usb_anchor *anchor)
{
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 7dad603dde4..0a6ee2e70b2 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -68,6 +68,8 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
* @alt_num: alternate interface setting number to search for.
*
* Search the configuration's interface cache for the given alt setting.
+ *
+ * Return: The alternate setting, if found. %NULL otherwise.
*/
struct usb_host_interface *usb_find_alt_setting(
struct usb_host_config *config,
@@ -103,8 +105,7 @@ EXPORT_SYMBOL_GPL(usb_find_alt_setting);
* @ifnum: the desired interface
*
* This walks the device descriptor for the currently active configuration
- * and returns a pointer to the interface with that particular interface
- * number, or null.
+ * to find the interface object with the particular interface number.
*
* Note that configuration descriptors are not required to assign interface
* numbers sequentially, so that it would be incorrect to assume that
@@ -115,6 +116,9 @@ EXPORT_SYMBOL_GPL(usb_find_alt_setting);
*
* Don't call this function unless you are bound to one of the interfaces
* on this device or you have locked the device!
+ *
+ * Return: A pointer to the interface that has @ifnum as interface number,
+ * if found. %NULL otherwise.
*/
struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
unsigned ifnum)
@@ -139,8 +143,7 @@ EXPORT_SYMBOL_GPL(usb_ifnum_to_if);
* @altnum: the desired alternate setting number
*
* This searches the altsetting array of the specified interface for
- * an entry with the correct bAlternateSetting value and returns a pointer
- * to that entry, or null.
+ * an entry with the correct bAlternateSetting value.
*
* Note that altsettings need not be stored sequentially by number, so
* it would be incorrect to assume that the first altsetting entry in
@@ -149,6 +152,9 @@ EXPORT_SYMBOL_GPL(usb_ifnum_to_if);
*
* Don't call this function unless you are bound to the intf interface
* or you have locked the device!
+ *
+ * Return: A pointer to the entry of the altsetting array of @intf that
+ * has @altnum as the alternate setting number. %NULL if not found.
*/
struct usb_host_interface *usb_altnum_to_altsetting(
const struct usb_interface *intf,
@@ -191,6 +197,8 @@ static int __find_interface(struct device *dev, void *data)
* This walks the bus device list and returns a pointer to the interface
* with the matching minor and driver. Note, this only works for devices
* that share the USB major number.
+ *
+ * Return: A pointer to the interface with the matching major and @minor.
*/
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
{
@@ -390,6 +398,9 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus)
* controllers) should ever call this.
*
* This call may not be used in a non-sleeping context.
+ *
+ * Return: On success, a pointer to the allocated usb device. %NULL on
+ * failure.
*/
struct usb_device *usb_alloc_dev(struct usb_device *parent,
struct usb_bus *bus, unsigned port1)
@@ -501,7 +512,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
* their probe() methods, when they bind to an interface, and release
* them by calling usb_put_dev(), in their disconnect() methods.
*
- * A pointer to the device with the incremented reference counter is returned.
+ * Return: A pointer to the device with the incremented reference counter.
*/
struct usb_device *usb_get_dev(struct usb_device *dev)
{
@@ -535,8 +546,7 @@ EXPORT_SYMBOL_GPL(usb_put_dev);
* their probe() methods, when they bind to an interface, and release
* them by calling usb_put_intf(), in their disconnect() methods.
*
- * A pointer to the interface with the incremented reference counter is
- * returned.
+ * Return: A pointer to the interface with the incremented reference counter.
*/
struct usb_interface *usb_get_intf(struct usb_interface *intf)
{
@@ -589,7 +599,7 @@ EXPORT_SYMBOL_GPL(usb_put_intf);
* disconnect; in some drivers (such as usb-storage) the disconnect()
* or suspend() method will block waiting for a device reset to complete.
*
- * Returns a negative error code for failure, otherwise 0.
+ * Return: A negative error code for failure, otherwise 0.
*/
int usb_lock_device_for_reset(struct usb_device *udev,
const struct usb_interface *iface)
@@ -628,14 +638,15 @@ EXPORT_SYMBOL_GPL(usb_lock_device_for_reset);
* usb_get_current_frame_number - return current bus frame number
* @dev: the device whose bus is being queried
*
- * Returns the current frame number for the USB host controller
- * used with the given USB device. This can be used when scheduling
+ * Return: The current frame number for the USB host controller used
+ * with the given USB device. This can be used when scheduling
* isochronous requests.
*
- * Note that different kinds of host controller have different
- * "scheduling horizons". While one type might support scheduling only
- * 32 frames into the future, others could support scheduling up to
- * 1024 frames into the future.
+ * Note: Different kinds of host controller have different "scheduling
+ * horizons". While one type might support scheduling only 32 frames
+ * into the future, others could support scheduling up to 1024 frames
+ * into the future.
+ *
*/
int usb_get_current_frame_number(struct usb_device *dev)
{
@@ -685,11 +696,12 @@ EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor);
* @mem_flags: affect whether allocation may block
* @dma: used to return DMA address of buffer
*
- * Return value is either null (indicating no buffer could be allocated), or
- * the cpu-space pointer to a buffer that may be used to perform DMA to the
+ * Return: Either null (indicating no buffer could be allocated), or the
+ * cpu-space pointer to a buffer that may be used to perform DMA to the
* specified device. Such cpu-space buffers are returned along with the DMA
* address (through the pointer provided).
*
+ * Note:
* These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
* to avoid behaviors like using "DMA bounce buffers", or thrashing IOMMU
* hardware during URB completion/resubmit. The implementation varies between
@@ -735,17 +747,18 @@ EXPORT_SYMBOL_GPL(usb_free_coherent);
* usb_buffer_map - create DMA mapping(s) for an urb
* @urb: urb whose transfer_buffer/setup_packet will be mapped
*
- * Return value is either null (indicating no buffer could be mapped), or
- * the parameter. URB_NO_TRANSFER_DMA_MAP is
- * added to urb->transfer_flags if the operation succeeds. If the device
- * is connected to this system through a non-DMA controller, this operation
- * always succeeds.
+ * URB_NO_TRANSFER_DMA_MAP is added to urb->transfer_flags if the operation
+ * succeeds. If the device is connected to this system through a non-DMA
+ * controller, this operation always succeeds.
*
* This call would normally be used for an urb which is reused, perhaps
* as the target of a large periodic transfer, with usb_buffer_dmasync()
* calls to synchronize memory and dma state.
*
* Reverse the effect of this call with usb_buffer_unmap().
+ *
+ * Return: Either %NULL (indicating no buffer could be mapped), or @urb.
+ *
*/
#if 0
struct urb *usb_buffer_map(struct urb *urb)
@@ -850,9 +863,10 @@ EXPORT_SYMBOL_GPL(usb_buffer_unmap);
* @sg: the scatterlist to map
* @nents: the number of entries in the scatterlist
*
- * Return value is either < 0 (indicating no buffers could be mapped), or
- * the number of DMA mapping array entries in the scatterlist.
+ * Return: Either < 0 (indicating no buffers could be mapped), or the
+ * number of DMA mapping array entries in the scatterlist.
*
+ * Note:
* The caller is responsible for placing the resulting DMA addresses from
* the scatterlist into URB transfer buffer pointers, and for setting the
* URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs.
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 757aa18027d..f969ea266ac 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,6 +1,7 @@
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
- depends on (USB || USB_GADGET) && GENERIC_HARDIRQS
+ depends on (USB || USB_GADGET) && GENERIC_HARDIRQS && HAS_DMA
+ depends on EXTCON
select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
help
Say Y or M here if your system has a Dual Role SuperSpeed
@@ -40,6 +41,38 @@ config USB_DWC3_DUAL_ROLE
endchoice
+comment "Platform Glue Driver Support"
+
+config USB_DWC3_OMAP
+ tristate "Texas Instruments OMAP5 and similar Platforms"
+ depends on EXTCON
+ default USB_DWC3
+ help
+ Some platforms from Texas Instruments like OMAP5, DRA7xxx and
+ AM437x use this IP for USB2/3 functionality.
+
+ Say 'Y' or 'M' here if you have one such device
+
+config USB_DWC3_EXYNOS
+ tristate "Samsung Exynos Platform"
+ default USB_DWC3
+ help
+ Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside,
+ say 'Y' or 'M' if you have one such device.
+
+config USB_DWC3_PCI
+ tristate "PCIe-based Platforms"
+ depends on PCI
+ default USB_DWC3
+ help
+ If you're using the DesignWare Core IP with a PCIe, please say
+ 'Y' or 'M' here.
+
+ One such PCIe-based platform is Synopsys' PCIe HAPS model of
+ this IP.
+
+comment "Debugging features"
+
config USB_DWC3_DEBUG
bool "Enable Debugging Messages"
help
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 0c7ac92582b..dd1760145c4 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -27,15 +27,8 @@ endif
# the entire driver (with all its glue layers) on several architectures
# and make sure it compiles fine. This will also help with allmodconfig
# and allyesconfig builds.
-#
-# The only exception is the PCI glue layer, but that's only because
-# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
##
-obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
-obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o
-
-ifneq ($(CONFIG_PCI),)
- obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
-endif
-
+obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
+obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o
+obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index c35d49d39b7..474162e9d01 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -6,34 +6,17 @@
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
+ * 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.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
@@ -50,20 +33,18 @@
#include <linux/dma-mapping.h>
#include <linux/of.h>
-#include <linux/usb/otg.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
+#include "platform_data.h"
#include "core.h"
#include "gadget.h"
#include "io.h"
#include "debug.h"
-static char *maximum_speed = "super";
-module_param(maximum_speed, charp, 0);
-MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
-
/* -------------------------------------------------------------------------- */
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
@@ -236,7 +217,7 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
upper_32_bits(evt->dma));
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
- evt->length & 0xffff);
+ DWC3_GEVNTSIZ_SIZE(evt->length));
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
}
@@ -255,7 +236,8 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
- dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
+ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
+ | DWC3_GEVNTSIZ_SIZE(0));
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
}
}
@@ -367,18 +349,17 @@ static void dwc3_core_exit(struct dwc3 *dwc)
static int dwc3_probe(struct platform_device *pdev)
{
- struct device_node *node = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct dwc3_platform_data *pdata = dev_get_platdata(dev);
+ struct device_node *node = dev->of_node;
struct resource *res;
struct dwc3 *dwc;
- struct device *dev = &pdev->dev;
int ret = -ENOMEM;
void __iomem *regs;
void *mem;
- u8 mode;
-
mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
if (!mem) {
dev_err(dev, "not enough memory\n");
@@ -402,38 +383,32 @@ static int dwc3_probe(struct platform_device *pdev)
dev_err(dev, "missing memory resource\n");
return -ENODEV;
}
- dwc->xhci_resources[0].start = res->start;
- dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
- DWC3_XHCI_REGS_END;
- dwc->xhci_resources[0].flags = res->flags;
- dwc->xhci_resources[0].name = res->name;
-
- /*
- * Request memory region but exclude xHCI regs,
- * since it will be requested by the xhci-plat driver.
- */
- res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
- resource_size(res) - DWC3_GLOBALS_REGS_START,
- dev_name(dev));
- if (!res) {
- dev_err(dev, "can't request mem region\n");
- return -ENOMEM;
- }
-
- regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
- if (!regs) {
- dev_err(dev, "ioremap failed\n");
- return -ENOMEM;
- }
if (node) {
+ dwc->maximum_speed = of_usb_get_maximum_speed(node);
+
dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
+
+ dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
+ dwc->dr_mode = of_usb_get_dr_mode(node);
+ } else if (pdata) {
+ dwc->maximum_speed = pdata->maximum_speed;
+
+ dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+ dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
+
+ dwc->needs_fifo_resize = pdata->tx_fifo_resize;
+ dwc->dr_mode = pdata->dr_mode;
} else {
dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
}
+ /* default to superspeed if no maximum_speed passed */
+ if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
+ dwc->maximum_speed = USB_SPEED_SUPER;
+
if (IS_ERR(dwc->usb2_phy)) {
ret = PTR_ERR(dwc->usb2_phy);
@@ -450,7 +425,7 @@ static int dwc3_probe(struct platform_device *pdev)
}
if (IS_ERR(dwc->usb3_phy)) {
- ret = PTR_ERR(dwc->usb2_phy);
+ ret = PTR_ERR(dwc->usb3_phy);
/*
* if -ENXIO is returned, it means PHY layer wasn't
@@ -464,6 +439,22 @@ static int dwc3_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}
+ dwc->xhci_resources[0].start = res->start;
+ dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+ DWC3_XHCI_REGS_END;
+ dwc->xhci_resources[0].flags = res->flags;
+ dwc->xhci_resources[0].name = res->name;
+
+ res->start += DWC3_GLOBALS_REGS_START;
+
+ /*
+ * Request memory region but exclude xHCI regs,
+ * since it will be requested by the xhci-plat driver.
+ */
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
usb_phy_set_suspend(dwc->usb2_phy, 0);
usb_phy_set_suspend(dwc->usb3_phy, 0);
@@ -478,19 +469,6 @@ static int dwc3_probe(struct platform_device *pdev)
dev->dma_parms = dev->parent->dma_parms;
dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
- if (!strncmp("super", maximum_speed, 5))
- dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
- else if (!strncmp("high", maximum_speed, 4))
- dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
- else if (!strncmp("full", maximum_speed, 4))
- dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
- else if (!strncmp("low", maximum_speed, 3))
- dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
- else
- dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
-
- dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
-
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
pm_runtime_forbid(dev);
@@ -517,14 +495,15 @@ static int dwc3_probe(struct platform_device *pdev)
}
if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
- mode = DWC3_MODE_HOST;
+ dwc->dr_mode = USB_DR_MODE_HOST;
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
- mode = DWC3_MODE_DEVICE;
- else
- mode = DWC3_MODE_DRD;
+ dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+ if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+ dwc->dr_mode = USB_DR_MODE_OTG;
- switch (mode) {
- case DWC3_MODE_DEVICE:
+ switch (dwc->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
@@ -532,7 +511,7 @@ static int dwc3_probe(struct platform_device *pdev)
goto err2;
}
break;
- case DWC3_MODE_HOST:
+ case USB_DR_MODE_HOST:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
@@ -540,7 +519,7 @@ static int dwc3_probe(struct platform_device *pdev)
goto err2;
}
break;
- case DWC3_MODE_DRD:
+ case USB_DR_MODE_OTG:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
ret = dwc3_host_init(dwc);
if (ret) {
@@ -555,10 +534,9 @@ static int dwc3_probe(struct platform_device *pdev)
}
break;
default:
- dev_err(dev, "Unsupported mode of operation %d\n", mode);
+ dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
goto err2;
}
- dwc->mode = mode;
ret = dwc3_debugfs_init(dwc);
if (ret) {
@@ -571,14 +549,14 @@ static int dwc3_probe(struct platform_device *pdev)
return 0;
err3:
- switch (mode) {
- case DWC3_MODE_DEVICE:
+ switch (dwc->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
dwc3_gadget_exit(dwc);
break;
- case DWC3_MODE_HOST:
+ case USB_DR_MODE_HOST:
dwc3_host_exit(dwc);
break;
- case DWC3_MODE_DRD:
+ case USB_DR_MODE_OTG:
dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
break;
@@ -611,14 +589,14 @@ static int dwc3_remove(struct platform_device *pdev)
dwc3_debugfs_exit(dwc);
- switch (dwc->mode) {
- case DWC3_MODE_DEVICE:
+ switch (dwc->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
dwc3_gadget_exit(dwc);
break;
- case DWC3_MODE_HOST:
+ case USB_DR_MODE_HOST:
dwc3_host_exit(dwc);
break;
- case DWC3_MODE_DRD:
+ case USB_DR_MODE_OTG:
dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
break;
@@ -642,12 +620,12 @@ static int dwc3_prepare(struct device *dev)
spin_lock_irqsave(&dwc->lock, flags);
- switch (dwc->mode) {
- case DWC3_MODE_DEVICE:
- case DWC3_MODE_DRD:
+ switch (dwc->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
+ case USB_DR_MODE_OTG:
dwc3_gadget_prepare(dwc);
/* FALLTHROUGH */
- case DWC3_MODE_HOST:
+ case USB_DR_MODE_HOST:
default:
dwc3_event_buffers_cleanup(dwc);
break;
@@ -665,12 +643,12 @@ static void dwc3_complete(struct device *dev)
spin_lock_irqsave(&dwc->lock, flags);
- switch (dwc->mode) {
- case DWC3_MODE_DEVICE:
- case DWC3_MODE_DRD:
+ switch (dwc->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
+ case USB_DR_MODE_OTG:
dwc3_gadget_complete(dwc);
/* FALLTHROUGH */
- case DWC3_MODE_HOST:
+ case USB_DR_MODE_HOST:
default:
dwc3_event_buffers_setup(dwc);
break;
@@ -686,12 +664,12 @@ static int dwc3_suspend(struct device *dev)
spin_lock_irqsave(&dwc->lock, flags);
- switch (dwc->mode) {
- case DWC3_MODE_DEVICE:
- case DWC3_MODE_DRD:
+ switch (dwc->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
+ case USB_DR_MODE_OTG:
dwc3_gadget_suspend(dwc);
/* FALLTHROUGH */
- case DWC3_MODE_HOST:
+ case USB_DR_MODE_HOST:
default:
/* do nothing */
break;
@@ -719,12 +697,12 @@ static int dwc3_resume(struct device *dev)
dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
- switch (dwc->mode) {
- case DWC3_MODE_DEVICE:
- case DWC3_MODE_DRD:
+ switch (dwc->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
+ case USB_DR_MODE_OTG:
dwc3_gadget_resume(dwc);
/* FALLTHROUGH */
- case DWC3_MODE_HOST:
+ case USB_DR_MODE_HOST:
default:
/* do nothing */
break;
@@ -754,6 +732,9 @@ static const struct dev_pm_ops dwc3_dev_pm_ops = {
#ifdef CONFIG_OF
static const struct of_device_id of_dwc3_match[] = {
{
+ .compatible = "snps,dwc3"
+ },
+ {
.compatible = "synopsys,dwc3"
},
{ },
@@ -775,5 +756,5 @@ module_platform_driver(dwc3_driver);
MODULE_ALIAS("platform:dwc3");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index b69d322e3ca..f8af8d44af8 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -6,34 +6,14 @@
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __DRIVERS_USB_DWC3_CORE_H
@@ -49,6 +29,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
/* Global constants */
#define DWC3_EP0_BOUNCE_SIZE 512
@@ -194,6 +175,10 @@
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
+/* Global Event Size Registers */
+#define DWC3_GEVNTSIZ_INTMASK (1 << 31)
+#define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff)
+
/* Global HWPARAMS1 Register */
#define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24)
#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
@@ -207,7 +192,6 @@
#define DWC3_MAX_HIBER_SCRATCHBUFS 15
/* Device Configuration Register */
-#define DWC3_DCFG_LPM_CAP (1 << 22)
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@@ -367,7 +351,6 @@ struct dwc3_trb;
/**
* struct dwc3_event_buffer - Software event buffer representation
- * @list: a list of event buffers
* @buf: _THE_ buffer
* @length: size of this buffer
* @lpos: event offset
@@ -415,7 +398,7 @@ struct dwc3_event_buffer {
* @number: endpoint number (1 - 15)
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
* @resource_index: Resource transfer index
- * @interval: the intervall on which the ISOC transfer is started
+ * @interval: the interval on which the ISOC transfer is started
* @name: a human readable name e.g. ep1out-bulk
* @direction: true for TX, false for RX
* @stream_capable: true when streams are enabled
@@ -566,11 +549,6 @@ struct dwc3_hwparams {
/* HWPARAMS0 */
#define DWC3_MODE(n) ((n) & 0x7)
-#define DWC3_MODE_DEVICE 0
-#define DWC3_MODE_HOST 1
-#define DWC3_MODE_DRD 2
-#define DWC3_MODE_HUB 3
-
#define DWC3_MDWIDTH(n) (((n) & 0xff00) >> 8)
/* HWPARAMS1 */
@@ -632,7 +610,7 @@ struct dwc3_scratchpad_array {
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
* @revision: revision register contents
- * @mode: mode of operation
+ * @dr_mode: requested mode of operation
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
* @dcfg: saved contents of DCFG register
@@ -690,6 +668,8 @@ struct dwc3 {
void __iomem *regs;
size_t regs_size;
+ enum usb_dr_mode dr_mode;
+
/* used for suspend/resume */
u32 dcfg;
u32 gctl;
@@ -698,7 +678,6 @@ struct dwc3 {
u32 u1u2;
u32 maximum_speed;
u32 revision;
- u32 mode;
#define DWC3_REVISION_173A 0x5533173a
#define DWC3_REVISION_175A 0x5533175a
@@ -759,8 +738,8 @@ struct dwc3 {
struct dwc3_event_type {
u32 is_devspec:1;
- u32 type:6;
- u32 reserved8_31:25;
+ u32 type:7;
+ u32 reserved8_31:24;
} __packed;
#define DWC3_DEPEVT_XFERCOMPLETE 0x01
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index 5894ee8222a..fceb39dc4bb 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -6,34 +6,14 @@
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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 "core.h"
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 9e9f122162f..9ac37fe1b6a 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -6,34 +6,14 @@
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#include <linux/kernel.h>
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index 8ce9d7fd6cf..2f2e88a3a11 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -6,10 +6,14 @@
*
* Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License 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.
*/
#include <linux/module.h>
@@ -20,7 +24,7 @@
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -34,13 +38,13 @@ struct dwc3_exynos {
static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
{
- struct nop_usb_xceiv_platform_data pdata;
+ struct usb_phy_gen_xceiv_platform_data pdata;
struct platform_device *pdev;
int ret;
memset(&pdata, 0x00, sizeof(pdata));
- pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
+ pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO);
if (!pdev)
return -ENOMEM;
@@ -51,7 +55,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
if (ret)
goto err1;
- pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
+ pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO);
if (!pdev) {
ret = -ENOMEM;
goto err1;
@@ -228,5 +232,5 @@ module_platform_driver(dwc3_exynos_driver);
MODULE_ALIAS("platform:exynos-dwc3");
MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 077f110bd74..7f7ea62e961 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -6,34 +6,14 @@
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#include <linux/module.h>
@@ -43,13 +23,15 @@
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/platform_data/dwc3-omap.h>
-#include <linux/usb/dwc3-omap.h>
#include <linux/pm_runtime.h>
#include <linux/dma-mapping.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/extcon.h>
+#include <linux/extcon/of_extcon.h>
+#include <linux/regulator/consumer.h>
#include <linux/usb/otg.h>
@@ -155,9 +137,21 @@ struct dwc3_omap {
u32 revision;
u32 dma_status:1;
+
+ struct extcon_specific_cable_nb extcon_vbus_dev;
+ struct extcon_specific_cable_nb extcon_id_dev;
+ struct notifier_block vbus_nb;
+ struct notifier_block id_nb;
+
+ struct regulator *vbus_reg;
};
-static struct dwc3_omap *_omap;
+enum omap_dwc3_vbus_id_status {
+ OMAP_DWC3_ID_FLOAT,
+ OMAP_DWC3_ID_GROUND,
+ OMAP_DWC3_VBUS_OFF,
+ OMAP_DWC3_VBUS_VALID,
+};
static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
{
@@ -221,18 +215,24 @@ static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value)
omap->irq0_offset, value);
}
-int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
+static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
+ enum omap_dwc3_vbus_id_status status)
{
- u32 val;
- struct dwc3_omap *omap = _omap;
-
- if (!omap)
- return -EPROBE_DEFER;
+ int ret;
+ u32 val;
switch (status) {
case OMAP_DWC3_ID_GROUND:
dev_dbg(omap->dev, "ID GND\n");
+ if (omap->vbus_reg) {
+ ret = regulator_enable(omap->vbus_reg);
+ if (ret) {
+ dev_dbg(omap->dev, "regulator enable failed\n");
+ return;
+ }
+ }
+
val = dwc3_omap_read_utmi_status(omap);
val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
@@ -255,6 +255,9 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
break;
case OMAP_DWC3_ID_FLOAT:
+ if (omap->vbus_reg)
+ regulator_disable(omap->vbus_reg);
+
case OMAP_DWC3_VBUS_OFF:
dev_dbg(omap->dev, "VBUS Disconnect\n");
@@ -268,12 +271,9 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
break;
default:
- dev_dbg(omap->dev, "ID float\n");
+ dev_dbg(omap->dev, "invalid state\n");
}
-
- return 0;
}
-EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
@@ -366,6 +366,32 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
+static int dwc3_omap_id_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, id_nb);
+
+ if (event)
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+ else
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT);
+
+ return NOTIFY_DONE;
+}
+
+static int dwc3_omap_vbus_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, vbus_nb);
+
+ if (event)
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+ else
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF);
+
+ return NOTIFY_DONE;
+}
+
static int dwc3_omap_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -373,6 +399,8 @@ static int dwc3_omap_probe(struct platform_device *pdev)
struct dwc3_omap *omap;
struct resource *res;
struct device *dev = &pdev->dev;
+ struct extcon_dev *edev;
+ struct regulator *vbus_reg = NULL;
int ret = -ENOMEM;
int irq;
@@ -409,10 +437,16 @@ static int dwc3_omap_probe(struct platform_device *pdev)
return -EINVAL;
}
- base = devm_ioremap_nocache(dev, res->start, resource_size(res));
- if (!base) {
- dev_err(dev, "ioremap failed\n");
- return -ENOMEM;
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ if (of_property_read_bool(node, "vbus-supply")) {
+ vbus_reg = devm_regulator_get(dev, "vbus");
+ if (IS_ERR(vbus_reg)) {
+ dev_err(dev, "vbus init failed\n");
+ return PTR_ERR(vbus_reg);
+ }
}
spin_lock_init(&omap->lock);
@@ -420,14 +454,9 @@ static int dwc3_omap_probe(struct platform_device *pdev)
omap->dev = dev;
omap->irq = irq;
omap->base = base;
+ omap->vbus_reg = vbus_reg;
dev->dma_mask = &dwc3_omap_dma_mask;
- /*
- * REVISIT if we ever have two instances of the wrapper, we will be
- * in big trouble
- */
- _omap = omap;
-
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
@@ -502,14 +531,46 @@ static int dwc3_omap_probe(struct platform_device *pdev)
dwc3_omap_enable_irqs(omap);
+ if (of_property_read_bool(node, "extcon")) {
+ edev = of_extcon_get_extcon_dev(dev, 0);
+ if (IS_ERR(edev)) {
+ dev_vdbg(dev, "couldn't get extcon device\n");
+ ret = PTR_ERR(edev);
+ goto err2;
+ }
+
+ omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
+ ret = extcon_register_interest(&omap->extcon_vbus_dev,
+ edev->name, "USB", &omap->vbus_nb);
+ if (ret < 0)
+ dev_vdbg(dev, "failed to register notifier for USB\n");
+ omap->id_nb.notifier_call = dwc3_omap_id_notifier;
+ ret = extcon_register_interest(&omap->extcon_id_dev, edev->name,
+ "USB-HOST", &omap->id_nb);
+ if (ret < 0)
+ dev_vdbg(dev,
+ "failed to register notifier for USB-HOST\n");
+
+ if (extcon_get_cable_state(edev, "USB") == true)
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+ if (extcon_get_cable_state(edev, "USB-HOST") == true)
+ dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+ }
+
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
dev_err(&pdev->dev, "failed to create dwc3 core\n");
- goto err2;
+ goto err3;
}
return 0;
+err3:
+ if (omap->extcon_vbus_dev.edev)
+ extcon_unregister_interest(&omap->extcon_vbus_dev);
+ if (omap->extcon_id_dev.edev)
+ extcon_unregister_interest(&omap->extcon_id_dev);
+
err2:
dwc3_omap_disable_irqs(omap);
@@ -526,6 +587,10 @@ static int dwc3_omap_remove(struct platform_device *pdev)
{
struct dwc3_omap *omap = platform_get_drvdata(pdev);
+ if (omap->extcon_vbus_dev.edev)
+ extcon_unregister_interest(&omap->extcon_vbus_dev);
+ if (omap->extcon_id_dev.edev)
+ extcon_unregister_interest(&omap->extcon_id_dev);
dwc3_omap_disable_irqs(omap);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -610,5 +675,5 @@ module_platform_driver(dwc3_omap_driver);
MODULE_ALIAS("platform:omap-dwc3");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index ed07ec04a96..9b138129e85 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -6,34 +6,14 @@
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#include <linux/kernel.h>
@@ -43,7 +23,7 @@
#include <linux/platform_device.h>
#include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
/* FIXME define these in <linux/pci_ids.h> */
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
@@ -58,13 +38,13 @@ struct dwc3_pci {
static int dwc3_pci_register_phys(struct dwc3_pci *glue)
{
- struct nop_usb_xceiv_platform_data pdata;
+ struct usb_phy_gen_xceiv_platform_data pdata;
struct platform_device *pdev;
int ret;
memset(&pdata, 0x00, sizeof(pdata));
- pdev = platform_device_alloc("nop_usb_xceiv", 0);
+ pdev = platform_device_alloc("usb_phy_gen_xceiv", 0);
if (!pdev)
return -ENOMEM;
@@ -75,7 +55,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue)
if (ret)
goto err1;
- pdev = platform_device_alloc("nop_usb_xceiv", 1);
+ pdev = platform_device_alloc("usb_phy_gen_xceiv", 1);
if (!pdev) {
ret = -ENOMEM;
goto err1;
@@ -211,7 +191,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int dwc3_pci_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
@@ -236,28 +216,24 @@ static int dwc3_pci_resume(struct device *dev)
return 0;
}
+#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
};
-#define DEV_PM_OPS (&dwc3_pci_dev_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif /* CONFIG_PM */
-
static struct pci_driver dwc3_pci_driver = {
.name = "dwc3-pci",
.id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe,
.remove = dwc3_pci_remove,
.driver = {
- .pm = DEV_PM_OPS,
+ .pm = &dwc3_pci_dev_pm_ops,
},
};
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
module_pci_driver(dwc3_pci_driver);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 5acbb948b70..7fa93f4bc50 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -6,34 +6,14 @@
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#include <linux/kernel.h>
@@ -168,6 +148,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
direction = !dwc->ep0_expect_in;
dwc->delayed_status = false;
+ usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED);
if (dwc->ep0state == EP0_STATUS_PHASE)
__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
@@ -553,8 +534,16 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
ret = dwc3_ep0_delegate_req(dwc, ctrl);
/* if the cfg matches and the cfg is non zero */
if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
- usb_gadget_set_state(&dwc->gadget,
- USB_STATE_CONFIGURED);
+
+ /*
+ * only change state if set_config has already
+ * been processed. If gadget driver returns
+ * USB_GADGET_DELAYED_STATUS, we will wait
+ * to change the state on the next usb_ep_queue()
+ */
+ if (ret == 0)
+ usb_gadget_set_state(&dwc->gadget,
+ USB_STATE_CONFIGURED);
/*
* Enable transition to U1/U2 state when
@@ -571,7 +560,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
case USB_STATE_CONFIGURED:
ret = dwc3_ep0_delegate_req(dwc, ctrl);
- if (!cfg)
+ if (!cfg && !ret)
usb_gadget_set_state(&dwc->gadget,
USB_STATE_ADDRESS);
break;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index b5e5b35df49..f168eaebdef 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -6,34 +6,14 @@
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#include <linux/kernel.h>
@@ -520,6 +500,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
u32 reg;
int ret = -ENOMEM;
+ dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+
if (!(dep->flags & DWC3_EP_ENABLED)) {
ret = dwc3_gadget_start_config(dwc, dep);
if (ret)
@@ -676,8 +658,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
dev_err(dwc->dev, "invalid endpoint transfer type\n");
}
- dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
-
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1508,6 +1488,15 @@ static int dwc3_gadget_start(struct usb_gadget *g,
int irq;
u32 reg;
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+ IRQF_SHARED, "dwc3", dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+ irq, ret);
+ goto err0;
+ }
+
spin_lock_irqsave(&dwc->lock, flags);
if (dwc->gadget_driver) {
@@ -1515,7 +1504,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
dwc->gadget.name,
dwc->gadget_driver->driver.name);
ret = -EBUSY;
- goto err0;
+ goto err1;
}
dwc->gadget_driver = driver;
@@ -1536,10 +1525,25 @@ static int dwc3_gadget_start(struct usb_gadget *g,
* STAR#9000525659: Clock Domain Crossing on DCTL in
* USB 2.0 Mode
*/
- if (dwc->revision < DWC3_REVISION_220A)
+ if (dwc->revision < DWC3_REVISION_220A) {
reg |= DWC3_DCFG_SUPERSPEED;
- else
- reg |= dwc->maximum_speed;
+ } else {
+ switch (dwc->maximum_speed) {
+ case USB_SPEED_LOW:
+ reg |= DWC3_DSTS_LOWSPEED;
+ break;
+ case USB_SPEED_FULL:
+ reg |= DWC3_DSTS_FULLSPEED1;
+ break;
+ case USB_SPEED_HIGH:
+ reg |= DWC3_DSTS_HIGHSPEED;
+ break;
+ case USB_SPEED_SUPER: /* FALLTHROUGH */
+ case USB_SPEED_UNKNOWN: /* FALTHROUGH */
+ default:
+ reg |= DWC3_DSTS_SUPERSPEED;
+ }
+ }
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc->start_config_issued = false;
@@ -1551,41 +1555,38 @@ static int dwc3_gadget_start(struct usb_gadget *g,
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
- goto err0;
+ goto err2;
}
dep = dwc->eps[1];
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
- goto err1;
+ goto err3;
}
/* begin to receive SETUP packets */
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
- irq = platform_get_irq(to_platform_device(dwc->dev), 0);
- ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
- IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
- if (ret) {
- dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
- irq, ret);
- goto err1;
- }
-
dwc3_gadget_enable_irq(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
-err1:
+err3:
__dwc3_gadget_ep_disable(dwc->eps[0]);
-err0:
+err2:
+ dwc->gadget_driver = NULL;
+
+err1:
spin_unlock_irqrestore(&dwc->lock, flags);
+ free_irq(irq, dwc);
+
+err0:
return ret;
}
@@ -1599,9 +1600,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_disable_irq(dwc);
- irq = platform_get_irq(to_platform_device(dwc->dev), 0);
- free_irq(irq, dwc);
-
__dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]);
@@ -1609,6 +1607,9 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
spin_unlock_irqrestore(&dwc->lock, flags);
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ free_irq(irq, dwc);
+
return 0;
}
@@ -1641,13 +1642,15 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
dep->dwc = dwc;
dep->number = epnum;
+ dep->direction = !!direction;
dwc->eps[epnum] = dep;
snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
(epnum & 1) ? "in" : "out");
dep->endpoint.name = dep->name;
- dep->direction = (epnum & 1);
+
+ dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
if (epnum == 0 || epnum == 1) {
dep->endpoint.maxpacket = 512;
@@ -2104,34 +2107,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
dwc->setup_packet_pending = false;
}
-static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend)
-{
- u32 reg;
-
- reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
-
- if (suspend)
- reg |= DWC3_GUSB3PIPECTL_SUSPHY;
- else
- reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
-
- dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
-}
-
-static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend)
-{
- u32 reg;
-
- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
-
- if (suspend)
- reg |= DWC3_GUSB2PHYCFG_SUSPHY;
- else
- reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
-
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
-}
-
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
{
u32 reg;
@@ -2172,13 +2147,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
/* after reset -> Default State */
usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
- /* Recent versions support automatic phy suspend and don't need this */
- if (dwc->revision < DWC3_REVISION_194A) {
- /* Resume PHYs */
- dwc3_gadget_usb2_phy_suspend(dwc, false);
- dwc3_gadget_usb3_phy_suspend(dwc, false);
- }
-
if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
dwc3_disconnect_gadget(dwc);
@@ -2222,20 +2190,6 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
-static void dwc3_gadget_phy_suspend(struct dwc3 *dwc, u8 speed)
-{
- switch (speed) {
- case USB_SPEED_SUPER:
- dwc3_gadget_usb2_phy_suspend(dwc, true);
- break;
- case USB_SPEED_HIGH:
- case USB_SPEED_FULL:
- case USB_SPEED_LOW:
- dwc3_gadget_usb3_phy_suspend(dwc, true);
- break;
- }
-}
-
static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
@@ -2311,12 +2265,6 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
}
- /* Recent versions support automatic phy suspend and don't need this */
- if (dwc->revision < DWC3_REVISION_194A) {
- /* Suspend unneeded PHY */
- dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed);
- }
-
dep = dwc->eps[0];
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
if (ret) {
@@ -2494,61 +2442,75 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
}
}
-static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
{
- struct dwc3 *dwc = _dwc;
- unsigned long flags;
+ struct dwc3_event_buffer *evt;
irqreturn_t ret = IRQ_NONE;
- int i;
+ int left;
+ u32 reg;
- spin_lock_irqsave(&dwc->lock, flags);
+ evt = dwc->ev_buffs[buf];
+ left = evt->count;
- for (i = 0; i < dwc->num_event_buffers; i++) {
- struct dwc3_event_buffer *evt;
- int left;
+ if (!(evt->flags & DWC3_EVENT_PENDING))
+ return IRQ_NONE;
- evt = dwc->ev_buffs[i];
- left = evt->count;
+ while (left > 0) {
+ union dwc3_event event;
- if (!(evt->flags & DWC3_EVENT_PENDING))
- continue;
+ event.raw = *(u32 *) (evt->buf + evt->lpos);
- while (left > 0) {
- union dwc3_event event;
+ dwc3_process_event_entry(dwc, &event);
- event.raw = *(u32 *) (evt->buf + evt->lpos);
+ /*
+ * FIXME we wrap around correctly to the next entry as
+ * almost all entries are 4 bytes in size. There is one
+ * entry which has 12 bytes which is a regular entry
+ * followed by 8 bytes data. ATM I don't know how
+ * things are organized if we get next to the a
+ * boundary so I worry about that once we try to handle
+ * that.
+ */
+ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+ left -= 4;
- dwc3_process_event_entry(dwc, &event);
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
+ }
- /*
- * FIXME we wrap around correctly to the next entry as
- * almost all entries are 4 bytes in size. There is one
- * entry which has 12 bytes which is a regular entry
- * followed by 8 bytes data. ATM I don't know how
- * things are organized if we get next to the a
- * boundary so I worry about that once we try to handle
- * that.
- */
- evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
- left -= 4;
+ evt->count = 0;
+ evt->flags &= ~DWC3_EVENT_PENDING;
+ ret = IRQ_HANDLED;
- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
- }
+ /* Unmask interrupt */
+ reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
+ reg &= ~DWC3_GEVNTSIZ_INTMASK;
+ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
- evt->count = 0;
- evt->flags &= ~DWC3_EVENT_PENDING;
- ret = IRQ_HANDLED;
- }
+ return ret;
+}
+
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+{
+ struct dwc3 *dwc = _dwc;
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
+ int i;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ for (i = 0; i < dwc->num_event_buffers; i++)
+ ret |= dwc3_process_event_buf(dwc, i);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
}
-static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
{
struct dwc3_event_buffer *evt;
u32 count;
+ u32 reg;
evt = dwc->ev_buffs[buf];
@@ -2560,6 +2522,11 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
evt->count = count;
evt->flags |= DWC3_EVENT_PENDING;
+ /* Mask interrupt */
+ reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
+ reg |= DWC3_GEVNTSIZ_INTMASK;
+ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
+
return IRQ_WAKE_THREAD;
}
@@ -2574,7 +2541,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
for (i = 0; i < dwc->num_event_buffers; i++) {
irqreturn_t status;
- status = dwc3_process_event_buf(dwc, i);
+ status = dwc3_check_event_buf(dwc, i);
if (status == IRQ_WAKE_THREAD)
ret = status;
}
@@ -2592,7 +2559,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
*/
int dwc3_gadget_init(struct dwc3 *dwc)
{
- u32 reg;
int ret;
dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
@@ -2642,16 +2608,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
if (ret)
goto err4;
- reg = dwc3_readl(dwc->regs, DWC3_DCFG);
- reg |= DWC3_DCFG_LPM_CAP;
- dwc3_writel(dwc->regs, DWC3_DCFG, reg);
-
- /* Enable USB2 LPM and automatic phy suspend only on recent versions */
- if (dwc->revision >= DWC3_REVISION_194A) {
- dwc3_gadget_usb2_phy_suspend(dwc, false);
- dwc3_gadget_usb3_phy_suspend(dwc, false);
- }
-
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
if (ret) {
dev_err(dwc->dev, "failed to register udc\n");
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 99e6d724882..febe1aa7b71 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -6,34 +6,14 @@
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __DRIVERS_USB_DWC3_GADGET_H
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 0fa1846eda4..32db328cc76 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -5,34 +5,14 @@
*
* Authors: Felipe Balbi <balbi@ti.com>,
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#include <linux/platform_device.h>
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index a50f76b9d19..d94441c14d8 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -6,34 +6,14 @@
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __DRIVERS_USB_DWC3_IO_H
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
new file mode 100644
index 00000000000..7db34f00b89
--- /dev/null
+++ b/drivers/usb/dwc3/platform_data.h
@@ -0,0 +1,27 @@
+/**
+ * platform_data.h - USB DWC3 Platform Data Support
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+
+struct dwc3_platform_data {
+ enum usb_device_speed maximum_speed;
+ enum usb_dr_mode dr_mode;
+ bool tx_fifo_resize;
+};
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 62f6802f6e0..30e2dd8a1f2 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -144,7 +144,6 @@ config USB_AT91
config USB_LPC32XX
tristate "LPC32XX USB Peripheral Controller"
depends on ARCH_LPC32XX
- depends on USB_PHY
select USB_ISP1301
help
This option selects the USB device controller in the LPC32xx SoC.
@@ -188,11 +187,12 @@ config USB_FSL_USB2
config USB_FUSB300
tristate "Faraday FUSB300 USB Peripheral Controller"
- depends on !PHYS_ADDR_T_64BIT
+ depends on !PHYS_ADDR_T_64BIT && HAS_DMA
help
Faraday usb device controller FUSB300 driver
config USB_FOTG210_UDC
+ depends on HAS_DMA
tristate "Faraday FOTG210 USB Peripheral Controller"
help
Faraday USB2.0 OTG controller which can be configured as
@@ -205,7 +205,6 @@ config USB_FOTG210_UDC
config USB_OMAP
tristate "OMAP USB Device Controller"
depends on ARCH_OMAP1
- depends on USB_PHY
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
help
Many Texas Instruments OMAP processors have flexible full
@@ -245,6 +244,7 @@ config USB_PXA25X_SMALL
config USB_R8A66597
tristate "Renesas R8A66597 USB Peripheral Controller"
+ depends on HAS_DMA
help
R8A66597 is a discrete USB host and peripheral controller chip that
supports both full and high speed USB 2.0 data transfers.
@@ -286,21 +286,6 @@ config USB_S3C_HSOTG
The Samsung S3C64XX USB2.0 high-speed gadget controller
integrated into the S3C64XX series SoC.
-config USB_IMX
- tristate "Freescale i.MX1 USB Peripheral Controller"
- depends on ARCH_MXC
- depends on BROKEN
- help
- Freescale's i.MX1 includes an integrated full speed
- USB 1.1 device controller.
-
- It has Six fixed-function endpoints, as well as endpoint
- zero (for control transfers).
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "imx_udc" and force all
- gadget drivers to also be dynamically linked.
-
config USB_S3C2410
tristate "S3C2410 USB Device Controller"
depends on ARCH_S3C24XX
@@ -328,13 +313,14 @@ config USB_S3C_HSUDC
config USB_MV_UDC
tristate "Marvell USB2.0 Device Controller"
- depends on GENERIC_HARDIRQS
+ depends on GENERIC_HARDIRQS && HAS_DMA
help
Marvell Socs (including PXA and MMP series) include a high speed
USB2.0 OTG controller, which can be configured as high speed or
full speed USB peripheral.
config USB_MV_U3D
+ depends on HAS_DMA
tristate "MARVELL PXA2128 USB 3.0 controller"
help
MARVELL PXA2128 Processor series include a super speed USB3.0 device
@@ -400,7 +386,7 @@ config USB_NET2272
config USB_NET2272_DMA
boolean "Support external DMA controller"
- depends on USB_NET2272
+ depends on USB_NET2272 && HAS_DMA
help
The NET2272 part can optionally support an external DMA
controller, but your board has to have support in the
@@ -570,7 +556,7 @@ config USB_CONFIGFS
specified simply by creating appropriate directories in configfs.
Associating functions with configurations is done by creating
appropriate symbolic links.
- For more information see Documentation/usb/gadget-configfs.txt.
+ For more information see Documentation/usb/gadget_configfs.txt.
config USB_CONFIGFS_SERIAL
boolean "Generic serial bulk in/out"
@@ -639,6 +625,7 @@ config USB_CONFIGFS_RNDIS
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
+ select USB_U_RNDIS
select USB_F_RNDIS
help
Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index bad08e66f36..386db9daf1d 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o
obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o
-obj-$(CONFIG_USB_IMX) += imx_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index f52dcfe8f54..a9a4346c83a 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1122,7 +1122,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
goto finished;
}
if (ep->dma) {
- retval = prep_dma(ep, req, gfp);
+ retval = prep_dma(ep, req, GFP_ATOMIC);
if (retval != 0)
goto finished;
/* write desc pointer to enable DMA */
@@ -1190,7 +1190,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
* for PPB modes, because of chain creation reasons
*/
if (ep->in) {
- retval = prep_dma(ep, req, gfp);
+ retval = prep_dma(ep, req, GFP_ATOMIC);
if (retval != 0)
goto finished;
}
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 073b938f913..4cc4fd6d147 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -870,8 +870,13 @@ static void clk_on(struct at91_udc *udc)
if (udc->clocked)
return;
udc->clocked = 1;
- clk_enable(udc->iclk);
- clk_enable(udc->fclk);
+
+ if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+ clk_set_rate(udc->uclk, 48000000);
+ clk_prepare_enable(udc->uclk);
+ }
+ clk_prepare_enable(udc->iclk);
+ clk_prepare_enable(udc->fclk);
}
static void clk_off(struct at91_udc *udc)
@@ -880,8 +885,10 @@ static void clk_off(struct at91_udc *udc)
return;
udc->clocked = 0;
udc->gadget.speed = USB_SPEED_UNKNOWN;
- clk_disable(udc->fclk);
- clk_disable(udc->iclk);
+ clk_disable_unprepare(udc->fclk);
+ clk_disable_unprepare(udc->iclk);
+ if (IS_ENABLED(CONFIG_COMMON_CLK))
+ clk_disable_unprepare(udc->uclk);
}
/*
@@ -1697,7 +1704,7 @@ static int at91udc_probe(struct platform_device *pdev)
int retval;
struct resource *res;
- if (!dev->platform_data && !pdev->dev.of_node) {
+ if (!dev_get_platdata(dev) && !pdev->dev.of_node) {
/* small (so we copy it) but critical! */
DBG("missing platform_data\n");
return -ENODEV;
@@ -1725,10 +1732,10 @@ static int at91udc_probe(struct platform_device *pdev)
/* init software state */
udc = &controller;
udc->gadget.dev.parent = dev;
- if (pdev->dev.of_node)
+ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
at91udc_of_init(udc, pdev->dev.of_node);
else
- memcpy(&udc->board, dev->platform_data,
+ memcpy(&udc->board, dev_get_platdata(dev),
sizeof(struct at91_udc_data));
udc->pdev = pdev;
udc->enabled = 0;
@@ -1774,20 +1781,24 @@ static int at91udc_probe(struct platform_device *pdev)
/* get interface and function clocks */
udc->iclk = clk_get(dev, "udc_clk");
udc->fclk = clk_get(dev, "udpck");
- if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
+ if (IS_ENABLED(CONFIG_COMMON_CLK))
+ udc->uclk = clk_get(dev, "usb_clk");
+ if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk) ||
+ (IS_ENABLED(CONFIG_COMMON_CLK) && IS_ERR(udc->uclk))) {
DBG("clocks missing\n");
retval = -ENODEV;
- /* NOTE: we "know" here that refcounts on these are NOPs */
goto fail1;
}
/* don't do anything until we have both gadget driver and VBUS */
- clk_enable(udc->iclk);
+ retval = clk_prepare_enable(udc->iclk);
+ if (retval)
+ goto fail1;
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
/* Clear all pending interrupts - UDP may be used by bootloader. */
at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff);
- clk_disable(udc->iclk);
+ clk_disable_unprepare(udc->iclk);
/* request UDC and maybe VBUS irqs */
udc->udp_irq = platform_get_irq(pdev, 0);
@@ -1849,6 +1860,12 @@ fail3:
fail2:
free_irq(udc->udp_irq, udc);
fail1:
+ if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk))
+ clk_put(udc->uclk);
+ if (!IS_ERR(udc->fclk))
+ clk_put(udc->fclk);
+ if (!IS_ERR(udc->iclk))
+ clk_put(udc->iclk);
iounmap(udc->udp_baseaddr);
fail0a:
if (cpu_is_at91rm9200())
@@ -1892,6 +1909,8 @@ static int __exit at91udc_remove(struct platform_device *pdev)
clk_put(udc->iclk);
clk_put(udc->fclk);
+ if (IS_ENABLED(CONFIG_COMMON_CLK))
+ clk_put(udc->uclk);
return 0;
}
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index e647d1c2ada..01752466338 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -126,7 +126,7 @@ struct at91_udc {
unsigned active_suspend:1;
u8 addr;
struct at91_udc_data board;
- struct clk *iclk, *fclk;
+ struct clk *iclk, *fclk, *uclk;
struct platform_device *pdev;
struct proc_dir_entry *pde;
void __iomem *udp_baseaddr;
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 1d9722203ca..2cb52e0438d 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1772,6 +1772,7 @@ out:
static int atmel_usba_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
+ int ret;
struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
unsigned long flags;
@@ -1781,8 +1782,14 @@ static int atmel_usba_start(struct usb_gadget *gadget,
udc->driver = driver;
spin_unlock_irqrestore(&udc->lock, flags);
- clk_enable(udc->pclk);
- clk_enable(udc->hclk);
+ ret = clk_prepare_enable(udc->pclk);
+ if (ret)
+ return ret;
+ ret = clk_prepare_enable(udc->hclk);
+ if (ret) {
+ clk_disable_unprepare(udc->pclk);
+ return ret;
+ }
DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
@@ -1822,8 +1829,8 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
udc->driver = NULL;
- clk_disable(udc->hclk);
- clk_disable(udc->pclk);
+ clk_disable_unprepare(udc->hclk);
+ clk_disable_unprepare(udc->pclk);
DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
@@ -1922,7 +1929,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
static struct usba_ep * usba_udc_pdata(struct platform_device *pdev,
struct usba_udc *udc)
{
- struct usba_platform_data *pdata = pdev->dev.platform_data;
+ struct usba_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct usba_ep *eps;
int i;
@@ -2022,10 +2029,14 @@ static int __init usba_udc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, udc);
/* Make sure we start from a clean slate */
- clk_enable(pclk);
+ ret = clk_prepare_enable(pclk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
+ goto err_clk_enable;
+ }
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
- clk_disable(pclk);
+ clk_disable_unprepare(pclk);
if (pdev->dev.of_node)
udc->usba_ep = atmel_udc_of_init(pdev, udc);
@@ -2081,6 +2092,7 @@ err_add_udc:
free_irq(irq, udc);
err_request_irq:
err_alloc_ep:
+err_clk_enable:
iounmap(udc->fifo);
err_map_fifo:
iounmap(udc->regs);
diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c
index fd24cb4540a..c58fcf1ebe4 100644
--- a/drivers/usb/gadget/bcm63xx_udc.c
+++ b/drivers/usb/gadget/bcm63xx_udc.c
@@ -2313,7 +2313,7 @@ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
static int bcm63xx_udc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct bcm63xx_usbd_platform_data *pd = dev->platform_data;
+ struct bcm63xx_usbd_platform_data *pd = dev_get_platdata(dev);
struct bcm63xx_udc *udc;
struct resource *res;
int rc = -ENOMEM, i, irq;
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 55f4df60f32..d4f0f330575 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1497,17 +1497,15 @@ void composite_disconnect(struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/
-static ssize_t composite_show_suspended(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t suspended_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_gadget *gadget = dev_to_usb_gadget(dev);
struct usb_composite_dev *cdev = get_gadget_data(gadget);
return sprintf(buf, "%d\n", cdev->suspended);
}
-
-static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
+static DEVICE_ATTR_RO(suspended);
static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
{
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 80e7f75a56c..8f0d6141e5e 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -859,8 +859,10 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
list_for_each_entry_safe(f, tmp, &cfg->func_list, list) {
list_del(&f->list);
ret = usb_add_function(c, f);
- if (ret)
+ if (ret) {
+ list_add(&f->list, &cfg->func_list);
goto err_purge_funcs;
+ }
}
usb_ep_autoconfig_reset(cdev->gadget);
}
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index c588e8e486e..06ecd08fd57 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -868,7 +868,7 @@ static const struct usb_gadget_ops dummy_ops = {
/*-------------------------------------------------------------------------*/
/* "function" sysfs attribute */
-static ssize_t show_function(struct device *dev, struct device_attribute *attr,
+static ssize_t function_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct dummy *dum = gadget_dev_to_dummy(dev);
@@ -877,7 +877,7 @@ static ssize_t show_function(struct device *dev, struct device_attribute *attr,
return 0;
return scnprintf(buf, PAGE_SIZE, "%s\n", dum->driver->function);
}
-static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
+static DEVICE_ATTR_RO(function);
/*-------------------------------------------------------------------------*/
@@ -2290,7 +2290,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)
urb->actual_length, urb->transfer_buffer_length);
}
-static ssize_t show_urbs(struct device *dev, struct device_attribute *attr,
+static ssize_t urbs_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -2311,7 +2311,7 @@ static ssize_t show_urbs(struct device *dev, struct device_attribute *attr,
return size;
}
-static DEVICE_ATTR(urbs, S_IRUGO, show_urbs, NULL);
+static DEVICE_ATTR_RO(urbs);
static int dummy_start_ss(struct dummy_hcd *dum_hcd)
{
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index f48712ffe26..c1c113ef950 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -449,14 +449,20 @@ fail:
static int __exit eth_unbind(struct usb_composite_dev *cdev)
{
- if (has_rndis())
+ if (has_rndis()) {
+ usb_put_function(f_rndis);
usb_put_function_instance(fi_rndis);
- if (use_eem)
+ }
+ if (use_eem) {
+ usb_put_function(f_eem);
usb_put_function_instance(fi_eem);
- else if (can_support_ecm(cdev->gadget))
+ } else if (can_support_ecm(cdev->gadget)) {
+ usb_put_function(f_ecm);
usb_put_function_instance(fi_ecm);
- else
+ } else {
+ usb_put_function(f_geth);
usb_put_function_instance(fi_geth);
+ }
return 0;
}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 4b7e33e5d9c..ab1065afbbd 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -285,6 +285,7 @@ static struct usb_string acm_string_defs[] = {
[ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
[ACM_DATA_IDX].s = "CDC ACM Data",
[ACM_IAD_IDX ].s = "CDC Serial",
+ { } /* end of list */
};
static struct usb_gadget_strings acm_string_table = {
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 5d3561ea1c1..edab45da374 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -959,8 +959,11 @@ static struct usb_function_instance *ecm_alloc_inst(void)
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = ecm_free_inst;
opts->net = gether_setup_default();
- if (IS_ERR(opts->net))
- return ERR_PTR(PTR_ERR(opts->net));
+ if (IS_ERR(opts->net)) {
+ struct net_device *net = opts->net;
+ kfree(opts);
+ return ERR_CAST(net);
+ }
config_group_init_type_name(&opts->func_inst.group, "", &ecm_func_type);
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index 90ee8022e8d..d00392d879d 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -593,8 +593,11 @@ static struct usb_function_instance *eem_alloc_inst(void)
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = eem_free_inst;
opts->net = gether_setup_default();
- if (IS_ERR(opts->net))
- return ERR_CAST(opts->net);
+ if (IS_ERR(opts->net)) {
+ struct net_device *net = opts->net;
+ kfree(opts);
+ return ERR_CAST(net);
+ }
config_group_init_type_name(&opts->func_inst.group, "", &eem_func_type);
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index f394f295d63..1a66c5baa0d 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1417,8 +1417,8 @@ static void functionfs_unbind(struct ffs_data *ffs)
usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
ffs->ep0req = NULL;
ffs->gadget = NULL;
- ffs_data_put(ffs);
clear_bit(FFS_FL_BOUND, &ffs->flags);
+ ffs_data_put(ffs);
}
}
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 56f1fd1cba2..313b835eedf 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2578,14 +2578,12 @@ static int fsg_main_thread(void *common_)
/*************************** DEVICE ATTRIBUTES ***************************/
-static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
-static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
-static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
+static DEVICE_ATTR_RW(ro);
+static DEVICE_ATTR_RW(nofua);
+static DEVICE_ATTR_RW(file);
-static struct device_attribute dev_attr_ro_cdrom =
- __ATTR(ro, 0444, fsg_show_ro, NULL);
-static struct device_attribute dev_attr_file_nonremovable =
- __ATTR(file, 0444, fsg_show_file, NULL);
+static struct device_attribute dev_attr_ro_cdrom = __ATTR_RO(ro);
+static struct device_attribute dev_attr_file_nonremovable = __ATTR_RO(file);
/****************************** FSG COMMON ******************************/
@@ -3043,12 +3041,12 @@ fsg_config_from_params(struct fsg_config *cfg,
lun->filename =
params->file_count > i && params->file[i][0]
? params->file[i]
- : 0;
+ : NULL;
}
/* Let MSF use defaults */
- cfg->vendor_name = 0;
- cfg->product_name = 0;
+ cfg->vendor_name = NULL;
+ cfg->product_name = NULL;
cfg->ops = NULL;
cfg->private_data = NULL;
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index 952177f7eb9..1c28fe13328 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -1350,8 +1350,11 @@ static struct usb_function_instance *ncm_alloc_inst(void)
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = ncm_free_inst;
opts->net = gether_setup_default();
- if (IS_ERR(opts->net))
- return ERR_PTR(PTR_ERR(opts->net));
+ if (IS_ERR(opts->net)) {
+ struct net_device *net = opts->net;
+ kfree(opts);
+ return ERR_CAST(net);
+ }
config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type);
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 7944fb0efe3..eb3aa817a66 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -488,7 +488,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_ep *ep;
int status, i;
-#ifndef USBF_PHONET_INCLUDED
struct f_phonet_opts *phonet_opts;
phonet_opts = container_of(f->fi, struct f_phonet_opts, func_inst);
@@ -507,7 +506,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
return status;
phonet_opts->bound = true;
}
-#endif
/* Reserve interface IDs */
status = usb_interface_id(c, f);
@@ -656,8 +654,11 @@ static struct usb_function_instance *phonet_alloc_inst(void)
opts->func_inst.free_func_inst = phonet_free_inst;
opts->net = gphonet_setup_default();
- if (IS_ERR(opts->net))
- return ERR_PTR(PTR_ERR(opts->net));
+ if (IS_ERR(opts->net)) {
+ struct net_device *net = opts->net;
+ kfree(opts);
+ return ERR_CAST(net);
+ }
config_group_init_type_name(&opts->func_inst.group, "",
&phonet_func_type);
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 191df35ae69..717ed7f9563 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -963,8 +963,11 @@ static struct usb_function_instance *rndis_alloc_inst(void)
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = rndis_free_inst;
opts->net = gether_setup_default();
- if (IS_ERR(opts->net))
- return ERR_CAST(opts->net);
+ if (IS_ERR(opts->net)) {
+ struct net_device *net = opts->net;
+ kfree(opts);
+ return ERR_CAST(net);
+ }
config_group_init_type_name(&opts->func_inst.group, "",
&rndis_func_type);
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index 5601e1d96c4..7c8674fa7e8 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -505,8 +505,11 @@ static struct usb_function_instance *geth_alloc_inst(void)
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = geth_free_inst;
opts->net = gether_setup_default();
- if (IS_ERR(opts->net))
- return ERR_CAST(opts->net);
+ if (IS_ERR(opts->net)) {
+ struct net_device *net = opts->net;
+ kfree(opts);
+ return ERR_CAST(net);
+ }
config_group_init_type_name(&opts->func_inst.group, "",
&gether_func_type);
diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c
index fa8ea4ea00c..2b4c82d84bf 100644
--- a/drivers/usb/gadget/f_uac1.c
+++ b/drivers/usb/gadget/f_uac1.c
@@ -695,7 +695,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd)
}
/* Todo: add more control selecotor dynamically */
-int __init control_selector_init(struct f_audio *audio)
+static int __init control_selector_init(struct f_audio *audio)
{
INIT_LIST_HEAD(&audio->cs);
list_add(&feature_unit.list, &audio->cs);
@@ -719,7 +719,7 @@ int __init control_selector_init(struct f_audio *audio)
*
* Returns zero on success, else negative errno.
*/
-int __init audio_bind_config(struct usb_configuration *c)
+static int __init audio_bind_config(struct usb_configuration *c)
{
struct f_audio *audio;
int status;
diff --git a/drivers/usb/gadget/fotg210-udc.c b/drivers/usb/gadget/fotg210-udc.c
index cce5535b1dc..32db2eee2d8 100644
--- a/drivers/usb/gadget/fotg210-udc.c
+++ b/drivers/usb/gadget/fotg210-udc.c
@@ -1074,9 +1074,9 @@ static struct usb_gadget_ops fotg210_gadget_ops = {
.udc_stop = fotg210_udc_stop,
};
-static int __exit fotg210_udc_remove(struct platform_device *pdev)
+static int fotg210_udc_remove(struct platform_device *pdev)
{
- struct fotg210_udc *fotg210 = dev_get_drvdata(&pdev->dev);
+ struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
usb_del_gadget_udc(&fotg210->gadget);
iounmap(fotg210->reg);
@@ -1088,7 +1088,7 @@ static int __exit fotg210_udc_remove(struct platform_device *pdev)
return 0;
}
-static int __init fotg210_udc_probe(struct platform_device *pdev)
+static int fotg210_udc_probe(struct platform_device *pdev)
{
struct resource *res, *ires;
struct fotg210_udc *fotg210 = NULL;
@@ -1134,7 +1134,7 @@ static int __init fotg210_udc_probe(struct platform_device *pdev)
spin_lock_init(&fotg210->lock);
- dev_set_drvdata(&pdev->dev, fotg210);
+ platform_set_drvdata(pdev, fotg210);
fotg210->gadget.ops = &fotg210_gadget_ops;
diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c
index d3bd7b095ba..9b140fc4d3b 100644
--- a/drivers/usb/gadget/fsl_mxc_udc.c
+++ b/drivers/usb/gadget/fsl_mxc_udc.c
@@ -33,7 +33,7 @@ int fsl_udc_clk_init(struct platform_device *pdev)
unsigned long freq;
int ret;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
mxc_ipg_clk = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(mxc_ipg_clk)) {
@@ -80,7 +80,7 @@ eclkrate:
int fsl_udc_clk_finalize(struct platform_device *pdev)
{
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+ struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
int ret = 0;
/* workaround ENGcm09152 for i.MX35 */
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index a766a4ca1cb..36ac7cfba91 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -2248,7 +2248,7 @@ static int __init struct_udc_setup(struct fsl_udc *udc,
struct fsl_usb2_platform_data *pdata;
size_t size;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
udc->phy_mode = pdata->phy_mode;
udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL);
@@ -2343,7 +2343,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
return -ENOMEM;
}
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
udc_controller->pdata = pdata;
spin_lock_init(&udc_controller->lock);
udc_controller->stopped = 1;
@@ -2524,7 +2524,7 @@ err_kfree:
static int __exit fsl_udc_remove(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+ struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
DECLARE_COMPLETION(done);
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index c83f3e16532..f1dd6daabe2 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -557,7 +557,7 @@ static void fusb300_set_cxdone(struct fusb300 *fusb300)
}
/* read data from cx fifo */
-void fusb300_rdcxf(struct fusb300 *fusb300,
+static void fusb300_rdcxf(struct fusb300 *fusb300,
u8 *buffer, u32 length)
{
int i = 0;
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 52dd6cc6c0a..c64deb9e3d6 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -772,7 +772,7 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
} /* else pio or dma irq handler advances the queue. */
- if (likely(req != 0))
+ if (likely(req != NULL))
list_add_tail(&req->queue, &ep->queue);
if (likely(!list_empty(&ep->queue))
diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c
index c36260ea8bf..778613eb37a 100644
--- a/drivers/usb/gadget/hid.c
+++ b/drivers/usb/gadget/hid.c
@@ -185,7 +185,7 @@ static int __exit hid_unbind(struct usb_composite_dev *cdev)
static int __init hidg_plat_driver_probe(struct platform_device *pdev)
{
- struct hidg_func_descriptor *func = pdev->dev.platform_data;
+ struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev);
struct hidg_func_node *entry;
if (!func) {
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
deleted file mode 100644
index 9b2d24e4c95..00000000000
--- a/drivers/usb/gadget/imx_udc.c
+++ /dev/null
@@ -1,1544 +0,0 @@
-/*
- * driver/usb/gadget/imx_udc.c
- *
- * Copyright (C) 2005 Mike Lee <eemike@gmail.com>
- * Copyright (C) 2008 Darius Augulis <augulis.darius@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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/prefetch.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-#include <linux/platform_data/usb-imx_udc.h>
-#include <mach/hardware.h>
-
-#include "imx_udc.h"
-
-static const char driver_name[] = "imx_udc";
-static const char ep0name[] = "ep0";
-
-void ep0_chg_stat(const char *label, struct imx_udc_struct *imx_usb,
- enum ep0_state stat);
-
-/*******************************************************************************
- * IMX UDC hardware related functions
- *******************************************************************************
- */
-
-void imx_udc_enable(struct imx_udc_struct *imx_usb)
-{
- int temp = __raw_readl(imx_usb->base + USB_CTRL);
- __raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA,
- imx_usb->base + USB_CTRL);
- imx_usb->gadget.speed = USB_SPEED_FULL;
-}
-
-void imx_udc_disable(struct imx_udc_struct *imx_usb)
-{
- int temp = __raw_readl(imx_usb->base + USB_CTRL);
-
- __raw_writel(temp & ~(CTRL_FE_ENA | CTRL_AFE_ENA),
- imx_usb->base + USB_CTRL);
-
- ep0_chg_stat(__func__, imx_usb, EP0_IDLE);
- imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
-}
-
-void imx_udc_reset(struct imx_udc_struct *imx_usb)
-{
- int temp = __raw_readl(imx_usb->base + USB_ENAB);
-
- /* set RST bit */
- __raw_writel(temp | ENAB_RST, imx_usb->base + USB_ENAB);
-
- /* wait RST bit to clear */
- do {} while (__raw_readl(imx_usb->base + USB_ENAB) & ENAB_RST);
-
- /* wait CFG bit to assert */
- do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG));
-
- /* udc module is now ready */
-}
-
-void imx_udc_config(struct imx_udc_struct *imx_usb)
-{
- u8 ep_conf[5];
- u8 i, j, cfg;
- struct imx_ep_struct *imx_ep;
-
- /* wait CFG bit to assert */
- do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG));
-
- /* Download the endpoint buffer for endpoint 0. */
- for (j = 0; j < 5; j++) {
- i = (j == 2 ? imx_usb->imx_ep[0].fifosize : 0x00);
- __raw_writeb(i, imx_usb->base + USB_DDAT);
- do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY);
- }
-
- /* Download the endpoint buffers for endpoints 1-5.
- * We specify two configurations, one interface
- */
- for (cfg = 1; cfg < 3; cfg++) {
- for (i = 1; i < IMX_USB_NB_EP; i++) {
- imx_ep = &imx_usb->imx_ep[i];
- /* EP no | Config no */
- ep_conf[0] = (i << 4) | (cfg << 2);
- /* Type | Direction */
- ep_conf[1] = (imx_ep->bmAttributes << 3) |
- (EP_DIR(imx_ep) << 2);
- /* Max packet size */
- ep_conf[2] = imx_ep->fifosize;
- /* TRXTYP */
- ep_conf[3] = 0xC0;
- /* FIFO no */
- ep_conf[4] = i;
-
- D_INI(imx_usb->dev,
- "<%s> ep%d_conf[%d]:"
- "[%02x-%02x-%02x-%02x-%02x]\n",
- __func__, i, cfg,
- ep_conf[0], ep_conf[1], ep_conf[2],
- ep_conf[3], ep_conf[4]);
-
- for (j = 0; j < 5; j++) {
- __raw_writeb(ep_conf[j],
- imx_usb->base + USB_DDAT);
- do {} while (__raw_readl(imx_usb->base
- + USB_DADR)
- & DADR_BSY);
- }
- }
- }
-
- /* wait CFG bit to clear */
- do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG);
-}
-
-void imx_udc_init_irq(struct imx_udc_struct *imx_usb)
-{
- int i;
-
- /* Mask and clear all irqs */
- __raw_writel(0xFFFFFFFF, imx_usb->base + USB_MASK);
- __raw_writel(0xFFFFFFFF, imx_usb->base + USB_INTR);
- for (i = 0; i < IMX_USB_NB_EP; i++) {
- __raw_writel(0x1FF, imx_usb->base + USB_EP_MASK(i));
- __raw_writel(0x1FF, imx_usb->base + USB_EP_INTR(i));
- }
-
- /* Enable USB irqs */
- __raw_writel(INTR_MSOF | INTR_FRAME_MATCH, imx_usb->base + USB_MASK);
-
- /* Enable EP0 irqs */
- __raw_writel(0x1FF & ~(EPINTR_DEVREQ | EPINTR_MDEVREQ | EPINTR_EOT
- | EPINTR_EOF | EPINTR_FIFO_EMPTY | EPINTR_FIFO_FULL),
- imx_usb->base + USB_EP_MASK(0));
-}
-
-void imx_udc_init_ep(struct imx_udc_struct *imx_usb)
-{
- int i, max, temp;
- struct imx_ep_struct *imx_ep;
- for (i = 0; i < IMX_USB_NB_EP; i++) {
- imx_ep = &imx_usb->imx_ep[i];
- switch (imx_ep->fifosize) {
- case 8:
- max = 0;
- break;
- case 16:
- max = 1;
- break;
- case 32:
- max = 2;
- break;
- case 64:
- max = 3;
- break;
- default:
- max = 1;
- break;
- }
- temp = (EP_DIR(imx_ep) << 7) | (max << 5)
- | (imx_ep->bmAttributes << 3);
- __raw_writel(temp, imx_usb->base + USB_EP_STAT(i));
- __raw_writel(temp | EPSTAT_FLUSH,
- imx_usb->base + USB_EP_STAT(i));
- D_INI(imx_usb->dev, "<%s> ep%d_stat %08x\n", __func__, i,
- __raw_readl(imx_usb->base + USB_EP_STAT(i)));
- }
-}
-
-void imx_udc_init_fifo(struct imx_udc_struct *imx_usb)
-{
- int i, temp;
- struct imx_ep_struct *imx_ep;
- for (i = 0; i < IMX_USB_NB_EP; i++) {
- imx_ep = &imx_usb->imx_ep[i];
-
- /* Fifo control */
- temp = EP_DIR(imx_ep) ? 0x0B000000 : 0x0F000000;
- __raw_writel(temp, imx_usb->base + USB_EP_FCTRL(i));
- D_INI(imx_usb->dev, "<%s> ep%d_fctrl %08x\n", __func__, i,
- __raw_readl(imx_usb->base + USB_EP_FCTRL(i)));
-
- /* Fifo alarm */
- temp = (i ? imx_ep->fifosize / 2 : 0);
- __raw_writel(temp, imx_usb->base + USB_EP_FALRM(i));
- D_INI(imx_usb->dev, "<%s> ep%d_falrm %08x\n", __func__, i,
- __raw_readl(imx_usb->base + USB_EP_FALRM(i)));
- }
-}
-
-static void imx_udc_init(struct imx_udc_struct *imx_usb)
-{
- /* Reset UDC */
- imx_udc_reset(imx_usb);
-
- /* Download config to enpoint buffer */
- imx_udc_config(imx_usb);
-
- /* Setup interrups */
- imx_udc_init_irq(imx_usb);
-
- /* Setup endpoints */
- imx_udc_init_ep(imx_usb);
-
- /* Setup fifos */
- imx_udc_init_fifo(imx_usb);
-}
-
-void imx_ep_irq_enable(struct imx_ep_struct *imx_ep)
-{
-
- int i = EP_NO(imx_ep);
-
- __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i));
- __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i));
- __raw_writel(0x1FF & ~(EPINTR_EOT | EPINTR_EOF),
- imx_ep->imx_usb->base + USB_EP_MASK(i));
-}
-
-void imx_ep_irq_disable(struct imx_ep_struct *imx_ep)
-{
-
- int i = EP_NO(imx_ep);
-
- __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i));
- __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i));
-}
-
-int imx_ep_empty(struct imx_ep_struct *imx_ep)
-{
- struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-
- return __raw_readl(imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep)))
- & FSTAT_EMPTY;
-}
-
-unsigned imx_fifo_bcount(struct imx_ep_struct *imx_ep)
-{
- struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-
- return (__raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)))
- & EPSTAT_BCOUNT) >> 16;
-}
-
-void imx_flush(struct imx_ep_struct *imx_ep)
-{
- struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-
- int temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
- __raw_writel(temp | EPSTAT_FLUSH,
- imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
-}
-
-void imx_ep_stall(struct imx_ep_struct *imx_ep)
-{
- struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
- int temp, i;
-
- D_ERR(imx_usb->dev,
- "<%s> Forced stall on %s\n", __func__, imx_ep->ep.name);
-
- imx_flush(imx_ep);
-
- /* Special care for ep0 */
- if (!EP_NO(imx_ep)) {
- temp = __raw_readl(imx_usb->base + USB_CTRL);
- __raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR,
- imx_usb->base + USB_CTRL);
- do { } while (__raw_readl(imx_usb->base + USB_CTRL)
- & CTRL_CMDOVER);
- temp = __raw_readl(imx_usb->base + USB_CTRL);
- __raw_writel(temp & ~CTRL_CMDERROR, imx_usb->base + USB_CTRL);
- }
- else {
- temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
- __raw_writel(temp | EPSTAT_STALL,
- imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
-
- for (i = 0; i < 100; i ++) {
- temp = __raw_readl(imx_usb->base
- + USB_EP_STAT(EP_NO(imx_ep)));
- if (!(temp & EPSTAT_STALL))
- break;
- udelay(20);
- }
- if (i == 100)
- D_ERR(imx_usb->dev, "<%s> Non finished stall on %s\n",
- __func__, imx_ep->ep.name);
- }
-}
-
-static int imx_udc_get_frame(struct usb_gadget *_gadget)
-{
- struct imx_udc_struct *imx_usb = container_of(_gadget,
- struct imx_udc_struct, gadget);
-
- return __raw_readl(imx_usb->base + USB_FRAME) & 0x7FF;
-}
-
-static int imx_udc_wakeup(struct usb_gadget *_gadget)
-{
- return 0;
-}
-
-/*******************************************************************************
- * USB request control functions
- *******************************************************************************
- */
-
-static void ep_add_request(struct imx_ep_struct *imx_ep,
- struct imx_request *req)
-{
- if (unlikely(!req))
- return;
-
- req->in_use = 1;
- list_add_tail(&req->queue, &imx_ep->queue);
-}
-
-static void ep_del_request(struct imx_ep_struct *imx_ep,
- struct imx_request *req)
-{
- if (unlikely(!req))
- return;
-
- list_del_init(&req->queue);
- req->in_use = 0;
-}
-
-static void done(struct imx_ep_struct *imx_ep,
- struct imx_request *req, int status)
-{
- ep_del_request(imx_ep, req);
-
- if (likely(req->req.status == -EINPROGRESS))
- req->req.status = status;
- else
- status = req->req.status;
-
- if (status && status != -ESHUTDOWN)
- D_ERR(imx_ep->imx_usb->dev,
- "<%s> complete %s req %p stat %d len %u/%u\n", __func__,
- imx_ep->ep.name, &req->req, status,
- req->req.actual, req->req.length);
-
- req->req.complete(&imx_ep->ep, &req->req);
-}
-
-static void nuke(struct imx_ep_struct *imx_ep, int status)
-{
- struct imx_request *req;
-
- while (!list_empty(&imx_ep->queue)) {
- req = list_entry(imx_ep->queue.next, struct imx_request, queue);
- done(imx_ep, req, status);
- }
-}
-
-/*******************************************************************************
- * Data tansfer over USB functions
- *******************************************************************************
- */
-static int read_packet(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
- u8 *buf;
- int bytes_ep, bufferspace, count, i;
-
- bytes_ep = imx_fifo_bcount(imx_ep);
- bufferspace = req->req.length - req->req.actual;
-
- buf = req->req.buf + req->req.actual;
- prefetchw(buf);
-
- if (unlikely(imx_ep_empty(imx_ep)))
- count = 0; /* zlp */
- else
- count = min(bytes_ep, bufferspace);
-
- for (i = count; i > 0; i--)
- *buf++ = __raw_readb(imx_ep->imx_usb->base
- + USB_EP_FDAT0(EP_NO(imx_ep)));
- req->req.actual += count;
-
- return count;
-}
-
-static int write_packet(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
- u8 *buf;
- int length, count, temp;
-
- if (unlikely(__raw_readl(imx_ep->imx_usb->base +
- USB_EP_STAT(EP_NO(imx_ep))) & EPSTAT_ZLPS)) {
- D_TRX(imx_ep->imx_usb->dev, "<%s> zlp still queued in EP %s\n",
- __func__, imx_ep->ep.name);
- return -1;
- }
-
- buf = req->req.buf + req->req.actual;
- prefetch(buf);
-
- length = min(req->req.length - req->req.actual, (u32)imx_ep->fifosize);
-
- if (imx_fifo_bcount(imx_ep) + length > imx_ep->fifosize) {
- D_TRX(imx_ep->imx_usb->dev, "<%s> packet overfill %s fifo\n",
- __func__, imx_ep->ep.name);
- return -1;
- }
-
- req->req.actual += length;
- count = length;
-
- if (!count && req->req.zero) { /* zlp */
- temp = __raw_readl(imx_ep->imx_usb->base
- + USB_EP_STAT(EP_NO(imx_ep)));
- __raw_writel(temp | EPSTAT_ZLPS, imx_ep->imx_usb->base
- + USB_EP_STAT(EP_NO(imx_ep)));
- D_TRX(imx_ep->imx_usb->dev, "<%s> zero packet\n", __func__);
- return 0;
- }
-
- while (count--) {
- if (count == 0) { /* last byte */
- temp = __raw_readl(imx_ep->imx_usb->base
- + USB_EP_FCTRL(EP_NO(imx_ep)));
- __raw_writel(temp | FCTRL_WFR, imx_ep->imx_usb->base
- + USB_EP_FCTRL(EP_NO(imx_ep)));
- }
- __raw_writeb(*buf++,
- imx_ep->imx_usb->base + USB_EP_FDAT0(EP_NO(imx_ep)));
- }
-
- return length;
-}
-
-static int read_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
- int bytes = 0,
- count,
- completed = 0;
-
- while (__raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep)))
- & FSTAT_FR) {
- count = read_packet(imx_ep, req);
- bytes += count;
-
- completed = (count != imx_ep->fifosize);
- if (completed || req->req.actual == req->req.length) {
- completed = 1;
- break;
- }
- }
-
- if (completed || !req->req.length) {
- done(imx_ep, req, 0);
- D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n",
- __func__, imx_ep->ep.name, req,
- completed ? "completed" : "not completed");
- if (!EP_NO(imx_ep))
- ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE);
- }
-
- D_TRX(imx_ep->imx_usb->dev, "<%s> bytes read: %d\n", __func__, bytes);
-
- return completed;
-}
-
-static int write_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
- int bytes = 0,
- count,
- completed = 0;
-
- while (!completed) {
- count = write_packet(imx_ep, req);
- if (count < 0)
- break; /* busy */
- bytes += count;
-
- /* last packet "must be" short (or a zlp) */
- completed = (count != imx_ep->fifosize);
-
- if (unlikely(completed)) {
- done(imx_ep, req, 0);
- D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n",
- __func__, imx_ep->ep.name, req,
- completed ? "completed" : "not completed");
- if (!EP_NO(imx_ep))
- ep0_chg_stat(__func__,
- imx_ep->imx_usb, EP0_IDLE);
- }
- }
-
- D_TRX(imx_ep->imx_usb->dev, "<%s> bytes sent: %d\n", __func__, bytes);
-
- return completed;
-}
-
-/*******************************************************************************
- * Endpoint handlers
- *******************************************************************************
- */
-static int handle_ep(struct imx_ep_struct *imx_ep)
-{
- struct imx_request *req;
- int completed = 0;
-
- do {
- if (!list_empty(&imx_ep->queue))
- req = list_entry(imx_ep->queue.next,
- struct imx_request, queue);
- else {
- D_REQ(imx_ep->imx_usb->dev, "<%s> no request on %s\n",
- __func__, imx_ep->ep.name);
- return 0;
- }
-
- if (EP_DIR(imx_ep)) /* to host */
- completed = write_fifo(imx_ep, req);
- else /* to device */
- completed = read_fifo(imx_ep, req);
-
- dump_ep_stat(__func__, imx_ep);
-
- } while (completed);
-
- return 0;
-}
-
-static int handle_ep0(struct imx_ep_struct *imx_ep)
-{
- struct imx_request *req = NULL;
- int ret = 0;
-
- if (!list_empty(&imx_ep->queue)) {
- req = list_entry(imx_ep->queue.next, struct imx_request, queue);
-
- switch (imx_ep->imx_usb->ep0state) {
-
- case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR */
- write_fifo(imx_ep, req);
- break;
- case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR */
- read_fifo(imx_ep, req);
- break;
- default:
- D_EP0(imx_ep->imx_usb->dev,
- "<%s> ep0 i/o, odd state %d\n",
- __func__, imx_ep->imx_usb->ep0state);
- ep_del_request(imx_ep, req);
- ret = -EL2HLT;
- break;
- }
- }
-
- else
- D_ERR(imx_ep->imx_usb->dev, "<%s> no request on %s\n",
- __func__, imx_ep->ep.name);
-
- return ret;
-}
-
-static void handle_ep0_devreq(struct imx_udc_struct *imx_usb)
-{
- struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0];
- union {
- struct usb_ctrlrequest r;
- u8 raw[8];
- u32 word[2];
- } u;
- int temp, i;
-
- nuke(imx_ep, -EPROTO);
-
- /* read SETUP packet */
- for (i = 0; i < 2; i++) {
- if (imx_ep_empty(imx_ep)) {
- D_ERR(imx_usb->dev,
- "<%s> no setup packet received\n", __func__);
- goto stall;
- }
- u.word[i] = __raw_readl(imx_usb->base
- + USB_EP_FDAT(EP_NO(imx_ep)));
- }
-
- temp = imx_ep_empty(imx_ep);
- while (!imx_ep_empty(imx_ep)) {
- i = __raw_readl(imx_usb->base + USB_EP_FDAT(EP_NO(imx_ep)));
- D_ERR(imx_usb->dev,
- "<%s> wrong to have extra bytes for setup : 0x%08x\n",
- __func__, i);
- }
- if (!temp)
- goto stall;
-
- le16_to_cpus(&u.r.wValue);
- le16_to_cpus(&u.r.wIndex);
- le16_to_cpus(&u.r.wLength);
-
- D_REQ(imx_usb->dev, "<%s> SETUP %02x.%02x v%04x i%04x l%04x\n",
- __func__, u.r.bRequestType, u.r.bRequest,
- u.r.wValue, u.r.wIndex, u.r.wLength);
-
- if (imx_usb->set_config) {
- /* NACK the host by using CMDOVER */
- temp = __raw_readl(imx_usb->base + USB_CTRL);
- __raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL);
-
- D_ERR(imx_usb->dev,
- "<%s> set config req is pending, NACK the host\n",
- __func__);
- return;
- }
-
- if (u.r.bRequestType & USB_DIR_IN)
- ep0_chg_stat(__func__, imx_usb, EP0_IN_DATA_PHASE);
- else
- ep0_chg_stat(__func__, imx_usb, EP0_OUT_DATA_PHASE);
-
- i = imx_usb->driver->setup(&imx_usb->gadget, &u.r);
- if (i < 0) {
- D_ERR(imx_usb->dev, "<%s> device setup error %d\n",
- __func__, i);
- goto stall;
- }
-
- return;
-stall:
- D_ERR(imx_usb->dev, "<%s> protocol STALL\n", __func__);
- imx_ep_stall(imx_ep);
- ep0_chg_stat(__func__, imx_usb, EP0_STALL);
- return;
-}
-
-/*******************************************************************************
- * USB gadget callback functions
- *******************************************************************************
- */
-
-static int imx_ep_enable(struct usb_ep *usb_ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct imx_ep_struct *imx_ep = container_of(usb_ep,
- struct imx_ep_struct, ep);
- struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
- unsigned long flags;
-
- if (!usb_ep
- || !desc
- || !EP_NO(imx_ep)
- || desc->bDescriptorType != USB_DT_ENDPOINT
- || imx_ep->bEndpointAddress != desc->bEndpointAddress) {
- D_ERR(imx_usb->dev,
- "<%s> bad ep or descriptor\n", __func__);
- return -EINVAL;
- }
-
- if (imx_ep->bmAttributes != desc->bmAttributes) {
- D_ERR(imx_usb->dev,
- "<%s> %s type mismatch\n", __func__, usb_ep->name);
- return -EINVAL;
- }
-
- if (imx_ep->fifosize < usb_endpoint_maxp(desc)) {
- D_ERR(imx_usb->dev,
- "<%s> bad %s maxpacket\n", __func__, usb_ep->name);
- return -ERANGE;
- }
-
- if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) {
- D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__);
- return -ESHUTDOWN;
- }
-
- local_irq_save(flags);
-
- imx_ep->stopped = 0;
- imx_flush(imx_ep);
- imx_ep_irq_enable(imx_ep);
-
- local_irq_restore(flags);
-
- D_EPX(imx_usb->dev, "<%s> ENABLED %s\n", __func__, usb_ep->name);
- return 0;
-}
-
-static int imx_ep_disable(struct usb_ep *usb_ep)
-{
- struct imx_ep_struct *imx_ep = container_of(usb_ep,
- struct imx_ep_struct, ep);
- unsigned long flags;
-
- if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) {
- D_ERR(imx_ep->imx_usb->dev, "<%s> %s can not be disabled\n",
- __func__, usb_ep ? imx_ep->ep.name : NULL);
- return -EINVAL;
- }
-
- local_irq_save(flags);
-
- imx_ep->stopped = 1;
- nuke(imx_ep, -ESHUTDOWN);
- imx_flush(imx_ep);
- imx_ep_irq_disable(imx_ep);
-
- local_irq_restore(flags);
-
- D_EPX(imx_ep->imx_usb->dev,
- "<%s> DISABLED %s\n", __func__, usb_ep->name);
- return 0;
-}
-
-static struct usb_request *imx_ep_alloc_request
- (struct usb_ep *usb_ep, gfp_t gfp_flags)
-{
- struct imx_request *req;
-
- if (!usb_ep)
- return NULL;
-
- req = kzalloc(sizeof *req, gfp_flags);
- if (!req)
- return NULL;
-
- INIT_LIST_HEAD(&req->queue);
- req->in_use = 0;
-
- return &req->req;
-}
-
-static void imx_ep_free_request
- (struct usb_ep *usb_ep, struct usb_request *usb_req)
-{
- struct imx_request *req;
-
- req = container_of(usb_req, struct imx_request, req);
- WARN_ON(!list_empty(&req->queue));
- kfree(req);
-}
-
-static int imx_ep_queue
- (struct usb_ep *usb_ep, struct usb_request *usb_req, gfp_t gfp_flags)
-{
- struct imx_ep_struct *imx_ep;
- struct imx_udc_struct *imx_usb;
- struct imx_request *req;
- unsigned long flags;
- int ret = 0;
-
- imx_ep = container_of(usb_ep, struct imx_ep_struct, ep);
- imx_usb = imx_ep->imx_usb;
- req = container_of(usb_req, struct imx_request, req);
-
- /*
- Special care on IMX udc.
- Ignore enqueue when after set configuration from the
- host. This assume all gadget drivers reply set
- configuration with the next ep0 req enqueue.
- */
- if (imx_usb->set_config && !EP_NO(imx_ep)) {
- imx_usb->set_config = 0;
- D_ERR(imx_usb->dev,
- "<%s> gadget reply set config\n", __func__);
- return 0;
- }
-
- if (unlikely(!usb_req || !req || !usb_req->complete || !usb_req->buf)) {
- D_ERR(imx_usb->dev, "<%s> bad params\n", __func__);
- return -EINVAL;
- }
-
- if (unlikely(!usb_ep || !imx_ep)) {
- D_ERR(imx_usb->dev, "<%s> bad ep\n", __func__);
- return -EINVAL;
- }
-
- if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) {
- D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__);
- return -ESHUTDOWN;
- }
-
- /* Debug */
- D_REQ(imx_usb->dev, "<%s> ep%d %s request for [%d] bytes\n",
- __func__, EP_NO(imx_ep),
- ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state
- == EP0_IN_DATA_PHASE)
- || (EP_NO(imx_ep) && EP_DIR(imx_ep)))
- ? "IN" : "OUT", usb_req->length);
- dump_req(__func__, imx_ep, usb_req);
-
- if (imx_ep->stopped) {
- usb_req->status = -ESHUTDOWN;
- return -ESHUTDOWN;
- }
-
- if (req->in_use) {
- D_ERR(imx_usb->dev,
- "<%s> refusing to queue req %p (already queued)\n",
- __func__, req);
- return 0;
- }
-
- local_irq_save(flags);
-
- usb_req->status = -EINPROGRESS;
- usb_req->actual = 0;
-
- ep_add_request(imx_ep, req);
-
- if (!EP_NO(imx_ep))
- ret = handle_ep0(imx_ep);
- else
- ret = handle_ep(imx_ep);
-
- local_irq_restore(flags);
- return ret;
-}
-
-static int imx_ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
-{
-
- struct imx_ep_struct *imx_ep = container_of
- (usb_ep, struct imx_ep_struct, ep);
- struct imx_request *req;
- unsigned long flags;
-
- if (unlikely(!usb_ep || !EP_NO(imx_ep))) {
- D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
- return -EINVAL;
- }
-
- local_irq_save(flags);
-
- /* make sure it's actually queued on this endpoint */
- list_for_each_entry(req, &imx_ep->queue, queue) {
- if (&req->req == usb_req)
- break;
- }
- if (&req->req != usb_req) {
- local_irq_restore(flags);
- return -EINVAL;
- }
-
- done(imx_ep, req, -ECONNRESET);
-
- local_irq_restore(flags);
- return 0;
-}
-
-static int imx_ep_set_halt(struct usb_ep *usb_ep, int value)
-{
- struct imx_ep_struct *imx_ep = container_of
- (usb_ep, struct imx_ep_struct, ep);
- unsigned long flags;
-
- if (unlikely(!usb_ep || !EP_NO(imx_ep))) {
- D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
- return -EINVAL;
- }
-
- local_irq_save(flags);
-
- if ((imx_ep->bEndpointAddress & USB_DIR_IN)
- && !list_empty(&imx_ep->queue)) {
- local_irq_restore(flags);
- return -EAGAIN;
- }
-
- imx_ep_stall(imx_ep);
-
- local_irq_restore(flags);
-
- D_EPX(imx_ep->imx_usb->dev, "<%s> %s halt\n", __func__, usb_ep->name);
- return 0;
-}
-
-static int imx_ep_fifo_status(struct usb_ep *usb_ep)
-{
- struct imx_ep_struct *imx_ep = container_of
- (usb_ep, struct imx_ep_struct, ep);
-
- if (!usb_ep) {
- D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
- return -ENODEV;
- }
-
- if (imx_ep->imx_usb->gadget.speed == USB_SPEED_UNKNOWN)
- return 0;
- else
- return imx_fifo_bcount(imx_ep);
-}
-
-static void imx_ep_fifo_flush(struct usb_ep *usb_ep)
-{
- struct imx_ep_struct *imx_ep = container_of
- (usb_ep, struct imx_ep_struct, ep);
- unsigned long flags;
-
- local_irq_save(flags);
-
- if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) {
- D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
- local_irq_restore(flags);
- return;
- }
-
- /* toggle and halt bits stay unchanged */
- imx_flush(imx_ep);
-
- local_irq_restore(flags);
-}
-
-static struct usb_ep_ops imx_ep_ops = {
- .enable = imx_ep_enable,
- .disable = imx_ep_disable,
-
- .alloc_request = imx_ep_alloc_request,
- .free_request = imx_ep_free_request,
-
- .queue = imx_ep_queue,
- .dequeue = imx_ep_dequeue,
-
- .set_halt = imx_ep_set_halt,
- .fifo_status = imx_ep_fifo_status,
- .fifo_flush = imx_ep_fifo_flush,
-};
-
-/*******************************************************************************
- * USB endpoint control functions
- *******************************************************************************
- */
-
-void ep0_chg_stat(const char *label,
- struct imx_udc_struct *imx_usb, enum ep0_state stat)
-{
- D_EP0(imx_usb->dev, "<%s> from %15s to %15s\n",
- label, state_name[imx_usb->ep0state], state_name[stat]);
-
- if (imx_usb->ep0state == stat)
- return;
-
- imx_usb->ep0state = stat;
-}
-
-static void usb_init_data(struct imx_udc_struct *imx_usb)
-{
- struct imx_ep_struct *imx_ep;
- u8 i;
-
- /* device/ep0 records init */
- INIT_LIST_HEAD(&imx_usb->gadget.ep_list);
- INIT_LIST_HEAD(&imx_usb->gadget.ep0->ep_list);
- ep0_chg_stat(__func__, imx_usb, EP0_IDLE);
-
- /* basic endpoint records init */
- for (i = 0; i < IMX_USB_NB_EP; i++) {
- imx_ep = &imx_usb->imx_ep[i];
-
- if (i) {
- list_add_tail(&imx_ep->ep.ep_list,
- &imx_usb->gadget.ep_list);
- imx_ep->stopped = 1;
- } else
- imx_ep->stopped = 0;
-
- INIT_LIST_HEAD(&imx_ep->queue);
- }
-}
-
-static void udc_stop_activity(struct imx_udc_struct *imx_usb,
- struct usb_gadget_driver *driver)
-{
- struct imx_ep_struct *imx_ep;
- int i;
-
- if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN)
- driver = NULL;
-
- /* prevent new request submissions, kill any outstanding requests */
- for (i = 1; i < IMX_USB_NB_EP; i++) {
- imx_ep = &imx_usb->imx_ep[i];
- imx_flush(imx_ep);
- imx_ep->stopped = 1;
- imx_ep_irq_disable(imx_ep);
- nuke(imx_ep, -ESHUTDOWN);
- }
-
- imx_usb->cfg = 0;
- imx_usb->intf = 0;
- imx_usb->alt = 0;
-
- if (driver)
- driver->disconnect(&imx_usb->gadget);
-}
-
-/*******************************************************************************
- * Interrupt handlers
- *******************************************************************************
- */
-
-/*
- * Called when timer expires.
- * Timer is started when CFG_CHG is received.
- */
-static void handle_config(unsigned long data)
-{
- struct imx_udc_struct *imx_usb = (void *)data;
- struct usb_ctrlrequest u;
- int temp, cfg, intf, alt;
-
- local_irq_disable();
-
- temp = __raw_readl(imx_usb->base + USB_STAT);
- cfg = (temp & STAT_CFG) >> 5;
- intf = (temp & STAT_INTF) >> 3;
- alt = temp & STAT_ALTSET;
-
- D_REQ(imx_usb->dev,
- "<%s> orig config C=%d, I=%d, A=%d / "
- "req config C=%d, I=%d, A=%d\n",
- __func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt,
- cfg, intf, alt);
-
- if (cfg == 1 || cfg == 2) {
-
- if (imx_usb->cfg != cfg) {
- u.bRequest = USB_REQ_SET_CONFIGURATION;
- u.bRequestType = USB_DIR_OUT |
- USB_TYPE_STANDARD |
- USB_RECIP_DEVICE;
- u.wValue = cfg;
- u.wIndex = 0;
- u.wLength = 0;
- imx_usb->cfg = cfg;
- imx_usb->driver->setup(&imx_usb->gadget, &u);
-
- }
- if (imx_usb->intf != intf || imx_usb->alt != alt) {
- u.bRequest = USB_REQ_SET_INTERFACE;
- u.bRequestType = USB_DIR_OUT |
- USB_TYPE_STANDARD |
- USB_RECIP_INTERFACE;
- u.wValue = alt;
- u.wIndex = intf;
- u.wLength = 0;
- imx_usb->intf = intf;
- imx_usb->alt = alt;
- imx_usb->driver->setup(&imx_usb->gadget, &u);
- }
- }
-
- imx_usb->set_config = 0;
-
- local_irq_enable();
-}
-
-static irqreturn_t imx_udc_irq(int irq, void *dev)
-{
- struct imx_udc_struct *imx_usb = dev;
- int intr = __raw_readl(imx_usb->base + USB_INTR);
- int temp;
-
- if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START
- | INTR_RESET_STOP | INTR_CFG_CHG)) {
- dump_intr(__func__, intr, imx_usb->dev);
- dump_usb_stat(__func__, imx_usb);
- }
-
- if (!imx_usb->driver)
- goto end_irq;
-
- if (intr & INTR_SOF) {
- /* Copy from Freescale BSP.
- We must enable SOF intr and set CMDOVER.
- Datasheet don't specifiy this action, but it
- is done in Freescale BSP, so just copy it.
- */
- if (imx_usb->ep0state == EP0_IDLE) {
- temp = __raw_readl(imx_usb->base + USB_CTRL);
- __raw_writel(temp | CTRL_CMDOVER,
- imx_usb->base + USB_CTRL);
- }
- }
-
- if (intr & INTR_CFG_CHG) {
- /* A workaround of serious IMX UDC bug.
- Handling of CFG_CHG should be delayed for some time, because
- IMX does not NACK the host when CFG_CHG interrupt is pending.
- There is no time to handle current CFG_CHG
- if next CFG_CHG or SETUP packed is send immediately.
- We have to clear CFG_CHG, start the timer and
- NACK the host by setting CTRL_CMDOVER
- if it sends any SETUP packet.
- When timer expires, handler is called to handle configuration
- changes. While CFG_CHG is not handled (set_config=1),
- we must NACK the host to every SETUP packed.
- This delay prevents from going out of sync with host.
- */
- __raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR);
- imx_usb->set_config = 1;
- mod_timer(&imx_usb->timer, jiffies + 5);
- goto end_irq;
- }
-
- if (intr & INTR_WAKEUP) {
- if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN
- && imx_usb->driver && imx_usb->driver->resume)
- imx_usb->driver->resume(&imx_usb->gadget);
- imx_usb->set_config = 0;
- del_timer(&imx_usb->timer);
- imx_usb->gadget.speed = USB_SPEED_FULL;
- }
-
- if (intr & INTR_SUSPEND) {
- if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN
- && imx_usb->driver && imx_usb->driver->suspend)
- imx_usb->driver->suspend(&imx_usb->gadget);
- imx_usb->set_config = 0;
- del_timer(&imx_usb->timer);
- imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
- }
-
- if (intr & INTR_RESET_START) {
- __raw_writel(intr, imx_usb->base + USB_INTR);
- udc_stop_activity(imx_usb, imx_usb->driver);
- imx_usb->set_config = 0;
- del_timer(&imx_usb->timer);
- imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
- }
-
- if (intr & INTR_RESET_STOP)
- imx_usb->gadget.speed = USB_SPEED_FULL;
-
-end_irq:
- __raw_writel(intr, imx_usb->base + USB_INTR);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev)
-{
- struct imx_udc_struct *imx_usb = dev;
- struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0];
- int intr = __raw_readl(imx_usb->base + USB_EP_INTR(0));
-
- dump_ep_intr(__func__, 0, intr, imx_usb->dev);
-
- if (!imx_usb->driver) {
- __raw_writel(intr, imx_usb->base + USB_EP_INTR(0));
- return IRQ_HANDLED;
- }
-
- /* DEVREQ has highest priority */
- if (intr & (EPINTR_DEVREQ | EPINTR_MDEVREQ))
- handle_ep0_devreq(imx_usb);
- /* Seem i.MX is missing EOF interrupt sometimes.
- * Therefore we don't monitor EOF.
- * We call handle_ep0() only if a request is queued for ep0.
- */
- else if (!list_empty(&imx_ep->queue))
- handle_ep0(imx_ep);
-
- __raw_writel(intr, imx_usb->base + USB_EP_INTR(0));
-
- return IRQ_HANDLED;
-}
-
-#ifndef MX1_INT_USBD0
-#define MX1_INT_USBD0 MX1_USBD_INT0
-#endif
-
-static irqreturn_t imx_udc_bulk_irq(int irq, void *dev)
-{
- struct imx_udc_struct *imx_usb = dev;
- struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - MX1_INT_USBD0];
- int intr = __raw_readl(imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
-
- dump_ep_intr(__func__, irq - MX1_INT_USBD0, intr, imx_usb->dev);
-
- if (!imx_usb->driver) {
- __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
- return IRQ_HANDLED;
- }
-
- handle_ep(imx_ep);
-
- __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
-
- return IRQ_HANDLED;
-}
-
-irq_handler_t intr_handler(int i)
-{
- switch (i) {
- case 0:
- return imx_udc_ctrl_irq;
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- return imx_udc_bulk_irq;
- default:
- return imx_udc_irq;
- }
-}
-
-/*******************************************************************************
- * Static defined IMX UDC structure
- *******************************************************************************
- */
-
-static int imx_udc_start(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver);
-static int imx_udc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver);
-static const struct usb_gadget_ops imx_udc_ops = {
- .get_frame = imx_udc_get_frame,
- .wakeup = imx_udc_wakeup,
- .udc_start = imx_udc_start,
- .udc_stop = imx_udc_stop,
-};
-
-static struct imx_udc_struct controller = {
- .gadget = {
- .ops = &imx_udc_ops,
- .ep0 = &controller.imx_ep[0].ep,
- .name = driver_name,
- .dev = {
- .init_name = "gadget",
- },
- },
-
- .imx_ep[0] = {
- .ep = {
- .name = ep0name,
- .ops = &imx_ep_ops,
- .maxpacket = 32,
- },
- .imx_usb = &controller,
- .fifosize = 32,
- .bEndpointAddress = 0,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- },
- .imx_ep[1] = {
- .ep = {
- .name = "ep1in-bulk",
- .ops = &imx_ep_ops,
- .maxpacket = 64,
- },
- .imx_usb = &controller,
- .fifosize = 64,
- .bEndpointAddress = USB_DIR_IN | 1,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- },
- .imx_ep[2] = {
- .ep = {
- .name = "ep2out-bulk",
- .ops = &imx_ep_ops,
- .maxpacket = 64,
- },
- .imx_usb = &controller,
- .fifosize = 64,
- .bEndpointAddress = USB_DIR_OUT | 2,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- },
- .imx_ep[3] = {
- .ep = {
- .name = "ep3out-bulk",
- .ops = &imx_ep_ops,
- .maxpacket = 32,
- },
- .imx_usb = &controller,
- .fifosize = 32,
- .bEndpointAddress = USB_DIR_OUT | 3,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- },
- .imx_ep[4] = {
- .ep = {
- .name = "ep4in-int",
- .ops = &imx_ep_ops,
- .maxpacket = 32,
- },
- .imx_usb = &controller,
- .fifosize = 32,
- .bEndpointAddress = USB_DIR_IN | 4,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- },
- .imx_ep[5] = {
- .ep = {
- .name = "ep5out-int",
- .ops = &imx_ep_ops,
- .maxpacket = 32,
- },
- .imx_usb = &controller,
- .fifosize = 32,
- .bEndpointAddress = USB_DIR_OUT | 5,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- },
-};
-
-/*******************************************************************************
- * USB gadget driver functions
- *******************************************************************************
- */
-static int imx_udc_start(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
-{
- struct imx_udc_struct *imx_usb;
-
- imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
- /* first hook up the driver ... */
- imx_usb->driver = driver;
-
- D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
- __func__, driver->driver.name);
-
- imx_udc_enable(imx_usb);
-
- return 0;
-}
-
-static int imx_udc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
-{
- struct imx_udc_struct *imx_usb = container_of(gadget,
- struct imx_udc_struct, gadget);
-
- udc_stop_activity(imx_usb, driver);
- imx_udc_disable(imx_usb);
- del_timer(&imx_usb->timer);
-
- imx_usb->driver = NULL;
-
- D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n",
- __func__, driver->driver.name);
-
- return 0;
-}
-
-/*******************************************************************************
- * Module functions
- *******************************************************************************
- */
-
-static int __init imx_udc_probe(struct platform_device *pdev)
-{
- struct imx_udc_struct *imx_usb = &controller;
- struct resource *res;
- struct imxusb_platform_data *pdata;
- struct clk *clk;
- void __iomem *base;
- int ret = 0;
- int i;
- resource_size_t res_size;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "can't get device resources\n");
- return -ENODEV;
- }
-
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "driver needs platform data\n");
- return -ENODEV;
- }
-
- res_size = resource_size(res);
- if (!request_mem_region(res->start, res_size, res->name)) {
- dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
- res_size, res->start);
- return -ENOMEM;
- }
-
- if (pdata->init) {
- ret = pdata->init(&pdev->dev);
- if (ret)
- goto fail0;
- }
-
- base = ioremap(res->start, res_size);
- if (!base) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -EIO;
- goto fail1;
- }
-
- clk = clk_get(NULL, "usbd_clk");
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- dev_err(&pdev->dev, "can't get USB clock\n");
- goto fail2;
- }
- clk_prepare_enable(clk);
-
- if (clk_get_rate(clk) != 48000000) {
- D_INI(&pdev->dev,
- "Bad USB clock (%d Hz), changing to 48000000 Hz\n",
- (int)clk_get_rate(clk));
- if (clk_set_rate(clk, 48000000)) {
- dev_err(&pdev->dev,
- "Unable to set correct USB clock (48MHz)\n");
- ret = -EIO;
- goto fail3;
- }
- }
-
- for (i = 0; i < IMX_USB_NB_EP + 1; i++) {
- imx_usb->usbd_int[i] = platform_get_irq(pdev, i);
- if (imx_usb->usbd_int[i] < 0) {
- dev_err(&pdev->dev, "can't get irq number\n");
- ret = -ENODEV;
- goto fail3;
- }
- }
-
- for (i = 0; i < IMX_USB_NB_EP + 1; i++) {
- ret = request_irq(imx_usb->usbd_int[i], intr_handler(i),
- 0, driver_name, imx_usb);
- if (ret) {
- dev_err(&pdev->dev, "can't get irq %i, err %d\n",
- imx_usb->usbd_int[i], ret);
- for (--i; i >= 0; i--)
- free_irq(imx_usb->usbd_int[i], imx_usb);
- goto fail3;
- }
- }
-
- imx_usb->res = res;
- imx_usb->base = base;
- imx_usb->clk = clk;
- imx_usb->dev = &pdev->dev;
-
- platform_set_drvdata(pdev, imx_usb);
-
- usb_init_data(imx_usb);
- imx_udc_init(imx_usb);
-
- init_timer(&imx_usb->timer);
- imx_usb->timer.function = handle_config;
- imx_usb->timer.data = (unsigned long)imx_usb;
-
- ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
- if (ret)
- goto fail4;
-
- return 0;
-fail4:
- for (i = 0; i < IMX_USB_NB_EP + 1; i++)
- free_irq(imx_usb->usbd_int[i], imx_usb);
-fail3:
- clk_put(clk);
- clk_disable_unprepare(clk);
-fail2:
- iounmap(base);
-fail1:
- if (pdata->exit)
- pdata->exit(&pdev->dev);
-fail0:
- release_mem_region(res->start, res_size);
- return ret;
-}
-
-static int __exit imx_udc_remove(struct platform_device *pdev)
-{
- struct imx_udc_struct *imx_usb = platform_get_drvdata(pdev);
- struct imxusb_platform_data *pdata = pdev->dev.platform_data;
- int i;
-
- usb_del_gadget_udc(&imx_usb->gadget);
- imx_udc_disable(imx_usb);
- del_timer(&imx_usb->timer);
-
- for (i = 0; i < IMX_USB_NB_EP + 1; i++)
- free_irq(imx_usb->usbd_int[i], imx_usb);
-
- clk_put(imx_usb->clk);
- clk_disable_unprepare(imx_usb->clk);
- iounmap(imx_usb->base);
-
- release_mem_region(imx_usb->res->start, resource_size(imx_usb->res));
-
- if (pdata->exit)
- pdata->exit(&pdev->dev);
-
- return 0;
-}
-
-/*----------------------------------------------------------------------------*/
-
-#ifdef CONFIG_PM
-#define imx_udc_suspend NULL
-#define imx_udc_resume NULL
-#else
-#define imx_udc_suspend NULL
-#define imx_udc_resume NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-static struct platform_driver udc_driver = {
- .driver = {
- .name = driver_name,
- .owner = THIS_MODULE,
- },
- .remove = __exit_p(imx_udc_remove),
- .suspend = imx_udc_suspend,
- .resume = imx_udc_resume,
-};
-
-module_platform_driver_probe(udc_driver, imx_udc_probe);
-
-MODULE_DESCRIPTION("IMX USB Device Controller driver");
-MODULE_AUTHOR("Darius Augulis <augulis.darius@gmail.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx_udc");
diff --git a/drivers/usb/gadget/imx_udc.h b/drivers/usb/gadget/imx_udc.h
deleted file mode 100644
index d118fb77784..00000000000
--- a/drivers/usb/gadget/imx_udc.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (C) 2005 Mike Lee(eemike@gmail.com)
- *
- * This udc driver is now under testing and code is based on pxa2xx_udc.h
- * Please use it with your own risk!
- *
- * 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 __LINUX_USB_GADGET_IMX_H
-#define __LINUX_USB_GADGET_IMX_H
-
-#include <linux/types.h>
-
-/* Helper macros */
-#define EP_NO(ep) ((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */
-#define EP_DIR(ep) ((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0)
-#define IMX_USB_NB_EP 6
-
-/* Driver structures */
-struct imx_request {
- struct usb_request req;
- struct list_head queue;
- unsigned int in_use;
-};
-
-enum ep0_state {
- EP0_IDLE,
- EP0_IN_DATA_PHASE,
- EP0_OUT_DATA_PHASE,
- EP0_CONFIG,
- EP0_STALL,
-};
-
-struct imx_ep_struct {
- struct usb_ep ep;
- struct imx_udc_struct *imx_usb;
- struct list_head queue;
- unsigned char stopped;
- unsigned char fifosize;
- unsigned char bEndpointAddress;
- unsigned char bmAttributes;
-};
-
-struct imx_udc_struct {
- struct usb_gadget gadget;
- struct usb_gadget_driver *driver;
- struct device *dev;
- struct imx_ep_struct imx_ep[IMX_USB_NB_EP];
- struct clk *clk;
- struct timer_list timer;
- enum ep0_state ep0state;
- struct resource *res;
- void __iomem *base;
- unsigned char set_config;
- int cfg,
- intf,
- alt,
- usbd_int[7];
-};
-
-/* USB registers */
-#define USB_FRAME (0x00) /* USB frame */
-#define USB_SPEC (0x04) /* USB Spec */
-#define USB_STAT (0x08) /* USB Status */
-#define USB_CTRL (0x0C) /* USB Control */
-#define USB_DADR (0x10) /* USB Desc RAM addr */
-#define USB_DDAT (0x14) /* USB Desc RAM/EP buffer data */
-#define USB_INTR (0x18) /* USB interrupt */
-#define USB_MASK (0x1C) /* USB Mask */
-#define USB_ENAB (0x24) /* USB Enable */
-#define USB_EP_STAT(x) (0x30 + (x*0x30)) /* USB status/control */
-#define USB_EP_INTR(x) (0x34 + (x*0x30)) /* USB interrupt */
-#define USB_EP_MASK(x) (0x38 + (x*0x30)) /* USB mask */
-#define USB_EP_FDAT(x) (0x3C + (x*0x30)) /* USB FIFO data */
-#define USB_EP_FDAT0(x) (0x3C + (x*0x30)) /* USB FIFO data */
-#define USB_EP_FDAT1(x) (0x3D + (x*0x30)) /* USB FIFO data */
-#define USB_EP_FDAT2(x) (0x3E + (x*0x30)) /* USB FIFO data */
-#define USB_EP_FDAT3(x) (0x3F + (x*0x30)) /* USB FIFO data */
-#define USB_EP_FSTAT(x) (0x40 + (x*0x30)) /* USB FIFO status */
-#define USB_EP_FCTRL(x) (0x44 + (x*0x30)) /* USB FIFO control */
-#define USB_EP_LRFP(x) (0x48 + (x*0x30)) /* USB last rd f. pointer */
-#define USB_EP_LWFP(x) (0x4C + (x*0x30)) /* USB last wr f. pointer */
-#define USB_EP_FALRM(x) (0x50 + (x*0x30)) /* USB FIFO alarm */
-#define USB_EP_FRDP(x) (0x54 + (x*0x30)) /* USB FIFO read pointer */
-#define USB_EP_FWRP(x) (0x58 + (x*0x30)) /* USB FIFO write pointer */
-/* USB Control Register Bit Fields.*/
-#define CTRL_CMDOVER (1<<6) /* UDC status */
-#define CTRL_CMDERROR (1<<5) /* UDC status */
-#define CTRL_FE_ENA (1<<3) /* Enable Font End logic */
-#define CTRL_UDC_RST (1<<2) /* UDC reset */
-#define CTRL_AFE_ENA (1<<1) /* Analog Font end enable */
-#define CTRL_RESUME (1<<0) /* UDC resume */
-/* USB Status Register Bit Fields.*/
-#define STAT_RST (1<<8)
-#define STAT_SUSP (1<<7)
-#define STAT_CFG (3<<5)
-#define STAT_INTF (3<<3)
-#define STAT_ALTSET (7<<0)
-/* USB Interrupt Status/Mask Registers Bit fields */
-#define INTR_WAKEUP (1<<31) /* Wake up Interrupt */
-#define INTR_MSOF (1<<7) /* Missed Start of Frame */
-#define INTR_SOF (1<<6) /* Start of Frame */
-#define INTR_RESET_STOP (1<<5) /* Reset Signaling stop */
-#define INTR_RESET_START (1<<4) /* Reset Signaling start */
-#define INTR_RESUME (1<<3) /* Suspend to resume */
-#define INTR_SUSPEND (1<<2) /* Active to suspend */
-#define INTR_FRAME_MATCH (1<<1) /* Frame matched */
-#define INTR_CFG_CHG (1<<0) /* Configuration change occurred */
-/* USB Enable Register Bit Fields.*/
-#define ENAB_RST (1<<31) /* Reset USB modules */
-#define ENAB_ENAB (1<<30) /* Enable USB modules*/
-#define ENAB_SUSPEND (1<<29) /* Suspend USB modules */
-#define ENAB_ENDIAN (1<<28) /* Endian of USB modules */
-#define ENAB_PWRMD (1<<0) /* Power mode of USB modules */
-/* USB Descriptor Ram Address Register bit fields */
-#define DADR_CFG (1<<31) /* Configuration */
-#define DADR_BSY (1<<30) /* Busy status */
-#define DADR_DADR (0x1FF) /* Descriptor Ram Address */
-/* USB Descriptor RAM/Endpoint Buffer Data Register bit fields */
-#define DDAT_DDAT (0xFF) /* Descriptor Endpoint Buffer */
-/* USB Endpoint Status Register bit fields */
-#define EPSTAT_BCOUNT (0x7F<<16) /* Endpoint FIFO byte count */
-#define EPSTAT_SIP (1<<8) /* Endpoint setup in progress */
-#define EPSTAT_DIR (1<<7) /* Endpoint transfer direction */
-#define EPSTAT_MAX (3<<5) /* Endpoint Max packet size */
-#define EPSTAT_TYP (3<<3) /* Endpoint type */
-#define EPSTAT_ZLPS (1<<2) /* Send zero length packet */
-#define EPSTAT_FLUSH (1<<1) /* Endpoint FIFO Flush */
-#define EPSTAT_STALL (1<<0) /* Force stall */
-/* USB Endpoint FIFO Status Register bit fields */
-#define FSTAT_FRAME_STAT (0xF<<24) /* Frame status bit [0-3] */
-#define FSTAT_ERR (1<<22) /* FIFO error */
-#define FSTAT_UF (1<<21) /* FIFO underflow */
-#define FSTAT_OF (1<<20) /* FIFO overflow */
-#define FSTAT_FR (1<<19) /* FIFO frame ready */
-#define FSTAT_FULL (1<<18) /* FIFO full */
-#define FSTAT_ALRM (1<<17) /* FIFO alarm */
-#define FSTAT_EMPTY (1<<16) /* FIFO empty */
-/* USB Endpoint FIFO Control Register bit fields */
-#define FCTRL_WFR (1<<29) /* Write frame end */
-/* USB Endpoint Interrupt Status Regsiter bit fields */
-#define EPINTR_FIFO_FULL (1<<8) /* fifo full */
-#define EPINTR_FIFO_EMPTY (1<<7) /* fifo empty */
-#define EPINTR_FIFO_ERROR (1<<6) /* fifo error */
-#define EPINTR_FIFO_HIGH (1<<5) /* fifo high */
-#define EPINTR_FIFO_LOW (1<<4) /* fifo low */
-#define EPINTR_MDEVREQ (1<<3) /* multi Device request */
-#define EPINTR_EOT (1<<2) /* fifo end of transfer */
-#define EPINTR_DEVREQ (1<<1) /* Device request */
-#define EPINTR_EOF (1<<0) /* fifo end of frame */
-
-/* Debug macros */
-#ifdef DEBUG
-
-/* #define DEBUG_REQ */
-/* #define DEBUG_TRX */
-/* #define DEBUG_INIT */
-/* #define DEBUG_EP0 */
-/* #define DEBUG_EPX */
-/* #define DEBUG_IRQ */
-/* #define DEBUG_EPIRQ */
-/* #define DEBUG_DUMP */
-/* #define DEBUG_ERR */
-
-#ifdef DEBUG_REQ
- #define D_REQ(dev, args...) dev_dbg(dev, ## args)
-#else
- #define D_REQ(dev, args...) do {} while (0)
-#endif /* DEBUG_REQ */
-
-#ifdef DEBUG_TRX
- #define D_TRX(dev, args...) dev_dbg(dev, ## args)
-#else
- #define D_TRX(dev, args...) do {} while (0)
-#endif /* DEBUG_TRX */
-
-#ifdef DEBUG_INIT
- #define D_INI(dev, args...) dev_dbg(dev, ## args)
-#else
- #define D_INI(dev, args...) do {} while (0)
-#endif /* DEBUG_INIT */
-
-#ifdef DEBUG_EP0
- static const char *state_name[] = {
- "EP0_IDLE",
- "EP0_IN_DATA_PHASE",
- "EP0_OUT_DATA_PHASE",
- "EP0_CONFIG",
- "EP0_STALL"
- };
- #define D_EP0(dev, args...) dev_dbg(dev, ## args)
-#else
- #define D_EP0(dev, args...) do {} while (0)
-#endif /* DEBUG_EP0 */
-
-#ifdef DEBUG_EPX
- #define D_EPX(dev, args...) dev_dbg(dev, ## args)
-#else
- #define D_EPX(dev, args...) do {} while (0)
-#endif /* DEBUG_EP0 */
-
-#ifdef DEBUG_IRQ
- static void dump_intr(const char *label, int irqreg, struct device *dev)
- {
- dev_dbg(dev, "<%s> USB_INTR=[%s%s%s%s%s%s%s%s%s]\n", label,
- (irqreg & INTR_WAKEUP) ? " wake" : "",
- (irqreg & INTR_MSOF) ? " msof" : "",
- (irqreg & INTR_SOF) ? " sof" : "",
- (irqreg & INTR_RESUME) ? " resume" : "",
- (irqreg & INTR_SUSPEND) ? " suspend" : "",
- (irqreg & INTR_RESET_STOP) ? " noreset" : "",
- (irqreg & INTR_RESET_START) ? " reset" : "",
- (irqreg & INTR_FRAME_MATCH) ? " fmatch" : "",
- (irqreg & INTR_CFG_CHG) ? " config" : "");
- }
-#else
- #define dump_intr(x, y, z) do {} while (0)
-#endif /* DEBUG_IRQ */
-
-#ifdef DEBUG_EPIRQ
- static void dump_ep_intr(const char *label, int nr, int irqreg,
- struct device *dev)
- {
- dev_dbg(dev, "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, nr,
- (irqreg & EPINTR_FIFO_FULL) ? " full" : "",
- (irqreg & EPINTR_FIFO_EMPTY) ? " fempty" : "",
- (irqreg & EPINTR_FIFO_ERROR) ? " ferr" : "",
- (irqreg & EPINTR_FIFO_HIGH) ? " fhigh" : "",
- (irqreg & EPINTR_FIFO_LOW) ? " flow" : "",
- (irqreg & EPINTR_MDEVREQ) ? " mreq" : "",
- (irqreg & EPINTR_EOF) ? " eof" : "",
- (irqreg & EPINTR_DEVREQ) ? " devreq" : "",
- (irqreg & EPINTR_EOT) ? " eot" : "");
- }
-#else
- #define dump_ep_intr(x, y, z, i) do {} while (0)
-#endif /* DEBUG_IRQ */
-
-#ifdef DEBUG_DUMP
- static void dump_usb_stat(const char *label,
- struct imx_udc_struct *imx_usb)
- {
- int temp = __raw_readl(imx_usb->base + USB_STAT);
-
- dev_dbg(imx_usb->dev,
- "<%s> USB_STAT=[%s%s CFG=%d, INTF=%d, ALTR=%d]\n", label,
- (temp & STAT_RST) ? " reset" : "",
- (temp & STAT_SUSP) ? " suspend" : "",
- (temp & STAT_CFG) >> 5,
- (temp & STAT_INTF) >> 3,
- (temp & STAT_ALTSET));
- }
-
- static void dump_ep_stat(const char *label,
- struct imx_ep_struct *imx_ep)
- {
- int temp = __raw_readl(imx_ep->imx_usb->base
- + USB_EP_INTR(EP_NO(imx_ep)));
-
- dev_dbg(imx_ep->imx_usb->dev,
- "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n",
- label, EP_NO(imx_ep),
- (temp & EPINTR_FIFO_FULL) ? " full" : "",
- (temp & EPINTR_FIFO_EMPTY) ? " fempty" : "",
- (temp & EPINTR_FIFO_ERROR) ? " ferr" : "",
- (temp & EPINTR_FIFO_HIGH) ? " fhigh" : "",
- (temp & EPINTR_FIFO_LOW) ? " flow" : "",
- (temp & EPINTR_MDEVREQ) ? " mreq" : "",
- (temp & EPINTR_EOF) ? " eof" : "",
- (temp & EPINTR_DEVREQ) ? " devreq" : "",
- (temp & EPINTR_EOT) ? " eot" : "");
-
- temp = __raw_readl(imx_ep->imx_usb->base
- + USB_EP_STAT(EP_NO(imx_ep)));
-
- dev_dbg(imx_ep->imx_usb->dev,
- "<%s> EP%d_STAT=[%s%s bcount=%d]\n",
- label, EP_NO(imx_ep),
- (temp & EPSTAT_SIP) ? " sip" : "",
- (temp & EPSTAT_STALL) ? " stall" : "",
- (temp & EPSTAT_BCOUNT) >> 16);
-
- temp = __raw_readl(imx_ep->imx_usb->base
- + USB_EP_FSTAT(EP_NO(imx_ep)));
-
- dev_dbg(imx_ep->imx_usb->dev,
- "<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n",
- label, EP_NO(imx_ep),
- (temp & FSTAT_ERR) ? " ferr" : "",
- (temp & FSTAT_UF) ? " funder" : "",
- (temp & FSTAT_OF) ? " fover" : "",
- (temp & FSTAT_FR) ? " fready" : "",
- (temp & FSTAT_FULL) ? " ffull" : "",
- (temp & FSTAT_ALRM) ? " falarm" : "",
- (temp & FSTAT_EMPTY) ? " fempty" : "");
- }
-
- static void dump_req(const char *label, struct imx_ep_struct *imx_ep,
- struct usb_request *req)
- {
- int i;
-
- if (!req || !req->buf) {
- dev_dbg(imx_ep->imx_usb->dev,
- "<%s> req or req buf is free\n", label);
- return;
- }
-
- if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state
- == EP0_IN_DATA_PHASE)
- || (EP_NO(imx_ep) && EP_DIR(imx_ep))) {
-
- dev_dbg(imx_ep->imx_usb->dev,
- "<%s> request dump <", label);
- for (i = 0; i < req->length; i++)
- printk("%02x-", *((u8 *)req->buf + i));
- printk(">\n");
- }
- }
-
-#else
- #define dump_ep_stat(x, y) do {} while (0)
- #define dump_usb_stat(x, y) do {} while (0)
- #define dump_req(x, y, z) do {} while (0)
-#endif /* DEBUG_DUMP */
-
-#ifdef DEBUG_ERR
- #define D_ERR(dev, args...) dev_dbg(dev, ## args)
-#else
- #define D_ERR(dev, args...) do {} while (0)
-#endif
-
-#else
- #define D_REQ(dev, args...) do {} while (0)
- #define D_TRX(dev, args...) do {} while (0)
- #define D_INI(dev, args...) do {} while (0)
- #define D_EP0(dev, args...) do {} while (0)
- #define D_EPX(dev, args...) do {} while (0)
- #define dump_ep_intr(x, y, z, i) do {} while (0)
- #define dump_intr(x, y, z) do {} while (0)
- #define dump_ep_stat(x, y) do {} while (0)
- #define dump_usb_stat(x, y) do {} while (0)
- #define dump_req(x, y, z) do {} while (0)
- #define D_ERR(dev, args...) do {} while (0)
-#endif /* DEBUG */
-
-#endif /* __LINUX_USB_GADGET_IMX_H */
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 570c005062a..465ef8e2cc9 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1270,10 +1270,6 @@ dev_release (struct inode *inode, struct file *fd)
dev->buf = NULL;
put_dev (dev);
- /* other endpoints were all decoupled from this device */
- spin_lock_irq(&dev->lock);
- dev->state = STATE_DEV_DISABLED;
- spin_unlock_irq(&dev->lock);
return 0;
}
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 46ba9838c3a..d5f050d30ed 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1584,7 +1584,7 @@ static int __init m66592_probe(struct platform_device *pdev)
goto clean_up;
}
- if (pdev->dev.platform_data == NULL) {
+ if (dev_get_platdata(&pdev->dev) == NULL) {
dev_err(&pdev->dev, "no platform data\n");
ret = -ENODEV;
goto clean_up;
@@ -1598,7 +1598,7 @@ static int __init m66592_probe(struct platform_device *pdev)
goto clean_up;
}
- m66592->pdata = pdev->dev.platform_data;
+ m66592->pdata = dev_get_platdata(&pdev->dev);
m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK;
spin_lock_init(&m66592->lock);
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index 032b96a51ce..2a1ebefd8f9 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -160,10 +160,8 @@ static __init int rndis_do_config(struct usb_configuration *c)
return ret;
f_acm_rndis = usb_get_function(fi_acm);
- if (IS_ERR(f_acm_rndis)) {
- ret = PTR_ERR(f_acm_rndis);
- goto err_func_acm;
- }
+ if (IS_ERR(f_acm_rndis))
+ return PTR_ERR(f_acm_rndis);
ret = usb_add_function(c, f_acm_rndis);
if (ret)
@@ -178,7 +176,6 @@ err_fsg:
usb_remove_function(c, f_acm_rndis);
err_conf:
usb_put_function(f_acm_rndis);
-err_func_acm:
return ret;
}
@@ -226,7 +223,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
/* implicit port_num is zero */
f_acm_multi = usb_get_function(fi_acm);
if (IS_ERR(f_acm_multi))
- goto err_func_acm;
+ return PTR_ERR(f_acm_multi);
ret = usb_add_function(c, f_acm_multi);
if (ret)
@@ -241,7 +238,6 @@ err_fsg:
usb_remove_function(c, f_acm_multi);
err_conf:
usb_put_function(f_acm_multi);
-err_func_acm:
return ret;
}
diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c
index 07fdb3eaf48..bbb6e98c438 100644
--- a/drivers/usb/gadget/mv_u3d_core.c
+++ b/drivers/usb/gadget/mv_u3d_core.c
@@ -1109,7 +1109,7 @@ static int mv_u3d_controller_reset(struct mv_u3d *u3d)
static int mv_u3d_enable(struct mv_u3d *u3d)
{
- struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+ struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
int retval;
if (u3d->active)
@@ -1138,7 +1138,7 @@ static int mv_u3d_enable(struct mv_u3d *u3d)
static void mv_u3d_disable(struct mv_u3d *u3d)
{
- struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+ struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
if (u3d->clock_gating && u3d->active) {
dev_dbg(u3d->dev, "disable u3d\n");
if (pdata->phy_deinit)
@@ -1246,7 +1246,7 @@ static int mv_u3d_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget);
- struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+ struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
unsigned long flags;
if (u3d->driver)
@@ -1277,7 +1277,7 @@ static int mv_u3d_stop(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget);
- struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+ struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
unsigned long flags;
u3d->vbus_valid_detect = 0;
@@ -1776,7 +1776,7 @@ static int mv_u3d_remove(struct platform_device *dev)
kfree(u3d->eps);
if (u3d->irq)
- free_irq(u3d->irq, &dev->dev);
+ free_irq(u3d->irq, u3d);
if (u3d->cap_regs)
iounmap(u3d->cap_regs);
@@ -1794,12 +1794,12 @@ static int mv_u3d_remove(struct platform_device *dev)
static int mv_u3d_probe(struct platform_device *dev)
{
struct mv_u3d *u3d = NULL;
- struct mv_usb_platform_data *pdata = dev->dev.platform_data;
+ struct mv_usb_platform_data *pdata = dev_get_platdata(&dev->dev);
int retval = 0;
struct resource *r;
size_t size;
- if (!dev->dev.platform_data) {
+ if (!dev_get_platdata(&dev->dev)) {
dev_err(&dev->dev, "missing platform_data\n");
retval = -ENODEV;
goto err_pdata;
@@ -1974,7 +1974,7 @@ static int mv_u3d_probe(struct platform_device *dev)
return 0;
err_unregister:
- free_irq(u3d->irq, &dev->dev);
+ free_irq(u3d->irq, u3d);
err_request_irq:
err_get_irq:
kfree(u3d->status_req);
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index c2a57023e46..104cdbea635 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -2100,7 +2100,7 @@ static int mv_udc_remove(struct platform_device *pdev)
static int mv_udc_probe(struct platform_device *pdev)
{
- struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+ struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct mv_udc *udc;
int retval = 0;
struct resource *r;
@@ -2118,7 +2118,7 @@ static int mv_udc_probe(struct platform_device *pdev)
}
udc->done = &release_done;
- udc->pdata = pdev->dev.platform_data;
+ udc->pdata = dev_get_platdata(&pdev->dev);
spin_lock_init(&udc->lock);
udc->dev = pdev;
diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c
index f1e50a3e322..bf2bb39f35a 100644
--- a/drivers/usb/gadget/net2272.c
+++ b/drivers/usb/gadget/net2272.c
@@ -1184,7 +1184,7 @@ static const struct usb_gadget_ops net2272_ops = {
/*---------------------------------------------------------------------------*/
static ssize_t
-net2272_show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
+registers_show(struct device *_dev, struct device_attribute *attr, char *buf)
{
struct net2272 *dev;
char *next;
@@ -1308,7 +1308,7 @@ net2272_show_registers(struct device *_dev, struct device_attribute *attr, char
return PAGE_SIZE - size;
}
-static DEVICE_ATTR(registers, S_IRUGO, net2272_show_registers, NULL);
+static DEVICE_ATTR_RO(registers);
/*---------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index fbd006ab31d..0781bff7001 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -1424,8 +1424,8 @@ static const struct usb_gadget_ops net2280_ops = {
*/
/* "function" sysfs attribute */
-static ssize_t
-show_function (struct device *_dev, struct device_attribute *attr, char *buf)
+static ssize_t function_show(struct device *_dev, struct device_attribute *attr,
+ char *buf)
{
struct net2280 *dev = dev_get_drvdata (_dev);
@@ -1435,10 +1435,10 @@ show_function (struct device *_dev, struct device_attribute *attr, char *buf)
return 0;
return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
}
-static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
+static DEVICE_ATTR_RO(function);
-static ssize_t net2280_show_registers(struct device *_dev,
- struct device_attribute *attr, char *buf)
+static ssize_t registers_show(struct device *_dev,
+ struct device_attribute *attr, char *buf)
{
struct net2280 *dev;
char *next;
@@ -1590,10 +1590,10 @@ static ssize_t net2280_show_registers(struct device *_dev,
return PAGE_SIZE - size;
}
-static DEVICE_ATTR(registers, S_IRUGO, net2280_show_registers, NULL);
+static DEVICE_ATTR_RO(registers);
-static ssize_t
-show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
+static ssize_t queues_show(struct device *_dev, struct device_attribute *attr,
+ char *buf)
{
struct net2280 *dev;
char *next;
@@ -1690,7 +1690,7 @@ done:
spin_unlock_irqrestore (&dev->lock, flags);
return PAGE_SIZE - size;
}
-static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL);
+static DEVICE_ATTR_RO(queues);
#else
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index b8ed74a823c..83957cc225d 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2734,7 +2734,7 @@ static int omap_udc_probe(struct platform_device *pdev)
int hmc;
struct usb_phy *xceiv = NULL;
const char *type = NULL;
- struct omap_usb_config *config = pdev->dev.platform_data;
+ struct omap_usb_config *config = dev_get_platdata(&pdev->dev);
struct clk *dc_clk = NULL;
struct clk *hhc_clk = NULL;
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 95c531d5aa4..cc9207473db 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -2117,7 +2117,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
/* other non-static parts of init */
dev->dev = &pdev->dev;
- dev->mach = pdev->dev.platform_data;
+ dev->mach = dev_get_platdata(&pdev->dev);
dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 41cea9566ac..3c97da7760d 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -2422,7 +2422,7 @@ static int pxa_udc_probe(struct platform_device *pdev)
return udc->irq;
udc->dev = &pdev->dev;
- udc->mach = pdev->dev.platform_data;
+ udc->mach = dev_get_platdata(&pdev->dev);
udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
gpio = udc->mach->gpio_pullup;
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index c6af649f324..68be48d3340 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -1910,7 +1910,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
spin_lock_init(&r8a66597->lock);
platform_set_drvdata(pdev, r8a66597);
- r8a66597->pdata = pdev->dev.platform_data;
+ r8a66597->pdata = dev_get_platdata(&pdev->dev);
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
r8a66597->gadget.ops = &r8a66597_gadget_ops;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 3e3ea720303..9575085ded8 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -1142,7 +1142,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-int rndis_init(void)
+static int rndis_init(void)
{
u8 i;
@@ -1176,7 +1176,7 @@ int rndis_init(void)
}
module_init(rndis_init);
-void rndis_exit(void)
+static void rndis_exit(void)
{
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
u8 i;
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index af22f24046b..d69b36a99db 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
+#include <linux/of_platform.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -3450,7 +3451,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
static int s3c_hsotg_probe(struct platform_device *pdev)
{
- struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
+ struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
struct usb_phy *phy;
struct device *dev = &pdev->dev;
struct s3c_hsotg_ep *eps;
@@ -3469,7 +3470,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
if (IS_ERR(phy)) {
/* Fallback for pdata */
- plat = pdev->dev.platform_data;
+ plat = dev_get_platdata(&pdev->dev);
if (!plat) {
dev_err(&pdev->dev, "no platform data or transceiver defined\n");
return -EPROBE_DEFER;
@@ -3648,10 +3649,19 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
#define s3c_hsotg_resume NULL
#endif
+#ifdef CONFIG_OF
+static const struct of_device_id s3c_hsotg_of_ids[] = {
+ { .compatible = "samsung,s3c6400-hsotg", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids);
+#endif
+
static struct platform_driver s3c_hsotg_driver = {
.driver = {
.name = "s3c-hsotg",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(s3c_hsotg_of_ids),
},
.probe = s3c_hsotg_probe,
.remove = s3c_hsotg_remove,
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index b1f0771fbd3..1a1a41498db 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -1262,7 +1262,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct resource *res;
struct s3c_hsudc *hsudc;
- struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
+ struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev);
int ret, i;
hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) +
@@ -1275,7 +1275,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
hsudc->dev = dev;
- hsudc->pd = pdev->dev.platform_data;
+ hsudc->pd = dev_get_platdata(&pdev->dev);
hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 09c4f70c93c..c72d810e6b3 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1809,7 +1809,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
}
spin_lock_init(&udc->lock);
- udc_info = pdev->dev.platform_data;
+ udc_info = dev_get_platdata(&pdev->dev);
rsrc_start = S3C2410_PA_USBDEV;
rsrc_len = S3C24XX_SZ_USBDEV;
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index dbce3a9074e..08a1a3210a2 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -172,7 +172,7 @@ MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers");
*/
#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
-#endif /* CONFIG_USB_DEBUG */
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
/* check if fsg_num_buffers is within a valid range */
static inline int fsg_num_buffers_validate(void)
@@ -547,8 +547,8 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)
/*-------------------------------------------------------------------------*/
-static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t ro_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
@@ -557,16 +557,16 @@ static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
: curlun->initially_ro);
}
-static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t nofua_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
return sprintf(buf, "%u\n", curlun->nofua);
}
-static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t file_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
struct rw_semaphore *filesem = dev_get_drvdata(dev);
@@ -593,8 +593,8 @@ static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
}
-static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t ro_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t rc;
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
@@ -623,9 +623,8 @@ static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
return rc;
}
-static ssize_t fsg_store_nofua(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t nofua_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
unsigned nofua;
@@ -644,8 +643,8 @@ static ssize_t fsg_store_nofua(struct device *dev,
return count;
}
-static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t file_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
struct rw_semaphore *filesem = dev_get_drvdata(dev);
diff --git a/drivers/usb/gadget/u_uac1.c b/drivers/usb/gadget/u_uac1.c
index c7d460f4339..7a55fea4343 100644
--- a/drivers/usb/gadget/u_uac1.c
+++ b/drivers/usb/gadget/u_uac1.c
@@ -191,7 +191,7 @@ try_again:
frames = bytes_to_frames(runtime, count);
old_fs = get_fs();
set_fs(KERNEL_DS);
- result = snd_pcm_lib_write(snd->substream, buf, frames);
+ result = snd_pcm_lib_write(snd->substream, (void __user *)buf, frames);
if (result != frames) {
ERROR(card, "Playback error: %d\n", (int)result);
set_fs(old_fs);
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index ffd8fa54110..59891b1c48f 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -23,6 +23,7 @@
#include <linux/list.h>
#include <linux/err.h>
#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -50,6 +51,8 @@ static DEFINE_MUTEX(udc_lock);
/* ------------------------------------------------------------------------- */
+#ifdef CONFIG_HAS_DMA
+
int usb_gadget_map_request(struct usb_gadget *gadget,
struct usb_request *req, int is_in)
{
@@ -99,13 +102,22 @@ void usb_gadget_unmap_request(struct usb_gadget *gadget,
}
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
+#endif /* CONFIG_HAS_DMA */
+
/* ------------------------------------------------------------------------- */
+static void usb_gadget_state_work(struct work_struct *work)
+{
+ struct usb_gadget *gadget = work_to_gadget(work);
+
+ sysfs_notify(&gadget->dev.kobj, NULL, "state");
+}
+
void usb_gadget_set_state(struct usb_gadget *gadget,
enum usb_device_state state)
{
gadget->state = state;
- sysfs_notify(&gadget->dev.kobj, NULL, "status");
+ schedule_work(&gadget->work);
}
EXPORT_SYMBOL_GPL(usb_gadget_set_state);
@@ -192,11 +204,14 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
goto err1;
dev_set_name(&gadget->dev, "gadget");
+ INIT_WORK(&gadget->work, usb_gadget_state_work);
gadget->dev.parent = parent;
+#ifdef CONFIG_HAS_DMA
dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
gadget->dev.dma_parms = parent->dma_parms;
gadget->dev.dma_mask = parent->dma_mask;
+#endif
if (release)
gadget->dev.release = release;
@@ -309,6 +324,7 @@ found:
usb_gadget_remove_driver(udc);
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
+ flush_work(&gadget->work);
device_unregister(&udc->dev);
device_unregister(&gadget->dev);
}
@@ -454,31 +470,31 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
}
static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
-static ssize_t usb_gadget_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
struct usb_gadget *gadget = udc->gadget;
return sprintf(buf, "%s\n", usb_state_string(gadget->state));
}
-static DEVICE_ATTR(state, S_IRUGO, usb_gadget_state_show, NULL);
+static DEVICE_ATTR_RO(state);
#define USB_UDC_SPEED_ATTR(name, param) \
-ssize_t usb_udc_##param##_show(struct device *dev, \
+ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \
return snprintf(buf, PAGE_SIZE, "%s\n", \
usb_speed_string(udc->gadget->param)); \
} \
-static DEVICE_ATTR(name, S_IRUGO, usb_udc_##param##_show, NULL)
+static DEVICE_ATTR_RO(name)
static USB_UDC_SPEED_ATTR(current_speed, speed);
static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
#define USB_UDC_ATTR(name) \
-ssize_t usb_udc_##name##_show(struct device *dev, \
+ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \
@@ -486,7 +502,7 @@ ssize_t usb_udc_##name##_show(struct device *dev, \
\
return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \
} \
-static DEVICE_ATTR(name, S_IRUGO, usb_udc_##name##_show, NULL)
+static DEVICE_ATTR_RO(name)
static USB_UDC_ATTR(is_otg);
static USB_UDC_ATTR(is_a_peripheral);
diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
index e6170478ea9..0bb5d50075d 100644
--- a/drivers/usb/gadget/uvc_queue.c
+++ b/drivers/usb/gadget/uvc_queue.c
@@ -193,12 +193,16 @@ static int uvc_queue_buffer(struct uvc_video_queue *queue,
mutex_lock(&queue->mutex);
ret = vb2_qbuf(&queue->queue, buf);
+ if (ret < 0)
+ goto done;
+
spin_lock_irqsave(&queue->irqlock, flags);
ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
queue->flags &= ~UVC_QUEUE_PAUSED;
spin_unlock_irqrestore(&queue->irqlock, flags);
- mutex_unlock(&queue->mutex);
+done:
+ mutex_unlock(&queue->mutex);
return ret;
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 4263d011392..5be0326aae3 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -29,15 +29,6 @@ if USB_XHCI_HCD
config USB_XHCI_PLATFORM
tristate
-config USB_XHCI_HCD_DEBUGGING
- bool "Debugging for the xHCI host controller"
- ---help---
- Say 'Y' to turn on debugging for the xHCI host controller driver.
- This will spew debugging output, even in interrupt context.
- This should only be used for debugging xHCI driver bugs.
-
- If unsure, say N.
-
endif # USB_XHCI_HCD
config USB_EHCI_HCD
@@ -113,12 +104,6 @@ config USB_EHCI_HCD_PMC_MSP
Enables support for the onchip USB controller on the PMC_MSP7100 Family SoC's.
If unsure, say N.
-config USB_EHCI_BIG_ENDIAN_MMIO
- bool
-
-config USB_EHCI_BIG_ENDIAN_DESC
- bool
-
config XPS_USB_HCD_XILINX
bool "Use Xilinx usb host EHCI controller core"
depends on (PPC32 || MICROBLAZE)
@@ -148,13 +133,11 @@ config USB_EHCI_MXC
config USB_EHCI_HCD_OMAP
tristate "EHCI support for OMAP3 and later chips"
depends on ARCH_OMAP
+ select NOP_USB_XCEIV
default y
---help---
Enables support for the on-chip EHCI controller on
OMAP3 and later chips.
- If your system uses a PHY on the USB port, you will need to
- enable USB_PHY and the appropriate PHY driver as well. Most
- boards need the NOP_USB_XCEIV PHY driver.
config USB_EHCI_HCD_ORION
tristate "Support for Marvell EBU on-chip EHCI USB controller"
@@ -186,7 +169,6 @@ config USB_EHCI_HCD_AT91
config USB_EHCI_MSM
tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller"
depends on ARCH_MSM
- depends on USB_PHY
select USB_EHCI_ROOT_HUB_TT
select USB_MSM_OTG
---help---
@@ -354,6 +336,18 @@ config USB_FUSBH200_HCD
To compile this driver as a module, choose M here: the
module will be called fusbh200-hcd.
+config USB_FOTG210_HCD
+ tristate "FOTG210 HCD support"
+ depends on USB
+ default N
+ ---help---
+ Faraday FOTG210 is an OTG controller which can be configured as
+ an USB2.0 host. It is designed to meet USB2.0 EHCI specification
+ with minor modification.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fotg210-hcd.
+
config USB_OHCI_HCD
tristate "OHCI HCD (USB 1.1) support"
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
@@ -497,20 +491,6 @@ config USB_OCTEON_OHCI
controller. It is needed for low-speed USB 1.0 device
support. All CN6XXX based chips with USB are supported.
-
-config USB_OHCI_BIG_ENDIAN_DESC
- bool
- default n
-
-config USB_OHCI_BIG_ENDIAN_MMIO
- bool
- default n
-
-config USB_OHCI_LITTLE_ENDIAN
- bool
- default n if STB03xxx || PPC_MPC52xx
- default y
-
endif # USB_OHCI_HCD
config USB_UHCI_HCD
@@ -710,3 +690,20 @@ config USB_HCD_SSB
for ehci and ohci.
If unsure, say N.
+
+config USB_HCD_TEST_MODE
+ bool "HCD test mode support"
+ ---help---
+ Say 'Y' to enable additional software test modes that may be
+ supported by the host controller drivers.
+
+ One such test mode is the Embedded High-speed Host Electrical Test
+ (EHSET) for EHCI host controller hardware, specifically the "Single
+ Step Set Feature" test. Typically this will be enabled for On-the-Go
+ or embedded hosts that need to undergo USB-IF compliance testing with
+ the aid of special testing hardware. In the future, this may expand
+ to include other tests that require support from a HCD driver.
+
+ This option is of interest only to developers who need to validate
+ their USB hardware designs. It is not needed for normal use. If
+ unsure, say N.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index bea71127b15..50b0041c09a 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -4,6 +4,9 @@
ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
+# tell define_trace.h where to find the xhci trace header
+CFLAGS_xhci-trace.o := -I$(src)
+
isp1760-y := isp1760-hcd.o isp1760-if.o
fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
@@ -13,6 +16,7 @@ fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
xhci-hcd-y := xhci.o xhci-mem.o
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
+xhci-hcd-y += xhci-trace.o
xhci-hcd-$(CONFIG_PCI) += xhci-pci.o
ifneq ($(CONFIG_USB_XHCI_PLATFORM), )
@@ -58,3 +62,4 @@ obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
obj-$(CONFIG_USB_FUSBH200_HCD) += fusbh200-hcd.o
+obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 5429d2645bb..aa5b603f393 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -18,7 +18,7 @@
/* this file is part of ehci-hcd.c */
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
/* check the values in the HCSPARAMS register
* (host controller _Structural_ parameters)
@@ -62,7 +62,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
#endif
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
/* check the values in the HCCPARAMS register
* (host controller _Capability_ parameters)
@@ -101,7 +101,7 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
#endif
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
static void __maybe_unused
dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
@@ -301,7 +301,7 @@ static inline int __maybe_unused
dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
{ return 0; }
-#endif /* DEBUG */
+#endif /* DEBUG || CONFIG_DYNAMIC_DEBUG */
/* functions have the "wrong" filename when they're output... */
#define dbg_status(ehci, label, status) { \
@@ -336,7 +336,6 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
static int debug_async_open(struct inode *, struct file *);
static int debug_periodic_open(struct inode *, struct file *);
static int debug_registers_open(struct inode *, struct file *);
-static int debug_async_open(struct inode *, struct file *);
static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
static int debug_close(struct inode *, struct file *);
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index bd831ec06dc..947b009009f 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -57,7 +57,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
pr_debug("initializing FSL-SOC USB Controller\n");
/* Need platform data for setup */
- pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data;
+ pdata = (struct fsl_usb2_platform_data *)dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev,
"No platform data for %s.\n", dev_name(&pdev->dev));
@@ -190,7 +190,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
struct platform_device *pdev)
{
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+ struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
if (!IS_ERR_OR_NULL(hcd->phy)) {
otg_set_host(hcd->phy->otg, NULL);
@@ -218,7 +218,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
void __iomem *non_ehci = hcd->regs;
struct device *dev = hcd->self.controller;
- struct fsl_usb2_platform_data *pdata = dev->platform_data;
+ struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
if (pdata->controller_ver < 0) {
dev_warn(hcd->self.controller, "Could not get controller version\n");
@@ -291,7 +291,7 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
struct fsl_usb2_platform_data *pdata;
void __iomem *non_ehci = hcd->regs;
- pdata = hcd->self.controller->platform_data;
+ pdata = dev_get_platdata(hcd->self.controller);
if (pdata->have_sysif_regs) {
/*
@@ -363,7 +363,7 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
struct device *dev;
dev = hcd->self.controller;
- pdata = hcd->self.controller->platform_data;
+ pdata = dev_get_platdata(hcd->self.controller);
ehci->big_endian_desc = pdata->big_endian_desc;
ehci->big_endian_mmio = pdata->big_endian_mmio;
@@ -415,10 +415,10 @@ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct fsl_usb2_platform_data *pdata = dev->platform_data;
+ struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
u32 tmp;
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);
mode &= USBMODE_CM_MASK;
tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */
@@ -484,7 +484,7 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct fsl_usb2_platform_data *pdata = dev->platform_data;
+ struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
u32 tmp;
dev_dbg(dev, "suspend=%d already_suspended=%d\n",
@@ -669,7 +669,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_USB2 | HCD_MEMORY,
+ .flags = HCD_USB2 | HCD_MEMORY | HCD_BH,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c
index a77bd8dc33f..b52a66ce92e 100644
--- a/drivers/usb/host/ehci-grlib.c
+++ b/drivers/usb/host/ehci-grlib.c
@@ -43,7 +43,7 @@ static const struct hc_driver ehci_grlib_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
@@ -167,15 +167,6 @@ static int ehci_hcd_grlib_remove(struct platform_device *op)
}
-static void ehci_hcd_grlib_shutdown(struct platform_device *op)
-{
- struct usb_hcd *hcd = platform_get_drvdata(op);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
-}
-
-
static const struct of_device_id ehci_hcd_grlib_of_match[] = {
{
.name = "GAISLER_EHCI",
@@ -191,7 +182,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match);
static struct platform_driver ehci_grlib_driver = {
.probe = ehci_hcd_grlib_probe,
.remove = ehci_hcd_grlib_remove,
- .shutdown = ehci_hcd_grlib_shutdown,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "grlib-ehci",
.owner = THIS_MODULE,
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 7abf1ce3a67..5d6022f30eb 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -440,14 +440,6 @@ static void ehci_stop (struct usb_hcd *hcd)
if (ehci->amd_pll_fix == 1)
usb_amd_dev_put();
-#ifdef EHCI_STATS
- ehci_dbg(ehci, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
- ehci->stats.normal, ehci->stats.error, ehci->stats.iaa,
- ehci->stats.lost_iaa);
- ehci_dbg (ehci, "complete %ld unlink %ld\n",
- ehci->stats.complete, ehci->stats.unlink);
-#endif
-
dbg_status (ehci, "ehci_stop completed",
ehci_readl(ehci, &ehci->regs->status));
}
@@ -487,6 +479,7 @@ static int ehci_init(struct usb_hcd *hcd)
ehci->periodic_size = DEFAULT_I_TDPS;
INIT_LIST_HEAD(&ehci->async_unlink);
INIT_LIST_HEAD(&ehci->async_idle);
+ INIT_LIST_HEAD(&ehci->intr_unlink_wait);
INIT_LIST_HEAD(&ehci->intr_unlink);
INIT_LIST_HEAD(&ehci->intr_qh_list);
INIT_LIST_HEAD(&ehci->cached_itd_list);
@@ -942,7 +935,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
unsigned long flags;
- struct ehci_qh *qh, *tmp;
+ struct ehci_qh *qh;
/* ASSERT: any requests/urbs are being unlinked */
/* ASSERT: nobody can be submitting urbs for this any more */
@@ -972,17 +965,13 @@ rescan:
qh->qh_state = QH_STATE_IDLE;
switch (qh->qh_state) {
case QH_STATE_LINKED:
- case QH_STATE_COMPLETING:
- for (tmp = ehci->async->qh_next.qh;
- tmp && tmp != qh;
- tmp = tmp->qh_next.qh)
- continue;
- /* periodic qh self-unlinks on empty, and a COMPLETING qh
- * may already be unlinked.
- */
- if (tmp)
+ WARN_ON(!list_empty(&qh->qtd_list));
+ if (usb_endpoint_type(&ep->desc) != USB_ENDPOINT_XFER_INT)
start_unlink_async(ehci, qh);
+ else
+ start_unlink_intr(ehci, qh);
/* FALL THROUGH */
+ case QH_STATE_COMPLETING: /* already in unlinking */
case QH_STATE_UNLINK: /* wait for hw to finish? */
case QH_STATE_UNLINK_WAIT:
idle_timeout:
@@ -1169,7 +1158,7 @@ static const struct hc_driver ehci_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
@@ -1303,7 +1292,7 @@ static int __init ehci_hcd_init(void)
sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);
if (!ehci_debug_root) {
retval = -ENOENT;
@@ -1352,7 +1341,7 @@ clean2:
platform_driver_unregister(&PLATFORM_DRIVER);
clean0:
#endif
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
debugfs_remove(ehci_debug_root);
ehci_debug_root = NULL;
err_debug:
@@ -1376,7 +1365,7 @@ static void __exit ehci_hcd_cleanup(void)
#ifdef PS3_SYSTEM_BUS_DRIVER
ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
debugfs_remove(ehci_debug_root);
#endif
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 2b702772d04..835fc0844a6 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -183,7 +183,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
spin_lock_irq(&ehci->lock);
/* clear phy low-power mode before changing wakeup flags */
- if (ehci->has_hostpc) {
+ if (ehci->has_tdi_phy_lpm) {
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
@@ -211,13 +211,11 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
else
t2 |= PORT_WKOC_E | PORT_WKCONN_E;
}
- ehci_vdbg(ehci, "port %d, %08x -> %08x\n",
- port + 1, t1, t2);
ehci_writel(ehci, t2, reg);
}
/* enter phy low-power mode again */
- if (ehci->has_hostpc) {
+ if (ehci->has_tdi_phy_lpm) {
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
@@ -302,14 +300,12 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
}
if (t1 != t2) {
- ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
- port + 1, t1, t2);
ehci_writel(ehci, t2, reg);
changed = 1;
}
}
- if (changed && ehci->has_hostpc) {
+ if (changed && ehci->has_tdi_phy_lpm) {
spin_unlock_irq(&ehci->lock);
msleep(5); /* 5 ms for HCD to enter low-power mode */
spin_lock_irq(&ehci->lock);
@@ -345,6 +341,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
end_unlink_async(ehci);
unlink_empty_async_suspended(ehci);
+ ehci_handle_start_intr_unlinks(ehci);
ehci_handle_intr_unlinks(ehci);
end_free_itds(ehci);
@@ -435,7 +432,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
goto shutdown;
/* clear phy low-power mode before resume */
- if (ehci->bus_suspended && ehci->has_hostpc) {
+ if (ehci->bus_suspended && ehci->has_tdi_phy_lpm) {
i = HCS_N_PORTS(ehci->hcs_params);
while (i--) {
if (test_bit(i, &ehci->bus_suspended)) {
@@ -482,7 +479,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
if (test_bit(i, &resume_needed)) {
temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME);
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
- ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
}
@@ -711,6 +707,145 @@ ehci_hub_descriptor (
}
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+
+#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
+
+static void usb_ehset_completion(struct urb *urb)
+{
+ struct completion *done = urb->context;
+
+ complete(done);
+}
+static int submit_single_step_set_feature(
+ struct usb_hcd *hcd,
+ struct urb *urb,
+ int is_setup
+);
+
+/*
+ * Allocate and initialize a control URB. This request will be used by the
+ * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
+ * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
+ * Return NULL if failed.
+ */
+static struct urb *request_single_step_set_feature_urb(
+ struct usb_device *udev,
+ void *dr,
+ void *buf,
+ struct completion *done
+) {
+ struct urb *urb;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct usb_host_endpoint *ep;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return NULL;
+
+ urb->pipe = usb_rcvctrlpipe(udev, 0);
+ ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (!ep) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ urb->ep = ep;
+ urb->dev = udev;
+ urb->setup_packet = (void *)dr;
+ urb->transfer_buffer = buf;
+ urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+ urb->complete = usb_ehset_completion;
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->transfer_flags = URB_DIR_IN;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ urb->setup_dma = dma_map_single(
+ hcd->self.controller,
+ urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ urb->transfer_dma = dma_map_single(
+ hcd->self.controller,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ DMA_FROM_DEVICE);
+ urb->context = done;
+ return urb;
+}
+
+static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+ int retval = -ENOMEM;
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ struct usb_device *udev;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct usb_device_descriptor *buf;
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ /* Obtain udev of the rhub's child port */
+ udev = usb_hub_find_child(hcd->self.root_hub, port);
+ if (!udev) {
+ ehci_err(ehci, "No device attached to the RootHub\n");
+ return -ENODEV;
+ }
+ buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!dr) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ /* Fill Setup packet for GetDescriptor */
+ dr->bRequestType = USB_DIR_IN;
+ dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+ dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+ dr->wIndex = 0;
+ dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+ urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
+ if (!urb)
+ goto cleanup;
+
+ /* Submit just the SETUP stage */
+ retval = submit_single_step_set_feature(hcd, urb, 1);
+ if (retval)
+ goto out1;
+ if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__);
+ goto out1;
+ }
+ msleep(15 * 1000);
+
+ /* Complete remaining DATA and STATUS stages using the same URB */
+ urb->status = -EINPROGRESS;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ retval = submit_single_step_set_feature(hcd, urb, 0);
+ if (!retval && !wait_for_completion_timeout(&done,
+ msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__);
+ }
+out1:
+ usb_free_urb(urb);
+cleanup:
+ kfree(dr);
+ kfree(buf);
+ return retval;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+/*-------------------------------------------------------------------------*/
static int ehci_hub_control (
struct usb_hcd *hcd,
@@ -788,7 +923,7 @@ static int ehci_hub_control (
goto error;
/* clear phy low-power mode before resume */
- if (ehci->has_hostpc) {
+ if (ehci->has_tdi_phy_lpm) {
temp1 = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
hostpc_reg);
@@ -801,6 +936,8 @@ static int ehci_hub_control (
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
ehci->reset_done[wIndex] = jiffies
+ msecs_to_jiffies(20);
+ set_bit(wIndex, &ehci->resuming_ports);
+ usb_hcd_start_port_resume(&hcd->self, wIndex);
break;
case USB_PORT_FEAT_C_SUSPEND:
clear_bit(wIndex, &ehci->port_c_suspend);
@@ -865,52 +1002,49 @@ static int ehci_hub_control (
}
}
- /* whoever resumes must GetPortStatus to complete it!! */
- if (temp & PORT_RESUME) {
+ /* no reset or resume pending */
+ if (!ehci->reset_done[wIndex]) {
/* Remote Wakeup received? */
- if (!ehci->reset_done[wIndex]) {
+ if (temp & PORT_RESUME) {
/* resume signaling for 20 msec */
ehci->reset_done[wIndex] = jiffies
+ msecs_to_jiffies(20);
usb_hcd_start_port_resume(&hcd->self, wIndex);
+ set_bit(wIndex, &ehci->resuming_ports);
/* check the port again */
mod_timer(&ehci_to_hcd(ehci)->rh_timer,
ehci->reset_done[wIndex]);
}
- /* resume completed? */
- else if (time_after_eq(jiffies,
- ehci->reset_done[wIndex])) {
- clear_bit(wIndex, &ehci->suspended_ports);
- set_bit(wIndex, &ehci->port_c_suspend);
- ehci->reset_done[wIndex] = 0;
- usb_hcd_end_port_resume(&hcd->self, wIndex);
-
- /* stop resume signaling */
- temp &= ~(PORT_RWC_BITS |
- PORT_SUSPEND | PORT_RESUME);
- ehci_writel(ehci, temp, status_reg);
- clear_bit(wIndex, &ehci->resuming_ports);
- retval = ehci_handshake(ehci, status_reg,
- PORT_RESUME, 0, 2000 /* 2msec */);
- if (retval != 0) {
- ehci_err(ehci,
- "port %d resume error %d\n",
+ /* reset or resume not yet complete */
+ } else if (!time_after_eq(jiffies, ehci->reset_done[wIndex])) {
+ ; /* wait until it is complete */
+
+ /* resume completed */
+ } else if (test_bit(wIndex, &ehci->resuming_ports)) {
+ clear_bit(wIndex, &ehci->suspended_ports);
+ set_bit(wIndex, &ehci->port_c_suspend);
+ ehci->reset_done[wIndex] = 0;
+ usb_hcd_end_port_resume(&hcd->self, wIndex);
+
+ /* stop resume signaling */
+ temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME);
+ ehci_writel(ehci, temp, status_reg);
+ clear_bit(wIndex, &ehci->resuming_ports);
+ retval = ehci_handshake(ehci, status_reg,
+ PORT_RESUME, 0, 2000 /* 2msec */);
+ if (retval != 0) {
+ ehci_err(ehci, "port %d resume error %d\n",
wIndex + 1, retval);
- goto error;
- }
- temp = ehci_readl(ehci, status_reg);
+ goto error;
}
- }
+ temp = ehci_readl(ehci, status_reg);
/* whoever resets must GetPortStatus to complete it!! */
- if ((temp & PORT_RESET)
- && time_after_eq(jiffies,
- ehci->reset_done[wIndex])) {
+ } else {
status |= USB_PORT_STAT_C_RESET << 16;
ehci->reset_done [wIndex] = 0;
- clear_bit(wIndex, &ehci->resuming_ports);
/* force reset to complete */
ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
@@ -931,11 +1065,6 @@ static int ehci_hub_control (
ehci_readl(ehci, status_reg));
}
- if (!(temp & (PORT_RESUME|PORT_RESET))) {
- ehci->reset_done[wIndex] = 0;
- clear_bit(wIndex, &ehci->resuming_ports);
- }
-
/* transfer dedicated ports to the companion hc */
if ((temp & PORT_CONNECT) &&
test_bit(wIndex, &ehci->companion_ports)) {
@@ -1031,12 +1160,12 @@ static int ehci_hub_control (
/* After above check the port must be connected.
* Set appropriate bit thus could put phy into low power
- * mode if we have hostpc feature
+ * mode if we have tdi_phy_lpm feature
*/
temp &= ~PORT_WKCONN_E;
temp |= PORT_WKDISC_E | PORT_WKOC_E;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
- if (ehci->has_hostpc) {
+ if (ehci->has_tdi_phy_lpm) {
spin_unlock_irqrestore(&ehci->lock, flags);
msleep(5);/* 5ms for HCD enter low pwr mode */
spin_lock_irqsave(&ehci->lock, flags);
@@ -1056,7 +1185,7 @@ static int ehci_hub_control (
status_reg);
break;
case USB_PORT_FEAT_RESET:
- if (temp & PORT_RESUME)
+ if (temp & (PORT_SUSPEND|PORT_RESUME))
goto error;
/* line status bits may report this as low speed,
* which can be fine if this root hub has a
@@ -1070,7 +1199,6 @@ static int ehci_hub_control (
wIndex + 1);
temp |= PORT_OWNER;
} else {
- ehci_vdbg (ehci, "port %d reset\n", wIndex + 1);
temp |= PORT_RESET;
temp &= ~PORT_PE;
@@ -1091,6 +1219,15 @@ static int ehci_hub_control (
* about the EHCI-specific stuff.
*/
case USB_PORT_FEAT_TEST:
+#ifdef CONFIG_USB_HCD_TEST_MODE
+ if (selector == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ retval = ehset_single_step_set_feature(hcd,
+ wIndex);
+ spin_lock_irqsave(&ehci->lock, flags);
+ break;
+ }
+#endif
if (!selector || selector > 5)
goto error;
spin_unlock_irqrestore(&ehci->lock, flags);
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index ef2c3a1eca4..52a77734a22 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -93,6 +93,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
+ INIT_LIST_HEAD(&qh->unlink_node);
/* dummy td enables safe urb queuing */
qh->dummy = ehci_qtd_alloc (ehci, flags);
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 915c2db96dc..417c10da945 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -96,7 +96,7 @@ static const struct hc_driver mv_ehci_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
@@ -131,7 +131,7 @@ static const struct hc_driver mv_ehci_hc_driver = {
static int mv_ehci_probe(struct platform_device *pdev)
{
- struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+ struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct ehci_hcd_mv *ehci_mv;
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index e4c34ac386c..0528dc4526c 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -49,7 +49,7 @@ static const struct ehci_driver_overrides ehci_mxc_overrides __initconst = {
static int ehci_mxc_drv_probe(struct platform_device *pdev)
{
- struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
+ struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct usb_hcd *hcd;
struct resource *res;
int irq, ret;
@@ -174,7 +174,7 @@ err_alloc:
static int ehci_mxc_drv_remove(struct platform_device *pdev)
{
- struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
+ struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct ehci_mxc_priv *priv = (struct ehci_mxc_priv *) ehci->priv;
@@ -184,7 +184,7 @@ static int ehci_mxc_drv_remove(struct platform_device *pdev)
if (pdata && pdata->exit)
pdata->exit(pdev);
- if (pdata->otg)
+ if (pdata && pdata->otg)
usb_phy_shutdown(pdata->otg);
clk_disable_unprepare(priv->usbclk);
@@ -197,20 +197,12 @@ static int ehci_mxc_drv_remove(struct platform_device *pdev)
return 0;
}
-static void ehci_mxc_drv_shutdown(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
-}
-
MODULE_ALIAS("platform:mxc-ehci");
static struct platform_driver ehci_mxc_driver = {
.probe = ehci_mxc_drv_probe,
.remove = ehci_mxc_drv_remove,
- .shutdown = ehci_mxc_drv_shutdown,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "mxc-ehci",
},
diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c
index 45cc0015841..ab0397e4d8f 100644
--- a/drivers/usb/host/ehci-octeon.c
+++ b/drivers/usb/host/ehci-octeon.c
@@ -51,7 +51,7 @@ static const struct hc_driver ehci_octeon_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 9bd7dfe3315..78b01fa475b 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -100,7 +100,7 @@ static const struct ehci_driver_overrides ehci_omap_overrides __initdata = {
static int ehci_hcd_omap_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct usbhs_omap_platform_data *pdata = dev->platform_data;
+ struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev);
struct resource *res;
struct usb_hcd *hcd;
void __iomem *regs;
@@ -119,7 +119,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
/* For DT boot, get platform data from parent. i.e. usbhshost */
if (dev->of_node) {
- pdata = dev->parent->platform_data;
+ pdata = dev_get_platdata(dev->parent);
dev->platform_data = pdata;
}
@@ -278,14 +278,6 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
return 0;
}
-static void ehci_hcd_omap_shutdown(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
-}
-
static const struct of_device_id omap_ehci_dt_ids[] = {
{ .compatible = "ti,ehci-omap" },
{ }
@@ -296,7 +288,7 @@ MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids);
static struct platform_driver ehci_hcd_omap_driver = {
.probe = ehci_hcd_omap_probe,
.remove = ehci_hcd_omap_remove,
- .shutdown = ehci_hcd_omap_shutdown,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ehci_hcd_omap_suspend, */
/*.resume = ehci_hcd_omap_resume, */
.driver = {
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 1a450aa13eb..d1dfb9db5b4 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -139,7 +139,7 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,
static int ehci_orion_drv_probe(struct platform_device *pdev)
{
- struct orion_ehci_data *pd = pdev->dev.platform_data;
+ struct orion_ehci_data *pd = dev_get_platdata(&pdev->dev);
const struct mbus_dram_target_info *dram;
struct resource *res;
struct usb_hcd *hcd;
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 595d210655b..6bd299e61f5 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -315,53 +315,11 @@ done:
* Also they depend on separate root hub suspend/resume.
*/
-static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
-{
- return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
- pdev->vendor == PCI_VENDOR_ID_INTEL &&
- (pdev->device == 0x1E26 ||
- pdev->device == 0x8C2D ||
- pdev->device == 0x8C26 ||
- pdev->device == 0x9C26);
-}
-
-static void ehci_enable_xhci_companion(void)
-{
- struct pci_dev *companion = NULL;
-
- /* The xHCI and EHCI controllers are not on the same PCI slot */
- for_each_pci_dev(companion) {
- if (!usb_is_intel_switchable_xhci(companion))
- continue;
- usb_enable_xhci_ports(companion);
- return;
- }
-}
-
static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
- /* The BIOS on systems with the Intel Panther Point chipset may or may
- * not support xHCI natively. That means that during system resume, it
- * may switch the ports back to EHCI so that users can use their
- * keyboard to select a kernel from GRUB after resume from hibernate.
- *
- * The BIOS is supposed to remember whether the OS had xHCI ports
- * enabled before resume, and switch the ports back to xHCI when the
- * BIOS/OS semaphore is written, but we all know we can't trust BIOS
- * writers.
- *
- * Unconditionally switch the ports back to xHCI after a system resume.
- * We can't tell whether the EHCI or xHCI controller will be resumed
- * first, so we have to do the port switchover in both drivers. Writing
- * a '1' to the port switchover registers should have no effect if the
- * port was already switched over.
- */
- if (usb_is_intel_switchable_ehci(pdev))
- ehci_enable_xhci_companion();
-
if (ehci_resume(hcd, hibernated) != 0)
(void) ehci_pci_reinit(ehci, pdev);
return 0;
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 5196d728517..f6b790ca8cf 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -39,7 +39,7 @@ static const char hcd_name[] = "ehci-platform";
static int ehci_platform_reset(struct usb_hcd *hcd)
{
struct platform_device *pdev = to_platform_device(hcd->self.controller);
- struct usb_ehci_pdata *pdata = pdev->dev.platform_data;
+ struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
@@ -87,14 +87,14 @@ static int ehci_platform_probe(struct platform_device *dev)
* use reasonable defaults so platforms don't have to provide these.
* with DT probing on ARM, none of these are set.
*/
- if (!dev->dev.platform_data)
+ if (!dev_get_platdata(&dev->dev))
dev->dev.platform_data = &ehci_platform_defaults;
if (!dev->dev.dma_mask)
dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
if (!dev->dev.coherent_dma_mask)
dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- pdata = dev->dev.platform_data;
+ pdata = dev_get_platdata(&dev->dev);
irq = platform_get_irq(dev, 0);
if (irq < 0) {
@@ -148,7 +148,7 @@ err_power:
static int ehci_platform_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
- struct usb_ehci_pdata *pdata = dev->dev.platform_data;
+ struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
@@ -167,7 +167,7 @@ static int ehci_platform_remove(struct platform_device *dev)
static int ehci_platform_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct usb_ehci_pdata *pdata = dev->platform_data;
+ struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
struct platform_device *pdev =
container_of(dev, struct platform_device, dev);
bool do_wakeup = device_may_wakeup(dev);
@@ -184,7 +184,7 @@ static int ehci_platform_suspend(struct device *dev)
static int ehci_platform_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct usb_ehci_pdata *pdata = dev->platform_data;
+ struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
struct platform_device *pdev =
container_of(dev, struct platform_device, dev);
diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c
index 601e208bd78..893b707f000 100644
--- a/drivers/usb/host/ehci-pmcmsp.c
+++ b/drivers/usb/host/ehci-pmcmsp.c
@@ -286,7 +286,7 @@ static const struct hc_driver ehci_msp_hc_driver = {
#else
.irq = ehci_irq,
#endif
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 86da09c0f8d..6cc5567bf9c 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -28,7 +28,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
@@ -215,15 +215,6 @@ static int ehci_hcd_ppc_of_remove(struct platform_device *op)
}
-static void ehci_hcd_ppc_of_shutdown(struct platform_device *op)
-{
- struct usb_hcd *hcd = platform_get_drvdata(op);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
-}
-
-
static const struct of_device_id ehci_hcd_ppc_of_match[] = {
{
.compatible = "usb-ehci",
@@ -236,7 +227,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match);
static struct platform_driver ehci_hcd_ppc_of_driver = {
.probe = ehci_hcd_ppc_of_probe,
.remove = ehci_hcd_ppc_of_remove,
- .shutdown = ehci_hcd_ppc_of_shutdown,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ppc-of-ehci",
.owner = THIS_MODULE,
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index fd983771b02..8188542ba17 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -71,7 +71,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
.product_desc = "PS3 EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
.reset = ps3_ehci_hc_reset,
.start = ehci_run,
.stop = ehci_stop,
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index d34b399b78e..e321804c347 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -168,13 +168,13 @@ static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh,
* Note: this routine is never called for Isochronous transfers.
*/
if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
struct usb_device *tt = urb->dev->tt->hub;
dev_dbg(&tt->dev,
"clear tt buffer port %d, a%d ep%d t%08x\n",
urb->dev->ttport, urb->dev->devnum,
usb_pipeendpoint(urb->pipe), token);
-#endif /* DEBUG */
+#endif /* DEBUG || CONFIG_DYNAMIC_DEBUG */
if (!ehci_is_TDI(ehci)
|| urb->dev->tt->hub !=
ehci_to_hcd(ehci)->self.root_hub) {
@@ -240,13 +240,6 @@ static int qtd_copy_status (
} else { /* unknown */
status = -EPROTO;
}
-
- ehci_vdbg (ehci,
- "dev%d ep%d%s qtd token %08x --> status %d\n",
- usb_pipedevice (urb->pipe),
- usb_pipeendpoint (urb->pipe),
- usb_pipein (urb->pipe) ? "in" : "out",
- token, status);
}
return status;
@@ -254,8 +247,6 @@ static int qtd_copy_status (
static void
ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
-__releases(ehci->lock)
-__acquires(ehci->lock)
{
if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
/* ... update hc-wide periodic stats */
@@ -281,11 +272,8 @@ __acquires(ehci->lock)
urb->actual_length, urb->transfer_buffer_length);
#endif
- /* complete() can reenter this HCD */
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
- spin_unlock (&ehci->lock);
usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
- spin_lock (&ehci->lock);
}
static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
@@ -1144,6 +1132,109 @@ submit_async (
}
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+/*
+ * This function creates the qtds and submits them for the
+ * SINGLE_STEP_SET_FEATURE Test.
+ * This is done in two parts: first SETUP req for GetDesc is sent then
+ * 15 seconds later, the IN stage for GetDesc starts to req data from dev
+ *
+ * is_setup : i/p arguement decides which of the two stage needs to be
+ * performed; TRUE - SETUP and FALSE - IN+STATUS
+ * Returns 0 if success
+ */
+static int submit_single_step_set_feature(
+ struct usb_hcd *hcd,
+ struct urb *urb,
+ int is_setup
+) {
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct list_head qtd_list;
+ struct list_head *head;
+
+ struct ehci_qtd *qtd, *qtd_prev;
+ dma_addr_t buf;
+ int len, maxpacket;
+ u32 token;
+
+ INIT_LIST_HEAD(&qtd_list);
+ head = &qtd_list;
+
+ /* URBs map to sequences of QTDs: one logical transaction */
+ qtd = ehci_qtd_alloc(ehci, GFP_KERNEL);
+ if (unlikely(!qtd))
+ return -1;
+ list_add_tail(&qtd->qtd_list, head);
+ qtd->urb = urb;
+
+ token = QTD_STS_ACTIVE;
+ token |= (EHCI_TUNE_CERR << 10);
+
+ len = urb->transfer_buffer_length;
+ /*
+ * Check if the request is to perform just the SETUP stage (getDesc)
+ * as in SINGLE_STEP_SET_FEATURE test, DATA stage (IN) happens
+ * 15 secs after the setup
+ */
+ if (is_setup) {
+ /* SETUP pid */
+ qtd_fill(ehci, qtd, urb->setup_dma,
+ sizeof(struct usb_ctrlrequest),
+ token | (2 /* "setup" */ << 8), 8);
+
+ submit_async(ehci, urb, &qtd_list, GFP_ATOMIC);
+ return 0; /*Return now; we shall come back after 15 seconds*/
+ }
+
+ /*
+ * IN: data transfer stage: buffer setup : start the IN txn phase for
+ * the get_Desc SETUP which was sent 15seconds back
+ */
+ token ^= QTD_TOGGLE; /*We need to start IN with DATA-1 Pid-sequence*/
+ buf = urb->transfer_dma;
+
+ token |= (1 /* "in" */ << 8); /*This is IN stage*/
+
+ maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, 0));
+
+ qtd_fill(ehci, qtd, buf, len, token, maxpacket);
+
+ /*
+ * Our IN phase shall always be a short read; so keep the queue running
+ * and let it advance to the next qtd which zero length OUT status
+ */
+ qtd->hw_alt_next = EHCI_LIST_END(ehci);
+
+ /* STATUS stage for GetDesc control request */
+ token ^= 0x0100; /* "in" <--> "out" */
+ token |= QTD_TOGGLE; /* force DATA1 */
+
+ qtd_prev = qtd;
+ qtd = ehci_qtd_alloc(ehci, GFP_ATOMIC);
+ if (unlikely(!qtd))
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* dont fill any data in such packets */
+ qtd_fill(ehci, qtd, 0, 0, token, 0);
+
+ /* by default, enable interrupt on urb completion */
+ if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
+ qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC);
+
+ submit_async(ehci, urb, &qtd_list, GFP_KERNEL);
+
+ return 0;
+
+cleanup:
+ qtd_list_free(ehci, urb, head);
+ return -1;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
+/*-------------------------------------------------------------------------*/
static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 7cc26e621aa..7c3de95c705 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -75,7 +75,7 @@ static void s5p_setup_vbus_gpio(struct platform_device *pdev)
static int s5p_ehci_probe(struct platform_device *pdev)
{
- struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
+ struct s5p_ehci_platdata *pdata = dev_get_platdata(&pdev->dev);
struct s5p_ehci_hcd *s5p_ehci;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
@@ -220,14 +220,6 @@ static int s5p_ehci_remove(struct platform_device *pdev)
return 0;
}
-static void s5p_ehci_shutdown(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
-}
-
#ifdef CONFIG_PM
static int s5p_ehci_suspend(struct device *dev)
{
@@ -297,7 +289,7 @@ MODULE_DEVICE_TABLE(of, exynos_ehci_match);
static struct platform_driver s5p_ehci_driver = {
.probe = s5p_ehci_probe,
.remove = s5p_ehci_remove,
- .shutdown = s5p_ehci_shutdown,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "s5p-ehci",
.owner = THIS_MODULE,
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index f80d0330d54..85dd24ed97a 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -169,7 +169,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
break;
}
}
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
if (usecs > ehci->uframe_periodic_max)
ehci_err (ehci, "uframe %d sched overrun: %d usecs\n",
frame * 8 + uframe, usecs);
@@ -327,17 +327,8 @@ static int tt_available (
periodic_tt_usecs (ehci, dev, frame, tt_usecs);
- ehci_vdbg(ehci, "tt frame %d check %d usecs start uframe %d in"
- " schedule %d/%d/%d/%d/%d/%d/%d/%d\n",
- frame, usecs, uframe,
- tt_usecs[0], tt_usecs[1], tt_usecs[2], tt_usecs[3],
- tt_usecs[4], tt_usecs[5], tt_usecs[6], tt_usecs[7]);
-
- if (max_tt_usecs[uframe] <= tt_usecs[uframe]) {
- ehci_vdbg(ehci, "frame %d uframe %d fully scheduled\n",
- frame, uframe);
+ if (max_tt_usecs[uframe] <= tt_usecs[uframe])
return 0;
- }
/* special case for isoc transfers larger than 125us:
* the first and each subsequent fully used uframe
@@ -348,13 +339,8 @@ static int tt_available (
int ufs = (usecs / 125);
int i;
for (i = uframe; i < (uframe + ufs) && i < 8; i++)
- if (0 < tt_usecs[i]) {
- ehci_vdbg(ehci,
- "multi-uframe xfer can't fit "
- "in frame %d uframe %d\n",
- frame, i);
+ if (0 < tt_usecs[i])
return 0;
- }
}
tt_usecs[uframe] += usecs;
@@ -362,12 +348,8 @@ static int tt_available (
carryover_tt_bandwidth(tt_usecs);
/* fail if the carryover pushed bw past the last uframe's limit */
- if (max_tt_usecs[7] < tt_usecs[7]) {
- ehci_vdbg(ehci,
- "tt unavailable usecs %d frame %d uframe %d\n",
- usecs, frame, uframe);
+ if (max_tt_usecs[7] < tt_usecs[7])
return 0;
- }
}
return 1;
@@ -601,12 +583,29 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
list_del(&qh->intr_node);
}
+static void cancel_unlink_wait_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+ if (qh->qh_state != QH_STATE_LINKED ||
+ list_empty(&qh->unlink_node))
+ return;
+
+ list_del_init(&qh->unlink_node);
+
+ /*
+ * TODO: disable the event of EHCI_HRTIMER_START_UNLINK_INTR for
+ * avoiding unnecessary CPU wakeup
+ */
+}
+
static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
/* If the QH isn't linked then there's nothing we can do. */
if (qh->qh_state != QH_STATE_LINKED)
return;
+ /* if the qh is waiting for unlink, cancel it now */
+ cancel_unlink_wait_intr(ehci, qh);
+
qh_unlink_periodic (ehci, qh);
/* Make sure the unlinks are visible before starting the timer */
@@ -632,6 +631,27 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
}
}
+/*
+ * It is common only one intr URB is scheduled on one qh, and
+ * given complete() is run in tasklet context, introduce a bit
+ * delay to avoid unlink qh too early.
+ */
+static void start_unlink_intr_wait(struct ehci_hcd *ehci,
+ struct ehci_qh *qh)
+{
+ qh->unlink_cycle = ehci->intr_unlink_wait_cycle;
+
+ /* New entries go at the end of the intr_unlink_wait list */
+ list_add_tail(&qh->unlink_node, &ehci->intr_unlink_wait);
+
+ if (ehci->rh_state < EHCI_RH_RUNNING)
+ ehci_handle_start_intr_unlinks(ehci);
+ else if (ehci->intr_unlink_wait.next == &qh->unlink_node) {
+ ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true);
+ ++ehci->intr_unlink_wait_cycle;
+ }
+}
+
static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qh_hw *hw = qh->hw;
@@ -889,6 +909,9 @@ static int intr_submit (
if (qh->qh_state == QH_STATE_IDLE) {
qh_refresh(ehci, qh);
qh_link_periodic(ehci, qh);
+ } else {
+ /* cancel unlink wait for the qh */
+ cancel_unlink_wait_intr(ehci, qh);
}
/* ... update usbfs periodic stats */
@@ -924,9 +947,11 @@ static void scan_intr(struct ehci_hcd *ehci)
* in qh_unlink_periodic().
*/
temp = qh_completions(ehci, qh);
- if (unlikely(temp || (list_empty(&qh->qtd_list) &&
- qh->qh_state == QH_STATE_LINKED)))
+ if (unlikely(temp))
start_unlink_intr(ehci, qh);
+ else if (unlikely(list_empty(&qh->qtd_list) &&
+ qh->qh_state == QH_STATE_LINKED))
+ start_unlink_intr_wait(ehci, qh);
}
}
}
@@ -1391,21 +1416,20 @@ iso_stream_schedule (
/* Behind the scheduling threshold? */
if (unlikely(start < next)) {
+ unsigned now2 = (now - base) & (mod - 1);
/* USB_ISO_ASAP: Round up to the first available slot */
if (urb->transfer_flags & URB_ISO_ASAP)
start += (next - start + period - 1) & -period;
/*
- * Not ASAP: Use the next slot in the stream. If
- * the entire URB falls before the threshold, fail.
+ * Not ASAP: Use the next slot in the stream,
+ * no matter what.
*/
- else if (start + span - period < next) {
- ehci_dbg(ehci, "iso urb late %p (%u+%u < %u)\n",
+ else if (start + span - period < now2) {
+ ehci_dbg(ehci, "iso underrun %p (%u+%u < %u)\n",
urb, start + base,
- span - period, next + base);
- status = -EXDEV;
- goto fail;
+ span - period, now2 + base);
}
}
@@ -1574,16 +1598,9 @@ static void itd_link_urb(
next_uframe = stream->next_uframe & (mod - 1);
- if (unlikely (list_empty(&stream->td_list))) {
+ if (unlikely (list_empty(&stream->td_list)))
ehci_to_hcd(ehci)->self.bandwidth_allocated
+= stream->bandwidth;
- ehci_vdbg (ehci,
- "schedule devp %s ep%d%s-iso period %d start %d.%d\n",
- urb->dev->devpath, stream->bEndpointAddress & 0x0f,
- (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
- urb->interval,
- next_uframe >> 3, next_uframe & 0x7);
- }
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
if (ehci->amd_pll_fix == 1)
@@ -1718,14 +1735,9 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
usb_amd_quirk_pll_enable();
}
- if (unlikely(list_is_singular(&stream->td_list))) {
+ if (unlikely(list_is_singular(&stream->td_list)))
ehci_to_hcd(ehci)->self.bandwidth_allocated
-= stream->bandwidth;
- ehci_vdbg (ehci,
- "deschedule devp %s ep%d%s-iso\n",
- dev->devpath, stream->bEndpointAddress & 0x0f,
- (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
- }
done:
itd->urb = NULL;
@@ -1983,17 +1995,10 @@ static void sitd_link_urb(
next_uframe = stream->next_uframe;
- if (list_empty(&stream->td_list)) {
+ if (list_empty(&stream->td_list))
/* usbfs ignores TT bandwidth */
ehci_to_hcd(ehci)->self.bandwidth_allocated
+= stream->bandwidth;
- ehci_vdbg (ehci,
- "sched devp %s ep%d%s-iso [%d] %dms/%04x\n",
- urb->dev->devpath, stream->bEndpointAddress & 0x0f,
- (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
- (next_uframe >> 3) & (ehci->periodic_size - 1),
- stream->interval, hc32_to_cpu(ehci, stream->splits));
- }
if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
if (ehci->amd_pll_fix == 1)
@@ -2107,14 +2112,9 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
usb_amd_quirk_pll_enable();
}
- if (list_is_singular(&stream->td_list)) {
+ if (list_is_singular(&stream->td_list))
ehci_to_hcd(ehci)->self.bandwidth_allocated
-= stream->bandwidth;
- ehci_vdbg (ehci,
- "deschedule devp %s ep%d%s-iso\n",
- dev->devpath, stream->bEndpointAddress & 0x0f,
- (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
- }
done:
sitd->urb = NULL;
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
index b2de52d3961..8a734498079 100644
--- a/drivers/usb/host/ehci-sead3.c
+++ b/drivers/usb/host/ehci-sead3.c
@@ -55,7 +55,7 @@ const struct hc_driver ehci_sead3_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index c4c0ee92a39..dc899eb2b86 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -36,7 +36,7 @@ static const struct hc_driver ehci_sh_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_USB2 | HCD_MEMORY,
+ .flags = HCD_USB2 | HCD_MEMORY | HCD_BH,
/*
* basic lifecycle operations
@@ -104,7 +104,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
goto fail_create_hcd;
}
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
/* initialize hcd */
hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev,
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 6ee7ef79b4f..78fa76da332 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -25,9 +25,9 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
-#include <linux/platform_data/tegra_usb.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/usb/ehci_def.h>
@@ -51,6 +51,10 @@
static struct hc_driver __read_mostly tegra_ehci_hc_driver;
+struct tegra_ehci_soc_config {
+ bool has_hostpc;
+};
+
static int (*orig_hub_control)(struct usb_hcd *hcd,
u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
@@ -58,7 +62,6 @@ static int (*orig_hub_control)(struct usb_hcd *hcd,
struct tegra_ehci_hcd {
struct tegra_usb_phy *phy;
struct clk *clk;
- struct usb_phy *transceiver;
int port_resuming;
bool needs_double_reset;
enum tegra_usb_phy_port_speed port_speed;
@@ -322,50 +325,38 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
free_dma_aligned_buffer(urb);
}
-static int setup_vbus_gpio(struct platform_device *pdev,
- struct tegra_ehci_platform_data *pdata)
-{
- int err = 0;
- int gpio;
-
- gpio = pdata->vbus_gpio;
- if (!gpio_is_valid(gpio))
- gpio = of_get_named_gpio(pdev->dev.of_node,
- "nvidia,vbus-gpio", 0);
- if (!gpio_is_valid(gpio))
- return 0;
+static const struct tegra_ehci_soc_config tegra30_soc_config = {
+ .has_hostpc = true,
+};
- err = gpio_request(gpio, "vbus_gpio");
- if (err) {
- dev_err(&pdev->dev, "can't request vbus gpio %d", gpio);
- return err;
- }
- err = gpio_direction_output(gpio, 1);
- if (err) {
- dev_err(&pdev->dev, "can't enable vbus\n");
- return err;
- }
+static const struct tegra_ehci_soc_config tegra20_soc_config = {
+ .has_hostpc = false,
+};
- return err;
-}
+static struct of_device_id tegra_ehci_of_match[] = {
+ { .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config },
+ { .compatible = "nvidia,tegra20-ehci", .data = &tegra20_soc_config },
+ { },
+};
static int tegra_ehci_probe(struct platform_device *pdev)
{
+ const struct of_device_id *match;
+ const struct tegra_ehci_soc_config *soc_config;
struct resource *res;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct tegra_ehci_hcd *tegra;
- struct tegra_ehci_platform_data *pdata;
int err = 0;
int irq;
- struct device_node *np_phy;
struct usb_phy *u_phy;
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "Platform data missing\n");
- return -EINVAL;
+ match = of_match_device(tegra_ehci_of_match, &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "Error: No device match found\n");
+ return -ENODEV;
}
+ soc_config = match->data;
/* Right now device-tree probed devices don't get dma_mask set.
* Since shared usb code relies on it, set it here for now.
@@ -376,14 +367,11 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (!pdev->dev.coherent_dma_mask)
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- setup_vbus_gpio(pdev, pdata);
-
hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
if (!hcd) {
dev_err(&pdev->dev, "Unable to create HCD\n");
- err = -ENOMEM;
- goto cleanup_vbus_gpio;
+ return -ENOMEM;
}
platform_set_drvdata(pdev, hcd);
ehci = hcd_to_ehci(hcd);
@@ -406,13 +394,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
udelay(1);
tegra_periph_reset_deassert(tegra->clk);
- np_phy = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
- if (!np_phy) {
- err = -ENODEV;
- goto cleanup_clk_en;
- }
-
- u_phy = tegra_usb_get_phy(np_phy);
+ u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);
if (IS_ERR(u_phy)) {
err = PTR_ERR(u_phy);
goto cleanup_clk_en;
@@ -437,6 +419,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto cleanup_clk_en;
}
ehci->caps = hcd->regs + 0x100;
+ ehci->has_hostpc = soc_config->has_hostpc;
err = usb_phy_init(hcd->phy);
if (err) {
@@ -466,26 +449,18 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto cleanup_phy;
}
- if (pdata->operating_mode == TEGRA_USB_OTG) {
- tegra->transceiver =
- devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (!IS_ERR(tegra->transceiver))
- otg_set_host(tegra->transceiver->otg, &hcd->self);
- } else {
- tegra->transceiver = ERR_PTR(-ENODEV);
- }
+ otg_set_host(u_phy->otg, &hcd->self);
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
- goto cleanup_transceiver;
+ goto cleanup_otg_set_host;
}
return err;
-cleanup_transceiver:
- if (!IS_ERR(tegra->transceiver))
- otg_set_host(tegra->transceiver->otg, NULL);
+cleanup_otg_set_host:
+ otg_set_host(u_phy->otg, NULL);
cleanup_phy:
usb_phy_shutdown(hcd->phy);
cleanup_clk_en:
@@ -494,8 +469,6 @@ cleanup_clk_get:
clk_put(tegra->clk);
cleanup_hcd_create:
usb_put_hcd(hcd);
-cleanup_vbus_gpio:
- /* FIXME: Undo setup_vbus_gpio() here */
return err;
}
@@ -505,8 +478,7 @@ static int tegra_ehci_remove(struct platform_device *pdev)
struct tegra_ehci_hcd *tegra =
(struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv;
- if (!IS_ERR(tegra->transceiver))
- otg_set_host(tegra->transceiver->otg, NULL);
+ otg_set_host(hcd->phy->otg, NULL);
usb_phy_shutdown(hcd->phy);
usb_remove_hcd(hcd);
@@ -525,11 +497,6 @@ static void tegra_ehci_hcd_shutdown(struct platform_device *pdev)
hcd->driver->shutdown(hcd);
}
-static struct of_device_id tegra_ehci_of_match[] = {
- { .compatible = "nvidia,tegra20-ehci", },
- { },
-};
-
static struct platform_driver tegra_ehci_driver = {
.probe = tegra_ehci_probe,
.remove = tegra_ehci_remove,
diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c
index d72b2929c03..67026ffbf9a 100644
--- a/drivers/usb/host/ehci-tilegx.c
+++ b/drivers/usb/host/ehci-tilegx.c
@@ -61,7 +61,7 @@ static const struct hc_driver ehci_tilegx_hc_driver = {
* Generic hardware linkage.
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
/*
* Basic lifecycle operations.
@@ -101,7 +101,7 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
- struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+ struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
pte_t pte = { 0 };
int my_cpu = smp_processor_id();
int ret;
@@ -186,7 +186,7 @@ err_hcd:
static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+ struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index 11e5b32f73e..424ac5d8371 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = {
1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */
1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */
2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */
+ 5 * NSEC_PER_MSEC, /* EHCI_HRTIMER_START_UNLINK_INTR */
6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */
10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */
10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */
@@ -215,6 +216,36 @@ static void ehci_handle_controller_death(struct ehci_hcd *ehci)
/* Not in process context, so don't try to reset the controller */
}
+/* start to unlink interrupt QHs */
+static void ehci_handle_start_intr_unlinks(struct ehci_hcd *ehci)
+{
+ bool stopped = (ehci->rh_state < EHCI_RH_RUNNING);
+
+ /*
+ * Process all the QHs on the intr_unlink list that were added
+ * before the current unlink cycle began. The list is in
+ * temporal order, so stop when we reach the first entry in the
+ * current cycle. But if the root hub isn't running then
+ * process all the QHs on the list.
+ */
+ while (!list_empty(&ehci->intr_unlink_wait)) {
+ struct ehci_qh *qh;
+
+ qh = list_first_entry(&ehci->intr_unlink_wait,
+ struct ehci_qh, unlink_node);
+ if (!stopped && (qh->unlink_cycle ==
+ ehci->intr_unlink_wait_cycle))
+ break;
+ list_del_init(&qh->unlink_node);
+ start_unlink_intr(ehci, qh);
+ }
+
+ /* Handle remaining entries later */
+ if (!list_empty(&ehci->intr_unlink_wait)) {
+ ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true);
+ ++ehci->intr_unlink_wait_cycle;
+ }
+}
/* Handle unlinked interrupt QHs once they are gone from the hardware */
static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
@@ -236,7 +267,7 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
unlink_node);
if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
break;
- list_del(&qh->unlink_node);
+ list_del_init(&qh->unlink_node);
end_unlink_intr(ehci, qh);
}
@@ -363,6 +394,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = {
ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */
ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */
end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */
+ ehci_handle_start_intr_unlinks, /* EHCI_HRTIMER_START_UNLINK_INTR */
unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */
ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */
ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */
diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c
index 59e0e24c753..1c370dfbee0 100644
--- a/drivers/usb/host/ehci-w90x900.c
+++ b/drivers/usb/host/ehci-w90x900.c
@@ -108,7 +108,7 @@ static const struct hc_driver ehci_w90x900_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_USB2|HCD_MEMORY,
+ .flags = HCD_USB2|HCD_MEMORY|HCD_BH,
/*
* basic lifecycle operations
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index 35c7f90384a..95979f9f438 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -79,7 +79,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
@@ -220,21 +220,6 @@ static int ehci_hcd_xilinx_of_remove(struct platform_device *op)
return 0;
}
-/**
- * ehci_hcd_xilinx_of_shutdown - shutdown the hcd
- * @op: pointer to platform_device structure that is to be removed
- *
- * Properly shutdown the hcd, call driver's shutdown routine.
- */
-static void ehci_hcd_xilinx_of_shutdown(struct platform_device *op)
-{
- struct usb_hcd *hcd = platform_get_drvdata(op);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
-}
-
-
static const struct of_device_id ehci_hcd_xilinx_of_match[] = {
{.compatible = "xlnx,xps-usb-host-1.00.a",},
{},
@@ -244,7 +229,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_xilinx_of_match);
static struct platform_driver ehci_hcd_xilinx_of_driver = {
.probe = ehci_hcd_xilinx_of_probe,
.remove = ehci_hcd_xilinx_of_remove,
- .shutdown = ehci_hcd_xilinx_of_shutdown,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "xilinx-of-ehci",
.owner = THIS_MODULE,
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 64f9a08e959..291db7d09f2 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -38,7 +38,7 @@ typedef __u16 __bitwise __hc16;
#endif
/* statistics can be kept for tuning/monitoring */
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
#define EHCI_STATS
#endif
@@ -88,6 +88,7 @@ enum ehci_hrtimer_event {
EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
+ EHCI_HRTIMER_START_UNLINK_INTR, /* Unlink empty interrupt QHs */
EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
@@ -143,7 +144,9 @@ struct ehci_hcd { /* one per controller */
unsigned i_thresh; /* uframes HC might cache */
union ehci_shadow *pshadow; /* mirror hw periodic table */
+ struct list_head intr_unlink_wait;
struct list_head intr_unlink;
+ unsigned intr_unlink_wait_cycle;
unsigned intr_unlink_cycle;
unsigned now_frame; /* frame from HC hardware */
unsigned last_iso_frame; /* last frame scanned for iso */
@@ -210,6 +213,7 @@ struct ehci_hcd { /* one per controller */
#define OHCI_HCCTRL_LEN 0x4
__hc32 *ohci_hcctrl_reg;
unsigned has_hostpc:1;
+ unsigned has_tdi_phy_lpm:1;
unsigned has_ppcd:1; /* support per-port change bits */
u8 sbrn; /* packed release number */
@@ -222,7 +226,7 @@ struct ehci_hcd { /* one per controller */
#endif
/* debug files */
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
struct dentry *debug_dir;
#endif
@@ -778,15 +782,10 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
#define ehci_warn(ehci, fmt, args...) \
dev_warn(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
-#ifdef VERBOSE_DEBUG
-# define ehci_vdbg ehci_dbg
-#else
- static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {}
-#endif
-#ifndef DEBUG
+#if !defined(DEBUG) && !defined(CONFIG_DYNAMIC_DEBUG)
#define STUB_DEBUG_FILES
-#endif /* DEBUG */
+#endif /* !DEBUG && !CONFIG_DYNAMIC_DEBUG */
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
new file mode 100644
index 00000000000..fce13bcc4a3
--- /dev/null
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -0,0 +1,6049 @@
+/*
+ * Faraday FOTG210 EHCI-like driver
+ *
+ * Copyright (c) 2013 Faraday Technology Corporation
+ *
+ * Author: Yuan-Hsin Chen <yhchen@faraday-tech.com>
+ * Feng-Hsin Chiang <john453@faraday-tech.com>
+ * Po-Yu Chuang <ratbert.chuang@gmail.com>
+ *
+ * Most of code borrowed from the Linux-3.7 EHCI driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/unaligned.h>
+
+/*-------------------------------------------------------------------------*/
+#define DRIVER_AUTHOR "Yuan-Hsin Chen"
+#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver"
+
+static const char hcd_name[] = "fotg210_hcd";
+
+#undef VERBOSE_DEBUG
+#undef FOTG210_URB_TRACE
+
+#ifdef DEBUG
+#define FOTG210_STATS
+#endif
+
+/* magic numbers that can affect system performance */
+#define FOTG210_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
+#define FOTG210_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
+#define FOTG210_TUNE_RL_TT 0
+#define FOTG210_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
+#define FOTG210_TUNE_MULT_TT 1
+/*
+ * Some drivers think it's safe to schedule isochronous transfers more than
+ * 256 ms into the future (partly as a result of an old bug in the scheduling
+ * code). In an attempt to avoid trouble, we will use a minimum scheduling
+ * length of 512 frames instead of 256.
+ */
+#define FOTG210_TUNE_FLS 1 /* (medium) 512-frame schedule */
+
+/* Initial IRQ latency: faster than hw default */
+static int log2_irq_thresh; /* 0 to 6 */
+module_param(log2_irq_thresh, int, S_IRUGO);
+MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
+
+/* initial park setting: slower than hw default */
+static unsigned park;
+module_param(park, uint, S_IRUGO);
+MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets");
+
+/* for link power management(LPM) feature */
+static unsigned int hird;
+module_param(hird, int, S_IRUGO);
+MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
+
+#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
+
+#include "fotg210.h"
+
+/*-------------------------------------------------------------------------*/
+
+#define fotg210_dbg(fotg210, fmt, args...) \
+ dev_dbg(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+#define fotg210_err(fotg210, fmt, args...) \
+ dev_err(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+#define fotg210_info(fotg210, fmt, args...) \
+ dev_info(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+#define fotg210_warn(fotg210, fmt, args...) \
+ dev_warn(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+
+#ifdef VERBOSE_DEBUG
+# define fotg210_vdbg fotg210_dbg
+#else
+ static inline void fotg210_vdbg(struct fotg210_hcd *fotg210, ...) {}
+#endif
+
+#ifdef DEBUG
+
+/* check the values in the HCSPARAMS register
+ * (host controller _Structural_ parameters)
+ * see EHCI spec, Table 2-4 for each value
+ */
+static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label)
+{
+ u32 params = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
+
+ fotg210_dbg(fotg210,
+ "%s hcs_params 0x%x ports=%d\n",
+ label, params,
+ HCS_N_PORTS(params)
+ );
+}
+#else
+
+static inline void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label) {}
+
+#endif
+
+#ifdef DEBUG
+
+/* check the values in the HCCPARAMS register
+ * (host controller _Capability_ parameters)
+ * see EHCI Spec, Table 2-5 for each value
+ * */
+static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label)
+{
+ u32 params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+
+ fotg210_dbg(fotg210,
+ "%s hcc_params %04x uframes %s%s\n",
+ label,
+ params,
+ HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
+ HCC_CANPARK(params) ? " park" : "");
+}
+#else
+
+static inline void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label) {}
+
+#endif
+
+#ifdef DEBUG
+
+static void __maybe_unused
+dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd)
+{
+ fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
+ hc32_to_cpup(fotg210, &qtd->hw_next),
+ hc32_to_cpup(fotg210, &qtd->hw_alt_next),
+ hc32_to_cpup(fotg210, &qtd->hw_token),
+ hc32_to_cpup(fotg210, &qtd->hw_buf[0]));
+ if (qtd->hw_buf[1])
+ fotg210_dbg(fotg210, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
+ hc32_to_cpup(fotg210, &qtd->hw_buf[1]),
+ hc32_to_cpup(fotg210, &qtd->hw_buf[2]),
+ hc32_to_cpup(fotg210, &qtd->hw_buf[3]),
+ hc32_to_cpup(fotg210, &qtd->hw_buf[4]));
+}
+
+static void __maybe_unused
+dbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+ struct fotg210_qh_hw *hw = qh->hw;
+
+ fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label,
+ qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current);
+ dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next);
+}
+
+static void __maybe_unused
+dbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
+{
+ fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n",
+ label, itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next),
+ itd->urb);
+ fotg210_dbg(fotg210,
+ " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ hc32_to_cpu(fotg210, itd->hw_transaction[0]),
+ hc32_to_cpu(fotg210, itd->hw_transaction[1]),
+ hc32_to_cpu(fotg210, itd->hw_transaction[2]),
+ hc32_to_cpu(fotg210, itd->hw_transaction[3]),
+ hc32_to_cpu(fotg210, itd->hw_transaction[4]),
+ hc32_to_cpu(fotg210, itd->hw_transaction[5]),
+ hc32_to_cpu(fotg210, itd->hw_transaction[6]),
+ hc32_to_cpu(fotg210, itd->hw_transaction[7]));
+ fotg210_dbg(fotg210,
+ " buf: %08x %08x %08x %08x %08x %08x %08x\n",
+ hc32_to_cpu(fotg210, itd->hw_bufp[0]),
+ hc32_to_cpu(fotg210, itd->hw_bufp[1]),
+ hc32_to_cpu(fotg210, itd->hw_bufp[2]),
+ hc32_to_cpu(fotg210, itd->hw_bufp[3]),
+ hc32_to_cpu(fotg210, itd->hw_bufp[4]),
+ hc32_to_cpu(fotg210, itd->hw_bufp[5]),
+ hc32_to_cpu(fotg210, itd->hw_bufp[6]));
+ fotg210_dbg(fotg210, " index: %d %d %d %d %d %d %d %d\n",
+ itd->index[0], itd->index[1], itd->index[2],
+ itd->index[3], itd->index[4], itd->index[5],
+ itd->index[6], itd->index[7]);
+}
+
+static int __maybe_unused
+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
+{
+ return scnprintf(buf, len,
+ "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
+ label, label[0] ? " " : "", status,
+ (status & STS_ASS) ? " Async" : "",
+ (status & STS_PSS) ? " Periodic" : "",
+ (status & STS_RECL) ? " Recl" : "",
+ (status & STS_HALT) ? " Halt" : "",
+ (status & STS_IAA) ? " IAA" : "",
+ (status & STS_FATAL) ? " FATAL" : "",
+ (status & STS_FLR) ? " FLR" : "",
+ (status & STS_PCD) ? " PCD" : "",
+ (status & STS_ERR) ? " ERR" : "",
+ (status & STS_INT) ? " INT" : ""
+ );
+}
+
+static int __maybe_unused
+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
+{
+ return scnprintf(buf, len,
+ "%s%sintrenable %02x%s%s%s%s%s%s",
+ label, label[0] ? " " : "", enable,
+ (enable & STS_IAA) ? " IAA" : "",
+ (enable & STS_FATAL) ? " FATAL" : "",
+ (enable & STS_FLR) ? " FLR" : "",
+ (enable & STS_PCD) ? " PCD" : "",
+ (enable & STS_ERR) ? " ERR" : "",
+ (enable & STS_INT) ? " INT" : ""
+ );
+}
+
+static const char *const fls_strings[] = { "1024", "512", "256", "??" };
+
+static int
+dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
+{
+ return scnprintf(buf, len,
+ "%s%scommand %07x %s=%d ithresh=%d%s%s%s "
+ "period=%s%s %s",
+ label, label[0] ? " " : "", command,
+ (command & CMD_PARK) ? " park" : "(park)",
+ CMD_PARK_CNT(command),
+ (command >> 16) & 0x3f,
+ (command & CMD_IAAD) ? " IAAD" : "",
+ (command & CMD_ASE) ? " Async" : "",
+ (command & CMD_PSE) ? " Periodic" : "",
+ fls_strings[(command >> 2) & 0x3],
+ (command & CMD_RESET) ? " Reset" : "",
+ (command & CMD_RUN) ? "RUN" : "HALT"
+ );
+}
+
+static int
+dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
+{
+ char *sig;
+
+ /* signaling state */
+ switch (status & (3 << 10)) {
+ case 0 << 10:
+ sig = "se0";
+ break;
+ case 1 << 10:
+ sig = "k";
+ break; /* low speed */
+ case 2 << 10:
+ sig = "j";
+ break;
+ default:
+ sig = "?";
+ break;
+ }
+
+ return scnprintf(buf, len,
+ "%s%sport:%d status %06x %d "
+ "sig=%s%s%s%s%s%s%s%s",
+ label, label[0] ? " " : "", port, status,
+ status>>25,/*device address */
+ sig,
+ (status & PORT_RESET) ? " RESET" : "",
+ (status & PORT_SUSPEND) ? " SUSPEND" : "",
+ (status & PORT_RESUME) ? " RESUME" : "",
+ (status & PORT_PEC) ? " PEC" : "",
+ (status & PORT_PE) ? " PE" : "",
+ (status & PORT_CSC) ? " CSC" : "",
+ (status & PORT_CONNECT) ? " CONNECT" : "");
+}
+
+#else
+static inline void __maybe_unused
+dbg_qh(char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{}
+
+static inline int __maybe_unused
+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
+{ return 0; }
+
+static inline int __maybe_unused
+dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
+{ return 0; }
+
+static inline int __maybe_unused
+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
+{ return 0; }
+
+static inline int __maybe_unused
+dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
+{ return 0; }
+
+#endif /* DEBUG */
+
+/* functions have the "wrong" filename when they're output... */
+#define dbg_status(fotg210, label, status) { \
+ char _buf[80]; \
+ dbg_status_buf(_buf, sizeof(_buf), label, status); \
+ fotg210_dbg(fotg210, "%s\n", _buf); \
+}
+
+#define dbg_cmd(fotg210, label, command) { \
+ char _buf[80]; \
+ dbg_command_buf(_buf, sizeof(_buf), label, command); \
+ fotg210_dbg(fotg210, "%s\n", _buf); \
+}
+
+#define dbg_port(fotg210, label, port, status) { \
+ char _buf[80]; \
+ dbg_port_buf(_buf, sizeof(_buf), label, port, status); \
+ fotg210_dbg(fotg210, "%s\n", _buf); \
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILES
+
+static inline void create_debug_files(struct fotg210_hcd *bus) { }
+static inline void remove_debug_files(struct fotg210_hcd *bus) { }
+
+#else
+
+/* troubleshooting help: expose state in debugfs */
+
+static int debug_async_open(struct inode *, struct file *);
+static int debug_periodic_open(struct inode *, struct file *);
+static int debug_registers_open(struct inode *, struct file *);
+static int debug_async_open(struct inode *, struct file *);
+
+static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
+static int debug_close(struct inode *, struct file *);
+
+static const struct file_operations debug_async_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_async_open,
+ .read = debug_output,
+ .release = debug_close,
+ .llseek = default_llseek,
+};
+static const struct file_operations debug_periodic_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_periodic_open,
+ .read = debug_output,
+ .release = debug_close,
+ .llseek = default_llseek,
+};
+static const struct file_operations debug_registers_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_registers_open,
+ .read = debug_output,
+ .release = debug_close,
+ .llseek = default_llseek,
+};
+
+static struct dentry *fotg210_debug_root;
+
+struct debug_buffer {
+ ssize_t (*fill_func)(struct debug_buffer *); /* fill method */
+ struct usb_bus *bus;
+ struct mutex mutex; /* protect filling of buffer */
+ size_t count; /* number of characters filled into buffer */
+ char *output_buf;
+ size_t alloc_size;
+};
+
+#define speed_char(info1)({ char tmp; \
+ switch (info1 & (3 << 12)) { \
+ case QH_FULL_SPEED: \
+ tmp = 'f'; break; \
+ case QH_LOW_SPEED: \
+ tmp = 'l'; break; \
+ case QH_HIGH_SPEED: \
+ tmp = 'h'; break; \
+ default: \
+ tmp = '?'; break; \
+ }; tmp; })
+
+static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token)
+{
+ __u32 v = hc32_to_cpu(fotg210, token);
+
+ if (v & QTD_STS_ACTIVE)
+ return '*';
+ if (v & QTD_STS_HALT)
+ return '-';
+ if (!IS_SHORT_READ(v))
+ return ' ';
+ /* tries to advance through hw_alt_next */
+ return '/';
+}
+
+static void qh_lines(
+ struct fotg210_hcd *fotg210,
+ struct fotg210_qh *qh,
+ char **nextp,
+ unsigned *sizep
+)
+{
+ u32 scratch;
+ u32 hw_curr;
+ struct fotg210_qtd *td;
+ unsigned temp;
+ unsigned size = *sizep;
+ char *next = *nextp;
+ char mark;
+ __le32 list_end = FOTG210_LIST_END(fotg210);
+ struct fotg210_qh_hw *hw = qh->hw;
+
+ if (hw->hw_qtd_next == list_end) /* NEC does this */
+ mark = '@';
+ else
+ mark = token_mark(fotg210, hw->hw_token);
+ if (mark == '/') { /* qh_alt_next controls qh advance? */
+ if ((hw->hw_alt_next & QTD_MASK(fotg210))
+ == fotg210->async->hw->hw_alt_next)
+ mark = '#'; /* blocked */
+ else if (hw->hw_alt_next == list_end)
+ mark = '.'; /* use hw_qtd_next */
+ /* else alt_next points to some other qtd */
+ }
+ scratch = hc32_to_cpup(fotg210, &hw->hw_info1);
+ hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0;
+ temp = scnprintf(next, size,
+ "qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)",
+ qh, scratch & 0x007f,
+ speed_char(scratch),
+ (scratch >> 8) & 0x000f,
+ scratch, hc32_to_cpup(fotg210, &hw->hw_info2),
+ hc32_to_cpup(fotg210, &hw->hw_token), mark,
+ (cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token)
+ ? "data1" : "data0",
+ (hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f);
+ size -= temp;
+ next += temp;
+
+ /* hc may be modifying the list as we read it ... */
+ list_for_each_entry(td, &qh->qtd_list, qtd_list) {
+ scratch = hc32_to_cpup(fotg210, &td->hw_token);
+ mark = ' ';
+ if (hw_curr == td->qtd_dma)
+ mark = '*';
+ else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma))
+ mark = '+';
+ else if (QTD_LENGTH(scratch)) {
+ if (td->hw_alt_next == fotg210->async->hw->hw_alt_next)
+ mark = '#';
+ else if (td->hw_alt_next != list_end)
+ mark = '/';
+ }
+ temp = snprintf(next, size,
+ "\n\t%p%c%s len=%d %08x urb %p",
+ td, mark, ({ char *tmp;
+ switch ((scratch>>8)&0x03) {
+ case 0:
+ tmp = "out";
+ break;
+ case 1:
+ tmp = "in";
+ break;
+ case 2:
+ tmp = "setup";
+ break;
+ default:
+ tmp = "?";
+ break;
+ } tmp; }),
+ (scratch >> 16) & 0x7fff,
+ scratch,
+ td->urb);
+ if (size < temp)
+ temp = size;
+ size -= temp;
+ next += temp;
+ if (temp == size)
+ goto done;
+ }
+
+ temp = snprintf(next, size, "\n");
+ if (size < temp)
+ temp = size;
+ size -= temp;
+ next += temp;
+
+done:
+ *sizep = size;
+ *nextp = next;
+}
+
+static ssize_t fill_async_buffer(struct debug_buffer *buf)
+{
+ struct usb_hcd *hcd;
+ struct fotg210_hcd *fotg210;
+ unsigned long flags;
+ unsigned temp, size;
+ char *next;
+ struct fotg210_qh *qh;
+
+ hcd = bus_to_hcd(buf->bus);
+ fotg210 = hcd_to_fotg210(hcd);
+ next = buf->output_buf;
+ size = buf->alloc_size;
+
+ *next = 0;
+
+ /* dumps a snapshot of the async schedule.
+ * usually empty except for long-term bulk reads, or head.
+ * one QH per line, and TDs we know about
+ */
+ spin_lock_irqsave(&fotg210->lock, flags);
+ for (qh = fotg210->async->qh_next.qh; size > 0 && qh;
+ qh = qh->qh_next.qh)
+ qh_lines(fotg210, qh, &next, &size);
+ if (fotg210->async_unlink && size > 0) {
+ temp = scnprintf(next, size, "\nunlink =\n");
+ size -= temp;
+ next += temp;
+
+ for (qh = fotg210->async_unlink; size > 0 && qh;
+ qh = qh->unlink_next)
+ qh_lines(fotg210, qh, &next, &size);
+ }
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+
+ return strlen(buf->output_buf);
+}
+
+#define DBG_SCHED_LIMIT 64
+static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
+{
+ struct usb_hcd *hcd;
+ struct fotg210_hcd *fotg210;
+ unsigned long flags;
+ union fotg210_shadow p, *seen;
+ unsigned temp, size, seen_count;
+ char *next;
+ unsigned i;
+ __hc32 tag;
+
+ seen = kmalloc(DBG_SCHED_LIMIT * sizeof(*seen), GFP_ATOMIC);
+ if (!seen)
+ return 0;
+ seen_count = 0;
+
+ hcd = bus_to_hcd(buf->bus);
+ fotg210 = hcd_to_fotg210(hcd);
+ next = buf->output_buf;
+ size = buf->alloc_size;
+
+ temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size);
+ size -= temp;
+ next += temp;
+
+ /* dump a snapshot of the periodic schedule.
+ * iso changes, interrupt usually doesn't.
+ */
+ spin_lock_irqsave(&fotg210->lock, flags);
+ for (i = 0; i < fotg210->periodic_size; i++) {
+ p = fotg210->pshadow[i];
+ if (likely(!p.ptr))
+ continue;
+ tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]);
+
+ temp = scnprintf(next, size, "%4d: ", i);
+ size -= temp;
+ next += temp;
+
+ do {
+ struct fotg210_qh_hw *hw;
+
+ switch (hc32_to_cpu(fotg210, tag)) {
+ case Q_TYPE_QH:
+ hw = p.qh->hw;
+ temp = scnprintf(next, size, " qh%d-%04x/%p",
+ p.qh->period,
+ hc32_to_cpup(fotg210,
+ &hw->hw_info2)
+ /* uframe masks */
+ & (QH_CMASK | QH_SMASK),
+ p.qh);
+ size -= temp;
+ next += temp;
+ /* don't repeat what follows this qh */
+ for (temp = 0; temp < seen_count; temp++) {
+ if (seen[temp].ptr != p.ptr)
+ continue;
+ if (p.qh->qh_next.ptr) {
+ temp = scnprintf(next, size,
+ " ...");
+ size -= temp;
+ next += temp;
+ }
+ break;
+ }
+ /* show more info the first time around */
+ if (temp == seen_count) {
+ u32 scratch = hc32_to_cpup(fotg210,
+ &hw->hw_info1);
+ struct fotg210_qtd *qtd;
+ char *type = "";
+
+ /* count tds, get ep direction */
+ temp = 0;
+ list_for_each_entry(qtd,
+ &p.qh->qtd_list,
+ qtd_list) {
+ temp++;
+ switch (0x03 & (hc32_to_cpu(
+ fotg210,
+ qtd->hw_token) >> 8)) {
+ case 0:
+ type = "out";
+ continue;
+ case 1:
+ type = "in";
+ continue;
+ }
+ }
+
+ temp = scnprintf(next, size,
+ "(%c%d ep%d%s "
+ "[%d/%d] q%d p%d)",
+ speed_char(scratch),
+ scratch & 0x007f,
+ (scratch >> 8) & 0x000f, type,
+ p.qh->usecs, p.qh->c_usecs,
+ temp,
+ 0x7ff & (scratch >> 16));
+
+ if (seen_count < DBG_SCHED_LIMIT)
+ seen[seen_count++].qh = p.qh;
+ } else
+ temp = 0;
+ tag = Q_NEXT_TYPE(fotg210, hw->hw_next);
+ p = p.qh->qh_next;
+ break;
+ case Q_TYPE_FSTN:
+ temp = scnprintf(next, size,
+ " fstn-%8x/%p", p.fstn->hw_prev,
+ p.fstn);
+ tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next);
+ p = p.fstn->fstn_next;
+ break;
+ case Q_TYPE_ITD:
+ temp = scnprintf(next, size,
+ " itd/%p", p.itd);
+ tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next);
+ p = p.itd->itd_next;
+ break;
+ }
+ size -= temp;
+ next += temp;
+ } while (p.ptr);
+
+ temp = scnprintf(next, size, "\n");
+ size -= temp;
+ next += temp;
+ }
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ kfree(seen);
+
+ return buf->alloc_size - size;
+}
+#undef DBG_SCHED_LIMIT
+
+static const char *rh_state_string(struct fotg210_hcd *fotg210)
+{
+ switch (fotg210->rh_state) {
+ case FOTG210_RH_HALTED:
+ return "halted";
+ case FOTG210_RH_SUSPENDED:
+ return "suspended";
+ case FOTG210_RH_RUNNING:
+ return "running";
+ case FOTG210_RH_STOPPING:
+ return "stopping";
+ }
+ return "?";
+}
+
+static ssize_t fill_registers_buffer(struct debug_buffer *buf)
+{
+ struct usb_hcd *hcd;
+ struct fotg210_hcd *fotg210;
+ unsigned long flags;
+ unsigned temp, size, i;
+ char *next, scratch[80];
+ static const char fmt[] = "%*s\n";
+ static const char label[] = "";
+
+ hcd = bus_to_hcd(buf->bus);
+ fotg210 = hcd_to_fotg210(hcd);
+ next = buf->output_buf;
+ size = buf->alloc_size;
+
+ spin_lock_irqsave(&fotg210->lock, flags);
+
+ if (!HCD_HW_ACCESSIBLE(hcd)) {
+ size = scnprintf(next, size,
+ "bus %s, device %s\n"
+ "%s\n"
+ "SUSPENDED(no register access)\n",
+ hcd->self.controller->bus->name,
+ dev_name(hcd->self.controller),
+ hcd->product_desc);
+ goto done;
+ }
+
+ /* Capability Registers */
+ i = HC_VERSION(fotg210, fotg210_readl(fotg210,
+ &fotg210->caps->hc_capbase));
+ temp = scnprintf(next, size,
+ "bus %s, device %s\n"
+ "%s\n"
+ "EHCI %x.%02x, rh state %s\n",
+ hcd->self.controller->bus->name,
+ dev_name(hcd->self.controller),
+ hcd->product_desc,
+ i >> 8, i & 0x0ff, rh_state_string(fotg210));
+ size -= temp;
+ next += temp;
+
+ /* FIXME interpret both types of params */
+ i = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
+ temp = scnprintf(next, size, "structural params 0x%08x\n", i);
+ size -= temp;
+ next += temp;
+
+ i = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+ temp = scnprintf(next, size, "capability params 0x%08x\n", i);
+ size -= temp;
+ next += temp;
+
+ /* Operational Registers */
+ temp = dbg_status_buf(scratch, sizeof(scratch), label,
+ fotg210_readl(fotg210, &fotg210->regs->status));
+ temp = scnprintf(next, size, fmt, temp, scratch);
+ size -= temp;
+ next += temp;
+
+ temp = dbg_command_buf(scratch, sizeof(scratch), label,
+ fotg210_readl(fotg210, &fotg210->regs->command));
+ temp = scnprintf(next, size, fmt, temp, scratch);
+ size -= temp;
+ next += temp;
+
+ temp = dbg_intr_buf(scratch, sizeof(scratch), label,
+ fotg210_readl(fotg210, &fotg210->regs->intr_enable));
+ temp = scnprintf(next, size, fmt, temp, scratch);
+ size -= temp;
+ next += temp;
+
+ temp = scnprintf(next, size, "uframe %04x\n",
+ fotg210_read_frame_index(fotg210));
+ size -= temp;
+ next += temp;
+
+ if (fotg210->async_unlink) {
+ temp = scnprintf(next, size, "async unlink qh %p\n",
+ fotg210->async_unlink);
+ size -= temp;
+ next += temp;
+ }
+
+#ifdef FOTG210_STATS
+ temp = scnprintf(next, size,
+ "irq normal %ld err %ld iaa %ld(lost %ld)\n",
+ fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa,
+ fotg210->stats.lost_iaa);
+ size -= temp;
+ next += temp;
+
+ temp = scnprintf(next, size, "complete %ld unlink %ld\n",
+ fotg210->stats.complete, fotg210->stats.unlink);
+ size -= temp;
+ next += temp;
+#endif
+
+done:
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+
+ return buf->alloc_size - size;
+}
+
+static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
+ ssize_t (*fill_func)(struct debug_buffer *))
+{
+ struct debug_buffer *buf;
+
+ buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
+
+ if (buf) {
+ buf->bus = bus;
+ buf->fill_func = fill_func;
+ mutex_init(&buf->mutex);
+ buf->alloc_size = PAGE_SIZE;
+ }
+
+ return buf;
+}
+
+static int fill_buffer(struct debug_buffer *buf)
+{
+ int ret = 0;
+
+ if (!buf->output_buf)
+ buf->output_buf = vmalloc(buf->alloc_size);
+
+ if (!buf->output_buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = buf->fill_func(buf);
+
+ if (ret >= 0) {
+ buf->count = ret;
+ ret = 0;
+ }
+
+out:
+ return ret;
+}
+
+static ssize_t debug_output(struct file *file, char __user *user_buf,
+ size_t len, loff_t *offset)
+{
+ struct debug_buffer *buf = file->private_data;
+ int ret = 0;
+
+ mutex_lock(&buf->mutex);
+ if (buf->count == 0) {
+ ret = fill_buffer(buf);
+ if (ret != 0) {
+ mutex_unlock(&buf->mutex);
+ goto out;
+ }
+ }
+ mutex_unlock(&buf->mutex);
+
+ ret = simple_read_from_buffer(user_buf, len, offset,
+ buf->output_buf, buf->count);
+
+out:
+ return ret;
+
+}
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+ struct debug_buffer *buf = file->private_data;
+
+ if (buf) {
+ vfree(buf->output_buf);
+ kfree(buf);
+ }
+
+ return 0;
+}
+static int debug_async_open(struct inode *inode, struct file *file)
+{
+ file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
+
+ return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_periodic_open(struct inode *inode, struct file *file)
+{
+ struct debug_buffer *buf;
+ buf = alloc_buffer(inode->i_private, fill_periodic_buffer);
+ if (!buf)
+ return -ENOMEM;
+
+ buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
+ file->private_data = buf;
+ return 0;
+}
+
+static int debug_registers_open(struct inode *inode, struct file *file)
+{
+ file->private_data = alloc_buffer(inode->i_private,
+ fill_registers_buffer);
+
+ return file->private_data ? 0 : -ENOMEM;
+}
+
+static inline void create_debug_files(struct fotg210_hcd *fotg210)
+{
+ struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
+
+ fotg210->debug_dir = debugfs_create_dir(bus->bus_name,
+ fotg210_debug_root);
+ if (!fotg210->debug_dir)
+ return;
+
+ if (!debugfs_create_file("async", S_IRUGO, fotg210->debug_dir, bus,
+ &debug_async_fops))
+ goto file_error;
+
+ if (!debugfs_create_file("periodic", S_IRUGO, fotg210->debug_dir, bus,
+ &debug_periodic_fops))
+ goto file_error;
+
+ if (!debugfs_create_file("registers", S_IRUGO, fotg210->debug_dir, bus,
+ &debug_registers_fops))
+ goto file_error;
+
+ return;
+
+file_error:
+ debugfs_remove_recursive(fotg210->debug_dir);
+}
+
+static inline void remove_debug_files(struct fotg210_hcd *fotg210)
+{
+ debugfs_remove_recursive(fotg210->debug_dir);
+}
+
+#endif /* STUB_DEBUG_FILES */
+/*-------------------------------------------------------------------------*/
+
+/*
+ * handshake - spin reading hc until handshake completes or fails
+ * @ptr: address of hc register to be read
+ * @mask: bits to look at in result of read
+ * @done: value of those bits when handshake succeeds
+ * @usec: timeout in microseconds
+ *
+ * Returns negative errno, or zero on success
+ *
+ * Success happens when the "mask" bits have the specified value (hardware
+ * handshake done). There are two failure modes: "usec" have passed (major
+ * hardware flakeout), or the register reads as all-ones (hardware removed).
+ *
+ * That last failure should_only happen in cases like physical cardbus eject
+ * before driver shutdown. But it also seems to be caused by bugs in cardbus
+ * bridge shutdown: shutting down the bridge before the devices using it.
+ */
+static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
+{
+ u32 result;
+
+ do {
+ result = fotg210_readl(fotg210, ptr);
+ if (result == ~(u32)0) /* card removed */
+ return -ENODEV;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay(1);
+ usec--;
+ } while (usec > 0);
+ return -ETIMEDOUT;
+}
+
+/*
+ * Force HC to halt state from unknown (EHCI spec section 2.3).
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static int fotg210_halt(struct fotg210_hcd *fotg210)
+{
+ u32 temp;
+
+ spin_lock_irq(&fotg210->lock);
+
+ /* disable any irqs left enabled by previous code */
+ fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
+
+ /*
+ * This routine gets called during probe before fotg210->command
+ * has been initialized, so we can't rely on its value.
+ */
+ fotg210->command &= ~CMD_RUN;
+ temp = fotg210_readl(fotg210, &fotg210->regs->command);
+ temp &= ~(CMD_RUN | CMD_IAAD);
+ fotg210_writel(fotg210, temp, &fotg210->regs->command);
+
+ spin_unlock_irq(&fotg210->lock);
+ synchronize_irq(fotg210_to_hcd(fotg210)->irq);
+
+ return handshake(fotg210, &fotg210->regs->status,
+ STS_HALT, STS_HALT, 16 * 125);
+}
+
+/*
+ * Reset a non-running (STS_HALT == 1) controller.
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static int fotg210_reset(struct fotg210_hcd *fotg210)
+{
+ int retval;
+ u32 command = fotg210_readl(fotg210, &fotg210->regs->command);
+
+ /* If the EHCI debug controller is active, special care must be
+ * taken before and after a host controller reset */
+ if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210)))
+ fotg210->debug = NULL;
+
+ command |= CMD_RESET;
+ dbg_cmd(fotg210, "reset", command);
+ fotg210_writel(fotg210, command, &fotg210->regs->command);
+ fotg210->rh_state = FOTG210_RH_HALTED;
+ fotg210->next_statechange = jiffies;
+ retval = handshake(fotg210, &fotg210->regs->command,
+ CMD_RESET, 0, 250 * 1000);
+
+ if (retval)
+ return retval;
+
+ if (fotg210->debug)
+ dbgp_external_startup(fotg210_to_hcd(fotg210));
+
+ fotg210->port_c_suspend = fotg210->suspended_ports =
+ fotg210->resuming_ports = 0;
+ return retval;
+}
+
+/*
+ * Idle the controller (turn off the schedules).
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static void fotg210_quiesce(struct fotg210_hcd *fotg210)
+{
+ u32 temp;
+
+ if (fotg210->rh_state != FOTG210_RH_RUNNING)
+ return;
+
+ /* wait for any schedule enables/disables to take effect */
+ temp = (fotg210->command << 10) & (STS_ASS | STS_PSS);
+ handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp,
+ 16 * 125);
+
+ /* then disable anything that's still active */
+ spin_lock_irq(&fotg210->lock);
+ fotg210->command &= ~(CMD_ASE | CMD_PSE);
+ fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+ spin_unlock_irq(&fotg210->lock);
+
+ /* hardware can take 16 microframes to turn off ... */
+ handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0,
+ 16 * 125);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void end_unlink_async(struct fotg210_hcd *fotg210);
+static void unlink_empty_async(struct fotg210_hcd *fotg210);
+static void fotg210_work(struct fotg210_hcd *fotg210);
+static void start_unlink_intr(struct fotg210_hcd *fotg210,
+ struct fotg210_qh *qh);
+static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
+
+/*-------------------------------------------------------------------------*/
+
+/* Set a bit in the USBCMD register */
+static void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit)
+{
+ fotg210->command |= bit;
+ fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+
+ /* unblock posted write */
+ fotg210_readl(fotg210, &fotg210->regs->command);
+}
+
+/* Clear a bit in the USBCMD register */
+static void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit)
+{
+ fotg210->command &= ~bit;
+ fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+
+ /* unblock posted write */
+ fotg210_readl(fotg210, &fotg210->regs->command);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI timer support... Now using hrtimers.
+ *
+ * Lots of different events are triggered from fotg210->hrtimer. Whenever
+ * the timer routine runs, it checks each possible event; events that are
+ * currently enabled and whose expiration time has passed get handled.
+ * The set of enabled events is stored as a collection of bitflags in
+ * fotg210->enabled_hrtimer_events, and they are numbered in order of
+ * increasing delay values (ranging between 1 ms and 100 ms).
+ *
+ * Rather than implementing a sorted list or tree of all pending events,
+ * we keep track only of the lowest-numbered pending event, in
+ * fotg210->next_hrtimer_event. Whenever fotg210->hrtimer gets restarted, its
+ * expiration time is set to the timeout value for this event.
+ *
+ * As a result, events might not get handled right away; the actual delay
+ * could be anywhere up to twice the requested delay. This doesn't
+ * matter, because none of the events are especially time-critical. The
+ * ones that matter most all have a delay of 1 ms, so they will be
+ * handled after 2 ms at most, which is okay. In addition to this, we
+ * allow for an expiration range of 1 ms.
+ */
+
+/*
+ * Delay lengths for the hrtimer event types.
+ * Keep this list sorted by delay length, in the same order as
+ * the event types indexed by enum fotg210_hrtimer_event in fotg210.h.
+ */
+static unsigned event_delays_ns[] = {
+ 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_ASS */
+ 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_PSS */
+ 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_DEAD */
+ 1125 * NSEC_PER_USEC, /* FOTG210_HRTIMER_UNLINK_INTR */
+ 2 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_FREE_ITDS */
+ 6 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_ASYNC_UNLINKS */
+ 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IAA_WATCHDOG */
+ 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_PERIODIC */
+ 15 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_ASYNC */
+ 100 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IO_WATCHDOG */
+};
+
+/* Enable a pending hrtimer event */
+static void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event,
+ bool resched)
+{
+ ktime_t *timeout = &fotg210->hr_timeouts[event];
+
+ if (resched)
+ *timeout = ktime_add(ktime_get(),
+ ktime_set(0, event_delays_ns[event]));
+ fotg210->enabled_hrtimer_events |= (1 << event);
+
+ /* Track only the lowest-numbered pending event */
+ if (event < fotg210->next_hrtimer_event) {
+ fotg210->next_hrtimer_event = event;
+ hrtimer_start_range_ns(&fotg210->hrtimer, *timeout,
+ NSEC_PER_MSEC, HRTIMER_MODE_ABS);
+ }
+}
+
+
+/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
+static void fotg210_poll_ASS(struct fotg210_hcd *fotg210)
+{
+ unsigned actual, want;
+
+ /* Don't enable anything if the controller isn't running (e.g., died) */
+ if (fotg210->rh_state != FOTG210_RH_RUNNING)
+ return;
+
+ want = (fotg210->command & CMD_ASE) ? STS_ASS : 0;
+ actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS;
+
+ if (want != actual) {
+
+ /* Poll again later, but give up after about 20 ms */
+ if (fotg210->ASS_poll_count++ < 20) {
+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS,
+ true);
+ return;
+ }
+ fotg210_dbg(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n",
+ want, actual);
+ }
+ fotg210->ASS_poll_count = 0;
+
+ /* The status is up-to-date; restart or stop the schedule as needed */
+ if (want == 0) { /* Stopped */
+ if (fotg210->async_count > 0)
+ fotg210_set_command_bit(fotg210, CMD_ASE);
+
+ } else { /* Running */
+ if (fotg210->async_count == 0) {
+
+ /* Turn off the schedule after a while */
+ fotg210_enable_event(fotg210,
+ FOTG210_HRTIMER_DISABLE_ASYNC,
+ true);
+ }
+ }
+}
+
+/* Turn off the async schedule after a brief delay */
+static void fotg210_disable_ASE(struct fotg210_hcd *fotg210)
+{
+ fotg210_clear_command_bit(fotg210, CMD_ASE);
+}
+
+
+/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
+static void fotg210_poll_PSS(struct fotg210_hcd *fotg210)
+{
+ unsigned actual, want;
+
+ /* Don't do anything if the controller isn't running (e.g., died) */
+ if (fotg210->rh_state != FOTG210_RH_RUNNING)
+ return;
+
+ want = (fotg210->command & CMD_PSE) ? STS_PSS : 0;
+ actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS;
+
+ if (want != actual) {
+
+ /* Poll again later, but give up after about 20 ms */
+ if (fotg210->PSS_poll_count++ < 20) {
+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS,
+ true);
+ return;
+ }
+ fotg210_dbg(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
+ want, actual);
+ }
+ fotg210->PSS_poll_count = 0;
+
+ /* The status is up-to-date; restart or stop the schedule as needed */
+ if (want == 0) { /* Stopped */
+ if (fotg210->periodic_count > 0)
+ fotg210_set_command_bit(fotg210, CMD_PSE);
+
+ } else { /* Running */
+ if (fotg210->periodic_count == 0) {
+
+ /* Turn off the schedule after a while */
+ fotg210_enable_event(fotg210,
+ FOTG210_HRTIMER_DISABLE_PERIODIC,
+ true);
+ }
+ }
+}
+
+/* Turn off the periodic schedule after a brief delay */
+static void fotg210_disable_PSE(struct fotg210_hcd *fotg210)
+{
+ fotg210_clear_command_bit(fotg210, CMD_PSE);
+}
+
+
+/* Poll the STS_HALT status bit; see when a dead controller stops */
+static void fotg210_handle_controller_death(struct fotg210_hcd *fotg210)
+{
+ if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) {
+
+ /* Give up after a few milliseconds */
+ if (fotg210->died_poll_count++ < 5) {
+ /* Try again later */
+ fotg210_enable_event(fotg210,
+ FOTG210_HRTIMER_POLL_DEAD, true);
+ return;
+ }
+ fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n");
+ }
+
+ /* Clean up the mess */
+ fotg210->rh_state = FOTG210_RH_HALTED;
+ fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
+ fotg210_work(fotg210);
+ end_unlink_async(fotg210);
+
+ /* Not in process context, so don't try to reset the controller */
+}
+
+
+/* Handle unlinked interrupt QHs once they are gone from the hardware */
+static void fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210)
+{
+ bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
+
+ /*
+ * Process all the QHs on the intr_unlink list that were added
+ * before the current unlink cycle began. The list is in
+ * temporal order, so stop when we reach the first entry in the
+ * current cycle. But if the root hub isn't running then
+ * process all the QHs on the list.
+ */
+ fotg210->intr_unlinking = true;
+ while (fotg210->intr_unlink) {
+ struct fotg210_qh *qh = fotg210->intr_unlink;
+
+ if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle)
+ break;
+ fotg210->intr_unlink = qh->unlink_next;
+ qh->unlink_next = NULL;
+ end_unlink_intr(fotg210, qh);
+ }
+
+ /* Handle remaining entries later */
+ if (fotg210->intr_unlink) {
+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
+ true);
+ ++fotg210->intr_unlink_cycle;
+ }
+ fotg210->intr_unlinking = false;
+}
+
+
+/* Start another free-iTDs/siTDs cycle */
+static void start_free_itds(struct fotg210_hcd *fotg210)
+{
+ if (!(fotg210->enabled_hrtimer_events &
+ BIT(FOTG210_HRTIMER_FREE_ITDS))) {
+ fotg210->last_itd_to_free = list_entry(
+ fotg210->cached_itd_list.prev,
+ struct fotg210_itd, itd_list);
+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true);
+ }
+}
+
+/* Wait for controller to stop using old iTDs and siTDs */
+static void end_free_itds(struct fotg210_hcd *fotg210)
+{
+ struct fotg210_itd *itd, *n;
+
+ if (fotg210->rh_state < FOTG210_RH_RUNNING)
+ fotg210->last_itd_to_free = NULL;
+
+ list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) {
+ list_del(&itd->itd_list);
+ dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma);
+ if (itd == fotg210->last_itd_to_free)
+ break;
+ }
+
+ if (!list_empty(&fotg210->cached_itd_list))
+ start_free_itds(fotg210);
+}
+
+
+/* Handle lost (or very late) IAA interrupts */
+static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210)
+{
+ if (fotg210->rh_state != FOTG210_RH_RUNNING)
+ return;
+
+ /*
+ * Lost IAA irqs wedge things badly; seen first with a vt8235.
+ * So we need this watchdog, but must protect it against both
+ * (a) SMP races against real IAA firing and retriggering, and
+ * (b) clean HC shutdown, when IAA watchdog was pending.
+ */
+ if (fotg210->async_iaa) {
+ u32 cmd, status;
+
+ /* If we get here, IAA is *REALLY* late. It's barely
+ * conceivable that the system is so busy that CMD_IAAD
+ * is still legitimately set, so let's be sure it's
+ * clear before we read STS_IAA. (The HC should clear
+ * CMD_IAAD when it sets STS_IAA.)
+ */
+ cmd = fotg210_readl(fotg210, &fotg210->regs->command);
+
+ /*
+ * If IAA is set here it either legitimately triggered
+ * after the watchdog timer expired (_way_ late, so we'll
+ * still count it as lost) ... or a silicon erratum:
+ * - VIA seems to set IAA without triggering the IRQ;
+ * - IAAD potentially cleared without setting IAA.
+ */
+ status = fotg210_readl(fotg210, &fotg210->regs->status);
+ if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
+ COUNT(fotg210->stats.lost_iaa);
+ fotg210_writel(fotg210, STS_IAA,
+ &fotg210->regs->status);
+ }
+
+ fotg210_vdbg(fotg210, "IAA watchdog: status %x cmd %x\n",
+ status, cmd);
+ end_unlink_async(fotg210);
+ }
+}
+
+
+/* Enable the I/O watchdog, if appropriate */
+static void turn_on_io_watchdog(struct fotg210_hcd *fotg210)
+{
+ /* Not needed if the controller isn't running or it's already enabled */
+ if (fotg210->rh_state != FOTG210_RH_RUNNING ||
+ (fotg210->enabled_hrtimer_events &
+ BIT(FOTG210_HRTIMER_IO_WATCHDOG)))
+ return;
+
+ /*
+ * Isochronous transfers always need the watchdog.
+ * For other sorts we use it only if the flag is set.
+ */
+ if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog &&
+ fotg210->async_count + fotg210->intr_count > 0))
+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_IO_WATCHDOG,
+ true);
+}
+
+
+/*
+ * Handler functions for the hrtimer event types.
+ * Keep this array in the same order as the event types indexed by
+ * enum fotg210_hrtimer_event in fotg210.h.
+ */
+static void (*event_handlers[])(struct fotg210_hcd *) = {
+ fotg210_poll_ASS, /* FOTG210_HRTIMER_POLL_ASS */
+ fotg210_poll_PSS, /* FOTG210_HRTIMER_POLL_PSS */
+ fotg210_handle_controller_death, /* FOTG210_HRTIMER_POLL_DEAD */
+ fotg210_handle_intr_unlinks, /* FOTG210_HRTIMER_UNLINK_INTR */
+ end_free_itds, /* FOTG210_HRTIMER_FREE_ITDS */
+ unlink_empty_async, /* FOTG210_HRTIMER_ASYNC_UNLINKS */
+ fotg210_iaa_watchdog, /* FOTG210_HRTIMER_IAA_WATCHDOG */
+ fotg210_disable_PSE, /* FOTG210_HRTIMER_DISABLE_PERIODIC */
+ fotg210_disable_ASE, /* FOTG210_HRTIMER_DISABLE_ASYNC */
+ fotg210_work, /* FOTG210_HRTIMER_IO_WATCHDOG */
+};
+
+static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t)
+{
+ struct fotg210_hcd *fotg210 =
+ container_of(t, struct fotg210_hcd, hrtimer);
+ ktime_t now;
+ unsigned long events;
+ unsigned long flags;
+ unsigned e;
+
+ spin_lock_irqsave(&fotg210->lock, flags);
+
+ events = fotg210->enabled_hrtimer_events;
+ fotg210->enabled_hrtimer_events = 0;
+ fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
+
+ /*
+ * Check each pending event. If its time has expired, handle
+ * the event; otherwise re-enable it.
+ */
+ now = ktime_get();
+ for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) {
+ if (now.tv64 >= fotg210->hr_timeouts[e].tv64)
+ event_handlers[e](fotg210);
+ else
+ fotg210_enable_event(fotg210, e, false);
+ }
+
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ return HRTIMER_NORESTART;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define fotg210_bus_suspend NULL
+#define fotg210_bus_resume NULL
+
+/*-------------------------------------------------------------------------*/
+
+static int check_reset_complete(
+ struct fotg210_hcd *fotg210,
+ int index,
+ u32 __iomem *status_reg,
+ int port_status
+) {
+ if (!(port_status & PORT_CONNECT))
+ return port_status;
+
+ /* if reset finished and it's still not enabled -- handoff */
+ if (!(port_status & PORT_PE)) {
+ /* with integrated TT, there's nobody to hand it to! */
+ fotg210_dbg(fotg210,
+ "Failed to enable port %d on root hub TT\n",
+ index+1);
+ return port_status;
+ } else {
+ fotg210_dbg(fotg210, "port %d reset complete, port enabled\n",
+ index + 1);
+ }
+
+ return port_status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+fotg210_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ u32 temp, status;
+ u32 mask;
+ int retval = 1;
+ unsigned long flags;
+
+ /* init status to no-changes */
+ buf[0] = 0;
+
+ /* Inform the core about resumes-in-progress by returning
+ * a non-zero value even if there are no status changes.
+ */
+ status = fotg210->resuming_ports;
+
+ mask = PORT_CSC | PORT_PEC;
+ /* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */
+
+ /* no hub change reports (bit 0) for now (power, ...) */
+
+ /* port N changes (bit N)? */
+ spin_lock_irqsave(&fotg210->lock, flags);
+
+ temp = fotg210_readl(fotg210, &fotg210->regs->port_status);
+
+ /*
+ * Return status information even for ports with OWNER set.
+ * Otherwise khubd wouldn't see the disconnect event when a
+ * high-speed device is switched over to the companion
+ * controller by the user.
+ */
+
+ if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend)
+ || (fotg210->reset_done[0] && time_after_eq(
+ jiffies, fotg210->reset_done[0]))) {
+ buf[0] |= 1 << 1;
+ status = STS_PCD;
+ }
+ /* FIXME autosuspend idle root hubs */
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ return status ? retval : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+fotg210_hub_descriptor(
+ struct fotg210_hcd *fotg210,
+ struct usb_hub_descriptor *desc
+) {
+ int ports = HCS_N_PORTS(fotg210->hcs_params);
+ u16 temp;
+
+ desc->bDescriptorType = 0x29;
+ desc->bPwrOn2PwrGood = 10; /* fotg210 1.0, 2.3.9 says 20ms max */
+ desc->bHubContrCurrent = 0;
+
+ desc->bNbrPorts = ports;
+ temp = 1 + (ports / 8);
+ desc->bDescLength = 7 + 2 * temp;
+
+ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+ memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
+ memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
+
+ temp = 0x0008; /* per-port overcurrent reporting */
+ temp |= 0x0002; /* no power switching */
+ desc->wHubCharacteristics = cpu_to_le16(temp);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int fotg210_hub_control(
+ struct usb_hcd *hcd,
+ u16 typeReq,
+ u16 wValue,
+ u16 wIndex,
+ char *buf,
+ u16 wLength
+) {
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ int ports = HCS_N_PORTS(fotg210->hcs_params);
+ u32 __iomem *status_reg = &fotg210->regs->port_status;
+ u32 temp, temp1, status;
+ unsigned long flags;
+ int retval = 0;
+ unsigned selector;
+
+ /*
+ * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+ * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+ * (track current state ourselves) ... blink for diagnostics,
+ * power, "this is the one", etc. EHCI spec supports this.
+ */
+
+ spin_lock_irqsave(&fotg210->lock, flags);
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case ClearPortFeature:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = fotg210_readl(fotg210, status_reg);
+ temp &= ~PORT_RWC_BITS;
+
+ /*
+ * Even if OWNER is set, so the port is owned by the
+ * companion controller, khubd needs to be able to clear
+ * the port-change status bits (especially
+ * USB_PORT_STAT_C_CONNECTION).
+ */
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ fotg210_writel(fotg210, temp & ~PORT_PE, status_reg);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ fotg210_writel(fotg210, temp | PORT_PEC, status_reg);
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ if (temp & PORT_RESET)
+ goto error;
+ if (!(temp & PORT_SUSPEND))
+ break;
+ if ((temp & PORT_PE) == 0)
+ goto error;
+
+ /* resume signaling for 20 msec */
+ fotg210_writel(fotg210, temp | PORT_RESUME, status_reg);
+ fotg210->reset_done[wIndex] = jiffies
+ + msecs_to_jiffies(20);
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ clear_bit(wIndex, &fotg210->port_c_suspend);
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ fotg210_writel(fotg210, temp | PORT_CSC, status_reg);
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ fotg210_writel(fotg210, temp | OTGISR_OVC,
+ &fotg210->regs->otgisr);
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ /* GetPortStatus clears reset */
+ break;
+ default:
+ goto error;
+ }
+ fotg210_readl(fotg210, &fotg210->regs->command);
+ break;
+ case GetHubDescriptor:
+ fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *)
+ buf);
+ break;
+ case GetHubStatus:
+ /* no hub-wide feature/status flags */
+ memset(buf, 0, 4);
+ /*cpu_to_le32s ((u32 *) buf); */
+ break;
+ case GetPortStatus:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ status = 0;
+ temp = fotg210_readl(fotg210, status_reg);
+
+ /* wPortChange bits */
+ if (temp & PORT_CSC)
+ status |= USB_PORT_STAT_C_CONNECTION << 16;
+ if (temp & PORT_PEC)
+ status |= USB_PORT_STAT_C_ENABLE << 16;
+
+ temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
+ if (temp1 & OTGISR_OVC)
+ status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+
+ /* whoever resumes must GetPortStatus to complete it!! */
+ if (temp & PORT_RESUME) {
+
+ /* Remote Wakeup received? */
+ if (!fotg210->reset_done[wIndex]) {
+ /* resume signaling for 20 msec */
+ fotg210->reset_done[wIndex] = jiffies
+ + msecs_to_jiffies(20);
+ /* check the port again */
+ mod_timer(&fotg210_to_hcd(fotg210)->rh_timer,
+ fotg210->reset_done[wIndex]);
+ }
+
+ /* resume completed? */
+ else if (time_after_eq(jiffies,
+ fotg210->reset_done[wIndex])) {
+ clear_bit(wIndex, &fotg210->suspended_ports);
+ set_bit(wIndex, &fotg210->port_c_suspend);
+ fotg210->reset_done[wIndex] = 0;
+
+ /* stop resume signaling */
+ temp = fotg210_readl(fotg210, status_reg);
+ fotg210_writel(fotg210,
+ temp & ~(PORT_RWC_BITS | PORT_RESUME),
+ status_reg);
+ clear_bit(wIndex, &fotg210->resuming_ports);
+ retval = handshake(fotg210, status_reg,
+ PORT_RESUME, 0, 2000 /* 2msec */);
+ if (retval != 0) {
+ fotg210_err(fotg210,
+ "port %d resume error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+ temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+ }
+ }
+
+ /* whoever resets must GetPortStatus to complete it!! */
+ if ((temp & PORT_RESET)
+ && time_after_eq(jiffies,
+ fotg210->reset_done[wIndex])) {
+ status |= USB_PORT_STAT_C_RESET << 16;
+ fotg210->reset_done[wIndex] = 0;
+ clear_bit(wIndex, &fotg210->resuming_ports);
+
+ /* force reset to complete */
+ fotg210_writel(fotg210,
+ temp & ~(PORT_RWC_BITS | PORT_RESET),
+ status_reg);
+ /* REVISIT: some hardware needs 550+ usec to clear
+ * this bit; seems too long to spin routinely...
+ */
+ retval = handshake(fotg210, status_reg,
+ PORT_RESET, 0, 1000);
+ if (retval != 0) {
+ fotg210_err(fotg210, "port %d reset error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+
+ /* see what we found out */
+ temp = check_reset_complete(fotg210, wIndex, status_reg,
+ fotg210_readl(fotg210, status_reg));
+ }
+
+ if (!(temp & (PORT_RESUME|PORT_RESET))) {
+ fotg210->reset_done[wIndex] = 0;
+ clear_bit(wIndex, &fotg210->resuming_ports);
+ }
+
+ /* transfer dedicated ports to the companion hc */
+ if ((temp & PORT_CONNECT) &&
+ test_bit(wIndex, &fotg210->companion_ports)) {
+ temp &= ~PORT_RWC_BITS;
+ fotg210_writel(fotg210, temp, status_reg);
+ fotg210_dbg(fotg210, "port %d --> companion\n",
+ wIndex + 1);
+ temp = fotg210_readl(fotg210, status_reg);
+ }
+
+ /*
+ * Even if OWNER is set, there's no harm letting khubd
+ * see the wPortStatus values (they should all be 0 except
+ * for PORT_POWER anyway).
+ */
+
+ if (temp & PORT_CONNECT) {
+ status |= USB_PORT_STAT_CONNECTION;
+ status |= fotg210_port_speed(fotg210, temp);
+ }
+ if (temp & PORT_PE)
+ status |= USB_PORT_STAT_ENABLE;
+
+ /* maybe the port was unsuspended without our knowledge */
+ if (temp & (PORT_SUSPEND|PORT_RESUME)) {
+ status |= USB_PORT_STAT_SUSPEND;
+ } else if (test_bit(wIndex, &fotg210->suspended_ports)) {
+ clear_bit(wIndex, &fotg210->suspended_ports);
+ clear_bit(wIndex, &fotg210->resuming_ports);
+ fotg210->reset_done[wIndex] = 0;
+ if (temp & PORT_PE)
+ set_bit(wIndex, &fotg210->port_c_suspend);
+ }
+
+ temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
+ if (temp1 & OTGISR_OVC)
+ status |= USB_PORT_STAT_OVERCURRENT;
+ if (temp & PORT_RESET)
+ status |= USB_PORT_STAT_RESET;
+ if (test_bit(wIndex, &fotg210->port_c_suspend))
+ status |= USB_PORT_STAT_C_SUSPEND << 16;
+
+#ifndef VERBOSE_DEBUG
+ if (status & ~0xffff) /* only if wPortChange is interesting */
+#endif
+ dbg_port(fotg210, "GetStatus", wIndex + 1, temp);
+ put_unaligned_le32(status, buf);
+ break;
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case SetPortFeature:
+ selector = wIndex >> 8;
+ wIndex &= 0xff;
+
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = fotg210_readl(fotg210, status_reg);
+ temp &= ~PORT_RWC_BITS;
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ if ((temp & PORT_PE) == 0
+ || (temp & PORT_RESET) != 0)
+ goto error;
+
+ /* After above check the port must be connected.
+ * Set appropriate bit thus could put phy into low power
+ * mode if we have hostpc feature
+ */
+ fotg210_writel(fotg210, temp | PORT_SUSPEND,
+ status_reg);
+ set_bit(wIndex, &fotg210->suspended_ports);
+ break;
+ case USB_PORT_FEAT_RESET:
+ if (temp & PORT_RESUME)
+ goto error;
+ /* line status bits may report this as low speed,
+ * which can be fine if this root hub has a
+ * transaction translator built in.
+ */
+ fotg210_vdbg(fotg210, "port %d reset\n", wIndex + 1);
+ temp |= PORT_RESET;
+ temp &= ~PORT_PE;
+
+ /*
+ * caller must wait, then call GetPortStatus
+ * usb 2.0 spec says 50 ms resets on root
+ */
+ fotg210->reset_done[wIndex] = jiffies
+ + msecs_to_jiffies(50);
+ fotg210_writel(fotg210, temp, status_reg);
+ break;
+
+ /* For downstream facing ports (these): one hub port is put
+ * into test mode according to USB2 11.24.2.13, then the hub
+ * must be reset (which for root hub now means rmmod+modprobe,
+ * or else system reboot). See EHCI 2.3.9 and 4.14 for info
+ * about the EHCI-specific stuff.
+ */
+ case USB_PORT_FEAT_TEST:
+ if (!selector || selector > 5)
+ goto error;
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ fotg210_quiesce(fotg210);
+ spin_lock_irqsave(&fotg210->lock, flags);
+
+ /* Put all enabled ports into suspend */
+ temp = fotg210_readl(fotg210, status_reg) &
+ ~PORT_RWC_BITS;
+ if (temp & PORT_PE)
+ fotg210_writel(fotg210, temp | PORT_SUSPEND,
+ status_reg);
+
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ fotg210_halt(fotg210);
+ spin_lock_irqsave(&fotg210->lock, flags);
+
+ temp = fotg210_readl(fotg210, status_reg);
+ temp |= selector << 16;
+ fotg210_writel(fotg210, temp, status_reg);
+ break;
+
+ default:
+ goto error;
+ }
+ fotg210_readl(fotg210, &fotg210->regs->command);
+ break;
+
+ default:
+error:
+ /* "stall" on error */
+ retval = -EPIPE;
+ }
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ return retval;
+}
+
+static void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd,
+ int portnum)
+{
+ return;
+}
+
+static int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd,
+ int portnum)
+{
+ return 0;
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * There's basically three types of memory:
+ * - data used only by the HCD ... kmalloc is fine
+ * - async and periodic schedules, shared by HC and HCD ... these
+ * need to use dma_pool or dma_alloc_coherent
+ * - driver buffers, read/written by HC ... single shot DMA mapped
+ *
+ * There's also "register" data (e.g. PCI or SOC), which is memory mapped.
+ * No memory seen by this driver is pageable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* Allocate the key transfer structures from the previously allocated pool */
+
+static inline void fotg210_qtd_init(struct fotg210_hcd *fotg210,
+ struct fotg210_qtd *qtd, dma_addr_t dma)
+{
+ memset(qtd, 0, sizeof(*qtd));
+ qtd->qtd_dma = dma;
+ qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
+ qtd->hw_next = FOTG210_LIST_END(fotg210);
+ qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
+ INIT_LIST_HEAD(&qtd->qtd_list);
+}
+
+static struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210,
+ gfp_t flags)
+{
+ struct fotg210_qtd *qtd;
+ dma_addr_t dma;
+
+ qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma);
+ if (qtd != NULL)
+ fotg210_qtd_init(fotg210, qtd, dma);
+
+ return qtd;
+}
+
+static inline void fotg210_qtd_free(struct fotg210_hcd *fotg210,
+ struct fotg210_qtd *qtd)
+{
+ dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma);
+}
+
+
+static void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+ /* clean qtds first, and know this is not linked */
+ if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) {
+ fotg210_dbg(fotg210, "unused qh not empty!\n");
+ BUG();
+ }
+ if (qh->dummy)
+ fotg210_qtd_free(fotg210, qh->dummy);
+ dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
+ kfree(qh);
+}
+
+static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210,
+ gfp_t flags)
+{
+ struct fotg210_qh *qh;
+ dma_addr_t dma;
+
+ qh = kzalloc(sizeof(*qh), GFP_ATOMIC);
+ if (!qh)
+ goto done;
+ qh->hw = (struct fotg210_qh_hw *)
+ dma_pool_alloc(fotg210->qh_pool, flags, &dma);
+ if (!qh->hw)
+ goto fail;
+ memset(qh->hw, 0, sizeof(*qh->hw));
+ qh->qh_dma = dma;
+ INIT_LIST_HEAD(&qh->qtd_list);
+
+ /* dummy td enables safe urb queuing */
+ qh->dummy = fotg210_qtd_alloc(fotg210, flags);
+ if (qh->dummy == NULL) {
+ fotg210_dbg(fotg210, "no dummy td\n");
+ goto fail1;
+ }
+done:
+ return qh;
+fail1:
+ dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
+fail:
+ kfree(qh);
+ return NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* The queue heads and transfer descriptors are managed from pools tied
+ * to each of the "per device" structures.
+ * This is the initialisation and cleanup code.
+ */
+
+static void fotg210_mem_cleanup(struct fotg210_hcd *fotg210)
+{
+ if (fotg210->async)
+ qh_destroy(fotg210, fotg210->async);
+ fotg210->async = NULL;
+
+ if (fotg210->dummy)
+ qh_destroy(fotg210, fotg210->dummy);
+ fotg210->dummy = NULL;
+
+ /* DMA consistent memory and pools */
+ if (fotg210->qtd_pool)
+ dma_pool_destroy(fotg210->qtd_pool);
+ fotg210->qtd_pool = NULL;
+
+ if (fotg210->qh_pool) {
+ dma_pool_destroy(fotg210->qh_pool);
+ fotg210->qh_pool = NULL;
+ }
+
+ if (fotg210->itd_pool)
+ dma_pool_destroy(fotg210->itd_pool);
+ fotg210->itd_pool = NULL;
+
+ if (fotg210->periodic)
+ dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller,
+ fotg210->periodic_size * sizeof(u32),
+ fotg210->periodic, fotg210->periodic_dma);
+ fotg210->periodic = NULL;
+
+ /* shadow periodic table */
+ kfree(fotg210->pshadow);
+ fotg210->pshadow = NULL;
+}
+
+/* remember to add cleanup code (above) if you add anything here */
+static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags)
+{
+ int i;
+
+ /* QTDs for control/bulk/intr transfers */
+ fotg210->qtd_pool = dma_pool_create("fotg210_qtd",
+ fotg210_to_hcd(fotg210)->self.controller,
+ sizeof(struct fotg210_qtd),
+ 32 /* byte alignment (for hw parts) */,
+ 4096 /* can't cross 4K */);
+ if (!fotg210->qtd_pool)
+ goto fail;
+
+ /* QHs for control/bulk/intr transfers */
+ fotg210->qh_pool = dma_pool_create("fotg210_qh",
+ fotg210_to_hcd(fotg210)->self.controller,
+ sizeof(struct fotg210_qh_hw),
+ 32 /* byte alignment (for hw parts) */,
+ 4096 /* can't cross 4K */);
+ if (!fotg210->qh_pool)
+ goto fail;
+
+ fotg210->async = fotg210_qh_alloc(fotg210, flags);
+ if (!fotg210->async)
+ goto fail;
+
+ /* ITD for high speed ISO transfers */
+ fotg210->itd_pool = dma_pool_create("fotg210_itd",
+ fotg210_to_hcd(fotg210)->self.controller,
+ sizeof(struct fotg210_itd),
+ 64 /* byte alignment (for hw parts) */,
+ 4096 /* can't cross 4K */);
+ if (!fotg210->itd_pool)
+ goto fail;
+
+ /* Hardware periodic table */
+ fotg210->periodic = (__le32 *)
+ dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller,
+ fotg210->periodic_size * sizeof(__le32),
+ &fotg210->periodic_dma, 0);
+ if (fotg210->periodic == NULL)
+ goto fail;
+
+ for (i = 0; i < fotg210->periodic_size; i++)
+ fotg210->periodic[i] = FOTG210_LIST_END(fotg210);
+
+ /* software shadow of hardware table */
+ fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *),
+ flags);
+ if (fotg210->pshadow != NULL)
+ return 0;
+
+fail:
+ fotg210_dbg(fotg210, "couldn't init memory\n");
+ fotg210_mem_cleanup(fotg210);
+ return -ENOMEM;
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * EHCI hardware queue manipulation ... the core. QH/QTD manipulation.
+ *
+ * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd"
+ * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
+ * buffers needed for the larger number). We use one QH per endpoint, queue
+ * multiple urbs (all three types) per endpoint. URBs may need several qtds.
+ *
+ * ISO traffic uses "ISO TD" (itd) records, and (along with
+ * interrupts) needs careful scheduling. Performance improvements can be
+ * an ongoing challenge. That's in "ehci-sched.c".
+ *
+ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
+ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
+ * (b) special fields in qh entries or (c) split iso entries. TTs will
+ * buffer low/full speed data so the host collects it at high speed.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* fill a qtd, returning how much of the buffer we were able to queue up */
+
+static int
+qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd, dma_addr_t buf,
+ size_t len, int token, int maxpacket)
+{
+ int i, count;
+ u64 addr = buf;
+
+ /* one buffer entry per 4K ... first might be short or unaligned */
+ qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr);
+ qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32));
+ count = 0x1000 - (buf & 0x0fff); /* rest of that page */
+ if (likely(len < count)) /* ... iff needed */
+ count = len;
+ else {
+ buf += 0x1000;
+ buf &= ~0x0fff;
+
+ /* per-qtd limit: from 16K to 20K (best alignment) */
+ for (i = 1; count < len && i < 5; i++) {
+ addr = buf;
+ qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr);
+ qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210,
+ (u32)(addr >> 32));
+ buf += 0x1000;
+ if ((count + 0x1000) < len)
+ count += 0x1000;
+ else
+ count = len;
+ }
+
+ /* short packets may only terminate transfers */
+ if (count != len)
+ count -= (count % maxpacket);
+ }
+ qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token);
+ qtd->length = count;
+
+ return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+qh_update(struct fotg210_hcd *fotg210, struct fotg210_qh *qh,
+ struct fotg210_qtd *qtd)
+{
+ struct fotg210_qh_hw *hw = qh->hw;
+
+ /* writes to an active overlay are unsafe */
+ BUG_ON(qh->qh_state != QH_STATE_IDLE);
+
+ hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+ hw->hw_alt_next = FOTG210_LIST_END(fotg210);
+
+ /* Except for control endpoints, we make hardware maintain data
+ * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+ * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+ * ever clear it.
+ */
+ if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) {
+ unsigned is_out, epnum;
+
+ is_out = qh->is_out;
+ epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f;
+ if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) {
+ hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE);
+ usb_settoggle(qh->dev, epnum, is_out, 1);
+ }
+ }
+
+ hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING);
+}
+
+/* if it weren't for a common silicon quirk (writing the dummy into the qh
+ * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
+ * recovery (including urb dequeue) would need software changes to a QH...
+ */
+static void
+qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+ struct fotg210_qtd *qtd;
+
+ if (list_empty(&qh->qtd_list))
+ qtd = qh->dummy;
+ else {
+ qtd = list_entry(qh->qtd_list.next,
+ struct fotg210_qtd, qtd_list);
+ /*
+ * first qtd may already be partially processed.
+ * If we come here during unlink, the QH overlay region
+ * might have reference to the just unlinked qtd. The
+ * qtd is updated in qh_completions(). Update the QH
+ * overlay here.
+ */
+ if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) {
+ qh->hw->hw_qtd_next = qtd->hw_next;
+ qtd = NULL;
+ }
+ }
+
+ if (qtd)
+ qh_update(fotg210, qh, qtd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
+
+static void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ struct fotg210_qh *qh = ep->hcpriv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fotg210->lock, flags);
+ qh->clearing_tt = 0;
+ if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
+ && fotg210->rh_state == FOTG210_RH_RUNNING)
+ qh_link_async(fotg210, qh);
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+}
+
+static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210,
+ struct fotg210_qh *qh,
+ struct urb *urb, u32 token)
+{
+
+ /* If an async split transaction gets an error or is unlinked,
+ * the TT buffer may be left in an indeterminate state. We
+ * have to clear the TT buffer.
+ *
+ * Note: this routine is never called for Isochronous transfers.
+ */
+ if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
+#ifdef DEBUG
+ struct usb_device *tt = urb->dev->tt->hub;
+ dev_dbg(&tt->dev,
+ "clear tt buffer port %d, a%d ep%d t%08x\n",
+ urb->dev->ttport, urb->dev->devnum,
+ usb_pipeendpoint(urb->pipe), token);
+#endif /* DEBUG */
+ if (urb->dev->tt->hub !=
+ fotg210_to_hcd(fotg210)->self.root_hub) {
+ if (usb_hub_clear_tt_buffer(urb) == 0)
+ qh->clearing_tt = 1;
+ }
+ }
+}
+
+static int qtd_copy_status(
+ struct fotg210_hcd *fotg210,
+ struct urb *urb,
+ size_t length,
+ u32 token
+)
+{
+ int status = -EINPROGRESS;
+
+ /* count IN/OUT bytes, not SETUP (even short packets) */
+ if (likely(QTD_PID(token) != 2))
+ urb->actual_length += length - QTD_LENGTH(token);
+
+ /* don't modify error codes */
+ if (unlikely(urb->unlinked))
+ return status;
+
+ /* force cleanup after short read; not always an error */
+ if (unlikely(IS_SHORT_READ(token)))
+ status = -EREMOTEIO;
+
+ /* serious "can't proceed" faults reported by the hardware */
+ if (token & QTD_STS_HALT) {
+ if (token & QTD_STS_BABBLE) {
+ /* FIXME "must" disable babbling device's port too */
+ status = -EOVERFLOW;
+ /* CERR nonzero + halt --> stall */
+ } else if (QTD_CERR(token)) {
+ status = -EPIPE;
+
+ /* In theory, more than one of the following bits can be set
+ * since they are sticky and the transaction is retried.
+ * Which to test first is rather arbitrary.
+ */
+ } else if (token & QTD_STS_MMF) {
+ /* fs/ls interrupt xfer missed the complete-split */
+ status = -EPROTO;
+ } else if (token & QTD_STS_DBE) {
+ status = (QTD_PID(token) == 1) /* IN ? */
+ ? -ENOSR /* hc couldn't read data */
+ : -ECOMM; /* hc couldn't write data */
+ } else if (token & QTD_STS_XACT) {
+ /* timeout, bad CRC, wrong PID, etc */
+ fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n",
+ urb->dev->devpath,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out");
+ status = -EPROTO;
+ } else { /* unknown */
+ status = -EPROTO;
+ }
+
+ fotg210_vdbg(fotg210,
+ "dev%d ep%d%s qtd token %08x --> status %d\n",
+ usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ token, status);
+ }
+
+ return status;
+}
+
+static void
+fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb, int status)
+__releases(fotg210->lock)
+__acquires(fotg210->lock)
+{
+ if (likely(urb->hcpriv != NULL)) {
+ struct fotg210_qh *qh = (struct fotg210_qh *) urb->hcpriv;
+
+ /* S-mask in a QH means it's an interrupt urb */
+ if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) {
+
+ /* ... update hc-wide periodic stats (for usbfs) */
+ fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--;
+ }
+ }
+
+ if (unlikely(urb->unlinked)) {
+ COUNT(fotg210->stats.unlink);
+ } else {
+ /* report non-error and short read status as zero */
+ if (status == -EINPROGRESS || status == -EREMOTEIO)
+ status = 0;
+ COUNT(fotg210->stats.complete);
+ }
+
+#ifdef FOTG210_URB_TRACE
+ fotg210_dbg(fotg210,
+ "%s %s urb %p ep%d%s status %d len %d/%d\n",
+ __func__, urb->dev->devpath, urb,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ status,
+ urb->actual_length, urb->transfer_buffer_length);
+#endif
+
+ /* complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+ spin_unlock(&fotg210->lock);
+ usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status);
+ spin_lock(&fotg210->lock);
+}
+
+static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
+
+/*
+ * Process and free completed qtds for a qh, returning URBs to drivers.
+ * Chases up to qh->hw_current. Returns number of completions called,
+ * indicating how much "real" work we did.
+ */
+static unsigned
+qh_completions(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+ struct fotg210_qtd *last, *end = qh->dummy;
+ struct list_head *entry, *tmp;
+ int last_status;
+ int stopped;
+ unsigned count = 0;
+ u8 state;
+ struct fotg210_qh_hw *hw = qh->hw;
+
+ if (unlikely(list_empty(&qh->qtd_list)))
+ return count;
+
+ /* completions (or tasks on other cpus) must never clobber HALT
+ * till we've gone through and cleaned everything up, even when
+ * they add urbs to this qh's queue or mark them for unlinking.
+ *
+ * NOTE: unlinking expects to be done in queue order.
+ *
+ * It's a bug for qh->qh_state to be anything other than
+ * QH_STATE_IDLE, unless our caller is scan_async() or
+ * scan_intr().
+ */
+ state = qh->qh_state;
+ qh->qh_state = QH_STATE_COMPLETING;
+ stopped = (state == QH_STATE_IDLE);
+
+ rescan:
+ last = NULL;
+ last_status = -EINPROGRESS;
+ qh->needs_rescan = 0;
+
+ /* remove de-activated QTDs from front of queue.
+ * after faults (including short reads), cleanup this urb
+ * then let the queue advance.
+ * if queue is stopped, handles unlinks.
+ */
+ list_for_each_safe(entry, tmp, &qh->qtd_list) {
+ struct fotg210_qtd *qtd;
+ struct urb *urb;
+ u32 token = 0;
+
+ qtd = list_entry(entry, struct fotg210_qtd, qtd_list);
+ urb = qtd->urb;
+
+ /* clean up any state from previous QTD ...*/
+ if (last) {
+ if (likely(last->urb != urb)) {
+ fotg210_urb_done(fotg210, last->urb,
+ last_status);
+ count++;
+ last_status = -EINPROGRESS;
+ }
+ fotg210_qtd_free(fotg210, last);
+ last = NULL;
+ }
+
+ /* ignore urbs submitted during completions we reported */
+ if (qtd == end)
+ break;
+
+ /* hardware copies qtd out of qh overlay */
+ rmb();
+ token = hc32_to_cpu(fotg210, qtd->hw_token);
+
+ /* always clean up qtds the hc de-activated */
+ retry_xacterr:
+ if ((token & QTD_STS_ACTIVE) == 0) {
+
+ /* Report Data Buffer Error: non-fatal but useful */
+ if (token & QTD_STS_DBE)
+ fotg210_dbg(fotg210,
+ "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+ urb,
+ usb_endpoint_num(&urb->ep->desc),
+ usb_endpoint_dir_in(&urb->ep->desc)
+ ? "in" : "out",
+ urb->transfer_buffer_length,
+ qtd,
+ qh);
+
+ /* on STALL, error, and short reads this urb must
+ * complete and all its qtds must be recycled.
+ */
+ if ((token & QTD_STS_HALT) != 0) {
+
+ /* retry transaction errors until we
+ * reach the software xacterr limit
+ */
+ if ((token & QTD_STS_XACT) &&
+ QTD_CERR(token) == 0 &&
+ ++qh->xacterrs < QH_XACTERR_MAX &&
+ !urb->unlinked) {
+ fotg210_dbg(fotg210,
+ "detected XactErr len %zu/%zu retry %d\n",
+ qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs);
+
+ /* reset the token in the qtd and the
+ * qh overlay (which still contains
+ * the qtd) so that we pick up from
+ * where we left off
+ */
+ token &= ~QTD_STS_HALT;
+ token |= QTD_STS_ACTIVE |
+ (FOTG210_TUNE_CERR << 10);
+ qtd->hw_token = cpu_to_hc32(fotg210,
+ token);
+ wmb();
+ hw->hw_token = cpu_to_hc32(fotg210,
+ token);
+ goto retry_xacterr;
+ }
+ stopped = 1;
+
+ /* magic dummy for some short reads; qh won't advance.
+ * that silicon quirk can kick in with this dummy too.
+ *
+ * other short reads won't stop the queue, including
+ * control transfers (status stage handles that) or
+ * most other single-qtd reads ... the queue stops if
+ * URB_SHORT_NOT_OK was set so the driver submitting
+ * the urbs could clean it up.
+ */
+ } else if (IS_SHORT_READ(token)
+ && !(qtd->hw_alt_next
+ & FOTG210_LIST_END(fotg210))) {
+ stopped = 1;
+ }
+
+ /* stop scanning when we reach qtds the hc is using */
+ } else if (likely(!stopped
+ && fotg210->rh_state >= FOTG210_RH_RUNNING)) {
+ break;
+
+ /* scan the whole queue for unlinks whenever it stops */
+ } else {
+ stopped = 1;
+
+ /* cancel everything if we halt, suspend, etc */
+ if (fotg210->rh_state < FOTG210_RH_RUNNING)
+ last_status = -ESHUTDOWN;
+
+ /* this qtd is active; skip it unless a previous qtd
+ * for its urb faulted, or its urb was canceled.
+ */
+ else if (last_status == -EINPROGRESS && !urb->unlinked)
+ continue;
+
+ /* qh unlinked; token in overlay may be most current */
+ if (state == QH_STATE_IDLE
+ && cpu_to_hc32(fotg210, qtd->qtd_dma)
+ == hw->hw_current) {
+ token = hc32_to_cpu(fotg210, hw->hw_token);
+
+ /* An unlink may leave an incomplete
+ * async transaction in the TT buffer.
+ * We have to clear it.
+ */
+ fotg210_clear_tt_buffer(fotg210, qh, urb,
+ token);
+ }
+ }
+
+ /* unless we already know the urb's status, collect qtd status
+ * and update count of bytes transferred. in common short read
+ * cases with only one data qtd (including control transfers),
+ * queue processing won't halt. but with two or more qtds (for
+ * example, with a 32 KB transfer), when the first qtd gets a
+ * short read the second must be removed by hand.
+ */
+ if (last_status == -EINPROGRESS) {
+ last_status = qtd_copy_status(fotg210, urb,
+ qtd->length, token);
+ if (last_status == -EREMOTEIO
+ && (qtd->hw_alt_next
+ & FOTG210_LIST_END(fotg210)))
+ last_status = -EINPROGRESS;
+
+ /* As part of low/full-speed endpoint-halt processing
+ * we must clear the TT buffer (11.17.5).
+ */
+ if (unlikely(last_status != -EINPROGRESS &&
+ last_status != -EREMOTEIO)) {
+ /* The TT's in some hubs malfunction when they
+ * receive this request following a STALL (they
+ * stop sending isochronous packets). Since a
+ * STALL can't leave the TT buffer in a busy
+ * state (if you believe Figures 11-48 - 11-51
+ * in the USB 2.0 spec), we won't clear the TT
+ * buffer in this case. Strictly speaking this
+ * is a violation of the spec.
+ */
+ if (last_status != -EPIPE)
+ fotg210_clear_tt_buffer(fotg210, qh,
+ urb, token);
+ }
+ }
+
+ /* if we're removing something not at the queue head,
+ * patch the hardware queue pointer.
+ */
+ if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
+ last = list_entry(qtd->qtd_list.prev,
+ struct fotg210_qtd, qtd_list);
+ last->hw_next = qtd->hw_next;
+ }
+
+ /* remove qtd; it's recycled after possible urb completion */
+ list_del(&qtd->qtd_list);
+ last = qtd;
+
+ /* reinit the xacterr counter for the next qtd */
+ qh->xacterrs = 0;
+ }
+
+ /* last urb's completion might still need calling */
+ if (likely(last != NULL)) {
+ fotg210_urb_done(fotg210, last->urb, last_status);
+ count++;
+ fotg210_qtd_free(fotg210, last);
+ }
+
+ /* Do we need to rescan for URBs dequeued during a giveback? */
+ if (unlikely(qh->needs_rescan)) {
+ /* If the QH is already unlinked, do the rescan now. */
+ if (state == QH_STATE_IDLE)
+ goto rescan;
+
+ /* Otherwise we have to wait until the QH is fully unlinked.
+ * Our caller will start an unlink if qh->needs_rescan is
+ * set. But if an unlink has already started, nothing needs
+ * to be done.
+ */
+ if (state != QH_STATE_LINKED)
+ qh->needs_rescan = 0;
+ }
+
+ /* restore original state; caller must unlink or relink */
+ qh->qh_state = state;
+
+ /* be sure the hardware's done with the qh before refreshing
+ * it after fault cleanup, or recovering from silicon wrongly
+ * overlaying the dummy qtd (which reduces DMA chatter).
+ */
+ if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) {
+ switch (state) {
+ case QH_STATE_IDLE:
+ qh_refresh(fotg210, qh);
+ break;
+ case QH_STATE_LINKED:
+ /* We won't refresh a QH that's linked (after the HC
+ * stopped the queue). That avoids a race:
+ * - HC reads first part of QH;
+ * - CPU updates that first part and the token;
+ * - HC reads rest of that QH, including token
+ * Result: HC gets an inconsistent image, and then
+ * DMAs to/from the wrong memory (corrupting it).
+ *
+ * That should be rare for interrupt transfers,
+ * except maybe high bandwidth ...
+ */
+
+ /* Tell the caller to start an unlink */
+ qh->needs_rescan = 1;
+ break;
+ /* otherwise, unlink already started */
+ }
+ }
+
+ return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+/* ... and packet size, for any kind of endpoint descriptor */
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
+/*
+ * reverse of qh_urb_transaction: free a list of TDs.
+ * used for cleanup after errors, before HC sees an URB's TDs.
+ */
+static void qtd_list_free(
+ struct fotg210_hcd *fotg210,
+ struct urb *urb,
+ struct list_head *qtd_list
+) {
+ struct list_head *entry, *temp;
+
+ list_for_each_safe(entry, temp, qtd_list) {
+ struct fotg210_qtd *qtd;
+
+ qtd = list_entry(entry, struct fotg210_qtd, qtd_list);
+ list_del(&qtd->qtd_list);
+ fotg210_qtd_free(fotg210, qtd);
+ }
+}
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *
+qh_urb_transaction(
+ struct fotg210_hcd *fotg210,
+ struct urb *urb,
+ struct list_head *head,
+ gfp_t flags
+) {
+ struct fotg210_qtd *qtd, *qtd_prev;
+ dma_addr_t buf;
+ int len, this_sg_len, maxpacket;
+ int is_input;
+ u32 token;
+ int i;
+ struct scatterlist *sg;
+
+ /*
+ * URBs map to sequences of QTDs: one logical transaction
+ */
+ qtd = fotg210_qtd_alloc(fotg210, flags);
+ if (unlikely(!qtd))
+ return NULL;
+ list_add_tail(&qtd->qtd_list, head);
+ qtd->urb = urb;
+
+ token = QTD_STS_ACTIVE;
+ token |= (FOTG210_TUNE_CERR << 10);
+ /* for split transactions, SplitXState initialized to zero */
+
+ len = urb->transfer_buffer_length;
+ is_input = usb_pipein(urb->pipe);
+ if (usb_pipecontrol(urb->pipe)) {
+ /* SETUP pid */
+ qtd_fill(fotg210, qtd, urb->setup_dma,
+ sizeof(struct usb_ctrlrequest),
+ token | (2 /* "setup" */ << 8), 8);
+
+ /* ... and always at least one more pid */
+ token ^= QTD_TOGGLE;
+ qtd_prev = qtd;
+ qtd = fotg210_qtd_alloc(fotg210, flags);
+ if (unlikely(!qtd))
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* for zero length DATA stages, STATUS is always IN */
+ if (len == 0)
+ token |= (1 /* "in" */ << 8);
+ }
+
+ /*
+ * data transfer stage: buffer setup
+ */
+ i = urb->num_mapped_sgs;
+ if (len > 0 && i > 0) {
+ sg = urb->sg;
+ buf = sg_dma_address(sg);
+
+ /* urb->transfer_buffer_length may be smaller than the
+ * size of the scatterlist (or vice versa)
+ */
+ this_sg_len = min_t(int, sg_dma_len(sg), len);
+ } else {
+ sg = NULL;
+ buf = urb->transfer_dma;
+ this_sg_len = len;
+ }
+
+ if (is_input)
+ token |= (1 /* "in" */ << 8);
+ /* else it's already initted to "out" pid (0 << 8) */
+
+ maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+
+ /*
+ * buffer gets wrapped in one or more qtds;
+ * last one may be "short" (including zero len)
+ * and may serve as a control status ack
+ */
+ for (;;) {
+ int this_qtd_len;
+
+ this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token,
+ maxpacket);
+ this_sg_len -= this_qtd_len;
+ len -= this_qtd_len;
+ buf += this_qtd_len;
+
+ /*
+ * short reads advance to a "magic" dummy instead of the next
+ * qtd ... that forces the queue to stop, for manual cleanup.
+ * (this will usually be overridden later.)
+ */
+ if (is_input)
+ qtd->hw_alt_next = fotg210->async->hw->hw_alt_next;
+
+ /* qh makes control packets use qtd toggle; maybe switch it */
+ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+ token ^= QTD_TOGGLE;
+
+ if (likely(this_sg_len <= 0)) {
+ if (--i <= 0 || len <= 0)
+ break;
+ sg = sg_next(sg);
+ buf = sg_dma_address(sg);
+ this_sg_len = min_t(int, sg_dma_len(sg), len);
+ }
+
+ qtd_prev = qtd;
+ qtd = fotg210_qtd_alloc(fotg210, flags);
+ if (unlikely(!qtd))
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+ list_add_tail(&qtd->qtd_list, head);
+ }
+
+ /*
+ * unless the caller requires manual cleanup after short reads,
+ * have the alt_next mechanism keep the queue running after the
+ * last data qtd (the only one, for control and most other cases).
+ */
+ if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
+ || usb_pipecontrol(urb->pipe)))
+ qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
+
+ /*
+ * control requests may need a terminating data "status" ack;
+ * other OUT ones may need a terminating short packet
+ * (zero length).
+ */
+ if (likely(urb->transfer_buffer_length != 0)) {
+ int one_more = 0;
+
+ if (usb_pipecontrol(urb->pipe)) {
+ one_more = 1;
+ token ^= 0x0100; /* "in" <--> "out" */
+ token |= QTD_TOGGLE; /* force DATA1 */
+ } else if (usb_pipeout(urb->pipe)
+ && (urb->transfer_flags & URB_ZERO_PACKET)
+ && !(urb->transfer_buffer_length % maxpacket)) {
+ one_more = 1;
+ }
+ if (one_more) {
+ qtd_prev = qtd;
+ qtd = fotg210_qtd_alloc(fotg210, flags);
+ if (unlikely(!qtd))
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* never any data in such packets */
+ qtd_fill(fotg210, qtd, 0, 0, token, 0);
+ }
+ }
+
+ /* by default, enable interrupt on urb completion */
+ if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
+ qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC);
+ return head;
+
+cleanup:
+ qtd_list_free(fotg210, urb, head);
+ return NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+/*
+ * Would be best to create all qh's from config descriptors,
+ * when each interface/altsetting is established. Unlink
+ * any previous qh and cancel its urbs first; endpoints are
+ * implicitly reset then (data toggle too).
+ * That'd mean updating how usbcore talks to HCDs. (2.7?)
+*/
+
+
+/*
+ * Each QH holds a qtd list; a QH is used for everything except iso.
+ *
+ * For interrupt urbs, the scheduler must set the microframe scheduling
+ * mask(s) each time the QH gets scheduled. For highspeed, that's
+ * just one microframe in the s-mask. For split interrupt transactions
+ * there are additional complications: c-mask, maybe FSTNs.
+ */
+static struct fotg210_qh *
+qh_make(
+ struct fotg210_hcd *fotg210,
+ struct urb *urb,
+ gfp_t flags
+) {
+ struct fotg210_qh *qh = fotg210_qh_alloc(fotg210, flags);
+ u32 info1 = 0, info2 = 0;
+ int is_input, type;
+ int maxp = 0;
+ struct usb_tt *tt = urb->dev->tt;
+ struct fotg210_qh_hw *hw;
+
+ if (!qh)
+ return qh;
+
+ /*
+ * init endpoint/device data for this QH
+ */
+ info1 |= usb_pipeendpoint(urb->pipe) << 8;
+ info1 |= usb_pipedevice(urb->pipe) << 0;
+
+ is_input = usb_pipein(urb->pipe);
+ type = usb_pipetype(urb->pipe);
+ maxp = usb_maxpacket(urb->dev, urb->pipe, !is_input);
+
+ /* 1024 byte maxpacket is a hardware ceiling. High bandwidth
+ * acts like up to 3KB, but is built from smaller packets.
+ */
+ if (max_packet(maxp) > 1024) {
+ fotg210_dbg(fotg210, "bogus qh maxpacket %d\n",
+ max_packet(maxp));
+ goto done;
+ }
+
+ /* Compute interrupt scheduling parameters just once, and save.
+ * - allowing for high bandwidth, how many nsec/uframe are used?
+ * - split transactions need a second CSPLIT uframe; same question
+ * - splits also need a schedule gap (for full/low speed I/O)
+ * - qh has a polling interval
+ *
+ * For control/bulk requests, the HC or TT handles these.
+ */
+ if (type == PIPE_INTERRUPT) {
+ qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
+ is_input, 0,
+ hb_mult(maxp) * max_packet(maxp)));
+ qh->start = NO_FRAME;
+
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ qh->c_usecs = 0;
+ qh->gap_uf = 0;
+
+ qh->period = urb->interval >> 3;
+ if (qh->period == 0 && urb->interval != 1) {
+ /* NOTE interval 2 or 4 uframes could work.
+ * But interval 1 scheduling is simpler, and
+ * includes high bandwidth.
+ */
+ urb->interval = 1;
+ } else if (qh->period > fotg210->periodic_size) {
+ qh->period = fotg210->periodic_size;
+ urb->interval = qh->period << 3;
+ }
+ } else {
+ int think_time;
+
+ /* gap is f(FS/LS transfer times) */
+ qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed,
+ is_input, 0, maxp) / (125 * 1000);
+
+ /* FIXME this just approximates SPLIT/CSPLIT times */
+ if (is_input) { /* SPLIT, gap, CSPLIT+DATA */
+ qh->c_usecs = qh->usecs + HS_USECS(0);
+ qh->usecs = HS_USECS(1);
+ } else { /* SPLIT+DATA, gap, CSPLIT */
+ qh->usecs += HS_USECS(1);
+ qh->c_usecs = HS_USECS(0);
+ }
+
+ think_time = tt ? tt->think_time : 0;
+ qh->tt_usecs = NS_TO_US(think_time +
+ usb_calc_bus_time(urb->dev->speed,
+ is_input, 0, max_packet(maxp)));
+ qh->period = urb->interval;
+ if (qh->period > fotg210->periodic_size) {
+ qh->period = fotg210->periodic_size;
+ urb->interval = qh->period;
+ }
+ }
+ }
+
+ /* support for tt scheduling, and access to toggles */
+ qh->dev = urb->dev;
+
+ /* using TT? */
+ switch (urb->dev->speed) {
+ case USB_SPEED_LOW:
+ info1 |= QH_LOW_SPEED;
+ /* FALL THROUGH */
+
+ case USB_SPEED_FULL:
+ /* EPS 0 means "full" */
+ if (type != PIPE_INTERRUPT)
+ info1 |= (FOTG210_TUNE_RL_TT << 28);
+ if (type == PIPE_CONTROL) {
+ info1 |= QH_CONTROL_EP; /* for TT */
+ info1 |= QH_TOGGLE_CTL; /* toggle from qtd */
+ }
+ info1 |= maxp << 16;
+
+ info2 |= (FOTG210_TUNE_MULT_TT << 30);
+
+ /* Some Freescale processors have an erratum in which the
+ * port number in the queue head was 0..N-1 instead of 1..N.
+ */
+ if (fotg210_has_fsl_portno_bug(fotg210))
+ info2 |= (urb->dev->ttport-1) << 23;
+ else
+ info2 |= urb->dev->ttport << 23;
+
+ /* set the address of the TT; for TDI's integrated
+ * root hub tt, leave it zeroed.
+ */
+ if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub)
+ info2 |= tt->hub->devnum << 16;
+
+ /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+
+ break;
+
+ case USB_SPEED_HIGH: /* no TT involved */
+ info1 |= QH_HIGH_SPEED;
+ if (type == PIPE_CONTROL) {
+ info1 |= (FOTG210_TUNE_RL_HS << 28);
+ info1 |= 64 << 16; /* usb2 fixed maxpacket */
+ info1 |= QH_TOGGLE_CTL; /* toggle from qtd */
+ info2 |= (FOTG210_TUNE_MULT_HS << 30);
+ } else if (type == PIPE_BULK) {
+ info1 |= (FOTG210_TUNE_RL_HS << 28);
+ /* The USB spec says that high speed bulk endpoints
+ * always use 512 byte maxpacket. But some device
+ * vendors decided to ignore that, and MSFT is happy
+ * to help them do so. So now people expect to use
+ * such nonconformant devices with Linux too; sigh.
+ */
+ info1 |= max_packet(maxp) << 16;
+ info2 |= (FOTG210_TUNE_MULT_HS << 30);
+ } else { /* PIPE_INTERRUPT */
+ info1 |= max_packet(maxp) << 16;
+ info2 |= hb_mult(maxp) << 30;
+ }
+ break;
+ default:
+ fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev,
+ urb->dev->speed);
+done:
+ qh_destroy(fotg210, qh);
+ return NULL;
+ }
+
+ /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */
+
+ /* init as live, toggle clear, advance to dummy */
+ qh->qh_state = QH_STATE_IDLE;
+ hw = qh->hw;
+ hw->hw_info1 = cpu_to_hc32(fotg210, info1);
+ hw->hw_info2 = cpu_to_hc32(fotg210, info2);
+ qh->is_out = !is_input;
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1);
+ qh_refresh(fotg210, qh);
+ return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void enable_async(struct fotg210_hcd *fotg210)
+{
+ if (fotg210->async_count++)
+ return;
+
+ /* Stop waiting to turn off the async schedule */
+ fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC);
+
+ /* Don't start the schedule until ASS is 0 */
+ fotg210_poll_ASS(fotg210);
+ turn_on_io_watchdog(fotg210);
+}
+
+static void disable_async(struct fotg210_hcd *fotg210)
+{
+ if (--fotg210->async_count)
+ return;
+
+ /* The async schedule and async_unlink list are supposed to be empty */
+ WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink);
+
+ /* Don't turn off the schedule until ASS is 1 */
+ fotg210_poll_ASS(fotg210);
+}
+
+/* move qh (and its qtds) onto async queue; maybe enable queue. */
+
+static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+ __hc32 dma = QH_NEXT(fotg210, qh->qh_dma);
+ struct fotg210_qh *head;
+
+ /* Don't link a QH if there's a Clear-TT-Buffer pending */
+ if (unlikely(qh->clearing_tt))
+ return;
+
+ WARN_ON(qh->qh_state != QH_STATE_IDLE);
+
+ /* clear halt and/or toggle; and maybe recover from silicon quirk */
+ qh_refresh(fotg210, qh);
+
+ /* splice right after start */
+ head = fotg210->async;
+ qh->qh_next = head->qh_next;
+ qh->hw->hw_next = head->hw->hw_next;
+ wmb();
+
+ head->qh_next.qh = qh;
+ head->hw->hw_next = dma;
+
+ qh->xacterrs = 0;
+ qh->qh_state = QH_STATE_LINKED;
+ /* qtd completions reported later by interrupt */
+
+ enable_async(fotg210);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct fotg210_qh *qh_append_tds(
+ struct fotg210_hcd *fotg210,
+ struct urb *urb,
+ struct list_head *qtd_list,
+ int epnum,
+ void **ptr
+)
+{
+ struct fotg210_qh *qh = NULL;
+ __hc32 qh_addr_mask = cpu_to_hc32(fotg210, 0x7f);
+
+ qh = (struct fotg210_qh *) *ptr;
+ if (unlikely(qh == NULL)) {
+ /* can't sleep here, we have fotg210->lock... */
+ qh = qh_make(fotg210, urb, GFP_ATOMIC);
+ *ptr = qh;
+ }
+ if (likely(qh != NULL)) {
+ struct fotg210_qtd *qtd;
+
+ if (unlikely(list_empty(qtd_list)))
+ qtd = NULL;
+ else
+ qtd = list_entry(qtd_list->next, struct fotg210_qtd,
+ qtd_list);
+
+ /* control qh may need patching ... */
+ if (unlikely(epnum == 0)) {
+ /* usb_reset_device() briefly reverts to address 0 */
+ if (usb_pipedevice(urb->pipe) == 0)
+ qh->hw->hw_info1 &= ~qh_addr_mask;
+ }
+
+ /* just one way to queue requests: swap with the dummy qtd.
+ * only hc or qh_refresh() ever modify the overlay.
+ */
+ if (likely(qtd != NULL)) {
+ struct fotg210_qtd *dummy;
+ dma_addr_t dma;
+ __hc32 token;
+
+ /* to avoid racing the HC, use the dummy td instead of
+ * the first td of our list (becomes new dummy). both
+ * tds stay deactivated until we're done, when the
+ * HC is allowed to fetch the old dummy (4.10.2).
+ */
+ token = qtd->hw_token;
+ qtd->hw_token = HALT_BIT(fotg210);
+
+ dummy = qh->dummy;
+
+ dma = dummy->qtd_dma;
+ *dummy = *qtd;
+ dummy->qtd_dma = dma;
+
+ list_del(&qtd->qtd_list);
+ list_add(&dummy->qtd_list, qtd_list);
+ list_splice_tail(qtd_list, &qh->qtd_list);
+
+ fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma);
+ qh->dummy = qtd;
+
+ /* hc must see the new dummy at list end */
+ dma = qtd->qtd_dma;
+ qtd = list_entry(qh->qtd_list.prev,
+ struct fotg210_qtd, qtd_list);
+ qtd->hw_next = QTD_NEXT(fotg210, dma);
+
+ /* let the hc process these next qtds */
+ wmb();
+ dummy->hw_token = token;
+
+ urb->hcpriv = qh;
+ }
+ }
+ return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+submit_async(
+ struct fotg210_hcd *fotg210,
+ struct urb *urb,
+ struct list_head *qtd_list,
+ gfp_t mem_flags
+) {
+ int epnum;
+ unsigned long flags;
+ struct fotg210_qh *qh = NULL;
+ int rc;
+
+ epnum = urb->ep->desc.bEndpointAddress;
+
+#ifdef FOTG210_URB_TRACE
+ {
+ struct fotg210_qtd *qtd;
+ qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list);
+ fotg210_dbg(fotg210,
+ "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+ __func__, urb->dev->devpath, urb,
+ epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
+ urb->transfer_buffer_length,
+ qtd, urb->ep->hcpriv);
+ }
+#endif
+
+ spin_lock_irqsave(&fotg210->lock, flags);
+ if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
+ rc = -ESHUTDOWN;
+ goto done;
+ }
+ rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
+ if (unlikely(rc))
+ goto done;
+
+ qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
+ if (unlikely(qh == NULL)) {
+ usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ /* Control/bulk operations through TTs don't need scheduling,
+ * the HC and TT handle it when the TT has a buffer ready.
+ */
+ if (likely(qh->qh_state == QH_STATE_IDLE))
+ qh_link_async(fotg210, qh);
+ done:
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ if (unlikely(qh == NULL))
+ qtd_list_free(fotg210, urb, qtd_list);
+ return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void single_unlink_async(struct fotg210_hcd *fotg210,
+ struct fotg210_qh *qh)
+{
+ struct fotg210_qh *prev;
+
+ /* Add to the end of the list of QHs waiting for the next IAAD */
+ qh->qh_state = QH_STATE_UNLINK;
+ if (fotg210->async_unlink)
+ fotg210->async_unlink_last->unlink_next = qh;
+ else
+ fotg210->async_unlink = qh;
+ fotg210->async_unlink_last = qh;
+
+ /* Unlink it from the schedule */
+ prev = fotg210->async;
+ while (prev->qh_next.qh != qh)
+ prev = prev->qh_next.qh;
+
+ prev->hw->hw_next = qh->hw->hw_next;
+ prev->qh_next = qh->qh_next;
+ if (fotg210->qh_scan_next == qh)
+ fotg210->qh_scan_next = qh->qh_next.qh;
+}
+
+static void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested)
+{
+ /*
+ * Do nothing if an IAA cycle is already running or
+ * if one will be started shortly.
+ */
+ if (fotg210->async_iaa || fotg210->async_unlinking)
+ return;
+
+ /* Do all the waiting QHs at once */
+ fotg210->async_iaa = fotg210->async_unlink;
+ fotg210->async_unlink = NULL;
+
+ /* If the controller isn't running, we don't have to wait for it */
+ if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) {
+ if (!nested) /* Avoid recursion */
+ end_unlink_async(fotg210);
+
+ /* Otherwise start a new IAA cycle */
+ } else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) {
+ /* Make sure the unlinks are all visible to the hardware */
+ wmb();
+
+ fotg210_writel(fotg210, fotg210->command | CMD_IAAD,
+ &fotg210->regs->command);
+ fotg210_readl(fotg210, &fotg210->regs->command);
+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG,
+ true);
+ }
+}
+
+/* the async qh for the qtds being unlinked are now gone from the HC */
+
+static void end_unlink_async(struct fotg210_hcd *fotg210)
+{
+ struct fotg210_qh *qh;
+
+ /* Process the idle QHs */
+ restart:
+ fotg210->async_unlinking = true;
+ while (fotg210->async_iaa) {
+ qh = fotg210->async_iaa;
+ fotg210->async_iaa = qh->unlink_next;
+ qh->unlink_next = NULL;
+
+ qh->qh_state = QH_STATE_IDLE;
+ qh->qh_next.qh = NULL;
+
+ qh_completions(fotg210, qh);
+ if (!list_empty(&qh->qtd_list) &&
+ fotg210->rh_state == FOTG210_RH_RUNNING)
+ qh_link_async(fotg210, qh);
+ disable_async(fotg210);
+ }
+ fotg210->async_unlinking = false;
+
+ /* Start a new IAA cycle if any QHs are waiting for it */
+ if (fotg210->async_unlink) {
+ start_iaa_cycle(fotg210, true);
+ if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING))
+ goto restart;
+ }
+}
+
+static void unlink_empty_async(struct fotg210_hcd *fotg210)
+{
+ struct fotg210_qh *qh, *next;
+ bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
+ bool check_unlinks_later = false;
+
+ /* Unlink all the async QHs that have been empty for a timer cycle */
+ next = fotg210->async->qh_next.qh;
+ while (next) {
+ qh = next;
+ next = qh->qh_next.qh;
+
+ if (list_empty(&qh->qtd_list) &&
+ qh->qh_state == QH_STATE_LINKED) {
+ if (!stopped && qh->unlink_cycle ==
+ fotg210->async_unlink_cycle)
+ check_unlinks_later = true;
+ else
+ single_unlink_async(fotg210, qh);
+ }
+ }
+
+ /* Start a new IAA cycle if any QHs are waiting for it */
+ if (fotg210->async_unlink)
+ start_iaa_cycle(fotg210, false);
+
+ /* QHs that haven't been empty for long enough will be handled later */
+ if (check_unlinks_later) {
+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS,
+ true);
+ ++fotg210->async_unlink_cycle;
+ }
+}
+
+/* makes sure the async qh will become idle */
+/* caller must own fotg210->lock */
+
+static void start_unlink_async(struct fotg210_hcd *fotg210,
+ struct fotg210_qh *qh)
+{
+ /*
+ * If the QH isn't linked then there's nothing we can do
+ * unless we were called during a giveback, in which case
+ * qh_completions() has to deal with it.
+ */
+ if (qh->qh_state != QH_STATE_LINKED) {
+ if (qh->qh_state == QH_STATE_COMPLETING)
+ qh->needs_rescan = 1;
+ return;
+ }
+
+ single_unlink_async(fotg210, qh);
+ start_iaa_cycle(fotg210, false);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_async(struct fotg210_hcd *fotg210)
+{
+ struct fotg210_qh *qh;
+ bool check_unlinks_later = false;
+
+ fotg210->qh_scan_next = fotg210->async->qh_next.qh;
+ while (fotg210->qh_scan_next) {
+ qh = fotg210->qh_scan_next;
+ fotg210->qh_scan_next = qh->qh_next.qh;
+ rescan:
+ /* clean any finished work for this qh */
+ if (!list_empty(&qh->qtd_list)) {
+ int temp;
+
+ /*
+ * Unlinks could happen here; completion reporting
+ * drops the lock. That's why fotg210->qh_scan_next
+ * always holds the next qh to scan; if the next qh
+ * gets unlinked then fotg210->qh_scan_next is adjusted
+ * in single_unlink_async().
+ */
+ temp = qh_completions(fotg210, qh);
+ if (qh->needs_rescan) {
+ start_unlink_async(fotg210, qh);
+ } else if (list_empty(&qh->qtd_list)
+ && qh->qh_state == QH_STATE_LINKED) {
+ qh->unlink_cycle = fotg210->async_unlink_cycle;
+ check_unlinks_later = true;
+ } else if (temp != 0)
+ goto rescan;
+ }
+ }
+
+ /*
+ * Unlink empty entries, reducing DMA usage as well
+ * as HCD schedule-scanning costs. Delay for any qh
+ * we just scanned, there's a not-unusual case that it
+ * doesn't stay idle for long.
+ */
+ if (check_unlinks_later && fotg210->rh_state == FOTG210_RH_RUNNING &&
+ !(fotg210->enabled_hrtimer_events &
+ BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) {
+ fotg210_enable_event(fotg210,
+ FOTG210_HRTIMER_ASYNC_UNLINKS, true);
+ ++fotg210->async_unlink_cycle;
+ }
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * EHCI scheduled transaction support: interrupt, iso, split iso
+ * These are called "periodic" transactions in the EHCI spec.
+ *
+ * Note that for interrupt transfers, the QH/QTD manipulation is shared
+ * with the "asynchronous" transaction support (control/bulk transfers).
+ * The only real difference is in how interrupt transfers are scheduled.
+ *
+ * For ISO, we make an "iso_stream" head to serve the same role as a QH.
+ * It keeps track of every ITD (or SITD) that's linked, and holds enough
+ * pre-calculated schedule data to make appending to the queue be quick.
+ */
+
+static int fotg210_get_frame(struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * periodic_next_shadow - return "next" pointer on shadow list
+ * @periodic: host pointer to qh/itd
+ * @tag: hardware tag for type of this record
+ */
+static union fotg210_shadow *
+periodic_next_shadow(struct fotg210_hcd *fotg210,
+ union fotg210_shadow *periodic, __hc32 tag)
+{
+ switch (hc32_to_cpu(fotg210, tag)) {
+ case Q_TYPE_QH:
+ return &periodic->qh->qh_next;
+ case Q_TYPE_FSTN:
+ return &periodic->fstn->fstn_next;
+ default:
+ return &periodic->itd->itd_next;
+ }
+}
+
+static __hc32 *
+shadow_next_periodic(struct fotg210_hcd *fotg210,
+ union fotg210_shadow *periodic, __hc32 tag)
+{
+ switch (hc32_to_cpu(fotg210, tag)) {
+ /* our fotg210_shadow.qh is actually software part */
+ case Q_TYPE_QH:
+ return &periodic->qh->hw->hw_next;
+ /* others are hw parts */
+ default:
+ return periodic->hw_next;
+ }
+}
+
+/* caller must hold fotg210->lock */
+static void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame,
+ void *ptr)
+{
+ union fotg210_shadow *prev_p = &fotg210->pshadow[frame];
+ __hc32 *hw_p = &fotg210->periodic[frame];
+ union fotg210_shadow here = *prev_p;
+
+ /* find predecessor of "ptr"; hw and shadow lists are in sync */
+ while (here.ptr && here.ptr != ptr) {
+ prev_p = periodic_next_shadow(fotg210, prev_p,
+ Q_NEXT_TYPE(fotg210, *hw_p));
+ hw_p = shadow_next_periodic(fotg210, &here,
+ Q_NEXT_TYPE(fotg210, *hw_p));
+ here = *prev_p;
+ }
+ /* an interrupt entry (at list end) could have been shared */
+ if (!here.ptr)
+ return;
+
+ /* update shadow and hardware lists ... the old "next" pointers
+ * from ptr may still be in use, the caller updates them.
+ */
+ *prev_p = *periodic_next_shadow(fotg210, &here,
+ Q_NEXT_TYPE(fotg210, *hw_p));
+
+ *hw_p = *shadow_next_periodic(fotg210, &here,
+ Q_NEXT_TYPE(fotg210, *hw_p));
+}
+
+/* how many of the uframe's 125 usecs are allocated? */
+static unsigned short
+periodic_usecs(struct fotg210_hcd *fotg210, unsigned frame, unsigned uframe)
+{
+ __hc32 *hw_p = &fotg210->periodic[frame];
+ union fotg210_shadow *q = &fotg210->pshadow[frame];
+ unsigned usecs = 0;
+ struct fotg210_qh_hw *hw;
+
+ while (q->ptr) {
+ switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) {
+ case Q_TYPE_QH:
+ hw = q->qh->hw;
+ /* is it in the S-mask? */
+ if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe))
+ usecs += q->qh->usecs;
+ /* ... or C-mask? */
+ if (hw->hw_info2 & cpu_to_hc32(fotg210,
+ 1 << (8 + uframe)))
+ usecs += q->qh->c_usecs;
+ hw_p = &hw->hw_next;
+ q = &q->qh->qh_next;
+ break;
+ /* case Q_TYPE_FSTN: */
+ default:
+ /* for "save place" FSTNs, count the relevant INTR
+ * bandwidth from the previous frame
+ */
+ if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210))
+ fotg210_dbg(fotg210, "ignoring FSTN cost ...\n");
+
+ hw_p = &q->fstn->hw_next;
+ q = &q->fstn->fstn_next;
+ break;
+ case Q_TYPE_ITD:
+ if (q->itd->hw_transaction[uframe])
+ usecs += q->itd->stream->usecs;
+ hw_p = &q->itd->hw_next;
+ q = &q->itd->itd_next;
+ break;
+ }
+ }
+#ifdef DEBUG
+ if (usecs > fotg210->uframe_periodic_max)
+ fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n",
+ frame * 8 + uframe, usecs);
+#endif
+ return usecs;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int same_tt(struct usb_device *dev1, struct usb_device *dev2)
+{
+ if (!dev1->tt || !dev2->tt)
+ return 0;
+ if (dev1->tt != dev2->tt)
+ return 0;
+ if (dev1->tt->multi)
+ return dev1->ttport == dev2->ttport;
+ else
+ return 1;
+}
+
+/* return true iff the device's transaction translator is available
+ * for a periodic transfer starting at the specified frame, using
+ * all the uframes in the mask.
+ */
+static int tt_no_collision(
+ struct fotg210_hcd *fotg210,
+ unsigned period,
+ struct usb_device *dev,
+ unsigned frame,
+ u32 uf_mask
+)
+{
+ if (period == 0) /* error */
+ return 0;
+
+ /* note bandwidth wastage: split never follows csplit
+ * (different dev or endpoint) until the next uframe.
+ * calling convention doesn't make that distinction.
+ */
+ for (; frame < fotg210->periodic_size; frame += period) {
+ union fotg210_shadow here;
+ __hc32 type;
+ struct fotg210_qh_hw *hw;
+
+ here = fotg210->pshadow[frame];
+ type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]);
+ while (here.ptr) {
+ switch (hc32_to_cpu(fotg210, type)) {
+ case Q_TYPE_ITD:
+ type = Q_NEXT_TYPE(fotg210, here.itd->hw_next);
+ here = here.itd->itd_next;
+ continue;
+ case Q_TYPE_QH:
+ hw = here.qh->hw;
+ if (same_tt(dev, here.qh->dev)) {
+ u32 mask;
+
+ mask = hc32_to_cpu(fotg210,
+ hw->hw_info2);
+ /* "knows" no gap is needed */
+ mask |= mask >> 8;
+ if (mask & uf_mask)
+ break;
+ }
+ type = Q_NEXT_TYPE(fotg210, hw->hw_next);
+ here = here.qh->qh_next;
+ continue;
+ /* case Q_TYPE_FSTN: */
+ default:
+ fotg210_dbg(fotg210,
+ "periodic frame %d bogus type %d\n",
+ frame, type);
+ }
+
+ /* collision or error */
+ return 0;
+ }
+ }
+
+ /* no collision */
+ return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void enable_periodic(struct fotg210_hcd *fotg210)
+{
+ if (fotg210->periodic_count++)
+ return;
+
+ /* Stop waiting to turn off the periodic schedule */
+ fotg210->enabled_hrtimer_events &=
+ ~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC);
+
+ /* Don't start the schedule until PSS is 0 */
+ fotg210_poll_PSS(fotg210);
+ turn_on_io_watchdog(fotg210);
+}
+
+static void disable_periodic(struct fotg210_hcd *fotg210)
+{
+ if (--fotg210->periodic_count)
+ return;
+
+ /* Don't turn off the schedule until PSS is 1 */
+ fotg210_poll_PSS(fotg210);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* periodic schedule slots have iso tds (normal or split) first, then a
+ * sparse tree for active interrupt transfers.
+ *
+ * this just links in a qh; caller guarantees uframe masks are set right.
+ * no FSTN support (yet; fotg210 0.96+)
+ */
+static void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+ unsigned i;
+ unsigned period = qh->period;
+
+ dev_dbg(&qh->dev->dev,
+ "link qh%d-%04x/%p start %d [%d/%d us]\n",
+ period, hc32_to_cpup(fotg210, &qh->hw->hw_info2)
+ & (QH_CMASK | QH_SMASK),
+ qh, qh->start, qh->usecs, qh->c_usecs);
+
+ /* high bandwidth, or otherwise every microframe */
+ if (period == 0)
+ period = 1;
+
+ for (i = qh->start; i < fotg210->periodic_size; i += period) {
+ union fotg210_shadow *prev = &fotg210->pshadow[i];
+ __hc32 *hw_p = &fotg210->periodic[i];
+ union fotg210_shadow here = *prev;
+ __hc32 type = 0;
+
+ /* skip the iso nodes at list head */
+ while (here.ptr) {
+ type = Q_NEXT_TYPE(fotg210, *hw_p);
+ if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
+ break;
+ prev = periodic_next_shadow(fotg210, prev, type);
+ hw_p = shadow_next_periodic(fotg210, &here, type);
+ here = *prev;
+ }
+
+ /* sorting each branch by period (slow-->fast)
+ * enables sharing interior tree nodes
+ */
+ while (here.ptr && qh != here.qh) {
+ if (qh->period > here.qh->period)
+ break;
+ prev = &here.qh->qh_next;
+ hw_p = &here.qh->hw->hw_next;
+ here = *prev;
+ }
+ /* link in this qh, unless some earlier pass did that */
+ if (qh != here.qh) {
+ qh->qh_next = here;
+ if (here.qh)
+ qh->hw->hw_next = *hw_p;
+ wmb();
+ prev->qh = qh;
+ *hw_p = QH_NEXT(fotg210, qh->qh_dma);
+ }
+ }
+ qh->qh_state = QH_STATE_LINKED;
+ qh->xacterrs = 0;
+
+ /* update per-qh bandwidth for usbfs */
+ fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period
+ ? ((qh->usecs + qh->c_usecs) / qh->period)
+ : (qh->usecs * 8);
+
+ list_add(&qh->intr_node, &fotg210->intr_qh_list);
+
+ /* maybe enable periodic schedule processing */
+ ++fotg210->intr_count;
+ enable_periodic(fotg210);
+}
+
+static void qh_unlink_periodic(struct fotg210_hcd *fotg210,
+ struct fotg210_qh *qh)
+{
+ unsigned i;
+ unsigned period;
+
+ /*
+ * If qh is for a low/full-speed device, simply unlinking it
+ * could interfere with an ongoing split transaction. To unlink
+ * it safely would require setting the QH_INACTIVATE bit and
+ * waiting at least one frame, as described in EHCI 4.12.2.5.
+ *
+ * We won't bother with any of this. Instead, we assume that the
+ * only reason for unlinking an interrupt QH while the current URB
+ * is still active is to dequeue all the URBs (flush the whole
+ * endpoint queue).
+ *
+ * If rebalancing the periodic schedule is ever implemented, this
+ * approach will no longer be valid.
+ */
+
+ /* high bandwidth, or otherwise part of every microframe */
+ period = qh->period;
+ if (!period)
+ period = 1;
+
+ for (i = qh->start; i < fotg210->periodic_size; i += period)
+ periodic_unlink(fotg210, i, qh);
+
+ /* update per-qh bandwidth for usbfs */
+ fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period
+ ? ((qh->usecs + qh->c_usecs) / qh->period)
+ : (qh->usecs * 8);
+
+ dev_dbg(&qh->dev->dev,
+ "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
+ qh->period,
+ hc32_to_cpup(fotg210, &qh->hw->hw_info2) &
+ (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs);
+
+ /* qh->qh_next still "live" to HC */
+ qh->qh_state = QH_STATE_UNLINK;
+ qh->qh_next.ptr = NULL;
+
+ if (fotg210->qh_scan_next == qh)
+ fotg210->qh_scan_next = list_entry(qh->intr_node.next,
+ struct fotg210_qh, intr_node);
+ list_del(&qh->intr_node);
+}
+
+static void start_unlink_intr(struct fotg210_hcd *fotg210,
+ struct fotg210_qh *qh)
+{
+ /* If the QH isn't linked then there's nothing we can do
+ * unless we were called during a giveback, in which case
+ * qh_completions() has to deal with it.
+ */
+ if (qh->qh_state != QH_STATE_LINKED) {
+ if (qh->qh_state == QH_STATE_COMPLETING)
+ qh->needs_rescan = 1;
+ return;
+ }
+
+ qh_unlink_periodic(fotg210, qh);
+
+ /* Make sure the unlinks are visible before starting the timer */
+ wmb();
+
+ /*
+ * The EHCI spec doesn't say how long it takes the controller to
+ * stop accessing an unlinked interrupt QH. The timer delay is
+ * 9 uframes; presumably that will be long enough.
+ */
+ qh->unlink_cycle = fotg210->intr_unlink_cycle;
+
+ /* New entries go at the end of the intr_unlink list */
+ if (fotg210->intr_unlink)
+ fotg210->intr_unlink_last->unlink_next = qh;
+ else
+ fotg210->intr_unlink = qh;
+ fotg210->intr_unlink_last = qh;
+
+ if (fotg210->intr_unlinking)
+ ; /* Avoid recursive calls */
+ else if (fotg210->rh_state < FOTG210_RH_RUNNING)
+ fotg210_handle_intr_unlinks(fotg210);
+ else if (fotg210->intr_unlink == qh) {
+ fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
+ true);
+ ++fotg210->intr_unlink_cycle;
+ }
+}
+
+static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+ struct fotg210_qh_hw *hw = qh->hw;
+ int rc;
+
+ qh->qh_state = QH_STATE_IDLE;
+ hw->hw_next = FOTG210_LIST_END(fotg210);
+
+ qh_completions(fotg210, qh);
+
+ /* reschedule QH iff another request is queued */
+ if (!list_empty(&qh->qtd_list) &&
+ fotg210->rh_state == FOTG210_RH_RUNNING) {
+ rc = qh_schedule(fotg210, qh);
+
+ /* An error here likely indicates handshake failure
+ * or no space left in the schedule. Neither fault
+ * should happen often ...
+ *
+ * FIXME kill the now-dysfunctional queued urbs
+ */
+ if (rc != 0)
+ fotg210_err(fotg210, "can't reschedule qh %p, err %d\n",
+ qh, rc);
+ }
+
+ /* maybe turn off periodic schedule */
+ --fotg210->intr_count;
+ disable_periodic(fotg210);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int check_period(
+ struct fotg210_hcd *fotg210,
+ unsigned frame,
+ unsigned uframe,
+ unsigned period,
+ unsigned usecs
+) {
+ int claimed;
+
+ /* complete split running into next frame?
+ * given FSTN support, we could sometimes check...
+ */
+ if (uframe >= 8)
+ return 0;
+
+ /* convert "usecs we need" to "max already claimed" */
+ usecs = fotg210->uframe_periodic_max - usecs;
+
+ /* we "know" 2 and 4 uframe intervals were rejected; so
+ * for period 0, check _every_ microframe in the schedule.
+ */
+ if (unlikely(period == 0)) {
+ do {
+ for (uframe = 0; uframe < 7; uframe++) {
+ claimed = periodic_usecs(fotg210, frame,
+ uframe);
+ if (claimed > usecs)
+ return 0;
+ }
+ } while ((frame += 1) < fotg210->periodic_size);
+
+ /* just check the specified uframe, at that period */
+ } else {
+ do {
+ claimed = periodic_usecs(fotg210, frame, uframe);
+ if (claimed > usecs)
+ return 0;
+ } while ((frame += period) < fotg210->periodic_size);
+ }
+
+ /* success! */
+ return 1;
+}
+
+static int check_intr_schedule(
+ struct fotg210_hcd *fotg210,
+ unsigned frame,
+ unsigned uframe,
+ const struct fotg210_qh *qh,
+ __hc32 *c_maskp
+)
+{
+ int retval = -ENOSPC;
+ u8 mask = 0;
+
+ if (qh->c_usecs && uframe >= 6) /* FSTN territory? */
+ goto done;
+
+ if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs))
+ goto done;
+ if (!qh->c_usecs) {
+ retval = 0;
+ *c_maskp = 0;
+ goto done;
+ }
+
+ /* Make sure this tt's buffer is also available for CSPLITs.
+ * We pessimize a bit; probably the typical full speed case
+ * doesn't need the second CSPLIT.
+ *
+ * NOTE: both SPLIT and CSPLIT could be checked in just
+ * one smart pass...
+ */
+ mask = 0x03 << (uframe + qh->gap_uf);
+ *c_maskp = cpu_to_hc32(fotg210, mask << 8);
+
+ mask |= 1 << uframe;
+ if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) {
+ if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1,
+ qh->period, qh->c_usecs))
+ goto done;
+ if (!check_period(fotg210, frame, uframe + qh->gap_uf,
+ qh->period, qh->c_usecs))
+ goto done;
+ retval = 0;
+ }
+done:
+ return retval;
+}
+
+/* "first fit" scheduling policy used the first time through,
+ * or when the previous schedule slot can't be re-used.
+ */
+static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+ int status;
+ unsigned uframe;
+ __hc32 c_mask;
+ unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
+ struct fotg210_qh_hw *hw = qh->hw;
+
+ qh_refresh(fotg210, qh);
+ hw->hw_next = FOTG210_LIST_END(fotg210);
+ frame = qh->start;
+
+ /* reuse the previous schedule slots, if we can */
+ if (frame < qh->period) {
+ uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK);
+ status = check_intr_schedule(fotg210, frame, --uframe,
+ qh, &c_mask);
+ } else {
+ uframe = 0;
+ c_mask = 0;
+ status = -ENOSPC;
+ }
+
+ /* else scan the schedule to find a group of slots such that all
+ * uframes have enough periodic bandwidth available.
+ */
+ if (status) {
+ /* "normal" case, uframing flexible except with splits */
+ if (qh->period) {
+ int i;
+
+ for (i = qh->period; status && i > 0; --i) {
+ frame = ++fotg210->random_frame % qh->period;
+ for (uframe = 0; uframe < 8; uframe++) {
+ status = check_intr_schedule(fotg210,
+ frame, uframe, qh,
+ &c_mask);
+ if (status == 0)
+ break;
+ }
+ }
+
+ /* qh->period == 0 means every uframe */
+ } else {
+ frame = 0;
+ status = check_intr_schedule(fotg210, 0, 0, qh,
+ &c_mask);
+ }
+ if (status)
+ goto done;
+ qh->start = frame;
+
+ /* reset S-frame and (maybe) C-frame masks */
+ hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK));
+ hw->hw_info2 |= qh->period
+ ? cpu_to_hc32(fotg210, 1 << uframe)
+ : cpu_to_hc32(fotg210, QH_SMASK);
+ hw->hw_info2 |= c_mask;
+ } else
+ fotg210_dbg(fotg210, "reused qh %p schedule\n", qh);
+
+ /* stuff into the periodic schedule */
+ qh_link_periodic(fotg210, qh);
+done:
+ return status;
+}
+
+static int intr_submit(
+ struct fotg210_hcd *fotg210,
+ struct urb *urb,
+ struct list_head *qtd_list,
+ gfp_t mem_flags
+) {
+ unsigned epnum;
+ unsigned long flags;
+ struct fotg210_qh *qh;
+ int status;
+ struct list_head empty;
+
+ /* get endpoint and transfer/schedule data */
+ epnum = urb->ep->desc.bEndpointAddress;
+
+ spin_lock_irqsave(&fotg210->lock, flags);
+
+ if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
+ status = -ESHUTDOWN;
+ goto done_not_linked;
+ }
+ status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
+ if (unlikely(status))
+ goto done_not_linked;
+
+ /* get qh and force any scheduling errors */
+ INIT_LIST_HEAD(&empty);
+ qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv);
+ if (qh == NULL) {
+ status = -ENOMEM;
+ goto done;
+ }
+ if (qh->qh_state == QH_STATE_IDLE) {
+ status = qh_schedule(fotg210, qh);
+ if (status)
+ goto done;
+ }
+
+ /* then queue the urb's tds to the qh */
+ qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
+ BUG_ON(qh == NULL);
+
+ /* ... update usbfs periodic stats */
+ fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++;
+
+done:
+ if (unlikely(status))
+ usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+done_not_linked:
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ if (status)
+ qtd_list_free(fotg210, urb, qtd_list);
+
+ return status;
+}
+
+static void scan_intr(struct fotg210_hcd *fotg210)
+{
+ struct fotg210_qh *qh;
+
+ list_for_each_entry_safe(qh, fotg210->qh_scan_next,
+ &fotg210->intr_qh_list, intr_node) {
+ rescan:
+ /* clean any finished work for this qh */
+ if (!list_empty(&qh->qtd_list)) {
+ int temp;
+
+ /*
+ * Unlinks could happen here; completion reporting
+ * drops the lock. That's why fotg210->qh_scan_next
+ * always holds the next qh to scan; if the next qh
+ * gets unlinked then fotg210->qh_scan_next is adjusted
+ * in qh_unlink_periodic().
+ */
+ temp = qh_completions(fotg210, qh);
+ if (unlikely(qh->needs_rescan ||
+ (list_empty(&qh->qtd_list) &&
+ qh->qh_state == QH_STATE_LINKED)))
+ start_unlink_intr(fotg210, qh);
+ else if (temp != 0)
+ goto rescan;
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* fotg210_iso_stream ops work with both ITD and SITD */
+
+static struct fotg210_iso_stream *
+iso_stream_alloc(gfp_t mem_flags)
+{
+ struct fotg210_iso_stream *stream;
+
+ stream = kzalloc(sizeof(*stream), mem_flags);
+ if (likely(stream != NULL)) {
+ INIT_LIST_HEAD(&stream->td_list);
+ INIT_LIST_HEAD(&stream->free_list);
+ stream->next_uframe = -1;
+ }
+ return stream;
+}
+
+static void
+iso_stream_init(
+ struct fotg210_hcd *fotg210,
+ struct fotg210_iso_stream *stream,
+ struct usb_device *dev,
+ int pipe,
+ unsigned interval
+)
+{
+ u32 buf1;
+ unsigned epnum, maxp;
+ int is_input;
+ long bandwidth;
+ unsigned multi;
+
+ /*
+ * this might be a "high bandwidth" highspeed endpoint,
+ * as encoded in the ep descriptor's wMaxPacket field
+ */
+ epnum = usb_pipeendpoint(pipe);
+ is_input = usb_pipein(pipe) ? USB_DIR_IN : 0;
+ maxp = usb_maxpacket(dev, pipe, !is_input);
+ if (is_input)
+ buf1 = (1 << 11);
+ else
+ buf1 = 0;
+
+ maxp = max_packet(maxp);
+ multi = hb_mult(maxp);
+ buf1 |= maxp;
+ maxp *= multi;
+
+ stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum);
+ stream->buf1 = cpu_to_hc32(fotg210, buf1);
+ stream->buf2 = cpu_to_hc32(fotg210, multi);
+
+ /* usbfs wants to report the average usecs per frame tied up
+ * when transfers on this endpoint are scheduled ...
+ */
+ if (dev->speed == USB_SPEED_FULL) {
+ interval <<= 3;
+ stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed,
+ is_input, 1, maxp));
+ stream->usecs /= 8;
+ } else {
+ stream->highspeed = 1;
+ stream->usecs = HS_USECS_ISO(maxp);
+ }
+ bandwidth = stream->usecs * 8;
+ bandwidth /= interval;
+
+ stream->bandwidth = bandwidth;
+ stream->udev = dev;
+ stream->bEndpointAddress = is_input | epnum;
+ stream->interval = interval;
+ stream->maxp = maxp;
+}
+
+static struct fotg210_iso_stream *
+iso_stream_find(struct fotg210_hcd *fotg210, struct urb *urb)
+{
+ unsigned epnum;
+ struct fotg210_iso_stream *stream;
+ struct usb_host_endpoint *ep;
+ unsigned long flags;
+
+ epnum = usb_pipeendpoint(urb->pipe);
+ if (usb_pipein(urb->pipe))
+ ep = urb->dev->ep_in[epnum];
+ else
+ ep = urb->dev->ep_out[epnum];
+
+ spin_lock_irqsave(&fotg210->lock, flags);
+ stream = ep->hcpriv;
+
+ if (unlikely(stream == NULL)) {
+ stream = iso_stream_alloc(GFP_ATOMIC);
+ if (likely(stream != NULL)) {
+ ep->hcpriv = stream;
+ stream->ep = ep;
+ iso_stream_init(fotg210, stream, urb->dev, urb->pipe,
+ urb->interval);
+ }
+
+ /* if dev->ep[epnum] is a QH, hw is set */
+ } else if (unlikely(stream->hw != NULL)) {
+ fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n",
+ urb->dev->devpath, epnum,
+ usb_pipein(urb->pipe) ? "in" : "out");
+ stream = NULL;
+ }
+
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ return stream;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* fotg210_iso_sched ops can be ITD-only or SITD-only */
+
+static struct fotg210_iso_sched *
+iso_sched_alloc(unsigned packets, gfp_t mem_flags)
+{
+ struct fotg210_iso_sched *iso_sched;
+ int size = sizeof(*iso_sched);
+
+ size += packets * sizeof(struct fotg210_iso_packet);
+ iso_sched = kzalloc(size, mem_flags);
+ if (likely(iso_sched != NULL))
+ INIT_LIST_HEAD(&iso_sched->td_list);
+
+ return iso_sched;
+}
+
+static inline void
+itd_sched_init(
+ struct fotg210_hcd *fotg210,
+ struct fotg210_iso_sched *iso_sched,
+ struct fotg210_iso_stream *stream,
+ struct urb *urb
+)
+{
+ unsigned i;
+ dma_addr_t dma = urb->transfer_dma;
+
+ /* how many uframes are needed for these transfers */
+ iso_sched->span = urb->number_of_packets * stream->interval;
+
+ /* figure out per-uframe itd fields that we'll need later
+ * when we fit new itds into the schedule.
+ */
+ for (i = 0; i < urb->number_of_packets; i++) {
+ struct fotg210_iso_packet *uframe = &iso_sched->packet[i];
+ unsigned length;
+ dma_addr_t buf;
+ u32 trans;
+
+ length = urb->iso_frame_desc[i].length;
+ buf = dma + urb->iso_frame_desc[i].offset;
+
+ trans = FOTG210_ISOC_ACTIVE;
+ trans |= buf & 0x0fff;
+ if (unlikely(((i + 1) == urb->number_of_packets))
+ && !(urb->transfer_flags & URB_NO_INTERRUPT))
+ trans |= FOTG210_ITD_IOC;
+ trans |= length << 16;
+ uframe->transaction = cpu_to_hc32(fotg210, trans);
+
+ /* might need to cross a buffer page within a uframe */
+ uframe->bufp = (buf & ~(u64)0x0fff);
+ buf += length;
+ if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff))))
+ uframe->cross = 1;
+ }
+}
+
+static void
+iso_sched_free(
+ struct fotg210_iso_stream *stream,
+ struct fotg210_iso_sched *iso_sched
+)
+{
+ if (!iso_sched)
+ return;
+ /* caller must hold fotg210->lock!*/
+ list_splice(&iso_sched->td_list, &stream->free_list);
+ kfree(iso_sched);
+}
+
+static int
+itd_urb_transaction(
+ struct fotg210_iso_stream *stream,
+ struct fotg210_hcd *fotg210,
+ struct urb *urb,
+ gfp_t mem_flags
+)
+{
+ struct fotg210_itd *itd;
+ dma_addr_t itd_dma;
+ int i;
+ unsigned num_itds;
+ struct fotg210_iso_sched *sched;
+ unsigned long flags;
+
+ sched = iso_sched_alloc(urb->number_of_packets, mem_flags);
+ if (unlikely(sched == NULL))
+ return -ENOMEM;
+
+ itd_sched_init(fotg210, sched, stream, urb);
+
+ if (urb->interval < 8)
+ num_itds = 1 + (sched->span + 7) / 8;
+ else
+ num_itds = urb->number_of_packets;
+
+ /* allocate/init ITDs */
+ spin_lock_irqsave(&fotg210->lock, flags);
+ for (i = 0; i < num_itds; i++) {
+
+ /*
+ * Use iTDs from the free list, but not iTDs that may
+ * still be in use by the hardware.
+ */
+ if (likely(!list_empty(&stream->free_list))) {
+ itd = list_first_entry(&stream->free_list,
+ struct fotg210_itd, itd_list);
+ if (itd->frame == fotg210->now_frame)
+ goto alloc_itd;
+ list_del(&itd->itd_list);
+ itd_dma = itd->itd_dma;
+ } else {
+ alloc_itd:
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ itd = dma_pool_alloc(fotg210->itd_pool, mem_flags,
+ &itd_dma);
+ spin_lock_irqsave(&fotg210->lock, flags);
+ if (!itd) {
+ iso_sched_free(stream, sched);
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ return -ENOMEM;
+ }
+ }
+
+ memset(itd, 0, sizeof(*itd));
+ itd->itd_dma = itd_dma;
+ list_add(&itd->itd_list, &sched->td_list);
+ }
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+
+ /* temporarily store schedule info in hcpriv */
+ urb->hcpriv = sched;
+ urb->error_count = 0;
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline int
+itd_slot_ok(
+ struct fotg210_hcd *fotg210,
+ u32 mod,
+ u32 uframe,
+ u8 usecs,
+ u32 period
+)
+{
+ uframe %= period;
+ do {
+ /* can't commit more than uframe_periodic_max usec */
+ if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7)
+ > (fotg210->uframe_periodic_max - usecs))
+ return 0;
+
+ /* we know urb->interval is 2^N uframes */
+ uframe += period;
+ } while (uframe < mod);
+ return 1;
+}
+
+/*
+ * This scheduler plans almost as far into the future as it has actual
+ * periodic schedule slots. (Affected by TUNE_FLS, which defaults to
+ * "as small as possible" to be cache-friendlier.) That limits the size
+ * transfers you can stream reliably; avoid more than 64 msec per urb.
+ * Also avoid queue depths of less than fotg210's worst irq latency (affected
+ * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
+ * and other factors); or more than about 230 msec total (for portability,
+ * given FOTG210_TUNE_FLS and the slop). Or, write a smarter scheduler!
+ */
+
+#define SCHEDULE_SLOP 80 /* microframes */
+
+static int
+iso_stream_schedule(
+ struct fotg210_hcd *fotg210,
+ struct urb *urb,
+ struct fotg210_iso_stream *stream
+)
+{
+ u32 now, next, start, period, span;
+ int status;
+ unsigned mod = fotg210->periodic_size << 3;
+ struct fotg210_iso_sched *sched = urb->hcpriv;
+
+ period = urb->interval;
+ span = sched->span;
+
+ if (span > mod - SCHEDULE_SLOP) {
+ fotg210_dbg(fotg210, "iso request %p too long\n", urb);
+ status = -EFBIG;
+ goto fail;
+ }
+
+ now = fotg210_read_frame_index(fotg210) & (mod - 1);
+
+ /* Typical case: reuse current schedule, stream is still active.
+ * Hopefully there are no gaps from the host falling behind
+ * (irq delays etc), but if there are we'll take the next
+ * slot in the schedule, implicitly assuming URB_ISO_ASAP.
+ */
+ if (likely(!list_empty(&stream->td_list))) {
+ u32 excess;
+
+ /* For high speed devices, allow scheduling within the
+ * isochronous scheduling threshold. For full speed devices
+ * and Intel PCI-based controllers, don't (work around for
+ * Intel ICH9 bug).
+ */
+ if (!stream->highspeed && fotg210->fs_i_thresh)
+ next = now + fotg210->i_thresh;
+ else
+ next = now;
+
+ /* Fell behind (by up to twice the slop amount)?
+ * We decide based on the time of the last currently-scheduled
+ * slot, not the time of the next available slot.
+ */
+ excess = (stream->next_uframe - period - next) & (mod - 1);
+ if (excess >= mod - 2 * SCHEDULE_SLOP)
+ start = next + excess - mod + period *
+ DIV_ROUND_UP(mod - excess, period);
+ else
+ start = next + excess + period;
+ if (start - now >= mod) {
+ fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
+ urb, start - now - period, period,
+ mod);
+ status = -EFBIG;
+ goto fail;
+ }
+ }
+
+ /* need to schedule; when's the next (u)frame we could start?
+ * this is bigger than fotg210->i_thresh allows; scheduling itself
+ * isn't free, the slop should handle reasonably slow cpus. it
+ * can also help high bandwidth if the dma and irq loads don't
+ * jump until after the queue is primed.
+ */
+ else {
+ int done = 0;
+ start = SCHEDULE_SLOP + (now & ~0x07);
+
+ /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
+
+ /* find a uframe slot with enough bandwidth.
+ * Early uframes are more precious because full-speed
+ * iso IN transfers can't use late uframes,
+ * and therefore they should be allocated last.
+ */
+ next = start;
+ start += period;
+ do {
+ start--;
+ /* check schedule: enough space? */
+ if (itd_slot_ok(fotg210, mod, start,
+ stream->usecs, period))
+ done = 1;
+ } while (start > next && !done);
+
+ /* no room in the schedule */
+ if (!done) {
+ fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n",
+ urb, now, now + mod);
+ status = -ENOSPC;
+ goto fail;
+ }
+ }
+
+ /* Tried to schedule too far into the future? */
+ if (unlikely(start - now + span - period
+ >= mod - 2 * SCHEDULE_SLOP)) {
+ fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
+ urb, start - now, span - period,
+ mod - 2 * SCHEDULE_SLOP);
+ status = -EFBIG;
+ goto fail;
+ }
+
+ stream->next_uframe = start & (mod - 1);
+
+ /* report high speed start in uframes; full speed, in frames */
+ urb->start_frame = stream->next_uframe;
+ if (!stream->highspeed)
+ urb->start_frame >>= 3;
+
+ /* Make sure scan_isoc() sees these */
+ if (fotg210->isoc_count == 0)
+ fotg210->next_frame = now >> 3;
+ return 0;
+
+ fail:
+ iso_sched_free(stream, sched);
+ urb->hcpriv = NULL;
+ return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+itd_init(struct fotg210_hcd *fotg210, struct fotg210_iso_stream *stream,
+ struct fotg210_itd *itd)
+{
+ int i;
+
+ /* it's been recently zeroed */
+ itd->hw_next = FOTG210_LIST_END(fotg210);
+ itd->hw_bufp[0] = stream->buf0;
+ itd->hw_bufp[1] = stream->buf1;
+ itd->hw_bufp[2] = stream->buf2;
+
+ for (i = 0; i < 8; i++)
+ itd->index[i] = -1;
+
+ /* All other fields are filled when scheduling */
+}
+
+static inline void
+itd_patch(
+ struct fotg210_hcd *fotg210,
+ struct fotg210_itd *itd,
+ struct fotg210_iso_sched *iso_sched,
+ unsigned index,
+ u16 uframe
+)
+{
+ struct fotg210_iso_packet *uf = &iso_sched->packet[index];
+ unsigned pg = itd->pg;
+
+ uframe &= 0x07;
+ itd->index[uframe] = index;
+
+ itd->hw_transaction[uframe] = uf->transaction;
+ itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12);
+ itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0);
+ itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32));
+
+ /* iso_frame_desc[].offset must be strictly increasing */
+ if (unlikely(uf->cross)) {
+ u64 bufp = uf->bufp + 4096;
+
+ itd->pg = ++pg;
+ itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0);
+ itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32));
+ }
+}
+
+static inline void
+itd_link(struct fotg210_hcd *fotg210, unsigned frame, struct fotg210_itd *itd)
+{
+ union fotg210_shadow *prev = &fotg210->pshadow[frame];
+ __hc32 *hw_p = &fotg210->periodic[frame];
+ union fotg210_shadow here = *prev;
+ __hc32 type = 0;
+
+ /* skip any iso nodes which might belong to previous microframes */
+ while (here.ptr) {
+ type = Q_NEXT_TYPE(fotg210, *hw_p);
+ if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
+ break;
+ prev = periodic_next_shadow(fotg210, prev, type);
+ hw_p = shadow_next_periodic(fotg210, &here, type);
+ here = *prev;
+ }
+
+ itd->itd_next = here;
+ itd->hw_next = *hw_p;
+ prev->itd = itd;
+ itd->frame = frame;
+ wmb();
+ *hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD);
+}
+
+/* fit urb's itds into the selected schedule slot; activate as needed */
+static void itd_link_urb(
+ struct fotg210_hcd *fotg210,
+ struct urb *urb,
+ unsigned mod,
+ struct fotg210_iso_stream *stream
+)
+{
+ int packet;
+ unsigned next_uframe, uframe, frame;
+ struct fotg210_iso_sched *iso_sched = urb->hcpriv;
+ struct fotg210_itd *itd;
+
+ next_uframe = stream->next_uframe & (mod - 1);
+
+ if (unlikely(list_empty(&stream->td_list))) {
+ fotg210_to_hcd(fotg210)->self.bandwidth_allocated
+ += stream->bandwidth;
+ fotg210_vdbg(fotg210,
+ "schedule devp %s ep%d%s-iso period %d start %d.%d\n",
+ urb->dev->devpath, stream->bEndpointAddress & 0x0f,
+ (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
+ urb->interval,
+ next_uframe >> 3, next_uframe & 0x7);
+ }
+
+ /* fill iTDs uframe by uframe */
+ for (packet = 0, itd = NULL; packet < urb->number_of_packets;) {
+ if (itd == NULL) {
+ /* ASSERT: we have all necessary itds */
+
+ /* ASSERT: no itds for this endpoint in this uframe */
+
+ itd = list_entry(iso_sched->td_list.next,
+ struct fotg210_itd, itd_list);
+ list_move_tail(&itd->itd_list, &stream->td_list);
+ itd->stream = stream;
+ itd->urb = urb;
+ itd_init(fotg210, stream, itd);
+ }
+
+ uframe = next_uframe & 0x07;
+ frame = next_uframe >> 3;
+
+ itd_patch(fotg210, itd, iso_sched, packet, uframe);
+
+ next_uframe += stream->interval;
+ next_uframe &= mod - 1;
+ packet++;
+
+ /* link completed itds into the schedule */
+ if (((next_uframe >> 3) != frame)
+ || packet == urb->number_of_packets) {
+ itd_link(fotg210, frame & (fotg210->periodic_size - 1),
+ itd);
+ itd = NULL;
+ }
+ }
+ stream->next_uframe = next_uframe;
+
+ /* don't need that schedule data any more */
+ iso_sched_free(stream, iso_sched);
+ urb->hcpriv = NULL;
+
+ ++fotg210->isoc_count;
+ enable_periodic(fotg210);
+}
+
+#define ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\
+ FOTG210_ISOC_XACTERR)
+
+/* Process and recycle a completed ITD. Return true iff its urb completed,
+ * and hence its completion callback probably added things to the hardware
+ * schedule.
+ *
+ * Note that we carefully avoid recycling this descriptor until after any
+ * completion callback runs, so that it won't be reused quickly. That is,
+ * assuming (a) no more than two urbs per frame on this endpoint, and also
+ * (b) only this endpoint's completions submit URBs. It seems some silicon
+ * corrupts things if you reuse completed descriptors very quickly...
+ */
+static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
+{
+ struct urb *urb = itd->urb;
+ struct usb_iso_packet_descriptor *desc;
+ u32 t;
+ unsigned uframe;
+ int urb_index = -1;
+ struct fotg210_iso_stream *stream = itd->stream;
+ struct usb_device *dev;
+ bool retval = false;
+
+ /* for each uframe with a packet */
+ for (uframe = 0; uframe < 8; uframe++) {
+ if (likely(itd->index[uframe] == -1))
+ continue;
+ urb_index = itd->index[uframe];
+ desc = &urb->iso_frame_desc[urb_index];
+
+ t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]);
+ itd->hw_transaction[uframe] = 0;
+
+ /* report transfer status */
+ if (unlikely(t & ISO_ERRS)) {
+ urb->error_count++;
+ if (t & FOTG210_ISOC_BUF_ERR)
+ desc->status = usb_pipein(urb->pipe)
+ ? -ENOSR /* hc couldn't read */
+ : -ECOMM; /* hc couldn't write */
+ else if (t & FOTG210_ISOC_BABBLE)
+ desc->status = -EOVERFLOW;
+ else /* (t & FOTG210_ISOC_XACTERR) */
+ desc->status = -EPROTO;
+
+ /* HC need not update length with this error */
+ if (!(t & FOTG210_ISOC_BABBLE)) {
+ desc->actual_length =
+ fotg210_itdlen(urb, desc, t);
+ urb->actual_length += desc->actual_length;
+ }
+ } else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) {
+ desc->status = 0;
+ desc->actual_length = fotg210_itdlen(urb, desc, t);
+ urb->actual_length += desc->actual_length;
+ } else {
+ /* URB was too late */
+ desc->status = -EXDEV;
+ }
+ }
+
+ /* handle completion now? */
+ if (likely((urb_index + 1) != urb->number_of_packets))
+ goto done;
+
+ /* ASSERT: it's really the last itd for this urb
+ list_for_each_entry (itd, &stream->td_list, itd_list)
+ BUG_ON (itd->urb == urb);
+ */
+
+ /* give urb back to the driver; completion often (re)submits */
+ dev = urb->dev;
+ fotg210_urb_done(fotg210, urb, 0);
+ retval = true;
+ urb = NULL;
+
+ --fotg210->isoc_count;
+ disable_periodic(fotg210);
+
+ if (unlikely(list_is_singular(&stream->td_list))) {
+ fotg210_to_hcd(fotg210)->self.bandwidth_allocated
+ -= stream->bandwidth;
+ fotg210_vdbg(fotg210,
+ "deschedule devp %s ep%d%s-iso\n",
+ dev->devpath, stream->bEndpointAddress & 0x0f,
+ (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
+ }
+
+done:
+ itd->urb = NULL;
+
+ /* Add to the end of the free list for later reuse */
+ list_move_tail(&itd->itd_list, &stream->free_list);
+
+ /* Recycle the iTDs when the pipeline is empty (ep no longer in use) */
+ if (list_empty(&stream->td_list)) {
+ list_splice_tail_init(&stream->free_list,
+ &fotg210->cached_itd_list);
+ start_free_itds(fotg210);
+ }
+
+ return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,
+ gfp_t mem_flags)
+{
+ int status = -EINVAL;
+ unsigned long flags;
+ struct fotg210_iso_stream *stream;
+
+ /* Get iso_stream head */
+ stream = iso_stream_find(fotg210, urb);
+ if (unlikely(stream == NULL)) {
+ fotg210_dbg(fotg210, "can't get iso stream\n");
+ return -ENOMEM;
+ }
+ if (unlikely(urb->interval != stream->interval &&
+ fotg210_port_speed(fotg210, 0) ==
+ USB_PORT_STAT_HIGH_SPEED)) {
+ fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n",
+ stream->interval, urb->interval);
+ goto done;
+ }
+
+#ifdef FOTG210_URB_TRACE
+ fotg210_dbg(fotg210,
+ "%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n",
+ __func__, urb->dev->devpath, urb,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ urb->transfer_buffer_length,
+ urb->number_of_packets, urb->interval,
+ stream);
+#endif
+
+ /* allocate ITDs w/o locking anything */
+ status = itd_urb_transaction(stream, fotg210, urb, mem_flags);
+ if (unlikely(status < 0)) {
+ fotg210_dbg(fotg210, "can't init itds\n");
+ goto done;
+ }
+
+ /* schedule ... need to lock */
+ spin_lock_irqsave(&fotg210->lock, flags);
+ if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
+ status = -ESHUTDOWN;
+ goto done_not_linked;
+ }
+ status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
+ if (unlikely(status))
+ goto done_not_linked;
+ status = iso_stream_schedule(fotg210, urb, stream);
+ if (likely(status == 0))
+ itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream);
+ else
+ usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+ done_not_linked:
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ done:
+ return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_isoc(struct fotg210_hcd *fotg210)
+{
+ unsigned uf, now_frame, frame;
+ unsigned fmask = fotg210->periodic_size - 1;
+ bool modified, live;
+
+ /*
+ * When running, scan from last scan point up to "now"
+ * else clean up by scanning everything that's left.
+ * Touches as few pages as possible: cache-friendly.
+ */
+ if (fotg210->rh_state >= FOTG210_RH_RUNNING) {
+ uf = fotg210_read_frame_index(fotg210);
+ now_frame = (uf >> 3) & fmask;
+ live = true;
+ } else {
+ now_frame = (fotg210->next_frame - 1) & fmask;
+ live = false;
+ }
+ fotg210->now_frame = now_frame;
+
+ frame = fotg210->next_frame;
+ for (;;) {
+ union fotg210_shadow q, *q_p;
+ __hc32 type, *hw_p;
+
+restart:
+ /* scan each element in frame's queue for completions */
+ q_p = &fotg210->pshadow[frame];
+ hw_p = &fotg210->periodic[frame];
+ q.ptr = q_p->ptr;
+ type = Q_NEXT_TYPE(fotg210, *hw_p);
+ modified = false;
+
+ while (q.ptr != NULL) {
+ switch (hc32_to_cpu(fotg210, type)) {
+ case Q_TYPE_ITD:
+ /* If this ITD is still active, leave it for
+ * later processing ... check the next entry.
+ * No need to check for activity unless the
+ * frame is current.
+ */
+ if (frame == now_frame && live) {
+ rmb();
+ for (uf = 0; uf < 8; uf++) {
+ if (q.itd->hw_transaction[uf] &
+ ITD_ACTIVE(fotg210))
+ break;
+ }
+ if (uf < 8) {
+ q_p = &q.itd->itd_next;
+ hw_p = &q.itd->hw_next;
+ type = Q_NEXT_TYPE(fotg210,
+ q.itd->hw_next);
+ q = *q_p;
+ break;
+ }
+ }
+
+ /* Take finished ITDs out of the schedule
+ * and process them: recycle, maybe report
+ * URB completion. HC won't cache the
+ * pointer for much longer, if at all.
+ */
+ *q_p = q.itd->itd_next;
+ *hw_p = q.itd->hw_next;
+ type = Q_NEXT_TYPE(fotg210, q.itd->hw_next);
+ wmb();
+ modified = itd_complete(fotg210, q.itd);
+ q = *q_p;
+ break;
+ default:
+ fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n",
+ type, frame, q.ptr);
+ /* FALL THROUGH */
+ case Q_TYPE_QH:
+ case Q_TYPE_FSTN:
+ /* End of the iTDs and siTDs */
+ q.ptr = NULL;
+ break;
+ }
+
+ /* assume completion callbacks modify the queue */
+ if (unlikely(modified && fotg210->isoc_count > 0))
+ goto restart;
+ }
+
+ /* Stop when we have reached the current frame */
+ if (frame == now_frame)
+ break;
+ frame = (frame + 1) & fmask;
+ }
+ fotg210->next_frame = now_frame;
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * Display / Set uframe_periodic_max
+ */
+static ssize_t show_uframe_periodic_max(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct fotg210_hcd *fotg210;
+ int n;
+
+ fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
+ n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max);
+ return n;
+}
+
+
+static ssize_t store_uframe_periodic_max(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fotg210_hcd *fotg210;
+ unsigned uframe_periodic_max;
+ unsigned frame, uframe;
+ unsigned short allocated_max;
+ unsigned long flags;
+ ssize_t ret;
+
+ fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
+ if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
+ return -EINVAL;
+
+ if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
+ fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n",
+ uframe_periodic_max);
+ return -EINVAL;
+ }
+
+ ret = -EINVAL;
+
+ /*
+ * lock, so that our checking does not race with possible periodic
+ * bandwidth allocation through submitting new urbs.
+ */
+ spin_lock_irqsave(&fotg210->lock, flags);
+
+ /*
+ * for request to decrease max periodic bandwidth, we have to check
+ * every microframe in the schedule to see whether the decrease is
+ * possible.
+ */
+ if (uframe_periodic_max < fotg210->uframe_periodic_max) {
+ allocated_max = 0;
+
+ for (frame = 0; frame < fotg210->periodic_size; ++frame)
+ for (uframe = 0; uframe < 7; ++uframe)
+ allocated_max = max(allocated_max,
+ periodic_usecs(fotg210, frame, uframe));
+
+ if (allocated_max > uframe_periodic_max) {
+ fotg210_info(fotg210,
+ "cannot decrease uframe_periodic_max becase "
+ "periodic bandwidth is already allocated "
+ "(%u > %u)\n",
+ allocated_max, uframe_periodic_max);
+ goto out_unlock;
+ }
+ }
+
+ /* increasing is always ok */
+
+ fotg210_info(fotg210, "setting max periodic bandwidth to %u%% (== %u usec/uframe)\n",
+ 100 * uframe_periodic_max/125, uframe_periodic_max);
+
+ if (uframe_periodic_max != 100)
+ fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n");
+
+ fotg210->uframe_periodic_max = uframe_periodic_max;
+ ret = count;
+
+out_unlock:
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ return ret;
+}
+
+static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max,
+ store_uframe_periodic_max);
+
+static inline int create_sysfs_files(struct fotg210_hcd *fotg210)
+{
+ struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
+ int i = 0;
+
+ if (i)
+ goto out;
+
+ i = device_create_file(controller, &dev_attr_uframe_periodic_max);
+out:
+ return i;
+}
+
+static inline void remove_sysfs_files(struct fotg210_hcd *fotg210)
+{
+ struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
+
+ device_remove_file(controller, &dev_attr_uframe_periodic_max);
+}
+/*-------------------------------------------------------------------------*/
+
+/* On some systems, leaving remote wakeup enabled prevents system shutdown.
+ * The firmware seems to think that powering off is a wakeup event!
+ * This routine turns off remote wakeup and everything else, on all ports.
+ */
+static void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210)
+{
+ u32 __iomem *status_reg = &fotg210->regs->port_status;
+
+ fotg210_writel(fotg210, PORT_RWC_BITS, status_reg);
+}
+
+/*
+ * Halt HC, turn off all ports, and let the BIOS use the companion controllers.
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static void fotg210_silence_controller(struct fotg210_hcd *fotg210)
+{
+ fotg210_halt(fotg210);
+
+ spin_lock_irq(&fotg210->lock);
+ fotg210->rh_state = FOTG210_RH_HALTED;
+ fotg210_turn_off_all_ports(fotg210);
+ spin_unlock_irq(&fotg210->lock);
+}
+
+/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc).
+ * This forcibly disables dma and IRQs, helping kexec and other cases
+ * where the next system software may expect clean state.
+ */
+static void fotg210_shutdown(struct usb_hcd *hcd)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+
+ spin_lock_irq(&fotg210->lock);
+ fotg210->shutdown = true;
+ fotg210->rh_state = FOTG210_RH_STOPPING;
+ fotg210->enabled_hrtimer_events = 0;
+ spin_unlock_irq(&fotg210->lock);
+
+ fotg210_silence_controller(fotg210);
+
+ hrtimer_cancel(&fotg210->hrtimer);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * fotg210_work is called from some interrupts, timers, and so on.
+ * it calls driver completion functions, after dropping fotg210->lock.
+ */
+static void fotg210_work(struct fotg210_hcd *fotg210)
+{
+ /* another CPU may drop fotg210->lock during a schedule scan while
+ * it reports urb completions. this flag guards against bogus
+ * attempts at re-entrant schedule scanning.
+ */
+ if (fotg210->scanning) {
+ fotg210->need_rescan = true;
+ return;
+ }
+ fotg210->scanning = true;
+
+ rescan:
+ fotg210->need_rescan = false;
+ if (fotg210->async_count)
+ scan_async(fotg210);
+ if (fotg210->intr_count > 0)
+ scan_intr(fotg210);
+ if (fotg210->isoc_count > 0)
+ scan_isoc(fotg210);
+ if (fotg210->need_rescan)
+ goto rescan;
+ fotg210->scanning = false;
+
+ /* the IO watchdog guards against hardware or driver bugs that
+ * misplace IRQs, and should let us run completely without IRQs.
+ * such lossage has been observed on both VT6202 and VT8235.
+ */
+ turn_on_io_watchdog(fotg210);
+}
+
+/*
+ * Called when the fotg210_hcd module is removed.
+ */
+static void fotg210_stop(struct usb_hcd *hcd)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+
+ fotg210_dbg(fotg210, "stop\n");
+
+ /* no more interrupts ... */
+
+ spin_lock_irq(&fotg210->lock);
+ fotg210->enabled_hrtimer_events = 0;
+ spin_unlock_irq(&fotg210->lock);
+
+ fotg210_quiesce(fotg210);
+ fotg210_silence_controller(fotg210);
+ fotg210_reset(fotg210);
+
+ hrtimer_cancel(&fotg210->hrtimer);
+ remove_sysfs_files(fotg210);
+ remove_debug_files(fotg210);
+
+ /* root hub is shut down separately (first, when possible) */
+ spin_lock_irq(&fotg210->lock);
+ end_free_itds(fotg210);
+ spin_unlock_irq(&fotg210->lock);
+ fotg210_mem_cleanup(fotg210);
+
+#ifdef FOTG210_STATS
+ fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
+ fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa,
+ fotg210->stats.lost_iaa);
+ fotg210_dbg(fotg210, "complete %ld unlink %ld\n",
+ fotg210->stats.complete, fotg210->stats.unlink);
+#endif
+
+ dbg_status(fotg210, "fotg210_stop completed",
+ fotg210_readl(fotg210, &fotg210->regs->status));
+}
+
+/* one-time init, only for memory state */
+static int hcd_fotg210_init(struct usb_hcd *hcd)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ u32 temp;
+ int retval;
+ u32 hcc_params;
+ struct fotg210_qh_hw *hw;
+
+ spin_lock_init(&fotg210->lock);
+
+ /*
+ * keep io watchdog by default, those good HCDs could turn off it later
+ */
+ fotg210->need_io_watchdog = 1;
+
+ hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ fotg210->hrtimer.function = fotg210_hrtimer_func;
+ fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
+
+ hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+
+ /*
+ * by default set standard 80% (== 100 usec/uframe) max periodic
+ * bandwidth as required by USB 2.0
+ */
+ fotg210->uframe_periodic_max = 100;
+
+ /*
+ * hw default: 1K periodic list heads, one per frame.
+ * periodic_size can shrink by USBCMD update if hcc_params allows.
+ */
+ fotg210->periodic_size = DEFAULT_I_TDPS;
+ INIT_LIST_HEAD(&fotg210->intr_qh_list);
+ INIT_LIST_HEAD(&fotg210->cached_itd_list);
+
+ if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
+ /* periodic schedule size can be smaller than default */
+ switch (FOTG210_TUNE_FLS) {
+ case 0:
+ fotg210->periodic_size = 1024;
+ break;
+ case 1:
+ fotg210->periodic_size = 512;
+ break;
+ case 2:
+ fotg210->periodic_size = 256;
+ break;
+ default:
+ BUG();
+ }
+ }
+ retval = fotg210_mem_init(fotg210, GFP_KERNEL);
+ if (retval < 0)
+ return retval;
+
+ /* controllers may cache some of the periodic schedule ... */
+ fotg210->i_thresh = 2;
+
+ /*
+ * dedicate a qh for the async ring head, since we couldn't unlink
+ * a 'real' qh without stopping the async schedule [4.8]. use it
+ * as the 'reclamation list head' too.
+ * its dummy is used in hw_alt_next of many tds, to prevent the qh
+ * from automatically advancing to the next td after short reads.
+ */
+ fotg210->async->qh_next.qh = NULL;
+ hw = fotg210->async->hw;
+ hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma);
+ hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD);
+ hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
+ hw->hw_qtd_next = FOTG210_LIST_END(fotg210);
+ fotg210->async->qh_state = QH_STATE_LINKED;
+ hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma);
+
+ /* clear interrupt enables, set irq latency */
+ if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+ log2_irq_thresh = 0;
+ temp = 1 << (16 + log2_irq_thresh);
+ if (HCC_CANPARK(hcc_params)) {
+ /* HW default park == 3, on hardware that supports it (like
+ * NVidia and ALI silicon), maximizes throughput on the async
+ * schedule by avoiding QH fetches between transfers.
+ *
+ * With fast usb storage devices and NForce2, "park" seems to
+ * make problems: throughput reduction (!), data errors...
+ */
+ if (park) {
+ park = min_t(unsigned, park, 3);
+ temp |= CMD_PARK;
+ temp |= park << 8;
+ }
+ fotg210_dbg(fotg210, "park %d\n", park);
+ }
+ if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
+ /* periodic schedule size can be smaller than default */
+ temp &= ~(3 << 2);
+ temp |= (FOTG210_TUNE_FLS << 2);
+ }
+ fotg210->command = temp;
+
+ /* Accept arbitrarily long scatter-gather lists */
+ if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+ hcd->self.sg_tablesize = ~0;
+ return 0;
+}
+
+/* start HC running; it's halted, hcd_fotg210_init() has been run (once) */
+static int fotg210_run(struct usb_hcd *hcd)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ u32 temp;
+ u32 hcc_params;
+
+ hcd->uses_new_polling = 1;
+
+ /* EHCI spec section 4.1 */
+
+ fotg210_writel(fotg210, fotg210->periodic_dma,
+ &fotg210->regs->frame_list);
+ fotg210_writel(fotg210, (u32)fotg210->async->qh_dma,
+ &fotg210->regs->async_next);
+
+ /*
+ * hcc_params controls whether fotg210->regs->segment must (!!!)
+ * be used; it constrains QH/ITD/SITD and QTD locations.
+ * pci_pool consistent memory always uses segment zero.
+ * streaming mappings for I/O buffers, like pci_map_single(),
+ * can return segments above 4GB, if the device allows.
+ *
+ * NOTE: the dma mask is visible through dma_supported(), so
+ * drivers can pass this info along ... like NETIF_F_HIGHDMA,
+ * Scsi_Host.highmem_io, and so forth. It's readonly to all
+ * host side drivers though.
+ */
+ hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+
+ /*
+ * Philips, Intel, and maybe others need CMD_RUN before the
+ * root hub will detect new devices (why?); NEC doesn't
+ */
+ fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
+ fotg210->command |= CMD_RUN;
+ fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+ dbg_cmd(fotg210, "init", fotg210->command);
+
+ /*
+ * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+ * are explicitly handed to companion controller(s), so no TT is
+ * involved with the root hub. (Except where one is integrated,
+ * and there's no companion controller unless maybe for USB OTG.)
+ *
+ * Turning on the CF flag will transfer ownership of all ports
+ * from the companions to the EHCI controller. If any of the
+ * companions are in the middle of a port reset at the time, it
+ * could cause trouble. Write-locking ehci_cf_port_reset_rwsem
+ * guarantees that no resets are in progress. After we set CF,
+ * a short delay lets the hardware catch up; new resets shouldn't
+ * be started before the port switching actions could complete.
+ */
+ down_write(&ehci_cf_port_reset_rwsem);
+ fotg210->rh_state = FOTG210_RH_RUNNING;
+ /* unblock posted writes */
+ fotg210_readl(fotg210, &fotg210->regs->command);
+ msleep(5);
+ up_write(&ehci_cf_port_reset_rwsem);
+ fotg210->last_periodic_enable = ktime_get_real();
+
+ temp = HC_VERSION(fotg210,
+ fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
+ fotg210_info(fotg210,
+ "USB %x.%x started, EHCI %x.%02x\n",
+ ((fotg210->sbrn & 0xf0)>>4), (fotg210->sbrn & 0x0f),
+ temp >> 8, temp & 0xff);
+
+ fotg210_writel(fotg210, INTR_MASK,
+ &fotg210->regs->intr_enable); /* Turn On Interrupts */
+
+ /* GRR this is run-once init(), being done every time the HC starts.
+ * So long as they're part of class devices, we can't do it init()
+ * since the class device isn't created that early.
+ */
+ create_debug_files(fotg210);
+ create_sysfs_files(fotg210);
+
+ return 0;
+}
+
+static int fotg210_setup(struct usb_hcd *hcd)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ int retval;
+
+ fotg210->regs = (void __iomem *)fotg210->caps +
+ HC_LENGTH(fotg210,
+ fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
+ dbg_hcs_params(fotg210, "reset");
+ dbg_hcc_params(fotg210, "reset");
+
+ /* cache this readonly data; minimize chip reads */
+ fotg210->hcs_params = fotg210_readl(fotg210,
+ &fotg210->caps->hcs_params);
+
+ fotg210->sbrn = HCD_USB2;
+
+ /* data structure init */
+ retval = hcd_fotg210_init(hcd);
+ if (retval)
+ return retval;
+
+ retval = fotg210_halt(fotg210);
+ if (retval)
+ return retval;
+
+ fotg210_reset(fotg210);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static irqreturn_t fotg210_irq(struct usb_hcd *hcd)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ u32 status, masked_status, pcd_status = 0, cmd;
+ int bh;
+
+ spin_lock(&fotg210->lock);
+
+ status = fotg210_readl(fotg210, &fotg210->regs->status);
+
+ /* e.g. cardbus physical eject */
+ if (status == ~(u32) 0) {
+ fotg210_dbg(fotg210, "device removed\n");
+ goto dead;
+ }
+
+ /*
+ * We don't use STS_FLR, but some controllers don't like it to
+ * remain on, so mask it out along with the other status bits.
+ */
+ masked_status = status & (INTR_MASK | STS_FLR);
+
+ /* Shared IRQ? */
+ if (!masked_status ||
+ unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) {
+ spin_unlock(&fotg210->lock);
+ return IRQ_NONE;
+ }
+
+ /* clear (just) interrupts */
+ fotg210_writel(fotg210, masked_status, &fotg210->regs->status);
+ cmd = fotg210_readl(fotg210, &fotg210->regs->command);
+ bh = 0;
+
+#ifdef VERBOSE_DEBUG
+ /* unrequested/ignored: Frame List Rollover */
+ dbg_status(fotg210, "irq", status);
+#endif
+
+ /* INT, ERR, and IAA interrupt rates can be throttled */
+
+ /* normal [4.15.1.2] or error [4.15.1.1] completion */
+ if (likely((status & (STS_INT|STS_ERR)) != 0)) {
+ if (likely((status & STS_ERR) == 0))
+ COUNT(fotg210->stats.normal);
+ else
+ COUNT(fotg210->stats.error);
+ bh = 1;
+ }
+
+ /* complete the unlinking of some qh [4.15.2.3] */
+ if (status & STS_IAA) {
+
+ /* Turn off the IAA watchdog */
+ fotg210->enabled_hrtimer_events &=
+ ~BIT(FOTG210_HRTIMER_IAA_WATCHDOG);
+
+ /*
+ * Mild optimization: Allow another IAAD to reset the
+ * hrtimer, if one occurs before the next expiration.
+ * In theory we could always cancel the hrtimer, but
+ * tests show that about half the time it will be reset
+ * for some other event anyway.
+ */
+ if (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG)
+ ++fotg210->next_hrtimer_event;
+
+ /* guard against (alleged) silicon errata */
+ if (cmd & CMD_IAAD)
+ fotg210_dbg(fotg210, "IAA with IAAD still set?\n");
+ if (fotg210->async_iaa) {
+ COUNT(fotg210->stats.iaa);
+ end_unlink_async(fotg210);
+ } else
+ fotg210_dbg(fotg210, "IAA with nothing unlinked?\n");
+ }
+
+ /* remote wakeup [4.3.1] */
+ if (status & STS_PCD) {
+ int pstatus;
+ u32 __iomem *status_reg = &fotg210->regs->port_status;
+
+ /* kick root hub later */
+ pcd_status = status;
+
+ /* resume root hub? */
+ if (fotg210->rh_state == FOTG210_RH_SUSPENDED)
+ usb_hcd_resume_root_hub(hcd);
+
+ pstatus = fotg210_readl(fotg210, status_reg);
+
+ if (test_bit(0, &fotg210->suspended_ports) &&
+ ((pstatus & PORT_RESUME) ||
+ !(pstatus & PORT_SUSPEND)) &&
+ (pstatus & PORT_PE) &&
+ fotg210->reset_done[0] == 0) {
+
+ /* start 20 msec resume signaling from this port,
+ * and make khubd collect PORT_STAT_C_SUSPEND to
+ * stop that signaling. Use 5 ms extra for safety,
+ * like usb_port_resume() does.
+ */
+ fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25);
+ set_bit(0, &fotg210->resuming_ports);
+ fotg210_dbg(fotg210, "port 1 remote wakeup\n");
+ mod_timer(&hcd->rh_timer, fotg210->reset_done[0]);
+ }
+ }
+
+ /* PCI errors [4.15.2.4] */
+ if (unlikely((status & STS_FATAL) != 0)) {
+ fotg210_err(fotg210, "fatal error\n");
+ dbg_cmd(fotg210, "fatal", cmd);
+ dbg_status(fotg210, "fatal", status);
+dead:
+ usb_hc_died(hcd);
+
+ /* Don't let the controller do anything more */
+ fotg210->shutdown = true;
+ fotg210->rh_state = FOTG210_RH_STOPPING;
+ fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE);
+ fotg210_writel(fotg210, fotg210->command,
+ &fotg210->regs->command);
+ fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
+ fotg210_handle_controller_death(fotg210);
+
+ /* Handle completions when the controller stops */
+ bh = 0;
+ }
+
+ if (bh)
+ fotg210_work(fotg210);
+ spin_unlock(&fotg210->lock);
+ if (pcd_status)
+ usb_hcd_poll_rh_status(hcd);
+ return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ *
+ * urb + dev is in hcd.self.controller.urb_list
+ * we're queueing TDs onto software and hardware lists
+ *
+ * hcd-specific init for hcpriv hasn't been done yet
+ *
+ * NOTE: control, bulk, and interrupt share the same code to append TDs
+ * to a (possibly active) QH, and the same QH scanning code.
+ */
+static int fotg210_urb_enqueue(
+ struct usb_hcd *hcd,
+ struct urb *urb,
+ gfp_t mem_flags
+) {
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ struct list_head qtd_list;
+
+ INIT_LIST_HEAD(&qtd_list);
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ /* qh_completions() code doesn't handle all the fault cases
+ * in multi-TD control transfers. Even 1KB is rare anyway.
+ */
+ if (urb->transfer_buffer_length > (16 * 1024))
+ return -EMSGSIZE;
+ /* FALLTHROUGH */
+ /* case PIPE_BULK: */
+ default:
+ if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
+ return -ENOMEM;
+ return submit_async(fotg210, urb, &qtd_list, mem_flags);
+
+ case PIPE_INTERRUPT:
+ if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
+ return -ENOMEM;
+ return intr_submit(fotg210, urb, &qtd_list, mem_flags);
+
+ case PIPE_ISOCHRONOUS:
+ return itd_submit(fotg210, urb, mem_flags);
+ }
+}
+
+/* remove from hardware lists
+ * completions normally happen asynchronously
+ */
+
+static int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ struct fotg210_qh *qh;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&fotg210->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
+ switch (usb_pipetype(urb->pipe)) {
+ /* case PIPE_CONTROL: */
+ /* case PIPE_BULK:*/
+ default:
+ qh = (struct fotg210_qh *) urb->hcpriv;
+ if (!qh)
+ break;
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
+ case QH_STATE_COMPLETING:
+ start_unlink_async(fotg210, qh);
+ break;
+ case QH_STATE_UNLINK:
+ case QH_STATE_UNLINK_WAIT:
+ /* already started */
+ break;
+ case QH_STATE_IDLE:
+ /* QH might be waiting for a Clear-TT-Buffer */
+ qh_completions(fotg210, qh);
+ break;
+ }
+ break;
+
+ case PIPE_INTERRUPT:
+ qh = (struct fotg210_qh *) urb->hcpriv;
+ if (!qh)
+ break;
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
+ case QH_STATE_COMPLETING:
+ start_unlink_intr(fotg210, qh);
+ break;
+ case QH_STATE_IDLE:
+ qh_completions(fotg210, qh);
+ break;
+ default:
+ fotg210_dbg(fotg210, "bogus qh %p state %d\n",
+ qh, qh->qh_state);
+ goto done;
+ }
+ break;
+
+ case PIPE_ISOCHRONOUS:
+ /* itd... */
+
+ /* wait till next completion, do it then. */
+ /* completion irqs can wait up to 1024 msec, */
+ break;
+ }
+done:
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* bulk qh holds the data toggle */
+
+static void
+fotg210_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ unsigned long flags;
+ struct fotg210_qh *qh, *tmp;
+
+ /* ASSERT: any requests/urbs are being unlinked */
+ /* ASSERT: nobody can be submitting urbs for this any more */
+
+rescan:
+ spin_lock_irqsave(&fotg210->lock, flags);
+ qh = ep->hcpriv;
+ if (!qh)
+ goto done;
+
+ /* endpoints can be iso streams. for now, we don't
+ * accelerate iso completions ... so spin a while.
+ */
+ if (qh->hw == NULL) {
+ struct fotg210_iso_stream *stream = ep->hcpriv;
+
+ if (!list_empty(&stream->td_list))
+ goto idle_timeout;
+
+ /* BUG_ON(!list_empty(&stream->free_list)); */
+ kfree(stream);
+ goto done;
+ }
+
+ if (fotg210->rh_state < FOTG210_RH_RUNNING)
+ qh->qh_state = QH_STATE_IDLE;
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
+ case QH_STATE_COMPLETING:
+ for (tmp = fotg210->async->qh_next.qh;
+ tmp && tmp != qh;
+ tmp = tmp->qh_next.qh)
+ continue;
+ /* periodic qh self-unlinks on empty, and a COMPLETING qh
+ * may already be unlinked.
+ */
+ if (tmp)
+ start_unlink_async(fotg210, qh);
+ /* FALL THROUGH */
+ case QH_STATE_UNLINK: /* wait for hw to finish? */
+ case QH_STATE_UNLINK_WAIT:
+idle_timeout:
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+ schedule_timeout_uninterruptible(1);
+ goto rescan;
+ case QH_STATE_IDLE: /* fully unlinked */
+ if (qh->clearing_tt)
+ goto idle_timeout;
+ if (list_empty(&qh->qtd_list)) {
+ qh_destroy(fotg210, qh);
+ break;
+ }
+ /* else FALL THROUGH */
+ default:
+ /* caller was supposed to have unlinked any requests;
+ * that's not our job. just leak this memory.
+ */
+ fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n",
+ qh, ep->desc.bEndpointAddress, qh->qh_state,
+ list_empty(&qh->qtd_list) ? "" : "(has tds)");
+ break;
+ }
+ done:
+ ep->hcpriv = NULL;
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+}
+
+static void
+fotg210_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ struct fotg210_qh *qh;
+ int eptype = usb_endpoint_type(&ep->desc);
+ int epnum = usb_endpoint_num(&ep->desc);
+ int is_out = usb_endpoint_dir_out(&ep->desc);
+ unsigned long flags;
+
+ if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
+ return;
+
+ spin_lock_irqsave(&fotg210->lock, flags);
+ qh = ep->hcpriv;
+
+ /* For Bulk and Interrupt endpoints we maintain the toggle state
+ * in the hardware; the toggle bits in udev aren't used at all.
+ * When an endpoint is reset by usb_clear_halt() we must reset
+ * the toggle bit in the QH.
+ */
+ if (qh) {
+ usb_settoggle(qh->dev, epnum, is_out, 0);
+ if (!list_empty(&qh->qtd_list)) {
+ WARN_ONCE(1, "clear_halt for a busy endpoint\n");
+ } else if (qh->qh_state == QH_STATE_LINKED ||
+ qh->qh_state == QH_STATE_COMPLETING) {
+
+ /* The toggle value in the QH can't be updated
+ * while the QH is active. Unlink it now;
+ * re-linking will call qh_refresh().
+ */
+ if (eptype == USB_ENDPOINT_XFER_BULK)
+ start_unlink_async(fotg210, qh);
+ else
+ start_unlink_intr(fotg210, qh);
+ }
+ }
+ spin_unlock_irqrestore(&fotg210->lock, flags);
+}
+
+static int fotg210_get_frame(struct usb_hcd *hcd)
+{
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+ return (fotg210_read_frame_index(fotg210) >> 3) %
+ fotg210->periodic_size;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * The EHCI in ChipIdea HDRC cannot be a separate module or device,
+ * because its registers (and irq) are shared between host/gadget/otg
+ * functions and in order to facilitate role switching we cannot
+ * give the fotg210 driver exclusive access to those.
+ */
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+
+static const struct hc_driver fotg210_fotg210_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Faraday USB2.0 Host Controller",
+ .hcd_priv_size = sizeof(struct fotg210_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = fotg210_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = hcd_fotg210_init,
+ .start = fotg210_run,
+ .stop = fotg210_stop,
+ .shutdown = fotg210_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = fotg210_urb_enqueue,
+ .urb_dequeue = fotg210_urb_dequeue,
+ .endpoint_disable = fotg210_endpoint_disable,
+ .endpoint_reset = fotg210_endpoint_reset,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = fotg210_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = fotg210_hub_status_data,
+ .hub_control = fotg210_hub_control,
+ .bus_suspend = fotg210_bus_suspend,
+ .bus_resume = fotg210_bus_resume,
+
+ .relinquish_port = fotg210_relinquish_port,
+ .port_handed_over = fotg210_port_handed_over,
+
+ .clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete,
+};
+
+static void fotg210_init(struct fotg210_hcd *fotg210)
+{
+ u32 value;
+
+ iowrite32(GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY,
+ &fotg210->regs->gmir);
+
+ value = ioread32(&fotg210->regs->otgcsr);
+ value &= ~OTGCSR_A_BUS_DROP;
+ value |= OTGCSR_A_BUS_REQ;
+ iowrite32(value, &fotg210->regs->otgcsr);
+}
+
+/**
+ * fotg210_hcd_probe - initialize faraday FOTG210 HCDs
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+static int fotg210_hcd_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct usb_hcd *hcd;
+ struct resource *res;
+ int irq;
+ int retval = -ENODEV;
+ struct fotg210_hcd *fotg210;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ pdev->dev.power.power_state = PMSG_ON;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev,
+ "Found HC with no IRQ. Check %s setup!\n",
+ dev_name(dev));
+ return -ENODEV;
+ }
+
+ irq = res->start;
+
+ hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev,
+ dev_name(dev));
+ if (!hcd) {
+ dev_err(dev, "failed to create hcd with err %d\n", retval);
+ retval = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev,
+ "Found HC with no register addr. Check %s setup!\n",
+ dev_name(dev));
+ retval = -ENODEV;
+ goto fail_request_resource;
+ }
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+ hcd->has_tt = 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ fotg210_fotg210_hc_driver.description)) {
+ dev_dbg(dev, "controller already in use\n");
+ retval = -EBUSY;
+ goto fail_request_resource;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(dev,
+ "Found HC with no register addr. Check %s setup!\n",
+ dev_name(dev));
+ retval = -ENODEV;
+ goto fail_request_resource;
+ }
+
+ hcd->regs = ioremap_nocache(res->start, resource_size(res));
+ if (hcd->regs == NULL) {
+ dev_dbg(dev, "error mapping memory\n");
+ retval = -EFAULT;
+ goto fail_ioremap;
+ }
+
+ fotg210 = hcd_to_fotg210(hcd);
+
+ fotg210->caps = hcd->regs;
+
+ retval = fotg210_setup(hcd);
+ if (retval)
+ goto fail_add_hcd;
+
+ fotg210_init(fotg210);
+
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (retval) {
+ dev_err(dev, "failed to add hcd with err %d\n", retval);
+ goto fail_add_hcd;
+ }
+
+ return retval;
+
+fail_add_hcd:
+ iounmap(hcd->regs);
+fail_ioremap:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+fail_request_resource:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
+ return retval;
+}
+
+/**
+ * fotg210_hcd_remove - shutdown processing for EHCI HCDs
+ * @dev: USB Host Controller being removed
+ *
+ */
+static int fotg210_hcd_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ if (!hcd)
+ return 0;
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+static struct platform_driver fotg210_hcd_driver = {
+ .driver = {
+ .name = "fotg210-hcd",
+ },
+ .probe = fotg210_hcd_probe,
+ .remove = fotg210_hcd_remove,
+};
+
+static int __init fotg210_hcd_init(void)
+{
+ int retval = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+ set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+ if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
+ test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
+ pr_warn(KERN_WARNING "Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n");
+
+ pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd\n",
+ hcd_name,
+ sizeof(struct fotg210_qh), sizeof(struct fotg210_qtd),
+ sizeof(struct fotg210_itd));
+
+#ifdef DEBUG
+ fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
+ if (!fotg210_debug_root) {
+ retval = -ENOENT;
+ goto err_debug;
+ }
+#endif
+
+ retval = platform_driver_register(&fotg210_hcd_driver);
+ if (retval < 0)
+ goto clean;
+ return retval;
+
+ platform_driver_unregister(&fotg210_hcd_driver);
+clean:
+#ifdef DEBUG
+ debugfs_remove(fotg210_debug_root);
+ fotg210_debug_root = NULL;
+err_debug:
+#endif
+ clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+ return retval;
+}
+module_init(fotg210_hcd_init);
+
+static void __exit fotg210_hcd_cleanup(void)
+{
+ platform_driver_unregister(&fotg210_hcd_driver);
+#ifdef DEBUG
+ debugfs_remove(fotg210_debug_root);
+#endif
+ clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+}
+module_exit(fotg210_hcd_cleanup);
diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h
new file mode 100644
index 00000000000..8920f9d3256
--- /dev/null
+++ b/drivers/usb/host/fotg210.h
@@ -0,0 +1,750 @@
+#ifndef __LINUX_FOTG210_H
+#define __LINUX_FOTG210_H
+
+/* definitions used for the EHCI driver */
+
+/*
+ * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
+ * __leXX (normally) or __beXX (given FOTG210_BIG_ENDIAN_DESC), depending on
+ * the host controller implementation.
+ *
+ * To facilitate the strongest possible byte-order checking from "sparse"
+ * and so on, we use __leXX unless that's not practical.
+ */
+#define __hc32 __le32
+#define __hc16 __le16
+
+/* statistics can be kept for tuning/monitoring */
+struct fotg210_stats {
+ /* irq usage */
+ unsigned long normal;
+ unsigned long error;
+ unsigned long iaa;
+ unsigned long lost_iaa;
+
+ /* termination of urbs from core */
+ unsigned long complete;
+ unsigned long unlink;
+};
+
+/* fotg210_hcd->lock guards shared data against other CPUs:
+ * fotg210_hcd: async, unlink, periodic (and shadow), ...
+ * usb_host_endpoint: hcpriv
+ * fotg210_qh: qh_next, qtd_list
+ * fotg210_qtd: qtd_list
+ *
+ * Also, hold this lock when talking to HC registers or
+ * when updating hw_* fields in shared qh/qtd/... structures.
+ */
+
+#define FOTG210_MAX_ROOT_PORTS 1 /* see HCS_N_PORTS */
+
+/*
+ * fotg210_rh_state values of FOTG210_RH_RUNNING or above mean that the
+ * controller may be doing DMA. Lower values mean there's no DMA.
+ */
+enum fotg210_rh_state {
+ FOTG210_RH_HALTED,
+ FOTG210_RH_SUSPENDED,
+ FOTG210_RH_RUNNING,
+ FOTG210_RH_STOPPING
+};
+
+/*
+ * Timer events, ordered by increasing delay length.
+ * Always update event_delays_ns[] and event_handlers[] (defined in
+ * ehci-timer.c) in parallel with this list.
+ */
+enum fotg210_hrtimer_event {
+ FOTG210_HRTIMER_POLL_ASS, /* Poll for async schedule off */
+ FOTG210_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
+ FOTG210_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
+ FOTG210_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
+ FOTG210_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
+ FOTG210_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
+ FOTG210_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
+ FOTG210_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
+ FOTG210_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
+ FOTG210_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
+ FOTG210_HRTIMER_NUM_EVENTS /* Must come last */
+};
+#define FOTG210_HRTIMER_NO_EVENT 99
+
+struct fotg210_hcd { /* one per controller */
+ /* timing support */
+ enum fotg210_hrtimer_event next_hrtimer_event;
+ unsigned enabled_hrtimer_events;
+ ktime_t hr_timeouts[FOTG210_HRTIMER_NUM_EVENTS];
+ struct hrtimer hrtimer;
+
+ int PSS_poll_count;
+ int ASS_poll_count;
+ int died_poll_count;
+
+ /* glue to PCI and HCD framework */
+ struct fotg210_caps __iomem *caps;
+ struct fotg210_regs __iomem *regs;
+ struct fotg210_dbg_port __iomem *debug;
+
+ __u32 hcs_params; /* cached register copy */
+ spinlock_t lock;
+ enum fotg210_rh_state rh_state;
+
+ /* general schedule support */
+ bool scanning:1;
+ bool need_rescan:1;
+ bool intr_unlinking:1;
+ bool async_unlinking:1;
+ bool shutdown:1;
+ struct fotg210_qh *qh_scan_next;
+
+ /* async schedule support */
+ struct fotg210_qh *async;
+ struct fotg210_qh *dummy; /* For AMD quirk use */
+ struct fotg210_qh *async_unlink;
+ struct fotg210_qh *async_unlink_last;
+ struct fotg210_qh *async_iaa;
+ unsigned async_unlink_cycle;
+ unsigned async_count; /* async activity count */
+
+ /* periodic schedule support */
+#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
+ unsigned periodic_size;
+ __hc32 *periodic; /* hw periodic table */
+ dma_addr_t periodic_dma;
+ struct list_head intr_qh_list;
+ unsigned i_thresh; /* uframes HC might cache */
+
+ union fotg210_shadow *pshadow; /* mirror hw periodic table */
+ struct fotg210_qh *intr_unlink;
+ struct fotg210_qh *intr_unlink_last;
+ unsigned intr_unlink_cycle;
+ unsigned now_frame; /* frame from HC hardware */
+ unsigned next_frame; /* scan periodic, start here */
+ unsigned intr_count; /* intr activity count */
+ unsigned isoc_count; /* isoc activity count */
+ unsigned periodic_count; /* periodic activity count */
+ /* max periodic time per uframe */
+ unsigned uframe_periodic_max;
+
+
+ /* list of itds completed while now_frame was still active */
+ struct list_head cached_itd_list;
+ struct fotg210_itd *last_itd_to_free;
+
+ /* per root hub port */
+ unsigned long reset_done[FOTG210_MAX_ROOT_PORTS];
+
+ /* bit vectors (one bit per port) */
+ unsigned long bus_suspended; /* which ports were
+ already suspended at the start of a bus suspend */
+ unsigned long companion_ports; /* which ports are
+ dedicated to the companion controller */
+ unsigned long owned_ports; /* which ports are
+ owned by the companion during a bus suspend */
+ unsigned long port_c_suspend; /* which ports have
+ the change-suspend feature turned on */
+ unsigned long suspended_ports; /* which ports are
+ suspended */
+ unsigned long resuming_ports; /* which ports have
+ started to resume */
+
+ /* per-HC memory pools (could be per-bus, but ...) */
+ struct dma_pool *qh_pool; /* qh per active urb */
+ struct dma_pool *qtd_pool; /* one or more per qh */
+ struct dma_pool *itd_pool; /* itd per iso urb */
+
+ unsigned random_frame;
+ unsigned long next_statechange;
+ ktime_t last_periodic_enable;
+ u32 command;
+
+ /* SILICON QUIRKS */
+ unsigned need_io_watchdog:1;
+ unsigned fs_i_thresh:1; /* Intel iso scheduling */
+
+ u8 sbrn; /* packed release number */
+
+ /* irq statistics */
+#ifdef FOTG210_STATS
+ struct fotg210_stats stats;
+# define COUNT(x) ((x)++)
+#else
+# define COUNT(x)
+#endif
+
+ /* debug files */
+#ifdef DEBUG
+ struct dentry *debug_dir;
+#endif
+};
+
+/* convert between an HCD pointer and the corresponding FOTG210_HCD */
+static inline struct fotg210_hcd *hcd_to_fotg210(struct usb_hcd *hcd)
+{
+ return (struct fotg210_hcd *)(hcd->hcd_priv);
+}
+static inline struct usb_hcd *fotg210_to_hcd(struct fotg210_hcd *fotg210)
+{
+ return container_of((void *) fotg210, struct usb_hcd, hcd_priv);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct fotg210_caps {
+ /* these fields are specified as 8 and 16 bit registers,
+ * but some hosts can't perform 8 or 16 bit PCI accesses.
+ * some hosts treat caplength and hciversion as parts of a 32-bit
+ * register, others treat them as two separate registers, this
+ * affects the memory map for big endian controllers.
+ */
+ u32 hc_capbase;
+#define HC_LENGTH(fotg210, p) (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \
+ (fotg210_big_endian_capbase(fotg210) ? 24 : 0)))
+#define HC_VERSION(fotg210, p) (0xffff&((p) >> /* bits 31:16 / offset 02h */ \
+ (fotg210_big_endian_capbase(fotg210) ? 0 : 16)))
+ u32 hcs_params; /* HCSPARAMS - offset 0x4 */
+#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
+
+ u32 hcc_params; /* HCCPARAMS - offset 0x8 */
+#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
+ u8 portroute[8]; /* nibbles for routing - offset 0xC */
+};
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct fotg210_regs {
+
+ /* USBCMD: offset 0x00 */
+ u32 command;
+
+/* EHCI 1.1 addendum */
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK (1<<11) /* enable "park" on async qh */
+#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
+#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
+#define CMD_ASE (1<<5) /* async schedule enable */
+#define CMD_PSE (1<<4) /* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET (1<<1) /* reset HC not bus */
+#define CMD_RUN (1<<0) /* start/stop HC */
+
+ /* USBSTS: offset 0x04 */
+ u32 status;
+#define STS_ASS (1<<15) /* Async Schedule Status */
+#define STS_PSS (1<<14) /* Periodic Schedule Status */
+#define STS_RECL (1<<13) /* Reclamation */
+#define STS_HALT (1<<12) /* Not running (any reason) */
+/* some bits reserved */
+ /* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA (1<<5) /* Interrupted on async advance */
+#define STS_FATAL (1<<4) /* such as some PCI access errors */
+#define STS_FLR (1<<3) /* frame list rolled over */
+#define STS_PCD (1<<2) /* port change detect */
+#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
+#define STS_INT (1<<0) /* "normal" completion (short, ...) */
+
+ /* USBINTR: offset 0x08 */
+ u32 intr_enable;
+
+ /* FRINDEX: offset 0x0C */
+ u32 frame_index; /* current microframe number */
+ /* CTRLDSSEGMENT: offset 0x10 */
+ u32 segment; /* address bits 63:32 if needed */
+ /* PERIODICLISTBASE: offset 0x14 */
+ u32 frame_list; /* points to periodic list */
+ /* ASYNCLISTADDR: offset 0x18 */
+ u32 async_next; /* address of next async queue head */
+
+ u32 reserved1;
+ /* PORTSC: offset 0x20 */
+ u32 port_status;
+/* 31:23 reserved */
+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
+#define PORT_RESET (1<<8) /* reset port */
+#define PORT_SUSPEND (1<<7) /* suspend port */
+#define PORT_RESUME (1<<6) /* resume it */
+#define PORT_PEC (1<<3) /* port enable change */
+#define PORT_PE (1<<2) /* port enable */
+#define PORT_CSC (1<<1) /* connect status change */
+#define PORT_CONNECT (1<<0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC | PORT_PEC)
+ u32 reserved2[19];
+
+ /* OTGCSR: offet 0x70 */
+ u32 otgcsr;
+#define OTGCSR_HOST_SPD_TYP (3 << 22)
+#define OTGCSR_A_BUS_DROP (1 << 5)
+#define OTGCSR_A_BUS_REQ (1 << 4)
+
+ /* OTGISR: offset 0x74 */
+ u32 otgisr;
+#define OTGISR_OVC (1 << 10)
+
+ u32 reserved3[15];
+
+ /* GMIR: offset 0xB4 */
+ u32 gmir;
+#define GMIR_INT_POLARITY (1 << 3) /*Active High*/
+#define GMIR_MHC_INT (1 << 2)
+#define GMIR_MOTG_INT (1 << 1)
+#define GMIR_MDEV_INT (1 << 0)
+};
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console. (nonstandard enumeration.)
+ */
+struct fotg210_dbg_port {
+ u32 control;
+#define DBGP_OWNER (1<<30)
+#define DBGP_ENABLED (1<<28)
+#define DBGP_DONE (1<<16)
+#define DBGP_INUSE (1<<10)
+#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
+# define DBGP_ERR_BAD 1
+# define DBGP_ERR_SIGNAL 2
+#define DBGP_ERROR (1<<6)
+#define DBGP_GO (1<<5)
+#define DBGP_OUT (1<<4)
+#define DBGP_LEN(x) (((x)>>0)&0x0f)
+ u32 pids;
+#define DBGP_PID_GET(x) (((x)>>16)&0xff)
+#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
+ u32 data03;
+ u32 data47;
+ u32 address;
+#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
+};
+
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+#include <linux/init.h>
+extern int __init early_dbgp_init(char *s);
+extern struct console early_dbgp_console;
+#endif /* CONFIG_EARLY_PRINTK_DBGP */
+
+struct usb_hcd;
+
+static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd)
+{
+ return 1; /* Shouldn't this be 0? */
+}
+
+static inline int xen_dbgp_external_startup(struct usb_hcd *hcd)
+{
+ return -1;
+}
+
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+/* Call backs from fotg210 host driver to fotg210 debug driver */
+extern int dbgp_external_startup(struct usb_hcd *);
+extern int dbgp_reset_prep(struct usb_hcd *hcd);
+#else
+static inline int dbgp_reset_prep(struct usb_hcd *hcd)
+{
+ return xen_dbgp_reset_prep(hcd);
+}
+static inline int dbgp_external_startup(struct usb_hcd *hcd)
+{
+ return xen_dbgp_external_startup(hcd);
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define QTD_NEXT(fotg210, dma) cpu_to_hc32(fotg210, (u32)dma)
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...)
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct fotg210_qtd {
+ /* first part defined by EHCI spec */
+ __hc32 hw_next; /* see EHCI 3.5.1 */
+ __hc32 hw_alt_next; /* see EHCI 3.5.2 */
+ __hc32 hw_token; /* see EHCI 3.5.3 */
+#define QTD_TOGGLE (1 << 31) /* data toggle */
+#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
+#define QTD_IOC (1 << 15) /* interrupt on complete */
+#define QTD_CERR(tok) (((tok)>>10) & 0x3)
+#define QTD_PID(tok) (((tok)>>8) & 0x3)
+#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
+#define QTD_STS_HALT (1 << 6) /* halted on error */
+#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
+#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
+#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
+#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
+#define QTD_STS_STS (1 << 1) /* split transaction state */
+#define QTD_STS_PING (1 << 0) /* issue PING? */
+
+#define ACTIVE_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_ACTIVE)
+#define HALT_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_HALT)
+#define STATUS_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_STS)
+
+ __hc32 hw_buf[5]; /* see EHCI 3.5.4 */
+ __hc32 hw_buf_hi[5]; /* Appendix B */
+
+ /* the rest is HCD-private */
+ dma_addr_t qtd_dma; /* qtd address */
+ struct list_head qtd_list; /* sw qtd list */
+ struct urb *urb; /* qtd's urb */
+ size_t length; /* length of buffer */
+} __aligned(32);
+
+/* mask NakCnt+T in qh->hw_alt_next */
+#define QTD_MASK(fotg210) cpu_to_hc32(fotg210, ~0x1f)
+
+#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
+
+/*-------------------------------------------------------------------------*/
+
+/* type tag from {qh,itd,fstn}->hw_next */
+#define Q_NEXT_TYPE(fotg210, dma) ((dma) & cpu_to_hc32(fotg210, 3 << 1))
+
+/*
+ * Now the following defines are not converted using the
+ * cpu_to_le32() macro anymore, since we have to support
+ * "dynamic" switching between be and le support, so that the driver
+ * can be used on one system with SoC EHCI controller using big-endian
+ * descriptors as well as a normal little-endian PCI EHCI controller.
+ */
+/* values for that type tag */
+#define Q_TYPE_ITD (0 << 1)
+#define Q_TYPE_QH (1 << 1)
+#define Q_TYPE_SITD (2 << 1)
+#define Q_TYPE_FSTN (3 << 1)
+
+/* next async queue entry, or pointer to interrupt/periodic QH */
+#define QH_NEXT(fotg210, dma) \
+ (cpu_to_hc32(fotg210, (((u32)dma)&~0x01f)|Q_TYPE_QH))
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define FOTG210_LIST_END(fotg210) \
+ cpu_to_hc32(fotg210, 1) /* "null pointer" to hw */
+
+/*
+ * Entries in periodic shadow table are pointers to one of four kinds
+ * of data structure. That's dictated by the hardware; a type tag is
+ * encoded in the low bits of the hardware's periodic schedule. Use
+ * Q_NEXT_TYPE to get the tag.
+ *
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+union fotg210_shadow {
+ struct fotg210_qh *qh; /* Q_TYPE_QH */
+ struct fotg210_itd *itd; /* Q_TYPE_ITD */
+ struct fotg210_fstn *fstn; /* Q_TYPE_FSTN */
+ __hc32 *hw_next; /* (all types) */
+ void *ptr;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+/* first part defined by EHCI spec */
+struct fotg210_qh_hw {
+ __hc32 hw_next; /* see EHCI 3.6.1 */
+ __hc32 hw_info1; /* see EHCI 3.6.2 */
+#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */
+#define QH_HEAD (1 << 15) /* Head of async reclamation list */
+#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */
+#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */
+#define QH_LOW_SPEED (1 << 12)
+#define QH_FULL_SPEED (0 << 12)
+#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */
+ __hc32 hw_info2; /* see EHCI 3.6.2 */
+#define QH_SMASK 0x000000ff
+#define QH_CMASK 0x0000ff00
+#define QH_HUBADDR 0x007f0000
+#define QH_HUBPORT 0x3f800000
+#define QH_MULT 0xc0000000
+ __hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
+
+ /* qtd overlay (hardware parts of a struct fotg210_qtd) */
+ __hc32 hw_qtd_next;
+ __hc32 hw_alt_next;
+ __hc32 hw_token;
+ __hc32 hw_buf[5];
+ __hc32 hw_buf_hi[5];
+} __aligned(32);
+
+struct fotg210_qh {
+ struct fotg210_qh_hw *hw; /* Must come first */
+ /* the rest is HCD-private */
+ dma_addr_t qh_dma; /* address of qh */
+ union fotg210_shadow qh_next; /* ptr to qh; or periodic */
+ struct list_head qtd_list; /* sw qtd list */
+ struct list_head intr_node; /* list of intr QHs */
+ struct fotg210_qtd *dummy;
+ struct fotg210_qh *unlink_next; /* next on unlink list */
+
+ unsigned unlink_cycle;
+
+ u8 needs_rescan; /* Dequeue during giveback */
+ u8 qh_state;
+#define QH_STATE_LINKED 1 /* HC sees this */
+#define QH_STATE_UNLINK 2 /* HC may still see this */
+#define QH_STATE_IDLE 3 /* HC doesn't see this */
+#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */
+#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
+
+ u8 xacterrs; /* XactErr retry counter */
+#define QH_XACTERR_MAX 32 /* XactErr retry limit */
+
+ /* periodic schedule info */
+ u8 usecs; /* intr bandwidth */
+ u8 gap_uf; /* uframes split/csplit gap */
+ u8 c_usecs; /* ... split completion bw */
+ u16 tt_usecs; /* tt downstream bandwidth */
+ unsigned short period; /* polling interval */
+ unsigned short start; /* where polling starts */
+#define NO_FRAME ((unsigned short)~0) /* pick new start */
+
+ struct usb_device *dev; /* access to TT */
+ unsigned is_out:1; /* bulk or intr OUT */
+ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* description of one iso transaction (up to 3 KB data if highspeed) */
+struct fotg210_iso_packet {
+ /* These will be copied to iTD when scheduling */
+ u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
+ __hc32 transaction; /* itd->hw_transaction[i] |= */
+ u8 cross; /* buf crosses pages */
+ /* for full speed OUT splits */
+ u32 buf1;
+};
+
+/* temporary schedule data for packets from iso urbs (both speeds)
+ * each packet is one logical usb transaction to the device (not TT),
+ * beginning at stream->next_uframe
+ */
+struct fotg210_iso_sched {
+ struct list_head td_list;
+ unsigned span;
+ struct fotg210_iso_packet packet[0];
+};
+
+/*
+ * fotg210_iso_stream - groups all (s)itds for this endpoint.
+ * acts like a qh would, if EHCI had them for ISO.
+ */
+struct fotg210_iso_stream {
+ /* first field matches fotg210_hq, but is NULL */
+ struct fotg210_qh_hw *hw;
+
+ u8 bEndpointAddress;
+ u8 highspeed;
+ struct list_head td_list; /* queued itds */
+ struct list_head free_list; /* list of unused itds */
+ struct usb_device *udev;
+ struct usb_host_endpoint *ep;
+
+ /* output of (re)scheduling */
+ int next_uframe;
+ __hc32 splits;
+
+ /* the rest is derived from the endpoint descriptor,
+ * trusting urb->interval == f(epdesc->bInterval) and
+ * including the extra info for hw_bufp[0..2]
+ */
+ u8 usecs, c_usecs;
+ u16 interval;
+ u16 tt_usecs;
+ u16 maxp;
+ u16 raw_mask;
+ unsigned bandwidth;
+
+ /* This is used to initialize iTD's hw_bufp fields */
+ __hc32 buf0;
+ __hc32 buf1;
+ __hc32 buf2;
+
+ /* this is used to initialize sITD's tt info */
+ __hc32 address;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.3
+ * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
+ *
+ * Schedule records for high speed iso xfers
+ */
+struct fotg210_itd {
+ /* first part defined by EHCI spec */
+ __hc32 hw_next; /* see EHCI 3.3.1 */
+ __hc32 hw_transaction[8]; /* see EHCI 3.3.2 */
+#define FOTG210_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
+#define FOTG210_ISOC_BUF_ERR (1<<30) /* Data buffer error */
+#define FOTG210_ISOC_BABBLE (1<<29) /* babble detected */
+#define FOTG210_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
+#define FOTG210_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
+#define FOTG210_ITD_IOC (1 << 15) /* interrupt on complete */
+
+#define ITD_ACTIVE(fotg210) cpu_to_hc32(fotg210, FOTG210_ISOC_ACTIVE)
+
+ __hc32 hw_bufp[7]; /* see EHCI 3.3.3 */
+ __hc32 hw_bufp_hi[7]; /* Appendix B */
+
+ /* the rest is HCD-private */
+ dma_addr_t itd_dma; /* for this itd */
+ union fotg210_shadow itd_next; /* ptr to periodic q entry */
+
+ struct urb *urb;
+ struct fotg210_iso_stream *stream; /* endpoint's queue */
+ struct list_head itd_list; /* list of stream's itds */
+
+ /* any/all hw_transactions here may be used by that urb */
+ unsigned frame; /* where scheduled */
+ unsigned pg;
+ unsigned index[8]; /* in urb->iso_frame_desc */
+} __aligned(32);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.96 Section 3.7
+ * Periodic Frame Span Traversal Node (FSTN)
+ *
+ * Manages split interrupt transactions (using TT) that span frame boundaries
+ * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN
+ * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
+ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
+ */
+struct fotg210_fstn {
+ __hc32 hw_next; /* any periodic q entry */
+ __hc32 hw_prev; /* qh or FOTG210_LIST_END */
+
+ /* the rest is HCD-private */
+ dma_addr_t fstn_dma;
+ union fotg210_shadow fstn_next; /* ptr to periodic q entry */
+} __aligned(32);
+
+/*-------------------------------------------------------------------------*/
+
+/* Prepare the PORTSC wakeup flags during controller suspend/resume */
+
+#define fotg210_prepare_ports_for_controller_suspend(fotg210, do_wakeup) \
+ fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup);
+
+#define fotg210_prepare_ports_for_controller_resume(fotg210) \
+ fotg210_adjust_port_wakeup_flags(fotg210, false, false);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Some EHCI controllers have a Transaction Translator built into the
+ * root hub. This is a non-standard feature. Each controller will need
+ * to add code to the following inline functions, and call them as
+ * needed (mostly in root hub code).
+ */
+
+static inline unsigned int
+fotg210_get_speed(struct fotg210_hcd *fotg210, unsigned int portsc)
+{
+ return (readl(&fotg210->regs->otgcsr)
+ & OTGCSR_HOST_SPD_TYP) >> 22;
+}
+
+/* Returns the speed of a device attached to a port on the root hub. */
+static inline unsigned int
+fotg210_port_speed(struct fotg210_hcd *fotg210, unsigned int portsc)
+{
+ switch (fotg210_get_speed(fotg210, portsc)) {
+ case 0:
+ return 0;
+ case 1:
+ return USB_PORT_STAT_LOW_SPEED;
+ case 2:
+ default:
+ return USB_PORT_STAT_HIGH_SPEED;
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define fotg210_has_fsl_portno_bug(e) (0)
+
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ *
+ */
+
+#define fotg210_big_endian_mmio(e) 0
+#define fotg210_big_endian_capbase(e) 0
+
+static inline unsigned int fotg210_readl(const struct fotg210_hcd *fotg210,
+ __u32 __iomem *regs)
+{
+ return readl(regs);
+}
+
+static inline void fotg210_writel(const struct fotg210_hcd *fotg210,
+ const unsigned int val, __u32 __iomem *regs)
+{
+ writel(val, regs);
+}
+
+/* cpu to fotg210 */
+static inline __hc32 cpu_to_hc32(const struct fotg210_hcd *fotg210, const u32 x)
+{
+ return cpu_to_le32(x);
+}
+
+/* fotg210 to cpu */
+static inline u32 hc32_to_cpu(const struct fotg210_hcd *fotg210, const __hc32 x)
+{
+ return le32_to_cpu(x);
+}
+
+static inline u32 hc32_to_cpup(const struct fotg210_hcd *fotg210,
+ const __hc32 *x)
+{
+ return le32_to_cpup(x);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline unsigned fotg210_read_frame_index(struct fotg210_hcd *fotg210)
+{
+ return fotg210_readl(fotg210, &fotg210->regs->frame_index);
+}
+
+#define fotg210_itdlen(urb, desc, t) ({ \
+ usb_pipein((urb)->pipe) ? \
+ (desc)->length - FOTG210_ITD_LENGTH(t) : \
+ FOTG210_ITD_LENGTH(t); \
+})
+/*-------------------------------------------------------------------------*/
+
+#ifndef DEBUG
+#define STUB_DEBUG_FILES
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*/
+
+#endif /* __LINUX_FOTG210_H */
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 11e0b79ff9d..cfbff716182 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -258,7 +258,7 @@ static int fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev)
int fsl_usb2_mpc5121_init(struct platform_device *pdev)
{
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+ struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct clk *clk;
char clk_name[10];
int base, clk_num;
@@ -298,7 +298,7 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
{
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+ struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
pdata->regs = NULL;
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
index 483990c716a..5b86ffb88f1 100644
--- a/drivers/usb/host/hwa-hc.c
+++ b/drivers/usb/host/hwa-hc.c
@@ -161,6 +161,13 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd)
usb_hcd->uses_new_polling = 1;
set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
usb_hcd->state = HC_STATE_RUNNING;
+
+ /*
+ * prevent USB core from suspending the root hub since
+ * bus_suspend and bus_resume are not yet supported.
+ */
+ pm_runtime_get_noresume(&usb_hcd->self.root_hub->dev);
+
result = 0;
out:
mutex_unlock(&wusbhc->mutex);
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index 03dc4d9cbec..60a5de505ca 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -1860,7 +1860,7 @@ static int imx21_probe(struct platform_device *pdev)
imx21 = hcd_to_imx21(hcd);
imx21->hcd = hcd;
imx21->dev = &pdev->dev;
- imx21->pdata = pdev->dev.platform_data;
+ imx21->pdata = dev_get_platdata(&pdev->dev);
if (!imx21->pdata)
imx21->pdata = &default_pdata;
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index b64e661618b..c7d0f8f231b 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1626,7 +1626,7 @@ static int isp116x_probe(struct platform_device *pdev)
isp116x->addr_reg = addr_reg;
spin_lock_init(&isp116x->lock);
INIT_LIST_HEAD(&isp116x->async);
- isp116x->board = pdev->dev.platform_data;
+ isp116x->board = dev_get_platdata(&pdev->dev);
if (!isp116x->board) {
ERR("Platform data structure not initialized\n");
diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h
index 9a2c400e609..dd34b7a3396 100644
--- a/drivers/usb/host/isp116x.h
+++ b/drivers/usb/host/isp116x.h
@@ -325,11 +325,7 @@ struct isp116x_ep {
/*-------------------------------------------------------------------------*/
-#ifdef DEBUG
-#define DBG(stuff...) printk(KERN_DEBUG "116x: " stuff)
-#else
-#define DBG(stuff...) do{}while(0)
-#endif
+#define DBG(stuff...) pr_debug("116x: " stuff)
#ifdef VERBOSE
# define VDBG DBG
@@ -358,15 +354,8 @@ struct isp116x_ep {
#define isp116x_check_platform_delay(h) 0
#endif
-#if defined(DEBUG)
-#define IRQ_TEST() BUG_ON(!irqs_disabled())
-#else
-#define IRQ_TEST() do{}while(0)
-#endif
-
static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
{
- IRQ_TEST();
writew(reg & 0xff, isp116x->addr_reg);
isp116x_delay(isp116x, 300);
}
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index b04e8ece4d3..6f29abad681 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -37,11 +37,7 @@
* recovery time (MSCx = 0x7f8c) with a memory clock of 99.53 MHz.
*/
-#ifdef CONFIG_USB_DEBUG
-# define ISP1362_DEBUG
-#else
-# undef ISP1362_DEBUG
-#endif
+#undef ISP1362_DEBUG
/*
* The PXA255 UDC apparently doesn't handle GET_STATUS, GET_CONFIG and
@@ -82,6 +78,8 @@
#include <linux/io.h>
#include <linux/bitmap.h>
#include <linux/prefetch.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
@@ -92,7 +90,6 @@ static int dbg_level;
module_param(dbg_level, int, 0644);
#else
module_param(dbg_level, int, 0);
-#define STUB_DEBUG_FILE
#endif
#include "../core/usb.h"
@@ -350,8 +347,6 @@ static void isp1362_write_ptd(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep
struct ptd *ptd = &ep->ptd;
int len = PTD_GET_DIR(ptd) == PTD_DIR_IN ? 0 : ep->length;
- _BUG_ON(ep->ptd_offset < 0);
-
prefetch(ptd);
isp1362_write_buffer(isp1362_hcd, ptd, ep->ptd_offset, PTD_HEADER_SIZE);
if (len)
@@ -1575,12 +1570,12 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
DBG(0, "ClearHubFeature: ");
switch (wValue) {
case C_HUB_OVER_CURRENT:
- _DBG(0, "C_HUB_OVER_CURRENT\n");
+ DBG(0, "C_HUB_OVER_CURRENT\n");
spin_lock_irqsave(&isp1362_hcd->lock, flags);
isp1362_write_reg32(isp1362_hcd, HCRHSTATUS, RH_HS_OCIC);
spin_unlock_irqrestore(&isp1362_hcd->lock, flags);
case C_HUB_LOCAL_POWER:
- _DBG(0, "C_HUB_LOCAL_POWER\n");
+ DBG(0, "C_HUB_LOCAL_POWER\n");
break;
default:
goto error;
@@ -1591,7 +1586,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
switch (wValue) {
case C_HUB_OVER_CURRENT:
case C_HUB_LOCAL_POWER:
- _DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n");
+ DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n");
break;
default:
goto error;
@@ -1622,36 +1617,36 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
- _DBG(0, "USB_PORT_FEAT_ENABLE\n");
+ DBG(0, "USB_PORT_FEAT_ENABLE\n");
tmp = RH_PS_CCS;
break;
case USB_PORT_FEAT_C_ENABLE:
- _DBG(0, "USB_PORT_FEAT_C_ENABLE\n");
+ DBG(0, "USB_PORT_FEAT_C_ENABLE\n");
tmp = RH_PS_PESC;
break;
case USB_PORT_FEAT_SUSPEND:
- _DBG(0, "USB_PORT_FEAT_SUSPEND\n");
+ DBG(0, "USB_PORT_FEAT_SUSPEND\n");
tmp = RH_PS_POCI;
break;
case USB_PORT_FEAT_C_SUSPEND:
- _DBG(0, "USB_PORT_FEAT_C_SUSPEND\n");
+ DBG(0, "USB_PORT_FEAT_C_SUSPEND\n");
tmp = RH_PS_PSSC;
break;
case USB_PORT_FEAT_POWER:
- _DBG(0, "USB_PORT_FEAT_POWER\n");
+ DBG(0, "USB_PORT_FEAT_POWER\n");
tmp = RH_PS_LSDA;
break;
case USB_PORT_FEAT_C_CONNECTION:
- _DBG(0, "USB_PORT_FEAT_C_CONNECTION\n");
+ DBG(0, "USB_PORT_FEAT_C_CONNECTION\n");
tmp = RH_PS_CSC;
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
- _DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n");
+ DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n");
tmp = RH_PS_OCIC;
break;
case USB_PORT_FEAT_C_RESET:
- _DBG(0, "USB_PORT_FEAT_C_RESET\n");
+ DBG(0, "USB_PORT_FEAT_C_RESET\n");
tmp = RH_PS_PRSC;
break;
default:
@@ -1671,7 +1666,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
wIndex--;
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- _DBG(0, "USB_PORT_FEAT_SUSPEND\n");
+ DBG(0, "USB_PORT_FEAT_SUSPEND\n");
spin_lock_irqsave(&isp1362_hcd->lock, flags);
isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PSS);
isp1362_hcd->rhport[wIndex] =
@@ -1679,7 +1674,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
spin_unlock_irqrestore(&isp1362_hcd->lock, flags);
break;
case USB_PORT_FEAT_POWER:
- _DBG(0, "USB_PORT_FEAT_POWER\n");
+ DBG(0, "USB_PORT_FEAT_POWER\n");
spin_lock_irqsave(&isp1362_hcd->lock, flags);
isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PPS);
isp1362_hcd->rhport[wIndex] =
@@ -1687,7 +1682,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
spin_unlock_irqrestore(&isp1362_hcd->lock, flags);
break;
case USB_PORT_FEAT_RESET:
- _DBG(0, "USB_PORT_FEAT_RESET\n");
+ DBG(0, "USB_PORT_FEAT_RESET\n");
spin_lock_irqsave(&isp1362_hcd->lock, flags);
t1 = jiffies + msecs_to_jiffies(USB_RESET_WIDTH);
@@ -1721,7 +1716,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
default:
error:
/* "protocol stall" on error */
- _DBG(0, "PROTOCOL STALL\n");
+ DBG(0, "PROTOCOL STALL\n");
retval = -EPIPE;
}
@@ -1913,20 +1908,6 @@ static int isp1362_bus_resume(struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
-#ifdef STUB_DEBUG_FILE
-
-static inline void create_debug_file(struct isp1362_hcd *isp1362_hcd)
-{
-}
-static inline void remove_debug_file(struct isp1362_hcd *isp1362_hcd)
-{
-}
-
-#else
-
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
static void dump_irq(struct seq_file *s, char *label, u16 mask)
{
seq_printf(s, "%-15s %04x%s%s%s%s%s%s\n", label, mask,
@@ -2069,7 +2050,7 @@ static void dump_regs(struct seq_file *s, struct isp1362_hcd *isp1362_hcd)
isp1362_read_reg16(isp1362_hcd, HCATLDTCTO));
}
-static int proc_isp1362_show(struct seq_file *s, void *unused)
+static int isp1362_show(struct seq_file *s, void *unused)
{
struct isp1362_hcd *isp1362_hcd = s->private;
struct isp1362_ep *ep;
@@ -2173,41 +2154,31 @@ static int proc_isp1362_show(struct seq_file *s, void *unused)
return 0;
}
-static int proc_isp1362_open(struct inode *inode, struct file *file)
+static int isp1362_open(struct inode *inode, struct file *file)
{
- return single_open(file, proc_isp1362_show, PDE_DATA(inode));
+ return single_open(file, isp1362_show, inode);
}
-static const struct file_operations proc_ops = {
- .open = proc_isp1362_open,
+static const struct file_operations debug_ops = {
+ .open = isp1362_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/* expect just one isp1362_hcd per system */
-static const char proc_filename[] = "driver/isp1362";
-
static void create_debug_file(struct isp1362_hcd *isp1362_hcd)
{
- struct proc_dir_entry *pde;
-
- pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, isp1362_hcd);
- if (pde == NULL) {
- pr_warning("%s: Failed to create debug file '%s'\n", __func__, proc_filename);
- return;
- }
- isp1362_hcd->pde = pde;
+ isp1362_hcd->debug_file = debugfs_create_file("isp1362", S_IRUGO,
+ usb_debug_root,
+ isp1362_hcd, &debug_ops);
}
static void remove_debug_file(struct isp1362_hcd *isp1362_hcd)
{
- if (isp1362_hcd->pde)
- remove_proc_entry(proc_filename, NULL);
+ debugfs_remove(isp1362_hcd->debug_file);
}
-#endif
-
/*-------------------------------------------------------------------------*/
static void __isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd)
@@ -2754,7 +2725,7 @@ static int isp1362_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&isp1362_hcd->periodic);
INIT_LIST_HEAD(&isp1362_hcd->isoc);
INIT_LIST_HEAD(&isp1362_hcd->remove_list);
- isp1362_hcd->board = pdev->dev.platform_data;
+ isp1362_hcd->board = dev_get_platdata(&pdev->dev);
#if USE_PLATFORM_DELAY
if (!isp1362_hcd->board->delay) {
dev_err(hcd->self.controller, "No platform delay function given\n");
diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h
index 0f97820e65b..3b0b4847c3a 100644
--- a/drivers/usb/host/isp1362.h
+++ b/drivers/usb/host/isp1362.h
@@ -76,14 +76,14 @@ static inline void delayed_insw(unsigned int addr, void *buf, int len)
#define ISP1362_REG_WRITE_OFFSET 0x80
-#ifdef ISP1362_DEBUG
-typedef const unsigned int isp1362_reg_t;
-
#define REG_WIDTH_16 0x000
#define REG_WIDTH_32 0x100
#define REG_WIDTH_MASK 0x100
#define REG_NO_MASK 0x0ff
+#ifdef ISP1362_DEBUG
+typedef const unsigned int isp1362_reg_t;
+
#define REG_ACCESS_R 0x200
#define REG_ACCESS_W 0x400
#define REG_ACCESS_RW 0x600
@@ -91,9 +91,6 @@ typedef const unsigned int isp1362_reg_t;
#define ISP1362_REG_NO(r) ((r) & REG_NO_MASK)
-#define _BUG_ON(x) BUG_ON(x)
-#define _WARN_ON(x) WARN_ON(x)
-
#define ISP1362_REG(name, addr, width, rw) \
static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw))
@@ -102,8 +99,6 @@ static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw))
#else
typedef const unsigned char isp1362_reg_t;
#define ISP1362_REG_NO(r) (r)
-#define _BUG_ON(x) do {} while (0)
-#define _WARN_ON(x) do {} while (0)
#define ISP1362_REG(name, addr, width, rw) \
static isp1362_reg_t ISP1362_REG_##name = addr
@@ -485,7 +480,7 @@ struct isp1362_hcd {
struct isp1362_platform_data *board;
- struct proc_dir_entry *pde;
+ struct dentry *debug_file;
unsigned long stat1, stat2, stat4, stat8, stat16;
/* HC registers */
@@ -587,21 +582,11 @@ static inline struct usb_hcd *isp1362_hcd_to_hcd(struct isp1362_hcd *isp1362_hcd
* ISP1362 HW Interface
*/
-#ifdef ISP1362_DEBUG
#define DBG(level, fmt...) \
do { \
if (dbg_level > level) \
pr_debug(fmt); \
} while (0)
-#define _DBG(level, fmt...) \
- do { \
- if (dbg_level > level) \
- printk(fmt); \
- } while (0)
-#else
-#define DBG(fmt...) do {} while (0)
-#define _DBG DBG
-#endif
#ifdef VERBOSE
# define VDBG(fmt...) DBG(3, fmt)
@@ -645,9 +630,7 @@ static inline struct usb_hcd *isp1362_hcd_to_hcd(struct isp1362_hcd *isp1362_hcd
*/
static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t reg)
{
- /*_BUG_ON((reg & ISP1362_REG_WRITE_OFFSET) && !(reg & REG_ACCESS_W));*/
REG_ACCESS_TEST(reg);
- _BUG_ON(!irqs_disabled());
DUMMY_DELAY_ACCESS;
writew(ISP1362_REG_NO(reg), isp1362_hcd->addr_reg);
DUMMY_DELAY_ACCESS;
@@ -656,7 +639,6 @@ static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t re
static void isp1362_write_data16(struct isp1362_hcd *isp1362_hcd, u16 val)
{
- _BUG_ON(!irqs_disabled());
DUMMY_DELAY_ACCESS;
writew(val, isp1362_hcd->data_reg);
}
@@ -665,7 +647,6 @@ static u16 isp1362_read_data16(struct isp1362_hcd *isp1362_hcd)
{
u16 val;
- _BUG_ON(!irqs_disabled());
DUMMY_DELAY_ACCESS;
val = readw(isp1362_hcd->data_reg);
@@ -674,7 +655,6 @@ static u16 isp1362_read_data16(struct isp1362_hcd *isp1362_hcd)
static void isp1362_write_data32(struct isp1362_hcd *isp1362_hcd, u32 val)
{
- _BUG_ON(!irqs_disabled());
#if USE_32BIT
DUMMY_DELAY_ACCESS;
writel(val, isp1362_hcd->data_reg);
@@ -690,7 +670,6 @@ static u32 isp1362_read_data32(struct isp1362_hcd *isp1362_hcd)
{
u32 val;
- _BUG_ON(!irqs_disabled());
#if USE_32BIT
DUMMY_DELAY_ACCESS;
val = readl(isp1362_hcd->data_reg);
@@ -713,8 +692,6 @@ static void isp1362_read_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 le
if (!len)
return;
- _BUG_ON(!irqs_disabled());
-
RDBG("%s: Reading %d byte from fifo to mem @ %p\n", __func__, len, buf);
#if USE_32BIT
if (len >= 4) {
@@ -760,8 +737,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
return;
}
- _BUG_ON(!irqs_disabled());
-
RDBG("%s: Writing %d byte to fifo from memory @%p\n", __func__, len, buf);
#if USE_32BIT
if (len >= 4) {
@@ -854,7 +829,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
isp1362_write_reg32(d, r, __v & ~m); \
}
-#ifdef ISP1362_DEBUG
#define isp1362_show_reg(d, r) { \
if ((ISP1362_REG_##r & REG_WIDTH_MASK) == REG_WIDTH_32) \
DBG(0, "%-12s[%02x]: %08x\n", #r, \
@@ -863,9 +837,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
DBG(0, "%-12s[%02x]: %04x\n", #r, \
ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg16(d, r)); \
}
-#else
-#define isp1362_show_reg(d, r) do {} while (0)
-#endif
static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *isp1362_hcd)
{
@@ -923,10 +894,6 @@ static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *is
static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u16 len)
{
- _BUG_ON(offset & 1);
- _BUG_ON(offset >= ISP1362_BUF_SIZE);
- _BUG_ON(len > ISP1362_BUF_SIZE);
- _BUG_ON(offset + len > ISP1362_BUF_SIZE);
len = (len + 1) & ~1;
isp1362_clr_mask16(isp1362_hcd, HCDMACFG, HCDMACFG_CTR_ENABLE);
@@ -936,42 +903,32 @@ static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u
static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len)
{
- _BUG_ON(offset & 1);
-
isp1362_write_diraddr(isp1362_hcd, offset, len);
DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n",
__func__, len, offset, buf);
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
- _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA);
isp1362_read_fifo(isp1362_hcd, buf, len);
- _WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
- _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
}
static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len)
{
- _BUG_ON(offset & 1);
-
isp1362_write_diraddr(isp1362_hcd, offset, len);
DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n",
__func__, len, offset, buf);
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
- _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA | ISP1362_REG_WRITE_OFFSET);
isp1362_write_fifo(isp1362_hcd, buf, len);
- _WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
- _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
}
static void __attribute__((unused)) dump_data(char *buf, int len)
@@ -1002,7 +959,7 @@ static void __attribute__((unused)) dump_data(char *buf, int len)
}
}
-#if defined(ISP1362_DEBUG) && defined(PTD_TRACE)
+#if defined(PTD_TRACE)
static void dump_ptd(struct ptd *ptd)
{
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 3df49b169b5..df931e9ba5b 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -351,7 +351,7 @@ static int isp1760_plat_probe(struct platform_device *pdev)
struct resource *mem_res;
struct resource *irq_res;
resource_size_t mem_size;
- struct isp1760_platform_data *priv = pdev->dev.platform_data;
+ struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev);
unsigned int devflags = 0;
unsigned long irqflags = IRQF_SHARED;
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 9677f683120..caa3764a340 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -31,8 +31,8 @@
#define at91_for_each_port(index) \
for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++)
-/* interface and function clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *hclk;
+/* interface, function and usb clocks; sometimes also an AHB clock */
+static struct clk *iclk, *fclk, *uclk, *hclk;
static int clocked;
extern int usb_disabled(void);
@@ -41,6 +41,10 @@ extern int usb_disabled(void);
static void at91_start_clock(void)
{
+ if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+ clk_set_rate(uclk, 48000000);
+ clk_prepare_enable(uclk);
+ }
clk_prepare_enable(hclk);
clk_prepare_enable(iclk);
clk_prepare_enable(fclk);
@@ -52,6 +56,8 @@ static void at91_stop_clock(void)
clk_disable_unprepare(fclk);
clk_disable_unprepare(iclk);
clk_disable_unprepare(hclk);
+ if (IS_ENABLED(CONFIG_COMMON_CLK))
+ clk_disable_unprepare(uclk);
clocked = 0;
}
@@ -162,6 +168,14 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
retval = PTR_ERR(hclk);
goto err5;
}
+ if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+ uclk = clk_get(&pdev->dev, "usb_clk");
+ if (IS_ERR(uclk)) {
+ dev_err(&pdev->dev, "failed to get uclk\n");
+ retval = PTR_ERR(uclk);
+ goto err6;
+ }
+ }
at91_start_hc(pdev);
ohci_hcd_init(hcd_to_ohci(hcd));
@@ -173,6 +187,9 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
/* Error handling */
at91_stop_hc(pdev);
+ if (IS_ENABLED(CONFIG_COMMON_CLK))
+ clk_put(uclk);
+ err6:
clk_put(hclk);
err5:
clk_put(fclk);
@@ -212,12 +229,12 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd,
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
+ if (IS_ENABLED(CONFIG_COMMON_CLK))
+ clk_put(uclk);
clk_put(hclk);
clk_put(fclk);
clk_put(iclk);
fclk = iclk = hclk = NULL;
-
- dev_set_drvdata(&pdev->dev, NULL);
}
/*-------------------------------------------------------------------------*/
@@ -225,7 +242,7 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd,
static int
ohci_at91_reset (struct usb_hcd *hcd)
{
- struct at91_usbh_data *board = hcd->self.controller->platform_data;
+ struct at91_usbh_data *board = dev_get_platdata(hcd->self.controller);
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret;
@@ -280,7 +297,7 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)
*/
static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
{
- struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
+ struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller);
int length = ohci_hub_status_data(hcd, buf);
int port;
@@ -301,7 +318,7 @@ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
- struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
+ struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller);
struct usb_hub_descriptor *desc;
int ret = -EINVAL;
u32 *data = (u32 *)buf;
@@ -461,7 +478,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
{
struct platform_device *pdev = data;
- struct at91_usbh_data *pdata = pdev->dev.platform_data;
+ struct at91_usbh_data *pdata = dev_get_platdata(&pdev->dev);
int val, gpio, port;
/* From the GPIO notifying the over-current situation, find
@@ -567,7 +584,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
if (ret)
return ret;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (pdata) {
at91_for_each_port(i) {
@@ -643,7 +660,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
{
- struct at91_usbh_data *pdata = pdev->dev.platform_data;
+ struct at91_usbh_data *pdata = dev_get_platdata(&pdev->dev);
int i;
if (pdata) {
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 6aaa9c9c8eb..9be59f11e05 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -85,7 +85,7 @@ static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
static int ohci_da8xx_init(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev->platform_data;
+ struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int result;
u32 rh_a;
@@ -171,7 +171,7 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
struct device *dev = hcd->self.controller;
- struct da8xx_ohci_root_hub *hub = dev->platform_data;
+ struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
int temp;
switch (typeReq) {
@@ -292,7 +292,7 @@ static const struct hc_driver ohci_da8xx_hc_driver = {
static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
struct platform_device *pdev)
{
- struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data;
+ struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
struct usb_hcd *hcd;
struct resource *mem;
int error, irq;
@@ -380,7 +380,7 @@ err0:
static inline void
usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
{
- struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data;
+ struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
hub->ocic_notify(NULL);
usb_remove_hcd(hcd);
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 8704e9fa5a8..84a20d5223b 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -30,83 +30,6 @@
static struct clk *usb_host_clock;
-static void ep93xx_start_hc(struct device *dev)
-{
- clk_enable(usb_host_clock);
-}
-
-static void ep93xx_stop_hc(struct device *dev)
-{
- clk_disable(usb_host_clock);
-}
-
-static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
- struct platform_device *pdev)
-{
- int retval;
- struct usb_hcd *hcd;
-
- if (pdev->resource[1].flags != IORESOURCE_IRQ) {
- dev_dbg(&pdev->dev, "resource[1] is not IORESOURCE_IRQ\n");
- return -ENOMEM;
- }
-
- hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx");
- if (hcd == NULL)
- return -ENOMEM;
-
- hcd->rsrc_start = pdev->resource[0].start;
- hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- usb_put_hcd(hcd);
- retval = -EBUSY;
- goto err1;
- }
-
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
- if (hcd->regs == NULL) {
- dev_dbg(&pdev->dev, "ioremap failed\n");
- retval = -ENOMEM;
- goto err2;
- }
-
- usb_host_clock = clk_get(&pdev->dev, NULL);
- if (IS_ERR(usb_host_clock)) {
- dev_dbg(&pdev->dev, "clk_get failed\n");
- retval = PTR_ERR(usb_host_clock);
- goto err3;
- }
-
- ep93xx_start_hc(&pdev->dev);
-
- ohci_hcd_init(hcd_to_ohci(hcd));
-
- retval = usb_add_hcd(hcd, pdev->resource[1].start, 0);
- if (retval == 0)
- return retval;
-
- ep93xx_stop_hc(&pdev->dev);
-err3:
- iounmap(hcd->regs);
-err2:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err1:
- usb_put_hcd(hcd);
-
- return retval;
-}
-
-static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd,
- struct platform_device *pdev)
-{
- usb_remove_hcd(hcd);
- ep93xx_stop_hc(&pdev->dev);
- clk_put(usb_host_clock);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
-}
-
static int ohci_ep93xx_start(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
@@ -147,15 +70,57 @@ static struct hc_driver ohci_ep93xx_hc_driver = {
.start_port_reset = ohci_start_port_reset,
};
-extern int usb_disabled(void);
-
static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev)
{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ int irq;
int ret;
- ret = -ENODEV;
- if (!usb_disabled())
- ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev);
+ if (usb_disabled())
+ return -ENODEV;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ hcd = usb_create_hcd(&ohci_ep93xx_hc_driver, &pdev->dev, "ep93xx");
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
+ hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hcd->regs)) {
+ ret = PTR_ERR(hcd->regs);
+ goto err_put_hcd;
+ }
+
+ usb_host_clock = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(usb_host_clock)) {
+ ret = PTR_ERR(usb_host_clock);
+ goto err_put_hcd;
+ }
+
+ clk_enable(usb_host_clock);
+
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ ret = usb_add_hcd(hcd, irq, 0);
+ if (ret)
+ goto err_clk_disable;
+
+ return 0;
+
+err_clk_disable:
+ clk_disable(usb_host_clock);
+err_put_hcd:
+ usb_put_hcd(hcd);
return ret;
}
@@ -164,7 +129,9 @@ static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
- usb_hcd_ep93xx_remove(hcd, pdev);
+ usb_remove_hcd(hcd);
+ clk_disable(usb_host_clock);
+ usb_put_hcd(hcd);
return 0;
}
@@ -179,7 +146,7 @@ static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_
msleep(5);
ohci->next_statechange = jiffies;
- ep93xx_stop_hc(&pdev->dev);
+ clk_disable(usb_host_clock);
return 0;
}
@@ -192,7 +159,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev)
msleep(5);
ohci->next_statechange = jiffies;
- ep93xx_start_hc(&pdev->dev);
+ clk_enable(usb_host_clock);
ohci_resume(hcd, false);
return 0;
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index b0b542c14e3..dc6ee9adacf 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -100,7 +100,7 @@ static const struct hc_driver exynos_ohci_hc_driver = {
static int exynos_ohci_probe(struct platform_device *pdev)
{
- struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
+ struct exynos4_ohci_platdata *pdata = dev_get_platdata(&pdev->dev);
struct exynos_ohci_hcd *exynos_ohci;
struct usb_hcd *hcd;
struct ohci_hcd *ohci;
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index a9d3437da22..8f6b695af6a 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -938,8 +938,8 @@ static void ohci_stop (struct usb_hcd *hcd)
if (quirk_nec(ohci))
flush_work(&ohci->nec_work);
- ohci_usb_reset (ohci);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ ohci_usb_reset(ohci);
free_irq(hcd->irq, hcd);
hcd->irq = 0;
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 8747fa6a51b..31d3a12eb48 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -191,7 +191,7 @@ static void start_hnp(struct ohci_hcd *ohci)
static int ohci_omap_init(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- struct omap_usb_config *config = hcd->self.controller->platform_data;
+ struct omap_usb_config *config = dev_get_platdata(hcd->self.controller);
int need_transceiver = (config->otg != 0);
int ret;
@@ -427,7 +427,7 @@ ohci_omap_start (struct usb_hcd *hcd)
if (!host_enabled)
return 0;
- config = hcd->self.controller->platform_data;
+ config = dev_get_platdata(hcd->self.controller);
if (config->otg || config->rwc) {
ohci->hc_control = OHCI_CTRL_RWC;
writel(OHCI_CTRL_RWC, &ohci->regs->control);
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
index 8f713571a0b..a09af26f69e 100644
--- a/drivers/usb/host/ohci-omap3.c
+++ b/drivers/usb/host/ohci-omap3.c
@@ -231,14 +231,6 @@ static int ohci_hcd_omap3_remove(struct platform_device *pdev)
return 0;
}
-static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
-}
-
static const struct of_device_id omap_ohci_dt_ids[] = {
{ .compatible = "ti,ohci-omap3" },
{ }
@@ -249,7 +241,7 @@ MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids);
static struct platform_driver ohci_hcd_omap3_driver = {
.probe = ohci_hcd_omap3_probe,
.remove = ohci_hcd_omap3_remove,
- .shutdown = ohci_hcd_omap3_shutdown,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ohci-omap3",
.of_match_table = omap_ohci_dt_ids,
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 08613e24189..ec337c2bd5e 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -289,7 +289,7 @@ static struct pci_driver ohci_pci_driver = {
.remove = usb_hcd_pci_remove,
.shutdown = usb_hcd_pci_shutdown,
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
.driver = {
.pm = &usb_hcd_pci_pm_ops
},
@@ -304,6 +304,13 @@ static int __init ohci_pci_init(void)
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
ohci_init_driver(&ohci_pci_hc_driver, &pci_overrides);
+
+#ifdef CONFIG_PM
+ /* Entries for the PCI suspend/resume callbacks are special */
+ ohci_pci_hc_driver.pci_suspend = ohci_suspend;
+ ohci_pci_hc_driver.pci_resume = ohci_resume;
+#endif
+
return pci_register_driver(&ohci_pci_driver);
}
module_init(ohci_pci_init);
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index bc30475c3a2..a4c6410f0ed 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -33,7 +33,7 @@ static const char hcd_name[] = "ohci-platform";
static int ohci_platform_reset(struct usb_hcd *hcd)
{
struct platform_device *pdev = to_platform_device(hcd->self.controller);
- struct usb_ohci_pdata *pdata = pdev->dev.platform_data;
+ struct usb_ohci_pdata *pdata = dev_get_platdata(&pdev->dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
if (pdata->big_endian_desc)
@@ -59,7 +59,7 @@ static int ohci_platform_probe(struct platform_device *dev)
{
struct usb_hcd *hcd;
struct resource *res_mem;
- struct usb_ohci_pdata *pdata = dev->dev.platform_data;
+ struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
int irq;
int err = -ENOMEM;
@@ -124,7 +124,7 @@ err_power:
static int ohci_platform_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
- struct usb_ohci_pdata *pdata = dev->dev.platform_data;
+ struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
@@ -139,7 +139,7 @@ static int ohci_platform_remove(struct platform_device *dev)
static int ohci_platform_suspend(struct device *dev)
{
- struct usb_ohci_pdata *pdata = dev->platform_data;
+ struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
struct platform_device *pdev =
container_of(dev, struct platform_device, dev);
@@ -152,7 +152,7 @@ static int ohci_platform_suspend(struct device *dev)
static int ohci_platform_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct usb_ohci_pdata *pdata = dev->platform_data;
+ struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
struct platform_device *pdev =
container_of(dev, struct platform_device, dev);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 8294e2fcc2f..75f5a1e2f01 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -200,15 +200,6 @@ static int ohci_hcd_ppc_of_remove(struct platform_device *op)
return 0;
}
-static void ohci_hcd_ppc_of_shutdown(struct platform_device *op)
-{
- struct usb_hcd *hcd = platform_get_drvdata(op);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
-}
-
-
static const struct of_device_id ohci_hcd_ppc_of_match[] = {
#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
{
@@ -243,7 +234,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
static struct platform_driver ohci_hcd_ppc_of_driver = {
.probe = ohci_hcd_ppc_of_probe,
.remove = ohci_hcd_ppc_of_remove,
- .shutdown = ohci_hcd_ppc_of_shutdown,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ppc-of-ohci",
.owner = THIS_MODULE,
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 3a9c01d8b79..93371a235e8 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -219,7 +219,7 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev)
struct pxaohci_platform_data *inf;
uint32_t uhchr;
- inf = dev->platform_data;
+ inf = dev_get_platdata(dev);
clk_prepare_enable(ohci->clk);
@@ -256,7 +256,7 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev)
struct pxaohci_platform_data *inf;
uint32_t uhccoms;
- inf = dev->platform_data;
+ inf = dev_get_platdata(dev);
if (cpu_is_pxa3xx())
pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self);
@@ -364,7 +364,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
if (retval)
return retval;
- inf = pdev->dev.platform_data;
+ inf = dev_get_platdata(&pdev->dev);
if (!inf)
return -ENODEV;
@@ -577,7 +577,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
- struct pxaohci_platform_data *inf = dev->platform_data;
+ struct pxaohci_platform_data *inf = dev_get_platdata(dev);
int status;
if (time_before(jiffies, ohci->ohci.next_statechange))
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index e125770b893..4919afa4125 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -38,12 +38,12 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc);
static struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd)
{
- return hcd->self.controller->platform_data;
+ return dev_get_platdata(hcd->self.controller);
}
static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
{
- struct s3c2410_hcd_info *info = dev->dev.platform_data;
+ struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
dev_dbg(&dev->dev, "s3c2410_start_hc:\n");
@@ -63,7 +63,7 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
static void s3c2410_stop_hc(struct platform_device *dev)
{
- struct s3c2410_hcd_info *info = dev->dev.platform_data;
+ struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
dev_dbg(&dev->dev, "s3c2410_stop_hc:\n");
@@ -339,10 +339,11 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
struct platform_device *dev)
{
struct usb_hcd *hcd = NULL;
+ struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
int retval;
- s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
- s3c2410_usb_set_power(dev->dev.platform_data, 2, 1);
+ s3c2410_usb_set_power(info, 1, 1);
+ s3c2410_usb_set_power(info, 2, 1);
hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
if (hcd == NULL)
diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c
index 197d514fe0d..22540ab71f5 100644
--- a/drivers/usb/host/ohci-tilegx.c
+++ b/drivers/usb/host/ohci-tilegx.c
@@ -95,7 +95,7 @@ static const struct hc_driver ohci_tilegx_hc_driver = {
static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
- struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+ struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
pte_t pte = { 0 };
int my_cpu = smp_processor_id();
int ret;
@@ -175,7 +175,7 @@ err_hcd:
static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct tilegx_usb_platform_data* pdata = pdev->dev.platform_data;
+ struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index b9848e4d3d4..2c76ef1320e 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -735,32 +735,6 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
return -ETIMEDOUT;
}
-#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31
-#define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI 0x9C31
-
-bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev)
-{
- return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
- pdev->vendor == PCI_VENDOR_ID_INTEL &&
- pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
-}
-
-/* The Intel Lynx Point chipset also has switchable ports. */
-bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev)
-{
- return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
- pdev->vendor == PCI_VENDOR_ID_INTEL &&
- (pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI ||
- pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI);
-}
-
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
-{
- return usb_is_intel_ppt_switchable_xhci(pdev) ||
- usb_is_intel_lpt_switchable_xhci(pdev);
-}
-EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
-
/*
* Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that
* share some number of ports. These ports can be switched between either
@@ -779,9 +753,23 @@ EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
* terminations before switching the USB 2.0 wires over, so that USB 3.0
* devices connect at SuperSpeed, rather than at USB 2.0 speeds.
*/
-void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
+void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
{
u32 ports_available;
+ bool ehci_found = false;
+ struct pci_dev *companion = NULL;
+
+ /* make sure an intel EHCI controller exists */
+ for_each_pci_dev(companion) {
+ if (companion->class == PCI_CLASS_SERIAL_USB_EHCI &&
+ companion->vendor == PCI_VENDOR_ID_INTEL) {
+ ehci_found = true;
+ break;
+ }
+ }
+
+ if (!ehci_found)
+ return;
/* Don't switchover the ports if the user hasn't compiled the xHCI
* driver. Otherwise they will see "dead" USB ports that don't power
@@ -840,7 +828,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over "
"to xHCI: 0x%x\n", ports_available);
}
-EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
+EXPORT_SYMBOL_GPL(usb_enable_intel_xhci_ports);
void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
{
@@ -921,8 +909,8 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
hc_init:
- if (usb_is_intel_switchable_xhci(pdev))
- usb_enable_xhci_ports(pdev);
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+ usb_enable_intel_xhci_ports(pdev);
op_reg_base = base + XHCI_HC_LENGTH(readl(base));
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index 4b8a2092432..ed6700d00fe 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -8,11 +8,11 @@ int usb_amd_find_chipset_info(void);
void usb_amd_dev_put(void);
void usb_amd_quirk_pll_disable(void);
void usb_amd_quirk_pll_enable(void);
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
-void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
+void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
void sb800_prefetch(struct device *dev, int on);
#else
+struct pci_dev;
static inline void usb_amd_quirk_pll_disable(void) {}
static inline void usb_amd_quirk_pll_enable(void) {}
static inline void usb_amd_dev_put(void) {}
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index a6fd8f5371d..2ad004ae747 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2393,7 +2393,7 @@ static const struct dev_pm_ops r8a66597_dev_pm_ops = {
static int r8a66597_remove(struct platform_device *pdev)
{
- struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
+ struct r8a66597 *r8a66597 = platform_get_drvdata(pdev);
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
del_timer_sync(&r8a66597->rh_timer);
@@ -2466,8 +2466,8 @@ static int r8a66597_probe(struct platform_device *pdev)
}
r8a66597 = hcd_to_r8a66597(hcd);
memset(r8a66597, 0, sizeof(struct r8a66597));
- dev_set_drvdata(&pdev->dev, r8a66597);
- r8a66597->pdata = pdev->dev.platform_data;
+ platform_set_drvdata(pdev, r8a66597);
+ r8a66597->pdata = dev_get_platdata(&pdev->dev);
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
if (r8a66597->pdata->on_chip) {
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index b2ec7fe758d..5477bf5df21 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -48,6 +48,8 @@
#include <linux/usb/hcd.h>
#include <linux/platform_device.h>
#include <linux/prefetch.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -63,11 +65,6 @@ MODULE_ALIAS("platform:sl811-hcd");
#define DRIVER_VERSION "19 May 2005"
-
-#ifndef DEBUG
-# define STUB_DEBUG_FILE
-#endif
-
/* for now, use only one transfer register bank */
#undef USE_B
@@ -100,7 +97,8 @@ static void port_power(struct sl811 *sl811, int is_on)
if (sl811->board && sl811->board->port_power) {
/* switch VBUS, at 500mA unless hub power budget gets set */
- DBG("power %s\n", is_on ? "on" : "off");
+ dev_dbg(hcd->self.controller, "power %s\n",
+ is_on ? "on" : "off");
sl811->board->port_power(hcd->self.controller, is_on);
}
@@ -282,7 +280,7 @@ static inline void sofirq_on(struct sl811 *sl811)
{
if (sl811->irq_enable & SL11H_INTMASK_SOFINTR)
return;
- VDBG("sof irq on\n");
+ dev_dbg(sl811_to_hcd(sl811)->self.controller, "sof irq on\n");
sl811->irq_enable |= SL11H_INTMASK_SOFINTR;
}
@@ -290,7 +288,7 @@ static inline void sofirq_off(struct sl811 *sl811)
{
if (!(sl811->irq_enable & SL11H_INTMASK_SOFINTR))
return;
- VDBG("sof irq off\n");
+ dev_dbg(sl811_to_hcd(sl811)->self.controller, "sof irq off\n");
sl811->irq_enable &= ~SL11H_INTMASK_SOFINTR;
}
@@ -338,7 +336,8 @@ static struct sl811h_ep *start(struct sl811 *sl811, u8 bank)
}
if (unlikely(list_empty(&ep->hep->urb_list))) {
- DBG("empty %p queue?\n", ep);
+ dev_dbg(sl811_to_hcd(sl811)->self.controller,
+ "empty %p queue?\n", ep);
return NULL;
}
@@ -391,7 +390,8 @@ static struct sl811h_ep *start(struct sl811 *sl811, u8 bank)
status_packet(sl811, ep, urb, bank, control);
break;
default:
- DBG("bad ep%p pid %02x\n", ep, ep->nextpid);
+ dev_dbg(sl811_to_hcd(sl811)->self.controller,
+ "bad ep%p pid %02x\n", ep, ep->nextpid);
ep = NULL;
}
return ep;
@@ -447,7 +447,8 @@ static void finish_request(
}
/* periodic deschedule */
- DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+ dev_dbg(sl811_to_hcd(sl811)->self.controller,
+ "deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
struct sl811h_ep *temp;
struct sl811h_ep **prev = &sl811->periodic[i];
@@ -593,7 +594,8 @@ static inline u8 checkdone(struct sl811 *sl811)
ctl = sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG));
if (ctl & SL11H_HCTLMASK_ARM)
sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
- DBG("%s DONE_A: ctrl %02x sts %02x\n",
+ dev_dbg(sl811_to_hcd(sl811)->self.controller,
+ "%s DONE_A: ctrl %02x sts %02x\n",
(ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost",
ctl,
sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG)));
@@ -604,7 +606,8 @@ static inline u8 checkdone(struct sl811 *sl811)
ctl = sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG));
if (ctl & SL11H_HCTLMASK_ARM)
sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
- DBG("%s DONE_B: ctrl %02x sts %02x\n",
+ dev_dbg(sl811_to_hcd(sl811)->self.controller,
+ "%s DONE_B: ctrl %02x sts %02x\n",
(ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost",
ctl,
sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG)));
@@ -665,7 +668,7 @@ retry:
* this one has nothing scheduled.
*/
if (sl811->next_periodic) {
- // ERR("overrun to slot %d\n", index);
+ // dev_err(hcd->self.controller, "overrun to slot %d\n", index);
sl811->stat_overrun++;
}
if (sl811->periodic[index])
@@ -723,7 +726,7 @@ retry:
} else if (irqstat & SL11H_INTMASK_RD) {
if (sl811->port1 & USB_PORT_STAT_SUSPEND) {
- DBG("wakeup\n");
+ dev_dbg(hcd->self.controller, "wakeup\n");
sl811->port1 |= USB_PORT_STAT_C_SUSPEND << 16;
sl811->stat_wake++;
} else
@@ -852,8 +855,9 @@ static int sl811h_urb_enqueue(
if (ep->maxpacket > H_MAXPACKET) {
/* iso packets up to 240 bytes could work... */
- DBG("dev %d ep%d maxpacket %d\n",
- udev->devnum, epnum, ep->maxpacket);
+ dev_dbg(hcd->self.controller,
+ "dev %d ep%d maxpacket %d\n", udev->devnum,
+ epnum, ep->maxpacket);
retval = -EINVAL;
kfree(ep);
goto fail;
@@ -917,7 +921,8 @@ static int sl811h_urb_enqueue(
* to share the faster parts of the tree without needing
* dummy/placeholder nodes
*/
- DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+ dev_dbg(hcd->self.controller, "schedule qh%d/%p branch %d\n",
+ ep->period, ep, ep->branch);
for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
struct sl811h_ep **prev = &sl811->periodic[i];
struct sl811h_ep *here = *prev;
@@ -976,7 +981,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
} else if (sl811->active_a == ep) {
if (time_before_eq(sl811->jiffies_a, jiffies)) {
/* happens a lot with lowspeed?? */
- DBG("giveup on DONE_A: ctrl %02x sts %02x\n",
+ dev_dbg(hcd->self.controller,
+ "giveup on DONE_A: ctrl %02x sts %02x\n",
sl811_read(sl811,
SL811_EP_A(SL11H_HOSTCTLREG)),
sl811_read(sl811,
@@ -990,7 +996,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
} else if (sl811->active_b == ep) {
if (time_before_eq(sl811->jiffies_a, jiffies)) {
/* happens a lot with lowspeed?? */
- DBG("giveup on DONE_B: ctrl %02x sts %02x\n",
+ dev_dbg(hcd->self.controller,
+ "giveup on DONE_B: ctrl %02x sts %02x\n",
sl811_read(sl811,
SL811_EP_B(SL11H_HOSTCTLREG)),
sl811_read(sl811,
@@ -1008,7 +1015,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
if (urb)
finish_request(sl811, ep, urb, 0);
else
- VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
+ dev_dbg(sl811_to_hcd(sl811)->self.controller,
+ "dequeue, urb %p active %s; wait4irq\n", urb,
(sl811->active_a == ep) ? "A" : "B");
} else
retval = -EINVAL;
@@ -1029,7 +1037,7 @@ sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
if (!list_empty(&hep->urb_list))
msleep(3);
if (!list_empty(&hep->urb_list))
- WARNING("ep %p not empty?\n", ep);
+ dev_warn(hcd->self.controller, "ep %p not empty?\n", ep);
kfree(ep);
hep->hcpriv = NULL;
@@ -1132,7 +1140,7 @@ sl811h_timer(unsigned long _sl811)
switch (signaling) {
case SL11H_CTL1MASK_SE0:
- DBG("end reset\n");
+ dev_dbg(sl811_to_hcd(sl811)->self.controller, "end reset\n");
sl811->port1 = (USB_PORT_STAT_C_RESET << 16)
| USB_PORT_STAT_POWER;
sl811->ctrl1 = 0;
@@ -1141,11 +1149,12 @@ sl811h_timer(unsigned long _sl811)
irqstat &= ~SL11H_INTMASK_RD;
break;
case SL11H_CTL1MASK_K:
- DBG("end resume\n");
+ dev_dbg(sl811_to_hcd(sl811)->self.controller, "end resume\n");
sl811->port1 &= ~USB_PORT_STAT_SUSPEND;
break;
default:
- DBG("odd timer signaling: %02x\n", signaling);
+ dev_dbg(sl811_to_hcd(sl811)->self.controller,
+ "odd timer signaling: %02x\n", signaling);
break;
}
sl811_write(sl811, SL11H_IRQ_STATUS, irqstat);
@@ -1243,7 +1252,7 @@ sl811h_hub_control(
break;
/* 20 msec of resume/K signaling, other irqs blocked */
- DBG("start resume...\n");
+ dev_dbg(hcd->self.controller, "start resume...\n");
sl811->irq_enable = 0;
sl811_write(sl811, SL11H_IRQ_ENABLE,
sl811->irq_enable);
@@ -1281,7 +1290,8 @@ sl811h_hub_control(
#ifndef VERBOSE
if (*(u16*)(buf+2)) /* only if wPortChange is interesting */
#endif
- DBG("GetPortStatus %08x\n", sl811->port1);
+ dev_dbg(hcd->self.controller, "GetPortStatus %08x\n",
+ sl811->port1);
break;
case SetPortFeature:
if (wIndex != 1 || wLength != 0)
@@ -1293,7 +1303,7 @@ sl811h_hub_control(
if (!(sl811->port1 & USB_PORT_STAT_ENABLE))
goto error;
- DBG("suspend...\n");
+ dev_dbg(hcd->self.controller,"suspend...\n");
sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA;
sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
break;
@@ -1338,7 +1348,7 @@ static int
sl811h_bus_suspend(struct usb_hcd *hcd)
{
// SOFs off
- DBG("%s\n", __func__);
+ dev_dbg(hcd->self.controller, "%s\n", __func__);
return 0;
}
@@ -1346,7 +1356,7 @@ static int
sl811h_bus_resume(struct usb_hcd *hcd)
{
// SOFs on
- DBG("%s\n", __func__);
+ dev_dbg(hcd->self.controller, "%s\n", __func__);
return 0;
}
@@ -1360,16 +1370,6 @@ sl811h_bus_resume(struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
-#ifdef STUB_DEBUG_FILE
-
-static inline void create_debug_file(struct sl811 *sl811) { }
-static inline void remove_debug_file(struct sl811 *sl811) { }
-
-#else
-
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
static void dump_irq(struct seq_file *s, char *label, u8 mask)
{
seq_printf(s, "%s %02x%s%s%s%s%s%s\n", label, mask,
@@ -1381,7 +1381,7 @@ static void dump_irq(struct seq_file *s, char *label, u8 mask)
(mask & SL11H_INTMASK_DP) ? " dp" : "");
}
-static int proc_sl811h_show(struct seq_file *s, void *unused)
+static int sl811h_show(struct seq_file *s, void *unused)
{
struct sl811 *sl811 = s->private;
struct sl811h_ep *ep;
@@ -1492,34 +1492,31 @@ static int proc_sl811h_show(struct seq_file *s, void *unused)
return 0;
}
-static int proc_sl811h_open(struct inode *inode, struct file *file)
+static int sl811h_open(struct inode *inode, struct file *file)
{
- return single_open(file, proc_sl811h_show, PDE_DATA(inode));
+ return single_open(file, sl811h_show, inode->i_private);
}
-static const struct file_operations proc_ops = {
- .open = proc_sl811h_open,
+static const struct file_operations debug_ops = {
+ .open = sl811h_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/* expect just one sl811 per system */
-static const char proc_filename[] = "driver/sl811h";
-
static void create_debug_file(struct sl811 *sl811)
{
- sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811);
+ sl811->debug_file = debugfs_create_file("sl811h", S_IRUGO,
+ usb_debug_root, sl811,
+ &debug_ops);
}
static void remove_debug_file(struct sl811 *sl811)
{
- if (sl811->pde)
- remove_proc_entry(proc_filename, NULL);
+ debugfs_remove(sl811->debug_file);
}
-#endif
-
/*-------------------------------------------------------------------------*/
static void
@@ -1648,7 +1645,7 @@ sl811h_probe(struct platform_device *dev)
/* refuse to confuse usbcore */
if (dev->dev.dma_mask) {
- DBG("no we won't dma\n");
+ dev_dbg(&dev->dev, "no we won't dma\n");
return -EINVAL;
}
@@ -1694,7 +1691,7 @@ sl811h_probe(struct platform_device *dev)
spin_lock_init(&sl811->lock);
INIT_LIST_HEAD(&sl811->async);
- sl811->board = dev->dev.platform_data;
+ sl811->board = dev_get_platdata(&dev->dev);
init_timer(&sl811->timer);
sl811->timer.function = sl811h_timer;
sl811->timer.data = (unsigned long) sl811;
@@ -1716,7 +1713,7 @@ sl811h_probe(struct platform_device *dev)
break;
default:
/* reject case 0, SL11S is less functional */
- DBG("chiprev %02x\n", tmp);
+ dev_dbg(&dev->dev, "chiprev %02x\n", tmp);
retval = -ENXIO;
goto err6;
}
@@ -1747,7 +1744,7 @@ sl811h_probe(struct platform_device *dev)
if (!ioaddr)
iounmap(addr_reg);
err2:
- DBG("init error, %d\n", retval);
+ dev_dbg(&dev->dev, "init error, %d\n", retval);
return retval;
}
diff --git a/drivers/usb/host/sl811.h b/drivers/usb/host/sl811.h
index b6b8c1f233d..1e23ef49bec 100644
--- a/drivers/usb/host/sl811.h
+++ b/drivers/usb/host/sl811.h
@@ -122,7 +122,7 @@ struct sl811 {
void __iomem *addr_reg;
void __iomem *data_reg;
struct sl811_platform_data *board;
- struct proc_dir_entry *pde;
+ struct dentry *debug_file;
unsigned long stat_insrmv;
unsigned long stat_wake;
@@ -242,25 +242,8 @@ sl811_read_buf(struct sl811 *sl811, int addr, void *buf, size_t count)
/*-------------------------------------------------------------------------*/
-#ifdef DEBUG
-#define DBG(stuff...) printk(KERN_DEBUG "sl811: " stuff)
-#else
-#define DBG(stuff...) do{}while(0)
-#endif
-
-#ifdef VERBOSE
-# define VDBG DBG
-#else
-# define VDBG(stuff...) do{}while(0)
-#endif
-
#ifdef PACKET_TRACE
-# define PACKET VDBG
+# define PACKET pr_debug("sl811: "stuff)
#else
# define PACKET(stuff...) do{}while(0)
#endif
-
-#define ERR(stuff...) printk(KERN_ERR "sl811: " stuff)
-#define WARNING(stuff...) printk(KERN_WARNING "sl811: " stuff)
-#define INFO(stuff...) printk(KERN_INFO "sl811: " stuff)
-
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 5c124bf5d01..e402beb5a06 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -1809,9 +1809,9 @@ static int u132_hcd_start(struct usb_hcd *hcd)
struct platform_device *pdev =
to_platform_device(hcd->self.controller);
u16 vendor = ((struct u132_platform_data *)
- (pdev->dev.platform_data))->vendor;
+ dev_get_platdata(&pdev->dev))->vendor;
u16 device = ((struct u132_platform_data *)
- (pdev->dev.platform_data))->device;
+ dev_get_platdata(&pdev->dev))->device;
mutex_lock(&u132->sw_lock);
msleep(10);
if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
@@ -3034,7 +3034,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
int addrs = MAX_U132_ADDRS;
int udevs = MAX_U132_UDEVS;
int endps = MAX_U132_ENDPS;
- u132->board = pdev->dev.platform_data;
+ u132->board = dev_get_platdata(&pdev->dev);
u132->platform_dev = pdev;
u132->power = 0;
u132->reset = 0;
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 5d5e58fdecc..73503a81ee8 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -580,3 +580,17 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci,
xhci_dbg_slot_ctx(xhci, ctx);
xhci_dbg_ep_ctx(xhci, ctx, last_ep);
}
+
+void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+ xhci_dbg(xhci, "%pV\n", &vaf);
+ trace(&vaf);
+ va_end(args);
+}
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index 8d7a1324e2f..9fe3225e6c6 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -71,7 +71,7 @@
/* USB 2.0 xHCI 1.0 hardware LMP capability - section 7.2.2.1.3.2 */
#define XHCI_HLC (1 << 19)
-#define XHCI_BLC (1 << 19)
+#define XHCI_BLC (1 << 20)
/* command register values to disable interrupts and halt the HC */
/* start/stop HC execution - do not write unless HC is halted*/
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 1d3545943c5..fae697ed0b7 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -24,6 +24,7 @@
#include <asm/unaligned.h>
#include "xhci.h"
+#include "xhci-trace.h"
#define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
@@ -461,8 +462,15 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
}
}
+/* Updates Link Status for USB 2.1 port */
+static void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg)
+{
+ if ((status_reg & PORT_PLS_MASK) == XDEV_U2)
+ *status |= USB_PORT_STAT_L1;
+}
+
/* Updates Link Status for super Speed port */
-static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
+static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg)
{
u32 pls = status_reg & PORT_PLS_MASK;
@@ -528,12 +536,128 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex)
xhci->port_status_u0 |= 1 << wIndex;
if (xhci->port_status_u0 == all_ports_seen_u0) {
del_timer_sync(&xhci->comp_mode_recovery_timer);
- xhci_dbg(xhci, "All USB3 ports have entered U0 already!\n");
- xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "All USB3 ports have entered U0 already!");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Compliance Mode Recovery Timer Deleted.");
}
}
}
+/*
+ * Converts a raw xHCI port status into the format that external USB 2.0 or USB
+ * 3.0 hubs use.
+ *
+ * Possible side effects:
+ * - Mark a port as being done with device resume,
+ * and ring the endpoint doorbells.
+ * - Stop the Synopsys redriver Compliance Mode polling.
+ */
+static u32 xhci_get_port_status(struct usb_hcd *hcd,
+ struct xhci_bus_state *bus_state,
+ __le32 __iomem **port_array,
+ u16 wIndex, u32 raw_port_status)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ u32 status = 0;
+ int slot_id;
+
+ /* wPortChange bits */
+ if (raw_port_status & PORT_CSC)
+ status |= USB_PORT_STAT_C_CONNECTION << 16;
+ if (raw_port_status & PORT_PEC)
+ status |= USB_PORT_STAT_C_ENABLE << 16;
+ if ((raw_port_status & PORT_OCC))
+ status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+ if ((raw_port_status & PORT_RC))
+ status |= USB_PORT_STAT_C_RESET << 16;
+ /* USB3.0 only */
+ if (hcd->speed == HCD_USB3) {
+ if ((raw_port_status & PORT_PLC))
+ status |= USB_PORT_STAT_C_LINK_STATE << 16;
+ if ((raw_port_status & PORT_WRC))
+ status |= USB_PORT_STAT_C_BH_RESET << 16;
+ }
+
+ if (hcd->speed != HCD_USB3) {
+ if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3
+ && (raw_port_status & PORT_POWER))
+ status |= USB_PORT_STAT_SUSPEND;
+ }
+ if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME &&
+ !DEV_SUPERSPEED(raw_port_status)) {
+ if ((raw_port_status & PORT_RESET) ||
+ !(raw_port_status & PORT_PE))
+ return 0xffffffff;
+ if (time_after_eq(jiffies,
+ bus_state->resume_done[wIndex])) {
+ xhci_dbg(xhci, "Resume USB2 port %d\n",
+ wIndex + 1);
+ bus_state->resume_done[wIndex] = 0;
+ clear_bit(wIndex, &bus_state->resuming_ports);
+ xhci_set_link_state(xhci, port_array, wIndex,
+ XDEV_U0);
+ xhci_dbg(xhci, "set port %d resume\n",
+ wIndex + 1);
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+ wIndex + 1);
+ if (!slot_id) {
+ xhci_dbg(xhci, "slot_id is zero\n");
+ return 0xffffffff;
+ }
+ xhci_ring_device(xhci, slot_id);
+ bus_state->port_c_suspend |= 1 << wIndex;
+ bus_state->suspended_ports &= ~(1 << wIndex);
+ } else {
+ /*
+ * The resume has been signaling for less than
+ * 20ms. Report the port status as SUSPEND,
+ * let the usbcore check port status again
+ * and clear resume signaling later.
+ */
+ status |= USB_PORT_STAT_SUSPEND;
+ }
+ }
+ if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0
+ && (raw_port_status & PORT_POWER)
+ && (bus_state->suspended_ports & (1 << wIndex))) {
+ bus_state->suspended_ports &= ~(1 << wIndex);
+ if (hcd->speed != HCD_USB3)
+ bus_state->port_c_suspend |= 1 << wIndex;
+ }
+ if (raw_port_status & PORT_CONNECT) {
+ status |= USB_PORT_STAT_CONNECTION;
+ status |= xhci_port_speed(raw_port_status);
+ }
+ if (raw_port_status & PORT_PE)
+ status |= USB_PORT_STAT_ENABLE;
+ if (raw_port_status & PORT_OC)
+ status |= USB_PORT_STAT_OVERCURRENT;
+ if (raw_port_status & PORT_RESET)
+ status |= USB_PORT_STAT_RESET;
+ if (raw_port_status & PORT_POWER) {
+ if (hcd->speed == HCD_USB3)
+ status |= USB_SS_PORT_STAT_POWER;
+ else
+ status |= USB_PORT_STAT_POWER;
+ }
+ /* Update Port Link State */
+ if (hcd->speed == HCD_USB3) {
+ xhci_hub_report_usb3_link_state(&status, raw_port_status);
+ /*
+ * Verify if all USB3 Ports Have entered U0 already.
+ * Delete Compliance Mode Timer if so.
+ */
+ xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex);
+ } else {
+ xhci_hub_report_usb2_link_state(&status, raw_port_status);
+ }
+ if (bus_state->port_c_suspend & (1 << wIndex))
+ status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+
+ return status;
+}
+
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
@@ -598,104 +722,20 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if (!wIndex || wIndex > max_ports)
goto error;
wIndex--;
- status = 0;
temp = xhci_readl(xhci, port_array[wIndex]);
if (temp == 0xffffffff) {
retval = -ENODEV;
break;
}
- xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp);
-
- /* wPortChange bits */
- if (temp & PORT_CSC)
- status |= USB_PORT_STAT_C_CONNECTION << 16;
- if (temp & PORT_PEC)
- status |= USB_PORT_STAT_C_ENABLE << 16;
- if ((temp & PORT_OCC))
- status |= USB_PORT_STAT_C_OVERCURRENT << 16;
- if ((temp & PORT_RC))
- status |= USB_PORT_STAT_C_RESET << 16;
- /* USB3.0 only */
- if (hcd->speed == HCD_USB3) {
- if ((temp & PORT_PLC))
- status |= USB_PORT_STAT_C_LINK_STATE << 16;
- if ((temp & PORT_WRC))
- status |= USB_PORT_STAT_C_BH_RESET << 16;
- }
+ status = xhci_get_port_status(hcd, bus_state, port_array,
+ wIndex, temp);
+ if (status == 0xffffffff)
+ goto error;
- if (hcd->speed != HCD_USB3) {
- if ((temp & PORT_PLS_MASK) == XDEV_U3
- && (temp & PORT_POWER))
- status |= USB_PORT_STAT_SUSPEND;
- }
- if ((temp & PORT_PLS_MASK) == XDEV_RESUME &&
- !DEV_SUPERSPEED(temp)) {
- if ((temp & PORT_RESET) || !(temp & PORT_PE))
- goto error;
- if (time_after_eq(jiffies,
- bus_state->resume_done[wIndex])) {
- xhci_dbg(xhci, "Resume USB2 port %d\n",
- wIndex + 1);
- bus_state->resume_done[wIndex] = 0;
- clear_bit(wIndex, &bus_state->resuming_ports);
- xhci_set_link_state(xhci, port_array, wIndex,
- XDEV_U0);
- xhci_dbg(xhci, "set port %d resume\n",
- wIndex + 1);
- slot_id = xhci_find_slot_id_by_port(hcd, xhci,
- wIndex + 1);
- if (!slot_id) {
- xhci_dbg(xhci, "slot_id is zero\n");
- goto error;
- }
- xhci_ring_device(xhci, slot_id);
- bus_state->port_c_suspend |= 1 << wIndex;
- bus_state->suspended_ports &= ~(1 << wIndex);
- } else {
- /*
- * The resume has been signaling for less than
- * 20ms. Report the port status as SUSPEND,
- * let the usbcore check port status again
- * and clear resume signaling later.
- */
- status |= USB_PORT_STAT_SUSPEND;
- }
- }
- if ((temp & PORT_PLS_MASK) == XDEV_U0
- && (temp & PORT_POWER)
- && (bus_state->suspended_ports & (1 << wIndex))) {
- bus_state->suspended_ports &= ~(1 << wIndex);
- if (hcd->speed != HCD_USB3)
- bus_state->port_c_suspend |= 1 << wIndex;
- }
- if (temp & PORT_CONNECT) {
- status |= USB_PORT_STAT_CONNECTION;
- status |= xhci_port_speed(temp);
- }
- if (temp & PORT_PE)
- status |= USB_PORT_STAT_ENABLE;
- if (temp & PORT_OC)
- status |= USB_PORT_STAT_OVERCURRENT;
- if (temp & PORT_RESET)
- status |= USB_PORT_STAT_RESET;
- if (temp & PORT_POWER) {
- if (hcd->speed == HCD_USB3)
- status |= USB_SS_PORT_STAT_POWER;
- else
- status |= USB_PORT_STAT_POWER;
- }
- /* Update Port Link State for super speed ports*/
- if (hcd->speed == HCD_USB3) {
- xhci_hub_report_link_state(&status, temp);
- /*
- * Verify if all USB3 Ports Have entered U0 already.
- * Delete Compliance Mode Timer if so.
- */
- xhci_del_comp_mod_timer(xhci, temp, wIndex);
- }
- if (bus_state->port_c_suspend & (1 << wIndex))
- status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n",
+ wIndex, temp);
xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
+
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
break;
case SetPortFeature:
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index df6978abd7e..53b972c2a09 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -24,8 +24,10 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
#include "xhci.h"
+#include "xhci-trace.h"
/*
* Allocates a generic ring segment from the ring pool, sets the dma address,
@@ -347,7 +349,8 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
return -ENOMEM;
xhci_link_rings(xhci, ring, first, last, num_segs);
- xhci_dbg(xhci, "ring expansion succeed, now has %d segments\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
+ "ring expansion succeed, now has %d segments",
ring->num_segs);
return 0;
@@ -481,17 +484,6 @@ struct xhci_ring *xhci_dma_to_transfer_ring(
return ep->ring;
}
-/* Only use this when you know stream_info is valid */
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-static struct xhci_ring *dma_to_stream_ring(
- struct xhci_stream_info *stream_info,
- u64 address)
-{
- return radix_tree_lookup(&stream_info->trb_address_map,
- address >> TRB_SEGMENT_SHIFT);
-}
-#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */
-
struct xhci_ring *xhci_stream_id_to_ring(
struct xhci_virt_device *dev,
unsigned int ep_index,
@@ -509,58 +501,6 @@ struct xhci_ring *xhci_stream_id_to_ring(
return ep->stream_info->stream_rings[stream_id];
}
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-static int xhci_test_radix_tree(struct xhci_hcd *xhci,
- unsigned int num_streams,
- struct xhci_stream_info *stream_info)
-{
- u32 cur_stream;
- struct xhci_ring *cur_ring;
- u64 addr;
-
- for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
- struct xhci_ring *mapped_ring;
- int trb_size = sizeof(union xhci_trb);
-
- cur_ring = stream_info->stream_rings[cur_stream];
- for (addr = cur_ring->first_seg->dma;
- addr < cur_ring->first_seg->dma + TRB_SEGMENT_SIZE;
- addr += trb_size) {
- mapped_ring = dma_to_stream_ring(stream_info, addr);
- if (cur_ring != mapped_ring) {
- xhci_warn(xhci, "WARN: DMA address 0x%08llx "
- "didn't map to stream ID %u; "
- "mapped to ring %p\n",
- (unsigned long long) addr,
- cur_stream,
- mapped_ring);
- return -EINVAL;
- }
- }
- /* One TRB after the end of the ring segment shouldn't return a
- * pointer to the current ring (although it may be a part of a
- * different ring).
- */
- mapped_ring = dma_to_stream_ring(stream_info, addr);
- if (mapped_ring != cur_ring) {
- /* One TRB before should also fail */
- addr = cur_ring->first_seg->dma - trb_size;
- mapped_ring = dma_to_stream_ring(stream_info, addr);
- }
- if (mapped_ring == cur_ring) {
- xhci_warn(xhci, "WARN: Bad DMA address 0x%08llx "
- "mapped to valid stream ID %u; "
- "mapped ring = %p\n",
- (unsigned long long) addr,
- cur_stream,
- mapped_ring);
- return -EINVAL;
- }
- }
- return 0;
-}
-#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */
-
/*
* Change an endpoint's internal structure so it supports stream IDs. The
* number of requested streams includes stream 0, which cannot be used by device
@@ -687,13 +627,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
* was any other way, the host controller would assume the ring is
* "empty" and wait forever for data to be queued to that stream ID).
*/
-#if XHCI_DEBUG
- /* Do a little test on the radix tree to make sure it returns the
- * correct values.
- */
- if (xhci_test_radix_tree(xhci, num_streams, stream_info))
- goto cleanup_rings;
-#endif
return stream_info;
@@ -731,7 +664,8 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
* fls(0) = 0, fls(0x1) = 1, fls(0x10) = 2, fls(0x100) = 3, etc.
*/
max_primary_streams = fls(stream_info->num_stream_ctxs) - 2;
- xhci_dbg(xhci, "Setting number of stream ctx array entries to %u\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+ "Setting number of stream ctx array entries to %u",
1 << (max_primary_streams + 1));
ep_ctx->ep_info &= cpu_to_le32(~EP_MAXPSTREAMS_MASK);
ep_ctx->ep_info |= cpu_to_le32(EP_MAXPSTREAMS(max_primary_streams)
@@ -1613,7 +1547,8 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
struct device *dev = xhci_to_hcd(xhci)->self.controller;
int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
- xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Allocating %d scratchpad buffers", num_sp);
if (!num_sp)
return 0;
@@ -1770,11 +1705,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
dma_free_coherent(&pdev->dev, size,
xhci->erst.entries, xhci->erst.erst_dma_addr);
xhci->erst.entries = NULL;
- xhci_dbg(xhci, "Freed ERST\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed ERST");
if (xhci->event_ring)
xhci_ring_free(xhci, xhci->event_ring);
xhci->event_ring = NULL;
- xhci_dbg(xhci, "Freed event ring\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
if (xhci->lpm_command)
xhci_free_command(xhci, xhci->lpm_command);
@@ -1782,7 +1717,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL;
- xhci_dbg(xhci, "Freed command ring\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed command ring");
list_for_each_entry_safe(cur_cd, next_cd,
&xhci->cancel_cmd_list, cancel_cmd_list) {
list_del(&cur_cd->cancel_cmd_list);
@@ -1795,22 +1730,24 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
if (xhci->segment_pool)
dma_pool_destroy(xhci->segment_pool);
xhci->segment_pool = NULL;
- xhci_dbg(xhci, "Freed segment pool\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed segment pool");
if (xhci->device_pool)
dma_pool_destroy(xhci->device_pool);
xhci->device_pool = NULL;
- xhci_dbg(xhci, "Freed device context pool\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed device context pool");
if (xhci->small_streams_pool)
dma_pool_destroy(xhci->small_streams_pool);
xhci->small_streams_pool = NULL;
- xhci_dbg(xhci, "Freed small stream array pool\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Freed small stream array pool");
if (xhci->medium_streams_pool)
dma_pool_destroy(xhci->medium_streams_pool);
xhci->medium_streams_pool = NULL;
- xhci_dbg(xhci, "Freed medium stream array pool\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Freed medium stream array pool");
if (xhci->dcbaa)
dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa),
@@ -2036,8 +1973,9 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
* there might be more events to service.
*/
temp &= ~ERST_EHB;
- xhci_dbg(xhci, "// Write event ring dequeue pointer, "
- "preserving EHB bit\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Write event ring dequeue pointer, "
+ "preserving EHB bit");
xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
&xhci->ir_set->erst_dequeue);
}
@@ -2060,8 +1998,9 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
temp = xhci_readl(xhci, addr + 2);
port_offset = XHCI_EXT_PORT_OFF(temp);
port_count = XHCI_EXT_PORT_COUNT(temp);
- xhci_dbg(xhci, "Ext Cap %p, port offset = %u, "
- "count = %u, revision = 0x%x\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Ext Cap %p, port offset = %u, "
+ "count = %u, revision = 0x%x",
addr, port_offset, port_count, major_revision);
/* Port count includes the current port offset */
if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
@@ -2075,15 +2014,18 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
/* Check the host's USB2 LPM capability */
if ((xhci->hci_version == 0x96) && (major_revision != 0x03) &&
(temp & XHCI_L1C)) {
- xhci_dbg(xhci, "xHCI 0.96: support USB2 software lpm\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "xHCI 0.96: support USB2 software lpm");
xhci->sw_lpm_support = 1;
}
if ((xhci->hci_version >= 0x100) && (major_revision != 0x03)) {
- xhci_dbg(xhci, "xHCI 1.0: support USB2 software lpm\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "xHCI 1.0: support USB2 software lpm");
xhci->sw_lpm_support = 1;
if (temp & XHCI_HLC) {
- xhci_dbg(xhci, "xHCI 1.0: support USB2 hardware lpm\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "xHCI 1.0: support USB2 hardware lpm");
xhci->hw_lpm_support = 1;
}
}
@@ -2207,18 +2149,21 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
xhci_warn(xhci, "No ports on the roothubs?\n");
return -ENODEV;
}
- xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Found %u USB 2.0 ports and %u USB 3.0 ports.",
xhci->num_usb2_ports, xhci->num_usb3_ports);
/* Place limits on the number of roothub ports so that the hub
* descriptors aren't longer than the USB core will allocate.
*/
if (xhci->num_usb3_ports > 15) {
- xhci_dbg(xhci, "Limiting USB 3.0 roothub ports to 15.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Limiting USB 3.0 roothub ports to 15.");
xhci->num_usb3_ports = 15;
}
if (xhci->num_usb2_ports > USB_MAXCHILDREN) {
- xhci_dbg(xhci, "Limiting USB 2.0 roothub ports to %u.\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Limiting USB 2.0 roothub ports to %u.",
USB_MAXCHILDREN);
xhci->num_usb2_ports = USB_MAXCHILDREN;
}
@@ -2243,8 +2188,9 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
xhci->usb2_ports[port_index] =
&xhci->op_regs->port_status_base +
NUM_PORT_REGS*i;
- xhci_dbg(xhci, "USB 2.0 port at index %u, "
- "addr = %p\n", i,
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "USB 2.0 port at index %u, "
+ "addr = %p", i,
xhci->usb2_ports[port_index]);
port_index++;
if (port_index == xhci->num_usb2_ports)
@@ -2263,8 +2209,9 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
xhci->usb3_ports[port_index] =
&xhci->op_regs->port_status_base +
NUM_PORT_REGS*i;
- xhci_dbg(xhci, "USB 3.0 port at index %u, "
- "addr = %p\n", i,
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "USB 3.0 port at index %u, "
+ "addr = %p", i,
xhci->usb3_ports[port_index]);
port_index++;
if (port_index == xhci->num_usb3_ports)
@@ -2288,32 +2235,35 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
INIT_LIST_HEAD(&xhci->cancel_cmd_list);
page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
- xhci_dbg(xhci, "Supported page size register = 0x%x\n", page_size);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Supported page size register = 0x%x", page_size);
for (i = 0; i < 16; i++) {
if ((0x1 & page_size) != 0)
break;
page_size = page_size >> 1;
}
if (i < 16)
- xhci_dbg(xhci, "Supported page size of %iK\n", (1 << (i+12)) / 1024);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Supported page size of %iK", (1 << (i+12)) / 1024);
else
xhci_warn(xhci, "WARN: no supported page size\n");
/* Use 4K pages, since that's common and the minimum the HC supports */
xhci->page_shift = 12;
xhci->page_size = 1 << xhci->page_shift;
- xhci_dbg(xhci, "HCD page size set to %iK\n", xhci->page_size / 1024);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "HCD page size set to %iK", xhci->page_size / 1024);
/*
* Program the Number of Device Slots Enabled field in the CONFIG
* register with the max value of slots the HC can handle.
*/
val = HCS_MAX_SLOTS(xhci_readl(xhci, &xhci->cap_regs->hcs_params1));
- xhci_dbg(xhci, "// xHC can handle at most %d device slots.\n",
- (unsigned int) val);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// xHC can handle at most %d device slots.", val);
val2 = xhci_readl(xhci, &xhci->op_regs->config_reg);
val |= (val2 & ~HCS_SLOTS_MASK);
- xhci_dbg(xhci, "// Setting Max device slots reg = 0x%x.\n",
- (unsigned int) val);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Setting Max device slots reg = 0x%x.", val);
xhci_writel(xhci, val, &xhci->op_regs->config_reg);
/*
@@ -2326,7 +2276,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
goto fail;
memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
xhci->dcbaa->dma = dma;
- xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Device context base array address = 0x%llx (DMA), %p (virt)",
(unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr);
@@ -2365,8 +2316,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
if (!xhci->cmd_ring)
goto fail;
- xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
- xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Allocated command ring at %p", xhci->cmd_ring);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%llx",
(unsigned long long)xhci->cmd_ring->first_seg->dma);
/* Set the address in the Command Ring Control register */
@@ -2374,7 +2326,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
(xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
xhci->cmd_ring->cycle_state;
- xhci_dbg(xhci, "// Setting command ring address to 0x%x\n", val);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Setting command ring address to 0x%x", val);
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
xhci_dbg_cmd_ptrs(xhci);
@@ -2390,8 +2343,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
val = xhci_readl(xhci, &xhci->cap_regs->db_off);
val &= DBOFF_MASK;
- xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
- " from cap regs base addr\n", val);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Doorbell array is located at offset 0x%x"
+ " from cap regs base addr", val);
xhci->dba = (void __iomem *) xhci->cap_regs + val;
xhci_dbg_regs(xhci);
xhci_print_run_regs(xhci);
@@ -2402,7 +2356,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
* Event ring setup: Allocate a normal ring, but also setup
* the event ring segment table (ERST). Section 4.9.3.
*/
- xhci_dbg(xhci, "// Allocating event ring\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
flags);
if (!xhci->event_ring)
@@ -2415,13 +2369,15 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
GFP_KERNEL);
if (!xhci->erst.entries)
goto fail;
- xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Allocated event ring segment table at 0x%llx",
(unsigned long long)dma);
memset(xhci->erst.entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS);
xhci->erst.num_entries = ERST_NUM_SEGS;
xhci->erst.erst_dma_addr = dma;
- xhci_dbg(xhci, "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx",
xhci->erst.num_entries,
xhci->erst.entries,
(unsigned long long)xhci->erst.erst_dma_addr);
@@ -2439,13 +2395,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
val = xhci_readl(xhci, &xhci->ir_set->erst_size);
val &= ERST_SIZE_MASK;
val |= ERST_NUM_SEGS;
- xhci_dbg(xhci, "// Write ERST size = %i to ir_set 0 (some bits preserved)\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Write ERST size = %i to ir_set 0 (some bits preserved)",
val);
xhci_writel(xhci, val, &xhci->ir_set->erst_size);
- xhci_dbg(xhci, "// Set ERST entries to point to event ring.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Set ERST entries to point to event ring.");
/* set the segment table base address */
- xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Set ERST base address for ir_set 0 = 0x%llx",
(unsigned long long)xhci->erst.erst_dma_addr);
val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
val_64 &= ERST_PTR_MASK;
@@ -2454,7 +2413,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
/* Set the event ring dequeue address */
xhci_set_hc_event_deq(xhci);
- xhci_dbg(xhci, "Wrote ERST address to ir_set 0.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Wrote ERST address to ir_set 0.");
xhci_print_ir_set(xhci, 0);
/*
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index cc24e39b97d..c2d495057eb 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include "xhci.h"
+#include "xhci-trace.h"
/* Device for a quirk */
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
@@ -64,16 +65,18 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
pdev->revision == 0x0) {
xhci->quirks |= XHCI_RESET_EP_QUIRK;
- xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
- " endpoint cmd after reset endpoint\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "QUIRK: Fresco Logic xHC needs configure"
+ " endpoint cmd after reset endpoint");
}
/* Fresco Logic confirms: all revisions of this chip do not
* support MSI, even though some of them claim to in their PCI
* capabilities.
*/
xhci->quirks |= XHCI_BROKEN_MSI;
- xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
- "has broken MSI implementation\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "QUIRK: Fresco Logic revision %u "
+ "has broken MSI implementation",
pdev->revision);
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
}
@@ -93,7 +96,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
- xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
xhci->limit_active_eps = 64;
xhci->quirks |= XHCI_SW_BW_CHECKING;
@@ -111,7 +113,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
xhci->quirks |= XHCI_RESET_ON_RESUME;
- xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "QUIRK: Resetting on resume");
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
}
if (pdev->vendor == PCI_VENDOR_ID_VIA)
@@ -250,13 +253,15 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
* writers.
*
* Unconditionally switch the ports back to xHCI after a system resume.
- * We can't tell whether the EHCI or xHCI controller will be resumed
- * first, so we have to do the port switchover in both drivers. Writing
- * a '1' to the port switchover registers should have no effect if the
- * port was already switched over.
+ * It should not matter whether the EHCI or xHCI controller is
+ * resumed first. It's enough to do the switchover in xHCI because
+ * USB core won't notice anything as the hub driver doesn't start
+ * running again until after all the devices (including both EHCI and
+ * xHCI host controllers) have been resumed.
*/
- if (usb_is_intel_switchable_xhci(pdev))
- usb_enable_xhci_ports(pdev);
+
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+ usb_enable_intel_xhci_ports(pdev);
retval = xhci_resume(xhci, hibernated);
return retval;
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 51e22bf8950..d9c169f470d 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -14,6 +14,8 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
#include "xhci.h"
@@ -24,7 +26,7 @@ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
* here that the generic code does not try to make a pci_dev from our
* dev struct in order to setup MSI
*/
- xhci->quirks |= XHCI_BROKEN_MSI;
+ xhci->quirks |= XHCI_PLAT;
}
/* called during probe() after chip reset completes */
@@ -104,6 +106,15 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (!res)
return -ENODEV;
+ /* Initialize dma_mask and coherent_dma_mask to 32-bits */
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ else
+ dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd)
return -ENOMEM;
@@ -186,11 +197,46 @@ static int xhci_plat_remove(struct platform_device *dev)
return 0;
}
+#ifdef CONFIG_PM
+static int xhci_plat_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ return xhci_suspend(xhci);
+}
+
+static int xhci_plat_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ return xhci_resume(xhci, 0);
+}
+
+static const struct dev_pm_ops xhci_plat_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
+};
+#define DEV_PM_OPS (&xhci_plat_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_OF
+static const struct of_device_id usb_xhci_of_match[] = {
+ { .compatible = "xhci-platform" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
+#endif
+
static struct platform_driver usb_xhci_driver = {
.probe = xhci_plat_probe,
.remove = xhci_plat_remove,
.driver = {
.name = "xhci-hcd",
+ .pm = DEV_PM_OPS,
+ .of_match_table = of_match_ptr(usb_xhci_of_match),
},
};
MODULE_ALIAS("platform:xhci-hcd");
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 1e57eafa691..411da1fc7ae 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -67,6 +67,7 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include "xhci.h"
+#include "xhci-trace.h"
static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
@@ -434,7 +435,7 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
/* A ring has pending URBs if its TD list is not empty */
if (!(ep->ep_state & EP_HAS_STREAMS)) {
- if (!(list_empty(&ep->ring->td_list)))
+ if (ep->ring && !(list_empty(&ep->ring->td_list)))
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, 0);
return;
}
@@ -555,7 +556,8 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
return;
}
state->new_cycle_state = 0;
- xhci_dbg(xhci, "Finding segment containing stopped TRB.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Finding segment containing stopped TRB.");
state->new_deq_seg = find_trb_seg(cur_td->start_seg,
dev->eps[ep_index].stopped_trb,
&state->new_cycle_state);
@@ -565,12 +567,14 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
}
/* Dig out the cycle state saved by the xHC during the stop ep cmd */
- xhci_dbg(xhci, "Finding endpoint context\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Finding endpoint context");
ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
state->new_cycle_state = 0x1 & le64_to_cpu(ep_ctx->deq);
state->new_deq_ptr = cur_td->last_trb;
- xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Finding segment containing last TRB in TD.");
state->new_deq_seg = find_trb_seg(state->new_deq_seg,
state->new_deq_ptr,
&state->new_cycle_state);
@@ -597,13 +601,16 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
if (ep_ring->first_seg == ep_ring->first_seg->next &&
state->new_deq_ptr < dev->eps[ep_index].stopped_trb)
state->new_cycle_state ^= 0x1;
- xhci_dbg(xhci, "Cycle state = 0x%x\n", state->new_cycle_state);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Cycle state = 0x%x", state->new_cycle_state);
/* Don't update the ring cycle state for the producer (us). */
- xhci_dbg(xhci, "New dequeue segment = %p (virtual)\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "New dequeue segment = %p (virtual)",
state->new_deq_seg);
addr = xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr);
- xhci_dbg(xhci, "New dequeue pointer = 0x%llx (DMA)\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "New dequeue pointer = 0x%llx (DMA)",
(unsigned long long) addr);
}
@@ -631,9 +638,11 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
if (flip_cycle)
cur_trb->generic.field[3] ^=
cpu_to_le32(TRB_CYCLE);
- xhci_dbg(xhci, "Cancel (unchain) link TRB\n");
- xhci_dbg(xhci, "Address = %p (0x%llx dma); "
- "in seg %p (0x%llx dma)\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Cancel (unchain) link TRB");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Address = %p (0x%llx dma); "
+ "in seg %p (0x%llx dma)",
cur_trb,
(unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb),
cur_seg,
@@ -651,7 +660,8 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
cpu_to_le32(TRB_CYCLE);
cur_trb->generic.field[3] |= cpu_to_le32(
TRB_TYPE(TRB_TR_NOOP));
- xhci_dbg(xhci, "TRB to noop at offset 0x%llx\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "TRB to noop at offset 0x%llx",
(unsigned long long)
xhci_trb_virt_to_dma(cur_seg, cur_trb));
}
@@ -672,8 +682,9 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
{
struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
- xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
- "new deq ptr = %p (0x%llx dma), new cycle = %u\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
+ "new deq ptr = %p (0x%llx dma), new cycle = %u",
deq_state->new_deq_seg,
(unsigned long long)deq_state->new_deq_seg->dma,
deq_state->new_deq_ptr,
@@ -793,7 +804,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
*/
list_for_each(entry, &ep->cancelled_td_list) {
cur_td = list_entry(entry, struct xhci_td, cancelled_td_list);
- xhci_dbg(xhci, "Removing canceled TD starting at 0x%llx (dma).\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Removing canceled TD starting at 0x%llx (dma).",
(unsigned long long)xhci_trb_virt_to_dma(
cur_td->start_seg, cur_td->first_trb));
ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb);
@@ -913,14 +925,16 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
ep->stop_cmds_pending--;
if (xhci->xhc_state & XHCI_STATE_DYING) {
- xhci_dbg(xhci, "Stop EP timer ran, but another timer marked "
- "xHCI as DYING, exiting.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Stop EP timer ran, but another timer marked "
+ "xHCI as DYING, exiting.");
spin_unlock_irqrestore(&xhci->lock, flags);
return;
}
if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) {
- xhci_dbg(xhci, "Stop EP timer ran, but no command pending, "
- "exiting.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Stop EP timer ran, but no command pending, "
+ "exiting.");
spin_unlock_irqrestore(&xhci->lock, flags);
return;
}
@@ -962,8 +976,9 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
ring = temp_ep->ring;
if (!ring)
continue;
- xhci_dbg(xhci, "Killing URBs for slot ID %u, "
- "ep index %u\n", i, j);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Killing URBs for slot ID %u, "
+ "ep index %u", i, j);
while (!list_empty(&ring->td_list)) {
cur_td = list_first_entry(&ring->td_list,
struct xhci_td,
@@ -986,9 +1001,11 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
}
}
spin_unlock_irqrestore(&xhci->lock, flags);
- xhci_dbg(xhci, "Calling usb_hc_died()\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Calling usb_hc_died()");
usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
- xhci_dbg(xhci, "xHCI host controller is dead.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "xHCI host controller is dead.");
}
@@ -1092,7 +1109,8 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
ep_state &= EP_STATE_MASK;
slot_state = le32_to_cpu(slot_ctx->dev_state);
slot_state = GET_SLOT_STATE(slot_state);
- xhci_dbg(xhci, "Slot state = %u, EP state = %u\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Slot state = %u, EP state = %u",
slot_state, ep_state);
break;
case COMP_EBADSLT:
@@ -1112,7 +1130,8 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
* cancelling URBs, which might not be an error...
*/
} else {
- xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Successful Set TR Deq Ptr cmd, deq = @%08llx",
le64_to_cpu(ep_ctx->deq));
if (xhci_trb_virt_to_dma(dev->eps[ep_index].queued_deq_seg,
dev->eps[ep_index].queued_deq_ptr) ==
@@ -1150,7 +1169,8 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
/* This command will only fail if the endpoint wasn't halted,
* but we don't care.
*/
- xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+ "Ignoring reset ep completion code of %u",
GET_COMP_CODE(le32_to_cpu(event->status)));
/* HW with the reset endpoint quirk needs to have a configure endpoint
@@ -1158,7 +1178,8 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
* because the HW can't handle two commands being queued in a row.
*/
if (xhci->quirks & XHCI_RESET_EP_QUIRK) {
- xhci_dbg(xhci, "Queueing configure endpoint command\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Queueing configure endpoint command");
xhci_queue_configure_endpoint(xhci,
xhci->devs[slot_id]->in_ctx->dma, slot_id,
false);
@@ -1377,6 +1398,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
return;
}
+ trace_xhci_cmd_completion(&xhci->cmd_ring->dequeue->generic,
+ (struct xhci_generic_trb *) event);
+
if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) ||
(GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) {
/* If the return value is 0, we think the trb pointed by
@@ -1444,8 +1468,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state;
if (!(ep_state & EP_HALTED))
goto bandwidth_change;
- xhci_dbg(xhci, "Completed config ep cmd - "
- "last ep index = %d, state = %d\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Completed config ep cmd - "
+ "last ep index = %d, state = %d",
ep_index, ep_state);
/* Clear internal halted state and restart ring(s) */
xhci->devs[slot_id]->eps[ep_index].ep_state &=
@@ -1454,7 +1479,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
break;
}
bandwidth_change:
- xhci_dbg(xhci, "Completed config ep cmd\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+ "Completed config ep cmd");
xhci->devs[slot_id]->cmd_status =
GET_COMP_CODE(le32_to_cpu(event->status));
complete(&xhci->devs[slot_id]->cmd_completion);
@@ -1497,7 +1523,8 @@ bandwidth_change:
xhci->error_bitmask |= 1 << 6;
break;
}
- xhci_dbg(xhci, "NEC firmware version %2x.%02x\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "NEC firmware version %2x.%02x",
NEC_FW_MAJOR(le32_to_cpu(event->status)),
NEC_FW_MINOR(le32_to_cpu(event->status)));
break;
@@ -2877,8 +2904,8 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
return -ENOMEM;
}
- xhci_dbg(xhci, "ERROR no room on ep ring, "
- "try ring expansion\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
+ "ERROR no room on ep ring, try ring expansion");
num_trbs_needed = num_trbs - ep_ring->num_trbs_free;
if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed,
mem_flags)) {
@@ -3060,14 +3087,10 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
* to set the polling interval (once the API is added).
*/
if (xhci_interval != ep_interval) {
- if (printk_ratelimit())
- dev_dbg(&urb->dev->dev, "Driver uses different interval"
- " (%d microframe%s) than xHCI "
- "(%d microframe%s)\n",
- ep_interval,
- ep_interval == 1 ? "" : "s",
- xhci_interval,
- xhci_interval == 1 ? "" : "s");
+ dev_dbg_ratelimited(&urb->dev->dev,
+ "Driver uses different interval (%d microframe%s) than xHCI (%d microframe%s)\n",
+ ep_interval, ep_interval == 1 ? "" : "s",
+ xhci_interval, xhci_interval == 1 ? "" : "s");
urb->interval = xhci_interval;
/* Convert back to frames for LS/FS devices */
if (urb->dev->speed == USB_SPEED_LOW ||
@@ -3849,14 +3872,10 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
* to set the polling interval (once the API is added).
*/
if (xhci_interval != ep_interval) {
- if (printk_ratelimit())
- dev_dbg(&urb->dev->dev, "Driver uses different interval"
- " (%d microframe%s) than xHCI "
- "(%d microframe%s)\n",
- ep_interval,
- ep_interval == 1 ? "" : "s",
- xhci_interval,
- xhci_interval == 1 ? "" : "s");
+ dev_dbg_ratelimited(&urb->dev->dev,
+ "Driver uses different interval (%d microframe%s) than xHCI (%d microframe%s)\n",
+ ep_interval, ep_interval == 1 ? "" : "s",
+ xhci_interval, xhci_interval == 1 ? "" : "s");
urb->interval = xhci_interval;
/* Convert back to frames for LS/FS devices */
if (urb->dev->speed == USB_SPEED_LOW ||
diff --git a/drivers/usb/host/xhci-trace.c b/drivers/usb/host/xhci-trace.c
new file mode 100644
index 00000000000..7cf30c83dcf
--- /dev/null
+++ b/drivers/usb/host/xhci-trace.c
@@ -0,0 +1,15 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2013 Xenia Ragiadakou
+ *
+ * Author: Xenia Ragiadakou
+ * Email : burzalodowa@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define CREATE_TRACE_POINTS
+#include "xhci-trace.h"
diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h
new file mode 100644
index 00000000000..20364cc8d2f
--- /dev/null
+++ b/drivers/usb/host/xhci-trace.h
@@ -0,0 +1,151 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2013 Xenia Ragiadakou
+ *
+ * Author: Xenia Ragiadakou
+ * Email : burzalodowa@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM xhci-hcd
+
+#if !defined(__XHCI_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __XHCI_TRACE_H
+
+#include <linux/tracepoint.h>
+#include "xhci.h"
+
+#define XHCI_MSG_MAX 500
+
+DECLARE_EVENT_CLASS(xhci_log_msg,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf),
+ TP_STRUCT__entry(__dynamic_array(char, msg, XHCI_MSG_MAX)),
+ TP_fast_assign(
+ vsnprintf(__get_str(msg), XHCI_MSG_MAX, vaf->fmt, *vaf->va);
+ ),
+ TP_printk("%s", __get_str(msg))
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_address,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_context_change,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_quirks,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_reset_ep,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_cancel_urb,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_init,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_ring_expansion,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DECLARE_EVENT_CLASS(xhci_log_ctx,
+ TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
+ unsigned int ep_num),
+ TP_ARGS(xhci, ctx, ep_num),
+ TP_STRUCT__entry(
+ __field(int, ctx_64)
+ __field(unsigned, ctx_type)
+ __field(dma_addr_t, ctx_dma)
+ __field(u8 *, ctx_va)
+ __field(unsigned, ctx_ep_num)
+ __field(int, slot_id)
+ __dynamic_array(u32, ctx_data,
+ ((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 8) *
+ ((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1))
+ ),
+ TP_fast_assign(
+ struct usb_device *udev;
+
+ udev = to_usb_device(xhci_to_hcd(xhci)->self.controller);
+ __entry->ctx_64 = HCC_64BYTE_CONTEXT(xhci->hcc_params);
+ __entry->ctx_type = ctx->type;
+ __entry->ctx_dma = ctx->dma;
+ __entry->ctx_va = ctx->bytes;
+ __entry->slot_id = udev->slot_id;
+ __entry->ctx_ep_num = ep_num;
+ memcpy(__get_dynamic_array(ctx_data), ctx->bytes,
+ ((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 32) *
+ ((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1));
+ ),
+ TP_printk("\nctx_64=%d, ctx_type=%u, ctx_dma=@%llx, ctx_va=@%p",
+ __entry->ctx_64, __entry->ctx_type,
+ (unsigned long long) __entry->ctx_dma, __entry->ctx_va
+ )
+);
+
+DEFINE_EVENT(xhci_log_ctx, xhci_address_ctx,
+ TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
+ unsigned int ep_num),
+ TP_ARGS(xhci, ctx, ep_num)
+);
+
+DECLARE_EVENT_CLASS(xhci_log_event,
+ TP_PROTO(void *trb_va, struct xhci_generic_trb *ev),
+ TP_ARGS(trb_va, ev),
+ TP_STRUCT__entry(
+ __field(void *, va)
+ __field(u64, dma)
+ __field(u32, status)
+ __field(u32, flags)
+ __dynamic_array(__le32, trb, 4)
+ ),
+ TP_fast_assign(
+ __entry->va = trb_va;
+ __entry->dma = le64_to_cpu(((u64)ev->field[1]) << 32 |
+ ev->field[0]);
+ __entry->status = le32_to_cpu(ev->field[2]);
+ __entry->flags = le32_to_cpu(ev->field[3]);
+ memcpy(__get_dynamic_array(trb), trb_va,
+ sizeof(struct xhci_generic_trb));
+ ),
+ TP_printk("\ntrb_dma=@%llx, trb_va=@%p, status=%08x, flags=%08x",
+ (unsigned long long) __entry->dma, __entry->va,
+ __entry->status, __entry->flags
+ )
+);
+
+DEFINE_EVENT(xhci_log_event, xhci_cmd_completion,
+ TP_PROTO(void *trb_va, struct xhci_generic_trb *ev),
+ TP_ARGS(trb_va, ev)
+);
+
+#endif /* __XHCI_TRACE_H */
+
+/* this part must be outside header guard */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE xhci-trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 2c49f00260c..49b6edb84a7 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -27,8 +27,10 @@
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/dmi.h>
+#include <linux/dma-mapping.h>
#include "xhci.h"
+#include "xhci-trace.h"
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
@@ -100,7 +102,7 @@ void xhci_quiesce(struct xhci_hcd *xhci)
int xhci_halt(struct xhci_hcd *xhci)
{
int ret;
- xhci_dbg(xhci, "// Halt the HC\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Halt the HC");
xhci_quiesce(xhci);
ret = xhci_handshake(xhci, &xhci->op_regs->status,
@@ -124,7 +126,7 @@ static int xhci_start(struct xhci_hcd *xhci)
temp = xhci_readl(xhci, &xhci->op_regs->command);
temp |= (CMD_RUN);
- xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.",
temp);
xhci_writel(xhci, temp, &xhci->op_regs->command);
@@ -162,7 +164,7 @@ int xhci_reset(struct xhci_hcd *xhci)
return 0;
}
- xhci_dbg(xhci, "// Reset the HC\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Reset the HC");
command = xhci_readl(xhci, &xhci->op_regs->command);
command |= CMD_RESET;
xhci_writel(xhci, command, &xhci->op_regs->command);
@@ -172,7 +174,8 @@ int xhci_reset(struct xhci_hcd *xhci)
if (ret)
return ret;
- xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Wait for controller to be ready for doorbell rings");
/*
* xHCI cannot write to any doorbells or operational registers other
* than status until the "Controller Not Ready" flag is cleared.
@@ -214,14 +217,16 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
ret = pci_enable_msi(pdev);
if (ret) {
- xhci_dbg(xhci, "failed to allocate MSI entry\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "failed to allocate MSI entry");
return ret;
}
ret = request_irq(pdev->irq, xhci_msi_irq,
0, "xhci_hcd", xhci_to_hcd(xhci));
if (ret) {
- xhci_dbg(xhci, "disable MSI interrupt\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "disable MSI interrupt");
pci_disable_msi(pdev);
}
@@ -284,7 +289,8 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);
if (ret) {
- xhci_dbg(xhci, "Failed to enable MSI-X\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Failed to enable MSI-X");
goto free_entries;
}
@@ -300,7 +306,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
return ret;
disable_msix:
- xhci_dbg(xhci, "disable MSI-X interrupt\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt");
xhci_free_irq(xhci);
pci_disable_msix(pdev);
free_entries:
@@ -329,7 +335,7 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)
return;
}
-static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci)
{
int i;
@@ -342,9 +348,14 @@ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
static int xhci_try_enable_msi(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+ struct pci_dev *pdev;
int ret;
+ /* The xhci platform device has set up IRQs through usb_add_hcd. */
+ if (xhci->quirks & XHCI_PLAT)
+ return 0;
+
+ pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
/*
* Some Fresco Logic host controllers advertise MSI, but fail to
* generate interrupts. Don't even try to enable MSI.
@@ -417,9 +428,11 @@ static void compliance_mode_recovery(unsigned long arg)
* Compliance Mode Detected. Letting USB Core
* handle the Warm Reset
*/
- xhci_dbg(xhci, "Compliance mode detected->port %d\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Compliance mode detected->port %d",
i + 1);
- xhci_dbg(xhci, "Attempting compliance mode recovery\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Attempting compliance mode recovery");
hcd = xhci->shared_hcd;
if (hcd->state == HC_STATE_SUSPENDED)
@@ -457,7 +470,8 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci)
set_timer_slack(&xhci->comp_mode_recovery_timer,
msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
add_timer(&xhci->comp_mode_recovery_timer);
- xhci_dbg(xhci, "Compliance mode recovery timer initialized\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Compliance mode recovery timer initialized");
}
/*
@@ -505,16 +519,18 @@ int xhci_init(struct usb_hcd *hcd)
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int retval = 0;
- xhci_dbg(xhci, "xhci_init\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_init");
spin_lock_init(&xhci->lock);
if (xhci->hci_version == 0x95 && link_quirk) {
- xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "QUIRK: Not clearing Link TRB chain bits.");
xhci->quirks |= XHCI_LINK_TRB_QUIRK;
} else {
- xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "xHCI doesn't need link TRB QUIRK");
}
retval = xhci_mem_init(xhci, GFP_KERNEL);
- xhci_dbg(xhci, "Finished xhci_init\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_init");
/* Initializing Compliance Mode Recovery Data If Needed */
if (xhci_compliance_mode_recovery_timer_quirk_check()) {
@@ -528,57 +544,6 @@ int xhci_init(struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-static void xhci_event_ring_work(unsigned long arg)
-{
- unsigned long flags;
- int temp;
- u64 temp_64;
- struct xhci_hcd *xhci = (struct xhci_hcd *) arg;
- int i, j;
-
- xhci_dbg(xhci, "Poll event ring: %lu\n", jiffies);
-
- spin_lock_irqsave(&xhci->lock, flags);
- temp = xhci_readl(xhci, &xhci->op_regs->status);
- xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
- if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
- (xhci->xhc_state & XHCI_STATE_HALTED)) {
- xhci_dbg(xhci, "HW died, polling stopped.\n");
- spin_unlock_irqrestore(&xhci->lock, flags);
- return;
- }
-
- temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
- xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp);
- xhci_dbg(xhci, "HC error bitmask = 0x%x\n", xhci->error_bitmask);
- xhci->error_bitmask = 0;
- xhci_dbg(xhci, "Event ring:\n");
- xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
- xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
- temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
- temp_64 &= ~ERST_PTR_MASK;
- xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);
- xhci_dbg(xhci, "Command ring:\n");
- xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg);
- xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
- xhci_dbg_cmd_ptrs(xhci);
- for (i = 0; i < MAX_HC_SLOTS; ++i) {
- if (!xhci->devs[i])
- continue;
- for (j = 0; j < 31; ++j) {
- xhci_dbg_ep_rings(xhci, i, j, &xhci->devs[i]->eps[j]);
- }
- }
- spin_unlock_irqrestore(&xhci->lock, flags);
-
- if (!xhci->zombie)
- mod_timer(&xhci->event_ring_timer, jiffies + POLL_TIMEOUT * HZ);
- else
- xhci_dbg(xhci, "Quit polling the event ring.\n");
-}
-#endif
-
static int xhci_run_finished(struct xhci_hcd *xhci)
{
if (xhci_start(xhci)) {
@@ -591,7 +556,8 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
if (xhci->quirks & XHCI_NEC_HOST)
xhci_ring_cmd_db(xhci);
- xhci_dbg(xhci, "Finished xhci_run for USB3 roothub\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Finished xhci_run for USB3 roothub");
return 0;
}
@@ -622,23 +588,12 @@ int xhci_run(struct usb_hcd *hcd)
if (!usb_hcd_is_primary_hcd(hcd))
return xhci_run_finished(xhci);
- xhci_dbg(xhci, "xhci_run\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run");
ret = xhci_try_enable_msi(hcd);
if (ret)
return ret;
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
- init_timer(&xhci->event_ring_timer);
- xhci->event_ring_timer.data = (unsigned long) xhci;
- xhci->event_ring_timer.function = xhci_event_ring_work;
- /* Poll the event ring */
- xhci->event_ring_timer.expires = jiffies + POLL_TIMEOUT * HZ;
- xhci->zombie = 0;
- xhci_dbg(xhci, "Setting event ring polling timer\n");
- add_timer(&xhci->event_ring_timer);
-#endif
-
xhci_dbg(xhci, "Command ring memory map follows:\n");
xhci_debug_ring(xhci, xhci->cmd_ring);
xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
@@ -651,9 +606,11 @@ int xhci_run(struct usb_hcd *hcd)
xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
temp_64 &= ~ERST_PTR_MASK;
- xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "ERST deq = 64'h%0lx", (long unsigned int) temp_64);
- xhci_dbg(xhci, "// Set the interrupt modulation register\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Set the interrupt modulation register");
temp = xhci_readl(xhci, &xhci->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
temp |= (u32) 160;
@@ -662,12 +619,13 @@ int xhci_run(struct usb_hcd *hcd)
/* Set the HCD state before we enable the irqs */
temp = xhci_readl(xhci, &xhci->op_regs->command);
temp |= (CMD_EIE);
- xhci_dbg(xhci, "// Enable interrupts, cmd = 0x%x.\n",
- temp);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Enable interrupts, cmd = 0x%x.", temp);
xhci_writel(xhci, temp, &xhci->op_regs->command);
temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
- xhci_dbg(xhci, "// Enabling event ring interrupter %p by writing 0x%x to irq_pending\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Enabling event ring interrupter %p by writing 0x%x to irq_pending",
xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp));
xhci_writel(xhci, ER_IRQ_ENABLE(temp),
&xhci->ir_set->irq_pending);
@@ -677,7 +635,8 @@ int xhci_run(struct usb_hcd *hcd)
xhci_queue_vendor_command(xhci, 0, 0, 0,
TRB_TYPE(TRB_NEC_GET_FW));
- xhci_dbg(xhci, "Finished xhci_run for USB2 roothub\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Finished xhci_run for USB2 roothub");
return 0;
}
@@ -725,24 +684,20 @@ void xhci_stop(struct usb_hcd *hcd)
xhci_cleanup_msix(xhci);
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
- /* Tell the event ring poll function not to reschedule */
- xhci->zombie = 1;
- del_timer_sync(&xhci->event_ring_timer);
-#endif
-
/* Deleting Compliance Mode Recovery Timer */
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
(!(xhci_all_ports_seen_u0(xhci)))) {
del_timer_sync(&xhci->comp_mode_recovery_timer);
- xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "%s: compliance mode recovery timer deleted",
__func__);
}
if (xhci->quirks & XHCI_AMD_PLL_FIX)
usb_amd_dev_put();
- xhci_dbg(xhci, "// Disabling event ring interrupts\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Disabling event ring interrupts");
temp = xhci_readl(xhci, &xhci->op_regs->status);
xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
@@ -750,10 +705,11 @@ void xhci_stop(struct usb_hcd *hcd)
&xhci->ir_set->irq_pending);
xhci_print_ir_set(xhci, 0);
- xhci_dbg(xhci, "cleaning up memory\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
xhci_mem_cleanup(xhci);
- xhci_dbg(xhci, "xhci_stop completed - status = %x\n",
- xhci_readl(xhci, &xhci->op_regs->status));
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "xhci_stop completed - status = %x",
+ xhci_readl(xhci, &xhci->op_regs->status));
}
/*
@@ -778,8 +734,9 @@ void xhci_shutdown(struct usb_hcd *hcd)
xhci_cleanup_msix(xhci);
- xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n",
- xhci_readl(xhci, &xhci->op_regs->status));
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "xhci_shutdown completed - status = %x",
+ xhci_readl(xhci, &xhci->op_regs->status));
}
#ifdef CONFIG_PM
@@ -820,7 +777,8 @@ static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
xhci->cmd_ring->dequeue) &
(u64) ~CMD_RING_RSVD_BITS) |
xhci->cmd_ring->cycle_state;
- xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "// Setting command ring address to 0x%llx",
(long unsigned long) val_64);
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
}
@@ -933,7 +891,8 @@ int xhci_suspend(struct xhci_hcd *xhci)
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
(!(xhci_all_ports_seen_u0(xhci)))) {
del_timer_sync(&xhci->comp_mode_recovery_timer);
- xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "%s: compliance mode recovery timer deleted",
__func__);
}
@@ -998,7 +957,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
!(xhci_all_ports_seen_u0(xhci))) {
del_timer_sync(&xhci->comp_mode_recovery_timer);
- xhci_dbg(xhci, "Compliance Mode Recovery Timer deleted!\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Compliance Mode Recovery Timer deleted!");
}
/* Let the USB core know _both_ roothubs lost power. */
@@ -1011,12 +971,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
spin_unlock_irq(&xhci->lock);
xhci_cleanup_msix(xhci);
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
- /* Tell the event ring poll function not to reschedule */
- xhci->zombie = 1;
- del_timer_sync(&xhci->event_ring_timer);
-#endif
-
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
temp = xhci_readl(xhci, &xhci->op_regs->status);
xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
@@ -1170,35 +1124,33 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
struct xhci_virt_device *virt_dev;
if (!hcd || (check_ep && !ep) || !udev) {
- printk(KERN_DEBUG "xHCI %s called with invalid args\n",
- func);
+ pr_debug("xHCI %s called with invalid args\n", func);
return -EINVAL;
}
if (!udev->parent) {
- printk(KERN_DEBUG "xHCI %s called for root hub\n",
- func);
+ pr_debug("xHCI %s called for root hub\n", func);
return 0;
}
xhci = hcd_to_xhci(hcd);
- if (xhci->xhc_state & XHCI_STATE_HALTED)
- return -ENODEV;
-
if (check_virt_dev) {
if (!udev->slot_id || !xhci->devs[udev->slot_id]) {
- printk(KERN_DEBUG "xHCI %s called with unaddressed "
- "device\n", func);
+ xhci_dbg(xhci, "xHCI %s called with unaddressed device\n",
+ func);
return -EINVAL;
}
virt_dev = xhci->devs[udev->slot_id];
if (virt_dev->udev != udev) {
- printk(KERN_DEBUG "xHCI %s called with udev and "
+ xhci_dbg(xhci, "xHCI %s called with udev and "
"virt_dev does not match\n", func);
return -EINVAL;
}
}
+ if (xhci->xhc_state & XHCI_STATE_HALTED)
+ return -ENODEV;
+
return 1;
}
@@ -1228,12 +1180,16 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc);
if (hw_max_packet_size != max_packet_size) {
- xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
- xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+ "Max Packet Size for ep 0 changed.");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+ "Max packet size in usb_device = %d",
max_packet_size);
- xhci_dbg(xhci, "Max packet size in xHCI HW = %d\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+ "Max packet size in xHCI HW = %d",
hw_max_packet_size);
- xhci_dbg(xhci, "Issuing evaluate context command.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+ "Issuing evaluate context command.");
/* Set up the input context flags for the command */
/* FIXME: This won't work if a non-default control endpoint
@@ -1498,7 +1454,8 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
goto done;
temp = xhci_readl(xhci, &xhci->op_regs->status);
if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
- xhci_dbg(xhci, "HW died, freeing TD.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "HW died, freeing TD.");
urb_priv = urb->hcpriv;
for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
td = urb_priv->td[i];
@@ -1516,8 +1473,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
}
if ((xhci->xhc_state & XHCI_STATE_DYING) ||
(xhci->xhc_state & XHCI_STATE_HALTED)) {
- xhci_dbg(xhci, "Ep 0x%x: URB %p to be canceled on "
- "non-responsive xHCI host.\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Ep 0x%x: URB %p to be canceled on "
+ "non-responsive xHCI host.",
urb->ep->desc.bEndpointAddress, urb);
/* Let the stop endpoint command watchdog timer (which set this
* state) finish cleaning up the endpoint TD lists. We must
@@ -1538,8 +1496,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
urb_priv = urb->hcpriv;
i = urb_priv->td_cnt;
if (i < urb_priv->length)
- xhci_dbg(xhci, "Cancel URB %p, dev %s, ep 0x%x, "
- "starting at offset 0x%llx\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+ "Cancel URB %p, dev %s, ep 0x%x, "
+ "starting at offset 0x%llx",
urb, urb->dev->devpath,
urb->ep->desc.bEndpointAddress,
(unsigned long long) xhci_trb_virt_to_dma(
@@ -1851,7 +1810,8 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
ret = -ENODEV;
break;
case COMP_SUCCESS:
- dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+ "Successful Endpoint Configure command");
ret = 0;
break;
default:
@@ -1897,7 +1857,8 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
ret = -EINVAL;
break;
case COMP_SUCCESS:
- dev_dbg(&udev->dev, "Successful evaluate context command\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+ "Successful evaluate context command");
ret = 0;
break;
default:
@@ -1963,14 +1924,16 @@ static int xhci_reserve_host_resources(struct xhci_hcd *xhci,
added_eps = xhci_count_num_new_endpoints(xhci, ctrl_ctx);
if (xhci->num_active_eps + added_eps > xhci->limit_active_eps) {
- xhci_dbg(xhci, "Not enough ep ctxs: "
- "%u active, need to add %u, limit is %u.\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Not enough ep ctxs: "
+ "%u active, need to add %u, limit is %u.",
xhci->num_active_eps, added_eps,
xhci->limit_active_eps);
return -ENOMEM;
}
xhci->num_active_eps += added_eps;
- xhci_dbg(xhci, "Adding %u ep ctxs, %u now active.\n", added_eps,
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Adding %u ep ctxs, %u now active.", added_eps,
xhci->num_active_eps);
return 0;
}
@@ -1988,7 +1951,8 @@ static void xhci_free_host_resources(struct xhci_hcd *xhci,
num_failed_eps = xhci_count_num_new_endpoints(xhci, ctrl_ctx);
xhci->num_active_eps -= num_failed_eps;
- xhci_dbg(xhci, "Removing %u failed ep ctxs, %u now active.\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Removing %u failed ep ctxs, %u now active.",
num_failed_eps,
xhci->num_active_eps);
}
@@ -2007,7 +1971,8 @@ static void xhci_finish_resource_reservation(struct xhci_hcd *xhci,
num_dropped_eps = xhci_count_num_dropped_endpoints(xhci, ctrl_ctx);
xhci->num_active_eps -= num_dropped_eps;
if (num_dropped_eps)
- xhci_dbg(xhci, "Removing %u dropped ep ctxs, %u now active.\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Removing %u dropped ep ctxs, %u now active.",
num_dropped_eps,
xhci->num_active_eps);
}
@@ -2168,18 +2133,21 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci,
* that the HS bus has enough bandwidth if we are activing a new TT.
*/
if (virt_dev->tt_info) {
- xhci_dbg(xhci, "Recalculating BW for rootport %u\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Recalculating BW for rootport %u",
virt_dev->real_port);
if (xhci_check_tt_bw_table(xhci, virt_dev, old_active_eps)) {
xhci_warn(xhci, "Not enough bandwidth on HS bus for "
"newly activated TT.\n");
return -ENOMEM;
}
- xhci_dbg(xhci, "Recalculating BW for TT slot %u port %u\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Recalculating BW for TT slot %u port %u",
virt_dev->tt_info->slot_id,
virt_dev->tt_info->ttport);
} else {
- xhci_dbg(xhci, "Recalculating BW for rootport %u\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Recalculating BW for rootport %u",
virt_dev->real_port);
}
@@ -2287,8 +2255,9 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci,
xhci->rh_bw[port_index].num_active_tts;
}
- xhci_dbg(xhci, "Final bandwidth: %u, Limit: %u, Reserved: %u, "
- "Available: %u " "percent\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Final bandwidth: %u, Limit: %u, Reserved: %u, "
+ "Available: %u " "percent",
bw_used, max_bandwidth, bw_reserved,
(max_bandwidth - bw_used - bw_reserved) * 100 /
max_bandwidth);
@@ -2658,7 +2627,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK))
xhci_free_host_resources(xhci, ctrl_ctx);
spin_unlock_irqrestore(&xhci->lock, flags);
- xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+ "FIXME allocate a new ring segment");
return -ENOMEM;
}
xhci_ring_cmd_db(xhci);
@@ -2871,7 +2841,8 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
struct xhci_dequeue_state deq_state;
struct xhci_virt_ep *ep;
- xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+ "Cleaning up stalled endpoint ring");
ep = &xhci->devs[udev->slot_id]->eps[ep_index];
/* We need to move the HW's dequeue pointer past this TD,
* or it will attempt to resend it on the next doorbell ring.
@@ -2884,7 +2855,8 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
* issue a configure endpoint command later.
*/
if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) {
- xhci_dbg(xhci, "Queueing new dequeue state\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+ "Queueing new dequeue state");
xhci_queue_new_dequeue_state(xhci, udev->slot_id,
ep_index, ep->stopped_stream, &deq_state);
} else {
@@ -2893,8 +2865,9 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
* XXX: No idea how this hardware will react when stream rings
* are enabled.
*/
- xhci_dbg(xhci, "Setting up input context for "
- "configure endpoint command\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Setting up input context for "
+ "configure endpoint command");
xhci_setup_input_ctx_for_quirk(xhci, udev->slot_id,
ep_index, &deq_state);
}
@@ -2926,16 +2899,19 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
ep_index = xhci_get_endpoint_index(&ep->desc);
virt_ep = &xhci->devs[udev->slot_id]->eps[ep_index];
if (!virt_ep->stopped_td) {
- xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n",
- ep->desc.bEndpointAddress);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+ "Endpoint 0x%x not halted, refusing to reset.",
+ ep->desc.bEndpointAddress);
return;
}
if (usb_endpoint_xfer_control(&ep->desc)) {
- xhci_dbg(xhci, "Control endpoint stall already handled.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+ "Control endpoint stall already handled.");
return;
}
- xhci_dbg(xhci, "Queueing reset endpoint command\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+ "Queueing reset endpoint command");
spin_lock_irqsave(&xhci->lock, flags);
ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index);
/*
@@ -3075,8 +3051,8 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci,
/* Are streams already being freed for the endpoint? */
if (ep_state & EP_GETTING_NO_STREAMS) {
xhci_warn(xhci, "WARN Can't disable streams for "
- "endpoint 0x%x\n, "
- "streams are being disabled already.",
+ "endpoint 0x%x, "
+ "streams are being disabled already\n",
eps[i]->desc.bEndpointAddress);
return 0;
}
@@ -3084,8 +3060,8 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci,
if (!(ep_state & EP_HAS_STREAMS) &&
!(ep_state & EP_GETTING_STREAMS)) {
xhci_warn(xhci, "WARN Can't disable streams for "
- "endpoint 0x%x\n, "
- "streams are already disabled!",
+ "endpoint 0x%x, "
+ "streams are already disabled!\n",
eps[i]->desc.bEndpointAddress);
xhci_warn(xhci, "WARN xhci_free_streams() called "
"with non-streams endpoint\n");
@@ -3373,8 +3349,9 @@ void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
}
xhci->num_active_eps -= num_dropped_eps;
if (num_dropped_eps)
- xhci_dbg(xhci, "Dropped %u ep ctxs, flags = 0x%x, "
- "%u now active.\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Dropped %u ep ctxs, flags = 0x%x, "
+ "%u now active.",
num_dropped_eps, drop_flags,
xhci->num_active_eps);
}
@@ -3508,10 +3485,10 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
switch (ret) {
case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
case COMP_CTX_STATE: /* 0.96 completion code for same thing */
- xhci_info(xhci, "Can't reset device (slot ID %u) in %s state\n",
+ xhci_dbg(xhci, "Can't reset device (slot ID %u) in %s state\n",
slot_id,
xhci_get_slot_state(xhci, virt_dev->out_ctx));
- xhci_info(xhci, "Not freeing device rings.\n");
+ xhci_dbg(xhci, "Not freeing device rings.\n");
/* Don't treat this as an error. May change my mind later. */
ret = 0;
goto command_cleanup;
@@ -3584,6 +3561,16 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
u32 state;
int i, ret;
+#ifndef CONFIG_USB_DEFAULT_PERSIST
+ /*
+ * We called pm_runtime_get_noresume when the device was attached.
+ * Decrement the counter here to allow controller to runtime suspend
+ * if no devices remain.
+ */
+ if (xhci->quirks & XHCI_RESET_ON_RESUME)
+ pm_runtime_put_noidle(hcd->self.controller);
+#endif
+
ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
/* If the host is halted due to driver unload, we still need to free the
* device.
@@ -3636,13 +3623,15 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
static int xhci_reserve_host_control_ep_resources(struct xhci_hcd *xhci)
{
if (xhci->num_active_eps + 1 > xhci->limit_active_eps) {
- xhci_dbg(xhci, "Not enough ep ctxs: "
- "%u active, need to add 1, limit is %u.\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Not enough ep ctxs: "
+ "%u active, need to add 1, limit is %u.",
xhci->num_active_eps, xhci->limit_active_eps);
return -ENOMEM;
}
xhci->num_active_eps += 1;
- xhci_dbg(xhci, "Adding 1 ep ctx, %u now active.\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+ "Adding 1 ep ctx, %u now active.",
xhci->num_active_eps);
return 0;
}
@@ -3707,6 +3696,16 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
goto disable_slot;
}
udev->slot_id = xhci->slot_id;
+
+#ifndef CONFIG_USB_DEFAULT_PERSIST
+ /*
+ * If resetting upon resume, we can't put the controller into runtime
+ * suspend if there is a device attached.
+ */
+ if (xhci->quirks & XHCI_RESET_ON_RESUME)
+ pm_runtime_get_noresume(hcd->self.controller);
+#endif
+
/* Is this a LS or FS device under a HS hub? */
/* Hub or peripherial? */
return 1;
@@ -3742,7 +3741,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
union xhci_trb *cmd_trb;
if (!udev->slot_id) {
- xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+ "Bad Slot ID %d", udev->slot_id);
return -EINVAL;
}
@@ -3781,6 +3781,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
+ trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
+ slot_ctx->dev_info >> 27);
spin_lock_irqsave(&xhci->lock, flags);
cmd_trb = xhci->cmd_ring->dequeue;
@@ -3788,7 +3790,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
udev->slot_id);
if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
- xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+ "FIXME: allocate a command ring segment");
return ret;
}
xhci_ring_cmd_db(xhci);
@@ -3828,13 +3831,15 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
ret = -ENODEV;
break;
case COMP_SUCCESS:
- xhci_dbg(xhci, "Successful Address Device command\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+ "Successful Address Device command");
break;
default:
xhci_err(xhci, "ERROR: unexpected command completion "
"code 0x%x.\n", virt_dev->cmd_status);
xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
+ trace_xhci_address_ctx(xhci, virt_dev->out_ctx, 1);
ret = -EINVAL;
break;
}
@@ -3842,16 +3847,21 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
return ret;
}
temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
- xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64);
- xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n",
- udev->slot_id,
- &xhci->dcbaa->dev_context_ptrs[udev->slot_id],
- (unsigned long long)
- le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id]));
- xhci_dbg(xhci, "Output Context DMA address = %#08llx\n",
+ xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+ "Op regs DCBAA ptr = %#016llx", temp_64);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+ "Slot ID %d dcbaa entry @%p = %#016llx",
+ udev->slot_id,
+ &xhci->dcbaa->dev_context_ptrs[udev->slot_id],
+ (unsigned long long)
+ le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id]));
+ xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+ "Output Context DMA address = %#08llx",
(unsigned long long)virt_dev->out_ctx->dma);
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
+ trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
+ slot_ctx->dev_info >> 27);
xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
/*
@@ -3859,6 +3869,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
* address given back to us by the HC.
*/
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+ trace_xhci_address_ctx(xhci, virt_dev->out_ctx,
+ slot_ctx->dev_info >> 27);
/* Use kernel assigned address for devices; store xHC assigned
* address locally. */
virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK)
@@ -3867,7 +3879,8 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
ctrl_ctx->add_flags = 0;
ctrl_ctx->drop_flags = 0;
- xhci_dbg(xhci, "Internal device address = %d\n", virt_dev->address);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+ "Internal device address = %d", virt_dev->address);
return 0;
}
@@ -3898,7 +3911,7 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
* Issue an Evaluate Context command to change the Maximum Exit Latency in the
* slot context. If that succeeds, store the new MEL in the xhci_virt_device.
*/
-static int xhci_change_max_exit_latency(struct xhci_hcd *xhci,
+static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
struct usb_device *udev, u16 max_exit_latency)
{
struct xhci_virt_device *virt_dev;
@@ -3933,7 +3946,8 @@ static int xhci_change_max_exit_latency(struct xhci_hcd *xhci,
slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT));
slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency);
- xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+ "Set up evaluate context for LPM MEL change.");
xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, command->in_ctx, 0);
@@ -4353,7 +4367,7 @@ static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev,
state_name, sel);
else
dev_dbg(&udev->dev, "Device-initiated %s disabled "
- "due to long PEL %llu\n ms",
+ "due to long PEL %llu ms\n",
state_name, pel);
return USB3_LPM_DISABLED;
}
@@ -4837,10 +4851,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
struct xhci_hcd *xhci;
struct device *dev = hcd->self.controller;
int retval;
- u32 temp;
/* Accept arbitrarily long scatter-gather lists */
hcd->self.sg_tablesize = ~0;
+
+ /* support to build packet from discontinuous buffers */
+ hcd->self.no_sg_constraint = 1;
+
/* XHCI controllers don't stop the ep queue on short packets :| */
hcd->self.no_stop_on_short = 1;
@@ -4865,14 +4882,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
/* xHCI private pointer was set in xhci_pci_probe for the second
* registered roothub.
*/
- xhci = hcd_to_xhci(hcd);
- temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
- if (HCC_64BIT_ADDR(temp)) {
- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
- } else {
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
- }
return 0;
}
@@ -4892,6 +4901,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
get_quirks(dev, xhci);
+ /* In xhci controllers which follow xhci 1.0 spec gives a spurious
+ * success event after a short transfer. This quirk will ignore such
+ * spurious event.
+ */
+ if (xhci->hci_version > 0x96)
+ xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
+
/* Make sure the HC is halted. */
retval = xhci_halt(xhci);
if (retval)
@@ -4904,12 +4920,12 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
goto error;
xhci_dbg(xhci, "Reset complete\n");
- temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
- if (HCC_64BIT_ADDR(temp)) {
+ /* Set dma_mask and coherent_dma_mask to 64-bits,
+ * if xHC supports 64-bit addressing */
+ if (HCC_64BIT_ADDR(xhci->hcc_params) &&
+ !dma_set_mask(dev, DMA_BIT_MASK(64))) {
xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
- } else {
- dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
}
xhci_dbg(xhci, "Calling HCD init\n");
@@ -4934,12 +4950,12 @@ static int __init xhci_hcd_init(void)
retval = xhci_register_pci();
if (retval < 0) {
- printk(KERN_DEBUG "Problem registering PCI driver.");
+ pr_debug("Problem registering PCI driver.\n");
return retval;
}
retval = xhci_register_plat();
if (retval < 0) {
- printk(KERN_DEBUG "Problem registering platform driver.");
+ pr_debug("Problem registering platform driver.\n");
goto unreg_pci;
}
/*
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c338741a675..46aa1489414 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1490,11 +1490,6 @@ struct xhci_hcd {
struct dma_pool *small_streams_pool;
struct dma_pool *medium_streams_pool;
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
- /* Poll the rings - for debugging */
- struct timer_list event_ring_timer;
- int zombie;
-#endif
/* Host controller watchdog timer structures */
unsigned int xhc_state;
@@ -1542,6 +1537,7 @@ struct xhci_hcd {
#define XHCI_SPURIOUS_REBOOT (1 << 13)
#define XHCI_COMP_MODE_QUIRK (1 << 14)
#define XHCI_AVOID_BEI (1 << 15)
+#define XHCI_PLAT (1 << 16)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
@@ -1579,16 +1575,8 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
return xhci->main_hcd;
}
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-#define XHCI_DEBUG 1
-#else
-#define XHCI_DEBUG 0
-#endif
-
#define xhci_dbg(xhci, fmt, args...) \
- do { if (XHCI_DEBUG) dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0)
-#define xhci_info(xhci, fmt, args...) \
- do { if (XHCI_DEBUG) dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0)
+ dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
#define xhci_err(xhci, fmt, args...) \
dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
#define xhci_warn(xhci, fmt, args...) \
@@ -1660,6 +1648,8 @@ char *xhci_get_slot_state(struct xhci_hcd *xhci,
void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
struct xhci_virt_ep *ep);
+void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
+ const char *fmt, ...);
/* xHCI memory management */
void xhci_mem_cleanup(struct xhci_hcd *xhci);
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index a51e7d6afda..e2b21c1d9c4 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -200,6 +200,19 @@ config USB_TEST
See <http://www.linux-usb.org/usbtest/> for more information,
including sample test device firmware and "how to use it".
+config USB_EHSET_TEST_FIXTURE
+ tristate "USB EHSET Test Fixture driver"
+ help
+ Say Y here if you want to support the special test fixture device
+ used for the USB-IF Embedded Host High-Speed Electrical Test procedure.
+
+ When the test fixture is connected, it can enumerate as one of several
+ VID/PID pairs. This driver then initiates a corresponding test mode on
+ the downstream port to which the test fixture is attached.
+
+ See <http://www.usb.org/developers/onthego/EHSET_v1.01.pdf> for more
+ information.
+
config USB_ISIGHTFW
tristate "iSight firmware loading support"
select FW_LOADER
@@ -233,5 +246,6 @@ config USB_EZUSB_FX2
config USB_HSIC_USB3503
tristate "USB3503 HSIC to USB20 Driver"
depends on I2C
+ select REGMAP
help
This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver.
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 3e1bd70b06e..e748fd5dbe9 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -2,9 +2,6 @@
# Makefile for the rest of the USB drivers
# (the ones that don't fit into any other categories)
#
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-
obj-$(CONFIG_USB_ADUTUX) += adutux.o
obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o
obj-$(CONFIG_USB_CYPRESS_CY7C63) += cypress_cy7c63.o
@@ -22,6 +19,7 @@ obj-$(CONFIG_USB_LED) += usbled.o
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
obj-$(CONFIG_USB_RIO500) += rio500.o
obj-$(CONFIG_USB_TEST) += usbtest.o
+obj-$(CONFIG_USB_EHSET_TEST_FIXTURE) += ehset.o
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
obj-$(CONFIG_USB_USS720) += uss720.o
obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index eb3c8c142fa..3eaa83f0508 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -18,6 +18,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -27,30 +29,11 @@
#include <linux/mutex.h>
#include <linux/uaccess.h>
-#ifdef CONFIG_USB_DEBUG
-static int debug = 5;
-#else
-static int debug = 1;
-#endif
-
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(lvl, format, arg...) \
-do { \
- if (debug >= lvl) \
- printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
-} while (0)
-
-
/* Version Information */
#define DRIVER_VERSION "v0.0.13"
#define DRIVER_AUTHOR "John Homppi"
#define DRIVER_DESC "adutux (see www.ontrak.net)"
-/* Module parameters */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
/* Define these values to match your device */
#define ADU_VENDOR_ID 0x0a07
#define ADU_PRODUCT_ID 0x0064
@@ -124,19 +107,11 @@ static DEFINE_MUTEX(adutux_mutex);
static struct usb_driver adu_driver;
-static void adu_debug_data(int level, const char *function, int size,
- const unsigned char *data)
+static inline void adu_debug_data(struct device *dev, const char *function,
+ int size, const unsigned char *data)
{
- int i;
-
- if (debug < level)
- return;
-
- printk(KERN_DEBUG "%s: %s - length = %d, data = ",
- __FILE__, function, size);
- for (i = 0; i < size; ++i)
- printk("%.2x ", data[i]);
- printk("\n");
+ dev_dbg(dev, "%s - length = %d, data = %*ph\n",
+ function, size, size, data);
}
/**
@@ -147,12 +122,8 @@ static void adu_abort_transfers(struct adu_device *dev)
{
unsigned long flags;
- dbg(2, " %s : enter", __func__);
-
- if (dev->udev == NULL) {
- dbg(1, " %s : udev is null", __func__);
- goto exit;
- }
+ if (dev->udev == NULL)
+ return;
/* shutdown transfer */
@@ -170,15 +141,10 @@ static void adu_abort_transfers(struct adu_device *dev)
usb_kill_urb(dev->interrupt_out_urb);
} else
spin_unlock_irqrestore(&dev->buflock, flags);
-
-exit:
- dbg(2, " %s : leave", __func__);
}
static void adu_delete(struct adu_device *dev)
{
- dbg(2, "%s enter", __func__);
-
/* free data structures */
usb_free_urb(dev->interrupt_in_urb);
usb_free_urb(dev->interrupt_out_urb);
@@ -187,8 +153,6 @@ static void adu_delete(struct adu_device *dev)
kfree(dev->interrupt_in_buffer);
kfree(dev->interrupt_out_buffer);
kfree(dev);
-
- dbg(2, "%s : leave", __func__);
}
static void adu_interrupt_in_callback(struct urb *urb)
@@ -196,17 +160,17 @@ static void adu_interrupt_in_callback(struct urb *urb)
struct adu_device *dev = urb->context;
int status = urb->status;
- dbg(4, " %s : enter, status %d", __func__, status);
- adu_debug_data(5, __func__, urb->actual_length,
- urb->transfer_buffer);
+ adu_debug_data(&dev->udev->dev, __func__,
+ urb->actual_length, urb->transfer_buffer);
spin_lock(&dev->buflock);
if (status != 0) {
if ((status != -ENOENT) && (status != -ECONNRESET) &&
(status != -ESHUTDOWN)) {
- dbg(1, " %s : nonzero status received: %d",
- __func__, status);
+ dev_dbg(&dev->udev->dev,
+ "%s : nonzero status received: %d\n",
+ __func__, status);
}
goto exit;
}
@@ -220,10 +184,11 @@ static void adu_interrupt_in_callback(struct urb *urb)
dev->interrupt_in_buffer, urb->actual_length);
dev->read_buffer_length += urb->actual_length;
- dbg(2, " %s reading %d ", __func__,
- urb->actual_length);
+ dev_dbg(&dev->udev->dev,"%s reading %d\n", __func__,
+ urb->actual_length);
} else {
- dbg(1, " %s : read_buffer overflow", __func__);
+ dev_dbg(&dev->udev->dev,"%s : read_buffer overflow\n",
+ __func__);
}
}
@@ -232,9 +197,6 @@ exit:
spin_unlock(&dev->buflock);
/* always wake up so we recover from errors */
wake_up_interruptible(&dev->read_wait);
- adu_debug_data(5, __func__, urb->actual_length,
- urb->transfer_buffer);
- dbg(4, " %s : leave, status %d", __func__, status);
}
static void adu_interrupt_out_callback(struct urb *urb)
@@ -242,27 +204,23 @@ static void adu_interrupt_out_callback(struct urb *urb)
struct adu_device *dev = urb->context;
int status = urb->status;
- dbg(4, " %s : enter, status %d", __func__, status);
- adu_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+ adu_debug_data(&dev->udev->dev, __func__,
+ urb->actual_length, urb->transfer_buffer);
if (status != 0) {
if ((status != -ENOENT) &&
(status != -ECONNRESET)) {
- dbg(1, " %s :nonzero status received: %d",
- __func__, status);
+ dev_dbg(&dev->udev->dev,
+ "%s :nonzero status received: %d\n", __func__,
+ status);
}
- goto exit;
+ return;
}
spin_lock(&dev->buflock);
dev->out_urb_finished = 1;
wake_up(&dev->write_wait);
spin_unlock(&dev->buflock);
-exit:
-
- adu_debug_data(5, __func__, urb->actual_length,
- urb->transfer_buffer);
- dbg(4, " %s : leave, status %d", __func__, status);
}
static int adu_open(struct inode *inode, struct file *file)
@@ -272,20 +230,16 @@ static int adu_open(struct inode *inode, struct file *file)
int subminor;
int retval;
- dbg(2, "%s : enter", __func__);
-
subminor = iminor(inode);
retval = mutex_lock_interruptible(&adutux_mutex);
- if (retval) {
- dbg(2, "%s : mutex lock failed", __func__);
+ if (retval)
goto exit_no_lock;
- }
interface = usb_find_interface(&adu_driver, subminor);
if (!interface) {
- printk(KERN_ERR "adutux: %s - error, can't find device for "
- "minor %d\n", __func__, subminor);
+ pr_err("%s - error, can't find device for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit_no_device;
}
@@ -303,7 +257,8 @@ static int adu_open(struct inode *inode, struct file *file)
}
++dev->open_count;
- dbg(2, "%s : open count %d", __func__, dev->open_count);
+ dev_dbg(&dev->udev->dev, "%s: open count %d\n", __func__,
+ dev->open_count);
/* save device in the file's private structure */
file->private_data = dev;
@@ -333,23 +288,19 @@ static int adu_open(struct inode *inode, struct file *file)
exit_no_device:
mutex_unlock(&adutux_mutex);
exit_no_lock:
- dbg(2, "%s : leave, return value %d ", __func__, retval);
return retval;
}
static void adu_release_internal(struct adu_device *dev)
{
- dbg(2, " %s : enter", __func__);
-
/* decrement our usage count for the device */
--dev->open_count;
- dbg(2, " %s : open count %d", __func__, dev->open_count);
+ dev_dbg(&dev->udev->dev, "%s : open count %d\n", __func__,
+ dev->open_count);
if (dev->open_count <= 0) {
adu_abort_transfers(dev);
dev->open_count = 0;
}
-
- dbg(2, " %s : leave", __func__);
}
static int adu_release(struct inode *inode, struct file *file)
@@ -357,17 +308,13 @@ static int adu_release(struct inode *inode, struct file *file)
struct adu_device *dev;
int retval = 0;
- dbg(2, " %s : enter", __func__);
-
if (file == NULL) {
- dbg(1, " %s : file is NULL", __func__);
retval = -ENODEV;
goto exit;
}
dev = file->private_data;
if (dev == NULL) {
- dbg(1, " %s : object is NULL", __func__);
retval = -ENODEV;
goto exit;
}
@@ -375,7 +322,7 @@ static int adu_release(struct inode *inode, struct file *file)
mutex_lock(&adutux_mutex); /* not interruptible */
if (dev->open_count <= 0) {
- dbg(1, " %s : device not opened", __func__);
+ dev_dbg(&dev->udev->dev, "%s : device not opened\n", __func__);
retval = -ENODEV;
goto unlock;
}
@@ -389,7 +336,6 @@ static int adu_release(struct inode *inode, struct file *file)
unlock:
mutex_unlock(&adutux_mutex);
exit:
- dbg(2, " %s : leave, return value %d", __func__, retval);
return retval;
}
@@ -406,35 +352,32 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
- dbg(2, " %s : enter, count = %Zd, file=%p", __func__, count, file);
-
dev = file->private_data;
- dbg(2, " %s : dev=%p", __func__, dev);
-
if (mutex_lock_interruptible(&dev->mtx))
return -ERESTARTSYS;
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
- printk(KERN_ERR "adutux: No device or device unplugged %d\n",
- retval);
+ pr_err("No device or device unplugged %d\n", retval);
goto exit;
}
/* verify that some data was requested */
if (count == 0) {
- dbg(1, " %s : read request of 0 bytes", __func__);
+ dev_dbg(&dev->udev->dev, "%s : read request of 0 bytes\n",
+ __func__);
goto exit;
}
timeout = COMMAND_TIMEOUT;
- dbg(2, " %s : about to start looping", __func__);
+ dev_dbg(&dev->udev->dev, "%s : about to start looping\n", __func__);
while (bytes_to_read) {
int data_in_secondary = dev->secondary_tail - dev->secondary_head;
- dbg(2, " %s : while, data_in_secondary=%d, status=%d",
- __func__, data_in_secondary,
- dev->interrupt_in_urb->status);
+ dev_dbg(&dev->udev->dev,
+ "%s : while, data_in_secondary=%d, status=%d\n",
+ __func__, data_in_secondary,
+ dev->interrupt_in_urb->status);
if (data_in_secondary) {
/* drain secondary buffer */
@@ -457,8 +400,9 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
if (dev->read_buffer_length) {
/* we secure access to the primary */
char *tmp;
- dbg(2, " %s : swap, read_buffer_length = %d",
- __func__, dev->read_buffer_length);
+ dev_dbg(&dev->udev->dev,
+ "%s : swap, read_buffer_length = %d\n",
+ __func__, dev->read_buffer_length);
tmp = dev->read_buffer_secondary;
dev->read_buffer_secondary = dev->read_buffer_primary;
dev->read_buffer_primary = tmp;
@@ -473,10 +417,14 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
if (!dev->read_urb_finished) {
/* somebody is doing IO */
spin_unlock_irqrestore(&dev->buflock, flags);
- dbg(2, " %s : submitted already", __func__);
+ dev_dbg(&dev->udev->dev,
+ "%s : submitted already\n",
+ __func__);
} else {
/* we must initiate input */
- dbg(2, " %s : initiate input", __func__);
+ dev_dbg(&dev->udev->dev,
+ "%s : initiate input\n",
+ __func__);
dev->read_urb_finished = 0;
spin_unlock_irqrestore(&dev->buflock, flags);
@@ -494,7 +442,9 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
if (retval == -ENOMEM) {
retval = bytes_read ? bytes_read : -ENOMEM;
}
- dbg(2, " %s : submit failed", __func__);
+ dev_dbg(&dev->udev->dev,
+ "%s : submit failed\n",
+ __func__);
goto exit;
}
}
@@ -513,13 +463,16 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
remove_wait_queue(&dev->read_wait, &wait);
if (timeout <= 0) {
- dbg(2, " %s : timeout", __func__);
+ dev_dbg(&dev->udev->dev,
+ "%s : timeout\n", __func__);
retval = bytes_read ? bytes_read : -ETIMEDOUT;
goto exit;
}
if (signal_pending(current)) {
- dbg(2, " %s : signal pending", __func__);
+ dev_dbg(&dev->udev->dev,
+ "%s : signal pending\n",
+ __func__);
retval = bytes_read ? bytes_read : -EINTR;
goto exit;
}
@@ -552,7 +505,6 @@ exit:
/* unlock the device */
mutex_unlock(&dev->mtx);
- dbg(2, " %s : leave, return value %d", __func__, retval);
return retval;
}
@@ -567,8 +519,6 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
unsigned long flags;
int retval;
- dbg(2, " %s : enter, count = %Zd", __func__, count);
-
dev = file->private_data;
retval = mutex_lock_interruptible(&dev->mtx);
@@ -578,14 +528,14 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
- printk(KERN_ERR "adutux: No device or device unplugged %d\n",
- retval);
+ pr_err("No device or device unplugged %d\n", retval);
goto exit;
}
/* verify that we actually have some data to write */
if (count == 0) {
- dbg(1, " %s : write request of 0 bytes", __func__);
+ dev_dbg(&dev->udev->dev, "%s : write request of 0 bytes\n",
+ __func__);
goto exit;
}
@@ -598,13 +548,15 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
mutex_unlock(&dev->mtx);
if (signal_pending(current)) {
- dbg(1, " %s : interrupted", __func__);
+ dev_dbg(&dev->udev->dev, "%s : interrupted\n",
+ __func__);
set_current_state(TASK_RUNNING);
retval = -EINTR;
goto exit_onqueue;
}
if (schedule_timeout(COMMAND_TIMEOUT) == 0) {
- dbg(1, "%s - command timed out.", __func__);
+ dev_dbg(&dev->udev->dev,
+ "%s - command timed out.\n", __func__);
retval = -ETIMEDOUT;
goto exit_onqueue;
}
@@ -615,18 +567,22 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
goto exit_nolock;
}
- dbg(4, " %s : in progress, count = %Zd", __func__, count);
+ dev_dbg(&dev->udev->dev,
+ "%s : in progress, count = %Zd\n",
+ __func__, count);
} else {
spin_unlock_irqrestore(&dev->buflock, flags);
set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->write_wait, &waita);
- dbg(4, " %s : sending, count = %Zd", __func__, count);
+ dev_dbg(&dev->udev->dev, "%s : sending, count = %Zd\n",
+ __func__, count);
/* write the data into interrupt_out_buffer from userspace */
buffer_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
bytes_to_write = count > buffer_size ? buffer_size : count;
- dbg(4, " %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",
- __func__, buffer_size, count, bytes_to_write);
+ dev_dbg(&dev->udev->dev,
+ "%s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd\n",
+ __func__, buffer_size, count, bytes_to_write);
if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) {
retval = -EFAULT;
@@ -665,7 +621,6 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
exit:
mutex_unlock(&dev->mtx);
exit_nolock:
- dbg(2, " %s : leave, return value %d", __func__, retval);
return retval;
exit_onqueue:
@@ -711,8 +666,6 @@ static int adu_probe(struct usb_interface *interface,
int out_end_size;
int i;
- dbg(2, " %s : enter", __func__);
-
if (udev == NULL) {
dev_err(&interface->dev, "udev is NULL.\n");
goto exit;
@@ -812,7 +765,7 @@ static int adu_probe(struct usb_interface *interface,
dev_err(&interface->dev, "Could not retrieve serial number\n");
goto error;
}
- dbg(2, " %s : serial_number=%s", __func__, dev->serial_number);
+ dev_dbg(&interface->dev,"serial_number=%s", dev->serial_number);
/* we can register the device now, as it is ready */
usb_set_intfdata(interface, dev);
@@ -830,11 +783,9 @@ static int adu_probe(struct usb_interface *interface,
/* let the user know what node this device is now attached to */
dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d\n",
- udev->descriptor.idProduct, dev->serial_number,
+ le16_to_cpu(udev->descriptor.idProduct), dev->serial_number,
(dev->minor - ADU_MINOR_BASE));
exit:
- dbg(2, " %s : leave, return value %p (dev)", __func__, dev);
-
return retval;
error:
@@ -852,8 +803,6 @@ static void adu_disconnect(struct usb_interface *interface)
struct adu_device *dev;
int minor;
- dbg(2, " %s : enter", __func__);
-
dev = usb_get_intfdata(interface);
mutex_lock(&dev->mtx); /* not interruptible */
@@ -866,7 +815,8 @@ static void adu_disconnect(struct usb_interface *interface)
usb_set_intfdata(interface, NULL);
/* if the device is not opened, then we clean up right now */
- dbg(2, " %s : open count %d", __func__, dev->open_count);
+ dev_dbg(&dev->udev->dev, "%s : open count %d\n",
+ __func__, dev->open_count);
if (!dev->open_count)
adu_delete(dev);
@@ -874,8 +824,6 @@ static void adu_disconnect(struct usb_interface *interface)
dev_info(&interface->dev, "ADU device adutux%d now disconnected\n",
(minor - ADU_MINOR_BASE));
-
- dbg(2, " %s : leave", __func__);
}
/* usb specific object needed to register this driver with the usb subsystem */
diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c
new file mode 100644
index 00000000000..c31b4a33e6b
--- /dev/null
+++ b/drivers/usb/misc/ehset.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/ch11.h>
+
+#define TEST_SE0_NAK_PID 0x0101
+#define TEST_J_PID 0x0102
+#define TEST_K_PID 0x0103
+#define TEST_PACKET_PID 0x0104
+#define TEST_HS_HOST_PORT_SUSPEND_RESUME 0x0106
+#define TEST_SINGLE_STEP_GET_DEV_DESC 0x0107
+#define TEST_SINGLE_STEP_SET_FEATURE 0x0108
+
+static int ehset_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int ret = -EINVAL;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_device *hub_udev = dev->parent;
+ struct usb_device_descriptor *buf;
+ u8 portnum = dev->portnum;
+ u16 test_pid = le16_to_cpu(dev->descriptor.idProduct);
+
+ switch (test_pid) {
+ case TEST_SE0_NAK_PID:
+ ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT,
+ USB_PORT_FEAT_TEST,
+ (TEST_SE0_NAK << 8) | portnum,
+ NULL, 0, 1000);
+ break;
+ case TEST_J_PID:
+ ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT,
+ USB_PORT_FEAT_TEST,
+ (TEST_J << 8) | portnum,
+ NULL, 0, 1000);
+ break;
+ case TEST_K_PID:
+ ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT,
+ USB_PORT_FEAT_TEST,
+ (TEST_K << 8) | portnum,
+ NULL, 0, 1000);
+ break;
+ case TEST_PACKET_PID:
+ ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT,
+ USB_PORT_FEAT_TEST,
+ (TEST_PACKET << 8) | portnum,
+ NULL, 0, 1000);
+ break;
+ case TEST_HS_HOST_PORT_SUSPEND_RESUME:
+ /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */
+ msleep(15 * 1000);
+ ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT,
+ USB_PORT_FEAT_SUSPEND, portnum,
+ NULL, 0, 1000);
+ if (ret < 0)
+ break;
+
+ msleep(15 * 1000);
+ ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RT_PORT,
+ USB_PORT_FEAT_SUSPEND, portnum,
+ NULL, 0, 1000);
+ break;
+ case TEST_SINGLE_STEP_GET_DEV_DESC:
+ /* Test: wait for 15secs -> GetDescriptor request */
+ msleep(15 * 1000);
+ buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ USB_DT_DEVICE << 8, 0,
+ buf, USB_DT_DEVICE_SIZE,
+ USB_CTRL_GET_TIMEOUT);
+ kfree(buf);
+ break;
+ case TEST_SINGLE_STEP_SET_FEATURE:
+ /*
+ * GetDescriptor SETUP request -> 15secs delay -> IN & STATUS
+ *
+ * Note, this test is only supported on root hubs since the
+ * SetPortFeature handling can only be done inside the HCD's
+ * hub_control callback function.
+ */
+ if (hub_udev != dev->bus->root_hub) {
+ dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n");
+ break;
+ }
+
+ ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT,
+ USB_PORT_FEAT_TEST,
+ (6 << 8) | portnum,
+ NULL, 0, 60 * 1000);
+
+ break;
+ default:
+ dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n",
+ __func__, test_pid);
+ }
+
+ return (ret < 0) ? ret : 0;
+}
+
+static void ehset_disconnect(struct usb_interface *intf)
+{
+}
+
+static const struct usb_device_id ehset_id_table[] = {
+ { USB_DEVICE(0x1a0a, TEST_SE0_NAK_PID) },
+ { USB_DEVICE(0x1a0a, TEST_J_PID) },
+ { USB_DEVICE(0x1a0a, TEST_K_PID) },
+ { USB_DEVICE(0x1a0a, TEST_PACKET_PID) },
+ { USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME) },
+ { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC) },
+ { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ehset_id_table);
+
+static struct usb_driver ehset_driver = {
+ .name = "usb_ehset_test",
+ .probe = ehset_probe,
+ .disconnect = ehset_disconnect,
+ .id_table = ehset_id_table,
+};
+
+module_usb_driver(ehset_driver);
+
+MODULE_DESCRIPTION("USB Driver for EHSET Test Fixture");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index ac762299eaa..b1d59532ac2 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -129,19 +129,6 @@ MODULE_DESCRIPTION("LD USB Driver");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("LD USB Devices");
-#ifdef CONFIG_USB_DEBUG
- static int debug = 1;
-#else
- static int debug = 0;
-#endif
-
-/* Use our own dbg macro */
-#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
-
-/* Module parameters */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
/* All interrupt in transfers are collected in a ring buffer to
* avoid racing conditions and get better performance of the driver.
*/
@@ -256,8 +243,9 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
status == -ESHUTDOWN) {
goto exit;
} else {
- dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
- __func__, status);
+ dev_dbg(&dev->intf->dev,
+ "%s: nonzero status received: %d\n", __func__,
+ status);
spin_lock(&dev->rbsl);
goto resubmit; /* maybe we can recover */
}
@@ -272,8 +260,8 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
*actual_buffer = urb->actual_length;
memcpy(actual_buffer+1, dev->interrupt_in_buffer, urb->actual_length);
dev->ring_head = next_ring_head;
- dbg_info(&dev->intf->dev, "%s: received %d bytes\n",
- __func__, urb->actual_length);
+ dev_dbg(&dev->intf->dev, "%s: received %d bytes\n",
+ __func__, urb->actual_length);
} else {
dev_warn(&dev->intf->dev,
"Ring buffer overflow, %d bytes dropped\n",
@@ -310,9 +298,9 @@ static void ld_usb_interrupt_out_callback(struct urb *urb)
if (status && !(status == -ENOENT ||
status == -ECONNRESET ||
status == -ESHUTDOWN))
- dbg_info(&dev->intf->dev,
- "%s - nonzero write interrupt status received: %d\n",
- __func__, status);
+ dev_dbg(&dev->intf->dev,
+ "%s - nonzero write interrupt status received: %d\n",
+ __func__, status);
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
@@ -585,7 +573,8 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
if (bytes_to_write < count)
dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
- dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __func__, count, bytes_to_write);
+ dev_dbg(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n",
+ __func__, count, bytes_to_write);
if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
retval = -EFAULT;
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 80894791c02..eb37c954205 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -75,6 +75,8 @@
* - move reset into open to clean out spurious data
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -87,28 +89,11 @@
#include <linux/poll.h>
-#ifdef CONFIG_USB_DEBUG
- static int debug = 4;
-#else
- static int debug = 0;
-#endif
-
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(lvl, format, arg...) \
-do { \
- if (debug >= lvl) \
- printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
-} while (0)
-
/* Version Information */
#define DRIVER_VERSION "v0.96"
#define DRIVER_AUTHOR "Juergen Stuber <starblue@sourceforge.net>"
#define DRIVER_DESC "LEGO USB Tower Driver"
-/* Module parameters */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
/* The defaults are chosen to work with the latest versions of leJOS and NQC.
*/
@@ -298,18 +283,12 @@ static struct usb_driver tower_driver = {
/**
* lego_usb_tower_debug_data
*/
-static inline void lego_usb_tower_debug_data (int level, const char *function, int size, const unsigned char *data)
+static inline void lego_usb_tower_debug_data(struct device *dev,
+ const char *function, int size,
+ const unsigned char *data)
{
- int i;
-
- if (debug < level)
- return;
-
- printk (KERN_DEBUG "%s: %s - length = %d, data = ", __FILE__, function, size);
- for (i = 0; i < size; ++i) {
- printk ("%.2x ", data[i]);
- }
- printk ("\n");
+ dev_dbg(dev, "%s - length = %d, data = %*ph\n",
+ function, size, size, data);
}
@@ -318,8 +297,6 @@ static inline void lego_usb_tower_debug_data (int level, const char *function, i
*/
static inline void tower_delete (struct lego_usb_tower *dev)
{
- dbg(2, "%s: enter", __func__);
-
tower_abort_transfers (dev);
/* free data structures */
@@ -329,8 +306,6 @@ static inline void tower_delete (struct lego_usb_tower *dev)
kfree (dev->interrupt_in_buffer);
kfree (dev->interrupt_out_buffer);
kfree (dev);
-
- dbg(2, "%s: leave", __func__);
}
@@ -346,16 +321,13 @@ static int tower_open (struct inode *inode, struct file *file)
struct tower_reset_reply reset_reply;
int result;
- dbg(2, "%s: enter", __func__);
-
nonseekable_open(inode, file);
subminor = iminor(inode);
interface = usb_find_interface (&tower_driver, subminor);
if (!interface) {
- printk(KERN_ERR "%s - error, can't find device for minor %d\n",
- __func__, subminor);
+ pr_err("error, can't find device for minor %d\n", subminor);
retval = -ENODEV;
goto exit;
}
@@ -435,8 +407,6 @@ unlock_exit:
mutex_unlock(&dev->lock);
exit:
- dbg(2, "%s: leave, return value %d ", __func__, retval);
-
return retval;
}
@@ -448,12 +418,9 @@ static int tower_release (struct inode *inode, struct file *file)
struct lego_usb_tower *dev;
int retval = 0;
- dbg(2, "%s: enter", __func__);
-
dev = file->private_data;
if (dev == NULL) {
- dbg(1, "%s: object is NULL", __func__);
retval = -ENODEV;
goto exit_nolock;
}
@@ -465,7 +432,8 @@ static int tower_release (struct inode *inode, struct file *file)
}
if (dev->open_count != 1) {
- dbg(1, "%s: device not opened exactly once", __func__);
+ dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n",
+ __func__);
retval = -ENODEV;
goto unlock_exit;
}
@@ -491,7 +459,6 @@ unlock_exit:
exit:
mutex_unlock(&open_disc_mutex);
exit_nolock:
- dbg(2, "%s: leave, return value %d", __func__, retval);
return retval;
}
@@ -502,12 +469,8 @@ exit_nolock:
*/
static void tower_abort_transfers (struct lego_usb_tower *dev)
{
- dbg(2, "%s: enter", __func__);
-
- if (dev == NULL) {
- dbg(1, "%s: dev is null", __func__);
- goto exit;
- }
+ if (dev == NULL)
+ return;
/* shutdown transfer */
if (dev->interrupt_in_running) {
@@ -518,9 +481,6 @@ static void tower_abort_transfers (struct lego_usb_tower *dev)
}
if (dev->interrupt_out_busy && dev->udev)
usb_kill_urb(dev->interrupt_out_urb);
-
-exit:
- dbg(2, "%s: leave", __func__);
}
@@ -553,8 +513,6 @@ static unsigned int tower_poll (struct file *file, poll_table *wait)
struct lego_usb_tower *dev;
unsigned int mask = 0;
- dbg(2, "%s: enter", __func__);
-
dev = file->private_data;
if (!dev->udev)
@@ -571,8 +529,6 @@ static unsigned int tower_poll (struct file *file, poll_table *wait)
mask |= POLLOUT | POLLWRNORM;
}
- dbg(2, "%s: leave, mask = %d", __func__, mask);
-
return mask;
}
@@ -597,8 +553,6 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
int retval = 0;
unsigned long timeout = 0;
- dbg(2, "%s: enter, count = %Zd", __func__, count);
-
dev = file->private_data;
/* lock this object */
@@ -610,13 +564,13 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
- printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
+ pr_err("No device or device unplugged %d\n", retval);
goto unlock_exit;
}
/* verify that we actually have some data to read */
if (count == 0) {
- dbg(1, "%s: read request of 0 bytes", __func__);
+ dev_dbg(&dev->udev->dev, "read request of 0 bytes\n");
goto unlock_exit;
}
@@ -672,7 +626,6 @@ unlock_exit:
mutex_unlock(&dev->lock);
exit:
- dbg(2, "%s: leave, return value %d", __func__, retval);
return retval;
}
@@ -686,8 +639,6 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
size_t bytes_to_write;
int retval = 0;
- dbg(2, "%s: enter, count = %Zd", __func__, count);
-
dev = file->private_data;
/* lock this object */
@@ -699,13 +650,13 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
- printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
+ pr_err("No device or device unplugged %d\n", retval);
goto unlock_exit;
}
/* verify that we actually have some data to write */
if (count == 0) {
- dbg(1, "%s: write request of 0 bytes", __func__);
+ dev_dbg(&dev->udev->dev, "write request of 0 bytes\n");
goto unlock_exit;
}
@@ -723,7 +674,8 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
/* write the data into interrupt_out_buffer from userspace */
bytes_to_write = min_t(int, count, write_buffer_size);
- dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __func__, count, bytes_to_write);
+ dev_dbg(&dev->udev->dev, "%s: count = %Zd, bytes_to_write = %Zd\n",
+ __func__, count, bytes_to_write);
if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) {
retval = -EFAULT;
@@ -757,8 +709,6 @@ unlock_exit:
mutex_unlock(&dev->lock);
exit:
- dbg(2, "%s: leave, return value %d", __func__, retval);
-
return retval;
}
@@ -772,9 +722,8 @@ static void tower_interrupt_in_callback (struct urb *urb)
int status = urb->status;
int retval;
- dbg(4, "%s: enter, status %d", __func__, status);
-
- lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+ lego_usb_tower_debug_data(&dev->udev->dev, __func__,
+ urb->actual_length, urb->transfer_buffer);
if (status) {
if (status == -ENOENT ||
@@ -782,7 +731,9 @@ static void tower_interrupt_in_callback (struct urb *urb)
status == -ESHUTDOWN) {
goto exit;
} else {
- dbg(1, "%s: nonzero status received: %d", __func__, status);
+ dev_dbg(&dev->udev->dev,
+ "%s: nonzero status received: %d\n", __func__,
+ status);
goto resubmit; /* maybe we can recover */
}
}
@@ -795,9 +746,11 @@ static void tower_interrupt_in_callback (struct urb *urb)
urb->actual_length);
dev->read_buffer_length += urb->actual_length;
dev->read_last_arrival = jiffies;
- dbg(3, "%s: received %d bytes", __func__, urb->actual_length);
+ dev_dbg(&dev->udev->dev, "%s: received %d bytes\n",
+ __func__, urb->actual_length);
} else {
- printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __func__, urb->actual_length);
+ pr_warn("read_buffer overflow, %d bytes dropped\n",
+ urb->actual_length);
}
spin_unlock (&dev->read_buffer_lock);
}
@@ -815,9 +768,6 @@ resubmit:
exit:
dev->interrupt_in_done = 1;
wake_up_interruptible (&dev->read_wait);
-
- lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
- dbg(4, "%s: leave, status %d", __func__, status);
}
@@ -829,22 +779,20 @@ static void tower_interrupt_out_callback (struct urb *urb)
struct lego_usb_tower *dev = urb->context;
int status = urb->status;
- dbg(4, "%s: enter, status %d", __func__, status);
- lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+ lego_usb_tower_debug_data(&dev->udev->dev, __func__,
+ urb->actual_length, urb->transfer_buffer);
/* sync/async unlink faults aren't errors */
if (status && !(status == -ENOENT ||
status == -ECONNRESET ||
status == -ESHUTDOWN)) {
- dbg(1, "%s - nonzero write bulk status received: %d",
- __func__, status);
+ dev_dbg(&dev->udev->dev,
+ "%s: nonzero write bulk status received: %d\n", __func__,
+ status);
}
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
-
- lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
- dbg(4, "%s: leave, status %d", __func__, status);
}
@@ -866,8 +814,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
int retval = -ENOMEM;
int result;
- dbg(2, "%s: enter", __func__);
-
/* allocate memory for our device state and initialize it */
dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
@@ -993,8 +939,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
exit:
- dbg(2, "%s: leave, return value 0x%.8lx (dev)", __func__, (long) dev);
-
return retval;
error:
@@ -1013,8 +957,6 @@ static void tower_disconnect (struct usb_interface *interface)
struct lego_usb_tower *dev;
int minor;
- dbg(2, "%s: enter", __func__);
-
dev = usb_get_intfdata (interface);
mutex_lock(&open_disc_mutex);
usb_set_intfdata (interface, NULL);
@@ -1041,8 +983,6 @@ static void tower_disconnect (struct usb_interface *interface)
dev_info(&interface->dev, "LEGO USB Tower #%d now disconnected\n",
(minor - LEGO_USB_TOWER_MINOR_BASE));
-
- dbg(2, "%s: leave", __func__);
}
module_usb_driver(tower_driver);
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index c21386ec5d3..de98906f786 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -3247,6 +3247,7 @@ static const struct usb_device_id sisusb_table[] = {
{ USB_DEVICE(0x0711, 0x0903) },
{ USB_DEVICE(0x0711, 0x0918) },
{ USB_DEVICE(0x0711, 0x0920) },
+ { USB_DEVICE(0x0711, 0x0950) },
{ USB_DEVICE(0x182d, 0x021c) },
{ USB_DEVICE(0x182d, 0x0269) },
{ }
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c
index c3578393dde..a31641e18d1 100644
--- a/drivers/usb/misc/usb3503.c
+++ b/drivers/usb/misc/usb3503.c
@@ -26,6 +26,7 @@
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/platform_data/usb3503.h>
+#include <linux/regmap.h>
#define USB3503_VIDL 0x00
#define USB3503_VIDM 0x01
@@ -50,60 +51,25 @@
#define USB3503_CFGP 0xee
#define USB3503_CLKSUSP (1 << 7)
+#define USB3503_RESET 0xff
+
struct usb3503 {
enum usb3503_mode mode;
- struct i2c_client *client;
+ struct regmap *regmap;
+ struct device *dev;
u8 port_off_mask;
int gpio_intn;
int gpio_reset;
int gpio_connect;
};
-static int usb3503_write_register(struct i2c_client *client,
- char reg, char data)
-{
- return i2c_smbus_write_byte_data(client, reg, data);
-}
-
-static int usb3503_read_register(struct i2c_client *client, char reg)
-{
- return i2c_smbus_read_byte_data(client, reg);
-}
-
-static int usb3503_set_bits(struct i2c_client *client, char reg, char req)
+static int usb3503_reset(struct usb3503 *hub, int state)
{
- int err;
-
- err = usb3503_read_register(client, reg);
- if (err < 0)
- return err;
-
- err = usb3503_write_register(client, reg, err | req);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int usb3503_clear_bits(struct i2c_client *client, char reg, char req)
-{
- int err;
-
- err = usb3503_read_register(client, reg);
- if (err < 0)
- return err;
-
- err = usb3503_write_register(client, reg, err & ~req);
- if (err < 0)
- return err;
-
- return 0;
-}
+ if (!state && gpio_is_valid(hub->gpio_connect))
+ gpio_set_value_cansleep(hub->gpio_connect, 0);
-static int usb3503_reset(int gpio_reset, int state)
-{
- if (gpio_is_valid(gpio_reset))
- gpio_set_value(gpio_reset, state);
+ if (gpio_is_valid(hub->gpio_reset))
+ gpio_set_value_cansleep(hub->gpio_reset, state);
/* Wait T_HUBINIT == 4ms for hub logic to stabilize */
if (state)
@@ -112,90 +78,105 @@ static int usb3503_reset(int gpio_reset, int state)
return 0;
}
-static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode)
+static int usb3503_connect(struct usb3503 *hub)
{
- struct i2c_client *i2c = hub->client;
- int err = 0;
+ struct device *dev = hub->dev;
+ int err;
- switch (mode) {
- case USB3503_MODE_HUB:
- usb3503_reset(hub->gpio_reset, 1);
+ usb3503_reset(hub, 1);
+ if (hub->regmap) {
/* SP_ILOCK: set connect_n, config_n for config */
- err = usb3503_write_register(i2c, USB3503_SP_ILOCK,
- (USB3503_SPILOCK_CONNECT
+ err = regmap_write(hub->regmap, USB3503_SP_ILOCK,
+ (USB3503_SPILOCK_CONNECT
| USB3503_SPILOCK_CONFIG));
if (err < 0) {
- dev_err(&i2c->dev, "SP_ILOCK failed (%d)\n", err);
- goto err_hubmode;
+ dev_err(dev, "SP_ILOCK failed (%d)\n", err);
+ return err;
}
/* PDS : Disable For Self Powered Operation */
if (hub->port_off_mask) {
- err = usb3503_set_bits(i2c, USB3503_PDS,
+ err = regmap_update_bits(hub->regmap, USB3503_PDS,
+ hub->port_off_mask,
hub->port_off_mask);
if (err < 0) {
- dev_err(&i2c->dev, "PDS failed (%d)\n", err);
- goto err_hubmode;
+ dev_err(dev, "PDS failed (%d)\n", err);
+ return err;
}
}
/* CFG1 : SELF_BUS_PWR -> Self-Powerd operation */
- err = usb3503_set_bits(i2c, USB3503_CFG1, USB3503_SELF_BUS_PWR);
+ err = regmap_update_bits(hub->regmap, USB3503_CFG1,
+ USB3503_SELF_BUS_PWR,
+ USB3503_SELF_BUS_PWR);
if (err < 0) {
- dev_err(&i2c->dev, "CFG1 failed (%d)\n", err);
- goto err_hubmode;
+ dev_err(dev, "CFG1 failed (%d)\n", err);
+ return err;
}
/* SP_LOCK: clear connect_n, config_n for hub connect */
- err = usb3503_clear_bits(i2c, USB3503_SP_ILOCK,
- (USB3503_SPILOCK_CONNECT
- | USB3503_SPILOCK_CONFIG));
+ err = regmap_update_bits(hub->regmap, USB3503_SP_ILOCK,
+ (USB3503_SPILOCK_CONNECT
+ | USB3503_SPILOCK_CONFIG), 0);
if (err < 0) {
- dev_err(&i2c->dev, "SP_ILOCK failed (%d)\n", err);
- goto err_hubmode;
+ dev_err(dev, "SP_ILOCK failed (%d)\n", err);
+ return err;
}
+ }
- hub->mode = mode;
- dev_info(&i2c->dev, "switched to HUB mode\n");
+ if (gpio_is_valid(hub->gpio_connect))
+ gpio_set_value_cansleep(hub->gpio_connect, 1);
+
+ hub->mode = USB3503_MODE_HUB;
+ dev_info(dev, "switched to HUB mode\n");
+
+ return 0;
+}
+
+static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode)
+{
+ struct device *dev = hub->dev;
+ int err = 0;
+
+ switch (mode) {
+ case USB3503_MODE_HUB:
+ err = usb3503_connect(hub);
break;
case USB3503_MODE_STANDBY:
- usb3503_reset(hub->gpio_reset, 0);
+ usb3503_reset(hub, 0);
hub->mode = mode;
- dev_info(&i2c->dev, "switched to STANDBY mode\n");
+ dev_info(dev, "switched to STANDBY mode\n");
break;
default:
- dev_err(&i2c->dev, "unknown mode is request\n");
+ dev_err(dev, "unknown mode is requested\n");
err = -EINVAL;
break;
}
-err_hubmode:
return err;
}
-static int usb3503_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+static const struct regmap_config usb3503_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = USB3503_RESET,
+};
+
+static int usb3503_probe(struct usb3503 *hub)
{
- struct usb3503_platform_data *pdata = i2c->dev.platform_data;
- struct device_node *np = i2c->dev.of_node;
- struct usb3503 *hub;
- int err = -ENOMEM;
- u32 mode = USB3503_MODE_UNKNOWN;
+ struct device *dev = hub->dev;
+ struct usb3503_platform_data *pdata = dev_get_platdata(dev);
+ struct device_node *np = dev->of_node;
+ int err;
+ u32 mode = USB3503_MODE_HUB;
const u32 *property;
int len;
- hub = kzalloc(sizeof(struct usb3503), GFP_KERNEL);
- if (!hub) {
- dev_err(&i2c->dev, "private data alloc fail\n");
- return err;
- }
-
- i2c_set_clientdata(i2c, hub);
- hub->client = i2c;
-
if (pdata) {
hub->port_off_mask = pdata->port_off_mask;
hub->gpio_intn = pdata->gpio_intn;
@@ -215,10 +196,10 @@ static int usb3503_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
}
}
- hub->gpio_intn = of_get_named_gpio(np, "connect-gpios", 0);
+ hub->gpio_intn = of_get_named_gpio(np, "intn-gpios", 0);
if (hub->gpio_intn == -EPROBE_DEFER)
return -EPROBE_DEFER;
- hub->gpio_connect = of_get_named_gpio(np, "intn-gpios", 0);
+ hub->gpio_connect = of_get_named_gpio(np, "connect-gpios", 0);
if (hub->gpio_connect == -EPROBE_DEFER)
return -EPROBE_DEFER;
hub->gpio_reset = of_get_named_gpio(np, "reset-gpios", 0);
@@ -228,72 +209,86 @@ static int usb3503_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
hub->mode = mode;
}
+ if (hub->port_off_mask && !hub->regmap)
+ dev_err(dev, "Ports disabled with no control interface\n");
+
if (gpio_is_valid(hub->gpio_intn)) {
- err = gpio_request_one(hub->gpio_intn,
+ err = devm_gpio_request_one(dev, hub->gpio_intn,
GPIOF_OUT_INIT_HIGH, "usb3503 intn");
if (err) {
- dev_err(&i2c->dev,
- "unable to request GPIO %d as connect pin (%d)\n",
- hub->gpio_intn, err);
- goto err_out;
+ dev_err(dev,
+ "unable to request GPIO %d as connect pin (%d)\n",
+ hub->gpio_intn, err);
+ return err;
}
}
if (gpio_is_valid(hub->gpio_connect)) {
- err = gpio_request_one(hub->gpio_connect,
- GPIOF_OUT_INIT_HIGH, "usb3503 connect");
+ err = devm_gpio_request_one(dev, hub->gpio_connect,
+ GPIOF_OUT_INIT_LOW, "usb3503 connect");
if (err) {
- dev_err(&i2c->dev,
- "unable to request GPIO %d as connect pin (%d)\n",
- hub->gpio_connect, err);
- goto err_gpio_connect;
+ dev_err(dev,
+ "unable to request GPIO %d as connect pin (%d)\n",
+ hub->gpio_connect, err);
+ return err;
}
}
if (gpio_is_valid(hub->gpio_reset)) {
- err = gpio_request_one(hub->gpio_reset,
+ err = devm_gpio_request_one(dev, hub->gpio_reset,
GPIOF_OUT_INIT_LOW, "usb3503 reset");
if (err) {
- dev_err(&i2c->dev,
- "unable to request GPIO %d as reset pin (%d)\n",
- hub->gpio_reset, err);
- goto err_gpio_reset;
+ dev_err(dev,
+ "unable to request GPIO %d as reset pin (%d)\n",
+ hub->gpio_reset, err);
+ return err;
}
}
usb3503_switch_mode(hub, hub->mode);
- dev_info(&i2c->dev, "%s: probed on %s mode\n", __func__,
+ dev_info(dev, "%s: probed in %s mode\n", __func__,
(hub->mode == USB3503_MODE_HUB) ? "hub" : "standby");
return 0;
+}
-err_gpio_reset:
- if (gpio_is_valid(hub->gpio_connect))
- gpio_free(hub->gpio_connect);
-err_gpio_connect:
- if (gpio_is_valid(hub->gpio_intn))
- gpio_free(hub->gpio_intn);
-err_out:
- kfree(hub);
+static int usb3503_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct usb3503 *hub;
+ int err;
- return err;
+ hub = devm_kzalloc(&i2c->dev, sizeof(struct usb3503), GFP_KERNEL);
+ if (!hub) {
+ dev_err(&i2c->dev, "private data alloc fail\n");
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(i2c, hub);
+ hub->regmap = devm_regmap_init_i2c(i2c, &usb3503_regmap_config);
+ if (IS_ERR(hub->regmap)) {
+ err = PTR_ERR(hub->regmap);
+ dev_err(&i2c->dev, "Failed to initialise regmap: %d\n", err);
+ return err;
+ }
+ hub->dev = &i2c->dev;
+
+ return usb3503_probe(hub);
}
-static int usb3503_remove(struct i2c_client *i2c)
+static int usb3503_platform_probe(struct platform_device *pdev)
{
- struct usb3503 *hub = i2c_get_clientdata(i2c);
-
- if (gpio_is_valid(hub->gpio_intn))
- gpio_free(hub->gpio_intn);
- if (gpio_is_valid(hub->gpio_connect))
- gpio_free(hub->gpio_connect);
- if (gpio_is_valid(hub->gpio_reset))
- gpio_free(hub->gpio_reset);
+ struct usb3503 *hub;
- kfree(hub);
+ hub = devm_kzalloc(&pdev->dev, sizeof(struct usb3503), GFP_KERNEL);
+ if (!hub) {
+ dev_err(&pdev->dev, "private data alloc fail\n");
+ return -ENOMEM;
+ }
+ hub->dev = &pdev->dev;
- return 0;
+ return usb3503_probe(hub);
}
static const struct i2c_device_id usb3503_id[] = {
@@ -305,22 +300,53 @@ MODULE_DEVICE_TABLE(i2c, usb3503_id);
#ifdef CONFIG_OF
static const struct of_device_id usb3503_of_match[] = {
{ .compatible = "smsc,usb3503", },
+ { .compatible = "smsc,usb3503a", },
{},
};
MODULE_DEVICE_TABLE(of, usb3503_of_match);
#endif
-static struct i2c_driver usb3503_driver = {
+static struct i2c_driver usb3503_i2c_driver = {
.driver = {
.name = USB3503_I2C_NAME,
.of_match_table = of_match_ptr(usb3503_of_match),
},
- .probe = usb3503_probe,
- .remove = usb3503_remove,
+ .probe = usb3503_i2c_probe,
.id_table = usb3503_id,
};
-module_i2c_driver(usb3503_driver);
+static struct platform_driver usb3503_platform_driver = {
+ .driver = {
+ .name = USB3503_I2C_NAME,
+ .of_match_table = of_match_ptr(usb3503_of_match),
+ .owner = THIS_MODULE,
+ },
+ .probe = usb3503_platform_probe,
+};
+
+static int __init usb3503_init(void)
+{
+ int err;
+
+ err = i2c_register_driver(THIS_MODULE, &usb3503_i2c_driver);
+ if (err != 0)
+ pr_err("usb3503: Failed to register I2C driver: %d\n", err);
+
+ err = platform_driver_register(&usb3503_platform_driver);
+ if (err != 0)
+ pr_err("usb3503: Failed to register platform driver: %d\n",
+ err);
+
+ return 0;
+}
+module_init(usb3503_init);
+
+static void __exit usb3503_exit(void)
+{
+ platform_driver_unregister(&usb3503_platform_driver);
+ i2c_del_driver(&usb3503_i2c_driver);
+}
+module_exit(usb3503_exit);
MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>");
MODULE_DESCRIPTION("USB3503 USB HUB driver");
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 8b4ca1cb450..aa28ac8c760 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -747,9 +747,9 @@ static int ch9_postconfig(struct usbtest_dev *dev)
/* [9.4.5] get_status always works */
retval = usb_get_status(udev, USB_RECIP_DEVICE, 0, dev->buf);
- if (retval != 2) {
+ if (retval) {
dev_err(&iface->dev, "get dev status --> %d\n", retval);
- return (retval < 0) ? retval : -EDOM;
+ return retval;
}
/* FIXME configuration.bmAttributes says if we could try to set/clear
@@ -758,9 +758,9 @@ static int ch9_postconfig(struct usbtest_dev *dev)
retval = usb_get_status(udev, USB_RECIP_INTERFACE,
iface->altsetting[0].desc.bInterfaceNumber, dev->buf);
- if (retval != 2) {
+ if (retval) {
dev_err(&iface->dev, "get interface status --> %d\n", retval);
- return (retval < 0) ? retval : -EDOM;
+ return retval;
}
/* FIXME get status for each endpoint in the interface */
@@ -1351,7 +1351,6 @@ static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
ep, retval);
return retval;
}
- le16_to_cpus(&status);
if (status != 1) {
ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status);
return -EINVAL;
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index e129cf66122..40ef40affe8 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -75,7 +75,7 @@ struct uss720_async_request {
struct list_head asynclist;
struct completion compl;
struct urb *urb;
- struct usb_ctrlrequest dr;
+ struct usb_ctrlrequest *dr;
__u8 reg[7];
};
@@ -98,6 +98,7 @@ static void destroy_async(struct kref *kref)
if (likely(rq->urb))
usb_free_urb(rq->urb);
+ kfree(rq->dr);
spin_lock_irqsave(&priv->asynclock, flags);
list_del_init(&rq->asynclist);
spin_unlock_irqrestore(&priv->asynclock, flags);
@@ -120,7 +121,7 @@ static void async_complete(struct urb *urb)
if (status) {
dev_err(&urb->dev->dev, "async_complete: urb error %d\n",
status);
- } else if (rq->dr.bRequest == 3) {
+ } else if (rq->dr->bRequest == 3) {
memcpy(priv->reg, rq->reg, sizeof(priv->reg));
#if 0
dev_dbg(&priv->usbdev->dev,
@@ -152,7 +153,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
usbdev = priv->usbdev;
if (!usbdev)
return NULL;
- rq = kmalloc(sizeof(struct uss720_async_request), mem_flags);
+ rq = kzalloc(sizeof(struct uss720_async_request), mem_flags);
if (!rq) {
dev_err(&usbdev->dev, "submit_async_request out of memory\n");
return NULL;
@@ -168,13 +169,18 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
dev_err(&usbdev->dev, "submit_async_request out of memory\n");
return NULL;
}
- rq->dr.bRequestType = requesttype;
- rq->dr.bRequest = request;
- rq->dr.wValue = cpu_to_le16(value);
- rq->dr.wIndex = cpu_to_le16(index);
- rq->dr.wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);
+ rq->dr = kmalloc(sizeof(*rq->dr), mem_flags);
+ if (!rq->dr) {
+ kref_put(&rq->ref_count, destroy_async);
+ return NULL;
+ }
+ rq->dr->bRequestType = requesttype;
+ rq->dr->bRequest = request;
+ rq->dr->wValue = cpu_to_le16(value);
+ rq->dr->wIndex = cpu_to_le16(index);
+ rq->dr->wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);
usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0),
- (unsigned char *)&rq->dr,
+ (unsigned char *)rq->dr,
(request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq);
/* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */
spin_lock_irqsave(&priv->asynclock, flags);
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 797e3fd4551..c64ee09a7c0 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -83,6 +83,8 @@ config USB_MUSB_AM35X
config USB_MUSB_DSPS
tristate "TI DSPS platforms"
+ select USB_MUSB_AM335X_CHILD
+ depends on OF_IRQ
config USB_MUSB_BLACKFIN
tristate "Blackfin"
@@ -93,6 +95,9 @@ config USB_MUSB_UX500
endchoice
+config USB_MUSB_AM335X_CHILD
+ tristate
+
choice
prompt 'MUSB DMA mode'
default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
@@ -125,6 +130,10 @@ config USB_TI_CPPI_DMA
help
Enable DMA transfers when TI CPPI DMA is available.
+config USB_TI_CPPI41_DMA
+ bool 'TI CPPI 4.1 (AM335x)'
+ depends on ARCH_OMAP
+
config USB_TUSB_OMAP_DMA
bool 'TUSB 6010'
depends on USB_MUSB_TUSB6010
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 2b82ed7c85c..c5ea5c6dc16 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -20,6 +20,9 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
+
+obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o
+
# the kconfig must guarantee that only one of the
# possible I/O schemes will be enabled at a time ...
# PIO only, or DMA (several potential schemes).
@@ -29,3 +32,4 @@ musb_hdrc-$(CONFIG_USB_INVENTRA_DMA) += musbhsdma.o
musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA) += cppi_dma.o
musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA) += tusb6010_omap.o
musb_hdrc-$(CONFIG_USB_UX500_DMA) += ux500_dma.o
+musb_hdrc-$(CONFIG_USB_TI_CPPI41_DMA) += musb_cppi41.o
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index 2231850c062..5c310c66421 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -33,7 +33,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/platform_data/usb-omap.h>
#include "musb_core.h"
@@ -218,7 +218,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base;
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
struct usb_otg *otg = musb->xceiv->otg;
unsigned long flags;
@@ -335,7 +335,7 @@ eoi:
static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
{
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
int retval = 0;
@@ -350,7 +350,7 @@ static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
static int am35x_musb_init(struct musb *musb)
{
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
void __iomem *reg_base = musb->ctrl_base;
u32 rev;
@@ -394,7 +394,7 @@ static int am35x_musb_init(struct musb *musb)
static int am35x_musb_exit(struct musb *musb)
{
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
del_timer_sync(&otg_workaround);
@@ -456,7 +456,7 @@ static u64 am35x_dmamask = DMA_BIT_MASK(32);
static int am35x_probe(struct platform_device *pdev)
{
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct platform_device *musb;
struct am35x_glue *glue;
@@ -577,7 +577,7 @@ static int am35x_remove(struct platform_device *pdev)
static int am35x_suspend(struct device *dev)
{
struct am35x_glue *glue = dev_get_drvdata(dev);
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
/* Shutdown the on-chip PHY and its PLL. */
@@ -593,7 +593,7 @@ static int am35x_suspend(struct device *dev)
static int am35x_resume(struct device *dev)
{
struct am35x_glue *glue = dev_get_drvdata(dev);
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
int ret;
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 6ba8439bd5a..72e2056b608 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -19,7 +19,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/prefetch.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <asm/cacheflush.h>
@@ -451,7 +451,7 @@ static u64 bfin_dmamask = DMA_BIT_MASK(32);
static int bfin_probe(struct platform_device *pdev)
{
struct resource musb_resources[2];
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct platform_device *musb;
struct bfin_glue *glue;
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 9db211ee15b..904fb85d85a 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -150,14 +150,11 @@ static void cppi_pool_free(struct cppi_channel *c)
c->last_processed = NULL;
}
-static int cppi_controller_start(struct dma_controller *c)
+static void cppi_controller_start(struct cppi *controller)
{
- struct cppi *controller;
void __iomem *tibase;
int i;
- controller = container_of(c, struct cppi, controller);
-
/* do whatever is necessary to start controller */
for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
controller->tx[i].transmit = true;
@@ -212,8 +209,6 @@ static int cppi_controller_start(struct dma_controller *c)
/* disable RNDIS mode, also host rx RNDIS autorequest */
musb_writel(tibase, DAVINCI_RNDIS_REG, 0);
musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0);
-
- return 0;
}
/*
@@ -222,14 +217,12 @@ static int cppi_controller_start(struct dma_controller *c)
* De-Init the DMA controller as necessary.
*/
-static int cppi_controller_stop(struct dma_controller *c)
+static void cppi_controller_stop(struct cppi *controller)
{
- struct cppi *controller;
void __iomem *tibase;
int i;
struct musb *musb;
- controller = container_of(c, struct cppi, controller);
musb = controller->musb;
tibase = controller->tibase;
@@ -255,8 +248,6 @@ static int cppi_controller_stop(struct dma_controller *c)
/*disable tx/rx cppi */
musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
-
- return 0;
}
/* While dma channel is allocated, we only want the core irqs active
@@ -1321,8 +1312,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr
controller->tibase = mregs - DAVINCI_BASE_OFFSET;
controller->musb = musb;
- controller->controller.start = cppi_controller_start;
- controller->controller.stop = cppi_controller_stop;
controller->controller.channel_alloc = cppi_channel_allocate;
controller->controller.channel_release = cppi_channel_release;
controller->controller.channel_program = cppi_channel_program;
@@ -1351,6 +1340,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr
controller->irq = irq;
}
+ cppi_controller_start(controller);
return &controller->controller;
}
@@ -1363,6 +1353,8 @@ void dma_controller_destroy(struct dma_controller *c)
cppi = container_of(c, struct cppi, controller);
+ cppi_controller_stop(cppi);
+
if (cppi->irq)
free_irq(cppi->irq, cppi->musb);
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 0da6f648a9f..d9ddf4122f3 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -33,7 +33,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <mach/da8xx.h>
#include <linux/platform_data/usb-davinci.h>
@@ -477,7 +477,7 @@ static u64 da8xx_dmamask = DMA_BIT_MASK(32);
static int da8xx_probe(struct platform_device *pdev)
{
struct resource musb_resources[2];
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct platform_device *musb;
struct da8xx_glue *glue;
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index f8aeaf2e2cd..ed0834e2b72 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -33,7 +33,7 @@
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <mach/cputype.h>
#include <mach/hardware.h>
@@ -510,7 +510,7 @@ static u64 davinci_dmamask = DMA_BIT_MASK(32);
static int davinci_probe(struct platform_device *pdev)
{
struct resource musb_resources[2];
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct platform_device *musb;
struct davinci_glue *glue;
struct clk *clk;
diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c
new file mode 100644
index 00000000000..41ac5b5b57c
--- /dev/null
+++ b/drivers/usb/musb/musb_am335x.c
@@ -0,0 +1,55 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+
+static int am335x_child_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+}
+
+static int of_remove_populated_child(struct device *dev, void *d)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ of_device_unregister(pdev);
+ return 0;
+}
+
+static int am335x_child_remove(struct platform_device *pdev)
+{
+ device_for_each_child(&pdev->dev, NULL, of_remove_populated_child);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id am335x_child_of_match[] = {
+ { .compatible = "ti,am33xx-usb" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, am335x_child_of_match);
+
+static struct platform_driver am335x_child_driver = {
+ .probe = am335x_child_probe,
+ .remove = am335x_child_remove,
+ .driver = {
+ .name = "am335x-usb-childs",
+ .of_match_table = of_match_ptr(am335x_child_of_match),
+ },
+};
+
+module_platform_driver(am335x_child_driver);
+MODULE_DESCRIPTION("AM33xx child devices");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 29a24ced674..18e877ffe7b 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -99,7 +99,6 @@
#include <linux/prefetch.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/idr.h>
#include <linux/dma-mapping.h>
#include "musb_core.h"
@@ -1764,12 +1763,8 @@ static void musb_free(struct musb *musb)
disable_irq_wake(musb->nIrq);
free_irq(musb->nIrq, musb);
}
- if (is_dma_capable() && musb->dma_controller) {
- struct dma_controller *c = musb->dma_controller;
-
- (void) c->stop(c);
- dma_controller_destroy(c);
- }
+ if (musb->dma_controller)
+ dma_controller_destroy(musb->dma_controller);
musb_host_free(musb);
}
@@ -1787,7 +1782,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
{
int status;
struct musb *musb;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
/* The driver might handle more features than the board; OK.
* Fail when the board needs a feature that's not enabled.
@@ -1844,19 +1839,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
pm_runtime_get_sync(musb->controller);
-#ifndef CONFIG_MUSB_PIO_ONLY
- if (use_dma && dev->dma_mask) {
- struct dma_controller *c;
-
- c = dma_controller_create(musb, musb->mregs);
- musb->dma_controller = c;
- if (c)
- (void) c->start(c);
- }
-#endif
- /* ideally this would be abstracted in platform setup */
- if (!is_dma_capable() || !musb->dma_controller)
- dev->dma_mask = NULL;
+ if (use_dma && dev->dma_mask)
+ musb->dma_controller = dma_controller_create(musb, musb->mregs);
/* be sure interrupts are disabled before connecting ISR */
musb_platform_disable(musb);
@@ -1944,6 +1928,8 @@ fail4:
musb_gadget_cleanup(musb);
fail3:
+ if (musb->dma_controller)
+ dma_controller_destroy(musb->dma_controller);
pm_runtime_put_sync(musb->controller);
fail2:
@@ -2002,9 +1988,6 @@ static int musb_remove(struct platform_device *pdev)
musb_free(musb);
device_init_wakeup(dev, 0);
-#ifndef CONFIG_MUSB_PIO_ONLY
- dma_set_mask(dev, *dev->parent->dma_mask);
-#endif
return 0;
}
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 7d341c387ea..65f3917b4fc 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -83,11 +83,6 @@ enum {
MUSB_PORT_MODE_DUAL_ROLE,
};
-#ifdef CONFIG_PROC_FS
-#include <linux/fs.h>
-#define MUSB_CONFIG_PROC_FS
-#endif
-
/****************************** CONSTANTS ********************************/
#ifndef MUSB_C_NUM_EPS
@@ -425,9 +420,6 @@ struct musb {
struct musb_hdrc_config *config;
-#ifdef MUSB_CONFIG_PROC_FS
- struct proc_dir_entry *proc_entry;
-#endif
int xceiv_old_state;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
new file mode 100644
index 00000000000..ae959746f77
--- /dev/null
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -0,0 +1,557 @@
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/sizes.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include "musb_core.h"
+
+#define RNDIS_REG(x) (0x80 + ((x - 1) * 4))
+
+#define EP_MODE_AUTOREG_NONE 0
+#define EP_MODE_AUTOREG_ALL_NEOP 1
+#define EP_MODE_AUTOREG_ALWAYS 3
+
+#define EP_MODE_DMA_TRANSPARENT 0
+#define EP_MODE_DMA_RNDIS 1
+#define EP_MODE_DMA_GEN_RNDIS 3
+
+#define USB_CTRL_TX_MODE 0x70
+#define USB_CTRL_RX_MODE 0x74
+#define USB_CTRL_AUTOREQ 0xd0
+#define USB_TDOWN 0xd8
+
+struct cppi41_dma_channel {
+ struct dma_channel channel;
+ struct cppi41_dma_controller *controller;
+ struct musb_hw_ep *hw_ep;
+ struct dma_chan *dc;
+ dma_cookie_t cookie;
+ u8 port_num;
+ u8 is_tx;
+ u8 is_allocated;
+ u8 usb_toggle;
+
+ dma_addr_t buf_addr;
+ u32 total_len;
+ u32 prog_len;
+ u32 transferred;
+ u32 packet_sz;
+};
+
+#define MUSB_DMA_NUM_CHANNELS 15
+
+struct cppi41_dma_controller {
+ struct dma_controller controller;
+ struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS];
+ struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS];
+ struct musb *musb;
+ u32 rx_mode;
+ u32 tx_mode;
+ u32 auto_req;
+};
+
+static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
+{
+ u16 csr;
+ u8 toggle;
+
+ if (cppi41_channel->is_tx)
+ return;
+ if (!is_host_active(cppi41_channel->controller->musb))
+ return;
+
+ csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+ toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
+
+ cppi41_channel->usb_toggle = toggle;
+}
+
+static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
+{
+ u16 csr;
+ u8 toggle;
+
+ if (cppi41_channel->is_tx)
+ return;
+ if (!is_host_active(cppi41_channel->controller->musb))
+ return;
+
+ csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+ toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
+
+ /*
+ * AM335x Advisory 1.0.13: Due to internal synchronisation error the
+ * data toggle may reset from DATA1 to DATA0 during receiving data from
+ * more than one endpoint.
+ */
+ if (!toggle && toggle == cppi41_channel->usb_toggle) {
+ csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE;
+ musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr);
+ dev_dbg(cppi41_channel->controller->musb->controller,
+ "Restoring DATA1 toggle.\n");
+ }
+
+ cppi41_channel->usb_toggle = toggle;
+}
+
+static void cppi41_dma_callback(void *private_data)
+{
+ struct dma_channel *channel = private_data;
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
+ struct musb *musb = hw_ep->musb;
+ unsigned long flags;
+ struct dma_tx_state txstate;
+ u32 transferred;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie,
+ &txstate);
+ transferred = cppi41_channel->prog_len - txstate.residue;
+ cppi41_channel->transferred += transferred;
+
+ dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n",
+ hw_ep->epnum, cppi41_channel->transferred,
+ cppi41_channel->total_len);
+
+ update_rx_toggle(cppi41_channel);
+
+ if (cppi41_channel->transferred == cppi41_channel->total_len ||
+ transferred < cppi41_channel->packet_sz) {
+
+ /* done, complete */
+ cppi41_channel->channel.actual_len =
+ cppi41_channel->transferred;
+ cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+ musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
+ } else {
+ /* next iteration, reload */
+ struct dma_chan *dc = cppi41_channel->dc;
+ struct dma_async_tx_descriptor *dma_desc;
+ enum dma_transfer_direction direction;
+ u16 csr;
+ u32 remain_bytes;
+ void __iomem *epio = cppi41_channel->hw_ep->regs;
+
+ cppi41_channel->buf_addr += cppi41_channel->packet_sz;
+
+ remain_bytes = cppi41_channel->total_len;
+ remain_bytes -= cppi41_channel->transferred;
+ remain_bytes = min(remain_bytes, cppi41_channel->packet_sz);
+ cppi41_channel->prog_len = remain_bytes;
+
+ direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV
+ : DMA_DEV_TO_MEM;
+ dma_desc = dmaengine_prep_slave_single(dc,
+ cppi41_channel->buf_addr,
+ remain_bytes,
+ direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (WARN_ON(!dma_desc)) {
+ spin_unlock_irqrestore(&musb->lock, flags);
+ return;
+ }
+
+ dma_desc->callback = cppi41_dma_callback;
+ dma_desc->callback_param = channel;
+ cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+ dma_async_issue_pending(dc);
+
+ if (!cppi41_channel->is_tx) {
+ csr = musb_readw(epio, MUSB_RXCSR);
+ csr |= MUSB_RXCSR_H_REQPKT;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static u32 update_ep_mode(unsigned ep, unsigned mode, u32 old)
+{
+ unsigned shift;
+
+ shift = (ep - 1) * 2;
+ old &= ~(3 << shift);
+ old |= mode << shift;
+ return old;
+}
+
+static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel,
+ unsigned mode)
+{
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ u32 port;
+ u32 new_mode;
+ u32 old_mode;
+
+ if (cppi41_channel->is_tx)
+ old_mode = controller->tx_mode;
+ else
+ old_mode = controller->rx_mode;
+ port = cppi41_channel->port_num;
+ new_mode = update_ep_mode(port, mode, old_mode);
+
+ if (new_mode == old_mode)
+ return;
+ if (cppi41_channel->is_tx) {
+ controller->tx_mode = new_mode;
+ musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE,
+ new_mode);
+ } else {
+ controller->rx_mode = new_mode;
+ musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE,
+ new_mode);
+ }
+}
+
+static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel,
+ unsigned mode)
+{
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ u32 port;
+ u32 new_mode;
+ u32 old_mode;
+
+ old_mode = controller->auto_req;
+ port = cppi41_channel->port_num;
+ new_mode = update_ep_mode(port, mode, old_mode);
+
+ if (new_mode == old_mode)
+ return;
+ controller->auto_req = new_mode;
+ musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode);
+}
+
+static bool cppi41_configure_channel(struct dma_channel *channel,
+ u16 packet_sz, u8 mode,
+ dma_addr_t dma_addr, u32 len)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ struct dma_chan *dc = cppi41_channel->dc;
+ struct dma_async_tx_descriptor *dma_desc;
+ enum dma_transfer_direction direction;
+ struct musb *musb = cppi41_channel->controller->musb;
+ unsigned use_gen_rndis = 0;
+
+ dev_dbg(musb->controller,
+ "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n",
+ cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num),
+ packet_sz, mode, (unsigned long long) dma_addr,
+ len, cppi41_channel->is_tx);
+
+ cppi41_channel->buf_addr = dma_addr;
+ cppi41_channel->total_len = len;
+ cppi41_channel->transferred = 0;
+ cppi41_channel->packet_sz = packet_sz;
+
+ /*
+ * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more
+ * than max packet size at a time.
+ */
+ if (cppi41_channel->is_tx)
+ use_gen_rndis = 1;
+
+ if (use_gen_rndis) {
+ /* RNDIS mode */
+ if (len > packet_sz) {
+ musb_writel(musb->ctrl_base,
+ RNDIS_REG(cppi41_channel->port_num), len);
+ /* gen rndis */
+ cppi41_set_dma_mode(cppi41_channel,
+ EP_MODE_DMA_GEN_RNDIS);
+
+ /* auto req */
+ cppi41_set_autoreq_mode(cppi41_channel,
+ EP_MODE_AUTOREG_ALL_NEOP);
+ } else {
+ musb_writel(musb->ctrl_base,
+ RNDIS_REG(cppi41_channel->port_num), 0);
+ cppi41_set_dma_mode(cppi41_channel,
+ EP_MODE_DMA_TRANSPARENT);
+ cppi41_set_autoreq_mode(cppi41_channel,
+ EP_MODE_AUTOREG_NONE);
+ }
+ } else {
+ /* fallback mode */
+ cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
+ cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
+ len = min_t(u32, packet_sz, len);
+ }
+ cppi41_channel->prog_len = len;
+ direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+ dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dma_desc)
+ return false;
+
+ dma_desc->callback = cppi41_dma_callback;
+ dma_desc->callback_param = channel;
+ cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+
+ save_rx_toggle(cppi41_channel);
+ dma_async_issue_pending(dc);
+ return true;
+}
+
+static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c,
+ struct musb_hw_ep *hw_ep, u8 is_tx)
+{
+ struct cppi41_dma_controller *controller = container_of(c,
+ struct cppi41_dma_controller, controller);
+ struct cppi41_dma_channel *cppi41_channel = NULL;
+ u8 ch_num = hw_ep->epnum - 1;
+
+ if (ch_num >= MUSB_DMA_NUM_CHANNELS)
+ return NULL;
+
+ if (is_tx)
+ cppi41_channel = &controller->tx_channel[ch_num];
+ else
+ cppi41_channel = &controller->rx_channel[ch_num];
+
+ if (!cppi41_channel->dc)
+ return NULL;
+
+ if (cppi41_channel->is_allocated)
+ return NULL;
+
+ cppi41_channel->hw_ep = hw_ep;
+ cppi41_channel->is_allocated = 1;
+
+ return &cppi41_channel->channel;
+}
+
+static void cppi41_dma_channel_release(struct dma_channel *channel)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+
+ if (cppi41_channel->is_allocated) {
+ cppi41_channel->is_allocated = 0;
+ channel->status = MUSB_DMA_STATUS_FREE;
+ channel->actual_len = 0;
+ }
+}
+
+static int cppi41_dma_channel_program(struct dma_channel *channel,
+ u16 packet_sz, u8 mode,
+ dma_addr_t dma_addr, u32 len)
+{
+ int ret;
+
+ BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
+ channel->status == MUSB_DMA_STATUS_BUSY);
+
+ channel->status = MUSB_DMA_STATUS_BUSY;
+ channel->actual_len = 0;
+ ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len);
+ if (!ret)
+ channel->status = MUSB_DMA_STATUS_FREE;
+
+ return ret;
+}
+
+static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket,
+ void *buf, u32 length)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ struct musb *musb = controller->musb;
+
+ if (is_host_active(musb)) {
+ WARN_ON(1);
+ return 1;
+ }
+ if (cppi41_channel->is_tx)
+ return 1;
+ /* AM335x Advisory 1.0.13. No workaround for device RX mode */
+ return 0;
+}
+
+static int cppi41_dma_channel_abort(struct dma_channel *channel)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ struct musb *musb = controller->musb;
+ void __iomem *epio = cppi41_channel->hw_ep->regs;
+ int tdbit;
+ int ret;
+ unsigned is_tx;
+ u16 csr;
+
+ is_tx = cppi41_channel->is_tx;
+ dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n",
+ cppi41_channel->port_num, is_tx);
+
+ if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)
+ return 0;
+
+ if (is_tx) {
+ csr = musb_readw(epio, MUSB_TXCSR);
+ csr &= ~MUSB_TXCSR_DMAENAB;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ } else {
+ csr = musb_readw(epio, MUSB_RXCSR);
+ csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB);
+ musb_writew(epio, MUSB_RXCSR, csr);
+
+ csr = musb_readw(epio, MUSB_RXCSR);
+ if (csr & MUSB_RXCSR_RXPKTRDY) {
+ csr |= MUSB_RXCSR_FLUSHFIFO;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+ }
+
+ tdbit = 1 << cppi41_channel->port_num;
+ if (is_tx)
+ tdbit <<= 16;
+
+ do {
+ musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+ ret = dmaengine_terminate_all(cppi41_channel->dc);
+ } while (ret == -EAGAIN);
+
+ musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+
+ if (is_tx) {
+ csr = musb_readw(epio, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_TXPKTRDY) {
+ csr |= MUSB_TXCSR_FLUSHFIFO;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ }
+ }
+
+ cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+ return 0;
+}
+
+static void cppi41_release_all_dma_chans(struct cppi41_dma_controller *ctrl)
+{
+ struct dma_chan *dc;
+ int i;
+
+ for (i = 0; i < MUSB_DMA_NUM_CHANNELS; i++) {
+ dc = ctrl->tx_channel[i].dc;
+ if (dc)
+ dma_release_channel(dc);
+ dc = ctrl->rx_channel[i].dc;
+ if (dc)
+ dma_release_channel(dc);
+ }
+}
+
+static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller)
+{
+ cppi41_release_all_dma_chans(controller);
+}
+
+static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
+{
+ struct musb *musb = controller->musb;
+ struct device *dev = musb->controller;
+ struct device_node *np = dev->of_node;
+ struct cppi41_dma_channel *cppi41_channel;
+ int count;
+ int i;
+ int ret;
+
+ count = of_property_count_strings(np, "dma-names");
+ if (count < 0)
+ return count;
+
+ for (i = 0; i < count; i++) {
+ struct dma_chan *dc;
+ struct dma_channel *musb_dma;
+ const char *str;
+ unsigned is_tx;
+ unsigned int port;
+
+ ret = of_property_read_string_index(np, "dma-names", i, &str);
+ if (ret)
+ goto err;
+ if (!strncmp(str, "tx", 2))
+ is_tx = 1;
+ else if (!strncmp(str, "rx", 2))
+ is_tx = 0;
+ else {
+ dev_err(dev, "Wrong dmatype %s\n", str);
+ goto err;
+ }
+ ret = kstrtouint(str + 2, 0, &port);
+ if (ret)
+ goto err;
+
+ if (port > MUSB_DMA_NUM_CHANNELS || !port)
+ goto err;
+ if (is_tx)
+ cppi41_channel = &controller->tx_channel[port - 1];
+ else
+ cppi41_channel = &controller->rx_channel[port - 1];
+
+ cppi41_channel->controller = controller;
+ cppi41_channel->port_num = port;
+ cppi41_channel->is_tx = is_tx;
+
+ musb_dma = &cppi41_channel->channel;
+ musb_dma->private_data = cppi41_channel;
+ musb_dma->status = MUSB_DMA_STATUS_FREE;
+ musb_dma->max_len = SZ_4M;
+
+ dc = dma_request_slave_channel(dev, str);
+ if (!dc) {
+ dev_err(dev, "Falied to request %s.\n", str);
+ goto err;
+ }
+ cppi41_channel->dc = dc;
+ }
+ return 0;
+err:
+ cppi41_release_all_dma_chans(controller);
+ return -EINVAL;
+}
+
+void dma_controller_destroy(struct dma_controller *c)
+{
+ struct cppi41_dma_controller *controller = container_of(c,
+ struct cppi41_dma_controller, controller);
+
+ cppi41_dma_controller_stop(controller);
+ kfree(controller);
+}
+
+struct dma_controller *dma_controller_create(struct musb *musb,
+ void __iomem *base)
+{
+ struct cppi41_dma_controller *controller;
+ int ret;
+
+ if (!musb->controller->of_node) {
+ dev_err(musb->controller, "Need DT for the DMA engine.\n");
+ return NULL;
+ }
+
+ controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+ if (!controller)
+ goto kzalloc_fail;
+
+ controller->musb = musb;
+
+ controller->controller.channel_alloc = cppi41_dma_channel_allocate;
+ controller->controller.channel_release = cppi41_dma_channel_release;
+ controller->controller.channel_program = cppi41_dma_channel_program;
+ controller->controller.channel_abort = cppi41_dma_channel_abort;
+ controller->controller.is_compatible = cppi41_is_compatible;
+
+ ret = cppi41_dma_controller_start(controller);
+ if (ret)
+ goto plat_get_fail;
+ return &controller->controller;
+
+plat_get_fail:
+ kfree(controller);
+kzalloc_fail:
+ return NULL;
+}
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 1b6b827b769..1345a4ff041 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -62,13 +62,13 @@ struct musb_hw_ep;
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-#ifndef CONFIG_MUSB_PIO_ONLY
-#define is_dma_capable() (1)
-#else
+#ifdef CONFIG_MUSB_PIO_ONLY
#define is_dma_capable() (0)
+#else
+#define is_dma_capable() (1)
#endif
-#ifdef CONFIG_USB_TI_CPPI_DMA
+#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA)
#define is_cppi_enabled() 1
#else
#define is_cppi_enabled() 0
@@ -159,8 +159,6 @@ dma_channel_status(struct dma_channel *c)
* Controllers manage dma channels.
*/
struct dma_controller {
- int (*start)(struct dma_controller *);
- int (*stop)(struct dma_controller *);
struct dma_channel *(*channel_alloc)(struct dma_controller *,
struct musb_hw_ep *, u8 is_tx);
void (*channel_release)(struct dma_channel *);
@@ -177,9 +175,20 @@ struct dma_controller {
/* called after channel_program(), may indicate a fault */
extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
+#ifdef CONFIG_MUSB_PIO_ONLY
+static inline struct dma_controller *dma_controller_create(struct musb *m,
+ void __iomem *io)
+{
+ return NULL;
+}
+
+static inline void dma_controller_destroy(struct dma_controller *d) { }
+
+#else
extern struct dma_controller *dma_controller_create(struct musb *, void __iomem *);
extern void dma_controller_destroy(struct dma_controller *);
+#endif
#endif /* __MUSB_DMA_H__ */
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 5233804d66b..4047cbb91ba 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -36,19 +36,19 @@
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/module.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/platform_data/usb-omap.h>
#include <linux/sizes.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/usb/of.h>
#include "musb_core.h"
-#ifdef CONFIG_OF
static const struct of_device_id musb_dsps_of_match[];
-#endif
/**
* avoid using musb_readx()/musb_writex() as glue layer should not be
@@ -75,7 +75,6 @@ struct dsps_musb_wrapper {
u16 revision;
u16 control;
u16 status;
- u16 eoi;
u16 epintr_set;
u16 epintr_clear;
u16 epintr_status;
@@ -108,10 +107,7 @@ struct dsps_musb_wrapper {
/* bit positions for mode */
unsigned iddig:5;
/* miscellaneous stuff */
- u32 musb_core_offset;
u8 poll_seconds;
- /* number of musb instances */
- u8 instances;
};
/**
@@ -119,53 +115,12 @@ struct dsps_musb_wrapper {
*/
struct dsps_glue {
struct device *dev;
- struct platform_device *musb[2]; /* child musb pdev */
+ struct platform_device *musb; /* child musb pdev */
const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
- struct timer_list timer[2]; /* otg_workaround timer */
- unsigned long last_timer[2]; /* last timer data for each instance */
- u32 __iomem *usb_ctrl[2];
+ struct timer_list timer; /* otg_workaround timer */
+ unsigned long last_timer; /* last timer data for each instance */
};
-#define DSPS_AM33XX_CONTROL_MODULE_PHYS_0 0x44e10620
-#define DSPS_AM33XX_CONTROL_MODULE_PHYS_1 0x44e10628
-
-static const resource_size_t dsps_control_module_phys[] = {
- DSPS_AM33XX_CONTROL_MODULE_PHYS_0,
- DSPS_AM33XX_CONTROL_MODULE_PHYS_1,
-};
-
-#define USBPHY_CM_PWRDN (1 << 0)
-#define USBPHY_OTG_PWRDN (1 << 1)
-#define USBPHY_OTGVDET_EN (1 << 19)
-#define USBPHY_OTGSESSEND_EN (1 << 20)
-
-/**
- * musb_dsps_phy_control - phy on/off
- * @glue: struct dsps_glue *
- * @id: musb instance
- * @on: flag for phy to be switched on or off
- *
- * This is to enable the PHY using usb_ctrl register in system control
- * module space.
- *
- * XXX: This function will be removed once we have a seperate driver for
- * control module
- */
-static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on)
-{
- u32 usbphycfg;
-
- usbphycfg = readl(glue->usb_ctrl[id]);
-
- if (on) {
- usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
- usbphycfg |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
- } else {
- usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
- }
-
- writel(usbphycfg, glue->usb_ctrl[id]);
-}
/**
* dsps_musb_enable - enable interrupts
*/
@@ -205,7 +160,6 @@ static void dsps_musb_disable(struct musb *musb)
dsps_writel(reg_base, wrp->epintr_clear,
wrp->txep_bitmap | wrp->rxep_bitmap);
dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
- dsps_writel(reg_base, wrp->eoi, 0);
}
static void otg_timer(unsigned long _musb)
@@ -213,7 +167,6 @@ static void otg_timer(unsigned long _musb)
struct musb *musb = (void *)_musb;
void __iomem *mregs = musb->mregs;
struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp;
u8 devctl;
@@ -250,7 +203,7 @@ static void otg_timer(unsigned long _musb)
case OTG_STATE_B_IDLE:
devctl = dsps_readb(mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE)
- mod_timer(&glue->timer[pdev->id],
+ mod_timer(&glue->timer,
jiffies + wrp->poll_seconds * HZ);
else
musb->xceiv->state = OTG_STATE_A_IDLE;
@@ -264,7 +217,6 @@ static void otg_timer(unsigned long _musb)
static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
{
struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
if (timeout == 0)
@@ -275,23 +227,25 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
usb_otg_state_string(musb->xceiv->state));
- del_timer(&glue->timer[pdev->id]);
- glue->last_timer[pdev->id] = jiffies;
+ del_timer(&glue->timer);
+ glue->last_timer = jiffies;
return;
}
+ if (musb->port_mode == MUSB_PORT_MODE_HOST)
+ return;
- if (time_after(glue->last_timer[pdev->id], timeout) &&
- timer_pending(&glue->timer[pdev->id])) {
+ if (time_after(glue->last_timer, timeout) &&
+ timer_pending(&glue->timer)) {
dev_dbg(musb->controller,
"Longer idle timer already pending, ignoring...\n");
return;
}
- glue->last_timer[pdev->id] = timeout;
+ glue->last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies));
- mod_timer(&glue->timer[pdev->id], timeout);
+ mod_timer(&glue->timer, timeout);
}
static irqreturn_t dsps_interrupt(int irq, void *hci)
@@ -299,7 +253,6 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base;
struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp;
unsigned long flags;
@@ -319,7 +272,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
/* Get usb core interrupts */
usbintr = dsps_readl(reg_base, wrp->coreintr_status);
if (!usbintr && !epintr)
- goto eoi;
+ goto out;
musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
if (usbintr)
@@ -359,15 +312,14 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
*/
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
- mod_timer(&glue->timer[pdev->id],
+ mod_timer(&glue->timer,
jiffies + wrp->poll_seconds * HZ);
WARNING("VBUS error workaround (delay coming)\n");
} else if (drvvbus) {
- musb->is_active = 1;
MUSB_HST_MODE(musb);
musb->xceiv->otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
- del_timer(&glue->timer[pdev->id]);
+ del_timer(&glue->timer);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
@@ -387,16 +339,10 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
if (musb->int_tx || musb->int_rx || musb->int_usb)
ret |= musb_interrupt(musb);
- eoi:
- /* EOI needs to be written for the IRQ to be re-asserted. */
- if (ret == IRQ_HANDLED || epintr || usbintr)
- dsps_writel(reg_base, wrp->eoi, 1);
-
/* Poll for ID change */
if (musb->xceiv->state == OTG_STATE_B_IDLE)
- mod_timer(&glue->timer[pdev->id],
- jiffies + wrp->poll_seconds * HZ);
-
+ mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
+out:
spin_unlock_irqrestore(&musb->lock, flags);
return ret;
@@ -405,37 +351,38 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
static int dsps_musb_init(struct musb *musb)
{
struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
+ struct platform_device *parent = to_platform_device(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp;
- void __iomem *reg_base = musb->ctrl_base;
+ void __iomem *reg_base;
+ struct resource *r;
u32 rev, val;
- int status;
- /* mentor core register starts at offset of 0x400 from musb base */
- musb->mregs += wrp->musb_core_offset;
+ r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
+ if (!r)
+ return -EINVAL;
+
+ reg_base = devm_ioremap_resource(dev, r);
+ if (IS_ERR(reg_base))
+ return PTR_ERR(reg_base);
+ musb->ctrl_base = reg_base;
/* NOP driver needs change if supporting dual instance */
- usb_nop_xceiv_register();
- musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(musb->xceiv))
- return -EPROBE_DEFER;
+ musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
+ if (IS_ERR(musb->xceiv))
+ return PTR_ERR(musb->xceiv);
/* Returns zero if e.g. not clocked */
rev = dsps_readl(reg_base, wrp->revision);
- if (!rev) {
- status = -ENODEV;
- goto err0;
- }
+ if (!rev)
+ return -ENODEV;
- setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb);
+ usb_phy_init(musb->xceiv);
+ setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
/* Reset the musb */
dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
- /* Start the on-chip PHY and its PLL. */
- musb_dsps_phy_control(glue, pdev->id, 1);
-
musb->isr = dsps_interrupt;
/* reset the otgdisable bit, needed for host mode to work */
@@ -443,31 +390,17 @@ static int dsps_musb_init(struct musb *musb)
val &= ~(1 << wrp->otg_disable);
dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
- /* clear level interrupt */
- dsps_writel(reg_base, wrp->eoi, 0);
-
return 0;
-err0:
- usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
- return status;
}
static int dsps_musb_exit(struct musb *musb)
{
struct device *dev = musb->controller;
- struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
- del_timer_sync(&glue->timer[pdev->id]);
-
- /* Shutdown the on-chip PHY and its PLL. */
- musb_dsps_phy_control(glue, pdev->id, 0);
-
- /* NOP driver needs change if supporting dual instance */
- usb_put_phy(musb->xceiv);
- usb_nop_xceiv_unregister();
+ del_timer_sync(&glue->timer);
+ usb_phy_shutdown(musb->xceiv);
return 0;
}
@@ -483,116 +416,115 @@ static struct musb_platform_ops dsps_ops = {
static u64 musb_dmamask = DMA_BIT_MASK(32);
-static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
+static int get_int_prop(struct device_node *dn, const char *s)
{
- struct device *dev = glue->dev;
- struct platform_device *pdev = to_platform_device(dev);
- struct musb_hdrc_platform_data *pdata = dev->platform_data;
- struct device_node *np = pdev->dev.of_node;
- struct musb_hdrc_config *config;
- struct platform_device *musb;
- struct resource *res;
- struct resource resources[2];
- char res_name[11];
int ret;
+ u32 val;
- resources[0].start = dsps_control_module_phys[id];
- resources[0].end = resources[0].start + SZ_4 - 1;
- resources[0].flags = IORESOURCE_MEM;
+ ret = of_property_read_u32(dn, s, &val);
+ if (ret)
+ return 0;
+ return val;
+}
- glue->usb_ctrl[id] = devm_ioremap_resource(&pdev->dev, resources);
- if (IS_ERR(glue->usb_ctrl[id])) {
- ret = PTR_ERR(glue->usb_ctrl[id]);
- goto err0;
- }
+static int get_musb_port_mode(struct device *dev)
+{
+ enum usb_dr_mode mode;
+
+ mode = of_usb_get_dr_mode(dev->of_node);
+ switch (mode) {
+ case USB_DR_MODE_HOST:
+ return MUSB_PORT_MODE_HOST;
+
+ case USB_DR_MODE_PERIPHERAL:
+ return MUSB_PORT_MODE_GADGET;
+
+ case USB_DR_MODE_UNKNOWN:
+ case USB_DR_MODE_OTG:
+ default:
+ return MUSB_PORT_MODE_DUAL_ROLE;
+ };
+}
+
+static int dsps_create_musb_pdev(struct dsps_glue *glue,
+ struct platform_device *parent)
+{
+ struct musb_hdrc_platform_data pdata;
+ struct resource resources[2];
+ struct resource *res;
+ struct device *dev = &parent->dev;
+ struct musb_hdrc_config *config;
+ struct platform_device *musb;
+ struct device_node *dn = parent->dev.of_node;
+ int ret;
- /* first resource is for usbss, so start index from 1 */
- res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1);
+ memset(resources, 0, sizeof(resources));
+ res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc");
if (!res) {
- dev_err(dev, "failed to get memory for instance %d\n", id);
- ret = -ENODEV;
- goto err0;
+ dev_err(dev, "failed to get memory.\n");
+ return -EINVAL;
}
- res->parent = NULL;
resources[0] = *res;
- /* first resource is for usbss, so start index from 1 */
- res = platform_get_resource(pdev, IORESOURCE_IRQ, id + 1);
+ res = platform_get_resource_byname(parent, IORESOURCE_IRQ, "mc");
if (!res) {
- dev_err(dev, "failed to get irq for instance %d\n", id);
- ret = -ENODEV;
- goto err0;
+ dev_err(dev, "failed to get irq.\n");
+ return -EINVAL;
}
- res->parent = NULL;
resources[1] = *res;
- resources[1].name = "mc";
/* allocate the child platform device */
musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
if (!musb) {
dev_err(dev, "failed to allocate musb device\n");
- ret = -ENOMEM;
- goto err0;
+ return -ENOMEM;
}
musb->dev.parent = dev;
musb->dev.dma_mask = &musb_dmamask;
musb->dev.coherent_dma_mask = musb_dmamask;
+ musb->dev.of_node = of_node_get(dn);
- glue->musb[id] = musb;
+ glue->musb = musb;
- ret = platform_device_add_resources(musb, resources, 2);
+ ret = platform_device_add_resources(musb, resources,
+ ARRAY_SIZE(resources));
if (ret) {
dev_err(dev, "failed to add resources\n");
- goto err2;
+ goto err;
}
- if (np) {
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev,
- "failed to allocate musb platform data\n");
- ret = -ENOMEM;
- goto err2;
- }
-
- config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
- if (!config) {
- dev_err(&pdev->dev,
- "failed to allocate musb hdrc config\n");
- ret = -ENOMEM;
- goto err2;
- }
-
- of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
- of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
- snprintf(res_name, sizeof(res_name), "port%d-mode", id);
- of_property_read_u32(np, res_name, (u32 *)&pdata->mode);
- of_property_read_u32(np, "power", (u32 *)&pdata->power);
- config->multipoint = of_property_read_bool(np, "multipoint");
-
- pdata->config = config;
+ config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL);
+ if (!config) {
+ dev_err(dev, "failed to allocate musb hdrc config\n");
+ ret = -ENOMEM;
+ goto err;
}
+ pdata.config = config;
+ pdata.platform_ops = &dsps_ops;
- pdata->platform_ops = &dsps_ops;
+ config->num_eps = get_int_prop(dn, "mentor,num-eps");
+ config->ram_bits = get_int_prop(dn, "mentor,ram-bits");
+ pdata.mode = get_musb_port_mode(dev);
+ /* DT keeps this entry in mA, musb expects it as per USB spec */
+ pdata.power = get_int_prop(dn, "mentor,power") / 2;
+ config->multipoint = of_property_read_bool(dn, "mentor,multipoint");
- ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
if (ret) {
dev_err(dev, "failed to add platform_data\n");
- goto err2;
+ goto err;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(dev, "failed to register musb device\n");
- goto err2;
+ goto err;
}
-
return 0;
-err2:
+err:
platform_device_put(musb);
-err0:
return ret;
}
@@ -601,14 +533,12 @@ static int dsps_probe(struct platform_device *pdev)
const struct of_device_id *match;
const struct dsps_musb_wrapper *wrp;
struct dsps_glue *glue;
- struct resource *iomem;
- int ret, i;
+ int ret;
match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
if (!match) {
dev_err(&pdev->dev, "fail to get matching of_match struct\n");
- ret = -EINVAL;
- goto err0;
+ return -EINVAL;
}
wrp = match->data;
@@ -616,29 +546,13 @@ static int dsps_probe(struct platform_device *pdev)
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "unable to allocate glue memory\n");
- ret = -ENOMEM;
- goto err0;
- }
-
- /* get memory resource */
- iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iomem) {
- dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
- ret = -ENODEV;
- goto err1;
+ return -ENOMEM;
}
glue->dev = &pdev->dev;
+ glue->wrp = wrp;
- glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
- if (!glue->wrp) {
- dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
- ret = -ENOMEM;
- goto err1;
- }
platform_set_drvdata(pdev, glue);
-
- /* enable the usbss clocks */
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
@@ -647,17 +561,9 @@ static int dsps_probe(struct platform_device *pdev)
goto err2;
}
- /* create the child platform device for all instances of musb */
- for (i = 0; i < wrp->instances ; i++) {
- ret = dsps_create_musb_pdev(glue, i);
- if (ret != 0) {
- dev_err(&pdev->dev, "failed to create child pdev\n");
- /* release resources of previously created instances */
- for (i--; i >= 0 ; i--)
- platform_device_unregister(glue->musb[i]);
- goto err3;
- }
- }
+ ret = dsps_create_musb_pdev(glue, pdev);
+ if (ret)
+ goto err3;
return 0;
@@ -665,65 +571,27 @@ err3:
pm_runtime_put(&pdev->dev);
err2:
pm_runtime_disable(&pdev->dev);
- kfree(glue->wrp);
-err1:
kfree(glue);
-err0:
return ret;
}
+
static int dsps_remove(struct platform_device *pdev)
{
struct dsps_glue *glue = platform_get_drvdata(pdev);
- const struct dsps_musb_wrapper *wrp = glue->wrp;
- int i;
- /* delete the child platform device */
- for (i = 0; i < wrp->instances ; i++)
- platform_device_unregister(glue->musb[i]);
+ platform_device_unregister(glue->musb);
/* disable usbss clocks */
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- kfree(glue->wrp);
kfree(glue);
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int dsps_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev->parent);
- struct dsps_glue *glue = platform_get_drvdata(pdev);
- const struct dsps_musb_wrapper *wrp = glue->wrp;
- int i;
-
- for (i = 0; i < wrp->instances; i++)
- musb_dsps_phy_control(glue, i, 0);
-
- return 0;
-}
-
-static int dsps_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev->parent);
- struct dsps_glue *glue = platform_get_drvdata(pdev);
- const struct dsps_musb_wrapper *wrp = glue->wrp;
- int i;
-
- for (i = 0; i < wrp->instances; i++)
- musb_dsps_phy_control(glue, i, 1);
-
- return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
-
-static const struct dsps_musb_wrapper ti81xx_driver_data = {
+static const struct dsps_musb_wrapper am33xx_driver_data = {
.revision = 0x00,
.control = 0x14,
.status = 0x18,
- .eoi = 0x24,
.epintr_set = 0x38,
.epintr_clear = 0x40,
.epintr_status = 0x30,
@@ -745,38 +613,23 @@ static const struct dsps_musb_wrapper ti81xx_driver_data = {
.rxep_shift = 16,
.rxep_mask = 0xfffe,
.rxep_bitmap = (0xfffe << 16),
- .musb_core_offset = 0x400,
.poll_seconds = 2,
- .instances = 1,
-};
-
-static const struct platform_device_id musb_dsps_id_table[] = {
- {
- .name = "musb-ti81xx",
- .driver_data = (kernel_ulong_t) &ti81xx_driver_data,
- },
- { }, /* Terminating Entry */
};
-MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
-#ifdef CONFIG_OF
static const struct of_device_id musb_dsps_of_match[] = {
{ .compatible = "ti,musb-am33xx",
- .data = (void *) &ti81xx_driver_data, },
+ .data = (void *) &am33xx_driver_data, },
{ },
};
MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
-#endif
static struct platform_driver dsps_usbss_driver = {
.probe = dsps_probe,
.remove = dsps_remove,
.driver = {
.name = "musb-dsps",
- .pm = &dsps_pm_ops,
.of_match_table = of_match_ptr(musb_dsps_of_match),
},
- .id_table = musb_dsps_id_table,
};
MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
@@ -784,14 +637,4 @@ MODULE_AUTHOR("Ravi B <ravibabu@ti.com>");
MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
MODULE_LICENSE("GPL v2");
-static int __init dsps_init(void)
-{
- return platform_driver_register(&dsps_usbss_driver);
-}
-subsys_initcall(dsps_init);
-
-static void __exit dsps_exit(void)
-{
- platform_driver_unregister(&dsps_usbss_driver);
-}
-module_exit(dsps_exit);
+module_platform_driver(dsps_usbss_driver);
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 0414bc19d00..9a08679d204 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -76,13 +76,21 @@ static inline void map_dma_buffer(struct musb_request *request,
return;
if (request->request.dma == DMA_ADDR_INVALID) {
- request->request.dma = dma_map_single(
+ dma_addr_t dma_addr;
+ int ret;
+
+ dma_addr = dma_map_single(
musb->controller,
request->request.buf,
request->request.length,
request->tx
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
+ ret = dma_mapping_error(musb->controller, dma_addr);
+ if (ret)
+ return;
+
+ request->request.dma = dma_addr;
request->map_state = MUSB_MAPPED;
} else {
dma_sync_single_for_device(musb->controller,
@@ -357,47 +365,49 @@ static void txstate(struct musb *musb, struct musb_request *req)
}
}
-#elif defined(CONFIG_USB_TI_CPPI_DMA)
- /* program endpoint CSR first, then setup DMA */
- csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
- csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
- MUSB_TXCSR_MODE;
- musb_writew(epio, MUSB_TXCSR,
- (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
- | csr);
-
- /* ensure writebuffer is empty */
- csr = musb_readw(epio, MUSB_TXCSR);
-
- /* NOTE host side sets DMAENAB later than this; both are
- * OK since the transfer dma glue (between CPPI and Mentor
- * fifos) just tells CPPI it could start. Data only moves
- * to the USB TX fifo when both fifos are ready.
- */
-
- /* "mode" is irrelevant here; handle terminating ZLPs like
- * PIO does, since the hardware RNDIS mode seems unreliable
- * except for the last-packet-is-already-short case.
- */
- use_dma = use_dma && c->channel_program(
- musb_ep->dma, musb_ep->packet_sz,
- 0,
- request->dma + request->actual,
- request_size);
- if (!use_dma) {
- c->channel_release(musb_ep->dma);
- musb_ep->dma = NULL;
- csr &= ~MUSB_TXCSR_DMAENAB;
- musb_writew(epio, MUSB_TXCSR, csr);
- /* invariant: prequest->buf is non-null */
- }
-#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
- use_dma = use_dma && c->channel_program(
- musb_ep->dma, musb_ep->packet_sz,
- request->zero,
- request->dma + request->actual,
- request_size);
#endif
+ if (is_cppi_enabled()) {
+ /* program endpoint CSR first, then setup DMA */
+ csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
+ csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
+ MUSB_TXCSR_MODE;
+ musb_writew(epio, MUSB_TXCSR, (MUSB_TXCSR_P_WZC_BITS &
+ ~MUSB_TXCSR_P_UNDERRUN) | csr);
+
+ /* ensure writebuffer is empty */
+ csr = musb_readw(epio, MUSB_TXCSR);
+
+ /*
+ * NOTE host side sets DMAENAB later than this; both are
+ * OK since the transfer dma glue (between CPPI and
+ * Mentor fifos) just tells CPPI it could start. Data
+ * only moves to the USB TX fifo when both fifos are
+ * ready.
+ */
+ /*
+ * "mode" is irrelevant here; handle terminating ZLPs
+ * like PIO does, since the hardware RNDIS mode seems
+ * unreliable except for the
+ * last-packet-is-already-short case.
+ */
+ use_dma = use_dma && c->channel_program(
+ musb_ep->dma, musb_ep->packet_sz,
+ 0,
+ request->dma + request->actual,
+ request_size);
+ if (!use_dma) {
+ c->channel_release(musb_ep->dma);
+ musb_ep->dma = NULL;
+ csr &= ~MUSB_TXCSR_DMAENAB;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ /* invariant: prequest->buf is non-null */
+ }
+ } else if (tusb_dma_omap())
+ use_dma = use_dma && c->channel_program(
+ musb_ep->dma, musb_ep->packet_sz,
+ request->zero,
+ request->dma + request->actual,
+ request_size);
}
#endif
@@ -1266,7 +1276,8 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
dev_dbg(musb->controller, "req %p queued to %s while ep %s\n",
req, ep->name, "disabled");
status = -ESHUTDOWN;
- goto cleanup;
+ unmap_dma_buffer(request, musb);
+ goto unlock;
}
/* add request to the list */
@@ -1276,7 +1287,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
if (!musb_ep->busy && &request->list == musb_ep->req_list.next)
musb_ep_restart(musb, request);
-cleanup:
+unlock:
spin_unlock_irqrestore(&musb->lock, lockflags);
return status;
}
@@ -1801,6 +1812,8 @@ err:
void musb_gadget_cleanup(struct musb *musb)
{
+ if (musb->port_mode == MUSB_PORT_MODE_HOST)
+ return;
usb_del_gadget_udc(&musb->g);
}
@@ -1926,7 +1939,8 @@ static int musb_gadget_stop(struct usb_gadget *g,
stop_activity(musb, driver);
otg_set_peripheral(musb->xceiv->otg, NULL);
- dev_dbg(musb->controller, "unregistering driver %s\n", driver->function);
+ dev_dbg(musb->controller, "unregistering driver %s\n",
+ driver ? driver->function : "(removed)");
musb->is_active = 0;
musb->gadget_driver = NULL;
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index a9695f5a92f..9a2b8c85f19 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -2628,6 +2628,8 @@ int musb_host_alloc(struct musb *musb)
void musb_host_cleanup(struct musb *musb)
{
+ if (musb->port_mode == MUSB_PORT_MODE_GADGET)
+ return;
usb_remove_hcd(musb->hcd);
musb->hcd = NULL;
}
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 3d1fd52a15a..e8e9f9aab20 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -37,18 +37,10 @@
#include "musb_core.h"
#include "musbhsdma.h"
-static int dma_controller_start(struct dma_controller *c)
-{
- /* nothing to do */
- return 0;
-}
-
static void dma_channel_release(struct dma_channel *channel);
-static int dma_controller_stop(struct dma_controller *c)
+static void dma_controller_stop(struct musb_dma_controller *controller)
{
- struct musb_dma_controller *controller = container_of(c,
- struct musb_dma_controller, controller);
struct musb *musb = controller->private_data;
struct dma_channel *channel;
u8 bit;
@@ -67,8 +59,6 @@ static int dma_controller_stop(struct dma_controller *c)
}
}
}
-
- return 0;
}
static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
@@ -371,8 +361,7 @@ void dma_controller_destroy(struct dma_controller *c)
struct musb_dma_controller *controller = container_of(c,
struct musb_dma_controller, controller);
- if (!controller)
- return;
+ dma_controller_stop(controller);
if (controller->irq)
free_irq(controller->irq, c);
@@ -400,8 +389,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
controller->private_data = musb;
controller->base = base;
- controller->controller.start = dma_controller_start;
- controller->controller.stop = dma_controller_stop;
controller->controller.channel_alloc = dma_channel_allocate;
controller->controller.channel_release = dma_channel_release;
controller->controller.channel_program = dma_channel_program;
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 6708a3b78ad..59d2245db1c 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -255,7 +255,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
{
struct musb *musb = glue_to_musb(glue);
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *pdata = dev->platform_data;
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
struct omap_musb_board_data *data = pdata->board_data;
struct usb_otg *otg = musb->xceiv->otg;
@@ -341,7 +341,7 @@ static int omap2430_musb_init(struct musb *musb)
int status = 0;
struct device *dev = musb->controller;
struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
/* We require some kind of external transceiver, hooked
@@ -412,7 +412,7 @@ static void omap2430_musb_enable(struct musb *musb)
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
struct device *dev = musb->controller;
struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
- struct musb_hdrc_platform_data *pdata = dev->platform_data;
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
struct omap_musb_board_data *data = pdata->board_data;
switch (glue->status) {
@@ -481,8 +481,8 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32);
static int omap2430_probe(struct platform_device *pdev)
{
- struct resource musb_resources[2];
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct resource musb_resources[3];
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct omap_musb_board_data *data;
struct platform_device *musb;
struct omap2430_glue *glue;
@@ -581,6 +581,11 @@ static int omap2430_probe(struct platform_device *pdev)
musb_resources[1].end = pdev->resource[1].end;
musb_resources[1].flags = pdev->resource[1].flags;
+ musb_resources[2].name = pdev->resource[2].name;
+ musb_resources[2].start = pdev->resource[2].start;
+ musb_resources[2].end = pdev->resource[2].end;
+ musb_resources[2].flags = pdev->resource[2].flags;
+
ret = platform_device_add_resources(musb, musb_resources,
ARRAY_SIZE(musb_resources));
if (ret) {
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 2c06a8969a9..b3b3ed72388 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -25,7 +25,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include "musb_core.h"
@@ -1156,8 +1156,8 @@ static u64 tusb_dmamask = DMA_BIT_MASK(32);
static int tusb_probe(struct platform_device *pdev)
{
- struct resource musb_resources[2];
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct resource musb_resources[3];
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct platform_device *musb;
struct tusb6010_glue *glue;
@@ -1199,6 +1199,11 @@ static int tusb_probe(struct platform_device *pdev)
musb_resources[1].end = pdev->resource[1].end;
musb_resources[1].flags = pdev->resource[1].flags;
+ musb_resources[2].name = pdev->resource[2].name;
+ musb_resources[2].start = pdev->resource[2].start;
+ musb_resources[2].end = pdev->resource[2].end;
+ musb_resources[2].flags = pdev->resource[2].flags;
+
ret = platform_device_add_resources(musb, musb_resources,
ARRAY_SIZE(musb_resources));
if (ret) {
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index 98df17c984a..b8794eb81e9 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -66,28 +66,6 @@ struct tusb_omap_dma {
unsigned multichannel:1;
};
-static int tusb_omap_dma_start(struct dma_controller *c)
-{
- struct tusb_omap_dma *tusb_dma;
-
- tusb_dma = container_of(c, struct tusb_omap_dma, controller);
-
- /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
-
- return 0;
-}
-
-static int tusb_omap_dma_stop(struct dma_controller *c)
-{
- struct tusb_omap_dma *tusb_dma;
-
- tusb_dma = container_of(c, struct tusb_omap_dma, controller);
-
- /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
-
- return 0;
-}
-
/*
* Allocate dmareq0 to the current channel unless it's already taken
*/
@@ -695,8 +673,6 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
tusb_dma->dmareq = -1;
tusb_dma->sync_dev = -1;
- tusb_dma->controller.start = tusb_omap_dma_start;
- tusb_dma->controller.stop = tusb_omap_dma_stop;
tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate;
tusb_dma->controller.channel_release = tusb_omap_dma_release;
tusb_dma->controller.channel_program = tusb_omap_dma_program;
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index fce71b60593..59256b12f74 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -227,7 +227,7 @@ ux500_of_probe(struct platform_device *pdev, struct device_node *np)
static int ux500_probe(struct platform_device *pdev)
{
struct resource musb_resources[2];
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct platform_device *musb;
struct ux500_glue *glue;
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index bfb7a65d83c..3700e971325 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -254,10 +254,8 @@ static int ux500_dma_channel_abort(struct dma_channel *channel)
return 0;
}
-static int ux500_dma_controller_stop(struct dma_controller *c)
+static void ux500_dma_controller_stop(struct ux500_dma_controller *controller)
{
- struct ux500_dma_controller *controller = container_of(c,
- struct ux500_dma_controller, controller);
struct ux500_dma_channel *ux500_channel;
struct dma_channel *channel;
u8 ch_num;
@@ -281,18 +279,14 @@ static int ux500_dma_controller_stop(struct dma_controller *c)
if (ux500_channel->dma_chan)
dma_release_channel(ux500_channel->dma_chan);
}
-
- return 0;
}
-static int ux500_dma_controller_start(struct dma_controller *c)
+static int ux500_dma_controller_start(struct ux500_dma_controller *controller)
{
- struct ux500_dma_controller *controller = container_of(c,
- struct ux500_dma_controller, controller);
struct ux500_dma_channel *ux500_channel = NULL;
struct musb *musb = controller->private_data;
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct ux500_musb_board_data *data;
struct dma_channel *dma_channel = NULL;
char **chan_names;
@@ -339,7 +333,9 @@ static int ux500_dma_controller_start(struct dma_controller *c)
if (!ux500_channel->dma_chan)
ux500_channel->dma_chan =
dma_request_channel(mask,
- data->dma_filter,
+ data ?
+ data->dma_filter :
+ NULL,
param_array[ch_num]);
if (!ux500_channel->dma_chan) {
@@ -347,7 +343,7 @@ static int ux500_dma_controller_start(struct dma_controller *c)
dir, ch_num);
/* Release already allocated channels */
- ux500_dma_controller_stop(c);
+ ux500_dma_controller_stop(controller);
return -EBUSY;
}
@@ -369,6 +365,7 @@ void dma_controller_destroy(struct dma_controller *c)
struct ux500_dma_controller *controller = container_of(c,
struct ux500_dma_controller, controller);
+ ux500_dma_controller_stop(controller);
kfree(controller);
}
@@ -378,6 +375,7 @@ struct dma_controller *dma_controller_create(struct musb *musb,
struct ux500_dma_controller *controller;
struct platform_device *pdev = to_platform_device(musb->controller);
struct resource *iomem;
+ int ret;
controller = kzalloc(sizeof(*controller), GFP_KERNEL);
if (!controller)
@@ -394,14 +392,15 @@ struct dma_controller *dma_controller_create(struct musb *musb,
controller->phy_base = (dma_addr_t) iomem->start;
- controller->controller.start = ux500_dma_controller_start;
- controller->controller.stop = ux500_dma_controller_stop;
controller->controller.channel_alloc = ux500_dma_channel_allocate;
controller->controller.channel_release = ux500_dma_channel_release;
controller->controller.channel_program = ux500_dma_channel_program;
controller->controller.channel_abort = ux500_dma_channel_abort;
controller->controller.is_compatible = ux500_dma_is_compatible;
+ ret = ux500_dma_controller_start(controller);
+ if (ret)
+ goto plat_get_fail;
return &controller->controller;
plat_get_fail:
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 3622fff8b79..d5589f9c60a 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -1,22 +1,10 @@
#
# Physical Layer USB driver configuration
#
-menuconfig USB_PHY
- bool "USB Physical Layer drivers"
- help
- Most USB controllers have the physical layer signalling part
- (commonly called a PHY) built in. However, dual-role devices
- (a.k.a. USB on-the-go) which support being USB master or slave
- with the same connector often use an external PHY.
-
- The drivers in this submenu add support for such PHY devices.
- They are not needed for standard master-only (or the vast
- majority of slave-only) USB interfaces.
+menu "USB Physical Layer drivers"
- If you're not sure if this applies to you, it probably doesn't;
- say N here.
-
-if USB_PHY
+config USB_PHY
+ def_bool n
#
# USB Transceiver Drivers
@@ -24,6 +12,7 @@ if USB_PHY
config AB8500_USB
tristate "AB8500 USB Transceiver Driver"
depends on AB8500_CORE
+ select USB_PHY
help
Enable this to support the USB OTG transceiver in AB8500 chip.
This transceiver supports high and full speed devices plus,
@@ -33,12 +22,14 @@ config FSL_USB2_OTG
bool "Freescale USB OTG Transceiver Driver"
depends on USB_EHCI_FSL && USB_FSL_USB2 && PM_RUNTIME
select USB_OTG
+ select USB_PHY
help
Enable this to support Freescale USB OTG transceiver.
config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
depends on I2C && ARCH_OMAP_OTG
+ select USB_PHY
help
If you say yes here you get support for the Philips ISP1301
USB-On-The-Go transceiver working with the OMAP OTG controller.
@@ -52,12 +43,14 @@ config ISP1301_OMAP
config MV_U3D_PHY
bool "Marvell USB 3.0 PHY controller Driver"
depends on CPU_MMP3
+ select USB_PHY
help
Enable this to support Marvell USB 3.0 phy controller for Marvell
SoC.
config NOP_USB_XCEIV
tristate "NOP USB Transceiver Driver"
+ select USB_PHY
help
This driver is to be used by all the usb transceiver which are either
built-in with usb ip or which are autonomous and doesn't require any
@@ -65,6 +58,7 @@ config NOP_USB_XCEIV
config OMAP_CONTROL_USB
tristate "OMAP CONTROL USB Driver"
+ depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
Enable this to add support for the USB part present in the control
module. This driver has API to power on the USB2 PHY and to write to
@@ -76,6 +70,7 @@ config OMAP_USB2
tristate "OMAP USB2 PHY Driver"
depends on ARCH_OMAP2PLUS
select OMAP_CONTROL_USB
+ select USB_PHY
help
Enable this to support the transceiver that is part of SOC. This
driver takes care of all the PHY functionality apart from comparator.
@@ -84,13 +79,27 @@ config OMAP_USB2
config OMAP_USB3
tristate "OMAP USB3 PHY Driver"
+ depends on ARCH_OMAP2PLUS || COMPILE_TEST
select OMAP_CONTROL_USB
+ select USB_PHY
help
Enable this to support the USB3 PHY that is part of SOC. This
driver takes care of all the PHY functionality apart from comparator.
This driver interacts with the "OMAP Control USB Driver" to power
on/off the PHY.
+config AM335X_CONTROL_USB
+ tristate
+
+config AM335X_PHY_USB
+ tristate "AM335x USB PHY Driver"
+ select USB_PHY
+ select AM335X_CONTROL_USB
+ select NOP_USB_XCEIV
+ help
+ This driver provides PHY support for that phy which part for the
+ AM335x SoC.
+
config SAMSUNG_USBPHY
tristate
help
@@ -101,6 +110,7 @@ config SAMSUNG_USBPHY
config SAMSUNG_USB2PHY
tristate "Samsung USB 2.0 PHY controller Driver"
select SAMSUNG_USBPHY
+ select USB_PHY
help
Enable this to support Samsung USB 2.0 (High Speed) PHY controller
driver for Samsung SoCs.
@@ -108,6 +118,7 @@ config SAMSUNG_USB2PHY
config SAMSUNG_USB3PHY
tristate "Samsung USB 3.0 PHY controller Driver"
select SAMSUNG_USBPHY
+ select USB_PHY
help
Enable this to support Samsung USB 3.0 (Super Speed) phy controller
for samsung SoCs.
@@ -115,6 +126,7 @@ config SAMSUNG_USB3PHY
config TWL4030_USB
tristate "TWL4030 USB Transceiver Driver"
depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
+ select USB_PHY
help
Enable this to support the USB OTG transceiver on TWL4030
family chips (including the TWL5030 and TPS659x0 devices).
@@ -135,6 +147,7 @@ config TWL6030_USB
config USB_GPIO_VBUS
tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
depends on GPIOLIB
+ select USB_PHY
help
Provides simple GPIO VBUS sensing for controllers with an
internal transceiver via the usb_phy interface, and
@@ -145,6 +158,7 @@ config USB_ISP1301
tristate "NXP ISP1301 USB transceiver support"
depends on USB || USB_GADGET
depends on I2C
+ select USB_PHY
help
Say Y here to add support for the NXP ISP1301 USB transceiver driver.
This chip is typically used as USB transceiver for USB host, gadget
@@ -156,6 +170,7 @@ config USB_ISP1301
config USB_MSM_OTG
tristate "OTG support for Qualcomm on-chip USB controller"
depends on (USB || USB_GADGET) && ARCH_MSM
+ select USB_PHY
help
Enable this to support the USB OTG transceiver on MSM chips. It
handles PHY initialization, clock management, and workarounds
@@ -169,6 +184,7 @@ config USB_MV_OTG
tristate "Marvell USB OTG support"
depends on USB_EHCI_MV && USB_MV_UDC && PM_RUNTIME
select USB_OTG
+ select USB_PHY
help
Say Y here if you want to build Marvell USB OTG transciever
driver in kernel (including PXA and MMP series). This driver
@@ -180,6 +196,7 @@ config USB_MXS_PHY
tristate "Freescale MXS USB PHY support"
depends on ARCH_MXC || ARCH_MXS
select STMP_DEVICE
+ select USB_PHY
help
Enable this to support the Freescale MXS USB PHY.
@@ -188,6 +205,7 @@ config USB_MXS_PHY
config USB_RCAR_PHY
tristate "Renesas R-Car USB PHY support"
depends on USB || USB_GADGET
+ select USB_PHY
help
Say Y here to add support for the Renesas R-Car USB common PHY driver.
This chip is typically used as USB PHY for USB host, gadget.
@@ -210,4 +228,4 @@ config USB_ULPI_VIEWPORT
Provides read/write operations to the ULPI phy register set for
controllers with a viewport register (e.g. Chipidea/ARC controllers).
-endif # USB_PHY
+endmenu
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 070eca3af18..2135e85f46e 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -1,9 +1,6 @@
#
# Makefile for physical layer USB drivers
#
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-
obj-$(CONFIG_USB_PHY) += phy.o
obj-$(CONFIG_OF) += of.o
@@ -14,8 +11,10 @@ phy-fsl-usb2-objs := phy-fsl-usb.o phy-fsm-usb.o
obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb2.o
obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o
obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o
-obj-$(CONFIG_NOP_USB_XCEIV) += phy-nop.o
+obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o
obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o
+obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o
+obj-$(CONFIG_AM335X_PHY_USB) += phy-am335x.o
obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o
obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o
diff --git a/drivers/usb/phy/am35x-phy-control.h b/drivers/usb/phy/am35x-phy-control.h
new file mode 100644
index 00000000000..b96594d1962
--- /dev/null
+++ b/drivers/usb/phy/am35x-phy-control.h
@@ -0,0 +1,21 @@
+#ifndef _AM335x_PHY_CONTROL_H_
+#define _AM335x_PHY_CONTROL_H_
+
+struct phy_control {
+ void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
+ void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
+};
+
+static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+ phy_ctrl->phy_power(phy_ctrl, id, on);
+}
+
+static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+ phy_ctrl->phy_wkup(phy_ctrl, id, on);
+}
+
+struct phy_control *am335x_get_phy_control(struct device *dev);
+
+#endif
diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c
new file mode 100644
index 00000000000..22cf07d62e4
--- /dev/null
+++ b/drivers/usb/phy/phy-am335x-control.c
@@ -0,0 +1,137 @@
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/io.h>
+
+struct phy_control {
+ void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
+ void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
+};
+
+struct am335x_control_usb {
+ struct device *dev;
+ void __iomem *phy_reg;
+ void __iomem *wkup;
+ spinlock_t lock;
+ struct phy_control phy_ctrl;
+};
+
+#define AM335X_USB0_CTRL 0x0
+#define AM335X_USB1_CTRL 0x8
+#define AM335x_USB_WKUP 0x0
+
+#define USBPHY_CM_PWRDN (1 << 0)
+#define USBPHY_OTG_PWRDN (1 << 1)
+#define USBPHY_OTGVDET_EN (1 << 19)
+#define USBPHY_OTGSESSEND_EN (1 << 20)
+
+static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+ struct am335x_control_usb *usb_ctrl;
+ u32 val;
+ u32 reg;
+
+ usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl);
+
+ switch (id) {
+ case 0:
+ reg = AM335X_USB0_CTRL;
+ break;
+ case 1:
+ reg = AM335X_USB1_CTRL;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ val = readl(usb_ctrl->phy_reg + reg);
+ if (on) {
+ val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
+ val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
+ } else {
+ val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
+ }
+
+ writel(val, usb_ctrl->phy_reg + reg);
+}
+
+static const struct phy_control ctrl_am335x = {
+ .phy_power = am335x_phy_power,
+};
+
+static const struct of_device_id omap_control_usb_id_table[] = {
+ { .compatible = "ti,am335x-usb-ctrl-module", .data = &ctrl_am335x },
+ {}
+};
+MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
+
+static struct platform_driver am335x_control_driver;
+static int match(struct device *dev, void *data)
+{
+ struct device_node *node = (struct device_node *)data;
+ return dev->of_node == node &&
+ dev->driver == &am335x_control_driver.driver;
+}
+
+struct phy_control *am335x_get_phy_control(struct device *dev)
+{
+ struct device_node *node;
+ struct am335x_control_usb *ctrl_usb;
+
+ node = of_parse_phandle(dev->of_node, "ti,ctrl_mod", 0);
+ if (!node)
+ return NULL;
+
+ dev = bus_find_device(&platform_bus_type, NULL, node, match);
+ ctrl_usb = dev_get_drvdata(dev);
+ if (!ctrl_usb)
+ return NULL;
+ return &ctrl_usb->phy_ctrl;
+}
+EXPORT_SYMBOL_GPL(am335x_get_phy_control);
+
+static int am335x_control_usb_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct am335x_control_usb *ctrl_usb;
+ const struct of_device_id *of_id;
+ const struct phy_control *phy_ctrl;
+
+ of_id = of_match_node(omap_control_usb_id_table, pdev->dev.of_node);
+ if (!of_id)
+ return -EINVAL;
+
+ phy_ctrl = of_id->data;
+
+ ctrl_usb = devm_kzalloc(&pdev->dev, sizeof(*ctrl_usb), GFP_KERNEL);
+ if (!ctrl_usb) {
+ dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+ return -ENOMEM;
+ }
+
+ ctrl_usb->dev = &pdev->dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
+ ctrl_usb->phy_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ctrl_usb->phy_reg))
+ return PTR_ERR(ctrl_usb->phy_reg);
+ spin_lock_init(&ctrl_usb->lock);
+ ctrl_usb->phy_ctrl = *phy_ctrl;
+
+ dev_set_drvdata(ctrl_usb->dev, ctrl_usb);
+ return 0;
+}
+
+static struct platform_driver am335x_control_driver = {
+ .probe = am335x_control_usb_probe,
+ .driver = {
+ .name = "am335x-control-usb",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(omap_control_usb_id_table),
+ },
+};
+
+module_platform_driver(am335x_control_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
new file mode 100644
index 00000000000..c4d614d1f17
--- /dev/null
+++ b/drivers/usb/phy/phy-am335x.c
@@ -0,0 +1,99 @@
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "am35x-phy-control.h"
+#include "phy-generic.h"
+
+struct am335x_phy {
+ struct usb_phy_gen_xceiv usb_phy_gen;
+ struct phy_control *phy_ctrl;
+ int id;
+};
+
+static int am335x_init(struct usb_phy *phy)
+{
+ struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
+
+ phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true);
+ return 0;
+}
+
+static void am335x_shutdown(struct usb_phy *phy)
+{
+ struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
+
+ phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+}
+
+static int am335x_phy_probe(struct platform_device *pdev)
+{
+ struct am335x_phy *am_phy;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ am_phy = devm_kzalloc(dev, sizeof(*am_phy), GFP_KERNEL);
+ if (!am_phy)
+ return -ENOMEM;
+
+ am_phy->phy_ctrl = am335x_get_phy_control(dev);
+ if (!am_phy->phy_ctrl)
+ return -EPROBE_DEFER;
+ am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy");
+ if (am_phy->id < 0) {
+ dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id);
+ return am_phy->id;
+ }
+
+ ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen,
+ USB_PHY_TYPE_USB2, 0, false, false);
+ if (ret)
+ return ret;
+
+ ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy);
+ if (ret)
+ goto err_add;
+ am_phy->usb_phy_gen.phy.init = am335x_init;
+ am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown;
+
+ platform_set_drvdata(pdev, am_phy);
+ return 0;
+
+err_add:
+ usb_phy_gen_cleanup_phy(&am_phy->usb_phy_gen);
+ return ret;
+}
+
+static int am335x_phy_remove(struct platform_device *pdev)
+{
+ struct am335x_phy *am_phy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&am_phy->usb_phy_gen.phy);
+ return 0;
+}
+
+static const struct of_device_id am335x_phy_ids[] = {
+ { .compatible = "ti,am335x-usb-phy" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, am335x_phy_ids);
+
+static struct platform_driver am335x_phy_driver = {
+ .probe = am335x_phy_probe,
+ .remove = am335x_phy_remove,
+ .driver = {
+ .name = "am335x-phy-driver",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(am335x_phy_ids),
+ },
+};
+
+module_platform_driver(am335x_phy_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index e771bafb9f1..fa7c9f9628b 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -611,7 +611,7 @@ static int fsl_otg_set_peripheral(struct usb_otg *otg,
otg_dev->fsm.b_bus_req = 1;
/* start the gadget right away if the ID pin says Mini-B */
- DBG("ID pin=%d\n", otg_dev->fsm.id);
+ pr_debug("ID pin=%d\n", otg_dev->fsm.id);
if (otg_dev->fsm.id == 1) {
fsl_otg_start_host(&otg_dev->fsm, 0);
otg_drv_vbus(&otg_dev->fsm, 0);
@@ -684,7 +684,7 @@ static int fsl_otg_start_hnp(struct usb_otg *otg)
if (otg_dev != fsl_otg_dev)
return -ENODEV;
- DBG("start_hnp...n");
+ pr_debug("start_hnp...\n");
/* clear a_bus_req to enter a_suspend state */
otg_dev->fsm.a_bus_req = 0;
@@ -834,7 +834,7 @@ int usb_otg_start(struct platform_device *pdev)
int status;
struct resource *res;
u32 temp;
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+ struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
p_otg = container_of(otg_trans, struct fsl_otg, phy);
fsm = &p_otg->fsm;
@@ -941,7 +941,7 @@ int usb_otg_start(struct platform_device *pdev)
p_otg->fsm.id = 0;
}
- DBG("initial ID pin=%d\n", p_otg->fsm.id);
+ pr_debug("initial ID pin=%d\n", p_otg->fsm.id);
/* enable OTG ID pin interrupt */
temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
@@ -1105,7 +1105,7 @@ static int fsl_otg_probe(struct platform_device *pdev)
{
int ret;
- if (!pdev->dev.platform_data)
+ if (!dev_get_platdata(&pdev->dev))
return -ENODEV;
/* configure the OTG */
@@ -1137,7 +1137,7 @@ static int fsl_otg_probe(struct platform_device *pdev)
static int fsl_otg_remove(struct platform_device *pdev)
{
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+ struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
usb_remove_phy(&fsl_otg_dev->phy);
free_irq(fsl_otg_dev->irq, fsl_otg_dev);
diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h
index ca266280895..e1859b8ef56 100644
--- a/drivers/usb/phy/phy-fsl-usb.h
+++ b/drivers/usb/phy/phy-fsl-usb.h
@@ -15,7 +15,7 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "otg_fsm.h"
+#include "phy-fsm-usb.h"
#include <linux/usb/otg.h>
#include <linux/ioctl.h>
diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c
index c520b3548e7..7f4596606e1 100644
--- a/drivers/usb/phy/phy-fsm-usb.c
+++ b/drivers/usb/phy/phy-fsm-usb.c
@@ -29,7 +29,7 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
-#include "phy-otg-fsm.h"
+#include "phy-fsm-usb.h"
/* Change USB protocol when there is a protocol change */
static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h
index c30a2e1d9e4..fbe586206f3 100644
--- a/drivers/usb/phy/phy-fsm-usb.h
+++ b/drivers/usb/phy/phy-fsm-usb.h
@@ -15,18 +15,11 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#undef DEBUG
#undef VERBOSE
-#ifdef DEBUG
-#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt , \
- __func__, ## args)
-#else
-#define DBG(fmt, args...) do {} while (0)
-#endif
-
#ifdef VERBOSE
-#define VDBG DBG
+#define VDBG(fmt, args...) pr_debug("[%s] " fmt , \
+ __func__, ## args)
#else
#define VDBG(stuff...) do {} while (0)
#endif
diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-generic.c
index 55445e5d72e..efe59f3f7fd 100644
--- a/drivers/usb/phy/phy-nop.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -30,19 +30,13 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
-struct nop_usb_xceiv {
- struct usb_phy phy;
- struct device *dev;
- struct clk *clk;
- struct regulator *vcc;
- struct regulator *reset;
-};
+#include "phy-generic.h"
static struct platform_device *pd;
@@ -50,9 +44,9 @@ void usb_nop_xceiv_register(void)
{
if (pd)
return;
- pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
+ pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0);
if (!pd) {
- printk(KERN_ERR "Unable to register usb nop transceiver\n");
+ pr_err("Unable to register generic usb transceiver\n");
return;
}
}
@@ -70,9 +64,9 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
return 0;
}
-static int nop_init(struct usb_phy *phy)
+int usb_gen_phy_init(struct usb_phy *phy)
{
- struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+ struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
if (!IS_ERR(nop->vcc)) {
if (regulator_enable(nop->vcc))
@@ -90,10 +84,11 @@ static int nop_init(struct usb_phy *phy)
return 0;
}
+EXPORT_SYMBOL_GPL(usb_gen_phy_init);
-static void nop_shutdown(struct usb_phy *phy)
+void usb_gen_phy_shutdown(struct usb_phy *phy)
{
- struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+ struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
if (!IS_ERR(nop->reset)) {
/* Assert RESET */
@@ -109,6 +104,7 @@ static void nop_shutdown(struct usb_phy *phy)
dev_err(phy->dev, "Failed to disable power\n");
}
}
+EXPORT_SYMBOL_GPL(usb_gen_phy_shutdown);
static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
{
@@ -139,52 +135,27 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
return 0;
}
-static int nop_usb_xceiv_probe(struct platform_device *pdev)
+int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
+ enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
+ bool needs_reset)
{
- struct device *dev = &pdev->dev;
- struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
- struct nop_usb_xceiv *nop;
- enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err;
- u32 clk_rate = 0;
- bool needs_vcc = false;
- bool needs_reset = false;
-
- nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
- if (!nop)
- return -ENOMEM;
- nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
- GFP_KERNEL);
+ nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
+ GFP_KERNEL);
if (!nop->phy.otg)
return -ENOMEM;
- if (dev->of_node) {
- struct device_node *node = dev->of_node;
-
- if (of_property_read_u32(node, "clock-frequency", &clk_rate))
- clk_rate = 0;
-
- needs_vcc = of_property_read_bool(node, "vcc-supply");
- needs_reset = of_property_read_bool(node, "reset-supply");
-
- } else if (pdata) {
- type = pdata->type;
- clk_rate = pdata->clk_rate;
- needs_vcc = pdata->needs_vcc;
- needs_reset = pdata->needs_reset;
- }
-
- nop->clk = devm_clk_get(&pdev->dev, "main_clk");
+ nop->clk = devm_clk_get(dev, "main_clk");
if (IS_ERR(nop->clk)) {
- dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n",
+ dev_dbg(dev, "Can't get phy clock: %ld\n",
PTR_ERR(nop->clk));
}
if (!IS_ERR(nop->clk) && clk_rate) {
err = clk_set_rate(nop->clk, clk_rate);
if (err) {
- dev_err(&pdev->dev, "Error setting clock rate\n");
+ dev_err(dev, "Error setting clock rate\n");
return err;
}
}
@@ -192,33 +163,31 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev)
if (!IS_ERR(nop->clk)) {
err = clk_prepare(nop->clk);
if (err) {
- dev_err(&pdev->dev, "Error preparing clock\n");
+ dev_err(dev, "Error preparing clock\n");
return err;
}
}
- nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
+ nop->vcc = devm_regulator_get(dev, "vcc");
if (IS_ERR(nop->vcc)) {
- dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n",
+ dev_dbg(dev, "Error getting vcc regulator: %ld\n",
PTR_ERR(nop->vcc));
if (needs_vcc)
return -EPROBE_DEFER;
}
- nop->reset = devm_regulator_get(&pdev->dev, "reset");
+ nop->reset = devm_regulator_get(dev, "reset");
if (IS_ERR(nop->reset)) {
- dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
+ dev_dbg(dev, "Error getting reset regulator: %ld\n",
PTR_ERR(nop->reset));
if (needs_reset)
return -EPROBE_DEFER;
}
- nop->dev = &pdev->dev;
+ nop->dev = dev;
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";
nop->phy.set_suspend = nop_set_suspend;
- nop->phy.init = nop_init;
- nop->phy.shutdown = nop_shutdown;
nop->phy.state = OTG_STATE_UNDEFINED;
nop->phy.type = type;
@@ -226,6 +195,59 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev)
nop->phy.otg->set_host = nop_set_host;
nop->phy.otg->set_peripheral = nop_set_peripheral;
+ ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
+
+void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop)
+{
+ if (!IS_ERR(nop->clk))
+ clk_unprepare(nop->clk);
+}
+EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy);
+
+static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct usb_phy_gen_xceiv_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct usb_phy_gen_xceiv *nop;
+ enum usb_phy_type type = USB_PHY_TYPE_USB2;
+ int err;
+ u32 clk_rate = 0;
+ bool needs_vcc = false;
+ bool needs_reset = false;
+
+ if (dev->of_node) {
+ struct device_node *node = dev->of_node;
+
+ if (of_property_read_u32(node, "clock-frequency", &clk_rate))
+ clk_rate = 0;
+
+ needs_vcc = of_property_read_bool(node, "vcc-supply");
+ needs_reset = of_property_read_bool(node, "reset-supply");
+
+ } else if (pdata) {
+ type = pdata->type;
+ clk_rate = pdata->clk_rate;
+ needs_vcc = pdata->needs_vcc;
+ needs_reset = pdata->needs_reset;
+ }
+
+ nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
+ if (!nop)
+ return -ENOMEM;
+
+
+ err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc,
+ needs_reset);
+ if (err)
+ return err;
+
+ nop->phy.init = usb_gen_phy_init;
+ nop->phy.shutdown = usb_gen_phy_shutdown;
+
err = usb_add_phy_dev(&nop->phy);
if (err) {
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
@@ -235,23 +257,18 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, nop);
- ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
-
return 0;
err_add:
- if (!IS_ERR(nop->clk))
- clk_unprepare(nop->clk);
+ usb_phy_gen_cleanup_phy(nop);
return err;
}
-static int nop_usb_xceiv_remove(struct platform_device *pdev)
+static int usb_phy_gen_xceiv_remove(struct platform_device *pdev)
{
- struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
-
- if (!IS_ERR(nop->clk))
- clk_unprepare(nop->clk);
+ struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev);
+ usb_phy_gen_cleanup_phy(nop);
usb_remove_phy(&nop->phy);
return 0;
@@ -264,29 +281,29 @@ static const struct of_device_id nop_xceiv_dt_ids[] = {
MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
-static struct platform_driver nop_usb_xceiv_driver = {
- .probe = nop_usb_xceiv_probe,
- .remove = nop_usb_xceiv_remove,
+static struct platform_driver usb_phy_gen_xceiv_driver = {
+ .probe = usb_phy_gen_xceiv_probe,
+ .remove = usb_phy_gen_xceiv_remove,
.driver = {
- .name = "nop_usb_xceiv",
+ .name = "usb_phy_gen_xceiv",
.owner = THIS_MODULE,
.of_match_table = nop_xceiv_dt_ids,
},
};
-static int __init nop_usb_xceiv_init(void)
+static int __init usb_phy_gen_xceiv_init(void)
{
- return platform_driver_register(&nop_usb_xceiv_driver);
+ return platform_driver_register(&usb_phy_gen_xceiv_driver);
}
-subsys_initcall(nop_usb_xceiv_init);
+subsys_initcall(usb_phy_gen_xceiv_init);
-static void __exit nop_usb_xceiv_exit(void)
+static void __exit usb_phy_gen_xceiv_exit(void)
{
- platform_driver_unregister(&nop_usb_xceiv_driver);
+ platform_driver_unregister(&usb_phy_gen_xceiv_driver);
}
-module_exit(nop_usb_xceiv_exit);
+module_exit(usb_phy_gen_xceiv_exit);
-MODULE_ALIAS("platform:nop_usb_xceiv");
+MODULE_ALIAS("platform:usb_phy_gen_xceiv");
MODULE_AUTHOR("Texas Instruments Inc");
MODULE_DESCRIPTION("NOP USB Transceiver driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h
new file mode 100644
index 00000000000..61687d5a965
--- /dev/null
+++ b/drivers/usb/phy/phy-generic.h
@@ -0,0 +1,20 @@
+#ifndef _PHY_GENERIC_H_
+#define _PHY_GENERIC_H_
+
+struct usb_phy_gen_xceiv {
+ struct usb_phy phy;
+ struct device *dev;
+ struct clk *clk;
+ struct regulator *vcc;
+ struct regulator *reset;
+};
+
+int usb_gen_phy_init(struct usb_phy *phy);
+void usb_gen_phy_shutdown(struct usb_phy *phy);
+
+int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
+ enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
+ bool needs_reset);
+void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop);
+
+#endif
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index 8443335c2ea..b2f29c9aebb 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -101,7 +101,7 @@ static void gpio_vbus_work(struct work_struct *work)
{
struct gpio_vbus_data *gpio_vbus =
container_of(work, struct gpio_vbus_data, work.work);
- struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
+ struct gpio_vbus_mach_info *pdata = dev_get_platdata(gpio_vbus->dev);
int gpio, status, vbus;
if (!gpio_vbus->phy.otg->gadget)
@@ -155,7 +155,7 @@ static void gpio_vbus_work(struct work_struct *work)
static irqreturn_t gpio_vbus_irq(int irq, void *data)
{
struct platform_device *pdev = data;
- struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+ struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
struct usb_otg *otg = gpio_vbus->phy.otg;
@@ -182,7 +182,7 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg,
gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
pdev = to_platform_device(gpio_vbus->dev);
- pdata = gpio_vbus->dev->platform_data;
+ pdata = dev_get_platdata(gpio_vbus->dev);
gpio = pdata->gpio_pullup;
if (!gadget) {
@@ -243,7 +243,7 @@ static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend)
static int __init gpio_vbus_probe(struct platform_device *pdev)
{
- struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+ struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
struct gpio_vbus_data *gpio_vbus;
struct resource *res;
int err, gpio, irq;
@@ -352,7 +352,7 @@ err_gpio:
static int __exit gpio_vbus_remove(struct platform_device *pdev)
{
struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
- struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+ struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
int gpio = pdata->gpio_vbus;
device_init_wakeup(&pdev->dev, 0);
diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c
index ae481afcb3e..d3a5160e4cc 100644
--- a/drivers/usb/phy/phy-isp1301-omap.c
+++ b/drivers/usb/phy/phy-isp1301-omap.c
@@ -40,9 +40,7 @@
#include <mach/usb.h>
-#ifndef DEBUG
-#undef VERBOSE
-#endif
+#undef VERBOSE
#define DRIVER_VERSION "24 August 2004"
@@ -387,7 +385,6 @@ static void b_idle(struct isp1301 *isp, const char *tag)
static void
dump_regs(struct isp1301 *isp, const char *label)
{
-#ifdef DEBUG
u8 ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1);
u8 status = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
u8 src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
@@ -396,7 +393,6 @@ dump_regs(struct isp1301 *isp, const char *label)
omap_readl(OTG_CTRL), label, state_name(isp),
ctrl, status, src);
/* mode control and irq enables don't change much */
-#endif
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index d08f33435e9..e9d4cd960ec 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -1419,7 +1419,7 @@ static int __init msm_otg_probe(struct platform_device *pdev)
struct usb_phy *phy;
dev_info(&pdev->dev, "msm_otg probe\n");
- if (!pdev->dev.platform_data) {
+ if (!dev_get_platdata(&pdev->dev)) {
dev_err(&pdev->dev, "No platform data given. Bailing out\n");
return -ENODEV;
}
@@ -1436,7 +1436,7 @@ static int __init msm_otg_probe(struct platform_device *pdev)
return -ENOMEM;
}
- motg->pdata = pdev->dev.platform_data;
+ motg->pdata = dev_get_platdata(&pdev->dev);
phy = &motg->phy;
phy->dev = &pdev->dev;
diff --git a/drivers/usb/phy/phy-mv-u3d-usb.c b/drivers/usb/phy/phy-mv-u3d-usb.c
index 1568ea63e33..d317903022b 100644
--- a/drivers/usb/phy/phy-mv-u3d-usb.c
+++ b/drivers/usb/phy/phy-mv-u3d-usb.c
@@ -82,7 +82,7 @@ static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value)
writel_relaxed(value, data);
}
-void mv_u3d_phy_shutdown(struct usb_phy *phy)
+static void mv_u3d_phy_shutdown(struct usb_phy *phy)
{
struct mv_u3d_phy *mv_u3d_phy;
void __iomem *base;
@@ -271,7 +271,7 @@ static int mv_u3d_phy_probe(struct platform_device *pdev)
void __iomem *phy_base;
int ret;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
return -EINVAL;
diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c
index 4a6b03c7387..98f6ac6a78e 100644
--- a/drivers/usb/phy/phy-mv-usb.c
+++ b/drivers/usb/phy/phy-mv-usb.c
@@ -653,7 +653,7 @@ static struct attribute_group inputs_attr_group = {
.attrs = inputs_attrs,
};
-int mv_otg_remove(struct platform_device *pdev)
+static int mv_otg_remove(struct platform_device *pdev)
{
struct mv_otg *mvotg = platform_get_drvdata(pdev);
@@ -673,7 +673,7 @@ int mv_otg_remove(struct platform_device *pdev)
static int mv_otg_probe(struct platform_device *pdev)
{
- struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+ struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct mv_otg *mvotg;
struct usb_otg *otg;
struct resource *r;
@@ -893,7 +893,7 @@ static int mv_otg_resume(struct platform_device *pdev)
static struct platform_driver mv_otg_driver = {
.probe = mv_otg_probe,
- .remove = __exit_p(mv_otg_remove),
+ .remove = mv_otg_remove,
.driver = {
.owner = THIS_MODULE,
.name = driver_name,
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index bd601c537c8..fdd33b44dbd 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -41,11 +41,14 @@ struct mxs_phy {
#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
-static void mxs_phy_hw_init(struct mxs_phy *mxs_phy)
+static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
{
+ int ret;
void __iomem *base = mxs_phy->phy.io_priv;
- stmp_reset_block(base + HW_USBPHY_CTRL);
+ ret = stmp_reset_block(base + HW_USBPHY_CTRL);
+ if (ret)
+ return ret;
/* Power up the PHY */
writel(0, base + HW_USBPHY_PWD);
@@ -54,6 +57,8 @@ static void mxs_phy_hw_init(struct mxs_phy *mxs_phy)
writel(BM_USBPHY_CTRL_ENUTMILEVEL2 |
BM_USBPHY_CTRL_ENUTMILEVEL3,
base + HW_USBPHY_CTRL_SET);
+
+ return 0;
}
static int mxs_phy_init(struct usb_phy *phy)
@@ -61,9 +66,7 @@ static int mxs_phy_init(struct usb_phy *phy)
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
clk_prepare_enable(mxs_phy->clk);
- mxs_phy_hw_init(mxs_phy);
-
- return 0;
+ return mxs_phy_hw_init(mxs_phy);
}
static void mxs_phy_shutdown(struct usb_phy *phy)
diff --git a/drivers/usb/phy/phy-omap-control.c b/drivers/usb/phy/phy-omap-control.c
index 1419ceda975..a4dda8e1256 100644
--- a/drivers/usb/phy/phy-omap-control.c
+++ b/drivers/usb/phy/phy-omap-control.c
@@ -197,7 +197,8 @@ static int omap_control_usb_probe(struct platform_device *pdev)
{
struct resource *res;
struct device_node *np = pdev->dev.of_node;
- struct omap_control_usb_platform_data *pdata = pdev->dev.platform_data;
+ struct omap_control_usb_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),
GFP_KERNEL);
diff --git a/drivers/usb/phy/phy-omap-usb2.c b/drivers/usb/phy/phy-omap-usb2.c
index 844ab68f08d..d266861d24f 100644
--- a/drivers/usb/phy/phy-omap-usb2.c
+++ b/drivers/usb/phy/phy-omap-usb2.c
@@ -98,8 +98,8 @@ static int omap_usb_set_peripheral(struct usb_otg *otg,
static int omap_usb2_suspend(struct usb_phy *x, int suspend)
{
- u32 ret;
struct omap_usb *phy = phy_to_omapusb(x);
+ int ret;
if (suspend && !phy->is_suspended) {
omap_control_usb_phy_power(phy->control_dev, 0);
@@ -108,8 +108,7 @@ static int omap_usb2_suspend(struct usb_phy *x, int suspend)
} else if (!suspend && phy->is_suspended) {
ret = pm_runtime_get_sync(phy->dev);
if (ret < 0) {
- dev_err(phy->dev, "get_sync failed with err %d\n",
- ret);
+ dev_err(phy->dev, "get_sync failed with err %d\n", ret);
return ret;
}
omap_control_usb_phy_power(phy->control_dev, 1);
@@ -209,9 +208,9 @@ static int omap_usb2_runtime_suspend(struct device *dev)
static int omap_usb2_runtime_resume(struct device *dev)
{
- u32 ret = 0;
struct platform_device *pdev = to_platform_device(dev);
struct omap_usb *phy = platform_get_drvdata(pdev);
+ int ret;
ret = clk_enable(phy->wkupclk);
if (ret < 0) {
diff --git a/drivers/usb/phy/phy-omap-usb3.c b/drivers/usb/phy/phy-omap-usb3.c
index efe6e1464f4..fc15694d303 100644
--- a/drivers/usb/phy/phy-omap-usb3.c
+++ b/drivers/usb/phy/phy-omap-usb3.c
@@ -27,7 +27,6 @@
#include <linux/delay.h>
#include <linux/usb/omap_control_usb.h>
-#define NUM_SYS_CLKS 6
#define PLL_STATUS 0x00000004
#define PLL_GO 0x00000008
#define PLL_CONFIGURATION1 0x0000000C
@@ -57,26 +56,32 @@
*/
# define PLL_IDLE_TIME 100;
-enum sys_clk_rate {
- CLK_RATE_UNDEFINED = -1,
- CLK_RATE_12MHZ,
- CLK_RATE_16MHZ,
- CLK_RATE_19MHZ,
- CLK_RATE_20MHZ,
- CLK_RATE_26MHZ,
- CLK_RATE_38MHZ
+struct usb_dpll_map {
+ unsigned long rate;
+ struct usb_dpll_params params;
};
-static struct usb_dpll_params omap_usb3_dpll_params[NUM_SYS_CLKS] = {
- {1250, 5, 4, 20, 0}, /* 12 MHz */
- {3125, 20, 4, 20, 0}, /* 16.8 MHz */
- {1172, 8, 4, 20, 65537}, /* 19.2 MHz */
- {1250, 12, 4, 20, 0}, /* 26 MHz */
- {3125, 47, 4, 20, 92843}, /* 38.4 MHz */
- {1000, 7, 4, 10, 0}, /* 20 MHz */
-
+static struct usb_dpll_map dpll_map[] = {
+ {12000000, {1250, 5, 4, 20, 0} }, /* 12 MHz */
+ {16800000, {3125, 20, 4, 20, 0} }, /* 16.8 MHz */
+ {19200000, {1172, 8, 4, 20, 65537} }, /* 19.2 MHz */
+ {20000000, {1000, 7, 4, 10, 0} }, /* 20 MHz */
+ {26000000, {1250, 12, 4, 20, 0} }, /* 26 MHz */
+ {38400000, {3125, 47, 4, 20, 92843} }, /* 38.4 MHz */
};
+static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dpll_map); i++) {
+ if (rate == dpll_map[i].rate)
+ return &dpll_map[i].params;
+ }
+
+ return 0;
+}
+
static int omap_usb3_suspend(struct usb_phy *x, int suspend)
{
struct omap_usb *phy = phy_to_omapusb(x);
@@ -116,26 +121,6 @@ static int omap_usb3_suspend(struct usb_phy *x, int suspend)
return 0;
}
-static inline enum sys_clk_rate __get_sys_clk_index(unsigned long rate)
-{
- switch (rate) {
- case 12000000:
- return CLK_RATE_12MHZ;
- case 16800000:
- return CLK_RATE_16MHZ;
- case 19200000:
- return CLK_RATE_19MHZ;
- case 20000000:
- return CLK_RATE_20MHZ;
- case 26000000:
- return CLK_RATE_26MHZ;
- case 38400000:
- return CLK_RATE_38MHZ;
- default:
- return CLK_RATE_UNDEFINED;
- }
-}
-
static void omap_usb_dpll_relock(struct omap_usb *phy)
{
u32 val;
@@ -155,39 +140,39 @@ static int omap_usb_dpll_lock(struct omap_usb *phy)
{
u32 val;
unsigned long rate;
- enum sys_clk_rate clk_index;
-
- rate = clk_get_rate(phy->sys_clk);
- clk_index = __get_sys_clk_index(rate);
+ struct usb_dpll_params *dpll_params;
- if (clk_index == CLK_RATE_UNDEFINED) {
- pr_err("dpll cannot be locked for sys clk freq:%luHz\n", rate);
+ rate = clk_get_rate(phy->sys_clk);
+ dpll_params = omap_usb3_get_dpll_params(rate);
+ if (!dpll_params) {
+ dev_err(phy->dev,
+ "No DPLL configuration for %lu Hz SYS CLK\n", rate);
return -EINVAL;
}
val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
val &= ~PLL_REGN_MASK;
- val |= omap_usb3_dpll_params[clk_index].n << PLL_REGN_SHIFT;
+ val |= dpll_params->n << PLL_REGN_SHIFT;
omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
val &= ~PLL_SELFREQDCO_MASK;
- val |= omap_usb3_dpll_params[clk_index].freq << PLL_SELFREQDCO_SHIFT;
+ val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
val &= ~PLL_REGM_MASK;
- val |= omap_usb3_dpll_params[clk_index].m << PLL_REGM_SHIFT;
+ val |= dpll_params->m << PLL_REGM_SHIFT;
omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
val &= ~PLL_REGM_F_MASK;
- val |= omap_usb3_dpll_params[clk_index].mf << PLL_REGM_F_SHIFT;
+ val |= dpll_params->mf << PLL_REGM_F_SHIFT;
omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
val &= ~PLL_SD_MASK;
- val |= omap_usb3_dpll_params[clk_index].sd << PLL_SD_SHIFT;
+ val |= dpll_params->sd << PLL_SD_SHIFT;
omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
omap_usb_dpll_relock(phy);
@@ -198,8 +183,12 @@ static int omap_usb_dpll_lock(struct omap_usb *phy)
static int omap_usb3_init(struct usb_phy *x)
{
struct omap_usb *phy = phy_to_omapusb(x);
+ int ret;
+
+ ret = omap_usb_dpll_lock(phy);
+ if (ret)
+ return ret;
- omap_usb_dpll_lock(phy);
omap_control_usb3_phy_power(phy->control_dev, 1);
return 0;
diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c
index ae909408958..33265a5b2cd 100644
--- a/drivers/usb/phy/phy-rcar-usb.c
+++ b/drivers/usb/phy/phy-rcar-usb.c
@@ -83,7 +83,7 @@ static int rcar_usb_phy_init(struct usb_phy *phy)
{
struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
struct device *dev = phy->dev;
- struct rcar_phy_platform_data *pdata = dev->platform_data;
+ struct rcar_phy_platform_data *pdata = dev_get_platdata(dev);
void __iomem *reg0 = priv->reg0;
void __iomem *reg1 = priv->reg1;
static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT };
@@ -184,17 +184,12 @@ static int rcar_usb_phy_probe(struct platform_device *pdev)
void __iomem *reg0, *reg1 = NULL;
int ret;
- if (!pdev->dev.platform_data) {
+ if (!dev_get_platdata(&pdev->dev)) {
dev_err(dev, "No platform data\n");
return -EINVAL;
}
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res0) {
- dev_err(dev, "Not enough platform resources\n");
- return -EINVAL;
- }
-
reg0 = devm_ioremap_resource(dev, res0);
if (IS_ERR(reg0))
return PTR_ERR(reg0);
diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c
index 1011c16ade7..ff70e4b19b9 100644
--- a/drivers/usb/phy/phy-samsung-usb2.c
+++ b/drivers/usb/phy/phy-samsung-usb2.c
@@ -359,7 +359,7 @@ static int samsung_usb2phy_probe(struct platform_device *pdev)
{
struct samsung_usbphy *sphy;
struct usb_otg *otg;
- struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+ struct samsung_usbphy_data *pdata = dev_get_platdata(&pdev->dev);
const struct samsung_usbphy_drvdata *drv_data;
struct device *dev = &pdev->dev;
struct resource *phy_mem;
@@ -388,7 +388,7 @@ static int samsung_usb2phy_probe(struct platform_device *pdev)
clk = devm_clk_get(dev, "otg");
if (IS_ERR(clk)) {
- dev_err(dev, "Failed to get otg clock\n");
+ dev_err(dev, "Failed to get usbhost/otg clock\n");
return PTR_ERR(clk);
}
diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c
index 300e0cf5e31..c6eb22213de 100644
--- a/drivers/usb/phy/phy-samsung-usb3.c
+++ b/drivers/usb/phy/phy-samsung-usb3.c
@@ -231,7 +231,7 @@ static void samsung_usb3phy_shutdown(struct usb_phy *phy)
static int samsung_usb3phy_probe(struct platform_device *pdev)
{
struct samsung_usbphy *sphy;
- struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+ struct samsung_usbphy_data *pdata = dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev;
struct resource *phy_mem;
void __iomem *phy_base;
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index cec0855ed24..e9cb1cb8abc 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -28,20 +28,28 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
+#include <linux/usb/of.h>
#include <asm/mach-types.h>
#include <linux/usb/ehci_def.h>
#include <linux/usb/tegra_usb_phy.h>
+#include <linux/regulator/consumer.h>
#define ULPI_VIEWPORT 0x170
-/* PORTSC registers */
+/* PORTSC PTS/PHCD bits, Tegra20 only */
#define TEGRA_USB_PORTSC1 0x184
#define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
#define TEGRA_USB_PORTSC1_PHCD (1 << 23)
+/* HOSTPC1 PTS/PHCD bits, Tegra30 and above */
+#define TEGRA_USB_HOSTPC1_DEVLC 0x1b4
+#define TEGRA_USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
+#define TEGRA_USB_HOSTPC1_DEVLC_PHCD (1 << 22)
+
/* Bits of PORTSC1, which will get cleared by writing 1 into them */
#define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
@@ -84,16 +92,22 @@
#define UTMIP_XCVR_CFG0 0x808
#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
+#define UTMIP_XCVR_SETUP_MSB(x) ((((x) & 0x70) >> 4) << 22)
#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
-#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
+#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
+#define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4)
+#define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25)
#define UTMIP_BIAS_CFG0 0x80c
#define UTMIP_OTGPD (1 << 11)
#define UTMIP_BIASPD (1 << 10)
+#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0)
+#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2)
+#define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24)
#define UTMIP_HSRX_CFG0 0x810
#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
@@ -137,6 +151,12 @@
#define UTMIP_BIAS_CFG1 0x83c
#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
+/* For Tegra30 and above only, the address is different in Tegra20 */
+#define USB_USBMODE 0x1f8
+#define USB_USBMODE_MASK (3 << 0)
+#define USB_USBMODE_HOST (3 << 0)
+#define USB_USBMODE_DEVICE (2 << 0)
+
static DEFINE_SPINLOCK(utmip_pad_lock);
static int utmip_pad_count;
@@ -184,36 +204,22 @@ static const struct tegra_xtal_freq tegra_freq_table[] = {
},
};
-static struct tegra_utmip_config utmip_default[] = {
- [0] = {
- .hssync_start_delay = 9,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 9,
- .xcvr_lsfslew = 1,
- .xcvr_lsrslew = 1,
- },
- [2] = {
- .hssync_start_delay = 9,
- .idle_wait_delay = 17,
- .elastic_limit = 16,
- .term_range_adj = 6,
- .xcvr_setup = 9,
- .xcvr_lsfslew = 2,
- .xcvr_lsrslew = 2,
- },
-};
-
static void set_pts(struct tegra_usb_phy *phy, u8 pts_val)
{
void __iomem *base = phy->regs;
unsigned long val;
- val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
- val &= ~TEGRA_USB_PORTSC1_PTS(3);
- val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3);
- writel(val, base + TEGRA_USB_PORTSC1);
+ if (phy->soc_config->has_hostpc) {
+ val = readl(base + TEGRA_USB_HOSTPC1_DEVLC);
+ val &= ~TEGRA_USB_HOSTPC1_DEVLC_PTS(~0);
+ val |= TEGRA_USB_HOSTPC1_DEVLC_PTS(pts_val);
+ writel(val, base + TEGRA_USB_HOSTPC1_DEVLC);
+ } else {
+ val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
+ val &= ~TEGRA_USB_PORTSC1_PTS(~0);
+ val |= TEGRA_USB_PORTSC1_PTS(pts_val);
+ writel(val, base + TEGRA_USB_PORTSC1);
+ }
}
static void set_phcd(struct tegra_usb_phy *phy, bool enable)
@@ -221,17 +227,26 @@ static void set_phcd(struct tegra_usb_phy *phy, bool enable)
void __iomem *base = phy->regs;
unsigned long val;
- val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
- if (enable)
- val |= TEGRA_USB_PORTSC1_PHCD;
- else
- val &= ~TEGRA_USB_PORTSC1_PHCD;
- writel(val, base + TEGRA_USB_PORTSC1);
+ if (phy->soc_config->has_hostpc) {
+ val = readl(base + TEGRA_USB_HOSTPC1_DEVLC);
+ if (enable)
+ val |= TEGRA_USB_HOSTPC1_DEVLC_PHCD;
+ else
+ val &= ~TEGRA_USB_HOSTPC1_DEVLC_PHCD;
+ writel(val, base + TEGRA_USB_HOSTPC1_DEVLC);
+ } else {
+ val = readl(base + TEGRA_USB_PORTSC1) & ~PORT_RWC_BITS;
+ if (enable)
+ val |= TEGRA_USB_PORTSC1_PHCD;
+ else
+ val &= ~TEGRA_USB_PORTSC1_PHCD;
+ writel(val, base + TEGRA_USB_PORTSC1);
+ }
}
static int utmip_pad_open(struct tegra_usb_phy *phy)
{
- phy->pad_clk = devm_clk_get(phy->dev, "utmi-pads");
+ phy->pad_clk = devm_clk_get(phy->u_phy.dev, "utmi-pads");
if (IS_ERR(phy->pad_clk)) {
pr_err("%s: can't get utmip pad clock\n", __func__);
return PTR_ERR(phy->pad_clk);
@@ -244,6 +259,7 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy)
{
unsigned long val, flags;
void __iomem *base = phy->pad_regs;
+ struct tegra_utmip_config *config = phy->config;
clk_prepare_enable(phy->pad_clk);
@@ -252,6 +268,16 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy)
if (utmip_pad_count++ == 0) {
val = readl(base + UTMIP_BIAS_CFG0);
val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+
+ if (phy->soc_config->requires_extra_tuning_parameters) {
+ val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) |
+ UTMIP_HSDISCON_LEVEL(~0) |
+ UTMIP_HSDISCON_LEVEL_MSB(~0));
+
+ val |= UTMIP_HSSQUELCH_LEVEL(config->hssquelch_level);
+ val |= UTMIP_HSDISCON_LEVEL(config->hsdiscon_level);
+ val |= UTMIP_HSDISCON_LEVEL_MSB(config->hsdiscon_level);
+ }
writel(val, base + UTMIP_BIAS_CFG0);
}
@@ -361,7 +387,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
}
val = readl(base + UTMIP_TX_CFG0);
- val &= ~UTMIP_FS_PREABMLE_J;
+ val |= UTMIP_FS_PREABMLE_J;
writel(val, base + UTMIP_TX_CFG0);
val = readl(base + UTMIP_HSRX_CFG0);
@@ -384,34 +410,56 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
writel(val, base + UTMIP_MISC_CFG0);
- val = readl(base + UTMIP_MISC_CFG1);
- val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
- val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
- UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
- writel(val, base + UTMIP_MISC_CFG1);
-
- val = readl(base + UTMIP_PLL_CFG1);
- val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
- val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
- UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
- writel(val, base + UTMIP_PLL_CFG1);
+ if (!phy->soc_config->utmi_pll_config_in_car_module) {
+ val = readl(base + UTMIP_MISC_CFG1);
+ val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) |
+ UTMIP_PLLU_STABLE_COUNT(~0));
+ val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
+ UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
+ writel(val, base + UTMIP_MISC_CFG1);
+
+ val = readl(base + UTMIP_PLL_CFG1);
+ val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) |
+ UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
+ val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
+ UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+ writel(val, base + UTMIP_PLL_CFG1);
+ }
- if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+ if (phy->mode == USB_DR_MODE_PERIPHERAL) {
val = readl(base + USB_SUSP_CTRL);
val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ } else {
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
}
utmip_pad_power_on(phy);
val = readl(base + UTMIP_XCVR_CFG0);
val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
- UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) |
- UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) |
- UTMIP_XCVR_HSSLEW_MSB(~0));
- val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
+ UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_LSBIAS_SEL |
+ UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_SETUP_MSB(~0) |
+ UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0));
+
+ if (!config->xcvr_setup_use_fuses) {
+ val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
+ val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup);
+ }
val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+
+ if (phy->soc_config->requires_extra_tuning_parameters) {
+ val &= ~(UTMIP_XCVR_HSSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
+ val |= UTMIP_XCVR_HSSLEW(config->xcvr_hsslew);
+ val |= UTMIP_XCVR_HSSLEW_MSB(config->xcvr_hsslew);
+ }
writel(val, base + UTMIP_XCVR_CFG0);
val = readl(base + UTMIP_XCVR_CFG1);
@@ -420,23 +468,19 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
writel(val, base + UTMIP_XCVR_CFG1);
- val = readl(base + UTMIP_BAT_CHRG_CFG0);
- val &= ~UTMIP_PD_CHRG;
- writel(val, base + UTMIP_BAT_CHRG_CFG0);
-
val = readl(base + UTMIP_BIAS_CFG1);
val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
writel(val, base + UTMIP_BIAS_CFG1);
- if (phy->is_legacy_phy) {
- val = readl(base + UTMIP_SPARE_CFG0);
- if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
- val &= ~FUSE_SETUP_SEL;
- else
- val |= FUSE_SETUP_SEL;
- writel(val, base + UTMIP_SPARE_CFG0);
- } else {
+ val = readl(base + UTMIP_SPARE_CFG0);
+ if (config->xcvr_setup_use_fuses)
+ val |= FUSE_SETUP_SEL;
+ else
+ val &= ~FUSE_SETUP_SEL;
+ writel(val, base + UTMIP_SPARE_CFG0);
+
+ if (!phy->is_legacy_phy) {
val = readl(base + USB_SUSP_CTRL);
val |= UTMIP_PHY_ENABLE;
writel(val, base + USB_SUSP_CTRL);
@@ -459,6 +503,16 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
utmi_phy_clk_enable(phy);
+ if (phy->soc_config->requires_usbmode_setup) {
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ if (phy->mode == USB_DR_MODE_HOST)
+ val |= USB_USBMODE_HOST;
+ else
+ val |= USB_USBMODE_DEVICE;
+ writel(val, base + USB_USBMODE);
+ }
+
if (!phy->is_legacy_phy)
set_pts(phy, 0);
@@ -472,7 +526,7 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
utmi_phy_clk_disable(phy);
- if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+ if (phy->mode == USB_DR_MODE_PERIPHERAL) {
val = readl(base + USB_SUSP_CTRL);
val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
@@ -560,13 +614,15 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
ret = gpio_direction_output(phy->reset_gpio, 0);
if (ret < 0) {
- dev_err(phy->dev, "gpio %d not set to 0\n", phy->reset_gpio);
+ dev_err(phy->u_phy.dev, "gpio %d not set to 0\n",
+ phy->reset_gpio);
return ret;
}
msleep(5);
ret = gpio_direction_output(phy->reset_gpio, 1);
if (ret < 0) {
- dev_err(phy->dev, "gpio %d not set to 1\n", phy->reset_gpio);
+ dev_err(phy->u_phy.dev, "gpio %d not set to 1\n",
+ phy->reset_gpio);
return ret;
}
@@ -634,6 +690,9 @@ static void tegra_usb_phy_close(struct usb_phy *x)
{
struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+ if (!IS_ERR(phy->vbus))
+ regulator_disable(phy->vbus);
+
clk_disable_unprepare(phy->pll_u);
}
@@ -666,29 +725,30 @@ static int ulpi_open(struct tegra_usb_phy *phy)
{
int err;
- phy->clk = devm_clk_get(phy->dev, "ulpi-link");
+ phy->clk = devm_clk_get(phy->u_phy.dev, "ulpi-link");
if (IS_ERR(phy->clk)) {
pr_err("%s: can't get ulpi clock\n", __func__);
return PTR_ERR(phy->clk);
}
- err = devm_gpio_request(phy->dev, phy->reset_gpio, "ulpi_phy_reset_b");
+ err = devm_gpio_request(phy->u_phy.dev, phy->reset_gpio,
+ "ulpi_phy_reset_b");
if (err < 0) {
- dev_err(phy->dev, "request failed for gpio: %d\n",
+ dev_err(phy->u_phy.dev, "request failed for gpio: %d\n",
phy->reset_gpio);
return err;
}
err = gpio_direction_output(phy->reset_gpio, 0);
if (err < 0) {
- dev_err(phy->dev, "gpio %d direction not set to output\n",
+ dev_err(phy->u_phy.dev, "gpio %d direction not set to output\n",
phy->reset_gpio);
return err;
}
phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
if (!phy->ulpi) {
- dev_err(phy->dev, "otg_ulpi_create returned NULL\n");
+ dev_err(phy->u_phy.dev, "otg_ulpi_create returned NULL\n");
err = -ENOMEM;
return err;
}
@@ -703,14 +763,7 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy)
int i;
int err;
- if (!phy->is_ulpi_phy) {
- if (phy->is_legacy_phy)
- phy->config = &utmip_default[0];
- else
- phy->config = &utmip_default[2];
- }
-
- phy->pll_u = devm_clk_get(phy->dev, "pll_u");
+ phy->pll_u = devm_clk_get(phy->u_phy.dev, "pll_u");
if (IS_ERR(phy->pll_u)) {
pr_err("Can't get pll_u clock\n");
return PTR_ERR(phy->pll_u);
@@ -733,6 +786,16 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy)
goto fail;
}
+ if (!IS_ERR(phy->vbus)) {
+ err = regulator_enable(phy->vbus);
+ if (err) {
+ dev_err(phy->u_phy.dev,
+ "failed to enable usb vbus regulator: %d\n",
+ err);
+ goto fail;
+ }
+ }
+
if (phy->is_ulpi_phy)
err = ulpi_open(phy);
else
@@ -784,11 +847,138 @@ void tegra_ehci_phy_restore_end(struct usb_phy *x)
}
EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
+static int read_utmi_param(struct platform_device *pdev, const char *param,
+ u8 *dest)
+{
+ u32 value;
+ int err = of_property_read_u32(pdev->dev.of_node, param, &value);
+ *dest = (u8)value;
+ if (err < 0)
+ dev_err(&pdev->dev, "Failed to read USB UTMI parameter %s: %d\n",
+ param, err);
+ return err;
+}
+
+static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,
+ struct platform_device *pdev)
+{
+ struct resource *res;
+ int err;
+ struct tegra_utmip_config *config;
+
+ tegra_phy->is_ulpi_phy = false;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n");
+ return -ENXIO;
+ }
+
+ tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!tegra_phy->regs) {
+ dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n");
+ return -ENOMEM;
+ }
+
+ tegra_phy->config = devm_kzalloc(&pdev->dev,
+ sizeof(*tegra_phy->config), GFP_KERNEL);
+ if (!tegra_phy->config) {
+ dev_err(&pdev->dev,
+ "unable to allocate memory for USB UTMIP config\n");
+ return -ENOMEM;
+ }
+
+ config = tegra_phy->config;
+
+ err = read_utmi_param(pdev, "nvidia,hssync-start-delay",
+ &config->hssync_start_delay);
+ if (err < 0)
+ return err;
+
+ err = read_utmi_param(pdev, "nvidia,elastic-limit",
+ &config->elastic_limit);
+ if (err < 0)
+ return err;
+
+ err = read_utmi_param(pdev, "nvidia,idle-wait-delay",
+ &config->idle_wait_delay);
+ if (err < 0)
+ return err;
+
+ err = read_utmi_param(pdev, "nvidia,term-range-adj",
+ &config->term_range_adj);
+ if (err < 0)
+ return err;
+
+ err = read_utmi_param(pdev, "nvidia,xcvr-lsfslew",
+ &config->xcvr_lsfslew);
+ if (err < 0)
+ return err;
+
+ err = read_utmi_param(pdev, "nvidia,xcvr-lsrslew",
+ &config->xcvr_lsrslew);
+ if (err < 0)
+ return err;
+
+ if (tegra_phy->soc_config->requires_extra_tuning_parameters) {
+ err = read_utmi_param(pdev, "nvidia,xcvr-hsslew",
+ &config->xcvr_hsslew);
+ if (err < 0)
+ return err;
+
+ err = read_utmi_param(pdev, "nvidia,hssquelch-level",
+ &config->hssquelch_level);
+ if (err < 0)
+ return err;
+
+ err = read_utmi_param(pdev, "nvidia,hsdiscon-level",
+ &config->hsdiscon_level);
+ if (err < 0)
+ return err;
+ }
+
+ config->xcvr_setup_use_fuses = of_property_read_bool(
+ pdev->dev.of_node, "nvidia,xcvr-setup-use-fuses");
+
+ if (!config->xcvr_setup_use_fuses) {
+ err = read_utmi_param(pdev, "nvidia,xcvr-setup",
+ &config->xcvr_setup);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct tegra_phy_soc_config tegra20_soc_config = {
+ .utmi_pll_config_in_car_module = false,
+ .has_hostpc = false,
+ .requires_usbmode_setup = false,
+ .requires_extra_tuning_parameters = false,
+};
+
+static const struct tegra_phy_soc_config tegra30_soc_config = {
+ .utmi_pll_config_in_car_module = true,
+ .has_hostpc = true,
+ .requires_usbmode_setup = true,
+ .requires_extra_tuning_parameters = true,
+};
+
+static struct of_device_id tegra_usb_phy_id_table[] = {
+ { .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config },
+ { .compatible = "nvidia,tegra20-usb-phy", .data = &tegra20_soc_config },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table);
+
static int tegra_usb_phy_probe(struct platform_device *pdev)
{
+ const struct of_device_id *match;
struct resource *res;
struct tegra_usb_phy *tegra_phy = NULL;
struct device_node *np = pdev->dev.of_node;
+ enum usb_phy_interface phy_type;
int err;
tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL);
@@ -797,6 +987,13 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ match = of_match_device(tegra_usb_phy_id_table, &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+ tegra_phy->soc_config = match->data;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "Failed to get I/O memory\n");
@@ -813,23 +1010,15 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
tegra_phy->is_legacy_phy =
of_property_read_bool(np, "nvidia,has-legacy-mode");
- err = of_property_match_string(np, "phy_type", "ulpi");
- if (err < 0) {
- tegra_phy->is_ulpi_phy = false;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n");
- return -ENXIO;
- }
+ phy_type = of_usb_get_phy_mode(np);
+ switch (phy_type) {
+ case USBPHY_INTERFACE_MODE_UTMI:
+ err = utmi_phy_probe(tegra_phy, pdev);
+ if (err < 0)
+ return err;
+ break;
- tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!tegra_phy->regs) {
- dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n");
- return -ENOMEM;
- }
- } else {
+ case USBPHY_INTERFACE_MODE_ULPI:
tegra_phy->is_ulpi_phy = true;
tegra_phy->reset_gpio =
@@ -839,19 +1028,35 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
tegra_phy->reset_gpio);
return tegra_phy->reset_gpio;
}
+ tegra_phy->config = NULL;
+ break;
+
+ default:
+ dev_err(&pdev->dev, "phy_type is invalid or unsupported\n");
+ return -EINVAL;
}
- err = of_property_match_string(np, "dr_mode", "otg");
- if (err < 0) {
- err = of_property_match_string(np, "dr_mode", "peripheral");
- if (err < 0)
- tegra_phy->mode = TEGRA_USB_PHY_MODE_HOST;
- else
- tegra_phy->mode = TEGRA_USB_PHY_MODE_DEVICE;
- } else
- tegra_phy->mode = TEGRA_USB_PHY_MODE_OTG;
+ if (of_find_property(np, "dr_mode", NULL))
+ tegra_phy->mode = of_usb_get_dr_mode(np);
+ else
+ tegra_phy->mode = USB_DR_MODE_HOST;
- tegra_phy->dev = &pdev->dev;
+ if (tegra_phy->mode == USB_DR_MODE_UNKNOWN) {
+ dev_err(&pdev->dev, "dr_mode is invalid\n");
+ return -EINVAL;
+ }
+
+ /* On some boards, the VBUS regulator doesn't need to be controlled */
+ if (of_find_property(np, "vbus-supply", NULL)) {
+ tegra_phy->vbus = devm_regulator_get(&pdev->dev, "vbus");
+ if (IS_ERR(tegra_phy->vbus))
+ return PTR_ERR(tegra_phy->vbus);
+ } else {
+ dev_notice(&pdev->dev, "no vbus regulator");
+ tegra_phy->vbus = ERR_PTR(-ENODEV);
+ }
+
+ tegra_phy->u_phy.dev = &pdev->dev;
err = tegra_usb_phy_init(tegra_phy);
if (err < 0)
return err;
@@ -859,18 +1064,29 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
tegra_phy->u_phy.shutdown = tegra_usb_phy_close;
tegra_phy->u_phy.set_suspend = tegra_usb_phy_suspend;
- dev_set_drvdata(&pdev->dev, tegra_phy);
+ platform_set_drvdata(pdev, tegra_phy);
+
+ err = usb_add_phy_dev(&tegra_phy->u_phy);
+ if (err < 0) {
+ tegra_usb_phy_close(&tegra_phy->u_phy);
+ return err;
+ }
+
return 0;
}
-static struct of_device_id tegra_usb_phy_id_table[] = {
- { .compatible = "nvidia,tegra20-usb-phy", },
- { },
-};
-MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table);
+static int tegra_usb_phy_remove(struct platform_device *pdev)
+{
+ struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&tegra_phy->u_phy);
+
+ return 0;
+}
static struct platform_driver tegra_usb_phy_driver = {
.probe = tegra_usb_phy_probe,
+ .remove = tegra_usb_phy_remove,
.driver = {
.name = "tegra-phy",
.owner = THIS_MODULE,
@@ -879,29 +1095,5 @@ static struct platform_driver tegra_usb_phy_driver = {
};
module_platform_driver(tegra_usb_phy_driver);
-static int tegra_usb_phy_match(struct device *dev, void *data)
-{
- struct tegra_usb_phy *tegra_phy = dev_get_drvdata(dev);
- struct device_node *dn = data;
-
- return (tegra_phy->dev->of_node == dn) ? 1 : 0;
-}
-
-struct usb_phy *tegra_usb_get_phy(struct device_node *dn)
-{
- struct device *dev;
- struct tegra_usb_phy *tegra_phy;
-
- dev = driver_find_device(&tegra_usb_phy_driver.driver, NULL, dn,
- tegra_usb_phy_match);
- if (!dev)
- return ERR_PTR(-EPROBE_DEFER);
-
- tegra_phy = dev_get_drvdata(dev);
-
- return &tegra_phy->u_phy;
-}
-EXPORT_SYMBOL_GPL(tegra_usb_get_phy);
-
MODULE_DESCRIPTION("Tegra USB PHY driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-twl4030-usb.c b/drivers/usb/phy/phy-twl4030-usb.c
index 8f78d2d4072..90730c8762b 100644
--- a/drivers/usb/phy/phy-twl4030-usb.c
+++ b/drivers/usb/phy/phy-twl4030-usb.c
@@ -648,7 +648,7 @@ static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host)
static int twl4030_usb_probe(struct platform_device *pdev)
{
- struct twl4030_usb_data *pdata = pdev->dev.platform_data;
+ struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev);
struct twl4030_usb *twl;
int status, err;
struct usb_otg *otg;
diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index 1753bd367e0..16dbc938267 100644
--- a/drivers/usb/phy/phy-twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -324,7 +324,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
int status, err;
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
- struct twl4030_usb_data *pdata = dev->platform_data;
+ struct twl4030_usb_data *pdata = dev_get_platdata(dev);
twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL);
if (!twl)
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index cfd205036ab..17267b0a2e9 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -416,7 +416,7 @@ static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
*/
static int usbhs_probe(struct platform_device *pdev)
{
- struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
+ struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev);
struct renesas_usbhs_driver_callback *dfunc;
struct usbhs_priv *priv;
struct resource *res, *irq_res;
@@ -499,7 +499,7 @@ static int usbhs_probe(struct platform_device *pdev)
goto probe_end_fifo_exit;
/* dev_set_drvdata should be called after usbhs_mod_init */
- dev_set_drvdata(&pdev->dev, priv);
+ platform_set_drvdata(pdev, priv);
/*
* deviece reset here because
@@ -558,7 +558,7 @@ probe_end_pipe_exit:
static int usbhs_remove(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
- struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
+ struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev);
struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback;
dev_dbg(&pdev->dev, "usb remove\n");
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index ed4949faa70..3385aeb5a36 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -77,9 +77,9 @@ struct usbhsg_recip_handle {
struct usbhsg_gpriv, mod)
#define __usbhsg_for_each_uep(start, pos, g, i) \
- for (i = start, pos = (g)->uep + i; \
- i < (g)->uep_size; \
- i++, pos = (g)->uep + i)
+ for ((i) = start; \
+ ((i) < (g)->uep_size) && ((pos) = (g)->uep + (i)); \
+ (i)++)
#define usbhsg_for_each_uep(pos, gpriv, i) \
__usbhsg_for_each_uep(1, pos, gpriv, i)
@@ -855,10 +855,6 @@ static int usbhsg_gadget_stop(struct usb_gadget *gadget,
struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
- if (!driver ||
- !driver->unbind)
- return -EINVAL;
-
usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD);
gpriv->driver = NULL;
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index b86815421c8..e40f565004d 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -111,9 +111,9 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";
container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod)
#define __usbhsh_for_each_udev(start, pos, h, i) \
- for (i = start, pos = (h)->udev + i; \
- i < USBHSH_DEVICE_MAX; \
- i++, pos = (h)->udev + i)
+ for ((i) = start; \
+ ((i) < USBHSH_DEVICE_MAX) && ((pos) = (h)->udev + (i)); \
+ (i)++)
#define usbhsh_for_each_udev(pos, hpriv, i) \
__usbhsh_for_each_udev(1, pos, hpriv, i)
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index b476fde955b..3e534987983 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -54,9 +54,9 @@ struct usbhs_pipe_info {
* pipe list
*/
#define __usbhs_for_each_pipe(start, pos, info, i) \
- for (i = start, pos = (info)->pipe + i; \
- i < (info)->size; \
- i++, pos = (info)->pipe + i)
+ for ((i) = start; \
+ ((i) < (info)->size) && ((pos) = (info)->pipe + (i)); \
+ (i)++)
#define usbhs_for_each_pipe(pos, priv, i) \
__usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i)
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 8c3a42ea910..c454bfa22a1 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -51,6 +51,24 @@ config USB_SERIAL_GENERIC
support" be compiled as a module for this driver to be used
properly.
+config USB_SERIAL_SIMPLE
+ tristate "USB Serial Simple Driver"
+ help
+ Say Y here to use the USB serial "simple" driver. This driver
+ handles a wide range of very simple devices, all in one
+ driver. Specifically, it supports:
+ - Suunto ANT+ USB device.
+ - Fundamental Software dongle.
+ - HP4x calculators
+ - a number of Motoroloa phones
+ - Siemens USB/MPI adapter.
+ - ViVOtech ViVOpay USB device.
+ - Infineon Modem Flashloader USB interface
+ - ZIO Motherboard USB serial interface
+
+ To compile this driver as a module, choose M here: the module
+ will be called usb-serial-simple.
+
config USB_SERIAL_AIRCABLE
tristate "USB AIRcable Bluetooth Dongle Driver"
help
@@ -158,14 +176,6 @@ config USB_SERIAL_FTDI_SIO
To compile this driver as a module, choose M here: the
module will be called ftdi_sio.
-config USB_SERIAL_FUNSOFT
- tristate "USB Fundamental Software Dongle Driver"
- ---help---
- Say Y here if you want to use the Fundamental Software dongle.
-
- To compile this driver as a module, choose M here: the
- module will be called funsoft.
-
config USB_SERIAL_VISOR
tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver"
help
@@ -462,15 +472,6 @@ config USB_SERIAL_MOS7840
To compile this driver as a module, choose M here: the
module will be called mos7840. If unsure, choose N.
-config USB_SERIAL_MOTOROLA
- tristate "USB Motorola Phone modem driver"
- ---help---
- Say Y here if you want to use a Motorola phone with a USB
- connector as a modem link.
-
- To compile this driver as a module, choose M here: the
- module will be called moto_modem. If unsure, choose N.
-
config USB_SERIAL_NAVMAN
tristate "USB Navman GPS device"
help
@@ -525,14 +526,6 @@ config USB_SERIAL_SPCP8X5
To compile this driver as a module, choose M here: the
module will be called spcp8x5.
-config USB_SERIAL_HP4X
- tristate "USB HP4x Calculators support"
- help
- Say Y here if you want to use an Hewlett-Packard 4x Calculator.
-
- To compile this driver as a module, choose M here: the
- module will be called hp4x.
-
config USB_SERIAL_SAFE
tristate "USB Safe Serial (Encapsulated) Driver"
@@ -540,14 +533,6 @@ config USB_SERIAL_SAFE_PADDED
bool "USB Secure Encapsulated Driver - Padded"
depends on USB_SERIAL_SAFE
-config USB_SERIAL_SIEMENS_MPI
- tristate "USB Siemens MPI driver"
- help
- Say M here if you want to use a Siemens USB/MPI adapter.
-
- To compile this driver as a module, choose M here: the
- module will be called siemens_mpi.
-
config USB_SERIAL_SIERRAWIRELESS
tristate "USB Sierra Wireless Driver"
help
@@ -639,14 +624,6 @@ config USB_SERIAL_OPTICON
To compile this driver as a module, choose M here: the
module will be called opticon.
-config USB_SERIAL_VIVOPAY_SERIAL
- tristate "USB ViVOpay serial interface driver"
- help
- Say Y here if you want to use a ViVOtech ViVOpay USB device.
-
- To compile this driver as a module, choose M here: the
- module will be called vivopay-serial.
-
config USB_SERIAL_XSENS_MT
tristate "Xsens motion tracker serial interface driver"
help
@@ -659,14 +636,6 @@ config USB_SERIAL_XSENS_MT
To compile this driver as a module, choose M here: the
module will be called xsens_mt.
-config USB_SERIAL_ZIO
- tristate "ZIO Motherboard USB serial interface driver"
- help
- Say Y here if you want to use ZIO Motherboard.
-
- To compile this driver as a module, choose M here: the
- module will be called zio.
-
config USB_SERIAL_WISHBONE
tristate "USB-Wishbone adapter interface driver"
help
@@ -710,16 +679,6 @@ config USB_SERIAL_QT2
To compile this driver as a module, choose M here: the
module will be called quatech-serial.
-config USB_SERIAL_FLASHLOADER
- tristate "Infineon Modem Flashloader USB interface driver"
- help
- Say Y here if you want to download Infineon Modem
- via USB Flashloader serial driver.
-
- To compile this driver as a module, choose M here: the
- module will be called flashloader.
-
-
config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index f7130114488..42670f0b5bc 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -24,9 +24,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o
obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
obj-$(CONFIG_USB_SERIAL_F81232) += f81232.o
obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o
-obj-$(CONFIG_USB_SERIAL_FUNSOFT) += funsoft.o
obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o
-obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o
obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o
obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o
obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o
@@ -39,7 +37,6 @@ obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
obj-$(CONFIG_USB_SERIAL_METRO) += metro-usb.o
obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
-obj-$(CONFIG_USB_SERIAL_MOTOROLA) += moto_modem.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o
@@ -50,8 +47,8 @@ obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o
obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o
obj-$(CONFIG_USB_SERIAL_QT2) += quatech2.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
-obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o
obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
+obj-$(CONFIG_USB_SERIAL_SIMPLE) += usb-serial-simple.o
obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o
obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o
obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o
@@ -61,8 +58,5 @@ obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o
-obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o
obj-$(CONFIG_USB_SERIAL_XSENS_MT) += xsens_mt.o
-obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o
obj-$(CONFIG_USB_SERIAL_ZTE) += zte_ev.o
-obj-$(CONFIG_USB_SERIAL_FLASHLOADER) += flashloader.o
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index f053b302a00..6335490d576 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -38,15 +38,14 @@ static int usb_serial_device_match(struct device *dev,
return 0;
}
-static ssize_t show_port_number(struct device *dev,
+static ssize_t port_number_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
return sprintf(buf, "%d\n", port->port_number);
}
-
-static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+static DEVICE_ATTR_RO(port_number);
static int usb_serial_device_probe(struct device *dev)
{
@@ -122,7 +121,7 @@ static int usb_serial_device_remove(struct device *dev)
return retval;
}
-static ssize_t store_new_id(struct device_driver *driver,
+static ssize_t new_id_store(struct device_driver *driver,
const char *buf, size_t count)
{
struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
@@ -135,17 +134,19 @@ static ssize_t store_new_id(struct device_driver *driver,
return retval;
}
-static ssize_t show_dynids(struct device_driver *driver, char *buf)
+static ssize_t new_id_show(struct device_driver *driver, char *buf)
{
struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
return usb_show_dynids(&usb_drv->dynids, buf);
}
+static DRIVER_ATTR_RW(new_id);
-static struct driver_attribute drv_attrs[] = {
- __ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id),
- __ATTR_NULL,
+static struct attribute *usb_serial_drv_attrs[] = {
+ &driver_attr_new_id.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(usb_serial_drv);
static void free_dynids(struct usb_serial_driver *drv)
{
@@ -164,7 +165,7 @@ struct bus_type usb_serial_bus_type = {
.match = usb_serial_device_match,
.probe = usb_serial_device_probe,
.remove = usb_serial_device_remove,
- .drv_attrs = drv_attrs,
+ .drv_groups = usb_serial_drv_groups,
};
int usb_serial_bus_register(struct usb_serial_driver *driver)
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index afb50eab204..c69bb50d466 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -151,11 +151,7 @@ static int usb_console_setup(struct console *co, char *options)
/* only call the device specific open if this
* is the first time the port is opened */
- if (serial->type->open)
- retval = serial->type->open(NULL, port);
- else
- retval = usb_serial_generic_open(NULL, port);
-
+ retval = serial->type->open(NULL, port);
if (retval) {
dev_err(&port->dev, "could not open USB console port\n");
goto fail;
@@ -210,10 +206,10 @@ static void usb_console_write(struct console *co,
if (count == 0)
return;
- pr_debug("%s - minor %d, %d byte(s)\n", __func__, port->minor, count);
+ dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count);
if (!port->port.console) {
- pr_debug("%s - port not opened\n", __func__);
+ dev_dbg(&port->dev, "%s - port not opened\n", __func__);
return;
}
@@ -230,21 +226,14 @@ static void usb_console_write(struct console *co,
}
/* pass on to the driver specific version of this function if
it is available */
- if (serial->type->write)
- retval = serial->type->write(NULL, port, buf, i);
- else
- retval = usb_serial_generic_write(NULL, port, buf, i);
- pr_debug("%s - return value : %d\n", __func__, retval);
+ retval = serial->type->write(NULL, port, buf, i);
+ dev_dbg(&port->dev, "%s - write: %d\n", __func__, retval);
if (lf) {
/* append CR after LF */
unsigned char cr = 13;
- if (serial->type->write)
- retval = serial->type->write(NULL,
- port, &cr, 1);
- else
- retval = usb_serial_generic_write(NULL,
- port, &cr, 1);
- pr_debug("%s - return value : %d\n", __func__, retval);
+ retval = serial->type->write(NULL, port, &cr, 1);
+ dev_dbg(&port->dev, "%s - write cr: %d\n",
+ __func__, retval);
}
buf += i;
count -= i;
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index d6ef2f8da37..6987b535aa9 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -53,6 +53,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
{ USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
{ USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
+ { USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
@@ -118,6 +119,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
{ USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
{ USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
+ { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
+ { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
@@ -148,6 +151,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
+ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
{ USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
{ USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */
@@ -666,9 +670,6 @@ static void cp210x_set_termios(struct tty_struct *tty,
unsigned int bits;
unsigned int modem_ctl[4];
- if (!tty)
- return;
-
cflag = tty->termios.c_cflag;
old_cflag = old_termios->c_cflag;
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index e948dc02795..558605d646f 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -495,6 +495,8 @@ static int cypress_generic_port_probe(struct usb_serial_port *port)
}
usb_set_serial_port_data(port, priv);
+ port->port.drain_delay = 256;
+
return 0;
}
@@ -625,7 +627,7 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
__func__, result);
cypress_set_dead(port);
}
- port->port.drain_delay = 256;
+
return result;
} /* cypress_open */
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 75e85cbf9e8..639a18fb67e 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -207,7 +207,6 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
return result;
}
- port->port.drain_delay = 256;
return 0;
}
@@ -322,6 +321,8 @@ static int f81232_port_probe(struct usb_serial_port *port)
usb_set_serial_port_data(port, priv);
+ port->port.drain_delay = 256;
+
return 0;
}
diff --git a/drivers/usb/serial/flashloader.c b/drivers/usb/serial/flashloader.c
deleted file mode 100644
index e6f5c10e891..00000000000
--- a/drivers/usb/serial/flashloader.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Infineon Flashloader driver
- *
- * Copyright (C) 2013 Wei Shuai <cpuwolf@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x8087, 0x0716) },
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver flashloader_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "flashloader",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &flashloader_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 7260ec66034..c45f9c0a1b3 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -51,8 +51,6 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
-static __u16 vendor = FTDI_VID;
-static __u16 product;
struct ftdi_private {
enum ftdi_chip_type chip_type;
@@ -144,8 +142,8 @@ static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
/*
- * Device ID not listed? Test via module params product/vendor or
- * /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
+ * Device ID not listed? Test it using
+ * /sys/bus/usb-serial/drivers/ftdi_sio/new_id and send a patch or report.
*/
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
@@ -735,9 +733,34 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID),
.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29A_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29F_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S01_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29C_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_81B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_82B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5D_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K4Y_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5G_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S05_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_60_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_61_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_64_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_65_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92D_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_W5R_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_A5R_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_PW1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
@@ -881,7 +904,6 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
/* Crucible Devices */
{ USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
- { }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -905,9 +927,6 @@ static const char *ftdi_chip_name[] = {
#define FTDI_STATUS_B1_MASK (FTDI_RS_BI)
/* End TIOCMIWAIT */
-#define FTDI_IMPL_ASYNC_FLAGS = (ASYNC_SPD_HI | ASYNC_SPD_VHI \
- | ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP)
-
/* function prototypes for a FTDI serial converter */
static int ftdi_sio_probe(struct usb_serial *serial,
const struct usb_device_id *id);
@@ -974,10 +993,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
#define WDR_TIMEOUT 5000 /* default urb timeout */
#define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */
-/* High and low are for DTR, RTS etc etc */
-#define HIGH 1
-#define LOW 0
-
/*
* ***************************************************************************
* Utility functions
@@ -1546,8 +1561,8 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)
* ***************************************************************************
*/
-static ssize_t show_latency_timer(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t latency_timer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1557,11 +1572,10 @@ static ssize_t show_latency_timer(struct device *dev,
return sprintf(buf, "%i\n", priv->latency);
}
-
/* Write a new value of the latency timer, in units of milliseconds. */
-static ssize_t store_latency_timer(struct device *dev,
- struct device_attribute *attr, const char *valbuf,
- size_t count)
+static ssize_t latency_timer_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *valbuf, size_t count)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1574,6 +1588,7 @@ static ssize_t store_latency_timer(struct device *dev,
return -EIO;
return count;
}
+static DEVICE_ATTR_RW(latency_timer);
/* Write an event character directly to the FTDI register. The ASCII
value is in the low 8 bits, with the enable bit in the 9th bit. */
@@ -1601,9 +1616,6 @@ static ssize_t store_event_char(struct device *dev,
return count;
}
-
-static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer,
- store_latency_timer);
static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char);
static int create_sysfs_attrs(struct usb_serial_port *port)
@@ -1842,7 +1854,6 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- struct ktermios dummy;
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1858,10 +1869,8 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
This is same behaviour as serial.c/rs_open() - Kuba */
/* ftdi_set_termios will send usb control messages */
- if (tty) {
- memset(&dummy, 0, sizeof(dummy));
- ftdi_set_termios(tty, port, &dummy);
- }
+ if (tty)
+ ftdi_set_termios(tty, port, NULL);
return usb_serial_generic_open(tty, port);
}
@@ -2190,7 +2199,7 @@ no_data_parity_stop_changes:
dev_err(ddev, "%s urb failed to set baudrate\n", __func__);
mutex_unlock(&priv->cfg_lock);
/* Ensure RTS and DTR are raised when baudrate changed from 0 */
- if (!old_termios || (old_termios->c_cflag & CBAUD) == B0)
+ if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
}
@@ -2380,38 +2389,11 @@ static int ftdi_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD;
}
-static int __init ftdi_init(void)
-{
- if (vendor > 0 && product > 0) {
- /* Add user specified VID/PID to reserved element of table. */
- int i;
- for (i = 0; id_table_combined[i].idVendor; i++)
- ;
- id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- id_table_combined[i].idVendor = vendor;
- id_table_combined[i].idProduct = product;
- }
- return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined);
-}
-
-static void __exit ftdi_exit(void)
-{
- usb_serial_deregister_drivers(serial_drivers);
-}
-
-
-module_init(ftdi_init);
-module_exit(ftdi_exit);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
- __MODULE_STRING(FTDI_VID)")");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified product ID");
-
module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override");
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 6dd79253205..1b8af461b52 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -815,11 +815,35 @@
/*
* RT Systems programming cables for various ham radios
*/
-#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
-#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */
-#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */
-#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */
-
+#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
+#define RTSYSTEMS_USB_S03_PID 0x9001 /* RTS-03 USB to Serial Adapter */
+#define RTSYSTEMS_USB_59_PID 0x9e50 /* USB-59 USB to 8 pin plug */
+#define RTSYSTEMS_USB_57A_PID 0x9e51 /* USB-57A USB to 4pin 3.5mm plug */
+#define RTSYSTEMS_USB_57B_PID 0x9e52 /* USB-57B USB to extended 4pin 3.5mm plug */
+#define RTSYSTEMS_USB_29A_PID 0x9e53 /* USB-29A USB to 3.5mm stereo plug */
+#define RTSYSTEMS_USB_29B_PID 0x9e54 /* USB-29B USB to 6 pin mini din */
+#define RTSYSTEMS_USB_29F_PID 0x9e55 /* USB-29F USB to 6 pin modular plug */
+#define RTSYSTEMS_USB_62B_PID 0x9e56 /* USB-62B USB to 8 pin mini din plug*/
+#define RTSYSTEMS_USB_S01_PID 0x9e57 /* USB-RTS01 USB to 3.5 mm stereo plug*/
+#define RTSYSTEMS_USB_63_PID 0x9e58 /* USB-63 USB to 9 pin female*/
+#define RTSYSTEMS_USB_29C_PID 0x9e59 /* USB-29C USB to 4 pin modular plug*/
+#define RTSYSTEMS_USB_81B_PID 0x9e5A /* USB-81 USB to 8 pin mini din plug*/
+#define RTSYSTEMS_USB_82B_PID 0x9e5B /* USB-82 USB to 2.5 mm stereo plug*/
+#define RTSYSTEMS_USB_K5D_PID 0x9e5C /* USB-K5D USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_K4Y_PID 0x9e5D /* USB-K4Y USB to 2.5/3.5 mm plugs*/
+#define RTSYSTEMS_USB_K5G_PID 0x9e5E /* USB-K5G USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_S05_PID 0x9e5F /* USB-RTS05 USB to 2.5 mm stereo plug*/
+#define RTSYSTEMS_USB_60_PID 0x9e60 /* USB-60 USB to 6 pin din*/
+#define RTSYSTEMS_USB_61_PID 0x9e61 /* USB-61 USB to 6 pin mini din*/
+#define RTSYSTEMS_USB_62_PID 0x9e62 /* USB-62 USB to 8 pin mini din*/
+#define RTSYSTEMS_USB_63B_PID 0x9e63 /* USB-63 USB to 9 pin female*/
+#define RTSYSTEMS_USB_64_PID 0x9e64 /* USB-64 USB to 9 pin male*/
+#define RTSYSTEMS_USB_65_PID 0x9e65 /* USB-65 USB to 9 pin female null modem*/
+#define RTSYSTEMS_USB_92_PID 0x9e66 /* USB-92 USB to 12 pin plug*/
+#define RTSYSTEMS_USB_92D_PID 0x9e67 /* USB-92D USB to 12 pin plug data*/
+#define RTSYSTEMS_USB_W5R_PID 0x9e68 /* USB-W5R USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_A5R_PID 0x9e69 /* USB-A5R USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_PW1_PID 0x9e6A /* USB-PW1 USB to 8 pin modular plug*/
/*
* Physik Instrumente
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
deleted file mode 100644
index 9362f8fd238..00000000000
--- a/drivers/usb/serial/funsoft.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Funsoft Serial USB driver
- *
- * Copyright (C) 2006 Greg Kroah-Hartman <gregkh@suse.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/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x1404, 0xcddc) },
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver funsoft_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "funsoft",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &funsoft_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index ba45170c78e..1f31e6b4c25 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -460,12 +460,7 @@ static bool usb_serial_generic_msr_changed(struct tty_struct *tty,
/*
* Use tty-port initialised flag to detect all hangups including the
* one generated at USB-device disconnect.
- *
- * FIXME: Remove hupping check once tty_port_hangup calls shutdown
- * (which clears the initialised flag) before wake up.
*/
- if (test_bit(TTY_HUPPING, &tty->flags))
- return true;
if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
return true;
@@ -496,12 +491,8 @@ int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg)
ret = wait_event_interruptible(port->port.delta_msr_wait,
usb_serial_generic_msr_changed(tty, arg, &cnow));
- if (!ret) {
- if (test_bit(TTY_HUPPING, &tty->flags))
- ret = -EIO;
- if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
- ret = -EIO;
- }
+ if (!ret && !test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ ret = -EIO;
return ret;
}
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
deleted file mode 100644
index 2cba60d90c7..00000000000
--- a/drivers/usb/serial/hp4x.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * HP4x Calculators Serial USB driver
- *
- * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net)
- * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.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.
- *
- * See Documentation/usb/usb-serial.txt for more information on using this
- * driver
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_DESC "HP4x (48/49) Generic Serial driver"
-
-#define HP_VENDOR_ID 0x03f0
-#define HP49GP_PRODUCT_ID 0x0121
-
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver hp49gp_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "hp4X",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &hp49gp_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index dc2803b5eb0..c91481d74a1 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -56,9 +56,7 @@
#define MAX_NAME_LEN 64
-#define CHASE_TIMEOUT (5*HZ) /* 5 seconds */
#define OPEN_TIMEOUT (5*HZ) /* 5 seconds */
-#define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */
/* receive port state */
enum RXSTATE {
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 60054e72b75..b7187bf3246 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -64,8 +64,6 @@
#define EDGE_CLOSING_WAIT 4000 /* in .01 sec */
-#define EDGE_OUT_BUF_SIZE 1024
-
/* Product information read from the Edgeport */
struct product_info {
@@ -93,7 +91,6 @@ struct edgeport_port {
spinlock_t ep_lock;
int ep_read_urb_state;
int ep_write_urb_in_use;
- struct kfifo write_fifo;
};
struct edgeport_serial {
@@ -1732,22 +1729,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
return -ENODEV;
port_number = port->port_number;
- switch (port_number) {
- case 0:
- edge_port->uart_base = UMPMEM_BASE_UART1;
- edge_port->dma_address = UMPD_OEDB1_ADDRESS;
- break;
- case 1:
- edge_port->uart_base = UMPMEM_BASE_UART2;
- edge_port->dma_address = UMPD_OEDB2_ADDRESS;
- break;
- default:
- dev_err(&port->dev, "Unknown port number!!!\n");
- return -ENODEV;
- }
-
- dev_dbg(&port->dev, "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n",
- __func__, port_number, edge_port->uart_base, edge_port->dma_address);
dev = port->serial->dev;
@@ -1872,8 +1853,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
++edge_serial->num_ports_open;
- port->port.drain_delay = 1;
-
goto release_es_lock;
unlink_int_urb:
@@ -1905,7 +1884,7 @@ static void edge_close(struct usb_serial_port *port)
usb_kill_urb(port->write_urb);
edge_port->ep_write_urb_in_use = 0;
spin_lock_irqsave(&edge_port->ep_lock, flags);
- kfifo_reset_out(&edge_port->write_fifo);
+ kfifo_reset_out(&port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__);
@@ -1939,7 +1918,7 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
if (edge_port->close_pending == 1)
return -ENODEV;
- count = kfifo_in_locked(&edge_port->write_fifo, data, count,
+ count = kfifo_in_locked(&port->write_fifo, data, count,
&edge_port->ep_lock);
edge_send(port, tty);
@@ -1959,7 +1938,7 @@ static void edge_send(struct usb_serial_port *port, struct tty_struct *tty)
return;
}
- count = kfifo_out(&edge_port->write_fifo,
+ count = kfifo_out(&port->write_fifo,
port->write_urb->transfer_buffer,
port->bulk_out_size);
@@ -2007,7 +1986,7 @@ static int edge_write_room(struct tty_struct *tty)
return 0;
spin_lock_irqsave(&edge_port->ep_lock, flags);
- room = kfifo_avail(&edge_port->write_fifo);
+ room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
@@ -2024,7 +2003,7 @@ static int edge_chars_in_buffer(struct tty_struct *tty)
return 0;
spin_lock_irqsave(&edge_port->ep_lock, flags);
- chars = kfifo_len(&edge_port->write_fifo);
+ chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
@@ -2451,30 +2430,45 @@ static int edge_port_probe(struct usb_serial_port *port)
if (!edge_port)
return -ENOMEM;
- ret = kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE,
- GFP_KERNEL);
- if (ret) {
- kfree(edge_port);
- return -ENOMEM;
- }
-
spin_lock_init(&edge_port->ep_lock);
edge_port->port = port;
edge_port->edge_serial = usb_get_serial_data(port->serial);
edge_port->bUartMode = default_uart_mode;
+ switch (port->port_number) {
+ case 0:
+ edge_port->uart_base = UMPMEM_BASE_UART1;
+ edge_port->dma_address = UMPD_OEDB1_ADDRESS;
+ break;
+ case 1:
+ edge_port->uart_base = UMPMEM_BASE_UART2;
+ edge_port->dma_address = UMPD_OEDB2_ADDRESS;
+ break;
+ default:
+ dev_err(&port->dev, "unknown port number\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ dev_dbg(&port->dev,
+ "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n",
+ __func__, port->port_number, edge_port->uart_base,
+ edge_port->dma_address);
+
usb_set_serial_port_data(port, edge_port);
ret = edge_create_sysfs_attrs(port);
- if (ret) {
- kfifo_free(&edge_port->write_fifo);
- kfree(edge_port);
- return ret;
- }
+ if (ret)
+ goto err;
port->port.closing_wait = msecs_to_jiffies(closing_wait * 10);
+ port->port.drain_delay = 1;
return 0;
+err:
+ kfree(edge_port);
+
+ return ret;
}
static int edge_port_remove(struct usb_serial_port *port)
@@ -2483,7 +2477,6 @@ static int edge_port_remove(struct usb_serial_port *port)
edge_port = usb_get_serial_port_data(port);
edge_remove_sysfs_attrs(port);
- kfifo_free(&edge_port->write_fifo);
kfree(edge_port);
return 0;
@@ -2491,7 +2484,7 @@ static int edge_port_remove(struct usb_serial_port *port)
/* Sysfs Attributes */
-static ssize_t show_uart_mode(struct device *dev,
+static ssize_t uart_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -2500,7 +2493,7 @@ static ssize_t show_uart_mode(struct device *dev,
return sprintf(buf, "%d\n", edge_port->bUartMode);
}
-static ssize_t store_uart_mode(struct device *dev,
+static ssize_t uart_mode_store(struct device *dev,
struct device_attribute *attr, const char *valbuf, size_t count)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -2516,9 +2509,7 @@ static ssize_t store_uart_mode(struct device *dev,
return count;
}
-
-static DEVICE_ATTR(uart_mode, S_IWUSR | S_IRUGO, show_uart_mode,
- store_uart_mode);
+static DEVICE_ATTR_RW(uart_mode);
static int edge_create_sysfs_attrs(struct usb_serial_port *port)
{
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 790673e5faa..57c439a24b5 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -1130,7 +1130,7 @@ static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc)
* Sysfs Attributes
*/
-static ssize_t show_vcc_mode(struct device *dev,
+static ssize_t vcc_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -1139,7 +1139,7 @@ static ssize_t show_vcc_mode(struct device *dev,
return sprintf(buf, "%d\n", priv->vcc);
}
-static ssize_t store_vcc_mode(struct device *dev,
+static ssize_t vcc_mode_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -1163,9 +1163,7 @@ static ssize_t store_vcc_mode(struct device *dev,
fail_store_vcc_mode:
return count;
}
-
-static DEVICE_ATTR(vcc_mode, S_IRUSR | S_IWUSR, show_vcc_mode,
- store_vcc_mode);
+static DEVICE_ATTR_RW(vcc_mode);
static int iuu_create_sysfs_attrs(struct usb_serial_port *port)
{
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 5a979729f8e..d6960aebe24 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -50,23 +50,27 @@
#define INSTAT_BUFLEN 32
#define GLOCONT_BUFLEN 64
#define INDAT49W_BUFLEN 512
+#define IN_BUFLEN 64
+#define OUT_BUFLEN 64
+#define INACK_BUFLEN 1
+#define OUTCONT_BUFLEN 64
/* Per device and per port private data */
struct keyspan_serial_private {
const struct keyspan_device_details *device_details;
struct urb *instat_urb;
- char instat_buf[INSTAT_BUFLEN];
+ char *instat_buf;
/* added to support 49wg, where data from all 4 ports comes in
on 1 EP and high-speed supported */
struct urb *indat_urb;
- char indat_buf[INDAT49W_BUFLEN];
+ char *indat_buf;
/* XXX this one probably will need a lock */
struct urb *glocont_urb;
- char glocont_buf[GLOCONT_BUFLEN];
- char ctrl_buf[8]; /* for EP0 control message */
+ char *glocont_buf;
+ char *ctrl_buf; /* for EP0 control message */
};
struct keyspan_port_private {
@@ -81,18 +85,18 @@ struct keyspan_port_private {
/* Input endpoints and buffer for this port */
struct urb *in_urbs[2];
- char in_buffer[2][64];
+ char *in_buffer[2];
/* Output endpoints and buffer for this port */
struct urb *out_urbs[2];
- char out_buffer[2][64];
+ char *out_buffer[2];
/* Input ack endpoint */
struct urb *inack_urb;
- char inack_buffer[1];
+ char *inack_buffer;
/* Output control endpoint */
struct urb *outcont_urb;
- char outcont_buffer[64];
+ char *outcont_buffer;
/* Settings for the port */
int baud;
@@ -2303,7 +2307,7 @@ static int keyspan_startup(struct usb_serial *serial)
if (d_details == NULL) {
dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
__func__, le16_to_cpu(serial->dev->descriptor.idProduct));
- return 1;
+ return -ENODEV;
}
/* Setup private data for serial driver */
@@ -2313,6 +2317,22 @@ static int keyspan_startup(struct usb_serial *serial)
return -ENOMEM;
}
+ s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
+ if (!s_priv->instat_buf)
+ goto err_instat_buf;
+
+ s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
+ if (!s_priv->indat_buf)
+ goto err_indat_buf;
+
+ s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
+ if (!s_priv->glocont_buf)
+ goto err_glocont_buf;
+
+ s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!s_priv->ctrl_buf)
+ goto err_ctrl_buf;
+
s_priv->device_details = d_details;
usb_set_serial_data(serial, s_priv);
@@ -2330,6 +2350,17 @@ static int keyspan_startup(struct usb_serial *serial)
}
return 0;
+
+err_ctrl_buf:
+ kfree(s_priv->glocont_buf);
+err_glocont_buf:
+ kfree(s_priv->indat_buf);
+err_indat_buf:
+ kfree(s_priv->instat_buf);
+err_instat_buf:
+ kfree(s_priv);
+
+ return -ENOMEM;
}
static void keyspan_disconnect(struct usb_serial *serial)
@@ -2353,6 +2384,11 @@ static void keyspan_release(struct usb_serial *serial)
usb_free_urb(s_priv->indat_urb);
usb_free_urb(s_priv->glocont_urb);
+ kfree(s_priv->ctrl_buf);
+ kfree(s_priv->glocont_buf);
+ kfree(s_priv->indat_buf);
+ kfree(s_priv->instat_buf);
+
kfree(s_priv);
}
@@ -2374,6 +2410,26 @@ static int keyspan_port_probe(struct usb_serial_port *port)
if (!p_priv)
return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
+ p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
+ if (!p_priv->in_buffer[i])
+ goto err_in_buffer;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
+ p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
+ if (!p_priv->out_buffer[i])
+ goto err_out_buffer;
+ }
+
+ p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
+ if (!p_priv->inack_buffer)
+ goto err_inack_buffer;
+
+ p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
+ if (!p_priv->outcont_buffer)
+ goto err_outcont_buffer;
+
p_priv->device_details = d_details;
/* Setup values for the various callback routines */
@@ -2386,7 +2442,8 @@ static int keyspan_port_probe(struct usb_serial_port *port)
for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
USB_DIR_IN, port,
- p_priv->in_buffer[i], 64,
+ p_priv->in_buffer[i],
+ IN_BUFLEN,
cback->indat_callback);
}
/* outdat endpoints also have flip */
@@ -2394,25 +2451,41 @@ static int keyspan_port_probe(struct usb_serial_port *port)
for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
USB_DIR_OUT, port,
- p_priv->out_buffer[i], 64,
+ p_priv->out_buffer[i],
+ OUT_BUFLEN,
cback->outdat_callback);
}
/* inack endpoint */
p_priv->inack_urb = keyspan_setup_urb(serial,
d_details->inack_endpoints[port_num],
USB_DIR_IN, port,
- p_priv->inack_buffer, 1,
+ p_priv->inack_buffer,
+ INACK_BUFLEN,
cback->inack_callback);
/* outcont endpoint */
p_priv->outcont_urb = keyspan_setup_urb(serial,
d_details->outcont_endpoints[port_num],
USB_DIR_OUT, port,
- p_priv->outcont_buffer, 64,
+ p_priv->outcont_buffer,
+ OUTCONT_BUFLEN,
cback->outcont_callback);
usb_set_serial_port_data(port, p_priv);
return 0;
+
+err_outcont_buffer:
+ kfree(p_priv->inack_buffer);
+err_inack_buffer:
+ for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
+ kfree(p_priv->out_buffer[i]);
+err_out_buffer:
+ for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
+ kfree(p_priv->in_buffer[i]);
+err_in_buffer:
+ kfree(p_priv);
+
+ return -ENOMEM;
}
static int keyspan_port_remove(struct usb_serial_port *port)
@@ -2436,6 +2509,13 @@ static int keyspan_port_remove(struct usb_serial_port *port)
usb_free_urb(p_priv->out_urbs[i]);
}
+ kfree(p_priv->outcont_buffer);
+ kfree(p_priv->inack_buffer);
+ for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
+ kfree(p_priv->out_buffer[i]);
+ for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
+ kfree(p_priv->in_buffer[i]);
+
kfree(p_priv);
return 0;
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 51da424327b..84657e07dc5 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -90,6 +90,7 @@ struct urbtracker {
struct list_head urblist_entry;
struct kref ref_count;
struct urb *urb;
+ struct usb_ctrlrequest *setup;
};
enum mos7715_pp_modes {
@@ -271,6 +272,7 @@ static void destroy_urbtracker(struct kref *kref)
struct mos7715_parport *mos_parport = urbtrack->mos_parport;
usb_free_urb(urbtrack->urb);
+ kfree(urbtrack->setup);
kfree(urbtrack);
kref_put(&mos_parport->ref_count, destroy_mos_parport);
}
@@ -355,7 +357,6 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
struct urbtracker *urbtrack;
int ret_val;
unsigned long flags;
- struct usb_ctrlrequest setup;
struct usb_serial *serial = mos_parport->serial;
struct usb_device *usbdev = serial->dev;
@@ -373,14 +374,20 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
kfree(urbtrack);
return -ENOMEM;
}
- setup.bRequestType = (__u8)0x40;
- setup.bRequest = (__u8)0x0e;
- setup.wValue = get_reg_value(reg, dummy);
- setup.wIndex = get_reg_index(reg);
- setup.wLength = 0;
+ urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_ATOMIC);
+ if (!urbtrack->setup) {
+ usb_free_urb(urbtrack->urb);
+ kfree(urbtrack);
+ return -ENOMEM;
+ }
+ urbtrack->setup->bRequestType = (__u8)0x40;
+ urbtrack->setup->bRequest = (__u8)0x0e;
+ urbtrack->setup->wValue = cpu_to_le16(get_reg_value(reg, dummy));
+ urbtrack->setup->wIndex = cpu_to_le16(get_reg_index(reg));
+ urbtrack->setup->wLength = 0;
usb_fill_control_urb(urbtrack->urb, usbdev,
usb_sndctrlpipe(usbdev, 0),
- (unsigned char *)&setup,
+ (unsigned char *)urbtrack->setup,
NULL, 0, async_complete, urbtrack);
kref_init(&urbtrack->ref_count);
INIT_LIST_HEAD(&urbtrack->urblist_entry);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 0a818b23850..fdf953539c6 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -183,7 +183,10 @@
#define LED_ON_MS 500
#define LED_OFF_MS 500
-static int device_type;
+enum mos7840_flag {
+ MOS7840_FLAG_CTRL_BUSY,
+ MOS7840_FLAG_LED_BUSY,
+};
static const struct usb_device_id id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
@@ -218,7 +221,6 @@ struct moschip_port {
__u8 shadowMCR; /* last MCR value received */
char open;
char open_ports;
- wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
struct usb_serial_port *port; /* loop back to the owner of this object */
/* Offsets */
@@ -238,9 +240,12 @@ struct moschip_port {
/* For device(s) with LED indicator */
bool has_led;
- bool led_flag;
struct timer_list led_timer1; /* Timer for LED on */
struct timer_list led_timer2; /* Timer for LED off */
+ struct urb *led_urb;
+ struct usb_ctrlrequest *led_dr;
+
+ unsigned long flags;
};
/*
@@ -460,10 +465,10 @@ static void mos7840_control_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
- return;
+ goto out;
default:
dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
- return;
+ goto out;
}
dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length);
@@ -476,6 +481,8 @@ static void mos7840_control_callback(struct urb *urb)
mos7840_handle_new_msr(mos7840_port, regval);
else if (mos7840_port->MsrLsr == 1)
mos7840_handle_new_lsr(mos7840_port, regval);
+out:
+ clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags);
}
static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
@@ -486,6 +493,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
unsigned char *buffer = mcs->ctrl_buf;
int ret;
+ if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags))
+ return -EBUSY;
+
dr->bRequestType = MCS_RD_RTYPE;
dr->bRequest = MCS_RDREQ;
dr->wValue = cpu_to_le16(Wval); /* 0 */
@@ -497,6 +507,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
mos7840_control_callback, mcs);
mcs->control_urb->transfer_buffer_length = 2;
ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+ if (ret)
+ clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags);
+
return ret;
}
@@ -523,7 +536,7 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
__u16 reg)
{
struct usb_device *dev = mcs->port->serial->dev;
- struct usb_ctrlrequest *dr = mcs->dr;
+ struct usb_ctrlrequest *dr = mcs->led_dr;
dr->bRequestType = MCS_WR_RTYPE;
dr->bRequest = MCS_WRREQ;
@@ -531,10 +544,10 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
dr->wIndex = cpu_to_le16(reg);
dr->wLength = cpu_to_le16(0);
- usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
+ usb_fill_control_urb(mcs->led_urb, dev, usb_sndctrlpipe(dev, 0),
(unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
- usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+ usb_submit_urb(mcs->led_urb, GFP_ATOMIC);
}
static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
@@ -560,7 +573,19 @@ static void mos7840_led_flag_off(unsigned long arg)
{
struct moschip_port *mcs = (struct moschip_port *) arg;
- mcs->led_flag = false;
+ clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags);
+}
+
+static void mos7840_led_activity(struct usb_serial_port *port)
+{
+ struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
+
+ if (test_and_set_bit_lock(MOS7840_FLAG_LED_BUSY, &mos7840_port->flags))
+ return;
+
+ mos7840_set_led_async(mos7840_port, 0x0301, MODEM_CONTROL_REGISTER);
+ mod_timer(&mos7840_port->led_timer1,
+ jiffies + msecs_to_jiffies(LED_ON_MS));
}
/*****************************************************************************
@@ -758,14 +783,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
return;
}
- /* Turn on LED */
- if (mos7840_port->has_led && !mos7840_port->led_flag) {
- mos7840_port->led_flag = true;
- mos7840_set_led_async(mos7840_port, 0x0301,
- MODEM_CONTROL_REGISTER);
- mod_timer(&mos7840_port->led_timer1,
- jiffies + msecs_to_jiffies(LED_ON_MS));
- }
+ if (mos7840_port->has_led)
+ mos7840_led_activity(port);
mos7840_port->read_urb_busy = true;
retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
@@ -816,18 +835,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
/************************************************************************/
/* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */
/************************************************************************/
-#ifdef MCSSerialProbe
-static int mos7840_serial_probe(struct usb_serial *serial,
- const struct usb_device_id *id)
-{
-
- /*need to implement the mode_reg reading and updating\
- structures usb_serial_ device_type\
- (i.e num_ports, num_bulkin,bulkout etc) */
- /* Also we can update the changes attach */
- return 1;
-}
-#endif
/*****************************************************************************
* mos7840_open
@@ -905,20 +912,20 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
if (status < 0) {
dev_dbg(&port->dev, "Reading Spreg failed\n");
- return -1;
+ goto err;
}
Data |= 0x80;
status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
if (status < 0) {
dev_dbg(&port->dev, "writing Spreg failed\n");
- return -1;
+ goto err;
}
Data &= ~0x80;
status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
if (status < 0) {
dev_dbg(&port->dev, "writing Spreg failed\n");
- return -1;
+ goto err;
}
/* End of block to be checked */
@@ -927,7 +934,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
&Data);
if (status < 0) {
dev_dbg(&port->dev, "Reading Controlreg failed\n");
- return -1;
+ goto err;
}
Data |= 0x08; /* Driver done bit */
Data |= 0x20; /* rx_disable */
@@ -935,7 +942,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
mos7840_port->ControlRegOffset, Data);
if (status < 0) {
dev_dbg(&port->dev, "writing Controlreg failed\n");
- return -1;
+ goto err;
}
/* do register settings here */
/* Set all regs to the device default values. */
@@ -946,21 +953,21 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
if (status < 0) {
dev_dbg(&port->dev, "disabling interrupts failed\n");
- return -1;
+ goto err;
}
/* Set FIFO_CONTROL_REGISTER to the default value */
Data = 0x00;
status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
if (status < 0) {
dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER failed\n");
- return -1;
+ goto err;
}
Data = 0xcf;
status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
if (status < 0) {
dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER failed\n");
- return -1;
+ goto err;
}
Data = 0x03;
@@ -1092,9 +1099,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
mos7840_port->read_urb_busy = false;
}
- /* initialize our wait queues */
- init_waitqueue_head(&mos7840_port->wait_chase);
-
/* initialize our port settings */
/* Must set to enable ints! */
mos7840_port->shadowMCR = MCR_MASTER_IE;
@@ -1103,6 +1107,15 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
/* mos7840_change_port_settings(mos7840_port,old_termios); */
return 0;
+err:
+ for (j = 0; j < NUM_URBS; ++j) {
+ urb = mos7840_port->write_urb_pool[j];
+ if (!urb)
+ continue;
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ }
+ return status;
}
/*****************************************************************************
@@ -1211,47 +1224,6 @@ static void mos7840_close(struct usb_serial_port *port)
mos7840_port->open = 0;
}
-/************************************************************************
- *
- * mos7840_block_until_chase_response
- *
- * This function will block the close until one of the following:
- * 1. Response to our Chase comes from mos7840
- * 2. A timeout of 10 seconds without activity has expired
- * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
- *
- ************************************************************************/
-
-static void mos7840_block_until_chase_response(struct tty_struct *tty,
- struct moschip_port *mos7840_port)
-{
- int timeout = msecs_to_jiffies(1000);
- int wait = 10;
- int count;
-
- while (1) {
- count = mos7840_chars_in_buffer(tty);
-
- /* Check for Buffer status */
- if (count <= 0)
- return;
-
- /* Block the thread for a while */
- interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
- timeout);
- /* No activity.. count down section */
- wait--;
- if (wait == 0) {
- dev_dbg(&mos7840_port->port->dev, "%s - TIMEOUT\n", __func__);
- return;
- } else {
- /* Reset timeout value back to seconds */
- wait = 10;
- }
- }
-
-}
-
/*****************************************************************************
* mos7840_break
* this function sends a break to the port
@@ -1275,9 +1247,6 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
if (mos7840_port == NULL)
return;
- /* flush and block until tx is empty */
- mos7840_block_until_chase_response(tty, mos7840_port);
-
if (break_state == -1)
data = mos7840_port->shadowLCR | LCR_SET_BREAK;
else
@@ -1445,13 +1414,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
data1 = urb->transfer_buffer;
dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress);
- /* Turn on LED */
- if (mos7840_port->has_led && !mos7840_port->led_flag) {
- mos7840_port->led_flag = true;
- mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
- mod_timer(&mos7840_port->led_timer1,
- jiffies + msecs_to_jiffies(LED_ON_MS));
- }
+ if (mos7840_port->has_led)
+ mos7840_led_activity(port);
/* send it down the pipe */
status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -2178,38 +2142,48 @@ static int mos7810_check(struct usb_serial *serial)
return 0;
}
-static int mos7840_calc_num_ports(struct usb_serial *serial)
+static int mos7840_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
{
- __u16 data = 0x00;
+ u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
u8 *buf;
- int mos7840_num_ports;
+ int device_type;
+
+ if (product == MOSCHIP_DEVICE_ID_7810 ||
+ product == MOSCHIP_DEVICE_ID_7820) {
+ device_type = product;
+ goto out;
+ }
buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
- if (buf) {
- usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ if (!buf)
+ return -ENOMEM;
+
+ usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
- data = *buf;
- kfree(buf);
- }
- if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
- serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
- device_type = serial->dev->descriptor.idProduct;
- } else {
- /* For a MCS7840 device GPIO0 must be set to 1 */
- if ((data & 0x01) == 1)
- device_type = MOSCHIP_DEVICE_ID_7840;
- else if (mos7810_check(serial))
- device_type = MOSCHIP_DEVICE_ID_7810;
- else
- device_type = MOSCHIP_DEVICE_ID_7820;
- }
+ /* For a MCS7840 device GPIO0 must be set to 1 */
+ if (buf[0] & 0x01)
+ device_type = MOSCHIP_DEVICE_ID_7840;
+ else if (mos7810_check(serial))
+ device_type = MOSCHIP_DEVICE_ID_7810;
+ else
+ device_type = MOSCHIP_DEVICE_ID_7820;
+
+ kfree(buf);
+out:
+ usb_set_serial_data(serial, (void *)(unsigned long)device_type);
+
+ return 0;
+}
+
+static int mos7840_calc_num_ports(struct usb_serial *serial)
+{
+ int device_type = (unsigned long)usb_get_serial_data(serial);
+ int mos7840_num_ports;
mos7840_num_ports = (device_type >> 4) & 0x000F;
- serial->num_bulk_in = mos7840_num_ports;
- serial->num_bulk_out = mos7840_num_ports;
- serial->num_ports = mos7840_num_ports;
return mos7840_num_ports;
}
@@ -2217,6 +2191,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
static int mos7840_port_probe(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
+ int device_type = (unsigned long)usb_get_serial_data(serial);
struct moschip_port *mos7840_port;
int status;
int pnum;
@@ -2392,6 +2367,14 @@ static int mos7840_port_probe(struct usb_serial_port *port)
if (device_type == MOSCHIP_DEVICE_ID_7810) {
mos7840_port->has_led = true;
+ mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL);
+ mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr),
+ GFP_KERNEL);
+ if (!mos7840_port->led_urb || !mos7840_port->led_dr) {
+ status = -ENOMEM;
+ goto error;
+ }
+
init_timer(&mos7840_port->led_timer1);
mos7840_port->led_timer1.function = mos7840_led_off;
mos7840_port->led_timer1.expires =
@@ -2404,8 +2387,6 @@ static int mos7840_port_probe(struct usb_serial_port *port)
jiffies + msecs_to_jiffies(LED_OFF_MS);
mos7840_port->led_timer2.data = (unsigned long)mos7840_port;
- mos7840_port->led_flag = false;
-
/* Turn off LED */
mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
}
@@ -2427,6 +2408,8 @@ out:
}
return 0;
error:
+ kfree(mos7840_port->led_dr);
+ usb_free_urb(mos7840_port->led_urb);
kfree(mos7840_port->dr);
kfree(mos7840_port->ctrl_buf);
usb_free_urb(mos7840_port->control_urb);
@@ -2447,6 +2430,10 @@ static int mos7840_port_remove(struct usb_serial_port *port)
del_timer_sync(&mos7840_port->led_timer1);
del_timer_sync(&mos7840_port->led_timer2);
+
+ usb_kill_urb(mos7840_port->led_urb);
+ usb_free_urb(mos7840_port->led_urb);
+ kfree(mos7840_port->led_dr);
}
usb_kill_urb(mos7840_port->control_urb);
usb_free_urb(mos7840_port->control_urb);
@@ -2473,9 +2460,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
.throttle = mos7840_throttle,
.unthrottle = mos7840_unthrottle,
.calc_num_ports = mos7840_calc_num_ports,
-#ifdef MCSSerialProbe
- .probe = mos7840_serial_probe,
-#endif
+ .probe = mos7840_probe,
.ioctl = mos7840_ioctl,
.set_termios = mos7840_set_termios,
.break_ctl = mos7840_break,
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
deleted file mode 100644
index c5ff6c7795a..00000000000
--- a/drivers/usb/serial/moto_modem.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Motorola USB Phone driver
- *
- * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.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.
- *
- * {sigh}
- * Motorola should be using the CDC ACM USB spec, but instead
- * they try to just "do their own thing"... This driver should handle a
- * few phones in which a basic "dumb serial connection" is needed to be
- * able to get a connection through to them.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */
- { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */
- { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */
- { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */
- { USB_DEVICE(0x22b8, 0x2c64) }, /* Motorola V950 phone */
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver moto_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "moto-modem",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &moto_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 5dd857de05b..1cf6f125f5f 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -341,17 +341,12 @@ static void option_instat_callback(struct urb *urb);
#define OLIVETTI_VENDOR_ID 0x0b3c
#define OLIVETTI_PRODUCT_OLICARD100 0xc000
#define OLIVETTI_PRODUCT_OLICARD145 0xc003
+#define OLIVETTI_PRODUCT_OLICARD200 0xc005
/* Celot products */
#define CELOT_VENDOR_ID 0x211f
#define CELOT_PRODUCT_CT680M 0x6801
-/* ONDA Communication vendor id */
-#define ONDA_VENDOR_ID 0x1ee8
-
-/* ONDA MT825UP HSDPA 14.2 modem */
-#define ONDA_MT825UP 0x000b
-
/* Samsung products */
#define SAMSUNG_VENDOR_ID 0x04e8
#define SAMSUNG_PRODUCT_GT_B3730 0x6889
@@ -444,7 +439,8 @@ static void option_instat_callback(struct urb *urb);
/* Hyundai Petatel Inc. products */
#define PETATEL_VENDOR_ID 0x1ff4
-#define PETATEL_PRODUCT_NP10T 0x600e
+#define PETATEL_PRODUCT_NP10T_600A 0x600a
+#define PETATEL_PRODUCT_NP10T_600E 0x600e
/* TP-LINK Incorporated products */
#define TPLINK_VENDOR_ID 0x2357
@@ -782,6 +778,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) },
@@ -817,7 +814,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
@@ -1256,8 +1254,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200) },
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
- { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM610) },
@@ -1329,9 +1327,12 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x02, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) },
{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
- { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) },
+ { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600A) },
+ { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600E) },
{ USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(TPLINK_VENDOR_ID, 0x9000), /* TP-Link MA260 */
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) }, /* D-Link DWM-156 (variant) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) }, /* D-Link DWM-156 (variant) */
@@ -1339,6 +1340,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 7e3e0782e51..a2080ac7b7e 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -343,6 +343,8 @@ static int oti6858_port_probe(struct usb_serial_port *port)
usb_set_serial_port_data(port, priv);
+ port->port.drain_delay = 256; /* FIXME: check the FIFO length */
+
return 0;
}
@@ -411,9 +413,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
__le16 divisor;
int br;
- if (!tty)
- return;
-
cflag = tty->termios.c_cflag;
spin_lock_irqsave(&priv->lock, flags);
@@ -509,7 +508,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct oti6858_private *priv = usb_get_serial_port_data(port);
- struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct oti6858_control_pkt *buf;
unsigned long flags;
@@ -560,8 +558,8 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
/* setup termios */
if (tty)
- oti6858_set_termios(tty, port, &tmp_termios);
- port->port.drain_delay = 256; /* FIXME: check the FIFO length */
+ oti6858_set_termios(tty, port, NULL);
+
return 0;
}
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index cb6bbed374f..e7a84f0f517 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -4,6 +4,11 @@
* Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2003 IBM Corp.
*
+ * Copyright (C) 2009, 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
+ * - fixes, improvements and documentation for the baud rate encoding methods
+ * Copyright (C) 2013 Reinhard Max <max@suse.de>
+ * - fixes and improvements for the divisor based baud rate encoding method
+ *
* Original driver for 2.2.x by anonymous
*
* This program is free software; you can redistribute it and/or
@@ -29,6 +34,7 @@
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#include <asm/unaligned.h>
#include "pl2303.h"
/*
@@ -128,10 +134,17 @@ MODULE_DEVICE_TABLE(usb, id_table);
enum pl2303_type {
- type_0, /* don't know the difference between type 0 and */
- type_1, /* type 1, until someone from prolific tells us... */
- HX, /* HX version of the pl2303 chip */
+ type_0, /* H version ? */
+ type_1, /* H version ? */
+ HX_TA, /* HX(A) / X(A) / TA version */ /* TODO: improve */
+ HXD_EA_RA_SA, /* HXD / EA / RA / SA version */ /* TODO: improve */
+ TB, /* TB version */
};
+/*
+ * NOTE: don't know the difference between type 0 and type 1,
+ * until someone from Prolific tells us...
+ * TODO: distinguish between X/HX, TA and HXD, EA, RA, SA variants
+ */
struct pl2303_serial_private {
enum pl2303_type type;
@@ -171,6 +184,7 @@ static int pl2303_startup(struct usb_serial *serial)
{
struct pl2303_serial_private *spriv;
enum pl2303_type type = type_0;
+ char *type_str = "unknown (treating as type_0)";
unsigned char *buf;
spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
@@ -183,15 +197,38 @@ static int pl2303_startup(struct usb_serial *serial)
return -ENOMEM;
}
- if (serial->dev->descriptor.bDeviceClass == 0x02)
+ if (serial->dev->descriptor.bDeviceClass == 0x02) {
type = type_0;
- else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
- type = HX;
- else if (serial->dev->descriptor.bDeviceClass == 0x00)
- type = type_1;
- else if (serial->dev->descriptor.bDeviceClass == 0xFF)
+ type_str = "type_0";
+ } else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) {
+ /*
+ * NOTE: The bcdDevice version is the only difference between
+ * the device descriptors of the X/HX, HXD, EA, RA, SA, TA, TB
+ */
+ if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x300) {
+ type = HX_TA;
+ type_str = "X/HX/TA";
+ } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice)
+ == 0x400) {
+ type = HXD_EA_RA_SA;
+ type_str = "HXD/EA/RA/SA";
+ } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice)
+ == 0x500) {
+ type = TB;
+ type_str = "TB";
+ } else {
+ dev_info(&serial->interface->dev,
+ "unknown/unsupported device type\n");
+ kfree(spriv);
+ kfree(buf);
+ return -ENODEV;
+ }
+ } else if (serial->dev->descriptor.bDeviceClass == 0x00
+ || serial->dev->descriptor.bDeviceClass == 0xFF) {
type = type_1;
- dev_dbg(&serial->interface->dev, "device type: %d\n", type);
+ type_str = "type_1";
+ }
+ dev_dbg(&serial->interface->dev, "device type: %s\n", type_str);
spriv->type = type;
usb_set_serial_data(serial, spriv);
@@ -206,10 +243,10 @@ static int pl2303_startup(struct usb_serial *serial)
pl2303_vendor_read(0x8383, 0, serial, buf);
pl2303_vendor_write(0, 1, serial);
pl2303_vendor_write(1, 0, serial);
- if (type == HX)
- pl2303_vendor_write(2, 0x44, serial);
- else
+ if (type == type_0 || type == type_1)
pl2303_vendor_write(2, 0x24, serial);
+ else
+ pl2303_vendor_write(2, 0x44, serial);
kfree(buf);
return 0;
@@ -235,6 +272,8 @@ static int pl2303_port_probe(struct usb_serial_port *port)
usb_set_serial_port_data(port, priv);
+ port->port.drain_delay = 256;
+
return 0;
}
@@ -261,6 +300,175 @@ static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
return retval;
}
+static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
+ u8 buf[4])
+{
+ /*
+ * NOTE: Only the values defined in baud_sup are supported !
+ * => if unsupported values are set, the PL2303 seems to
+ * use 9600 baud (at least my PL2303X always does)
+ */
+ const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
+ 4800, 7200, 9600, 14400, 19200, 28800, 38400,
+ 57600, 115200, 230400, 460800, 614400, 921600,
+ 1228800, 2457600, 3000000, 6000000, 12000000 };
+ /*
+ * NOTE: With the exception of type_0/1 devices, the following
+ * additional baud rates are supported (tested with HX rev. 3A only):
+ * 110*, 56000*, 128000, 134400, 161280, 201600, 256000*, 268800,
+ * 403200, 806400. (*: not HX)
+ *
+ * Maximum values: HXD, TB: 12000000; HX, TA: 6000000;
+ * type_0+1: 1228800; RA: 921600; SA: 115200
+ *
+ * As long as we are not using this encoding method for anything else
+ * than the type_0+1 and HX chips, there is no point in complicating
+ * the code to support them.
+ */
+ int i;
+
+ /* Set baudrate to nearest supported value */
+ for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
+ if (baud_sup[i] > baud)
+ break;
+ }
+ if (i == ARRAY_SIZE(baud_sup))
+ baud = baud_sup[i - 1];
+ else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
+ baud = baud_sup[i - 1];
+ else
+ baud = baud_sup[i];
+ /* Respect the chip type specific baud rate limits */
+ /*
+ * FIXME: as long as we don't know how to distinguish between the
+ * HXD, EA, RA, and SA chip variants, allow the max. value of 12M.
+ */
+ if (type == HX_TA)
+ baud = min_t(int, baud, 6000000);
+ else if (type == type_0 || type == type_1)
+ baud = min_t(int, baud, 1228800);
+ /* Direct (standard) baud rate encoding method */
+ put_unaligned_le32(baud, buf);
+
+ return baud;
+}
+
+static int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type,
+ u8 buf[4])
+{
+ /*
+ * Divisor based baud rate encoding method
+ *
+ * NOTE: it's not clear if the type_0/1 chips support this method
+ *
+ * divisor = 12MHz * 32 / baudrate = 2^A * B
+ *
+ * with
+ *
+ * A = buf[1] & 0x0e
+ * B = buf[0] + (buf[1] & 0x01) << 8
+ *
+ * Special cases:
+ * => 8 < B < 16: device seems to work not properly
+ * => B <= 8: device uses the max. value B = 512 instead
+ */
+ unsigned int A, B;
+
+ /*
+ * NOTE: The Windows driver allows maximum baud rates of 110% of the
+ * specified maximium value.
+ * Quick tests with early (2004) HX (rev. A) chips suggest, that even
+ * higher baud rates (up to the maximum of 24M baud !) are working fine,
+ * but that should really be tested carefully in "real life" scenarios
+ * before removing the upper limit completely.
+ * Baud rates smaller than the specified 75 baud are definitely working
+ * fine.
+ */
+ if (type == type_0 || type == type_1)
+ baud = min_t(int, baud, 1228800 * 1.1);
+ else if (type == HX_TA)
+ baud = min_t(int, baud, 6000000 * 1.1);
+ else if (type == HXD_EA_RA_SA)
+ /* HXD, EA: 12Mbps; RA: 1Mbps; SA: 115200 bps */
+ /*
+ * FIXME: as long as we don't know how to distinguish between
+ * these chip variants, allow the max. of these values
+ */
+ baud = min_t(int, baud, 12000000 * 1.1);
+ else if (type == TB)
+ baud = min_t(int, baud, 12000000 * 1.1);
+ /* Determine factors A and B */
+ A = 0;
+ B = 12000000 * 32 / baud; /* 12MHz */
+ B <<= 1; /* Add one bit for rounding */
+ while (B > (512 << 1) && A <= 14) {
+ A += 2;
+ B >>= 2;
+ }
+ if (A > 14) { /* max. divisor = min. baudrate reached */
+ A = 14;
+ B = 512;
+ /* => ~45.78 baud */
+ } else {
+ B = (B + 1) >> 1; /* Round the last bit */
+ }
+ /* Handle special cases */
+ if (B == 512)
+ B = 0; /* also: 1 to 8 */
+ else if (B < 16)
+ /*
+ * NOTE: With the current algorithm this happens
+ * only for A=0 and means that the min. divisor
+ * (respectively: the max. baudrate) is reached.
+ */
+ B = 16; /* => 24 MBaud */
+ /* Encode the baud rate */
+ buf[3] = 0x80; /* Select divisor encoding method */
+ buf[2] = 0;
+ buf[1] = (A & 0x0e); /* A */
+ buf[1] |= ((B & 0x100) >> 8); /* MSB of B */
+ buf[0] = B & 0xff; /* 8 LSBs of B */
+ /* Calculate the actual/resulting baud rate */
+ if (B <= 8)
+ B = 512;
+ baud = 12000000 * 32 / ((1 << A) * B);
+
+ return baud;
+}
+
+static void pl2303_encode_baudrate(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ enum pl2303_type type,
+ u8 buf[4])
+{
+ int baud;
+
+ baud = tty_get_baud_rate(tty);
+ dev_dbg(&port->dev, "baud requested = %d\n", baud);
+ if (!baud)
+ return;
+ /*
+ * There are two methods for setting/encoding the baud rate
+ * 1) Direct method: encodes the baud rate value directly
+ * => supported by all chip types
+ * 2) Divisor based method: encodes a divisor to a base value (12MHz*32)
+ * => supported by HX chips (and likely not by type_0/1 chips)
+ *
+ * NOTE: Although the divisor based baud rate encoding method is much
+ * more flexible, some of the standard baud rate values can not be
+ * realized exactly. But the difference is very small (max. 0.2%) and
+ * the device likely uses the same baud rate generator for both methods
+ * so that there is likley no difference.
+ */
+ if (type == type_0 || type == type_1)
+ baud = pl2303_baudrate_encode_direct(baud, type, buf);
+ else
+ baud = pl2303_baudrate_encode_divisor(baud, type, buf);
+ /* Save resulting baud rate */
+ tty_encode_baud_rate(tty, baud, baud);
+ dev_dbg(&port->dev, "baud set = %d\n", baud);
+}
+
static void pl2303_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -268,27 +476,18 @@ static void pl2303_set_termios(struct tty_struct *tty,
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- unsigned int cflag;
unsigned char *buf;
- int baud;
int i;
u8 control;
- const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
- 4800, 7200, 9600, 14400, 19200, 28800, 38400,
- 57600, 115200, 230400, 460800, 500000, 614400,
- 921600, 1228800, 2457600, 3000000, 6000000 };
- int baud_floor, baud_ceil;
- int k;
-
- /* The PL2303 is reported to lose bytes if you change
- serial settings even to the same values as before. Thus
- we actually need to filter in this specific case */
+ /*
+ * The PL2303 is reported to lose bytes if you change serial settings
+ * even to the same values as before. Thus we actually need to filter
+ * in this specific case.
+ */
if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
return;
- cflag = tty->termios.c_cflag;
-
buf = kzalloc(7, GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __func__);
@@ -303,8 +502,8 @@ static void pl2303_set_termios(struct tty_struct *tty,
0, 0, buf, 7, 100);
dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf);
- if (cflag & CSIZE) {
- switch (cflag & CSIZE) {
+ if (C_CSIZE(tty)) {
+ switch (C_CSIZE(tty)) {
case CS5:
buf[6] = 5;
break;
@@ -317,73 +516,22 @@ static void pl2303_set_termios(struct tty_struct *tty,
default:
case CS8:
buf[6] = 8;
- break;
}
dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
}
- /* For reference buf[0]:buf[3] baud rate value */
- /* NOTE: Only the values defined in baud_sup are supported !
- * => if unsupported values are set, the PL2303 seems to use
- * 9600 baud (at least my PL2303X always does)
- */
- baud = tty_get_baud_rate(tty);
- dev_dbg(&port->dev, "baud requested = %d\n", baud);
- if (baud) {
- /* Set baudrate to nearest supported value */
- for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
- if (baud_sup[k] / baud) {
- baud_ceil = baud_sup[k];
- if (k==0) {
- baud = baud_ceil;
- } else {
- baud_floor = baud_sup[k-1];
- if ((baud_ceil % baud)
- > (baud % baud_floor))
- baud = baud_floor;
- else
- baud = baud_ceil;
- }
- break;
- }
- }
- if (baud > 1228800) {
- /* type_0, type_1 only support up to 1228800 baud */
- if (spriv->type != HX)
- baud = 1228800;
- else if (baud > 6000000)
- baud = 6000000;
- }
- dev_dbg(&port->dev, "baud set = %d\n", baud);
- if (baud <= 115200) {
- buf[0] = baud & 0xff;
- buf[1] = (baud >> 8) & 0xff;
- buf[2] = (baud >> 16) & 0xff;
- buf[3] = (baud >> 24) & 0xff;
- } else {
- /* apparently the formula for higher speeds is:
- * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
- */
- unsigned tmp = 12*1000*1000*32 / baud;
- buf[3] = 0x80;
- buf[2] = 0;
- buf[1] = (tmp >= 256);
- while (tmp >= 256) {
- tmp >>= 2;
- buf[1] <<= 1;
- }
- buf[0] = tmp;
- }
- }
+ /* For reference: buf[0]:buf[3] baud rate value */
+ pl2303_encode_baudrate(tty, port, spriv->type, buf);
/* For reference buf[4]=0 is 1 stop bits */
/* For reference buf[4]=1 is 1.5 stop bits */
/* For reference buf[4]=2 is 2 stop bits */
- if (cflag & CSTOPB) {
- /* NOTE: Comply with "real" UARTs / RS232:
+ if (C_CSTOPB(tty)) {
+ /*
+ * NOTE: Comply with "real" UARTs / RS232:
* use 1.5 instead of 2 stop bits with 5 data bits
*/
- if ((cflag & CSIZE) == CS5) {
+ if (C_CSIZE(tty) == CS5) {
buf[4] = 1;
dev_dbg(&port->dev, "stop bits = 1.5\n");
} else {
@@ -395,14 +543,14 @@ static void pl2303_set_termios(struct tty_struct *tty,
dev_dbg(&port->dev, "stop bits = 1\n");
}
- if (cflag & PARENB) {
+ if (C_PARENB(tty)) {
/* For reference buf[5]=0 is none parity */
/* For reference buf[5]=1 is odd parity */
/* For reference buf[5]=2 is even parity */
/* For reference buf[5]=3 is mark parity */
/* For reference buf[5]=4 is space parity */
- if (cflag & PARODD) {
- if (cflag & CMSPAR) {
+ if (C_PARODD(tty)) {
+ if (tty->termios.c_cflag & CMSPAR) {
buf[5] = 3;
dev_dbg(&port->dev, "parity = mark\n");
} else {
@@ -410,7 +558,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
dev_dbg(&port->dev, "parity = odd\n");
}
} else {
- if (cflag & CMSPAR) {
+ if (tty->termios.c_cflag & CMSPAR) {
buf[5] = 4;
dev_dbg(&port->dev, "parity = space\n");
} else {
@@ -431,7 +579,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
/* change control lines if we are switching to or from B0 */
spin_lock_irqsave(&priv->lock, flags);
control = priv->line_control;
- if ((cflag & CBAUD) == B0)
+ if (C_BAUD(tty) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
@@ -443,26 +591,21 @@ static void pl2303_set_termios(struct tty_struct *tty,
spin_unlock_irqrestore(&priv->lock, flags);
}
- buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
-
+ memset(buf, 0, 7);
i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf);
- if (cflag & CRTSCTS) {
- if (spriv->type == HX)
- pl2303_vendor_write(0x0, 0x61, serial);
- else
+ if (C_CRTSCTS(tty)) {
+ if (spriv->type == type_0 || spriv->type == type_1)
pl2303_vendor_write(0x0, 0x41, serial);
+ else
+ pl2303_vendor_write(0x0, 0x61, serial);
} else {
pl2303_vendor_write(0x0, 0x0, serial);
}
- /* Save resulting baud rate */
- if (baud)
- tty_encode_baud_rate(tty, baud, baud);
-
kfree(buf);
}
@@ -495,7 +638,7 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
int result;
- if (spriv->type != HX) {
+ if (spriv->type == type_0 || spriv->type == type_1) {
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
} else {
@@ -521,7 +664,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
return result;
}
- port->port.drain_delay = 256;
return 0;
}
@@ -789,8 +931,10 @@ static void pl2303_process_read_urb(struct urb *urb)
tty_flag = TTY_PARITY;
else if (line_status & UART_FRAME_ERROR)
tty_flag = TTY_FRAME;
- dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
+ if (tty_flag != TTY_NORMAL)
+ dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__,
+ tty_flag);
/* overrun is special, not associated with a char */
if (line_status & UART_OVERRUN_ERROR)
tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index d99743290fc..a24d59ae403 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -62,6 +62,7 @@
#define MAX_BAUD_RATE 921600
#define DEFAULT_BAUD_RATE 9600
+#define QT2_READ_BUFFER_SIZE 512 /* size of read buffer */
#define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */
#define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */
@@ -112,7 +113,7 @@ struct qt2_serial_private {
unsigned char current_port; /* current port for incoming data */
struct urb *read_urb; /* shared among all ports */
- char read_buffer[512];
+ char *read_buffer;
};
struct qt2_port_private {
@@ -121,7 +122,7 @@ struct qt2_port_private {
spinlock_t urb_lock;
bool urb_in_use;
struct urb *write_urb;
- char write_buffer[QT2_WRITE_BUFFER_SIZE];
+ char *write_buffer;
spinlock_t lock;
u8 shadowLSR;
@@ -142,6 +143,7 @@ static void qt2_release(struct usb_serial *serial)
serial_priv = usb_get_serial_data(serial);
usb_free_urb(serial_priv->read_urb);
+ kfree(serial_priv->read_buffer);
kfree(serial_priv);
}
@@ -683,7 +685,7 @@ static int qt2_setup_urbs(struct usb_serial *serial)
usb_rcvbulkpipe(serial->dev,
port0->bulk_in_endpointAddress),
serial_priv->read_buffer,
- sizeof(serial_priv->read_buffer),
+ QT2_READ_BUFFER_SIZE,
qt2_read_bulk_callback, serial);
status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL);
@@ -718,6 +720,12 @@ static int qt2_attach(struct usb_serial *serial)
return -ENOMEM;
}
+ serial_priv->read_buffer = kmalloc(QT2_READ_BUFFER_SIZE, GFP_KERNEL);
+ if (!serial_priv->read_buffer) {
+ status = -ENOMEM;
+ goto err_buf;
+ }
+
usb_set_serial_data(serial, serial_priv);
status = qt2_setup_urbs(serial);
@@ -727,6 +735,8 @@ static int qt2_attach(struct usb_serial *serial)
return 0;
attach_failed:
+ kfree(serial_priv->read_buffer);
+err_buf:
kfree(serial_priv);
return status;
}
@@ -745,21 +755,29 @@ static int qt2_port_probe(struct usb_serial_port *port)
spin_lock_init(&port_priv->urb_lock);
port_priv->port = port;
+ port_priv->write_buffer = kmalloc(QT2_WRITE_BUFFER_SIZE, GFP_KERNEL);
+ if (!port_priv->write_buffer)
+ goto err_buf;
+
port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!port_priv->write_urb) {
- kfree(port_priv);
- return -ENOMEM;
- }
+ if (!port_priv->write_urb)
+ goto err_urb;
+
bEndpointAddress = serial->port[0]->bulk_out_endpointAddress;
usb_fill_bulk_urb(port_priv->write_urb, serial->dev,
usb_sndbulkpipe(serial->dev, bEndpointAddress),
port_priv->write_buffer,
- sizeof(port_priv->write_buffer),
+ QT2_WRITE_BUFFER_SIZE,
qt2_write_bulk_callback, port);
usb_set_serial_port_data(port, port_priv);
return 0;
+err_urb:
+ kfree(port_priv->write_buffer);
+err_buf:
+ kfree(port_priv);
+ return -ENOMEM;
}
static int qt2_port_remove(struct usb_serial_port *port)
@@ -768,6 +786,7 @@ static int qt2_port_remove(struct usb_serial_port *port)
port_priv = usb_get_serial_port_data(port);
usb_free_urb(port_priv->write_urb);
+ kfree(port_priv->write_buffer);
kfree(port_priv);
return 0;
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 21cd7bf2a8c..ba895989d8c 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -92,13 +92,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-static __u16 vendor; /* no default */
-static __u16 product; /* no default */
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-
module_param(safe, bool, 0);
MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off");
@@ -140,8 +133,6 @@ static struct usb_device_id id_table[] = {
{MY_USB_DEVICE(0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */
{MY_USB_DEVICE(0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */
{MY_USB_DEVICE(0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Sharp tmp */
- /* extra null entry for module vendor/produc parameters */
- {MY_USB_DEVICE(0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
{} /* terminating entry */
};
@@ -272,7 +263,19 @@ static int safe_prepare_write_buffer(struct usb_serial_port *port,
static int safe_startup(struct usb_serial *serial)
{
- switch (serial->interface->cur_altsetting->desc.bInterfaceProtocol) {
+ struct usb_interface_descriptor *desc;
+
+ if (serial->dev->descriptor.bDeviceClass != CDC_DEVICE_CLASS)
+ return -ENODEV;
+
+ desc = &serial->interface->cur_altsetting->desc;
+
+ if (desc->bInterfaceClass != LINEO_INTERFACE_CLASS)
+ return -ENODEV;
+ if (desc->bInterfaceSubClass != LINEO_INTERFACE_SUBCLASS_SAFESERIAL)
+ return -ENODEV;
+
+ switch (desc->bInterfaceProtocol) {
case LINEO_SAFESERIAL_CRC:
break;
case LINEO_SAFESERIAL_CRC_PADDED:
@@ -300,30 +303,4 @@ static struct usb_serial_driver * const serial_drivers[] = {
&safe_device, NULL
};
-static int __init safe_init(void)
-{
- int i;
-
- /* if we have vendor / product parameters patch them into id list */
- if (vendor || product) {
- pr_info("vendor: %x product: %x\n", vendor, product);
-
- for (i = 0; i < ARRAY_SIZE(id_table); i++) {
- if (!id_table[i].idVendor && !id_table[i].idProduct) {
- id_table[i].idVendor = vendor;
- id_table[i].idProduct = product;
- break;
- }
- }
- }
-
- return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table);
-}
-
-static void __exit safe_exit(void)
-{
- usb_serial_deregister_drivers(serial_drivers);
-}
-
-module_init(safe_init);
-module_exit(safe_exit);
+module_usb_serial_driver(serial_drivers, id_table);
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
deleted file mode 100644
index a76b1ae54a2..00000000000
--- a/drivers/usb/serial/siemens_mpi.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Siemens USB-MPI Serial USB driver
- *
- * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de>
- * Copyright (C) 2005,2008 Greg Kroah-Hartman <gregkh@suse.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/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_AUTHOR "Thomas Hergenhahn@web.de http://libnodave.sf.net"
-#define DRIVER_DESC "Driver for Siemens USB/MPI adapter"
-
-
-static const struct usb_device_id id_table[] = {
- /* Vendor and product id for 6ES7-972-0CB20-0XA0 */
- { USB_DEVICE(0x908, 0x0004) },
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver siemens_usb_mpi_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "siemens_mpi",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &siemens_usb_mpi_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index ddf6c47137d..4abac28b599 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -169,6 +169,8 @@ static int spcp8x5_port_probe(struct usb_serial_port *port)
usb_set_serial_port_data(port, priv);
+ port->port.drain_delay = 256;
+
return 0;
}
@@ -411,8 +413,6 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
if (tty)
spcp8x5_set_termios(tty, port, NULL);
- port->port.drain_delay = 256;
-
return usb_serial_generic_open(tty, port);
}
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 7182bb774b7..760b78560f6 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -45,8 +45,6 @@
#define TI_FIRMWARE_BUF_SIZE 16284
-#define TI_WRITE_BUF_SIZE 1024
-
#define TI_TRANSFER_TIMEOUT 2
#define TI_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */
@@ -71,13 +69,11 @@ struct ti_port {
__u8 tp_uart_mode; /* 232 or 485 modes */
unsigned int tp_uart_base_addr;
int tp_flags;
- wait_queue_head_t tp_write_wait;
struct ti_device *tp_tdev;
struct usb_serial_port *tp_port;
spinlock_t tp_lock;
int tp_read_urb_state;
int tp_write_urb_in_use;
- struct kfifo write_fifo;
};
struct ti_device {
@@ -145,20 +141,9 @@ static int ti_download_firmware(struct ti_device *tdev);
/* module parameters */
static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
-static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT];
-static unsigned int vendor_3410_count;
-static ushort product_3410[TI_EXTRA_VID_PID_COUNT];
-static unsigned int product_3410_count;
-static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT];
-static unsigned int vendor_5052_count;
-static ushort product_5052[TI_EXTRA_VID_PID_COUNT];
-static unsigned int product_5052_count;
/* supported devices */
-/* the array dimension is the number of default entries plus */
-/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
-/* null entry */
-static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_3410[] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -175,16 +160,18 @@ static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
+ { } /* terminator */
};
-static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_5052[] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
+ { } /* terminator */
};
-static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_combined[] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -204,7 +191,7 @@ static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1]
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
- { }
+ { } /* terminator */
};
static struct usb_serial_driver ti_1port_device = {
@@ -293,61 +280,12 @@ module_param(closing_wait, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(closing_wait,
"Maximum wait for data to drain in close, in .01 secs, default is 4000");
-module_param_array(vendor_3410, ushort, &vendor_3410_count, S_IRUGO);
-MODULE_PARM_DESC(vendor_3410,
- "Vendor ids for 3410 based devices, 1-5 short integers");
-module_param_array(product_3410, ushort, &product_3410_count, S_IRUGO);
-MODULE_PARM_DESC(product_3410,
- "Product ids for 3410 based devices, 1-5 short integers");
-module_param_array(vendor_5052, ushort, &vendor_5052_count, S_IRUGO);
-MODULE_PARM_DESC(vendor_5052,
- "Vendor ids for 5052 based devices, 1-5 short integers");
-module_param_array(product_5052, ushort, &product_5052_count, S_IRUGO);
-MODULE_PARM_DESC(product_5052,
- "Product ids for 5052 based devices, 1-5 short integers");
-
MODULE_DEVICE_TABLE(usb, ti_id_table_combined);
+module_usb_serial_driver(serial_drivers, ti_id_table_combined);
/* Functions */
-static int __init ti_init(void)
-{
- int i, j, c;
-
- /* insert extra vendor and product ids */
- c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1;
- j = ARRAY_SIZE(ti_id_table_3410) - TI_EXTRA_VID_PID_COUNT - 1;
- for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++, c++) {
- ti_id_table_3410[j].idVendor = vendor_3410[i];
- ti_id_table_3410[j].idProduct = product_3410[i];
- ti_id_table_3410[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- ti_id_table_combined[c].idVendor = vendor_3410[i];
- ti_id_table_combined[c].idProduct = product_3410[i];
- ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- }
- j = ARRAY_SIZE(ti_id_table_5052) - TI_EXTRA_VID_PID_COUNT - 1;
- for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++, c++) {
- ti_id_table_5052[j].idVendor = vendor_5052[i];
- ti_id_table_5052[j].idProduct = product_5052[i];
- ti_id_table_5052[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- ti_id_table_combined[c].idVendor = vendor_5052[i];
- ti_id_table_combined[c].idProduct = product_5052[i];
- ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- }
-
- return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined);
-}
-
-static void __exit ti_exit(void)
-{
- usb_serial_deregister_drivers(serial_drivers);
-}
-
-module_init(ti_init);
-module_exit(ti_exit);
-
-
static int ti_startup(struct usb_serial *serial)
{
struct ti_device *tdev;
@@ -371,7 +309,7 @@ static int ti_startup(struct usb_serial *serial)
usb_set_serial_data(serial, tdev);
/* determine device type */
- if (usb_match_id(serial->interface, ti_id_table_3410))
+ if (serial->type == &ti_1port_device)
tdev->td_is_3410 = 1;
dev_dbg(&dev->dev, "%s - device type is %s\n", __func__,
tdev->td_is_3410 ? "3410" : "5052");
@@ -430,17 +368,14 @@ static int ti_port_probe(struct usb_serial_port *port)
else
tport->tp_uart_base_addr = TI_UART2_BASE_ADDR;
port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
- init_waitqueue_head(&tport->tp_write_wait);
- if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) {
- kfree(tport);
- return -ENOMEM;
- }
tport->tp_port = port;
tport->tp_tdev = usb_get_serial_data(port->serial);
tport->tp_uart_mode = 0; /* default is RS232 */
usb_set_serial_port_data(port, tport);
+ port->port.drain_delay = 3;
+
return 0;
}
@@ -449,7 +384,6 @@ static int ti_port_remove(struct usb_serial_port *port)
struct ti_port *tport;
tport = usb_get_serial_port_data(port);
- kfifo_free(&tport->write_fifo);
kfree(tport);
return 0;
@@ -582,8 +516,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
tport->tp_is_open = 1;
++tdev->td_open_port_count;
- port->port.drain_delay = 3;
-
goto release_lock;
unlink_int_urb:
@@ -616,7 +548,7 @@ static void ti_close(struct usb_serial_port *port)
usb_kill_urb(port->write_urb);
tport->tp_write_urb_in_use = 0;
spin_lock_irqsave(&tport->tp_lock, flags);
- kfifo_reset_out(&tport->write_fifo);
+ kfifo_reset_out(&port->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
port_number = port->port_number;
@@ -655,7 +587,7 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
if (tport == NULL || !tport->tp_is_open)
return -ENODEV;
- count = kfifo_in_locked(&tport->write_fifo, data, count,
+ count = kfifo_in_locked(&port->write_fifo, data, count,
&tport->tp_lock);
ti_send(tport);
@@ -674,7 +606,7 @@ static int ti_write_room(struct tty_struct *tty)
return 0;
spin_lock_irqsave(&tport->tp_lock, flags);
- room = kfifo_avail(&tport->write_fifo);
+ room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
@@ -693,7 +625,7 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
return 0;
spin_lock_irqsave(&tport->tp_lock, flags);
- chars = kfifo_len(&tport->write_fifo);
+ chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
@@ -1090,13 +1022,11 @@ static void ti_bulk_in_callback(struct urb *urb)
case -ESHUTDOWN:
dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status);
tport->tp_tdev->td_urb_error = 1;
- wake_up_interruptible(&tport->tp_write_wait);
return;
default:
dev_err(dev, "%s - nonzero urb status, %d\n",
__func__, status);
tport->tp_tdev->td_urb_error = 1;
- wake_up_interruptible(&tport->tp_write_wait);
}
if (status == -EPIPE)
@@ -1152,13 +1082,11 @@ static void ti_bulk_out_callback(struct urb *urb)
case -ESHUTDOWN:
dev_dbg(&port->dev, "%s - urb shutting down, %d\n", __func__, status);
tport->tp_tdev->td_urb_error = 1;
- wake_up_interruptible(&tport->tp_write_wait);
return;
default:
dev_err_console(port, "%s - nonzero urb status, %d\n",
__func__, status);
tport->tp_tdev->td_urb_error = 1;
- wake_up_interruptible(&tport->tp_write_wait);
}
/* send any buffered data */
@@ -1197,7 +1125,7 @@ static void ti_send(struct ti_port *tport)
if (tport->tp_write_urb_in_use)
goto unlock;
- count = kfifo_out(&tport->write_fifo,
+ count = kfifo_out(&port->write_fifo,
port->write_urb->transfer_buffer,
port->bulk_out_size);
@@ -1232,7 +1160,6 @@ static void ti_send(struct ti_port *tport)
/* more room in the buffer for new writes, wakeup */
tty_port_tty_wakeup(&port->port);
- wake_up_interruptible(&tport->tp_write_wait);
return;
unlock:
spin_unlock_irqrestore(&tport->tp_lock, flags);
@@ -1312,7 +1239,7 @@ static int ti_get_serial_info(struct ti_port *tport,
ret_serial.line = port->minor;
ret_serial.port = port->port_number;
ret_serial.flags = tport->tp_flags;
- ret_serial.xmit_fifo_size = TI_WRITE_BUF_SIZE;
+ ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo);
ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800;
ret_serial.closing_wait = cwait;
@@ -1536,14 +1463,15 @@ static int ti_download_firmware(struct ti_device *tdev)
char buf[32];
/* try ID specific firmware first, then try generic firmware */
- sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor,
- dev->descriptor.idProduct);
+ sprintf(buf, "ti_usb-v%04x-p%04x.fw",
+ le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
status = request_firmware(&fw_p, buf, &dev->dev);
if (status != 0) {
buf[0] = '\0';
- if (dev->descriptor.idVendor == MTS_VENDOR_ID) {
- switch (dev->descriptor.idProduct) {
+ if (le16_to_cpu(dev->descriptor.idVendor) == MTS_VENDOR_ID) {
+ switch (le16_to_cpu(dev->descriptor.idProduct)) {
case MTS_CDMA_PRODUCT_ID:
strcpy(buf, "mts_cdma.fw");
break;
diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c
new file mode 100644
index 00000000000..52eb91f2eb2
--- /dev/null
+++ b/drivers/usb/serial/usb-serial-simple.c
@@ -0,0 +1,110 @@
+/*
+ * USB Serial "Simple" driver
+ *
+ * Copyright (C) 2001-2006,2008,2013 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net)
+ * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de>
+ * Copyright (C) 2009 Outpost Embedded, LLC
+ * Copyright (C) 2010 Zilogic Systems <code@zilogic.com>
+ * Copyright (C) 2013 Wei Shuai <cpuwolf@gmail.com>
+ * Copyright (C) 2013 Linux Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+#define DEVICE(vendor, IDS) \
+static const struct usb_device_id vendor##_id_table[] = { \
+ IDS(), \
+ { }, \
+}; \
+static struct usb_serial_driver vendor##_device = { \
+ .driver = { \
+ .owner = THIS_MODULE, \
+ .name = #vendor, \
+ }, \
+ .id_table = vendor##_id_table, \
+ .num_ports = 1, \
+};
+
+
+/* ZIO Motherboard USB driver */
+#define ZIO_IDS() \
+ { USB_DEVICE(0x1CBE, 0x0103) }
+DEVICE(zio, ZIO_IDS);
+
+/* Funsoft Serial USB driver */
+#define FUNSOFT_IDS() \
+ { USB_DEVICE(0x1404, 0xcddc) }
+DEVICE(funsoft, FUNSOFT_IDS);
+
+/* Infineon Flashloader driver */
+#define FLASHLOADER_IDS() \
+ { USB_DEVICE(0x8087, 0x0716) }
+DEVICE(flashloader, FLASHLOADER_IDS);
+
+/* ViVOpay USB Serial Driver */
+#define VIVOPAY_IDS() \
+ { USB_DEVICE(0x1d5f, 0x1004) } /* ViVOpay 8800 */
+DEVICE(vivopay, VIVOPAY_IDS);
+
+/* Motorola USB Phone driver */
+#define MOTO_IDS() \
+ { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */ \
+ { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */ \
+ { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */ \
+ { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */ \
+ { USB_DEVICE(0x22b8, 0x2c64) } /* Motorola V950 phone */
+DEVICE(moto_modem, MOTO_IDS);
+
+/* HP4x (48/49) Generic Serial driver */
+#define HP4X_IDS() \
+ { USB_DEVICE(0x03f0, 0x0121) }
+DEVICE(hp4x, HP4X_IDS);
+
+/* Suunto ANT+ USB Driver */
+#define SUUNTO_IDS() \
+ { USB_DEVICE(0x0fcf, 0x1008) }
+DEVICE(suunto, SUUNTO_IDS);
+
+/* Siemens USB/MPI adapter */
+#define SIEMENS_IDS() \
+ { USB_DEVICE(0x908, 0x0004) }
+DEVICE(siemens_mpi, SIEMENS_IDS);
+
+/* All of the above structures mushed into two lists */
+static struct usb_serial_driver * const serial_drivers[] = {
+ &zio_device,
+ &funsoft_device,
+ &flashloader_device,
+ &vivopay_device,
+ &moto_modem_device,
+ &hp4x_device,
+ &suunto_device,
+ &siemens_mpi_device,
+ NULL
+};
+
+static const struct usb_device_id id_table[] = {
+ ZIO_IDS(),
+ FUNSOFT_IDS(),
+ FLASHLOADER_IDS(),
+ VIVOPAY_IDS(),
+ MOTO_IDS(),
+ HP4X_IDS(),
+ SUUNTO_IDS(),
+ SIEMENS_IDS(),
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+module_usb_serial_driver(serial_drivers, id_table);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index cb27fcb2fc9..6091bd5a1f4 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -681,20 +681,10 @@ static int serial_port_carrier_raised(struct tty_port *port)
static void serial_port_dtr_rts(struct tty_port *port, int on)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
- struct usb_serial *serial = p->serial;
- struct usb_serial_driver *drv = serial->type;
+ struct usb_serial_driver *drv = p->serial->type;
- if (!drv->dtr_rts)
- return;
- /*
- * Work-around bug in the tty-layer which can result in dtr_rts
- * being called after a disconnect (and tty_unregister_device
- * has returned). Remove once bug has been squashed.
- */
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
+ if (drv->dtr_rts)
drv->dtr_rts(p, on);
- mutex_unlock(&serial->disc_mutex);
}
static const struct tty_port_operations serial_port_ops = {
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 8257d30c407..85365784040 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -291,18 +291,18 @@ static void usb_wwan_indat_callback(struct urb *urb)
tty_flip_buffer_push(&port->port);
} else
dev_dbg(dev, "%s: empty read urb received\n", __func__);
-
- /* Resubmit urb so we continue receiving */
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err) {
- if (err != -EPERM) {
- dev_err(dev, "%s: resubmit read urb failed. (%d)\n", __func__, err);
- /* busy also in error unless we are killed */
- usb_mark_last_busy(port->serial->dev);
- }
- } else {
+ }
+ /* Resubmit urb so we continue receiving */
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ if (err != -EPERM) {
+ dev_err(dev, "%s: resubmit read urb failed. (%d)\n",
+ __func__, err);
+ /* busy also in error unless we are killed */
usb_mark_last_busy(port->serial->dev);
}
+ } else {
+ usb_mark_last_busy(port->serial->dev);
}
}
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
deleted file mode 100644
index 6299526ff8c..00000000000
--- a/drivers/usb/serial/vivopay-serial.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2009 Outpost Embedded, LLC
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_DESC "ViVOpay USB Serial Driver"
-
-#define VIVOPAY_VENDOR_ID 0x1d5f
-
-
-static struct usb_device_id id_table [] = {
- /* ViVOpay 8800 */
- { USB_DEVICE(VIVOPAY_VENDOR_ID, 0x1004) },
- { },
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver vivopay_serial_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "vivopay-serial",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &vivopay_serial_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c
deleted file mode 100644
index c043aa84a0b..00000000000
--- a/drivers/usb/serial/zio.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * ZIO Motherboard USB driver
- *
- * Copyright (C) 2010 Zilogic Systems <code@zilogic.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/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x1CBE, 0x0103) },
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver zio_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "zio",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &zio_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 92b05d95ec5..94d75edef77 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -496,7 +496,7 @@ US_DO_ALL_FLAGS
***********************************************************************/
/* Output routine for the sysfs max_sectors file */
-static ssize_t show_max_sectors(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t max_sectors_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -504,7 +504,7 @@ static ssize_t show_max_sectors(struct device *dev, struct device_attribute *att
}
/* Input routine for the sysfs max_sectors file */
-static ssize_t store_max_sectors(struct device *dev, struct device_attribute *attr, const char *buf,
+static ssize_t max_sectors_store(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -514,16 +514,14 @@ static ssize_t store_max_sectors(struct device *dev, struct device_attribute *at
blk_queue_max_hw_sectors(sdev->request_queue, ms);
return count;
}
- return -EINVAL;
+ return -EINVAL;
}
-
-static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors,
- store_max_sectors);
+static DEVICE_ATTR_RW(max_sectors);
static struct device_attribute *sysfs_device_attr_list[] = {
- &dev_attr_max_sectors,
- NULL,
- };
+ &dev_attr_max_sectors,
+ NULL,
+};
/*
* this defines our host template, with which we'll allocate hosts
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 1799335288b..c015f2c1672 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -665,6 +665,13 @@ UNUSUAL_DEV( 0x054c, 0x016a, 0x0000, 0x9999,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
+/* Submitted by Ren Bigcren <bigcren.ren@sonymobile.com> */
+UNUSUAL_DEV( 0x054c, 0x02a5, 0x0100, 0x0100,
+ "Sony Corp.",
+ "MicroVault Flash Drive",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NO_READ_CAPACITY_16 ),
+
/* floppy reports multiple luns */
UNUSUAL_DEV( 0x055d, 0x2020, 0x0000, 0x0210,
"SAMSUNG",
diff --git a/drivers/usb/usb-common.c b/drivers/usb/usb-common.c
index 675384dabfe..d771870a819 100644
--- a/drivers/usb/usb-common.c
+++ b/drivers/usb/usb-common.c
@@ -43,20 +43,20 @@ const char *usb_otg_state_string(enum usb_otg_state state)
}
EXPORT_SYMBOL_GPL(usb_otg_state_string);
+static const char *const speed_names[] = {
+ [USB_SPEED_UNKNOWN] = "UNKNOWN",
+ [USB_SPEED_LOW] = "low-speed",
+ [USB_SPEED_FULL] = "full-speed",
+ [USB_SPEED_HIGH] = "high-speed",
+ [USB_SPEED_WIRELESS] = "wireless",
+ [USB_SPEED_SUPER] = "super-speed",
+};
+
const char *usb_speed_string(enum usb_device_speed speed)
{
- static const char *const names[] = {
- [USB_SPEED_UNKNOWN] = "UNKNOWN",
- [USB_SPEED_LOW] = "low-speed",
- [USB_SPEED_FULL] = "full-speed",
- [USB_SPEED_HIGH] = "high-speed",
- [USB_SPEED_WIRELESS] = "wireless",
- [USB_SPEED_SUPER] = "super-speed",
- };
-
- if (speed < 0 || speed >= ARRAY_SIZE(names))
+ if (speed < 0 || speed >= ARRAY_SIZE(speed_names))
speed = USB_SPEED_UNKNOWN;
- return names[speed];
+ return speed_names[speed];
}
EXPORT_SYMBOL_GPL(usb_speed_string);
@@ -112,6 +112,33 @@ enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
return USB_DR_MODE_UNKNOWN;
}
EXPORT_SYMBOL_GPL(of_usb_get_dr_mode);
+
+/**
+ * of_usb_get_maximum_speed - Get maximum requested speed for a given USB
+ * controller.
+ * @np: Pointer to the given device_node
+ *
+ * The function gets the maximum speed string from property "maximum-speed",
+ * and returns the corresponding enum usb_device_speed.
+ */
+enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np)
+{
+ const char *maximum_speed;
+ int err;
+ int i;
+
+ err = of_property_read_string(np, "maximum-speed", &maximum_speed);
+ if (err < 0)
+ return USB_SPEED_UNKNOWN;
+
+ for (i = 0; i < ARRAY_SIZE(speed_names); i++)
+ if (strcmp(maximum_speed, speed_names[i]) == 0)
+ return i;
+
+ return USB_SPEED_UNKNOWN;
+}
+EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed);
+
#endif
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 7ed3b039dbe..ff97652343a 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -325,9 +325,8 @@ retry:
rv = skel_do_read_io(dev, count);
if (rv < 0)
goto exit;
- else if (!(file->f_flags & O_NONBLOCK))
+ else
goto retry;
- rv = -EAGAIN;
}
exit:
mutex_unlock(&dev->io_mutex);
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c
index bdb0cc3046b..fe8bc777ab8 100644
--- a/drivers/usb/wusbcore/rh.c
+++ b/drivers/usb/wusbcore/rh.c
@@ -141,18 +141,26 @@ static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx)
int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
{
struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- size_t cnt, size;
- unsigned long *buf = (unsigned long *) _buf;
+ size_t cnt, size, bits_set = 0;
/* WE DON'T LOCK, see comment */
- size = wusbhc->ports_max + 1 /* hub bit */;
- size = (size + 8 - 1) / 8; /* round to bytes */
- for (cnt = 0; cnt < wusbhc->ports_max; cnt++)
- if (wusb_port_by_idx(wusbhc, cnt)->change)
- set_bit(cnt + 1, buf);
- else
- clear_bit(cnt + 1, buf);
- return size;
+ /* round up to bytes. Hub bit is bit 0 so add 1. */
+ size = DIV_ROUND_UP(wusbhc->ports_max + 1, 8);
+
+ /* clear the output buffer. */
+ memset(_buf, 0, size);
+ /* set the bit for each changed port. */
+ for (cnt = 0; cnt < wusbhc->ports_max; cnt++) {
+
+ if (wusb_port_by_idx(wusbhc, cnt)->change) {
+ const int bitpos = cnt+1;
+
+ _buf[bitpos/8] |= (1 << (bitpos % 8));
+ bits_set++;
+ }
+ }
+
+ return bits_set ? size : 0;
}
EXPORT_SYMBOL_GPL(wusbhc_rh_status_data);
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h
index d6bea3e0b54..cf250c21e94 100644
--- a/drivers/usb/wusbcore/wa-hc.h
+++ b/drivers/usb/wusbcore/wa-hc.h
@@ -91,6 +91,7 @@
struct wusbhc;
struct wahc;
extern void wa_urb_enqueue_run(struct work_struct *ws);
+extern void wa_process_errored_transfers_run(struct work_struct *ws);
/**
* RPipe instance
@@ -190,8 +191,14 @@ struct wahc {
struct list_head xfer_list;
struct list_head xfer_delayed_list;
+ struct list_head xfer_errored_list;
+ /*
+ * lock for the above xfer lists. Can be taken while a xfer->lock is
+ * held but not in the reverse order.
+ */
spinlock_t xfer_list_lock;
- struct work_struct xfer_work;
+ struct work_struct xfer_enqueue_work;
+ struct work_struct xfer_error_work;
atomic_t xfer_id_count;
};
@@ -244,8 +251,10 @@ static inline void wa_init(struct wahc *wa)
edc_init(&wa->dti_edc);
INIT_LIST_HEAD(&wa->xfer_list);
INIT_LIST_HEAD(&wa->xfer_delayed_list);
+ INIT_LIST_HEAD(&wa->xfer_errored_list);
spin_lock_init(&wa->xfer_list_lock);
- INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run);
+ INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run);
+ INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run);
atomic_set(&wa->xfer_id_count, 1);
}
@@ -269,6 +278,8 @@ static inline void rpipe_put(struct wa_rpipe *rpipe)
}
extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *);
+extern void rpipe_clear_feature_stalled(struct wahc *,
+ struct usb_host_endpoint *);
extern int wa_rpipes_create(struct wahc *);
extern void wa_rpipes_destroy(struct wahc *);
static inline void rpipe_avail_dec(struct wa_rpipe *rpipe)
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
index 9a595c1ed86..fd4f1ce6256 100644
--- a/drivers/usb/wusbcore/wa-rpipe.c
+++ b/drivers/usb/wusbcore/wa-rpipe.c
@@ -527,3 +527,24 @@ void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep)
mutex_unlock(&wa->rpipe_mutex);
}
EXPORT_SYMBOL_GPL(rpipe_ep_disable);
+
+/* Clear the stalled status of an RPIPE. */
+void rpipe_clear_feature_stalled(struct wahc *wa, struct usb_host_endpoint *ep)
+{
+ struct wa_rpipe *rpipe;
+
+ mutex_lock(&wa->rpipe_mutex);
+ rpipe = ep->hcpriv;
+ if (rpipe != NULL) {
+ u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+
+ usb_control_msg(
+ wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+ RPIPE_STALL, index, NULL, 0, 1000);
+ }
+ mutex_unlock(&wa->rpipe_mutex);
+}
+EXPORT_SYMBOL_GPL(rpipe_clear_feature_stalled);
+
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
index 16968c89949..6ad02f57c36 100644
--- a/drivers/usb/wusbcore/wa-xfer.c
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -125,10 +125,13 @@ struct wa_seg {
u8 xfer_extra[]; /* xtra space for xfer_hdr_ctl */
};
-static void wa_seg_init(struct wa_seg *seg)
+static inline void wa_seg_init(struct wa_seg *seg)
{
- /* usb_init_urb() repeats a lot of work, so we do it here */
- kref_init(&seg->urb.kref);
+ usb_init_urb(&seg->urb);
+
+ /* set the remaining memory to 0. */
+ memset(((void *)seg) + sizeof(seg->urb), 0,
+ sizeof(*seg) - sizeof(seg->urb));
}
/*
@@ -166,8 +169,8 @@ static inline void wa_xfer_init(struct wa_xfer *xfer)
/*
* Destroy a transfer structure
*
- * Note that the xfer->seg[index] thingies follow the URB life cycle,
- * so we need to put them, not free them.
+ * Note that freeing xfer->seg[cnt]->urb will free the containing
+ * xfer->seg[cnt] memory that was allocated by __wa_xfer_setup_segs.
*/
static void wa_xfer_destroy(struct kref *_xfer)
{
@@ -175,9 +178,8 @@ static void wa_xfer_destroy(struct kref *_xfer)
if (xfer->seg) {
unsigned cnt;
for (cnt = 0; cnt < xfer->segs; cnt++) {
- if (xfer->is_inbound)
- usb_put_urb(xfer->seg[cnt]->dto_urb);
- usb_put_urb(&xfer->seg[cnt]->urb);
+ usb_free_urb(xfer->seg[cnt]->dto_urb);
+ usb_free_urb(&xfer->seg[cnt]->urb);
}
}
kfree(xfer);
@@ -732,9 +734,9 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
buf_itr = 0;
buf_size = xfer->urb->transfer_buffer_length;
for (cnt = 0; cnt < xfer->segs; cnt++) {
- seg = xfer->seg[cnt] = kzalloc(alloc_size, GFP_ATOMIC);
+ seg = xfer->seg[cnt] = kmalloc(alloc_size, GFP_ATOMIC);
if (seg == NULL)
- goto error_seg_kzalloc;
+ goto error_seg_kmalloc;
wa_seg_init(seg);
seg->xfer = xfer;
seg->index = cnt;
@@ -804,15 +806,17 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
return 0;
error_sg_alloc:
- kfree(seg->dto_urb);
+ usb_free_urb(xfer->seg[cnt]->dto_urb);
error_dto_alloc:
kfree(xfer->seg[cnt]);
cnt--;
-error_seg_kzalloc:
+error_seg_kmalloc:
/* use the fact that cnt is left at were it failed */
for (; cnt >= 0; cnt--) {
- if (xfer->seg[cnt] && xfer->is_inbound == 0)
+ if (xfer->seg[cnt] && xfer->is_inbound == 0) {
usb_free_urb(xfer->seg[cnt]->dto_urb);
+ kfree(xfer->seg[cnt]->dto_urb->sg);
+ }
kfree(xfer->seg[cnt]);
}
error_segs_kzalloc:
@@ -928,7 +932,7 @@ static void wa_xfer_delayed_run(struct wa_rpipe *rpipe)
spin_lock_irqsave(&rpipe->seg_lock, flags);
while (atomic_read(&rpipe->segs_available) > 0
&& !list_empty(&rpipe->seg_list)) {
- seg = list_entry(rpipe->seg_list.next, struct wa_seg,
+ seg = list_first_entry(&(rpipe->seg_list), struct wa_seg,
list_node);
list_del(&seg->list_node);
xfer = seg->xfer;
@@ -1093,34 +1097,82 @@ error_xfer_submit:
*
* We need to be careful here, as dequeue() could be called in the
* middle. That's why we do the whole thing under the
- * wa->xfer_list_lock. If dequeue() jumps in, it first locks urb->lock
+ * wa->xfer_list_lock. If dequeue() jumps in, it first locks xfer->lock
* and then checks the list -- so as we would be acquiring in inverse
- * order, we just drop the lock once we have the xfer and reacquire it
- * later.
+ * order, we move the delayed list to a separate list while locked and then
+ * submit them without the list lock held.
*/
void wa_urb_enqueue_run(struct work_struct *ws)
{
- struct wahc *wa = container_of(ws, struct wahc, xfer_work);
+ struct wahc *wa = container_of(ws, struct wahc, xfer_enqueue_work);
struct wa_xfer *xfer, *next;
struct urb *urb;
+ LIST_HEAD(tmp_list);
+ /* Create a copy of the wa->xfer_delayed_list while holding the lock */
spin_lock_irq(&wa->xfer_list_lock);
- list_for_each_entry_safe(xfer, next, &wa->xfer_delayed_list,
- list_node) {
+ list_cut_position(&tmp_list, &wa->xfer_delayed_list,
+ wa->xfer_delayed_list.prev);
+ spin_unlock_irq(&wa->xfer_list_lock);
+
+ /*
+ * enqueue from temp list without list lock held since wa_urb_enqueue_b
+ * can take xfer->lock as well as lock mutexes.
+ */
+ list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
list_del_init(&xfer->list_node);
- spin_unlock_irq(&wa->xfer_list_lock);
urb = xfer->urb;
wa_urb_enqueue_b(xfer);
usb_put_urb(urb); /* taken when queuing */
-
- spin_lock_irq(&wa->xfer_list_lock);
}
- spin_unlock_irq(&wa->xfer_list_lock);
}
EXPORT_SYMBOL_GPL(wa_urb_enqueue_run);
/*
+ * Process the errored transfers on the Wire Adapter outside of interrupt.
+ */
+void wa_process_errored_transfers_run(struct work_struct *ws)
+{
+ struct wahc *wa = container_of(ws, struct wahc, xfer_error_work);
+ struct wa_xfer *xfer, *next;
+ LIST_HEAD(tmp_list);
+
+ pr_info("%s: Run delayed STALL processing.\n", __func__);
+
+ /* Create a copy of the wa->xfer_errored_list while holding the lock */
+ spin_lock_irq(&wa->xfer_list_lock);
+ list_cut_position(&tmp_list, &wa->xfer_errored_list,
+ wa->xfer_errored_list.prev);
+ spin_unlock_irq(&wa->xfer_list_lock);
+
+ /*
+ * run rpipe_clear_feature_stalled from temp list without list lock
+ * held.
+ */
+ list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
+ struct usb_host_endpoint *ep;
+ unsigned long flags;
+ struct wa_rpipe *rpipe;
+
+ spin_lock_irqsave(&xfer->lock, flags);
+ ep = xfer->ep;
+ rpipe = ep->hcpriv;
+ spin_unlock_irqrestore(&xfer->lock, flags);
+
+ /* clear RPIPE feature stalled without holding a lock. */
+ rpipe_clear_feature_stalled(wa, ep);
+
+ /* complete the xfer. This removes it from the tmp list. */
+ wa_xfer_completion(xfer);
+
+ /* check for work. */
+ wa_xfer_delayed_run(rpipe);
+ }
+}
+EXPORT_SYMBOL_GPL(wa_process_errored_transfers_run);
+
+/*
* Submit a transfer to the Wire Adapter in a delayed way
*
* The process of enqueuing involves possible sleeps() [see
@@ -1175,7 +1227,7 @@ int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,
spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
list_add_tail(&xfer->list_node, &wa->xfer_delayed_list);
spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
- queue_work(wusbd, &wa->xfer_work);
+ queue_work(wusbd, &wa->xfer_enqueue_work);
} else {
wa_urb_enqueue_b(xfer);
}
@@ -1217,7 +1269,8 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb)
xfer = urb->hcpriv;
if (xfer == NULL) {
- /* NOthing setup yet enqueue will see urb->status !=
+ /*
+ * Nothing setup yet enqueue will see urb->status !=
* -EINPROGRESS (by hcd layer) and bail out with
* error, no need to do completion
*/
@@ -1226,6 +1279,12 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb)
}
spin_lock_irqsave(&xfer->lock, flags);
rpipe = xfer->ep->hcpriv;
+ if (rpipe == NULL) {
+ pr_debug("%s: xfer id 0x%08X has no RPIPE. %s",
+ __func__, wa_xfer_id(xfer),
+ "Probably already aborted.\n" );
+ goto out_unlock;
+ }
/* Check the delayed list -> if there, release and complete */
spin_lock_irqsave(&wa->xfer_list_lock, flags2);
if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
@@ -1355,7 +1414,7 @@ static int wa_xfer_status_to_errno(u8 status)
*
* inbound transfers: need to schedule a DTI read
*
- * FIXME: this functio needs to be broken up in parts
+ * FIXME: this function needs to be broken up in parts
*/
static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)
{
@@ -1477,17 +1536,37 @@ error_submit_buf_in:
seg->result = result;
kfree(wa->buf_in_urb->sg);
error_sg_alloc:
+ __wa_xfer_abort(xfer);
error_complete:
seg->status = WA_SEG_ERROR;
xfer->segs_done++;
rpipe_ready = rpipe_avail_inc(rpipe);
- __wa_xfer_abort(xfer);
done = __wa_xfer_is_done(xfer);
- spin_unlock_irqrestore(&xfer->lock, flags);
- if (done)
- wa_xfer_completion(xfer);
- if (rpipe_ready)
- wa_xfer_delayed_run(rpipe);
+ /*
+ * queue work item to clear STALL for control endpoints.
+ * Otherwise, let endpoint_reset take care of it.
+ */
+ if (((usb_status & 0x3f) == WA_XFER_STATUS_HALTED) &&
+ usb_endpoint_xfer_control(&xfer->ep->desc) &&
+ done) {
+
+ dev_info(dev, "Control EP stall. Queue delayed work.\n");
+ spin_lock_irq(&wa->xfer_list_lock);
+ /* remove xfer from xfer_list. */
+ list_del(&xfer->list_node);
+ /* add xfer to xfer_errored_list. */
+ list_add_tail(&xfer->list_node, &wa->xfer_errored_list);
+ spin_unlock_irq(&wa->xfer_list_lock);
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ queue_work(wusbd, &wa->xfer_error_work);
+ } else {
+ spin_unlock_irqrestore(&xfer->lock, flags);
+ if (done)
+ wa_xfer_completion(xfer);
+ if (rpipe_ready)
+ wa_xfer_delayed_run(rpipe);
+ }
+
return;
error_bad_seg:
@@ -1644,8 +1723,7 @@ static void wa_xfer_result_cb(struct urb *urb)
break;
}
usb_status = xfer_result->bTransferStatus & 0x3f;
- if (usb_status == WA_XFER_STATUS_ABORTED
- || usb_status == WA_XFER_STATUS_NOT_FOUND)
+ if (usb_status == WA_XFER_STATUS_NOT_FOUND)
/* taken care of already */
break;
xfer_id = xfer_result->dwTransferID;
diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c
index 520673109a7..b7d4f6b75ee 100644
--- a/drivers/uwb/drp-ie.c
+++ b/drivers/uwb/drp-ie.c
@@ -27,7 +27,7 @@
/*
* Return the reason code for a reservations's DRP IE.
*/
-int uwb_rsv_reason_code(struct uwb_rsv *rsv)
+static int uwb_rsv_reason_code(struct uwb_rsv *rsv)
{
static const int reason_codes[] = {
[UWB_RSV_STATE_O_INITIATED] = UWB_DRP_REASON_ACCEPTED,
@@ -55,7 +55,7 @@ int uwb_rsv_reason_code(struct uwb_rsv *rsv)
/*
* Return the reason code for a reservations's companion DRP IE .
*/
-int uwb_rsv_companion_reason_code(struct uwb_rsv *rsv)
+static int uwb_rsv_companion_reason_code(struct uwb_rsv *rsv)
{
static const int companion_reason_codes[] = {
[UWB_RSV_STATE_O_MOVE_EXPANDING] = UWB_DRP_REASON_ACCEPTED,
diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c
index 0621abef9b4..0257f35cfb9 100644
--- a/drivers/uwb/hwa-rc.c
+++ b/drivers/uwb/hwa-rc.c
@@ -611,7 +611,16 @@ static
int hwarc_reset(struct uwb_rc *uwb_rc)
{
struct hwarc *hwarc = uwb_rc->priv;
- return usb_reset_device(hwarc->usb_dev);
+ int result;
+
+ /* device lock must be held when calling usb_reset_device. */
+ result = usb_lock_device_for_reset(hwarc->usb_dev, NULL);
+ if (result >= 0) {
+ result = usb_reset_device(hwarc->usb_dev);
+ usb_unlock_device(hwarc->usb_dev);
+ }
+
+ return result;
}
/**
@@ -709,8 +718,10 @@ static int hwarc_neep_init(struct uwb_rc *rc)
error_neep_submit:
usb_free_urb(hwarc->neep_urb);
+ hwarc->neep_urb = NULL;
error_urb_alloc:
free_page((unsigned long)hwarc->rd_buffer);
+ hwarc->rd_buffer = NULL;
error_rd_buffer:
return -ENOMEM;
}
@@ -723,7 +734,10 @@ static void hwarc_neep_release(struct uwb_rc *rc)
usb_kill_urb(hwarc->neep_urb);
usb_free_urb(hwarc->neep_urb);
+ hwarc->neep_urb = NULL;
+
free_page((unsigned long)hwarc->rd_buffer);
+ hwarc->rd_buffer = NULL;
}
/**
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c
index 690577d2a35..c1304b8d498 100644
--- a/drivers/uwb/pal.c
+++ b/drivers/uwb/pal.c
@@ -68,8 +68,40 @@ int uwb_pal_register(struct uwb_pal *pal)
}
EXPORT_SYMBOL_GPL(uwb_pal_register);
+static int find_rc(struct device *dev, const void *data)
+{
+ const struct uwb_rc *target_rc = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc == NULL) {
+ WARN_ON(1);
+ return 0;
+ }
+ if (rc == target_rc) {
+ if (rc->ready == 0)
+ return 0;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Given a radio controller descriptor see if it is registered.
+ *
+ * @returns false if the rc does not exist or is quiescing; true otherwise.
+ */
+static bool uwb_rc_class_device_exists(struct uwb_rc *target_rc)
+{
+ struct device *dev;
+
+ dev = class_find_device(&uwb_rc_class, NULL, target_rc, find_rc);
+
+ return (dev != NULL);
+}
+
/**
- * uwb_pal_register - unregister a UWB PAL
+ * uwb_pal_unregister - unregister a UWB PAL
* @pal: the PAL
*/
void uwb_pal_unregister(struct uwb_pal *pal)
@@ -85,7 +117,11 @@ void uwb_pal_unregister(struct uwb_pal *pal)
debugfs_remove(pal->debugfs_dir);
if (pal->device) {
- sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
+ /* remove link to the PAL in the UWB device's directory. */
+ if (uwb_rc_class_device_exists(rc))
+ sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
+
+ /* remove link to uwb_rc in the PAL device's directory. */
sysfs_remove_link(&pal->device->kobj, "uwb_rc");
}
}
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index c5179e269df..cef6002acbd 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -137,8 +137,27 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
*/
pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
- if (vdev->reset_works)
- __pci_reset_function(pdev);
+ /*
+ * Careful, device_lock may already be held. This is the case if
+ * a driver unbind is blocked. Try to get the locks ourselves to
+ * prevent a deadlock.
+ */
+ if (vdev->reset_works) {
+ bool reset_done = false;
+
+ if (pci_cfg_access_trylock(pdev)) {
+ if (device_trylock(&pdev->dev)) {
+ __pci_reset_function_locked(pdev);
+ reset_done = true;
+ device_unlock(&pdev->dev);
+ }
+ pci_cfg_access_unlock(pdev);
+ }
+
+ if (!reset_done)
+ pr_warn("%s: Unable to acquire locks for reset of %s\n",
+ __func__, dev_name(&pdev->dev));
+ }
pci_restore_state(pdev);
}
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index c488da5db7c..842f4507883 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -494,27 +494,6 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev)
return 0;
}
-static int vfio_group_nb_del_dev(struct vfio_group *group, struct device *dev)
-{
- struct vfio_device *device;
-
- /*
- * Expect to fall out here. If a device was in use, it would
- * have been bound to a vfio sub-driver, which would have blocked
- * in .remove at vfio_del_group_dev. Sanity check that we no
- * longer track the device, so it's safe to remove.
- */
- device = vfio_group_get_device(group, dev);
- if (likely(!device))
- return 0;
-
- WARN("Device %s removed from live group %d!\n", dev_name(dev),
- iommu_group_id(group->iommu_group));
-
- vfio_device_put(device);
- return 0;
-}
-
static int vfio_group_nb_verify(struct vfio_group *group, struct device *dev)
{
/* We don't care what happens when the group isn't in use */
@@ -531,13 +510,11 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
struct device *dev = data;
/*
- * Need to go through a group_lock lookup to get a reference or
- * we risk racing a group being removed. Leave a WARN_ON for
- * debuging, but if the group no longer exists, a spurious notify
- * is harmless.
+ * Need to go through a group_lock lookup to get a reference or we
+ * risk racing a group being removed. Ignore spurious notifies.
*/
group = vfio_group_try_get(group);
- if (WARN_ON(!group))
+ if (!group)
return NOTIFY_OK;
switch (action) {
@@ -545,7 +522,13 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
vfio_group_nb_add_dev(group, dev);
break;
case IOMMU_GROUP_NOTIFY_DEL_DEVICE:
- vfio_group_nb_del_dev(group, dev);
+ /*
+ * Nothing to do here. If the device is in use, then the
+ * vfio sub-driver should block the remove callback until
+ * it is unused. If the device is unused or attached to a
+ * stub driver, then it should be released and we don't
+ * care that it will be going away.
+ */
break;
case IOMMU_GROUP_NOTIFY_BIND_DRIVER:
pr_debug("%s: Device %s, group %d binding to driver\n",
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 027be91db13..969a85960e9 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -15,7 +15,6 @@
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
-#include <linux/rcupdate.h>
#include <linux/file.h>
#include <linux/slab.h>
@@ -346,12 +345,11 @@ static void handle_tx(struct vhost_net *net)
struct vhost_net_ubuf_ref *uninitialized_var(ubufs);
bool zcopy, zcopy_used;
- /* TODO: check that we are running from vhost_worker? */
- sock = rcu_dereference_check(vq->private_data, 1);
+ mutex_lock(&vq->mutex);
+ sock = vq->private_data;
if (!sock)
- return;
+ goto out;
- mutex_lock(&vq->mutex);
vhost_disable_notify(&net->dev, vq);
hdr_size = nvq->vhost_hlen;
@@ -461,7 +459,7 @@ static void handle_tx(struct vhost_net *net)
break;
}
}
-
+out:
mutex_unlock(&vq->mutex);
}
@@ -570,14 +568,14 @@ static void handle_rx(struct vhost_net *net)
s16 headcount;
size_t vhost_hlen, sock_hlen;
size_t vhost_len, sock_len;
- /* TODO: check that we are running from vhost_worker? */
- struct socket *sock = rcu_dereference_check(vq->private_data, 1);
-
- if (!sock)
- return;
+ struct socket *sock;
mutex_lock(&vq->mutex);
+ sock = vq->private_data;
+ if (!sock)
+ goto out;
vhost_disable_notify(&net->dev, vq);
+
vhost_hlen = nvq->vhost_hlen;
sock_hlen = nvq->sock_hlen;
@@ -652,7 +650,7 @@ static void handle_rx(struct vhost_net *net)
break;
}
}
-
+out:
mutex_unlock(&vq->mutex);
}
@@ -750,8 +748,7 @@ static int vhost_net_enable_vq(struct vhost_net *n,
struct vhost_poll *poll = n->poll + (nvq - n->vqs);
struct socket *sock;
- sock = rcu_dereference_protected(vq->private_data,
- lockdep_is_held(&vq->mutex));
+ sock = vq->private_data;
if (!sock)
return 0;
@@ -764,10 +761,9 @@ static struct socket *vhost_net_stop_vq(struct vhost_net *n,
struct socket *sock;
mutex_lock(&vq->mutex);
- sock = rcu_dereference_protected(vq->private_data,
- lockdep_is_held(&vq->mutex));
+ sock = vq->private_data;
vhost_net_disable_vq(n, vq);
- rcu_assign_pointer(vq->private_data, NULL);
+ vq->private_data = NULL;
mutex_unlock(&vq->mutex);
return sock;
}
@@ -923,8 +919,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
}
/* start polling new socket */
- oldsock = rcu_dereference_protected(vq->private_data,
- lockdep_is_held(&vq->mutex));
+ oldsock = vq->private_data;
if (sock != oldsock) {
ubufs = vhost_net_ubuf_alloc(vq,
sock && vhost_sock_zcopy(sock));
@@ -934,7 +929,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
}
vhost_net_disable_vq(n, vq);
- rcu_assign_pointer(vq->private_data, sock);
+ vq->private_data = sock;
r = vhost_init_used(vq);
if (r)
goto err_used;
@@ -968,7 +963,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
return 0;
err_used:
- rcu_assign_pointer(vq->private_data, oldsock);
+ vq->private_data = oldsock;
vhost_net_enable_vq(n, vq);
if (ubufs)
vhost_net_ubuf_put_wait_and_free(ubufs);
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index 06adf31a924..0c27c7df1b0 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -902,19 +902,15 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
int head, ret;
u8 target;
+ mutex_lock(&vq->mutex);
/*
* We can handle the vq only after the endpoint is setup by calling the
* VHOST_SCSI_SET_ENDPOINT ioctl.
- *
- * TODO: Check that we are running from vhost_worker which acts
- * as read-side critical section for vhost kind of RCU.
- * See the comments in struct vhost_virtqueue in drivers/vhost/vhost.h
*/
- vs_tpg = rcu_dereference_check(vq->private_data, 1);
+ vs_tpg = vq->private_data;
if (!vs_tpg)
- return;
+ goto out;
- mutex_lock(&vq->mutex);
vhost_disable_notify(&vs->dev, vq);
for (;;) {
@@ -1064,6 +1060,7 @@ err_free:
vhost_scsi_free_cmd(cmd);
err_cmd:
vhost_scsi_send_bad_target(vs, vq, head, out);
+out:
mutex_unlock(&vq->mutex);
}
@@ -1232,9 +1229,8 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs,
sizeof(vs->vs_vhost_wwpn));
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
vq = &vs->vqs[i].vq;
- /* Flushing the vhost_work acts as synchronize_rcu */
mutex_lock(&vq->mutex);
- rcu_assign_pointer(vq->private_data, vs_tpg);
+ vq->private_data = vs_tpg;
vhost_init_used(vq);
mutex_unlock(&vq->mutex);
}
@@ -1313,9 +1309,8 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
if (match) {
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
vq = &vs->vqs[i].vq;
- /* Flushing the vhost_work acts as synchronize_rcu */
mutex_lock(&vq->mutex);
- rcu_assign_pointer(vq->private_data, NULL);
+ vq->private_data = NULL;
mutex_unlock(&vq->mutex);
}
}
diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c
index a73ea217f24..339eae85859 100644
--- a/drivers/vhost/test.c
+++ b/drivers/vhost/test.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
-#include <linux/rcupdate.h>
#include <linux/file.h>
#include <linux/slab.h>
@@ -200,9 +199,8 @@ static long vhost_test_run(struct vhost_test *n, int test)
priv = test ? n : NULL;
/* start polling new socket */
- oldpriv = rcu_dereference_protected(vq->private_data,
- lockdep_is_held(&vq->mutex));
- rcu_assign_pointer(vq->private_data, priv);
+ oldpriv = vq->private_data;
+ vq->private_data = priv;
r = vhost_init_used(&n->vqs[index]);
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 42298cd23c7..4465ed5f316 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -103,14 +103,8 @@ struct vhost_virtqueue {
struct iovec iov[UIO_MAXIOV];
struct iovec *indirect;
struct vring_used_elem *heads;
- /* We use a kind of RCU to access private pointer.
- * All readers access it from worker, which makes it possible to
- * flush the vhost_work instead of synchronize_rcu. Therefore readers do
- * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
- * vhost_work execution acts instead of rcu_read_lock() and the end of
- * vhost_work execution acts instead of rcu_read_unlock().
- * Writers use virtqueue mutex. */
- void __rcu *private_data;
+ /* Protected by virtqueue mutex. */
+ void *private_data;
/* Log write descriptors */
void __user *log_base;
struct vhost_log *log;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index a89c15de9f4..9b0f12c5c28 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -435,8 +435,8 @@ static int correct_chipset(struct atyfb_par *par)
const char *name;
int i;
- for (i = ARRAY_SIZE(aty_chips); i > 0; i--)
- if (par->pci_id == aty_chips[i - 1].pci_id)
+ for (i = (int)ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
+ if (par->pci_id == aty_chips[i].pci_id)
break;
if (i < 0)
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 3fccb6d3c8c..94a403a9717 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -103,16 +103,16 @@ static void backlight_generate_event(struct backlight_device *bd,
sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness");
}
-static ssize_t backlight_show_power(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t bl_power_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.power);
}
-static ssize_t backlight_store_power(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t bl_power_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
int rc;
struct backlight_device *bd = to_backlight_device(dev);
@@ -136,8 +136,9 @@ static ssize_t backlight_store_power(struct device *dev,
return rc;
}
+static DEVICE_ATTR_RW(bl_power);
-static ssize_t backlight_show_brightness(struct device *dev,
+static ssize_t brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct backlight_device *bd = to_backlight_device(dev);
@@ -145,7 +146,7 @@ static ssize_t backlight_show_brightness(struct device *dev,
return sprintf(buf, "%d\n", bd->props.brightness);
}
-static ssize_t backlight_store_brightness(struct device *dev,
+static ssize_t brightness_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
@@ -175,24 +176,27 @@ static ssize_t backlight_store_brightness(struct device *dev,
return rc;
}
+static DEVICE_ATTR_RW(brightness);
-static ssize_t backlight_show_type(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%s\n", backlight_types[bd->props.type]);
}
+static DEVICE_ATTR_RO(type);
-static ssize_t backlight_show_max_brightness(struct device *dev,
+static ssize_t max_brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.max_brightness);
}
+static DEVICE_ATTR_RO(max_brightness);
-static ssize_t backlight_show_actual_brightness(struct device *dev,
+static ssize_t actual_brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int rc = -ENXIO;
@@ -205,6 +209,7 @@ static ssize_t backlight_show_actual_brightness(struct device *dev,
return rc;
}
+static DEVICE_ATTR_RO(actual_brightness);
static struct class *backlight_class;
@@ -247,16 +252,15 @@ static void bl_device_release(struct device *dev)
kfree(bd);
}
-static struct device_attribute bl_device_attributes[] = {
- __ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
- __ATTR(brightness, 0644, backlight_show_brightness,
- backlight_store_brightness),
- __ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
- NULL),
- __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
- __ATTR(type, 0444, backlight_show_type, NULL),
- __ATTR_NULL,
+static struct attribute *bl_device_attrs[] = {
+ &dev_attr_bl_power.attr,
+ &dev_attr_brightness.attr,
+ &dev_attr_actual_brightness.attr,
+ &dev_attr_max_brightness.attr,
+ &dev_attr_type.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(bl_device);
/**
* backlight_force_update - tell the backlight subsystem that hardware state
@@ -493,7 +497,7 @@ static int __init backlight_class_init(void)
return PTR_ERR(backlight_class);
}
- backlight_class->dev_attrs = bl_device_attributes;
+ backlight_class->dev_groups = bl_device_groups;
backlight_class->pm = &backlight_class_dev_pm_ops;
return 0;
}
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 41964a71a03..93cf15efc71 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -89,7 +89,7 @@ static inline void lcd_unregister_fb(struct lcd_device *ld)
}
#endif /* CONFIG_FB */
-static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr,
+static ssize_t lcd_power_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int rc;
@@ -105,7 +105,7 @@ static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr,
return rc;
}
-static ssize_t lcd_store_power(struct device *dev,
+static ssize_t lcd_power_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
@@ -128,8 +128,9 @@ static ssize_t lcd_store_power(struct device *dev,
return rc;
}
+static DEVICE_ATTR_RW(lcd_power);
-static ssize_t lcd_show_contrast(struct device *dev,
+static ssize_t contrast_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int rc = -ENXIO;
@@ -143,7 +144,7 @@ static ssize_t lcd_show_contrast(struct device *dev,
return rc;
}
-static ssize_t lcd_store_contrast(struct device *dev,
+static ssize_t contrast_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
@@ -166,14 +167,16 @@ static ssize_t lcd_store_contrast(struct device *dev,
return rc;
}
+static DEVICE_ATTR_RW(contrast);
-static ssize_t lcd_show_max_contrast(struct device *dev,
+static ssize_t max_contrast_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lcd_device *ld = to_lcd_device(dev);
return sprintf(buf, "%d\n", ld->props.max_contrast);
}
+static DEVICE_ATTR_RO(max_contrast);
static struct class *lcd_class;
@@ -183,12 +186,13 @@ static void lcd_device_release(struct device *dev)
kfree(ld);
}
-static struct device_attribute lcd_device_attributes[] = {
- __ATTR(lcd_power, 0644, lcd_show_power, lcd_store_power),
- __ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
- __ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
- __ATTR_NULL,
+static struct attribute *lcd_device_attrs[] = {
+ &dev_attr_lcd_power.attr,
+ &dev_attr_contrast.attr,
+ &dev_attr_max_contrast.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(lcd_device);
/**
* lcd_device_register - register a new object of lcd_device class.
@@ -344,7 +348,7 @@ static int __init lcd_class_init(void)
return PTR_ERR(lcd_class);
}
- lcd_class->dev_attrs = lcd_device_attributes;
+ lcd_class->dev_groups = lcd_device_groups;
return 0;
}
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
index 5ca11b066b7..886e797f75f 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -101,33 +101,37 @@ static const struct backlight_ops max8925_backlight_ops = {
.get_brightness = max8925_backlight_get_brightness,
};
-#ifdef CONFIG_OF
-static int max8925_backlight_dt_init(struct platform_device *pdev,
- struct max8925_backlight_pdata *pdata)
+static void max8925_backlight_dt_init(struct platform_device *pdev)
{
struct device_node *nproot = pdev->dev.parent->of_node, *np;
- int dual_string;
+ struct max8925_backlight_pdata *pdata;
+ u32 val;
+
+ if (!nproot || !IS_ENABLED(CONFIG_OF))
+ return;
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct max8925_backlight_pdata),
+ GFP_KERNEL);
+ if (!pdata)
+ return;
- if (!nproot)
- return -ENODEV;
np = of_find_node_by_name(nproot, "backlight");
if (!np) {
dev_err(&pdev->dev, "failed to find backlight node\n");
- return -ENODEV;
+ return;
}
- of_property_read_u32(np, "maxim,max8925-dual-string", &dual_string);
- pdata->dual_string = dual_string;
- return 0;
+ if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val))
+ pdata->dual_string = val;
+
+ pdev->dev.platform_data = pdata;
}
-#else
-#define max8925_backlight_dt_init(x, y) (-1)
-#endif
static int max8925_backlight_probe(struct platform_device *pdev)
{
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
- struct max8925_backlight_pdata *pdata = pdev->dev.platform_data;
+ struct max8925_backlight_pdata *pdata;
struct max8925_backlight_data *data;
struct backlight_device *bl;
struct backlight_properties props;
@@ -170,13 +174,10 @@ static int max8925_backlight_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, bl);
value = 0;
- if (pdev->dev.parent->of_node && !pdata) {
- pdata = devm_kzalloc(&pdev->dev,
- sizeof(struct max8925_backlight_pdata),
- GFP_KERNEL);
- max8925_backlight_dt_init(pdev, pdata);
- }
+ if (!pdev->dev.platform_data)
+ max8925_backlight_dt_init(pdev);
+ pdata = pdev->dev.platform_data;
if (pdata) {
if (pdata->lxw_scl)
value |= (1 << 7);
diff --git a/drivers/video/hyperv_fb.c b/drivers/video/hyperv_fb.c
index d4d2c5fe248..8ac99b87c07 100644
--- a/drivers/video/hyperv_fb.c
+++ b/drivers/video/hyperv_fb.c
@@ -825,5 +825,4 @@ module_init(hvfb_drv_init);
module_exit(hvfb_drv_exit);
MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Video Frame Buffer Driver");
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 3ba37713b1f..dc09ebe4aba 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -239,24 +239,6 @@ static const struct fb_bitfield def_rgb565[] = {
}
};
-static const struct fb_bitfield def_rgb666[] = {
- [RED] = {
- .offset = 16,
- .length = 6,
- },
- [GREEN] = {
- .offset = 8,
- .length = 6,
- },
- [BLUE] = {
- .offset = 0,
- .length = 6,
- },
- [TRANSP] = { /* no support for transparency */
- .length = 0,
- }
-};
-
static const struct fb_bitfield def_rgb888[] = {
[RED] = {
.offset = 16,
@@ -309,9 +291,6 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var,
break;
case STMLCDIF_16BIT:
case STMLCDIF_18BIT:
- /* 24 bit to 18 bit mapping */
- rgb = def_rgb666;
- break;
case STMLCDIF_24BIT:
/* real 24 bit */
rgb = def_rgb888;
@@ -453,11 +432,6 @@ static int mxsfb_set_par(struct fb_info *fb_info)
return -EINVAL;
case STMLCDIF_16BIT:
case STMLCDIF_18BIT:
- /* 24 bit to 18 bit mapping */
- ctrl |= CTRL_DF24; /* ignore the upper 2 bits in
- * each colour component
- */
- break;
case STMLCDIF_24BIT:
/* real 24 bit */
break;
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c
index 8c527e5b293..796e5112cee 100644
--- a/drivers/video/nuc900fb.c
+++ b/drivers/video/nuc900fb.c
@@ -587,8 +587,7 @@ static int nuc900fb_probe(struct platform_device *pdev)
fbinfo->flags = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &fbi->pseudo_pal;
- ret = request_irq(irq, nuc900fb_irqhandler, 0,
- pdev->name, fbinfo);
+ ret = request_irq(irq, nuc900fb_irqhandler, 0, pdev->name, fbi);
if (ret) {
dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
irq, ret);
diff --git a/drivers/video/omap2/displays-new/connector-analog-tv.c b/drivers/video/omap2/displays-new/connector-analog-tv.c
index 5338f362293..1b60698f141 100644
--- a/drivers/video/omap2/displays-new/connector-analog-tv.c
+++ b/drivers/video/omap2/displays-new/connector-analog-tv.c
@@ -28,6 +28,20 @@ struct panel_drv_data {
bool invert_polarity;
};
+static const struct omap_video_timings tvc_pal_timings = {
+ .x_res = 720,
+ .y_res = 574,
+ .pixel_clock = 13500,
+ .hsw = 64,
+ .hfp = 12,
+ .hbp = 68,
+ .vsw = 5,
+ .vfp = 5,
+ .vbp = 41,
+
+ .interlace = true,
+};
+
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
static int tvc_connect(struct omap_dss_device *dssdev)
@@ -212,14 +226,14 @@ static int tvc_probe(struct platform_device *pdev)
return -ENODEV;
}
- ddata->timings = omap_dss_pal_timings;
+ ddata->timings = tvc_pal_timings;
dssdev = &ddata->dssdev;
dssdev->driver = &tvc_driver;
dssdev->dev = &pdev->dev;
dssdev->type = OMAP_DISPLAY_TYPE_VENC;
dssdev->owner = THIS_MODULE;
- dssdev->panel.timings = omap_dss_pal_timings;
+ dssdev->panel.timings = tvc_pal_timings;
r = omapdss_register_display(dssdev);
if (r) {
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index b2a8912f643..a9ac3ce2d0e 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -713,7 +713,7 @@ static int sgivwfb_mmap(struct fb_info *info,
r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size);
printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
- offset, vma->vm_start);
+ sgivwfb_mem_phys + (vma->vm_pgoff << PAGE_SHIFT), vma->vm_start);
return r;
}
diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c
index a8c6c43a465..1265b25f9f9 100644
--- a/drivers/video/sh7760fb.c
+++ b/drivers/video/sh7760fb.c
@@ -567,7 +567,7 @@ static int sh7760fb_remove(struct platform_device *dev)
fb_dealloc_cmap(&info->cmap);
sh7760fb_free_mem(info);
if (par->irq >= 0)
- free_irq(par->irq, par);
+ free_irq(par->irq, &par->vsync);
iounmap(par->base);
release_mem_region(par->ioarea->start, resource_size(par->ioarea));
framebuffer_release(info);
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 830ded45fd4..2827333703d 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -1265,7 +1265,6 @@ static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image
static void vga16fb_destroy(struct fb_info *info)
{
- struct platform_device *dev = container_of(info->device, struct platform_device, dev);
iounmap(info->screen_base);
fb_dealloc_cmap(&info->cmap);
/* XXX unshare VGA regions */
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index f3d4a69e1e4..6629b29a820 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -341,8 +341,8 @@ static int xilinxfb_assign(struct platform_device *pdev,
if (drvdata->flags & BUS_ACCESS_FLAG) {
/* Put a banner in the log (for DEBUG) */
- dev_dbg(dev, "regs: phys=%x, virt=%p\n", drvdata->regs_phys,
- drvdata->regs);
+ dev_dbg(dev, "regs: phys=%pa, virt=%p\n",
+ &drvdata->regs_phys, drvdata->regs);
}
/* Put a banner in the log (for DEBUG) */
dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n",
diff --git a/drivers/vme/boards/vme_vmivme7805.c b/drivers/vme/boards/vme_vmivme7805.c
index dd22b5072e2..cf74aee2cef 100644
--- a/drivers/vme/boards/vme_vmivme7805.c
+++ b/drivers/vme/boards/vme_vmivme7805.c
@@ -23,7 +23,7 @@ static int vmic_probe(struct pci_dev *, const struct pci_device_id *);
static void vmic_remove(struct pci_dev *);
/** Base address to access FPGA register */
-static void *vmic_base;
+static void __iomem *vmic_base;
static const char driver_name[] = "vmivme_7805";
diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c
index 64bfea31442..f8448573d03 100644
--- a/drivers/vme/bridges/vme_ca91cx42.c
+++ b/drivers/vme/bridges/vme_ca91cx42.c
@@ -243,6 +243,8 @@ static int ca91cx42_irq_init(struct vme_bridge *ca91cx42_bridge)
static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge,
struct pci_dev *pdev)
{
+ struct vme_bridge *ca91cx42_bridge;
+
/* Disable interrupts from PCI to VME */
iowrite32(0, bridge->base + VINT_EN);
@@ -251,7 +253,9 @@ static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge,
/* Clear Any Pending PCI Interrupts */
iowrite32(0x00FFFFFF, bridge->base + LINT_STAT);
- free_irq(pdev->irq, pdev);
+ ca91cx42_bridge = container_of((void *)bridge, struct vme_bridge,
+ driver_priv);
+ free_irq(pdev->irq, ca91cx42_bridge);
}
static int ca91cx42_iack_received(struct ca91cx42_driver *bridge, int level)
@@ -856,7 +860,7 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
void *buf, size_t count, loff_t offset)
{
ssize_t retval;
- void *addr = image->kern_base + offset;
+ void __iomem *addr = image->kern_base + offset;
unsigned int done = 0;
unsigned int count32;
@@ -916,7 +920,7 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
void *buf, size_t count, loff_t offset)
{
ssize_t retval;
- void *addr = image->kern_base + offset;
+ void __iomem *addr = image->kern_base + offset;
unsigned int done = 0;
unsigned int count32;
diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c
index 94c892f27be..9cf88337e4e 100644
--- a/drivers/vme/bridges/vme_tsi148.c
+++ b/drivers/vme/bridges/vme_tsi148.c
@@ -1267,7 +1267,7 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
u32 aspace, cycle, dwidth;
struct vme_bus_error *vme_err = NULL;
struct vme_bridge *tsi148_bridge;
- void *addr = image->kern_base + offset;
+ void __iomem *addr = image->kern_base + offset;
unsigned int done = 0;
unsigned int count32;
@@ -1348,7 +1348,7 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
int retval = 0, enabled;
unsigned long long vme_base, size;
u32 aspace, cycle, dwidth;
- void *addr = image->kern_base + offset;
+ void __iomem *addr = image->kern_base + offset;
unsigned int done = 0;
unsigned int count32;
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
index cb8a8e5d957..7dfa0e11688 100644
--- a/drivers/w1/slaves/w1_ds2408.c
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -72,10 +72,9 @@ static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
return 1;
}
-static ssize_t w1_f29_read_state(
- struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t state_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off,
+ size_t count)
{
dev_dbg(&kobj_to_w1_slave(kobj)->dev,
"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
@@ -85,10 +84,9 @@ static ssize_t w1_f29_read_state(
return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf);
}
-static ssize_t w1_f29_read_output(
- struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t output_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
dev_dbg(&kobj_to_w1_slave(kobj)->dev,
"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
@@ -99,10 +97,9 @@ static ssize_t w1_f29_read_output(
W1_F29_REG_OUTPUT_LATCH_STATE, buf);
}
-static ssize_t w1_f29_read_activity(
- struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t activity_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
dev_dbg(&kobj_to_w1_slave(kobj)->dev,
"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
@@ -113,10 +110,9 @@ static ssize_t w1_f29_read_activity(
W1_F29_REG_ACTIVITY_LATCH_STATE, buf);
}
-static ssize_t w1_f29_read_cond_search_mask(
- struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
dev_dbg(&kobj_to_w1_slave(kobj)->dev,
"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
@@ -127,10 +123,10 @@ static ssize_t w1_f29_read_cond_search_mask(
W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);
}
-static ssize_t w1_f29_read_cond_search_polarity(
- struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t cond_search_polarity_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
if (count != 1 || off != 0)
return -EFAULT;
@@ -138,10 +134,9 @@ static ssize_t w1_f29_read_cond_search_polarity(
W1_F29_REG_COND_SEARCH_POL_SELECT, buf);
}
-static ssize_t w1_f29_read_status_control(
- struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t status_control_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
if (count != 1 || off != 0)
return -EFAULT;
@@ -149,13 +144,9 @@ static ssize_t w1_f29_read_status_control(
W1_F29_REG_CONTROL_AND_STATUS, buf);
}
-
-
-
-static ssize_t w1_f29_write_output(
- struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t output_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
u8 w1_buf[3];
@@ -224,10 +215,9 @@ error:
/**
* Writing to the activity file resets the activity latches.
*/
-static ssize_t w1_f29_write_activity(
- struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t activity_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
unsigned int retries = W1_F29_RETRIES;
@@ -255,13 +245,9 @@ error:
return -EIO;
}
-static ssize_t w1_f29_write_status_control(
- struct file *filp,
- struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf,
- loff_t off,
- size_t count)
+static ssize_t status_control_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
u8 w1_buf[4];
@@ -330,91 +316,35 @@ out:
return res;
}
-static struct bin_attribute w1_f29_sysfs_bin_files[] = {
- {
- .attr = {
- .name = "state",
- .mode = S_IRUGO,
- },
- .size = 1,
- .read = w1_f29_read_state,
- },
- {
- .attr = {
- .name = "output",
- .mode = S_IRUGO | S_IWUSR | S_IWGRP,
- },
- .size = 1,
- .read = w1_f29_read_output,
- .write = w1_f29_write_output,
- },
- {
- .attr = {
- .name = "activity",
- .mode = S_IRUGO,
- },
- .size = 1,
- .read = w1_f29_read_activity,
- .write = w1_f29_write_activity,
- },
- {
- .attr = {
- .name = "cond_search_mask",
- .mode = S_IRUGO,
- },
- .size = 1,
- .read = w1_f29_read_cond_search_mask,
- },
- {
- .attr = {
- .name = "cond_search_polarity",
- .mode = S_IRUGO,
- },
- .size = 1,
- .read = w1_f29_read_cond_search_polarity,
- },
- {
- .attr = {
- .name = "status_control",
- .mode = S_IRUGO | S_IWUSR | S_IWGRP,
- },
- .size = 1,
- .read = w1_f29_read_status_control,
- .write = w1_f29_write_status_control,
- }
+static BIN_ATTR_RO(state, 1);
+static BIN_ATTR_RW(output, 1);
+static BIN_ATTR_RW(activity, 1);
+static BIN_ATTR_RO(cond_search_mask, 1);
+static BIN_ATTR_RO(cond_search_polarity, 1);
+static BIN_ATTR_RW(status_control, 1);
+
+static struct bin_attribute *w1_f29_bin_attrs[] = {
+ &bin_attr_state,
+ &bin_attr_output,
+ &bin_attr_activity,
+ &bin_attr_cond_search_mask,
+ &bin_attr_cond_search_polarity,
+ &bin_attr_status_control,
+ NULL,
};
-static int w1_f29_add_slave(struct w1_slave *sl)
-{
- int err = 0;
- int i;
-
- err = w1_f29_disable_test_mode(sl);
- if (err)
- return err;
-
- for (i = 0; i < ARRAY_SIZE(w1_f29_sysfs_bin_files) && !err; ++i)
- err = sysfs_create_bin_file(
- &sl->dev.kobj,
- &(w1_f29_sysfs_bin_files[i]));
- if (err)
- while (--i >= 0)
- sysfs_remove_bin_file(&sl->dev.kobj,
- &(w1_f29_sysfs_bin_files[i]));
- return err;
-}
+static const struct attribute_group w1_f29_group = {
+ .bin_attrs = w1_f29_bin_attrs,
+};
-static void w1_f29_remove_slave(struct w1_slave *sl)
-{
- int i;
- for (i = ARRAY_SIZE(w1_f29_sysfs_bin_files) - 1; i >= 0; --i)
- sysfs_remove_bin_file(&sl->dev.kobj,
- &(w1_f29_sysfs_bin_files[i]));
-}
+static const struct attribute_group *w1_f29_groups[] = {
+ &w1_f29_group,
+ NULL,
+};
static struct w1_family_ops w1_f29_fops = {
- .add_slave = w1_f29_add_slave,
- .remove_slave = w1_f29_remove_slave,
+ .add_slave = w1_f29_disable_test_mode,
+ .groups = w1_f29_groups,
};
static struct w1_family w1_family_29 = {
diff --git a/drivers/w1/slaves/w1_ds2413.c b/drivers/w1/slaves/w1_ds2413.c
index 85937773a96..ee28fc1ff39 100644
--- a/drivers/w1/slaves/w1_ds2413.c
+++ b/drivers/w1/slaves/w1_ds2413.c
@@ -30,10 +30,9 @@ MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2413));
#define W1_F3A_FUNC_PIO_ACCESS_WRITE 0x5A
#define W1_F3A_SUCCESS_CONFIRM_BYTE 0xAA
-static ssize_t w1_f3a_read_state(
- struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t state_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off,
+ size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
dev_dbg(&sl->dev,
@@ -66,10 +65,11 @@ static ssize_t w1_f3a_read_state(
return 1;
}
-static ssize_t w1_f3a_write_output(
- struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static BIN_ATTR_RO(state, 1);
+
+static ssize_t output_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
u8 w1_buf[3];
@@ -110,53 +110,25 @@ error:
return -EIO;
}
-#define NB_SYSFS_BIN_FILES 2
-static struct bin_attribute w1_f3a_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
- {
- .attr = {
- .name = "state",
- .mode = S_IRUGO,
- },
- .size = 1,
- .read = w1_f3a_read_state,
- },
- {
- .attr = {
- .name = "output",
- .mode = S_IRUGO | S_IWUSR | S_IWGRP,
- },
- .size = 1,
- .write = w1_f3a_write_output,
- }
+static BIN_ATTR(output, S_IRUGO | S_IWUSR | S_IWGRP, NULL, output_write, 1);
+
+static struct bin_attribute *w1_f3a_bin_attrs[] = {
+ &bin_attr_state,
+ &bin_attr_output,
+ NULL,
};
-static int w1_f3a_add_slave(struct w1_slave *sl)
-{
- int err = 0;
- int i;
-
- for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
- err = sysfs_create_bin_file(
- &sl->dev.kobj,
- &(w1_f3a_sysfs_bin_files[i]));
- if (err)
- while (--i >= 0)
- sysfs_remove_bin_file(&sl->dev.kobj,
- &(w1_f3a_sysfs_bin_files[i]));
- return err;
-}
+static const struct attribute_group w1_f3a_group = {
+ .bin_attrs = w1_f3a_bin_attrs,
+};
-static void w1_f3a_remove_slave(struct w1_slave *sl)
-{
- int i;
- for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i)
- sysfs_remove_bin_file(&sl->dev.kobj,
- &(w1_f3a_sysfs_bin_files[i]));
-}
+static const struct attribute_group *w1_f3a_groups[] = {
+ &w1_f3a_group,
+ NULL,
+};
static struct w1_family_ops w1_f3a_fops = {
- .add_slave = w1_f3a_add_slave,
- .remove_slave = w1_f3a_remove_slave,
+ .groups = w1_f3a_groups,
};
static struct w1_family w1_family_3a = {
diff --git a/drivers/w1/slaves/w1_ds2423.c b/drivers/w1/slaves/w1_ds2423.c
index 7f86aec7408..7e41b7d91fb 100644
--- a/drivers/w1/slaves/w1_ds2423.c
+++ b/drivers/w1/slaves/w1_ds2423.c
@@ -40,14 +40,8 @@
#define COUNTER_COUNT 4
#define READ_BYTE_COUNT 42
-static ssize_t w1_counter_read(struct device *device,
- struct device_attribute *attr, char *buf);
-
-static struct device_attribute w1_counter_attr =
- __ATTR(w1_slave, S_IRUGO, w1_counter_read, NULL);
-
-static ssize_t w1_counter_read(struct device *device,
- struct device_attribute *attr, char *out_buf)
+static ssize_t w1_slave_show(struct device *device,
+ struct device_attribute *attr, char *out_buf)
{
struct w1_slave *sl = dev_to_w1_slave(device);
struct w1_master *dev = sl->master;
@@ -128,19 +122,16 @@ static ssize_t w1_counter_read(struct device *device,
return PAGE_SIZE - c;
}
-static int w1_f1d_add_slave(struct w1_slave *sl)
-{
- return device_create_file(&sl->dev, &w1_counter_attr);
-}
+static DEVICE_ATTR_RO(w1_slave);
-static void w1_f1d_remove_slave(struct w1_slave *sl)
-{
- device_remove_file(&sl->dev, &w1_counter_attr);
-}
+static struct attribute *w1_f1d_attrs[] = {
+ &dev_attr_w1_slave.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(w1_f1d);
static struct w1_family_ops w1_f1d_fops = {
- .add_slave = w1_f1d_add_slave,
- .remove_slave = w1_f1d_remove_slave,
+ .groups = w1_f1d_groups,
};
static struct w1_family w1_family_1d = {
diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c
index cef8605e43e..9c4ff9d28ad 100644
--- a/drivers/w1/slaves/w1_ds2431.c
+++ b/drivers/w1/slaves/w1_ds2431.c
@@ -96,9 +96,9 @@ static int w1_f2d_readblock(struct w1_slave *sl, int off, int count, char *buf)
return -1;
}
-static ssize_t w1_f2d_read_bin(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
int todo = count;
@@ -202,9 +202,9 @@ retry:
return 0;
}
-static ssize_t w1_f2d_write_bin(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
int addr, len;
@@ -264,29 +264,24 @@ out_up:
return count;
}
-static struct bin_attribute w1_f2d_bin_attr = {
- .attr = {
- .name = "eeprom",
- .mode = S_IRUGO | S_IWUSR,
- },
- .size = W1_F2D_EEPROM_SIZE,
- .read = w1_f2d_read_bin,
- .write = w1_f2d_write_bin,
+static BIN_ATTR_RW(eeprom, W1_F2D_EEPROM_SIZE);
+
+static struct bin_attribute *w1_f2d_bin_attrs[] = {
+ &bin_attr_eeprom,
+ NULL,
};
-static int w1_f2d_add_slave(struct w1_slave *sl)
-{
- return sysfs_create_bin_file(&sl->dev.kobj, &w1_f2d_bin_attr);
-}
+static const struct attribute_group w1_f2d_group = {
+ .bin_attrs = w1_f2d_bin_attrs,
+};
-static void w1_f2d_remove_slave(struct w1_slave *sl)
-{
- sysfs_remove_bin_file(&sl->dev.kobj, &w1_f2d_bin_attr);
-}
+static const struct attribute_group *w1_f2d_groups[] = {
+ &w1_f2d_group,
+ NULL,
+};
static struct w1_family_ops w1_f2d_fops = {
- .add_slave = w1_f2d_add_slave,
- .remove_slave = w1_f2d_remove_slave,
+ .groups = w1_f2d_groups,
};
static struct w1_family w1_family_2d = {
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
index 10cc1b6176e..72319a968a9 100644
--- a/drivers/w1/slaves/w1_ds2433.c
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -93,9 +93,9 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
}
#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
-static ssize_t w1_f23_read_bin(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
@@ -207,9 +207,9 @@ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
return 0;
}
-static ssize_t w1_f23_write_bin(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
int addr, len, idx;
@@ -257,19 +257,24 @@ out_up:
return count;
}
-static struct bin_attribute w1_f23_bin_attr = {
- .attr = {
- .name = "eeprom",
- .mode = S_IRUGO | S_IWUSR,
- },
- .size = W1_EEPROM_SIZE,
- .read = w1_f23_read_bin,
- .write = w1_f23_write_bin,
+static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE);
+
+static struct bin_attribute *w1_f23_bin_attributes[] = {
+ &bin_attr_eeprom,
+ NULL,
+};
+
+static const struct attribute_group w1_f23_group = {
+ .bin_attrs = w1_f23_bin_attributes,
+};
+
+static const struct attribute_group *w1_f23_groups[] = {
+ &w1_f23_group,
+ NULL,
};
static int w1_f23_add_slave(struct w1_slave *sl)
{
- int err;
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
struct w1_f23_data *data;
@@ -279,15 +284,7 @@ static int w1_f23_add_slave(struct w1_slave *sl)
sl->family_data = data;
#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
-
- err = sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
-
-#ifdef CONFIG_W1_SLAVE_DS2433_CRC
- if (err)
- kfree(data);
-#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
-
- return err;
+ return 0;
}
static void w1_f23_remove_slave(struct w1_slave *sl)
@@ -296,12 +293,12 @@ static void w1_f23_remove_slave(struct w1_slave *sl)
kfree(sl->family_data);
sl->family_data = NULL;
#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
- sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
}
static struct w1_family_ops w1_f23_fops = {
.add_slave = w1_f23_add_slave,
.remove_slave = w1_f23_remove_slave,
+ .groups = w1_f23_groups,
};
static struct w1_family w1_family_23 = {
diff --git a/drivers/w1/slaves/w1_ds2760.c b/drivers/w1/slaves/w1_ds2760.c
index 93719d25d84..65f90dccd60 100644
--- a/drivers/w1/slaves/w1_ds2760.c
+++ b/drivers/w1/slaves/w1_ds2760.c
@@ -97,21 +97,28 @@ int w1_ds2760_recall_eeprom(struct device *dev, int addr)
return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_RECALL_DATA);
}
-static ssize_t w1_ds2760_read_bin(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
return w1_ds2760_read(dev, buf, off, count);
}
-static struct bin_attribute w1_ds2760_bin_attr = {
- .attr = {
- .name = "w1_slave",
- .mode = S_IRUGO,
- },
- .size = DS2760_DATA_SIZE,
- .read = w1_ds2760_read_bin,
+static BIN_ATTR_RO(w1_slave, DS2760_DATA_SIZE);
+
+static struct bin_attribute *w1_ds2760_bin_attrs[] = {
+ &bin_attr_w1_slave,
+ NULL,
+};
+
+static const struct attribute_group w1_ds2760_group = {
+ .bin_attrs = w1_ds2760_bin_attrs,
+};
+
+static const struct attribute_group *w1_ds2760_groups[] = {
+ &w1_ds2760_group,
+ NULL,
};
static DEFINE_IDA(bat_ida);
@@ -139,16 +146,10 @@ static int w1_ds2760_add_slave(struct w1_slave *sl)
if (ret)
goto pdev_add_failed;
- ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
- if (ret)
- goto bin_attr_failed;
-
dev_set_drvdata(&sl->dev, pdev);
goto success;
-bin_attr_failed:
- platform_device_del(pdev);
pdev_add_failed:
platform_device_put(pdev);
pdev_alloc_failed:
@@ -165,12 +166,12 @@ static void w1_ds2760_remove_slave(struct w1_slave *sl)
platform_device_unregister(pdev);
ida_simple_remove(&bat_ida, id);
- sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
}
static struct w1_family_ops w1_ds2760_fops = {
.add_slave = w1_ds2760_add_slave,
.remove_slave = w1_ds2760_remove_slave,
+ .groups = w1_ds2760_groups,
};
static struct w1_family w1_ds2760_family = {
diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c
index 0cd7a27b5d6..50e85f7929d 100644
--- a/drivers/w1/slaves/w1_ds2780.c
+++ b/drivers/w1/slaves/w1_ds2780.c
@@ -89,22 +89,28 @@ int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd)
}
EXPORT_SYMBOL(w1_ds2780_eeprom_cmd);
-static ssize_t w1_ds2780_read_bin(struct file *filp,
- struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
return w1_ds2780_io(dev, buf, off, count, 0);
}
-static struct bin_attribute w1_ds2780_bin_attr = {
- .attr = {
- .name = "w1_slave",
- .mode = S_IRUGO,
- },
- .size = DS2780_DATA_SIZE,
- .read = w1_ds2780_read_bin,
+static BIN_ATTR_RO(w1_slave, DS2780_DATA_SIZE);
+
+static struct bin_attribute *w1_ds2780_bin_attrs[] = {
+ &bin_attr_w1_slave,
+ NULL,
+};
+
+static const struct attribute_group w1_ds2780_group = {
+ .bin_attrs = w1_ds2780_bin_attrs,
+};
+
+static const struct attribute_group *w1_ds2780_groups[] = {
+ &w1_ds2780_group,
+ NULL,
};
static DEFINE_IDA(bat_ida);
@@ -132,16 +138,10 @@ static int w1_ds2780_add_slave(struct w1_slave *sl)
if (ret)
goto pdev_add_failed;
- ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2780_bin_attr);
- if (ret)
- goto bin_attr_failed;
-
dev_set_drvdata(&sl->dev, pdev);
return 0;
-bin_attr_failed:
- platform_device_del(pdev);
pdev_add_failed:
platform_device_put(pdev);
pdev_alloc_failed:
@@ -157,12 +157,12 @@ static void w1_ds2780_remove_slave(struct w1_slave *sl)
platform_device_unregister(pdev);
ida_simple_remove(&bat_ida, id);
- sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2780_bin_attr);
}
static struct w1_family_ops w1_ds2780_fops = {
.add_slave = w1_ds2780_add_slave,
.remove_slave = w1_ds2780_remove_slave,
+ .groups = w1_ds2780_groups,
};
static struct w1_family w1_ds2780_family = {
diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c
index 1aba8e41ad4..1eb98fb1688 100644
--- a/drivers/w1/slaves/w1_ds2781.c
+++ b/drivers/w1/slaves/w1_ds2781.c
@@ -87,22 +87,28 @@ int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd)
}
EXPORT_SYMBOL(w1_ds2781_eeprom_cmd);
-static ssize_t w1_ds2781_read_bin(struct file *filp,
- struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
return w1_ds2781_io(dev, buf, off, count, 0);
}
-static struct bin_attribute w1_ds2781_bin_attr = {
- .attr = {
- .name = "w1_slave",
- .mode = S_IRUGO,
- },
- .size = DS2781_DATA_SIZE,
- .read = w1_ds2781_read_bin,
+static BIN_ATTR_RO(w1_slave, DS2781_DATA_SIZE);
+
+static struct bin_attribute *w1_ds2781_bin_attrs[] = {
+ &bin_attr_w1_slave,
+ NULL,
+};
+
+static const struct attribute_group w1_ds2781_group = {
+ .bin_attrs = w1_ds2781_bin_attrs,
+};
+
+static const struct attribute_group *w1_ds2781_groups[] = {
+ &w1_ds2781_group,
+ NULL,
};
static DEFINE_IDA(bat_ida);
@@ -130,16 +136,10 @@ static int w1_ds2781_add_slave(struct w1_slave *sl)
if (ret)
goto pdev_add_failed;
- ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2781_bin_attr);
- if (ret)
- goto bin_attr_failed;
-
dev_set_drvdata(&sl->dev, pdev);
return 0;
-bin_attr_failed:
- platform_device_del(pdev);
pdev_add_failed:
platform_device_put(pdev);
pdev_alloc_failed:
@@ -155,12 +155,12 @@ static void w1_ds2781_remove_slave(struct w1_slave *sl)
platform_device_unregister(pdev);
ida_simple_remove(&bat_ida, id);
- sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2781_bin_attr);
}
static struct w1_family_ops w1_ds2781_fops = {
.add_slave = w1_ds2781_add_slave,
.remove_slave = w1_ds2781_remove_slave,
+ .groups = w1_ds2781_groups,
};
static struct w1_family w1_ds2781_family = {
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c
index cd30a6d95ea..365d6dff21d 100644
--- a/drivers/w1/slaves/w1_ds28e04.c
+++ b/drivers/w1/slaves/w1_ds28e04.c
@@ -118,9 +118,9 @@ static int w1_f1C_read(struct w1_slave *sl, int addr, int len, char *data)
return w1_read_block(sl->master, data, len);
}
-static ssize_t w1_f1C_read_bin(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
struct w1_f1C_data *data = sl->family_data;
@@ -226,9 +226,9 @@ static int w1_f1C_write(struct w1_slave *sl, int addr, int len, const u8 *data)
return 0;
}
-static ssize_t w1_f1C_write_bin(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -280,9 +280,11 @@ out_up:
return count;
}
-static ssize_t w1_f1C_read_pio(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE);
+
+static ssize_t pio_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off,
+ size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -299,9 +301,9 @@ static ssize_t w1_f1C_read_pio(struct file *filp, struct kobject *kobj,
return ret;
}
-static ssize_t w1_f1C_write_pio(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t pio_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off,
+ size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -339,8 +341,10 @@ static ssize_t w1_f1C_write_pio(struct file *filp, struct kobject *kobj,
return count;
}
-static ssize_t w1_f1C_show_crccheck(struct device *dev,
- struct device_attribute *attr, char *buf)
+static BIN_ATTR_RW(pio, 1);
+
+static ssize_t crccheck_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
if (put_user(w1_enable_crccheck + 0x30, buf))
return -EFAULT;
@@ -348,9 +352,8 @@ static ssize_t w1_f1C_show_crccheck(struct device *dev,
return sizeof(w1_enable_crccheck);
}
-static ssize_t w1_f1C_store_crccheck(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t crccheck_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
char val;
@@ -371,35 +374,31 @@ static ssize_t w1_f1C_store_crccheck(struct device *dev,
return sizeof(w1_enable_crccheck);
}
-#define NB_SYSFS_BIN_FILES 2
-static struct bin_attribute w1_f1C_bin_attr[NB_SYSFS_BIN_FILES] = {
- {
- .attr = {
- .name = "eeprom",
- .mode = S_IRUGO | S_IWUSR,
- },
- .size = W1_EEPROM_SIZE,
- .read = w1_f1C_read_bin,
- .write = w1_f1C_write_bin,
- },
- {
- .attr = {
- .name = "pio",
- .mode = S_IRUGO | S_IWUSR,
- },
- .size = 1,
- .read = w1_f1C_read_pio,
- .write = w1_f1C_write_pio,
- }
+static DEVICE_ATTR_RW(crccheck);
+
+static struct attribute *w1_f1C_attrs[] = {
+ &dev_attr_crccheck.attr,
+ NULL,
};
-static DEVICE_ATTR(crccheck, S_IWUSR | S_IRUGO,
- w1_f1C_show_crccheck, w1_f1C_store_crccheck);
+static struct bin_attribute *w1_f1C_bin_attrs[] = {
+ &bin_attr_eeprom,
+ &bin_attr_pio,
+ NULL,
+};
+
+static const struct attribute_group w1_f1C_group = {
+ .attrs = w1_f1C_attrs,
+ .bin_attrs = w1_f1C_bin_attrs,
+};
+
+static const struct attribute_group *w1_f1C_groups[] = {
+ &w1_f1C_group,
+ NULL,
+};
static int w1_f1C_add_slave(struct w1_slave *sl)
{
- int err = 0;
- int i;
struct w1_f1C_data *data = NULL;
if (w1_enable_crccheck) {
@@ -409,46 +408,19 @@ static int w1_f1C_add_slave(struct w1_slave *sl)
sl->family_data = data;
}
- /* create binary sysfs attributes */
- for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
- err = sysfs_create_bin_file(
- &sl->dev.kobj, &(w1_f1C_bin_attr[i]));
-
- if (!err) {
- /* create device attributes */
- err = device_create_file(&sl->dev, &dev_attr_crccheck);
- }
-
- if (err) {
- /* remove binary sysfs attributes */
- for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
- sysfs_remove_bin_file(
- &sl->dev.kobj, &(w1_f1C_bin_attr[i]));
-
- kfree(data);
- }
-
- return err;
+ return 0;
}
static void w1_f1C_remove_slave(struct w1_slave *sl)
{
- int i;
-
kfree(sl->family_data);
sl->family_data = NULL;
-
- /* remove device attributes */
- device_remove_file(&sl->dev, &dev_attr_crccheck);
-
- /* remove binary sysfs attributes */
- for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
- sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
}
static struct w1_family_ops w1_f1C_fops = {
.add_slave = w1_f1C_add_slave,
.remove_slave = w1_f1C_remove_slave,
+ .groups = w1_f1C_groups,
};
static struct w1_family w1_family_1C = {
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 8978360bd38..8b5ff33f72c 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -59,25 +59,19 @@ static int w1_strong_pullup = 1;
module_param_named(strong_pullup, w1_strong_pullup, int, 0);
-static ssize_t w1_therm_read(struct device *device,
+static ssize_t w1_slave_show(struct device *device,
struct device_attribute *attr, char *buf);
-static struct device_attribute w1_therm_attr =
- __ATTR(w1_slave, S_IRUGO, w1_therm_read, NULL);
+static DEVICE_ATTR_RO(w1_slave);
-static int w1_therm_add_slave(struct w1_slave *sl)
-{
- return device_create_file(&sl->dev, &w1_therm_attr);
-}
-
-static void w1_therm_remove_slave(struct w1_slave *sl)
-{
- device_remove_file(&sl->dev, &w1_therm_attr);
-}
+static struct attribute *w1_therm_attrs[] = {
+ &dev_attr_w1_slave.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(w1_therm);
static struct w1_family_ops w1_therm_fops = {
- .add_slave = w1_therm_add_slave,
- .remove_slave = w1_therm_remove_slave,
+ .groups = w1_therm_groups,
};
static struct w1_family w1_therm_family_DS18S20 = {
@@ -178,7 +172,7 @@ static inline int w1_convert_temp(u8 rom[9], u8 fid)
}
-static ssize_t w1_therm_read(struct device *device,
+static ssize_t w1_slave_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct w1_slave *sl = dev_to_w1_slave(device);
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 0459df843c5..22013ca2119 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -96,14 +96,15 @@ static void w1_slave_release(struct device *dev)
complete(&sl->released);
}
-static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct w1_slave *sl = dev_to_w1_slave(dev);
return sprintf(buf, "%s\n", sl->name);
}
+static DEVICE_ATTR_RO(name);
-static ssize_t w1_slave_read_id(struct device *dev,
+static ssize_t id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct w1_slave *sl = dev_to_w1_slave(dev);
@@ -112,17 +113,20 @@ static ssize_t w1_slave_read_id(struct device *dev,
memcpy(buf, (u8 *)&sl->reg_num, count);
return count;
}
+static DEVICE_ATTR_RO(id);
-static struct device_attribute w1_slave_attr_name =
- __ATTR(name, S_IRUGO, w1_slave_read_name, NULL);
-static struct device_attribute w1_slave_attr_id =
- __ATTR(id, S_IRUGO, w1_slave_read_id, NULL);
+static struct attribute *w1_slave_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_id.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(w1_slave);
/* Default family */
-static ssize_t w1_default_write(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t rw_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off,
+ size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -139,9 +143,9 @@ out_up:
return count;
}
-static ssize_t w1_default_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t rw_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off,
+ size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -151,29 +155,24 @@ static ssize_t w1_default_read(struct file *filp, struct kobject *kobj,
return count;
}
-static struct bin_attribute w1_default_attr = {
- .attr = {
- .name = "rw",
- .mode = S_IRUGO | S_IWUSR,
- },
- .size = PAGE_SIZE,
- .read = w1_default_read,
- .write = w1_default_write,
+static BIN_ATTR_RW(rw, PAGE_SIZE);
+
+static struct bin_attribute *w1_slave_bin_attrs[] = {
+ &bin_attr_rw,
+ NULL,
};
-static int w1_default_add_slave(struct w1_slave *sl)
-{
- return sysfs_create_bin_file(&sl->dev.kobj, &w1_default_attr);
-}
+static const struct attribute_group w1_slave_default_group = {
+ .bin_attrs = w1_slave_bin_attrs,
+};
-static void w1_default_remove_slave(struct w1_slave *sl)
-{
- sysfs_remove_bin_file(&sl->dev.kobj, &w1_default_attr);
-}
+static const struct attribute_group *w1_slave_default_groups[] = {
+ &w1_slave_default_group,
+ NULL,
+};
static struct w1_family_ops w1_default_fops = {
- .add_slave = w1_default_add_slave,
- .remove_slave = w1_default_remove_slave,
+ .groups = w1_slave_default_groups,
};
static struct w1_family w1_default_family = {
@@ -587,6 +586,66 @@ end:
return err;
}
+/*
+ * Handle sysfs file creation and removal here, before userspace is told that
+ * the device is added / removed from the system
+ */
+static int w1_bus_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct device *dev = data;
+ struct w1_slave *sl;
+ struct w1_family_ops *fops;
+ int err;
+
+ /*
+ * Only care about slave devices at the moment. Yes, we should use a
+ * separate "type" for this, but for now, look at the release function
+ * to know which type it is...
+ */
+ if (dev->release != w1_slave_release)
+ return 0;
+
+ sl = dev_to_w1_slave(dev);
+ fops = sl->family->fops;
+
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ /* if the family driver needs to initialize something... */
+ if (fops->add_slave) {
+ err = fops->add_slave(sl);
+ if (err < 0) {
+ dev_err(&sl->dev,
+ "add_slave() call failed. err=%d\n",
+ err);
+ return err;
+ }
+ }
+ if (fops->groups) {
+ err = sysfs_create_groups(&sl->dev.kobj, fops->groups);
+ if (err) {
+ dev_err(&sl->dev,
+ "sysfs group creation failed. err=%d\n",
+ err);
+ return err;
+ }
+ }
+
+ break;
+ case BUS_NOTIFY_DEL_DEVICE:
+ if (fops->remove_slave)
+ sl->family->fops->remove_slave(sl);
+ if (fops->groups)
+ sysfs_remove_groups(&sl->dev.kobj, fops->groups);
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block w1_bus_nb = {
+ .notifier_call = w1_bus_notify,
+};
+
static int __w1_attach_slave_device(struct w1_slave *sl)
{
int err;
@@ -595,6 +654,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
sl->dev.driver = &w1_slave_driver;
sl->dev.bus = &w1_bus_type;
sl->dev.release = &w1_slave_release;
+ sl->dev.groups = w1_slave_groups;
dev_set_name(&sl->dev, "%02x-%012llx",
(unsigned int) sl->reg_num.family,
@@ -615,44 +675,13 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
return err;
}
- /* Create "name" entry */
- err = device_create_file(&sl->dev, &w1_slave_attr_name);
- if (err < 0) {
- dev_err(&sl->dev,
- "sysfs file creation for [%s] failed. err=%d\n",
- dev_name(&sl->dev), err);
- goto out_unreg;
- }
-
- /* Create "id" entry */
- err = device_create_file(&sl->dev, &w1_slave_attr_id);
- if (err < 0) {
- dev_err(&sl->dev,
- "sysfs file creation for [%s] failed. err=%d\n",
- dev_name(&sl->dev), err);
- goto out_rem1;
- }
- /* if the family driver needs to initialize something... */
- if (sl->family->fops && sl->family->fops->add_slave &&
- ((err = sl->family->fops->add_slave(sl)) < 0)) {
- dev_err(&sl->dev,
- "sysfs file creation for [%s] failed. err=%d\n",
- dev_name(&sl->dev), err);
- goto out_rem2;
- }
+ dev_set_uevent_suppress(&sl->dev, false);
+ kobject_uevent(&sl->dev.kobj, KOBJ_ADD);
list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
return 0;
-
-out_rem2:
- device_remove_file(&sl->dev, &w1_slave_attr_id);
-out_rem1:
- device_remove_file(&sl->dev, &w1_slave_attr_name);
-out_unreg:
- device_unregister(&sl->dev);
- return err;
}
static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
@@ -723,16 +752,11 @@ void w1_slave_detach(struct w1_slave *sl)
list_del(&sl->w1_slave_entry);
- if (sl->family->fops && sl->family->fops->remove_slave)
- sl->family->fops->remove_slave(sl);
-
memset(&msg, 0, sizeof(msg));
memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
msg.type = W1_SLAVE_REMOVE;
w1_netlink_send(sl->master, &msg);
- device_remove_file(&sl->dev, &w1_slave_attr_id);
- device_remove_file(&sl->dev, &w1_slave_attr_name);
device_unregister(&sl->dev);
wait_for_completion(&sl->released);
@@ -1017,6 +1041,10 @@ static int __init w1_init(void)
goto err_out_exit_init;
}
+ retval = bus_register_notifier(&w1_bus_type, &w1_bus_nb);
+ if (retval)
+ goto err_out_bus_unregister;
+
retval = driver_register(&w1_master_driver);
if (retval) {
printk(KERN_ERR
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 625dd08f775..4ad0e81b640 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -52,6 +52,7 @@ struct w1_family_ops
{
int (* add_slave)(struct w1_slave *);
void (* remove_slave)(struct w1_slave *);
+ const struct attribute_group **groups;
};
struct w1_family
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 9e02d60a364..23eae5cb69c 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -145,7 +145,7 @@ config SWIOTLB_XEN
config XEN_TMEM
tristate
- depends on !ARM
+ depends on !ARM && !ARM64
default m if (CLEANCACHE || FRONTSWAP)
help
Shim to interface in-kernel Transcendent Memory hooks
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index eabd0ee1c2b..14fe79d8634 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,9 +1,8 @@
-ifneq ($(CONFIG_ARM),y)
-obj-y += manage.o
+ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),)
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
endif
obj-$(CONFIG_X86) += fallback.o
-obj-y += grant-table.o features.o events.o balloon.o
+obj-y += grant-table.o features.o events.o balloon.o manage.o
obj-y += xenbus/
nostackp := $(call cc-option, -fno-stack-protector)
diff --git a/drivers/xen/acpi.c b/drivers/xen/acpi.c
index 119d42a2bf5..90307c0b630 100644
--- a/drivers/xen/acpi.c
+++ b/drivers/xen/acpi.c
@@ -35,28 +35,43 @@
#include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h>
-int xen_acpi_notify_hypervisor_state(u8 sleep_state,
- u32 pm1a_cnt, u32 pm1b_cnt)
+static int xen_acpi_notify_hypervisor_state(u8 sleep_state,
+ u32 val_a, u32 val_b,
+ bool extended)
{
+ unsigned int bits = extended ? 8 : 16;
+
struct xen_platform_op op = {
.cmd = XENPF_enter_acpi_sleep,
.interface_version = XENPF_INTERFACE_VERSION,
- .u = {
- .enter_acpi_sleep = {
- .pm1a_cnt_val = (u16)pm1a_cnt,
- .pm1b_cnt_val = (u16)pm1b_cnt,
- .sleep_state = sleep_state,
- },
+ .u.enter_acpi_sleep = {
+ .val_a = (u16)val_a,
+ .val_b = (u16)val_b,
+ .sleep_state = sleep_state,
+ .flags = extended ? XENPF_ACPI_SLEEP_EXTENDED : 0,
},
};
- if ((pm1a_cnt & 0xffff0000) || (pm1b_cnt & 0xffff0000)) {
- WARN(1, "Using more than 16bits of PM1A/B 0x%x/0x%x!"
- "Email xen-devel@lists.xensource.com Thank you.\n", \
- pm1a_cnt, pm1b_cnt);
+ if (WARN((val_a & (~0 << bits)) || (val_b & (~0 << bits)),
+ "Using more than %u bits of sleep control values %#x/%#x!"
+ "Email xen-devel@lists.xen.org - Thank you.\n", \
+ bits, val_a, val_b))
return -1;
- }
HYPERVISOR_dom0_op(&op);
return 1;
}
+
+int xen_acpi_notify_hypervisor_sleep(u8 sleep_state,
+ u32 pm1a_cnt, u32 pm1b_cnt)
+{
+ return xen_acpi_notify_hypervisor_state(sleep_state, pm1a_cnt,
+ pm1b_cnt, false);
+}
+
+int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state,
+ u32 val_a, u32 val_b)
+{
+ return xen_acpi_notify_hypervisor_state(sleep_state, val_a,
+ val_b, true);
+}
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index a58ac435a9a..5e8be462aed 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -348,7 +348,7 @@ static void init_evtchn_cpu_bindings(void)
for_each_possible_cpu(i)
memset(per_cpu(cpu_evtchn_mask, i),
- (i == 0) ? ~0 : 0, sizeof(*per_cpu(cpu_evtchn_mask, i)));
+ (i == 0) ? ~0 : 0, NR_EVENT_CHANNELS/8);
}
static inline void clear_evtchn(int port)
@@ -1493,8 +1493,10 @@ void rebind_evtchn_irq(int evtchn, int irq)
/* Rebind an evtchn so that it gets delivered to a specific cpu */
static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
{
+ struct shared_info *s = HYPERVISOR_shared_info;
struct evtchn_bind_vcpu bind_vcpu;
int evtchn = evtchn_from_irq(irq);
+ int masked;
if (!VALID_EVTCHN(evtchn))
return -1;
@@ -1511,6 +1513,12 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
bind_vcpu.vcpu = tcpu;
/*
+ * Mask the event while changing the VCPU binding to prevent
+ * it being delivered on an unexpected VCPU.
+ */
+ masked = sync_test_and_set_bit(evtchn, BM(s->evtchn_mask));
+
+ /*
* If this fails, it usually just indicates that we're dealing with a
* virq or IPI channel, which don't actually need to be rebound. Ignore
* it, but don't do the xenlinux-level rebind in that case.
@@ -1518,6 +1526,9 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
bind_evtchn_to_cpu(evtchn, tcpu);
+ if (!masked)
+ unmask_evtchn(evtchn);
+
return 0;
}
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index 8feecf01d55..b6165e047f4 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -379,18 +379,12 @@ static long evtchn_ioctl(struct file *file,
if (unbind.port >= NR_EVENT_CHANNELS)
break;
- spin_lock_irq(&port_user_lock);
-
rc = -ENOTCONN;
- if (get_port_user(unbind.port) != u) {
- spin_unlock_irq(&port_user_lock);
+ if (get_port_user(unbind.port) != u)
break;
- }
disable_irq(irq_from_evtchn(unbind.port));
- spin_unlock_irq(&port_user_lock);
-
evtchn_unbind_from_user(u, unbind.port);
rc = 0;
@@ -490,26 +484,15 @@ static int evtchn_release(struct inode *inode, struct file *filp)
int i;
struct per_user_data *u = filp->private_data;
- spin_lock_irq(&port_user_lock);
-
- free_page((unsigned long)u->ring);
-
for (i = 0; i < NR_EVENT_CHANNELS; i++) {
if (get_port_user(i) != u)
continue;
disable_irq(irq_from_evtchn(i));
- }
-
- spin_unlock_irq(&port_user_lock);
-
- for (i = 0; i < NR_EVENT_CHANNELS; i++) {
- if (get_port_user(i) != u)
- continue;
-
evtchn_unbind_from_user(get_port_user(i), i);
}
+ free_page((unsigned long)u->ring);
kfree(u->name);
kfree(u);
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index 6ed8a9df447..34b20bfa4e8 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -115,7 +115,6 @@ static int xenbus_frontend_dev_resume(struct device *dev)
return -EFAULT;
}
- INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
queue_work(xenbus_frontend_wq, &xdev->work);
return 0;
@@ -124,6 +123,16 @@ static int xenbus_frontend_dev_resume(struct device *dev)
return xenbus_dev_resume(dev);
}
+static int xenbus_frontend_dev_probe(struct device *dev)
+{
+ if (xen_store_domain_type == XS_LOCAL) {
+ struct xenbus_device *xdev = to_xenbus_device(dev);
+ INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
+ }
+
+ return xenbus_dev_probe(dev);
+}
+
static const struct dev_pm_ops xenbus_pm_ops = {
.suspend = xenbus_dev_suspend,
.resume = xenbus_frontend_dev_resume,
@@ -142,7 +151,7 @@ static struct xen_bus_type xenbus_frontend = {
.name = "xen",
.match = xenbus_match,
.uevent = xenbus_uevent_frontend,
- .probe = xenbus_dev_probe,
+ .probe = xenbus_frontend_dev_probe,
.remove = xenbus_dev_remove,
.shutdown = xenbus_dev_shutdown,
.dev_attrs = xenbus_dev_attrs,
@@ -474,7 +483,11 @@ static int __init xenbus_probe_frontend_init(void)
register_xenstore_notifier(&xenstore_notifier);
- xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+ if (xen_store_domain_type == XS_LOCAL) {
+ xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+ if (!xenbus_frontend_wq)
+ pr_warn("create xenbus frontend workqueue failed, S3 resume is likely to fail\n");
+ }
return 0;
}